From f18c6caded8808ca8850214875229036c9d53307 Mon Sep 17 00:00:00 2001 From: huyuhui001 Date: Tue, 3 Oct 2023 01:50:06 +0800 Subject: [PATCH] Deployed ae9ce1c with MkDocs version: 1.3.0 --- 404.html | 2 +- about/index.html | 2 +- assets/javascripts/bundle.2ab50757.min.js | 29 - assets/javascripts/bundle.2ab50757.min.js.map | 8 - assets/javascripts/bundle.b1047164.min.js | 29 + assets/javascripts/bundle.b1047164.min.js.map | 7 + ...ecf98df9.min.js => search.fcfe8b6d.min.js} | 14 +- ....min.js.map => search.fcfe8b6d.min.js.map} | 9 +- assets/stylesheets/main.6b80c2a2.min.css | 1 - assets/stylesheets/main.6b80c2a2.min.css.map | 1 - assets/stylesheets/main.a57b2b03.min.css | 2 + assets/stylesheets/main.a57b2b03.min.css.map | 1 + assets/stylesheets/palette.3f5d1f46.min.css | 2 + .../stylesheets/palette.3f5d1f46.min.css.map | 1 + assets/stylesheets/palette.cbb835fc.min.css | 1 - .../stylesheets/palette.cbb835fc.min.css.map | 1 - index.html | 2 +- k8s/cka_cn/foundamentals/basics/index.html | 84 +- .../foundamentals/casestudy-calico/index.html | 330 +-- .../casestudy-health-check/index.html | 132 +- .../casestudy-operation-resources/index.html | 218 +- .../foundamentals/clustermgt/index.html | 202 +- .../foundamentals/configuration/index.html | 2 +- k8s/cka_cn/foundamentals/daemonset/index.html | 18 +- .../foundamentals/deployment/index.html | 76 +- k8s/cka_cn/foundamentals/docker/index.html | 508 ++-- .../foundamentals/healthcheck/index.html | 54 +- k8s/cka_cn/foundamentals/helming/index.html | 368 +-- k8s/cka_cn/foundamentals/hpa/index.html | 76 +- k8s/cka_cn/foundamentals/ingress/index.html | 90 +- k8s/cka_cn/foundamentals/job/index.html | 20 +- k8s/cka_cn/foundamentals/memo/index.html | 224 +- k8s/cka_cn/foundamentals/namespace/index.html | 18 +- .../foundamentals/networkpolicy/index.html | 114 +- k8s/cka_cn/foundamentals/overview/index.html | 34 +- .../foundamentals/persistence/index.html | 314 +-- k8s/cka_cn/foundamentals/pod/index.html | 446 ++-- k8s/cka_cn/foundamentals/policy/index.html | 150 +- k8s/cka_cn/foundamentals/rbac/index.html | 246 +- .../foundamentals/scheduling/index.html | 26 +- k8s/cka_cn/foundamentals/secrets/index.html | 2 +- k8s/cka_cn/foundamentals/service/index.html | 104 +- .../foundamentals/statefulset/index.html | 18 +- .../foundamentals/troubleshooting/index.html | 52 +- .../installation/aliyun-ubuntu/index.html | 344 +-- .../installation/multiple-local/index.html | 344 +-- .../installation/single-local/index.html | 178 +- k8s/cka_en/foundamentals/basics/index.html | 8 +- .../foundamentals/casestudy-calico/index.html | 52 +- .../casestudy-health-check/index.html | 20 +- .../casestudy-operation-resources/index.html | 28 +- .../foundamentals/clustermgt/index.html | 6 +- .../foundamentals/configuration/index.html | 2 +- k8s/cka_en/foundamentals/daemonset/index.html | 4 +- .../foundamentals/deployment/index.html | 76 +- k8s/cka_en/foundamentals/docker/index.html | 200 +- .../foundamentals/healthcheck/index.html | 4 +- k8s/cka_en/foundamentals/helming/index.html | 238 +- k8s/cka_en/foundamentals/hpa/index.html | 36 +- k8s/cka_en/foundamentals/ingress/index.html | 4 +- k8s/cka_en/foundamentals/job/index.html | 4 +- k8s/cka_en/foundamentals/kyma/index.html | 4 +- k8s/cka_en/foundamentals/memo/index.html | 102 +- k8s/cka_en/foundamentals/namespace/index.html | 4 +- .../foundamentals/networkpolicy/index.html | 8 +- k8s/cka_en/foundamentals/overview/index.html | 4 +- .../foundamentals/persistence/index.html | 128 +- k8s/cka_en/foundamentals/pod/index.html | 6 +- k8s/cka_en/foundamentals/policy/index.html | 120 +- k8s/cka_en/foundamentals/rbac/index.html | 56 +- .../foundamentals/scheduling/index.html | 4 +- k8s/cka_en/foundamentals/secrets/index.html | 2 +- k8s/cka_en/foundamentals/service/index.html | 22 +- .../foundamentals/statefulset/index.html | 4 +- .../foundamentals/troubleshooting/index.html | 8 +- .../installation/aliyun-ubuntu/index.html | 342 +-- .../installation/multiple-local/index.html | 336 +-- .../installation/single-local/index.html | 198 +- k8s/demo/cap_on_kyma/index.html | 186 +- k8s/index.html | 2 +- linux/Administration/01/index.html | 122 +- linux/Administration/02/index.html | 100 +- linux/Administration/03/index.html | 2 +- linux/SES/linux_ses_demo/index.html | 4 +- linux/SES/linux_ses_memo/index.html | 4 +- linux/SRE/01-fundamentals/index.html | 366 +-- linux/SRE/02-filesystem/index.html | 902 +++---- linux/SRE/03-identity-security/index.html | 1626 ++++++------ linux/SRE/04-TextTools/index.html | 720 ++--- linux/SRE/05-RegExpress/index.html | 2330 ++++++++--------- linux/SRE/06-FileLookup/index.html | 16 +- linux/SRE/07-FilePacking/index.html | 2 +- linux/index.html | 2 +- python/DataAnalysis/ch01/index.html | 4 +- python/DataAnalysis/ch02/index.html | 4 +- python/DataAnalysis/ch03/index.html | 4 +- python/DataAnalysis/ch04/index.html | 4 +- python/DataAnalysis/ch05/index.html | 4 +- python/DataAnalysis/ch06/index.html | 4 +- python/DataAnalysis/ch07/index.html | 4 +- python/DataAnalysis/ch08/index.html | 4 +- python/DataAnalysis/ch09/index.html | 4 +- python/DataAnalysis/ch10/index.html | 4 +- python/DataAnalysis/ch11/index.html | 4 +- .../01_PythonFundmantal/index.html | 70 +- .../02_CollectionsOverview/index.html | 32 +- .../03_TimeComplexity/index.html | 98 +- python/DataStructure/04_ArrayChain/index.html | 425 ++- .../05_InterfacePolymorphism/index.html | 4 +- .../06_InheritanceAbstractClass/index.html | 2 +- python/DataStructure/code/tmp.py | 293 ++- python/Demo/CourseSystem/index.html | 4 +- python/Foundation/Algorithms/index.html | 4 +- python/Foundation/ch00/index.html | 148 +- python/Foundation/ch01/index.html | 8 +- python/Foundation/ch02/index.html | 8 +- python/Foundation/ch03/index.html | 4 +- python/Foundation/ch04/index.html | 16 +- python/Foundation/ch05/index.html | 12 +- python/index.html | 2 +- search/search_index.json | 2 +- sitemap.xml | 208 +- sitemap.xml.gz | Bin 939 -> 939 bytes 123 files changed, 7516 insertions(+), 7186 deletions(-) delete mode 100644 assets/javascripts/bundle.2ab50757.min.js delete mode 100644 assets/javascripts/bundle.2ab50757.min.js.map create mode 100644 assets/javascripts/bundle.b1047164.min.js create mode 100644 assets/javascripts/bundle.b1047164.min.js.map rename assets/javascripts/workers/{search.ecf98df9.min.js => search.fcfe8b6d.min.js} (71%) rename assets/javascripts/workers/{search.ecf98df9.min.js.map => search.fcfe8b6d.min.js.map} (59%) delete mode 100644 assets/stylesheets/main.6b80c2a2.min.css delete mode 100644 assets/stylesheets/main.6b80c2a2.min.css.map create mode 100644 assets/stylesheets/main.a57b2b03.min.css create mode 100644 assets/stylesheets/main.a57b2b03.min.css.map create mode 100644 assets/stylesheets/palette.3f5d1f46.min.css create mode 100644 assets/stylesheets/palette.3f5d1f46.min.css.map delete mode 100644 assets/stylesheets/palette.cbb835fc.min.css delete mode 100644 assets/stylesheets/palette.cbb835fc.min.css.map diff --git a/404.html b/404.html index 9c59e433..5af18223 100644 --- a/404.html +++ b/404.html @@ -1 +1 @@ - UPSkilling

404 - Not found

\ No newline at end of file + UPSkilling

404 - Not found

Back to top
\ No newline at end of file diff --git a/about/index.html b/about/index.html index 587d231f..4b6707e0 100644 --- a/about/index.html +++ b/about/index.html @@ -1 +1 @@ - About - UPSkilling
Skip to content

About

What's past is prologue. It’s never too late to do.

You may also visit my posts on zhihu.

--From Shanghai China

\ No newline at end of file + About - UPSkilling
Skip to content

About

What's past is prologue. It’s never too late to do.

You may also visit my posts on zhihu.

--From Shanghai China

Back to top
\ No newline at end of file diff --git a/assets/javascripts/bundle.2ab50757.min.js b/assets/javascripts/bundle.2ab50757.min.js deleted file mode 100644 index cc6ae1c4..00000000 --- a/assets/javascripts/bundle.2ab50757.min.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict";(()=>{var oa=Object.create;var xr=Object.defineProperty;var ia=Object.getOwnPropertyDescriptor;var aa=Object.getOwnPropertyNames,kt=Object.getOwnPropertySymbols,sa=Object.getPrototypeOf,Sr=Object.prototype.hasOwnProperty,sn=Object.prototype.propertyIsEnumerable;var an=(e,t,r)=>t in e?xr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,H=(e,t)=>{for(var r in t||(t={}))Sr.call(t,r)&&an(e,r,t[r]);if(kt)for(var r of kt(t))sn.call(t,r)&&an(e,r,t[r]);return e};var cn=(e,t)=>{var r={};for(var n in e)Sr.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&kt)for(var n of kt(e))t.indexOf(n)<0&&sn.call(e,n)&&(r[n]=e[n]);return r};var yt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var ca=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of aa(t))!Sr.call(e,o)&&o!==r&&xr(e,o,{get:()=>t[o],enumerable:!(n=ia(t,o))||n.enumerable});return e};var Ye=(e,t,r)=>(r=e!=null?oa(sa(e)):{},ca(t||!e||!e.__esModule?xr(r,"default",{value:e,enumerable:!0}):r,e));var fn=yt((wr,un)=>{(function(e,t){typeof wr=="object"&&typeof un!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(wr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(O){return!!(O&&O!==document&&O.nodeName!=="HTML"&&O.nodeName!=="BODY"&&"classList"in O&&"contains"in O.classList)}function c(O){var Ue=O.type,He=O.tagName;return!!(He==="INPUT"&&a[Ue]&&!O.readOnly||He==="TEXTAREA"&&!O.readOnly||O.isContentEditable)}function u(O){O.classList.contains("focus-visible")||(O.classList.add("focus-visible"),O.setAttribute("data-focus-visible-added",""))}function f(O){!O.hasAttribute("data-focus-visible-added")||(O.classList.remove("focus-visible"),O.removeAttribute("data-focus-visible-added"))}function p(O){O.metaKey||O.altKey||O.ctrlKey||(s(r.activeElement)&&u(r.activeElement),n=!0)}function l(O){n=!1}function d(O){!s(O.target)||(n||c(O.target))&&u(O.target)}function h(O){!s(O.target)||(O.target.classList.contains("focus-visible")||O.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),f(O.target))}function b(O){document.visibilityState==="hidden"&&(o&&(n=!0),U())}function U(){document.addEventListener("mousemove",W),document.addEventListener("mousedown",W),document.addEventListener("mouseup",W),document.addEventListener("pointermove",W),document.addEventListener("pointerdown",W),document.addEventListener("pointerup",W),document.addEventListener("touchmove",W),document.addEventListener("touchstart",W),document.addEventListener("touchend",W)}function G(){document.removeEventListener("mousemove",W),document.removeEventListener("mousedown",W),document.removeEventListener("mouseup",W),document.removeEventListener("pointermove",W),document.removeEventListener("pointerdown",W),document.removeEventListener("pointerup",W),document.removeEventListener("touchmove",W),document.removeEventListener("touchstart",W),document.removeEventListener("touchend",W)}function W(O){O.target.nodeName&&O.target.nodeName.toLowerCase()==="html"||(n=!1,G())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",l,!0),document.addEventListener("pointerdown",l,!0),document.addEventListener("touchstart",l,!0),document.addEventListener("visibilitychange",b,!0),U(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var pn=yt(Er=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(u){return!1}},r=t(),n=function(u){var f={next:function(){var p=u.shift();return{done:p===void 0,value:p}}};return r&&(f[Symbol.iterator]=function(){return f}),f},o=function(u){return encodeURIComponent(u).replace(/%20/g,"+")},i=function(u){return decodeURIComponent(String(u).replace(/\+/g," "))},a=function(){var u=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var l=typeof p;if(l!=="undefined")if(l==="string")p!==""&&this._fromString(p);else if(p instanceof u){var d=this;p.forEach(function(G,W){d.append(W,G)})}else if(p!==null&&l==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),u._entries&&(u._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(c,u){typeof c!="string"&&(c=String(c)),u&&typeof u!="string"&&(u=String(u));var f=document,p;if(u&&(e.location===void 0||u!==e.location.href)){u=u.toLowerCase(),f=document.implementation.createHTMLDocument(""),p=f.createElement("base"),p.href=u,f.head.appendChild(p);try{if(p.href.indexOf(u)!==0)throw new Error(p.href)}catch(O){throw new Error("URL unable to set base "+u+" due to "+O)}}var l=f.createElement("a");l.href=c,p&&(f.body.appendChild(l),l.href=l.href);var d=f.createElement("input");if(d.type="url",d.value=c,l.protocol===":"||!/:/.test(l.href)||!d.checkValidity()&&!u)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:l});var h=new e.URLSearchParams(this.search),b=!0,U=!0,G=this;["append","delete","set"].forEach(function(O){var Ue=h[O];h[O]=function(){Ue.apply(h,arguments),b&&(U=!1,G.search=h.toString(),U=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var W=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==W&&(W=this.search,U&&(b=!1,this.searchParams._fromString(this.search),b=!0))}})},a=i.prototype,s=function(c){Object.defineProperty(a,c,{get:function(){return this._anchorElement[c]},set:function(u){this._anchorElement[c]=u},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(c){s(c)}),Object.defineProperty(a,"search",{get:function(){return this._anchorElement.search},set:function(c){this._anchorElement.search=c,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(a,{toString:{get:function(){var c=this;return function(){return c.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(c){this._anchorElement.href=c,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(c){this._anchorElement.pathname=c},enumerable:!0},origin:{get:function(){var c={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],u=this._anchorElement.port!=c&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(u?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(c){},enumerable:!0},username:{get:function(){return""},set:function(c){},enumerable:!0}}),i.createObjectURL=function(c){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(c){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er)});var kn=yt((zs,It)=>{/*! ***************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */var ln,mn,dn,hn,bn,vn,gn,yn,xn,Ht,Or,Sn,wn,En,rt,On,_n,Tn,Mn,Ln,An,Cn,Rn,Pt;(function(e){var t=typeof global=="object"?global:typeof self=="object"?self:typeof this=="object"?this:{};typeof define=="function"&&define.amd?define("tslib",["exports"],function(n){e(r(t,r(n)))}):typeof It=="object"&&typeof It.exports=="object"?e(r(t,r(It.exports))):e(r(t));function r(n,o){return n!==t&&(typeof Object.create=="function"?Object.defineProperty(n,"__esModule",{value:!0}):n.__esModule=!0),function(i,a){return n[i]=o?o(i,a):a}}})(function(e){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,o){n.__proto__=o}||function(n,o){for(var i in o)Object.prototype.hasOwnProperty.call(o,i)&&(n[i]=o[i])};ln=function(n,o){if(typeof o!="function"&&o!==null)throw new TypeError("Class extends value "+String(o)+" is not a constructor or null");t(n,o);function i(){this.constructor=n}n.prototype=o===null?Object.create(o):(i.prototype=o.prototype,new i)},mn=Object.assign||function(n){for(var o,i=1,a=arguments.length;i=0;f--)(u=n[f])&&(c=(s<3?u(c):s>3?u(o,i,c):u(o,i))||c);return s>3&&c&&Object.defineProperty(o,i,c),c},bn=function(n,o){return function(i,a){o(i,a,n)}},vn=function(n,o){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(n,o)},gn=function(n,o,i,a){function s(c){return c instanceof i?c:new i(function(u){u(c)})}return new(i||(i=Promise))(function(c,u){function f(d){try{l(a.next(d))}catch(h){u(h)}}function p(d){try{l(a.throw(d))}catch(h){u(h)}}function l(d){d.done?c(d.value):s(d.value).then(f,p)}l((a=a.apply(n,o||[])).next())})},yn=function(n,o){var i={label:0,sent:function(){if(c[0]&1)throw c[1];return c[1]},trys:[],ops:[]},a,s,c,u;return u={next:f(0),throw:f(1),return:f(2)},typeof Symbol=="function"&&(u[Symbol.iterator]=function(){return this}),u;function f(l){return function(d){return p([l,d])}}function p(l){if(a)throw new TypeError("Generator is already executing.");for(;i;)try{if(a=1,s&&(c=l[0]&2?s.return:l[0]?s.throw||((c=s.return)&&c.call(s),0):s.next)&&!(c=c.call(s,l[1])).done)return c;switch(s=0,c&&(l=[l[0]&2,c.value]),l[0]){case 0:case 1:c=l;break;case 4:return i.label++,{value:l[1],done:!1};case 5:i.label++,s=l[1],l=[0];continue;case 7:l=i.ops.pop(),i.trys.pop();continue;default:if(c=i.trys,!(c=c.length>0&&c[c.length-1])&&(l[0]===6||l[0]===2)){i=0;continue}if(l[0]===3&&(!c||l[1]>c[0]&&l[1]=n.length&&(n=void 0),{value:n&&n[a++],done:!n}}};throw new TypeError(o?"Object is not iterable.":"Symbol.iterator is not defined.")},Or=function(n,o){var i=typeof Symbol=="function"&&n[Symbol.iterator];if(!i)return n;var a=i.call(n),s,c=[],u;try{for(;(o===void 0||o-- >0)&&!(s=a.next()).done;)c.push(s.value)}catch(f){u={error:f}}finally{try{s&&!s.done&&(i=a.return)&&i.call(a)}finally{if(u)throw u.error}}return c},Sn=function(){for(var n=[],o=0;o1||f(b,U)})})}function f(b,U){try{p(a[b](U))}catch(G){h(c[0][3],G)}}function p(b){b.value instanceof rt?Promise.resolve(b.value.v).then(l,d):h(c[0][2],b)}function l(b){f("next",b)}function d(b){f("throw",b)}function h(b,U){b(U),c.shift(),c.length&&f(c[0][0],c[0][1])}},_n=function(n){var o,i;return o={},a("next"),a("throw",function(s){throw s}),a("return"),o[Symbol.iterator]=function(){return this},o;function a(s,c){o[s]=n[s]?function(u){return(i=!i)?{value:rt(n[s](u)),done:s==="return"}:c?c(u):u}:c}},Tn=function(n){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var o=n[Symbol.asyncIterator],i;return o?o.call(n):(n=typeof Ht=="function"?Ht(n):n[Symbol.iterator](),i={},a("next"),a("throw"),a("return"),i[Symbol.asyncIterator]=function(){return this},i);function a(c){i[c]=n[c]&&function(u){return new Promise(function(f,p){u=n[c](u),s(f,p,u.done,u.value)})}}function s(c,u,f,p){Promise.resolve(p).then(function(l){c({value:l,done:f})},u)}},Mn=function(n,o){return Object.defineProperty?Object.defineProperty(n,"raw",{value:o}):n.raw=o,n};var r=Object.create?function(n,o){Object.defineProperty(n,"default",{enumerable:!0,value:o})}:function(n,o){n.default=o};Ln=function(n){if(n&&n.__esModule)return n;var o={};if(n!=null)for(var i in n)i!=="default"&&Object.prototype.hasOwnProperty.call(n,i)&&Pt(o,n,i);return r(o,n),o},An=function(n){return n&&n.__esModule?n:{default:n}},Cn=function(n,o,i,a){if(i==="a"&&!a)throw new TypeError("Private accessor was defined without a getter");if(typeof o=="function"?n!==o||!a:!o.has(n))throw new TypeError("Cannot read private member from an object whose class did not declare it");return i==="m"?a:i==="a"?a.call(n):a?a.value:o.get(n)},Rn=function(n,o,i,a,s){if(a==="m")throw new TypeError("Private method is not writable");if(a==="a"&&!s)throw new TypeError("Private accessor was defined without a setter");if(typeof o=="function"?n!==o||!s:!o.has(n))throw new TypeError("Cannot write private member to an object whose class did not declare it");return a==="a"?s.call(n,i):s?s.value=i:o.set(n,i),i},e("__extends",ln),e("__assign",mn),e("__rest",dn),e("__decorate",hn),e("__param",bn),e("__metadata",vn),e("__awaiter",gn),e("__generator",yn),e("__exportStar",xn),e("__createBinding",Pt),e("__values",Ht),e("__read",Or),e("__spread",Sn),e("__spreadArrays",wn),e("__spreadArray",En),e("__await",rt),e("__asyncGenerator",On),e("__asyncDelegator",_n),e("__asyncValues",Tn),e("__makeTemplateObject",Mn),e("__importStar",Ln),e("__importDefault",An),e("__classPrivateFieldGet",Cn),e("__classPrivateFieldSet",Rn)})});var Kr=yt((At,Yr)=>{/*! - * clipboard.js v2.0.11 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */(function(t,r){typeof At=="object"&&typeof Yr=="object"?Yr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof At=="object"?At.ClipboardJS=r():t.ClipboardJS=r()})(At,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return na}});var a=i(279),s=i.n(a),c=i(370),u=i.n(c),f=i(817),p=i.n(f);function l(j){try{return document.execCommand(j)}catch(_){return!1}}var d=function(_){var E=p()(_);return l("cut"),E},h=d;function b(j){var _=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[_?"right":"left"]="-9999px";var k=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(k,"px"),E.setAttribute("readonly",""),E.value=j,E}var U=function(_,E){var k=b(_);E.container.appendChild(k);var I=p()(k);return l("copy"),k.remove(),I},G=function(_){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},k="";return typeof _=="string"?k=U(_,E):_ instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(_==null?void 0:_.type)?k=U(_.value,E):(k=p()(_),l("copy")),k},W=G;function O(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?O=function(E){return typeof E}:O=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},O(j)}var Ue=function(){var _=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=_.action,k=E===void 0?"copy":E,I=_.container,Q=_.target,Oe=_.text;if(k!=="copy"&&k!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Q!==void 0)if(Q&&O(Q)==="object"&&Q.nodeType===1){if(k==="copy"&&Q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(k==="cut"&&(Q.hasAttribute("readonly")||Q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Oe)return W(Oe,{container:I});if(Q)return k==="cut"?h(Q):W(Q,{container:I})},He=Ue;function Ce(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Ce=function(E){return typeof E}:Ce=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},Ce(j)}function Bi(j,_){if(!(j instanceof _))throw new TypeError("Cannot call a class as a function")}function on(j,_){for(var E=0;E<_.length;E++){var k=_[E];k.enumerable=k.enumerable||!1,k.configurable=!0,"value"in k&&(k.writable=!0),Object.defineProperty(j,k.key,k)}}function Gi(j,_,E){return _&&on(j.prototype,_),E&&on(j,E),j}function Ji(j,_){if(typeof _!="function"&&_!==null)throw new TypeError("Super expression must either be null or a function");j.prototype=Object.create(_&&_.prototype,{constructor:{value:j,writable:!0,configurable:!0}}),_&&gr(j,_)}function gr(j,_){return gr=Object.setPrototypeOf||function(k,I){return k.__proto__=I,k},gr(j,_)}function Xi(j){var _=ta();return function(){var k=Ct(j),I;if(_){var Q=Ct(this).constructor;I=Reflect.construct(k,arguments,Q)}else I=k.apply(this,arguments);return Zi(this,I)}}function Zi(j,_){return _&&(Ce(_)==="object"||typeof _=="function")?_:ea(j)}function ea(j){if(j===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return j}function ta(){if(typeof Reflect=="undefined"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(j){return!1}}function Ct(j){return Ct=Object.setPrototypeOf?Object.getPrototypeOf:function(E){return E.__proto__||Object.getPrototypeOf(E)},Ct(j)}function yr(j,_){var E="data-clipboard-".concat(j);if(!!_.hasAttribute(E))return _.getAttribute(E)}var ra=function(j){Ji(E,j);var _=Xi(E);function E(k,I){var Q;return Bi(this,E),Q=_.call(this),Q.resolveOptions(I),Q.listenClick(k),Q}return Gi(E,[{key:"resolveOptions",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof I.action=="function"?I.action:this.defaultAction,this.target=typeof I.target=="function"?I.target:this.defaultTarget,this.text=typeof I.text=="function"?I.text:this.defaultText,this.container=Ce(I.container)==="object"?I.container:document.body}},{key:"listenClick",value:function(I){var Q=this;this.listener=u()(I,"click",function(Oe){return Q.onClick(Oe)})}},{key:"onClick",value:function(I){var Q=I.delegateTarget||I.currentTarget,Oe=this.action(Q)||"copy",Rt=He({action:Oe,container:this.container,target:this.target(Q),text:this.text(Q)});this.emit(Rt?"success":"error",{action:Oe,text:Rt,trigger:Q,clearSelection:function(){Q&&Q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(I){return yr("action",I)}},{key:"defaultTarget",value:function(I){var Q=yr("target",I);if(Q)return document.querySelector(Q)}},{key:"defaultText",value:function(I){return yr("text",I)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(I){var Q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return W(I,Q)}},{key:"cut",value:function(I){return h(I)}},{key:"isSupported",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Q=typeof I=="string"?[I]:I,Oe=!!document.queryCommandSupported;return Q.forEach(function(Rt){Oe=Oe&&!!document.queryCommandSupported(Rt)}),Oe}}]),E}(s()),na=ra},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,c){for(;s&&s.nodeType!==o;){if(typeof s.matches=="function"&&s.matches(c))return s;s=s.parentNode}}n.exports=a},438:function(n,o,i){var a=i(828);function s(f,p,l,d,h){var b=u.apply(this,arguments);return f.addEventListener(l,b,h),{destroy:function(){f.removeEventListener(l,b,h)}}}function c(f,p,l,d,h){return typeof f.addEventListener=="function"?s.apply(null,arguments):typeof l=="function"?s.bind(null,document).apply(null,arguments):(typeof f=="string"&&(f=document.querySelectorAll(f)),Array.prototype.map.call(f,function(b){return s(b,p,l,d,h)}))}function u(f,p,l,d){return function(h){h.delegateTarget=a(h.target,p),h.delegateTarget&&d.call(f,h)}}n.exports=c},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(n,o,i){var a=i(879),s=i(438);function c(l,d,h){if(!l&&!d&&!h)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(h))throw new TypeError("Third argument must be a Function");if(a.node(l))return u(l,d,h);if(a.nodeList(l))return f(l,d,h);if(a.string(l))return p(l,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function u(l,d,h){return l.addEventListener(d,h),{destroy:function(){l.removeEventListener(d,h)}}}function f(l,d,h){return Array.prototype.forEach.call(l,function(b){b.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(l,function(b){b.removeEventListener(d,h)})}}}function p(l,d,h){return s(document.body,l,d,h)}n.exports=c},817:function(n){function o(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),u=document.createRange();u.selectNodeContents(i),c.removeAllRanges(),c.addRange(u),a=c.toString()}return a}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,a,s){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var c=this;function u(){c.off(i,u),a.apply(s,arguments)}return u._=a,this.on(i,u,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),c=0,u=s.length;for(c;c{"use strict";/*! - * escape-html - * Copyright(c) 2012-2013 TJ Holowaychuk - * Copyright(c) 2015 Andreas Lubbe - * Copyright(c) 2015 Tiancheng "Timothy" Gu - * MIT Licensed - */var _s=/["'&<>]/;Si.exports=Ts;function Ts(e){var t=""+e,r=_s.exec(t);if(!r)return t;var n,o="",i=0,a=0;for(i=r.index;i0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,a=o.isStopped,s=o.observers;return i||a?_r:(this.currentObservers=null,s.push(r),new Re(function(){n.currentObservers=null,Pe(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,a=n.isStopped;o?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,n){return new qn(r,n)},t}(F);var qn=function(e){re(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:_r},t}(w);var St={now:function(){return(St.delegate||Date).now()},delegate:void 0};var wt=function(e){re(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=St);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,a=n._infiniteTimeWindow,s=n._timestampProvider,c=n._windowTime;o||(i.push(r),!a&&i.push(s.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,a=o._buffer,s=a.slice(),c=0;c0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=at.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){if(o===void 0&&(o=0),o!=null&&o>0||o==null&&this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);r.actions.some(function(i){return i.id===n})||(at.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Nt);var Kn=function(e){re(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(zt);var Te=new Kn(Yn);var C=new F(function(e){return e.complete()});function qt(e){return e&&T(e.schedule)}function kr(e){return e[e.length-1]}function De(e){return T(kr(e))?e.pop():void 0}function ye(e){return qt(kr(e))?e.pop():void 0}function Qt(e,t){return typeof kr(e)=="number"?e.pop():t}var st=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Yt(e){return T(e==null?void 0:e.then)}function Kt(e){return T(e[it])}function Bt(e){return Symbol.asyncIterator&&T(e==null?void 0:e[Symbol.asyncIterator])}function Gt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function va(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Jt=va();function Xt(e){return T(e==null?void 0:e[Jt])}function Zt(e){return In(this,arguments,function(){var r,n,o,i;return $t(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,jt(r.read())];case 3:return n=a.sent(),o=n.value,i=n.done,i?[4,jt(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,jt(o)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function er(e){return T(e==null?void 0:e.getReader)}function N(e){if(e instanceof F)return e;if(e!=null){if(Kt(e))return ga(e);if(st(e))return ya(e);if(Yt(e))return xa(e);if(Bt(e))return Bn(e);if(Xt(e))return Sa(e);if(er(e))return wa(e)}throw Gt(e)}function ga(e){return new F(function(t){var r=e[it]();if(T(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function ya(e){return new F(function(t){for(var r=0;r=2,!0))}function oe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new w}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,c=s===void 0?!0:s;return function(u){var f,p,l,d=0,h=!1,b=!1,U=function(){p==null||p.unsubscribe(),p=void 0},G=function(){U(),f=l=void 0,h=b=!1},W=function(){var O=f;G(),O==null||O.unsubscribe()};return g(function(O,Ue){d++,!b&&!h&&U();var He=l=l!=null?l:r();Ue.add(function(){d--,d===0&&!b&&!h&&(p=Ur(W,c))}),He.subscribe(Ue),!f&&d>0&&(f=new Be({next:function(Ce){return He.next(Ce)},error:function(Ce){b=!0,U(),p=Ur(G,o,Ce),He.error(Ce)},complete:function(){h=!0,U(),p=Ur(G,a),He.complete()}}),N(O).subscribe(f))})(u)}}function Ur(e,t){for(var r=[],n=2;ne.next(document)),e}function B(e,t=document){return Array.from(t.querySelectorAll(e))}function z(e,t=document){let r=pe(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function pe(e,t=document){return t.querySelector(e)||void 0}function Ne(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function nr(e){return R(v(document.body,"focusin"),v(document.body,"focusout")).pipe(Ze(1),m(()=>{let t=Ne();return typeof t!="undefined"?e.contains(t):!1}),q(e===Ne()),K())}function ze(e){return{x:e.offsetLeft,y:e.offsetTop}}function vo(e){return R(v(window,"load"),v(window,"resize")).pipe($e(0,Te),m(()=>ze(e)),q(ze(e)))}function or(e){return{x:e.scrollLeft,y:e.scrollTop}}function pt(e){return R(v(e,"scroll"),v(window,"resize")).pipe($e(0,Te),m(()=>or(e)),q(or(e)))}var yo=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!zr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),za?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!zr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=Na.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),xo=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),wo=typeof WeakMap!="undefined"?new WeakMap:new yo,Eo=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=qa.getInstance(),n=new ts(t,r,this);wo.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Eo.prototype[e]=function(){var t;return(t=wo.get(this))[e].apply(t,arguments)}});var rs=function(){return typeof ir.ResizeObserver!="undefined"?ir.ResizeObserver:Eo}(),Oo=rs;var _o=new w,ns=P(()=>$(new Oo(e=>{for(let t of e)_o.next(t)}))).pipe(S(e=>R(xe,$(e)).pipe(L(()=>e.disconnect()))),X(1));function Ae(e){return{width:e.offsetWidth,height:e.offsetHeight}}function de(e){return ns.pipe(x(t=>t.observe(e)),S(t=>_o.pipe(M(({target:r})=>r===e),L(()=>t.unobserve(e)),m(()=>Ae(e)))),q(Ae(e)))}function mt(e){return{width:e.scrollWidth,height:e.scrollHeight}}var To=new w,os=P(()=>$(new IntersectionObserver(e=>{for(let t of e)To.next(t)},{threshold:0}))).pipe(S(e=>R(xe,$(e)).pipe(L(()=>e.disconnect()))),X(1));function cr(e){return os.pipe(x(t=>t.observe(e)),S(t=>To.pipe(M(({target:r})=>r===e),L(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function Mo(e,t=16){return pt(e).pipe(m(({y:r})=>{let n=Ae(e),o=mt(e);return r>=o.height-n.height-t}),K())}var ur={drawer:z("[data-md-toggle=drawer]"),search:z("[data-md-toggle=search]")};function Lo(e){return ur[e].checked}function qe(e,t){ur[e].checked!==t&&ur[e].click()}function dt(e){let t=ur[e];return v(t,"change").pipe(m(()=>t.checked),q(t.checked))}function is(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ao(){return v(window,"keydown").pipe(M(e=>!(e.metaKey||e.ctrlKey)),m(e=>({mode:Lo("search")?"search":"global",type:e.key,claim(){e.preventDefault(),e.stopPropagation()}})),M(({mode:e,type:t})=>{if(e==="global"){let r=Ne();if(typeof r!="undefined")return!is(r,t)}return!0}),oe())}function Se(){return new URL(location.href)}function fr(e){location.href=e.href}function Co(){return new w}function Ro(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Ro(e,r)}function A(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)Ro(n,o);return n}function ko(e,t){let r=t;if(e.length>r){for(;e[r]!==" "&&--r>0;);return`${e.substring(0,r)}...`}return e}function pr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function Ho(){return location.hash.substring(1)}function Po(e){let t=A("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function as(){return v(window,"hashchange").pipe(m(Ho),q(Ho()),M(e=>e.length>0),X(1))}function Io(){return as().pipe(m(e=>pe(`[id="${e}"]`)),M(e=>typeof e!="undefined"))}function qr(e){let t=matchMedia(e);return rr(r=>t.addListener(()=>r(t.matches))).pipe(q(t.matches))}function $o(){let e=matchMedia("print");return R(v(window,"beforeprint").pipe(m(()=>!0)),v(window,"afterprint").pipe(m(()=>!1))).pipe(q(e.matches))}function Qr(e,t){return e.pipe(S(r=>r?t():C))}function lr(e,t={credentials:"same-origin"}){return fe(fetch(`${e}`,t)).pipe(ae(()=>C),S(r=>r.status!==200?Ot(()=>new Error(r.statusText)):$(r)))}function ke(e,t){return lr(e,t).pipe(S(r=>r.json()),X(1))}function jo(e,t){let r=new DOMParser;return lr(e,t).pipe(S(n=>n.text()),m(n=>r.parseFromString(n,"text/xml")),X(1))}function Fo(e){let t=A("script",{src:e});return P(()=>(document.head.appendChild(t),R(v(t,"load"),v(t,"error").pipe(S(()=>Ot(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),L(()=>document.head.removeChild(t)),se(1))))}function Uo(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function Do(){return R(v(window,"scroll",{passive:!0}),v(window,"resize",{passive:!0})).pipe(m(Uo),q(Uo()))}function Wo(){return{width:innerWidth,height:innerHeight}}function Vo(){return v(window,"resize",{passive:!0}).pipe(m(Wo),q(Wo()))}function No(){return Y([Do(),Vo()]).pipe(m(([e,t])=>({offset:e,size:t})),X(1))}function mr(e,{viewport$:t,header$:r}){let n=t.pipe(J("size")),o=Y([n,r]).pipe(m(()=>ze(e)));return Y([r,t,o]).pipe(m(([{height:i},{offset:a,size:s},{x:c,y:u}])=>({offset:{x:a.x-c,y:a.y-u+i},size:s})))}function zo(e,{tx$:t}){let r=v(e,"message").pipe(m(({data:n})=>n));return t.pipe(Lt(()=>r,{leading:!0,trailing:!0}),x(n=>e.postMessage(n)),S(()=>r),oe())}var ss=z("#__config"),ht=JSON.parse(ss.textContent);ht.base=`${new URL(ht.base,Se())}`;function he(){return ht}function ee(e){return ht.features.includes(e)}function te(e,t){return typeof t!="undefined"?ht.translations[e].replace("#",t.toString()):ht.translations[e]}function we(e,t=document){return z(`[data-md-component=${e}]`,t)}function ne(e,t=document){return B(`[data-md-component=${e}]`,t)}function cs(e){let t=z(".md-typeset > :first-child",e);return v(t,"click",{once:!0}).pipe(m(()=>z(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function qo(e){return!ee("announce.dismiss")||!e.childElementCount?C:P(()=>{let t=new w;return t.pipe(q({hash:__md_get("__announce")})).subscribe(({hash:r})=>{var n;r&&r===((n=__md_get("__announce"))!=null?n:r)&&(e.hidden=!0,__md_set("__announce",r))}),cs(e).pipe(x(r=>t.next(r)),L(()=>t.complete()),m(r=>H({ref:e},r)))})}function us(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function Qo(e,t){let r=new w;return r.subscribe(({hidden:n})=>{e.hidden=n}),us(e,t).pipe(x(n=>r.next(n)),L(()=>r.complete()),m(n=>H({ref:e},n)))}var ni=Ye(Kr());function Yo(e){return A("aside",{class:"md-annotation",tabIndex:0},A("div",{class:"md-annotation__inner md-tooltip"},A("div",{class:"md-tooltip__inner md-typeset"})),A("span",{class:"md-annotation__index"},A("span",{"data-md-annotation-id":e})))}function Ko(e){return A("button",{class:"md-clipboard md-icon",title:te("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}function Br(e,t){let r=t&2,n=t&1,o=Object.keys(e.terms).filter(a=>!e.terms[a]).reduce((a,s)=>[...a,A("del",null,s)," "],[]).slice(0,-1),i=new URL(e.location);return ee("search.highlight")&&i.searchParams.set("h",Object.entries(e.terms).filter(([,a])=>a).reduce((a,[s])=>`${a} ${s}`.trim(),"")),A("a",{href:`${i}`,class:"md-search-result__link",tabIndex:-1},A("article",{class:["md-search-result__article",...r?["md-search-result__article--document"]:[]].join(" "),"data-md-score":e.score.toFixed(2)},r>0&&A("div",{class:"md-search-result__icon md-icon"}),A("h1",{class:"md-search-result__title"},e.title),n>0&&e.text.length>0&&A("p",{class:"md-search-result__teaser"},ko(e.text,320)),e.tags&&e.tags.map(a=>A("span",{class:"md-tag"},a)),n>0&&o.length>0&&A("p",{class:"md-search-result__terms"},te("search.result.term.missing"),": ",...o)))}function Bo(e){let t=e[0].score,r=[...e],n=r.findIndex(u=>!u.location.includes("#")),[o]=r.splice(n,1),i=r.findIndex(u=>u.scoreBr(u,1)),...s.length?[A("details",{class:"md-search-result__more"},A("summary",{tabIndex:-1},s.length>0&&s.length===1?te("search.result.more.one"):te("search.result.more.other",s.length)),...s.map(u=>Br(u,1)))]:[]];return A("li",{class:"md-search-result__item"},c)}function Go(e){return A("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>A("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?pr(r):r)))}function Gr(e){let t=`tabbed-control tabbed-control--${e}`;return A("div",{class:t,hidden:!0},A("button",{class:"tabbed-button",tabIndex:-1}))}function Jo(e){return A("div",{class:"md-typeset__scrollwrap"},A("div",{class:"md-typeset__table"},e))}function fs(e){let t=he(),r=new URL(`../${e.version}/`,t.base);return A("li",{class:"md-version__item"},A("a",{href:`${r}`,class:"md-version__link"},e.title))}function Xo(e,t){return A("div",{class:"md-version"},A("button",{class:"md-version__current","aria-label":te("select.version.title")},t.title),A("ul",{class:"md-version__list"},e.map(fs)))}function ps(e,t){let r=P(()=>Y([vo(e),pt(t)])).pipe(m(([{x:n,y:o},i])=>{let{width:a}=Ae(e);return{x:n-i.x+a/2,y:o-i.y}}));return nr(e).pipe(S(n=>r.pipe(m(o=>({active:n,offset:o})),se(+!n||1/0))))}function Zo(e,t){return P(()=>{let r=new w;r.subscribe({next({offset:a}){e.style.setProperty("--md-tooltip-x",`${a.x}px`),e.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}});let n=r.pipe(ce(1));cr(e).pipe(Z(n)).subscribe(a=>{e.toggleAttribute("data-md-visible",a)}),r.pipe(Vr(500,Te),m(()=>t.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?e.style.setProperty("--md-tooltip-0",`${-a}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}});let o=z(":scope > :last-child",e),i=v(o,"mousedown",{once:!0});return r.pipe(S(({active:a})=>a?i:C),x(a=>a.preventDefault())).subscribe(()=>e.blur()),ps(e,t).pipe(x(a=>r.next(a)),L(()=>r.complete()),m(a=>H({ref:e},a)))})}function ls(e){let t=[];for(let r of B(".c, .c1, .cm",e)){let n,o=r.firstChild;if(o instanceof Text)for(;n=/\((\d+)\)/.exec(o.textContent);){let i=o.splitText(n.index);o=i.splitText(n[0].length),t.push(i)}}return t}function ei(e,t){t.append(...Array.from(e.childNodes))}function ti(e,t,{print$:r}){let n=new Map;for(let o of ls(t)){let[,i]=o.textContent.match(/\((\d+)\)/);pe(`li:nth-child(${i})`,e)&&(n.set(+i,Yo(+i)),o.replaceWith(n.get(+i)))}return n.size===0?C:P(()=>{let o=new w;return r.pipe(Z(o.pipe(ce(1)))).subscribe(i=>{e.hidden=!i;for(let[a,s]of n){let c=z(".md-typeset",s),u=z(`li:nth-child(${a})`,e);i?ei(c,u):ei(u,c)}}),R(...[...n].map(([,i])=>Zo(i,t))).pipe(L(()=>o.complete()),oe())})}var ms=0;function oi(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return oi(t)}}function ri(e){return de(e).pipe(m(({width:t})=>({scrollable:mt(e).width>t})),J("scrollable"))}function ii(e,t){let{matches:r}=matchMedia("(hover)"),n=P(()=>{let o=new w;if(o.subscribe(({scrollable:a})=>{a&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")}),ni.default.isSupported()){let a=e.closest("pre");a.id=`__code_${++ms}`,a.insertBefore(Ko(a.id),e)}let i=e.closest(".highlight");if(i instanceof HTMLElement){let a=oi(i);if(typeof a!="undefined"&&(i.classList.contains("annotate")||ee("content.code.annotate"))){let s=ti(a,e,t);return ri(e).pipe(x(c=>o.next(c)),L(()=>o.complete()),m(c=>H({ref:e},c)),et(de(i).pipe(Z(o.pipe(ce(1))),m(({width:c,height:u})=>c&&u),K(),S(c=>c?s:C))))}}return ri(e).pipe(x(a=>o.next(a)),L(()=>o.complete()),m(a=>H({ref:e},a)))});return cr(e).pipe(M(o=>o),se(1),S(()=>n))}var ai=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:transparent}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color)}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}defs #flowchart-circleEnd,defs #flowchart-circleStart,defs #flowchart-crossEnd,defs #flowchart-crossStart,defs #flowchart-pointEnd,defs #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}.actor,defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{stroke:var(--md-mermaid-node-fg-color)}text.actor>tspan{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-default-fg-color--lighter)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-edge-color)}.loopText>tspan,.messageText{font-family:var(--md-mermaid-font-family)!important}#arrowhead path,.loopText>tspan,.messageText{fill:var(--md-mermaid-edge-color);stroke:none}.loopLine{stroke:var(--md-mermaid-node-fg-color)}.labelBox,.loopLine{fill:var(--md-mermaid-node-bg-color)}.labelBox{stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-node-fg-color);font-family:var(--md-mermaid-font-family)}";var Jr,hs=0;function bs(){return typeof mermaid=="undefined"||mermaid instanceof Element?Fo("https://unpkg.com/mermaid@9.0.1/dist/mermaid.min.js"):$(void 0)}function si(e){return e.classList.remove("mermaid"),Jr||(Jr=bs().pipe(x(()=>mermaid.initialize({startOnLoad:!1,themeCSS:ai})),m(()=>{}),X(1))),Jr.subscribe(()=>{e.classList.add("mermaid");let t=`__mermaid_${hs++}`,r=A("div",{class:"mermaid"});mermaid.mermaidAPI.render(t,e.textContent,n=>{let o=r.attachShadow({mode:"closed"});o.innerHTML=n,e.replaceWith(r)})}),Jr.pipe(m(()=>({ref:e})))}function vs(e,{target$:t,print$:r}){let n=!0;return R(t.pipe(m(o=>o.closest("details:not([open])")),M(o=>e===o),m(()=>({action:"open",reveal:!0}))),r.pipe(M(o=>o||!n),x(()=>n=e.open),m(o=>({action:o?"open":"close"}))))}function ci(e,t){return P(()=>{let r=new w;return r.subscribe(({action:n,reveal:o})=>{n==="open"?e.setAttribute("open",""):e.removeAttribute("open"),o&&e.scrollIntoView()}),vs(e,t).pipe(x(n=>r.next(n)),L(()=>r.complete()),m(n=>H({ref:e},n)))})}var ui=A("table");function fi(e){return e.replaceWith(ui),ui.replaceWith(Jo(e)),$({ref:e})}function gs(e){let t=B(":scope > input",e),r=t.find(n=>n.checked)||t[0];return R(...t.map(n=>v(n,"change").pipe(m(()=>z(`label[for="${n.id}"]`))))).pipe(q(z(`label[for="${r.id}"]`)),m(n=>({active:n})))}function pi(e){let t=Gr("prev");e.append(t);let r=Gr("next");e.append(r);let n=z(".tabbed-labels",e);return P(()=>{let o=new w,i=o.pipe(ce(1));return Y([o,de(e)]).pipe($e(1,Te),Z(i)).subscribe({next([{active:a},s]){let c=ze(a),{width:u}=Ae(a);e.style.setProperty("--md-indicator-x",`${c.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let f=or(n);(c.xf.x+s.width)&&n.scrollTo({left:Math.max(0,c.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),Y([pt(n),de(n)]).pipe(Z(i)).subscribe(([a,s])=>{let c=mt(n);t.hidden=a.x<16,r.hidden=a.x>c.width-s.width-16}),R(v(t,"click").pipe(m(()=>-1)),v(r,"click").pipe(m(()=>1))).pipe(Z(i)).subscribe(a=>{let{width:s}=Ae(n);n.scrollBy({left:s*a,behavior:"smooth"})}),ee("content.tabs.link")&&o.pipe(Le(1)).subscribe(({active:a})=>{let s=a.innerText.trim();for(let u of B("[data-tabs]"))for(let f of B(":scope > input",u))if(z(`label[for="${f.id}"]`).innerText.trim()===s){f.click();break}let c=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([s,...c])])}),gs(e).pipe(x(a=>o.next(a)),L(()=>o.complete()),m(a=>H({ref:e},a)))}).pipe(Ge(ue))}function li(e,{target$:t,print$:r}){return R(...B("pre:not(.mermaid) > code",e).map(n=>ii(n,{print$:r})),...B("pre.mermaid",e).map(n=>si(n)),...B("table:not([class])",e).map(n=>fi(n)),...B("details",e).map(n=>ci(n,{target$:t,print$:r})),...B("[data-tabs]",e).map(n=>pi(n)))}function ys(e,{alert$:t}){return t.pipe(S(r=>R($(!0),$(!1).pipe(Fe(2e3))).pipe(m(n=>({message:r,active:n})))))}function mi(e,t){let r=z(".md-typeset",e);return P(()=>{let n=new w;return n.subscribe(({message:o,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=o}),ys(e,t).pipe(x(o=>n.next(o)),L(()=>n.complete()),m(o=>H({ref:e},o)))})}function xs({viewport$:e}){if(!ee("header.autohide"))return $(!1);let t=e.pipe(m(({offset:{y:o}})=>o),Me(2,1),m(([o,i])=>[oMath.abs(i-o.y)>100),m(([,[o]])=>o),K()),n=dt("search");return Y([e,n]).pipe(m(([{offset:o},i])=>o.y>400&&!i),K(),S(o=>o?r:$(!1)),q(!1))}function di(e,t){return P(()=>Y([de(e),xs(t)])).pipe(m(([{height:r},n])=>({height:r,hidden:n})),K((r,n)=>r.height===n.height&&r.hidden===n.hidden),X(1))}function hi(e,{header$:t,main$:r}){return P(()=>{let n=new w,o=n.pipe(ce(1));return n.pipe(J("active"),Xe(t)).subscribe(([{active:i},{hidden:a}])=>{e.classList.toggle("md-header--shadow",i&&!a),e.hidden=a}),r.subscribe(n),t.pipe(Z(o),m(i=>H({ref:e},i)))})}function Ss(e,{viewport$:t,header$:r}){return mr(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:n}})=>{let{height:o}=Ae(e);return{active:n>=o}}),J("active"))}function bi(e,t){return P(()=>{let r=new w;r.subscribe(({active:o})=>{e.classList.toggle("md-header__title--active",o)});let n=pe("article h1");return typeof n=="undefined"?C:Ss(n,t).pipe(x(o=>r.next(o)),L(()=>r.complete()),m(o=>H({ref:e},o)))})}function vi(e,{viewport$:t,header$:r}){let n=r.pipe(m(({height:i})=>i),K()),o=n.pipe(S(()=>de(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),J("bottom"))));return Y([n,o,t]).pipe(m(([i,{top:a,bottom:s},{offset:{y:c},size:{height:u}}])=>(u=Math.max(0,u-Math.max(0,a-c,i)-Math.max(0,u+c-s)),{offset:a-i,height:u,active:a-i<=c})),K((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function ws(e){let t=__md_get("__palette")||{index:e.findIndex(r=>matchMedia(r.getAttribute("data-md-color-media")).matches)};return $(...e).pipe(ie(r=>v(r,"change").pipe(m(()=>r))),q(e[Math.max(0,t.index)]),m(r=>({index:e.indexOf(r),color:{scheme:r.getAttribute("data-md-color-scheme"),primary:r.getAttribute("data-md-color-primary"),accent:r.getAttribute("data-md-color-accent")}})),X(1))}function gi(e){return P(()=>{let t=new w;t.subscribe(n=>{document.body.setAttribute("data-md-color-switching","");for(let[o,i]of Object.entries(n.color))document.body.setAttribute(`data-md-color-${o}`,i);for(let o=0;o{document.body.removeAttribute("data-md-color-switching")});let r=B("input",e);return ws(r).pipe(x(n=>t.next(n)),L(()=>t.complete()),m(n=>H({ref:e},n)))})}var Xr=Ye(Kr());function Es(e){e.setAttribute("data-md-copying","");let t=e.innerText;return e.removeAttribute("data-md-copying"),t}function yi({alert$:e}){Xr.default.isSupported()&&new F(t=>{new Xr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||Es(z(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(x(t=>{t.trigger.focus()}),m(()=>te("clipboard.copied"))).subscribe(e)}function Os(e){if(e.length<2)return[""];let[t,r]=[...e].sort((o,i)=>o.length-i.length).map(o=>o.replace(/[^/]+$/,"")),n=0;if(t===r)n=t.length;else for(;t.charCodeAt(n)===r.charCodeAt(n);)n++;return e.map(o=>o.replace(t.slice(0,n),""))}function dr(e){let t=__md_get("__sitemap",sessionStorage,e);if(t)return $(t);{let r=he();return jo(new URL("sitemap.xml",e||r.base)).pipe(m(n=>Os(B("loc",n).map(o=>o.textContent))),ae(()=>C),je([]),x(n=>__md_set("__sitemap",n,sessionStorage,e)))}}function xi({document$:e,location$:t,viewport$:r}){let n=he();if(location.protocol==="file:")return;"scrollRestoration"in history&&(history.scrollRestoration="manual",v(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}));let o=pe("link[rel=icon]");typeof o!="undefined"&&(o.href=o.href);let i=dr().pipe(m(u=>u.map(f=>`${new URL(f,n.base)}`)),S(u=>v(document.body,"click").pipe(M(f=>!f.metaKey&&!f.ctrlKey),S(f=>{if(f.target instanceof Element){let p=f.target.closest("a");if(p&&!p.target){let l=new URL(p.href);if(l.search="",l.hash="",l.pathname!==location.pathname&&u.includes(l.toString()))return f.preventDefault(),$({url:new URL(p.href)})}}return xe}))),oe()),a=v(window,"popstate").pipe(M(u=>u.state!==null),m(u=>({url:new URL(location.href),offset:u.state})),oe());R(i,a).pipe(K((u,f)=>u.url.href===f.url.href),m(({url:u})=>u)).subscribe(t);let s=t.pipe(J("pathname"),S(u=>lr(u.href).pipe(ae(()=>(fr(u),xe)))),oe());i.pipe(ft(s)).subscribe(({url:u})=>{history.pushState({},"",`${u}`)});let c=new DOMParser;s.pipe(S(u=>u.text()),m(u=>c.parseFromString(u,"text/html"))).subscribe(e),e.pipe(Le(1)).subscribe(u=>{for(let f of["title","link[rel=canonical]","meta[name=author]","meta[name=description]","[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...ee("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let p=pe(f),l=pe(f,u);typeof p!="undefined"&&typeof l!="undefined"&&p.replaceWith(l)}}),e.pipe(Le(1),m(()=>we("container")),S(u=>B("script",u)),Ir(u=>{let f=A("script");if(u.src){for(let p of u.getAttributeNames())f.setAttribute(p,u.getAttribute(p));return u.replaceWith(f),new F(p=>{f.onload=()=>p.complete()})}else return f.textContent=u.textContent,u.replaceWith(f),C})).subscribe(),R(i,a).pipe(ft(e)).subscribe(({url:u,offset:f})=>{u.hash&&!f?Po(u.hash):window.scrollTo(0,(f==null?void 0:f.y)||0)}),r.pipe(Mt(i),Ze(250),J("offset")).subscribe(({offset:u})=>{history.replaceState(u,"")}),R(i,a).pipe(Me(2,1),M(([u,f])=>u.url.pathname===f.url.pathname),m(([,u])=>u)).subscribe(({offset:u})=>{window.scrollTo(0,(u==null?void 0:u.y)||0)})}var Ms=Ye(Zr());var wi=Ye(Zr());function en(e,t){let r=new RegExp(e.separator,"img"),n=(o,i,a)=>`${i}${a}`;return o=>{o=o.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator})(${o.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(t?(0,wi.default)(a):a).replace(i,n).replace(/<\/mark>(\s+)]*>/img,"$1")}}function Ei(e){return e.split(/"([^"]+)"/g).map((t,r)=>r&1?t.replace(/^\b|^(?![^\x00-\x7F]|$)|\s+/g," +"):t).join("").replace(/"|(?:^|\s+)[*+\-:^~]+(?=\s+|$)/g,"").trim()}function bt(e){return e.type===1}function Oi(e){return e.type===2}function vt(e){return e.type===3}function As({config:e,docs:t}){e.lang.length===1&&e.lang[0]==="en"&&(e.lang=[te("search.config.lang")]),e.separator==="[\\s\\-]+"&&(e.separator=te("search.config.separator"));let n={pipeline:te("search.config.pipeline").split(/\s*,\s*/).filter(Boolean),suggestions:ee("search.suggest")};return{config:e,docs:t,options:n}}function _i(e,t){let r=he(),n=new Worker(e),o=new w,i=zo(n,{tx$:o}).pipe(m(a=>{if(vt(a))for(let s of a.data.items)for(let c of s)c.location=`${new URL(c.location,r.base)}`;return a}),oe());return fe(t).pipe(m(a=>({type:0,data:As(a)}))).subscribe(o.next.bind(o)),{tx$:o,rx$:i}}function Ti({document$:e}){let t=he(),r=ke(new URL("../versions.json",t.base)).pipe(ae(()=>C)),n=r.pipe(m(o=>{let[,i]=t.base.match(/([^/]+)\/?$/);return o.find(({version:a,aliases:s})=>a===i||s.includes(i))||o[0]}));r.pipe(m(o=>new Map(o.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),S(o=>v(document.body,"click").pipe(M(i=>!i.metaKey&&!i.ctrlKey),ge(n),S(([i,a])=>{if(i.target instanceof Element){let s=i.target.closest("a");if(s&&!s.target&&o.has(s.href)){let c=s.href;return!i.target.closest(".md-version")&&o.get(c)===a?C:(i.preventDefault(),$(c))}}return C}),S(i=>{let{version:a}=o.get(i);return dr(new URL(i)).pipe(m(s=>{let u=Se().href.replace(t.base,"");return s.includes(u.split("#")[0])?new URL(`../${a}/${u}`,t.base):new URL(i)}))})))).subscribe(o=>fr(o)),Y([r,n]).subscribe(([o,i])=>{z(".md-header__topic").appendChild(Xo(o,i))}),e.pipe(S(()=>n)).subscribe(o=>{var a;let i=__md_get("__outdated",sessionStorage);if(i===null){let s=((a=t.version)==null?void 0:a.default)||"latest";i=!o.aliases.includes(s),__md_set("__outdated",i,sessionStorage)}if(i)for(let s of ne("outdated"))s.hidden=!1})}function Cs(e,{rx$:t}){let r=(__search==null?void 0:__search.transform)||Ei,{searchParams:n}=Se();n.has("q")&&qe("search",!0);let o=t.pipe(M(bt),se(1),m(()=>n.get("q")||""));dt("search").pipe(M(s=>!s),se(1)).subscribe(()=>{let s=new URL(location.href);s.searchParams.delete("q"),history.replaceState({},"",`${s}`)}),o.subscribe(s=>{s&&(e.value=s,e.focus())});let i=nr(e),a=R(v(e,"keyup"),v(e,"focus").pipe(Fe(1)),o).pipe(m(()=>r(e.value)),q(""),K());return Y([a,i]).pipe(m(([s,c])=>({value:s,focus:c})),X(1))}function Mi(e,{tx$:t,rx$:r}){let n=new w,o=n.pipe(ce(1));return n.pipe(J("value"),m(({value:i})=>({type:2,data:i}))).subscribe(t.next.bind(t)),n.pipe(J("focus")).subscribe(({focus:i})=>{i?(qe("search",i),e.placeholder=""):e.placeholder=te("search.placeholder")}),v(e.form,"reset").pipe(Z(o)).subscribe(()=>e.focus()),Cs(e,{tx$:t,rx$:r}).pipe(x(i=>n.next(i)),L(()=>n.complete()),m(i=>H({ref:e},i)),oe())}function Li(e,{rx$:t},{query$:r}){let n=new w,o=Mo(e.parentElement).pipe(M(Boolean)),i=z(":scope > :first-child",e),a=z(":scope > :last-child",e),s=t.pipe(M(bt),se(1));return n.pipe(ge(r),Mt(s)).subscribe(([{items:u},{value:f}])=>{if(f)switch(u.length){case 0:i.textContent=te("search.result.none");break;case 1:i.textContent=te("search.result.one");break;default:i.textContent=te("search.result.other",pr(u.length))}else i.textContent=te("search.result.placeholder")}),n.pipe(x(()=>a.innerHTML=""),S(({items:u})=>R($(...u.slice(0,10)),$(...u.slice(10)).pipe(Me(4),Nr(o),S(([f])=>f))))).subscribe(u=>a.appendChild(Bo(u))),t.pipe(M(vt),m(({data:u})=>u)).pipe(x(u=>n.next(u)),L(()=>n.complete()),m(u=>H({ref:e},u)))}function Rs(e,{query$:t}){return t.pipe(m(({value:r})=>{let n=Se();return n.hash="",n.searchParams.delete("h"),n.searchParams.set("q",r),{url:n}}))}function Ai(e,t){let r=new w;return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),v(e,"click").subscribe(n=>n.preventDefault()),Rs(e,t).pipe(x(n=>r.next(n)),L(()=>r.complete()),m(n=>H({ref:e},n)))}function Ci(e,{rx$:t},{keyboard$:r}){let n=new w,o=we("search-query"),i=R(v(o,"keydown"),v(o,"focus")).pipe(Ie(ue),m(()=>o.value),K());return n.pipe(Xe(i),m(([{suggestions:s},c])=>{let u=c.split(/([\s-]+)/);if((s==null?void 0:s.length)&&u[u.length-1]){let f=s[s.length-1];f.startsWith(u[u.length-1])&&(u[u.length-1]=f)}else u.length=0;return u})).subscribe(s=>e.innerHTML=s.join("").replace(/\s/g," ")),r.pipe(M(({mode:s})=>s==="search")).subscribe(s=>{switch(s.type){case"ArrowRight":e.innerText.length&&o.selectionStart===o.value.length&&(o.value=e.innerText);break}}),t.pipe(M(vt),m(({data:s})=>s)).pipe(x(s=>n.next(s)),L(()=>n.complete()),m(()=>({ref:e})))}function Ri(e,{index$:t,keyboard$:r}){let n=he();try{let o=(__search==null?void 0:__search.worker)||n.search,i=_i(o,t),a=we("search-query",e),s=we("search-result",e),{tx$:c,rx$:u}=i;c.pipe(M(Oi),ft(u.pipe(M(bt))),se(1)).subscribe(c.next.bind(c)),r.pipe(M(({mode:l})=>l==="search")).subscribe(l=>{let d=Ne();switch(l.type){case"Enter":if(d===a){let h=new Map;for(let b of B(":first-child [href]",s)){let U=b.firstElementChild;h.set(b,parseFloat(U.getAttribute("data-md-score")))}if(h.size){let[[b]]=[...h].sort(([,U],[,G])=>G-U);b.click()}l.claim()}break;case"Escape":case"Tab":qe("search",!1),a.blur();break;case"ArrowUp":case"ArrowDown":if(typeof d=="undefined")a.focus();else{let h=[a,...B(":not(details) > [href], summary, details[open] [href]",s)],b=Math.max(0,(Math.max(0,h.indexOf(d))+h.length+(l.type==="ArrowUp"?-1:1))%h.length);h[b].focus()}l.claim();break;default:a!==Ne()&&a.focus()}}),r.pipe(M(({mode:l})=>l==="global")).subscribe(l=>{switch(l.type){case"f":case"s":case"/":a.focus(),a.select(),l.claim();break}});let f=Mi(a,i),p=Li(s,i,{query$:f});return R(f,p).pipe(et(...ne("search-share",e).map(l=>Ai(l,{query$:f})),...ne("search-suggest",e).map(l=>Ci(l,i,{keyboard$:r}))))}catch(o){return e.hidden=!0,xe}}function ki(e,{index$:t,location$:r}){return Y([t,r.pipe(q(Se()),M(n=>!!n.searchParams.get("h")))]).pipe(m(([n,o])=>en(n.config,!0)(o.searchParams.get("h"))),m(n=>{var a;let o=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let s=i.nextNode();s;s=i.nextNode())if((a=s.parentElement)!=null&&a.offsetHeight){let c=s.textContent,u=n(c);u.length>c.length&&o.set(s,u)}for(let[s,c]of o){let{childNodes:u}=A("span",null,c);s.replaceWith(...Array.from(u))}return{ref:e,nodes:o}}))}function ks(e,{viewport$:t,main$:r}){let n=e.parentElement,o=n.offsetTop-n.parentElement.offsetTop;return Y([r,t]).pipe(m(([{offset:i,height:a},{offset:{y:s}}])=>(a=a+Math.min(o,Math.max(0,s-i))-o,{height:a,locked:s>=i+o})),K((i,a)=>i.height===a.height&&i.locked===a.locked))}function tn(e,n){var o=n,{header$:t}=o,r=cn(o,["header$"]);let i=z(".md-sidebar__scrollwrap",e),{y:a}=ze(i);return P(()=>{let s=new w;return s.pipe($e(0,Te),ge(t)).subscribe({next([{height:c},{height:u}]){i.style.height=`${c-2*a}px`,e.style.top=`${u}px`},complete(){i.style.height="",e.style.top=""}}),ks(e,r).pipe(x(c=>s.next(c)),L(()=>s.complete()),m(c=>H({ref:e},c)))})}function Hi(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return _t(ke(`${r}/releases/latest`).pipe(ae(()=>C),m(n=>({version:n.tag_name})),je({})),ke(r).pipe(ae(()=>C),m(n=>({stars:n.stargazers_count,forks:n.forks_count})),je({}))).pipe(m(([n,o])=>H(H({},n),o)))}else{let r=`https://api.github.com/users/${e}`;return ke(r).pipe(m(n=>({repositories:n.public_repos})),je({}))}}function Pi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return ke(r).pipe(ae(()=>C),m(({star_count:n,forks_count:o})=>({stars:n,forks:o})),je({}))}function Ii(e){let[t]=e.match(/(git(?:hub|lab))/i)||[];switch(t.toLowerCase()){case"github":let[,r,n]=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);return Hi(r,n);case"gitlab":let[,o,i]=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i);return Pi(o,i);default:return C}}var Hs;function Ps(e){return Hs||(Hs=P(()=>{let t=__md_get("__source",sessionStorage);return t?$(t):Ii(e.href).pipe(x(r=>__md_set("__source",r,sessionStorage)))}).pipe(ae(()=>C),M(t=>Object.keys(t).length>0),m(t=>({facts:t})),X(1)))}function $i(e){let t=z(":scope > :last-child",e);return P(()=>{let r=new w;return r.subscribe(({facts:n})=>{t.appendChild(Go(n)),t.classList.add("md-source__repository--active")}),Ps(e).pipe(x(n=>r.next(n)),L(()=>r.complete()),m(n=>H({ref:e},n)))})}function Is(e,{viewport$:t,header$:r}){return de(document.body).pipe(S(()=>mr(e,{header$:r,viewport$:t})),m(({offset:{y:n}})=>({hidden:n>=10})),J("hidden"))}function ji(e,t){return P(()=>{let r=new w;return r.subscribe({next({hidden:n}){e.hidden=n},complete(){e.hidden=!1}}),(ee("navigation.tabs.sticky")?$({hidden:!1}):Is(e,t)).pipe(x(n=>r.next(n)),L(()=>r.complete()),m(n=>H({ref:e},n)))})}function $s(e,{viewport$:t,header$:r}){let n=new Map,o=B("[href^=\\#]",e);for(let s of o){let c=decodeURIComponent(s.hash.substring(1)),u=pe(`[id="${c}"]`);typeof u!="undefined"&&n.set(s,u)}let i=r.pipe(J("height"),m(({height:s})=>{let c=we("main"),u=z(":scope > :first-child",c);return s+.8*(u.offsetTop-c.offsetTop)}),oe());return de(document.body).pipe(J("height"),S(s=>P(()=>{let c=[];return $([...n].reduce((u,[f,p])=>{for(;c.length&&n.get(c[c.length-1]).tagName>=p.tagName;)c.pop();let l=p.offsetTop;for(;!l&&p.parentElement;)p=p.parentElement,l=p.offsetTop;return u.set([...c=[...c,f]].reverse(),l)},new Map))}).pipe(m(c=>new Map([...c].sort(([,u],[,f])=>u-f))),Xe(i),S(([c,u])=>t.pipe(Fr(([f,p],{offset:{y:l},size:d})=>{let h=l+d.height>=Math.floor(s.height);for(;p.length;){let[,b]=p[0];if(b-u=l&&!h)p=[f.pop(),...p];else break}return[f,p]},[[],[...c]]),K((f,p)=>f[0]===p[0]&&f[1]===p[1])))))).pipe(m(([s,c])=>({prev:s.map(([u])=>u),next:c.map(([u])=>u)})),q({prev:[],next:[]}),Me(2,1),m(([s,c])=>s.prev.length{let o=new w,i=o.pipe(ce(1));return o.subscribe(({prev:a,next:s})=>{for(let[c]of s)c.classList.remove("md-nav__link--passed"),c.classList.remove("md-nav__link--active");for(let[c,[u]]of a.entries())u.classList.add("md-nav__link--passed"),u.classList.toggle("md-nav__link--active",c===a.length-1)}),ee("navigation.tracking")&&t.pipe(Z(i),J("offset"),Ze(250),Le(1),Z(n.pipe(Le(1))),Tt({delay:250}),ge(o)).subscribe(([,{prev:a}])=>{let s=Se(),c=a[a.length-1];if(c&&c.length){let[u]=c,{hash:f}=new URL(u.href);s.hash!==f&&(s.hash=f,history.replaceState({},"",`${s}`))}else s.hash="",history.replaceState({},"",`${s}`)}),$s(e,{viewport$:t,header$:r}).pipe(x(a=>o.next(a)),L(()=>o.complete()),m(a=>H({ref:e},a)))})}function js(e,{viewport$:t,main$:r,target$:n}){let o=t.pipe(m(({offset:{y:a}})=>a),Me(2,1),m(([a,s])=>a>s&&s>0),K()),i=r.pipe(m(({active:a})=>a));return Y([i,o]).pipe(m(([a,s])=>!(a&&s)),K(),Z(n.pipe(Le(1))),jr(!0),Tt({delay:250}),m(a=>({hidden:a})))}function Ui(e,{viewport$:t,header$:r,main$:n,target$:o}){let i=new w,a=i.pipe(ce(1));return i.subscribe({next({hidden:s}){e.hidden=s,s?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(Z(a),J("height")).subscribe(({height:s})=>{e.style.top=`${s+16}px`}),js(e,{viewport$:t,main$:n,target$:o}).pipe(x(s=>i.next(s)),L(()=>i.complete()),m(s=>H({ref:e},s)))}function Di({document$:e,tablet$:t}){e.pipe(S(()=>B(".md-toggle--indeterminate, [data-md-state=indeterminate]")),x(r=>{r.indeterminate=!0,r.checked=!1}),ie(r=>v(r,"change").pipe(Dr(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),ge(t)).subscribe(([r,n])=>{r.classList.remove("md-toggle--indeterminate"),n&&(r.checked=!1)})}function Fs(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Wi({document$:e}){e.pipe(S(()=>B("[data-md-scrollfix]")),x(t=>t.removeAttribute("data-md-scrollfix")),M(Fs),ie(t=>v(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Vi({viewport$:e,tablet$:t}){Y([dt("search"),t]).pipe(m(([r,n])=>r&&!n),S(r=>$(r).pipe(Fe(r?400:100))),ge(e)).subscribe(([r,{offset:{y:n}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${n}px`;else{let o=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",o&&window.scrollTo(0,o)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let n=e[r];typeof n!="object"?n=document.createTextNode(n):n.parentNode&&n.parentNode.removeChild(n),r?t.insertBefore(this.previousSibling,n):t.replaceChild(n,this)}}}));document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var tt=bo(),br=Co(),gt=Io(),rn=Ao(),Ee=No(),vr=qr("(min-width: 960px)"),zi=qr("(min-width: 1220px)"),qi=$o(),Qi=he(),Yi=document.forms.namedItem("search")?(__search==null?void 0:__search.index)||ke(new URL("search/search_index.json",Qi.base)):xe,nn=new w;yi({alert$:nn});ee("navigation.instant")&&xi({document$:tt,location$:br,viewport$:Ee});var Ni;((Ni=Qi.version)==null?void 0:Ni.provider)==="mike"&&Ti({document$:tt});R(br,gt).pipe(Fe(125)).subscribe(()=>{qe("drawer",!1),qe("search",!1)});rn.pipe(M(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=pe("[href][rel=prev]");typeof t!="undefined"&&t.click();break;case"n":case".":let r=pe("[href][rel=next]");typeof r!="undefined"&&r.click();break}});Di({document$:tt,tablet$:vr});Wi({document$:tt});Vi({viewport$:Ee,tablet$:vr});var Qe=di(we("header"),{viewport$:Ee}),hr=tt.pipe(m(()=>we("main")),S(e=>vi(e,{viewport$:Ee,header$:Qe})),X(1)),Us=R(...ne("consent").map(e=>Qo(e,{target$:gt})),...ne("dialog").map(e=>mi(e,{alert$:nn})),...ne("header").map(e=>hi(e,{viewport$:Ee,header$:Qe,main$:hr})),...ne("palette").map(e=>gi(e)),...ne("search").map(e=>Ri(e,{index$:Yi,keyboard$:rn})),...ne("source").map(e=>$i(e))),Ds=P(()=>R(...ne("announce").map(e=>qo(e)),...ne("content").map(e=>li(e,{target$:gt,print$:qi})),...ne("content").map(e=>ee("search.highlight")?ki(e,{index$:Yi,location$:br}):C),...ne("header-title").map(e=>bi(e,{viewport$:Ee,header$:Qe})),...ne("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Qr(zi,()=>tn(e,{viewport$:Ee,header$:Qe,main$:hr})):Qr(vr,()=>tn(e,{viewport$:Ee,header$:Qe,main$:hr}))),...ne("tabs").map(e=>ji(e,{viewport$:Ee,header$:Qe})),...ne("toc").map(e=>Fi(e,{viewport$:Ee,header$:Qe,target$:gt})),...ne("top").map(e=>Ui(e,{viewport$:Ee,header$:Qe,main$:hr,target$:gt})))),Ki=tt.pipe(S(()=>Ds),et(Us),X(1));Ki.subscribe();window.document$=tt;window.location$=br;window.target$=gt;window.keyboard$=rn;window.viewport$=Ee;window.tablet$=vr;window.screen$=zi;window.print$=qi;window.alert$=nn;window.component$=Ki;})(); -//# sourceMappingURL=bundle.2ab50757.min.js.map - diff --git a/assets/javascripts/bundle.2ab50757.min.js.map b/assets/javascripts/bundle.2ab50757.min.js.map deleted file mode 100644 index 05d622de..00000000 --- a/assets/javascripts/bundle.2ab50757.min.js.map +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version": 3, - "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/url-polyfill/url-polyfill.js", "node_modules/rxjs/node_modules/tslib/tslib.js", "node_modules/clipboard/dist/clipboard.js", "node_modules/escape-html/index.js", "node_modules/array-flat-polyfill/index.mjs", "src/assets/javascripts/bundle.ts", "node_modules/unfetch/polyfill/index.js", "node_modules/rxjs/node_modules/tslib/modules/index.js", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/concatMap.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/sample.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/assets/javascripts/browser/document/index.ts", "src/assets/javascripts/browser/element/_/index.ts", "src/assets/javascripts/browser/element/focus/index.ts", "src/assets/javascripts/browser/element/offset/_/index.ts", "src/assets/javascripts/browser/element/offset/content/index.ts", "node_modules/resize-observer-polyfill/dist/ResizeObserver.es.js", "src/assets/javascripts/browser/element/size/_/index.ts", "src/assets/javascripts/browser/element/size/content/index.ts", "src/assets/javascripts/browser/element/visibility/index.ts", "src/assets/javascripts/browser/toggle/index.ts", "src/assets/javascripts/browser/keyboard/index.ts", "src/assets/javascripts/browser/location/_/index.ts", "src/assets/javascripts/utilities/h/index.ts", "src/assets/javascripts/utilities/string/index.ts", "src/assets/javascripts/browser/location/hash/index.ts", "src/assets/javascripts/browser/media/index.ts", "src/assets/javascripts/browser/request/index.ts", "src/assets/javascripts/browser/script/index.ts", "src/assets/javascripts/browser/viewport/offset/index.ts", "src/assets/javascripts/browser/viewport/size/index.ts", "src/assets/javascripts/browser/viewport/_/index.ts", "src/assets/javascripts/browser/viewport/at/index.ts", "src/assets/javascripts/browser/worker/index.ts", "src/assets/javascripts/_/index.ts", "src/assets/javascripts/components/_/index.ts", "src/assets/javascripts/components/announce/index.ts", "src/assets/javascripts/components/consent/index.ts", "src/assets/javascripts/components/content/code/_/index.ts", "src/assets/javascripts/templates/annotation/index.tsx", "src/assets/javascripts/templates/clipboard/index.tsx", "src/assets/javascripts/templates/search/index.tsx", "src/assets/javascripts/templates/source/index.tsx", "src/assets/javascripts/templates/tabbed/index.tsx", "src/assets/javascripts/templates/table/index.tsx", "src/assets/javascripts/templates/version/index.tsx", "src/assets/javascripts/components/content/annotation/_/index.ts", "src/assets/javascripts/components/content/annotation/list/index.ts", "src/assets/javascripts/components/content/code/mermaid/index.ts", "src/assets/javascripts/components/content/details/index.ts", "src/assets/javascripts/components/content/table/index.ts", "src/assets/javascripts/components/content/tabs/index.ts", "src/assets/javascripts/components/content/_/index.ts", "src/assets/javascripts/components/dialog/index.ts", "src/assets/javascripts/components/header/_/index.ts", "src/assets/javascripts/components/header/title/index.ts", "src/assets/javascripts/components/main/index.ts", "src/assets/javascripts/components/palette/index.ts", "src/assets/javascripts/integrations/clipboard/index.ts", "src/assets/javascripts/integrations/sitemap/index.ts", "src/assets/javascripts/integrations/instant/index.ts", "src/assets/javascripts/integrations/search/document/index.ts", "src/assets/javascripts/integrations/search/highlighter/index.ts", "src/assets/javascripts/integrations/search/query/transform/index.ts", "src/assets/javascripts/integrations/search/worker/message/index.ts", "src/assets/javascripts/integrations/search/worker/_/index.ts", "src/assets/javascripts/integrations/version/index.ts", "src/assets/javascripts/components/search/query/index.ts", "src/assets/javascripts/components/search/result/index.ts", "src/assets/javascripts/components/search/share/index.ts", "src/assets/javascripts/components/search/suggest/index.ts", "src/assets/javascripts/components/search/_/index.ts", "src/assets/javascripts/components/search/highlight/index.ts", "src/assets/javascripts/components/sidebar/index.ts", "src/assets/javascripts/components/source/facts/github/index.ts", "src/assets/javascripts/components/source/facts/gitlab/index.ts", "src/assets/javascripts/components/source/facts/_/index.ts", "src/assets/javascripts/components/source/_/index.ts", "src/assets/javascripts/components/tabs/index.ts", "src/assets/javascripts/components/toc/index.ts", "src/assets/javascripts/components/top/index.ts", "src/assets/javascripts/patches/indeterminate/index.ts", "src/assets/javascripts/patches/scrollfix/index.ts", "src/assets/javascripts/patches/scrolllock/index.ts", "src/assets/javascripts/polyfills/index.ts"], - "sourceRoot": "../../../..", - "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "(function(global) {\r\n /**\r\n * Polyfill URLSearchParams\r\n *\r\n * Inspired from : https://github.com/WebReflection/url-search-params/blob/master/src/url-search-params.js\r\n */\r\n\r\n var checkIfIteratorIsSupported = function() {\r\n try {\r\n return !!Symbol.iterator;\r\n } catch (error) {\r\n return false;\r\n }\r\n };\r\n\r\n\r\n var iteratorSupported = checkIfIteratorIsSupported();\r\n\r\n var createIterator = function(items) {\r\n var iterator = {\r\n next: function() {\r\n var value = items.shift();\r\n return { done: value === void 0, value: value };\r\n }\r\n };\r\n\r\n if (iteratorSupported) {\r\n iterator[Symbol.iterator] = function() {\r\n return iterator;\r\n };\r\n }\r\n\r\n return iterator;\r\n };\r\n\r\n /**\r\n * Search param name and values should be encoded according to https://url.spec.whatwg.org/#urlencoded-serializing\r\n * encodeURIComponent() produces the same result except encoding spaces as `%20` instead of `+`.\r\n */\r\n var serializeParam = function(value) {\r\n return encodeURIComponent(value).replace(/%20/g, '+');\r\n };\r\n\r\n var deserializeParam = function(value) {\r\n return decodeURIComponent(String(value).replace(/\\+/g, ' '));\r\n };\r\n\r\n var polyfillURLSearchParams = function() {\r\n\r\n var URLSearchParams = function(searchString) {\r\n Object.defineProperty(this, '_entries', { writable: true, value: {} });\r\n var typeofSearchString = typeof searchString;\r\n\r\n if (typeofSearchString === 'undefined') {\r\n // do nothing\r\n } else if (typeofSearchString === 'string') {\r\n if (searchString !== '') {\r\n this._fromString(searchString);\r\n }\r\n } else if (searchString instanceof URLSearchParams) {\r\n var _this = this;\r\n searchString.forEach(function(value, name) {\r\n _this.append(name, value);\r\n });\r\n } else if ((searchString !== null) && (typeofSearchString === 'object')) {\r\n if (Object.prototype.toString.call(searchString) === '[object Array]') {\r\n for (var i = 0; i < searchString.length; i++) {\r\n var entry = searchString[i];\r\n if ((Object.prototype.toString.call(entry) === '[object Array]') || (entry.length !== 2)) {\r\n this.append(entry[0], entry[1]);\r\n } else {\r\n throw new TypeError('Expected [string, any] as entry at index ' + i + ' of URLSearchParams\\'s input');\r\n }\r\n }\r\n } else {\r\n for (var key in searchString) {\r\n if (searchString.hasOwnProperty(key)) {\r\n this.append(key, searchString[key]);\r\n }\r\n }\r\n }\r\n } else {\r\n throw new TypeError('Unsupported input\\'s type for URLSearchParams');\r\n }\r\n };\r\n\r\n var proto = URLSearchParams.prototype;\r\n\r\n proto.append = function(name, value) {\r\n if (name in this._entries) {\r\n this._entries[name].push(String(value));\r\n } else {\r\n this._entries[name] = [String(value)];\r\n }\r\n };\r\n\r\n proto.delete = function(name) {\r\n delete this._entries[name];\r\n };\r\n\r\n proto.get = function(name) {\r\n return (name in this._entries) ? this._entries[name][0] : null;\r\n };\r\n\r\n proto.getAll = function(name) {\r\n return (name in this._entries) ? this._entries[name].slice(0) : [];\r\n };\r\n\r\n proto.has = function(name) {\r\n return (name in this._entries);\r\n };\r\n\r\n proto.set = function(name, value) {\r\n this._entries[name] = [String(value)];\r\n };\r\n\r\n proto.forEach = function(callback, thisArg) {\r\n var entries;\r\n for (var name in this._entries) {\r\n if (this._entries.hasOwnProperty(name)) {\r\n entries = this._entries[name];\r\n for (var i = 0; i < entries.length; i++) {\r\n callback.call(thisArg, entries[i], name, this);\r\n }\r\n }\r\n }\r\n };\r\n\r\n proto.keys = function() {\r\n var items = [];\r\n this.forEach(function(value, name) {\r\n items.push(name);\r\n });\r\n return createIterator(items);\r\n };\r\n\r\n proto.values = function() {\r\n var items = [];\r\n this.forEach(function(value) {\r\n items.push(value);\r\n });\r\n return createIterator(items);\r\n };\r\n\r\n proto.entries = function() {\r\n var items = [];\r\n this.forEach(function(value, name) {\r\n items.push([name, value]);\r\n });\r\n return createIterator(items);\r\n };\r\n\r\n if (iteratorSupported) {\r\n proto[Symbol.iterator] = proto.entries;\r\n }\r\n\r\n proto.toString = function() {\r\n var searchArray = [];\r\n this.forEach(function(value, name) {\r\n searchArray.push(serializeParam(name) + '=' + serializeParam(value));\r\n });\r\n return searchArray.join('&');\r\n };\r\n\r\n\r\n global.URLSearchParams = URLSearchParams;\r\n };\r\n\r\n var checkIfURLSearchParamsSupported = function() {\r\n try {\r\n var URLSearchParams = global.URLSearchParams;\r\n\r\n return (\r\n (new URLSearchParams('?a=1').toString() === 'a=1') &&\r\n (typeof URLSearchParams.prototype.set === 'function') &&\r\n (typeof URLSearchParams.prototype.entries === 'function')\r\n );\r\n } catch (e) {\r\n return false;\r\n }\r\n };\r\n\r\n if (!checkIfURLSearchParamsSupported()) {\r\n polyfillURLSearchParams();\r\n }\r\n\r\n var proto = global.URLSearchParams.prototype;\r\n\r\n if (typeof proto.sort !== 'function') {\r\n proto.sort = function() {\r\n var _this = this;\r\n var items = [];\r\n this.forEach(function(value, name) {\r\n items.push([name, value]);\r\n if (!_this._entries) {\r\n _this.delete(name);\r\n }\r\n });\r\n items.sort(function(a, b) {\r\n if (a[0] < b[0]) {\r\n return -1;\r\n } else if (a[0] > b[0]) {\r\n return +1;\r\n } else {\r\n return 0;\r\n }\r\n });\r\n if (_this._entries) { // force reset because IE keeps keys index\r\n _this._entries = {};\r\n }\r\n for (var i = 0; i < items.length; i++) {\r\n this.append(items[i][0], items[i][1]);\r\n }\r\n };\r\n }\r\n\r\n if (typeof proto._fromString !== 'function') {\r\n Object.defineProperty(proto, '_fromString', {\r\n enumerable: false,\r\n configurable: false,\r\n writable: false,\r\n value: function(searchString) {\r\n if (this._entries) {\r\n this._entries = {};\r\n } else {\r\n var keys = [];\r\n this.forEach(function(value, name) {\r\n keys.push(name);\r\n });\r\n for (var i = 0; i < keys.length; i++) {\r\n this.delete(keys[i]);\r\n }\r\n }\r\n\r\n searchString = searchString.replace(/^\\?/, '');\r\n var attributes = searchString.split('&');\r\n var attribute;\r\n for (var i = 0; i < attributes.length; i++) {\r\n attribute = attributes[i].split('=');\r\n this.append(\r\n deserializeParam(attribute[0]),\r\n (attribute.length > 1) ? deserializeParam(attribute[1]) : ''\r\n );\r\n }\r\n }\r\n });\r\n }\r\n\r\n // HTMLAnchorElement\r\n\r\n})(\r\n (typeof global !== 'undefined') ? global\r\n : ((typeof window !== 'undefined') ? window\r\n : ((typeof self !== 'undefined') ? self : this))\r\n);\r\n\r\n(function(global) {\r\n /**\r\n * Polyfill URL\r\n *\r\n * Inspired from : https://github.com/arv/DOM-URL-Polyfill/blob/master/src/url.js\r\n */\r\n\r\n var checkIfURLIsSupported = function() {\r\n try {\r\n var u = new global.URL('b', 'http://a');\r\n u.pathname = 'c d';\r\n return (u.href === 'http://a/c%20d') && u.searchParams;\r\n } catch (e) {\r\n return false;\r\n }\r\n };\r\n\r\n\r\n var polyfillURL = function() {\r\n var _URL = global.URL;\r\n\r\n var URL = function(url, base) {\r\n if (typeof url !== 'string') url = String(url);\r\n if (base && typeof base !== 'string') base = String(base);\r\n\r\n // Only create another document if the base is different from current location.\r\n var doc = document, baseElement;\r\n if (base && (global.location === void 0 || base !== global.location.href)) {\r\n base = base.toLowerCase();\r\n doc = document.implementation.createHTMLDocument('');\r\n baseElement = doc.createElement('base');\r\n baseElement.href = base;\r\n doc.head.appendChild(baseElement);\r\n try {\r\n if (baseElement.href.indexOf(base) !== 0) throw new Error(baseElement.href);\r\n } catch (err) {\r\n throw new Error('URL unable to set base ' + base + ' due to ' + err);\r\n }\r\n }\r\n\r\n var anchorElement = doc.createElement('a');\r\n anchorElement.href = url;\r\n if (baseElement) {\r\n doc.body.appendChild(anchorElement);\r\n anchorElement.href = anchorElement.href; // force href to refresh\r\n }\r\n\r\n var inputElement = doc.createElement('input');\r\n inputElement.type = 'url';\r\n inputElement.value = url;\r\n\r\n if (anchorElement.protocol === ':' || !/:/.test(anchorElement.href) || (!inputElement.checkValidity() && !base)) {\r\n throw new TypeError('Invalid URL');\r\n }\r\n\r\n Object.defineProperty(this, '_anchorElement', {\r\n value: anchorElement\r\n });\r\n\r\n\r\n // create a linked searchParams which reflect its changes on URL\r\n var searchParams = new global.URLSearchParams(this.search);\r\n var enableSearchUpdate = true;\r\n var enableSearchParamsUpdate = true;\r\n var _this = this;\r\n ['append', 'delete', 'set'].forEach(function(methodName) {\r\n var method = searchParams[methodName];\r\n searchParams[methodName] = function() {\r\n method.apply(searchParams, arguments);\r\n if (enableSearchUpdate) {\r\n enableSearchParamsUpdate = false;\r\n _this.search = searchParams.toString();\r\n enableSearchParamsUpdate = true;\r\n }\r\n };\r\n });\r\n\r\n Object.defineProperty(this, 'searchParams', {\r\n value: searchParams,\r\n enumerable: true\r\n });\r\n\r\n var search = void 0;\r\n Object.defineProperty(this, '_updateSearchParams', {\r\n enumerable: false,\r\n configurable: false,\r\n writable: false,\r\n value: function() {\r\n if (this.search !== search) {\r\n search = this.search;\r\n if (enableSearchParamsUpdate) {\r\n enableSearchUpdate = false;\r\n this.searchParams._fromString(this.search);\r\n enableSearchUpdate = true;\r\n }\r\n }\r\n }\r\n });\r\n };\r\n\r\n var proto = URL.prototype;\r\n\r\n var linkURLWithAnchorAttribute = function(attributeName) {\r\n Object.defineProperty(proto, attributeName, {\r\n get: function() {\r\n return this._anchorElement[attributeName];\r\n },\r\n set: function(value) {\r\n this._anchorElement[attributeName] = value;\r\n },\r\n enumerable: true\r\n });\r\n };\r\n\r\n ['hash', 'host', 'hostname', 'port', 'protocol']\r\n .forEach(function(attributeName) {\r\n linkURLWithAnchorAttribute(attributeName);\r\n });\r\n\r\n Object.defineProperty(proto, 'search', {\r\n get: function() {\r\n return this._anchorElement['search'];\r\n },\r\n set: function(value) {\r\n this._anchorElement['search'] = value;\r\n this._updateSearchParams();\r\n },\r\n enumerable: true\r\n });\r\n\r\n Object.defineProperties(proto, {\r\n\r\n 'toString': {\r\n get: function() {\r\n var _this = this;\r\n return function() {\r\n return _this.href;\r\n };\r\n }\r\n },\r\n\r\n 'href': {\r\n get: function() {\r\n return this._anchorElement.href.replace(/\\?$/, '');\r\n },\r\n set: function(value) {\r\n this._anchorElement.href = value;\r\n this._updateSearchParams();\r\n },\r\n enumerable: true\r\n },\r\n\r\n 'pathname': {\r\n get: function() {\r\n return this._anchorElement.pathname.replace(/(^\\/?)/, '/');\r\n },\r\n set: function(value) {\r\n this._anchorElement.pathname = value;\r\n },\r\n enumerable: true\r\n },\r\n\r\n 'origin': {\r\n get: function() {\r\n // get expected port from protocol\r\n var expectedPort = { 'http:': 80, 'https:': 443, 'ftp:': 21 }[this._anchorElement.protocol];\r\n // add port to origin if, expected port is different than actual port\r\n // and it is not empty f.e http://foo:8080\r\n // 8080 != 80 && 8080 != ''\r\n var addPortToOrigin = this._anchorElement.port != expectedPort &&\r\n this._anchorElement.port !== '';\r\n\r\n return this._anchorElement.protocol +\r\n '//' +\r\n this._anchorElement.hostname +\r\n (addPortToOrigin ? (':' + this._anchorElement.port) : '');\r\n },\r\n enumerable: true\r\n },\r\n\r\n 'password': { // TODO\r\n get: function() {\r\n return '';\r\n },\r\n set: function(value) {\r\n },\r\n enumerable: true\r\n },\r\n\r\n 'username': { // TODO\r\n get: function() {\r\n return '';\r\n },\r\n set: function(value) {\r\n },\r\n enumerable: true\r\n },\r\n });\r\n\r\n URL.createObjectURL = function(blob) {\r\n return _URL.createObjectURL.apply(_URL, arguments);\r\n };\r\n\r\n URL.revokeObjectURL = function(url) {\r\n return _URL.revokeObjectURL.apply(_URL, arguments);\r\n };\r\n\r\n global.URL = URL;\r\n\r\n };\r\n\r\n if (!checkIfURLIsSupported()) {\r\n polyfillURL();\r\n }\r\n\r\n if ((global.location !== void 0) && !('origin' in global.location)) {\r\n var getOrigin = function() {\r\n return global.location.protocol + '//' + global.location.hostname + (global.location.port ? (':' + global.location.port) : '');\r\n };\r\n\r\n try {\r\n Object.defineProperty(global.location, 'origin', {\r\n get: getOrigin,\r\n enumerable: true\r\n });\r\n } catch (e) {\r\n setInterval(function() {\r\n global.location.origin = getOrigin();\r\n }, 100);\r\n }\r\n }\r\n\r\n})(\r\n (typeof global !== 'undefined') ? global\r\n : ((typeof window !== 'undefined') ? window\r\n : ((typeof self !== 'undefined') ? self : this))\r\n);\r\n", "/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global global, define, System, Reflect, Promise */\r\nvar __extends;\r\nvar __assign;\r\nvar __rest;\r\nvar __decorate;\r\nvar __param;\r\nvar __metadata;\r\nvar __awaiter;\r\nvar __generator;\r\nvar __exportStar;\r\nvar __values;\r\nvar __read;\r\nvar __spread;\r\nvar __spreadArrays;\r\nvar __spreadArray;\r\nvar __await;\r\nvar __asyncGenerator;\r\nvar __asyncDelegator;\r\nvar __asyncValues;\r\nvar __makeTemplateObject;\r\nvar __importStar;\r\nvar __importDefault;\r\nvar __classPrivateFieldGet;\r\nvar __classPrivateFieldSet;\r\nvar __createBinding;\r\n(function (factory) {\r\n var root = typeof global === \"object\" ? global : typeof self === \"object\" ? self : typeof this === \"object\" ? this : {};\r\n if (typeof define === \"function\" && define.amd) {\r\n define(\"tslib\", [\"exports\"], function (exports) { factory(createExporter(root, createExporter(exports))); });\r\n }\r\n else if (typeof module === \"object\" && typeof module.exports === \"object\") {\r\n factory(createExporter(root, createExporter(module.exports)));\r\n }\r\n else {\r\n factory(createExporter(root));\r\n }\r\n function createExporter(exports, previous) {\r\n if (exports !== root) {\r\n if (typeof Object.create === \"function\") {\r\n Object.defineProperty(exports, \"__esModule\", { value: true });\r\n }\r\n else {\r\n exports.__esModule = true;\r\n }\r\n }\r\n return function (id, v) { return exports[id] = previous ? previous(id, v) : v; };\r\n }\r\n})\r\n(function (exporter) {\r\n var extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n\r\n __extends = function (d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n };\r\n\r\n __assign = Object.assign || function (t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n };\r\n\r\n __rest = function (s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n };\r\n\r\n __decorate = function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n };\r\n\r\n __param = function (paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n };\r\n\r\n __metadata = function (metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n };\r\n\r\n __awaiter = function (thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n };\r\n\r\n __generator = function (thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n };\r\n\r\n __exportStar = function(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n };\r\n\r\n __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n }) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n });\r\n\r\n __values = function (o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n };\r\n\r\n __read = function (o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n };\r\n\r\n /** @deprecated */\r\n __spread = function () {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n };\r\n\r\n /** @deprecated */\r\n __spreadArrays = function () {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n };\r\n\r\n __spreadArray = function (to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n };\r\n\r\n __await = function (v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n };\r\n\r\n __asyncGenerator = function (thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n };\r\n\r\n __asyncDelegator = function (o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n };\r\n\r\n __asyncValues = function (o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n };\r\n\r\n __makeTemplateObject = function (cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n };\r\n\r\n var __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n }) : function(o, v) {\r\n o[\"default\"] = v;\r\n };\r\n\r\n __importStar = function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n };\r\n\r\n __importDefault = function (mod) {\r\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n };\r\n\r\n __classPrivateFieldGet = function (receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n };\r\n\r\n __classPrivateFieldSet = function (receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n };\r\n\r\n exporter(\"__extends\", __extends);\r\n exporter(\"__assign\", __assign);\r\n exporter(\"__rest\", __rest);\r\n exporter(\"__decorate\", __decorate);\r\n exporter(\"__param\", __param);\r\n exporter(\"__metadata\", __metadata);\r\n exporter(\"__awaiter\", __awaiter);\r\n exporter(\"__generator\", __generator);\r\n exporter(\"__exportStar\", __exportStar);\r\n exporter(\"__createBinding\", __createBinding);\r\n exporter(\"__values\", __values);\r\n exporter(\"__read\", __read);\r\n exporter(\"__spread\", __spread);\r\n exporter(\"__spreadArrays\", __spreadArrays);\r\n exporter(\"__spreadArray\", __spreadArray);\r\n exporter(\"__await\", __await);\r\n exporter(\"__asyncGenerator\", __asyncGenerator);\r\n exporter(\"__asyncDelegator\", __asyncDelegator);\r\n exporter(\"__asyncValues\", __asyncValues);\r\n exporter(\"__makeTemplateObject\", __makeTemplateObject);\r\n exporter(\"__importStar\", __importStar);\r\n exporter(\"__importDefault\", __importDefault);\r\n exporter(\"__classPrivateFieldGet\", __classPrivateFieldGet);\r\n exporter(\"__classPrivateFieldSet\", __classPrivateFieldSet);\r\n});\r\n", "/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "Array.prototype.flat||Object.defineProperty(Array.prototype,\"flat\",{configurable:!0,value:function r(){var t=isNaN(arguments[0])?1:Number(arguments[0]);return t?Array.prototype.reduce.call(this,function(a,e){return Array.isArray(e)?a.push.apply(a,r.call(e,t-1)):a.push(e),a},[]):Array.prototype.slice.call(this)},writable:!0}),Array.prototype.flatMap||Object.defineProperty(Array.prototype,\"flatMap\",{configurable:!0,value:function(r){return Array.prototype.map.apply(this,arguments).flat()},writable:!0})\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"array-flat-polyfill\"\nimport \"focus-visible\"\nimport \"unfetch/polyfill\"\nimport \"url-polyfill\"\n\nimport {\n EMPTY,\n NEVER,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getOptionalElement,\n requestJSON,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountAnnounce,\n mountBackToTop,\n mountConsent,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantLoading,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget()\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? __search?.index || requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up instant loading, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantLoading({ document$, location$, viewport$ })\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector({ document$ })\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"[href][rel=prev]\")\n if (typeof prev !== \"undefined\")\n prev.click()\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"[href][rel=next]\")\n if (typeof next !== \"undefined\")\n next.click()\n break\n }\n })\n\n/* Set up patches */\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Consent */\n ...getComponentElements(\"consent\")\n .map(el => mountConsent(el, { target$ })),\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Announcement bar */\n ...getComponentElements(\"announce\")\n .map(el => mountAnnounce(el)),\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, { viewport$, header$, target$ })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.component$ = component$ /* Component observable */\n", "self.fetch||(self.fetch=function(e,n){return n=n||{},new Promise(function(t,s){var r=new XMLHttpRequest,o=[],u=[],i={},a=function(){return{ok:2==(r.status/100|0),statusText:r.statusText,status:r.status,url:r.responseURL,text:function(){return Promise.resolve(r.responseText)},json:function(){return Promise.resolve(r.responseText).then(JSON.parse)},blob:function(){return Promise.resolve(new Blob([r.response]))},clone:a,headers:{keys:function(){return o},entries:function(){return u},get:function(e){return i[e.toLowerCase()]},has:function(e){return e.toLowerCase()in i}}}};for(var c in r.open(n.method||\"get\",e,!0),r.onload=function(){r.getAllResponseHeaders().replace(/^(.*?):[^\\S\\n]*([\\s\\S]*?)$/gm,function(e,n,t){o.push(n=n.toLowerCase()),u.push([n,t]),i[n]=i[n]?i[n]+\",\"+t:t}),t(a())},r.onerror=s,r.withCredentials=\"include\"==n.credentials,n.headers)r.setRequestHeader(c,n.headers[c]);r.send(n.body||null)})});\n", "import tslib from '../tslib.js';\r\nconst {\r\n __extends,\r\n __assign,\r\n __rest,\r\n __decorate,\r\n __param,\r\n __metadata,\r\n __awaiter,\r\n __generator,\r\n __exportStar,\r\n __createBinding,\r\n __values,\r\n __read,\r\n __spread,\r\n __spreadArrays,\r\n __spreadArray,\r\n __await,\r\n __asyncGenerator,\r\n __asyncDelegator,\r\n __asyncValues,\r\n __makeTemplateObject,\r\n __importStar,\r\n __importDefault,\r\n __classPrivateFieldGet,\r\n __classPrivateFieldSet,\r\n} = tslib;\r\nexport {\r\n __extends,\r\n __assign,\r\n __rest,\r\n __decorate,\r\n __param,\r\n __metadata,\r\n __awaiter,\r\n __generator,\r\n __exportStar,\r\n __createBinding,\r\n __values,\r\n __read,\r\n __spread,\r\n __spreadArrays,\r\n __spreadArray,\r\n __await,\r\n __asyncGenerator,\r\n __asyncDelegator,\r\n __asyncValues,\r\n __makeTemplateObject,\r\n __importStar,\r\n __importDefault,\r\n __classPrivateFieldGet,\r\n __classPrivateFieldSet,\r\n};\r\n", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n ReplaySubject,\n Subject,\n fromEvent\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch document\n *\n * Documents are implemented as subjects, so all downstream observables are\n * automatically updated when a new document is emitted.\n *\n * @returns Document subject\n */\nexport function watchDocument(): Subject {\n const document$ = new ReplaySubject(1)\n fromEvent(document, \"DOMContentLoaded\", { once: true })\n .subscribe(() => document$.next(document))\n\n /* Return document */\n return document$\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve all elements matching the query selector\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Elements\n */\nexport function getElements(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T][]\n\nexport function getElements(\n selector: string, node?: ParentNode\n): T[]\n\nexport function getElements(\n selector: string, node: ParentNode = document\n): T[] {\n return Array.from(node.querySelectorAll(selector))\n}\n\n/**\n * Retrieve an element matching a query selector or throw a reference error\n *\n * Note that this function assumes that the element is present. If unsure if an\n * element is existent, use the `getOptionalElement` function instead.\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Element\n */\nexport function getElement(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T]\n\nexport function getElement(\n selector: string, node?: ParentNode\n): T\n\nexport function getElement(\n selector: string, node: ParentNode = document\n): T {\n const el = getOptionalElement(selector, node)\n if (typeof el === \"undefined\")\n throw new ReferenceError(\n `Missing element: expected \"${selector}\" to be present`\n )\n\n /* Return element */\n return el\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Retrieve an optional element matching the query selector\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Element or nothing\n */\nexport function getOptionalElement(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T] | undefined\n\nexport function getOptionalElement(\n selector: string, node?: ParentNode\n): T | undefined\n\nexport function getOptionalElement(\n selector: string, node: ParentNode = document\n): T | undefined {\n return node.querySelector(selector) || undefined\n}\n\n/**\n * Retrieve the currently active element\n *\n * @returns Element or nothing\n */\nexport function getActiveElement(): HTMLElement | undefined {\n return document.activeElement instanceof HTMLElement\n ? document.activeElement || undefined\n : undefined\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n debounceTime,\n distinctUntilChanged,\n fromEvent,\n map,\n merge,\n startWith\n} from \"rxjs\"\n\nimport { getActiveElement } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch element focus\n *\n * Previously, this function used `focus` and `blur` events to determine whether\n * an element is focused, but this doesn't work if there are focusable elements\n * within the elements itself. A better solutions are `focusin` and `focusout`\n * events, which bubble up the tree and allow for more fine-grained control.\n *\n * `debounceTime` is necessary, because when a focus change happens inside an\n * element, the observable would first emit `false` and then `true` again.\n *\n * @param el - Element\n *\n * @returns Element focus observable\n */\nexport function watchElementFocus(\n el: HTMLElement\n): Observable {\n return merge(\n fromEvent(document.body, \"focusin\"),\n fromEvent(document.body, \"focusout\")\n )\n .pipe(\n debounceTime(1),\n map(() => {\n const active = getActiveElement()\n return typeof active !== \"undefined\"\n ? el.contains(active)\n : false\n }),\n startWith(el === getActiveElement()),\n distinctUntilChanged()\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n animationFrameScheduler,\n auditTime,\n fromEvent,\n map,\n merge,\n startWith\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Element offset\n */\nexport interface ElementOffset {\n x: number /* Horizontal offset */\n y: number /* Vertical offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element offset\n *\n * @param el - Element\n *\n * @returns Element offset\n */\nexport function getElementOffset(\n el: HTMLElement\n): ElementOffset {\n return {\n x: el.offsetLeft,\n y: el.offsetTop\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element offset\n *\n * @param el - Element\n *\n * @returns Element offset observable\n */\nexport function watchElementOffset(\n el: HTMLElement\n): Observable {\n return merge(\n fromEvent(window, \"load\"),\n fromEvent(window, \"resize\")\n )\n .pipe(\n auditTime(0, animationFrameScheduler),\n map(() => getElementOffset(el)),\n startWith(getElementOffset(el))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n animationFrameScheduler,\n auditTime,\n fromEvent,\n map,\n merge,\n startWith\n} from \"rxjs\"\n\nimport { ElementOffset } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element content offset (= scroll offset)\n *\n * @param el - Element\n *\n * @returns Element content offset\n */\nexport function getElementContentOffset(\n el: HTMLElement\n): ElementOffset {\n return {\n x: el.scrollLeft,\n y: el.scrollTop\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element content offset\n *\n * @param el - Element\n *\n * @returns Element content offset observable\n */\nexport function watchElementContentOffset(\n el: HTMLElement\n): Observable {\n return merge(\n fromEvent(el, \"scroll\"),\n fromEvent(window, \"resize\")\n )\n .pipe(\n auditTime(0, animationFrameScheduler),\n map(() => getElementContentOffset(el)),\n startWith(getElementContentOffset(el))\n )\n}\n", "/**\r\n * A collection of shims that provide minimal functionality of the ES6 collections.\r\n *\r\n * These implementations are not meant to be used outside of the ResizeObserver\r\n * modules as they cover only a limited range of use cases.\r\n */\r\n/* eslint-disable require-jsdoc, valid-jsdoc */\r\nvar MapShim = (function () {\r\n if (typeof Map !== 'undefined') {\r\n return Map;\r\n }\r\n /**\r\n * Returns index in provided array that matches the specified key.\r\n *\r\n * @param {Array} arr\r\n * @param {*} key\r\n * @returns {number}\r\n */\r\n function getIndex(arr, key) {\r\n var result = -1;\r\n arr.some(function (entry, index) {\r\n if (entry[0] === key) {\r\n result = index;\r\n return true;\r\n }\r\n return false;\r\n });\r\n return result;\r\n }\r\n return /** @class */ (function () {\r\n function class_1() {\r\n this.__entries__ = [];\r\n }\r\n Object.defineProperty(class_1.prototype, \"size\", {\r\n /**\r\n * @returns {boolean}\r\n */\r\n get: function () {\r\n return this.__entries__.length;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n /**\r\n * @param {*} key\r\n * @returns {*}\r\n */\r\n class_1.prototype.get = function (key) {\r\n var index = getIndex(this.__entries__, key);\r\n var entry = this.__entries__[index];\r\n return entry && entry[1];\r\n };\r\n /**\r\n * @param {*} key\r\n * @param {*} value\r\n * @returns {void}\r\n */\r\n class_1.prototype.set = function (key, value) {\r\n var index = getIndex(this.__entries__, key);\r\n if (~index) {\r\n this.__entries__[index][1] = value;\r\n }\r\n else {\r\n this.__entries__.push([key, value]);\r\n }\r\n };\r\n /**\r\n * @param {*} key\r\n * @returns {void}\r\n */\r\n class_1.prototype.delete = function (key) {\r\n var entries = this.__entries__;\r\n var index = getIndex(entries, key);\r\n if (~index) {\r\n entries.splice(index, 1);\r\n }\r\n };\r\n /**\r\n * @param {*} key\r\n * @returns {void}\r\n */\r\n class_1.prototype.has = function (key) {\r\n return !!~getIndex(this.__entries__, key);\r\n };\r\n /**\r\n * @returns {void}\r\n */\r\n class_1.prototype.clear = function () {\r\n this.__entries__.splice(0);\r\n };\r\n /**\r\n * @param {Function} callback\r\n * @param {*} [ctx=null]\r\n * @returns {void}\r\n */\r\n class_1.prototype.forEach = function (callback, ctx) {\r\n if (ctx === void 0) { ctx = null; }\r\n for (var _i = 0, _a = this.__entries__; _i < _a.length; _i++) {\r\n var entry = _a[_i];\r\n callback.call(ctx, entry[1], entry[0]);\r\n }\r\n };\r\n return class_1;\r\n }());\r\n})();\n\n/**\r\n * Detects whether window and document objects are available in current environment.\r\n */\r\nvar isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && window.document === document;\n\n// Returns global object of a current environment.\r\nvar global$1 = (function () {\r\n if (typeof global !== 'undefined' && global.Math === Math) {\r\n return global;\r\n }\r\n if (typeof self !== 'undefined' && self.Math === Math) {\r\n return self;\r\n }\r\n if (typeof window !== 'undefined' && window.Math === Math) {\r\n return window;\r\n }\r\n // eslint-disable-next-line no-new-func\r\n return Function('return this')();\r\n})();\n\n/**\r\n * A shim for the requestAnimationFrame which falls back to the setTimeout if\r\n * first one is not supported.\r\n *\r\n * @returns {number} Requests' identifier.\r\n */\r\nvar requestAnimationFrame$1 = (function () {\r\n if (typeof requestAnimationFrame === 'function') {\r\n // It's required to use a bounded function because IE sometimes throws\r\n // an \"Invalid calling object\" error if rAF is invoked without the global\r\n // object on the left hand side.\r\n return requestAnimationFrame.bind(global$1);\r\n }\r\n return function (callback) { return setTimeout(function () { return callback(Date.now()); }, 1000 / 60); };\r\n})();\n\n// Defines minimum timeout before adding a trailing call.\r\nvar trailingTimeout = 2;\r\n/**\r\n * Creates a wrapper function which ensures that provided callback will be\r\n * invoked only once during the specified delay period.\r\n *\r\n * @param {Function} callback - Function to be invoked after the delay period.\r\n * @param {number} delay - Delay after which to invoke callback.\r\n * @returns {Function}\r\n */\r\nfunction throttle (callback, delay) {\r\n var leadingCall = false, trailingCall = false, lastCallTime = 0;\r\n /**\r\n * Invokes the original callback function and schedules new invocation if\r\n * the \"proxy\" was called during current request.\r\n *\r\n * @returns {void}\r\n */\r\n function resolvePending() {\r\n if (leadingCall) {\r\n leadingCall = false;\r\n callback();\r\n }\r\n if (trailingCall) {\r\n proxy();\r\n }\r\n }\r\n /**\r\n * Callback invoked after the specified delay. It will further postpone\r\n * invocation of the original function delegating it to the\r\n * requestAnimationFrame.\r\n *\r\n * @returns {void}\r\n */\r\n function timeoutCallback() {\r\n requestAnimationFrame$1(resolvePending);\r\n }\r\n /**\r\n * Schedules invocation of the original function.\r\n *\r\n * @returns {void}\r\n */\r\n function proxy() {\r\n var timeStamp = Date.now();\r\n if (leadingCall) {\r\n // Reject immediately following calls.\r\n if (timeStamp - lastCallTime < trailingTimeout) {\r\n return;\r\n }\r\n // Schedule new call to be in invoked when the pending one is resolved.\r\n // This is important for \"transitions\" which never actually start\r\n // immediately so there is a chance that we might miss one if change\r\n // happens amids the pending invocation.\r\n trailingCall = true;\r\n }\r\n else {\r\n leadingCall = true;\r\n trailingCall = false;\r\n setTimeout(timeoutCallback, delay);\r\n }\r\n lastCallTime = timeStamp;\r\n }\r\n return proxy;\r\n}\n\n// Minimum delay before invoking the update of observers.\r\nvar REFRESH_DELAY = 20;\r\n// A list of substrings of CSS properties used to find transition events that\r\n// might affect dimensions of observed elements.\r\nvar transitionKeys = ['top', 'right', 'bottom', 'left', 'width', 'height', 'size', 'weight'];\r\n// Check if MutationObserver is available.\r\nvar mutationObserverSupported = typeof MutationObserver !== 'undefined';\r\n/**\r\n * Singleton controller class which handles updates of ResizeObserver instances.\r\n */\r\nvar ResizeObserverController = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of ResizeObserverController.\r\n *\r\n * @private\r\n */\r\n function ResizeObserverController() {\r\n /**\r\n * Indicates whether DOM listeners have been added.\r\n *\r\n * @private {boolean}\r\n */\r\n this.connected_ = false;\r\n /**\r\n * Tells that controller has subscribed for Mutation Events.\r\n *\r\n * @private {boolean}\r\n */\r\n this.mutationEventsAdded_ = false;\r\n /**\r\n * Keeps reference to the instance of MutationObserver.\r\n *\r\n * @private {MutationObserver}\r\n */\r\n this.mutationsObserver_ = null;\r\n /**\r\n * A list of connected observers.\r\n *\r\n * @private {Array}\r\n */\r\n this.observers_ = [];\r\n this.onTransitionEnd_ = this.onTransitionEnd_.bind(this);\r\n this.refresh = throttle(this.refresh.bind(this), REFRESH_DELAY);\r\n }\r\n /**\r\n * Adds observer to observers list.\r\n *\r\n * @param {ResizeObserverSPI} observer - Observer to be added.\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.addObserver = function (observer) {\r\n if (!~this.observers_.indexOf(observer)) {\r\n this.observers_.push(observer);\r\n }\r\n // Add listeners if they haven't been added yet.\r\n if (!this.connected_) {\r\n this.connect_();\r\n }\r\n };\r\n /**\r\n * Removes observer from observers list.\r\n *\r\n * @param {ResizeObserverSPI} observer - Observer to be removed.\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.removeObserver = function (observer) {\r\n var observers = this.observers_;\r\n var index = observers.indexOf(observer);\r\n // Remove observer if it's present in registry.\r\n if (~index) {\r\n observers.splice(index, 1);\r\n }\r\n // Remove listeners if controller has no connected observers.\r\n if (!observers.length && this.connected_) {\r\n this.disconnect_();\r\n }\r\n };\r\n /**\r\n * Invokes the update of observers. It will continue running updates insofar\r\n * it detects changes.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.refresh = function () {\r\n var changesDetected = this.updateObservers_();\r\n // Continue running updates if changes have been detected as there might\r\n // be future ones caused by CSS transitions.\r\n if (changesDetected) {\r\n this.refresh();\r\n }\r\n };\r\n /**\r\n * Updates every observer from observers list and notifies them of queued\r\n * entries.\r\n *\r\n * @private\r\n * @returns {boolean} Returns \"true\" if any observer has detected changes in\r\n * dimensions of it's elements.\r\n */\r\n ResizeObserverController.prototype.updateObservers_ = function () {\r\n // Collect observers that have active observations.\r\n var activeObservers = this.observers_.filter(function (observer) {\r\n return observer.gatherActive(), observer.hasActive();\r\n });\r\n // Deliver notifications in a separate cycle in order to avoid any\r\n // collisions between observers, e.g. when multiple instances of\r\n // ResizeObserver are tracking the same element and the callback of one\r\n // of them changes content dimensions of the observed target. Sometimes\r\n // this may result in notifications being blocked for the rest of observers.\r\n activeObservers.forEach(function (observer) { return observer.broadcastActive(); });\r\n return activeObservers.length > 0;\r\n };\r\n /**\r\n * Initializes DOM listeners.\r\n *\r\n * @private\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.connect_ = function () {\r\n // Do nothing if running in a non-browser environment or if listeners\r\n // have been already added.\r\n if (!isBrowser || this.connected_) {\r\n return;\r\n }\r\n // Subscription to the \"Transitionend\" event is used as a workaround for\r\n // delayed transitions. This way it's possible to capture at least the\r\n // final state of an element.\r\n document.addEventListener('transitionend', this.onTransitionEnd_);\r\n window.addEventListener('resize', this.refresh);\r\n if (mutationObserverSupported) {\r\n this.mutationsObserver_ = new MutationObserver(this.refresh);\r\n this.mutationsObserver_.observe(document, {\r\n attributes: true,\r\n childList: true,\r\n characterData: true,\r\n subtree: true\r\n });\r\n }\r\n else {\r\n document.addEventListener('DOMSubtreeModified', this.refresh);\r\n this.mutationEventsAdded_ = true;\r\n }\r\n this.connected_ = true;\r\n };\r\n /**\r\n * Removes DOM listeners.\r\n *\r\n * @private\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.disconnect_ = function () {\r\n // Do nothing if running in a non-browser environment or if listeners\r\n // have been already removed.\r\n if (!isBrowser || !this.connected_) {\r\n return;\r\n }\r\n document.removeEventListener('transitionend', this.onTransitionEnd_);\r\n window.removeEventListener('resize', this.refresh);\r\n if (this.mutationsObserver_) {\r\n this.mutationsObserver_.disconnect();\r\n }\r\n if (this.mutationEventsAdded_) {\r\n document.removeEventListener('DOMSubtreeModified', this.refresh);\r\n }\r\n this.mutationsObserver_ = null;\r\n this.mutationEventsAdded_ = false;\r\n this.connected_ = false;\r\n };\r\n /**\r\n * \"Transitionend\" event handler.\r\n *\r\n * @private\r\n * @param {TransitionEvent} event\r\n * @returns {void}\r\n */\r\n ResizeObserverController.prototype.onTransitionEnd_ = function (_a) {\r\n var _b = _a.propertyName, propertyName = _b === void 0 ? '' : _b;\r\n // Detect whether transition may affect dimensions of an element.\r\n var isReflowProperty = transitionKeys.some(function (key) {\r\n return !!~propertyName.indexOf(key);\r\n });\r\n if (isReflowProperty) {\r\n this.refresh();\r\n }\r\n };\r\n /**\r\n * Returns instance of the ResizeObserverController.\r\n *\r\n * @returns {ResizeObserverController}\r\n */\r\n ResizeObserverController.getInstance = function () {\r\n if (!this.instance_) {\r\n this.instance_ = new ResizeObserverController();\r\n }\r\n return this.instance_;\r\n };\r\n /**\r\n * Holds reference to the controller's instance.\r\n *\r\n * @private {ResizeObserverController}\r\n */\r\n ResizeObserverController.instance_ = null;\r\n return ResizeObserverController;\r\n}());\n\n/**\r\n * Defines non-writable/enumerable properties of the provided target object.\r\n *\r\n * @param {Object} target - Object for which to define properties.\r\n * @param {Object} props - Properties to be defined.\r\n * @returns {Object} Target object.\r\n */\r\nvar defineConfigurable = (function (target, props) {\r\n for (var _i = 0, _a = Object.keys(props); _i < _a.length; _i++) {\r\n var key = _a[_i];\r\n Object.defineProperty(target, key, {\r\n value: props[key],\r\n enumerable: false,\r\n writable: false,\r\n configurable: true\r\n });\r\n }\r\n return target;\r\n});\n\n/**\r\n * Returns the global object associated with provided element.\r\n *\r\n * @param {Object} target\r\n * @returns {Object}\r\n */\r\nvar getWindowOf = (function (target) {\r\n // Assume that the element is an instance of Node, which means that it\r\n // has the \"ownerDocument\" property from which we can retrieve a\r\n // corresponding global object.\r\n var ownerGlobal = target && target.ownerDocument && target.ownerDocument.defaultView;\r\n // Return the local global object if it's not possible extract one from\r\n // provided element.\r\n return ownerGlobal || global$1;\r\n});\n\n// Placeholder of an empty content rectangle.\r\nvar emptyRect = createRectInit(0, 0, 0, 0);\r\n/**\r\n * Converts provided string to a number.\r\n *\r\n * @param {number|string} value\r\n * @returns {number}\r\n */\r\nfunction toFloat(value) {\r\n return parseFloat(value) || 0;\r\n}\r\n/**\r\n * Extracts borders size from provided styles.\r\n *\r\n * @param {CSSStyleDeclaration} styles\r\n * @param {...string} positions - Borders positions (top, right, ...)\r\n * @returns {number}\r\n */\r\nfunction getBordersSize(styles) {\r\n var positions = [];\r\n for (var _i = 1; _i < arguments.length; _i++) {\r\n positions[_i - 1] = arguments[_i];\r\n }\r\n return positions.reduce(function (size, position) {\r\n var value = styles['border-' + position + '-width'];\r\n return size + toFloat(value);\r\n }, 0);\r\n}\r\n/**\r\n * Extracts paddings sizes from provided styles.\r\n *\r\n * @param {CSSStyleDeclaration} styles\r\n * @returns {Object} Paddings box.\r\n */\r\nfunction getPaddings(styles) {\r\n var positions = ['top', 'right', 'bottom', 'left'];\r\n var paddings = {};\r\n for (var _i = 0, positions_1 = positions; _i < positions_1.length; _i++) {\r\n var position = positions_1[_i];\r\n var value = styles['padding-' + position];\r\n paddings[position] = toFloat(value);\r\n }\r\n return paddings;\r\n}\r\n/**\r\n * Calculates content rectangle of provided SVG element.\r\n *\r\n * @param {SVGGraphicsElement} target - Element content rectangle of which needs\r\n * to be calculated.\r\n * @returns {DOMRectInit}\r\n */\r\nfunction getSVGContentRect(target) {\r\n var bbox = target.getBBox();\r\n return createRectInit(0, 0, bbox.width, bbox.height);\r\n}\r\n/**\r\n * Calculates content rectangle of provided HTMLElement.\r\n *\r\n * @param {HTMLElement} target - Element for which to calculate the content rectangle.\r\n * @returns {DOMRectInit}\r\n */\r\nfunction getHTMLElementContentRect(target) {\r\n // Client width & height properties can't be\r\n // used exclusively as they provide rounded values.\r\n var clientWidth = target.clientWidth, clientHeight = target.clientHeight;\r\n // By this condition we can catch all non-replaced inline, hidden and\r\n // detached elements. Though elements with width & height properties less\r\n // than 0.5 will be discarded as well.\r\n //\r\n // Without it we would need to implement separate methods for each of\r\n // those cases and it's not possible to perform a precise and performance\r\n // effective test for hidden elements. E.g. even jQuery's ':visible' filter\r\n // gives wrong results for elements with width & height less than 0.5.\r\n if (!clientWidth && !clientHeight) {\r\n return emptyRect;\r\n }\r\n var styles = getWindowOf(target).getComputedStyle(target);\r\n var paddings = getPaddings(styles);\r\n var horizPad = paddings.left + paddings.right;\r\n var vertPad = paddings.top + paddings.bottom;\r\n // Computed styles of width & height are being used because they are the\r\n // only dimensions available to JS that contain non-rounded values. It could\r\n // be possible to utilize the getBoundingClientRect if only it's data wasn't\r\n // affected by CSS transformations let alone paddings, borders and scroll bars.\r\n var width = toFloat(styles.width), height = toFloat(styles.height);\r\n // Width & height include paddings and borders when the 'border-box' box\r\n // model is applied (except for IE).\r\n if (styles.boxSizing === 'border-box') {\r\n // Following conditions are required to handle Internet Explorer which\r\n // doesn't include paddings and borders to computed CSS dimensions.\r\n //\r\n // We can say that if CSS dimensions + paddings are equal to the \"client\"\r\n // properties then it's either IE, and thus we don't need to subtract\r\n // anything, or an element merely doesn't have paddings/borders styles.\r\n if (Math.round(width + horizPad) !== clientWidth) {\r\n width -= getBordersSize(styles, 'left', 'right') + horizPad;\r\n }\r\n if (Math.round(height + vertPad) !== clientHeight) {\r\n height -= getBordersSize(styles, 'top', 'bottom') + vertPad;\r\n }\r\n }\r\n // Following steps can't be applied to the document's root element as its\r\n // client[Width/Height] properties represent viewport area of the window.\r\n // Besides, it's as well not necessary as the itself neither has\r\n // rendered scroll bars nor it can be clipped.\r\n if (!isDocumentElement(target)) {\r\n // In some browsers (only in Firefox, actually) CSS width & height\r\n // include scroll bars size which can be removed at this step as scroll\r\n // bars are the only difference between rounded dimensions + paddings\r\n // and \"client\" properties, though that is not always true in Chrome.\r\n var vertScrollbar = Math.round(width + horizPad) - clientWidth;\r\n var horizScrollbar = Math.round(height + vertPad) - clientHeight;\r\n // Chrome has a rather weird rounding of \"client\" properties.\r\n // E.g. for an element with content width of 314.2px it sometimes gives\r\n // the client width of 315px and for the width of 314.7px it may give\r\n // 314px. And it doesn't happen all the time. So just ignore this delta\r\n // as a non-relevant.\r\n if (Math.abs(vertScrollbar) !== 1) {\r\n width -= vertScrollbar;\r\n }\r\n if (Math.abs(horizScrollbar) !== 1) {\r\n height -= horizScrollbar;\r\n }\r\n }\r\n return createRectInit(paddings.left, paddings.top, width, height);\r\n}\r\n/**\r\n * Checks whether provided element is an instance of the SVGGraphicsElement.\r\n *\r\n * @param {Element} target - Element to be checked.\r\n * @returns {boolean}\r\n */\r\nvar isSVGGraphicsElement = (function () {\r\n // Some browsers, namely IE and Edge, don't have the SVGGraphicsElement\r\n // interface.\r\n if (typeof SVGGraphicsElement !== 'undefined') {\r\n return function (target) { return target instanceof getWindowOf(target).SVGGraphicsElement; };\r\n }\r\n // If it's so, then check that element is at least an instance of the\r\n // SVGElement and that it has the \"getBBox\" method.\r\n // eslint-disable-next-line no-extra-parens\r\n return function (target) { return (target instanceof getWindowOf(target).SVGElement &&\r\n typeof target.getBBox === 'function'); };\r\n})();\r\n/**\r\n * Checks whether provided element is a document element ().\r\n *\r\n * @param {Element} target - Element to be checked.\r\n * @returns {boolean}\r\n */\r\nfunction isDocumentElement(target) {\r\n return target === getWindowOf(target).document.documentElement;\r\n}\r\n/**\r\n * Calculates an appropriate content rectangle for provided html or svg element.\r\n *\r\n * @param {Element} target - Element content rectangle of which needs to be calculated.\r\n * @returns {DOMRectInit}\r\n */\r\nfunction getContentRect(target) {\r\n if (!isBrowser) {\r\n return emptyRect;\r\n }\r\n if (isSVGGraphicsElement(target)) {\r\n return getSVGContentRect(target);\r\n }\r\n return getHTMLElementContentRect(target);\r\n}\r\n/**\r\n * Creates rectangle with an interface of the DOMRectReadOnly.\r\n * Spec: https://drafts.fxtf.org/geometry/#domrectreadonly\r\n *\r\n * @param {DOMRectInit} rectInit - Object with rectangle's x/y coordinates and dimensions.\r\n * @returns {DOMRectReadOnly}\r\n */\r\nfunction createReadOnlyRect(_a) {\r\n var x = _a.x, y = _a.y, width = _a.width, height = _a.height;\r\n // If DOMRectReadOnly is available use it as a prototype for the rectangle.\r\n var Constr = typeof DOMRectReadOnly !== 'undefined' ? DOMRectReadOnly : Object;\r\n var rect = Object.create(Constr.prototype);\r\n // Rectangle's properties are not writable and non-enumerable.\r\n defineConfigurable(rect, {\r\n x: x, y: y, width: width, height: height,\r\n top: y,\r\n right: x + width,\r\n bottom: height + y,\r\n left: x\r\n });\r\n return rect;\r\n}\r\n/**\r\n * Creates DOMRectInit object based on the provided dimensions and the x/y coordinates.\r\n * Spec: https://drafts.fxtf.org/geometry/#dictdef-domrectinit\r\n *\r\n * @param {number} x - X coordinate.\r\n * @param {number} y - Y coordinate.\r\n * @param {number} width - Rectangle's width.\r\n * @param {number} height - Rectangle's height.\r\n * @returns {DOMRectInit}\r\n */\r\nfunction createRectInit(x, y, width, height) {\r\n return { x: x, y: y, width: width, height: height };\r\n}\n\n/**\r\n * Class that is responsible for computations of the content rectangle of\r\n * provided DOM element and for keeping track of it's changes.\r\n */\r\nvar ResizeObservation = /** @class */ (function () {\r\n /**\r\n * Creates an instance of ResizeObservation.\r\n *\r\n * @param {Element} target - Element to be observed.\r\n */\r\n function ResizeObservation(target) {\r\n /**\r\n * Broadcasted width of content rectangle.\r\n *\r\n * @type {number}\r\n */\r\n this.broadcastWidth = 0;\r\n /**\r\n * Broadcasted height of content rectangle.\r\n *\r\n * @type {number}\r\n */\r\n this.broadcastHeight = 0;\r\n /**\r\n * Reference to the last observed content rectangle.\r\n *\r\n * @private {DOMRectInit}\r\n */\r\n this.contentRect_ = createRectInit(0, 0, 0, 0);\r\n this.target = target;\r\n }\r\n /**\r\n * Updates content rectangle and tells whether it's width or height properties\r\n * have changed since the last broadcast.\r\n *\r\n * @returns {boolean}\r\n */\r\n ResizeObservation.prototype.isActive = function () {\r\n var rect = getContentRect(this.target);\r\n this.contentRect_ = rect;\r\n return (rect.width !== this.broadcastWidth ||\r\n rect.height !== this.broadcastHeight);\r\n };\r\n /**\r\n * Updates 'broadcastWidth' and 'broadcastHeight' properties with a data\r\n * from the corresponding properties of the last observed content rectangle.\r\n *\r\n * @returns {DOMRectInit} Last observed content rectangle.\r\n */\r\n ResizeObservation.prototype.broadcastRect = function () {\r\n var rect = this.contentRect_;\r\n this.broadcastWidth = rect.width;\r\n this.broadcastHeight = rect.height;\r\n return rect;\r\n };\r\n return ResizeObservation;\r\n}());\n\nvar ResizeObserverEntry = /** @class */ (function () {\r\n /**\r\n * Creates an instance of ResizeObserverEntry.\r\n *\r\n * @param {Element} target - Element that is being observed.\r\n * @param {DOMRectInit} rectInit - Data of the element's content rectangle.\r\n */\r\n function ResizeObserverEntry(target, rectInit) {\r\n var contentRect = createReadOnlyRect(rectInit);\r\n // According to the specification following properties are not writable\r\n // and are also not enumerable in the native implementation.\r\n //\r\n // Property accessors are not being used as they'd require to define a\r\n // private WeakMap storage which may cause memory leaks in browsers that\r\n // don't support this type of collections.\r\n defineConfigurable(this, { target: target, contentRect: contentRect });\r\n }\r\n return ResizeObserverEntry;\r\n}());\n\nvar ResizeObserverSPI = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of ResizeObserver.\r\n *\r\n * @param {ResizeObserverCallback} callback - Callback function that is invoked\r\n * when one of the observed elements changes it's content dimensions.\r\n * @param {ResizeObserverController} controller - Controller instance which\r\n * is responsible for the updates of observer.\r\n * @param {ResizeObserver} callbackCtx - Reference to the public\r\n * ResizeObserver instance which will be passed to callback function.\r\n */\r\n function ResizeObserverSPI(callback, controller, callbackCtx) {\r\n /**\r\n * Collection of resize observations that have detected changes in dimensions\r\n * of elements.\r\n *\r\n * @private {Array}\r\n */\r\n this.activeObservations_ = [];\r\n /**\r\n * Registry of the ResizeObservation instances.\r\n *\r\n * @private {Map}\r\n */\r\n this.observations_ = new MapShim();\r\n if (typeof callback !== 'function') {\r\n throw new TypeError('The callback provided as parameter 1 is not a function.');\r\n }\r\n this.callback_ = callback;\r\n this.controller_ = controller;\r\n this.callbackCtx_ = callbackCtx;\r\n }\r\n /**\r\n * Starts observing provided element.\r\n *\r\n * @param {Element} target - Element to be observed.\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.observe = function (target) {\r\n if (!arguments.length) {\r\n throw new TypeError('1 argument required, but only 0 present.');\r\n }\r\n // Do nothing if current environment doesn't have the Element interface.\r\n if (typeof Element === 'undefined' || !(Element instanceof Object)) {\r\n return;\r\n }\r\n if (!(target instanceof getWindowOf(target).Element)) {\r\n throw new TypeError('parameter 1 is not of type \"Element\".');\r\n }\r\n var observations = this.observations_;\r\n // Do nothing if element is already being observed.\r\n if (observations.has(target)) {\r\n return;\r\n }\r\n observations.set(target, new ResizeObservation(target));\r\n this.controller_.addObserver(this);\r\n // Force the update of observations.\r\n this.controller_.refresh();\r\n };\r\n /**\r\n * Stops observing provided element.\r\n *\r\n * @param {Element} target - Element to stop observing.\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.unobserve = function (target) {\r\n if (!arguments.length) {\r\n throw new TypeError('1 argument required, but only 0 present.');\r\n }\r\n // Do nothing if current environment doesn't have the Element interface.\r\n if (typeof Element === 'undefined' || !(Element instanceof Object)) {\r\n return;\r\n }\r\n if (!(target instanceof getWindowOf(target).Element)) {\r\n throw new TypeError('parameter 1 is not of type \"Element\".');\r\n }\r\n var observations = this.observations_;\r\n // Do nothing if element is not being observed.\r\n if (!observations.has(target)) {\r\n return;\r\n }\r\n observations.delete(target);\r\n if (!observations.size) {\r\n this.controller_.removeObserver(this);\r\n }\r\n };\r\n /**\r\n * Stops observing all elements.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.disconnect = function () {\r\n this.clearActive();\r\n this.observations_.clear();\r\n this.controller_.removeObserver(this);\r\n };\r\n /**\r\n * Collects observation instances the associated element of which has changed\r\n * it's content rectangle.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.gatherActive = function () {\r\n var _this = this;\r\n this.clearActive();\r\n this.observations_.forEach(function (observation) {\r\n if (observation.isActive()) {\r\n _this.activeObservations_.push(observation);\r\n }\r\n });\r\n };\r\n /**\r\n * Invokes initial callback function with a list of ResizeObserverEntry\r\n * instances collected from active resize observations.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.broadcastActive = function () {\r\n // Do nothing if observer doesn't have active observations.\r\n if (!this.hasActive()) {\r\n return;\r\n }\r\n var ctx = this.callbackCtx_;\r\n // Create ResizeObserverEntry instance for every active observation.\r\n var entries = this.activeObservations_.map(function (observation) {\r\n return new ResizeObserverEntry(observation.target, observation.broadcastRect());\r\n });\r\n this.callback_.call(ctx, entries, ctx);\r\n this.clearActive();\r\n };\r\n /**\r\n * Clears the collection of active observations.\r\n *\r\n * @returns {void}\r\n */\r\n ResizeObserverSPI.prototype.clearActive = function () {\r\n this.activeObservations_.splice(0);\r\n };\r\n /**\r\n * Tells whether observer has active observations.\r\n *\r\n * @returns {boolean}\r\n */\r\n ResizeObserverSPI.prototype.hasActive = function () {\r\n return this.activeObservations_.length > 0;\r\n };\r\n return ResizeObserverSPI;\r\n}());\n\n// Registry of internal observers. If WeakMap is not available use current shim\r\n// for the Map collection as it has all required methods and because WeakMap\r\n// can't be fully polyfilled anyway.\r\nvar observers = typeof WeakMap !== 'undefined' ? new WeakMap() : new MapShim();\r\n/**\r\n * ResizeObserver API. Encapsulates the ResizeObserver SPI implementation\r\n * exposing only those methods and properties that are defined in the spec.\r\n */\r\nvar ResizeObserver = /** @class */ (function () {\r\n /**\r\n * Creates a new instance of ResizeObserver.\r\n *\r\n * @param {ResizeObserverCallback} callback - Callback that is invoked when\r\n * dimensions of the observed elements change.\r\n */\r\n function ResizeObserver(callback) {\r\n if (!(this instanceof ResizeObserver)) {\r\n throw new TypeError('Cannot call a class as a function.');\r\n }\r\n if (!arguments.length) {\r\n throw new TypeError('1 argument required, but only 0 present.');\r\n }\r\n var controller = ResizeObserverController.getInstance();\r\n var observer = new ResizeObserverSPI(callback, controller, this);\r\n observers.set(this, observer);\r\n }\r\n return ResizeObserver;\r\n}());\r\n// Expose public methods of ResizeObserver.\r\n[\r\n 'observe',\r\n 'unobserve',\r\n 'disconnect'\r\n].forEach(function (method) {\r\n ResizeObserver.prototype[method] = function () {\r\n var _a;\r\n return (_a = observers.get(this))[method].apply(_a, arguments);\r\n };\r\n});\n\nvar index = (function () {\r\n // Export existing implementation if available.\r\n if (typeof global$1.ResizeObserver !== 'undefined') {\r\n return global$1.ResizeObserver;\r\n }\r\n return ResizeObserver;\r\n})();\n\nexport default index;\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ResizeObserver from \"resize-observer-polyfill\"\nimport {\n NEVER,\n Observable,\n Subject,\n defer,\n filter,\n finalize,\n map,\n merge,\n of,\n shareReplay,\n startWith,\n switchMap,\n tap\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Element offset\n */\nexport interface ElementSize {\n width: number /* Element width */\n height: number /* Element height */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Resize observer entry subject\n */\nconst entry$ = new Subject()\n\n/**\n * Resize observer observable\n *\n * This observable will create a `ResizeObserver` on the first subscription\n * and will automatically terminate it when there are no more subscribers.\n * It's quite important to centralize observation in a single `ResizeObserver`,\n * as the performance difference can be quite dramatic, as the link shows.\n *\n * @see https://bit.ly/3iIYfEm - Google Groups on performance\n */\nconst observer$ = defer(() => of(\n new ResizeObserver(entries => {\n for (const entry of entries)\n entry$.next(entry)\n })\n))\n .pipe(\n switchMap(observer => merge(NEVER, of(observer))\n .pipe(\n finalize(() => observer.disconnect())\n )\n ),\n shareReplay(1)\n )\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element size\n *\n * @param el - Element\n *\n * @returns Element size\n */\nexport function getElementSize(\n el: HTMLElement\n): ElementSize {\n return {\n width: el.offsetWidth,\n height: el.offsetHeight\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element size\n *\n * This function returns an observable that subscribes to a single internal\n * instance of `ResizeObserver` upon subscription, and emit resize events until\n * termination. Note that this function should not be called with the same\n * element twice, as the first unsubscription will terminate observation.\n *\n * Sadly, we can't use the `DOMRect` objects returned by the observer, because\n * we need the emitted values to be consistent with `getElementSize`, which will\n * return the used values (rounded) and not actual values (unrounded). Thus, we\n * use the `offset*` properties. See the linked GitHub issue.\n *\n * @see https://bit.ly/3m0k3he - GitHub issue\n *\n * @param el - Element\n *\n * @returns Element size observable\n */\nexport function watchElementSize(\n el: HTMLElement\n): Observable {\n return observer$\n .pipe(\n tap(observer => observer.observe(el)),\n switchMap(observer => entry$\n .pipe(\n filter(({ target }) => target === el),\n finalize(() => observer.unobserve(el)),\n map(() => getElementSize(el))\n )\n ),\n startWith(getElementSize(el))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ElementSize } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element content size (= scroll width and height)\n *\n * @param el - Element\n *\n * @returns Element content size\n */\nexport function getElementContentSize(\n el: HTMLElement\n): ElementSize {\n return {\n width: el.scrollWidth,\n height: el.scrollHeight\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n NEVER,\n Observable,\n Subject,\n defer,\n distinctUntilChanged,\n filter,\n finalize,\n map,\n merge,\n of,\n shareReplay,\n switchMap,\n tap\n} from \"rxjs\"\n\nimport {\n getElementContentSize,\n getElementSize,\n watchElementContentOffset\n} from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Intersection observer entry subject\n */\nconst entry$ = new Subject()\n\n/**\n * Intersection observer observable\n *\n * This observable will create an `IntersectionObserver` on first subscription\n * and will automatically terminate it when there are no more subscribers.\n *\n * @see https://bit.ly/3iIYfEm - Google Groups on performance\n */\nconst observer$ = defer(() => of(\n new IntersectionObserver(entries => {\n for (const entry of entries)\n entry$.next(entry)\n }, {\n threshold: 0\n })\n))\n .pipe(\n switchMap(observer => merge(NEVER, of(observer))\n .pipe(\n finalize(() => observer.disconnect())\n )\n ),\n shareReplay(1)\n )\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch element visibility\n *\n * @param el - Element\n *\n * @returns Element visibility observable\n */\nexport function watchElementVisibility(\n el: HTMLElement\n): Observable {\n return observer$\n .pipe(\n tap(observer => observer.observe(el)),\n switchMap(observer => entry$\n .pipe(\n filter(({ target }) => target === el),\n finalize(() => observer.unobserve(el)),\n map(({ isIntersecting }) => isIntersecting)\n )\n )\n )\n}\n\n/**\n * Watch element boundary\n *\n * This function returns an observable which emits whether the bottom content\n * boundary (= scroll offset) of an element is within a certain threshold.\n *\n * @param el - Element\n * @param threshold - Threshold\n *\n * @returns Element boundary observable\n */\nexport function watchElementBoundary(\n el: HTMLElement, threshold = 16\n): Observable {\n return watchElementContentOffset(el)\n .pipe(\n map(({ y }) => {\n const visible = getElementSize(el)\n const content = getElementContentSize(el)\n return y >= (\n content.height - visible.height - threshold\n )\n }),\n distinctUntilChanged()\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n fromEvent,\n map,\n startWith\n} from \"rxjs\"\n\nimport { getElement } from \"../element\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Toggle\n */\nexport type Toggle =\n | \"drawer\" /* Toggle for drawer */\n | \"search\" /* Toggle for search */\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Toggle map\n */\nconst toggles: Record = {\n drawer: getElement(\"[data-md-toggle=drawer]\"),\n search: getElement(\"[data-md-toggle=search]\")\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve the value of a toggle\n *\n * @param name - Toggle\n *\n * @returns Toggle value\n */\nexport function getToggle(name: Toggle): boolean {\n return toggles[name].checked\n}\n\n/**\n * Set toggle\n *\n * Simulating a click event seems to be the most cross-browser compatible way\n * of changing the value while also emitting a `change` event. Before, Material\n * used `CustomEvent` to programmatically change the value of a toggle, but this\n * is a much simpler and cleaner solution which doesn't require a polyfill.\n *\n * @param name - Toggle\n * @param value - Toggle value\n */\nexport function setToggle(name: Toggle, value: boolean): void {\n if (toggles[name].checked !== value)\n toggles[name].click()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch toggle\n *\n * @param name - Toggle\n *\n * @returns Toggle value observable\n */\nexport function watchToggle(name: Toggle): Observable {\n const el = toggles[name]\n return fromEvent(el, \"change\")\n .pipe(\n map(() => el.checked),\n startWith(el.checked)\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n filter,\n fromEvent,\n map,\n share\n} from \"rxjs\"\n\nimport { getActiveElement } from \"../element\"\nimport { getToggle } from \"../toggle\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Keyboard mode\n */\nexport type KeyboardMode =\n | \"global\" /* Global */\n | \"search\" /* Search is open */\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Keyboard\n */\nexport interface Keyboard {\n mode: KeyboardMode /* Keyboard mode */\n type: string /* Key type */\n claim(): void /* Key claim */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Check whether an element may receive keyboard input\n *\n * @param el - Element\n * @param type - Key type\n *\n * @returns Test result\n */\nfunction isSusceptibleToKeyboard(\n el: HTMLElement, type: string\n): boolean {\n switch (el.constructor) {\n\n /* Input elements */\n case HTMLInputElement:\n /* @ts-expect-error - omit unnecessary type cast */\n if (el.type === \"radio\")\n return /^Arrow/.test(type)\n else\n return true\n\n /* Select element and textarea */\n case HTMLSelectElement:\n case HTMLTextAreaElement:\n return true\n\n /* Everything else */\n default:\n return el.isContentEditable\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch keyboard\n *\n * @returns Keyboard observable\n */\nexport function watchKeyboard(): Observable {\n return fromEvent(window, \"keydown\")\n .pipe(\n filter(ev => !(ev.metaKey || ev.ctrlKey)),\n map(ev => ({\n mode: getToggle(\"search\") ? \"search\" : \"global\",\n type: ev.key,\n claim() {\n ev.preventDefault()\n ev.stopPropagation()\n }\n } as Keyboard)),\n filter(({ mode, type }) => {\n if (mode === \"global\") {\n const active = getActiveElement()\n if (typeof active !== \"undefined\")\n return !isSusceptibleToKeyboard(active, type)\n }\n return true\n }),\n share()\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Subject } from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve location\n *\n * This function returns a `URL` object (and not `Location`) to normalize the\n * typings across the application. Furthermore, locations need to be tracked\n * without setting them and `Location` is a singleton which represents the\n * current location.\n *\n * @returns URL\n */\nexport function getLocation(): URL {\n return new URL(location.href)\n}\n\n/**\n * Set location\n *\n * @param url - URL to change to\n */\nexport function setLocation(url: URL): void {\n location.href = url.href\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch location\n *\n * @returns Location subject\n */\nexport function watchLocation(): Subject {\n return new Subject()\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { JSX as JSXInternal } from \"preact\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * HTML attributes\n */\ntype Attributes =\n & JSXInternal.HTMLAttributes\n & JSXInternal.SVGAttributes\n & Record\n\n/**\n * Child element\n */\ntype Child =\n | HTMLElement\n | Text\n | string\n | number\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Append a child node to an element\n *\n * @param el - Element\n * @param child - Child node(s)\n */\nfunction appendChild(el: HTMLElement, child: Child | Child[]): void {\n\n /* Handle primitive types (including raw HTML) */\n if (typeof child === \"string\" || typeof child === \"number\") {\n el.innerHTML += child.toString()\n\n /* Handle nodes */\n } else if (child instanceof Node) {\n el.appendChild(child)\n\n /* Handle nested children */\n } else if (Array.isArray(child)) {\n for (const node of child)\n appendChild(el, node)\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * JSX factory\n *\n * @template T - Element type\n *\n * @param tag - HTML tag\n * @param attributes - HTML attributes\n * @param children - Child elements\n *\n * @returns Element\n */\nexport function h(\n tag: T, attributes?: Attributes | null, ...children: Child[]\n): HTMLElementTagNameMap[T]\n\nexport function h(\n tag: string, attributes?: Attributes | null, ...children: Child[]\n): T\n\nexport function h(\n tag: string, attributes?: Attributes | null, ...children: Child[]\n): T {\n const el = document.createElement(tag)\n\n /* Set attributes, if any */\n if (attributes)\n for (const attr of Object.keys(attributes)) {\n if (typeof attributes[attr] === \"undefined\")\n continue\n\n /* Set default attribute or boolean */\n if (typeof attributes[attr] !== \"boolean\")\n el.setAttribute(attr, attributes[attr])\n else\n el.setAttribute(attr, \"\")\n }\n\n /* Append child nodes */\n for (const child of children)\n appendChild(el, child)\n\n /* Return element */\n return el as T\n}\n\n/* ----------------------------------------------------------------------------\n * Namespace\n * ------------------------------------------------------------------------- */\n\nexport declare namespace h {\n namespace JSX {\n type Element = HTMLElement\n type IntrinsicElements = JSXInternal.IntrinsicElements\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Truncate a string after the given number of characters\n *\n * This is not a very reasonable approach, since the summaries kind of suck.\n * It would be better to create something more intelligent, highlighting the\n * search occurrences and making a better summary out of it, but this note was\n * written three years ago, so who knows if we'll ever fix it.\n *\n * @param value - Value to be truncated\n * @param n - Number of characters\n *\n * @returns Truncated value\n */\nexport function truncate(value: string, n: number): string {\n let i = n\n if (value.length > i) {\n while (value[i] !== \" \" && --i > 0) { /* keep eating */ }\n return `${value.substring(0, i)}...`\n }\n return value\n}\n\n/**\n * Round a number for display with repository facts\n *\n * This is a reverse-engineered version of GitHub's weird rounding algorithm\n * for stars, forks and all other numbers. While all numbers below `1,000` are\n * returned as-is, bigger numbers are converted to fixed numbers:\n *\n * - `1,049` => `1k`\n * - `1,050` => `1.1k`\n * - `1,949` => `1.9k`\n * - `1,950` => `2k`\n *\n * @param value - Original value\n *\n * @returns Rounded value\n */\nexport function round(value: number): string {\n if (value > 999) {\n const digits = +((value - 950) % 1000 > 99)\n return `${((value + 0.000001) / 1000).toFixed(digits)}k`\n } else {\n return value.toString()\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n filter,\n fromEvent,\n map,\n shareReplay,\n startWith\n} from \"rxjs\"\n\nimport { getOptionalElement } from \"~/browser\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve location hash\n *\n * @returns Location hash\n */\nexport function getLocationHash(): string {\n return location.hash.substring(1)\n}\n\n/**\n * Set location hash\n *\n * Setting a new fragment identifier via `location.hash` will have no effect\n * if the value doesn't change. When a new fragment identifier is set, we want\n * the browser to target the respective element at all times, which is why we\n * use this dirty little trick.\n *\n * @param hash - Location hash\n */\nexport function setLocationHash(hash: string): void {\n const el = h(\"a\", { href: hash })\n el.addEventListener(\"click\", ev => ev.stopPropagation())\n el.click()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch location hash\n *\n * @returns Location hash observable\n */\nexport function watchLocationHash(): Observable {\n return fromEvent(window, \"hashchange\")\n .pipe(\n map(getLocationHash),\n startWith(getLocationHash()),\n filter(hash => hash.length > 0),\n shareReplay(1)\n )\n}\n\n/**\n * Watch location target\n *\n * @returns Location target observable\n */\nexport function watchLocationTarget(): Observable {\n return watchLocationHash()\n .pipe(\n map(id => getOptionalElement(`[id=\"${id}\"]`)!),\n filter(el => typeof el !== \"undefined\")\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n fromEvent,\n fromEventPattern,\n map,\n merge,\n startWith,\n switchMap\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch media query\n *\n * Note that although `MediaQueryList.addListener` is deprecated we have to\n * use it, because it's the only way to ensure proper downward compatibility.\n *\n * @see https://bit.ly/3dUBH2m - GitHub issue\n *\n * @param query - Media query\n *\n * @returns Media observable\n */\nexport function watchMedia(query: string): Observable {\n const media = matchMedia(query)\n return fromEventPattern(next => (\n media.addListener(() => next(media.matches))\n ))\n .pipe(\n startWith(media.matches)\n )\n}\n\n/**\n * Watch print mode\n *\n * @returns Print observable\n */\nexport function watchPrint(): Observable {\n const media = matchMedia(\"print\")\n return merge(\n fromEvent(window, \"beforeprint\").pipe(map(() => true)),\n fromEvent(window, \"afterprint\").pipe(map(() => false))\n )\n .pipe(\n startWith(media.matches)\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Toggle an observable with a media observable\n *\n * @template T - Data type\n *\n * @param query$ - Media observable\n * @param factory - Observable factory\n *\n * @returns Toggled observable\n */\nexport function at(\n query$: Observable, factory: () => Observable\n): Observable {\n return query$\n .pipe(\n switchMap(active => active ? factory() : EMPTY)\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n catchError,\n from,\n map,\n of,\n shareReplay,\n switchMap,\n throwError\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch the given URL\n *\n * If the request fails (e.g. when dispatched from `file://` locations), the\n * observable will complete without emitting a value.\n *\n * @param url - Request URL\n * @param options - Options\n *\n * @returns Response observable\n */\nexport function request(\n url: URL | string, options: RequestInit = { credentials: \"same-origin\" }\n): Observable {\n return from(fetch(`${url}`, options))\n .pipe(\n catchError(() => EMPTY),\n switchMap(res => res.status !== 200\n ? throwError(() => new Error(res.statusText))\n : of(res)\n )\n )\n}\n\n/**\n * Fetch JSON from the given URL\n *\n * @template T - Data type\n *\n * @param url - Request URL\n * @param options - Options\n *\n * @returns Data observable\n */\nexport function requestJSON(\n url: URL | string, options?: RequestInit\n): Observable {\n return request(url, options)\n .pipe(\n switchMap(res => res.json()),\n shareReplay(1)\n )\n}\n\n/**\n * Fetch XML from the given URL\n *\n * @param url - Request URL\n * @param options - Options\n *\n * @returns Data observable\n */\nexport function requestXML(\n url: URL | string, options?: RequestInit\n): Observable {\n const dom = new DOMParser()\n return request(url, options)\n .pipe(\n switchMap(res => res.text()),\n map(res => dom.parseFromString(res, \"text/xml\")),\n shareReplay(1)\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n defer,\n finalize,\n fromEvent,\n map,\n merge,\n switchMap,\n take,\n throwError\n} from \"rxjs\"\n\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create and load a `script` element\n *\n * This function returns an observable that will emit when the script was\n * successfully loaded, or throw an error if it didn't.\n *\n * @param src - Script URL\n *\n * @returns Script observable\n */\nexport function watchScript(src: string): Observable {\n const script = h(\"script\", { src })\n return defer(() => {\n document.head.appendChild(script)\n return merge(\n fromEvent(script, \"load\"),\n fromEvent(script, \"error\")\n .pipe(\n switchMap(() => (\n throwError(() => new ReferenceError(`Invalid script: ${src}`))\n ))\n )\n )\n .pipe(\n map(() => undefined),\n finalize(() => document.head.removeChild(script)),\n take(1)\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n fromEvent,\n map,\n merge,\n startWith\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport offset\n */\nexport interface ViewportOffset {\n x: number /* Horizontal offset */\n y: number /* Vertical offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve viewport offset\n *\n * On iOS Safari, viewport offset can be negative due to overflow scrolling.\n * As this may induce strange behaviors downstream, we'll just limit it to 0.\n *\n * @returns Viewport offset\n */\nexport function getViewportOffset(): ViewportOffset {\n return {\n x: Math.max(0, scrollX),\n y: Math.max(0, scrollY)\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport offset\n *\n * @returns Viewport offset observable\n */\nexport function watchViewportOffset(): Observable {\n return merge(\n fromEvent(window, \"scroll\", { passive: true }),\n fromEvent(window, \"resize\", { passive: true })\n )\n .pipe(\n map(getViewportOffset),\n startWith(getViewportOffset())\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n fromEvent,\n map,\n startWith\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport size\n */\nexport interface ViewportSize {\n width: number /* Viewport width */\n height: number /* Viewport height */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve viewport size\n *\n * @returns Viewport size\n */\nexport function getViewportSize(): ViewportSize {\n return {\n width: innerWidth,\n height: innerHeight\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport size\n *\n * @returns Viewport size observable\n */\nexport function watchViewportSize(): Observable {\n return fromEvent(window, \"resize\", { passive: true })\n .pipe(\n map(getViewportSize),\n startWith(getViewportSize())\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n combineLatest,\n map,\n shareReplay\n} from \"rxjs\"\n\nimport {\n ViewportOffset,\n watchViewportOffset\n} from \"../offset\"\nimport {\n ViewportSize,\n watchViewportSize\n} from \"../size\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport\n */\nexport interface Viewport {\n offset: ViewportOffset /* Viewport offset */\n size: ViewportSize /* Viewport size */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport\n *\n * @returns Viewport observable\n */\nexport function watchViewport(): Observable {\n return combineLatest([\n watchViewportOffset(),\n watchViewportSize()\n ])\n .pipe(\n map(([offset, size]) => ({ offset, size })),\n shareReplay(1)\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n combineLatest,\n distinctUntilKeyChanged,\n map\n} from \"rxjs\"\n\nimport { Header } from \"~/components\"\n\nimport { getElementOffset } from \"../../element\"\nimport { Viewport } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
/* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport relative to element\n *\n * @param el - Element\n * @param options - Options\n *\n * @returns Viewport observable\n */\nexport function watchViewportAt(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable {\n const size$ = viewport$\n .pipe(\n distinctUntilKeyChanged(\"size\")\n )\n\n /* Compute element offset */\n const offset$ = combineLatest([size$, header$])\n .pipe(\n map(() => getElementOffset(el))\n )\n\n /* Compute relative viewport, return hot observable */\n return combineLatest([header$, viewport$, offset$])\n .pipe(\n map(([{ height }, { offset, size }, { x, y }]) => ({\n offset: {\n x: offset.x - x,\n y: offset.y - y + height\n },\n size\n }))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n fromEvent,\n map,\n share,\n switchMap,\n tap,\n throttle\n} from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Worker message\n */\nexport interface WorkerMessage {\n type: unknown /* Message type */\n data?: unknown /* Message data */\n}\n\n/**\n * Worker handler\n *\n * @template T - Message type\n */\nexport interface WorkerHandler<\n T extends WorkerMessage\n> {\n tx$: Subject /* Message transmission subject */\n rx$: Observable /* Message receive observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n *\n * @template T - Worker message type\n */\ninterface WatchOptions {\n tx$: Observable /* Message transmission observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch a web worker\n *\n * This function returns an observable that sends all values emitted by the\n * message observable to the web worker. Web worker communication is expected\n * to be bidirectional (request-response) and synchronous. Messages that are\n * emitted during a pending request are throttled, the last one is emitted.\n *\n * @param worker - Web worker\n * @param options - Options\n *\n * @returns Worker message observable\n */\nexport function watchWorker(\n worker: Worker, { tx$ }: WatchOptions\n): Observable {\n\n /* Intercept messages from worker-like objects */\n const rx$ = fromEvent(worker, \"message\")\n .pipe(\n map(({ data }) => data as T)\n )\n\n /* Send and receive messages, return hot observable */\n return tx$\n .pipe(\n throttle(() => rx$, { leading: true, trailing: true }),\n tap(message => worker.postMessage(message)),\n switchMap(() => rx$),\n share()\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { getElement, getLocation } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Feature flag\n */\nexport type Flag =\n | \"announce.dismiss\" /* Dismissable announcement bar */\n | \"content.code.annotate\" /* Code annotations */\n | \"content.tabs.link\" /* Link content tabs */\n | \"header.autohide\" /* Hide header */\n | \"navigation.expand\" /* Automatic expansion */\n | \"navigation.indexes\" /* Section pages */\n | \"navigation.instant\" /* Instant loading */\n | \"navigation.sections\" /* Section navigation */\n | \"navigation.tabs\" /* Tabs navigation */\n | \"navigation.tabs.sticky\" /* Tabs navigation (sticky) */\n | \"navigation.top\" /* Back-to-top button */\n | \"navigation.tracking\" /* Anchor tracking */\n | \"search.highlight\" /* Search highlighting */\n | \"search.share\" /* Search sharing */\n | \"search.suggest\" /* Search suggestions */\n | \"toc.integrate\" /* Integrated table of contents */\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Translation\n */\nexport type Translation =\n | \"clipboard.copy\" /* Copy to clipboard */\n | \"clipboard.copied\" /* Copied to clipboard */\n | \"search.config.lang\" /* Search language */\n | \"search.config.pipeline\" /* Search pipeline */\n | \"search.config.separator\" /* Search separator */\n | \"search.placeholder\" /* Search */\n | \"search.result.placeholder\" /* Type to start searching */\n | \"search.result.none\" /* No matching documents */\n | \"search.result.one\" /* 1 matching document */\n | \"search.result.other\" /* # matching documents */\n | \"search.result.more.one\" /* 1 more on this page */\n | \"search.result.more.other\" /* # more on this page */\n | \"search.result.term.missing\" /* Missing */\n | \"select.version.title\" /* Version selector */\n\n/**\n * Translations\n */\nexport type Translations = Record\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Versioning\n */\nexport interface Versioning {\n provider: \"mike\" /* Version provider */\n default?: string /* Default version */\n}\n\n/**\n * Configuration\n */\nexport interface Config {\n base: string /* Base URL */\n features: Flag[] /* Feature flags */\n translations: Translations /* Translations */\n search: string /* Search worker URL */\n version?: Versioning /* Versioning */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve global configuration and make base URL absolute\n */\nconst script = getElement(\"#__config\")\nconst config: Config = JSON.parse(script.textContent!)\nconfig.base = `${new URL(config.base, getLocation())}`\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve global configuration\n *\n * @returns Global configuration\n */\nexport function configuration(): Config {\n return config\n}\n\n/**\n * Check whether a feature flag is enabled\n *\n * @param flag - Feature flag\n *\n * @returns Test result\n */\nexport function feature(flag: Flag): boolean {\n return config.features.includes(flag)\n}\n\n/**\n * Retrieve the translation for the given key\n *\n * @param key - Key to be translated\n * @param value - Positional value, if any\n *\n * @returns Translation\n */\nexport function translation(\n key: Translation, value?: string | number\n): string {\n return typeof value !== \"undefined\"\n ? config.translations[key].replace(\"#\", value.toString())\n : config.translations[key]\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { getElement, getElements } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Component type\n */\nexport type ComponentType =\n | \"announce\" /* Announcement bar */\n | \"container\" /* Container */\n | \"consent\" /* Consent */\n | \"content\" /* Content */\n | \"dialog\" /* Dialog */\n | \"header\" /* Header */\n | \"header-title\" /* Header title */\n | \"header-topic\" /* Header topic */\n | \"main\" /* Main area */\n | \"outdated\" /* Version warning */\n | \"palette\" /* Color palette */\n | \"search\" /* Search */\n | \"search-query\" /* Search input */\n | \"search-result\" /* Search results */\n | \"search-share\" /* Search sharing */\n | \"search-suggest\" /* Search suggestions */\n | \"sidebar\" /* Sidebar */\n | \"skip\" /* Skip link */\n | \"source\" /* Repository information */\n | \"tabs\" /* Navigation tabs */\n | \"toc\" /* Table of contents */\n | \"top\" /* Back-to-top button */\n\n/**\n * Component\n *\n * @template T - Component type\n * @template U - Reference type\n */\nexport type Component<\n T extends {} = {},\n U extends HTMLElement = HTMLElement\n> =\n T & {\n ref: U /* Component reference */\n }\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Component type map\n */\ninterface ComponentTypeMap {\n \"announce\": HTMLElement /* Announcement bar */\n \"container\": HTMLElement /* Container */\n \"consent\": HTMLElement /* Consent */\n \"content\": HTMLElement /* Content */\n \"dialog\": HTMLElement /* Dialog */\n \"header\": HTMLElement /* Header */\n \"header-title\": HTMLElement /* Header title */\n \"header-topic\": HTMLElement /* Header topic */\n \"main\": HTMLElement /* Main area */\n \"outdated\": HTMLElement /* Version warning */\n \"palette\": HTMLElement /* Color palette */\n \"search\": HTMLElement /* Search */\n \"search-query\": HTMLInputElement /* Search input */\n \"search-result\": HTMLElement /* Search results */\n \"search-share\": HTMLAnchorElement /* Search sharing */\n \"search-suggest\": HTMLElement /* Search suggestions */\n \"sidebar\": HTMLElement /* Sidebar */\n \"skip\": HTMLAnchorElement /* Skip link */\n \"source\": HTMLAnchorElement /* Repository information */\n \"tabs\": HTMLElement /* Navigation tabs */\n \"toc\": HTMLElement /* Table of contents */\n \"top\": HTMLAnchorElement /* Back-to-top button */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve the element for a given component or throw a reference error\n *\n * @template T - Component type\n *\n * @param type - Component type\n * @param node - Node of reference\n *\n * @returns Element\n */\nexport function getComponentElement(\n type: T, node: ParentNode = document\n): ComponentTypeMap[T] {\n return getElement(`[data-md-component=${type}]`, node)\n}\n\n/**\n * Retrieve all elements for a given component\n *\n * @template T - Component type\n *\n * @param type - Component type\n * @param node - Node of reference\n *\n * @returns Elements\n */\nexport function getComponentElements(\n type: T, node: ParentNode = document\n): ComponentTypeMap[T][] {\n return getElements(`[data-md-component=${type}]`, node)\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n Subject,\n defer,\n finalize,\n fromEvent,\n map,\n startWith,\n tap\n} from \"rxjs\"\n\nimport { feature } from \"~/_\"\nimport { getElement } from \"~/browser\"\n\nimport { Component } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Announcement bar\n */\nexport interface Announce {\n hash: number /* Content hash */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch announcement bar\n *\n * @param el - Announcement bar element\n *\n * @returns Announcement bar observable\n */\nexport function watchAnnounce(\n el: HTMLElement\n): Observable {\n const button = getElement(\".md-typeset > :first-child\", el)\n return fromEvent(button, \"click\", { once: true })\n .pipe(\n map(() => getElement(\".md-typeset\", el)),\n map(content => ({ hash: __md_hash(content.innerHTML) }))\n )\n}\n\n/**\n * Mount announcement bar\n *\n * @param el - Announcement bar element\n *\n * @returns Announcement bar component observable\n */\nexport function mountAnnounce(\n el: HTMLElement\n): Observable> {\n if (!feature(\"announce.dismiss\") || !el.childElementCount)\n return EMPTY\n\n /* Mount component on subscription */\n return defer(() => {\n const push$ = new Subject()\n push$\n .pipe(\n startWith({ hash: __md_get(\"__announce\") })\n )\n .subscribe(({ hash }) => {\n if (hash && hash === (__md_get(\"__announce\") ?? hash)) {\n el.hidden = true\n\n /* Persist preference in local storage */\n __md_set(\"__announce\", hash)\n }\n })\n\n /* Create and return component */\n return watchAnnounce(el)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n finalize,\n map,\n tap\n} from \"rxjs\"\n\nimport { Component } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Consent\n */\nexport interface Consent {\n hidden: boolean /* Consent is hidden */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n target$: Observable /* Target observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n target$: Observable /* Target observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch consent\n *\n * @param el - Consent element\n * @param options - Options\n *\n * @returns Consent observable\n */\nexport function watchConsent(\n el: HTMLElement, { target$ }: WatchOptions\n): Observable {\n return target$\n .pipe(\n map(target => ({ hidden: target !== el }))\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Mount consent\n *\n * @param el - Consent element\n * @param options - Options\n *\n * @returns Consent component observable\n */\nexport function mountConsent(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$.subscribe(({ hidden }) => {\n el.hidden = hidden\n })\n\n /* Create and return component */\n return watchConsent(el, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ClipboardJS from \"clipboard\"\nimport {\n EMPTY,\n Observable,\n Subject,\n defer,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n filter,\n finalize,\n map,\n mergeWith,\n switchMap,\n take,\n takeLast,\n takeUntil,\n tap\n} from \"rxjs\"\n\nimport { feature } from \"~/_\"\nimport {\n getElementContentSize,\n watchElementSize,\n watchElementVisibility\n} from \"~/browser\"\nimport { renderClipboardButton } from \"~/templates\"\n\nimport { Component } from \"../../../_\"\nimport {\n Annotation,\n mountAnnotationList\n} from \"../../annotation\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Code block\n */\nexport interface CodeBlock {\n scrollable: boolean /* Code block overflows */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n print$: Observable /* Media print observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Global sequence number for Clipboard.js integration\n */\nlet sequence = 0\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Find candidate list element directly following a code block\n *\n * @param el - Code block element\n *\n * @returns List element or nothing\n */\nfunction findCandidateList(el: HTMLElement): HTMLElement | undefined {\n if (el.nextElementSibling) {\n const sibling = el.nextElementSibling as HTMLElement\n if (sibling.tagName === \"OL\")\n return sibling\n\n /* Skip empty paragraphs - see https://bit.ly/3r4ZJ2O */\n else if (sibling.tagName === \"P\" && !sibling.children.length)\n return findCandidateList(sibling)\n }\n\n /* Everything else */\n return undefined\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch code block\n *\n * This function monitors size changes of the viewport, as well as switches of\n * content tabs with embedded code blocks, as both may trigger overflow.\n *\n * @param el - Code block element\n *\n * @returns Code block observable\n */\nexport function watchCodeBlock(\n el: HTMLElement\n): Observable {\n return watchElementSize(el)\n .pipe(\n map(({ width }) => {\n const content = getElementContentSize(el)\n return {\n scrollable: content.width > width\n }\n }),\n distinctUntilKeyChanged(\"scrollable\")\n )\n}\n\n/**\n * Mount code block\n *\n * This function ensures that an overflowing code block is focusable through\n * keyboard, so it can be scrolled without a mouse to improve on accessibility.\n * Furthermore, if code annotations are enabled, they are mounted if and only\n * if the code block is currently visible, e.g., not in a hidden content tab.\n *\n * @param el - Code block element\n * @param options - Options\n *\n * @returns Code block and annotation component observable\n */\nexport function mountCodeBlock(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const { matches: hover } = matchMedia(\"(hover)\")\n\n /* Defer mounting of code block - see https://bit.ly/3vHVoVD */\n const factory$ = defer(() => {\n const push$ = new Subject()\n push$.subscribe(({ scrollable }) => {\n if (scrollable && hover)\n el.setAttribute(\"tabindex\", \"0\")\n else\n el.removeAttribute(\"tabindex\")\n })\n\n /* Render button for Clipboard.js integration */\n if (ClipboardJS.isSupported()) {\n const parent = el.closest(\"pre\")!\n parent.id = `__code_${++sequence}`\n parent.insertBefore(\n renderClipboardButton(parent.id),\n el\n )\n }\n\n /* Handle code annotations */\n const container = el.closest(\".highlight\")\n if (container instanceof HTMLElement) {\n const list = findCandidateList(container)\n\n /* Mount code annotations, if enabled */\n if (typeof list !== \"undefined\" && (\n container.classList.contains(\"annotate\") ||\n feature(\"content.code.annotate\")\n )) {\n const annotations$ = mountAnnotationList(list, el, options)\n\n /* Create and return component */\n return watchCodeBlock(el)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state })),\n mergeWith(\n watchElementSize(container)\n .pipe(\n takeUntil(push$.pipe(takeLast(1))),\n map(({ width, height }) => width && height),\n distinctUntilChanged(),\n switchMap(active => active ? annotations$ : EMPTY)\n )\n )\n )\n }\n }\n\n /* Create and return component */\n return watchCodeBlock(el)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n\n /* Mount code block on first sight */\n return watchElementVisibility(el)\n .pipe(\n filter(visible => visible),\n take(1),\n switchMap(() => factory$)\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render an empty annotation\n *\n * @param id - Annotation identifier\n *\n * @returns Element\n */\nexport function renderAnnotation(id: number): HTMLElement {\n return (\n \n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a 'copy-to-clipboard' button\n *\n * @param id - Unique identifier\n *\n * @returns Element\n */\nexport function renderClipboardButton(id: string): HTMLElement {\n return (\n code`}\n >\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ComponentChild } from \"preact\"\n\nimport { feature, translation } from \"~/_\"\nimport {\n SearchDocument,\n SearchMetadata,\n SearchResultItem\n} from \"~/integrations/search\"\nimport { h, truncate } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Render flag\n */\nconst enum Flag {\n TEASER = 1, /* Render teaser */\n PARENT = 2 /* Render as parent */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper function\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a search document\n *\n * @param document - Search document\n * @param flag - Render flags\n *\n * @returns Element\n */\nfunction renderSearchDocument(\n document: SearchDocument & SearchMetadata, flag: Flag\n): HTMLElement {\n const parent = flag & Flag.PARENT\n const teaser = flag & Flag.TEASER\n\n /* Render missing query terms */\n const missing = Object.keys(document.terms)\n .filter(key => !document.terms[key])\n .reduce((list, key) => [\n ...list, {key}, \" \"\n ], [])\n .slice(0, -1)\n\n /* Assemble query string for highlighting */\n const url = new URL(document.location)\n if (feature(\"search.highlight\"))\n url.searchParams.set(\"h\", Object.entries(document.terms)\n .filter(([, match]) => match)\n .reduce((highlight, [value]) => `${highlight} ${value}`.trim(), \"\")\n )\n\n /* Render article or section, depending on flags */\n return (\n \n \n {parent > 0 &&
}\n

{document.title}

\n {teaser > 0 && document.text.length > 0 &&\n

\n {truncate(document.text, 320)}\n

\n }\n {document.tags && document.tags.map(tag => (\n {tag}\n ))}\n {teaser > 0 && missing.length > 0 &&\n

\n {translation(\"search.result.term.missing\")}: {...missing}\n

\n }\n \n
\n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a search result\n *\n * @param result - Search result\n *\n * @returns Element\n */\nexport function renderSearchResultItem(\n result: SearchResultItem\n): HTMLElement {\n const threshold = result[0].score\n const docs = [...result]\n\n /* Find and extract parent article */\n const parent = docs.findIndex(doc => !doc.location.includes(\"#\"))\n const [article] = docs.splice(parent, 1)\n\n /* Determine last index above threshold */\n let index = docs.findIndex(doc => doc.score < threshold)\n if (index === -1)\n index = docs.length\n\n /* Partition sections */\n const best = docs.slice(0, index)\n const more = docs.slice(index)\n\n /* Render children */\n const children = [\n renderSearchDocument(article, Flag.PARENT | +(!parent && index === 0)),\n ...best.map(section => renderSearchDocument(section, Flag.TEASER)),\n ...more.length ? [\n
\n \n {more.length > 0 && more.length === 1\n ? translation(\"search.result.more.one\")\n : translation(\"search.result.more.other\", more.length)\n }\n \n {...more.map(section => renderSearchDocument(section, Flag.TEASER))}\n
\n ] : []\n ]\n\n /* Render search result */\n return (\n
  • \n {children}\n
  • \n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SourceFacts } from \"~/components\"\nimport { h, round } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render repository facts\n *\n * @param facts - Repository facts\n *\n * @returns Element\n */\nexport function renderSourceFacts(facts: SourceFacts): HTMLElement {\n return (\n
      \n {Object.entries(facts).map(([key, value]) => (\n
    • \n {typeof value === \"number\" ? round(value) : value}\n
    • \n ))}\n
    \n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Tabbed control type\n */\ntype TabbedControlType =\n | \"prev\"\n | \"next\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render control for content tabs\n *\n * @param type - Control type\n *\n * @returns Element\n */\nexport function renderTabbedControl(\n type: TabbedControlType\n): HTMLElement {\n const classes = `tabbed-control tabbed-control--${type}`\n return (\n \n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a table inside a wrapper to improve scrolling on mobile\n *\n * @param table - Table element\n *\n * @returns Element\n */\nexport function renderTable(table: HTMLElement): HTMLElement {\n return (\n
    \n
    \n {table}\n
    \n
    \n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { configuration, translation } from \"~/_\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Version\n */\nexport interface Version {\n version: string /* Version identifier */\n title: string /* Version title */\n aliases: string[] /* Version aliases */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a version\n *\n * @param version - Version\n *\n * @returns Element\n */\nfunction renderVersion(version: Version): HTMLElement {\n const config = configuration()\n\n /* Ensure trailing slash, see https://bit.ly/3rL5u3f */\n const url = new URL(`../${version.version}/`, config.base)\n return (\n
  • \n \n {version.title}\n \n
  • \n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a version selector\n *\n * @param versions - Versions\n * @param active - Active version\n *\n * @returns Element\n */\nexport function renderVersionSelector(\n versions: Version[], active: Version\n): HTMLElement {\n return (\n
    \n \n {active.title}\n \n
      \n {versions.map(renderVersion)}\n
    \n
    \n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest,\n defer,\n finalize,\n fromEvent,\n map,\n switchMap,\n take,\n takeLast,\n takeUntil,\n tap,\n throttleTime\n} from \"rxjs\"\n\nimport {\n ElementOffset,\n getElement,\n getElementSize,\n watchElementContentOffset,\n watchElementFocus,\n watchElementOffset,\n watchElementVisibility\n} from \"~/browser\"\n\nimport { Component } from \"../../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Annotation\n */\nexport interface Annotation {\n active: boolean /* Annotation is active */\n offset: ElementOffset /* Annotation offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch annotation\n *\n * @param el - Annotation element\n * @param container - Containing element\n *\n * @returns Annotation observable\n */\nexport function watchAnnotation(\n el: HTMLElement, container: HTMLElement\n): Observable {\n const offset$ = defer(() => combineLatest([\n watchElementOffset(el),\n watchElementContentOffset(container)\n ]))\n .pipe(\n map(([{ x, y }, scroll]) => {\n const { width } = getElementSize(el)\n return ({\n x: x - scroll.x + width / 2,\n y: y - scroll.y\n })\n })\n )\n\n /* Actively watch annotation on focus */\n return watchElementFocus(el)\n .pipe(\n switchMap(active => offset$\n .pipe(\n map(offset => ({ active, offset })),\n take(+!active || Infinity)\n )\n )\n )\n}\n\n/**\n * Mount annotation\n *\n * @param el - Annotation element\n * @param container - Containing element\n *\n * @returns Annotation component observable\n */\nexport function mountAnnotation(\n el: HTMLElement, container: HTMLElement\n): Observable> {\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe({\n\n /* Handle emission */\n next({ offset }) {\n el.style.setProperty(\"--md-tooltip-x\", `${offset.x}px`)\n el.style.setProperty(\"--md-tooltip-y\", `${offset.y}px`)\n },\n\n /* Handle complete */\n complete() {\n el.style.removeProperty(\"--md-tooltip-x\")\n el.style.removeProperty(\"--md-tooltip-y\")\n }\n })\n\n /* Start animation only when annotation is visible */\n const done$ = push$.pipe(takeLast(1))\n watchElementVisibility(el)\n .pipe(\n takeUntil(done$)\n )\n .subscribe(visible => {\n el.toggleAttribute(\"data-md-visible\", visible)\n })\n\n /* Track relative origin of tooltip */\n push$\n .pipe(\n throttleTime(500, animationFrameScheduler),\n map(() => container.getBoundingClientRect()),\n map(({ x }) => x)\n )\n .subscribe({\n\n /* Handle emission */\n next(origin) {\n if (origin)\n el.style.setProperty(\"--md-tooltip-0\", `${-origin}px`)\n else\n el.style.removeProperty(\"--md-tooltip-0\")\n },\n\n /* Handle complete */\n complete() {\n el.style.removeProperty(\"--md-tooltip-0\")\n }\n })\n\n /* Close open annotation on click */\n const index = getElement(\":scope > :last-child\", el)\n const blur$ = fromEvent(index, \"mousedown\", { once: true })\n push$\n .pipe(\n switchMap(({ active }) => active ? blur$ : EMPTY),\n tap(ev => ev.preventDefault())\n )\n .subscribe(() => el.blur())\n\n /* Create and return component */\n return watchAnnotation(el, container)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n Subject,\n defer,\n finalize,\n merge,\n share,\n takeLast,\n takeUntil\n} from \"rxjs\"\n\nimport {\n getElement,\n getElements,\n getOptionalElement\n} from \"~/browser\"\nimport { renderAnnotation } from \"~/templates\"\n\nimport { Component } from \"../../../_\"\nimport {\n Annotation,\n mountAnnotation\n} from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n print$: Observable /* Media print observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Find all annotation markers in the given code block\n *\n * @param container - Containing element\n *\n * @returns Annotation markers\n */\nfunction findAnnotationMarkers(container: HTMLElement): Text[] {\n const markers: Text[] = []\n for (const comment of getElements(\".c, .c1, .cm\", container)) {\n let match: RegExpExecArray | null\n\n /* Split text at marker and add to list */\n let text = comment.firstChild as Text\n if (text instanceof Text)\n while ((match = /\\((\\d+)\\)/.exec(text.textContent!))) {\n const marker = text.splitText(match.index)\n text = marker.splitText(match[0].length)\n markers.push(marker)\n }\n }\n return markers\n}\n\n/**\n * Swap the child nodes of two elements\n *\n * @param source - Source element\n * @param target - Target element\n */\nfunction swap(source: HTMLElement, target: HTMLElement): void {\n target.append(...Array.from(source.childNodes))\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount annotation list\n *\n * This function analyzes the containing code block and checks for markers\n * referring to elements in the given annotation list. If no markers are found,\n * the list is left untouched. Otherwise, list elements are rendered as\n * annotations inside the code block.\n *\n * @param el - Annotation list element\n * @param container - Containing element\n * @param options - Options\n *\n * @returns Annotation component observable\n */\nexport function mountAnnotationList(\n el: HTMLElement, container: HTMLElement, { print$ }: MountOptions\n): Observable> {\n\n /* Find and replace all markers with empty annotations */\n const annotations = new Map()\n for (const marker of findAnnotationMarkers(container)) {\n const [, id] = marker.textContent!.match(/\\((\\d+)\\)/)!\n if (getOptionalElement(`li:nth-child(${id})`, el)) {\n annotations.set(+id, renderAnnotation(+id))\n marker.replaceWith(annotations.get(+id)!)\n }\n }\n\n /* Keep list if there are no annotations to render */\n if (annotations.size === 0)\n return EMPTY\n\n /* Create and return component */\n return defer(() => {\n const done$ = new Subject()\n\n /* Handle print mode - see https://bit.ly/3rgPdpt */\n print$\n .pipe(\n takeUntil(done$.pipe(takeLast(1)))\n )\n .subscribe(active => {\n el.hidden = !active\n\n /* Show annotations in code block or list (print) */\n for (const [id, annotation] of annotations) {\n const inner = getElement(\".md-typeset\", annotation)\n const child = getElement(`li:nth-child(${id})`, el)\n if (!active)\n swap(child, inner)\n else\n swap(inner, child)\n }\n })\n\n /* Create and return component */\n return merge(...[...annotations]\n .map(([, annotation]) => (\n mountAnnotation(annotation, container)\n ))\n )\n .pipe(\n finalize(() => done$.complete()),\n share()\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n map,\n of,\n shareReplay,\n tap\n} from \"rxjs\"\n\nimport { watchScript } from \"~/browser\"\nimport { h } from \"~/utilities\"\n\nimport { Component } from \"../../../_\"\n\nimport themeCSS from \"./index.css\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mermaid diagram\n */\nexport interface Mermaid {}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Mermaid instance observable\n */\nlet mermaid$: Observable\n\n/**\n * Global sequence number for diagrams\n */\nlet sequence = 0\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch Mermaid script\n *\n * @returns Mermaid scripts observable\n */\nfunction fetchScripts(): Observable {\n return typeof mermaid === \"undefined\" || mermaid instanceof Element\n ? watchScript(\"https://unpkg.com/mermaid@9.0.1/dist/mermaid.min.js\")\n : of(undefined)\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount Mermaid diagram\n *\n * @param el - Code block element\n *\n * @returns Mermaid diagram component observable\n */\nexport function mountMermaid(\n el: HTMLElement\n): Observable> {\n el.classList.remove(\"mermaid\") // Hack: mitigate https://bit.ly/3CiN6Du\n mermaid$ ||= fetchScripts()\n .pipe(\n tap(() => mermaid.initialize({\n startOnLoad: false,\n themeCSS\n })),\n map(() => undefined),\n shareReplay(1)\n )\n\n /* Render diagram */\n mermaid$.subscribe(() => {\n el.classList.add(\"mermaid\") // Hack: mitigate https://bit.ly/3CiN6Du\n const id = `__mermaid_${sequence++}`\n const host = h(\"div\", { class: \"mermaid\" })\n mermaid.mermaidAPI.render(id, el.textContent, (svg: string) => {\n\n /* Create a shadow root and inject diagram */\n const shadow = host.attachShadow({ mode: \"closed\" })\n shadow.innerHTML = svg\n\n /* Replace code block with diagram */\n el.replaceWith(host)\n })\n })\n\n /* Create and return component */\n return mermaid$\n .pipe(\n map(() => ({ ref: el }))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n defer,\n filter,\n finalize,\n map,\n merge,\n tap\n} from \"rxjs\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Details\n */\nexport interface Details {\n action: \"open\" | \"close\" /* Details state */\n reveal?: boolean /* Details is revealed */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Media print observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Media print observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch details\n *\n * @param el - Details element\n * @param options - Options\n *\n * @returns Details observable\n */\nexport function watchDetails(\n el: HTMLDetailsElement, { target$, print$ }: WatchOptions\n): Observable
    {\n let open = true\n return merge(\n\n /* Open and focus details on location target */\n target$\n .pipe(\n map(target => target.closest(\"details:not([open])\")!),\n filter(details => el === details),\n map(() => ({\n action: \"open\", reveal: true\n }) as Details)\n ),\n\n /* Open details on print and close afterwards */\n print$\n .pipe(\n filter(active => active || !open),\n tap(() => open = el.open),\n map(active => ({\n action: active ? \"open\" : \"close\"\n }) as Details)\n )\n )\n}\n\n/**\n * Mount details\n *\n * This function ensures that `details` tags are opened on anchor jumps and\n * prior to printing, so the whole content of the page is visible.\n *\n * @param el - Details element\n * @param options - Options\n *\n * @returns Details component observable\n */\nexport function mountDetails(\n el: HTMLDetailsElement, options: MountOptions\n): Observable> {\n return defer(() => {\n const push$ = new Subject
    ()\n push$.subscribe(({ action, reveal }) => {\n if (action === \"open\")\n el.setAttribute(\"open\", \"\")\n else\n el.removeAttribute(\"open\")\n if (reveal)\n el.scrollIntoView()\n })\n\n /* Create and return component */\n return watchDetails(el, options)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, of } from \"rxjs\"\n\nimport { renderTable } from \"~/templates\"\nimport { h } from \"~/utilities\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Data table\n */\nexport interface DataTable {}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Sentinel for replacement\n */\nconst sentinel = h(\"table\")\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount data table\n *\n * This function wraps a data table in another scrollable container, so it can\n * be smoothly scrolled on smaller screen sizes and won't break the layout.\n *\n * @param el - Data table element\n *\n * @returns Data table component observable\n */\nexport function mountDataTable(\n el: HTMLElement\n): Observable> {\n el.replaceWith(sentinel)\n sentinel.replaceWith(renderTable(el))\n\n /* Create and return component */\n return of({ ref: el })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n asyncScheduler,\n auditTime,\n combineLatest,\n defer,\n finalize,\n fromEvent,\n map,\n merge,\n skip,\n startWith,\n subscribeOn,\n takeLast,\n takeUntil,\n tap\n} from \"rxjs\"\n\nimport { feature } from \"~/_\"\nimport {\n getElement,\n getElementContentOffset,\n getElementContentSize,\n getElementOffset,\n getElementSize,\n getElements,\n watchElementContentOffset,\n watchElementSize\n} from \"~/browser\"\nimport { renderTabbedControl } from \"~/templates\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Content tabs\n */\nexport interface ContentTabs {\n active: HTMLLabelElement /* Active tab label */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch content tabs\n *\n * @param el - Content tabs element\n *\n * @returns Content tabs observable\n */\nexport function watchContentTabs(\n el: HTMLElement\n): Observable {\n const inputs = getElements(\":scope > input\", el)\n const initial = inputs.find(input => input.checked) || inputs[0]\n return merge(...inputs.map(input => fromEvent(input, \"change\")\n .pipe(\n map(() => getElement(`label[for=\"${input.id}\"]`))\n )\n ))\n .pipe(\n startWith(getElement(`label[for=\"${initial.id}\"]`)),\n map(active => ({ active }))\n )\n}\n\n/**\n * Mount content tabs\n *\n * This function scrolls the active tab into view. While this functionality is\n * provided by browsers as part of `scrollInfoView`, browsers will always also\n * scroll the vertical axis, which we do not want. Thus, we decided to provide\n * this functionality ourselves.\n *\n * @param el - Content tabs element\n *\n * @returns Content tabs component observable\n */\nexport function mountContentTabs(\n el: HTMLElement\n): Observable> {\n\n /* Render content tab previous button for pagination */\n const prev = renderTabbedControl(\"prev\")\n el.append(prev)\n\n /* Render content tab next button for pagination */\n const next = renderTabbedControl(\"next\")\n el.append(next)\n\n /* Mount component on subscription */\n const container = getElement(\".tabbed-labels\", el)\n return defer(() => {\n const push$ = new Subject()\n const done$ = push$.pipe(takeLast(1))\n combineLatest([push$, watchElementSize(el)])\n .pipe(\n auditTime(1, animationFrameScheduler),\n takeUntil(done$)\n )\n .subscribe({\n\n /* Handle emission */\n next([{ active }, size]) {\n const offset = getElementOffset(active)\n const { width } = getElementSize(active)\n\n /* Set tab indicator offset and width */\n el.style.setProperty(\"--md-indicator-x\", `${offset.x}px`)\n el.style.setProperty(\"--md-indicator-width\", `${width}px`)\n\n /* Scroll container to active content tab */\n const content = getElementContentOffset(container)\n if (\n offset.x < content.x ||\n offset.x + width > content.x + size.width\n )\n container.scrollTo({\n left: Math.max(0, offset.x - 16),\n behavior: \"smooth\"\n })\n },\n\n /* Handle complete */\n complete() {\n el.style.removeProperty(\"--md-indicator-x\")\n el.style.removeProperty(\"--md-indicator-width\")\n }\n })\n\n /* Hide content tab buttons on borders */\n combineLatest([\n watchElementContentOffset(container),\n watchElementSize(container)\n ])\n .pipe(\n takeUntil(done$)\n )\n .subscribe(([offset, size]) => {\n const content = getElementContentSize(container)\n prev.hidden = offset.x < 16\n next.hidden = offset.x > content.width - size.width - 16\n })\n\n /* Paginate content tab container on click */\n merge(\n fromEvent(prev, \"click\").pipe(map(() => -1)),\n fromEvent(next, \"click\").pipe(map(() => +1))\n )\n .pipe(\n takeUntil(done$)\n )\n .subscribe(direction => {\n const { width } = getElementSize(container)\n container.scrollBy({\n left: width * direction,\n behavior: \"smooth\"\n })\n })\n\n /* Set up linking of content tabs, if enabled */\n if (feature(\"content.tabs.link\"))\n push$.pipe(skip(1))\n .subscribe(({ active }) => {\n const tab = active.innerText.trim()\n for (const set of getElements(\"[data-tabs]\"))\n for (const input of getElements(\n \":scope > input\", set\n )) {\n const label = getElement(`label[for=\"${input.id}\"]`)\n if (label.innerText.trim() === tab) {\n input.click()\n break\n }\n }\n\n /* Persist active tabs in local storage */\n const tabs = __md_get(\"__tabs\") || []\n __md_set(\"__tabs\", [...new Set([tab, ...tabs])])\n })\n\n /* Create and return component */\n return watchContentTabs(el)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n .pipe(\n subscribeOn(asyncScheduler)\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, merge } from \"rxjs\"\n\nimport { getElements } from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Annotation } from \"../annotation\"\nimport {\n CodeBlock,\n Mermaid,\n mountCodeBlock,\n mountMermaid\n} from \"../code\"\nimport {\n Details,\n mountDetails\n} from \"../details\"\nimport {\n DataTable,\n mountDataTable\n} from \"../table\"\nimport {\n ContentTabs,\n mountContentTabs\n} from \"../tabs\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Content\n */\nexport type Content =\n | Annotation\n | ContentTabs\n | CodeBlock\n | Mermaid\n | DataTable\n | Details\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Media print observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount content\n *\n * This function mounts all components that are found in the content of the\n * actual article, including code blocks, data tables and details.\n *\n * @param el - Content element\n * @param options - Options\n *\n * @returns Content component observable\n */\nexport function mountContent(\n el: HTMLElement, { target$, print$ }: MountOptions\n): Observable> {\n return merge(\n\n /* Code blocks */\n ...getElements(\"pre:not(.mermaid) > code\", el)\n .map(child => mountCodeBlock(child, { print$ })),\n\n /* Mermaid diagrams */\n ...getElements(\"pre.mermaid\", el)\n .map(child => mountMermaid(child)),\n\n /* Data tables */\n ...getElements(\"table:not([class])\", el)\n .map(child => mountDataTable(child)),\n\n /* Details */\n ...getElements(\"details\", el)\n .map(child => mountDetails(child, { target$, print$ })),\n\n /* Content tabs */\n ...getElements(\"[data-tabs]\", el)\n .map(child => mountContentTabs(child))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n defer,\n delay,\n finalize,\n map,\n merge,\n of,\n switchMap,\n tap\n} from \"rxjs\"\n\nimport { getElement } from \"~/browser\"\n\nimport { Component } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Dialog\n */\nexport interface Dialog {\n message: string /* Dialog message */\n active: boolean /* Dialog is active */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n alert$: Subject /* Alert subject */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n alert$: Subject /* Alert subject */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch dialog\n *\n * @param _el - Dialog element\n * @param options - Options\n *\n * @returns Dialog observable\n */\nexport function watchDialog(\n _el: HTMLElement, { alert$ }: WatchOptions\n): Observable {\n return alert$\n .pipe(\n switchMap(message => merge(\n of(true),\n of(false).pipe(delay(2000))\n )\n .pipe(\n map(active => ({ message, active }))\n )\n )\n )\n}\n\n/**\n * Mount dialog\n *\n * This function reveals the dialog in the right corner when a new alert is\n * emitted through the subject that is passed as part of the options.\n *\n * @param el - Dialog element\n * @param options - Options\n *\n * @returns Dialog component observable\n */\nexport function mountDialog(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const inner = getElement(\".md-typeset\", el)\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe(({ message, active }) => {\n el.classList.toggle(\"md-dialog--active\", active)\n inner.textContent = message\n })\n\n /* Create and return component */\n return watchDialog(el, options)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n bufferCount,\n combineLatest,\n combineLatestWith,\n defer,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n filter,\n map,\n of,\n shareReplay,\n startWith,\n switchMap,\n takeLast,\n takeUntil\n} from \"rxjs\"\n\nimport { feature } from \"~/_\"\nimport {\n Viewport,\n watchElementSize,\n watchToggle\n} from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Main } from \"../../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Header\n */\nexport interface Header {\n height: number /* Header visible height */\n hidden: boolean /* Header is hidden */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Compute whether the header is hidden\n *\n * If the user scrolls past a certain threshold, the header can be hidden when\n * scrolling down, and shown when scrolling up.\n *\n * @param options - Options\n *\n * @returns Toggle observable\n */\nfunction isHidden({ viewport$ }: WatchOptions): Observable {\n if (!feature(\"header.autohide\"))\n return of(false)\n\n /* Compute direction and turning point */\n const direction$ = viewport$\n .pipe(\n map(({ offset: { y } }) => y),\n bufferCount(2, 1),\n map(([a, b]) => [a < b, b] as const),\n distinctUntilKeyChanged(0)\n )\n\n /* Compute whether header should be hidden */\n const hidden$ = combineLatest([viewport$, direction$])\n .pipe(\n filter(([{ offset }, [, y]]) => Math.abs(y - offset.y) > 100),\n map(([, [direction]]) => direction),\n distinctUntilChanged()\n )\n\n /* Compute threshold for hiding */\n const search$ = watchToggle(\"search\")\n return combineLatest([viewport$, search$])\n .pipe(\n map(([{ offset }, search]) => offset.y > 400 && !search),\n distinctUntilChanged(),\n switchMap(active => active ? hidden$ : of(false)),\n startWith(false)\n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch header\n *\n * @param el - Header element\n * @param options - Options\n *\n * @returns Header observable\n */\nexport function watchHeader(\n el: HTMLElement, options: WatchOptions\n): Observable
    {\n return defer(() => combineLatest([\n watchElementSize(el),\n isHidden(options)\n ]))\n .pipe(\n map(([{ height }, hidden]) => ({\n height,\n hidden\n })),\n distinctUntilChanged((a, b) => (\n a.height === b.height &&\n a.hidden === b.hidden\n )),\n shareReplay(1)\n )\n}\n\n/**\n * Mount header\n *\n * This function manages the different states of the header, i.e. whether it's\n * hidden or rendered with a shadow. This depends heavily on the main area.\n *\n * @param el - Header element\n * @param options - Options\n *\n * @returns Header component observable\n */\nexport function mountHeader(\n el: HTMLElement, { header$, main$ }: MountOptions\n): Observable> {\n return defer(() => {\n const push$ = new Subject
    ()\n const done$ = push$.pipe(takeLast(1))\n push$\n .pipe(\n distinctUntilKeyChanged(\"active\"),\n combineLatestWith(header$)\n )\n .subscribe(([{ active }, { hidden }]) => {\n el.classList.toggle(\"md-header--shadow\", active && !hidden)\n el.hidden = hidden\n })\n\n /* Link to main area */\n main$.subscribe(push$)\n\n /* Create and return component */\n return header$\n .pipe(\n takeUntil(done$),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n Subject,\n defer,\n distinctUntilKeyChanged,\n finalize,\n map,\n tap\n} from \"rxjs\"\n\nimport {\n Viewport,\n getElementSize,\n getOptionalElement,\n watchViewportAt\n} from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Header } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Header\n */\nexport interface HeaderTitle {\n active: boolean /* Header title is active */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch header title\n *\n * @param el - Heading element\n * @param options - Options\n *\n * @returns Header title observable\n */\nexport function watchHeaderTitle(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable {\n return watchViewportAt(el, { viewport$, header$ })\n .pipe(\n map(({ offset: { y } }) => {\n const { height } = getElementSize(el)\n return {\n active: y >= height\n }\n }),\n distinctUntilKeyChanged(\"active\")\n )\n}\n\n/**\n * Mount header title\n *\n * This function swaps the header title from the site title to the title of the\n * current page when the user scrolls past the first headline.\n *\n * @param el - Header title element\n * @param options - Options\n *\n * @returns Header title component observable\n */\nexport function mountHeaderTitle(\n el: HTMLElement, options: MountOptions\n): Observable> {\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe(({ active }) => {\n el.classList.toggle(\"md-header__title--active\", active)\n })\n\n /* Obtain headline, if any */\n const heading = getOptionalElement(\"article h1\")\n if (typeof heading === \"undefined\")\n return EMPTY\n\n /* Create and return component */\n return watchHeaderTitle(heading, options)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n combineLatest,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n map,\n switchMap\n} from \"rxjs\"\n\nimport {\n Viewport,\n watchElementSize\n} from \"~/browser\"\n\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Main area\n */\nexport interface Main {\n offset: number /* Main area top offset */\n height: number /* Main area visible height */\n active: boolean /* Main area is active */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch main area\n *\n * This function returns an observable that computes the visual parameters of\n * the main area which depends on the viewport vertical offset and height, as\n * well as the height of the header element, if the header is fixed.\n *\n * @param el - Main area element\n * @param options - Options\n *\n * @returns Main area observable\n */\nexport function watchMain(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable
    {\n\n /* Compute necessary adjustment for header */\n const adjust$ = header$\n .pipe(\n map(({ height }) => height),\n distinctUntilChanged()\n )\n\n /* Compute the main area's top and bottom borders */\n const border$ = adjust$\n .pipe(\n switchMap(() => watchElementSize(el)\n .pipe(\n map(({ height }) => ({\n top: el.offsetTop,\n bottom: el.offsetTop + height\n })),\n distinctUntilKeyChanged(\"bottom\")\n )\n )\n )\n\n /* Compute the main area's offset, visible height and if we scrolled past */\n return combineLatest([adjust$, border$, viewport$])\n .pipe(\n map(([header, { top, bottom }, { offset: { y }, size: { height } }]) => {\n height = Math.max(0, height\n - Math.max(0, top - y, header)\n - Math.max(0, height + y - bottom)\n )\n return {\n offset: top - header,\n height,\n active: top - header <= y\n }\n }),\n distinctUntilChanged((a, b) => (\n a.offset === b.offset &&\n a.height === b.height &&\n a.active === b.active\n ))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n asyncScheduler,\n defer,\n finalize,\n fromEvent,\n map,\n mergeMap,\n observeOn,\n of,\n shareReplay,\n startWith,\n tap\n} from \"rxjs\"\n\nimport { getElements } from \"~/browser\"\n\nimport { Component } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Palette colors\n */\nexport interface PaletteColor {\n scheme?: string /* Color scheme */\n primary?: string /* Primary color */\n accent?: string /* Accent color */\n}\n\n/**\n * Palette\n */\nexport interface Palette {\n index: number /* Palette index */\n color: PaletteColor /* Palette colors */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch color palette\n *\n * @param inputs - Color palette element\n *\n * @returns Color palette observable\n */\nexport function watchPalette(\n inputs: HTMLInputElement[]\n): Observable {\n const current = __md_get(\"__palette\") || {\n index: inputs.findIndex(input => matchMedia(\n input.getAttribute(\"data-md-color-media\")!\n ).matches)\n }\n\n /* Emit changes in color palette */\n return of(...inputs)\n .pipe(\n mergeMap(input => fromEvent(input, \"change\")\n .pipe(\n map(() => input)\n )\n ),\n startWith(inputs[Math.max(0, current.index)]),\n map(input => ({\n index: inputs.indexOf(input),\n color: {\n scheme: input.getAttribute(\"data-md-color-scheme\"),\n primary: input.getAttribute(\"data-md-color-primary\"),\n accent: input.getAttribute(\"data-md-color-accent\")\n }\n } as Palette)),\n shareReplay(1)\n )\n}\n\n/**\n * Mount color palette\n *\n * @param el - Color palette element\n *\n * @returns Color palette component observable\n */\nexport function mountPalette(\n el: HTMLElement\n): Observable> {\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe(palette => {\n document.body.setAttribute(\"data-md-color-switching\", \"\")\n\n /* Set color palette */\n for (const [key, value] of Object.entries(palette.color))\n document.body.setAttribute(`data-md-color-${key}`, value)\n\n /* Toggle visibility */\n for (let index = 0; index < inputs.length; index++) {\n const label = inputs[index].nextElementSibling\n if (label instanceof HTMLElement)\n label.hidden = palette.index !== index\n }\n\n /* Persist preference in local storage */\n __md_set(\"__palette\", palette)\n })\n\n /* Revert transition durations after color switch */\n push$.pipe(observeOn(asyncScheduler))\n .subscribe(() => {\n document.body.removeAttribute(\"data-md-color-switching\")\n })\n\n /* Create and return component */\n const inputs = getElements(\"input\", el)\n return watchPalette(inputs)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ClipboardJS from \"clipboard\"\nimport {\n Observable,\n Subject,\n map,\n tap\n} from \"rxjs\"\n\nimport { translation } from \"~/_\"\nimport { getElement } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Setup options\n */\ninterface SetupOptions {\n alert$: Subject /* Alert subject */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Extract text to copy\n *\n * @param el - HTML element\n *\n * @returns Extracted text\n */\nfunction extract(el: HTMLElement): string {\n el.setAttribute(\"data-md-copying\", \"\")\n const text = el.innerText\n el.removeAttribute(\"data-md-copying\")\n return text\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up Clipboard.js integration\n *\n * @param options - Options\n */\nexport function setupClipboardJS(\n { alert$ }: SetupOptions\n): void {\n if (ClipboardJS.isSupported()) {\n new Observable(subscriber => {\n new ClipboardJS(\"[data-clipboard-target], [data-clipboard-text]\", {\n text: el => (\n el.getAttribute(\"data-clipboard-text\")! ||\n extract(getElement(\n el.getAttribute(\"data-clipboard-target\")!\n ))\n )\n })\n .on(\"success\", ev => subscriber.next(ev))\n })\n .pipe(\n tap(ev => {\n const trigger = ev.trigger as HTMLElement\n trigger.focus()\n }),\n map(() => translation(\"clipboard.copied\"))\n )\n .subscribe(alert$)\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n catchError,\n defaultIfEmpty,\n map,\n of,\n tap\n} from \"rxjs\"\n\nimport { configuration } from \"~/_\"\nimport { getElements, requestXML } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Sitemap, i.e. a list of URLs\n */\nexport type Sitemap = string[]\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Preprocess a list of URLs\n *\n * This function replaces the `site_url` in the sitemap with the actual base\n * URL, to allow instant loading to work in occasions like Netlify previews.\n *\n * @param urls - URLs\n *\n * @returns URL path parts\n */\nfunction preprocess(urls: Sitemap): Sitemap {\n if (urls.length < 2)\n return [\"\"]\n\n /* Take the first two URLs and remove everything after the last slash */\n const [root, next] = [...urls]\n .sort((a, b) => a.length - b.length)\n .map(url => url.replace(/[^/]+$/, \"\"))\n\n /* Compute common prefix */\n let index = 0\n if (root === next)\n index = root.length\n else\n while (root.charCodeAt(index) === next.charCodeAt(index))\n index++\n\n /* Remove common prefix and return in original order */\n return urls.map(url => url.replace(root.slice(0, index), \"\"))\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch the sitemap for the given base URL\n *\n * @param base - Base URL\n *\n * @returns Sitemap observable\n */\nexport function fetchSitemap(base?: URL): Observable {\n const cached = __md_get(\"__sitemap\", sessionStorage, base)\n if (cached) {\n return of(cached)\n } else {\n const config = configuration()\n return requestXML(new URL(\"sitemap.xml\", base || config.base))\n .pipe(\n map(sitemap => preprocess(getElements(\"loc\", sitemap)\n .map(node => node.textContent!)\n )),\n catchError(() => EMPTY), // @todo refactor instant loading\n defaultIfEmpty([]),\n tap(sitemap => __md_set(\"__sitemap\", sitemap, sessionStorage, base))\n )\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n bufferCount,\n catchError,\n concatMap,\n debounceTime,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n filter,\n fromEvent,\n map,\n merge,\n of,\n sample,\n share,\n skip,\n skipUntil,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"~/_\"\nimport {\n Viewport,\n ViewportOffset,\n getElements,\n getOptionalElement,\n request,\n setLocation,\n setLocationHash\n} from \"~/browser\"\nimport { getComponentElement } from \"~/components\"\nimport { h } from \"~/utilities\"\n\nimport { fetchSitemap } from \"../sitemap\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * History state\n */\nexport interface HistoryState {\n url: URL /* State URL */\n offset?: ViewportOffset /* State viewport offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Setup options\n */\ninterface SetupOptions {\n document$: Subject /* Document subject */\n location$: Subject /* Location subject */\n viewport$: Observable /* Viewport observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up instant loading\n *\n * When fetching, theoretically, we could use `responseType: \"document\"`, but\n * since all MkDocs links are relative, we need to make sure that the current\n * location matches the document we just loaded. Otherwise any relative links\n * in the document could use the old location.\n *\n * This is the reason why we need to synchronize history events and the process\n * of fetching the document for navigation changes (except `popstate` events):\n *\n * 1. Fetch document via `XMLHTTPRequest`\n * 2. Set new location via `history.pushState`\n * 3. Parse and emit fetched document\n *\n * For `popstate` events, we must not use `history.pushState`, or the forward\n * history will be irreversibly overwritten. In case the request fails, the\n * location change is dispatched regularly.\n *\n * @param options - Options\n */\nexport function setupInstantLoading(\n { document$, location$, viewport$ }: SetupOptions\n): void {\n const config = configuration()\n if (location.protocol === \"file:\")\n return\n\n /* Disable automatic scroll restoration */\n if (\"scrollRestoration\" in history) {\n history.scrollRestoration = \"manual\"\n\n /* Hack: ensure that reloads restore viewport offset */\n fromEvent(window, \"beforeunload\")\n .subscribe(() => {\n history.scrollRestoration = \"auto\"\n })\n }\n\n /* Hack: ensure absolute favicon link to omit 404s when switching */\n const favicon = getOptionalElement(\"link[rel=icon]\")\n if (typeof favicon !== \"undefined\")\n favicon.href = favicon.href\n\n /* Intercept internal navigation */\n const push$ = fetchSitemap()\n .pipe(\n map(paths => paths.map(path => `${new URL(path, config.base)}`)),\n switchMap(urls => fromEvent(document.body, \"click\")\n .pipe(\n filter(ev => !ev.metaKey && !ev.ctrlKey),\n switchMap(ev => {\n if (ev.target instanceof Element) {\n const el = ev.target.closest(\"a\")\n if (el && !el.target) {\n const url = new URL(el.href)\n\n /* Canonicalize URL */\n url.search = \"\"\n url.hash = \"\"\n\n /* Check if URL should be intercepted */\n if (\n url.pathname !== location.pathname &&\n urls.includes(url.toString())\n ) {\n ev.preventDefault()\n return of({\n url: new URL(el.href)\n })\n }\n }\n }\n return NEVER\n })\n )\n ),\n share()\n )\n\n /* Intercept history back and forward */\n const pop$ = fromEvent(window, \"popstate\")\n .pipe(\n filter(ev => ev.state !== null),\n map(ev => ({\n url: new URL(location.href),\n offset: ev.state\n })),\n share()\n )\n\n /* Emit location change */\n merge(push$, pop$)\n .pipe(\n distinctUntilChanged((a, b) => a.url.href === b.url.href),\n map(({ url }) => url)\n )\n .subscribe(location$)\n\n /* Fetch document via `XMLHTTPRequest` */\n const response$ = location$\n .pipe(\n distinctUntilKeyChanged(\"pathname\"),\n switchMap(url => request(url.href)\n .pipe(\n catchError(() => {\n setLocation(url)\n return NEVER\n })\n )\n ),\n share()\n )\n\n /* Set new location via `history.pushState` */\n push$\n .pipe(\n sample(response$)\n )\n .subscribe(({ url }) => {\n history.pushState({}, \"\", `${url}`)\n })\n\n /* Parse and emit fetched document */\n const dom = new DOMParser()\n response$\n .pipe(\n switchMap(res => res.text()),\n map(res => dom.parseFromString(res, \"text/html\"))\n )\n .subscribe(document$)\n\n /* Replace meta tags and components */\n document$\n .pipe(\n skip(1)\n )\n .subscribe(replacement => {\n for (const selector of [\n\n /* Meta tags */\n \"title\",\n \"link[rel=canonical]\",\n \"meta[name=author]\",\n \"meta[name=description]\",\n\n /* Components */\n \"[data-md-component=announce]\",\n \"[data-md-component=container]\",\n \"[data-md-component=header-topic]\",\n \"[data-md-component=outdated]\",\n \"[data-md-component=logo]\",\n \"[data-md-component=skip]\",\n ...feature(\"navigation.tabs.sticky\")\n ? [\"[data-md-component=tabs]\"]\n : []\n ]) {\n const source = getOptionalElement(selector)\n const target = getOptionalElement(selector, replacement)\n if (\n typeof source !== \"undefined\" &&\n typeof target !== \"undefined\"\n ) {\n source.replaceWith(target)\n }\n }\n })\n\n /* Re-evaluate scripts */\n document$\n .pipe(\n skip(1),\n map(() => getComponentElement(\"container\")),\n switchMap(el => getElements(\"script\", el)),\n concatMap(el => {\n const script = h(\"script\")\n if (el.src) {\n for (const name of el.getAttributeNames())\n script.setAttribute(name, el.getAttribute(name)!)\n el.replaceWith(script)\n\n /* Complete when script is loaded */\n return new Observable(observer => {\n script.onload = () => observer.complete()\n })\n\n /* Complete immediately */\n } else {\n script.textContent = el.textContent\n el.replaceWith(script)\n return EMPTY\n }\n })\n )\n .subscribe()\n\n /* Emit history state change */\n merge(push$, pop$)\n .pipe(\n sample(document$)\n )\n .subscribe(({ url, offset }) => {\n if (url.hash && !offset) {\n setLocationHash(url.hash)\n } else {\n window.scrollTo(0, offset?.y || 0)\n }\n })\n\n /* Debounce update of viewport offset */\n viewport$\n .pipe(\n skipUntil(push$),\n debounceTime(250),\n distinctUntilKeyChanged(\"offset\")\n )\n .subscribe(({ offset }) => {\n history.replaceState(offset, \"\")\n })\n\n /* Set viewport offset from history */\n merge(push$, pop$)\n .pipe(\n bufferCount(2, 1),\n filter(([a, b]) => a.url.pathname === b.url.pathname),\n map(([, state]) => state)\n )\n .subscribe(({ offset }) => {\n window.scrollTo(0, offset?.y || 0)\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexDocument } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search document\n */\nexport interface SearchDocument extends SearchIndexDocument {\n parent?: SearchIndexDocument /* Parent article */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search document mapping\n */\nexport type SearchDocumentMap = Map\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search document mapping\n *\n * @param docs - Search index documents\n *\n * @returns Search document map\n */\nexport function setupSearchDocumentMap(\n docs: SearchIndexDocument[]\n): SearchDocumentMap {\n const documents = new Map()\n const parents = new Set()\n for (const doc of docs) {\n const [path, hash] = doc.location.split(\"#\")\n\n /* Extract location, title and tags */\n const location = doc.location\n const title = doc.title\n const tags = doc.tags\n\n /* Escape and cleanup text */\n const text = escapeHTML(doc.text)\n .replace(/\\s+(?=[,.:;!?])/g, \"\")\n .replace(/\\s+/g, \" \")\n\n /* Handle section */\n if (hash) {\n const parent = documents.get(path)!\n\n /* Ignore first section, override article */\n if (!parents.has(parent)) {\n parent.title = doc.title\n parent.text = text\n\n /* Remember that we processed the article */\n parents.add(parent)\n\n /* Add subsequent section */\n } else {\n documents.set(location, {\n location,\n title,\n text,\n parent\n })\n }\n\n /* Add article */\n } else {\n documents.set(location, {\n location,\n title,\n text,\n ...tags && { tags }\n })\n }\n }\n return documents\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexConfig } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search highlight function\n *\n * @param value - Value\n *\n * @returns Highlighted value\n */\nexport type SearchHighlightFn = (value: string) => string\n\n/**\n * Search highlight factory function\n *\n * @param query - Query value\n *\n * @returns Search highlight function\n */\nexport type SearchHighlightFactoryFn = (query: string) => SearchHighlightFn\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search highlighter\n *\n * @param config - Search index configuration\n * @param escape - Whether to escape HTML\n *\n * @returns Search highlight factory function\n */\nexport function setupSearchHighlighter(\n config: SearchIndexConfig, escape: boolean\n): SearchHighlightFactoryFn {\n const separator = new RegExp(config.separator, \"img\")\n const highlight = (_: unknown, data: string, term: string) => {\n return `${data}${term}`\n }\n\n /* Return factory function */\n return (query: string) => {\n query = query\n .replace(/[\\s*+\\-:~^]+/g, \" \")\n .trim()\n\n /* Create search term match expression */\n const match = new RegExp(`(^|${config.separator})(${\n query\n .replace(/[|\\\\{}()[\\]^$+*?.-]/g, \"\\\\$&\")\n .replace(separator, \"|\")\n })`, \"img\")\n\n /* Highlight string value */\n return value => (\n escape\n ? escapeHTML(value)\n : value\n )\n .replace(match, highlight)\n .replace(/<\\/mark>(\\s+)]*>/img, \"$1\")\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search transformation function\n *\n * @param value - Query value\n *\n * @returns Transformed query value\n */\nexport type SearchTransformFn = (value: string) => string\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Default transformation function\n *\n * 1. Search for terms in quotation marks and prepend a `+` modifier to denote\n * that the resulting document must contain all terms, converting the query\n * to an `AND` query (as opposed to the default `OR` behavior). While users\n * may expect terms enclosed in quotation marks to map to span queries, i.e.\n * for which order is important, Lunr.js doesn't support them, so the best\n * we can do is to convert the terms to an `AND` query.\n *\n * 2. Replace control characters which are not located at the beginning of the\n * query or preceded by white space, or are not followed by a non-whitespace\n * character or are at the end of the query string. Furthermore, filter\n * unmatched quotation marks.\n *\n * 3. Trim excess whitespace from left and right.\n *\n * @param query - Query value\n *\n * @returns Transformed query value\n */\nexport function defaultTransform(query: string): string {\n return query\n .split(/\"([^\"]+)\"/g) /* => 1 */\n .map((terms, index) => index & 1\n ? terms.replace(/^\\b|^(?![^\\x00-\\x7F]|$)|\\s+/g, \" +\")\n : terms\n )\n .join(\"\")\n .replace(/\"|(?:^|\\s+)[*+\\-:^~]+(?=\\s+|$)/g, \"\") /* => 2 */\n .trim() /* => 3 */\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SearchIndex, SearchResult } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search message type\n */\nexport const enum SearchMessageType {\n SETUP, /* Search index setup */\n READY, /* Search index ready */\n QUERY, /* Search query */\n RESULT /* Search results */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Message containing the data necessary to setup the search index\n */\nexport interface SearchSetupMessage {\n type: SearchMessageType.SETUP /* Message type */\n data: SearchIndex /* Message data */\n}\n\n/**\n * Message indicating the search index is ready\n */\nexport interface SearchReadyMessage {\n type: SearchMessageType.READY /* Message type */\n}\n\n/**\n * Message containing a search query\n */\nexport interface SearchQueryMessage {\n type: SearchMessageType.QUERY /* Message type */\n data: string /* Message data */\n}\n\n/**\n * Message containing results for a search query\n */\nexport interface SearchResultMessage {\n type: SearchMessageType.RESULT /* Message type */\n data: SearchResult /* Message data */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Message exchanged with the search worker\n */\nexport type SearchMessage =\n | SearchSetupMessage\n | SearchReadyMessage\n | SearchQueryMessage\n | SearchResultMessage\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Type guard for search setup messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchSetupMessage(\n message: SearchMessage\n): message is SearchSetupMessage {\n return message.type === SearchMessageType.SETUP\n}\n\n/**\n * Type guard for search ready messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchReadyMessage(\n message: SearchMessage\n): message is SearchReadyMessage {\n return message.type === SearchMessageType.READY\n}\n\n/**\n * Type guard for search query messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchQueryMessage(\n message: SearchMessage\n): message is SearchQueryMessage {\n return message.type === SearchMessageType.QUERY\n}\n\n/**\n * Type guard for search result messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchResultMessage(\n message: SearchMessage\n): message is SearchResultMessage {\n return message.type === SearchMessageType.RESULT\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n ObservableInput,\n Subject,\n from,\n map,\n share\n} from \"rxjs\"\n\nimport { configuration, feature, translation } from \"~/_\"\nimport { WorkerHandler, watchWorker } from \"~/browser\"\n\nimport { SearchIndex } from \"../../_\"\nimport {\n SearchOptions,\n SearchPipeline\n} from \"../../options\"\nimport {\n SearchMessage,\n SearchMessageType,\n SearchSetupMessage,\n isSearchResultMessage\n} from \"../message\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search worker\n */\nexport type SearchWorker = WorkerHandler\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up search index\n *\n * @param data - Search index\n *\n * @returns Search index\n */\nfunction setupSearchIndex({ config, docs }: SearchIndex): SearchIndex {\n\n /* Override default language with value from translation */\n if (config.lang.length === 1 && config.lang[0] === \"en\")\n config.lang = [\n translation(\"search.config.lang\")\n ]\n\n /* Override default separator with value from translation */\n if (config.separator === \"[\\\\s\\\\-]+\")\n config.separator = translation(\"search.config.separator\")\n\n /* Set pipeline from translation */\n const pipeline = translation(\"search.config.pipeline\")\n .split(/\\s*,\\s*/)\n .filter(Boolean) as SearchPipeline\n\n /* Determine search options */\n const options: SearchOptions = {\n pipeline,\n suggestions: feature(\"search.suggest\")\n }\n\n /* Return search index after defaulting */\n return { config, docs, options }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up search worker\n *\n * This function creates a web worker to set up and query the search index,\n * which is done using Lunr.js. The index must be passed as an observable to\n * enable hacks like _localsearch_ via search index embedding as JSON.\n *\n * @param url - Worker URL\n * @param index - Search index observable input\n *\n * @returns Search worker\n */\nexport function setupSearchWorker(\n url: string, index: ObservableInput\n): SearchWorker {\n const config = configuration()\n const worker = new Worker(url)\n\n /* Create communication channels and resolve relative links */\n const tx$ = new Subject()\n const rx$ = watchWorker(worker, { tx$ })\n .pipe(\n map(message => {\n if (isSearchResultMessage(message)) {\n for (const result of message.data.items)\n for (const document of result)\n document.location = `${new URL(document.location, config.base)}`\n }\n return message\n }),\n share()\n )\n\n /* Set up search index */\n from(index)\n .pipe(\n map(data => ({\n type: SearchMessageType.SETUP,\n data: setupSearchIndex(data)\n } as SearchSetupMessage))\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Return search worker */\n return { tx$, rx$ }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Subject,\n catchError,\n combineLatest,\n filter,\n fromEvent,\n map,\n of,\n switchMap,\n withLatestFrom\n} from \"rxjs\"\n\nimport { configuration } from \"~/_\"\nimport {\n getElement,\n getLocation,\n requestJSON,\n setLocation\n} from \"~/browser\"\nimport { getComponentElements } from \"~/components\"\nimport {\n Version,\n renderVersionSelector\n} from \"~/templates\"\n\nimport { fetchSitemap } from \"../sitemap\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Setup options\n */\ninterface SetupOptions {\n document$: Subject /* Document subject */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up version selector\n *\n * @param options - Options\n */\nexport function setupVersionSelector(\n { document$ }: SetupOptions\n): void {\n const config = configuration()\n const versions$ = requestJSON(\n new URL(\"../versions.json\", config.base)\n )\n .pipe(\n catchError(() => EMPTY) // @todo refactor instant loading\n )\n\n /* Determine current version */\n const current$ = versions$\n .pipe(\n map(versions => {\n const [, current] = config.base.match(/([^/]+)\\/?$/)!\n return versions.find(({ version, aliases }) => (\n version === current || aliases.includes(current)\n )) || versions[0]\n })\n )\n\n /* Intercept inter-version navigation */\n versions$\n .pipe(\n map(versions => new Map(versions.map(version => [\n `${new URL(`../${version.version}/`, config.base)}`,\n version\n ]))),\n switchMap(urls => fromEvent(document.body, \"click\")\n .pipe(\n filter(ev => !ev.metaKey && !ev.ctrlKey),\n withLatestFrom(current$),\n switchMap(([ev, current]) => {\n if (ev.target instanceof Element) {\n const el = ev.target.closest(\"a\")\n if (el && !el.target && urls.has(el.href)) {\n const url = el.href\n // This is a temporary hack to detect if a version inside the\n // version selector or on another part of the site was clicked.\n // If we're inside the version selector, we definitely want to\n // find the same page, as we might have different deployments\n // due to aliases. However, if we're outside the version\n // selector, we must abort here, because we might otherwise\n // interfere with instant loading. We need to refactor this\n // at some point together with instant loading.\n //\n // See https://github.com/squidfunk/mkdocs-material/issues/4012\n if (!ev.target.closest(\".md-version\")) {\n const version = urls.get(url)!\n if (version === current)\n return EMPTY\n }\n ev.preventDefault()\n return of(url)\n }\n }\n return EMPTY\n }),\n switchMap(url => {\n const { version } = urls.get(url)!\n return fetchSitemap(new URL(url))\n .pipe(\n map(sitemap => {\n const location = getLocation()\n const path = location.href.replace(config.base, \"\")\n return sitemap.includes(path.split(\"#\")[0])\n ? new URL(`../${version}/${path}`, config.base)\n : new URL(url)\n })\n )\n })\n )\n )\n )\n .subscribe(url => setLocation(url))\n\n /* Render version selector and warning */\n combineLatest([versions$, current$])\n .subscribe(([versions, current]) => {\n const topic = getElement(\".md-header__topic\")\n topic.appendChild(renderVersionSelector(versions, current))\n })\n\n /* Integrate outdated version banner with instant loading */\n document$.pipe(switchMap(() => current$))\n .subscribe(current => {\n\n /* Check if version state was already determined */\n let outdated = __md_get(\"__outdated\", sessionStorage)\n if (outdated === null) {\n const latest = config.version?.default || \"latest\"\n outdated = !current.aliases.includes(latest)\n\n /* Persist version state in session storage */\n __md_set(\"__outdated\", outdated, sessionStorage)\n }\n\n /* Unhide outdated version banner */\n if (outdated)\n for (const warning of getComponentElements(\"outdated\"))\n warning.hidden = false\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n combineLatest,\n delay,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n filter,\n finalize,\n fromEvent,\n map,\n merge,\n share,\n shareReplay,\n startWith,\n take,\n takeLast,\n takeUntil,\n tap\n} from \"rxjs\"\n\nimport { translation } from \"~/_\"\nimport {\n getLocation,\n setToggle,\n watchElementFocus,\n watchToggle\n} from \"~/browser\"\nimport {\n SearchMessageType,\n SearchQueryMessage,\n SearchWorker,\n defaultTransform,\n isSearchReadyMessage\n} from \"~/integrations\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search query\n */\nexport interface SearchQuery {\n value: string /* Query value */\n focus: boolean /* Query focus */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch search query\n *\n * Note that the focus event which triggers re-reading the current query value\n * is delayed by `1ms` so the input's empty state is allowed to propagate.\n *\n * @param el - Search query element\n * @param worker - Search worker\n *\n * @returns Search query observable\n */\nexport function watchSearchQuery(\n el: HTMLInputElement, { rx$ }: SearchWorker\n): Observable {\n const fn = __search?.transform || defaultTransform\n\n /* Immediately show search dialog */\n const { searchParams } = getLocation()\n if (searchParams.has(\"q\"))\n setToggle(\"search\", true)\n\n /* Intercept query parameter (deep link) */\n const param$ = rx$\n .pipe(\n filter(isSearchReadyMessage),\n take(1),\n map(() => searchParams.get(\"q\") || \"\")\n )\n\n /* Remove query parameter when search is closed */\n watchToggle(\"search\")\n .pipe(\n filter(active => !active),\n take(1)\n )\n .subscribe(() => {\n const url = new URL(location.href)\n url.searchParams.delete(\"q\")\n history.replaceState({}, \"\", `${url}`)\n })\n\n /* Set query from parameter */\n param$.subscribe(value => { // TODO: not ideal - find a better way\n if (value) {\n el.value = value\n el.focus()\n }\n })\n\n /* Intercept focus and input events */\n const focus$ = watchElementFocus(el)\n const value$ = merge(\n fromEvent(el, \"keyup\"),\n fromEvent(el, \"focus\").pipe(delay(1)),\n param$\n )\n .pipe(\n map(() => fn(el.value)),\n startWith(\"\"),\n distinctUntilChanged(),\n )\n\n /* Combine into single observable */\n return combineLatest([value$, focus$])\n .pipe(\n map(([value, focus]) => ({ value, focus })),\n shareReplay(1)\n )\n}\n\n/**\n * Mount search query\n *\n * @param el - Search query element\n * @param worker - Search worker\n *\n * @returns Search query component observable\n */\nexport function mountSearchQuery(\n el: HTMLInputElement, { tx$, rx$ }: SearchWorker\n): Observable> {\n const push$ = new Subject()\n const done$ = push$.pipe(takeLast(1))\n\n /* Handle value changes */\n push$\n .pipe(\n distinctUntilKeyChanged(\"value\"),\n map(({ value }): SearchQueryMessage => ({\n type: SearchMessageType.QUERY,\n data: value\n }))\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Handle focus changes */\n push$\n .pipe(\n distinctUntilKeyChanged(\"focus\")\n )\n .subscribe(({ focus }) => {\n if (focus) {\n setToggle(\"search\", focus)\n el.placeholder = \"\"\n } else {\n el.placeholder = translation(\"search.placeholder\")\n }\n })\n\n /* Handle reset */\n fromEvent(el.form!, \"reset\")\n .pipe(\n takeUntil(done$)\n )\n .subscribe(() => el.focus())\n\n /* Create and return component */\n return watchSearchQuery(el, { tx$, rx$ })\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state })),\n share()\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n bufferCount,\n filter,\n finalize,\n map,\n merge,\n of,\n skipUntil,\n switchMap,\n take,\n tap,\n withLatestFrom,\n zipWith\n} from \"rxjs\"\n\nimport { translation } from \"~/_\"\nimport {\n getElement,\n watchElementBoundary\n} from \"~/browser\"\nimport {\n SearchResult,\n SearchWorker,\n isSearchReadyMessage,\n isSearchResultMessage\n} from \"~/integrations\"\nimport { renderSearchResultItem } from \"~/templates\"\nimport { round } from \"~/utilities\"\n\nimport { Component } from \"../../_\"\nimport { SearchQuery } from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n query$: Observable /* Search query observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search result list\n *\n * This function performs a lazy rendering of the search results, depending on\n * the vertical offset of the search result container.\n *\n * @param el - Search result list element\n * @param worker - Search worker\n * @param options - Options\n *\n * @returns Search result list component observable\n */\nexport function mountSearchResult(\n el: HTMLElement, { rx$ }: SearchWorker, { query$ }: MountOptions\n): Observable> {\n const push$ = new Subject()\n const boundary$ = watchElementBoundary(el.parentElement!)\n .pipe(\n filter(Boolean)\n )\n\n /* Retrieve nested components */\n const meta = getElement(\":scope > :first-child\", el)\n const list = getElement(\":scope > :last-child\", el)\n\n /* Wait until search is ready */\n const ready$ = rx$\n .pipe(\n filter(isSearchReadyMessage),\n take(1)\n )\n\n /* Update search result metadata */\n push$\n .pipe(\n withLatestFrom(query$),\n skipUntil(ready$)\n )\n .subscribe(([{ items }, { value }]) => {\n if (value) {\n switch (items.length) {\n\n /* No results */\n case 0:\n meta.textContent = translation(\"search.result.none\")\n break\n\n /* One result */\n case 1:\n meta.textContent = translation(\"search.result.one\")\n break\n\n /* Multiple result */\n default:\n meta.textContent = translation(\n \"search.result.other\",\n round(items.length)\n )\n }\n } else {\n meta.textContent = translation(\"search.result.placeholder\")\n }\n })\n\n /* Update search result list */\n push$\n .pipe(\n tap(() => list.innerHTML = \"\"),\n switchMap(({ items }) => merge(\n of(...items.slice(0, 10)),\n of(...items.slice(10))\n .pipe(\n bufferCount(4),\n zipWith(boundary$),\n switchMap(([chunk]) => chunk)\n )\n ))\n )\n .subscribe(result => list.appendChild(\n renderSearchResultItem(result)\n ))\n\n /* Filter search result message */\n const result$ = rx$\n .pipe(\n filter(isSearchResultMessage),\n map(({ data }) => data)\n )\n\n /* Create and return component */\n return result$\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n finalize,\n fromEvent,\n map,\n tap\n} from \"rxjs\"\n\nimport { getLocation } from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { SearchQuery } from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search sharing\n */\nexport interface SearchShare {\n url: URL /* Deep link for sharing */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n query$: Observable /* Search query observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n query$: Observable /* Search query observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search sharing\n *\n * @param _el - Search sharing element\n * @param options - Options\n *\n * @returns Search sharing observable\n */\nexport function watchSearchShare(\n _el: HTMLElement, { query$ }: WatchOptions\n): Observable {\n return query$\n .pipe(\n map(({ value }) => {\n const url = getLocation()\n url.hash = \"\"\n url.searchParams.delete(\"h\")\n url.searchParams.set(\"q\", value)\n return { url }\n })\n )\n}\n\n/**\n * Mount search sharing\n *\n * @param el - Search sharing element\n * @param options - Options\n *\n * @returns Search sharing component observable\n */\nexport function mountSearchShare(\n el: HTMLAnchorElement, options: MountOptions\n): Observable> {\n const push$ = new Subject()\n push$.subscribe(({ url }) => {\n el.setAttribute(\"data-clipboard-text\", el.href)\n el.href = `${url}`\n })\n\n /* Prevent following of link */\n fromEvent(el, \"click\")\n .subscribe(ev => ev.preventDefault())\n\n /* Create and return component */\n return watchSearchShare(el, options)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n asyncScheduler,\n combineLatestWith,\n distinctUntilChanged,\n filter,\n finalize,\n fromEvent,\n map,\n merge,\n observeOn,\n tap\n} from \"rxjs\"\n\nimport { Keyboard } from \"~/browser\"\nimport {\n SearchResult,\n SearchWorker,\n isSearchResultMessage\n} from \"~/integrations\"\n\nimport { Component, getComponentElement } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search suggestions\n */\nexport interface SearchSuggest {}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n keyboard$: Observable /* Keyboard observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search suggestions\n *\n * This function will perform a lazy rendering of the search results, depending\n * on the vertical offset of the search result container.\n *\n * @param el - Search result list element\n * @param worker - Search worker\n * @param options - Options\n *\n * @returns Search result list component observable\n */\nexport function mountSearchSuggest(\n el: HTMLElement, { rx$ }: SearchWorker, { keyboard$ }: MountOptions\n): Observable> {\n const push$ = new Subject()\n\n /* Retrieve query component and track all changes */\n const query = getComponentElement(\"search-query\")\n const query$ = merge(\n fromEvent(query, \"keydown\"),\n fromEvent(query, \"focus\")\n )\n .pipe(\n observeOn(asyncScheduler),\n map(() => query.value),\n distinctUntilChanged(),\n )\n\n /* Update search suggestions */\n push$\n .pipe(\n combineLatestWith(query$),\n map(([{ suggestions }, value]) => {\n const words = value.split(/([\\s-]+)/)\n if (suggestions?.length && words[words.length - 1]) {\n const last = suggestions[suggestions.length - 1]\n if (last.startsWith(words[words.length - 1]))\n words[words.length - 1] = last\n } else {\n words.length = 0\n }\n return words\n })\n )\n .subscribe(words => el.innerHTML = words\n .join(\"\")\n .replace(/\\s/g, \" \")\n )\n\n /* Set up search keyboard handlers */\n keyboard$\n .pipe(\n filter(({ mode }) => mode === \"search\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Right arrow: accept current suggestion */\n case \"ArrowRight\":\n if (\n el.innerText.length &&\n query.selectionStart === query.value.length\n )\n query.value = el.innerText\n break\n }\n })\n\n /* Filter search result message */\n const result$ = rx$\n .pipe(\n filter(isSearchResultMessage),\n map(({ data }) => data)\n )\n\n /* Create and return component */\n return result$\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(() => ({ ref: el }))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n NEVER,\n Observable,\n ObservableInput,\n filter,\n merge,\n mergeWith,\n sample,\n take\n} from \"rxjs\"\n\nimport { configuration } from \"~/_\"\nimport {\n Keyboard,\n getActiveElement,\n getElements,\n setToggle\n} from \"~/browser\"\nimport {\n SearchIndex,\n SearchResult,\n isSearchQueryMessage,\n isSearchReadyMessage,\n setupSearchWorker\n} from \"~/integrations\"\n\nimport {\n Component,\n getComponentElement,\n getComponentElements\n} from \"../../_\"\nimport {\n SearchQuery,\n mountSearchQuery\n} from \"../query\"\nimport { mountSearchResult } from \"../result\"\nimport {\n SearchShare,\n mountSearchShare\n} from \"../share\"\nimport {\n SearchSuggest,\n mountSearchSuggest\n} from \"../suggest\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search\n */\nexport type Search =\n | SearchQuery\n | SearchResult\n | SearchShare\n | SearchSuggest\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n index$: ObservableInput /* Search index observable */\n keyboard$: Observable /* Keyboard observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search\n *\n * This function sets up the search functionality, including the underlying\n * web worker and all keyboard bindings.\n *\n * @param el - Search element\n * @param options - Options\n *\n * @returns Search component observable\n */\nexport function mountSearch(\n el: HTMLElement, { index$, keyboard$ }: MountOptions\n): Observable> {\n const config = configuration()\n try {\n const url = __search?.worker || config.search\n const worker = setupSearchWorker(url, index$)\n\n /* Retrieve query and result components */\n const query = getComponentElement(\"search-query\", el)\n const result = getComponentElement(\"search-result\", el)\n\n /* Re-emit query when search is ready */\n const { tx$, rx$ } = worker\n tx$\n .pipe(\n filter(isSearchQueryMessage),\n sample(rx$.pipe(filter(isSearchReadyMessage))),\n take(1)\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Set up search keyboard handlers */\n keyboard$\n .pipe(\n filter(({ mode }) => mode === \"search\")\n )\n .subscribe(key => {\n const active = getActiveElement()\n switch (key.type) {\n\n /* Enter: go to first (best) result */\n case \"Enter\":\n if (active === query) {\n const anchors = new Map()\n for (const anchor of getElements(\n \":first-child [href]\", result\n )) {\n const article = anchor.firstElementChild!\n anchors.set(anchor, parseFloat(\n article.getAttribute(\"data-md-score\")!\n ))\n }\n\n /* Go to result with highest score, if any */\n if (anchors.size) {\n const [[best]] = [...anchors].sort(([, a], [, b]) => b - a)\n best.click()\n }\n\n /* Otherwise omit form submission */\n key.claim()\n }\n break\n\n /* Escape or Tab: close search */\n case \"Escape\":\n case \"Tab\":\n setToggle(\"search\", false)\n query.blur()\n break\n\n /* Vertical arrows: select previous or next search result */\n case \"ArrowUp\":\n case \"ArrowDown\":\n if (typeof active === \"undefined\") {\n query.focus()\n } else {\n const els = [query, ...getElements(\n \":not(details) > [href], summary, details[open] [href]\",\n result\n )]\n const i = Math.max(0, (\n Math.max(0, els.indexOf(active)) + els.length + (\n key.type === \"ArrowUp\" ? -1 : +1\n )\n ) % els.length)\n els[i].focus()\n }\n\n /* Prevent scrolling of page */\n key.claim()\n break\n\n /* All other keys: hand to search query */\n default:\n if (query !== getActiveElement())\n query.focus()\n }\n })\n\n /* Set up global keyboard handlers */\n keyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\"),\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Open search and select query */\n case \"f\":\n case \"s\":\n case \"/\":\n query.focus()\n query.select()\n\n /* Prevent scrolling of page */\n key.claim()\n break\n }\n })\n\n /* Create and return component */\n const query$ = mountSearchQuery(query, worker)\n const result$ = mountSearchResult(result, worker, { query$ })\n return merge(query$, result$)\n .pipe(\n mergeWith(\n\n /* Search sharing */\n ...getComponentElements(\"search-share\", el)\n .map(child => mountSearchShare(child, { query$ })),\n\n /* Search suggestions */\n ...getComponentElements(\"search-suggest\", el)\n .map(child => mountSearchSuggest(child, worker, { keyboard$ }))\n )\n )\n\n /* Gracefully handle broken search */\n } catch (err) {\n el.hidden = true\n return NEVER\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n ObservableInput,\n combineLatest,\n filter,\n map,\n startWith\n} from \"rxjs\"\n\nimport { getLocation } from \"~/browser\"\nimport {\n SearchIndex,\n setupSearchHighlighter\n} from \"~/integrations\"\nimport { h } from \"~/utilities\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search highlighting\n */\nexport interface SearchHighlight {\n nodes: Map /* Map of replacements */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n index$: ObservableInput /* Search index observable */\n location$: Observable /* Location observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search highlighting\n *\n * @param el - Content element\n * @param options - Options\n *\n * @returns Search highlighting component observable\n */\nexport function mountSearchHiglight(\n el: HTMLElement, { index$, location$ }: MountOptions\n): Observable> {\n return combineLatest([\n index$,\n location$\n .pipe(\n startWith(getLocation()),\n filter(url => !!url.searchParams.get(\"h\"))\n )\n ])\n .pipe(\n map(([index, url]) => setupSearchHighlighter(index.config, true)(\n url.searchParams.get(\"h\")!\n )),\n map(fn => {\n const nodes = new Map()\n\n /* Traverse text nodes and collect matches */\n const it = document.createNodeIterator(el, NodeFilter.SHOW_TEXT)\n for (let node = it.nextNode(); node; node = it.nextNode()) {\n if (node.parentElement?.offsetHeight) {\n const original = node.textContent!\n const replaced = fn(original)\n if (replaced.length > original.length)\n nodes.set(node as ChildNode, replaced)\n }\n }\n\n /* Replace original nodes with matches */\n for (const [node, text] of nodes) {\n const { childNodes } = h(\"span\", null, text)\n node.replaceWith(...Array.from(childNodes))\n }\n\n /* Return component */\n return { ref: el, nodes }\n })\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n auditTime,\n combineLatest,\n defer,\n distinctUntilChanged,\n finalize,\n map,\n tap,\n withLatestFrom\n} from \"rxjs\"\n\nimport {\n Viewport,\n getElement,\n getElementOffset\n} from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\nimport { Main } from \"../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Sidebar\n */\nexport interface Sidebar {\n height: number /* Sidebar height */\n locked: boolean /* Sidebar is locked */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n main$: Observable
    /* Main area observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch sidebar\n *\n * This function returns an observable that computes the visual parameters of\n * the sidebar which depends on the vertical viewport offset, as well as the\n * height of the main area. When the page is scrolled beyond the header, the\n * sidebar is locked and fills the remaining space.\n *\n * @param el - Sidebar element\n * @param options - Options\n *\n * @returns Sidebar observable\n */\nexport function watchSidebar(\n el: HTMLElement, { viewport$, main$ }: WatchOptions\n): Observable {\n const parent = el.parentElement!\n const adjust =\n parent.offsetTop -\n parent.parentElement!.offsetTop\n\n /* Compute the sidebar's available height and if it should be locked */\n return combineLatest([main$, viewport$])\n .pipe(\n map(([{ offset, height }, { offset: { y } }]) => {\n height = height\n + Math.min(adjust, Math.max(0, y - offset))\n - adjust\n return {\n height,\n locked: y >= offset + adjust\n }\n }),\n distinctUntilChanged((a, b) => (\n a.height === b.height &&\n a.locked === b.locked\n ))\n )\n}\n\n/**\n * Mount sidebar\n *\n * This function doesn't set the height of the actual sidebar, but of its first\n * child \u2013 the `.md-sidebar__scrollwrap` element in order to mitigiate jittery\n * sidebars when the footer is scrolled into view. At some point we switched\n * from `absolute` / `fixed` positioning to `sticky` positioning, significantly\n * reducing jitter in some browsers (respectively Firefox and Safari) when\n * scrolling from the top. However, top-aligned sticky positioning means that\n * the sidebar snaps to the bottom when the end of the container is reached.\n * This is what leads to the mentioned jitter, as the sidebar's height may be\n * updated too slowly.\n *\n * This behaviour can be mitigiated by setting the height of the sidebar to `0`\n * while preserving the padding, and the height on its first element.\n *\n * @param el - Sidebar element\n * @param options - Options\n *\n * @returns Sidebar component observable\n */\nexport function mountSidebar(\n el: HTMLElement, { header$, ...options }: MountOptions\n): Observable> {\n const inner = getElement(\".md-sidebar__scrollwrap\", el)\n const { y } = getElementOffset(inner)\n return defer(() => {\n const push$ = new Subject()\n push$\n .pipe(\n auditTime(0, animationFrameScheduler),\n withLatestFrom(header$)\n )\n .subscribe({\n\n /* Handle emission */\n next([{ height }, { height: offset }]) {\n inner.style.height = `${height - 2 * y}px`\n el.style.top = `${offset}px`\n },\n\n /* Handle complete */\n complete() {\n inner.style.height = \"\"\n el.style.top = \"\"\n }\n })\n\n /* Create and return component */\n return watchSidebar(el, options)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Repo, User } from \"github-types\"\nimport {\n EMPTY,\n Observable,\n catchError,\n defaultIfEmpty,\n map,\n zip\n} from \"rxjs\"\n\nimport { requestJSON } from \"~/browser\"\n\nimport { SourceFacts } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * GitHub release (partial)\n */\ninterface Release {\n tag_name: string /* Tag name */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch GitHub repository facts\n *\n * @param user - GitHub user or organization\n * @param repo - GitHub repository\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFactsFromGitHub(\n user: string, repo?: string\n): Observable {\n if (typeof repo !== \"undefined\") {\n const url = `https://api.github.com/repos/${user}/${repo}`\n return zip(\n\n /* Fetch version */\n requestJSON(`${url}/releases/latest`)\n .pipe(\n catchError(() => EMPTY), // @todo refactor instant loading\n map(release => ({\n version: release.tag_name\n })),\n defaultIfEmpty({})\n ),\n\n /* Fetch stars and forks */\n requestJSON(url)\n .pipe(\n catchError(() => EMPTY), // @todo refactor instant loading\n map(info => ({\n stars: info.stargazers_count,\n forks: info.forks_count\n })),\n defaultIfEmpty({})\n )\n )\n .pipe(\n map(([release, info]) => ({ ...release, ...info }))\n )\n\n /* User or organization */\n } else {\n const url = `https://api.github.com/users/${user}`\n return requestJSON(url)\n .pipe(\n map(info => ({\n repositories: info.public_repos\n })),\n defaultIfEmpty({})\n )\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ProjectSchema } from \"gitlab\"\nimport {\n EMPTY,\n Observable,\n catchError,\n defaultIfEmpty,\n map\n} from \"rxjs\"\n\nimport { requestJSON } from \"~/browser\"\n\nimport { SourceFacts } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch GitLab repository facts\n *\n * @param base - GitLab base\n * @param project - GitLab project\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFactsFromGitLab(\n base: string, project: string\n): Observable {\n const url = `https://${base}/api/v4/projects/${encodeURIComponent(project)}`\n return requestJSON(url)\n .pipe(\n catchError(() => EMPTY), // @todo refactor instant loading\n map(({ star_count, forks_count }) => ({\n stars: star_count,\n forks: forks_count\n })),\n defaultIfEmpty({})\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { EMPTY, Observable } from \"rxjs\"\n\nimport { fetchSourceFactsFromGitHub } from \"../github\"\nimport { fetchSourceFactsFromGitLab } from \"../gitlab\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository facts for repositories\n */\nexport interface RepositoryFacts {\n stars?: number /* Number of stars */\n forks?: number /* Number of forks */\n version?: string /* Latest version */\n}\n\n/**\n * Repository facts for organizations\n */\nexport interface OrganizationFacts {\n repositories?: number /* Number of repositories */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Repository facts\n */\nexport type SourceFacts =\n | RepositoryFacts\n | OrganizationFacts\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch repository facts\n *\n * @param url - Repository URL\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFacts(\n url: string\n): Observable {\n const [type] = url.match(/(git(?:hub|lab))/i) || []\n switch (type.toLowerCase()) {\n\n /* GitHub repository */\n case \"github\":\n const [, user, repo] = url.match(/^.+github\\.com\\/([^/]+)\\/?([^/]+)?/i)!\n return fetchSourceFactsFromGitHub(user, repo)\n\n /* GitLab repository */\n case \"gitlab\":\n const [, base, slug] = url.match(/^.+?([^/]*gitlab[^/]+)\\/(.+?)\\/?$/i)!\n return fetchSourceFactsFromGitLab(base, slug)\n\n /* Everything else */\n default:\n return EMPTY\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n Observable,\n Subject,\n catchError,\n defer,\n filter,\n finalize,\n map,\n of,\n shareReplay,\n tap\n} from \"rxjs\"\n\nimport { getElement } from \"~/browser\"\nimport { renderSourceFacts } from \"~/templates\"\n\nimport { Component } from \"../../_\"\nimport {\n SourceFacts,\n fetchSourceFacts\n} from \"../facts\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository information\n */\nexport interface Source {\n facts: SourceFacts /* Repository facts */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository information observable\n */\nlet fetch$: Observable\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch repository information\n *\n * This function tries to read the repository facts from session storage, and\n * if unsuccessful, fetches them from the underlying provider.\n *\n * @param el - Repository information element\n *\n * @returns Repository information observable\n */\nexport function watchSource(\n el: HTMLAnchorElement\n): Observable {\n return fetch$ ||= defer(() => {\n const cached = __md_get(\"__source\", sessionStorage)\n if (cached)\n return of(cached)\n else\n return fetchSourceFacts(el.href)\n .pipe(\n tap(facts => __md_set(\"__source\", facts, sessionStorage))\n )\n })\n .pipe(\n catchError(() => EMPTY),\n filter(facts => Object.keys(facts).length > 0),\n map(facts => ({ facts })),\n shareReplay(1)\n )\n}\n\n/**\n * Mount repository information\n *\n * @param el - Repository information element\n *\n * @returns Repository information component observable\n */\nexport function mountSource(\n el: HTMLAnchorElement\n): Observable> {\n const inner = getElement(\":scope > :last-child\", el)\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe(({ facts }) => {\n inner.appendChild(renderSourceFacts(facts))\n inner.classList.add(\"md-source__repository--active\")\n })\n\n /* Create and return component */\n return watchSource(el)\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n defer,\n distinctUntilKeyChanged,\n finalize,\n map,\n of,\n switchMap,\n tap\n} from \"rxjs\"\n\nimport { feature } from \"~/_\"\nimport {\n Viewport,\n watchElementSize,\n watchViewportAt\n} from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Navigation tabs\n */\nexport interface Tabs {\n hidden: boolean /* Navigation tabs are hidden */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch navigation tabs\n *\n * @param el - Navigation tabs element\n * @param options - Options\n *\n * @returns Navigation tabs observable\n */\nexport function watchTabs(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable {\n return watchElementSize(document.body)\n .pipe(\n switchMap(() => watchViewportAt(el, { header$, viewport$ })),\n map(({ offset: { y } }) => {\n return {\n hidden: y >= 10\n }\n }),\n distinctUntilKeyChanged(\"hidden\")\n )\n}\n\n/**\n * Mount navigation tabs\n *\n * This function hides the navigation tabs when scrolling past the threshold\n * and makes them reappear in a nice CSS animation when scrolling back up.\n *\n * @param el - Navigation tabs element\n * @param options - Options\n *\n * @returns Navigation tabs component observable\n */\nexport function mountTabs(\n el: HTMLElement, options: MountOptions\n): Observable> {\n return defer(() => {\n const push$ = new Subject()\n push$.subscribe({\n\n /* Handle emission */\n next({ hidden }) {\n el.hidden = hidden\n },\n\n /* Handle complete */\n complete() {\n el.hidden = false\n }\n })\n\n /* Create and return component */\n return (\n feature(\"navigation.tabs.sticky\")\n ? of({ hidden: false })\n : watchTabs(el, options)\n )\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n bufferCount,\n combineLatestWith,\n debounceTime,\n defer,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n finalize,\n map,\n of,\n repeat,\n scan,\n share,\n skip,\n startWith,\n switchMap,\n takeLast,\n takeUntil,\n tap,\n withLatestFrom\n} from \"rxjs\"\n\nimport { feature } from \"~/_\"\nimport {\n Viewport,\n getElement,\n getElements,\n getLocation,\n getOptionalElement,\n watchElementSize\n} from \"~/browser\"\n\nimport {\n Component,\n getComponentElement\n} from \"../_\"\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Table of contents\n */\nexport interface TableOfContents {\n prev: HTMLAnchorElement[][] /* Anchors (previous) */\n next: HTMLAnchorElement[][] /* Anchors (next) */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n target$: Observable /* Location target observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch table of contents\n *\n * This is effectively a scroll spy implementation which will account for the\n * fixed header and automatically re-calculate anchor offsets when the viewport\n * is resized. The returned observable will only emit if the table of contents\n * needs to be repainted.\n *\n * This implementation tracks an anchor element's entire path starting from its\n * level up to the top-most anchor element, e.g. `[h3, h2, h1]`. Although the\n * Material theme currently doesn't make use of this information, it enables\n * the styling of the entire hierarchy through customization.\n *\n * Note that the current anchor is the last item of the `prev` anchor list.\n *\n * @param el - Table of contents element\n * @param options - Options\n *\n * @returns Table of contents observable\n */\nexport function watchTableOfContents(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable {\n const table = new Map()\n\n /* Compute anchor-to-target mapping */\n const anchors = getElements(\"[href^=\\\\#]\", el)\n for (const anchor of anchors) {\n const id = decodeURIComponent(anchor.hash.substring(1))\n const target = getOptionalElement(`[id=\"${id}\"]`)\n if (typeof target !== \"undefined\")\n table.set(anchor, target)\n }\n\n /* Compute necessary adjustment for header */\n const adjust$ = header$\n .pipe(\n distinctUntilKeyChanged(\"height\"),\n map(({ height }) => {\n const main = getComponentElement(\"main\")\n const grid = getElement(\":scope > :first-child\", main)\n return height + 0.8 * (\n grid.offsetTop -\n main.offsetTop\n )\n }),\n share()\n )\n\n /* Compute partition of previous and next anchors */\n const partition$ = watchElementSize(document.body)\n .pipe(\n distinctUntilKeyChanged(\"height\"),\n\n /* Build index to map anchor paths to vertical offsets */\n switchMap(body => defer(() => {\n let path: HTMLAnchorElement[] = []\n return of([...table].reduce((index, [anchor, target]) => {\n while (path.length) {\n const last = table.get(path[path.length - 1])!\n if (last.tagName >= target.tagName) {\n path.pop()\n } else {\n break\n }\n }\n\n /* If the current anchor is hidden, continue with its parent */\n let offset = target.offsetTop\n while (!offset && target.parentElement) {\n target = target.parentElement\n offset = target.offsetTop\n }\n\n /* Map reversed anchor path to vertical offset */\n return index.set(\n [...path = [...path, anchor]].reverse(),\n offset\n )\n }, new Map()))\n })\n .pipe(\n\n /* Sort index by vertical offset (see https://bit.ly/30z6QSO) */\n map(index => new Map([...index].sort(([, a], [, b]) => a - b))),\n combineLatestWith(adjust$),\n\n /* Re-compute partition when viewport offset changes */\n switchMap(([index, adjust]) => viewport$\n .pipe(\n scan(([prev, next], { offset: { y }, size }) => {\n const last = y + size.height >= Math.floor(body.height)\n\n /* Look forward */\n while (next.length) {\n const [, offset] = next[0]\n if (offset - adjust < y || last) {\n prev = [...prev, next.shift()!]\n } else {\n break\n }\n }\n\n /* Look backward */\n while (prev.length) {\n const [, offset] = prev[prev.length - 1]\n if (offset - adjust >= y && !last) {\n next = [prev.pop()!, ...next]\n } else {\n break\n }\n }\n\n /* Return partition */\n return [prev, next]\n }, [[], [...index]]),\n distinctUntilChanged((a, b) => (\n a[0] === b[0] &&\n a[1] === b[1]\n ))\n )\n )\n )\n )\n )\n\n /* Compute and return anchor list migrations */\n return partition$\n .pipe(\n map(([prev, next]) => ({\n prev: prev.map(([path]) => path),\n next: next.map(([path]) => path)\n })),\n\n /* Extract anchor list migrations */\n startWith({ prev: [], next: [] }),\n bufferCount(2, 1),\n map(([a, b]) => {\n\n /* Moving down */\n if (a.prev.length < b.prev.length) {\n return {\n prev: b.prev.slice(Math.max(0, a.prev.length - 1), b.prev.length),\n next: []\n }\n\n /* Moving up */\n } else {\n return {\n prev: b.prev.slice(-1),\n next: b.next.slice(0, b.next.length - a.next.length)\n }\n }\n })\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Mount table of contents\n *\n * @param el - Table of contents element\n * @param options - Options\n *\n * @returns Table of contents component observable\n */\nexport function mountTableOfContents(\n el: HTMLElement, { viewport$, header$, target$ }: MountOptions\n): Observable> {\n return defer(() => {\n const push$ = new Subject()\n const done$ = push$.pipe(takeLast(1))\n push$.subscribe(({ prev, next }) => {\n\n /* Look forward */\n for (const [anchor] of next) {\n anchor.classList.remove(\"md-nav__link--passed\")\n anchor.classList.remove(\"md-nav__link--active\")\n }\n\n /* Look backward */\n for (const [index, [anchor]] of prev.entries()) {\n anchor.classList.add(\"md-nav__link--passed\")\n anchor.classList.toggle(\n \"md-nav__link--active\",\n index === prev.length - 1\n )\n }\n })\n\n /* Set up anchor tracking, if enabled */\n if (feature(\"navigation.tracking\"))\n viewport$\n .pipe(\n takeUntil(done$),\n distinctUntilKeyChanged(\"offset\"),\n debounceTime(250),\n skip(1),\n takeUntil(target$.pipe(skip(1))),\n repeat({ delay: 250 }),\n withLatestFrom(push$)\n )\n .subscribe(([, { prev }]) => {\n const url = getLocation()\n\n /* Set hash fragment to active anchor */\n const anchor = prev[prev.length - 1]\n if (anchor && anchor.length) {\n const [active] = anchor\n const { hash } = new URL(active.href)\n if (url.hash !== hash) {\n url.hash = hash\n history.replaceState({}, \"\", `${url}`)\n }\n\n /* Reset anchor when at the top */\n } else {\n url.hash = \"\"\n history.replaceState({}, \"\", `${url}`)\n }\n })\n\n /* Create and return component */\n return watchTableOfContents(el, { viewport$, header$ })\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n bufferCount,\n combineLatest,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n endWith,\n finalize,\n map,\n repeat,\n skip,\n takeLast,\n takeUntil,\n tap\n} from \"rxjs\"\n\nimport { Viewport } from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\nimport { Main } from \"../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Back-to-top button\n */\nexport interface BackToTop {\n hidden: boolean /* Back-to-top button is hidden */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n main$: Observable
    /* Main area observable */\n target$: Observable /* Location target observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n target$: Observable /* Location target observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch back-to-top\n *\n * @param _el - Back-to-top element\n * @param options - Options\n *\n * @returns Back-to-top observable\n */\nexport function watchBackToTop(\n _el: HTMLElement, { viewport$, main$, target$ }: WatchOptions\n): Observable {\n\n /* Compute direction */\n const direction$ = viewport$\n .pipe(\n map(({ offset: { y } }) => y),\n bufferCount(2, 1),\n map(([a, b]) => a > b && b > 0),\n distinctUntilChanged()\n )\n\n /* Compute whether main area is active */\n const active$ = main$\n .pipe(\n map(({ active }) => active)\n )\n\n /* Compute threshold for hiding */\n return combineLatest([active$, direction$])\n .pipe(\n map(([active, direction]) => !(active && direction)),\n distinctUntilChanged(),\n takeUntil(target$.pipe(skip(1))),\n endWith(true),\n repeat({ delay: 250 }),\n map(hidden => ({ hidden }))\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Mount back-to-top\n *\n * @param el - Back-to-top element\n * @param options - Options\n *\n * @returns Back-to-top component observable\n */\nexport function mountBackToTop(\n el: HTMLElement, { viewport$, header$, main$, target$ }: MountOptions\n): Observable> {\n const push$ = new Subject()\n const done$ = push$.pipe(takeLast(1))\n push$.subscribe({\n\n /* Handle emission */\n next({ hidden }) {\n el.hidden = hidden\n if (hidden) {\n el.setAttribute(\"tabindex\", \"-1\")\n el.blur()\n } else {\n el.removeAttribute(\"tabindex\")\n }\n },\n\n /* Handle complete */\n complete() {\n el.style.top = \"\"\n el.hidden = true\n el.removeAttribute(\"tabindex\")\n }\n })\n\n /* Watch header height */\n header$\n .pipe(\n takeUntil(done$),\n distinctUntilKeyChanged(\"height\")\n )\n .subscribe(({ height }) => {\n el.style.top = `${height + 16}px`\n })\n\n /* Create and return component */\n return watchBackToTop(el, { viewport$, main$, target$ })\n .pipe(\n tap(state => push$.next(state)),\n finalize(() => push$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n fromEvent,\n map,\n mergeMap,\n switchMap,\n takeWhile,\n tap,\n withLatestFrom\n} from \"rxjs\"\n\nimport { getElements } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch options\n */\ninterface PatchOptions {\n document$: Observable /* Document observable */\n tablet$: Observable /* Media tablet observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch indeterminate checkboxes\n *\n * This function replaces the indeterminate \"pseudo state\" with the actual\n * indeterminate state, which is used to keep navigation always expanded.\n *\n * @param options - Options\n */\nexport function patchIndeterminate(\n { document$, tablet$ }: PatchOptions\n): void {\n document$\n .pipe(\n switchMap(() => getElements(\n // @todo `data-md-state` is deprecated and removed in v9\n \".md-toggle--indeterminate, [data-md-state=indeterminate]\"\n )),\n tap(el => {\n el.indeterminate = true\n el.checked = false\n }),\n mergeMap(el => fromEvent(el, \"change\")\n .pipe(\n takeWhile(() => el.classList.contains(\"md-toggle--indeterminate\")),\n map(() => el)\n )\n ),\n withLatestFrom(tablet$)\n )\n .subscribe(([el, tablet]) => {\n el.classList.remove(\"md-toggle--indeterminate\")\n if (tablet)\n el.checked = false\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n filter,\n fromEvent,\n map,\n mergeMap,\n switchMap,\n tap\n} from \"rxjs\"\n\nimport { getElements } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch options\n */\ninterface PatchOptions {\n document$: Observable /* Document observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Check whether the given device is an Apple device\n *\n * @returns Test result\n */\nfunction isAppleDevice(): boolean {\n return /(iPad|iPhone|iPod)/.test(navigator.userAgent)\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch all elements with `data-md-scrollfix` attributes\n *\n * This is a year-old patch which ensures that overflow scrolling works at the\n * top and bottom of containers on iOS by ensuring a `1px` scroll offset upon\n * the start of a touch event.\n *\n * @see https://bit.ly/2SCtAOO - Original source\n *\n * @param options - Options\n */\nexport function patchScrollfix(\n { document$ }: PatchOptions\n): void {\n document$\n .pipe(\n switchMap(() => getElements(\"[data-md-scrollfix]\")),\n tap(el => el.removeAttribute(\"data-md-scrollfix\")),\n filter(isAppleDevice),\n mergeMap(el => fromEvent(el, \"touchstart\")\n .pipe(\n map(() => el)\n )\n )\n )\n .subscribe(el => {\n const top = el.scrollTop\n\n /* We're at the top of the container */\n if (top === 0) {\n el.scrollTop = 1\n\n /* We're at the bottom of the container */\n } else if (top + el.offsetHeight === el.scrollHeight) {\n el.scrollTop = top - 1\n }\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n combineLatest,\n delay,\n map,\n of,\n switchMap,\n withLatestFrom\n} from \"rxjs\"\n\nimport {\n Viewport,\n watchToggle\n} from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch options\n */\ninterface PatchOptions {\n viewport$: Observable /* Viewport observable */\n tablet$: Observable /* Media tablet observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch the document body to lock when search is open\n *\n * For mobile and tablet viewports, the search is rendered full screen, which\n * leads to scroll leaking when at the top or bottom of the search result. This\n * function locks the body when the search is in full screen mode, and restores\n * the scroll position when leaving.\n *\n * @param options - Options\n */\nexport function patchScrolllock(\n { viewport$, tablet$ }: PatchOptions\n): void {\n combineLatest([watchToggle(\"search\"), tablet$])\n .pipe(\n map(([active, tablet]) => active && !tablet),\n switchMap(active => of(active)\n .pipe(\n delay(active ? 400 : 100)\n )\n ),\n withLatestFrom(viewport$)\n )\n .subscribe(([active, { offset: { y }}]) => {\n if (active) {\n document.body.setAttribute(\"data-md-scrolllock\", \"\")\n document.body.style.top = `-${y}px`\n } else {\n const value = -1 * parseInt(document.body.style.top, 10)\n document.body.removeAttribute(\"data-md-scrolllock\")\n document.body.style.top = \"\"\n if (value)\n window.scrollTo(0, value)\n }\n })\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Polyfills\n * ------------------------------------------------------------------------- */\n\n/* Polyfill `Object.entries` */\nif (!Object.entries)\n Object.entries = function (obj: object) {\n const data: [string, string][] = []\n for (const key of Object.keys(obj))\n // @ts-expect-error - ignore property access warning\n data.push([key, obj[key]])\n\n /* Return entries */\n return data\n }\n\n/* Polyfill `Object.values` */\nif (!Object.values)\n Object.values = function (obj: object) {\n const data: string[] = []\n for (const key of Object.keys(obj))\n // @ts-expect-error - ignore property access warning\n data.push(obj[key])\n\n /* Return values */\n return data\n }\n\n/* ------------------------------------------------------------------------- */\n\n/* Polyfills for `Element` */\nif (typeof Element !== \"undefined\") {\n\n /* Polyfill `Element.scrollTo` */\n if (!Element.prototype.scrollTo)\n Element.prototype.scrollTo = function (\n x?: ScrollToOptions | number, y?: number\n ): void {\n if (typeof x === \"object\") {\n this.scrollLeft = x.left!\n this.scrollTop = x.top!\n } else {\n this.scrollLeft = x!\n this.scrollTop = y!\n }\n }\n\n /* Polyfill `Element.replaceWith` */\n if (!Element.prototype.replaceWith)\n Element.prototype.replaceWith = function (\n ...nodes: Array\n ): void {\n const parent = this.parentNode\n if (parent) {\n if (nodes.length === 0)\n parent.removeChild(this)\n\n /* Replace children and create text nodes */\n for (let i = nodes.length - 1; i >= 0; i--) {\n let node = nodes[i]\n if (typeof node !== \"object\")\n node = document.createTextNode(node)\n else if (node.parentNode)\n node.parentNode.removeChild(node)\n\n /* Replace child or insert before previous sibling */\n if (!i)\n parent.replaceChild(node, this)\n else\n parent.insertBefore(this.previousSibling!, node)\n }\n }\n }\n}\n"], - "mappings": "6+BAAA,IAAAA,GAAAC,GAAA,CAAAC,GAAAC,KAAA,EAAC,SAAUC,EAAQC,EAAS,CAC1B,OAAOH,IAAY,UAAY,OAAOC,IAAW,YAAcE,EAAQ,EACvE,OAAO,QAAW,YAAc,OAAO,IAAM,OAAOA,CAAO,EAC1DA,EAAQ,CACX,GAAEH,GAAO,UAAY,CAAE,aASrB,SAASI,EAA0BC,EAAO,CACxC,IAAIC,EAAmB,GACnBC,EAA0B,GAC1BC,EAAiC,KAEjCC,EAAsB,CACxB,KAAM,GACN,OAAQ,GACR,IAAK,GACL,IAAK,GACL,MAAO,GACP,SAAU,GACV,OAAQ,GACR,KAAM,GACN,MAAO,GACP,KAAM,GACN,KAAM,GACN,SAAU,GACV,iBAAkB,EACpB,EAOA,SAASC,EAAmBC,EAAI,CAC9B,MACE,GAAAA,GACAA,IAAO,UACPA,EAAG,WAAa,QAChBA,EAAG,WAAa,QAChB,cAAeA,GACf,aAAcA,EAAG,UAKrB,CASA,SAASC,EAA8BD,EAAI,CACzC,IAAIE,GAAOF,EAAG,KACVG,GAAUH,EAAG,QAUjB,MARI,GAAAG,KAAY,SAAWL,EAAoBI,KAAS,CAACF,EAAG,UAIxDG,KAAY,YAAc,CAACH,EAAG,UAI9BA,EAAG,kBAKT,CAOA,SAASI,EAAqBJ,EAAI,CAC5BA,EAAG,UAAU,SAAS,eAAe,IAGzCA,EAAG,UAAU,IAAI,eAAe,EAChCA,EAAG,aAAa,2BAA4B,EAAE,EAChD,CAOA,SAASK,EAAwBL,EAAI,CAC/B,CAACA,EAAG,aAAa,0BAA0B,IAG/CA,EAAG,UAAU,OAAO,eAAe,EACnCA,EAAG,gBAAgB,0BAA0B,EAC/C,CAUA,SAASM,EAAUC,EAAG,CAChBA,EAAE,SAAWA,EAAE,QAAUA,EAAE,UAI3BR,EAAmBL,EAAM,aAAa,GACxCU,EAAqBV,EAAM,aAAa,EAG1CC,EAAmB,GACrB,CAUA,SAASa,EAAcD,EAAG,CACxBZ,EAAmB,EACrB,CASA,SAASc,EAAQF,EAAG,CAEd,CAACR,EAAmBQ,EAAE,MAAM,IAI5BZ,GAAoBM,EAA8BM,EAAE,MAAM,IAC5DH,EAAqBG,EAAE,MAAM,CAEjC,CAMA,SAASG,EAAOH,EAAG,CACb,CAACR,EAAmBQ,EAAE,MAAM,IAK9BA,EAAE,OAAO,UAAU,SAAS,eAAe,GAC3CA,EAAE,OAAO,aAAa,0BAA0B,KAMhDX,EAA0B,GAC1B,OAAO,aAAaC,CAA8B,EAClDA,EAAiC,OAAO,WAAW,UAAW,CAC5DD,EAA0B,EAC5B,EAAG,GAAG,EACNS,EAAwBE,EAAE,MAAM,EAEpC,CAOA,SAASI,EAAmBJ,EAAG,CACzB,SAAS,kBAAoB,WAK3BX,IACFD,EAAmB,IAErBiB,EAA+B,EAEnC,CAQA,SAASA,GAAiC,CACxC,SAAS,iBAAiB,YAAaC,CAAoB,EAC3D,SAAS,iBAAiB,YAAaA,CAAoB,EAC3D,SAAS,iBAAiB,UAAWA,CAAoB,EACzD,SAAS,iBAAiB,cAAeA,CAAoB,EAC7D,SAAS,iBAAiB,cAAeA,CAAoB,EAC7D,SAAS,iBAAiB,YAAaA,CAAoB,EAC3D,SAAS,iBAAiB,YAAaA,CAAoB,EAC3D,SAAS,iBAAiB,aAAcA,CAAoB,EAC5D,SAAS,iBAAiB,WAAYA,CAAoB,CAC5D,CAEA,SAASC,GAAoC,CAC3C,SAAS,oBAAoB,YAAaD,CAAoB,EAC9D,SAAS,oBAAoB,YAAaA,CAAoB,EAC9D,SAAS,oBAAoB,UAAWA,CAAoB,EAC5D,SAAS,oBAAoB,cAAeA,CAAoB,EAChE,SAAS,oBAAoB,cAAeA,CAAoB,EAChE,SAAS,oBAAoB,YAAaA,CAAoB,EAC9D,SAAS,oBAAoB,YAAaA,CAAoB,EAC9D,SAAS,oBAAoB,aAAcA,CAAoB,EAC/D,SAAS,oBAAoB,WAAYA,CAAoB,CAC/D,CASA,SAASA,EAAqBN,EAAG,CAG3BA,EAAE,OAAO,UAAYA,EAAE,OAAO,SAAS,YAAY,IAAM,SAI7DZ,EAAmB,GACnBmB,EAAkC,EACpC,CAKA,SAAS,iBAAiB,UAAWR,EAAW,EAAI,EACpD,SAAS,iBAAiB,YAAaE,EAAe,EAAI,EAC1D,SAAS,iBAAiB,cAAeA,EAAe,EAAI,EAC5D,SAAS,iBAAiB,aAAcA,EAAe,EAAI,EAC3D,SAAS,iBAAiB,mBAAoBG,EAAoB,EAAI,EAEtEC,EAA+B,EAM/BlB,EAAM,iBAAiB,QAASe,EAAS,EAAI,EAC7Cf,EAAM,iBAAiB,OAAQgB,EAAQ,EAAI,EAOvChB,EAAM,WAAa,KAAK,wBAA0BA,EAAM,KAI1DA,EAAM,KAAK,aAAa,wBAAyB,EAAE,EAC1CA,EAAM,WAAa,KAAK,gBACjC,SAAS,gBAAgB,UAAU,IAAI,kBAAkB,EACzD,SAAS,gBAAgB,aAAa,wBAAyB,EAAE,EAErE,CAKA,GAAI,OAAO,QAAW,aAAe,OAAO,UAAa,YAAa,CAIpE,OAAO,0BAA4BD,EAInC,IAAIsB,EAEJ,GAAI,CACFA,EAAQ,IAAI,YAAY,8BAA8B,CACxD,OAASC,EAAP,CAEAD,EAAQ,SAAS,YAAY,aAAa,EAC1CA,EAAM,gBAAgB,+BAAgC,GAAO,GAAO,CAAC,CAAC,CACxE,CAEA,OAAO,cAAcA,CAAK,CAC5B,CAEI,OAAO,UAAa,aAGtBtB,EAA0B,QAAQ,CAGtC,CAAE,ICvTF,IAAAwB,GAAAC,GAAAC,IAAA,EAAC,SAASC,EAAQ,CAOhB,IAAIC,EAA6B,UAAW,CAC1C,GAAI,CACF,MAAO,CAAC,CAAC,OAAO,QAClB,OAASC,EAAP,CACA,MAAO,EACT,CACF,EAGIC,EAAoBF,EAA2B,EAE/CG,EAAiB,SAASC,EAAO,CACnC,IAAIC,EAAW,CACb,KAAM,UAAW,CACf,IAAIC,EAAQF,EAAM,MAAM,EACxB,MAAO,CAAE,KAAME,IAAU,OAAQ,MAAOA,CAAM,CAChD,CACF,EAEA,OAAIJ,IACFG,EAAS,OAAO,UAAY,UAAW,CACrC,OAAOA,CACT,GAGKA,CACT,EAMIE,EAAiB,SAASD,EAAO,CACnC,OAAO,mBAAmBA,CAAK,EAAE,QAAQ,OAAQ,GAAG,CACtD,EAEIE,EAAmB,SAASF,EAAO,CACrC,OAAO,mBAAmB,OAAOA,CAAK,EAAE,QAAQ,MAAO,GAAG,CAAC,CAC7D,EAEIG,EAA0B,UAAW,CAEvC,IAAIC,EAAkB,SAASC,EAAc,CAC3C,OAAO,eAAe,KAAM,WAAY,CAAE,SAAU,GAAM,MAAO,CAAC,CAAE,CAAC,EACrE,IAAIC,EAAqB,OAAOD,EAEhC,GAAIC,IAAuB,YAEpB,GAAIA,IAAuB,SAC5BD,IAAiB,IACnB,KAAK,YAAYA,CAAY,UAEtBA,aAAwBD,EAAiB,CAClD,IAAIG,EAAQ,KACZF,EAAa,QAAQ,SAASL,EAAOQ,EAAM,CACzCD,EAAM,OAAOC,EAAMR,CAAK,CAC1B,CAAC,CACH,SAAYK,IAAiB,MAAUC,IAAuB,SAC5D,GAAI,OAAO,UAAU,SAAS,KAAKD,CAAY,IAAM,iBACnD,QAASI,EAAI,EAAGA,EAAIJ,EAAa,OAAQI,IAAK,CAC5C,IAAIC,EAAQL,EAAaI,GACzB,GAAK,OAAO,UAAU,SAAS,KAAKC,CAAK,IAAM,kBAAsBA,EAAM,SAAW,EACpF,KAAK,OAAOA,EAAM,GAAIA,EAAM,EAAE,MAE9B,OAAM,IAAI,UAAU,4CAA8CD,EAAI,6BAA8B,CAExG,KAEA,SAASE,KAAON,EACVA,EAAa,eAAeM,CAAG,GACjC,KAAK,OAAOA,EAAKN,EAAaM,EAAI,MAKxC,OAAM,IAAI,UAAU,8CAA+C,CAEvE,EAEIC,EAAQR,EAAgB,UAE5BQ,EAAM,OAAS,SAASJ,EAAMR,EAAO,CAC/BQ,KAAQ,KAAK,SACf,KAAK,SAASA,GAAM,KAAK,OAAOR,CAAK,CAAC,EAEtC,KAAK,SAASQ,GAAQ,CAAC,OAAOR,CAAK,CAAC,CAExC,EAEAY,EAAM,OAAS,SAASJ,EAAM,CAC5B,OAAO,KAAK,SAASA,EACvB,EAEAI,EAAM,IAAM,SAASJ,EAAM,CACzB,OAAQA,KAAQ,KAAK,SAAY,KAAK,SAASA,GAAM,GAAK,IAC5D,EAEAI,EAAM,OAAS,SAASJ,EAAM,CAC5B,OAAQA,KAAQ,KAAK,SAAY,KAAK,SAASA,GAAM,MAAM,CAAC,EAAI,CAAC,CACnE,EAEAI,EAAM,IAAM,SAASJ,EAAM,CACzB,OAAQA,KAAQ,KAAK,QACvB,EAEAI,EAAM,IAAM,SAASJ,EAAMR,EAAO,CAChC,KAAK,SAASQ,GAAQ,CAAC,OAAOR,CAAK,CAAC,CACtC,EAEAY,EAAM,QAAU,SAASC,EAAUC,EAAS,CAC1C,IAAIC,EACJ,QAASP,KAAQ,KAAK,SACpB,GAAI,KAAK,SAAS,eAAeA,CAAI,EAAG,CACtCO,EAAU,KAAK,SAASP,GACxB,QAASC,EAAI,EAAGA,EAAIM,EAAQ,OAAQN,IAClCI,EAAS,KAAKC,EAASC,EAAQN,GAAID,EAAM,IAAI,CAEjD,CAEJ,EAEAI,EAAM,KAAO,UAAW,CACtB,IAAId,EAAQ,CAAC,EACb,YAAK,QAAQ,SAASE,EAAOQ,EAAM,CACjCV,EAAM,KAAKU,CAAI,CACjB,CAAC,EACMX,EAAeC,CAAK,CAC7B,EAEAc,EAAM,OAAS,UAAW,CACxB,IAAId,EAAQ,CAAC,EACb,YAAK,QAAQ,SAASE,EAAO,CAC3BF,EAAM,KAAKE,CAAK,CAClB,CAAC,EACMH,EAAeC,CAAK,CAC7B,EAEAc,EAAM,QAAU,UAAW,CACzB,IAAId,EAAQ,CAAC,EACb,YAAK,QAAQ,SAASE,EAAOQ,EAAM,CACjCV,EAAM,KAAK,CAACU,EAAMR,CAAK,CAAC,CAC1B,CAAC,EACMH,EAAeC,CAAK,CAC7B,EAEIF,IACFgB,EAAM,OAAO,UAAYA,EAAM,SAGjCA,EAAM,SAAW,UAAW,CAC1B,IAAII,EAAc,CAAC,EACnB,YAAK,QAAQ,SAAShB,EAAOQ,EAAM,CACjCQ,EAAY,KAAKf,EAAeO,CAAI,EAAI,IAAMP,EAAeD,CAAK,CAAC,CACrE,CAAC,EACMgB,EAAY,KAAK,GAAG,CAC7B,EAGAvB,EAAO,gBAAkBW,CAC3B,EAEIa,EAAkC,UAAW,CAC/C,GAAI,CACF,IAAIb,EAAkBX,EAAO,gBAE7B,OACG,IAAIW,EAAgB,MAAM,EAAE,SAAS,IAAM,OAC3C,OAAOA,EAAgB,UAAU,KAAQ,YACzC,OAAOA,EAAgB,UAAU,SAAY,UAElD,OAASc,EAAP,CACA,MAAO,EACT,CACF,EAEKD,EAAgC,GACnCd,EAAwB,EAG1B,IAAIS,EAAQnB,EAAO,gBAAgB,UAE/B,OAAOmB,EAAM,MAAS,aACxBA,EAAM,KAAO,UAAW,CACtB,IAAIL,EAAQ,KACRT,EAAQ,CAAC,EACb,KAAK,QAAQ,SAASE,EAAOQ,EAAM,CACjCV,EAAM,KAAK,CAACU,EAAMR,CAAK,CAAC,EACnBO,EAAM,UACTA,EAAM,OAAOC,CAAI,CAErB,CAAC,EACDV,EAAM,KAAK,SAASqB,EAAGC,EAAG,CACxB,OAAID,EAAE,GAAKC,EAAE,GACJ,GACED,EAAE,GAAKC,EAAE,GACX,EAEA,CAEX,CAAC,EACGb,EAAM,WACRA,EAAM,SAAW,CAAC,GAEpB,QAASE,EAAI,EAAGA,EAAIX,EAAM,OAAQW,IAChC,KAAK,OAAOX,EAAMW,GAAG,GAAIX,EAAMW,GAAG,EAAE,CAExC,GAGE,OAAOG,EAAM,aAAgB,YAC/B,OAAO,eAAeA,EAAO,cAAe,CAC1C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,SAASP,EAAc,CAC5B,GAAI,KAAK,SACP,KAAK,SAAW,CAAC,MACZ,CACL,IAAIgB,EAAO,CAAC,EACZ,KAAK,QAAQ,SAASrB,EAAOQ,EAAM,CACjCa,EAAK,KAAKb,CAAI,CAChB,CAAC,EACD,QAASC,EAAI,EAAGA,EAAIY,EAAK,OAAQZ,IAC/B,KAAK,OAAOY,EAAKZ,EAAE,CAEvB,CAEAJ,EAAeA,EAAa,QAAQ,MAAO,EAAE,EAG7C,QAFIiB,EAAajB,EAAa,MAAM,GAAG,EACnCkB,EACKd,EAAI,EAAGA,EAAIa,EAAW,OAAQb,IACrCc,EAAYD,EAAWb,GAAG,MAAM,GAAG,EACnC,KAAK,OACHP,EAAiBqB,EAAU,EAAE,EAC5BA,EAAU,OAAS,EAAKrB,EAAiBqB,EAAU,EAAE,EAAI,EAC5D,CAEJ,CACF,CAAC,CAKL,GACG,OAAO,QAAW,YAAe,OAC5B,OAAO,QAAW,YAAe,OACjC,OAAO,MAAS,YAAe,KAAO/B,EAC9C,GAEC,SAASC,EAAQ,CAOhB,IAAI+B,EAAwB,UAAW,CACrC,GAAI,CACF,IAAIC,EAAI,IAAIhC,EAAO,IAAI,IAAK,UAAU,EACtC,OAAAgC,EAAE,SAAW,MACLA,EAAE,OAAS,kBAAqBA,EAAE,YAC5C,OAASP,EAAP,CACA,MAAO,EACT,CACF,EAGIQ,EAAc,UAAW,CAC3B,IAAIC,EAAOlC,EAAO,IAEdmC,EAAM,SAASC,EAAKC,EAAM,CACxB,OAAOD,GAAQ,WAAUA,EAAM,OAAOA,CAAG,GACzCC,GAAQ,OAAOA,GAAS,WAAUA,EAAO,OAAOA,CAAI,GAGxD,IAAIC,EAAM,SAAUC,EACpB,GAAIF,IAASrC,EAAO,WAAa,QAAUqC,IAASrC,EAAO,SAAS,MAAO,CACzEqC,EAAOA,EAAK,YAAY,EACxBC,EAAM,SAAS,eAAe,mBAAmB,EAAE,EACnDC,EAAcD,EAAI,cAAc,MAAM,EACtCC,EAAY,KAAOF,EACnBC,EAAI,KAAK,YAAYC,CAAW,EAChC,GAAI,CACF,GAAIA,EAAY,KAAK,QAAQF,CAAI,IAAM,EAAG,MAAM,IAAI,MAAME,EAAY,IAAI,CAC5E,OAASC,EAAP,CACA,MAAM,IAAI,MAAM,0BAA4BH,EAAO,WAAaG,CAAG,CACrE,CACF,CAEA,IAAIC,EAAgBH,EAAI,cAAc,GAAG,EACzCG,EAAc,KAAOL,EACjBG,IACFD,EAAI,KAAK,YAAYG,CAAa,EAClCA,EAAc,KAAOA,EAAc,MAGrC,IAAIC,EAAeJ,EAAI,cAAc,OAAO,EAI5C,GAHAI,EAAa,KAAO,MACpBA,EAAa,MAAQN,EAEjBK,EAAc,WAAa,KAAO,CAAC,IAAI,KAAKA,EAAc,IAAI,GAAM,CAACC,EAAa,cAAc,GAAK,CAACL,EACxG,MAAM,IAAI,UAAU,aAAa,EAGnC,OAAO,eAAe,KAAM,iBAAkB,CAC5C,MAAOI,CACT,CAAC,EAID,IAAIE,EAAe,IAAI3C,EAAO,gBAAgB,KAAK,MAAM,EACrD4C,EAAqB,GACrBC,EAA2B,GAC3B/B,EAAQ,KACZ,CAAC,SAAU,SAAU,KAAK,EAAE,QAAQ,SAASgC,EAAY,CACvD,IAAIC,GAASJ,EAAaG,GAC1BH,EAAaG,GAAc,UAAW,CACpCC,GAAO,MAAMJ,EAAc,SAAS,EAChCC,IACFC,EAA2B,GAC3B/B,EAAM,OAAS6B,EAAa,SAAS,EACrCE,EAA2B,GAE/B,CACF,CAAC,EAED,OAAO,eAAe,KAAM,eAAgB,CAC1C,MAAOF,EACP,WAAY,EACd,CAAC,EAED,IAAIK,EAAS,OACb,OAAO,eAAe,KAAM,sBAAuB,CACjD,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,UAAW,CACZ,KAAK,SAAWA,IAClBA,EAAS,KAAK,OACVH,IACFD,EAAqB,GACrB,KAAK,aAAa,YAAY,KAAK,MAAM,EACzCA,EAAqB,IAG3B,CACF,CAAC,CACH,EAEIzB,EAAQgB,EAAI,UAEZc,EAA6B,SAASC,EAAe,CACvD,OAAO,eAAe/B,EAAO+B,EAAe,CAC1C,IAAK,UAAW,CACd,OAAO,KAAK,eAAeA,EAC7B,EACA,IAAK,SAAS3C,EAAO,CACnB,KAAK,eAAe2C,GAAiB3C,CACvC,EACA,WAAY,EACd,CAAC,CACH,EAEA,CAAC,OAAQ,OAAQ,WAAY,OAAQ,UAAU,EAC5C,QAAQ,SAAS2C,EAAe,CAC/BD,EAA2BC,CAAa,CAC1C,CAAC,EAEH,OAAO,eAAe/B,EAAO,SAAU,CACrC,IAAK,UAAW,CACd,OAAO,KAAK,eAAe,MAC7B,EACA,IAAK,SAASZ,EAAO,CACnB,KAAK,eAAe,OAAYA,EAChC,KAAK,oBAAoB,CAC3B,EACA,WAAY,EACd,CAAC,EAED,OAAO,iBAAiBY,EAAO,CAE7B,SAAY,CACV,IAAK,UAAW,CACd,IAAIL,EAAQ,KACZ,OAAO,UAAW,CAChB,OAAOA,EAAM,IACf,CACF,CACF,EAEA,KAAQ,CACN,IAAK,UAAW,CACd,OAAO,KAAK,eAAe,KAAK,QAAQ,MAAO,EAAE,CACnD,EACA,IAAK,SAASP,EAAO,CACnB,KAAK,eAAe,KAAOA,EAC3B,KAAK,oBAAoB,CAC3B,EACA,WAAY,EACd,EAEA,SAAY,CACV,IAAK,UAAW,CACd,OAAO,KAAK,eAAe,SAAS,QAAQ,SAAU,GAAG,CAC3D,EACA,IAAK,SAASA,EAAO,CACnB,KAAK,eAAe,SAAWA,CACjC,EACA,WAAY,EACd,EAEA,OAAU,CACR,IAAK,UAAW,CAEd,IAAI4C,EAAe,CAAE,QAAS,GAAI,SAAU,IAAK,OAAQ,EAAG,EAAE,KAAK,eAAe,UAI9EC,EAAkB,KAAK,eAAe,MAAQD,GAChD,KAAK,eAAe,OAAS,GAE/B,OAAO,KAAK,eAAe,SACzB,KACA,KAAK,eAAe,UACnBC,EAAmB,IAAM,KAAK,eAAe,KAAQ,GAC1D,EACA,WAAY,EACd,EAEA,SAAY,CACV,IAAK,UAAW,CACd,MAAO,EACT,EACA,IAAK,SAAS7C,EAAO,CACrB,EACA,WAAY,EACd,EAEA,SAAY,CACV,IAAK,UAAW,CACd,MAAO,EACT,EACA,IAAK,SAASA,EAAO,CACrB,EACA,WAAY,EACd,CACF,CAAC,EAED4B,EAAI,gBAAkB,SAASkB,EAAM,CACnC,OAAOnB,EAAK,gBAAgB,MAAMA,EAAM,SAAS,CACnD,EAEAC,EAAI,gBAAkB,SAASC,EAAK,CAClC,OAAOF,EAAK,gBAAgB,MAAMA,EAAM,SAAS,CACnD,EAEAlC,EAAO,IAAMmC,CAEf,EAMA,GAJKJ,EAAsB,GACzBE,EAAY,EAGTjC,EAAO,WAAa,QAAW,EAAE,WAAYA,EAAO,UAAW,CAClE,IAAIsD,EAAY,UAAW,CACzB,OAAOtD,EAAO,SAAS,SAAW,KAAOA,EAAO,SAAS,UAAYA,EAAO,SAAS,KAAQ,IAAMA,EAAO,SAAS,KAAQ,GAC7H,EAEA,GAAI,CACF,OAAO,eAAeA,EAAO,SAAU,SAAU,CAC/C,IAAKsD,EACL,WAAY,EACd,CAAC,CACH,OAAS7B,EAAP,CACA,YAAY,UAAW,CACrBzB,EAAO,SAAS,OAASsD,EAAU,CACrC,EAAG,GAAG,CACR,CACF,CAEF,GACG,OAAO,QAAW,YAAe,OAC5B,OAAO,QAAW,YAAe,OACjC,OAAO,MAAS,YAAe,KAAOvD,EAC9C,IC5eA,IAAAwD,GAAAC,GAAA,CAAAC,GAAAC,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gFAeA,IAAIC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,GACAC,IACH,SAAUC,EAAS,CAChB,IAAIC,EAAO,OAAO,QAAW,SAAW,OAAS,OAAO,MAAS,SAAW,KAAO,OAAO,MAAS,SAAW,KAAO,CAAC,EAClH,OAAO,QAAW,YAAc,OAAO,IACvC,OAAO,QAAS,CAAC,SAAS,EAAG,SAAU3B,EAAS,CAAE0B,EAAQE,EAAeD,EAAMC,EAAe5B,CAAO,CAAC,CAAC,CAAG,CAAC,EAEtG,OAAOC,IAAW,UAAY,OAAOA,GAAO,SAAY,SAC7DyB,EAAQE,EAAeD,EAAMC,EAAe3B,GAAO,OAAO,CAAC,CAAC,EAG5DyB,EAAQE,EAAeD,CAAI,CAAC,EAEhC,SAASC,EAAe5B,EAAS6B,EAAU,CACvC,OAAI7B,IAAY2B,IACR,OAAO,OAAO,QAAW,WACzB,OAAO,eAAe3B,EAAS,aAAc,CAAE,MAAO,EAAK,CAAC,EAG5DA,EAAQ,WAAa,IAGtB,SAAU8B,EAAIC,EAAG,CAAE,OAAO/B,EAAQ8B,GAAMD,EAAWA,EAASC,EAAIC,CAAC,EAAIA,CAAG,CACnF,CACJ,GACC,SAAUC,EAAU,CACjB,IAAIC,EAAgB,OAAO,gBACtB,CAAE,UAAW,CAAC,CAAE,YAAa,OAAS,SAAUC,EAAGC,EAAG,CAAED,EAAE,UAAYC,CAAG,GAC1E,SAAUD,EAAGC,EAAG,CAAE,QAASC,KAAKD,EAAO,OAAO,UAAU,eAAe,KAAKA,EAAGC,CAAC,IAAGF,EAAEE,GAAKD,EAAEC,GAAI,EAEpGlC,GAAY,SAAUgC,EAAGC,EAAG,CACxB,GAAI,OAAOA,GAAM,YAAcA,IAAM,KACjC,MAAM,IAAI,UAAU,uBAAyB,OAAOA,CAAC,EAAI,+BAA+B,EAC5FF,EAAcC,EAAGC,CAAC,EAClB,SAASE,GAAK,CAAE,KAAK,YAAcH,CAAG,CACtCA,EAAE,UAAYC,IAAM,KAAO,OAAO,OAAOA,CAAC,GAAKE,EAAG,UAAYF,EAAE,UAAW,IAAIE,EACnF,EAEAlC,GAAW,OAAO,QAAU,SAAUmC,EAAG,CACrC,QAASC,EAAG,EAAI,EAAGC,EAAI,UAAU,OAAQ,EAAIA,EAAG,IAAK,CACjDD,EAAI,UAAU,GACd,QAASH,KAAKG,EAAO,OAAO,UAAU,eAAe,KAAKA,EAAGH,CAAC,IAAGE,EAAEF,GAAKG,EAAEH,GAC9E,CACA,OAAOE,CACX,EAEAlC,GAAS,SAAUmC,EAAGE,EAAG,CACrB,IAAIH,EAAI,CAAC,EACT,QAASF,KAAKG,EAAO,OAAO,UAAU,eAAe,KAAKA,EAAGH,CAAC,GAAKK,EAAE,QAAQL,CAAC,EAAI,IAC9EE,EAAEF,GAAKG,EAAEH,IACb,GAAIG,GAAK,MAAQ,OAAO,OAAO,uBAA0B,WACrD,QAASG,EAAI,EAAGN,EAAI,OAAO,sBAAsBG,CAAC,EAAGG,EAAIN,EAAE,OAAQM,IAC3DD,EAAE,QAAQL,EAAEM,EAAE,EAAI,GAAK,OAAO,UAAU,qBAAqB,KAAKH,EAAGH,EAAEM,EAAE,IACzEJ,EAAEF,EAAEM,IAAMH,EAAEH,EAAEM,KAE1B,OAAOJ,CACX,EAEAjC,GAAa,SAAUsC,EAAYC,EAAQC,EAAKC,EAAM,CAClD,IAAIC,EAAI,UAAU,OAAQC,EAAID,EAAI,EAAIH,EAASE,IAAS,KAAOA,EAAO,OAAO,yBAAyBF,EAAQC,CAAG,EAAIC,EAAMZ,EAC3H,GAAI,OAAO,SAAY,UAAY,OAAO,QAAQ,UAAa,WAAYc,EAAI,QAAQ,SAASL,EAAYC,EAAQC,EAAKC,CAAI,MACxH,SAASJ,EAAIC,EAAW,OAAS,EAAGD,GAAK,EAAGA,KAASR,EAAIS,EAAWD,MAAIM,GAAKD,EAAI,EAAIb,EAAEc,CAAC,EAAID,EAAI,EAAIb,EAAEU,EAAQC,EAAKG,CAAC,EAAId,EAAEU,EAAQC,CAAG,IAAMG,GAChJ,OAAOD,EAAI,GAAKC,GAAK,OAAO,eAAeJ,EAAQC,EAAKG,CAAC,EAAGA,CAChE,EAEA1C,GAAU,SAAU2C,EAAYC,EAAW,CACvC,OAAO,SAAUN,EAAQC,EAAK,CAAEK,EAAUN,EAAQC,EAAKI,CAAU,CAAG,CACxE,EAEA1C,GAAa,SAAU4C,EAAaC,EAAe,CAC/C,GAAI,OAAO,SAAY,UAAY,OAAO,QAAQ,UAAa,WAAY,OAAO,QAAQ,SAASD,EAAaC,CAAa,CACjI,EAEA5C,GAAY,SAAU6C,EAASC,EAAYC,EAAGC,EAAW,CACrD,SAASC,EAAMC,EAAO,CAAE,OAAOA,aAAiBH,EAAIG,EAAQ,IAAIH,EAAE,SAAUI,EAAS,CAAEA,EAAQD,CAAK,CAAG,CAAC,CAAG,CAC3G,OAAO,IAAKH,IAAMA,EAAI,UAAU,SAAUI,EAASC,EAAQ,CACvD,SAASC,EAAUH,EAAO,CAAE,GAAI,CAAEI,EAAKN,EAAU,KAAKE,CAAK,CAAC,CAAG,OAASjB,EAAP,CAAYmB,EAAOnB,CAAC,CAAG,CAAE,CAC1F,SAASsB,EAASL,EAAO,CAAE,GAAI,CAAEI,EAAKN,EAAU,MAASE,CAAK,CAAC,CAAG,OAASjB,EAAP,CAAYmB,EAAOnB,CAAC,CAAG,CAAE,CAC7F,SAASqB,EAAKE,EAAQ,CAAEA,EAAO,KAAOL,EAAQK,EAAO,KAAK,EAAIP,EAAMO,EAAO,KAAK,EAAE,KAAKH,EAAWE,CAAQ,CAAG,CAC7GD,GAAMN,EAAYA,EAAU,MAAMH,EAASC,GAAc,CAAC,CAAC,GAAG,KAAK,CAAC,CACxE,CAAC,CACL,EAEA7C,GAAc,SAAU4C,EAASY,EAAM,CACnC,IAAIC,EAAI,CAAE,MAAO,EAAG,KAAM,UAAW,CAAE,GAAI5B,EAAE,GAAK,EAAG,MAAMA,EAAE,GAAI,OAAOA,EAAE,EAAI,EAAG,KAAM,CAAC,EAAG,IAAK,CAAC,CAAE,EAAG6B,EAAGC,EAAG9B,EAAG+B,EAC/G,OAAOA,EAAI,CAAE,KAAMC,EAAK,CAAC,EAAG,MAASA,EAAK,CAAC,EAAG,OAAUA,EAAK,CAAC,CAAE,EAAG,OAAO,QAAW,aAAeD,EAAE,OAAO,UAAY,UAAW,CAAE,OAAO,IAAM,GAAIA,EACvJ,SAASC,EAAK9B,EAAG,CAAE,OAAO,SAAUT,EAAG,CAAE,OAAO+B,EAAK,CAACtB,EAAGT,CAAC,CAAC,CAAG,CAAG,CACjE,SAAS+B,EAAKS,EAAI,CACd,GAAIJ,EAAG,MAAM,IAAI,UAAU,iCAAiC,EAC5D,KAAOD,GAAG,GAAI,CACV,GAAIC,EAAI,EAAGC,IAAM9B,EAAIiC,EAAG,GAAK,EAAIH,EAAE,OAAYG,EAAG,GAAKH,EAAE,SAAc9B,EAAI8B,EAAE,SAAc9B,EAAE,KAAK8B,CAAC,EAAG,GAAKA,EAAE,OAAS,EAAE9B,EAAIA,EAAE,KAAK8B,EAAGG,EAAG,EAAE,GAAG,KAAM,OAAOjC,EAE3J,OADI8B,EAAI,EAAG9B,IAAGiC,EAAK,CAACA,EAAG,GAAK,EAAGjC,EAAE,KAAK,GAC9BiC,EAAG,QACF,OAAQ,GAAGjC,EAAIiC,EAAI,UACnB,GAAG,OAAAL,EAAE,QAAgB,CAAE,MAAOK,EAAG,GAAI,KAAM,EAAM,MACjD,GAAGL,EAAE,QAASE,EAAIG,EAAG,GAAIA,EAAK,CAAC,CAAC,EAAG,aACnC,GAAGA,EAAKL,EAAE,IAAI,IAAI,EAAGA,EAAE,KAAK,IAAI,EAAG,iBAEpC,GAAM5B,EAAI4B,EAAE,KAAM,EAAA5B,EAAIA,EAAE,OAAS,GAAKA,EAAEA,EAAE,OAAS,MAAQiC,EAAG,KAAO,GAAKA,EAAG,KAAO,GAAI,CAAEL,EAAI,EAAG,QAAU,CAC3G,GAAIK,EAAG,KAAO,IAAM,CAACjC,GAAMiC,EAAG,GAAKjC,EAAE,IAAMiC,EAAG,GAAKjC,EAAE,IAAM,CAAE4B,EAAE,MAAQK,EAAG,GAAI,KAAO,CACrF,GAAIA,EAAG,KAAO,GAAKL,EAAE,MAAQ5B,EAAE,GAAI,CAAE4B,EAAE,MAAQ5B,EAAE,GAAIA,EAAIiC,EAAI,KAAO,CACpE,GAAIjC,GAAK4B,EAAE,MAAQ5B,EAAE,GAAI,CAAE4B,EAAE,MAAQ5B,EAAE,GAAI4B,EAAE,IAAI,KAAKK,CAAE,EAAG,KAAO,CAC9DjC,EAAE,IAAI4B,EAAE,IAAI,IAAI,EACpBA,EAAE,KAAK,IAAI,EAAG,SAEtBK,EAAKN,EAAK,KAAKZ,EAASa,CAAC,CAC7B,OAASzB,EAAP,CAAY8B,EAAK,CAAC,EAAG9B,CAAC,EAAG2B,EAAI,CAAG,QAAE,CAAUD,EAAI7B,EAAI,CAAG,CACzD,GAAIiC,EAAG,GAAK,EAAG,MAAMA,EAAG,GAAI,MAAO,CAAE,MAAOA,EAAG,GAAKA,EAAG,GAAK,OAAQ,KAAM,EAAK,CACnF,CACJ,EAEA7D,GAAe,SAAS8D,EAAG,EAAG,CAC1B,QAASpC,KAAKoC,EAAOpC,IAAM,WAAa,CAAC,OAAO,UAAU,eAAe,KAAK,EAAGA,CAAC,GAAGX,GAAgB,EAAG+C,EAAGpC,CAAC,CAChH,EAEAX,GAAkB,OAAO,OAAU,SAASgD,EAAGD,EAAGE,EAAGC,EAAI,CACjDA,IAAO,SAAWA,EAAKD,GAC3B,OAAO,eAAeD,EAAGE,EAAI,CAAE,WAAY,GAAM,IAAK,UAAW,CAAE,OAAOH,EAAEE,EAAI,CAAE,CAAC,CACvF,EAAM,SAASD,EAAGD,EAAGE,EAAGC,EAAI,CACpBA,IAAO,SAAWA,EAAKD,GAC3BD,EAAEE,GAAMH,EAAEE,EACd,EAEA/D,GAAW,SAAU8D,EAAG,CACpB,IAAIlC,EAAI,OAAO,QAAW,YAAc,OAAO,SAAUiC,EAAIjC,GAAKkC,EAAElC,GAAIG,EAAI,EAC5E,GAAI8B,EAAG,OAAOA,EAAE,KAAKC,CAAC,EACtB,GAAIA,GAAK,OAAOA,EAAE,QAAW,SAAU,MAAO,CAC1C,KAAM,UAAY,CACd,OAAIA,GAAK/B,GAAK+B,EAAE,SAAQA,EAAI,QACrB,CAAE,MAAOA,GAAKA,EAAE/B,KAAM,KAAM,CAAC+B,CAAE,CAC1C,CACJ,EACA,MAAM,IAAI,UAAUlC,EAAI,0BAA4B,iCAAiC,CACzF,EAEA3B,GAAS,SAAU6D,EAAGjC,EAAG,CACrB,IAAIgC,EAAI,OAAO,QAAW,YAAcC,EAAE,OAAO,UACjD,GAAI,CAACD,EAAG,OAAOC,EACf,IAAI/B,EAAI8B,EAAE,KAAKC,CAAC,EAAGzB,EAAG4B,EAAK,CAAC,EAAGnC,EAC/B,GAAI,CACA,MAAQD,IAAM,QAAUA,KAAM,IAAM,EAAEQ,EAAIN,EAAE,KAAK,GAAG,MAAMkC,EAAG,KAAK5B,EAAE,KAAK,CAC7E,OACO6B,EAAP,CAAgBpC,EAAI,CAAE,MAAOoC,CAAM,CAAG,QACtC,CACI,GAAI,CACI7B,GAAK,CAACA,EAAE,OAASwB,EAAI9B,EAAE,SAAY8B,EAAE,KAAK9B,CAAC,CACnD,QACA,CAAU,GAAID,EAAG,MAAMA,EAAE,KAAO,CACpC,CACA,OAAOmC,CACX,EAGA/D,GAAW,UAAY,CACnB,QAAS+D,EAAK,CAAC,EAAGlC,EAAI,EAAGA,EAAI,UAAU,OAAQA,IAC3CkC,EAAKA,EAAG,OAAOhE,GAAO,UAAU8B,EAAE,CAAC,EACvC,OAAOkC,CACX,EAGA9D,GAAiB,UAAY,CACzB,QAASyB,EAAI,EAAGG,EAAI,EAAGoC,EAAK,UAAU,OAAQpC,EAAIoC,EAAIpC,IAAKH,GAAK,UAAUG,GAAG,OAC7E,QAASM,EAAI,MAAMT,CAAC,EAAGmC,EAAI,EAAGhC,EAAI,EAAGA,EAAIoC,EAAIpC,IACzC,QAASqC,EAAI,UAAUrC,GAAIsC,EAAI,EAAGC,EAAKF,EAAE,OAAQC,EAAIC,EAAID,IAAKN,IAC1D1B,EAAE0B,GAAKK,EAAEC,GACjB,OAAOhC,CACX,EAEAjC,GAAgB,SAAUmE,EAAIC,EAAMC,EAAM,CACtC,GAAIA,GAAQ,UAAU,SAAW,EAAG,QAAS1C,EAAI,EAAG2C,EAAIF,EAAK,OAAQP,EAAIlC,EAAI2C,EAAG3C,KACxEkC,GAAM,EAAElC,KAAKyC,MACRP,IAAIA,EAAK,MAAM,UAAU,MAAM,KAAKO,EAAM,EAAGzC,CAAC,GACnDkC,EAAGlC,GAAKyC,EAAKzC,IAGrB,OAAOwC,EAAG,OAAON,GAAM,MAAM,UAAU,MAAM,KAAKO,CAAI,CAAC,CAC3D,EAEAnE,GAAU,SAAUe,EAAG,CACnB,OAAO,gBAAgBf,IAAW,KAAK,EAAIe,EAAG,MAAQ,IAAIf,GAAQe,CAAC,CACvE,EAEAd,GAAmB,SAAUoC,EAASC,EAAYE,EAAW,CACzD,GAAI,CAAC,OAAO,cAAe,MAAM,IAAI,UAAU,sCAAsC,EACrF,IAAIa,EAAIb,EAAU,MAAMH,EAASC,GAAc,CAAC,CAAC,EAAGZ,EAAG4C,EAAI,CAAC,EAC5D,OAAO5C,EAAI,CAAC,EAAG4B,EAAK,MAAM,EAAGA,EAAK,OAAO,EAAGA,EAAK,QAAQ,EAAG5B,EAAE,OAAO,eAAiB,UAAY,CAAE,OAAO,IAAM,EAAGA,EACpH,SAAS4B,EAAK9B,EAAG,CAAM6B,EAAE7B,KAAIE,EAAEF,GAAK,SAAUT,EAAG,CAAE,OAAO,IAAI,QAAQ,SAAUgD,EAAG5C,EAAG,CAAEmD,EAAE,KAAK,CAAC9C,EAAGT,EAAGgD,EAAG5C,CAAC,CAAC,EAAI,GAAKoD,EAAO/C,EAAGT,CAAC,CAAG,CAAC,CAAG,EAAG,CACzI,SAASwD,EAAO/C,EAAGT,EAAG,CAAE,GAAI,CAAE+B,EAAKO,EAAE7B,GAAGT,CAAC,CAAC,CAAG,OAASU,EAAP,CAAY+C,EAAOF,EAAE,GAAG,GAAI7C,CAAC,CAAG,CAAE,CACjF,SAASqB,EAAKd,EAAG,CAAEA,EAAE,iBAAiBhC,GAAU,QAAQ,QAAQgC,EAAE,MAAM,CAAC,EAAE,KAAKyC,EAAS7B,CAAM,EAAI4B,EAAOF,EAAE,GAAG,GAAItC,CAAC,CAAI,CACxH,SAASyC,EAAQ/B,EAAO,CAAE6B,EAAO,OAAQ7B,CAAK,CAAG,CACjD,SAASE,EAAOF,EAAO,CAAE6B,EAAO,QAAS7B,CAAK,CAAG,CACjD,SAAS8B,EAAOrB,EAAGpC,EAAG,CAAMoC,EAAEpC,CAAC,EAAGuD,EAAE,MAAM,EAAGA,EAAE,QAAQC,EAAOD,EAAE,GAAG,GAAIA,EAAE,GAAG,EAAE,CAAG,CACrF,EAEApE,GAAmB,SAAUuD,EAAG,CAC5B,IAAI/B,EAAGN,EACP,OAAOM,EAAI,CAAC,EAAG4B,EAAK,MAAM,EAAGA,EAAK,QAAS,SAAU7B,EAAG,CAAE,MAAMA,CAAG,CAAC,EAAG6B,EAAK,QAAQ,EAAG5B,EAAE,OAAO,UAAY,UAAY,CAAE,OAAO,IAAM,EAAGA,EAC1I,SAAS4B,EAAK9B,EAAG2B,EAAG,CAAEzB,EAAEF,GAAKiC,EAAEjC,GAAK,SAAUT,EAAG,CAAE,OAAQK,EAAI,CAACA,GAAK,CAAE,MAAOpB,GAAQyD,EAAEjC,GAAGT,CAAC,CAAC,EAAG,KAAMS,IAAM,QAAS,EAAI2B,EAAIA,EAAEpC,CAAC,EAAIA,CAAG,EAAIoC,CAAG,CAClJ,EAEAhD,GAAgB,SAAUsD,EAAG,CACzB,GAAI,CAAC,OAAO,cAAe,MAAM,IAAI,UAAU,sCAAsC,EACrF,IAAID,EAAIC,EAAE,OAAO,eAAgB,EACjC,OAAOD,EAAIA,EAAE,KAAKC,CAAC,GAAKA,EAAI,OAAO9D,IAAa,WAAaA,GAAS8D,CAAC,EAAIA,EAAE,OAAO,UAAU,EAAG,EAAI,CAAC,EAAGH,EAAK,MAAM,EAAGA,EAAK,OAAO,EAAGA,EAAK,QAAQ,EAAG,EAAE,OAAO,eAAiB,UAAY,CAAE,OAAO,IAAM,EAAG,GAC9M,SAASA,EAAK9B,EAAG,CAAE,EAAEA,GAAKiC,EAAEjC,IAAM,SAAUT,EAAG,CAAE,OAAO,IAAI,QAAQ,SAAU4B,EAASC,EAAQ,CAAE7B,EAAI0C,EAAEjC,GAAGT,CAAC,EAAGyD,EAAO7B,EAASC,EAAQ7B,EAAE,KAAMA,EAAE,KAAK,CAAG,CAAC,CAAG,CAAG,CAC/J,SAASyD,EAAO7B,EAASC,EAAQ1B,EAAGH,EAAG,CAAE,QAAQ,QAAQA,CAAC,EAAE,KAAK,SAASA,EAAG,CAAE4B,EAAQ,CAAE,MAAO5B,EAAG,KAAMG,CAAE,CAAC,CAAG,EAAG0B,CAAM,CAAG,CAC/H,EAEAxC,GAAuB,SAAUsE,EAAQC,EAAK,CAC1C,OAAI,OAAO,eAAkB,OAAO,eAAeD,EAAQ,MAAO,CAAE,MAAOC,CAAI,CAAC,EAAYD,EAAO,IAAMC,EAClGD,CACX,EAEA,IAAIE,EAAqB,OAAO,OAAU,SAASnB,EAAG1C,EAAG,CACrD,OAAO,eAAe0C,EAAG,UAAW,CAAE,WAAY,GAAM,MAAO1C,CAAE,CAAC,CACtE,EAAK,SAAS0C,EAAG1C,EAAG,CAChB0C,EAAE,QAAa1C,CACnB,EAEAV,GAAe,SAAUwE,EAAK,CAC1B,GAAIA,GAAOA,EAAI,WAAY,OAAOA,EAClC,IAAI7B,EAAS,CAAC,EACd,GAAI6B,GAAO,KAAM,QAASnB,KAAKmB,EAASnB,IAAM,WAAa,OAAO,UAAU,eAAe,KAAKmB,EAAKnB,CAAC,GAAGjD,GAAgBuC,EAAQ6B,EAAKnB,CAAC,EACvI,OAAAkB,EAAmB5B,EAAQ6B,CAAG,EACvB7B,CACX,EAEA1C,GAAkB,SAAUuE,EAAK,CAC7B,OAAQA,GAAOA,EAAI,WAAcA,EAAM,CAAE,QAAWA,CAAI,CAC5D,EAEAtE,GAAyB,SAAUuE,EAAUC,EAAOC,EAAM7B,EAAG,CACzD,GAAI6B,IAAS,KAAO,CAAC7B,EAAG,MAAM,IAAI,UAAU,+CAA+C,EAC3F,GAAI,OAAO4B,GAAU,WAAaD,IAAaC,GAAS,CAAC5B,EAAI,CAAC4B,EAAM,IAAID,CAAQ,EAAG,MAAM,IAAI,UAAU,0EAA0E,EACjL,OAAOE,IAAS,IAAM7B,EAAI6B,IAAS,IAAM7B,EAAE,KAAK2B,CAAQ,EAAI3B,EAAIA,EAAE,MAAQ4B,EAAM,IAAID,CAAQ,CAChG,EAEAtE,GAAyB,SAAUsE,EAAUC,EAAOrC,EAAOsC,EAAM7B,EAAG,CAChE,GAAI6B,IAAS,IAAK,MAAM,IAAI,UAAU,gCAAgC,EACtE,GAAIA,IAAS,KAAO,CAAC7B,EAAG,MAAM,IAAI,UAAU,+CAA+C,EAC3F,GAAI,OAAO4B,GAAU,WAAaD,IAAaC,GAAS,CAAC5B,EAAI,CAAC4B,EAAM,IAAID,CAAQ,EAAG,MAAM,IAAI,UAAU,yEAAyE,EAChL,OAAQE,IAAS,IAAM7B,EAAE,KAAK2B,EAAUpC,CAAK,EAAIS,EAAIA,EAAE,MAAQT,EAAQqC,EAAM,IAAID,EAAUpC,CAAK,EAAIA,CACxG,EAEA1B,EAAS,YAAa9B,EAAS,EAC/B8B,EAAS,WAAY7B,EAAQ,EAC7B6B,EAAS,SAAU5B,EAAM,EACzB4B,EAAS,aAAc3B,EAAU,EACjC2B,EAAS,UAAW1B,EAAO,EAC3B0B,EAAS,aAAczB,EAAU,EACjCyB,EAAS,YAAaxB,EAAS,EAC/BwB,EAAS,cAAevB,EAAW,EACnCuB,EAAS,eAAgBtB,EAAY,EACrCsB,EAAS,kBAAmBP,EAAe,EAC3CO,EAAS,WAAYrB,EAAQ,EAC7BqB,EAAS,SAAUpB,EAAM,EACzBoB,EAAS,WAAYnB,EAAQ,EAC7BmB,EAAS,iBAAkBlB,EAAc,EACzCkB,EAAS,gBAAiBjB,EAAa,EACvCiB,EAAS,UAAWhB,EAAO,EAC3BgB,EAAS,mBAAoBf,EAAgB,EAC7Ce,EAAS,mBAAoBd,EAAgB,EAC7Cc,EAAS,gBAAiBb,EAAa,EACvCa,EAAS,uBAAwBZ,EAAoB,EACrDY,EAAS,eAAgBX,EAAY,EACrCW,EAAS,kBAAmBV,EAAe,EAC3CU,EAAS,yBAA0BT,EAAsB,EACzDS,EAAS,yBAA0BR,EAAsB,CAC7D,CAAC,ICjTD,IAAAyE,GAAAC,GAAA,CAAAC,GAAAC,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMC,SAA0CC,EAAMC,EAAS,CACtD,OAAOH,IAAY,UAAY,OAAOC,IAAW,SACnDA,GAAO,QAAUE,EAAQ,EAClB,OAAO,QAAW,YAAc,OAAO,IAC9C,OAAO,CAAC,EAAGA,CAAO,EACX,OAAOH,IAAY,SAC1BA,GAAQ,YAAiBG,EAAQ,EAEjCD,EAAK,YAAiBC,EAAQ,CAChC,GAAGH,GAAM,UAAW,CACpB,OAAiB,UAAW,CAClB,IAAII,EAAuB,CAE/B,IACC,SAASC,EAAyBC,EAAqBC,EAAqB,CAEnF,aAGAA,EAAoB,EAAED,EAAqB,CACzC,QAAW,UAAW,CAAE,OAAqBE,EAAW,CAC1D,CAAC,EAGD,IAAIC,EAAeF,EAAoB,GAAG,EACtCG,EAAoCH,EAAoB,EAAEE,CAAY,EAEtEE,EAASJ,EAAoB,GAAG,EAChCK,EAA8BL,EAAoB,EAAEI,CAAM,EAE1DE,EAAaN,EAAoB,GAAG,EACpCO,EAA8BP,EAAoB,EAAEM,CAAU,EAOlE,SAASE,EAAQC,EAAM,CACrB,GAAI,CACF,OAAO,SAAS,YAAYA,CAAI,CAClC,OAASC,EAAP,CACA,MAAO,EACT,CACF,CAUA,IAAIC,EAAqB,SAA4BC,EAAQ,CAC3D,IAAIC,EAAeN,EAAe,EAAEK,CAAM,EAC1C,OAAAJ,EAAQ,KAAK,EACNK,CACT,EAEiCC,EAAeH,EAOhD,SAASI,EAAkBC,EAAO,CAChC,IAAIC,EAAQ,SAAS,gBAAgB,aAAa,KAAK,IAAM,MACzDC,EAAc,SAAS,cAAc,UAAU,EAEnDA,EAAY,MAAM,SAAW,OAE7BA,EAAY,MAAM,OAAS,IAC3BA,EAAY,MAAM,QAAU,IAC5BA,EAAY,MAAM,OAAS,IAE3BA,EAAY,MAAM,SAAW,WAC7BA,EAAY,MAAMD,EAAQ,QAAU,QAAU,UAE9C,IAAIE,EAAY,OAAO,aAAe,SAAS,gBAAgB,UAC/D,OAAAD,EAAY,MAAM,IAAM,GAAG,OAAOC,EAAW,IAAI,EACjDD,EAAY,aAAa,WAAY,EAAE,EACvCA,EAAY,MAAQF,EACbE,CACT,CAYA,IAAIE,EAAiB,SAAwBJ,EAAOK,EAAS,CAC3D,IAAIH,EAAcH,EAAkBC,CAAK,EACzCK,EAAQ,UAAU,YAAYH,CAAW,EACzC,IAAIL,EAAeN,EAAe,EAAEW,CAAW,EAC/C,OAAAV,EAAQ,MAAM,EACdU,EAAY,OAAO,EACZL,CACT,EASIS,EAAsB,SAA6BV,EAAQ,CAC7D,IAAIS,EAAU,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,CAChF,UAAW,SAAS,IACtB,EACIR,EAAe,GAEnB,OAAI,OAAOD,GAAW,SACpBC,EAAeO,EAAeR,EAAQS,CAAO,EACpCT,aAAkB,kBAAoB,CAAC,CAAC,OAAQ,SAAU,MAAO,MAAO,UAAU,EAAE,SAASA,GAAW,KAA4B,OAASA,EAAO,IAAI,EAEjKC,EAAeO,EAAeR,EAAO,MAAOS,CAAO,GAEnDR,EAAeN,EAAe,EAAEK,CAAM,EACtCJ,EAAQ,MAAM,GAGTK,CACT,EAEiCU,EAAgBD,EAEjD,SAASE,EAAQC,EAAK,CAA6B,OAAI,OAAO,QAAW,YAAc,OAAO,OAAO,UAAa,SAAYD,EAAU,SAAiBC,EAAK,CAAE,OAAO,OAAOA,CAAK,EAAYD,EAAU,SAAiBC,EAAK,CAAE,OAAOA,GAAO,OAAO,QAAW,YAAcA,EAAI,cAAgB,QAAUA,IAAQ,OAAO,UAAY,SAAW,OAAOA,CAAK,EAAYD,EAAQC,CAAG,CAAG,CAUzX,IAAIC,GAAyB,UAAkC,CAC7D,IAAIL,EAAU,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,CAAC,EAE/EM,EAAkBN,EAAQ,OAC1BO,EAASD,IAAoB,OAAS,OAASA,EAC/CE,EAAYR,EAAQ,UACpBT,EAASS,EAAQ,OACjBS,GAAOT,EAAQ,KAEnB,GAAIO,IAAW,QAAUA,IAAW,MAClC,MAAM,IAAI,MAAM,oDAAoD,EAItE,GAAIhB,IAAW,OACb,GAAIA,GAAUY,EAAQZ,CAAM,IAAM,UAAYA,EAAO,WAAa,EAAG,CACnE,GAAIgB,IAAW,QAAUhB,EAAO,aAAa,UAAU,EACrD,MAAM,IAAI,MAAM,mFAAmF,EAGrG,GAAIgB,IAAW,QAAUhB,EAAO,aAAa,UAAU,GAAKA,EAAO,aAAa,UAAU,GACxF,MAAM,IAAI,MAAM,uGAAwG,CAE5H,KACE,OAAM,IAAI,MAAM,6CAA6C,EAKjE,GAAIkB,GACF,OAAOP,EAAaO,GAAM,CACxB,UAAWD,CACb,CAAC,EAIH,GAAIjB,EACF,OAAOgB,IAAW,MAAQd,EAAYF,CAAM,EAAIW,EAAaX,EAAQ,CACnE,UAAWiB,CACb,CAAC,CAEL,EAEiCE,GAAmBL,GAEpD,SAASM,GAAiBP,EAAK,CAA6B,OAAI,OAAO,QAAW,YAAc,OAAO,OAAO,UAAa,SAAYO,GAAmB,SAAiBP,EAAK,CAAE,OAAO,OAAOA,CAAK,EAAYO,GAAmB,SAAiBP,EAAK,CAAE,OAAOA,GAAO,OAAO,QAAW,YAAcA,EAAI,cAAgB,QAAUA,IAAQ,OAAO,UAAY,SAAW,OAAOA,CAAK,EAAYO,GAAiBP,CAAG,CAAG,CAE7Z,SAASQ,GAAgBC,EAAUC,EAAa,CAAE,GAAI,EAAED,aAAoBC,GAAgB,MAAM,IAAI,UAAU,mCAAmC,CAAK,CAExJ,SAASC,GAAkBxB,EAAQyB,EAAO,CAAE,QAASC,EAAI,EAAGA,EAAID,EAAM,OAAQC,IAAK,CAAE,IAAIC,EAAaF,EAAMC,GAAIC,EAAW,WAAaA,EAAW,YAAc,GAAOA,EAAW,aAAe,GAAU,UAAWA,IAAYA,EAAW,SAAW,IAAM,OAAO,eAAe3B,EAAQ2B,EAAW,IAAKA,CAAU,CAAG,CAAE,CAE5T,SAASC,GAAaL,EAAaM,EAAYC,EAAa,CAAE,OAAID,GAAYL,GAAkBD,EAAY,UAAWM,CAAU,EAAOC,GAAaN,GAAkBD,EAAaO,CAAW,EAAUP,CAAa,CAEtN,SAASQ,GAAUC,EAAUC,EAAY,CAAE,GAAI,OAAOA,GAAe,YAAcA,IAAe,KAAQ,MAAM,IAAI,UAAU,oDAAoD,EAAKD,EAAS,UAAY,OAAO,OAAOC,GAAcA,EAAW,UAAW,CAAE,YAAa,CAAE,MAAOD,EAAU,SAAU,GAAM,aAAc,EAAK,CAAE,CAAC,EAAOC,GAAYC,GAAgBF,EAAUC,CAAU,CAAG,CAEhY,SAASC,GAAgBC,EAAGC,EAAG,CAAE,OAAAF,GAAkB,OAAO,gBAAkB,SAAyBC,EAAGC,EAAG,CAAE,OAAAD,EAAE,UAAYC,EAAUD,CAAG,EAAUD,GAAgBC,EAAGC,CAAC,CAAG,CAEzK,SAASC,GAAaC,EAAS,CAAE,IAAIC,EAA4BC,GAA0B,EAAG,OAAO,UAAgC,CAAE,IAAIC,EAAQC,GAAgBJ,CAAO,EAAGK,EAAQ,GAAIJ,EAA2B,CAAE,IAAIK,EAAYF,GAAgB,IAAI,EAAE,YAAaC,EAAS,QAAQ,UAAUF,EAAO,UAAWG,CAAS,CAAG,MAASD,EAASF,EAAM,MAAM,KAAM,SAAS,EAAK,OAAOI,GAA2B,KAAMF,CAAM,CAAG,CAAG,CAExa,SAASE,GAA2BC,EAAMC,EAAM,CAAE,OAAIA,IAAS3B,GAAiB2B,CAAI,IAAM,UAAY,OAAOA,GAAS,YAAsBA,EAAeC,GAAuBF,CAAI,CAAG,CAEzL,SAASE,GAAuBF,EAAM,CAAE,GAAIA,IAAS,OAAU,MAAM,IAAI,eAAe,2DAA2D,EAAK,OAAOA,CAAM,CAErK,SAASN,IAA4B,CAA0E,GAApE,OAAO,SAAY,aAAe,CAAC,QAAQ,WAA6B,QAAQ,UAAU,KAAM,MAAO,GAAO,GAAI,OAAO,OAAU,WAAY,MAAO,GAAM,GAAI,CAAE,YAAK,UAAU,SAAS,KAAK,QAAQ,UAAU,KAAM,CAAC,EAAG,UAAY,CAAC,CAAC,CAAC,EAAU,EAAM,OAASS,EAAP,CAAY,MAAO,EAAO,CAAE,CAEnU,SAASP,GAAgBP,EAAG,CAAE,OAAAO,GAAkB,OAAO,eAAiB,OAAO,eAAiB,SAAyBP,EAAG,CAAE,OAAOA,EAAE,WAAa,OAAO,eAAeA,CAAC,CAAG,EAAUO,GAAgBP,CAAC,CAAG,CAa5M,SAASe,GAAkBC,EAAQC,EAAS,CAC1C,IAAIC,EAAY,kBAAkB,OAAOF,CAAM,EAE/C,GAAI,EAACC,EAAQ,aAAaC,CAAS,EAInC,OAAOD,EAAQ,aAAaC,CAAS,CACvC,CAOA,IAAIC,GAAyB,SAAUC,EAAU,CAC/CxB,GAAUuB,EAAWC,CAAQ,EAE7B,IAAIC,EAASnB,GAAaiB,CAAS,EAMnC,SAASA,EAAUG,EAAShD,EAAS,CACnC,IAAIiD,EAEJ,OAAArC,GAAgB,KAAMiC,CAAS,EAE/BI,EAAQF,EAAO,KAAK,IAAI,EAExBE,EAAM,eAAejD,CAAO,EAE5BiD,EAAM,YAAYD,CAAO,EAElBC,CACT,CAQA,OAAA9B,GAAa0B,EAAW,CAAC,CACvB,IAAK,iBACL,MAAO,UAA0B,CAC/B,IAAI7C,EAAU,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,CAAC,EACnF,KAAK,OAAS,OAAOA,EAAQ,QAAW,WAAaA,EAAQ,OAAS,KAAK,cAC3E,KAAK,OAAS,OAAOA,EAAQ,QAAW,WAAaA,EAAQ,OAAS,KAAK,cAC3E,KAAK,KAAO,OAAOA,EAAQ,MAAS,WAAaA,EAAQ,KAAO,KAAK,YACrE,KAAK,UAAYW,GAAiBX,EAAQ,SAAS,IAAM,SAAWA,EAAQ,UAAY,SAAS,IACnG,CAMF,EAAG,CACD,IAAK,cACL,MAAO,SAAqBgD,EAAS,CACnC,IAAIE,EAAS,KAEb,KAAK,SAAWlE,EAAe,EAAEgE,EAAS,QAAS,SAAUR,GAAG,CAC9D,OAAOU,EAAO,QAAQV,EAAC,CACzB,CAAC,CACH,CAMF,EAAG,CACD,IAAK,UACL,MAAO,SAAiBA,EAAG,CACzB,IAAIQ,EAAUR,EAAE,gBAAkBA,EAAE,cAChCjC,GAAS,KAAK,OAAOyC,CAAO,GAAK,OACjCvC,GAAOC,GAAgB,CACzB,OAAQH,GACR,UAAW,KAAK,UAChB,OAAQ,KAAK,OAAOyC,CAAO,EAC3B,KAAM,KAAK,KAAKA,CAAO,CACzB,CAAC,EAED,KAAK,KAAKvC,GAAO,UAAY,QAAS,CACpC,OAAQF,GACR,KAAME,GACN,QAASuC,EACT,eAAgB,UAA0B,CACpCA,GACFA,EAAQ,MAAM,EAGhB,OAAO,aAAa,EAAE,gBAAgB,CACxC,CACF,CAAC,CACH,CAMF,EAAG,CACD,IAAK,gBACL,MAAO,SAAuBA,EAAS,CACrC,OAAOP,GAAkB,SAAUO,CAAO,CAC5C,CAMF,EAAG,CACD,IAAK,gBACL,MAAO,SAAuBA,EAAS,CACrC,IAAIG,EAAWV,GAAkB,SAAUO,CAAO,EAElD,GAAIG,EACF,OAAO,SAAS,cAAcA,CAAQ,CAE1C,CAQF,EAAG,CACD,IAAK,cAML,MAAO,SAAqBH,EAAS,CACnC,OAAOP,GAAkB,OAAQO,CAAO,CAC1C,CAKF,EAAG,CACD,IAAK,UACL,MAAO,UAAmB,CACxB,KAAK,SAAS,QAAQ,CACxB,CACF,CAAC,EAAG,CAAC,CACH,IAAK,OACL,MAAO,SAAczD,EAAQ,CAC3B,IAAIS,EAAU,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,CAChF,UAAW,SAAS,IACtB,EACA,OAAOE,EAAaX,EAAQS,CAAO,CACrC,CAOF,EAAG,CACD,IAAK,MACL,MAAO,SAAaT,EAAQ,CAC1B,OAAOE,EAAYF,CAAM,CAC3B,CAOF,EAAG,CACD,IAAK,cACL,MAAO,UAAuB,CAC5B,IAAIgB,EAAS,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,CAAC,OAAQ,KAAK,EAC3F6C,EAAU,OAAO7C,GAAW,SAAW,CAACA,CAAM,EAAIA,EAClD8C,GAAU,CAAC,CAAC,SAAS,sBACzB,OAAAD,EAAQ,QAAQ,SAAU7C,GAAQ,CAChC8C,GAAUA,IAAW,CAAC,CAAC,SAAS,sBAAsB9C,EAAM,CAC9D,CAAC,EACM8C,EACT,CACF,CAAC,CAAC,EAEKR,CACT,EAAG/D,EAAqB,CAAE,EAEOF,GAAaiE,EAExC,EAEA,IACC,SAASxE,EAAQ,CAExB,IAAIiF,EAAqB,EAKzB,GAAI,OAAO,SAAY,aAAe,CAAC,QAAQ,UAAU,QAAS,CAC9D,IAAIC,EAAQ,QAAQ,UAEpBA,EAAM,QAAUA,EAAM,iBACNA,EAAM,oBACNA,EAAM,mBACNA,EAAM,kBACNA,EAAM,qBAC1B,CASA,SAASC,EAASb,EAASQ,EAAU,CACjC,KAAOR,GAAWA,EAAQ,WAAaW,GAAoB,CACvD,GAAI,OAAOX,EAAQ,SAAY,YAC3BA,EAAQ,QAAQQ,CAAQ,EAC1B,OAAOR,EAETA,EAAUA,EAAQ,UACtB,CACJ,CAEAtE,EAAO,QAAUmF,CAGX,EAEA,IACC,SAASnF,EAAQoF,EAA0B9E,EAAqB,CAEvE,IAAI6E,EAAU7E,EAAoB,GAAG,EAYrC,SAAS+E,EAAUf,EAASQ,EAAU/D,EAAMuE,EAAUC,EAAY,CAC9D,IAAIC,EAAaC,EAAS,MAAM,KAAM,SAAS,EAE/C,OAAAnB,EAAQ,iBAAiBvD,EAAMyE,EAAYD,CAAU,EAE9C,CACH,QAAS,UAAW,CAChBjB,EAAQ,oBAAoBvD,EAAMyE,EAAYD,CAAU,CAC5D,CACJ,CACJ,CAYA,SAASG,EAASC,EAAUb,EAAU/D,EAAMuE,EAAUC,EAAY,CAE9D,OAAI,OAAOI,EAAS,kBAAqB,WAC9BN,EAAU,MAAM,KAAM,SAAS,EAItC,OAAOtE,GAAS,WAGTsE,EAAU,KAAK,KAAM,QAAQ,EAAE,MAAM,KAAM,SAAS,GAI3D,OAAOM,GAAa,WACpBA,EAAW,SAAS,iBAAiBA,CAAQ,GAI1C,MAAM,UAAU,IAAI,KAAKA,EAAU,SAAUrB,EAAS,CACzD,OAAOe,EAAUf,EAASQ,EAAU/D,EAAMuE,EAAUC,CAAU,CAClE,CAAC,EACL,CAWA,SAASE,EAASnB,EAASQ,EAAU/D,EAAMuE,EAAU,CACjD,OAAO,SAASnB,EAAG,CACfA,EAAE,eAAiBgB,EAAQhB,EAAE,OAAQW,CAAQ,EAEzCX,EAAE,gBACFmB,EAAS,KAAKhB,EAASH,CAAC,CAEhC,CACJ,CAEAnE,EAAO,QAAU0F,CAGX,EAEA,IACC,SAAStF,EAAyBL,EAAS,CAQlDA,EAAQ,KAAO,SAASuB,EAAO,CAC3B,OAAOA,IAAU,QACVA,aAAiB,aACjBA,EAAM,WAAa,CAC9B,EAQAvB,EAAQ,SAAW,SAASuB,EAAO,CAC/B,IAAIP,EAAO,OAAO,UAAU,SAAS,KAAKO,CAAK,EAE/C,OAAOA,IAAU,SACTP,IAAS,qBAAuBA,IAAS,4BACzC,WAAYO,IACZA,EAAM,SAAW,GAAKvB,EAAQ,KAAKuB,EAAM,EAAE,EACvD,EAQAvB,EAAQ,OAAS,SAASuB,EAAO,CAC7B,OAAO,OAAOA,GAAU,UACjBA,aAAiB,MAC5B,EAQAvB,EAAQ,GAAK,SAASuB,EAAO,CACzB,IAAIP,EAAO,OAAO,UAAU,SAAS,KAAKO,CAAK,EAE/C,OAAOP,IAAS,mBACpB,CAGM,EAEA,IACC,SAASf,EAAQoF,EAA0B9E,EAAqB,CAEvE,IAAIsF,EAAKtF,EAAoB,GAAG,EAC5BoF,EAAWpF,EAAoB,GAAG,EAWtC,SAASI,EAAOQ,EAAQH,EAAMuE,EAAU,CACpC,GAAI,CAACpE,GAAU,CAACH,GAAQ,CAACuE,EACrB,MAAM,IAAI,MAAM,4BAA4B,EAGhD,GAAI,CAACM,EAAG,OAAO7E,CAAI,EACf,MAAM,IAAI,UAAU,kCAAkC,EAG1D,GAAI,CAAC6E,EAAG,GAAGN,CAAQ,EACf,MAAM,IAAI,UAAU,mCAAmC,EAG3D,GAAIM,EAAG,KAAK1E,CAAM,EACd,OAAO2E,EAAW3E,EAAQH,EAAMuE,CAAQ,EAEvC,GAAIM,EAAG,SAAS1E,CAAM,EACvB,OAAO4E,EAAe5E,EAAQH,EAAMuE,CAAQ,EAE3C,GAAIM,EAAG,OAAO1E,CAAM,EACrB,OAAO6E,EAAe7E,EAAQH,EAAMuE,CAAQ,EAG5C,MAAM,IAAI,UAAU,2EAA2E,CAEvG,CAWA,SAASO,EAAWG,EAAMjF,EAAMuE,EAAU,CACtC,OAAAU,EAAK,iBAAiBjF,EAAMuE,CAAQ,EAE7B,CACH,QAAS,UAAW,CAChBU,EAAK,oBAAoBjF,EAAMuE,CAAQ,CAC3C,CACJ,CACJ,CAWA,SAASQ,EAAeG,EAAUlF,EAAMuE,EAAU,CAC9C,aAAM,UAAU,QAAQ,KAAKW,EAAU,SAASD,EAAM,CAClDA,EAAK,iBAAiBjF,EAAMuE,CAAQ,CACxC,CAAC,EAEM,CACH,QAAS,UAAW,CAChB,MAAM,UAAU,QAAQ,KAAKW,EAAU,SAASD,EAAM,CAClDA,EAAK,oBAAoBjF,EAAMuE,CAAQ,CAC3C,CAAC,CACL,CACJ,CACJ,CAWA,SAASS,EAAejB,EAAU/D,EAAMuE,EAAU,CAC9C,OAAOI,EAAS,SAAS,KAAMZ,EAAU/D,EAAMuE,CAAQ,CAC3D,CAEAtF,EAAO,QAAUU,CAGX,EAEA,IACC,SAASV,EAAQ,CAExB,SAASkG,EAAO5B,EAAS,CACrB,IAAInD,EAEJ,GAAImD,EAAQ,WAAa,SACrBA,EAAQ,MAAM,EAEdnD,EAAemD,EAAQ,cAElBA,EAAQ,WAAa,SAAWA,EAAQ,WAAa,WAAY,CACtE,IAAI6B,EAAa7B,EAAQ,aAAa,UAAU,EAE3C6B,GACD7B,EAAQ,aAAa,WAAY,EAAE,EAGvCA,EAAQ,OAAO,EACfA,EAAQ,kBAAkB,EAAGA,EAAQ,MAAM,MAAM,EAE5C6B,GACD7B,EAAQ,gBAAgB,UAAU,EAGtCnD,EAAemD,EAAQ,KAC3B,KACK,CACGA,EAAQ,aAAa,iBAAiB,GACtCA,EAAQ,MAAM,EAGlB,IAAI8B,EAAY,OAAO,aAAa,EAChCC,EAAQ,SAAS,YAAY,EAEjCA,EAAM,mBAAmB/B,CAAO,EAChC8B,EAAU,gBAAgB,EAC1BA,EAAU,SAASC,CAAK,EAExBlF,EAAeiF,EAAU,SAAS,CACtC,CAEA,OAAOjF,CACX,CAEAnB,EAAO,QAAUkG,CAGX,EAEA,IACC,SAASlG,EAAQ,CAExB,SAASsG,GAAK,CAGd,CAEAA,EAAE,UAAY,CACZ,GAAI,SAAUC,EAAMjB,EAAUkB,EAAK,CACjC,IAAIrC,EAAI,KAAK,IAAM,KAAK,EAAI,CAAC,GAE7B,OAACA,EAAEoC,KAAUpC,EAAEoC,GAAQ,CAAC,IAAI,KAAK,CAC/B,GAAIjB,EACJ,IAAKkB,CACP,CAAC,EAEM,IACT,EAEA,KAAM,SAAUD,EAAMjB,EAAUkB,EAAK,CACnC,IAAIxC,EAAO,KACX,SAASyB,GAAY,CACnBzB,EAAK,IAAIuC,EAAMd,CAAQ,EACvBH,EAAS,MAAMkB,EAAK,SAAS,CAC/B,CAEA,OAAAf,EAAS,EAAIH,EACN,KAAK,GAAGiB,EAAMd,EAAUe,CAAG,CACpC,EAEA,KAAM,SAAUD,EAAM,CACpB,IAAIE,EAAO,CAAC,EAAE,MAAM,KAAK,UAAW,CAAC,EACjCC,IAAW,KAAK,IAAM,KAAK,EAAI,CAAC,IAAIH,IAAS,CAAC,GAAG,MAAM,EACvD3D,EAAI,EACJ+D,EAAMD,EAAO,OAEjB,IAAK9D,EAAGA,EAAI+D,EAAK/D,IACf8D,EAAO9D,GAAG,GAAG,MAAM8D,EAAO9D,GAAG,IAAK6D,CAAI,EAGxC,OAAO,IACT,EAEA,IAAK,SAAUF,EAAMjB,EAAU,CAC7B,IAAInB,EAAI,KAAK,IAAM,KAAK,EAAI,CAAC,GACzByC,EAAOzC,EAAEoC,GACTM,EAAa,CAAC,EAElB,GAAID,GAAQtB,EACV,QAAS1C,EAAI,EAAG+D,EAAMC,EAAK,OAAQhE,EAAI+D,EAAK/D,IACtCgE,EAAKhE,GAAG,KAAO0C,GAAYsB,EAAKhE,GAAG,GAAG,IAAM0C,GAC9CuB,EAAW,KAAKD,EAAKhE,EAAE,EAQ7B,OAACiE,EAAW,OACR1C,EAAEoC,GAAQM,EACV,OAAO1C,EAAEoC,GAEN,IACT,CACF,EAEAvG,EAAO,QAAUsG,EACjBtG,EAAO,QAAQ,YAAcsG,CAGvB,CAEI,EAGIQ,EAA2B,CAAC,EAGhC,SAASxG,EAAoByG,EAAU,CAEtC,GAAGD,EAAyBC,GAC3B,OAAOD,EAAyBC,GAAU,QAG3C,IAAI/G,EAAS8G,EAAyBC,GAAY,CAGjD,QAAS,CAAC,CACX,EAGA,OAAA5G,EAAoB4G,GAAU/G,EAAQA,EAAO,QAASM,CAAmB,EAGlEN,EAAO,OACf,CAIA,OAAC,UAAW,CAEXM,EAAoB,EAAI,SAASN,EAAQ,CACxC,IAAIgH,EAAShH,GAAUA,EAAO,WAC7B,UAAW,CAAE,OAAOA,EAAO,OAAY,EACvC,UAAW,CAAE,OAAOA,CAAQ,EAC7B,OAAAM,EAAoB,EAAE0G,EAAQ,CAAE,EAAGA,CAAO,CAAC,EACpCA,CACR,CACD,EAAE,EAGD,UAAW,CAEX1G,EAAoB,EAAI,SAASP,EAASkH,EAAY,CACrD,QAAQC,KAAOD,EACX3G,EAAoB,EAAE2G,EAAYC,CAAG,GAAK,CAAC5G,EAAoB,EAAEP,EAASmH,CAAG,GAC/E,OAAO,eAAenH,EAASmH,EAAK,CAAE,WAAY,GAAM,IAAKD,EAAWC,EAAK,CAAC,CAGjF,CACD,EAAE,EAGD,UAAW,CACX5G,EAAoB,EAAI,SAASyB,EAAKoF,EAAM,CAAE,OAAO,OAAO,UAAU,eAAe,KAAKpF,EAAKoF,CAAI,CAAG,CACvG,EAAE,EAMK7G,EAAoB,GAAG,CAC/B,EAAG,EACX,OACD,CAAC,ICz3BD,IAAA8G,GAAAC,GAAA,CAAAC,GAAAC,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAeA,IAAIC,GAAkB,UAOtBD,GAAO,QAAUE,GAUjB,SAASA,GAAWC,EAAQ,CAC1B,IAAIC,EAAM,GAAKD,EACXE,EAAQJ,GAAgB,KAAKG,CAAG,EAEpC,GAAI,CAACC,EACH,OAAOD,EAGT,IAAIE,EACAC,EAAO,GACPC,EAAQ,EACRC,EAAY,EAEhB,IAAKD,EAAQH,EAAM,MAAOG,EAAQJ,EAAI,OAAQI,IAAS,CACrD,OAAQJ,EAAI,WAAWI,CAAK,OACrB,IACHF,EAAS,SACT,UACG,IACHA,EAAS,QACT,UACG,IACHA,EAAS,QACT,UACG,IACHA,EAAS,OACT,UACG,IACHA,EAAS,OACT,cAEA,SAGAG,IAAcD,IAChBD,GAAQH,EAAI,UAAUK,EAAWD,CAAK,GAGxCC,EAAYD,EAAQ,EACpBD,GAAQD,CACV,CAEA,OAAOG,IAAcD,EACjBD,EAAOH,EAAI,UAAUK,EAAWD,CAAK,EACrCD,CACN,IC7EA,MAAM,UAAU,MAAM,OAAO,eAAe,MAAM,UAAU,OAAO,CAAC,aAAa,GAAG,MAAM,SAASG,GAAG,CAAC,IAAI,EAAE,MAAM,UAAU,EAAE,EAAE,EAAE,OAAO,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,UAAU,OAAO,KAAK,KAAK,SAASC,EAAEC,EAAE,CAAC,OAAO,MAAM,QAAQA,CAAC,EAAED,EAAE,KAAK,MAAMA,EAAED,EAAE,KAAKE,EAAE,EAAE,CAAC,CAAC,EAAED,EAAE,KAAKC,CAAC,EAAED,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,UAAU,MAAM,KAAK,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,UAAU,SAAS,OAAO,eAAe,MAAM,UAAU,UAAU,CAAC,aAAa,GAAG,MAAM,SAASD,EAAE,CAAC,OAAO,MAAM,UAAU,IAAI,MAAM,KAAK,SAAS,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,ECuBxf,IAAAG,GAAO,SCvBP,KAAK,QAAQ,KAAK,MAAM,SAAS,EAAEC,EAAE,CAAC,OAAOA,EAAEA,GAAG,CAAC,EAAE,IAAI,QAAQ,SAASC,EAAEC,EAAE,CAAC,IAAIC,EAAE,IAAI,eAAeC,EAAE,CAAC,EAAEC,EAAE,CAAC,EAAEC,EAAE,CAAC,EAAEC,EAAE,UAAU,CAAC,MAAM,CAAC,IAAOJ,EAAE,OAAO,IAAI,IAAjB,EAAoB,WAAWA,EAAE,WAAW,OAAOA,EAAE,OAAO,IAAIA,EAAE,YAAY,KAAK,UAAU,CAAC,OAAO,QAAQ,QAAQA,EAAE,YAAY,CAAC,EAAE,KAAK,UAAU,CAAC,OAAO,QAAQ,QAAQA,EAAE,YAAY,EAAE,KAAK,KAAK,KAAK,CAAC,EAAE,KAAK,UAAU,CAAC,OAAO,QAAQ,QAAQ,IAAI,KAAK,CAACA,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAMI,EAAE,QAAQ,CAAC,KAAK,UAAU,CAAC,OAAOH,CAAC,EAAE,QAAQ,UAAU,CAAC,OAAOC,CAAC,EAAE,IAAI,SAASG,EAAE,CAAC,OAAOF,EAAEE,EAAE,YAAY,EAAE,EAAE,IAAI,SAASA,EAAE,CAAC,OAAOA,EAAE,YAAY,IAAIF,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQG,KAAKN,EAAE,KAAKH,EAAE,QAAQ,MAAM,EAAE,EAAE,EAAEG,EAAE,OAAO,UAAU,CAACA,EAAE,sBAAsB,EAAE,QAAQ,+BAA+B,SAASK,EAAER,EAAEC,EAAE,CAACG,EAAE,KAAKJ,EAAEA,EAAE,YAAY,CAAC,EAAEK,EAAE,KAAK,CAACL,EAAEC,CAAC,CAAC,EAAEK,EAAEN,GAAGM,EAAEN,GAAGM,EAAEN,GAAG,IAAIC,EAAEA,CAAC,CAAC,EAAEA,EAAEM,EAAE,CAAC,CAAC,EAAEJ,EAAE,QAAQD,EAAEC,EAAE,gBAA2BH,EAAE,aAAb,UAAyBA,EAAE,QAAQG,EAAE,iBAAiBM,EAAET,EAAE,QAAQS,EAAE,EAAEN,EAAE,KAAKH,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,GDyBj5B,IAAAU,GAAO,SEzBP,IAAAC,GAAkB,WACZ,CACF,UAAAC,GACA,SAAAC,GACA,OAAAC,GACA,WAAAC,GACA,QAAAC,GACA,WAAAC,GACA,UAAAC,GACA,YAAAC,GACA,aAAAC,GACA,gBAAAC,GACA,SAAAC,GACA,OAAAC,EACA,SAAAC,GACA,eAAAC,GACA,cAAAC,EACA,QAAAC,GACA,iBAAAC,GACA,iBAAAC,GACA,cAAAC,GACA,qBAAAC,GACA,aAAAC,GACA,gBAAAC,GACA,uBAAAC,GACA,uBAAAC,EACJ,EAAI,GAAAC,QCtBE,SAAUC,EAAWC,EAAU,CACnC,OAAO,OAAOA,GAAU,UAC1B,CCGM,SAAUC,GAAoBC,EAAgC,CAClE,IAAMC,EAAS,SAACC,EAAa,CAC3B,MAAM,KAAKA,CAAQ,EACnBA,EAAS,MAAQ,IAAI,MAAK,EAAG,KAC/B,EAEMC,EAAWH,EAAWC,CAAM,EAClC,OAAAE,EAAS,UAAY,OAAO,OAAO,MAAM,SAAS,EAClDA,EAAS,UAAU,YAAcA,EAC1BA,CACT,CCDO,IAAMC,GAA+CC,GAC1D,SAACC,EAAM,CACL,OAAA,SAA4CC,EAA0B,CACpED,EAAO,IAAI,EACX,KAAK,QAAUC,EACRA,EAAO,OAAM;EACxBA,EAAO,IAAI,SAACC,EAAKC,EAAC,CAAK,OAAGA,EAAI,EAAC,KAAKD,EAAI,SAAQ,CAAzB,CAA6B,EAAE,KAAK;GAAM,EACzD,GACJ,KAAK,KAAO,sBACZ,KAAK,OAASD,CAChB,CARA,CAQC,ECvBC,SAAUG,GAAaC,EAA6BC,EAAO,CAC/D,GAAID,EAAK,CACP,IAAME,EAAQF,EAAI,QAAQC,CAAI,EAC9B,GAAKC,GAASF,EAAI,OAAOE,EAAO,CAAC,EAErC,CCOA,IAAAC,GAAA,UAAA,CAyBE,SAAAA,EAAoBC,EAA4B,CAA5B,KAAA,gBAAAA,EAdb,KAAA,OAAS,GAER,KAAA,WAAmD,KAMnD,KAAA,YAAqD,IAMV,CAQnD,OAAAD,EAAA,UAAA,YAAA,UAAA,aACME,EAEJ,GAAI,CAAC,KAAK,OAAQ,CAChB,KAAK,OAAS,GAGN,IAAAC,EAAe,KAAI,WAC3B,GAAIA,EAEF,GADA,KAAK,WAAa,KACd,MAAM,QAAQA,CAAU,MAC1B,QAAqBC,EAAAC,GAAAF,CAAU,EAAAG,EAAAF,EAAA,KAAA,EAAA,CAAAE,EAAA,KAAAA,EAAAF,EAAA,KAAA,EAAE,CAA5B,IAAMG,EAAMD,EAAA,MACfC,EAAO,OAAO,IAAI,yGAGpBJ,EAAW,OAAO,IAAI,EAIlB,IAAiBK,EAAqB,KAAI,gBAClD,GAAIC,EAAWD,CAAgB,EAC7B,GAAI,CACFA,EAAgB,QACTE,EAAP,CACAR,EAASQ,aAAaC,GAAsBD,EAAE,OAAS,CAACA,CAAC,EAIrD,IAAAE,EAAgB,KAAI,YAC5B,GAAIA,EAAa,CACf,KAAK,YAAc,SACnB,QAAwBC,EAAAR,GAAAO,CAAW,EAAAE,EAAAD,EAAA,KAAA,EAAA,CAAAC,EAAA,KAAAA,EAAAD,EAAA,KAAA,EAAE,CAAhC,IAAME,EAASD,EAAA,MAClB,GAAI,CACFE,GAAcD,CAAS,QAChBE,EAAP,CACAf,EAASA,GAAM,KAANA,EAAU,CAAA,EACfe,aAAeN,GACjBT,EAAMgB,EAAAA,EAAA,CAAA,EAAAC,EAAOjB,CAAM,CAAA,EAAAiB,EAAKF,EAAI,MAAM,CAAA,EAElCf,EAAO,KAAKe,CAAG,sGAMvB,GAAIf,EACF,MAAM,IAAIS,GAAoBT,CAAM,EAG1C,EAoBAF,EAAA,UAAA,IAAA,SAAIoB,EAAuB,OAGzB,GAAIA,GAAYA,IAAa,KAC3B,GAAI,KAAK,OAGPJ,GAAcI,CAAQ,MACjB,CACL,GAAIA,aAAoBpB,EAAc,CAGpC,GAAIoB,EAAS,QAAUA,EAAS,WAAW,IAAI,EAC7C,OAEFA,EAAS,WAAW,IAAI,GAEzB,KAAK,aAAcC,EAAA,KAAK,eAAW,MAAAA,IAAA,OAAAA,EAAI,CAAA,GAAI,KAAKD,CAAQ,EAG/D,EAOQpB,EAAA,UAAA,WAAR,SAAmBsB,EAAoB,CAC7B,IAAAnB,EAAe,KAAI,WAC3B,OAAOA,IAAemB,GAAW,MAAM,QAAQnB,CAAU,GAAKA,EAAW,SAASmB,CAAM,CAC1F,EASQtB,EAAA,UAAA,WAAR,SAAmBsB,EAAoB,CAC7B,IAAAnB,EAAe,KAAI,WAC3B,KAAK,WAAa,MAAM,QAAQA,CAAU,GAAKA,EAAW,KAAKmB,CAAM,EAAGnB,GAAcA,EAAa,CAACA,EAAYmB,CAAM,EAAIA,CAC5H,EAMQtB,EAAA,UAAA,cAAR,SAAsBsB,EAAoB,CAChC,IAAAnB,EAAe,KAAI,WACvBA,IAAemB,EACjB,KAAK,WAAa,KACT,MAAM,QAAQnB,CAAU,GACjCoB,GAAUpB,EAAYmB,CAAM,CAEhC,EAgBAtB,EAAA,UAAA,OAAA,SAAOoB,EAAsC,CACnC,IAAAR,EAAgB,KAAI,YAC5BA,GAAeW,GAAUX,EAAaQ,CAAQ,EAE1CA,aAAoBpB,GACtBoB,EAAS,cAAc,IAAI,CAE/B,EAlLcpB,EAAA,MAAS,UAAA,CACrB,IAAMwB,EAAQ,IAAIxB,EAClB,OAAAwB,EAAM,OAAS,GACRA,CACT,EAAE,EA+KJxB,GArLA,EAuLO,IAAMyB,GAAqBC,GAAa,MAEzC,SAAUC,GAAeC,EAAU,CACvC,OACEA,aAAiBF,IAChBE,GAAS,WAAYA,GAASC,EAAWD,EAAM,MAAM,GAAKC,EAAWD,EAAM,GAAG,GAAKC,EAAWD,EAAM,WAAW,CAEpH,CAEA,SAASE,GAAcC,EAAwC,CACzDF,EAAWE,CAAS,EACtBA,EAAS,EAETA,EAAU,YAAW,CAEzB,CChNO,IAAMC,GAAuB,CAClC,iBAAkB,KAClB,sBAAuB,KACvB,QAAS,OACT,sCAAuC,GACvC,yBAA0B,ICGrB,IAAMC,GAAmC,CAG9C,WAAA,SAAWC,EAAqBC,EAAgB,SAAEC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,EAAA,GAAA,UAAAA,GACxC,IAAAC,EAAaL,GAAe,SACpC,OAAIK,GAAQ,MAARA,EAAU,WACLA,EAAS,WAAU,MAAnBA,EAAQC,EAAA,CAAYL,EAASC,CAAO,EAAAK,EAAKJ,CAAI,CAAA,CAAA,EAE/C,WAAU,MAAA,OAAAG,EAAA,CAACL,EAASC,CAAO,EAAAK,EAAKJ,CAAI,CAAA,CAAA,CAC7C,EACA,aAAA,SAAaK,EAAM,CACT,IAAAH,EAAaL,GAAe,SACpC,QAAQK,GAAQ,KAAA,OAARA,EAAU,eAAgB,cAAcG,CAAa,CAC/D,EACA,SAAU,QCjBN,SAAUC,GAAqBC,EAAQ,CAC3CC,GAAgB,WAAW,UAAA,CACjB,IAAAC,EAAqBC,GAAM,iBACnC,GAAID,EAEFA,EAAiBF,CAAG,MAGpB,OAAMA,CAEV,CAAC,CACH,CCtBM,SAAUI,IAAI,CAAK,CCMlB,IAAMC,GAAyB,UAAA,CAAM,OAAAC,GAAmB,IAAK,OAAW,MAAS,CAA5C,EAAsE,EAO5G,SAAUC,GAAkBC,EAAU,CAC1C,OAAOF,GAAmB,IAAK,OAAWE,CAAK,CACjD,CAOM,SAAUC,GAAoBC,EAAQ,CAC1C,OAAOJ,GAAmB,IAAKI,EAAO,MAAS,CACjD,CAQM,SAAUJ,GAAmBK,EAAuBD,EAAYF,EAAU,CAC9E,MAAO,CACL,KAAIG,EACJ,MAAKD,EACL,MAAKF,EAET,CCrCA,IAAII,GAAuD,KASrD,SAAUC,GAAaC,EAAc,CACzC,GAAIC,GAAO,sCAAuC,CAChD,IAAMC,EAAS,CAACJ,GAKhB,GAJII,IACFJ,GAAU,CAAE,YAAa,GAAO,MAAO,IAAI,GAE7CE,EAAE,EACEE,EAAQ,CACJ,IAAAC,EAAyBL,GAAvBM,EAAWD,EAAA,YAAEE,EAAKF,EAAA,MAE1B,GADAL,GAAU,KACNM,EACF,MAAMC,QAMVL,EAAE,CAEN,CAMM,SAAUM,GAAaC,EAAQ,CAC/BN,GAAO,uCAAyCH,KAClDA,GAAQ,YAAc,GACtBA,GAAQ,MAAQS,EAEpB,CCrBA,IAAAC,GAAA,SAAAC,EAAA,CAAmCC,GAAAF,EAAAC,CAAA,EA6BjC,SAAAD,EAAYG,EAA6C,CAAzD,IAAAC,EACEH,EAAA,KAAA,IAAA,GAAO,KATC,OAAAG,EAAA,UAAqB,GAUzBD,GACFC,EAAK,YAAcD,EAGfE,GAAeF,CAAW,GAC5BA,EAAY,IAAIC,CAAI,GAGtBA,EAAK,YAAcE,IAEvB,CAzBO,OAAAN,EAAA,OAAP,SAAiBO,EAAwBC,EAA2BC,EAAqB,CACvF,OAAO,IAAIC,GAAeH,EAAMC,EAAOC,CAAQ,CACjD,EAgCAT,EAAA,UAAA,KAAA,SAAKW,EAAS,CACR,KAAK,UACPC,GAA0BC,GAAiBF,CAAK,EAAG,IAAI,EAEvD,KAAK,MAAMA,CAAM,CAErB,EASAX,EAAA,UAAA,MAAA,SAAMc,EAAS,CACT,KAAK,UACPF,GAA0BG,GAAkBD,CAAG,EAAG,IAAI,GAEtD,KAAK,UAAY,GACjB,KAAK,OAAOA,CAAG,EAEnB,EAQAd,EAAA,UAAA,SAAA,UAAA,CACM,KAAK,UACPY,GAA0BI,GAAuB,IAAI,GAErD,KAAK,UAAY,GACjB,KAAK,UAAS,EAElB,EAEAhB,EAAA,UAAA,YAAA,UAAA,CACO,KAAK,SACR,KAAK,UAAY,GACjBC,EAAA,UAAM,YAAW,KAAA,IAAA,EACjB,KAAK,YAAc,KAEvB,EAEUD,EAAA,UAAA,MAAV,SAAgBW,EAAQ,CACtB,KAAK,YAAY,KAAKA,CAAK,CAC7B,EAEUX,EAAA,UAAA,OAAV,SAAiBc,EAAQ,CACvB,GAAI,CACF,KAAK,YAAY,MAAMA,CAAG,UAE1B,KAAK,YAAW,EAEpB,EAEUd,EAAA,UAAA,UAAV,UAAA,CACE,GAAI,CACF,KAAK,YAAY,SAAQ,UAEzB,KAAK,YAAW,EAEpB,EACFA,CAAA,EApHmCiB,EAAY,EA2H/C,IAAMC,GAAQ,SAAS,UAAU,KAEjC,SAASC,GAAyCC,EAAQC,EAAY,CACpE,OAAOH,GAAM,KAAKE,EAAIC,CAAO,CAC/B,CAMA,IAAAC,GAAA,UAAA,CACE,SAAAA,EAAoBC,EAAqC,CAArC,KAAA,gBAAAA,CAAwC,CAE5D,OAAAD,EAAA,UAAA,KAAA,SAAKE,EAAQ,CACH,IAAAD,EAAoB,KAAI,gBAChC,GAAIA,EAAgB,KAClB,GAAI,CACFA,EAAgB,KAAKC,CAAK,QACnBC,EAAP,CACAC,GAAqBD,CAAK,EAGhC,EAEAH,EAAA,UAAA,MAAA,SAAMK,EAAQ,CACJ,IAAAJ,EAAoB,KAAI,gBAChC,GAAIA,EAAgB,MAClB,GAAI,CACFA,EAAgB,MAAMI,CAAG,QAClBF,EAAP,CACAC,GAAqBD,CAAK,OAG5BC,GAAqBC,CAAG,CAE5B,EAEAL,EAAA,UAAA,SAAA,UAAA,CACU,IAAAC,EAAoB,KAAI,gBAChC,GAAIA,EAAgB,SAClB,GAAI,CACFA,EAAgB,SAAQ,QACjBE,EAAP,CACAC,GAAqBD,CAAK,EAGhC,EACFH,CAAA,EArCA,EAuCAM,GAAA,SAAAC,EAAA,CAAuCC,GAAAF,EAAAC,CAAA,EACrC,SAAAD,EACEG,EACAN,EACAO,EAA8B,CAHhC,IAAAC,EAKEJ,EAAA,KAAA,IAAA,GAAO,KAEHN,EACJ,GAAIW,EAAWH,CAAc,GAAK,CAACA,EAGjCR,EAAkB,CAChB,KAAOQ,GAAc,KAAdA,EAAkB,OACzB,MAAON,GAAK,KAALA,EAAS,OAChB,SAAUO,GAAQ,KAARA,EAAY,YAEnB,CAEL,IAAIG,EACAF,GAAQG,GAAO,0BAIjBD,EAAU,OAAO,OAAOJ,CAAc,EACtCI,EAAQ,YAAc,UAAA,CAAM,OAAAF,EAAK,YAAW,CAAhB,EAC5BV,EAAkB,CAChB,KAAMQ,EAAe,MAAQZ,GAAKY,EAAe,KAAMI,CAAO,EAC9D,MAAOJ,EAAe,OAASZ,GAAKY,EAAe,MAAOI,CAAO,EACjE,SAAUJ,EAAe,UAAYZ,GAAKY,EAAe,SAAUI,CAAO,IAI5EZ,EAAkBQ,EAMtB,OAAAE,EAAK,YAAc,IAAIX,GAAiBC,CAAe,GACzD,CACF,OAAAK,CAAA,EAzCuCS,EAAU,EA2CjD,SAASC,GAAqBC,EAAU,CAClCC,GAAO,sCACTC,GAAaF,CAAK,EAIlBG,GAAqBH,CAAK,CAE9B,CAQA,SAASI,GAAoBC,EAAQ,CACnC,MAAMA,CACR,CAOA,SAASC,GAA0BC,EAA2CC,EAA2B,CAC/F,IAAAC,EAA0BR,GAAM,sBACxCQ,GAAyBC,GAAgB,WAAW,UAAA,CAAM,OAAAD,EAAsBF,EAAcC,CAAU,CAA9C,CAA+C,CAC3G,CAOO,IAAMG,GAA6D,CACxE,OAAQ,GACR,KAAMC,GACN,MAAOR,GACP,SAAUQ,ICjRL,IAAMC,GAA+B,UAAA,CAAM,OAAC,OAAO,QAAW,YAAc,OAAO,YAAe,cAAvD,EAAsE,ECyClH,SAAUC,GAAYC,EAAI,CAC9B,OAAOA,CACT,CCiCM,SAAUC,IAAI,SAACC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GACnB,OAAOC,GAAcF,CAAG,CAC1B,CAGM,SAAUE,GAAoBF,EAA+B,CACjE,OAAIA,EAAI,SAAW,EACVG,GAGLH,EAAI,SAAW,EACVA,EAAI,GAGN,SAAeI,EAAQ,CAC5B,OAAOJ,EAAI,OAAO,SAACK,EAAWC,EAAuB,CAAK,OAAAA,EAAGD,CAAI,CAAP,EAAUD,CAAY,CAClF,CACF,CC9EA,IAAAG,EAAA,UAAA,CAkBE,SAAAA,EAAYC,EAA6E,CACnFA,IACF,KAAK,WAAaA,EAEtB,CA4BA,OAAAD,EAAA,UAAA,KAAA,SAAQE,EAAyB,CAC/B,IAAMC,EAAa,IAAIH,EACvB,OAAAG,EAAW,OAAS,KACpBA,EAAW,SAAWD,EACfC,CACT,EA8IAH,EAAA,UAAA,UAAA,SACEI,EACAC,EACAC,EAA8B,CAHhC,IAAAC,EAAA,KAKQC,EAAaC,GAAaL,CAAc,EAAIA,EAAiB,IAAIM,GAAeN,EAAgBC,EAAOC,CAAQ,EAErH,OAAAK,GAAa,UAAA,CACL,IAAAC,EAAuBL,EAArBL,EAAQU,EAAA,SAAEC,EAAMD,EAAA,OACxBJ,EAAW,IACTN,EAGIA,EAAS,KAAKM,EAAYK,CAAM,EAChCA,EAIAN,EAAK,WAAWC,CAAU,EAG1BD,EAAK,cAAcC,CAAU,CAAC,CAEtC,CAAC,EAEMA,CACT,EAGUR,EAAA,UAAA,cAAV,SAAwBc,EAAmB,CACzC,GAAI,CACF,OAAO,KAAK,WAAWA,CAAI,QACpBC,EAAP,CAIAD,EAAK,MAAMC,CAAG,EAElB,EA6DAf,EAAA,UAAA,QAAA,SAAQgB,EAA0BC,EAAoC,CAAtE,IAAAV,EAAA,KACE,OAAAU,EAAcC,GAAeD,CAAW,EAEjC,IAAIA,EAAkB,SAACE,EAASC,EAAM,CAC3C,IAAMZ,EAAa,IAAIE,GAAkB,CACvC,KAAM,SAACW,EAAK,CACV,GAAI,CACFL,EAAKK,CAAK,QACHN,EAAP,CACAK,EAAOL,CAAG,EACVP,EAAW,YAAW,EAE1B,EACA,MAAOY,EACP,SAAUD,EACX,EACDZ,EAAK,UAAUC,CAAU,CAC3B,CAAC,CACH,EAGUR,EAAA,UAAA,WAAV,SAAqBQ,EAA2B,OAC9C,OAAOI,EAAA,KAAK,UAAM,MAAAA,IAAA,OAAA,OAAAA,EAAE,UAAUJ,CAAU,CAC1C,EAOAR,EAAA,UAACG,IAAD,UAAA,CACE,OAAO,IACT,EA4FAH,EAAA,UAAA,KAAA,UAAA,SAAKsB,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GACH,OAAOC,GAAcF,CAAU,EAAE,IAAI,CACvC,EA6BAtB,EAAA,UAAA,UAAA,SAAUiB,EAAoC,CAA9C,IAAAV,EAAA,KACE,OAAAU,EAAcC,GAAeD,CAAW,EAEjC,IAAIA,EAAY,SAACE,EAASC,EAAM,CACrC,IAAIC,EACJd,EAAK,UACH,SAACkB,EAAI,CAAK,OAACJ,EAAQI,CAAT,EACV,SAACV,EAAQ,CAAK,OAAAK,EAAOL,CAAG,CAAV,EACd,UAAA,CAAM,OAAAI,EAAQE,CAAK,CAAb,CAAc,CAExB,CAAC,CACH,EA3aOrB,EAAA,OAAkC,SAAIC,EAAwD,CACnG,OAAO,IAAID,EAAcC,CAAS,CACpC,EA0aFD,GA/cA,EAwdA,SAAS0B,GAAeC,EAA+C,OACrE,OAAOC,EAAAD,GAAW,KAAXA,EAAeE,GAAO,WAAO,MAAAD,IAAA,OAAAA,EAAI,OAC1C,CAEA,SAASE,GAAcC,EAAU,CAC/B,OAAOA,GAASC,EAAWD,EAAM,IAAI,GAAKC,EAAWD,EAAM,KAAK,GAAKC,EAAWD,EAAM,QAAQ,CAChG,CAEA,SAASE,GAAgBF,EAAU,CACjC,OAAQA,GAASA,aAAiBG,IAAgBJ,GAAWC,CAAK,GAAKI,GAAeJ,CAAK,CAC7F,CC1eM,SAAUK,GAAQC,EAAW,CACjC,OAAOC,EAAWD,GAAM,KAAA,OAANA,EAAQ,IAAI,CAChC,CAMM,SAAUE,EACdC,EAAqF,CAErF,OAAO,SAACH,EAAqB,CAC3B,GAAID,GAAQC,CAAM,EAChB,OAAOA,EAAO,KAAK,SAA+BI,EAA2B,CAC3E,GAAI,CACF,OAAOD,EAAKC,EAAc,IAAI,QACvBC,EAAP,CACA,KAAK,MAAMA,CAAG,EAElB,CAAC,EAEH,MAAM,IAAI,UAAU,wCAAwC,CAC9D,CACF,CCjBM,SAAUC,EACdC,EACAC,EACAC,EACAC,EACAC,EAAuB,CAEvB,OAAO,IAAIC,GAAmBL,EAAaC,EAAQC,EAAYC,EAASC,CAAU,CACpF,CAMA,IAAAC,GAAA,SAAAC,EAAA,CAA2CC,GAAAF,EAAAC,CAAA,EAiBzC,SAAAD,EACEL,EACAC,EACAC,EACAC,EACQC,EACAI,EAAiC,CAN3C,IAAAC,EAoBEH,EAAA,KAAA,KAAMN,CAAW,GAAC,KAfV,OAAAS,EAAA,WAAAL,EACAK,EAAA,kBAAAD,EAeRC,EAAK,MAAQR,EACT,SAAuCS,EAAQ,CAC7C,GAAI,CACFT,EAAOS,CAAK,QACLC,EAAP,CACAX,EAAY,MAAMW,CAAG,EAEzB,EACAL,EAAA,UAAM,MACVG,EAAK,OAASN,EACV,SAAuCQ,EAAQ,CAC7C,GAAI,CACFR,EAAQQ,CAAG,QACJA,EAAP,CAEAX,EAAY,MAAMW,CAAG,UAGrB,KAAK,YAAW,EAEpB,EACAL,EAAA,UAAM,OACVG,EAAK,UAAYP,EACb,UAAA,CACE,GAAI,CACFA,EAAU,QACHS,EAAP,CAEAX,EAAY,MAAMW,CAAG,UAGrB,KAAK,YAAW,EAEpB,EACAL,EAAA,UAAM,WACZ,CAEA,OAAAD,EAAA,UAAA,YAAA,UAAA,OACE,GAAI,CAAC,KAAK,mBAAqB,KAAK,kBAAiB,EAAI,CAC/C,IAAAO,EAAW,KAAI,OACvBN,EAAA,UAAM,YAAW,KAAA,IAAA,EAEjB,CAACM,KAAUC,EAAA,KAAK,cAAU,MAAAA,IAAA,QAAAA,EAAA,KAAf,IAAI,GAEnB,EACFR,CAAA,EAnF2CS,EAAU,ECd9C,IAAMC,GAAiD,CAG5D,SAAA,SAASC,EAAQ,CACf,IAAIC,EAAU,sBACVC,EAAkD,qBAC9CC,EAAaJ,GAAsB,SACvCI,IACFF,EAAUE,EAAS,sBACnBD,EAASC,EAAS,sBAEpB,IAAMC,EAASH,EAAQ,SAACI,EAAS,CAI/BH,EAAS,OACTF,EAASK,CAAS,CACpB,CAAC,EACD,OAAO,IAAIC,GAAa,UAAA,CAAM,OAAAJ,GAAM,KAAA,OAANA,EAASE,CAAM,CAAf,CAAgB,CAChD,EACA,sBAAqB,UAAA,SAACG,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GACZ,IAAAL,EAAaJ,GAAsB,SAC3C,QAAQI,GAAQ,KAAA,OAARA,EAAU,wBAAyB,uBAAsB,MAAA,OAAAM,EAAA,CAAA,EAAAC,EAAIH,CAAI,CAAA,CAAA,CAC3E,EACA,qBAAoB,UAAA,SAACA,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GACX,IAAAL,EAAaJ,GAAsB,SAC3C,QAAQI,GAAQ,KAAA,OAARA,EAAU,uBAAwB,sBAAqB,MAAA,OAAAM,EAAA,CAAA,EAAAC,EAAIH,CAAI,CAAA,CAAA,CACzE,EACA,SAAU,QCrBL,IAAMI,GAAuDC,GAClE,SAACC,EAAM,CACL,OAAA,UAAoC,CAClCA,EAAO,IAAI,EACX,KAAK,KAAO,0BACZ,KAAK,QAAU,qBACjB,CAJA,CAIC,ECXL,IAAAC,EAAA,SAAAC,EAAA,CAAgCC,GAAAF,EAAAC,CAAA,EAwB9B,SAAAD,GAAA,CAAA,IAAAG,EAEEF,EAAA,KAAA,IAAA,GAAO,KAzBT,OAAAE,EAAA,OAAS,GAEDA,EAAA,iBAAyC,KAGjDA,EAAA,UAA2B,CAAA,EAE3BA,EAAA,UAAY,GAEZA,EAAA,SAAW,GAEXA,EAAA,YAAmB,MAenB,CAGA,OAAAH,EAAA,UAAA,KAAA,SAAQI,EAAwB,CAC9B,IAAMC,EAAU,IAAIC,GAAiB,KAAM,IAAI,EAC/C,OAAAD,EAAQ,SAAWD,EACZC,CACT,EAGUL,EAAA,UAAA,eAAV,UAAA,CACE,GAAI,KAAK,OACP,MAAM,IAAIO,EAEd,EAEAP,EAAA,UAAA,KAAA,SAAKQ,EAAQ,CAAb,IAAAL,EAAA,KACEM,GAAa,UAAA,SAEX,GADAN,EAAK,eAAc,EACf,CAACA,EAAK,UAAW,CACdA,EAAK,mBACRA,EAAK,iBAAmB,MAAM,KAAKA,EAAK,SAAS,OAEnD,QAAuBO,EAAAC,GAAAR,EAAK,gBAAgB,EAAAS,EAAAF,EAAA,KAAA,EAAA,CAAAE,EAAA,KAAAA,EAAAF,EAAA,KAAA,EAAE,CAAzC,IAAMG,EAAQD,EAAA,MACjBC,EAAS,KAAKL,CAAK,qGAGzB,CAAC,CACH,EAEAR,EAAA,UAAA,MAAA,SAAMc,EAAQ,CAAd,IAAAX,EAAA,KACEM,GAAa,UAAA,CAEX,GADAN,EAAK,eAAc,EACf,CAACA,EAAK,UAAW,CACnBA,EAAK,SAAWA,EAAK,UAAY,GACjCA,EAAK,YAAcW,EAEnB,QADQC,EAAcZ,EAAI,UACnBY,EAAU,QACfA,EAAU,MAAK,EAAI,MAAMD,CAAG,EAGlC,CAAC,CACH,EAEAd,EAAA,UAAA,SAAA,UAAA,CAAA,IAAAG,EAAA,KACEM,GAAa,UAAA,CAEX,GADAN,EAAK,eAAc,EACf,CAACA,EAAK,UAAW,CACnBA,EAAK,UAAY,GAEjB,QADQY,EAAcZ,EAAI,UACnBY,EAAU,QACfA,EAAU,MAAK,EAAI,SAAQ,EAGjC,CAAC,CACH,EAEAf,EAAA,UAAA,YAAA,UAAA,CACE,KAAK,UAAY,KAAK,OAAS,GAC/B,KAAK,UAAY,KAAK,iBAAmB,IAC3C,EAEA,OAAA,eAAIA,EAAA,UAAA,WAAQ,KAAZ,UAAA,OACE,QAAOgB,EAAA,KAAK,aAAS,MAAAA,IAAA,OAAA,OAAAA,EAAE,QAAS,CAClC,kCAGUhB,EAAA,UAAA,cAAV,SAAwBiB,EAAyB,CAC/C,YAAK,eAAc,EACZhB,EAAA,UAAM,cAAa,KAAA,KAACgB,CAAU,CACvC,EAGUjB,EAAA,UAAA,WAAV,SAAqBiB,EAAyB,CAC5C,YAAK,eAAc,EACnB,KAAK,wBAAwBA,CAAU,EAChC,KAAK,gBAAgBA,CAAU,CACxC,EAGUjB,EAAA,UAAA,gBAAV,SAA0BiB,EAA2B,CAArD,IAAAd,EAAA,KACQa,EAAqC,KAAnCE,EAAQF,EAAA,SAAEG,EAASH,EAAA,UAAED,EAASC,EAAA,UACtC,OAAIE,GAAYC,EACPC,IAET,KAAK,iBAAmB,KACxBL,EAAU,KAAKE,CAAU,EAClB,IAAII,GAAa,UAAA,CACtBlB,EAAK,iBAAmB,KACxBmB,GAAUP,EAAWE,CAAU,CACjC,CAAC,EACH,EAGUjB,EAAA,UAAA,wBAAV,SAAkCiB,EAA2B,CACrD,IAAAD,EAAuC,KAArCE,EAAQF,EAAA,SAAEO,EAAWP,EAAA,YAAEG,EAASH,EAAA,UACpCE,EACFD,EAAW,MAAMM,CAAW,EACnBJ,GACTF,EAAW,SAAQ,CAEvB,EAQAjB,EAAA,UAAA,aAAA,UAAA,CACE,IAAMwB,EAAkB,IAAIC,EAC5B,OAAAD,EAAW,OAAS,KACbA,CACT,EAxHOxB,EAAA,OAAkC,SAAI0B,EAA0BC,EAAqB,CAC1F,OAAO,IAAIrB,GAAoBoB,EAAaC,CAAM,CACpD,EAuHF3B,GA7IgCyB,CAAU,EAkJ1C,IAAAG,GAAA,SAAAC,EAAA,CAAyCC,GAAAF,EAAAC,CAAA,EACvC,SAAAD,EAESG,EACPC,EAAsB,CAHxB,IAAAC,EAKEJ,EAAA,KAAA,IAAA,GAAO,KAHA,OAAAI,EAAA,YAAAF,EAIPE,EAAK,OAASD,GAChB,CAEA,OAAAJ,EAAA,UAAA,KAAA,SAAKM,EAAQ,UACXC,GAAAC,EAAA,KAAK,eAAW,MAAAA,IAAA,OAAA,OAAAA,EAAE,QAAI,MAAAD,IAAA,QAAAA,EAAA,KAAAC,EAAGF,CAAK,CAChC,EAEAN,EAAA,UAAA,MAAA,SAAMS,EAAQ,UACZF,GAAAC,EAAA,KAAK,eAAW,MAAAA,IAAA,OAAA,OAAAA,EAAE,SAAK,MAAAD,IAAA,QAAAA,EAAA,KAAAC,EAAGC,CAAG,CAC/B,EAEAT,EAAA,UAAA,SAAA,UAAA,UACEO,GAAAC,EAAA,KAAK,eAAW,MAAAA,IAAA,OAAA,OAAAA,EAAE,YAAQ,MAAAD,IAAA,QAAAA,EAAA,KAAAC,CAAA,CAC5B,EAGUR,EAAA,UAAA,WAAV,SAAqBU,EAAyB,SAC5C,OAAOH,GAAAC,EAAA,KAAK,UAAM,MAAAA,IAAA,OAAA,OAAAA,EAAE,UAAUE,CAAU,KAAC,MAAAH,IAAA,OAAAA,EAAII,EAC/C,EACFX,CAAA,EA1ByCY,CAAO,EC5JzC,IAAMC,GAA+C,CAC1D,IAAG,UAAA,CAGD,OAAQA,GAAsB,UAAY,MAAM,IAAG,CACrD,EACA,SAAU,QCwBZ,IAAAC,GAAA,SAAAC,EAAA,CAAsCC,GAAAF,EAAAC,CAAA,EAUpC,SAAAD,EACUG,EACAC,EACAC,EAA6D,CAF7DF,IAAA,SAAAA,EAAA,KACAC,IAAA,SAAAA,EAAA,KACAC,IAAA,SAAAA,EAAAC,IAHV,IAAAC,EAKEN,EAAA,KAAA,IAAA,GAAO,KAJC,OAAAM,EAAA,YAAAJ,EACAI,EAAA,YAAAH,EACAG,EAAA,mBAAAF,EAZFE,EAAA,QAA0B,CAAA,EAC1BA,EAAA,oBAAsB,GAc5BA,EAAK,oBAAsBH,IAAgB,IAC3CG,EAAK,YAAc,KAAK,IAAI,EAAGJ,CAAW,EAC1CI,EAAK,YAAc,KAAK,IAAI,EAAGH,CAAW,GAC5C,CAEA,OAAAJ,EAAA,UAAA,KAAA,SAAKQ,EAAQ,CACL,IAAAC,EAA+E,KAA7EC,EAASD,EAAA,UAAEE,EAAOF,EAAA,QAAEG,EAAmBH,EAAA,oBAAEJ,EAAkBI,EAAA,mBAAEL,EAAWK,EAAA,YAC3EC,IACHC,EAAQ,KAAKH,CAAK,EAClB,CAACI,GAAuBD,EAAQ,KAAKN,EAAmB,IAAG,EAAKD,CAAW,GAE7E,KAAK,YAAW,EAChBH,EAAA,UAAM,KAAI,KAAA,KAACO,CAAK,CAClB,EAGUR,EAAA,UAAA,WAAV,SAAqBa,EAAyB,CAC5C,KAAK,eAAc,EACnB,KAAK,YAAW,EAQhB,QANMC,EAAe,KAAK,gBAAgBD,CAAU,EAE9CJ,EAAmC,KAAjCG,EAAmBH,EAAA,oBAAEE,EAAOF,EAAA,QAG9BM,EAAOJ,EAAQ,MAAK,EACjBK,EAAI,EAAGA,EAAID,EAAK,QAAU,CAACF,EAAW,OAAQG,GAAKJ,EAAsB,EAAI,EACpFC,EAAW,KAAKE,EAAKC,EAAO,EAG9B,YAAK,wBAAwBH,CAAU,EAEhCC,CACT,EAEQd,EAAA,UAAA,YAAR,UAAA,CACQ,IAAAS,EAAoE,KAAlEN,EAAWM,EAAA,YAAEJ,EAAkBI,EAAA,mBAAEE,EAAOF,EAAA,QAAEG,EAAmBH,EAAA,oBAK/DQ,GAAsBL,EAAsB,EAAI,GAAKT,EAK3D,GAJAA,EAAc,KAAYc,EAAqBN,EAAQ,QAAUA,EAAQ,OAAO,EAAGA,EAAQ,OAASM,CAAkB,EAIlH,CAACL,EAAqB,CAKxB,QAJMM,EAAMb,EAAmB,IAAG,EAC9Bc,EAAO,EAGFH,EAAI,EAAGA,EAAIL,EAAQ,QAAWA,EAAQK,IAAiBE,EAAKF,GAAK,EACxEG,EAAOH,EAETG,GAAQR,EAAQ,OAAO,EAAGQ,EAAO,CAAC,EAEtC,EACFnB,CAAA,EAzEsCoB,CAAO,EClB7C,IAAAC,GAAA,SAAAC,EAAA,CAA+BC,GAAAF,EAAAC,CAAA,EAC7B,SAAAD,EAAYG,EAAsBC,EAAmD,QACnFH,EAAA,KAAA,IAAA,GAAO,IACT,CAWO,OAAAD,EAAA,UAAA,SAAP,SAAgBK,EAAWC,EAAiB,CAAjB,OAAAA,IAAA,SAAAA,EAAA,GAClB,IACT,EACFN,CAAA,EAjB+BO,EAAY,ECHpC,IAAMC,GAAqC,CAGhD,YAAA,SAAYC,EAAqBC,EAAgB,SAAEC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,EAAA,GAAA,UAAAA,GACzC,IAAAC,EAAaL,GAAgB,SACrC,OAAIK,GAAQ,MAARA,EAAU,YACLA,EAAS,YAAW,MAApBA,EAAQC,EAAA,CAAaL,EAASC,CAAO,EAAAK,EAAKJ,CAAI,CAAA,CAAA,EAEhD,YAAW,MAAA,OAAAG,EAAA,CAACL,EAASC,CAAO,EAAAK,EAAKJ,CAAI,CAAA,CAAA,CAC9C,EACA,cAAA,SAAcK,EAAM,CACV,IAAAH,EAAaL,GAAgB,SACrC,QAAQK,GAAQ,KAAA,OAARA,EAAU,gBAAiB,eAAeG,CAAa,CACjE,EACA,SAAU,QCtBZ,IAAAC,GAAA,SAAAC,EAAA,CAAoCC,GAAAF,EAAAC,CAAA,EAOlC,SAAAD,EAAsBG,EAAqCC,EAAmD,CAA9G,IAAAC,EACEJ,EAAA,KAAA,KAAME,EAAWC,CAAI,GAAC,KADF,OAAAC,EAAA,UAAAF,EAAqCE,EAAA,KAAAD,EAFjDC,EAAA,QAAmB,IAI7B,CAEO,OAAAL,EAAA,UAAA,SAAP,SAAgBM,EAAWC,EAAiB,CAC1C,GADyBA,IAAA,SAAAA,EAAA,GACrB,KAAK,OACP,OAAO,KAIT,KAAK,MAAQD,EAEb,IAAME,EAAK,KAAK,GACVL,EAAY,KAAK,UAuBvB,OAAIK,GAAM,OACR,KAAK,GAAK,KAAK,eAAeL,EAAWK,EAAID,CAAK,GAKpD,KAAK,QAAU,GAEf,KAAK,MAAQA,EAEb,KAAK,GAAK,KAAK,IAAM,KAAK,eAAeJ,EAAW,KAAK,GAAII,CAAK,EAE3D,IACT,EAEUP,EAAA,UAAA,eAAV,SAAyBG,EAA2BM,EAAWF,EAAiB,CAAjB,OAAAA,IAAA,SAAAA,EAAA,GACtDG,GAAiB,YAAYP,EAAU,MAAM,KAAKA,EAAW,IAAI,EAAGI,CAAK,CAClF,EAEUP,EAAA,UAAA,eAAV,SAAyBW,EAA4BH,EAASD,EAAwB,CAEpF,GAF4DA,IAAA,SAAAA,EAAA,GAExDA,GAAS,MAAQ,KAAK,QAAUA,GAAS,KAAK,UAAY,GAC5D,OAAOC,EAITE,GAAiB,cAAcF,CAAE,CAEnC,EAMOR,EAAA,UAAA,QAAP,SAAeM,EAAUC,EAAa,CACpC,GAAI,KAAK,OACP,OAAO,IAAI,MAAM,8BAA8B,EAGjD,KAAK,QAAU,GACf,IAAMK,EAAQ,KAAK,SAASN,EAAOC,CAAK,EACxC,GAAIK,EACF,OAAOA,EACE,KAAK,UAAY,IAAS,KAAK,IAAM,OAc9C,KAAK,GAAK,KAAK,eAAe,KAAK,UAAW,KAAK,GAAI,IAAI,EAE/D,EAEUZ,EAAA,UAAA,SAAV,SAAmBM,EAAUO,EAAc,CACzC,IAAIC,EAAmB,GACnBC,EACJ,GAAI,CACF,KAAK,KAAKT,CAAK,QACRU,EAAP,CACAF,EAAU,GAIVC,EAAaC,GAAQ,IAAI,MAAM,oCAAoC,EAErE,GAAIF,EACF,YAAK,YAAW,EACTC,CAEX,EAEAf,EAAA,UAAA,YAAA,UAAA,CACE,GAAI,CAAC,KAAK,OAAQ,CACV,IAAAiB,EAAoB,KAAlBT,EAAES,EAAA,GAAEd,EAASc,EAAA,UACbC,EAAYf,EAAS,QAE7B,KAAK,KAAO,KAAK,MAAQ,KAAK,UAAY,KAC1C,KAAK,QAAU,GAEfgB,GAAUD,EAAS,IAAI,EACnBV,GAAM,OACR,KAAK,GAAK,KAAK,eAAeL,EAAWK,EAAI,IAAI,GAGnD,KAAK,MAAQ,KACbP,EAAA,UAAM,YAAW,KAAA,IAAA,EAErB,EACFD,CAAA,EA3IoCoB,EAAM,ECiB1C,IAAAC,GAAA,UAAA,CAGE,SAAAA,EAAoBC,EAAoCC,EAAiC,CAAjCA,IAAA,SAAAA,EAAoBF,EAAU,KAAlE,KAAA,oBAAAC,EAClB,KAAK,IAAMC,CACb,CA6BO,OAAAF,EAAA,UAAA,SAAP,SAAmBG,EAAqDC,EAAmBC,EAAS,CAA5B,OAAAD,IAAA,SAAAA,EAAA,GAC/D,IAAI,KAAK,oBAAuB,KAAMD,CAAI,EAAE,SAASE,EAAOD,CAAK,CAC1E,EAnCcJ,EAAA,IAAoBM,GAAsB,IAoC1DN,GArCA,ECpBA,IAAAO,GAAA,SAAAC,EAAA,CAAoCC,GAAAF,EAAAC,CAAA,EAkBlC,SAAAD,EAAYG,EAAgCC,EAAiC,CAAjCA,IAAA,SAAAA,EAAoBC,GAAU,KAA1E,IAAAC,EACEL,EAAA,KAAA,KAAME,EAAiBC,CAAG,GAAC,KAlBtB,OAAAE,EAAA,QAAmC,CAAA,EAOnCA,EAAA,QAAmB,GAQnBA,EAAA,WAAkB,QAIzB,CAEO,OAAAN,EAAA,UAAA,MAAP,SAAaO,EAAwB,CAC3B,IAAAC,EAAY,KAAI,QAExB,GAAI,KAAK,QAAS,CAChBA,EAAQ,KAAKD,CAAM,EACnB,OAGF,IAAIE,EACJ,KAAK,QAAU,GAEf,EACE,IAAKA,EAAQF,EAAO,QAAQA,EAAO,MAAOA,EAAO,KAAK,EACpD,YAEMA,EAASC,EAAQ,MAAK,GAIhC,GAFA,KAAK,QAAU,GAEXC,EAAO,CACT,KAAQF,EAASC,EAAQ,MAAK,GAC5BD,EAAO,YAAW,EAEpB,MAAME,EAEV,EACFT,CAAA,EAhDoCK,EAAS,EC8CtC,IAAMK,GAAiB,IAAIC,GAAeC,EAAW,EAK/CC,GAAQH,GClDrB,IAAAI,GAAA,SAAAC,EAAA,CAA6CC,GAAAF,EAAAC,CAAA,EAC3C,SAAAD,EAAsBG,EAA8CC,EAAmD,CAAvH,IAAAC,EACEJ,EAAA,KAAA,KAAME,EAAWC,CAAI,GAAC,KADF,OAAAC,EAAA,UAAAF,EAA8CE,EAAA,KAAAD,GAEpE,CAEU,OAAAJ,EAAA,UAAA,eAAV,SAAyBG,EAAoCG,EAAUC,EAAiB,CAEtF,OAFqEA,IAAA,SAAAA,EAAA,GAEjEA,IAAU,MAAQA,EAAQ,EACrBN,EAAA,UAAM,eAAc,KAAA,KAACE,EAAWG,EAAIC,CAAK,GAGlDJ,EAAU,QAAQ,KAAK,IAAI,EAIpBA,EAAU,aAAeA,EAAU,WAAaK,GAAuB,sBAAsB,UAAA,CAAM,OAAAL,EAAU,MAAM,MAAS,CAAzB,CAA0B,GACtI,EACUH,EAAA,UAAA,eAAV,SAAyBG,EAAoCG,EAAUC,EAAiB,CAItF,GAJqEA,IAAA,SAAAA,EAAA,GAIhEA,GAAS,MAAQA,EAAQ,GAAOA,GAAS,MAAQ,KAAK,MAAQ,EACjE,OAAON,EAAA,UAAM,eAAc,KAAA,KAACE,EAAWG,EAAIC,CAAK,EAK7CJ,EAAU,QAAQ,KAAK,SAACM,EAAM,CAAK,OAAAA,EAAO,KAAOH,CAAd,CAAgB,IACtDE,GAAuB,qBAAqBF,CAAE,EAC9CH,EAAU,WAAa,OAI3B,EACFH,CAAA,EAlC6CU,EAAW,ECFxD,IAAAC,GAAA,SAAAC,EAAA,CAA6CC,GAAAF,EAAAC,CAAA,EAA7C,SAAAD,GAAA,+CAkCA,CAjCS,OAAAA,EAAA,UAAA,MAAP,SAAaG,EAAyB,CACpC,KAAK,QAAU,GAUf,IAAMC,EAAU,KAAK,WACrB,KAAK,WAAa,OAEV,IAAAC,EAAY,KAAI,QACpBC,EACJH,EAASA,GAAUE,EAAQ,MAAK,EAEhC,EACE,IAAKC,EAAQH,EAAO,QAAQA,EAAO,MAAOA,EAAO,KAAK,EACpD,aAEMA,EAASE,EAAQ,KAAOF,EAAO,KAAOC,GAAWC,EAAQ,MAAK,GAIxE,GAFA,KAAK,QAAU,GAEXC,EAAO,CACT,MAAQH,EAASE,EAAQ,KAAOF,EAAO,KAAOC,GAAWC,EAAQ,MAAK,GACpEF,EAAO,YAAW,EAEpB,MAAMG,EAEV,EACFN,CAAA,EAlC6CO,EAAc,ECgCpD,IAAMC,GAA0B,IAAIC,GAAwBC,EAAoB,EC8BhF,IAAMC,EAAQ,IAAIC,EAAkB,SAACC,EAAU,CAAK,OAAAA,EAAW,SAAQ,CAAnB,CAAqB,EC9D1E,SAAUC,GAAYC,EAAU,CACpC,OAAOA,GAASC,EAAWD,EAAM,QAAQ,CAC3C,CCDA,SAASE,GAAQC,EAAQ,CACvB,OAAOA,EAAIA,EAAI,OAAS,EAC1B,CAEM,SAAUC,GAAkBC,EAAW,CAC3C,OAAOC,EAAWJ,GAAKG,CAAI,CAAC,EAAIA,EAAK,IAAG,EAAK,MAC/C,CAEM,SAAUE,GAAaF,EAAW,CACtC,OAAOG,GAAYN,GAAKG,CAAI,CAAC,EAAIA,EAAK,IAAG,EAAK,MAChD,CAEM,SAAUI,GAAUJ,EAAaK,EAAoB,CACzD,OAAO,OAAOR,GAAKG,CAAI,GAAM,SAAWA,EAAK,IAAG,EAAMK,CACxD,CClBO,IAAMC,GAAe,SAAIC,EAAM,CAAwB,OAAAA,GAAK,OAAOA,EAAE,QAAW,UAAY,OAAOA,GAAM,UAAlD,ECMxD,SAAUC,GAAUC,EAAU,CAClC,OAAOC,EAAWD,GAAK,KAAA,OAALA,EAAO,IAAI,CAC/B,CCHM,SAAUE,GAAoBC,EAAU,CAC5C,OAAOC,EAAWD,EAAME,GAAkB,CAC5C,CCLM,SAAUC,GAAmBC,EAAQ,CACzC,OAAO,OAAO,eAAiBC,EAAWD,GAAG,KAAA,OAAHA,EAAM,OAAO,cAAc,CACvE,CCAM,SAAUE,GAAiCC,EAAU,CAEzD,OAAO,IAAI,UACT,iBACEA,IAAU,MAAQ,OAAOA,GAAU,SAAW,oBAAsB,IAAIA,EAAK,KAAG,0HACwC,CAE9H,CCXM,SAAUC,IAAiB,CAC/B,OAAI,OAAO,QAAW,YAAc,CAAC,OAAO,SACnC,aAGF,OAAO,QAChB,CAEO,IAAMC,GAAWD,GAAiB,ECJnC,SAAUE,GAAWC,EAAU,CACnC,OAAOC,EAAWD,GAAK,KAAA,OAALA,EAAQE,GAAgB,CAC5C,CCHM,SAAiBC,GAAsCC,EAAqC,mGAC1FC,EAASD,EAAe,UAAS,2DAGX,MAAA,CAAA,EAAAE,GAAMD,EAAO,KAAI,CAAE,CAAA,gBAArCE,EAAkBC,EAAA,KAAA,EAAhBC,EAAKF,EAAA,MAAEG,EAAIH,EAAA,KACfG,iBAAA,CAAA,EAAA,CAAA,SACF,MAAA,CAAA,EAAAF,EAAA,KAAA,CAAA,qBAEIC,CAAM,CAAA,SAAZ,MAAA,CAAA,EAAAD,EAAA,KAAA,CAAA,SAAA,OAAAA,EAAA,KAAA,mCAGF,OAAAH,EAAO,YAAW,6BAIhB,SAAUM,GAAwBC,EAAQ,CAG9C,OAAOC,EAAWD,GAAG,KAAA,OAAHA,EAAK,SAAS,CAClC,CCPM,SAAUE,EAAaC,EAAyB,CACpD,GAAIA,aAAiBC,EACnB,OAAOD,EAET,GAAIA,GAAS,KAAM,CACjB,GAAIE,GAAoBF,CAAK,EAC3B,OAAOG,GAAsBH,CAAK,EAEpC,GAAII,GAAYJ,CAAK,EACnB,OAAOK,GAAcL,CAAK,EAE5B,GAAIM,GAAUN,CAAK,EACjB,OAAOO,GAAYP,CAAK,EAE1B,GAAIQ,GAAgBR,CAAK,EACvB,OAAOS,GAAkBT,CAAK,EAEhC,GAAIU,GAAWV,CAAK,EAClB,OAAOW,GAAaX,CAAK,EAE3B,GAAIY,GAAqBZ,CAAK,EAC5B,OAAOa,GAAuBb,CAAK,EAIvC,MAAMc,GAAiCd,CAAK,CAC9C,CAMM,SAAUG,GAAyBY,EAAQ,CAC/C,OAAO,IAAId,EAAW,SAACe,EAAyB,CAC9C,IAAMC,EAAMF,EAAIG,IAAkB,EAClC,GAAIC,EAAWF,EAAI,SAAS,EAC1B,OAAOA,EAAI,UAAUD,CAAU,EAGjC,MAAM,IAAI,UAAU,gEAAgE,CACtF,CAAC,CACH,CASM,SAAUX,GAAiBe,EAAmB,CAClD,OAAO,IAAInB,EAAW,SAACe,EAAyB,CAU9C,QAASK,EAAI,EAAGA,EAAID,EAAM,QAAU,CAACJ,EAAW,OAAQK,IACtDL,EAAW,KAAKI,EAAMC,EAAE,EAE1BL,EAAW,SAAQ,CACrB,CAAC,CACH,CAEM,SAAUT,GAAee,EAAuB,CACpD,OAAO,IAAIrB,EAAW,SAACe,EAAyB,CAC9CM,EACG,KACC,SAACC,EAAK,CACCP,EAAW,SACdA,EAAW,KAAKO,CAAK,EACrBP,EAAW,SAAQ,EAEvB,EACA,SAACQ,EAAQ,CAAK,OAAAR,EAAW,MAAMQ,CAAG,CAApB,CAAqB,EAEpC,KAAK,KAAMC,EAAoB,CACpC,CAAC,CACH,CAEM,SAAUd,GAAgBe,EAAqB,CACnD,OAAO,IAAIzB,EAAW,SAACe,EAAyB,aAC9C,QAAoBW,EAAAC,GAAAF,CAAQ,EAAAG,EAAAF,EAAA,KAAA,EAAA,CAAAE,EAAA,KAAAA,EAAAF,EAAA,KAAA,EAAE,CAAzB,IAAMJ,EAAKM,EAAA,MAEd,GADAb,EAAW,KAAKO,CAAK,EACjBP,EAAW,OACb,yGAGJA,EAAW,SAAQ,CACrB,CAAC,CACH,CAEM,SAAUP,GAAqBqB,EAA+B,CAClE,OAAO,IAAI7B,EAAW,SAACe,EAAyB,CAC9Ce,GAAQD,EAAed,CAAU,EAAE,MAAM,SAACQ,EAAG,CAAK,OAAAR,EAAW,MAAMQ,CAAG,CAApB,CAAqB,CACzE,CAAC,CACH,CAEM,SAAUX,GAA0BmB,EAAqC,CAC7E,OAAOvB,GAAkBwB,GAAmCD,CAAc,CAAC,CAC7E,CAEA,SAAeD,GAAWD,EAAiCd,EAAyB,uIACxDkB,EAAAC,GAAAL,CAAa,gFAIrC,GAJeP,EAAKa,EAAA,MACpBpB,EAAW,KAAKO,CAAK,EAGjBP,EAAW,OACb,MAAA,CAAA,CAAA,6RAGJ,OAAAA,EAAW,SAAQ,WChHf,SAAUqB,GACdC,EACAC,EACAC,EACAC,EACAC,EAAc,CADdD,IAAA,SAAAA,EAAA,GACAC,IAAA,SAAAA,EAAA,IAEA,IAAMC,EAAuBJ,EAAU,SAAS,UAAA,CAC9CC,EAAI,EACAE,EACFJ,EAAmB,IAAI,KAAK,SAAS,KAAMG,CAAK,CAAC,EAEjD,KAAK,YAAW,CAEpB,EAAGA,CAAK,EAIR,GAFAH,EAAmB,IAAIK,CAAoB,EAEvC,CAACD,EAKH,OAAOC,CAEX,CCeM,SAAUC,GAAaC,EAA0BC,EAAS,CAAT,OAAAA,IAAA,SAAAA,EAAA,GAC9CC,EAAQ,SAACC,EAAQC,EAAU,CAChCD,EAAO,UACLE,EACED,EACA,SAACE,EAAK,CAAK,OAAAC,GAAgBH,EAAYJ,EAAW,UAAA,CAAM,OAAAI,EAAW,KAAKE,CAAK,CAArB,EAAwBL,CAAK,CAA1E,EACX,UAAA,CAAM,OAAAM,GAAgBH,EAAYJ,EAAW,UAAA,CAAM,OAAAI,EAAW,SAAQ,CAAnB,EAAuBH,CAAK,CAAzE,EACN,SAACO,EAAG,CAAK,OAAAD,GAAgBH,EAAYJ,EAAW,UAAA,CAAM,OAAAI,EAAW,MAAMI,CAAG,CAApB,EAAuBP,CAAK,CAAzE,CAA0E,CACpF,CAEL,CAAC,CACH,CCPM,SAAUQ,GAAeC,EAA0BC,EAAiB,CAAjB,OAAAA,IAAA,SAAAA,EAAA,GAChDC,EAAQ,SAACC,EAAQC,EAAU,CAChCA,EAAW,IAAIJ,EAAU,SAAS,UAAA,CAAM,OAAAG,EAAO,UAAUC,CAAU,CAA3B,EAA8BH,CAAK,CAAC,CAC9E,CAAC,CACH,CC7DM,SAAUI,GAAsBC,EAA6BC,EAAwB,CACzF,OAAOC,EAAUF,CAAK,EAAE,KAAKG,GAAYF,CAAS,EAAGG,GAAUH,CAAS,CAAC,CAC3E,CCFM,SAAUI,GAAmBC,EAAuBC,EAAwB,CAChF,OAAOC,EAAUF,CAAK,EAAE,KAAKG,GAAYF,CAAS,EAAGG,GAAUH,CAAS,CAAC,CAC3E,CCJM,SAAUI,GAAiBC,EAAqBC,EAAwB,CAC5E,OAAO,IAAIC,EAAc,SAACC,EAAU,CAElC,IAAIC,EAAI,EAER,OAAOH,EAAU,SAAS,UAAA,CACpBG,IAAMJ,EAAM,OAGdG,EAAW,SAAQ,GAInBA,EAAW,KAAKH,EAAMI,IAAI,EAIrBD,EAAW,QACd,KAAK,SAAQ,EAGnB,CAAC,CACH,CAAC,CACH,CCfM,SAAUE,GAAoBC,EAAoBC,EAAwB,CAC9E,OAAO,IAAIC,EAAc,SAACC,EAAU,CAClC,IAAIC,EAKJ,OAAAC,GAAgBF,EAAYF,EAAW,UAAA,CAErCG,EAAYJ,EAAcI,IAAgB,EAE1CC,GACEF,EACAF,EACA,UAAA,OACMK,EACAC,EACJ,GAAI,CAEDC,EAAkBJ,EAAS,KAAI,EAA7BE,EAAKE,EAAA,MAAED,EAAIC,EAAA,WACPC,EAAP,CAEAN,EAAW,MAAMM,CAAG,EACpB,OAGEF,EAKFJ,EAAW,SAAQ,EAGnBA,EAAW,KAAKG,CAAK,CAEzB,EACA,EACA,EAAI,CAER,CAAC,EAMM,UAAA,CAAM,OAAAI,EAAWN,GAAQ,KAAA,OAARA,EAAU,MAAM,GAAKA,EAAS,OAAM,CAA/C,CACf,CAAC,CACH,CCvDM,SAAUO,GAAyBC,EAAyBC,EAAwB,CACxF,GAAI,CAACD,EACH,MAAM,IAAI,MAAM,yBAAyB,EAE3C,OAAO,IAAIE,EAAc,SAACC,EAAU,CAClCC,GAAgBD,EAAYF,EAAW,UAAA,CACrC,IAAMI,EAAWL,EAAM,OAAO,eAAc,EAC5CI,GACED,EACAF,EACA,UAAA,CACEI,EAAS,KAAI,EAAG,KAAK,SAACC,EAAM,CACtBA,EAAO,KAGTH,EAAW,SAAQ,EAEnBA,EAAW,KAAKG,EAAO,KAAK,CAEhC,CAAC,CACH,EACA,EACA,EAAI,CAER,CAAC,CACH,CAAC,CACH,CCzBM,SAAUC,GAA8BC,EAA8BC,EAAwB,CAClG,OAAOC,GAAsBC,GAAmCH,CAAK,EAAGC,CAAS,CACnF,CCoBM,SAAUG,GAAaC,EAA2BC,EAAwB,CAC9E,GAAID,GAAS,KAAM,CACjB,GAAIE,GAAoBF,CAAK,EAC3B,OAAOG,GAAmBH,EAAOC,CAAS,EAE5C,GAAIG,GAAYJ,CAAK,EACnB,OAAOK,GAAcL,EAAOC,CAAS,EAEvC,GAAIK,GAAUN,CAAK,EACjB,OAAOO,GAAgBP,EAAOC,CAAS,EAEzC,GAAIO,GAAgBR,CAAK,EACvB,OAAOS,GAAsBT,EAAOC,CAAS,EAE/C,GAAIS,GAAWV,CAAK,EAClB,OAAOW,GAAiBX,EAAOC,CAAS,EAE1C,GAAIW,GAAqBZ,CAAK,EAC5B,OAAOa,GAA2Bb,EAAOC,CAAS,EAGtD,MAAMa,GAAiCd,CAAK,CAC9C,CCoDM,SAAUe,GAAQC,EAA2BC,EAAyB,CAC1E,OAAOA,EAAYC,GAAUF,EAAOC,CAAS,EAAIE,EAAUH,CAAK,CAClE,CCxBM,SAAUI,GAAE,SAAIC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GACpB,IAAMC,EAAYC,GAAaH,CAAI,EACnC,OAAOI,GAAKJ,EAAaE,CAAS,CACpC,CCsCM,SAAUG,GAAWC,EAA0BC,EAAyB,CAC5E,IAAMC,EAAeC,EAAWH,CAAmB,EAAIA,EAAsB,UAAA,CAAM,OAAAA,CAAA,EAC7EI,EAAO,SAACC,EAA6B,CAAK,OAAAA,EAAW,MAAMH,EAAY,CAAE,CAA/B,EAChD,OAAO,IAAII,EAAWL,EAAY,SAACI,EAAU,CAAK,OAAAJ,EAAU,SAASG,EAAa,EAAGC,CAAU,CAA7C,EAAiDD,CAAI,CACzG,CCrHM,SAAUG,GAAYC,EAAU,CACpC,OAAOA,aAAiB,MAAQ,CAAC,MAAMA,CAAY,CACrD,CCsCM,SAAUC,EAAUC,EAAyCC,EAAa,CAC9E,OAAOC,EAAQ,SAACC,EAAQC,EAAU,CAEhC,IAAIC,EAAQ,EAGZF,EAAO,UACLG,EAAyBF,EAAY,SAACG,EAAQ,CAG5CH,EAAW,KAAKJ,EAAQ,KAAKC,EAASM,EAAOF,GAAO,CAAC,CACvD,CAAC,CAAC,CAEN,CAAC,CACH,CC1DQ,IAAAG,GAAY,MAAK,QAEzB,SAASC,GAAkBC,EAA6BC,EAAW,CAC/D,OAAOH,GAAQG,CAAI,EAAID,EAAE,MAAA,OAAAE,EAAA,CAAA,EAAAC,EAAIF,CAAI,CAAA,CAAA,EAAID,EAAGC,CAAI,CAChD,CAMM,SAAUG,GAAuBJ,EAA2B,CAC9D,OAAOK,EAAI,SAAAJ,EAAI,CAAI,OAAAF,GAAYC,EAAIC,CAAI,CAApB,CAAqB,CAC5C,CCfQ,IAAAK,GAAY,MAAK,QACjBC,GAA0D,OAAM,eAArCC,GAA+B,OAAM,UAAlBC,GAAY,OAAM,KAQlE,SAAUC,GAAqDC,EAAuB,CAC1F,GAAIA,EAAK,SAAW,EAAG,CACrB,IAAMC,EAAQD,EAAK,GACnB,GAAIL,GAAQM,CAAK,EACf,MAAO,CAAE,KAAMA,EAAO,KAAM,IAAI,EAElC,GAAIC,GAAOD,CAAK,EAAG,CACjB,IAAME,EAAOL,GAAQG,CAAK,EAC1B,MAAO,CACL,KAAME,EAAK,IAAI,SAACC,EAAG,CAAK,OAAAH,EAAMG,EAAN,CAAU,EAClC,KAAID,IAKV,MAAO,CAAE,KAAMH,EAAa,KAAM,IAAI,CACxC,CAEA,SAASE,GAAOG,EAAQ,CACtB,OAAOA,GAAO,OAAOA,GAAQ,UAAYT,GAAeS,CAAG,IAAMR,EACnE,CC7BM,SAAUS,GAAaC,EAAgBC,EAAa,CACxD,OAAOD,EAAK,OAAO,SAACE,EAAQC,EAAKC,EAAC,CAAK,OAAEF,EAAOC,GAAOF,EAAOG,GAAKF,CAA5B,EAAqC,CAAA,CAAS,CACvF,CCsMM,SAAUG,GAAa,SAAoCC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GAC/D,IAAMC,EAAYC,GAAaH,CAAI,EAC7BI,EAAiBC,GAAkBL,CAAI,EAEvCM,EAA8BC,GAAqBP,CAAI,EAA/CQ,EAAWF,EAAA,KAAEG,EAAIH,EAAA,KAE/B,GAAIE,EAAY,SAAW,EAIzB,OAAOE,GAAK,CAAA,EAAIR,CAAgB,EAGlC,IAAMS,EAAS,IAAIC,EACjBC,GACEL,EACAN,EACAO,EAEI,SAACK,EAAM,CAAK,OAAAC,GAAaN,EAAMK,CAAM,CAAzB,EAEZE,EAAQ,CACb,EAGH,OAAOZ,EAAkBO,EAAO,KAAKM,GAAiBb,CAAc,CAAC,EAAsBO,CAC7F,CAEM,SAAUE,GACdL,EACAN,EACAgB,EAAiD,CAAjD,OAAAA,IAAA,SAAAA,EAAAF,IAEO,SAACG,EAA2B,CAGjCC,GACElB,EACA,UAAA,CAaE,QAZQmB,EAAWb,EAAW,OAExBM,EAAS,IAAI,MAAMO,CAAM,EAG3BC,EAASD,EAITE,EAAuBF,aAGlBG,EAAC,CACRJ,GACElB,EACA,UAAA,CACE,IAAMuB,EAASf,GAAKF,EAAYgB,GAAItB,CAAgB,EAChDwB,EAAgB,GACpBD,EAAO,UACLE,EACER,EACA,SAACS,EAAK,CAEJd,EAAOU,GAAKI,EACPF,IAEHA,EAAgB,GAChBH,KAEGA,GAGHJ,EAAW,KAAKD,EAAeJ,EAAO,MAAK,CAAE,CAAC,CAElD,EACA,UAAA,CACO,EAAEQ,GAGLH,EAAW,SAAQ,CAEvB,CAAC,CACF,CAEL,EACAA,CAAU,GAjCLK,EAAI,EAAGA,EAAIH,EAAQG,MAAnBA,CAAC,CAoCZ,EACAL,CAAU,CAEd,CACF,CAMA,SAASC,GAAclB,EAAsC2B,EAAqBC,EAA0B,CACtG5B,EACF6B,GAAgBD,EAAc5B,EAAW2B,CAAO,EAEhDA,EAAO,CAEX,CC3RM,SAAUG,GACdC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAAgC,CAGhC,IAAMC,EAAc,CAAA,EAEhBC,EAAS,EAETC,EAAQ,EAERC,EAAa,GAKXC,EAAgB,UAAA,CAIhBD,GAAc,CAACH,EAAO,QAAU,CAACC,GACnCR,EAAW,SAAQ,CAEvB,EAGMY,EAAY,SAACC,EAAQ,CAAK,OAACL,EAASN,EAAaY,EAAWD,CAAK,EAAIN,EAAO,KAAKM,CAAK,CAA5D,EAE1BC,EAAa,SAACD,EAAQ,CAI1BT,GAAUJ,EAAW,KAAKa,CAAY,EAItCL,IAKA,IAAIO,EAAgB,GAGpBC,EAAUf,EAAQY,EAAOJ,GAAO,CAAC,EAAE,UACjCQ,EACEjB,EACA,SAACkB,EAAU,CAGTf,GAAY,MAAZA,EAAee,CAAU,EAErBd,EAGFQ,EAAUM,CAAiB,EAG3BlB,EAAW,KAAKkB,CAAU,CAE9B,EACA,UAAA,CAGEH,EAAgB,EAClB,EAEA,OACA,UAAA,CAIE,GAAIA,EAKF,GAAI,CAIFP,IAKA,qBACE,IAAMW,EAAgBZ,EAAO,MAAK,EAI9BF,EACFe,GAAgBpB,EAAYK,EAAmB,UAAA,CAAM,OAAAS,EAAWK,CAAa,CAAxB,CAAyB,EAE9EL,EAAWK,CAAa,GARrBZ,EAAO,QAAUC,EAASN,OAYjCS,EAAa,QACNU,EAAP,CACArB,EAAW,MAAMqB,CAAG,EAG1B,CAAC,CACF,CAEL,EAGA,OAAAtB,EAAO,UACLkB,EAAyBjB,EAAYY,EAAW,UAAA,CAE9CF,EAAa,GACbC,EAAa,CACf,CAAC,CAAC,EAKG,UAAA,CACLL,GAAmB,MAAnBA,EAAmB,CACrB,CACF,CClEM,SAAUgB,GACdC,EACAC,EACAC,EAA6B,CAE7B,OAFAA,IAAA,SAAAA,EAAA,KAEIC,EAAWF,CAAc,EAEpBF,GAAS,SAACK,EAAGC,EAAC,CAAK,OAAAC,EAAI,SAACC,EAAQC,EAAU,CAAK,OAAAP,EAAeG,EAAGG,EAAGF,EAAGG,CAAE,CAA1B,CAA2B,EAAEC,EAAUT,EAAQI,EAAGC,CAAC,CAAC,CAAC,CAAjF,EAAoFH,CAAU,GAC/G,OAAOD,GAAmB,WACnCC,EAAaD,GAGRS,EAAQ,SAACC,EAAQC,EAAU,CAAK,OAAAC,GAAeF,EAAQC,EAAYZ,EAASE,CAAU,CAAtD,CAAuD,EAChG,CChCM,SAAUY,GAAyCC,EAA6B,CAA7B,OAAAA,IAAA,SAAAA,EAAA,KAChDC,GAASC,GAAUF,CAAU,CACtC,CCNM,SAAUG,IAAS,CACvB,OAAOC,GAAS,CAAC,CACnB,CCmDM,SAAUC,IAAM,SAACC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GACrB,OAAOC,GAAS,EAAGC,GAAKH,EAAMI,GAAaJ,CAAI,CAAC,CAAC,CACnD,CC9DM,SAAUK,EAAsCC,EAA0B,CAC9E,OAAO,IAAIC,EAA+B,SAACC,EAAU,CACnDC,EAAUH,EAAiB,CAAE,EAAE,UAAUE,CAAU,CACrD,CAAC,CACH,CChDA,IAAME,GAA0B,CAAC,cAAe,gBAAgB,EAC1DC,GAAqB,CAAC,mBAAoB,qBAAqB,EAC/DC,GAAgB,CAAC,KAAM,KAAK,EA8N5B,SAAUC,EACdC,EACAC,EACAC,EACAC,EAAsC,CAMtC,GAJIC,EAAWF,CAAO,IACpBC,EAAiBD,EACjBA,EAAU,QAERC,EACF,OAAOJ,EAAaC,EAAQC,EAAWC,CAA+B,EAAE,KAAKG,GAAiBF,CAAc,CAAC,EAUzG,IAAAG,EAAAC,EAEJC,GAAcR,CAAM,EAChBH,GAAmB,IAAI,SAACY,EAAU,CAAK,OAAA,SAACC,EAAY,CAAK,OAAAV,EAAOS,GAAYR,EAAWS,EAASR,CAA+B,CAAtE,CAAlB,CAAyF,EAElIS,GAAwBX,CAAM,EAC5BJ,GAAwB,IAAIgB,GAAwBZ,EAAQC,CAAS,CAAC,EACtEY,GAA0Bb,CAAM,EAChCF,GAAc,IAAIc,GAAwBZ,EAAQC,CAAS,CAAC,EAC5D,CAAA,EAAE,CAAA,EATDa,EAAGR,EAAA,GAAES,EAAMT,EAAA,GAgBlB,GAAI,CAACQ,GACCE,GAAYhB,CAAM,EACpB,OAAOiB,GAAS,SAACC,EAAc,CAAK,OAAAnB,EAAUmB,EAAWjB,EAAWC,CAA+B,CAA/D,CAAgE,EAClGiB,EAAUnB,CAAM,CAAC,EAOvB,GAAI,CAACc,EACH,MAAM,IAAI,UAAU,sBAAsB,EAG5C,OAAO,IAAIM,EAAc,SAACC,EAAU,CAIlC,IAAMX,EAAU,UAAA,SAACY,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GAAmB,OAAAF,EAAW,KAAK,EAAIC,EAAK,OAASA,EAAOA,EAAK,EAAE,CAAhD,EAEpC,OAAAR,EAAIJ,CAAO,EAEJ,UAAA,CAAM,OAAAK,EAAQL,CAAO,CAAf,CACf,CAAC,CACH,CASA,SAASE,GAAwBZ,EAAaC,EAAiB,CAC7D,OAAO,SAACQ,EAAkB,CAAK,OAAA,SAACC,EAAY,CAAK,OAAAV,EAAOS,GAAYR,EAAWS,CAAO,CAArC,CAAlB,CACjC,CAOA,SAASC,GAAwBX,EAAW,CAC1C,OAAOI,EAAWJ,EAAO,WAAW,GAAKI,EAAWJ,EAAO,cAAc,CAC3E,CAOA,SAASa,GAA0Bb,EAAW,CAC5C,OAAOI,EAAWJ,EAAO,EAAE,GAAKI,EAAWJ,EAAO,GAAG,CACvD,CAOA,SAASQ,GAAcR,EAAW,CAChC,OAAOI,EAAWJ,EAAO,gBAAgB,GAAKI,EAAWJ,EAAO,mBAAmB,CACrF,CC/LM,SAAUwB,GACdC,EACAC,EACAC,EAAsC,CAEtC,OAAIA,EACKH,GAAoBC,EAAYC,CAAa,EAAE,KAAKE,GAAiBD,CAAc,CAAC,EAGtF,IAAIE,EAAoB,SAACC,EAAU,CACxC,IAAMC,EAAU,UAAA,SAACC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GAAc,OAAAH,EAAW,KAAKE,EAAE,SAAW,EAAIA,EAAE,GAAKA,CAAC,CAAzC,EACzBE,EAAWT,EAAWM,CAAO,EACnC,OAAOI,EAAWT,CAAa,EAAI,UAAA,CAAM,OAAAA,EAAcK,EAASG,CAAQ,CAA/B,EAAmC,MAC9E,CAAC,CACH,CCtBM,SAAUE,GACdC,EACAC,EACAC,EAAyC,CAFzCF,IAAA,SAAAA,EAAA,GAEAE,IAAA,SAAAA,EAAAC,IAIA,IAAIC,EAAmB,GAEvB,OAAIH,GAAuB,OAIrBI,GAAYJ,CAAmB,EACjCC,EAAYD,EAIZG,EAAmBH,GAIhB,IAAIK,EAAW,SAACC,EAAU,CAI/B,IAAIC,EAAMC,GAAYT,CAAO,EAAI,CAACA,EAAUE,EAAW,IAAG,EAAKF,EAE3DQ,EAAM,IAERA,EAAM,GAIR,IAAIE,EAAI,EAGR,OAAOR,EAAU,SAAS,UAAA,CACnBK,EAAW,SAEdA,EAAW,KAAKG,GAAG,EAEf,GAAKN,EAGP,KAAK,SAAS,OAAWA,CAAgB,EAGzCG,EAAW,SAAQ,EAGzB,EAAGC,CAAG,CACR,CAAC,CACH,CChGM,SAAUG,GAAK,SAACC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GACpB,IAAMC,EAAYC,GAAaH,CAAI,EAC7BI,EAAaC,GAAUL,EAAM,GAAQ,EACrCM,EAAUN,EAChB,OAAQM,EAAQ,OAGZA,EAAQ,SAAW,EAEnBC,EAAUD,EAAQ,EAAE,EAEpBE,GAASJ,CAAU,EAAEK,GAAKH,EAASJ,CAAS,CAAC,EAL7CQ,CAMN,CCjEO,IAAMC,GAAQ,IAAIC,EAAkBC,EAAI,ECpCvC,IAAAC,GAAY,MAAK,QAMnB,SAAUC,GAAkBC,EAAiB,CACjD,OAAOA,EAAK,SAAW,GAAKF,GAAQE,EAAK,EAAE,EAAIA,EAAK,GAAMA,CAC5D,CCoDM,SAAUC,EAAUC,EAAiDC,EAAa,CACtF,OAAOC,EAAQ,SAACC,EAAQC,EAAU,CAEhC,IAAIC,EAAQ,EAIZF,EAAO,UAILG,EAAyBF,EAAY,SAACG,EAAK,CAAK,OAAAP,EAAU,KAAKC,EAASM,EAAOF,GAAO,GAAKD,EAAW,KAAKG,CAAK,CAAhE,CAAiE,CAAC,CAEtH,CAAC,CACH,CCxBM,SAAUC,IAAG,SAACC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GAClB,IAAMC,EAAiBC,GAAkBH,CAAI,EAEvCI,EAAUC,GAAeL,CAAI,EAEnC,OAAOI,EAAQ,OACX,IAAIE,EAAsB,SAACC,EAAU,CAGnC,IAAIC,EAAuBJ,EAAQ,IAAI,UAAA,CAAM,MAAA,CAAA,CAAA,CAAE,EAK3CK,EAAYL,EAAQ,IAAI,UAAA,CAAM,MAAA,EAAA,CAAK,EAGvCG,EAAW,IAAI,UAAA,CACbC,EAAUC,EAAY,IACxB,CAAC,EAKD,mBAASC,EAAW,CAClBC,EAAUP,EAAQM,EAAY,EAAE,UAC9BE,EACEL,EACA,SAACM,EAAK,CAKJ,GAJAL,EAAQE,GAAa,KAAKG,CAAK,EAI3BL,EAAQ,MAAM,SAACM,EAAM,CAAK,OAAAA,EAAO,MAAP,CAAa,EAAG,CAC5C,IAAMC,EAAcP,EAAQ,IAAI,SAACM,EAAM,CAAK,OAAAA,EAAO,MAAK,CAAZ,CAAe,EAE3DP,EAAW,KAAKL,EAAiBA,EAAc,MAAA,OAAAc,EAAA,CAAA,EAAAC,EAAIF,CAAM,CAAA,CAAA,EAAIA,CAAM,EAI/DP,EAAQ,KAAK,SAACM,EAAQI,EAAC,CAAK,MAAA,CAACJ,EAAO,QAAUL,EAAUS,EAA5B,CAA8B,GAC5DX,EAAW,SAAQ,EAGzB,EACA,UAAA,CAGEE,EAAUC,GAAe,GAIzB,CAACF,EAAQE,GAAa,QAAUH,EAAW,SAAQ,CACrD,CAAC,CACF,GA9BIG,EAAc,EAAG,CAACH,EAAW,QAAUG,EAAcN,EAAQ,OAAQM,MAArEA,CAAW,EAmCpB,OAAO,UAAA,CACLF,EAAUC,EAAY,IACxB,CACF,CAAC,EACDU,CACN,CC9DM,SAAUC,GAASC,EAAoD,CAC3E,OAAOC,EAAQ,SAACC,EAAQC,EAAU,CAChC,IAAIC,EAAW,GACXC,EAAsB,KACtBC,EAA6C,KAC7CC,EAAa,GAEXC,EAAc,UAAA,CAGlB,GAFAF,GAAkB,MAAlBA,EAAoB,YAAW,EAC/BA,EAAqB,KACjBF,EAAU,CACZA,EAAW,GACX,IAAMK,EAAQJ,EACdA,EAAY,KACZF,EAAW,KAAKM,CAAK,EAEvBF,GAAcJ,EAAW,SAAQ,CACnC,EAEMO,EAAkB,UAAA,CACtBJ,EAAqB,KACrBC,GAAcJ,EAAW,SAAQ,CACnC,EAEAD,EAAO,UACLS,EACER,EACA,SAACM,EAAK,CACJL,EAAW,GACXC,EAAYI,EACPH,GACHM,EAAUZ,EAAiBS,CAAK,CAAC,EAAE,UAChCH,EAAqBK,EAAyBR,EAAYK,EAAaE,CAAe,CAAE,CAG/F,EACA,UAAA,CACEH,EAAa,IACZ,CAACH,GAAY,CAACE,GAAsBA,EAAmB,SAAWH,EAAW,SAAQ,CACxF,CAAC,CACF,CAEL,CAAC,CACH,CC3CM,SAAUU,GAAaC,EAAkBC,EAAyC,CAAzC,OAAAA,IAAA,SAAAA,EAAAC,IACtCC,GAAM,UAAA,CAAM,OAAAC,GAAMJ,EAAUC,CAAS,CAAzB,CAA0B,CAC/C,CCEM,SAAUI,GAAeC,EAAoBC,EAAsC,CAAtC,OAAAA,IAAA,SAAAA,EAAA,MAGjDA,EAAmBA,GAAgB,KAAhBA,EAAoBD,EAEhCE,EAAQ,SAACC,EAAQC,EAAU,CAChC,IAAIC,EAAiB,CAAA,EACjBC,EAAQ,EAEZH,EAAO,UACLI,EACEH,EACA,SAACI,EAAK,aACAC,EAAuB,KAKvBH,IAAUL,IAAsB,GAClCI,EAAQ,KAAK,CAAA,CAAE,MAIjB,QAAqBK,EAAAC,GAAAN,CAAO,EAAAO,EAAAF,EAAA,KAAA,EAAA,CAAAE,EAAA,KAAAA,EAAAF,EAAA,KAAA,EAAE,CAAzB,IAAMG,EAAMD,EAAA,MACfC,EAAO,KAAKL,CAAK,EAMbR,GAAca,EAAO,SACvBJ,EAASA,GAAM,KAANA,EAAU,CAAA,EACnBA,EAAO,KAAKI,CAAM,qGAItB,GAAIJ,MAIF,QAAqBK,EAAAH,GAAAF,CAAM,EAAAM,EAAAD,EAAA,KAAA,EAAA,CAAAC,EAAA,KAAAA,EAAAD,EAAA,KAAA,EAAE,CAAxB,IAAMD,EAAME,EAAA,MACfC,GAAUX,EAASQ,CAAM,EACzBT,EAAW,KAAKS,CAAM,oGAG5B,EACA,UAAA,aAGE,QAAqBI,EAAAN,GAAAN,CAAO,EAAAa,EAAAD,EAAA,KAAA,EAAA,CAAAC,EAAA,KAAAA,EAAAD,EAAA,KAAA,EAAE,CAAzB,IAAMJ,EAAMK,EAAA,MACfd,EAAW,KAAKS,CAAM,oGAExBT,EAAW,SAAQ,CACrB,EAEA,OACA,UAAA,CAEEC,EAAU,IACZ,CAAC,CACF,CAEL,CAAC,CACH,CCbM,SAAUc,GACdC,EAAgD,CAEhD,OAAOC,EAAQ,SAACC,EAAQC,EAAU,CAChC,IAAIC,EAAgC,KAChCC,EAAY,GACZC,EAEJF,EAAWF,EAAO,UAChBK,EAAyBJ,EAAY,OAAW,OAAW,SAACK,EAAG,CAC7DF,EAAgBG,EAAUT,EAASQ,EAAKT,GAAWC,CAAQ,EAAEE,CAAM,CAAC,CAAC,EACjEE,GACFA,EAAS,YAAW,EACpBA,EAAW,KACXE,EAAc,UAAUH,CAAU,GAIlCE,EAAY,EAEhB,CAAC,CAAC,EAGAA,IAMFD,EAAS,YAAW,EACpBA,EAAW,KACXE,EAAe,UAAUH,CAAU,EAEvC,CAAC,CACH,CC/HM,SAAUO,GACdC,EACAC,EACAC,EACAC,EACAC,EAAqC,CAErC,OAAO,SAACC,EAAuBC,EAA2B,CAIxD,IAAIC,EAAWL,EAIXM,EAAaP,EAEbQ,EAAQ,EAGZJ,EAAO,UACLK,EACEJ,EACA,SAACK,EAAK,CAEJ,IAAMC,EAAIH,IAEVD,EAAQD,EAEJP,EAAYQ,EAAOG,EAAOC,CAAC,GAIzBL,EAAW,GAAOI,GAGxBR,GAAcG,EAAW,KAAKE,CAAK,CACrC,EAGAJ,GACG,UAAA,CACCG,GAAYD,EAAW,KAAKE,CAAK,EACjCF,EAAW,SAAQ,CACrB,CAAE,CACL,CAEL,CACF,CCnCM,SAAUO,IAAa,SAAOC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GAClC,IAAMC,EAAiBC,GAAkBH,CAAI,EAC7C,OAAOE,EACHE,GAAKL,GAAa,MAAA,OAAAM,EAAA,CAAA,EAAAC,EAAKN,CAAoC,CAAA,CAAA,EAAGO,GAAiBL,CAAc,CAAC,EAC9FM,EAAQ,SAACC,EAAQC,EAAU,CACzBC,GAAiBN,EAAA,CAAEI,CAAM,EAAAH,EAAKM,GAAeZ,CAAI,CAAC,CAAA,CAAA,EAAGU,CAAU,CACjE,CAAC,CACP,CCUM,SAAUG,IAAiB,SAC/BC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GAEA,OAAOC,GAAa,MAAA,OAAAC,EAAA,CAAA,EAAAC,EAAIJ,CAAY,CAAA,CAAA,CACtC,CC+BM,SAAUK,GACdC,EACAC,EAA6G,CAE7G,OAAOC,EAAWD,CAAc,EAAIE,GAASH,EAASC,EAAgB,CAAC,EAAIE,GAASH,EAAS,CAAC,CAChG,CCpBM,SAAUI,GAAgBC,EAAiBC,EAAyC,CAAzC,OAAAA,IAAA,SAAAA,EAAAC,IACxCC,EAAQ,SAACC,EAAQC,EAAU,CAChC,IAAIC,EAAkC,KAClCC,EAAsB,KACtBC,EAA0B,KAExBC,EAAO,UAAA,CACX,GAAIH,EAAY,CAEdA,EAAW,YAAW,EACtBA,EAAa,KACb,IAAMI,EAAQH,EACdA,EAAY,KACZF,EAAW,KAAKK,CAAK,EAEzB,EACA,SAASC,GAAY,CAInB,IAAMC,EAAaJ,EAAYR,EACzBa,EAAMZ,EAAU,IAAG,EACzB,GAAIY,EAAMD,EAAY,CAEpBN,EAAa,KAAK,SAAS,OAAWM,EAAaC,CAAG,EACtDR,EAAW,IAAIC,CAAU,EACzB,OAGFG,EAAI,CACN,CAEAL,EAAO,UACLU,EACET,EACA,SAACK,EAAQ,CACPH,EAAYG,EACZF,EAAWP,EAAU,IAAG,EAGnBK,IACHA,EAAaL,EAAU,SAASU,EAAcX,CAAO,EACrDK,EAAW,IAAIC,CAAU,EAE7B,EACA,UAAA,CAGEG,EAAI,EACJJ,EAAW,SAAQ,CACrB,EAEA,OACA,UAAA,CAEEE,EAAYD,EAAa,IAC3B,CAAC,CACF,CAEL,CAAC,CACH,CCpFM,SAAUS,GAAqBC,EAAe,CAClD,OAAOC,EAAQ,SAACC,EAAQC,EAAU,CAChC,IAAIC,EAAW,GACfF,EAAO,UACLG,EACEF,EACA,SAACG,EAAK,CACJF,EAAW,GACXD,EAAW,KAAKG,CAAK,CACvB,EACA,UAAA,CACOF,GACHD,EAAW,KAAKH,CAAa,EAE/BG,EAAW,SAAQ,CACrB,CAAC,CACF,CAEL,CAAC,CACH,CCXM,SAAUI,GAAQC,EAAa,CACnC,OAAOA,GAAS,EAEZ,UAAA,CAAM,OAAAC,CAAA,EACNC,EAAQ,SAACC,EAAQC,EAAU,CACzB,IAAIC,EAAO,EACXF,EAAO,UACLG,EAAyBF,EAAY,SAACG,EAAK,CAIrC,EAAEF,GAAQL,IACZI,EAAW,KAAKG,CAAK,EAIjBP,GAASK,GACXD,EAAW,SAAQ,EAGzB,CAAC,CAAC,CAEN,CAAC,CACP,CC9BM,SAAUI,IAAc,CAC5B,OAAOC,EAAQ,SAACC,EAAQC,EAAU,CAChCD,EAAO,UAAUE,EAAyBD,EAAYE,EAAI,CAAC,CAC7D,CAAC,CACH,CCCM,SAAUC,GAASC,EAAQ,CAC/B,OAAOC,EAAI,UAAA,CAAM,OAAAD,CAAA,CAAK,CACxB,CC2BM,SAAUE,GACdC,EACAC,EAAmC,CAEnC,OAAIA,EAEK,SAACC,EAAqB,CAC3B,OAAAC,GAAOF,EAAkB,KAAKG,GAAK,CAAC,EAAGC,GAAc,CAAE,EAAGH,EAAO,KAAKH,GAAUC,CAAqB,CAAC,CAAC,CAAvG,EAGGM,GAAS,SAACC,EAAOC,EAAK,CAAK,OAAAR,EAAsBO,EAAOC,CAAK,EAAE,KAAKJ,GAAK,CAAC,EAAGK,GAAMF,CAAK,CAAC,CAA9D,CAA+D,CACnG,CCxBM,SAAUG,GAASC,EAAoBC,EAAyC,CAAzCA,IAAA,SAAAA,EAAAC,IAC3C,IAAMC,EAAWC,GAAMJ,EAAKC,CAAS,EACrC,OAAOI,GAAU,UAAA,CAAM,OAAAF,CAAA,CAAQ,CACjC,CC0EM,SAAUG,EACdC,EACAC,EAA0D,CAA1D,OAAAA,IAAA,SAAAA,EAA+BC,IAK/BF,EAAaA,GAAU,KAAVA,EAAcG,GAEpBC,EAAQ,SAACC,EAAQC,EAAU,CAGhC,IAAIC,EAEAC,EAAQ,GAEZH,EAAO,UACLI,EAAyBH,EAAY,SAACI,EAAK,CAEzC,IAAMC,EAAaV,EAAYS,CAAK,GAKhCF,GAAS,CAACR,EAAYO,EAAaI,CAAU,KAM/CH,EAAQ,GACRD,EAAcI,EAGdL,EAAW,KAAKI,CAAK,EAEzB,CAAC,CAAC,CAEN,CAAC,CACH,CAEA,SAASP,GAAeS,EAAQC,EAAM,CACpC,OAAOD,IAAMC,CACf,CCjHM,SAAUC,EAA8CC,EAAQC,EAAuC,CAC3G,OAAOC,EAAqB,SAACC,EAAMC,EAAI,CAAK,OAAAH,EAAUA,EAAQE,EAAEH,GAAMI,EAAEJ,EAAI,EAAIG,EAAEH,KAASI,EAAEJ,EAAjD,CAAqD,CACnG,CCLM,SAAUK,IAAO,SAAIC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GACzB,OAAO,SAACC,EAAqB,CAAK,OAAAC,GAAOD,EAAQE,EAAE,MAAA,OAAAC,EAAA,CAAA,EAAAC,EAAIN,CAAM,CAAA,CAAA,CAAA,CAA3B,CACpC,CCHM,SAAUO,EAAYC,EAAoB,CAC9C,OAAOC,EAAQ,SAACC,EAAQC,EAAU,CAGhC,GAAI,CACFD,EAAO,UAAUC,CAAU,UAE3BA,EAAW,IAAIH,CAAQ,EAE3B,CAAC,CACH,CC9BM,SAAUI,GAAYC,EAAa,CACvC,OAAOA,GAAS,EACZ,UAAA,CAAM,OAAAC,CAAA,EACNC,EAAQ,SAACC,EAAQC,EAAU,CAKzB,IAAIC,EAAc,CAAA,EAClBF,EAAO,UACLG,EACEF,EACA,SAACG,EAAK,CAEJF,EAAO,KAAKE,CAAK,EAGjBP,EAAQK,EAAO,QAAUA,EAAO,MAAK,CACvC,EACA,UAAA,aAGE,QAAoBG,EAAAC,GAAAJ,CAAM,EAAAK,EAAAF,EAAA,KAAA,EAAA,CAAAE,EAAA,KAAAA,EAAAF,EAAA,KAAA,EAAE,CAAvB,IAAMD,EAAKG,EAAA,MACdN,EAAW,KAAKG,CAAK,oGAEvBH,EAAW,SAAQ,CACrB,EAEA,OACA,UAAA,CAEEC,EAAS,IACX,CAAC,CACF,CAEL,CAAC,CACP,CC1DM,SAAUM,IAAK,SAAIC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GACvB,IAAMC,EAAYC,GAAaH,CAAI,EAC7BI,EAAaC,GAAUL,EAAM,GAAQ,EAC3C,OAAAA,EAAOM,GAAeN,CAAI,EAEnBO,EAAQ,SAACC,EAAQC,EAAU,CAChCC,GAASN,CAAU,EAAEO,GAAIC,EAAA,CAAEJ,CAAM,EAAAK,EAAMb,CAA6B,CAAA,EAAGE,CAAS,CAAC,EAAE,UAAUO,CAAU,CACzG,CAAC,CACH,CCcM,SAAUK,IAAS,SACvBC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GAEA,OAAOC,GAAK,MAAA,OAAAC,EAAA,CAAA,EAAAC,EAAIJ,CAAY,CAAA,CAAA,CAC9B,CCmEM,SAAUK,GAAUC,EAAqC,OACzDC,EAAQ,IACRC,EAEJ,OAAIF,GAAiB,OACf,OAAOA,GAAkB,UACxBG,EAA4BH,EAAa,MAAzCC,EAAKE,IAAA,OAAG,IAAQA,EAAED,EAAUF,EAAa,OAE5CC,EAAQD,GAILC,GAAS,EACZ,UAAA,CAAM,OAAAG,CAAA,EACNC,EAAQ,SAACC,EAAQC,EAAU,CACzB,IAAIC,EAAQ,EACRC,EAEEC,EAAc,UAAA,CAGlB,GAFAD,GAAS,MAATA,EAAW,YAAW,EACtBA,EAAY,KACRP,GAAS,KAAM,CACjB,IAAMS,EAAW,OAAOT,GAAU,SAAWU,GAAMV,CAAK,EAAIW,EAAUX,EAAMM,CAAK,CAAC,EAC5EM,EAAqBC,EAAyBR,EAAY,UAAA,CAC9DO,EAAmB,YAAW,EAC9BE,EAAiB,CACnB,CAAC,EACDL,EAAS,UAAUG,CAAkB,OAErCE,EAAiB,CAErB,EAEMA,EAAoB,UAAA,CACxB,IAAIC,EAAY,GAChBR,EAAYH,EAAO,UACjBS,EAAyBR,EAAY,OAAW,UAAA,CAC1C,EAAEC,EAAQP,EACRQ,EACFC,EAAW,EAEXO,EAAY,GAGdV,EAAW,SAAQ,CAEvB,CAAC,CAAC,EAGAU,GACFP,EAAW,CAEf,EAEAM,EAAiB,CACnB,CAAC,CACP,CC7HM,SAAUE,GAAUC,EAAyB,CACjD,OAAOC,EAAQ,SAACC,EAAQC,EAAU,CAChC,IAAIC,EAAW,GACXC,EAAsB,KAC1BH,EAAO,UACLI,EAAyBH,EAAY,SAACI,EAAK,CACzCH,EAAW,GACXC,EAAYE,CACd,CAAC,CAAC,EAEJP,EAAS,UACPM,EACEH,EACA,UAAA,CACE,GAAIC,EAAU,CACZA,EAAW,GACX,IAAMG,EAAQF,EACdA,EAAY,KACZF,EAAW,KAAKI,CAAK,EAEzB,EACAC,EAAI,CACL,CAEL,CAAC,CACH,CCgBM,SAAUC,GAAcC,EAA6DC,EAAQ,CAMjG,OAAOC,EAAQC,GAAcH,EAAaC,EAAW,UAAU,QAAU,EAAG,EAAI,CAAC,CACnF,CCgDM,SAAUG,GAASC,EAA4B,CAA5BA,IAAA,SAAAA,EAAA,CAAA,GACf,IAAAC,EAAgHD,EAAO,UAAvHE,EAASD,IAAA,OAAG,UAAA,CAAM,OAAA,IAAIE,CAAJ,EAAgBF,EAAEG,EAA4EJ,EAAO,aAAnFK,EAAYD,IAAA,OAAG,GAAIA,EAAEE,EAAuDN,EAAO,gBAA9DO,EAAeD,IAAA,OAAG,GAAIA,EAAEE,EAA+BR,EAAO,oBAAtCS,EAAmBD,IAAA,OAAG,GAAIA,EAUnH,OAAO,SAACE,EAAa,CACnB,IAAIC,EACAC,EACAC,EACAC,EAAW,EACXC,EAAe,GACfC,EAAa,GAEXC,EAAc,UAAA,CAClBL,GAAe,MAAfA,EAAiB,YAAW,EAC5BA,EAAkB,MACpB,EAGMM,EAAQ,UAAA,CACZD,EAAW,EACXN,EAAaE,EAAU,OACvBE,EAAeC,EAAa,EAC9B,EACMG,EAAsB,UAAA,CAG1B,IAAMC,EAAOT,EACbO,EAAK,EACLE,GAAI,MAAJA,EAAM,YAAW,CACnB,EAEA,OAAOC,EAAc,SAACC,EAAQC,GAAU,CACtCT,IACI,CAACE,GAAc,CAACD,GAClBE,EAAW,EAOb,IAAMO,GAAQX,EAAUA,GAAO,KAAPA,EAAWX,EAAS,EAO5CqB,GAAW,IAAI,UAAA,CACbT,IAKIA,IAAa,GAAK,CAACE,GAAc,CAACD,IACpCH,EAAkBa,GAAYN,EAAqBV,CAAmB,EAE1E,CAAC,EAIDe,GAAK,UAAUD,EAAU,EAGvB,CAACZ,GAIDG,EAAW,IAOXH,EAAa,IAAIe,GAAe,CAC9B,KAAM,SAACC,GAAK,CAAK,OAAAH,GAAK,KAAKG,EAAK,CAAf,EACjB,MAAO,SAACC,GAAG,CACTZ,EAAa,GACbC,EAAW,EACXL,EAAkBa,GAAYP,EAAOb,EAAcuB,EAAG,EACtDJ,GAAK,MAAMI,EAAG,CAChB,EACA,SAAU,UAAA,CACRb,EAAe,GACfE,EAAW,EACXL,EAAkBa,GAAYP,EAAOX,CAAe,EACpDiB,GAAK,SAAQ,CACf,EACD,EACDK,EAAUP,CAAM,EAAE,UAAUX,CAAU,EAE1C,CAAC,EAAED,CAAa,CAClB,CACF,CAEA,SAASe,GACPP,EACAY,EAA+C,SAC/CC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,EAAA,GAAA,UAAAA,GAEA,GAAIF,IAAO,GAAM,CACfZ,EAAK,EACL,OAGF,GAAIY,IAAO,GAIX,KAAMG,EAAe,IAAIP,GAAe,CACtC,KAAM,UAAA,CACJO,EAAa,YAAW,EACxBf,EAAK,CACP,EACD,EAED,OAAOY,EAAE,MAAA,OAAAI,EAAA,CAAA,EAAAC,EAAIJ,CAAI,CAAA,CAAA,EAAE,UAAUE,CAAY,EAC3C,CClHM,SAAUG,EACdC,EACAC,EACAC,EAAyB,WAErBC,EACAC,EAAW,GACf,OAAIJ,GAAsB,OAAOA,GAAuB,UACnDK,EAA8EL,EAAkB,WAAhGG,EAAUE,IAAA,OAAG,IAAQA,EAAEC,EAAuDN,EAAkB,WAAzEC,EAAUK,IAAA,OAAG,IAAQA,EAAEC,EAAgCP,EAAkB,SAAlDI,EAAQG,IAAA,OAAG,GAAKA,EAAEL,EAAcF,EAAkB,WAEnGG,EAAcH,GAAkB,KAAlBA,EAAsB,IAE/BQ,GAAS,CACd,UAAW,UAAA,CAAM,OAAA,IAAIC,GAAcN,EAAYF,EAAYC,CAAS,CAAnD,EACjB,aAAc,GACd,gBAAiB,GACjB,oBAAqBE,EACtB,CACH,CCvIM,SAAUM,GAAQC,EAAa,CACnC,OAAOC,EAAO,SAACC,EAAGC,EAAK,CAAK,OAAAH,GAASG,CAAT,CAAc,CAC5C,CCWM,SAAUC,GAAaC,EAAyB,CACpD,OAAOC,EAAQ,SAACC,EAAQC,EAAU,CAChC,IAAIC,EAAS,GAEPC,EAAiBC,EACrBH,EACA,UAAA,CACEE,GAAc,MAAdA,EAAgB,YAAW,EAC3BD,EAAS,EACX,EACAG,EAAI,EAGNC,EAAUR,CAAQ,EAAE,UAAUK,CAAc,EAE5CH,EAAO,UAAUI,EAAyBH,EAAY,SAACM,EAAK,CAAK,OAAAL,GAAUD,EAAW,KAAKM,CAAK,CAA/B,CAAgC,CAAC,CACpG,CAAC,CACH,CCRM,SAAUC,GAAS,SAAOC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GAC9B,IAAMC,EAAYC,GAAaH,CAAM,EACrC,OAAOI,EAAQ,SAACC,EAAQC,EAAU,EAI/BJ,EAAYK,GAAOP,EAAQK,EAAQH,CAAS,EAAIK,GAAOP,EAAQK,CAAM,GAAG,UAAUC,CAAU,CAC/F,CAAC,CACH,CCmBM,SAAUE,EACdC,EACAC,EAA6G,CAE7G,OAAOC,EAAQ,SAACC,EAAQC,EAAU,CAChC,IAAIC,EAAyD,KACzDC,EAAQ,EAERC,EAAa,GAIXC,EAAgB,UAAA,CAAM,OAAAD,GAAc,CAACF,GAAmBD,EAAW,SAAQ,CAArD,EAE5BD,EAAO,UACLM,EACEL,EACA,SAACM,EAAK,CAEJL,GAAe,MAAfA,EAAiB,YAAW,EAC5B,IAAIM,EAAa,EACXC,EAAaN,IAEnBO,EAAUb,EAAQU,EAAOE,CAAU,CAAC,EAAE,UACnCP,EAAkBI,EACjBL,EAIA,SAACU,EAAU,CAAK,OAAAV,EAAW,KAAKH,EAAiBA,EAAeS,EAAOI,EAAYF,EAAYD,GAAY,EAAIG,CAAU,CAAzG,EAChB,UAAA,CAIET,EAAkB,KAClBG,EAAa,CACf,CAAC,CACD,CAEN,EACA,UAAA,CACED,EAAa,GACbC,EAAa,CACf,CAAC,CACF,CAEL,CAAC,CACH,CCvFM,SAAUO,EAAaC,EAA8B,CACzD,OAAOC,EAAQ,SAACC,EAAQC,EAAU,CAChCC,EAAUJ,CAAQ,EAAE,UAAUK,EAAyBF,EAAY,UAAA,CAAM,OAAAA,EAAW,SAAQ,CAAnB,EAAuBG,EAAI,CAAC,EACrG,CAACH,EAAW,QAAUD,EAAO,UAAUC,CAAU,CACnD,CAAC,CACH,CCIM,SAAUI,GAAaC,EAAiDC,EAAiB,CAAjB,OAAAA,IAAA,SAAAA,EAAA,IACrEC,EAAQ,SAACC,EAAQC,EAAU,CAChC,IAAIC,EAAQ,EACZF,EAAO,UACLG,EAAyBF,EAAY,SAACG,EAAK,CACzC,IAAMC,EAASR,EAAUO,EAAOF,GAAO,GACtCG,GAAUP,IAAcG,EAAW,KAAKG,CAAK,EAC9C,CAACC,GAAUJ,EAAW,SAAQ,CAChC,CAAC,CAAC,CAEN,CAAC,CACH,CCyCM,SAAUK,EACdC,EACAC,EACAC,EAA8B,CAK9B,IAAMC,EACJC,EAAWJ,CAAc,GAAKC,GAASC,EAElC,CAAE,KAAMF,EAA2E,MAAKC,EAAE,SAAQC,CAAA,EACnGF,EAEN,OAAOG,EACHE,EAAQ,SAACC,EAAQC,EAAU,QACzBC,EAAAL,EAAY,aAAS,MAAAK,IAAA,QAAAA,EAAA,KAArBL,CAAW,EACX,IAAIM,EAAU,GACdH,EAAO,UACLI,EACEH,EACA,SAACI,EAAK,QACJH,EAAAL,EAAY,QAAI,MAAAK,IAAA,QAAAA,EAAA,KAAhBL,EAAmBQ,CAAK,EACxBJ,EAAW,KAAKI,CAAK,CACvB,EACA,UAAA,OACEF,EAAU,IACVD,EAAAL,EAAY,YAAQ,MAAAK,IAAA,QAAAA,EAAA,KAApBL,CAAW,EACXI,EAAW,SAAQ,CACrB,EACA,SAACK,EAAG,OACFH,EAAU,IACVD,EAAAL,EAAY,SAAK,MAAAK,IAAA,QAAAA,EAAA,KAAjBL,EAAoBS,CAAG,EACvBL,EAAW,MAAMK,CAAG,CACtB,EACA,UAAA,SACMH,KACFD,EAAAL,EAAY,eAAW,MAAAK,IAAA,QAAAA,EAAA,KAAvBL,CAAW,IAEbU,EAAAV,EAAY,YAAQ,MAAAU,IAAA,QAAAA,EAAA,KAApBV,CAAW,CACb,CAAC,CACF,CAEL,CAAC,EAIDW,EACN,CC9IO,IAAMC,GAAwC,CACnD,QAAS,GACT,SAAU,IAiDN,SAAUC,GACdC,EACAC,EAA8C,CAA9C,OAAAA,IAAA,SAAAA,EAAAH,IAEOI,EAAQ,SAACC,EAAQC,EAAU,CACxB,IAAAC,EAAsBJ,EAAM,QAAnBK,EAAaL,EAAM,SAChCM,EAAW,GACXC,EAAsB,KACtBC,EAAiC,KACjCC,EAAa,GAEXC,EAAgB,UAAA,CACpBF,GAAS,MAATA,EAAW,YAAW,EACtBA,EAAY,KACRH,IACFM,EAAI,EACJF,GAAcN,EAAW,SAAQ,EAErC,EAEMS,EAAoB,UAAA,CACxBJ,EAAY,KACZC,GAAcN,EAAW,SAAQ,CACnC,EAEMU,EAAgB,SAACC,EAAQ,CAC7B,OAACN,EAAYO,EAAUhB,EAAiBe,CAAK,CAAC,EAAE,UAAUE,EAAyBb,EAAYO,EAAeE,CAAiB,CAAC,CAAhI,EAEID,EAAO,UAAA,CACX,GAAIL,EAAU,CAIZA,EAAW,GACX,IAAMQ,EAAQP,EACdA,EAAY,KAEZJ,EAAW,KAAKW,CAAK,EACrB,CAACL,GAAcI,EAAcC,CAAK,EAEtC,EAEAZ,EAAO,UACLc,EACEb,EAMA,SAACW,EAAK,CACJR,EAAW,GACXC,EAAYO,EACZ,EAAEN,GAAa,CAACA,EAAU,UAAYJ,EAAUO,EAAI,EAAKE,EAAcC,CAAK,EAC9E,EACA,UAAA,CACEL,EAAa,GACb,EAAEJ,GAAYC,GAAYE,GAAa,CAACA,EAAU,SAAWL,EAAW,SAAQ,CAClF,CAAC,CACF,CAEL,CAAC,CACH,CCvEM,SAAUc,GACdC,EACAC,EACAC,EAA8B,CAD9BD,IAAA,SAAAA,EAAAE,IACAD,IAAA,SAAAA,EAAAE,IAEA,IAAMC,EAAYC,GAAMN,EAAUC,CAAS,EAC3C,OAAOM,GAAS,UAAA,CAAM,OAAAF,CAAA,EAAWH,CAAM,CACzC,CCJM,SAAUM,IAAc,SAAOC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GACnC,IAAMC,EAAUC,GAAkBH,CAAM,EAExC,OAAOI,EAAQ,SAACC,EAAQC,EAAU,CAehC,QAdMC,EAAMP,EAAO,OACbQ,EAAc,IAAI,MAAMD,CAAG,EAI7BE,EAAWT,EAAO,IAAI,UAAA,CAAM,MAAA,EAAA,CAAK,EAGjCU,EAAQ,cAMHC,EAAC,CACRC,EAAUZ,EAAOW,EAAE,EAAE,UACnBE,EACEP,EACA,SAACQ,EAAK,CACJN,EAAYG,GAAKG,EACb,CAACJ,GAAS,CAACD,EAASE,KAEtBF,EAASE,GAAK,IAKbD,EAAQD,EAAS,MAAMM,EAAQ,KAAON,EAAW,MAEtD,EAGAO,EAAI,CACL,GAnBIL,EAAI,EAAGA,EAAIJ,EAAKI,MAAhBA,CAAC,EAwBVN,EAAO,UACLQ,EAAyBP,EAAY,SAACQ,EAAK,CACzC,GAAIJ,EAAO,CAET,IAAMO,EAAMC,EAAA,CAAIJ,CAAK,EAAAK,EAAKX,CAAW,CAAA,EACrCF,EAAW,KAAKJ,EAAUA,EAAO,MAAA,OAAAgB,EAAA,CAAA,EAAAC,EAAIF,CAAM,CAAA,CAAA,EAAIA,CAAM,EAEzD,CAAC,CAAC,CAEN,CAAC,CACH,CCxFM,SAAUG,IAAG,SAAOC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GACxB,OAAOC,EAAQ,SAACC,EAAQC,EAAU,CAChCL,GAAS,MAAA,OAAAM,EAAA,CAACF,CAA8B,EAAAG,EAAMN,CAAuC,CAAA,CAAA,EAAE,UAAUI,CAAU,CAC7G,CAAC,CACH,CCCM,SAAUG,IAAO,SAAkCC,EAAA,CAAA,EAAAC,EAAA,EAAAA,EAAA,UAAA,OAAAA,IAAAD,EAAAC,GAAA,UAAAA,GACvD,OAAOC,GAAG,MAAA,OAAAC,EAAA,CAAA,EAAAC,EAAIJ,CAAW,CAAA,CAAA,CAC3B,CCYO,SAASK,IAAmC,CACjD,IAAMC,EAAY,IAAIC,GAAwB,CAAC,EAC/C,OAAAC,EAAU,SAAU,mBAAoB,CAAE,KAAM,EAAK,CAAC,EACnD,UAAU,IAAMF,EAAU,KAAK,QAAQ,CAAC,EAGpCA,CACT,CCHO,SAASG,EACdC,EAAkBC,EAAmB,SAChC,CACL,OAAO,MAAM,KAAKA,EAAK,iBAAoBD,CAAQ,CAAC,CACtD,CAuBO,SAASE,EACdF,EAAkBC,EAAmB,SAClC,CACH,IAAME,EAAKC,GAAsBJ,EAAUC,CAAI,EAC/C,GAAI,OAAOE,GAAO,YAChB,MAAM,IAAI,eACR,8BAA8BH,kBAChC,EAGF,OAAOG,CACT,CAsBO,SAASC,GACdJ,EAAkBC,EAAmB,SACtB,CACf,OAAOA,EAAK,cAAiBD,CAAQ,GAAK,MAC5C,CAOO,SAASK,IAA4C,CAC1D,OAAO,SAAS,yBAAyB,aACrC,SAAS,eAAiB,MAEhC,CClEO,SAASC,GACdC,EACqB,CACrB,OAAOC,EACLC,EAAU,SAAS,KAAM,SAAS,EAClCA,EAAU,SAAS,KAAM,UAAU,CACrC,EACG,KACCC,GAAa,CAAC,EACdC,EAAI,IAAM,CACR,IAAMC,EAASC,GAAiB,EAChC,OAAO,OAAOD,GAAW,YACrBL,EAAG,SAASK,CAAM,EAClB,EACN,CAAC,EACDE,EAAUP,IAAOM,GAAiB,CAAC,EACnCE,EAAqB,CACvB,CACJ,CChBO,SAASC,GACdC,EACe,CACf,MAAO,CACL,EAAGA,EAAG,WACN,EAAGA,EAAG,SACR,CACF,CAWO,SAASC,GACdD,EAC2B,CAC3B,OAAOE,EACLC,EAAU,OAAQ,MAAM,EACxBA,EAAU,OAAQ,QAAQ,CAC5B,EACG,KACCC,GAAU,EAAGC,EAAuB,EACpCC,EAAI,IAAMP,GAAiBC,CAAE,CAAC,EAC9BO,EAAUR,GAAiBC,CAAE,CAAC,CAChC,CACJ,CCxCO,SAASQ,GACdC,EACe,CACf,MAAO,CACL,EAAGA,EAAG,WACN,EAAGA,EAAG,SACR,CACF,CAWO,SAASC,GACdD,EAC2B,CAC3B,OAAOE,EACLC,EAAUH,EAAI,QAAQ,EACtBG,EAAU,OAAQ,QAAQ,CAC5B,EACG,KACCC,GAAU,EAAGC,EAAuB,EACpCC,EAAI,IAAMP,GAAwBC,CAAE,CAAC,EACrCO,EAAUR,GAAwBC,CAAE,CAAC,CACvC,CACJ,CCpEA,IAAIQ,GAAW,UAAY,CACvB,GAAI,OAAO,KAAQ,YACf,OAAO,IASX,SAASC,EAASC,EAAKC,EAAK,CACxB,IAAIC,EAAS,GACb,OAAAF,EAAI,KAAK,SAAUG,EAAOC,EAAO,CAC7B,OAAID,EAAM,KAAOF,GACbC,EAASE,EACF,IAEJ,EACX,CAAC,EACMF,CACX,CACA,OAAsB,UAAY,CAC9B,SAASG,GAAU,CACf,KAAK,YAAc,CAAC,CACxB,CACA,cAAO,eAAeA,EAAQ,UAAW,OAAQ,CAI7C,IAAK,UAAY,CACb,OAAO,KAAK,YAAY,MAC5B,EACA,WAAY,GACZ,aAAc,EAClB,CAAC,EAKDA,EAAQ,UAAU,IAAM,SAAUJ,EAAK,CACnC,IAAIG,EAAQL,EAAS,KAAK,YAAaE,CAAG,EACtCE,EAAQ,KAAK,YAAYC,GAC7B,OAAOD,GAASA,EAAM,EAC1B,EAMAE,EAAQ,UAAU,IAAM,SAAUJ,EAAKK,EAAO,CAC1C,IAAIF,EAAQL,EAAS,KAAK,YAAaE,CAAG,EACtC,CAACG,EACD,KAAK,YAAYA,GAAO,GAAKE,EAG7B,KAAK,YAAY,KAAK,CAACL,EAAKK,CAAK,CAAC,CAE1C,EAKAD,EAAQ,UAAU,OAAS,SAAUJ,EAAK,CACtC,IAAIM,EAAU,KAAK,YACfH,EAAQL,EAASQ,EAASN,CAAG,EAC7B,CAACG,GACDG,EAAQ,OAAOH,EAAO,CAAC,CAE/B,EAKAC,EAAQ,UAAU,IAAM,SAAUJ,EAAK,CACnC,MAAO,CAAC,CAAC,CAACF,EAAS,KAAK,YAAaE,CAAG,CAC5C,EAIAI,EAAQ,UAAU,MAAQ,UAAY,CAClC,KAAK,YAAY,OAAO,CAAC,CAC7B,EAMAA,EAAQ,UAAU,QAAU,SAAUG,EAAUC,EAAK,CAC7CA,IAAQ,SAAUA,EAAM,MAC5B,QAASC,EAAK,EAAGC,EAAK,KAAK,YAAaD,EAAKC,EAAG,OAAQD,IAAM,CAC1D,IAAIP,EAAQQ,EAAGD,GACfF,EAAS,KAAKC,EAAKN,EAAM,GAAIA,EAAM,EAAE,CACzC,CACJ,EACOE,CACX,EAAE,CACN,EAAG,EAKCO,GAAY,OAAO,QAAW,aAAe,OAAO,UAAa,aAAe,OAAO,WAAa,SAGpGC,GAAY,UAAY,CACxB,OAAI,OAAO,QAAW,aAAe,OAAO,OAAS,KAC1C,OAEP,OAAO,MAAS,aAAe,KAAK,OAAS,KACtC,KAEP,OAAO,QAAW,aAAe,OAAO,OAAS,KAC1C,OAGJ,SAAS,aAAa,EAAE,CACnC,EAAG,EAQCC,GAA2B,UAAY,CACvC,OAAI,OAAO,uBAA0B,WAI1B,sBAAsB,KAAKD,EAAQ,EAEvC,SAAUL,EAAU,CAAE,OAAO,WAAW,UAAY,CAAE,OAAOA,EAAS,KAAK,IAAI,CAAC,CAAG,EAAG,IAAO,EAAE,CAAG,CAC7G,EAAG,EAGCO,GAAkB,EAStB,SAASC,GAAUR,EAAUS,EAAO,CAChC,IAAIC,EAAc,GAAOC,EAAe,GAAOC,EAAe,EAO9D,SAASC,GAAiB,CAClBH,IACAA,EAAc,GACdV,EAAS,GAETW,GACAG,EAAM,CAEd,CAQA,SAASC,GAAkB,CACvBT,GAAwBO,CAAc,CAC1C,CAMA,SAASC,GAAQ,CACb,IAAIE,EAAY,KAAK,IAAI,EACzB,GAAIN,EAAa,CAEb,GAAIM,EAAYJ,EAAeL,GAC3B,OAMJI,EAAe,EACnB,MAEID,EAAc,GACdC,EAAe,GACf,WAAWI,EAAiBN,CAAK,EAErCG,EAAeI,CACnB,CACA,OAAOF,CACX,CAGA,IAAIG,GAAgB,GAGhBC,GAAiB,CAAC,MAAO,QAAS,SAAU,OAAQ,QAAS,SAAU,OAAQ,QAAQ,EAEvFC,GAA4B,OAAO,kBAAqB,YAIxDC,GAA0C,UAAY,CAMtD,SAASA,GAA2B,CAMhC,KAAK,WAAa,GAMlB,KAAK,qBAAuB,GAM5B,KAAK,mBAAqB,KAM1B,KAAK,WAAa,CAAC,EACnB,KAAK,iBAAmB,KAAK,iBAAiB,KAAK,IAAI,EACvD,KAAK,QAAUZ,GAAS,KAAK,QAAQ,KAAK,IAAI,EAAGS,EAAa,CAClE,CAOA,OAAAG,EAAyB,UAAU,YAAc,SAAUC,EAAU,CAC5D,CAAC,KAAK,WAAW,QAAQA,CAAQ,GAClC,KAAK,WAAW,KAAKA,CAAQ,EAG5B,KAAK,YACN,KAAK,SAAS,CAEtB,EAOAD,EAAyB,UAAU,eAAiB,SAAUC,EAAU,CACpE,IAAIC,EAAY,KAAK,WACjB1B,EAAQ0B,EAAU,QAAQD,CAAQ,EAElC,CAACzB,GACD0B,EAAU,OAAO1B,EAAO,CAAC,EAGzB,CAAC0B,EAAU,QAAU,KAAK,YAC1B,KAAK,YAAY,CAEzB,EAOAF,EAAyB,UAAU,QAAU,UAAY,CACrD,IAAIG,EAAkB,KAAK,iBAAiB,EAGxCA,GACA,KAAK,QAAQ,CAErB,EASAH,EAAyB,UAAU,iBAAmB,UAAY,CAE9D,IAAII,EAAkB,KAAK,WAAW,OAAO,SAAUH,EAAU,CAC7D,OAAOA,EAAS,aAAa,EAAGA,EAAS,UAAU,CACvD,CAAC,EAMD,OAAAG,EAAgB,QAAQ,SAAUH,EAAU,CAAE,OAAOA,EAAS,gBAAgB,CAAG,CAAC,EAC3EG,EAAgB,OAAS,CACpC,EAOAJ,EAAyB,UAAU,SAAW,UAAY,CAGlD,CAAChB,IAAa,KAAK,aAMvB,SAAS,iBAAiB,gBAAiB,KAAK,gBAAgB,EAChE,OAAO,iBAAiB,SAAU,KAAK,OAAO,EAC1Ce,IACA,KAAK,mBAAqB,IAAI,iBAAiB,KAAK,OAAO,EAC3D,KAAK,mBAAmB,QAAQ,SAAU,CACtC,WAAY,GACZ,UAAW,GACX,cAAe,GACf,QAAS,EACb,CAAC,IAGD,SAAS,iBAAiB,qBAAsB,KAAK,OAAO,EAC5D,KAAK,qBAAuB,IAEhC,KAAK,WAAa,GACtB,EAOAC,EAAyB,UAAU,YAAc,UAAY,CAGrD,CAAChB,IAAa,CAAC,KAAK,aAGxB,SAAS,oBAAoB,gBAAiB,KAAK,gBAAgB,EACnE,OAAO,oBAAoB,SAAU,KAAK,OAAO,EAC7C,KAAK,oBACL,KAAK,mBAAmB,WAAW,EAEnC,KAAK,sBACL,SAAS,oBAAoB,qBAAsB,KAAK,OAAO,EAEnE,KAAK,mBAAqB,KAC1B,KAAK,qBAAuB,GAC5B,KAAK,WAAa,GACtB,EAQAgB,EAAyB,UAAU,iBAAmB,SAAUjB,EAAI,CAChE,IAAIsB,EAAKtB,EAAG,aAAcuB,EAAeD,IAAO,OAAS,GAAKA,EAE1DE,EAAmBT,GAAe,KAAK,SAAUzB,EAAK,CACtD,MAAO,CAAC,CAAC,CAACiC,EAAa,QAAQjC,CAAG,CACtC,CAAC,EACGkC,GACA,KAAK,QAAQ,CAErB,EAMAP,EAAyB,YAAc,UAAY,CAC/C,OAAK,KAAK,YACN,KAAK,UAAY,IAAIA,GAElB,KAAK,SAChB,EAMAA,EAAyB,UAAY,KAC9BA,CACX,EAAE,EASEQ,GAAsB,SAAUC,EAAQC,EAAO,CAC/C,QAAS5B,EAAK,EAAGC,EAAK,OAAO,KAAK2B,CAAK,EAAG5B,EAAKC,EAAG,OAAQD,IAAM,CAC5D,IAAIT,EAAMU,EAAGD,GACb,OAAO,eAAe2B,EAAQpC,EAAK,CAC/B,MAAOqC,EAAMrC,GACb,WAAY,GACZ,SAAU,GACV,aAAc,EAClB,CAAC,CACL,CACA,OAAOoC,CACX,EAQIE,GAAe,SAAUF,EAAQ,CAIjC,IAAIG,EAAcH,GAAUA,EAAO,eAAiBA,EAAO,cAAc,YAGzE,OAAOG,GAAe3B,EAC1B,EAGI4B,GAAYC,GAAe,EAAG,EAAG,EAAG,CAAC,EAOzC,SAASC,GAAQrC,EAAO,CACpB,OAAO,WAAWA,CAAK,GAAK,CAChC,CAQA,SAASsC,GAAeC,EAAQ,CAE5B,QADIC,EAAY,CAAC,EACRpC,EAAK,EAAGA,EAAK,UAAU,OAAQA,IACpCoC,EAAUpC,EAAK,GAAK,UAAUA,GAElC,OAAOoC,EAAU,OAAO,SAAUC,EAAMC,EAAU,CAC9C,IAAI1C,EAAQuC,EAAO,UAAYG,EAAW,UAC1C,OAAOD,EAAOJ,GAAQrC,CAAK,CAC/B,EAAG,CAAC,CACR,CAOA,SAAS2C,GAAYJ,EAAQ,CAGzB,QAFIC,EAAY,CAAC,MAAO,QAAS,SAAU,MAAM,EAC7CI,EAAW,CAAC,EACPxC,EAAK,EAAGyC,EAAcL,EAAWpC,EAAKyC,EAAY,OAAQzC,IAAM,CACrE,IAAIsC,EAAWG,EAAYzC,GACvBJ,EAAQuC,EAAO,WAAaG,GAChCE,EAASF,GAAYL,GAAQrC,CAAK,CACtC,CACA,OAAO4C,CACX,CAQA,SAASE,GAAkBf,EAAQ,CAC/B,IAAIgB,EAAOhB,EAAO,QAAQ,EAC1B,OAAOK,GAAe,EAAG,EAAGW,EAAK,MAAOA,EAAK,MAAM,CACvD,CAOA,SAASC,GAA0BjB,EAAQ,CAGvC,IAAIkB,EAAclB,EAAO,YAAamB,EAAenB,EAAO,aAS5D,GAAI,CAACkB,GAAe,CAACC,EACjB,OAAOf,GAEX,IAAII,EAASN,GAAYF,CAAM,EAAE,iBAAiBA,CAAM,EACpDa,EAAWD,GAAYJ,CAAM,EAC7BY,EAAWP,EAAS,KAAOA,EAAS,MACpCQ,EAAUR,EAAS,IAAMA,EAAS,OAKlCS,EAAQhB,GAAQE,EAAO,KAAK,EAAGe,EAASjB,GAAQE,EAAO,MAAM,EAqBjE,GAlBIA,EAAO,YAAc,eAOjB,KAAK,MAAMc,EAAQF,CAAQ,IAAMF,IACjCI,GAASf,GAAeC,EAAQ,OAAQ,OAAO,EAAIY,GAEnD,KAAK,MAAMG,EAASF,CAAO,IAAMF,IACjCI,GAAUhB,GAAeC,EAAQ,MAAO,QAAQ,EAAIa,IAOxD,CAACG,GAAkBxB,CAAM,EAAG,CAK5B,IAAIyB,EAAgB,KAAK,MAAMH,EAAQF,CAAQ,EAAIF,EAC/CQ,EAAiB,KAAK,MAAMH,EAASF,CAAO,EAAIF,EAMhD,KAAK,IAAIM,CAAa,IAAM,IAC5BH,GAASG,GAET,KAAK,IAAIC,CAAc,IAAM,IAC7BH,GAAUG,EAElB,CACA,OAAOrB,GAAeQ,EAAS,KAAMA,EAAS,IAAKS,EAAOC,CAAM,CACpE,CAOA,IAAII,GAAwB,UAAY,CAGpC,OAAI,OAAO,oBAAuB,YACvB,SAAU3B,EAAQ,CAAE,OAAOA,aAAkBE,GAAYF,CAAM,EAAE,kBAAoB,EAKzF,SAAUA,EAAQ,CAAE,OAAQA,aAAkBE,GAAYF,CAAM,EAAE,YACrE,OAAOA,EAAO,SAAY,UAAa,CAC/C,EAAG,EAOH,SAASwB,GAAkBxB,EAAQ,CAC/B,OAAOA,IAAWE,GAAYF,CAAM,EAAE,SAAS,eACnD,CAOA,SAAS4B,GAAe5B,EAAQ,CAC5B,OAAKzB,GAGDoD,GAAqB3B,CAAM,EACpBe,GAAkBf,CAAM,EAE5BiB,GAA0BjB,CAAM,EAL5BI,EAMf,CAQA,SAASyB,GAAmBvD,EAAI,CAC5B,IAAIwD,EAAIxD,EAAG,EAAGyD,EAAIzD,EAAG,EAAGgD,EAAQhD,EAAG,MAAOiD,EAASjD,EAAG,OAElD0D,EAAS,OAAO,iBAAoB,YAAc,gBAAkB,OACpEC,EAAO,OAAO,OAAOD,EAAO,SAAS,EAEzC,OAAAjC,GAAmBkC,EAAM,CACrB,EAAGH,EAAG,EAAGC,EAAG,MAAOT,EAAO,OAAQC,EAClC,IAAKQ,EACL,MAAOD,EAAIR,EACX,OAAQC,EAASQ,EACjB,KAAMD,CACV,CAAC,EACMG,CACX,CAWA,SAAS5B,GAAeyB,EAAGC,EAAGT,EAAOC,EAAQ,CACzC,MAAO,CAAE,EAAGO,EAAG,EAAGC,EAAG,MAAOT,EAAO,OAAQC,CAAO,CACtD,CAMA,IAAIW,GAAmC,UAAY,CAM/C,SAASA,EAAkBlC,EAAQ,CAM/B,KAAK,eAAiB,EAMtB,KAAK,gBAAkB,EAMvB,KAAK,aAAeK,GAAe,EAAG,EAAG,EAAG,CAAC,EAC7C,KAAK,OAASL,CAClB,CAOA,OAAAkC,EAAkB,UAAU,SAAW,UAAY,CAC/C,IAAID,EAAOL,GAAe,KAAK,MAAM,EACrC,YAAK,aAAeK,EACZA,EAAK,QAAU,KAAK,gBACxBA,EAAK,SAAW,KAAK,eAC7B,EAOAC,EAAkB,UAAU,cAAgB,UAAY,CACpD,IAAID,EAAO,KAAK,aAChB,YAAK,eAAiBA,EAAK,MAC3B,KAAK,gBAAkBA,EAAK,OACrBA,CACX,EACOC,CACX,EAAE,EAEEC,GAAqC,UAAY,CAOjD,SAASA,EAAoBnC,EAAQoC,EAAU,CAC3C,IAAIC,EAAcR,GAAmBO,CAAQ,EAO7CrC,GAAmB,KAAM,CAAE,OAAQC,EAAQ,YAAaqC,CAAY,CAAC,CACzE,CACA,OAAOF,CACX,EAAE,EAEEG,GAAmC,UAAY,CAW/C,SAASA,EAAkBnE,EAAUoE,EAAYC,EAAa,CAc1D,GAPA,KAAK,oBAAsB,CAAC,EAM5B,KAAK,cAAgB,IAAI/E,GACrB,OAAOU,GAAa,WACpB,MAAM,IAAI,UAAU,yDAAyD,EAEjF,KAAK,UAAYA,EACjB,KAAK,YAAcoE,EACnB,KAAK,aAAeC,CACxB,CAOA,OAAAF,EAAkB,UAAU,QAAU,SAAUtC,EAAQ,CACpD,GAAI,CAAC,UAAU,OACX,MAAM,IAAI,UAAU,0CAA0C,EAGlE,GAAI,SAAO,SAAY,aAAe,EAAE,mBAAmB,SAG3D,IAAI,EAAEA,aAAkBE,GAAYF,CAAM,EAAE,SACxC,MAAM,IAAI,UAAU,uCAAuC,EAE/D,IAAIyC,EAAe,KAAK,cAEpBA,EAAa,IAAIzC,CAAM,IAG3ByC,EAAa,IAAIzC,EAAQ,IAAIkC,GAAkBlC,CAAM,CAAC,EACtD,KAAK,YAAY,YAAY,IAAI,EAEjC,KAAK,YAAY,QAAQ,GAC7B,EAOAsC,EAAkB,UAAU,UAAY,SAAUtC,EAAQ,CACtD,GAAI,CAAC,UAAU,OACX,MAAM,IAAI,UAAU,0CAA0C,EAGlE,GAAI,SAAO,SAAY,aAAe,EAAE,mBAAmB,SAG3D,IAAI,EAAEA,aAAkBE,GAAYF,CAAM,EAAE,SACxC,MAAM,IAAI,UAAU,uCAAuC,EAE/D,IAAIyC,EAAe,KAAK,cAEpB,CAACA,EAAa,IAAIzC,CAAM,IAG5ByC,EAAa,OAAOzC,CAAM,EACrByC,EAAa,MACd,KAAK,YAAY,eAAe,IAAI,GAE5C,EAMAH,EAAkB,UAAU,WAAa,UAAY,CACjD,KAAK,YAAY,EACjB,KAAK,cAAc,MAAM,EACzB,KAAK,YAAY,eAAe,IAAI,CACxC,EAOAA,EAAkB,UAAU,aAAe,UAAY,CACnD,IAAII,EAAQ,KACZ,KAAK,YAAY,EACjB,KAAK,cAAc,QAAQ,SAAUC,EAAa,CAC1CA,EAAY,SAAS,GACrBD,EAAM,oBAAoB,KAAKC,CAAW,CAElD,CAAC,CACL,EAOAL,EAAkB,UAAU,gBAAkB,UAAY,CAEtD,GAAI,EAAC,KAAK,UAAU,EAGpB,KAAIlE,EAAM,KAAK,aAEXF,EAAU,KAAK,oBAAoB,IAAI,SAAUyE,EAAa,CAC9D,OAAO,IAAIR,GAAoBQ,EAAY,OAAQA,EAAY,cAAc,CAAC,CAClF,CAAC,EACD,KAAK,UAAU,KAAKvE,EAAKF,EAASE,CAAG,EACrC,KAAK,YAAY,EACrB,EAMAkE,EAAkB,UAAU,YAAc,UAAY,CAClD,KAAK,oBAAoB,OAAO,CAAC,CACrC,EAMAA,EAAkB,UAAU,UAAY,UAAY,CAChD,OAAO,KAAK,oBAAoB,OAAS,CAC7C,EACOA,CACX,EAAE,EAKE7C,GAAY,OAAO,SAAY,YAAc,IAAI,QAAY,IAAIhC,GAKjEmF,GAAgC,UAAY,CAO5C,SAASA,EAAezE,EAAU,CAC9B,GAAI,EAAE,gBAAgByE,GAClB,MAAM,IAAI,UAAU,oCAAoC,EAE5D,GAAI,CAAC,UAAU,OACX,MAAM,IAAI,UAAU,0CAA0C,EAElE,IAAIL,EAAahD,GAAyB,YAAY,EAClDC,EAAW,IAAI8C,GAAkBnE,EAAUoE,EAAY,IAAI,EAC/D9C,GAAU,IAAI,KAAMD,CAAQ,CAChC,CACA,OAAOoD,CACX,EAAE,EAEF,CACI,UACA,YACA,YACJ,EAAE,QAAQ,SAAUC,EAAQ,CACxBD,GAAe,UAAUC,GAAU,UAAY,CAC3C,IAAIvE,EACJ,OAAQA,EAAKmB,GAAU,IAAI,IAAI,GAAGoD,GAAQ,MAAMvE,EAAI,SAAS,CACjE,CACJ,CAAC,EAED,IAAIP,GAAS,UAAY,CAErB,OAAI,OAAOS,GAAS,gBAAmB,YAC5BA,GAAS,eAEboE,EACX,EAAG,EAEIE,GAAQ/E,GCr2Bf,IAAMgF,GAAS,IAAIC,EAYbC,GAAYC,EAAM,IAAMC,EAC5B,IAAIC,GAAeC,GAAW,CAC5B,QAAWC,KAASD,EAClBN,GAAO,KAAKO,CAAK,CACrB,CAAC,CACH,CAAC,EACE,KACCC,EAAUC,GAAYC,EAAMC,GAAOP,EAAGK,CAAQ,CAAC,EAC5C,KACCG,EAAS,IAAMH,EAAS,WAAW,CAAC,CACtC,CACF,EACAI,EAAY,CAAC,CACf,EAaK,SAASC,GACdC,EACa,CACb,MAAO,CACL,MAAQA,EAAG,YACX,OAAQA,EAAG,YACb,CACF,CAuBO,SAASC,GACdD,EACyB,CACzB,OAAOb,GACJ,KACCe,EAAIR,GAAYA,EAAS,QAAQM,CAAE,CAAC,EACpCP,EAAUC,GAAYT,GACnB,KACCkB,EAAO,CAAC,CAAE,OAAAC,CAAO,IAAMA,IAAWJ,CAAE,EACpCH,EAAS,IAAMH,EAAS,UAAUM,CAAE,CAAC,EACrCK,EAAI,IAAMN,GAAeC,CAAE,CAAC,CAC9B,CACF,EACAM,EAAUP,GAAeC,CAAE,CAAC,CAC9B,CACJ,CC1GO,SAASO,GACdC,EACa,CACb,MAAO,CACL,MAAQA,EAAG,YACX,OAAQA,EAAG,YACb,CACF,CCSA,IAAMC,GAAS,IAAIC,EAUbC,GAAYC,EAAM,IAAMC,EAC5B,IAAI,qBAAqBC,GAAW,CAClC,QAAWC,KAASD,EAClBL,GAAO,KAAKM,CAAK,CACrB,EAAG,CACD,UAAW,CACb,CAAC,CACH,CAAC,EACE,KACCC,EAAUC,GAAYC,EAAMC,GAAON,EAAGI,CAAQ,CAAC,EAC5C,KACCG,EAAS,IAAMH,EAAS,WAAW,CAAC,CACtC,CACF,EACAI,EAAY,CAAC,CACf,EAaK,SAASC,GACdC,EACqB,CACrB,OAAOZ,GACJ,KACCa,EAAIP,GAAYA,EAAS,QAAQM,CAAE,CAAC,EACpCP,EAAUC,GAAYR,GACnB,KACCgB,EAAO,CAAC,CAAE,OAAAC,CAAO,IAAMA,IAAWH,CAAE,EACpCH,EAAS,IAAMH,EAAS,UAAUM,CAAE,CAAC,EACrCI,EAAI,CAAC,CAAE,eAAAC,CAAe,IAAMA,CAAc,CAC5C,CACF,CACF,CACJ,CAaO,SAASC,GACdN,EAAiBO,EAAY,GACR,CACrB,OAAOC,GAA0BR,CAAE,EAChC,KACCI,EAAI,CAAC,CAAE,EAAAK,CAAE,IAAM,CACb,IAAMC,EAAUC,GAAeX,CAAE,EAC3BY,EAAUC,GAAsBb,CAAE,EACxC,OAAOS,GACLG,EAAQ,OAASF,EAAQ,OAASH,CAEtC,CAAC,EACDO,EAAqB,CACvB,CACJ,CCjFA,IAAMC,GAA4C,CAChD,OAAQC,EAAW,yBAAyB,EAC5C,OAAQA,EAAW,yBAAyB,CAC9C,EAaO,SAASC,GAAUC,EAAuB,CAC/C,OAAOH,GAAQG,GAAM,OACvB,CAaO,SAASC,GAAUD,EAAcE,EAAsB,CACxDL,GAAQG,GAAM,UAAYE,GAC5BL,GAAQG,GAAM,MAAM,CACxB,CAWO,SAASG,GAAYH,EAAmC,CAC7D,IAAMI,EAAKP,GAAQG,GACnB,OAAOK,EAAUD,EAAI,QAAQ,EAC1B,KACCE,EAAI,IAAMF,EAAG,OAAO,EACpBG,EAAUH,EAAG,OAAO,CACtB,CACJ,CClCA,SAASI,GACPC,EAAiBC,EACR,CACT,OAAQD,EAAG,kBAGJ,iBAEH,OAAIA,EAAG,OAAS,QACP,SAAS,KAAKC,CAAI,EAElB,QAGN,uBACA,oBACH,MAAO,WAIP,OAAOD,EAAG,kBAEhB,CAWO,SAASE,IAAsC,CACpD,OAAOC,EAAyB,OAAQ,SAAS,EAC9C,KACCC,EAAOC,GAAM,EAAEA,EAAG,SAAWA,EAAG,QAAQ,EACxCC,EAAID,IAAO,CACT,KAAME,GAAU,QAAQ,EAAI,SAAW,SACvC,KAAMF,EAAG,IACT,OAAQ,CACNA,EAAG,eAAe,EAClBA,EAAG,gBAAgB,CACrB,CACF,EAAc,EACdD,EAAO,CAAC,CAAE,KAAAI,EAAM,KAAAP,CAAK,IAAM,CACzB,GAAIO,IAAS,SAAU,CACrB,IAAMC,EAASC,GAAiB,EAChC,GAAI,OAAOD,GAAW,YACpB,MAAO,CAACV,GAAwBU,EAAQR,CAAI,CAChD,CACA,MAAO,EACT,CAAC,EACDU,GAAM,CACR,CACJ,CCpFO,SAASC,IAAmB,CACjC,OAAO,IAAI,IAAI,SAAS,IAAI,CAC9B,CAOO,SAASC,GAAYC,EAAgB,CAC1C,SAAS,KAAOA,EAAI,IACtB,CASO,SAASC,IAA8B,CAC5C,OAAO,IAAIC,CACb,CCLA,SAASC,GAAYC,EAAiBC,EAA8B,CAGlE,GAAI,OAAOA,GAAU,UAAY,OAAOA,GAAU,SAChDD,EAAG,WAAaC,EAAM,SAAS,UAGtBA,aAAiB,KAC1BD,EAAG,YAAYC,CAAK,UAGX,MAAM,QAAQA,CAAK,EAC5B,QAAWC,KAAQD,EACjBF,GAAYC,EAAIE,CAAI,CAE1B,CAyBO,SAASC,EACdC,EAAaC,KAAmCC,EAC7C,CACH,IAAMN,EAAK,SAAS,cAAcI,CAAG,EAGrC,GAAIC,EACF,QAAWE,KAAQ,OAAO,KAAKF,CAAU,EACnC,OAAOA,EAAWE,IAAU,cAI5B,OAAOF,EAAWE,IAAU,UAC9BP,EAAG,aAAaO,EAAMF,EAAWE,EAAK,EAEtCP,EAAG,aAAaO,EAAM,EAAE,GAI9B,QAAWN,KAASK,EAClBP,GAAYC,EAAIC,CAAK,EAGvB,OAAOD,CACT,CChFO,SAASQ,GAASC,EAAeC,EAAmB,CACzD,IAAIC,EAAID,EACR,GAAID,EAAM,OAASE,EAAG,CACpB,KAAOF,EAAME,KAAO,KAAO,EAAEA,EAAI,GAAG,CACpC,MAAO,GAAGF,EAAM,UAAU,EAAGE,CAAC,MAChC,CACA,OAAOF,CACT,CAkBO,SAASG,GAAMH,EAAuB,CAC3C,GAAIA,EAAQ,IAAK,CACf,IAAMI,EAAS,GAAGJ,EAAQ,KAAO,IAAO,IACxC,MAAO,KAAKA,EAAQ,MAAY,KAAM,QAAQI,CAAM,IACtD,KACE,QAAOJ,EAAM,SAAS,CAE1B,CC5BO,SAASK,IAA0B,CACxC,OAAO,SAAS,KAAK,UAAU,CAAC,CAClC,CAYO,SAASC,GAAgBC,EAAoB,CAClD,IAAMC,EAAKC,EAAE,IAAK,CAAE,KAAMF,CAAK,CAAC,EAChCC,EAAG,iBAAiB,QAASE,GAAMA,EAAG,gBAAgB,CAAC,EACvDF,EAAG,MAAM,CACX,CASO,SAASG,IAAwC,CACtD,OAAOC,EAA2B,OAAQ,YAAY,EACnD,KACCC,EAAIR,EAAe,EACnBS,EAAUT,GAAgB,CAAC,EAC3BU,EAAOR,GAAQA,EAAK,OAAS,CAAC,EAC9BS,EAAY,CAAC,CACf,CACJ,CAOO,SAASC,IAA+C,CAC7D,OAAON,GAAkB,EACtB,KACCE,EAAIK,GAAMC,GAAmB,QAAQD,KAAM,CAAE,EAC7CH,EAAOP,GAAM,OAAOA,GAAO,WAAW,CACxC,CACJ,CC1CO,SAASY,GAAWC,EAAoC,CAC7D,IAAMC,EAAQ,WAAWD,CAAK,EAC9B,OAAOE,GAA0BC,GAC/BF,EAAM,YAAY,IAAME,EAAKF,EAAM,OAAO,CAAC,CAC5C,EACE,KACCG,EAAUH,EAAM,OAAO,CACzB,CACJ,CAOO,SAASI,IAAkC,CAChD,IAAMJ,EAAQ,WAAW,OAAO,EAChC,OAAOK,EACLC,EAAU,OAAQ,aAAa,EAAE,KAAKC,EAAI,IAAM,EAAI,CAAC,EACrDD,EAAU,OAAQ,YAAY,EAAE,KAAKC,EAAI,IAAM,EAAK,CAAC,CACvD,EACG,KACCJ,EAAUH,EAAM,OAAO,CACzB,CACJ,CAcO,SAASQ,GACdC,EAA6BC,EACd,CACf,OAAOD,EACJ,KACCE,EAAUC,GAAUA,EAASF,EAAQ,EAAIG,CAAK,CAChD,CACJ,CC7CO,SAASC,GACdC,EAAmBC,EAAuB,CAAE,YAAa,aAAc,EACjD,CACtB,OAAOC,GAAK,MAAM,GAAGF,IAAOC,CAAO,CAAC,EACjC,KACCE,GAAW,IAAMC,CAAK,EACtBC,EAAUC,GAAOA,EAAI,SAAW,IAC5BC,GAAW,IAAM,IAAI,MAAMD,EAAI,UAAU,CAAC,EAC1CE,EAAGF,CAAG,CACV,CACF,CACJ,CAYO,SAASG,GACdT,EAAmBC,EACJ,CACf,OAAOF,GAAQC,EAAKC,CAAO,EACxB,KACCI,EAAUC,GAAOA,EAAI,KAAK,CAAC,EAC3BI,EAAY,CAAC,CACf,CACJ,CAUO,SAASC,GACdX,EAAmBC,EACG,CACtB,IAAMW,EAAM,IAAI,UAChB,OAAOb,GAAQC,EAAKC,CAAO,EACxB,KACCI,EAAUC,GAAOA,EAAI,KAAK,CAAC,EAC3BO,EAAIP,GAAOM,EAAI,gBAAgBN,EAAK,UAAU,CAAC,EAC/CI,EAAY,CAAC,CACf,CACJ,CClDO,SAASI,GAAYC,EAA+B,CACzD,IAAMC,EAASC,EAAE,SAAU,CAAE,IAAAF,CAAI,CAAC,EAClC,OAAOG,EAAM,KACX,SAAS,KAAK,YAAYF,CAAM,EACzBG,EACLC,EAAUJ,EAAQ,MAAM,EACxBI,EAAUJ,EAAQ,OAAO,EACtB,KACCK,EAAU,IACRC,GAAW,IAAM,IAAI,eAAe,mBAAmBP,GAAK,CAAC,CAC9D,CACH,CACJ,EACG,KACCQ,EAAI,IAAG,EAAY,EACnBC,EAAS,IAAM,SAAS,KAAK,YAAYR,CAAM,CAAC,EAChDS,GAAK,CAAC,CACR,EACH,CACH,CCfO,SAASC,IAAoC,CAClD,MAAO,CACL,EAAG,KAAK,IAAI,EAAG,OAAO,EACtB,EAAG,KAAK,IAAI,EAAG,OAAO,CACxB,CACF,CASO,SAASC,IAAkD,CAChE,OAAOC,EACLC,EAAU,OAAQ,SAAU,CAAE,QAAS,EAAK,CAAC,EAC7CA,EAAU,OAAQ,SAAU,CAAE,QAAS,EAAK,CAAC,CAC/C,EACG,KACCC,EAAIJ,EAAiB,EACrBK,EAAUL,GAAkB,CAAC,CAC/B,CACJ,CC3BO,SAASM,IAAgC,CAC9C,MAAO,CACL,MAAQ,WACR,OAAQ,WACV,CACF,CASO,SAASC,IAA8C,CAC5D,OAAOC,EAAU,OAAQ,SAAU,CAAE,QAAS,EAAK,CAAC,EACjD,KACCC,EAAIH,EAAe,EACnBI,EAAUJ,GAAgB,CAAC,CAC7B,CACJ,CCXO,SAASK,IAAsC,CACpD,OAAOC,EAAc,CACnBC,GAAoB,EACpBC,GAAkB,CACpB,CAAC,EACE,KACCC,EAAI,CAAC,CAACC,EAAQC,CAAI,KAAO,CAAE,OAAAD,EAAQ,KAAAC,CAAK,EAAE,EAC1CC,EAAY,CAAC,CACf,CACJ,CCVO,SAASC,GACdC,EAAiB,CAAE,UAAAC,EAAW,QAAAC,CAAQ,EAChB,CACtB,IAAMC,EAAQF,EACX,KACCG,EAAwB,MAAM,CAChC,EAGIC,EAAUC,EAAc,CAACH,EAAOD,CAAO,CAAC,EAC3C,KACCK,EAAI,IAAMC,GAAiBR,CAAE,CAAC,CAChC,EAGF,OAAOM,EAAc,CAACJ,EAASD,EAAWI,CAAO,CAAC,EAC/C,KACCE,EAAI,CAAC,CAAC,CAAE,OAAAE,CAAO,EAAG,CAAE,OAAAC,EAAQ,KAAAC,CAAK,EAAG,CAAE,EAAAC,EAAG,EAAAC,CAAE,CAAC,KAAO,CACjD,OAAQ,CACN,EAAGH,EAAO,EAAIE,EACd,EAAGF,EAAO,EAAIG,EAAIJ,CACpB,EACA,KAAAE,CACF,EAAE,CACJ,CACJ,CCIO,SAASG,GACdC,EAAgB,CAAE,IAAAC,CAAI,EACP,CAGf,IAAMC,EAAMC,EAAwBH,EAAQ,SAAS,EAClD,KACCI,EAAI,CAAC,CAAE,KAAAC,CAAK,IAAMA,CAAS,CAC7B,EAGF,OAAOJ,EACJ,KACCK,GAAS,IAAMJ,EAAK,CAAE,QAAS,GAAM,SAAU,EAAK,CAAC,EACrDK,EAAIC,GAAWR,EAAO,YAAYQ,CAAO,CAAC,EAC1CC,EAAU,IAAMP,CAAG,EACnBQ,GAAM,CACR,CACJ,CCFA,IAAMC,GAASC,EAAW,WAAW,EAC/BC,GAAiB,KAAK,MAAMF,GAAO,WAAY,EACrDE,GAAO,KAAO,GAAG,IAAI,IAAIA,GAAO,KAAMC,GAAY,CAAC,IAW5C,SAASC,IAAwB,CACtC,OAAOF,EACT,CASO,SAASG,GAAQC,EAAqB,CAC3C,OAAOJ,GAAO,SAAS,SAASI,CAAI,CACtC,CAUO,SAASC,GACdC,EAAkBC,EACV,CACR,OAAO,OAAOA,GAAU,YACpBP,GAAO,aAAaM,GAAK,QAAQ,IAAKC,EAAM,SAAS,CAAC,EACtDP,GAAO,aAAaM,EAC1B,CC9BO,SAASE,GACdC,EAASC,EAAmB,SACP,CACrB,OAAOC,EAAW,sBAAsBF,KAASC,CAAI,CACvD,CAYO,SAASE,GACdH,EAASC,EAAmB,SACL,CACvB,OAAOG,EAAY,sBAAsBJ,KAASC,CAAI,CACxD,CC1EO,SAASI,GACdC,EACsB,CACtB,IAAMC,EAASC,EAAW,6BAA8BF,CAAE,EAC1D,OAAOG,EAAUF,EAAQ,QAAS,CAAE,KAAM,EAAK,CAAC,EAC7C,KACCG,EAAI,IAAMF,EAAW,cAAeF,CAAE,CAAC,EACvCI,EAAIC,IAAY,CAAE,KAAM,UAAUA,EAAQ,SAAS,CAAE,EAAE,CACzD,CACJ,CASO,SAASC,GACdN,EACiC,CACjC,MAAI,CAACO,GAAQ,kBAAkB,GAAK,CAACP,EAAG,kBAC/BQ,EAGFC,EAAM,IAAM,CACjB,IAAMC,EAAQ,IAAIC,EAClB,OAAAD,EACG,KACCE,EAAU,CAAE,KAAM,SAAiB,YAAY,CAAE,CAAC,CACpD,EACG,UAAU,CAAC,CAAE,KAAAC,CAAK,IAAM,CA5FjC,IAAAC,EA6FcD,GAAQA,MAAUC,EAAA,SAAiB,YAAY,IAA7B,KAAAA,EAAkCD,KACtDb,EAAG,OAAS,GAGZ,SAAiB,aAAca,CAAI,EAEvC,CAAC,EAGEd,GAAcC,CAAE,EACpB,KACCe,EAAIC,GAASN,EAAM,KAAKM,CAAK,CAAC,EAC9BC,EAAS,IAAMP,EAAM,SAAS,CAAC,EAC/BN,EAAIY,GAAUE,EAAA,CAAE,IAAKlB,GAAOgB,EAAQ,CACtC,CACJ,CAAC,CACH,CCpCO,SAASG,GACdC,EAAiB,CAAE,QAAAC,CAAQ,EACN,CACrB,OAAOA,EACJ,KACCC,EAAIC,IAAW,CAAE,OAAQA,IAAWH,CAAG,EAAE,CAC3C,CACJ,CAYO,SAASI,GACdJ,EAAiBK,EACe,CAChC,IAAMC,EAAY,IAAIC,EACtB,OAAAD,EAAU,UAAU,CAAC,CAAE,OAAAE,CAAO,IAAM,CAClCR,EAAG,OAASQ,CACd,CAAC,EAGMT,GAAaC,EAAIK,CAAO,EAC5B,KACCI,EAAIC,GAASJ,EAAU,KAAKI,CAAK,CAAC,EAClCC,EAAS,IAAML,EAAU,SAAS,CAAC,EACnCJ,EAAIQ,GAAUE,EAAA,CAAE,IAAKZ,GAAOU,EAAQ,CACtC,CACJ,CCrFA,IAAAG,GAAwB,SCajB,SAASC,GAAiBC,EAAyB,CACxD,OACEC,EAAC,SAAM,MAAM,gBAAgB,SAAU,GACrCA,EAAC,OAAI,MAAM,mCACTA,EAAC,OAAI,MAAM,+BAA+B,CAC5C,EACAA,EAAC,QAAK,MAAM,wBACVA,EAAC,QAAK,wBAAuBD,EAAI,CACnC,CACF,CAEJ,CCVO,SAASE,GAAsBC,EAAyB,CAC7D,OACEC,EAAC,UACC,MAAM,uBACN,MAAOC,GAAY,gBAAgB,EACnC,wBAAuB,IAAIF,WAC5B,CAEL,CCYA,SAASG,GACPC,EAA2CC,EAC9B,CACb,IAAMC,EAASD,EAAO,EAChBE,EAASF,EAAO,EAGhBG,EAAU,OAAO,KAAKJ,EAAS,KAAK,EACvC,OAAOK,GAAO,CAACL,EAAS,MAAMK,EAAI,EAClC,OAAyB,CAACC,EAAMD,IAAQ,CACvC,GAAGC,EAAMC,EAAC,WAAKF,CAAI,EAAQ,GAC7B,EAAG,CAAC,CAAC,EACJ,MAAM,EAAG,EAAE,EAGRG,EAAM,IAAI,IAAIR,EAAS,QAAQ,EACrC,OAAIS,GAAQ,kBAAkB,GAC5BD,EAAI,aAAa,IAAI,IAAK,OAAO,QAAQR,EAAS,KAAK,EACpD,OAAO,CAAC,CAAC,CAAEU,CAAK,IAAMA,CAAK,EAC3B,OAAO,CAACC,EAAW,CAACC,CAAK,IAAM,GAAGD,KAAaC,IAAQ,KAAK,EAAG,EAAE,CACpE,EAIAL,EAAC,KAAE,KAAM,GAAGC,IAAO,MAAM,yBAAyB,SAAU,IAC1DD,EAAC,WACC,MAAO,CAAC,4BAA6B,GAAGL,EACpC,CAAC,qCAAqC,EACtC,CAAC,CACL,EAAE,KAAK,GAAG,EACV,gBAAeF,EAAS,MAAM,QAAQ,CAAC,GAEtCE,EAAS,GAAKK,EAAC,OAAI,MAAM,iCAAiC,EAC3DA,EAAC,MAAG,MAAM,2BAA2BP,EAAS,KAAM,EACnDG,EAAS,GAAKH,EAAS,KAAK,OAAS,GACpCO,EAAC,KAAE,MAAM,4BACNM,GAASb,EAAS,KAAM,GAAG,CAC9B,EAEDA,EAAS,MAAQA,EAAS,KAAK,IAAIc,GAClCP,EAAC,QAAK,MAAM,UAAUO,CAAI,CAC3B,EACAX,EAAS,GAAKC,EAAQ,OAAS,GAC9BG,EAAC,KAAE,MAAM,2BACNQ,GAAY,4BAA4B,EAAE,KAAG,GAAGX,CACnD,CAEJ,CACF,CAEJ,CAaO,SAASY,GACdC,EACa,CACb,IAAMC,EAAYD,EAAO,GAAG,MACtBE,EAAO,CAAC,GAAGF,CAAM,EAGjBf,EAASiB,EAAK,UAAUC,GAAO,CAACA,EAAI,SAAS,SAAS,GAAG,CAAC,EAC1D,CAACC,CAAO,EAAIF,EAAK,OAAOjB,EAAQ,CAAC,EAGnCoB,EAAQH,EAAK,UAAUC,GAAOA,EAAI,MAAQF,CAAS,EACnDI,IAAU,KACZA,EAAQH,EAAK,QAGf,IAAMI,EAAOJ,EAAK,MAAM,EAAGG,CAAK,EAC1BE,EAAOL,EAAK,MAAMG,CAAK,EAGvBG,EAAW,CACf1B,GAAqBsB,EAAS,EAAc,EAAE,CAACnB,GAAUoB,IAAU,EAAE,EACrE,GAAGC,EAAK,IAAIG,GAAW3B,GAAqB2B,EAAS,CAAW,CAAC,EACjE,GAAGF,EAAK,OAAS,CACfjB,EAAC,WAAQ,MAAM,0BACbA,EAAC,WAAQ,SAAU,IAChBiB,EAAK,OAAS,GAAKA,EAAK,SAAW,EAChCT,GAAY,wBAAwB,EACpCA,GAAY,2BAA4BS,EAAK,MAAM,CAEzD,EACC,GAAGA,EAAK,IAAIE,GAAW3B,GAAqB2B,EAAS,CAAW,CAAC,CACpE,CACF,EAAI,CAAC,CACP,EAGA,OACEnB,EAAC,MAAG,MAAM,0BACPkB,CACH,CAEJ,CC7HO,SAASE,GAAkBC,EAAiC,CACjE,OACEC,EAAC,MAAG,MAAM,oBACP,OAAO,QAAQD,CAAK,EAAE,IAAI,CAAC,CAACE,EAAKC,CAAK,IACrCF,EAAC,MAAG,MAAO,oCAAoCC,KAC5C,OAAOC,GAAU,SAAWC,GAAMD,CAAK,EAAIA,CAC9C,CACD,CACH,CAEJ,CCAO,SAASE,GACdC,EACa,CACb,IAAMC,EAAU,kCAAkCD,IAClD,OACEE,EAAC,OAAI,MAAOD,EAAS,OAAM,IACzBC,EAAC,UAAO,MAAM,gBAAgB,SAAU,GAAI,CAC9C,CAEJ,CCpBO,SAASC,GAAYC,EAAiC,CAC3D,OACEC,EAAC,OAAI,MAAM,0BACTA,EAAC,OAAI,MAAM,qBACRD,CACH,CACF,CAEJ,CCMA,SAASE,GAAcC,EAA+B,CACpD,IAAMC,EAASC,GAAc,EAGvBC,EAAM,IAAI,IAAI,MAAMH,EAAQ,WAAYC,EAAO,IAAI,EACzD,OACEG,EAAC,MAAG,MAAM,oBACRA,EAAC,KAAE,KAAM,GAAGD,IAAO,MAAM,oBACtBH,EAAQ,KACX,CACF,CAEJ,CAcO,SAASK,GACdC,EAAqBC,EACR,CACb,OACEH,EAAC,OAAI,MAAM,cACTA,EAAC,UACC,MAAM,sBACN,aAAYI,GAAY,sBAAsB,GAE7CD,EAAO,KACV,EACAH,EAAC,MAAG,MAAM,oBACPE,EAAS,IAAIP,EAAa,CAC7B,CACF,CAEJ,CCfO,SAASU,GACdC,EAAiBC,EACO,CACxB,IAAMC,EAAUC,EAAM,IAAMC,EAAc,CACxCC,GAAmBL,CAAE,EACrBM,GAA0BL,CAAS,CACrC,CAAC,CAAC,EACC,KACCM,EAAI,CAAC,CAAC,CAAE,EAAAC,EAAG,EAAAC,CAAE,EAAGC,CAAM,IAAM,CAC1B,GAAM,CAAE,MAAAC,CAAM,EAAIC,GAAeZ,CAAE,EACnC,MAAQ,CACN,EAAGQ,EAAIE,EAAO,EAAIC,EAAQ,EAC1B,EAAGF,EAAIC,EAAO,CAChB,CACF,CAAC,CACH,EAGF,OAAOG,GAAkBb,CAAE,EACxB,KACCc,EAAUC,GAAUb,EACjB,KACCK,EAAIS,IAAW,CAAE,OAAAD,EAAQ,OAAAC,CAAO,EAAE,EAClCC,GAAK,CAAC,CAACF,GAAU,GAAQ,CAC3B,CACF,CACF,CACJ,CAUO,SAASG,GACdlB,EAAiBC,EACkB,CACnC,OAAOE,EAAM,IAAM,CACjB,IAAMgB,EAAQ,IAAIC,EAClBD,EAAM,UAAU,CAGd,KAAK,CAAE,OAAAH,CAAO,EAAG,CACfhB,EAAG,MAAM,YAAY,iBAAkB,GAAGgB,EAAO,KAAK,EACtDhB,EAAG,MAAM,YAAY,iBAAkB,GAAGgB,EAAO,KAAK,CACxD,EAGA,UAAW,CACThB,EAAG,MAAM,eAAe,gBAAgB,EACxCA,EAAG,MAAM,eAAe,gBAAgB,CAC1C,CACF,CAAC,EAGD,IAAMqB,EAAQF,EAAM,KAAKG,GAAS,CAAC,CAAC,EACpCC,GAAuBvB,CAAE,EACtB,KACCwB,EAAUH,CAAK,CACjB,EACG,UAAUI,GAAW,CACpBzB,EAAG,gBAAgB,kBAAmByB,CAAO,CAC/C,CAAC,EAGLN,EACG,KACCO,GAAa,IAAKC,EAAuB,EACzCpB,EAAI,IAAMN,EAAU,sBAAsB,CAAC,EAC3CM,EAAI,CAAC,CAAE,EAAAC,CAAE,IAAMA,CAAC,CAClB,EACG,UAAU,CAGT,KAAKoB,EAAQ,CACPA,EACF5B,EAAG,MAAM,YAAY,iBAAkB,GAAG,CAAC4B,KAAU,EAErD5B,EAAG,MAAM,eAAe,gBAAgB,CAC5C,EAGA,UAAW,CACTA,EAAG,MAAM,eAAe,gBAAgB,CAC1C,CACF,CAAC,EAGL,IAAM6B,EAAQC,EAAW,uBAAwB9B,CAAE,EAC7C+B,EAAQC,EAAUH,EAAO,YAAa,CAAE,KAAM,EAAK,CAAC,EAC1D,OAAAV,EACG,KACCL,EAAU,CAAC,CAAE,OAAAC,CAAO,IAAMA,EAASgB,EAAQE,CAAK,EAChDC,EAAIC,GAAMA,EAAG,eAAe,CAAC,CAC/B,EACG,UAAU,IAAMnC,EAAG,KAAK,CAAC,EAGvBD,GAAgBC,EAAIC,CAAS,EACjC,KACCiC,EAAIE,GAASjB,EAAM,KAAKiB,CAAK,CAAC,EAC9BC,EAAS,IAAMlB,EAAM,SAAS,CAAC,EAC/BZ,EAAI6B,GAAUE,EAAA,CAAE,IAAKtC,GAAOoC,EAAQ,CACtC,CACJ,CAAC,CACH,CCnHA,SAASG,GAAsBC,EAAgC,CAC7D,IAAMC,EAAkB,CAAC,EACzB,QAAWC,KAAWC,EAAY,eAAgBH,CAAS,EAAG,CAC5D,IAAII,EAGAC,EAAOH,EAAQ,WACnB,GAAIG,aAAgB,KAClB,KAAQD,EAAQ,YAAY,KAAKC,EAAK,WAAY,GAAI,CACpD,IAAMC,EAASD,EAAK,UAAUD,EAAM,KAAK,EACzCC,EAAOC,EAAO,UAAUF,EAAM,GAAG,MAAM,EACvCH,EAAQ,KAAKK,CAAM,CACrB,CACJ,CACA,OAAOL,CACT,CAQA,SAASM,GAAKC,EAAqBC,EAA2B,CAC5DA,EAAO,OAAO,GAAG,MAAM,KAAKD,EAAO,UAAU,CAAC,CAChD,CAoBO,SAASE,GACdC,EAAiBX,EAAwB,CAAE,OAAAY,CAAO,EACf,CAGnC,IAAMC,EAAc,IAAI,IACxB,QAAWP,KAAUP,GAAsBC,CAAS,EAAG,CACrD,GAAM,CAAC,CAAEc,CAAE,EAAIR,EAAO,YAAa,MAAM,WAAW,EAChDS,GAAmB,gBAAgBD,KAAOH,CAAE,IAC9CE,EAAY,IAAI,CAACC,EAAIE,GAAiB,CAACF,CAAE,CAAC,EAC1CR,EAAO,YAAYO,EAAY,IAAI,CAACC,CAAE,CAAE,EAE5C,CAGA,OAAID,EAAY,OAAS,EAChBI,EAGFC,EAAM,IAAM,CACjB,IAAMC,EAAQ,IAAIC,EAGlB,OAAAR,EACG,KACCS,EAAUF,EAAM,KAAKG,GAAS,CAAC,CAAC,CAAC,CACnC,EACG,UAAUC,GAAU,CACnBZ,EAAG,OAAS,CAACY,EAGb,OAAW,CAACT,EAAIU,CAAU,IAAKX,EAAa,CAC1C,IAAMY,EAAQC,EAAW,cAAeF,CAAU,EAC5CG,EAAQD,EAAW,gBAAgBZ,KAAOH,CAAE,EAC7CY,EAGHhB,GAAKkB,EAAOE,CAAK,EAFjBpB,GAAKoB,EAAOF,CAAK,CAGrB,CACF,CAAC,EAGEG,EAAM,GAAG,CAAC,GAAGf,CAAW,EAC5B,IAAI,CAAC,CAAC,CAAEW,CAAU,IACjBK,GAAgBL,EAAYxB,CAAS,CACtC,CACH,EACG,KACC8B,EAAS,IAAMX,EAAM,SAAS,CAAC,EAC/BY,GAAM,CACR,CACJ,CAAC,CACH,CTlFA,IAAIC,GAAW,EAaf,SAASC,GAAkBC,EAA0C,CACnE,GAAIA,EAAG,mBAAoB,CACzB,IAAMC,EAAUD,EAAG,mBACnB,GAAIC,EAAQ,UAAY,KACtB,OAAOA,EAGJ,GAAIA,EAAQ,UAAY,KAAO,CAACA,EAAQ,SAAS,OACpD,OAAOF,GAAkBE,CAAO,CACpC,CAIF,CAgBO,SAASC,GACdF,EACuB,CACvB,OAAOG,GAAiBH,CAAE,EACvB,KACCI,EAAI,CAAC,CAAE,MAAAC,CAAM,KAEJ,CACL,WAFcC,GAAsBN,CAAE,EAElB,MAAQK,CAC9B,EACD,EACDE,EAAwB,YAAY,CACtC,CACJ,CAeO,SAASC,GACdR,EAAiBS,EAC8B,CAC/C,GAAM,CAAE,QAASC,CAAM,EAAI,WAAW,SAAS,EAGzCC,EAAWC,EAAM,IAAM,CAC3B,IAAMC,EAAQ,IAAIC,EASlB,GARAD,EAAM,UAAU,CAAC,CAAE,WAAAE,CAAW,IAAM,CAC9BA,GAAcL,EAChBV,EAAG,aAAa,WAAY,GAAG,EAE/BA,EAAG,gBAAgB,UAAU,CACjC,CAAC,EAGG,GAAAgB,QAAY,YAAY,EAAG,CAC7B,IAAMC,EAASjB,EAAG,QAAQ,KAAK,EAC/BiB,EAAO,GAAK,UAAU,EAAEnB,KACxBmB,EAAO,aACLC,GAAsBD,EAAO,EAAE,EAC/BjB,CACF,CACF,CAGA,IAAMmB,EAAYnB,EAAG,QAAQ,YAAY,EACzC,GAAImB,aAAqB,YAAa,CACpC,IAAMC,EAAOrB,GAAkBoB,CAAS,EAGxC,GAAI,OAAOC,GAAS,cAClBD,EAAU,UAAU,SAAS,UAAU,GACvCE,GAAQ,uBAAuB,GAC9B,CACD,IAAMC,EAAeC,GAAoBH,EAAMpB,EAAIS,CAAO,EAG1D,OAAOP,GAAeF,CAAE,EACrB,KACCwB,EAAIC,GAASZ,EAAM,KAAKY,CAAK,CAAC,EAC9BC,EAAS,IAAMb,EAAM,SAAS,CAAC,EAC/BT,EAAIqB,GAAUE,EAAA,CAAE,IAAK3B,GAAOyB,EAAQ,EACpCG,GACEzB,GAAiBgB,CAAS,EACvB,KACCU,EAAUhB,EAAM,KAAKiB,GAAS,CAAC,CAAC,CAAC,EACjC1B,EAAI,CAAC,CAAE,MAAAC,EAAO,OAAA0B,CAAO,IAAM1B,GAAS0B,CAAM,EAC1CC,EAAqB,EACrBC,EAAUC,GAAUA,EAASZ,EAAea,CAAK,CACnD,CACJ,CACF,CACJ,CACF,CAGA,OAAOjC,GAAeF,CAAE,EACrB,KACCwB,EAAIC,GAASZ,EAAM,KAAKY,CAAK,CAAC,EAC9BC,EAAS,IAAMb,EAAM,SAAS,CAAC,EAC/BT,EAAIqB,GAAUE,EAAA,CAAE,IAAK3B,GAAOyB,EAAQ,CACtC,CACJ,CAAC,EAGD,OAAOW,GAAuBpC,CAAE,EAC7B,KACCqC,EAAOC,GAAWA,CAAO,EACzBC,GAAK,CAAC,EACNN,EAAU,IAAMtB,CAAQ,CAC1B,CACJ,4uJU7KA,IAAI6B,GAKAC,GAAW,EAWf,SAASC,IAAiC,CACxC,OAAO,OAAO,SAAY,aAAe,mBAAmB,QACxDC,GAAY,qDAAqD,EACjEC,EAAG,MAAS,CAClB,CAaO,SAASC,GACdC,EACgC,CAChC,OAAAA,EAAG,UAAU,OAAO,SAAS,EAC7BN,QAAaE,GAAa,EACvB,KACCK,EAAI,IAAM,QAAQ,WAAW,CAC3B,YAAa,GACb,SAAAC,EACF,CAAC,CAAC,EACFC,EAAI,IAAG,EAAY,EACnBC,EAAY,CAAC,CACf,GAGFV,GAAS,UAAU,IAAM,CACvBM,EAAG,UAAU,IAAI,SAAS,EAC1B,IAAMK,EAAK,aAAaV,OAClBW,EAAOC,EAAE,MAAO,CAAE,MAAO,SAAU,CAAC,EAC1C,QAAQ,WAAW,OAAOF,EAAIL,EAAG,YAAcQ,GAAgB,CAG7D,IAAMC,EAASH,EAAK,aAAa,CAAE,KAAM,QAAS,CAAC,EACnDG,EAAO,UAAYD,EAGnBR,EAAG,YAAYM,CAAI,CACrB,CAAC,CACH,CAAC,EAGMZ,GACJ,KACCS,EAAI,KAAO,CAAE,IAAKH,CAAG,EAAE,CACzB,CACJ,CC1CO,SAASU,GACdC,EAAwB,CAAE,QAAAC,EAAS,OAAAC,CAAO,EACrB,CACrB,IAAIC,EAAO,GACX,OAAOC,EAGLH,EACG,KACCI,EAAIC,GAAUA,EAAO,QAAQ,qBAAqB,CAAE,EACpDC,EAAOC,GAAWR,IAAOQ,CAAO,EAChCH,EAAI,KAAO,CACT,OAAQ,OAAQ,OAAQ,EAC1B,EAAa,CACf,EAGFH,EACG,KACCK,EAAOE,GAAUA,GAAU,CAACN,CAAI,EAChCO,EAAI,IAAMP,EAAOH,EAAG,IAAI,EACxBK,EAAII,IAAW,CACb,OAAQA,EAAS,OAAS,OAC5B,EAAa,CACf,CACJ,CACF,CAaO,SAASE,GACdX,EAAwBY,EACQ,CAChC,OAAOC,EAAM,IAAM,CACjB,IAAMC,EAAQ,IAAIC,EAClB,OAAAD,EAAM,UAAU,CAAC,CAAE,OAAAE,EAAQ,OAAAC,CAAO,IAAM,CAClCD,IAAW,OACbhB,EAAG,aAAa,OAAQ,EAAE,EAE1BA,EAAG,gBAAgB,MAAM,EACvBiB,GACFjB,EAAG,eAAe,CACtB,CAAC,EAGMD,GAAaC,EAAIY,CAAO,EAC5B,KACCF,EAAIQ,GAASJ,EAAM,KAAKI,CAAK,CAAC,EAC9BC,EAAS,IAAML,EAAM,SAAS,CAAC,EAC/BT,EAAIa,GAAUE,EAAA,CAAE,IAAKpB,GAAOkB,EAAQ,CACtC,CACJ,CAAC,CACH,CC/FA,IAAMG,GAAWC,EAAE,OAAO,EAgBnB,SAASC,GACdC,EACkC,CAClC,OAAAA,EAAG,YAAYH,EAAQ,EACvBA,GAAS,YAAYI,GAAYD,CAAE,CAAC,EAG7BE,EAAG,CAAE,IAAKF,CAAG,CAAC,CACvB,CCUO,SAASG,GACdC,EACyB,CACzB,IAAMC,EAASC,EAA8B,iBAAkBF,CAAE,EAC3DG,EAAUF,EAAO,KAAKG,GAASA,EAAM,OAAO,GAAKH,EAAO,GAC9D,OAAOI,EAAM,GAAGJ,EAAO,IAAIG,GAASE,EAAUF,EAAO,QAAQ,EAC1D,KACCG,EAAI,IAAMC,EAA6B,cAAcJ,EAAM,MAAM,CAAC,CACpE,CACF,CAAC,EACE,KACCK,EAAUD,EAA6B,cAAcL,EAAQ,MAAM,CAAC,EACpEI,EAAIG,IAAW,CAAE,OAAAA,CAAO,EAAE,CAC5B,CACJ,CAcO,SAASC,GACdX,EACoC,CAGpC,IAAMY,EAAOC,GAAoB,MAAM,EACvCb,EAAG,OAAOY,CAAI,EAGd,IAAME,EAAOD,GAAoB,MAAM,EACvCb,EAAG,OAAOc,CAAI,EAGd,IAAMC,EAAYP,EAAW,iBAAkBR,CAAE,EACjD,OAAOgB,EAAM,IAAM,CACjB,IAAMC,EAAQ,IAAIC,EACZC,EAAQF,EAAM,KAAKG,GAAS,CAAC,CAAC,EACpC,OAAAC,EAAc,CAACJ,EAAOK,GAAiBtB,CAAE,CAAC,CAAC,EACxC,KACCuB,GAAU,EAAGC,EAAuB,EACpCC,EAAUN,CAAK,CACjB,EACG,UAAU,CAGT,KAAK,CAAC,CAAE,OAAAT,CAAO,EAAGgB,CAAI,EAAG,CACvB,IAAMC,EAASC,GAAiBlB,CAAM,EAChC,CAAE,MAAAmB,CAAM,EAAIC,GAAepB,CAAM,EAGvCV,EAAG,MAAM,YAAY,mBAAoB,GAAG2B,EAAO,KAAK,EACxD3B,EAAG,MAAM,YAAY,uBAAwB,GAAG6B,KAAS,EAGzD,IAAME,EAAUC,GAAwBjB,CAAS,GAE/CY,EAAO,EAAYI,EAAQ,GAC3BJ,EAAO,EAAIE,EAAQE,EAAQ,EAAIL,EAAK,QAEpCX,EAAU,SAAS,CACjB,KAAM,KAAK,IAAI,EAAGY,EAAO,EAAI,EAAE,EAC/B,SAAU,QACZ,CAAC,CACL,EAGA,UAAW,CACT3B,EAAG,MAAM,eAAe,kBAAkB,EAC1CA,EAAG,MAAM,eAAe,sBAAsB,CAChD,CACF,CAAC,EAGLqB,EAAc,CACZY,GAA0BlB,CAAS,EACnCO,GAAiBP,CAAS,CAC5B,CAAC,EACE,KACCU,EAAUN,CAAK,CACjB,EACG,UAAU,CAAC,CAACQ,EAAQD,CAAI,IAAM,CAC7B,IAAMK,EAAUG,GAAsBnB,CAAS,EAC/CH,EAAK,OAASe,EAAO,EAAI,GACzBb,EAAK,OAASa,EAAO,EAAII,EAAQ,MAAQL,EAAK,MAAQ,EACxD,CAAC,EAGLrB,EACEC,EAAUM,EAAM,OAAO,EAAE,KAAKL,EAAI,IAAM,EAAE,CAAC,EAC3CD,EAAUQ,EAAM,OAAO,EAAE,KAAKP,EAAI,IAAM,CAAE,CAAC,CAC7C,EACG,KACCkB,EAAUN,CAAK,CACjB,EACG,UAAUgB,GAAa,CACtB,GAAM,CAAE,MAAAN,CAAM,EAAIC,GAAef,CAAS,EAC1CA,EAAU,SAAS,CACjB,KAAMc,EAAQM,EACd,SAAU,QACZ,CAAC,CACH,CAAC,EAGDC,GAAQ,mBAAmB,GAC7BnB,EAAM,KAAKoB,GAAK,CAAC,CAAC,EACf,UAAU,CAAC,CAAE,OAAA3B,CAAO,IAAM,CACzB,IAAM4B,EAAM5B,EAAO,UAAU,KAAK,EAClC,QAAW6B,KAAOrC,EAAY,aAAa,EACzC,QAAWE,KAASF,EAClB,iBAAkBqC,CACpB,EAEE,GADc/B,EAAW,cAAcJ,EAAM,MAAM,EACzC,UAAU,KAAK,IAAMkC,EAAK,CAClClC,EAAM,MAAM,EACZ,KACF,CAIJ,IAAMoC,EAAO,SAAmB,QAAQ,GAAK,CAAC,EAC9C,SAAS,SAAU,CAAC,GAAG,IAAI,IAAI,CAACF,EAAK,GAAGE,CAAI,CAAC,CAAC,CAAC,CACjD,CAAC,EAGEzC,GAAiBC,CAAE,EACvB,KACCyC,EAAIC,GAASzB,EAAM,KAAKyB,CAAK,CAAC,EAC9BC,EAAS,IAAM1B,EAAM,SAAS,CAAC,EAC/BV,EAAImC,GAAUE,EAAA,CAAE,IAAK5C,GAAO0C,EAAQ,CACtC,CACJ,CAAC,EACE,KACCG,GAAYC,EAAc,CAC5B,CACJ,CCpIO,SAASC,GACdC,EAAiB,CAAE,QAAAC,EAAS,OAAAC,CAAO,EACH,CAChC,OAAOC,EAGL,GAAGC,EAAY,2BAA4BJ,CAAE,EAC1C,IAAIK,GAASC,GAAeD,EAAO,CAAE,OAAAH,CAAO,CAAC,CAAC,EAGjD,GAAGE,EAAY,cAAeJ,CAAE,EAC7B,IAAIK,GAASE,GAAaF,CAAK,CAAC,EAGnC,GAAGD,EAAY,qBAAsBJ,CAAE,EACpC,IAAIK,GAASG,GAAeH,CAAK,CAAC,EAGrC,GAAGD,EAAY,UAAWJ,CAAE,EACzB,IAAIK,GAASI,GAAaJ,EAAO,CAAE,QAAAJ,EAAS,OAAAC,CAAO,CAAC,CAAC,EAGxD,GAAGE,EAAY,cAAeJ,CAAE,EAC7B,IAAIK,GAASK,GAAiBL,CAAK,CAAC,CACzC,CACF,CCjCO,SAASM,GACdC,EAAkB,CAAE,OAAAC,CAAO,EACP,CACpB,OAAOA,EACJ,KACCC,EAAUC,GAAWC,EACnBC,EAAG,EAAI,EACPA,EAAG,EAAK,EAAE,KAAKC,GAAM,GAAI,CAAC,CAC5B,EACG,KACCC,EAAIC,IAAW,CAAE,QAAAL,EAAS,OAAAK,CAAO,EAAE,CACrC,CACF,CACF,CACJ,CAaO,SAASC,GACdC,EAAiBC,EACc,CAC/B,IAAMC,EAAQC,EAAW,cAAeH,CAAE,EAC1C,OAAOI,EAAM,IAAM,CACjB,IAAMC,EAAQ,IAAIC,EAClB,OAAAD,EAAM,UAAU,CAAC,CAAE,QAAAZ,EAAS,OAAAK,CAAO,IAAM,CACvCE,EAAG,UAAU,OAAO,oBAAqBF,CAAM,EAC/CI,EAAM,YAAcT,CACtB,CAAC,EAGMJ,GAAYW,EAAIC,CAAO,EAC3B,KACCM,EAAIC,GAASH,EAAM,KAAKG,CAAK,CAAC,EAC9BC,EAAS,IAAMJ,EAAM,SAAS,CAAC,EAC/BR,EAAIW,GAAUE,EAAA,CAAE,IAAKV,GAAOQ,EAAQ,CACtC,CACJ,CAAC,CACH,CC9BA,SAASG,GAAS,CAAE,UAAAC,CAAU,EAAsC,CAClE,GAAI,CAACC,GAAQ,iBAAiB,EAC5B,OAAOC,EAAG,EAAK,EAGjB,IAAMC,EAAaH,EAChB,KACCI,EAAI,CAAC,CAAE,OAAQ,CAAE,EAAAC,CAAE,CAAE,IAAMA,CAAC,EAC5BC,GAAY,EAAG,CAAC,EAChBF,EAAI,CAAC,CAACG,EAAGC,CAAC,IAAM,CAACD,EAAIC,EAAGA,CAAC,CAAU,EACnCC,EAAwB,CAAC,CAC3B,EAGIC,EAAUC,EAAc,CAACX,EAAWG,CAAU,CAAC,EAClD,KACCS,EAAO,CAAC,CAAC,CAAE,OAAAC,CAAO,EAAG,CAAC,CAAER,CAAC,CAAC,IAAM,KAAK,IAAIA,EAAIQ,EAAO,CAAC,EAAI,GAAG,EAC5DT,EAAI,CAAC,CAAC,CAAE,CAACU,CAAS,CAAC,IAAMA,CAAS,EAClCC,EAAqB,CACvB,EAGIC,EAAUC,GAAY,QAAQ,EACpC,OAAON,EAAc,CAACX,EAAWgB,CAAO,CAAC,EACtC,KACCZ,EAAI,CAAC,CAAC,CAAE,OAAAS,CAAO,EAAGK,CAAM,IAAML,EAAO,EAAI,KAAO,CAACK,CAAM,EACvDH,EAAqB,EACrBI,EAAUC,GAAUA,EAASV,EAAUR,EAAG,EAAK,CAAC,EAChDmB,EAAU,EAAK,CACjB,CACJ,CAcO,SAASC,GACdC,EAAiBC,EACG,CACpB,OAAOC,EAAM,IAAMd,EAAc,CAC/Be,GAAiBH,CAAE,EACnBxB,GAASyB,CAAO,CAClB,CAAC,CAAC,EACC,KACCpB,EAAI,CAAC,CAAC,CAAE,OAAAuB,CAAO,EAAGC,CAAM,KAAO,CAC7B,OAAAD,EACA,OAAAC,CACF,EAAE,EACFb,EAAqB,CAACR,EAAGC,IACvBD,EAAE,SAAWC,EAAE,QACfD,EAAE,SAAWC,EAAE,MAChB,EACDqB,EAAY,CAAC,CACf,CACJ,CAaO,SAASC,GACdP,EAAiB,CAAE,QAAAQ,EAAS,MAAAC,CAAM,EACH,CAC/B,OAAOP,EAAM,IAAM,CACjB,IAAMQ,EAAQ,IAAIC,EACZC,EAAQF,EAAM,KAAKG,GAAS,CAAC,CAAC,EACpC,OAAAH,EACG,KACCxB,EAAwB,QAAQ,EAChC4B,GAAkBN,CAAO,CAC3B,EACG,UAAU,CAAC,CAAC,CAAE,OAAAX,CAAO,EAAG,CAAE,OAAAQ,CAAO,CAAC,IAAM,CACvCL,EAAG,UAAU,OAAO,oBAAqBH,GAAU,CAACQ,CAAM,EAC1DL,EAAG,OAASK,CACd,CAAC,EAGLI,EAAM,UAAUC,CAAK,EAGdF,EACJ,KACCO,EAAUH,CAAK,EACf/B,EAAImC,GAAUC,EAAA,CAAE,IAAKjB,GAAOgB,EAAQ,CACtC,CACJ,CAAC,CACH,CChHO,SAASE,GACdC,EAAiB,CAAE,UAAAC,EAAW,QAAAC,CAAQ,EACb,CACzB,OAAOC,GAAgBH,EAAI,CAAE,UAAAC,EAAW,QAAAC,CAAQ,CAAC,EAC9C,KACCE,EAAI,CAAC,CAAE,OAAQ,CAAE,EAAAC,CAAE,CAAE,IAAM,CACzB,GAAM,CAAE,OAAAC,CAAO,EAAIC,GAAeP,CAAE,EACpC,MAAO,CACL,OAAQK,GAAKC,CACf,CACF,CAAC,EACDE,EAAwB,QAAQ,CAClC,CACJ,CAaO,SAASC,GACdT,EAAiBU,EACmB,CACpC,OAAOC,EAAM,IAAM,CACjB,IAAMC,EAAQ,IAAIC,EAClBD,EAAM,UAAU,CAAC,CAAE,OAAAE,CAAO,IAAM,CAC9Bd,EAAG,UAAU,OAAO,2BAA4Bc,CAAM,CACxD,CAAC,EAGD,IAAMC,EAAUC,GAAmB,YAAY,EAC/C,OAAI,OAAOD,GAAY,YACdE,EAGFlB,GAAiBgB,EAASL,CAAO,EACrC,KACCQ,EAAIC,GAASP,EAAM,KAAKO,CAAK,CAAC,EAC9BC,EAAS,IAAMR,EAAM,SAAS,CAAC,EAC/BR,EAAIe,GAAUE,EAAA,CAAE,IAAKrB,GAAOmB,EAAQ,CACtC,CACJ,CAAC,CACH,CCvDO,SAASG,GACdC,EAAiB,CAAE,UAAAC,EAAW,QAAAC,CAAQ,EACpB,CAGlB,IAAMC,EAAUD,EACb,KACCE,EAAI,CAAC,CAAE,OAAAC,CAAO,IAAMA,CAAM,EAC1BC,EAAqB,CACvB,EAGIC,EAAUJ,EACb,KACCK,EAAU,IAAMC,GAAiBT,CAAE,EAChC,KACCI,EAAI,CAAC,CAAE,OAAAC,CAAO,KAAO,CACnB,IAAQL,EAAG,UACX,OAAQA,EAAG,UAAYK,CACzB,EAAE,EACFK,EAAwB,QAAQ,CAClC,CACF,CACF,EAGF,OAAOC,EAAc,CAACR,EAASI,EAASN,CAAS,CAAC,EAC/C,KACCG,EAAI,CAAC,CAACQ,EAAQ,CAAE,IAAAC,EAAK,OAAAC,CAAO,EAAG,CAAE,OAAQ,CAAE,EAAAC,CAAE,EAAG,KAAM,CAAE,OAAAV,CAAO,CAAE,CAAC,KAChEA,EAAS,KAAK,IAAI,EAAGA,EACjB,KAAK,IAAI,EAAGQ,EAASE,EAAIH,CAAM,EAC/B,KAAK,IAAI,EAAGP,EAASU,EAAID,CAAM,CACnC,EACO,CACL,OAAQD,EAAMD,EACd,OAAAP,EACA,OAAQQ,EAAMD,GAAUG,CAC1B,EACD,EACDT,EAAqB,CAACU,EAAGC,IACvBD,EAAE,SAAWC,EAAE,QACfD,EAAE,SAAWC,EAAE,QACfD,EAAE,SAAWC,EAAE,MAChB,CACH,CACJ,CClDO,SAASC,GACdC,EACqB,CACrB,IAAMC,EAAU,SAAkB,WAAW,GAAK,CAChD,MAAOD,EAAO,UAAUE,GAAS,WAC/BA,EAAM,aAAa,qBAAqB,CAC1C,EAAE,OAAO,CACX,EAGA,OAAOC,EAAG,GAAGH,CAAM,EAChB,KACCI,GAASF,GAASG,EAAUH,EAAO,QAAQ,EACxC,KACCI,EAAI,IAAMJ,CAAK,CACjB,CACF,EACAK,EAAUP,EAAO,KAAK,IAAI,EAAGC,EAAQ,KAAK,EAAE,EAC5CK,EAAIJ,IAAU,CACZ,MAAOF,EAAO,QAAQE,CAAK,EAC3B,MAAO,CACL,OAASA,EAAM,aAAa,sBAAsB,EAClD,QAASA,EAAM,aAAa,uBAAuB,EACnD,OAASA,EAAM,aAAa,sBAAsB,CACpD,CACF,EAAa,EACbM,EAAY,CAAC,CACf,CACJ,CASO,SAASC,GACdC,EACgC,CAChC,OAAOC,EAAM,IAAM,CACjB,IAAMC,EAAQ,IAAIC,EAClBD,EAAM,UAAUE,GAAW,CACzB,SAAS,KAAK,aAAa,0BAA2B,EAAE,EAGxD,OAAW,CAACC,EAAKC,CAAK,IAAK,OAAO,QAAQF,EAAQ,KAAK,EACrD,SAAS,KAAK,aAAa,iBAAiBC,IAAOC,CAAK,EAG1D,QAASC,EAAQ,EAAGA,EAAQjB,EAAO,OAAQiB,IAAS,CAClD,IAAMC,EAAQlB,EAAOiB,GAAO,mBACxBC,aAAiB,cACnBA,EAAM,OAASJ,EAAQ,QAAUG,EACrC,CAGA,SAAS,YAAaH,CAAO,CAC/B,CAAC,EAGDF,EAAM,KAAKO,GAAUC,EAAc,CAAC,EACjC,UAAU,IAAM,CACf,SAAS,KAAK,gBAAgB,yBAAyB,CACzD,CAAC,EAGH,IAAMpB,EAASqB,EAA8B,QAASX,CAAE,EACxD,OAAOX,GAAaC,CAAM,EACvB,KACCsB,EAAIC,GAASX,EAAM,KAAKW,CAAK,CAAC,EAC9BC,EAAS,IAAMZ,EAAM,SAAS,CAAC,EAC/BN,EAAIiB,GAAUE,EAAA,CAAE,IAAKf,GAAOa,EAAQ,CACtC,CACJ,CAAC,CACH,CC/HA,IAAAG,GAAwB,SAiCxB,SAASC,GAAQC,EAAyB,CACxCA,EAAG,aAAa,kBAAmB,EAAE,EACrC,IAAMC,EAAOD,EAAG,UAChB,OAAAA,EAAG,gBAAgB,iBAAiB,EAC7BC,CACT,CAWO,SAASC,GACd,CAAE,OAAAC,CAAO,EACH,CACF,GAAAC,QAAY,YAAY,GAC1B,IAAIC,EAA8BC,GAAc,CAC9C,IAAI,GAAAF,QAAY,iDAAkD,CAChE,KAAMJ,GACJA,EAAG,aAAa,qBAAqB,GACrCD,GAAQQ,EACNP,EAAG,aAAa,uBAAuB,CACzC,CAAC,CAEL,CAAC,EACE,GAAG,UAAWQ,GAAMF,EAAW,KAAKE,CAAE,CAAC,CAC5C,CAAC,EACE,KACCC,EAAID,GAAM,CACQA,EAAG,QACX,MAAM,CAChB,CAAC,EACDE,EAAI,IAAMC,GAAY,kBAAkB,CAAC,CAC3C,EACG,UAAUR,CAAM,CAEzB,CCrCA,SAASS,GAAWC,EAAwB,CAC1C,GAAIA,EAAK,OAAS,EAChB,MAAO,CAAC,EAAE,EAGZ,GAAM,CAACC,EAAMC,CAAI,EAAI,CAAC,GAAGF,CAAI,EAC1B,KAAK,CAACG,EAAGC,IAAMD,EAAE,OAASC,EAAE,MAAM,EAClC,IAAIC,GAAOA,EAAI,QAAQ,SAAU,EAAE,CAAC,EAGnCC,EAAQ,EACZ,GAAIL,IAASC,EACXI,EAAQL,EAAK,WAEb,MAAOA,EAAK,WAAWK,CAAK,IAAMJ,EAAK,WAAWI,CAAK,GACrDA,IAGJ,OAAON,EAAK,IAAIK,GAAOA,EAAI,QAAQJ,EAAK,MAAM,EAAGK,CAAK,EAAG,EAAE,CAAC,CAC9D,CAaO,SAASC,GAAaC,EAAiC,CAC5D,IAAMC,EAAS,SAAkB,YAAa,eAAgBD,CAAI,EAClE,GAAIC,EACF,OAAOC,EAAGD,CAAM,EACX,CACL,IAAME,EAASC,GAAc,EAC7B,OAAOC,GAAW,IAAI,IAAI,cAAeL,GAAQG,EAAO,IAAI,CAAC,EAC1D,KACCG,EAAIC,GAAWhB,GAAWiB,EAAY,MAAOD,CAAO,EACjD,IAAIE,GAAQA,EAAK,WAAY,CAChC,CAAC,EACDC,GAAW,IAAMC,CAAK,EACtBC,GAAe,CAAC,CAAC,EACjBC,EAAIN,GAAW,SAAS,YAAaA,EAAS,eAAgBP,CAAI,CAAC,CACrE,CACJ,CACF,CCIO,SAASc,GACd,CAAE,UAAAC,EAAW,UAAAC,EAAW,UAAAC,CAAU,EAC5B,CACN,IAAMC,EAASC,GAAc,EAC7B,GAAI,SAAS,WAAa,QACxB,OAGE,sBAAuB,UACzB,QAAQ,kBAAoB,SAG5BC,EAAU,OAAQ,cAAc,EAC7B,UAAU,IAAM,CACf,QAAQ,kBAAoB,MAC9B,CAAC,GAIL,IAAMC,EAAUC,GAAoC,gBAAgB,EAChE,OAAOD,GAAY,cACrBA,EAAQ,KAAOA,EAAQ,MAGzB,IAAME,EAAQC,GAAa,EACxB,KACCC,EAAIC,GAASA,EAAM,IAAIC,GAAQ,GAAG,IAAI,IAAIA,EAAMT,EAAO,IAAI,GAAG,CAAC,EAC/DU,EAAUC,GAAQT,EAAsB,SAAS,KAAM,OAAO,EAC3D,KACCU,EAAOC,GAAM,CAACA,EAAG,SAAW,CAACA,EAAG,OAAO,EACvCH,EAAUG,GAAM,CACd,GAAIA,EAAG,kBAAkB,QAAS,CAChC,IAAMC,EAAKD,EAAG,OAAO,QAAQ,GAAG,EAChC,GAAIC,GAAM,CAACA,EAAG,OAAQ,CACpB,IAAMC,EAAM,IAAI,IAAID,EAAG,IAAI,EAO3B,GAJAC,EAAI,OAAS,GACbA,EAAI,KAAO,GAITA,EAAI,WAAa,SAAS,UAC1BJ,EAAK,SAASI,EAAI,SAAS,CAAC,EAE5B,OAAAF,EAAG,eAAe,EACXG,EAAG,CACR,IAAK,IAAI,IAAIF,EAAG,IAAI,CACtB,CAAC,CAEL,CACF,CACA,OAAOG,EACT,CAAC,CACH,CACF,EACAC,GAAoB,CACtB,EAGIC,EAAOjB,EAAyB,OAAQ,UAAU,EACrD,KACCU,EAAOC,GAAMA,EAAG,QAAU,IAAI,EAC9BN,EAAIM,IAAO,CACT,IAAK,IAAI,IAAI,SAAS,IAAI,EAC1B,OAAQA,EAAG,KACb,EAAE,EACFK,GAAoB,CACtB,EAGFE,EAAMf,EAAOc,CAAI,EACd,KACCE,EAAqB,CAACC,EAAGC,IAAMD,EAAE,IAAI,OAASC,EAAE,IAAI,IAAI,EACxDhB,EAAI,CAAC,CAAE,IAAAQ,CAAI,IAAMA,CAAG,CACtB,EACG,UAAUjB,CAAS,EAGxB,IAAM0B,EAAY1B,EACf,KACC2B,EAAwB,UAAU,EAClCf,EAAUK,GAAOW,GAAQX,EAAI,IAAI,EAC9B,KACCY,GAAW,KACTC,GAAYb,CAAG,EACRE,GACR,CACH,CACF,EACAC,GAAM,CACR,EAGFb,EACG,KACCwB,GAAOL,CAAS,CAClB,EACG,UAAU,CAAC,CAAE,IAAAT,CAAI,IAAM,CACtB,QAAQ,UAAU,CAAC,EAAG,GAAI,GAAGA,GAAK,CACpC,CAAC,EAGL,IAAMe,EAAM,IAAI,UAChBN,EACG,KACCd,EAAUqB,GAAOA,EAAI,KAAK,CAAC,EAC3BxB,EAAIwB,GAAOD,EAAI,gBAAgBC,EAAK,WAAW,CAAC,CAClD,EACG,UAAUlC,CAAS,EAGxBA,EACG,KACCmC,GAAK,CAAC,CACR,EACG,UAAUC,GAAe,CACxB,QAAWC,IAAY,CAGrB,QACA,sBACA,oBACA,yBAGA,+BACA,gCACA,mCACA,+BACA,2BACA,2BACA,GAAGC,GAAQ,wBAAwB,EAC/B,CAAC,0BAA0B,EAC3B,CAAC,CACP,EAAG,CACD,IAAMC,EAAShC,GAAmB8B,CAAQ,EACpCG,EAASjC,GAAmB8B,EAAUD,CAAW,EAErD,OAAOG,GAAW,aAClB,OAAOC,GAAW,aAElBD,EAAO,YAAYC,CAAM,CAE7B,CACF,CAAC,EAGLxC,EACG,KACCmC,GAAK,CAAC,EACNzB,EAAI,IAAM+B,GAAoB,WAAW,CAAC,EAC1C5B,EAAUI,GAAMyB,EAAY,SAAUzB,CAAE,CAAC,EACzC0B,GAAU1B,GAAM,CACd,IAAM2B,EAASC,EAAE,QAAQ,EACzB,GAAI5B,EAAG,IAAK,CACV,QAAW6B,KAAQ7B,EAAG,kBAAkB,EACtC2B,EAAO,aAAaE,EAAM7B,EAAG,aAAa6B,CAAI,CAAE,EAClD,OAAA7B,EAAG,YAAY2B,CAAM,EAGd,IAAIG,EAAWC,GAAY,CAChCJ,EAAO,OAAS,IAAMI,EAAS,SAAS,CAC1C,CAAC,CAGH,KACE,QAAAJ,EAAO,YAAc3B,EAAG,YACxBA,EAAG,YAAY2B,CAAM,EACdK,CAEX,CAAC,CACH,EACG,UAAU,EAGf1B,EAAMf,EAAOc,CAAI,EACd,KACCU,GAAOhC,CAAS,CAClB,EACG,UAAU,CAAC,CAAE,IAAAkB,EAAK,OAAAgC,CAAO,IAAM,CAC1BhC,EAAI,MAAQ,CAACgC,EACfC,GAAgBjC,EAAI,IAAI,EAExB,OAAO,SAAS,GAAGgC,GAAA,YAAAA,EAAQ,IAAK,CAAC,CAErC,CAAC,EAGLhD,EACG,KACCkD,GAAU5C,CAAK,EACf6C,GAAa,GAAG,EAChBzB,EAAwB,QAAQ,CAClC,EACG,UAAU,CAAC,CAAE,OAAAsB,CAAO,IAAM,CACzB,QAAQ,aAAaA,EAAQ,EAAE,CACjC,CAAC,EAGL3B,EAAMf,EAAOc,CAAI,EACd,KACCgC,GAAY,EAAG,CAAC,EAChBvC,EAAO,CAAC,CAACU,EAAGC,CAAC,IAAMD,EAAE,IAAI,WAAaC,EAAE,IAAI,QAAQ,EACpDhB,EAAI,CAAC,CAAC,CAAE6C,CAAK,IAAMA,CAAK,CAC1B,EACG,UAAU,CAAC,CAAE,OAAAL,CAAO,IAAM,CACzB,OAAO,SAAS,GAAGA,GAAA,YAAAA,EAAQ,IAAK,CAAC,CACnC,CAAC,CACP,CCzSA,IAAAM,GAAuB,SCAvB,IAAAC,GAAuB,SAsChB,SAASC,GACdC,EAA2BC,EACD,CAC1B,IAAMC,EAAY,IAAI,OAAOF,EAAO,UAAW,KAAK,EAC9CG,EAAY,CAACC,EAAYC,EAAcC,IACpC,GAAGD,4BAA+BC,WAI3C,OAAQC,GAAkB,CACxBA,EAAQA,EACL,QAAQ,gBAAiB,GAAG,EAC5B,KAAK,EAGR,IAAMC,EAAQ,IAAI,OAAO,MAAMR,EAAO,cACpCO,EACG,QAAQ,uBAAwB,MAAM,EACtC,QAAQL,EAAW,GAAG,KACtB,KAAK,EAGV,OAAOO,IACLR,KACI,GAAAS,SAAWD,CAAK,EAChBA,GAED,QAAQD,EAAOL,CAAS,EACxB,QAAQ,8BAA+B,IAAI,CAClD,CACF,CC9BO,SAASQ,GAAiBC,EAAuB,CACtD,OAAOA,EACJ,MAAM,YAAY,EAChB,IAAI,CAACC,EAAOC,IAAUA,EAAQ,EAC3BD,EAAM,QAAQ,+BAAgC,IAAI,EAClDA,CACJ,EACC,KAAK,EAAE,EACT,QAAQ,kCAAmC,EAAE,EAC7C,KAAK,CACV,CCoCO,SAASE,GACdC,EAC+B,CAC/B,OAAOA,EAAQ,OAAS,CAC1B,CASO,SAASC,GACdD,EAC+B,CAC/B,OAAOA,EAAQ,OAAS,CAC1B,CASO,SAASE,GACdF,EACgC,CAChC,OAAOA,EAAQ,OAAS,CAC1B,CCvEA,SAASG,GAAiB,CAAE,OAAAC,EAAQ,KAAAC,CAAK,EAA6B,CAGhED,EAAO,KAAK,SAAW,GAAKA,EAAO,KAAK,KAAO,OACjDA,EAAO,KAAO,CACZE,GAAY,oBAAoB,CAClC,GAGEF,EAAO,YAAc,cACvBA,EAAO,UAAYE,GAAY,yBAAyB,GAQ1D,IAAMC,EAAyB,CAC7B,SANeD,GAAY,wBAAwB,EAClD,MAAM,SAAS,EACf,OAAO,OAAO,EAKf,YAAaE,GAAQ,gBAAgB,CACvC,EAGA,MAAO,CAAE,OAAAJ,EAAQ,KAAAC,EAAM,QAAAE,CAAQ,CACjC,CAkBO,SAASE,GACdC,EAAaC,EACC,CACd,IAAMP,EAASQ,GAAc,EACvBC,EAAS,IAAI,OAAOH,CAAG,EAGvBI,EAAM,IAAIC,EACVC,EAAMC,GAAYJ,EAAQ,CAAE,IAAAC,CAAI,CAAC,EACpC,KACCI,EAAIC,GAAW,CACb,GAAIC,GAAsBD,CAAO,EAC/B,QAAWE,KAAUF,EAAQ,KAAK,MAChC,QAAWG,KAAYD,EACrBC,EAAS,SAAW,GAAG,IAAI,IAAIA,EAAS,SAAUlB,EAAO,IAAI,IAEnE,OAAOe,CACT,CAAC,EACDI,GAAM,CACR,EAGF,OAAAC,GAAKb,CAAK,EACP,KACCO,EAAIO,IAAS,CACX,OACA,KAAMtB,GAAiBsB,CAAI,CAC7B,EAAwB,CAC1B,EACG,UAAUX,EAAI,KAAK,KAAKA,CAAG,CAAC,EAG1B,CAAE,IAAAA,EAAK,IAAAE,CAAI,CACpB,CCvEO,SAASU,GACd,CAAE,UAAAC,CAAU,EACN,CACN,IAAMC,EAASC,GAAc,EACvBC,EAAYC,GAChB,IAAI,IAAI,mBAAoBH,EAAO,IAAI,CACzC,EACG,KACCI,GAAW,IAAMC,CAAK,CACxB,EAGIC,EAAWJ,EACd,KACCK,EAAIC,GAAY,CACd,GAAM,CAAC,CAAEC,CAAO,EAAIT,EAAO,KAAK,MAAM,aAAa,EACnD,OAAOQ,EAAS,KAAK,CAAC,CAAE,QAAAE,EAAS,QAAAC,CAAQ,IACvCD,IAAYD,GAAWE,EAAQ,SAASF,CAAO,CAChD,GAAKD,EAAS,EACjB,CAAC,CACH,EAGFN,EACG,KACCK,EAAIC,GAAY,IAAI,IAAIA,EAAS,IAAIE,GAAW,CAC9C,GAAG,IAAI,IAAI,MAAMA,EAAQ,WAAYV,EAAO,IAAI,IAChDU,CACF,CAAC,CAAC,CAAC,EACHE,EAAUC,GAAQC,EAAsB,SAAS,KAAM,OAAO,EAC3D,KACCC,EAAOC,GAAM,CAACA,EAAG,SAAW,CAACA,EAAG,OAAO,EACvCC,GAAeX,CAAQ,EACvBM,EAAU,CAAC,CAACI,EAAIP,CAAO,IAAM,CAC3B,GAAIO,EAAG,kBAAkB,QAAS,CAChC,IAAME,EAAKF,EAAG,OAAO,QAAQ,GAAG,EAChC,GAAIE,GAAM,CAACA,EAAG,QAAUL,EAAK,IAAIK,EAAG,IAAI,EAAG,CACzC,IAAMC,EAAMD,EAAG,KAWf,MAAI,CAACF,EAAG,OAAO,QAAQ,aAAa,GAClBH,EAAK,IAAIM,CAAG,IACZV,EACPJ,GAEXW,EAAG,eAAe,EACXI,EAAGD,CAAG,EACf,CACF,CACA,OAAOd,CACT,CAAC,EACDO,EAAUO,GAAO,CACf,GAAM,CAAE,QAAAT,CAAQ,EAAIG,EAAK,IAAIM,CAAG,EAChC,OAAOE,GAAa,IAAI,IAAIF,CAAG,CAAC,EAC7B,KACCZ,EAAIe,GAAW,CAEb,IAAMC,EADWC,GAAY,EACP,KAAK,QAAQxB,EAAO,KAAM,EAAE,EAClD,OAAOsB,EAAQ,SAASC,EAAK,MAAM,GAAG,EAAE,EAAE,EACtC,IAAI,IAAI,MAAMb,KAAWa,IAAQvB,EAAO,IAAI,EAC5C,IAAI,IAAImB,CAAG,CACjB,CAAC,CACH,CACJ,CAAC,CACH,CACF,CACF,EACG,UAAUA,GAAOM,GAAYN,CAAG,CAAC,EAGtCO,EAAc,CAACxB,EAAWI,CAAQ,CAAC,EAChC,UAAU,CAAC,CAACE,EAAUC,CAAO,IAAM,CACpBkB,EAAW,mBAAmB,EACtC,YAAYC,GAAsBpB,EAAUC,CAAO,CAAC,CAC5D,CAAC,EAGHV,EAAU,KAAKa,EAAU,IAAMN,CAAQ,CAAC,EACrC,UAAUG,GAAW,CA5J1B,IAAAoB,EA+JM,IAAIC,EAAW,SAAS,aAAc,cAAc,EACpD,GAAIA,IAAa,KAAM,CACrB,IAAMC,IAASF,EAAA7B,EAAO,UAAP,YAAA6B,EAAgB,UAAW,SAC1CC,EAAW,CAACrB,EAAQ,QAAQ,SAASsB,CAAM,EAG3C,SAAS,aAAcD,EAAU,cAAc,CACjD,CAGA,GAAIA,EACF,QAAWE,KAAWC,GAAqB,UAAU,EACnDD,EAAQ,OAAS,EACvB,CAAC,CACL,CCtFO,SAASE,GACdC,EAAsB,CAAE,IAAAC,CAAI,EACH,CACzB,IAAMC,GAAK,+BAAU,YAAaC,GAG5B,CAAE,aAAAC,CAAa,EAAIC,GAAY,EACjCD,EAAa,IAAI,GAAG,GACtBE,GAAU,SAAU,EAAI,EAG1B,IAAMC,EAASN,EACZ,KACCO,EAAOC,EAAoB,EAC3BC,GAAK,CAAC,EACNC,EAAI,IAAMP,EAAa,IAAI,GAAG,GAAK,EAAE,CACvC,EAGFQ,GAAY,QAAQ,EACjB,KACCJ,EAAOK,GAAU,CAACA,CAAM,EACxBH,GAAK,CAAC,CACR,EACG,UAAU,IAAM,CACf,IAAMI,EAAM,IAAI,IAAI,SAAS,IAAI,EACjCA,EAAI,aAAa,OAAO,GAAG,EAC3B,QAAQ,aAAa,CAAC,EAAG,GAAI,GAAGA,GAAK,CACvC,CAAC,EAGLP,EAAO,UAAUQ,GAAS,CACpBA,IACFf,EAAG,MAAQe,EACXf,EAAG,MAAM,EAEb,CAAC,EAGD,IAAMgB,EAASC,GAAkBjB,CAAE,EAC7BkB,EAASC,EACbC,EAAUpB,EAAI,OAAO,EACrBoB,EAAUpB,EAAI,OAAO,EAAE,KAAKqB,GAAM,CAAC,CAAC,EACpCd,CACF,EACG,KACCI,EAAI,IAAMT,EAAGF,EAAG,KAAK,CAAC,EACtBsB,EAAU,EAAE,EACZC,EAAqB,CACvB,EAGF,OAAOC,EAAc,CAACN,EAAQF,CAAM,CAAC,EAClC,KACCL,EAAI,CAAC,CAACI,EAAOU,CAAK,KAAO,CAAE,MAAAV,EAAO,MAAAU,CAAM,EAAE,EAC1CC,EAAY,CAAC,CACf,CACJ,CAUO,SAASC,GACd3B,EAAsB,CAAE,IAAA4B,EAAK,IAAA3B,CAAI,EACqB,CACtD,IAAM4B,EAAQ,IAAIC,EACZC,EAAQF,EAAM,KAAKG,GAAS,CAAC,CAAC,EAGpC,OAAAH,EACG,KACCI,EAAwB,OAAO,EAC/BtB,EAAI,CAAC,CAAE,MAAAI,CAAM,KAA2B,CACtC,OACA,KAAMA,CACR,EAAE,CACJ,EACG,UAAUa,EAAI,KAAK,KAAKA,CAAG,CAAC,EAGjCC,EACG,KACCI,EAAwB,OAAO,CACjC,EACG,UAAU,CAAC,CAAE,MAAAR,CAAM,IAAM,CACpBA,GACFnB,GAAU,SAAUmB,CAAK,EACzBzB,EAAG,YAAc,IAEjBA,EAAG,YAAckC,GAAY,oBAAoB,CAErD,CAAC,EAGLd,EAAUpB,EAAG,KAAO,OAAO,EACxB,KACCmC,EAAUJ,CAAK,CACjB,EACG,UAAU,IAAM/B,EAAG,MAAM,CAAC,EAGxBD,GAAiBC,EAAI,CAAE,IAAA4B,EAAK,IAAA3B,CAAI,CAAC,EACrC,KACCmC,EAAIC,GAASR,EAAM,KAAKQ,CAAK,CAAC,EAC9BC,EAAS,IAAMT,EAAM,SAAS,CAAC,EAC/BlB,EAAI0B,GAAUE,EAAA,CAAE,IAAKvC,GAAOqC,EAAQ,EACpCG,GAAM,CACR,CACJ,CCrHO,SAASC,GACdC,EAAiB,CAAE,IAAAC,CAAI,EAAiB,CAAE,OAAAC,CAAO,EACZ,CACrC,IAAMC,EAAQ,IAAIC,EACZC,EAAYC,GAAqBN,EAAG,aAAc,EACrD,KACCO,EAAO,OAAO,CAChB,EAGIC,EAAOC,EAAW,wBAAyBT,CAAE,EAC7CU,EAAOD,EAAW,uBAAwBT,CAAE,EAG5CW,EAASV,EACZ,KACCM,EAAOK,EAAoB,EAC3BC,GAAK,CAAC,CACR,EAGF,OAAAV,EACG,KACCW,GAAeZ,CAAM,EACrBa,GAAUJ,CAAM,CAClB,EACG,UAAU,CAAC,CAAC,CAAE,MAAAK,CAAM,EAAG,CAAE,MAAAC,CAAM,CAAC,IAAM,CACrC,GAAIA,EACF,OAAQD,EAAM,YAGP,GACHR,EAAK,YAAcU,GAAY,oBAAoB,EACnD,UAGG,GACHV,EAAK,YAAcU,GAAY,mBAAmB,EAClD,cAIAV,EAAK,YAAcU,GACjB,sBACAC,GAAMH,EAAM,MAAM,CACpB,OAGJR,EAAK,YAAcU,GAAY,2BAA2B,CAE9D,CAAC,EAGLf,EACG,KACCiB,EAAI,IAAMV,EAAK,UAAY,EAAE,EAC7BW,EAAU,CAAC,CAAE,MAAAL,CAAM,IAAMM,EACvBC,EAAG,GAAGP,EAAM,MAAM,EAAG,EAAE,CAAC,EACxBO,EAAG,GAAGP,EAAM,MAAM,EAAE,CAAC,EAClB,KACCQ,GAAY,CAAC,EACbC,GAAQpB,CAAS,EACjBgB,EAAU,CAAC,CAACK,CAAK,IAAMA,CAAK,CAC9B,CACJ,CAAC,CACH,EACG,UAAUC,GAAUjB,EAAK,YACxBkB,GAAuBD,CAAM,CAC/B,CAAC,EAGW1B,EACb,KACCM,EAAOsB,EAAqB,EAC5BC,EAAI,CAAC,CAAE,KAAAC,CAAK,IAAMA,CAAI,CACxB,EAIC,KACCX,EAAIY,GAAS7B,EAAM,KAAK6B,CAAK,CAAC,EAC9BC,EAAS,IAAM9B,EAAM,SAAS,CAAC,EAC/B2B,EAAIE,GAAUE,EAAA,CAAE,IAAKlC,GAAOgC,EAAQ,CACtC,CACJ,CC1FO,SAASG,GACdC,EAAkB,CAAE,OAAAC,CAAO,EACF,CACzB,OAAOA,EACJ,KACCC,EAAI,CAAC,CAAE,MAAAC,CAAM,IAAM,CACjB,IAAMC,EAAMC,GAAY,EACxB,OAAAD,EAAI,KAAO,GACXA,EAAI,aAAa,OAAO,GAAG,EAC3BA,EAAI,aAAa,IAAI,IAAKD,CAAK,EACxB,CAAE,IAAAC,CAAI,CACf,CAAC,CACH,CACJ,CAUO,SAASE,GACdC,EAAuBC,EACa,CACpC,IAAMC,EAAQ,IAAIC,EAClB,OAAAD,EAAM,UAAU,CAAC,CAAE,IAAAL,CAAI,IAAM,CAC3BG,EAAG,aAAa,sBAAuBA,EAAG,IAAI,EAC9CA,EAAG,KAAO,GAAGH,GACf,CAAC,EAGDO,EAAUJ,EAAI,OAAO,EAClB,UAAUK,GAAMA,EAAG,eAAe,CAAC,EAG/Bb,GAAiBQ,EAAIC,CAAO,EAChC,KACCK,EAAIC,GAASL,EAAM,KAAKK,CAAK,CAAC,EAC9BC,EAAS,IAAMN,EAAM,SAAS,CAAC,EAC/BP,EAAIY,GAAUE,EAAA,CAAE,IAAKT,GAAOO,EAAQ,CACtC,CACJ,CCtCO,SAASG,GACdC,EAAiB,CAAE,IAAAC,CAAI,EAAiB,CAAE,UAAAC,CAAU,EACd,CACtC,IAAMC,EAAQ,IAAIC,EAGZC,EAASC,GAAoB,cAAc,EAC3CC,EAASC,EACbC,EAAUJ,EAAO,SAAS,EAC1BI,EAAUJ,EAAO,OAAO,CAC1B,EACG,KACCK,GAAUC,EAAc,EACxBC,EAAI,IAAMP,EAAM,KAAK,EACrBQ,EAAqB,CACvB,EAGF,OAAAV,EACG,KACCW,GAAkBP,CAAM,EACxBK,EAAI,CAAC,CAAC,CAAE,YAAAG,CAAY,EAAGC,CAAK,IAAM,CAChC,IAAMC,EAAQD,EAAM,MAAM,UAAU,EACpC,IAAID,GAAA,YAAAA,EAAa,SAAUE,EAAMA,EAAM,OAAS,GAAI,CAClD,IAAMC,EAAOH,EAAYA,EAAY,OAAS,GAC1CG,EAAK,WAAWD,EAAMA,EAAM,OAAS,EAAE,IACzCA,EAAMA,EAAM,OAAS,GAAKC,EAC9B,MACED,EAAM,OAAS,EAEjB,OAAOA,CACT,CAAC,CACH,EACG,UAAUA,GAASjB,EAAG,UAAYiB,EAChC,KAAK,EAAE,EACP,QAAQ,MAAO,QAAQ,CAC1B,EAGJf,EACG,KACCiB,EAAO,CAAC,CAAE,KAAAC,CAAK,IAAMA,IAAS,QAAQ,CACxC,EACG,UAAUC,GAAO,CAChB,OAAQA,EAAI,UAGL,aAEDrB,EAAG,UAAU,QACbK,EAAM,iBAAmBA,EAAM,MAAM,SAErCA,EAAM,MAAQL,EAAG,WACnB,MAEN,CAAC,EAGWC,EACb,KACCkB,EAAOG,EAAqB,EAC5BV,EAAI,CAAC,CAAE,KAAAW,CAAK,IAAMA,CAAI,CACxB,EAIC,KACCC,EAAIC,GAAStB,EAAM,KAAKsB,CAAK,CAAC,EAC9BC,EAAS,IAAMvB,EAAM,SAAS,CAAC,EAC/BS,EAAI,KAAO,CAAE,IAAKZ,CAAG,EAAE,CACzB,CACJ,CC9CO,SAAS2B,GACdC,EAAiB,CAAE,OAAAC,EAAQ,UAAAC,CAAU,EACN,CAC/B,IAAMC,EAASC,GAAc,EAC7B,GAAI,CACF,IAAMC,GAAM,+BAAU,SAAUF,EAAO,OACjCG,EAASC,GAAkBF,EAAKJ,CAAM,EAGtCO,EAASC,GAAoB,eAAgBT,CAAE,EAC/CU,EAASD,GAAoB,gBAAiBT,CAAE,EAGhD,CAAE,IAAAW,EAAK,IAAAC,CAAI,EAAIN,EACrBK,EACG,KACCE,EAAOC,EAAoB,EAC3BC,GAAOH,EAAI,KAAKC,EAAOG,EAAoB,CAAC,CAAC,EAC7CC,GAAK,CAAC,CACR,EACG,UAAUN,EAAI,KAAK,KAAKA,CAAG,CAAC,EAGjCT,EACG,KACCW,EAAO,CAAC,CAAE,KAAAK,CAAK,IAAMA,IAAS,QAAQ,CACxC,EACG,UAAUC,GAAO,CAChB,IAAMC,EAASC,GAAiB,EAChC,OAAQF,EAAI,UAGL,QACH,GAAIC,IAAWZ,EAAO,CACpB,IAAMc,EAAU,IAAI,IACpB,QAAWC,KAAUC,EACnB,sBAAuBd,CACzB,EAAG,CACD,IAAMe,EAAUF,EAAO,kBACvBD,EAAQ,IAAIC,EAAQ,WAClBE,EAAQ,aAAa,eAAe,CACtC,CAAC,CACH,CAGA,GAAIH,EAAQ,KAAM,CAChB,GAAM,CAAC,CAACI,CAAI,CAAC,EAAI,CAAC,GAAGJ,CAAO,EAAE,KAAK,CAAC,CAAC,CAAEK,CAAC,EAAG,CAAC,CAAEC,CAAC,IAAMA,EAAID,CAAC,EAC1DD,EAAK,MAAM,CACb,CAGAP,EAAI,MAAM,CACZ,CACA,UAGG,aACA,MACHU,GAAU,SAAU,EAAK,EACzBrB,EAAM,KAAK,EACX,UAGG,cACA,YACH,GAAI,OAAOY,GAAW,YACpBZ,EAAM,MAAM,MACP,CACL,IAAMsB,EAAM,CAACtB,EAAO,GAAGgB,EACrB,wDACAd,CACF,CAAC,EACKqB,EAAI,KAAK,IAAI,GACjB,KAAK,IAAI,EAAGD,EAAI,QAAQV,CAAM,CAAC,EAAIU,EAAI,QACrCX,EAAI,OAAS,UAAY,GAAK,IAE9BW,EAAI,MAAM,EACdA,EAAIC,GAAG,MAAM,CACf,CAGAZ,EAAI,MAAM,EACV,cAIIX,IAAUa,GAAiB,GAC7Bb,EAAM,MAAM,EAEpB,CAAC,EAGLN,EACG,KACCW,EAAO,CAAC,CAAE,KAAAK,CAAK,IAAMA,IAAS,QAAQ,CACxC,EACG,UAAUC,GAAO,CAChB,OAAQA,EAAI,UAGL,QACA,QACA,IACHX,EAAM,MAAM,EACZA,EAAM,OAAO,EAGbW,EAAI,MAAM,EACV,MAEN,CAAC,EAGL,IAAMa,EAAUC,GAAiBzB,EAAOF,CAAM,EACxC4B,EAAUC,GAAkBzB,EAAQJ,EAAQ,CAAE,OAAA0B,CAAO,CAAC,EAC5D,OAAOI,EAAMJ,EAAQE,CAAO,EACzB,KACCG,GAGE,GAAGC,GAAqB,eAAgBtC,CAAE,EACvC,IAAIuC,GAASC,GAAiBD,EAAO,CAAE,OAAAP,CAAO,CAAC,CAAC,EAGnD,GAAGM,GAAqB,iBAAkBtC,CAAE,EACzC,IAAIuC,GAASE,GAAmBF,EAAOjC,EAAQ,CAAE,UAAAJ,CAAU,CAAC,CAAC,CAClE,CACF,CAGJ,OAASwC,EAAP,CACA,OAAA1C,EAAG,OAAS,GACL2C,EACT,CACF,CCtKO,SAASC,GACdC,EAAiB,CAAE,OAAAC,EAAQ,UAAAC,CAAU,EACG,CACxC,OAAOC,EAAc,CACnBF,EACAC,EACG,KACCE,EAAUC,GAAY,CAAC,EACvBC,EAAOC,GAAO,CAAC,CAACA,EAAI,aAAa,IAAI,GAAG,CAAC,CAC3C,CACJ,CAAC,EACE,KACCC,EAAI,CAAC,CAACC,EAAOF,CAAG,IAAMG,GAAuBD,EAAM,OAAQ,EAAI,EAC7DF,EAAI,aAAa,IAAI,GAAG,CAC1B,CAAC,EACDC,EAAIG,GAAM,CA1FhB,IAAAC,EA2FQ,IAAMC,EAAQ,IAAI,IAGZC,EAAK,SAAS,mBAAmBd,EAAI,WAAW,SAAS,EAC/D,QAASe,EAAOD,EAAG,SAAS,EAAGC,EAAMA,EAAOD,EAAG,SAAS,EACtD,IAAIF,EAAAG,EAAK,gBAAL,MAAAH,EAAoB,aAAc,CACpC,IAAMI,EAAWD,EAAK,YAChBE,EAAWN,EAAGK,CAAQ,EACxBC,EAAS,OAASD,EAAS,QAC7BH,EAAM,IAAIE,EAAmBE,CAAQ,CACzC,CAIF,OAAW,CAACF,EAAMG,CAAI,IAAKL,EAAO,CAChC,GAAM,CAAE,WAAAM,CAAW,EAAIC,EAAE,OAAQ,KAAMF,CAAI,EAC3CH,EAAK,YAAY,GAAG,MAAM,KAAKI,CAAU,CAAC,CAC5C,CAGA,MAAO,CAAE,IAAKnB,EAAI,MAAAa,CAAM,CAC1B,CAAC,CACH,CACJ,CClBO,SAASQ,GACdC,EAAiB,CAAE,UAAAC,EAAW,MAAAC,CAAM,EACf,CACrB,IAAMC,EAASH,EAAG,cACZI,EACJD,EAAO,UACPA,EAAO,cAAe,UAGxB,OAAOE,EAAc,CAACH,EAAOD,CAAS,CAAC,EACpC,KACCK,EAAI,CAAC,CAAC,CAAE,OAAAC,EAAQ,OAAAC,CAAO,EAAG,CAAE,OAAQ,CAAE,EAAAC,CAAE,CAAE,CAAC,KACzCD,EAASA,EACL,KAAK,IAAIJ,EAAQ,KAAK,IAAI,EAAGK,EAAIF,CAAM,CAAC,EACxCH,EACG,CACL,OAAAI,EACA,OAAQC,GAAKF,EAASH,CACxB,EACD,EACDM,EAAqB,CAACC,EAAGC,IACvBD,EAAE,SAAWC,EAAE,QACfD,EAAE,SAAWC,EAAE,MAChB,CACH,CACJ,CAuBO,SAASC,GACdb,EAAiBc,EACe,CADf,IAAAC,EAAAD,EAAE,SAAAE,CAjJrB,EAiJmBD,EAAcE,EAAAC,GAAdH,EAAc,CAAZ,YAEnB,IAAMI,EAAQC,EAAW,0BAA2BpB,CAAE,EAChD,CAAE,EAAAS,CAAE,EAAIY,GAAiBF,CAAK,EACpC,OAAOG,EAAM,IAAM,CACjB,IAAMC,EAAQ,IAAIC,EAClB,OAAAD,EACG,KACCE,GAAU,EAAGC,EAAuB,EACpCC,GAAeX,CAAO,CACxB,EACG,UAAU,CAGT,KAAK,CAAC,CAAE,OAAAR,CAAO,EAAG,CAAE,OAAQD,CAAO,CAAC,EAAG,CACrCY,EAAM,MAAM,OAAS,GAAGX,EAAS,EAAIC,MACrCT,EAAG,MAAM,IAAY,GAAGO,KAC1B,EAGA,UAAW,CACTY,EAAM,MAAM,OAAS,GACrBnB,EAAG,MAAM,IAAY,EACvB,CACF,CAAC,EAGED,GAAaC,EAAIiB,CAAO,EAC5B,KACCW,EAAIC,GAASN,EAAM,KAAKM,CAAK,CAAC,EAC9BC,EAAS,IAAMP,EAAM,SAAS,CAAC,EAC/BjB,EAAIuB,GAAUE,EAAA,CAAE,IAAK/B,GAAO6B,EAAQ,CACtC,CACJ,CAAC,CACH,CCxHO,SAASG,GACdC,EAAcC,EACW,CACzB,GAAI,OAAOA,GAAS,YAAa,CAC/B,IAAMC,EAAM,gCAAgCF,KAAQC,IACpD,OAAOE,GAGLC,GAAqB,GAAGF,mBAAqB,EAC1C,KACCG,GAAW,IAAMC,CAAK,EACtBC,EAAIC,IAAY,CACd,QAASA,EAAQ,QACnB,EAAE,EACFC,GAAe,CAAC,CAAC,CACnB,EAGFL,GAAkBF,CAAG,EAClB,KACCG,GAAW,IAAMC,CAAK,EACtBC,EAAIG,IAAS,CACX,MAAOA,EAAK,iBACZ,MAAOA,EAAK,WACd,EAAE,EACFD,GAAe,CAAC,CAAC,CACnB,CACJ,EACG,KACCF,EAAI,CAAC,CAACC,EAASE,CAAI,IAAOC,IAAA,GAAKH,GAAYE,EAAO,CACpD,CAGJ,KAAO,CACL,IAAMR,EAAM,gCAAgCF,IAC5C,OAAOI,GAAkBF,CAAG,EACzB,KACCK,EAAIG,IAAS,CACX,aAAcA,EAAK,YACrB,EAAE,EACFD,GAAe,CAAC,CAAC,CACnB,CACJ,CACF,CCvDO,SAASG,GACdC,EAAcC,EACW,CACzB,IAAMC,EAAM,WAAWF,qBAAwB,mBAAmBC,CAAO,IACzE,OAAOE,GAA2BD,CAAG,EAClC,KACCE,GAAW,IAAMC,CAAK,EACtBC,EAAI,CAAC,CAAE,WAAAC,EAAY,YAAAC,CAAY,KAAO,CACpC,MAAOD,EACP,MAAOC,CACT,EAAE,EACFC,GAAe,CAAC,CAAC,CACnB,CACJ,CCOO,SAASC,GACdC,EACyB,CACzB,GAAM,CAACC,CAAI,EAAID,EAAI,MAAM,mBAAmB,GAAK,CAAC,EAClD,OAAQC,EAAK,YAAY,OAGlB,SACH,GAAM,CAAC,CAAEC,EAAMC,CAAI,EAAIH,EAAI,MAAM,qCAAqC,EACtE,OAAOI,GAA2BF,EAAMC,CAAI,MAGzC,SACH,GAAM,CAAC,CAAEE,EAAMC,CAAI,EAAIN,EAAI,MAAM,oCAAoC,EACrE,OAAOO,GAA2BF,EAAMC,CAAI,UAI5C,OAAOE,EAEb,CCxBA,IAAIC,GAgBG,SAASC,GACdC,EACoB,CACpB,OAAOF,QAAWG,EAAM,IAAM,CAC5B,IAAMC,EAAS,SAAsB,WAAY,cAAc,EAC/D,OAAIA,EACKC,EAAGD,CAAM,EAETE,GAAiBJ,EAAG,IAAI,EAC5B,KACCK,EAAIC,GAAS,SAAS,WAAYA,EAAO,cAAc,CAAC,CAC1D,CACN,CAAC,EACE,KACCC,GAAW,IAAMC,CAAK,EACtBC,EAAOH,GAAS,OAAO,KAAKA,CAAK,EAAE,OAAS,CAAC,EAC7CI,EAAIJ,IAAU,CAAE,MAAAA,CAAM,EAAE,EACxBK,EAAY,CAAC,CACf,EACJ,CASO,SAASC,GACdZ,EAC+B,CAC/B,IAAMa,EAAQC,EAAW,uBAAwBd,CAAE,EACnD,OAAOC,EAAM,IAAM,CACjB,IAAMc,EAAQ,IAAIC,EAClB,OAAAD,EAAM,UAAU,CAAC,CAAE,MAAAT,CAAM,IAAM,CAC7BO,EAAM,YAAYI,GAAkBX,CAAK,CAAC,EAC1CO,EAAM,UAAU,IAAI,+BAA+B,CACrD,CAAC,EAGMd,GAAYC,CAAE,EAClB,KACCK,EAAIa,GAASH,EAAM,KAAKG,CAAK,CAAC,EAC9BC,EAAS,IAAMJ,EAAM,SAAS,CAAC,EAC/BL,EAAIQ,GAAUE,EAAA,CAAE,IAAKpB,GAAOkB,EAAQ,CACtC,CACJ,CAAC,CACH,CCvCO,SAASG,GACdC,EAAiB,CAAE,UAAAC,EAAW,QAAAC,CAAQ,EACpB,CAClB,OAAOC,GAAiB,SAAS,IAAI,EAClC,KACCC,EAAU,IAAMC,GAAgBL,EAAI,CAAE,QAAAE,EAAS,UAAAD,CAAU,CAAC,CAAC,EAC3DK,EAAI,CAAC,CAAE,OAAQ,CAAE,EAAAC,CAAE,CAAE,KACZ,CACL,OAAQA,GAAK,EACf,EACD,EACDC,EAAwB,QAAQ,CAClC,CACJ,CAaO,SAASC,GACdT,EAAiBU,EACY,CAC7B,OAAOC,EAAM,IAAM,CACjB,IAAMC,EAAQ,IAAIC,EAClB,OAAAD,EAAM,UAAU,CAGd,KAAK,CAAE,OAAAE,CAAO,EAAG,CACfd,EAAG,OAASc,CACd,EAGA,UAAW,CACTd,EAAG,OAAS,EACd,CACF,CAAC,GAICe,GAAQ,wBAAwB,EAC5BC,EAAG,CAAE,OAAQ,EAAM,CAAC,EACpBjB,GAAUC,EAAIU,CAAO,GAExB,KACCO,EAAIC,GAASN,EAAM,KAAKM,CAAK,CAAC,EAC9BC,EAAS,IAAMP,EAAM,SAAS,CAAC,EAC/BN,EAAIY,GAAUE,EAAA,CAAE,IAAKpB,GAAOkB,EAAQ,CACtC,CACJ,CAAC,CACH,CCxBO,SAASG,GACdC,EAAiB,CAAE,UAAAC,EAAW,QAAAC,CAAQ,EACT,CAC7B,IAAMC,EAAQ,IAAI,IAGZC,EAAUC,EAA+B,cAAeL,CAAE,EAChE,QAAWM,KAAUF,EAAS,CAC5B,IAAMG,EAAK,mBAAmBD,EAAO,KAAK,UAAU,CAAC,CAAC,EAChDE,EAASC,GAAmB,QAAQF,KAAM,EAC5C,OAAOC,GAAW,aACpBL,EAAM,IAAIG,EAAQE,CAAM,CAC5B,CAGA,IAAME,EAAUR,EACb,KACCS,EAAwB,QAAQ,EAChCC,EAAI,CAAC,CAAE,OAAAC,CAAO,IAAM,CAClB,IAAMC,EAAOC,GAAoB,MAAM,EACjCC,EAAOC,EAAW,wBAAyBH,CAAI,EACrD,OAAOD,EAAS,IACdG,EAAK,UACLF,EAAK,UAET,CAAC,EACDI,GAAM,CACR,EAgFF,OA7EmBC,GAAiB,SAAS,IAAI,EAC9C,KACCR,EAAwB,QAAQ,EAGhCS,EAAUC,GAAQC,EAAM,IAAM,CAC5B,IAAIC,EAA4B,CAAC,EACjC,OAAOC,EAAG,CAAC,GAAGrB,CAAK,EAAE,OAAO,CAACsB,EAAO,CAACnB,EAAQE,CAAM,IAAM,CACvD,KAAOe,EAAK,QACGpB,EAAM,IAAIoB,EAAKA,EAAK,OAAS,EAAE,EACnC,SAAWf,EAAO,SACzBe,EAAK,IAAI,EAOb,IAAIG,EAASlB,EAAO,UACpB,KAAO,CAACkB,GAAUlB,EAAO,eACvBA,EAASA,EAAO,cAChBkB,EAASlB,EAAO,UAIlB,OAAOiB,EAAM,IACX,CAAC,GAAGF,EAAO,CAAC,GAAGA,EAAMjB,CAAM,CAAC,EAAE,QAAQ,EACtCoB,CACF,CACF,EAAG,IAAI,GAAkC,CAAC,CAC5C,CAAC,EACE,KAGCd,EAAIa,GAAS,IAAI,IAAI,CAAC,GAAGA,CAAK,EAAE,KAAK,CAAC,CAAC,CAAEE,CAAC,EAAG,CAAC,CAAEC,CAAC,IAAMD,EAAIC,CAAC,CAAC,CAAC,EAC9DC,GAAkBnB,CAAO,EAGzBU,EAAU,CAAC,CAACK,EAAOK,CAAM,IAAM7B,EAC5B,KACC8B,GAAK,CAAC,CAACC,EAAMC,CAAI,EAAG,CAAE,OAAQ,CAAE,EAAAC,CAAE,EAAG,KAAAC,CAAK,IAAM,CAC9C,IAAMC,EAAOF,EAAIC,EAAK,QAAU,KAAK,MAAMd,EAAK,MAAM,EAGtD,KAAOY,EAAK,QAAQ,CAClB,GAAM,CAAC,CAAEP,CAAM,EAAIO,EAAK,GACxB,GAAIP,EAASI,EAASI,GAAKE,EACzBJ,EAAO,CAAC,GAAGA,EAAMC,EAAK,MAAM,CAAE,MAE9B,MAEJ,CAGA,KAAOD,EAAK,QAAQ,CAClB,GAAM,CAAC,CAAEN,CAAM,EAAIM,EAAKA,EAAK,OAAS,GACtC,GAAIN,EAASI,GAAUI,GAAK,CAACE,EAC3BH,EAAO,CAACD,EAAK,IAAI,EAAI,GAAGC,CAAI,MAE5B,MAEJ,CAGA,MAAO,CAACD,EAAMC,CAAI,CACpB,EAAG,CAAC,CAAC,EAAG,CAAC,GAAGR,CAAK,CAAC,CAAC,EACnBY,EAAqB,CAACV,EAAGC,IACvBD,EAAE,KAAOC,EAAE,IACXD,EAAE,KAAOC,EAAE,EACZ,CACH,CACF,CACF,CACF,CACF,EAIC,KACChB,EAAI,CAAC,CAACoB,EAAMC,CAAI,KAAO,CACrB,KAAMD,EAAK,IAAI,CAAC,CAACT,CAAI,IAAMA,CAAI,EAC/B,KAAMU,EAAK,IAAI,CAAC,CAACV,CAAI,IAAMA,CAAI,CACjC,EAAE,EAGFe,EAAU,CAAE,KAAM,CAAC,EAAG,KAAM,CAAC,CAAE,CAAC,EAChCC,GAAY,EAAG,CAAC,EAChB3B,EAAI,CAAC,CAACe,EAAGC,CAAC,IAGJD,EAAE,KAAK,OAASC,EAAE,KAAK,OAClB,CACL,KAAMA,EAAE,KAAK,MAAM,KAAK,IAAI,EAAGD,EAAE,KAAK,OAAS,CAAC,EAAGC,EAAE,KAAK,MAAM,EAChE,KAAM,CAAC,CACT,EAIO,CACL,KAAMA,EAAE,KAAK,MAAM,EAAE,EACrB,KAAMA,EAAE,KAAK,MAAM,EAAGA,EAAE,KAAK,OAASD,EAAE,KAAK,MAAM,CACrD,CAEH,CACH,CACJ,CAYO,SAASa,GACdxC,EAAiB,CAAE,UAAAC,EAAW,QAAAC,EAAS,QAAAuC,CAAQ,EACP,CACxC,OAAOnB,EAAM,IAAM,CACjB,IAAMoB,EAAQ,IAAIC,EACZC,EAAQF,EAAM,KAAKG,GAAS,CAAC,CAAC,EACpC,OAAAH,EAAM,UAAU,CAAC,CAAE,KAAAV,EAAM,KAAAC,CAAK,IAAM,CAGlC,OAAW,CAAC3B,CAAM,IAAK2B,EACrB3B,EAAO,UAAU,OAAO,sBAAsB,EAC9CA,EAAO,UAAU,OAAO,sBAAsB,EAIhD,OAAW,CAACmB,EAAO,CAACnB,CAAM,CAAC,IAAK0B,EAAK,QAAQ,EAC3C1B,EAAO,UAAU,IAAI,sBAAsB,EAC3CA,EAAO,UAAU,OACf,uBACAmB,IAAUO,EAAK,OAAS,CAC1B,CAEJ,CAAC,EAGGc,GAAQ,qBAAqB,GAC/B7C,EACG,KACC8C,EAAUH,CAAK,EACfjC,EAAwB,QAAQ,EAChCqC,GAAa,GAAG,EAChBC,GAAK,CAAC,EACNF,EAAUN,EAAQ,KAAKQ,GAAK,CAAC,CAAC,CAAC,EAC/BC,GAAO,CAAE,MAAO,GAAI,CAAC,EACrBC,GAAeT,CAAK,CACtB,EACG,UAAU,CAAC,CAAC,CAAE,CAAE,KAAAV,CAAK,CAAC,IAAM,CAC3B,IAAMoB,EAAMC,GAAY,EAGlB/C,EAAS0B,EAAKA,EAAK,OAAS,GAClC,GAAI1B,GAAUA,EAAO,OAAQ,CAC3B,GAAM,CAACgD,CAAM,EAAIhD,EACX,CAAE,KAAAiD,CAAK,EAAI,IAAI,IAAID,EAAO,IAAI,EAChCF,EAAI,OAASG,IACfH,EAAI,KAAOG,EACX,QAAQ,aAAa,CAAC,EAAG,GAAI,GAAGH,GAAK,EAIzC,MACEA,EAAI,KAAO,GACX,QAAQ,aAAa,CAAC,EAAG,GAAI,GAAGA,GAAK,CAEzC,CAAC,EAGArD,GAAqBC,EAAI,CAAE,UAAAC,EAAW,QAAAC,CAAQ,CAAC,EACnD,KACCsD,EAAIC,GAASf,EAAM,KAAKe,CAAK,CAAC,EAC9BC,EAAS,IAAMhB,EAAM,SAAS,CAAC,EAC/B9B,EAAI6C,GAAUE,EAAA,CAAE,IAAK3D,GAAOyD,EAAQ,CACtC,CACJ,CAAC,CACH,CC/OO,SAASG,GACdC,EAAkB,CAAE,UAAAC,EAAW,MAAAC,EAAO,QAAAC,CAAQ,EACvB,CAGvB,IAAMC,EAAaH,EAChB,KACCI,EAAI,CAAC,CAAE,OAAQ,CAAE,EAAAC,CAAE,CAAE,IAAMA,CAAC,EAC5BC,GAAY,EAAG,CAAC,EAChBF,EAAI,CAAC,CAAC,EAAGG,CAAC,IAAM,EAAIA,GAAKA,EAAI,CAAC,EAC9BC,EAAqB,CACvB,EAGIC,EAAUR,EACb,KACCG,EAAI,CAAC,CAAE,OAAAM,CAAO,IAAMA,CAAM,CAC5B,EAGF,OAAOC,EAAc,CAACF,EAASN,CAAU,CAAC,EACvC,KACCC,EAAI,CAAC,CAACM,EAAQE,CAAS,IAAM,EAAEF,GAAUE,EAAU,EACnDJ,EAAqB,EACrBK,EAAUX,EAAQ,KAAKY,GAAK,CAAC,CAAC,CAAC,EAC/BC,GAAQ,EAAI,EACZC,GAAO,CAAE,MAAO,GAAI,CAAC,EACrBZ,EAAIa,IAAW,CAAE,OAAAA,CAAO,EAAE,CAC5B,CACJ,CAYO,SAASC,GACdC,EAAiB,CAAE,UAAAnB,EAAW,QAAAoB,EAAS,MAAAnB,EAAO,QAAAC,CAAQ,EACpB,CAClC,IAAMmB,EAAQ,IAAIC,EACZC,EAAQF,EAAM,KAAKG,GAAS,CAAC,CAAC,EACpC,OAAAH,EAAM,UAAU,CAGd,KAAK,CAAE,OAAAJ,CAAO,EAAG,CACfE,EAAG,OAASF,EACRA,GACFE,EAAG,aAAa,WAAY,IAAI,EAChCA,EAAG,KAAK,GAERA,EAAG,gBAAgB,UAAU,CAEjC,EAGA,UAAW,CACTA,EAAG,MAAM,IAAM,GACfA,EAAG,OAAS,GACZA,EAAG,gBAAgB,UAAU,CAC/B,CACF,CAAC,EAGDC,EACG,KACCP,EAAUU,CAAK,EACfE,EAAwB,QAAQ,CAClC,EACG,UAAU,CAAC,CAAE,OAAAC,CAAO,IAAM,CACzBP,EAAG,MAAM,IAAM,GAAGO,EAAS,MAC7B,CAAC,EAGE5B,GAAeqB,EAAI,CAAE,UAAAnB,EAAW,MAAAC,EAAO,QAAAC,CAAQ,CAAC,EACpD,KACCyB,EAAIC,GAASP,EAAM,KAAKO,CAAK,CAAC,EAC9BC,EAAS,IAAMR,EAAM,SAAS,CAAC,EAC/BjB,EAAIwB,GAAUE,EAAA,CAAE,IAAKX,GAAOS,EAAQ,CACtC,CACJ,CCpHO,SAASG,GACd,CAAE,UAAAC,EAAW,QAAAC,CAAQ,EACf,CACND,EACG,KACCE,EAAU,IAAMC,EAEd,0DACF,CAAC,EACDC,EAAIC,GAAM,CACRA,EAAG,cAAgB,GACnBA,EAAG,QAAU,EACf,CAAC,EACDC,GAASD,GAAME,EAAUF,EAAI,QAAQ,EAClC,KACCG,GAAU,IAAMH,EAAG,UAAU,SAAS,0BAA0B,CAAC,EACjEI,EAAI,IAAMJ,CAAE,CACd,CACF,EACAK,GAAeT,CAAO,CACxB,EACG,UAAU,CAAC,CAACI,EAAIM,CAAM,IAAM,CAC3BN,EAAG,UAAU,OAAO,0BAA0B,EAC1CM,IACFN,EAAG,QAAU,GACjB,CAAC,CACP,CC/BA,SAASO,IAAyB,CAChC,MAAO,qBAAqB,KAAK,UAAU,SAAS,CACtD,CAiBO,SAASC,GACd,CAAE,UAAAC,CAAU,EACN,CACNA,EACG,KACCC,EAAU,IAAMC,EAAY,qBAAqB,CAAC,EAClDC,EAAIC,GAAMA,EAAG,gBAAgB,mBAAmB,CAAC,EACjDC,EAAOP,EAAa,EACpBQ,GAASF,GAAMG,EAAUH,EAAI,YAAY,EACtC,KACCI,EAAI,IAAMJ,CAAE,CACd,CACF,CACF,EACG,UAAUA,GAAM,CACf,IAAMK,EAAML,EAAG,UAGXK,IAAQ,EACVL,EAAG,UAAY,EAGNK,EAAML,EAAG,eAAiBA,EAAG,eACtCA,EAAG,UAAYK,EAAM,EAEzB,CAAC,CACP,CCpCO,SAASC,GACd,CAAE,UAAAC,EAAW,QAAAC,CAAQ,EACf,CACNC,EAAc,CAACC,GAAY,QAAQ,EAAGF,CAAO,CAAC,EAC3C,KACCG,EAAI,CAAC,CAACC,EAAQC,CAAM,IAAMD,GAAU,CAACC,CAAM,EAC3CC,EAAUF,GAAUG,EAAGH,CAAM,EAC1B,KACCI,GAAMJ,EAAS,IAAM,GAAG,CAC1B,CACF,EACAK,GAAeV,CAAS,CAC1B,EACG,UAAU,CAAC,CAACK,EAAQ,CAAE,OAAQ,CAAE,EAAAM,CAAE,CAAC,CAAC,IAAM,CACzC,GAAIN,EACF,SAAS,KAAK,aAAa,qBAAsB,EAAE,EACnD,SAAS,KAAK,MAAM,IAAM,IAAIM,UACzB,CACL,IAAMC,EAAQ,GAAK,SAAS,SAAS,KAAK,MAAM,IAAK,EAAE,EACvD,SAAS,KAAK,gBAAgB,oBAAoB,EAClD,SAAS,KAAK,MAAM,IAAM,GACtBA,GACF,OAAO,SAAS,EAAGA,CAAK,CAC5B,CACF,CAAC,CACP,CC7DK,OAAO,UACV,OAAO,QAAU,SAAUC,EAAa,CACtC,IAAMC,EAA2B,CAAC,EAClC,QAAWC,KAAO,OAAO,KAAKF,CAAG,EAE/BC,EAAK,KAAK,CAACC,EAAKF,EAAIE,EAAI,CAAC,EAG3B,OAAOD,CACT,GAGG,OAAO,SACV,OAAO,OAAS,SAAUD,EAAa,CACrC,IAAMC,EAAiB,CAAC,EACxB,QAAWC,KAAO,OAAO,KAAKF,CAAG,EAE/BC,EAAK,KAAKD,EAAIE,EAAI,EAGpB,OAAOD,CACT,GAKE,OAAO,SAAY,cAGhB,QAAQ,UAAU,WACrB,QAAQ,UAAU,SAAW,SAC3BE,EAA8BC,EACxB,CACF,OAAOD,GAAM,UACf,KAAK,WAAaA,EAAE,KACpB,KAAK,UAAYA,EAAE,MAEnB,KAAK,WAAaA,EAClB,KAAK,UAAYC,EAErB,GAGG,QAAQ,UAAU,cACrB,QAAQ,UAAU,YAAc,YAC3BC,EACG,CACN,IAAMC,EAAS,KAAK,WACpB,GAAIA,EAAQ,CACND,EAAM,SAAW,GACnBC,EAAO,YAAY,IAAI,EAGzB,QAASC,EAAIF,EAAM,OAAS,EAAGE,GAAK,EAAGA,IAAK,CAC1C,IAAIC,EAAOH,EAAME,GACb,OAAOC,GAAS,SAClBA,EAAO,SAAS,eAAeA,CAAI,EAC5BA,EAAK,YACZA,EAAK,WAAW,YAAYA,CAAI,EAG7BD,EAGHD,EAAO,aAAa,KAAK,gBAAkBE,CAAI,EAF/CF,EAAO,aAAaE,EAAM,IAAI,CAGlC,CACF,CACF,IhMDJ,SAAS,gBAAgB,UAAU,OAAO,OAAO,EACjD,SAAS,gBAAgB,UAAU,IAAI,IAAI,EAG3C,IAAMC,GAAYC,GAAc,EAC1BC,GAAYC,GAAc,EAC1BC,GAAYC,GAAoB,EAChCC,GAAYC,GAAc,EAG1BC,GAAYC,GAAc,EAC1BC,GAAYC,GAAW,oBAAoB,EAC3CC,GAAYD,GAAW,qBAAqB,EAC5CE,GAAYC,GAAW,EAGvBC,GAASC,GAAc,EACvBC,GAAS,SAAS,MAAM,UAAU,QAAQ,GAC5C,+BAAU,QAASC,GACnB,IAAI,IAAI,2BAA4BH,GAAO,IAAI,CACjD,EACEI,GAGEC,GAAS,IAAIC,EACnBC,GAAiB,CAAE,OAAAF,EAAO,CAAC,EAGvBG,GAAQ,oBAAoB,GAC9BC,GAAoB,CAAE,UAAAxB,GAAW,UAAAE,GAAW,UAAAM,EAAU,CAAC,EA1HzD,IAAAiB,KA6HIA,GAAAV,GAAO,UAAP,YAAAU,GAAgB,YAAa,QAC/BC,GAAqB,CAAE,UAAA1B,EAAU,CAAC,EAGpC2B,EAAMzB,GAAWE,EAAO,EACrB,KACCwB,GAAM,GAAG,CACX,EACG,UAAU,IAAM,CACfC,GAAU,SAAU,EAAK,EACzBA,GAAU,SAAU,EAAK,CAC3B,CAAC,EAGLvB,GACG,KACCwB,EAAO,CAAC,CAAE,KAAAC,CAAK,IAAMA,IAAS,QAAQ,CACxC,EACG,UAAUC,GAAO,CAChB,OAAQA,EAAI,UAGL,QACA,IACH,IAAMC,EAAOC,GAAmB,kBAAkB,EAC9C,OAAOD,GAAS,aAClBA,EAAK,MAAM,EACb,UAGG,QACA,IACH,IAAME,EAAOD,GAAmB,kBAAkB,EAC9C,OAAOC,GAAS,aAClBA,EAAK,MAAM,EACb,MAEN,CAAC,EAGLC,GAAmB,CAAE,UAAApC,GAAW,QAAAU,EAAQ,CAAC,EACzC2B,GAAe,CAAE,UAAArC,EAAU,CAAC,EAC5BsC,GAAgB,CAAE,UAAA9B,GAAW,QAAAE,EAAQ,CAAC,EAGtC,IAAM6B,GAAUC,GAAYC,GAAoB,QAAQ,EAAG,CAAE,UAAAjC,EAAU,CAAC,EAClEkC,GAAQ1C,GACX,KACC2C,EAAI,IAAMF,GAAoB,MAAM,CAAC,EACrCG,EAAUC,GAAMC,GAAUD,EAAI,CAAE,UAAArC,GAAW,QAAA+B,EAAQ,CAAC,CAAC,EACrDQ,EAAY,CAAC,CACf,EAGIC,GAAWrB,EAGf,GAAGsB,GAAqB,SAAS,EAC9B,IAAIJ,GAAMK,GAAaL,EAAI,CAAE,QAAAzC,EAAQ,CAAC,CAAC,EAG1C,GAAG6C,GAAqB,QAAQ,EAC7B,IAAIJ,GAAMM,GAAYN,EAAI,CAAE,OAAAzB,EAAO,CAAC,CAAC,EAGxC,GAAG6B,GAAqB,QAAQ,EAC7B,IAAIJ,GAAMO,GAAYP,EAAI,CAAE,UAAArC,GAAW,QAAA+B,GAAS,MAAAG,EAAM,CAAC,CAAC,EAG3D,GAAGO,GAAqB,SAAS,EAC9B,IAAIJ,GAAMQ,GAAaR,CAAE,CAAC,EAG7B,GAAGI,GAAqB,QAAQ,EAC7B,IAAIJ,GAAMS,GAAYT,EAAI,CAAE,OAAA5B,GAAQ,UAAAX,EAAU,CAAC,CAAC,EAGnD,GAAG2C,GAAqB,QAAQ,EAC7B,IAAIJ,GAAMU,GAAYV,CAAE,CAAC,CAC9B,EAGMW,GAAWC,EAAM,IAAM9B,EAG3B,GAAGsB,GAAqB,UAAU,EAC/B,IAAIJ,GAAMa,GAAcb,CAAE,CAAC,EAG9B,GAAGI,GAAqB,SAAS,EAC9B,IAAIJ,GAAMc,GAAad,EAAI,CAAE,QAAAzC,GAAS,OAAAS,EAAO,CAAC,CAAC,EAGlD,GAAGoC,GAAqB,SAAS,EAC9B,IAAIJ,GAAMtB,GAAQ,kBAAkB,EACjCqC,GAAoBf,EAAI,CAAE,OAAA5B,GAAQ,UAAAf,EAAU,CAAC,EAC7C2D,CACJ,EAGF,GAAGZ,GAAqB,cAAc,EACnC,IAAIJ,GAAMiB,GAAiBjB,EAAI,CAAE,UAAArC,GAAW,QAAA+B,EAAQ,CAAC,CAAC,EAGzD,GAAGU,GAAqB,SAAS,EAC9B,IAAIJ,GAAMA,EAAG,aAAa,cAAc,IAAM,aAC3CkB,GAAGnD,GAAS,IAAMoD,GAAanB,EAAI,CAAE,UAAArC,GAAW,QAAA+B,GAAS,MAAAG,EAAM,CAAC,CAAC,EACjEqB,GAAGrD,GAAS,IAAMsD,GAAanB,EAAI,CAAE,UAAArC,GAAW,QAAA+B,GAAS,MAAAG,EAAM,CAAC,CAAC,CACrE,EAGF,GAAGO,GAAqB,MAAM,EAC3B,IAAIJ,GAAMoB,GAAUpB,EAAI,CAAE,UAAArC,GAAW,QAAA+B,EAAQ,CAAC,CAAC,EAGlD,GAAGU,GAAqB,KAAK,EAC1B,IAAIJ,GAAMqB,GAAqBrB,EAAI,CAAE,UAAArC,GAAW,QAAA+B,GAAS,QAAAnC,EAAQ,CAAC,CAAC,EAGtE,GAAG6C,GAAqB,KAAK,EAC1B,IAAIJ,GAAMsB,GAAetB,EAAI,CAAE,UAAArC,GAAW,QAAA+B,GAAS,MAAAG,GAAO,QAAAtC,EAAQ,CAAC,CAAC,CACzE,CAAC,EAGKgE,GAAapE,GAChB,KACC4C,EAAU,IAAMY,EAAQ,EACxBa,GAAUrB,EAAQ,EAClBD,EAAY,CAAC,CACf,EAGFqB,GAAW,UAAU,EAMrB,OAAO,UAAapE,GACpB,OAAO,UAAaE,GACpB,OAAO,QAAaE,GACpB,OAAO,UAAaE,GACpB,OAAO,UAAaE,GACpB,OAAO,QAAaE,GACpB,OAAO,QAAaE,GACpB,OAAO,OAAaC,GACpB,OAAO,OAAaO,GACpB,OAAO,WAAagD", - "names": ["require_focus_visible", "__commonJSMin", "exports", "module", "global", "factory", "applyFocusVisiblePolyfill", "scope", "hadKeyboardEvent", "hadFocusVisibleRecently", "hadFocusVisibleRecentlyTimeout", "inputTypesAllowlist", "isValidFocusTarget", "el", "focusTriggersKeyboardModality", "type", "tagName", "addFocusVisibleClass", "removeFocusVisibleClass", "onKeyDown", "e", "onPointerDown", "onFocus", "onBlur", "onVisibilityChange", "addInitialPointerMoveListeners", "onInitialPointerMove", "removeInitialPointerMoveListeners", "event", "error", "require_url_polyfill", "__commonJSMin", "exports", "global", "checkIfIteratorIsSupported", "error", "iteratorSupported", "createIterator", "items", "iterator", "value", "serializeParam", "deserializeParam", "polyfillURLSearchParams", "URLSearchParams", "searchString", "typeofSearchString", "_this", "name", "i", "entry", "key", "proto", "callback", "thisArg", "entries", "searchArray", "checkIfURLSearchParamsSupported", "e", "a", "b", "keys", "attributes", "attribute", "checkIfURLIsSupported", "u", "polyfillURL", "_URL", "URL", "url", "base", "doc", "baseElement", "err", "anchorElement", "inputElement", "searchParams", "enableSearchUpdate", "enableSearchParamsUpdate", "methodName", "method", "search", "linkURLWithAnchorAttribute", "attributeName", "expectedPort", "addPortToOrigin", "blob", "getOrigin", "require_tslib", "__commonJSMin", "exports", "module", "__extends", "__assign", "__rest", "__decorate", "__param", "__metadata", "__awaiter", "__generator", "__exportStar", "__values", "__read", "__spread", "__spreadArrays", "__spreadArray", "__await", "__asyncGenerator", "__asyncDelegator", "__asyncValues", "__makeTemplateObject", "__importStar", "__importDefault", "__classPrivateFieldGet", "__classPrivateFieldSet", "__createBinding", "factory", "root", "createExporter", "previous", "id", "v", "exporter", "extendStatics", "d", "b", "p", "__", "t", "s", "n", "e", "i", "decorators", "target", "key", "desc", "c", "r", "paramIndex", "decorator", "metadataKey", "metadataValue", "thisArg", "_arguments", "P", "generator", "adopt", "value", "resolve", "reject", "fulfilled", "step", "rejected", "result", "body", "_", "f", "y", "g", "verb", "op", "m", "o", "k", "k2", "ar", "error", "il", "a", "j", "jl", "to", "from", "pack", "l", "q", "resume", "settle", "fulfill", "cooked", "raw", "__setModuleDefault", "mod", "receiver", "state", "kind", "require_clipboard", "__commonJSMin", "exports", "module", "root", "factory", "__webpack_modules__", "__unused_webpack_module", "__webpack_exports__", "__webpack_require__", "clipboard", "tiny_emitter", "tiny_emitter_default", "listen", "listen_default", "src_select", "select_default", "command", "type", "err", "ClipboardActionCut", "target", "selectedText", "actions_cut", "createFakeElement", "value", "isRTL", "fakeElement", "yPosition", "fakeCopyAction", "options", "ClipboardActionCopy", "actions_copy", "_typeof", "obj", "ClipboardActionDefault", "_options$action", "action", "container", "text", "actions_default", "clipboard_typeof", "_classCallCheck", "instance", "Constructor", "_defineProperties", "props", "i", "descriptor", "_createClass", "protoProps", "staticProps", "_inherits", "subClass", "superClass", "_setPrototypeOf", "o", "p", "_createSuper", "Derived", "hasNativeReflectConstruct", "_isNativeReflectConstruct", "Super", "_getPrototypeOf", "result", "NewTarget", "_possibleConstructorReturn", "self", "call", "_assertThisInitialized", "e", "getAttributeValue", "suffix", "element", "attribute", "Clipboard", "_Emitter", "_super", "trigger", "_this", "_this2", "selector", "actions", "support", "DOCUMENT_NODE_TYPE", "proto", "closest", "__unused_webpack_exports", "_delegate", "callback", "useCapture", "listenerFn", "listener", "delegate", "elements", "is", "listenNode", "listenNodeList", "listenSelector", "node", "nodeList", "select", "isReadOnly", "selection", "range", "E", "name", "ctx", "data", "evtArr", "len", "evts", "liveEvents", "__webpack_module_cache__", "moduleId", "getter", "definition", "key", "prop", "require_escape_html", "__commonJSMin", "exports", "module", "matchHtmlRegExp", "escapeHtml", "string", "str", "match", "escape", "html", "index", "lastIndex", "r", "a", "e", "import_focus_visible", "n", "t", "s", "r", "o", "u", "i", "a", "e", "c", "import_url_polyfill", "import_tslib", "__extends", "__assign", "__rest", "__decorate", "__param", "__metadata", "__awaiter", "__generator", "__exportStar", "__createBinding", "__values", "__read", "__spread", "__spreadArrays", "__spreadArray", "__await", "__asyncGenerator", "__asyncDelegator", "__asyncValues", "__makeTemplateObject", "__importStar", "__importDefault", "__classPrivateFieldGet", "__classPrivateFieldSet", "tslib", "isFunction", "value", "createErrorClass", "createImpl", "_super", "instance", "ctorFunc", "UnsubscriptionError", "createErrorClass", "_super", "errors", "err", "i", "arrRemove", "arr", "item", "index", "Subscription", "initialTeardown", "errors", "_parentage", "_parentage_1", "__values", "_parentage_1_1", "parent_1", "initialFinalizer", "isFunction", "e", "UnsubscriptionError", "_finalizers", "_finalizers_1", "_finalizers_1_1", "finalizer", "execFinalizer", "err", "__spreadArray", "__read", "teardown", "_a", "parent", "arrRemove", "empty", "EMPTY_SUBSCRIPTION", "Subscription", "isSubscription", "value", "isFunction", "execFinalizer", "finalizer", "config", "timeoutProvider", "handler", "timeout", "args", "_i", "delegate", "__spreadArray", "__read", "handle", "reportUnhandledError", "err", "timeoutProvider", "onUnhandledError", "config", "noop", "COMPLETE_NOTIFICATION", "createNotification", "errorNotification", "error", "nextNotification", "value", "kind", "context", "errorContext", "cb", "config", "isRoot", "_a", "errorThrown", "error", "captureError", "err", "Subscriber", "_super", "__extends", "destination", "_this", "isSubscription", "EMPTY_OBSERVER", "next", "error", "complete", "SafeSubscriber", "value", "handleStoppedNotification", "nextNotification", "err", "errorNotification", "COMPLETE_NOTIFICATION", "Subscription", "_bind", "bind", "fn", "thisArg", "ConsumerObserver", "partialObserver", "value", "error", "handleUnhandledError", "err", "SafeSubscriber", "_super", "__extends", "observerOrNext", "complete", "_this", "isFunction", "context_1", "config", "Subscriber", "handleUnhandledError", "error", "config", "captureError", "reportUnhandledError", "defaultErrorHandler", "err", "handleStoppedNotification", "notification", "subscriber", "onStoppedNotification", "timeoutProvider", "EMPTY_OBSERVER", "noop", "observable", "identity", "x", "pipe", "fns", "_i", "pipeFromArray", "identity", "input", "prev", "fn", "Observable", "subscribe", "operator", "observable", "observerOrNext", "error", "complete", "_this", "subscriber", "isSubscriber", "SafeSubscriber", "errorContext", "_a", "source", "sink", "err", "next", "promiseCtor", "getPromiseCtor", "resolve", "reject", "value", "operations", "_i", "pipeFromArray", "x", "getPromiseCtor", "promiseCtor", "_a", "config", "isObserver", "value", "isFunction", "isSubscriber", "Subscriber", "isSubscription", "hasLift", "source", "isFunction", "operate", "init", "liftedSource", "err", "createOperatorSubscriber", "destination", "onNext", "onComplete", "onError", "onFinalize", "OperatorSubscriber", "_super", "__extends", "shouldUnsubscribe", "_this", "value", "err", "closed_1", "_a", "Subscriber", "animationFrameProvider", "callback", "request", "cancel", "delegate", "handle", "timestamp", "Subscription", "args", "_i", "__spreadArray", "__read", "ObjectUnsubscribedError", "createErrorClass", "_super", "Subject", "_super", "__extends", "_this", "operator", "subject", "AnonymousSubject", "ObjectUnsubscribedError", "value", "errorContext", "_b", "__values", "_c", "observer", "err", "observers", "_a", "subscriber", "hasError", "isStopped", "EMPTY_SUBSCRIPTION", "Subscription", "arrRemove", "thrownError", "observable", "Observable", "destination", "source", "AnonymousSubject", "_super", "__extends", "destination", "source", "_this", "value", "_b", "_a", "err", "subscriber", "EMPTY_SUBSCRIPTION", "Subject", "dateTimestampProvider", "ReplaySubject", "_super", "__extends", "_bufferSize", "_windowTime", "_timestampProvider", "dateTimestampProvider", "_this", "value", "_a", "isStopped", "_buffer", "_infiniteTimeWindow", "subscriber", "subscription", "copy", "i", "adjustedBufferSize", "now", "last", "Subject", "Action", "_super", "__extends", "scheduler", "work", "state", "delay", "Subscription", "intervalProvider", "handler", "timeout", "args", "_i", "delegate", "__spreadArray", "__read", "handle", "AsyncAction", "_super", "__extends", "scheduler", "work", "_this", "state", "delay", "id", "_id", "intervalProvider", "_scheduler", "error", "_delay", "errored", "errorValue", "e", "_a", "actions", "arrRemove", "Action", "Scheduler", "schedulerActionCtor", "now", "work", "delay", "state", "dateTimestampProvider", "AsyncScheduler", "_super", "__extends", "SchedulerAction", "now", "Scheduler", "_this", "action", "actions", "error", "asyncScheduler", "AsyncScheduler", "AsyncAction", "async", "AnimationFrameAction", "_super", "__extends", "scheduler", "work", "_this", "id", "delay", "animationFrameProvider", "action", "AsyncAction", "AnimationFrameScheduler", "_super", "__extends", "action", "flushId", "actions", "error", "AsyncScheduler", "animationFrameScheduler", "AnimationFrameScheduler", "AnimationFrameAction", "EMPTY", "Observable", "subscriber", "isScheduler", "value", "isFunction", "last", "arr", "popResultSelector", "args", "isFunction", "popScheduler", "isScheduler", "popNumber", "defaultValue", "isArrayLike", "x", "isPromise", "value", "isFunction", "isInteropObservable", "input", "isFunction", "observable", "isAsyncIterable", "obj", "isFunction", "createInvalidObservableTypeError", "input", "getSymbolIterator", "iterator", "isIterable", "input", "isFunction", "iterator", "readableStreamLikeToAsyncGenerator", "readableStream", "reader", "__await", "_a", "_b", "value", "done", "isReadableStreamLike", "obj", "isFunction", "innerFrom", "input", "Observable", "isInteropObservable", "fromInteropObservable", "isArrayLike", "fromArrayLike", "isPromise", "fromPromise", "isAsyncIterable", "fromAsyncIterable", "isIterable", "fromIterable", "isReadableStreamLike", "fromReadableStreamLike", "createInvalidObservableTypeError", "obj", "subscriber", "obs", "observable", "isFunction", "array", "i", "promise", "value", "err", "reportUnhandledError", "iterable", "iterable_1", "__values", "iterable_1_1", "asyncIterable", "process", "readableStream", "readableStreamLikeToAsyncGenerator", "asyncIterable_1", "__asyncValues", "asyncIterable_1_1", "executeSchedule", "parentSubscription", "scheduler", "work", "delay", "repeat", "scheduleSubscription", "observeOn", "scheduler", "delay", "operate", "source", "subscriber", "createOperatorSubscriber", "value", "executeSchedule", "err", "subscribeOn", "scheduler", "delay", "operate", "source", "subscriber", "scheduleObservable", "input", "scheduler", "innerFrom", "subscribeOn", "observeOn", "schedulePromise", "input", "scheduler", "innerFrom", "subscribeOn", "observeOn", "scheduleArray", "input", "scheduler", "Observable", "subscriber", "i", "scheduleIterable", "input", "scheduler", "Observable", "subscriber", "iterator", "executeSchedule", "value", "done", "_a", "err", "isFunction", "scheduleAsyncIterable", "input", "scheduler", "Observable", "subscriber", "executeSchedule", "iterator", "result", "scheduleReadableStreamLike", "input", "scheduler", "scheduleAsyncIterable", "readableStreamLikeToAsyncGenerator", "scheduled", "input", "scheduler", "isInteropObservable", "scheduleObservable", "isArrayLike", "scheduleArray", "isPromise", "schedulePromise", "isAsyncIterable", "scheduleAsyncIterable", "isIterable", "scheduleIterable", "isReadableStreamLike", "scheduleReadableStreamLike", "createInvalidObservableTypeError", "from", "input", "scheduler", "scheduled", "innerFrom", "of", "args", "_i", "scheduler", "popScheduler", "from", "throwError", "errorOrErrorFactory", "scheduler", "errorFactory", "isFunction", "init", "subscriber", "Observable", "isValidDate", "value", "map", "project", "thisArg", "operate", "source", "subscriber", "index", "createOperatorSubscriber", "value", "isArray", "callOrApply", "fn", "args", "__spreadArray", "__read", "mapOneOrManyArgs", "map", "isArray", "getPrototypeOf", "objectProto", "getKeys", "argsArgArrayOrObject", "args", "first_1", "isPOJO", "keys", "key", "obj", "createObject", "keys", "values", "result", "key", "i", "combineLatest", "args", "_i", "scheduler", "popScheduler", "resultSelector", "popResultSelector", "_a", "argsArgArrayOrObject", "observables", "keys", "from", "result", "Observable", "combineLatestInit", "values", "createObject", "identity", "mapOneOrManyArgs", "valueTransform", "subscriber", "maybeSchedule", "length", "active", "remainingFirstValues", "i", "source", "hasFirstValue", "createOperatorSubscriber", "value", "execute", "subscription", "executeSchedule", "mergeInternals", "source", "subscriber", "project", "concurrent", "onBeforeNext", "expand", "innerSubScheduler", "additionalFinalizer", "buffer", "active", "index", "isComplete", "checkComplete", "outerNext", "value", "doInnerSub", "innerComplete", "innerFrom", "createOperatorSubscriber", "innerValue", "bufferedValue", "executeSchedule", "err", "mergeMap", "project", "resultSelector", "concurrent", "isFunction", "a", "i", "map", "b", "ii", "innerFrom", "operate", "source", "subscriber", "mergeInternals", "mergeAll", "concurrent", "mergeMap", "identity", "concatAll", "mergeAll", "concat", "args", "_i", "concatAll", "from", "popScheduler", "defer", "observableFactory", "Observable", "subscriber", "innerFrom", "nodeEventEmitterMethods", "eventTargetMethods", "jqueryMethods", "fromEvent", "target", "eventName", "options", "resultSelector", "isFunction", "mapOneOrManyArgs", "_a", "__read", "isEventTarget", "methodName", "handler", "isNodeStyleEventEmitter", "toCommonHandlerRegistry", "isJQueryStyleEventEmitter", "add", "remove", "isArrayLike", "mergeMap", "subTarget", "innerFrom", "Observable", "subscriber", "args", "_i", "fromEventPattern", "addHandler", "removeHandler", "resultSelector", "mapOneOrManyArgs", "Observable", "subscriber", "handler", "e", "_i", "retValue", "isFunction", "timer", "dueTime", "intervalOrScheduler", "scheduler", "async", "intervalDuration", "isScheduler", "Observable", "subscriber", "due", "isValidDate", "n", "merge", "args", "_i", "scheduler", "popScheduler", "concurrent", "popNumber", "sources", "innerFrom", "mergeAll", "from", "EMPTY", "NEVER", "Observable", "noop", "isArray", "argsOrArgArray", "args", "filter", "predicate", "thisArg", "operate", "source", "subscriber", "index", "createOperatorSubscriber", "value", "zip", "args", "_i", "resultSelector", "popResultSelector", "sources", "argsOrArgArray", "Observable", "subscriber", "buffers", "completed", "sourceIndex", "innerFrom", "createOperatorSubscriber", "value", "buffer", "result", "__spreadArray", "__read", "i", "EMPTY", "audit", "durationSelector", "operate", "source", "subscriber", "hasValue", "lastValue", "durationSubscriber", "isComplete", "endDuration", "value", "cleanupDuration", "createOperatorSubscriber", "innerFrom", "auditTime", "duration", "scheduler", "asyncScheduler", "audit", "timer", "bufferCount", "bufferSize", "startBufferEvery", "operate", "source", "subscriber", "buffers", "count", "createOperatorSubscriber", "value", "toEmit", "buffers_1", "__values", "buffers_1_1", "buffer", "toEmit_1", "toEmit_1_1", "arrRemove", "buffers_2", "buffers_2_1", "catchError", "selector", "operate", "source", "subscriber", "innerSub", "syncUnsub", "handledResult", "createOperatorSubscriber", "err", "innerFrom", "scanInternals", "accumulator", "seed", "hasSeed", "emitOnNext", "emitBeforeComplete", "source", "subscriber", "hasState", "state", "index", "createOperatorSubscriber", "value", "i", "combineLatest", "args", "_i", "resultSelector", "popResultSelector", "pipe", "__spreadArray", "__read", "mapOneOrManyArgs", "operate", "source", "subscriber", "combineLatestInit", "argsOrArgArray", "combineLatestWith", "otherSources", "_i", "combineLatest", "__spreadArray", "__read", "concatMap", "project", "resultSelector", "isFunction", "mergeMap", "debounceTime", "dueTime", "scheduler", "asyncScheduler", "operate", "source", "subscriber", "activeTask", "lastValue", "lastTime", "emit", "value", "emitWhenIdle", "targetTime", "now", "createOperatorSubscriber", "defaultIfEmpty", "defaultValue", "operate", "source", "subscriber", "hasValue", "createOperatorSubscriber", "value", "take", "count", "EMPTY", "operate", "source", "subscriber", "seen", "createOperatorSubscriber", "value", "ignoreElements", "operate", "source", "subscriber", "createOperatorSubscriber", "noop", "mapTo", "value", "map", "delayWhen", "delayDurationSelector", "subscriptionDelay", "source", "concat", "take", "ignoreElements", "mergeMap", "value", "index", "mapTo", "delay", "due", "scheduler", "asyncScheduler", "duration", "timer", "delayWhen", "distinctUntilChanged", "comparator", "keySelector", "identity", "defaultCompare", "operate", "source", "subscriber", "previousKey", "first", "createOperatorSubscriber", "value", "currentKey", "a", "b", "distinctUntilKeyChanged", "key", "compare", "distinctUntilChanged", "x", "y", "endWith", "values", "_i", "source", "concat", "of", "__spreadArray", "__read", "finalize", "callback", "operate", "source", "subscriber", "takeLast", "count", "EMPTY", "operate", "source", "subscriber", "buffer", "createOperatorSubscriber", "value", "buffer_1", "__values", "buffer_1_1", "merge", "args", "_i", "scheduler", "popScheduler", "concurrent", "popNumber", "argsOrArgArray", "operate", "source", "subscriber", "mergeAll", "from", "__spreadArray", "__read", "mergeWith", "otherSources", "_i", "merge", "__spreadArray", "__read", "repeat", "countOrConfig", "count", "delay", "_a", "EMPTY", "operate", "source", "subscriber", "soFar", "sourceSub", "resubscribe", "notifier", "timer", "innerFrom", "notifierSubscriber_1", "createOperatorSubscriber", "subscribeToSource", "syncUnsub", "sample", "notifier", "operate", "source", "subscriber", "hasValue", "lastValue", "createOperatorSubscriber", "value", "noop", "scan", "accumulator", "seed", "operate", "scanInternals", "share", "options", "_a", "connector", "Subject", "_b", "resetOnError", "_c", "resetOnComplete", "_d", "resetOnRefCountZero", "wrapperSource", "connection", "resetConnection", "subject", "refCount", "hasCompleted", "hasErrored", "cancelReset", "reset", "resetAndUnsubscribe", "conn", "operate", "source", "subscriber", "dest", "handleReset", "SafeSubscriber", "value", "err", "innerFrom", "on", "args", "_i", "onSubscriber", "__spreadArray", "__read", "shareReplay", "configOrBufferSize", "windowTime", "scheduler", "bufferSize", "refCount", "_a", "_b", "_c", "share", "ReplaySubject", "skip", "count", "filter", "_", "index", "skipUntil", "notifier", "operate", "source", "subscriber", "taking", "skipSubscriber", "createOperatorSubscriber", "noop", "innerFrom", "value", "startWith", "values", "_i", "scheduler", "popScheduler", "operate", "source", "subscriber", "concat", "switchMap", "project", "resultSelector", "operate", "source", "subscriber", "innerSubscriber", "index", "isComplete", "checkComplete", "createOperatorSubscriber", "value", "innerIndex", "outerIndex", "innerFrom", "innerValue", "takeUntil", "notifier", "operate", "source", "subscriber", "innerFrom", "createOperatorSubscriber", "noop", "takeWhile", "predicate", "inclusive", "operate", "source", "subscriber", "index", "createOperatorSubscriber", "value", "result", "tap", "observerOrNext", "error", "complete", "tapObserver", "isFunction", "operate", "source", "subscriber", "_a", "isUnsub", "createOperatorSubscriber", "value", "err", "_b", "identity", "defaultThrottleConfig", "throttle", "durationSelector", "config", "operate", "source", "subscriber", "leading", "trailing", "hasValue", "sendValue", "throttled", "isComplete", "endThrottling", "send", "cleanupThrottling", "startThrottle", "value", "innerFrom", "createOperatorSubscriber", "throttleTime", "duration", "scheduler", "config", "asyncScheduler", "defaultThrottleConfig", "duration$", "timer", "throttle", "withLatestFrom", "inputs", "_i", "project", "popResultSelector", "operate", "source", "subscriber", "len", "otherValues", "hasValue", "ready", "i", "innerFrom", "createOperatorSubscriber", "value", "identity", "noop", "values", "__spreadArray", "__read", "zip", "sources", "_i", "operate", "source", "subscriber", "__spreadArray", "__read", "zipWith", "otherInputs", "_i", "zip", "__spreadArray", "__read", "watchDocument", "document$", "ReplaySubject", "fromEvent", "getElements", "selector", "node", "getElement", "el", "getOptionalElement", "getActiveElement", "watchElementFocus", "el", "merge", "fromEvent", "debounceTime", "map", "active", "getActiveElement", "startWith", "distinctUntilChanged", "getElementOffset", "el", "watchElementOffset", "merge", "fromEvent", "auditTime", "animationFrameScheduler", "map", "startWith", "getElementContentOffset", "el", "watchElementContentOffset", "merge", "fromEvent", "auditTime", "animationFrameScheduler", "map", "startWith", "MapShim", "getIndex", "arr", "key", "result", "entry", "index", "class_1", "value", "entries", "callback", "ctx", "_i", "_a", "isBrowser", "global$1", "requestAnimationFrame$1", "trailingTimeout", "throttle", "delay", "leadingCall", "trailingCall", "lastCallTime", "resolvePending", "proxy", "timeoutCallback", "timeStamp", "REFRESH_DELAY", "transitionKeys", "mutationObserverSupported", "ResizeObserverController", "observer", "observers", "changesDetected", "activeObservers", "_b", "propertyName", "isReflowProperty", "defineConfigurable", "target", "props", "getWindowOf", "ownerGlobal", "emptyRect", "createRectInit", "toFloat", "getBordersSize", "styles", "positions", "size", "position", "getPaddings", "paddings", "positions_1", "getSVGContentRect", "bbox", "getHTMLElementContentRect", "clientWidth", "clientHeight", "horizPad", "vertPad", "width", "height", "isDocumentElement", "vertScrollbar", "horizScrollbar", "isSVGGraphicsElement", "getContentRect", "createReadOnlyRect", "x", "y", "Constr", "rect", "ResizeObservation", "ResizeObserverEntry", "rectInit", "contentRect", "ResizeObserverSPI", "controller", "callbackCtx", "observations", "_this", "observation", "ResizeObserver", "method", "ResizeObserver_es_default", "entry$", "Subject", "observer$", "defer", "of", "ResizeObserver_es_default", "entries", "entry", "switchMap", "observer", "merge", "NEVER", "finalize", "shareReplay", "getElementSize", "el", "watchElementSize", "tap", "filter", "target", "map", "startWith", "getElementContentSize", "el", "entry$", "Subject", "observer$", "defer", "of", "entries", "entry", "switchMap", "observer", "merge", "NEVER", "finalize", "shareReplay", "watchElementVisibility", "el", "tap", "filter", "target", "map", "isIntersecting", "watchElementBoundary", "threshold", "watchElementContentOffset", "y", "visible", "getElementSize", "content", "getElementContentSize", "distinctUntilChanged", "toggles", "getElement", "getToggle", "name", "setToggle", "value", "watchToggle", "el", "fromEvent", "map", "startWith", "isSusceptibleToKeyboard", "el", "type", "watchKeyboard", "fromEvent", "filter", "ev", "map", "getToggle", "mode", "active", "getActiveElement", "share", "getLocation", "setLocation", "url", "watchLocation", "Subject", "appendChild", "el", "child", "node", "h", "tag", "attributes", "children", "attr", "truncate", "value", "n", "i", "round", "digits", "getLocationHash", "setLocationHash", "hash", "el", "h", "ev", "watchLocationHash", "fromEvent", "map", "startWith", "filter", "shareReplay", "watchLocationTarget", "id", "getOptionalElement", "watchMedia", "query", "media", "fromEventPattern", "next", "startWith", "watchPrint", "merge", "fromEvent", "map", "at", "query$", "factory", "switchMap", "active", "EMPTY", "request", "url", "options", "from", "catchError", "EMPTY", "switchMap", "res", "throwError", "of", "requestJSON", "shareReplay", "requestXML", "dom", "map", "watchScript", "src", "script", "h", "defer", "merge", "fromEvent", "switchMap", "throwError", "map", "finalize", "take", "getViewportOffset", "watchViewportOffset", "merge", "fromEvent", "map", "startWith", "getViewportSize", "watchViewportSize", "fromEvent", "map", "startWith", "watchViewport", "combineLatest", "watchViewportOffset", "watchViewportSize", "map", "offset", "size", "shareReplay", "watchViewportAt", "el", "viewport$", "header$", "size$", "distinctUntilKeyChanged", "offset$", "combineLatest", "map", "getElementOffset", "height", "offset", "size", "x", "y", "watchWorker", "worker", "tx$", "rx$", "fromEvent", "map", "data", "throttle", "tap", "message", "switchMap", "share", "script", "getElement", "config", "getLocation", "configuration", "feature", "flag", "translation", "key", "value", "getComponentElement", "type", "node", "getElement", "getComponentElements", "getElements", "watchAnnounce", "el", "button", "getElement", "fromEvent", "map", "content", "mountAnnounce", "feature", "EMPTY", "defer", "push$", "Subject", "startWith", "hash", "_a", "tap", "state", "finalize", "__spreadValues", "watchConsent", "el", "target$", "map", "target", "mountConsent", "options", "internal$", "Subject", "hidden", "tap", "state", "finalize", "__spreadValues", "import_clipboard", "renderAnnotation", "id", "h", "renderClipboardButton", "id", "h", "translation", "renderSearchDocument", "document", "flag", "parent", "teaser", "missing", "key", "list", "h", "url", "feature", "match", "highlight", "value", "truncate", "tag", "translation", "renderSearchResultItem", "result", "threshold", "docs", "doc", "article", "index", "best", "more", "children", "section", "renderSourceFacts", "facts", "h", "key", "value", "round", "renderTabbedControl", "type", "classes", "h", "renderTable", "table", "h", "renderVersion", "version", "config", "configuration", "url", "h", "renderVersionSelector", "versions", "active", "translation", "watchAnnotation", "el", "container", "offset$", "defer", "combineLatest", "watchElementOffset", "watchElementContentOffset", "map", "x", "y", "scroll", "width", "getElementSize", "watchElementFocus", "switchMap", "active", "offset", "take", "mountAnnotation", "push$", "Subject", "done$", "takeLast", "watchElementVisibility", "takeUntil", "visible", "throttleTime", "animationFrameScheduler", "origin", "index", "getElement", "blur$", "fromEvent", "EMPTY", "tap", "ev", "state", "finalize", "__spreadValues", "findAnnotationMarkers", "container", "markers", "comment", "getElements", "match", "text", "marker", "swap", "source", "target", "mountAnnotationList", "el", "print$", "annotations", "id", "getOptionalElement", "renderAnnotation", "EMPTY", "defer", "done$", "Subject", "takeUntil", "takeLast", "active", "annotation", "inner", "getElement", "child", "merge", "mountAnnotation", "finalize", "share", "sequence", "findCandidateList", "el", "sibling", "watchCodeBlock", "watchElementSize", "map", "width", "getElementContentSize", "distinctUntilKeyChanged", "mountCodeBlock", "options", "hover", "factory$", "defer", "push$", "Subject", "scrollable", "ClipboardJS", "parent", "renderClipboardButton", "container", "list", "feature", "annotations$", "mountAnnotationList", "tap", "state", "finalize", "__spreadValues", "mergeWith", "takeUntil", "takeLast", "height", "distinctUntilChanged", "switchMap", "active", "EMPTY", "watchElementVisibility", "filter", "visible", "take", "mermaid$", "sequence", "fetchScripts", "watchScript", "of", "mountMermaid", "el", "tap", "mermaid_default", "map", "shareReplay", "id", "host", "h", "svg", "shadow", "watchDetails", "el", "target$", "print$", "open", "merge", "map", "target", "filter", "details", "active", "tap", "mountDetails", "options", "defer", "push$", "Subject", "action", "reveal", "state", "finalize", "__spreadValues", "sentinel", "h", "mountDataTable", "el", "renderTable", "of", "watchContentTabs", "el", "inputs", "getElements", "initial", "input", "merge", "fromEvent", "map", "getElement", "startWith", "active", "mountContentTabs", "prev", "renderTabbedControl", "next", "container", "defer", "push$", "Subject", "done$", "takeLast", "combineLatest", "watchElementSize", "auditTime", "animationFrameScheduler", "takeUntil", "size", "offset", "getElementOffset", "width", "getElementSize", "content", "getElementContentOffset", "watchElementContentOffset", "getElementContentSize", "direction", "feature", "skip", "tab", "set", "tabs", "tap", "state", "finalize", "__spreadValues", "subscribeOn", "asyncScheduler", "mountContent", "el", "target$", "print$", "merge", "getElements", "child", "mountCodeBlock", "mountMermaid", "mountDataTable", "mountDetails", "mountContentTabs", "watchDialog", "_el", "alert$", "switchMap", "message", "merge", "of", "delay", "map", "active", "mountDialog", "el", "options", "inner", "getElement", "defer", "push$", "Subject", "tap", "state", "finalize", "__spreadValues", "isHidden", "viewport$", "feature", "of", "direction$", "map", "y", "bufferCount", "a", "b", "distinctUntilKeyChanged", "hidden$", "combineLatest", "filter", "offset", "direction", "distinctUntilChanged", "search$", "watchToggle", "search", "switchMap", "active", "startWith", "watchHeader", "el", "options", "defer", "watchElementSize", "height", "hidden", "shareReplay", "mountHeader", "header$", "main$", "push$", "Subject", "done$", "takeLast", "combineLatestWith", "takeUntil", "state", "__spreadValues", "watchHeaderTitle", "el", "viewport$", "header$", "watchViewportAt", "map", "y", "height", "getElementSize", "distinctUntilKeyChanged", "mountHeaderTitle", "options", "defer", "push$", "Subject", "active", "heading", "getOptionalElement", "EMPTY", "tap", "state", "finalize", "__spreadValues", "watchMain", "el", "viewport$", "header$", "adjust$", "map", "height", "distinctUntilChanged", "border$", "switchMap", "watchElementSize", "distinctUntilKeyChanged", "combineLatest", "header", "top", "bottom", "y", "a", "b", "watchPalette", "inputs", "current", "input", "of", "mergeMap", "fromEvent", "map", "startWith", "shareReplay", "mountPalette", "el", "defer", "push$", "Subject", "palette", "key", "value", "index", "label", "observeOn", "asyncScheduler", "getElements", "tap", "state", "finalize", "__spreadValues", "import_clipboard", "extract", "el", "text", "setupClipboardJS", "alert$", "ClipboardJS", "Observable", "subscriber", "getElement", "ev", "tap", "map", "translation", "preprocess", "urls", "root", "next", "a", "b", "url", "index", "fetchSitemap", "base", "cached", "of", "config", "configuration", "requestXML", "map", "sitemap", "getElements", "node", "catchError", "EMPTY", "defaultIfEmpty", "tap", "setupInstantLoading", "document$", "location$", "viewport$", "config", "configuration", "fromEvent", "favicon", "getOptionalElement", "push$", "fetchSitemap", "map", "paths", "path", "switchMap", "urls", "filter", "ev", "el", "url", "of", "NEVER", "share", "pop$", "merge", "distinctUntilChanged", "a", "b", "response$", "distinctUntilKeyChanged", "request", "catchError", "setLocation", "sample", "dom", "res", "skip", "replacement", "selector", "feature", "source", "target", "getComponentElement", "getElements", "concatMap", "script", "h", "name", "Observable", "observer", "EMPTY", "offset", "setLocationHash", "skipUntil", "debounceTime", "bufferCount", "state", "import_escape_html", "import_escape_html", "setupSearchHighlighter", "config", "escape", "separator", "highlight", "_", "data", "term", "query", "match", "value", "escapeHTML", "defaultTransform", "query", "terms", "index", "isSearchReadyMessage", "message", "isSearchQueryMessage", "isSearchResultMessage", "setupSearchIndex", "config", "docs", "translation", "options", "feature", "setupSearchWorker", "url", "index", "configuration", "worker", "tx$", "Subject", "rx$", "watchWorker", "map", "message", "isSearchResultMessage", "result", "document", "share", "from", "data", "setupVersionSelector", "document$", "config", "configuration", "versions$", "requestJSON", "catchError", "EMPTY", "current$", "map", "versions", "current", "version", "aliases", "switchMap", "urls", "fromEvent", "filter", "ev", "withLatestFrom", "el", "url", "of", "fetchSitemap", "sitemap", "path", "getLocation", "setLocation", "combineLatest", "getElement", "renderVersionSelector", "_a", "outdated", "latest", "warning", "getComponentElements", "watchSearchQuery", "el", "rx$", "fn", "defaultTransform", "searchParams", "getLocation", "setToggle", "param$", "filter", "isSearchReadyMessage", "take", "map", "watchToggle", "active", "url", "value", "focus$", "watchElementFocus", "value$", "merge", "fromEvent", "delay", "startWith", "distinctUntilChanged", "combineLatest", "focus", "shareReplay", "mountSearchQuery", "tx$", "push$", "Subject", "done$", "takeLast", "distinctUntilKeyChanged", "translation", "takeUntil", "tap", "state", "finalize", "__spreadValues", "share", "mountSearchResult", "el", "rx$", "query$", "push$", "Subject", "boundary$", "watchElementBoundary", "filter", "meta", "getElement", "list", "ready$", "isSearchReadyMessage", "take", "withLatestFrom", "skipUntil", "items", "value", "translation", "round", "tap", "switchMap", "merge", "of", "bufferCount", "zipWith", "chunk", "result", "renderSearchResultItem", "isSearchResultMessage", "map", "data", "state", "finalize", "__spreadValues", "watchSearchShare", "_el", "query$", "map", "value", "url", "getLocation", "mountSearchShare", "el", "options", "push$", "Subject", "fromEvent", "ev", "tap", "state", "finalize", "__spreadValues", "mountSearchSuggest", "el", "rx$", "keyboard$", "push$", "Subject", "query", "getComponentElement", "query$", "merge", "fromEvent", "observeOn", "asyncScheduler", "map", "distinctUntilChanged", "combineLatestWith", "suggestions", "value", "words", "last", "filter", "mode", "key", "isSearchResultMessage", "data", "tap", "state", "finalize", "mountSearch", "el", "index$", "keyboard$", "config", "configuration", "url", "worker", "setupSearchWorker", "query", "getComponentElement", "result", "tx$", "rx$", "filter", "isSearchQueryMessage", "sample", "isSearchReadyMessage", "take", "mode", "key", "active", "getActiveElement", "anchors", "anchor", "getElements", "article", "best", "a", "b", "setToggle", "els", "i", "query$", "mountSearchQuery", "result$", "mountSearchResult", "merge", "mergeWith", "getComponentElements", "child", "mountSearchShare", "mountSearchSuggest", "err", "NEVER", "mountSearchHiglight", "el", "index$", "location$", "combineLatest", "startWith", "getLocation", "filter", "url", "map", "index", "setupSearchHighlighter", "fn", "_a", "nodes", "it", "node", "original", "replaced", "text", "childNodes", "h", "watchSidebar", "el", "viewport$", "main$", "parent", "adjust", "combineLatest", "map", "offset", "height", "y", "distinctUntilChanged", "a", "b", "mountSidebar", "_a", "_b", "header$", "options", "__objRest", "inner", "getElement", "getElementOffset", "defer", "push$", "Subject", "auditTime", "animationFrameScheduler", "withLatestFrom", "tap", "state", "finalize", "__spreadValues", "fetchSourceFactsFromGitHub", "user", "repo", "url", "zip", "requestJSON", "catchError", "EMPTY", "map", "release", "defaultIfEmpty", "info", "__spreadValues", "fetchSourceFactsFromGitLab", "base", "project", "url", "requestJSON", "catchError", "EMPTY", "map", "star_count", "forks_count", "defaultIfEmpty", "fetchSourceFacts", "url", "type", "user", "repo", "fetchSourceFactsFromGitHub", "base", "slug", "fetchSourceFactsFromGitLab", "EMPTY", "fetch$", "watchSource", "el", "defer", "cached", "of", "fetchSourceFacts", "tap", "facts", "catchError", "EMPTY", "filter", "map", "shareReplay", "mountSource", "inner", "getElement", "push$", "Subject", "renderSourceFacts", "state", "finalize", "__spreadValues", "watchTabs", "el", "viewport$", "header$", "watchElementSize", "switchMap", "watchViewportAt", "map", "y", "distinctUntilKeyChanged", "mountTabs", "options", "defer", "push$", "Subject", "hidden", "feature", "of", "tap", "state", "finalize", "__spreadValues", "watchTableOfContents", "el", "viewport$", "header$", "table", "anchors", "getElements", "anchor", "id", "target", "getOptionalElement", "adjust$", "distinctUntilKeyChanged", "map", "height", "main", "getComponentElement", "grid", "getElement", "share", "watchElementSize", "switchMap", "body", "defer", "path", "of", "index", "offset", "a", "b", "combineLatestWith", "adjust", "scan", "prev", "next", "y", "size", "last", "distinctUntilChanged", "startWith", "bufferCount", "mountTableOfContents", "target$", "push$", "Subject", "done$", "takeLast", "feature", "takeUntil", "debounceTime", "skip", "repeat", "withLatestFrom", "url", "getLocation", "active", "hash", "tap", "state", "finalize", "__spreadValues", "watchBackToTop", "_el", "viewport$", "main$", "target$", "direction$", "map", "y", "bufferCount", "b", "distinctUntilChanged", "active$", "active", "combineLatest", "direction", "takeUntil", "skip", "endWith", "repeat", "hidden", "mountBackToTop", "el", "header$", "push$", "Subject", "done$", "takeLast", "distinctUntilKeyChanged", "height", "tap", "state", "finalize", "__spreadValues", "patchIndeterminate", "document$", "tablet$", "switchMap", "getElements", "tap", "el", "mergeMap", "fromEvent", "takeWhile", "map", "withLatestFrom", "tablet", "isAppleDevice", "patchScrollfix", "document$", "switchMap", "getElements", "tap", "el", "filter", "mergeMap", "fromEvent", "map", "top", "patchScrolllock", "viewport$", "tablet$", "combineLatest", "watchToggle", "map", "active", "tablet", "switchMap", "of", "delay", "withLatestFrom", "y", "value", "obj", "data", "key", "x", "y", "nodes", "parent", "i", "node", "document$", "watchDocument", "location$", "watchLocation", "target$", "watchLocationTarget", "keyboard$", "watchKeyboard", "viewport$", "watchViewport", "tablet$", "watchMedia", "screen$", "print$", "watchPrint", "config", "configuration", "index$", "requestJSON", "NEVER", "alert$", "Subject", "setupClipboardJS", "feature", "setupInstantLoading", "_a", "setupVersionSelector", "merge", "delay", "setToggle", "filter", "mode", "key", "prev", "getOptionalElement", "next", "patchIndeterminate", "patchScrollfix", "patchScrolllock", "header$", "watchHeader", "getComponentElement", "main$", "map", "switchMap", "el", "watchMain", "shareReplay", "control$", "getComponentElements", "mountConsent", "mountDialog", "mountHeader", "mountPalette", "mountSearch", "mountSource", "content$", "defer", "mountAnnounce", "mountContent", "mountSearchHiglight", "EMPTY", "mountHeaderTitle", "at", "mountSidebar", "mountTabs", "mountTableOfContents", "mountBackToTop", "component$", "mergeWith"] -} diff --git a/assets/javascripts/bundle.b1047164.min.js b/assets/javascripts/bundle.b1047164.min.js new file mode 100644 index 00000000..ba974993 --- /dev/null +++ b/assets/javascripts/bundle.b1047164.min.js @@ -0,0 +1,29 @@ +(()=>{var ea=Object.create;var St=Object.defineProperty;var ta=Object.getOwnPropertyDescriptor;var ra=Object.getOwnPropertyNames,wt=Object.getOwnPropertySymbols,oa=Object.getPrototypeOf,sr=Object.prototype.hasOwnProperty,qr=Object.prototype.propertyIsEnumerable,ls=Reflect.get,ps=Reflect.set;var Qr=(e,t,r)=>t in e?St(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))sr.call(t,r)&&Qr(e,r,t[r]);if(wt)for(var r of wt(t))qr.call(t,r)&&Qr(e,r,t[r]);return e};var na=e=>St(e,"__esModule",{value:!0});var Kr=(e,t)=>{var r={};for(var o in e)sr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&wt)for(var o of wt(e))t.indexOf(o)<0&&qr.call(e,o)&&(r[o]=e[o]);return r};var Et=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var ia=(e,t,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ra(t))!sr.call(e,o)&&o!=="default"&&St(e,o,{get:()=>t[o],enumerable:!(r=ta(t,o))||r.enumerable});return e},Ke=e=>ia(na(St(e!=null?ea(oa(e)):{},"default",e&&e.__esModule&&"default"in e?{get:()=>e.default,enumerable:!0}:{value:e,enumerable:!0})),e);var Jr=Et((cr,Br)=>{(function(e,t){typeof cr=="object"&&typeof Br!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(cr,function(){"use strict";function e(r){var o=!0,n=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(E){return!!(E&&E!==document&&E.nodeName!=="HTML"&&E.nodeName!=="BODY"&&"classList"in E&&"contains"in E.classList)}function c(E){var We=E.type,Oe=E.tagName;return!!(Oe==="INPUT"&&a[We]&&!E.readOnly||Oe==="TEXTAREA"&&!E.readOnly||E.isContentEditable)}function l(E){E.classList.contains("focus-visible")||(E.classList.add("focus-visible"),E.setAttribute("data-focus-visible-added",""))}function p(E){!E.hasAttribute("data-focus-visible-added")||(E.classList.remove("focus-visible"),E.removeAttribute("data-focus-visible-added"))}function m(E){E.metaKey||E.altKey||E.ctrlKey||(s(r.activeElement)&&l(r.activeElement),o=!0)}function u(E){o=!1}function b(E){!s(E.target)||(o||c(E.target))&&l(E.target)}function v(E){!s(E.target)||(E.target.classList.contains("focus-visible")||E.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),p(E.target))}function d(E){document.visibilityState==="hidden"&&(n&&(o=!0),V())}function V(){document.addEventListener("mousemove",j),document.addEventListener("mousedown",j),document.addEventListener("mouseup",j),document.addEventListener("pointermove",j),document.addEventListener("pointerdown",j),document.addEventListener("pointerup",j),document.addEventListener("touchmove",j),document.addEventListener("touchstart",j),document.addEventListener("touchend",j)}function K(){document.removeEventListener("mousemove",j),document.removeEventListener("mousedown",j),document.removeEventListener("mouseup",j),document.removeEventListener("pointermove",j),document.removeEventListener("pointerdown",j),document.removeEventListener("pointerup",j),document.removeEventListener("touchmove",j),document.removeEventListener("touchstart",j),document.removeEventListener("touchend",j)}function j(E){E.target.nodeName&&E.target.nodeName.toLowerCase()==="html"||(o=!1,K())}document.addEventListener("keydown",m,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",d,!0),V(),r.addEventListener("focus",b,!0),r.addEventListener("blur",v,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var vo=Et((fs,_t)=>{/*! ***************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */var Yr,Gr,Xr,Zr,eo,to,ro,oo,no,Tt,lr,io,ao,so,Be,co,lo,po,uo,fo,mo,ho,bo,Ot;(function(e){var t=typeof global=="object"?global:typeof self=="object"?self:typeof this=="object"?this:{};typeof define=="function"&&define.amd?define("tslib",["exports"],function(o){e(r(t,r(o)))}):typeof _t=="object"&&typeof _t.exports=="object"?e(r(t,r(_t.exports))):e(r(t));function r(o,n){return o!==t&&(typeof Object.create=="function"?Object.defineProperty(o,"__esModule",{value:!0}):o.__esModule=!0),function(i,a){return o[i]=n?n(i,a):a}}})(function(e){var t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(o,n){o.__proto__=n}||function(o,n){for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(o[i]=n[i])};Yr=function(o,n){if(typeof n!="function"&&n!==null)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");t(o,n);function i(){this.constructor=o}o.prototype=n===null?Object.create(n):(i.prototype=n.prototype,new i)},Gr=Object.assign||function(o){for(var n,i=1,a=arguments.length;i=0;p--)(l=o[p])&&(c=(s<3?l(c):s>3?l(n,i,c):l(n,i))||c);return s>3&&c&&Object.defineProperty(n,i,c),c},eo=function(o,n){return function(i,a){n(i,a,o)}},to=function(o,n){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(o,n)},ro=function(o,n,i,a){function s(c){return c instanceof i?c:new i(function(l){l(c)})}return new(i||(i=Promise))(function(c,l){function p(b){try{u(a.next(b))}catch(v){l(v)}}function m(b){try{u(a.throw(b))}catch(v){l(v)}}function u(b){b.done?c(b.value):s(b.value).then(p,m)}u((a=a.apply(o,n||[])).next())})},oo=function(o,n){var i={label:0,sent:function(){if(c[0]&1)throw c[1];return c[1]},trys:[],ops:[]},a,s,c,l;return l={next:p(0),throw:p(1),return:p(2)},typeof Symbol=="function"&&(l[Symbol.iterator]=function(){return this}),l;function p(u){return function(b){return m([u,b])}}function m(u){if(a)throw new TypeError("Generator is already executing.");for(;i;)try{if(a=1,s&&(c=u[0]&2?s.return:u[0]?s.throw||((c=s.return)&&c.call(s),0):s.next)&&!(c=c.call(s,u[1])).done)return c;switch(s=0,c&&(u=[u[0]&2,c.value]),u[0]){case 0:case 1:c=u;break;case 4:return i.label++,{value:u[1],done:!1};case 5:i.label++,s=u[1],u=[0];continue;case 7:u=i.ops.pop(),i.trys.pop();continue;default:if(c=i.trys,!(c=c.length>0&&c[c.length-1])&&(u[0]===6||u[0]===2)){i=0;continue}if(u[0]===3&&(!c||u[1]>c[0]&&u[1]=o.length&&(o=void 0),{value:o&&o[a++],done:!o}}};throw new TypeError(n?"Object is not iterable.":"Symbol.iterator is not defined.")},lr=function(o,n){var i=typeof Symbol=="function"&&o[Symbol.iterator];if(!i)return o;var a=i.call(o),s,c=[],l;try{for(;(n===void 0||n-- >0)&&!(s=a.next()).done;)c.push(s.value)}catch(p){l={error:p}}finally{try{s&&!s.done&&(i=a.return)&&i.call(a)}finally{if(l)throw l.error}}return c},io=function(){for(var o=[],n=0;n1||p(d,V)})})}function p(d,V){try{m(a[d](V))}catch(K){v(c[0][3],K)}}function m(d){d.value instanceof Be?Promise.resolve(d.value.v).then(u,b):v(c[0][2],d)}function u(d){p("next",d)}function b(d){p("throw",d)}function v(d,V){d(V),c.shift(),c.length&&p(c[0][0],c[0][1])}},lo=function(o){var n,i;return n={},a("next"),a("throw",function(s){throw s}),a("return"),n[Symbol.iterator]=function(){return this},n;function a(s,c){n[s]=o[s]?function(l){return(i=!i)?{value:Be(o[s](l)),done:s==="return"}:c?c(l):l}:c}},po=function(o){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var n=o[Symbol.asyncIterator],i;return n?n.call(o):(o=typeof Tt=="function"?Tt(o):o[Symbol.iterator](),i={},a("next"),a("throw"),a("return"),i[Symbol.asyncIterator]=function(){return this},i);function a(c){i[c]=o[c]&&function(l){return new Promise(function(p,m){l=o[c](l),s(p,m,l.done,l.value)})}}function s(c,l,p,m){Promise.resolve(m).then(function(u){c({value:u,done:p})},l)}},uo=function(o,n){return Object.defineProperty?Object.defineProperty(o,"raw",{value:n}):o.raw=n,o};var r=Object.create?function(o,n){Object.defineProperty(o,"default",{enumerable:!0,value:n})}:function(o,n){o.default=n};fo=function(o){if(o&&o.__esModule)return o;var n={};if(o!=null)for(var i in o)i!=="default"&&Object.prototype.hasOwnProperty.call(o,i)&&Ot(n,o,i);return r(n,o),n},mo=function(o){return o&&o.__esModule?o:{default:o}},ho=function(o,n){if(!n.has(o))throw new TypeError("attempted to get private field on non-instance");return n.get(o)},bo=function(o,n,i){if(!n.has(o))throw new TypeError("attempted to set private field on non-instance");return n.set(o,i),i},e("__extends",Yr),e("__assign",Gr),e("__rest",Xr),e("__decorate",Zr),e("__param",eo),e("__metadata",to),e("__awaiter",ro),e("__generator",oo),e("__exportStar",no),e("__createBinding",Ot),e("__values",Tt),e("__read",lr),e("__spread",io),e("__spreadArrays",ao),e("__spreadArray",so),e("__await",Be),e("__asyncGenerator",co),e("__asyncDelegator",lo),e("__asyncValues",po),e("__makeTemplateObject",uo),e("__importStar",fo),e("__importDefault",mo),e("__classPrivateFieldGet",ho),e("__classPrivateFieldSet",bo)})});var jr=Et((xt,Fr)=>{/*! + * clipboard.js v2.0.8 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof xt=="object"&&typeof Fr=="object"?Fr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof xt=="object"?xt.ClipboardJS=r():t.ClipboardJS=r()})(xt,function(){return function(){var e={134:function(o,n,i){"use strict";i.d(n,{default:function(){return Xi}});var a=i(279),s=i.n(a),c=i(370),l=i.n(c),p=i(817),m=i.n(p);function u(O){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?u=function(h){return typeof h}:u=function(h){return h&&typeof Symbol=="function"&&h.constructor===Symbol&&h!==Symbol.prototype?"symbol":typeof h},u(O)}function b(O,x){if(!(O instanceof x))throw new TypeError("Cannot call a class as a function")}function v(O,x){for(var h=0;h0&&arguments[0]!==void 0?arguments[0]:{};this.action=h.action,this.container=h.container,this.emitter=h.emitter,this.target=h.target,this.text=h.text,this.trigger=h.trigger,this.selectedText=""}},{key:"initSelection",value:function(){this.text?this.selectFake():this.target&&this.selectTarget()}},{key:"createFakeElement",value:function(){var h=document.documentElement.getAttribute("dir")==="rtl";this.fakeElem=document.createElement("textarea"),this.fakeElem.style.fontSize="12pt",this.fakeElem.style.border="0",this.fakeElem.style.padding="0",this.fakeElem.style.margin="0",this.fakeElem.style.position="absolute",this.fakeElem.style[h?"right":"left"]="-9999px";var A=window.pageYOffset||document.documentElement.scrollTop;return this.fakeElem.style.top="".concat(A,"px"),this.fakeElem.setAttribute("readonly",""),this.fakeElem.value=this.text,this.fakeElem}},{key:"selectFake",value:function(){var h=this,A=this.createFakeElement();this.fakeHandlerCallback=function(){return h.removeFake()},this.fakeHandler=this.container.addEventListener("click",this.fakeHandlerCallback)||!0,this.container.appendChild(A),this.selectedText=m()(A),this.copyText(),this.removeFake()}},{key:"removeFake",value:function(){this.fakeHandler&&(this.container.removeEventListener("click",this.fakeHandlerCallback),this.fakeHandler=null,this.fakeHandlerCallback=null),this.fakeElem&&(this.container.removeChild(this.fakeElem),this.fakeElem=null)}},{key:"selectTarget",value:function(){this.selectedText=m()(this.target),this.copyText()}},{key:"copyText",value:function(){var h;try{h=document.execCommand(this.action)}catch(A){h=!1}this.handleResult(h)}},{key:"handleResult",value:function(h){this.emitter.emit(h?"success":"error",{action:this.action,text:this.selectedText,trigger:this.trigger,clearSelection:this.clearSelection.bind(this)})}},{key:"clearSelection",value:function(){this.trigger&&this.trigger.focus(),document.activeElement.blur(),window.getSelection().removeAllRanges()}},{key:"destroy",value:function(){this.removeFake()}},{key:"action",set:function(){var h=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"copy";if(this._action=h,this._action!=="copy"&&this._action!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"')},get:function(){return this._action}},{key:"target",set:function(h){if(h!==void 0)if(h&&u(h)==="object"&&h.nodeType===1){if(this.action==="copy"&&h.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(this.action==="cut"&&(h.hasAttribute("readonly")||h.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`);this._target=h}else throw new Error('Invalid "target" value, use a valid Element')},get:function(){return this._target}}]),O}(),K=V;function j(O){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?j=function(h){return typeof h}:j=function(h){return h&&typeof Symbol=="function"&&h.constructor===Symbol&&h!==Symbol.prototype?"symbol":typeof h},j(O)}function E(O,x){if(!(O instanceof x))throw new TypeError("Cannot call a class as a function")}function We(O,x){for(var h=0;h0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof W.action=="function"?W.action:this.defaultAction,this.target=typeof W.target=="function"?W.target:this.defaultTarget,this.text=typeof W.text=="function"?W.text:this.defaultText,this.container=j(W.container)==="object"?W.container:document.body}},{key:"listenClick",value:function(W){var te=this;this.listener=l()(W,"click",function(ct){return te.onClick(ct)})}},{key:"onClick",value:function(W){var te=W.delegateTarget||W.currentTarget;this.clipboardAction&&(this.clipboardAction=null),this.clipboardAction=new K({action:this.action(te),target:this.target(te),text:this.text(te),container:this.container,trigger:te,emitter:this})}},{key:"defaultAction",value:function(W){return ar("action",W)}},{key:"defaultTarget",value:function(W){var te=ar("target",W);if(te)return document.querySelector(te)}},{key:"defaultText",value:function(W){return ar("text",W)}},{key:"destroy",value:function(){this.listener.destroy(),this.clipboardAction&&(this.clipboardAction.destroy(),this.clipboardAction=null)}}],[{key:"isSupported",value:function(){var W=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],te=typeof W=="string"?[W]:W,ct=!!document.queryCommandSupported;return te.forEach(function(Zi){ct=ct&&!!document.queryCommandSupported(Zi)}),ct}}]),h}(s()),Xi=Gi},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,c){for(;s&&s.nodeType!==n;){if(typeof s.matches=="function"&&s.matches(c))return s;s=s.parentNode}}o.exports=a},438:function(o,n,i){var a=i(828);function s(p,m,u,b,v){var d=l.apply(this,arguments);return p.addEventListener(u,d,v),{destroy:function(){p.removeEventListener(u,d,v)}}}function c(p,m,u,b,v){return typeof p.addEventListener=="function"?s.apply(null,arguments):typeof u=="function"?s.bind(null,document).apply(null,arguments):(typeof p=="string"&&(p=document.querySelectorAll(p)),Array.prototype.map.call(p,function(d){return s(d,m,u,b,v)}))}function l(p,m,u,b){return function(v){v.delegateTarget=a(v.target,m),v.delegateTarget&&b.call(p,v)}}o.exports=c},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(o,n,i){var a=i(879),s=i(438);function c(u,b,v){if(!u&&!b&&!v)throw new Error("Missing required arguments");if(!a.string(b))throw new TypeError("Second argument must be a String");if(!a.fn(v))throw new TypeError("Third argument must be a Function");if(a.node(u))return l(u,b,v);if(a.nodeList(u))return p(u,b,v);if(a.string(u))return m(u,b,v);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function l(u,b,v){return u.addEventListener(b,v),{destroy:function(){u.removeEventListener(b,v)}}}function p(u,b,v){return Array.prototype.forEach.call(u,function(d){d.addEventListener(b,v)}),{destroy:function(){Array.prototype.forEach.call(u,function(d){d.removeEventListener(b,v)})}}}function m(u,b,v){return s(document.body,u,b,v)}o.exports=c},817:function(o){function n(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),l=document.createRange();l.selectNodeContents(i),c.removeAllRanges(),c.addRange(l),a=c.toString()}return a}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,a,s){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var c=this;function l(){c.off(i,l),a.apply(s,arguments)}return l._=a,this.on(i,l,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),c=0,l=s.length;for(c;c{/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */"use strict";var Ba=/["'&<>]/;gi.exports=Ja;function Ja(e){var t=""+e,r=Ba.exec(t);if(!r)return t;var o,n="",i=0,a=0;for(i=r.index;i0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=o.hasError,i=o.isStopped,a=o.observers;return n||i?pr:(a.push(r),new Se(function(){return _e(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,a=o.isStopped;n?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new k;return r.source=this,r},t.create=function(r,o){return new Co(r,o)},t}(k);var Co=function(e){X(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:pr},t}(T);var ut={now:function(){return(ut.delegate||Date).now()},delegate:void 0};var ft=function(e){X(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=ut);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,a=o._infiniteTimeWindow,s=o._timestampProvider,c=o._windowTime;n||(i.push(r),!a&&i.push(s.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,a=n._buffer,s=a.slice(),c=0;c0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=Xe.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){if(n===void 0&&(n=0),n!=null&&n>0||n==null&&this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);r.actions.length===0&&(Xe.cancelAnimationFrame(o),r._scheduled=void 0)},t}(Ft);var jo=function(e){X(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0,this._scheduled=void 0;var o=this.actions,n,i=-1;r=r||o.shift();var a=o.length;do if(n=r.execute(r.state,r.delay))break;while(++i=2,!0))}function me(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new T}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,c=s===void 0?!0:s;return function(l){var p=null,m=null,u=null,b=0,v=!1,d=!1,V=function(){m==null||m.unsubscribe(),m=null},K=function(){V(),p=u=null,v=d=!1},j=function(){var E=p;K(),E==null||E.unsubscribe()};return g(function(E,We){b++,!d&&!v&&V();var Oe=u=u!=null?u:r();We.add(function(){b--,b===0&&!d&&!v&&(m=Or(j,c))}),Oe.subscribe(We),p||(p=new pt({next:function(Qe){return Oe.next(Qe)},error:function(Qe){d=!0,V(),m=Or(K,n,Qe),Oe.error(Qe)},complete:function(){v=!0,V(),m=Or(K,a),Oe.complete()}}),re(E).subscribe(p))})(l)}}function Or(e,t){for(var r=[],o=2;ot==="focus"),N(e===De()))}var rn=new T,Fa=Me(()=>R(new ResizeObserver(e=>{for(let t of e)rn.next(t)}))).pipe(M(e=>B.pipe(N(e)).pipe(F(()=>e.disconnect()))),Y(1));function je(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Jt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function Re(e){return Fa.pipe(L(t=>t.observe(e)),M(t=>rn.pipe(_(({target:r})=>r===e),F(()=>t.unobserve(e)),f(()=>je(e)))),N(je(e)))}function on(e){return{x:e.scrollLeft,y:e.scrollTop}}function ja(e){return $(w(e,"scroll"),w(window,"resize")).pipe(f(()=>on(e)),N(on(e)))}function nn(e,t=16){return ja(e).pipe(f(({y:r})=>{let o=je(e),n=Jt(e);return r>=n.height-o.height-t}),q())}function an(e){if(e instanceof HTMLInputElement)e.select();else throw new Error("Not implemented")}var Yt={drawer:ce("[data-md-toggle=drawer]"),search:ce("[data-md-toggle=search]")};function sn(e){return Yt[e].checked}function Ie(e,t){Yt[e].checked!==t&&Yt[e].click()}function Gt(e){let t=Yt[e];return w(t,"change").pipe(f(()=>t.checked),N(t.checked))}function Ra(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function cn(){return w(window,"keydown").pipe(_(e=>!(e.metaKey||e.ctrlKey)),f(e=>({mode:sn("search")?"search":"global",type:e.key,claim(){e.preventDefault(),e.stopPropagation()}})),_(({mode:e,type:t})=>{if(e==="global"){let r=De();if(typeof r!="undefined")return!Ra(r,t)}return!0}),me())}function Pe(){return new URL(location.href)}function ln(e){location.href=e.href}function pn(){return new T}function un(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)un(e,r)}function I(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="boolean"?o.setAttribute(n,t[n]):t[n]&&o.setAttribute(n,"");for(let n of r)un(o,n);return o}function fn(e,t){let r=t;if(e.length>r){for(;e[r]!==" "&&--r>0;);return`${e.substring(0,r)}...`}return e}function Xt(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function mn(){return location.hash.substring(1)}function dn(e){let t=I("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Ia(){return w(window,"hashchange").pipe(f(mn),N(mn()),_(e=>e.length>0),Y(1))}function hn(){return Ia().pipe(f(e=>se(`[id="${e}"]`)),_(e=>typeof e!="undefined"))}function vt(e){let t=matchMedia(e);return Kt(r=>t.addListener(()=>r(t.matches))).pipe(N(t.matches))}function bn(){return w(window,"beforeprint").pipe(ee(void 0))}function Cr(e,t){return e.pipe(M(r=>r?t():B))}function Zt(e,t={credentials:"same-origin"}){return re(fetch(`${e}`,t)).pipe(_(r=>r.status===200),Fe(()=>fe))}function Ee(e,t){return Zt(e,t).pipe(M(r=>r.json()),Y(1))}function vn(e,t){let r=new DOMParser;return Zt(e,t).pipe(M(o=>o.text()),f(o=>r.parseFromString(o,"text/xml")),Y(1))}function xn(){return{x:Math.max(0,pageXOffset),y:Math.max(0,pageYOffset)}}function Hr({x:e,y:t}){window.scrollTo(e||0,t||0)}function gn(){return $(w(window,"scroll",{passive:!0}),w(window,"resize",{passive:!0})).pipe(f(xn),N(xn()))}function yn(){return{width:innerWidth,height:innerHeight}}function Sn(){return w(window,"resize",{passive:!0}).pipe(f(yn),N(yn()))}function wn(){return J([gn(),Sn()]).pipe(f(([e,t])=>({offset:e,size:t})),Y(1))}function er(e,{viewport$:t,header$:r}){let o=t.pipe(z("size")),n=J([o,r]).pipe(f(()=>({x:e.offsetLeft,y:e.offsetTop})));return J([r,t,n]).pipe(f(([{height:i},{offset:a,size:s},{x:c,y:l}])=>({offset:{x:a.x-c,y:a.y-l+i},size:s})))}function En(e,{tx$:t}){let r=w(e,"message").pipe(f(({data:o})=>o));return t.pipe(Ar(()=>r,{leading:!0,trailing:!0}),L(o=>e.postMessage(o)),_r(r),me())}var Pa=ce("#__config"),nt=JSON.parse(Pa.textContent);nt.base=`${new URL(nt.base,Pe())}`;function le(){return nt}function he(e){return nt.features.includes(e)}function G(e,t){return typeof t!="undefined"?nt.translations[e].replace("#",t.toString()):nt.translations[e]}function Te(e,t=document){return ce(`[data-md-component=${e}]`,t)}function ie(e,t=document){return Q(`[data-md-component=${e}]`,t)}var ni=Ke(jr());function tr(e,t=0){e.setAttribute("tabindex",t.toString())}function gt(e){e.removeAttribute("tabindex")}function Tn(e,t){e.setAttribute("data-md-state","lock"),e.style.top=`-${t}px`}function On(e){let t=-1*parseInt(e.style.top,10);e.removeAttribute("data-md-state"),e.style.top="",t&&window.scrollTo(0,t)}function _n(e,t){e.setAttribute("data-md-state",t)}function Mn(e){e.removeAttribute("data-md-state")}function Ln(e,t){e.classList.toggle("md-nav__link--active",t)}function An(e){e.classList.remove("md-nav__link--active")}function kn(e,t){e.firstElementChild.innerHTML=t}function Cn(e,t){e.setAttribute("data-md-state",t)}function Hn(e){e.removeAttribute("data-md-state")}function Fn(e,t){e.setAttribute("data-md-state",t)}function jn(e){e.removeAttribute("data-md-state")}function Rn(e,t){e.setAttribute("data-md-state",t)}function In(e){e.removeAttribute("data-md-state")}function Pn(e,t){e.placeholder=t}function $n(e){e.placeholder=G("search.placeholder")}function Wn(e,t){switch(t){case 0:e.textContent=G("search.result.none");break;case 1:e.textContent=G("search.result.one");break;default:e.textContent=G("search.result.other",Xt(t))}}function Un(e){e.textContent=G("search.result.placeholder")}function Vn(e,t){e.appendChild(t)}function Nn(e){e.innerHTML=""}function Dn(e,t){e.style.top=`${t}px`}function zn(e){e.style.top=""}function qn(e,t){let r=e.firstElementChild;r.style.height=`${t-2*r.offsetTop}px`}function Qn(e){let t=e.firstElementChild;t.style.height=""}function Kn(e,t){e.lastElementChild.appendChild(t)}function Bn(e,t){e.lastElementChild.setAttribute("data-md-state",t)}function Jn(e,t){e.setAttribute("data-md-state",t)}function Rr(e){e.removeAttribute("data-md-state")}function Yn(e,t){e.setAttribute("data-md-state",t)}function Ir(e){e.removeAttribute("data-md-state")}function Gn(e,t){e.style.top=`${t}px`}function Xn(e){e.style.top=""}function Zn(e){return I("button",{class:"md-clipboard md-icon",title:G("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}var qe;(function(r){r[r.TEASER=1]="TEASER",r[r.PARENT=2]="PARENT"})(qe||(qe={}));function Pr(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(a=>!e.terms[a]).map(a=>[I("del",null,a)," "]).flat().slice(0,-1),i=new URL(e.location);return he("search.highlight")&&i.searchParams.set("h",Object.entries(e.terms).filter(([,a])=>a).reduce((a,[s])=>`${a} ${s}`.trim(),"")),I("a",{href:`${i}`,class:"md-search-result__link",tabIndex:-1},I("article",{class:["md-search-result__article",...r?["md-search-result__article--document"]:[]].join(" "),"data-md-score":e.score.toFixed(2)},r>0&&I("div",{class:"md-search-result__icon md-icon"}),I("h1",{class:"md-search-result__title"},e.title),o>0&&e.text.length>0&&I("p",{class:"md-search-result__teaser"},fn(e.text,320)),o>0&&n.length>0&&I("p",{class:"md-search-result__terms"},G("search.result.term.missing"),": ",n)))}function ei(e){let t=e[0].score,r=[...e],o=r.findIndex(l=>!l.location.includes("#")),[n]=r.splice(o,1),i=r.findIndex(l=>l.scorePr(l,1)),...s.length?[I("details",{class:"md-search-result__more"},I("summary",{tabIndex:-1},s.length>0&&s.length===1?G("search.result.more.one"):G("search.result.more.other",s.length)),s.map(l=>Pr(l,1)))]:[]];return I("li",{class:"md-search-result__item"},c)}function ti(e){return I("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>I("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?Xt(r):r)))}function ri(e){return I("div",{class:"md-typeset__scrollwrap"},I("div",{class:"md-typeset__table"},e))}function $a(e){let t=le(),r=new URL(`../${e.version}/`,t.base);return I("li",{class:"md-version__item"},I("a",{href:r.toString(),class:"md-version__link"},e.title))}function oi(e){let t=le(),[,r]=t.base.match(/([^/]+)\/?$/),o=e.find(({version:n,aliases:i})=>n===r||i.includes(r))||e[0];return I("div",{class:"md-version"},I("button",{class:"md-version__current","aria-label":G("select.version.title")},o.title),I("ul",{class:"md-version__list"},e.map($a)))}var Wa=0;function Ua(e,{viewport$:t}){let r=R(e).pipe(M(o=>{let n=o.closest("[data-tabs]");return n instanceof HTMLElement?$(...Q("input",n).map(i=>w(i,"change"))):B}));return $(t.pipe(z("size")),r).pipe(f(()=>{let o=je(e);return{scroll:Jt(e).width>o.width}}),z("scroll"))}function ii(e,t){let r=new T;if(r.pipe(de(vt("(hover)"))).subscribe(([{scroll:o},n])=>{o&&n?tr(e):gt(e)}),ni.default.isSupported()){let o=e.closest("pre");o.id=`__code_${Wa++}`,o.insertBefore(Zn(o.id),e)}return Ua(e,t).pipe(L(o=>r.next(o)),F(()=>r.complete()),f(o=>P({ref:e},o)))}function Va(e,{target$:t,print$:r}){return t.pipe(f(o=>o.closest("details:not([open])")),_(o=>e===o),ee({scroll:!0}),Ne(r.pipe(ee({}))))}function ai(e,t){let r=new T;return r.subscribe(({scroll:o})=>{e.setAttribute("open",""),o&&e.scrollIntoView()}),Va(e,t).pipe(L(o=>r.next(o)),F(()=>r.complete()),ee({ref:e}))}var si=I("table");function ci(e){return ze(e,si),ze(si,ri(e)),R({ref:e})}function Na(e){return e.classList.contains("tabbed-alternate")?$(...Q(":scope > input",e).map(t=>w(t,"change").pipe(ee(t.id)))).pipe(f(t=>({active:ce(`label[for=${t}]`)}))):B}function li(e){let t=new T;return t.subscribe(({active:r})=>{let o=r.parentElement;(r.offsetLeft+r.offsetWidth>o.scrollLeft+o.offsetWidth||r.offsetLeftt.next(r)),F(()=>t.complete()),f(r=>P({ref:e},r)))}function pi(e,{target$:t,viewport$:r,print$:o}){return $(...Q("pre > code",e).map(n=>ii(n,{viewport$:r})),...Q("table:not([class])",e).map(n=>ci(n)),...Q("details",e).map(n=>ai(n,{target$:t,print$:o})),...Q("[data-tabs]",e).map(n=>li(n)))}function Da(e,{alert$:t}){return t.pipe(M(r=>$(R(!0),R(!1).pipe(Le(2e3))).pipe(f(o=>({message:r,open:o})))))}function ui(e,t){let r=new T;return r.pipe(D(Z)).subscribe(({message:o,open:n})=>{kn(e,o),n?Cn(e,"open"):Hn(e)}),Da(e,t).pipe(L(o=>r.next(o)),F(()=>r.complete()),f(o=>P({ref:e},o)))}function za({viewport$:e}){if(!he("header.autohide"))return R(!1);let t=e.pipe(f(({offset:{y:n}})=>n),ye(2,1),f(([n,i])=>[nMath.abs(i-n.y)>100),f(([,[n]])=>n),q()),o=Gt("search");return J([e,o]).pipe(f(([{offset:n},i])=>n.y>400&&!i),q(),M(n=>n?r:R(!1)),N(!1))}function fi(e,t){return Me(()=>{let r=getComputedStyle(e);return R(r.position==="sticky"||r.position==="-webkit-sticky")}).pipe(rt(Re(e),za(t)),f(([r,{height:o},n])=>({height:r?o:0,sticky:r,hidden:n})),q((r,o)=>r.sticky===o.sticky&&r.height===o.height&&r.hidden===o.hidden),Y(1))}function mi(e,{header$:t,main$:r}){let o=new T;return o.pipe(z("active"),rt(t),D(Z)).subscribe(([{active:n},{hidden:i}])=>{n?Fn(e,i?"hidden":"shadow"):jn(e)}),r.subscribe(n=>o.next(n)),t.pipe(f(n=>P({ref:e},n)))}function qa(e,{viewport$:t,header$:r}){return er(e,{header$:r,viewport$:t}).pipe(f(({offset:{y:o}})=>{let{height:n}=je(e);return{active:o>=n}}),z("active"))}function di(e,t){let r=new T;r.pipe(D(Z)).subscribe(({active:n})=>{n?Rn(e,"active"):In(e)});let o=se("article h1");return typeof o=="undefined"?B:qa(o,t).pipe(L(n=>r.next(n)),F(()=>r.complete()),f(n=>P({ref:e},n)))}function hi(e,{viewport$:t,header$:r}){let o=r.pipe(f(({height:i})=>i),q()),n=o.pipe(M(()=>Re(e).pipe(f(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),z("bottom"))));return J([o,n,t]).pipe(f(([i,{top:a,bottom:s},{offset:{y:c},size:{height:l}}])=>(l=Math.max(0,l-Math.max(0,a-c,i)-Math.max(0,l+c-s)),{offset:a-i,height:l,active:a-i<=c})),q((i,a)=>i.offset===a.offset&&i.height===a.height&&i.active===a.active))}function Qa(e){let t=localStorage.getItem(__prefix("__palette")),r=JSON.parse(t)||{index:e.findIndex(n=>matchMedia(n.getAttribute("data-md-color-media")).matches)},o=R(...e).pipe(ne(n=>w(n,"change").pipe(ee(n))),N(e[Math.max(0,r.index)]),f(n=>({index:e.indexOf(n),color:{scheme:n.getAttribute("data-md-color-scheme"),primary:n.getAttribute("data-md-color-primary"),accent:n.getAttribute("data-md-color-accent")}})),Y(1));return o.subscribe(n=>{localStorage.setItem(__prefix("__palette"),JSON.stringify(n))}),o}function bi(e){let t=new T;t.subscribe(o=>{for(let[n,i]of Object.entries(o.color))typeof i=="string"&&document.body.setAttribute(`data-md-color-${n}`,i);for(let n=0;nt.next(o)),F(()=>t.complete()),f(o=>P({ref:e},o)))}var $r=Ke(jr());function vi({alert$:e}){$r.default.isSupported()&&new k(t=>{new $r.default("[data-clipboard-target], [data-clipboard-text]").on("success",r=>t.next(r))}).subscribe(()=>e.next(G("clipboard.copied")))}function Ka(e){if(e.length<2)return e;let[t,r]=e.sort((i,a)=>i.length-a.length).map(i=>i.replace(/[^/]+$/,"")),o=0;if(t===r)o=t.length;else for(;t.charCodeAt(o)===r.charCodeAt(o);)o++;let n=le();return e.map(i=>i.replace(t.slice(0,o),n.base))}function xi({document$:e,location$:t,viewport$:r}){let o=le();if(location.protocol==="file:")return;"scrollRestoration"in history&&(history.scrollRestoration="manual",w(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}));let n=se("link[rel=icon]");typeof n!="undefined"&&(n.href=n.href);let i=vn(new URL("sitemap.xml",o.base)).pipe(f(l=>Ka(Q("loc",l).map(p=>p.textContent))),M(l=>w(document.body,"click").pipe(_(p=>!p.metaKey&&!p.ctrlKey),M(p=>{if(p.target instanceof Element){let m=p.target.closest("a");if(m&&!m.target){let u=new URL(m.href);if(u.search="",u.hash="",u.pathname!==location.pathname&&l.includes(u.toString()))return p.preventDefault(),R({url:new URL(m.href)})}}return B}))),me()),a=w(window,"popstate").pipe(_(l=>l.state!==null),f(l=>({url:new URL(location.href),offset:l.state})),me());$(i,a).pipe(q((l,p)=>l.url.href===p.url.href),f(({url:l})=>l)).subscribe(t);let s=t.pipe(z("pathname"),M(l=>Zt(l.href).pipe(Fe(()=>(ln(l),B)))),me());i.pipe(ot(s)).subscribe(({url:l})=>{history.pushState({},"",`${l}`)});let c=new DOMParser;s.pipe(M(l=>l.text()),f(l=>c.parseFromString(l,"text/html"))).subscribe(e),e.pipe(Bt(1)).subscribe(l=>{for(let p of["title","link[rel=canonical]","meta[name=author]","meta[name=description]","[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=logo], .md-logo","[data-md-component=skip]",...he("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let m=se(p),u=se(p,l);typeof m!="undefined"&&typeof u!="undefined"&&ze(m,u)}}),e.pipe(Bt(1),f(()=>Te("container")),M(l=>R(...Q("script",l))),yr(l=>{let p=I("script");if(l.src){for(let m of l.getAttributeNames())p.setAttribute(m,l.getAttribute(m));return ze(l,p),new k(m=>{p.onload=()=>m.complete()})}else return p.textContent=l.textContent,ze(l,p),fe})).subscribe(),$(i,a).pipe(ot(e)).subscribe(({url:l,offset:p})=>{l.hash&&!p?dn(l.hash):Hr(p||{y:0})}),r.pipe(bt(i),Sr(250),z("offset")).subscribe(({offset:l})=>{history.replaceState(l,"")}),$(i,a).pipe(ye(2,1),_(([l,p])=>l.url.pathname===p.url.pathname),f(([,l])=>l)).subscribe(({offset:l})=>{Hr(l||{y:0})})}var Ya=Ke(Wr());var yi=Ke(Wr());function Ur(e,t){let r=new RegExp(e.separator,"img"),o=(n,i,a)=>`${i}${a}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator})(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return a=>(t?(0,yi.default)(a):a).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function Si(e){return e.split(/"([^"]+)"/g).map((t,r)=>r&1?t.replace(/^\b|^(?![^\x00-\x7F]|$)|\s+/g," +"):t).join("").replace(/"|(?:^|\s+)[*+\-:^~]+(?=\s+|$)/g,"").trim()}var Ae;(function(n){n[n.SETUP=0]="SETUP",n[n.READY=1]="READY",n[n.QUERY=2]="QUERY",n[n.RESULT=3]="RESULT"})(Ae||(Ae={}));function it(e){return e.type===1}function wi(e){return e.type===2}function at(e){return e.type===3}function Ga({config:e,docs:t,index:r}){e.lang.length===1&&e.lang[0]==="en"&&(e.lang=[G("search.config.lang")]),e.separator==="[\\s\\-]+"&&(e.separator=G("search.config.separator"));let n={pipeline:G("search.config.pipeline").split(/\s*,\s*/).filter(Boolean),suggestions:he("search.suggest")};return{config:e,docs:t,index:r,options:n}}function Ei(e,t){let r=le(),o=new Worker(e),n=new T,i=En(o,{tx$:n}).pipe(f(a=>{if(at(a))for(let s of a.data.items)for(let c of s)c.location=`${new URL(c.location,r.base)}`;return a}),me());return re(t).pipe(f(a=>({type:Ae.SETUP,data:Ga(a)}))).subscribe(n.next.bind(n)),{tx$:n,rx$:i}}function Ti(){let e=le();Ee(new URL("../versions.json",e.base)).subscribe(t=>{ce(".md-header__topic").appendChild(oi(t))})}function Xa(e,{rx$:t}){let r=(__search==null?void 0:__search.transform)||Si,{searchParams:o}=Pe();o.has("q")&&Ie("search",!0);let n=t.pipe(_(it),xe(1),f(()=>o.get("q")||""));n.subscribe(s=>{s&&(e.value=s)});let i=tn(e),a=$(w(e,"keyup"),w(e,"focus").pipe(Le(1)),n).pipe(f(()=>r(e.value)),N(""),q());return J([a,i]).pipe(f(([s,c])=>({value:s,focus:c})),Y(1))}function Oi(e,{tx$:t,rx$:r}){let o=new T;return o.pipe(z("value"),f(({value:n})=>({type:Ae.QUERY,data:n}))).subscribe(t.next.bind(t)),o.pipe(z("focus")).subscribe(({focus:n})=>{n?(Ie("search",n),Pn(e,"")):$n(e)}),w(e.form,"reset").pipe(Mr(o.pipe(Er(1)))).subscribe(()=>we(e)),Xa(e,{tx$:t,rx$:r}).pipe(L(n=>o.next(n)),F(()=>o.complete()),f(n=>P({ref:e},n)))}function _i(e,{rx$:t},{query$:r}){let o=new T,n=nn(e.parentElement).pipe(_(Boolean)),i=ce(":scope > :first-child",e),a=ce(":scope > :last-child",e),s=t.pipe(_(it),xe(1));return o.pipe(D(Z),de(r),bt(s)).subscribe(([{items:l},{value:p}])=>{p?Wn(i,l.length):Un(i)}),o.pipe(D(Z),L(()=>Nn(a)),M(({items:l})=>$(R(...l.slice(0,10)),R(...l.slice(10)).pipe(ye(4),kr(n),M(([p])=>R(...p)))))).subscribe(l=>{Vn(a,ei(l))}),t.pipe(_(at),f(({data:l})=>l)).pipe(L(l=>o.next(l)),F(()=>o.complete()),f(l=>P({ref:e},l)))}function Za(e,{query$:t}){return t.pipe(f(({value:r})=>{let o=Pe();return o.hash="",o.searchParams.delete("h"),o.searchParams.set("q",r),{url:o}}))}function Mi(e,t){let r=new T;return r.subscribe(({url:o})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${o}`}),w(e,"click").subscribe(o=>o.preventDefault()),Za(e,t).pipe(L(o=>r.next(o)),F(()=>r.complete()),f(o=>P({ref:e},o)))}function Li(e,{rx$:t},{keyboard$:r}){let o=new T,n=Te("search-query"),i=$(w(n,"keydown"),w(n,"focus")).pipe(D(ke),f(()=>n.value),q());return o.pipe(rt(i),f(([{suggestions:s},c])=>{let l=c.split(/([\s-]+)/);if((s==null?void 0:s.length)&&l[l.length-1]){let p=s[s.length-1];p.startsWith(l[l.length-1])&&(l[l.length-1]=p)}else l.length=0;return l})).subscribe(s=>e.innerHTML=s.join("").replace(/\s/g," ")),r.pipe(_(({mode:s})=>s==="search")).subscribe(s=>{switch(s.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(_(at),f(({data:s})=>s)).pipe(L(s=>o.next(s)),F(()=>o.complete()),f(()=>({ref:e})))}function Ai(e,{index$:t,keyboard$:r}){let o=le();try{let n=(__search==null?void 0:__search.worker)||o.search,i=Ei(n,t),a=Te("search-query",e),s=Te("search-result",e),{tx$:c,rx$:l}=i;c.pipe(_(wi),ot(l.pipe(_(it))),xe(1)).subscribe(c.next.bind(c)),r.pipe(_(({mode:u})=>u==="search")).subscribe(u=>{let b=De();switch(u.type){case"Enter":if(b===a){let v=new Map;for(let d of Q(":first-child [href]",s)){let V=d.firstElementChild;v.set(d,parseFloat(V.getAttribute("data-md-score")))}if(v.size){let[[d]]=[...v].sort(([,V],[,K])=>K-V);d.click()}u.claim()}break;case"Escape":case"Tab":Ie("search",!1),we(a,!1);break;case"ArrowUp":case"ArrowDown":if(typeof b=="undefined")we(a);else{let v=[a,...Q(":not(details) > [href], summary, details[open] [href]",s)],d=Math.max(0,(Math.max(0,v.indexOf(b))+v.length+(u.type==="ArrowUp"?-1:1))%v.length);we(v[d])}u.claim();break;default:a!==De()&&we(a)}}),r.pipe(_(({mode:u})=>u==="global")).subscribe(u=>{switch(u.type){case"f":case"s":case"/":we(a),an(a),u.claim();break}});let p=Oi(a,i),m=_i(s,i,{query$:p});return $(p,m).pipe(Ne(...ie("search-share",e).map(u=>Mi(u,{query$:p})),...ie("search-suggest",e).map(u=>Li(u,i,{keyboard$:r}))))}catch(n){return e.hidden=!0,B}}function ki(e,{index$:t,location$:r}){return J([t,r.pipe(N(Pe()),_(o=>o.searchParams.has("h")))]).pipe(f(([o,n])=>Ur(o.config,!0)(n.searchParams.get("h"))),f(o=>{var a;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let s=i.nextNode();s;s=i.nextNode())if((a=s.parentElement)==null?void 0:a.offsetHeight){let c=s.textContent,l=o(c);l.length>c.length&&n.set(s,l)}for(let[s,c]of n){let{childNodes:l}=I("span",null,c);s.replaceWith(...Array.from(l))}return{ref:e,nodes:n}}))}function es(e,{viewport$:t,main$:r}){let o=e.parentElement.offsetTop-e.parentElement.parentElement.offsetTop;return J([r,t]).pipe(f(([{offset:n,height:i},{offset:{y:a}}])=>(i=i+Math.min(o,Math.max(0,a-n))-o,{height:i,locked:a>=n+o})),q((n,i)=>n.height===i.height&&n.locked===i.locked))}function Vr(e,o){var n=o,{header$:t}=n,r=Kr(n,["header$"]);let i=new T;return i.pipe(D(Z),de(t)).subscribe({next([{height:a},{height:s}]){qn(e,a),Dn(e,s)},complete(){zn(e),Qn(e)}}),es(e,r).pipe(L(a=>i.next(a)),F(()=>i.complete()),f(a=>P({ref:e},a)))}function Ci(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return ht(Ee(`${r}/releases/latest`).pipe(f(o=>({version:o.tag_name})),Ve({})),Ee(r).pipe(f(o=>({stars:o.stargazers_count,forks:o.forks_count})),Ve({}))).pipe(f(([o,n])=>P(P({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return Ee(r).pipe(f(o=>({repositories:o.public_repos})),Ve({}))}}function Hi(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return Ee(r).pipe(f(({star_count:o,forks_count:n})=>({stars:o,forks:n})),Ve({}))}function Fi(e){let[t]=e.match(/(git(?:hub|lab))/i)||[];switch(t.toLowerCase()){case"github":let[,r,o]=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);return Ci(r,o);case"gitlab":let[,n,i]=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i);return Hi(n,i);default:return B}}var ts;function rs(e){return ts||(ts=Me(()=>{let t=sessionStorage.getItem(__prefix("__source"));if(t)return R(JSON.parse(t));{let r=Fi(e.href);return r.subscribe(o=>{try{sessionStorage.setItem(__prefix("__source"),JSON.stringify(o))}catch(n){}}),r}}).pipe(Fe(()=>B),_(t=>Object.keys(t).length>0),f(t=>({facts:t})),Y(1)))}function ji(e){let t=new T;return t.subscribe(({facts:r})=>{Kn(e,ti(r)),Bn(e,"done")}),rs(e).pipe(L(r=>t.next(r)),F(()=>t.complete()),f(r=>P({ref:e},r)))}function os(e,{viewport$:t,header$:r}){return Re(document.body).pipe(M(()=>er(e,{header$:r,viewport$:t})),f(({offset:{y:o}})=>({hidden:o>=10})),z("hidden"))}function Ri(e,t){let r=new T;return r.pipe(D(Z)).subscribe({next({hidden:o}){o?Jn(e,"hidden"):Rr(e)},complete(){Rr(e)}}),(he("navigation.tabs.sticky")?R({hidden:!1}):os(e,t)).pipe(L(o=>r.next(o)),F(()=>r.complete()),f(o=>P({ref:e},o)))}function ns(e,{viewport$:t,header$:r}){let o=new Map;for(let a of e){let s=decodeURIComponent(a.hash.substring(1)),c=se(`[id="${s}"]`);typeof c!="undefined"&&o.set(a,c)}let n=r.pipe(f(a=>24+a.height));return Re(document.body).pipe(z("height"),f(()=>{let a=[];return[...o].reduce((s,[c,l])=>{for(;a.length&&o.get(a[a.length-1]).tagName>=l.tagName;)a.pop();let p=l.offsetTop;for(;!p&&l.parentElement;)l=l.parentElement,p=l.offsetTop;return s.set([...a=[...a,c]].reverse(),p)},new Map)}),f(a=>new Map([...a].sort(([,s],[,c])=>s-c))),M(a=>J([n,t]).pipe(Tr(([s,c],[l,{offset:{y:p}}])=>{for(;c.length;){let[,m]=c[0];if(m-l=p)c=[s.pop(),...c];else break}return[s,c]},[[],[...a]]),q((s,c)=>s[0]===c[0]&&s[1]===c[1])))).pipe(f(([a,s])=>({prev:a.map(([c])=>c),next:s.map(([c])=>c)})),N({prev:[],next:[]}),ye(2,1),f(([a,s])=>a.prev.length{for(let[a]of i)An(a),Mn(a);for(let[a,[s]]of n.entries())Ln(s,a===n.length-1),_n(s,"blur")});let o=Q("[href^=\\#]",e);return ns(o,t).pipe(L(n=>r.next(n)),F(()=>r.complete()),f(n=>P({ref:e},n)))}function is(e,{viewport$:t,main$:r}){let o=t.pipe(f(({offset:{y:i}})=>i),ye(2,1),f(([i,a])=>i>a&&a),q()),n=r.pipe(z("active"));return J([n,o]).pipe(f(([{active:i},a])=>({hidden:!(i&&a)})),q((i,a)=>i.hidden===a.hidden))}function Pi(e,{viewport$:t,header$:r,main$:o}){let n=new T;return n.pipe(D(Z),de(r.pipe(z("height")))).subscribe({next([{hidden:i},{height:a}]){Gn(e,a+16),i?(Yn(e,"hidden"),we(e,!1),tr(e,-1)):(Ir(e),gt(e))},complete(){Xn(e),Ir(e),gt(e)}}),is(e,{viewport$:t,header$:r,main$:o}).pipe(L(i=>n.next(i)),F(()=>n.complete()),f(i=>P({ref:e},i)))}function $i({document$:e,tablet$:t}){e.pipe(M(()=>R(...Q("[data-md-state=indeterminate]"))),L(r=>{r.indeterminate=!0,r.checked=!1}),ne(r=>w(r,"change").pipe(Lr(()=>r.hasAttribute("data-md-state")),ee(r))),de(t)).subscribe(([r,o])=>{r.removeAttribute("data-md-state"),o&&(r.checked=!1)})}function as(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function Wi({document$:e}){e.pipe(M(()=>R(...Q("[data-md-scrollfix]"))),L(t=>t.removeAttribute("data-md-scrollfix")),_(as),ne(t=>w(t,"touchstart").pipe(ee(t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function Ui({viewport$:e,tablet$:t}){J([Gt("search"),t]).pipe(f(([r,o])=>r&&!o),M(r=>R(r).pipe(Le(r?400:100),D(Z))),de(e)).subscribe(([r,{offset:{y:o}}])=>{r?Tn(document.body,o):On(document.body)})}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var st=en(),rr=pn(),Nr=hn(),Dr=cn(),be=wn(),or=vt("(min-width: 960px)"),Vi=vt("(min-width: 1220px)"),Ni=bn(),Di=le(),zi=document.forms.namedItem("search")?(__search==null?void 0:__search.index)||Ee(new URL("search/search_index.json",Di.base)):B,zr=new T;vi({alert$:zr});he("navigation.instant")&&xi({document$:st,location$:rr,viewport$:be});var Qi;((Qi=Di.version)==null?void 0:Qi.provider)==="mike"&&Ti();$(rr,Nr).pipe(Le(125)).subscribe(()=>{Ie("drawer",!1),Ie("search",!1)});Dr.pipe(_(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=se("[href][rel=prev]");typeof t!="undefined"&&t.click();break;case"n":case".":let r=se("[href][rel=next]");typeof r!="undefined"&&r.click();break}});$i({document$:st,tablet$:or});Wi({document$:st});Ui({viewport$:be,tablet$:or});var $e=fi(Te("header"),{viewport$:be}),nr=st.pipe(f(()=>Te("main")),M(e=>hi(e,{viewport$:be,header$:$e})),Y(1)),ss=$(...ie("dialog").map(e=>ui(e,{alert$:zr})),...ie("header").map(e=>mi(e,{viewport$:be,header$:$e,main$:nr})),...ie("palette").map(e=>bi(e)),...ie("search").map(e=>Ai(e,{index$:zi,keyboard$:Dr})),...ie("source").map(e=>ji(e))),cs=Me(()=>$(...ie("content").map(e=>pi(e,{target$:Nr,viewport$:be,print$:Ni})),...ie("content").map(e=>he("search.highlight")?ki(e,{index$:zi,location$:rr}):B),...ie("header-title").map(e=>di(e,{viewport$:be,header$:$e})),...ie("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Cr(Vi,()=>Vr(e,{viewport$:be,header$:$e,main$:nr})):Cr(or,()=>Vr(e,{viewport$:be,header$:$e,main$:nr}))),...ie("tabs").map(e=>Ri(e,{viewport$:be,header$:$e})),...ie("toc").map(e=>Ii(e,{viewport$:be,header$:$e})),...ie("top").map(e=>Pi(e,{viewport$:be,header$:$e,main$:nr})))),qi=st.pipe(M(()=>cs),Ne(ss),Y(1));qi.subscribe();window.document$=st;window.location$=rr;window.target$=Nr;window.keyboard$=Dr;window.viewport$=be;window.tablet$=or;window.screen$=Vi;window.print$=Ni;window.alert$=zr;window.component$=qi;})(); +//# sourceMappingURL=bundle.b1047164.min.js.map + diff --git a/assets/javascripts/bundle.b1047164.min.js.map b/assets/javascripts/bundle.b1047164.min.js.map new file mode 100644 index 00000000..16e07a8a --- /dev/null +++ b/assets/javascripts/bundle.b1047164.min.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/rxjs/node_modules/tslib/tslib.js", "node_modules/clipboard/dist/clipboard.js", "node_modules/escape-html/index.js", "src/assets/javascripts/bundle.ts", "node_modules/rxjs/node_modules/tslib/modules/index.js", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/concatMap.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/sample.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/switchMapTo.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/assets/javascripts/browser/document/index.ts", "src/assets/javascripts/browser/element/_/index.ts", "src/assets/javascripts/browser/element/focus/index.ts", "src/assets/javascripts/browser/element/size/index.ts", "src/assets/javascripts/browser/element/offset/index.ts", "src/assets/javascripts/browser/element/selection/index.ts", "src/assets/javascripts/browser/toggle/index.ts", "src/assets/javascripts/browser/keyboard/index.ts", "src/assets/javascripts/browser/location/_/index.ts", "src/assets/javascripts/utilities/h/index.ts", "src/assets/javascripts/utilities/string/index.ts", "src/assets/javascripts/browser/location/hash/index.ts", "src/assets/javascripts/browser/media/index.ts", "src/assets/javascripts/browser/request/index.ts", "src/assets/javascripts/browser/viewport/offset/index.ts", "src/assets/javascripts/browser/viewport/size/index.ts", "src/assets/javascripts/browser/viewport/_/index.ts", "src/assets/javascripts/browser/worker/index.ts", "src/assets/javascripts/_/index.ts", "src/assets/javascripts/components/_/index.ts", "src/assets/javascripts/components/content/code/index.ts", "src/assets/javascripts/actions/_/index.ts", "src/assets/javascripts/actions/anchor/index.ts", "src/assets/javascripts/actions/dialog/index.ts", "src/assets/javascripts/actions/header/_/index.ts", "src/assets/javascripts/actions/header/title/index.ts", "src/assets/javascripts/actions/search/query/index.ts", "src/assets/javascripts/actions/search/result/index.ts", "src/assets/javascripts/actions/sidebar/index.ts", "src/assets/javascripts/actions/source/index.ts", "src/assets/javascripts/actions/tabs/index.ts", "src/assets/javascripts/actions/top/index.ts", "src/assets/javascripts/templates/clipboard/index.tsx", "src/assets/javascripts/templates/search/index.tsx", "src/assets/javascripts/templates/source/index.tsx", "src/assets/javascripts/templates/table/index.tsx", "src/assets/javascripts/templates/version/index.tsx", "src/assets/javascripts/components/content/details/index.ts", "src/assets/javascripts/components/content/table/index.ts", "src/assets/javascripts/components/content/tabs/index.ts", "src/assets/javascripts/components/content/_/index.ts", "src/assets/javascripts/components/dialog/index.ts", "src/assets/javascripts/components/header/_/index.ts", "src/assets/javascripts/components/header/title/index.ts", "src/assets/javascripts/components/main/index.ts", "src/assets/javascripts/components/palette/index.ts", "src/assets/javascripts/integrations/clipboard/index.ts", "src/assets/javascripts/integrations/instant/index.ts", "src/assets/javascripts/integrations/search/document/index.ts", "src/assets/javascripts/integrations/search/highlighter/index.ts", "src/assets/javascripts/integrations/search/query/transform/index.ts", "src/assets/javascripts/integrations/search/worker/message/index.ts", "src/assets/javascripts/integrations/search/worker/_/index.ts", "src/assets/javascripts/integrations/version/index.ts", "src/assets/javascripts/components/search/query/index.ts", "src/assets/javascripts/components/search/result/index.ts", "src/assets/javascripts/components/search/share/index.ts", "src/assets/javascripts/components/search/suggest/index.ts", "src/assets/javascripts/components/search/_/index.ts", "src/assets/javascripts/components/search/highlight/index.ts", "src/assets/javascripts/components/sidebar/index.ts", "src/assets/javascripts/components/source/facts/github/index.ts", "src/assets/javascripts/components/source/facts/gitlab/index.ts", "src/assets/javascripts/components/source/facts/_/index.ts", "src/assets/javascripts/components/source/_/index.ts", "src/assets/javascripts/components/tabs/index.ts", "src/assets/javascripts/components/toc/index.ts", "src/assets/javascripts/components/top/index.ts", "src/assets/javascripts/patches/indeterminate/index.ts", "src/assets/javascripts/patches/scrollfix/index.ts", "src/assets/javascripts/patches/scrolllock/index.ts"], + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global global, define, System, Reflect, Promise */\r\nvar __extends;\r\nvar __assign;\r\nvar __rest;\r\nvar __decorate;\r\nvar __param;\r\nvar __metadata;\r\nvar __awaiter;\r\nvar __generator;\r\nvar __exportStar;\r\nvar __values;\r\nvar __read;\r\nvar __spread;\r\nvar __spreadArrays;\r\nvar __spreadArray;\r\nvar __await;\r\nvar __asyncGenerator;\r\nvar __asyncDelegator;\r\nvar __asyncValues;\r\nvar __makeTemplateObject;\r\nvar __importStar;\r\nvar __importDefault;\r\nvar __classPrivateFieldGet;\r\nvar __classPrivateFieldSet;\r\nvar __createBinding;\r\n(function (factory) {\r\n var root = typeof global === \"object\" ? global : typeof self === \"object\" ? self : typeof this === \"object\" ? this : {};\r\n if (typeof define === \"function\" && define.amd) {\r\n define(\"tslib\", [\"exports\"], function (exports) { factory(createExporter(root, createExporter(exports))); });\r\n }\r\n else if (typeof module === \"object\" && typeof module.exports === \"object\") {\r\n factory(createExporter(root, createExporter(module.exports)));\r\n }\r\n else {\r\n factory(createExporter(root));\r\n }\r\n function createExporter(exports, previous) {\r\n if (exports !== root) {\r\n if (typeof Object.create === \"function\") {\r\n Object.defineProperty(exports, \"__esModule\", { value: true });\r\n }\r\n else {\r\n exports.__esModule = true;\r\n }\r\n }\r\n return function (id, v) { return exports[id] = previous ? previous(id, v) : v; };\r\n }\r\n})\r\n(function (exporter) {\r\n var extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n\r\n __extends = function (d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n };\r\n\r\n __assign = Object.assign || function (t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n };\r\n\r\n __rest = function (s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n };\r\n\r\n __decorate = function (decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n };\r\n\r\n __param = function (paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n };\r\n\r\n __metadata = function (metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n };\r\n\r\n __awaiter = function (thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n };\r\n\r\n __generator = function (thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n };\r\n\r\n __exportStar = function(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n };\r\n\r\n __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n }) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n });\r\n\r\n __values = function (o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n };\r\n\r\n __read = function (o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n };\r\n\r\n /** @deprecated */\r\n __spread = function () {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n };\r\n\r\n /** @deprecated */\r\n __spreadArrays = function () {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n };\r\n\r\n __spreadArray = function (to, from) {\r\n for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)\r\n to[j] = from[i];\r\n return to;\r\n };\r\n\r\n __await = function (v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n };\r\n\r\n __asyncGenerator = function (thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n };\r\n\r\n __asyncDelegator = function (o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n };\r\n\r\n __asyncValues = function (o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n };\r\n\r\n __makeTemplateObject = function (cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n };\r\n\r\n var __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n }) : function(o, v) {\r\n o[\"default\"] = v;\r\n };\r\n\r\n __importStar = function (mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n };\r\n\r\n __importDefault = function (mod) {\r\n return (mod && mod.__esModule) ? mod : { \"default\": mod };\r\n };\r\n\r\n __classPrivateFieldGet = function (receiver, privateMap) {\r\n if (!privateMap.has(receiver)) {\r\n throw new TypeError(\"attempted to get private field on non-instance\");\r\n }\r\n return privateMap.get(receiver);\r\n };\r\n\r\n __classPrivateFieldSet = function (receiver, privateMap, value) {\r\n if (!privateMap.has(receiver)) {\r\n throw new TypeError(\"attempted to set private field on non-instance\");\r\n }\r\n privateMap.set(receiver, value);\r\n return value;\r\n };\r\n\r\n exporter(\"__extends\", __extends);\r\n exporter(\"__assign\", __assign);\r\n exporter(\"__rest\", __rest);\r\n exporter(\"__decorate\", __decorate);\r\n exporter(\"__param\", __param);\r\n exporter(\"__metadata\", __metadata);\r\n exporter(\"__awaiter\", __awaiter);\r\n exporter(\"__generator\", __generator);\r\n exporter(\"__exportStar\", __exportStar);\r\n exporter(\"__createBinding\", __createBinding);\r\n exporter(\"__values\", __values);\r\n exporter(\"__read\", __read);\r\n exporter(\"__spread\", __spread);\r\n exporter(\"__spreadArrays\", __spreadArrays);\r\n exporter(\"__spreadArray\", __spreadArray);\r\n exporter(\"__await\", __await);\r\n exporter(\"__asyncGenerator\", __asyncGenerator);\r\n exporter(\"__asyncDelegator\", __asyncDelegator);\r\n exporter(\"__asyncValues\", __asyncValues);\r\n exporter(\"__makeTemplateObject\", __makeTemplateObject);\r\n exporter(\"__importStar\", __importStar);\r\n exporter(\"__importDefault\", __importDefault);\r\n exporter(\"__classPrivateFieldGet\", __classPrivateFieldGet);\r\n exporter(\"__classPrivateFieldSet\", __classPrivateFieldSet);\r\n});\r\n", "/*!\n * clipboard.js v2.0.8\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 134:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/clipboard-action.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n\n/**\n * Inner class which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n */\n\nvar ClipboardAction = /*#__PURE__*/function () {\n /**\n * @param {Object} options\n */\n function ClipboardAction(options) {\n _classCallCheck(this, ClipboardAction);\n\n this.resolveOptions(options);\n this.initSelection();\n }\n /**\n * Defines base properties passed from constructor.\n * @param {Object} options\n */\n\n\n _createClass(ClipboardAction, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = options.action;\n this.container = options.container;\n this.emitter = options.emitter;\n this.target = options.target;\n this.text = options.text;\n this.trigger = options.trigger;\n this.selectedText = '';\n }\n /**\n * Decides which selection strategy is going to be applied based\n * on the existence of `text` and `target` properties.\n */\n\n }, {\n key: \"initSelection\",\n value: function initSelection() {\n if (this.text) {\n this.selectFake();\n } else if (this.target) {\n this.selectTarget();\n }\n }\n /**\n * Creates a fake textarea element, sets its value from `text` property,\n */\n\n }, {\n key: \"createFakeElement\",\n value: function createFakeElement() {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n this.fakeElem = document.createElement('textarea'); // Prevent zooming on iOS\n\n this.fakeElem.style.fontSize = '12pt'; // Reset box model\n\n this.fakeElem.style.border = '0';\n this.fakeElem.style.padding = '0';\n this.fakeElem.style.margin = '0'; // Move element out of screen horizontally\n\n this.fakeElem.style.position = 'absolute';\n this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n this.fakeElem.style.top = \"\".concat(yPosition, \"px\");\n this.fakeElem.setAttribute('readonly', '');\n this.fakeElem.value = this.text;\n return this.fakeElem;\n }\n /**\n * Get's the value of fakeElem,\n * and makes a selection on it.\n */\n\n }, {\n key: \"selectFake\",\n value: function selectFake() {\n var _this = this;\n\n var fakeElem = this.createFakeElement();\n\n this.fakeHandlerCallback = function () {\n return _this.removeFake();\n };\n\n this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true;\n this.container.appendChild(fakeElem);\n this.selectedText = select_default()(fakeElem);\n this.copyText();\n this.removeFake();\n }\n /**\n * Only removes the fake element after another click event, that way\n * a user can hit `Ctrl+C` to copy because selection still exists.\n */\n\n }, {\n key: \"removeFake\",\n value: function removeFake() {\n if (this.fakeHandler) {\n this.container.removeEventListener('click', this.fakeHandlerCallback);\n this.fakeHandler = null;\n this.fakeHandlerCallback = null;\n }\n\n if (this.fakeElem) {\n this.container.removeChild(this.fakeElem);\n this.fakeElem = null;\n }\n }\n /**\n * Selects the content from element passed on `target` property.\n */\n\n }, {\n key: \"selectTarget\",\n value: function selectTarget() {\n this.selectedText = select_default()(this.target);\n this.copyText();\n }\n /**\n * Executes the copy operation based on the current selection.\n */\n\n }, {\n key: \"copyText\",\n value: function copyText() {\n var succeeded;\n\n try {\n succeeded = document.execCommand(this.action);\n } catch (err) {\n succeeded = false;\n }\n\n this.handleResult(succeeded);\n }\n /**\n * Fires an event based on the copy operation result.\n * @param {Boolean} succeeded\n */\n\n }, {\n key: \"handleResult\",\n value: function handleResult(succeeded) {\n this.emitter.emit(succeeded ? 'success' : 'error', {\n action: this.action,\n text: this.selectedText,\n trigger: this.trigger,\n clearSelection: this.clearSelection.bind(this)\n });\n }\n /**\n * Moves focus away from `target` and back to the trigger, removes current selection.\n */\n\n }, {\n key: \"clearSelection\",\n value: function clearSelection() {\n if (this.trigger) {\n this.trigger.focus();\n }\n\n document.activeElement.blur();\n window.getSelection().removeAllRanges();\n }\n /**\n * Sets the `action` to be performed which can be either 'copy' or 'cut'.\n * @param {String} action\n */\n\n }, {\n key: \"destroy\",\n\n /**\n * Destroy lifecycle.\n */\n value: function destroy() {\n this.removeFake();\n }\n }, {\n key: \"action\",\n set: function set() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy';\n this._action = action;\n\n if (this._action !== 'copy' && this._action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n }\n }\n /**\n * Gets the `action` property.\n * @return {String}\n */\n ,\n get: function get() {\n return this._action;\n }\n /**\n * Sets the `target` property using an element\n * that will be have its content copied.\n * @param {Element} target\n */\n\n }, {\n key: \"target\",\n set: function set(target) {\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (this.action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n\n this._target = target;\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n }\n }\n /**\n * Gets the `target` property.\n * @return {String|HTMLElement}\n */\n ,\n get: function get() {\n return this._target;\n }\n }]);\n\n return ClipboardAction;\n}();\n\n/* harmony default export */ var clipboard_action = (ClipboardAction);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction clipboard_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction clipboard_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction clipboard_createClass(Constructor, protoProps, staticProps) { if (protoProps) clipboard_defineProperties(Constructor.prototype, protoProps); if (staticProps) clipboard_defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n clipboard_classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n clipboard_createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n\n if (this.clipboardAction) {\n this.clipboardAction = null;\n }\n\n this.clipboardAction = new clipboard_action({\n action: this.action(trigger),\n target: this.target(trigger),\n text: this.text(trigger),\n container: this.container,\n trigger: trigger,\n emitter: this\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n\n if (this.clipboardAction) {\n this.clipboardAction.destroy();\n this.clipboardAction = null;\n }\n }\n }], [{\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(134);\n/******/ })()\n.default;\n});", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\nimport { NEVER, Subject, defer, merge } from \"rxjs\"\nimport {\n delay,\n filter,\n map,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs/operators\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getElement,\n requestJSON,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountBackToTop,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantLoading,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget()\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? __search?.index || requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up instant loading, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantLoading({ document$, location$, viewport$ })\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector()\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getElement(\"[href][rel=prev]\")\n if (typeof prev !== \"undefined\")\n prev.click()\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getElement(\"[href][rel=next]\")\n if (typeof next !== \"undefined\")\n next.click()\n break\n }\n })\n\n/* Set up patches */\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { target$, viewport$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : NEVER\n ),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, { viewport$, header$ })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Tablet observable */\nwindow.screen$ = screen$ /* Screen observable */\nwindow.print$ = print$ /* Print mode observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.component$ = component$ /* Component observable */\n", "import tslib from '../tslib.js';\r\nconst {\r\n __extends,\r\n __assign,\r\n __rest,\r\n __decorate,\r\n __param,\r\n __metadata,\r\n __awaiter,\r\n __generator,\r\n __exportStar,\r\n __createBinding,\r\n __values,\r\n __read,\r\n __spread,\r\n __spreadArrays,\r\n __spreadArray,\r\n __await,\r\n __asyncGenerator,\r\n __asyncDelegator,\r\n __asyncValues,\r\n __makeTemplateObject,\r\n __importStar,\r\n __importDefault,\r\n __classPrivateFieldGet,\r\n __classPrivateFieldSet,\r\n} = tslib;\r\nexport {\r\n __extends,\r\n __assign,\r\n __rest,\r\n __decorate,\r\n __param,\r\n __metadata,\r\n __awaiter,\r\n __generator,\r\n __exportStar,\r\n __createBinding,\r\n __values,\r\n __read,\r\n __spread,\r\n __spreadArrays,\r\n __spreadArray,\r\n __await,\r\n __asyncGenerator,\r\n __asyncDelegator,\r\n __asyncValues,\r\n __makeTemplateObject,\r\n __importStar,\r\n __importDefault,\r\n __classPrivateFieldGet,\r\n __classPrivateFieldSet,\r\n};\r\n", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ReplaySubject, Subject, fromEvent } from \"rxjs\"\nimport { mapTo } from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch document\n *\n * Documents are implemented as subjects, so all downstream observables are\n * automatically updated when a new document is emitted.\n *\n * @returns Document subject\n */\nexport function watchDocument(): Subject {\n const document$ = new ReplaySubject()\n fromEvent(document, \"DOMContentLoaded\")\n .pipe(\n mapTo(document)\n )\n .subscribe(document$)\n\n /* Return document */\n return document$\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve an element matching the query selector\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Element or nothing\n */\nexport function getElement(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T] | undefined\n\nexport function getElement(\n selector: string, node?: ParentNode\n): T | undefined\n\nexport function getElement(\n selector: string, node: ParentNode = document\n): T | undefined {\n return node.querySelector(selector) || undefined\n}\n\n/**\n * Retrieve an element matching a query selector or throw a reference error\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Element\n */\nexport function getElementOrThrow(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T]\n\nexport function getElementOrThrow(\n selector: string, node?: ParentNode\n): T\n\nexport function getElementOrThrow(\n selector: string, node: ParentNode = document\n): T {\n const el = getElement(selector, node)\n if (typeof el === \"undefined\")\n throw new ReferenceError(\n `Missing element: expected \"${selector}\" to be present`\n )\n\n /* Return element */\n return el\n}\n\n/**\n * Retrieve the currently active element\n *\n * @returns Element or nothing\n */\nexport function getActiveElement(): HTMLElement | undefined {\n return document.activeElement instanceof HTMLElement\n ? document.activeElement\n : undefined\n}\n\n/**\n * Retrieve all elements matching the query selector\n *\n * @template T - Element type\n *\n * @param selector - Query selector\n * @param node - Node of reference\n *\n * @returns Elements\n */\nexport function getElements(\n selector: T, node?: ParentNode\n): HTMLElementTagNameMap[T][]\n\nexport function getElements(\n selector: string, node?: ParentNode\n): T[]\n\nexport function getElements(\n selector: string, node: ParentNode = document\n): T[] {\n return Array.from(node.querySelectorAll(selector))\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Replace an element with the given list of nodes\n *\n * @param el - Element\n * @param nodes - Replacement nodes\n */\nexport function replaceElement(\n el: HTMLElement, ...nodes: Node[]\n): void {\n el.replaceWith(...nodes)\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, merge } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\nimport { getActiveElement } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set element focus\n *\n * @param el - Element\n * @param value - Whether the element should be focused\n */\nexport function setElementFocus(\n el: HTMLElement, value = true\n): void {\n if (value)\n el.focus()\n else\n el.blur()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element focus\n *\n * @param el - Element\n *\n * @returns Element focus observable\n */\nexport function watchElementFocus(\n el: HTMLElement\n): Observable {\n return merge(\n fromEvent(el, \"focus\"),\n fromEvent(el, \"blur\")\n )\n .pipe(\n map(({ type }) => type === \"focus\"),\n startWith(el === getActiveElement())\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n NEVER,\n Observable,\n Subject,\n defer,\n of\n} from \"rxjs\"\nimport {\n filter,\n finalize,\n map,\n shareReplay,\n startWith,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Element offset\n */\nexport interface ElementSize {\n width: number /* Element width */\n height: number /* Element height */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Resize observer entry subject\n */\nconst entry$ = new Subject()\n\n/**\n * Resize observer observable\n *\n * This observable will create a `ResizeObserver` on the first subscription\n * and will automatically terminate it when there are no more subscribers.\n * It's quite important to centralize observation in a single `ResizeObserver`,\n * as the performance difference can be quite dramatic, as the link shows.\n *\n * @see https://bit.ly/3iIYfEm - Google Groups on performance\n */\nconst observer$ = defer(() => of(\n new ResizeObserver(entries => {\n for (const entry of entries)\n entry$.next(entry)\n })\n))\n .pipe(\n switchMap(resize => NEVER.pipe(startWith(resize))\n .pipe(\n finalize(() => resize.disconnect())\n )\n ),\n shareReplay(1)\n )\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element size\n *\n * @param el - Element\n *\n * @returns Element size\n */\nexport function getElementSize(el: HTMLElement): ElementSize {\n return {\n width: el.offsetWidth,\n height: el.offsetHeight\n }\n}\n\n/**\n * Retrieve element content size, i.e. including overflowing content\n *\n * @param el - Element\n *\n * @returns Element size\n */\nexport function getElementContentSize(el: HTMLElement): ElementSize {\n return {\n width: el.scrollWidth,\n height: el.scrollHeight\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element size\n *\n * This function returns an observable that subscribes to a single internal\n * instance of `ResizeObserver` upon subscription, and emit resize events until\n * termination. Note that this function should not be called with the same\n * element twice, as the first unsubscription will terminate observation.\n *\n * Sadly, we can't use the `DOMRect` objects returned by the observer, because\n * we need the emitted values to be consistent with `getElementSize`, which will\n * return the used values (rounded) and not actual values (unrounded). Thus, we\n * use the `offset*` properties. See the linked GitHub issue.\n *\n * @see https://bit.ly/3m0k3he - GitHub issue\n *\n * @param el - Element\n *\n * @returns Element size observable\n */\nexport function watchElementSize(\n el: HTMLElement\n): Observable {\n return observer$\n .pipe(\n tap(observer => observer.observe(el)),\n switchMap(observer => entry$\n .pipe(\n filter(({ target }) => target === el),\n finalize(() => observer.unobserve(el)),\n map(() => getElementSize(el))\n )\n ),\n startWith(getElementSize(el))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, merge } from \"rxjs\"\nimport {\n distinctUntilChanged,\n map,\n startWith\n} from \"rxjs/operators\"\n\nimport {\n getElementContentSize,\n getElementSize\n} from \"../size\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Element offset\n */\nexport interface ElementOffset {\n x: number /* Horizontal offset */\n y: number /* Vertical offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve element offset\n *\n * @param el - Element\n *\n * @returns Element offset\n */\nexport function getElementOffset(el: HTMLElement): ElementOffset {\n return {\n x: el.scrollLeft,\n y: el.scrollTop\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch element offset\n *\n * @param el - Element\n *\n * @returns Element offset observable\n */\nexport function watchElementOffset(\n el: HTMLElement\n): Observable {\n return merge(\n fromEvent(el, \"scroll\"),\n fromEvent(window, \"resize\")\n )\n .pipe(\n map(() => getElementOffset(el)),\n startWith(getElementOffset(el))\n )\n}\n\n/**\n * Watch element threshold\n *\n * This function returns an observable which emits whether the bottom scroll\n * offset of an elements is within a certain threshold.\n *\n * @param el - Element\n * @param threshold - Threshold\n *\n * @returns Element threshold observable\n */\nexport function watchElementThreshold(\n el: HTMLElement, threshold = 16\n): Observable {\n return watchElementOffset(el)\n .pipe(\n map(({ y }) => {\n const visible = getElementSize(el)\n const content = getElementContentSize(el)\n return y >= (\n content.height - visible.height - threshold\n )\n }),\n distinctUntilChanged()\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set element text selection\n *\n * @param el - Element\n */\nexport function setElementSelection(\n el: HTMLElement\n): void {\n if (el instanceof HTMLInputElement)\n el.select()\n else\n throw new Error(\"Not implemented\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\nimport { getElementOrThrow } from \"../element\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Toggle\n */\nexport type Toggle =\n | \"drawer\" /* Toggle for drawer */\n | \"search\" /* Toggle for search */\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Toggle map\n */\nconst toggles: Record = {\n drawer: getElementOrThrow(\"[data-md-toggle=drawer]\"),\n search: getElementOrThrow(\"[data-md-toggle=search]\")\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve the value of a toggle\n *\n * @param name - Toggle\n *\n * @returns Toggle value\n */\nexport function getToggle(name: Toggle): boolean {\n return toggles[name].checked\n}\n\n/**\n * Set toggle\n *\n * Simulating a click event seems to be the most cross-browser compatible way\n * of changing the value while also emitting a `change` event. Before, Material\n * used `CustomEvent` to programmatically change the value of a toggle, but this\n * is a much simpler and cleaner solution which doesn't require a polyfill.\n *\n * @param name - Toggle\n * @param value - Toggle value\n */\nexport function setToggle(name: Toggle, value: boolean): void {\n if (toggles[name].checked !== value)\n toggles[name].click()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch toggle\n *\n * @param name - Toggle\n *\n * @returns Toggle value observable\n */\nexport function watchToggle(name: Toggle): Observable {\n const el = toggles[name]\n return fromEvent(el, \"change\")\n .pipe(\n map(() => el.checked),\n startWith(el.checked)\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent } from \"rxjs\"\nimport { filter, map, share } from \"rxjs/operators\"\n\nimport { getActiveElement } from \"../element\"\nimport { getToggle } from \"../toggle\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Keyboard mode\n */\nexport type KeyboardMode =\n | \"global\" /* Global */\n | \"search\" /* Search is open */\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Keyboard\n */\nexport interface Keyboard {\n mode: KeyboardMode /* Keyboard mode */\n type: string /* Key type */\n claim(): void /* Key claim */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Check whether an element may receive keyboard input\n *\n * @param el - Element\n * @param type - Key type\n *\n * @returns Test result\n */\nfunction isSusceptibleToKeyboard(\n el: HTMLElement, type: string\n): boolean {\n switch (el.constructor) {\n\n /* Input elements */\n case HTMLInputElement:\n /* @ts-expect-error - omit unnecessary type cast */\n if (el.type === \"radio\")\n return /^Arrow/.test(type)\n else\n return true\n\n /* Select element and textarea */\n case HTMLSelectElement:\n case HTMLTextAreaElement:\n return true\n\n /* Everything else */\n default:\n return el.isContentEditable\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch keyboard\n *\n * @returns Keyboard observable\n */\nexport function watchKeyboard(): Observable {\n return fromEvent(window, \"keydown\")\n .pipe(\n filter(ev => !(ev.metaKey || ev.ctrlKey)),\n map(ev => ({\n mode: getToggle(\"search\") ? \"search\" : \"global\",\n type: ev.key,\n claim() {\n ev.preventDefault()\n ev.stopPropagation()\n }\n } as Keyboard)),\n filter(({ mode, type }) => {\n if (mode === \"global\") {\n const active = getActiveElement()\n if (typeof active !== \"undefined\")\n return !isSusceptibleToKeyboard(active, type)\n }\n return true\n }),\n share()\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Subject } from \"rxjs\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve location\n *\n * This function returns a `URL` object (and not `Location`) to normalize the\n * typings across the application. Furthermore, locations need to be tracked\n * without setting them and `Location` is a singleton which represents the\n * current location.\n *\n * @returns URL\n */\nexport function getLocation(): URL {\n return new URL(location.href)\n}\n\n/**\n * Set location\n *\n * @param url - URL to change to\n */\nexport function setLocation(url: URL): void {\n location.href = url.href\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch location\n *\n * @returns Location subject\n */\nexport function watchLocation(): Subject {\n return new Subject()\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { JSX as JSXInternal } from \"preact\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * HTML attributes\n */\ntype Attributes =\n & JSXInternal.HTMLAttributes\n & JSXInternal.SVGAttributes\n & Record\n\n/**\n * Child element\n */\ntype Child =\n | HTMLElement\n | Text\n | string\n | number\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Append a child node to an element\n *\n * @param el - Element\n * @param child - Child node(s)\n */\nfunction appendChild(el: HTMLElement, child: Child | Child[]): void {\n\n /* Handle primitive types (including raw HTML) */\n if (typeof child === \"string\" || typeof child === \"number\") {\n el.innerHTML += child.toString()\n\n /* Handle nodes */\n } else if (child instanceof Node) {\n el.appendChild(child)\n\n /* Handle nested children */\n } else if (Array.isArray(child)) {\n for (const node of child)\n appendChild(el, node)\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * JSX factory\n *\n * @template T - Element type\n *\n * @param tag - HTML tag\n * @param attributes - HTML attributes\n * @param children - Child elements\n *\n * @returns Element\n */\nexport function h(\n tag: T, attributes?: Attributes | null, ...children: Child[]\n): HTMLElementTagNameMap[T]\n\nexport function h(\n tag: string, attributes?: Attributes | null, ...children: Child[]\n): T\n\nexport function h(\n tag: string, attributes?: Attributes | null, ...children: Child[]\n): T {\n const el = document.createElement(tag)\n\n /* Set attributes, if any */\n if (attributes)\n for (const attr of Object.keys(attributes))\n if (typeof attributes[attr] !== \"boolean\")\n el.setAttribute(attr, attributes[attr])\n else if (attributes[attr])\n el.setAttribute(attr, \"\")\n\n /* Append child nodes */\n for (const child of children)\n appendChild(el, child)\n\n /* Return element */\n return el as T\n}\n\n/* ----------------------------------------------------------------------------\n * Namespace\n * ------------------------------------------------------------------------- */\n\nexport declare namespace h {\n namespace JSX {\n type Element = HTMLElement\n type IntrinsicElements = JSXInternal.IntrinsicElements\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Truncate a string after the given number of characters\n *\n * This is not a very reasonable approach, since the summaries kind of suck.\n * It would be better to create something more intelligent, highlighting the\n * search occurrences and making a better summary out of it, but this note was\n * written three years ago, so who knows if we'll ever fix it.\n *\n * @param value - Value to be truncated\n * @param n - Number of characters\n *\n * @returns Truncated value\n */\nexport function truncate(value: string, n: number): string {\n let i = n\n if (value.length > i) {\n while (value[i] !== \" \" && --i > 0) { /* keep eating */ }\n return `${value.substring(0, i)}...`\n }\n return value\n}\n\n/**\n * Round a number for display with repository facts\n *\n * This is a reverse-engineered version of GitHub's weird rounding algorithm\n * for stars, forks and all other numbers. While all numbers below `1,000` are\n * returned as-is, bigger numbers are converted to fixed numbers:\n *\n * - `1,049` => `1k`\n * - `1,050` => `1.1k`\n * - `1,949` => `1.9k`\n * - `1,950` => `2k`\n *\n * @param value - Original value\n *\n * @returns Rounded value\n */\nexport function round(value: number): string {\n if (value > 999) {\n const digits = +((value - 950) % 1000 > 99)\n return `${((value + 0.000001) / 1000).toFixed(digits)}k`\n } else {\n return value.toString()\n }\n}\n\n/**\n * Simple hash function\n *\n * @see https://bit.ly/2wsVjJ4 - Original source\n *\n * @param value - Value to be hashed\n *\n * @returns Hash as 32bit integer\n */\nexport function hash(value: string): number {\n let h = 0\n for (let i = 0, len = value.length; i < len; i++) {\n h = ((h << 5) - h) + value.charCodeAt(i)\n h |= 0 // Convert to 32bit integer\n }\n return h\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent } from \"rxjs\"\nimport {\n filter,\n map,\n shareReplay,\n startWith\n} from \"rxjs/operators\"\n\nimport { getElement } from \"~/browser\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve location hash\n *\n * @returns Location hash\n */\nexport function getLocationHash(): string {\n return location.hash.substring(1)\n}\n\n/**\n * Set location hash\n *\n * Setting a new fragment identifier via `location.hash` will have no effect\n * if the value doesn't change. When a new fragment identifier is set, we want\n * the browser to target the respective element at all times, which is why we\n * use this dirty little trick.\n *\n * @param hash - Location hash\n */\nexport function setLocationHash(hash: string): void {\n const el = h(\"a\", { href: hash })\n el.addEventListener(\"click\", ev => ev.stopPropagation())\n el.click()\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch location hash\n *\n * @returns Location hash observable\n */\nexport function watchLocationHash(): Observable {\n return fromEvent(window, \"hashchange\")\n .pipe(\n map(getLocationHash),\n startWith(getLocationHash()),\n filter(hash => hash.length > 0),\n shareReplay(1)\n )\n}\n\n/**\n * Watch location target\n *\n * @returns Location target observable\n */\nexport function watchLocationTarget(): Observable {\n return watchLocationHash()\n .pipe(\n map(id => getElement(`[id=\"${id}\"]`)!),\n filter(el => typeof el !== \"undefined\")\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n NEVER,\n Observable,\n fromEvent,\n fromEventPattern\n} from \"rxjs\"\nimport {\n mapTo,\n startWith,\n switchMap\n} from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch media query\n *\n * Note that although `MediaQueryList.addListener` is deprecated we have to\n * use it, because it's the only way to ensure proper downward compatibility.\n *\n * @see https://bit.ly/3dUBH2m - GitHub issue\n *\n * @param query - Media query\n *\n * @returns Media observable\n */\nexport function watchMedia(query: string): Observable {\n const media = matchMedia(query)\n return fromEventPattern(next => (\n media.addListener(() => next(media.matches))\n ))\n .pipe(\n startWith(media.matches)\n )\n}\n\n/**\n * Watch print mode, cross-browser\n *\n * @returns Print mode observable\n */\nexport function watchPrint(): Observable {\n return fromEvent(window, \"beforeprint\")\n .pipe(\n mapTo(undefined)\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Toggle an observable with a media observable\n *\n * @template T - Data type\n *\n * @param query$ - Media observable\n * @param factory - Observable factory\n *\n * @returns Toggled observable\n */\nexport function at(\n query$: Observable, factory: () => Observable\n): Observable {\n return query$\n .pipe(\n switchMap(active => active ? factory() : NEVER)\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { EMPTY, Observable, from } from \"rxjs\"\nimport {\n catchError,\n filter,\n map,\n shareReplay,\n switchMap\n} from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch the given URL\n *\n * If the request fails (e.g. when dispatched from `file://` locations), the\n * observable will complete without emitting a value.\n *\n * @param url - Request URL\n * @param options - Options\n *\n * @returns Response observable\n */\nexport function request(\n url: URL | string, options: RequestInit = { credentials: \"same-origin\" }\n): Observable {\n return from(fetch(`${url}`, options))\n .pipe(\n filter(res => res.status === 200),\n catchError(() => EMPTY)\n )\n}\n\n/**\n * Fetch JSON from the given URL\n *\n * @template T - Data type\n *\n * @param url - Request URL\n * @param options - Options\n *\n * @returns Data observable\n */\nexport function requestJSON(\n url: URL | string, options?: RequestInit\n): Observable {\n return request(url, options)\n .pipe(\n switchMap(res => res.json()),\n shareReplay(1)\n )\n}\n\n/**\n * Fetch XML from the given URL\n *\n * @param url - Request URL\n * @param options - Options\n *\n * @returns Data observable\n */\nexport function requestXML(\n url: URL | string, options?: RequestInit\n): Observable {\n const dom = new DOMParser()\n return request(url, options)\n .pipe(\n switchMap(res => res.text()),\n map(res => dom.parseFromString(res, \"text/xml\")),\n shareReplay(1)\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, merge } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport offset\n */\nexport interface ViewportOffset {\n x: number /* Horizontal offset */\n y: number /* Vertical offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve viewport offset\n *\n * On iOS Safari, viewport offset can be negative due to overflow scrolling.\n * As this may induce strange behaviors downstream, we'll just limit it to 0.\n *\n * @returns Viewport offset\n */\nexport function getViewportOffset(): ViewportOffset {\n return {\n x: Math.max(0, pageXOffset),\n y: Math.max(0, pageYOffset)\n }\n}\n\n/**\n * Set viewport offset\n *\n * @param offset - Viewport offset\n */\nexport function setViewportOffset(\n { x, y }: Partial\n): void {\n window.scrollTo(x || 0, y || 0)\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport offset\n *\n * @returns Viewport offset observable\n */\nexport function watchViewportOffset(): Observable {\n return merge(\n fromEvent(window, \"scroll\", { passive: true }),\n fromEvent(window, \"resize\", { passive: true })\n )\n .pipe(\n map(getViewportOffset),\n startWith(getViewportOffset())\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent } from \"rxjs\"\nimport { map, startWith } from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport size\n */\nexport interface ViewportSize {\n width: number /* Viewport width */\n height: number /* Viewport height */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve viewport size\n *\n * @returns Viewport size\n */\nexport function getViewportSize(): ViewportSize {\n return {\n width: innerWidth,\n height: innerHeight\n }\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport size\n *\n * @returns Viewport size observable\n */\nexport function watchViewportSize(): Observable {\n return fromEvent(window, \"resize\", { passive: true })\n .pipe(\n map(getViewportSize),\n startWith(getViewportSize())\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, combineLatest } from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n map,\n shareReplay\n} from \"rxjs/operators\"\n\nimport { Header } from \"~/components\"\n\nimport {\n ViewportOffset,\n watchViewportOffset\n} from \"../offset\"\nimport {\n ViewportSize,\n watchViewportSize\n} from \"../size\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Viewport\n */\nexport interface Viewport {\n offset: ViewportOffset /* Viewport offset */\n size: ViewportSize /* Viewport size */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch at options\n */\ninterface WatchAtOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch viewport\n *\n * @returns Viewport observable\n */\nexport function watchViewport(): Observable {\n return combineLatest([\n watchViewportOffset(),\n watchViewportSize()\n ])\n .pipe(\n map(([offset, size]) => ({ offset, size })),\n shareReplay(1)\n )\n}\n\n/**\n * Watch viewport relative to element\n *\n * @param el - Element\n * @param options - Options\n *\n * @returns Viewport observable\n */\nexport function watchViewportAt(\n el: HTMLElement, { viewport$, header$ }: WatchAtOptions\n): Observable {\n const size$ = viewport$\n .pipe(\n distinctUntilKeyChanged(\"size\")\n )\n\n /* Compute element offset */\n const offset$ = combineLatest([size$, header$])\n .pipe(\n map((): ViewportOffset => ({\n x: el.offsetLeft,\n y: el.offsetTop\n }))\n )\n\n /* Compute relative viewport, return hot observable */\n return combineLatest([header$, viewport$, offset$])\n .pipe(\n map(([{ height }, { offset, size }, { x, y }]) => ({\n offset: {\n x: offset.x - x,\n y: offset.y - y + height\n },\n size\n }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject, fromEvent } from \"rxjs\"\nimport {\n map,\n share,\n switchMapTo,\n tap,\n throttle\n} from \"rxjs/operators\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Worker message\n */\nexport interface WorkerMessage {\n type: unknown /* Message type */\n data?: unknown /* Message data */\n}\n\n/**\n * Worker handler\n *\n * @template T - Message type\n */\nexport interface WorkerHandler<\n T extends WorkerMessage\n> {\n tx$: Subject /* Message transmission subject */\n rx$: Observable /* Message receive observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n *\n * @template T - Worker message type\n */\ninterface WatchOptions {\n tx$: Observable /* Message transmission observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch a web worker\n *\n * This function returns an observable that sends all values emitted by the\n * message observable to the web worker. Web worker communication is expected\n * to be bidirectional (request-response) and synchronous. Messages that are\n * emitted during a pending request are throttled, the last one is emitted.\n *\n * @param worker - Web worker\n * @param options - Options\n *\n * @returns Worker message observable\n */\nexport function watchWorker(\n worker: Worker, { tx$ }: WatchOptions\n): Observable {\n\n /* Intercept messages from worker-like objects */\n const rx$ = fromEvent(worker, \"message\")\n .pipe(\n map(({ data }) => data as T)\n )\n\n /* Send and receive messages, return hot observable */\n return tx$\n .pipe(\n throttle(() => rx$, { leading: true, trailing: true }),\n tap(message => worker.postMessage(message)),\n switchMapTo(rx$),\n share()\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { getElementOrThrow, getLocation } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Feature flag\n */\nexport type Flag =\n | \"header.autohide\" /* Hide header */\n | \"navigation.expand\" /* Automatic expansion */\n | \"navigation.instant\" /* Instant loading */\n | \"navigation.indexes\" /* Section pages */\n | \"navigation.sections\" /* Section navigation */\n | \"navigation.tabs\" /* Tabs navigation */\n | \"navigation.tabs.sticky\" /* Tabs navigation (sticky) */\n | \"navigation.top\" /* Back-to-top button */\n | \"search.highlight\" /* Search highlighting */\n | \"search.share\" /* Search sharing */\n | \"search.suggest\" /* Search suggestions */\n | \"toc.integrate\" /* Integrated table of contents */\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Translation\n */\nexport type Translation =\n | \"clipboard.copy\" /* Copy to clipboard */\n | \"clipboard.copied\" /* Copied to clipboard */\n | \"search.config.lang\" /* Search language */\n | \"search.config.pipeline\" /* Search pipeline */\n | \"search.config.separator\" /* Search separator */\n | \"search.placeholder\" /* Search */\n | \"search.result.placeholder\" /* Type to start searching */\n | \"search.result.none\" /* No matching documents */\n | \"search.result.one\" /* 1 matching document */\n | \"search.result.other\" /* # matching documents */\n | \"search.result.more.one\" /* 1 more on this page */\n | \"search.result.more.other\" /* # more on this page */\n | \"search.result.term.missing\" /* Missing */\n | \"select.version.title\" /* Version selector */\n\n/**\n * Translations\n */\nexport type Translations = Record\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Versioning\n */\nexport interface Versioning {\n provider: \"mike\" /* Version provider */\n}\n\n/**\n * Configuration\n */\nexport interface Config {\n base: string /* Base URL */\n features: Flag[] /* Feature flags */\n translations: Translations /* Translations */\n search: string /* Search worker URL */\n version?: Versioning /* Versioning */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve global configuration and make base URL absolute\n */\nconst script = getElementOrThrow(\"#__config\")\nconst config: Config = JSON.parse(script.textContent!)\nconfig.base = `${new URL(config.base, getLocation())}`\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve global configuration\n *\n * @returns Global configuration\n */\nexport function configuration(): Config {\n return config\n}\n\n/**\n * Check whether a feature flag is enabled\n *\n * @param flag - Feature flag\n *\n * @returns Test result\n */\nexport function feature(flag: Flag): boolean {\n return config.features.includes(flag)\n}\n\n/**\n * Retrieve the translation for the given key\n *\n * @param key - Key to be translated\n * @param value - Positional value, if any\n *\n * @returns Translation\n */\nexport function translation(\n key: Translation, value?: string | number\n): string {\n return typeof value !== \"undefined\"\n ? config.translations[key].replace(\"#\", value.toString())\n : config.translations[key]\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { getElementOrThrow, getElements } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Component type\n */\nexport type ComponentType =\n | \"announce\" /* Announcement bar */\n | \"container\" /* Container */\n | \"content\" /* Content */\n | \"dialog\" /* Dialog */\n | \"header\" /* Header */\n | \"header-title\" /* Header title */\n | \"header-topic\" /* Header topic */\n | \"main\" /* Main area */\n | \"palette\" /* Color palette */\n | \"search\" /* Search */\n | \"search-query\" /* Search input */\n | \"search-result\" /* Search results */\n | \"search-share\" /* Search sharing */\n | \"search-suggest\" /* Search suggestions */\n | \"sidebar\" /* Sidebar */\n | \"skip\" /* Skip link */\n | \"source\" /* Repository information */\n | \"tabs\" /* Navigation tabs */\n | \"toc\" /* Table of contents */\n | \"top\" /* Back-to-top button */\n\n/**\n * Component\n *\n * @template T - Component type\n * @template U - Reference type\n */\nexport type Component<\n T extends {} = {},\n U extends HTMLElement = HTMLElement\n> =\n T & {\n ref: U /* Component reference */\n }\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Component type map\n */\ninterface ComponentTypeMap {\n \"announce\": HTMLElement /* Announcement bar */\n \"container\": HTMLElement /* Container */\n \"content\": HTMLElement /* Content */\n \"dialog\": HTMLElement /* Dialog */\n \"header\": HTMLElement /* Header */\n \"header-title\": HTMLElement /* Header title */\n \"header-topic\": HTMLElement /* Header topic */\n \"main\": HTMLElement /* Main area */\n \"palette\": HTMLElement /* Color palette */\n \"search\": HTMLElement /* Search */\n \"search-query\": HTMLInputElement /* Search input */\n \"search-result\": HTMLElement /* Search results */\n \"search-share\": HTMLAnchorElement /* Search sharing */\n \"search-suggest\": HTMLElement /* Search suggestions */\n \"sidebar\": HTMLElement /* Sidebar */\n \"skip\": HTMLAnchorElement /* Skip link */\n \"source\": HTMLAnchorElement /* Repository information */\n \"tabs\": HTMLElement /* Navigation tabs */\n \"toc\": HTMLElement /* Table of contents */\n \"top\": HTMLAnchorElement /* Back-to-top button */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Retrieve the element for a given component or throw a reference error\n *\n * @template T - Component type\n *\n * @param type - Component type\n * @param node - Node of reference\n *\n * @returns Element\n */\nexport function getComponentElement(\n type: T, node: ParentNode = document\n): ComponentTypeMap[T] {\n return getElementOrThrow(`[data-md-component=${type}]`, node)\n}\n\n/**\n * Retrieve all elements for a given component\n *\n * @template T - Component type\n *\n * @param type - Component type\n * @param node - Node of reference\n *\n * @returns Elements\n */\nexport function getComponentElements(\n type: T, node: ParentNode = document\n): ComponentTypeMap[T][] {\n return getElements(`[data-md-component=${type}]`, node)\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ClipboardJS from \"clipboard\"\nimport {\n NEVER,\n Observable,\n Subject,\n fromEvent,\n merge,\n of\n} from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n finalize,\n map,\n switchMap,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport { resetFocusable, setFocusable } from \"~/actions\"\nimport {\n Viewport,\n getElementContentSize,\n getElementSize,\n getElements,\n watchMedia\n} from \"~/browser\"\nimport { renderClipboardButton } from \"~/templates\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Code block\n */\nexport interface CodeBlock {\n scroll: boolean /* Code block overflows */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Global index for Clipboard.js integration\n */\nlet index = 0\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch code block\n *\n * This function monitors size changes of the viewport, as well as switches of\n * content tabs with embedded code blocks, as both may trigger overflow.\n *\n * @param el - Code block element\n * @param options - Options\n *\n * @returns Code block observable\n */\nexport function watchCodeBlock(\n el: HTMLElement, { viewport$ }: WatchOptions\n): Observable {\n const container$ = of(el)\n .pipe(\n switchMap(child => {\n const container = child.closest(\"[data-tabs]\")\n if (container instanceof HTMLElement) {\n return merge(\n ...getElements(\"input\", container)\n .map(input => fromEvent(input, \"change\"))\n )\n }\n return NEVER\n })\n )\n\n /* Check overflow on resize and tab change */\n return merge(\n viewport$.pipe(distinctUntilKeyChanged(\"size\")),\n container$\n )\n .pipe(\n map(() => {\n const visible = getElementSize(el)\n const content = getElementContentSize(el)\n return {\n scroll: content.width > visible.width\n }\n }),\n distinctUntilKeyChanged(\"scroll\")\n )\n}\n\n/**\n * Mount code block\n *\n * This function ensures that an overflowing code block is focusable through\n * keyboard, so it can be scrolled without a mouse to improve on accessibility.\n *\n * @param el - Code block element\n * @param options - Options\n *\n * @returns Code block component observable\n */\nexport function mountCodeBlock(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n withLatestFrom(watchMedia(\"(hover)\"))\n )\n .subscribe(([{ scroll }, hover]) => {\n if (scroll && hover)\n setFocusable(el)\n else\n resetFocusable(el)\n })\n\n /* Render button for Clipboard.js integration */\n if (ClipboardJS.isSupported()) {\n const parent = el.closest(\"pre\")!\n parent.id = `__code_${index++}`\n parent.insertBefore(\n renderClipboardButton(parent.id),\n el\n )\n }\n\n /* Create and return component */\n return watchCodeBlock(el, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set focusable property\n *\n * @param el - Element\n * @param value - Tabindex value\n */\nexport function setFocusable(\n el: HTMLElement, value = 0\n): void {\n el.setAttribute(\"tabindex\", value.toString())\n}\n\n/**\n * Reset focusable property\n *\n * @param el - Element\n */\nexport function resetFocusable(\n el: HTMLElement\n): void {\n el.removeAttribute(\"tabindex\")\n}\n\n/**\n * Set scroll lock\n *\n * @param el - Scrollable element\n * @param value - Vertical offset\n */\nexport function setScrollLock(\n el: HTMLElement, value: number\n): void {\n el.setAttribute(\"data-md-state\", \"lock\")\n el.style.top = `-${value}px`\n}\n\n/**\n * Reset scroll lock\n *\n * @param el - Scrollable element\n */\nexport function resetScrollLock(\n el: HTMLElement\n): void {\n const value = -1 * parseInt(el.style.top, 10)\n el.removeAttribute(\"data-md-state\")\n el.style.top = \"\"\n if (value)\n window.scrollTo(0, value)\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set anchor state\n *\n * @param el - Anchor element\n * @param state - Anchor state\n */\nexport function setAnchorState(\n el: HTMLElement, state: \"blur\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset anchor state\n *\n * @param el - Anchor element\n */\nexport function resetAnchorState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set anchor active\n *\n * @param el - Anchor element\n * @param value - Whether the anchor is active\n */\nexport function setAnchorActive(\n el: HTMLElement, value: boolean\n): void {\n el.classList.toggle(\"md-nav__link--active\", value)\n}\n\n/**\n * Reset anchor active\n *\n * @param el - Anchor element\n */\nexport function resetAnchorActive(\n el: HTMLElement\n): void {\n el.classList.remove(\"md-nav__link--active\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set dialog message\n *\n * @param el - Dialog element\n * @param value - Dialog message\n */\nexport function setDialogMessage(\n el: HTMLElement, value: string\n): void {\n el.firstElementChild!.innerHTML = value\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set dialog state\n *\n * @param el - Dialog element\n * @param state - Dialog state\n */\nexport function setDialogState(\n el: HTMLElement, state: \"open\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset dialog state\n *\n * @param el - Dialog element\n */\nexport function resetDialogState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set header state\n *\n * @param el - Header element\n * @param state - Header state\n */\nexport function setHeaderState(\n el: HTMLElement, state: \"shadow\" | \"hidden\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset header state\n *\n * @param el - Header element\n */\nexport function resetHeaderState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set header title state\n *\n * @param el - Header title element\n * @param state - Header title state\n */\nexport function setHeaderTitleState(\n el: HTMLElement, state: \"active\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset header title state\n *\n * @param el - Header title element\n */\nexport function resetHeaderTitleState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set search query placeholder\n *\n * @param el - Search query element\n * @param value - Placeholder\n */\nexport function setSearchQueryPlaceholder(\n el: HTMLInputElement, value: string\n): void {\n el.placeholder = value\n}\n\n/**\n * Reset search query placeholder\n *\n * @param el - Search query element\n */\nexport function resetSearchQueryPlaceholder(\n el: HTMLInputElement\n): void {\n el.placeholder = translation(\"search.placeholder\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\nimport { round } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set number of search results\n *\n * @param el - Search result metadata element\n * @param value - Number of results\n */\nexport function setSearchResultMeta(\n el: HTMLElement, value: number\n): void {\n switch (value) {\n\n /* No results */\n case 0:\n el.textContent = translation(\"search.result.none\")\n break\n\n /* One result */\n case 1:\n el.textContent = translation(\"search.result.one\")\n break\n\n /* Multiple result */\n default:\n el.textContent = translation(\"search.result.other\", round(value))\n }\n}\n\n/**\n * Reset number of search results\n *\n * @param el - Search result metadata element\n */\nexport function resetSearchResultMeta(\n el: HTMLElement\n): void {\n el.textContent = translation(\"search.result.placeholder\")\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Add an element to the search result list\n *\n * @param el - Search result list element\n * @param child - Search result element\n */\nexport function addToSearchResultList(\n el: HTMLElement, child: Element\n): void {\n el.appendChild(child)\n}\n\n/**\n * Reset search result list\n *\n * @param el - Search result list element\n */\nexport function resetSearchResultList(\n el: HTMLElement\n): void {\n el.innerHTML = \"\"\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set sidebar offset\n *\n * @param el - Sidebar element\n * @param value - Sidebar offset\n */\nexport function setSidebarOffset(\n el: HTMLElement, value: number\n): void {\n el.style.top = `${value}px`\n}\n\n/**\n * Reset sidebar offset\n *\n * @param el - Sidebar element\n */\nexport function resetSidebarOffset(\n el: HTMLElement\n): void {\n el.style.top = \"\"\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set sidebar height\n *\n * This function doesn't set the height of the actual sidebar, but of its first\n * child \u2013 the `.md-sidebar__scrollwrap` element in order to mitigiate jittery\n * sidebars when the footer is scrolled into view. At some point we switched\n * from `absolute` / `fixed` positioning to `sticky` positioning, significantly\n * reducing jitter in some browsers (respectively Firefox and Safari) when\n * scrolling from the top. However, top-aligned sticky positioning means that\n * the sidebar snaps to the bottom when the end of the container is reached.\n * This is what leads to the mentioned jitter, as the sidebar's height may be\n * updated too slowly.\n *\n * This behaviour can be mitigiated by setting the height of the sidebar to `0`\n * while preserving the padding, and the height on its first element.\n *\n * @param el - Sidebar element\n * @param value - Sidebar height\n */\nexport function setSidebarHeight(\n el: HTMLElement, value: number\n): void {\n const scrollwrap = el.firstElementChild as HTMLElement\n scrollwrap.style.height = `${value - 2 * scrollwrap.offsetTop}px`\n}\n\n/**\n * Reset sidebar height\n *\n * @param el - Sidebar element\n */\nexport function resetSidebarHeight(\n el: HTMLElement\n): void {\n const scrollwrap = el.firstElementChild as HTMLElement\n scrollwrap.style.height = \"\"\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set repository facts\n *\n * @param el - Repository element\n * @param child - Repository facts element\n */\nexport function setSourceFacts(\n el: HTMLElement, child: Element\n): void {\n el.lastElementChild!.appendChild(child)\n}\n\n/**\n * Set repository state\n *\n * @param el - Repository element\n * @param state - Repository state\n */\nexport function setSourceState(\n el: HTMLElement, state: \"done\"\n): void {\n el.lastElementChild!.setAttribute(\"data-md-state\", state)\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set tabs state\n *\n * @param el - Tabs element\n * @param state - Tabs state\n */\nexport function setTabsState(\n el: HTMLElement, state: \"hidden\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset tabs state\n *\n * @param el - Tabs element\n */\nexport function resetTabsState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set back-to-top state\n *\n * @param el - Back-to-top element\n * @param state - Back-to-top state\n */\nexport function setBackToTopState(\n el: HTMLElement, state: \"hidden\"\n): void {\n el.setAttribute(\"data-md-state\", state)\n}\n\n/**\n * Reset back-to-top state\n *\n * @param el - Back-to-top element\n */\nexport function resetBackToTopState(\n el: HTMLElement\n): void {\n el.removeAttribute(\"data-md-state\")\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Set back-to-top offset\n *\n * @param el - Back-to-top element\n * @param value - Back-to-top offset\n */\nexport function setBackToTopOffset(\n el: HTMLElement, value: number\n): void {\n el.style.top = `${value}px`\n}\n\n/**\n * Reset back-to-top offset\n *\n * @param el - Back-to-top element\n */\nexport function resetBackToTopOffset(\n el: HTMLElement\n): void {\n el.style.top = \"\"\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { translation } from \"~/_\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a 'copy-to-clipboard' button\n *\n * @param id - Unique identifier\n *\n * @returns Element\n */\nexport function renderClipboardButton(id: string): HTMLElement {\n return (\n code`}\n >\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { feature, translation } from \"~/_\"\nimport {\n SearchDocument,\n SearchMetadata,\n SearchResultItem\n} from \"~/integrations/search\"\nimport { h, truncate } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Render flag\n */\nconst enum Flag {\n TEASER = 1, /* Render teaser */\n PARENT = 2 /* Render as parent */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper function\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a search document\n *\n * @param document - Search document\n * @param flag - Render flags\n *\n * @returns Element\n */\nfunction renderSearchDocument(\n document: SearchDocument & SearchMetadata, flag: Flag\n): HTMLElement {\n const parent = flag & Flag.PARENT\n const teaser = flag & Flag.TEASER\n\n /* Render missing query terms */\n const missing = Object.keys(document.terms)\n .filter(key => !document.terms[key])\n .map(key => [{key}, \" \"])\n .flat()\n .slice(0, -1)\n\n /* Assemble query string for highlighting */\n const url = new URL(document.location)\n if (feature(\"search.highlight\"))\n url.searchParams.set(\"h\", Object.entries(document.terms)\n .filter(([, match]) => match)\n .reduce((highlight, [value]) => `${highlight} ${value}`.trim(), \"\")\n )\n\n /* Render article or section, depending on flags */\n return (\n \n \n {parent > 0 &&
    }\n

    {document.title}

    \n {teaser > 0 && document.text.length > 0 &&\n

    \n {truncate(document.text, 320)}\n

    \n }\n {teaser > 0 && missing.length > 0 &&\n

    \n {translation(\"search.result.term.missing\")}: {...missing}\n

    \n }\n \n
    \n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a search result\n *\n * @param result - Search result\n *\n * @returns Element\n */\nexport function renderSearchResultItem(\n result: SearchResultItem\n): HTMLElement {\n const threshold = result[0].score\n const docs = [...result]\n\n /* Find and extract parent article */\n const parent = docs.findIndex(doc => !doc.location.includes(\"#\"))\n const [article] = docs.splice(parent, 1)\n\n /* Determine last index above threshold */\n let index = docs.findIndex(doc => doc.score < threshold)\n if (index === -1)\n index = docs.length\n\n /* Partition sections */\n const best = docs.slice(0, index)\n const more = docs.slice(index)\n\n /* Render children */\n const children = [\n renderSearchDocument(article, Flag.PARENT | +(!parent && index === 0)),\n ...best.map(section => renderSearchDocument(section, Flag.TEASER)),\n ...more.length ? [\n
    \n \n {more.length > 0 && more.length === 1\n ? translation(\"search.result.more.one\")\n : translation(\"search.result.more.other\", more.length)\n }\n \n {...more.map(section => renderSearchDocument(section, Flag.TEASER))}\n
    \n ] : []\n ]\n\n /* Render search result */\n return (\n
  • \n {children}\n
  • \n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SourceFacts } from \"~/components\"\nimport { h, round } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render repository facts\n *\n * @param facts - Repository facts\n *\n * @returns Element\n */\nexport function renderSourceFacts(facts: SourceFacts): HTMLElement {\n return (\n
      \n {Object.entries(facts).map(([key, value]) => (\n
    • \n {typeof value === \"number\" ? round(value) : value}\n
    • \n ))}\n
    \n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a table inside a wrapper to improve scrolling on mobile\n *\n * @param table - Table element\n *\n * @returns Element\n */\nexport function renderTable(table: HTMLElement): HTMLElement {\n return (\n
    \n
    \n {table}\n
    \n
    \n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { configuration, translation } from \"~/_\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Version\n */\nexport interface Version {\n version: string /* Version identifier */\n title: string /* Version title */\n aliases: string[] /* Version aliases */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a version\n *\n * @param version - Version\n *\n * @returns Element\n */\nfunction renderVersion(version: Version): HTMLElement {\n const config = configuration()\n\n /* Ensure trailing slash, see https://bit.ly/3rL5u3f */\n const url = new URL(`../${version.version}/`, config.base)\n return (\n
  • \n \n {version.title}\n \n
  • \n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Render a version selector\n *\n * @param versions - Versions\n *\n * @returns Element\n */\nexport function renderVersionSelector(versions: Version[]): HTMLElement {\n const config = configuration()\n\n /* Determine active version */\n const [, current] = config.base.match(/([^/]+)\\/?$/)!\n const active =\n versions.find(({ version, aliases }) => (\n version === current || aliases.includes(current)\n )) || versions[0]\n\n /* Render version selector */\n return (\n
    \n \n {active.title}\n \n
      \n {versions.map(renderVersion)}\n
    \n
    \n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, Subject } from \"rxjs\"\nimport {\n filter,\n finalize,\n map,\n mapTo,\n mergeWith,\n tap\n} from \"rxjs/operators\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Details\n */\nexport interface Details {\n scroll?: boolean /* Scroll into view */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Print mode observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n target$: Observable /* Location target observable */\n print$: Observable /* Print mode observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch details\n *\n * @param el - Details element\n * @param options - Options\n *\n * @returns Details observable\n */\nexport function watchDetails(\n el: HTMLDetailsElement, { target$, print$ }: WatchOptions\n): Observable
    {\n return target$\n .pipe(\n map(target => target.closest(\"details:not([open])\")!),\n filter(details => el === details),\n mapTo({ scroll: true }),\n mergeWith(print$.pipe(mapTo({})))\n )\n}\n\n/**\n * Mount details\n *\n * This function ensures that `details` tags are opened on anchor jumps and\n * prior to printing, so the whole content of the page is visible.\n *\n * @param el - Details element\n * @param options - Options\n *\n * @returns Details component observable\n */\nexport function mountDetails(\n el: HTMLDetailsElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject
    ()\n internal$.subscribe(({ scroll }) => {\n el.setAttribute(\"open\", \"\")\n if (scroll)\n el.scrollIntoView()\n })\n\n /* Create and return component */\n return watchDetails(el, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n mapTo({ ref: el })\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, of } from \"rxjs\"\n\nimport { replaceElement } from \"~/browser\"\nimport { renderTable } from \"~/templates\"\nimport { h } from \"~/utilities\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Data table\n */\nexport interface DataTable {}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Sentinel for replacement\n */\nconst sentinel = h(\"table\")\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount data table\n *\n * This function wraps a data table in another scrollable container, so it can\n * be smoothly scrolled on smaller screen sizes and won't break the layout.\n *\n * @param el - Data table element\n *\n * @returns Data table component observable\n */\nexport function mountDataTable(\n el: HTMLElement\n): Observable> {\n replaceElement(el, sentinel)\n replaceElement(sentinel, renderTable(el))\n\n /* Create and return component */\n return of({ ref: el })\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { NEVER, Observable, Subject, fromEvent, merge } from \"rxjs\"\nimport { finalize, map, mapTo, tap } from \"rxjs/operators\"\n\nimport { getElementOrThrow, getElements } from \"~/browser\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Content tabs\n */\nexport interface ContentTabs {\n active: HTMLLabelElement /* Active tab label */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch content tabs\n *\n * @param el - Content tabs element\n *\n * @returns Content tabs observable\n */\nexport function watchContentTabs(\n el: HTMLElement\n): Observable {\n if (!el.classList.contains(\"tabbed-alternate\"))\n return NEVER\n else\n return merge(...getElements(\":scope > input\", el)\n .map(input => fromEvent(input, \"change\").pipe(mapTo(input.id)))\n )\n .pipe(\n map(id => ({\n active: getElementOrThrow(`label[for=${id}]`)\n }))\n )\n}\n\n/**\n * Mount content tabs\n *\n * @param el - Content tabs element\n *\n * @returns Content tabs component observable\n */\nexport function mountContentTabs(\n el: HTMLElement\n): Observable> {\n const internal$ = new Subject()\n internal$.subscribe(({ active }) => {\n // TODO: Hack, scrollIntoView is too buggy\n const container = active.parentElement!\n if (\n active.offsetLeft + active.offsetWidth > container.scrollLeft + container.offsetWidth ||\n active.offsetLeft < container.scrollLeft\n )\n container.scrollTo({\n behavior: \"smooth\",\n left: active.offsetLeft\n })\n })\n\n /* Create and return component */\n return watchContentTabs(el)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, merge } from \"rxjs\"\n\nimport { Viewport, getElements } from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { CodeBlock, mountCodeBlock } from \"../code\"\nimport { Details, mountDetails } from \"../details\"\nimport { DataTable, mountDataTable } from \"../table\"\nimport { ContentTabs, mountContentTabs } from \"../tabs\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Content\n */\nexport type Content =\n | ContentTabs\n | CodeBlock\n | DataTable\n | Details\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n target$: Observable /* Location target observable */\n viewport$: Observable /* Viewport observable */\n print$: Observable /* Print mode observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount content\n *\n * This function mounts all components that are found in the content of the\n * actual article, including code blocks, data tables and details.\n *\n * @param el - Content element\n * @param options - Options\n *\n * @returns Content component observable\n */\nexport function mountContent(\n el: HTMLElement, { target$, viewport$, print$ }: MountOptions\n): Observable> {\n return merge(\n\n /* Code blocks */\n ...getElements(\"pre > code\", el)\n .map(child => mountCodeBlock(child, { viewport$ })),\n\n /* Data tables */\n ...getElements(\"table:not([class])\", el)\n .map(child => mountDataTable(child)),\n\n /* Details */\n ...getElements(\"details\", el)\n .map(child => mountDetails(child, { target$, print$ })),\n\n /* Content tabs */\n ...getElements(\"[data-tabs]\", el)\n .map(child => mountContentTabs(child))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n merge,\n of\n} from \"rxjs\"\nimport {\n delay,\n finalize,\n map,\n observeOn,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetDialogState,\n setDialogMessage,\n setDialogState\n} from \"~/actions\"\n\nimport { Component } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Dialog\n */\nexport interface Dialog {\n message: string /* Dialog message */\n open: boolean /* Dialog is visible */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n alert$: Subject /* Alert subject */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n alert$: Subject /* Alert subject */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch dialog\n *\n * @param _el - Dialog element\n * @param options - Options\n *\n * @returns Dialog observable\n */\nexport function watchDialog(\n _el: HTMLElement, { alert$ }: WatchOptions\n): Observable {\n return alert$\n .pipe(\n switchMap(message => merge(\n of(true),\n of(false).pipe(delay(2000))\n )\n .pipe(\n map(open => ({ message, open }))\n )\n )\n )\n}\n\n/**\n * Mount dialog\n *\n * This function reveals the dialog in the right cornerwhen a new alert is\n * emitted through the subject that is passed as part of the options.\n *\n * @param el - Dialog element\n * @param options - Options\n *\n * @returns Dialog component observable\n */\nexport function mountDialog(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler)\n )\n .subscribe(({ message, open }) => {\n setDialogMessage(el, message)\n if (open)\n setDialogState(el, \"open\")\n else\n resetDialogState(el)\n })\n\n /* Create and return component */\n return watchDialog(el, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest,\n defer,\n of\n} from \"rxjs\"\nimport {\n bufferCount,\n combineLatestWith,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n filter,\n map,\n observeOn,\n shareReplay,\n startWith,\n switchMap\n} from \"rxjs/operators\"\n\nimport { feature } from \"~/_\"\nimport { resetHeaderState, setHeaderState } from \"~/actions\"\nimport {\n Viewport,\n watchElementSize,\n watchToggle\n} from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Main } from \"../../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Header\n */\nexport interface Header {\n height: number /* Header visible height */\n sticky: boolean /* Header stickyness */\n hidden: boolean /* User scrolled past threshold */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Compute whether the header is hidden\n *\n * If the user scrolls past a certain threshold, the header can be hidden when\n * scrolling down, and shown when scrolling up.\n *\n * @param options - Options\n *\n * @returns Toggle observable\n */\nfunction isHidden({ viewport$ }: WatchOptions): Observable {\n if (!feature(\"header.autohide\"))\n return of(false)\n\n /* Compute direction and turning point */\n const direction$ = viewport$\n .pipe(\n map(({ offset: { y } }) => y),\n bufferCount(2, 1),\n map(([a, b]) => [a < b, b] as const),\n distinctUntilKeyChanged(0)\n )\n\n /* Compute whether header should be hidden */\n const hidden$ = combineLatest([viewport$, direction$])\n .pipe(\n filter(([{ offset }, [, y]]) => Math.abs(y - offset.y) > 100),\n map(([, [direction]]) => direction),\n distinctUntilChanged()\n )\n\n /* Compute threshold for hiding */\n const search$ = watchToggle(\"search\")\n return combineLatest([viewport$, search$])\n .pipe(\n map(([{ offset }, search]) => offset.y > 400 && !search),\n distinctUntilChanged(),\n switchMap(active => active ? hidden$ : of(false)),\n startWith(false)\n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch header\n *\n * @param el - Header element\n * @param options - Options\n *\n * @returns Header observable\n */\nexport function watchHeader(\n el: HTMLElement, options: WatchOptions\n): Observable
    {\n return defer(() => {\n const styles = getComputedStyle(el)\n return of(\n styles.position === \"sticky\" ||\n styles.position === \"-webkit-sticky\"\n )\n })\n .pipe(\n combineLatestWith(watchElementSize(el), isHidden(options)),\n map(([sticky, { height }, hidden]) => ({\n height: sticky ? height : 0,\n sticky,\n hidden\n })),\n distinctUntilChanged((a, b) => (\n a.sticky === b.sticky &&\n a.height === b.height &&\n a.hidden === b.hidden\n )),\n shareReplay(1)\n )\n}\n\n/**\n * Mount header\n *\n * This function manages the different states of the header, i.e. whether it's\n * hidden or rendered with a shadow. This depends heavily on the main area.\n *\n * @param el - Header element\n * @param options - Options\n *\n * @returns Header component observable\n */\nexport function mountHeader(\n el: HTMLElement, { header$, main$ }: MountOptions\n): Observable> {\n const internal$ = new Subject
    ()\n internal$\n .pipe(\n distinctUntilKeyChanged(\"active\"),\n combineLatestWith(header$),\n observeOn(animationFrameScheduler)\n )\n .subscribe(([{ active }, { hidden }]) => {\n if (active)\n setHeaderState(el, hidden ? \"hidden\" : \"shadow\")\n else\n resetHeaderState(el)\n })\n\n /* Connect to long-living subject and return component */\n main$.subscribe(main => internal$.next(main))\n return header$\n .pipe(\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n NEVER,\n Observable,\n Subject,\n animationFrameScheduler\n} from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetHeaderTitleState,\n setHeaderTitleState\n} from \"~/actions\"\nimport {\n Viewport,\n getElement,\n getElementSize,\n watchViewportAt\n} from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { Header } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Header\n */\nexport interface HeaderTitle {\n active: boolean /* User scrolled past first headline */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch header title\n *\n * @param el - Heading element\n * @param options - Options\n *\n * @returns Header title observable\n */\nexport function watchHeaderTitle(\n el: HTMLHeadingElement, { viewport$, header$ }: WatchOptions\n): Observable {\n return watchViewportAt(el, { header$, viewport$ })\n .pipe(\n map(({ offset: { y } }) => {\n const { height } = getElementSize(el)\n return {\n active: y >= height\n }\n }),\n distinctUntilKeyChanged(\"active\")\n )\n}\n\n/**\n * Mount header title\n *\n * This function swaps the header title from the site title to the title of the\n * current page when the user scrolls past the first headline.\n *\n * @param el - Header title element\n * @param options - Options\n *\n * @returns Header title component observable\n */\nexport function mountHeaderTitle(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler)\n )\n .subscribe(({ active }) => {\n if (active)\n setHeaderTitleState(el, \"active\")\n else\n resetHeaderTitleState(el)\n })\n\n /* Obtain headline, if any */\n const headline = getElement(\"article h1\")\n if (typeof headline === \"undefined\")\n return NEVER\n\n /* Create and return component */\n return watchHeaderTitle(headline, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n combineLatest\n} from \"rxjs\"\nimport {\n distinctUntilChanged,\n distinctUntilKeyChanged,\n map,\n switchMap\n} from \"rxjs/operators\"\n\nimport { Viewport, watchElementSize } from \"~/browser\"\n\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Main area\n */\nexport interface Main {\n offset: number /* Main area top offset */\n height: number /* Main area visible height */\n active: boolean /* User scrolled past header */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch main area\n *\n * This function returns an observable that computes the visual parameters of\n * the main area which depends on the viewport vertical offset and height, as\n * well as the height of the header element, if the header is fixed.\n *\n * @param el - Main area element\n * @param options - Options\n *\n * @returns Main area observable\n */\nexport function watchMain(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable
    {\n\n /* Compute necessary adjustment for header */\n const adjust$ = header$\n .pipe(\n map(({ height }) => height),\n distinctUntilChanged()\n )\n\n /* Compute the main area's top and bottom borders */\n const border$ = adjust$\n .pipe(\n switchMap(() => watchElementSize(el)\n .pipe(\n map(({ height }) => ({\n top: el.offsetTop,\n bottom: el.offsetTop + height\n })),\n distinctUntilKeyChanged(\"bottom\")\n )\n )\n )\n\n /* Compute the main area's offset, visible height and if we scrolled past */\n return combineLatest([adjust$, border$, viewport$])\n .pipe(\n map(([header, { top, bottom }, { offset: { y }, size: { height } }]) => {\n height = Math.max(0, height\n - Math.max(0, top - y, header)\n - Math.max(0, height + y - bottom)\n )\n return {\n offset: top - header,\n height,\n active: top - header <= y\n }\n }),\n distinctUntilChanged((a, b) => (\n a.offset === b.offset &&\n a.height === b.height &&\n a.active === b.active\n ))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n fromEvent,\n of\n} from \"rxjs\"\nimport {\n finalize,\n map,\n mapTo,\n mergeMap,\n shareReplay,\n startWith,\n tap\n} from \"rxjs/operators\"\n\nimport { getElements } from \"~/browser\"\n\nimport { Component } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Palette colors\n */\nexport interface PaletteColor {\n scheme?: string /* Color scheme */\n primary?: string /* Primary color */\n accent?: string /* Accent color */\n}\n\n/**\n * Palette\n */\nexport interface Palette {\n index: number /* Palette index */\n color: PaletteColor /* Palette colors */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch color palette\n *\n * @param inputs - Color palette element\n *\n * @returns Color palette observable\n */\nexport function watchPalette(\n inputs: HTMLInputElement[]\n): Observable {\n const data = localStorage.getItem(__prefix(\"__palette\"))!\n const current = JSON.parse(data) || {\n index: inputs.findIndex(input => (\n matchMedia(input.getAttribute(\"data-md-color-media\")!).matches\n ))\n }\n\n /* Emit changes in color palette */\n const palette$ = of(...inputs)\n .pipe(\n mergeMap(input => fromEvent(input, \"change\")\n .pipe(\n mapTo(input)\n )\n ),\n startWith(inputs[Math.max(0, current.index)]),\n map(input => ({\n index: inputs.indexOf(input),\n color: {\n scheme: input.getAttribute(\"data-md-color-scheme\"),\n primary: input.getAttribute(\"data-md-color-primary\"),\n accent: input.getAttribute(\"data-md-color-accent\")\n }\n } as Palette)),\n shareReplay(1)\n )\n\n /* Persist preference in local storage */\n palette$.subscribe(palette => {\n localStorage.setItem(__prefix(\"__palette\"), JSON.stringify(palette))\n })\n\n /* Return palette */\n return palette$\n}\n\n/**\n * Mount color palette\n *\n * @param el - Color palette element\n *\n * @returns Color palette component observable\n */\nexport function mountPalette(\n el: HTMLElement\n): Observable> {\n const internal$ = new Subject()\n\n /* Set color palette */\n internal$.subscribe(palette => {\n for (const [key, value] of Object.entries(palette.color))\n if (typeof value === \"string\")\n document.body.setAttribute(`data-md-color-${key}`, value)\n\n /* Toggle visibility */\n for (let index = 0; index < inputs.length; index++) {\n const label = inputs[index].nextElementSibling\n if (label instanceof HTMLElement)\n label.hidden = palette.index !== index\n }\n })\n\n /* Create and return component */\n const inputs = getElements(\"input\", el)\n return watchPalette(inputs)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport ClipboardJS from \"clipboard\"\nimport { Observable, Subject } from \"rxjs\"\n\nimport { translation } from \"~/_\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Setup options\n */\ninterface SetupOptions {\n alert$: Subject /* Alert subject */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up Clipboard.js integration\n *\n * @param options - Options\n */\nexport function setupClipboardJS(\n { alert$ }: SetupOptions\n): void {\n if (ClipboardJS.isSupported()) {\n new Observable(subscriber => {\n new ClipboardJS(\"[data-clipboard-target], [data-clipboard-text]\")\n .on(\"success\", ev => subscriber.next(ev))\n })\n .subscribe(() => alert$.next(translation(\"clipboard.copied\")))\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n fromEvent,\n merge,\n of\n} from \"rxjs\"\nimport {\n bufferCount,\n catchError,\n concatMap,\n debounceTime,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n filter,\n map,\n sample,\n share,\n skip,\n skipUntil,\n switchMap\n} from \"rxjs/operators\"\n\nimport { configuration, feature } from \"~/_\"\nimport {\n Viewport,\n ViewportOffset,\n getElement,\n getElements,\n replaceElement,\n request,\n requestXML,\n setLocation,\n setLocationHash,\n setViewportOffset\n} from \"~/browser\"\nimport { getComponentElement } from \"~/components\"\nimport { h } from \"~/utilities\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * History state\n */\nexport interface HistoryState {\n url: URL /* State URL */\n offset?: ViewportOffset /* State viewport offset */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Setup options\n */\ninterface SetupOptions {\n document$: Subject /* Document subject */\n location$: Subject /* Location subject */\n viewport$: Observable /* Viewport observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Preprocess a list of URLs\n *\n * This function replaces the `site_url` in the sitemap with the actual base\n * URL, to allow instant loading to work in occasions like Netlify previews.\n *\n * @param urls - URLs\n *\n * @returns Processed URLs\n */\nfunction preprocess(urls: string[]): string[] {\n if (urls.length < 2)\n return urls\n\n /* Take the first two URLs and remove everything after the last slash */\n const [root, next] = urls\n .sort((a, b) => a.length - b.length)\n .map(url => url.replace(/[^/]+$/, \"\"))\n\n /* Compute common prefix */\n let index = 0\n if (root === next)\n index = root.length\n else\n while (root.charCodeAt(index) === next.charCodeAt(index))\n index++\n\n /* Replace common prefix (i.e. base) with effective base */\n const config = configuration()\n return urls.map(url => (\n url.replace(root.slice(0, index), config.base)\n ))\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up instant loading\n *\n * When fetching, theoretically, we could use `responseType: \"document\"`, but\n * since all MkDocs links are relative, we need to make sure that the current\n * location matches the document we just loaded. Otherwise any relative links\n * in the document could use the old location.\n *\n * This is the reason why we need to synchronize history events and the process\n * of fetching the document for navigation changes (except `popstate` events):\n *\n * 1. Fetch document via `XMLHTTPRequest`\n * 2. Set new location via `history.pushState`\n * 3. Parse and emit fetched document\n *\n * For `popstate` events, we must not use `history.pushState`, or the forward\n * history will be irreversibly overwritten. In case the request fails, the\n * location change is dispatched regularly.\n *\n * @param options - Options\n */\nexport function setupInstantLoading(\n { document$, location$, viewport$ }: SetupOptions\n): void {\n const config = configuration()\n if (location.protocol === \"file:\")\n return\n\n /* Disable automatic scroll restoration */\n if (\"scrollRestoration\" in history) {\n history.scrollRestoration = \"manual\"\n\n /* Hack: ensure that reloads restore viewport offset */\n fromEvent(window, \"beforeunload\")\n .subscribe(() => {\n history.scrollRestoration = \"auto\"\n })\n }\n\n /* Hack: ensure absolute favicon link to omit 404s when switching */\n const favicon = getElement(\"link[rel=icon]\")\n if (typeof favicon !== \"undefined\")\n favicon.href = favicon.href\n\n /* Intercept internal navigation */\n const push$ = requestXML(new URL(\"sitemap.xml\", config.base))\n .pipe(\n map(sitemap => preprocess(getElements(\"loc\", sitemap)\n .map(node => node.textContent!)\n )),\n switchMap(urls => fromEvent(document.body, \"click\")\n .pipe(\n filter(ev => !ev.metaKey && !ev.ctrlKey),\n switchMap(ev => {\n\n /* Handle HTML and SVG elements */\n if (ev.target instanceof Element) {\n const el = ev.target.closest(\"a\")\n if (el && !el.target) {\n const url = new URL(el.href)\n\n /* Canonicalize URL */\n url.search = \"\"\n url.hash = \"\"\n\n /* Check if URL should be intercepted */\n if (\n url.pathname !== location.pathname &&\n urls.includes(url.toString())\n ) {\n ev.preventDefault()\n return of({\n url: new URL(el.href)\n })\n }\n }\n }\n return NEVER\n })\n )\n ),\n share()\n )\n\n /* Intercept history back and forward */\n const pop$ = fromEvent(window, \"popstate\")\n .pipe(\n filter(ev => ev.state !== null),\n map(ev => ({\n url: new URL(location.href),\n offset: ev.state\n })),\n share()\n )\n\n /* Emit location change */\n merge(push$, pop$)\n .pipe(\n distinctUntilChanged((a, b) => a.url.href === b.url.href),\n map(({ url }) => url)\n )\n .subscribe(location$)\n\n /* Fetch document via `XMLHTTPRequest` */\n const response$ = location$\n .pipe(\n distinctUntilKeyChanged(\"pathname\"),\n switchMap(url => request(url.href)\n .pipe(\n catchError(() => {\n setLocation(url)\n return NEVER\n })\n )\n ),\n share()\n )\n\n /* Set new location via `history.pushState` */\n push$\n .pipe(\n sample(response$)\n )\n .subscribe(({ url }) => {\n history.pushState({}, \"\", `${url}`)\n })\n\n /* Parse and emit fetched document */\n const dom = new DOMParser()\n response$\n .pipe(\n switchMap(res => res.text()),\n map(res => dom.parseFromString(res, \"text/html\"))\n )\n .subscribe(document$)\n\n /* Replace meta tags and components */\n document$\n .pipe(\n skip(1)\n )\n .subscribe(replacement => {\n for (const selector of [\n\n /* Meta tags */\n \"title\",\n \"link[rel=canonical]\",\n \"meta[name=author]\",\n \"meta[name=description]\",\n\n /* Components */\n \"[data-md-component=announce]\",\n \"[data-md-component=container]\",\n \"[data-md-component=header-topic]\",\n \"[data-md-component=logo], .md-logo\", // compat\n \"[data-md-component=skip]\",\n ...feature(\"navigation.tabs.sticky\")\n ? [\"[data-md-component=tabs]\"]\n : []\n ]) {\n const source = getElement(selector)\n const target = getElement(selector, replacement)\n if (\n typeof source !== \"undefined\" &&\n typeof target !== \"undefined\"\n ) {\n replaceElement(source, target)\n }\n }\n })\n\n /* Re-evaluate scripts */\n document$\n .pipe(\n skip(1),\n map(() => getComponentElement(\"container\")),\n switchMap(el => of(...getElements(\"script\", el))),\n concatMap(el => {\n const script = h(\"script\")\n if (el.src) {\n for (const name of el.getAttributeNames())\n script.setAttribute(name, el.getAttribute(name)!)\n replaceElement(el, script)\n\n /* Complete when script is loaded */\n return new Observable(observer => {\n script.onload = () => observer.complete()\n })\n\n /* Complete immediately */\n } else {\n script.textContent = el.textContent\n replaceElement(el, script)\n return EMPTY\n }\n })\n )\n .subscribe()\n\n /* Emit history state change */\n merge(push$, pop$)\n .pipe(\n sample(document$),\n )\n .subscribe(({ url, offset }) => {\n if (url.hash && !offset) {\n setLocationHash(url.hash)\n } else {\n setViewportOffset(offset || { y: 0 })\n }\n })\n\n /* Debounce update of viewport offset */\n viewport$\n .pipe(\n skipUntil(push$),\n debounceTime(250),\n distinctUntilKeyChanged(\"offset\")\n )\n .subscribe(({ offset }) => {\n history.replaceState(offset, \"\")\n })\n\n /* Set viewport offset from history */\n merge(push$, pop$)\n .pipe(\n bufferCount(2, 1),\n filter(([a, b]) => a.url.pathname === b.url.pathname),\n map(([, state]) => state)\n )\n .subscribe(({ offset }) => {\n setViewportOffset(offset || { y: 0 })\n })\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexDocument } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search document\n */\nexport interface SearchDocument extends SearchIndexDocument {\n parent?: SearchIndexDocument /* Parent article */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search document mapping\n */\nexport type SearchDocumentMap = Map\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search document mapping\n *\n * @param docs - Search index documents\n *\n * @returns Search document map\n */\nexport function setupSearchDocumentMap(\n docs: SearchIndexDocument[]\n): SearchDocumentMap {\n const documents = new Map()\n const parents = new Set()\n for (const doc of docs) {\n const [path, hash] = doc.location.split(\"#\")\n\n /* Extract location and title */\n const location = doc.location\n const title = doc.title\n\n /* Escape and cleanup text */\n const text = escapeHTML(doc.text)\n .replace(/\\s+(?=[,.:;!?])/g, \"\")\n .replace(/\\s+/g, \" \")\n\n /* Handle section */\n if (hash) {\n const parent = documents.get(path)!\n\n /* Ignore first section, override article */\n if (!parents.has(parent)) {\n parent.title = doc.title\n parent.text = text\n\n /* Remember that we processed the article */\n parents.add(parent)\n\n /* Add subsequent section */\n } else {\n documents.set(location, {\n location,\n title,\n text,\n parent\n })\n }\n\n /* Add article */\n } else {\n documents.set(location, {\n location,\n title,\n text\n })\n }\n }\n return documents\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexConfig } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search highlight function\n *\n * @param value - Value\n *\n * @returns Highlighted value\n */\nexport type SearchHighlightFn = (value: string) => string\n\n/**\n * Search highlight factory function\n *\n * @param query - Query value\n *\n * @returns Search highlight function\n */\nexport type SearchHighlightFactoryFn = (query: string) => SearchHighlightFn\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search highlighter\n *\n * @param config - Search index configuration\n * @param escape - Whether to escape HTML\n *\n * @returns Search highlight factory function\n */\nexport function setupSearchHighlighter(\n config: SearchIndexConfig, escape: boolean\n): SearchHighlightFactoryFn {\n const separator = new RegExp(config.separator, \"img\")\n const highlight = (_: unknown, data: string, term: string) => {\n return `${data}${term}`\n }\n\n /* Return factory function */\n return (query: string) => {\n query = query\n .replace(/[\\s*+\\-:~^]+/g, \" \")\n .trim()\n\n /* Create search term match expression */\n const match = new RegExp(`(^|${config.separator})(${\n query\n .replace(/[|\\\\{}()[\\]^$+*?.-]/g, \"\\\\$&\")\n .replace(separator, \"|\")\n })`, \"img\")\n\n /* Highlight string value */\n return value => (\n escape\n ? escapeHTML(value)\n : value\n )\n .replace(match, highlight)\n .replace(/<\\/mark>(\\s+)]*>/img, \"$1\")\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search transformation function\n *\n * @param value - Query value\n *\n * @returns Transformed query value\n */\nexport type SearchTransformFn = (value: string) => string\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Default transformation function\n *\n * 1. Search for terms in quotation marks and prepend a `+` modifier to denote\n * that the resulting document must contain all terms, converting the query\n * to an `AND` query (as opposed to the default `OR` behavior). While users\n * may expect terms enclosed in quotation marks to map to span queries, i.e.\n * for which order is important, Lunr.js doesn't support them, so the best\n * we can do is to convert the terms to an `AND` query.\n *\n * 2. Replace control characters which are not located at the beginning of the\n * query or preceded by white space, or are not followed by a non-whitespace\n * character or are at the end of the query string. Furthermore, filter\n * unmatched quotation marks.\n *\n * 3. Trim excess whitespace from left and right.\n *\n * @param query - Query value\n *\n * @returns Transformed query value\n */\nexport function defaultTransform(query: string): string {\n return query\n .split(/\"([^\"]+)\"/g) /* => 1 */\n .map((terms, index) => index & 1\n ? terms.replace(/^\\b|^(?![^\\x00-\\x7F]|$)|\\s+/g, \" +\")\n : terms\n )\n .join(\"\")\n .replace(/\"|(?:^|\\s+)[*+\\-:^~]+(?=\\s+|$)/g, \"\") /* => 2 */\n .trim() /* => 3 */\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SearchIndex, SearchResult } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search message type\n */\nexport const enum SearchMessageType {\n SETUP, /* Search index setup */\n READY, /* Search index ready */\n QUERY, /* Search query */\n RESULT /* Search results */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Message containing the data necessary to setup the search index\n */\nexport interface SearchSetupMessage {\n type: SearchMessageType.SETUP /* Message type */\n data: SearchIndex /* Message data */\n}\n\n/**\n * Message indicating the search index is ready\n */\nexport interface SearchReadyMessage {\n type: SearchMessageType.READY /* Message type */\n}\n\n/**\n * Message containing a search query\n */\nexport interface SearchQueryMessage {\n type: SearchMessageType.QUERY /* Message type */\n data: string /* Message data */\n}\n\n/**\n * Message containing results for a search query\n */\nexport interface SearchResultMessage {\n type: SearchMessageType.RESULT /* Message type */\n data: SearchResult /* Message data */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Message exchanged with the search worker\n */\nexport type SearchMessage =\n | SearchSetupMessage\n | SearchReadyMessage\n | SearchQueryMessage\n | SearchResultMessage\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Type guard for search setup messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchSetupMessage(\n message: SearchMessage\n): message is SearchSetupMessage {\n return message.type === SearchMessageType.SETUP\n}\n\n/**\n * Type guard for search ready messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchReadyMessage(\n message: SearchMessage\n): message is SearchReadyMessage {\n return message.type === SearchMessageType.READY\n}\n\n/**\n * Type guard for search query messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchQueryMessage(\n message: SearchMessage\n): message is SearchQueryMessage {\n return message.type === SearchMessageType.QUERY\n}\n\n/**\n * Type guard for search result messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchResultMessage(\n message: SearchMessage\n): message is SearchResultMessage {\n return message.type === SearchMessageType.RESULT\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ObservableInput, Subject, from } from \"rxjs\"\nimport { map, share } from \"rxjs/operators\"\n\nimport { configuration, feature, translation } from \"~/_\"\nimport { WorkerHandler, watchWorker } from \"~/browser\"\n\nimport { SearchIndex } from \"../../_\"\nimport {\n SearchOptions,\n SearchPipeline\n} from \"../../options\"\nimport {\n SearchMessage,\n SearchMessageType,\n SearchSetupMessage,\n isSearchResultMessage\n} from \"../message\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search worker\n */\nexport type SearchWorker = WorkerHandler\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up search index\n *\n * @param data - Search index\n *\n * @returns Search index\n */\nfunction setupSearchIndex(\n { config, docs, index }: SearchIndex\n): SearchIndex {\n\n /* Override default language with value from translation */\n if (config.lang.length === 1 && config.lang[0] === \"en\")\n config.lang = [\n translation(\"search.config.lang\")\n ]\n\n /* Override default separator with value from translation */\n if (config.separator === \"[\\\\s\\\\-]+\")\n config.separator = translation(\"search.config.separator\")\n\n /* Set pipeline from translation */\n const pipeline = translation(\"search.config.pipeline\")\n .split(/\\s*,\\s*/)\n .filter(Boolean) as SearchPipeline\n\n /* Determine search options */\n const options: SearchOptions = {\n pipeline,\n suggestions: feature(\"search.suggest\")\n }\n\n /* Return search index after defaulting */\n return { config, docs, index, options }\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up search worker\n *\n * This function creates a web worker to set up and query the search index,\n * which is done using Lunr.js. The index must be passed as an observable to\n * enable hacks like _localsearch_ via search index embedding as JSON.\n *\n * @param url - Worker URL\n * @param index - Search index observable input\n *\n * @returns Search worker\n */\nexport function setupSearchWorker(\n url: string, index: ObservableInput\n): SearchWorker {\n const config = configuration()\n const worker = new Worker(url)\n\n /* Create communication channels and resolve relative links */\n const tx$ = new Subject()\n const rx$ = watchWorker(worker, { tx$ })\n .pipe(\n map(message => {\n if (isSearchResultMessage(message)) {\n for (const result of message.data.items)\n for (const document of result)\n document.location = `${new URL(document.location, config.base)}`\n }\n return message\n }),\n share()\n )\n\n /* Set up search index */\n from(index)\n .pipe(\n map(data => ({\n type: SearchMessageType.SETUP,\n data: setupSearchIndex(data)\n } as SearchSetupMessage))\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Return search worker */\n return { tx$, rx$ }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { configuration } from \"~/_\"\nimport { getElementOrThrow, requestJSON } from \"~/browser\"\nimport { Version, renderVersionSelector } from \"~/templates\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Set up version selector\n */\nexport function setupVersionSelector(): void {\n const config = configuration()\n requestJSON(new URL(\"../versions.json\", config.base))\n .subscribe(versions => {\n const topic = getElementOrThrow(\".md-header__topic\")\n topic.appendChild(renderVersionSelector(versions))\n })\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n combineLatest,\n fromEvent,\n merge\n} from \"rxjs\"\nimport {\n delay,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n filter,\n finalize,\n map,\n shareReplay,\n startWith,\n take,\n takeLast,\n takeUntil,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetSearchQueryPlaceholder,\n setSearchQueryPlaceholder\n} from \"~/actions\"\nimport {\n getLocation,\n setElementFocus,\n setToggle,\n watchElementFocus\n} from \"~/browser\"\nimport {\n SearchMessageType,\n SearchQueryMessage,\n SearchWorker,\n defaultTransform,\n isSearchReadyMessage\n} from \"~/integrations\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search query\n */\nexport interface SearchQuery {\n value: string /* Query value */\n focus: boolean /* Query focus */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch search query\n *\n * Note that the focus event which triggers re-reading the current query value\n * is delayed by `1ms` so the input's empty state is allowed to propagate.\n *\n * @param el - Search query element\n * @param worker - Search worker\n *\n * @returns Search query observable\n */\nexport function watchSearchQuery(\n el: HTMLInputElement, { rx$ }: SearchWorker\n): Observable {\n const fn = __search?.transform || defaultTransform\n\n /* Immediately show search dialog */\n const { searchParams } = getLocation()\n if (searchParams.has(\"q\"))\n setToggle(\"search\", true)\n\n /* Intercept query parameter (deep link) */\n const param$ = rx$\n .pipe(\n filter(isSearchReadyMessage),\n take(1),\n map(() => searchParams.get(\"q\") || \"\")\n )\n\n /* Set query from parameter */\n param$.subscribe(value => { // TODO: not ideal - find a better way\n if (value)\n el.value = value\n })\n\n /* Intercept focus and input events */\n const focus$ = watchElementFocus(el)\n const value$ = merge(\n fromEvent(el, \"keyup\"),\n fromEvent(el, \"focus\").pipe(delay(1)),\n param$\n )\n .pipe(\n map(() => fn(el.value)),\n startWith(\"\"),\n distinctUntilChanged(),\n )\n\n /* Combine into single observable */\n return combineLatest([value$, focus$])\n .pipe(\n map(([value, focus]) => ({ value, focus })),\n shareReplay(1)\n )\n}\n\n/**\n * Mount search query\n *\n * @param el - Search query element\n * @param worker - Search worker\n *\n * @returns Search query component observable\n */\nexport function mountSearchQuery(\n el: HTMLInputElement, { tx$, rx$ }: SearchWorker\n): Observable> {\n const internal$ = new Subject()\n\n /* Handle value changes */\n internal$\n .pipe(\n distinctUntilKeyChanged(\"value\"),\n map(({ value }): SearchQueryMessage => ({\n type: SearchMessageType.QUERY,\n data: value\n }))\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Handle focus changes */\n internal$\n .pipe(\n distinctUntilKeyChanged(\"focus\")\n )\n .subscribe(({ focus }) => {\n if (focus) {\n setToggle(\"search\", focus)\n setSearchQueryPlaceholder(el, \"\")\n } else {\n resetSearchQueryPlaceholder(el)\n }\n })\n\n /* Handle reset */\n fromEvent(el.form!, \"reset\")\n .pipe(\n takeUntil(internal$.pipe(takeLast(1)))\n )\n .subscribe(() => setElementFocus(el))\n\n /* Create and return component */\n return watchSearchQuery(el, { tx$, rx$ })\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n merge,\n of\n} from \"rxjs\"\nimport {\n bufferCount,\n filter,\n finalize,\n map,\n observeOn,\n skipUntil,\n switchMap,\n take,\n tap,\n withLatestFrom,\n zipWith\n} from \"rxjs/operators\"\n\nimport {\n addToSearchResultList,\n resetSearchResultList,\n resetSearchResultMeta,\n setSearchResultMeta\n} from \"~/actions\"\nimport {\n getElementOrThrow,\n watchElementThreshold\n} from \"~/browser\"\nimport {\n SearchResult,\n SearchWorker,\n isSearchReadyMessage,\n isSearchResultMessage\n} from \"~/integrations\"\nimport { renderSearchResultItem } from \"~/templates\"\n\nimport { Component } from \"../../_\"\nimport { SearchQuery } from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n query$: Observable /* Search query observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search result list\n *\n * This function performs a lazy rendering of the search results, depending on\n * the vertical offset of the search result container.\n *\n * @param el - Search result list element\n * @param worker - Search worker\n * @param options - Options\n *\n * @returns Search result list component observable\n */\nexport function mountSearchResult(\n el: HTMLElement, { rx$ }: SearchWorker, { query$ }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n const boundary$ = watchElementThreshold(el.parentElement!)\n .pipe(\n filter(Boolean)\n )\n\n /* Retrieve nested components */\n const meta = getElementOrThrow(\":scope > :first-child\", el)\n const list = getElementOrThrow(\":scope > :last-child\", el)\n\n /* Wait until search is ready */\n const ready$ = rx$\n .pipe(\n filter(isSearchReadyMessage),\n take(1)\n )\n\n /* Update search result metadata */\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n withLatestFrom(query$),\n skipUntil(ready$)\n )\n .subscribe(([{ items }, { value }]) => {\n if (value)\n setSearchResultMeta(meta, items.length)\n else\n resetSearchResultMeta(meta)\n })\n\n /* Update search result list */\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n tap(() => resetSearchResultList(list)),\n switchMap(({ items }) => merge(\n of(...items.slice(0, 10)),\n of(...items.slice(10))\n .pipe(\n bufferCount(4),\n zipWith(boundary$),\n switchMap(([chunk]) => of(...chunk))\n )\n ))\n )\n .subscribe(result => {\n addToSearchResultList(list, renderSearchResultItem(result))\n })\n\n /* Filter search result message */\n const result$ = rx$\n .pipe(\n filter(isSearchResultMessage),\n map(({ data }) => data)\n )\n\n /* Create and return component */\n return result$\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n fromEvent\n} from \"rxjs\"\nimport {\n finalize,\n map,\n tap\n} from \"rxjs/operators\"\n\nimport { getLocation } from \"~/browser\"\n\nimport { Component } from \"../../_\"\nimport { SearchQuery } from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search sharing\n */\nexport interface SearchShare {\n url: URL /* Deep link for sharing */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n query$: Observable /* Search query observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n query$: Observable /* Search query observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search sharing\n *\n * @param _el - Search sharing element\n * @param options - Options\n *\n * @returns Search sharing observable\n */\nexport function watchSearchShare(\n _el: HTMLElement, { query$ }: WatchOptions\n): Observable {\n return query$\n .pipe(\n map(({ value }) => {\n const url = getLocation()\n url.hash = \"\"\n url.searchParams.delete(\"h\")\n url.searchParams.set(\"q\", value)\n return { url }\n })\n )\n}\n\n/**\n * Mount search sharing\n *\n * @param el - Search sharing element\n * @param options - Options\n *\n * @returns Search sharing component observable\n */\nexport function mountSearchShare(\n el: HTMLAnchorElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$.subscribe(({ url }) => {\n el.setAttribute(\"data-clipboard-text\", el.href)\n el.href = `${url}`\n })\n\n /* Prevent following of link */\n fromEvent(el, \"click\")\n .subscribe(ev => ev.preventDefault())\n\n /* Create and return component */\n return watchSearchShare(el, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n asyncScheduler,\n fromEvent,\n merge\n} from \"rxjs\"\nimport {\n combineLatestWith,\n distinctUntilChanged,\n filter,\n finalize,\n map,\n observeOn,\n tap\n} from \"rxjs/operators\"\n\nimport { Keyboard } from \"~/browser\"\nimport {\n SearchResult,\n SearchWorker,\n isSearchResultMessage\n} from \"~/integrations\"\n\nimport { Component, getComponentElement } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search suggestions\n */\nexport interface SearchSuggest {}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n keyboard$: Observable /* Keyboard observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search suggestions\n *\n * This function will perform a lazy rendering of the search results, depending\n * on the vertical offset of the search result container.\n *\n * @param el - Search result list element\n * @param worker - Search worker\n * @param options - Options\n *\n * @returns Search result list component observable\n */\nexport function mountSearchSuggest(\n el: HTMLElement, { rx$ }: SearchWorker, { keyboard$ }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n\n /* Retrieve query component and track all changes */\n const query = getComponentElement(\"search-query\")\n const query$ = merge(\n fromEvent(query, \"keydown\"),\n fromEvent(query, \"focus\")\n )\n .pipe(\n observeOn(asyncScheduler),\n map(() => query.value),\n distinctUntilChanged(),\n )\n\n /* Update search suggestions */\n internal$\n .pipe(\n combineLatestWith(query$),\n map(([{ suggestions }, value]) => {\n const words = value.split(/([\\s-]+)/)\n if (suggestions?.length && words[words.length - 1]) {\n const last = suggestions[suggestions.length - 1]\n if (last.startsWith(words[words.length - 1]))\n words[words.length - 1] = last\n } else {\n words.length = 0\n }\n return words\n })\n )\n .subscribe(words => el.innerHTML = words\n .join(\"\")\n .replace(/\\s/g, \" \")\n )\n\n /* Set up search keyboard handlers */\n keyboard$\n .pipe(\n filter(({ mode }) => mode === \"search\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Right arrow: accept current suggestion */\n case \"ArrowRight\":\n if (\n el.innerText.length &&\n query.selectionStart === query.value.length\n )\n query.value = el.innerText\n break\n }\n })\n\n /* Filter search result message */\n const result$ = rx$\n .pipe(\n filter(isSearchResultMessage),\n map(({ data }) => data)\n )\n\n /* Create and return component */\n return result$\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(() => ({ ref: el }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { NEVER, Observable, ObservableInput, merge } from \"rxjs\"\nimport { filter, mergeWith, sample, take } from \"rxjs/operators\"\n\nimport { configuration } from \"~/_\"\nimport {\n Keyboard,\n getActiveElement,\n getElements,\n setElementFocus,\n setElementSelection,\n setToggle\n} from \"~/browser\"\nimport {\n SearchIndex,\n SearchResult,\n isSearchQueryMessage,\n isSearchReadyMessage,\n setupSearchWorker\n} from \"~/integrations\"\n\nimport {\n Component,\n getComponentElement,\n getComponentElements\n} from \"../../_\"\nimport { SearchQuery, mountSearchQuery } from \"../query\"\nimport { mountSearchResult } from \"../result\"\nimport { SearchShare, mountSearchShare } from \"../share\"\nimport { SearchSuggest, mountSearchSuggest } from \"../suggest\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search\n */\nexport type Search =\n | SearchQuery\n | SearchResult\n | SearchShare\n | SearchSuggest\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n index$: ObservableInput /* Search index observable */\n keyboard$: Observable /* Keyboard observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search\n *\n * This function sets up the search functionality, including the underlying\n * web worker and all keyboard bindings.\n *\n * @param el - Search element\n * @param options - Options\n *\n * @returns Search component observable\n */\nexport function mountSearch(\n el: HTMLElement, { index$, keyboard$ }: MountOptions\n): Observable> {\n const config = configuration()\n try {\n const url = __search?.worker || config.search\n const worker = setupSearchWorker(url, index$)\n\n /* Retrieve query and result components */\n const query = getComponentElement(\"search-query\", el)\n const result = getComponentElement(\"search-result\", el)\n\n /* Re-emit query when search is ready */\n const { tx$, rx$ } = worker\n tx$\n .pipe(\n filter(isSearchQueryMessage),\n sample(rx$.pipe(filter(isSearchReadyMessage))),\n take(1)\n )\n .subscribe(tx$.next.bind(tx$))\n\n /* Set up search keyboard handlers */\n keyboard$\n .pipe(\n filter(({ mode }) => mode === \"search\")\n )\n .subscribe(key => {\n const active = getActiveElement()\n switch (key.type) {\n\n /* Enter: go to first (best) result */\n case \"Enter\":\n if (active === query) {\n const anchors = new Map()\n for (const anchor of getElements(\n \":first-child [href]\", result\n )) {\n const article = anchor.firstElementChild!\n anchors.set(anchor, parseFloat(\n article.getAttribute(\"data-md-score\")!\n ))\n }\n\n /* Go to result with highest score, if any */\n if (anchors.size) {\n const [[best]] = [...anchors].sort(([, a], [, b]) => b - a)\n best.click()\n }\n\n /* Otherwise omit form submission */\n key.claim()\n }\n break\n\n /* Escape or Tab: close search */\n case \"Escape\":\n case \"Tab\":\n setToggle(\"search\", false)\n setElementFocus(query, false)\n break\n\n /* Vertical arrows: select previous or next search result */\n case \"ArrowUp\":\n case \"ArrowDown\":\n if (typeof active === \"undefined\") {\n setElementFocus(query)\n } else {\n const els = [query, ...getElements(\n \":not(details) > [href], summary, details[open] [href]\",\n result\n )]\n const i = Math.max(0, (\n Math.max(0, els.indexOf(active)) + els.length + (\n key.type === \"ArrowUp\" ? -1 : +1\n )\n ) % els.length)\n setElementFocus(els[i])\n }\n\n /* Prevent scrolling of page */\n key.claim()\n break\n\n /* All other keys: hand to search query */\n default:\n if (query !== getActiveElement())\n setElementFocus(query)\n }\n })\n\n /* Set up global keyboard handlers */\n keyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\"),\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Open search and select query */\n case \"f\":\n case \"s\":\n case \"/\":\n setElementFocus(query)\n setElementSelection(query)\n key.claim()\n break\n }\n })\n\n /* Create and return component */\n const query$ = mountSearchQuery(query, worker)\n const result$ = mountSearchResult(result, worker, { query$ })\n return merge(query$, result$)\n .pipe(\n mergeWith(\n\n /* Search sharing */\n ...getComponentElements(\"search-share\", el)\n .map(child => mountSearchShare(child, { query$ })),\n\n /* Search suggestions */\n ...getComponentElements(\"search-suggest\", el)\n .map(child => mountSearchSuggest(child, worker, { keyboard$ }))\n )\n )\n\n /* Gracefully handle broken search */\n } catch (err) {\n el.hidden = true\n return NEVER\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n ObservableInput,\n combineLatest\n} from \"rxjs\"\nimport { filter, map, startWith } from \"rxjs/operators\"\n\nimport { getLocation } from \"~/browser\"\nimport {\n SearchIndex,\n setupSearchHighlighter\n} from \"~/integrations\"\nimport { h } from \"~/utilities\"\n\nimport { Component } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search highlighting\n */\nexport interface SearchHighlight {\n nodes: Map /* Map of replacements */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount options\n */\ninterface MountOptions {\n index$: ObservableInput /* Search index observable */\n location$: Observable /* Location observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Mount search highlighting\n *\n * @param el - Content element\n * @param options - Options\n *\n * @returns Search highlighting component observable\n */\nexport function mountSearchHiglight(\n el: HTMLElement, { index$, location$ }: MountOptions\n): Observable> {\n return combineLatest([\n index$,\n location$\n .pipe(\n startWith(getLocation()),\n filter(url => url.searchParams.has(\"h\"))\n )\n ])\n .pipe(\n map(([index, url]) => setupSearchHighlighter(index.config, true)(\n url.searchParams.get(\"h\")!\n )),\n map(fn => {\n const nodes = new Map()\n\n /* Traverse text nodes and collect matches */\n const it = document.createNodeIterator(el, NodeFilter.SHOW_TEXT)\n for (let node = it.nextNode(); node; node = it.nextNode()) {\n if (node.parentElement?.offsetHeight) {\n const original = node.textContent!\n const replaced = fn(original)\n if (replaced.length > original.length)\n nodes.set(node as ChildNode, replaced)\n }\n }\n\n /* Replace original nodes with matches */\n for (const [node, text] of nodes) {\n const { childNodes } = h(\"span\", null, text)\n node.replaceWith(...Array.from(childNodes))\n }\n\n /* Return component */\n return { ref: el, nodes }\n })\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest\n} from \"rxjs\"\nimport {\n distinctUntilChanged,\n finalize,\n map,\n observeOn,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport {\n resetSidebarHeight,\n resetSidebarOffset,\n setSidebarHeight,\n setSidebarOffset\n} from \"~/actions\"\nimport { Viewport } from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\nimport { Main } from \"../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Sidebar\n */\nexport interface Sidebar {\n height: number /* Sidebar height */\n locked: boolean /* User scrolled past header */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n main$: Observable
    /* Main area observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch sidebar\n *\n * This function returns an observable that computes the visual parameters of\n * the sidebar which depends on the vertical viewport offset, as well as the\n * height of the main area. When the page is scrolled beyond the header, the\n * sidebar is locked and fills the remaining space.\n *\n * @param el - Sidebar element\n * @param options - Options\n *\n * @returns Sidebar observable\n */\nexport function watchSidebar(\n el: HTMLElement, { viewport$, main$ }: WatchOptions\n): Observable {\n const adjust =\n el.parentElement!.offsetTop -\n el.parentElement!.parentElement!.offsetTop\n\n /* Compute the sidebar's available height and if it should be locked */\n return combineLatest([main$, viewport$])\n .pipe(\n map(([{ offset, height }, { offset: { y } }]) => {\n height = height\n + Math.min(adjust, Math.max(0, y - offset))\n - adjust\n return {\n height,\n locked: y >= offset + adjust\n }\n }),\n distinctUntilChanged((a, b) => (\n a.height === b.height &&\n a.locked === b.locked\n ))\n )\n}\n\n/**\n * Mount sidebar\n *\n * @param el - Sidebar element\n * @param options - Options\n *\n * @returns Sidebar component observable\n */\nexport function mountSidebar(\n el: HTMLElement, { header$, ...options }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n withLatestFrom(header$)\n )\n .subscribe({\n\n /* Update height and offset */\n next([{ height }, { height: offset }]) {\n setSidebarHeight(el, height)\n setSidebarOffset(el, offset)\n },\n\n /* Reset on complete */\n complete() {\n resetSidebarOffset(el)\n resetSidebarHeight(el)\n }\n })\n\n /* Create and return component */\n return watchSidebar(el, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Repo, User } from \"github-types\"\nimport { Observable, zip } from \"rxjs\"\nimport { defaultIfEmpty, map } from \"rxjs/operators\"\n\nimport { requestJSON } from \"~/browser\"\n\nimport { SourceFacts } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * GitHub release (partial)\n */\ninterface Release {\n tag_name: string /* Tag name */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch GitHub repository facts\n *\n * @param user - GitHub user\n * @param repo - GitHub repository\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFactsFromGitHub(\n user: string, repo?: string\n): Observable {\n if (typeof repo !== \"undefined\") {\n const url = `https://api.github.com/repos/${user}/${repo}`\n return zip(\n\n /* Fetch version */\n requestJSON(`${url}/releases/latest`)\n .pipe(\n map(release => ({\n version: release.tag_name\n })),\n defaultIfEmpty({})\n ),\n\n /* Fetch stars and forks */\n requestJSON(url)\n .pipe(\n map(info => ({\n stars: info.stargazers_count,\n forks: info.forks_count\n })),\n defaultIfEmpty({})\n )\n )\n .pipe(\n map(([release, info]) => ({ ...release, ...info }))\n )\n\n /* User or organization */\n } else {\n const url = `https://api.github.com/users/${user}`\n return requestJSON(url)\n .pipe(\n map(info => ({\n repositories: info.public_repos\n })),\n defaultIfEmpty({})\n )\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { ProjectSchema } from \"gitlab\"\nimport { Observable } from \"rxjs\"\nimport { defaultIfEmpty, map } from \"rxjs/operators\"\n\nimport { requestJSON } from \"~/browser\"\n\nimport { SourceFacts } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch GitLab repository facts\n *\n * @param base - GitLab base\n * @param project - GitLab project\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFactsFromGitLab(\n base: string, project: string\n): Observable {\n const url = `https://${base}/api/v4/projects/${encodeURIComponent(project)}`\n return requestJSON(url)\n .pipe(\n map(({ star_count, forks_count }) => ({\n stars: star_count,\n forks: forks_count\n })),\n defaultIfEmpty({})\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { NEVER, Observable } from \"rxjs\"\n\nimport { fetchSourceFactsFromGitHub } from \"../github\"\nimport { fetchSourceFactsFromGitLab } from \"../gitlab\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository facts for repositories\n */\nexport interface RepositoryFacts {\n stars?: number /* Number of stars */\n forks?: number /* Number of forks */\n version?: string /* Latest version */\n}\n\n/**\n * Repository facts for organizations\n */\nexport interface OrganizationFacts {\n repositories?: number /* Number of repositories */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Repository facts\n */\nexport type SourceFacts =\n | RepositoryFacts\n | OrganizationFacts\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch repository facts\n *\n * @param url - Repository URL\n *\n * @returns Repository facts observable\n */\nexport function fetchSourceFacts(\n url: string\n): Observable {\n const [type] = url.match(/(git(?:hub|lab))/i) || []\n switch (type.toLowerCase()) {\n\n /* GitHub repository */\n case \"github\":\n const [, user, repo] = url.match(/^.+github\\.com\\/([^/]+)\\/?([^/]+)?/i)!\n return fetchSourceFactsFromGitHub(user, repo)\n\n /* GitLab repository */\n case \"gitlab\":\n const [, base, slug] = url.match(/^.+?([^/]*gitlab[^/]+)\\/(.+?)\\/?$/i)!\n return fetchSourceFactsFromGitLab(base, slug)\n\n /* Everything else */\n default:\n return NEVER\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { NEVER, Observable, Subject, defer, of } from \"rxjs\"\nimport {\n catchError,\n filter,\n finalize,\n map,\n shareReplay,\n tap\n} from \"rxjs/operators\"\n\nimport { setSourceFacts, setSourceState } from \"~/actions\"\nimport { renderSourceFacts } from \"~/templates\"\n\nimport { Component } from \"../../_\"\nimport { SourceFacts, fetchSourceFacts } from \"../facts\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository information\n */\nexport interface Source {\n facts: SourceFacts /* Repository facts */\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Repository information observable\n */\nlet fetch$: Observable\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch repository information\n *\n * This function tries to read the repository facts from session storage, and\n * if unsuccessful, fetches them from the underlying provider.\n *\n * @param el - Repository information element\n *\n * @returns Repository information observable\n */\nexport function watchSource(\n el: HTMLAnchorElement\n): Observable {\n return fetch$ ||= defer(() => {\n const data = sessionStorage.getItem(__prefix(\"__source\"))\n if (data) {\n return of(JSON.parse(data))\n } else {\n const value$ = fetchSourceFacts(el.href)\n value$.subscribe(value => {\n try {\n sessionStorage.setItem(__prefix(\"__source\"), JSON.stringify(value))\n } catch (err) {\n /* Uncritical, just swallow */\n }\n })\n\n /* Return value */\n return value$\n }\n })\n .pipe(\n catchError(() => NEVER),\n filter(facts => Object.keys(facts).length > 0),\n map(facts => ({ facts })),\n shareReplay(1)\n )\n}\n\n/**\n * Mount repository information\n *\n * @param el - Repository information element\n *\n * @returns Repository information component observable\n */\nexport function mountSource(\n el: HTMLAnchorElement\n): Observable> {\n const internal$ = new Subject()\n internal$.subscribe(({ facts }) => {\n setSourceFacts(el, renderSourceFacts(facts))\n setSourceState(el, \"done\")\n })\n\n /* Create and return component */\n return watchSource(el)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n of\n} from \"rxjs\"\nimport {\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\nimport { feature } from \"~/_\"\nimport { resetTabsState, setTabsState } from \"~/actions\"\nimport {\n Viewport,\n watchElementSize,\n watchViewportAt\n} from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Navigation tabs\n */\nexport interface Tabs {\n hidden: boolean /* User scrolled past tabs */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch navigation tabs\n *\n * @param el - Navigation tabs element\n * @param options - Options\n *\n * @returns Navigation tabs observable\n */\nexport function watchTabs(\n el: HTMLElement, { viewport$, header$ }: WatchOptions\n): Observable {\n return watchElementSize(document.body)\n .pipe(\n switchMap(() => watchViewportAt(el, { header$, viewport$ })),\n map(({ offset: { y } }) => {\n return {\n hidden: y >= 10\n }\n }),\n distinctUntilKeyChanged(\"hidden\")\n )\n}\n\n/**\n * Mount navigation tabs\n *\n * This function hides the navigation tabs when scrolling past the threshold\n * and makes them reappear in a nice CSS animation when scrolling back up.\n *\n * @param el - Navigation tabs element\n * @param options - Options\n *\n * @returns Navigation tabs component observable\n */\nexport function mountTabs(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler)\n )\n .subscribe({\n\n /* Update state */\n next({ hidden }) {\n if (hidden)\n setTabsState(el, \"hidden\")\n else\n resetTabsState(el)\n },\n\n /* Reset on complete */\n complete() {\n resetTabsState(el)\n }\n })\n\n /* Create and return component */\n return (\n feature(\"navigation.tabs.sticky\")\n ? of({ hidden: false })\n : watchTabs(el, options)\n )\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest\n} from \"rxjs\"\nimport {\n bufferCount,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n scan,\n startWith,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\nimport {\n resetAnchorActive,\n resetAnchorState,\n setAnchorActive,\n setAnchorState\n} from \"~/actions\"\nimport {\n Viewport,\n getElement,\n getElements,\n watchElementSize\n} from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Table of contents\n */\nexport interface TableOfContents {\n prev: HTMLAnchorElement[][] /* Anchors (previous) */\n next: HTMLAnchorElement[][] /* Anchors (next) */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch table of contents\n *\n * This is effectively a scroll spy implementation which will account for the\n * fixed header and automatically re-calculate anchor offsets when the viewport\n * is resized. The returned observable will only emit if the table of contents\n * needs to be repainted.\n *\n * This implementation tracks an anchor element's entire path starting from its\n * level up to the top-most anchor element, e.g. `[h3, h2, h1]`. Although the\n * Material theme currently doesn't make use of this information, it enables\n * the styling of the entire hierarchy through customization.\n *\n * Note that the current anchor is the last item of the `prev` anchor list.\n *\n * @param anchors - Anchor elements\n * @param options - Options\n *\n * @returns Table of contents observable\n */\nexport function watchTableOfContents(\n anchors: HTMLAnchorElement[], { viewport$, header$ }: WatchOptions\n): Observable {\n const table = new Map()\n for (const anchor of anchors) {\n const id = decodeURIComponent(anchor.hash.substring(1))\n const target = getElement(`[id=\"${id}\"]`)\n if (typeof target !== \"undefined\")\n table.set(anchor, target)\n }\n\n /* Compute necessary adjustment for header */\n const adjust$ = header$\n .pipe(\n map(header => 24 + header.height)\n )\n\n /* Compute partition of previous and next anchors */\n const partition$ = watchElementSize(document.body)\n .pipe(\n distinctUntilKeyChanged(\"height\"),\n\n /* Build index to map anchor paths to vertical offsets */\n map(() => {\n let path: HTMLAnchorElement[] = []\n return [...table].reduce((index, [anchor, target]) => {\n while (path.length) {\n const last = table.get(path[path.length - 1])!\n if (last.tagName >= target.tagName) {\n path.pop()\n } else {\n break\n }\n }\n\n /* If the current anchor is hidden, continue with its parent */\n let offset = target.offsetTop\n while (!offset && target.parentElement) {\n target = target.parentElement\n offset = target.offsetTop\n }\n\n /* Map reversed anchor path to vertical offset */\n return index.set(\n [...path = [...path, anchor]].reverse(),\n offset\n )\n }, new Map())\n }),\n\n /* Sort index by vertical offset (see https://bit.ly/30z6QSO) */\n map(index => new Map([...index].sort(([, a], [, b]) => a - b))),\n\n /* Re-compute partition when viewport offset changes */\n switchMap(index => combineLatest([adjust$, viewport$])\n .pipe(\n scan(([prev, next], [adjust, { offset: { y } }]) => {\n\n /* Look forward */\n while (next.length) {\n const [, offset] = next[0]\n if (offset - adjust < y) {\n prev = [...prev, next.shift()!]\n } else {\n break\n }\n }\n\n /* Look backward */\n while (prev.length) {\n const [, offset] = prev[prev.length - 1]\n if (offset - adjust >= y) {\n next = [prev.pop()!, ...next]\n } else {\n break\n }\n }\n\n /* Return partition */\n return [prev, next]\n }, [[], [...index]]),\n distinctUntilChanged((a, b) => (\n a[0] === b[0] &&\n a[1] === b[1]\n ))\n )\n )\n )\n\n /* Compute and return anchor list migrations */\n return partition$\n .pipe(\n map(([prev, next]) => ({\n prev: prev.map(([path]) => path),\n next: next.map(([path]) => path)\n })),\n\n /* Extract anchor list migrations */\n startWith({ prev: [], next: [] }),\n bufferCount(2, 1),\n map(([a, b]) => {\n\n /* Moving down */\n if (a.prev.length < b.prev.length) {\n return {\n prev: b.prev.slice(Math.max(0, a.prev.length - 1), b.prev.length),\n next: []\n }\n\n /* Moving up */\n } else {\n return {\n prev: b.prev.slice(-1),\n next: b.next.slice(0, b.next.length - a.next.length)\n }\n }\n })\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Mount table of contents\n *\n * @param el - Anchor list element\n * @param options - Options\n *\n * @returns Table of contents component observable\n */\nexport function mountTableOfContents(\n el: HTMLElement, options: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n )\n .subscribe(({ prev, next }) => {\n\n /* Look forward */\n for (const [anchor] of next) {\n resetAnchorActive(anchor)\n resetAnchorState(anchor)\n }\n\n /* Look backward */\n for (const [index, [anchor]] of prev.entries()) {\n setAnchorActive(anchor, index === prev.length - 1)\n setAnchorState(anchor, \"blur\")\n }\n })\n\n /* Create and return component */\n const anchors = getElements(\"[href^=\\\\#]\", el)\n return watchTableOfContents(anchors, options)\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n Subject,\n animationFrameScheduler,\n combineLatest\n} from \"rxjs\"\nimport {\n bufferCount,\n distinctUntilChanged,\n distinctUntilKeyChanged,\n finalize,\n map,\n observeOn,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport {\n resetBackToTopOffset,\n resetBackToTopState,\n resetFocusable,\n setBackToTopOffset,\n setBackToTopState,\n setFocusable\n} from \"~/actions\"\nimport { Viewport, setElementFocus } from \"~/browser\"\n\nimport { Component } from \"../_\"\nimport { Header } from \"../header\"\nimport { Main } from \"../main\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Back-to-top button\n */\nexport interface BackToTop {\n hidden: boolean /* User scrolled up */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch options\n */\ninterface WatchOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/**\n * Mount options\n */\ninterface MountOptions {\n viewport$: Observable /* Viewport observable */\n header$: Observable
    /* Header observable */\n main$: Observable
    /* Main area observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Watch back-to-top\n *\n * @param _el - Back-to-top element\n * @param options - Options\n *\n * @returns Back-to-top observable\n */\nexport function watchBackToTop(\n _el: HTMLElement, { viewport$, main$ }: WatchOptions\n): Observable {\n\n /* Compute direction */\n const direction$ = viewport$\n .pipe(\n map(({ offset: { y } }) => y),\n bufferCount(2, 1),\n map(([a, b]) => a > b && b),\n distinctUntilChanged()\n )\n\n /* Compute whether button should be hidden */\n const hidden$ = main$\n .pipe(\n distinctUntilKeyChanged(\"active\")\n )\n\n /* Compute threshold for hiding */\n return combineLatest([hidden$, direction$])\n .pipe(\n map(([{ active }, direction]) => ({\n hidden: !(active && direction)\n })),\n distinctUntilChanged((a, b) => (\n a.hidden === b.hidden\n ))\n )\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Mount back-to-top\n *\n * @param el - Back-to-top element\n * @param options - Options\n *\n * @returns Back-to-top component observable\n */\nexport function mountBackToTop(\n el: HTMLElement, { viewport$, header$, main$ }: MountOptions\n): Observable> {\n const internal$ = new Subject()\n internal$\n .pipe(\n observeOn(animationFrameScheduler),\n withLatestFrom(header$\n .pipe(\n distinctUntilKeyChanged(\"height\")\n )\n )\n )\n .subscribe({\n\n /* Update state */\n next([{ hidden }, { height }]) {\n setBackToTopOffset(el, height + 16)\n if (hidden) {\n setBackToTopState(el, \"hidden\")\n setElementFocus(el, false)\n setFocusable(el, -1)\n } else {\n resetBackToTopState(el)\n resetFocusable(el)\n }\n },\n\n /* Reset on complete */\n complete() {\n resetBackToTopOffset(el)\n resetBackToTopState(el)\n resetFocusable(el)\n }\n })\n\n /* Create and return component */\n return watchBackToTop(el, { viewport$, header$, main$ })\n .pipe(\n tap(state => internal$.next(state)),\n finalize(() => internal$.complete()),\n map(state => ({ ref: el, ...state }))\n )\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, of } from \"rxjs\"\nimport {\n mapTo,\n mergeMap,\n switchMap,\n takeWhile,\n tap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport { getElements } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch options\n */\ninterface PatchOptions {\n document$: Observable /* Document observable */\n tablet$: Observable /* Tablet breakpoint observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch indeterminate checkboxes\n *\n * This function replaces the indeterminate \"pseudo state\" with the actual\n * indeterminate state, which is used to keep navigation always expanded.\n *\n * @param options - Options\n */\nexport function patchIndeterminate(\n { document$, tablet$ }: PatchOptions\n): void {\n document$\n .pipe(\n switchMap(() => of(...getElements(\n \"[data-md-state=indeterminate]\"\n ))),\n tap(el => {\n el.indeterminate = true\n el.checked = false\n }),\n mergeMap(el => fromEvent(el, \"change\")\n .pipe(\n takeWhile(() => el.hasAttribute(\"data-md-state\")),\n mapTo(el)\n )\n ),\n withLatestFrom(tablet$)\n )\n .subscribe(([el, tablet]) => {\n el.removeAttribute(\"data-md-state\")\n if (tablet)\n el.checked = false\n })\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { Observable, fromEvent, of } from \"rxjs\"\nimport {\n filter,\n mapTo,\n mergeMap,\n switchMap,\n tap\n} from \"rxjs/operators\"\n\nimport { getElements } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch options\n */\ninterface PatchOptions {\n document$: Observable /* Document observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Check whether the given device is an Apple device\n *\n * @returns Test result\n */\nfunction isAppleDevice(): boolean {\n return /(iPad|iPhone|iPod)/.test(navigator.userAgent)\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch all elements with `data-md-scrollfix` attributes\n *\n * This is a year-old patch which ensures that overflow scrolling works at the\n * top and bottom of containers on iOS by ensuring a `1px` scroll offset upon\n * the start of a touch event.\n *\n * @see https://bit.ly/2SCtAOO - Original source\n *\n * @param options - Options\n */\nexport function patchScrollfix(\n { document$ }: PatchOptions\n): void {\n document$\n .pipe(\n switchMap(() => of(...getElements(\"[data-md-scrollfix]\"))),\n tap(el => el.removeAttribute(\"data-md-scrollfix\")),\n filter(isAppleDevice),\n mergeMap(el => fromEvent(el, \"touchstart\")\n .pipe(\n mapTo(el)\n )\n )\n )\n .subscribe(el => {\n const top = el.scrollTop\n\n /* We're at the top of the container */\n if (top === 0) {\n el.scrollTop = 1\n\n /* We're at the bottom of the container */\n } else if (top + el.offsetHeight === el.scrollHeight) {\n el.scrollTop = top - 1\n }\n })\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n Observable,\n animationFrameScheduler,\n combineLatest,\n of\n} from \"rxjs\"\nimport {\n delay,\n map,\n observeOn,\n switchMap,\n withLatestFrom\n} from \"rxjs/operators\"\n\nimport { resetScrollLock, setScrollLock } from \"~/actions\"\nimport { Viewport, watchToggle } from \"~/browser\"\n\n/* ----------------------------------------------------------------------------\n * Helper types\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch options\n */\ninterface PatchOptions {\n viewport$: Observable /* Viewport observable */\n tablet$: Observable /* Tablet breakpoint observable */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Patch the document body to lock when search is open\n *\n * For mobile and tablet viewports, the search is rendered full screen, which\n * leads to scroll leaking when at the top or bottom of the search result. This\n * function locks the body when the search is in full screen mode, and restores\n * the scroll position when leaving.\n *\n * @param options - Options\n */\nexport function patchScrolllock(\n { viewport$, tablet$ }: PatchOptions\n): void {\n combineLatest([watchToggle(\"search\"), tablet$])\n .pipe(\n map(([active, tablet]) => active && !tablet),\n switchMap(active => of(active)\n .pipe(\n delay(active ? 400 : 100),\n observeOn(animationFrameScheduler)\n )\n ),\n withLatestFrom(viewport$)\n )\n .subscribe(([active, { offset: { y }}]) => {\n if (active)\n setScrollLock(document.body, y)\n else\n resetScrollLock(document.body)\n })\n}\n"], + "mappings": "0kCAAA,oBAAC,UAAU,EAAQ,EAAS,CAC1B,MAAO,KAAY,UAAY,MAAO,KAAW,YAAc,IAC/D,MAAO,SAAW,YAAc,OAAO,IAAM,OAAO,GACnD,MACD,GAAO,UAAY,CAAE,aASrB,WAAmC,EAAO,CACxC,GAAI,GAAmB,GACnB,EAA0B,GAC1B,EAAiC,KAEjC,EAAsB,CACxB,KAAM,GACN,OAAQ,GACR,IAAK,GACL,IAAK,GACL,MAAO,GACP,SAAU,GACV,OAAQ,GACR,KAAM,GACN,MAAO,GACP,KAAM,GACN,KAAM,GACN,SAAU,GACV,iBAAkB,IAQpB,WAA4B,EAAI,CAC9B,MACE,MACA,IAAO,UACP,EAAG,WAAa,QAChB,EAAG,WAAa,QAChB,aAAe,IACf,YAAc,GAAG,WAcrB,WAAuC,EAAI,CACzC,GAAI,IAAO,EAAG,KACV,GAAU,EAAG,QAUjB,MARI,QAAY,SAAW,EAAoB,KAAS,CAAC,EAAG,UAIxD,KAAY,YAAc,CAAC,EAAG,UAI9B,EAAG,mBAYT,WAA8B,EAAI,CAChC,AAAI,EAAG,UAAU,SAAS,kBAG1B,GAAG,UAAU,IAAI,iBACjB,EAAG,aAAa,2BAA4B,KAQ9C,WAAiC,EAAI,CACnC,AAAI,CAAC,EAAG,aAAa,6BAGrB,GAAG,UAAU,OAAO,iBACpB,EAAG,gBAAgB,6BAWrB,WAAmB,EAAG,CACpB,AAAI,EAAE,SAAW,EAAE,QAAU,EAAE,SAI3B,GAAmB,EAAM,gBAC3B,EAAqB,EAAM,eAG7B,EAAmB,IAWrB,WAAuB,EAAG,CACxB,EAAmB,GAUrB,WAAiB,EAAG,CAElB,AAAI,CAAC,EAAmB,EAAE,SAItB,IAAoB,EAA8B,EAAE,UACtD,EAAqB,EAAE,QAQ3B,WAAgB,EAAG,CACjB,AAAI,CAAC,EAAmB,EAAE,SAKxB,GAAE,OAAO,UAAU,SAAS,kBAC5B,EAAE,OAAO,aAAa,8BAMtB,GAA0B,GAC1B,OAAO,aAAa,GACpB,EAAiC,OAAO,WAAW,UAAW,CAC5D,EAA0B,IACzB,KACH,EAAwB,EAAE,SAS9B,WAA4B,EAAG,CAC7B,AAAI,SAAS,kBAAoB,UAK3B,IACF,GAAmB,IAErB,KAUJ,YAA0C,CACxC,SAAS,iBAAiB,YAAa,GACvC,SAAS,iBAAiB,YAAa,GACvC,SAAS,iBAAiB,UAAW,GACrC,SAAS,iBAAiB,cAAe,GACzC,SAAS,iBAAiB,cAAe,GACzC,SAAS,iBAAiB,YAAa,GACvC,SAAS,iBAAiB,YAAa,GACvC,SAAS,iBAAiB,aAAc,GACxC,SAAS,iBAAiB,WAAY,GAGxC,YAA6C,CAC3C,SAAS,oBAAoB,YAAa,GAC1C,SAAS,oBAAoB,YAAa,GAC1C,SAAS,oBAAoB,UAAW,GACxC,SAAS,oBAAoB,cAAe,GAC5C,SAAS,oBAAoB,cAAe,GAC5C,SAAS,oBAAoB,YAAa,GAC1C,SAAS,oBAAoB,YAAa,GAC1C,SAAS,oBAAoB,aAAc,GAC3C,SAAS,oBAAoB,WAAY,GAU3C,WAA8B,EAAG,CAG/B,AAAI,EAAE,OAAO,UAAY,EAAE,OAAO,SAAS,gBAAkB,QAI7D,GAAmB,GACnB,KAMF,SAAS,iBAAiB,UAAW,EAAW,IAChD,SAAS,iBAAiB,YAAa,EAAe,IACtD,SAAS,iBAAiB,cAAe,EAAe,IACxD,SAAS,iBAAiB,aAAc,EAAe,IACvD,SAAS,iBAAiB,mBAAoB,EAAoB,IAElE,IAMA,EAAM,iBAAiB,QAAS,EAAS,IACzC,EAAM,iBAAiB,OAAQ,EAAQ,IAOvC,AAAI,EAAM,WAAa,KAAK,wBAA0B,EAAM,KAI1D,EAAM,KAAK,aAAa,wBAAyB,IACxC,EAAM,WAAa,KAAK,eACjC,UAAS,gBAAgB,UAAU,IAAI,oBACvC,SAAS,gBAAgB,aAAa,wBAAyB,KAOnE,GAAI,MAAO,SAAW,aAAe,MAAO,WAAa,YAAa,CAIpE,OAAO,0BAA4B,EAInC,GAAI,GAEJ,GAAI,CACF,EAAQ,GAAI,aAAY,sCACjB,EAAP,CAEA,EAAQ,SAAS,YAAY,eAC7B,EAAM,gBAAgB,+BAAgC,GAAO,GAAO,IAGtE,OAAO,cAAc,GAGvB,AAAI,MAAO,WAAa,aAGtB,EAA0B,cCpT9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gFAeA,GAAI,IACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACJ,AAAC,UAAU,EAAS,CAChB,GAAI,GAAO,MAAO,SAAW,SAAW,OAAS,MAAO,OAAS,SAAW,KAAO,MAAO,OAAS,SAAW,KAAO,GACrH,AAAI,MAAO,SAAW,YAAc,OAAO,IACvC,OAAO,QAAS,CAAC,WAAY,SAAU,EAAS,CAAE,EAAQ,EAAe,EAAM,EAAe,OAE7F,AAAI,MAAO,KAAW,UAAY,MAAO,IAAO,SAAY,SAC7D,EAAQ,EAAe,EAAM,EAAe,GAAO,WAGnD,EAAQ,EAAe,IAE3B,WAAwB,EAAS,EAAU,CACvC,MAAI,KAAY,GACZ,CAAI,MAAO,QAAO,QAAW,WACzB,OAAO,eAAe,EAAS,aAAc,CAAE,MAAO,KAGtD,EAAQ,WAAa,IAGtB,SAAU,EAAI,EAAG,CAAE,MAAO,GAAQ,GAAM,EAAW,EAAS,EAAI,GAAK,MAGnF,SAAU,EAAU,CACjB,GAAI,GAAgB,OAAO,gBACtB,CAAE,UAAW,aAAgB,QAAS,SAAU,EAAG,EAAG,CAAE,EAAE,UAAY,IACvE,SAAU,EAAG,EAAG,CAAE,OAAS,KAAK,GAAG,AAAI,OAAO,UAAU,eAAe,KAAK,EAAG,IAAI,GAAE,GAAK,EAAE,KAEhG,GAAY,SAAU,EAAG,EAAG,CACxB,GAAI,MAAO,IAAM,YAAc,IAAM,KACjC,KAAM,IAAI,WAAU,uBAAyB,OAAO,GAAK,iCAC7D,EAAc,EAAG,GACjB,YAAc,CAAE,KAAK,YAAc,EACnC,EAAE,UAAY,IAAM,KAAO,OAAO,OAAO,GAAM,GAAG,UAAY,EAAE,UAAW,GAAI,KAGnF,GAAW,OAAO,QAAU,SAAU,EAAG,CACrC,OAAS,GAAG,EAAI,EAAG,EAAI,UAAU,OAAQ,EAAI,EAAG,IAAK,CACjD,EAAI,UAAU,GACd,OAAS,KAAK,GAAG,AAAI,OAAO,UAAU,eAAe,KAAK,EAAG,IAAI,GAAE,GAAK,EAAE,IAE9E,MAAO,IAGX,GAAS,SAAU,EAAG,EAAG,CACrB,GAAI,GAAI,GACR,OAAS,KAAK,GAAG,AAAI,OAAO,UAAU,eAAe,KAAK,EAAG,IAAM,EAAE,QAAQ,GAAK,GAC9E,GAAE,GAAK,EAAE,IACb,GAAI,GAAK,MAAQ,MAAO,QAAO,uBAA0B,WACrD,OAAS,GAAI,EAAG,EAAI,OAAO,sBAAsB,GAAI,EAAI,EAAE,OAAQ,IAC/D,AAAI,EAAE,QAAQ,EAAE,IAAM,GAAK,OAAO,UAAU,qBAAqB,KAAK,EAAG,EAAE,KACvE,GAAE,EAAE,IAAM,EAAE,EAAE,KAE1B,MAAO,IAGX,GAAa,SAAU,EAAY,EAAQ,EAAK,EAAM,CAClD,GAAI,GAAI,UAAU,OAAQ,EAAI,EAAI,EAAI,EAAS,IAAS,KAAO,EAAO,OAAO,yBAAyB,EAAQ,GAAO,EAAM,EAC3H,GAAI,MAAO,UAAY,UAAY,MAAO,SAAQ,UAAa,WAAY,EAAI,QAAQ,SAAS,EAAY,EAAQ,EAAK,OACpH,QAAS,GAAI,EAAW,OAAS,EAAG,GAAK,EAAG,IAAK,AAAI,GAAI,EAAW,KAAI,GAAK,GAAI,EAAI,EAAE,GAAK,EAAI,EAAI,EAAE,EAAQ,EAAK,GAAK,EAAE,EAAQ,KAAS,GAChJ,MAAO,GAAI,GAAK,GAAK,OAAO,eAAe,EAAQ,EAAK,GAAI,GAGhE,GAAU,SAAU,EAAY,EAAW,CACvC,MAAO,UAAU,EAAQ,EAAK,CAAE,EAAU,EAAQ,EAAK,KAG3D,GAAa,SAAU,EAAa,EAAe,CAC/C,GAAI,MAAO,UAAY,UAAY,MAAO,SAAQ,UAAa,WAAY,MAAO,SAAQ,SAAS,EAAa,IAGpH,GAAY,SAAU,EAAS,EAAY,EAAG,EAAW,CACrD,WAAe,EAAO,CAAE,MAAO,aAAiB,GAAI,EAAQ,GAAI,GAAE,SAAU,EAAS,CAAE,EAAQ,KAC/F,MAAO,IAAK,IAAM,GAAI,UAAU,SAAU,EAAS,EAAQ,CACvD,WAAmB,EAAO,CAAE,GAAI,CAAE,EAAK,EAAU,KAAK,UAAkB,EAAP,CAAY,EAAO,IACpF,WAAkB,EAAO,CAAE,GAAI,CAAE,EAAK,EAAU,MAAS,UAAkB,EAAP,CAAY,EAAO,IACvF,WAAc,EAAQ,CAAE,EAAO,KAAO,EAAQ,EAAO,OAAS,EAAM,EAAO,OAAO,KAAK,EAAW,GAClG,EAAM,GAAY,EAAU,MAAM,EAAS,GAAc,KAAK,WAItE,GAAc,SAAU,EAAS,EAAM,CACnC,GAAI,GAAI,CAAE,MAAO,EAAG,KAAM,UAAW,CAAE,GAAI,EAAE,GAAK,EAAG,KAAM,GAAE,GAAI,MAAO,GAAE,IAAO,KAAM,GAAI,IAAK,IAAM,EAAG,EAAG,EAAG,EAC/G,MAAO,GAAI,CAAE,KAAM,EAAK,GAAI,MAAS,EAAK,GAAI,OAAU,EAAK,IAAM,MAAO,SAAW,YAAe,GAAE,OAAO,UAAY,UAAW,CAAE,MAAO,QAAU,EACvJ,WAAc,EAAG,CAAE,MAAO,UAAU,EAAG,CAAE,MAAO,GAAK,CAAC,EAAG,KACzD,WAAc,EAAI,CACd,GAAI,EAAG,KAAM,IAAI,WAAU,mCAC3B,KAAO,GAAG,GAAI,CACV,GAAI,EAAI,EAAG,GAAM,GAAI,EAAG,GAAK,EAAI,EAAE,OAAY,EAAG,GAAK,EAAE,OAAc,IAAI,EAAE,SAAc,EAAE,KAAK,GAAI,GAAK,EAAE,OAAS,CAAE,GAAI,EAAE,KAAK,EAAG,EAAG,KAAK,KAAM,MAAO,GAE3J,OADI,EAAI,EAAG,GAAG,GAAK,CAAC,EAAG,GAAK,EAAG,EAAE,QACzB,EAAG,QACF,OAAQ,GAAG,EAAI,EAAI,UACnB,GAAG,SAAE,QAAgB,CAAE,MAAO,EAAG,GAAI,KAAM,QAC3C,GAAG,EAAE,QAAS,EAAI,EAAG,GAAI,EAAK,CAAC,GAAI,aACnC,GAAG,EAAK,EAAE,IAAI,MAAO,EAAE,KAAK,MAAO,iBAEpC,GAAM,EAAI,EAAE,KAAM,IAAI,EAAE,OAAS,GAAK,EAAE,EAAE,OAAS,KAAQ,GAAG,KAAO,GAAK,EAAG,KAAO,GAAI,CAAE,EAAI,EAAG,SACjG,GAAI,EAAG,KAAO,GAAM,EAAC,GAAM,EAAG,GAAK,EAAE,IAAM,EAAG,GAAK,EAAE,IAAM,CAAE,EAAE,MAAQ,EAAG,GAAI,MAC9E,GAAI,EAAG,KAAO,GAAK,EAAE,MAAQ,EAAE,GAAI,CAAE,EAAE,MAAQ,EAAE,GAAI,EAAI,EAAI,MAC7D,GAAI,GAAK,EAAE,MAAQ,EAAE,GAAI,CAAE,EAAE,MAAQ,EAAE,GAAI,EAAE,IAAI,KAAK,GAAK,MAC3D,AAAI,EAAE,IAAI,EAAE,IAAI,MAChB,EAAE,KAAK,MAAO,SAEtB,EAAK,EAAK,KAAK,EAAS,SACnB,EAAP,CAAY,EAAK,CAAC,EAAG,GAAI,EAAI,SAAK,CAAU,EAAI,EAAI,EACtD,GAAI,EAAG,GAAK,EAAG,KAAM,GAAG,GAAI,MAAO,CAAE,MAAO,EAAG,GAAK,EAAG,GAAK,OAAQ,KAAM,MAIlF,GAAe,SAAS,EAAG,EAAG,CAC1B,OAAS,KAAK,GAAG,AAAI,IAAM,WAAa,CAAC,OAAO,UAAU,eAAe,KAAK,EAAG,IAAI,GAAgB,EAAG,EAAG,IAG/G,GAAkB,OAAO,OAAU,SAAS,EAAG,EAAG,EAAG,EAAI,CACrD,AAAI,IAAO,QAAW,GAAK,GAC3B,OAAO,eAAe,EAAG,EAAI,CAAE,WAAY,GAAM,IAAK,UAAW,CAAE,MAAO,GAAE,OAC1E,SAAS,EAAG,EAAG,EAAG,EAAI,CACxB,AAAI,IAAO,QAAW,GAAK,GAC3B,EAAE,GAAM,EAAE,IAGd,GAAW,SAAU,EAAG,CACpB,GAAI,GAAI,MAAO,SAAW,YAAc,OAAO,SAAU,EAAI,GAAK,EAAE,GAAI,EAAI,EAC5E,GAAI,EAAG,MAAO,GAAE,KAAK,GACrB,GAAI,GAAK,MAAO,GAAE,QAAW,SAAU,MAAO,CAC1C,KAAM,UAAY,CACd,MAAI,IAAK,GAAK,EAAE,QAAQ,GAAI,QACrB,CAAE,MAAO,GAAK,EAAE,KAAM,KAAM,CAAC,KAG5C,KAAM,IAAI,WAAU,EAAI,0BAA4B,oCAGxD,GAAS,SAAU,EAAG,EAAG,CACrB,GAAI,GAAI,MAAO,SAAW,YAAc,EAAE,OAAO,UACjD,GAAI,CAAC,EAAG,MAAO,GACf,GAAI,GAAI,EAAE,KAAK,GAAI,EAAG,EAAK,GAAI,EAC/B,GAAI,CACA,KAAQ,KAAM,QAAU,KAAM,IAAM,CAAE,GAAI,EAAE,QAAQ,MAAM,EAAG,KAAK,EAAE,aAEjE,EAAP,CAAgB,EAAI,CAAE,MAAO,UAC7B,CACI,GAAI,CACA,AAAI,GAAK,CAAC,EAAE,MAAS,GAAI,EAAE,SAAY,EAAE,KAAK,UAElD,CAAU,GAAI,EAAG,KAAM,GAAE,OAE7B,MAAO,IAIX,GAAW,UAAY,CACnB,OAAS,GAAK,GAAI,EAAI,EAAG,EAAI,UAAU,OAAQ,IAC3C,EAAK,EAAG,OAAO,GAAO,UAAU,KACpC,MAAO,IAIX,GAAiB,UAAY,CACzB,OAAS,GAAI,EAAG,EAAI,EAAG,EAAK,UAAU,OAAQ,EAAI,EAAI,IAAK,GAAK,UAAU,GAAG,OAC7E,OAAS,GAAI,MAAM,GAAI,EAAI,EAAG,EAAI,EAAG,EAAI,EAAI,IACzC,OAAS,GAAI,UAAU,GAAI,EAAI,EAAG,EAAK,EAAE,OAAQ,EAAI,EAAI,IAAK,IAC1D,EAAE,GAAK,EAAE,GACjB,MAAO,IAGX,GAAgB,SAAU,EAAI,EAAM,CAChC,OAAS,GAAI,EAAG,EAAK,EAAK,OAAQ,EAAI,EAAG,OAAQ,EAAI,EAAI,IAAK,IAC1D,EAAG,GAAK,EAAK,GACjB,MAAO,IAGX,GAAU,SAAU,EAAG,CACnB,MAAO,gBAAgB,IAAW,MAAK,EAAI,EAAG,MAAQ,GAAI,IAAQ,IAGtE,GAAmB,SAAU,EAAS,EAAY,EAAW,CACzD,GAAI,CAAC,OAAO,cAAe,KAAM,IAAI,WAAU,wCAC/C,GAAI,GAAI,EAAU,MAAM,EAAS,GAAc,IAAK,EAAG,EAAI,GAC3D,MAAO,GAAI,GAAI,EAAK,QAAS,EAAK,SAAU,EAAK,UAAW,EAAE,OAAO,eAAiB,UAAY,CAAE,MAAO,OAAS,EACpH,WAAc,EAAG,CAAE,AAAI,EAAE,IAAI,GAAE,GAAK,SAAU,EAAG,CAAE,MAAO,IAAI,SAAQ,SAAU,EAAG,EAAG,CAAE,EAAE,KAAK,CAAC,EAAG,EAAG,EAAG,IAAM,GAAK,EAAO,EAAG,OAC9H,WAAgB,EAAG,EAAG,CAAE,GAAI,CAAE,EAAK,EAAE,GAAG,UAAc,EAAP,CAAY,EAAO,EAAE,GAAG,GAAI,IAC3E,WAAc,EAAG,CAAE,EAAE,gBAAiB,IAAU,QAAQ,QAAQ,EAAE,MAAM,GAAG,KAAK,EAAS,GAAU,EAAO,EAAE,GAAG,GAAI,GACnH,WAAiB,EAAO,CAAE,EAAO,OAAQ,GACzC,WAAgB,EAAO,CAAE,EAAO,QAAS,GACzC,WAAgB,EAAG,EAAG,CAAE,AAAI,EAAE,GAAI,EAAE,QAAS,EAAE,QAAQ,EAAO,EAAE,GAAG,GAAI,EAAE,GAAG,MAGhF,GAAmB,SAAU,EAAG,CAC5B,GAAI,GAAG,EACP,MAAO,GAAI,GAAI,EAAK,QAAS,EAAK,QAAS,SAAU,EAAG,CAAE,KAAM,KAAO,EAAK,UAAW,EAAE,OAAO,UAAY,UAAY,CAAE,MAAO,OAAS,EAC1I,WAAc,EAAG,EAAG,CAAE,EAAE,GAAK,EAAE,GAAK,SAAU,EAAG,CAAE,MAAQ,GAAI,CAAC,GAAK,CAAE,MAAO,GAAQ,EAAE,GAAG,IAAK,KAAM,IAAM,UAAa,EAAI,EAAE,GAAK,GAAO,IAG/I,GAAgB,SAAU,EAAG,CACzB,GAAI,CAAC,OAAO,cAAe,KAAM,IAAI,WAAU,wCAC/C,GAAI,GAAI,EAAE,OAAO,eAAgB,EACjC,MAAO,GAAI,EAAE,KAAK,GAAM,GAAI,MAAO,KAAa,WAAa,GAAS,GAAK,EAAE,OAAO,YAAa,EAAI,GAAI,EAAK,QAAS,EAAK,SAAU,EAAK,UAAW,EAAE,OAAO,eAAiB,UAAY,CAAE,MAAO,OAAS,GAC9M,WAAc,EAAG,CAAE,EAAE,GAAK,EAAE,IAAM,SAAU,EAAG,CAAE,MAAO,IAAI,SAAQ,SAAU,EAAS,EAAQ,CAAE,EAAI,EAAE,GAAG,GAAI,EAAO,EAAS,EAAQ,EAAE,KAAM,EAAE,UAChJ,WAAgB,EAAS,EAAQ,EAAG,EAAG,CAAE,QAAQ,QAAQ,GAAG,KAAK,SAAS,EAAG,CAAE,EAAQ,CAAE,MAAO,EAAG,KAAM,KAAS,KAGtH,GAAuB,SAAU,EAAQ,EAAK,CAC1C,MAAI,QAAO,eAAkB,OAAO,eAAe,EAAQ,MAAO,CAAE,MAAO,IAAiB,EAAO,IAAM,EAClG,GAGX,GAAI,GAAqB,OAAO,OAAU,SAAS,EAAG,EAAG,CACrD,OAAO,eAAe,EAAG,UAAW,CAAE,WAAY,GAAM,MAAO,KAC9D,SAAS,EAAG,EAAG,CAChB,EAAE,QAAa,GAGnB,GAAe,SAAU,EAAK,CAC1B,GAAI,GAAO,EAAI,WAAY,MAAO,GAClC,GAAI,GAAS,GACb,GAAI,GAAO,KAAM,OAAS,KAAK,GAAK,AAAI,IAAM,WAAa,OAAO,UAAU,eAAe,KAAK,EAAK,IAAI,GAAgB,EAAQ,EAAK,GACtI,SAAmB,EAAQ,GACpB,GAGX,GAAkB,SAAU,EAAK,CAC7B,MAAQ,IAAO,EAAI,WAAc,EAAM,CAAE,QAAW,IAGxD,GAAyB,SAAU,EAAU,EAAY,CACrD,GAAI,CAAC,EAAW,IAAI,GAChB,KAAM,IAAI,WAAU,kDAExB,MAAO,GAAW,IAAI,IAG1B,GAAyB,SAAU,EAAU,EAAY,EAAO,CAC5D,GAAI,CAAC,EAAW,IAAI,GAChB,KAAM,IAAI,WAAU,kDAExB,SAAW,IAAI,EAAU,GAClB,GAGX,EAAS,YAAa,IACtB,EAAS,WAAY,IACrB,EAAS,SAAU,IACnB,EAAS,aAAc,IACvB,EAAS,UAAW,IACpB,EAAS,aAAc,IACvB,EAAS,YAAa,IACtB,EAAS,cAAe,IACxB,EAAS,eAAgB,IACzB,EAAS,kBAAmB,IAC5B,EAAS,WAAY,IACrB,EAAS,SAAU,IACnB,EAAS,WAAY,IACrB,EAAS,iBAAkB,IAC3B,EAAS,gBAAiB,IAC1B,EAAS,UAAW,IACpB,EAAS,mBAAoB,IAC7B,EAAS,mBAAoB,IAC7B,EAAS,gBAAiB,IAC1B,EAAS,uBAAwB,IACjC,EAAS,eAAgB,IACzB,EAAS,kBAAmB,IAC5B,EAAS,yBAA0B,IACnC,EAAS,yBAA0B,QC9SvC;AAAA;AAAA;AAAA;AAAA;AAAA,GAMA,AAAC,UAA0C,EAAM,EAAS,CACzD,AAAG,MAAO,KAAY,UAAY,MAAO,KAAW,SACnD,GAAO,QAAU,IACb,AAAG,MAAO,SAAW,YAAc,OAAO,IAC9C,OAAO,GAAI,GACP,AAAG,MAAO,KAAY,SAC1B,GAAQ,YAAiB,IAEzB,EAAK,YAAiB,MACrB,GAAM,UAAW,CACpB,MAAiB,WAAW,CAClB,GAAI,GAAuB,CAE/B,IACC,SAAS,EAAyB,EAAqB,EAAqB,CAEnF,aAGA,EAAoB,EAAE,EAAqB,CACzC,QAAW,UAAW,CAAE,MAAqB,OAI/C,GAAI,GAAe,EAAoB,KACnC,EAAoC,EAAoB,EAAE,GAE1D,EAAS,EAAoB,KAC7B,EAA8B,EAAoB,EAAE,GAEpD,EAAa,EAAoB,KACjC,EAA8B,EAAoB,EAAE,GAExD,WAAiB,EAAK,CAA6B,MAAI,OAAO,SAAW,YAAc,MAAO,QAAO,UAAa,SAAY,EAAU,SAAiB,EAAK,CAAE,MAAO,OAAO,IAAiB,EAAU,SAAiB,EAAK,CAAE,MAAO,IAAO,MAAO,SAAW,YAAc,EAAI,cAAgB,QAAU,IAAQ,OAAO,UAAY,SAAW,MAAO,IAAiB,EAAQ,GAEnX,WAAyB,EAAU,EAAa,CAAE,GAAI,CAAE,aAAoB,IAAgB,KAAM,IAAI,WAAU,qCAEhH,WAA2B,EAAQ,EAAO,CAAE,OAAS,GAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CAAE,GAAI,GAAa,EAAM,GAAI,EAAW,WAAa,EAAW,YAAc,GAAO,EAAW,aAAe,GAAU,SAAW,IAAY,GAAW,SAAW,IAAM,OAAO,eAAe,EAAQ,EAAW,IAAK,IAE7S,WAAsB,EAAa,EAAY,EAAa,CAAE,MAAI,IAAY,EAAkB,EAAY,UAAW,GAAiB,GAAa,EAAkB,EAAa,GAAqB,EAQzM,GAAI,GAA+B,UAAY,CAI7C,WAAyB,EAAS,CAChC,EAAgB,KAAM,GAEtB,KAAK,eAAe,GACpB,KAAK,gBAQP,SAAa,EAAiB,CAAC,CAC7B,IAAK,iBACL,MAAO,UAA0B,CAC/B,GAAI,GAAU,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,GAClF,KAAK,OAAS,EAAQ,OACtB,KAAK,UAAY,EAAQ,UACzB,KAAK,QAAU,EAAQ,QACvB,KAAK,OAAS,EAAQ,OACtB,KAAK,KAAO,EAAQ,KACpB,KAAK,QAAU,EAAQ,QACvB,KAAK,aAAe,KAOrB,CACD,IAAK,gBACL,MAAO,UAAyB,CAC9B,AAAI,KAAK,KACP,KAAK,aACI,KAAK,QACd,KAAK,iBAOR,CACD,IAAK,oBACL,MAAO,UAA6B,CAClC,GAAI,GAAQ,SAAS,gBAAgB,aAAa,SAAW,MAC7D,KAAK,SAAW,SAAS,cAAc,YAEvC,KAAK,SAAS,MAAM,SAAW,OAE/B,KAAK,SAAS,MAAM,OAAS,IAC7B,KAAK,SAAS,MAAM,QAAU,IAC9B,KAAK,SAAS,MAAM,OAAS,IAE7B,KAAK,SAAS,MAAM,SAAW,WAC/B,KAAK,SAAS,MAAM,EAAQ,QAAU,QAAU,UAEhD,GAAI,GAAY,OAAO,aAAe,SAAS,gBAAgB,UAC/D,YAAK,SAAS,MAAM,IAAM,GAAG,OAAO,EAAW,MAC/C,KAAK,SAAS,aAAa,WAAY,IACvC,KAAK,SAAS,MAAQ,KAAK,KACpB,KAAK,WAOb,CACD,IAAK,aACL,MAAO,UAAsB,CAC3B,GAAI,GAAQ,KAER,EAAW,KAAK,oBAEpB,KAAK,oBAAsB,UAAY,CACrC,MAAO,GAAM,cAGf,KAAK,YAAc,KAAK,UAAU,iBAAiB,QAAS,KAAK,sBAAwB,GACzF,KAAK,UAAU,YAAY,GAC3B,KAAK,aAAe,IAAiB,GACrC,KAAK,WACL,KAAK,eAON,CACD,IAAK,aACL,MAAO,UAAsB,CAC3B,AAAI,KAAK,aACP,MAAK,UAAU,oBAAoB,QAAS,KAAK,qBACjD,KAAK,YAAc,KACnB,KAAK,oBAAsB,MAGzB,KAAK,UACP,MAAK,UAAU,YAAY,KAAK,UAChC,KAAK,SAAW,QAOnB,CACD,IAAK,eACL,MAAO,UAAwB,CAC7B,KAAK,aAAe,IAAiB,KAAK,QAC1C,KAAK,aAMN,CACD,IAAK,WACL,MAAO,UAAoB,CACzB,GAAI,GAEJ,GAAI,CACF,EAAY,SAAS,YAAY,KAAK,cAC/B,EAAP,CACA,EAAY,GAGd,KAAK,aAAa,KAOnB,CACD,IAAK,eACL,MAAO,SAAsB,EAAW,CACtC,KAAK,QAAQ,KAAK,EAAY,UAAY,QAAS,CACjD,OAAQ,KAAK,OACb,KAAM,KAAK,aACX,QAAS,KAAK,QACd,eAAgB,KAAK,eAAe,KAAK,UAO5C,CACD,IAAK,iBACL,MAAO,UAA0B,CAC/B,AAAI,KAAK,SACP,KAAK,QAAQ,QAGf,SAAS,cAAc,OACvB,OAAO,eAAe,oBAOvB,CACD,IAAK,UAKL,MAAO,UAAmB,CACxB,KAAK,eAEN,CACD,IAAK,SACL,IAAK,UAAe,CAClB,GAAI,GAAS,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,OAGjF,GAFA,KAAK,QAAU,EAEX,KAAK,UAAY,QAAU,KAAK,UAAY,MAC9C,KAAM,IAAI,OAAM,uDAQpB,IAAK,UAAe,CAClB,MAAO,MAAK,UAQb,CACD,IAAK,SACL,IAAK,SAAa,EAAQ,CACxB,GAAI,IAAW,OACb,GAAI,GAAU,EAAQ,KAAY,UAAY,EAAO,WAAa,EAAG,CACnE,GAAI,KAAK,SAAW,QAAU,EAAO,aAAa,YAChD,KAAM,IAAI,OAAM,qFAGlB,GAAI,KAAK,SAAW,OAAU,GAAO,aAAa,aAAe,EAAO,aAAa,aACnF,KAAM,IAAI,OAAM,yGAGlB,KAAK,QAAU,MAEf,MAAM,IAAI,OAAM,gDAStB,IAAK,UAAe,CAClB,MAAO,MAAK,YAIT,KAGwB,EAAoB,EAErD,WAA0B,EAAK,CAA6B,MAAI,OAAO,SAAW,YAAc,MAAO,QAAO,UAAa,SAAY,EAAmB,SAAiB,EAAK,CAAE,MAAO,OAAO,IAAiB,EAAmB,SAAiB,EAAK,CAAE,MAAO,IAAO,MAAO,SAAW,YAAc,EAAI,cAAgB,QAAU,IAAQ,OAAO,UAAY,SAAW,MAAO,IAAiB,EAAiB,GAEvZ,WAAkC,EAAU,EAAa,CAAE,GAAI,CAAE,aAAoB,IAAgB,KAAM,IAAI,WAAU,qCAEzH,YAAoC,EAAQ,EAAO,CAAE,OAAS,GAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CAAE,GAAI,GAAa,EAAM,GAAI,EAAW,WAAa,EAAW,YAAc,GAAO,EAAW,aAAe,GAAU,SAAW,IAAY,GAAW,SAAW,IAAM,OAAO,eAAe,EAAQ,EAAW,IAAK,IAEtT,YAA+B,EAAa,EAAY,EAAa,CAAE,MAAI,IAAY,GAA2B,EAAY,UAAW,GAAiB,GAAa,GAA2B,EAAa,GAAqB,EAEpO,YAAmB,EAAU,EAAY,CAAE,GAAI,MAAO,IAAe,YAAc,IAAe,KAAQ,KAAM,IAAI,WAAU,sDAAyD,EAAS,UAAY,OAAO,OAAO,GAAc,EAAW,UAAW,CAAE,YAAa,CAAE,MAAO,EAAU,SAAU,GAAM,aAAc,MAAe,GAAY,GAAgB,EAAU,GAEnX,YAAyB,EAAG,EAAG,CAAE,UAAkB,OAAO,gBAAkB,SAAyB,EAAG,EAAG,CAAE,SAAE,UAAY,EAAU,GAAa,GAAgB,EAAG,GAErK,YAAsB,EAAS,CAAE,GAAI,GAA4B,KAA6B,MAAO,WAAgC,CAAE,GAAI,GAAQ,GAAgB,GAAU,EAAQ,GAAI,EAA2B,CAAE,GAAI,IAAY,GAAgB,MAAM,YAAa,EAAS,QAAQ,UAAU,EAAO,UAAW,QAAqB,GAAS,EAAM,MAAM,KAAM,WAAc,MAAO,IAA2B,KAAM,IAE5Z,YAAoC,EAAM,EAAM,CAAE,MAAI,IAAS,GAAiB,KAAU,UAAY,MAAO,IAAS,YAAsB,EAAe,GAAuB,GAElL,YAAgC,EAAM,CAAE,GAAI,IAAS,OAAU,KAAM,IAAI,gBAAe,6DAAgE,MAAO,GAE/J,aAAqC,CAA0E,GAApE,MAAO,UAAY,aAAe,CAAC,QAAQ,WAA6B,QAAQ,UAAU,KAAM,MAAO,GAAO,GAAI,MAAO,QAAU,WAAY,MAAO,GAAM,GAAI,CAAE,YAAK,UAAU,SAAS,KAAK,QAAQ,UAAU,KAAM,GAAI,UAAY,KAAa,SAAe,EAAP,CAAY,MAAO,IAE1T,YAAyB,EAAG,CAAE,UAAkB,OAAO,eAAiB,OAAO,eAAiB,SAAyB,EAAG,CAAE,MAAO,GAAE,WAAa,OAAO,eAAe,IAAc,GAAgB,GAWxM,YAA2B,EAAQ,EAAS,CAC1C,GAAI,GAAY,kBAAkB,OAAO,GAEzC,GAAI,EAAC,EAAQ,aAAa,GAI1B,MAAO,GAAQ,aAAa,GAQ9B,GAAI,IAAyB,SAAU,EAAU,CAC/C,GAAU,EAAW,GAErB,GAAI,GAAS,GAAa,GAM1B,WAAmB,EAAS,EAAS,CACnC,GAAI,IAEJ,SAAyB,KAAM,GAE/B,GAAQ,EAAO,KAAK,MAEpB,GAAM,eAAe,GAErB,GAAM,YAAY,GAEX,GAST,UAAsB,EAAW,CAAC,CAChC,IAAK,iBACL,MAAO,UAA0B,CAC/B,GAAI,GAAU,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,GAClF,KAAK,OAAS,MAAO,GAAQ,QAAW,WAAa,EAAQ,OAAS,KAAK,cAC3E,KAAK,OAAS,MAAO,GAAQ,QAAW,WAAa,EAAQ,OAAS,KAAK,cAC3E,KAAK,KAAO,MAAO,GAAQ,MAAS,WAAa,EAAQ,KAAO,KAAK,YACrE,KAAK,UAAY,EAAiB,EAAQ,aAAe,SAAW,EAAQ,UAAY,SAAS,OAOlG,CACD,IAAK,cACL,MAAO,SAAqB,EAAS,CACnC,GAAI,IAAS,KAEb,KAAK,SAAW,IAAiB,EAAS,QAAS,SAAU,GAAG,CAC9D,MAAO,IAAO,QAAQ,QAQzB,CACD,IAAK,UACL,MAAO,SAAiB,EAAG,CACzB,GAAI,IAAU,EAAE,gBAAkB,EAAE,cAEpC,AAAI,KAAK,iBACP,MAAK,gBAAkB,MAGzB,KAAK,gBAAkB,GAAI,GAAiB,CAC1C,OAAQ,KAAK,OAAO,IACpB,OAAQ,KAAK,OAAO,IACpB,KAAM,KAAK,KAAK,IAChB,UAAW,KAAK,UAChB,QAAS,GACT,QAAS,SAQZ,CACD,IAAK,gBACL,MAAO,SAAuB,EAAS,CACrC,MAAO,IAAkB,SAAU,KAOpC,CACD,IAAK,gBACL,MAAO,SAAuB,EAAS,CACrC,GAAI,IAAW,GAAkB,SAAU,GAE3C,GAAI,GACF,MAAO,UAAS,cAAc,MASjC,CACD,IAAK,cAML,MAAO,SAAqB,EAAS,CACnC,MAAO,IAAkB,OAAQ,KAMlC,CACD,IAAK,UACL,MAAO,UAAmB,CACxB,KAAK,SAAS,UAEV,KAAK,iBACP,MAAK,gBAAgB,UACrB,KAAK,gBAAkB,SAGzB,CAAC,CACH,IAAK,cACL,MAAO,UAAuB,CAC5B,GAAI,GAAS,UAAU,OAAS,GAAK,UAAU,KAAO,OAAY,UAAU,GAAK,CAAC,OAAQ,OACtF,GAAU,MAAO,IAAW,SAAW,CAAC,GAAU,EAClD,GAAU,CAAC,CAAC,SAAS,sBACzB,UAAQ,QAAQ,SAAU,GAAQ,CAChC,GAAU,IAAW,CAAC,CAAC,SAAS,sBAAsB,MAEjD,OAIJ,GACN,KAE8B,GAAa,IAIxC,IACC,SAAS,EAAQ,CAExB,GAAI,GAAqB,EAKzB,GAAI,MAAO,UAAY,aAAe,CAAC,QAAQ,UAAU,QAAS,CAC9D,GAAI,GAAQ,QAAQ,UAEpB,EAAM,QAAU,EAAM,iBACN,EAAM,oBACN,EAAM,mBACN,EAAM,kBACN,EAAM,sBAU1B,WAAkB,EAAS,EAAU,CACjC,KAAO,GAAW,EAAQ,WAAa,GAAoB,CACvD,GAAI,MAAO,GAAQ,SAAY,YAC3B,EAAQ,QAAQ,GAClB,MAAO,GAET,EAAU,EAAQ,YAI1B,EAAO,QAAU,GAKX,IACC,SAAS,EAAQ,EAA0B,EAAqB,CAEvE,GAAI,GAAU,EAAoB,KAYlC,WAAmB,EAAS,EAAU,EAAM,EAAU,EAAY,CAC9D,GAAI,GAAa,EAAS,MAAM,KAAM,WAEtC,SAAQ,iBAAiB,EAAM,EAAY,GAEpC,CACH,QAAS,UAAW,CAChB,EAAQ,oBAAoB,EAAM,EAAY,KAe1D,WAAkB,EAAU,EAAU,EAAM,EAAU,EAAY,CAE9D,MAAI,OAAO,GAAS,kBAAqB,WAC9B,EAAU,MAAM,KAAM,WAI7B,MAAO,IAAS,WAGT,EAAU,KAAK,KAAM,UAAU,MAAM,KAAM,WAIlD,OAAO,IAAa,UACpB,GAAW,SAAS,iBAAiB,IAIlC,MAAM,UAAU,IAAI,KAAK,EAAU,SAAU,EAAS,CACzD,MAAO,GAAU,EAAS,EAAU,EAAM,EAAU,MAa5D,WAAkB,EAAS,EAAU,EAAM,EAAU,CACjD,MAAO,UAAS,EAAG,CACf,EAAE,eAAiB,EAAQ,EAAE,OAAQ,GAEjC,EAAE,gBACF,EAAS,KAAK,EAAS,IAKnC,EAAO,QAAU,GAKX,IACC,SAAS,EAAyB,EAAS,CAQlD,EAAQ,KAAO,SAAS,EAAO,CAC3B,MAAO,KAAU,QACV,YAAiB,cACjB,EAAM,WAAa,GAS9B,EAAQ,SAAW,SAAS,EAAO,CAC/B,GAAI,GAAO,OAAO,UAAU,SAAS,KAAK,GAE1C,MAAO,KAAU,QACT,KAAS,qBAAuB,IAAS,4BACzC,UAAY,IACZ,GAAM,SAAW,GAAK,EAAQ,KAAK,EAAM,MASrD,EAAQ,OAAS,SAAS,EAAO,CAC7B,MAAO,OAAO,IAAU,UACjB,YAAiB,SAS5B,EAAQ,GAAK,SAAS,EAAO,CACzB,GAAI,GAAO,OAAO,UAAU,SAAS,KAAK,GAE1C,MAAO,KAAS,sBAMd,IACC,SAAS,EAAQ,EAA0B,EAAqB,CAEvE,GAAI,GAAK,EAAoB,KACzB,EAAW,EAAoB,KAWnC,WAAgB,EAAQ,EAAM,EAAU,CACpC,GAAI,CAAC,GAAU,CAAC,GAAQ,CAAC,EACrB,KAAM,IAAI,OAAM,8BAGpB,GAAI,CAAC,EAAG,OAAO,GACX,KAAM,IAAI,WAAU,oCAGxB,GAAI,CAAC,EAAG,GAAG,GACP,KAAM,IAAI,WAAU,qCAGxB,GAAI,EAAG,KAAK,GACR,MAAO,GAAW,EAAQ,EAAM,GAE/B,GAAI,EAAG,SAAS,GACjB,MAAO,GAAe,EAAQ,EAAM,GAEnC,GAAI,EAAG,OAAO,GACf,MAAO,GAAe,EAAQ,EAAM,GAGpC,KAAM,IAAI,WAAU,6EAa5B,WAAoB,EAAM,EAAM,EAAU,CACtC,SAAK,iBAAiB,EAAM,GAErB,CACH,QAAS,UAAW,CAChB,EAAK,oBAAoB,EAAM,KAc3C,WAAwB,EAAU,EAAM,EAAU,CAC9C,aAAM,UAAU,QAAQ,KAAK,EAAU,SAAS,EAAM,CAClD,EAAK,iBAAiB,EAAM,KAGzB,CACH,QAAS,UAAW,CAChB,MAAM,UAAU,QAAQ,KAAK,EAAU,SAAS,EAAM,CAClD,EAAK,oBAAoB,EAAM,OAe/C,WAAwB,EAAU,EAAM,EAAU,CAC9C,MAAO,GAAS,SAAS,KAAM,EAAU,EAAM,GAGnD,EAAO,QAAU,GAKX,IACC,SAAS,EAAQ,CAExB,WAAgB,EAAS,CACrB,GAAI,GAEJ,GAAI,EAAQ,WAAa,SACrB,EAAQ,QAER,EAAe,EAAQ,cAElB,EAAQ,WAAa,SAAW,EAAQ,WAAa,WAAY,CACtE,GAAI,GAAa,EAAQ,aAAa,YAEtC,AAAK,GACD,EAAQ,aAAa,WAAY,IAGrC,EAAQ,SACR,EAAQ,kBAAkB,EAAG,EAAQ,MAAM,QAEtC,GACD,EAAQ,gBAAgB,YAG5B,EAAe,EAAQ,UAEtB,CACD,AAAI,EAAQ,aAAa,oBACrB,EAAQ,QAGZ,GAAI,GAAY,OAAO,eACnB,EAAQ,SAAS,cAErB,EAAM,mBAAmB,GACzB,EAAU,kBACV,EAAU,SAAS,GAEnB,EAAe,EAAU,WAG7B,MAAO,GAGX,EAAO,QAAU,GAKX,IACC,SAAS,EAAQ,CAExB,YAAc,EAKd,EAAE,UAAY,CACZ,GAAI,SAAU,EAAM,EAAU,EAAK,CACjC,GAAI,GAAI,KAAK,GAAM,MAAK,EAAI,IAE5B,MAAC,GAAE,IAAU,GAAE,GAAQ,KAAK,KAAK,CAC/B,GAAI,EACJ,IAAK,IAGA,MAGT,KAAM,SAAU,EAAM,EAAU,EAAK,CACnC,GAAI,GAAO,KACX,YAAqB,CACnB,EAAK,IAAI,EAAM,GACf,EAAS,MAAM,EAAK,WAGtB,SAAS,EAAI,EACN,KAAK,GAAG,EAAM,EAAU,IAGjC,KAAM,SAAU,EAAM,CACpB,GAAI,GAAO,GAAG,MAAM,KAAK,UAAW,GAChC,EAAW,OAAK,GAAM,MAAK,EAAI,KAAK,IAAS,IAAI,QACjD,EAAI,EACJ,EAAM,EAAO,OAEjB,IAAK,EAAG,EAAI,EAAK,IACf,EAAO,GAAG,GAAG,MAAM,EAAO,GAAG,IAAK,GAGpC,MAAO,OAGT,IAAK,SAAU,EAAM,EAAU,CAC7B,GAAI,GAAI,KAAK,GAAM,MAAK,EAAI,IACxB,EAAO,EAAE,GACT,EAAa,GAEjB,GAAI,GAAQ,EACV,OAAS,GAAI,EAAG,EAAM,EAAK,OAAQ,EAAI,EAAK,IAC1C,AAAI,EAAK,GAAG,KAAO,GAAY,EAAK,GAAG,GAAG,IAAM,GAC9C,EAAW,KAAK,EAAK,IAQ3B,MAAC,GAAW,OACR,EAAE,GAAQ,EACV,MAAO,GAAE,GAEN,OAIX,EAAO,QAAU,EACjB,EAAO,QAAQ,YAAc,IAQf,EAA2B,GAG/B,WAA6B,EAAU,CAEtC,GAAG,EAAyB,GAC3B,MAAO,GAAyB,GAAU,QAG3C,GAAI,GAAS,EAAyB,GAAY,CAGjD,QAAS,IAIV,SAAoB,GAAU,EAAQ,EAAO,QAAS,GAG/C,EAAO,QAKf,MAAC,WAAW,CAEX,EAAoB,EAAI,SAAS,EAAQ,CACxC,GAAI,GAAS,GAAU,EAAO,WAC7B,UAAW,CAAE,MAAO,GAAO,SAC3B,UAAW,CAAE,MAAO,IACrB,SAAoB,EAAE,EAAQ,CAAE,EAAG,IAC5B,MAKR,UAAW,CAEX,EAAoB,EAAI,SAAS,EAAS,EAAY,CACrD,OAAQ,KAAO,GACd,AAAG,EAAoB,EAAE,EAAY,IAAQ,CAAC,EAAoB,EAAE,EAAS,IAC5E,OAAO,eAAe,EAAS,EAAK,CAAE,WAAY,GAAM,IAAK,EAAW,SAO3E,UAAW,CACX,EAAoB,EAAI,SAAS,EAAK,EAAM,CAAE,MAAO,QAAO,UAAU,eAAe,KAAK,EAAK,OAOzF,EAAoB,QAEpC,YCx7BD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAQA,aAOA,GAAI,IAAkB,UAOtB,GAAO,QAAU,GAUjB,YAAoB,EAAQ,CAC1B,GAAI,GAAM,GAAK,EACX,EAAQ,GAAgB,KAAK,GAEjC,GAAI,CAAC,EACH,MAAO,GAGT,GAAI,GACA,EAAO,GACP,EAAQ,EACR,EAAY,EAEhB,IAAK,EAAQ,EAAM,MAAO,EAAQ,EAAI,OAAQ,IAAS,CACrD,OAAQ,EAAI,WAAW,QAChB,IACH,EAAS,SACT,UACG,IACH,EAAS,QACT,UACG,IACH,EAAS,QACT,UACG,IACH,EAAS,OACT,UACG,IACH,EAAS,OACT,cAEA,SAGJ,AAAI,IAAc,GAChB,IAAQ,EAAI,UAAU,EAAW,IAGnC,EAAY,EAAQ,EACpB,GAAQ,EAGV,MAAO,KAAc,EACjB,EAAO,EAAI,UAAU,EAAW,GAChC,KCtDN,OAAO,SCtBP,OAAkB,SACZ,CACF,YACA,YACA,UACA,cACA,WACA,cACA,aACA,eACA,gBACA,mBACA,YACA,SACA,YACA,kBACA,gBACA,WACA,oBACA,oBACA,iBACA,wBACA,gBACA,mBACA,0BACA,2BACA,WCtBE,WAAqB,EAAU,CACnC,MAAO,OAAO,IAAU,WCIpB,YAA8B,EAAgC,CAClE,GAAM,GAAS,SAAC,EAAa,CAC3B,MAAM,KAAK,GACX,EAAS,MAAQ,GAAI,SAAQ,OAGzB,EAAW,EAAW,GAC5B,SAAS,UAAY,OAAO,OAAO,MAAM,WACzC,EAAS,UAAU,YAAc,EAC1B,ECAF,GAAM,IAA+C,GAC1D,SAAC,EAAM,CACL,MAAA,UAA4C,EAA0B,CACpE,EAAO,MACP,KAAK,QAAU,EACR,EAAO,OAAM;EACxB,EAAO,IAAI,SAAC,EAAK,EAAC,CAAK,MAAG,GAAI,EAAC,KAAK,EAAI,aAAc,KAAK;KACnD,GACJ,KAAK,KAAO,sBACZ,KAAK,OAAS,KCtBd,YAAuB,EAA6B,EAAO,CAC/D,GAAI,EAAK,CACP,GAAM,GAAQ,EAAI,QAAQ,GAC1B,GAAK,GAAS,EAAI,OAAO,EAAO,ICSpC,GAAA,IAAA,UAAA,CAyBE,WAAoB,EAA4B,CAA5B,KAAA,gBAAA,EAdb,KAAA,OAAS,GAER,KAAA,WAAmD,KAMnD,KAAA,WAAoD,KAc5D,SAAA,UAAA,YAAA,UAAA,aACM,EAEJ,GAAI,CAAC,KAAK,OAAQ,CAChB,KAAK,OAAS,GAGN,GAAA,GAAe,KAAI,WAC3B,GAAI,EAEF,GADA,KAAK,WAAa,KACd,MAAM,QAAQ,OAChB,OAAqB,GAAA,GAAA,GAAU,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAA5B,GAAM,GAAM,EAAA,MACf,EAAO,OAAO,4GAGhB,GAAW,OAAO,MAId,GAAA,GAAoB,KAAI,gBAChC,GAAI,EAAW,GACb,GAAI,CACF,UACO,EAAP,CACA,EAAS,YAAa,IAAsB,EAAE,OAAS,CAAC,GAIpD,GAAA,GAAe,KAAI,WAC3B,GAAI,EAAY,CACd,KAAK,WAAa,SAClB,OAAuB,GAAA,GAAA,GAAU,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAA9B,GAAM,GAAQ,EAAA,MACjB,GAAI,CACF,GAAa,SACN,EAAP,CACA,EAAS,GAAM,KAAN,EAAU,GACnB,AAAI,YAAe,IACjB,EAAM,EAAA,EAAA,GAAA,EAAO,IAAM,EAAK,EAAI,SAE5B,EAAO,KAAK,uGAMpB,GAAI,EACF,KAAM,IAAI,IAAoB,KAuBpC,EAAA,UAAA,IAAA,SAAI,EAAuB,OAGzB,GAAI,GAAY,IAAa,KAC3B,GAAI,KAAK,OAGP,GAAa,OACR,CACL,GAAI,YAAoB,GAAc,CAGpC,GAAI,EAAS,QAAU,EAAS,WAAW,MACzC,OAEF,EAAS,WAAW,MAEtB,AAAC,MAAK,WAAa,GAAA,KAAK,cAAU,MAAA,IAAA,OAAA,EAAI,IAAI,KAAK,KAU7C,EAAA,UAAA,WAAR,SAAmB,EAAoB,CAC7B,GAAA,GAAe,KAAI,WAC3B,MAAO,KAAe,GAAW,MAAM,QAAQ,IAAe,EAAW,SAAS,IAU5E,EAAA,UAAA,WAAR,SAAmB,EAAoB,CAC7B,GAAA,GAAe,KAAI,WAC3B,KAAK,WAAa,MAAM,QAAQ,GAAe,GAAW,KAAK,GAAS,GAAc,EAAa,CAAC,EAAY,GAAU,GAOpH,EAAA,UAAA,cAAR,SAAsB,EAAoB,CAChC,GAAA,GAAe,KAAI,WAC3B,AAAI,IAAe,EACjB,KAAK,WAAa,KACT,MAAM,QAAQ,IACvB,GAAU,EAAY,IAkB1B,EAAA,UAAA,OAAA,SAAO,EAAsC,CACnC,GAAA,GAAe,KAAI,WAC3B,GAAc,GAAU,EAAY,GAEhC,YAAoB,IACtB,EAAS,cAAc,OAhLb,EAAA,MAAS,UAAA,CACrB,GAAM,GAAQ,GAAI,GAClB,SAAM,OAAS,GACR,KAgLX,KAEO,GAAM,IAAqB,GAAa,MAEzC,YAAyB,EAAU,CACvC,MACE,aAAiB,KAChB,GAAS,UAAY,IAAS,EAAW,EAAM,SAAW,EAAW,EAAM,MAAQ,EAAW,EAAM,aAIzG,YAAsB,EAAuC,CAC3D,AAAI,EAAW,GACb,IAEA,EAAS,cC9MN,GAAM,IAAuB,CAClC,iBAAkB,KAClB,sBAAuB,KACvB,QAAS,OACT,sCAAuC,GACvC,yBAA0B,ICErB,GAAM,IAAmC,CAG9C,WAAU,UAAA,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACD,GAAA,GAAa,GAAe,SACpC,MAAQ,KAAQ,KAAA,OAAR,EAAU,aAAc,YAAW,MAAA,OAAA,EAAA,GAAA,EAAI,MAEjD,aAAY,SAAC,EAAM,CACT,GAAA,GAAa,GAAe,SACpC,MAAQ,KAAQ,KAAA,OAAR,EAAU,eAAgB,cAAc,IAElD,SAAU,QCbN,YAA+B,EAAQ,CAC3C,GAAgB,WAAW,UAAA,CACjB,GAAA,GAAqB,GAAM,iBACnC,GAAI,EAEF,EAAiB,OAGjB,MAAM,KCnBN,aAAc,ECMb,GAAM,IAAyB,UAAA,CAAM,MAAA,IAAmB,IAAK,OAAW,WAOzE,YAA4B,EAAU,CAC1C,MAAO,IAAmB,IAAK,OAAW,GAQtC,YAA8B,EAAQ,CAC1C,MAAO,IAAmB,IAAK,EAAO,QASlC,YAA6B,EAAuB,EAAY,EAAU,CAC9E,MAAO,CACL,KAAI,EACJ,MAAK,EACL,MAAK,GCnCT,GAAI,IAAuD,KASrD,YAAuB,EAAc,CACzC,GAAI,GAAO,sCAAuC,CAChD,GAAM,GAAS,CAAC,GAKhB,GAJI,GACF,IAAU,CAAE,YAAa,GAAO,MAAO,OAEzC,IACI,EAAQ,CACJ,GAAA,GAAyB,GAAvB,EAAW,EAAA,YAAE,EAAK,EAAA,MAE1B,GADA,GAAU,KACN,EACF,KAAM,QAMV,KAQE,YAAuB,EAAQ,CACnC,AAAI,GAAO,uCAAyC,IAClD,IAAQ,YAAc,GACtB,GAAQ,MAAQ,GCnBpB,GAAA,IAAA,SAAA,EAAA,CAAmC,EAAA,EAAA,GA6BjC,WAAY,EAA6C,CAAzD,GAAA,GACE,EAAA,KAAA,OAAO,KATC,SAAA,UAAqB,GAU7B,AAAI,EACF,GAAK,YAAc,EAGf,GAAe,IACjB,EAAY,IAAI,IAGlB,EAAK,YAAc,KAvBhB,SAAA,OAAP,SAAiB,EAAwB,EAA2B,EAAqB,CACvF,MAAO,IAAI,IAAe,EAAM,EAAO,IAiCzC,EAAA,UAAA,KAAA,SAAK,EAAS,CACZ,AAAI,KAAK,UACP,GAA0B,GAAiB,GAAQ,MAEnD,KAAK,MAAM,IAWf,EAAA,UAAA,MAAA,SAAM,EAAS,CACb,AAAI,KAAK,UACP,GAA0B,GAAkB,GAAM,MAElD,MAAK,UAAY,GACjB,KAAK,OAAO,KAUhB,EAAA,UAAA,SAAA,UAAA,CACE,AAAI,KAAK,UACP,GAA0B,GAAuB,MAEjD,MAAK,UAAY,GACjB,KAAK,cAIT,EAAA,UAAA,YAAA,UAAA,CACE,AAAK,KAAK,QACR,MAAK,UAAY,GACjB,EAAA,UAAM,YAAW,KAAA,MACjB,KAAK,YAAc,OAIb,EAAA,UAAA,MAAV,SAAgB,EAAQ,CACtB,KAAK,YAAY,KAAK,IAGd,EAAA,UAAA,OAAV,SAAiB,EAAQ,CACvB,GAAI,CACF,KAAK,YAAY,MAAM,WAEvB,KAAK,gBAIC,EAAA,UAAA,UAAV,UAAA,CACE,GAAI,CACF,KAAK,YAAY,mBAEjB,KAAK,gBAGX,GApHmC,IAsHnC,GAAA,IAAA,SAAA,EAAA,CAAuC,EAAA,EAAA,GACrC,WACE,EACA,EACA,EAA8B,CAHhC,GAAA,GAKE,EAAA,KAAA,OAAO,KAEH,EACJ,GAAI,EAAW,GAGb,EAAO,UACE,EAAgB,CAMzB,AAAG,EAA0B,EAAc,KAAlC,EAAoB,EAAc,MAA3B,EAAa,EAAc,SAC3C,GAAI,GACJ,AAAI,GAAQ,GAAO,yBAIjB,GAAU,OAAO,OAAO,GACxB,EAAQ,YAAc,UAAA,CAAM,MAAA,GAAK,gBAEjC,EAAU,EAEZ,EAAO,GAAI,KAAA,OAAJ,EAAM,KAAK,GAClB,EAAQ,GAAK,KAAA,OAAL,EAAO,KAAK,GACpB,EAAW,GAAQ,KAAA,OAAR,EAAU,KAAK,GAK5B,SAAK,YAAc,CACjB,KAAM,EAAO,GAAqB,EAAM,GAAQ,GAChD,MAAO,GAAqB,GAAK,KAAL,EAAS,GAAqB,GAC1D,SAAU,EAAW,GAAqB,EAAU,GAAQ,MAGlE,MAAA,IA3CuC,IAoDvC,YAA8B,EAA8B,EAA6B,CACvF,MAAO,WAAA,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACN,GAAI,CACF,EAAO,MAAA,OAAA,EAAA,GAAA,EAAI,WACJ,EAAP,CACA,AAAI,GAAO,sCACT,GAAa,GAIb,GAAqB,KAW7B,YAA6B,EAAQ,CACnC,KAAM,GAQR,YAAmC,EAA2C,EAA2B,CAC/F,GAAA,GAA0B,GAAM,sBACxC,GAAyB,GAAgB,WAAW,UAAA,CAAM,MAAA,GAAsB,EAAc,KAQzF,GAAM,IAA6D,CACxE,OAAQ,GACR,KAAM,GACN,MAAO,GACP,SAAU,ICzOL,GAAM,IAA+B,UAAA,CAAM,MAAC,OAAO,SAAW,YAAc,OAAO,YAAe,kBCDnG,YAAsB,EAAI,CAC9B,MAAO,GCsEH,aAAc,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACnB,MAAO,IAAc,GAIjB,YAA8B,EAA+B,CACjE,MAAI,GAAI,SAAW,EACV,GAGL,EAAI,SAAW,EACV,EAAI,GAGN,SAAe,EAAQ,CAC5B,MAAO,GAAI,OAAO,SAAC,EAAW,EAAuB,CAAK,MAAA,GAAG,IAAO,ICnExE,GAAA,GAAA,UAAA,CAkBE,WAAY,EAA6E,CACvF,AAAI,GACF,MAAK,WAAa,GA8BtB,SAAA,UAAA,KAAA,SAAQ,EAAyB,CAC/B,GAAM,GAAa,GAAI,GACvB,SAAW,OAAS,KACpB,EAAW,SAAW,EACf,GA2IT,EAAA,UAAA,UAAA,SACE,EACA,EACA,EAA8B,CAHhC,GAAA,GAAA,KAKQ,EAAa,GAAa,GAAkB,EAAiB,GAAI,IAAe,EAAgB,EAAO,GAE7G,UAAa,UAAA,CACL,GAAA,GAAuB,EAArB,EAAQ,EAAA,SAAE,EAAM,EAAA,OACxB,EAAW,IACT,EAGI,EAAS,KAAK,EAAY,GAC1B,EAIA,EAAK,WAAW,GAGhB,EAAK,cAAc,MAIpB,GAIC,EAAA,UAAA,cAAV,SAAwB,EAAmB,CACzC,GAAI,CACF,MAAO,MAAK,WAAW,SAChB,EAAP,CAIA,EAAK,MAAM,KA+Df,EAAA,UAAA,QAAA,SAAQ,EAA0B,EAAoC,CAAtE,GAAA,GAAA,KACE,SAAc,GAAe,GAEtB,GAAI,GAAkB,SAAC,EAAS,EAAM,CAG3C,GAAI,GACJ,EAAe,EAAK,UAClB,SAAC,EAAK,CACJ,GAAI,CACF,EAAK,SACE,EAAP,CACA,EAAO,GACP,GAAY,MAAZ,EAAc,gBAGlB,EACA,MAMI,EAAA,UAAA,WAAV,SAAqB,EAA2B,OAC9C,MAAO,GAAA,KAAK,UAAM,MAAA,IAAA,OAAA,OAAA,EAAE,UAAU,IAQhC,EAAA,UAAC,IAAD,UAAA,CACE,MAAO,OA6FT,EAAA,UAAA,KAAA,UAAA,QAAK,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACH,MAAO,IAAc,GAAY,OA8BnC,EAAA,UAAA,UAAA,SAAU,EAAoC,CAA9C,GAAA,GAAA,KACE,SAAc,GAAe,GAEtB,GAAI,GAAY,SAAC,EAAS,EAAM,CACrC,GAAI,GACJ,EAAK,UACH,SAAC,EAAI,CAAK,MAAC,GAAQ,GACnB,SAAC,EAAQ,CAAK,MAAA,GAAO,IACrB,UAAA,CAAM,MAAA,GAAQ,QAtab,EAAA,OAAkC,SAAI,EAAwD,CACnG,MAAO,IAAI,GAAc,IAya7B,KASA,YAAwB,EAA+C,OACrE,MAAO,GAAA,GAAW,KAAX,EAAe,GAAO,WAAO,MAAA,IAAA,OAAA,EAAI,QAG1C,YAAuB,EAAU,CAC/B,MAAO,IAAS,EAAW,EAAM,OAAS,EAAW,EAAM,QAAU,EAAW,EAAM,UAGxF,YAAyB,EAAU,CACjC,MAAQ,IAAS,YAAiB,KAAgB,GAAW,IAAU,GAAe,GC1elF,YAAkB,EAAW,CACjC,MAAO,GAAW,GAAM,KAAA,OAAN,EAAQ,MAOtB,WACJ,EAAqF,CAErF,MAAO,UAAC,EAAqB,CAC3B,GAAI,GAAQ,GACV,MAAO,GAAO,KAAK,SAA+B,EAA2B,CAC3E,GAAI,CACF,MAAO,GAAK,EAAc,YACnB,EAAP,CACA,KAAK,MAAM,MAIjB,KAAM,IAAI,WAAU,2CCvBxB,GAAA,GAAA,SAAA,EAAA,CAA2C,EAAA,EAAA,GAazC,WACE,EACA,EACA,EACA,EACQ,EAAuB,CALjC,GAAA,GAmBE,EAAA,KAAA,KAAM,IAAY,KAdV,SAAA,WAAA,EAeR,EAAK,MAAQ,EACT,SAAuC,EAAQ,CAC7C,GAAI,CACF,EAAO,SACA,EAAP,CACA,EAAY,MAAM,KAGtB,EAAA,UAAM,MACV,EAAK,OAAS,EACV,SAAuC,EAAQ,CAC7C,GAAI,CACF,EAAQ,SACD,EAAP,CAEA,EAAY,MAAM,WAGlB,KAAK,gBAGT,EAAA,UAAM,OACV,EAAK,UAAY,EACb,UAAA,CACE,GAAI,CACF,UACO,EAAP,CAEA,EAAY,MAAM,WAGlB,KAAK,gBAGT,EAAA,UAAM,YAGZ,SAAA,UAAA,YAAA,UAAA,OACU,EAAW,KAAI,OACvB,EAAA,UAAM,YAAW,KAAA,MAEjB,CAAC,GAAU,IAAA,KAAK,cAAU,MAAA,IAAA,QAAA,EAAA,KAAf,QAEf,GA5E2C,ICQpC,GAAM,IAAiD,CAG5D,SAAA,SAAS,EAAQ,CACf,GAAI,GAAU,sBACV,EAAkD,qBAC9C,EAAa,GAAsB,SAC3C,AAAI,GACF,GAAU,EAAS,sBACnB,EAAS,EAAS,sBAEpB,GAAM,GAAS,EAAQ,SAAC,EAAS,CAI/B,EAAS,OACT,EAAS,KAEX,MAAO,IAAI,IAAa,UAAA,CAAM,MAAA,IAAM,KAAA,OAAN,EAAS,MAEzC,sBAAqB,UAAA,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACZ,GAAA,GAAa,GAAsB,SAC3C,MAAQ,KAAQ,KAAA,OAAR,EAAU,wBAAyB,uBAAsB,MAAA,OAAA,EAAA,GAAA,EAAI,MAEvE,qBAAoB,UAAA,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACX,GAAA,GAAa,GAAsB,SAC3C,MAAQ,KAAQ,KAAA,OAAR,EAAU,uBAAwB,sBAAqB,MAAA,OAAA,EAAA,GAAA,EAAI,MAErE,SAAU,QCrBL,GAAM,IAAuD,GAClE,SAAC,EAAM,CACL,MAAA,WAAoC,CAClC,EAAO,MACP,KAAK,KAAO,0BACZ,KAAK,QAAU,yBCVrB,GAAA,GAAA,SAAA,EAAA,CAAgC,EAAA,EAAA,GAqB9B,YAAA,CAAA,GAAA,GAEE,EAAA,KAAA,OAAO,KAtBT,SAAA,OAAS,GAET,EAAA,UAA2B,GAE3B,EAAA,UAAY,GAEZ,EAAA,SAAW,GAEX,EAAA,YAAmB,OAkBnB,SAAA,UAAA,KAAA,SAAQ,EAAwB,CAC9B,GAAM,GAAU,GAAI,IAAiB,KAAM,MAC3C,SAAQ,SAAW,EACZ,GAIC,EAAA,UAAA,eAAV,UAAA,CACE,GAAI,KAAK,OACP,KAAM,IAAI,KAId,EAAA,UAAA,KAAA,SAAK,EAAQ,CAAb,GAAA,GAAA,KACE,GAAa,UAAA,SAEX,GADA,EAAK,iBACD,CAAC,EAAK,UAAW,CACnB,GAAM,GAAO,EAAK,UAAU,YAC5B,OAAuB,GAAA,GAAA,GAAI,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAAxB,GAAM,GAAQ,EAAA,MACjB,EAAS,KAAK,0GAMtB,EAAA,UAAA,MAAA,SAAM,EAAQ,CAAd,GAAA,GAAA,KACE,GAAa,UAAA,CAEX,GADA,EAAK,iBACD,CAAC,EAAK,UAAW,CACnB,EAAK,SAAW,EAAK,UAAY,GACjC,EAAK,YAAc,EAEnB,OADQ,GAAc,EAAI,UACnB,EAAU,QACf,EAAU,QAAS,MAAM,OAMjC,EAAA,UAAA,SAAA,UAAA,CAAA,GAAA,GAAA,KACE,GAAa,UAAA,CAEX,GADA,EAAK,iBACD,CAAC,EAAK,UAAW,CACnB,EAAK,UAAY,GAEjB,OADQ,GAAc,EAAI,UACnB,EAAU,QACf,EAAU,QAAS,eAM3B,EAAA,UAAA,YAAA,UAAA,CACE,KAAK,UAAY,KAAK,OAAS,GAC/B,KAAK,UAAY,MAGnB,OAAA,eAAI,EAAA,UAAA,WAAQ,KAAZ,UAAA,OACE,MAAO,IAAA,KAAK,aAAS,MAAA,IAAA,OAAA,OAAA,EAAE,QAAS,mCAIxB,EAAA,UAAA,cAAV,SAAwB,EAAyB,CAC/C,YAAK,iBACE,EAAA,UAAM,cAAa,KAAA,KAAC,IAInB,EAAA,UAAA,WAAV,SAAqB,EAAyB,CAC5C,YAAK,iBACL,KAAK,wBAAwB,GACtB,KAAK,gBAAgB,IAIpB,EAAA,UAAA,gBAAV,SAA0B,EAA2B,CAC7C,GAAA,GAAqC,KAAnC,EAAQ,EAAA,SAAE,EAAS,EAAA,UAAE,EAAS,EAAA,UACtC,MAAO,IAAY,EACf,GACC,GAAU,KAAK,GAAa,GAAI,IAAa,UAAA,CAAM,MAAA,IAAU,EAAW,OAIrE,EAAA,UAAA,wBAAV,SAAkC,EAA2B,CACrD,GAAA,GAAuC,KAArC,EAAQ,EAAA,SAAE,EAAW,EAAA,YAAE,EAAS,EAAA,UACxC,AAAI,EACF,EAAW,MAAM,GACR,GACT,EAAW,YAUf,EAAA,UAAA,aAAA,UAAA,CACE,GAAM,GAAkB,GAAI,GAC5B,SAAW,OAAS,KACb,GA/GF,EAAA,OAAkC,SAAI,EAA0B,EAAqB,CAC1F,MAAO,IAAI,IAAoB,EAAa,IAgHhD,GAlIgC,GAuIhC,GAAA,IAAA,SAAA,EAAA,CAAyC,EAAA,EAAA,GACvC,WAES,EACP,EAAsB,CAHxB,GAAA,GAKE,EAAA,KAAA,OAAO,KAHA,SAAA,YAAA,EAIP,EAAK,OAAS,IAGhB,SAAA,UAAA,KAAA,SAAK,EAAQ,SACX,AAAA,GAAA,GAAA,KAAK,eAAW,MAAA,IAAA,OAAA,OAAA,EAAE,QAAI,MAAA,IAAA,QAAA,EAAA,KAAA,EAAG,IAG3B,EAAA,UAAA,MAAA,SAAM,EAAQ,SACZ,AAAA,GAAA,GAAA,KAAK,eAAW,MAAA,IAAA,OAAA,OAAA,EAAE,SAAK,MAAA,IAAA,QAAA,EAAA,KAAA,EAAG,IAG5B,EAAA,UAAA,SAAA,UAAA,SACE,AAAA,GAAA,GAAA,KAAK,eAAW,MAAA,IAAA,OAAA,OAAA,EAAE,YAAQ,MAAA,IAAA,QAAA,EAAA,KAAA,IAIlB,EAAA,UAAA,WAAV,SAAqB,EAAyB,SAC5C,MAAO,GAAA,GAAA,KAAK,UAAM,MAAA,IAAA,OAAA,OAAA,EAAE,UAAU,MAAW,MAAA,IAAA,OAAA,EAAI,IAEjD,GA1ByC,GCjJlC,GAAM,IAA+C,CAC1D,IAAG,UAAA,CAGD,MAAQ,IAAsB,UAAY,MAAM,OAElD,SAAU,QCwBZ,GAAA,IAAA,SAAA,EAAA,CAAsC,EAAA,EAAA,GAUpC,WACU,EACA,EACA,EAA6D,CAF7D,AAAA,IAAA,QAAA,GAAA,KACA,IAAA,QAAA,GAAA,KACA,IAAA,QAAA,GAAA,IAHV,GAAA,GAKE,EAAA,KAAA,OAAO,KAJC,SAAA,YAAA,EACA,EAAA,YAAA,EACA,EAAA,mBAAA,EAZF,EAAA,QAA0B,GAC1B,EAAA,oBAAsB,GAc5B,EAAK,oBAAsB,IAAgB,IAC3C,EAAK,YAAc,KAAK,IAAI,EAAG,GAC/B,EAAK,YAAc,KAAK,IAAI,EAAG,KAGjC,SAAA,UAAA,KAAA,SAAK,EAAQ,CACL,GAAA,GAA+E,KAA7E,EAAS,EAAA,UAAE,EAAO,EAAA,QAAE,EAAmB,EAAA,oBAAE,EAAkB,EAAA,mBAAE,EAAW,EAAA,YAChF,AAAK,GACH,GAAQ,KAAK,GACb,CAAC,GAAuB,EAAQ,KAAK,EAAmB,MAAQ,IAElE,KAAK,cACL,EAAA,UAAM,KAAI,KAAA,KAAC,IAIH,EAAA,UAAA,WAAV,SAAqB,EAAyB,CAC5C,KAAK,iBACL,KAAK,cAQL,OANM,GAAe,KAAK,gBAAgB,GAEpC,EAAmC,KAAjC,EAAmB,EAAA,oBAAE,EAAO,EAAA,QAG9B,EAAO,EAAQ,QACZ,EAAI,EAAG,EAAI,EAAK,QAAU,CAAC,EAAW,OAAQ,GAAK,EAAsB,EAAI,EACpF,EAAW,KAAK,EAAK,IAGvB,YAAK,wBAAwB,GAEtB,GAGD,EAAA,UAAA,YAAR,UAAA,CACQ,GAAA,GAAoE,KAAlE,EAAW,EAAA,YAAE,EAAkB,EAAA,mBAAE,EAAO,EAAA,QAAE,EAAmB,EAAA,oBAK/D,EAAsB,GAAsB,EAAI,GAAK,EAK3D,GAJA,EAAc,KAAY,EAAqB,EAAQ,QAAU,EAAQ,OAAO,EAAG,EAAQ,OAAS,GAIhG,CAAC,EAAqB,CAKxB,OAJM,GAAM,EAAmB,MAC3B,EAAO,EAGF,EAAI,EAAG,EAAI,EAAQ,QAAW,EAAQ,IAAiB,EAAK,GAAK,EACxE,EAAO,EAET,GAAQ,EAAQ,OAAO,EAAG,EAAO,KAGvC,GAzEsC,GClBtC,GAAA,IAAA,SAAA,EAAA,CAA+B,EAAA,EAAA,GAC7B,WAAY,EAAsB,EAAmD,OACnF,GAAA,KAAA,OAAO,KAYF,SAAA,UAAA,SAAP,SAAgB,EAAW,EAAiB,CAAjB,MAAA,KAAA,QAAA,GAAA,GAClB,MAEX,GAjB+B,ICJxB,GAAM,IAAqC,CAGhD,YAAW,UAAA,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACF,GAAA,GAAa,GAAgB,SACrC,MAAQ,KAAQ,KAAA,OAAR,EAAU,cAAe,aAAY,MAAA,OAAA,EAAA,GAAA,EAAI,MAEnD,cAAa,SAAC,EAAM,CACV,GAAA,GAAa,GAAgB,SACrC,MAAQ,KAAQ,KAAA,OAAR,EAAU,gBAAiB,eAAe,IAEpD,SAAU,QClBZ,GAAA,IAAA,SAAA,EAAA,CAAoC,EAAA,EAAA,GAOlC,WAAsB,EAAqC,EAAmD,CAA9G,GAAA,GACE,EAAA,KAAA,KAAM,EAAW,IAAK,KADF,SAAA,UAAA,EAAqC,EAAA,KAAA,EAFjD,EAAA,QAAmB,KAMtB,SAAA,UAAA,SAAP,SAAgB,EAAW,EAAiB,CAC1C,GADyB,IAAA,QAAA,GAAA,GACrB,KAAK,OACP,MAAO,MAIT,KAAK,MAAQ,EAEb,GAAM,GAAK,KAAK,GACV,EAAY,KAAK,UAuBvB,MAAI,IAAM,MACR,MAAK,GAAK,KAAK,eAAe,EAAW,EAAI,IAK/C,KAAK,QAAU,GAEf,KAAK,MAAQ,EAEb,KAAK,GAAK,KAAK,IAAM,KAAK,eAAe,EAAW,KAAK,GAAI,GAEtD,MAGC,EAAA,UAAA,eAAV,SAAyB,EAA2B,EAAW,EAAiB,CAAjB,MAAA,KAAA,QAAA,GAAA,GACtD,GAAiB,YAAY,EAAU,MAAM,KAAK,EAAW,MAAO,IAGnE,EAAA,UAAA,eAAV,SAAyB,EAA4B,EAAS,EAAwB,CAEpF,GAF4D,IAAA,QAAA,GAAA,GAExD,GAAS,MAAQ,KAAK,QAAU,GAAS,KAAK,UAAY,GAC5D,MAAO,GAIT,GAAiB,cAAc,IAQ1B,EAAA,UAAA,QAAP,SAAe,EAAU,EAAa,CACpC,GAAI,KAAK,OACP,MAAO,IAAI,OAAM,gCAGnB,KAAK,QAAU,GACf,GAAM,GAAQ,KAAK,SAAS,EAAO,GACnC,GAAI,EACF,MAAO,GACF,AAAI,KAAK,UAAY,IAAS,KAAK,IAAM,MAc9C,MAAK,GAAK,KAAK,eAAe,KAAK,UAAW,KAAK,GAAI,QAIjD,EAAA,UAAA,SAAV,SAAmB,EAAU,EAAc,CACzC,GAAI,GAAmB,GACnB,EACJ,GAAI,CACF,KAAK,KAAK,SACH,EAAP,CACA,EAAU,GAIV,EAAa,GAAQ,GAAI,OAAM,sCAEjC,GAAI,EACF,YAAK,cACE,GAIX,EAAA,UAAA,YAAA,UAAA,CACE,GAAI,CAAC,KAAK,OAAQ,CACV,GAAA,GAAoB,KAAlB,EAAE,EAAA,GAAE,EAAS,EAAA,UACb,EAAY,EAAS,QAE7B,KAAK,KAAO,KAAK,MAAQ,KAAK,UAAY,KAC1C,KAAK,QAAU,GAEf,GAAU,EAAS,MACf,GAAM,MACR,MAAK,GAAK,KAAK,eAAe,EAAW,EAAI,OAG/C,KAAK,MAAQ,KACb,EAAA,UAAM,YAAW,KAAA,QAGvB,GA3IoC,ICiBpC,GAAA,IAAA,UAAA,CAGE,WAAoB,EAAoC,EAAiC,CAAjC,AAAA,IAAA,QAAA,GAAoB,EAAU,KAAlE,KAAA,oBAAA,EAClB,KAAK,IAAM,EA8BN,SAAA,UAAA,SAAP,SAAmB,EAAqD,EAAmB,EAAS,CAA5B,MAAA,KAAA,QAAA,GAAA,GAC/D,GAAI,MAAK,oBAAuB,KAAM,GAAM,SAAS,EAAO,IAlCvD,EAAA,IAAoB,GAAsB,IAoC1D,KCzDA,GAAA,IAAA,SAAA,EAAA,CAAoC,EAAA,EAAA,GAkBlC,WAAY,EAAgC,EAAiC,CAAjC,AAAA,IAAA,QAAA,GAAoB,GAAU,KAA1E,GAAA,GACE,EAAA,KAAA,KAAM,EAAiB,IAAI,KAlBtB,SAAA,QAAmC,GAOnC,EAAA,QAAmB,GAQnB,EAAA,WAAkB,SAMlB,SAAA,UAAA,MAAP,SAAa,EAAwB,CAC3B,GAAA,GAAY,KAAI,QAExB,GAAI,KAAK,QAAS,CAChB,EAAQ,KAAK,GACb,OAGF,GAAI,GACJ,KAAK,QAAU,GAEf,EACE,IAAK,EAAQ,EAAO,QAAQ,EAAO,MAAO,EAAO,OAC/C,YAEM,EAAS,EAAQ,SAI3B,GAFA,KAAK,QAAU,GAEX,EAAO,CACT,KAAQ,EAAS,EAAQ,SACvB,EAAO,cAET,KAAM,KAGZ,GAhDoC,IC8C7B,GAAM,IAAiB,GAAI,IAAe,IAKpC,GAAQ,GClDrB,GAAA,IAAA,SAAA,EAAA,CAA6C,EAAA,EAAA,GAC3C,WAAsB,EAA8C,EAAmD,CAAvH,GAAA,GACE,EAAA,KAAA,KAAM,EAAW,IAAK,KADF,SAAA,UAAA,EAA8C,EAAA,KAAA,IAI1D,SAAA,UAAA,eAAV,SAAyB,EAAoC,EAAU,EAAiB,CAEtF,MAFqE,KAAA,QAAA,GAAA,GAEjE,IAAU,MAAQ,EAAQ,EACrB,EAAA,UAAM,eAAc,KAAA,KAAC,EAAW,EAAI,GAG7C,GAAU,QAAQ,KAAK,MAIhB,EAAU,YAAe,GAAU,WAAa,GAAuB,sBAAsB,UAAA,CAAM,MAAA,GAAU,MAAM,aAElH,EAAA,UAAA,eAAV,SAAyB,EAAoC,EAAU,EAAiB,CAItF,GAJqE,IAAA,QAAA,GAAA,GAIhE,GAAS,MAAQ,EAAQ,GAAO,GAAS,MAAQ,KAAK,MAAQ,EACjE,MAAO,GAAA,UAAM,eAAc,KAAA,KAAC,EAAW,EAAI,GAK7C,AAAI,EAAU,QAAQ,SAAW,GAC/B,IAAuB,qBAAqB,GAC5C,EAAU,WAAa,SAK7B,GAlC6C,ICF7C,GAAA,IAAA,SAAA,EAAA,CAA6C,EAAA,EAAA,GAA7C,YAAA,gDACS,SAAA,UAAA,MAAP,SAAa,EAAyB,CACpC,KAAK,QAAU,GACf,KAAK,WAAa,OAEV,GAAA,GAAY,KAAI,QACpB,EACA,EAAQ,GACZ,EAAS,GAAU,EAAQ,QAC3B,GAAM,GAAQ,EAAQ,OAEtB,EACE,IAAK,EAAQ,EAAO,QAAQ,EAAO,MAAO,EAAO,OAC/C,YAEK,EAAE,EAAQ,GAAU,GAAS,EAAQ,UAI9C,GAFA,KAAK,QAAU,GAEX,EAAO,CACT,KAAO,EAAE,EAAQ,GAAU,GAAS,EAAQ,UAC1C,EAAO,cAET,KAAM,KAGZ,GA1B6C,ICgCtC,GAAM,GAA0B,GAAI,IAAwB,ICR5D,GAAM,IAAQ,GAAI,GAAkB,SAAC,EAAU,CAAK,MAAA,GAAW,aCxBhE,YAAsB,EAAU,CACpC,MAAO,IAAS,EAAW,EAAM,UCAnC,YAAiB,EAAQ,CACvB,MAAO,GAAI,EAAI,OAAS,GAGpB,YAA4B,EAAW,CAC3C,MAAO,GAAW,GAAK,IAAS,EAAK,MAAQ,OAGzC,YAAuB,EAAW,CACtC,MAAO,IAAY,GAAK,IAAS,EAAK,MAAQ,OAG1C,YAAoB,EAAa,EAAoB,CACzD,MAAO,OAAO,IAAK,IAAU,SAAW,EAAK,MAAS,ECjBjD,GAAM,IAAe,SAAI,EAAM,CAAwB,MAAA,IAAK,MAAO,GAAE,QAAW,UAAY,MAAO,IAAM,YCM1G,YAAoB,EAAU,CAClC,MAAO,GAAW,GAAK,KAAA,OAAL,EAAO,MCFrB,YAA8B,EAAU,CAC5C,MAAO,GAAW,EAAM,KCJpB,YAA6B,EAAQ,CACzC,MAAO,QAAO,eAAiB,EAAW,GAAG,KAAA,OAAH,EAAM,OAAO,gBCCnD,YAA2C,EAAU,CAEzD,MAAO,IAAI,WACT,gBACE,KAAU,MAAQ,MAAO,IAAU,SAAW,oBAAsB,IAAI,EAAK,KAAG,4HCRhF,aAA2B,CAC/B,MAAI,OAAO,SAAW,YAAc,CAAC,OAAO,SACnC,aAGF,OAAO,SAGT,GAAM,IAAW,KCJlB,YAAqB,EAAU,CACnC,MAAO,GAAW,GAAK,KAAA,OAAL,EAAQ,KCFtB,YAAuD,EAAqC,mGAC1F,EAAS,EAAe,qEAGF,MAAA,CAAA,EAAA,GAAM,EAAO,sBAA/B,GAAkB,EAAA,OAAhB,EAAK,EAAA,MAAE,EAAI,EAAA,KACf,iBAAA,CAAA,EAAA,UACF,MAAA,CAAA,EAAA,EAAA,2BAEI,WAAN,MAAA,CAAA,EAAA,EAAA,eAAA,SAAA,wCAGF,SAAO,yCAIL,YAAkC,EAAQ,CAG9C,MAAO,GAAW,GAAG,KAAA,OAAH,EAAK,WCPnB,WAAuB,EAAyB,CACpD,GAAI,YAAiB,GACnB,MAAO,GAET,GAAI,GAAS,KAAM,CACjB,GAAI,GAAoB,GACtB,MAAO,IAAsB,GAE/B,GAAI,GAAY,GACd,MAAO,IAAc,GAEvB,GAAI,GAAU,GACZ,MAAO,IAAY,GAErB,GAAI,GAAgB,GAClB,MAAO,IAAkB,GAE3B,GAAI,GAAW,GACb,MAAO,IAAa,GAEtB,GAAI,GAAqB,GACvB,MAAO,IAAuB,GAIlC,KAAM,IAAiC,GAOnC,YAAmC,EAAQ,CAC/C,MAAO,IAAI,GAAW,SAAC,EAAyB,CAC9C,GAAM,GAAM,EAAI,MAChB,GAAI,EAAW,EAAI,WACjB,MAAO,GAAI,UAAU,GAGvB,KAAM,IAAI,WAAU,oEAWlB,YAA2B,EAAmB,CAClD,MAAO,IAAI,GAAW,SAAC,EAAyB,CAU9C,OAAS,GAAI,EAAG,EAAI,EAAM,QAAU,CAAC,EAAW,OAAQ,IACtD,EAAW,KAAK,EAAM,IAExB,EAAW,aAIT,YAAyB,EAAuB,CACpD,MAAO,IAAI,GAAW,SAAC,EAAyB,CAC9C,EACG,KACC,SAAC,EAAK,CACJ,AAAK,EAAW,QACd,GAAW,KAAK,GAChB,EAAW,aAGf,SAAC,EAAQ,CAAK,MAAA,GAAW,MAAM,KAEhC,KAAK,KAAM,MAIZ,YAA0B,EAAqB,CACnD,MAAO,IAAI,GAAW,SAAC,EAAyB,aAC9C,OAAoB,GAAA,GAAA,GAAQ,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAAzB,GAAM,GAAK,EAAA,MAEd,GADA,EAAW,KAAK,GACZ,EAAW,OACb,yGAGJ,EAAW,aAIT,YAA+B,EAA+B,CAClE,MAAO,IAAI,GAAW,SAAC,EAAyB,CAC9C,GAAQ,EAAe,GAAY,MAAM,SAAC,EAAG,CAAK,MAAA,GAAW,MAAM,OAIjE,YAAoC,EAAqC,CAC7E,MAAO,IAAkB,GAAmC,IAG9D,YAA0B,EAAiC,EAAyB,uIACxD,EAAA,GAAA,iFAIxB,GAJe,EAAK,EAAA,MACpB,EAAW,KAAK,GAGZ,EAAW,OACb,MAAA,CAAA,8RAGJ,SAAW,oBC/GP,YACJ,EACA,EACA,EACA,EACA,EAAc,CADd,AAAA,IAAA,QAAA,GAAA,GACA,IAAA,QAAA,GAAA,IAEA,GAAM,GAAuB,EAAU,SAAS,UAAA,CAC9C,IACA,AAAI,EACF,EAAmB,IAAI,KAAK,SAAS,KAAM,IAE3C,KAAK,eAEN,GAIH,GAFA,EAAmB,IAAI,GAEnB,CAAC,EAKH,MAAO,GCmBL,WAAuB,EAA0B,EAAS,CAAT,MAAA,KAAA,QAAA,GAAA,GAC9C,EAAQ,SAAC,EAAQ,EAAU,CAChC,EAAO,UACL,GAAI,GACF,EACA,SAAC,EAAK,CAAK,MAAA,IAAgB,EAAY,EAAW,UAAA,CAAM,MAAA,GAAW,KAAK,IAAQ,IAChF,UAAA,CAAM,MAAA,IAAgB,EAAY,EAAW,UAAA,CAAM,MAAA,GAAW,YAAY,IAC1E,SAAC,EAAG,CAAK,MAAA,IAAgB,EAAY,EAAW,UAAA,CAAM,MAAA,GAAW,MAAM,IAAM,QCJ/E,YAAyB,EAA0B,EAAiB,CAAjB,MAAA,KAAA,QAAA,GAAA,GAChD,EAAQ,SAAC,EAAQ,EAAU,CAChC,EAAW,IAAI,EAAU,SAAS,UAAA,CAAM,MAAA,GAAO,UAAU,IAAa,MC5DpE,YAAgC,EAA6B,EAAwB,CACzF,MAAO,GAAU,GAAO,KAAK,GAAY,GAAY,EAAU,ICD3D,YAA6B,EAAuB,EAAwB,CAChF,MAAO,GAAU,GAAO,KAAK,GAAY,GAAY,EAAU,ICH3D,YAA2B,EAAqB,EAAwB,CAC5E,MAAO,IAAI,GAAc,SAAC,EAAU,CAElC,GAAI,GAAI,EAER,MAAO,GAAU,SAAS,UAAA,CACxB,AAAI,IAAM,EAAM,OAGd,EAAW,WAIX,GAAW,KAAK,EAAM,MAIjB,EAAW,QACd,KAAK,gBCVT,YAA8B,EAAoB,EAAwB,CAC9E,MAAO,IAAI,GAAc,SAAC,EAAU,CAClC,GAAI,GAKJ,UAAgB,EAAY,EAAW,UAAA,CAErC,EAAY,EAAc,MAE1B,GACE,EACA,EACA,UAAA,OACM,EACA,EACJ,GAAI,CAEF,AAAC,EAAkB,EAAS,OAAzB,EAAK,EAAA,MAAE,EAAI,EAAA,WACP,EAAP,CAEA,EAAW,MAAM,GACjB,OAGF,AAAI,EAKF,EAAW,WAGX,EAAW,KAAK,IAGpB,EACA,MAQG,UAAA,CAAM,MAAA,GAAW,GAAQ,KAAA,OAAR,EAAU,SAAW,EAAS,YCrDpD,YAAmC,EAAyB,EAAwB,CACxF,GAAI,CAAC,EACH,KAAM,IAAI,OAAM,2BAElB,MAAO,IAAI,GAAc,SAAC,EAAU,CAClC,GAAgB,EAAY,EAAW,UAAA,CACrC,GAAM,GAAW,EAAM,OAAO,iBAC9B,GACE,EACA,EACA,UAAA,CACE,EAAS,OAAO,KAAK,SAAC,EAAM,CAC1B,AAAI,EAAO,KAGT,EAAW,WAEX,EAAW,KAAK,EAAO,UAI7B,EACA,QCrBF,YAAwC,EAA8B,EAAwB,CAClG,MAAO,IAAsB,GAAmC,GAAQ,GCqBpE,YAAuB,EAA2B,EAAwB,CAC9E,GAAI,GAAS,KAAM,CACjB,GAAI,GAAoB,GACtB,MAAO,IAAmB,EAAO,GAEnC,GAAI,GAAY,GACd,MAAO,IAAc,EAAO,GAE9B,GAAI,GAAU,GACZ,MAAO,IAAgB,EAAO,GAEhC,GAAI,GAAgB,GAClB,MAAO,IAAsB,EAAO,GAEtC,GAAI,GAAW,GACb,MAAO,IAAiB,EAAO,GAEjC,GAAI,GAAqB,GACvB,MAAO,IAA2B,EAAO,GAG7C,KAAM,IAAiC,GC0DnC,YAAkB,EAA2B,EAAyB,CAC1E,MAAO,GAAY,GAAU,EAAO,GAAa,EAAU,GC5BvD,YAAY,QAAI,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACpB,GAAM,GAAY,GAAa,GAC/B,MAAO,IAAK,EAAa,GC1ErB,YAAsB,EAAU,CACpC,MAAO,aAAiB,OAAQ,CAAC,MAAM,GCqCnC,WAAoB,EAAyC,EAAa,CAC9E,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAEhC,GAAI,GAAQ,EAGZ,EAAO,UACL,GAAI,GAAmB,EAAY,SAAC,EAAQ,CAG1C,EAAW,KAAK,EAAQ,KAAK,EAAS,EAAO,WCpD7C,GAAA,IAAY,MAAK,QAEzB,YAA2B,EAA6B,EAAW,CAC/D,MAAO,IAAQ,GAAQ,EAAE,MAAA,OAAA,EAAA,GAAA,EAAI,KAAQ,EAAG,GAOtC,YAAiC,EAA2B,CAC9D,MAAO,GAAI,SAAA,EAAI,CAAI,MAAA,IAAY,EAAI,KCd/B,GAAA,IAAY,MAAK,QACjB,GAA0D,OAAM,eAArC,GAA+B,OAAM,UAAlB,GAAY,OAAM,KAQlE,YAA+D,EAAuB,CAC1F,GAAI,EAAK,SAAW,EAAG,CACrB,GAAM,GAAQ,EAAK,GACnB,GAAI,GAAQ,GACV,MAAO,CAAE,KAAM,EAAO,KAAM,MAE9B,GAAI,GAAO,GAAQ,CACjB,GAAM,GAAO,GAAQ,GACrB,MAAO,CACL,KAAM,EAAK,IAAI,SAAC,EAAG,CAAK,MAAA,GAAM,KAC9B,KAAI,IAKV,MAAO,CAAE,KAAM,EAAa,KAAM,MAGpC,YAAgB,EAAQ,CACtB,MAAO,IAAO,MAAO,IAAQ,UAAY,GAAe,KAAS,GC5B7D,YAAuB,EAAgB,EAAa,CACxD,MAAO,GAAK,OAAO,SAAC,EAAQ,EAAK,EAAC,CAAK,MAAE,GAAO,GAAO,EAAO,GAAK,GAAS,ICoMxE,YAAuB,QAAoC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAC/D,GAAM,GAAY,GAAa,GACzB,EAAiB,GAAkB,GAEnC,EAA8B,GAAqB,GAA3C,EAAW,EAAA,KAAE,EAAI,EAAA,KAE/B,GAAI,EAAY,SAAW,EAIzB,MAAO,IAAK,GAAI,GAGlB,GAAM,GAAS,GAAI,GACjB,GACE,EACA,EACA,EAEI,SAAC,EAAM,CAAK,MAAA,IAAa,EAAM,IAE/B,KAIR,MAAO,GAAkB,EAAO,KAAK,GAAiB,IAAqC,EAGvF,YACJ,EACA,EACA,EAAiD,CAAjD,MAAA,KAAA,QAAA,GAAA,IAEO,SAAC,EAA2B,CAGjC,GACE,EACA,UAAA,CAaE,OAZQ,GAAW,EAAW,OAExB,EAAS,GAAI,OAAM,GAGrB,EAAS,EAIT,EAAuB,aAGlB,EAAC,CACR,GACE,EACA,UAAA,CACE,GAAM,GAAS,GAAK,EAAY,GAAI,GAChC,EAAgB,GACpB,EAAO,UACL,GAAI,GACF,EACA,SAAC,EAAK,CAEJ,EAAO,GAAK,EACP,GAEH,GAAgB,GAChB,KAEG,GAGH,EAAW,KAAK,EAAe,EAAO,WAG1C,UAAA,CACE,AAAK,EAAE,GAGL,EAAW,eAMrB,IAjCK,EAAI,EAAG,EAAI,EAAQ,MAAnB,IAqCX,IASN,YAAuB,EAAsC,EAAqB,EAA0B,CAC1G,AAAI,EACF,GAAgB,EAAc,EAAW,GAEzC,ICtRE,YACJ,EACA,EACA,EACA,EACA,EACA,EACA,EACA,EAA+B,CAG/B,GAAM,GAAc,GAEhB,EAAS,EAET,EAAQ,EAER,EAAa,GAKX,EAAgB,UAAA,CAIpB,AAAI,GAAc,CAAC,EAAO,QAAU,CAAC,GACnC,EAAW,YAKT,EAAY,SAAC,EAAQ,CAAK,MAAC,GAAS,EAAa,EAAW,GAAS,EAAO,KAAK,IAEjF,EAAa,SAAC,EAAQ,CAI1B,GAAU,EAAW,KAAK,GAI1B,IAKA,GAAI,GAAgB,GAGpB,EAAU,EAAQ,EAAO,MAAU,UACjC,GAAI,GACF,EACA,SAAC,EAAU,CAGT,GAAY,MAAZ,EAAe,GAEf,AAAI,EAGF,EAAU,GAGV,EAAW,KAAK,IAGpB,UAAA,CAGE,EAAgB,IAGlB,OACA,UAAA,CAIE,GAAI,EAKF,GAAI,CAIF,IAKA,qBACE,GAAM,GAAgB,EAAO,QAI7B,AAAI,EACF,GAAgB,EAAY,EAAmB,UAAA,CAAM,MAAA,GAAW,KAEhE,EAAW,IARR,EAAO,QAAU,EAAS,OAYjC,UACO,EAAP,CACA,EAAW,MAAM,QAS7B,SAAO,UACL,GAAI,GAAmB,EAAY,EAAW,UAAA,CAE5C,EAAa,GACb,OAMG,UAAA,CACL,GAAkB,MAAlB,KClEE,YACJ,EACA,EACA,EAA6B,CAE7B,MAFA,KAAA,QAAA,GAAA,KAEI,EAAW,GAEN,GAAS,SAAC,EAAG,EAAC,CAAK,MAAA,GAAI,SAAC,EAAQ,EAAU,CAAK,MAAA,GAAe,EAAG,EAAG,EAAG,KAAK,EAAU,EAAQ,EAAG,MAAM,GACrG,OAAO,IAAmB,UACnC,GAAa,GAGR,EAAQ,SAAC,EAAQ,EAAU,CAAK,MAAA,IAAe,EAAQ,EAAY,EAAS,MChC/E,YAAmD,EAA6B,CAA7B,MAAA,KAAA,QAAA,GAAA,KAChD,GAAS,GAAU,GCFtB,aAAmB,CACvB,MAAO,IAAS,GCwDZ,aAAgB,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACrB,MAAO,MAAY,GAAK,EAAM,GAAa,KCnEvC,YAAgD,EAA0B,CAC9E,MAAO,IAAI,GAA+B,SAAC,EAAU,CACnD,EAAU,KAAqB,UAAU,KC5C7C,GAAM,IAA0B,CAAC,cAAe,kBAC1C,GAAqB,CAAC,mBAAoB,uBAC1C,GAAgB,CAAC,KAAM,OA2NvB,WACJ,EACA,EACA,EACA,EAAsC,CAMtC,GAJI,EAAW,IACb,GAAiB,EACjB,EAAU,QAER,EACF,MAAO,GAAa,EAAQ,EAAW,GAAiC,KAAK,GAAiB,IAU1F,GAAA,GAAA,EAEJ,GAAc,GACV,GAAmB,IAAI,SAAC,EAAU,CAAK,MAAA,UAAC,EAAY,CAAK,MAAA,GAAO,GAAY,EAAW,EAAS,MAElG,GAAwB,GACtB,GAAwB,IAAI,GAAwB,EAAQ,IAC5D,GAA0B,GAC1B,GAAc,IAAI,GAAwB,EAAQ,IAClD,GAAE,GATD,EAAG,EAAA,GAAE,EAAM,EAAA,GAgBlB,GAAI,CAAC,GACC,GAAY,GACd,MAAO,IAAS,SAAC,EAAc,CAAK,MAAA,GAAU,EAAW,EAAW,KAClE,EAAU,IAOhB,GAAI,CAAC,EACH,KAAM,IAAI,WAAU,wBAGtB,MAAO,IAAI,GAAc,SAAC,EAAU,CAIlC,GAAM,GAAU,UAAA,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAAmB,MAAA,GAAW,KAAK,EAAI,EAAK,OAAS,EAAO,EAAK,KAElF,SAAI,GAEG,UAAA,CAAM,MAAA,GAAQ,MAWzB,YAAiC,EAAa,EAAiB,CAC7D,MAAO,UAAC,EAAkB,CAAK,MAAA,UAAC,EAAY,CAAK,MAAA,GAAO,GAAY,EAAW,KAQjF,YAAiC,EAAW,CAC1C,MAAO,GAAW,EAAO,cAAgB,EAAW,EAAO,gBAQ7D,YAAmC,EAAW,CAC5C,MAAO,GAAW,EAAO,KAAO,EAAW,EAAO,KAQpD,YAAuB,EAAW,CAChC,MAAO,GAAW,EAAO,mBAAqB,EAAW,EAAO,qBC1L5D,YACJ,EACA,EACA,EAAsC,CAEtC,MAAI,GACK,GAAoB,EAAY,GAAe,KAAK,GAAiB,IAGvE,GAAI,GAAoB,SAAC,EAAU,CACxC,GAAM,GAAU,UAAA,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAAc,MAAA,GAAW,KAAK,EAAE,SAAW,EAAI,EAAE,GAAK,IACjE,EAAW,EAAW,GAC5B,MAAO,GAAW,GAAiB,UAAA,CAAM,MAAA,GAAc,EAAS,IAAY,SClB1E,YACJ,EACA,EACA,EAAyC,CAFzC,AAAA,IAAA,QAAA,GAAA,GAEA,IAAA,QAAA,GAAA,IAIA,GAAI,GAAmB,GAEvB,MAAI,IAAuB,MAIzB,CAAI,GAAY,GACd,EAAY,EAIZ,EAAmB,GAIhB,GAAI,GAAW,SAAC,EAAU,CAI/B,GAAI,GAAM,GAAY,GAAW,CAAC,EAAU,EAAW,MAAQ,EAE/D,AAAI,EAAM,GAER,GAAM,GAIR,GAAI,GAAI,EAGR,MAAO,GAAU,SAAS,UAAA,CACxB,AAAK,EAAW,QAEd,GAAW,KAAK,KAEhB,AAAI,GAAK,EAGP,KAAK,SAAS,OAAW,GAGzB,EAAW,aAGd,KCpGD,YAAe,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACpB,GAAM,GAAY,GAAa,GACzB,EAAa,GAAU,EAAM,KAC7B,EAAU,EAChB,MAAO,AAAC,GAAQ,OAGZ,EAAQ,SAAW,EAEnB,EAAU,EAAQ,IAElB,GAAS,GAAY,GAAK,EAAS,IALnC,GC3DC,GAAM,GAAQ,GAAI,GAAkB,ICjCnC,GAAA,IAAY,MAAK,QAMnB,YAA4B,EAAiB,CACjD,MAAO,GAAK,SAAW,GAAK,GAAQ,EAAK,IAAM,EAAK,GAAM,ECoDtD,WAAoB,EAAiD,EAAa,CACtF,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAEhC,GAAI,GAAQ,EAIZ,EAAO,UAIL,GAAI,GAAmB,EAAY,SAAC,EAAK,CAAK,MAAA,GAAU,KAAK,EAAS,EAAO,MAAY,EAAW,KAAK,QCpBzG,aAAa,QAAC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAClB,GAAM,GAAiB,GAAkB,GAEnC,EAAU,GAAe,GAE/B,MAAO,GAAQ,OACX,GAAI,GAAsB,SAAC,EAAU,CAGnC,GAAI,GAAuB,EAAQ,IAAI,UAAA,CAAM,MAAA,KAKzC,EAAY,EAAQ,IAAI,UAAA,CAAM,MAAA,KAGlC,EAAW,IAAI,UAAA,CACb,EAAU,EAAY,OAMxB,mBAAS,EAAW,CAClB,EAAU,EAAQ,IAAc,UAC9B,GAAI,GACF,EACA,SAAC,EAAK,CAKJ,GAJA,EAAQ,GAAa,KAAK,GAItB,EAAQ,MAAM,SAAC,EAAM,CAAK,MAAA,GAAO,SAAS,CAC5C,GAAM,GAAc,EAAQ,IAAI,SAAC,EAAM,CAAK,MAAA,GAAO,UAEnD,EAAW,KAAK,EAAiB,EAAc,MAAA,OAAA,EAAA,GAAA,EAAI,KAAU,GAIzD,EAAQ,KAAK,SAAC,EAAQ,EAAC,CAAK,MAAA,CAAC,EAAO,QAAU,EAAU,MAC1D,EAAW,aAIjB,UAAA,CAGE,EAAU,GAAe,GAIzB,CAAC,EAAQ,GAAa,QAAU,EAAW,eA5B1C,EAAc,EAAG,CAAC,EAAW,QAAU,EAAc,EAAQ,OAAQ,MAArE,GAmCT,MAAO,WAAA,CACL,EAAU,EAAY,QAG1B,GCvDA,YAAyB,EAAoB,EAAsC,CAAtC,MAAA,KAAA,QAAA,GAAA,MAGjD,EAAmB,GAAgB,KAAhB,EAAoB,EAEhC,EAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAiB,GACjB,EAAQ,EAEZ,EAAO,UACL,GAAI,GACF,EACA,SAAC,EAAK,aACA,EAAuB,KAK3B,AAAI,IAAU,GAAsB,GAClC,EAAQ,KAAK,QAIf,OAAqB,GAAA,GAAA,GAAO,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAAzB,GAAM,GAAM,EAAA,MACf,EAAO,KAAK,GAMR,GAAc,EAAO,QACvB,GAAS,GAAM,KAAN,EAAU,GACnB,EAAO,KAAK,sGAIhB,GAAI,MAIF,OAAqB,GAAA,GAAA,GAAM,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAAxB,GAAM,GAAM,EAAA,MACf,GAAU,EAAS,GACnB,EAAW,KAAK,uGAItB,UAAA,aAGE,OAAqB,GAAA,GAAA,GAAO,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAAzB,GAAM,GAAM,EAAA,MACf,EAAW,KAAK,qGAElB,EAAW,YAGb,OACA,UAAA,CAEE,EAAU,UCXd,YACJ,EAAgD,CAEhD,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAgC,KAChC,EAAY,GACZ,EAEJ,EAAW,EAAO,UAChB,GAAI,GAAmB,EAAY,OAAW,OAAW,SAAC,EAAG,CAC3D,EAAgB,EAAU,EAAS,EAAK,GAAW,GAAU,KAC7D,AAAI,EACF,GAAS,cACT,EAAW,KACX,EAAc,UAAU,IAIxB,EAAY,MAKd,GAMF,GAAS,cACT,EAAW,KACX,EAAe,UAAU,MC3HzB,YACJ,EACA,EACA,EACA,EACA,EAAqC,CAErC,MAAO,UAAC,EAAuB,EAA2B,CAIxD,GAAI,GAAW,EAIX,EAAa,EAEb,EAAQ,EAGZ,EAAO,UACL,GAAI,GACF,EACA,SAAC,EAAK,CAEJ,GAAM,GAAI,IAEV,EAAQ,EAEJ,EAAY,EAAO,EAAO,GAIxB,GAAW,GAAO,GAGxB,GAAc,EAAW,KAAK,IAIhC,GACG,UAAA,CACC,GAAY,EAAW,KAAK,GAC5B,EAAW,eC9BjB,aAAuB,QAAO,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAClC,GAAM,GAAiB,GAAkB,GACzC,MAAO,GACH,GAAK,GAAa,MAAA,OAAA,EAAA,GAAA,EAAK,KAAuC,GAAiB,IAC/E,EAAQ,SAAC,EAAQ,EAAU,CACzB,GAAiB,EAAA,CAAE,GAAM,EAAK,GAAe,MAAQ,KCavD,aAA2B,QAC/B,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAEA,MAAO,IAAa,MAAA,OAAA,EAAA,GAAA,EAAI,KC+BpB,YACJ,EACA,EAA6G,CAE7G,MAAO,GAAW,GAAkB,GAAS,EAAS,EAAgB,GAAK,GAAS,EAAS,GCnBzF,YAA0B,EAAiB,EAAyC,CAAzC,MAAA,KAAA,QAAA,GAAA,IACxC,EAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAkC,KAClC,EAAsB,KACtB,EAA0B,KAExB,EAAO,UAAA,CACX,GAAI,EAAY,CAEd,EAAW,cACX,EAAa,KACb,GAAM,GAAQ,EACd,EAAY,KACZ,EAAW,KAAK,KAGpB,YAAqB,CAInB,GAAM,GAAa,EAAY,EACzB,EAAM,EAAU,MACtB,GAAI,EAAM,EAAY,CAEpB,EAAa,KAAK,SAAS,OAAW,EAAa,GACnD,EAAW,IAAI,GACf,OAGF,IAGF,EAAO,UACL,GAAI,GACF,EACA,SAAC,EAAQ,CACP,EAAY,EACZ,EAAW,EAAU,MAGhB,GACH,GAAa,EAAU,SAAS,EAAc,GAC9C,EAAW,IAAI,KAGnB,UAAA,CAGE,IACA,EAAW,YAGb,OACA,UAAA,CAEE,EAAY,EAAa,UChF7B,YAA+B,EAAe,CAClD,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAW,GACf,EAAO,UACL,GAAI,GACF,EACA,SAAC,EAAK,CACJ,EAAW,GACX,EAAW,KAAK,IAElB,UAAA,CACE,AAAK,GACH,EAAW,KAAK,GAElB,EAAW,gBCNf,YAAkB,EAAa,CACnC,MAAO,IAAS,EAEZ,UAAA,CAAM,MAAA,KACN,EAAQ,SAAC,EAAQ,EAAU,CACzB,GAAI,GAAO,EACX,EAAO,UACL,GAAI,GAAmB,EAAY,SAAC,EAAK,CAIvC,AAAI,EAAE,GAAQ,GACZ,GAAW,KAAK,GAIZ,GAAS,GACX,EAAW,iBC1BrB,aAAwB,CAC5B,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,EAAO,UAAU,GAAI,GAAmB,EAAY,OCFlD,YAAmB,EAAQ,CAC/B,MAAO,GAAI,UAAA,CAAM,MAAA,KCmCb,YACJ,EACA,EAAmC,CAEnC,MAAI,GAEK,SAAC,EAAqB,CAC3B,MAAA,IAAO,EAAkB,KAAK,GAAK,GAAI,MAAmB,EAAO,KAAK,GAAU,MAG7E,GAAS,SAAC,EAAO,EAAK,CAAK,MAAA,GAAsB,EAAO,GAAO,KAAK,GAAK,GAAI,GAAM,MCvBtF,YAAmB,EAAoB,EAAyC,CAAzC,AAAA,IAAA,QAAA,GAAA,IAC3C,GAAM,GAAW,GAAM,EAAK,GAC5B,MAAO,IAAU,UAAA,CAAM,MAAA,KCoFnB,WACJ,EACA,EAA0D,CAA1D,MAAA,KAAA,QAAA,GAA+B,IAK/B,EAAa,GAAU,KAAV,EAAc,GAEpB,EAAQ,SAAC,EAAQ,EAAU,CAGhC,GAAI,GAEA,EAAQ,GAEZ,EAAO,UACL,GAAI,GAAmB,EAAY,SAAC,EAAK,CAEvC,GAAM,GAAa,EAAY,GAK/B,AAAI,IAAS,CAAC,EAAY,EAAa,KAMrC,GAAQ,GACR,EAAc,EAGd,EAAW,KAAK,SAO1B,YAAwB,EAAQ,EAAM,CACpC,MAAO,KAAM,EC/GT,WAAwD,EAAQ,EAAuC,CAC3G,MAAO,GAAqB,SAAC,EAAM,EAAI,CAAK,MAAA,GAAU,EAAQ,EAAE,GAAM,EAAE,IAAQ,EAAE,KAAS,EAAE,KCbzF,WAAsB,EAAoB,CAC9C,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAGhC,GAAI,CACF,EAAO,UAAU,WAEjB,EAAW,IAAI,MC3Bf,YAAsB,EAAa,CACvC,MAAO,IAAS,EACZ,UAAA,CAAM,MAAA,KACN,EAAQ,SAAC,EAAQ,EAAU,CAKzB,GAAI,GAAc,GAClB,EAAO,UACL,GAAI,GACF,EACA,SAAC,EAAK,CAEJ,EAAO,KAAK,GAGZ,EAAQ,EAAO,QAAU,EAAO,SAElC,UAAA,aAGE,OAAoB,GAAA,GAAA,GAAM,EAAA,EAAA,OAAA,CAAA,EAAA,KAAA,EAAA,EAAA,OAAE,CAAvB,GAAM,GAAK,EAAA,MACd,EAAW,KAAK,qGAElB,EAAW,YAGb,OACA,UAAA,CAEE,EAAS,UCtDjB,aAAe,QAAI,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACvB,GAAM,GAAY,GAAa,GACzB,EAAa,GAAU,EAAM,KACnC,SAAO,GAAe,GAEf,EAAQ,SAAC,EAAQ,EAAU,CAChC,GAAS,GAAY,GAAI,EAAA,CAAE,GAAM,EAAM,IAAgC,IAAY,UAAU,KCgB3F,aAAmB,QACvB,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAEA,MAAO,IAAK,MAAA,OAAA,EAAA,GAAA,EAAI,KCHZ,YAAoB,EAAyB,CACjD,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAW,GACX,EAAsB,KAC1B,EAAO,UACL,GAAI,GAAmB,EAAY,SAAC,EAAK,CACvC,EAAW,GACX,EAAY,KAGhB,GAAM,GAAO,UAAA,CACX,GAAI,EAAU,CACZ,EAAW,GACX,GAAM,GAAQ,EACd,EAAY,KACZ,EAAW,KAAK,KAGpB,EAAS,UAAU,GAAI,GAAmB,EAAY,EAAM,OC8B1D,YAAwB,EAA6D,EAAQ,CAMjG,MAAO,GAAQ,GAAc,EAAa,EAAW,UAAU,QAAU,EAAG,KCqCxE,YAAmB,EAA4B,CAA5B,AAAA,IAAA,QAAA,GAAA,IACf,GAAA,GAAgH,EAAO,UAAvH,EAAS,IAAA,OAAG,UAAA,CAAM,MAAA,IAAI,IAAY,EAAE,EAA4E,EAAO,aAAnF,EAAY,IAAA,OAAG,GAAI,EAAE,EAAuD,EAAO,gBAA9D,EAAe,IAAA,OAAG,GAAI,EAAE,EAA+B,EAAO,oBAAtC,EAAmB,IAAA,OAAG,GAAI,EAUnH,MAAO,UAAC,EAAa,CACnB,GAAI,GAAuC,KACvC,EAAuC,KACvC,EAAiC,KACjC,EAAW,EACX,EAAe,GACf,EAAa,GAEX,EAAc,UAAA,CAClB,GAAe,MAAf,EAAiB,cACjB,EAAkB,MAId,EAAQ,UAAA,CACZ,IACA,EAAa,EAAU,KACvB,EAAe,EAAa,IAExB,EAAsB,UAAA,CAG1B,GAAM,GAAO,EACb,IACA,GAAI,MAAJ,EAAM,eAGR,MAAO,GAAc,SAAC,EAAQ,GAAU,CACtC,IACI,CAAC,GAAc,CAAC,GAClB,IAOF,GAAM,IAAQ,EAAU,GAAO,KAAP,EAAW,IAOnC,GAAW,IAAI,UAAA,CACb,IAKI,IAAa,GAAK,CAAC,GAAc,CAAC,GACpC,GAAkB,GAAY,EAAqB,MAMvD,GAAK,UAAU,IAEV,GAMH,GAAa,GAAI,IAAe,CAC9B,KAAM,SAAC,GAAK,CAAK,MAAA,IAAK,KAAK,KAC3B,MAAO,SAAC,GAAG,CACT,EAAa,GACb,IACA,EAAkB,GAAY,EAAO,EAAc,IACnD,GAAK,MAAM,KAEb,SAAU,UAAA,CACR,EAAe,GACf,IACA,EAAkB,GAAY,EAAO,GACrC,GAAK,cAGT,GAAK,GAAQ,UAAU,MAExB,IAIP,YACE,EACA,EAA+C,QAC/C,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,EAAA,GAAA,UAAA,GAEA,MAAI,KAAO,GACT,KAEO,MAGL,IAAO,GACF,KAGF,EAAE,MAAA,OAAA,EAAA,GAAA,EAAI,KACV,KAAK,GAAK,IACV,UAAU,UAAA,CAAM,MAAA,OChIf,WACJ,EACA,EACA,EAAyB,SAErB,EACA,EAAW,GACf,MAAI,IAAsB,MAAO,IAAuB,SACtD,GAAa,GAAA,EAAmB,cAAU,MAAA,IAAA,OAAA,EAAI,IAC9C,EAAa,GAAA,EAAmB,cAAU,MAAA,IAAA,OAAA,EAAI,IAC9C,EAAW,CAAC,CAAC,EAAmB,SAChC,EAAY,EAAmB,WAE/B,EAAa,GAAkB,KAAlB,EAAsB,IAE9B,GAAS,CACd,UAAW,UAAA,CAAM,MAAA,IAAI,IAAc,EAAY,EAAY,IAC3D,aAAc,GACd,gBAAiB,GACjB,oBAAqB,IC1GnB,YAAkB,EAAa,CACnC,MAAO,GAAO,SAAC,EAAG,EAAK,CAAK,MAAA,IAAS,ICUjC,YAAuB,EAAyB,CACpD,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAS,GAEP,EAAiB,GAAI,GACzB,EACA,UAAA,CACE,GAAc,MAAd,EAAgB,cAChB,EAAS,IAEX,IAGF,EAAU,GAAU,UAAU,GAE9B,EAAO,UAAU,GAAI,GAAmB,EAAY,SAAC,EAAK,CAAK,MAAA,IAAU,EAAW,KAAK,QCDvF,YAAmB,QAAO,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GAC9B,GAAM,GAAY,GAAa,GAC/B,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAIhC,AAAC,GAAY,GAAO,EAAQ,EAAQ,GAAa,GAAO,EAAQ,IAAS,UAAU,KCiBjF,WACJ,EACA,EAA6G,CAE7G,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAyD,KACzD,EAAQ,EAER,EAAa,GAIX,EAAgB,UAAA,CAAM,MAAA,IAAc,CAAC,GAAmB,EAAW,YAEzE,EAAO,UACL,GAAI,GACF,EACA,SAAC,EAAK,CAEJ,GAAe,MAAf,EAAiB,cACjB,GAAI,GAAa,EACX,EAAa,IAEnB,EAAU,EAAQ,EAAO,IAAa,UACnC,EAAkB,GAAI,GACrB,EAIA,SAAC,EAAU,CAAK,MAAA,GAAW,KAAK,EAAiB,EAAe,EAAO,EAAY,EAAY,KAAgB,IAC/G,UAAA,CAIE,EAAkB,KAClB,QAKR,UAAA,CACE,EAAa,GACb,SCnEJ,YACJ,EACA,EAA6G,CAE7G,MAAO,GAAW,GAAkB,EAAU,UAAA,CAAM,MAAA,IAAiB,GAAkB,EAAU,UAAA,CAAM,MAAA,KCjBnG,YAAuB,EAA8B,CACzD,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,EAAU,GAAU,UAAU,GAAI,GAAmB,EAAY,UAAA,CAAM,MAAA,GAAW,YAAY,KAC9F,CAAC,EAAW,QAAU,EAAO,UAAU,KCSrC,YAAuB,EAAiD,EAAiB,CAAjB,MAAA,KAAA,QAAA,GAAA,IACrE,EAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAQ,EACZ,EAAO,UACL,GAAI,GAAmB,EAAY,SAAC,EAAK,CACvC,GAAM,GAAS,EAAU,EAAO,KAChC,AAAC,IAAU,IAAc,EAAW,KAAK,GACzC,CAAC,GAAU,EAAW,gBCkDxB,WACJ,EACA,EACA,EAA8B,CAK9B,GAAM,GACJ,EAAW,IAAmB,GAAS,EAElC,CAAE,KAAM,EAA2E,MAAK,EAAE,SAAQ,GACnG,EAEN,MAAO,GACH,EAAQ,SAAC,EAAQ,EAAU,OACzB,AAAA,GAAA,EAAY,aAAS,MAAA,IAAA,QAAA,EAAA,KAArB,GACA,GAAI,GAAU,GACd,EAAO,UACL,GAAI,GACF,EACA,SAAC,EAAK,OACJ,AAAA,GAAA,EAAY,QAAI,MAAA,IAAA,QAAA,EAAA,KAAhB,EAAmB,GACnB,EAAW,KAAK,IAElB,UAAA,OACE,EAAU,GACV,GAAA,EAAY,YAAQ,MAAA,IAAA,QAAA,EAAA,KAApB,GACA,EAAW,YAEb,SAAC,EAAG,OACF,EAAU,GACV,GAAA,EAAY,SAAK,MAAA,IAAA,QAAA,EAAA,KAAjB,EAAoB,GACpB,EAAW,MAAM,IAEnB,UAAA,SACE,AAAI,GACF,IAAA,EAAY,eAAW,MAAA,IAAA,QAAA,EAAA,KAAvB,IAEF,GAAA,EAAY,YAAQ,MAAA,IAAA,QAAA,EAAA,KAApB,QAQR,GCpJC,GAAM,IAAwC,CACnD,QAAS,GACT,SAAU,IA+CN,YACJ,EACA,EAA6D,IAA7D,GAAA,IAAA,OAAwC,GAAqB,EAA3D,EAAO,EAAA,QAAE,EAAQ,EAAA,SAEnB,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAChC,GAAI,GAAW,GACX,EAAsB,KACtB,EAAiC,KACjC,EAAa,GAEX,EAAgB,UAAA,CACpB,GAAS,MAAT,EAAW,cACX,EAAY,KACR,GACF,KACA,GAAc,EAAW,aAIvB,EAAoB,UAAA,CACxB,EAAY,KACZ,GAAc,EAAW,YAGrB,EAAgB,SAAC,EAAQ,CAC7B,MAAC,GAAY,EAAU,EAAiB,IAAQ,UAAU,GAAI,GAAmB,EAAY,EAAe,KAExG,EAAO,UAAA,CACX,GAAI,EAAU,CAIZ,EAAW,GACX,GAAM,GAAQ,EACd,EAAY,KAEZ,EAAW,KAAK,GAChB,CAAC,GAAc,EAAc,KAIjC,EAAO,UACL,GAAI,GACF,EAMA,SAAC,EAAK,CACJ,EAAW,GACX,EAAY,EACZ,CAAE,IAAa,CAAC,EAAU,SAAY,GAAU,IAAS,EAAc,KAEzE,UAAA,CACE,EAAa,GACb,CAAE,IAAY,GAAY,GAAa,CAAC,EAAU,SAAW,EAAW,gBC7D5E,aAAwB,QAAO,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACnC,GAAM,GAAU,GAAkB,GAElC,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAehC,OAdM,GAAM,EAAO,OACb,EAAc,GAAI,OAAM,GAI1B,EAAW,EAAO,IAAI,UAAA,CAAM,MAAA,KAG5B,EAAQ,cAMH,EAAC,CACR,EAAU,EAAO,IAAI,UACnB,GAAI,GACF,EACA,SAAC,EAAK,CACJ,EAAY,GAAK,EACb,CAAC,GAAS,CAAC,EAAS,IAEtB,GAAS,GAAK,GAKb,GAAQ,EAAS,MAAM,MAAe,GAAW,QAKtD,MAlBG,EAAI,EAAG,EAAI,EAAK,MAAhB,GAwBT,EAAO,UACL,GAAI,GAAmB,EAAY,SAAC,EAAK,CACvC,GAAI,EAAO,CAET,GAAM,GAAM,EAAA,CAAI,GAAK,EAAK,IAC1B,EAAW,KAAK,EAAU,EAAO,MAAA,OAAA,EAAA,GAAA,EAAI,KAAU,SClFnD,aAAa,QAAO,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACxB,MAAO,GAAQ,SAAC,EAAQ,EAAU,CAEhC,GAAS,MAAA,OAAA,EAAA,CAAC,GAAM,EAAM,KAAmB,UAAU,KCEjD,aAAiB,QAAkC,GAAA,GAAA,EAAA,EAAA,EAAA,UAAA,OAAA,IAAA,EAAA,GAAA,UAAA,GACvD,MAAO,IAAG,MAAA,OAAA,EAAA,GAAA,EAAI,KCUT,aAA4C,CACjD,GAAM,GAAY,GAAI,IACtB,SAAU,SAAU,oBACjB,KACC,GAAM,WAEL,UAAU,GAGR,ECFF,YACL,EAAkB,EAAmB,SACtB,CACf,MAAO,GAAK,cAAiB,IAAa,OAqBrC,YACL,EAAkB,EAAmB,SAClC,CACH,GAAM,GAAK,GAAc,EAAU,GACnC,GAAI,MAAO,IAAO,YAChB,KAAM,IAAI,gBACR,8BAA8B,oBAIlC,MAAO,GAQF,aAAqD,CAC1D,MAAO,UAAS,wBAAyB,aACrC,SAAS,cACT,OAqBC,WACL,EAAkB,EAAmB,SAChC,CACL,MAAO,OAAM,KAAK,EAAK,iBAAoB,IAWtC,YACL,KAAoB,EACd,CACN,EAAG,YAAY,GAAG,GC1Fb,YACL,EAAiB,EAAQ,GACnB,CACN,AAAI,EACF,EAAG,QAEH,EAAG,OAYA,YACL,EACqB,CACrB,MAAO,GACL,EAAsB,EAAI,SAC1B,EAAsB,EAAI,SAEzB,KACC,EAAI,CAAC,CAAE,UAAW,IAAS,SAC3B,EAAU,IAAO,OCNvB,GAAM,IAAS,GAAI,GAYb,GAAY,GAAM,IAAM,EAC5B,GAAI,gBAAe,GAAW,CAC5B,OAAW,KAAS,GAClB,GAAO,KAAK,OAGf,KACC,EAAU,GAAU,EAAM,KAAK,EAAU,IACtC,KACC,EAAS,IAAM,EAAO,gBAG1B,EAAY,IAcT,YAAwB,EAA8B,CAC3D,MAAO,CACL,MAAQ,EAAG,YACX,OAAQ,EAAG,cAWR,YAA+B,EAA8B,CAClE,MAAO,CACL,MAAQ,EAAG,YACX,OAAQ,EAAG,cAyBR,YACL,EACyB,CACzB,MAAO,IACJ,KACC,EAAI,GAAY,EAAS,QAAQ,IACjC,EAAU,GAAY,GACnB,KACC,EAAO,CAAC,CAAE,YAAa,IAAW,GAClC,EAAS,IAAM,EAAS,UAAU,IAClC,EAAI,IAAM,GAAe,MAG7B,EAAU,GAAe,KC9FxB,YAA0B,EAAgC,CAC/D,MAAO,CACL,EAAG,EAAG,WACN,EAAG,EAAG,WAaH,YACL,EAC2B,CAC3B,MAAO,GACL,EAAU,EAAI,UACd,EAAU,OAAQ,WAEjB,KACC,EAAI,IAAM,GAAiB,IAC3B,EAAU,GAAiB,KAe1B,YACL,EAAiB,EAAY,GACR,CACrB,MAAO,IAAmB,GACvB,KACC,EAAI,CAAC,CAAE,OAAQ,CACb,GAAM,GAAU,GAAe,GACzB,EAAU,GAAsB,GACtC,MAAO,IACL,EAAQ,OAAS,EAAQ,OAAS,IAGtC,KC9EC,YACL,EACM,CACN,GAAI,YAAc,kBAChB,EAAG,aAEH,MAAM,IAAI,OAAM,mBCQpB,GAAM,IAA4C,CAChD,OAAQ,GAAkB,2BAC1B,OAAQ,GAAkB,4BAcrB,YAAmB,EAAuB,CAC/C,MAAO,IAAQ,GAAM,QAchB,YAAmB,EAAc,EAAsB,CAC5D,AAAI,GAAQ,GAAM,UAAY,GAC5B,GAAQ,GAAM,QAYX,YAAqB,EAAmC,CAC7D,GAAM,GAAK,GAAQ,GACnB,MAAO,GAAU,EAAI,UAClB,KACC,EAAI,IAAM,EAAG,SACb,EAAU,EAAG,UCjCnB,YACE,EAAiB,EACR,CACT,OAAQ,EAAG,iBAGJ,kBAEH,MAAI,GAAG,OAAS,QACP,SAAS,KAAK,GAEd,OAGN,uBACA,qBACH,MAAO,WAIP,MAAO,GAAG,mBAaT,aAA+C,CACpD,MAAO,GAAyB,OAAQ,WACrC,KACC,EAAO,GAAM,CAAE,GAAG,SAAW,EAAG,UAChC,EAAI,GAAO,EACT,KAAM,GAAU,UAAY,SAAW,SACvC,KAAM,EAAG,IACT,OAAQ,CACN,EAAG,iBACH,EAAG,sBAGP,EAAO,CAAC,CAAE,OAAM,UAAW,CACzB,GAAI,IAAS,SAAU,CACrB,GAAM,GAAS,KACf,GAAI,MAAO,IAAW,YACpB,MAAO,CAAC,GAAwB,EAAQ,GAE5C,MAAO,KAET,MC7EC,aAA4B,CACjC,MAAO,IAAI,KAAI,SAAS,MAQnB,YAAqB,EAAgB,CAC1C,SAAS,KAAO,EAAI,KAUf,aAAuC,CAC5C,MAAO,IAAI,GCJb,YAAqB,EAAiB,EAA8B,CAGlE,GAAI,MAAO,IAAU,UAAY,MAAO,IAAU,SAChD,EAAG,WAAa,EAAM,mBAGb,YAAiB,MAC1B,EAAG,YAAY,WAGN,MAAM,QAAQ,GACvB,OAAW,KAAQ,GACjB,GAAY,EAAI,GA2Bf,WACL,EAAa,KAAmC,EAC7C,CACH,GAAM,GAAK,SAAS,cAAc,GAGlC,GAAI,EACF,OAAW,KAAQ,QAAO,KAAK,GAC7B,AAAI,MAAO,GAAW,IAAU,UAC9B,EAAG,aAAa,EAAM,EAAW,IAC1B,EAAW,IAClB,EAAG,aAAa,EAAM,IAG5B,OAAW,KAAS,GAClB,GAAY,EAAI,GAGlB,MAAO,GC1EF,YAAkB,EAAe,EAAmB,CACzD,GAAI,GAAI,EACR,GAAI,EAAM,OAAS,EAAG,CACpB,KAAO,EAAM,KAAO,KAAO,EAAE,EAAI,GAAG,CACpC,MAAO,GAAG,EAAM,UAAU,EAAG,QAE/B,MAAO,GAmBF,YAAe,EAAuB,CAC3C,GAAI,EAAQ,IAAK,CACf,GAAM,GAAS,CAAG,IAAQ,KAAO,IAAO,IACxC,MAAO,GAAK,IAAQ,MAAY,KAAM,QAAQ,UAE9C,OAAO,GAAM,WC3BV,aAAmC,CACxC,MAAO,UAAS,KAAK,UAAU,GAa1B,YAAyB,EAAoB,CAClD,GAAM,GAAK,EAAE,IAAK,CAAE,KAAM,IAC1B,EAAG,iBAAiB,QAAS,GAAM,EAAG,mBACtC,EAAG,QAUE,aAAiD,CACtD,MAAO,GAA2B,OAAQ,cACvC,KACC,EAAI,IACJ,EAAU,MACV,EAAO,GAAQ,EAAK,OAAS,GAC7B,EAAY,IASX,aAAwD,CAC7D,MAAO,MACJ,KACC,EAAI,GAAM,GAAW,QAAQ,QAC7B,EAAO,GAAM,MAAO,IAAO,cCtC1B,YAAoB,EAAoC,CAC7D,GAAM,GAAQ,WAAW,GACzB,MAAO,IAA0B,GAC/B,EAAM,YAAY,IAAM,EAAK,EAAM,WAElC,KACC,EAAU,EAAM,UASf,aAAwC,CAC7C,MAAO,GAAU,OAAQ,eACtB,KACC,GAAM,SAgBL,YACL,EAA6B,EACd,CACf,MAAO,GACJ,KACC,EAAU,GAAU,EAAS,IAAY,IC3CxC,YACL,EAAmB,EAAuB,CAAE,YAAa,eACnC,CACtB,MAAO,IAAK,MAAM,GAAG,IAAO,IACzB,KACC,EAAO,GAAO,EAAI,SAAW,KAC7B,GAAW,IAAM,KAchB,YACL,EAAmB,EACJ,CACf,MAAO,IAAQ,EAAK,GACjB,KACC,EAAU,GAAO,EAAI,QACrB,EAAY,IAYX,YACL,EAAmB,EACG,CACtB,GAAM,GAAM,GAAI,WAChB,MAAO,IAAQ,EAAK,GACjB,KACC,EAAU,GAAO,EAAI,QACrB,EAAI,GAAO,EAAI,gBAAgB,EAAK,aACpC,EAAY,IC3CX,aAA6C,CAClD,MAAO,CACL,EAAG,KAAK,IAAI,EAAG,aACf,EAAG,KAAK,IAAI,EAAG,cASZ,YACL,CAAE,IAAG,KACC,CACN,OAAO,SAAS,GAAK,EAAG,GAAK,GAUxB,aAA2D,CAChE,MAAO,GACL,EAAU,OAAQ,SAAU,CAAE,QAAS,KACvC,EAAU,OAAQ,SAAU,CAAE,QAAS,MAEtC,KACC,EAAI,IACJ,EAAU,OCnCT,aAAyC,CAC9C,MAAO,CACL,MAAQ,WACR,OAAQ,aAWL,aAAuD,CAC5D,MAAO,GAAU,OAAQ,SAAU,CAAE,QAAS,KAC3C,KACC,EAAI,IACJ,EAAU,OCST,aAA+C,CACpD,MAAO,GAAc,CACnB,KACA,OAEC,KACC,EAAI,CAAC,CAAC,EAAQ,KAAW,EAAE,SAAQ,UACnC,EAAY,IAYX,YACL,EAAiB,CAAE,YAAW,WACR,CACtB,GAAM,GAAQ,EACX,KACC,EAAwB,SAItB,EAAU,EAAc,CAAC,EAAO,IACnC,KACC,EAAI,IAAuB,EACzB,EAAG,EAAG,WACN,EAAG,EAAG,cAKZ,MAAO,GAAc,CAAC,EAAS,EAAW,IACvC,KACC,EAAI,CAAC,CAAC,CAAE,UAAU,CAAE,SAAQ,QAAQ,CAAE,IAAG,QAAU,EACjD,OAAQ,CACN,EAAG,EAAO,EAAI,EACd,EAAG,EAAO,EAAI,EAAI,GAEpB,WChCD,YACL,EAAgB,CAAE,OACH,CAGf,GAAM,GAAM,EAAwB,EAAQ,WACzC,KACC,EAAI,CAAC,CAAE,UAAW,IAItB,MAAO,GACJ,KACC,GAAS,IAAM,EAAK,CAAE,QAAS,GAAM,SAAU,KAC/C,EAAI,GAAW,EAAO,YAAY,IAClC,GAAY,GACZ,MCHN,GAAM,IAAS,GAAkB,aAC3B,GAAiB,KAAK,MAAM,GAAO,aACzC,GAAO,KAAO,GAAG,GAAI,KAAI,GAAO,KAAM,QAW/B,aAAiC,CACtC,MAAO,IAUF,YAAiB,EAAqB,CAC3C,MAAO,IAAO,SAAS,SAAS,GAW3B,WACL,EAAkB,EACV,CACR,MAAO,OAAO,IAAU,YACpB,GAAO,aAAa,GAAK,QAAQ,IAAK,EAAM,YAC5C,GAAO,aAAa,GC5BnB,YACL,EAAS,EAAmB,SACP,CACrB,MAAO,IAAkB,sBAAsB,KAAS,GAanD,YACL,EAAS,EAAmB,SACL,CACvB,MAAO,GAAY,sBAAsB,KAAS,GC5GpD,OAAwB,SCUjB,YACL,EAAiB,EAAQ,EACnB,CACN,EAAG,aAAa,WAAY,EAAM,YAQ7B,YACL,EACM,CACN,EAAG,gBAAgB,YASd,YACL,EAAiB,EACX,CACN,EAAG,aAAa,gBAAiB,QACjC,EAAG,MAAM,IAAM,IAAI,MAQd,YACL,EACM,CACN,GAAM,GAAQ,GAAK,SAAS,EAAG,MAAM,IAAK,IAC1C,EAAG,gBAAgB,iBACnB,EAAG,MAAM,IAAM,GACX,GACF,OAAO,SAAS,EAAG,GC1ChB,YACL,EAAiB,EACX,CACN,EAAG,aAAa,gBAAiB,GAQ5B,YACL,EACM,CACN,EAAG,gBAAgB,iBAWd,YACL,EAAiB,EACX,CACN,EAAG,UAAU,OAAO,uBAAwB,GAQvC,YACL,EACM,CACN,EAAG,UAAU,OAAO,wBCvCf,YACL,EAAiB,EACX,CACN,EAAG,kBAAmB,UAAY,EAW7B,YACL,EAAiB,EACX,CACN,EAAG,aAAa,gBAAiB,GAQ5B,YACL,EACM,CACN,EAAG,gBAAgB,iBC5Bd,YACL,EAAiB,EACX,CACN,EAAG,aAAa,gBAAiB,GAQ5B,YACL,EACM,CACN,EAAG,gBAAgB,iBCdd,YACL,EAAiB,EACX,CACN,EAAG,aAAa,gBAAiB,GAQ5B,YACL,EACM,CACN,EAAG,gBAAgB,iBCZd,YACL,EAAsB,EAChB,CACN,EAAG,YAAc,EAQZ,YACL,EACM,CACN,EAAG,YAAc,EAAY,sBCbxB,YACL,EAAiB,EACX,CACN,OAAQ,OAGD,GACH,EAAG,YAAc,EAAY,sBAC7B,UAGG,GACH,EAAG,YAAc,EAAY,qBAC7B,cAIA,EAAG,YAAc,EAAY,sBAAuB,GAAM,KASzD,YACL,EACM,CACN,EAAG,YAAc,EAAY,6BAWxB,YACL,EAAiB,EACX,CACN,EAAG,YAAY,GAQV,YACL,EACM,CACN,EAAG,UAAY,GCzDV,YACL,EAAiB,EACX,CACN,EAAG,MAAM,IAAM,GAAG,MAQb,YACL,EACM,CACN,EAAG,MAAM,IAAM,GAwBV,YACL,EAAiB,EACX,CACN,GAAM,GAAa,EAAG,kBACtB,EAAW,MAAM,OAAS,GAAG,EAAQ,EAAI,EAAW,cAQ/C,YACL,EACM,CACN,GAAM,GAAa,EAAG,kBACtB,EAAW,MAAM,OAAS,GCtDrB,YACL,EAAiB,EACX,CACN,EAAG,iBAAkB,YAAY,GAS5B,YACL,EAAiB,EACX,CACN,EAAG,iBAAkB,aAAa,gBAAiB,GCf9C,YACL,EAAiB,EACX,CACN,EAAG,aAAa,gBAAiB,GAQ5B,YACL,EACM,CACN,EAAG,gBAAgB,iBCdd,YACL,EAAiB,EACX,CACN,EAAG,aAAa,gBAAiB,GAQ5B,YACL,EACM,CACN,EAAG,gBAAgB,iBAWd,YACL,EAAiB,EACX,CACN,EAAG,MAAM,IAAM,GAAG,MAQb,YACL,EACM,CACN,EAAG,MAAM,IAAM,GCnCV,YAA+B,EAAyB,CAC7D,MACE,GAAC,SAAD,CACE,MAAM,uBACN,MAAO,EAAY,kBACnB,wBAAuB,IAAI,aCJjC,GAAW,IAAX,UAAW,EAAX,CACE,WAAS,GAAT,SACA,WAAS,GAAT,WAFS,aAiBX,YACE,EAA2C,EAC9B,CACb,GAAM,GAAS,EAAO,EAChB,EAAS,EAAO,EAGhB,EAAU,OAAO,KAAK,EAAS,OAClC,OAAO,GAAO,CAAC,EAAS,MAAM,IAC9B,IAAI,GAAO,CAAC,EAAC,MAAD,KAAM,GAAY,MAC9B,OACA,MAAM,EAAG,IAGN,EAAM,GAAI,KAAI,EAAS,UAC7B,MAAI,IAAQ,qBACV,EAAI,aAAa,IAAI,IAAK,OAAO,QAAQ,EAAS,OAC/C,OAAO,CAAC,CAAC,CAAE,KAAW,GACtB,OAAO,CAAC,EAAW,CAAC,KAAW,GAAG,KAAa,IAAQ,OAAQ,KAKlE,EAAC,IAAD,CAAG,KAAM,GAAG,IAAO,MAAM,yBAAyB,SAAU,IAC1D,EAAC,UAAD,CACE,MAAO,CAAC,4BAA6B,GAAG,EACpC,CAAC,uCACD,IACF,KAAK,KACP,gBAAe,EAAS,MAAM,QAAQ,IAErC,EAAS,GAAK,EAAC,MAAD,CAAK,MAAM,mCAC1B,EAAC,KAAD,CAAI,MAAM,2BAA2B,EAAS,OAC7C,EAAS,GAAK,EAAS,KAAK,OAAS,GACpC,EAAC,IAAD,CAAG,MAAM,4BACN,GAAS,EAAS,KAAM,MAG5B,EAAS,GAAK,EAAQ,OAAS,GAC9B,EAAC,IAAD,CAAG,MAAM,2BACN,EAAY,8BAA8B,KAAM,KAmBtD,YACL,EACa,CACb,GAAM,GAAY,EAAO,GAAG,MACtB,EAAO,CAAC,GAAG,GAGX,EAAS,EAAK,UAAU,GAAO,CAAC,EAAI,SAAS,SAAS,MACtD,CAAC,GAAW,EAAK,OAAO,EAAQ,GAGlC,EAAQ,EAAK,UAAU,GAAO,EAAI,MAAQ,GAC9C,AAAI,IAAU,IACZ,GAAQ,EAAK,QAGf,GAAM,GAAO,EAAK,MAAM,EAAG,GACrB,EAAO,EAAK,MAAM,GAGlB,EAAW,CACf,GAAqB,EAAS,EAAc,CAAE,EAAC,GAAU,IAAU,IACnE,GAAG,EAAK,IAAI,GAAW,GAAqB,EAAS,IACrD,GAAG,EAAK,OAAS,CACf,EAAC,UAAD,CAAS,MAAM,0BACb,EAAC,UAAD,CAAS,SAAU,IAChB,EAAK,OAAS,GAAK,EAAK,SAAW,EAChC,EAAY,0BACZ,EAAY,2BAA4B,EAAK,SAG/C,EAAK,IAAI,GAAW,GAAqB,EAAS,MAEtD,IAIN,MACE,GAAC,KAAD,CAAI,MAAM,0BACP,GCpHA,YAA2B,EAAiC,CACjE,MACE,GAAC,KAAD,CAAI,MAAM,oBACP,OAAO,QAAQ,GAAO,IAAI,CAAC,CAAC,EAAK,KAChC,EAAC,KAAD,CAAI,MAAO,oCAAoC,KAC5C,MAAO,IAAU,SAAW,GAAM,GAAS,KCN/C,YAAqB,EAAiC,CAC3D,MACE,GAAC,MAAD,CAAK,MAAM,0BACT,EAAC,MAAD,CAAK,MAAM,qBACR,ICUT,YAAuB,EAA+B,CACpD,GAAM,GAAS,KAGT,EAAM,GAAI,KAAI,MAAM,EAAQ,WAAY,EAAO,MACrD,MACE,GAAC,KAAD,CAAI,MAAM,oBACR,EAAC,IAAD,CAAG,KAAM,EAAI,WAAY,MAAM,oBAC5B,EAAQ,QAiBV,YAA+B,EAAkC,CACtE,GAAM,GAAS,KAGT,CAAC,CAAE,GAAW,EAAO,KAAK,MAAM,eAChC,EACJ,EAAS,KAAK,CAAC,CAAE,UAAS,aACxB,IAAY,GAAW,EAAQ,SAAS,KACpC,EAAS,GAGjB,MACE,GAAC,MAAD,CAAK,MAAM,cACT,EAAC,SAAD,CACE,MAAM,sBACN,aAAY,EAAY,yBAEvB,EAAO,OAEV,EAAC,KAAD,CAAI,MAAM,oBACP,EAAS,IAAI,MhBNtB,GAAI,IAAQ,EAiBL,YACL,EAAiB,CAAE,aACI,CACvB,GAAM,GAAa,EAAG,GACnB,KACC,EAAU,GAAS,CACjB,GAAM,GAAY,EAAM,QAAQ,eAChC,MAAI,aAAqB,aAChB,EACL,GAAG,EAAY,QAAS,GACrB,IAAI,GAAS,EAAU,EAAO,YAG9B,KAKb,MAAO,GACL,EAAU,KAAK,EAAwB,SACvC,GAEC,KACC,EAAI,IAAM,CACR,GAAM,GAAU,GAAe,GAE/B,MAAO,CACL,OAAQ,AAFM,GAAsB,GAEpB,MAAQ,EAAQ,SAGpC,EAAwB,WAevB,YACL,EAAiB,EACiB,CAClC,GAAM,GAAY,GAAI,GAatB,GAZA,EACG,KACC,GAAe,GAAW,aAEzB,UAAU,CAAC,CAAC,CAAE,UAAU,KAAW,CAClC,AAAI,GAAU,EACZ,GAAa,GAEb,GAAe,KAInB,WAAY,cAAe,CAC7B,GAAM,GAAS,EAAG,QAAQ,OAC1B,EAAO,GAAK,UAAU,OACtB,EAAO,aACL,GAAsB,EAAO,IAC7B,GAKJ,MAAO,IAAe,EAAI,GACvB,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,GAAU,GAAE,IAAK,GAAO,KiBvG3B,YACL,EAAwB,CAAE,UAAS,UACd,CACrB,MAAO,GACJ,KACC,EAAI,GAAU,EAAO,QAAQ,wBAC7B,EAAO,GAAW,IAAO,GACzB,GAAM,CAAE,OAAQ,KAChB,GAAU,EAAO,KAAK,GAAM,OAe3B,YACL,EAAwB,EACQ,CAChC,GAAM,GAAY,GAAI,GACtB,SAAU,UAAU,CAAC,CAAE,YAAa,CAClC,EAAG,aAAa,OAAQ,IACpB,GACF,EAAG,mBAIA,GAAa,EAAI,GACrB,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,GAAM,CAAE,IAAK,KCrEnB,GAAM,IAAW,EAAE,SAgBZ,YACL,EACkC,CAClC,UAAe,EAAI,IACnB,GAAe,GAAU,GAAY,IAG9B,EAAG,CAAE,IAAK,IClBZ,YACL,EACyB,CACzB,MAAK,GAAG,UAAU,SAAS,oBAGlB,EAAM,GAAG,EAAY,iBAAkB,GAC3C,IAAI,GAAS,EAAU,EAAO,UAAU,KAAK,GAAM,EAAM,OAEzD,KACC,EAAI,GAAO,EACT,OAAQ,GAAoC,aAAa,UAPxD,EAmBJ,YACL,EACoC,CACpC,GAAM,GAAY,GAAI,GACtB,SAAU,UAAU,CAAC,CAAE,YAAa,CAElC,GAAM,GAAY,EAAO,cACzB,AACE,GAAO,WAAa,EAAO,YAAc,EAAU,WAAa,EAAU,aAC1E,EAAO,WAAkC,EAAU,aAEnD,EAAU,SAAS,CACjB,SAAU,SACV,KAAM,EAAO,eAKZ,GAAiB,GACrB,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,GAAU,GAAE,IAAK,GAAO,KCvB3B,YACL,EAAiB,CAAE,UAAS,YAAW,UACP,CAChC,MAAO,GAGL,GAAG,EAAY,aAAc,GAC1B,IAAI,GAAS,GAAe,EAAO,CAAE,eAGxC,GAAG,EAAY,qBAAsB,GAClC,IAAI,GAAS,GAAe,IAG/B,GAAG,EAAY,UAAW,GACvB,IAAI,GAAS,GAAa,EAAO,CAAE,UAAS,YAG/C,GAAG,EAAY,cAAe,GAC3B,IAAI,GAAS,GAAiB,KCJ9B,YACL,EAAkB,CAAE,UACA,CACpB,MAAO,GACJ,KACC,EAAU,GAAW,EACnB,EAAG,IACH,EAAG,IAAO,KAAK,GAAM,OAEpB,KACC,EAAI,GAAS,EAAE,UAAS,aAiB3B,YACL,EAAiB,EACc,CAC/B,GAAM,GAAY,GAAI,GACtB,SACG,KACC,EAAU,IAET,UAAU,CAAC,CAAE,UAAS,UAAW,CAChC,GAAiB,EAAI,GACrB,AAAI,EACF,GAAe,EAAI,QAEnB,GAAiB,KAIlB,GAAY,EAAI,GACpB,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,GAAU,GAAE,IAAK,GAAO,KCnClC,YAAkB,CAAE,aAAgD,CAClE,GAAI,CAAC,GAAQ,mBACX,MAAO,GAAG,IAGZ,GAAM,GAAa,EAChB,KACC,EAAI,CAAC,CAAE,OAAQ,CAAE,QAAU,GAC3B,GAAY,EAAG,GACf,EAAI,CAAC,CAAC,EAAG,KAAO,CAAC,EAAI,EAAG,IACxB,EAAwB,IAItB,EAAU,EAAc,CAAC,EAAW,IACvC,KACC,EAAO,CAAC,CAAC,CAAE,UAAU,CAAC,CAAE,MAAQ,KAAK,IAAI,EAAI,EAAO,GAAK,KACzD,EAAI,CAAC,CAAC,CAAE,CAAC,MAAgB,GACzB,KAIE,EAAU,GAAY,UAC5B,MAAO,GAAc,CAAC,EAAW,IAC9B,KACC,EAAI,CAAC,CAAC,CAAE,UAAU,KAAY,EAAO,EAAI,KAAO,CAAC,GACjD,IACA,EAAU,GAAU,EAAS,EAAU,EAAG,KAC1C,EAAU,KAgBT,YACL,EAAiB,EACG,CACpB,MAAO,IAAM,IAAM,CACjB,GAAM,GAAS,iBAAiB,GAChC,MAAO,GACL,EAAO,WAAa,UACpB,EAAO,WAAa,oBAGrB,KACC,GAAkB,GAAiB,GAAK,GAAS,IACjD,EAAI,CAAC,CAAC,EAAQ,CAAE,UAAU,KAAa,EACrC,OAAQ,EAAS,EAAS,EAC1B,SACA,YAEF,EAAqB,CAAC,EAAG,IACvB,EAAE,SAAW,EAAE,QACf,EAAE,SAAW,EAAE,QACf,EAAE,SAAW,EAAE,QAEjB,EAAY,IAeX,YACL,EAAiB,CAAE,UAAS,SACG,CAC/B,GAAM,GAAY,GAAI,GACtB,SACG,KACC,EAAwB,UACxB,GAAkB,GAClB,EAAU,IAET,UAAU,CAAC,CAAC,CAAE,UAAU,CAAE,aAAc,CACvC,AAAI,EACF,GAAe,EAAI,EAAS,SAAW,UAEvC,GAAiB,KAIzB,EAAM,UAAU,GAAQ,EAAU,KAAK,IAChC,EACJ,KACC,EAAI,GAAU,GAAE,IAAK,GAAO,KC9G3B,YACL,EAAwB,CAAE,YAAW,WACZ,CACzB,MAAO,IAAgB,EAAI,CAAE,UAAS,cACnC,KACC,EAAI,CAAC,CAAE,OAAQ,CAAE,QAAU,CACzB,GAAM,CAAE,UAAW,GAAe,GAClC,MAAO,CACL,OAAQ,GAAK,KAGjB,EAAwB,WAevB,YACL,EAAiB,EACmB,CACpC,GAAM,GAAY,GAAI,GACtB,EACG,KACC,EAAU,IAET,UAAU,CAAC,CAAE,YAAa,CACzB,AAAI,EACF,GAAoB,EAAI,UAExB,GAAsB,KAI9B,GAAM,GAAW,GAA+B,cAChD,MAAI,OAAO,IAAa,YACf,EAGF,GAAiB,EAAU,GAC/B,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,GAAU,GAAE,IAAK,GAAO,KClE3B,YACL,EAAiB,CAAE,YAAW,WACZ,CAGlB,GAAM,GAAU,EACb,KACC,EAAI,CAAC,CAAE,YAAa,GACpB,KAIE,EAAU,EACb,KACC,EAAU,IAAM,GAAiB,GAC9B,KACC,EAAI,CAAC,CAAE,YAAc,EACnB,IAAQ,EAAG,UACX,OAAQ,EAAG,UAAY,KAEzB,EAAwB,aAMhC,MAAO,GAAc,CAAC,EAAS,EAAS,IACrC,KACC,EAAI,CAAC,CAAC,EAAQ,CAAE,MAAK,UAAU,CAAE,OAAQ,CAAE,KAAK,KAAM,CAAE,cACtD,GAAS,KAAK,IAAI,EAAG,EACjB,KAAK,IAAI,EAAG,EAAS,EAAI,GACzB,KAAK,IAAI,EAAG,EAAS,EAAI,IAEtB,CACL,OAAQ,EAAM,EACd,SACA,OAAQ,EAAM,GAAU,KAG5B,EAAqB,CAAC,EAAG,IACvB,EAAE,SAAW,EAAE,QACf,EAAE,SAAW,EAAE,QACf,EAAE,SAAW,EAAE,SC9ChB,YACL,EACqB,CACrB,GAAM,GAAO,aAAa,QAAQ,SAAS,cACrC,EAAU,KAAK,MAAM,IAAS,CAClC,MAAO,EAAO,UAAU,GACtB,WAAW,EAAM,aAAa,wBAAyB,UAKrD,EAAW,EAAG,GAAG,GACpB,KACC,GAAS,GAAS,EAAU,EAAO,UAChC,KACC,GAAM,KAGV,EAAU,EAAO,KAAK,IAAI,EAAG,EAAQ,SACrC,EAAI,GAAU,EACZ,MAAO,EAAO,QAAQ,GACtB,MAAO,CACL,OAAS,EAAM,aAAa,wBAC5B,QAAS,EAAM,aAAa,yBAC5B,OAAS,EAAM,aAAa,4BAGhC,EAAY,IAIhB,SAAS,UAAU,GAAW,CAC5B,aAAa,QAAQ,SAAS,aAAc,KAAK,UAAU,MAItD,EAUF,YACL,EACgC,CAChC,GAAM,GAAY,GAAI,GAGtB,EAAU,UAAU,GAAW,CAC7B,OAAW,CAAC,EAAK,IAAU,QAAO,QAAQ,EAAQ,OAChD,AAAI,MAAO,IAAU,UACnB,SAAS,KAAK,aAAa,iBAAiB,IAAO,GAGvD,OAAS,GAAQ,EAAG,EAAQ,EAAO,OAAQ,IAAS,CAClD,GAAM,GAAQ,EAAO,GAAO,mBAC5B,AAAI,YAAiB,cACnB,GAAM,OAAS,EAAQ,QAAU,MAKvC,GAAM,GAAS,EAA8B,QAAS,GACtD,MAAO,IAAa,GACjB,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,GAAU,GAAE,IAAK,GAAO,KC3HlC,OAAwB,SAyBjB,YACL,CAAE,UACI,CACN,AAAI,WAAY,eACd,GAAI,GAA8B,GAAc,CAC9C,GAAI,YAAY,kDACb,GAAG,UAAW,GAAM,EAAW,KAAK,MAEtC,UAAU,IAAM,EAAO,KAAK,EAAY,sBC+C/C,YAAoB,EAA0B,CAC5C,GAAI,EAAK,OAAS,EAChB,MAAO,GAGT,GAAM,CAAC,EAAM,GAAQ,EAClB,KAAK,CAAC,EAAG,IAAM,EAAE,OAAS,EAAE,QAC5B,IAAI,GAAO,EAAI,QAAQ,SAAU,KAGhC,EAAQ,EACZ,GAAI,IAAS,EACX,EAAQ,EAAK,WAEb,MAAO,EAAK,WAAW,KAAW,EAAK,WAAW,IAChD,IAGJ,GAAM,GAAS,KACf,MAAO,GAAK,IAAI,GACd,EAAI,QAAQ,EAAK,MAAM,EAAG,GAAQ,EAAO,OA6BtC,YACL,CAAE,YAAW,YAAW,aAClB,CACN,GAAM,GAAS,KACf,GAAI,SAAS,WAAa,QACxB,OAGF,AAAI,qBAAuB,UACzB,SAAQ,kBAAoB,SAG5B,EAAU,OAAQ,gBACf,UAAU,IAAM,CACf,QAAQ,kBAAoB,UAKlC,GAAM,GAAU,GAA4B,kBAC5C,AAAI,MAAO,IAAY,aACrB,GAAQ,KAAO,EAAQ,MAGzB,GAAM,GAAQ,GAAW,GAAI,KAAI,cAAe,EAAO,OACpD,KACC,EAAI,GAAW,GAAW,EAAY,MAAO,GAC1C,IAAI,GAAQ,EAAK,eAEpB,EAAU,GAAQ,EAAsB,SAAS,KAAM,SACpD,KACC,EAAO,GAAM,CAAC,EAAG,SAAW,CAAC,EAAG,SAChC,EAAU,GAAM,CAGd,GAAI,EAAG,iBAAkB,SAAS,CAChC,GAAM,GAAK,EAAG,OAAO,QAAQ,KAC7B,GAAI,GAAM,CAAC,EAAG,OAAQ,CACpB,GAAM,GAAM,GAAI,KAAI,EAAG,MAOvB,GAJA,EAAI,OAAS,GACb,EAAI,KAAO,GAIT,EAAI,WAAa,SAAS,UAC1B,EAAK,SAAS,EAAI,YAElB,SAAG,iBACI,EAAG,CACR,IAAK,GAAI,KAAI,EAAG,SAKxB,MAAO,OAIb,MAIE,EAAO,EAAyB,OAAQ,YAC3C,KACC,EAAO,GAAM,EAAG,QAAU,MAC1B,EAAI,GAAO,EACT,IAAK,GAAI,KAAI,SAAS,MACtB,OAAQ,EAAG,SAEb,MAIJ,EAAM,EAAO,GACV,KACC,EAAqB,CAAC,EAAG,IAAM,EAAE,IAAI,OAAS,EAAE,IAAI,MACpD,EAAI,CAAC,CAAE,SAAU,IAEhB,UAAU,GAGf,GAAM,GAAY,EACf,KACC,EAAwB,YACxB,EAAU,GAAO,GAAQ,EAAI,MAC1B,KACC,GAAW,IACT,IAAY,GACL,MAIb,MAIJ,EACG,KACC,GAAO,IAEN,UAAU,CAAC,CAAE,SAAU,CACtB,QAAQ,UAAU,GAAI,GAAI,GAAG,OAInC,GAAM,GAAM,GAAI,WAChB,EACG,KACC,EAAU,GAAO,EAAI,QACrB,EAAI,GAAO,EAAI,gBAAgB,EAAK,eAEnC,UAAU,GAGf,EACG,KACC,GAAK,IAEJ,UAAU,GAAe,CACxB,OAAW,KAAY,CAGrB,QACA,sBACA,oBACA,yBAGA,+BACA,gCACA,mCACA,qCACA,2BACA,GAAG,GAAQ,0BACP,CAAC,4BACD,IACH,CACD,GAAM,GAAS,GAAW,GACpB,EAAS,GAAW,EAAU,GACpC,AACE,MAAO,IAAW,aAClB,MAAO,IAAW,aAElB,GAAe,EAAQ,MAMjC,EACG,KACC,GAAK,GACL,EAAI,IAAM,GAAoB,cAC9B,EAAU,GAAM,EAAG,GAAG,EAAY,SAAU,KAC5C,GAAU,GAAM,CACd,GAAM,GAAS,EAAE,UACjB,GAAI,EAAG,IAAK,CACV,OAAW,KAAQ,GAAG,oBACpB,EAAO,aAAa,EAAM,EAAG,aAAa,IAC5C,UAAe,EAAI,GAGZ,GAAI,GAAW,GAAY,CAChC,EAAO,OAAS,IAAM,EAAS,iBAKjC,UAAO,YAAc,EAAG,YACxB,GAAe,EAAI,GACZ,MAIV,YAGL,EAAM,EAAO,GACV,KACC,GAAO,IAEN,UAAU,CAAC,CAAE,MAAK,YAAa,CAC9B,AAAI,EAAI,MAAQ,CAAC,EACf,GAAgB,EAAI,MAEpB,GAAkB,GAAU,CAAE,EAAG,MAKzC,EACG,KACC,GAAU,GACV,GAAa,KACb,EAAwB,WAEvB,UAAU,CAAC,CAAE,YAAa,CACzB,QAAQ,aAAa,EAAQ,MAInC,EAAM,EAAO,GACV,KACC,GAAY,EAAG,GACf,EAAO,CAAC,CAAC,EAAG,KAAO,EAAE,IAAI,WAAa,EAAE,IAAI,UAC5C,EAAI,CAAC,CAAC,CAAE,KAAW,IAElB,UAAU,CAAC,CAAE,YAAa,CACzB,GAAkB,GAAU,CAAE,EAAG,MCnVzC,OAAuB,SCAvB,OAAuB,SAsChB,YACL,EAA2B,EACD,CAC1B,GAAM,GAAY,GAAI,QAAO,EAAO,UAAW,OACzC,EAAY,CAAC,EAAY,EAAc,IACpC,GAAG,4BAA+B,WAI3C,MAAO,AAAC,IAAkB,CACxB,EAAQ,EACL,QAAQ,gBAAiB,KACzB,OAGH,GAAM,GAAQ,GAAI,QAAO,MAAM,EAAO,cACpC,EACG,QAAQ,uBAAwB,QAChC,QAAQ,EAAW,QACnB,OAGL,MAAO,IACL,GACI,eAAW,GACX,GAED,QAAQ,EAAO,GACf,QAAQ,8BAA+B,OC5BzC,YAA0B,EAAuB,CACtD,MAAO,GACJ,MAAM,cACJ,IAAI,CAAC,EAAO,IAAU,EAAQ,EAC3B,EAAM,QAAQ,+BAAgC,MAC9C,GAEH,KAAK,IACP,QAAQ,kCAAmC,IAC3C,OCtCE,GAAW,IAAX,UAAW,EAAX,CACL,qBACA,qBACA,qBACA,yBAJgB,aA2EX,YACL,EAC+B,CAC/B,MAAO,GAAQ,OAAS,EAUnB,YACL,EAC+B,CAC/B,MAAO,GAAQ,OAAS,EAUnB,YACL,EACgC,CAChC,MAAO,GAAQ,OAAS,EC3E1B,YACE,CAAE,SAAQ,OAAM,SACH,CAGb,AAAI,EAAO,KAAK,SAAW,GAAK,EAAO,KAAK,KAAO,MACjD,GAAO,KAAO,CACZ,EAAY,wBAIZ,EAAO,YAAc,aACvB,GAAO,UAAY,EAAY,4BAQjC,GAAM,GAAyB,CAC7B,SANe,EAAY,0BAC1B,MAAM,WACN,OAAO,SAKR,YAAa,GAAQ,mBAIvB,MAAO,CAAE,SAAQ,OAAM,QAAO,WAmBzB,YACL,EAAa,EACC,CACd,GAAM,GAAS,KACT,EAAS,GAAI,QAAO,GAGpB,EAAM,GAAI,GACV,EAAM,GAAY,EAAQ,CAAE,QAC/B,KACC,EAAI,GAAW,CACb,GAAI,GAAsB,GACxB,OAAW,KAAU,GAAQ,KAAK,MAChC,OAAW,KAAY,GACrB,EAAS,SAAW,GAAG,GAAI,KAAI,EAAS,SAAU,EAAO,QAE/D,MAAO,KAET,MAIJ,UAAK,GACF,KACC,EAAI,GAAS,EACX,KAAM,GAAkB,MACxB,KAAM,GAAiB,OAGxB,UAAU,EAAI,KAAK,KAAK,IAGtB,CAAE,MAAK,OCxGT,aAAsC,CAC3C,GAAM,GAAS,KACf,GAAuB,GAAI,KAAI,mBAAoB,EAAO,OACvD,UAAU,GAAY,CAErB,AADc,GAAkB,qBAC1B,YAAY,GAAsB,MCqDvC,YACL,EAAsB,CAAE,OACC,CACzB,GAAM,GAAK,gCAAU,YAAa,GAG5B,CAAE,gBAAiB,KACzB,AAAI,EAAa,IAAI,MACnB,GAAU,SAAU,IAGtB,GAAM,GAAS,EACZ,KACC,EAAO,IACP,GAAK,GACL,EAAI,IAAM,EAAa,IAAI,MAAQ,KAIvC,EAAO,UAAU,GAAS,CACxB,AAAI,GACF,GAAG,MAAQ,KAIf,GAAM,GAAS,GAAkB,GAC3B,EAAS,EACb,EAAU,EAAI,SACd,EAAU,EAAI,SAAS,KAAK,GAAM,IAClC,GAEC,KACC,EAAI,IAAM,EAAG,EAAG,QAChB,EAAU,IACV,KAIJ,MAAO,GAAc,CAAC,EAAQ,IAC3B,KACC,EAAI,CAAC,CAAC,EAAO,KAAY,EAAE,QAAO,WAClC,EAAY,IAYX,YACL,EAAsB,CAAE,MAAK,OACyB,CACtD,GAAM,GAAY,GAAI,GAGtB,SACG,KACC,EAAwB,SACxB,EAAI,CAAC,CAAE,WAAiC,EACtC,KAAM,GAAkB,MACxB,KAAM,MAGP,UAAU,EAAI,KAAK,KAAK,IAG7B,EACG,KACC,EAAwB,UAEvB,UAAU,CAAC,CAAE,WAAY,CACxB,AAAI,EACF,IAAU,SAAU,GACpB,GAA0B,EAAI,KAE9B,GAA4B,KAKpC,EAAU,EAAG,KAAO,SACjB,KACC,GAAU,EAAU,KAAK,GAAS,MAEjC,UAAU,IAAM,GAAgB,IAG9B,GAAiB,EAAI,CAAE,MAAK,QAChC,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,GAAU,GAAE,IAAK,GAAO,KC/F3B,YACL,EAAiB,CAAE,OAAqB,CAAE,UACL,CACrC,GAAM,GAAY,GAAI,GAChB,EAAY,GAAsB,EAAG,eACxC,KACC,EAAO,UAIL,EAAO,GAAkB,wBAAyB,GAClD,EAAO,GAAkB,uBAAwB,GAGjD,EAAS,EACZ,KACC,EAAO,IACP,GAAK,IAIT,SACG,KACC,EAAU,GACV,GAAe,GACf,GAAU,IAET,UAAU,CAAC,CAAC,CAAE,SAAS,CAAE,YAAa,CACrC,AAAI,EACF,GAAoB,EAAM,EAAM,QAEhC,GAAsB,KAI9B,EACG,KACC,EAAU,GACV,EAAI,IAAM,GAAsB,IAChC,EAAU,CAAC,CAAE,WAAY,EACvB,EAAG,GAAG,EAAM,MAAM,EAAG,KACrB,EAAG,GAAG,EAAM,MAAM,KACf,KACC,GAAY,GACZ,GAAQ,GACR,EAAU,CAAC,CAAC,KAAW,EAAG,GAAG,QAIlC,UAAU,GAAU,CACnB,GAAsB,EAAM,GAAuB,MAWlD,AAPS,EACb,KACC,EAAO,IACP,EAAI,CAAC,CAAE,UAAW,IAKnB,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,GAAU,GAAE,IAAK,GAAO,KC7E3B,YACL,EAAkB,CAAE,UACK,CACzB,MAAO,GACJ,KACC,EAAI,CAAC,CAAE,WAAY,CACjB,GAAM,GAAM,KACZ,SAAI,KAAO,GACX,EAAI,aAAa,OAAO,KACxB,EAAI,aAAa,IAAI,IAAK,GACnB,CAAE,UAaV,YACL,EAAuB,EACa,CACpC,GAAM,GAAY,GAAI,GACtB,SAAU,UAAU,CAAC,CAAE,SAAU,CAC/B,EAAG,aAAa,sBAAuB,EAAG,MAC1C,EAAG,KAAO,GAAG,MAIf,EAAU,EAAI,SACX,UAAU,GAAM,EAAG,kBAGf,GAAiB,EAAI,GACzB,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,GAAU,GAAE,IAAK,GAAO,KCpC3B,YACL,EAAiB,CAAE,OAAqB,CAAE,aACJ,CACtC,GAAM,GAAY,GAAI,GAGhB,EAAS,GAAoB,gBAC7B,EAAS,EACb,EAAU,EAAO,WACjB,EAAU,EAAO,UAEhB,KACC,EAAU,IACV,EAAI,IAAM,EAAM,OAChB,KAIJ,SACG,KACC,GAAkB,GAClB,EAAI,CAAC,CAAC,CAAE,eAAe,KAAW,CAChC,GAAM,GAAQ,EAAM,MAAM,YAC1B,GAAI,kBAAa,SAAU,EAAM,EAAM,OAAS,GAAI,CAClD,GAAM,GAAO,EAAY,EAAY,OAAS,GAC9C,AAAI,EAAK,WAAW,EAAM,EAAM,OAAS,KACvC,GAAM,EAAM,OAAS,GAAK,OAE5B,GAAM,OAAS,EAEjB,MAAO,MAGR,UAAU,GAAS,EAAG,UAAY,EAChC,KAAK,IACL,QAAQ,MAAO,WAItB,EACG,KACC,EAAO,CAAC,CAAE,UAAW,IAAS,WAE7B,UAAU,GAAO,CAChB,OAAQ,EAAI,UAGL,aACH,AACE,EAAG,UAAU,QACb,EAAM,iBAAmB,EAAM,MAAM,QAErC,GAAM,MAAQ,EAAG,WACnB,SAYH,AAPS,EACb,KACC,EAAO,IACP,EAAI,CAAC,CAAE,UAAW,IAKnB,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,IAAO,EAAE,IAAK,MC7DjB,YACL,EAAiB,CAAE,SAAQ,aACI,CAC/B,GAAM,GAAS,KACf,GAAI,CACF,GAAM,GAAM,gCAAU,SAAU,EAAO,OACjC,EAAS,GAAkB,EAAK,GAGhC,EAAS,GAAoB,eAAgB,GAC7C,EAAS,GAAoB,gBAAiB,GAG9C,CAAE,MAAK,OAAQ,EACrB,EACG,KACC,EAAO,IACP,GAAO,EAAI,KAAK,EAAO,MACvB,GAAK,IAEJ,UAAU,EAAI,KAAK,KAAK,IAG7B,EACG,KACC,EAAO,CAAC,CAAE,UAAW,IAAS,WAE7B,UAAU,GAAO,CAChB,GAAM,GAAS,KACf,OAAQ,EAAI,UAGL,QACH,GAAI,IAAW,EAAO,CACpB,GAAM,GAAU,GAAI,KACpB,OAAW,KAAU,GACnB,sBAAuB,GACtB,CACD,GAAM,GAAU,EAAO,kBACvB,EAAQ,IAAI,EAAQ,WAClB,EAAQ,aAAa,mBAKzB,GAAI,EAAQ,KAAM,CAChB,GAAM,CAAC,CAAC,IAAS,CAAC,GAAG,GAAS,KAAK,CAAC,CAAC,CAAE,GAAI,CAAC,CAAE,KAAO,EAAI,GACzD,EAAK,QAIP,EAAI,QAEN,UAGG,aACA,MACH,GAAU,SAAU,IACpB,GAAgB,EAAO,IACvB,UAGG,cACA,YACH,GAAI,MAAO,IAAW,YACpB,GAAgB,OACX,CACL,GAAM,GAAM,CAAC,EAAO,GAAG,EACrB,wDACA,IAEI,EAAI,KAAK,IAAI,EACjB,MAAK,IAAI,EAAG,EAAI,QAAQ,IAAW,EAAI,OACrC,GAAI,OAAS,UAAY,GAAK,IAE9B,EAAI,QACR,GAAgB,EAAI,IAItB,EAAI,QACJ,cAIA,AAAI,IAAU,MACZ,GAAgB,MAK5B,EACG,KACC,EAAO,CAAC,CAAE,UAAW,IAAS,WAE7B,UAAU,GAAO,CAChB,OAAQ,EAAI,UAGL,QACA,QACA,IACH,GAAgB,GAChB,GAAoB,GACpB,EAAI,QACJ,SAKV,GAAM,GAAU,GAAiB,EAAO,GAClC,EAAU,GAAkB,EAAQ,EAAQ,CAAE,WACpD,MAAO,GAAM,EAAQ,GAClB,KACC,GAGE,GAAG,GAAqB,eAAgB,GACrC,IAAI,GAAS,GAAiB,EAAO,CAAE,YAG1C,GAAG,GAAqB,iBAAkB,GACvC,IAAI,GAAS,GAAmB,EAAO,EAAQ,CAAE,uBAKnD,EAAP,CACA,SAAG,OAAS,GACL,GCrJJ,YACL,EAAiB,CAAE,SAAQ,aACa,CACxC,MAAO,GAAc,CACnB,EACA,EACG,KACC,EAAU,MACV,EAAO,GAAO,EAAI,aAAa,IAAI,SAGtC,KACC,EAAI,CAAC,CAAC,EAAO,KAAS,GAAuB,EAAM,OAAQ,IACzD,EAAI,aAAa,IAAI,OAEvB,EAAI,GAAM,CAxFhB,MAyFQ,GAAM,GAAQ,GAAI,KAGZ,EAAK,SAAS,mBAAmB,EAAI,WAAW,WACtD,OAAS,GAAO,EAAG,WAAY,EAAM,EAAO,EAAG,WAC7C,GAAI,KAAK,gBAAL,cAAoB,aAAc,CACpC,GAAM,GAAW,EAAK,YAChB,EAAW,EAAG,GACpB,AAAI,EAAS,OAAS,EAAS,QAC7B,EAAM,IAAI,EAAmB,GAKnC,OAAW,CAAC,EAAM,IAAS,GAAO,CAChC,GAAM,CAAE,cAAe,EAAE,OAAQ,KAAM,GACvC,EAAK,YAAY,GAAG,MAAM,KAAK,IAIjC,MAAO,CAAE,IAAK,EAAI,YCVnB,YACL,EAAiB,CAAE,YAAW,SACT,CACrB,GAAM,GACJ,EAAG,cAAe,UAClB,EAAG,cAAe,cAAe,UAGnC,MAAO,GAAc,CAAC,EAAO,IAC1B,KACC,EAAI,CAAC,CAAC,CAAE,SAAQ,UAAU,CAAE,OAAQ,CAAE,SACpC,GAAS,EACL,KAAK,IAAI,EAAQ,KAAK,IAAI,EAAG,EAAI,IACjC,EACG,CACL,SACA,OAAQ,GAAK,EAAS,KAG1B,EAAqB,CAAC,EAAG,IACvB,EAAE,SAAW,EAAE,QACf,EAAE,SAAW,EAAE,SAahB,YACL,EAAiB,EACe,CADf,QAAE,YAAF,EAAc,KAAd,EAAc,CAAZ,YAEnB,GAAM,GAAY,GAAI,GACtB,SACG,KACC,EAAU,GACV,GAAe,IAEd,UAAU,CAGT,KAAK,CAAC,CAAE,UAAU,CAAE,OAAQ,IAAW,CACrC,GAAiB,EAAI,GACrB,GAAiB,EAAI,IAIvB,UAAW,CACT,GAAmB,GACnB,GAAmB,MAKpB,GAAa,EAAI,GACrB,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,GAAU,GAAE,IAAK,GAAO,KC7G3B,YACL,EAAc,EACW,CACzB,GAAI,MAAO,IAAS,YAAa,CAC/B,GAAM,GAAM,gCAAgC,KAAQ,IACpD,MAAO,IAGL,GAAqB,GAAG,qBACrB,KACC,EAAI,GAAY,EACd,QAAS,EAAQ,YAEnB,GAAe,KAInB,GAAkB,GACf,KACC,EAAI,GAAS,EACX,MAAO,EAAK,iBACZ,MAAO,EAAK,eAEd,GAAe,MAGlB,KACC,EAAI,CAAC,CAAC,EAAS,KAAW,OAAK,GAAY,SAI1C,CACL,GAAM,GAAM,gCAAgC,IAC5C,MAAO,IAAkB,GACtB,KACC,EAAI,GAAS,EACX,aAAc,EAAK,gBAErB,GAAe,MCjDhB,YACL,EAAc,EACW,CACzB,GAAM,GAAM,WAAW,qBAAwB,mBAAmB,KAClE,MAAO,IAA2B,GAC/B,KACC,EAAI,CAAC,CAAE,aAAY,iBAAmB,EACpC,MAAO,EACP,MAAO,KAET,GAAe,KCed,YACL,EACyB,CACzB,GAAM,CAAC,GAAQ,EAAI,MAAM,sBAAwB,GACjD,OAAQ,EAAK,mBAGN,SACH,GAAM,CAAC,CAAE,EAAM,GAAQ,EAAI,MAAM,uCACjC,MAAO,IAA2B,EAAM,OAGrC,SACH,GAAM,CAAC,CAAE,EAAM,GAAQ,EAAI,MAAM,sCACjC,MAAO,IAA2B,EAAM,WAIxC,MAAO,IC7Bb,GAAI,IAgBG,YACL,EACoB,CACpB,MAAO,SAAW,GAAM,IAAM,CAC5B,GAAM,GAAO,eAAe,QAAQ,SAAS,aAC7C,GAAI,EACF,MAAO,GAAgB,KAAK,MAAM,IAC7B,CACL,GAAM,GAAS,GAAiB,EAAG,MACnC,SAAO,UAAU,GAAS,CACxB,GAAI,CACF,eAAe,QAAQ,SAAS,YAAa,KAAK,UAAU,UACrD,EAAP,KAMG,KAGR,KACC,GAAW,IAAM,GACjB,EAAO,GAAS,OAAO,KAAK,GAAO,OAAS,GAC5C,EAAI,GAAU,EAAE,WAChB,EAAY,KAWX,YACL,EAC+B,CAC/B,GAAM,GAAY,GAAI,GACtB,SAAU,UAAU,CAAC,CAAE,WAAY,CACjC,GAAe,EAAI,GAAkB,IACrC,GAAe,EAAI,UAId,GAAY,GAChB,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,GAAU,GAAE,IAAK,GAAO,KC/B3B,YACL,EAAiB,CAAE,YAAW,WACZ,CAClB,MAAO,IAAiB,SAAS,MAC9B,KACC,EAAU,IAAM,GAAgB,EAAI,CAAE,UAAS,eAC/C,EAAI,CAAC,CAAE,OAAQ,CAAE,QACR,EACL,OAAQ,GAAK,MAGjB,EAAwB,WAevB,YACL,EAAiB,EACY,CAC7B,GAAM,GAAY,GAAI,GACtB,SACG,KACC,EAAU,IAET,UAAU,CAGT,KAAK,CAAE,UAAU,CACf,AAAI,EACF,GAAa,EAAI,UAEjB,GAAe,IAInB,UAAW,CACT,GAAe,MAMrB,IAAQ,0BACJ,EAAG,CAAE,OAAQ,KACb,GAAU,EAAI,IAEjB,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,GAAU,GAAE,IAAK,GAAO,KCrC3B,YACL,EAA8B,CAAE,YAAW,WACd,CAC7B,GAAM,GAAQ,GAAI,KAClB,OAAW,KAAU,GAAS,CAC5B,GAAM,GAAK,mBAAmB,EAAO,KAAK,UAAU,IAC9C,EAAS,GAAW,QAAQ,OAClC,AAAI,MAAO,IAAW,aACpB,EAAM,IAAI,EAAQ,GAItB,GAAM,GAAU,EACb,KACC,EAAI,GAAU,GAAK,EAAO,SA4E9B,MAAO,AAxEY,IAAiB,SAAS,MAC1C,KACC,EAAwB,UAGxB,EAAI,IAAM,CACR,GAAI,GAA4B,GAChC,MAAO,CAAC,GAAG,GAAO,OAAO,CAAC,EAAO,CAAC,EAAQ,KAAY,CACpD,KAAO,EAAK,QAEN,AADS,EAAM,IAAI,EAAK,EAAK,OAAS,IACjC,SAAW,EAAO,SACzB,EAAK,MAOT,GAAI,GAAS,EAAO,UACpB,KAAO,CAAC,GAAU,EAAO,eACvB,EAAS,EAAO,cAChB,EAAS,EAAO,UAIlB,MAAO,GAAM,IACX,CAAC,GAAG,EAAO,CAAC,GAAG,EAAM,IAAS,UAC9B,IAED,GAAI,QAIT,EAAI,GAAS,GAAI,KAAI,CAAC,GAAG,GAAO,KAAK,CAAC,CAAC,CAAE,GAAI,CAAC,CAAE,KAAO,EAAI,KAG3D,EAAU,GAAS,EAAc,CAAC,EAAS,IACxC,KACC,GAAK,CAAC,CAAC,EAAM,GAAO,CAAC,EAAQ,CAAE,OAAQ,CAAE,SAAW,CAGlD,KAAO,EAAK,QAAQ,CAClB,GAAM,CAAC,CAAE,GAAU,EAAK,GACxB,GAAI,EAAS,EAAS,EACpB,EAAO,CAAC,GAAG,EAAM,EAAK,aAEtB,OAKJ,KAAO,EAAK,QAAQ,CAClB,GAAM,CAAC,CAAE,GAAU,EAAK,EAAK,OAAS,GACtC,GAAI,EAAS,GAAU,EACrB,EAAO,CAAC,EAAK,MAAQ,GAAG,OAExB,OAKJ,MAAO,CAAC,EAAM,IACb,CAAC,GAAI,CAAC,GAAG,KACZ,EAAqB,CAAC,EAAG,IACvB,EAAE,KAAO,EAAE,IACX,EAAE,KAAO,EAAE,OAQlB,KACC,EAAI,CAAC,CAAC,EAAM,KAAW,EACrB,KAAM,EAAK,IAAI,CAAC,CAAC,KAAU,GAC3B,KAAM,EAAK,IAAI,CAAC,CAAC,KAAU,MAI7B,EAAU,CAAE,KAAM,GAAI,KAAM,KAC5B,GAAY,EAAG,GACf,EAAI,CAAC,CAAC,EAAG,KAGH,EAAE,KAAK,OAAS,EAAE,KAAK,OAClB,CACL,KAAM,EAAE,KAAK,MAAM,KAAK,IAAI,EAAG,EAAE,KAAK,OAAS,GAAI,EAAE,KAAK,QAC1D,KAAM,IAKD,CACL,KAAM,EAAE,KAAK,MAAM,IACnB,KAAM,EAAE,KAAK,MAAM,EAAG,EAAE,KAAK,OAAS,EAAE,KAAK,WAiBlD,YACL,EAAiB,EACuB,CACxC,GAAM,GAAY,GAAI,GACtB,EACG,KACC,EAAU,IAET,UAAU,CAAC,CAAE,OAAM,UAAW,CAG7B,OAAW,CAAC,IAAW,GACrB,GAAkB,GAClB,GAAiB,GAInB,OAAW,CAAC,EAAO,CAAC,KAAY,GAAK,UACnC,GAAgB,EAAQ,IAAU,EAAK,OAAS,GAChD,GAAe,EAAQ,UAK/B,GAAM,GAAU,EAA+B,cAAe,GAC9D,MAAO,IAAqB,EAAS,GAClC,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,GAAU,GAAE,IAAK,GAAO,KC9K3B,YACL,EAAkB,CAAE,YAAW,SACR,CAGvB,GAAM,GAAa,EAChB,KACC,EAAI,CAAC,CAAE,OAAQ,CAAE,QAAU,GAC3B,GAAY,EAAG,GACf,EAAI,CAAC,CAAC,EAAG,KAAO,EAAI,GAAK,GACzB,KAIE,EAAU,EACb,KACC,EAAwB,WAI5B,MAAO,GAAc,CAAC,EAAS,IAC5B,KACC,EAAI,CAAC,CAAC,CAAE,UAAU,KAAgB,EAChC,OAAQ,CAAE,IAAU,MAEtB,EAAqB,CAAC,EAAG,IACvB,EAAE,SAAW,EAAE,SAehB,YACL,EAAiB,CAAE,YAAW,UAAS,SACL,CAClC,GAAM,GAAY,GAAI,GACtB,SACG,KACC,EAAU,GACV,GAAe,EACZ,KACC,EAAwB,aAI3B,UAAU,CAGT,KAAK,CAAC,CAAE,UAAU,CAAE,WAAW,CAC7B,GAAmB,EAAI,EAAS,IAChC,AAAI,EACF,IAAkB,EAAI,UACtB,GAAgB,EAAI,IACpB,GAAa,EAAI,KAEjB,IAAoB,GACpB,GAAe,KAKnB,UAAW,CACT,GAAqB,GACrB,GAAoB,GACpB,GAAe,MAKhB,GAAe,EAAI,CAAE,YAAW,UAAS,UAC7C,KACC,EAAI,GAAS,EAAU,KAAK,IAC5B,EAAS,IAAM,EAAU,YACzB,EAAI,GAAU,GAAE,IAAK,GAAO,KC1H3B,YACL,CAAE,YAAW,WACP,CACN,EACG,KACC,EAAU,IAAM,EAAG,GAAG,EACpB,mCAEF,EAAI,GAAM,CACR,EAAG,cAAgB,GACnB,EAAG,QAAU,KAEf,GAAS,GAAM,EAAU,EAAI,UAC1B,KACC,GAAU,IAAM,EAAG,aAAa,kBAChC,GAAM,KAGV,GAAe,IAEd,UAAU,CAAC,CAAC,EAAI,KAAY,CAC3B,EAAG,gBAAgB,iBACf,GACF,GAAG,QAAU,MC5BvB,aAAkC,CAChC,MAAO,qBAAqB,KAAK,UAAU,WAkBtC,YACL,CAAE,aACI,CACN,EACG,KACC,EAAU,IAAM,EAAG,GAAG,EAAY,yBAClC,EAAI,GAAM,EAAG,gBAAgB,sBAC7B,EAAO,IACP,GAAS,GAAM,EAAU,EAAI,cAC1B,KACC,GAAM,MAIT,UAAU,GAAM,CACf,GAAM,GAAM,EAAG,UAGf,AAAI,IAAQ,EACV,EAAG,UAAY,EAGN,EAAM,EAAG,eAAiB,EAAG,cACtC,GAAG,UAAY,EAAM,KC9BxB,YACL,CAAE,YAAW,WACP,CACN,EAAc,CAAC,GAAY,UAAW,IACnC,KACC,EAAI,CAAC,CAAC,EAAQ,KAAY,GAAU,CAAC,GACrC,EAAU,GAAU,EAAG,GACpB,KACC,GAAM,EAAS,IAAM,KACrB,EAAU,KAGd,GAAe,IAEd,UAAU,CAAC,CAAC,EAAQ,CAAE,OAAQ,CAAE,SAAU,CACzC,AAAI,EACF,GAAc,SAAS,KAAM,GAE7B,GAAgB,SAAS,QvLDnC,SAAS,gBAAgB,UAAU,OAAO,SAC1C,SAAS,gBAAgB,UAAU,IAAI,MAGvC,GAAM,IAAY,KACZ,GAAY,KACZ,GAAY,KACZ,GAAY,KAGZ,GAAY,KACZ,GAAY,GAAW,sBACvB,GAAY,GAAW,uBACvB,GAAY,KAGZ,GAAS,KACT,GAAS,SAAS,MAAM,UAAU,UACpC,gCAAU,QAAS,GACnB,GAAI,KAAI,2BAA4B,GAAO,OAE3C,EAGE,GAAS,GAAI,GACnB,GAAiB,CAAE,YAGnB,AAAI,GAAQ,uBACV,GAAoB,CAAE,aAAW,aAAW,eA/G9C,OAkHA,AAAI,QAAO,UAAP,eAAgB,YAAa,QAC/B,KAGF,EAAM,GAAW,IACd,KACC,GAAM,MAEL,UAAU,IAAM,CACf,GAAU,SAAU,IACpB,GAAU,SAAU,MAI1B,GACG,KACC,EAAO,CAAC,CAAE,UAAW,IAAS,WAE7B,UAAU,GAAO,CAChB,OAAQ,EAAI,UAGL,QACA,IACH,GAAM,GAAO,GAAW,oBACxB,AAAI,MAAO,IAAS,aAClB,EAAK,QACP,UAGG,QACA,IACH,GAAM,GAAO,GAAW,oBACxB,AAAI,MAAO,IAAS,aAClB,EAAK,QACP,SAKV,GAAmB,CAAE,aAAW,aAChC,GAAe,CAAE,eACjB,GAAgB,CAAE,aAAW,aAG7B,GAAM,IAAU,GAAY,GAAoB,UAAW,CAAE,eACvD,GAAQ,GACX,KACC,EAAI,IAAM,GAAoB,SAC9B,EAAU,GAAM,GAAU,EAAI,CAAE,aAAW,cAC3C,EAAY,IAIV,GAAW,EAGf,GAAG,GAAqB,UACrB,IAAI,GAAM,GAAY,EAAI,CAAE,aAG/B,GAAG,GAAqB,UACrB,IAAI,GAAM,GAAY,EAAI,CAAE,aAAW,WAAS,YAGnD,GAAG,GAAqB,WACrB,IAAI,GAAM,GAAa,IAG1B,GAAG,GAAqB,UACrB,IAAI,GAAM,GAAY,EAAI,CAAE,UAAQ,gBAGvC,GAAG,GAAqB,UACrB,IAAI,GAAM,GAAY,KAIrB,GAAW,GAAM,IAAM,EAG3B,GAAG,GAAqB,WACrB,IAAI,GAAM,GAAa,EAAI,CAAE,WAAS,aAAW,aAGpD,GAAG,GAAqB,WACrB,IAAI,GAAM,GAAQ,oBACf,GAAoB,EAAI,CAAE,UAAQ,eAClC,GAIN,GAAG,GAAqB,gBACrB,IAAI,GAAM,GAAiB,EAAI,CAAE,aAAW,cAG/C,GAAG,GAAqB,WACrB,IAAI,GAAM,EAAG,aAAa,kBAAoB,aAC3C,GAAG,GAAS,IAAM,GAAa,EAAI,CAAE,aAAW,WAAS,YACzD,GAAG,GAAS,IAAM,GAAa,EAAI,CAAE,aAAW,WAAS,aAI/D,GAAG,GAAqB,QACrB,IAAI,GAAM,GAAU,EAAI,CAAE,aAAW,cAGxC,GAAG,GAAqB,OACrB,IAAI,GAAM,GAAqB,EAAI,CAAE,aAAW,cAGnD,GAAG,GAAqB,OACrB,IAAI,GAAM,GAAe,EAAI,CAAE,aAAW,WAAS,cAIlD,GAAa,GAChB,KACC,EAAU,IAAM,IAChB,GAAU,IACV,EAAY,IAIhB,GAAW,YAMX,OAAO,UAAa,GACpB,OAAO,UAAa,GACpB,OAAO,QAAa,GACpB,OAAO,UAAa,GACpB,OAAO,UAAa,GACpB,OAAO,QAAa,GACpB,OAAO,QAAa,GACpB,OAAO,OAAa,GACpB,OAAO,OAAa,GACpB,OAAO,WAAa", + "names": [] +} diff --git a/assets/javascripts/workers/search.ecf98df9.min.js b/assets/javascripts/workers/search.fcfe8b6d.min.js similarity index 71% rename from assets/javascripts/workers/search.ecf98df9.min.js rename to assets/javascripts/workers/search.fcfe8b6d.min.js index f8c73991..32379fdd 100644 --- a/assets/javascripts/workers/search.ecf98df9.min.js +++ b/assets/javascripts/workers/search.fcfe8b6d.min.js @@ -1,4 +1,4 @@ -"use strict";(()=>{var ge=Object.create;var W=Object.defineProperty,ye=Object.defineProperties,me=Object.getOwnPropertyDescriptor,ve=Object.getOwnPropertyDescriptors,xe=Object.getOwnPropertyNames,G=Object.getOwnPropertySymbols,Se=Object.getPrototypeOf,X=Object.prototype.hasOwnProperty,Qe=Object.prototype.propertyIsEnumerable;var J=(t,e,r)=>e in t?W(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,M=(t,e)=>{for(var r in e||(e={}))X.call(e,r)&&J(t,r,e[r]);if(G)for(var r of G(e))Qe.call(e,r)&&J(t,r,e[r]);return t},Z=(t,e)=>ye(t,ve(e));var K=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var be=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of xe(e))!X.call(t,i)&&i!==r&&W(t,i,{get:()=>e[i],enumerable:!(n=me(e,i))||n.enumerable});return t};var H=(t,e,r)=>(r=t!=null?ge(Se(t)):{},be(e||!t||!t.__esModule?W(r,"default",{value:t,enumerable:!0}):r,t));var z=(t,e,r)=>new Promise((n,i)=>{var s=u=>{try{a(r.next(u))}catch(c){i(c)}},o=u=>{try{a(r.throw(u))}catch(c){i(c)}},a=u=>u.done?n(u.value):Promise.resolve(u.value).then(s,o);a((r=r.apply(t,e)).next())});var re=K((ee,te)=>{/** +(()=>{var ge=Object.create;var z=Object.defineProperty;var ye=Object.getOwnPropertyDescriptor;var me=Object.getOwnPropertyNames,G=Object.getOwnPropertySymbols,ve=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty,xe=Object.prototype.propertyIsEnumerable,Pe=Reflect.get,Ie=Reflect.set;var X=(t,e,r)=>e in t?z(t,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):t[e]=r,Z=(t,e)=>{for(var r in e||(e={}))J.call(e,r)&&X(t,r,e[r]);if(G)for(var r of G(e))xe.call(e,r)&&X(t,r,e[r]);return t};var Se=t=>z(t,"__esModule",{value:!0});var K=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var Qe=(t,e,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of me(e))!J.call(t,n)&&n!=="default"&&z(t,n,{get:()=>e[n],enumerable:!(r=ye(e,n))||r.enumerable});return t},W=t=>Qe(Se(z(t!=null?ge(ve(t)):{},"default",t&&t.__esModule&&"default"in t?{get:()=>t.default,enumerable:!0}:{value:t,enumerable:!0})),t);var U=(t,e,r)=>new Promise((n,i)=>{var s=u=>{try{a(r.next(u))}catch(c){i(c)}},o=u=>{try{a(r.throw(u))}catch(c){i(c)}},a=u=>u.done?n(u.value):Promise.resolve(u.value).then(s,o);a((r=r.apply(t,e)).next())});var re=K((ee,te)=>{/** * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 * Copyright (C) 2020 Oliver Nightingale * @license MIT @@ -22,7 +22,7 @@ * lunr.stemmer * Copyright (C) 2020 Oliver Nightingale * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt - */t.stemmer=function(){var e={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},r={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",s=n+"[^aeiouy]*",o=i+"[aeiou]*",a="^("+s+")?"+o+s,u="^("+s+")?"+o+s+"("+o+")?$",c="^("+s+")?"+o+s+o+s,h="^("+s+")?"+i,y=new RegExp(a),g=new RegExp(c),b=new RegExp(u),m=new RegExp(h),Q=/^(.+?)(ss|i)es$/,p=/^(.+?)([^s])s$/,d=/^(.+?)eed$/,w=/^(.+?)(ed|ing)$/,L=/.$/,k=/(at|bl|iz)$/,I=new RegExp("([^aeiouylsz])\\1$"),j=new RegExp("^"+s+i+"[^aeiouwxy]$"),F=/^(.+?[^aeiou])y$/,A=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,N=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,C=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,$=/^(.+?)(s|t)(ion)$/,T=/^(.+?)e$/,V=/ll$/,B=new RegExp("^"+s+i+"[^aeiouwxy]$"),D=function(l){var v,P,E,f,x,R,_;if(l.length<3)return l;if(E=l.substr(0,1),E=="y"&&(l=E.toUpperCase()+l.substr(1)),f=Q,x=p,f.test(l)?l=l.replace(f,"$1$2"):x.test(l)&&(l=l.replace(x,"$1$2")),f=d,x=w,f.test(l)){var S=f.exec(l);f=y,f.test(S[1])&&(f=L,l=l.replace(f,""))}else if(x.test(l)){var S=x.exec(l);v=S[1],x=m,x.test(v)&&(l=v,x=k,R=I,_=j,x.test(l)?l=l+"e":R.test(l)?(f=L,l=l.replace(f,"")):_.test(l)&&(l=l+"e"))}if(f=F,f.test(l)){var S=f.exec(l);v=S[1],l=v+"i"}if(f=A,f.test(l)){var S=f.exec(l);v=S[1],P=S[2],f=y,f.test(v)&&(l=v+e[P])}if(f=N,f.test(l)){var S=f.exec(l);v=S[1],P=S[2],f=y,f.test(v)&&(l=v+r[P])}if(f=C,x=$,f.test(l)){var S=f.exec(l);v=S[1],f=g,f.test(v)&&(l=v)}else if(x.test(l)){var S=x.exec(l);v=S[1]+S[2],x=g,x.test(v)&&(l=v)}if(f=T,f.test(l)){var S=f.exec(l);v=S[1],f=g,x=b,R=B,(f.test(v)||x.test(v)&&!R.test(v))&&(l=v)}return f=V,x=g,f.test(l)&&x.test(l)&&(f=L,l=l.replace(f,"")),E=="y"&&(l=E.toLowerCase()+l.substr(1)),l};return function(O){return O.update(D)}}(),t.Pipeline.registerFunction(t.stemmer,"stemmer");/*! + */t.stemmer=function(){var e={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},r={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",s=n+"[^aeiouy]*",o=i+"[aeiou]*",a="^("+s+")?"+o+s,u="^("+s+")?"+o+s+"("+o+")?$",c="^("+s+")?"+o+s+o+s,h="^("+s+")?"+i,y=new RegExp(a),g=new RegExp(c),b=new RegExp(u),v=new RegExp(h),Q=/^(.+?)(ss|i)es$/,f=/^(.+?)([^s])s$/,p=/^(.+?)eed$/,L=/^(.+?)(ed|ing)$/,w=/.$/,k=/(at|bl|iz)$/,O=new RegExp("([^aeiouylsz])\\1$"),j=new RegExp("^"+s+i+"[^aeiouwxy]$"),C=/^(.+?[^aeiou])y$/,A=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,$=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,D=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,V=/^(.+?)(s|t)(ion)$/,P=/^(.+?)e$/,N=/ll$/,B=new RegExp("^"+s+i+"[^aeiouwxy]$"),M=function(l){var m,I,E,d,x,R,F;if(l.length<3)return l;if(E=l.substr(0,1),E=="y"&&(l=E.toUpperCase()+l.substr(1)),d=Q,x=f,d.test(l)?l=l.replace(d,"$1$2"):x.test(l)&&(l=l.replace(x,"$1$2")),d=p,x=L,d.test(l)){var S=d.exec(l);d=y,d.test(S[1])&&(d=w,l=l.replace(d,""))}else if(x.test(l)){var S=x.exec(l);m=S[1],x=v,x.test(m)&&(l=m,x=k,R=O,F=j,x.test(l)?l=l+"e":R.test(l)?(d=w,l=l.replace(d,"")):F.test(l)&&(l=l+"e"))}if(d=C,d.test(l)){var S=d.exec(l);m=S[1],l=m+"i"}if(d=A,d.test(l)){var S=d.exec(l);m=S[1],I=S[2],d=y,d.test(m)&&(l=m+e[I])}if(d=$,d.test(l)){var S=d.exec(l);m=S[1],I=S[2],d=y,d.test(m)&&(l=m+r[I])}if(d=D,x=V,d.test(l)){var S=d.exec(l);m=S[1],d=g,d.test(m)&&(l=m)}else if(x.test(l)){var S=x.exec(l);m=S[1]+S[2],x=g,x.test(m)&&(l=m)}if(d=P,d.test(l)){var S=d.exec(l);m=S[1],d=g,x=b,R=B,(d.test(m)||x.test(m)&&!R.test(m))&&(l=m)}return d=N,x=g,d.test(l)&&x.test(l)&&(d=w,l=l.replace(d,"")),E=="y"&&(l=E.toLowerCase()+l.substr(1)),l};return function(_){return _.update(M)}}(),t.Pipeline.registerFunction(t.stemmer,"stemmer");/*! * lunr.stopWordFilter * Copyright (C) 2020 Oliver Nightingale */t.generateStopWordFilter=function(e){var r=e.reduce(function(n,i){return n[i]=i,n},{});return function(n){if(n&&r[n.toString()]!==n.toString())return n}},t.stopWordFilter=t.generateStopWordFilter(["a","able","about","across","after","all","almost","also","am","among","an","and","any","are","as","at","be","because","been","but","by","can","cannot","could","dear","did","do","does","either","else","ever","every","for","from","get","got","had","has","have","he","her","hers","him","his","how","however","i","if","in","into","is","it","its","just","least","let","like","likely","may","me","might","most","must","my","neither","no","nor","not","of","off","often","on","only","or","other","our","own","rather","said","say","says","she","should","since","so","some","than","that","the","their","them","then","there","these","they","this","tis","to","too","twas","us","wants","was","we","were","what","when","where","which","while","who","whom","why","will","with","would","yet","you","your"]),t.Pipeline.registerFunction(t.stopWordFilter,"stopWordFilter");/*! @@ -31,18 +31,18 @@ */t.trimmer=function(e){return e.update(function(r){return r.replace(/^\W+/,"").replace(/\W+$/,"")})},t.Pipeline.registerFunction(t.trimmer,"trimmer");/*! * lunr.TokenSet * Copyright (C) 2020 Oliver Nightingale - */t.TokenSet=function(){this.final=!1,this.edges={},this.id=t.TokenSet._nextId,t.TokenSet._nextId+=1},t.TokenSet._nextId=1,t.TokenSet.fromArray=function(e){for(var r=new t.TokenSet.Builder,n=0,i=e.length;n0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new t.TokenSet;s.node.edges["*"]=u}if(s.str.length==0&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var c=s.node.edges["*"];else{var c=new t.TokenSet;s.node.edges["*"]=c}s.str.length==1&&(c.final=!0),i.push({node:c,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var h=s.str.charAt(0),y=s.str.charAt(1),g;y in s.node.edges?g=s.node.edges[y]:(g=new t.TokenSet,s.node.edges[y]=g),s.str.length==1&&(g.final=!0),i.push({node:g,editsRemaining:s.editsRemaining-1,str:h+s.str.slice(2)})}}}return n},t.TokenSet.fromString=function(e){for(var r=new t.TokenSet,n=r,i=0,s=e.length;i=e;r--){var n=this.uncheckedNodes[r],i=n.child.toString();i in this.minimizedNodes?n.parent.edges[n.char]=this.minimizedNodes[i]:(n.child._str=i,this.minimizedNodes[i]=n.child),this.uncheckedNodes.pop()}};/*! + */t.TokenSet=function(){this.final=!1,this.edges={},this.id=t.TokenSet._nextId,t.TokenSet._nextId+=1},t.TokenSet._nextId=1,t.TokenSet.fromArray=function(e){for(var r=new t.TokenSet.Builder,n=0,i=e.length;n0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var u=s.node.edges["*"];else{var u=new t.TokenSet;s.node.edges["*"]=u}if(s.str.length==0&&(u.final=!0),i.push({node:u,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var c=s.node.edges["*"];else{var c=new t.TokenSet;s.node.edges["*"]=c}s.str.length==1&&(c.final=!0),i.push({node:c,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var h=s.str.charAt(0),y=s.str.charAt(1),g;y in s.node.edges?g=s.node.edges[y]:(g=new t.TokenSet,s.node.edges[y]=g),s.str.length==1&&(g.final=!0),i.push({node:g,editsRemaining:s.editsRemaining-1,str:h+s.str.slice(2)})}}}return n},t.TokenSet.fromString=function(e){for(var r=new t.TokenSet,n=r,i=0,s=e.length;i=e;r--){var n=this.uncheckedNodes[r],i=n.child.toString();i in this.minimizedNodes?n.parent.edges[n.char]=this.minimizedNodes[i]:(n.child._str=i,this.minimizedNodes[i]=n.child),this.uncheckedNodes.pop()}};/*! * lunr.Index * Copyright (C) 2020 Oliver Nightingale - */t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(r){var n=new t.QueryParser(e,r);n.parse()})},t.Index.prototype.query=function(e){for(var r=new t.Query(this.fields),n=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),u=0;u1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,r){var n=e[this._ref],i=Object.keys(this._fields);this._documents[n]=r||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,r;do e=this.next(),r=e.charCodeAt(0);while(r>47&&r<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var r=e.next();if(r==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(r.charCodeAt(0)==92){e.escapeCharacter();continue}if(r==":")return t.QueryLexer.lexField;if(r=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(r=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(r=="+"&&e.width()===1||r=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(r.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,r){this.lexer=new t.QueryLexer(e),this.query=r,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var r=e.peekLexeme();if(r!=null)switch(r.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var n="expected either a field or a term, found "+r.type;throw r.str.length>=1&&(n+=" with value '"+r.str+"'"),new t.QueryParseError(n,r.start,r.end)}},t.QueryParser.parsePresence=function(e){var r=e.consumeLexeme();if(r!=null){switch(r.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var n="unrecognised presence operator'"+r.str+"'";throw new t.QueryParseError(n,r.start,r.end)}var i=e.peekLexeme();if(i==null){var n="expecting term or field, found nothing";throw new t.QueryParseError(n,r.start,r.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var n="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(n,i.start,i.end)}}},t.QueryParser.parseField=function(e){var r=e.consumeLexeme();if(r!=null){if(e.query.allFields.indexOf(r.str)==-1){var n=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+r.str+"', possible fields: "+n;throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.fields=[r.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,r.start,r.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var r=e.consumeLexeme();if(r!=null){e.currentClause.term=r.str.toLowerCase(),r.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var n=e.peekLexeme();if(n==null){e.nextClause();return}switch(n.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+n.type+"'";throw new t.QueryParseError(i,n.start,n.end)}}},t.QueryParser.parseEditDistance=function(e){var r=e.consumeLexeme();if(r!=null){var n=parseInt(r.str,10);if(isNaN(n)){var i="edit distance must be numeric";throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.editDistance=n;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var r=e.consumeLexeme();if(r!=null){var n=parseInt(r.str,10);if(isNaN(n)){var i="boost must be numeric";throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.boost=n;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},function(e,r){typeof define=="function"&&define.amd?define(r):typeof ee=="object"?te.exports=r():e.lunr=r()}(this,function(){return t})})()});var q=K((Re,ne)=>{"use strict";/*! + */t.Builder=function(){this._ref="id",this._fields=Object.create(null),this._documents=Object.create(null),this.invertedIndex=Object.create(null),this.fieldTermFrequencies={},this.fieldLengths={},this.tokenizer=t.tokenizer,this.pipeline=new t.Pipeline,this.searchPipeline=new t.Pipeline,this.documentCount=0,this._b=.75,this._k1=1.2,this.termIndex=0,this.metadataWhitelist=[]},t.Builder.prototype.ref=function(e){this._ref=e},t.Builder.prototype.field=function(e,r){if(/\//.test(e))throw new RangeError("Field '"+e+"' contains illegal character '/'");this._fields[e]=r||{}},t.Builder.prototype.b=function(e){e<0?this._b=0:e>1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,r){var n=e[this._ref],i=Object.keys(this._fields);this._documents[n]=r||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,r;do e=this.next(),r=e.charCodeAt(0);while(r>47&&r<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var r=e.next();if(r==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(r.charCodeAt(0)==92){e.escapeCharacter();continue}if(r==":")return t.QueryLexer.lexField;if(r=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(r=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(r=="+"&&e.width()===1||r=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(r.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,r){this.lexer=new t.QueryLexer(e),this.query=r,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var r=e.peekLexeme();if(r!=null)switch(r.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var n="expected either a field or a term, found "+r.type;throw r.str.length>=1&&(n+=" with value '"+r.str+"'"),new t.QueryParseError(n,r.start,r.end)}},t.QueryParser.parsePresence=function(e){var r=e.consumeLexeme();if(r!=null){switch(r.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var n="unrecognised presence operator'"+r.str+"'";throw new t.QueryParseError(n,r.start,r.end)}var i=e.peekLexeme();if(i==null){var n="expecting term or field, found nothing";throw new t.QueryParseError(n,r.start,r.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var n="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(n,i.start,i.end)}}},t.QueryParser.parseField=function(e){var r=e.consumeLexeme();if(r!=null){if(e.query.allFields.indexOf(r.str)==-1){var n=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+r.str+"', possible fields: "+n;throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.fields=[r.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,r.start,r.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var r=e.consumeLexeme();if(r!=null){e.currentClause.term=r.str.toLowerCase(),r.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var n=e.peekLexeme();if(n==null){e.nextClause();return}switch(n.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+n.type+"'";throw new t.QueryParseError(i,n.start,n.end)}}},t.QueryParser.parseEditDistance=function(e){var r=e.consumeLexeme();if(r!=null){var n=parseInt(r.str,10);if(isNaN(n)){var i="edit distance must be numeric";throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.editDistance=n;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var r=e.consumeLexeme();if(r!=null){var n=parseInt(r.str,10);if(isNaN(n)){var i="boost must be numeric";throw new t.QueryParseError(i,r.start,r.end)}e.currentClause.boost=n;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},function(e,r){typeof define=="function"&&define.amd?define(r):typeof ee=="object"?te.exports=r():e.lunr=r()}(this,function(){return t})})()});var H=K((Te,ne)=>{/*! * escape-html * Copyright(c) 2012-2013 TJ Holowaychuk * Copyright(c) 2015 Andreas Lubbe * Copyright(c) 2015 Tiancheng "Timothy" Gu * MIT Licensed - */var Le=/["'&<>]/;ne.exports=we;function we(t){var e=""+t,r=Le.exec(e);if(!r)return e;var n,i="",s=0,o=0;for(s=r.index;s=0;r--){let n=t[r];typeof n!="object"?n=document.createTextNode(n):n.parentNode&&n.parentNode.removeChild(n),r?e.insertBefore(this.previousSibling,n):e.replaceChild(n,this)}}}));var ie=H(q());function se(t){let e=new Map,r=new Set;for(let n of t){let[i,s]=n.location.split("#"),o=n.location,a=n.title,u=n.tags,c=(0,ie.default)(n.text).replace(/\s+(?=[,.:;!?])/g,"").replace(/\s+/g," ");if(s){let h=e.get(i);r.has(h)?e.set(o,{location:o,title:a,text:c,parent:h}):(h.title=n.title,h.text=c,r.add(h))}else e.set(o,M({location:o,title:a,text:c},u&&{tags:u}))}return e}var oe=H(q());function ae(t,e){let r=new RegExp(t.separator,"img"),n=(i,s,o)=>`${s}${o}`;return i=>{i=i.replace(/[\s*+\-:~^]+/g," ").trim();let s=new RegExp(`(^|${t.separator})(${i.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return o=>(e?(0,oe.default)(o):o).replace(s,n).replace(/<\/mark>(\s+)]*>/img,"$1")}}function ue(t){let e=new lunr.Query(["title","text"]);return new lunr.QueryParser(t,e).parse(),e.clauses}function ce(t,e){var i;let r=new Set(t),n={};for(let s=0;s!n.has(i)))]}var U=class{constructor({config:e,docs:r,options:n}){this.options=n,this.documents=se(r),this.highlight=ae(e,!1),lunr.tokenizer.separator=new RegExp(e.separator),this.index=lunr(function(){e.lang.length===1&&e.lang[0]!=="en"?this.use(lunr[e.lang[0]]):e.lang.length>1&&this.use(lunr.multiLanguage(...e.lang));let i=Ee(["trimmer","stopWordFilter","stemmer"],n.pipeline);for(let s of e.lang.map(o=>o==="en"?lunr:lunr[o]))for(let o of i)this.pipeline.remove(s[o]),this.searchPipeline.remove(s[o]);this.ref("location"),this.field("title",{boost:1e3}),this.field("text"),this.field("tags",{boost:1e6,extractor:s=>{let{tags:o=[]}=s;return o.reduce((a,u)=>[...a,...lunr.tokenizer(u)],[])}});for(let s of r)this.add(s,{boost:s.boost})})}search(e){if(e)try{let r=this.highlight(e),n=ue(e).filter(o=>o.presence!==lunr.Query.presence.PROHIBITED),i=this.index.search(`${e}*`).reduce((o,{ref:a,score:u,matchData:c})=>{let h=this.documents.get(a);if(typeof h!="undefined"){let{location:y,title:g,text:b,tags:m,parent:Q}=h,p=ce(n,Object.keys(c.metadata)),d=+!Q+ +Object.values(p).every(w=>w);o.push(Z(M({location:y,title:r(g),text:r(b)},m&&{tags:m.map(r)}),{score:u*(1+d),terms:p}))}return o},[]).sort((o,a)=>a.score-o.score).reduce((o,a)=>{let u=this.documents.get(a.location);if(typeof u!="undefined"){let c="parent"in u?u.parent.location:u.location;o.set(c,[...o.get(c)||[],a])}return o},new Map),s;if(this.options.suggestions){let o=this.index.query(a=>{for(let u of n)a.term(u.term,{fields:["title"],presence:lunr.Query.presence.REQUIRED,wildcard:lunr.Query.wildcard.TRAILING})});s=o.length?Object.keys(o[0].matchData.metadata):[]}return M({items:[...i.values()]},typeof s!="undefined"&&{suggestions:s})}catch(r){console.warn(`Invalid query: ${e} \u2013 see https://bit.ly/2s3ChXG`)}return{items:[]}}};var Y;function ke(t){return z(this,null,function*(){let e="../lunr";if(typeof parent!="undefined"&&"IFrameWorker"in parent){let n=document.querySelector("script[src]"),[i]=n.src.split("/worker");e=e.replace("..",i)}let r=[];for(let n of t.lang){switch(n){case"ja":r.push(`${e}/tinyseg.js`);break;case"hi":case"th":r.push(`${e}/wordcut.js`);break}n!=="en"&&r.push(`${e}/min/lunr.${n}.min.js`)}t.lang.length>1&&r.push(`${e}/min/lunr.multi.min.js`),r.length&&(yield importScripts(`${e}/min/lunr.stemmer.support.min.js`,...r))})}function Te(t){return z(this,null,function*(){switch(t.type){case 0:return yield ke(t.data.config),Y=new U(t.data),{type:1};case 2:return{type:3,data:Y?Y.search(t.data):{items:[]}};default:throw new TypeError("Invalid message type")}})}self.lunr=le.default;addEventListener("message",t=>z(void 0,null,function*(){postMessage(yield Te(t.data))}));})(); -//# sourceMappingURL=search.ecf98df9.min.js.map + */"use strict";var be=/["'&<>]/;ne.exports=we;function we(t){var e=""+t,r=be.exec(e);if(!r)return e;var n,i="",s=0,o=0;for(s=r.index;s`${s}${o}`;return i=>{i=i.replace(/[\s*+\-:~^]+/g," ").trim();let s=new RegExp(`(^|${t.separator})(${i.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return o=>(e?(0,oe.default)(o):o).replace(s,n).replace(/<\/mark>(\s+)]*>/img,"$1")}}function ue(t){let e=new lunr.Query(["title","text"]);return new lunr.QueryParser(t,e).parse(),e.clauses}function ce(t,e){let r=new Set(t),n={};for(let i=0;i!n.has(i)))]}var q=class{constructor({config:e,docs:r,index:n,options:i}){this.options=i,this.documents=se(r),this.highlight=ae(e,!1),lunr.tokenizer.separator=new RegExp(e.separator),typeof n=="undefined"?this.index=lunr(function(){e.lang.length===1&&e.lang[0]!=="en"?this.use(lunr[e.lang[0]]):e.lang.length>1&&this.use(lunr.multiLanguage(...e.lang));let s=Le(["trimmer","stopWordFilter","stemmer"],i.pipeline);for(let o of e.lang.map(a=>a==="en"?lunr:lunr[a]))for(let a of s)this.pipeline.remove(o[a]),this.searchPipeline.remove(o[a]);this.ref("location"),this.field("title",{boost:1e3}),this.field("text");for(let o of r)this.add(o)}):this.index=lunr.Index.load(n)}search(e){if(e)try{let r=this.highlight(e),n=ue(e).filter(o=>o.presence!==lunr.Query.presence.PROHIBITED),i=this.index.search(`${e}*`).reduce((o,{ref:a,score:u,matchData:c})=>{let h=this.documents.get(a);if(typeof h!="undefined"){let{location:y,title:g,text:b,parent:v}=h,Q=ce(n,Object.keys(c.metadata)),f=+!v+ +Object.values(Q).every(p=>p);o.push({location:y,title:r(g),text:r(b),score:u*(1+f),terms:Q})}return o},[]).sort((o,a)=>a.score-o.score).reduce((o,a)=>{let u=this.documents.get(a.location);if(typeof u!="undefined"){let c="parent"in u?u.parent.location:u.location;o.set(c,[...o.get(c)||[],a])}return o},new Map),s;if(this.options.suggestions){let o=this.index.query(a=>{for(let u of n)a.term(u.term,{fields:["title"],presence:lunr.Query.presence.REQUIRED,wildcard:lunr.Query.wildcard.TRAILING})});s=o.length?Object.keys(o[0].matchData.metadata):[]}return Z({items:[...i.values()]},typeof s!="undefined"&&{suggestions:s})}catch(r){console.warn(`Invalid query: ${e} \u2013 see https://bit.ly/2s3ChXG`)}return{items:[]}}};var T;(function(i){i[i.SETUP=0]="SETUP",i[i.READY=1]="READY",i[i.QUERY=2]="QUERY",i[i.RESULT=3]="RESULT"})(T||(T={}));var Y;function Ee(t){return U(this,null,function*(){let e="../lunr";if(typeof parent!="undefined"&&"IFrameWorker"in parent){let n=document.querySelector("script[src]"),[i]=n.src.split("/worker");e=e.replace("..",i)}let r=[];for(let n of t.lang){switch(n){case"ja":r.push(`${e}/tinyseg.js`);break;case"hi":case"th":r.push(`${e}/wordcut.js`);break}n!=="en"&&r.push(`${e}/min/lunr.${n}.min.js`)}t.lang.length>1&&r.push(`${e}/min/lunr.multi.min.js`),r.length&&(yield importScripts(`${e}/min/lunr.stemmer.support.min.js`,...r))})}function ke(t){return U(this,null,function*(){switch(t.type){case T.SETUP:return yield Ee(t.data.config),Y=new q(t.data),{type:T.READY};case T.QUERY:return{type:T.RESULT,data:Y?Y.search(t.data):{items:[]}};default:throw new TypeError("Invalid message type")}})}self.lunr=le.default;addEventListener("message",t=>U(void 0,null,function*(){postMessage(yield ke(t.data))}));})(); +//# sourceMappingURL=search.fcfe8b6d.min.js.map diff --git a/assets/javascripts/workers/search.ecf98df9.min.js.map b/assets/javascripts/workers/search.fcfe8b6d.min.js.map similarity index 59% rename from assets/javascripts/workers/search.ecf98df9.min.js.map rename to assets/javascripts/workers/search.fcfe8b6d.min.js.map index eada3e64..83fb6ec3 100644 --- a/assets/javascripts/workers/search.ecf98df9.min.js.map +++ b/assets/javascripts/workers/search.fcfe8b6d.min.js.map @@ -1,8 +1,7 @@ { "version": 3, - "sources": ["node_modules/lunr/lunr.js", "node_modules/escape-html/index.js", "src/assets/javascripts/integrations/search/worker/main/index.ts", "src/assets/javascripts/polyfills/index.ts", "src/assets/javascripts/integrations/search/document/index.ts", "src/assets/javascripts/integrations/search/highlighter/index.ts", "src/assets/javascripts/integrations/search/query/_/index.ts", "src/assets/javascripts/integrations/search/_/index.ts"], - "sourceRoot": "../../../..", - "sourcesContent": ["/**\n * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9\n * Copyright (C) 2020 Oliver Nightingale\n * @license MIT\n */\n\n;(function(){\n\n/**\n * A convenience function for configuring and constructing\n * a new lunr Index.\n *\n * A lunr.Builder instance is created and the pipeline setup\n * with a trimmer, stop word filter and stemmer.\n *\n * This builder object is yielded to the configuration function\n * that is passed as a parameter, allowing the list of fields\n * and other builder parameters to be customised.\n *\n * All documents _must_ be added within the passed config function.\n *\n * @example\n * var idx = lunr(function () {\n * this.field('title')\n * this.field('body')\n * this.ref('id')\n *\n * documents.forEach(function (doc) {\n * this.add(doc)\n * }, this)\n * })\n *\n * @see {@link lunr.Builder}\n * @see {@link lunr.Pipeline}\n * @see {@link lunr.trimmer}\n * @see {@link lunr.stopWordFilter}\n * @see {@link lunr.stemmer}\n * @namespace {function} lunr\n */\nvar lunr = function (config) {\n var builder = new lunr.Builder\n\n builder.pipeline.add(\n lunr.trimmer,\n lunr.stopWordFilter,\n lunr.stemmer\n )\n\n builder.searchPipeline.add(\n lunr.stemmer\n )\n\n config.call(builder, builder)\n return builder.build()\n}\n\nlunr.version = \"2.3.9\"\n/*!\n * lunr.utils\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A namespace containing utils for the rest of the lunr library\n * @namespace lunr.utils\n */\nlunr.utils = {}\n\n/**\n * Print a warning message to the console.\n *\n * @param {String} message The message to be printed.\n * @memberOf lunr.utils\n * @function\n */\nlunr.utils.warn = (function (global) {\n /* eslint-disable no-console */\n return function (message) {\n if (global.console && console.warn) {\n console.warn(message)\n }\n }\n /* eslint-enable no-console */\n})(this)\n\n/**\n * Convert an object to a string.\n *\n * In the case of `null` and `undefined` the function returns\n * the empty string, in all other cases the result of calling\n * `toString` on the passed object is returned.\n *\n * @param {Any} obj The object to convert to a string.\n * @return {String} string representation of the passed object.\n * @memberOf lunr.utils\n */\nlunr.utils.asString = function (obj) {\n if (obj === void 0 || obj === null) {\n return \"\"\n } else {\n return obj.toString()\n }\n}\n\n/**\n * Clones an object.\n *\n * Will create a copy of an existing object such that any mutations\n * on the copy cannot affect the original.\n *\n * Only shallow objects are supported, passing a nested object to this\n * function will cause a TypeError.\n *\n * Objects with primitives, and arrays of primitives are supported.\n *\n * @param {Object} obj The object to clone.\n * @return {Object} a clone of the passed object.\n * @throws {TypeError} when a nested object is passed.\n * @memberOf Utils\n */\nlunr.utils.clone = function (obj) {\n if (obj === null || obj === undefined) {\n return obj\n }\n\n var clone = Object.create(null),\n keys = Object.keys(obj)\n\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i],\n val = obj[key]\n\n if (Array.isArray(val)) {\n clone[key] = val.slice()\n continue\n }\n\n if (typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean') {\n clone[key] = val\n continue\n }\n\n throw new TypeError(\"clone is not deep and does not support nested objects\")\n }\n\n return clone\n}\nlunr.FieldRef = function (docRef, fieldName, stringValue) {\n this.docRef = docRef\n this.fieldName = fieldName\n this._stringValue = stringValue\n}\n\nlunr.FieldRef.joiner = \"/\"\n\nlunr.FieldRef.fromString = function (s) {\n var n = s.indexOf(lunr.FieldRef.joiner)\n\n if (n === -1) {\n throw \"malformed field ref string\"\n }\n\n var fieldRef = s.slice(0, n),\n docRef = s.slice(n + 1)\n\n return new lunr.FieldRef (docRef, fieldRef, s)\n}\n\nlunr.FieldRef.prototype.toString = function () {\n if (this._stringValue == undefined) {\n this._stringValue = this.fieldName + lunr.FieldRef.joiner + this.docRef\n }\n\n return this._stringValue\n}\n/*!\n * lunr.Set\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A lunr set.\n *\n * @constructor\n */\nlunr.Set = function (elements) {\n this.elements = Object.create(null)\n\n if (elements) {\n this.length = elements.length\n\n for (var i = 0; i < this.length; i++) {\n this.elements[elements[i]] = true\n }\n } else {\n this.length = 0\n }\n}\n\n/**\n * A complete set that contains all elements.\n *\n * @static\n * @readonly\n * @type {lunr.Set}\n */\nlunr.Set.complete = {\n intersect: function (other) {\n return other\n },\n\n union: function () {\n return this\n },\n\n contains: function () {\n return true\n }\n}\n\n/**\n * An empty set that contains no elements.\n *\n * @static\n * @readonly\n * @type {lunr.Set}\n */\nlunr.Set.empty = {\n intersect: function () {\n return this\n },\n\n union: function (other) {\n return other\n },\n\n contains: function () {\n return false\n }\n}\n\n/**\n * Returns true if this set contains the specified object.\n *\n * @param {object} object - Object whose presence in this set is to be tested.\n * @returns {boolean} - True if this set contains the specified object.\n */\nlunr.Set.prototype.contains = function (object) {\n return !!this.elements[object]\n}\n\n/**\n * Returns a new set containing only the elements that are present in both\n * this set and the specified set.\n *\n * @param {lunr.Set} other - set to intersect with this set.\n * @returns {lunr.Set} a new set that is the intersection of this and the specified set.\n */\n\nlunr.Set.prototype.intersect = function (other) {\n var a, b, elements, intersection = []\n\n if (other === lunr.Set.complete) {\n return this\n }\n\n if (other === lunr.Set.empty) {\n return other\n }\n\n if (this.length < other.length) {\n a = this\n b = other\n } else {\n a = other\n b = this\n }\n\n elements = Object.keys(a.elements)\n\n for (var i = 0; i < elements.length; i++) {\n var element = elements[i]\n if (element in b.elements) {\n intersection.push(element)\n }\n }\n\n return new lunr.Set (intersection)\n}\n\n/**\n * Returns a new set combining the elements of this and the specified set.\n *\n * @param {lunr.Set} other - set to union with this set.\n * @return {lunr.Set} a new set that is the union of this and the specified set.\n */\n\nlunr.Set.prototype.union = function (other) {\n if (other === lunr.Set.complete) {\n return lunr.Set.complete\n }\n\n if (other === lunr.Set.empty) {\n return this\n }\n\n return new lunr.Set(Object.keys(this.elements).concat(Object.keys(other.elements)))\n}\n/**\n * A function to calculate the inverse document frequency for\n * a posting. This is shared between the builder and the index\n *\n * @private\n * @param {object} posting - The posting for a given term\n * @param {number} documentCount - The total number of documents.\n */\nlunr.idf = function (posting, documentCount) {\n var documentsWithTerm = 0\n\n for (var fieldName in posting) {\n if (fieldName == '_index') continue // Ignore the term index, its not a field\n documentsWithTerm += Object.keys(posting[fieldName]).length\n }\n\n var x = (documentCount - documentsWithTerm + 0.5) / (documentsWithTerm + 0.5)\n\n return Math.log(1 + Math.abs(x))\n}\n\n/**\n * A token wraps a string representation of a token\n * as it is passed through the text processing pipeline.\n *\n * @constructor\n * @param {string} [str=''] - The string token being wrapped.\n * @param {object} [metadata={}] - Metadata associated with this token.\n */\nlunr.Token = function (str, metadata) {\n this.str = str || \"\"\n this.metadata = metadata || {}\n}\n\n/**\n * Returns the token string that is being wrapped by this object.\n *\n * @returns {string}\n */\nlunr.Token.prototype.toString = function () {\n return this.str\n}\n\n/**\n * A token update function is used when updating or optionally\n * when cloning a token.\n *\n * @callback lunr.Token~updateFunction\n * @param {string} str - The string representation of the token.\n * @param {Object} metadata - All metadata associated with this token.\n */\n\n/**\n * Applies the given function to the wrapped string token.\n *\n * @example\n * token.update(function (str, metadata) {\n * return str.toUpperCase()\n * })\n *\n * @param {lunr.Token~updateFunction} fn - A function to apply to the token string.\n * @returns {lunr.Token}\n */\nlunr.Token.prototype.update = function (fn) {\n this.str = fn(this.str, this.metadata)\n return this\n}\n\n/**\n * Creates a clone of this token. Optionally a function can be\n * applied to the cloned token.\n *\n * @param {lunr.Token~updateFunction} [fn] - An optional function to apply to the cloned token.\n * @returns {lunr.Token}\n */\nlunr.Token.prototype.clone = function (fn) {\n fn = fn || function (s) { return s }\n return new lunr.Token (fn(this.str, this.metadata), this.metadata)\n}\n/*!\n * lunr.tokenizer\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A function for splitting a string into tokens ready to be inserted into\n * the search index. Uses `lunr.tokenizer.separator` to split strings, change\n * the value of this property to change how strings are split into tokens.\n *\n * This tokenizer will convert its parameter to a string by calling `toString` and\n * then will split this string on the character in `lunr.tokenizer.separator`.\n * Arrays will have their elements converted to strings and wrapped in a lunr.Token.\n *\n * Optional metadata can be passed to the tokenizer, this metadata will be cloned and\n * added as metadata to every token that is created from the object to be tokenized.\n *\n * @static\n * @param {?(string|object|object[])} obj - The object to convert into tokens\n * @param {?object} metadata - Optional metadata to associate with every token\n * @returns {lunr.Token[]}\n * @see {@link lunr.Pipeline}\n */\nlunr.tokenizer = function (obj, metadata) {\n if (obj == null || obj == undefined) {\n return []\n }\n\n if (Array.isArray(obj)) {\n return obj.map(function (t) {\n return new lunr.Token(\n lunr.utils.asString(t).toLowerCase(),\n lunr.utils.clone(metadata)\n )\n })\n }\n\n var str = obj.toString().toLowerCase(),\n len = str.length,\n tokens = []\n\n for (var sliceEnd = 0, sliceStart = 0; sliceEnd <= len; sliceEnd++) {\n var char = str.charAt(sliceEnd),\n sliceLength = sliceEnd - sliceStart\n\n if ((char.match(lunr.tokenizer.separator) || sliceEnd == len)) {\n\n if (sliceLength > 0) {\n var tokenMetadata = lunr.utils.clone(metadata) || {}\n tokenMetadata[\"position\"] = [sliceStart, sliceLength]\n tokenMetadata[\"index\"] = tokens.length\n\n tokens.push(\n new lunr.Token (\n str.slice(sliceStart, sliceEnd),\n tokenMetadata\n )\n )\n }\n\n sliceStart = sliceEnd + 1\n }\n\n }\n\n return tokens\n}\n\n/**\n * The separator used to split a string into tokens. Override this property to change the behaviour of\n * `lunr.tokenizer` behaviour when tokenizing strings. By default this splits on whitespace and hyphens.\n *\n * @static\n * @see lunr.tokenizer\n */\nlunr.tokenizer.separator = /[\\s\\-]+/\n/*!\n * lunr.Pipeline\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.Pipelines maintain an ordered list of functions to be applied to all\n * tokens in documents entering the search index and queries being ran against\n * the index.\n *\n * An instance of lunr.Index created with the lunr shortcut will contain a\n * pipeline with a stop word filter and an English language stemmer. Extra\n * functions can be added before or after either of these functions or these\n * default functions can be removed.\n *\n * When run the pipeline will call each function in turn, passing a token, the\n * index of that token in the original list of all tokens and finally a list of\n * all the original tokens.\n *\n * The output of functions in the pipeline will be passed to the next function\n * in the pipeline. To exclude a token from entering the index the function\n * should return undefined, the rest of the pipeline will not be called with\n * this token.\n *\n * For serialisation of pipelines to work, all functions used in an instance of\n * a pipeline should be registered with lunr.Pipeline. Registered functions can\n * then be loaded. If trying to load a serialised pipeline that uses functions\n * that are not registered an error will be thrown.\n *\n * If not planning on serialising the pipeline then registering pipeline functions\n * is not necessary.\n *\n * @constructor\n */\nlunr.Pipeline = function () {\n this._stack = []\n}\n\nlunr.Pipeline.registeredFunctions = Object.create(null)\n\n/**\n * A pipeline function maps lunr.Token to lunr.Token. A lunr.Token contains the token\n * string as well as all known metadata. A pipeline function can mutate the token string\n * or mutate (or add) metadata for a given token.\n *\n * A pipeline function can indicate that the passed token should be discarded by returning\n * null, undefined or an empty string. This token will not be passed to any downstream pipeline\n * functions and will not be added to the index.\n *\n * Multiple tokens can be returned by returning an array of tokens. Each token will be passed\n * to any downstream pipeline functions and all will returned tokens will be added to the index.\n *\n * Any number of pipeline functions may be chained together using a lunr.Pipeline.\n *\n * @interface lunr.PipelineFunction\n * @param {lunr.Token} token - A token from the document being processed.\n * @param {number} i - The index of this token in the complete list of tokens for this document/field.\n * @param {lunr.Token[]} tokens - All tokens for this document/field.\n * @returns {(?lunr.Token|lunr.Token[])}\n */\n\n/**\n * Register a function with the pipeline.\n *\n * Functions that are used in the pipeline should be registered if the pipeline\n * needs to be serialised, or a serialised pipeline needs to be loaded.\n *\n * Registering a function does not add it to a pipeline, functions must still be\n * added to instances of the pipeline for them to be used when running a pipeline.\n *\n * @param {lunr.PipelineFunction} fn - The function to check for.\n * @param {String} label - The label to register this function with\n */\nlunr.Pipeline.registerFunction = function (fn, label) {\n if (label in this.registeredFunctions) {\n lunr.utils.warn('Overwriting existing registered function: ' + label)\n }\n\n fn.label = label\n lunr.Pipeline.registeredFunctions[fn.label] = fn\n}\n\n/**\n * Warns if the function is not registered as a Pipeline function.\n *\n * @param {lunr.PipelineFunction} fn - The function to check for.\n * @private\n */\nlunr.Pipeline.warnIfFunctionNotRegistered = function (fn) {\n var isRegistered = fn.label && (fn.label in this.registeredFunctions)\n\n if (!isRegistered) {\n lunr.utils.warn('Function is not registered with pipeline. This may cause problems when serialising the index.\\n', fn)\n }\n}\n\n/**\n * Loads a previously serialised pipeline.\n *\n * All functions to be loaded must already be registered with lunr.Pipeline.\n * If any function from the serialised data has not been registered then an\n * error will be thrown.\n *\n * @param {Object} serialised - The serialised pipeline to load.\n * @returns {lunr.Pipeline}\n */\nlunr.Pipeline.load = function (serialised) {\n var pipeline = new lunr.Pipeline\n\n serialised.forEach(function (fnName) {\n var fn = lunr.Pipeline.registeredFunctions[fnName]\n\n if (fn) {\n pipeline.add(fn)\n } else {\n throw new Error('Cannot load unregistered function: ' + fnName)\n }\n })\n\n return pipeline\n}\n\n/**\n * Adds new functions to the end of the pipeline.\n *\n * Logs a warning if the function has not been registered.\n *\n * @param {lunr.PipelineFunction[]} functions - Any number of functions to add to the pipeline.\n */\nlunr.Pipeline.prototype.add = function () {\n var fns = Array.prototype.slice.call(arguments)\n\n fns.forEach(function (fn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(fn)\n this._stack.push(fn)\n }, this)\n}\n\n/**\n * Adds a single function after a function that already exists in the\n * pipeline.\n *\n * Logs a warning if the function has not been registered.\n *\n * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline.\n * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline.\n */\nlunr.Pipeline.prototype.after = function (existingFn, newFn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(newFn)\n\n var pos = this._stack.indexOf(existingFn)\n if (pos == -1) {\n throw new Error('Cannot find existingFn')\n }\n\n pos = pos + 1\n this._stack.splice(pos, 0, newFn)\n}\n\n/**\n * Adds a single function before a function that already exists in the\n * pipeline.\n *\n * Logs a warning if the function has not been registered.\n *\n * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline.\n * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline.\n */\nlunr.Pipeline.prototype.before = function (existingFn, newFn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(newFn)\n\n var pos = this._stack.indexOf(existingFn)\n if (pos == -1) {\n throw new Error('Cannot find existingFn')\n }\n\n this._stack.splice(pos, 0, newFn)\n}\n\n/**\n * Removes a function from the pipeline.\n *\n * @param {lunr.PipelineFunction} fn The function to remove from the pipeline.\n */\nlunr.Pipeline.prototype.remove = function (fn) {\n var pos = this._stack.indexOf(fn)\n if (pos == -1) {\n return\n }\n\n this._stack.splice(pos, 1)\n}\n\n/**\n * Runs the current list of functions that make up the pipeline against the\n * passed tokens.\n *\n * @param {Array} tokens The tokens to run through the pipeline.\n * @returns {Array}\n */\nlunr.Pipeline.prototype.run = function (tokens) {\n var stackLength = this._stack.length\n\n for (var i = 0; i < stackLength; i++) {\n var fn = this._stack[i]\n var memo = []\n\n for (var j = 0; j < tokens.length; j++) {\n var result = fn(tokens[j], j, tokens)\n\n if (result === null || result === void 0 || result === '') continue\n\n if (Array.isArray(result)) {\n for (var k = 0; k < result.length; k++) {\n memo.push(result[k])\n }\n } else {\n memo.push(result)\n }\n }\n\n tokens = memo\n }\n\n return tokens\n}\n\n/**\n * Convenience method for passing a string through a pipeline and getting\n * strings out. This method takes care of wrapping the passed string in a\n * token and mapping the resulting tokens back to strings.\n *\n * @param {string} str - The string to pass through the pipeline.\n * @param {?object} metadata - Optional metadata to associate with the token\n * passed to the pipeline.\n * @returns {string[]}\n */\nlunr.Pipeline.prototype.runString = function (str, metadata) {\n var token = new lunr.Token (str, metadata)\n\n return this.run([token]).map(function (t) {\n return t.toString()\n })\n}\n\n/**\n * Resets the pipeline by removing any existing processors.\n *\n */\nlunr.Pipeline.prototype.reset = function () {\n this._stack = []\n}\n\n/**\n * Returns a representation of the pipeline ready for serialisation.\n *\n * Logs a warning if the function has not been registered.\n *\n * @returns {Array}\n */\nlunr.Pipeline.prototype.toJSON = function () {\n return this._stack.map(function (fn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(fn)\n\n return fn.label\n })\n}\n/*!\n * lunr.Vector\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A vector is used to construct the vector space of documents and queries. These\n * vectors support operations to determine the similarity between two documents or\n * a document and a query.\n *\n * Normally no parameters are required for initializing a vector, but in the case of\n * loading a previously dumped vector the raw elements can be provided to the constructor.\n *\n * For performance reasons vectors are implemented with a flat array, where an elements\n * index is immediately followed by its value. E.g. [index, value, index, value]. This\n * allows the underlying array to be as sparse as possible and still offer decent\n * performance when being used for vector calculations.\n *\n * @constructor\n * @param {Number[]} [elements] - The flat list of element index and element value pairs.\n */\nlunr.Vector = function (elements) {\n this._magnitude = 0\n this.elements = elements || []\n}\n\n\n/**\n * Calculates the position within the vector to insert a given index.\n *\n * This is used internally by insert and upsert. If there are duplicate indexes then\n * the position is returned as if the value for that index were to be updated, but it\n * is the callers responsibility to check whether there is a duplicate at that index\n *\n * @param {Number} insertIdx - The index at which the element should be inserted.\n * @returns {Number}\n */\nlunr.Vector.prototype.positionForIndex = function (index) {\n // For an empty vector the tuple can be inserted at the beginning\n if (this.elements.length == 0) {\n return 0\n }\n\n var start = 0,\n end = this.elements.length / 2,\n sliceLength = end - start,\n pivotPoint = Math.floor(sliceLength / 2),\n pivotIndex = this.elements[pivotPoint * 2]\n\n while (sliceLength > 1) {\n if (pivotIndex < index) {\n start = pivotPoint\n }\n\n if (pivotIndex > index) {\n end = pivotPoint\n }\n\n if (pivotIndex == index) {\n break\n }\n\n sliceLength = end - start\n pivotPoint = start + Math.floor(sliceLength / 2)\n pivotIndex = this.elements[pivotPoint * 2]\n }\n\n if (pivotIndex == index) {\n return pivotPoint * 2\n }\n\n if (pivotIndex > index) {\n return pivotPoint * 2\n }\n\n if (pivotIndex < index) {\n return (pivotPoint + 1) * 2\n }\n}\n\n/**\n * Inserts an element at an index within the vector.\n *\n * Does not allow duplicates, will throw an error if there is already an entry\n * for this index.\n *\n * @param {Number} insertIdx - The index at which the element should be inserted.\n * @param {Number} val - The value to be inserted into the vector.\n */\nlunr.Vector.prototype.insert = function (insertIdx, val) {\n this.upsert(insertIdx, val, function () {\n throw \"duplicate index\"\n })\n}\n\n/**\n * Inserts or updates an existing index within the vector.\n *\n * @param {Number} insertIdx - The index at which the element should be inserted.\n * @param {Number} val - The value to be inserted into the vector.\n * @param {function} fn - A function that is called for updates, the existing value and the\n * requested value are passed as arguments\n */\nlunr.Vector.prototype.upsert = function (insertIdx, val, fn) {\n this._magnitude = 0\n var position = this.positionForIndex(insertIdx)\n\n if (this.elements[position] == insertIdx) {\n this.elements[position + 1] = fn(this.elements[position + 1], val)\n } else {\n this.elements.splice(position, 0, insertIdx, val)\n }\n}\n\n/**\n * Calculates the magnitude of this vector.\n *\n * @returns {Number}\n */\nlunr.Vector.prototype.magnitude = function () {\n if (this._magnitude) return this._magnitude\n\n var sumOfSquares = 0,\n elementsLength = this.elements.length\n\n for (var i = 1; i < elementsLength; i += 2) {\n var val = this.elements[i]\n sumOfSquares += val * val\n }\n\n return this._magnitude = Math.sqrt(sumOfSquares)\n}\n\n/**\n * Calculates the dot product of this vector and another vector.\n *\n * @param {lunr.Vector} otherVector - The vector to compute the dot product with.\n * @returns {Number}\n */\nlunr.Vector.prototype.dot = function (otherVector) {\n var dotProduct = 0,\n a = this.elements, b = otherVector.elements,\n aLen = a.length, bLen = b.length,\n aVal = 0, bVal = 0,\n i = 0, j = 0\n\n while (i < aLen && j < bLen) {\n aVal = a[i], bVal = b[j]\n if (aVal < bVal) {\n i += 2\n } else if (aVal > bVal) {\n j += 2\n } else if (aVal == bVal) {\n dotProduct += a[i + 1] * b[j + 1]\n i += 2\n j += 2\n }\n }\n\n return dotProduct\n}\n\n/**\n * Calculates the similarity between this vector and another vector.\n *\n * @param {lunr.Vector} otherVector - The other vector to calculate the\n * similarity with.\n * @returns {Number}\n */\nlunr.Vector.prototype.similarity = function (otherVector) {\n return this.dot(otherVector) / this.magnitude() || 0\n}\n\n/**\n * Converts the vector to an array of the elements within the vector.\n *\n * @returns {Number[]}\n */\nlunr.Vector.prototype.toArray = function () {\n var output = new Array (this.elements.length / 2)\n\n for (var i = 1, j = 0; i < this.elements.length; i += 2, j++) {\n output[j] = this.elements[i]\n }\n\n return output\n}\n\n/**\n * A JSON serializable representation of the vector.\n *\n * @returns {Number[]}\n */\nlunr.Vector.prototype.toJSON = function () {\n return this.elements\n}\n/* eslint-disable */\n/*!\n * lunr.stemmer\n * Copyright (C) 2020 Oliver Nightingale\n * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt\n */\n\n/**\n * lunr.stemmer is an english language stemmer, this is a JavaScript\n * implementation of the PorterStemmer taken from http://tartarus.org/~martin\n *\n * @static\n * @implements {lunr.PipelineFunction}\n * @param {lunr.Token} token - The string to stem\n * @returns {lunr.Token}\n * @see {@link lunr.Pipeline}\n * @function\n */\nlunr.stemmer = (function(){\n var step2list = {\n \"ational\" : \"ate\",\n \"tional\" : \"tion\",\n \"enci\" : \"ence\",\n \"anci\" : \"ance\",\n \"izer\" : \"ize\",\n \"bli\" : \"ble\",\n \"alli\" : \"al\",\n \"entli\" : \"ent\",\n \"eli\" : \"e\",\n \"ousli\" : \"ous\",\n \"ization\" : \"ize\",\n \"ation\" : \"ate\",\n \"ator\" : \"ate\",\n \"alism\" : \"al\",\n \"iveness\" : \"ive\",\n \"fulness\" : \"ful\",\n \"ousness\" : \"ous\",\n \"aliti\" : \"al\",\n \"iviti\" : \"ive\",\n \"biliti\" : \"ble\",\n \"logi\" : \"log\"\n },\n\n step3list = {\n \"icate\" : \"ic\",\n \"ative\" : \"\",\n \"alize\" : \"al\",\n \"iciti\" : \"ic\",\n \"ical\" : \"ic\",\n \"ful\" : \"\",\n \"ness\" : \"\"\n },\n\n c = \"[^aeiou]\", // consonant\n v = \"[aeiouy]\", // vowel\n C = c + \"[^aeiouy]*\", // consonant sequence\n V = v + \"[aeiou]*\", // vowel sequence\n\n mgr0 = \"^(\" + C + \")?\" + V + C, // [C]VC... is m>0\n meq1 = \"^(\" + C + \")?\" + V + C + \"(\" + V + \")?$\", // [C]VC[V] is m=1\n mgr1 = \"^(\" + C + \")?\" + V + C + V + C, // [C]VCVC... is m>1\n s_v = \"^(\" + C + \")?\" + v; // vowel in stem\n\n var re_mgr0 = new RegExp(mgr0);\n var re_mgr1 = new RegExp(mgr1);\n var re_meq1 = new RegExp(meq1);\n var re_s_v = new RegExp(s_v);\n\n var re_1a = /^(.+?)(ss|i)es$/;\n var re2_1a = /^(.+?)([^s])s$/;\n var re_1b = /^(.+?)eed$/;\n var re2_1b = /^(.+?)(ed|ing)$/;\n var re_1b_2 = /.$/;\n var re2_1b_2 = /(at|bl|iz)$/;\n var re3_1b_2 = new RegExp(\"([^aeiouylsz])\\\\1$\");\n var re4_1b_2 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n\n var re_1c = /^(.+?[^aeiou])y$/;\n var re_2 = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;\n\n var re_3 = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;\n\n var re_4 = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;\n var re2_4 = /^(.+?)(s|t)(ion)$/;\n\n var re_5 = /^(.+?)e$/;\n var re_5_1 = /ll$/;\n var re3_5 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n\n var porterStemmer = function porterStemmer(w) {\n var stem,\n suffix,\n firstch,\n re,\n re2,\n re3,\n re4;\n\n if (w.length < 3) { return w; }\n\n firstch = w.substr(0,1);\n if (firstch == \"y\") {\n w = firstch.toUpperCase() + w.substr(1);\n }\n\n // Step 1a\n re = re_1a\n re2 = re2_1a;\n\n if (re.test(w)) { w = w.replace(re,\"$1$2\"); }\n else if (re2.test(w)) { w = w.replace(re2,\"$1$2\"); }\n\n // Step 1b\n re = re_1b;\n re2 = re2_1b;\n if (re.test(w)) {\n var fp = re.exec(w);\n re = re_mgr0;\n if (re.test(fp[1])) {\n re = re_1b_2;\n w = w.replace(re,\"\");\n }\n } else if (re2.test(w)) {\n var fp = re2.exec(w);\n stem = fp[1];\n re2 = re_s_v;\n if (re2.test(stem)) {\n w = stem;\n re2 = re2_1b_2;\n re3 = re3_1b_2;\n re4 = re4_1b_2;\n if (re2.test(w)) { w = w + \"e\"; }\n else if (re3.test(w)) { re = re_1b_2; w = w.replace(re,\"\"); }\n else if (re4.test(w)) { w = w + \"e\"; }\n }\n }\n\n // Step 1c - replace suffix y or Y by i if preceded by a non-vowel which is not the first letter of the word (so cry -> cri, by -> by, say -> say)\n re = re_1c;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n w = stem + \"i\";\n }\n\n // Step 2\n re = re_2;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n suffix = fp[2];\n re = re_mgr0;\n if (re.test(stem)) {\n w = stem + step2list[suffix];\n }\n }\n\n // Step 3\n re = re_3;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n suffix = fp[2];\n re = re_mgr0;\n if (re.test(stem)) {\n w = stem + step3list[suffix];\n }\n }\n\n // Step 4\n re = re_4;\n re2 = re2_4;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n re = re_mgr1;\n if (re.test(stem)) {\n w = stem;\n }\n } else if (re2.test(w)) {\n var fp = re2.exec(w);\n stem = fp[1] + fp[2];\n re2 = re_mgr1;\n if (re2.test(stem)) {\n w = stem;\n }\n }\n\n // Step 5\n re = re_5;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n re = re_mgr1;\n re2 = re_meq1;\n re3 = re3_5;\n if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) {\n w = stem;\n }\n }\n\n re = re_5_1;\n re2 = re_mgr1;\n if (re.test(w) && re2.test(w)) {\n re = re_1b_2;\n w = w.replace(re,\"\");\n }\n\n // and turn initial Y back to y\n\n if (firstch == \"y\") {\n w = firstch.toLowerCase() + w.substr(1);\n }\n\n return w;\n };\n\n return function (token) {\n return token.update(porterStemmer);\n }\n})();\n\nlunr.Pipeline.registerFunction(lunr.stemmer, 'stemmer')\n/*!\n * lunr.stopWordFilter\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.generateStopWordFilter builds a stopWordFilter function from the provided\n * list of stop words.\n *\n * The built in lunr.stopWordFilter is built using this generator and can be used\n * to generate custom stopWordFilters for applications or non English languages.\n *\n * @function\n * @param {Array} token The token to pass through the filter\n * @returns {lunr.PipelineFunction}\n * @see lunr.Pipeline\n * @see lunr.stopWordFilter\n */\nlunr.generateStopWordFilter = function (stopWords) {\n var words = stopWords.reduce(function (memo, stopWord) {\n memo[stopWord] = stopWord\n return memo\n }, {})\n\n return function (token) {\n if (token && words[token.toString()] !== token.toString()) return token\n }\n}\n\n/**\n * lunr.stopWordFilter is an English language stop word list filter, any words\n * contained in the list will not be passed through the filter.\n *\n * This is intended to be used in the Pipeline. If the token does not pass the\n * filter then undefined will be returned.\n *\n * @function\n * @implements {lunr.PipelineFunction}\n * @params {lunr.Token} token - A token to check for being a stop word.\n * @returns {lunr.Token}\n * @see {@link lunr.Pipeline}\n */\nlunr.stopWordFilter = lunr.generateStopWordFilter([\n 'a',\n 'able',\n 'about',\n 'across',\n 'after',\n 'all',\n 'almost',\n 'also',\n 'am',\n 'among',\n 'an',\n 'and',\n 'any',\n 'are',\n 'as',\n 'at',\n 'be',\n 'because',\n 'been',\n 'but',\n 'by',\n 'can',\n 'cannot',\n 'could',\n 'dear',\n 'did',\n 'do',\n 'does',\n 'either',\n 'else',\n 'ever',\n 'every',\n 'for',\n 'from',\n 'get',\n 'got',\n 'had',\n 'has',\n 'have',\n 'he',\n 'her',\n 'hers',\n 'him',\n 'his',\n 'how',\n 'however',\n 'i',\n 'if',\n 'in',\n 'into',\n 'is',\n 'it',\n 'its',\n 'just',\n 'least',\n 'let',\n 'like',\n 'likely',\n 'may',\n 'me',\n 'might',\n 'most',\n 'must',\n 'my',\n 'neither',\n 'no',\n 'nor',\n 'not',\n 'of',\n 'off',\n 'often',\n 'on',\n 'only',\n 'or',\n 'other',\n 'our',\n 'own',\n 'rather',\n 'said',\n 'say',\n 'says',\n 'she',\n 'should',\n 'since',\n 'so',\n 'some',\n 'than',\n 'that',\n 'the',\n 'their',\n 'them',\n 'then',\n 'there',\n 'these',\n 'they',\n 'this',\n 'tis',\n 'to',\n 'too',\n 'twas',\n 'us',\n 'wants',\n 'was',\n 'we',\n 'were',\n 'what',\n 'when',\n 'where',\n 'which',\n 'while',\n 'who',\n 'whom',\n 'why',\n 'will',\n 'with',\n 'would',\n 'yet',\n 'you',\n 'your'\n])\n\nlunr.Pipeline.registerFunction(lunr.stopWordFilter, 'stopWordFilter')\n/*!\n * lunr.trimmer\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.trimmer is a pipeline function for trimming non word\n * characters from the beginning and end of tokens before they\n * enter the index.\n *\n * This implementation may not work correctly for non latin\n * characters and should either be removed or adapted for use\n * with languages with non-latin characters.\n *\n * @static\n * @implements {lunr.PipelineFunction}\n * @param {lunr.Token} token The token to pass through the filter\n * @returns {lunr.Token}\n * @see lunr.Pipeline\n */\nlunr.trimmer = function (token) {\n return token.update(function (s) {\n return s.replace(/^\\W+/, '').replace(/\\W+$/, '')\n })\n}\n\nlunr.Pipeline.registerFunction(lunr.trimmer, 'trimmer')\n/*!\n * lunr.TokenSet\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A token set is used to store the unique list of all tokens\n * within an index. Token sets are also used to represent an\n * incoming query to the index, this query token set and index\n * token set are then intersected to find which tokens to look\n * up in the inverted index.\n *\n * A token set can hold multiple tokens, as in the case of the\n * index token set, or it can hold a single token as in the\n * case of a simple query token set.\n *\n * Additionally token sets are used to perform wildcard matching.\n * Leading, contained and trailing wildcards are supported, and\n * from this edit distance matching can also be provided.\n *\n * Token sets are implemented as a minimal finite state automata,\n * where both common prefixes and suffixes are shared between tokens.\n * This helps to reduce the space used for storing the token set.\n *\n * @constructor\n */\nlunr.TokenSet = function () {\n this.final = false\n this.edges = {}\n this.id = lunr.TokenSet._nextId\n lunr.TokenSet._nextId += 1\n}\n\n/**\n * Keeps track of the next, auto increment, identifier to assign\n * to a new tokenSet.\n *\n * TokenSets require a unique identifier to be correctly minimised.\n *\n * @private\n */\nlunr.TokenSet._nextId = 1\n\n/**\n * Creates a TokenSet instance from the given sorted array of words.\n *\n * @param {String[]} arr - A sorted array of strings to create the set from.\n * @returns {lunr.TokenSet}\n * @throws Will throw an error if the input array is not sorted.\n */\nlunr.TokenSet.fromArray = function (arr) {\n var builder = new lunr.TokenSet.Builder\n\n for (var i = 0, len = arr.length; i < len; i++) {\n builder.insert(arr[i])\n }\n\n builder.finish()\n return builder.root\n}\n\n/**\n * Creates a token set from a query clause.\n *\n * @private\n * @param {Object} clause - A single clause from lunr.Query.\n * @param {string} clause.term - The query clause term.\n * @param {number} [clause.editDistance] - The optional edit distance for the term.\n * @returns {lunr.TokenSet}\n */\nlunr.TokenSet.fromClause = function (clause) {\n if ('editDistance' in clause) {\n return lunr.TokenSet.fromFuzzyString(clause.term, clause.editDistance)\n } else {\n return lunr.TokenSet.fromString(clause.term)\n }\n}\n\n/**\n * Creates a token set representing a single string with a specified\n * edit distance.\n *\n * Insertions, deletions, substitutions and transpositions are each\n * treated as an edit distance of 1.\n *\n * Increasing the allowed edit distance will have a dramatic impact\n * on the performance of both creating and intersecting these TokenSets.\n * It is advised to keep the edit distance less than 3.\n *\n * @param {string} str - The string to create the token set from.\n * @param {number} editDistance - The allowed edit distance to match.\n * @returns {lunr.Vector}\n */\nlunr.TokenSet.fromFuzzyString = function (str, editDistance) {\n var root = new lunr.TokenSet\n\n var stack = [{\n node: root,\n editsRemaining: editDistance,\n str: str\n }]\n\n while (stack.length) {\n var frame = stack.pop()\n\n // no edit\n if (frame.str.length > 0) {\n var char = frame.str.charAt(0),\n noEditNode\n\n if (char in frame.node.edges) {\n noEditNode = frame.node.edges[char]\n } else {\n noEditNode = new lunr.TokenSet\n frame.node.edges[char] = noEditNode\n }\n\n if (frame.str.length == 1) {\n noEditNode.final = true\n }\n\n stack.push({\n node: noEditNode,\n editsRemaining: frame.editsRemaining,\n str: frame.str.slice(1)\n })\n }\n\n if (frame.editsRemaining == 0) {\n continue\n }\n\n // insertion\n if (\"*\" in frame.node.edges) {\n var insertionNode = frame.node.edges[\"*\"]\n } else {\n var insertionNode = new lunr.TokenSet\n frame.node.edges[\"*\"] = insertionNode\n }\n\n if (frame.str.length == 0) {\n insertionNode.final = true\n }\n\n stack.push({\n node: insertionNode,\n editsRemaining: frame.editsRemaining - 1,\n str: frame.str\n })\n\n // deletion\n // can only do a deletion if we have enough edits remaining\n // and if there are characters left to delete in the string\n if (frame.str.length > 1) {\n stack.push({\n node: frame.node,\n editsRemaining: frame.editsRemaining - 1,\n str: frame.str.slice(1)\n })\n }\n\n // deletion\n // just removing the last character from the str\n if (frame.str.length == 1) {\n frame.node.final = true\n }\n\n // substitution\n // can only do a substitution if we have enough edits remaining\n // and if there are characters left to substitute\n if (frame.str.length >= 1) {\n if (\"*\" in frame.node.edges) {\n var substitutionNode = frame.node.edges[\"*\"]\n } else {\n var substitutionNode = new lunr.TokenSet\n frame.node.edges[\"*\"] = substitutionNode\n }\n\n if (frame.str.length == 1) {\n substitutionNode.final = true\n }\n\n stack.push({\n node: substitutionNode,\n editsRemaining: frame.editsRemaining - 1,\n str: frame.str.slice(1)\n })\n }\n\n // transposition\n // can only do a transposition if there are edits remaining\n // and there are enough characters to transpose\n if (frame.str.length > 1) {\n var charA = frame.str.charAt(0),\n charB = frame.str.charAt(1),\n transposeNode\n\n if (charB in frame.node.edges) {\n transposeNode = frame.node.edges[charB]\n } else {\n transposeNode = new lunr.TokenSet\n frame.node.edges[charB] = transposeNode\n }\n\n if (frame.str.length == 1) {\n transposeNode.final = true\n }\n\n stack.push({\n node: transposeNode,\n editsRemaining: frame.editsRemaining - 1,\n str: charA + frame.str.slice(2)\n })\n }\n }\n\n return root\n}\n\n/**\n * Creates a TokenSet from a string.\n *\n * The string may contain one or more wildcard characters (*)\n * that will allow wildcard matching when intersecting with\n * another TokenSet.\n *\n * @param {string} str - The string to create a TokenSet from.\n * @returns {lunr.TokenSet}\n */\nlunr.TokenSet.fromString = function (str) {\n var node = new lunr.TokenSet,\n root = node\n\n /*\n * Iterates through all characters within the passed string\n * appending a node for each character.\n *\n * When a wildcard character is found then a self\n * referencing edge is introduced to continually match\n * any number of any characters.\n */\n for (var i = 0, len = str.length; i < len; i++) {\n var char = str[i],\n final = (i == len - 1)\n\n if (char == \"*\") {\n node.edges[char] = node\n node.final = final\n\n } else {\n var next = new lunr.TokenSet\n next.final = final\n\n node.edges[char] = next\n node = next\n }\n }\n\n return root\n}\n\n/**\n * Converts this TokenSet into an array of strings\n * contained within the TokenSet.\n *\n * This is not intended to be used on a TokenSet that\n * contains wildcards, in these cases the results are\n * undefined and are likely to cause an infinite loop.\n *\n * @returns {string[]}\n */\nlunr.TokenSet.prototype.toArray = function () {\n var words = []\n\n var stack = [{\n prefix: \"\",\n node: this\n }]\n\n while (stack.length) {\n var frame = stack.pop(),\n edges = Object.keys(frame.node.edges),\n len = edges.length\n\n if (frame.node.final) {\n /* In Safari, at this point the prefix is sometimes corrupted, see:\n * https://github.com/olivernn/lunr.js/issues/279 Calling any\n * String.prototype method forces Safari to \"cast\" this string to what\n * it's supposed to be, fixing the bug. */\n frame.prefix.charAt(0)\n words.push(frame.prefix)\n }\n\n for (var i = 0; i < len; i++) {\n var edge = edges[i]\n\n stack.push({\n prefix: frame.prefix.concat(edge),\n node: frame.node.edges[edge]\n })\n }\n }\n\n return words\n}\n\n/**\n * Generates a string representation of a TokenSet.\n *\n * This is intended to allow TokenSets to be used as keys\n * in objects, largely to aid the construction and minimisation\n * of a TokenSet. As such it is not designed to be a human\n * friendly representation of the TokenSet.\n *\n * @returns {string}\n */\nlunr.TokenSet.prototype.toString = function () {\n // NOTE: Using Object.keys here as this.edges is very likely\n // to enter 'hash-mode' with many keys being added\n //\n // avoiding a for-in loop here as it leads to the function\n // being de-optimised (at least in V8). From some simple\n // benchmarks the performance is comparable, but allowing\n // V8 to optimize may mean easy performance wins in the future.\n\n if (this._str) {\n return this._str\n }\n\n var str = this.final ? '1' : '0',\n labels = Object.keys(this.edges).sort(),\n len = labels.length\n\n for (var i = 0; i < len; i++) {\n var label = labels[i],\n node = this.edges[label]\n\n str = str + label + node.id\n }\n\n return str\n}\n\n/**\n * Returns a new TokenSet that is the intersection of\n * this TokenSet and the passed TokenSet.\n *\n * This intersection will take into account any wildcards\n * contained within the TokenSet.\n *\n * @param {lunr.TokenSet} b - An other TokenSet to intersect with.\n * @returns {lunr.TokenSet}\n */\nlunr.TokenSet.prototype.intersect = function (b) {\n var output = new lunr.TokenSet,\n frame = undefined\n\n var stack = [{\n qNode: b,\n output: output,\n node: this\n }]\n\n while (stack.length) {\n frame = stack.pop()\n\n // NOTE: As with the #toString method, we are using\n // Object.keys and a for loop instead of a for-in loop\n // as both of these objects enter 'hash' mode, causing\n // the function to be de-optimised in V8\n var qEdges = Object.keys(frame.qNode.edges),\n qLen = qEdges.length,\n nEdges = Object.keys(frame.node.edges),\n nLen = nEdges.length\n\n for (var q = 0; q < qLen; q++) {\n var qEdge = qEdges[q]\n\n for (var n = 0; n < nLen; n++) {\n var nEdge = nEdges[n]\n\n if (nEdge == qEdge || qEdge == '*') {\n var node = frame.node.edges[nEdge],\n qNode = frame.qNode.edges[qEdge],\n final = node.final && qNode.final,\n next = undefined\n\n if (nEdge in frame.output.edges) {\n // an edge already exists for this character\n // no need to create a new node, just set the finality\n // bit unless this node is already final\n next = frame.output.edges[nEdge]\n next.final = next.final || final\n\n } else {\n // no edge exists yet, must create one\n // set the finality bit and insert it\n // into the output\n next = new lunr.TokenSet\n next.final = final\n frame.output.edges[nEdge] = next\n }\n\n stack.push({\n qNode: qNode,\n output: next,\n node: node\n })\n }\n }\n }\n }\n\n return output\n}\nlunr.TokenSet.Builder = function () {\n this.previousWord = \"\"\n this.root = new lunr.TokenSet\n this.uncheckedNodes = []\n this.minimizedNodes = {}\n}\n\nlunr.TokenSet.Builder.prototype.insert = function (word) {\n var node,\n commonPrefix = 0\n\n if (word < this.previousWord) {\n throw new Error (\"Out of order word insertion\")\n }\n\n for (var i = 0; i < word.length && i < this.previousWord.length; i++) {\n if (word[i] != this.previousWord[i]) break\n commonPrefix++\n }\n\n this.minimize(commonPrefix)\n\n if (this.uncheckedNodes.length == 0) {\n node = this.root\n } else {\n node = this.uncheckedNodes[this.uncheckedNodes.length - 1].child\n }\n\n for (var i = commonPrefix; i < word.length; i++) {\n var nextNode = new lunr.TokenSet,\n char = word[i]\n\n node.edges[char] = nextNode\n\n this.uncheckedNodes.push({\n parent: node,\n char: char,\n child: nextNode\n })\n\n node = nextNode\n }\n\n node.final = true\n this.previousWord = word\n}\n\nlunr.TokenSet.Builder.prototype.finish = function () {\n this.minimize(0)\n}\n\nlunr.TokenSet.Builder.prototype.minimize = function (downTo) {\n for (var i = this.uncheckedNodes.length - 1; i >= downTo; i--) {\n var node = this.uncheckedNodes[i],\n childKey = node.child.toString()\n\n if (childKey in this.minimizedNodes) {\n node.parent.edges[node.char] = this.minimizedNodes[childKey]\n } else {\n // Cache the key for this node since\n // we know it can't change anymore\n node.child._str = childKey\n\n this.minimizedNodes[childKey] = node.child\n }\n\n this.uncheckedNodes.pop()\n }\n}\n/*!\n * lunr.Index\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * An index contains the built index of all documents and provides a query interface\n * to the index.\n *\n * Usually instances of lunr.Index will not be created using this constructor, instead\n * lunr.Builder should be used to construct new indexes, or lunr.Index.load should be\n * used to load previously built and serialized indexes.\n *\n * @constructor\n * @param {Object} attrs - The attributes of the built search index.\n * @param {Object} attrs.invertedIndex - An index of term/field to document reference.\n * @param {Object} attrs.fieldVectors - Field vectors\n * @param {lunr.TokenSet} attrs.tokenSet - An set of all corpus tokens.\n * @param {string[]} attrs.fields - The names of indexed document fields.\n * @param {lunr.Pipeline} attrs.pipeline - The pipeline to use for search terms.\n */\nlunr.Index = function (attrs) {\n this.invertedIndex = attrs.invertedIndex\n this.fieldVectors = attrs.fieldVectors\n this.tokenSet = attrs.tokenSet\n this.fields = attrs.fields\n this.pipeline = attrs.pipeline\n}\n\n/**\n * A result contains details of a document matching a search query.\n * @typedef {Object} lunr.Index~Result\n * @property {string} ref - The reference of the document this result represents.\n * @property {number} score - A number between 0 and 1 representing how similar this document is to the query.\n * @property {lunr.MatchData} matchData - Contains metadata about this match including which term(s) caused the match.\n */\n\n/**\n * Although lunr provides the ability to create queries using lunr.Query, it also provides a simple\n * query language which itself is parsed into an instance of lunr.Query.\n *\n * For programmatically building queries it is advised to directly use lunr.Query, the query language\n * is best used for human entered text rather than program generated text.\n *\n * At its simplest queries can just be a single term, e.g. `hello`, multiple terms are also supported\n * and will be combined with OR, e.g `hello world` will match documents that contain either 'hello'\n * or 'world', though those that contain both will rank higher in the results.\n *\n * Wildcards can be included in terms to match one or more unspecified characters, these wildcards can\n * be inserted anywhere within the term, and more than one wildcard can exist in a single term. Adding\n * wildcards will increase the number of documents that will be found but can also have a negative\n * impact on query performance, especially with wildcards at the beginning of a term.\n *\n * Terms can be restricted to specific fields, e.g. `title:hello`, only documents with the term\n * hello in the title field will match this query. Using a field not present in the index will lead\n * to an error being thrown.\n *\n * Modifiers can also be added to terms, lunr supports edit distance and boost modifiers on terms. A term\n * boost will make documents matching that term score higher, e.g. `foo^5`. Edit distance is also supported\n * to provide fuzzy matching, e.g. 'hello~2' will match documents with hello with an edit distance of 2.\n * Avoid large values for edit distance to improve query performance.\n *\n * Each term also supports a presence modifier. By default a term's presence in document is optional, however\n * this can be changed to either required or prohibited. For a term's presence to be required in a document the\n * term should be prefixed with a '+', e.g. `+foo bar` is a search for documents that must contain 'foo' and\n * optionally contain 'bar'. Conversely a leading '-' sets the terms presence to prohibited, i.e. it must not\n * appear in a document, e.g. `-foo bar` is a search for documents that do not contain 'foo' but may contain 'bar'.\n *\n * To escape special characters the backslash character '\\' can be used, this allows searches to include\n * characters that would normally be considered modifiers, e.g. `foo\\~2` will search for a term \"foo~2\" instead\n * of attempting to apply a boost of 2 to the search term \"foo\".\n *\n * @typedef {string} lunr.Index~QueryString\n * @example Simple single term query\n * hello\n * @example Multiple term query\n * hello world\n * @example term scoped to a field\n * title:hello\n * @example term with a boost of 10\n * hello^10\n * @example term with an edit distance of 2\n * hello~2\n * @example terms with presence modifiers\n * -foo +bar baz\n */\n\n/**\n * Performs a search against the index using lunr query syntax.\n *\n * Results will be returned sorted by their score, the most relevant results\n * will be returned first. For details on how the score is calculated, please see\n * the {@link https://lunrjs.com/guides/searching.html#scoring|guide}.\n *\n * For more programmatic querying use lunr.Index#query.\n *\n * @param {lunr.Index~QueryString} queryString - A string containing a lunr query.\n * @throws {lunr.QueryParseError} If the passed query string cannot be parsed.\n * @returns {lunr.Index~Result[]}\n */\nlunr.Index.prototype.search = function (queryString) {\n return this.query(function (query) {\n var parser = new lunr.QueryParser(queryString, query)\n parser.parse()\n })\n}\n\n/**\n * A query builder callback provides a query object to be used to express\n * the query to perform on the index.\n *\n * @callback lunr.Index~queryBuilder\n * @param {lunr.Query} query - The query object to build up.\n * @this lunr.Query\n */\n\n/**\n * Performs a query against the index using the yielded lunr.Query object.\n *\n * If performing programmatic queries against the index, this method is preferred\n * over lunr.Index#search so as to avoid the additional query parsing overhead.\n *\n * A query object is yielded to the supplied function which should be used to\n * express the query to be run against the index.\n *\n * Note that although this function takes a callback parameter it is _not_ an\n * asynchronous operation, the callback is just yielded a query object to be\n * customized.\n *\n * @param {lunr.Index~queryBuilder} fn - A function that is used to build the query.\n * @returns {lunr.Index~Result[]}\n */\nlunr.Index.prototype.query = function (fn) {\n // for each query clause\n // * process terms\n // * expand terms from token set\n // * find matching documents and metadata\n // * get document vectors\n // * score documents\n\n var query = new lunr.Query(this.fields),\n matchingFields = Object.create(null),\n queryVectors = Object.create(null),\n termFieldCache = Object.create(null),\n requiredMatches = Object.create(null),\n prohibitedMatches = Object.create(null)\n\n /*\n * To support field level boosts a query vector is created per\n * field. An empty vector is eagerly created to support negated\n * queries.\n */\n for (var i = 0; i < this.fields.length; i++) {\n queryVectors[this.fields[i]] = new lunr.Vector\n }\n\n fn.call(query, query)\n\n for (var i = 0; i < query.clauses.length; i++) {\n /*\n * Unless the pipeline has been disabled for this term, which is\n * the case for terms with wildcards, we need to pass the clause\n * term through the search pipeline. A pipeline returns an array\n * of processed terms. Pipeline functions may expand the passed\n * term, which means we may end up performing multiple index lookups\n * for a single query term.\n */\n var clause = query.clauses[i],\n terms = null,\n clauseMatches = lunr.Set.empty\n\n if (clause.usePipeline) {\n terms = this.pipeline.runString(clause.term, {\n fields: clause.fields\n })\n } else {\n terms = [clause.term]\n }\n\n for (var m = 0; m < terms.length; m++) {\n var term = terms[m]\n\n /*\n * Each term returned from the pipeline needs to use the same query\n * clause object, e.g. the same boost and or edit distance. The\n * simplest way to do this is to re-use the clause object but mutate\n * its term property.\n */\n clause.term = term\n\n /*\n * From the term in the clause we create a token set which will then\n * be used to intersect the indexes token set to get a list of terms\n * to lookup in the inverted index\n */\n var termTokenSet = lunr.TokenSet.fromClause(clause),\n expandedTerms = this.tokenSet.intersect(termTokenSet).toArray()\n\n /*\n * If a term marked as required does not exist in the tokenSet it is\n * impossible for the search to return any matches. We set all the field\n * scoped required matches set to empty and stop examining any further\n * clauses.\n */\n if (expandedTerms.length === 0 && clause.presence === lunr.Query.presence.REQUIRED) {\n for (var k = 0; k < clause.fields.length; k++) {\n var field = clause.fields[k]\n requiredMatches[field] = lunr.Set.empty\n }\n\n break\n }\n\n for (var j = 0; j < expandedTerms.length; j++) {\n /*\n * For each term get the posting and termIndex, this is required for\n * building the query vector.\n */\n var expandedTerm = expandedTerms[j],\n posting = this.invertedIndex[expandedTerm],\n termIndex = posting._index\n\n for (var k = 0; k < clause.fields.length; k++) {\n /*\n * For each field that this query term is scoped by (by default\n * all fields are in scope) we need to get all the document refs\n * that have this term in that field.\n *\n * The posting is the entry in the invertedIndex for the matching\n * term from above.\n */\n var field = clause.fields[k],\n fieldPosting = posting[field],\n matchingDocumentRefs = Object.keys(fieldPosting),\n termField = expandedTerm + \"/\" + field,\n matchingDocumentsSet = new lunr.Set(matchingDocumentRefs)\n\n /*\n * if the presence of this term is required ensure that the matching\n * documents are added to the set of required matches for this clause.\n *\n */\n if (clause.presence == lunr.Query.presence.REQUIRED) {\n clauseMatches = clauseMatches.union(matchingDocumentsSet)\n\n if (requiredMatches[field] === undefined) {\n requiredMatches[field] = lunr.Set.complete\n }\n }\n\n /*\n * if the presence of this term is prohibited ensure that the matching\n * documents are added to the set of prohibited matches for this field,\n * creating that set if it does not yet exist.\n */\n if (clause.presence == lunr.Query.presence.PROHIBITED) {\n if (prohibitedMatches[field] === undefined) {\n prohibitedMatches[field] = lunr.Set.empty\n }\n\n prohibitedMatches[field] = prohibitedMatches[field].union(matchingDocumentsSet)\n\n /*\n * Prohibited matches should not be part of the query vector used for\n * similarity scoring and no metadata should be extracted so we continue\n * to the next field\n */\n continue\n }\n\n /*\n * The query field vector is populated using the termIndex found for\n * the term and a unit value with the appropriate boost applied.\n * Using upsert because there could already be an entry in the vector\n * for the term we are working with. In that case we just add the scores\n * together.\n */\n queryVectors[field].upsert(termIndex, clause.boost, function (a, b) { return a + b })\n\n /**\n * If we've already seen this term, field combo then we've already collected\n * the matching documents and metadata, no need to go through all that again\n */\n if (termFieldCache[termField]) {\n continue\n }\n\n for (var l = 0; l < matchingDocumentRefs.length; l++) {\n /*\n * All metadata for this term/field/document triple\n * are then extracted and collected into an instance\n * of lunr.MatchData ready to be returned in the query\n * results\n */\n var matchingDocumentRef = matchingDocumentRefs[l],\n matchingFieldRef = new lunr.FieldRef (matchingDocumentRef, field),\n metadata = fieldPosting[matchingDocumentRef],\n fieldMatch\n\n if ((fieldMatch = matchingFields[matchingFieldRef]) === undefined) {\n matchingFields[matchingFieldRef] = new lunr.MatchData (expandedTerm, field, metadata)\n } else {\n fieldMatch.add(expandedTerm, field, metadata)\n }\n\n }\n\n termFieldCache[termField] = true\n }\n }\n }\n\n /**\n * If the presence was required we need to update the requiredMatches field sets.\n * We do this after all fields for the term have collected their matches because\n * the clause terms presence is required in _any_ of the fields not _all_ of the\n * fields.\n */\n if (clause.presence === lunr.Query.presence.REQUIRED) {\n for (var k = 0; k < clause.fields.length; k++) {\n var field = clause.fields[k]\n requiredMatches[field] = requiredMatches[field].intersect(clauseMatches)\n }\n }\n }\n\n /**\n * Need to combine the field scoped required and prohibited\n * matching documents into a global set of required and prohibited\n * matches\n */\n var allRequiredMatches = lunr.Set.complete,\n allProhibitedMatches = lunr.Set.empty\n\n for (var i = 0; i < this.fields.length; i++) {\n var field = this.fields[i]\n\n if (requiredMatches[field]) {\n allRequiredMatches = allRequiredMatches.intersect(requiredMatches[field])\n }\n\n if (prohibitedMatches[field]) {\n allProhibitedMatches = allProhibitedMatches.union(prohibitedMatches[field])\n }\n }\n\n var matchingFieldRefs = Object.keys(matchingFields),\n results = [],\n matches = Object.create(null)\n\n /*\n * If the query is negated (contains only prohibited terms)\n * we need to get _all_ fieldRefs currently existing in the\n * index. This is only done when we know that the query is\n * entirely prohibited terms to avoid any cost of getting all\n * fieldRefs unnecessarily.\n *\n * Additionally, blank MatchData must be created to correctly\n * populate the results.\n */\n if (query.isNegated()) {\n matchingFieldRefs = Object.keys(this.fieldVectors)\n\n for (var i = 0; i < matchingFieldRefs.length; i++) {\n var matchingFieldRef = matchingFieldRefs[i]\n var fieldRef = lunr.FieldRef.fromString(matchingFieldRef)\n matchingFields[matchingFieldRef] = new lunr.MatchData\n }\n }\n\n for (var i = 0; i < matchingFieldRefs.length; i++) {\n /*\n * Currently we have document fields that match the query, but we\n * need to return documents. The matchData and scores are combined\n * from multiple fields belonging to the same document.\n *\n * Scores are calculated by field, using the query vectors created\n * above, and combined into a final document score using addition.\n */\n var fieldRef = lunr.FieldRef.fromString(matchingFieldRefs[i]),\n docRef = fieldRef.docRef\n\n if (!allRequiredMatches.contains(docRef)) {\n continue\n }\n\n if (allProhibitedMatches.contains(docRef)) {\n continue\n }\n\n var fieldVector = this.fieldVectors[fieldRef],\n score = queryVectors[fieldRef.fieldName].similarity(fieldVector),\n docMatch\n\n if ((docMatch = matches[docRef]) !== undefined) {\n docMatch.score += score\n docMatch.matchData.combine(matchingFields[fieldRef])\n } else {\n var match = {\n ref: docRef,\n score: score,\n matchData: matchingFields[fieldRef]\n }\n matches[docRef] = match\n results.push(match)\n }\n }\n\n /*\n * Sort the results objects by score, highest first.\n */\n return results.sort(function (a, b) {\n return b.score - a.score\n })\n}\n\n/**\n * Prepares the index for JSON serialization.\n *\n * The schema for this JSON blob will be described in a\n * separate JSON schema file.\n *\n * @returns {Object}\n */\nlunr.Index.prototype.toJSON = function () {\n var invertedIndex = Object.keys(this.invertedIndex)\n .sort()\n .map(function (term) {\n return [term, this.invertedIndex[term]]\n }, this)\n\n var fieldVectors = Object.keys(this.fieldVectors)\n .map(function (ref) {\n return [ref, this.fieldVectors[ref].toJSON()]\n }, this)\n\n return {\n version: lunr.version,\n fields: this.fields,\n fieldVectors: fieldVectors,\n invertedIndex: invertedIndex,\n pipeline: this.pipeline.toJSON()\n }\n}\n\n/**\n * Loads a previously serialized lunr.Index\n *\n * @param {Object} serializedIndex - A previously serialized lunr.Index\n * @returns {lunr.Index}\n */\nlunr.Index.load = function (serializedIndex) {\n var attrs = {},\n fieldVectors = {},\n serializedVectors = serializedIndex.fieldVectors,\n invertedIndex = Object.create(null),\n serializedInvertedIndex = serializedIndex.invertedIndex,\n tokenSetBuilder = new lunr.TokenSet.Builder,\n pipeline = lunr.Pipeline.load(serializedIndex.pipeline)\n\n if (serializedIndex.version != lunr.version) {\n lunr.utils.warn(\"Version mismatch when loading serialised index. Current version of lunr '\" + lunr.version + \"' does not match serialized index '\" + serializedIndex.version + \"'\")\n }\n\n for (var i = 0; i < serializedVectors.length; i++) {\n var tuple = serializedVectors[i],\n ref = tuple[0],\n elements = tuple[1]\n\n fieldVectors[ref] = new lunr.Vector(elements)\n }\n\n for (var i = 0; i < serializedInvertedIndex.length; i++) {\n var tuple = serializedInvertedIndex[i],\n term = tuple[0],\n posting = tuple[1]\n\n tokenSetBuilder.insert(term)\n invertedIndex[term] = posting\n }\n\n tokenSetBuilder.finish()\n\n attrs.fields = serializedIndex.fields\n\n attrs.fieldVectors = fieldVectors\n attrs.invertedIndex = invertedIndex\n attrs.tokenSet = tokenSetBuilder.root\n attrs.pipeline = pipeline\n\n return new lunr.Index(attrs)\n}\n/*!\n * lunr.Builder\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.Builder performs indexing on a set of documents and\n * returns instances of lunr.Index ready for querying.\n *\n * All configuration of the index is done via the builder, the\n * fields to index, the document reference, the text processing\n * pipeline and document scoring parameters are all set on the\n * builder before indexing.\n *\n * @constructor\n * @property {string} _ref - Internal reference to the document reference field.\n * @property {string[]} _fields - Internal reference to the document fields to index.\n * @property {object} invertedIndex - The inverted index maps terms to document fields.\n * @property {object} documentTermFrequencies - Keeps track of document term frequencies.\n * @property {object} documentLengths - Keeps track of the length of documents added to the index.\n * @property {lunr.tokenizer} tokenizer - Function for splitting strings into tokens for indexing.\n * @property {lunr.Pipeline} pipeline - The pipeline performs text processing on tokens before indexing.\n * @property {lunr.Pipeline} searchPipeline - A pipeline for processing search terms before querying the index.\n * @property {number} documentCount - Keeps track of the total number of documents indexed.\n * @property {number} _b - A parameter to control field length normalization, setting this to 0 disabled normalization, 1 fully normalizes field lengths, the default value is 0.75.\n * @property {number} _k1 - A parameter to control how quickly an increase in term frequency results in term frequency saturation, the default value is 1.2.\n * @property {number} termIndex - A counter incremented for each unique term, used to identify a terms position in the vector space.\n * @property {array} metadataWhitelist - A list of metadata keys that have been whitelisted for entry in the index.\n */\nlunr.Builder = function () {\n this._ref = \"id\"\n this._fields = Object.create(null)\n this._documents = Object.create(null)\n this.invertedIndex = Object.create(null)\n this.fieldTermFrequencies = {}\n this.fieldLengths = {}\n this.tokenizer = lunr.tokenizer\n this.pipeline = new lunr.Pipeline\n this.searchPipeline = new lunr.Pipeline\n this.documentCount = 0\n this._b = 0.75\n this._k1 = 1.2\n this.termIndex = 0\n this.metadataWhitelist = []\n}\n\n/**\n * Sets the document field used as the document reference. Every document must have this field.\n * The type of this field in the document should be a string, if it is not a string it will be\n * coerced into a string by calling toString.\n *\n * The default ref is 'id'.\n *\n * The ref should _not_ be changed during indexing, it should be set before any documents are\n * added to the index. Changing it during indexing can lead to inconsistent results.\n *\n * @param {string} ref - The name of the reference field in the document.\n */\nlunr.Builder.prototype.ref = function (ref) {\n this._ref = ref\n}\n\n/**\n * A function that is used to extract a field from a document.\n *\n * Lunr expects a field to be at the top level of a document, if however the field\n * is deeply nested within a document an extractor function can be used to extract\n * the right field for indexing.\n *\n * @callback fieldExtractor\n * @param {object} doc - The document being added to the index.\n * @returns {?(string|object|object[])} obj - The object that will be indexed for this field.\n * @example Extracting a nested field\n * function (doc) { return doc.nested.field }\n */\n\n/**\n * Adds a field to the list of document fields that will be indexed. Every document being\n * indexed should have this field. Null values for this field in indexed documents will\n * not cause errors but will limit the chance of that document being retrieved by searches.\n *\n * All fields should be added before adding documents to the index. Adding fields after\n * a document has been indexed will have no effect on already indexed documents.\n *\n * Fields can be boosted at build time. This allows terms within that field to have more\n * importance when ranking search results. Use a field boost to specify that matches within\n * one field are more important than other fields.\n *\n * @param {string} fieldName - The name of a field to index in all documents.\n * @param {object} attributes - Optional attributes associated with this field.\n * @param {number} [attributes.boost=1] - Boost applied to all terms within this field.\n * @param {fieldExtractor} [attributes.extractor] - Function to extract a field from a document.\n * @throws {RangeError} fieldName cannot contain unsupported characters '/'\n */\nlunr.Builder.prototype.field = function (fieldName, attributes) {\n if (/\\//.test(fieldName)) {\n throw new RangeError (\"Field '\" + fieldName + \"' contains illegal character '/'\")\n }\n\n this._fields[fieldName] = attributes || {}\n}\n\n/**\n * A parameter to tune the amount of field length normalisation that is applied when\n * calculating relevance scores. A value of 0 will completely disable any normalisation\n * and a value of 1 will fully normalise field lengths. The default is 0.75. Values of b\n * will be clamped to the range 0 - 1.\n *\n * @param {number} number - The value to set for this tuning parameter.\n */\nlunr.Builder.prototype.b = function (number) {\n if (number < 0) {\n this._b = 0\n } else if (number > 1) {\n this._b = 1\n } else {\n this._b = number\n }\n}\n\n/**\n * A parameter that controls the speed at which a rise in term frequency results in term\n * frequency saturation. The default value is 1.2. Setting this to a higher value will give\n * slower saturation levels, a lower value will result in quicker saturation.\n *\n * @param {number} number - The value to set for this tuning parameter.\n */\nlunr.Builder.prototype.k1 = function (number) {\n this._k1 = number\n}\n\n/**\n * Adds a document to the index.\n *\n * Before adding fields to the index the index should have been fully setup, with the document\n * ref and all fields to index already having been specified.\n *\n * The document must have a field name as specified by the ref (by default this is 'id') and\n * it should have all fields defined for indexing, though null or undefined values will not\n * cause errors.\n *\n * Entire documents can be boosted at build time. Applying a boost to a document indicates that\n * this document should rank higher in search results than other documents.\n *\n * @param {object} doc - The document to add to the index.\n * @param {object} attributes - Optional attributes associated with this document.\n * @param {number} [attributes.boost=1] - Boost applied to all terms within this document.\n */\nlunr.Builder.prototype.add = function (doc, attributes) {\n var docRef = doc[this._ref],\n fields = Object.keys(this._fields)\n\n this._documents[docRef] = attributes || {}\n this.documentCount += 1\n\n for (var i = 0; i < fields.length; i++) {\n var fieldName = fields[i],\n extractor = this._fields[fieldName].extractor,\n field = extractor ? extractor(doc) : doc[fieldName],\n tokens = this.tokenizer(field, {\n fields: [fieldName]\n }),\n terms = this.pipeline.run(tokens),\n fieldRef = new lunr.FieldRef (docRef, fieldName),\n fieldTerms = Object.create(null)\n\n this.fieldTermFrequencies[fieldRef] = fieldTerms\n this.fieldLengths[fieldRef] = 0\n\n // store the length of this field for this document\n this.fieldLengths[fieldRef] += terms.length\n\n // calculate term frequencies for this field\n for (var j = 0; j < terms.length; j++) {\n var term = terms[j]\n\n if (fieldTerms[term] == undefined) {\n fieldTerms[term] = 0\n }\n\n fieldTerms[term] += 1\n\n // add to inverted index\n // create an initial posting if one doesn't exist\n if (this.invertedIndex[term] == undefined) {\n var posting = Object.create(null)\n posting[\"_index\"] = this.termIndex\n this.termIndex += 1\n\n for (var k = 0; k < fields.length; k++) {\n posting[fields[k]] = Object.create(null)\n }\n\n this.invertedIndex[term] = posting\n }\n\n // add an entry for this term/fieldName/docRef to the invertedIndex\n if (this.invertedIndex[term][fieldName][docRef] == undefined) {\n this.invertedIndex[term][fieldName][docRef] = Object.create(null)\n }\n\n // store all whitelisted metadata about this token in the\n // inverted index\n for (var l = 0; l < this.metadataWhitelist.length; l++) {\n var metadataKey = this.metadataWhitelist[l],\n metadata = term.metadata[metadataKey]\n\n if (this.invertedIndex[term][fieldName][docRef][metadataKey] == undefined) {\n this.invertedIndex[term][fieldName][docRef][metadataKey] = []\n }\n\n this.invertedIndex[term][fieldName][docRef][metadataKey].push(metadata)\n }\n }\n\n }\n}\n\n/**\n * Calculates the average document length for this index\n *\n * @private\n */\nlunr.Builder.prototype.calculateAverageFieldLengths = function () {\n\n var fieldRefs = Object.keys(this.fieldLengths),\n numberOfFields = fieldRefs.length,\n accumulator = {},\n documentsWithField = {}\n\n for (var i = 0; i < numberOfFields; i++) {\n var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]),\n field = fieldRef.fieldName\n\n documentsWithField[field] || (documentsWithField[field] = 0)\n documentsWithField[field] += 1\n\n accumulator[field] || (accumulator[field] = 0)\n accumulator[field] += this.fieldLengths[fieldRef]\n }\n\n var fields = Object.keys(this._fields)\n\n for (var i = 0; i < fields.length; i++) {\n var fieldName = fields[i]\n accumulator[fieldName] = accumulator[fieldName] / documentsWithField[fieldName]\n }\n\n this.averageFieldLength = accumulator\n}\n\n/**\n * Builds a vector space model of every document using lunr.Vector\n *\n * @private\n */\nlunr.Builder.prototype.createFieldVectors = function () {\n var fieldVectors = {},\n fieldRefs = Object.keys(this.fieldTermFrequencies),\n fieldRefsLength = fieldRefs.length,\n termIdfCache = Object.create(null)\n\n for (var i = 0; i < fieldRefsLength; i++) {\n var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]),\n fieldName = fieldRef.fieldName,\n fieldLength = this.fieldLengths[fieldRef],\n fieldVector = new lunr.Vector,\n termFrequencies = this.fieldTermFrequencies[fieldRef],\n terms = Object.keys(termFrequencies),\n termsLength = terms.length\n\n\n var fieldBoost = this._fields[fieldName].boost || 1,\n docBoost = this._documents[fieldRef.docRef].boost || 1\n\n for (var j = 0; j < termsLength; j++) {\n var term = terms[j],\n tf = termFrequencies[term],\n termIndex = this.invertedIndex[term]._index,\n idf, score, scoreWithPrecision\n\n if (termIdfCache[term] === undefined) {\n idf = lunr.idf(this.invertedIndex[term], this.documentCount)\n termIdfCache[term] = idf\n } else {\n idf = termIdfCache[term]\n }\n\n score = idf * ((this._k1 + 1) * tf) / (this._k1 * (1 - this._b + this._b * (fieldLength / this.averageFieldLength[fieldName])) + tf)\n score *= fieldBoost\n score *= docBoost\n scoreWithPrecision = Math.round(score * 1000) / 1000\n // Converts 1.23456789 to 1.234.\n // Reducing the precision so that the vectors take up less\n // space when serialised. Doing it now so that they behave\n // the same before and after serialisation. Also, this is\n // the fastest approach to reducing a number's precision in\n // JavaScript.\n\n fieldVector.insert(termIndex, scoreWithPrecision)\n }\n\n fieldVectors[fieldRef] = fieldVector\n }\n\n this.fieldVectors = fieldVectors\n}\n\n/**\n * Creates a token set of all tokens in the index using lunr.TokenSet\n *\n * @private\n */\nlunr.Builder.prototype.createTokenSet = function () {\n this.tokenSet = lunr.TokenSet.fromArray(\n Object.keys(this.invertedIndex).sort()\n )\n}\n\n/**\n * Builds the index, creating an instance of lunr.Index.\n *\n * This completes the indexing process and should only be called\n * once all documents have been added to the index.\n *\n * @returns {lunr.Index}\n */\nlunr.Builder.prototype.build = function () {\n this.calculateAverageFieldLengths()\n this.createFieldVectors()\n this.createTokenSet()\n\n return new lunr.Index({\n invertedIndex: this.invertedIndex,\n fieldVectors: this.fieldVectors,\n tokenSet: this.tokenSet,\n fields: Object.keys(this._fields),\n pipeline: this.searchPipeline\n })\n}\n\n/**\n * Applies a plugin to the index builder.\n *\n * A plugin is a function that is called with the index builder as its context.\n * Plugins can be used to customise or extend the behaviour of the index\n * in some way. A plugin is just a function, that encapsulated the custom\n * behaviour that should be applied when building the index.\n *\n * The plugin function will be called with the index builder as its argument, additional\n * arguments can also be passed when calling use. The function will be called\n * with the index builder as its context.\n *\n * @param {Function} plugin The plugin to apply.\n */\nlunr.Builder.prototype.use = function (fn) {\n var args = Array.prototype.slice.call(arguments, 1)\n args.unshift(this)\n fn.apply(this, args)\n}\n/**\n * Contains and collects metadata about a matching document.\n * A single instance of lunr.MatchData is returned as part of every\n * lunr.Index~Result.\n *\n * @constructor\n * @param {string} term - The term this match data is associated with\n * @param {string} field - The field in which the term was found\n * @param {object} metadata - The metadata recorded about this term in this field\n * @property {object} metadata - A cloned collection of metadata associated with this document.\n * @see {@link lunr.Index~Result}\n */\nlunr.MatchData = function (term, field, metadata) {\n var clonedMetadata = Object.create(null),\n metadataKeys = Object.keys(metadata || {})\n\n // Cloning the metadata to prevent the original\n // being mutated during match data combination.\n // Metadata is kept in an array within the inverted\n // index so cloning the data can be done with\n // Array#slice\n for (var i = 0; i < metadataKeys.length; i++) {\n var key = metadataKeys[i]\n clonedMetadata[key] = metadata[key].slice()\n }\n\n this.metadata = Object.create(null)\n\n if (term !== undefined) {\n this.metadata[term] = Object.create(null)\n this.metadata[term][field] = clonedMetadata\n }\n}\n\n/**\n * An instance of lunr.MatchData will be created for every term that matches a\n * document. However only one instance is required in a lunr.Index~Result. This\n * method combines metadata from another instance of lunr.MatchData with this\n * objects metadata.\n *\n * @param {lunr.MatchData} otherMatchData - Another instance of match data to merge with this one.\n * @see {@link lunr.Index~Result}\n */\nlunr.MatchData.prototype.combine = function (otherMatchData) {\n var terms = Object.keys(otherMatchData.metadata)\n\n for (var i = 0; i < terms.length; i++) {\n var term = terms[i],\n fields = Object.keys(otherMatchData.metadata[term])\n\n if (this.metadata[term] == undefined) {\n this.metadata[term] = Object.create(null)\n }\n\n for (var j = 0; j < fields.length; j++) {\n var field = fields[j],\n keys = Object.keys(otherMatchData.metadata[term][field])\n\n if (this.metadata[term][field] == undefined) {\n this.metadata[term][field] = Object.create(null)\n }\n\n for (var k = 0; k < keys.length; k++) {\n var key = keys[k]\n\n if (this.metadata[term][field][key] == undefined) {\n this.metadata[term][field][key] = otherMatchData.metadata[term][field][key]\n } else {\n this.metadata[term][field][key] = this.metadata[term][field][key].concat(otherMatchData.metadata[term][field][key])\n }\n\n }\n }\n }\n}\n\n/**\n * Add metadata for a term/field pair to this instance of match data.\n *\n * @param {string} term - The term this match data is associated with\n * @param {string} field - The field in which the term was found\n * @param {object} metadata - The metadata recorded about this term in this field\n */\nlunr.MatchData.prototype.add = function (term, field, metadata) {\n if (!(term in this.metadata)) {\n this.metadata[term] = Object.create(null)\n this.metadata[term][field] = metadata\n return\n }\n\n if (!(field in this.metadata[term])) {\n this.metadata[term][field] = metadata\n return\n }\n\n var metadataKeys = Object.keys(metadata)\n\n for (var i = 0; i < metadataKeys.length; i++) {\n var key = metadataKeys[i]\n\n if (key in this.metadata[term][field]) {\n this.metadata[term][field][key] = this.metadata[term][field][key].concat(metadata[key])\n } else {\n this.metadata[term][field][key] = metadata[key]\n }\n }\n}\n/**\n * A lunr.Query provides a programmatic way of defining queries to be performed\n * against a {@link lunr.Index}.\n *\n * Prefer constructing a lunr.Query using the {@link lunr.Index#query} method\n * so the query object is pre-initialized with the right index fields.\n *\n * @constructor\n * @property {lunr.Query~Clause[]} clauses - An array of query clauses.\n * @property {string[]} allFields - An array of all available fields in a lunr.Index.\n */\nlunr.Query = function (allFields) {\n this.clauses = []\n this.allFields = allFields\n}\n\n/**\n * Constants for indicating what kind of automatic wildcard insertion will be used when constructing a query clause.\n *\n * This allows wildcards to be added to the beginning and end of a term without having to manually do any string\n * concatenation.\n *\n * The wildcard constants can be bitwise combined to select both leading and trailing wildcards.\n *\n * @constant\n * @default\n * @property {number} wildcard.NONE - The term will have no wildcards inserted, this is the default behaviour\n * @property {number} wildcard.LEADING - Prepend the term with a wildcard, unless a leading wildcard already exists\n * @property {number} wildcard.TRAILING - Append a wildcard to the term, unless a trailing wildcard already exists\n * @see lunr.Query~Clause\n * @see lunr.Query#clause\n * @see lunr.Query#term\n * @example query term with trailing wildcard\n * query.term('foo', { wildcard: lunr.Query.wildcard.TRAILING })\n * @example query term with leading and trailing wildcard\n * query.term('foo', {\n * wildcard: lunr.Query.wildcard.LEADING | lunr.Query.wildcard.TRAILING\n * })\n */\n\nlunr.Query.wildcard = new String (\"*\")\nlunr.Query.wildcard.NONE = 0\nlunr.Query.wildcard.LEADING = 1\nlunr.Query.wildcard.TRAILING = 2\n\n/**\n * Constants for indicating what kind of presence a term must have in matching documents.\n *\n * @constant\n * @enum {number}\n * @see lunr.Query~Clause\n * @see lunr.Query#clause\n * @see lunr.Query#term\n * @example query term with required presence\n * query.term('foo', { presence: lunr.Query.presence.REQUIRED })\n */\nlunr.Query.presence = {\n /**\n * Term's presence in a document is optional, this is the default value.\n */\n OPTIONAL: 1,\n\n /**\n * Term's presence in a document is required, documents that do not contain\n * this term will not be returned.\n */\n REQUIRED: 2,\n\n /**\n * Term's presence in a document is prohibited, documents that do contain\n * this term will not be returned.\n */\n PROHIBITED: 3\n}\n\n/**\n * A single clause in a {@link lunr.Query} contains a term and details on how to\n * match that term against a {@link lunr.Index}.\n *\n * @typedef {Object} lunr.Query~Clause\n * @property {string[]} fields - The fields in an index this clause should be matched against.\n * @property {number} [boost=1] - Any boost that should be applied when matching this clause.\n * @property {number} [editDistance] - Whether the term should have fuzzy matching applied, and how fuzzy the match should be.\n * @property {boolean} [usePipeline] - Whether the term should be passed through the search pipeline.\n * @property {number} [wildcard=lunr.Query.wildcard.NONE] - Whether the term should have wildcards appended or prepended.\n * @property {number} [presence=lunr.Query.presence.OPTIONAL] - The terms presence in any matching documents.\n */\n\n/**\n * Adds a {@link lunr.Query~Clause} to this query.\n *\n * Unless the clause contains the fields to be matched all fields will be matched. In addition\n * a default boost of 1 is applied to the clause.\n *\n * @param {lunr.Query~Clause} clause - The clause to add to this query.\n * @see lunr.Query~Clause\n * @returns {lunr.Query}\n */\nlunr.Query.prototype.clause = function (clause) {\n if (!('fields' in clause)) {\n clause.fields = this.allFields\n }\n\n if (!('boost' in clause)) {\n clause.boost = 1\n }\n\n if (!('usePipeline' in clause)) {\n clause.usePipeline = true\n }\n\n if (!('wildcard' in clause)) {\n clause.wildcard = lunr.Query.wildcard.NONE\n }\n\n if ((clause.wildcard & lunr.Query.wildcard.LEADING) && (clause.term.charAt(0) != lunr.Query.wildcard)) {\n clause.term = \"*\" + clause.term\n }\n\n if ((clause.wildcard & lunr.Query.wildcard.TRAILING) && (clause.term.slice(-1) != lunr.Query.wildcard)) {\n clause.term = \"\" + clause.term + \"*\"\n }\n\n if (!('presence' in clause)) {\n clause.presence = lunr.Query.presence.OPTIONAL\n }\n\n this.clauses.push(clause)\n\n return this\n}\n\n/**\n * A negated query is one in which every clause has a presence of\n * prohibited. These queries require some special processing to return\n * the expected results.\n *\n * @returns boolean\n */\nlunr.Query.prototype.isNegated = function () {\n for (var i = 0; i < this.clauses.length; i++) {\n if (this.clauses[i].presence != lunr.Query.presence.PROHIBITED) {\n return false\n }\n }\n\n return true\n}\n\n/**\n * Adds a term to the current query, under the covers this will create a {@link lunr.Query~Clause}\n * to the list of clauses that make up this query.\n *\n * The term is used as is, i.e. no tokenization will be performed by this method. Instead conversion\n * to a token or token-like string should be done before calling this method.\n *\n * The term will be converted to a string by calling `toString`. Multiple terms can be passed as an\n * array, each term in the array will share the same options.\n *\n * @param {object|object[]} term - The term(s) to add to the query.\n * @param {object} [options] - Any additional properties to add to the query clause.\n * @returns {lunr.Query}\n * @see lunr.Query#clause\n * @see lunr.Query~Clause\n * @example adding a single term to a query\n * query.term(\"foo\")\n * @example adding a single term to a query and specifying search fields, term boost and automatic trailing wildcard\n * query.term(\"foo\", {\n * fields: [\"title\"],\n * boost: 10,\n * wildcard: lunr.Query.wildcard.TRAILING\n * })\n * @example using lunr.tokenizer to convert a string to tokens before using them as terms\n * query.term(lunr.tokenizer(\"foo bar\"))\n */\nlunr.Query.prototype.term = function (term, options) {\n if (Array.isArray(term)) {\n term.forEach(function (t) { this.term(t, lunr.utils.clone(options)) }, this)\n return this\n }\n\n var clause = options || {}\n clause.term = term.toString()\n\n this.clause(clause)\n\n return this\n}\nlunr.QueryParseError = function (message, start, end) {\n this.name = \"QueryParseError\"\n this.message = message\n this.start = start\n this.end = end\n}\n\nlunr.QueryParseError.prototype = new Error\nlunr.QueryLexer = function (str) {\n this.lexemes = []\n this.str = str\n this.length = str.length\n this.pos = 0\n this.start = 0\n this.escapeCharPositions = []\n}\n\nlunr.QueryLexer.prototype.run = function () {\n var state = lunr.QueryLexer.lexText\n\n while (state) {\n state = state(this)\n }\n}\n\nlunr.QueryLexer.prototype.sliceString = function () {\n var subSlices = [],\n sliceStart = this.start,\n sliceEnd = this.pos\n\n for (var i = 0; i < this.escapeCharPositions.length; i++) {\n sliceEnd = this.escapeCharPositions[i]\n subSlices.push(this.str.slice(sliceStart, sliceEnd))\n sliceStart = sliceEnd + 1\n }\n\n subSlices.push(this.str.slice(sliceStart, this.pos))\n this.escapeCharPositions.length = 0\n\n return subSlices.join('')\n}\n\nlunr.QueryLexer.prototype.emit = function (type) {\n this.lexemes.push({\n type: type,\n str: this.sliceString(),\n start: this.start,\n end: this.pos\n })\n\n this.start = this.pos\n}\n\nlunr.QueryLexer.prototype.escapeCharacter = function () {\n this.escapeCharPositions.push(this.pos - 1)\n this.pos += 1\n}\n\nlunr.QueryLexer.prototype.next = function () {\n if (this.pos >= this.length) {\n return lunr.QueryLexer.EOS\n }\n\n var char = this.str.charAt(this.pos)\n this.pos += 1\n return char\n}\n\nlunr.QueryLexer.prototype.width = function () {\n return this.pos - this.start\n}\n\nlunr.QueryLexer.prototype.ignore = function () {\n if (this.start == this.pos) {\n this.pos += 1\n }\n\n this.start = this.pos\n}\n\nlunr.QueryLexer.prototype.backup = function () {\n this.pos -= 1\n}\n\nlunr.QueryLexer.prototype.acceptDigitRun = function () {\n var char, charCode\n\n do {\n char = this.next()\n charCode = char.charCodeAt(0)\n } while (charCode > 47 && charCode < 58)\n\n if (char != lunr.QueryLexer.EOS) {\n this.backup()\n }\n}\n\nlunr.QueryLexer.prototype.more = function () {\n return this.pos < this.length\n}\n\nlunr.QueryLexer.EOS = 'EOS'\nlunr.QueryLexer.FIELD = 'FIELD'\nlunr.QueryLexer.TERM = 'TERM'\nlunr.QueryLexer.EDIT_DISTANCE = 'EDIT_DISTANCE'\nlunr.QueryLexer.BOOST = 'BOOST'\nlunr.QueryLexer.PRESENCE = 'PRESENCE'\n\nlunr.QueryLexer.lexField = function (lexer) {\n lexer.backup()\n lexer.emit(lunr.QueryLexer.FIELD)\n lexer.ignore()\n return lunr.QueryLexer.lexText\n}\n\nlunr.QueryLexer.lexTerm = function (lexer) {\n if (lexer.width() > 1) {\n lexer.backup()\n lexer.emit(lunr.QueryLexer.TERM)\n }\n\n lexer.ignore()\n\n if (lexer.more()) {\n return lunr.QueryLexer.lexText\n }\n}\n\nlunr.QueryLexer.lexEditDistance = function (lexer) {\n lexer.ignore()\n lexer.acceptDigitRun()\n lexer.emit(lunr.QueryLexer.EDIT_DISTANCE)\n return lunr.QueryLexer.lexText\n}\n\nlunr.QueryLexer.lexBoost = function (lexer) {\n lexer.ignore()\n lexer.acceptDigitRun()\n lexer.emit(lunr.QueryLexer.BOOST)\n return lunr.QueryLexer.lexText\n}\n\nlunr.QueryLexer.lexEOS = function (lexer) {\n if (lexer.width() > 0) {\n lexer.emit(lunr.QueryLexer.TERM)\n }\n}\n\n// This matches the separator used when tokenising fields\n// within a document. These should match otherwise it is\n// not possible to search for some tokens within a document.\n//\n// It is possible for the user to change the separator on the\n// tokenizer so it _might_ clash with any other of the special\n// characters already used within the search string, e.g. :.\n//\n// This means that it is possible to change the separator in\n// such a way that makes some words unsearchable using a search\n// string.\nlunr.QueryLexer.termSeparator = lunr.tokenizer.separator\n\nlunr.QueryLexer.lexText = function (lexer) {\n while (true) {\n var char = lexer.next()\n\n if (char == lunr.QueryLexer.EOS) {\n return lunr.QueryLexer.lexEOS\n }\n\n // Escape character is '\\'\n if (char.charCodeAt(0) == 92) {\n lexer.escapeCharacter()\n continue\n }\n\n if (char == \":\") {\n return lunr.QueryLexer.lexField\n }\n\n if (char == \"~\") {\n lexer.backup()\n if (lexer.width() > 0) {\n lexer.emit(lunr.QueryLexer.TERM)\n }\n return lunr.QueryLexer.lexEditDistance\n }\n\n if (char == \"^\") {\n lexer.backup()\n if (lexer.width() > 0) {\n lexer.emit(lunr.QueryLexer.TERM)\n }\n return lunr.QueryLexer.lexBoost\n }\n\n // \"+\" indicates term presence is required\n // checking for length to ensure that only\n // leading \"+\" are considered\n if (char == \"+\" && lexer.width() === 1) {\n lexer.emit(lunr.QueryLexer.PRESENCE)\n return lunr.QueryLexer.lexText\n }\n\n // \"-\" indicates term presence is prohibited\n // checking for length to ensure that only\n // leading \"-\" are considered\n if (char == \"-\" && lexer.width() === 1) {\n lexer.emit(lunr.QueryLexer.PRESENCE)\n return lunr.QueryLexer.lexText\n }\n\n if (char.match(lunr.QueryLexer.termSeparator)) {\n return lunr.QueryLexer.lexTerm\n }\n }\n}\n\nlunr.QueryParser = function (str, query) {\n this.lexer = new lunr.QueryLexer (str)\n this.query = query\n this.currentClause = {}\n this.lexemeIdx = 0\n}\n\nlunr.QueryParser.prototype.parse = function () {\n this.lexer.run()\n this.lexemes = this.lexer.lexemes\n\n var state = lunr.QueryParser.parseClause\n\n while (state) {\n state = state(this)\n }\n\n return this.query\n}\n\nlunr.QueryParser.prototype.peekLexeme = function () {\n return this.lexemes[this.lexemeIdx]\n}\n\nlunr.QueryParser.prototype.consumeLexeme = function () {\n var lexeme = this.peekLexeme()\n this.lexemeIdx += 1\n return lexeme\n}\n\nlunr.QueryParser.prototype.nextClause = function () {\n var completedClause = this.currentClause\n this.query.clause(completedClause)\n this.currentClause = {}\n}\n\nlunr.QueryParser.parseClause = function (parser) {\n var lexeme = parser.peekLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n switch (lexeme.type) {\n case lunr.QueryLexer.PRESENCE:\n return lunr.QueryParser.parsePresence\n case lunr.QueryLexer.FIELD:\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.TERM:\n return lunr.QueryParser.parseTerm\n default:\n var errorMessage = \"expected either a field or a term, found \" + lexeme.type\n\n if (lexeme.str.length >= 1) {\n errorMessage += \" with value '\" + lexeme.str + \"'\"\n }\n\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n}\n\nlunr.QueryParser.parsePresence = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n switch (lexeme.str) {\n case \"-\":\n parser.currentClause.presence = lunr.Query.presence.PROHIBITED\n break\n case \"+\":\n parser.currentClause.presence = lunr.Query.presence.REQUIRED\n break\n default:\n var errorMessage = \"unrecognised presence operator'\" + lexeme.str + \"'\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n var errorMessage = \"expecting term or field, found nothing\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.FIELD:\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.TERM:\n return lunr.QueryParser.parseTerm\n default:\n var errorMessage = \"expecting term or field, found '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseField = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n if (parser.query.allFields.indexOf(lexeme.str) == -1) {\n var possibleFields = parser.query.allFields.map(function (f) { return \"'\" + f + \"'\" }).join(', '),\n errorMessage = \"unrecognised field '\" + lexeme.str + \"', possible fields: \" + possibleFields\n\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n parser.currentClause.fields = [lexeme.str]\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n var errorMessage = \"expecting term, found nothing\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n return lunr.QueryParser.parseTerm\n default:\n var errorMessage = \"expecting term, found '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseTerm = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n parser.currentClause.term = lexeme.str.toLowerCase()\n\n if (lexeme.str.indexOf(\"*\") != -1) {\n parser.currentClause.usePipeline = false\n }\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n parser.nextClause()\n return\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n parser.nextClause()\n return lunr.QueryParser.parseTerm\n case lunr.QueryLexer.FIELD:\n parser.nextClause()\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.EDIT_DISTANCE:\n return lunr.QueryParser.parseEditDistance\n case lunr.QueryLexer.BOOST:\n return lunr.QueryParser.parseBoost\n case lunr.QueryLexer.PRESENCE:\n parser.nextClause()\n return lunr.QueryParser.parsePresence\n default:\n var errorMessage = \"Unexpected lexeme type '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseEditDistance = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n var editDistance = parseInt(lexeme.str, 10)\n\n if (isNaN(editDistance)) {\n var errorMessage = \"edit distance must be numeric\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n parser.currentClause.editDistance = editDistance\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n parser.nextClause()\n return\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n parser.nextClause()\n return lunr.QueryParser.parseTerm\n case lunr.QueryLexer.FIELD:\n parser.nextClause()\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.EDIT_DISTANCE:\n return lunr.QueryParser.parseEditDistance\n case lunr.QueryLexer.BOOST:\n return lunr.QueryParser.parseBoost\n case lunr.QueryLexer.PRESENCE:\n parser.nextClause()\n return lunr.QueryParser.parsePresence\n default:\n var errorMessage = \"Unexpected lexeme type '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseBoost = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n var boost = parseInt(lexeme.str, 10)\n\n if (isNaN(boost)) {\n var errorMessage = \"boost must be numeric\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n parser.currentClause.boost = boost\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n parser.nextClause()\n return\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n parser.nextClause()\n return lunr.QueryParser.parseTerm\n case lunr.QueryLexer.FIELD:\n parser.nextClause()\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.EDIT_DISTANCE:\n return lunr.QueryParser.parseEditDistance\n case lunr.QueryLexer.BOOST:\n return lunr.QueryParser.parseBoost\n case lunr.QueryLexer.PRESENCE:\n parser.nextClause()\n return lunr.QueryParser.parsePresence\n default:\n var errorMessage = \"Unexpected lexeme type '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\n /**\n * export the module via AMD, CommonJS or as a browser global\n * Export code from https://github.com/umdjs/umd/blob/master/returnExports.js\n */\n ;(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define(factory)\n } else if (typeof exports === 'object') {\n /**\n * Node. Does not work with strict CommonJS, but\n * only CommonJS-like enviroments that support module.exports,\n * like Node.\n */\n module.exports = factory()\n } else {\n // Browser globals (root is window)\n root.lunr = factory()\n }\n }(this, function () {\n /**\n * Just return a value to define the module export.\n * This example returns an object, but the module\n * can return a function as the exported value.\n */\n return lunr\n }))\n})();\n", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport lunr from \"lunr\"\n\nimport \"~/polyfills\"\n\nimport { Search, SearchIndexConfig } from \"../../_\"\nimport {\n SearchMessage,\n SearchMessageType\n} from \"../message\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Add support for usage with `iframe-worker` polyfill\n *\n * While `importScripts` is synchronous when executed inside of a web worker,\n * it's not possible to provide a synchronous polyfilled implementation. The\n * cool thing is that awaiting a non-Promise is a noop, so extending the type\n * definition to return a `Promise` shouldn't break anything.\n *\n * @see https://bit.ly/2PjDnXi - GitHub comment\n */\ndeclare global {\n function importScripts(...urls: string[]): Promise | void\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Search index\n */\nlet index: Search\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch (= import) multi-language support through `lunr-languages`\n *\n * This function automatically imports the stemmers necessary to process the\n * languages, which are defined through the search index configuration.\n *\n * If the worker runs inside of an `iframe` (when using `iframe-worker` as\n * a shim), the base URL for the stemmers to be loaded must be determined by\n * searching for the first `script` element with a `src` attribute, which will\n * contain the contents of this script.\n *\n * @param config - Search index configuration\n *\n * @returns Promise resolving with no result\n */\nasync function setupSearchLanguages(\n config: SearchIndexConfig\n): Promise {\n let base = \"../lunr\"\n\n /* Detect `iframe-worker` and fix base URL */\n if (typeof parent !== \"undefined\" && \"IFrameWorker\" in parent) {\n const worker = document.querySelector(\"script[src]\")!\n const [path] = worker.src.split(\"/worker\")\n\n /* Prefix base with path */\n base = base.replace(\"..\", path)\n }\n\n /* Add scripts for languages */\n const scripts = []\n for (const lang of config.lang) {\n switch (lang) {\n\n /* Add segmenter for Japanese */\n case \"ja\":\n scripts.push(`${base}/tinyseg.js`)\n break\n\n /* Add segmenter for Hindi and Thai */\n case \"hi\":\n case \"th\":\n scripts.push(`${base}/wordcut.js`)\n break\n }\n\n /* Add language support */\n if (lang !== \"en\")\n scripts.push(`${base}/min/lunr.${lang}.min.js`)\n }\n\n /* Add multi-language support */\n if (config.lang.length > 1)\n scripts.push(`${base}/min/lunr.multi.min.js`)\n\n /* Load scripts synchronously */\n if (scripts.length)\n await importScripts(\n `${base}/min/lunr.stemmer.support.min.js`,\n ...scripts\n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Message handler\n *\n * @param message - Source message\n *\n * @returns Target message\n */\nexport async function handler(\n message: SearchMessage\n): Promise {\n switch (message.type) {\n\n /* Search setup message */\n case SearchMessageType.SETUP:\n await setupSearchLanguages(message.data.config)\n index = new Search(message.data)\n return {\n type: SearchMessageType.READY\n }\n\n /* Search query message */\n case SearchMessageType.QUERY:\n return {\n type: SearchMessageType.RESULT,\n data: index ? index.search(message.data) : { items: [] }\n }\n\n /* All other messages */\n default:\n throw new TypeError(\"Invalid message type\")\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Worker\n * ------------------------------------------------------------------------- */\n\n/* @ts-expect-error - expose Lunr.js in global scope, or stemmers won't work */\nself.lunr = lunr\n\n/* Handle messages */\naddEventListener(\"message\", async ev => {\n postMessage(await handler(ev.data))\n})\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Polyfills\n * ------------------------------------------------------------------------- */\n\n/* Polyfill `Object.entries` */\nif (!Object.entries)\n Object.entries = function (obj: object) {\n const data: [string, string][] = []\n for (const key of Object.keys(obj))\n // @ts-expect-error - ignore property access warning\n data.push([key, obj[key]])\n\n /* Return entries */\n return data\n }\n\n/* Polyfill `Object.values` */\nif (!Object.values)\n Object.values = function (obj: object) {\n const data: string[] = []\n for (const key of Object.keys(obj))\n // @ts-expect-error - ignore property access warning\n data.push(obj[key])\n\n /* Return values */\n return data\n }\n\n/* ------------------------------------------------------------------------- */\n\n/* Polyfills for `Element` */\nif (typeof Element !== \"undefined\") {\n\n /* Polyfill `Element.scrollTo` */\n if (!Element.prototype.scrollTo)\n Element.prototype.scrollTo = function (\n x?: ScrollToOptions | number, y?: number\n ): void {\n if (typeof x === \"object\") {\n this.scrollLeft = x.left!\n this.scrollTop = x.top!\n } else {\n this.scrollLeft = x!\n this.scrollTop = y!\n }\n }\n\n /* Polyfill `Element.replaceWith` */\n if (!Element.prototype.replaceWith)\n Element.prototype.replaceWith = function (\n ...nodes: Array\n ): void {\n const parent = this.parentNode\n if (parent) {\n if (nodes.length === 0)\n parent.removeChild(this)\n\n /* Replace children and create text nodes */\n for (let i = nodes.length - 1; i >= 0; i--) {\n let node = nodes[i]\n if (typeof node !== \"object\")\n node = document.createTextNode(node)\n else if (node.parentNode)\n node.parentNode.removeChild(node)\n\n /* Replace child or insert before previous sibling */\n if (!i)\n parent.replaceChild(node, this)\n else\n parent.insertBefore(this.previousSibling!, node)\n }\n }\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexDocument } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search document\n */\nexport interface SearchDocument extends SearchIndexDocument {\n parent?: SearchIndexDocument /* Parent article */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search document mapping\n */\nexport type SearchDocumentMap = Map\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search document mapping\n *\n * @param docs - Search index documents\n *\n * @returns Search document map\n */\nexport function setupSearchDocumentMap(\n docs: SearchIndexDocument[]\n): SearchDocumentMap {\n const documents = new Map()\n const parents = new Set()\n for (const doc of docs) {\n const [path, hash] = doc.location.split(\"#\")\n\n /* Extract location, title and tags */\n const location = doc.location\n const title = doc.title\n const tags = doc.tags\n\n /* Escape and cleanup text */\n const text = escapeHTML(doc.text)\n .replace(/\\s+(?=[,.:;!?])/g, \"\")\n .replace(/\\s+/g, \" \")\n\n /* Handle section */\n if (hash) {\n const parent = documents.get(path)!\n\n /* Ignore first section, override article */\n if (!parents.has(parent)) {\n parent.title = doc.title\n parent.text = text\n\n /* Remember that we processed the article */\n parents.add(parent)\n\n /* Add subsequent section */\n } else {\n documents.set(location, {\n location,\n title,\n text,\n parent\n })\n }\n\n /* Add article */\n } else {\n documents.set(location, {\n location,\n title,\n text,\n ...tags && { tags }\n })\n }\n }\n return documents\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexConfig } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search highlight function\n *\n * @param value - Value\n *\n * @returns Highlighted value\n */\nexport type SearchHighlightFn = (value: string) => string\n\n/**\n * Search highlight factory function\n *\n * @param query - Query value\n *\n * @returns Search highlight function\n */\nexport type SearchHighlightFactoryFn = (query: string) => SearchHighlightFn\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search highlighter\n *\n * @param config - Search index configuration\n * @param escape - Whether to escape HTML\n *\n * @returns Search highlight factory function\n */\nexport function setupSearchHighlighter(\n config: SearchIndexConfig, escape: boolean\n): SearchHighlightFactoryFn {\n const separator = new RegExp(config.separator, \"img\")\n const highlight = (_: unknown, data: string, term: string) => {\n return `${data}${term}`\n }\n\n /* Return factory function */\n return (query: string) => {\n query = query\n .replace(/[\\s*+\\-:~^]+/g, \" \")\n .trim()\n\n /* Create search term match expression */\n const match = new RegExp(`(^|${config.separator})(${\n query\n .replace(/[|\\\\{}()[\\]^$+*?.-]/g, \"\\\\$&\")\n .replace(separator, \"|\")\n })`, \"img\")\n\n /* Highlight string value */\n return value => (\n escape\n ? escapeHTML(value)\n : value\n )\n .replace(match, highlight)\n .replace(/<\\/mark>(\\s+)]*>/img, \"$1\")\n }\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search query clause\n */\nexport interface SearchQueryClause {\n presence: lunr.Query.presence /* Clause presence */\n term: string /* Clause term */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search query terms\n */\nexport type SearchQueryTerms = Record\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Parse a search query for analysis\n *\n * @param value - Query value\n *\n * @returns Search query clauses\n */\nexport function parseSearchQuery(\n value: string\n): SearchQueryClause[] {\n const query = new (lunr as any).Query([\"title\", \"text\"])\n const parser = new (lunr as any).QueryParser(value, query)\n\n /* Parse and return query clauses */\n parser.parse()\n return query.clauses\n}\n\n/**\n * Analyze the search query clauses in regard to the search terms found\n *\n * @param query - Search query clauses\n * @param terms - Search terms\n *\n * @returns Search query terms\n */\nexport function getSearchQueryTerms(\n query: SearchQueryClause[], terms: string[]\n): SearchQueryTerms {\n const clauses = new Set(query)\n\n /* Match query clauses against terms */\n const result: SearchQueryTerms = {}\n for (let t = 0; t < terms.length; t++)\n for (const clause of clauses)\n if (terms[t].startsWith(clause.term)) {\n result[clause.term] = true\n clauses.delete(clause)\n }\n\n /* Annotate unmatched non-stopword query clauses */\n for (const clause of clauses)\n if (lunr.stopWordFilter?.(clause.term as any))\n result[clause.term] = false\n\n /* Return query terms */\n return result\n}\n", "/*\n * Copyright (c) 2016-2022 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n SearchDocument,\n SearchDocumentMap,\n setupSearchDocumentMap\n} from \"../document\"\nimport {\n SearchHighlightFactoryFn,\n setupSearchHighlighter\n} from \"../highlighter\"\nimport { SearchOptions } from \"../options\"\nimport {\n SearchQueryTerms,\n getSearchQueryTerms,\n parseSearchQuery\n} from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search index configuration\n */\nexport interface SearchIndexConfig {\n lang: string[] /* Search languages */\n separator: string /* Search separator */\n}\n\n/**\n * Search index document\n */\nexport interface SearchIndexDocument {\n location: string /* Document location */\n title: string /* Document title */\n text: string /* Document text */\n tags?: string[] /* Document tags */\n boost?: number /* Document boost */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search index\n *\n * This interfaces describes the format of the `search_index.json` file which\n * is automatically built by the MkDocs search plugin.\n */\nexport interface SearchIndex {\n config: SearchIndexConfig /* Search index configuration */\n docs: SearchIndexDocument[] /* Search index documents */\n options: SearchOptions /* Search options */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search metadata\n */\nexport interface SearchMetadata {\n score: number /* Score (relevance) */\n terms: SearchQueryTerms /* Search query terms */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search result document\n */\nexport type SearchResultDocument = SearchDocument & SearchMetadata\n\n/**\n * Search result item\n */\nexport type SearchResultItem = SearchResultDocument[]\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search result\n */\nexport interface SearchResult {\n items: SearchResultItem[] /* Search result items */\n suggestions?: string[] /* Search suggestions */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Compute the difference of two lists of strings\n *\n * @param a - 1st list of strings\n * @param b - 2nd list of strings\n *\n * @returns Difference\n */\nfunction difference(a: string[], b: string[]): string[] {\n const [x, y] = [new Set(a), new Set(b)]\n return [\n ...new Set([...x].filter(value => !y.has(value)))\n ]\n}\n\n/* ----------------------------------------------------------------------------\n * Class\n * ------------------------------------------------------------------------- */\n\n/**\n * Search index\n */\nexport class Search {\n\n /**\n * Search document mapping\n *\n * A mapping of URLs (including hash fragments) to the actual articles and\n * sections of the documentation. The search document mapping must be created\n * regardless of whether the index was prebuilt or not, as Lunr.js itself\n * only stores the actual index.\n */\n protected documents: SearchDocumentMap\n\n /**\n * Search highlight factory function\n */\n protected highlight: SearchHighlightFactoryFn\n\n /**\n * The underlying Lunr.js search index\n */\n protected index: lunr.Index\n\n /**\n * Search options\n */\n protected options: SearchOptions\n\n /**\n * Create the search integration\n *\n * @param data - Search index\n */\n public constructor({ config, docs, options }: SearchIndex) {\n this.options = options\n\n /* Set up document map and highlighter factory */\n this.documents = setupSearchDocumentMap(docs)\n this.highlight = setupSearchHighlighter(config, false)\n\n /* Set separator for tokenizer */\n lunr.tokenizer.separator = new RegExp(config.separator)\n\n /* Create search index */\n this.index = lunr(function () {\n\n /* Set up multi-language support */\n if (config.lang.length === 1 && config.lang[0] !== \"en\") {\n this.use((lunr as any)[config.lang[0]])\n } else if (config.lang.length > 1) {\n this.use((lunr as any).multiLanguage(...config.lang))\n }\n\n /* Compute functions to be removed from the pipeline */\n const fns = difference([\n \"trimmer\", \"stopWordFilter\", \"stemmer\"\n ], options.pipeline)\n\n /* Remove functions from the pipeline for registered languages */\n for (const lang of config.lang.map(language => (\n language === \"en\" ? lunr : (lunr as any)[language]\n ))) {\n for (const fn of fns) {\n this.pipeline.remove(lang[fn])\n this.searchPipeline.remove(lang[fn])\n }\n }\n\n /* Set up reference */\n this.ref(\"location\")\n\n /* Set up fields */\n this.field(\"title\", { boost: 1e3 })\n this.field(\"text\")\n this.field(\"tags\", { boost: 1e6, extractor: doc => {\n const { tags = [] } = doc as SearchDocument\n return tags.reduce((list, tag) => [\n ...list,\n ...lunr.tokenizer(tag)\n ], [] as lunr.Token[])\n } })\n\n /* Index documents */\n for (const doc of docs)\n this.add(doc, { boost: doc.boost })\n })\n }\n\n /**\n * Search for matching documents\n *\n * The search index which MkDocs provides is divided up into articles, which\n * contain the whole content of the individual pages, and sections, which only\n * contain the contents of the subsections obtained by breaking the individual\n * pages up at `h1` ... `h6`. As there may be many sections on different pages\n * with identical titles (for example within this very project, e.g. \"Usage\"\n * or \"Installation\"), they need to be put into the context of the containing\n * page. For this reason, section results are grouped within their respective\n * articles which are the top-level results that are returned.\n *\n * @param query - Query value\n *\n * @returns Search results\n */\n public search(query: string): SearchResult {\n if (query) {\n try {\n const highlight = this.highlight(query)\n\n /* Parse query to extract clauses for analysis */\n const clauses = parseSearchQuery(query)\n .filter(clause => (\n clause.presence !== lunr.Query.presence.PROHIBITED\n ))\n\n /* Perform search and post-process results */\n const groups = this.index.search(`${query}*`)\n\n /* Apply post-query boosts based on title and search query terms */\n .reduce((item, { ref, score, matchData }) => {\n const document = this.documents.get(ref)\n if (typeof document !== \"undefined\") {\n const { location, title, text, tags, parent } = document\n\n /* Compute and analyze search query terms */\n const terms = getSearchQueryTerms(\n clauses,\n Object.keys(matchData.metadata)\n )\n\n /* Highlight title and text and apply post-query boosts */\n const boost = +!parent + +Object.values(terms).every(t => t)\n item.push({\n location,\n title: highlight(title),\n text: highlight(text),\n ...tags && { tags: tags.map(highlight) },\n score: score * (1 + boost),\n terms\n })\n }\n return item\n }, [])\n\n /* Sort search results again after applying boosts */\n .sort((a, b) => b.score - a.score)\n\n /* Group search results by page */\n .reduce((items, result) => {\n const document = this.documents.get(result.location)\n if (typeof document !== \"undefined\") {\n const ref = \"parent\" in document\n ? document.parent!.location\n : document.location\n items.set(ref, [...items.get(ref) || [], result])\n }\n return items\n }, new Map())\n\n /* Generate search suggestions, if desired */\n let suggestions: string[] | undefined\n if (this.options.suggestions) {\n const titles = this.index.query(builder => {\n for (const clause of clauses)\n builder.term(clause.term, {\n fields: [\"title\"],\n presence: lunr.Query.presence.REQUIRED,\n wildcard: lunr.Query.wildcard.TRAILING\n })\n })\n\n /* Retrieve suggestions for best match */\n suggestions = titles.length\n ? Object.keys(titles[0].matchData.metadata)\n : []\n }\n\n /* Return items and suggestions */\n return {\n items: [...groups.values()],\n ...typeof suggestions !== \"undefined\" && { suggestions }\n }\n\n /* Log errors to console (for now) */\n } catch {\n console.warn(`Invalid query: ${query} \u2013 see https://bit.ly/2s3ChXG`)\n }\n }\n\n /* Return nothing in case of error or empty query */\n return { items: [] }\n }\n}\n"], - "mappings": "glCAAA,IAAAA,GAAAC,EAAA,CAAAC,GAAAC,KAAA;AAAA;AAAA;AAAA;AAAA,IAME,UAAU,CAiCZ,IAAIC,EAAO,SAAUC,EAAQ,CAC3B,IAAIC,EAAU,IAAIF,EAAK,QAEvB,OAAAE,EAAQ,SAAS,IACfF,EAAK,QACLA,EAAK,eACLA,EAAK,OACP,EAEAE,EAAQ,eAAe,IACrBF,EAAK,OACP,EAEAC,EAAO,KAAKC,EAASA,CAAO,EACrBA,EAAQ,MAAM,CACvB,EAEAF,EAAK,QAAU,QACf;AAAA;AAAA;AAAA,GASAA,EAAK,MAAQ,CAAC,EASdA,EAAK,MAAM,KAAQ,SAAUG,EAAQ,CAEnC,OAAO,SAAUC,EAAS,CACpBD,EAAO,SAAW,QAAQ,MAC5B,QAAQ,KAAKC,CAAO,CAExB,CAEF,EAAG,IAAI,EAaPJ,EAAK,MAAM,SAAW,SAAUK,EAAK,CACnC,OAAsBA,GAAQ,KACrB,GAEAA,EAAI,SAAS,CAExB,EAkBAL,EAAK,MAAM,MAAQ,SAAUK,EAAK,CAChC,GAAIA,GAAQ,KACV,OAAOA,EAMT,QAHIC,EAAQ,OAAO,OAAO,IAAI,EAC1BC,EAAO,OAAO,KAAKF,CAAG,EAEjB,EAAI,EAAG,EAAIE,EAAK,OAAQ,IAAK,CACpC,IAAIC,EAAMD,EAAK,GACXE,EAAMJ,EAAIG,GAEd,GAAI,MAAM,QAAQC,CAAG,EAAG,CACtBH,EAAME,GAAOC,EAAI,MAAM,EACvB,QACF,CAEA,GAAI,OAAOA,GAAQ,UACf,OAAOA,GAAQ,UACf,OAAOA,GAAQ,UAAW,CAC5BH,EAAME,GAAOC,EACb,QACF,CAEA,MAAM,IAAI,UAAU,uDAAuD,CAC7E,CAEA,OAAOH,CACT,EACAN,EAAK,SAAW,SAAUU,EAAQC,EAAWC,EAAa,CACxD,KAAK,OAASF,EACd,KAAK,UAAYC,EACjB,KAAK,aAAeC,CACtB,EAEAZ,EAAK,SAAS,OAAS,IAEvBA,EAAK,SAAS,WAAa,SAAUa,EAAG,CACtC,IAAIC,EAAID,EAAE,QAAQb,EAAK,SAAS,MAAM,EAEtC,GAAIc,IAAM,GACR,KAAM,6BAGR,IAAIC,EAAWF,EAAE,MAAM,EAAGC,CAAC,EACvBJ,EAASG,EAAE,MAAMC,EAAI,CAAC,EAE1B,OAAO,IAAId,EAAK,SAAUU,EAAQK,EAAUF,CAAC,CAC/C,EAEAb,EAAK,SAAS,UAAU,SAAW,UAAY,CAC7C,OAAI,KAAK,cAAgB,OACvB,KAAK,aAAe,KAAK,UAAYA,EAAK,SAAS,OAAS,KAAK,QAG5D,KAAK,YACd,EACA;AAAA;AAAA;AAAA,GAUAA,EAAK,IAAM,SAAUgB,EAAU,CAG7B,GAFA,KAAK,SAAW,OAAO,OAAO,IAAI,EAE9BA,EAAU,CACZ,KAAK,OAASA,EAAS,OAEvB,QAASC,EAAI,EAAGA,EAAI,KAAK,OAAQA,IAC/B,KAAK,SAASD,EAASC,IAAM,EAEjC,MACE,KAAK,OAAS,CAElB,EASAjB,EAAK,IAAI,SAAW,CAClB,UAAW,SAAUkB,EAAO,CAC1B,OAAOA,CACT,EAEA,MAAO,UAAY,CACjB,OAAO,IACT,EAEA,SAAU,UAAY,CACpB,MAAO,EACT,CACF,EASAlB,EAAK,IAAI,MAAQ,CACf,UAAW,UAAY,CACrB,OAAO,IACT,EAEA,MAAO,SAAUkB,EAAO,CACtB,OAAOA,CACT,EAEA,SAAU,UAAY,CACpB,MAAO,EACT,CACF,EAQAlB,EAAK,IAAI,UAAU,SAAW,SAAUmB,EAAQ,CAC9C,MAAO,CAAC,CAAC,KAAK,SAASA,EACzB,EAUAnB,EAAK,IAAI,UAAU,UAAY,SAAUkB,EAAO,CAC9C,IAAIE,EAAGC,EAAGL,EAAUM,EAAe,CAAC,EAEpC,GAAIJ,IAAUlB,EAAK,IAAI,SACrB,OAAO,KAGT,GAAIkB,IAAUlB,EAAK,IAAI,MACrB,OAAOkB,EAGL,KAAK,OAASA,EAAM,QACtBE,EAAI,KACJC,EAAIH,IAEJE,EAAIF,EACJG,EAAI,MAGNL,EAAW,OAAO,KAAKI,EAAE,QAAQ,EAEjC,QAASH,EAAI,EAAGA,EAAID,EAAS,OAAQC,IAAK,CACxC,IAAIM,EAAUP,EAASC,GACnBM,KAAWF,EAAE,UACfC,EAAa,KAAKC,CAAO,CAE7B,CAEA,OAAO,IAAIvB,EAAK,IAAKsB,CAAY,CACnC,EASAtB,EAAK,IAAI,UAAU,MAAQ,SAAUkB,EAAO,CAC1C,OAAIA,IAAUlB,EAAK,IAAI,SACdA,EAAK,IAAI,SAGdkB,IAAUlB,EAAK,IAAI,MACd,KAGF,IAAIA,EAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,OAAO,OAAO,KAAKkB,EAAM,QAAQ,CAAC,CAAC,CACpF,EASAlB,EAAK,IAAM,SAAUwB,EAASC,EAAe,CAC3C,IAAIC,EAAoB,EAExB,QAASf,KAAaa,EAChBb,GAAa,WACjBe,GAAqB,OAAO,KAAKF,EAAQb,EAAU,EAAE,QAGvD,IAAIgB,GAAKF,EAAgBC,EAAoB,KAAQA,EAAoB,IAEzE,OAAO,KAAK,IAAI,EAAI,KAAK,IAAIC,CAAC,CAAC,CACjC,EAUA3B,EAAK,MAAQ,SAAU4B,EAAKC,EAAU,CACpC,KAAK,IAAMD,GAAO,GAClB,KAAK,SAAWC,GAAY,CAAC,CAC/B,EAOA7B,EAAK,MAAM,UAAU,SAAW,UAAY,CAC1C,OAAO,KAAK,GACd,EAsBAA,EAAK,MAAM,UAAU,OAAS,SAAU8B,EAAI,CAC1C,YAAK,IAAMA,EAAG,KAAK,IAAK,KAAK,QAAQ,EAC9B,IACT,EASA9B,EAAK,MAAM,UAAU,MAAQ,SAAU8B,EAAI,CACzC,OAAAA,EAAKA,GAAM,SAAUjB,EAAG,CAAE,OAAOA,CAAE,EAC5B,IAAIb,EAAK,MAAO8B,EAAG,KAAK,IAAK,KAAK,QAAQ,EAAG,KAAK,QAAQ,CACnE,EACA;AAAA;AAAA;AAAA,GAuBA9B,EAAK,UAAY,SAAUK,EAAKwB,EAAU,CACxC,GAAIxB,GAAO,MAAQA,GAAO,KACxB,MAAO,CAAC,EAGV,GAAI,MAAM,QAAQA,CAAG,EACnB,OAAOA,EAAI,IAAI,SAAU0B,EAAG,CAC1B,OAAO,IAAI/B,EAAK,MACdA,EAAK,MAAM,SAAS+B,CAAC,EAAE,YAAY,EACnC/B,EAAK,MAAM,MAAM6B,CAAQ,CAC3B,CACF,CAAC,EAOH,QAJID,EAAMvB,EAAI,SAAS,EAAE,YAAY,EACjC2B,EAAMJ,EAAI,OACVK,EAAS,CAAC,EAELC,EAAW,EAAGC,EAAa,EAAGD,GAAYF,EAAKE,IAAY,CAClE,IAAIE,EAAOR,EAAI,OAAOM,CAAQ,EAC1BG,EAAcH,EAAWC,EAE7B,GAAKC,EAAK,MAAMpC,EAAK,UAAU,SAAS,GAAKkC,GAAYF,EAAM,CAE7D,GAAIK,EAAc,EAAG,CACnB,IAAIC,EAAgBtC,EAAK,MAAM,MAAM6B,CAAQ,GAAK,CAAC,EACnDS,EAAc,SAAc,CAACH,EAAYE,CAAW,EACpDC,EAAc,MAAWL,EAAO,OAEhCA,EAAO,KACL,IAAIjC,EAAK,MACP4B,EAAI,MAAMO,EAAYD,CAAQ,EAC9BI,CACF,CACF,CACF,CAEAH,EAAaD,EAAW,CAC1B,CAEF,CAEA,OAAOD,CACT,EASAjC,EAAK,UAAU,UAAY,UAC3B;AAAA;AAAA;AAAA,GAkCAA,EAAK,SAAW,UAAY,CAC1B,KAAK,OAAS,CAAC,CACjB,EAEAA,EAAK,SAAS,oBAAsB,OAAO,OAAO,IAAI,EAmCtDA,EAAK,SAAS,iBAAmB,SAAU8B,EAAIS,EAAO,CAChDA,KAAS,KAAK,qBAChBvC,EAAK,MAAM,KAAK,6CAA+CuC,CAAK,EAGtET,EAAG,MAAQS,EACXvC,EAAK,SAAS,oBAAoB8B,EAAG,OAASA,CAChD,EAQA9B,EAAK,SAAS,4BAA8B,SAAU8B,EAAI,CACxD,IAAIU,EAAeV,EAAG,OAAUA,EAAG,SAAS,KAAK,oBAE5CU,GACHxC,EAAK,MAAM,KAAK;AAAA,EAAmG8B,CAAE,CAEzH,EAYA9B,EAAK,SAAS,KAAO,SAAUyC,EAAY,CACzC,IAAIC,EAAW,IAAI1C,EAAK,SAExB,OAAAyC,EAAW,QAAQ,SAAUE,EAAQ,CACnC,IAAIb,EAAK9B,EAAK,SAAS,oBAAoB2C,GAE3C,GAAIb,EACFY,EAAS,IAAIZ,CAAE,MAEf,OAAM,IAAI,MAAM,sCAAwCa,CAAM,CAElE,CAAC,EAEMD,CACT,EASA1C,EAAK,SAAS,UAAU,IAAM,UAAY,CACxC,IAAI4C,EAAM,MAAM,UAAU,MAAM,KAAK,SAAS,EAE9CA,EAAI,QAAQ,SAAUd,EAAI,CACxB9B,EAAK,SAAS,4BAA4B8B,CAAE,EAC5C,KAAK,OAAO,KAAKA,CAAE,CACrB,EAAG,IAAI,CACT,EAWA9B,EAAK,SAAS,UAAU,MAAQ,SAAU6C,EAAYC,EAAO,CAC3D9C,EAAK,SAAS,4BAA4B8C,CAAK,EAE/C,IAAIC,EAAM,KAAK,OAAO,QAAQF,CAAU,EACxC,GAAIE,GAAO,GACT,MAAM,IAAI,MAAM,wBAAwB,EAG1CA,EAAMA,EAAM,EACZ,KAAK,OAAO,OAAOA,EAAK,EAAGD,CAAK,CAClC,EAWA9C,EAAK,SAAS,UAAU,OAAS,SAAU6C,EAAYC,EAAO,CAC5D9C,EAAK,SAAS,4BAA4B8C,CAAK,EAE/C,IAAIC,EAAM,KAAK,OAAO,QAAQF,CAAU,EACxC,GAAIE,GAAO,GACT,MAAM,IAAI,MAAM,wBAAwB,EAG1C,KAAK,OAAO,OAAOA,EAAK,EAAGD,CAAK,CAClC,EAOA9C,EAAK,SAAS,UAAU,OAAS,SAAU8B,EAAI,CAC7C,IAAIiB,EAAM,KAAK,OAAO,QAAQjB,CAAE,EAC5BiB,GAAO,IAIX,KAAK,OAAO,OAAOA,EAAK,CAAC,CAC3B,EASA/C,EAAK,SAAS,UAAU,IAAM,SAAUiC,EAAQ,CAG9C,QAFIe,EAAc,KAAK,OAAO,OAErB/B,EAAI,EAAGA,EAAI+B,EAAa/B,IAAK,CAIpC,QAHIa,EAAK,KAAK,OAAOb,GACjBgC,EAAO,CAAC,EAEHC,EAAI,EAAGA,EAAIjB,EAAO,OAAQiB,IAAK,CACtC,IAAIC,EAASrB,EAAGG,EAAOiB,GAAIA,EAAGjB,CAAM,EAEpC,GAAI,EAAAkB,GAAW,MAA6BA,IAAW,IAEvD,GAAI,MAAM,QAAQA,CAAM,EACtB,QAASC,EAAI,EAAGA,EAAID,EAAO,OAAQC,IACjCH,EAAK,KAAKE,EAAOC,EAAE,OAGrBH,EAAK,KAAKE,CAAM,CAEpB,CAEAlB,EAASgB,CACX,CAEA,OAAOhB,CACT,EAYAjC,EAAK,SAAS,UAAU,UAAY,SAAU4B,EAAKC,EAAU,CAC3D,IAAIwB,EAAQ,IAAIrD,EAAK,MAAO4B,EAAKC,CAAQ,EAEzC,OAAO,KAAK,IAAI,CAACwB,CAAK,CAAC,EAAE,IAAI,SAAUtB,EAAG,CACxC,OAAOA,EAAE,SAAS,CACpB,CAAC,CACH,EAMA/B,EAAK,SAAS,UAAU,MAAQ,UAAY,CAC1C,KAAK,OAAS,CAAC,CACjB,EASAA,EAAK,SAAS,UAAU,OAAS,UAAY,CAC3C,OAAO,KAAK,OAAO,IAAI,SAAU8B,EAAI,CACnC,OAAA9B,EAAK,SAAS,4BAA4B8B,CAAE,EAErCA,EAAG,KACZ,CAAC,CACH,EACA;AAAA;AAAA;AAAA,GAqBA9B,EAAK,OAAS,SAAUgB,EAAU,CAChC,KAAK,WAAa,EAClB,KAAK,SAAWA,GAAY,CAAC,CAC/B,EAaAhB,EAAK,OAAO,UAAU,iBAAmB,SAAUsD,EAAO,CAExD,GAAI,KAAK,SAAS,QAAU,EAC1B,MAAO,GAST,QANIC,EAAQ,EACRC,EAAM,KAAK,SAAS,OAAS,EAC7BnB,EAAcmB,EAAMD,EACpBE,EAAa,KAAK,MAAMpB,EAAc,CAAC,EACvCqB,EAAa,KAAK,SAASD,EAAa,GAErCpB,EAAc,IACfqB,EAAaJ,IACfC,EAAQE,GAGNC,EAAaJ,IACfE,EAAMC,GAGJC,GAAcJ,IAIlBjB,EAAcmB,EAAMD,EACpBE,EAAaF,EAAQ,KAAK,MAAMlB,EAAc,CAAC,EAC/CqB,EAAa,KAAK,SAASD,EAAa,GAO1C,GAJIC,GAAcJ,GAIdI,EAAaJ,EACf,OAAOG,EAAa,EAGtB,GAAIC,EAAaJ,EACf,OAAQG,EAAa,GAAK,CAE9B,EAWAzD,EAAK,OAAO,UAAU,OAAS,SAAU2D,EAAWlD,EAAK,CACvD,KAAK,OAAOkD,EAAWlD,EAAK,UAAY,CACtC,KAAM,iBACR,CAAC,CACH,EAUAT,EAAK,OAAO,UAAU,OAAS,SAAU2D,EAAWlD,EAAKqB,EAAI,CAC3D,KAAK,WAAa,EAClB,IAAI8B,EAAW,KAAK,iBAAiBD,CAAS,EAE1C,KAAK,SAASC,IAAaD,EAC7B,KAAK,SAASC,EAAW,GAAK9B,EAAG,KAAK,SAAS8B,EAAW,GAAInD,CAAG,EAEjE,KAAK,SAAS,OAAOmD,EAAU,EAAGD,EAAWlD,CAAG,CAEpD,EAOAT,EAAK,OAAO,UAAU,UAAY,UAAY,CAC5C,GAAI,KAAK,WAAY,OAAO,KAAK,WAKjC,QAHI6D,EAAe,EACfC,EAAiB,KAAK,SAAS,OAE1B7C,EAAI,EAAGA,EAAI6C,EAAgB7C,GAAK,EAAG,CAC1C,IAAIR,EAAM,KAAK,SAASQ,GACxB4C,GAAgBpD,EAAMA,CACxB,CAEA,OAAO,KAAK,WAAa,KAAK,KAAKoD,CAAY,CACjD,EAQA7D,EAAK,OAAO,UAAU,IAAM,SAAU+D,EAAa,CAOjD,QANIC,EAAa,EACb5C,EAAI,KAAK,SAAUC,EAAI0C,EAAY,SACnCE,EAAO7C,EAAE,OAAQ8C,EAAO7C,EAAE,OAC1B8C,EAAO,EAAGC,EAAO,EACjBnD,EAAI,EAAGiC,EAAI,EAERjC,EAAIgD,GAAQf,EAAIgB,GACrBC,EAAO/C,EAAEH,GAAImD,EAAO/C,EAAE6B,GAClBiB,EAAOC,EACTnD,GAAK,EACIkD,EAAOC,EAChBlB,GAAK,EACIiB,GAAQC,IACjBJ,GAAc5C,EAAEH,EAAI,GAAKI,EAAE6B,EAAI,GAC/BjC,GAAK,EACLiC,GAAK,GAIT,OAAOc,CACT,EASAhE,EAAK,OAAO,UAAU,WAAa,SAAU+D,EAAa,CACxD,OAAO,KAAK,IAAIA,CAAW,EAAI,KAAK,UAAU,GAAK,CACrD,EAOA/D,EAAK,OAAO,UAAU,QAAU,UAAY,CAG1C,QAFIqE,EAAS,IAAI,MAAO,KAAK,SAAS,OAAS,CAAC,EAEvCpD,EAAI,EAAGiC,EAAI,EAAGjC,EAAI,KAAK,SAAS,OAAQA,GAAK,EAAGiC,IACvDmB,EAAOnB,GAAK,KAAK,SAASjC,GAG5B,OAAOoD,CACT,EAOArE,EAAK,OAAO,UAAU,OAAS,UAAY,CACzC,OAAO,KAAK,QACd,EAEA;AAAA;AAAA;AAAA;AAAA,GAiBAA,EAAK,QAAW,UAAU,CACxB,IAAIsE,EAAY,CACZ,QAAY,MACZ,OAAW,OACX,KAAS,OACT,KAAS,OACT,KAAS,MACT,IAAQ,MACR,KAAS,KACT,MAAU,MACV,IAAQ,IACR,MAAU,MACV,QAAY,MACZ,MAAU,MACV,KAAS,MACT,MAAU,KACV,QAAY,MACZ,QAAY,MACZ,QAAY,MACZ,MAAU,KACV,MAAU,MACV,OAAW,MACX,KAAS,KACX,EAEAC,EAAY,CACV,MAAU,KACV,MAAU,GACV,MAAU,KACV,MAAU,KACV,KAAS,KACT,IAAQ,GACR,KAAS,EACX,EAEAC,EAAI,WACJC,EAAI,WACJC,EAAIF,EAAI,aACRG,EAAIF,EAAI,WAERG,EAAO,KAAOF,EAAI,KAAOC,EAAID,EAC7BG,EAAO,KAAOH,EAAI,KAAOC,EAAID,EAAI,IAAMC,EAAI,MAC3CG,EAAO,KAAOJ,EAAI,KAAOC,EAAID,EAAIC,EAAID,EACrCK,EAAM,KAAOL,EAAI,KAAOD,EAEtBO,EAAU,IAAI,OAAOJ,CAAI,EACzBK,EAAU,IAAI,OAAOH,CAAI,EACzBI,EAAU,IAAI,OAAOL,CAAI,EACzBM,EAAS,IAAI,OAAOJ,CAAG,EAEvBK,EAAQ,kBACRC,EAAS,iBACTC,EAAQ,aACRC,EAAS,kBACTC,EAAU,KACVC,EAAW,cACXC,EAAW,IAAI,OAAO,oBAAoB,EAC1CC,EAAW,IAAI,OAAO,IAAMjB,EAAID,EAAI,cAAc,EAElDmB,EAAQ,mBACRC,EAAO,2IAEPC,EAAO,iDAEPC,EAAO,sFACPC,EAAQ,oBAERC,EAAO,WACPC,EAAS,MACTC,EAAQ,IAAI,OAAO,IAAMzB,EAAID,EAAI,cAAc,EAE/C2B,EAAgB,SAAuBC,EAAG,CAC5C,IAAIC,EACFC,EACAC,EACAC,EACAC,EACAC,EACAC,EAEF,GAAIP,EAAE,OAAS,EAAK,OAAOA,EAiB3B,GAfAG,EAAUH,EAAE,OAAO,EAAE,CAAC,EAClBG,GAAW,MACbH,EAAIG,EAAQ,YAAY,EAAIH,EAAE,OAAO,CAAC,GAIxCI,EAAKrB,EACLsB,EAAMrB,EAEFoB,EAAG,KAAKJ,CAAC,EAAKA,EAAIA,EAAE,QAAQI,EAAG,MAAM,EAChCC,EAAI,KAAKL,CAAC,IAAKA,EAAIA,EAAE,QAAQK,EAAI,MAAM,GAGhDD,EAAKnB,EACLoB,EAAMnB,EACFkB,EAAG,KAAKJ,CAAC,EAAG,CACd,IAAIQ,EAAKJ,EAAG,KAAKJ,CAAC,EAClBI,EAAKzB,EACDyB,EAAG,KAAKI,EAAG,EAAE,IACfJ,EAAKjB,EACLa,EAAIA,EAAE,QAAQI,EAAG,EAAE,EAEvB,SAAWC,EAAI,KAAKL,CAAC,EAAG,CACtB,IAAIQ,EAAKH,EAAI,KAAKL,CAAC,EACnBC,EAAOO,EAAG,GACVH,EAAMvB,EACFuB,EAAI,KAAKJ,CAAI,IACfD,EAAIC,EACJI,EAAMjB,EACNkB,EAAMjB,EACNkB,EAAMjB,EACFe,EAAI,KAAKL,CAAC,EAAKA,EAAIA,EAAI,IAClBM,EAAI,KAAKN,CAAC,GAAKI,EAAKjB,EAASa,EAAIA,EAAE,QAAQI,EAAG,EAAE,GAChDG,EAAI,KAAKP,CAAC,IAAKA,EAAIA,EAAI,KAEpC,CAIA,GADAI,EAAKb,EACDa,EAAG,KAAKJ,CAAC,EAAG,CACd,IAAIQ,EAAKJ,EAAG,KAAKJ,CAAC,EAClBC,EAAOO,EAAG,GACVR,EAAIC,EAAO,GACb,CAIA,GADAG,EAAKZ,EACDY,EAAG,KAAKJ,CAAC,EAAG,CACd,IAAIQ,EAAKJ,EAAG,KAAKJ,CAAC,EAClBC,EAAOO,EAAG,GACVN,EAASM,EAAG,GACZJ,EAAKzB,EACDyB,EAAG,KAAKH,CAAI,IACdD,EAAIC,EAAOhC,EAAUiC,GAEzB,CAIA,GADAE,EAAKX,EACDW,EAAG,KAAKJ,CAAC,EAAG,CACd,IAAIQ,EAAKJ,EAAG,KAAKJ,CAAC,EAClBC,EAAOO,EAAG,GACVN,EAASM,EAAG,GACZJ,EAAKzB,EACDyB,EAAG,KAAKH,CAAI,IACdD,EAAIC,EAAO/B,EAAUgC,GAEzB,CAKA,GAFAE,EAAKV,EACLW,EAAMV,EACFS,EAAG,KAAKJ,CAAC,EAAG,CACd,IAAIQ,EAAKJ,EAAG,KAAKJ,CAAC,EAClBC,EAAOO,EAAG,GACVJ,EAAKxB,EACDwB,EAAG,KAAKH,CAAI,IACdD,EAAIC,EAER,SAAWI,EAAI,KAAKL,CAAC,EAAG,CACtB,IAAIQ,EAAKH,EAAI,KAAKL,CAAC,EACnBC,EAAOO,EAAG,GAAKA,EAAG,GAClBH,EAAMzB,EACFyB,EAAI,KAAKJ,CAAI,IACfD,EAAIC,EAER,CAIA,GADAG,EAAKR,EACDQ,EAAG,KAAKJ,CAAC,EAAG,CACd,IAAIQ,EAAKJ,EAAG,KAAKJ,CAAC,EAClBC,EAAOO,EAAG,GACVJ,EAAKxB,EACLyB,EAAMxB,EACNyB,EAAMR,GACFM,EAAG,KAAKH,CAAI,GAAMI,EAAI,KAAKJ,CAAI,GAAK,CAAEK,EAAI,KAAKL,CAAI,KACrDD,EAAIC,EAER,CAEA,OAAAG,EAAKP,EACLQ,EAAMzB,EACFwB,EAAG,KAAKJ,CAAC,GAAKK,EAAI,KAAKL,CAAC,IAC1BI,EAAKjB,EACLa,EAAIA,EAAE,QAAQI,EAAG,EAAE,GAKjBD,GAAW,MACbH,EAAIG,EAAQ,YAAY,EAAIH,EAAE,OAAO,CAAC,GAGjCA,CACT,EAEA,OAAO,SAAUhD,EAAO,CACtB,OAAOA,EAAM,OAAO+C,CAAa,CACnC,CACF,EAAG,EAEHpG,EAAK,SAAS,iBAAiBA,EAAK,QAAS,SAAS,EACtD;AAAA;AAAA;AAAA,GAkBAA,EAAK,uBAAyB,SAAU8G,EAAW,CACjD,IAAIC,EAAQD,EAAU,OAAO,SAAU7D,EAAM+D,EAAU,CACrD,OAAA/D,EAAK+D,GAAYA,EACV/D,CACT,EAAG,CAAC,CAAC,EAEL,OAAO,SAAUI,EAAO,CACtB,GAAIA,GAAS0D,EAAM1D,EAAM,SAAS,KAAOA,EAAM,SAAS,EAAG,OAAOA,CACpE,CACF,EAeArD,EAAK,eAAiBA,EAAK,uBAAuB,CAChD,IACA,OACA,QACA,SACA,QACA,MACA,SACA,OACA,KACA,QACA,KACA,MACA,MACA,MACA,KACA,KACA,KACA,UACA,OACA,MACA,KACA,MACA,SACA,QACA,OACA,MACA,KACA,OACA,SACA,OACA,OACA,QACA,MACA,OACA,MACA,MACA,MACA,MACA,OACA,KACA,MACA,OACA,MACA,MACA,MACA,UACA,IACA,KACA,KACA,OACA,KACA,KACA,MACA,OACA,QACA,MACA,OACA,SACA,MACA,KACA,QACA,OACA,OACA,KACA,UACA,KACA,MACA,MACA,KACA,MACA,QACA,KACA,OACA,KACA,QACA,MACA,MACA,SACA,OACA,MACA,OACA,MACA,SACA,QACA,KACA,OACA,OACA,OACA,MACA,QACA,OACA,OACA,QACA,QACA,OACA,OACA,MACA,KACA,MACA,OACA,KACA,QACA,MACA,KACA,OACA,OACA,OACA,QACA,QACA,QACA,MACA,OACA,MACA,OACA,OACA,QACA,MACA,MACA,MACF,CAAC,EAEDA,EAAK,SAAS,iBAAiBA,EAAK,eAAgB,gBAAgB,EACpE;AAAA;AAAA;AAAA,GAoBAA,EAAK,QAAU,SAAUqD,EAAO,CAC9B,OAAOA,EAAM,OAAO,SAAUxC,EAAG,CAC/B,OAAOA,EAAE,QAAQ,OAAQ,EAAE,EAAE,QAAQ,OAAQ,EAAE,CACjD,CAAC,CACH,EAEAb,EAAK,SAAS,iBAAiBA,EAAK,QAAS,SAAS,EACtD;AAAA;AAAA;AAAA,GA0BAA,EAAK,SAAW,UAAY,CAC1B,KAAK,MAAQ,GACb,KAAK,MAAQ,CAAC,EACd,KAAK,GAAKA,EAAK,SAAS,QACxBA,EAAK,SAAS,SAAW,CAC3B,EAUAA,EAAK,SAAS,QAAU,EASxBA,EAAK,SAAS,UAAY,SAAUiH,EAAK,CAGvC,QAFI/G,EAAU,IAAIF,EAAK,SAAS,QAEvBiB,EAAI,EAAGe,EAAMiF,EAAI,OAAQhG,EAAIe,EAAKf,IACzCf,EAAQ,OAAO+G,EAAIhG,EAAE,EAGvB,OAAAf,EAAQ,OAAO,EACRA,EAAQ,IACjB,EAWAF,EAAK,SAAS,WAAa,SAAUkH,EAAQ,CAC3C,MAAI,iBAAkBA,EACblH,EAAK,SAAS,gBAAgBkH,EAAO,KAAMA,EAAO,YAAY,EAE9DlH,EAAK,SAAS,WAAWkH,EAAO,IAAI,CAE/C,EAiBAlH,EAAK,SAAS,gBAAkB,SAAU4B,EAAKuF,EAAc,CAS3D,QARIC,EAAO,IAAIpH,EAAK,SAEhBqH,EAAQ,CAAC,CACX,KAAMD,EACN,eAAgBD,EAChB,IAAKvF,CACP,CAAC,EAEMyF,EAAM,QAAQ,CACnB,IAAIC,EAAQD,EAAM,IAAI,EAGtB,GAAIC,EAAM,IAAI,OAAS,EAAG,CACxB,IAAIlF,EAAOkF,EAAM,IAAI,OAAO,CAAC,EACzBC,EAEAnF,KAAQkF,EAAM,KAAK,MACrBC,EAAaD,EAAM,KAAK,MAAMlF,IAE9BmF,EAAa,IAAIvH,EAAK,SACtBsH,EAAM,KAAK,MAAMlF,GAAQmF,GAGvBD,EAAM,IAAI,QAAU,IACtBC,EAAW,MAAQ,IAGrBF,EAAM,KAAK,CACT,KAAME,EACN,eAAgBD,EAAM,eACtB,IAAKA,EAAM,IAAI,MAAM,CAAC,CACxB,CAAC,CACH,CAEA,GAAIA,EAAM,gBAAkB,EAK5B,IAAI,MAAOA,EAAM,KAAK,MACpB,IAAIE,EAAgBF,EAAM,KAAK,MAAM,SAChC,CACL,IAAIE,EAAgB,IAAIxH,EAAK,SAC7BsH,EAAM,KAAK,MAAM,KAAOE,CAC1B,CAgCA,GA9BIF,EAAM,IAAI,QAAU,IACtBE,EAAc,MAAQ,IAGxBH,EAAM,KAAK,CACT,KAAMG,EACN,eAAgBF,EAAM,eAAiB,EACvC,IAAKA,EAAM,GACb,CAAC,EAKGA,EAAM,IAAI,OAAS,GACrBD,EAAM,KAAK,CACT,KAAMC,EAAM,KACZ,eAAgBA,EAAM,eAAiB,EACvC,IAAKA,EAAM,IAAI,MAAM,CAAC,CACxB,CAAC,EAKCA,EAAM,IAAI,QAAU,IACtBA,EAAM,KAAK,MAAQ,IAMjBA,EAAM,IAAI,QAAU,EAAG,CACzB,GAAI,MAAOA,EAAM,KAAK,MACpB,IAAIG,EAAmBH,EAAM,KAAK,MAAM,SACnC,CACL,IAAIG,EAAmB,IAAIzH,EAAK,SAChCsH,EAAM,KAAK,MAAM,KAAOG,CAC1B,CAEIH,EAAM,IAAI,QAAU,IACtBG,EAAiB,MAAQ,IAG3BJ,EAAM,KAAK,CACT,KAAMI,EACN,eAAgBH,EAAM,eAAiB,EACvC,IAAKA,EAAM,IAAI,MAAM,CAAC,CACxB,CAAC,CACH,CAKA,GAAIA,EAAM,IAAI,OAAS,EAAG,CACxB,IAAII,EAAQJ,EAAM,IAAI,OAAO,CAAC,EAC1BK,EAAQL,EAAM,IAAI,OAAO,CAAC,EAC1BM,EAEAD,KAASL,EAAM,KAAK,MACtBM,EAAgBN,EAAM,KAAK,MAAMK,IAEjCC,EAAgB,IAAI5H,EAAK,SACzBsH,EAAM,KAAK,MAAMK,GAASC,GAGxBN,EAAM,IAAI,QAAU,IACtBM,EAAc,MAAQ,IAGxBP,EAAM,KAAK,CACT,KAAMO,EACN,eAAgBN,EAAM,eAAiB,EACvC,IAAKI,EAAQJ,EAAM,IAAI,MAAM,CAAC,CAChC,CAAC,CACH,EACF,CAEA,OAAOF,CACT,EAYApH,EAAK,SAAS,WAAa,SAAU4B,EAAK,CAYxC,QAXIiG,EAAO,IAAI7H,EAAK,SAChBoH,EAAOS,EAUF,EAAI,EAAG7F,EAAMJ,EAAI,OAAQ,EAAII,EAAK,IAAK,CAC9C,IAAII,EAAOR,EAAI,GACXkG,EAAS,GAAK9F,EAAM,EAExB,GAAII,GAAQ,IACVyF,EAAK,MAAMzF,GAAQyF,EACnBA,EAAK,MAAQC,MAER,CACL,IAAIC,EAAO,IAAI/H,EAAK,SACpB+H,EAAK,MAAQD,EAEbD,EAAK,MAAMzF,GAAQ2F,EACnBF,EAAOE,CACT,CACF,CAEA,OAAOX,CACT,EAYApH,EAAK,SAAS,UAAU,QAAU,UAAY,CAQ5C,QAPI+G,EAAQ,CAAC,EAETM,EAAQ,CAAC,CACX,OAAQ,GACR,KAAM,IACR,CAAC,EAEMA,EAAM,QAAQ,CACnB,IAAIC,EAAQD,EAAM,IAAI,EAClBW,EAAQ,OAAO,KAAKV,EAAM,KAAK,KAAK,EACpCtF,EAAMgG,EAAM,OAEZV,EAAM,KAAK,QAKbA,EAAM,OAAO,OAAO,CAAC,EACrBP,EAAM,KAAKO,EAAM,MAAM,GAGzB,QAASrG,EAAI,EAAGA,EAAIe,EAAKf,IAAK,CAC5B,IAAIgH,EAAOD,EAAM/G,GAEjBoG,EAAM,KAAK,CACT,OAAQC,EAAM,OAAO,OAAOW,CAAI,EAChC,KAAMX,EAAM,KAAK,MAAMW,EACzB,CAAC,CACH,CACF,CAEA,OAAOlB,CACT,EAYA/G,EAAK,SAAS,UAAU,SAAW,UAAY,CAS7C,GAAI,KAAK,KACP,OAAO,KAAK,KAOd,QAJI4B,EAAM,KAAK,MAAQ,IAAM,IACzBsG,EAAS,OAAO,KAAK,KAAK,KAAK,EAAE,KAAK,EACtClG,EAAMkG,EAAO,OAER,EAAI,EAAG,EAAIlG,EAAK,IAAK,CAC5B,IAAIO,EAAQ2F,EAAO,GACfL,EAAO,KAAK,MAAMtF,GAEtBX,EAAMA,EAAMW,EAAQsF,EAAK,EAC3B,CAEA,OAAOjG,CACT,EAYA5B,EAAK,SAAS,UAAU,UAAY,SAAUqB,EAAG,CAU/C,QATIgD,EAAS,IAAIrE,EAAK,SAClBsH,EAAQ,OAERD,EAAQ,CAAC,CACX,MAAOhG,EACP,OAAQgD,EACR,KAAM,IACR,CAAC,EAEMgD,EAAM,QAAQ,CACnBC,EAAQD,EAAM,IAAI,EAWlB,QALIc,EAAS,OAAO,KAAKb,EAAM,MAAM,KAAK,EACtCc,EAAOD,EAAO,OACdE,EAAS,OAAO,KAAKf,EAAM,KAAK,KAAK,EACrCgB,EAAOD,EAAO,OAETE,EAAI,EAAGA,EAAIH,EAAMG,IAGxB,QAFIC,EAAQL,EAAOI,GAEVzH,EAAI,EAAGA,EAAIwH,EAAMxH,IAAK,CAC7B,IAAI2H,EAAQJ,EAAOvH,GAEnB,GAAI2H,GAASD,GAASA,GAAS,IAAK,CAClC,IAAIX,EAAOP,EAAM,KAAK,MAAMmB,GACxBC,EAAQpB,EAAM,MAAM,MAAMkB,GAC1BV,EAAQD,EAAK,OAASa,EAAM,MAC5BX,EAAO,OAEPU,KAASnB,EAAM,OAAO,OAIxBS,EAAOT,EAAM,OAAO,MAAMmB,GAC1BV,EAAK,MAAQA,EAAK,OAASD,IAM3BC,EAAO,IAAI/H,EAAK,SAChB+H,EAAK,MAAQD,EACbR,EAAM,OAAO,MAAMmB,GAASV,GAG9BV,EAAM,KAAK,CACT,MAAOqB,EACP,OAAQX,EACR,KAAMF,CACR,CAAC,CACH,CACF,CAEJ,CAEA,OAAOxD,CACT,EACArE,EAAK,SAAS,QAAU,UAAY,CAClC,KAAK,aAAe,GACpB,KAAK,KAAO,IAAIA,EAAK,SACrB,KAAK,eAAiB,CAAC,EACvB,KAAK,eAAiB,CAAC,CACzB,EAEAA,EAAK,SAAS,QAAQ,UAAU,OAAS,SAAU2I,EAAM,CACvD,IAAId,EACAe,EAAe,EAEnB,GAAID,EAAO,KAAK,aACd,MAAM,IAAI,MAAO,6BAA6B,EAGhD,QAAS,EAAI,EAAG,EAAIA,EAAK,QAAU,EAAI,KAAK,aAAa,QACnDA,EAAK,IAAM,KAAK,aAAa,GAD8B,IAE/DC,IAGF,KAAK,SAASA,CAAY,EAEtB,KAAK,eAAe,QAAU,EAChCf,EAAO,KAAK,KAEZA,EAAO,KAAK,eAAe,KAAK,eAAe,OAAS,GAAG,MAG7D,QAAS,EAAIe,EAAc,EAAID,EAAK,OAAQ,IAAK,CAC/C,IAAIE,EAAW,IAAI7I,EAAK,SACpBoC,EAAOuG,EAAK,GAEhBd,EAAK,MAAMzF,GAAQyG,EAEnB,KAAK,eAAe,KAAK,CACvB,OAAQhB,EACR,KAAMzF,EACN,MAAOyG,CACT,CAAC,EAEDhB,EAAOgB,CACT,CAEAhB,EAAK,MAAQ,GACb,KAAK,aAAec,CACtB,EAEA3I,EAAK,SAAS,QAAQ,UAAU,OAAS,UAAY,CACnD,KAAK,SAAS,CAAC,CACjB,EAEAA,EAAK,SAAS,QAAQ,UAAU,SAAW,SAAU8I,EAAQ,CAC3D,QAAS7H,EAAI,KAAK,eAAe,OAAS,EAAGA,GAAK6H,EAAQ7H,IAAK,CAC7D,IAAI4G,EAAO,KAAK,eAAe5G,GAC3B8H,EAAWlB,EAAK,MAAM,SAAS,EAE/BkB,KAAY,KAAK,eACnBlB,EAAK,OAAO,MAAMA,EAAK,MAAQ,KAAK,eAAekB,IAInDlB,EAAK,MAAM,KAAOkB,EAElB,KAAK,eAAeA,GAAYlB,EAAK,OAGvC,KAAK,eAAe,IAAI,CAC1B,CACF,EACA;AAAA;AAAA;AAAA,GAqBA7H,EAAK,MAAQ,SAAUgJ,EAAO,CAC5B,KAAK,cAAgBA,EAAM,cAC3B,KAAK,aAAeA,EAAM,aAC1B,KAAK,SAAWA,EAAM,SACtB,KAAK,OAASA,EAAM,OACpB,KAAK,SAAWA,EAAM,QACxB,EAyEAhJ,EAAK,MAAM,UAAU,OAAS,SAAUiJ,EAAa,CACnD,OAAO,KAAK,MAAM,SAAUC,EAAO,CACjC,IAAIC,EAAS,IAAInJ,EAAK,YAAYiJ,EAAaC,CAAK,EACpDC,EAAO,MAAM,CACf,CAAC,CACH,EA2BAnJ,EAAK,MAAM,UAAU,MAAQ,SAAU8B,EAAI,CAoBzC,QAZIoH,EAAQ,IAAIlJ,EAAK,MAAM,KAAK,MAAM,EAClCoJ,EAAiB,OAAO,OAAO,IAAI,EACnCC,EAAe,OAAO,OAAO,IAAI,EACjCC,EAAiB,OAAO,OAAO,IAAI,EACnCC,EAAkB,OAAO,OAAO,IAAI,EACpCC,EAAoB,OAAO,OAAO,IAAI,EAOjCvI,EAAI,EAAGA,EAAI,KAAK,OAAO,OAAQA,IACtCoI,EAAa,KAAK,OAAOpI,IAAM,IAAIjB,EAAK,OAG1C8B,EAAG,KAAKoH,EAAOA,CAAK,EAEpB,QAASjI,EAAI,EAAGA,EAAIiI,EAAM,QAAQ,OAAQjI,IAAK,CAS7C,IAAIiG,EAASgC,EAAM,QAAQjI,GACvBwI,EAAQ,KACRC,EAAgB1J,EAAK,IAAI,MAEzBkH,EAAO,YACTuC,EAAQ,KAAK,SAAS,UAAUvC,EAAO,KAAM,CAC3C,OAAQA,EAAO,MACjB,CAAC,EAEDuC,EAAQ,CAACvC,EAAO,IAAI,EAGtB,QAASyC,EAAI,EAAGA,EAAIF,EAAM,OAAQE,IAAK,CACrC,IAAIC,EAAOH,EAAME,GAQjBzC,EAAO,KAAO0C,EAOd,IAAIC,EAAe7J,EAAK,SAAS,WAAWkH,CAAM,EAC9C4C,EAAgB,KAAK,SAAS,UAAUD,CAAY,EAAE,QAAQ,EAQlE,GAAIC,EAAc,SAAW,GAAK5C,EAAO,WAAalH,EAAK,MAAM,SAAS,SAAU,CAClF,QAASoD,EAAI,EAAGA,EAAI8D,EAAO,OAAO,OAAQ9D,IAAK,CAC7C,IAAI2G,EAAQ7C,EAAO,OAAO9D,GAC1BmG,EAAgBQ,GAAS/J,EAAK,IAAI,KACpC,CAEA,KACF,CAEA,QAASkD,EAAI,EAAGA,EAAI4G,EAAc,OAAQ5G,IASxC,QAJI8G,EAAeF,EAAc5G,GAC7B1B,EAAU,KAAK,cAAcwI,GAC7BC,EAAYzI,EAAQ,OAEf4B,EAAI,EAAGA,EAAI8D,EAAO,OAAO,OAAQ9D,IAAK,CAS7C,IAAI2G,EAAQ7C,EAAO,OAAO9D,GACtB8G,EAAe1I,EAAQuI,GACvBI,EAAuB,OAAO,KAAKD,CAAY,EAC/CE,EAAYJ,EAAe,IAAMD,EACjCM,EAAuB,IAAIrK,EAAK,IAAImK,CAAoB,EAoB5D,GAbIjD,EAAO,UAAYlH,EAAK,MAAM,SAAS,WACzC0J,EAAgBA,EAAc,MAAMW,CAAoB,EAEpDd,EAAgBQ,KAAW,SAC7BR,EAAgBQ,GAAS/J,EAAK,IAAI,WASlCkH,EAAO,UAAYlH,EAAK,MAAM,SAAS,WAAY,CACjDwJ,EAAkBO,KAAW,SAC/BP,EAAkBO,GAAS/J,EAAK,IAAI,OAGtCwJ,EAAkBO,GAASP,EAAkBO,GAAO,MAAMM,CAAoB,EAO9E,QACF,CAeA,GANAhB,EAAaU,GAAO,OAAOE,EAAW/C,EAAO,MAAO,SAAU9F,GAAGC,GAAG,CAAE,OAAOD,GAAIC,EAAE,CAAC,EAMhF,CAAAiI,EAAec,GAInB,SAASE,EAAI,EAAGA,EAAIH,EAAqB,OAAQG,IAAK,CAOpD,IAAIC,EAAsBJ,EAAqBG,GAC3CE,EAAmB,IAAIxK,EAAK,SAAUuK,EAAqBR,CAAK,EAChElI,EAAWqI,EAAaK,GACxBE,GAECA,EAAarB,EAAeoB,MAAuB,OACtDpB,EAAeoB,GAAoB,IAAIxK,EAAK,UAAWgK,EAAcD,EAAOlI,CAAQ,EAEpF4I,EAAW,IAAIT,EAAcD,EAAOlI,CAAQ,CAGhD,CAEAyH,EAAec,GAAa,GAC9B,CAEJ,CAQA,GAAIlD,EAAO,WAAalH,EAAK,MAAM,SAAS,SAC1C,QAASoD,EAAI,EAAGA,EAAI8D,EAAO,OAAO,OAAQ9D,IAAK,CAC7C,IAAI2G,EAAQ7C,EAAO,OAAO9D,GAC1BmG,EAAgBQ,GAASR,EAAgBQ,GAAO,UAAUL,CAAa,CACzE,CAEJ,CAUA,QAHIgB,EAAqB1K,EAAK,IAAI,SAC9B2K,EAAuB3K,EAAK,IAAI,MAE3BiB,EAAI,EAAGA,EAAI,KAAK,OAAO,OAAQA,IAAK,CAC3C,IAAI8I,EAAQ,KAAK,OAAO9I,GAEpBsI,EAAgBQ,KAClBW,EAAqBA,EAAmB,UAAUnB,EAAgBQ,EAAM,GAGtEP,EAAkBO,KACpBY,EAAuBA,EAAqB,MAAMnB,EAAkBO,EAAM,EAE9E,CAEA,IAAIa,EAAoB,OAAO,KAAKxB,CAAc,EAC9CyB,EAAU,CAAC,EACXC,EAAU,OAAO,OAAO,IAAI,EAYhC,GAAI5B,EAAM,UAAU,EAAG,CACrB0B,EAAoB,OAAO,KAAK,KAAK,YAAY,EAEjD,QAAS3J,EAAI,EAAGA,EAAI2J,EAAkB,OAAQ3J,IAAK,CACjD,IAAIuJ,EAAmBI,EAAkB3J,GACrCF,EAAWf,EAAK,SAAS,WAAWwK,CAAgB,EACxDpB,EAAeoB,GAAoB,IAAIxK,EAAK,SAC9C,CACF,CAEA,QAASiB,EAAI,EAAGA,EAAI2J,EAAkB,OAAQ3J,IAAK,CASjD,IAAIF,EAAWf,EAAK,SAAS,WAAW4K,EAAkB3J,EAAE,EACxDP,EAASK,EAAS,OAEtB,GAAI,EAAC2J,EAAmB,SAAShK,CAAM,GAInC,CAAAiK,EAAqB,SAASjK,CAAM,EAIxC,KAAIqK,EAAc,KAAK,aAAahK,GAChCiK,EAAQ3B,EAAatI,EAAS,WAAW,WAAWgK,CAAW,EAC/DE,EAEJ,IAAKA,EAAWH,EAAQpK,MAAa,OACnCuK,EAAS,OAASD,EAClBC,EAAS,UAAU,QAAQ7B,EAAerI,EAAS,MAC9C,CACL,IAAImK,EAAQ,CACV,IAAKxK,EACL,MAAOsK,EACP,UAAW5B,EAAerI,EAC5B,EACA+J,EAAQpK,GAAUwK,EAClBL,EAAQ,KAAKK,CAAK,CACpB,EACF,CAKA,OAAOL,EAAQ,KAAK,SAAUzJ,GAAGC,GAAG,CAClC,OAAOA,GAAE,MAAQD,GAAE,KACrB,CAAC,CACH,EAUApB,EAAK,MAAM,UAAU,OAAS,UAAY,CACxC,IAAImL,EAAgB,OAAO,KAAK,KAAK,aAAa,EAC/C,KAAK,EACL,IAAI,SAAUvB,EAAM,CACnB,MAAO,CAACA,EAAM,KAAK,cAAcA,EAAK,CACxC,EAAG,IAAI,EAELwB,EAAe,OAAO,KAAK,KAAK,YAAY,EAC7C,IAAI,SAAUC,EAAK,CAClB,MAAO,CAACA,EAAK,KAAK,aAAaA,GAAK,OAAO,CAAC,CAC9C,EAAG,IAAI,EAET,MAAO,CACL,QAASrL,EAAK,QACd,OAAQ,KAAK,OACb,aAAcoL,EACd,cAAeD,EACf,SAAU,KAAK,SAAS,OAAO,CACjC,CACF,EAQAnL,EAAK,MAAM,KAAO,SAAUsL,EAAiB,CAC3C,IAAItC,EAAQ,CAAC,EACToC,EAAe,CAAC,EAChBG,EAAoBD,EAAgB,aACpCH,EAAgB,OAAO,OAAO,IAAI,EAClCK,EAA0BF,EAAgB,cAC1CG,EAAkB,IAAIzL,EAAK,SAAS,QACpC0C,EAAW1C,EAAK,SAAS,KAAKsL,EAAgB,QAAQ,EAEtDA,EAAgB,SAAWtL,EAAK,SAClCA,EAAK,MAAM,KAAK,4EAA8EA,EAAK,QAAU,sCAAwCsL,EAAgB,QAAU,GAAG,EAGpL,QAASrK,EAAI,EAAGA,EAAIsK,EAAkB,OAAQtK,IAAK,CACjD,IAAIyK,EAAQH,EAAkBtK,GAC1BoK,EAAMK,EAAM,GACZ1K,EAAW0K,EAAM,GAErBN,EAAaC,GAAO,IAAIrL,EAAK,OAAOgB,CAAQ,CAC9C,CAEA,QAASC,EAAI,EAAGA,EAAIuK,EAAwB,OAAQvK,IAAK,CACvD,IAAIyK,EAAQF,EAAwBvK,GAChC2I,EAAO8B,EAAM,GACblK,EAAUkK,EAAM,GAEpBD,EAAgB,OAAO7B,CAAI,EAC3BuB,EAAcvB,GAAQpI,CACxB,CAEA,OAAAiK,EAAgB,OAAO,EAEvBzC,EAAM,OAASsC,EAAgB,OAE/BtC,EAAM,aAAeoC,EACrBpC,EAAM,cAAgBmC,EACtBnC,EAAM,SAAWyC,EAAgB,KACjCzC,EAAM,SAAWtG,EAEV,IAAI1C,EAAK,MAAMgJ,CAAK,CAC7B,EACA;AAAA;AAAA;AAAA,GA6BAhJ,EAAK,QAAU,UAAY,CACzB,KAAK,KAAO,KACZ,KAAK,QAAU,OAAO,OAAO,IAAI,EACjC,KAAK,WAAa,OAAO,OAAO,IAAI,EACpC,KAAK,cAAgB,OAAO,OAAO,IAAI,EACvC,KAAK,qBAAuB,CAAC,EAC7B,KAAK,aAAe,CAAC,EACrB,KAAK,UAAYA,EAAK,UACtB,KAAK,SAAW,IAAIA,EAAK,SACzB,KAAK,eAAiB,IAAIA,EAAK,SAC/B,KAAK,cAAgB,EACrB,KAAK,GAAK,IACV,KAAK,IAAM,IACX,KAAK,UAAY,EACjB,KAAK,kBAAoB,CAAC,CAC5B,EAcAA,EAAK,QAAQ,UAAU,IAAM,SAAUqL,EAAK,CAC1C,KAAK,KAAOA,CACd,EAkCArL,EAAK,QAAQ,UAAU,MAAQ,SAAUW,EAAWgL,EAAY,CAC9D,GAAI,KAAK,KAAKhL,CAAS,EACrB,MAAM,IAAI,WAAY,UAAYA,EAAY,kCAAkC,EAGlF,KAAK,QAAQA,GAAagL,GAAc,CAAC,CAC3C,EAUA3L,EAAK,QAAQ,UAAU,EAAI,SAAU4L,EAAQ,CACvCA,EAAS,EACX,KAAK,GAAK,EACDA,EAAS,EAClB,KAAK,GAAK,EAEV,KAAK,GAAKA,CAEd,EASA5L,EAAK,QAAQ,UAAU,GAAK,SAAU4L,EAAQ,CAC5C,KAAK,IAAMA,CACb,EAmBA5L,EAAK,QAAQ,UAAU,IAAM,SAAU6L,EAAKF,EAAY,CACtD,IAAIjL,EAASmL,EAAI,KAAK,MAClBC,EAAS,OAAO,KAAK,KAAK,OAAO,EAErC,KAAK,WAAWpL,GAAUiL,GAAc,CAAC,EACzC,KAAK,eAAiB,EAEtB,QAAS1K,EAAI,EAAGA,EAAI6K,EAAO,OAAQ7K,IAAK,CACtC,IAAIN,EAAYmL,EAAO7K,GACnB8K,EAAY,KAAK,QAAQpL,GAAW,UACpCoJ,EAAQgC,EAAYA,EAAUF,CAAG,EAAIA,EAAIlL,GACzCsB,EAAS,KAAK,UAAU8H,EAAO,CAC7B,OAAQ,CAACpJ,CAAS,CACpB,CAAC,EACD8I,EAAQ,KAAK,SAAS,IAAIxH,CAAM,EAChClB,EAAW,IAAIf,EAAK,SAAUU,EAAQC,CAAS,EAC/CqL,EAAa,OAAO,OAAO,IAAI,EAEnC,KAAK,qBAAqBjL,GAAYiL,EACtC,KAAK,aAAajL,GAAY,EAG9B,KAAK,aAAaA,IAAa0I,EAAM,OAGrC,QAASvG,EAAI,EAAGA,EAAIuG,EAAM,OAAQvG,IAAK,CACrC,IAAI0G,EAAOH,EAAMvG,GAUjB,GARI8I,EAAWpC,IAAS,OACtBoC,EAAWpC,GAAQ,GAGrBoC,EAAWpC,IAAS,EAIhB,KAAK,cAAcA,IAAS,KAAW,CACzC,IAAIpI,EAAU,OAAO,OAAO,IAAI,EAChCA,EAAQ,OAAY,KAAK,UACzB,KAAK,WAAa,EAElB,QAAS4B,EAAI,EAAGA,EAAI0I,EAAO,OAAQ1I,IACjC5B,EAAQsK,EAAO1I,IAAM,OAAO,OAAO,IAAI,EAGzC,KAAK,cAAcwG,GAAQpI,CAC7B,CAGI,KAAK,cAAcoI,GAAMjJ,GAAWD,IAAW,OACjD,KAAK,cAAckJ,GAAMjJ,GAAWD,GAAU,OAAO,OAAO,IAAI,GAKlE,QAAS4J,EAAI,EAAGA,EAAI,KAAK,kBAAkB,OAAQA,IAAK,CACtD,IAAI2B,EAAc,KAAK,kBAAkB3B,GACrCzI,EAAW+H,EAAK,SAASqC,GAEzB,KAAK,cAAcrC,GAAMjJ,GAAWD,GAAQuL,IAAgB,OAC9D,KAAK,cAAcrC,GAAMjJ,GAAWD,GAAQuL,GAAe,CAAC,GAG9D,KAAK,cAAcrC,GAAMjJ,GAAWD,GAAQuL,GAAa,KAAKpK,CAAQ,CACxE,CACF,CAEF,CACF,EAOA7B,EAAK,QAAQ,UAAU,6BAA+B,UAAY,CAOhE,QALIkM,EAAY,OAAO,KAAK,KAAK,YAAY,EACzCC,EAAiBD,EAAU,OAC3BE,EAAc,CAAC,EACfC,EAAqB,CAAC,EAEjBpL,EAAI,EAAGA,EAAIkL,EAAgBlL,IAAK,CACvC,IAAIF,EAAWf,EAAK,SAAS,WAAWkM,EAAUjL,EAAE,EAChD8I,EAAQhJ,EAAS,UAErBsL,EAAmBtC,KAAWsC,EAAmBtC,GAAS,GAC1DsC,EAAmBtC,IAAU,EAE7BqC,EAAYrC,KAAWqC,EAAYrC,GAAS,GAC5CqC,EAAYrC,IAAU,KAAK,aAAahJ,EAC1C,CAIA,QAFI+K,EAAS,OAAO,KAAK,KAAK,OAAO,EAE5B7K,EAAI,EAAGA,EAAI6K,EAAO,OAAQ7K,IAAK,CACtC,IAAIN,EAAYmL,EAAO7K,GACvBmL,EAAYzL,GAAayL,EAAYzL,GAAa0L,EAAmB1L,EACvE,CAEA,KAAK,mBAAqByL,CAC5B,EAOApM,EAAK,QAAQ,UAAU,mBAAqB,UAAY,CAMtD,QALIoL,EAAe,CAAC,EAChBc,EAAY,OAAO,KAAK,KAAK,oBAAoB,EACjDI,EAAkBJ,EAAU,OAC5BK,EAAe,OAAO,OAAO,IAAI,EAE5BtL,EAAI,EAAGA,EAAIqL,EAAiBrL,IAAK,CAaxC,QAZIF,EAAWf,EAAK,SAAS,WAAWkM,EAAUjL,EAAE,EAChDN,EAAYI,EAAS,UACrByL,EAAc,KAAK,aAAazL,GAChCgK,EAAc,IAAI/K,EAAK,OACvByM,EAAkB,KAAK,qBAAqB1L,GAC5C0I,EAAQ,OAAO,KAAKgD,CAAe,EACnCC,EAAcjD,EAAM,OAGpBkD,EAAa,KAAK,QAAQhM,GAAW,OAAS,EAC9CiM,EAAW,KAAK,WAAW7L,EAAS,QAAQ,OAAS,EAEhDmC,EAAI,EAAGA,EAAIwJ,EAAaxJ,IAAK,CACpC,IAAI0G,EAAOH,EAAMvG,GACb2J,EAAKJ,EAAgB7C,GACrBK,EAAY,KAAK,cAAcL,GAAM,OACrCkD,EAAK9B,EAAO+B,EAEZR,EAAa3C,KAAU,QACzBkD,EAAM9M,EAAK,IAAI,KAAK,cAAc4J,GAAO,KAAK,aAAa,EAC3D2C,EAAa3C,GAAQkD,GAErBA,EAAMP,EAAa3C,GAGrBoB,EAAQ8B,IAAQ,KAAK,IAAM,GAAKD,IAAO,KAAK,KAAO,EAAI,KAAK,GAAK,KAAK,IAAML,EAAc,KAAK,mBAAmB7L,KAAekM,GACjI7B,GAAS2B,EACT3B,GAAS4B,EACTG,EAAqB,KAAK,MAAM/B,EAAQ,GAAI,EAAI,IAQhDD,EAAY,OAAOd,EAAW8C,CAAkB,CAClD,CAEA3B,EAAarK,GAAYgK,CAC3B,CAEA,KAAK,aAAeK,CACtB,EAOApL,EAAK,QAAQ,UAAU,eAAiB,UAAY,CAClD,KAAK,SAAWA,EAAK,SAAS,UAC5B,OAAO,KAAK,KAAK,aAAa,EAAE,KAAK,CACvC,CACF,EAUAA,EAAK,QAAQ,UAAU,MAAQ,UAAY,CACzC,YAAK,6BAA6B,EAClC,KAAK,mBAAmB,EACxB,KAAK,eAAe,EAEb,IAAIA,EAAK,MAAM,CACpB,cAAe,KAAK,cACpB,aAAc,KAAK,aACnB,SAAU,KAAK,SACf,OAAQ,OAAO,KAAK,KAAK,OAAO,EAChC,SAAU,KAAK,cACjB,CAAC,CACH,EAgBAA,EAAK,QAAQ,UAAU,IAAM,SAAU8B,EAAI,CACzC,IAAIkL,EAAO,MAAM,UAAU,MAAM,KAAK,UAAW,CAAC,EAClDA,EAAK,QAAQ,IAAI,EACjBlL,EAAG,MAAM,KAAMkL,CAAI,CACrB,EAaAhN,EAAK,UAAY,SAAU4J,EAAMG,EAAOlI,EAAU,CAShD,QARIoL,EAAiB,OAAO,OAAO,IAAI,EACnCC,EAAe,OAAO,KAAKrL,GAAY,CAAC,CAAC,EAOpCZ,EAAI,EAAGA,EAAIiM,EAAa,OAAQjM,IAAK,CAC5C,IAAIT,EAAM0M,EAAajM,GACvBgM,EAAezM,GAAOqB,EAASrB,GAAK,MAAM,CAC5C,CAEA,KAAK,SAAW,OAAO,OAAO,IAAI,EAE9BoJ,IAAS,SACX,KAAK,SAASA,GAAQ,OAAO,OAAO,IAAI,EACxC,KAAK,SAASA,GAAMG,GAASkD,EAEjC,EAWAjN,EAAK,UAAU,UAAU,QAAU,SAAUmN,EAAgB,CAG3D,QAFI1D,EAAQ,OAAO,KAAK0D,EAAe,QAAQ,EAEtClM,EAAI,EAAGA,EAAIwI,EAAM,OAAQxI,IAAK,CACrC,IAAI2I,EAAOH,EAAMxI,GACb6K,EAAS,OAAO,KAAKqB,EAAe,SAASvD,EAAK,EAElD,KAAK,SAASA,IAAS,OACzB,KAAK,SAASA,GAAQ,OAAO,OAAO,IAAI,GAG1C,QAAS1G,EAAI,EAAGA,EAAI4I,EAAO,OAAQ5I,IAAK,CACtC,IAAI6G,EAAQ+B,EAAO5I,GACf3C,EAAO,OAAO,KAAK4M,EAAe,SAASvD,GAAMG,EAAM,EAEvD,KAAK,SAASH,GAAMG,IAAU,OAChC,KAAK,SAASH,GAAMG,GAAS,OAAO,OAAO,IAAI,GAGjD,QAAS3G,EAAI,EAAGA,EAAI7C,EAAK,OAAQ6C,IAAK,CACpC,IAAI5C,EAAMD,EAAK6C,GAEX,KAAK,SAASwG,GAAMG,GAAOvJ,IAAQ,KACrC,KAAK,SAASoJ,GAAMG,GAAOvJ,GAAO2M,EAAe,SAASvD,GAAMG,GAAOvJ,GAEvE,KAAK,SAASoJ,GAAMG,GAAOvJ,GAAO,KAAK,SAASoJ,GAAMG,GAAOvJ,GAAK,OAAO2M,EAAe,SAASvD,GAAMG,GAAOvJ,EAAI,CAGtH,CACF,CACF,CACF,EASAR,EAAK,UAAU,UAAU,IAAM,SAAU4J,EAAMG,EAAOlI,EAAU,CAC9D,GAAI,EAAE+H,KAAQ,KAAK,UAAW,CAC5B,KAAK,SAASA,GAAQ,OAAO,OAAO,IAAI,EACxC,KAAK,SAASA,GAAMG,GAASlI,EAC7B,MACF,CAEA,GAAI,EAAEkI,KAAS,KAAK,SAASH,IAAQ,CACnC,KAAK,SAASA,GAAMG,GAASlI,EAC7B,MACF,CAIA,QAFIqL,EAAe,OAAO,KAAKrL,CAAQ,EAE9BZ,EAAI,EAAGA,EAAIiM,EAAa,OAAQjM,IAAK,CAC5C,IAAIT,EAAM0M,EAAajM,GAEnBT,KAAO,KAAK,SAASoJ,GAAMG,GAC7B,KAAK,SAASH,GAAMG,GAAOvJ,GAAO,KAAK,SAASoJ,GAAMG,GAAOvJ,GAAK,OAAOqB,EAASrB,EAAI,EAEtF,KAAK,SAASoJ,GAAMG,GAAOvJ,GAAOqB,EAASrB,EAE/C,CACF,EAYAR,EAAK,MAAQ,SAAUoN,EAAW,CAChC,KAAK,QAAU,CAAC,EAChB,KAAK,UAAYA,CACnB,EA0BApN,EAAK,MAAM,SAAW,IAAI,OAAQ,GAAG,EACrCA,EAAK,MAAM,SAAS,KAAO,EAC3BA,EAAK,MAAM,SAAS,QAAU,EAC9BA,EAAK,MAAM,SAAS,SAAW,EAa/BA,EAAK,MAAM,SAAW,CAIpB,SAAU,EAMV,SAAU,EAMV,WAAY,CACd,EAyBAA,EAAK,MAAM,UAAU,OAAS,SAAUkH,EAAQ,CAC9C,MAAM,WAAYA,IAChBA,EAAO,OAAS,KAAK,WAGjB,UAAWA,IACfA,EAAO,MAAQ,GAGX,gBAAiBA,IACrBA,EAAO,YAAc,IAGjB,aAAcA,IAClBA,EAAO,SAAWlH,EAAK,MAAM,SAAS,MAGnCkH,EAAO,SAAWlH,EAAK,MAAM,SAAS,SAAakH,EAAO,KAAK,OAAO,CAAC,GAAKlH,EAAK,MAAM,WAC1FkH,EAAO,KAAO,IAAMA,EAAO,MAGxBA,EAAO,SAAWlH,EAAK,MAAM,SAAS,UAAckH,EAAO,KAAK,MAAM,EAAE,GAAKlH,EAAK,MAAM,WAC3FkH,EAAO,KAAO,GAAKA,EAAO,KAAO,KAG7B,aAAcA,IAClBA,EAAO,SAAWlH,EAAK,MAAM,SAAS,UAGxC,KAAK,QAAQ,KAAKkH,CAAM,EAEjB,IACT,EASAlH,EAAK,MAAM,UAAU,UAAY,UAAY,CAC3C,QAASiB,EAAI,EAAGA,EAAI,KAAK,QAAQ,OAAQA,IACvC,GAAI,KAAK,QAAQA,GAAG,UAAYjB,EAAK,MAAM,SAAS,WAClD,MAAO,GAIX,MAAO,EACT,EA4BAA,EAAK,MAAM,UAAU,KAAO,SAAU4J,EAAMyD,EAAS,CACnD,GAAI,MAAM,QAAQzD,CAAI,EACpB,OAAAA,EAAK,QAAQ,SAAU7H,EAAG,CAAE,KAAK,KAAKA,EAAG/B,EAAK,MAAM,MAAMqN,CAAO,CAAC,CAAE,EAAG,IAAI,EACpE,KAGT,IAAInG,EAASmG,GAAW,CAAC,EACzB,OAAAnG,EAAO,KAAO0C,EAAK,SAAS,EAE5B,KAAK,OAAO1C,CAAM,EAEX,IACT,EACAlH,EAAK,gBAAkB,SAAUI,EAASmD,EAAOC,EAAK,CACpD,KAAK,KAAO,kBACZ,KAAK,QAAUpD,EACf,KAAK,MAAQmD,EACb,KAAK,IAAMC,CACb,EAEAxD,EAAK,gBAAgB,UAAY,IAAI,MACrCA,EAAK,WAAa,SAAU4B,EAAK,CAC/B,KAAK,QAAU,CAAC,EAChB,KAAK,IAAMA,EACX,KAAK,OAASA,EAAI,OAClB,KAAK,IAAM,EACX,KAAK,MAAQ,EACb,KAAK,oBAAsB,CAAC,CAC9B,EAEA5B,EAAK,WAAW,UAAU,IAAM,UAAY,CAG1C,QAFIsN,EAAQtN,EAAK,WAAW,QAErBsN,GACLA,EAAQA,EAAM,IAAI,CAEtB,EAEAtN,EAAK,WAAW,UAAU,YAAc,UAAY,CAKlD,QAJIuN,EAAY,CAAC,EACbpL,EAAa,KAAK,MAClBD,EAAW,KAAK,IAEX,EAAI,EAAG,EAAI,KAAK,oBAAoB,OAAQ,IACnDA,EAAW,KAAK,oBAAoB,GACpCqL,EAAU,KAAK,KAAK,IAAI,MAAMpL,EAAYD,CAAQ,CAAC,EACnDC,EAAaD,EAAW,EAG1B,OAAAqL,EAAU,KAAK,KAAK,IAAI,MAAMpL,EAAY,KAAK,GAAG,CAAC,EACnD,KAAK,oBAAoB,OAAS,EAE3BoL,EAAU,KAAK,EAAE,CAC1B,EAEAvN,EAAK,WAAW,UAAU,KAAO,SAAUwN,EAAM,CAC/C,KAAK,QAAQ,KAAK,CAChB,KAAMA,EACN,IAAK,KAAK,YAAY,EACtB,MAAO,KAAK,MACZ,IAAK,KAAK,GACZ,CAAC,EAED,KAAK,MAAQ,KAAK,GACpB,EAEAxN,EAAK,WAAW,UAAU,gBAAkB,UAAY,CACtD,KAAK,oBAAoB,KAAK,KAAK,IAAM,CAAC,EAC1C,KAAK,KAAO,CACd,EAEAA,EAAK,WAAW,UAAU,KAAO,UAAY,CAC3C,GAAI,KAAK,KAAO,KAAK,OACnB,OAAOA,EAAK,WAAW,IAGzB,IAAIoC,EAAO,KAAK,IAAI,OAAO,KAAK,GAAG,EACnC,YAAK,KAAO,EACLA,CACT,EAEApC,EAAK,WAAW,UAAU,MAAQ,UAAY,CAC5C,OAAO,KAAK,IAAM,KAAK,KACzB,EAEAA,EAAK,WAAW,UAAU,OAAS,UAAY,CACzC,KAAK,OAAS,KAAK,MACrB,KAAK,KAAO,GAGd,KAAK,MAAQ,KAAK,GACpB,EAEAA,EAAK,WAAW,UAAU,OAAS,UAAY,CAC7C,KAAK,KAAO,CACd,EAEAA,EAAK,WAAW,UAAU,eAAiB,UAAY,CACrD,IAAIoC,EAAMqL,EAEV,GACErL,EAAO,KAAK,KAAK,EACjBqL,EAAWrL,EAAK,WAAW,CAAC,QACrBqL,EAAW,IAAMA,EAAW,IAEjCrL,GAAQpC,EAAK,WAAW,KAC1B,KAAK,OAAO,CAEhB,EAEAA,EAAK,WAAW,UAAU,KAAO,UAAY,CAC3C,OAAO,KAAK,IAAM,KAAK,MACzB,EAEAA,EAAK,WAAW,IAAM,MACtBA,EAAK,WAAW,MAAQ,QACxBA,EAAK,WAAW,KAAO,OACvBA,EAAK,WAAW,cAAgB,gBAChCA,EAAK,WAAW,MAAQ,QACxBA,EAAK,WAAW,SAAW,WAE3BA,EAAK,WAAW,SAAW,SAAU0N,EAAO,CAC1C,OAAAA,EAAM,OAAO,EACbA,EAAM,KAAK1N,EAAK,WAAW,KAAK,EAChC0N,EAAM,OAAO,EACN1N,EAAK,WAAW,OACzB,EAEAA,EAAK,WAAW,QAAU,SAAU0N,EAAO,CAQzC,GAPIA,EAAM,MAAM,EAAI,IAClBA,EAAM,OAAO,EACbA,EAAM,KAAK1N,EAAK,WAAW,IAAI,GAGjC0N,EAAM,OAAO,EAETA,EAAM,KAAK,EACb,OAAO1N,EAAK,WAAW,OAE3B,EAEAA,EAAK,WAAW,gBAAkB,SAAU0N,EAAO,CACjD,OAAAA,EAAM,OAAO,EACbA,EAAM,eAAe,EACrBA,EAAM,KAAK1N,EAAK,WAAW,aAAa,EACjCA,EAAK,WAAW,OACzB,EAEAA,EAAK,WAAW,SAAW,SAAU0N,EAAO,CAC1C,OAAAA,EAAM,OAAO,EACbA,EAAM,eAAe,EACrBA,EAAM,KAAK1N,EAAK,WAAW,KAAK,EACzBA,EAAK,WAAW,OACzB,EAEAA,EAAK,WAAW,OAAS,SAAU0N,EAAO,CACpCA,EAAM,MAAM,EAAI,GAClBA,EAAM,KAAK1N,EAAK,WAAW,IAAI,CAEnC,EAaAA,EAAK,WAAW,cAAgBA,EAAK,UAAU,UAE/CA,EAAK,WAAW,QAAU,SAAU0N,EAAO,CACzC,OAAa,CACX,IAAItL,EAAOsL,EAAM,KAAK,EAEtB,GAAItL,GAAQpC,EAAK,WAAW,IAC1B,OAAOA,EAAK,WAAW,OAIzB,GAAIoC,EAAK,WAAW,CAAC,GAAK,GAAI,CAC5BsL,EAAM,gBAAgB,EACtB,QACF,CAEA,GAAItL,GAAQ,IACV,OAAOpC,EAAK,WAAW,SAGzB,GAAIoC,GAAQ,IACV,OAAAsL,EAAM,OAAO,EACTA,EAAM,MAAM,EAAI,GAClBA,EAAM,KAAK1N,EAAK,WAAW,IAAI,EAE1BA,EAAK,WAAW,gBAGzB,GAAIoC,GAAQ,IACV,OAAAsL,EAAM,OAAO,EACTA,EAAM,MAAM,EAAI,GAClBA,EAAM,KAAK1N,EAAK,WAAW,IAAI,EAE1BA,EAAK,WAAW,SAczB,GARIoC,GAAQ,KAAOsL,EAAM,MAAM,IAAM,GAQjCtL,GAAQ,KAAOsL,EAAM,MAAM,IAAM,EACnC,OAAAA,EAAM,KAAK1N,EAAK,WAAW,QAAQ,EAC5BA,EAAK,WAAW,QAGzB,GAAIoC,EAAK,MAAMpC,EAAK,WAAW,aAAa,EAC1C,OAAOA,EAAK,WAAW,OAE3B,CACF,EAEAA,EAAK,YAAc,SAAU4B,EAAKsH,EAAO,CACvC,KAAK,MAAQ,IAAIlJ,EAAK,WAAY4B,CAAG,EACrC,KAAK,MAAQsH,EACb,KAAK,cAAgB,CAAC,EACtB,KAAK,UAAY,CACnB,EAEAlJ,EAAK,YAAY,UAAU,MAAQ,UAAY,CAC7C,KAAK,MAAM,IAAI,EACf,KAAK,QAAU,KAAK,MAAM,QAI1B,QAFIsN,EAAQtN,EAAK,YAAY,YAEtBsN,GACLA,EAAQA,EAAM,IAAI,EAGpB,OAAO,KAAK,KACd,EAEAtN,EAAK,YAAY,UAAU,WAAa,UAAY,CAClD,OAAO,KAAK,QAAQ,KAAK,UAC3B,EAEAA,EAAK,YAAY,UAAU,cAAgB,UAAY,CACrD,IAAI2N,EAAS,KAAK,WAAW,EAC7B,YAAK,WAAa,EACXA,CACT,EAEA3N,EAAK,YAAY,UAAU,WAAa,UAAY,CAClD,IAAI4N,EAAkB,KAAK,cAC3B,KAAK,MAAM,OAAOA,CAAe,EACjC,KAAK,cAAgB,CAAC,CACxB,EAEA5N,EAAK,YAAY,YAAc,SAAUmJ,EAAQ,CAC/C,IAAIwE,EAASxE,EAAO,WAAW,EAE/B,GAAIwE,GAAU,KAId,OAAQA,EAAO,WACR3N,EAAK,WAAW,SACnB,OAAOA,EAAK,YAAY,mBACrBA,EAAK,WAAW,MACnB,OAAOA,EAAK,YAAY,gBACrBA,EAAK,WAAW,KACnB,OAAOA,EAAK,YAAY,kBAExB,IAAI6N,EAAe,4CAA8CF,EAAO,KAExE,MAAIA,EAAO,IAAI,QAAU,IACvBE,GAAgB,gBAAkBF,EAAO,IAAM,KAG3C,IAAI3N,EAAK,gBAAiB6N,EAAcF,EAAO,MAAOA,EAAO,GAAG,EAE5E,EAEA3N,EAAK,YAAY,cAAgB,SAAUmJ,EAAQ,CACjD,IAAIwE,EAASxE,EAAO,cAAc,EAElC,GAAIwE,GAAU,KAId,QAAQA,EAAO,SACR,IACHxE,EAAO,cAAc,SAAWnJ,EAAK,MAAM,SAAS,WACpD,UACG,IACHmJ,EAAO,cAAc,SAAWnJ,EAAK,MAAM,SAAS,SACpD,cAEA,IAAI6N,EAAe,kCAAoCF,EAAO,IAAM,IACpE,MAAM,IAAI3N,EAAK,gBAAiB6N,EAAcF,EAAO,MAAOA,EAAO,GAAG,EAG1E,IAAIG,EAAa3E,EAAO,WAAW,EAEnC,GAAI2E,GAAc,KAAW,CAC3B,IAAID,EAAe,yCACnB,MAAM,IAAI7N,EAAK,gBAAiB6N,EAAcF,EAAO,MAAOA,EAAO,GAAG,CACxE,CAEA,OAAQG,EAAW,WACZ9N,EAAK,WAAW,MACnB,OAAOA,EAAK,YAAY,gBACrBA,EAAK,WAAW,KACnB,OAAOA,EAAK,YAAY,kBAExB,IAAI6N,EAAe,mCAAqCC,EAAW,KAAO,IAC1E,MAAM,IAAI9N,EAAK,gBAAiB6N,EAAcC,EAAW,MAAOA,EAAW,GAAG,GAEpF,EAEA9N,EAAK,YAAY,WAAa,SAAUmJ,EAAQ,CAC9C,IAAIwE,EAASxE,EAAO,cAAc,EAElC,GAAIwE,GAAU,KAId,IAAIxE,EAAO,MAAM,UAAU,QAAQwE,EAAO,GAAG,GAAK,GAAI,CACpD,IAAII,EAAiB5E,EAAO,MAAM,UAAU,IAAI,SAAU6E,EAAG,CAAE,MAAO,IAAMA,EAAI,GAAI,CAAC,EAAE,KAAK,IAAI,EAC5FH,EAAe,uBAAyBF,EAAO,IAAM,uBAAyBI,EAElF,MAAM,IAAI/N,EAAK,gBAAiB6N,EAAcF,EAAO,MAAOA,EAAO,GAAG,CACxE,CAEAxE,EAAO,cAAc,OAAS,CAACwE,EAAO,GAAG,EAEzC,IAAIG,EAAa3E,EAAO,WAAW,EAEnC,GAAI2E,GAAc,KAAW,CAC3B,IAAID,EAAe,gCACnB,MAAM,IAAI7N,EAAK,gBAAiB6N,EAAcF,EAAO,MAAOA,EAAO,GAAG,CACxE,CAEA,OAAQG,EAAW,WACZ9N,EAAK,WAAW,KACnB,OAAOA,EAAK,YAAY,kBAExB,IAAI6N,EAAe,0BAA4BC,EAAW,KAAO,IACjE,MAAM,IAAI9N,EAAK,gBAAiB6N,EAAcC,EAAW,MAAOA,EAAW,GAAG,GAEpF,EAEA9N,EAAK,YAAY,UAAY,SAAUmJ,EAAQ,CAC7C,IAAIwE,EAASxE,EAAO,cAAc,EAElC,GAAIwE,GAAU,KAId,CAAAxE,EAAO,cAAc,KAAOwE,EAAO,IAAI,YAAY,EAE/CA,EAAO,IAAI,QAAQ,GAAG,GAAK,KAC7BxE,EAAO,cAAc,YAAc,IAGrC,IAAI2E,EAAa3E,EAAO,WAAW,EAEnC,GAAI2E,GAAc,KAAW,CAC3B3E,EAAO,WAAW,EAClB,MACF,CAEA,OAAQ2E,EAAW,WACZ9N,EAAK,WAAW,KACnB,OAAAmJ,EAAO,WAAW,EACXnJ,EAAK,YAAY,eACrBA,EAAK,WAAW,MACnB,OAAAmJ,EAAO,WAAW,EACXnJ,EAAK,YAAY,gBACrBA,EAAK,WAAW,cACnB,OAAOA,EAAK,YAAY,uBACrBA,EAAK,WAAW,MACnB,OAAOA,EAAK,YAAY,gBACrBA,EAAK,WAAW,SACnB,OAAAmJ,EAAO,WAAW,EACXnJ,EAAK,YAAY,sBAExB,IAAI6N,EAAe,2BAA6BC,EAAW,KAAO,IAClE,MAAM,IAAI9N,EAAK,gBAAiB6N,EAAcC,EAAW,MAAOA,EAAW,GAAG,GAEpF,EAEA9N,EAAK,YAAY,kBAAoB,SAAUmJ,EAAQ,CACrD,IAAIwE,EAASxE,EAAO,cAAc,EAElC,GAAIwE,GAAU,KAId,KAAIxG,EAAe,SAASwG,EAAO,IAAK,EAAE,EAE1C,GAAI,MAAMxG,CAAY,EAAG,CACvB,IAAI0G,EAAe,gCACnB,MAAM,IAAI7N,EAAK,gBAAiB6N,EAAcF,EAAO,MAAOA,EAAO,GAAG,CACxE,CAEAxE,EAAO,cAAc,aAAehC,EAEpC,IAAI2G,EAAa3E,EAAO,WAAW,EAEnC,GAAI2E,GAAc,KAAW,CAC3B3E,EAAO,WAAW,EAClB,MACF,CAEA,OAAQ2E,EAAW,WACZ9N,EAAK,WAAW,KACnB,OAAAmJ,EAAO,WAAW,EACXnJ,EAAK,YAAY,eACrBA,EAAK,WAAW,MACnB,OAAAmJ,EAAO,WAAW,EACXnJ,EAAK,YAAY,gBACrBA,EAAK,WAAW,cACnB,OAAOA,EAAK,YAAY,uBACrBA,EAAK,WAAW,MACnB,OAAOA,EAAK,YAAY,gBACrBA,EAAK,WAAW,SACnB,OAAAmJ,EAAO,WAAW,EACXnJ,EAAK,YAAY,sBAExB,IAAI6N,EAAe,2BAA6BC,EAAW,KAAO,IAClE,MAAM,IAAI9N,EAAK,gBAAiB6N,EAAcC,EAAW,MAAOA,EAAW,GAAG,GAEpF,EAEA9N,EAAK,YAAY,WAAa,SAAUmJ,EAAQ,CAC9C,IAAIwE,EAASxE,EAAO,cAAc,EAElC,GAAIwE,GAAU,KAId,KAAIM,EAAQ,SAASN,EAAO,IAAK,EAAE,EAEnC,GAAI,MAAMM,CAAK,EAAG,CAChB,IAAIJ,EAAe,wBACnB,MAAM,IAAI7N,EAAK,gBAAiB6N,EAAcF,EAAO,MAAOA,EAAO,GAAG,CACxE,CAEAxE,EAAO,cAAc,MAAQ8E,EAE7B,IAAIH,EAAa3E,EAAO,WAAW,EAEnC,GAAI2E,GAAc,KAAW,CAC3B3E,EAAO,WAAW,EAClB,MACF,CAEA,OAAQ2E,EAAW,WACZ9N,EAAK,WAAW,KACnB,OAAAmJ,EAAO,WAAW,EACXnJ,EAAK,YAAY,eACrBA,EAAK,WAAW,MACnB,OAAAmJ,EAAO,WAAW,EACXnJ,EAAK,YAAY,gBACrBA,EAAK,WAAW,cACnB,OAAOA,EAAK,YAAY,uBACrBA,EAAK,WAAW,MACnB,OAAOA,EAAK,YAAY,gBACrBA,EAAK,WAAW,SACnB,OAAAmJ,EAAO,WAAW,EACXnJ,EAAK,YAAY,sBAExB,IAAI6N,EAAe,2BAA6BC,EAAW,KAAO,IAClE,MAAM,IAAI9N,EAAK,gBAAiB6N,EAAcC,EAAW,MAAOA,EAAW,GAAG,GAEpF,EAMI,SAAU1G,EAAM8G,EAAS,CACrB,OAAO,QAAW,YAAc,OAAO,IAEzC,OAAOA,CAAO,EACL,OAAOpO,IAAY,SAM5BC,GAAO,QAAUmO,EAAQ,EAGzB9G,EAAK,KAAO8G,EAAQ,CAExB,EAAE,KAAM,UAAY,CAMlB,OAAOlO,CACT,CAAC,CACH,GAAG,ICl5GH,IAAAmO,EAAAC,EAAA,CAAAC,GAAAC,KAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAeA,IAAIC,GAAkB,UAOtBD,GAAO,QAAUE,GAUjB,SAASA,GAAWC,EAAQ,CAC1B,IAAIC,EAAM,GAAKD,EACXE,EAAQJ,GAAgB,KAAKG,CAAG,EAEpC,GAAI,CAACC,EACH,OAAOD,EAGT,IAAIE,EACAC,EAAO,GACPC,EAAQ,EACRC,EAAY,EAEhB,IAAKD,EAAQH,EAAM,MAAOG,EAAQJ,EAAI,OAAQI,IAAS,CACrD,OAAQJ,EAAI,WAAWI,CAAK,OACrB,IACHF,EAAS,SACT,UACG,IACHA,EAAS,QACT,UACG,IACHA,EAAS,QACT,UACG,IACHA,EAAS,OACT,UACG,IACHA,EAAS,OACT,cAEA,SAGAG,IAAcD,IAChBD,GAAQH,EAAI,UAAUK,EAAWD,CAAK,GAGxCC,EAAYD,EAAQ,EACpBD,GAAQD,CACV,CAEA,OAAOG,IAAcD,EACjBD,EAAOH,EAAI,UAAUK,EAAWD,CAAK,EACrCD,CACN,ICvDA,IAAAG,GAAiB,QCKZ,OAAO,UACV,OAAO,QAAU,SAAUC,EAAa,CACtC,IAAMC,EAA2B,CAAC,EAClC,QAAWC,KAAO,OAAO,KAAKF,CAAG,EAE/BC,EAAK,KAAK,CAACC,EAAKF,EAAIE,EAAI,CAAC,EAG3B,OAAOD,CACT,GAGG,OAAO,SACV,OAAO,OAAS,SAAUD,EAAa,CACrC,IAAMC,EAAiB,CAAC,EACxB,QAAWC,KAAO,OAAO,KAAKF,CAAG,EAE/BC,EAAK,KAAKD,EAAIE,EAAI,EAGpB,OAAOD,CACT,GAKE,OAAO,SAAY,cAGhB,QAAQ,UAAU,WACrB,QAAQ,UAAU,SAAW,SAC3BE,EAA8BC,EACxB,CACF,OAAOD,GAAM,UACf,KAAK,WAAaA,EAAE,KACpB,KAAK,UAAYA,EAAE,MAEnB,KAAK,WAAaA,EAClB,KAAK,UAAYC,EAErB,GAGG,QAAQ,UAAU,cACrB,QAAQ,UAAU,YAAc,YAC3BC,EACG,CACN,IAAMC,EAAS,KAAK,WACpB,GAAIA,EAAQ,CACND,EAAM,SAAW,GACnBC,EAAO,YAAY,IAAI,EAGzB,QAASC,EAAIF,EAAM,OAAS,EAAGE,GAAK,EAAGA,IAAK,CAC1C,IAAIC,EAAOH,EAAME,GACb,OAAOC,GAAS,SAClBA,EAAO,SAAS,eAAeA,CAAI,EAC5BA,EAAK,YACZA,EAAK,WAAW,YAAYA,CAAI,EAG7BD,EAGHD,EAAO,aAAa,KAAK,gBAAkBE,CAAI,EAF/CF,EAAO,aAAaE,EAAM,IAAI,CAGlC,CACF,CACF,ICxEJ,IAAAC,GAAuB,OAiChB,SAASC,GACdC,EACmB,CACnB,IAAMC,EAAY,IAAI,IAChBC,EAAY,IAAI,IACtB,QAAWC,KAAOH,EAAM,CACtB,GAAM,CAACI,EAAMC,CAAI,EAAIF,EAAI,SAAS,MAAM,GAAG,EAGrCG,EAAWH,EAAI,SACfI,EAAWJ,EAAI,MACfK,EAAWL,EAAI,KAGfM,KAAO,GAAAC,SAAWP,EAAI,IAAI,EAC7B,QAAQ,mBAAoB,EAAE,EAC9B,QAAQ,OAAQ,GAAG,EAGtB,GAAIE,EAAM,CACR,IAAMM,EAASV,EAAU,IAAIG,CAAI,EAG5BF,EAAQ,IAAIS,CAAM,EASrBV,EAAU,IAAIK,EAAU,CACtB,SAAAA,EACA,MAAAC,EACA,KAAAE,EACA,OAAAE,CACF,CAAC,GAbDA,EAAO,MAAQR,EAAI,MACnBQ,EAAO,KAAQF,EAGfP,EAAQ,IAAIS,CAAM,EAatB,MACEV,EAAU,IAAIK,EAAUM,EAAA,CACtB,SAAAN,EACA,MAAAC,EACA,KAAAE,GACGD,GAAQ,CAAE,KAAAA,CAAK,EACnB,CAEL,CACA,OAAOP,CACT,CCpFA,IAAAY,GAAuB,OAsChB,SAASC,GACdC,EAA2BC,EACD,CAC1B,IAAMC,EAAY,IAAI,OAAOF,EAAO,UAAW,KAAK,EAC9CG,EAAY,CAACC,EAAYC,EAAcC,IACpC,GAAGD,4BAA+BC,WAI3C,OAAQC,GAAkB,CACxBA,EAAQA,EACL,QAAQ,gBAAiB,GAAG,EAC5B,KAAK,EAGR,IAAMC,EAAQ,IAAI,OAAO,MAAMR,EAAO,cACpCO,EACG,QAAQ,uBAAwB,MAAM,EACtC,QAAQL,EAAW,GAAG,KACtB,KAAK,EAGV,OAAOO,IACLR,KACI,GAAAS,SAAWD,CAAK,EAChBA,GAED,QAAQD,EAAOL,CAAS,EACxB,QAAQ,8BAA+B,IAAI,CAClD,CACF,CCtCO,SAASQ,GACdC,EACqB,CACrB,IAAMC,EAAS,IAAK,KAAa,MAAM,CAAC,QAAS,MAAM,CAAC,EAIxD,OAHe,IAAK,KAAa,YAAYD,EAAOC,CAAK,EAGlD,MAAM,EACNA,EAAM,OACf,CAUO,SAASC,GACdD,EAA4BE,EACV,CAzEpB,IAAAC,EA0EE,IAAMC,EAAU,IAAI,IAAuBJ,CAAK,EAG1CK,EAA2B,CAAC,EAClC,QAASC,EAAI,EAAGA,EAAIJ,EAAM,OAAQI,IAChC,QAAWC,KAAUH,EACfF,EAAMI,GAAG,WAAWC,EAAO,IAAI,IACjCF,EAAOE,EAAO,MAAQ,GACtBH,EAAQ,OAAOG,CAAM,GAI3B,QAAWA,KAAUH,GACfD,EAAA,KAAK,iBAAL,MAAAA,EAAA,UAAsBI,EAAO,QAC/BF,EAAOE,EAAO,MAAQ,IAG1B,OAAOF,CACT,CC2BA,SAASG,GAAWC,EAAaC,EAAuB,CACtD,GAAM,CAACC,EAAGC,CAAC,EAAI,CAAC,IAAI,IAAIH,CAAC,EAAG,IAAI,IAAIC,CAAC,CAAC,EACtC,MAAO,CACL,GAAG,IAAI,IAAI,CAAC,GAAGC,CAAC,EAAE,OAAOE,GAAS,CAACD,EAAE,IAAIC,CAAK,CAAC,CAAC,CAClD,CACF,CASO,IAAMC,EAAN,KAAa,CAgCX,YAAY,CAAE,OAAAC,EAAQ,KAAAC,EAAM,QAAAC,CAAQ,EAAgB,CACzD,KAAK,QAAUA,EAGf,KAAK,UAAYC,GAAuBF,CAAI,EAC5C,KAAK,UAAYG,GAAuBJ,EAAQ,EAAK,EAGrD,KAAK,UAAU,UAAY,IAAI,OAAOA,EAAO,SAAS,EAGtD,KAAK,MAAQ,KAAK,UAAY,CAGxBA,EAAO,KAAK,SAAW,GAAKA,EAAO,KAAK,KAAO,KACjD,KAAK,IAAK,KAAaA,EAAO,KAAK,GAAG,EAC7BA,EAAO,KAAK,OAAS,GAC9B,KAAK,IAAK,KAAa,cAAc,GAAGA,EAAO,IAAI,CAAC,EAItD,IAAMK,EAAMZ,GAAW,CACrB,UAAW,iBAAkB,SAC/B,EAAGS,EAAQ,QAAQ,EAGnB,QAAWI,KAAQN,EAAO,KAAK,IAAIO,GACjCA,IAAa,KAAO,KAAQ,KAAaA,EAC1C,EACC,QAAWC,KAAMH,EACf,KAAK,SAAS,OAAOC,EAAKE,EAAG,EAC7B,KAAK,eAAe,OAAOF,EAAKE,EAAG,EAKvC,KAAK,IAAI,UAAU,EAGnB,KAAK,MAAM,QAAS,CAAE,MAAO,GAAI,CAAC,EAClC,KAAK,MAAM,MAAM,EACjB,KAAK,MAAM,OAAQ,CAAE,MAAO,IAAK,UAAWC,GAAO,CACjD,GAAM,CAAE,KAAAC,EAAO,CAAC,CAAE,EAAID,EACtB,OAAOC,EAAK,OAAO,CAACC,EAAMC,IAAQ,CAChC,GAAGD,EACH,GAAG,KAAK,UAAUC,CAAG,CACvB,EAAG,CAAC,CAAiB,CACvB,CAAE,CAAC,EAGH,QAAWH,KAAOR,EAChB,KAAK,IAAIQ,EAAK,CAAE,MAAOA,EAAI,KAAM,CAAC,CACtC,CAAC,CACH,CAkBO,OAAOI,EAA6B,CACzC,GAAIA,EACF,GAAI,CACF,IAAMC,EAAY,KAAK,UAAUD,CAAK,EAGhCE,EAAUC,GAAiBH,CAAK,EACnC,OAAOI,GACNA,EAAO,WAAa,KAAK,MAAM,SAAS,UACzC,EAGGC,EAAS,KAAK,MAAM,OAAO,GAAGL,IAAQ,EAGzC,OAAyB,CAACM,EAAM,CAAE,IAAAC,EAAK,MAAAC,EAAO,UAAAC,CAAU,IAAM,CAC7D,IAAMC,EAAW,KAAK,UAAU,IAAIH,CAAG,EACvC,GAAI,OAAOG,GAAa,YAAa,CACnC,GAAM,CAAE,SAAAC,EAAU,MAAAC,EAAO,KAAAC,EAAM,KAAAhB,EAAM,OAAAiB,CAAO,EAAIJ,EAG1CK,EAAQC,GACZd,EACA,OAAO,KAAKO,EAAU,QAAQ,CAChC,EAGMQ,EAAQ,CAAC,CAACH,GAAS,CAAC,OAAO,OAAOC,CAAK,EAAE,MAAMG,GAAKA,CAAC,EAC3DZ,EAAK,KAAKa,EAAAC,EAAA,CACR,SAAAT,EACA,MAAOV,EAAUW,CAAK,EACtB,KAAOX,EAAUY,CAAI,GAClBhB,GAAQ,CAAE,KAAMA,EAAK,IAAII,CAAS,CAAE,GAJ/B,CAKR,MAAOO,GAAS,EAAIS,GACpB,MAAAF,CACF,EAAC,CACH,CACA,OAAOT,CACT,EAAG,CAAC,CAAC,EAGJ,KAAK,CAACzB,EAAGC,IAAMA,EAAE,MAAQD,EAAE,KAAK,EAGhC,OAAO,CAACwC,EAAOC,IAAW,CACzB,IAAMZ,EAAW,KAAK,UAAU,IAAIY,EAAO,QAAQ,EACnD,GAAI,OAAOZ,GAAa,YAAa,CACnC,IAAMH,EAAM,WAAYG,EACpBA,EAAS,OAAQ,SACjBA,EAAS,SACbW,EAAM,IAAId,EAAK,CAAC,GAAGc,EAAM,IAAId,CAAG,GAAK,CAAC,EAAGe,CAAM,CAAC,CAClD,CACA,OAAOD,CACT,EAAG,IAAI,GAA+B,EAGpCE,EACJ,GAAI,KAAK,QAAQ,YAAa,CAC5B,IAAMC,EAAS,KAAK,MAAM,MAAMC,GAAW,CACzC,QAAWrB,KAAUF,EACnBuB,EAAQ,KAAKrB,EAAO,KAAM,CACxB,OAAQ,CAAC,OAAO,EAChB,SAAU,KAAK,MAAM,SAAS,SAC9B,SAAU,KAAK,MAAM,SAAS,QAChC,CAAC,CACL,CAAC,EAGDmB,EAAcC,EAAO,OACjB,OAAO,KAAKA,EAAO,GAAG,UAAU,QAAQ,EACxC,CAAC,CACP,CAGA,OAAOJ,EAAA,CACL,MAAO,CAAC,GAAGf,EAAO,OAAO,CAAC,GACvB,OAAOkB,GAAgB,aAAe,CAAE,YAAAA,CAAY,EAI3D,OAAQG,EAAN,CACA,QAAQ,KAAK,kBAAkB1B,qCAAoC,CACrE,CAIF,MAAO,CAAE,MAAO,CAAC,CAAE,CACrB,CACF,EL3QA,IAAI2B,EAqBJ,SAAeC,GACbC,EACe,QAAAC,EAAA,sBACf,IAAIC,EAAO,UAGX,GAAI,OAAO,QAAW,aAAe,iBAAkB,OAAQ,CAC7D,IAAMC,EAAS,SAAS,cAAiC,aAAa,EAChE,CAACC,CAAI,EAAID,EAAO,IAAI,MAAM,SAAS,EAGzCD,EAAOA,EAAK,QAAQ,KAAME,CAAI,CAChC,CAGA,IAAMC,EAAU,CAAC,EACjB,QAAWC,KAAQN,EAAO,KAAM,CAC9B,OAAQM,OAGD,KACHD,EAAQ,KAAK,GAAGH,cAAiB,EACjC,UAGG,SACA,KACHG,EAAQ,KAAK,GAAGH,cAAiB,EACjC,MAIAI,IAAS,MACXD,EAAQ,KAAK,GAAGH,cAAiBI,UAAa,CAClD,CAGIN,EAAO,KAAK,OAAS,GACvBK,EAAQ,KAAK,GAAGH,yBAA4B,EAG1CG,EAAQ,SACV,MAAM,cACJ,GAAGH,oCACH,GAAGG,CACL,EACJ,GAaA,SAAsBE,GACpBC,EACwB,QAAAP,EAAA,sBACxB,OAAQO,EAAQ,aAIZ,aAAMT,GAAqBS,EAAQ,KAAK,MAAM,EAC9CV,EAAQ,IAAIW,EAAOD,EAAQ,IAAI,EACxB,CACL,MACF,SAIA,MAAO,CACL,OACA,KAAMV,EAAQA,EAAM,OAAOU,EAAQ,IAAI,EAAI,CAAE,MAAO,CAAC,CAAE,CACzD,UAIA,MAAM,IAAI,UAAU,sBAAsB,EAEhD,GAOA,KAAK,KAAO,GAAAE,QAGZ,iBAAiB,UAAiBC,GAAMV,EAAA,wBACtC,YAAY,MAAMM,GAAQI,EAAG,IAAI,CAAC,CACpC,EAAC", - "names": ["require_lunr", "__commonJSMin", "exports", "module", "lunr", "config", "builder", "global", "message", "obj", "clone", "keys", "key", "val", "docRef", "fieldName", "stringValue", "s", "n", "fieldRef", "elements", "i", "other", "object", "a", "b", "intersection", "element", "posting", "documentCount", "documentsWithTerm", "x", "str", "metadata", "fn", "t", "len", "tokens", "sliceEnd", "sliceStart", "char", "sliceLength", "tokenMetadata", "label", "isRegistered", "serialised", "pipeline", "fnName", "fns", "existingFn", "newFn", "pos", "stackLength", "memo", "j", "result", "k", "token", "index", "start", "end", "pivotPoint", "pivotIndex", "insertIdx", "position", "sumOfSquares", "elementsLength", "otherVector", "dotProduct", "aLen", "bLen", "aVal", "bVal", "output", "step2list", "step3list", "c", "v", "C", "V", "mgr0", "meq1", "mgr1", "s_v", "re_mgr0", "re_mgr1", "re_meq1", "re_s_v", "re_1a", "re2_1a", "re_1b", "re2_1b", "re_1b_2", "re2_1b_2", "re3_1b_2", "re4_1b_2", "re_1c", "re_2", "re_3", "re_4", "re2_4", "re_5", "re_5_1", "re3_5", "porterStemmer", "w", "stem", "suffix", "firstch", "re", "re2", "re3", "re4", "fp", "stopWords", "words", "stopWord", "arr", "clause", "editDistance", "root", "stack", "frame", "noEditNode", "insertionNode", "substitutionNode", "charA", "charB", "transposeNode", "node", "final", "next", "edges", "edge", "labels", "qEdges", "qLen", "nEdges", "nLen", "q", "qEdge", "nEdge", "qNode", "word", "commonPrefix", "nextNode", "downTo", "childKey", "attrs", "queryString", "query", "parser", "matchingFields", "queryVectors", "termFieldCache", "requiredMatches", "prohibitedMatches", "terms", "clauseMatches", "m", "term", "termTokenSet", "expandedTerms", "field", "expandedTerm", "termIndex", "fieldPosting", "matchingDocumentRefs", "termField", "matchingDocumentsSet", "l", "matchingDocumentRef", "matchingFieldRef", "fieldMatch", "allRequiredMatches", "allProhibitedMatches", "matchingFieldRefs", "results", "matches", "fieldVector", "score", "docMatch", "match", "invertedIndex", "fieldVectors", "ref", "serializedIndex", "serializedVectors", "serializedInvertedIndex", "tokenSetBuilder", "tuple", "attributes", "number", "doc", "fields", "extractor", "fieldTerms", "metadataKey", "fieldRefs", "numberOfFields", "accumulator", "documentsWithField", "fieldRefsLength", "termIdfCache", "fieldLength", "termFrequencies", "termsLength", "fieldBoost", "docBoost", "tf", "idf", "scoreWithPrecision", "args", "clonedMetadata", "metadataKeys", "otherMatchData", "allFields", "options", "state", "subSlices", "type", "charCode", "lexer", "lexeme", "completedClause", "errorMessage", "nextLexeme", "possibleFields", "f", "boost", "factory", "require_escape_html", "__commonJSMin", "exports", "module", "matchHtmlRegExp", "escapeHtml", "string", "str", "match", "escape", "html", "index", "lastIndex", "import_lunr", "obj", "data", "key", "x", "y", "nodes", "parent", "i", "node", "import_escape_html", "setupSearchDocumentMap", "docs", "documents", "parents", "doc", "path", "hash", "location", "title", "tags", "text", "escapeHTML", "parent", "__spreadValues", "import_escape_html", "setupSearchHighlighter", "config", "escape", "separator", "highlight", "_", "data", "term", "query", "match", "value", "escapeHTML", "parseSearchQuery", "value", "query", "getSearchQueryTerms", "terms", "_a", "clauses", "result", "t", "clause", "difference", "a", "b", "x", "y", "value", "Search", "config", "docs", "options", "setupSearchDocumentMap", "setupSearchHighlighter", "fns", "lang", "language", "fn", "doc", "tags", "list", "tag", "query", "highlight", "clauses", "parseSearchQuery", "clause", "groups", "item", "ref", "score", "matchData", "document", "location", "title", "text", "parent", "terms", "getSearchQueryTerms", "boost", "t", "__spreadProps", "__spreadValues", "items", "result", "suggestions", "titles", "builder", "e", "index", "setupSearchLanguages", "config", "__async", "base", "worker", "path", "scripts", "lang", "handler", "message", "Search", "lunr", "ev"] + "sources": ["node_modules/lunr/lunr.js", "node_modules/escape-html/index.js", "src/assets/javascripts/integrations/search/worker/main/index.ts", "src/assets/javascripts/integrations/search/document/index.ts", "src/assets/javascripts/integrations/search/highlighter/index.ts", "src/assets/javascripts/integrations/search/query/_/index.ts", "src/assets/javascripts/integrations/search/_/index.ts", "src/assets/javascripts/integrations/search/worker/message/index.ts"], + "sourcesContent": ["/**\n * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9\n * Copyright (C) 2020 Oliver Nightingale\n * @license MIT\n */\n\n;(function(){\n\n/**\n * A convenience function for configuring and constructing\n * a new lunr Index.\n *\n * A lunr.Builder instance is created and the pipeline setup\n * with a trimmer, stop word filter and stemmer.\n *\n * This builder object is yielded to the configuration function\n * that is passed as a parameter, allowing the list of fields\n * and other builder parameters to be customised.\n *\n * All documents _must_ be added within the passed config function.\n *\n * @example\n * var idx = lunr(function () {\n * this.field('title')\n * this.field('body')\n * this.ref('id')\n *\n * documents.forEach(function (doc) {\n * this.add(doc)\n * }, this)\n * })\n *\n * @see {@link lunr.Builder}\n * @see {@link lunr.Pipeline}\n * @see {@link lunr.trimmer}\n * @see {@link lunr.stopWordFilter}\n * @see {@link lunr.stemmer}\n * @namespace {function} lunr\n */\nvar lunr = function (config) {\n var builder = new lunr.Builder\n\n builder.pipeline.add(\n lunr.trimmer,\n lunr.stopWordFilter,\n lunr.stemmer\n )\n\n builder.searchPipeline.add(\n lunr.stemmer\n )\n\n config.call(builder, builder)\n return builder.build()\n}\n\nlunr.version = \"2.3.9\"\n/*!\n * lunr.utils\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A namespace containing utils for the rest of the lunr library\n * @namespace lunr.utils\n */\nlunr.utils = {}\n\n/**\n * Print a warning message to the console.\n *\n * @param {String} message The message to be printed.\n * @memberOf lunr.utils\n * @function\n */\nlunr.utils.warn = (function (global) {\n /* eslint-disable no-console */\n return function (message) {\n if (global.console && console.warn) {\n console.warn(message)\n }\n }\n /* eslint-enable no-console */\n})(this)\n\n/**\n * Convert an object to a string.\n *\n * In the case of `null` and `undefined` the function returns\n * the empty string, in all other cases the result of calling\n * `toString` on the passed object is returned.\n *\n * @param {Any} obj The object to convert to a string.\n * @return {String} string representation of the passed object.\n * @memberOf lunr.utils\n */\nlunr.utils.asString = function (obj) {\n if (obj === void 0 || obj === null) {\n return \"\"\n } else {\n return obj.toString()\n }\n}\n\n/**\n * Clones an object.\n *\n * Will create a copy of an existing object such that any mutations\n * on the copy cannot affect the original.\n *\n * Only shallow objects are supported, passing a nested object to this\n * function will cause a TypeError.\n *\n * Objects with primitives, and arrays of primitives are supported.\n *\n * @param {Object} obj The object to clone.\n * @return {Object} a clone of the passed object.\n * @throws {TypeError} when a nested object is passed.\n * @memberOf Utils\n */\nlunr.utils.clone = function (obj) {\n if (obj === null || obj === undefined) {\n return obj\n }\n\n var clone = Object.create(null),\n keys = Object.keys(obj)\n\n for (var i = 0; i < keys.length; i++) {\n var key = keys[i],\n val = obj[key]\n\n if (Array.isArray(val)) {\n clone[key] = val.slice()\n continue\n }\n\n if (typeof val === 'string' ||\n typeof val === 'number' ||\n typeof val === 'boolean') {\n clone[key] = val\n continue\n }\n\n throw new TypeError(\"clone is not deep and does not support nested objects\")\n }\n\n return clone\n}\nlunr.FieldRef = function (docRef, fieldName, stringValue) {\n this.docRef = docRef\n this.fieldName = fieldName\n this._stringValue = stringValue\n}\n\nlunr.FieldRef.joiner = \"/\"\n\nlunr.FieldRef.fromString = function (s) {\n var n = s.indexOf(lunr.FieldRef.joiner)\n\n if (n === -1) {\n throw \"malformed field ref string\"\n }\n\n var fieldRef = s.slice(0, n),\n docRef = s.slice(n + 1)\n\n return new lunr.FieldRef (docRef, fieldRef, s)\n}\n\nlunr.FieldRef.prototype.toString = function () {\n if (this._stringValue == undefined) {\n this._stringValue = this.fieldName + lunr.FieldRef.joiner + this.docRef\n }\n\n return this._stringValue\n}\n/*!\n * lunr.Set\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A lunr set.\n *\n * @constructor\n */\nlunr.Set = function (elements) {\n this.elements = Object.create(null)\n\n if (elements) {\n this.length = elements.length\n\n for (var i = 0; i < this.length; i++) {\n this.elements[elements[i]] = true\n }\n } else {\n this.length = 0\n }\n}\n\n/**\n * A complete set that contains all elements.\n *\n * @static\n * @readonly\n * @type {lunr.Set}\n */\nlunr.Set.complete = {\n intersect: function (other) {\n return other\n },\n\n union: function () {\n return this\n },\n\n contains: function () {\n return true\n }\n}\n\n/**\n * An empty set that contains no elements.\n *\n * @static\n * @readonly\n * @type {lunr.Set}\n */\nlunr.Set.empty = {\n intersect: function () {\n return this\n },\n\n union: function (other) {\n return other\n },\n\n contains: function () {\n return false\n }\n}\n\n/**\n * Returns true if this set contains the specified object.\n *\n * @param {object} object - Object whose presence in this set is to be tested.\n * @returns {boolean} - True if this set contains the specified object.\n */\nlunr.Set.prototype.contains = function (object) {\n return !!this.elements[object]\n}\n\n/**\n * Returns a new set containing only the elements that are present in both\n * this set and the specified set.\n *\n * @param {lunr.Set} other - set to intersect with this set.\n * @returns {lunr.Set} a new set that is the intersection of this and the specified set.\n */\n\nlunr.Set.prototype.intersect = function (other) {\n var a, b, elements, intersection = []\n\n if (other === lunr.Set.complete) {\n return this\n }\n\n if (other === lunr.Set.empty) {\n return other\n }\n\n if (this.length < other.length) {\n a = this\n b = other\n } else {\n a = other\n b = this\n }\n\n elements = Object.keys(a.elements)\n\n for (var i = 0; i < elements.length; i++) {\n var element = elements[i]\n if (element in b.elements) {\n intersection.push(element)\n }\n }\n\n return new lunr.Set (intersection)\n}\n\n/**\n * Returns a new set combining the elements of this and the specified set.\n *\n * @param {lunr.Set} other - set to union with this set.\n * @return {lunr.Set} a new set that is the union of this and the specified set.\n */\n\nlunr.Set.prototype.union = function (other) {\n if (other === lunr.Set.complete) {\n return lunr.Set.complete\n }\n\n if (other === lunr.Set.empty) {\n return this\n }\n\n return new lunr.Set(Object.keys(this.elements).concat(Object.keys(other.elements)))\n}\n/**\n * A function to calculate the inverse document frequency for\n * a posting. This is shared between the builder and the index\n *\n * @private\n * @param {object} posting - The posting for a given term\n * @param {number} documentCount - The total number of documents.\n */\nlunr.idf = function (posting, documentCount) {\n var documentsWithTerm = 0\n\n for (var fieldName in posting) {\n if (fieldName == '_index') continue // Ignore the term index, its not a field\n documentsWithTerm += Object.keys(posting[fieldName]).length\n }\n\n var x = (documentCount - documentsWithTerm + 0.5) / (documentsWithTerm + 0.5)\n\n return Math.log(1 + Math.abs(x))\n}\n\n/**\n * A token wraps a string representation of a token\n * as it is passed through the text processing pipeline.\n *\n * @constructor\n * @param {string} [str=''] - The string token being wrapped.\n * @param {object} [metadata={}] - Metadata associated with this token.\n */\nlunr.Token = function (str, metadata) {\n this.str = str || \"\"\n this.metadata = metadata || {}\n}\n\n/**\n * Returns the token string that is being wrapped by this object.\n *\n * @returns {string}\n */\nlunr.Token.prototype.toString = function () {\n return this.str\n}\n\n/**\n * A token update function is used when updating or optionally\n * when cloning a token.\n *\n * @callback lunr.Token~updateFunction\n * @param {string} str - The string representation of the token.\n * @param {Object} metadata - All metadata associated with this token.\n */\n\n/**\n * Applies the given function to the wrapped string token.\n *\n * @example\n * token.update(function (str, metadata) {\n * return str.toUpperCase()\n * })\n *\n * @param {lunr.Token~updateFunction} fn - A function to apply to the token string.\n * @returns {lunr.Token}\n */\nlunr.Token.prototype.update = function (fn) {\n this.str = fn(this.str, this.metadata)\n return this\n}\n\n/**\n * Creates a clone of this token. Optionally a function can be\n * applied to the cloned token.\n *\n * @param {lunr.Token~updateFunction} [fn] - An optional function to apply to the cloned token.\n * @returns {lunr.Token}\n */\nlunr.Token.prototype.clone = function (fn) {\n fn = fn || function (s) { return s }\n return new lunr.Token (fn(this.str, this.metadata), this.metadata)\n}\n/*!\n * lunr.tokenizer\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A function for splitting a string into tokens ready to be inserted into\n * the search index. Uses `lunr.tokenizer.separator` to split strings, change\n * the value of this property to change how strings are split into tokens.\n *\n * This tokenizer will convert its parameter to a string by calling `toString` and\n * then will split this string on the character in `lunr.tokenizer.separator`.\n * Arrays will have their elements converted to strings and wrapped in a lunr.Token.\n *\n * Optional metadata can be passed to the tokenizer, this metadata will be cloned and\n * added as metadata to every token that is created from the object to be tokenized.\n *\n * @static\n * @param {?(string|object|object[])} obj - The object to convert into tokens\n * @param {?object} metadata - Optional metadata to associate with every token\n * @returns {lunr.Token[]}\n * @see {@link lunr.Pipeline}\n */\nlunr.tokenizer = function (obj, metadata) {\n if (obj == null || obj == undefined) {\n return []\n }\n\n if (Array.isArray(obj)) {\n return obj.map(function (t) {\n return new lunr.Token(\n lunr.utils.asString(t).toLowerCase(),\n lunr.utils.clone(metadata)\n )\n })\n }\n\n var str = obj.toString().toLowerCase(),\n len = str.length,\n tokens = []\n\n for (var sliceEnd = 0, sliceStart = 0; sliceEnd <= len; sliceEnd++) {\n var char = str.charAt(sliceEnd),\n sliceLength = sliceEnd - sliceStart\n\n if ((char.match(lunr.tokenizer.separator) || sliceEnd == len)) {\n\n if (sliceLength > 0) {\n var tokenMetadata = lunr.utils.clone(metadata) || {}\n tokenMetadata[\"position\"] = [sliceStart, sliceLength]\n tokenMetadata[\"index\"] = tokens.length\n\n tokens.push(\n new lunr.Token (\n str.slice(sliceStart, sliceEnd),\n tokenMetadata\n )\n )\n }\n\n sliceStart = sliceEnd + 1\n }\n\n }\n\n return tokens\n}\n\n/**\n * The separator used to split a string into tokens. Override this property to change the behaviour of\n * `lunr.tokenizer` behaviour when tokenizing strings. By default this splits on whitespace and hyphens.\n *\n * @static\n * @see lunr.tokenizer\n */\nlunr.tokenizer.separator = /[\\s\\-]+/\n/*!\n * lunr.Pipeline\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.Pipelines maintain an ordered list of functions to be applied to all\n * tokens in documents entering the search index and queries being ran against\n * the index.\n *\n * An instance of lunr.Index created with the lunr shortcut will contain a\n * pipeline with a stop word filter and an English language stemmer. Extra\n * functions can be added before or after either of these functions or these\n * default functions can be removed.\n *\n * When run the pipeline will call each function in turn, passing a token, the\n * index of that token in the original list of all tokens and finally a list of\n * all the original tokens.\n *\n * The output of functions in the pipeline will be passed to the next function\n * in the pipeline. To exclude a token from entering the index the function\n * should return undefined, the rest of the pipeline will not be called with\n * this token.\n *\n * For serialisation of pipelines to work, all functions used in an instance of\n * a pipeline should be registered with lunr.Pipeline. Registered functions can\n * then be loaded. If trying to load a serialised pipeline that uses functions\n * that are not registered an error will be thrown.\n *\n * If not planning on serialising the pipeline then registering pipeline functions\n * is not necessary.\n *\n * @constructor\n */\nlunr.Pipeline = function () {\n this._stack = []\n}\n\nlunr.Pipeline.registeredFunctions = Object.create(null)\n\n/**\n * A pipeline function maps lunr.Token to lunr.Token. A lunr.Token contains the token\n * string as well as all known metadata. A pipeline function can mutate the token string\n * or mutate (or add) metadata for a given token.\n *\n * A pipeline function can indicate that the passed token should be discarded by returning\n * null, undefined or an empty string. This token will not be passed to any downstream pipeline\n * functions and will not be added to the index.\n *\n * Multiple tokens can be returned by returning an array of tokens. Each token will be passed\n * to any downstream pipeline functions and all will returned tokens will be added to the index.\n *\n * Any number of pipeline functions may be chained together using a lunr.Pipeline.\n *\n * @interface lunr.PipelineFunction\n * @param {lunr.Token} token - A token from the document being processed.\n * @param {number} i - The index of this token in the complete list of tokens for this document/field.\n * @param {lunr.Token[]} tokens - All tokens for this document/field.\n * @returns {(?lunr.Token|lunr.Token[])}\n */\n\n/**\n * Register a function with the pipeline.\n *\n * Functions that are used in the pipeline should be registered if the pipeline\n * needs to be serialised, or a serialised pipeline needs to be loaded.\n *\n * Registering a function does not add it to a pipeline, functions must still be\n * added to instances of the pipeline for them to be used when running a pipeline.\n *\n * @param {lunr.PipelineFunction} fn - The function to check for.\n * @param {String} label - The label to register this function with\n */\nlunr.Pipeline.registerFunction = function (fn, label) {\n if (label in this.registeredFunctions) {\n lunr.utils.warn('Overwriting existing registered function: ' + label)\n }\n\n fn.label = label\n lunr.Pipeline.registeredFunctions[fn.label] = fn\n}\n\n/**\n * Warns if the function is not registered as a Pipeline function.\n *\n * @param {lunr.PipelineFunction} fn - The function to check for.\n * @private\n */\nlunr.Pipeline.warnIfFunctionNotRegistered = function (fn) {\n var isRegistered = fn.label && (fn.label in this.registeredFunctions)\n\n if (!isRegistered) {\n lunr.utils.warn('Function is not registered with pipeline. This may cause problems when serialising the index.\\n', fn)\n }\n}\n\n/**\n * Loads a previously serialised pipeline.\n *\n * All functions to be loaded must already be registered with lunr.Pipeline.\n * If any function from the serialised data has not been registered then an\n * error will be thrown.\n *\n * @param {Object} serialised - The serialised pipeline to load.\n * @returns {lunr.Pipeline}\n */\nlunr.Pipeline.load = function (serialised) {\n var pipeline = new lunr.Pipeline\n\n serialised.forEach(function (fnName) {\n var fn = lunr.Pipeline.registeredFunctions[fnName]\n\n if (fn) {\n pipeline.add(fn)\n } else {\n throw new Error('Cannot load unregistered function: ' + fnName)\n }\n })\n\n return pipeline\n}\n\n/**\n * Adds new functions to the end of the pipeline.\n *\n * Logs a warning if the function has not been registered.\n *\n * @param {lunr.PipelineFunction[]} functions - Any number of functions to add to the pipeline.\n */\nlunr.Pipeline.prototype.add = function () {\n var fns = Array.prototype.slice.call(arguments)\n\n fns.forEach(function (fn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(fn)\n this._stack.push(fn)\n }, this)\n}\n\n/**\n * Adds a single function after a function that already exists in the\n * pipeline.\n *\n * Logs a warning if the function has not been registered.\n *\n * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline.\n * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline.\n */\nlunr.Pipeline.prototype.after = function (existingFn, newFn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(newFn)\n\n var pos = this._stack.indexOf(existingFn)\n if (pos == -1) {\n throw new Error('Cannot find existingFn')\n }\n\n pos = pos + 1\n this._stack.splice(pos, 0, newFn)\n}\n\n/**\n * Adds a single function before a function that already exists in the\n * pipeline.\n *\n * Logs a warning if the function has not been registered.\n *\n * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline.\n * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline.\n */\nlunr.Pipeline.prototype.before = function (existingFn, newFn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(newFn)\n\n var pos = this._stack.indexOf(existingFn)\n if (pos == -1) {\n throw new Error('Cannot find existingFn')\n }\n\n this._stack.splice(pos, 0, newFn)\n}\n\n/**\n * Removes a function from the pipeline.\n *\n * @param {lunr.PipelineFunction} fn The function to remove from the pipeline.\n */\nlunr.Pipeline.prototype.remove = function (fn) {\n var pos = this._stack.indexOf(fn)\n if (pos == -1) {\n return\n }\n\n this._stack.splice(pos, 1)\n}\n\n/**\n * Runs the current list of functions that make up the pipeline against the\n * passed tokens.\n *\n * @param {Array} tokens The tokens to run through the pipeline.\n * @returns {Array}\n */\nlunr.Pipeline.prototype.run = function (tokens) {\n var stackLength = this._stack.length\n\n for (var i = 0; i < stackLength; i++) {\n var fn = this._stack[i]\n var memo = []\n\n for (var j = 0; j < tokens.length; j++) {\n var result = fn(tokens[j], j, tokens)\n\n if (result === null || result === void 0 || result === '') continue\n\n if (Array.isArray(result)) {\n for (var k = 0; k < result.length; k++) {\n memo.push(result[k])\n }\n } else {\n memo.push(result)\n }\n }\n\n tokens = memo\n }\n\n return tokens\n}\n\n/**\n * Convenience method for passing a string through a pipeline and getting\n * strings out. This method takes care of wrapping the passed string in a\n * token and mapping the resulting tokens back to strings.\n *\n * @param {string} str - The string to pass through the pipeline.\n * @param {?object} metadata - Optional metadata to associate with the token\n * passed to the pipeline.\n * @returns {string[]}\n */\nlunr.Pipeline.prototype.runString = function (str, metadata) {\n var token = new lunr.Token (str, metadata)\n\n return this.run([token]).map(function (t) {\n return t.toString()\n })\n}\n\n/**\n * Resets the pipeline by removing any existing processors.\n *\n */\nlunr.Pipeline.prototype.reset = function () {\n this._stack = []\n}\n\n/**\n * Returns a representation of the pipeline ready for serialisation.\n *\n * Logs a warning if the function has not been registered.\n *\n * @returns {Array}\n */\nlunr.Pipeline.prototype.toJSON = function () {\n return this._stack.map(function (fn) {\n lunr.Pipeline.warnIfFunctionNotRegistered(fn)\n\n return fn.label\n })\n}\n/*!\n * lunr.Vector\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A vector is used to construct the vector space of documents and queries. These\n * vectors support operations to determine the similarity between two documents or\n * a document and a query.\n *\n * Normally no parameters are required for initializing a vector, but in the case of\n * loading a previously dumped vector the raw elements can be provided to the constructor.\n *\n * For performance reasons vectors are implemented with a flat array, where an elements\n * index is immediately followed by its value. E.g. [index, value, index, value]. This\n * allows the underlying array to be as sparse as possible and still offer decent\n * performance when being used for vector calculations.\n *\n * @constructor\n * @param {Number[]} [elements] - The flat list of element index and element value pairs.\n */\nlunr.Vector = function (elements) {\n this._magnitude = 0\n this.elements = elements || []\n}\n\n\n/**\n * Calculates the position within the vector to insert a given index.\n *\n * This is used internally by insert and upsert. If there are duplicate indexes then\n * the position is returned as if the value for that index were to be updated, but it\n * is the callers responsibility to check whether there is a duplicate at that index\n *\n * @param {Number} insertIdx - The index at which the element should be inserted.\n * @returns {Number}\n */\nlunr.Vector.prototype.positionForIndex = function (index) {\n // For an empty vector the tuple can be inserted at the beginning\n if (this.elements.length == 0) {\n return 0\n }\n\n var start = 0,\n end = this.elements.length / 2,\n sliceLength = end - start,\n pivotPoint = Math.floor(sliceLength / 2),\n pivotIndex = this.elements[pivotPoint * 2]\n\n while (sliceLength > 1) {\n if (pivotIndex < index) {\n start = pivotPoint\n }\n\n if (pivotIndex > index) {\n end = pivotPoint\n }\n\n if (pivotIndex == index) {\n break\n }\n\n sliceLength = end - start\n pivotPoint = start + Math.floor(sliceLength / 2)\n pivotIndex = this.elements[pivotPoint * 2]\n }\n\n if (pivotIndex == index) {\n return pivotPoint * 2\n }\n\n if (pivotIndex > index) {\n return pivotPoint * 2\n }\n\n if (pivotIndex < index) {\n return (pivotPoint + 1) * 2\n }\n}\n\n/**\n * Inserts an element at an index within the vector.\n *\n * Does not allow duplicates, will throw an error if there is already an entry\n * for this index.\n *\n * @param {Number} insertIdx - The index at which the element should be inserted.\n * @param {Number} val - The value to be inserted into the vector.\n */\nlunr.Vector.prototype.insert = function (insertIdx, val) {\n this.upsert(insertIdx, val, function () {\n throw \"duplicate index\"\n })\n}\n\n/**\n * Inserts or updates an existing index within the vector.\n *\n * @param {Number} insertIdx - The index at which the element should be inserted.\n * @param {Number} val - The value to be inserted into the vector.\n * @param {function} fn - A function that is called for updates, the existing value and the\n * requested value are passed as arguments\n */\nlunr.Vector.prototype.upsert = function (insertIdx, val, fn) {\n this._magnitude = 0\n var position = this.positionForIndex(insertIdx)\n\n if (this.elements[position] == insertIdx) {\n this.elements[position + 1] = fn(this.elements[position + 1], val)\n } else {\n this.elements.splice(position, 0, insertIdx, val)\n }\n}\n\n/**\n * Calculates the magnitude of this vector.\n *\n * @returns {Number}\n */\nlunr.Vector.prototype.magnitude = function () {\n if (this._magnitude) return this._magnitude\n\n var sumOfSquares = 0,\n elementsLength = this.elements.length\n\n for (var i = 1; i < elementsLength; i += 2) {\n var val = this.elements[i]\n sumOfSquares += val * val\n }\n\n return this._magnitude = Math.sqrt(sumOfSquares)\n}\n\n/**\n * Calculates the dot product of this vector and another vector.\n *\n * @param {lunr.Vector} otherVector - The vector to compute the dot product with.\n * @returns {Number}\n */\nlunr.Vector.prototype.dot = function (otherVector) {\n var dotProduct = 0,\n a = this.elements, b = otherVector.elements,\n aLen = a.length, bLen = b.length,\n aVal = 0, bVal = 0,\n i = 0, j = 0\n\n while (i < aLen && j < bLen) {\n aVal = a[i], bVal = b[j]\n if (aVal < bVal) {\n i += 2\n } else if (aVal > bVal) {\n j += 2\n } else if (aVal == bVal) {\n dotProduct += a[i + 1] * b[j + 1]\n i += 2\n j += 2\n }\n }\n\n return dotProduct\n}\n\n/**\n * Calculates the similarity between this vector and another vector.\n *\n * @param {lunr.Vector} otherVector - The other vector to calculate the\n * similarity with.\n * @returns {Number}\n */\nlunr.Vector.prototype.similarity = function (otherVector) {\n return this.dot(otherVector) / this.magnitude() || 0\n}\n\n/**\n * Converts the vector to an array of the elements within the vector.\n *\n * @returns {Number[]}\n */\nlunr.Vector.prototype.toArray = function () {\n var output = new Array (this.elements.length / 2)\n\n for (var i = 1, j = 0; i < this.elements.length; i += 2, j++) {\n output[j] = this.elements[i]\n }\n\n return output\n}\n\n/**\n * A JSON serializable representation of the vector.\n *\n * @returns {Number[]}\n */\nlunr.Vector.prototype.toJSON = function () {\n return this.elements\n}\n/* eslint-disable */\n/*!\n * lunr.stemmer\n * Copyright (C) 2020 Oliver Nightingale\n * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt\n */\n\n/**\n * lunr.stemmer is an english language stemmer, this is a JavaScript\n * implementation of the PorterStemmer taken from http://tartarus.org/~martin\n *\n * @static\n * @implements {lunr.PipelineFunction}\n * @param {lunr.Token} token - The string to stem\n * @returns {lunr.Token}\n * @see {@link lunr.Pipeline}\n * @function\n */\nlunr.stemmer = (function(){\n var step2list = {\n \"ational\" : \"ate\",\n \"tional\" : \"tion\",\n \"enci\" : \"ence\",\n \"anci\" : \"ance\",\n \"izer\" : \"ize\",\n \"bli\" : \"ble\",\n \"alli\" : \"al\",\n \"entli\" : \"ent\",\n \"eli\" : \"e\",\n \"ousli\" : \"ous\",\n \"ization\" : \"ize\",\n \"ation\" : \"ate\",\n \"ator\" : \"ate\",\n \"alism\" : \"al\",\n \"iveness\" : \"ive\",\n \"fulness\" : \"ful\",\n \"ousness\" : \"ous\",\n \"aliti\" : \"al\",\n \"iviti\" : \"ive\",\n \"biliti\" : \"ble\",\n \"logi\" : \"log\"\n },\n\n step3list = {\n \"icate\" : \"ic\",\n \"ative\" : \"\",\n \"alize\" : \"al\",\n \"iciti\" : \"ic\",\n \"ical\" : \"ic\",\n \"ful\" : \"\",\n \"ness\" : \"\"\n },\n\n c = \"[^aeiou]\", // consonant\n v = \"[aeiouy]\", // vowel\n C = c + \"[^aeiouy]*\", // consonant sequence\n V = v + \"[aeiou]*\", // vowel sequence\n\n mgr0 = \"^(\" + C + \")?\" + V + C, // [C]VC... is m>0\n meq1 = \"^(\" + C + \")?\" + V + C + \"(\" + V + \")?$\", // [C]VC[V] is m=1\n mgr1 = \"^(\" + C + \")?\" + V + C + V + C, // [C]VCVC... is m>1\n s_v = \"^(\" + C + \")?\" + v; // vowel in stem\n\n var re_mgr0 = new RegExp(mgr0);\n var re_mgr1 = new RegExp(mgr1);\n var re_meq1 = new RegExp(meq1);\n var re_s_v = new RegExp(s_v);\n\n var re_1a = /^(.+?)(ss|i)es$/;\n var re2_1a = /^(.+?)([^s])s$/;\n var re_1b = /^(.+?)eed$/;\n var re2_1b = /^(.+?)(ed|ing)$/;\n var re_1b_2 = /.$/;\n var re2_1b_2 = /(at|bl|iz)$/;\n var re3_1b_2 = new RegExp(\"([^aeiouylsz])\\\\1$\");\n var re4_1b_2 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n\n var re_1c = /^(.+?[^aeiou])y$/;\n var re_2 = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;\n\n var re_3 = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;\n\n var re_4 = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;\n var re2_4 = /^(.+?)(s|t)(ion)$/;\n\n var re_5 = /^(.+?)e$/;\n var re_5_1 = /ll$/;\n var re3_5 = new RegExp(\"^\" + C + v + \"[^aeiouwxy]$\");\n\n var porterStemmer = function porterStemmer(w) {\n var stem,\n suffix,\n firstch,\n re,\n re2,\n re3,\n re4;\n\n if (w.length < 3) { return w; }\n\n firstch = w.substr(0,1);\n if (firstch == \"y\") {\n w = firstch.toUpperCase() + w.substr(1);\n }\n\n // Step 1a\n re = re_1a\n re2 = re2_1a;\n\n if (re.test(w)) { w = w.replace(re,\"$1$2\"); }\n else if (re2.test(w)) { w = w.replace(re2,\"$1$2\"); }\n\n // Step 1b\n re = re_1b;\n re2 = re2_1b;\n if (re.test(w)) {\n var fp = re.exec(w);\n re = re_mgr0;\n if (re.test(fp[1])) {\n re = re_1b_2;\n w = w.replace(re,\"\");\n }\n } else if (re2.test(w)) {\n var fp = re2.exec(w);\n stem = fp[1];\n re2 = re_s_v;\n if (re2.test(stem)) {\n w = stem;\n re2 = re2_1b_2;\n re3 = re3_1b_2;\n re4 = re4_1b_2;\n if (re2.test(w)) { w = w + \"e\"; }\n else if (re3.test(w)) { re = re_1b_2; w = w.replace(re,\"\"); }\n else if (re4.test(w)) { w = w + \"e\"; }\n }\n }\n\n // Step 1c - replace suffix y or Y by i if preceded by a non-vowel which is not the first letter of the word (so cry -> cri, by -> by, say -> say)\n re = re_1c;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n w = stem + \"i\";\n }\n\n // Step 2\n re = re_2;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n suffix = fp[2];\n re = re_mgr0;\n if (re.test(stem)) {\n w = stem + step2list[suffix];\n }\n }\n\n // Step 3\n re = re_3;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n suffix = fp[2];\n re = re_mgr0;\n if (re.test(stem)) {\n w = stem + step3list[suffix];\n }\n }\n\n // Step 4\n re = re_4;\n re2 = re2_4;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n re = re_mgr1;\n if (re.test(stem)) {\n w = stem;\n }\n } else if (re2.test(w)) {\n var fp = re2.exec(w);\n stem = fp[1] + fp[2];\n re2 = re_mgr1;\n if (re2.test(stem)) {\n w = stem;\n }\n }\n\n // Step 5\n re = re_5;\n if (re.test(w)) {\n var fp = re.exec(w);\n stem = fp[1];\n re = re_mgr1;\n re2 = re_meq1;\n re3 = re3_5;\n if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) {\n w = stem;\n }\n }\n\n re = re_5_1;\n re2 = re_mgr1;\n if (re.test(w) && re2.test(w)) {\n re = re_1b_2;\n w = w.replace(re,\"\");\n }\n\n // and turn initial Y back to y\n\n if (firstch == \"y\") {\n w = firstch.toLowerCase() + w.substr(1);\n }\n\n return w;\n };\n\n return function (token) {\n return token.update(porterStemmer);\n }\n})();\n\nlunr.Pipeline.registerFunction(lunr.stemmer, 'stemmer')\n/*!\n * lunr.stopWordFilter\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.generateStopWordFilter builds a stopWordFilter function from the provided\n * list of stop words.\n *\n * The built in lunr.stopWordFilter is built using this generator and can be used\n * to generate custom stopWordFilters for applications or non English languages.\n *\n * @function\n * @param {Array} token The token to pass through the filter\n * @returns {lunr.PipelineFunction}\n * @see lunr.Pipeline\n * @see lunr.stopWordFilter\n */\nlunr.generateStopWordFilter = function (stopWords) {\n var words = stopWords.reduce(function (memo, stopWord) {\n memo[stopWord] = stopWord\n return memo\n }, {})\n\n return function (token) {\n if (token && words[token.toString()] !== token.toString()) return token\n }\n}\n\n/**\n * lunr.stopWordFilter is an English language stop word list filter, any words\n * contained in the list will not be passed through the filter.\n *\n * This is intended to be used in the Pipeline. If the token does not pass the\n * filter then undefined will be returned.\n *\n * @function\n * @implements {lunr.PipelineFunction}\n * @params {lunr.Token} token - A token to check for being a stop word.\n * @returns {lunr.Token}\n * @see {@link lunr.Pipeline}\n */\nlunr.stopWordFilter = lunr.generateStopWordFilter([\n 'a',\n 'able',\n 'about',\n 'across',\n 'after',\n 'all',\n 'almost',\n 'also',\n 'am',\n 'among',\n 'an',\n 'and',\n 'any',\n 'are',\n 'as',\n 'at',\n 'be',\n 'because',\n 'been',\n 'but',\n 'by',\n 'can',\n 'cannot',\n 'could',\n 'dear',\n 'did',\n 'do',\n 'does',\n 'either',\n 'else',\n 'ever',\n 'every',\n 'for',\n 'from',\n 'get',\n 'got',\n 'had',\n 'has',\n 'have',\n 'he',\n 'her',\n 'hers',\n 'him',\n 'his',\n 'how',\n 'however',\n 'i',\n 'if',\n 'in',\n 'into',\n 'is',\n 'it',\n 'its',\n 'just',\n 'least',\n 'let',\n 'like',\n 'likely',\n 'may',\n 'me',\n 'might',\n 'most',\n 'must',\n 'my',\n 'neither',\n 'no',\n 'nor',\n 'not',\n 'of',\n 'off',\n 'often',\n 'on',\n 'only',\n 'or',\n 'other',\n 'our',\n 'own',\n 'rather',\n 'said',\n 'say',\n 'says',\n 'she',\n 'should',\n 'since',\n 'so',\n 'some',\n 'than',\n 'that',\n 'the',\n 'their',\n 'them',\n 'then',\n 'there',\n 'these',\n 'they',\n 'this',\n 'tis',\n 'to',\n 'too',\n 'twas',\n 'us',\n 'wants',\n 'was',\n 'we',\n 'were',\n 'what',\n 'when',\n 'where',\n 'which',\n 'while',\n 'who',\n 'whom',\n 'why',\n 'will',\n 'with',\n 'would',\n 'yet',\n 'you',\n 'your'\n])\n\nlunr.Pipeline.registerFunction(lunr.stopWordFilter, 'stopWordFilter')\n/*!\n * lunr.trimmer\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.trimmer is a pipeline function for trimming non word\n * characters from the beginning and end of tokens before they\n * enter the index.\n *\n * This implementation may not work correctly for non latin\n * characters and should either be removed or adapted for use\n * with languages with non-latin characters.\n *\n * @static\n * @implements {lunr.PipelineFunction}\n * @param {lunr.Token} token The token to pass through the filter\n * @returns {lunr.Token}\n * @see lunr.Pipeline\n */\nlunr.trimmer = function (token) {\n return token.update(function (s) {\n return s.replace(/^\\W+/, '').replace(/\\W+$/, '')\n })\n}\n\nlunr.Pipeline.registerFunction(lunr.trimmer, 'trimmer')\n/*!\n * lunr.TokenSet\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * A token set is used to store the unique list of all tokens\n * within an index. Token sets are also used to represent an\n * incoming query to the index, this query token set and index\n * token set are then intersected to find which tokens to look\n * up in the inverted index.\n *\n * A token set can hold multiple tokens, as in the case of the\n * index token set, or it can hold a single token as in the\n * case of a simple query token set.\n *\n * Additionally token sets are used to perform wildcard matching.\n * Leading, contained and trailing wildcards are supported, and\n * from this edit distance matching can also be provided.\n *\n * Token sets are implemented as a minimal finite state automata,\n * where both common prefixes and suffixes are shared between tokens.\n * This helps to reduce the space used for storing the token set.\n *\n * @constructor\n */\nlunr.TokenSet = function () {\n this.final = false\n this.edges = {}\n this.id = lunr.TokenSet._nextId\n lunr.TokenSet._nextId += 1\n}\n\n/**\n * Keeps track of the next, auto increment, identifier to assign\n * to a new tokenSet.\n *\n * TokenSets require a unique identifier to be correctly minimised.\n *\n * @private\n */\nlunr.TokenSet._nextId = 1\n\n/**\n * Creates a TokenSet instance from the given sorted array of words.\n *\n * @param {String[]} arr - A sorted array of strings to create the set from.\n * @returns {lunr.TokenSet}\n * @throws Will throw an error if the input array is not sorted.\n */\nlunr.TokenSet.fromArray = function (arr) {\n var builder = new lunr.TokenSet.Builder\n\n for (var i = 0, len = arr.length; i < len; i++) {\n builder.insert(arr[i])\n }\n\n builder.finish()\n return builder.root\n}\n\n/**\n * Creates a token set from a query clause.\n *\n * @private\n * @param {Object} clause - A single clause from lunr.Query.\n * @param {string} clause.term - The query clause term.\n * @param {number} [clause.editDistance] - The optional edit distance for the term.\n * @returns {lunr.TokenSet}\n */\nlunr.TokenSet.fromClause = function (clause) {\n if ('editDistance' in clause) {\n return lunr.TokenSet.fromFuzzyString(clause.term, clause.editDistance)\n } else {\n return lunr.TokenSet.fromString(clause.term)\n }\n}\n\n/**\n * Creates a token set representing a single string with a specified\n * edit distance.\n *\n * Insertions, deletions, substitutions and transpositions are each\n * treated as an edit distance of 1.\n *\n * Increasing the allowed edit distance will have a dramatic impact\n * on the performance of both creating and intersecting these TokenSets.\n * It is advised to keep the edit distance less than 3.\n *\n * @param {string} str - The string to create the token set from.\n * @param {number} editDistance - The allowed edit distance to match.\n * @returns {lunr.Vector}\n */\nlunr.TokenSet.fromFuzzyString = function (str, editDistance) {\n var root = new lunr.TokenSet\n\n var stack = [{\n node: root,\n editsRemaining: editDistance,\n str: str\n }]\n\n while (stack.length) {\n var frame = stack.pop()\n\n // no edit\n if (frame.str.length > 0) {\n var char = frame.str.charAt(0),\n noEditNode\n\n if (char in frame.node.edges) {\n noEditNode = frame.node.edges[char]\n } else {\n noEditNode = new lunr.TokenSet\n frame.node.edges[char] = noEditNode\n }\n\n if (frame.str.length == 1) {\n noEditNode.final = true\n }\n\n stack.push({\n node: noEditNode,\n editsRemaining: frame.editsRemaining,\n str: frame.str.slice(1)\n })\n }\n\n if (frame.editsRemaining == 0) {\n continue\n }\n\n // insertion\n if (\"*\" in frame.node.edges) {\n var insertionNode = frame.node.edges[\"*\"]\n } else {\n var insertionNode = new lunr.TokenSet\n frame.node.edges[\"*\"] = insertionNode\n }\n\n if (frame.str.length == 0) {\n insertionNode.final = true\n }\n\n stack.push({\n node: insertionNode,\n editsRemaining: frame.editsRemaining - 1,\n str: frame.str\n })\n\n // deletion\n // can only do a deletion if we have enough edits remaining\n // and if there are characters left to delete in the string\n if (frame.str.length > 1) {\n stack.push({\n node: frame.node,\n editsRemaining: frame.editsRemaining - 1,\n str: frame.str.slice(1)\n })\n }\n\n // deletion\n // just removing the last character from the str\n if (frame.str.length == 1) {\n frame.node.final = true\n }\n\n // substitution\n // can only do a substitution if we have enough edits remaining\n // and if there are characters left to substitute\n if (frame.str.length >= 1) {\n if (\"*\" in frame.node.edges) {\n var substitutionNode = frame.node.edges[\"*\"]\n } else {\n var substitutionNode = new lunr.TokenSet\n frame.node.edges[\"*\"] = substitutionNode\n }\n\n if (frame.str.length == 1) {\n substitutionNode.final = true\n }\n\n stack.push({\n node: substitutionNode,\n editsRemaining: frame.editsRemaining - 1,\n str: frame.str.slice(1)\n })\n }\n\n // transposition\n // can only do a transposition if there are edits remaining\n // and there are enough characters to transpose\n if (frame.str.length > 1) {\n var charA = frame.str.charAt(0),\n charB = frame.str.charAt(1),\n transposeNode\n\n if (charB in frame.node.edges) {\n transposeNode = frame.node.edges[charB]\n } else {\n transposeNode = new lunr.TokenSet\n frame.node.edges[charB] = transposeNode\n }\n\n if (frame.str.length == 1) {\n transposeNode.final = true\n }\n\n stack.push({\n node: transposeNode,\n editsRemaining: frame.editsRemaining - 1,\n str: charA + frame.str.slice(2)\n })\n }\n }\n\n return root\n}\n\n/**\n * Creates a TokenSet from a string.\n *\n * The string may contain one or more wildcard characters (*)\n * that will allow wildcard matching when intersecting with\n * another TokenSet.\n *\n * @param {string} str - The string to create a TokenSet from.\n * @returns {lunr.TokenSet}\n */\nlunr.TokenSet.fromString = function (str) {\n var node = new lunr.TokenSet,\n root = node\n\n /*\n * Iterates through all characters within the passed string\n * appending a node for each character.\n *\n * When a wildcard character is found then a self\n * referencing edge is introduced to continually match\n * any number of any characters.\n */\n for (var i = 0, len = str.length; i < len; i++) {\n var char = str[i],\n final = (i == len - 1)\n\n if (char == \"*\") {\n node.edges[char] = node\n node.final = final\n\n } else {\n var next = new lunr.TokenSet\n next.final = final\n\n node.edges[char] = next\n node = next\n }\n }\n\n return root\n}\n\n/**\n * Converts this TokenSet into an array of strings\n * contained within the TokenSet.\n *\n * This is not intended to be used on a TokenSet that\n * contains wildcards, in these cases the results are\n * undefined and are likely to cause an infinite loop.\n *\n * @returns {string[]}\n */\nlunr.TokenSet.prototype.toArray = function () {\n var words = []\n\n var stack = [{\n prefix: \"\",\n node: this\n }]\n\n while (stack.length) {\n var frame = stack.pop(),\n edges = Object.keys(frame.node.edges),\n len = edges.length\n\n if (frame.node.final) {\n /* In Safari, at this point the prefix is sometimes corrupted, see:\n * https://github.com/olivernn/lunr.js/issues/279 Calling any\n * String.prototype method forces Safari to \"cast\" this string to what\n * it's supposed to be, fixing the bug. */\n frame.prefix.charAt(0)\n words.push(frame.prefix)\n }\n\n for (var i = 0; i < len; i++) {\n var edge = edges[i]\n\n stack.push({\n prefix: frame.prefix.concat(edge),\n node: frame.node.edges[edge]\n })\n }\n }\n\n return words\n}\n\n/**\n * Generates a string representation of a TokenSet.\n *\n * This is intended to allow TokenSets to be used as keys\n * in objects, largely to aid the construction and minimisation\n * of a TokenSet. As such it is not designed to be a human\n * friendly representation of the TokenSet.\n *\n * @returns {string}\n */\nlunr.TokenSet.prototype.toString = function () {\n // NOTE: Using Object.keys here as this.edges is very likely\n // to enter 'hash-mode' with many keys being added\n //\n // avoiding a for-in loop here as it leads to the function\n // being de-optimised (at least in V8). From some simple\n // benchmarks the performance is comparable, but allowing\n // V8 to optimize may mean easy performance wins in the future.\n\n if (this._str) {\n return this._str\n }\n\n var str = this.final ? '1' : '0',\n labels = Object.keys(this.edges).sort(),\n len = labels.length\n\n for (var i = 0; i < len; i++) {\n var label = labels[i],\n node = this.edges[label]\n\n str = str + label + node.id\n }\n\n return str\n}\n\n/**\n * Returns a new TokenSet that is the intersection of\n * this TokenSet and the passed TokenSet.\n *\n * This intersection will take into account any wildcards\n * contained within the TokenSet.\n *\n * @param {lunr.TokenSet} b - An other TokenSet to intersect with.\n * @returns {lunr.TokenSet}\n */\nlunr.TokenSet.prototype.intersect = function (b) {\n var output = new lunr.TokenSet,\n frame = undefined\n\n var stack = [{\n qNode: b,\n output: output,\n node: this\n }]\n\n while (stack.length) {\n frame = stack.pop()\n\n // NOTE: As with the #toString method, we are using\n // Object.keys and a for loop instead of a for-in loop\n // as both of these objects enter 'hash' mode, causing\n // the function to be de-optimised in V8\n var qEdges = Object.keys(frame.qNode.edges),\n qLen = qEdges.length,\n nEdges = Object.keys(frame.node.edges),\n nLen = nEdges.length\n\n for (var q = 0; q < qLen; q++) {\n var qEdge = qEdges[q]\n\n for (var n = 0; n < nLen; n++) {\n var nEdge = nEdges[n]\n\n if (nEdge == qEdge || qEdge == '*') {\n var node = frame.node.edges[nEdge],\n qNode = frame.qNode.edges[qEdge],\n final = node.final && qNode.final,\n next = undefined\n\n if (nEdge in frame.output.edges) {\n // an edge already exists for this character\n // no need to create a new node, just set the finality\n // bit unless this node is already final\n next = frame.output.edges[nEdge]\n next.final = next.final || final\n\n } else {\n // no edge exists yet, must create one\n // set the finality bit and insert it\n // into the output\n next = new lunr.TokenSet\n next.final = final\n frame.output.edges[nEdge] = next\n }\n\n stack.push({\n qNode: qNode,\n output: next,\n node: node\n })\n }\n }\n }\n }\n\n return output\n}\nlunr.TokenSet.Builder = function () {\n this.previousWord = \"\"\n this.root = new lunr.TokenSet\n this.uncheckedNodes = []\n this.minimizedNodes = {}\n}\n\nlunr.TokenSet.Builder.prototype.insert = function (word) {\n var node,\n commonPrefix = 0\n\n if (word < this.previousWord) {\n throw new Error (\"Out of order word insertion\")\n }\n\n for (var i = 0; i < word.length && i < this.previousWord.length; i++) {\n if (word[i] != this.previousWord[i]) break\n commonPrefix++\n }\n\n this.minimize(commonPrefix)\n\n if (this.uncheckedNodes.length == 0) {\n node = this.root\n } else {\n node = this.uncheckedNodes[this.uncheckedNodes.length - 1].child\n }\n\n for (var i = commonPrefix; i < word.length; i++) {\n var nextNode = new lunr.TokenSet,\n char = word[i]\n\n node.edges[char] = nextNode\n\n this.uncheckedNodes.push({\n parent: node,\n char: char,\n child: nextNode\n })\n\n node = nextNode\n }\n\n node.final = true\n this.previousWord = word\n}\n\nlunr.TokenSet.Builder.prototype.finish = function () {\n this.minimize(0)\n}\n\nlunr.TokenSet.Builder.prototype.minimize = function (downTo) {\n for (var i = this.uncheckedNodes.length - 1; i >= downTo; i--) {\n var node = this.uncheckedNodes[i],\n childKey = node.child.toString()\n\n if (childKey in this.minimizedNodes) {\n node.parent.edges[node.char] = this.minimizedNodes[childKey]\n } else {\n // Cache the key for this node since\n // we know it can't change anymore\n node.child._str = childKey\n\n this.minimizedNodes[childKey] = node.child\n }\n\n this.uncheckedNodes.pop()\n }\n}\n/*!\n * lunr.Index\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * An index contains the built index of all documents and provides a query interface\n * to the index.\n *\n * Usually instances of lunr.Index will not be created using this constructor, instead\n * lunr.Builder should be used to construct new indexes, or lunr.Index.load should be\n * used to load previously built and serialized indexes.\n *\n * @constructor\n * @param {Object} attrs - The attributes of the built search index.\n * @param {Object} attrs.invertedIndex - An index of term/field to document reference.\n * @param {Object} attrs.fieldVectors - Field vectors\n * @param {lunr.TokenSet} attrs.tokenSet - An set of all corpus tokens.\n * @param {string[]} attrs.fields - The names of indexed document fields.\n * @param {lunr.Pipeline} attrs.pipeline - The pipeline to use for search terms.\n */\nlunr.Index = function (attrs) {\n this.invertedIndex = attrs.invertedIndex\n this.fieldVectors = attrs.fieldVectors\n this.tokenSet = attrs.tokenSet\n this.fields = attrs.fields\n this.pipeline = attrs.pipeline\n}\n\n/**\n * A result contains details of a document matching a search query.\n * @typedef {Object} lunr.Index~Result\n * @property {string} ref - The reference of the document this result represents.\n * @property {number} score - A number between 0 and 1 representing how similar this document is to the query.\n * @property {lunr.MatchData} matchData - Contains metadata about this match including which term(s) caused the match.\n */\n\n/**\n * Although lunr provides the ability to create queries using lunr.Query, it also provides a simple\n * query language which itself is parsed into an instance of lunr.Query.\n *\n * For programmatically building queries it is advised to directly use lunr.Query, the query language\n * is best used for human entered text rather than program generated text.\n *\n * At its simplest queries can just be a single term, e.g. `hello`, multiple terms are also supported\n * and will be combined with OR, e.g `hello world` will match documents that contain either 'hello'\n * or 'world', though those that contain both will rank higher in the results.\n *\n * Wildcards can be included in terms to match one or more unspecified characters, these wildcards can\n * be inserted anywhere within the term, and more than one wildcard can exist in a single term. Adding\n * wildcards will increase the number of documents that will be found but can also have a negative\n * impact on query performance, especially with wildcards at the beginning of a term.\n *\n * Terms can be restricted to specific fields, e.g. `title:hello`, only documents with the term\n * hello in the title field will match this query. Using a field not present in the index will lead\n * to an error being thrown.\n *\n * Modifiers can also be added to terms, lunr supports edit distance and boost modifiers on terms. A term\n * boost will make documents matching that term score higher, e.g. `foo^5`. Edit distance is also supported\n * to provide fuzzy matching, e.g. 'hello~2' will match documents with hello with an edit distance of 2.\n * Avoid large values for edit distance to improve query performance.\n *\n * Each term also supports a presence modifier. By default a term's presence in document is optional, however\n * this can be changed to either required or prohibited. For a term's presence to be required in a document the\n * term should be prefixed with a '+', e.g. `+foo bar` is a search for documents that must contain 'foo' and\n * optionally contain 'bar'. Conversely a leading '-' sets the terms presence to prohibited, i.e. it must not\n * appear in a document, e.g. `-foo bar` is a search for documents that do not contain 'foo' but may contain 'bar'.\n *\n * To escape special characters the backslash character '\\' can be used, this allows searches to include\n * characters that would normally be considered modifiers, e.g. `foo\\~2` will search for a term \"foo~2\" instead\n * of attempting to apply a boost of 2 to the search term \"foo\".\n *\n * @typedef {string} lunr.Index~QueryString\n * @example Simple single term query\n * hello\n * @example Multiple term query\n * hello world\n * @example term scoped to a field\n * title:hello\n * @example term with a boost of 10\n * hello^10\n * @example term with an edit distance of 2\n * hello~2\n * @example terms with presence modifiers\n * -foo +bar baz\n */\n\n/**\n * Performs a search against the index using lunr query syntax.\n *\n * Results will be returned sorted by their score, the most relevant results\n * will be returned first. For details on how the score is calculated, please see\n * the {@link https://lunrjs.com/guides/searching.html#scoring|guide}.\n *\n * For more programmatic querying use lunr.Index#query.\n *\n * @param {lunr.Index~QueryString} queryString - A string containing a lunr query.\n * @throws {lunr.QueryParseError} If the passed query string cannot be parsed.\n * @returns {lunr.Index~Result[]}\n */\nlunr.Index.prototype.search = function (queryString) {\n return this.query(function (query) {\n var parser = new lunr.QueryParser(queryString, query)\n parser.parse()\n })\n}\n\n/**\n * A query builder callback provides a query object to be used to express\n * the query to perform on the index.\n *\n * @callback lunr.Index~queryBuilder\n * @param {lunr.Query} query - The query object to build up.\n * @this lunr.Query\n */\n\n/**\n * Performs a query against the index using the yielded lunr.Query object.\n *\n * If performing programmatic queries against the index, this method is preferred\n * over lunr.Index#search so as to avoid the additional query parsing overhead.\n *\n * A query object is yielded to the supplied function which should be used to\n * express the query to be run against the index.\n *\n * Note that although this function takes a callback parameter it is _not_ an\n * asynchronous operation, the callback is just yielded a query object to be\n * customized.\n *\n * @param {lunr.Index~queryBuilder} fn - A function that is used to build the query.\n * @returns {lunr.Index~Result[]}\n */\nlunr.Index.prototype.query = function (fn) {\n // for each query clause\n // * process terms\n // * expand terms from token set\n // * find matching documents and metadata\n // * get document vectors\n // * score documents\n\n var query = new lunr.Query(this.fields),\n matchingFields = Object.create(null),\n queryVectors = Object.create(null),\n termFieldCache = Object.create(null),\n requiredMatches = Object.create(null),\n prohibitedMatches = Object.create(null)\n\n /*\n * To support field level boosts a query vector is created per\n * field. An empty vector is eagerly created to support negated\n * queries.\n */\n for (var i = 0; i < this.fields.length; i++) {\n queryVectors[this.fields[i]] = new lunr.Vector\n }\n\n fn.call(query, query)\n\n for (var i = 0; i < query.clauses.length; i++) {\n /*\n * Unless the pipeline has been disabled for this term, which is\n * the case for terms with wildcards, we need to pass the clause\n * term through the search pipeline. A pipeline returns an array\n * of processed terms. Pipeline functions may expand the passed\n * term, which means we may end up performing multiple index lookups\n * for a single query term.\n */\n var clause = query.clauses[i],\n terms = null,\n clauseMatches = lunr.Set.empty\n\n if (clause.usePipeline) {\n terms = this.pipeline.runString(clause.term, {\n fields: clause.fields\n })\n } else {\n terms = [clause.term]\n }\n\n for (var m = 0; m < terms.length; m++) {\n var term = terms[m]\n\n /*\n * Each term returned from the pipeline needs to use the same query\n * clause object, e.g. the same boost and or edit distance. The\n * simplest way to do this is to re-use the clause object but mutate\n * its term property.\n */\n clause.term = term\n\n /*\n * From the term in the clause we create a token set which will then\n * be used to intersect the indexes token set to get a list of terms\n * to lookup in the inverted index\n */\n var termTokenSet = lunr.TokenSet.fromClause(clause),\n expandedTerms = this.tokenSet.intersect(termTokenSet).toArray()\n\n /*\n * If a term marked as required does not exist in the tokenSet it is\n * impossible for the search to return any matches. We set all the field\n * scoped required matches set to empty and stop examining any further\n * clauses.\n */\n if (expandedTerms.length === 0 && clause.presence === lunr.Query.presence.REQUIRED) {\n for (var k = 0; k < clause.fields.length; k++) {\n var field = clause.fields[k]\n requiredMatches[field] = lunr.Set.empty\n }\n\n break\n }\n\n for (var j = 0; j < expandedTerms.length; j++) {\n /*\n * For each term get the posting and termIndex, this is required for\n * building the query vector.\n */\n var expandedTerm = expandedTerms[j],\n posting = this.invertedIndex[expandedTerm],\n termIndex = posting._index\n\n for (var k = 0; k < clause.fields.length; k++) {\n /*\n * For each field that this query term is scoped by (by default\n * all fields are in scope) we need to get all the document refs\n * that have this term in that field.\n *\n * The posting is the entry in the invertedIndex for the matching\n * term from above.\n */\n var field = clause.fields[k],\n fieldPosting = posting[field],\n matchingDocumentRefs = Object.keys(fieldPosting),\n termField = expandedTerm + \"/\" + field,\n matchingDocumentsSet = new lunr.Set(matchingDocumentRefs)\n\n /*\n * if the presence of this term is required ensure that the matching\n * documents are added to the set of required matches for this clause.\n *\n */\n if (clause.presence == lunr.Query.presence.REQUIRED) {\n clauseMatches = clauseMatches.union(matchingDocumentsSet)\n\n if (requiredMatches[field] === undefined) {\n requiredMatches[field] = lunr.Set.complete\n }\n }\n\n /*\n * if the presence of this term is prohibited ensure that the matching\n * documents are added to the set of prohibited matches for this field,\n * creating that set if it does not yet exist.\n */\n if (clause.presence == lunr.Query.presence.PROHIBITED) {\n if (prohibitedMatches[field] === undefined) {\n prohibitedMatches[field] = lunr.Set.empty\n }\n\n prohibitedMatches[field] = prohibitedMatches[field].union(matchingDocumentsSet)\n\n /*\n * Prohibited matches should not be part of the query vector used for\n * similarity scoring and no metadata should be extracted so we continue\n * to the next field\n */\n continue\n }\n\n /*\n * The query field vector is populated using the termIndex found for\n * the term and a unit value with the appropriate boost applied.\n * Using upsert because there could already be an entry in the vector\n * for the term we are working with. In that case we just add the scores\n * together.\n */\n queryVectors[field].upsert(termIndex, clause.boost, function (a, b) { return a + b })\n\n /**\n * If we've already seen this term, field combo then we've already collected\n * the matching documents and metadata, no need to go through all that again\n */\n if (termFieldCache[termField]) {\n continue\n }\n\n for (var l = 0; l < matchingDocumentRefs.length; l++) {\n /*\n * All metadata for this term/field/document triple\n * are then extracted and collected into an instance\n * of lunr.MatchData ready to be returned in the query\n * results\n */\n var matchingDocumentRef = matchingDocumentRefs[l],\n matchingFieldRef = new lunr.FieldRef (matchingDocumentRef, field),\n metadata = fieldPosting[matchingDocumentRef],\n fieldMatch\n\n if ((fieldMatch = matchingFields[matchingFieldRef]) === undefined) {\n matchingFields[matchingFieldRef] = new lunr.MatchData (expandedTerm, field, metadata)\n } else {\n fieldMatch.add(expandedTerm, field, metadata)\n }\n\n }\n\n termFieldCache[termField] = true\n }\n }\n }\n\n /**\n * If the presence was required we need to update the requiredMatches field sets.\n * We do this after all fields for the term have collected their matches because\n * the clause terms presence is required in _any_ of the fields not _all_ of the\n * fields.\n */\n if (clause.presence === lunr.Query.presence.REQUIRED) {\n for (var k = 0; k < clause.fields.length; k++) {\n var field = clause.fields[k]\n requiredMatches[field] = requiredMatches[field].intersect(clauseMatches)\n }\n }\n }\n\n /**\n * Need to combine the field scoped required and prohibited\n * matching documents into a global set of required and prohibited\n * matches\n */\n var allRequiredMatches = lunr.Set.complete,\n allProhibitedMatches = lunr.Set.empty\n\n for (var i = 0; i < this.fields.length; i++) {\n var field = this.fields[i]\n\n if (requiredMatches[field]) {\n allRequiredMatches = allRequiredMatches.intersect(requiredMatches[field])\n }\n\n if (prohibitedMatches[field]) {\n allProhibitedMatches = allProhibitedMatches.union(prohibitedMatches[field])\n }\n }\n\n var matchingFieldRefs = Object.keys(matchingFields),\n results = [],\n matches = Object.create(null)\n\n /*\n * If the query is negated (contains only prohibited terms)\n * we need to get _all_ fieldRefs currently existing in the\n * index. This is only done when we know that the query is\n * entirely prohibited terms to avoid any cost of getting all\n * fieldRefs unnecessarily.\n *\n * Additionally, blank MatchData must be created to correctly\n * populate the results.\n */\n if (query.isNegated()) {\n matchingFieldRefs = Object.keys(this.fieldVectors)\n\n for (var i = 0; i < matchingFieldRefs.length; i++) {\n var matchingFieldRef = matchingFieldRefs[i]\n var fieldRef = lunr.FieldRef.fromString(matchingFieldRef)\n matchingFields[matchingFieldRef] = new lunr.MatchData\n }\n }\n\n for (var i = 0; i < matchingFieldRefs.length; i++) {\n /*\n * Currently we have document fields that match the query, but we\n * need to return documents. The matchData and scores are combined\n * from multiple fields belonging to the same document.\n *\n * Scores are calculated by field, using the query vectors created\n * above, and combined into a final document score using addition.\n */\n var fieldRef = lunr.FieldRef.fromString(matchingFieldRefs[i]),\n docRef = fieldRef.docRef\n\n if (!allRequiredMatches.contains(docRef)) {\n continue\n }\n\n if (allProhibitedMatches.contains(docRef)) {\n continue\n }\n\n var fieldVector = this.fieldVectors[fieldRef],\n score = queryVectors[fieldRef.fieldName].similarity(fieldVector),\n docMatch\n\n if ((docMatch = matches[docRef]) !== undefined) {\n docMatch.score += score\n docMatch.matchData.combine(matchingFields[fieldRef])\n } else {\n var match = {\n ref: docRef,\n score: score,\n matchData: matchingFields[fieldRef]\n }\n matches[docRef] = match\n results.push(match)\n }\n }\n\n /*\n * Sort the results objects by score, highest first.\n */\n return results.sort(function (a, b) {\n return b.score - a.score\n })\n}\n\n/**\n * Prepares the index for JSON serialization.\n *\n * The schema for this JSON blob will be described in a\n * separate JSON schema file.\n *\n * @returns {Object}\n */\nlunr.Index.prototype.toJSON = function () {\n var invertedIndex = Object.keys(this.invertedIndex)\n .sort()\n .map(function (term) {\n return [term, this.invertedIndex[term]]\n }, this)\n\n var fieldVectors = Object.keys(this.fieldVectors)\n .map(function (ref) {\n return [ref, this.fieldVectors[ref].toJSON()]\n }, this)\n\n return {\n version: lunr.version,\n fields: this.fields,\n fieldVectors: fieldVectors,\n invertedIndex: invertedIndex,\n pipeline: this.pipeline.toJSON()\n }\n}\n\n/**\n * Loads a previously serialized lunr.Index\n *\n * @param {Object} serializedIndex - A previously serialized lunr.Index\n * @returns {lunr.Index}\n */\nlunr.Index.load = function (serializedIndex) {\n var attrs = {},\n fieldVectors = {},\n serializedVectors = serializedIndex.fieldVectors,\n invertedIndex = Object.create(null),\n serializedInvertedIndex = serializedIndex.invertedIndex,\n tokenSetBuilder = new lunr.TokenSet.Builder,\n pipeline = lunr.Pipeline.load(serializedIndex.pipeline)\n\n if (serializedIndex.version != lunr.version) {\n lunr.utils.warn(\"Version mismatch when loading serialised index. Current version of lunr '\" + lunr.version + \"' does not match serialized index '\" + serializedIndex.version + \"'\")\n }\n\n for (var i = 0; i < serializedVectors.length; i++) {\n var tuple = serializedVectors[i],\n ref = tuple[0],\n elements = tuple[1]\n\n fieldVectors[ref] = new lunr.Vector(elements)\n }\n\n for (var i = 0; i < serializedInvertedIndex.length; i++) {\n var tuple = serializedInvertedIndex[i],\n term = tuple[0],\n posting = tuple[1]\n\n tokenSetBuilder.insert(term)\n invertedIndex[term] = posting\n }\n\n tokenSetBuilder.finish()\n\n attrs.fields = serializedIndex.fields\n\n attrs.fieldVectors = fieldVectors\n attrs.invertedIndex = invertedIndex\n attrs.tokenSet = tokenSetBuilder.root\n attrs.pipeline = pipeline\n\n return new lunr.Index(attrs)\n}\n/*!\n * lunr.Builder\n * Copyright (C) 2020 Oliver Nightingale\n */\n\n/**\n * lunr.Builder performs indexing on a set of documents and\n * returns instances of lunr.Index ready for querying.\n *\n * All configuration of the index is done via the builder, the\n * fields to index, the document reference, the text processing\n * pipeline and document scoring parameters are all set on the\n * builder before indexing.\n *\n * @constructor\n * @property {string} _ref - Internal reference to the document reference field.\n * @property {string[]} _fields - Internal reference to the document fields to index.\n * @property {object} invertedIndex - The inverted index maps terms to document fields.\n * @property {object} documentTermFrequencies - Keeps track of document term frequencies.\n * @property {object} documentLengths - Keeps track of the length of documents added to the index.\n * @property {lunr.tokenizer} tokenizer - Function for splitting strings into tokens for indexing.\n * @property {lunr.Pipeline} pipeline - The pipeline performs text processing on tokens before indexing.\n * @property {lunr.Pipeline} searchPipeline - A pipeline for processing search terms before querying the index.\n * @property {number} documentCount - Keeps track of the total number of documents indexed.\n * @property {number} _b - A parameter to control field length normalization, setting this to 0 disabled normalization, 1 fully normalizes field lengths, the default value is 0.75.\n * @property {number} _k1 - A parameter to control how quickly an increase in term frequency results in term frequency saturation, the default value is 1.2.\n * @property {number} termIndex - A counter incremented for each unique term, used to identify a terms position in the vector space.\n * @property {array} metadataWhitelist - A list of metadata keys that have been whitelisted for entry in the index.\n */\nlunr.Builder = function () {\n this._ref = \"id\"\n this._fields = Object.create(null)\n this._documents = Object.create(null)\n this.invertedIndex = Object.create(null)\n this.fieldTermFrequencies = {}\n this.fieldLengths = {}\n this.tokenizer = lunr.tokenizer\n this.pipeline = new lunr.Pipeline\n this.searchPipeline = new lunr.Pipeline\n this.documentCount = 0\n this._b = 0.75\n this._k1 = 1.2\n this.termIndex = 0\n this.metadataWhitelist = []\n}\n\n/**\n * Sets the document field used as the document reference. Every document must have this field.\n * The type of this field in the document should be a string, if it is not a string it will be\n * coerced into a string by calling toString.\n *\n * The default ref is 'id'.\n *\n * The ref should _not_ be changed during indexing, it should be set before any documents are\n * added to the index. Changing it during indexing can lead to inconsistent results.\n *\n * @param {string} ref - The name of the reference field in the document.\n */\nlunr.Builder.prototype.ref = function (ref) {\n this._ref = ref\n}\n\n/**\n * A function that is used to extract a field from a document.\n *\n * Lunr expects a field to be at the top level of a document, if however the field\n * is deeply nested within a document an extractor function can be used to extract\n * the right field for indexing.\n *\n * @callback fieldExtractor\n * @param {object} doc - The document being added to the index.\n * @returns {?(string|object|object[])} obj - The object that will be indexed for this field.\n * @example Extracting a nested field\n * function (doc) { return doc.nested.field }\n */\n\n/**\n * Adds a field to the list of document fields that will be indexed. Every document being\n * indexed should have this field. Null values for this field in indexed documents will\n * not cause errors but will limit the chance of that document being retrieved by searches.\n *\n * All fields should be added before adding documents to the index. Adding fields after\n * a document has been indexed will have no effect on already indexed documents.\n *\n * Fields can be boosted at build time. This allows terms within that field to have more\n * importance when ranking search results. Use a field boost to specify that matches within\n * one field are more important than other fields.\n *\n * @param {string} fieldName - The name of a field to index in all documents.\n * @param {object} attributes - Optional attributes associated with this field.\n * @param {number} [attributes.boost=1] - Boost applied to all terms within this field.\n * @param {fieldExtractor} [attributes.extractor] - Function to extract a field from a document.\n * @throws {RangeError} fieldName cannot contain unsupported characters '/'\n */\nlunr.Builder.prototype.field = function (fieldName, attributes) {\n if (/\\//.test(fieldName)) {\n throw new RangeError (\"Field '\" + fieldName + \"' contains illegal character '/'\")\n }\n\n this._fields[fieldName] = attributes || {}\n}\n\n/**\n * A parameter to tune the amount of field length normalisation that is applied when\n * calculating relevance scores. A value of 0 will completely disable any normalisation\n * and a value of 1 will fully normalise field lengths. The default is 0.75. Values of b\n * will be clamped to the range 0 - 1.\n *\n * @param {number} number - The value to set for this tuning parameter.\n */\nlunr.Builder.prototype.b = function (number) {\n if (number < 0) {\n this._b = 0\n } else if (number > 1) {\n this._b = 1\n } else {\n this._b = number\n }\n}\n\n/**\n * A parameter that controls the speed at which a rise in term frequency results in term\n * frequency saturation. The default value is 1.2. Setting this to a higher value will give\n * slower saturation levels, a lower value will result in quicker saturation.\n *\n * @param {number} number - The value to set for this tuning parameter.\n */\nlunr.Builder.prototype.k1 = function (number) {\n this._k1 = number\n}\n\n/**\n * Adds a document to the index.\n *\n * Before adding fields to the index the index should have been fully setup, with the document\n * ref and all fields to index already having been specified.\n *\n * The document must have a field name as specified by the ref (by default this is 'id') and\n * it should have all fields defined for indexing, though null or undefined values will not\n * cause errors.\n *\n * Entire documents can be boosted at build time. Applying a boost to a document indicates that\n * this document should rank higher in search results than other documents.\n *\n * @param {object} doc - The document to add to the index.\n * @param {object} attributes - Optional attributes associated with this document.\n * @param {number} [attributes.boost=1] - Boost applied to all terms within this document.\n */\nlunr.Builder.prototype.add = function (doc, attributes) {\n var docRef = doc[this._ref],\n fields = Object.keys(this._fields)\n\n this._documents[docRef] = attributes || {}\n this.documentCount += 1\n\n for (var i = 0; i < fields.length; i++) {\n var fieldName = fields[i],\n extractor = this._fields[fieldName].extractor,\n field = extractor ? extractor(doc) : doc[fieldName],\n tokens = this.tokenizer(field, {\n fields: [fieldName]\n }),\n terms = this.pipeline.run(tokens),\n fieldRef = new lunr.FieldRef (docRef, fieldName),\n fieldTerms = Object.create(null)\n\n this.fieldTermFrequencies[fieldRef] = fieldTerms\n this.fieldLengths[fieldRef] = 0\n\n // store the length of this field for this document\n this.fieldLengths[fieldRef] += terms.length\n\n // calculate term frequencies for this field\n for (var j = 0; j < terms.length; j++) {\n var term = terms[j]\n\n if (fieldTerms[term] == undefined) {\n fieldTerms[term] = 0\n }\n\n fieldTerms[term] += 1\n\n // add to inverted index\n // create an initial posting if one doesn't exist\n if (this.invertedIndex[term] == undefined) {\n var posting = Object.create(null)\n posting[\"_index\"] = this.termIndex\n this.termIndex += 1\n\n for (var k = 0; k < fields.length; k++) {\n posting[fields[k]] = Object.create(null)\n }\n\n this.invertedIndex[term] = posting\n }\n\n // add an entry for this term/fieldName/docRef to the invertedIndex\n if (this.invertedIndex[term][fieldName][docRef] == undefined) {\n this.invertedIndex[term][fieldName][docRef] = Object.create(null)\n }\n\n // store all whitelisted metadata about this token in the\n // inverted index\n for (var l = 0; l < this.metadataWhitelist.length; l++) {\n var metadataKey = this.metadataWhitelist[l],\n metadata = term.metadata[metadataKey]\n\n if (this.invertedIndex[term][fieldName][docRef][metadataKey] == undefined) {\n this.invertedIndex[term][fieldName][docRef][metadataKey] = []\n }\n\n this.invertedIndex[term][fieldName][docRef][metadataKey].push(metadata)\n }\n }\n\n }\n}\n\n/**\n * Calculates the average document length for this index\n *\n * @private\n */\nlunr.Builder.prototype.calculateAverageFieldLengths = function () {\n\n var fieldRefs = Object.keys(this.fieldLengths),\n numberOfFields = fieldRefs.length,\n accumulator = {},\n documentsWithField = {}\n\n for (var i = 0; i < numberOfFields; i++) {\n var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]),\n field = fieldRef.fieldName\n\n documentsWithField[field] || (documentsWithField[field] = 0)\n documentsWithField[field] += 1\n\n accumulator[field] || (accumulator[field] = 0)\n accumulator[field] += this.fieldLengths[fieldRef]\n }\n\n var fields = Object.keys(this._fields)\n\n for (var i = 0; i < fields.length; i++) {\n var fieldName = fields[i]\n accumulator[fieldName] = accumulator[fieldName] / documentsWithField[fieldName]\n }\n\n this.averageFieldLength = accumulator\n}\n\n/**\n * Builds a vector space model of every document using lunr.Vector\n *\n * @private\n */\nlunr.Builder.prototype.createFieldVectors = function () {\n var fieldVectors = {},\n fieldRefs = Object.keys(this.fieldTermFrequencies),\n fieldRefsLength = fieldRefs.length,\n termIdfCache = Object.create(null)\n\n for (var i = 0; i < fieldRefsLength; i++) {\n var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]),\n fieldName = fieldRef.fieldName,\n fieldLength = this.fieldLengths[fieldRef],\n fieldVector = new lunr.Vector,\n termFrequencies = this.fieldTermFrequencies[fieldRef],\n terms = Object.keys(termFrequencies),\n termsLength = terms.length\n\n\n var fieldBoost = this._fields[fieldName].boost || 1,\n docBoost = this._documents[fieldRef.docRef].boost || 1\n\n for (var j = 0; j < termsLength; j++) {\n var term = terms[j],\n tf = termFrequencies[term],\n termIndex = this.invertedIndex[term]._index,\n idf, score, scoreWithPrecision\n\n if (termIdfCache[term] === undefined) {\n idf = lunr.idf(this.invertedIndex[term], this.documentCount)\n termIdfCache[term] = idf\n } else {\n idf = termIdfCache[term]\n }\n\n score = idf * ((this._k1 + 1) * tf) / (this._k1 * (1 - this._b + this._b * (fieldLength / this.averageFieldLength[fieldName])) + tf)\n score *= fieldBoost\n score *= docBoost\n scoreWithPrecision = Math.round(score * 1000) / 1000\n // Converts 1.23456789 to 1.234.\n // Reducing the precision so that the vectors take up less\n // space when serialised. Doing it now so that they behave\n // the same before and after serialisation. Also, this is\n // the fastest approach to reducing a number's precision in\n // JavaScript.\n\n fieldVector.insert(termIndex, scoreWithPrecision)\n }\n\n fieldVectors[fieldRef] = fieldVector\n }\n\n this.fieldVectors = fieldVectors\n}\n\n/**\n * Creates a token set of all tokens in the index using lunr.TokenSet\n *\n * @private\n */\nlunr.Builder.prototype.createTokenSet = function () {\n this.tokenSet = lunr.TokenSet.fromArray(\n Object.keys(this.invertedIndex).sort()\n )\n}\n\n/**\n * Builds the index, creating an instance of lunr.Index.\n *\n * This completes the indexing process and should only be called\n * once all documents have been added to the index.\n *\n * @returns {lunr.Index}\n */\nlunr.Builder.prototype.build = function () {\n this.calculateAverageFieldLengths()\n this.createFieldVectors()\n this.createTokenSet()\n\n return new lunr.Index({\n invertedIndex: this.invertedIndex,\n fieldVectors: this.fieldVectors,\n tokenSet: this.tokenSet,\n fields: Object.keys(this._fields),\n pipeline: this.searchPipeline\n })\n}\n\n/**\n * Applies a plugin to the index builder.\n *\n * A plugin is a function that is called with the index builder as its context.\n * Plugins can be used to customise or extend the behaviour of the index\n * in some way. A plugin is just a function, that encapsulated the custom\n * behaviour that should be applied when building the index.\n *\n * The plugin function will be called with the index builder as its argument, additional\n * arguments can also be passed when calling use. The function will be called\n * with the index builder as its context.\n *\n * @param {Function} plugin The plugin to apply.\n */\nlunr.Builder.prototype.use = function (fn) {\n var args = Array.prototype.slice.call(arguments, 1)\n args.unshift(this)\n fn.apply(this, args)\n}\n/**\n * Contains and collects metadata about a matching document.\n * A single instance of lunr.MatchData is returned as part of every\n * lunr.Index~Result.\n *\n * @constructor\n * @param {string} term - The term this match data is associated with\n * @param {string} field - The field in which the term was found\n * @param {object} metadata - The metadata recorded about this term in this field\n * @property {object} metadata - A cloned collection of metadata associated with this document.\n * @see {@link lunr.Index~Result}\n */\nlunr.MatchData = function (term, field, metadata) {\n var clonedMetadata = Object.create(null),\n metadataKeys = Object.keys(metadata || {})\n\n // Cloning the metadata to prevent the original\n // being mutated during match data combination.\n // Metadata is kept in an array within the inverted\n // index so cloning the data can be done with\n // Array#slice\n for (var i = 0; i < metadataKeys.length; i++) {\n var key = metadataKeys[i]\n clonedMetadata[key] = metadata[key].slice()\n }\n\n this.metadata = Object.create(null)\n\n if (term !== undefined) {\n this.metadata[term] = Object.create(null)\n this.metadata[term][field] = clonedMetadata\n }\n}\n\n/**\n * An instance of lunr.MatchData will be created for every term that matches a\n * document. However only one instance is required in a lunr.Index~Result. This\n * method combines metadata from another instance of lunr.MatchData with this\n * objects metadata.\n *\n * @param {lunr.MatchData} otherMatchData - Another instance of match data to merge with this one.\n * @see {@link lunr.Index~Result}\n */\nlunr.MatchData.prototype.combine = function (otherMatchData) {\n var terms = Object.keys(otherMatchData.metadata)\n\n for (var i = 0; i < terms.length; i++) {\n var term = terms[i],\n fields = Object.keys(otherMatchData.metadata[term])\n\n if (this.metadata[term] == undefined) {\n this.metadata[term] = Object.create(null)\n }\n\n for (var j = 0; j < fields.length; j++) {\n var field = fields[j],\n keys = Object.keys(otherMatchData.metadata[term][field])\n\n if (this.metadata[term][field] == undefined) {\n this.metadata[term][field] = Object.create(null)\n }\n\n for (var k = 0; k < keys.length; k++) {\n var key = keys[k]\n\n if (this.metadata[term][field][key] == undefined) {\n this.metadata[term][field][key] = otherMatchData.metadata[term][field][key]\n } else {\n this.metadata[term][field][key] = this.metadata[term][field][key].concat(otherMatchData.metadata[term][field][key])\n }\n\n }\n }\n }\n}\n\n/**\n * Add metadata for a term/field pair to this instance of match data.\n *\n * @param {string} term - The term this match data is associated with\n * @param {string} field - The field in which the term was found\n * @param {object} metadata - The metadata recorded about this term in this field\n */\nlunr.MatchData.prototype.add = function (term, field, metadata) {\n if (!(term in this.metadata)) {\n this.metadata[term] = Object.create(null)\n this.metadata[term][field] = metadata\n return\n }\n\n if (!(field in this.metadata[term])) {\n this.metadata[term][field] = metadata\n return\n }\n\n var metadataKeys = Object.keys(metadata)\n\n for (var i = 0; i < metadataKeys.length; i++) {\n var key = metadataKeys[i]\n\n if (key in this.metadata[term][field]) {\n this.metadata[term][field][key] = this.metadata[term][field][key].concat(metadata[key])\n } else {\n this.metadata[term][field][key] = metadata[key]\n }\n }\n}\n/**\n * A lunr.Query provides a programmatic way of defining queries to be performed\n * against a {@link lunr.Index}.\n *\n * Prefer constructing a lunr.Query using the {@link lunr.Index#query} method\n * so the query object is pre-initialized with the right index fields.\n *\n * @constructor\n * @property {lunr.Query~Clause[]} clauses - An array of query clauses.\n * @property {string[]} allFields - An array of all available fields in a lunr.Index.\n */\nlunr.Query = function (allFields) {\n this.clauses = []\n this.allFields = allFields\n}\n\n/**\n * Constants for indicating what kind of automatic wildcard insertion will be used when constructing a query clause.\n *\n * This allows wildcards to be added to the beginning and end of a term without having to manually do any string\n * concatenation.\n *\n * The wildcard constants can be bitwise combined to select both leading and trailing wildcards.\n *\n * @constant\n * @default\n * @property {number} wildcard.NONE - The term will have no wildcards inserted, this is the default behaviour\n * @property {number} wildcard.LEADING - Prepend the term with a wildcard, unless a leading wildcard already exists\n * @property {number} wildcard.TRAILING - Append a wildcard to the term, unless a trailing wildcard already exists\n * @see lunr.Query~Clause\n * @see lunr.Query#clause\n * @see lunr.Query#term\n * @example query term with trailing wildcard\n * query.term('foo', { wildcard: lunr.Query.wildcard.TRAILING })\n * @example query term with leading and trailing wildcard\n * query.term('foo', {\n * wildcard: lunr.Query.wildcard.LEADING | lunr.Query.wildcard.TRAILING\n * })\n */\n\nlunr.Query.wildcard = new String (\"*\")\nlunr.Query.wildcard.NONE = 0\nlunr.Query.wildcard.LEADING = 1\nlunr.Query.wildcard.TRAILING = 2\n\n/**\n * Constants for indicating what kind of presence a term must have in matching documents.\n *\n * @constant\n * @enum {number}\n * @see lunr.Query~Clause\n * @see lunr.Query#clause\n * @see lunr.Query#term\n * @example query term with required presence\n * query.term('foo', { presence: lunr.Query.presence.REQUIRED })\n */\nlunr.Query.presence = {\n /**\n * Term's presence in a document is optional, this is the default value.\n */\n OPTIONAL: 1,\n\n /**\n * Term's presence in a document is required, documents that do not contain\n * this term will not be returned.\n */\n REQUIRED: 2,\n\n /**\n * Term's presence in a document is prohibited, documents that do contain\n * this term will not be returned.\n */\n PROHIBITED: 3\n}\n\n/**\n * A single clause in a {@link lunr.Query} contains a term and details on how to\n * match that term against a {@link lunr.Index}.\n *\n * @typedef {Object} lunr.Query~Clause\n * @property {string[]} fields - The fields in an index this clause should be matched against.\n * @property {number} [boost=1] - Any boost that should be applied when matching this clause.\n * @property {number} [editDistance] - Whether the term should have fuzzy matching applied, and how fuzzy the match should be.\n * @property {boolean} [usePipeline] - Whether the term should be passed through the search pipeline.\n * @property {number} [wildcard=lunr.Query.wildcard.NONE] - Whether the term should have wildcards appended or prepended.\n * @property {number} [presence=lunr.Query.presence.OPTIONAL] - The terms presence in any matching documents.\n */\n\n/**\n * Adds a {@link lunr.Query~Clause} to this query.\n *\n * Unless the clause contains the fields to be matched all fields will be matched. In addition\n * a default boost of 1 is applied to the clause.\n *\n * @param {lunr.Query~Clause} clause - The clause to add to this query.\n * @see lunr.Query~Clause\n * @returns {lunr.Query}\n */\nlunr.Query.prototype.clause = function (clause) {\n if (!('fields' in clause)) {\n clause.fields = this.allFields\n }\n\n if (!('boost' in clause)) {\n clause.boost = 1\n }\n\n if (!('usePipeline' in clause)) {\n clause.usePipeline = true\n }\n\n if (!('wildcard' in clause)) {\n clause.wildcard = lunr.Query.wildcard.NONE\n }\n\n if ((clause.wildcard & lunr.Query.wildcard.LEADING) && (clause.term.charAt(0) != lunr.Query.wildcard)) {\n clause.term = \"*\" + clause.term\n }\n\n if ((clause.wildcard & lunr.Query.wildcard.TRAILING) && (clause.term.slice(-1) != lunr.Query.wildcard)) {\n clause.term = \"\" + clause.term + \"*\"\n }\n\n if (!('presence' in clause)) {\n clause.presence = lunr.Query.presence.OPTIONAL\n }\n\n this.clauses.push(clause)\n\n return this\n}\n\n/**\n * A negated query is one in which every clause has a presence of\n * prohibited. These queries require some special processing to return\n * the expected results.\n *\n * @returns boolean\n */\nlunr.Query.prototype.isNegated = function () {\n for (var i = 0; i < this.clauses.length; i++) {\n if (this.clauses[i].presence != lunr.Query.presence.PROHIBITED) {\n return false\n }\n }\n\n return true\n}\n\n/**\n * Adds a term to the current query, under the covers this will create a {@link lunr.Query~Clause}\n * to the list of clauses that make up this query.\n *\n * The term is used as is, i.e. no tokenization will be performed by this method. Instead conversion\n * to a token or token-like string should be done before calling this method.\n *\n * The term will be converted to a string by calling `toString`. Multiple terms can be passed as an\n * array, each term in the array will share the same options.\n *\n * @param {object|object[]} term - The term(s) to add to the query.\n * @param {object} [options] - Any additional properties to add to the query clause.\n * @returns {lunr.Query}\n * @see lunr.Query#clause\n * @see lunr.Query~Clause\n * @example adding a single term to a query\n * query.term(\"foo\")\n * @example adding a single term to a query and specifying search fields, term boost and automatic trailing wildcard\n * query.term(\"foo\", {\n * fields: [\"title\"],\n * boost: 10,\n * wildcard: lunr.Query.wildcard.TRAILING\n * })\n * @example using lunr.tokenizer to convert a string to tokens before using them as terms\n * query.term(lunr.tokenizer(\"foo bar\"))\n */\nlunr.Query.prototype.term = function (term, options) {\n if (Array.isArray(term)) {\n term.forEach(function (t) { this.term(t, lunr.utils.clone(options)) }, this)\n return this\n }\n\n var clause = options || {}\n clause.term = term.toString()\n\n this.clause(clause)\n\n return this\n}\nlunr.QueryParseError = function (message, start, end) {\n this.name = \"QueryParseError\"\n this.message = message\n this.start = start\n this.end = end\n}\n\nlunr.QueryParseError.prototype = new Error\nlunr.QueryLexer = function (str) {\n this.lexemes = []\n this.str = str\n this.length = str.length\n this.pos = 0\n this.start = 0\n this.escapeCharPositions = []\n}\n\nlunr.QueryLexer.prototype.run = function () {\n var state = lunr.QueryLexer.lexText\n\n while (state) {\n state = state(this)\n }\n}\n\nlunr.QueryLexer.prototype.sliceString = function () {\n var subSlices = [],\n sliceStart = this.start,\n sliceEnd = this.pos\n\n for (var i = 0; i < this.escapeCharPositions.length; i++) {\n sliceEnd = this.escapeCharPositions[i]\n subSlices.push(this.str.slice(sliceStart, sliceEnd))\n sliceStart = sliceEnd + 1\n }\n\n subSlices.push(this.str.slice(sliceStart, this.pos))\n this.escapeCharPositions.length = 0\n\n return subSlices.join('')\n}\n\nlunr.QueryLexer.prototype.emit = function (type) {\n this.lexemes.push({\n type: type,\n str: this.sliceString(),\n start: this.start,\n end: this.pos\n })\n\n this.start = this.pos\n}\n\nlunr.QueryLexer.prototype.escapeCharacter = function () {\n this.escapeCharPositions.push(this.pos - 1)\n this.pos += 1\n}\n\nlunr.QueryLexer.prototype.next = function () {\n if (this.pos >= this.length) {\n return lunr.QueryLexer.EOS\n }\n\n var char = this.str.charAt(this.pos)\n this.pos += 1\n return char\n}\n\nlunr.QueryLexer.prototype.width = function () {\n return this.pos - this.start\n}\n\nlunr.QueryLexer.prototype.ignore = function () {\n if (this.start == this.pos) {\n this.pos += 1\n }\n\n this.start = this.pos\n}\n\nlunr.QueryLexer.prototype.backup = function () {\n this.pos -= 1\n}\n\nlunr.QueryLexer.prototype.acceptDigitRun = function () {\n var char, charCode\n\n do {\n char = this.next()\n charCode = char.charCodeAt(0)\n } while (charCode > 47 && charCode < 58)\n\n if (char != lunr.QueryLexer.EOS) {\n this.backup()\n }\n}\n\nlunr.QueryLexer.prototype.more = function () {\n return this.pos < this.length\n}\n\nlunr.QueryLexer.EOS = 'EOS'\nlunr.QueryLexer.FIELD = 'FIELD'\nlunr.QueryLexer.TERM = 'TERM'\nlunr.QueryLexer.EDIT_DISTANCE = 'EDIT_DISTANCE'\nlunr.QueryLexer.BOOST = 'BOOST'\nlunr.QueryLexer.PRESENCE = 'PRESENCE'\n\nlunr.QueryLexer.lexField = function (lexer) {\n lexer.backup()\n lexer.emit(lunr.QueryLexer.FIELD)\n lexer.ignore()\n return lunr.QueryLexer.lexText\n}\n\nlunr.QueryLexer.lexTerm = function (lexer) {\n if (lexer.width() > 1) {\n lexer.backup()\n lexer.emit(lunr.QueryLexer.TERM)\n }\n\n lexer.ignore()\n\n if (lexer.more()) {\n return lunr.QueryLexer.lexText\n }\n}\n\nlunr.QueryLexer.lexEditDistance = function (lexer) {\n lexer.ignore()\n lexer.acceptDigitRun()\n lexer.emit(lunr.QueryLexer.EDIT_DISTANCE)\n return lunr.QueryLexer.lexText\n}\n\nlunr.QueryLexer.lexBoost = function (lexer) {\n lexer.ignore()\n lexer.acceptDigitRun()\n lexer.emit(lunr.QueryLexer.BOOST)\n return lunr.QueryLexer.lexText\n}\n\nlunr.QueryLexer.lexEOS = function (lexer) {\n if (lexer.width() > 0) {\n lexer.emit(lunr.QueryLexer.TERM)\n }\n}\n\n// This matches the separator used when tokenising fields\n// within a document. These should match otherwise it is\n// not possible to search for some tokens within a document.\n//\n// It is possible for the user to change the separator on the\n// tokenizer so it _might_ clash with any other of the special\n// characters already used within the search string, e.g. :.\n//\n// This means that it is possible to change the separator in\n// such a way that makes some words unsearchable using a search\n// string.\nlunr.QueryLexer.termSeparator = lunr.tokenizer.separator\n\nlunr.QueryLexer.lexText = function (lexer) {\n while (true) {\n var char = lexer.next()\n\n if (char == lunr.QueryLexer.EOS) {\n return lunr.QueryLexer.lexEOS\n }\n\n // Escape character is '\\'\n if (char.charCodeAt(0) == 92) {\n lexer.escapeCharacter()\n continue\n }\n\n if (char == \":\") {\n return lunr.QueryLexer.lexField\n }\n\n if (char == \"~\") {\n lexer.backup()\n if (lexer.width() > 0) {\n lexer.emit(lunr.QueryLexer.TERM)\n }\n return lunr.QueryLexer.lexEditDistance\n }\n\n if (char == \"^\") {\n lexer.backup()\n if (lexer.width() > 0) {\n lexer.emit(lunr.QueryLexer.TERM)\n }\n return lunr.QueryLexer.lexBoost\n }\n\n // \"+\" indicates term presence is required\n // checking for length to ensure that only\n // leading \"+\" are considered\n if (char == \"+\" && lexer.width() === 1) {\n lexer.emit(lunr.QueryLexer.PRESENCE)\n return lunr.QueryLexer.lexText\n }\n\n // \"-\" indicates term presence is prohibited\n // checking for length to ensure that only\n // leading \"-\" are considered\n if (char == \"-\" && lexer.width() === 1) {\n lexer.emit(lunr.QueryLexer.PRESENCE)\n return lunr.QueryLexer.lexText\n }\n\n if (char.match(lunr.QueryLexer.termSeparator)) {\n return lunr.QueryLexer.lexTerm\n }\n }\n}\n\nlunr.QueryParser = function (str, query) {\n this.lexer = new lunr.QueryLexer (str)\n this.query = query\n this.currentClause = {}\n this.lexemeIdx = 0\n}\n\nlunr.QueryParser.prototype.parse = function () {\n this.lexer.run()\n this.lexemes = this.lexer.lexemes\n\n var state = lunr.QueryParser.parseClause\n\n while (state) {\n state = state(this)\n }\n\n return this.query\n}\n\nlunr.QueryParser.prototype.peekLexeme = function () {\n return this.lexemes[this.lexemeIdx]\n}\n\nlunr.QueryParser.prototype.consumeLexeme = function () {\n var lexeme = this.peekLexeme()\n this.lexemeIdx += 1\n return lexeme\n}\n\nlunr.QueryParser.prototype.nextClause = function () {\n var completedClause = this.currentClause\n this.query.clause(completedClause)\n this.currentClause = {}\n}\n\nlunr.QueryParser.parseClause = function (parser) {\n var lexeme = parser.peekLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n switch (lexeme.type) {\n case lunr.QueryLexer.PRESENCE:\n return lunr.QueryParser.parsePresence\n case lunr.QueryLexer.FIELD:\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.TERM:\n return lunr.QueryParser.parseTerm\n default:\n var errorMessage = \"expected either a field or a term, found \" + lexeme.type\n\n if (lexeme.str.length >= 1) {\n errorMessage += \" with value '\" + lexeme.str + \"'\"\n }\n\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n}\n\nlunr.QueryParser.parsePresence = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n switch (lexeme.str) {\n case \"-\":\n parser.currentClause.presence = lunr.Query.presence.PROHIBITED\n break\n case \"+\":\n parser.currentClause.presence = lunr.Query.presence.REQUIRED\n break\n default:\n var errorMessage = \"unrecognised presence operator'\" + lexeme.str + \"'\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n var errorMessage = \"expecting term or field, found nothing\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.FIELD:\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.TERM:\n return lunr.QueryParser.parseTerm\n default:\n var errorMessage = \"expecting term or field, found '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseField = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n if (parser.query.allFields.indexOf(lexeme.str) == -1) {\n var possibleFields = parser.query.allFields.map(function (f) { return \"'\" + f + \"'\" }).join(', '),\n errorMessage = \"unrecognised field '\" + lexeme.str + \"', possible fields: \" + possibleFields\n\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n parser.currentClause.fields = [lexeme.str]\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n var errorMessage = \"expecting term, found nothing\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n return lunr.QueryParser.parseTerm\n default:\n var errorMessage = \"expecting term, found '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseTerm = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n parser.currentClause.term = lexeme.str.toLowerCase()\n\n if (lexeme.str.indexOf(\"*\") != -1) {\n parser.currentClause.usePipeline = false\n }\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n parser.nextClause()\n return\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n parser.nextClause()\n return lunr.QueryParser.parseTerm\n case lunr.QueryLexer.FIELD:\n parser.nextClause()\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.EDIT_DISTANCE:\n return lunr.QueryParser.parseEditDistance\n case lunr.QueryLexer.BOOST:\n return lunr.QueryParser.parseBoost\n case lunr.QueryLexer.PRESENCE:\n parser.nextClause()\n return lunr.QueryParser.parsePresence\n default:\n var errorMessage = \"Unexpected lexeme type '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseEditDistance = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n var editDistance = parseInt(lexeme.str, 10)\n\n if (isNaN(editDistance)) {\n var errorMessage = \"edit distance must be numeric\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n parser.currentClause.editDistance = editDistance\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n parser.nextClause()\n return\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n parser.nextClause()\n return lunr.QueryParser.parseTerm\n case lunr.QueryLexer.FIELD:\n parser.nextClause()\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.EDIT_DISTANCE:\n return lunr.QueryParser.parseEditDistance\n case lunr.QueryLexer.BOOST:\n return lunr.QueryParser.parseBoost\n case lunr.QueryLexer.PRESENCE:\n parser.nextClause()\n return lunr.QueryParser.parsePresence\n default:\n var errorMessage = \"Unexpected lexeme type '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\nlunr.QueryParser.parseBoost = function (parser) {\n var lexeme = parser.consumeLexeme()\n\n if (lexeme == undefined) {\n return\n }\n\n var boost = parseInt(lexeme.str, 10)\n\n if (isNaN(boost)) {\n var errorMessage = \"boost must be numeric\"\n throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end)\n }\n\n parser.currentClause.boost = boost\n\n var nextLexeme = parser.peekLexeme()\n\n if (nextLexeme == undefined) {\n parser.nextClause()\n return\n }\n\n switch (nextLexeme.type) {\n case lunr.QueryLexer.TERM:\n parser.nextClause()\n return lunr.QueryParser.parseTerm\n case lunr.QueryLexer.FIELD:\n parser.nextClause()\n return lunr.QueryParser.parseField\n case lunr.QueryLexer.EDIT_DISTANCE:\n return lunr.QueryParser.parseEditDistance\n case lunr.QueryLexer.BOOST:\n return lunr.QueryParser.parseBoost\n case lunr.QueryLexer.PRESENCE:\n parser.nextClause()\n return lunr.QueryParser.parsePresence\n default:\n var errorMessage = \"Unexpected lexeme type '\" + nextLexeme.type + \"'\"\n throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end)\n }\n}\n\n /**\n * export the module via AMD, CommonJS or as a browser global\n * Export code from https://github.com/umdjs/umd/blob/master/returnExports.js\n */\n ;(function (root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module.\n define(factory)\n } else if (typeof exports === 'object') {\n /**\n * Node. Does not work with strict CommonJS, but\n * only CommonJS-like enviroments that support module.exports,\n * like Node.\n */\n module.exports = factory()\n } else {\n // Browser globals (root is window)\n root.lunr = factory()\n }\n }(this, function () {\n /**\n * Just return a value to define the module export.\n * This example returns an object, but the module\n * can return a function as the exported value.\n */\n return lunr\n }))\n})();\n", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport lunr from \"lunr\"\n\nimport { Search, SearchIndexConfig } from \"../../_\"\nimport {\n SearchMessage,\n SearchMessageType\n} from \"../message\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Add support for usage with `iframe-worker` polyfill\n *\n * While `importScripts` is synchronous when executed inside of a web worker,\n * it's not possible to provide a synchronous polyfilled implementation. The\n * cool thing is that awaiting a non-Promise is a noop, so extending the type\n * definition to return a `Promise` shouldn't break anything.\n *\n * @see https://bit.ly/2PjDnXi - GitHub comment\n */\ndeclare global {\n function importScripts(...urls: string[]): Promise | void\n}\n\n/* ----------------------------------------------------------------------------\n * Data\n * ------------------------------------------------------------------------- */\n\n/**\n * Search index\n */\nlet index: Search\n\n/* ----------------------------------------------------------------------------\n * Helper functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch (= import) multi-language support through `lunr-languages`\n *\n * This function automatically imports the stemmers necessary to process the\n * languages, which are defined through the search index configuration.\n *\n * If the worker runs inside of an `iframe` (when using `iframe-worker` as\n * a shim), the base URL for the stemmers to be loaded must be determined by\n * searching for the first `script` element with a `src` attribute, which will\n * contain the contents of this script.\n *\n * @param config - Search index configuration\n *\n * @returns Promise resolving with no result\n */\nasync function setupSearchLanguages(\n config: SearchIndexConfig\n): Promise {\n let base = \"../lunr\"\n\n /* Detect `iframe-worker` and fix base URL */\n if (typeof parent !== \"undefined\" && \"IFrameWorker\" in parent) {\n const worker = document.querySelector(\"script[src]\")!\n const [path] = worker.src.split(\"/worker\")\n\n /* Prefix base with path */\n base = base.replace(\"..\", path)\n }\n\n /* Add scripts for languages */\n const scripts = []\n for (const lang of config.lang) {\n switch (lang) {\n\n /* Add segmenter for Japanese */\n case \"ja\":\n scripts.push(`${base}/tinyseg.js`)\n break\n\n /* Add segmenter for Hindi and Thai */\n case \"hi\":\n case \"th\":\n scripts.push(`${base}/wordcut.js`)\n break\n }\n\n /* Add language support */\n if (lang !== \"en\")\n scripts.push(`${base}/min/lunr.${lang}.min.js`)\n }\n\n /* Add multi-language support */\n if (config.lang.length > 1)\n scripts.push(`${base}/min/lunr.multi.min.js`)\n\n /* Load scripts synchronously */\n if (scripts.length)\n await importScripts(\n `${base}/min/lunr.stemmer.support.min.js`,\n ...scripts\n )\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Message handler\n *\n * @param message - Source message\n *\n * @returns Target message\n */\nexport async function handler(\n message: SearchMessage\n): Promise {\n switch (message.type) {\n\n /* Search setup message */\n case SearchMessageType.SETUP:\n await setupSearchLanguages(message.data.config)\n index = new Search(message.data)\n return {\n type: SearchMessageType.READY\n }\n\n /* Search query message */\n case SearchMessageType.QUERY:\n return {\n type: SearchMessageType.RESULT,\n data: index ? index.search(message.data) : { items: [] }\n }\n\n /* All other messages */\n default:\n throw new TypeError(\"Invalid message type\")\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Worker\n * ------------------------------------------------------------------------- */\n\n/* @ts-expect-error - expose Lunr.js in global scope, or stemmers won't work */\nself.lunr = lunr\n\n/* Handle messages */\naddEventListener(\"message\", async ev => {\n postMessage(await handler(ev.data))\n})\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexDocument } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search document\n */\nexport interface SearchDocument extends SearchIndexDocument {\n parent?: SearchIndexDocument /* Parent article */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search document mapping\n */\nexport type SearchDocumentMap = Map\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search document mapping\n *\n * @param docs - Search index documents\n *\n * @returns Search document map\n */\nexport function setupSearchDocumentMap(\n docs: SearchIndexDocument[]\n): SearchDocumentMap {\n const documents = new Map()\n const parents = new Set()\n for (const doc of docs) {\n const [path, hash] = doc.location.split(\"#\")\n\n /* Extract location and title */\n const location = doc.location\n const title = doc.title\n\n /* Escape and cleanup text */\n const text = escapeHTML(doc.text)\n .replace(/\\s+(?=[,.:;!?])/g, \"\")\n .replace(/\\s+/g, \" \")\n\n /* Handle section */\n if (hash) {\n const parent = documents.get(path)!\n\n /* Ignore first section, override article */\n if (!parents.has(parent)) {\n parent.title = doc.title\n parent.text = text\n\n /* Remember that we processed the article */\n parents.add(parent)\n\n /* Add subsequent section */\n } else {\n documents.set(location, {\n location,\n title,\n text,\n parent\n })\n }\n\n /* Add article */\n } else {\n documents.set(location, {\n location,\n title,\n text\n })\n }\n }\n return documents\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport escapeHTML from \"escape-html\"\n\nimport { SearchIndexConfig } from \"../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search highlight function\n *\n * @param value - Value\n *\n * @returns Highlighted value\n */\nexport type SearchHighlightFn = (value: string) => string\n\n/**\n * Search highlight factory function\n *\n * @param query - Query value\n *\n * @returns Search highlight function\n */\nexport type SearchHighlightFactoryFn = (query: string) => SearchHighlightFn\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Create a search highlighter\n *\n * @param config - Search index configuration\n * @param escape - Whether to escape HTML\n *\n * @returns Search highlight factory function\n */\nexport function setupSearchHighlighter(\n config: SearchIndexConfig, escape: boolean\n): SearchHighlightFactoryFn {\n const separator = new RegExp(config.separator, \"img\")\n const highlight = (_: unknown, data: string, term: string) => {\n return `${data}${term}`\n }\n\n /* Return factory function */\n return (query: string) => {\n query = query\n .replace(/[\\s*+\\-:~^]+/g, \" \")\n .trim()\n\n /* Create search term match expression */\n const match = new RegExp(`(^|${config.separator})(${\n query\n .replace(/[|\\\\{}()[\\]^$+*?.-]/g, \"\\\\$&\")\n .replace(separator, \"|\")\n })`, \"img\")\n\n /* Highlight string value */\n return value => (\n escape\n ? escapeHTML(value)\n : value\n )\n .replace(match, highlight)\n .replace(/<\\/mark>(\\s+)]*>/img, \"$1\")\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search query clause\n */\nexport interface SearchQueryClause {\n presence: lunr.Query.presence /* Clause presence */\n term: string /* Clause term */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search query terms\n */\nexport type SearchQueryTerms = Record\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Parse a search query for analysis\n *\n * @param value - Query value\n *\n * @returns Search query clauses\n */\nexport function parseSearchQuery(\n value: string\n): SearchQueryClause[] {\n const query = new (lunr as any).Query([\"title\", \"text\"])\n const parser = new (lunr as any).QueryParser(value, query)\n\n /* Parse and return query clauses */\n parser.parse()\n return query.clauses\n}\n\n/**\n * Analyze the search query clauses in regard to the search terms found\n *\n * @param query - Search query clauses\n * @param terms - Search terms\n *\n * @returns Search query terms\n */\nexport function getSearchQueryTerms(\n query: SearchQueryClause[], terms: string[]\n): SearchQueryTerms {\n const clauses = new Set(query)\n\n /* Match query clauses against terms */\n const result: SearchQueryTerms = {}\n for (let t = 0; t < terms.length; t++)\n for (const clause of clauses)\n if (terms[t].startsWith(clause.term)) {\n result[clause.term] = true\n clauses.delete(clause)\n }\n\n /* Annotate unmatched query clauses */\n for (const clause of clauses)\n result[clause.term] = false\n\n /* Return query terms */\n return result\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport {\n SearchDocument,\n SearchDocumentMap,\n setupSearchDocumentMap\n} from \"../document\"\nimport {\n SearchHighlightFactoryFn,\n setupSearchHighlighter\n} from \"../highlighter\"\nimport { SearchOptions } from \"../options\"\nimport {\n SearchQueryTerms,\n getSearchQueryTerms,\n parseSearchQuery\n} from \"../query\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search index configuration\n */\nexport interface SearchIndexConfig {\n lang: string[] /* Search languages */\n separator: string /* Search separator */\n}\n\n/**\n * Search index document\n */\nexport interface SearchIndexDocument {\n location: string /* Document location */\n title: string /* Document title */\n text: string /* Document text */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search index\n *\n * This interfaces describes the format of the `search_index.json` file which\n * is automatically built by the MkDocs search plugin.\n */\nexport interface SearchIndex {\n config: SearchIndexConfig /* Search index configuration */\n docs: SearchIndexDocument[] /* Search index documents */\n index?: object /* Prebuilt index */\n options: SearchOptions /* Search options */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search metadata\n */\nexport interface SearchMetadata {\n score: number /* Score (relevance) */\n terms: SearchQueryTerms /* Search query terms */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search result document\n */\nexport type SearchResultDocument = SearchDocument & SearchMetadata\n\n/**\n * Search result item\n */\nexport type SearchResultItem = SearchResultDocument[]\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Search result\n */\nexport interface SearchResult {\n items: SearchResultItem[] /* Search result items */\n suggestions?: string[] /* Search suggestions */\n}\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Compute the difference of two lists of strings\n *\n * @param a - 1st list of strings\n * @param b - 2nd list of strings\n *\n * @returns Difference\n */\nfunction difference(a: string[], b: string[]): string[] {\n const [x, y] = [new Set(a), new Set(b)]\n return [\n ...new Set([...x].filter(value => !y.has(value)))\n ]\n}\n\n/* ----------------------------------------------------------------------------\n * Class\n * ------------------------------------------------------------------------- */\n\n/**\n * Search index\n */\nexport class Search {\n\n /**\n * Search document mapping\n *\n * A mapping of URLs (including hash fragments) to the actual articles and\n * sections of the documentation. The search document mapping must be created\n * regardless of whether the index was prebuilt or not, as Lunr.js itself\n * only stores the actual index.\n */\n protected documents: SearchDocumentMap\n\n /**\n * Search highlight factory function\n */\n protected highlight: SearchHighlightFactoryFn\n\n /**\n * The underlying Lunr.js search index\n */\n protected index: lunr.Index\n\n /**\n * Search options\n */\n protected options: SearchOptions\n\n /**\n * Create the search integration\n *\n * @param data - Search index\n */\n public constructor({ config, docs, index, options }: SearchIndex) {\n this.options = options\n\n /* Set up document map and highlighter factory */\n this.documents = setupSearchDocumentMap(docs)\n this.highlight = setupSearchHighlighter(config, false)\n\n /* Set separator for tokenizer */\n lunr.tokenizer.separator = new RegExp(config.separator)\n\n /* If no index was given, create it */\n if (typeof index === \"undefined\") {\n this.index = lunr(function () {\n\n /* Set up multi-language support */\n if (config.lang.length === 1 && config.lang[0] !== \"en\") {\n this.use((lunr as any)[config.lang[0]])\n } else if (config.lang.length > 1) {\n this.use((lunr as any).multiLanguage(...config.lang))\n }\n\n /* Compute functions to be removed from the pipeline */\n const fns = difference([\n \"trimmer\", \"stopWordFilter\", \"stemmer\"\n ], options.pipeline)\n\n /* Remove functions from the pipeline for registered languages */\n for (const lang of config.lang.map(language => (\n language === \"en\" ? lunr : (lunr as any)[language]\n ))) {\n for (const fn of fns) {\n this.pipeline.remove(lang[fn])\n this.searchPipeline.remove(lang[fn])\n }\n }\n\n /* Set up reference */\n this.ref(\"location\")\n\n /* Set up fields */\n this.field(\"title\", { boost: 1e3 })\n this.field(\"text\")\n\n /* Index documents */\n for (const doc of docs)\n this.add(doc)\n })\n\n /* Handle prebuilt index */\n } else {\n this.index = lunr.Index.load(index)\n }\n }\n\n /**\n * Search for matching documents\n *\n * The search index which MkDocs provides is divided up into articles, which\n * contain the whole content of the individual pages, and sections, which only\n * contain the contents of the subsections obtained by breaking the individual\n * pages up at `h1` ... `h6`. As there may be many sections on different pages\n * with identical titles (for example within this very project, e.g. \"Usage\"\n * or \"Installation\"), they need to be put into the context of the containing\n * page. For this reason, section results are grouped within their respective\n * articles which are the top-level results that are returned.\n *\n * @param query - Query value\n *\n * @returns Search results\n */\n public search(query: string): SearchResult {\n if (query) {\n try {\n const highlight = this.highlight(query)\n\n /* Parse query to extract clauses for analysis */\n const clauses = parseSearchQuery(query)\n .filter(clause => (\n clause.presence !== lunr.Query.presence.PROHIBITED\n ))\n\n /* Perform search and post-process results */\n const groups = this.index.search(`${query}*`)\n\n /* Apply post-query boosts based on title and search query terms */\n .reduce((item, { ref, score, matchData }) => {\n const document = this.documents.get(ref)\n if (typeof document !== \"undefined\") {\n const { location, title, text, parent } = document\n\n /* Compute and analyze search query terms */\n const terms = getSearchQueryTerms(\n clauses,\n Object.keys(matchData.metadata)\n )\n\n /* Highlight title and text and apply post-query boosts */\n const boost = +!parent + +Object.values(terms).every(t => t)\n item.push({\n location,\n title: highlight(title),\n text: highlight(text),\n score: score * (1 + boost),\n terms\n })\n }\n return item\n }, [])\n\n /* Sort search results again after applying boosts */\n .sort((a, b) => b.score - a.score)\n\n /* Group search results by page */\n .reduce((items, result) => {\n const document = this.documents.get(result.location)\n if (typeof document !== \"undefined\") {\n const ref = \"parent\" in document\n ? document.parent!.location\n : document.location\n items.set(ref, [...items.get(ref) || [], result])\n }\n return items\n }, new Map())\n\n /* Generate search suggestions, if desired */\n let suggestions: string[] | undefined\n if (this.options.suggestions) {\n const titles = this.index.query(builder => {\n for (const clause of clauses)\n builder.term(clause.term, {\n fields: [\"title\"],\n presence: lunr.Query.presence.REQUIRED,\n wildcard: lunr.Query.wildcard.TRAILING\n })\n })\n\n /* Retrieve suggestions for best match */\n suggestions = titles.length\n ? Object.keys(titles[0].matchData.metadata)\n : []\n }\n\n /* Return items and suggestions */\n return {\n items: [...groups.values()],\n ...typeof suggestions !== \"undefined\" && { suggestions }\n }\n\n /* Log errors to console (for now) */\n } catch {\n console.warn(`Invalid query: ${query} \u2013 see https://bit.ly/2s3ChXG`)\n }\n }\n\n /* Return nothing in case of error or empty query */\n return { items: [] }\n }\n}\n", "/*\n * Copyright (c) 2016-2021 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A RTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport { SearchIndex, SearchResult } from \"../../_\"\n\n/* ----------------------------------------------------------------------------\n * Types\n * ------------------------------------------------------------------------- */\n\n/**\n * Search message type\n */\nexport const enum SearchMessageType {\n SETUP, /* Search index setup */\n READY, /* Search index ready */\n QUERY, /* Search query */\n RESULT /* Search results */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Message containing the data necessary to setup the search index\n */\nexport interface SearchSetupMessage {\n type: SearchMessageType.SETUP /* Message type */\n data: SearchIndex /* Message data */\n}\n\n/**\n * Message indicating the search index is ready\n */\nexport interface SearchReadyMessage {\n type: SearchMessageType.READY /* Message type */\n}\n\n/**\n * Message containing a search query\n */\nexport interface SearchQueryMessage {\n type: SearchMessageType.QUERY /* Message type */\n data: string /* Message data */\n}\n\n/**\n * Message containing results for a search query\n */\nexport interface SearchResultMessage {\n type: SearchMessageType.RESULT /* Message type */\n data: SearchResult /* Message data */\n}\n\n/* ------------------------------------------------------------------------- */\n\n/**\n * Message exchanged with the search worker\n */\nexport type SearchMessage =\n | SearchSetupMessage\n | SearchReadyMessage\n | SearchQueryMessage\n | SearchResultMessage\n\n/* ----------------------------------------------------------------------------\n * Functions\n * ------------------------------------------------------------------------- */\n\n/**\n * Type guard for search setup messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchSetupMessage(\n message: SearchMessage\n): message is SearchSetupMessage {\n return message.type === SearchMessageType.SETUP\n}\n\n/**\n * Type guard for search ready messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchReadyMessage(\n message: SearchMessage\n): message is SearchReadyMessage {\n return message.type === SearchMessageType.READY\n}\n\n/**\n * Type guard for search query messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchQueryMessage(\n message: SearchMessage\n): message is SearchQueryMessage {\n return message.type === SearchMessageType.QUERY\n}\n\n/**\n * Type guard for search result messages\n *\n * @param message - Search worker message\n *\n * @returns Test result\n */\nexport function isSearchResultMessage(\n message: SearchMessage\n): message is SearchResultMessage {\n return message.type === SearchMessageType.RESULT\n}\n"], + "mappings": "gmCAAA;AAAA;AAAA;AAAA;AAAA,GAMC,AAAC,WAAU,CAiCZ,GAAI,GAAO,SAAU,EAAQ,CAC3B,GAAI,GAAU,GAAI,GAAK,QAEvB,SAAQ,SAAS,IACf,EAAK,QACL,EAAK,eACL,EAAK,SAGP,EAAQ,eAAe,IACrB,EAAK,SAGP,EAAO,KAAK,EAAS,GACd,EAAQ,SAGjB,EAAK,QAAU,QACf;AAAA;AAAA;AAAA,GASA,EAAK,MAAQ,GASb,EAAK,MAAM,KAAQ,SAAU,EAAQ,CAEnC,MAAO,UAAU,EAAS,CACxB,AAAI,EAAO,SAAW,QAAQ,MAC5B,QAAQ,KAAK,KAIhB,MAaH,EAAK,MAAM,SAAW,SAAU,EAAK,CACnC,MAAI,AAAkB,IAAQ,KACrB,GAEA,EAAI,YAoBf,EAAK,MAAM,MAAQ,SAAU,EAAK,CAChC,GAAI,GAAQ,KACV,MAAO,GAMT,OAHI,GAAQ,OAAO,OAAO,MACtB,EAAO,OAAO,KAAK,GAEd,EAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,GAAI,GAAM,EAAK,GACX,EAAM,EAAI,GAEd,GAAI,MAAM,QAAQ,GAAM,CACtB,EAAM,GAAO,EAAI,QACjB,SAGF,GAAI,MAAO,IAAQ,UACf,MAAO,IAAQ,UACf,MAAO,IAAQ,UAAW,CAC5B,EAAM,GAAO,EACb,SAGF,KAAM,IAAI,WAAU,yDAGtB,MAAO,IAET,EAAK,SAAW,SAAU,EAAQ,EAAW,EAAa,CACxD,KAAK,OAAS,EACd,KAAK,UAAY,EACjB,KAAK,aAAe,GAGtB,EAAK,SAAS,OAAS,IAEvB,EAAK,SAAS,WAAa,SAAU,EAAG,CACtC,GAAI,GAAI,EAAE,QAAQ,EAAK,SAAS,QAEhC,GAAI,IAAM,GACR,KAAM,6BAGR,GAAI,GAAW,EAAE,MAAM,EAAG,GACtB,EAAS,EAAE,MAAM,EAAI,GAEzB,MAAO,IAAI,GAAK,SAAU,EAAQ,EAAU,IAG9C,EAAK,SAAS,UAAU,SAAW,UAAY,CAC7C,MAAI,MAAK,cAAgB,MACvB,MAAK,aAAe,KAAK,UAAY,EAAK,SAAS,OAAS,KAAK,QAG5D,KAAK,cAEd;AAAA;AAAA;AAAA,GAUA,EAAK,IAAM,SAAU,EAAU,CAG7B,GAFA,KAAK,SAAW,OAAO,OAAO,MAE1B,EAAU,CACZ,KAAK,OAAS,EAAS,OAEvB,OAAS,GAAI,EAAG,EAAI,KAAK,OAAQ,IAC/B,KAAK,SAAS,EAAS,IAAM,OAG/B,MAAK,OAAS,GAWlB,EAAK,IAAI,SAAW,CAClB,UAAW,SAAU,EAAO,CAC1B,MAAO,IAGT,MAAO,UAAY,CACjB,MAAO,OAGT,SAAU,UAAY,CACpB,MAAO,KAWX,EAAK,IAAI,MAAQ,CACf,UAAW,UAAY,CACrB,MAAO,OAGT,MAAO,SAAU,EAAO,CACtB,MAAO,IAGT,SAAU,UAAY,CACpB,MAAO,KAUX,EAAK,IAAI,UAAU,SAAW,SAAU,EAAQ,CAC9C,MAAO,CAAC,CAAC,KAAK,SAAS,IAWzB,EAAK,IAAI,UAAU,UAAY,SAAU,EAAO,CAC9C,GAAI,GAAG,EAAG,EAAU,EAAe,GAEnC,GAAI,IAAU,EAAK,IAAI,SACrB,MAAO,MAGT,GAAI,IAAU,EAAK,IAAI,MACrB,MAAO,GAGT,AAAI,KAAK,OAAS,EAAM,OACtB,GAAI,KACJ,EAAI,GAEJ,GAAI,EACJ,EAAI,MAGN,EAAW,OAAO,KAAK,EAAE,UAEzB,OAAS,GAAI,EAAG,EAAI,EAAS,OAAQ,IAAK,CACxC,GAAI,GAAU,EAAS,GACvB,AAAI,IAAW,GAAE,UACf,EAAa,KAAK,GAItB,MAAO,IAAI,GAAK,IAAK,IAUvB,EAAK,IAAI,UAAU,MAAQ,SAAU,EAAO,CAC1C,MAAI,KAAU,EAAK,IAAI,SACd,EAAK,IAAI,SAGd,IAAU,EAAK,IAAI,MACd,KAGF,GAAI,GAAK,IAAI,OAAO,KAAK,KAAK,UAAU,OAAO,OAAO,KAAK,EAAM,aAU1E,EAAK,IAAM,SAAU,EAAS,EAAe,CAC3C,GAAI,GAAoB,EAExB,OAAS,KAAa,GACpB,AAAI,GAAa,UACjB,IAAqB,OAAO,KAAK,EAAQ,IAAY,QAGvD,GAAI,GAAK,GAAgB,EAAoB,IAAQ,GAAoB,IAEzE,MAAO,MAAK,IAAI,EAAI,KAAK,IAAI,KAW/B,EAAK,MAAQ,SAAU,EAAK,EAAU,CACpC,KAAK,IAAM,GAAO,GAClB,KAAK,SAAW,GAAY,IAQ9B,EAAK,MAAM,UAAU,SAAW,UAAY,CAC1C,MAAO,MAAK,KAuBd,EAAK,MAAM,UAAU,OAAS,SAAU,EAAI,CAC1C,YAAK,IAAM,EAAG,KAAK,IAAK,KAAK,UACtB,MAUT,EAAK,MAAM,UAAU,MAAQ,SAAU,EAAI,CACzC,SAAK,GAAM,SAAU,EAAG,CAAE,MAAO,IAC1B,GAAI,GAAK,MAAO,EAAG,KAAK,IAAK,KAAK,UAAW,KAAK,WAE3D;AAAA;AAAA;AAAA,GAuBA,EAAK,UAAY,SAAU,EAAK,EAAU,CACxC,GAAI,GAAO,MAAQ,GAAO,KACxB,MAAO,GAGT,GAAI,MAAM,QAAQ,GAChB,MAAO,GAAI,IAAI,SAAU,EAAG,CAC1B,MAAO,IAAI,GAAK,MACd,EAAK,MAAM,SAAS,GAAG,cACvB,EAAK,MAAM,MAAM,MASvB,OAJI,GAAM,EAAI,WAAW,cACrB,EAAM,EAAI,OACV,EAAS,GAEJ,EAAW,EAAG,EAAa,EAAG,GAAY,EAAK,IAAY,CAClE,GAAI,GAAO,EAAI,OAAO,GAClB,EAAc,EAAW,EAE7B,GAAK,EAAK,MAAM,EAAK,UAAU,YAAc,GAAY,EAAM,CAE7D,GAAI,EAAc,EAAG,CACnB,GAAI,GAAgB,EAAK,MAAM,MAAM,IAAa,GAClD,EAAc,SAAc,CAAC,EAAY,GACzC,EAAc,MAAW,EAAO,OAEhC,EAAO,KACL,GAAI,GAAK,MACP,EAAI,MAAM,EAAY,GACtB,IAKN,EAAa,EAAW,GAK5B,MAAO,IAUT,EAAK,UAAU,UAAY,UAC3B;AAAA;AAAA;AAAA,GAkCA,EAAK,SAAW,UAAY,CAC1B,KAAK,OAAS,IAGhB,EAAK,SAAS,oBAAsB,OAAO,OAAO,MAmClD,EAAK,SAAS,iBAAmB,SAAU,EAAI,EAAO,CACpD,AAAI,IAAS,MAAK,qBAChB,EAAK,MAAM,KAAK,6CAA+C,GAGjE,EAAG,MAAQ,EACX,EAAK,SAAS,oBAAoB,EAAG,OAAS,GAShD,EAAK,SAAS,4BAA8B,SAAU,EAAI,CACxD,GAAI,GAAe,EAAG,OAAU,EAAG,QAAS,MAAK,oBAEjD,AAAK,GACH,EAAK,MAAM,KAAK;AAAA,EAAmG,IAcvH,EAAK,SAAS,KAAO,SAAU,EAAY,CACzC,GAAI,GAAW,GAAI,GAAK,SAExB,SAAW,QAAQ,SAAU,EAAQ,CACnC,GAAI,GAAK,EAAK,SAAS,oBAAoB,GAE3C,GAAI,EACF,EAAS,IAAI,OAEb,MAAM,IAAI,OAAM,sCAAwC,KAIrD,GAUT,EAAK,SAAS,UAAU,IAAM,UAAY,CACxC,GAAI,GAAM,MAAM,UAAU,MAAM,KAAK,WAErC,EAAI,QAAQ,SAAU,EAAI,CACxB,EAAK,SAAS,4BAA4B,GAC1C,KAAK,OAAO,KAAK,IAChB,OAYL,EAAK,SAAS,UAAU,MAAQ,SAAU,EAAY,EAAO,CAC3D,EAAK,SAAS,4BAA4B,GAE1C,GAAI,GAAM,KAAK,OAAO,QAAQ,GAC9B,GAAI,GAAO,GACT,KAAM,IAAI,OAAM,0BAGlB,EAAM,EAAM,EACZ,KAAK,OAAO,OAAO,EAAK,EAAG,IAY7B,EAAK,SAAS,UAAU,OAAS,SAAU,EAAY,EAAO,CAC5D,EAAK,SAAS,4BAA4B,GAE1C,GAAI,GAAM,KAAK,OAAO,QAAQ,GAC9B,GAAI,GAAO,GACT,KAAM,IAAI,OAAM,0BAGlB,KAAK,OAAO,OAAO,EAAK,EAAG,IAQ7B,EAAK,SAAS,UAAU,OAAS,SAAU,EAAI,CAC7C,GAAI,GAAM,KAAK,OAAO,QAAQ,GAC9B,AAAI,GAAO,IAIX,KAAK,OAAO,OAAO,EAAK,IAU1B,EAAK,SAAS,UAAU,IAAM,SAAU,EAAQ,CAG9C,OAFI,GAAc,KAAK,OAAO,OAErB,EAAI,EAAG,EAAI,EAAa,IAAK,CAIpC,OAHI,GAAK,KAAK,OAAO,GACjB,EAAO,GAEF,EAAI,EAAG,EAAI,EAAO,OAAQ,IAAK,CACtC,GAAI,GAAS,EAAG,EAAO,GAAI,EAAG,GAE9B,GAAI,KAAW,MAA6B,IAAW,IAEvD,GAAI,MAAM,QAAQ,GAChB,OAAS,GAAI,EAAG,EAAI,EAAO,OAAQ,IACjC,EAAK,KAAK,EAAO,QAGnB,GAAK,KAAK,GAId,EAAS,EAGX,MAAO,IAaT,EAAK,SAAS,UAAU,UAAY,SAAU,EAAK,EAAU,CAC3D,GAAI,GAAQ,GAAI,GAAK,MAAO,EAAK,GAEjC,MAAO,MAAK,IAAI,CAAC,IAAQ,IAAI,SAAU,EAAG,CACxC,MAAO,GAAE,cAQb,EAAK,SAAS,UAAU,MAAQ,UAAY,CAC1C,KAAK,OAAS,IAUhB,EAAK,SAAS,UAAU,OAAS,UAAY,CAC3C,MAAO,MAAK,OAAO,IAAI,SAAU,EAAI,CACnC,SAAK,SAAS,4BAA4B,GAEnC,EAAG,SAGd;AAAA;AAAA;AAAA,GAqBA,EAAK,OAAS,SAAU,EAAU,CAChC,KAAK,WAAa,EAClB,KAAK,SAAW,GAAY,IAc9B,EAAK,OAAO,UAAU,iBAAmB,SAAU,EAAO,CAExD,GAAI,KAAK,SAAS,QAAU,EAC1B,MAAO,GAST,OANI,GAAQ,EACR,EAAM,KAAK,SAAS,OAAS,EAC7B,EAAc,EAAM,EACpB,EAAa,KAAK,MAAM,EAAc,GACtC,EAAa,KAAK,SAAS,EAAa,GAErC,EAAc,GACf,GAAa,GACf,GAAQ,GAGN,EAAa,GACf,GAAM,GAGJ,GAAc,IAIlB,EAAc,EAAM,EACpB,EAAa,EAAQ,KAAK,MAAM,EAAc,GAC9C,EAAa,KAAK,SAAS,EAAa,GAO1C,GAJI,GAAc,GAId,EAAa,EACf,MAAO,GAAa,EAGtB,GAAI,EAAa,EACf,MAAQ,GAAa,GAAK,GAa9B,EAAK,OAAO,UAAU,OAAS,SAAU,EAAW,EAAK,CACvD,KAAK,OAAO,EAAW,EAAK,UAAY,CACtC,KAAM,qBAYV,EAAK,OAAO,UAAU,OAAS,SAAU,EAAW,EAAK,EAAI,CAC3D,KAAK,WAAa,EAClB,GAAI,GAAW,KAAK,iBAAiB,GAErC,AAAI,KAAK,SAAS,IAAa,EAC7B,KAAK,SAAS,EAAW,GAAK,EAAG,KAAK,SAAS,EAAW,GAAI,GAE9D,KAAK,SAAS,OAAO,EAAU,EAAG,EAAW,IASjD,EAAK,OAAO,UAAU,UAAY,UAAY,CAC5C,GAAI,KAAK,WAAY,MAAO,MAAK,WAKjC,OAHI,GAAe,EACf,EAAiB,KAAK,SAAS,OAE1B,EAAI,EAAG,EAAI,EAAgB,GAAK,EAAG,CAC1C,GAAI,GAAM,KAAK,SAAS,GACxB,GAAgB,EAAM,EAGxB,MAAO,MAAK,WAAa,KAAK,KAAK,IASrC,EAAK,OAAO,UAAU,IAAM,SAAU,EAAa,CAOjD,OANI,GAAa,EACb,EAAI,KAAK,SAAU,EAAI,EAAY,SACnC,EAAO,EAAE,OAAQ,EAAO,EAAE,OAC1B,EAAO,EAAG,EAAO,EACjB,EAAI,EAAG,EAAI,EAER,EAAI,GAAQ,EAAI,GACrB,EAAO,EAAE,GAAI,EAAO,EAAE,GACtB,AAAI,EAAO,EACT,GAAK,EACA,AAAI,EAAO,EAChB,GAAK,EACI,GAAQ,GACjB,IAAc,EAAE,EAAI,GAAK,EAAE,EAAI,GAC/B,GAAK,EACL,GAAK,GAIT,MAAO,IAUT,EAAK,OAAO,UAAU,WAAa,SAAU,EAAa,CACxD,MAAO,MAAK,IAAI,GAAe,KAAK,aAAe,GAQrD,EAAK,OAAO,UAAU,QAAU,UAAY,CAG1C,OAFI,GAAS,GAAI,OAAO,KAAK,SAAS,OAAS,GAEtC,EAAI,EAAG,EAAI,EAAG,EAAI,KAAK,SAAS,OAAQ,GAAK,EAAG,IACvD,EAAO,GAAK,KAAK,SAAS,GAG5B,MAAO,IAQT,EAAK,OAAO,UAAU,OAAS,UAAY,CACzC,MAAO,MAAK,UAGd;AAAA;AAAA;AAAA;AAAA,GAiBA,EAAK,QAAW,UAAU,CACxB,GAAI,GAAY,CACZ,QAAY,MACZ,OAAW,OACX,KAAS,OACT,KAAS,OACT,KAAS,MACT,IAAQ,MACR,KAAS,KACT,MAAU,MACV,IAAQ,IACR,MAAU,MACV,QAAY,MACZ,MAAU,MACV,KAAS,MACT,MAAU,KACV,QAAY,MACZ,QAAY,MACZ,QAAY,MACZ,MAAU,KACV,MAAU,MACV,OAAW,MACX,KAAS,OAGX,EAAY,CACV,MAAU,KACV,MAAU,GACV,MAAU,KACV,MAAU,KACV,KAAS,KACT,IAAQ,GACR,KAAS,IAGX,EAAI,WACJ,EAAI,WACJ,EAAI,EAAI,aACR,EAAI,EAAI,WAER,EAAO,KAAO,EAAI,KAAO,EAAI,EAC7B,EAAO,KAAO,EAAI,KAAO,EAAI,EAAI,IAAM,EAAI,MAC3C,EAAO,KAAO,EAAI,KAAO,EAAI,EAAI,EAAI,EACrC,EAAM,KAAO,EAAI,KAAO,EAEtB,EAAU,GAAI,QAAO,GACrB,EAAU,GAAI,QAAO,GACrB,EAAU,GAAI,QAAO,GACrB,EAAS,GAAI,QAAO,GAEpB,EAAQ,kBACR,EAAS,iBACT,EAAQ,aACR,EAAS,kBACT,EAAU,KACV,EAAW,cACX,EAAW,GAAI,QAAO,sBACtB,EAAW,GAAI,QAAO,IAAM,EAAI,EAAI,gBAEpC,EAAQ,mBACR,EAAO,2IAEP,EAAO,iDAEP,EAAO,sFACP,EAAQ,oBAER,EAAO,WACP,EAAS,MACT,EAAQ,GAAI,QAAO,IAAM,EAAI,EAAI,gBAEjC,EAAgB,SAAuB,EAAG,CAC5C,GAAI,GACF,EACA,EACA,EACA,EACA,EACA,EAEF,GAAI,EAAE,OAAS,EAAK,MAAO,GAiB3B,GAfA,EAAU,EAAE,OAAO,EAAE,GACjB,GAAW,KACb,GAAI,EAAQ,cAAgB,EAAE,OAAO,IAIvC,EAAK,EACL,EAAM,EAEN,AAAI,EAAG,KAAK,GAAM,EAAI,EAAE,QAAQ,EAAG,QAC1B,EAAI,KAAK,IAAM,GAAI,EAAE,QAAQ,EAAI,SAG1C,EAAK,EACL,EAAM,EACF,EAAG,KAAK,GAAI,CACd,GAAI,GAAK,EAAG,KAAK,GACjB,EAAK,EACD,EAAG,KAAK,EAAG,KACb,GAAK,EACL,EAAI,EAAE,QAAQ,EAAG,aAEV,EAAI,KAAK,GAAI,CACtB,GAAI,GAAK,EAAI,KAAK,GAClB,EAAO,EAAG,GACV,EAAM,EACF,EAAI,KAAK,IACX,GAAI,EACJ,EAAM,EACN,EAAM,EACN,EAAM,EACN,AAAI,EAAI,KAAK,GAAM,EAAI,EAAI,IACtB,AAAI,EAAI,KAAK,GAAM,GAAK,EAAS,EAAI,EAAE,QAAQ,EAAG,KAC9C,EAAI,KAAK,IAAM,GAAI,EAAI,MAMpC,GADA,EAAK,EACD,EAAG,KAAK,GAAI,CACd,GAAI,GAAK,EAAG,KAAK,GACjB,EAAO,EAAG,GACV,EAAI,EAAO,IAKb,GADA,EAAK,EACD,EAAG,KAAK,GAAI,CACd,GAAI,GAAK,EAAG,KAAK,GACjB,EAAO,EAAG,GACV,EAAS,EAAG,GACZ,EAAK,EACD,EAAG,KAAK,IACV,GAAI,EAAO,EAAU,IAMzB,GADA,EAAK,EACD,EAAG,KAAK,GAAI,CACd,GAAI,GAAK,EAAG,KAAK,GACjB,EAAO,EAAG,GACV,EAAS,EAAG,GACZ,EAAK,EACD,EAAG,KAAK,IACV,GAAI,EAAO,EAAU,IAOzB,GAFA,EAAK,EACL,EAAM,EACF,EAAG,KAAK,GAAI,CACd,GAAI,GAAK,EAAG,KAAK,GACjB,EAAO,EAAG,GACV,EAAK,EACD,EAAG,KAAK,IACV,GAAI,WAEG,EAAI,KAAK,GAAI,CACtB,GAAI,GAAK,EAAI,KAAK,GAClB,EAAO,EAAG,GAAK,EAAG,GAClB,EAAM,EACF,EAAI,KAAK,IACX,GAAI,GAMR,GADA,EAAK,EACD,EAAG,KAAK,GAAI,CACd,GAAI,GAAK,EAAG,KAAK,GACjB,EAAO,EAAG,GACV,EAAK,EACL,EAAM,EACN,EAAM,EACF,GAAG,KAAK,IAAU,EAAI,KAAK,IAAS,CAAE,EAAI,KAAK,KACjD,GAAI,GAIR,SAAK,EACL,EAAM,EACF,EAAG,KAAK,IAAM,EAAI,KAAK,IACzB,GAAK,EACL,EAAI,EAAE,QAAQ,EAAG,KAKf,GAAW,KACb,GAAI,EAAQ,cAAgB,EAAE,OAAO,IAGhC,GAGT,MAAO,UAAU,EAAO,CACtB,MAAO,GAAM,OAAO,OAIxB,EAAK,SAAS,iBAAiB,EAAK,QAAS,WAC7C;AAAA;AAAA;AAAA,GAkBA,EAAK,uBAAyB,SAAU,EAAW,CACjD,GAAI,GAAQ,EAAU,OAAO,SAAU,EAAM,EAAU,CACrD,SAAK,GAAY,EACV,GACN,IAEH,MAAO,UAAU,EAAO,CACtB,GAAI,GAAS,EAAM,EAAM,cAAgB,EAAM,WAAY,MAAO,KAiBtE,EAAK,eAAiB,EAAK,uBAAuB,CAChD,IACA,OACA,QACA,SACA,QACA,MACA,SACA,OACA,KACA,QACA,KACA,MACA,MACA,MACA,KACA,KACA,KACA,UACA,OACA,MACA,KACA,MACA,SACA,QACA,OACA,MACA,KACA,OACA,SACA,OACA,OACA,QACA,MACA,OACA,MACA,MACA,MACA,MACA,OACA,KACA,MACA,OACA,MACA,MACA,MACA,UACA,IACA,KACA,KACA,OACA,KACA,KACA,MACA,OACA,QACA,MACA,OACA,SACA,MACA,KACA,QACA,OACA,OACA,KACA,UACA,KACA,MACA,MACA,KACA,MACA,QACA,KACA,OACA,KACA,QACA,MACA,MACA,SACA,OACA,MACA,OACA,MACA,SACA,QACA,KACA,OACA,OACA,OACA,MACA,QACA,OACA,OACA,QACA,QACA,OACA,OACA,MACA,KACA,MACA,OACA,KACA,QACA,MACA,KACA,OACA,OACA,OACA,QACA,QACA,QACA,MACA,OACA,MACA,OACA,OACA,QACA,MACA,MACA,SAGF,EAAK,SAAS,iBAAiB,EAAK,eAAgB,kBACpD;AAAA;AAAA;AAAA,GAoBA,EAAK,QAAU,SAAU,EAAO,CAC9B,MAAO,GAAM,OAAO,SAAU,EAAG,CAC/B,MAAO,GAAE,QAAQ,OAAQ,IAAI,QAAQ,OAAQ,OAIjD,EAAK,SAAS,iBAAiB,EAAK,QAAS,WAC7C;AAAA;AAAA;AAAA,GA0BA,EAAK,SAAW,UAAY,CAC1B,KAAK,MAAQ,GACb,KAAK,MAAQ,GACb,KAAK,GAAK,EAAK,SAAS,QACxB,EAAK,SAAS,SAAW,GAW3B,EAAK,SAAS,QAAU,EASxB,EAAK,SAAS,UAAY,SAAU,EAAK,CAGvC,OAFI,GAAU,GAAI,GAAK,SAAS,QAEvB,EAAI,EAAG,EAAM,EAAI,OAAQ,EAAI,EAAK,IACzC,EAAQ,OAAO,EAAI,IAGrB,SAAQ,SACD,EAAQ,MAYjB,EAAK,SAAS,WAAa,SAAU,EAAQ,CAC3C,MAAI,gBAAkB,GACb,EAAK,SAAS,gBAAgB,EAAO,KAAM,EAAO,cAElD,EAAK,SAAS,WAAW,EAAO,OAmB3C,EAAK,SAAS,gBAAkB,SAAU,EAAK,EAAc,CAS3D,OARI,GAAO,GAAI,GAAK,SAEhB,EAAQ,CAAC,CACX,KAAM,EACN,eAAgB,EAChB,IAAK,IAGA,EAAM,QAAQ,CACnB,GAAI,GAAQ,EAAM,MAGlB,GAAI,EAAM,IAAI,OAAS,EAAG,CACxB,GAAI,GAAO,EAAM,IAAI,OAAO,GACxB,EAEJ,AAAI,IAAQ,GAAM,KAAK,MACrB,EAAa,EAAM,KAAK,MAAM,GAE9B,GAAa,GAAI,GAAK,SACtB,EAAM,KAAK,MAAM,GAAQ,GAGvB,EAAM,IAAI,QAAU,GACtB,GAAW,MAAQ,IAGrB,EAAM,KAAK,CACT,KAAM,EACN,eAAgB,EAAM,eACtB,IAAK,EAAM,IAAI,MAAM,KAIzB,GAAI,EAAM,gBAAkB,EAK5B,IAAI,KAAO,GAAM,KAAK,MACpB,GAAI,GAAgB,EAAM,KAAK,MAAM,SAChC,CACL,GAAI,GAAgB,GAAI,GAAK,SAC7B,EAAM,KAAK,MAAM,KAAO,EAiC1B,GA9BI,EAAM,IAAI,QAAU,GACtB,GAAc,MAAQ,IAGxB,EAAM,KAAK,CACT,KAAM,EACN,eAAgB,EAAM,eAAiB,EACvC,IAAK,EAAM,MAMT,EAAM,IAAI,OAAS,GACrB,EAAM,KAAK,CACT,KAAM,EAAM,KACZ,eAAgB,EAAM,eAAiB,EACvC,IAAK,EAAM,IAAI,MAAM,KAMrB,EAAM,IAAI,QAAU,GACtB,GAAM,KAAK,MAAQ,IAMjB,EAAM,IAAI,QAAU,EAAG,CACzB,GAAI,KAAO,GAAM,KAAK,MACpB,GAAI,GAAmB,EAAM,KAAK,MAAM,SACnC,CACL,GAAI,GAAmB,GAAI,GAAK,SAChC,EAAM,KAAK,MAAM,KAAO,EAG1B,AAAI,EAAM,IAAI,QAAU,GACtB,GAAiB,MAAQ,IAG3B,EAAM,KAAK,CACT,KAAM,EACN,eAAgB,EAAM,eAAiB,EACvC,IAAK,EAAM,IAAI,MAAM,KAOzB,GAAI,EAAM,IAAI,OAAS,EAAG,CACxB,GAAI,GAAQ,EAAM,IAAI,OAAO,GACzB,EAAQ,EAAM,IAAI,OAAO,GACzB,EAEJ,AAAI,IAAS,GAAM,KAAK,MACtB,EAAgB,EAAM,KAAK,MAAM,GAEjC,GAAgB,GAAI,GAAK,SACzB,EAAM,KAAK,MAAM,GAAS,GAGxB,EAAM,IAAI,QAAU,GACtB,GAAc,MAAQ,IAGxB,EAAM,KAAK,CACT,KAAM,EACN,eAAgB,EAAM,eAAiB,EACvC,IAAK,EAAQ,EAAM,IAAI,MAAM,OAKnC,MAAO,IAaT,EAAK,SAAS,WAAa,SAAU,EAAK,CAYxC,OAXI,GAAO,GAAI,GAAK,SAChB,EAAO,EAUF,EAAI,EAAG,EAAM,EAAI,OAAQ,EAAI,EAAK,IAAK,CAC9C,GAAI,GAAO,EAAI,GACX,EAAS,GAAK,EAAM,EAExB,GAAI,GAAQ,IACV,EAAK,MAAM,GAAQ,EACnB,EAAK,MAAQ,MAER,CACL,GAAI,GAAO,GAAI,GAAK,SACpB,EAAK,MAAQ,EAEb,EAAK,MAAM,GAAQ,EACnB,EAAO,GAIX,MAAO,IAaT,EAAK,SAAS,UAAU,QAAU,UAAY,CAQ5C,OAPI,GAAQ,GAER,EAAQ,CAAC,CACX,OAAQ,GACR,KAAM,OAGD,EAAM,QAAQ,CACnB,GAAI,GAAQ,EAAM,MACd,EAAQ,OAAO,KAAK,EAAM,KAAK,OAC/B,EAAM,EAAM,OAEhB,AAAI,EAAM,KAAK,OAKb,GAAM,OAAO,OAAO,GACpB,EAAM,KAAK,EAAM,SAGnB,OAAS,GAAI,EAAG,EAAI,EAAK,IAAK,CAC5B,GAAI,GAAO,EAAM,GAEjB,EAAM,KAAK,CACT,OAAQ,EAAM,OAAO,OAAO,GAC5B,KAAM,EAAM,KAAK,MAAM,MAK7B,MAAO,IAaT,EAAK,SAAS,UAAU,SAAW,UAAY,CAS7C,GAAI,KAAK,KACP,MAAO,MAAK,KAOd,OAJI,GAAM,KAAK,MAAQ,IAAM,IACzB,EAAS,OAAO,KAAK,KAAK,OAAO,OACjC,EAAM,EAAO,OAER,EAAI,EAAG,EAAI,EAAK,IAAK,CAC5B,GAAI,GAAQ,EAAO,GACf,EAAO,KAAK,MAAM,GAEtB,EAAM,EAAM,EAAQ,EAAK,GAG3B,MAAO,IAaT,EAAK,SAAS,UAAU,UAAY,SAAU,EAAG,CAU/C,OATI,GAAS,GAAI,GAAK,SAClB,EAAQ,OAER,EAAQ,CAAC,CACX,MAAO,EACP,OAAQ,EACR,KAAM,OAGD,EAAM,QAAQ,CACnB,EAAQ,EAAM,MAWd,OALI,GAAS,OAAO,KAAK,EAAM,MAAM,OACjC,EAAO,EAAO,OACd,EAAS,OAAO,KAAK,EAAM,KAAK,OAChC,EAAO,EAAO,OAET,EAAI,EAAG,EAAI,EAAM,IAGxB,OAFI,GAAQ,EAAO,GAEV,EAAI,EAAG,EAAI,EAAM,IAAK,CAC7B,GAAI,GAAQ,EAAO,GAEnB,GAAI,GAAS,GAAS,GAAS,IAAK,CAClC,GAAI,GAAO,EAAM,KAAK,MAAM,GACxB,EAAQ,EAAM,MAAM,MAAM,GAC1B,EAAQ,EAAK,OAAS,EAAM,MAC5B,EAAO,OAEX,AAAI,IAAS,GAAM,OAAO,MAIxB,GAAO,EAAM,OAAO,MAAM,GAC1B,EAAK,MAAQ,EAAK,OAAS,GAM3B,GAAO,GAAI,GAAK,SAChB,EAAK,MAAQ,EACb,EAAM,OAAO,MAAM,GAAS,GAG9B,EAAM,KAAK,CACT,MAAO,EACP,OAAQ,EACR,KAAM,MAOhB,MAAO,IAET,EAAK,SAAS,QAAU,UAAY,CAClC,KAAK,aAAe,GACpB,KAAK,KAAO,GAAI,GAAK,SACrB,KAAK,eAAiB,GACtB,KAAK,eAAiB,IAGxB,EAAK,SAAS,QAAQ,UAAU,OAAS,SAAU,EAAM,CACvD,GAAI,GACA,EAAe,EAEnB,GAAI,EAAO,KAAK,aACd,KAAM,IAAI,OAAO,+BAGnB,OAAS,GAAI,EAAG,EAAI,EAAK,QAAU,EAAI,KAAK,aAAa,QACnD,EAAK,IAAM,KAAK,aAAa,GAD8B,IAE/D,IAGF,KAAK,SAAS,GAEd,AAAI,KAAK,eAAe,QAAU,EAChC,EAAO,KAAK,KAEZ,EAAO,KAAK,eAAe,KAAK,eAAe,OAAS,GAAG,MAG7D,OAAS,GAAI,EAAc,EAAI,EAAK,OAAQ,IAAK,CAC/C,GAAI,GAAW,GAAI,GAAK,SACpB,EAAO,EAAK,GAEhB,EAAK,MAAM,GAAQ,EAEnB,KAAK,eAAe,KAAK,CACvB,OAAQ,EACR,KAAM,EACN,MAAO,IAGT,EAAO,EAGT,EAAK,MAAQ,GACb,KAAK,aAAe,GAGtB,EAAK,SAAS,QAAQ,UAAU,OAAS,UAAY,CACnD,KAAK,SAAS,IAGhB,EAAK,SAAS,QAAQ,UAAU,SAAW,SAAU,EAAQ,CAC3D,OAAS,GAAI,KAAK,eAAe,OAAS,EAAG,GAAK,EAAQ,IAAK,CAC7D,GAAI,GAAO,KAAK,eAAe,GAC3B,EAAW,EAAK,MAAM,WAE1B,AAAI,IAAY,MAAK,eACnB,EAAK,OAAO,MAAM,EAAK,MAAQ,KAAK,eAAe,GAInD,GAAK,MAAM,KAAO,EAElB,KAAK,eAAe,GAAY,EAAK,OAGvC,KAAK,eAAe,QAGxB;AAAA;AAAA;AAAA,GAqBA,EAAK,MAAQ,SAAU,EAAO,CAC5B,KAAK,cAAgB,EAAM,cAC3B,KAAK,aAAe,EAAM,aAC1B,KAAK,SAAW,EAAM,SACtB,KAAK,OAAS,EAAM,OACpB,KAAK,SAAW,EAAM,UA0ExB,EAAK,MAAM,UAAU,OAAS,SAAU,EAAa,CACnD,MAAO,MAAK,MAAM,SAAU,EAAO,CACjC,GAAI,GAAS,GAAI,GAAK,YAAY,EAAa,GAC/C,EAAO,WA6BX,EAAK,MAAM,UAAU,MAAQ,SAAU,EAAI,CAoBzC,OAZI,GAAQ,GAAI,GAAK,MAAM,KAAK,QAC5B,EAAiB,OAAO,OAAO,MAC/B,EAAe,OAAO,OAAO,MAC7B,EAAiB,OAAO,OAAO,MAC/B,EAAkB,OAAO,OAAO,MAChC,EAAoB,OAAO,OAAO,MAO7B,EAAI,EAAG,EAAI,KAAK,OAAO,OAAQ,IACtC,EAAa,KAAK,OAAO,IAAM,GAAI,GAAK,OAG1C,EAAG,KAAK,EAAO,GAEf,OAAS,GAAI,EAAG,EAAI,EAAM,QAAQ,OAAQ,IAAK,CAS7C,GAAI,GAAS,EAAM,QAAQ,GACvB,EAAQ,KACR,EAAgB,EAAK,IAAI,MAE7B,AAAI,EAAO,YACT,EAAQ,KAAK,SAAS,UAAU,EAAO,KAAM,CAC3C,OAAQ,EAAO,SAGjB,EAAQ,CAAC,EAAO,MAGlB,OAAS,GAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACrC,GAAI,GAAO,EAAM,GAQjB,EAAO,KAAO,EAOd,GAAI,GAAe,EAAK,SAAS,WAAW,GACxC,EAAgB,KAAK,SAAS,UAAU,GAAc,UAQ1D,GAAI,EAAc,SAAW,GAAK,EAAO,WAAa,EAAK,MAAM,SAAS,SAAU,CAClF,OAAS,GAAI,EAAG,EAAI,EAAO,OAAO,OAAQ,IAAK,CAC7C,GAAI,GAAQ,EAAO,OAAO,GAC1B,EAAgB,GAAS,EAAK,IAAI,MAGpC,MAGF,OAAS,GAAI,EAAG,EAAI,EAAc,OAAQ,IASxC,OAJI,GAAe,EAAc,GAC7B,EAAU,KAAK,cAAc,GAC7B,EAAY,EAAQ,OAEf,EAAI,EAAG,EAAI,EAAO,OAAO,OAAQ,IAAK,CAS7C,GAAI,GAAQ,EAAO,OAAO,GACtB,EAAe,EAAQ,GACvB,EAAuB,OAAO,KAAK,GACnC,EAAY,EAAe,IAAM,EACjC,EAAuB,GAAI,GAAK,IAAI,GAoBxC,GAbI,EAAO,UAAY,EAAK,MAAM,SAAS,UACzC,GAAgB,EAAc,MAAM,GAEhC,EAAgB,KAAW,QAC7B,GAAgB,GAAS,EAAK,IAAI,WASlC,EAAO,UAAY,EAAK,MAAM,SAAS,WAAY,CACrD,AAAI,EAAkB,KAAW,QAC/B,GAAkB,GAAS,EAAK,IAAI,OAGtC,EAAkB,GAAS,EAAkB,GAAO,MAAM,GAO1D,SAgBF,GANA,EAAa,GAAO,OAAO,EAAW,EAAO,MAAO,SAAU,GAAG,GAAG,CAAE,MAAO,IAAI,KAM7E,GAAe,GAInB,QAAS,GAAI,EAAG,EAAI,EAAqB,OAAQ,IAAK,CAOpD,GAAI,GAAsB,EAAqB,GAC3C,EAAmB,GAAI,GAAK,SAAU,EAAqB,GAC3D,EAAW,EAAa,GACxB,EAEJ,AAAK,GAAa,EAAe,MAAuB,OACtD,EAAe,GAAoB,GAAI,GAAK,UAAW,EAAc,EAAO,GAE5E,EAAW,IAAI,EAAc,EAAO,GAKxC,EAAe,GAAa,KAWlC,GAAI,EAAO,WAAa,EAAK,MAAM,SAAS,SAC1C,OAAS,GAAI,EAAG,EAAI,EAAO,OAAO,OAAQ,IAAK,CAC7C,GAAI,GAAQ,EAAO,OAAO,GAC1B,EAAgB,GAAS,EAAgB,GAAO,UAAU,IAahE,OAHI,GAAqB,EAAK,IAAI,SAC9B,EAAuB,EAAK,IAAI,MAE3B,EAAI,EAAG,EAAI,KAAK,OAAO,OAAQ,IAAK,CAC3C,GAAI,GAAQ,KAAK,OAAO,GAExB,AAAI,EAAgB,IAClB,GAAqB,EAAmB,UAAU,EAAgB,KAGhE,EAAkB,IACpB,GAAuB,EAAqB,MAAM,EAAkB,KAIxE,GAAI,GAAoB,OAAO,KAAK,GAChC,EAAU,GACV,EAAU,OAAO,OAAO,MAY5B,GAAI,EAAM,YAAa,CACrB,EAAoB,OAAO,KAAK,KAAK,cAErC,OAAS,GAAI,EAAG,EAAI,EAAkB,OAAQ,IAAK,CACjD,GAAI,GAAmB,EAAkB,GACrC,EAAW,EAAK,SAAS,WAAW,GACxC,EAAe,GAAoB,GAAI,GAAK,WAIhD,OAAS,GAAI,EAAG,EAAI,EAAkB,OAAQ,IAAK,CASjD,GAAI,GAAW,EAAK,SAAS,WAAW,EAAkB,IACtD,EAAS,EAAS,OAEtB,GAAI,EAAC,EAAmB,SAAS,IAI7B,GAAqB,SAAS,GAIlC,IAAI,GAAc,KAAK,aAAa,GAChC,EAAQ,EAAa,EAAS,WAAW,WAAW,GACpD,EAEJ,GAAK,GAAW,EAAQ,MAAa,OACnC,EAAS,OAAS,EAClB,EAAS,UAAU,QAAQ,EAAe,QACrC,CACL,GAAI,GAAQ,CACV,IAAK,EACL,MAAO,EACP,UAAW,EAAe,IAE5B,EAAQ,GAAU,EAClB,EAAQ,KAAK,KAOjB,MAAO,GAAQ,KAAK,SAAU,GAAG,GAAG,CAClC,MAAO,IAAE,MAAQ,GAAE,SAYvB,EAAK,MAAM,UAAU,OAAS,UAAY,CACxC,GAAI,GAAgB,OAAO,KAAK,KAAK,eAClC,OACA,IAAI,SAAU,EAAM,CACnB,MAAO,CAAC,EAAM,KAAK,cAAc,KAChC,MAED,EAAe,OAAO,KAAK,KAAK,cACjC,IAAI,SAAU,EAAK,CAClB,MAAO,CAAC,EAAK,KAAK,aAAa,GAAK,WACnC,MAEL,MAAO,CACL,QAAS,EAAK,QACd,OAAQ,KAAK,OACb,aAAc,EACd,cAAe,EACf,SAAU,KAAK,SAAS,WAU5B,EAAK,MAAM,KAAO,SAAU,EAAiB,CAC3C,GAAI,GAAQ,GACR,EAAe,GACf,EAAoB,EAAgB,aACpC,EAAgB,OAAO,OAAO,MAC9B,EAA0B,EAAgB,cAC1C,EAAkB,GAAI,GAAK,SAAS,QACpC,EAAW,EAAK,SAAS,KAAK,EAAgB,UAElD,AAAI,EAAgB,SAAW,EAAK,SAClC,EAAK,MAAM,KAAK,4EAA8E,EAAK,QAAU,sCAAwC,EAAgB,QAAU,KAGjL,OAAS,GAAI,EAAG,EAAI,EAAkB,OAAQ,IAAK,CACjD,GAAI,GAAQ,EAAkB,GAC1B,EAAM,EAAM,GACZ,EAAW,EAAM,GAErB,EAAa,GAAO,GAAI,GAAK,OAAO,GAGtC,OAAS,GAAI,EAAG,EAAI,EAAwB,OAAQ,IAAK,CACvD,GAAI,GAAQ,EAAwB,GAChC,EAAO,EAAM,GACb,EAAU,EAAM,GAEpB,EAAgB,OAAO,GACvB,EAAc,GAAQ,EAGxB,SAAgB,SAEhB,EAAM,OAAS,EAAgB,OAE/B,EAAM,aAAe,EACrB,EAAM,cAAgB,EACtB,EAAM,SAAW,EAAgB,KACjC,EAAM,SAAW,EAEV,GAAI,GAAK,MAAM,IAExB;AAAA;AAAA;AAAA,GA6BA,EAAK,QAAU,UAAY,CACzB,KAAK,KAAO,KACZ,KAAK,QAAU,OAAO,OAAO,MAC7B,KAAK,WAAa,OAAO,OAAO,MAChC,KAAK,cAAgB,OAAO,OAAO,MACnC,KAAK,qBAAuB,GAC5B,KAAK,aAAe,GACpB,KAAK,UAAY,EAAK,UACtB,KAAK,SAAW,GAAI,GAAK,SACzB,KAAK,eAAiB,GAAI,GAAK,SAC/B,KAAK,cAAgB,EACrB,KAAK,GAAK,IACV,KAAK,IAAM,IACX,KAAK,UAAY,EACjB,KAAK,kBAAoB,IAe3B,EAAK,QAAQ,UAAU,IAAM,SAAU,EAAK,CAC1C,KAAK,KAAO,GAmCd,EAAK,QAAQ,UAAU,MAAQ,SAAU,EAAW,EAAY,CAC9D,GAAI,KAAK,KAAK,GACZ,KAAM,IAAI,YAAY,UAAY,EAAY,oCAGhD,KAAK,QAAQ,GAAa,GAAc,IAW1C,EAAK,QAAQ,UAAU,EAAI,SAAU,EAAQ,CAC3C,AAAI,EAAS,EACX,KAAK,GAAK,EACL,AAAI,EAAS,EAClB,KAAK,GAAK,EAEV,KAAK,GAAK,GAWd,EAAK,QAAQ,UAAU,GAAK,SAAU,EAAQ,CAC5C,KAAK,IAAM,GAoBb,EAAK,QAAQ,UAAU,IAAM,SAAU,EAAK,EAAY,CACtD,GAAI,GAAS,EAAI,KAAK,MAClB,EAAS,OAAO,KAAK,KAAK,SAE9B,KAAK,WAAW,GAAU,GAAc,GACxC,KAAK,eAAiB,EAEtB,OAAS,GAAI,EAAG,EAAI,EAAO,OAAQ,IAAK,CACtC,GAAI,GAAY,EAAO,GACnB,EAAY,KAAK,QAAQ,GAAW,UACpC,EAAQ,EAAY,EAAU,GAAO,EAAI,GACzC,EAAS,KAAK,UAAU,EAAO,CAC7B,OAAQ,CAAC,KAEX,EAAQ,KAAK,SAAS,IAAI,GAC1B,EAAW,GAAI,GAAK,SAAU,EAAQ,GACtC,EAAa,OAAO,OAAO,MAE/B,KAAK,qBAAqB,GAAY,EACtC,KAAK,aAAa,GAAY,EAG9B,KAAK,aAAa,IAAa,EAAM,OAGrC,OAAS,GAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACrC,GAAI,GAAO,EAAM,GAUjB,GARI,EAAW,IAAS,MACtB,GAAW,GAAQ,GAGrB,EAAW,IAAS,EAIhB,KAAK,cAAc,IAAS,KAAW,CACzC,GAAI,GAAU,OAAO,OAAO,MAC5B,EAAQ,OAAY,KAAK,UACzB,KAAK,WAAa,EAElB,OAAS,GAAI,EAAG,EAAI,EAAO,OAAQ,IACjC,EAAQ,EAAO,IAAM,OAAO,OAAO,MAGrC,KAAK,cAAc,GAAQ,EAI7B,AAAI,KAAK,cAAc,GAAM,GAAW,IAAW,MACjD,MAAK,cAAc,GAAM,GAAW,GAAU,OAAO,OAAO,OAK9D,OAAS,GAAI,EAAG,EAAI,KAAK,kBAAkB,OAAQ,IAAK,CACtD,GAAI,GAAc,KAAK,kBAAkB,GACrC,EAAW,EAAK,SAAS,GAE7B,AAAI,KAAK,cAAc,GAAM,GAAW,GAAQ,IAAgB,MAC9D,MAAK,cAAc,GAAM,GAAW,GAAQ,GAAe,IAG7D,KAAK,cAAc,GAAM,GAAW,GAAQ,GAAa,KAAK,OAYtE,EAAK,QAAQ,UAAU,6BAA+B,UAAY,CAOhE,OALI,GAAY,OAAO,KAAK,KAAK,cAC7B,EAAiB,EAAU,OAC3B,EAAc,GACd,EAAqB,GAEhB,EAAI,EAAG,EAAI,EAAgB,IAAK,CACvC,GAAI,GAAW,EAAK,SAAS,WAAW,EAAU,IAC9C,EAAQ,EAAS,UAErB,EAAmB,IAAW,GAAmB,GAAS,GAC1D,EAAmB,IAAU,EAE7B,EAAY,IAAW,GAAY,GAAS,GAC5C,EAAY,IAAU,KAAK,aAAa,GAK1C,OAFI,GAAS,OAAO,KAAK,KAAK,SAErB,EAAI,EAAG,EAAI,EAAO,OAAQ,IAAK,CACtC,GAAI,GAAY,EAAO,GACvB,EAAY,GAAa,EAAY,GAAa,EAAmB,GAGvE,KAAK,mBAAqB,GAQ5B,EAAK,QAAQ,UAAU,mBAAqB,UAAY,CAMtD,OALI,GAAe,GACf,EAAY,OAAO,KAAK,KAAK,sBAC7B,EAAkB,EAAU,OAC5B,EAAe,OAAO,OAAO,MAExB,EAAI,EAAG,EAAI,EAAiB,IAAK,CAaxC,OAZI,GAAW,EAAK,SAAS,WAAW,EAAU,IAC9C,EAAY,EAAS,UACrB,EAAc,KAAK,aAAa,GAChC,EAAc,GAAI,GAAK,OACvB,EAAkB,KAAK,qBAAqB,GAC5C,EAAQ,OAAO,KAAK,GACpB,EAAc,EAAM,OAGpB,EAAa,KAAK,QAAQ,GAAW,OAAS,EAC9C,EAAW,KAAK,WAAW,EAAS,QAAQ,OAAS,EAEhD,EAAI,EAAG,EAAI,EAAa,IAAK,CACpC,GAAI,GAAO,EAAM,GACb,EAAK,EAAgB,GACrB,EAAY,KAAK,cAAc,GAAM,OACrC,EAAK,EAAO,EAEhB,AAAI,EAAa,KAAU,OACzB,GAAM,EAAK,IAAI,KAAK,cAAc,GAAO,KAAK,eAC9C,EAAa,GAAQ,GAErB,EAAM,EAAa,GAGrB,EAAQ,EAAQ,OAAK,IAAM,GAAK,GAAO,MAAK,IAAO,GAAI,KAAK,GAAK,KAAK,GAAM,GAAc,KAAK,mBAAmB,KAAe,GACjI,GAAS,EACT,GAAS,EACT,EAAqB,KAAK,MAAM,EAAQ,KAAQ,IAQhD,EAAY,OAAO,EAAW,GAGhC,EAAa,GAAY,EAG3B,KAAK,aAAe,GAQtB,EAAK,QAAQ,UAAU,eAAiB,UAAY,CAClD,KAAK,SAAW,EAAK,SAAS,UAC5B,OAAO,KAAK,KAAK,eAAe,SAYpC,EAAK,QAAQ,UAAU,MAAQ,UAAY,CACzC,YAAK,+BACL,KAAK,qBACL,KAAK,iBAEE,GAAI,GAAK,MAAM,CACpB,cAAe,KAAK,cACpB,aAAc,KAAK,aACnB,SAAU,KAAK,SACf,OAAQ,OAAO,KAAK,KAAK,SACzB,SAAU,KAAK,kBAkBnB,EAAK,QAAQ,UAAU,IAAM,SAAU,EAAI,CACzC,GAAI,GAAO,MAAM,UAAU,MAAM,KAAK,UAAW,GACjD,EAAK,QAAQ,MACb,EAAG,MAAM,KAAM,IAcjB,EAAK,UAAY,SAAU,EAAM,EAAO,EAAU,CAShD,OARI,GAAiB,OAAO,OAAO,MAC/B,EAAe,OAAO,KAAK,GAAY,IAOlC,EAAI,EAAG,EAAI,EAAa,OAAQ,IAAK,CAC5C,GAAI,GAAM,EAAa,GACvB,EAAe,GAAO,EAAS,GAAK,QAGtC,KAAK,SAAW,OAAO,OAAO,MAE1B,IAAS,QACX,MAAK,SAAS,GAAQ,OAAO,OAAO,MACpC,KAAK,SAAS,GAAM,GAAS,IAajC,EAAK,UAAU,UAAU,QAAU,SAAU,EAAgB,CAG3D,OAFI,GAAQ,OAAO,KAAK,EAAe,UAE9B,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,CACrC,GAAI,GAAO,EAAM,GACb,EAAS,OAAO,KAAK,EAAe,SAAS,IAEjD,AAAI,KAAK,SAAS,IAAS,MACzB,MAAK,SAAS,GAAQ,OAAO,OAAO,OAGtC,OAAS,GAAI,EAAG,EAAI,EAAO,OAAQ,IAAK,CACtC,GAAI,GAAQ,EAAO,GACf,EAAO,OAAO,KAAK,EAAe,SAAS,GAAM,IAErD,AAAI,KAAK,SAAS,GAAM,IAAU,MAChC,MAAK,SAAS,GAAM,GAAS,OAAO,OAAO,OAG7C,OAAS,GAAI,EAAG,EAAI,EAAK,OAAQ,IAAK,CACpC,GAAI,GAAM,EAAK,GAEf,AAAI,KAAK,SAAS,GAAM,GAAO,IAAQ,KACrC,KAAK,SAAS,GAAM,GAAO,GAAO,EAAe,SAAS,GAAM,GAAO,GAEvE,KAAK,SAAS,GAAM,GAAO,GAAO,KAAK,SAAS,GAAM,GAAO,GAAK,OAAO,EAAe,SAAS,GAAM,GAAO,QAexH,EAAK,UAAU,UAAU,IAAM,SAAU,EAAM,EAAO,EAAU,CAC9D,GAAI,CAAE,KAAQ,MAAK,UAAW,CAC5B,KAAK,SAAS,GAAQ,OAAO,OAAO,MACpC,KAAK,SAAS,GAAM,GAAS,EAC7B,OAGF,GAAI,CAAE,KAAS,MAAK,SAAS,IAAQ,CACnC,KAAK,SAAS,GAAM,GAAS,EAC7B,OAKF,OAFI,GAAe,OAAO,KAAK,GAEtB,EAAI,EAAG,EAAI,EAAa,OAAQ,IAAK,CAC5C,GAAI,GAAM,EAAa,GAEvB,AAAI,IAAO,MAAK,SAAS,GAAM,GAC7B,KAAK,SAAS,GAAM,GAAO,GAAO,KAAK,SAAS,GAAM,GAAO,GAAK,OAAO,EAAS,IAElF,KAAK,SAAS,GAAM,GAAO,GAAO,EAAS,KAejD,EAAK,MAAQ,SAAU,EAAW,CAChC,KAAK,QAAU,GACf,KAAK,UAAY,GA2BnB,EAAK,MAAM,SAAW,GAAI,QAAQ,KAClC,EAAK,MAAM,SAAS,KAAO,EAC3B,EAAK,MAAM,SAAS,QAAU,EAC9B,EAAK,MAAM,SAAS,SAAW,EAa/B,EAAK,MAAM,SAAW,CAIpB,SAAU,EAMV,SAAU,EAMV,WAAY,GA0Bd,EAAK,MAAM,UAAU,OAAS,SAAU,EAAQ,CAC9C,MAAM,UAAY,IAChB,GAAO,OAAS,KAAK,WAGjB,SAAW,IACf,GAAO,MAAQ,GAGX,eAAiB,IACrB,GAAO,YAAc,IAGjB,YAAc,IAClB,GAAO,SAAW,EAAK,MAAM,SAAS,MAGnC,EAAO,SAAW,EAAK,MAAM,SAAS,SAAa,EAAO,KAAK,OAAO,IAAM,EAAK,MAAM,UAC1F,GAAO,KAAO,IAAM,EAAO,MAGxB,EAAO,SAAW,EAAK,MAAM,SAAS,UAAc,EAAO,KAAK,MAAM,KAAO,EAAK,MAAM,UAC3F,GAAO,KAAO,GAAK,EAAO,KAAO,KAG7B,YAAc,IAClB,GAAO,SAAW,EAAK,MAAM,SAAS,UAGxC,KAAK,QAAQ,KAAK,GAEX,MAUT,EAAK,MAAM,UAAU,UAAY,UAAY,CAC3C,OAAS,GAAI,EAAG,EAAI,KAAK,QAAQ,OAAQ,IACvC,GAAI,KAAK,QAAQ,GAAG,UAAY,EAAK,MAAM,SAAS,WAClD,MAAO,GAIX,MAAO,IA6BT,EAAK,MAAM,UAAU,KAAO,SAAU,EAAM,EAAS,CACnD,GAAI,MAAM,QAAQ,GAChB,SAAK,QAAQ,SAAU,EAAG,CAAE,KAAK,KAAK,EAAG,EAAK,MAAM,MAAM,KAAa,MAChE,KAGT,GAAI,GAAS,GAAW,GACxB,SAAO,KAAO,EAAK,WAEnB,KAAK,OAAO,GAEL,MAET,EAAK,gBAAkB,SAAU,EAAS,EAAO,EAAK,CACpD,KAAK,KAAO,kBACZ,KAAK,QAAU,EACf,KAAK,MAAQ,EACb,KAAK,IAAM,GAGb,EAAK,gBAAgB,UAAY,GAAI,OACrC,EAAK,WAAa,SAAU,EAAK,CAC/B,KAAK,QAAU,GACf,KAAK,IAAM,EACX,KAAK,OAAS,EAAI,OAClB,KAAK,IAAM,EACX,KAAK,MAAQ,EACb,KAAK,oBAAsB,IAG7B,EAAK,WAAW,UAAU,IAAM,UAAY,CAG1C,OAFI,GAAQ,EAAK,WAAW,QAErB,GACL,EAAQ,EAAM,OAIlB,EAAK,WAAW,UAAU,YAAc,UAAY,CAKlD,OAJI,GAAY,GACZ,EAAa,KAAK,MAClB,EAAW,KAAK,IAEX,EAAI,EAAG,EAAI,KAAK,oBAAoB,OAAQ,IACnD,EAAW,KAAK,oBAAoB,GACpC,EAAU,KAAK,KAAK,IAAI,MAAM,EAAY,IAC1C,EAAa,EAAW,EAG1B,SAAU,KAAK,KAAK,IAAI,MAAM,EAAY,KAAK,MAC/C,KAAK,oBAAoB,OAAS,EAE3B,EAAU,KAAK,KAGxB,EAAK,WAAW,UAAU,KAAO,SAAU,EAAM,CAC/C,KAAK,QAAQ,KAAK,CAChB,KAAM,EACN,IAAK,KAAK,cACV,MAAO,KAAK,MACZ,IAAK,KAAK,MAGZ,KAAK,MAAQ,KAAK,KAGpB,EAAK,WAAW,UAAU,gBAAkB,UAAY,CACtD,KAAK,oBAAoB,KAAK,KAAK,IAAM,GACzC,KAAK,KAAO,GAGd,EAAK,WAAW,UAAU,KAAO,UAAY,CAC3C,GAAI,KAAK,KAAO,KAAK,OACnB,MAAO,GAAK,WAAW,IAGzB,GAAI,GAAO,KAAK,IAAI,OAAO,KAAK,KAChC,YAAK,KAAO,EACL,GAGT,EAAK,WAAW,UAAU,MAAQ,UAAY,CAC5C,MAAO,MAAK,IAAM,KAAK,OAGzB,EAAK,WAAW,UAAU,OAAS,UAAY,CAC7C,AAAI,KAAK,OAAS,KAAK,KACrB,MAAK,KAAO,GAGd,KAAK,MAAQ,KAAK,KAGpB,EAAK,WAAW,UAAU,OAAS,UAAY,CAC7C,KAAK,KAAO,GAGd,EAAK,WAAW,UAAU,eAAiB,UAAY,CACrD,GAAI,GAAM,EAEV,EACE,GAAO,KAAK,OACZ,EAAW,EAAK,WAAW,SACpB,EAAW,IAAM,EAAW,IAErC,AAAI,GAAQ,EAAK,WAAW,KAC1B,KAAK,UAIT,EAAK,WAAW,UAAU,KAAO,UAAY,CAC3C,MAAO,MAAK,IAAM,KAAK,QAGzB,EAAK,WAAW,IAAM,MACtB,EAAK,WAAW,MAAQ,QACxB,EAAK,WAAW,KAAO,OACvB,EAAK,WAAW,cAAgB,gBAChC,EAAK,WAAW,MAAQ,QACxB,EAAK,WAAW,SAAW,WAE3B,EAAK,WAAW,SAAW,SAAU,EAAO,CAC1C,SAAM,SACN,EAAM,KAAK,EAAK,WAAW,OAC3B,EAAM,SACC,EAAK,WAAW,SAGzB,EAAK,WAAW,QAAU,SAAU,EAAO,CAQzC,GAPI,EAAM,QAAU,GAClB,GAAM,SACN,EAAM,KAAK,EAAK,WAAW,OAG7B,EAAM,SAEF,EAAM,OACR,MAAO,GAAK,WAAW,SAI3B,EAAK,WAAW,gBAAkB,SAAU,EAAO,CACjD,SAAM,SACN,EAAM,iBACN,EAAM,KAAK,EAAK,WAAW,eACpB,EAAK,WAAW,SAGzB,EAAK,WAAW,SAAW,SAAU,EAAO,CAC1C,SAAM,SACN,EAAM,iBACN,EAAM,KAAK,EAAK,WAAW,OACpB,EAAK,WAAW,SAGzB,EAAK,WAAW,OAAS,SAAU,EAAO,CACxC,AAAI,EAAM,QAAU,GAClB,EAAM,KAAK,EAAK,WAAW,OAe/B,EAAK,WAAW,cAAgB,EAAK,UAAU,UAE/C,EAAK,WAAW,QAAU,SAAU,EAAO,CACzC,OAAa,CACX,GAAI,GAAO,EAAM,OAEjB,GAAI,GAAQ,EAAK,WAAW,IAC1B,MAAO,GAAK,WAAW,OAIzB,GAAI,EAAK,WAAW,IAAM,GAAI,CAC5B,EAAM,kBACN,SAGF,GAAI,GAAQ,IACV,MAAO,GAAK,WAAW,SAGzB,GAAI,GAAQ,IACV,SAAM,SACF,EAAM,QAAU,GAClB,EAAM,KAAK,EAAK,WAAW,MAEtB,EAAK,WAAW,gBAGzB,GAAI,GAAQ,IACV,SAAM,SACF,EAAM,QAAU,GAClB,EAAM,KAAK,EAAK,WAAW,MAEtB,EAAK,WAAW,SAczB,GARI,GAAQ,KAAO,EAAM,UAAY,GAQjC,GAAQ,KAAO,EAAM,UAAY,EACnC,SAAM,KAAK,EAAK,WAAW,UACpB,EAAK,WAAW,QAGzB,GAAI,EAAK,MAAM,EAAK,WAAW,eAC7B,MAAO,GAAK,WAAW,UAK7B,EAAK,YAAc,SAAU,EAAK,EAAO,CACvC,KAAK,MAAQ,GAAI,GAAK,WAAY,GAClC,KAAK,MAAQ,EACb,KAAK,cAAgB,GACrB,KAAK,UAAY,GAGnB,EAAK,YAAY,UAAU,MAAQ,UAAY,CAC7C,KAAK,MAAM,MACX,KAAK,QAAU,KAAK,MAAM,QAI1B,OAFI,GAAQ,EAAK,YAAY,YAEtB,GACL,EAAQ,EAAM,MAGhB,MAAO,MAAK,OAGd,EAAK,YAAY,UAAU,WAAa,UAAY,CAClD,MAAO,MAAK,QAAQ,KAAK,YAG3B,EAAK,YAAY,UAAU,cAAgB,UAAY,CACrD,GAAI,GAAS,KAAK,aAClB,YAAK,WAAa,EACX,GAGT,EAAK,YAAY,UAAU,WAAa,UAAY,CAClD,GAAI,GAAkB,KAAK,cAC3B,KAAK,MAAM,OAAO,GAClB,KAAK,cAAgB,IAGvB,EAAK,YAAY,YAAc,SAAU,EAAQ,CAC/C,GAAI,GAAS,EAAO,aAEpB,GAAI,GAAU,KAId,OAAQ,EAAO,UACR,GAAK,WAAW,SACnB,MAAO,GAAK,YAAY,kBACrB,GAAK,WAAW,MACnB,MAAO,GAAK,YAAY,eACrB,GAAK,WAAW,KACnB,MAAO,GAAK,YAAY,kBAExB,GAAI,GAAe,4CAA8C,EAAO,KAExE,KAAI,GAAO,IAAI,QAAU,GACvB,IAAgB,gBAAkB,EAAO,IAAM,KAG3C,GAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,OAIzE,EAAK,YAAY,cAAgB,SAAU,EAAQ,CACjD,GAAI,GAAS,EAAO,gBAEpB,GAAI,GAAU,KAId,QAAQ,EAAO,SACR,IACH,EAAO,cAAc,SAAW,EAAK,MAAM,SAAS,WACpD,UACG,IACH,EAAO,cAAc,SAAW,EAAK,MAAM,SAAS,SACpD,cAEA,GAAI,GAAe,kCAAoC,EAAO,IAAM,IACpE,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,KAGvE,GAAI,GAAa,EAAO,aAExB,GAAI,GAAc,KAAW,CAC3B,GAAI,GAAe,yCACnB,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,KAGrE,OAAQ,EAAW,UACZ,GAAK,WAAW,MACnB,MAAO,GAAK,YAAY,eACrB,GAAK,WAAW,KACnB,MAAO,GAAK,YAAY,kBAExB,GAAI,GAAe,mCAAqC,EAAW,KAAO,IAC1E,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAW,MAAO,EAAW,QAIjF,EAAK,YAAY,WAAa,SAAU,EAAQ,CAC9C,GAAI,GAAS,EAAO,gBAEpB,GAAI,GAAU,KAId,IAAI,EAAO,MAAM,UAAU,QAAQ,EAAO,MAAQ,GAAI,CACpD,GAAI,GAAiB,EAAO,MAAM,UAAU,IAAI,SAAU,EAAG,CAAE,MAAO,IAAM,EAAI,MAAO,KAAK,MACxF,EAAe,uBAAyB,EAAO,IAAM,uBAAyB,EAElF,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,KAGrE,EAAO,cAAc,OAAS,CAAC,EAAO,KAEtC,GAAI,GAAa,EAAO,aAExB,GAAI,GAAc,KAAW,CAC3B,GAAI,GAAe,gCACnB,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,KAGrE,OAAQ,EAAW,UACZ,GAAK,WAAW,KACnB,MAAO,GAAK,YAAY,kBAExB,GAAI,GAAe,0BAA4B,EAAW,KAAO,IACjE,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAW,MAAO,EAAW,QAIjF,EAAK,YAAY,UAAY,SAAU,EAAQ,CAC7C,GAAI,GAAS,EAAO,gBAEpB,GAAI,GAAU,KAId,GAAO,cAAc,KAAO,EAAO,IAAI,cAEnC,EAAO,IAAI,QAAQ,MAAQ,IAC7B,GAAO,cAAc,YAAc,IAGrC,GAAI,GAAa,EAAO,aAExB,GAAI,GAAc,KAAW,CAC3B,EAAO,aACP,OAGF,OAAQ,EAAW,UACZ,GAAK,WAAW,KACnB,SAAO,aACA,EAAK,YAAY,cACrB,GAAK,WAAW,MACnB,SAAO,aACA,EAAK,YAAY,eACrB,GAAK,WAAW,cACnB,MAAO,GAAK,YAAY,sBACrB,GAAK,WAAW,MACnB,MAAO,GAAK,YAAY,eACrB,GAAK,WAAW,SACnB,SAAO,aACA,EAAK,YAAY,sBAExB,GAAI,GAAe,2BAA6B,EAAW,KAAO,IAClE,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAW,MAAO,EAAW,QAIjF,EAAK,YAAY,kBAAoB,SAAU,EAAQ,CACrD,GAAI,GAAS,EAAO,gBAEpB,GAAI,GAAU,KAId,IAAI,GAAe,SAAS,EAAO,IAAK,IAExC,GAAI,MAAM,GAAe,CACvB,GAAI,GAAe,gCACnB,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,KAGrE,EAAO,cAAc,aAAe,EAEpC,GAAI,GAAa,EAAO,aAExB,GAAI,GAAc,KAAW,CAC3B,EAAO,aACP,OAGF,OAAQ,EAAW,UACZ,GAAK,WAAW,KACnB,SAAO,aACA,EAAK,YAAY,cACrB,GAAK,WAAW,MACnB,SAAO,aACA,EAAK,YAAY,eACrB,GAAK,WAAW,cACnB,MAAO,GAAK,YAAY,sBACrB,GAAK,WAAW,MACnB,MAAO,GAAK,YAAY,eACrB,GAAK,WAAW,SACnB,SAAO,aACA,EAAK,YAAY,sBAExB,GAAI,GAAe,2BAA6B,EAAW,KAAO,IAClE,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAW,MAAO,EAAW,QAIjF,EAAK,YAAY,WAAa,SAAU,EAAQ,CAC9C,GAAI,GAAS,EAAO,gBAEpB,GAAI,GAAU,KAId,IAAI,GAAQ,SAAS,EAAO,IAAK,IAEjC,GAAI,MAAM,GAAQ,CAChB,GAAI,GAAe,wBACnB,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAO,MAAO,EAAO,KAGrE,EAAO,cAAc,MAAQ,EAE7B,GAAI,GAAa,EAAO,aAExB,GAAI,GAAc,KAAW,CAC3B,EAAO,aACP,OAGF,OAAQ,EAAW,UACZ,GAAK,WAAW,KACnB,SAAO,aACA,EAAK,YAAY,cACrB,GAAK,WAAW,MACnB,SAAO,aACA,EAAK,YAAY,eACrB,GAAK,WAAW,cACnB,MAAO,GAAK,YAAY,sBACrB,GAAK,WAAW,MACnB,MAAO,GAAK,YAAY,eACrB,GAAK,WAAW,SACnB,SAAO,aACA,EAAK,YAAY,sBAExB,GAAI,GAAe,2BAA6B,EAAW,KAAO,IAClE,KAAM,IAAI,GAAK,gBAAiB,EAAc,EAAW,MAAO,EAAW,QAQ7E,SAAU,EAAM,EAAS,CACzB,AAAI,MAAO,SAAW,YAAc,OAAO,IAEzC,OAAO,GACF,AAAI,MAAO,KAAY,SAM5B,GAAO,QAAU,IAGjB,EAAK,KAAO,KAEd,KAAM,UAAY,CAMlB,MAAO,WCh5GX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAQA,aAOA,GAAI,IAAkB,UAOtB,GAAO,QAAU,GAUjB,YAAoB,EAAQ,CAC1B,GAAI,GAAM,GAAK,EACX,EAAQ,GAAgB,KAAK,GAEjC,GAAI,CAAC,EACH,MAAO,GAGT,GAAI,GACA,EAAO,GACP,EAAQ,EACR,EAAY,EAEhB,IAAK,EAAQ,EAAM,MAAO,EAAQ,EAAI,OAAQ,IAAS,CACrD,OAAQ,EAAI,WAAW,QAChB,IACH,EAAS,SACT,UACG,IACH,EAAS,QACT,UACG,IACH,EAAS,QACT,UACG,IACH,EAAS,OACT,UACG,IACH,EAAS,OACT,cAEA,SAGJ,AAAI,IAAc,GAChB,IAAQ,EAAI,UAAU,EAAW,IAGnC,EAAY,EAAQ,EACpB,GAAQ,EAGV,MAAO,KAAc,EACjB,EAAO,EAAI,UAAU,EAAW,GAChC,KCtDN,OAAiB,QCAjB,OAAuB,OAiChB,YACL,EACmB,CACnB,GAAM,GAAY,GAAI,KAChB,EAAY,GAAI,KACtB,OAAW,KAAO,GAAM,CACtB,GAAM,CAAC,EAAM,GAAQ,EAAI,SAAS,MAAM,KAGlC,EAAW,EAAI,SACf,EAAW,EAAI,MAGf,EAAO,eAAW,EAAI,MACzB,QAAQ,mBAAoB,IAC5B,QAAQ,OAAQ,KAGnB,GAAI,EAAM,CACR,GAAM,GAAS,EAAU,IAAI,GAG7B,AAAK,EAAQ,IAAI,GASf,EAAU,IAAI,EAAU,CACtB,WACA,QACA,OACA,WAZF,GAAO,MAAQ,EAAI,MACnB,EAAO,KAAQ,EAGf,EAAQ,IAAI,QAcd,GAAU,IAAI,EAAU,CACtB,WACA,QACA,SAIN,MAAO,GCjFT,OAAuB,OAsChB,YACL,EAA2B,EACD,CAC1B,GAAM,GAAY,GAAI,QAAO,EAAO,UAAW,OACzC,EAAY,CAAC,EAAY,EAAc,IACpC,GAAG,4BAA+B,WAI3C,MAAO,AAAC,IAAkB,CACxB,EAAQ,EACL,QAAQ,gBAAiB,KACzB,OAGH,GAAM,GAAQ,GAAI,QAAO,MAAM,EAAO,cACpC,EACG,QAAQ,uBAAwB,QAChC,QAAQ,EAAW,QACnB,OAGL,MAAO,IACL,GACI,eAAW,GACX,GAED,QAAQ,EAAO,GACf,QAAQ,8BAA+B,OCpCzC,YACL,EACqB,CACrB,GAAM,GAAS,GAAK,MAAa,MAAM,CAAC,QAAS,SAIjD,MAHe,IAAK,MAAa,YAAY,EAAO,GAG7C,QACA,EAAM,QAWR,YACL,EAA4B,EACV,CAClB,GAAM,GAAU,GAAI,KAAuB,GAGrC,EAA2B,GACjC,OAAS,GAAI,EAAG,EAAI,EAAM,OAAQ,IAChC,OAAW,KAAU,GACnB,AAAI,EAAM,GAAG,WAAW,EAAO,OAC7B,GAAO,EAAO,MAAQ,GACtB,EAAQ,OAAO,IAIrB,OAAW,KAAU,GACnB,EAAO,EAAO,MAAQ,GAGxB,MAAO,GC4BT,YAAoB,EAAa,EAAuB,CACtD,GAAM,CAAC,EAAG,GAAK,CAAC,GAAI,KAAI,GAAI,GAAI,KAAI,IACpC,MAAO,CACL,GAAG,GAAI,KAAI,CAAC,GAAG,GAAG,OAAO,GAAS,CAAC,EAAE,IAAI,MAWtC,WAAa,CAgCX,YAAY,CAAE,SAAQ,OAAM,QAAO,WAAwB,CAChE,KAAK,QAAU,EAGf,KAAK,UAAY,GAAuB,GACxC,KAAK,UAAY,GAAuB,EAAQ,IAGhD,KAAK,UAAU,UAAY,GAAI,QAAO,EAAO,WAG7C,AAAI,MAAO,IAAU,YACnB,KAAK,MAAQ,KAAK,UAAY,CAG5B,AAAI,EAAO,KAAK,SAAW,GAAK,EAAO,KAAK,KAAO,KACjD,KAAK,IAAK,KAAa,EAAO,KAAK,KAC1B,EAAO,KAAK,OAAS,GAC9B,KAAK,IAAK,KAAa,cAAc,GAAG,EAAO,OAIjD,GAAM,GAAM,GAAW,CACrB,UAAW,iBAAkB,WAC5B,EAAQ,UAGX,OAAW,KAAQ,GAAO,KAAK,IAAI,GACjC,IAAa,KAAO,KAAQ,KAAa,IAEzC,OAAW,KAAM,GACf,KAAK,SAAS,OAAO,EAAK,IAC1B,KAAK,eAAe,OAAO,EAAK,IAKpC,KAAK,IAAI,YAGT,KAAK,MAAM,QAAS,CAAE,MAAO,MAC7B,KAAK,MAAM,QAGX,OAAW,KAAO,GAChB,KAAK,IAAI,KAKb,KAAK,MAAQ,KAAK,MAAM,KAAK,GAoB1B,OAAO,EAA6B,CACzC,GAAI,EACF,GAAI,CACF,GAAM,GAAY,KAAK,UAAU,GAG3B,EAAU,GAAiB,GAC9B,OAAO,GACN,EAAO,WAAa,KAAK,MAAM,SAAS,YAItC,EAAS,KAAK,MAAM,OAAO,GAAG,MAGjC,OAAyB,CAAC,EAAM,CAAE,MAAK,QAAO,eAAgB,CAC7D,GAAM,GAAW,KAAK,UAAU,IAAI,GACpC,GAAI,MAAO,IAAa,YAAa,CACnC,GAAM,CAAE,WAAU,QAAO,OAAM,UAAW,EAGpC,EAAQ,GACZ,EACA,OAAO,KAAK,EAAU,WAIlB,EAAQ,CAAC,CAAC,EAAS,EAAC,OAAO,OAAO,GAAO,MAAM,GAAK,GAC1D,EAAK,KAAK,CACR,WACA,MAAO,EAAU,GACjB,KAAO,EAAU,GACjB,MAAO,EAAS,GAAI,GACpB,UAGJ,MAAO,IACN,IAGF,KAAK,CAAC,EAAG,IAAM,EAAE,MAAQ,EAAE,OAG3B,OAAO,CAAC,EAAO,IAAW,CACzB,GAAM,GAAW,KAAK,UAAU,IAAI,EAAO,UAC3C,GAAI,MAAO,IAAa,YAAa,CACnC,GAAM,GAAM,UAAY,GACpB,EAAS,OAAQ,SACjB,EAAS,SACb,EAAM,IAAI,EAAK,CAAC,GAAG,EAAM,IAAI,IAAQ,GAAI,IAE3C,MAAO,IACN,GAAI,MAGL,EACJ,GAAI,KAAK,QAAQ,YAAa,CAC5B,GAAM,GAAS,KAAK,MAAM,MAAM,GAAW,CACzC,OAAW,KAAU,GACnB,EAAQ,KAAK,EAAO,KAAM,CACxB,OAAQ,CAAC,SACT,SAAU,KAAK,MAAM,SAAS,SAC9B,SAAU,KAAK,MAAM,SAAS,aAKpC,EAAc,EAAO,OACjB,OAAO,KAAK,EAAO,GAAG,UAAU,UAChC,GAIN,MAAO,IACL,MAAO,CAAC,GAAG,EAAO,WACf,MAAO,IAAgB,aAAe,CAAE,sBAIvC,EAAN,CACA,QAAQ,KAAK,kBAAkB,uCAKnC,MAAO,CAAE,MAAO,MChSb,GAAW,GAAX,UAAW,EAAX,CACL,qBACA,qBACA,qBACA,yBAJgB,WLwBlB,GAAI,GAqBJ,YACE,EACe,gCACf,GAAI,GAAO,UAGX,GAAI,MAAO,SAAW,aAAe,gBAAkB,QAAQ,CAC7D,GAAM,GAAS,SAAS,cAAiC,eACnD,CAAC,GAAQ,EAAO,IAAI,MAAM,WAGhC,EAAO,EAAK,QAAQ,KAAM,GAI5B,GAAM,GAAU,GAChB,OAAW,KAAQ,GAAO,KAAM,CAC9B,OAAQ,OAGD,KACH,EAAQ,KAAK,GAAG,gBAChB,UAGG,SACA,KACH,EAAQ,KAAK,GAAG,gBAChB,MAIJ,AAAI,IAAS,MACX,EAAQ,KAAK,GAAG,cAAiB,YAIrC,AAAI,EAAO,KAAK,OAAS,GACvB,EAAQ,KAAK,GAAG,2BAGd,EAAQ,QACV,MAAM,eACJ,GAAG,oCACH,GAAG,MAeT,YACE,EACwB,gCACxB,OAAQ,EAAQ,UAGT,GAAkB,MACrB,YAAM,IAAqB,EAAQ,KAAK,QACxC,EAAQ,GAAI,GAAO,EAAQ,MACpB,CACL,KAAM,EAAkB,WAIvB,GAAkB,MACrB,MAAO,CACL,KAAM,EAAkB,OACxB,KAAM,EAAQ,EAAM,OAAO,EAAQ,MAAQ,CAAE,MAAO,aAKtD,KAAM,IAAI,WAAU,2BAS1B,KAAK,KAAO,WAGZ,iBAAiB,UAAW,AAAM,GAAM,0BACtC,YAAY,KAAM,IAAQ,EAAG", + "names": [] } diff --git a/assets/stylesheets/main.6b80c2a2.min.css b/assets/stylesheets/main.6b80c2a2.min.css deleted file mode 100644 index 6c543308..00000000 --- a/assets/stylesheets/main.6b80c2a2.min.css +++ /dev/null @@ -1 +0,0 @@ -@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}@media (prefers-reduced-motion){*,:after,:before{transition:none!important}}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:initial;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:initial;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:transparent;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root,[data-md-color-scheme=default]{--md-default-fg-color:rgba(0,0,0,.87);--md-default-fg-color--light:rgba(0,0,0,.54);--md-default-fg-color--lighter:rgba(0,0,0,.32);--md-default-fg-color--lightest:rgba(0,0,0,.07);--md-default-bg-color:#fff;--md-default-bg-color--light:hsla(0,0%,100%,.7);--md-default-bg-color--lighter:hsla(0,0%,100%,.3);--md-default-bg-color--lightest:hsla(0,0%,100%,.12);--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7);--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-hl-color:rgba(255,255,0,.5);--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-mark-color:rgba(255,255,0,.5);--md-typeset-del-color:rgba(245,80,61,.15);--md-typeset-ins-color:rgba(11,213,112,.15);--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-table-color:rgba(0,0,0,.12);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-footer-fg-color:#fff;--md-footer-fg-color--light:hsla(0,0%,100%,.7);--md-footer-fg-color--lighter:hsla(0,0%,100%,.3);--md-footer-bg-color:rgba(0,0,0,.87);--md-footer-bg-color--dark:rgba(0,0,0,.32);--md-shadow-z1:0 0.2rem 0.5rem rgba(0,0,0,.05),0 0 0.05rem rgba(0,0,0,.1);--md-shadow-z2:0 0.2rem 0.5rem rgba(0,0,0,.1),0 0 0.05rem rgba(0,0,0,.25);--md-shadow-z3:0 0.2rem 0.5rem rgba(0,0,0,.2),0 0 0.05rem rgba(0,0,0,.35)}.md-icon svg{fill:currentcolor;display:block;height:1.2rem;width:1.2rem}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--md-text-font-family:var(--md-text-font,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;--md-code-font-family:var(--md-code-font,_),SFMono-Regular,Consolas,Menlo,monospace}body,input{font-feature-settings:"kern","liga";font-family:var(--md-text-font-family)}body,code,input,kbd,pre{color:var(--md-typeset-color)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family)}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.8rem;line-height:1.6}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin-bottom:1em;margin-top:1em}.md-typeset h1{color:var(--md-default-fg-color--light);font-size:2em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{font-size:1.5625em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:400;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a:focus code,.md-typeset a:hover code{background-color:var(--md-accent-fg-color--transparent)}.md-typeset a code{color:currentcolor;transition:background-color 125ms}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.1rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:0 .2941176471em;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;outline-color:var(--md-accent-fg-color);overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.md-typeset kbd{background-color:var(--md-typeset-kbd-color);border-radius:.1rem;box-shadow:0 .1rem 0 .05rem var(--md-typeset-kbd-border-color),0 .1rem 0 var(--md-typeset-kbd-border-color),0 -.1rem .2rem var(--md-typeset-kbd-accent-color) inset;color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light);cursor:help;text-decoration:none}@media (hover:none){.md-typeset abbr{position:relative}.md-typeset abbr[title]:-webkit-any(:focus,:hover):after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z3);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;margin-top:2em;max-width:80%;min-width:-webkit-max-content;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}.md-typeset abbr[title]:-moz-any(:focus,:hover):after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z3);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;margin-top:2em;max-width:80%;min-width:-moz-max-content;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}[dir=ltr] .md-typeset abbr[title]:-webkit-any(:focus,:hover):after{left:0}[dir=ltr] .md-typeset abbr[title]:-moz-any(:focus,:hover):after{left:0}[dir=ltr] .md-typeset abbr[title]:is(:focus,:hover):after{left:0}[dir=rtl] .md-typeset abbr[title]:-webkit-any(:focus,:hover):after{right:0}[dir=rtl] .md-typeset abbr[title]:-moz-any(:focus,:hover):after{right:0}[dir=rtl] .md-typeset abbr[title]:is(:focus,:hover):after{right:0}.md-typeset abbr[title]:is(:focus,:hover):after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z3);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;margin-top:2em;max-width:80%;min-width:-webkit-max-content;min-width:-moz-max-content;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}}.md-typeset small{opacity:.75}[dir=ltr] .md-typeset sub,[dir=ltr] .md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-right:.078125em}[dir=ltr] .md-typeset blockquote{padding-left:.6rem}[dir=rtl] .md-typeset blockquote{padding-right:.6rem}[dir=ltr] .md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter)}[dir=rtl] .md-typeset blockquote{border-right:.2rem solid var(--md-default-fg-color--lighter)}.md-typeset blockquote{color:var(--md-default-fg-color--light);margin-left:0;margin-right:0}.md-typeset ul{list-style-type:disc}[dir=ltr] .md-typeset ol,[dir=ltr] .md-typeset ul{margin-left:.625em}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-right:.625em}.md-typeset ol,.md-typeset ul{padding:0}.md-typeset ol:not([hidden]),.md-typeset ul:not([hidden]){display:flow-root}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}[dir=ltr] .md-typeset ol li,[dir=ltr] .md-typeset ul li{margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-right:1.25em}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}.md-typeset ol li :-webkit-any(ul,ol),.md-typeset ul li :-webkit-any(ul,ol){margin-bottom:.5em;margin-top:.5em}.md-typeset ol li :-moz-any(ul,ol),.md-typeset ul li :-moz-any(ul,ol){margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset ol li :-webkit-any(ul,ol),[dir=ltr] .md-typeset ul li :-webkit-any(ul,ol){margin-left:.625em}[dir=ltr] .md-typeset ol li :-moz-any(ul,ol),[dir=ltr] .md-typeset ul li :-moz-any(ul,ol){margin-left:.625em}[dir=ltr] .md-typeset ol li :is(ul,ol),[dir=ltr] .md-typeset ul li :is(ul,ol){margin-left:.625em}[dir=rtl] .md-typeset ol li :-webkit-any(ul,ol),[dir=rtl] .md-typeset ul li :-webkit-any(ul,ol){margin-right:.625em}[dir=rtl] .md-typeset ol li :-moz-any(ul,ol),[dir=rtl] .md-typeset ul li :-moz-any(ul,ol){margin-right:.625em}[dir=rtl] .md-typeset ol li :is(ul,ol),[dir=rtl] .md-typeset ul li :is(ul,ol){margin-right:.625em}.md-typeset ol li :is(ul,ol),.md-typeset ul li :is(ul,ol){margin-bottom:.5em;margin-top:.5em}[dir=ltr] .md-typeset dd{margin-left:1.875em}[dir=rtl] .md-typeset dd{margin-right:1.875em}.md-typeset dd{margin-bottom:1.5em;margin-top:1em}.md-typeset img,.md-typeset svg,.md-typeset video{height:auto;max-width:100%}.md-typeset img[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child{margin-top:0}.md-typeset img[src$="#gh-dark-mode-only"],.md-typeset img[src$="#only-dark"]{display:none}.md-typeset figure{display:flow-root;margin:1em auto;max-width:100%;text-align:center;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.md-typeset figure img{display:block}.md-typeset figcaption{font-style:italic;margin:1em auto;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table:not([class]){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:inline-block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto}@media print{.md-typeset table:not([class]){display:table}}.md-typeset table:not([class])+*{margin-top:1.5em}.md-typeset table:not([class]) :-webkit-any(th,td)>:first-child{margin-top:0}.md-typeset table:not([class]) :-moz-any(th,td)>:first-child{margin-top:0}.md-typeset table:not([class]) :is(th,td)>:first-child{margin-top:0}.md-typeset table:not([class]) :-webkit-any(th,td)>:last-child{margin-bottom:0}.md-typeset table:not([class]) :-moz-any(th,td)>:last-child{margin-bottom:0}.md-typeset table:not([class]) :is(th,td)>:last-child{margin-bottom:0}.md-typeset table:not([class]) :-webkit-any(th,td):not([align]){text-align:left}.md-typeset table:not([class]) :-moz-any(th,td):not([align]){text-align:left}.md-typeset table:not([class]) :is(th,td):not([align]){text-align:left}[dir=rtl] .md-typeset table:not([class]) :-webkit-any(th,td):not([align]){text-align:right}[dir=rtl] .md-typeset table:not([class]) :-moz-any(th,td):not([align]){text-align:right}[dir=rtl] .md-typeset table:not([class]) :is(th,td):not([align]){text-align:right}.md-typeset table:not([class]) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) tbody tr{transition:background-color 125ms}.md-typeset table:not([class]) tbody tr:hover{background-color:rgba(0,0,0,.035);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table:not([class]) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}[dir=ltr] .md-typeset table th[role=columnheader]:after{margin-left:.5em}[dir=rtl] .md-typeset table th[role=columnheader]:after{margin-right:.5em}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}@media screen and (max-width:44.9375em){.md-content__inner>pre{margin:1em -.8rem}.md-content__inner>pre code{border-radius:0}}.md-banner{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color);overflow:auto}@media print{.md-banner{display:none}}.md-banner--warning{background:var(--md-typeset-mark-color);color:var(--md-default-fg-color)}.md-banner__inner{font-size:.7rem;margin:.6rem auto;padding:0 .8rem}.md-banner__button{color:inherit;cursor:pointer;float:right;transition:opacity .25s}.md-banner__button:hover{opacity:.7}html{font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.9375em){body[data-md-scrolllock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;position:absolute;right:.5em;top:.5em;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-clipboard:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-clipboard:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentcolor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:-webkit-any(:focus,:hover) code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-clipboard--inline:-moz-any(:focus,:hover) code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-clipboard--inline:is(:focus,:hover) code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}@-webkit-keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes consent{0%{opacity:0;transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@-webkit-keyframes overlay{0%{opacity:0}to{opacity:1}}@keyframes overlay{0%{opacity:0}to{opacity:1}}.md-consent__overlay{-webkit-animation:overlay .25s both;animation:overlay .25s both;-webkit-backdrop-filter:blur(.1rem);backdrop-filter:blur(.1rem);background-color:rgba(0,0,0,.54);height:100%;opacity:1;position:fixed;top:0;width:100%;z-index:5}.md-consent__inner{-webkit-animation:consent .5s cubic-bezier(.1,.7,.1,1) both;animation:consent .5s cubic-bezier(.1,.7,.1,1) both;background-color:var(--md-default-bg-color);border:0;border-radius:.1rem;bottom:0;box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2);max-height:100%;overflow:auto;padding:0;position:fixed;width:100%;z-index:5}.md-consent__form{padding:.8rem}.md-consent__settings{display:none;margin:1em 0}input:checked+.md-consent__settings{display:block}.md-consent__controls{margin-bottom:.8rem}.md-typeset .md-consent__controls .md-button{display:inline}@media screen and (max-width:44.9375em){.md-typeset .md-consent__controls .md-button{display:block;margin-top:.4rem;text-align:center;width:100%}}.md-consent label{cursor:pointer}.md-content{flex-grow:1;min-width:0}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner,[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}[dir=ltr] .md-content__button{margin-left:.4rem}[dir=rtl] .md-content__button{margin-right:.4rem}.md-content__button{float:right;margin:.4rem 0;padding:0}@media print{.md-content__button{display:none}}[dir=rtl] .md-content__button{float:left}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}[dir=ltr] .md-dialog{right:.8rem}[dir=rtl] .md-dialog{left:.8rem}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:var(--md-shadow-z3);min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:4}@media print{.md-dialog{display:none}}.md-dialog--active{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-feedback{margin:2em 0 1em;text-align:center}.md-feedback fieldset{border:none;margin:0;padding:0}.md-feedback__title{font-weight:700;margin:1em auto}.md-feedback__inner{position:relative}.md-feedback__list{align-content:baseline;display:flex;flex-wrap:wrap;justify-content:center;position:relative}.md-feedback__list:hover .md-icon:not(:disabled){color:var(--md-default-fg-color--lighter)}:disabled .md-feedback__list{min-height:1.8rem}.md-feedback__icon{color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;margin:0 .1rem;transition:color 125ms}.md-feedback__icon:not(:disabled).md-icon:hover{color:var(--md-accent-fg-color)}.md-feedback__icon:disabled{color:var(--md-default-fg-color--lightest);pointer-events:none}.md-feedback__note{opacity:0;position:relative;transform:translateY(.4rem);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-feedback__note>*{margin:0 auto;max-width:16rem}:disabled .md-feedback__note{opacity:1;transform:translateY(0)}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{justify-content:space-between;overflow:auto;padding:.2rem}.md-footer__inner:not([hidden]){display:flex}.md-footer__link{display:flex;flex-grow:0.01;outline-color:var(--md-accent-fg-color);overflow:hidden;padding-bottom:.4rem;padding-top:1.4rem;transition:opacity .25s}.md-footer__link:-webkit-any(:focus,:hover){opacity:.7}.md-footer__link:-moz-any(:focus,:hover){opacity:.7}.md-footer__link:is(:focus,:hover){opacity:.7}[dir=rtl] .md-footer__link svg{transform:scaleX(-1)}@media screen and (max-width:44.9375em){.md-footer__link--prev .md-footer__title{display:none}}[dir=ltr] .md-footer__link--next{margin-left:auto}[dir=rtl] .md-footer__link--next{margin-right:auto}.md-footer__link--next{text-align:right}[dir=rtl] .md-footer__link--next{text-align:left}.md-footer__title{flex-grow:1;font-size:.9rem;line-height:2.4rem;max-width:calc(100% - 2.4rem);padding:0 1rem;position:relative;white-space:nowrap}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;left:0;margin-top:-1rem;opacity:.7;padding:0 1rem;position:absolute;right:0}.md-footer-meta{background-color:var(--md-footer-bg-color--dark)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a{color:var(--md-footer-fg-color--light)}html .md-footer-meta.md-typeset a:-webkit-any(:focus,:hover){color:var(--md-footer-fg-color)}html .md-footer-meta.md-typeset a:-moz-any(:focus,:hover){color:var(--md-footer-fg-color)}html .md-footer-meta.md-typeset a:is(:focus,:hover){color:var(--md-footer-fg-color)}.md-copyright{color:var(--md-footer-fg-color--lighter);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-copyright{width:auto}}.md-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-social{margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-social{padding:.6rem 0}}.md-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-social__link:before{line-height:1.9}.md-social__link svg{fill:currentcolor;max-height:.8rem;vertical-align:-25%}.md-typeset .md-button{border:.1rem solid;border-radius:.1rem;color:var(--md-primary-fg-color);cursor:pointer;display:inline-block;font-weight:700;padding:.625em 2em;transition:color 125ms,background-color 125ms,border-color 125ms}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);border-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-typeset .md-button:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-typeset .md-button:is(:focus,:hover){background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[dir=ltr] .md-typeset .md-input{border-top-left-radius:.1rem}[dir=ltr] .md-typeset .md-input,[dir=rtl] .md-typeset .md-input{border-top-right-radius:.1rem}[dir=rtl] .md-typeset .md-input{border-top-left-radius:.1rem}.md-typeset .md-input{border-bottom:.1rem solid var(--md-default-fg-color--lighter);box-shadow:var(--md-shadow-z1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:border .25s,box-shadow .25s}.md-typeset .md-input:-webkit-any(:focus,:hover){border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input:-moz-any(:focus,:hover){border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input:is(:focus,:hover){border-bottom-color:var(--md-accent-fg-color);box-shadow:var(--md-shadow-z2)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem transparent,0 .2rem .4rem transparent;color:var(--md-primary-bg-color);display:block;left:0;position:-webkit-sticky;position:sticky;right:0;top:0;z-index:4}@media print{.md-header{display:none}}.md-header[hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1),box-shadow .25s}.md-header--shadow{box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2);transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header__inner{align-items:center;display:flex;padding:0 .2rem}.md-header__button{color:currentcolor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.1875em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo :-webkit-any(img,svg){fill:currentcolor;display:block;height:1.2rem;width:auto}.md-header__button.md-logo :-moz-any(img,svg){fill:currentcolor;display:block;height:1.2rem;width:auto}.md-header__button.md-logo :is(img,svg){fill:currentcolor;display:block;height:1.2rem;width:auto}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;white-space:nowrap}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__topic:first-child{font-weight:700}[dir=ltr] .md-header__title{margin-right:.4rem}[dir=rtl] .md-header__title{margin-left:.4rem}[dir=ltr] .md-header__title{margin-left:1rem}[dir=rtl] .md-header__title{margin-right:1rem}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem}.md-header__title--active .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title--active .md-header__topic{transform:translateX(1.25rem)}.md-header__title--active .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;transition:max-width 0ms .25s,opacity .25s .25s;white-space:nowrap}[data-md-toggle=search]:checked~.md-header .md-header__option{max-width:0;opacity:0;transition:max-width 0ms,opacity 0ms}.md-header__source{display:none}@media screen and (min-width:60em){[dir=ltr] .md-header__source{margin-left:1rem}[dir=rtl] .md-header__source{margin-right:1rem}.md-header__source{display:block;max-width:11.7rem;width:11.7rem}}@media screen and (min-width:76.25em){[dir=ltr] .md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}:root{--md-nav-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,');--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3}.md-nav__title{display:block;font-weight:700;overflow:hidden;padding:0 .6rem;text-overflow:ellipsis}.md-nav__title .md-nav__button{display:none}.md-nav__title .md-nav__button img{height:100%;width:auto}.md-nav__title .md-nav__button.md-logo :-webkit-any(img,svg){fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__title .md-nav__button.md-logo :-moz-any(img,svg){fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__title .md-nav__button.md-logo :is(img,svg){fill:currentcolor;display:block;height:2.4rem;max-width:100%;object-fit:contain;width:auto}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__item{padding:0 .6rem}[dir=ltr] .md-nav__item .md-nav__item{padding-right:0}[dir=rtl] .md-nav__item .md-nav__item{padding-left:0}.md-nav__link{align-items:center;cursor:pointer;display:flex;justify-content:space-between;margin-top:.625em;overflow:hidden;scroll-snap-align:start;text-overflow:ellipsis;transition:color 125ms}.md-nav__link--passed{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active{color:var(--md-typeset-a-color)}.md-nav__item .md-nav__link--index [href]{width:100%}.md-nav__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-nav--primary .md-nav__link[for=__toc]{display:none}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{background-color:currentcolor;display:block;height:100%;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);width:100%}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__link>*{cursor:pointer;display:flex}.md-nav__icon{flex-shrink:0}.md-nav__source{display:none}@media screen and (max-width:76.1875em){.md-nav--primary,.md-nav--primary .md-nav{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;height:100%;left:0;position:absolute;right:0;top:0;z-index:1}.md-nav--primary :-webkit-any(.md-nav__title,.md-nav__item){font-size:.8rem;line-height:1.5}.md-nav--primary :-moz-any(.md-nav__title,.md-nav__item){font-size:.8rem;line-height:1.5}.md-nav--primary :is(.md-nav__title,.md-nav__item){font-size:.8rem;line-height:1.5}.md-nav--primary .md-nav__title{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);cursor:pointer;height:5.6rem;line-height:2.4rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}[dir=ltr] .md-nav--primary .md-nav__title .md-nav__icon{left:.4rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{right:.4rem}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}.md-nav--primary .md-nav__title .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--prev);mask-image:var(--md-nav-icon--prev);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}.md-nav--primary .md-nav__title~.md-nav__list{background-color:var(--md-default-bg-color);box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest) inset;overflow-y:auto;-ms-scroll-snap-type:y mandatory;scroll-snap-type:y mandatory;touch-action:pan-y}.md-nav--primary .md-nav__title~.md-nav__list>:first-child{border-top:0}.md-nav--primary .md-nav__title[for=__drawer]{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);font-weight:700}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;right:.2rem;top:.2rem}.md-nav--primary .md-nav__list{flex:1}.md-nav--primary .md-nav__item{border-top:.05rem solid var(--md-default-fg-color--lightest);padding:0}.md-nav--primary .md-nav__item--active>.md-nav__link{color:var(--md-typeset-a-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link{margin-top:0;padding:.6rem .8rem}[dir=ltr] .md-nav--primary .md-nav__link .md-nav__icon{margin-right:-.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{margin-left:-.2rem}.md-nav--primary .md-nav__link .md-nav__icon{font-size:1.2rem;height:1.2rem;width:1.2rem}.md-nav--primary .md-nav__link .md-nav__icon:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-nav--primary .md-nav__icon:after{transform:scale(-1)}.md-nav--primary .md-nav--secondary .md-nav{background-color:initial;position:static}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:1.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-right:1.4rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-right:2rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:2.6rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-right:2.6rem}[dir=ltr] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:3.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-right:3.2rem}.md-nav--secondary{background-color:initial}.md-nav__toggle~.md-nav{display:flex;opacity:0;transform:translateX(100%);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity 125ms 50ms}[dir=rtl] .md-nav__toggle~.md-nav{transform:translateX(-100%)}.md-nav__toggle:checked~.md-nav{opacity:1;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 125ms 125ms}.md-nav__toggle:checked~.md-nav>.md-nav__list{-webkit-backface-visibility:hidden;backface-visibility:hidden}}@media screen and (max-width:59.9375em){.md-nav--primary .md-nav__link[for=__toc]{display:flex}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--primary .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:flex}.md-nav__source{background-color:var(--md-primary-fg-color--dark);color:var(--md-primary-bg-color);display:block;padding:0 .2rem}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-nav--integrated .md-nav__link[for=__toc]{display:flex}.md-nav--integrated .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--integrated .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{display:flex}}@media screen and (min-width:60em){.md-nav--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}}@media screen and (min-width:76.25em){.md-nav{transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon,.md-nav__toggle~.md-nav{display:none}.md-nav__toggle:-webkit-any(:checked,:indeterminate)~.md-nav{display:block}.md-nav__toggle:-moz-any(:checked,:indeterminate)~.md-nav{display:block}.md-nav__toggle:is(:checked,:indeterminate)~.md-nav{display:block}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--section{display:block;margin:1.25em 0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700;pointer-events:none}.md-nav__item--section>.md-nav__link--index [href]{pointer-events:auto}.md-nav__item--section>.md-nav__link .md-nav__icon{display:none}.md-nav__item--section>.md-nav{display:block}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{border-radius:100%;float:right;height:.9rem;transition:background-color .25s,transform .25s;width:.9rem}[dir=rtl] .md-nav__icon{float:left;transform:rotate(180deg)}.md-nav__icon:hover{background-color:var(--md-accent-fg-color--transparent)}.md-nav__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:-.1rem;width:100%}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon,.md-nav__item--nested .md-nav__toggle:indeterminate~.md-nav__link .md-nav__icon{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item,.md-nav--lifted>.md-nav__list>.md-nav__item--nested,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block;padding:0}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{font-weight:700;margin-top:0;padding:0 .6rem;pointer-events:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link--index [href]{pointer-events:auto}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link .md-nav__icon{display:none}.md-nav--lifted .md-nav[data-md-level="1"]{display:block}[dir=ltr] .md-nav--lifted .md-nav[data-md-level="1"]>.md-nav__list>.md-nav__item{padding-right:.6rem}[dir=rtl] .md-nav--lifted .md-nav[data-md-level="1"]>.md-nav__list>.md-nav__item{padding-left:.6rem}.md-nav--integrated>.md-nav__list>.md-nav__item--active:not(.md-nav__item--nested){padding:0 .6rem}.md-nav--integrated>.md-nav__list>.md-nav__item--active:not(.md-nav__item--nested)>.md-nav__link{padding:0}[dir=ltr] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-primary-fg-color)}[dir=rtl] .md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-right:.05rem solid var(--md-primary-fg-color)}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{display:block;margin-bottom:1.25em}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}}:root{--md-search-result-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:60em){.md-search{padding:.2rem 0}}.no-js .md-search{display:none}.md-search__overlay{opacity:0;z-index:1}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__overlay{left:-2.2rem}[dir=rtl] .md-search__overlay{right:-2.2rem}.md-search__overlay{background-color:var(--md-default-bg-color);border-radius:1rem;height:2rem;overflow:hidden;pointer-events:none;position:absolute;top:-1rem;transform-origin:center;transition:transform .3s .1s,opacity .2s .2s;width:2rem}[data-md-toggle=search]:checked~.md-header .md-search__overlay{opacity:1;transition:transform .4s,opacity .1s}}@media screen and (min-width:60em){[dir=ltr] .md-search__overlay{left:0}[dir=rtl] .md-search__overlay{right:0}.md-search__overlay{background-color:rgba(0,0,0,.54);cursor:pointer;height:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0}[data-md-toggle=search]:checked~.md-header .md-search__overlay{height:200vh;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@media screen and (max-width:29.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(45)}}@media screen and (min-width:30em) and (max-width:44.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(60)}}@media screen and (min-width:45em) and (max-width:59.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(75)}}.md-search__inner{-webkit-backface-visibility:hidden;backface-visibility:hidden}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__inner{left:0}[dir=rtl] .md-search__inner{right:0}.md-search__inner{height:0;opacity:0;overflow:hidden;position:fixed;top:0;transform:translateX(5%);transition:width 0ms .3s,height 0ms .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;width:0;z-index:2}[dir=rtl] .md-search__inner{transform:translateX(-5%)}[data-md-toggle=search]:checked~.md-header .md-search__inner{height:100%;opacity:1;transform:translateX(0);transition:width 0ms 0ms,height 0ms 0ms,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;width:100%}}@media screen and (min-width:60em){.md-search__inner{float:right;padding:.1rem 0;position:relative;transition:width .25s cubic-bezier(.1,.7,.1,1);width:11.7rem}[dir=rtl] .md-search__inner{float:left}}@media screen and (min-width:60em) and (max-width:76.1875em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:23.4rem}}@media screen and (min-width:76.25em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:34.4rem}}.md-search__form{background-color:var(--md-default-bg-color);box-shadow:0 0 .6rem transparent;height:2.4rem;position:relative;transition:color .25s,background-color .25s;z-index:2}@media screen and (min-width:60em){.md-search__form{background-color:rgba(0,0,0,.26);border-radius:.1rem;height:1.8rem}.md-search__form:hover{background-color:hsla(0,0%,100%,.12)}}[data-md-toggle=search]:checked~.md-header .md-search__form{background-color:var(--md-default-bg-color);border-radius:.1rem .1rem 0 0;box-shadow:0 0 .6rem rgba(0,0,0,.07);color:var(--md-default-fg-color)}[dir=ltr] .md-search__input{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__input{padding-left:2.2rem;padding-right:3.6rem}.md-search__input{background:transparent;font-size:.9rem;height:100%;position:relative;text-overflow:ellipsis;width:100%;z-index:2}.md-search__input::-ms-input-placeholder{-ms-transition:color .25s;transition:color .25s}.md-search__input::placeholder{transition:color .25s}.md-search__input::-ms-input-placeholder{color:var(--md-default-fg-color--light)}.md-search__input::placeholder,.md-search__input~.md-search__icon{color:var(--md-default-fg-color--light)}.md-search__input::-ms-clear{display:none}@media screen and (max-width:59.9375em){.md-search__input{font-size:.9rem;height:2.4rem;width:100%}}@media screen and (min-width:60em){[dir=ltr] .md-search__input{padding-left:2.2rem}[dir=rtl] .md-search__input{padding-right:2.2rem}.md-search__input{color:inherit;font-size:.8rem}.md-search__input::-ms-input-placeholder{color:var(--md-primary-bg-color--light)}.md-search__input::placeholder{color:var(--md-primary-bg-color--light)}.md-search__input+.md-search__icon{color:var(--md-primary-bg-color)}[data-md-toggle=search]:checked~.md-header .md-search__input{text-overflow:clip}[data-md-toggle=search]:checked~.md-header .md-search__input::-ms-input-placeholder{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:var(--md-default-fg-color--light)}}.md-search__icon{cursor:pointer;display:inline-block;height:1.2rem;transition:color .25s,opacity .25s;width:1.2rem}.md-search__icon:hover{opacity:.7}[dir=ltr] .md-search__icon[for=__search]{left:.5rem}[dir=rtl] .md-search__icon[for=__search]{right:.5rem}.md-search__icon[for=__search]{position:absolute;top:.3rem;z-index:2}[dir=rtl] .md-search__icon[for=__search] svg{transform:scaleX(-1)}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__icon[for=__search]{left:.8rem}[dir=rtl] .md-search__icon[for=__search]{right:.8rem}.md-search__icon[for=__search]{top:.6rem}.md-search__icon[for=__search] svg:first-child{display:none}}@media screen and (min-width:60em){.md-search__icon[for=__search]{pointer-events:none}.md-search__icon[for=__search] svg:last-child{display:none}}[dir=ltr] .md-search__options{right:.5rem}[dir=rtl] .md-search__options{left:.5rem}.md-search__options{pointer-events:none;position:absolute;top:.3rem;z-index:2}@media screen and (max-width:59.9375em){[dir=ltr] .md-search__options{right:.8rem}[dir=rtl] .md-search__options{left:.8rem}.md-search__options{top:.6rem}}[dir=ltr] .md-search__options>*{margin-left:.2rem}[dir=rtl] .md-search__options>*{margin-right:.2rem}.md-search__options>*{color:var(--md-default-fg-color--light);opacity:0;transform:scale(.75);transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-search__options>:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>*{opacity:1;pointer-events:auto;transform:scale(1)}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>:hover{opacity:.7}[dir=ltr] .md-search__suggest{padding-left:3.6rem;padding-right:2.2rem}[dir=rtl] .md-search__suggest{padding-left:2.2rem;padding-right:3.6rem}.md-search__suggest{align-items:center;color:var(--md-default-fg-color--lighter);display:flex;font-size:.9rem;height:100%;opacity:0;position:absolute;top:0;transition:opacity 50ms;white-space:nowrap;width:100%}@media screen and (min-width:60em){[dir=ltr] .md-search__suggest{padding-left:2.2rem}[dir=rtl] .md-search__suggest{padding-right:2.2rem}.md-search__suggest{font-size:.8rem}}[data-md-toggle=search]:checked~.md-header .md-search__suggest{opacity:1;transition:opacity .3s .1s}[dir=ltr] .md-search__output{border-bottom-left-radius:.1rem}[dir=ltr] .md-search__output,[dir=rtl] .md-search__output{border-bottom-right-radius:.1rem}[dir=rtl] .md-search__output{border-bottom-left-radius:.1rem}.md-search__output{overflow:hidden;position:absolute;width:100%;z-index:1}@media screen and (max-width:59.9375em){.md-search__output{bottom:0;top:2.4rem}}@media screen and (min-width:60em){.md-search__output{opacity:0;top:1.9rem;transition:opacity .4s}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:var(--md-shadow-z3);opacity:1}}.md-search__scrollwrap{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);height:100%;overflow-y:auto;touch-action:pan-y}@media (-webkit-max-device-pixel-ratio:1),(max-resolution:1dppx){.md-search__scrollwrap{transform:translateZ(0)}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-search__scrollwrap{width:23.4rem}}@media screen and (min-width:76.25em){.md-search__scrollwrap{width:34.4rem}}@media screen and (min-width:60em){.md-search__scrollwrap{max-height:0;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-search__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}}.md-search-result{color:var(--md-default-fg-color);word-break:break-word}.md-search-result__meta{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.8rem;padding:0 .8rem;scroll-snap-align:start}@media screen and (min-width:60em){[dir=ltr] .md-search-result__meta{padding-left:2.2rem}[dir=rtl] .md-search-result__meta{padding-right:2.2rem}}.md-search-result__list{list-style:none;margin:0;padding:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.md-search-result__item{box-shadow:0 -.05rem var(--md-default-fg-color--lightest)}.md-search-result__item:first-child{box-shadow:none}.md-search-result__link{display:block;outline:none;scroll-snap-align:start;transition:background-color .25s}.md-search-result__link:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:is(:focus,:hover){background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:last-child p:last-child{margin-bottom:.6rem}.md-search-result__more summary{color:var(--md-typeset-a-color);cursor:pointer;display:block;font-size:.64rem;outline:none;padding:.75em .8rem;scroll-snap-align:start;transition:color .25s,background-color .25s}@media screen and (min-width:60em){[dir=ltr] .md-search-result__more summary{padding-left:2.2rem}[dir=rtl] .md-search-result__more summary{padding-right:2.2rem}}.md-search-result__more summary:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary:is(:focus,:hover){background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary::marker{display:none}.md-search-result__more summary::-webkit-details-marker{display:none}.md-search-result__more summary~*>*{opacity:.65}.md-search-result__article{overflow:hidden;padding:0 .8rem;position:relative}@media screen and (min-width:60em){[dir=ltr] .md-search-result__article{padding-left:2.2rem}[dir=rtl] .md-search-result__article{padding-right:2.2rem}}.md-search-result__article--document .md-search-result__title{font-size:.8rem;font-weight:400;line-height:1.4;margin:.55rem 0}[dir=ltr] .md-search-result__icon{left:0}[dir=rtl] .md-search-result__icon{right:0}.md-search-result__icon{color:var(--md-default-fg-color--light);height:1.2rem;margin:.5rem;position:absolute;width:1.2rem}@media screen and (max-width:59.9375em){.md-search-result__icon{display:none}}.md-search-result__icon:after{background-color:currentcolor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-search-result-icon);mask-image:var(--md-search-result-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-search-result__icon:after{transform:scaleX(-1)}.md-search-result__title{font-size:.64rem;font-weight:700;line-height:1.6;margin:.5em 0}.md-search-result__teaser{-webkit-box-orient:vertical;-webkit-line-clamp:2;color:var(--md-default-fg-color--light);display:-webkit-box;font-size:.64rem;line-height:1.6;margin:.5em 0;max-height:2rem;overflow:hidden;text-overflow:ellipsis}@media screen and (max-width:44.9375em){.md-search-result__teaser{-webkit-line-clamp:3;max-height:3rem}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-search-result__teaser{-webkit-line-clamp:3;max-height:3rem}}.md-search-result__teaser mark{background-color:initial;text-decoration:underline}.md-search-result__terms{font-size:.64rem;font-style:italic;margin:.5em 0}.md-search-result mark{background-color:initial;color:var(--md-accent-fg-color)}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}.md-select:-webkit-any(:focus-within,:hover) .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);-webkit-transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms;transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select:-moz-any(:focus-within,:hover) .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);-moz-transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms;transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select:is(:focus-within,:hover) .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select__inner:after{border-bottom:.2rem solid transparent;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid transparent;border-right:.2rem solid transparent;border-top:0;content:"";height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}[dir=ltr] .md-select__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}.md-select__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-select__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-select__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.2rem 0;position:-webkit-sticky;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.1875em){[dir=ltr] .md-sidebar--primary{left:-12.1rem}[dir=rtl] .md-sidebar--primary{right:-12.1rem}.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:5}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:var(--md-shadow-z3);transform:translateX(12.1rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.1rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overflow:hidden;position:absolute;right:0;-ms-scroll-snap-type:none;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}}.md-sidebar--secondary{display:none;order:2}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{-webkit-backface-visibility:hidden;backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@media screen and (max-width:76.1875em){.md-overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:5}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@-webkit-keyframes facts{0%{height:0}to{height:.65rem}}@keyframes facts{0%{height:0}to{height:.65rem}}@-webkit-keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.65rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}[dir=ltr] .md-source__icon svg{margin-left:.6rem}[dir=rtl] .md-source__icon svg{margin-right:.6rem}.md-source__icon svg{margin-top:.6rem}[dir=ltr] .md-source__icon+.md-source__repository{margin-left:-2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-right:-2rem}[dir=ltr] .md-source__icon+.md-source__repository{padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{padding-right:2rem}[dir=ltr] .md-source__repository{margin-left:.6rem}[dir=rtl] .md-source__repository{margin-right:.6rem}.md-source__repository{display:inline-block;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{display:flex;font-size:.55rem;gap:.4rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0;width:100%}.md-source__repository--active .md-source__facts{-webkit-animation:facts .25s ease-in;animation:facts .25s ease-in}.md-source__fact{overflow:hidden;text-overflow:ellipsis}.md-source__repository--active .md-source__fact{-webkit-animation:fact .4s ease-out;animation:fact .4s ease-out}[dir=ltr] .md-source__fact:before{margin-right:.1rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem}.md-source__fact:before{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}.md-source__fact:nth-child(1n+2){flex-shrink:0}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);display:block;line-height:1.3;overflow:auto;width:100%;z-index:3}@media print{.md-tabs{display:none}}@media screen and (max-width:76.1875em){.md-tabs{display:none}}.md-tabs[hidden]{pointer-events:none}[dir=ltr] .md-tabs__list{margin-left:.2rem}[dir=rtl] .md-tabs__list{margin-right:.2rem}.md-tabs__list{contain:content;list-style:none;margin:0;padding:0;white-space:nowrap}.md-tabs__item{display:inline-block;height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__link{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link--active,.md-tabs__link:-webkit-any(:focus,:hover){color:inherit;opacity:1}.md-tabs__link--active,.md-tabs__link:-moz-any(:focus,:hover){color:inherit;opacity:1}.md-tabs__link--active,.md-tabs__link:is(:focus,:hover){color:inherit;opacity:1}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}.md-tags{margin-bottom:.75em}[dir=ltr] .md-tag{margin-right:.5em}[dir=rtl] .md-tag{margin-left:.5em}.md-tag{background:var(--md-default-fg-color--lightest);border-radius:.4rem;display:inline-block;font-size:.64rem;font-weight:700;line-height:1.6;margin-bottom:.5em;padding:.3125em .9375em}.md-tag[href]{-webkit-tap-highlight-color:transparent;color:inherit;outline:none;transition:color 125ms,background-color 125ms}.md-tag[href]:focus,.md-tag[href]:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}[id]>.md-tag{vertical-align:text-top}@-webkit-keyframes pulse{0%{box-shadow:0 0 0 0 var(--md-default-fg-color--lightest);transform:scale(.95)}75%{box-shadow:0 0 0 .625em transparent;transform:scale(1)}to{box-shadow:0 0 0 0 transparent;transform:scale(.95)}}@keyframes pulse{0%{box-shadow:0 0 0 0 var(--md-default-fg-color--lightest);transform:scale(.95)}75%{box-shadow:0 0 0 .625em transparent;transform:scale(1)}to{box-shadow:0 0 0 0 transparent;transform:scale(.95)}}:root{--md-tooltip-width:20rem}.md-tooltip{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);left:clamp(var(--md-tooltip-0,0rem) + .8rem,var(--md-tooltip-x),100vw + var(--md-tooltip-0,0rem) + .8rem - var(--md-tooltip-width) - 2 * .8rem);max-height:0;max-width:calc(100vw - 1.6rem);opacity:0;position:absolute;top:var(--md-tooltip-y);transform:translateY(-.4rem);transition:transform 0ms .25s,opacity .25s,max-height 0ms .25s,z-index .25s;width:var(--md-tooltip-width);z-index:0}:focus-within>.md-tooltip{max-height:1000%;opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height .25s,z-index 0ms}.focus-visible>.md-tooltip{outline:var(--md-accent-fg-color) auto}.md-tooltip__inner{font-size:.64rem;padding:.8rem}.md-tooltip__inner.md-typeset>:first-child{margin-top:0}.md-tooltip__inner.md-typeset>:last-child{margin-bottom:0}.md-annotation{outline:none;white-space:normal}[dir=rtl] .md-annotation{direction:rtl}.md-annotation:not([hidden]){display:inline-block;line-height:1.325}.md-annotation:focus-within>*{z-index:2}.md-annotation__inner{font-family:var(--md-text-font-family);top:calc(var(--md-tooltip-y) + 1.2ch)}:not(:focus-within)>.md-annotation__inner{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.md-annotation__index{color:#fff;cursor:pointer;margin:0 1ch;position:relative;transition:z-index .25s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:0}.md-annotation__index:after{background-color:var(--md-default-fg-color--lighter);border-radius:2ch;content:"";height:2.2ch;left:-.126em;margin:0 -.4ch;padding:0 .4ch;position:absolute;transition:color .25s,background-color .25s;width:calc(100% + 1.2ch);width:max(2.2ch,100% + 1.2ch);z-index:-1}@media not all and (prefers-reduced-motion){[data-md-visible]>.md-annotation__index:after{-webkit-animation:pulse 2s infinite;animation:pulse 2s infinite}}:-webkit-any(:focus-within,:hover)>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}:-moz-any(:focus-within,:hover)>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}:is(:focus-within,:hover)>.md-annotation__index:after{background-color:var(--md-accent-fg-color)}:focus-within>.md-annotation__index:after{-webkit-animation:none;animation:none;transition:color .25s,background-color .25s}.md-annotation__index [data-md-annotation-id]{display:inline-block;line-height:90%}.md-annotation__index [data-md-annotation-id]:before{content:attr(data-md-annotation-id);display:inline-block;padding-bottom:.1em;transform:scale(1.15);transition:transform .4s cubic-bezier(.1,.7,.1,1);vertical-align:.065em}@media not print{.md-annotation__index [data-md-annotation-id]:before{content:"+"}:focus-within>.md-annotation__index [data-md-annotation-id]:before{transform:scale(1.25) rotate(45deg)}}:-webkit-any(:focus-within,:hover)>.md-annotation__index{color:var(--md-accent-bg-color)}:-moz-any(:focus-within,:hover)>.md-annotation__index{color:var(--md-accent-bg-color)}:is(:focus-within,:hover)>.md-annotation__index{color:var(--md-accent-bg-color)}:focus-within>.md-annotation__index{-webkit-animation:none;animation:none;transition:none}[dir=ltr] .md-top{margin-left:50%}[dir=rtl] .md-top{margin-right:50%}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color--light);display:block;font-size:.7rem;outline:none;padding:.4rem .8rem;position:fixed;top:3.2rem;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{transform:translate(50%)}.md-top[hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[hidden]{transform:translate(50%,.2rem)}.md-top:-webkit-any(:focus,:hover){background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top:-moz-any(:focus,:hover){background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top:is(:focus,:hover){background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;vertical-align:-.5em}@-webkit-keyframes hoverfix{0%{pointer-events:none}}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}[dir=ltr] .md-version__current{margin-left:1.4rem;margin-right:.4rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current{color:inherit;cursor:pointer;outline:none;position:relative;top:.05rem}[dir=ltr] .md-version__current:after{margin-left:.4rem}[dir=rtl] .md-version__current:after{margin-right:.4rem}.md-version__current:after{background-color:currentcolor;content:"";display:inline-block;height:.6rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;width:.4rem}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:var(--md-shadow-z2);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;-ms-scroll-snap-type:y mandatory;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:3}.md-version:-webkit-any(:focus-within,:hover) .md-version__list{max-height:10rem;opacity:1;-webkit-transition:max-height 0ms,opacity .25s;transition:max-height 0ms,opacity .25s}.md-version:-moz-any(:focus-within,:hover) .md-version__list{max-height:10rem;opacity:1;-moz-transition:max-height 0ms,opacity .25s;transition:max-height 0ms,opacity .25s}.md-version:is(:focus-within,:hover) .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (pointer:coarse){.md-version:hover .md-version__list{-webkit-animation:hoverfix .25s forwards;animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{-webkit-animation:none;animation:none}}.md-version__item{line-height:1.8rem}[dir=ltr] .md-version__link{padding-left:.6rem;padding-right:1.2rem}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link{cursor:pointer;display:block;outline:none;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}.md-version__link:-webkit-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-version__link:-moz-any(:focus,:hover){color:var(--md-accent-fg-color)}.md-version__link:is(:focus,:hover){color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset :-webkit-any(.admonition,details){background-color:var(--md-admonition-bg-color);border:0 solid #448aff;border-radius:.1rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid}.md-typeset :-moz-any(.admonition,details){background-color:var(--md-admonition-bg-color);border:0 solid #448aff;border-radius:.1rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid}[dir=ltr] .md-typeset :-webkit-any(.admonition,details){border-left-width:.2rem}[dir=ltr] .md-typeset :-moz-any(.admonition,details){border-left-width:.2rem}[dir=ltr] .md-typeset :is(.admonition,details){border-left-width:.2rem}[dir=rtl] .md-typeset :-webkit-any(.admonition,details){border-right-width:.2rem}[dir=rtl] .md-typeset :-moz-any(.admonition,details){border-right-width:.2rem}[dir=rtl] .md-typeset :is(.admonition,details){border-right-width:.2rem}.md-typeset :is(.admonition,details){background-color:var(--md-admonition-bg-color);border:0 solid #448aff;border-radius:.1rem;box-shadow:var(--md-shadow-z1);color:var(--md-admonition-fg-color);display:flow-root;font-size:.64rem;margin:1.5625em 0;padding:0 .6rem;page-break-inside:avoid}@media print{.md-typeset :-webkit-any(.admonition,details){box-shadow:none}.md-typeset :-moz-any(.admonition,details){box-shadow:none}.md-typeset :is(.admonition,details){box-shadow:none}}.md-typeset :-webkit-any(.admonition,details)>*{box-sizing:border-box}.md-typeset :-moz-any(.admonition,details)>*{box-sizing:border-box}.md-typeset :is(.admonition,details)>*{box-sizing:border-box}.md-typeset :-webkit-any(.admonition,details) :-webkit-any(.admonition,details){margin-bottom:1em;margin-top:1em}.md-typeset :-moz-any(.admonition,details) :-moz-any(.admonition,details){margin-bottom:1em;margin-top:1em}.md-typeset :is(.admonition,details) :is(.admonition,details){margin-bottom:1em;margin-top:1em}.md-typeset :-webkit-any(.admonition,details) .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset :-moz-any(.admonition,details) .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset :is(.admonition,details) .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset :-webkit-any(.admonition,details) .md-typeset__table{padding:0 .6rem}.md-typeset :-moz-any(.admonition,details) .md-typeset__table{padding:0 .6rem}.md-typeset :is(.admonition,details) .md-typeset__table{padding:0 .6rem}.md-typeset :-webkit-any(.admonition,details)>.tabbed-set:only-child{margin-top:0}.md-typeset :-moz-any(.admonition,details)>.tabbed-set:only-child{margin-top:0}.md-typeset :is(.admonition,details)>.tabbed-set:only-child{margin-top:0}html .md-typeset :-webkit-any(.admonition,details)>:last-child{margin-bottom:.6rem}html .md-typeset :-moz-any(.admonition,details)>:last-child{margin-bottom:.6rem}html .md-typeset :is(.admonition,details)>:last-child{margin-bottom:.6rem}.md-typeset :-webkit-any(.admonition-title,summary){background-color:rgba(68,138,255,.1);border:none;font-weight:700;margin-bottom:0;margin-top:0;padding-bottom:.4rem;padding-top:.4rem;position:relative}.md-typeset :-moz-any(.admonition-title,summary){background-color:rgba(68,138,255,.1);border:none;font-weight:700;margin-bottom:0;margin-top:0;padding-bottom:.4rem;padding-top:.4rem;position:relative}[dir=ltr] .md-typeset :-webkit-any(.admonition-title,summary){margin-left:-.8rem;margin-right:-.6rem}[dir=ltr] .md-typeset :-moz-any(.admonition-title,summary){margin-left:-.8rem;margin-right:-.6rem}[dir=ltr] .md-typeset :is(.admonition-title,summary){margin-left:-.8rem;margin-right:-.6rem}[dir=rtl] .md-typeset :-webkit-any(.admonition-title,summary){margin-left:-.6rem;margin-right:-.8rem}[dir=rtl] .md-typeset :-moz-any(.admonition-title,summary){margin-left:-.6rem;margin-right:-.8rem}[dir=rtl] .md-typeset :is(.admonition-title,summary){margin-left:-.6rem;margin-right:-.8rem}[dir=ltr] .md-typeset :-webkit-any(.admonition-title,summary){padding-left:2.2rem;padding-right:.6rem}[dir=ltr] .md-typeset :-moz-any(.admonition-title,summary){padding-left:2.2rem;padding-right:.6rem}[dir=ltr] .md-typeset :is(.admonition-title,summary){padding-left:2.2rem;padding-right:.6rem}[dir=rtl] .md-typeset :-webkit-any(.admonition-title,summary){padding-left:.6rem;padding-right:2.2rem}[dir=rtl] .md-typeset :-moz-any(.admonition-title,summary){padding-left:.6rem;padding-right:2.2rem}[dir=rtl] .md-typeset :is(.admonition-title,summary){padding-left:.6rem;padding-right:2.2rem}[dir=ltr] .md-typeset :-webkit-any(.admonition-title,summary){border-left-width:.2rem}[dir=ltr] .md-typeset :-moz-any(.admonition-title,summary){border-left-width:.2rem}[dir=ltr] .md-typeset :is(.admonition-title,summary){border-left-width:.2rem}[dir=rtl] .md-typeset :-webkit-any(.admonition-title,summary){border-right-width:.2rem}[dir=rtl] .md-typeset :-moz-any(.admonition-title,summary){border-right-width:.2rem}[dir=rtl] .md-typeset :is(.admonition-title,summary){border-right-width:.2rem}[dir=ltr] .md-typeset :-webkit-any(.admonition-title,summary){border-top-left-radius:.1rem}[dir=ltr] .md-typeset :-moz-any(.admonition-title,summary){border-top-left-radius:.1rem}[dir=ltr] .md-typeset :is(.admonition-title,summary){border-top-left-radius:.1rem}[dir=rtl] .md-typeset :-webkit-any(.admonition-title,summary){border-top-right-radius:.1rem}[dir=rtl] .md-typeset :-moz-any(.admonition-title,summary){border-top-right-radius:.1rem}[dir=rtl] .md-typeset :is(.admonition-title,summary){border-top-right-radius:.1rem}[dir=ltr] .md-typeset :-webkit-any(.admonition-title,summary){border-top-right-radius:.1rem}[dir=ltr] .md-typeset :-moz-any(.admonition-title,summary){border-top-right-radius:.1rem}[dir=ltr] .md-typeset :is(.admonition-title,summary){border-top-right-radius:.1rem}[dir=rtl] .md-typeset :-webkit-any(.admonition-title,summary){border-top-left-radius:.1rem}[dir=rtl] .md-typeset :-moz-any(.admonition-title,summary){border-top-left-radius:.1rem}[dir=rtl] .md-typeset :is(.admonition-title,summary){border-top-left-radius:.1rem}.md-typeset :is(.admonition-title,summary){background-color:rgba(68,138,255,.1);border:none;font-weight:700;margin-bottom:0;margin-top:0;padding-bottom:.4rem;padding-top:.4rem;position:relative}html .md-typeset :-webkit-any(.admonition-title,summary):last-child{margin-bottom:0}html .md-typeset :-moz-any(.admonition-title,summary):last-child{margin-bottom:0}html .md-typeset :is(.admonition-title,summary):last-child{margin-bottom:0}.md-typeset :-webkit-any(.admonition-title,summary):before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset :-moz-any(.admonition-title,summary):before{background-color:#448aff;content:"";height:1rem;mask-image:var(--md-admonition-icon--note);mask-repeat:no-repeat;mask-size:contain;position:absolute;top:.625em;width:1rem}[dir=ltr] .md-typeset :-webkit-any(.admonition-title,summary):before{left:.8rem}[dir=ltr] .md-typeset :-moz-any(.admonition-title,summary):before{left:.8rem}[dir=ltr] .md-typeset :is(.admonition-title,summary):before{left:.8rem}[dir=rtl] .md-typeset :-webkit-any(.admonition-title,summary):before{right:.8rem}[dir=rtl] .md-typeset :-moz-any(.admonition-title,summary):before{right:.8rem}[dir=rtl] .md-typeset :is(.admonition-title,summary):before{right:.8rem}.md-typeset :is(.admonition-title,summary):before{background-color:#448aff;content:"";height:1rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;width:1rem}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.note){border-color:#448aff}.md-typeset :-moz-any(.admonition,details):-moz-any(.note){border-color:#448aff}.md-typeset :is(.admonition,details):is(.note){border-color:#448aff}.md-typeset :-webkit-any(.note)>:-webkit-any(.admonition-title,summary){background-color:rgba(68,138,255,.1)}.md-typeset :-moz-any(.note)>:-moz-any(.admonition-title,summary){background-color:rgba(68,138,255,.1)}.md-typeset :is(.note)>:is(.admonition-title,summary){background-color:rgba(68,138,255,.1)}.md-typeset :-webkit-any(.note)>:-webkit-any(.admonition-title,summary):before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.note)>:-moz-any(.admonition-title,summary):before{background-color:#448aff;mask-image:var(--md-admonition-icon--note);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.note)>:is(.admonition-title,summary):before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.abstract,.summary,.tldr){border-color:#00b0ff}.md-typeset :-moz-any(.admonition,details):-moz-any(.abstract,.summary,.tldr){border-color:#00b0ff}.md-typeset :is(.admonition,details):is(.abstract,.summary,.tldr){border-color:#00b0ff}.md-typeset :-webkit-any(.abstract,.summary,.tldr)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,176,255,.1)}.md-typeset :-moz-any(.abstract,.summary,.tldr)>:-moz-any(.admonition-title,summary){background-color:rgba(0,176,255,.1)}.md-typeset :is(.abstract,.summary,.tldr)>:is(.admonition-title,summary){background-color:rgba(0,176,255,.1)}.md-typeset :-webkit-any(.abstract,.summary,.tldr)>:-webkit-any(.admonition-title,summary):before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.abstract,.summary,.tldr)>:-moz-any(.admonition-title,summary):before{background-color:#00b0ff;mask-image:var(--md-admonition-icon--abstract);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.abstract,.summary,.tldr)>:is(.admonition-title,summary):before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.info,.todo){border-color:#00b8d4}.md-typeset :-moz-any(.admonition,details):-moz-any(.info,.todo){border-color:#00b8d4}.md-typeset :is(.admonition,details):is(.info,.todo){border-color:#00b8d4}.md-typeset :-webkit-any(.info,.todo)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,184,212,.1)}.md-typeset :-moz-any(.info,.todo)>:-moz-any(.admonition-title,summary){background-color:rgba(0,184,212,.1)}.md-typeset :is(.info,.todo)>:is(.admonition-title,summary){background-color:rgba(0,184,212,.1)}.md-typeset :-webkit-any(.info,.todo)>:-webkit-any(.admonition-title,summary):before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.info,.todo)>:-moz-any(.admonition-title,summary):before{background-color:#00b8d4;mask-image:var(--md-admonition-icon--info);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.info,.todo)>:is(.admonition-title,summary):before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.tip,.hint,.important){border-color:#00bfa5}.md-typeset :-moz-any(.admonition,details):-moz-any(.tip,.hint,.important){border-color:#00bfa5}.md-typeset :is(.admonition,details):is(.tip,.hint,.important){border-color:#00bfa5}.md-typeset :-webkit-any(.tip,.hint,.important)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,191,165,.1)}.md-typeset :-moz-any(.tip,.hint,.important)>:-moz-any(.admonition-title,summary){background-color:rgba(0,191,165,.1)}.md-typeset :is(.tip,.hint,.important)>:is(.admonition-title,summary){background-color:rgba(0,191,165,.1)}.md-typeset :-webkit-any(.tip,.hint,.important)>:-webkit-any(.admonition-title,summary):before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.tip,.hint,.important)>:-moz-any(.admonition-title,summary):before{background-color:#00bfa5;mask-image:var(--md-admonition-icon--tip);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.tip,.hint,.important)>:is(.admonition-title,summary):before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.success,.check,.done){border-color:#00c853}.md-typeset :-moz-any(.admonition,details):-moz-any(.success,.check,.done){border-color:#00c853}.md-typeset :is(.admonition,details):is(.success,.check,.done){border-color:#00c853}.md-typeset :-webkit-any(.success,.check,.done)>:-webkit-any(.admonition-title,summary){background-color:rgba(0,200,83,.1)}.md-typeset :-moz-any(.success,.check,.done)>:-moz-any(.admonition-title,summary){background-color:rgba(0,200,83,.1)}.md-typeset :is(.success,.check,.done)>:is(.admonition-title,summary){background-color:rgba(0,200,83,.1)}.md-typeset :-webkit-any(.success,.check,.done)>:-webkit-any(.admonition-title,summary):before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.success,.check,.done)>:-moz-any(.admonition-title,summary):before{background-color:#00c853;mask-image:var(--md-admonition-icon--success);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.success,.check,.done)>:is(.admonition-title,summary):before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.question,.help,.faq){border-color:#64dd17}.md-typeset :-moz-any(.admonition,details):-moz-any(.question,.help,.faq){border-color:#64dd17}.md-typeset :is(.admonition,details):is(.question,.help,.faq){border-color:#64dd17}.md-typeset :-webkit-any(.question,.help,.faq)>:-webkit-any(.admonition-title,summary){background-color:rgba(100,221,23,.1)}.md-typeset :-moz-any(.question,.help,.faq)>:-moz-any(.admonition-title,summary){background-color:rgba(100,221,23,.1)}.md-typeset :is(.question,.help,.faq)>:is(.admonition-title,summary){background-color:rgba(100,221,23,.1)}.md-typeset :-webkit-any(.question,.help,.faq)>:-webkit-any(.admonition-title,summary):before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.question,.help,.faq)>:-moz-any(.admonition-title,summary):before{background-color:#64dd17;mask-image:var(--md-admonition-icon--question);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.question,.help,.faq)>:is(.admonition-title,summary):before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.warning,.caution,.attention){border-color:#ff9100}.md-typeset :-moz-any(.admonition,details):-moz-any(.warning,.caution,.attention){border-color:#ff9100}.md-typeset :is(.admonition,details):is(.warning,.caution,.attention){border-color:#ff9100}.md-typeset :-webkit-any(.warning,.caution,.attention)>:-webkit-any(.admonition-title,summary){background-color:rgba(255,145,0,.1)}.md-typeset :-moz-any(.warning,.caution,.attention)>:-moz-any(.admonition-title,summary){background-color:rgba(255,145,0,.1)}.md-typeset :is(.warning,.caution,.attention)>:is(.admonition-title,summary){background-color:rgba(255,145,0,.1)}.md-typeset :-webkit-any(.warning,.caution,.attention)>:-webkit-any(.admonition-title,summary):before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.warning,.caution,.attention)>:-moz-any(.admonition-title,summary):before{background-color:#ff9100;mask-image:var(--md-admonition-icon--warning);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.warning,.caution,.attention)>:is(.admonition-title,summary):before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.failure,.fail,.missing){border-color:#ff5252}.md-typeset :-moz-any(.admonition,details):-moz-any(.failure,.fail,.missing){border-color:#ff5252}.md-typeset :is(.admonition,details):is(.failure,.fail,.missing){border-color:#ff5252}.md-typeset :-webkit-any(.failure,.fail,.missing)>:-webkit-any(.admonition-title,summary){background-color:rgba(255,82,82,.1)}.md-typeset :-moz-any(.failure,.fail,.missing)>:-moz-any(.admonition-title,summary){background-color:rgba(255,82,82,.1)}.md-typeset :is(.failure,.fail,.missing)>:is(.admonition-title,summary){background-color:rgba(255,82,82,.1)}.md-typeset :-webkit-any(.failure,.fail,.missing)>:-webkit-any(.admonition-title,summary):before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.failure,.fail,.missing)>:-moz-any(.admonition-title,summary):before{background-color:#ff5252;mask-image:var(--md-admonition-icon--failure);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.failure,.fail,.missing)>:is(.admonition-title,summary):before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.danger,.error){border-color:#ff1744}.md-typeset :-moz-any(.admonition,details):-moz-any(.danger,.error){border-color:#ff1744}.md-typeset :is(.admonition,details):is(.danger,.error){border-color:#ff1744}.md-typeset :-webkit-any(.danger,.error)>:-webkit-any(.admonition-title,summary){background-color:rgba(255,23,68,.1)}.md-typeset :-moz-any(.danger,.error)>:-moz-any(.admonition-title,summary){background-color:rgba(255,23,68,.1)}.md-typeset :is(.danger,.error)>:is(.admonition-title,summary){background-color:rgba(255,23,68,.1)}.md-typeset :-webkit-any(.danger,.error)>:-webkit-any(.admonition-title,summary):before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.danger,.error)>:-moz-any(.admonition-title,summary):before{background-color:#ff1744;mask-image:var(--md-admonition-icon--danger);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.danger,.error)>:is(.admonition-title,summary):before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.bug){border-color:#f50057}.md-typeset :-moz-any(.admonition,details):-moz-any(.bug){border-color:#f50057}.md-typeset :is(.admonition,details):is(.bug){border-color:#f50057}.md-typeset :-webkit-any(.bug)>:-webkit-any(.admonition-title,summary){background-color:rgba(245,0,87,.1)}.md-typeset :-moz-any(.bug)>:-moz-any(.admonition-title,summary){background-color:rgba(245,0,87,.1)}.md-typeset :is(.bug)>:is(.admonition-title,summary){background-color:rgba(245,0,87,.1)}.md-typeset :-webkit-any(.bug)>:-webkit-any(.admonition-title,summary):before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.bug)>:-moz-any(.admonition-title,summary):before{background-color:#f50057;mask-image:var(--md-admonition-icon--bug);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.bug)>:is(.admonition-title,summary):before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.example){border-color:#7c4dff}.md-typeset :-moz-any(.admonition,details):-moz-any(.example){border-color:#7c4dff}.md-typeset :is(.admonition,details):is(.example){border-color:#7c4dff}.md-typeset :-webkit-any(.example)>:-webkit-any(.admonition-title,summary){background-color:rgba(124,77,255,.1)}.md-typeset :-moz-any(.example)>:-moz-any(.admonition-title,summary){background-color:rgba(124,77,255,.1)}.md-typeset :is(.example)>:is(.admonition-title,summary){background-color:rgba(124,77,255,.1)}.md-typeset :-webkit-any(.example)>:-webkit-any(.admonition-title,summary):before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.example)>:-moz-any(.admonition-title,summary):before{background-color:#7c4dff;mask-image:var(--md-admonition-icon--example);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.example)>:is(.admonition-title,summary):before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-webkit-any(.admonition,details):-webkit-any(.quote,.cite){border-color:#9e9e9e}.md-typeset :-moz-any(.admonition,details):-moz-any(.quote,.cite){border-color:#9e9e9e}.md-typeset :is(.admonition,details):is(.quote,.cite){border-color:#9e9e9e}.md-typeset :-webkit-any(.quote,.cite)>:-webkit-any(.admonition-title,summary){background-color:hsla(0,0%,62%,.1)}.md-typeset :-moz-any(.quote,.cite)>:-moz-any(.admonition-title,summary){background-color:hsla(0,0%,62%,.1)}.md-typeset :is(.quote,.cite)>:is(.admonition-title,summary){background-color:hsla(0,0%,62%,.1)}.md-typeset :-webkit-any(.quote,.cite)>:-webkit-any(.admonition-title,summary):before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset :-moz-any(.quote,.cite)>:-moz-any(.admonition-title,summary):before{background-color:#9e9e9e;mask-image:var(--md-admonition-icon--quote);mask-repeat:no-repeat;mask-size:contain}.md-typeset :is(.quote,.cite)>:is(.admonition-title,summary):before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}[dir=ltr] .md-typeset .footnote>ol{margin-left:0}[dir=rtl] .md-typeset .footnote>ol{margin-right:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:focus-within .footnote-backref{opacity:1;transform:translateX(0);transition:none}.md-typeset .footnote>ol>li:-webkit-any(:hover,:target) .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li:-moz-any(:hover,:target) .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li:is(:hover,:target) .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateX(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateX(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateX(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentcolor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before svg{transform:scaleX(-1)}[dir=ltr] .md-typeset .headerlink{margin-left:.5rem}[dir=rtl] .md-typeset .headerlink{margin-right:.5rem}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}.md-typeset .headerlink:focus,.md-typeset :-webkit-any(:hover,:target)>.headerlink{opacity:1;-webkit-transition:color .25s,opacity 125ms;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset :-moz-any(:hover,:target)>.headerlink{opacity:1;-moz-transition:color .25s,opacity 125ms;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset :is(:hover,:target)>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:-webkit-any(:focus,:hover),.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset .headerlink:-moz-any(:focus,:hover),.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset .headerlink:is(:focus,:hover),.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{--md-scroll-margin:3.6rem;--md-scroll-offset:0rem;scroll-margin-top:calc(var(--md-scroll-margin) - var(--md-scroll-offset))}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{--md-scroll-margin:6rem}}.md-typeset :-webkit-any(h1,h2,h3):target{--md-scroll-offset:0.2rem}.md-typeset :-moz-any(h1,h2,h3):target{--md-scroll-offset:0.2rem}.md-typeset :is(h1,h2,h3):target{--md-scroll-offset:0.2rem}.md-typeset h4:target{--md-scroll-offset:0.15rem}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.9375em){.md-typeset div.arithmatex{margin:0 -.8rem}}.md-typeset div.arithmatex>*{margin-left:auto!important;margin-right:auto!important;padding:0 .8rem;touch-action:auto;width:-webkit-min-content;width:-moz-min-content;width:min-content}.md-typeset div.arithmatex>* mjx-container{margin:0!important}.md-typeset :-webkit-any(del,ins,.comment).critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset :-moz-any(del,ins,.comment).critic{box-decoration-break:clone}.md-typeset :is(del,ins,.comment).critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem}[dir=ltr] .md-typeset summary{padding-right:1.8rem}[dir=rtl] .md-typeset summary{padding-left:1.8rem}[dir=ltr] .md-typeset summary{border-top-left-radius:.1rem}[dir=ltr] .md-typeset summary,[dir=rtl] .md-typeset summary{border-top-right-radius:.1rem}[dir=rtl] .md-typeset summary{border-top-left-radius:.1rem}.md-typeset summary{cursor:pointer;display:block;min-height:1rem}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[dir=ltr] .md-typeset summary:after{right:.4rem}[dir=rtl] .md-typeset summary:after{left:.4rem}.md-typeset summary:after{background-color:currentcolor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.625em;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{transform:rotate(180deg)}.md-typeset summary::marker{display:none}.md-typeset summary::-webkit-details-marker{display:none}.md-typeset :-webkit-any(.emojione,.twemoji,.gemoji){display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset :-moz-any(.emojione,.twemoji,.gemoji){display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset :is(.emojione,.twemoji,.gemoji){display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset :-webkit-any(.emojione,.twemoji,.gemoji) svg{fill:currentcolor;max-height:100%;width:1.125em}.md-typeset :-moz-any(.emojione,.twemoji,.gemoji) svg{fill:currentcolor;max-height:100%;width:1.125em}.md-typeset :is(.emojione,.twemoji,.gemoji) svg{fill:currentcolor;max-height:100%;width:1.125em}.highlight :-webkit-any(.o,.ow){color:var(--md-code-hl-operator-color)}.highlight :-moz-any(.o,.ow){color:var(--md-code-hl-operator-color)}.highlight :is(.o,.ow){color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight :-webkit-any(.cpf,.l,.s,.sb,.sc,.s2,.si,.s1,.ss){color:var(--md-code-hl-string-color)}.highlight :-moz-any(.cpf,.l,.s,.sb,.sc,.s2,.si,.s1,.ss){color:var(--md-code-hl-string-color)}.highlight :is(.cpf,.l,.s,.sb,.sc,.s2,.si,.s1,.ss){color:var(--md-code-hl-string-color)}.highlight :-webkit-any(.cp,.se,.sh,.sr,.sx){color:var(--md-code-hl-special-color)}.highlight :-moz-any(.cp,.se,.sh,.sr,.sx){color:var(--md-code-hl-special-color)}.highlight :is(.cp,.se,.sh,.sr,.sx){color:var(--md-code-hl-special-color)}.highlight :-webkit-any(.m,.mb,.mf,.mh,.mi,.il,.mo){color:var(--md-code-hl-number-color)}.highlight :-moz-any(.m,.mb,.mf,.mh,.mi,.il,.mo){color:var(--md-code-hl-number-color)}.highlight :is(.m,.mb,.mf,.mh,.mi,.il,.mo){color:var(--md-code-hl-number-color)}.highlight :-webkit-any(.k,.kd,.kn,.kp,.kr,.kt){color:var(--md-code-hl-keyword-color)}.highlight :-moz-any(.k,.kd,.kn,.kp,.kr,.kt){color:var(--md-code-hl-keyword-color)}.highlight :is(.k,.kd,.kn,.kp,.kr,.kt){color:var(--md-code-hl-keyword-color)}.highlight :-webkit-any(.kc,.n){color:var(--md-code-hl-name-color)}.highlight :-moz-any(.kc,.n){color:var(--md-code-hl-name-color)}.highlight :is(.kc,.n){color:var(--md-code-hl-name-color)}.highlight :-webkit-any(.no,.nb,.bp){color:var(--md-code-hl-constant-color)}.highlight :-moz-any(.no,.nb,.bp){color:var(--md-code-hl-constant-color)}.highlight :is(.no,.nb,.bp){color:var(--md-code-hl-constant-color)}.highlight :-webkit-any(.nc,.ne,.nf,.nn){color:var(--md-code-hl-function-color)}.highlight :-moz-any(.nc,.ne,.nf,.nn){color:var(--md-code-hl-function-color)}.highlight :is(.nc,.ne,.nf,.nn){color:var(--md-code-hl-function-color)}.highlight :-webkit-any(.nd,.ni,.nl,.nt){color:var(--md-code-hl-keyword-color)}.highlight :-moz-any(.nd,.ni,.nl,.nt){color:var(--md-code-hl-keyword-color)}.highlight :is(.nd,.ni,.nl,.nt){color:var(--md-code-hl-keyword-color)}.highlight :-webkit-any(.c,.cm,.c1,.ch,.cs,.sd){color:var(--md-code-hl-comment-color)}.highlight :-moz-any(.c,.cm,.c1,.ch,.cs,.sd){color:var(--md-code-hl-comment-color)}.highlight :is(.c,.cm,.c1,.ch,.cs,.sd){color:var(--md-code-hl-comment-color)}.highlight :-webkit-any(.na,.nv,.vc,.vg,.vi){color:var(--md-code-hl-variable-color)}.highlight :-moz-any(.na,.nv,.vc,.vg,.vi){color:var(--md-code-hl-variable-color)}.highlight :is(.na,.nv,.vc,.vg,.vi){color:var(--md-code-hl-variable-color)}.highlight :-webkit-any(.ge,.gr,.gh,.go,.gp,.gs,.gu,.gt){color:var(--md-code-hl-generic-color)}.highlight :-moz-any(.ge,.gr,.gh,.go,.gp,.gs,.gu,.gt){color:var(--md-code-hl-generic-color)}.highlight :is(.ge,.gr,.gh,.go,.gp,.gs,.gu,.gt){color:var(--md-code-hl-generic-color)}.highlight :-webkit-any(.gd,.gi){border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight :-moz-any(.gd,.gi){border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight :is(.gd,.gi){border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color);display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.1rem;border-top-right-radius:.1rem;display:flow-root;font-size:.85em;font-weight:700;margin-top:1em;padding:.6617647059em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight span.filename+pre>code{border-top-left-radius:0;border-top-right-radius:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:-webkit-sticky;position:sticky;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:3}.highlight code a[id]{position:absolute;visibility:hidden}.highlight code[data-md-copying] .hll{display:contents}.highlight code[data-md-copying] .md-annotation{display:none}.highlighttable{display:flow-root}.highlighttable :-webkit-any(tbody,td){display:block;padding:0}.highlighttable :-moz-any(tbody,td){display:block;padding:0}.highlighttable :is(tbody,td){display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable th.filename span.filename{margin-top:0}.highlighttable .linenos{background-color:var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-top-left-radius:.1rem;font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;padding-right:.5882352941em}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .code{flex:1;min-width:0}.linenodiv a{color:inherit}.md-typeset .highlighttable{direction:ltr;margin:1em 0}.md-typeset .highlighttable>tbody>tr>.code>div>pre>code{border-bottom-left-radius:0;border-top-left-radius:0}.md-typeset .highlight+.result{border:.05rem solid var(--md-code-bg-color);border-bottom-left-radius:.1rem;border-bottom-right-radius:.1rem;border-top-width:.1rem;margin-top:-1.125em;overflow:visible;padding:0 1em}.md-typeset .highlight+.result:after{clear:both;content:"";display:block}@media screen and (max-width:44.9375em){.md-content__inner>.highlight{margin:1em -.8rem}.md-content__inner>.highlight>.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.code>div>pre>code,.md-content__inner>.highlight>.highlighttable>tbody>tr>.filename span.filename,.md-content__inner>.highlight>.highlighttable>tbody>tr>.linenos,.md-content__inner>.highlight>pre>code{border-radius:0}.md-content__inner>.highlight+.result{border-left-width:0;border-radius:0;border-right-width:0;margin-left:-.8rem;margin-right:-.8rem}}.md-typeset .keys kbd:-webkit-any(:before,:after){-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys kbd:-moz-any(:before,:after){-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys kbd:is(:before,:after){-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before,.md-typeset .keys .key-left-alt:before,.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before,.md-typeset .keys .key-left-command:before,.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before,.md-typeset .keys .key-left-control:before,.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-meta:before,.md-typeset .keys .key-meta:before,.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-option:before,.md-typeset .keys .key-option:before,.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-shift:before,.md-typeset .keys .key-right-shift:before,.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-super:before,.md-typeset .keys .key-right-super:before,.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-windows:before,.md-typeset .keys .key-right-windows:before,.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}:root{--md-tabbed-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-tabbed-icon--next:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-flow:column wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:target{--md-scroll-offset:0.625em}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}@media screen{.js .md-typeset .tabbed-labels{position:relative}.js .md-typeset .tabbed-labels:before{background:var(--md-accent-fg-color);bottom:0;content:"";display:block;height:2px;left:0;position:absolute;transform:translateX(var(--md-indicator-x));transition:width 225ms,transform .25s;transition-timing-function:cubic-bezier(.4,0,.2,1);width:var(--md-indicator-width)}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid transparent;border-radius:.1rem .1rem 0 0;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.64rem;font-weight:700;padding:.78125em 1.25em .625em;scroll-margin-inline-start:1rem;transition:background-color .25s,color .25s;white-space:nowrap;width:auto}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-accent-fg-color)}.md-typeset .tabbed-content{width:100%}@media print{.md-typeset .tabbed-content{display:contents}}.md-typeset .tabbed-block{display:none}@media print{.md-typeset .tabbed-block{display:block}.md-typeset .tabbed-block:first-child{order:1}.md-typeset .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-block>.highlight:first-child>pre,.md-typeset .tabbed-block>pre:first-child{margin:0}.md-typeset .tabbed-block>.highlight:first-child>pre>code,.md-typeset .tabbed-block>pre:first-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child>.filename{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable{margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.filename span.filename,.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.linenos{border-top-left-radius:0;border-top-right-radius:0;margin:0}.md-typeset .tabbed-block>.highlight:first-child>.highlighttable>tbody>tr>.code>div>pre>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-block>.highlight:first-child+.result{margin-top:-.125em}.md-typeset .tabbed-block>.tabbed-set{margin:0}.md-typeset .tabbed-button{align-self:center;border-radius:100%;color:var(--md-default-fg-color--light);cursor:pointer;display:block;height:.9rem;margin-top:.1rem;pointer-events:auto;transition:background-color .25s;width:.9rem}.md-typeset .tabbed-button:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-typeset .tabbed-button:after{background-color:currentcolor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-tabbed-icon--prev);mask-image:var(--md-tabbed-icon--prev);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color .25s,transform .25s;width:100%}.md-typeset .tabbed-control{background:linear-gradient(to right,var(--md-default-bg-color) 60%,transparent);display:flex;height:1.9rem;justify-content:start;pointer-events:none;position:absolute;transition:opacity 125ms;width:1.2rem}[dir=rtl] .md-typeset .tabbed-control{transform:rotate(180deg)}.md-typeset .tabbed-control[hidden]{opacity:0}.md-typeset .tabbed-control--next{background:linear-gradient(to left,var(--md-default-bg-color) 60%,transparent);justify-content:end;right:0}.md-typeset .tabbed-control--next .tabbed-button:after{-webkit-mask-image:var(--md-tabbed-icon--next);mask-image:var(--md-tabbed-icon--next)}@media screen and (max-width:44.9375em){[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels{margin:0 -.8rem;max-width:100vw;scroll-padding-inline-start:.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels:after{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels:after{content:""}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-left:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{margin-right:-.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-left:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{padding-right:.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--prev{width:2rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-right:-.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{margin-left:-.8rem}[dir=ltr] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-right:.8rem}[dir=rtl] .md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{padding-left:.8rem}.md-content__inner>.tabbed-set .tabbed-labels~.tabbed-control--next{width:2rem}}@media screen{.md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){color:var(--md-accent-fg-color)}.md-typeset .no-js .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .no-js .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .no-js .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .no-js .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .no-js .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .no-js .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .no-js .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .no-js .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .no-js .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .no-js .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .no-js .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .no-js .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .no-js .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.md-typeset .no-js .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .no-js .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .no-js .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .no-js .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .no-js .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .no-js .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .no-js .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.no-js .md-typeset .tabbed-set>input:first-child:checked~.tabbed-labels>:first-child,.no-js .md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.no-js .md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.no-js .md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.no-js .md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.no-js .md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.no-js .md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.no-js .md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.no-js .md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.no-js .md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.no-js .md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.no-js .md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.no-js .md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-labels>:nth-child(20),.no-js .md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.no-js .md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.no-js .md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.no-js .md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.no-js .md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.no-js .md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.no-js .md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-labels>:nth-child(9){border-color:var(--md-accent-fg-color)}}.md-typeset .tabbed-set>input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-set>input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9){background-color:var(--md-accent-fg-color--transparent)}.md-typeset .tabbed-set>input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-set>input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-set>input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-set>input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-set>input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-set>input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-set>input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-set>input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-set>input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-set>input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-set>input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-set>input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-set>input:nth-child(20):checked~.tabbed-content>:nth-child(20),.md-typeset .tabbed-set>input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-set>input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-set>input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-set>input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-set>input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-set>input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-set>input:nth-child(9):checked~.tabbed-content>:nth-child(9){display:block}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}[dir=ltr] .md-typeset .task-list-item [type=checkbox]{left:-2em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{right:-2em}.md-typeset .task-list-item [type=checkbox]{position:absolute;top:.45em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}[dir=ltr] .md-typeset .task-list-indicator:before{left:-1.5em}[dir=rtl] .md-typeset .task-list-indicator:before{right:-1.5em}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}:root>*{--md-mermaid-font-family:var(--md-text-font-family),sans-serif;--md-mermaid-edge-color:var(--md-code-fg-color);--md-mermaid-node-bg-color:var(--md-accent-fg-color--transparent);--md-mermaid-node-fg-color:var(--md-accent-fg-color);--md-mermaid-label-bg-color:var(--md-default-bg-color);--md-mermaid-label-fg-color:var(--md-code-fg-color)}.mermaid{line-height:normal;margin:1em 0}@media screen and (min-width:45em){[dir=ltr] .md-typeset .inline{margin-right:.8rem}[dir=rtl] .md-typeset .inline{margin-left:.8rem}.md-typeset .inline{float:left;margin-bottom:.8rem;margin-top:0;width:11.7rem}[dir=rtl] .md-typeset .inline{float:right}[dir=ltr] .md-typeset .inline.end{margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{margin-left:0;margin-right:.8rem}.md-typeset .inline.end{float:right}[dir=rtl] .md-typeset .inline.end{float:left}} \ No newline at end of file diff --git a/assets/stylesheets/main.6b80c2a2.min.css.map b/assets/stylesheets/main.6b80c2a2.min.css.map deleted file mode 100644 index a1576e4f..00000000 --- a/assets/stylesheets/main.6b80c2a2.min.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["src/assets/stylesheets/main/extensions/pymdownx/_keys.scss","../../../src/assets/stylesheets/main.scss","src/assets/stylesheets/main/_resets.scss","src/assets/stylesheets/main/_colors.scss","src/assets/stylesheets/main/_icons.scss","src/assets/stylesheets/main/_typeset.scss","src/assets/stylesheets/utilities/_break.scss","src/assets/stylesheets/main/layout/_banner.scss","src/assets/stylesheets/main/layout/_base.scss","src/assets/stylesheets/main/layout/_clipboard.scss","src/assets/stylesheets/main/layout/_consent.scss","src/assets/stylesheets/main/layout/_content.scss","src/assets/stylesheets/main/layout/_dialog.scss","src/assets/stylesheets/main/layout/_feedback.scss","src/assets/stylesheets/main/layout/_footer.scss","src/assets/stylesheets/main/layout/_form.scss","src/assets/stylesheets/main/layout/_header.scss","src/assets/stylesheets/main/layout/_nav.scss","src/assets/stylesheets/main/layout/_search.scss","src/assets/stylesheets/main/layout/_select.scss","src/assets/stylesheets/main/layout/_sidebar.scss","src/assets/stylesheets/main/layout/_source.scss","src/assets/stylesheets/main/layout/_tabs.scss","src/assets/stylesheets/main/layout/_tag.scss","src/assets/stylesheets/main/layout/_tooltip.scss","src/assets/stylesheets/main/layout/_top.scss","src/assets/stylesheets/main/layout/_version.scss","src/assets/stylesheets/main/extensions/markdown/_admonition.scss","node_modules/material-design-color/material-color.scss","src/assets/stylesheets/main/extensions/markdown/_footnotes.scss","src/assets/stylesheets/main/extensions/markdown/_toc.scss","src/assets/stylesheets/main/extensions/pymdownx/_arithmatex.scss","src/assets/stylesheets/main/extensions/pymdownx/_critic.scss","src/assets/stylesheets/main/extensions/pymdownx/_details.scss","src/assets/stylesheets/main/extensions/pymdownx/_emoji.scss","src/assets/stylesheets/main/extensions/pymdownx/_highlight.scss","src/assets/stylesheets/main/extensions/pymdownx/_tabbed.scss","src/assets/stylesheets/main/extensions/pymdownx/_tasklist.scss","src/assets/stylesheets/main/integrations/_mermaid.scss","src/assets/stylesheets/main/_modifiers.scss"],"names":[],"mappings":"AAgGM,gBC04GN,CC98GA,KAEE,6BAAA,CAAA,0BAAA,CAAA,yBAAA,CAAA,qBAAA,CADA,qBDzBF,CC8BA,iBAGE,kBD3BF,CC8BE,gCANF,iBAOI,yBDzBF,CACF,CC6BA,KACE,QD1BF,CC8BA,qBAIE,uCD3BF,CC+BA,EACE,aAAA,CACA,oBD5BF,CCgCA,GAME,QAAA,CAJA,kBAAA,CADA,aAAA,CAEA,aAAA,CAEA,gBAAA,CADA,SD3BF,CCiCA,MACE,aD9BF,CCkCA,QAEE,eD/BF,CCmCA,IACE,iBDhCF,CCoCA,MACE,uBAAA,CACA,gBDjCF,CCqCA,MAEE,eAAA,CACA,kBDlCF,CCsCA,OAKE,sBAAA,CACA,QAAA,CAFA,mBAAA,CADA,iBAAA,CAFA,QAAA,CACA,SD/BF,CCuCA,MACE,QAAA,CACA,YDpCF,CErCA,qCAGE,qCAAA,CACA,4CAAA,CACA,8CAAA,CACA,+CAAA,CACA,0BAAA,CACA,+CAAA,CACA,iDAAA,CACA,mDAAA,CAGA,6BAAA,CACA,oCAAA,CACA,mCAAA,CACA,0BAAA,CACA,+CAAA,CAGA,4BAAA,CACA,qDAAA,CACA,yBAAA,CACA,8CAAA,CAGA,0BAAA,CACA,0BAAA,CAGA,qCAAA,CACA,iCAAA,CACA,kCAAA,CACA,mCAAA,CACA,mCAAA,CACA,kCAAA,CACA,iCAAA,CACA,+CAAA,CACA,6DAAA,CACA,gEAAA,CACA,4DAAA,CACA,4DAAA,CACA,6DAAA,CAGA,6CAAA,CAGA,+CAAA,CAGA,0CAAA,CAGA,0CAAA,CACA,2CAAA,CAGA,8BAAA,CACA,kCAAA,CACA,qCAAA,CAGA,wCAAA,CAGA,mDAAA,CACA,mDAAA,CAGA,yBAAA,CACA,8CAAA,CACA,gDAAA,CACA,oCAAA,CACA,0CAAA,CAGA,yEAAA,CAKA,yEAAA,CAKA,yEFUF,CG9GE,aAIE,iBAAA,CAHA,aAAA,CAEA,aAAA,CADA,YHmHJ,CIxHA,KACE,kCAAA,CACA,iCAAA,CAGA,uGAAA,CAKA,mFJyHF,CInHA,WAGE,mCAAA,CACA,sCJsHF,CIlHA,wBANE,6BJgIF,CI1HA,aAIE,4BAAA,CACA,sCJqHF,CI7GA,MACE,0NAAA,CACA,mNAAA,CACA,oNJgHF,CIzGA,YAGE,gCAAA,CAAA,kBAAA,CAFA,eAAA,CACA,eJ6GF,CIxGE,aAPF,YAQI,gBJ2GF,CACF,CIxGE,uGAME,iBAAA,CAAA,cJ0GJ,CItGE,eAEE,uCAAA,CAEA,aAAA,CACA,eAAA,CAJA,iBJ6GJ,CIpGE,8BAPE,eAAA,CAGA,qBJ+GJ,CI3GE,eAGE,kBAAA,CACA,eAAA,CAHA,oBJ0GJ,CIlGE,eAGE,gBAAA,CADA,eAAA,CAGA,qBAAA,CADA,eAAA,CAHA,mBJwGJ,CIhGE,kBACE,eJkGJ,CI9FE,eAEE,eAAA,CACA,qBAAA,CAFA,YJkGJ,CI5FE,8BAGE,uCAAA,CAEA,cAAA,CADA,eAAA,CAEA,qBAAA,CAJA,eJkGJ,CI1FE,eACE,wBJ4FJ,CIxFE,eAGE,+DAAA,CAFA,iBAAA,CACA,cJ2FJ,CItFE,cACE,+BAAA,CACA,qBJwFJ,CIrFI,mCAEE,sBJsFN,CIlFI,wCAEE,+BJmFN,CIhFM,kDACE,uDJkFR,CI7EI,mBACE,kBAAA,CACA,iCJ+EN,CI3EI,4BACE,uCAAA,CACA,oBJ6EN,CIxEE,iDAGE,6BAAA,CACA,aJ0EJ,CIvEI,aAPF,iDAQI,oBJ4EJ,CACF,CIxEE,iBAIE,wCAAA,CACA,mBAAA,CACA,kCAAA,CAAA,0BAAA,CAJA,eAAA,CADA,uBAAA,CAEA,qBJ6EJ,CIvEI,qCAEE,uCAAA,CADA,YJ0EN,CIpEE,gBAEE,iBAAA,CACA,eAAA,CAFA,iBJwEJ,CInEI,qBAQE,kCAAA,CAAA,0BAAA,CADA,eAAA,CANA,aAAA,CACA,QAAA,CAIA,uCAAA,CAFA,aAAA,CADA,oCAAA,CAQA,+DAAA,CADA,oBAAA,CADA,iBAAA,CAJA,iBJ2EN,CIlEM,2BACE,qDJoER,CIhEM,wCAEE,YAAA,CADA,WJmER,CI9DM,8CACE,oDJgER,CI7DQ,oDACE,0CJ+DV,CIxDE,gBAOE,4CAAA,CACA,mBAAA,CACA,mKACE,CAPF,gCAAA,CAFA,oBAAA,CAGA,eAAA,CAFA,uBAAA,CAGA,uBAAA,CACA,qBJ6DJ,CInDE,iBAGE,6CAAA,CACA,kCAAA,CAAA,0BAAA,CAHA,aAAA,CACA,qBJuDJ,CIjDE,iBAEE,6DAAA,CACA,WAAA,CAFA,oBJqDJ,CIhDI,oBANF,iBAOI,iBJmDJ,CIhDI,yDAWE,2CAAA,CACA,mBAAA,CACA,8BAAA,CAJA,gCAAA,CAKA,mBAAA,CAXA,oBAAA,CAOA,eAAA,CAHA,cAAA,CADA,aAAA,CADA,6BAAA,CAAA,qBAAA,CAGA,mBAAA,CAPA,iBAAA,CAGA,UJ4DN,CIhEI,sDAWE,2CAAA,CACA,mBAAA,CACA,8BAAA,CAJA,gCAAA,CAKA,mBAAA,CAXA,oBAAA,CAOA,eAAA,CAHA,cAAA,CADA,aAAA,CADA,0BAAA,CAAA,qBAAA,CAGA,mBAAA,CAPA,iBAAA,CAGA,UJ4DN,CIhEI,mEAEE,MJ8DN,CIhEI,gEAEE,MJ8DN,CIhEI,0DAEE,MJ8DN,CIhEI,mEAEE,OJ8DN,CIhEI,gEAEE,OJ8DN,CIhEI,0DAEE,OJ8DN,CIhEI,gDAWE,2CAAA,CACA,mBAAA,CACA,8BAAA,CAJA,gCAAA,CAKA,mBAAA,CAXA,oBAAA,CAOA,eAAA,CAHA,cAAA,CADA,aAAA,CADA,6BAAA,CAAA,0BAAA,CAAA,qBAAA,CAGA,mBAAA,CAPA,iBAAA,CAGA,UJ4DN,CACF,CI7CE,kBACE,WJ+CJ,CI3CE,oDAEE,qBJ6CJ,CI/CE,oDAEE,sBJ6CJ,CIzCE,iCACE,kBJ8CJ,CI/CE,iCACE,mBJ8CJ,CI/CE,iCAIE,2DJ2CJ,CI/CE,iCAIE,4DJ2CJ,CI/CE,uBAGE,uCAAA,CADA,aAAA,CAAA,cJ6CJ,CIvCE,eACE,oBJyCJ,CIrCE,kDAEE,kBJwCJ,CI1CE,kDAEE,mBJwCJ,CI1CE,8BAGE,SJuCJ,CIpCI,0DACE,iBJuCN,CInCI,oCACE,2BJsCN,CInCM,0CACE,2BJsCR,CIjCI,wDAEE,kBJoCN,CItCI,wDAEE,mBJoCN,CItCI,oCACE,kBJqCN,CIjCM,kGAEE,aJqCR,CIjCM,0DACE,eJoCR,CIhCM,4EACE,kBAAA,CAAA,eJoCR,CIrCM,sEACE,kBAAA,CAAA,eJoCR,CIrCM,gGAEE,kBJmCR,CIrCM,0FAEE,kBJmCR,CIrCM,8EAEE,kBJmCR,CIrCM,gGAEE,mBJmCR,CIrCM,0FAEE,mBJmCR,CIrCM,8EAEE,mBJmCR,CIrCM,0DACE,kBAAA,CAAA,eJoCR,CI7BE,yBAEE,mBJ+BJ,CIjCE,yBAEE,oBJ+BJ,CIjCE,eACE,mBAAA,CAAA,cJgCJ,CI3BE,kDAIE,WAAA,CADA,cJ8BJ,CItBI,4BAEE,oBJwBN,CIpBI,6BAEE,oBJsBN,CIlBI,kCACE,YJoBN,CIhBI,8EAEE,YJiBN,CIZE,mBACE,iBAAA,CAGA,eAAA,CADA,cAAA,CAEA,iBAAA,CAHA,yBAAA,CAAA,sBAAA,CAAA,iBJiBJ,CIXI,uBACE,aJaN,CIRE,uBAGE,iBAAA,CADA,eAAA,CADA,eJYJ,CINE,mBACE,cJQJ,CIJE,+BAKE,2CAAA,CACA,iDAAA,CACA,mBAAA,CANA,oBAAA,CAGA,gBAAA,CAFA,cAAA,CACA,aAAA,CAKA,iBJMJ,CIHI,aAXF,+BAYI,aJMJ,CACF,CIDI,iCACE,gBJGN,CIIM,gEACE,YJFR,CICM,6DACE,YJFR,CICM,uDACE,YJFR,CIMM,+DACE,eJJR,CIGM,4DACE,eJJR,CIGM,sDACE,eJJR,CISI,gEACE,eJPN,CIMI,6DACE,eJPN,CIMI,uDACE,eJPN,CIUM,0EACE,gBJRR,CIOM,uEACE,gBJRR,CIOM,iEACE,gBJRR,CIaI,kCAGE,eAAA,CAFA,cAAA,CACA,sBAAA,CAEA,kBJXN,CIeI,kCAGE,qDAAA,CAFA,sBAAA,CACA,kBJZN,CIiBI,wCACE,iCJfN,CIkBM,8CACE,iCAAA,CACA,sDJhBR,CIqBI,iCACE,iBJnBN,CIwBE,wCACE,cJtBJ,CIyBI,wDAIE,gBJjBN,CIaI,wDAIE,iBJjBN,CIaI,8CAUE,UAAA,CATA,oBAAA,CAEA,YAAA,CAGA,oDAAA,CAAA,4CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CACA,iCAAA,CAJA,0BAAA,CAHA,WJfN,CI2BI,oDACE,oDJzBN,CI6BI,mEACE,kDAAA,CACA,yDAAA,CAAA,iDJ3BN,CI+BI,oEACE,kDAAA,CACA,0DAAA,CAAA,kDJ7BN,CIkCE,wBACE,iBAAA,CACA,eAAA,CACA,iBJhCJ,CIoCE,mBACE,oBAAA,CACA,kBAAA,CACA,eJlCJ,CIqCI,aANF,mBAOI,aJlCJ,CACF,CIqCI,8BACE,aAAA,CAEA,QAAA,CACA,eAAA,CAFA,UJjCN,CKzVI,wCDyYF,uBACE,iBJ5CF,CI+CE,4BACE,eJ7CJ,CACF,CM3hBA,WAGE,0CAAA,CADA,+BAAA,CADA,aN+hBF,CM1hBE,aANF,WAOI,YN6hBF,CACF,CM1hBE,oBAEE,uCAAA,CADA,gCN6hBJ,CMxhBE,kBAGE,eAAA,CAFA,iBAAA,CACA,eN2hBJ,CMthBE,mBAEE,aAAA,CACA,cAAA,CAFA,WAAA,CAGA,uBNwhBJ,CMrhBI,yBACE,UNuhBN,COvjBA,KASE,cAAA,CARA,WAAA,CACA,iBP2jBF,CKvZI,oCEtKJ,KAaI,gBPojBF,CACF,CK5ZI,oCEtKJ,KAkBI,cPojBF,CACF,CO/iBA,KASE,2CAAA,CAPA,YAAA,CACA,qBAAA,CAKA,eAAA,CAHA,eAAA,CAJA,iBAAA,CAGA,UPqjBF,CO7iBE,aAZF,KAaI,aPgjBF,CACF,CK7ZI,wCEhJF,yBAII,cP6iBJ,CACF,COpiBA,SAEE,gBAAA,CAAA,iBAAA,CADA,ePwiBF,COniBA,cACE,YAAA,CACA,qBAAA,CACA,WPsiBF,COniBE,aANF,cAOI,aPsiBF,CACF,COliBA,SACE,WPqiBF,COliBE,gBACE,YAAA,CACA,WAAA,CACA,iBPoiBJ,CO/hBA,aACE,eAAA,CAEA,sBAAA,CADA,kBPmiBF,COzhBA,WACE,YP4hBF,COvhBA,WAGE,QAAA,CACA,SAAA,CAHA,iBAAA,CACA,OP4hBF,COvhBE,uCACE,aPyhBJ,COrhBE,+BAEE,uCAAA,CADA,kBPwhBJ,COlhBA,SASE,2CAAA,CACA,mBAAA,CAHA,gCAAA,CACA,gBAAA,CAHA,YAAA,CAQA,SAAA,CAFA,uCAAA,CALA,mBAAA,CALA,cAAA,CAWA,2BAAA,CARA,UP4hBF,COhhBE,eAGE,SAAA,CADA,uBAAA,CAEA,oEACE,CAJF,UPqhBJ,COvgBA,MACE,WP0gBF,CQpqBA,MACE,+PRsqBF,CQhqBA,cAQE,mBAAA,CADA,0CAAA,CAIA,cAAA,CALA,YAAA,CAGA,uCAAA,CACA,oBAAA,CATA,iBAAA,CAEA,UAAA,CADA,QAAA,CAUA,qBAAA,CAPA,WAAA,CADA,SR2qBF,CQhqBE,aAfF,cAgBI,YRmqBF,CACF,CQhqBE,kCAEE,uCAAA,CADA,YRmqBJ,CQ9pBE,qBACE,uCRgqBJ,CQ5pBE,yCACE,+BR8pBJ,CQ/pBE,sCACE,+BR8pBJ,CQ/pBE,gCACE,+BR8pBJ,CQzpBE,oBAKE,6BAAA,CAIA,UAAA,CARA,aAAA,CAEA,cAAA,CACA,aAAA,CAEA,2CAAA,CAAA,mCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CANA,aRkqBJ,CQvpBE,sBACE,cRypBJ,CQtpBI,2BACE,2CRwpBN,CQlpBI,sDAEE,uDAAA,CADA,+BRqpBN,CQtpBI,mDAEE,uDAAA,CADA,+BRqpBN,CQtpBI,6CAEE,uDAAA,CADA,+BRqpBN,CS1tBA,2BACE,GAEE,SAAA,CADA,0BT8tBF,CS1tBA,GAEE,SAAA,CADA,uBT6tBF,CACF,CSruBA,mBACE,GAEE,SAAA,CADA,0BT8tBF,CS1tBA,GAEE,SAAA,CADA,uBT6tBF,CACF,CSxtBA,2BACE,GACE,ST0tBF,CSvtBA,GACE,STytBF,CACF,CShuBA,mBACE,GACE,ST0tBF,CSvtBA,GACE,STytBF,CACF,CS9sBE,qBASE,mCAAA,CAAA,2BAAA,CADA,mCAAA,CAAA,2BAAA,CAFA,gCAAA,CADA,WAAA,CAEA,SAAA,CANA,cAAA,CACA,KAAA,CAEA,UAAA,CADA,STstBJ,CS5sBE,mBAcE,2DAAA,CAAA,mDAAA,CANA,2CAAA,CACA,QAAA,CACA,mBAAA,CARA,QAAA,CASA,gEACE,CAPF,eAAA,CAEA,aAAA,CADA,SAAA,CALA,cAAA,CAGA,UAAA,CADA,STutBJ,CSxsBE,kBACE,aT0sBJ,CStsBE,sBACE,YAAA,CACA,YTwsBJ,CSrsBI,oCACE,aTusBN,CSlsBE,sBACE,mBTosBJ,CSjsBI,6CACE,cTmsBN,CK7lBI,wCIvGA,6CAKI,aAAA,CAEA,gBAAA,CACA,iBAAA,CAFA,UTqsBN,CACF,CS9rBE,kBACE,cTgsBJ,CUjyBA,YACE,WAAA,CAIA,WViyBF,CU9xBE,mBACE,qBAAA,CACA,iBVgyBJ,CKpoBI,sCKtJE,4EACE,kBV6xBN,CUzxBI,0JACE,mBV2xBN,CU5xBI,8EACE,kBV2xBN,CACF,CUtxBI,0BAGE,UAAA,CAFA,aAAA,CACA,YVyxBN,CUpxBI,+BACE,eVsxBN,CUhxBE,8BAGE,iBVmxBJ,CUtxBE,8BAGE,kBVmxBJ,CUtxBE,oBACE,WAAA,CACA,cAAA,CAEA,SVkxBJ,CU/wBI,aAPF,oBAQI,YVkxBJ,CACF,CU/wBI,8BACE,UVixBN,CU7wBI,gCACE,yCV+wBN,CU3wBI,wBACE,cAAA,CACA,kBV6wBN,CU1wBM,kCACE,oBV4wBR,CWl1BA,qBAEE,WXg2BF,CWl2BA,qBAEE,UXg2BF,CWl2BA,WAOE,2CAAA,CACA,mBAAA,CALA,YAAA,CAMA,8BAAA,CAJA,iBAAA,CAMA,SAAA,CALA,mBAAA,CASA,mBAAA,CAdA,cAAA,CASA,0BAAA,CAEA,wCACE,CATF,SX81BF,CWh1BE,aAlBF,WAmBI,YXm1BF,CACF,CWh1BE,mBAEE,SAAA,CAIA,mBAAA,CALA,uBAAA,CAEA,kEXm1BJ,CW50BE,kBACE,gCAAA,CACA,eX80BJ,CYj3BA,aACE,gBAAA,CACA,iBZo3BF,CYj3BE,sBAGE,WAAA,CAFA,QAAA,CACA,SZo3BJ,CY/2BE,oBAEE,eAAA,CADA,eZk3BJ,CY72BE,oBACE,iBZ+2BJ,CY32BE,mBAIE,sBAAA,CAFA,YAAA,CACA,cAAA,CAEA,sBAAA,CAJA,iBZi3BJ,CY12BI,iDACE,yCZ42BN,CYx2BI,6BACE,iBZ02BN,CYr2BE,mBAGE,uCAAA,CACA,cAAA,CAHA,aAAA,CACA,cAAA,CAGA,sBZu2BJ,CYp2BI,gDACE,+BZs2BN,CYl2BI,4BACE,0CAAA,CACA,mBZo2BN,CY/1BE,mBAGE,SAAA,CAFA,iBAAA,CACA,2BAAA,CAEA,8DZi2BJ,CY51BI,qBAEE,aAAA,CADA,eZ+1BN,CY11BI,6BAEE,SAAA,CADA,uBZ61BN,Ca36BA,WAEE,0CAAA,CADA,+Bb+6BF,Ca36BE,aALF,WAMI,Yb86BF,CACF,Ca36BE,kBACE,6BAAA,CAEA,aAAA,CADA,ab86BJ,Ca16BI,gCACE,Yb46BN,Cav6BE,iBACE,YAAA,CAKA,cAAA,CAIA,uCAAA,CADA,eAAA,CADA,oBAAA,CADA,kBAAA,CAIA,uBbq6BJ,Cal6BI,4CACE,Ubo6BN,Car6BI,yCACE,Ubo6BN,Car6BI,mCACE,Ubo6BN,Cah6BI,+BACE,oBbk6BN,CKnxBI,wCQrII,yCACE,Yb25BR,CACF,Cat5BI,iCACE,gBby5BN,Ca15BI,iCACE,iBby5BN,Ca15BI,uBAEE,gBbw5BN,Car5BM,iCACE,ebu5BR,Caj5BE,kBAEE,WAAA,CAGA,eAAA,CACA,kBAAA,CAHA,6BAAA,CACA,cAAA,CAHA,iBAAA,CAMA,kBbm5BJ,Ca/4BE,mBACE,YAAA,CACA,abi5BJ,Ca74BE,sBAKE,gBAAA,CAHA,MAAA,CACA,gBAAA,CAGA,UAAA,CAFA,cAAA,CAHA,iBAAA,CACA,Obm5BJ,Ca14BA,gBACE,gDb64BF,Ca14BE,uBACE,YAAA,CACA,cAAA,CACA,6BAAA,CACA,ab44BJ,Cax4BE,kCACE,sCb04BJ,Cav4BI,6DACE,+Bby4BN,Ca14BI,0DACE,+Bby4BN,Ca14BI,oDACE,+Bby4BN,Caj4BA,cAIE,wCAAA,CACA,gBAAA,CAHA,iBAAA,CACA,eAAA,CAFA,Ubw4BF,CK/1BI,mCQ1CJ,cASI,Ubo4BF,CACF,Cah4BE,yBACE,sCbk4BJ,Ca33BA,WACE,cAAA,CACA,qBb83BF,CK52BI,mCQpBJ,WAMI,eb83BF,CACF,Ca33BE,iBACE,oBAAA,CAEA,aAAA,CACA,iBAAA,CAFA,Yb+3BJ,Ca13BI,wBACE,eb43BN,Cax3BI,qBAGE,iBAAA,CAFA,gBAAA,CACA,mBb23BN,CcliCE,uBAKE,kBAAA,CACA,mBAAA,CAHA,gCAAA,CAIA,cAAA,CANA,oBAAA,CAGA,eAAA,CAFA,kBAAA,CAMA,gEdqiCJ,Cc/hCI,gCAEE,2CAAA,CACA,uCAAA,CAFA,gCdmiCN,Cc7hCI,kDAEE,0CAAA,CACA,sCAAA,CAFA,+BdiiCN,CcliCI,+CAEE,0CAAA,CACA,sCAAA,CAFA,+BdiiCN,CcliCI,yCAEE,0CAAA,CACA,sCAAA,CAFA,+BdiiCN,Cc1hCE,gCAKE,4Bd+hCJ,CcpiCE,gEAME,6Bd8hCJ,CcpiCE,gCAME,4Bd8hCJ,CcpiCE,sBAIE,6DAAA,CAGA,8BAAA,CAJA,eAAA,CAFA,aAAA,CACA,eAAA,CAMA,sCd4hCJ,CcvhCI,iDACE,6CAAA,CACA,8BdyhCN,Cc3hCI,8CACE,6CAAA,CACA,8BdyhCN,Cc3hCI,wCACE,6CAAA,CACA,8BdyhCN,CcrhCI,+BACE,UduhCN,Ce1kCA,WAOE,2CAAA,CAGA,0DACE,CALF,gCAAA,CADA,aAAA,CAFA,MAAA,CAFA,uBAAA,CAAA,eAAA,CAEA,OAAA,CADA,KAAA,CAEA,SfilCF,CetkCE,aAfF,WAgBI,YfykCF,CACF,CetkCE,mBACE,2BAAA,CACA,iEfwkCJ,CelkCE,mBACE,gEACE,CAEF,kEfkkCJ,Ce5jCE,kBAEE,kBAAA,CADA,YAAA,CAEA,ef8jCJ,Ce1jCE,mBAKE,kBAAA,CAGA,cAAA,CALA,YAAA,CAIA,uCAAA,CAHA,aAAA,CAHA,iBAAA,CAQA,uBAAA,CAHA,qBAAA,CAJA,SfmkCJ,CezjCI,yBACE,Uf2jCN,CevjCI,iCACE,oBfyjCN,CerjCI,uCAEE,uCAAA,CADA,YfwjCN,CenjCI,2BACE,YAAA,CACA,afqjCN,CKx8BI,wCU/GA,2BAMI,YfqjCN,CACF,CeljCM,iDAIE,iBAAA,CAHA,aAAA,CAEA,aAAA,CADA,UfsjCR,CexjCM,8CAIE,iBAAA,CAHA,aAAA,CAEA,aAAA,CADA,UfsjCR,CexjCM,wCAIE,iBAAA,CAHA,aAAA,CAEA,aAAA,CADA,UfsjCR,CKt+BI,mCUzEA,iCAII,Yf+iCN,CACF,Ce5iCM,wCACE,Yf8iCR,Ce1iCM,+CACE,oBf4iCR,CKj/BI,sCUtDA,iCAII,YfuiCN,CACF,CeliCE,kBAEE,YAAA,CACA,cAAA,CAFA,iBAAA,CAIA,8DACE,CAFF,kBfqiCJ,Ce/hCI,oCAGE,SAAA,CAIA,mBAAA,CALA,6BAAA,CAEA,8DACE,CAJF,UfqiCN,Ce5hCM,8CACE,8Bf8hCR,CezhCI,8BACE,ef2hCN,CethCE,4BAGE,kBf2hCJ,Ce9hCE,4BAGE,iBf2hCJ,Ce9hCE,4BAIE,gBf0hCJ,Ce9hCE,4BAIE,iBf0hCJ,Ce9hCE,kBACE,WAAA,CAIA,eAAA,CAHA,aAAA,CAIA,kBfwhCJ,CerhCI,4CAGE,SAAA,CAIA,mBAAA,CALA,8BAAA,CAEA,8DACE,CAJF,Uf2hCN,CelhCM,sDACE,6BfohCR,CehhCM,8DAGE,SAAA,CAIA,mBAAA,CALA,uBAAA,CAEA,8DACE,CAJF,SfshCR,Ce3gCI,uCAGE,WAAA,CAFA,iBAAA,CACA,Uf8gCN,CexgCE,mBACE,YAAA,CACA,aAAA,CACA,cAAA,CAEA,+CACE,CAFF,kBf2gCJ,CergCI,8DACE,WAAA,CACA,SAAA,CACA,oCfugCN,CehgCE,mBACE,YfkgCJ,CKvjCI,mCUoDF,6BAQI,gBfkgCJ,Ce1gCA,6BAQI,iBfkgCJ,Ce1gCA,mBAKI,aAAA,CAEA,iBAAA,CADA,afogCJ,CACF,CK/jCI,sCUoDF,6BAaI,kBfkgCJ,Ce/gCA,6BAaI,mBfkgCJ,CACF,CgB1uCA,MACE,0MAAA,CACA,gMAAA,CACA,yNhB6uCF,CgBvuCA,QACE,eAAA,CACA,ehB0uCF,CgBvuCE,eACE,aAAA,CAGA,eAAA,CADA,eAAA,CADA,eAAA,CAGA,sBhByuCJ,CgBtuCI,+BACE,YhBwuCN,CgBruCM,mCAEE,WAAA,CADA,UhBwuCR,CgBhuCQ,6DAME,iBAAA,CALA,aAAA,CAGA,aAAA,CADA,cAAA,CAEA,kBAAA,CAHA,UhBsuCV,CgBxuCQ,0DAME,iBAAA,CALA,aAAA,CAGA,aAAA,CADA,cAAA,CAEA,kBAAA,CAHA,UhBsuCV,CgBxuCQ,oDAME,iBAAA,CALA,aAAA,CAGA,aAAA,CADA,cAAA,CAEA,kBAAA,CAHA,UhBsuCV,CgB3tCE,cAGE,eAAA,CAFA,QAAA,CACA,ShB8tCJ,CgBztCE,cACE,ehB2tCJ,CgBxtCI,sCACE,ehB0tCN,CgB3tCI,sCACE,chB0tCN,CgBrtCE,cAEE,kBAAA,CAKA,cAAA,CANA,YAAA,CAEA,6BAAA,CACA,iBAAA,CACA,eAAA,CAIA,uBAAA,CAHA,sBAAA,CAEA,sBhBwtCJ,CgBptCI,sBACE,uChBstCN,CgBltCI,oCACE,+BhBotCN,CgBhtCI,0CACE,UhBktCN,CgB9sCI,yCACE,+BhBgtCN,CgBjtCI,sCACE,+BhBgtCN,CgBjtCI,gCACE,+BhBgtCN,CgB5sCI,4BACE,uCAAA,CACA,oBhB8sCN,CgB1sCI,0CACE,YhB4sCN,CgBzsCM,yDAKE,6BAAA,CAJA,aAAA,CAEA,WAAA,CACA,qCAAA,CAAA,6BAAA,CAFA,UhB8sCR,CgBvsCM,kDACE,YhBysCR,CgBpsCI,gBAEE,cAAA,CADA,YhBusCN,CgBjsCE,cACE,ahBmsCJ,CgB/rCE,gBACE,YhBisCJ,CK/oCI,wCW3CA,0CASE,2CAAA,CAHA,YAAA,CACA,qBAAA,CACA,WAAA,CAJA,MAAA,CAFA,iBAAA,CAEA,OAAA,CADA,KAAA,CAEA,ShBgsCJ,CgBrrCI,4DACE,eAAA,CACA,ehBurCN,CgBzrCI,yDACE,eAAA,CACA,ehBurCN,CgBzrCI,mDACE,eAAA,CACA,ehBurCN,CgBnrCI,gCAOE,qDAAA,CAHA,uCAAA,CAIA,cAAA,CANA,aAAA,CAGA,kBAAA,CAFA,wBAAA,CAFA,iBAAA,CAKA,kBhBurCN,CgBlrCM,wDAGE,UhBwrCR,CgB3rCM,wDAGE,WhBwrCR,CgB3rCM,8CAIE,aAAA,CAEA,aAAA,CACA,YAAA,CANA,iBAAA,CACA,SAAA,CAGA,YhBsrCR,CgBjrCQ,oDAIE,6BAAA,CAIA,UAAA,CAPA,aAAA,CAEA,WAAA,CAEA,2CAAA,CAAA,mCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CALA,UhByrCV,CgB9qCM,8CAEE,2CAAA,CACA,gEACE,CAHF,eAAA,CAIA,gCAAA,CAAA,4BAAA,CACA,kBhB+qCR,CgB5qCQ,2DACE,YhB8qCV,CgBzqCM,8CAGE,2CAAA,CAFA,gCAAA,CACA,ehB4qCR,CgBvqCM,yCAIE,aAAA,CADA,UAAA,CAEA,YAAA,CACA,aAAA,CALA,iBAAA,CAEA,WAAA,CADA,ShB6qCR,CgBpqCI,+BACE,MhBsqCN,CgBlqCI,+BAEE,4DAAA,CADA,ShBqqCN,CgBjqCM,qDACE,+BhBmqCR,CgBhqCQ,gFACE,+BhBkqCV,CgBnqCQ,6EACE,+BhBkqCV,CgBnqCQ,uEACE,+BhBkqCV,CgB5pCI,+BACE,YAAA,CACA,mBhB8pCN,CgB3pCM,uDAGE,mBhB8pCR,CgBjqCM,uDAGE,kBhB8pCR,CgBjqCM,6CAIE,gBAAA,CAFA,aAAA,CADA,YhBgqCR,CgB1pCQ,mDAIE,6BAAA,CAIA,UAAA,CAPA,aAAA,CAEA,WAAA,CAEA,2CAAA,CAAA,mCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CALA,UhBkqCV,CgBnpCM,+CACE,mBhBqpCR,CgB7oCM,4CAEE,wBAAA,CADA,ehBgpCR,CgB5oCQ,oEACE,mBhB8oCV,CgB/oCQ,oEACE,oBhB8oCV,CgB1oCQ,4EACE,iBhB4oCV,CgB7oCQ,4EACE,kBhB4oCV,CgBxoCQ,oFACE,mBhB0oCV,CgB3oCQ,oFACE,oBhB0oCV,CgBtoCQ,4FACE,mBhBwoCV,CgBzoCQ,4FACE,oBhBwoCV,CgBjoCE,mBACE,wBhBmoCJ,CgB/nCE,wBACE,YAAA,CAEA,SAAA,CADA,0BAAA,CAEA,oEhBioCJ,CgB5nCI,kCACE,2BhB8nCN,CgBznCE,gCAEE,SAAA,CADA,uBAAA,CAEA,qEhB2nCJ,CgBtnCI,8CAEE,kCAAA,CAAA,0BhBunCN,CACF,CK3xCI,wCW4KA,0CACE,YhBknCJ,CgB/mCI,yDACE,UhBinCN,CgB7mCI,wDACE,YhB+mCN,CgB3mCI,kDACE,YhB6mCN,CgBxmCE,gBAIE,iDAAA,CADA,gCAAA,CAFA,aAAA,CACA,ehB4mCJ,CACF,CKx1CM,6DWqPF,6CACE,YhBsmCJ,CgBnmCI,4DACE,UhBqmCN,CgBjmCI,2DACE,YhBmmCN,CgB/lCI,qDACE,YhBimCN,CACF,CKh1CI,mCW0PE,6CACE,uBhBylCN,CgBrlCI,gDACE,YhBulCN,CACF,CKx1CI,sCW7JJ,QAoaI,oDhBqlCF,CgB/kCI,8CACE,uBhBilCN,CgBvkCE,sEACE,YhB4kCJ,CgBxkCE,6DACE,ahB0kCJ,CgB3kCE,0DACE,ahB0kCJ,CgB3kCE,oDACE,ahB0kCJ,CgBtkCE,6CACE,YhBwkCJ,CgBpkCE,uBACE,aAAA,CACA,ehBskCJ,CgBnkCI,kCACE,ehBqkCN,CgBjkCI,qCACE,eAAA,CACA,mBhBmkCN,CgBhkCM,mDACE,mBhBkkCR,CgB9jCM,mDACE,YhBgkCR,CgB3jCI,+BACE,ahB6jCN,CgB1jCM,2DACE,ShB4jCR,CgBtjCE,cAIE,kBAAA,CAHA,WAAA,CAEA,YAAA,CAEA,+CACE,CAJF,WhB2jCJ,CgBnjCI,wBACE,UAAA,CACA,wBhBqjCN,CgBjjCI,oBACE,uDhBmjCN,CgB/iCI,oBAKE,6BAAA,CAIA,UAAA,CARA,oBAAA,CAEA,WAAA,CAGA,2CAAA,CAAA,mCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CAJA,qBAAA,CAFA,UhBwjCN,CgB7iCI,0JAEE,uBhB8iCN,CgBhiCI,+HACE,YhBsiCN,CgBniCM,oDACE,aAAA,CACA,ShBqiCR,CgBliCQ,kEAGE,eAAA,CAFA,YAAA,CACA,eAAA,CAEA,mBhBoiCV,CgBjiCU,gFACE,mBhBmiCZ,CgB/hCU,gFACE,YhBiiCZ,CgBzhCI,2CACE,ahB2hCN,CgBxhCM,iFACE,mBhB0hCR,CgB3hCM,iFACE,kBhB0hCR,CgBjhCI,mFACE,ehBmhCN,CgBhhCM,iGACE,ShBkhCR,CgB7gCI,qFAGE,mDhB+gCN,CgBlhCI,qFAGE,oDhB+gCN,CgBlhCI,2EACE,aAAA,CACA,oBhBghCN,CgB5gCM,0FACE,YhB8gCR,CACF,CiBhnDA,MACE,igBjBmnDF,CiB7mDA,WACE,iBjBgnDF,CKl9CI,mCY/JJ,WAKI,ejBgnDF,CACF,CiB7mDE,kBACE,YjB+mDJ,CiB3mDE,oBAEE,SAAA,CADA,SjB8mDJ,CK38CI,wCYpKF,8BAQI,YjBqnDJ,CiB7nDA,8BAQI,ajBqnDJ,CiB7nDA,oBAYI,2CAAA,CACA,kBAAA,CAHA,WAAA,CACA,eAAA,CAOA,mBAAA,CAZA,iBAAA,CACA,SAAA,CAOA,uBAAA,CACA,4CACE,CAPF,UjBonDJ,CiBxmDI,+DACE,SAAA,CACA,oCjB0mDN,CACF,CKj/CI,mCYjJF,8BAiCI,MjB4mDJ,CiB7oDA,8BAiCI,OjB4mDJ,CiB7oDA,oBAoCI,gCAAA,CACA,cAAA,CAFA,QAAA,CAJA,cAAA,CACA,KAAA,CAMA,sDACE,CALF,OjB2mDJ,CiBjmDI,+DAME,YAAA,CACA,SAAA,CACA,4CACE,CARF,UjBsmDN,CACF,CKh/CI,wCYxGA,+DAII,mBjBwlDN,CACF,CK9hDM,6DY/DF,+DASI,mBjBwlDN,CACF,CKniDM,6DY/DF,+DAcI,mBjBwlDN,CACF,CiBnlDE,kBAEE,kCAAA,CAAA,0BjBolDJ,CKlgDI,wCYpFF,4BAQI,MjB2lDJ,CiBnmDA,4BAQI,OjB2lDJ,CiBnmDA,kBAWI,QAAA,CAGA,SAAA,CAFA,eAAA,CANA,cAAA,CACA,KAAA,CAMA,wBAAA,CAEA,qGACE,CANF,OAAA,CADA,SjB0lDJ,CiB7kDI,4BACE,yBjB+kDN,CiB3kDI,6DAEE,WAAA,CAEA,SAAA,CADA,uBAAA,CAEA,sGACE,CALF,UjBilDN,CACF,CK7iDI,mCYjEF,kBA2CI,WAAA,CAEA,eAAA,CAHA,iBAAA,CAIA,8CAAA,CAFA,ajB0kDJ,CiBrkDI,4BACE,UjBukDN,CACF,CK/kDM,6DYYF,6DAII,ajBmkDN,CACF,CK9jDI,sCYVA,6DASI,ajBmkDN,CACF,CiB9jDE,iBAIE,2CAAA,CACA,gCAAA,CAFA,aAAA,CAFA,iBAAA,CAKA,2CACE,CALF,SjBokDJ,CK3kDI,mCYKF,iBAaI,gCAAA,CACA,mBAAA,CAFA,ajBgkDJ,CiB3jDI,uBACE,oCjB6jDN,CACF,CiBzjDI,4DAEE,2CAAA,CACA,6BAAA,CACA,oCAAA,CAHA,gCjB8jDN,CiBtjDE,4BAKE,mBAAA,CAAA,oBjB2jDJ,CiBhkDE,4BAKE,mBAAA,CAAA,oBjB2jDJ,CiBhkDE,kBAQE,sBAAA,CAFA,eAAA,CAFA,WAAA,CAHA,iBAAA,CAMA,sBAAA,CAJA,UAAA,CADA,SjB8jDJ,CiBrjDI,yCACE,yBAAA,CAAA,qBjBujDN,CiBxjDI,+BACE,qBjBujDN,CiBnjDI,yCAEE,uCjBojDN,CiBtjDI,kEAEE,uCjBojDN,CiBhjDI,6BACE,YjBkjDN,CK3lDI,wCYkBF,kBA8BI,eAAA,CADA,aAAA,CADA,UjBmjDJ,CACF,CKrnDI,mCYqCF,4BAmCI,mBjBmjDJ,CiBtlDA,4BAmCI,oBjBmjDJ,CiBtlDA,kBAoCI,aAAA,CACA,ejBijDJ,CiB9iDI,yCACE,uCjBgjDN,CiBjjDI,+BACE,uCjBgjDN,CiB5iDI,mCACE,gCjB8iDN,CiB1iDI,6DACE,kBjB4iDN,CiBziDM,oFAEE,uCjB0iDR,CiB5iDM,wJAEE,uCjB0iDR,CACF,CiBpiDE,iBAIE,cAAA,CAHA,oBAAA,CAEA,aAAA,CAEA,kCACE,CAJF,YjByiDJ,CiBjiDI,uBACE,UjBmiDN,CiB/hDI,yCAGE,UjBkiDN,CiBriDI,yCAGE,WjBkiDN,CiBriDI,+BACE,iBAAA,CACA,SAAA,CAEA,SjBiiDN,CiB9hDM,6CACE,oBjBgiDR,CKxoDI,wCYgGA,yCAcI,UjB+hDN,CiB7iDE,yCAcI,WjB+hDN,CiB7iDE,+BAaI,SjBgiDN,CiB5hDM,+CACE,YjB8hDR,CACF,CKpqDI,mCYmHA,+BAwBI,mBjB6hDN,CiB1hDM,8CACE,YjB4hDR,CACF,CiBthDE,8BAGE,WjB0hDJ,CiB7hDE,8BAGE,UjB0hDJ,CiB7hDE,oBAKE,mBAAA,CAJA,iBAAA,CACA,SAAA,CAEA,SjByhDJ,CKhqDI,wCYmIF,8BAUI,WjBwhDJ,CiBliDA,8BAUI,UjBwhDJ,CiBliDA,oBASI,SjByhDJ,CACF,CiBrhDI,gCACE,iBjB2hDN,CiB5hDI,gCACE,kBjB2hDN,CiB5hDI,sBAEE,uCAAA,CAEA,SAAA,CADA,oBAAA,CAEA,+DjBuhDN,CiBlhDM,yCAEE,uCAAA,CADA,YjBqhDR,CiBhhDM,yFAGE,SAAA,CACA,mBAAA,CAFA,kBjBmhDR,CiB9gDQ,8FACE,UjBghDV,CiBzgDE,8BAOE,mBAAA,CAAA,oBjBghDJ,CiBvhDE,8BAOE,mBAAA,CAAA,oBjBghDJ,CiBvhDE,oBAIE,kBAAA,CAIA,yCAAA,CALA,YAAA,CAMA,eAAA,CAHA,WAAA,CAKA,SAAA,CAVA,iBAAA,CACA,KAAA,CAUA,uBAAA,CAFA,kBAAA,CALA,UjBkhDJ,CK1tDI,mCYmMF,8BAgBI,mBjB4gDJ,CiB5hDA,8BAgBI,oBjB4gDJ,CiB5hDA,oBAiBI,ejB2gDJ,CACF,CiBxgDI,+DACE,SAAA,CACA,0BjB0gDN,CiBrgDE,6BAKE,+BjBwgDJ,CiB7gDE,0DAME,gCjBugDJ,CiB7gDE,6BAME,+BjBugDJ,CiB7gDE,mBAIE,eAAA,CAHA,iBAAA,CAEA,UAAA,CADA,SjB2gDJ,CKztDI,wCY4MF,mBAWI,QAAA,CADA,UjBwgDJ,CACF,CKlvDI,mCY+NF,mBAiBI,SAAA,CADA,UAAA,CAEA,sBjBugDJ,CiBpgDI,8DACE,8BAAA,CACA,SjBsgDN,CACF,CiBjgDE,uBAKE,kCAAA,CAAA,0BAAA,CAFA,2CAAA,CAFA,WAAA,CACA,eAAA,CAOA,kBjB+/CJ,CiB5/CI,iEAZF,uBAaI,uBjB+/CJ,CACF,CK/xDM,6DYkRJ,uBAkBI,ajB+/CJ,CACF,CK9wDI,sCY4PF,uBAuBI,ajB+/CJ,CACF,CKnxDI,mCY4PF,uBA4BI,YAAA,CAEA,+DAAA,CADA,oBjBggDJ,CiB5/CI,kEACE,ejB8/CN,CiB1/CI,6BACE,qDjB4/CN,CiBx/CI,0CAEE,YAAA,CADA,WjB2/CN,CiBt/CI,gDACE,oDjBw/CN,CiBr/CM,sDACE,0CjBu/CR,CACF,CiBh/CA,kBACE,gCAAA,CACA,qBjBm/CF,CiBh/CE,wBAKE,qDAAA,CAHA,uCAAA,CACA,gBAAA,CACA,kBAAA,CAHA,eAAA,CAKA,uBjBk/CJ,CKvzDI,mCY+TF,kCAUI,mBjBk/CJ,CiB5/CA,kCAUI,oBjBk/CJ,CACF,CiB9+CE,wBAGE,eAAA,CAFA,QAAA,CACA,SAAA,CAGA,wBAAA,CAAA,qBAAA,CAAA,oBAAA,CAAA,gBjB++CJ,CiB3+CE,wBACE,yDjB6+CJ,CiB1+CI,oCACE,ejB4+CN,CiBv+CE,wBACE,aAAA,CACA,YAAA,CAEA,uBAAA,CADA,gCjB0+CJ,CiBt+CI,mDACE,uDjBw+CN,CiBz+CI,gDACE,uDjBw+CN,CiBz+CI,0CACE,uDjBw+CN,CiBp+CI,gDACE,mBjBs+CN,CiBj+CE,gCAGE,+BAAA,CAGA,cAAA,CALA,aAAA,CAGA,gBAAA,CACA,YAAA,CAHA,mBAAA,CAQA,uBAAA,CAHA,2CjBo+CJ,CK91DI,mCYmXF,0CAcI,mBjBi+CJ,CiB/+CA,0CAcI,oBjBi+CJ,CACF,CiB99CI,2DAEE,uDAAA,CADA,+BjBi+CN,CiBl+CI,wDAEE,uDAAA,CADA,+BjBi+CN,CiBl+CI,kDAEE,uDAAA,CADA,+BjBi+CN,CiB59CI,wCACE,YjB89CN,CiBz9CI,wDACE,YjB29CN,CiBv9CI,oCACE,WjBy9CN,CiBp9CE,2BAGE,eAAA,CADA,eAAA,CADA,iBjBw9CJ,CKr3DI,mCY4ZF,qCAOI,mBjBs9CJ,CiB79CA,qCAOI,oBjBs9CJ,CACF,CiBh9CM,8DAGE,eAAA,CADA,eAAA,CAEA,eAAA,CAHA,ejBq9CR,CiB58CE,kCAEE,MjBk9CJ,CiBp9CE,kCAEE,OjBk9CJ,CiBp9CE,wBAME,uCAAA,CAFA,aAAA,CACA,YAAA,CAJA,iBAAA,CAEA,YjBi9CJ,CKr3DI,wCYiaF,wBAUI,YjB88CJ,CACF,CiB38CI,8BAIE,6BAAA,CAIA,UAAA,CAPA,oBAAA,CAEA,WAAA,CAEA,+CAAA,CAAA,uCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CALA,UjBm9CN,CiB18CM,wCACE,oBjB48CR,CiBt8CE,yBAGE,gBAAA,CADA,eAAA,CAEA,eAAA,CAHA,ajB28CJ,CiBp8CE,0BASE,2BAAA,CACA,oBAAA,CALA,uCAAA,CAJA,mBAAA,CAKA,gBAAA,CACA,eAAA,CAJA,aAAA,CADA,eAAA,CAEA,eAAA,CAIA,sBjBw8CJ,CKz5DI,wCYycF,0BAeI,oBAAA,CADA,ejBu8CJ,CACF,CKx8DM,6DYkfJ,0BAqBI,oBAAA,CADA,ejBu8CJ,CACF,CiBn8CI,+BAEE,wBAAA,CADA,yBjBs8CN,CiBh8CE,yBAEE,gBAAA,CACA,iBAAA,CAFA,ajBo8CJ,CiB97CE,uBAEE,wBAAA,CADA,+BjBi8CJ,CkB3mEA,WACE,iBAAA,CACA,SlB8mEF,CkB3mEE,kBAOE,2CAAA,CACA,mBAAA,CACA,8BAAA,CAHA,gCAAA,CAHA,QAAA,CAEA,gBAAA,CADA,YAAA,CAOA,SAAA,CAVA,iBAAA,CACA,sBAAA,CAQA,mCAAA,CAEA,oElB6mEJ,CkBvmEI,+DACE,gBAAA,CAEA,SAAA,CADA,+BAAA,CAEA,sFACE,CADF,8ElBymEN,CkB7mEI,4DACE,gBAAA,CAEA,SAAA,CADA,+BAAA,CAEA,mFACE,CADF,8ElBymEN,CkB7mEI,sDACE,gBAAA,CAEA,SAAA,CADA,+BAAA,CAEA,8ElBymEN,CkBlmEI,wBAUE,qCAAA,CAAA,8CAAA,CAFA,mCAAA,CAAA,oCAAA,CACA,YAAA,CAEA,UAAA,CANA,QAAA,CAFA,QAAA,CAIA,kBAAA,CADA,iBAAA,CALA,iBAAA,CACA,KAAA,CAEA,OlB2mEN,CkB/lEE,iBAOE,mBAAA,CAFA,eAAA,CACA,oBAAA,CAJA,QAAA,CADA,kBAAA,CAGA,aAAA,CADA,SlBqmEJ,CkB7lEE,iBACE,kBlB+lEJ,CkB3lEE,2BAGE,kBAAA,CAAA,oBlBimEJ,CkBpmEE,2BAGE,mBAAA,CAAA,mBlBimEJ,CkBpmEE,iBAKE,cAAA,CAJA,aAAA,CAGA,YAAA,CAKA,uBAAA,CAHA,2CACE,CALF,UlBkmEJ,CkBxlEI,4CACE,+BlB0lEN,CkB3lEI,yCACE,+BlB0lEN,CkB3lEI,mCACE,+BlB0lEN,CkBtlEI,uBACE,qDlBwlEN,CmB5qEA,YAIE,qBAAA,CADA,aAAA,CAGA,gBAAA,CALA,uBAAA,CAAA,eAAA,CACA,UAAA,CAGA,anBgrEF,CmB5qEE,aATF,YAUI,YnB+qEF,CACF,CKjgEI,wCcxKA,+BAGE,anBmrEJ,CmBtrEE,+BAGE,cnBmrEJ,CmBtrEE,qBAQE,2CAAA,CAHA,aAAA,CAEA,WAAA,CANA,cAAA,CACA,KAAA,CAOA,uBAAA,CACA,iEACE,CALF,aAAA,CAFA,SnBkrEJ,CmBvqEI,mEACE,8BAAA,CACA,6BnByqEN,CmBtqEM,6EACE,8BnBwqER,CmBnqEI,6CAEE,QAAA,CAAA,MAAA,CACA,QAAA,CAEA,eAAA,CAJA,iBAAA,CACA,OAAA,CAEA,yBAAA,CAAA,qBAAA,CAFA,KnBwqEN,CACF,CKhjEI,sCctKJ,YAuDI,QnBmqEF,CmBhqEE,mBACE,WnBkqEJ,CACF,CmB9pEE,uBACE,YAAA,CACA,OnBgqEJ,CK5jEI,mCctGF,uBAMI,QnBgqEJ,CmB7pEI,8BACE,WnB+pEN,CmB3pEI,qCACE,anB6pEN,CmBzpEI,+CACE,kBnB2pEN,CACF,CmBtpEE,wBAIE,kCAAA,CAAA,0BAAA,CAHA,cAAA,CACA,eAAA,CAQA,+DAAA,CADA,oBnBopEJ,CmBhpEI,8BACE,qDnBkpEN,CmB9oEI,2CAEE,YAAA,CADA,WnBipEN,CmB5oEI,iDACE,oDnB8oEN,CmB3oEM,uDACE,0CnB6oER,CK3kEI,wCcxDF,YAME,gCAAA,CADA,QAAA,CAEA,SAAA,CANA,cAAA,CACA,KAAA,CAMA,sDACE,CALF,OAAA,CADA,SnB4oEF,CmBjoEE,4CAEE,WAAA,CACA,SAAA,CACA,4CACE,CAJF,UnBsoEJ,CACF,CoBvxEA,yBACE,GACE,QpByxEF,CoBtxEA,GACE,apBwxEF,CACF,CoB/xEA,iBACE,GACE,QpByxEF,CoBtxEA,GACE,apBwxEF,CACF,CoBpxEA,wBACE,GAEE,SAAA,CADA,0BpBuxEF,CoBnxEA,IACE,SpBqxEF,CoBlxEA,GAEE,SAAA,CADA,uBpBqxEF,CACF,CoBjyEA,gBACE,GAEE,SAAA,CADA,0BpBuxEF,CoBnxEA,IACE,SpBqxEF,CoBlxEA,GAEE,SAAA,CADA,uBpBqxEF,CACF,CoB5wEA,MACE,mgBAAA,CACA,oiBAAA,CACA,0nBAAA,CACA,mhBpB8wEF,CoBxwEA,WAOE,kCAAA,CAAA,0BAAA,CANA,aAAA,CACA,gBAAA,CACA,eAAA,CAEA,uCAAA,CAGA,uBAAA,CAJA,kBpB8wEF,CoBvwEE,iBACE,UpBywEJ,CoBrwEE,iBACE,oBAAA,CAEA,aAAA,CACA,qBAAA,CAFA,UpBywEJ,CoBpwEI,+BAEE,iBpBswEN,CoBxwEI,+BAEE,kBpBswEN,CoBxwEI,qBACE,gBpBuwEN,CoBlwEI,kDACE,iBpBqwEN,CoBtwEI,kDACE,kBpBqwEN,CoBtwEI,kDAEE,iBpBowEN,CoBtwEI,kDAEE,kBpBowEN,CoB/vEE,iCAGE,iBpBowEJ,CoBvwEE,iCAGE,kBpBowEJ,CoBvwEE,uBACE,oBAAA,CACA,6BAAA,CAEA,eAAA,CACA,sBAAA,CACA,qBpBiwEJ,CoB7vEE,kBACE,YAAA,CAMA,gBAAA,CALA,SAAA,CAMA,oBAAA,CAJA,gBAAA,CAKA,WAAA,CAHA,eAAA,CADA,SAAA,CAFA,UpBqwEJ,CoB5vEI,iDACE,oCAAA,CAAA,4BpB8vEN,CoBzvEE,iBACE,eAAA,CACA,sBpB2vEJ,CoBxvEI,gDACE,mCAAA,CAAA,2BpB0vEN,CoBtvEI,kCAIE,kBpB6vEN,CoBjwEI,kCAIE,iBpB6vEN,CoBjwEI,wBAME,6BAAA,CAGA,UAAA,CARA,oBAAA,CAEA,YAAA,CAIA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CAHA,uBAAA,CAHA,WpB+vEN,CoBpvEI,iCACE,apBsvEN,CoBlvEI,iCACE,gDAAA,CAAA,wCpBovEN,CoBhvEI,+BACE,8CAAA,CAAA,sCpBkvEN,CoB9uEI,+BACE,8CAAA,CAAA,sCpBgvEN,CoB5uEI,sCACE,qDAAA,CAAA,6CpB8uEN,CqBp4EA,SASE,2CAAA,CAFA,gCAAA,CAHA,aAAA,CAIA,eAAA,CAFA,aAAA,CADA,UAAA,CAFA,SrB24EF,CqBl4EE,aAZF,SAaI,YrBq4EF,CACF,CK1tEI,wCgBzLJ,SAkBI,YrBq4EF,CACF,CqBl4EE,iBACE,mBrBo4EJ,CqBh4EE,yBAEE,iBrBs4EJ,CqBx4EE,yBAEE,kBrBs4EJ,CqBx4EE,eAME,eAAA,CADA,eAAA,CAJA,QAAA,CAEA,SAAA,CACA,kBrBo4EJ,CqB93EE,eACE,oBAAA,CACA,aAAA,CACA,kBAAA,CAAA,mBrBg4EJ,CqB33EE,eAOE,kCAAA,CAAA,0BAAA,CANA,aAAA,CAEA,eAAA,CADA,gBAAA,CAMA,UAAA,CAJA,uCAAA,CACA,oBAAA,CAIA,8DrB43EJ,CqBv3EI,iEAEE,aAAA,CACA,SrBw3EN,CqB33EI,8DAEE,aAAA,CACA,SrBw3EN,CqB33EI,wDAEE,aAAA,CACA,SrBw3EN,CqBn3EM,2CACE,qBrBq3ER,CqBt3EM,2CACE,qBrBw3ER,CqBz3EM,2CACE,qBrB23ER,CqB53EM,2CACE,qBrB83ER,CqB/3EM,2CACE,oBrBi4ER,CqBl4EM,2CACE,qBrBo4ER,CqBr4EM,2CACE,qBrBu4ER,CqBx4EM,2CACE,qBrB04ER,CqB34EM,4CACE,qBrB64ER,CqB94EM,4CACE,oBrBg5ER,CqBj5EM,4CACE,qBrBm5ER,CqBp5EM,4CACE,qBrBs5ER,CqBv5EM,4CACE,qBrBy5ER,CqB15EM,4CACE,qBrB45ER,CqB75EM,4CACE,oBrB+5ER,CqBz5EI,gCAEE,SAAA,CADA,yBAAA,CAEA,wCrB25EN,CsBx+EA,SACE,mBtB2+EF,CsBv+EA,kBAEE,iBtBi/EF,CsBn/EA,kBAEE,gBtBi/EF,CsBn/EA,QAQE,+CAAA,CACA,mBAAA,CARA,oBAAA,CAKA,gBAAA,CADA,eAAA,CAEA,eAAA,CAJA,kBAAA,CACA,uBtB++EF,CsBv+EE,cAGE,uCAAA,CAFA,aAAA,CACA,YAAA,CAEA,6CtBy+EJ,CsBp+EI,wCAGE,0CAAA,CADA,+BtBs+EN,CsBh+EE,aACE,uBtBk+EJ,CuBrgFA,yBACE,GACE,uDAAA,CACA,oBvBwgFF,CuBrgFA,IACE,mCAAA,CACA,kBvBugFF,CuBpgFA,GACE,8BAAA,CACA,oBvBsgFF,CACF,CuBphFA,iBACE,GACE,uDAAA,CACA,oBvBwgFF,CuBrgFA,IACE,mCAAA,CACA,kBvBugFF,CuBpgFA,GACE,8BAAA,CACA,oBvBsgFF,CACF,CuB9/EA,MACE,wBvBggFF,CuB1/EA,YAwBE,kCAAA,CAAA,0BAAA,CALA,2CAAA,CACA,mBAAA,CACA,8BAAA,CAHA,gCAAA,CAfA,+IACE,CAaF,YAAA,CADA,8BAAA,CASA,SAAA,CAxBA,iBAAA,CACA,uBAAA,CAoBA,4BAAA,CAIA,2EACE,CAZF,6BAAA,CADA,SvBqgFF,CuBl/EE,0BACE,gBAAA,CAEA,SAAA,CADA,uBAAA,CAEA,2FvBo/EJ,CuB5+EE,2BACE,sCvB8+EJ,CuB1+EE,mBAEE,gBAAA,CADA,avB6+EJ,CuBz+EI,2CACE,YvB2+EN,CuBv+EI,0CACE,evBy+EN,CuBj+EA,eAEE,YAAA,CADA,kBvBq+EF,CuBj+EE,yBACE,avBm+EJ,CuB/9EE,6BACE,oBAAA,CAGA,iBvB+9EJ,CuB39EE,8BACE,SvB69EJ,CuBz9EE,sBAEE,sCAAA,CADA,qCvB49EJ,CuBx9EI,0CAEE,mBAAA,CADA,wBAAA,CAAA,qBAAA,CAAA,oBAAA,CAAA,gBvB29EN,CuBr9EE,sBAIE,UAAA,CACA,cAAA,CAFA,YAAA,CAFA,iBAAA,CAKA,uBAAA,CACA,wBAAA,CAAA,qBAAA,CAAA,oBAAA,CAAA,gBAAA,CALA,SvB49EJ,CuBj9EI,4BAWE,oDAAA,CACA,iBAAA,CAIA,UAAA,CARA,YAAA,CANA,YAAA,CAOA,cAAA,CACA,cAAA,CATA,iBAAA,CAYA,2CACE,CARF,wBAAA,CACA,6BAAA,CAJA,UvB49EN,CuB58EM,4CAGE,8CACE,mCAAA,CAAA,2BvB48ER,CACF,CuBx8EM,+DACE,0CvB08ER,CuB38EM,4DACE,0CvB08ER,CuB38EM,sDACE,0CvB08ER,CuBt8EM,0CAIE,sBAAA,CAAA,cAAA,CAHA,2CvBy8ER,CuBj8EI,8CACE,oBAAA,CACA,evBm8EN,CuBh8EM,qDAME,mCAAA,CALA,oBAAA,CACA,mBAAA,CAEA,qBAAA,CACA,iDAAA,CAFA,qBvBq8ER,CuB97EQ,iBAVF,qDAWI,WvBi8ER,CuB97EQ,mEACE,mCvBg8EV,CACF,CuB17EI,yDACE,+BvB47EN,CuB77EI,sDACE,+BvB47EN,CuB77EI,gDACE,+BvB47EN,CuBx7EI,oCAEE,sBAAA,CAAA,cAAA,CADA,evB27EN,CwBxpFA,kBAKE,exBoqFF,CwBzqFA,kBAKE,gBxBoqFF,CwBzqFA,QASE,2CAAA,CACA,oBAAA,CAEA,8BAAA,CALA,uCAAA,CAHA,aAAA,CAIA,eAAA,CAGA,YAAA,CALA,mBAAA,CALA,cAAA,CACA,UAAA,CAWA,yBAAA,CACA,mGACE,CAZF,SxBsqFF,CwBppFE,aArBF,QAsBI,YxBupFF,CACF,CwBppFE,kBACE,wBxBspFJ,CwBlpFE,gBAEE,SAAA,CAEA,mBAAA,CAHA,+BAAA,CAEA,uBxBqpFJ,CwBjpFI,0BACE,8BxBmpFN,CwB9oFE,mCAEE,0CAAA,CADA,+BxBipFJ,CwBlpFE,gCAEE,0CAAA,CADA,+BxBipFJ,CwBlpFE,0BAEE,0CAAA,CADA,+BxBipFJ,CwB5oFE,YACE,oBAAA,CACA,oBxB8oFJ,CyBlsFA,4BACE,GACE,mBzBqsFF,CACF,CyBxsFA,oBACE,GACE,mBzBqsFF,CACF,CyB7rFA,MACE,wfzB+rFF,CyBzrFA,YACE,aAAA,CAEA,eAAA,CADA,azB6rFF,CyBzrFE,+BAOE,kBAAA,CAAA,kBzB0rFJ,CyBjsFE,+BAOE,iBAAA,CAAA,mBzB0rFJ,CyBjsFE,qBAQE,aAAA,CAEA,cAAA,CADA,YAAA,CARA,iBAAA,CAKA,UzB2rFJ,CyBprFI,qCAIE,iBzB0rFN,CyB9rFI,qCAIE,kBzB0rFN,CyB9rFI,2BAKE,6BAAA,CAGA,UAAA,CAPA,oBAAA,CAEA,YAAA,CAGA,yCAAA,CAAA,iCAAA,CACA,6BAAA,CAAA,qBAAA,CALA,WzB4rFN,CyBjrFE,kBAUE,2CAAA,CACA,mBAAA,CACA,8BAAA,CAJA,gCAAA,CACA,oBAAA,CAJA,kBAAA,CADA,YAAA,CASA,SAAA,CANA,aAAA,CADA,SAAA,CALA,iBAAA,CAgBA,gCAAA,CAAA,4BAAA,CAfA,UAAA,CAYA,+CACE,CAZF,SzB+rFJ,CyB9qFI,gEACE,gBAAA,CACA,SAAA,CACA,8CACE,CADF,sCzBgrFN,CyBnrFI,6DACE,gBAAA,CACA,SAAA,CACA,2CACE,CADF,sCzBgrFN,CyBnrFI,uDACE,gBAAA,CACA,SAAA,CACA,sCzBgrFN,CyB1qFI,wBAGE,oCACE,wCAAA,CAAA,gCzB0qFN,CyBtqFI,2CACE,sBAAA,CAAA,czBwqFN,CACF,CyBnqFE,kBACE,kBzBqqFJ,CyBjqFE,4BAGE,kBAAA,CAAA,oBzBwqFJ,CyB3qFE,4BAGE,mBAAA,CAAA,mBzBwqFJ,CyB3qFE,kBAME,cAAA,CALA,aAAA,CAIA,YAAA,CAKA,uBAAA,CAHA,2CACE,CAJF,kBAAA,CAFA,UzByqFJ,CyB9pFI,6CACE,+BzBgqFN,CyBjqFI,0CACE,+BzBgqFN,CyBjqFI,oCACE,+BzBgqFN,CyB5pFI,wBACE,qDzB8pFN,C0B7vFA,MAEI,2RAAA,CAAA,8WAAA,CAAA,sPAAA,CAAA,8xBAAA,CAAA,qNAAA,CAAA,gbAAA,CAAA,gMAAA,CAAA,+PAAA,CAAA,8KAAA,CAAA,0eAAA,CAAA,kUAAA,CAAA,gM1BsxFJ,C0B1wFE,8CAOE,8CAAA,CACA,sBAAA,CAEA,mBAAA,CACA,8BAAA,CAPA,mCAAA,CAHA,iBAAA,CAIA,gBAAA,CAHA,iBAAA,CACA,eAAA,CAGA,uB1BkxFJ,C0BxxFE,2CAOE,8CAAA,CACA,sBAAA,CAEA,mBAAA,CACA,8BAAA,CAPA,mCAAA,CAHA,iBAAA,CAIA,gBAAA,CAHA,iBAAA,CACA,eAAA,CAGA,uB1BkxFJ,C0BxxFE,wDASE,uB1B+wFJ,C0BxxFE,qDASE,uB1B+wFJ,C0BxxFE,+CASE,uB1B+wFJ,C0BxxFE,wDASE,wB1B+wFJ,C0BxxFE,qDASE,wB1B+wFJ,C0BxxFE,+CASE,wB1B+wFJ,C0BxxFE,qCAOE,8CAAA,CACA,sBAAA,CAEA,mBAAA,CACA,8BAAA,CAPA,mCAAA,CAHA,iBAAA,CAIA,gBAAA,CAHA,iBAAA,CACA,eAAA,CAGA,uB1BkxFJ,C0B1wFI,aAdF,8CAeI,e1B6wFJ,C0B5xFA,2CAeI,e1B6wFJ,C0B5xFA,qCAeI,e1B6wFJ,CACF,C0BzwFI,gDACE,qB1B2wFN,C0B5wFI,6CACE,qB1B2wFN,C0B5wFI,uCACE,qB1B2wFN,C0BvwFI,gFAEE,iBAAA,CADA,c1B0wFN,C0B3wFI,0EAEE,iBAAA,CADA,c1B0wFN,C0B3wFI,8DAEE,iBAAA,CADA,c1B0wFN,C0BrwFI,sEACE,iB1BuwFN,C0BxwFI,mEACE,iB1BuwFN,C0BxwFI,6DACE,iB1BuwFN,C0BnwFI,iEACE,e1BqwFN,C0BtwFI,8DACE,e1BqwFN,C0BtwFI,wDACE,e1BqwFN,C0BjwFI,qEACE,Y1BmwFN,C0BpwFI,kEACE,Y1BmwFN,C0BpwFI,4DACE,Y1BmwFN,C0B/vFI,+DACE,mB1BiwFN,C0BlwFI,4DACE,mB1BiwFN,C0BlwFI,sDACE,mB1BiwFN,C0B5vFE,oDAOE,oCAAA,CACA,WAAA,CAFA,eAAA,CAJA,eAAA,CAAA,YAAA,CAEA,oBAAA,CAAA,iBAAA,CAHA,iB1BwwFJ,C0BzwFE,iDAOE,oCAAA,CACA,WAAA,CAFA,eAAA,CAJA,eAAA,CAAA,YAAA,CAEA,oBAAA,CAAA,iBAAA,CAHA,iB1BwwFJ,C0BzwFE,8DAGE,kBAAA,CAAA,mB1BswFJ,C0BzwFE,2DAGE,kBAAA,CAAA,mB1BswFJ,C0BzwFE,qDAGE,kBAAA,CAAA,mB1BswFJ,C0BzwFE,8DAGE,kBAAA,CAAA,mB1BswFJ,C0BzwFE,2DAGE,kBAAA,CAAA,mB1BswFJ,C0BzwFE,qDAGE,kBAAA,CAAA,mB1BswFJ,C0BzwFE,8DAKE,mBAAA,CAAA,mB1BowFJ,C0BzwFE,2DAKE,mBAAA,CAAA,mB1BowFJ,C0BzwFE,qDAKE,mBAAA,CAAA,mB1BowFJ,C0BzwFE,8DAKE,kBAAA,CAAA,oB1BowFJ,C0BzwFE,2DAKE,kBAAA,CAAA,oB1BowFJ,C0BzwFE,qDAKE,kBAAA,CAAA,oB1BowFJ,C0BzwFE,8DASE,uB1BgwFJ,C0BzwFE,2DASE,uB1BgwFJ,C0BzwFE,qDASE,uB1BgwFJ,C0BzwFE,8DASE,wB1BgwFJ,C0BzwFE,2DASE,wB1BgwFJ,C0BzwFE,qDASE,wB1BgwFJ,C0BzwFE,8DAUE,4B1B+vFJ,C0BzwFE,2DAUE,4B1B+vFJ,C0BzwFE,qDAUE,4B1B+vFJ,C0BzwFE,8DAUE,6B1B+vFJ,C0BzwFE,2DAUE,6B1B+vFJ,C0BzwFE,qDAUE,6B1B+vFJ,C0BzwFE,8DAWE,6B1B8vFJ,C0BzwFE,2DAWE,6B1B8vFJ,C0BzwFE,qDAWE,6B1B8vFJ,C0BzwFE,8DAWE,4B1B8vFJ,C0BzwFE,2DAWE,4B1B8vFJ,C0BzwFE,qDAWE,4B1B8vFJ,C0BzwFE,2CAOE,oCAAA,CACA,WAAA,CAFA,eAAA,CAJA,eAAA,CAAA,YAAA,CAEA,oBAAA,CAAA,iBAAA,CAHA,iB1BwwFJ,C0B3vFI,oEACE,e1B6vFN,C0B9vFI,iEACE,e1B6vFN,C0B9vFI,2DACE,e1B6vFN,C0BzvFI,2DAME,wBCuIU,CDnIV,UAAA,CALA,WAAA,CAEA,kDAAA,CAAA,0CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CARA,iBAAA,CACA,UAAA,CAEA,U1BiwFN,C0BrwFI,wDAME,wBCuIU,CDnIV,UAAA,CALA,WAAA,CAEA,0CAAA,CACA,qBAAA,CACA,iBAAA,CARA,iBAAA,CACA,UAAA,CAEA,U1BiwFN,C0BrwFI,qEAGE,U1BkwFN,C0BrwFI,kEAGE,U1BkwFN,C0BrwFI,4DAGE,U1BkwFN,C0BrwFI,qEAGE,W1BkwFN,C0BrwFI,kEAGE,W1BkwFN,C0BrwFI,4DAGE,W1BkwFN,C0BrwFI,kDAME,wBCuIU,CDnIV,UAAA,CALA,WAAA,CAEA,kDAAA,CAAA,0CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CARA,iBAAA,CACA,UAAA,CAEA,U1BiwFN,C0BtuFE,iEACE,oB1ByuFJ,C0B1uFE,2DACE,oB1ByuFJ,C0B1uFE,+CACE,oB1ByuFJ,C0BruFE,wEACE,oC1BwuFJ,C0BzuFE,kEACE,oC1BwuFJ,C0BzuFE,sDACE,oC1BwuFJ,C0BruFI,+EACE,wBAnBG,CAoBH,kDAAA,CAAA,0CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1BuuFN,C0B3uFI,yEACE,wBAnBG,CAoBH,0CAAA,CACA,qBAAA,CACA,iB1BuuFN,C0B3uFI,6DACE,wBAnBG,CAoBH,kDAAA,CAAA,0CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1BuuFN,C0BpvFE,oFACE,oB1BuvFJ,C0BxvFE,8EACE,oB1BuvFJ,C0BxvFE,kEACE,oB1BuvFJ,C0BnvFE,2FACE,mC1BsvFJ,C0BvvFE,qFACE,mC1BsvFJ,C0BvvFE,yEACE,mC1BsvFJ,C0BnvFI,kGACE,wBAnBG,CAoBH,sDAAA,CAAA,8CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1BqvFN,C0BzvFI,4FACE,wBAnBG,CAoBH,8CAAA,CACA,qBAAA,CACA,iB1BqvFN,C0BzvFI,gFACE,wBAnBG,CAoBH,sDAAA,CAAA,8CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1BqvFN,C0BlwFE,uEACE,oB1BqwFJ,C0BtwFE,iEACE,oB1BqwFJ,C0BtwFE,qDACE,oB1BqwFJ,C0BjwFE,8EACE,mC1BowFJ,C0BrwFE,wEACE,mC1BowFJ,C0BrwFE,4DACE,mC1BowFJ,C0BjwFI,qFACE,wBAnBG,CAoBH,kDAAA,CAAA,0CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1BmwFN,C0BvwFI,+EACE,wBAnBG,CAoBH,0CAAA,CACA,qBAAA,CACA,iB1BmwFN,C0BvwFI,mEACE,wBAnBG,CAoBH,kDAAA,CAAA,0CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1BmwFN,C0BhxFE,iFACE,oB1BmxFJ,C0BpxFE,2EACE,oB1BmxFJ,C0BpxFE,+DACE,oB1BmxFJ,C0B/wFE,wFACE,mC1BkxFJ,C0BnxFE,kFACE,mC1BkxFJ,C0BnxFE,sEACE,mC1BkxFJ,C0B/wFI,+FACE,wBAnBG,CAoBH,iDAAA,CAAA,yCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1BixFN,C0BrxFI,yFACE,wBAnBG,CAoBH,yCAAA,CACA,qBAAA,CACA,iB1BixFN,C0BrxFI,6EACE,wBAnBG,CAoBH,iDAAA,CAAA,yCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1BixFN,C0B9xFE,iFACE,oB1BiyFJ,C0BlyFE,2EACE,oB1BiyFJ,C0BlyFE,+DACE,oB1BiyFJ,C0B7xFE,wFACE,kC1BgyFJ,C0BjyFE,kFACE,kC1BgyFJ,C0BjyFE,sEACE,kC1BgyFJ,C0B7xFI,+FACE,wBAnBG,CAoBH,qDAAA,CAAA,6CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1B+xFN,C0BnyFI,yFACE,wBAnBG,CAoBH,6CAAA,CACA,qBAAA,CACA,iB1B+xFN,C0BnyFI,6EACE,wBAnBG,CAoBH,qDAAA,CAAA,6CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1B+xFN,C0B5yFE,gFACE,oB1B+yFJ,C0BhzFE,0EACE,oB1B+yFJ,C0BhzFE,8DACE,oB1B+yFJ,C0B3yFE,uFACE,oC1B8yFJ,C0B/yFE,iFACE,oC1B8yFJ,C0B/yFE,qEACE,oC1B8yFJ,C0B3yFI,8FACE,wBAnBG,CAoBH,sDAAA,CAAA,8CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1B6yFN,C0BjzFI,wFACE,wBAnBG,CAoBH,8CAAA,CACA,qBAAA,CACA,iB1B6yFN,C0BjzFI,4EACE,wBAnBG,CAoBH,sDAAA,CAAA,8CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1B6yFN,C0B1zFE,wFACE,oB1B6zFJ,C0B9zFE,kFACE,oB1B6zFJ,C0B9zFE,sEACE,oB1B6zFJ,C0BzzFE,+FACE,mC1B4zFJ,C0B7zFE,yFACE,mC1B4zFJ,C0B7zFE,6EACE,mC1B4zFJ,C0BzzFI,sGACE,wBAnBG,CAoBH,qDAAA,CAAA,6CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1B2zFN,C0B/zFI,gGACE,wBAnBG,CAoBH,6CAAA,CACA,qBAAA,CACA,iB1B2zFN,C0B/zFI,oFACE,wBAnBG,CAoBH,qDAAA,CAAA,6CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1B2zFN,C0Bx0FE,mFACE,oB1B20FJ,C0B50FE,6EACE,oB1B20FJ,C0B50FE,iEACE,oB1B20FJ,C0Bv0FE,0FACE,mC1B00FJ,C0B30FE,oFACE,mC1B00FJ,C0B30FE,wEACE,mC1B00FJ,C0Bv0FI,iGACE,wBAnBG,CAoBH,qDAAA,CAAA,6CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1By0FN,C0B70FI,2FACE,wBAnBG,CAoBH,6CAAA,CACA,qBAAA,CACA,iB1By0FN,C0B70FI,+EACE,wBAnBG,CAoBH,qDAAA,CAAA,6CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1By0FN,C0Bt1FE,0EACE,oB1By1FJ,C0B11FE,oEACE,oB1By1FJ,C0B11FE,wDACE,oB1By1FJ,C0Br1FE,iFACE,mC1Bw1FJ,C0Bz1FE,2EACE,mC1Bw1FJ,C0Bz1FE,+DACE,mC1Bw1FJ,C0Br1FI,wFACE,wBAnBG,CAoBH,oDAAA,CAAA,4CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1Bu1FN,C0B31FI,kFACE,wBAnBG,CAoBH,4CAAA,CACA,qBAAA,CACA,iB1Bu1FN,C0B31FI,sEACE,wBAnBG,CAoBH,oDAAA,CAAA,4CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1Bu1FN,C0Bp2FE,gEACE,oB1Bu2FJ,C0Bx2FE,0DACE,oB1Bu2FJ,C0Bx2FE,8CACE,oB1Bu2FJ,C0Bn2FE,uEACE,kC1Bs2FJ,C0Bv2FE,iEACE,kC1Bs2FJ,C0Bv2FE,qDACE,kC1Bs2FJ,C0Bn2FI,8EACE,wBAnBG,CAoBH,iDAAA,CAAA,yCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1Bq2FN,C0Bz2FI,wEACE,wBAnBG,CAoBH,yCAAA,CACA,qBAAA,CACA,iB1Bq2FN,C0Bz2FI,4DACE,wBAnBG,CAoBH,iDAAA,CAAA,yCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1Bq2FN,C0Bl3FE,oEACE,oB1Bq3FJ,C0Bt3FE,8DACE,oB1Bq3FJ,C0Bt3FE,kDACE,oB1Bq3FJ,C0Bj3FE,2EACE,oC1Bo3FJ,C0Br3FE,qEACE,oC1Bo3FJ,C0Br3FE,yDACE,oC1Bo3FJ,C0Bj3FI,kFACE,wBAnBG,CAoBH,qDAAA,CAAA,6CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1Bm3FN,C0Bv3FI,4EACE,wBAnBG,CAoBH,6CAAA,CACA,qBAAA,CACA,iB1Bm3FN,C0Bv3FI,gEACE,wBAnBG,CAoBH,qDAAA,CAAA,6CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1Bm3FN,C0Bh4FE,wEACE,oB1Bm4FJ,C0Bp4FE,kEACE,oB1Bm4FJ,C0Bp4FE,sDACE,oB1Bm4FJ,C0B/3FE,+EACE,kC1Bk4FJ,C0Bn4FE,yEACE,kC1Bk4FJ,C0Bn4FE,6DACE,kC1Bk4FJ,C0B/3FI,sFACE,wBAnBG,CAoBH,mDAAA,CAAA,2CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1Bi4FN,C0Br4FI,gFACE,wBAnBG,CAoBH,2CAAA,CACA,qBAAA,CACA,iB1Bi4FN,C0Br4FI,oEACE,wBAnBG,CAoBH,mDAAA,CAAA,2CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iB1Bi4FN,C4BzhGA,MACE,wM5B4hGF,C4BnhGE,sBACE,uCAAA,CACA,gB5BshGJ,C4BnhGI,mCACE,a5BqhGN,C4BthGI,mCACE,c5BqhGN,C4BjhGM,4BACE,sB5BmhGR,C4BhhGQ,mCACE,gC5BkhGV,C4B9gGQ,2DAEE,SAAA,CADA,uBAAA,CAEA,e5BghGV,C4B5gGQ,0EAEE,SAAA,CADA,uB5B+gGV,C4BhhGQ,uEAEE,SAAA,CADA,uB5B+gGV,C4BhhGQ,iEAEE,SAAA,CADA,uB5B+gGV,C4B1gGQ,yCACE,Y5B4gGV,C4BrgGE,0BAEE,eAAA,CADA,e5BwgGJ,C4BpgGI,+BACE,oB5BsgGN,C4BjgGE,gDACE,Y5BmgGJ,C4B//FE,8BAEE,+BAAA,CADA,oBAAA,CAGA,WAAA,CAGA,SAAA,CADA,4BAAA,CAEA,4DACE,CAJF,0B5BmgGJ,C4B1/FI,aAdF,8BAeI,+BAAA,CAEA,SAAA,CADA,uB5B8/FJ,CACF,C4B1/FI,wCACE,6B5B4/FN,C4Bx/FI,oCACE,+B5B0/FN,C4Bt/FI,qCAIE,6BAAA,CAIA,UAAA,CAPA,oBAAA,CAEA,YAAA,CAEA,2CAAA,CAAA,mCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CALA,W5B8/FN,C4Bl/FQ,mDACE,oB5Bo/FV,C6BjmGE,kCAEE,iB7BumGJ,C6BzmGE,kCAEE,kB7BumGJ,C6BzmGE,wBAGE,yCAAA,CAFA,oBAAA,CAGA,SAAA,CACA,mC7BomGJ,C6B/lGI,aAVF,wBAWI,Y7BkmGJ,CACF,C6B9lGE,mFAEE,SAAA,CACA,2CACE,CADF,mC7BgmGJ,C6BnmGE,gFAEE,SAAA,CACA,wCACE,CADF,mC7BgmGJ,C6BnmGE,0EAEE,SAAA,CACA,mC7BgmGJ,C6B1lGE,mFAEE,+B7B4lGJ,C6B9lGE,gFAEE,+B7B4lGJ,C6B9lGE,0EAEE,+B7B4lGJ,C6BxlGE,oBACE,yBAAA,CACA,uBAAA,CAGA,yE7BwlGJ,CKz9FI,sCwBrHE,qDACE,uB7BilGN,CACF,C6B5kGE,0CACE,yB7B8kGJ,C6B/kGE,uCACE,yB7B8kGJ,C6B/kGE,iCACE,yB7B8kGJ,C6B1kGE,sBACE,0B7B4kGJ,C8BvoGE,2BACE,a9B0oGJ,CKr9FI,wCyBtLF,2BAKI,e9B0oGJ,CACF,C8BvoGI,6BAEE,0BAAA,CAAA,2BAAA,CACA,eAAA,CACA,iBAAA,CAHA,yBAAA,CAAA,sBAAA,CAAA,iB9B4oGN,C8BtoGM,2CACE,kB9BwoGR,C+BzpGE,kDACE,kCAAA,CAAA,0B/B4pGJ,C+B7pGE,+CACE,0B/B4pGJ,C+B7pGE,yCACE,kCAAA,CAAA,0B/B4pGJ,C+BxpGE,uBACE,4C/B0pGJ,C+BtpGE,uBACE,4C/BwpGJ,C+BppGE,4BACE,qC/BspGJ,C+BnpGI,mCACE,a/BqpGN,C+BjpGI,kCACE,a/BmpGN,C+B9oGE,0BAKE,eAAA,CAJA,aAAA,CACA,YAAA,CAEA,aAAA,CADA,kBAAA,CAAA,mB/BkpGJ,C+B7oGI,uCACE,e/B+oGN,C+B3oGI,sCACE,kB/B6oGN,CgC5rGA,MACE,8LhC+rGF,CgCtrGE,oBACE,iBAAA,CAEA,gBAAA,CADA,ahC0rGJ,CgCtrGI,wCACE,uBhCwrGN,CgCprGI,gCAEE,eAAA,CADA,gBhCurGN,CgChrGM,wCACE,mBhCkrGR,CgC5qGE,8BAGE,oBhCirGJ,CgCprGE,8BAGE,mBhCirGJ,CgCprGE,8BAIE,4BhCgrGJ,CgCprGE,4DAKE,6BhC+qGJ,CgCprGE,8BAKE,4BhC+qGJ,CgCprGE,oBAME,cAAA,CALA,aAAA,CACA,ehCkrGJ,CgC3qGI,kCACE,uCAAA,CACA,oBhC6qGN,CgCzqGI,wCAEE,uCAAA,CADA,YhC4qGN,CgCvqGI,oCAGE,WhCkrGN,CgCrrGI,oCAGE,UhCkrGN,CgCrrGI,0BAME,6BAAA,CAMA,UAAA,CAPA,WAAA,CAEA,yCAAA,CAAA,iCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CARA,iBAAA,CACA,UAAA,CAQA,sBAAA,CACA,yBAAA,CAPA,UhCirGN,CgCtqGM,oCACE,wBhCwqGR,CgCnqGI,4BACE,YhCqqGN,CgChqGI,4CACE,YhCkqGN,CiCpvGE,qDACE,mBAAA,CACA,cAAA,CACA,uBjCuvGJ,CiC1vGE,kDACE,mBAAA,CACA,cAAA,CACA,uBjCuvGJ,CiC1vGE,4CACE,mBAAA,CACA,cAAA,CACA,uBjCuvGJ,CiCpvGI,yDAGE,iBAAA,CADA,eAAA,CADA,ajCwvGN,CiCzvGI,sDAGE,iBAAA,CADA,eAAA,CADA,ajCwvGN,CiCzvGI,gDAGE,iBAAA,CADA,eAAA,CADA,ajCwvGN,CkC9vGE,gCACE,sClCiwGJ,CkClwGE,6BACE,sClCiwGJ,CkClwGE,uBACE,sClCiwGJ,CkC9vGE,cACE,yClCgwGJ,CkCpvGE,4DACE,oClCsvGJ,CkCvvGE,yDACE,oClCsvGJ,CkCvvGE,mDACE,oClCsvGJ,CkC9uGE,6CACE,qClCgvGJ,CkCjvGE,0CACE,qClCgvGJ,CkCjvGE,oCACE,qClCgvGJ,CkCtuGE,oDACE,oClCwuGJ,CkCzuGE,iDACE,oClCwuGJ,CkCzuGE,2CACE,oClCwuGJ,CkC/tGE,gDACE,qClCiuGJ,CkCluGE,6CACE,qClCiuGJ,CkCluGE,uCACE,qClCiuGJ,CkC5tGE,gCACE,kClC8tGJ,CkC/tGE,6BACE,kClC8tGJ,CkC/tGE,uBACE,kClC8tGJ,CkCxtGE,qCACE,sClC0tGJ,CkC3tGE,kCACE,sClC0tGJ,CkC3tGE,4BACE,sClC0tGJ,CkCntGE,yCACE,sClCqtGJ,CkCttGE,sCACE,sClCqtGJ,CkCttGE,gCACE,sClCqtGJ,CkC9sGE,yCACE,qClCgtGJ,CkCjtGE,sCACE,qClCgtGJ,CkCjtGE,gCACE,qClCgtGJ,CkCvsGE,gDACE,qClCysGJ,CkC1sGE,6CACE,qClCysGJ,CkC1sGE,uCACE,qClCysGJ,CkCjsGE,6CACE,sClCmsGJ,CkCpsGE,0CACE,sClCmsGJ,CkCpsGE,oCACE,sClCmsGJ,CkCxrGE,yDACE,qClC0rGJ,CkC3rGE,sDACE,qClC0rGJ,CkC3rGE,gDACE,qClC0rGJ,CkCrrGE,iCAGE,mBAAA,CAFA,gBAAA,CACA,gBlCwrGJ,CkC1rGE,8BAGE,mBAAA,CAFA,gBAAA,CACA,gBlCwrGJ,CkC1rGE,wBAGE,mBAAA,CAFA,gBAAA,CACA,gBlCwrGJ,CkCprGE,eACE,4ClCsrGJ,CkCnrGE,eACE,4ClCqrGJ,CkCjrGE,gBAIE,wCAAA,CAHA,aAAA,CACA,wBAAA,CACA,wBlCorGJ,CkC/qGE,yBAOE,wCAAA,CACA,+DAAA,CACA,4BAAA,CACA,6BAAA,CARA,iBAAA,CAIA,eAAA,CADA,eAAA,CAFA,cAAA,CACA,oCAAA,CAHA,iBlC0rGJ,CkC9qGI,6BACE,YlCgrGN,CkC7qGM,kCACE,wBAAA,CACA,yBlC+qGR,CkCzqGE,iCAWE,wCAAA,CACA,+DAAA,CAFA,uCAAA,CAGA,0BAAA,CAPA,UAAA,CAJA,oBAAA,CAMA,2BAAA,CADA,2BAAA,CAEA,2BAAA,CARA,uBAAA,CAAA,eAAA,CAaA,wBAAA,CAAA,qBAAA,CAAA,oBAAA,CAAA,gBAAA,CATA,SlCkrGJ,CkChqGE,sBACE,iBAAA,CACA,iBlCkqGJ,CkC1pGI,sCACE,gBlC4pGN,CkCxpGI,gDACE,YlC0pGN,CkChpGA,gBACE,iBlCmpGF,CkC/oGE,uCACE,aAAA,CACA,SlCipGJ,CkCnpGE,oCACE,aAAA,CACA,SlCipGJ,CkCnpGE,8BACE,aAAA,CACA,SlCipGJ,CkC5oGE,mBACE,YlC8oGJ,CkCzoGE,oBACE,QlC2oGJ,CkCvoGE,4BACE,WAAA,CACA,SAAA,CACA,elCyoGJ,CkCtoGI,0CACE,YlCwoGN,CkCloGE,yBAIE,wCAAA,CAEA,+BAAA,CADA,4BAAA,CAFA,eAAA,CADA,oDAAA,CAKA,wBAAA,CAAA,qBAAA,CAAA,oBAAA,CAAA,gBlCooGJ,CkChoGE,2BAEE,+DAAA,CADA,2BlCmoGJ,CkC/nGI,+BACE,uCAAA,CACA,gBlCioGN,CkC5nGE,sBACE,MAAA,CACA,WlC8nGJ,CkCznGA,aACE,alC4nGF,CkClnGE,4BAEE,aAAA,CADA,YlCsnGJ,CkClnGI,wDAEE,2BAAA,CADA,wBlCqnGN,CkC/mGE,+BAKE,2CAAA,CAEA,+BAAA,CADA,gCAAA,CADA,sBAAA,CAJA,mBAAA,CAEA,gBAAA,CADA,alCsnGJ,CkC9mGI,qCAEE,UAAA,CACA,UAAA,CAFA,alCknGN,CKnvGI,wC6BgJF,8BACE,iBlCumGF,CkC7lGE,wSAGE,elCmmGJ,CkC/lGE,sCAEE,mBAAA,CACA,eAAA,CADA,oBAAA,CADA,kBAAA,CAAA,mBlCmmGJ,CACF,CD17GI,kDAIE,+BAAA,CACA,8BAAA,CAFA,aAAA,CADA,QAAA,CADA,iBCg8GN,CDj8GI,+CAIE,+BAAA,CACA,8BAAA,CAFA,aAAA,CADA,QAAA,CADA,iBCg8GN,CDj8GI,yCAIE,+BAAA,CACA,8BAAA,CAFA,aAAA,CADA,QAAA,CADA,iBCg8GN,CDx7GI,uBAEE,uCAAA,CADA,cC27GN,CDt4GM,iHAEE,WAlDkB,CAiDlB,kBCi5GR,CDl5GM,6HAEE,WAlDkB,CAiDlB,kBC65GR,CD95GM,6HAEE,WAlDkB,CAiDlB,kBCy6GR,CD16GM,oHAEE,WAlDkB,CAiDlB,kBCq7GR,CDt7GM,0HAEE,WAlDkB,CAiDlB,kBCi8GR,CDl8GM,uHAEE,WAlDkB,CAiDlB,kBC68GR,CD98GM,uHAEE,WAlDkB,CAiDlB,kBCy9GR,CD19GM,6HAEE,WAlDkB,CAiDlB,kBCq+GR,CDt+GM,yCAEE,WAlDkB,CAiDlB,kBCy+GR,CD1+GM,yCAEE,WAlDkB,CAiDlB,kBC6+GR,CD9+GM,0CAEE,WAlDkB,CAiDlB,kBCi/GR,CDl/GM,uCAEE,WAlDkB,CAiDlB,kBCq/GR,CDt/GM,wCAEE,WAlDkB,CAiDlB,kBCy/GR,CD1/GM,sCAEE,WAlDkB,CAiDlB,kBC6/GR,CD9/GM,wCAEE,WAlDkB,CAiDlB,kBCigHR,CDlgHM,oCAEE,WAlDkB,CAiDlB,kBCqgHR,CDtgHM,2CAEE,WAlDkB,CAiDlB,kBCygHR,CD1gHM,qCAEE,WAlDkB,CAiDlB,kBC6gHR,CD9gHM,oCAEE,WAlDkB,CAiDlB,kBCihHR,CDlhHM,kCAEE,WAlDkB,CAiDlB,kBCqhHR,CDthHM,qCAEE,WAlDkB,CAiDlB,kBCyhHR,CD1hHM,mCAEE,WAlDkB,CAiDlB,kBC6hHR,CD9hHM,qCAEE,WAlDkB,CAiDlB,kBCiiHR,CDliHM,wCAEE,WAlDkB,CAiDlB,kBCqiHR,CDtiHM,sCAEE,WAlDkB,CAiDlB,kBCyiHR,CD1iHM,2CAEE,WAlDkB,CAiDlB,kBC6iHR,CDliHM,iCAEE,WAPkB,CAMlB,iBCqiHR,CDtiHM,uCAEE,WAPkB,CAMlB,iBCyiHR,CD1iHM,mCAEE,WAPkB,CAMlB,iBC6iHR,CmC/nHA,MACE,qMAAA,CACA,mMnCkoHF,CmCznHE,wBAKE,mBAAA,CAHA,YAAA,CACA,qBAAA,CACA,YAAA,CAHA,iBnCgoHJ,CmCtnHI,8BAGE,QAAA,CACA,SAAA,CAHA,iBAAA,CACA,OnC0nHN,CmCrnHM,qCACE,0BnCunHR,CmCxlHE,2BAKE,uBAAA,CADA,+DAAA,CAHA,YAAA,CACA,cAAA,CACA,aAAA,CAGA,oBnC0lHJ,CmCvlHI,aATF,2BAUI,gBnC0lHJ,CACF,CmCvlHI,cAGE,+BACE,iBnCulHN,CmCplHM,sCAOE,oCAAA,CALA,QAAA,CAWA,UAAA,CATA,aAAA,CAEA,UAAA,CAHA,MAAA,CAFA,iBAAA,CAOA,2CAAA,CACA,qCACE,CAEF,kDAAA,CAPA,+BnC4lHR,CACF,CmC/kHI,8CACE,YnCilHN,CmC7kHI,iCAQE,qCAAA,CACA,6BAAA,CALA,uCAAA,CAMA,cAAA,CATA,aAAA,CAKA,gBAAA,CADA,eAAA,CAFA,8BAAA,CAWA,+BAAA,CAHA,2CACE,CALF,kBAAA,CALA,UnCylHN,CmC1kHM,aAII,6CACE,OnCykHV,CmC1kHQ,8CACE,OnC4kHV,CmC7kHQ,8CACE,OnC+kHV,CmChlHQ,8CACE,OnCklHV,CmCnlHQ,8CACE,OnCqlHV,CmCtlHQ,8CACE,OnCwlHV,CmCzlHQ,8CACE,OnC2lHV,CmC5lHQ,8CACE,OnC8lHV,CmC/lHQ,8CACE,OnCimHV,CmClmHQ,+CACE,QnComHV,CmCrmHQ,+CACE,QnCumHV,CmCxmHQ,+CACE,QnC0mHV,CmC3mHQ,+CACE,QnC6mHV,CmC9mHQ,+CACE,QnCgnHV,CmCjnHQ,+CACE,QnCmnHV,CmCpnHQ,+CACE,QnCsnHV,CmCvnHQ,+CACE,QnCynHV,CmC1nHQ,+CACE,QnC4nHV,CmC7nHQ,+CACE,QnC+nHV,CmChoHQ,+CACE,QnCkoHV,CACF,CmC7nHM,uCACE,+BnC+nHR,CmCznHE,4BACE,UnC2nHJ,CmCxnHI,aAJF,4BAKI,gBnC2nHJ,CACF,CmCvnHE,0BACE,YnCynHJ,CmCtnHI,aAJF,0BAKI,anCynHJ,CmCrnHM,sCACE,OnCunHR,CmCxnHM,uCACE,OnC0nHR,CmC3nHM,uCACE,OnC6nHR,CmC9nHM,uCACE,OnCgoHR,CmCjoHM,uCACE,OnCmoHR,CmCpoHM,uCACE,OnCsoHR,CmCvoHM,uCACE,OnCyoHR,CmC1oHM,uCACE,OnC4oHR,CmC7oHM,uCACE,OnC+oHR,CmChpHM,wCACE,QnCkpHR,CmCnpHM,wCACE,QnCqpHR,CmCtpHM,wCACE,QnCwpHR,CmCzpHM,wCACE,QnC2pHR,CmC5pHM,wCACE,QnC8pHR,CmC/pHM,wCACE,QnCiqHR,CmClqHM,wCACE,QnCoqHR,CmCrqHM,wCACE,QnCuqHR,CmCxqHM,wCACE,QnC0qHR,CmC3qHM,wCACE,QnC6qHR,CmC9qHM,wCACE,QnCgrHR,CACF,CmC1qHI,+FAEE,QnC4qHN,CmCzqHM,yGACE,wBAAA,CACA,yBnC4qHR,CmCnqHM,2DAEE,wBAAA,CACA,yBAAA,CAFA,QnCuqHR,CmChqHM,iEACE,QnCkqHR,CmC/pHQ,qLAGE,wBAAA,CACA,yBAAA,CAFA,QnCmqHV,CmC7pHQ,6FACE,wBAAA,CACA,yBnC+pHV,CmC1pHM,yDACE,kBnC4pHR,CmCvpHI,sCACE,QnCypHN,CmCppHE,2BAEE,iBAAA,CAKA,kBAAA,CADA,uCAAA,CAEA,cAAA,CAPA,aAAA,CAGA,YAAA,CACA,gBAAA,CAKA,mBAAA,CADA,gCAAA,CANA,WnC6pHJ,CmCnpHI,iCAEE,uDAAA,CADA,+BnCspHN,CmCjpHI,iCAIE,6BAAA,CAOA,UAAA,CAVA,aAAA,CAEA,WAAA,CAKA,8CAAA,CAAA,sCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CALA,+CACE,CAJF,UnC0pHN,CmC5oHE,4BAME,+EACE,CALF,YAAA,CAGA,aAAA,CAFA,qBAAA,CAUA,mBAAA,CAZA,iBAAA,CAWA,wBAAA,CARA,YnCkpHJ,CmCtoHI,sCACE,wBnCwoHN,CmCpoHI,oCACE,SnCsoHN,CmCloHI,kCAGE,8EACE,CAFF,mBAAA,CADA,OnCsoHN,CmC5nHM,uDACE,8CAAA,CAAA,sCnC8nHR,CK7uHI,wC8B6HF,wDAGE,kBnCqnHF,CmCxnHA,wDAGE,mBnCqnHF,CmCxnHA,8CAEE,eAAA,CADA,eAAA,CAGA,iCnConHF,CmChnHE,8DACE,mBnCmnHJ,CmCpnHE,8DACE,kBnCmnHJ,CmCpnHE,oDAEE,UnCknHJ,CmC9mHE,8EAEE,kBnCinHJ,CmCnnHE,8EAEE,mBnCinHJ,CmCnnHE,8EAGE,kBnCgnHJ,CmCnnHE,8EAGE,mBnCgnHJ,CmCnnHE,oEACE,UnCknHJ,CmC5mHE,8EAEE,mBnC+mHJ,CmCjnHE,8EAEE,kBnC+mHJ,CmCjnHE,8EAGE,mBnC8mHJ,CmCjnHE,8EAGE,kBnC8mHJ,CmCjnHE,oEACE,UnCgnHJ,CACF,CmClmHE,cAHF,olDAII,+BnCqmHF,CmClmHE,g8GACE,sCnComHJ,CACF,CmC/lHA,4sDACE,uDnCkmHF,CmC9lHA,wmDACE,anCimHF,CoC78HA,MACE,mVAAA,CAEA,4VpCi9HF,CoCv8HE,4BAEE,oBAAA,CADA,iBpC28HJ,CoCt8HI,sDAGE,SpCw8HN,CoC38HI,sDAGE,UpCw8HN,CoC38HI,4CACE,iBAAA,CACA,SpCy8HN,CoCn8HE,+CAEE,SAAA,CADA,UpCs8HJ,CoCj8HE,kDAGE,WpC08HJ,CoC78HE,kDAGE,YpC08HJ,CoC78HE,wCAME,qDAAA,CAIA,UAAA,CALA,aAAA,CAEA,0CAAA,CAAA,kCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CARA,iBAAA,CACA,SAAA,CAEA,YpCy8HJ,CoC/7HE,gEACE,wBT0Wa,CSzWb,mDAAA,CAAA,2CpCi8HJ,CqCl/HA,QACE,8DAAA,CAGA,+CAAA,CACA,iEAAA,CACA,oDAAA,CACA,sDAAA,CACA,mDrCm/HF,CqC/+HA,SAEE,kBAAA,CADA,YrCm/HF,CK11HI,mCiChKA,8BAIE,kBtC+/HJ,CsCngIE,8BAIE,iBtC+/HJ,CsCngIE,oBACE,UAAA,CAIA,mBAAA,CAFA,YAAA,CADA,atCigIJ,CsC3/HI,8BACE,WtC6/HN,CsCz/HI,kCAEE,iBAAA,CAAA,ctC2/HN,CsC7/HI,kCAEE,aAAA,CAAA,kBtC2/HN,CsC7/HI,wBACE,WtC4/HN,CsCx/HM,kCACE,UtC0/HR,CACF","file":"main.css"} \ No newline at end of file diff --git a/assets/stylesheets/main.a57b2b03.min.css b/assets/stylesheets/main.a57b2b03.min.css new file mode 100644 index 00000000..3e26d6c8 --- /dev/null +++ b/assets/stylesheets/main.a57b2b03.min.css @@ -0,0 +1,2 @@ +@charset "UTF-8";html{-webkit-text-size-adjust:none;-moz-text-size-adjust:none;-ms-text-size-adjust:none;text-size-adjust:none;box-sizing:border-box}*,:after,:before{box-sizing:inherit}body{margin:0}a,button,input,label{-webkit-tap-highlight-color:transparent}a{color:inherit;text-decoration:none}hr{border:0;box-sizing:content-box;display:block;height:.05rem;overflow:visible;padding:0}small{font-size:80%}sub,sup{line-height:1em}img{border-style:none}table{border-collapse:separate;border-spacing:0}td,th{font-weight:400;vertical-align:top}button{background:transparent;border:0;font-family:inherit;font-size:inherit;margin:0;padding:0}input{border:0;outline:none}:root{--md-default-fg-color:rgba(0,0,0,0.87);--md-default-fg-color--light:rgba(0,0,0,0.54);--md-default-fg-color--lighter:rgba(0,0,0,0.32);--md-default-fg-color--lightest:rgba(0,0,0,0.07);--md-default-bg-color:#fff;--md-default-bg-color--light:hsla(0,0%,100%,0.7);--md-default-bg-color--lighter:hsla(0,0%,100%,0.3);--md-default-bg-color--lightest:hsla(0,0%,100%,0.12);--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7);--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}:root>*{--md-code-fg-color:#36464e;--md-code-bg-color:#f5f5f5;--md-code-hl-color:rgba(255,255,0,0.5);--md-code-hl-number-color:#d52a2a;--md-code-hl-special-color:#db1457;--md-code-hl-function-color:#a846b9;--md-code-hl-constant-color:#6e59d9;--md-code-hl-keyword-color:#3f6ec6;--md-code-hl-string-color:#1c7d4d;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-mark-color:rgba(255,255,0,0.5);--md-typeset-del-color:hsla(6,90%,60%,0.15);--md-typeset-ins-color:rgba(11,213,112,0.15);--md-typeset-kbd-color:#fafafa;--md-typeset-kbd-accent-color:#fff;--md-typeset-kbd-border-color:#b8b8b8;--md-typeset-table-color:rgba(0,0,0,0.12);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-footer-fg-color:#fff;--md-footer-fg-color--light:hsla(0,0%,100%,0.7);--md-footer-fg-color--lighter:hsla(0,0%,100%,0.3);--md-footer-bg-color:rgba(0,0,0,0.87);--md-footer-bg-color--dark:rgba(0,0,0,0.32)}.md-icon svg{fill:currentColor;display:block;height:1.2rem;width:1.2rem}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body,input{font-feature-settings:"kern","liga";font-family:var(--md-text-font-family,_),-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif}body,code,input,kbd,pre{color:var(--md-typeset-color)}code,kbd,pre{font-feature-settings:"kern";font-family:var(--md-code-font-family,_),SFMono-Regular,Consolas,Menlo,monospace}:root{--md-typeset-table-sort-icon:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--asc:url('data:image/svg+xml;charset=utf-8,');--md-typeset-table-sort-icon--desc:url('data:image/svg+xml;charset=utf-8,')}.md-typeset{-webkit-print-color-adjust:exact;color-adjust:exact;font-size:.8rem;line-height:1.6}@media print{.md-typeset{font-size:.68rem}}.md-typeset blockquote,.md-typeset dl,.md-typeset figure,.md-typeset ol,.md-typeset pre,.md-typeset ul{margin:1em 0}.md-typeset h1{color:var(--md-default-fg-color--light);font-size:2em;line-height:1.3;margin:0 0 1.25em}.md-typeset h1,.md-typeset h2{font-weight:300;letter-spacing:-.01em}.md-typeset h2{font-size:1.5625em;line-height:1.4;margin:1.6em 0 .64em}.md-typeset h3{font-size:1.25em;font-weight:400;letter-spacing:-.01em;line-height:1.5;margin:1.6em 0 .8em}.md-typeset h2+h3{margin-top:.8em}.md-typeset h4{font-weight:700;letter-spacing:-.01em;margin:1em 0}.md-typeset h5,.md-typeset h6{color:var(--md-default-fg-color--light);font-size:.8em;font-weight:700;letter-spacing:-.01em;margin:1.25em 0}.md-typeset h5{text-transform:uppercase}.md-typeset hr{border-bottom:.05rem solid var(--md-default-fg-color--lightest);display:flow-root;margin:1.5em 0}.md-typeset a{color:var(--md-typeset-a-color);word-break:break-word}.md-typeset a,.md-typeset a:before{transition:color 125ms}.md-typeset a:focus,.md-typeset a:hover{color:var(--md-accent-fg-color)}.md-typeset a.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset code,.md-typeset kbd,.md-typeset pre{color:var(--md-code-fg-color);direction:ltr}@media print{.md-typeset code,.md-typeset kbd,.md-typeset pre{white-space:pre-wrap}}.md-typeset code{background-color:var(--md-code-bg-color);border-radius:.1rem;-webkit-box-decoration-break:clone;box-decoration-break:clone;font-size:.85em;padding:0 .2941176471em;word-break:break-word}.md-typeset code:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset h1 code,.md-typeset h2 code,.md-typeset h3 code,.md-typeset h4 code,.md-typeset h5 code,.md-typeset h6 code{background-color:transparent;box-shadow:none;margin:initial;padding:initial}.md-typeset a code{color:currentColor}.md-typeset pre{display:flow-root;line-height:1.4;position:relative}.md-typeset pre>code{-webkit-box-decoration-break:slice;box-decoration-break:slice;box-shadow:none;display:block;margin:0;overflow:auto;padding:.7720588235em 1.1764705882em;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin;touch-action:auto;word-break:normal}.md-typeset pre>code:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-typeset pre>code::-webkit-scrollbar{height:.2rem;width:.2rem}.md-typeset pre>code::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset pre>code::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@media screen and (max-width:44.9375em){.md-typeset>pre{margin:1em -.8rem}.md-typeset>pre code{border-radius:0}}.md-typeset kbd{background-color:var(--md-typeset-kbd-color);border-radius:.1rem;box-shadow:0 .1rem 0 .05rem var(--md-typeset-kbd-border-color),0 .1rem 0 var(--md-typeset-kbd-border-color),0 -.1rem .2rem var(--md-typeset-kbd-accent-color) inset;color:var(--md-default-fg-color);display:inline-block;font-size:.75em;padding:0 .6666666667em;vertical-align:text-top;word-break:break-word}.md-typeset mark{background-color:var(--md-typeset-mark-color);-webkit-box-decoration-break:clone;box-decoration-break:clone;color:inherit;word-break:break-word}.md-typeset abbr{border-bottom:.05rem dotted var(--md-default-fg-color--light);cursor:help;text-decoration:none}@media (hover:none){.md-typeset abbr{position:relative}.md-typeset abbr[title]:focus:after,.md-typeset abbr[title]:hover:after{background-color:var(--md-default-fg-color);border-radius:.1rem;box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2);color:var(--md-default-bg-color);content:attr(title);display:inline-block;font-size:.7rem;left:0;margin-top:2em;max-width:80%;min-width:-webkit-max-content;min-width:-moz-max-content;min-width:max-content;padding:.2rem .3rem;position:absolute;width:auto}}.md-typeset small{opacity:.75}.md-typeset sub,.md-typeset sup{margin-left:.078125em}[dir=rtl] .md-typeset sub,[dir=rtl] .md-typeset sup{margin-left:0;margin-right:.078125em}.md-typeset blockquote{border-left:.2rem solid var(--md-default-fg-color--lighter);color:var(--md-default-fg-color--light);padding-left:.6rem}[dir=rtl] .md-typeset blockquote{border-left:initial;border-right:.2rem solid var(--md-default-fg-color--lighter);padding-left:0;padding-right:.6rem}.md-typeset ul{list-style-type:disc}.md-typeset ol,.md-typeset ul{display:flow-root;margin-left:.625em;padding:0}[dir=rtl] .md-typeset ol,[dir=rtl] .md-typeset ul{margin-left:0;margin-right:.625em}.md-typeset ol ol,.md-typeset ul ol{list-style-type:lower-alpha}.md-typeset ol ol ol,.md-typeset ul ol ol{list-style-type:lower-roman}.md-typeset ol li,.md-typeset ul li{margin-bottom:.5em;margin-left:1.25em}[dir=rtl] .md-typeset ol li,[dir=rtl] .md-typeset ul li{margin-left:0;margin-right:1.25em}.md-typeset ol li blockquote,.md-typeset ol li p,.md-typeset ul li blockquote,.md-typeset ul li p{margin:.5em 0}.md-typeset ol li:last-child,.md-typeset ul li:last-child{margin-bottom:0}.md-typeset ol li ol,.md-typeset ol li ul,.md-typeset ul li ol,.md-typeset ul li ul{margin:.5em 0 .5em .625em}[dir=rtl] .md-typeset ol li ol,[dir=rtl] .md-typeset ol li ul,[dir=rtl] .md-typeset ul li ol,[dir=rtl] .md-typeset ul li ul{margin-left:0;margin-right:.625em}.md-typeset dd{margin:1em 0 1.5em 1.875em}[dir=rtl] .md-typeset dd{margin-left:0;margin-right:1.875em}.md-typeset img,.md-typeset svg{height:auto;max-width:100%}.md-typeset img[align=left],.md-typeset svg[align=left]{margin:1em 1em 1em 0}.md-typeset img[align=right],.md-typeset svg[align=right]{margin:1em 0 1em 1em}.md-typeset img[align]:only-child,.md-typeset svg[align]:only-child{margin-top:0}.md-typeset figure{display:flow-root;margin:0 auto;max-width:100%;text-align:center;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.md-typeset figure img{display:block}.md-typeset figcaption{font-style:italic;margin:1em auto 2em;max-width:24rem}.md-typeset iframe{max-width:100%}.md-typeset table:not([class]){background-color:var(--md-default-bg-color);border:.05rem solid var(--md-typeset-table-color);border-radius:.1rem;display:inline-block;font-size:.64rem;max-width:100%;overflow:auto;touch-action:auto}@media print{.md-typeset table:not([class]){display:table}}.md-typeset table:not([class])+*{margin-top:1.5em}.md-typeset table:not([class]) td>:first-child,.md-typeset table:not([class]) th>:first-child{margin-top:0}.md-typeset table:not([class]) td>:last-child,.md-typeset table:not([class]) th>:last-child{margin-bottom:0}.md-typeset table:not([class]) td:not([align]),.md-typeset table:not([class]) th:not([align]){text-align:left}[dir=rtl] .md-typeset table:not([class]) td:not([align]),[dir=rtl] .md-typeset table:not([class]) th:not([align]){text-align:right}.md-typeset table:not([class]) th{font-weight:700;min-width:5rem;padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) th a{color:inherit}.md-typeset table:not([class]) td{border-top:.05rem solid var(--md-typeset-table-color);padding:.9375em 1.25em;vertical-align:top}.md-typeset table:not([class]) tbody tr{transition:background-color 125ms}.md-typeset table:not([class]) tbody tr:hover{background-color:rgba(0,0,0,.035);box-shadow:0 .05rem 0 var(--md-default-bg-color) inset}.md-typeset table:not([class]) a{word-break:normal}.md-typeset table th[role=columnheader]{cursor:pointer}.md-typeset table th[role=columnheader]:after{content:"";display:inline-block;height:1.2em;margin-left:.5em;-webkit-mask-image:var(--md-typeset-table-sort-icon);mask-image:var(--md-typeset-table-sort-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;transition:background-color 125ms;vertical-align:text-bottom;width:1.2em}.md-typeset table th[role=columnheader]:hover:after{background-color:var(--md-default-fg-color--lighter)}.md-typeset table th[role=columnheader][aria-sort=ascending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--asc);mask-image:var(--md-typeset-table-sort-icon--asc)}.md-typeset table th[role=columnheader][aria-sort=descending]:after{background-color:var(--md-default-fg-color--light);-webkit-mask-image:var(--md-typeset-table-sort-icon--desc);mask-image:var(--md-typeset-table-sort-icon--desc)}.md-typeset__scrollwrap{margin:1em -.8rem;overflow-x:auto;touch-action:auto}.md-typeset__table{display:inline-block;margin-bottom:.5em;padding:0 .8rem}@media print{.md-typeset__table{display:block}}html .md-typeset__table table{display:table;margin:0;overflow:hidden;width:100%}html{font-size:125%;height:100%;overflow-x:hidden}@media screen and (min-width:100em){html{font-size:137.5%}}@media screen and (min-width:125em){html{font-size:150%}}body{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;font-size:.5rem;min-height:100%;position:relative;width:100%}@media print{body{display:block}}@media screen and (max-width:59.9375em){body[data-md-state=lock]{position:fixed}}.md-grid{margin-left:auto;margin-right:auto;max-width:61rem}.md-container{display:flex;flex-direction:column;flex-grow:1}@media print{.md-container{display:block}}.md-main{flex-grow:1}.md-main__inner{display:flex;height:100%;margin-top:1.5rem}.md-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.md-toggle{display:none}.md-option{height:0;opacity:0;position:absolute;width:0}.md-option:checked+label:not([hidden]){display:block}.md-option.focus-visible+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-skip{background-color:var(--md-default-fg-color);border-radius:.1rem;color:var(--md-default-bg-color);font-size:.64rem;margin:.5rem;opacity:0;outline-color:var(--md-accent-fg-color);padding:.3rem .5rem;position:fixed;transform:translateY(.4rem);z-index:-1}.md-skip:focus{opacity:1;transform:translateY(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 175ms 75ms;z-index:10}@page{margin:25mm}.md-announce{background-color:var(--md-footer-bg-color);overflow:auto}@media print{.md-announce{display:none}}.md-announce__inner{color:var(--md-footer-fg-color);font-size:.7rem;margin:.6rem auto;padding:0 .8rem}:root{--md-clipboard-icon:url('data:image/svg+xml;charset=utf-8,')}.md-clipboard{border-radius:.1rem;color:var(--md-default-fg-color--lightest);cursor:pointer;height:1.5em;outline-color:var(--md-accent-fg-color);outline-offset:.1rem;position:absolute;right:.5em;top:.5em;transition:color .25s;width:1.5em;z-index:1}@media print{.md-clipboard{display:none}}.md-clipboard:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}:hover>.md-clipboard{color:var(--md-default-fg-color--light)}.md-clipboard:focus,.md-clipboard:hover{color:var(--md-accent-fg-color)}.md-clipboard:after{background-color:currentColor;content:"";display:block;height:1.125em;margin:0 auto;-webkit-mask-image:var(--md-clipboard-icon);mask-image:var(--md-clipboard-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:1.125em}.md-clipboard--inline{cursor:pointer}.md-clipboard--inline code{transition:color .25s,background-color .25s}.md-clipboard--inline:focus code,.md-clipboard--inline:hover code{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-content{flex-grow:1;overflow:hidden;scroll-padding-top:51.2rem}.md-content__inner{margin:0 .8rem 1.2rem;padding-top:.6rem}@media screen and (min-width:76.25em){[dir=ltr] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}[dir=rtl] .md-sidebar--primary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=ltr] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-right:1.2rem}[dir=rtl] .md-sidebar--secondary:not([hidden])~.md-content>.md-content__inner{margin-left:1.2rem}}.md-content__inner:before{content:"";display:block;height:.4rem}.md-content__inner>:last-child{margin-bottom:0}.md-content__button{float:right;margin:.4rem 0 .4rem .4rem;padding:0}@media print{.md-content__button{display:none}}[dir=rtl] .md-content__button{float:left;margin-left:0;margin-right:.4rem}[dir=rtl] .md-content__button svg{transform:scaleX(-1)}.md-typeset .md-content__button{color:var(--md-default-fg-color--lighter)}.md-content__button svg{display:inline;vertical-align:top}.md-dialog{background-color:var(--md-default-fg-color);border-radius:.1rem;bottom:.8rem;box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12),0 3px 1px -2px rgba(0,0,0,.2);left:auto;min-width:11.1rem;opacity:0;padding:.4rem .6rem;pointer-events:none;position:fixed;right:.8rem;transform:translateY(100%);transition:transform 0ms .4s,opacity .4s;z-index:3}@media print{.md-dialog{display:none}}[dir=rtl] .md-dialog{left:.8rem;right:auto}.md-dialog[data-md-state=open]{opacity:1;pointer-events:auto;transform:translateY(0);transition:transform .4s cubic-bezier(.075,.85,.175,1),opacity .4s}.md-dialog__inner{color:var(--md-default-bg-color);font-size:.7rem}.md-typeset .md-button{border:.1rem solid;border-radius:.1rem;color:var(--md-primary-fg-color);cursor:pointer;display:inline-block;font-weight:700;padding:.625em 2em;transition:color 125ms,background-color 125ms,border-color 125ms}.md-typeset .md-button--primary{background-color:var(--md-primary-fg-color);border-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-typeset .md-button:focus,.md-typeset .md-button:hover{background-color:var(--md-accent-fg-color);border-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-typeset .md-input{border-radius:.1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.1),0 .025rem .05rem rgba(0,0,0,.1);font-size:.8rem;height:1.8rem;padding:0 .6rem;transition:box-shadow .25s}.md-typeset .md-input:focus,.md-typeset .md-input:hover{box-shadow:0 .4rem 1rem rgba(0,0,0,.15),0 .025rem .05rem rgba(0,0,0,.15)}.md-typeset .md-input--stretch{width:100%}.md-header{background-color:var(--md-primary-fg-color);box-shadow:0 0 .2rem transparent,0 .2rem .4rem transparent;color:var(--md-primary-bg-color);left:0;position:-webkit-sticky;position:sticky;right:0;top:0;z-index:3}@media print{.md-header{display:none}}.md-header[data-md-state=shadow]{box-shadow:0 0 .2rem rgba(0,0,0,.1),0 .2rem .4rem rgba(0,0,0,.2);transition:transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s}.md-header[data-md-state=hidden]{transform:translateY(-100%);transition:transform .25s cubic-bezier(.8,0,.6,1),box-shadow .25s}.md-header__inner{align-items:center;display:flex;padding:0 .2rem}.md-header__button{color:currentColor;cursor:pointer;margin:.2rem;outline-color:var(--md-accent-fg-color);padding:.4rem;position:relative;transition:opacity .25s;vertical-align:middle;z-index:1}.md-header__button:hover{opacity:.7}.md-header__button:not([hidden]){display:inline-block}.md-header__button:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-header__button.md-logo{margin:.2rem;padding:.4rem}@media screen and (max-width:76.1875em){.md-header__button.md-logo{display:none}}.md-header__button.md-logo img,.md-header__button.md-logo svg{fill:currentColor;display:block;height:1.2rem;width:1.2rem}@media screen and (min-width:60em){.md-header__button[for=__search]{display:none}}.no-js .md-header__button[for=__search]{display:none}[dir=rtl] .md-header__button[for=__search] svg{transform:scaleX(-1)}@media screen and (min-width:76.25em){.md-header__button[for=__drawer]{display:none}}.md-header__topic{display:flex;max-width:100%;position:absolute;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-header__topic+.md-header__topic{opacity:0;pointer-events:none;transform:translateX(1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__topic+.md-header__topic{transform:translateX(-1.25rem)}.md-header__title{flex-grow:1;font-size:.9rem;height:2.4rem;line-height:2.4rem;margin-left:1rem;margin-right:.4rem}.md-header__title[data-md-state=active] .md-header__topic{opacity:0;pointer-events:none;transform:translateX(-1.25rem);transition:transform .4s cubic-bezier(1,.7,.1,.1),opacity .15s;z-index:-1}[dir=rtl] .md-header__title[data-md-state=active] .md-header__topic{transform:translateX(1.25rem)}.md-header__title[data-md-state=active] .md-header__topic+.md-header__topic{opacity:1;pointer-events:auto;transform:translateX(0);transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .15s;z-index:0}.md-header__title>.md-header__ellipsis{height:100%;position:relative;width:100%}.md-header__option{display:flex;flex-shrink:0;max-width:100%;transition:max-width 0ms .25s,opacity .25s .25s;white-space:nowrap}[data-md-toggle=search]:checked~.md-header .md-header__option{max-width:0;opacity:0;transition:max-width 0ms,opacity 0ms}.md-header__source{display:none}@media screen and (min-width:60em){.md-header__source{display:block;margin-left:1rem;max-width:11.7rem;width:11.7rem}[dir=rtl] .md-header__source{margin-left:0;margin-right:1rem}}@media screen and (min-width:76.25em){.md-header__source{margin-left:1.4rem}[dir=rtl] .md-header__source{margin-right:1.4rem}}.md-footer{background-color:var(--md-footer-bg-color);color:var(--md-footer-fg-color)}@media print{.md-footer{display:none}}.md-footer__inner{overflow:auto;padding:.2rem}.md-footer__link{display:flex;outline-color:var(--md-accent-fg-color);padding-bottom:.4rem;padding-top:1.4rem;transition:opacity .25s}@media screen and (min-width:45em){.md-footer__link{width:50%}}.md-footer__link:focus,.md-footer__link:hover{opacity:.7}.md-footer__link--prev{float:left}@media screen and (max-width:44.9375em){.md-footer__link--prev{width:25%}.md-footer__link--prev .md-footer__title{display:none}}[dir=rtl] .md-footer__link--prev{float:right}[dir=rtl] .md-footer__link--prev svg{transform:scaleX(-1)}.md-footer__link--next{float:right;text-align:right}@media screen and (max-width:44.9375em){.md-footer__link--next{width:75%}}[dir=rtl] .md-footer__link--next{float:left;text-align:left}[dir=rtl] .md-footer__link--next svg{transform:scaleX(-1)}.md-footer__title{flex-grow:1;font-size:.9rem;line-height:2.4rem;max-width:calc(100% - 2.4rem);padding:0 1rem;position:relative}.md-footer__button{margin:.2rem;padding:.4rem}.md-footer__direction{font-size:.64rem;left:0;margin-top:-1rem;opacity:.7;padding:0 1rem;position:absolute;right:0}.md-footer-meta{background-color:var(--md-footer-bg-color--dark)}.md-footer-meta__inner{display:flex;flex-wrap:wrap;justify-content:space-between;padding:.2rem}html .md-footer-meta.md-typeset a{color:var(--md-footer-fg-color--light)}html .md-footer-meta.md-typeset a:focus,html .md-footer-meta.md-typeset a:hover{color:var(--md-footer-fg-color)}.md-footer-copyright{color:var(--md-footer-fg-color--lighter);font-size:.64rem;margin:auto .6rem;padding:.4rem 0;width:100%}@media screen and (min-width:45em){.md-footer-copyright{width:auto}}.md-footer-copyright__highlight{color:var(--md-footer-fg-color--light)}.md-footer-social{margin:0 .4rem;padding:.2rem 0 .6rem}@media screen and (min-width:45em){.md-footer-social{padding:.6rem 0}}.md-footer-social__link{display:inline-block;height:1.6rem;text-align:center;width:1.6rem}.md-footer-social__link:before{line-height:1.9}.md-footer-social__link svg{fill:currentColor;max-height:.8rem;vertical-align:-25%}:root{--md-nav-icon--prev:url('data:image/svg+xml;charset=utf-8,');--md-nav-icon--next:url('data:image/svg+xml;charset=utf-8,');--md-toc-icon:url('data:image/svg+xml;charset=utf-8,')}.md-nav{font-size:.7rem;line-height:1.3}.md-nav__title{display:block;font-weight:700;overflow:hidden;padding:0 .6rem;text-overflow:ellipsis}.md-nav__title .md-nav__button{display:none}.md-nav__title .md-nav__button img{height:100%;width:auto}.md-nav__title .md-nav__button.md-logo img,.md-nav__title .md-nav__button.md-logo svg{fill:currentColor;display:block;height:2.4rem;width:2.4rem}.md-nav__list{list-style:none;margin:0;padding:0}.md-nav__item{padding:0 .6rem}.md-nav__item .md-nav__item{padding-right:0}[dir=rtl] .md-nav__item .md-nav__item{padding-left:0;padding-right:.6rem}.md-nav__link{align-items:center;cursor:pointer;display:flex;justify-content:space-between;margin-top:.625em;overflow:hidden;scroll-snap-align:start;text-overflow:ellipsis;transition:color 125ms}.md-nav__link[data-md-state=blur]{color:var(--md-default-fg-color--light)}.md-nav__item .md-nav__link--active{color:var(--md-typeset-a-color)}.md-nav__item .md-nav__link--index [href]{width:100%}.md-nav__link:focus,.md-nav__link:hover{color:var(--md-accent-fg-color)}.md-nav__link.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-nav--primary .md-nav__link[for=__toc]{display:none}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{background-color:currentColor;display:block;height:100%;-webkit-mask-image:var(--md-toc-icon);mask-image:var(--md-toc-icon);width:100%}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:none}.md-nav__link>*{cursor:pointer;display:flex}.md-nav__source{display:none}@media screen and (max-width:76.1875em){.md-nav--primary,.md-nav--primary .md-nav{background-color:var(--md-default-bg-color);display:flex;flex-direction:column;height:100%;left:0;position:absolute;right:0;top:0;z-index:1}.md-nav--primary .md-nav__item,.md-nav--primary .md-nav__title{font-size:.8rem;line-height:1.5}.md-nav--primary .md-nav__title{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);cursor:pointer;font-weight:400;height:5.6rem;line-height:2.4rem;padding:3rem .8rem .2rem;position:relative;white-space:nowrap}.md-nav--primary .md-nav__title .md-nav__icon{display:block;height:1.2rem;left:.4rem;margin:.2rem;position:absolute;top:.4rem;width:1.2rem}[dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon{left:auto;right:.4rem}.md-nav--primary .md-nav__title .md-nav__icon:after{background-color:currentColor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--prev);mask-image:var(--md-nav-icon--prev);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}.md-nav--primary .md-nav__title~.md-nav__list{background-color:var(--md-default-bg-color);box-shadow:0 .05rem 0 var(--md-default-fg-color--lightest) inset;overflow-y:auto;-ms-scroll-snap-type:y mandatory;scroll-snap-type:y mandatory;touch-action:pan-y}.md-nav--primary .md-nav__title~.md-nav__list>:first-child{border-top:0}.md-nav--primary .md-nav__title[for=__drawer]{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color)}.md-nav--primary .md-nav__title .md-logo{display:block;left:.2rem;margin:.2rem;padding:.4rem;position:absolute;top:.2rem}[dir=rtl] .md-nav--primary .md-nav__title .md-logo{left:auto;right:.2rem}.md-nav--primary .md-nav__list{flex:1}.md-nav--primary .md-nav__item{border-top:.05rem solid var(--md-default-fg-color--lightest);padding:0}.md-nav--primary .md-nav__item--active>.md-nav__link{color:var(--md-typeset-a-color)}.md-nav--primary .md-nav__item--active>.md-nav__link:focus,.md-nav--primary .md-nav__item--active>.md-nav__link:hover{color:var(--md-accent-fg-color)}.md-nav--primary .md-nav__link{margin-top:0;padding:.6rem .8rem}.md-nav--primary .md-nav__link .md-nav__icon{flex-shrink:0;font-size:1.2rem;height:1.2rem;margin-right:-.2rem;width:1.2rem}[dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon{margin-left:-.2rem;margin-right:0}.md-nav--primary .md-nav__link .md-nav__icon:after{background-color:currentColor;content:"";display:block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-nav--primary .md-nav__icon:after{transform:scale(-1)}.md-nav--primary .md-nav--secondary .md-nav{background-color:transparent;position:static}.md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:1.4rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link{padding-left:0;padding-right:1.4rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link{padding-left:0;padding-right:2rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:2.6rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link{padding-left:0;padding-right:2.6rem}.md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:3.2rem}[dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link{padding-left:0;padding-right:3.2rem}.md-nav--secondary{background-color:transparent}.md-nav__toggle~.md-nav{display:flex;opacity:0;transform:translateX(100%);transition:transform .25s cubic-bezier(.8,0,.6,1),opacity 125ms 50ms}[dir=rtl] .md-nav__toggle~.md-nav{transform:translateX(-100%)}.md-nav__toggle:checked~.md-nav{opacity:1;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),opacity 125ms 125ms}.md-nav__toggle:checked~.md-nav>.md-nav__list{-webkit-backface-visibility:hidden;backface-visibility:hidden}}@media screen and (max-width:59.9375em){.md-nav--primary .md-nav__link[for=__toc]{display:flex}.md-nav--primary .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--primary .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--primary .md-nav__link[for=__toc]~.md-nav{display:flex}.md-nav__source{background-color:var(--md-primary-fg-color--dark);color:var(--md-primary-bg-color);display:block;padding:0 .2rem}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-nav--integrated .md-nav__link[for=__toc]{display:flex}.md-nav--integrated .md-nav__link[for=__toc] .md-icon:after{content:""}.md-nav--integrated .md-nav__link[for=__toc]+.md-nav__link{display:none}.md-nav--integrated .md-nav__link[for=__toc]~.md-nav{display:flex}}@media screen and (min-width:60em){.md-nav--secondary .md-nav__title[for=__toc]{scroll-snap-align:start}.md-nav--secondary .md-nav__title .md-nav__icon{display:none}}@media screen and (min-width:76.25em){.md-nav{transition:max-height .25s cubic-bezier(.86,0,.07,1)}.md-nav--primary .md-nav__title[for=__drawer]{scroll-snap-align:start}.md-nav--primary .md-nav__title .md-nav__icon{display:none}.md-nav__toggle~.md-nav{display:none}.md-nav__toggle:checked~.md-nav,.md-nav__toggle:indeterminate~.md-nav{display:block}.md-nav__item--nested>.md-nav>.md-nav__title{display:none}.md-nav__item--section{display:block;margin:1.25em 0}.md-nav__item--section:last-child{margin-bottom:0}.md-nav__item--section>.md-nav__link{font-weight:700;pointer-events:none}.md-nav__item--section>.md-nav__link--index [href]{pointer-events:auto}.md-nav__item--section>.md-nav__link .md-nav__icon{display:none}.md-nav__item--section>.md-nav{display:block}.md-nav__item--section>.md-nav>.md-nav__list>.md-nav__item{padding:0}.md-nav__icon{float:right;height:.9rem;transition:transform .25s;width:.9rem}[dir=rtl] .md-nav__icon{float:left;transform:rotate(180deg)}.md-nav__icon:after{background-color:currentColor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-nav-icon--next);mask-image:var(--md-nav-icon--next);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:-.1rem;width:100%}.md-nav__item--nested .md-nav__toggle:checked~.md-nav__link .md-nav__icon,.md-nav__item--nested .md-nav__toggle:indeterminate~.md-nav__link .md-nav__icon{transform:rotate(90deg)}.md-nav--lifted>.md-nav__list>.md-nav__item--nested,.md-nav--lifted>.md-nav__title{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item{display:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active{display:block;padding:0}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link{font-weight:700;margin-top:0;padding:0 .6rem;pointer-events:none}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link--index [href]{pointer-events:auto}.md-nav--lifted>.md-nav__list>.md-nav__item--active>.md-nav__link .md-nav__icon{display:none}.md-nav--lifted .md-nav[data-md-level="1"]{display:block}.md-nav--lifted .md-nav[data-md-level="1"]>.md-nav__list>.md-nav__item{padding-right:.6rem}.md-nav--integrated>.md-nav__list>.md-nav__item--active:not(.md-nav__item--nested){padding:0 .6rem}.md-nav--integrated>.md-nav__list>.md-nav__item--active:not(.md-nav__item--nested)>.md-nav__link{padding:0}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary{border-left:.05rem solid var(--md-primary-fg-color);display:block;margin-bottom:1.25em}.md-nav--integrated>.md-nav__list>.md-nav__item--active .md-nav--secondary>.md-nav__title{display:none}}:root{--md-search-result-icon:url('data:image/svg+xml;charset=utf-8,')}.md-search{position:relative}@media screen and (min-width:60em){.md-search{padding:.2rem 0}}.no-js .md-search{display:none}.md-search__overlay{opacity:0;z-index:1}@media screen and (max-width:59.9375em){.md-search__overlay{background-color:var(--md-default-bg-color);border-radius:1rem;height:2rem;left:-2.2rem;overflow:hidden;pointer-events:none;position:absolute;top:-1rem;transform-origin:center;transition:transform .3s .1s,opacity .2s .2s;width:2rem}[dir=rtl] .md-search__overlay{left:auto;right:-2.2rem}[data-md-toggle=search]:checked~.md-header .md-search__overlay{opacity:1;transition:transform .4s,opacity .1s}}@media screen and (min-width:60em){.md-search__overlay{background-color:rgba(0,0,0,.54);cursor:pointer;height:0;left:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0}[dir=rtl] .md-search__overlay{left:auto;right:0}[data-md-toggle=search]:checked~.md-header .md-search__overlay{height:200vh;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@media screen and (max-width:29.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(45)}}@media screen and (min-width:30em) and (max-width:44.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(60)}}@media screen and (min-width:45em) and (max-width:59.9375em){[data-md-toggle=search]:checked~.md-header .md-search__overlay{transform:scale(75)}}.md-search__inner{-webkit-backface-visibility:hidden;backface-visibility:hidden}@media screen and (max-width:59.9375em){.md-search__inner{height:0;left:0;opacity:0;overflow:hidden;position:fixed;top:0;transform:translateX(5%);transition:width 0ms .3s,height 0ms .3s,transform .15s cubic-bezier(.4,0,.2,1) .15s,opacity .15s .15s;width:0;z-index:2}[dir=rtl] .md-search__inner{left:auto;right:0;transform:translateX(-5%)}[data-md-toggle=search]:checked~.md-header .md-search__inner{height:100%;opacity:1;transform:translateX(0);transition:width 0ms 0ms,height 0ms 0ms,transform .15s cubic-bezier(.1,.7,.1,1) .15s,opacity .15s .15s;width:100%}}@media screen and (min-width:60em){.md-search__inner{float:right;padding:.1rem 0;position:relative;transition:width .25s cubic-bezier(.1,.7,.1,1);width:11.7rem}[dir=rtl] .md-search__inner{float:left}}@media screen and (min-width:60em) and (max-width:76.1875em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:23.4rem}}@media screen and (min-width:76.25em){[data-md-toggle=search]:checked~.md-header .md-search__inner{width:34.4rem}}.md-search__form{background-color:var(--md-default-bg-color);box-shadow:0 0 .6rem transparent;height:2.4rem;position:relative;transition:color .25s,background-color .25s;z-index:2}@media screen and (min-width:60em){.md-search__form{background-color:rgba(0,0,0,.26);border-radius:.1rem;height:1.8rem}.md-search__form:hover{background-color:hsla(0,0%,100%,.12)}}[data-md-toggle=search]:checked~.md-header .md-search__form{background-color:var(--md-default-bg-color);border-radius:.1rem .1rem 0 0;box-shadow:0 0 .6rem rgba(0,0,0,.07);color:var(--md-default-fg-color)}.md-search__input{background:transparent;font-size:.9rem;height:100%;padding:0 2.2rem 0 3.6rem;position:relative;text-overflow:ellipsis;width:100%;z-index:2}[dir=rtl] .md-search__input{padding:0 3.6rem 0 2.2rem}.md-search__input::-webkit-input-placeholder{-webkit-transition:color .25s;transition:color .25s}.md-search__input::-moz-placeholder{-moz-transition:color .25s;transition:color .25s}.md-search__input::-ms-input-placeholder{-ms-transition:color .25s;transition:color .25s}.md-search__input::placeholder{transition:color .25s}.md-search__input::-webkit-input-placeholder{color:var(--md-default-fg-color--light)}.md-search__input::-moz-placeholder{color:var(--md-default-fg-color--light)}.md-search__input::-ms-input-placeholder{color:var(--md-default-fg-color--light)}.md-search__input::placeholder,.md-search__input~.md-search__icon{color:var(--md-default-fg-color--light)}.md-search__input::-ms-clear{display:none}@media screen and (max-width:59.9375em){.md-search__input{font-size:.9rem;height:2.4rem;width:100%}}@media screen and (min-width:60em){.md-search__input{color:inherit;font-size:.8rem;padding-left:2.2rem}[dir=rtl] .md-search__input{padding-right:2.2rem}.md-search__input::-webkit-input-placeholder{color:var(--md-primary-bg-color--light)}.md-search__input::-moz-placeholder{color:var(--md-primary-bg-color--light)}.md-search__input::-ms-input-placeholder{color:var(--md-primary-bg-color--light)}.md-search__input::placeholder{color:var(--md-primary-bg-color--light)}.md-search__input+.md-search__icon{color:var(--md-primary-bg-color)}[data-md-toggle=search]:checked~.md-header .md-search__input{text-overflow:clip}[data-md-toggle=search]:checked~.md-header .md-search__input::-webkit-input-placeholder{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input::-moz-placeholder{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input::-ms-input-placeholder{color:var(--md-default-fg-color--light)}[data-md-toggle=search]:checked~.md-header .md-search__input+.md-search__icon,[data-md-toggle=search]:checked~.md-header .md-search__input::placeholder{color:var(--md-default-fg-color--light)}}.md-search__icon{cursor:pointer;display:inline-block;height:1.2rem;transition:color .25s,opacity .25s;width:1.2rem}.md-search__icon:hover{opacity:.7}.md-search__icon[for=__search]{left:.5rem;position:absolute;top:.3rem;z-index:2}[dir=rtl] .md-search__icon[for=__search]{left:auto;right:.5rem}[dir=rtl] .md-search__icon[for=__search] svg{transform:scaleX(-1)}@media screen and (max-width:59.9375em){.md-search__icon[for=__search]{left:.8rem;top:.6rem}[dir=rtl] .md-search__icon[for=__search]{left:auto;right:.8rem}.md-search__icon[for=__search] svg:first-child{display:none}}@media screen and (min-width:60em){.md-search__icon[for=__search]{pointer-events:none}.md-search__icon[for=__search] svg:last-child{display:none}}.md-search__options{pointer-events:none;position:absolute;right:.5rem;top:.3rem;z-index:2}[dir=rtl] .md-search__options{left:.5rem;right:auto}@media screen and (max-width:59.9375em){.md-search__options{right:.8rem;top:.6rem}[dir=rtl] .md-search__options{left:.8rem;right:auto}}.md-search__options>*{color:var(--md-default-fg-color--light);margin-left:.2rem;opacity:0;transform:scale(.75);transition:transform .15s cubic-bezier(.1,.7,.1,1),opacity .15s}.md-search__options>:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>*{opacity:1;pointer-events:auto;transform:scale(1)}[data-md-toggle=search]:checked~.md-header .md-search__input:valid~.md-search__options>:hover{opacity:.7}.md-search__suggest{align-items:center;color:var(--md-default-fg-color--lighter);display:flex;font-size:.9rem;height:100%;opacity:0;padding:0 2.2rem 0 3.6rem;position:absolute;top:0;transition:opacity 50ms;white-space:nowrap;width:100%}[dir=rtl] .md-search__suggest{padding:0 3.6rem 0 2.2rem}@media screen and (min-width:60em){.md-search__suggest{font-size:.8rem;padding-left:2.2rem}[dir=rtl] .md-search__suggest{padding-right:2.2rem}}[data-md-toggle=search]:checked~.md-header .md-search__suggest{opacity:1;transition:opacity .3s .1s}.md-search__output{border-radius:0 0 .1rem .1rem;overflow:hidden;position:absolute;width:100%;z-index:1}@media screen and (max-width:59.9375em){.md-search__output{bottom:0;top:2.4rem}}@media screen and (min-width:60em){.md-search__output{opacity:0;top:1.9rem;transition:opacity .4s}[data-md-toggle=search]:checked~.md-header .md-search__output{box-shadow:0 6px 10px 0 rgba(0,0,0,.14),0 1px 18px 0 rgba(0,0,0,.12),0 3px 5px -1px rgba(0,0,0,.4);opacity:1}}.md-search__scrollwrap{-webkit-backface-visibility:hidden;backface-visibility:hidden;background-color:var(--md-default-bg-color);height:100%;overflow-y:auto;touch-action:pan-y}@media (-webkit-max-device-pixel-ratio:1),(max-resolution:1dppx){.md-search__scrollwrap{transform:translateZ(0)}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-search__scrollwrap{width:23.4rem}}@media screen and (min-width:76.25em){.md-search__scrollwrap{width:34.4rem}}@media screen and (min-width:60em){.md-search__scrollwrap{max-height:0;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}[data-md-toggle=search]:checked~.md-header .md-search__scrollwrap{max-height:75vh}.md-search__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-search__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-search__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-search__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}}.md-search-result{color:var(--md-default-fg-color);word-break:break-word}.md-search-result__meta{background-color:var(--md-default-fg-color--lightest);color:var(--md-default-fg-color--light);font-size:.64rem;line-height:1.8rem;padding:0 .8rem;scroll-snap-align:start}@media screen and (min-width:60em){.md-search-result__meta{padding-left:2.2rem}[dir=rtl] .md-search-result__meta{padding-left:0;padding-right:2.2rem}}.md-search-result__list{list-style:none;margin:0;padding:0}.md-search-result__item{box-shadow:0 -.05rem 0 var(--md-default-fg-color--lightest)}.md-search-result__item:first-child{box-shadow:none}.md-search-result__link{display:block;outline:none;scroll-snap-align:start;transition:background-color .25s}.md-search-result__link:focus,.md-search-result__link:hover{background-color:var(--md-accent-fg-color--transparent)}.md-search-result__link:last-child p:last-child{margin-bottom:.6rem}.md-search-result__more summary{color:var(--md-typeset-a-color);cursor:pointer;display:block;font-size:.64rem;outline:none;padding:.75em .8rem;scroll-snap-align:start;transition:color .25s,background-color .25s}@media screen and (min-width:60em){.md-search-result__more summary{padding-left:2.2rem}[dir=rtl] .md-search-result__more summary{padding-left:.8rem;padding-right:2.2rem}}.md-search-result__more summary:focus,.md-search-result__more summary:hover{background-color:var(--md-accent-fg-color--transparent);color:var(--md-accent-fg-color)}.md-search-result__more summary::-webkit-details-marker,.md-search-result__more summary::marker{display:none}.md-search-result__more summary~*>*{opacity:.65}.md-search-result__article{overflow:hidden;padding:0 .8rem;position:relative}@media screen and (min-width:60em){.md-search-result__article{padding-left:2.2rem}[dir=rtl] .md-search-result__article{padding-left:.8rem;padding-right:2.2rem}}.md-search-result__article--document .md-search-result__title{font-size:.8rem;font-weight:400;line-height:1.4;margin:.55rem 0}.md-search-result__icon{color:var(--md-default-fg-color--light);height:1.2rem;left:0;margin:.5rem;position:absolute;width:1.2rem}@media screen and (max-width:59.9375em){.md-search-result__icon{display:none}}.md-search-result__icon:after{background-color:currentColor;content:"";display:inline-block;height:100%;-webkit-mask-image:var(--md-search-result-icon);mask-image:var(--md-search-result-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:100%}[dir=rtl] .md-search-result__icon{left:auto;right:0}[dir=rtl] .md-search-result__icon:after{transform:scaleX(-1)}.md-search-result__title{font-size:.64rem;font-weight:700;line-height:1.6;margin:.5em 0}.md-search-result__teaser{-webkit-box-orient:vertical;-webkit-line-clamp:2;color:var(--md-default-fg-color--light);display:-webkit-box;font-size:.64rem;line-height:1.6;margin:.5em 0;max-height:2rem;overflow:hidden;text-overflow:ellipsis}@media screen and (max-width:44.9375em){.md-search-result__teaser{-webkit-line-clamp:3;max-height:3rem}}@media screen and (min-width:60em) and (max-width:76.1875em){.md-search-result__teaser{-webkit-line-clamp:3;max-height:3rem}}.md-search-result__teaser mark{background-color:transparent;text-decoration:underline}.md-search-result__terms{font-size:.64rem;font-style:italic;margin:.5em 0}.md-search-result mark{background-color:transparent;color:var(--md-accent-fg-color)}.md-select{position:relative;z-index:1}.md-select__inner{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.1),0 0 .05rem rgba(0,0,0,.25);color:var(--md-default-fg-color);left:50%;margin-top:.2rem;max-height:0;opacity:0;position:absolute;top:calc(100% - .2rem);transform:translate3d(-50%,.3rem,0);transition:transform .25s 375ms,opacity .25s .25s,max-height 0ms .5s}.md-select:focus-within .md-select__inner,.md-select:hover .md-select__inner{max-height:10rem;opacity:1;transform:translate3d(-50%,0,0);transition:transform .25s cubic-bezier(.1,.7,.1,1),opacity .25s,max-height 0ms}.md-select__inner:after{border-bottom:.2rem solid transparent;border-bottom-color:var(--md-default-bg-color);border-left:.2rem solid transparent;border-right:.2rem solid transparent;border-top:0;content:"";height:0;left:50%;margin-left:-.2rem;margin-top:-.2rem;position:absolute;top:0;width:0}.md-select__list{border-radius:.1rem;font-size:.8rem;list-style-type:none;margin:0;max-height:inherit;overflow:auto;padding:0}.md-select__item{line-height:1.8rem}.md-select__link{cursor:pointer;display:block;outline:none;padding-left:.6rem;padding-right:1.2rem;scroll-snap-align:start;transition:background-color .25s,color .25s;width:100%}[dir=rtl] .md-select__link{padding-left:1.2rem;padding-right:.6rem}.md-select__link:focus,.md-select__link:hover{color:var(--md-accent-fg-color)}.md-select__link:focus{background-color:var(--md-default-fg-color--lightest)}.md-sidebar{align-self:flex-start;flex-shrink:0;padding:1.2rem 0;position:-webkit-sticky;position:sticky;top:2.4rem;width:12.1rem}@media print{.md-sidebar{display:none}}@media screen and (max-width:76.1875em){.md-sidebar--primary{background-color:var(--md-default-bg-color);display:block;height:100%;left:-12.1rem;position:fixed;top:0;transform:translateX(0);transition:transform .25s cubic-bezier(.4,0,.2,1),box-shadow .25s;width:12.1rem;z-index:4}[dir=rtl] .md-sidebar--primary{left:auto;right:-12.1rem}[data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{box-shadow:0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12),0 5px 5px -3px rgba(0,0,0,.4);transform:translateX(12.1rem)}[dir=rtl] [data-md-toggle=drawer]:checked~.md-container .md-sidebar--primary{transform:translateX(-12.1rem)}.md-sidebar--primary .md-sidebar__scrollwrap{bottom:0;left:0;margin:0;overflow:hidden;position:absolute;right:0;-ms-scroll-snap-type:none;scroll-snap-type:none;top:0}}@media screen and (min-width:76.25em){.md-sidebar{height:0}.no-js .md-sidebar{height:auto}}.md-sidebar--secondary{display:none;order:2}@media screen and (min-width:60em){.md-sidebar--secondary{height:0}.no-js .md-sidebar--secondary{height:auto}.md-sidebar--secondary:not([hidden]){display:block}.md-sidebar--secondary .md-sidebar__scrollwrap{touch-action:pan-y}}.md-sidebar__scrollwrap{-webkit-backface-visibility:hidden;backface-visibility:hidden;margin:0 .2rem;overflow-y:auto;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}.md-sidebar__scrollwrap:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-sidebar__scrollwrap::-webkit-scrollbar{height:.2rem;width:.2rem}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}@media screen and (max-width:76.1875em){.md-overlay{background-color:rgba(0,0,0,.54);height:0;opacity:0;position:fixed;top:0;transition:width 0ms .25s,height 0ms .25s,opacity .25s;width:0;z-index:4}[data-md-toggle=drawer]:checked~.md-overlay{height:100%;opacity:1;transition:width 0ms,height 0ms,opacity .25s;width:100%}}@-webkit-keyframes facts{0%{height:0}to{height:.65rem}}@keyframes facts{0%{height:0}to{height:.65rem}}@-webkit-keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}@keyframes fact{0%{opacity:0;transform:translateY(100%)}50%{opacity:0}to{opacity:1;transform:translateY(0)}}:root{--md-source-forks-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-repositories-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-stars-icon:url('data:image/svg+xml;charset=utf-8,');--md-source-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-source{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.65rem;line-height:1.2;outline-color:var(--md-accent-fg-color);transition:opacity .25s;white-space:nowrap}.md-source:hover{opacity:.7}.md-source__icon{display:inline-block;height:2.4rem;vertical-align:middle;width:2rem}.md-source__icon svg{margin-left:.6rem;margin-top:.6rem}[dir=rtl] .md-source__icon svg{margin-left:0;margin-right:.6rem}.md-source__icon+.md-source__repository{margin-left:-2rem;padding-left:2rem}[dir=rtl] .md-source__icon+.md-source__repository{margin-left:0;margin-right:-2rem;padding-left:0;padding-right:2rem}.md-source__repository{display:inline-block;margin-left:.6rem;max-width:calc(100% - 1.2rem);overflow:hidden;text-overflow:ellipsis;vertical-align:middle}.md-source__facts{font-size:.55rem;list-style-type:none;margin:.1rem 0 0;opacity:.75;overflow:hidden;padding:0}[data-md-state=done] .md-source__facts{-webkit-animation:facts .25s ease-in;animation:facts .25s ease-in}.md-source__fact{display:inline-block}[data-md-state=done] .md-source__fact{-webkit-animation:fact .4s ease-out;animation:fact .4s ease-out}.md-source__fact:before{background-color:currentColor;content:"";display:inline-block;height:.6rem;margin-right:.1rem;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;vertical-align:text-top;width:.6rem}[dir=rtl] .md-source__fact:before{margin-left:.1rem;margin-right:0}.md-source__fact:nth-child(1n+2):before{margin-left:.4rem}[dir=rtl] .md-source__fact:nth-child(1n+2):before{margin-left:.1rem;margin-right:.4rem}.md-source__fact--version:before{-webkit-mask-image:var(--md-source-version-icon);mask-image:var(--md-source-version-icon)}.md-source__fact--stars:before{-webkit-mask-image:var(--md-source-stars-icon);mask-image:var(--md-source-stars-icon)}.md-source__fact--forks:before{-webkit-mask-image:var(--md-source-forks-icon);mask-image:var(--md-source-forks-icon)}.md-source__fact--repositories:before{-webkit-mask-image:var(--md-source-repositories-icon);mask-image:var(--md-source-repositories-icon)}.md-tabs{background-color:var(--md-primary-fg-color);color:var(--md-primary-bg-color);overflow:auto;width:100%}@media print{.md-tabs{display:none}}@media screen and (max-width:76.1875em){.md-tabs{display:none}}.md-tabs[data-md-state=hidden]{pointer-events:none}.md-tabs__list{contain:content;list-style:none;margin:0 0 0 .2rem;padding:0;white-space:nowrap}[dir=rtl] .md-tabs__list{margin-left:0;margin-right:.2rem}.md-tabs__item{display:inline-block;height:2.4rem;padding-left:.6rem;padding-right:.6rem}.md-tabs__link{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;font-size:.7rem;margin-top:.8rem;opacity:.7;outline-color:var(--md-accent-fg-color);outline-offset:.2rem;transition:transform .4s cubic-bezier(.1,.7,.1,1),opacity .25s}.md-tabs__link--active,.md-tabs__link:focus,.md-tabs__link:hover{color:inherit;opacity:1}.md-tabs__item:nth-child(2) .md-tabs__link{transition-delay:20ms}.md-tabs__item:nth-child(3) .md-tabs__link{transition-delay:40ms}.md-tabs__item:nth-child(4) .md-tabs__link{transition-delay:60ms}.md-tabs__item:nth-child(5) .md-tabs__link{transition-delay:80ms}.md-tabs__item:nth-child(6) .md-tabs__link{transition-delay:.1s}.md-tabs__item:nth-child(7) .md-tabs__link{transition-delay:.12s}.md-tabs__item:nth-child(8) .md-tabs__link{transition-delay:.14s}.md-tabs__item:nth-child(9) .md-tabs__link{transition-delay:.16s}.md-tabs__item:nth-child(10) .md-tabs__link{transition-delay:.18s}.md-tabs__item:nth-child(11) .md-tabs__link{transition-delay:.2s}.md-tabs__item:nth-child(12) .md-tabs__link{transition-delay:.22s}.md-tabs__item:nth-child(13) .md-tabs__link{transition-delay:.24s}.md-tabs__item:nth-child(14) .md-tabs__link{transition-delay:.26s}.md-tabs__item:nth-child(15) .md-tabs__link{transition-delay:.28s}.md-tabs__item:nth-child(16) .md-tabs__link{transition-delay:.3s}.md-tabs[data-md-state=hidden] .md-tabs__link{opacity:0;transform:translateY(50%);transition:transform 0ms .1s,opacity .1s}.md-top{background-color:var(--md-default-bg-color);border-radius:1.6rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.1),0 0 .05rem rgba(0,0,0,.25);color:var(--md-default-fg-color--light);font-size:.7rem;margin-left:50%;outline:none;padding:.4rem .8rem;position:fixed;top:3.2rem;transform:translate(-50%);transition:color 125ms,background-color 125ms,transform 125ms cubic-bezier(.4,0,.2,1),opacity 125ms;z-index:2}@media print{.md-top{display:none}}[dir=rtl] .md-top{margin-left:0;margin-right:50%;transform:translate(50%)}.md-top[data-md-state=hidden]{opacity:0;pointer-events:none;transform:translate(-50%,.2rem);transition-duration:0ms}[dir=rtl] .md-top[data-md-state=hidden]{transform:translate(50%,.2rem)}.md-top:focus,.md-top:hover{background-color:var(--md-accent-fg-color);color:var(--md-accent-bg-color)}.md-top svg{display:inline-block;vertical-align:-.5em}@-webkit-keyframes hoverfix{0%{pointer-events:none}}@keyframes hoverfix{0%{pointer-events:none}}:root{--md-version-icon:url('data:image/svg+xml;charset=utf-8,')}.md-version{flex-shrink:0;font-size:.8rem;height:2.4rem}.md-version__current{color:inherit;cursor:pointer;margin-left:1.4rem;margin-right:.4rem;outline:none;position:relative;top:.05rem}[dir=rtl] .md-version__current{margin-left:.4rem;margin-right:1.4rem}.md-version__current:after{background-color:currentColor;content:"";display:inline-block;height:.6rem;margin-left:.4rem;-webkit-mask-image:var(--md-version-icon);mask-image:var(--md-version-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;width:.4rem}[dir=rtl] .md-version__current:after{margin-left:0;margin-right:.4rem}.md-version__list{background-color:var(--md-default-bg-color);border-radius:.1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.1),0 0 .05rem rgba(0,0,0,.25);color:var(--md-default-fg-color);list-style-type:none;margin:.2rem .8rem;max-height:0;opacity:0;overflow:auto;padding:0;position:absolute;-ms-scroll-snap-type:y mandatory;scroll-snap-type:y mandatory;top:.15rem;transition:max-height 0ms .5s,opacity .25s .25s;z-index:1}.md-version:focus-within .md-version__list,.md-version:hover .md-version__list{max-height:10rem;opacity:1;transition:max-height 0ms,opacity .25s}@media (pointer:coarse){.md-version:hover .md-version__list{-webkit-animation:hoverfix .25s forwards;animation:hoverfix .25s forwards}.md-version:focus-within .md-version__list{-webkit-animation:none;animation:none}}.md-version__item{line-height:1.8rem}.md-version__link{cursor:pointer;display:block;outline:none;padding-left:.6rem;padding-right:1.2rem;scroll-snap-align:start;transition:color .25s,background-color .25s;white-space:nowrap;width:100%}[dir=rtl] .md-version__link{padding-left:1.2rem;padding-right:.6rem}.md-version__link:focus,.md-version__link:hover{color:var(--md-accent-fg-color)}.md-version__link:focus{background-color:var(--md-default-fg-color--lightest)}:root{--md-admonition-icon--note:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--abstract:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--info:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--tip:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--success:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--question:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--warning:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--failure:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--danger:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--bug:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--example:url('data:image/svg+xml;charset=utf-8,');--md-admonition-icon--quote:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .admonition,.md-typeset details{background-color:var(--md-admonition-bg-color);border-left:.2rem solid #448aff;border-radius:.1rem;box-shadow:0 .2rem .5rem rgba(0,0,0,.05),0 .025rem .05rem rgba(0,0,0,.05);color:var(--md-admonition-fg-color);font-size:.64rem;margin:1.5625em 0;overflow:hidden;padding:0 .6rem;page-break-inside:avoid}@media print{.md-typeset .admonition,.md-typeset details{box-shadow:none}}[dir=rtl] .md-typeset .admonition,[dir=rtl] .md-typeset details{border-left:none;border-right:.2rem solid #448aff}.md-typeset .admonition .admonition,.md-typeset .admonition details,.md-typeset details .admonition,.md-typeset details details{margin-bottom:1em;margin-top:1em}.md-typeset .admonition .md-typeset__scrollwrap,.md-typeset details .md-typeset__scrollwrap{margin:1em -.6rem}.md-typeset .admonition .md-typeset__table,.md-typeset details .md-typeset__table{padding:0 .6rem}.md-typeset .admonition>.tabbed-set:only-child,.md-typeset details>.tabbed-set:only-child{margin-top:0}html .md-typeset .admonition>:last-child,html .md-typeset details>:last-child{margin-bottom:.6rem}.md-typeset .admonition-title,.md-typeset summary{background-color:rgba(68,138,255,.1);border-left:.2rem solid #448aff;font-weight:700;margin:0 -.6rem 0 -.8rem;padding:.4rem .6rem .4rem 2rem;position:relative}[dir=rtl] .md-typeset .admonition-title,[dir=rtl] .md-typeset summary{border-left:none;border-right:.2rem solid #448aff;margin:0 -.8rem 0 -.6rem;padding:.4rem 2rem .4rem .6rem}html .md-typeset .admonition-title:last-child,html .md-typeset summary:last-child{margin-bottom:0}.md-typeset .admonition-title:before,.md-typeset summary:before{background-color:#448aff;content:"";height:1rem;left:.6rem;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;width:1rem}[dir=rtl] .md-typeset .admonition-title:before,[dir=rtl] .md-typeset summary:before{left:auto;right:.6rem}.md-typeset .admonition.note,.md-typeset details.note{border-color:#448aff}.md-typeset .note>.admonition-title,.md-typeset .note>summary{background-color:rgba(68,138,255,.1);border-color:#448aff}.md-typeset .note>.admonition-title:before,.md-typeset .note>summary:before{background-color:#448aff;-webkit-mask-image:var(--md-admonition-icon--note);mask-image:var(--md-admonition-icon--note);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.abstract,.md-typeset .admonition.summary,.md-typeset .admonition.tldr,.md-typeset details.abstract,.md-typeset details.summary,.md-typeset details.tldr{border-color:#00b0ff}.md-typeset .abstract>.admonition-title,.md-typeset .abstract>summary,.md-typeset .summary>.admonition-title,.md-typeset .summary>summary,.md-typeset .tldr>.admonition-title,.md-typeset .tldr>summary{background-color:rgba(0,176,255,.1);border-color:#00b0ff}.md-typeset .abstract>.admonition-title:before,.md-typeset .abstract>summary:before,.md-typeset .summary>.admonition-title:before,.md-typeset .summary>summary:before,.md-typeset .tldr>.admonition-title:before,.md-typeset .tldr>summary:before{background-color:#00b0ff;-webkit-mask-image:var(--md-admonition-icon--abstract);mask-image:var(--md-admonition-icon--abstract);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.info,.md-typeset .admonition.todo,.md-typeset details.info,.md-typeset details.todo{border-color:#00b8d4}.md-typeset .info>.admonition-title,.md-typeset .info>summary,.md-typeset .todo>.admonition-title,.md-typeset .todo>summary{background-color:rgba(0,184,212,.1);border-color:#00b8d4}.md-typeset .info>.admonition-title:before,.md-typeset .info>summary:before,.md-typeset .todo>.admonition-title:before,.md-typeset .todo>summary:before{background-color:#00b8d4;-webkit-mask-image:var(--md-admonition-icon--info);mask-image:var(--md-admonition-icon--info);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.hint,.md-typeset .admonition.important,.md-typeset .admonition.tip,.md-typeset details.hint,.md-typeset details.important,.md-typeset details.tip{border-color:#00bfa5}.md-typeset .hint>.admonition-title,.md-typeset .hint>summary,.md-typeset .important>.admonition-title,.md-typeset .important>summary,.md-typeset .tip>.admonition-title,.md-typeset .tip>summary{background-color:rgba(0,191,165,.1);border-color:#00bfa5}.md-typeset .hint>.admonition-title:before,.md-typeset .hint>summary:before,.md-typeset .important>.admonition-title:before,.md-typeset .important>summary:before,.md-typeset .tip>.admonition-title:before,.md-typeset .tip>summary:before{background-color:#00bfa5;-webkit-mask-image:var(--md-admonition-icon--tip);mask-image:var(--md-admonition-icon--tip);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.check,.md-typeset .admonition.done,.md-typeset .admonition.success,.md-typeset details.check,.md-typeset details.done,.md-typeset details.success{border-color:#00c853}.md-typeset .check>.admonition-title,.md-typeset .check>summary,.md-typeset .done>.admonition-title,.md-typeset .done>summary,.md-typeset .success>.admonition-title,.md-typeset .success>summary{background-color:rgba(0,200,83,.1);border-color:#00c853}.md-typeset .check>.admonition-title:before,.md-typeset .check>summary:before,.md-typeset .done>.admonition-title:before,.md-typeset .done>summary:before,.md-typeset .success>.admonition-title:before,.md-typeset .success>summary:before{background-color:#00c853;-webkit-mask-image:var(--md-admonition-icon--success);mask-image:var(--md-admonition-icon--success);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.faq,.md-typeset .admonition.help,.md-typeset .admonition.question,.md-typeset details.faq,.md-typeset details.help,.md-typeset details.question{border-color:#64dd17}.md-typeset .faq>.admonition-title,.md-typeset .faq>summary,.md-typeset .help>.admonition-title,.md-typeset .help>summary,.md-typeset .question>.admonition-title,.md-typeset .question>summary{background-color:rgba(100,221,23,.1);border-color:#64dd17}.md-typeset .faq>.admonition-title:before,.md-typeset .faq>summary:before,.md-typeset .help>.admonition-title:before,.md-typeset .help>summary:before,.md-typeset .question>.admonition-title:before,.md-typeset .question>summary:before{background-color:#64dd17;-webkit-mask-image:var(--md-admonition-icon--question);mask-image:var(--md-admonition-icon--question);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.attention,.md-typeset .admonition.caution,.md-typeset .admonition.warning,.md-typeset details.attention,.md-typeset details.caution,.md-typeset details.warning{border-color:#ff9100}.md-typeset .attention>.admonition-title,.md-typeset .attention>summary,.md-typeset .caution>.admonition-title,.md-typeset .caution>summary,.md-typeset .warning>.admonition-title,.md-typeset .warning>summary{background-color:rgba(255,145,0,.1);border-color:#ff9100}.md-typeset .attention>.admonition-title:before,.md-typeset .attention>summary:before,.md-typeset .caution>.admonition-title:before,.md-typeset .caution>summary:before,.md-typeset .warning>.admonition-title:before,.md-typeset .warning>summary:before{background-color:#ff9100;-webkit-mask-image:var(--md-admonition-icon--warning);mask-image:var(--md-admonition-icon--warning);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.fail,.md-typeset .admonition.failure,.md-typeset .admonition.missing,.md-typeset details.fail,.md-typeset details.failure,.md-typeset details.missing{border-color:#ff5252}.md-typeset .fail>.admonition-title,.md-typeset .fail>summary,.md-typeset .failure>.admonition-title,.md-typeset .failure>summary,.md-typeset .missing>.admonition-title,.md-typeset .missing>summary{background-color:rgba(255,82,82,.1);border-color:#ff5252}.md-typeset .fail>.admonition-title:before,.md-typeset .fail>summary:before,.md-typeset .failure>.admonition-title:before,.md-typeset .failure>summary:before,.md-typeset .missing>.admonition-title:before,.md-typeset .missing>summary:before{background-color:#ff5252;-webkit-mask-image:var(--md-admonition-icon--failure);mask-image:var(--md-admonition-icon--failure);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.danger,.md-typeset .admonition.error,.md-typeset details.danger,.md-typeset details.error{border-color:#ff1744}.md-typeset .danger>.admonition-title,.md-typeset .danger>summary,.md-typeset .error>.admonition-title,.md-typeset .error>summary{background-color:rgba(255,23,68,.1);border-color:#ff1744}.md-typeset .danger>.admonition-title:before,.md-typeset .danger>summary:before,.md-typeset .error>.admonition-title:before,.md-typeset .error>summary:before{background-color:#ff1744;-webkit-mask-image:var(--md-admonition-icon--danger);mask-image:var(--md-admonition-icon--danger);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.bug,.md-typeset details.bug{border-color:#f50057}.md-typeset .bug>.admonition-title,.md-typeset .bug>summary{background-color:rgba(245,0,87,.1);border-color:#f50057}.md-typeset .bug>.admonition-title:before,.md-typeset .bug>summary:before{background-color:#f50057;-webkit-mask-image:var(--md-admonition-icon--bug);mask-image:var(--md-admonition-icon--bug);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.example,.md-typeset details.example{border-color:#7c4dff}.md-typeset .example>.admonition-title,.md-typeset .example>summary{background-color:rgba(124,77,255,.1);border-color:#7c4dff}.md-typeset .example>.admonition-title:before,.md-typeset .example>summary:before{background-color:#7c4dff;-webkit-mask-image:var(--md-admonition-icon--example);mask-image:var(--md-admonition-icon--example);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}.md-typeset .admonition.cite,.md-typeset .admonition.quote,.md-typeset details.cite,.md-typeset details.quote{border-color:#9e9e9e}.md-typeset .cite>.admonition-title,.md-typeset .cite>summary,.md-typeset .quote>.admonition-title,.md-typeset .quote>summary{background-color:hsla(0,0%,62%,.1);border-color:#9e9e9e}.md-typeset .cite>.admonition-title:before,.md-typeset .cite>summary:before,.md-typeset .quote>.admonition-title:before,.md-typeset .quote>summary:before{background-color:#9e9e9e;-webkit-mask-image:var(--md-admonition-icon--quote);mask-image:var(--md-admonition-icon--quote);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain}:root{--md-footnotes-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .footnote{color:var(--md-default-fg-color--light);font-size:.64rem}.md-typeset .footnote>ol{margin-left:0}.md-typeset .footnote>ol>li{transition:color 125ms}.md-typeset .footnote>ol>li:target{color:var(--md-default-fg-color)}.md-typeset .footnote>ol>li:hover .footnote-backref,.md-typeset .footnote>ol>li:target .footnote-backref{opacity:1;transform:translateX(0)}.md-typeset .footnote>ol>li>:first-child{margin-top:0}.md-typeset .footnote-ref{font-size:.75em;font-weight:700}html .md-typeset .footnote-ref{outline-offset:.1rem}.md-typeset .footnote-backref{color:var(--md-typeset-a-color);display:inline-block;font-size:0;opacity:0;transform:translateX(.25rem);transition:color .25s,transform .25s .25s,opacity 125ms .25s;vertical-align:text-bottom}@media print{.md-typeset .footnote-backref{color:var(--md-typeset-a-color);opacity:1;transform:translateX(0)}}[dir=rtl] .md-typeset .footnote-backref{transform:translateX(-.25rem)}.md-typeset .footnote-backref:hover{color:var(--md-accent-fg-color)}.md-typeset .footnote-backref:before{background-color:currentColor;content:"";display:inline-block;height:.8rem;-webkit-mask-image:var(--md-footnotes-icon);mask-image:var(--md-footnotes-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;width:.8rem}[dir=rtl] .md-typeset .footnote-backref:before svg{transform:scaleX(-1)}.md-typeset [id^="fnref:"]:target{margin-top:-3.4rem;padding-top:3.4rem;scroll-margin-top:0}.md-typeset [id^="fnref:"]:target>.footnote-ref{outline:auto}.md-typeset [id^="fn:"]:target{margin-top:-3.45rem;padding-top:3.45rem;scroll-margin-top:0}.md-typeset .headerlink{color:var(--md-default-fg-color--lighter);display:inline-block;margin-left:.5rem;opacity:0;transition:color .25s,opacity 125ms}@media print{.md-typeset .headerlink{display:none}}[dir=rtl] .md-typeset .headerlink{margin-left:0;margin-right:.5rem}.md-typeset .headerlink:focus,.md-typeset :hover>.headerlink,.md-typeset :target>.headerlink{opacity:1;transition:color .25s,opacity 125ms}.md-typeset .headerlink:focus,.md-typeset .headerlink:hover,.md-typeset :target>.headerlink{color:var(--md-accent-fg-color)}.md-typeset :target{scroll-margin-top:3.6rem}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset :target{scroll-margin-top:6rem}}.md-typeset h1:target,.md-typeset h2:target,.md-typeset h3:target{scroll-margin-top:0}.md-typeset h1:target:before,.md-typeset h2:target:before,.md-typeset h3:target:before{content:"";display:block;margin-top:-3.4rem;padding-top:3.4rem}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset h1:target,.md-header--lifted~.md-container .md-typeset h2:target,.md-header--lifted~.md-container .md-typeset h3:target{scroll-margin-top:0}.md-header--lifted~.md-container .md-typeset h1:target:before,.md-header--lifted~.md-container .md-typeset h2:target:before,.md-header--lifted~.md-container .md-typeset h3:target:before{margin-top:-5.8rem;padding-top:5.8rem}}.md-typeset h4:target{scroll-margin-top:0}.md-typeset h4:target:before{content:"";display:block;margin-top:-3.45rem;padding-top:3.45rem}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset h4:target{scroll-margin-top:0}.md-header--lifted~.md-container .md-typeset h4:target:before{margin-top:-5.85rem;padding-top:5.85rem}}.md-typeset h5:target,.md-typeset h6:target{scroll-margin-top:0}.md-typeset h5:target:before,.md-typeset h6:target:before{content:"";display:block;margin-top:-3.6rem;padding-top:3.6rem}@media screen and (min-width:76.25em){.md-header--lifted~.md-container .md-typeset h5:target,.md-header--lifted~.md-container .md-typeset h6:target{scroll-margin-top:0}.md-header--lifted~.md-container .md-typeset h5:target:before,.md-header--lifted~.md-container .md-typeset h6:target:before{margin-top:-6rem;padding-top:6rem}}.md-typeset div.arithmatex{overflow:auto}@media screen and (max-width:44.9375em){.md-typeset div.arithmatex{margin:0 -.8rem}}.md-typeset div.arithmatex>*{margin:1em auto!important;padding:0 .8rem;touch-action:auto;width:-webkit-min-content;width:-moz-min-content;width:min-content}.md-typeset .critic.comment,.md-typeset del.critic,.md-typeset ins.critic{-webkit-box-decoration-break:clone;box-decoration-break:clone}.md-typeset del.critic{background-color:var(--md-typeset-del-color)}.md-typeset ins.critic{background-color:var(--md-typeset-ins-color)}.md-typeset .critic.comment{color:var(--md-code-hl-comment-color)}.md-typeset .critic.comment:before{content:"/* "}.md-typeset .critic.comment:after{content:" */"}.md-typeset .critic.block{box-shadow:none;display:block;margin:1em 0;overflow:auto;padding-left:.8rem;padding-right:.8rem}.md-typeset .critic.block>:first-child{margin-top:.5em}.md-typeset .critic.block>:last-child{margin-bottom:.5em}:root{--md-details-icon:url('data:image/svg+xml;charset=utf-8,')}.md-typeset details{display:flow-root;overflow:visible;padding-top:0}.md-typeset details[open]>summary:after{transform:rotate(90deg)}.md-typeset details:not([open]){box-shadow:none;padding-bottom:0}.md-typeset details:not([open])>summary{border-radius:.1rem}.md-typeset details:after{content:"";display:table}.md-typeset summary{border-top-left-radius:.1rem;border-top-right-radius:.1rem;cursor:pointer;display:block;min-height:1rem;padding:.4rem 1.8rem .4rem 2rem}[dir=rtl] .md-typeset summary{padding:.4rem 2.2rem .4rem 1.8rem}.md-typeset summary.focus-visible{outline-color:var(--md-accent-fg-color);outline-offset:.2rem}.md-typeset summary:not(.focus-visible){-webkit-tap-highlight-color:transparent;outline:none}.md-typeset summary:after{background-color:currentColor;content:"";height:1rem;-webkit-mask-image:var(--md-details-icon);mask-image:var(--md-details-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;right:.4rem;top:.4rem;transform:rotate(0deg);transition:transform .25s;width:1rem}[dir=rtl] .md-typeset summary:after{left:.4rem;right:auto;transform:rotate(180deg)}.md-typeset summary::-webkit-details-marker,.md-typeset summary::marker{display:none}.md-typeset .emojione,.md-typeset .gemoji,.md-typeset .twemoji{display:inline-flex;height:1.125em;vertical-align:text-top}.md-typeset .emojione svg,.md-typeset .gemoji svg,.md-typeset .twemoji svg{fill:currentColor;max-height:100%;width:1.125em}.highlight .o,.highlight .ow{color:var(--md-code-hl-operator-color)}.highlight .p{color:var(--md-code-hl-punctuation-color)}.highlight .cpf,.highlight .l,.highlight .s,.highlight .s1,.highlight .s2,.highlight .sb,.highlight .sc,.highlight .si,.highlight .ss{color:var(--md-code-hl-string-color)}.highlight .cp,.highlight .se,.highlight .sh,.highlight .sr,.highlight .sx{color:var(--md-code-hl-special-color)}.highlight .il,.highlight .m,.highlight .mb,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo{color:var(--md-code-hl-number-color)}.highlight .k,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr,.highlight .kt{color:var(--md-code-hl-keyword-color)}.highlight .kc,.highlight .n{color:var(--md-code-hl-name-color)}.highlight .bp,.highlight .nb,.highlight .no{color:var(--md-code-hl-constant-color)}.highlight .nc,.highlight .ne,.highlight .nf,.highlight .nn{color:var(--md-code-hl-function-color)}.highlight .nd,.highlight .ni,.highlight .nl,.highlight .nt{color:var(--md-code-hl-keyword-color)}.highlight .c,.highlight .c1,.highlight .ch,.highlight .cm,.highlight .cs,.highlight .sd{color:var(--md-code-hl-comment-color)}.highlight .na,.highlight .nv,.highlight .vc,.highlight .vg,.highlight .vi{color:var(--md-code-hl-variable-color)}.highlight .ge,.highlight .gh,.highlight .go,.highlight .gp,.highlight .gr,.highlight .gs,.highlight .gt,.highlight .gu{color:var(--md-code-hl-generic-color)}.highlight .gd,.highlight .gi{border-radius:.1rem;margin:0 -.125em;padding:0 .125em}.highlight .gd{background-color:var(--md-typeset-del-color)}.highlight .gi{background-color:var(--md-typeset-ins-color)}.highlight .hll{background-color:var(--md-code-hl-color);display:block;margin:0 -1.1764705882em;padding:0 1.1764705882em}.highlight span.filename{background-color:var(--md-code-bg-color);border-bottom:.05rem solid var(--md-default-fg-color--lightest);border-top-left-radius:.1rem;border-top-right-radius:.1rem;display:block;font-size:.85em;font-weight:700;margin-top:1em;padding:.7720588235em 1.1764705882em;position:relative}.highlight span.filename+pre{margin-top:0}.highlight [data-linenos]:before{background-color:var(--md-code-bg-color);box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;color:var(--md-default-fg-color--light);content:attr(data-linenos);float:left;left:-1.1764705882em;margin-left:-1.1764705882em;margin-right:1.1764705882em;padding-left:1.1764705882em;position:-webkit-sticky;position:sticky;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.highlighttable{display:flow-root;overflow:hidden}.highlighttable tbody,.highlighttable td{display:block;padding:0}.highlighttable tr{display:flex}.highlighttable pre{margin:0}.highlighttable th.filename{flex-grow:1;padding:0;text-align:left}.highlighttable .linenos{background-color:var(--md-code-bg-color);font-size:.85em;padding:.7720588235em 0 .7720588235em 1.1764705882em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.highlighttable .linenodiv{box-shadow:-.05rem 0 var(--md-default-fg-color--lightest) inset;padding-right:.5882352941em}.highlighttable .linenodiv pre{color:var(--md-default-fg-color--light);text-align:right}.highlighttable .code{flex:1;overflow:hidden}.md-typeset .highlighttable{border-radius:.1rem;direction:ltr;margin:1em 0}.md-typeset .highlighttable code{border-radius:0}@media screen and (max-width:44.9375em){.md-typeset>.highlight{margin:1em -.8rem}.md-typeset>.highlight .hll{margin:0 -.8rem;padding:0 .8rem}.md-typeset>.highlight code{border-radius:0}.md-typeset>.highlighttable{border-radius:0;margin:1em -.8rem}.md-typeset>.highlighttable .hll{margin:0 -.8rem;padding:0 .8rem}}.md-typeset .keys kbd:after,.md-typeset .keys kbd:before{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;color:inherit;margin:0;position:relative}.md-typeset .keys span{color:var(--md-default-fg-color--light);padding:0 .2em}.md-typeset .keys .key-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-left-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-right-alt:before{content:"⎇";padding-right:.4em}.md-typeset .keys .key-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-left-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-right-command:before{content:"⌘";padding-right:.4em}.md-typeset .keys .key-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-left-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-right-control:before{content:"⌃";padding-right:.4em}.md-typeset .keys .key-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-left-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-right-meta:before{content:"◆";padding-right:.4em}.md-typeset .keys .key-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-left-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-right-option:before{content:"⌥";padding-right:.4em}.md-typeset .keys .key-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-left-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-right-shift:before{content:"⇧";padding-right:.4em}.md-typeset .keys .key-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-left-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-right-super:before{content:"❖";padding-right:.4em}.md-typeset .keys .key-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-left-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-right-windows:before{content:"⊞";padding-right:.4em}.md-typeset .keys .key-arrow-down:before{content:"↓";padding-right:.4em}.md-typeset .keys .key-arrow-left:before{content:"←";padding-right:.4em}.md-typeset .keys .key-arrow-right:before{content:"→";padding-right:.4em}.md-typeset .keys .key-arrow-up:before{content:"↑";padding-right:.4em}.md-typeset .keys .key-backspace:before{content:"⌫";padding-right:.4em}.md-typeset .keys .key-backtab:before{content:"⇤";padding-right:.4em}.md-typeset .keys .key-caps-lock:before{content:"⇪";padding-right:.4em}.md-typeset .keys .key-clear:before{content:"⌧";padding-right:.4em}.md-typeset .keys .key-context-menu:before{content:"☰";padding-right:.4em}.md-typeset .keys .key-delete:before{content:"⌦";padding-right:.4em}.md-typeset .keys .key-eject:before{content:"⏏";padding-right:.4em}.md-typeset .keys .key-end:before{content:"⤓";padding-right:.4em}.md-typeset .keys .key-escape:before{content:"⎋";padding-right:.4em}.md-typeset .keys .key-home:before{content:"⤒";padding-right:.4em}.md-typeset .keys .key-insert:before{content:"⎀";padding-right:.4em}.md-typeset .keys .key-page-down:before{content:"⇟";padding-right:.4em}.md-typeset .keys .key-page-up:before{content:"⇞";padding-right:.4em}.md-typeset .keys .key-print-screen:before{content:"⎙";padding-right:.4em}.md-typeset .keys .key-tab:after{content:"⇥";padding-left:.4em}.md-typeset .keys .key-num-enter:after{content:"⌤";padding-left:.4em}.md-typeset .keys .key-enter:after{content:"⏎";padding-left:.4em}.md-typeset .tabbed-content{box-shadow:0 -.05rem var(--md-default-fg-color--lightest);display:none;order:99;width:100%}@media print{.md-typeset .tabbed-content{display:block;order:0}}.md-typeset .tabbed-content>.highlight:only-child pre,.md-typeset .tabbed-content>.highlighttable:only-child,.md-typeset .tabbed-content>pre:only-child{margin:0}.md-typeset .tabbed-content>.highlight:only-child pre>code,.md-typeset .tabbed-content>.highlighttable:only-child>code,.md-typeset .tabbed-content>pre:only-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-content>.tabbed-set{margin:0}.md-typeset .tabbed-set{border-radius:.1rem;display:flex;flex-wrap:wrap;margin:1em 0;position:relative}.md-typeset .tabbed-set>input{height:0;opacity:0;position:absolute;width:0}.md-typeset .tabbed-set>input:checked+label{border-color:var(--md-accent-fg-color);color:var(--md-accent-fg-color)}.md-typeset .tabbed-set>input:checked+label+.tabbed-content{display:block}.md-typeset .tabbed-set>input:focus+label{outline-color:var(--md-accent-fg-color);outline-style:auto}.md-typeset .tabbed-set>input:not(.focus-visible)+label{-webkit-tap-highlight-color:transparent;outline:none}.md-typeset .tabbed-set>label{border-bottom:.1rem solid transparent;color:var(--md-default-fg-color--light);cursor:pointer;font-size:.64rem;font-weight:700;padding:.9375em 1.25em .78125em;transition:color .25s;width:auto;z-index:1}.md-typeset .tabbed-set>label:hover{color:var(--md-accent-fg-color)}@media screen{.md-typeset .tabbed-alternate input:first-child:checked~.tabbed-labels>:first-child,.md-typeset .tabbed-alternate input:nth-child(2):checked~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-alternate input:nth-child(3):checked~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-alternate input:nth-child(4):checked~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-alternate input:nth-child(5):checked~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-alternate input:nth-child(6):checked~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-alternate input:nth-child(7):checked~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-alternate input:nth-child(8):checked~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-alternate input:nth-child(9):checked~.tabbed-labels>:nth-child(9),.md-typeset .tabbed-alternate input:nth-child(10):checked~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-alternate input:nth-child(11):checked~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-alternate input:nth-child(12):checked~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-alternate input:nth-child(13):checked~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-alternate input:nth-child(14):checked~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-alternate input:nth-child(15):checked~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-alternate input:nth-child(16):checked~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-alternate input:nth-child(17):checked~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-alternate input:nth-child(18):checked~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-alternate input:nth-child(19):checked~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-alternate input:nth-child(20):checked~.tabbed-labels>:nth-child(20){border-color:var(--md-accent-fg-color);color:var(--md-accent-fg-color)}}.md-typeset .tabbed-alternate input:first-child.focus-visible~.tabbed-labels>:first-child,.md-typeset .tabbed-alternate input:nth-child(2).focus-visible~.tabbed-labels>:nth-child(2),.md-typeset .tabbed-alternate input:nth-child(3).focus-visible~.tabbed-labels>:nth-child(3),.md-typeset .tabbed-alternate input:nth-child(4).focus-visible~.tabbed-labels>:nth-child(4),.md-typeset .tabbed-alternate input:nth-child(5).focus-visible~.tabbed-labels>:nth-child(5),.md-typeset .tabbed-alternate input:nth-child(6).focus-visible~.tabbed-labels>:nth-child(6),.md-typeset .tabbed-alternate input:nth-child(7).focus-visible~.tabbed-labels>:nth-child(7),.md-typeset .tabbed-alternate input:nth-child(8).focus-visible~.tabbed-labels>:nth-child(8),.md-typeset .tabbed-alternate input:nth-child(9).focus-visible~.tabbed-labels>:nth-child(9),.md-typeset .tabbed-alternate input:nth-child(10).focus-visible~.tabbed-labels>:nth-child(10),.md-typeset .tabbed-alternate input:nth-child(11).focus-visible~.tabbed-labels>:nth-child(11),.md-typeset .tabbed-alternate input:nth-child(12).focus-visible~.tabbed-labels>:nth-child(12),.md-typeset .tabbed-alternate input:nth-child(13).focus-visible~.tabbed-labels>:nth-child(13),.md-typeset .tabbed-alternate input:nth-child(14).focus-visible~.tabbed-labels>:nth-child(14),.md-typeset .tabbed-alternate input:nth-child(15).focus-visible~.tabbed-labels>:nth-child(15),.md-typeset .tabbed-alternate input:nth-child(16).focus-visible~.tabbed-labels>:nth-child(16),.md-typeset .tabbed-alternate input:nth-child(17).focus-visible~.tabbed-labels>:nth-child(17),.md-typeset .tabbed-alternate input:nth-child(18).focus-visible~.tabbed-labels>:nth-child(18),.md-typeset .tabbed-alternate input:nth-child(19).focus-visible~.tabbed-labels>:nth-child(19),.md-typeset .tabbed-alternate input:nth-child(20).focus-visible~.tabbed-labels>:nth-child(20){background-color:var(--md-accent-fg-color--transparent)}.md-typeset .tabbed-alternate input:first-child:checked~.tabbed-content>:first-child,.md-typeset .tabbed-alternate input:nth-child(2):checked~.tabbed-content>:nth-child(2),.md-typeset .tabbed-alternate input:nth-child(3):checked~.tabbed-content>:nth-child(3),.md-typeset .tabbed-alternate input:nth-child(4):checked~.tabbed-content>:nth-child(4),.md-typeset .tabbed-alternate input:nth-child(5):checked~.tabbed-content>:nth-child(5),.md-typeset .tabbed-alternate input:nth-child(6):checked~.tabbed-content>:nth-child(6),.md-typeset .tabbed-alternate input:nth-child(7):checked~.tabbed-content>:nth-child(7),.md-typeset .tabbed-alternate input:nth-child(8):checked~.tabbed-content>:nth-child(8),.md-typeset .tabbed-alternate input:nth-child(9):checked~.tabbed-content>:nth-child(9),.md-typeset .tabbed-alternate input:nth-child(10):checked~.tabbed-content>:nth-child(10),.md-typeset .tabbed-alternate input:nth-child(11):checked~.tabbed-content>:nth-child(11),.md-typeset .tabbed-alternate input:nth-child(12):checked~.tabbed-content>:nth-child(12),.md-typeset .tabbed-alternate input:nth-child(13):checked~.tabbed-content>:nth-child(13),.md-typeset .tabbed-alternate input:nth-child(14):checked~.tabbed-content>:nth-child(14),.md-typeset .tabbed-alternate input:nth-child(15):checked~.tabbed-content>:nth-child(15),.md-typeset .tabbed-alternate input:nth-child(16):checked~.tabbed-content>:nth-child(16),.md-typeset .tabbed-alternate input:nth-child(17):checked~.tabbed-content>:nth-child(17),.md-typeset .tabbed-alternate input:nth-child(18):checked~.tabbed-content>:nth-child(18),.md-typeset .tabbed-alternate input:nth-child(19):checked~.tabbed-content>:nth-child(19),.md-typeset .tabbed-alternate input:nth-child(20):checked~.tabbed-content>:nth-child(20){display:block}.md-typeset .tabbed-labels{-ms-overflow-style:none;box-shadow:0 -.05rem var(--md-default-fg-color--lightest) inset;display:flex;max-width:100%;overflow:auto;-ms-scroll-snap-type:x proximity;scroll-snap-type:x proximity;scrollbar-width:none}@media print{.md-typeset .tabbed-labels{display:contents}}.md-typeset .tabbed-labels::-webkit-scrollbar{display:none}.md-typeset .tabbed-labels>label{border-bottom:.1rem solid transparent;border-top-left-radius:.1rem;border-top-right-radius:.1rem;color:var(--md-default-fg-color--light);cursor:pointer;flex-shrink:0;font-size:.64rem;font-weight:700;padding:.78125em 1.25em .625em;scroll-snap-align:start;transition:background-color .25s,color .25s;white-space:nowrap;width:auto;z-index:1}@media print{.md-typeset .tabbed-labels>label:first-child{order:1}.md-typeset .tabbed-labels>label:nth-child(2){order:2}.md-typeset .tabbed-labels>label:nth-child(3){order:3}.md-typeset .tabbed-labels>label:nth-child(4){order:4}.md-typeset .tabbed-labels>label:nth-child(5){order:5}.md-typeset .tabbed-labels>label:nth-child(6){order:6}.md-typeset .tabbed-labels>label:nth-child(7){order:7}.md-typeset .tabbed-labels>label:nth-child(8){order:8}.md-typeset .tabbed-labels>label:nth-child(9){order:9}.md-typeset .tabbed-labels>label:nth-child(10){order:10}.md-typeset .tabbed-labels>label:nth-child(11){order:11}.md-typeset .tabbed-labels>label:nth-child(12){order:12}.md-typeset .tabbed-labels>label:nth-child(13){order:13}.md-typeset .tabbed-labels>label:nth-child(14){order:14}.md-typeset .tabbed-labels>label:nth-child(15){order:15}.md-typeset .tabbed-labels>label:nth-child(16){order:16}.md-typeset .tabbed-labels>label:nth-child(17){order:17}.md-typeset .tabbed-labels>label:nth-child(18){order:18}.md-typeset .tabbed-labels>label:nth-child(19){order:19}.md-typeset .tabbed-labels>label:nth-child(20){order:20}}.md-typeset .tabbed-labels>label:hover{color:var(--md-accent-fg-color)}@media screen and (max-width:44.9375em){.md-typeset>.tabbed-alternate .tabbed-labels{margin:0 -.8rem;max-width:100vw;padding-left:.8rem;scroll-padding-left:.8rem}[dir=rtl] .md-typeset>.tabbed-alternate .tabbed-labels{padding-left:0;padding-right:.8rem;scroll-padding-left:auto;scroll-padding-right:.8rem}.md-typeset>.tabbed-alternate .tabbed-labels:after{content:"";padding-right:.8rem}[dir=rtl] .md-typeset>.tabbed-alternate .tabbed-labels:after{padding-left:.8rem;padding-right:0}}.md-typeset .tabbed-alternate{flex-direction:column}.md-typeset .tabbed-alternate .tabbed-content{box-shadow:none;display:initial;order:0;width:100%}@media print{.md-typeset .tabbed-alternate .tabbed-content{display:contents}}.md-typeset .tabbed-alternate .tabbed-block{display:none}@media print{.md-typeset .tabbed-alternate .tabbed-block{display:block}.md-typeset .tabbed-alternate .tabbed-block:first-child{order:1}.md-typeset .tabbed-alternate .tabbed-block:nth-child(2){order:2}.md-typeset .tabbed-alternate .tabbed-block:nth-child(3){order:3}.md-typeset .tabbed-alternate .tabbed-block:nth-child(4){order:4}.md-typeset .tabbed-alternate .tabbed-block:nth-child(5){order:5}.md-typeset .tabbed-alternate .tabbed-block:nth-child(6){order:6}.md-typeset .tabbed-alternate .tabbed-block:nth-child(7){order:7}.md-typeset .tabbed-alternate .tabbed-block:nth-child(8){order:8}.md-typeset .tabbed-alternate .tabbed-block:nth-child(9){order:9}.md-typeset .tabbed-alternate .tabbed-block:nth-child(10){order:10}.md-typeset .tabbed-alternate .tabbed-block:nth-child(11){order:11}.md-typeset .tabbed-alternate .tabbed-block:nth-child(12){order:12}.md-typeset .tabbed-alternate .tabbed-block:nth-child(13){order:13}.md-typeset .tabbed-alternate .tabbed-block:nth-child(14){order:14}.md-typeset .tabbed-alternate .tabbed-block:nth-child(15){order:15}.md-typeset .tabbed-alternate .tabbed-block:nth-child(16){order:16}.md-typeset .tabbed-alternate .tabbed-block:nth-child(17){order:17}.md-typeset .tabbed-alternate .tabbed-block:nth-child(18){order:18}.md-typeset .tabbed-alternate .tabbed-block:nth-child(19){order:19}.md-typeset .tabbed-alternate .tabbed-block:nth-child(20){order:20}}.md-typeset .tabbed-alternate .tabbed-block>.highlight:only-child pre,.md-typeset .tabbed-alternate .tabbed-block>.highlighttable:only-child,.md-typeset .tabbed-alternate .tabbed-block>pre:only-child{margin:0}.md-typeset .tabbed-alternate .tabbed-block>.highlight:only-child pre>code,.md-typeset .tabbed-alternate .tabbed-block>.highlighttable:only-child>code,.md-typeset .tabbed-alternate .tabbed-block>pre:only-child>code{border-top-left-radius:0;border-top-right-radius:0}.md-typeset .tabbed-alternate .tabbed-block>.tabbed-set{margin:0}:root{--md-tasklist-icon:url('data:image/svg+xml;charset=utf-8,');--md-tasklist-icon--checked:url('data:image/svg+xml;charset=utf-8,')}.md-typeset .task-list-item{list-style-type:none;position:relative}.md-typeset .task-list-item [type=checkbox]{left:-2em;position:absolute;top:.45em}[dir=rtl] .md-typeset .task-list-item [type=checkbox]{left:auto;right:-2em}.md-typeset .task-list-control [type=checkbox]{opacity:0;z-index:-1}.md-typeset .task-list-indicator:before{background-color:var(--md-default-fg-color--lightest);content:"";height:1.25em;left:-1.5em;-webkit-mask-image:var(--md-tasklist-icon);mask-image:var(--md-tasklist-icon);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;position:absolute;top:.15em;width:1.25em}[dir=rtl] .md-typeset .task-list-indicator:before{left:auto;right:-1.5em}.md-typeset [type=checkbox]:checked+.task-list-indicator:before{background-color:#00e676;-webkit-mask-image:var(--md-tasklist-icon--checked);mask-image:var(--md-tasklist-icon--checked)}@media screen and (min-width:45em){.md-typeset .inline{float:left;margin-bottom:.8rem;margin-right:.8rem;margin-top:0;width:11.7rem}[dir=rtl] .md-typeset .inline{float:right;margin-left:.8rem;margin-right:0}.md-typeset .inline.end{float:right;margin-left:.8rem;margin-right:0}[dir=rtl] .md-typeset .inline.end{float:left;margin-left:0;margin-right:.8rem}} +/*# sourceMappingURL=main.a57b2b03.min.css.map */ \ No newline at end of file diff --git a/assets/stylesheets/main.a57b2b03.min.css.map b/assets/stylesheets/main.a57b2b03.min.css.map new file mode 100644 index 00000000..6e7f44f9 --- /dev/null +++ b/assets/stylesheets/main.a57b2b03.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["src/assets/stylesheets/main/extensions/pymdownx/_keys.scss","src/assets/stylesheets/main.scss","src/assets/stylesheets/main/_reset.scss","src/assets/stylesheets/main/_colors.scss","src/assets/stylesheets/main/_icons.scss","src/assets/stylesheets/main/_typeset.scss","src/assets/stylesheets/utilities/_break.scss","node_modules/material-shadows/material-shadows.scss","src/assets/stylesheets/main/layout/_base.scss","src/assets/stylesheets/main/layout/_announce.scss","src/assets/stylesheets/main/layout/_clipboard.scss","src/assets/stylesheets/main/layout/_content.scss","src/assets/stylesheets/main/layout/_dialog.scss","src/assets/stylesheets/main/layout/_form.scss","src/assets/stylesheets/main/layout/_header.scss","src/assets/stylesheets/main/layout/_footer.scss","src/assets/stylesheets/main/layout/_nav.scss","src/assets/stylesheets/main/layout/_search.scss","src/assets/stylesheets/main/layout/_select.scss","src/assets/stylesheets/main/layout/_sidebar.scss","src/assets/stylesheets/main/layout/_source.scss","src/assets/stylesheets/main/layout/_tabs.scss","src/assets/stylesheets/main/layout/_top.scss","src/assets/stylesheets/main/layout/_version.scss","src/assets/stylesheets/main/extensions/markdown/_admonition.scss","node_modules/material-design-color/material-color.scss","src/assets/stylesheets/main/extensions/markdown/_footnotes.scss","src/assets/stylesheets/main/extensions/markdown/_toc.scss","src/assets/stylesheets/main/extensions/pymdownx/_arithmatex.scss","src/assets/stylesheets/main/extensions/pymdownx/_critic.scss","src/assets/stylesheets/main/extensions/pymdownx/_details.scss","src/assets/stylesheets/main/extensions/pymdownx/_emoji.scss","src/assets/stylesheets/main/extensions/pymdownx/_highlight.scss","src/assets/stylesheets/main/extensions/pymdownx/_tabbed.scss","src/assets/stylesheets/main/extensions/pymdownx/_tasklist.scss","src/assets/stylesheets/main/_modifiers.scss"],"names":[],"mappings":"AAkGQ,gBCq2GR,CC36GA,KAEE,6BAAA,CAAA,0BAAA,CAAA,yBAAA,CAAA,qBAAA,CADA,qBDzBF,CC8BA,iBAGE,kBD3BF,CC+BA,KACE,QD5BF,CCgCA,qBAIE,uCD7BF,CCiCA,EACE,aAAA,CACA,oBD9BF,CCkCA,GAME,QAAA,CAJA,sBAAA,CADA,aAAA,CAEA,aAAA,CAEA,gBAAA,CADA,SD7BF,CCmCA,MACE,aDhCF,CCoCA,QAEE,eDjCF,CCqCA,IACE,iBDlCF,CCsCA,MACE,wBAAA,CACA,gBDnCF,CCuCA,MAEE,eAAA,CACA,kBDpCF,CCwCA,OAKE,sBAAA,CACA,QAAA,CAFA,mBAAA,CADA,iBAAA,CAFA,QAAA,CACA,SDjCF,CCyCA,MACE,QAAA,CACA,YDtCF,CE9CA,MAGE,sCAAA,CACA,6CAAA,CACA,+CAAA,CACA,gDAAA,CACA,0BAAA,CACA,gDAAA,CACA,kDAAA,CACA,oDAAA,CAGA,6BAAA,CACA,oCAAA,CACA,mCAAA,CACA,0BAAA,CACA,gDAAA,CAGA,4BAAA,CACA,sDAAA,CACA,yBAAA,CACA,+CF2CF,CExCE,QAGE,0BAAA,CACA,0BAAA,CAGA,sCAAA,CACA,iCAAA,CACA,kCAAA,CACA,mCAAA,CACA,mCAAA,CACA,kCAAA,CACA,iCAAA,CACA,+CAAA,CACA,6DAAA,CACA,gEAAA,CACA,4DAAA,CACA,4DAAA,CACA,6DAAA,CAGA,6CAAA,CAGA,+CAAA,CAGA,2CAAA,CAGA,2CAAA,CACA,4CAAA,CAGA,8BAAA,CACA,kCAAA,CACA,qCAAA,CAGA,yCAAA,CAGA,mDAAA,CACA,mDAAA,CAGA,yBAAA,CACA,+CAAA,CACA,iDAAA,CACA,qCAAA,CACA,2CFsBJ,CGhGE,aAIE,iBAAA,CAHA,aAAA,CAEA,aAAA,CADA,YHqGJ,CI1GA,KACE,kCAAA,CACA,iCJ6GF,CIzGA,WAGE,mCAAA,CACA,oGJ4GF,CItGA,wBARE,6BJsHF,CI9GA,aAIE,4BAAA,CACA,gFJyGF,CI/FA,MACE,0NAAA,CACA,mNAAA,CACA,oNJkGF,CI3FA,YAGE,gCAAA,CAAA,kBAAA,CAFA,eAAA,CACA,eJ+FF,CI1FE,aAPF,YAQI,gBJ6FF,CACF,CI1FE,uGAME,YJ4FJ,CIxFE,eAEE,uCAAA,CAEA,aAAA,CACA,eAAA,CAJA,iBJ+FJ,CItFE,8BAPE,eAAA,CAGA,qBJiGJ,CI7FE,eAGE,kBAAA,CACA,eAAA,CAHA,oBJ4FJ,CIpFE,eAGE,gBAAA,CADA,eAAA,CAGA,qBAAA,CADA,eAAA,CAHA,mBJ0FJ,CIlFE,kBACE,eJoFJ,CIhFE,eAEE,eAAA,CACA,qBAAA,CAFA,YJoFJ,CI9EE,8BAGE,uCAAA,CAEA,cAAA,CADA,eAAA,CAEA,qBAAA,CAJA,eJoFJ,CI5EE,eACE,wBJ8EJ,CI1EE,eAGE,+DAAA,CAFA,iBAAA,CACA,cJ6EJ,CIxEE,cACE,+BAAA,CACA,qBJ0EJ,CIvEI,mCAEE,sBJwEN,CIpEI,wCAEE,+BJqEN,CIjEI,4BACE,uCAAA,CACA,oBJmEN,CI9DE,iDAGE,6BAAA,CACA,aJgEJ,CI7DI,aAPF,iDAQI,oBJkEJ,CACF,CI9DE,iBAIE,wCAAA,CACA,mBAAA,CACA,kCAAA,CAAA,0BAAA,CAJA,eAAA,CADA,uBAAA,CAEA,qBJmEJ,CI7DI,qCAEE,uCAAA,CADA,YJgEN,CI1DE,wHAQE,4BAAA,CACA,eAAA,CAHA,cAAA,CACA,eJ8DJ,CIxDE,mBACE,kBJ0DJ,CItDE,gBAEE,iBAAA,CACA,eAAA,CAFA,iBJ0DJ,CIrDI,qBAOE,kCAAA,CAAA,0BAAA,CADA,eAAA,CALA,aAAA,CACA,QAAA,CAEA,aAAA,CADA,oCAAA,CAOA,+DAAA,CADA,oBAAA,CADA,iBAAA,CAHA,iBJ4DN,CIpDM,2BACE,qDJsDR,CIlDM,wCAEE,YAAA,CADA,WJqDR,CIhDM,8CACE,oDJkDR,CI/CQ,oDACE,0CJiDV,CK/FI,wCDwDA,gBACE,iBJ0CJ,CIvCI,qBACE,eJyCN,CACF,CIpCE,gBAOE,4CAAA,CACA,mBAAA,CACA,mKACE,CAPF,gCAAA,CAFA,oBAAA,CAGA,eAAA,CAFA,uBAAA,CAGA,uBAAA,CACA,qBJyCJ,CI/BE,iBAGE,6CAAA,CACA,kCAAA,CAAA,0BAAA,CAHA,aAAA,CACA,qBJmCJ,CI7BE,iBAEE,6DAAA,CACA,WAAA,CAFA,oBJiCJ,CI5BI,oBANF,iBAOI,iBJ+BJ,CI5BI,wEAcE,2CAAA,CACA,mBAAA,CE/SN,gGAAA,CF4SM,gCAAA,CAIA,mBAAA,CAVA,oBAAA,CAOA,eAAA,CARA,MAAA,CAKA,cAAA,CADA,aAAA,CADA,6BAAA,CAAA,0BAAA,CAAA,qBAAA,CAGA,mBAAA,CAPA,iBAAA,CAGA,UJqCN,CACF,CIvBE,kBACE,WJyBJ,CIrBE,gCAEE,qBJuBJ,CIpBI,oDAEE,aAAA,CADA,sBJwBN,CIlBE,uBAGE,2DAAA,CADA,uCAAA,CADA,kBJsBJ,CIjBI,iCAIE,mBAAA,CADA,4DAAA,CADA,cAAA,CADA,mBJsBN,CIdE,eACE,oBJgBJ,CIZE,8BAEE,iBAAA,CACA,kBAAA,CACA,SJcJ,CIXI,kDAEE,aAAA,CADA,mBJeN,CIVI,oCACE,2BJaN,CIVM,0CACE,2BJaR,CIRI,oCACE,kBAAA,CACA,kBJWN,CIRM,wDAEE,aAAA,CADA,mBJYR,CIPM,kGAEE,aJWR,CIPM,0DACE,eJUR,CINM,oFAEE,yBJUR,CIPQ,4HAEE,aAAA,CADA,mBJaV,CILE,eACE,0BJOJ,CIJI,yBAEE,aAAA,CADA,oBJON,CIDE,gCAGE,WAAA,CADA,cJIJ,CIAI,wDAEE,oBJGN,CICI,0DAEE,oBJEN,CIEI,oEACE,YJCN,CIIE,mBACE,iBAAA,CAGA,aAAA,CADA,cAAA,CAEA,iBAAA,CAHA,yBAAA,CAAA,sBAAA,CAAA,iBJCJ,CIKI,uBACE,aJHN,CIQE,uBAGE,iBAAA,CADA,mBAAA,CADA,eJJJ,CIUE,mBACE,cJRJ,CIYE,+BAKE,2CAAA,CACA,iDAAA,CACA,mBAAA,CANA,oBAAA,CAGA,gBAAA,CAFA,cAAA,CACA,aAAA,CAKA,iBJVJ,CIaI,aAXF,+BAYI,aJVJ,CACF,CIeI,iCACE,gBJbN,CIqBM,8FACE,YJlBR,CIsBM,4FACE,eJnBR,CIwBI,8FAEE,eJtBN,CIyBM,kHACE,gBJtBR,CI2BI,kCAGE,eAAA,CAFA,cAAA,CACA,sBAAA,CAEA,kBJzBN,CI4BM,oCACE,aJ1BR,CI+BI,kCAGE,qDAAA,CAFA,sBAAA,CACA,kBJ5BN,CIiCI,wCACE,iCJ/BN,CIkCM,8CACE,iCAAA,CACA,sDJhCR,CIqCI,iCACE,iBJnCN,CIwCE,wCACE,cJtCJ,CIyCI,8CAUE,UAAA,CATA,oBAAA,CAEA,YAAA,CACA,gBAAA,CAEA,oDAAA,CAAA,4CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CACA,iCAAA,CAJA,0BAAA,CAHA,WJ/BN,CI2CI,oDACE,oDJzCN,CI6CI,mEACE,kDAAA,CACA,yDAAA,CAAA,iDJ3CN,CI+CI,oEACE,kDAAA,CACA,0DAAA,CAAA,kDJ7CN,CIkDE,wBACE,iBAAA,CACA,eAAA,CACA,iBJhDJ,CIoDE,mBACE,oBAAA,CACA,kBAAA,CACA,eJlDJ,CIqDI,aANF,mBAOI,aJlDJ,CACF,CIqDI,8BACE,aAAA,CAEA,QAAA,CACA,eAAA,CAFA,UJjDN,CO9iBA,KASE,cAAA,CARA,WAAA,CACA,iBPkjBF,CK9YI,oCEtKJ,KAaI,gBP2iBF,CACF,CKnZI,oCEtKJ,KAkBI,cP2iBF,CACF,COtiBA,KASE,2CAAA,CAPA,YAAA,CACA,qBAAA,CAKA,eAAA,CAHA,eAAA,CAJA,iBAAA,CAGA,UP4iBF,COpiBE,aAZF,KAaI,aPuiBF,CACF,CKpZI,wCEhJF,yBAII,cPoiBJ,CACF,CO3hBA,SAGE,gBAAA,CADA,iBAAA,CADA,ePgiBF,CO1hBA,cACE,YAAA,CACA,qBAAA,CACA,WP6hBF,CO1hBE,aANF,cAOI,aP6hBF,CACF,COzhBA,SACE,WP4hBF,COzhBE,gBACE,YAAA,CACA,WAAA,CACA,iBP2hBJ,COthBA,aACE,eAAA,CAEA,sBAAA,CADA,kBP0hBF,COhhBA,WACE,YPmhBF,CO9gBA,WAGE,QAAA,CACA,SAAA,CAHA,iBAAA,CACA,OPmhBF,CO9gBE,uCACE,aPghBJ,CO5gBE,+BAEE,uCAAA,CADA,kBP+gBJ,COzgBA,SASE,2CAAA,CACA,mBAAA,CAHA,gCAAA,CACA,gBAAA,CAHA,YAAA,CAQA,SAAA,CAFA,uCAAA,CALA,mBAAA,CALA,cAAA,CAWA,2BAAA,CARA,UPmhBF,COvgBE,eAGE,SAAA,CADA,uBAAA,CAEA,oEACE,CAJF,UP4gBJ,CO9fA,MACE,WPigBF,CQ5pBA,aAEE,0CAAA,CADA,aR+pBF,CQ3pBE,aALF,aAMI,YR8pBF,CACF,CQ3pBE,oBAGE,+BAAA,CACA,eAAA,CAHA,iBAAA,CACA,eR+pBJ,CS3qBA,MACE,+PT8qBF,CSxqBA,cAQE,mBAAA,CADA,0CAAA,CAIA,cAAA,CALA,YAAA,CAGA,uCAAA,CACA,oBAAA,CATA,iBAAA,CAEA,UAAA,CADA,QAAA,CAUA,qBAAA,CAPA,WAAA,CADA,STmrBF,CSxqBE,aAfF,cAgBI,YT2qBF,CACF,CSxqBE,kCAEE,uCAAA,CADA,YT2qBJ,CStqBE,qBACE,uCTwqBJ,CSpqBE,wCAEE,+BTqqBJ,CShqBE,oBAKE,6BAAA,CAIA,UAAA,CARA,aAAA,CAEA,cAAA,CACA,aAAA,CAEA,2CAAA,CAAA,mCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CANA,aTyqBJ,CS9pBE,sBACE,cTgqBJ,CS7pBI,2BACE,2CT+pBN,CSzpBI,kEAGE,uDAAA,CADA,+BT2pBN,CUluBA,YACE,WAAA,CAMA,eAAA,CACA,0BVguBF,CU7tBE,mBACE,qBAAA,CACA,iBV+tBJ,CKtkBI,sCKhJI,4EACE,kBVytBR,CUrtBM,4EACE,mBVutBR,CU/sBM,8EACE,mBVitBR,CU7sBM,8EACE,kBV+sBR,CACF,CUzsBI,0BAGE,UAAA,CAFA,aAAA,CACA,YV4sBN,CUvsBI,+BACE,eVysBN,CUnsBE,oBACE,WAAA,CAEA,0BAAA,CACA,SVqsBJ,CUlsBI,aAPF,oBAQI,YVqsBJ,CACF,CUlsBI,8BACE,UAAA,CAEA,aAAA,CADA,kBVqsBN,CUjsBM,kCACE,oBVmsBR,CU9rBI,gCACE,yCVgsBN,CU5rBI,wBACE,cAAA,CACA,kBV8rBN,CW5xBA,WAUE,2CAAA,CACA,mBAAA,CANA,YAAA,CLPA,gGAAA,CKQA,SAAA,CAEA,iBAAA,CAKA,SAAA,CAJA,mBAAA,CAQA,mBAAA,CAdA,cAAA,CACA,WAAA,CAQA,0BAAA,CAEA,wCACE,CARF,SXsyBF,CWzxBE,aApBF,WAqBI,YX4xBF,CACF,CWzxBE,qBAEE,UAAA,CADA,UX4xBJ,CWvxBE,+BAEE,SAAA,CAIA,mBAAA,CALA,uBAAA,CAEA,kEX0xBJ,CWnxBE,kBACE,gCAAA,CACA,eXqxBJ,CY7zBE,uBAKE,kBAAA,CACA,mBAAA,CAHA,gCAAA,CAIA,cAAA,CANA,oBAAA,CAGA,eAAA,CAFA,kBAAA,CAMA,gEZg0BJ,CY1zBI,gCAEE,2CAAA,CACA,uCAAA,CAFA,gCZ8zBN,CYxzBI,0DAGE,0CAAA,CACA,sCAAA,CAFA,+BZ2zBN,CYpzBE,sBAIE,mBAAA,CACA,uEACE,CAHF,eAAA,CAFA,aAAA,CACA,eAAA,CAMA,0BZozBJ,CYjzBI,wDAEE,wEZkzBN,CY5yBI,+BACE,UZ8yBN,Cal2BA,WAOE,2CAAA,CAGA,0DACE,CALF,gCAAA,CAFA,MAAA,CAHA,uBAAA,CAAA,eAAA,CAEA,OAAA,CADA,KAAA,CAGA,Sbw2BF,Ca91BE,aAfF,WAgBI,Ybi2BF,CACF,Ca91BE,iCACE,gEACE,CAEF,kEb81BJ,Cax1BE,iCACE,2BAAA,CACA,iEb01BJ,Cap1BE,kBAEE,kBAAA,CADA,YAAA,CAEA,ebs1BJ,Cal1BE,mBAKE,kBAAA,CAGA,cAAA,CALA,YAAA,CAIA,uCAAA,CAHA,aAAA,CAHA,iBAAA,CAQA,uBAAA,CAHA,qBAAA,CAJA,Sb21BJ,Caj1BI,yBACE,Ubm1BN,Ca/0BI,iCACE,oBbi1BN,Ca70BI,uCAEE,uCAAA,CADA,Ybg1BN,Ca30BI,2BACE,YAAA,CACA,ab60BN,CKhuBI,wCQ/GA,2BAMI,Yb60BN,CACF,Ca10BM,8DAKE,iBAAA,CAHA,aAAA,CAEA,aAAA,CADA,Yb80BR,CK/vBI,mCQxEA,iCAII,Ybu0BN,CACF,Cap0BM,wCACE,Ybs0BR,Ca/zBQ,+CACE,oBbi0BV,CK1wBI,sCQjDA,iCAII,Yb2zBN,CACF,CatzBE,kBAEE,YAAA,CACA,cAAA,CAFA,iBAAA,CAGA,8DbwzBJ,CanzBI,oCAGE,SAAA,CAIA,mBAAA,CALA,6BAAA,CAEA,8DACE,CAJF,UbyzBN,CahzBM,8CACE,8BbkzBR,Ca5yBE,kBACE,WAAA,CAIA,eAAA,CAHA,aAAA,CAIA,kBAAA,CAFA,gBAAA,CADA,kBbizBJ,Ca3yBI,0DAGE,SAAA,CAIA,mBAAA,CALA,8BAAA,CAEA,8DACE,CAJF,UbizBN,CaxyBM,oEACE,6Bb0yBR,CatyBM,4EAGE,SAAA,CAIA,mBAAA,CALA,uBAAA,CAEA,8DACE,CAJF,Sb4yBR,CajyBI,uCAGE,WAAA,CAFA,iBAAA,CACA,UboyBN,Ca9xBE,mBACE,YAAA,CACA,aAAA,CACA,cAAA,CAEA,+CACE,CAFF,kBbiyBJ,Ca3xBI,8DACE,WAAA,CACA,SAAA,CACA,oCb6xBN,CatxBE,mBACE,YbwxBJ,CK50BI,mCQmDF,mBAKI,aAAA,CAGA,gBAAA,CADA,iBAAA,CADA,ab0xBJ,CarxBI,6BAEE,aAAA,CADA,iBbwxBN,CACF,CKx1BI,sCQmDF,mBAmBI,kBbsxBJ,CanxBI,6BACE,mBbqxBN,CACF,CctgCA,WAEE,0CAAA,CADA,+Bd0gCF,CctgCE,aALF,WAMI,YdygCF,CACF,CctgCE,kBAEE,aAAA,CADA,adygCJ,CcpgCE,iBACE,YAAA,CAGA,uCAAA,CADA,oBAAA,CADA,kBAAA,CAGA,uBdsgCJ,CKr3BI,mCStJF,iBASI,SdsgCJ,CACF,CcngCI,8CAEE,UdogCN,CchgCI,uBACE,UdkgCN,CK72BI,wCStJA,uBAKI,SdkgCN,Cc//BM,yCACE,YdigCR,CACF,Cc7/BM,iCACE,Wd+/BR,Cc5/BQ,qCACE,oBd8/BV,Ccx/BI,uBACE,WAAA,CACA,gBd0/BN,CK/3BI,wCS7HA,uBAMI,Sd0/BN,CACF,Ccv/BM,iCACE,UAAA,CACA,edy/BR,Cct/BQ,qCACE,oBdw/BV,Ccj/BE,kBAEE,WAAA,CAGA,eAAA,CACA,kBAAA,CAHA,6BAAA,CACA,cAAA,CAHA,iBdw/BJ,Cc/+BE,mBACE,YAAA,CACA,adi/BJ,Cc7+BE,sBAME,gBAAA,CAHA,MAAA,CACA,gBAAA,CAGA,UAAA,CAFA,cAAA,CAJA,iBAAA,CACA,Odo/BJ,Cc1+BA,gBACE,gDd6+BF,Cc1+BE,uBACE,YAAA,CACA,cAAA,CACA,6BAAA,CACA,ad4+BJ,Ccx+BE,kCACE,sCd0+BJ,Ccv+BI,gFAEE,+Bdw+BN,Ccl+BA,qBAIE,wCAAA,CACA,gBAAA,CAHA,iBAAA,CACA,eAAA,CAFA,Udy+BF,CK38BI,mCS/BJ,qBASI,Udq+BF,CACF,Ccj+BE,gCACE,sCdm+BJ,Cc99BA,kBACE,cAAA,CACA,qBdi+BF,CKx9BI,mCSXJ,kBAMI,edi+BF,CACF,Cc99BE,wBACE,oBAAA,CAEA,aAAA,CACA,iBAAA,CAFA,Ydk+BJ,Cc79BI,+BACE,ed+9BN,Cc39BI,4BAGE,iBAAA,CAFA,gBAAA,CACA,mBd89BN,CejpCA,MACE,0MAAA,CACA,gMAAA,CACA,yNfopCF,Ce9oCA,QACE,eAAA,CACA,efipCF,Ce9oCE,eACE,aAAA,CAGA,eAAA,CADA,eAAA,CADA,eAAA,CAGA,sBfgpCJ,Ce7oCI,+BACE,Yf+oCN,Ce5oCM,mCAEE,WAAA,CADA,Uf+oCR,CevoCQ,sFAKE,iBAAA,CAHA,aAAA,CAEA,aAAA,CADA,Yf2oCV,CeloCE,cAGE,eAAA,CAFA,QAAA,CACA,SfqoCJ,CehoCE,cACE,efkoCJ,Ce/nCI,4BACE,efioCN,Ce9nCM,sCAEE,cAAA,CADA,mBfioCR,Ce1nCE,cAEE,kBAAA,CAKA,cAAA,CANA,YAAA,CAEA,6BAAA,CACA,iBAAA,CACA,eAAA,CAIA,uBAAA,CAHA,sBAAA,CAEA,sBf6nCJ,CeznCI,kCACE,uCf2nCN,CevnCI,oCACE,+BfynCN,CernCI,0CACE,UfunCN,CennCI,wCAEE,+BfonCN,CehnCI,4BACE,uCAAA,CACA,oBfknCN,Ce9mCI,0CACE,YfgnCN,Ce7mCM,yDAKE,6BAAA,CAJA,aAAA,CAEA,WAAA,CACA,qCAAA,CAAA,6BAAA,CAFA,UfknCR,Ce3mCM,kDACE,Yf6mCR,CexmCI,gBAEE,cAAA,CADA,Yf2mCN,CermCE,gBACE,YfumCJ,CKtjCI,wCU1CA,0CAUE,2CAAA,CAHA,YAAA,CACA,qBAAA,CACA,WAAA,CAJA,MAAA,CAHA,iBAAA,CAEA,OAAA,CADA,KAAA,CAGA,SfsmCJ,Ce3lCI,+DAEE,eAAA,CACA,ef6lCN,CezlCI,gCAQE,qDAAA,CAJA,uCAAA,CAKA,cAAA,CAJA,eAAA,CAHA,aAAA,CAIA,kBAAA,CAHA,wBAAA,CAFA,iBAAA,CAMA,kBf6lCN,CexlCM,8CAIE,aAAA,CAEA,aAAA,CAHA,UAAA,CAIA,YAAA,CANA,iBAAA,CACA,SAAA,CAGA,Yf4lCR,CevlCQ,wDAEE,SAAA,CADA,Wf0lCV,CerlCQ,oDAIE,6BAAA,CAIA,UAAA,CAPA,aAAA,CAEA,WAAA,CAEA,2CAAA,CAAA,mCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CALA,Uf6lCV,CellCM,8CAEE,2CAAA,CACA,gEACE,CAHF,eAAA,CAIA,gCAAA,CAAA,4BAAA,CACA,kBfmlCR,CehlCQ,2DACE,YfklCV,Ce7kCM,8CAEE,2CAAA,CADA,gCfglCR,Ce3kCM,yCAIE,aAAA,CADA,UAAA,CAEA,YAAA,CACA,aAAA,CALA,iBAAA,CACA,SfilCR,Ce1kCQ,mDAEE,SAAA,CADA,Wf6kCV,CetkCI,+BACE,MfwkCN,CepkCI,+BAEE,4DAAA,CADA,SfukCN,CenkCM,qDACE,+BfqkCR,CelkCQ,sHAEE,+BfmkCV,Ce7jCI,+BACE,YAAA,CACA,mBf+jCN,Ce5jCM,6CACE,aAAA,CAIA,gBAAA,CAFA,aAAA,CACA,mBAAA,CAFA,YfikCR,Ce3jCQ,uDAEE,kBAAA,CADA,cf8jCV,CezjCQ,mDAIE,6BAAA,CAIA,UAAA,CAPA,aAAA,CAEA,WAAA,CAEA,2CAAA,CAAA,mCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CALA,UfikCV,CeljCM,+CACE,mBfojCR,Ce5iCM,4CAEE,4BAAA,CADA,ef+iCR,Ce3iCQ,0DACE,mBf6iCV,Ce1iCU,oEAEE,cAAA,CADA,oBf6iCZ,CeviCQ,kEACE,iBfyiCV,CetiCU,4EAEE,cAAA,CADA,kBfyiCZ,CeniCQ,0EACE,mBfqiCV,CeliCU,oFAEE,cAAA,CADA,oBfqiCZ,Ce/hCQ,kFACE,mBfiiCV,Ce9hCU,4FAEE,cAAA,CADA,oBfiiCZ,CexhCE,mBACE,4Bf0hCJ,CethCE,wBACE,YAAA,CAEA,SAAA,CADA,0BAAA,CAEA,oEfwhCJ,CenhCI,kCACE,2BfqhCN,CehhCE,gCAEE,SAAA,CADA,uBAAA,CAEA,qEfkhCJ,Ce7gCI,8CAEE,kCAAA,CAAA,0Bf8gCN,CACF,CKjuCI,wCU2NA,0CACE,YfygCJ,CetgCI,yDACE,UfwgCN,CepgCI,wDACE,YfsgCN,CelgCI,kDACE,YfogCN,Ce//BE,gBAIE,iDAAA,CADA,gCAAA,CAFA,aAAA,CACA,efmgCJ,CACF,CK9xCM,6DUoSF,6CACE,Yf6/BJ,Ce1/BI,4DACE,Uf4/BN,Cex/BI,2DACE,Yf0/BN,Cet/BI,qDACE,Yfw/BN,CACF,CKtxCI,mCUySE,6CACE,uBfg/BN,Ce5+BI,gDACE,Yf8+BN,CACF,CK9xCI,sCU7JJ,QAmdI,oDf4+BF,Cet+BI,8CACE,uBfw+BN,Cep+BI,8CACE,Yfs+BN,Cej+BE,wBACE,Yfm+BJ,Ce/9BE,sEAEE,afg+BJ,Ce59BE,6CACE,Yf89BJ,Ce19BE,uBACE,aAAA,CACA,ef49BJ,Cez9BI,kCACE,ef29BN,Cev9BI,qCACE,eAAA,CACA,mBfy9BN,Cet9BM,mDACE,mBfw9BR,Cep9BM,mDACE,Yfs9BR,Cej9BI,+BACE,afm9BN,Ceh9BM,2DACE,Sfk9BR,Ce58BE,cACE,WAAA,CAEA,YAAA,CACA,yBAAA,CAFA,Wfg9BJ,Ce38BI,wBACE,UAAA,CACA,wBf68BN,Cez8BI,oBAKE,6BAAA,CAIA,UAAA,CARA,oBAAA,CAEA,WAAA,CAGA,2CAAA,CAAA,mCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CAJA,qBAAA,CAFA,Ufk9BN,Cev8BI,0JAEE,uBfw8BN,Ceh8BI,mFAEE,Yfk8BN,Ce97BI,4CACE,Yfg8BN,Ce77BM,oDACE,aAAA,CACA,Sf+7BR,Ce57BQ,kEAGE,eAAA,CAFA,YAAA,CACA,eAAA,CAEA,mBf87BV,Ce37BU,gFACE,mBf67BZ,Cez7BU,gFACE,Yf27BZ,Cen7BI,2CACE,afq7BN,Cel7BM,uEACE,mBfo7BR,Ce36BI,mFACE,ef66BN,Ce16BM,iGACE,Sf46BR,Cev6BI,2EAGE,mDAAA,CAFA,aAAA,CACA,oBf06BN,Cet6BM,0FACE,Yfw6BR,CACF,CgBljDA,MACE,igBhBqjDF,CgB/iDA,WACE,iBhBkjDF,CKp5CI,mCW/JJ,WAKI,ehBkjDF,CACF,CgB/iDE,kBACE,YhBijDJ,CgB7iDE,oBAEE,SAAA,CADA,ShBgjDJ,CK74CI,wCWpKF,oBAYI,2CAAA,CACA,kBAAA,CAHA,WAAA,CAFA,YAAA,CAGA,eAAA,CAOA,mBAAA,CAZA,iBAAA,CACA,SAAA,CAOA,uBAAA,CACA,4CACE,CAPF,UhBsjDJ,CgB1iDI,8BAEE,SAAA,CADA,ahB6iDN,CgBxiDI,+DACE,SAAA,CACA,oChB0iDN,CACF,CKv7CI,mCWjJF,oBA0CI,gCAAA,CACA,cAAA,CAFA,QAAA,CAFA,MAAA,CAFA,cAAA,CACA,KAAA,CAMA,sDACE,CALF,OhB2iDJ,CgBjiDI,8BAEE,SAAA,CADA,OhBoiDN,CgB/hDI,+DAME,YAAA,CACA,SAAA,CACA,4CACE,CARF,UhBoiDN,CACF,CK17CI,wCW5FA,+DAII,mBhBshDN,CACF,CKx+CM,6DWnDF,+DASI,mBhBshDN,CACF,CK7+CM,6DWnDF,+DAcI,mBhBshDN,CACF,CgBjhDE,kBAEE,kCAAA,CAAA,0BhBkhDJ,CK58CI,wCWxEF,kBAWI,QAAA,CAHA,MAAA,CAMA,SAAA,CAFA,eAAA,CANA,cAAA,CACA,KAAA,CAMA,wBAAA,CAEA,qGACE,CANF,OAAA,CADA,ShBwhDJ,CgB3gDI,4BAEE,SAAA,CADA,OAAA,CAEA,yBhB6gDN,CgBzgDI,6DAEE,WAAA,CAEA,SAAA,CADA,uBAAA,CAEA,sGACE,CALF,UhB+gDN,CACF,CKz/CI,mCWrDF,kBA6CI,WAAA,CAEA,eAAA,CAHA,iBAAA,CAIA,8CAAA,CAFA,ahBwgDJ,CgBngDI,4BACE,UhBqgDN,CACF,CK3hDM,6DW0BF,6DAII,ahBigDN,CACF,CK1gDI,sCWIA,6DASI,ahBigDN,CACF,CgB5/CE,iBAIE,2CAAA,CACA,gCAAA,CAFA,aAAA,CAFA,iBAAA,CAKA,2CACE,CALF,ShBkgDJ,CKvhDI,mCWmBF,iBAaI,gCAAA,CACA,mBAAA,CAFA,ahB8/CJ,CgBz/CI,uBACE,oChB2/CN,CACF,CgBv/CI,4DAEE,2CAAA,CACA,6BAAA,CACA,oCAAA,CAHA,gChB4/CN,CgBp/CE,kBAQE,sBAAA,CAFA,eAAA,CAFA,WAAA,CACA,yBAAA,CAJA,iBAAA,CAMA,sBAAA,CAJA,UAAA,CADA,ShB4/CJ,CgBn/CI,4BACE,yBhBq/CN,CgBj/CI,6CACE,6BAAA,CAAA,qBhBm/CN,CgBp/CI,oCACE,0BAAA,CAAA,qBhBm/CN,CgBp/CI,yCACE,yBAAA,CAAA,qBhBm/CN,CgBp/CI,+BACE,qBhBm/CN,CgB/+CI,6CAEE,uChBg/CN,CgBl/CI,oCAEE,uChBg/CN,CgBl/CI,yCAEE,uChBg/CN,CgBl/CI,kEAEE,uChBg/CN,CgB5+CI,6BACE,YhB8+CN,CK1iDI,wCWgCF,kBAmCI,eAAA,CADA,aAAA,CADA,UhB++CJ,CACF,CKpkDI,mCWmDF,kBAyCI,aAAA,CACA,eAAA,CAFA,mBhB++CJ,CgB1+CI,4BACE,oBhB4+CN,CgBx+CI,6CACE,uChB0+CN,CgB3+CI,oCACE,uChB0+CN,CgB3+CI,yCACE,uChB0+CN,CgB3+CI,+BACE,uChB0+CN,CgBt+CI,mCACE,gChBw+CN,CgBp+CI,6DACE,kBhBs+CN,CgBn+CM,wFAEE,uChBo+CR,CgBt+CM,+EAEE,uChBo+CR,CgBt+CM,oFAEE,uChBo+CR,CgBt+CM,wJAEE,uChBo+CR,CACF,CgB99CE,iBAIE,cAAA,CAHA,oBAAA,CAEA,aAAA,CAEA,kCACE,CAJF,YhBm+CJ,CgB39CI,uBACE,UhB69CN,CgBz9CI,+BAGE,UAAA,CAFA,iBAAA,CACA,SAAA,CAEA,ShB29CN,CgBx9CM,yCAEE,SAAA,CADA,WhB29CR,CgBv9CQ,6CACE,oBhBy9CV,CK9lDI,wCWwHA,+BAoBI,UAAA,CADA,ShBw9CN,CgBp9CM,yCAEE,SAAA,CADA,WhBu9CR,CgBl9CM,+CACE,YhBo9CR,CACF,CK9nDI,mCW2IA,+BAoCI,mBhBm9CN,CgBh9CM,8CACE,YhBk9CR,CACF,CgB58CE,oBAKE,mBAAA,CAJA,iBAAA,CAEA,WAAA,CADA,SAAA,CAEA,ShB+8CJ,CgB38CI,8BAEE,UAAA,CADA,UhB88CN,CK9nDI,wCWuKF,oBAgBI,WAAA,CADA,ShB68CJ,CgBz8CI,8BAEE,UAAA,CADA,UhB48CN,CACF,CgBv8CI,sBAEE,uCAAA,CADA,iBAAA,CAGA,SAAA,CADA,oBAAA,CAEA,+DhBy8CN,CgBp8CM,yCAEE,uCAAA,CADA,YhBu8CR,CgBl8CM,yFAGE,SAAA,CACA,mBAAA,CAFA,kBhBq8CR,CgBh8CQ,8FACE,UhBk8CV,CgB37CE,oBAIE,kBAAA,CAIA,yCAAA,CALA,YAAA,CAMA,eAAA,CAHA,WAAA,CAKA,SAAA,CAJA,yBAAA,CANA,iBAAA,CACA,KAAA,CAUA,uBAAA,CAFA,kBAAA,CALA,UhBo8CJ,CgB17CI,8BACE,yBhB47CN,CK/rDI,mCWmPF,oBAsBI,eAAA,CADA,mBhB47CJ,CgBx7CI,8BACE,oBhB07CN,CACF,CgBt7CI,+DACE,SAAA,CACA,0BhBw7CN,CgBn7CE,mBAKE,6BAAA,CADA,eAAA,CAHA,iBAAA,CAEA,UAAA,CADA,ShBw7CJ,CKhsDI,wCWsQF,mBAUI,QAAA,CADA,UhBs7CJ,CACF,CKztDI,mCWyRF,mBAgBI,SAAA,CADA,UAAA,CAEA,sBhBq7CJ,CgBl7CI,8DVncJ,kGAAA,CUscM,ShBm7CN,CACF,CgB96CE,uBAKE,kCAAA,CAAA,0BAAA,CAFA,2CAAA,CAFA,WAAA,CACA,eAAA,CAOA,kBhB46CJ,CgBz6CI,iEAZF,uBAaI,uBhB46CJ,CACF,CKtwDM,6DW4UJ,uBAkBI,ahB46CJ,CACF,CKrvDI,sCWsTF,uBAuBI,ahB46CJ,CACF,CK1vDI,mCWsTF,uBA4BI,YAAA,CAEA,+DAAA,CADA,oBhB66CJ,CgBz6CI,kEACE,ehB26CN,CgBv6CI,6BACE,qDhBy6CN,CgBr6CI,0CAEE,YAAA,CADA,WhBw6CN,CgBn6CI,gDACE,oDhBq6CN,CgBl6CM,sDACE,0ChBo6CR,CACF,CgB75CA,kBACE,gCAAA,CACA,qBhBg6CF,CgB75CE,wBAKE,qDAAA,CAHA,uCAAA,CACA,gBAAA,CACA,kBAAA,CAHA,eAAA,CAKA,uBhB+5CJ,CK9xDI,mCWyXF,wBAUI,mBhB+5CJ,CgB55CI,kCAEE,cAAA,CADA,oBhB+5CN,CACF,CgBz5CE,wBAGE,eAAA,CAFA,QAAA,CACA,ShB45CJ,CgBv5CE,wBACE,2DhBy5CJ,CgBt5CI,oCACE,ehBw5CN,CgBn5CE,wBACE,aAAA,CACA,YAAA,CAEA,uBAAA,CADA,gChBs5CJ,CgBl5CI,4DAEE,uDhBm5CN,CgB/4CI,gDACE,mBhBi5CN,CgB54CE,gCAGE,+BAAA,CAGA,cAAA,CALA,aAAA,CAGA,gBAAA,CACA,YAAA,CAHA,mBAAA,CAQA,uBAAA,CAHA,2ChB+4CJ,CKx0DI,mCWkbF,gCAcI,mBhB44CJ,CgBz4CI,0CAEE,kBAAA,CADA,oBhB44CN,CACF,CgBv4CI,4EAGE,uDAAA,CADA,+BhBy4CN,CgBp4CI,gGAEE,YhBq4CN,CgBj4CI,oCACE,WhBm4CN,CgB93CE,2BAGE,eAAA,CADA,eAAA,CADA,iBhBk4CJ,CKh2DI,mCW6dF,2BAOI,mBhBg4CJ,CgB73CI,qCAEE,kBAAA,CADA,oBhBg4CN,CACF,CgBx3CM,8DAGE,eAAA,CADA,eAAA,CAEA,eAAA,CAHA,ehB63CR,CgBp3CE,wBAME,uCAAA,CAFA,aAAA,CAFA,MAAA,CAGA,YAAA,CAJA,iBAAA,CAEA,YhBy3CJ,CKp2DI,wCWweF,wBAUI,YhBs3CJ,CACF,CgBn3CI,8BAIE,6BAAA,CAIA,UAAA,CAPA,oBAAA,CAEA,WAAA,CAEA,+CAAA,CAAA,uCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CALA,UhB23CN,CgBj3CI,kCAEE,SAAA,CADA,OhBo3CN,CgBh3CM,wCACE,oBhBk3CR,CgB52CE,yBAGE,gBAAA,CADA,eAAA,CAEA,eAAA,CAHA,ahBi3CJ,CgB12CE,0BASE,2BAAA,CACA,oBAAA,CALA,uCAAA,CAJA,mBAAA,CAKA,gBAAA,CACA,eAAA,CAJA,aAAA,CADA,eAAA,CAEA,eAAA,CAIA,sBhB82CJ,CK54DI,wCWshBF,0BAeI,oBAAA,CADA,ehB62CJ,CACF,CK37DM,6DW+jBJ,0BAqBI,oBAAA,CADA,ehB62CJ,CACF,CgBz2CI,+BAEE,4BAAA,CADA,yBhB42CN,CgBt2CE,yBAEE,gBAAA,CACA,iBAAA,CAFA,ahB02CJ,CgBp2CE,uBAEE,4BAAA,CADA,+BhBu2CJ,CiB9lEA,WACE,iBAAA,CACA,SjBimEF,CiB9lEE,kBAOE,2CAAA,CACA,mBAAA,CACA,kEACE,CAJF,gCAAA,CAHA,QAAA,CAEA,gBAAA,CADA,YAAA,CASA,SAAA,CAZA,iBAAA,CACA,sBAAA,CAUA,mCAAA,CAEA,oEjB8lEJ,CiBxlEI,6EAEE,gBAAA,CAEA,SAAA,CADA,+BAAA,CAEA,8EjBylEN,CiBllEI,wBAUE,qCAAA,CAAA,8CAAA,CAFA,mCAAA,CAAA,oCAAA,CACA,YAAA,CAEA,UAAA,CANA,QAAA,CAFA,QAAA,CAIA,kBAAA,CADA,iBAAA,CALA,iBAAA,CACA,KAAA,CAEA,OjB2lEN,CiB/kEE,iBAOE,mBAAA,CAFA,eAAA,CACA,oBAAA,CAJA,QAAA,CADA,kBAAA,CAGA,aAAA,CADA,SjBqlEJ,CiB7kEE,iBACE,kBjB+kEJ,CiB3kEE,iBAME,cAAA,CALA,aAAA,CAIA,YAAA,CADA,kBAAA,CADA,oBAAA,CAOA,uBAAA,CAHA,2CACE,CANF,UjBmlEJ,CiBxkEI,2BAEE,mBAAA,CADA,mBjB2kEN,CiBtkEI,8CAEE,+BjBukEN,CiBnkEI,uBACE,qDjBqkEN,CkBpqEA,YAIE,qBAAA,CADA,aAAA,CAGA,gBAAA,CALA,uBAAA,CAAA,eAAA,CACA,UAAA,CAGA,alBwqEF,CkBpqEE,aATF,YAUI,YlBuqEF,CACF,CKz/DI,wCaxKA,qBAQE,2CAAA,CAHA,aAAA,CAEA,WAAA,CAJA,aAAA,CAFA,cAAA,CACA,KAAA,CAOA,uBAAA,CACA,iEACE,CALF,aAAA,CAFA,SlB0qEJ,CkB/pEI,+BAEE,SAAA,CADA,clBkqEN,CkB7pEI,mEZhBJ,sGAAA,CYmBM,6BlB8pEN,CkB3pEM,6EACE,8BlB6pER,CkBxpEI,6CAIE,QAAA,CACA,MAAA,CACA,QAAA,CAEA,eAAA,CAPA,iBAAA,CAEA,OAAA,CAIA,yBAAA,CAAA,qBAAA,CALA,KlBgqEN,CACF,CK/iEI,sCatKJ,YAiEI,QlBwpEF,CkBrpEE,mBACE,WlBupEJ,CACF,CkBnpEE,uBACE,YAAA,CACA,OlBqpEJ,CK3jEI,mCa5FF,uBAMI,QlBqpEJ,CkBlpEI,8BACE,WlBopEN,CkBhpEI,qCACE,alBkpEN,CkB9oEI,+CACE,kBlBgpEN,CACF,CkB3oEE,wBAIE,kCAAA,CAAA,0BAAA,CAHA,cAAA,CACA,eAAA,CAQA,+DAAA,CADA,oBlByoEJ,CkBroEI,8BACE,qDlBuoEN,CkBnoEI,2CAEE,YAAA,CADA,WlBsoEN,CkBjoEI,iDACE,oDlBmoEN,CkBhoEM,uDACE,0ClBkoER,CK1kEI,wCa9CF,YAME,gCAAA,CADA,QAAA,CAEA,SAAA,CANA,cAAA,CACA,KAAA,CAMA,sDACE,CALF,OAAA,CADA,SlBioEF,CkBtnEE,4CAEE,WAAA,CACA,SAAA,CACA,4CACE,CAJF,UlB2nEJ,CACF,CmBtxEA,yBACE,GACE,QnBwxEF,CmBrxEA,GACE,anBuxEF,CACF,CmB9xEA,iBACE,GACE,QnBwxEF,CmBrxEA,GACE,anBuxEF,CACF,CmBnxEA,wBACE,GAEE,SAAA,CADA,0BnBsxEF,CmBlxEA,IACE,SnBoxEF,CmBjxEA,GAEE,SAAA,CADA,uBnBoxEF,CACF,CmBhyEA,gBACE,GAEE,SAAA,CADA,0BnBsxEF,CmBlxEA,IACE,SnBoxEF,CmBjxEA,GAEE,SAAA,CADA,uBnBoxEF,CACF,CmB3wEA,MACE,mgBAAA,CACA,oiBAAA,CACA,0nBAAA,CACA,mhBnB6wEF,CmBvwEA,WAOE,kCAAA,CAAA,0BAAA,CANA,aAAA,CACA,gBAAA,CACA,eAAA,CAEA,uCAAA,CAGA,uBAAA,CAJA,kBnB6wEF,CmBtwEE,iBACE,UnBwwEJ,CmBpwEE,iBACE,oBAAA,CAEA,aAAA,CACA,qBAAA,CAFA,UnBwwEJ,CmBnwEI,qBAEE,iBAAA,CADA,gBnBswEN,CmBlwEM,+BAEE,aAAA,CADA,kBnBqwER,CmB/vEI,wCACE,iBAAA,CACA,iBnBiwEN,CmB9vEM,kDAEE,aAAA,CADA,kBAAA,CAGA,cAAA,CADA,kBnBiwER,CmB1vEE,uBACE,oBAAA,CAEA,iBAAA,CADA,6BAAA,CAEA,eAAA,CACA,sBAAA,CACA,qBnB4vEJ,CmBxvEE,kBAIE,gBAAA,CACA,oBAAA,CAJA,gBAAA,CAKA,WAAA,CAHA,eAAA,CADA,SnB8vEJ,CmBvvEI,uCACE,oCAAA,CAAA,4BnByvEN,CmBpvEE,iBACE,oBnBsvEJ,CmBnvEI,sCACE,mCAAA,CAAA,2BnBqvEN,CmBjvEI,wBAME,6BAAA,CAGA,UAAA,CARA,oBAAA,CAEA,YAAA,CACA,kBAAA,CAGA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CAHA,uBAAA,CAHA,WnB0vEN,CmBhvEM,kCAEE,iBAAA,CADA,cnBmvER,CmB7uEI,wCACE,iBnB+uEN,CmB5uEM,kDAEE,iBAAA,CADA,kBnB+uER,CmBzuEI,iCACE,gDAAA,CAAA,wCnB2uEN,CmBvuEI,+BACE,8CAAA,CAAA,sCnByuEN,CmBruEI,+BACE,8CAAA,CAAA,sCnBuuEN,CmBnuEI,sCACE,qDAAA,CAAA,6CnBquEN,CoBj5EA,SAIE,2CAAA,CADA,gCAAA,CADA,aAAA,CADA,UpBu5EF,CoBj5EE,aAPF,SAQI,YpBo5EF,CACF,CKpuEI,wCezLJ,SAaI,YpBo5EF,CACF,CoBj5EE,+BACE,mBpBm5EJ,CoB/4EE,eAME,eAAA,CADA,eAAA,CAHA,kBAAA,CACA,SAAA,CACA,kBpBm5EJ,CoB94EI,yBAEE,aAAA,CADA,kBpBi5EN,CoB34EE,eACE,oBAAA,CACA,aAAA,CAEA,kBAAA,CADA,mBpB84EJ,CoBx4EE,eAOE,kCAAA,CAAA,0BAAA,CANA,aAAA,CAEA,eAAA,CADA,gBAAA,CAMA,UAAA,CAJA,uCAAA,CACA,oBAAA,CAIA,8DpBy4EJ,CoBp4EI,iEAGE,aAAA,CACA,SpBo4EN,CoB/3EM,2CACE,qBpBi4ER,CoBl4EM,2CACE,qBpBo4ER,CoBr4EM,2CACE,qBpBu4ER,CoBx4EM,2CACE,qBpB04ER,CoB34EM,2CACE,oBpB64ER,CoB94EM,2CACE,qBpBg5ER,CoBj5EM,2CACE,qBpBm5ER,CoBp5EM,2CACE,qBpBs5ER,CoBv5EM,4CACE,qBpBy5ER,CoB15EM,4CACE,oBpB45ER,CoB75EM,4CACE,qBpB+5ER,CoBh6EM,4CACE,qBpBk6ER,CoBn6EM,4CACE,qBpBq6ER,CoBt6EM,4CACE,qBpBw6ER,CoBz6EM,4CACE,oBpB26ER,CoBr6EI,8CAEE,SAAA,CADA,yBAAA,CAEA,wCpBu6EN,CqBv/EA,QAQE,2CAAA,CACA,oBAAA,CAEA,kEACE,CANF,uCAAA,CACA,eAAA,CAHA,eAAA,CAMA,YAAA,CALA,mBAAA,CAJA,cAAA,CACA,UAAA,CAYA,yBAAA,CACA,mGACE,CAbF,SrBogFF,CqBj/EE,aAtBF,QAuBI,YrBo/EF,CACF,CqBj/EE,kBAEE,aAAA,CADA,gBAAA,CAEA,wBrBm/EJ,CqB/+EE,8BAEE,SAAA,CAEA,mBAAA,CAHA,+BAAA,CAEA,uBrBk/EJ,CqB9+EI,wCACE,8BrBg/EN,CqB3+EE,4BAGE,0CAAA,CADA,+BrB6+EJ,CqBx+EE,YACE,oBAAA,CACA,oBrB0+EJ,CsBliFA,4BACE,GACE,mBtBqiFF,CACF,CsBxiFA,oBACE,GACE,mBtBqiFF,CACF,CsB7hFA,MACE,iQtB+hFF,CsBzhFA,YACE,aAAA,CAEA,eAAA,CADA,atB6hFF,CsBzhFE,qBASE,aAAA,CAEA,cAAA,CAHA,kBAAA,CADA,kBAAA,CAGA,YAAA,CATA,iBAAA,CAKA,UtB4hFJ,CsBphFI,+BAEE,iBAAA,CADA,mBtBuhFN,CsBlhFI,2BAKE,6BAAA,CAGA,UAAA,CAPA,oBAAA,CAEA,YAAA,CACA,iBAAA,CAEA,yCAAA,CAAA,iCAAA,CACA,6BAAA,CAAA,qBAAA,CALA,WtB0hFN,CsBjhFM,qCAEE,aAAA,CADA,kBtBohFR,CsB7gFE,kBAUE,2CAAA,CACA,mBAAA,CACA,kEACE,CALF,gCAAA,CACA,oBAAA,CAJA,kBAAA,CADA,YAAA,CAWA,SAAA,CARA,aAAA,CADA,SAAA,CALA,iBAAA,CAkBA,gCAAA,CAAA,4BAAA,CAjBA,UAAA,CAcA,+CACE,CAdF,StB2hFJ,CsBxgFI,+EAEE,gBAAA,CACA,SAAA,CACA,sCtBygFN,CsBngFI,wBAGE,oCACE,wCAAA,CAAA,gCtBmgFN,CsB//EI,2CACE,sBAAA,CAAA,ctBigFN,CACF,CsB5/EE,kBACE,kBtB8/EJ,CsB1/EE,kBAOE,cAAA,CANA,aAAA,CAKA,YAAA,CAFA,kBAAA,CADA,oBAAA,CAQA,uBAAA,CAHA,2CACE,CAJF,kBAAA,CAHA,UtBmgFJ,CsBv/EI,4BAEE,mBAAA,CADA,mBtB0/EN,CsBr/EI,gDAEE,+BtBs/EN,CsBl/EI,wBACE,qDtBo/EN,CuB3mFA,MAEI,2RAAA,CAAA,8WAAA,CAAA,sPAAA,CAAA,8xBAAA,CAAA,qNAAA,CAAA,gbAAA,CAAA,gMAAA,CAAA,+PAAA,CAAA,8KAAA,CAAA,0eAAA,CAAA,kUAAA,CAAA,gMvBooFJ,CuBznFE,4CAOE,8CAAA,CACA,+BAAA,CACA,mBAAA,CACA,yEACE,CAPF,mCAAA,CACA,gBAAA,CAJA,iBAAA,CAEA,eAAA,CADA,eAAA,CAIA,uBvBgoFJ,CuBvnFI,aAfF,4CAgBI,evB0nFJ,CACF,CuBvnFI,gEAEE,gBAAA,CADA,gCvB0nFN,CuBrnFI,gIAEE,iBAAA,CADA,cvBwnFN,CuBnnFI,4FACE,iBvBqnFN,CuBjnFI,kFACE,evBmnFN,CuB/mFI,0FACE,YvBinFN,CuB7mFI,8EACE,mBvB+mFN,CuB1mFE,kDAKE,oCAAA,CACA,+BAAA,CAFA,eAAA,CAFA,wBAAA,CACA,8BAAA,CAFA,iBvBinFJ,CuBzmFI,sEAIE,gBAAA,CADA,gCAAA,CAFA,wBAAA,CACA,8BvB6mFN,CuBvmFI,kFACE,evBymFN,CuBrmFI,gEAKE,wBCqIU,CDjIV,UAAA,CALA,WAAA,CAFA,UAAA,CAIA,kDAAA,CAAA,0CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CAPA,iBAAA,CAEA,UvB6mFN,CuBpmFM,oFAEE,SAAA,CADA,WvBumFR,CuBvlFE,sDACE,oBvB0lFJ,CuBtlFE,8DACE,oCAAA,CACA,oBvBylFJ,CuBtlFI,4EACE,wBAdG,CAeH,kDAAA,CAAA,0CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBvBwlFN,CuBtmFE,gLACE,oBvBymFJ,CuBrmFE,wMACE,mCAAA,CACA,oBvBwmFJ,CuBrmFI,kPACE,wBAdG,CAeH,sDAAA,CAAA,8CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBvBumFN,CuBrnFE,4GACE,oBvBwnFJ,CuBpnFE,4HACE,mCAAA,CACA,oBvBunFJ,CuBpnFI,wJACE,wBAdG,CAeH,kDAAA,CAAA,0CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBvBsnFN,CuBpoFE,0KACE,oBvBuoFJ,CuBnoFE,kMACE,mCAAA,CACA,oBvBsoFJ,CuBnoFI,4OACE,wBAdG,CAeH,iDAAA,CAAA,yCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBvBqoFN,CuBnpFE,0KACE,oBvBspFJ,CuBlpFE,kMACE,kCAAA,CACA,oBvBqpFJ,CuBlpFI,4OACE,wBAdG,CAeH,qDAAA,CAAA,6CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBvBopFN,CuBlqFE,wKACE,oBvBqqFJ,CuBjqFE,gMACE,oCAAA,CACA,oBvBoqFJ,CuBjqFI,0OACE,wBAdG,CAeH,sDAAA,CAAA,8CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBvBmqFN,CuBjrFE,wLACE,oBvBorFJ,CuBhrFE,gNACE,mCAAA,CACA,oBvBmrFJ,CuBhrFI,0PACE,wBAdG,CAeH,qDAAA,CAAA,6CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBvBkrFN,CuBhsFE,8KACE,oBvBmsFJ,CuB/rFE,sMACE,mCAAA,CACA,oBvBksFJ,CuB/rFI,gPACE,wBAdG,CAeH,qDAAA,CAAA,6CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBvBisFN,CuB/sFE,kHACE,oBvBktFJ,CuB9sFE,kIACE,mCAAA,CACA,oBvBitFJ,CuB9sFI,8JACE,wBAdG,CAeH,oDAAA,CAAA,4CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBvBgtFN,CuB9tFE,oDACE,oBvBiuFJ,CuB7tFE,4DACE,kCAAA,CACA,oBvBguFJ,CuB7tFI,0EACE,wBAdG,CAeH,iDAAA,CAAA,yCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBvB+tFN,CuB7uFE,4DACE,oBvBgvFJ,CuB5uFE,oEACE,oCAAA,CACA,oBvB+uFJ,CuB5uFI,kFACE,wBAdG,CAeH,qDAAA,CAAA,6CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBvB8uFN,CuB5vFE,8GACE,oBvB+vFJ,CuB3vFE,8HACE,kCAAA,CACA,oBvB8vFJ,CuB3vFI,0JACE,wBAdG,CAeH,mDAAA,CAAA,2CAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBvB6vFN,CyBv5FA,MACE,wMzB05FF,CyBj5FE,sBACE,uCAAA,CACA,gBzBo5FJ,CyBj5FI,yBACE,azBm5FN,CyB/4FM,4BACE,sBzBi5FR,CyB94FQ,mCACE,gCzBg5FV,CyB54FQ,yGAGE,SAAA,CADA,uBzB84FV,CyBz4FQ,yCACE,YzB24FV,CyBp4FE,0BAEE,eAAA,CADA,ezBu4FJ,CyBn4FI,+BACE,oBzBq4FN,CyBh4FE,8BAEE,+BAAA,CADA,oBAAA,CAGA,WAAA,CAGA,SAAA,CADA,4BAAA,CAEA,4DACE,CAJF,0BzBo4FJ,CyB33FI,aAdF,8BAeI,+BAAA,CAEA,SAAA,CADA,uBzB+3FJ,CACF,CyB33FI,wCACE,6BzB63FN,CyBz3FI,oCACE,+BzB23FN,CyBv3FI,qCAIE,6BAAA,CAIA,UAAA,CAPA,oBAAA,CAEA,YAAA,CAEA,2CAAA,CAAA,mCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CALA,WzB+3FN,CyBn3FQ,mDACE,oBzBq3FV,CyB92FE,kCAEE,kBAAA,CACA,kBAAA,CAFA,mBzBk3FJ,CyB72FI,gDACE,YzB+2FN,CyB12FE,+BAEE,mBAAA,CACA,mBAAA,CAFA,mBzB82FJ,C0Bp+FE,wBAGE,yCAAA,CAFA,oBAAA,CACA,iBAAA,CAEA,SAAA,CACA,mC1Bu+FJ,C0Bl+FI,aAVF,wBAWI,Y1Bq+FJ,CACF,C0Bl+FI,kCAEE,aAAA,CADA,kB1Bq+FN,C0B/9FE,6FAGE,SAAA,CACA,mC1Bi+FJ,C0B39FE,4FAGE,+B1B69FJ,C0Bt9FE,oBACE,wB1Bw9FJ,CKh2FI,sCqBlHE,qDACE,sB1Bq9FN,CACF,C0Bh9FE,kEAGE,mB1Bk9FJ,C0B/8FI,uFAIE,UAAA,CAHA,aAAA,CACA,kBAAA,CACA,kB1Bo9FN,CKl3FI,sCqB1FE,qKACE,mB1Bi9FN,C0B98FM,0LACE,kBAAA,CACA,kB1Bk9FR,CACF,C0B58FE,sBACE,mB1B88FJ,C0B38FI,6BAIE,UAAA,CAHA,aAAA,CACA,mBAAA,CACA,mB1B88FN,CKx4FI,sCqB9DE,uDACE,mB1By8FN,C0Bt8FM,8DACE,mBAAA,CACA,mB1Bw8FR,CACF,C0Bl8FE,4CAEE,mB1Bo8FJ,C0Bj8FI,0DAIE,UAAA,CAHA,aAAA,CACA,kBAAA,CACA,kB1Bq8FN,CK55FI,sCqBjCE,8GACE,mB1Bi8FN,C0B97FM,4HACE,gBAAA,CACA,gB1Bi8FR,CACF,C2B1kGE,2BACE,a3B6kGJ,CKx5FI,wCsBtLF,2BAKI,e3B6kGJ,CACF,C2B1kGI,6BAGE,yBAAA,CACA,eAAA,CACA,iBAAA,CAJA,yBAAA,CAAA,sBAAA,CAAA,iB3B+kGN,C4BzlGE,0EAGE,kCAAA,CAAA,0B5B4lGJ,C4BxlGE,uBACE,4C5B0lGJ,C4BtlGE,uBACE,4C5BwlGJ,C4BplGE,4BACE,qC5BslGJ,C4BnlGI,mCACE,a5BqlGN,C4BjlGI,kCACE,a5BmlGN,C4B9kGE,0BAME,eAAA,CALA,aAAA,CACA,YAAA,CAGA,aAAA,CADA,kBAAA,CADA,mB5BmlGJ,C4B7kGI,uCACE,e5B+kGN,C4B3kGI,sCACE,kB5B6kGN,C6B/nGA,MACE,8L7BkoGF,C6BznGE,oBAGE,iBAAA,CAEA,gBAAA,CADA,a7B2nGJ,C6BvnGI,wCACE,uB7BynGN,C6BrnGI,gCAEE,eAAA,CADA,gB7BwnGN,C6BjnGM,wCACE,mB7BmnGR,C6B9mGI,0BAEE,UAAA,CADA,a7BinGN,C6B3mGE,oBAME,4BAAA,CACA,6BAAA,CACA,cAAA,CALA,aAAA,CACA,eAAA,CACA,+B7B8mGJ,C6BxmGI,8BACE,iC7B0mGN,C6BtmGI,kCACE,uCAAA,CACA,oB7BwmGN,C6BpmGI,wCAEE,uCAAA,CADA,Y7BumGN,C6BlmGI,0BAME,6BAAA,CAMA,UAAA,CAPA,WAAA,CAEA,yCAAA,CAAA,iCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CARA,iBAAA,CAEA,WAAA,CADA,SAAA,CAQA,sBAAA,CACA,yBAAA,CAPA,U7B4mGN,C6BjmGM,oCAEE,UAAA,CADA,UAAA,CAEA,wB7BmmGR,C6B9lGI,wEAEE,Y7B+lGN,C8B7rGE,+DAGE,mBAAA,CACA,cAAA,CACA,uB9BgsGJ,C8B7rGI,2EAGE,iBAAA,CADA,eAAA,CADA,a9BmsGN,C+B9sGE,6BAEE,sC/BitGJ,C+B9sGE,cACE,yC/BgtGJ,C+B7sGE,sIASE,oC/B+sGJ,C+B5sGE,2EAKE,qC/B8sGJ,C+B3sGE,wGAOE,oC/B6sGJ,C+B1sGE,yFAME,qC/B4sGJ,C+BzsGE,6BAEE,kC/B2sGJ,C+BxsGE,6CAGE,sC/B0sGJ,C+BvsGE,4DAIE,sC/BysGJ,C+BtsGE,4DAIE,qC/BwsGJ,C+BrsGE,yFAME,qC/BusGJ,C+BpsGE,2EAKE,sC/BssGJ,C+BnsGE,wHAQE,qC/BqsGJ,C+BlsGE,8BAIE,mBAAA,CAFA,gBAAA,CACA,gB/BqsGJ,C+BjsGE,eACE,4C/BmsGJ,C+BhsGE,eACE,4C/BksGJ,C+B9rGE,gBAIE,wCAAA,CAHA,aAAA,CACA,wBAAA,CACA,wB/BisGJ,C+B5rGE,yBAOE,wCAAA,CACA,+DAAA,CACA,4BAAA,CACA,6BAAA,CARA,aAAA,CAIA,eAAA,CADA,eAAA,CAFA,cAAA,CACA,oCAAA,CAHA,iB/BusGJ,C+B3rGI,6BACE,Y/B6rGN,C+BxrGE,iCAQE,wCAAA,CACA,+DAAA,CAFA,uCAAA,CAGA,0BAAA,CAPA,UAAA,CADA,oBAAA,CAGA,2BAAA,CADA,2BAAA,CAEA,2BAAA,CALA,uBAAA,CAAA,eAAA,CAUA,wBAAA,CAAA,qBAAA,CAAA,oBAAA,CAAA,gB/B0rGJ,C+BjrGA,gBACE,iBAAA,CACA,e/BorGF,C+BhrGE,yCAEE,aAAA,CACA,S/BkrGJ,C+B7qGE,mBACE,Y/B+qGJ,C+B1qGE,oBACE,Q/B4qGJ,C+BxqGE,4BACE,WAAA,CACA,SAAA,CACA,e/B0qGJ,C+BrqGE,yBAIE,wCAAA,CADA,eAAA,CADA,oDAAA,CAGA,wBAAA,CAAA,qBAAA,CAAA,oBAAA,CAAA,gB/BuqGJ,C+BnqGE,2BAEE,+DAAA,CADA,2B/BsqGJ,C+BlqGI,+BACE,uCAAA,CACA,gB/BoqGN,C+B/pGE,sBACE,MAAA,CACA,e/BiqGJ,C+BvpGE,4BAGE,mBAAA,CADA,aAAA,CADA,Y/B4pGJ,C+BvpGI,iCACE,e/BypGN,CK9sGI,wC0B6DA,uBACE,iB/BopGJ,C+BjpGI,4BACE,eAAA,CACA,e/BmpGN,C+B/oGI,4BACE,e/BipGN,C+B5oGE,4BAEE,eAAA,CADA,iB/B+oGJ,C+B3oGI,iCACE,eAAA,CACA,e/B6oGN,CACF,CDr5GI,yDAKE,+BAAA,CACA,8BAAA,CAFA,aAAA,CADA,QAAA,CADA,iBC45GN,CDp5GI,uBAEE,uCAAA,CADA,cCu5GN,CDj2GQ,kCAEE,WAnDgB,CAkDhB,kBCo2GV,CDr2GQ,uCAEE,WAnDgB,CAkDhB,kBCw2GV,CDz2GQ,wCAEE,WAnDgB,CAkDhB,kBC42GV,CD72GQ,sCAEE,WAnDgB,CAkDhB,kBCg3GV,CDj3GQ,2CAEE,WAnDgB,CAkDhB,kBCo3GV,CDr3GQ,4CAEE,WAnDgB,CAkDhB,kBCw3GV,CDz3GQ,sCAEE,WAnDgB,CAkDhB,kBC43GV,CD73GQ,2CAEE,WAnDgB,CAkDhB,kBCg4GV,CDj4GQ,4CAEE,WAnDgB,CAkDhB,kBCo4GV,CDr4GQ,mCAEE,WAnDgB,CAkDhB,kBCw4GV,CDz4GQ,wCAEE,WAnDgB,CAkDhB,kBC44GV,CD74GQ,yCAEE,WAnDgB,CAkDhB,kBCg5GV,CDj5GQ,qCAEE,WAnDgB,CAkDhB,kBCo5GV,CDr5GQ,0CAEE,WAnDgB,CAkDhB,kBCw5GV,CDz5GQ,2CAEE,WAnDgB,CAkDhB,kBC45GV,CD75GQ,oCAEE,WAnDgB,CAkDhB,kBCg6GV,CDj6GQ,yCAEE,WAnDgB,CAkDhB,kBCo6GV,CDr6GQ,0CAEE,WAnDgB,CAkDhB,kBCw6GV,CDz6GQ,oCAEE,WAnDgB,CAkDhB,kBC46GV,CD76GQ,yCAEE,WAnDgB,CAkDhB,kBCg7GV,CDj7GQ,0CAEE,WAnDgB,CAkDhB,kBCo7GV,CDr7GQ,sCAEE,WAnDgB,CAkDhB,kBCw7GV,CDz7GQ,2CAEE,WAnDgB,CAkDhB,kBC47GV,CD77GQ,4CAEE,WAnDgB,CAkDhB,kBCg8GV,CDj8GQ,yCAEE,WAnDgB,CAkDhB,kBCo8GV,CDr8GQ,yCAEE,WAnDgB,CAkDhB,kBCw8GV,CDz8GQ,0CAEE,WAnDgB,CAkDhB,kBC48GV,CD78GQ,uCAEE,WAnDgB,CAkDhB,kBCg9GV,CDj9GQ,wCAEE,WAnDgB,CAkDhB,kBCo9GV,CDr9GQ,sCAEE,WAnDgB,CAkDhB,kBCw9GV,CDz9GQ,wCAEE,WAnDgB,CAkDhB,kBC49GV,CD79GQ,oCAEE,WAnDgB,CAkDhB,kBCg+GV,CDj+GQ,2CAEE,WAnDgB,CAkDhB,kBCo+GV,CDr+GQ,qCAEE,WAnDgB,CAkDhB,kBCw+GV,CDz+GQ,oCAEE,WAnDgB,CAkDhB,kBC4+GV,CD7+GQ,kCAEE,WAnDgB,CAkDhB,kBCg/GV,CDj/GQ,qCAEE,WAnDgB,CAkDhB,kBCo/GV,CDr/GQ,mCAEE,WAnDgB,CAkDhB,kBCw/GV,CDz/GQ,qCAEE,WAnDgB,CAkDhB,kBC4/GV,CD7/GQ,wCAEE,WAnDgB,CAkDhB,kBCggHV,CDjgHQ,sCAEE,WAnDgB,CAkDhB,kBCogHV,CDrgHQ,2CAEE,WAnDgB,CAkDhB,kBCwgHV,CD3/GQ,iCAEE,WARgB,CAOhB,iBC8/GV,CD//GQ,uCAEE,WARgB,CAOhB,iBCkgHV,CDngHQ,mCAEE,WARgB,CAOhB,iBCsgHV,CgCzlHE,4BAIE,yDAAA,CAHA,YAAA,CACA,QAAA,CACA,UhC6lHJ,CgCzlHI,aAPF,4BAQI,aAAA,CACA,OhC4lHJ,CACF,CgCxlHI,wJAGE,QhC0lHN,CgCvlHM,uKACE,wBAAA,CACA,yBhC2lHR,CgCtlHI,wCACE,QhCwlHN,CgCnlHE,wBAKE,mBAAA,CAHA,YAAA,CACA,cAAA,CACA,YAAA,CAHA,iBhCylHJ,CgC/kHI,8BAGE,QAAA,CACA,SAAA,CAHA,iBAAA,CACA,OhCmlHN,CgC9kHM,4CAEE,sCAAA,CADA,+BhCilHR,CgC7kHQ,4DACE,ahC+kHV,CgC1kHM,0CAEE,uCAAA,CADA,kBhC6kHR,CgCxkHM,wDAEE,uCAAA,CADA,YhC2kHR,CgCrkHI,8BAOE,qCAAA,CAHA,uCAAA,CAIA,cAAA,CAFA,gBAAA,CADA,eAAA,CAFA,+BAAA,CAMA,qBAAA,CAPA,UAAA,CADA,ShC+kHN,CgCpkHM,oCACE,+BhCskHR,CgCxjHE,cAHF,4sDAKI,sCAAA,CADA,+BhC6jHF,CACF,CgCxjHA,o0DACE,uDhC2jHF,CgCvjHA,guDACE,ahC0jHF,CgC/iHE,2BAME,uBAAA,CAFA,+DAAA,CAHA,YAAA,CACA,cAAA,CACA,aAAA,CAEA,gCAAA,CAAA,4BAAA,CAEA,oBhCkjHJ,CgC/iHI,aAVF,2BAWI,gBhCkjHJ,CACF,CgC/iHI,8CACE,YhCijHN,CgC7iHI,iCASE,qCAAA,CAEA,4BAAA,CACA,6BAAA,CAPA,uCAAA,CAQA,cAAA,CAXA,aAAA,CAKA,gBAAA,CADA,eAAA,CAFA,8BAAA,CAMA,uBAAA,CAIA,2CACE,CAPF,kBAAA,CALA,UAAA,CAFA,ShC4jHN,CgC1iHM,aAII,6CACE,OhCyiHV,CgC1iHQ,8CACE,OhC4iHV,CgC7iHQ,8CACE,OhC+iHV,CgChjHQ,8CACE,OhCkjHV,CgCnjHQ,8CACE,OhCqjHV,CgCtjHQ,8CACE,OhCwjHV,CgCzjHQ,8CACE,OhC2jHV,CgC5jHQ,8CACE,OhC8jHV,CgC/jHQ,8CACE,OhCikHV,CgClkHQ,+CACE,QhCokHV,CgCrkHQ,+CACE,QhCukHV,CgCxkHQ,+CACE,QhC0kHV,CgC3kHQ,+CACE,QhC6kHV,CgC9kHQ,+CACE,QhCglHV,CgCjlHQ,+CACE,QhCmlHV,CgCplHQ,+CACE,QhCslHV,CgCvlHQ,+CACE,QhCylHV,CgC1lHQ,+CACE,QhC4lHV,CgC7lHQ,+CACE,QhC+lHV,CgChmHQ,+CACE,QhCkmHV,CACF,CgC7lHM,uCACE,+BhC+lHR,CK1lHI,wC2BIA,6CAEE,eAAA,CADA,eAAA,CAEA,kBAAA,CACA,yBhCylHJ,CgCtlHI,uDAEE,cAAA,CADA,mBAAA,CAGA,wBAAA,CADA,0BhCylHN,CgCnlHI,mDAEE,UAAA,CADA,mBhCslHN,CgCllHM,6DAEE,kBAAA,CADA,ehCqlHR,CACF,CgC9kHE,8BACE,qBhCglHJ,CgC7kHI,8CAIE,eAAA,CAHA,eAAA,CACA,OAAA,CACA,UhCglHN,CgC5kHM,aAPF,8CAQI,gBhC+kHN,CACF,CgC3kHI,4CACE,YhC6kHN,CgC1kHM,aAJF,4CAKI,ahC6kHN,CgCzkHQ,wDACE,OhC2kHV,CgC5kHQ,yDACE,OhC8kHV,CgC/kHQ,yDACE,OhCilHV,CgCllHQ,yDACE,OhColHV,CgCrlHQ,yDACE,OhCulHV,CgCxlHQ,yDACE,OhC0lHV,CgC3lHQ,yDACE,OhC6lHV,CgC9lHQ,yDACE,OhCgmHV,CgCjmHQ,yDACE,OhCmmHV,CgCpmHQ,0DACE,QhCsmHV,CgCvmHQ,0DACE,QhCymHV,CgC1mHQ,0DACE,QhC4mHV,CgC7mHQ,0DACE,QhC+mHV,CgChnHQ,0DACE,QhCknHV,CgCnnHQ,0DACE,QhCqnHV,CgCtnHQ,0DACE,QhCwnHV,CgCznHQ,0DACE,QhC2nHV,CgC5nHQ,0DACE,QhC8nHV,CgC/nHQ,0DACE,QhCioHV,CgCloHQ,0DACE,QhCooHV,CACF,CgC9nHM,wMAGE,QhCgoHR,CgC7nHQ,uNACE,wBAAA,CACA,yBhCioHV,CgC5nHM,wDACE,QhC8nHR,CiCz4HA,MACE,mVAAA,CAEA,4VjC44HF,CiCl4HE,4BAEE,oBAAA,CADA,iBjCs4HJ,CiCj4HI,4CAGE,SAAA,CAFA,iBAAA,CACA,SjCo4HN,CiCh4HM,sDAEE,SAAA,CADA,UjCm4HR,CiC53HE,+CAEE,SAAA,CADA,UjC+3HJ,CiC13HE,wCAME,qDAAA,CAIA,UAAA,CALA,aAAA,CAFA,WAAA,CAIA,0CAAA,CAAA,kCAAA,CACA,6BAAA,CAAA,qBAAA,CACA,yBAAA,CAAA,iBAAA,CARA,iBAAA,CACA,SAAA,CAEA,YjCk4HJ,CiCz3HI,kDAEE,SAAA,CADA,YjC43HN,CiCt3HE,gEACE,wBT8Va,CS7Vb,mDAAA,CAAA,2CjCw3HJ,CK/wHI,mC6BhKA,oBACE,UAAA,CAIA,mBAAA,CADA,kBAAA,CADA,YAAA,CADA,alCs7HJ,CkCh7HI,8BACE,WAAA,CAEA,iBAAA,CADA,clCm7HN,CkC96HI,wBACE,WAAA,CAEA,iBAAA,CADA,clCi7HN,CkC76HM,kCACE,UAAA,CAEA,aAAA,CADA,kBlCg7HR,CACF","file":"src/assets/stylesheets/main.scss","sourcesContent":["////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Keyboard key\n .keys {\n\n // Keyboard key icon\n kbd::before,\n kbd::after {\n position: relative;\n margin: 0;\n color: inherit;\n -moz-osx-font-smoothing: initial;\n -webkit-font-smoothing: initial;\n }\n\n // Surrounding text\n span {\n padding: 0 px2em(3.2px);\n color: var(--md-default-fg-color--light);\n }\n\n // Define keyboard keys with left icon\n @each $name, $code in (\n\n // Modifiers\n \"alt\": \"\\2387\",\n \"left-alt\": \"\\2387\",\n \"right-alt\": \"\\2387\",\n \"command\": \"\\2318\",\n \"left-command\": \"\\2318\",\n \"right-command\": \"\\2318\",\n \"control\": \"\\2303\",\n \"left-control\": \"\\2303\",\n \"right-control\": \"\\2303\",\n \"meta\": \"\\25C6\",\n \"left-meta\": \"\\25C6\",\n \"right-meta\": \"\\25C6\",\n \"option\": \"\\2325\",\n \"left-option\": \"\\2325\",\n \"right-option\": \"\\2325\",\n \"shift\": \"\\21E7\",\n \"left-shift\": \"\\21E7\",\n \"right-shift\": \"\\21E7\",\n \"super\": \"\\2756\",\n \"left-super\": \"\\2756\",\n \"right-super\": \"\\2756\",\n \"windows\": \"\\229E\",\n \"left-windows\": \"\\229E\",\n \"right-windows\": \"\\229E\",\n\n // Other keys\n \"arrow-down\": \"\\2193\",\n \"arrow-left\": \"\\2190\",\n \"arrow-right\": \"\\2192\",\n \"arrow-up\": \"\\2191\",\n \"backspace\": \"\\232B\",\n \"backtab\": \"\\21E4\",\n \"caps-lock\": \"\\21EA\",\n \"clear\": \"\\2327\",\n \"context-menu\": \"\\2630\",\n \"delete\": \"\\2326\",\n \"eject\": \"\\23CF\",\n \"end\": \"\\2913\",\n \"escape\": \"\\238B\",\n \"home\": \"\\2912\",\n \"insert\": \"\\2380\",\n \"page-down\": \"\\21DF\",\n \"page-up\": \"\\21DE\",\n \"print-screen\": \"\\2399\"\n ) {\n .key-#{$name} {\n &::before {\n padding-right: px2em(6.4px);\n content: $code;\n }\n }\n }\n\n // Define keyboard keys with right icon\n @each $name, $code in (\n \"tab\": \"\\21E5\",\n \"num-enter\": \"\\2324\",\n \"enter\": \"\\23CE\"\n ) {\n .key-#{$name} {\n &::after {\n padding-left: px2em(6.4px);\n content: $code;\n }\n }\n }\n }\n}\n","@charset \"UTF-8\";\nhtml {\n box-sizing: border-box;\n text-size-adjust: none;\n}\n\n*,\n*::before,\n*::after {\n box-sizing: inherit;\n}\n\nbody {\n margin: 0;\n}\n\na,\nbutton,\nlabel,\ninput {\n -webkit-tap-highlight-color: transparent;\n}\n\na {\n color: inherit;\n text-decoration: none;\n}\n\nhr {\n display: block;\n box-sizing: content-box;\n height: 0.05rem;\n padding: 0;\n overflow: visible;\n border: 0;\n}\n\nsmall {\n font-size: 80%;\n}\n\nsub,\nsup {\n line-height: 1em;\n}\n\nimg {\n border-style: none;\n}\n\ntable {\n border-collapse: separate;\n border-spacing: 0;\n}\n\ntd,\nth {\n font-weight: 400;\n vertical-align: top;\n}\n\nbutton {\n margin: 0;\n padding: 0;\n font-size: inherit;\n font-family: inherit;\n background: transparent;\n border: 0;\n}\n\ninput {\n border: 0;\n outline: none;\n}\n\n:root {\n --md-default-fg-color: hsla(0, 0%, 0%, 0.87);\n --md-default-fg-color--light: hsla(0, 0%, 0%, 0.54);\n --md-default-fg-color--lighter: hsla(0, 0%, 0%, 0.32);\n --md-default-fg-color--lightest: hsla(0, 0%, 0%, 0.07);\n --md-default-bg-color: hsla(0, 0%, 100%, 1);\n --md-default-bg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-default-bg-color--lighter: hsla(0, 0%, 100%, 0.3);\n --md-default-bg-color--lightest: hsla(0, 0%, 100%, 0.12);\n --md-primary-fg-color: hsla(231, 48%, 48%, 1);\n --md-primary-fg-color--light: hsla(231, 44%, 56%, 1);\n --md-primary-fg-color--dark: hsla(232, 54%, 41%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-accent-fg-color: hsla(231, 99%, 66%, 1);\n --md-accent-fg-color--transparent: hsla(231, 99%, 66%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n:root > * {\n --md-code-fg-color: hsla(200, 18%, 26%, 1);\n --md-code-bg-color: hsla(0, 0%, 96%, 1);\n --md-code-hl-color: hsla(60, 100%, 50%, 0.5);\n --md-code-hl-number-color: hsla(0, 67%, 50%, 1);\n --md-code-hl-special-color: hsla(340, 83%, 47%, 1);\n --md-code-hl-function-color: hsla(291, 45%, 50%, 1);\n --md-code-hl-constant-color: hsla(250, 63%, 60%, 1);\n --md-code-hl-keyword-color: hsla(219, 54%, 51%, 1);\n --md-code-hl-string-color: hsla(150, 63%, 30%, 1);\n --md-code-hl-name-color: var(--md-code-fg-color);\n --md-code-hl-operator-color: var(--md-default-fg-color--light);\n --md-code-hl-punctuation-color: var(--md-default-fg-color--light);\n --md-code-hl-comment-color: var(--md-default-fg-color--light);\n --md-code-hl-generic-color: var(--md-default-fg-color--light);\n --md-code-hl-variable-color: var(--md-default-fg-color--light);\n --md-typeset-color: var(--md-default-fg-color);\n --md-typeset-a-color: var(--md-primary-fg-color);\n --md-typeset-mark-color: hsla(60, 100%, 50%, 0.5);\n --md-typeset-del-color: hsla(6, 90%, 60%, 0.15);\n --md-typeset-ins-color: hsla(150, 90%, 44%, 0.15);\n --md-typeset-kbd-color: hsla(0, 0%, 98%, 1);\n --md-typeset-kbd-accent-color: hsla(0, 100%, 100%, 1);\n --md-typeset-kbd-border-color: hsla(0, 0%, 72%, 1);\n --md-typeset-table-color: hsla(0, 0%, 0%, 0.12);\n --md-admonition-fg-color: var(--md-default-fg-color);\n --md-admonition-bg-color: var(--md-default-bg-color);\n --md-footer-fg-color: hsla(0, 0%, 100%, 1);\n --md-footer-fg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-footer-fg-color--lighter: hsla(0, 0%, 100%, 0.3);\n --md-footer-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-footer-bg-color--dark: hsla(0, 0%, 0%, 0.32);\n}\n\n.md-icon svg {\n display: block;\n width: 1.2rem;\n height: 1.2rem;\n fill: currentColor;\n}\n\nbody {\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\nbody,\ninput {\n color: var(--md-typeset-color);\n font-feature-settings: \"kern\", \"liga\";\n font-family: var(--md-text-font-family, _), -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;\n}\n\ncode,\npre,\nkbd {\n color: var(--md-typeset-color);\n font-feature-settings: \"kern\";\n font-family: var(--md-code-font-family, _), SFMono-Regular, Consolas, Menlo, monospace;\n}\n\n:root {\n --md-typeset-table-sort-icon: svg-load(\"material/sort.svg\");\n --md-typeset-table-sort-icon--asc: svg-load(\"material/sort-ascending.svg\");\n --md-typeset-table-sort-icon--desc: svg-load(\"material/sort-descending.svg\");\n}\n\n.md-typeset {\n font-size: 0.8rem;\n line-height: 1.6;\n color-adjust: exact;\n}\n@media print {\n .md-typeset {\n font-size: 0.68rem;\n }\n}\n.md-typeset ul,\n.md-typeset ol,\n.md-typeset dl,\n.md-typeset figure,\n.md-typeset blockquote,\n.md-typeset pre {\n margin: 1em 0;\n}\n.md-typeset h1 {\n margin: 0 0 1.25em;\n color: var(--md-default-fg-color--light);\n font-weight: 300;\n font-size: 2em;\n line-height: 1.3;\n letter-spacing: -0.01em;\n}\n.md-typeset h2 {\n margin: 1.6em 0 0.64em;\n font-weight: 300;\n font-size: 1.5625em;\n line-height: 1.4;\n letter-spacing: -0.01em;\n}\n.md-typeset h3 {\n margin: 1.6em 0 0.8em;\n font-weight: 400;\n font-size: 1.25em;\n line-height: 1.5;\n letter-spacing: -0.01em;\n}\n.md-typeset h2 + h3 {\n margin-top: 0.8em;\n}\n.md-typeset h4 {\n margin: 1em 0;\n font-weight: 700;\n letter-spacing: -0.01em;\n}\n.md-typeset h5,\n.md-typeset h6 {\n margin: 1.25em 0;\n color: var(--md-default-fg-color--light);\n font-weight: 700;\n font-size: 0.8em;\n letter-spacing: -0.01em;\n}\n.md-typeset h5 {\n text-transform: uppercase;\n}\n.md-typeset hr {\n display: flow-root;\n margin: 1.5em 0;\n border-bottom: 0.05rem solid var(--md-default-fg-color--lightest);\n}\n.md-typeset a {\n color: var(--md-typeset-a-color);\n word-break: break-word;\n}\n.md-typeset a, .md-typeset a::before {\n transition: color 125ms;\n}\n.md-typeset a:focus, .md-typeset a:hover {\n color: var(--md-accent-fg-color);\n}\n.md-typeset a.focus-visible {\n outline-color: var(--md-accent-fg-color);\n outline-offset: 0.2rem;\n}\n.md-typeset code,\n.md-typeset pre,\n.md-typeset kbd {\n color: var(--md-code-fg-color);\n direction: ltr;\n}\n@media print {\n .md-typeset code,\n.md-typeset pre,\n.md-typeset kbd {\n white-space: pre-wrap;\n }\n}\n.md-typeset code {\n padding: 0 0.2941176471em;\n font-size: 0.85em;\n word-break: break-word;\n background-color: var(--md-code-bg-color);\n border-radius: 0.1rem;\n box-decoration-break: clone;\n}\n.md-typeset code:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n.md-typeset h1 code,\n.md-typeset h2 code,\n.md-typeset h3 code,\n.md-typeset h4 code,\n.md-typeset h5 code,\n.md-typeset h6 code {\n margin: initial;\n padding: initial;\n background-color: transparent;\n box-shadow: none;\n}\n.md-typeset a code {\n color: currentColor;\n}\n.md-typeset pre {\n position: relative;\n display: flow-root;\n line-height: 1.4;\n}\n.md-typeset pre > code {\n display: block;\n margin: 0;\n padding: 0.7720588235em 1.1764705882em;\n overflow: auto;\n word-break: normal;\n box-shadow: none;\n box-decoration-break: slice;\n touch-action: auto;\n scrollbar-width: thin;\n scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n}\n.md-typeset pre > code:hover {\n scrollbar-color: var(--md-accent-fg-color) transparent;\n}\n.md-typeset pre > code::-webkit-scrollbar {\n width: 0.2rem;\n height: 0.2rem;\n}\n.md-typeset pre > code::-webkit-scrollbar-thumb {\n background-color: var(--md-default-fg-color--lighter);\n}\n.md-typeset pre > code::-webkit-scrollbar-thumb:hover {\n background-color: var(--md-accent-fg-color);\n}\n@media screen and (max-width: 44.9375em) {\n .md-typeset > pre {\n margin: 1em -0.8rem;\n }\n .md-typeset > pre code {\n border-radius: 0;\n }\n}\n.md-typeset kbd {\n display: inline-block;\n padding: 0 0.6666666667em;\n color: var(--md-default-fg-color);\n font-size: 0.75em;\n vertical-align: text-top;\n word-break: break-word;\n background-color: var(--md-typeset-kbd-color);\n border-radius: 0.1rem;\n box-shadow: 0 0.1rem 0 0.05rem var(--md-typeset-kbd-border-color), 0 0.1rem 0 var(--md-typeset-kbd-border-color), 0 -0.1rem 0.2rem var(--md-typeset-kbd-accent-color) inset;\n}\n.md-typeset mark {\n color: inherit;\n word-break: break-word;\n background-color: var(--md-typeset-mark-color);\n box-decoration-break: clone;\n}\n.md-typeset abbr {\n text-decoration: none;\n border-bottom: 0.05rem dotted var(--md-default-fg-color--light);\n cursor: help;\n}\n@media (hover: none) {\n .md-typeset abbr {\n position: relative;\n }\n .md-typeset abbr[title]:focus::after, .md-typeset abbr[title]:hover::after {\n box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);\n position: absolute;\n left: 0;\n display: inline-block;\n width: auto;\n min-width: max-content;\n max-width: 80%;\n margin-top: 2em;\n padding: 0.2rem 0.3rem;\n color: var(--md-default-bg-color);\n font-size: 0.7rem;\n background-color: var(--md-default-fg-color);\n border-radius: 0.1rem;\n content: attr(title);\n }\n}\n.md-typeset small {\n opacity: 0.75;\n}\n.md-typeset sup,\n.md-typeset sub {\n margin-left: 0.078125em;\n}\n[dir=rtl] .md-typeset sup,\n[dir=rtl] .md-typeset sub {\n margin-right: 0.078125em;\n margin-left: initial;\n}\n.md-typeset blockquote {\n padding-left: 0.6rem;\n color: var(--md-default-fg-color--light);\n border-left: 0.2rem solid var(--md-default-fg-color--lighter);\n}\n[dir=rtl] .md-typeset blockquote {\n padding-right: 0.6rem;\n padding-left: initial;\n border-right: 0.2rem solid var(--md-default-fg-color--lighter);\n border-left: initial;\n}\n.md-typeset ul {\n list-style-type: disc;\n}\n.md-typeset ul,\n.md-typeset ol {\n display: flow-root;\n margin-left: 0.625em;\n padding: 0;\n}\n[dir=rtl] .md-typeset ul,\n[dir=rtl] .md-typeset ol {\n margin-right: 0.625em;\n margin-left: initial;\n}\n.md-typeset ul ol,\n.md-typeset ol ol {\n list-style-type: lower-alpha;\n}\n.md-typeset ul ol ol,\n.md-typeset ol ol ol {\n list-style-type: lower-roman;\n}\n.md-typeset ul li,\n.md-typeset ol li {\n margin-bottom: 0.5em;\n margin-left: 1.25em;\n}\n[dir=rtl] .md-typeset ul li,\n[dir=rtl] .md-typeset ol li {\n margin-right: 1.25em;\n margin-left: initial;\n}\n.md-typeset ul li p,\n.md-typeset ul li blockquote,\n.md-typeset ol li p,\n.md-typeset ol li blockquote {\n margin: 0.5em 0;\n}\n.md-typeset ul li:last-child,\n.md-typeset ol li:last-child {\n margin-bottom: 0;\n}\n.md-typeset ul li ul,\n.md-typeset ul li ol,\n.md-typeset ol li ul,\n.md-typeset ol li ol {\n margin: 0.5em 0 0.5em 0.625em;\n}\n[dir=rtl] .md-typeset ul li ul,\n[dir=rtl] .md-typeset ul li ol,\n[dir=rtl] .md-typeset ol li ul,\n[dir=rtl] .md-typeset ol li ol {\n margin-right: 0.625em;\n margin-left: initial;\n}\n.md-typeset dd {\n margin: 1em 0 1.5em 1.875em;\n}\n[dir=rtl] .md-typeset dd {\n margin-right: 1.875em;\n margin-left: initial;\n}\n.md-typeset img,\n.md-typeset svg {\n max-width: 100%;\n height: auto;\n}\n.md-typeset img[align=left],\n.md-typeset svg[align=left] {\n margin: 1em;\n margin-left: 0;\n}\n.md-typeset img[align=right],\n.md-typeset svg[align=right] {\n margin: 1em;\n margin-right: 0;\n}\n.md-typeset img[align]:only-child,\n.md-typeset svg[align]:only-child {\n margin-top: 0;\n}\n.md-typeset figure {\n display: flow-root;\n width: fit-content;\n max-width: 100%;\n margin: 0 auto;\n text-align: center;\n}\n.md-typeset figure img {\n display: block;\n}\n.md-typeset figcaption {\n max-width: 24rem;\n margin: 1em auto 2em;\n font-style: italic;\n}\n.md-typeset iframe {\n max-width: 100%;\n}\n.md-typeset table:not([class]) {\n display: inline-block;\n max-width: 100%;\n overflow: auto;\n font-size: 0.64rem;\n background-color: var(--md-default-bg-color);\n border: 0.05rem solid var(--md-typeset-table-color);\n border-radius: 0.1rem;\n touch-action: auto;\n}\n@media print {\n .md-typeset table:not([class]) {\n display: table;\n }\n}\n.md-typeset table:not([class]) + * {\n margin-top: 1.5em;\n}\n.md-typeset table:not([class]) th > *:first-child,\n.md-typeset table:not([class]) td > *:first-child {\n margin-top: 0;\n}\n.md-typeset table:not([class]) th > *:last-child,\n.md-typeset table:not([class]) td > *:last-child {\n margin-bottom: 0;\n}\n.md-typeset table:not([class]) th:not([align]),\n.md-typeset table:not([class]) td:not([align]) {\n text-align: left;\n}\n[dir=rtl] .md-typeset table:not([class]) th:not([align]),\n[dir=rtl] .md-typeset table:not([class]) td:not([align]) {\n text-align: right;\n}\n.md-typeset table:not([class]) th {\n min-width: 5rem;\n padding: 0.9375em 1.25em;\n font-weight: 700;\n vertical-align: top;\n}\n.md-typeset table:not([class]) th a {\n color: inherit;\n}\n.md-typeset table:not([class]) td {\n padding: 0.9375em 1.25em;\n vertical-align: top;\n border-top: 0.05rem solid var(--md-typeset-table-color);\n}\n.md-typeset table:not([class]) tbody tr {\n transition: background-color 125ms;\n}\n.md-typeset table:not([class]) tbody tr:hover {\n background-color: rgba(0, 0, 0, 0.035);\n box-shadow: 0 0.05rem 0 var(--md-default-bg-color) inset;\n}\n.md-typeset table:not([class]) a {\n word-break: normal;\n}\n.md-typeset table th[role=columnheader] {\n cursor: pointer;\n}\n.md-typeset table th[role=columnheader]::after {\n display: inline-block;\n width: 1.2em;\n height: 1.2em;\n margin-left: 0.5em;\n vertical-align: text-bottom;\n mask-image: var(--md-typeset-table-sort-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n transition: background-color 125ms;\n content: \"\";\n}\n.md-typeset table th[role=columnheader]:hover::after {\n background-color: var(--md-default-fg-color--lighter);\n}\n.md-typeset table th[role=columnheader][aria-sort=ascending]::after {\n background-color: var(--md-default-fg-color--light);\n mask-image: var(--md-typeset-table-sort-icon--asc);\n}\n.md-typeset table th[role=columnheader][aria-sort=descending]::after {\n background-color: var(--md-default-fg-color--light);\n mask-image: var(--md-typeset-table-sort-icon--desc);\n}\n.md-typeset__scrollwrap {\n margin: 1em -0.8rem;\n overflow-x: auto;\n touch-action: auto;\n}\n.md-typeset__table {\n display: inline-block;\n margin-bottom: 0.5em;\n padding: 0 0.8rem;\n}\n@media print {\n .md-typeset__table {\n display: block;\n }\n}\nhtml .md-typeset__table table {\n display: table;\n width: 100%;\n margin: 0;\n overflow: hidden;\n}\n\nhtml {\n height: 100%;\n overflow-x: hidden;\n font-size: 125%;\n}\n@media screen and (min-width: 100em) {\n html {\n font-size: 137.5%;\n }\n}\n@media screen and (min-width: 125em) {\n html {\n font-size: 150%;\n }\n}\n\nbody {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n min-height: 100%;\n font-size: 0.5rem;\n background-color: var(--md-default-bg-color);\n}\n@media print {\n body {\n display: block;\n }\n}\n@media screen and (max-width: 59.9375em) {\n body[data-md-state=lock] {\n position: fixed;\n }\n}\n\n.md-grid {\n max-width: 61rem;\n margin-right: auto;\n margin-left: auto;\n}\n\n.md-container {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n}\n@media print {\n .md-container {\n display: block;\n }\n}\n\n.md-main {\n flex-grow: 1;\n}\n.md-main__inner {\n display: flex;\n height: 100%;\n margin-top: 1.5rem;\n}\n\n.md-ellipsis {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.md-toggle {\n display: none;\n}\n\n.md-option {\n position: absolute;\n width: 0;\n height: 0;\n opacity: 0;\n}\n.md-option:checked + label:not([hidden]) {\n display: block;\n}\n.md-option.focus-visible + label {\n outline-style: auto;\n outline-color: var(--md-accent-fg-color);\n}\n\n.md-skip {\n position: fixed;\n z-index: -1;\n margin: 0.5rem;\n padding: 0.3rem 0.5rem;\n color: var(--md-default-bg-color);\n font-size: 0.64rem;\n background-color: var(--md-default-fg-color);\n border-radius: 0.1rem;\n outline-color: var(--md-accent-fg-color);\n transform: translateY(0.4rem);\n opacity: 0;\n}\n.md-skip:focus {\n z-index: 10;\n transform: translateY(0);\n opacity: 1;\n transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1), opacity 175ms 75ms;\n}\n\n@page {\n margin: 25mm;\n}\n.md-announce {\n overflow: auto;\n background-color: var(--md-footer-bg-color);\n}\n@media print {\n .md-announce {\n display: none;\n }\n}\n.md-announce__inner {\n margin: 0.6rem auto;\n padding: 0 0.8rem;\n color: var(--md-footer-fg-color);\n font-size: 0.7rem;\n}\n\n:root {\n --md-clipboard-icon: svg-load(\"material/content-copy.svg\");\n}\n\n.md-clipboard {\n position: absolute;\n top: 0.5em;\n right: 0.5em;\n z-index: 1;\n width: 1.5em;\n height: 1.5em;\n color: var(--md-default-fg-color--lightest);\n border-radius: 0.1rem;\n outline-color: var(--md-accent-fg-color);\n outline-offset: 0.1rem;\n cursor: pointer;\n transition: color 250ms;\n}\n@media print {\n .md-clipboard {\n display: none;\n }\n}\n.md-clipboard:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n:hover > .md-clipboard {\n color: var(--md-default-fg-color--light);\n}\n.md-clipboard:focus, .md-clipboard:hover {\n color: var(--md-accent-fg-color);\n}\n.md-clipboard::after {\n display: block;\n width: 1.125em;\n height: 1.125em;\n margin: 0 auto;\n background-color: currentColor;\n mask-image: var(--md-clipboard-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n}\n.md-clipboard--inline {\n cursor: pointer;\n}\n.md-clipboard--inline code {\n transition: color 250ms, background-color 250ms;\n}\n.md-clipboard--inline:focus code, .md-clipboard--inline:hover code {\n color: var(--md-accent-fg-color);\n background-color: var(--md-accent-fg-color--transparent);\n}\n\n.md-content {\n flex-grow: 1;\n overflow: hidden;\n scroll-padding-top: 51.2rem;\n}\n.md-content__inner {\n margin: 0 0.8rem 1.2rem;\n padding-top: 0.6rem;\n}\n@media screen and (min-width: 76.25em) {\n [dir=ltr] .md-sidebar--primary:not([hidden]) ~ .md-content > .md-content__inner {\n margin-left: 1.2rem;\n }\n [dir=rtl] .md-sidebar--primary:not([hidden]) ~ .md-content > .md-content__inner {\n margin-right: 1.2rem;\n }\n [dir=ltr] .md-sidebar--secondary:not([hidden]) ~ .md-content > .md-content__inner {\n margin-right: 1.2rem;\n }\n [dir=rtl] .md-sidebar--secondary:not([hidden]) ~ .md-content > .md-content__inner {\n margin-left: 1.2rem;\n }\n}\n.md-content__inner::before {\n display: block;\n height: 0.4rem;\n content: \"\";\n}\n.md-content__inner > :last-child {\n margin-bottom: 0;\n}\n.md-content__button {\n float: right;\n margin: 0.4rem 0;\n margin-left: 0.4rem;\n padding: 0;\n}\n@media print {\n .md-content__button {\n display: none;\n }\n}\n[dir=rtl] .md-content__button {\n float: left;\n margin-right: 0.4rem;\n margin-left: initial;\n}\n[dir=rtl] .md-content__button svg {\n transform: scaleX(-1);\n}\n.md-typeset .md-content__button {\n color: var(--md-default-fg-color--lighter);\n}\n.md-content__button svg {\n display: inline;\n vertical-align: top;\n}\n\n.md-dialog {\n box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);\n position: fixed;\n right: 0.8rem;\n bottom: 0.8rem;\n left: initial;\n z-index: 3;\n min-width: 11.1rem;\n padding: 0.4rem 0.6rem;\n background-color: var(--md-default-fg-color);\n border-radius: 0.1rem;\n transform: translateY(100%);\n opacity: 0;\n transition: transform 0ms 400ms, opacity 400ms;\n pointer-events: none;\n}\n@media print {\n .md-dialog {\n display: none;\n }\n}\n[dir=rtl] .md-dialog {\n right: initial;\n left: 0.8rem;\n}\n.md-dialog[data-md-state=open] {\n transform: translateY(0);\n opacity: 1;\n transition: transform 400ms cubic-bezier(0.075, 0.85, 0.175, 1), opacity 400ms;\n pointer-events: initial;\n}\n.md-dialog__inner {\n color: var(--md-default-bg-color);\n font-size: 0.7rem;\n}\n\n.md-typeset .md-button {\n display: inline-block;\n padding: 0.625em 2em;\n color: var(--md-primary-fg-color);\n font-weight: 700;\n border: 0.1rem solid currentColor;\n border-radius: 0.1rem;\n cursor: pointer;\n transition: color 125ms, background-color 125ms, border-color 125ms;\n}\n.md-typeset .md-button--primary {\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n border-color: var(--md-primary-fg-color);\n}\n.md-typeset .md-button:focus, .md-typeset .md-button:hover {\n color: var(--md-accent-bg-color);\n background-color: var(--md-accent-fg-color);\n border-color: var(--md-accent-fg-color);\n}\n.md-typeset .md-input {\n height: 1.8rem;\n padding: 0 0.6rem;\n font-size: 0.8rem;\n border-radius: 0.1rem;\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.1), 0 0.025rem 0.05rem rgba(0, 0, 0, 0.1);\n transition: box-shadow 250ms;\n}\n.md-typeset .md-input:focus, .md-typeset .md-input:hover {\n box-shadow: 0 0.4rem 1rem rgba(0, 0, 0, 0.15), 0 0.025rem 0.05rem rgba(0, 0, 0, 0.15);\n}\n.md-typeset .md-input--stretch {\n width: 100%;\n}\n\n.md-header {\n position: sticky;\n top: 0;\n right: 0;\n left: 0;\n z-index: 3;\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0), 0 0.2rem 0.4rem rgba(0, 0, 0, 0);\n}\n@media print {\n .md-header {\n display: none;\n }\n}\n.md-header[data-md-state=shadow] {\n box-shadow: 0 0 0.2rem rgba(0, 0, 0, 0.1), 0 0.2rem 0.4rem rgba(0, 0, 0, 0.2);\n transition: transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1), box-shadow 250ms;\n}\n.md-header[data-md-state=hidden] {\n transform: translateY(-100%);\n transition: transform 250ms cubic-bezier(0.8, 0, 0.6, 1), box-shadow 250ms;\n}\n.md-header__inner {\n display: flex;\n align-items: center;\n padding: 0 0.2rem;\n}\n.md-header__button {\n position: relative;\n z-index: 1;\n margin: 0.2rem;\n padding: 0.4rem;\n color: currentColor;\n vertical-align: middle;\n outline-color: var(--md-accent-fg-color);\n cursor: pointer;\n transition: opacity 250ms;\n}\n.md-header__button:hover {\n opacity: 0.7;\n}\n.md-header__button:not([hidden]) {\n display: inline-block;\n}\n.md-header__button:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n.md-header__button.md-logo {\n margin: 0.2rem;\n padding: 0.4rem;\n}\n@media screen and (max-width: 76.1875em) {\n .md-header__button.md-logo {\n display: none;\n }\n}\n.md-header__button.md-logo img,\n.md-header__button.md-logo svg {\n display: block;\n width: 1.2rem;\n height: 1.2rem;\n fill: currentColor;\n}\n@media screen and (min-width: 60em) {\n .md-header__button[for=__search] {\n display: none;\n }\n}\n.no-js .md-header__button[for=__search] {\n display: none;\n}\n[dir=rtl] .md-header__button[for=__search] svg {\n transform: scaleX(-1);\n}\n@media screen and (min-width: 76.25em) {\n .md-header__button[for=__drawer] {\n display: none;\n }\n}\n.md-header__topic {\n position: absolute;\n display: flex;\n max-width: 100%;\n transition: transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), opacity 150ms;\n}\n.md-header__topic + .md-header__topic {\n z-index: -1;\n transform: translateX(1.25rem);\n opacity: 0;\n transition: transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1), opacity 150ms;\n pointer-events: none;\n}\n[dir=rtl] .md-header__topic + .md-header__topic {\n transform: translateX(-1.25rem);\n}\n.md-header__title {\n flex-grow: 1;\n height: 2.4rem;\n margin-right: 0.4rem;\n margin-left: 1rem;\n font-size: 0.9rem;\n line-height: 2.4rem;\n}\n.md-header__title[data-md-state=active] .md-header__topic {\n z-index: -1;\n transform: translateX(-1.25rem);\n opacity: 0;\n transition: transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1), opacity 150ms;\n pointer-events: none;\n}\n[dir=rtl] .md-header__title[data-md-state=active] .md-header__topic {\n transform: translateX(1.25rem);\n}\n.md-header__title[data-md-state=active] .md-header__topic + .md-header__topic {\n z-index: 0;\n transform: translateX(0);\n opacity: 1;\n transition: transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), opacity 150ms;\n pointer-events: initial;\n}\n.md-header__title > .md-header__ellipsis {\n position: relative;\n width: 100%;\n height: 100%;\n}\n.md-header__option {\n display: flex;\n flex-shrink: 0;\n max-width: 100%;\n white-space: nowrap;\n transition: max-width 0ms 250ms, opacity 250ms 250ms;\n}\n[data-md-toggle=search]:checked ~ .md-header .md-header__option {\n max-width: 0;\n opacity: 0;\n transition: max-width 0ms, opacity 0ms;\n}\n.md-header__source {\n display: none;\n}\n@media screen and (min-width: 60em) {\n .md-header__source {\n display: block;\n width: 11.7rem;\n max-width: 11.7rem;\n margin-left: 1rem;\n }\n [dir=rtl] .md-header__source {\n margin-right: 1rem;\n margin-left: initial;\n }\n}\n@media screen and (min-width: 76.25em) {\n .md-header__source {\n margin-left: 1.4rem;\n }\n [dir=rtl] .md-header__source {\n margin-right: 1.4rem;\n }\n}\n\n.md-footer {\n color: var(--md-footer-fg-color);\n background-color: var(--md-footer-bg-color);\n}\n@media print {\n .md-footer {\n display: none;\n }\n}\n.md-footer__inner {\n padding: 0.2rem;\n overflow: auto;\n}\n.md-footer__link {\n display: flex;\n padding-top: 1.4rem;\n padding-bottom: 0.4rem;\n outline-color: var(--md-accent-fg-color);\n transition: opacity 250ms;\n}\n@media screen and (min-width: 45em) {\n .md-footer__link {\n width: 50%;\n }\n}\n.md-footer__link:focus, .md-footer__link:hover {\n opacity: 0.7;\n}\n.md-footer__link--prev {\n float: left;\n}\n@media screen and (max-width: 44.9375em) {\n .md-footer__link--prev {\n width: 25%;\n }\n .md-footer__link--prev .md-footer__title {\n display: none;\n }\n}\n[dir=rtl] .md-footer__link--prev {\n float: right;\n}\n[dir=rtl] .md-footer__link--prev svg {\n transform: scaleX(-1);\n}\n.md-footer__link--next {\n float: right;\n text-align: right;\n}\n@media screen and (max-width: 44.9375em) {\n .md-footer__link--next {\n width: 75%;\n }\n}\n[dir=rtl] .md-footer__link--next {\n float: left;\n text-align: left;\n}\n[dir=rtl] .md-footer__link--next svg {\n transform: scaleX(-1);\n}\n.md-footer__title {\n position: relative;\n flex-grow: 1;\n max-width: calc(100% - 2.4rem);\n padding: 0 1rem;\n font-size: 0.9rem;\n line-height: 2.4rem;\n}\n.md-footer__button {\n margin: 0.2rem;\n padding: 0.4rem;\n}\n.md-footer__direction {\n position: absolute;\n right: 0;\n left: 0;\n margin-top: -1rem;\n padding: 0 1rem;\n font-size: 0.64rem;\n opacity: 0.7;\n}\n\n.md-footer-meta {\n background-color: var(--md-footer-bg-color--dark);\n}\n.md-footer-meta__inner {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n padding: 0.2rem;\n}\nhtml .md-footer-meta.md-typeset a {\n color: var(--md-footer-fg-color--light);\n}\nhtml .md-footer-meta.md-typeset a:focus, html .md-footer-meta.md-typeset a:hover {\n color: var(--md-footer-fg-color);\n}\n\n.md-footer-copyright {\n width: 100%;\n margin: auto 0.6rem;\n padding: 0.4rem 0;\n color: var(--md-footer-fg-color--lighter);\n font-size: 0.64rem;\n}\n@media screen and (min-width: 45em) {\n .md-footer-copyright {\n width: auto;\n }\n}\n.md-footer-copyright__highlight {\n color: var(--md-footer-fg-color--light);\n}\n\n.md-footer-social {\n margin: 0 0.4rem;\n padding: 0.2rem 0 0.6rem;\n}\n@media screen and (min-width: 45em) {\n .md-footer-social {\n padding: 0.6rem 0;\n }\n}\n.md-footer-social__link {\n display: inline-block;\n width: 1.6rem;\n height: 1.6rem;\n text-align: center;\n}\n.md-footer-social__link::before {\n line-height: 1.9;\n}\n.md-footer-social__link svg {\n max-height: 0.8rem;\n vertical-align: -25%;\n fill: currentColor;\n}\n\n:root {\n --md-nav-icon--prev: svg-load(\"material/arrow-left.svg\");\n --md-nav-icon--next: svg-load(\"material/chevron-right.svg\");\n --md-toc-icon: svg-load(\"material/table-of-contents.svg\");\n}\n\n.md-nav {\n font-size: 0.7rem;\n line-height: 1.3;\n}\n.md-nav__title {\n display: block;\n padding: 0 0.6rem;\n overflow: hidden;\n font-weight: 700;\n text-overflow: ellipsis;\n}\n.md-nav__title .md-nav__button {\n display: none;\n}\n.md-nav__title .md-nav__button img {\n width: auto;\n height: 100%;\n}\n.md-nav__title .md-nav__button.md-logo img,\n.md-nav__title .md-nav__button.md-logo svg {\n display: block;\n width: 2.4rem;\n height: 2.4rem;\n fill: currentColor;\n}\n.md-nav__list {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.md-nav__item {\n padding: 0 0.6rem;\n}\n.md-nav__item .md-nav__item {\n padding-right: 0;\n}\n[dir=rtl] .md-nav__item .md-nav__item {\n padding-right: 0.6rem;\n padding-left: 0;\n}\n.md-nav__link {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 0.625em;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n transition: color 125ms;\n scroll-snap-align: start;\n}\n.md-nav__link[data-md-state=blur] {\n color: var(--md-default-fg-color--light);\n}\n.md-nav__item .md-nav__link--active {\n color: var(--md-typeset-a-color);\n}\n.md-nav__item .md-nav__link--index [href] {\n width: 100%;\n}\n.md-nav__link:focus, .md-nav__link:hover {\n color: var(--md-accent-fg-color);\n}\n.md-nav__link.focus-visible {\n outline-color: var(--md-accent-fg-color);\n outline-offset: 0.2rem;\n}\n.md-nav--primary .md-nav__link[for=__toc] {\n display: none;\n}\n.md-nav--primary .md-nav__link[for=__toc] .md-icon::after {\n display: block;\n width: 100%;\n height: 100%;\n mask-image: var(--md-toc-icon);\n background-color: currentColor;\n}\n.md-nav--primary .md-nav__link[for=__toc] ~ .md-nav {\n display: none;\n}\n.md-nav__link > * {\n display: flex;\n cursor: pointer;\n}\n.md-nav__source {\n display: none;\n}\n@media screen and (max-width: 76.1875em) {\n .md-nav--primary, .md-nav--primary .md-nav {\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n background-color: var(--md-default-bg-color);\n }\n .md-nav--primary .md-nav__title,\n.md-nav--primary .md-nav__item {\n font-size: 0.8rem;\n line-height: 1.5;\n }\n .md-nav--primary .md-nav__title {\n position: relative;\n height: 5.6rem;\n padding: 3rem 0.8rem 0.2rem;\n color: var(--md-default-fg-color--light);\n font-weight: 400;\n line-height: 2.4rem;\n white-space: nowrap;\n background-color: var(--md-default-fg-color--lightest);\n cursor: pointer;\n }\n .md-nav--primary .md-nav__title .md-nav__icon {\n position: absolute;\n top: 0.4rem;\n left: 0.4rem;\n display: block;\n width: 1.2rem;\n height: 1.2rem;\n margin: 0.2rem;\n }\n [dir=rtl] .md-nav--primary .md-nav__title .md-nav__icon {\n right: 0.4rem;\n left: initial;\n }\n .md-nav--primary .md-nav__title .md-nav__icon::after {\n display: block;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n mask-image: var(--md-nav-icon--prev);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n .md-nav--primary .md-nav__title ~ .md-nav__list {\n overflow-y: auto;\n background-color: var(--md-default-bg-color);\n box-shadow: 0 0.05rem 0 var(--md-default-fg-color--lightest) inset;\n scroll-snap-type: y mandatory;\n touch-action: pan-y;\n }\n .md-nav--primary .md-nav__title ~ .md-nav__list > :first-child {\n border-top: 0;\n }\n .md-nav--primary .md-nav__title[for=__drawer] {\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n }\n .md-nav--primary .md-nav__title .md-logo {\n position: absolute;\n top: 0.2rem;\n left: 0.2rem;\n display: block;\n margin: 0.2rem;\n padding: 0.4rem;\n }\n [dir=rtl] .md-nav--primary .md-nav__title .md-logo {\n right: 0.2rem;\n left: initial;\n }\n .md-nav--primary .md-nav__list {\n flex: 1;\n }\n .md-nav--primary .md-nav__item {\n padding: 0;\n border-top: 0.05rem solid var(--md-default-fg-color--lightest);\n }\n .md-nav--primary .md-nav__item--active > .md-nav__link {\n color: var(--md-typeset-a-color);\n }\n .md-nav--primary .md-nav__item--active > .md-nav__link:focus, .md-nav--primary .md-nav__item--active > .md-nav__link:hover {\n color: var(--md-accent-fg-color);\n }\n .md-nav--primary .md-nav__link {\n margin-top: 0;\n padding: 0.6rem 0.8rem;\n }\n .md-nav--primary .md-nav__link .md-nav__icon {\n flex-shrink: 0;\n width: 1.2rem;\n height: 1.2rem;\n margin-right: -0.2rem;\n font-size: 1.2rem;\n }\n [dir=rtl] .md-nav--primary .md-nav__link .md-nav__icon {\n margin-right: 0;\n margin-left: -0.2rem;\n }\n .md-nav--primary .md-nav__link .md-nav__icon::after {\n display: block;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n mask-image: var(--md-nav-icon--next);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n [dir=rtl] .md-nav--primary .md-nav__icon::after {\n transform: scale(-1);\n }\n .md-nav--primary .md-nav--secondary .md-nav {\n position: static;\n background-color: transparent;\n }\n .md-nav--primary .md-nav--secondary .md-nav .md-nav__link {\n padding-left: 1.4rem;\n }\n [dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav__link {\n padding-right: 1.4rem;\n padding-left: initial;\n }\n .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link {\n padding-left: 2rem;\n }\n [dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav__link {\n padding-right: 2rem;\n padding-left: initial;\n }\n .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link {\n padding-left: 2.6rem;\n }\n [dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav__link {\n padding-right: 2.6rem;\n padding-left: initial;\n }\n .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link {\n padding-left: 3.2rem;\n }\n [dir=rtl] .md-nav--primary .md-nav--secondary .md-nav .md-nav .md-nav .md-nav .md-nav__link {\n padding-right: 3.2rem;\n padding-left: initial;\n }\n .md-nav--secondary {\n background-color: transparent;\n }\n .md-nav__toggle ~ .md-nav {\n display: flex;\n transform: translateX(100%);\n opacity: 0;\n transition: transform 250ms cubic-bezier(0.8, 0, 0.6, 1), opacity 125ms 50ms;\n }\n [dir=rtl] .md-nav__toggle ~ .md-nav {\n transform: translateX(-100%);\n }\n .md-nav__toggle:checked ~ .md-nav {\n transform: translateX(0);\n opacity: 1;\n transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1), opacity 125ms 125ms;\n }\n .md-nav__toggle:checked ~ .md-nav > .md-nav__list {\n backface-visibility: hidden;\n }\n}\n@media screen and (max-width: 59.9375em) {\n .md-nav--primary .md-nav__link[for=__toc] {\n display: flex;\n }\n .md-nav--primary .md-nav__link[for=__toc] .md-icon::after {\n content: \"\";\n }\n .md-nav--primary .md-nav__link[for=__toc] + .md-nav__link {\n display: none;\n }\n .md-nav--primary .md-nav__link[for=__toc] ~ .md-nav {\n display: flex;\n }\n .md-nav__source {\n display: block;\n padding: 0 0.2rem;\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color--dark);\n }\n}\n@media screen and (min-width: 60em) and (max-width: 76.1875em) {\n .md-nav--integrated .md-nav__link[for=__toc] {\n display: flex;\n }\n .md-nav--integrated .md-nav__link[for=__toc] .md-icon::after {\n content: \"\";\n }\n .md-nav--integrated .md-nav__link[for=__toc] + .md-nav__link {\n display: none;\n }\n .md-nav--integrated .md-nav__link[for=__toc] ~ .md-nav {\n display: flex;\n }\n}\n@media screen and (min-width: 60em) {\n .md-nav--secondary .md-nav__title[for=__toc] {\n scroll-snap-align: start;\n }\n .md-nav--secondary .md-nav__title .md-nav__icon {\n display: none;\n }\n}\n@media screen and (min-width: 76.25em) {\n .md-nav {\n transition: max-height 250ms cubic-bezier(0.86, 0, 0.07, 1);\n }\n .md-nav--primary .md-nav__title[for=__drawer] {\n scroll-snap-align: start;\n }\n .md-nav--primary .md-nav__title .md-nav__icon {\n display: none;\n }\n .md-nav__toggle ~ .md-nav {\n display: none;\n }\n .md-nav__toggle:checked ~ .md-nav, .md-nav__toggle:indeterminate ~ .md-nav {\n display: block;\n }\n .md-nav__item--nested > .md-nav > .md-nav__title {\n display: none;\n }\n .md-nav__item--section {\n display: block;\n margin: 1.25em 0;\n }\n .md-nav__item--section:last-child {\n margin-bottom: 0;\n }\n .md-nav__item--section > .md-nav__link {\n font-weight: 700;\n pointer-events: none;\n }\n .md-nav__item--section > .md-nav__link--index [href] {\n pointer-events: initial;\n }\n .md-nav__item--section > .md-nav__link .md-nav__icon {\n display: none;\n }\n .md-nav__item--section > .md-nav {\n display: block;\n }\n .md-nav__item--section > .md-nav > .md-nav__list > .md-nav__item {\n padding: 0;\n }\n .md-nav__icon {\n float: right;\n width: 0.9rem;\n height: 0.9rem;\n transition: transform 250ms;\n }\n [dir=rtl] .md-nav__icon {\n float: left;\n transform: rotate(180deg);\n }\n .md-nav__icon::after {\n display: inline-block;\n width: 100%;\n height: 100%;\n vertical-align: -0.1rem;\n background-color: currentColor;\n mask-image: var(--md-nav-icon--next);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n .md-nav__item--nested .md-nav__toggle:checked ~ .md-nav__link .md-nav__icon, .md-nav__item--nested .md-nav__toggle:indeterminate ~ .md-nav__link .md-nav__icon {\n transform: rotate(90deg);\n }\n .md-nav--lifted > .md-nav__list > .md-nav__item--nested,\n.md-nav--lifted > .md-nav__title {\n display: none;\n }\n .md-nav--lifted > .md-nav__list > .md-nav__item {\n display: none;\n }\n .md-nav--lifted > .md-nav__list > .md-nav__item--active {\n display: block;\n padding: 0;\n }\n .md-nav--lifted > .md-nav__list > .md-nav__item--active > .md-nav__link {\n margin-top: 0;\n padding: 0 0.6rem;\n font-weight: 700;\n pointer-events: none;\n }\n .md-nav--lifted > .md-nav__list > .md-nav__item--active > .md-nav__link--index [href] {\n pointer-events: initial;\n }\n .md-nav--lifted > .md-nav__list > .md-nav__item--active > .md-nav__link .md-nav__icon {\n display: none;\n }\n .md-nav--lifted .md-nav[data-md-level=\"1\"] {\n display: block;\n }\n .md-nav--lifted .md-nav[data-md-level=\"1\"] > .md-nav__list > .md-nav__item {\n padding-right: 0.6rem;\n }\n .md-nav--integrated > .md-nav__list > .md-nav__item--active:not(.md-nav__item--nested) {\n padding: 0 0.6rem;\n }\n .md-nav--integrated > .md-nav__list > .md-nav__item--active:not(.md-nav__item--nested) > .md-nav__link {\n padding: 0;\n }\n .md-nav--integrated > .md-nav__list > .md-nav__item--active .md-nav--secondary {\n display: block;\n margin-bottom: 1.25em;\n border-left: 0.05rem solid var(--md-primary-fg-color);\n }\n .md-nav--integrated > .md-nav__list > .md-nav__item--active .md-nav--secondary > .md-nav__title {\n display: none;\n }\n}\n\n:root {\n --md-search-result-icon: svg-load(\"material/file-search-outline.svg\");\n}\n\n.md-search {\n position: relative;\n}\n@media screen and (min-width: 60em) {\n .md-search {\n padding: 0.2rem 0;\n }\n}\n.no-js .md-search {\n display: none;\n}\n.md-search__overlay {\n z-index: 1;\n opacity: 0;\n}\n@media screen and (max-width: 59.9375em) {\n .md-search__overlay {\n position: absolute;\n top: -1rem;\n left: -2.2rem;\n width: 2rem;\n height: 2rem;\n overflow: hidden;\n background-color: var(--md-default-bg-color);\n border-radius: 1rem;\n transform-origin: center;\n transition: transform 300ms 100ms, opacity 200ms 200ms;\n pointer-events: none;\n }\n [dir=rtl] .md-search__overlay {\n right: -2.2rem;\n left: initial;\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__overlay {\n opacity: 1;\n transition: transform 400ms, opacity 100ms;\n }\n}\n@media screen and (min-width: 60em) {\n .md-search__overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 0;\n height: 0;\n background-color: rgba(0, 0, 0, 0.54);\n cursor: pointer;\n transition: width 0ms 250ms, height 0ms 250ms, opacity 250ms;\n }\n [dir=rtl] .md-search__overlay {\n right: 0;\n left: initial;\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__overlay {\n width: 100%;\n height: 200vh;\n opacity: 1;\n transition: width 0ms, height 0ms, opacity 250ms;\n }\n}\n@media screen and (max-width: 29.9375em) {\n [data-md-toggle=search]:checked ~ .md-header .md-search__overlay {\n transform: scale(45);\n }\n}\n@media screen and (min-width: 30em) and (max-width: 44.9375em) {\n [data-md-toggle=search]:checked ~ .md-header .md-search__overlay {\n transform: scale(60);\n }\n}\n@media screen and (min-width: 45em) and (max-width: 59.9375em) {\n [data-md-toggle=search]:checked ~ .md-header .md-search__overlay {\n transform: scale(75);\n }\n}\n.md-search__inner {\n backface-visibility: hidden;\n}\n@media screen and (max-width: 59.9375em) {\n .md-search__inner {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 2;\n width: 0;\n height: 0;\n overflow: hidden;\n transform: translateX(5%);\n opacity: 0;\n transition: width 0ms 300ms, height 0ms 300ms, transform 150ms 150ms cubic-bezier(0.4, 0, 0.2, 1), opacity 150ms 150ms;\n }\n [dir=rtl] .md-search__inner {\n right: 0;\n left: initial;\n transform: translateX(-5%);\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__inner {\n width: 100%;\n height: 100%;\n transform: translateX(0);\n opacity: 1;\n transition: width 0ms 0ms, height 0ms 0ms, transform 150ms 150ms cubic-bezier(0.1, 0.7, 0.1, 1), opacity 150ms 150ms;\n }\n}\n@media screen and (min-width: 60em) {\n .md-search__inner {\n position: relative;\n float: right;\n width: 11.7rem;\n padding: 0.1rem 0;\n transition: width 250ms cubic-bezier(0.1, 0.7, 0.1, 1);\n }\n [dir=rtl] .md-search__inner {\n float: left;\n }\n}\n@media screen and (min-width: 60em) and (max-width: 76.1875em) {\n [data-md-toggle=search]:checked ~ .md-header .md-search__inner {\n width: 23.4rem;\n }\n}\n@media screen and (min-width: 76.25em) {\n [data-md-toggle=search]:checked ~ .md-header .md-search__inner {\n width: 34.4rem;\n }\n}\n.md-search__form {\n position: relative;\n z-index: 2;\n height: 2.4rem;\n background-color: var(--md-default-bg-color);\n box-shadow: 0 0 0.6rem transparent;\n transition: color 250ms, background-color 250ms;\n}\n@media screen and (min-width: 60em) {\n .md-search__form {\n height: 1.8rem;\n background-color: rgba(0, 0, 0, 0.26);\n border-radius: 0.1rem;\n }\n .md-search__form:hover {\n background-color: rgba(255, 255, 255, 0.12);\n }\n}\n[data-md-toggle=search]:checked ~ .md-header .md-search__form {\n color: var(--md-default-fg-color);\n background-color: var(--md-default-bg-color);\n border-radius: 0.1rem 0.1rem 0 0;\n box-shadow: 0 0 0.6rem rgba(0, 0, 0, 0.07);\n}\n.md-search__input {\n position: relative;\n z-index: 2;\n width: 100%;\n height: 100%;\n padding: 0 2.2rem 0 3.6rem;\n font-size: 0.9rem;\n text-overflow: ellipsis;\n background: transparent;\n}\n[dir=rtl] .md-search__input {\n padding: 0 3.6rem 0 2.2rem;\n}\n.md-search__input::placeholder {\n transition: color 250ms;\n}\n.md-search__input ~ .md-search__icon, .md-search__input::placeholder {\n color: var(--md-default-fg-color--light);\n}\n.md-search__input::-ms-clear {\n display: none;\n}\n@media screen and (max-width: 59.9375em) {\n .md-search__input {\n width: 100%;\n height: 2.4rem;\n font-size: 0.9rem;\n }\n}\n@media screen and (min-width: 60em) {\n .md-search__input {\n padding-left: 2.2rem;\n color: inherit;\n font-size: 0.8rem;\n }\n [dir=rtl] .md-search__input {\n padding-right: 2.2rem;\n }\n .md-search__input::placeholder {\n color: var(--md-primary-bg-color--light);\n }\n .md-search__input + .md-search__icon {\n color: var(--md-primary-bg-color);\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__input {\n text-overflow: clip;\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__input + .md-search__icon, [data-md-toggle=search]:checked ~ .md-header .md-search__input::placeholder {\n color: var(--md-default-fg-color--light);\n }\n}\n.md-search__icon {\n display: inline-block;\n width: 1.2rem;\n height: 1.2rem;\n cursor: pointer;\n transition: color 250ms, opacity 250ms;\n}\n.md-search__icon:hover {\n opacity: 0.7;\n}\n.md-search__icon[for=__search] {\n position: absolute;\n top: 0.3rem;\n left: 0.5rem;\n z-index: 2;\n}\n[dir=rtl] .md-search__icon[for=__search] {\n right: 0.5rem;\n left: initial;\n}\n[dir=rtl] .md-search__icon[for=__search] svg {\n transform: scaleX(-1);\n}\n@media screen and (max-width: 59.9375em) {\n .md-search__icon[for=__search] {\n top: 0.6rem;\n left: 0.8rem;\n }\n [dir=rtl] .md-search__icon[for=__search] {\n right: 0.8rem;\n left: initial;\n }\n .md-search__icon[for=__search] svg:first-child {\n display: none;\n }\n}\n@media screen and (min-width: 60em) {\n .md-search__icon[for=__search] {\n pointer-events: none;\n }\n .md-search__icon[for=__search] svg:last-child {\n display: none;\n }\n}\n.md-search__options {\n position: absolute;\n top: 0.3rem;\n right: 0.5rem;\n z-index: 2;\n pointer-events: none;\n}\n[dir=rtl] .md-search__options {\n right: initial;\n left: 0.5rem;\n}\n@media screen and (max-width: 59.9375em) {\n .md-search__options {\n top: 0.6rem;\n right: 0.8rem;\n }\n [dir=rtl] .md-search__options {\n right: initial;\n left: 0.8rem;\n }\n}\n.md-search__options > * {\n margin-left: 0.2rem;\n color: var(--md-default-fg-color--light);\n transform: scale(0.75);\n opacity: 0;\n transition: transform 150ms cubic-bezier(0.1, 0.7, 0.1, 1), opacity 150ms;\n}\n.md-search__options > *:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n[data-md-toggle=search]:checked ~ .md-header .md-search__input:valid ~ .md-search__options > * {\n transform: scale(1);\n opacity: 1;\n pointer-events: initial;\n}\n[data-md-toggle=search]:checked ~ .md-header .md-search__input:valid ~ .md-search__options > *:hover {\n opacity: 0.7;\n}\n.md-search__suggest {\n position: absolute;\n top: 0;\n display: flex;\n align-items: center;\n width: 100%;\n height: 100%;\n padding: 0 2.2rem 0 3.6rem;\n color: var(--md-default-fg-color--lighter);\n font-size: 0.9rem;\n white-space: nowrap;\n opacity: 0;\n transition: opacity 50ms;\n}\n[dir=rtl] .md-search__suggest {\n padding: 0 3.6rem 0 2.2rem;\n}\n@media screen and (min-width: 60em) {\n .md-search__suggest {\n padding-left: 2.2rem;\n font-size: 0.8rem;\n }\n [dir=rtl] .md-search__suggest {\n padding-right: 2.2rem;\n }\n}\n[data-md-toggle=search]:checked ~ .md-header .md-search__suggest {\n opacity: 1;\n transition: opacity 300ms 100ms;\n}\n.md-search__output {\n position: absolute;\n z-index: 1;\n width: 100%;\n overflow: hidden;\n border-radius: 0 0 0.1rem 0.1rem;\n}\n@media screen and (max-width: 59.9375em) {\n .md-search__output {\n top: 2.4rem;\n bottom: 0;\n }\n}\n@media screen and (min-width: 60em) {\n .md-search__output {\n top: 1.9rem;\n opacity: 0;\n transition: opacity 400ms;\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__output {\n box-shadow: 0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.4);\n opacity: 1;\n }\n}\n.md-search__scrollwrap {\n height: 100%;\n overflow-y: auto;\n background-color: var(--md-default-bg-color);\n backface-visibility: hidden;\n touch-action: pan-y;\n}\n@media (max-resolution: 1dppx) {\n .md-search__scrollwrap {\n transform: translateZ(0);\n }\n}\n@media screen and (min-width: 60em) and (max-width: 76.1875em) {\n .md-search__scrollwrap {\n width: 23.4rem;\n }\n}\n@media screen and (min-width: 76.25em) {\n .md-search__scrollwrap {\n width: 34.4rem;\n }\n}\n@media screen and (min-width: 60em) {\n .md-search__scrollwrap {\n max-height: 0;\n scrollbar-width: thin;\n scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n }\n [data-md-toggle=search]:checked ~ .md-header .md-search__scrollwrap {\n max-height: 75vh;\n }\n .md-search__scrollwrap:hover {\n scrollbar-color: var(--md-accent-fg-color) transparent;\n }\n .md-search__scrollwrap::-webkit-scrollbar {\n width: 0.2rem;\n height: 0.2rem;\n }\n .md-search__scrollwrap::-webkit-scrollbar-thumb {\n background-color: var(--md-default-fg-color--lighter);\n }\n .md-search__scrollwrap::-webkit-scrollbar-thumb:hover {\n background-color: var(--md-accent-fg-color);\n }\n}\n\n.md-search-result {\n color: var(--md-default-fg-color);\n word-break: break-word;\n}\n.md-search-result__meta {\n padding: 0 0.8rem;\n color: var(--md-default-fg-color--light);\n font-size: 0.64rem;\n line-height: 1.8rem;\n background-color: var(--md-default-fg-color--lightest);\n scroll-snap-align: start;\n}\n@media screen and (min-width: 60em) {\n .md-search-result__meta {\n padding-left: 2.2rem;\n }\n [dir=rtl] .md-search-result__meta {\n padding-right: 2.2rem;\n padding-left: initial;\n }\n}\n.md-search-result__list {\n margin: 0;\n padding: 0;\n list-style: none;\n}\n.md-search-result__item {\n box-shadow: 0 -0.05rem 0 var(--md-default-fg-color--lightest);\n}\n.md-search-result__item:first-child {\n box-shadow: none;\n}\n.md-search-result__link {\n display: block;\n outline: none;\n transition: background-color 250ms;\n scroll-snap-align: start;\n}\n.md-search-result__link:focus, .md-search-result__link:hover {\n background-color: var(--md-accent-fg-color--transparent);\n}\n.md-search-result__link:last-child p:last-child {\n margin-bottom: 0.6rem;\n}\n.md-search-result__more summary {\n display: block;\n padding: 0.75em 0.8rem;\n color: var(--md-typeset-a-color);\n font-size: 0.64rem;\n outline: none;\n cursor: pointer;\n transition: color 250ms, background-color 250ms;\n scroll-snap-align: start;\n}\n@media screen and (min-width: 60em) {\n .md-search-result__more summary {\n padding-left: 2.2rem;\n }\n [dir=rtl] .md-search-result__more summary {\n padding-right: 2.2rem;\n padding-left: 0.8rem;\n }\n}\n.md-search-result__more summary:focus, .md-search-result__more summary:hover {\n color: var(--md-accent-fg-color);\n background-color: var(--md-accent-fg-color--transparent);\n}\n.md-search-result__more summary::marker, .md-search-result__more summary::-webkit-details-marker {\n display: none;\n}\n.md-search-result__more summary ~ * > * {\n opacity: 0.65;\n}\n.md-search-result__article {\n position: relative;\n padding: 0 0.8rem;\n overflow: hidden;\n}\n@media screen and (min-width: 60em) {\n .md-search-result__article {\n padding-left: 2.2rem;\n }\n [dir=rtl] .md-search-result__article {\n padding-right: 2.2rem;\n padding-left: 0.8rem;\n }\n}\n.md-search-result__article--document .md-search-result__title {\n margin: 0.55rem 0;\n font-weight: 400;\n font-size: 0.8rem;\n line-height: 1.4;\n}\n.md-search-result__icon {\n position: absolute;\n left: 0;\n width: 1.2rem;\n height: 1.2rem;\n margin: 0.5rem;\n color: var(--md-default-fg-color--light);\n}\n@media screen and (max-width: 59.9375em) {\n .md-search-result__icon {\n display: none;\n }\n}\n.md-search-result__icon::after {\n display: inline-block;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n mask-image: var(--md-search-result-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n}\n[dir=rtl] .md-search-result__icon {\n right: 0;\n left: initial;\n}\n[dir=rtl] .md-search-result__icon::after {\n transform: scaleX(-1);\n}\n.md-search-result__title {\n margin: 0.5em 0;\n font-weight: 700;\n font-size: 0.64rem;\n line-height: 1.6;\n}\n.md-search-result__teaser {\n display: -webkit-box;\n max-height: 2rem;\n margin: 0.5em 0;\n overflow: hidden;\n color: var(--md-default-fg-color--light);\n font-size: 0.64rem;\n line-height: 1.6;\n text-overflow: ellipsis;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n}\n@media screen and (max-width: 44.9375em) {\n .md-search-result__teaser {\n max-height: 3rem;\n -webkit-line-clamp: 3;\n }\n}\n@media screen and (min-width: 60em) and (max-width: 76.1875em) {\n .md-search-result__teaser {\n max-height: 3rem;\n -webkit-line-clamp: 3;\n }\n}\n.md-search-result__teaser mark {\n text-decoration: underline;\n background-color: transparent;\n}\n.md-search-result__terms {\n margin: 0.5em 0;\n font-size: 0.64rem;\n font-style: italic;\n}\n.md-search-result mark {\n color: var(--md-accent-fg-color);\n background-color: transparent;\n}\n\n.md-select {\n position: relative;\n z-index: 1;\n}\n.md-select__inner {\n position: absolute;\n top: calc(100% - 0.2rem);\n left: 50%;\n max-height: 0;\n margin-top: 0.2rem;\n color: var(--md-default-fg-color);\n background-color: var(--md-default-bg-color);\n border-radius: 0.1rem;\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.1), 0 0 0.05rem rgba(0, 0, 0, 0.25);\n transform: translate3d(-50%, 0.3rem, 0);\n opacity: 0;\n transition: transform 250ms 375ms, opacity 250ms 250ms, max-height 0ms 500ms;\n}\n.md-select:focus-within .md-select__inner, .md-select:hover .md-select__inner {\n max-height: 10rem;\n transform: translate3d(-50%, 0, 0);\n opacity: 1;\n transition: transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1), opacity 250ms, max-height 0ms;\n}\n.md-select__inner::after {\n position: absolute;\n top: 0;\n left: 50%;\n width: 0;\n height: 0;\n margin-top: -0.2rem;\n margin-left: -0.2rem;\n border: 0.2rem solid transparent;\n border-top: 0;\n border-bottom-color: var(--md-default-bg-color);\n content: \"\";\n}\n.md-select__list {\n max-height: inherit;\n margin: 0;\n padding: 0;\n overflow: auto;\n font-size: 0.8rem;\n list-style-type: none;\n border-radius: 0.1rem;\n}\n.md-select__item {\n line-height: 1.8rem;\n}\n.md-select__link {\n display: block;\n width: 100%;\n padding-right: 1.2rem;\n padding-left: 0.6rem;\n outline: none;\n cursor: pointer;\n transition: background-color 250ms, color 250ms;\n scroll-snap-align: start;\n}\n[dir=rtl] .md-select__link {\n padding-right: 0.6rem;\n padding-left: 1.2rem;\n}\n.md-select__link:focus, .md-select__link:hover {\n color: var(--md-accent-fg-color);\n}\n.md-select__link:focus {\n background-color: var(--md-default-fg-color--lightest);\n}\n\n.md-sidebar {\n position: sticky;\n top: 2.4rem;\n flex-shrink: 0;\n align-self: flex-start;\n width: 12.1rem;\n padding: 1.2rem 0;\n}\n@media print {\n .md-sidebar {\n display: none;\n }\n}\n@media screen and (max-width: 76.1875em) {\n .md-sidebar--primary {\n position: fixed;\n top: 0;\n left: -12.1rem;\n z-index: 4;\n display: block;\n width: 12.1rem;\n height: 100%;\n background-color: var(--md-default-bg-color);\n transform: translateX(0);\n transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1), box-shadow 250ms;\n }\n [dir=rtl] .md-sidebar--primary {\n right: -12.1rem;\n left: initial;\n }\n [data-md-toggle=drawer]:checked ~ .md-container .md-sidebar--primary {\n box-shadow: 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.4);\n transform: translateX(12.1rem);\n }\n [dir=rtl] [data-md-toggle=drawer]:checked ~ .md-container .md-sidebar--primary {\n transform: translateX(-12.1rem);\n }\n .md-sidebar--primary .md-sidebar__scrollwrap {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n margin: 0;\n scroll-snap-type: none;\n overflow: hidden;\n }\n}\n@media screen and (min-width: 76.25em) {\n .md-sidebar {\n height: 0;\n }\n .no-js .md-sidebar {\n height: auto;\n }\n}\n.md-sidebar--secondary {\n display: none;\n order: 2;\n}\n@media screen and (min-width: 60em) {\n .md-sidebar--secondary {\n height: 0;\n }\n .no-js .md-sidebar--secondary {\n height: auto;\n }\n .md-sidebar--secondary:not([hidden]) {\n display: block;\n }\n .md-sidebar--secondary .md-sidebar__scrollwrap {\n touch-action: pan-y;\n }\n}\n.md-sidebar__scrollwrap {\n margin: 0 0.2rem;\n overflow-y: auto;\n backface-visibility: hidden;\n scrollbar-width: thin;\n scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n}\n.md-sidebar__scrollwrap:hover {\n scrollbar-color: var(--md-accent-fg-color) transparent;\n}\n.md-sidebar__scrollwrap::-webkit-scrollbar {\n width: 0.2rem;\n height: 0.2rem;\n}\n.md-sidebar__scrollwrap::-webkit-scrollbar-thumb {\n background-color: var(--md-default-fg-color--lighter);\n}\n.md-sidebar__scrollwrap::-webkit-scrollbar-thumb:hover {\n background-color: var(--md-accent-fg-color);\n}\n\n@media screen and (max-width: 76.1875em) {\n .md-overlay {\n position: fixed;\n top: 0;\n z-index: 4;\n width: 0;\n height: 0;\n background-color: rgba(0, 0, 0, 0.54);\n opacity: 0;\n transition: width 0ms 250ms, height 0ms 250ms, opacity 250ms;\n }\n [data-md-toggle=drawer]:checked ~ .md-overlay {\n width: 100%;\n height: 100%;\n opacity: 1;\n transition: width 0ms, height 0ms, opacity 250ms;\n }\n}\n@keyframes facts {\n 0% {\n height: 0;\n }\n 100% {\n height: 0.65rem;\n }\n}\n@keyframes fact {\n 0% {\n transform: translateY(100%);\n opacity: 0;\n }\n 50% {\n opacity: 0;\n }\n 100% {\n transform: translateY(0%);\n opacity: 1;\n }\n}\n:root {\n --md-source-forks-icon: svg-load(\"octicons/repo-forked-16.svg\");\n --md-source-repositories-icon: svg-load(\"octicons/repo-16.svg\");\n --md-source-stars-icon: svg-load(\"octicons/star-16.svg\");\n --md-source-version-icon: svg-load(\"octicons/tag-16.svg\");\n}\n\n.md-source {\n display: block;\n font-size: 0.65rem;\n line-height: 1.2;\n white-space: nowrap;\n outline-color: var(--md-accent-fg-color);\n backface-visibility: hidden;\n transition: opacity 250ms;\n}\n.md-source:hover {\n opacity: 0.7;\n}\n.md-source__icon {\n display: inline-block;\n width: 2rem;\n height: 2.4rem;\n vertical-align: middle;\n}\n.md-source__icon svg {\n margin-top: 0.6rem;\n margin-left: 0.6rem;\n}\n[dir=rtl] .md-source__icon svg {\n margin-right: 0.6rem;\n margin-left: initial;\n}\n.md-source__icon + .md-source__repository {\n margin-left: -2rem;\n padding-left: 2rem;\n}\n[dir=rtl] .md-source__icon + .md-source__repository {\n margin-right: -2rem;\n margin-left: initial;\n padding-right: 2rem;\n padding-left: initial;\n}\n.md-source__repository {\n display: inline-block;\n max-width: calc(100% - 1.2rem);\n margin-left: 0.6rem;\n overflow: hidden;\n text-overflow: ellipsis;\n vertical-align: middle;\n}\n.md-source__facts {\n margin: 0.1rem 0 0;\n padding: 0;\n overflow: hidden;\n font-size: 0.55rem;\n list-style-type: none;\n opacity: 0.75;\n}\n[data-md-state=done] .md-source__facts {\n animation: facts 250ms ease-in;\n}\n.md-source__fact {\n display: inline-block;\n}\n[data-md-state=done] .md-source__fact {\n animation: fact 400ms ease-out;\n}\n.md-source__fact::before {\n display: inline-block;\n width: 0.6rem;\n height: 0.6rem;\n margin-right: 0.1rem;\n vertical-align: text-top;\n background-color: currentColor;\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n}\n[dir=rtl] .md-source__fact::before {\n margin-right: initial;\n margin-left: 0.1rem;\n}\n.md-source__fact:nth-child(1n+2)::before {\n margin-left: 0.4rem;\n}\n[dir=rtl] .md-source__fact:nth-child(1n+2)::before {\n margin-right: 0.4rem;\n margin-left: 0.1rem;\n}\n.md-source__fact--version::before {\n mask-image: var(--md-source-version-icon);\n}\n.md-source__fact--stars::before {\n mask-image: var(--md-source-stars-icon);\n}\n.md-source__fact--forks::before {\n mask-image: var(--md-source-forks-icon);\n}\n.md-source__fact--repositories::before {\n mask-image: var(--md-source-repositories-icon);\n}\n\n.md-tabs {\n width: 100%;\n overflow: auto;\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n}\n@media print {\n .md-tabs {\n display: none;\n }\n}\n@media screen and (max-width: 76.1875em) {\n .md-tabs {\n display: none;\n }\n}\n.md-tabs[data-md-state=hidden] {\n pointer-events: none;\n}\n.md-tabs__list {\n margin: 0;\n margin-left: 0.2rem;\n padding: 0;\n white-space: nowrap;\n list-style: none;\n contain: content;\n}\n[dir=rtl] .md-tabs__list {\n margin-right: 0.2rem;\n margin-left: initial;\n}\n.md-tabs__item {\n display: inline-block;\n height: 2.4rem;\n padding-right: 0.6rem;\n padding-left: 0.6rem;\n}\n.md-tabs__link {\n display: block;\n margin-top: 0.8rem;\n font-size: 0.7rem;\n outline-color: var(--md-accent-fg-color);\n outline-offset: 0.2rem;\n backface-visibility: hidden;\n opacity: 0.7;\n transition: transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1), opacity 250ms;\n}\n.md-tabs__link--active, .md-tabs__link:focus, .md-tabs__link:hover {\n color: inherit;\n opacity: 1;\n}\n.md-tabs__item:nth-child(2) .md-tabs__link {\n transition-delay: 20ms;\n}\n.md-tabs__item:nth-child(3) .md-tabs__link {\n transition-delay: 40ms;\n}\n.md-tabs__item:nth-child(4) .md-tabs__link {\n transition-delay: 60ms;\n}\n.md-tabs__item:nth-child(5) .md-tabs__link {\n transition-delay: 80ms;\n}\n.md-tabs__item:nth-child(6) .md-tabs__link {\n transition-delay: 100ms;\n}\n.md-tabs__item:nth-child(7) .md-tabs__link {\n transition-delay: 120ms;\n}\n.md-tabs__item:nth-child(8) .md-tabs__link {\n transition-delay: 140ms;\n}\n.md-tabs__item:nth-child(9) .md-tabs__link {\n transition-delay: 160ms;\n}\n.md-tabs__item:nth-child(10) .md-tabs__link {\n transition-delay: 180ms;\n}\n.md-tabs__item:nth-child(11) .md-tabs__link {\n transition-delay: 200ms;\n}\n.md-tabs__item:nth-child(12) .md-tabs__link {\n transition-delay: 220ms;\n}\n.md-tabs__item:nth-child(13) .md-tabs__link {\n transition-delay: 240ms;\n}\n.md-tabs__item:nth-child(14) .md-tabs__link {\n transition-delay: 260ms;\n}\n.md-tabs__item:nth-child(15) .md-tabs__link {\n transition-delay: 280ms;\n}\n.md-tabs__item:nth-child(16) .md-tabs__link {\n transition-delay: 300ms;\n}\n.md-tabs[data-md-state=hidden] .md-tabs__link {\n transform: translateY(50%);\n opacity: 0;\n transition: transform 0ms 100ms, opacity 100ms;\n}\n\n.md-top {\n position: fixed;\n top: 3.2rem;\n z-index: 2;\n margin-left: 50%;\n padding: 0.4rem 0.8rem;\n color: var(--md-default-fg-color--light);\n font-size: 0.7rem;\n background-color: var(--md-default-bg-color);\n border-radius: 1.6rem;\n outline: none;\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.1), 0 0 0.05rem rgba(0, 0, 0, 0.25);\n transform: translate(-50%, 0);\n transition: color 125ms, background-color 125ms, transform 125ms cubic-bezier(0.4, 0, 0.2, 1), opacity 125ms;\n}\n@media print {\n .md-top {\n display: none;\n }\n}\n[dir=rtl] .md-top {\n margin-right: 50%;\n margin-left: initial;\n transform: translate(50%, 0);\n}\n.md-top[data-md-state=hidden] {\n transform: translate(-50%, 0.2rem);\n opacity: 0;\n transition-duration: 0ms;\n pointer-events: none;\n}\n[dir=rtl] .md-top[data-md-state=hidden] {\n transform: translate(50%, 0.2rem);\n}\n.md-top:focus, .md-top:hover {\n color: var(--md-accent-bg-color);\n background-color: var(--md-accent-fg-color);\n}\n.md-top svg {\n display: inline-block;\n vertical-align: -0.5em;\n}\n\n@keyframes hoverfix {\n 0% {\n pointer-events: none;\n }\n}\n:root {\n --md-version-icon: svg-load(\"fontawesome/solid/caret-down.svg\");\n}\n\n.md-version {\n flex-shrink: 0;\n height: 2.4rem;\n font-size: 0.8rem;\n}\n.md-version__current {\n position: relative;\n top: 0.05rem;\n margin-right: 0.4rem;\n margin-left: 1.4rem;\n color: inherit;\n outline: none;\n cursor: pointer;\n}\n[dir=rtl] .md-version__current {\n margin-right: 1.4rem;\n margin-left: 0.4rem;\n}\n.md-version__current::after {\n display: inline-block;\n width: 0.4rem;\n height: 0.6rem;\n margin-left: 0.4rem;\n background-color: currentColor;\n mask-image: var(--md-version-icon);\n mask-repeat: no-repeat;\n content: \"\";\n}\n[dir=rtl] .md-version__current::after {\n margin-right: 0.4rem;\n margin-left: initial;\n}\n.md-version__list {\n position: absolute;\n top: 0.15rem;\n z-index: 1;\n max-height: 0;\n margin: 0.2rem 0.8rem;\n padding: 0;\n overflow: auto;\n color: var(--md-default-fg-color);\n list-style-type: none;\n background-color: var(--md-default-bg-color);\n border-radius: 0.1rem;\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.1), 0 0 0.05rem rgba(0, 0, 0, 0.25);\n opacity: 0;\n transition: max-height 0ms 500ms, opacity 250ms 250ms;\n scroll-snap-type: y mandatory;\n}\n.md-version:focus-within .md-version__list, .md-version:hover .md-version__list {\n max-height: 10rem;\n opacity: 1;\n transition: max-height 0ms, opacity 250ms;\n}\n@media (pointer: coarse) {\n .md-version:hover .md-version__list {\n animation: hoverfix 250ms forwards;\n }\n .md-version:focus-within .md-version__list {\n animation: none;\n }\n}\n.md-version__item {\n line-height: 1.8rem;\n}\n.md-version__link {\n display: block;\n width: 100%;\n padding-right: 1.2rem;\n padding-left: 0.6rem;\n white-space: nowrap;\n outline: none;\n cursor: pointer;\n transition: color 250ms, background-color 250ms;\n scroll-snap-align: start;\n}\n[dir=rtl] .md-version__link {\n padding-right: 0.6rem;\n padding-left: 1.2rem;\n}\n.md-version__link:focus, .md-version__link:hover {\n color: var(--md-accent-fg-color);\n}\n.md-version__link:focus {\n background-color: var(--md-default-fg-color--lightest);\n}\n\n:root {\n --md-admonition-icon--note:\n svg-load(\"material/pencil.svg\");\n --md-admonition-icon--abstract:\n svg-load(\"material/clipboard-text.svg\");\n --md-admonition-icon--info:\n svg-load(\"material/information.svg\");\n --md-admonition-icon--tip:\n svg-load(\"material/fire.svg\");\n --md-admonition-icon--success:\n svg-load(\"material/check-bold.svg\");\n --md-admonition-icon--question:\n svg-load(\"material/help-circle.svg\");\n --md-admonition-icon--warning:\n svg-load(\"material/alert.svg\");\n --md-admonition-icon--failure:\n svg-load(\"material/close-thick.svg\");\n --md-admonition-icon--danger:\n svg-load(\"material/lightning-bolt.svg\");\n --md-admonition-icon--bug:\n svg-load(\"material/bug.svg\");\n --md-admonition-icon--example:\n svg-load(\"material/format-list-numbered.svg\");\n --md-admonition-icon--quote:\n svg-load(\"material/format-quote-close.svg\");\n}\n\n.md-typeset .admonition, .md-typeset details {\n margin: 1.5625em 0;\n padding: 0 0.6rem;\n overflow: hidden;\n color: var(--md-admonition-fg-color);\n font-size: 0.64rem;\n page-break-inside: avoid;\n background-color: var(--md-admonition-bg-color);\n border-left: 0.2rem solid #448aff;\n border-radius: 0.1rem;\n box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0.025rem 0.05rem rgba(0, 0, 0, 0.05);\n}\n@media print {\n .md-typeset .admonition, .md-typeset details {\n box-shadow: none;\n }\n}\n[dir=rtl] .md-typeset .admonition, [dir=rtl] .md-typeset details {\n border-right: 0.2rem solid #448aff;\n border-left: none;\n}\n.md-typeset .admonition .admonition, .md-typeset details .admonition, .md-typeset .admonition details, .md-typeset details details {\n margin-top: 1em;\n margin-bottom: 1em;\n}\n.md-typeset .admonition .md-typeset__scrollwrap, .md-typeset details .md-typeset__scrollwrap {\n margin: 1em -0.6rem;\n}\n.md-typeset .admonition .md-typeset__table, .md-typeset details .md-typeset__table {\n padding: 0 0.6rem;\n}\n.md-typeset .admonition > .tabbed-set:only-child, .md-typeset details > .tabbed-set:only-child {\n margin-top: 0;\n}\nhtml .md-typeset .admonition > :last-child, html .md-typeset details > :last-child {\n margin-bottom: 0.6rem;\n}\n.md-typeset .admonition-title, .md-typeset summary {\n position: relative;\n margin: 0 -0.6rem 0 -0.8rem;\n padding: 0.4rem 0.6rem 0.4rem 2rem;\n font-weight: 700;\n background-color: rgba(68, 138, 255, 0.1);\n border-left: 0.2rem solid #448aff;\n}\n[dir=rtl] .md-typeset .admonition-title, [dir=rtl] .md-typeset summary {\n margin: 0 -0.8rem 0 -0.6rem;\n padding: 0.4rem 2rem 0.4rem 0.6rem;\n border-right: 0.2rem solid #448aff;\n border-left: none;\n}\nhtml .md-typeset .admonition-title:last-child, html .md-typeset summary:last-child {\n margin-bottom: 0;\n}\n.md-typeset .admonition-title::before, .md-typeset summary::before {\n position: absolute;\n left: 0.6rem;\n width: 1rem;\n height: 1rem;\n background-color: #448aff;\n mask-image: var(--md-admonition-icon--note);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n}\n[dir=rtl] .md-typeset .admonition-title::before, [dir=rtl] .md-typeset summary::before {\n right: 0.6rem;\n left: initial;\n}\n\n.md-typeset .admonition.note, .md-typeset details.note {\n border-color: #448aff;\n}\n\n.md-typeset .note > .admonition-title, .md-typeset .note > summary {\n background-color: rgba(68, 138, 255, 0.1);\n border-color: #448aff;\n}\n.md-typeset .note > .admonition-title::before, .md-typeset .note > summary::before {\n background-color: #448aff;\n mask-image: var(--md-admonition-icon--note);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.abstract, .md-typeset details.abstract, .md-typeset .admonition.tldr, .md-typeset details.tldr, .md-typeset .admonition.summary, .md-typeset details.summary {\n border-color: #00b0ff;\n}\n\n.md-typeset .abstract > .admonition-title, .md-typeset .abstract > summary, .md-typeset .tldr > .admonition-title, .md-typeset .tldr > summary, .md-typeset .summary > .admonition-title, .md-typeset .summary > summary {\n background-color: rgba(0, 176, 255, 0.1);\n border-color: #00b0ff;\n}\n.md-typeset .abstract > .admonition-title::before, .md-typeset .abstract > summary::before, .md-typeset .tldr > .admonition-title::before, .md-typeset .tldr > summary::before, .md-typeset .summary > .admonition-title::before, .md-typeset .summary > summary::before {\n background-color: #00b0ff;\n mask-image: var(--md-admonition-icon--abstract);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.info, .md-typeset details.info, .md-typeset .admonition.todo, .md-typeset details.todo {\n border-color: #00b8d4;\n}\n\n.md-typeset .info > .admonition-title, .md-typeset .info > summary, .md-typeset .todo > .admonition-title, .md-typeset .todo > summary {\n background-color: rgba(0, 184, 212, 0.1);\n border-color: #00b8d4;\n}\n.md-typeset .info > .admonition-title::before, .md-typeset .info > summary::before, .md-typeset .todo > .admonition-title::before, .md-typeset .todo > summary::before {\n background-color: #00b8d4;\n mask-image: var(--md-admonition-icon--info);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.tip, .md-typeset details.tip, .md-typeset .admonition.important, .md-typeset details.important, .md-typeset .admonition.hint, .md-typeset details.hint {\n border-color: #00bfa5;\n}\n\n.md-typeset .tip > .admonition-title, .md-typeset .tip > summary, .md-typeset .important > .admonition-title, .md-typeset .important > summary, .md-typeset .hint > .admonition-title, .md-typeset .hint > summary {\n background-color: rgba(0, 191, 165, 0.1);\n border-color: #00bfa5;\n}\n.md-typeset .tip > .admonition-title::before, .md-typeset .tip > summary::before, .md-typeset .important > .admonition-title::before, .md-typeset .important > summary::before, .md-typeset .hint > .admonition-title::before, .md-typeset .hint > summary::before {\n background-color: #00bfa5;\n mask-image: var(--md-admonition-icon--tip);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.success, .md-typeset details.success, .md-typeset .admonition.done, .md-typeset details.done, .md-typeset .admonition.check, .md-typeset details.check {\n border-color: #00c853;\n}\n\n.md-typeset .success > .admonition-title, .md-typeset .success > summary, .md-typeset .done > .admonition-title, .md-typeset .done > summary, .md-typeset .check > .admonition-title, .md-typeset .check > summary {\n background-color: rgba(0, 200, 83, 0.1);\n border-color: #00c853;\n}\n.md-typeset .success > .admonition-title::before, .md-typeset .success > summary::before, .md-typeset .done > .admonition-title::before, .md-typeset .done > summary::before, .md-typeset .check > .admonition-title::before, .md-typeset .check > summary::before {\n background-color: #00c853;\n mask-image: var(--md-admonition-icon--success);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.question, .md-typeset details.question, .md-typeset .admonition.faq, .md-typeset details.faq, .md-typeset .admonition.help, .md-typeset details.help {\n border-color: #64dd17;\n}\n\n.md-typeset .question > .admonition-title, .md-typeset .question > summary, .md-typeset .faq > .admonition-title, .md-typeset .faq > summary, .md-typeset .help > .admonition-title, .md-typeset .help > summary {\n background-color: rgba(100, 221, 23, 0.1);\n border-color: #64dd17;\n}\n.md-typeset .question > .admonition-title::before, .md-typeset .question > summary::before, .md-typeset .faq > .admonition-title::before, .md-typeset .faq > summary::before, .md-typeset .help > .admonition-title::before, .md-typeset .help > summary::before {\n background-color: #64dd17;\n mask-image: var(--md-admonition-icon--question);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.warning, .md-typeset details.warning, .md-typeset .admonition.attention, .md-typeset details.attention, .md-typeset .admonition.caution, .md-typeset details.caution {\n border-color: #ff9100;\n}\n\n.md-typeset .warning > .admonition-title, .md-typeset .warning > summary, .md-typeset .attention > .admonition-title, .md-typeset .attention > summary, .md-typeset .caution > .admonition-title, .md-typeset .caution > summary {\n background-color: rgba(255, 145, 0, 0.1);\n border-color: #ff9100;\n}\n.md-typeset .warning > .admonition-title::before, .md-typeset .warning > summary::before, .md-typeset .attention > .admonition-title::before, .md-typeset .attention > summary::before, .md-typeset .caution > .admonition-title::before, .md-typeset .caution > summary::before {\n background-color: #ff9100;\n mask-image: var(--md-admonition-icon--warning);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.failure, .md-typeset details.failure, .md-typeset .admonition.missing, .md-typeset details.missing, .md-typeset .admonition.fail, .md-typeset details.fail {\n border-color: #ff5252;\n}\n\n.md-typeset .failure > .admonition-title, .md-typeset .failure > summary, .md-typeset .missing > .admonition-title, .md-typeset .missing > summary, .md-typeset .fail > .admonition-title, .md-typeset .fail > summary {\n background-color: rgba(255, 82, 82, 0.1);\n border-color: #ff5252;\n}\n.md-typeset .failure > .admonition-title::before, .md-typeset .failure > summary::before, .md-typeset .missing > .admonition-title::before, .md-typeset .missing > summary::before, .md-typeset .fail > .admonition-title::before, .md-typeset .fail > summary::before {\n background-color: #ff5252;\n mask-image: var(--md-admonition-icon--failure);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.danger, .md-typeset details.danger, .md-typeset .admonition.error, .md-typeset details.error {\n border-color: #ff1744;\n}\n\n.md-typeset .danger > .admonition-title, .md-typeset .danger > summary, .md-typeset .error > .admonition-title, .md-typeset .error > summary {\n background-color: rgba(255, 23, 68, 0.1);\n border-color: #ff1744;\n}\n.md-typeset .danger > .admonition-title::before, .md-typeset .danger > summary::before, .md-typeset .error > .admonition-title::before, .md-typeset .error > summary::before {\n background-color: #ff1744;\n mask-image: var(--md-admonition-icon--danger);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.bug, .md-typeset details.bug {\n border-color: #f50057;\n}\n\n.md-typeset .bug > .admonition-title, .md-typeset .bug > summary {\n background-color: rgba(245, 0, 87, 0.1);\n border-color: #f50057;\n}\n.md-typeset .bug > .admonition-title::before, .md-typeset .bug > summary::before {\n background-color: #f50057;\n mask-image: var(--md-admonition-icon--bug);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.example, .md-typeset details.example {\n border-color: #7c4dff;\n}\n\n.md-typeset .example > .admonition-title, .md-typeset .example > summary {\n background-color: rgba(124, 77, 255, 0.1);\n border-color: #7c4dff;\n}\n.md-typeset .example > .admonition-title::before, .md-typeset .example > summary::before {\n background-color: #7c4dff;\n mask-image: var(--md-admonition-icon--example);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n.md-typeset .admonition.quote, .md-typeset details.quote, .md-typeset .admonition.cite, .md-typeset details.cite {\n border-color: #9e9e9e;\n}\n\n.md-typeset .quote > .admonition-title, .md-typeset .quote > summary, .md-typeset .cite > .admonition-title, .md-typeset .cite > summary {\n background-color: rgba(158, 158, 158, 0.1);\n border-color: #9e9e9e;\n}\n.md-typeset .quote > .admonition-title::before, .md-typeset .quote > summary::before, .md-typeset .cite > .admonition-title::before, .md-typeset .cite > summary::before {\n background-color: #9e9e9e;\n mask-image: var(--md-admonition-icon--quote);\n mask-repeat: no-repeat;\n mask-size: contain;\n}\n\n:root {\n --md-footnotes-icon: svg-load(\"material/keyboard-return.svg\");\n}\n\n.md-typeset .footnote {\n color: var(--md-default-fg-color--light);\n font-size: 0.64rem;\n}\n.md-typeset .footnote > ol {\n margin-left: 0;\n}\n.md-typeset .footnote > ol > li {\n transition: color 125ms;\n}\n.md-typeset .footnote > ol > li:target {\n color: var(--md-default-fg-color);\n}\n.md-typeset .footnote > ol > li:hover .footnote-backref, .md-typeset .footnote > ol > li:target .footnote-backref {\n transform: translateX(0);\n opacity: 1;\n}\n.md-typeset .footnote > ol > li > :first-child {\n margin-top: 0;\n}\n.md-typeset .footnote-ref {\n font-weight: 700;\n font-size: 0.75em;\n}\nhtml .md-typeset .footnote-ref {\n outline-offset: 0.1rem;\n}\n.md-typeset .footnote-backref {\n display: inline-block;\n color: var(--md-typeset-a-color);\n font-size: 0;\n vertical-align: text-bottom;\n transform: translateX(0.25rem);\n opacity: 0;\n transition: color 250ms, transform 250ms 250ms, opacity 125ms 250ms;\n}\n@media print {\n .md-typeset .footnote-backref {\n color: var(--md-typeset-a-color);\n transform: translateX(0);\n opacity: 1;\n }\n}\n[dir=rtl] .md-typeset .footnote-backref {\n transform: translateX(-0.25rem);\n}\n.md-typeset .footnote-backref:hover {\n color: var(--md-accent-fg-color);\n}\n.md-typeset .footnote-backref::before {\n display: inline-block;\n width: 0.8rem;\n height: 0.8rem;\n background-color: currentColor;\n mask-image: var(--md-footnotes-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n}\n[dir=rtl] .md-typeset .footnote-backref::before svg {\n transform: scaleX(-1);\n}\n.md-typeset [id^=\"fnref:\"]:target {\n scroll-margin-top: initial;\n margin-top: -3.4rem;\n padding-top: 3.4rem;\n}\n.md-typeset [id^=\"fnref:\"]:target > .footnote-ref {\n outline: auto;\n}\n.md-typeset [id^=\"fn:\"]:target {\n scroll-margin-top: initial;\n margin-top: -3.45rem;\n padding-top: 3.45rem;\n}\n\n.md-typeset .headerlink {\n display: inline-block;\n margin-left: 0.5rem;\n color: var(--md-default-fg-color--lighter);\n opacity: 0;\n transition: color 250ms, opacity 125ms;\n}\n@media print {\n .md-typeset .headerlink {\n display: none;\n }\n}\n[dir=rtl] .md-typeset .headerlink {\n margin-right: 0.5rem;\n margin-left: initial;\n}\n.md-typeset :hover > .headerlink,\n.md-typeset :target > .headerlink,\n.md-typeset .headerlink:focus {\n opacity: 1;\n transition: color 250ms, opacity 125ms;\n}\n.md-typeset :target > .headerlink,\n.md-typeset .headerlink:focus,\n.md-typeset .headerlink:hover {\n color: var(--md-accent-fg-color);\n}\n.md-typeset :target {\n scroll-margin-top: 3.6rem;\n}\n@media screen and (min-width: 76.25em) {\n .md-header--lifted ~ .md-container .md-typeset :target {\n scroll-margin-top: 6rem;\n }\n}\n.md-typeset h1:target,\n.md-typeset h2:target,\n.md-typeset h3:target {\n scroll-margin-top: initial;\n}\n.md-typeset h1:target::before,\n.md-typeset h2:target::before,\n.md-typeset h3:target::before {\n display: block;\n margin-top: -3.4rem;\n padding-top: 3.4rem;\n content: \"\";\n}\n@media screen and (min-width: 76.25em) {\n .md-header--lifted ~ .md-container .md-typeset h1:target,\n.md-header--lifted ~ .md-container .md-typeset h2:target,\n.md-header--lifted ~ .md-container .md-typeset h3:target {\n scroll-margin-top: initial;\n }\n .md-header--lifted ~ .md-container .md-typeset h1:target::before,\n.md-header--lifted ~ .md-container .md-typeset h2:target::before,\n.md-header--lifted ~ .md-container .md-typeset h3:target::before {\n margin-top: -5.8rem;\n padding-top: 5.8rem;\n }\n}\n.md-typeset h4:target {\n scroll-margin-top: initial;\n}\n.md-typeset h4:target::before {\n display: block;\n margin-top: -3.45rem;\n padding-top: 3.45rem;\n content: \"\";\n}\n@media screen and (min-width: 76.25em) {\n .md-header--lifted ~ .md-container .md-typeset h4:target {\n scroll-margin-top: initial;\n }\n .md-header--lifted ~ .md-container .md-typeset h4:target::before {\n margin-top: -5.85rem;\n padding-top: 5.85rem;\n }\n}\n.md-typeset h5:target,\n.md-typeset h6:target {\n scroll-margin-top: initial;\n}\n.md-typeset h5:target::before,\n.md-typeset h6:target::before {\n display: block;\n margin-top: -3.6rem;\n padding-top: 3.6rem;\n content: \"\";\n}\n@media screen and (min-width: 76.25em) {\n .md-header--lifted ~ .md-container .md-typeset h5:target,\n.md-header--lifted ~ .md-container .md-typeset h6:target {\n scroll-margin-top: initial;\n }\n .md-header--lifted ~ .md-container .md-typeset h5:target::before,\n.md-header--lifted ~ .md-container .md-typeset h6:target::before {\n margin-top: -6rem;\n padding-top: 6rem;\n }\n}\n\n.md-typeset div.arithmatex {\n overflow: auto;\n}\n@media screen and (max-width: 44.9375em) {\n .md-typeset div.arithmatex {\n margin: 0 -0.8rem;\n }\n}\n.md-typeset div.arithmatex > * {\n width: min-content;\n margin: 1em auto !important;\n padding: 0 0.8rem;\n touch-action: auto;\n}\n\n.md-typeset del.critic,\n.md-typeset ins.critic,\n.md-typeset .critic.comment {\n box-decoration-break: clone;\n}\n.md-typeset del.critic {\n background-color: var(--md-typeset-del-color);\n}\n.md-typeset ins.critic {\n background-color: var(--md-typeset-ins-color);\n}\n.md-typeset .critic.comment {\n color: var(--md-code-hl-comment-color);\n}\n.md-typeset .critic.comment::before {\n content: \"/* \";\n}\n.md-typeset .critic.comment::after {\n content: \" */\";\n}\n.md-typeset .critic.block {\n display: block;\n margin: 1em 0;\n padding-right: 0.8rem;\n padding-left: 0.8rem;\n overflow: auto;\n box-shadow: none;\n}\n.md-typeset .critic.block > :first-child {\n margin-top: 0.5em;\n}\n.md-typeset .critic.block > :last-child {\n margin-bottom: 0.5em;\n}\n\n:root {\n --md-details-icon: svg-load(\"material/chevron-right.svg\");\n}\n\n.md-typeset details {\n display: flow-root;\n padding-top: 0;\n overflow: visible;\n}\n.md-typeset details[open] > summary::after {\n transform: rotate(90deg);\n}\n.md-typeset details:not([open]) {\n padding-bottom: 0;\n box-shadow: none;\n}\n.md-typeset details:not([open]) > summary {\n border-radius: 0.1rem;\n}\n.md-typeset details::after {\n display: table;\n content: \"\";\n}\n.md-typeset summary {\n display: block;\n min-height: 1rem;\n padding: 0.4rem 1.8rem 0.4rem 2rem;\n border-top-left-radius: 0.1rem;\n border-top-right-radius: 0.1rem;\n cursor: pointer;\n}\n[dir=rtl] .md-typeset summary {\n padding: 0.4rem 2.2rem 0.4rem 1.8rem;\n}\n.md-typeset summary.focus-visible {\n outline-color: var(--md-accent-fg-color);\n outline-offset: 0.2rem;\n}\n.md-typeset summary:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n.md-typeset summary::after {\n position: absolute;\n top: 0.4rem;\n right: 0.4rem;\n width: 1rem;\n height: 1rem;\n background-color: currentColor;\n mask-image: var(--md-details-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n transform: rotate(0deg);\n transition: transform 250ms;\n content: \"\";\n}\n[dir=rtl] .md-typeset summary::after {\n right: initial;\n left: 0.4rem;\n transform: rotate(180deg);\n}\n.md-typeset summary::marker, .md-typeset summary::-webkit-details-marker {\n display: none;\n}\n\n.md-typeset .emojione,\n.md-typeset .twemoji,\n.md-typeset .gemoji {\n display: inline-flex;\n height: 1.125em;\n vertical-align: text-top;\n}\n.md-typeset .emojione svg,\n.md-typeset .twemoji svg,\n.md-typeset .gemoji svg {\n width: 1.125em;\n max-height: 100%;\n fill: currentColor;\n}\n\n.highlight .o,\n.highlight .ow {\n color: var(--md-code-hl-operator-color);\n}\n.highlight .p {\n color: var(--md-code-hl-punctuation-color);\n}\n.highlight .cpf,\n.highlight .l,\n.highlight .s,\n.highlight .sb,\n.highlight .sc,\n.highlight .s2,\n.highlight .si,\n.highlight .s1,\n.highlight .ss {\n color: var(--md-code-hl-string-color);\n}\n.highlight .cp,\n.highlight .se,\n.highlight .sh,\n.highlight .sr,\n.highlight .sx {\n color: var(--md-code-hl-special-color);\n}\n.highlight .m,\n.highlight .mb,\n.highlight .mf,\n.highlight .mh,\n.highlight .mi,\n.highlight .il,\n.highlight .mo {\n color: var(--md-code-hl-number-color);\n}\n.highlight .k,\n.highlight .kd,\n.highlight .kn,\n.highlight .kp,\n.highlight .kr,\n.highlight .kt {\n color: var(--md-code-hl-keyword-color);\n}\n.highlight .kc,\n.highlight .n {\n color: var(--md-code-hl-name-color);\n}\n.highlight .no,\n.highlight .nb,\n.highlight .bp {\n color: var(--md-code-hl-constant-color);\n}\n.highlight .nc,\n.highlight .ne,\n.highlight .nf,\n.highlight .nn {\n color: var(--md-code-hl-function-color);\n}\n.highlight .nd,\n.highlight .ni,\n.highlight .nl,\n.highlight .nt {\n color: var(--md-code-hl-keyword-color);\n}\n.highlight .c,\n.highlight .cm,\n.highlight .c1,\n.highlight .ch,\n.highlight .cs,\n.highlight .sd {\n color: var(--md-code-hl-comment-color);\n}\n.highlight .na,\n.highlight .nv,\n.highlight .vc,\n.highlight .vg,\n.highlight .vi {\n color: var(--md-code-hl-variable-color);\n}\n.highlight .ge,\n.highlight .gr,\n.highlight .gh,\n.highlight .go,\n.highlight .gp,\n.highlight .gs,\n.highlight .gu,\n.highlight .gt {\n color: var(--md-code-hl-generic-color);\n}\n.highlight .gd,\n.highlight .gi {\n margin: 0 -0.125em;\n padding: 0 0.125em;\n border-radius: 0.1rem;\n}\n.highlight .gd {\n background-color: var(--md-typeset-del-color);\n}\n.highlight .gi {\n background-color: var(--md-typeset-ins-color);\n}\n.highlight .hll {\n display: block;\n margin: 0 -1.1764705882em;\n padding: 0 1.1764705882em;\n background-color: var(--md-code-hl-color);\n}\n.highlight span.filename {\n position: relative;\n display: block;\n margin-top: 1em;\n padding: 0.7720588235em 1.1764705882em;\n font-weight: 700;\n font-size: 0.85em;\n background-color: var(--md-code-bg-color);\n border-bottom: 0.05rem solid var(--md-default-fg-color--lightest);\n border-top-left-radius: 0.1rem;\n border-top-right-radius: 0.1rem;\n}\n.highlight span.filename + pre {\n margin-top: 0;\n}\n.highlight [data-linenos]::before {\n position: sticky;\n left: -1.1764705882em;\n float: left;\n margin-right: 1.1764705882em;\n margin-left: -1.1764705882em;\n padding-left: 1.1764705882em;\n color: var(--md-default-fg-color--light);\n background-color: var(--md-code-bg-color);\n box-shadow: -0.05rem 0 var(--md-default-fg-color--lightest) inset;\n content: attr(data-linenos);\n user-select: none;\n}\n\n.highlighttable {\n display: flow-root;\n overflow: hidden;\n}\n.highlighttable tbody,\n.highlighttable td {\n display: block;\n padding: 0;\n}\n.highlighttable tr {\n display: flex;\n}\n.highlighttable pre {\n margin: 0;\n}\n.highlighttable th.filename {\n flex-grow: 1;\n padding: 0;\n text-align: left;\n}\n.highlighttable .linenos {\n padding: 0.7720588235em 1.1764705882em;\n padding-right: 0;\n font-size: 0.85em;\n background-color: var(--md-code-bg-color);\n user-select: none;\n}\n.highlighttable .linenodiv {\n padding-right: 0.5882352941em;\n box-shadow: -0.05rem 0 var(--md-default-fg-color--lightest) inset;\n}\n.highlighttable .linenodiv pre {\n color: var(--md-default-fg-color--light);\n text-align: right;\n}\n.highlighttable .code {\n flex: 1;\n overflow: hidden;\n}\n\n.md-typeset .highlighttable {\n margin: 1em 0;\n direction: ltr;\n border-radius: 0.1rem;\n}\n.md-typeset .highlighttable code {\n border-radius: 0;\n}\n@media screen and (max-width: 44.9375em) {\n .md-typeset > .highlight {\n margin: 1em -0.8rem;\n }\n .md-typeset > .highlight .hll {\n margin: 0 -0.8rem;\n padding: 0 0.8rem;\n }\n .md-typeset > .highlight code {\n border-radius: 0;\n }\n .md-typeset > .highlighttable {\n margin: 1em -0.8rem;\n border-radius: 0;\n }\n .md-typeset > .highlighttable .hll {\n margin: 0 -0.8rem;\n padding: 0 0.8rem;\n }\n}\n\n.md-typeset .keys kbd::before,\n.md-typeset .keys kbd::after {\n position: relative;\n margin: 0;\n color: inherit;\n -moz-osx-font-smoothing: initial;\n -webkit-font-smoothing: initial;\n}\n.md-typeset .keys span {\n padding: 0 0.2em;\n color: var(--md-default-fg-color--light);\n}\n.md-typeset .keys .key-alt::before {\n padding-right: 0.4em;\n content: \"⎇\";\n}\n.md-typeset .keys .key-left-alt::before {\n padding-right: 0.4em;\n content: \"⎇\";\n}\n.md-typeset .keys .key-right-alt::before {\n padding-right: 0.4em;\n content: \"⎇\";\n}\n.md-typeset .keys .key-command::before {\n padding-right: 0.4em;\n content: \"⌘\";\n}\n.md-typeset .keys .key-left-command::before {\n padding-right: 0.4em;\n content: \"⌘\";\n}\n.md-typeset .keys .key-right-command::before {\n padding-right: 0.4em;\n content: \"⌘\";\n}\n.md-typeset .keys .key-control::before {\n padding-right: 0.4em;\n content: \"⌃\";\n}\n.md-typeset .keys .key-left-control::before {\n padding-right: 0.4em;\n content: \"⌃\";\n}\n.md-typeset .keys .key-right-control::before {\n padding-right: 0.4em;\n content: \"⌃\";\n}\n.md-typeset .keys .key-meta::before {\n padding-right: 0.4em;\n content: \"◆\";\n}\n.md-typeset .keys .key-left-meta::before {\n padding-right: 0.4em;\n content: \"◆\";\n}\n.md-typeset .keys .key-right-meta::before {\n padding-right: 0.4em;\n content: \"◆\";\n}\n.md-typeset .keys .key-option::before {\n padding-right: 0.4em;\n content: \"⌥\";\n}\n.md-typeset .keys .key-left-option::before {\n padding-right: 0.4em;\n content: \"⌥\";\n}\n.md-typeset .keys .key-right-option::before {\n padding-right: 0.4em;\n content: \"⌥\";\n}\n.md-typeset .keys .key-shift::before {\n padding-right: 0.4em;\n content: \"⇧\";\n}\n.md-typeset .keys .key-left-shift::before {\n padding-right: 0.4em;\n content: \"⇧\";\n}\n.md-typeset .keys .key-right-shift::before {\n padding-right: 0.4em;\n content: \"⇧\";\n}\n.md-typeset .keys .key-super::before {\n padding-right: 0.4em;\n content: \"❖\";\n}\n.md-typeset .keys .key-left-super::before {\n padding-right: 0.4em;\n content: \"❖\";\n}\n.md-typeset .keys .key-right-super::before {\n padding-right: 0.4em;\n content: \"❖\";\n}\n.md-typeset .keys .key-windows::before {\n padding-right: 0.4em;\n content: \"⊞\";\n}\n.md-typeset .keys .key-left-windows::before {\n padding-right: 0.4em;\n content: \"⊞\";\n}\n.md-typeset .keys .key-right-windows::before {\n padding-right: 0.4em;\n content: \"⊞\";\n}\n.md-typeset .keys .key-arrow-down::before {\n padding-right: 0.4em;\n content: \"↓\";\n}\n.md-typeset .keys .key-arrow-left::before {\n padding-right: 0.4em;\n content: \"←\";\n}\n.md-typeset .keys .key-arrow-right::before {\n padding-right: 0.4em;\n content: \"→\";\n}\n.md-typeset .keys .key-arrow-up::before {\n padding-right: 0.4em;\n content: \"↑\";\n}\n.md-typeset .keys .key-backspace::before {\n padding-right: 0.4em;\n content: \"⌫\";\n}\n.md-typeset .keys .key-backtab::before {\n padding-right: 0.4em;\n content: \"⇤\";\n}\n.md-typeset .keys .key-caps-lock::before {\n padding-right: 0.4em;\n content: \"⇪\";\n}\n.md-typeset .keys .key-clear::before {\n padding-right: 0.4em;\n content: \"⌧\";\n}\n.md-typeset .keys .key-context-menu::before {\n padding-right: 0.4em;\n content: \"☰\";\n}\n.md-typeset .keys .key-delete::before {\n padding-right: 0.4em;\n content: \"⌦\";\n}\n.md-typeset .keys .key-eject::before {\n padding-right: 0.4em;\n content: \"⏏\";\n}\n.md-typeset .keys .key-end::before {\n padding-right: 0.4em;\n content: \"⤓\";\n}\n.md-typeset .keys .key-escape::before {\n padding-right: 0.4em;\n content: \"⎋\";\n}\n.md-typeset .keys .key-home::before {\n padding-right: 0.4em;\n content: \"⤒\";\n}\n.md-typeset .keys .key-insert::before {\n padding-right: 0.4em;\n content: \"⎀\";\n}\n.md-typeset .keys .key-page-down::before {\n padding-right: 0.4em;\n content: \"⇟\";\n}\n.md-typeset .keys .key-page-up::before {\n padding-right: 0.4em;\n content: \"⇞\";\n}\n.md-typeset .keys .key-print-screen::before {\n padding-right: 0.4em;\n content: \"⎙\";\n}\n.md-typeset .keys .key-tab::after {\n padding-left: 0.4em;\n content: \"⇥\";\n}\n.md-typeset .keys .key-num-enter::after {\n padding-left: 0.4em;\n content: \"⌤\";\n}\n.md-typeset .keys .key-enter::after {\n padding-left: 0.4em;\n content: \"⏎\";\n}\n\n.md-typeset .tabbed-content {\n display: none;\n order: 99;\n width: 100%;\n box-shadow: 0 -0.05rem var(--md-default-fg-color--lightest);\n}\n@media print {\n .md-typeset .tabbed-content {\n display: block;\n order: initial;\n }\n}\n.md-typeset .tabbed-content > pre:only-child,\n.md-typeset .tabbed-content > .highlight:only-child pre,\n.md-typeset .tabbed-content > .highlighttable:only-child {\n margin: 0;\n}\n.md-typeset .tabbed-content > pre:only-child > code,\n.md-typeset .tabbed-content > .highlight:only-child pre > code,\n.md-typeset .tabbed-content > .highlighttable:only-child > code {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.md-typeset .tabbed-content > .tabbed-set {\n margin: 0;\n}\n.md-typeset .tabbed-set {\n position: relative;\n display: flex;\n flex-wrap: wrap;\n margin: 1em 0;\n border-radius: 0.1rem;\n}\n.md-typeset .tabbed-set > input {\n position: absolute;\n width: 0;\n height: 0;\n opacity: 0;\n}\n.md-typeset .tabbed-set > input:checked + label {\n color: var(--md-accent-fg-color);\n border-color: var(--md-accent-fg-color);\n}\n.md-typeset .tabbed-set > input:checked + label + .tabbed-content {\n display: block;\n}\n.md-typeset .tabbed-set > input:focus + label {\n outline-style: auto;\n outline-color: var(--md-accent-fg-color);\n}\n.md-typeset .tabbed-set > input:not(.focus-visible) + label {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n}\n.md-typeset .tabbed-set > label {\n z-index: 1;\n width: auto;\n padding: 0.9375em 1.25em 0.78125em;\n color: var(--md-default-fg-color--light);\n font-weight: 700;\n font-size: 0.64rem;\n border-bottom: 0.1rem solid transparent;\n cursor: pointer;\n transition: color 250ms;\n}\n.md-typeset .tabbed-set > label:hover {\n color: var(--md-accent-fg-color);\n}\n\n@media screen {\n .md-typeset .tabbed-alternate input:nth-child(1):checked ~ .tabbed-labels > :nth-child(1), .md-typeset .tabbed-alternate input:nth-child(2):checked ~ .tabbed-labels > :nth-child(2), .md-typeset .tabbed-alternate input:nth-child(3):checked ~ .tabbed-labels > :nth-child(3), .md-typeset .tabbed-alternate input:nth-child(4):checked ~ .tabbed-labels > :nth-child(4), .md-typeset .tabbed-alternate input:nth-child(5):checked ~ .tabbed-labels > :nth-child(5), .md-typeset .tabbed-alternate input:nth-child(6):checked ~ .tabbed-labels > :nth-child(6), .md-typeset .tabbed-alternate input:nth-child(7):checked ~ .tabbed-labels > :nth-child(7), .md-typeset .tabbed-alternate input:nth-child(8):checked ~ .tabbed-labels > :nth-child(8), .md-typeset .tabbed-alternate input:nth-child(9):checked ~ .tabbed-labels > :nth-child(9), .md-typeset .tabbed-alternate input:nth-child(10):checked ~ .tabbed-labels > :nth-child(10), .md-typeset .tabbed-alternate input:nth-child(11):checked ~ .tabbed-labels > :nth-child(11), .md-typeset .tabbed-alternate input:nth-child(12):checked ~ .tabbed-labels > :nth-child(12), .md-typeset .tabbed-alternate input:nth-child(13):checked ~ .tabbed-labels > :nth-child(13), .md-typeset .tabbed-alternate input:nth-child(14):checked ~ .tabbed-labels > :nth-child(14), .md-typeset .tabbed-alternate input:nth-child(15):checked ~ .tabbed-labels > :nth-child(15), .md-typeset .tabbed-alternate input:nth-child(16):checked ~ .tabbed-labels > :nth-child(16), .md-typeset .tabbed-alternate input:nth-child(17):checked ~ .tabbed-labels > :nth-child(17), .md-typeset .tabbed-alternate input:nth-child(18):checked ~ .tabbed-labels > :nth-child(18), .md-typeset .tabbed-alternate input:nth-child(19):checked ~ .tabbed-labels > :nth-child(19), .md-typeset .tabbed-alternate input:nth-child(20):checked ~ .tabbed-labels > :nth-child(20) {\n color: var(--md-accent-fg-color);\n border-color: var(--md-accent-fg-color);\n }\n}\n\n.md-typeset .tabbed-alternate input:nth-child(1).focus-visible ~ .tabbed-labels > :nth-child(1), .md-typeset .tabbed-alternate input:nth-child(2).focus-visible ~ .tabbed-labels > :nth-child(2), .md-typeset .tabbed-alternate input:nth-child(3).focus-visible ~ .tabbed-labels > :nth-child(3), .md-typeset .tabbed-alternate input:nth-child(4).focus-visible ~ .tabbed-labels > :nth-child(4), .md-typeset .tabbed-alternate input:nth-child(5).focus-visible ~ .tabbed-labels > :nth-child(5), .md-typeset .tabbed-alternate input:nth-child(6).focus-visible ~ .tabbed-labels > :nth-child(6), .md-typeset .tabbed-alternate input:nth-child(7).focus-visible ~ .tabbed-labels > :nth-child(7), .md-typeset .tabbed-alternate input:nth-child(8).focus-visible ~ .tabbed-labels > :nth-child(8), .md-typeset .tabbed-alternate input:nth-child(9).focus-visible ~ .tabbed-labels > :nth-child(9), .md-typeset .tabbed-alternate input:nth-child(10).focus-visible ~ .tabbed-labels > :nth-child(10), .md-typeset .tabbed-alternate input:nth-child(11).focus-visible ~ .tabbed-labels > :nth-child(11), .md-typeset .tabbed-alternate input:nth-child(12).focus-visible ~ .tabbed-labels > :nth-child(12), .md-typeset .tabbed-alternate input:nth-child(13).focus-visible ~ .tabbed-labels > :nth-child(13), .md-typeset .tabbed-alternate input:nth-child(14).focus-visible ~ .tabbed-labels > :nth-child(14), .md-typeset .tabbed-alternate input:nth-child(15).focus-visible ~ .tabbed-labels > :nth-child(15), .md-typeset .tabbed-alternate input:nth-child(16).focus-visible ~ .tabbed-labels > :nth-child(16), .md-typeset .tabbed-alternate input:nth-child(17).focus-visible ~ .tabbed-labels > :nth-child(17), .md-typeset .tabbed-alternate input:nth-child(18).focus-visible ~ .tabbed-labels > :nth-child(18), .md-typeset .tabbed-alternate input:nth-child(19).focus-visible ~ .tabbed-labels > :nth-child(19), .md-typeset .tabbed-alternate input:nth-child(20).focus-visible ~ .tabbed-labels > :nth-child(20) {\n background-color: var(--md-accent-fg-color--transparent);\n}\n\n.md-typeset .tabbed-alternate input:nth-child(1):checked ~ .tabbed-content > :nth-child(1), .md-typeset .tabbed-alternate input:nth-child(2):checked ~ .tabbed-content > :nth-child(2), .md-typeset .tabbed-alternate input:nth-child(3):checked ~ .tabbed-content > :nth-child(3), .md-typeset .tabbed-alternate input:nth-child(4):checked ~ .tabbed-content > :nth-child(4), .md-typeset .tabbed-alternate input:nth-child(5):checked ~ .tabbed-content > :nth-child(5), .md-typeset .tabbed-alternate input:nth-child(6):checked ~ .tabbed-content > :nth-child(6), .md-typeset .tabbed-alternate input:nth-child(7):checked ~ .tabbed-content > :nth-child(7), .md-typeset .tabbed-alternate input:nth-child(8):checked ~ .tabbed-content > :nth-child(8), .md-typeset .tabbed-alternate input:nth-child(9):checked ~ .tabbed-content > :nth-child(9), .md-typeset .tabbed-alternate input:nth-child(10):checked ~ .tabbed-content > :nth-child(10), .md-typeset .tabbed-alternate input:nth-child(11):checked ~ .tabbed-content > :nth-child(11), .md-typeset .tabbed-alternate input:nth-child(12):checked ~ .tabbed-content > :nth-child(12), .md-typeset .tabbed-alternate input:nth-child(13):checked ~ .tabbed-content > :nth-child(13), .md-typeset .tabbed-alternate input:nth-child(14):checked ~ .tabbed-content > :nth-child(14), .md-typeset .tabbed-alternate input:nth-child(15):checked ~ .tabbed-content > :nth-child(15), .md-typeset .tabbed-alternate input:nth-child(16):checked ~ .tabbed-content > :nth-child(16), .md-typeset .tabbed-alternate input:nth-child(17):checked ~ .tabbed-content > :nth-child(17), .md-typeset .tabbed-alternate input:nth-child(18):checked ~ .tabbed-content > :nth-child(18), .md-typeset .tabbed-alternate input:nth-child(19):checked ~ .tabbed-content > :nth-child(19), .md-typeset .tabbed-alternate input:nth-child(20):checked ~ .tabbed-content > :nth-child(20) {\n display: block;\n}\n\n.md-typeset .tabbed-labels {\n display: flex;\n max-width: 100%;\n overflow: auto;\n box-shadow: 0 -0.05rem var(--md-default-fg-color--lightest) inset;\n scroll-snap-type: x proximity;\n -ms-overflow-style: none;\n scrollbar-width: none;\n}\n@media print {\n .md-typeset .tabbed-labels {\n display: contents;\n }\n}\n.md-typeset .tabbed-labels::-webkit-scrollbar {\n display: none;\n}\n.md-typeset .tabbed-labels > label {\n z-index: 1;\n flex-shrink: 0;\n width: auto;\n padding: 0.78125em 1.25em 0.625em;\n color: var(--md-default-fg-color--light);\n font-weight: 700;\n font-size: 0.64rem;\n white-space: nowrap;\n border-bottom: 0.1rem solid transparent;\n scroll-snap-align: start;\n border-top-left-radius: 0.1rem;\n border-top-right-radius: 0.1rem;\n cursor: pointer;\n transition: background-color 250ms, color 250ms;\n}\n@media print {\n .md-typeset .tabbed-labels > label:nth-child(1) {\n order: 1;\n }\n .md-typeset .tabbed-labels > label:nth-child(2) {\n order: 2;\n }\n .md-typeset .tabbed-labels > label:nth-child(3) {\n order: 3;\n }\n .md-typeset .tabbed-labels > label:nth-child(4) {\n order: 4;\n }\n .md-typeset .tabbed-labels > label:nth-child(5) {\n order: 5;\n }\n .md-typeset .tabbed-labels > label:nth-child(6) {\n order: 6;\n }\n .md-typeset .tabbed-labels > label:nth-child(7) {\n order: 7;\n }\n .md-typeset .tabbed-labels > label:nth-child(8) {\n order: 8;\n }\n .md-typeset .tabbed-labels > label:nth-child(9) {\n order: 9;\n }\n .md-typeset .tabbed-labels > label:nth-child(10) {\n order: 10;\n }\n .md-typeset .tabbed-labels > label:nth-child(11) {\n order: 11;\n }\n .md-typeset .tabbed-labels > label:nth-child(12) {\n order: 12;\n }\n .md-typeset .tabbed-labels > label:nth-child(13) {\n order: 13;\n }\n .md-typeset .tabbed-labels > label:nth-child(14) {\n order: 14;\n }\n .md-typeset .tabbed-labels > label:nth-child(15) {\n order: 15;\n }\n .md-typeset .tabbed-labels > label:nth-child(16) {\n order: 16;\n }\n .md-typeset .tabbed-labels > label:nth-child(17) {\n order: 17;\n }\n .md-typeset .tabbed-labels > label:nth-child(18) {\n order: 18;\n }\n .md-typeset .tabbed-labels > label:nth-child(19) {\n order: 19;\n }\n .md-typeset .tabbed-labels > label:nth-child(20) {\n order: 20;\n }\n}\n.md-typeset .tabbed-labels > label:hover {\n color: var(--md-accent-fg-color);\n}\n@media screen and (max-width: 44.9375em) {\n .md-typeset > .tabbed-alternate .tabbed-labels {\n max-width: 100vw;\n margin: 0 -0.8rem;\n padding-left: 0.8rem;\n scroll-padding-left: 0.8rem;\n }\n [dir=rtl] .md-typeset > .tabbed-alternate .tabbed-labels {\n padding-right: 0.8rem;\n padding-left: initial;\n scroll-padding-right: 0.8rem;\n scroll-padding-left: initial;\n }\n .md-typeset > .tabbed-alternate .tabbed-labels::after {\n padding-right: 0.8rem;\n content: \"\";\n }\n [dir=rtl] .md-typeset > .tabbed-alternate .tabbed-labels::after {\n padding-right: initial;\n padding-left: 0.8rem;\n }\n}\n.md-typeset .tabbed-alternate {\n flex-direction: column;\n}\n.md-typeset .tabbed-alternate .tabbed-content {\n display: initial;\n order: initial;\n width: 100%;\n box-shadow: initial;\n}\n@media print {\n .md-typeset .tabbed-alternate .tabbed-content {\n display: contents;\n }\n}\n.md-typeset .tabbed-alternate .tabbed-block {\n display: none;\n}\n@media print {\n .md-typeset .tabbed-alternate .tabbed-block {\n display: block;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(1) {\n order: 1;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(2) {\n order: 2;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(3) {\n order: 3;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(4) {\n order: 4;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(5) {\n order: 5;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(6) {\n order: 6;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(7) {\n order: 7;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(8) {\n order: 8;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(9) {\n order: 9;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(10) {\n order: 10;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(11) {\n order: 11;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(12) {\n order: 12;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(13) {\n order: 13;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(14) {\n order: 14;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(15) {\n order: 15;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(16) {\n order: 16;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(17) {\n order: 17;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(18) {\n order: 18;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(19) {\n order: 19;\n }\n .md-typeset .tabbed-alternate .tabbed-block:nth-child(20) {\n order: 20;\n }\n}\n.md-typeset .tabbed-alternate .tabbed-block > pre:only-child,\n.md-typeset .tabbed-alternate .tabbed-block > .highlight:only-child pre,\n.md-typeset .tabbed-alternate .tabbed-block > .highlighttable:only-child {\n margin: 0;\n}\n.md-typeset .tabbed-alternate .tabbed-block > pre:only-child > code,\n.md-typeset .tabbed-alternate .tabbed-block > .highlight:only-child pre > code,\n.md-typeset .tabbed-alternate .tabbed-block > .highlighttable:only-child > code {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n}\n.md-typeset .tabbed-alternate .tabbed-block > .tabbed-set {\n margin: 0;\n}\n:root {\n --md-tasklist-icon:\n svg-load(\"octicons/check-circle-fill-24.svg\");\n --md-tasklist-icon--checked:\n svg-load(\"octicons/check-circle-fill-24.svg\");\n}\n\n.md-typeset .task-list-item {\n position: relative;\n list-style-type: none;\n}\n.md-typeset .task-list-item [type=checkbox] {\n position: absolute;\n top: 0.45em;\n left: -2em;\n}\n[dir=rtl] .md-typeset .task-list-item [type=checkbox] {\n right: -2em;\n left: initial;\n}\n.md-typeset .task-list-control [type=checkbox] {\n z-index: -1;\n opacity: 0;\n}\n.md-typeset .task-list-indicator::before {\n position: absolute;\n top: 0.15em;\n left: -1.5em;\n width: 1.25em;\n height: 1.25em;\n background-color: var(--md-default-fg-color--lightest);\n mask-image: var(--md-tasklist-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n}\n[dir=rtl] .md-typeset .task-list-indicator::before {\n right: -1.5em;\n left: initial;\n}\n.md-typeset [type=checkbox]:checked + .task-list-indicator::before {\n background-color: #00e676;\n mask-image: var(--md-tasklist-icon--checked);\n}\n\n@media screen and (min-width: 45em) {\n .md-typeset .inline {\n float: left;\n width: 11.7rem;\n margin-top: 0;\n margin-right: 0.8rem;\n margin-bottom: 0.8rem;\n }\n [dir=rtl] .md-typeset .inline {\n float: right;\n margin-right: 0;\n margin-left: 0.8rem;\n }\n .md-typeset .inline.end {\n float: right;\n margin-right: 0;\n margin-left: 0.8rem;\n }\n [dir=rtl] .md-typeset .inline.end {\n float: left;\n margin-right: 0.8rem;\n margin-left: 0;\n }\n}\n\n/*# sourceMappingURL=main.css.map */","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Enforce correct box model and prevent adjustments of font size after\n// orientation changes in IE and iOS\nhtml {\n box-sizing: border-box;\n text-size-adjust: none;\n}\n\n// All elements shall inherit the document default\n*,\n*::before,\n*::after {\n box-sizing: inherit;\n}\n\n// Remove margin in all browsers\nbody {\n margin: 0;\n}\n\n// Reset tap outlines on iOS and Android\na,\nbutton,\nlabel,\ninput {\n -webkit-tap-highlight-color: transparent;\n}\n\n// Reset link styles\na {\n color: inherit;\n text-decoration: none;\n}\n\n// Normalize horizontal separator styles\nhr {\n display: block;\n box-sizing: content-box;\n height: px2rem(1px);\n padding: 0;\n overflow: visible;\n border: 0;\n}\n\n// Normalize font-size in all browsers\nsmall {\n font-size: 80%;\n}\n\n// Prevent subscript and superscript from affecting line-height\nsub,\nsup {\n line-height: 1em;\n}\n\n// Remove border on image\nimg {\n border-style: none;\n}\n\n// Reset table styles\ntable {\n border-collapse: separate;\n border-spacing: 0;\n}\n\n// Reset table cell styles\ntd,\nth {\n font-weight: 400;\n vertical-align: top;\n}\n\n// Reset button styles\nbutton {\n margin: 0;\n padding: 0;\n font-size: inherit;\n font-family: inherit;\n background: transparent;\n border: 0;\n}\n\n// Reset input styles\ninput {\n border: 0;\n outline: none;\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Color definitions\n:root {\n\n // Default color shades\n --md-default-fg-color: hsla(0, 0%, 0%, 0.87);\n --md-default-fg-color--light: hsla(0, 0%, 0%, 0.54);\n --md-default-fg-color--lighter: hsla(0, 0%, 0%, 0.32);\n --md-default-fg-color--lightest: hsla(0, 0%, 0%, 0.07);\n --md-default-bg-color: hsla(0, 0%, 100%, 1);\n --md-default-bg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-default-bg-color--lighter: hsla(0, 0%, 100%, 0.3);\n --md-default-bg-color--lightest: hsla(0, 0%, 100%, 0.12);\n\n // Primary color shades\n --md-primary-fg-color: hsla(#{hex2hsl($clr-indigo-500)}, 1);\n --md-primary-fg-color--light: hsla(#{hex2hsl($clr-indigo-400)}, 1);\n --md-primary-fg-color--dark: hsla(#{hex2hsl($clr-indigo-700)}, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n\n // Accent color shades\n --md-accent-fg-color: hsla(#{hex2hsl($clr-indigo-a200)}, 1);\n --md-accent-fg-color--transparent: hsla(#{hex2hsl($clr-indigo-a200)}, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n\n // Light theme (default)\n > * {\n\n // Code color shades\n --md-code-fg-color: hsla(200, 18%, 26%, 1);\n --md-code-bg-color: hsla(0, 0%, 96%, 1);\n\n // Code highlighting color shades\n --md-code-hl-color: hsla(#{hex2hsl($clr-yellow-a200)}, 0.5);\n --md-code-hl-number-color: hsla(0, 67%, 50%, 1);\n --md-code-hl-special-color: hsla(340, 83%, 47%, 1);\n --md-code-hl-function-color: hsla(291, 45%, 50%, 1);\n --md-code-hl-constant-color: hsla(250, 63%, 60%, 1);\n --md-code-hl-keyword-color: hsla(219, 54%, 51%, 1);\n --md-code-hl-string-color: hsla(150, 63%, 30%, 1);\n --md-code-hl-name-color: var(--md-code-fg-color);\n --md-code-hl-operator-color: var(--md-default-fg-color--light);\n --md-code-hl-punctuation-color: var(--md-default-fg-color--light);\n --md-code-hl-comment-color: var(--md-default-fg-color--light);\n --md-code-hl-generic-color: var(--md-default-fg-color--light);\n --md-code-hl-variable-color: var(--md-default-fg-color--light);\n\n // Typeset color shades\n --md-typeset-color: var(--md-default-fg-color);\n\n // Typeset `a` color shades\n --md-typeset-a-color: var(--md-primary-fg-color);\n\n // Typeset `mark` color shades\n --md-typeset-mark-color: hsla(#{hex2hsl($clr-yellow-a200)}, 0.5);\n\n // Typeset `del` and `ins` color shades\n --md-typeset-del-color: hsla(6, 90%, 60%, 0.15);\n --md-typeset-ins-color: hsla(150, 90%, 44%, 0.15);\n\n // Typeset `kbd` color shades\n --md-typeset-kbd-color: hsla(0, 0%, 98%, 1);\n --md-typeset-kbd-accent-color: hsla(0, 100%, 100%, 1);\n --md-typeset-kbd-border-color: hsla(0, 0%, 72%, 1);\n\n // Typeset `table` color shades\n --md-typeset-table-color: hsla(0, 0%, 0%, 0.12);\n\n // Admonition color shades\n --md-admonition-fg-color: var(--md-default-fg-color);\n --md-admonition-bg-color: var(--md-default-bg-color);\n\n // Footer color shades\n --md-footer-fg-color: hsla(0, 0%, 100%, 1);\n --md-footer-fg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-footer-fg-color--lighter: hsla(0, 0%, 100%, 0.3);\n --md-footer-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-footer-bg-color--dark: hsla(0, 0%, 0%, 0.32);\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon\n.md-icon {\n\n // SVG defaults\n svg {\n display: block;\n width: px2rem(24px);\n height: px2rem(24px);\n fill: currentColor;\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules: font definitions\n// ----------------------------------------------------------------------------\n\n// Enable font-smoothing in Webkit and FF\nbody {\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n// Define default fonts\nbody,\ninput {\n color: var(--md-typeset-color);\n font-feature-settings: \"kern\", \"liga\";\n font-family:\n var(--md-text-font-family, _),\n -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;\n}\n\n// Define monospaced fonts\ncode,\npre,\nkbd {\n color: var(--md-typeset-color);\n font-feature-settings: \"kern\";\n font-family:\n var(--md-code-font-family, _),\n SFMono-Regular, Consolas, Menlo, monospace;\n}\n\n// ----------------------------------------------------------------------------\n// Rules: typesetted content\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-typeset-table-sort-icon: svg-load(\"material/sort.svg\");\n --md-typeset-table-sort-icon--asc: svg-load(\"material/sort-ascending.svg\");\n --md-typeset-table-sort-icon--desc: svg-load(\"material/sort-descending.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Content that is typeset - if possible, all margins, paddings and font sizes\n// should be set in ems, so nested blocks (e.g. admonitions) render correctly.\n.md-typeset {\n font-size: px2rem(16px);\n line-height: 1.6;\n color-adjust: exact;\n\n // [print]: We'll use a smaller `font-size` for printing, so code examples\n // don't break too early, and `16px` looks too big anyway.\n @media print {\n font-size: px2rem(13.6px);\n }\n\n // Default spacing\n ul,\n ol,\n dl,\n figure,\n blockquote,\n pre {\n margin: 1em 0;\n }\n\n // Headline on level 1\n h1 {\n margin: 0 0 px2em(40px, 32px);\n color: var(--md-default-fg-color--light);\n font-weight: 300;\n font-size: px2em(32px);\n line-height: 1.3;\n letter-spacing: -0.01em;\n }\n\n // Headline on level 2\n h2 {\n margin: px2em(40px, 25px) 0 px2em(16px, 25px);\n font-weight: 300;\n font-size: px2em(25px);\n line-height: 1.4;\n letter-spacing: -0.01em;\n }\n\n // Headline on level 3\n h3 {\n margin: px2em(32px, 20px) 0 px2em(16px, 20px);\n font-weight: 400;\n font-size: px2em(20px);\n line-height: 1.5;\n letter-spacing: -0.01em;\n }\n\n // Headline on level 3 following level 2\n h2 + h3 {\n margin-top: px2em(16px, 20px);\n }\n\n // Headline on level 4\n h4 {\n margin: px2em(16px) 0;\n font-weight: 700;\n letter-spacing: -0.01em;\n }\n\n // Headline on level 5-6\n h5,\n h6 {\n margin: px2em(16px, 12.8px) 0;\n color: var(--md-default-fg-color--light);\n font-weight: 700;\n font-size: px2em(12.8px);\n letter-spacing: -0.01em;\n }\n\n // Headline on level 5\n h5 {\n text-transform: uppercase;\n }\n\n // Horizontal separator\n hr {\n display: flow-root;\n margin: 1.5em 0;\n border-bottom: px2rem(1px) solid var(--md-default-fg-color--lightest);\n }\n\n // Text link\n a {\n color: var(--md-typeset-a-color);\n word-break: break-word;\n\n // Also enable color transition on pseudo elements\n &,\n &::before {\n transition: color 125ms;\n }\n\n // Text link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Show outline for keyboard devices\n &.focus-visible {\n outline-color: var(--md-accent-fg-color);\n outline-offset: px2rem(4px);\n }\n }\n\n // Code block\n code,\n pre,\n kbd {\n color: var(--md-code-fg-color);\n direction: ltr;\n\n // [print]: Wrap text and hide scollbars\n @media print {\n white-space: pre-wrap;\n }\n }\n\n // Inline code block\n code {\n padding: 0 px2em(4px, 13.6px);\n font-size: px2em(13.6px);\n word-break: break-word;\n background-color: var(--md-code-bg-color);\n border-radius: px2rem(2px);\n box-decoration-break: clone;\n\n // Hide outline for pointer devices\n &:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n }\n\n // Code block in headline\n h1 code,\n h2 code,\n h3 code,\n h4 code,\n h5 code,\n h6 code {\n margin: initial;\n padding: initial;\n background-color: transparent;\n box-shadow: none;\n }\n\n // Ensure link color in code blocks\n a code {\n color: currentColor;\n }\n\n // Unformatted content\n pre {\n position: relative;\n display: flow-root;\n line-height: 1.4;\n\n // Code block\n > code {\n display: block;\n margin: 0;\n padding: px2em(10.5px, 13.6px) px2em(16px, 13.6px);\n overflow: auto;\n word-break: normal;\n box-shadow: none;\n box-decoration-break: slice;\n touch-action: auto;\n scrollbar-width: thin;\n scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n\n // Code block on hover\n &:hover {\n scrollbar-color: var(--md-accent-fg-color) transparent;\n }\n\n // Webkit scrollbar\n &::-webkit-scrollbar {\n width: px2rem(4px);\n height: px2rem(4px);\n }\n\n // Webkit scrollbar thumb\n &::-webkit-scrollbar-thumb {\n background-color: var(--md-default-fg-color--lighter);\n\n // Webkit scrollbar thumb on hover\n &:hover {\n background-color: var(--md-accent-fg-color);\n }\n }\n }\n }\n\n // [mobile -]: Align with body copy\n @include break-to-device(mobile) {\n\n // Unformatted text\n > pre {\n margin: 1em px2rem(-16px);\n\n // Code block\n code {\n border-radius: 0;\n }\n }\n }\n\n // Keyboard key\n kbd {\n display: inline-block;\n padding: 0 px2em(8px, 12px);\n color: var(--md-default-fg-color);\n font-size: px2em(12px);\n vertical-align: text-top;\n word-break: break-word;\n background-color: var(--md-typeset-kbd-color);\n border-radius: px2rem(2px);\n box-shadow:\n 0 px2rem(2px) 0 px2rem(1px) var(--md-typeset-kbd-border-color),\n 0 px2rem(2px) 0 var(--md-typeset-kbd-border-color),\n 0 px2rem(-2px) px2rem(4px) var(--md-typeset-kbd-accent-color) inset;\n }\n\n // Text highlighting marker\n mark {\n color: inherit;\n word-break: break-word;\n background-color: var(--md-typeset-mark-color);\n box-decoration-break: clone;\n }\n\n // Abbreviation\n abbr {\n text-decoration: none;\n border-bottom: px2rem(1px) dotted var(--md-default-fg-color--light);\n cursor: help;\n\n // Show tooltip for touch devices\n @media (hover: none) {\n position: relative;\n\n // Tooltip\n &[title]:focus::after,\n &[title]:hover::after {\n @include z-depth(2);\n\n position: absolute;\n left: 0;\n display: inline-block;\n width: auto;\n min-width: max-content;\n max-width: 80%;\n margin-top: 2em;\n padding: px2rem(4px) px2rem(6px);\n color: var(--md-default-bg-color);\n font-size: px2rem(14px);\n background-color: var(--md-default-fg-color);\n border-radius: px2rem(2px);\n content: attr(title);\n }\n }\n }\n\n // Small text\n small {\n opacity: 0.75;\n }\n\n // Superscript and subscript\n sup,\n sub {\n margin-left: px2em(1px, 12.8px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2em(1px, 12.8px);\n margin-left: initial;\n }\n }\n\n // Blockquotes, possibly nested\n blockquote {\n padding-left: px2rem(12px);\n color: var(--md-default-fg-color--light);\n border-left: px2rem(4px) solid var(--md-default-fg-color--lighter);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(12px);\n padding-left: initial;\n border-right: px2rem(4px) solid var(--md-default-fg-color--lighter);\n border-left: initial;\n }\n }\n\n // Unordered list\n ul {\n list-style-type: disc;\n }\n\n // Unordered and ordered list\n ul,\n ol {\n display: flow-root;\n margin-left: px2em(10px);\n padding: 0;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2em(10px);\n margin-left: initial;\n }\n\n // Nested ordered list\n ol {\n list-style-type: lower-alpha;\n\n // Triply nested ordered list\n ol {\n list-style-type: lower-roman;\n }\n }\n\n // List element\n li {\n margin-bottom: 0.5em;\n margin-left: px2em(20px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2em(20px);\n margin-left: initial;\n }\n\n // Adjust spacing\n p,\n blockquote {\n margin: 0.5em 0;\n }\n\n // Adjust spacing on last child\n &:last-child {\n margin-bottom: 0;\n }\n\n // Nested list\n ul,\n ol {\n margin: 0.5em 0 0.5em px2em(10px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2em(10px);\n margin-left: initial;\n }\n }\n }\n }\n\n // Definition list\n dd {\n margin: 1em 0 1.5em px2em(30px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2em(30px);\n margin-left: initial;\n }\n }\n\n // Image or icon\n img,\n svg {\n max-width: 100%;\n height: auto;\n\n // Adjust spacing when left-aligned\n &[align=\"left\"] {\n margin: 1em;\n margin-left: 0;\n }\n\n // Adjust spacing when right-aligned\n &[align=\"right\"] {\n margin: 1em;\n margin-right: 0;\n }\n\n // Adjust spacing when sole children\n &[align]:only-child {\n margin-top: 0;\n }\n }\n\n // Figure\n figure {\n display: flow-root;\n width: fit-content;\n max-width: 100%;\n margin: 0 auto;\n text-align: center;\n\n // Figure images\n img {\n display: block;\n }\n }\n\n // Figure caption\n figcaption {\n max-width: px2rem(480px);\n margin: 1em auto 2em;\n font-style: italic;\n }\n\n // Limit width to container\n iframe {\n max-width: 100%;\n }\n\n // Data table\n table:not([class]) {\n display: inline-block;\n max-width: 100%;\n overflow: auto;\n font-size: px2rem(12.8px);\n background-color: var(--md-default-bg-color);\n border: px2rem(1px) solid var(--md-typeset-table-color);\n border-radius: px2rem(2px);\n touch-action: auto;\n\n // [print]: Reset display mode so table header wraps when printing\n @media print {\n display: table;\n }\n\n // Due to margin collapse because of the necessary inline-block hack, we\n // cannot increase the bottom margin on the table, so we just increase the\n // top margin on the following element\n + * {\n margin-top: 1.5em;\n }\n\n // Elements in table heading and cell\n th > *,\n td > * {\n\n // Adjust spacing on first child\n &:first-child {\n margin-top: 0;\n }\n\n // Adjust spacing on last child\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n // Table heading and cell\n th:not([align]),\n td:not([align]) {\n text-align: left;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n text-align: right;\n }\n }\n\n // Table heading\n th {\n min-width: px2rem(100px);\n padding: px2em(12px, 12.8px) px2em(16px, 12.8px);\n font-weight: 700;\n vertical-align: top;\n\n // Links in table headings\n a {\n color: inherit;\n }\n }\n\n // Table cell\n td {\n padding: px2em(12px, 12.8px) px2em(16px, 12.8px);\n vertical-align: top;\n border-top: px2rem(1px) solid var(--md-typeset-table-color);\n }\n\n // Table body row\n tbody tr {\n transition: background-color 125ms;\n\n // Table row on hover\n &:hover {\n background-color: rgba(0, 0, 0, 0.035);\n box-shadow: 0 px2rem(1px) 0 var(--md-default-bg-color) inset;\n }\n }\n\n // Text link in table\n a {\n word-break: normal;\n }\n }\n\n // Sortable table\n table th[role=\"columnheader\"] {\n cursor: pointer;\n\n // Sort icon\n &::after {\n display: inline-block;\n width: 1.2em;\n height: 1.2em;\n margin-left: 0.5em;\n vertical-align: text-bottom;\n mask-image: var(--md-typeset-table-sort-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n transition: background-color 125ms;\n content: \"\";\n }\n\n // Show sort icon on hover\n &:hover::after {\n background-color: var(--md-default-fg-color--lighter);\n }\n\n // Sort ascending icon\n &[aria-sort=\"ascending\"]::after {\n background-color: var(--md-default-fg-color--light);\n mask-image: var(--md-typeset-table-sort-icon--asc);\n }\n\n // Sort descending icon\n &[aria-sort=\"descending\"]::after {\n background-color: var(--md-default-fg-color--light);\n mask-image: var(--md-typeset-table-sort-icon--desc);\n }\n }\n\n // Data table scroll wrapper\n &__scrollwrap {\n margin: 1em px2rem(-16px);\n overflow-x: auto;\n touch-action: auto;\n }\n\n // Data table wrapper\n &__table {\n display: inline-block;\n margin-bottom: 0.5em;\n padding: 0 px2rem(16px);\n\n // [print]: Reset display mode so table header wraps when printing\n @media print {\n display: block;\n }\n\n // Data table\n html & table {\n display: table;\n width: 100%;\n margin: 0;\n overflow: hidden;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n@use \"sass:list\";\n@use \"sass:map\";\n@use \"sass:math\";\n\n// ----------------------------------------------------------------------------\n// Variables\n// ----------------------------------------------------------------------------\n\n///\n/// Device-specific breakpoints\n///\n/// @example\n/// $break-devices: (\n/// mobile: (\n/// portrait: 220px 479px,\n/// landscape: 480px 719px\n/// ),\n/// tablet: (\n/// portrait: 720px 959px,\n/// landscape: 960px 1219px\n/// ),\n/// screen: (\n/// small: 1220px 1599px,\n/// medium: 1600px 1999px,\n/// large: 2000px\n/// )\n/// );\n///\n$break-devices: () !default;\n\n// ----------------------------------------------------------------------------\n// Helpers\n// ----------------------------------------------------------------------------\n\n///\n/// Choose minimum and maximum device widths\n///\n@function break-select-min-max($devices) {\n $min: 1000000;\n $max: 0;\n @each $key, $value in $devices {\n @while type-of($value) == map {\n $value: break-select-min-max($value);\n }\n @if type-of($value) == list {\n @each $number in $value {\n @if type-of($number) == number {\n $min: math.min($number, $min);\n @if $max {\n $max: math.max($number, $max);\n }\n } @else {\n @error \"Invalid number: #{$number}\";\n }\n }\n } @else if type-of($value) == number {\n $min: math.min($value, $min);\n $max: null;\n } @else {\n @error \"Invalid value: #{$value}\";\n }\n }\n @return $min, $max;\n}\n\n///\n/// Select minimum and maximum widths for a device breakpoint\n///\n@function break-select-device($device) {\n $current: $break-devices;\n @for $n from 1 through length($device) {\n @if type-of($current) == map {\n $current: map.get($current, list.nth($device, $n));\n } @else {\n @error \"Invalid device map: #{$devices}\";\n }\n }\n @if type-of($current) == list or type-of($current) == number {\n $current: (default: $current);\n }\n @return break-select-min-max($current);\n}\n\n// ----------------------------------------------------------------------------\n// Mixins\n// ----------------------------------------------------------------------------\n\n///\n/// A minimum-maximum media query breakpoint\n///\n@mixin break-at($breakpoint) {\n @if type-of($breakpoint) == number {\n @media screen and (min-width: $breakpoint) {\n @content;\n }\n } @else if type-of($breakpoint) == list {\n $min: list.nth($breakpoint, 1);\n $max: list.nth($breakpoint, 2);\n @if type-of($min) == number and type-of($max) == number {\n @media screen and (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n}\n\n///\n/// An orientation media query breakpoint\n///\n@mixin break-at-orientation($breakpoint) {\n @if type-of($breakpoint) == string {\n @media screen and (orientation: $breakpoint) {\n @content;\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n}\n\n///\n/// A maximum-aspect-ratio media query breakpoint\n///\n@mixin break-at-ratio($breakpoint) {\n @if type-of($breakpoint) == number {\n @media screen and (max-aspect-ratio: $breakpoint) {\n @content;\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n}\n\n///\n/// A minimum-maximum media query device breakpoint\n///\n@mixin break-at-device($device) {\n @if type-of($device) == string {\n $device: $device,;\n }\n @if type-of($device) == list {\n $breakpoint: break-select-device($device);\n @if list.nth($breakpoint, 2) {\n $min: list.nth($breakpoint, 1);\n $max: list.nth($breakpoint, 2);\n\n @media screen and (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n}\n\n///\n/// A minimum media query device breakpoint\n///\n@mixin break-from-device($device) {\n @if type-of($device) == string {\n $device: $device,;\n }\n @if type-of($device) == list {\n $breakpoint: break-select-device($device);\n $min: list.nth($breakpoint, 1);\n\n @media screen and (min-width: $min) {\n @content;\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n}\n\n///\n/// A maximum media query device breakpoint\n///\n@mixin break-to-device($device) {\n @if type-of($device) == string {\n $device: $device,;\n }\n @if type-of($device) == list {\n $breakpoint: break-select-device($device);\n $max: list.nth($breakpoint, 2);\n\n @media screen and (max-width: $max) {\n @content;\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n}\n","//\n// Name: Material Shadows\n// Description: Mixins for Material Design Shadows.\n// Version: 3.0.1\n//\n// Author: Denis Malinochkin\n// Git: https://github.com/mrmlnc/material-shadows\n//\n// twitter: @mrmlnc\n//\n// ------------------------------------\n\n\n// Mixins\n// ------------------------------------\n\n@mixin z-depth-transition() {\n transition: box-shadow .28s cubic-bezier(.4, 0, .2, 1);\n}\n\n@mixin z-depth-focus() {\n box-shadow: 0 0 8px rgba(0, 0, 0, .18), 0 8px 16px rgba(0, 0, 0, .36);\n}\n\n@mixin z-depth-2dp() {\n box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14),\n 0 1px 5px 0 rgba(0, 0, 0, .12),\n 0 3px 1px -2px rgba(0, 0, 0, .2);\n}\n\n@mixin z-depth-3dp() {\n box-shadow: 0 3px 4px 0 rgba(0, 0, 0, .14),\n 0 1px 8px 0 rgba(0, 0, 0, .12),\n 0 3px 3px -2px rgba(0, 0, 0, .4);\n}\n\n@mixin z-depth-4dp() {\n box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14),\n 0 1px 10px 0 rgba(0, 0, 0, .12),\n 0 2px 4px -1px rgba(0, 0, 0, .4);\n}\n\n@mixin z-depth-6dp() {\n box-shadow: 0 6px 10px 0 rgba(0, 0, 0, .14),\n 0 1px 18px 0 rgba(0, 0, 0, .12),\n 0 3px 5px -1px rgba(0, 0, 0, .4);\n}\n\n@mixin z-depth-8dp() {\n box-shadow: 0 8px 10px 1px rgba(0, 0, 0, .14),\n 0 3px 14px 2px rgba(0, 0, 0, .12),\n 0 5px 5px -3px rgba(0, 0, 0, .4);\n}\n\n@mixin z-depth-16dp() {\n box-shadow: 0 16px 24px 2px rgba(0, 0, 0, .14),\n 0 6px 30px 5px rgba(0, 0, 0, .12),\n 0 8px 10px -5px rgba(0, 0, 0, .4);\n}\n\n@mixin z-depth-24dp() {\n box-shadow: 0 9px 46px 8px rgba(0, 0, 0, .14),\n 0 24px 38px 3px rgba(0, 0, 0, .12),\n 0 11px 15px -7px rgba(0, 0, 0, .4);\n}\n\n@mixin z-depth($dp: 2) {\n @if $dp == 2 {\n @include z-depth-2dp();\n } @else if $dp == 3 {\n @include z-depth-3dp();\n } @else if $dp == 4 {\n @include z-depth-4dp();\n } @else if $dp == 6 {\n @include z-depth-6dp();\n } @else if $dp == 8 {\n @include z-depth-8dp();\n } @else if $dp == 16 {\n @include z-depth-16dp();\n } @else if $dp == 24 {\n @include z-depth-24dp();\n }\n}\n\n\n// Class generator\n// ------------------------------------\n\n@mixin z-depth-classes($transition: false, $focus: false) {\n @if $transition == true {\n &-transition {\n @include z-depth-transition();\n }\n }\n\n @if $focus == true {\n &-focus {\n @include z-depth-focus();\n }\n }\n\n // The available values for the shadow depth\n @each $depth in 2, 3, 4, 6, 8, 16, 24 {\n &-#{$depth}dp {\n @include z-depth($depth);\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules: base grid and containers\n// ----------------------------------------------------------------------------\n\n// Stretch container to viewport and set base `font-size`\nhtml {\n height: 100%;\n overflow-x: hidden;\n // Hack: normally, we would set the base `font-size` to `62.5%`, so we can\n // base all calculations on `10px`, but Chromium and Chrome define a minimal\n // `font-size` of `12px` if the system language is set to Chinese. For this\n // reason we just double the `font-size` and set it to `20px`.\n //\n // See https://github.com/squidfunk/mkdocs-material/issues/911\n font-size: 125%;\n\n // [screen medium +]: Set base `font-size` to `11px`\n @include break-from-device(screen medium) {\n font-size: 137.5%;\n }\n\n // [screen large +]: Set base `font-size` to `12px`\n @include break-from-device(screen large) {\n font-size: 150%;\n }\n}\n\n// Stretch body to container - flexbox is used, so the footer will always be\n// aligned to the bottom of the viewport\nbody {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n min-height: 100%;\n // Hack: reset `font-size` to `10px`, so the spacing for all inline elements\n // is correct again. Otherwise the spacing would be based on `20px`.\n font-size: px2rem(10px);\n background-color: var(--md-default-bg-color);\n\n // [print]: Omit flexbox layout due to a Firefox bug (https://mzl.la/39DgR3m)\n @media print {\n display: block;\n }\n\n // Body in locked state\n &[data-md-state=\"lock\"] {\n\n // [tablet portrait -]: Omit scroll bubbling\n @include break-to-device(tablet portrait) {\n position: fixed;\n }\n }\n}\n\n// ----------------------------------------------------------------------------\n\n// Grid container - this class is applied to wrapper elements within the\n// header, content area and footer, and makes sure that their width is limited\n// to `1220px`, and they are rendered centered if the screen is larger.\n.md-grid {\n max-width: px2rem(1220px);\n margin-right: auto;\n margin-left: auto;\n}\n\n// Main container\n.md-container {\n display: flex;\n flex-direction: column;\n flex-grow: 1;\n\n // [print]: Omit flexbox layout due to a Firefox bug (https://mzl.la/39DgR3m)\n @media print {\n display: block;\n }\n}\n\n// Main area - stretch to remaining space of container\n.md-main {\n flex-grow: 1;\n\n // Main area wrapper\n &__inner {\n display: flex;\n height: 100%;\n margin-top: px2rem(24px + 6px);\n }\n}\n\n// Add ellipsis in case of overflowing text\n.md-ellipsis {\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n// ----------------------------------------------------------------------------\n// Rules: navigational elements\n// ----------------------------------------------------------------------------\n\n// Toggle - this class is applied to checkbox elements, which are used to\n// implement the CSS-only drawer and navigation, as well as the search\n.md-toggle {\n display: none;\n}\n\n// Option - this class is applied to radio elements, which are used to\n// implement the color palette toggle\n.md-option {\n position: absolute;\n width: 0;\n height: 0;\n opacity: 0;\n\n // Option label for checked radio button\n &:checked + label:not([hidden]) {\n display: block;\n }\n\n // Show outline for keyboard devices\n &.focus-visible + label {\n outline-style: auto;\n outline-color: var(--md-accent-fg-color);\n }\n}\n\n// Skip link\n.md-skip {\n position: fixed;\n // Hack: if we don't set the negative `z-index`, the skip link will force the\n // creation of new layers when code blocks are near the header on scrolling\n z-index: -1;\n margin: px2rem(10px);\n padding: px2rem(6px) px2rem(10px);\n color: var(--md-default-bg-color);\n font-size: px2rem(12.8px);\n background-color: var(--md-default-fg-color);\n border-radius: px2rem(2px);\n outline-color: var(--md-accent-fg-color);\n transform: translateY(px2rem(8px));\n opacity: 0;\n\n // Show skip link on focus\n &:focus {\n z-index: 10;\n transform: translateY(0);\n opacity: 1;\n transition:\n transform 250ms cubic-bezier(0.4, 0, 0.2, 1),\n opacity 175ms 75ms;\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules: print styles\n// ----------------------------------------------------------------------------\n\n// Add margins to page\n@page {\n margin: 25mm;\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Announcement bar\n.md-announce {\n overflow: auto;\n background-color: var(--md-footer-bg-color);\n\n // [print]: Hide announcement bar\n @media print {\n display: none;\n }\n\n // Announcement wrapper\n &__inner {\n margin: px2rem(12px) auto;\n padding: 0 px2rem(16px);\n color: var(--md-footer-fg-color);\n font-size: px2rem(14px);\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-clipboard-icon: svg-load(\"material/content-copy.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Button to copy to clipboard\n.md-clipboard {\n position: absolute;\n top: px2em(8px);\n right: px2em(8px);\n z-index: 1;\n width: px2em(24px);\n height: px2em(24px);\n color: var(--md-default-fg-color--lightest);\n border-radius: px2rem(2px);\n outline-color: var(--md-accent-fg-color);\n outline-offset: px2rem(2px);\n cursor: pointer;\n transition: color 250ms;\n\n // [print]: Hide button\n @media print {\n display: none;\n }\n\n // Hide outline for pointer devices\n &:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n\n // Darken color on code block hover\n :hover > & {\n color: var(--md-default-fg-color--light);\n }\n\n // Button on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Button icon - the width and height are defined in `em`, so the size is\n // automatically adjusted for nested code blocks (e.g. in admonitions)\n &::after {\n display: block;\n width: px2em(18px);\n height: px2em(18px);\n margin: 0 auto;\n background-color: currentColor;\n mask-image: var(--md-clipboard-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n\n // Inline button\n &--inline {\n cursor: pointer;\n\n // Code block\n code {\n transition:\n color 250ms,\n background-color 250ms;\n }\n\n // Code block on focus/hover\n &:focus code,\n &:hover code {\n color: var(--md-accent-fg-color);\n background-color: var(--md-accent-fg-color--transparent);\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Content area\n.md-content {\n flex-grow: 1;\n // Hack: we must use `overflow: hidden`, so the content area is capped by\n // the dimensions of its parent. Otherwise, long code blocks might lead to\n // a wider content area which will break everything. This, however, induces\n // margin collapse, which will break scroll margins. Adding a large enough\n // scroll padding seems to do the trick, at least in Chrome and Firefox.\n overflow: hidden;\n scroll-padding-top: px2rem(1024px);\n\n // Content wrapper\n &__inner {\n margin: 0 px2rem(16px) px2rem(24px);\n padding-top: px2rem(12px);\n\n // [screen +]: Adjust spacing between content area and sidebars\n @include break-from-device(screen) {\n\n // Sidebar with navigation is visible\n .md-sidebar--primary:not([hidden]) ~ .md-content > & {\n\n // Adjust for left-to-right languages\n [dir=\"ltr\"] & {\n margin-left: px2rem(24px);\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(24px);\n }\n }\n\n // Sidebar with table of contents is visible\n .md-sidebar--secondary:not([hidden]) ~ .md-content > & {\n\n // Adjust for left-to-right languages\n [dir=\"ltr\"] & {\n margin-right: px2rem(24px);\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-left: px2rem(24px);\n }\n }\n }\n\n // Hack: add pseudo element for spacing, as the overflow of the content\n // container may not be hidden due to an imminent offset error on targets\n &::before {\n display: block;\n height: px2rem(8px);\n content: \"\";\n }\n\n // Adjust spacing on last child\n > :last-child {\n margin-bottom: 0;\n }\n }\n\n // Button inside of the content area - these buttons are meant for actions on\n // a document-level, i.e. linking to related source code files, printing etc.\n &__button {\n float: right;\n margin: px2rem(8px) 0;\n margin-left: px2rem(8px);\n padding: 0;\n\n // [print]: Hide buttons\n @media print {\n display: none;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: left;\n margin-right: px2rem(8px);\n margin-left: initial;\n\n // Flip icon vertically\n svg {\n transform: scaleX(-1);\n }\n }\n\n // Adjust default link color for icons\n .md-typeset & {\n color: var(--md-default-fg-color--lighter);\n }\n\n // Align with body copy located next to icon\n svg {\n display: inline;\n vertical-align: top;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Dialog\n.md-dialog {\n @include z-depth(2);\n\n position: fixed;\n right: px2rem(16px);\n bottom: px2rem(16px);\n left: initial;\n z-index: 3;\n min-width: px2rem(222px);\n padding: px2rem(8px) px2rem(12px);\n background-color: var(--md-default-fg-color);\n border-radius: px2rem(2px);\n transform: translateY(100%);\n opacity: 0;\n transition:\n transform 0ms 400ms,\n opacity 400ms;\n pointer-events: none;\n\n // [print]: Hide dialog\n @media print {\n display: none;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: initial;\n left: px2rem(16px);\n }\n\n // Dialog in open state\n &[data-md-state=\"open\"] {\n transform: translateY(0);\n opacity: 1;\n transition:\n transform 400ms cubic-bezier(0.075, 0.85, 0.175, 1),\n opacity 400ms;\n pointer-events: initial;\n }\n\n // Dialog wrapper\n &__inner {\n color: var(--md-default-bg-color);\n font-size: px2rem(14px);\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Form button\n .md-button {\n display: inline-block;\n padding: px2em(10px) px2em(32px);\n color: var(--md-primary-fg-color);\n font-weight: 700;\n border: px2rem(2px) solid currentColor;\n border-radius: px2rem(2px);\n cursor: pointer;\n transition:\n color 125ms,\n background-color 125ms,\n border-color 125ms;\n\n // Primary button\n &--primary {\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n border-color: var(--md-primary-fg-color);\n }\n\n // Button on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-bg-color);\n background-color: var(--md-accent-fg-color);\n border-color: var(--md-accent-fg-color);\n }\n }\n\n // Form input\n .md-input {\n height: px2rem(36px);\n padding: 0 px2rem(12px);\n font-size: px2rem(16px);\n border-radius: px2rem(2px);\n box-shadow:\n 0 px2rem(4px) px2rem(10px) hsla(0, 0%, 0%, 0.1),\n 0 px2rem(0.5px) px2rem(1px) hsla(0, 0%, 0%, 0.1);\n transition: box-shadow 250ms;\n\n // Input on focus/hover\n &:focus,\n &:hover {\n box-shadow:\n 0 px2rem(8px) px2rem(20px) hsla(0, 0%, 0%, 0.15),\n 0 px2rem(0.5px) px2rem(1px) hsla(0, 0%, 0%, 0.15);\n }\n\n // Stretch to full width\n &--stretch {\n width: 100%;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Header - by default, the header will be sticky and stay always on top of the\n// viewport. If this behavior is not desired, just set `position: static`.\n.md-header {\n position: sticky;\n top: 0;\n right: 0;\n left: 0;\n z-index: 3;\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n // Hack: reduce jitter by adding a transparent box shadow of the same size\n // so the size of the layer doesn't change during animation\n box-shadow:\n 0 0 px2rem(4px) rgba(0, 0, 0, 0),\n 0 px2rem(4px) px2rem(8px) rgba(0, 0, 0, 0);\n\n // [print]: Hide header\n @media print {\n display: none;\n }\n\n // Header in shadow state, i.e. shadow is visible\n &[data-md-state=\"shadow\"] {\n box-shadow:\n 0 0 px2rem(4px) rgba(0, 0, 0, 0.1),\n 0 px2rem(4px) px2rem(8px) rgba(0, 0, 0, 0.2);\n transition:\n transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1),\n box-shadow 250ms;\n }\n\n // Header in hidden state, i.e. moved out of sight\n &[data-md-state=\"hidden\"] {\n transform: translateY(-100%);\n transition:\n transform 250ms cubic-bezier(0.8, 0, 0.6, 1),\n box-shadow 250ms;\n }\n\n // Header wrapper\n &__inner {\n display: flex;\n align-items: center;\n padding: 0 px2rem(4px);\n }\n\n // Header button\n &__button {\n position: relative;\n z-index: 1;\n margin: px2rem(4px);\n padding: px2rem(8px);\n color: currentColor;\n vertical-align: middle;\n outline-color: var(--md-accent-fg-color);\n cursor: pointer;\n transition: opacity 250ms;\n\n // Button on hover\n &:hover {\n opacity: 0.7;\n }\n\n // Header button is visible\n &:not([hidden]) {\n display: inline-block;\n }\n\n // Hide outline for pointer devices\n &:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n\n // Button with logo, pointing to `config.site_url`\n &.md-logo {\n margin: px2rem(4px);\n padding: px2rem(8px);\n\n // [tablet -]: Hide button\n @include break-to-device(tablet) {\n display: none;\n }\n\n // Image or icon\n img,\n svg {\n display: block;\n width: px2rem(24px);\n height: px2rem(24px);\n fill: currentColor;\n }\n }\n\n // Button for search\n &[for=\"__search\"] {\n\n // [tablet landscape +]: Hide button\n @include break-from-device(tablet landscape) {\n display: none;\n }\n\n // [no-js]: Hide button\n .no-js & {\n display: none;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n\n // Flip icon vertically\n svg {\n transform: scaleX(-1);\n }\n }\n }\n\n // Button for drawer\n &[for=\"__drawer\"] {\n\n // [screen +]: Hide button\n @include break-from-device(screen) {\n display: none;\n }\n }\n }\n\n // Header topic\n &__topic {\n position: absolute;\n display: flex;\n max-width: 100%;\n transition:\n transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1),\n opacity 150ms;\n\n // Second header topic - title of the current page\n & + & {\n z-index: -1;\n transform: translateX(px2rem(25px));\n opacity: 0;\n transition:\n transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1),\n opacity 150ms;\n pointer-events: none;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n transform: translateX(px2rem(-25px));\n }\n }\n }\n\n // Header title\n &__title {\n flex-grow: 1;\n height: px2rem(48px);\n margin-right: px2rem(8px);\n margin-left: px2rem(20px);\n font-size: px2rem(18px);\n line-height: px2rem(48px);\n\n // Header title in active state, i.e. page title is visible\n &[data-md-state=\"active\"] .md-header__topic {\n z-index: -1;\n transform: translateX(px2rem(-25px));\n opacity: 0;\n transition:\n transform 400ms cubic-bezier(1, 0.7, 0.1, 0.1),\n opacity 150ms;\n pointer-events: none;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n transform: translateX(px2rem(25px));\n }\n\n // Second header topic - title of the current page\n + .md-header__topic {\n z-index: 0;\n transform: translateX(0);\n opacity: 1;\n transition:\n transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1),\n opacity 150ms;\n pointer-events: initial;\n }\n }\n\n // Add ellipsis in case of overflowing text\n > .md-header__ellipsis {\n position: relative;\n width: 100%;\n height: 100%;\n }\n }\n\n // Header option\n &__option {\n display: flex;\n flex-shrink: 0;\n max-width: 100%;\n white-space: nowrap;\n transition:\n max-width 0ms 250ms,\n opacity 250ms 250ms;\n\n // Hide toggle when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n max-width: 0;\n opacity: 0;\n transition:\n max-width 0ms,\n opacity 0ms;\n }\n }\n\n // Repository information container\n &__source {\n display: none;\n\n // [tablet landscape +]: Show repository information\n @include break-from-device(tablet landscape) {\n display: block;\n width: px2rem(234px);\n max-width: px2rem(234px);\n margin-left: px2rem(20px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(20px);\n margin-left: initial;\n }\n }\n\n // [screen +]: Adjust spacing of search bar\n @include break-from-device(screen) {\n margin-left: px2rem(28px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(28px);\n }\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Footer\n.md-footer {\n color: var(--md-footer-fg-color);\n background-color: var(--md-footer-bg-color);\n\n // [print]: Hide footer\n @media print {\n display: none;\n }\n\n // Footer wrapper\n &__inner {\n padding: px2rem(4px);\n overflow: auto;\n }\n\n // Footer link to previous and next page\n &__link {\n display: flex;\n padding-top: px2rem(28px);\n padding-bottom: px2rem(8px);\n outline-color: var(--md-accent-fg-color);\n transition: opacity 250ms;\n\n // [tablet +]: Adjust width to 50/50\n @include break-from-device(tablet) {\n width: 50%;\n }\n\n // Footer link on focus/hover\n &:focus,\n &:hover {\n opacity: 0.7;\n }\n\n // Footer link to previous page\n &--prev {\n float: left;\n\n // [mobile -]: Adjust width to 25/75 and hide title\n @include break-to-device(mobile) {\n width: 25%;\n\n // Hide footer title\n .md-footer__title {\n display: none;\n }\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: right;\n\n // Flip icon vertically\n svg {\n transform: scaleX(-1);\n }\n }\n }\n\n // Footer link to next page\n &--next {\n float: right;\n text-align: right;\n\n // [mobile -]: Adjust width to 25/75\n @include break-to-device(mobile) {\n width: 75%;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: left;\n text-align: left;\n\n // Flip icon vertically\n svg {\n transform: scaleX(-1);\n }\n }\n }\n }\n\n // Footer title\n &__title {\n position: relative;\n flex-grow: 1;\n max-width: calc(100% - #{px2rem(48px)});\n padding: 0 px2rem(20px);\n font-size: px2rem(18px);\n line-height: px2rem(48px);\n }\n\n // Footer link button\n &__button {\n margin: px2rem(4px);\n padding: px2rem(8px);\n }\n\n // Footer link direction (i.e. prev and next)\n &__direction {\n position: absolute;\n right: 0;\n left: 0;\n margin-top: px2rem(-20px);\n padding: 0 px2rem(20px);\n font-size: px2rem(12.8px);\n opacity: 0.7;\n }\n}\n\n// Footer metadata\n.md-footer-meta {\n background-color: var(--md-footer-bg-color--dark);\n\n // Footer metadata wrapper\n &__inner {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n padding: px2rem(4px);\n }\n\n // Lighten color for non-hovered text links\n html &.md-typeset a {\n color: var(--md-footer-fg-color--light);\n\n // Text link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-footer-fg-color);\n }\n }\n}\n\n// Footer copyright and theme information\n.md-footer-copyright {\n width: 100%;\n margin: auto px2rem(12px);\n padding: px2rem(8px) 0;\n color: var(--md-footer-fg-color--lighter);\n font-size: px2rem(12.8px);\n\n // [tablet portrait +]: Show copyright and social links in one line\n @include break-from-device(tablet portrait) {\n width: auto;\n }\n\n // Footer copyright highlight - this is the upper part of the copyright and\n // theme information, which will include a darker color than the theme link\n &__highlight {\n color: var(--md-footer-fg-color--light);\n }\n}\n\n// Footer social links\n.md-footer-social {\n margin: 0 px2rem(8px);\n padding: px2rem(4px) 0 px2rem(12px);\n\n // [tablet portrait +]: Show copyright and social links in one line\n @include break-from-device(tablet portrait) {\n padding: px2rem(12px) 0;\n }\n\n // Footer social link\n &__link {\n display: inline-block;\n width: px2rem(32px);\n height: px2rem(32px);\n text-align: center;\n\n // Adjust line-height to match height for correct alignment\n &::before {\n line-height: 1.9;\n }\n\n // Fill icon with current color\n svg {\n max-height: px2rem(16px);\n vertical-align: -25%;\n fill: currentColor;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-nav-icon--prev: svg-load(\"material/arrow-left.svg\");\n --md-nav-icon--next: svg-load(\"material/chevron-right.svg\");\n --md-toc-icon: svg-load(\"material/table-of-contents.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Navigation\n.md-nav {\n font-size: px2rem(14px);\n line-height: 1.3;\n\n // Navigation title\n &__title {\n display: block;\n padding: 0 px2rem(12px);\n overflow: hidden;\n font-weight: 700;\n text-overflow: ellipsis;\n\n // Navigaton button\n .md-nav__button {\n display: none;\n\n // Stretch images based on height, as it's the smaller dimension\n img {\n width: auto;\n height: 100%;\n }\n\n // Button with logo, pointing to `config.site_url`\n &.md-logo {\n\n // Image or icon\n img,\n svg {\n display: block;\n width: px2rem(48px);\n height: px2rem(48px);\n fill: currentColor;\n }\n }\n }\n }\n\n // Navigation list\n &__list {\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n // Navigation item\n &__item {\n padding: 0 px2rem(12px);\n\n // Navigation item on level 2\n & & {\n padding-right: 0;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(12px);\n padding-left: 0;\n }\n }\n }\n\n // Navigation link\n &__link {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-top: 0.625em;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n transition: color 125ms;\n scroll-snap-align: start;\n\n // Navigation link in blurred state\n &[data-md-state=\"blur\"] {\n color: var(--md-default-fg-color--light);\n }\n\n // Active link\n .md-nav__item &--active {\n color: var(--md-typeset-a-color);\n }\n\n // Stretch section index link to full width\n .md-nav__item &--index [href] {\n width: 100%;\n }\n\n // Navigation link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Show outline for keyboard devices\n &.focus-visible {\n outline-color: var(--md-accent-fg-color);\n outline-offset: px2rem(4px);\n }\n\n // Navigation link for table of contents\n .md-nav--primary &[for=\"__toc\"] {\n display: none;\n\n // Table of contents icon\n .md-icon::after {\n display: block;\n width: 100%;\n height: 100%;\n mask-image: var(--md-toc-icon);\n background-color: currentColor;\n }\n\n // Hide table of contents\n ~ .md-nav {\n display: none;\n }\n }\n\n // Navigation link children (for section indexes)\n > * {\n display: flex;\n cursor: pointer;\n }\n }\n\n // Repository information container\n &__source {\n display: none;\n }\n\n // [tablet -]: Layered navigation\n @include break-to-device(tablet) {\n\n // Primary and nested navigation\n &--primary,\n &--primary & {\n position: absolute;\n top: 0;\n right: 0;\n left: 0;\n z-index: 1;\n display: flex;\n flex-direction: column;\n height: 100%;\n background-color: var(--md-default-bg-color);\n }\n\n // Primary navigation\n &--primary {\n\n // Navigation title and item\n .md-nav__title,\n .md-nav__item {\n font-size: px2rem(16px);\n line-height: 1.5;\n }\n\n // Navigation title\n .md-nav__title {\n position: relative;\n height: px2rem(112px);\n padding: px2rem(60px) px2rem(16px) px2rem(4px);\n color: var(--md-default-fg-color--light);\n font-weight: 400;\n line-height: px2rem(48px);\n white-space: nowrap;\n background-color: var(--md-default-fg-color--lightest);\n cursor: pointer;\n\n // Navigation icon\n .md-nav__icon {\n position: absolute;\n top: px2rem(8px);\n left: px2rem(8px);\n display: block;\n width: px2rem(24px);\n height: px2rem(24px);\n margin: px2rem(4px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(8px);\n left: initial;\n }\n\n // Navigation icon in link to previous level\n &::after {\n display: block;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n mask-image: var(--md-nav-icon--prev);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n }\n\n // Navigation list\n ~ .md-nav__list {\n overflow-y: auto;\n background-color: var(--md-default-bg-color);\n box-shadow:\n 0 px2rem(1px) 0 var(--md-default-fg-color--lightest) inset;\n scroll-snap-type: y mandatory;\n touch-action: pan-y;\n\n // Omit border on first child\n > :first-child {\n border-top: 0;\n }\n }\n\n // Top-level navigation title\n &[for=\"__drawer\"] {\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n }\n\n // Button with logo, pointing to `config.site_url`\n .md-logo {\n position: absolute;\n top: px2rem(4px);\n left: px2rem(4px);\n display: block;\n margin: px2rem(4px);\n padding: px2rem(8px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(4px);\n left: initial;\n }\n }\n }\n\n // Navigation list\n .md-nav__list {\n flex: 1;\n }\n\n // Navigation item\n .md-nav__item {\n padding: 0;\n border-top: px2rem(1px) solid var(--md-default-fg-color--lightest);\n\n // Navigation link in active navigation\n &--active > .md-nav__link {\n color: var(--md-typeset-a-color);\n\n // Navigation link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n }\n }\n }\n\n // Navigation link\n .md-nav__link {\n margin-top: 0;\n padding: px2rem(12px) px2rem(16px);\n\n // Navigation icon\n .md-nav__icon {\n flex-shrink: 0;\n width: px2rem(24px);\n height: px2rem(24px);\n margin-right: px2rem(-4px);\n font-size: px2rem(24px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: 0;\n margin-left: px2rem(-4px);\n }\n\n // Navigation icon in link to next level\n &::after {\n display: block;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n mask-image: var(--md-nav-icon--next);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n }\n }\n\n // Flip icon vertically\n .md-nav__icon {\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] &::after {\n transform: scale(-1);\n }\n }\n\n // Table of contents contained in primary navigation\n .md-nav--secondary {\n\n // Navigation on level 2-6\n .md-nav {\n position: static;\n background-color: transparent;\n\n // Navigation link on level 3\n .md-nav__link {\n padding-left: px2rem(28px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(28px);\n padding-left: initial;\n }\n }\n\n // Navigation link on level 4\n .md-nav .md-nav__link {\n padding-left: px2rem(40px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(40px);\n padding-left: initial;\n }\n }\n\n // Navigation link on level 5\n .md-nav .md-nav .md-nav__link {\n padding-left: px2rem(52px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(52px);\n padding-left: initial;\n }\n }\n\n // Navigation link on level 6\n .md-nav .md-nav .md-nav .md-nav__link {\n padding-left: px2rem(64px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(64px);\n padding-left: initial;\n }\n }\n }\n }\n }\n\n // Table of contents\n &--secondary {\n background-color: transparent;\n }\n\n // Toggle for nested navigation\n &__toggle ~ & {\n display: flex;\n transform: translateX(100%);\n opacity: 0;\n transition:\n transform 250ms cubic-bezier(0.8, 0, 0.6, 1),\n opacity 125ms 50ms;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n transform: translateX(-100%);\n }\n }\n\n // Show nested navigation when toggle is active\n &__toggle:checked ~ & {\n transform: translateX(0);\n opacity: 1;\n transition:\n transform 250ms cubic-bezier(0.4, 0, 0.2, 1),\n opacity 125ms 125ms;\n\n // Navigation list\n > .md-nav__list {\n // Hack: promote to own layer to reduce jitter\n backface-visibility: hidden;\n }\n }\n }\n\n // [tablet portrait -]: Layered navigation with table of contents\n @include break-to-device(tablet portrait) {\n\n // Show link to table of contents\n &--primary &__link[for=\"__toc\"] {\n display: flex;\n\n // Show table of contents icon\n .md-icon::after {\n content: \"\";\n }\n\n // Hide navigation link to current page\n + .md-nav__link {\n display: none;\n }\n\n // Show table of contents\n ~ .md-nav {\n display: flex;\n }\n }\n\n // Repository information container\n &__source {\n display: block;\n padding: 0 px2rem(4px);\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color--dark);\n }\n }\n\n // [tablet landscape]: Layered navigation with table of contents\n @include break-at-device(tablet landscape) {\n\n // Show link to integrated table of contents\n &--integrated &__link[for=\"__toc\"] {\n display: flex;\n\n // Show table of contents icon\n .md-icon::after {\n content: \"\";\n }\n\n // Hide navigation link to current page\n + .md-nav__link {\n display: none;\n }\n\n // Show table of contents\n ~ .md-nav {\n display: flex;\n }\n }\n }\n\n // [tablet landscape +]: Tree-like table of contents\n @include break-from-device(tablet landscape) {\n\n // Navigation title\n &--secondary &__title {\n\n // Adjust snapping behavior\n &[for=\"__toc\"] {\n scroll-snap-align: start;\n }\n\n // Hide navigation icon\n .md-nav__icon {\n display: none;\n }\n }\n }\n\n // [screen +]: Tree-like navigation\n @include break-from-device(screen) {\n transition: max-height 250ms cubic-bezier(0.86, 0, 0.07, 1);\n\n // Navigation title\n &--primary &__title {\n\n // Adjust snapping behavior\n &[for=\"__drawer\"] {\n scroll-snap-align: start;\n }\n\n // Hide navigation icon\n .md-nav__icon {\n display: none;\n }\n }\n\n // Hide toggle for nested navigation\n &__toggle ~ & {\n display: none;\n }\n\n // Show nested navigation when toggle is active or indeterminate\n &__toggle:checked ~ &,\n &__toggle:indeterminate ~ & {\n display: block;\n }\n\n // Hide navigation title in nested navigation\n &__item--nested > & > &__title {\n display: none;\n }\n\n // Navigation section\n &__item--section {\n display: block;\n margin: 1.25em 0;\n\n // Adjust spacing on last child\n &:last-child {\n margin-bottom: 0;\n }\n\n // Show navigation link as title\n > .md-nav__link {\n font-weight: 700;\n pointer-events: none;\n\n // Make navigation link clickable\n &--index [href] {\n pointer-events: initial;\n }\n\n // Hide naviation icon\n .md-nav__icon {\n display: none;\n }\n }\n\n // Navigation\n > .md-nav {\n display: block;\n\n // Adjust spacing on next level item\n > .md-nav__list > .md-nav__item {\n padding: 0;\n }\n }\n }\n\n // Navigation icon\n &__icon {\n float: right;\n width: px2rem(18px);\n height: px2rem(18px);\n transition: transform 250ms;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: left;\n transform: rotate(180deg);\n }\n\n // Navigation icon content\n &::after {\n display: inline-block;\n width: 100%;\n height: 100%;\n vertical-align: px2rem(-2px);\n background-color: currentColor;\n mask-image: var(--md-nav-icon--next);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n\n // Navigation icon - rotate icon when toggle is active or indeterminate\n .md-nav__item--nested .md-nav__toggle:checked ~ .md-nav__link &,\n .md-nav__item--nested .md-nav__toggle:indeterminate ~ .md-nav__link & {\n transform: rotate(90deg);\n }\n }\n\n // Modifier for when navigation tabs are rendered\n &--lifted {\n\n // Hide nested level 0 navigation items and site title\n > .md-nav__list > .md-nav__item--nested,\n > .md-nav__title {\n display: none;\n }\n\n // Hide level 0 navigation items\n > .md-nav__list > .md-nav__item {\n display: none;\n\n // Active parent navigation item\n &--active {\n display: block;\n padding: 0;\n\n // Show navigation link as title\n > .md-nav__link {\n margin-top: 0;\n padding: 0 px2rem(12px);\n font-weight: 700;\n pointer-events: none;\n\n // Make navigation link clickable\n &--index [href] {\n pointer-events: initial;\n }\n\n // Hide naviation icon\n .md-nav__icon {\n display: none;\n }\n }\n }\n }\n\n // Hack: Always show active navigation tab on breakpoint screen, despite\n // of checkbox being checked or not. Fixes #1655.\n .md-nav[data-md-level=\"1\"] {\n display: block;\n\n // Adjust spacing for level 1 navigation items\n > .md-nav__list > .md-nav__item {\n padding-right: px2rem(12px);\n }\n }\n }\n\n // Modifier for when table of contents is rendered in primary navigation\n &--integrated > .md-nav__list > .md-nav__item--active {\n\n // Add spacing to container for non-nested navigation items\n &:not(.md-nav__item--nested) {\n padding: 0 px2rem(12px);\n\n // Remove padding as it's given by container\n > .md-nav__link {\n padding: 0;\n }\n }\n\n // Show integrated table of contents\n .md-nav--secondary {\n display: block;\n margin-bottom: 1.25em;\n border-left: px2rem(1px) solid var(--md-primary-fg-color);\n\n // Hide table of contents title\n > .md-nav__title {\n display: none;\n }\n }\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-search-result-icon: svg-load(\"material/file-search-outline.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Search\n.md-search {\n position: relative;\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n padding: px2rem(4px) 0;\n }\n\n // [no-js]: Hide search\n .no-js & {\n display: none;\n }\n\n // Search overlay\n &__overlay {\n z-index: 1;\n opacity: 0;\n\n // [tablet portrait -]: Search modal\n @include break-to-device(tablet portrait) {\n position: absolute;\n top: px2rem(-20px);\n left: px2rem(-44px);\n width: px2rem(40px);\n height: px2rem(40px);\n overflow: hidden;\n background-color: var(--md-default-bg-color);\n border-radius: px2rem(20px);\n transform-origin: center;\n transition:\n transform 300ms 100ms,\n opacity 200ms 200ms;\n pointer-events: none;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(-44px);\n left: initial;\n }\n\n // Show overlay when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n opacity: 1;\n transition:\n transform 400ms,\n opacity 100ms;\n }\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n position: fixed;\n top: 0;\n left: 0;\n width: 0;\n height: 0;\n background-color: hsla(0, 0%, 0%, 0.54);\n cursor: pointer;\n transition:\n width 0ms 250ms,\n height 0ms 250ms,\n opacity 250ms;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: 0;\n left: initial;\n }\n\n // Show overlay when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n width: 100%;\n // Hack: when the header is translated upon scrolling, a new layer is\n // induced, which means that the height will now refer to the height of\n // the header, albeit positioning is fixed. This should be mitigated\n // in all cases when setting the height to 2x the viewport.\n height: 200vh;\n opacity: 1;\n transition:\n width 0ms,\n height 0ms,\n opacity 250ms;\n }\n }\n\n // Adjust appearance when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n\n // [mobile portrait -]: Scale up 45 times\n @include break-to-device(mobile portrait) {\n transform: scale(45);\n }\n\n // [mobile landscape]: Scale up 60 times\n @include break-at-device(mobile landscape) {\n transform: scale(60);\n }\n\n // [tablet portrait]: Scale up 75 times\n @include break-at-device(tablet portrait) {\n transform: scale(75);\n }\n }\n }\n\n // Search wrapper\n &__inner {\n // Hack: promote to own layer to reduce jitter\n backface-visibility: hidden;\n\n // [tablet portrait -]: Search modal\n @include break-to-device(tablet portrait) {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 2;\n width: 0;\n height: 0;\n overflow: hidden;\n transform: translateX(5%);\n opacity: 0;\n transition:\n width 0ms 300ms,\n height 0ms 300ms,\n transform 150ms 150ms cubic-bezier(0.4, 0, 0.2, 1),\n opacity 150ms 150ms;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: 0;\n left: initial;\n transform: translateX(-5%);\n }\n\n // Adjust appearance when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n width: 100%;\n height: 100%;\n transform: translateX(0);\n opacity: 1;\n transition:\n width 0ms 0ms,\n height 0ms 0ms,\n transform 150ms 150ms cubic-bezier(0.1, 0.7, 0.1, 1),\n opacity 150ms 150ms;\n }\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n position: relative;\n float: right;\n width: px2rem(234px);\n padding: px2rem(2px) 0;\n transition: width 250ms cubic-bezier(0.1, 0.7, 0.1, 1);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: left;\n }\n }\n\n // Adjust appearance when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n\n // [tablet landscape]: Omit overlaying header title\n @include break-at-device(tablet landscape) {\n width: px2rem(468px);\n }\n\n // [screen +]: Match width of content area\n @include break-from-device(screen) {\n width: px2rem(688px);\n }\n }\n }\n\n // Search form\n &__form {\n position: relative;\n z-index: 2;\n height: px2rem(48px);\n background-color: var(--md-default-bg-color);\n box-shadow: 0 0 px2rem(12px) transparent;\n transition:\n color 250ms,\n background-color 250ms;\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n height: px2rem(36px);\n background-color: hsla(0, 0%, 0%, 0.26);\n border-radius: px2rem(2px);\n\n // Search form on hover\n &:hover {\n background-color: hsla(0, 0%, 100%, 0.12);\n }\n }\n\n // Adjust appearance when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n color: var(--md-default-fg-color);\n background-color: var(--md-default-bg-color);\n border-radius: px2rem(2px) px2rem(2px) 0 0;\n box-shadow: 0 0 px2rem(12px) hsla(0, 0%, 0%, 0.07);\n }\n }\n\n // Search input\n &__input {\n position: relative;\n z-index: 2;\n width: 100%;\n height: 100%;\n padding: 0 px2rem(44px) 0 px2rem(72px);\n font-size: px2rem(18px);\n text-overflow: ellipsis;\n background: transparent;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding: 0 px2rem(72px) 0 px2rem(44px);\n }\n\n // Search placeholder\n &::placeholder {\n transition: color 250ms;\n }\n\n // Search icon and placeholder\n ~ .md-search__icon,\n &::placeholder {\n color: var(--md-default-fg-color--light);\n }\n\n // Remove the \"x\" rendered by Internet Explorer\n &::-ms-clear {\n display: none;\n }\n\n // [tablet portrait -]: Search modal\n @include break-to-device(tablet portrait) {\n width: 100%;\n height: px2rem(48px);\n font-size: px2rem(18px);\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n padding-left: px2rem(44px);\n color: inherit;\n font-size: px2rem(16px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(44px);\n }\n\n // Search placeholder\n &::placeholder {\n color: var(--md-primary-bg-color--light);\n }\n\n // Search icon\n + .md-search__icon {\n color: var(--md-primary-bg-color);\n }\n\n // Adjust appearance when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n text-overflow: clip;\n\n // Search icon and placeholder\n + .md-search__icon,\n &::placeholder {\n color: var(--md-default-fg-color--light);\n }\n }\n }\n }\n\n // Search icon\n &__icon {\n display: inline-block;\n width: px2rem(24px);\n height: px2rem(24px);\n cursor: pointer;\n transition:\n color 250ms,\n opacity 250ms;\n\n // Search icon on hover\n &:hover {\n opacity: 0.7;\n }\n\n // Search focus button\n &[for=\"__search\"] {\n position: absolute;\n top: px2rem(6px);\n left: px2rem(10px);\n z-index: 2;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(10px);\n left: initial;\n\n // Flip icon vertically\n svg {\n transform: scaleX(-1);\n }\n }\n\n // [tablet portrait -]: Search modal\n @include break-to-device(tablet portrait) {\n top: px2rem(12px);\n left: px2rem(16px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(16px);\n left: initial;\n }\n\n // Hide the magnifying glass\n svg:first-child {\n display: none;\n }\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n pointer-events: none;\n\n // Hide the back arrow\n svg:last-child {\n display: none;\n }\n }\n }\n }\n\n // Search options\n &__options {\n position: absolute;\n top: px2rem(6px);\n right: px2rem(10px);\n z-index: 2;\n pointer-events: none;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: initial;\n left: px2rem(10px);\n }\n\n // [tablet portrait -]: Search modal\n @include break-to-device(tablet portrait) {\n top: px2rem(12px);\n right: px2rem(16px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: initial;\n left: px2rem(16px);\n }\n }\n\n // Search option buttons\n > * {\n margin-left: px2rem(4px);\n color: var(--md-default-fg-color--light);\n transform: scale(0.75);\n opacity: 0;\n transition:\n transform 150ms cubic-bezier(0.1, 0.7, 0.1, 1),\n opacity 150ms;\n\n // Hide outline for pointer devices\n &:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n\n // Show reset button when search is active and input non-empty\n [data-md-toggle=\"search\"]:checked ~ .md-header\n .md-search__input:valid ~ & {\n transform: scale(1);\n opacity: 1;\n pointer-events: initial;\n\n // Search focus icon\n &:hover {\n opacity: 0.7;\n }\n }\n }\n }\n\n // Search suggestions\n &__suggest {\n position: absolute;\n top: 0;\n display: flex;\n align-items: center;\n width: 100%;\n height: 100%;\n padding: 0 px2rem(44px) 0 px2rem(72px);\n color: var(--md-default-fg-color--lighter);\n font-size: px2rem(18px);\n white-space: nowrap;\n opacity: 0;\n transition: opacity 50ms;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding: 0 px2rem(72px) 0 px2rem(44px);\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n padding-left: px2rem(44px);\n font-size: px2rem(16px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(44px);\n }\n }\n\n // Show suggestions when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n opacity: 1;\n transition: opacity 300ms 100ms;\n }\n }\n\n // Search output\n &__output {\n position: absolute;\n z-index: 1;\n width: 100%;\n overflow: hidden;\n border-radius: 0 0 px2rem(2px) px2rem(2px);\n\n // [tablet portrait -]: Search modal\n @include break-to-device(tablet portrait) {\n top: px2rem(48px);\n bottom: 0;\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n top: px2rem(38px);\n opacity: 0;\n transition: opacity 400ms;\n\n // Show output when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n @include z-depth(6);\n\n opacity: 1;\n }\n }\n }\n\n // Search scroll wrapper\n &__scrollwrap {\n height: 100%;\n overflow-y: auto;\n background-color: var(--md-default-bg-color);\n // Hack: promote to own layer to reduce jitter\n backface-visibility: hidden;\n // Hack: Chrome 88+ has weird overscroll behavior. Overall, scroll snapping\n // seems to be something that is not ready for prime time on some browsers.\n // scroll-snap-type: y mandatory;\n touch-action: pan-y;\n\n // Mitigiate excessive repaints on non-retina devices\n @media (max-resolution: 1dppx) {\n transform: translateZ(0);\n }\n\n // [tablet landscape]: Set fixed width to omit unnecessary reflow\n @include break-at-device(tablet landscape) {\n width: px2rem(468px);\n }\n\n // [screen +]: Set fixed width to omit unnecessary reflow\n @include break-from-device(screen) {\n width: px2rem(688px);\n }\n\n // [tablet landscape +]: Limit height to viewport\n @include break-from-device(tablet landscape) {\n max-height: 0;\n scrollbar-width: thin;\n scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n\n // Show scroll wrapper when search is active\n [data-md-toggle=\"search\"]:checked ~ .md-header & {\n max-height: 75vh;\n }\n\n // Search scroll wrapper on hover\n &:hover {\n scrollbar-color: var(--md-accent-fg-color) transparent;\n }\n\n // Webkit scrollbar\n &::-webkit-scrollbar {\n width: px2rem(4px);\n height: px2rem(4px);\n }\n\n // Webkit scrollbar thumb\n &::-webkit-scrollbar-thumb {\n background-color: var(--md-default-fg-color--lighter);\n\n // Webkit scrollbar thumb on hover\n &:hover {\n background-color: var(--md-accent-fg-color);\n }\n }\n }\n }\n}\n\n// Search result\n.md-search-result {\n color: var(--md-default-fg-color);\n word-break: break-word;\n\n // Search result metadata\n &__meta {\n padding: 0 px2rem(16px);\n color: var(--md-default-fg-color--light);\n font-size: px2rem(12.8px);\n line-height: px2rem(36px);\n background-color: var(--md-default-fg-color--lightest);\n scroll-snap-align: start;\n\n // [tablet landscape +]: Adjust spacing\n @include break-from-device(tablet landscape) {\n padding-left: px2rem(44px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(44px);\n padding-left: initial;\n }\n }\n }\n\n // Search result list\n &__list {\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n // Search result item\n &__item {\n box-shadow: 0 px2rem(-1px) 0 var(--md-default-fg-color--lightest);\n\n // Omit border on first child\n &:first-child {\n box-shadow: none;\n }\n }\n\n // Search result link\n &__link {\n display: block;\n outline: none;\n transition: background-color 250ms;\n scroll-snap-align: start;\n\n // Search result link on focus/hover\n &:focus,\n &:hover {\n background-color: var(--md-accent-fg-color--transparent);\n }\n\n // Adjust spacing on last child of last link\n &:last-child p:last-child {\n margin-bottom: px2rem(12px);\n }\n }\n\n // Search result more link\n &__more summary {\n display: block;\n padding: px2em(12px) px2rem(16px);\n color: var(--md-typeset-a-color);\n font-size: px2rem(12.8px);\n outline: none;\n cursor: pointer;\n transition:\n color 250ms,\n background-color 250ms;\n scroll-snap-align: start;\n\n // [tablet landscape +]: Adjust spacing\n @include break-from-device(tablet landscape) {\n padding-left: px2rem(44px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(44px);\n padding-left: px2rem(16px);\n }\n }\n\n // Search result more link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n background-color: var(--md-accent-fg-color--transparent);\n }\n\n // Hide native details marker\n &::marker,\n &::-webkit-details-marker {\n display: none;\n }\n\n // Adjust transparency of less relevant results\n ~ * > * {\n opacity: 0.65;\n }\n }\n\n // Search result article\n &__article {\n position: relative;\n padding: 0 px2rem(16px);\n overflow: hidden;\n\n // [tablet landscape +]: Adjust spacing\n @include break-from-device(tablet landscape) {\n padding-left: px2rem(44px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(44px);\n padding-left: px2rem(16px);\n }\n }\n\n // Search result article document\n &--document {\n\n // Search result title\n .md-search-result__title {\n margin: px2rem(11px) 0;\n font-weight: 400;\n font-size: px2rem(16px);\n line-height: 1.4;\n }\n }\n }\n\n // Search result icon\n &__icon {\n position: absolute;\n left: 0;\n width: px2rem(24px);\n height: px2rem(24px);\n margin: px2rem(10px);\n color: var(--md-default-fg-color--light);\n\n // [tablet portrait -]: Hide icon\n @include break-to-device(tablet portrait) {\n display: none;\n }\n\n // Search result icon content\n &::after {\n display: inline-block;\n width: 100%;\n height: 100%;\n background-color: currentColor;\n mask-image: var(--md-search-result-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: 0;\n left: initial;\n\n // Flip icon vertically\n &::after {\n transform: scaleX(-1);\n }\n }\n }\n\n // Search result title\n &__title {\n margin: 0.5em 0;\n font-weight: 700;\n font-size: px2rem(12.8px);\n line-height: 1.6;\n }\n\n // Search result teaser\n &__teaser {\n display: -webkit-box;\n max-height: px2rem(40px);\n margin: 0.5em 0;\n overflow: hidden;\n color: var(--md-default-fg-color--light);\n font-size: px2rem(12.8px);\n line-height: 1.6;\n text-overflow: ellipsis;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n\n // [mobile -]: Adjust number of lines\n @include break-to-device(mobile) {\n max-height: px2rem(60px);\n -webkit-line-clamp: 3;\n }\n\n // [tablet landscape]: Adjust number of lines\n @include break-at-device(tablet landscape) {\n max-height: px2rem(60px);\n -webkit-line-clamp: 3;\n }\n\n // Search term highlighting\n mark {\n text-decoration: underline;\n background-color: transparent;\n }\n }\n\n // Search result terms\n &__terms {\n margin: 0.5em 0;\n font-size: px2rem(12.8px);\n font-style: italic;\n }\n\n // Search term highlighting\n mark {\n color: var(--md-accent-fg-color);\n background-color: transparent;\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Selection\n.md-select {\n position: relative;\n z-index: 1;\n\n // Selection bubble\n &__inner {\n position: absolute;\n top: calc(100% - #{px2rem(4px)});\n left: 50%;\n max-height: 0;\n margin-top: px2rem(4px);\n color: var(--md-default-fg-color);\n background-color: var(--md-default-bg-color);\n border-radius: px2rem(2px);\n box-shadow:\n 0 px2rem(4px) px2rem(10px) hsla(0, 0%, 0%, 0.1),\n 0 0 px2rem(1px) hsla(0, 0%, 0%, 0.25);\n transform: translate3d(-50%, px2rem(6px), 0);\n opacity: 0;\n transition:\n transform 250ms 375ms,\n opacity 250ms 250ms,\n max-height 0ms 500ms;\n\n // Selection bubble on parent focus/hover\n .md-select:focus-within &,\n .md-select:hover & {\n max-height: px2rem(200px);\n transform: translate3d(-50%, 0, 0);\n opacity: 1;\n transition:\n transform 250ms cubic-bezier(0.1, 0.7, 0.1, 1),\n opacity 250ms,\n max-height 0ms;\n }\n\n // Selection bubble handle\n &::after {\n position: absolute;\n top: 0;\n left: 50%;\n width: 0;\n height: 0;\n margin-top: px2rem(-4px);\n margin-left: px2rem(-4px);\n border: px2rem(4px) solid transparent;\n border-top: 0;\n border-bottom-color: var(--md-default-bg-color);\n content: \"\";\n }\n }\n\n // Selection list\n &__list {\n max-height: inherit;\n margin: 0;\n padding: 0;\n overflow: auto;\n font-size: px2rem(16px);\n list-style-type: none;\n border-radius: px2rem(2px);\n }\n\n // Selection item\n &__item {\n line-height: px2rem(36px);\n }\n\n // Selection link\n &__link {\n display: block;\n width: 100%;\n padding-right: px2rem(24px);\n padding-left: px2rem(12px);\n outline: none;\n cursor: pointer;\n transition:\n background-color 250ms,\n color 250ms;\n scroll-snap-align: start;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(12px);\n padding-left: px2rem(24px);\n }\n\n // Link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Link on focus\n &:focus {\n background-color: var(--md-default-fg-color--lightest);\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Sidebar\n.md-sidebar {\n position: sticky;\n top: px2rem(48px);\n flex-shrink: 0;\n align-self: flex-start;\n width: px2rem(242px);\n padding: px2rem(24px) 0;\n\n // [print]: Hide sidebar\n @media print {\n display: none;\n }\n\n // [tablet -]: Show navigation as drawer\n @include break-to-device(tablet) {\n\n // Primary sidebar with navigation\n &--primary {\n position: fixed;\n top: 0;\n left: px2rem(-242px);\n z-index: 4;\n display: block;\n width: px2rem(242px);\n height: 100%;\n background-color: var(--md-default-bg-color);\n transform: translateX(0);\n transition:\n transform 250ms cubic-bezier(0.4, 0, 0.2, 1),\n box-shadow 250ms;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(-242px);\n left: initial;\n }\n\n // Show sidebar when drawer is active\n [data-md-toggle=\"drawer\"]:checked ~ .md-container & {\n @include z-depth(8);\n\n transform: translateX(px2rem(242px));\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n transform: translateX(px2rem(-242px));\n }\n }\n\n // Stretch scroll wrapper for primary sidebar\n .md-sidebar__scrollwrap {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n margin: 0;\n scroll-snap-type: none;\n overflow: hidden;\n }\n }\n }\n\n // [screen +]: Show navigation as sidebar\n @include break-from-device(screen) {\n height: 0;\n\n // [no-js]: Switch to native sticky behavior\n .no-js & {\n height: auto;\n }\n }\n\n // Secondary sidebar with table of contents\n &--secondary {\n display: none;\n order: 2;\n\n // [tablet landscape +]: Show table of contents as sidebar\n @include break-from-device(tablet landscape) {\n height: 0;\n\n // [no-js]: Switch to native sticky behavior\n .no-js & {\n height: auto;\n }\n\n // Sidebar is visible\n &:not([hidden]) {\n display: block;\n }\n\n // Ensure smooth scrolling on iOS\n .md-sidebar__scrollwrap {\n touch-action: pan-y;\n }\n }\n }\n\n // Sidebar scroll wrapper\n &__scrollwrap {\n margin: 0 px2rem(4px);\n overflow-y: auto;\n // Hack: promote to own layer to reduce jitter\n backface-visibility: hidden;\n // Hack: Chrome 81+ exhibits a strange bug, where it scrolls the container\n // to the bottom if `scroll-snap-type` is set on the initial render. For\n // this reason, we disable scroll snapping until this is resolved (#1667).\n // scroll-snap-type: y mandatory;\n scrollbar-width: thin;\n scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n\n // Sidebar scroll wrapper on hover\n &:hover {\n scrollbar-color: var(--md-accent-fg-color) transparent;\n }\n\n // Webkit scrollbar\n &::-webkit-scrollbar {\n width: px2rem(4px);\n height: px2rem(4px);\n }\n\n // Webkit scrollbar thumb\n &::-webkit-scrollbar-thumb {\n background-color: var(--md-default-fg-color--lighter);\n\n // Webkit scrollbar thumb on hover\n &:hover {\n background-color: var(--md-accent-fg-color);\n }\n }\n }\n}\n\n// [tablet -]: Show overlay on active drawer\n@include break-to-device(tablet) {\n\n // Sidebar overlay\n .md-overlay {\n position: fixed;\n top: 0;\n z-index: 4;\n width: 0;\n height: 0;\n background-color: hsla(0, 0%, 0%, 0.54);\n opacity: 0;\n transition:\n width 0ms 250ms,\n height 0ms 250ms,\n opacity 250ms;\n\n // Show overlay when drawer is active\n [data-md-toggle=\"drawer\"]:checked ~ & {\n width: 100%;\n height: 100%;\n opacity: 1;\n transition:\n width 0ms,\n height 0ms,\n opacity 250ms;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Keyframes\n// ----------------------------------------------------------------------------\n\n// Show repository facts\n@keyframes facts {\n 0% {\n height: 0;\n }\n\n 100% {\n height: px2rem(13px);\n }\n}\n\n// Show repository fact\n@keyframes fact {\n 0% {\n transform: translateY(100%);\n opacity: 0;\n }\n\n 50% {\n opacity: 0;\n }\n\n 100% {\n transform: translateY(0%);\n opacity: 1;\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-source-forks-icon: svg-load(\"octicons/repo-forked-16.svg\");\n --md-source-repositories-icon: svg-load(\"octicons/repo-16.svg\");\n --md-source-stars-icon: svg-load(\"octicons/star-16.svg\");\n --md-source-version-icon: svg-load(\"octicons/tag-16.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Repository information\n.md-source {\n display: block;\n font-size: px2rem(13px);\n line-height: 1.2;\n white-space: nowrap;\n outline-color: var(--md-accent-fg-color);\n // Hack: promote to own layer to reduce jitter\n backface-visibility: hidden;\n transition: opacity 250ms;\n\n // Repository information on hover\n &:hover {\n opacity: 0.7;\n }\n\n // Repository icon\n &__icon {\n display: inline-block;\n width: px2rem(40px);\n height: px2rem(48px);\n vertical-align: middle;\n\n // Align with margin only (as opposed to normal button alignment)\n svg {\n margin-top: px2rem(12px);\n margin-left: px2rem(12px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(12px);\n margin-left: initial;\n }\n }\n\n // Adjust spacing if icon is present\n + .md-source__repository {\n margin-left: px2rem(-40px);\n padding-left: px2rem(40px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(-40px);\n margin-left: initial;\n padding-right: px2rem(40px);\n padding-left: initial;\n }\n }\n }\n\n // Repository name\n &__repository {\n display: inline-block;\n max-width: calc(100% - #{px2rem(24px)});\n margin-left: px2rem(12px);\n overflow: hidden;\n text-overflow: ellipsis;\n vertical-align: middle;\n }\n\n // Repository facts\n &__facts {\n margin: px2rem(2px) 0 0;\n padding: 0;\n overflow: hidden;\n font-size: px2rem(11px);\n list-style-type: none;\n opacity: 0.75;\n\n // Show after the data was loaded\n [data-md-state=\"done\"] & {\n animation: facts 250ms ease-in;\n }\n }\n\n // Repository fact\n &__fact {\n display: inline-block;\n\n // Show after the data was loaded\n [data-md-state=\"done\"] & {\n animation: fact 400ms ease-out;\n }\n\n // Repository fact icon\n &::before {\n display: inline-block;\n width: px2rem(12px);\n height: px2rem(12px);\n margin-right: px2rem(2px);\n vertical-align: text-top;\n background-color: currentColor;\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: initial;\n margin-left: px2rem(2px);\n }\n }\n\n // Adjust spacing for repository fact icon\n &:nth-child(1n+2)::before {\n margin-left: px2rem(8px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(8px);\n margin-left: px2rem(2px);\n }\n }\n\n // Repository fact: version\n &--version::before {\n mask-image: var(--md-source-version-icon);\n }\n\n // Repository fact: stars\n &--stars::before {\n mask-image: var(--md-source-stars-icon);\n }\n\n // Repository fact: forks\n &--forks::before {\n mask-image: var(--md-source-forks-icon);\n }\n\n // Repository fact: repositories\n &--repositories::before {\n mask-image: var(--md-source-repositories-icon);\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Navigation tabs\n.md-tabs {\n width: 100%;\n overflow: auto;\n color: var(--md-primary-bg-color);\n background-color: var(--md-primary-fg-color);\n\n // [print]: Hide tabs\n @media print {\n display: none;\n }\n\n // [tablet -]: Hide tabs\n @include break-to-device(tablet) {\n display: none;\n }\n\n // Tabs in hidden state, i.e. when scrolling down\n &[data-md-state=\"hidden\"] {\n pointer-events: none;\n }\n\n // Navigation tabs list\n &__list {\n margin: 0;\n margin-left: px2rem(4px);\n padding: 0;\n white-space: nowrap;\n list-style: none;\n contain: content;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(4px);\n margin-left: initial;\n }\n }\n\n // Navigation tabs item\n &__item {\n display: inline-block;\n height: px2rem(48px);\n padding-right: px2rem(12px);\n padding-left: px2rem(12px);\n }\n\n // Navigation tabs link - could be defined as block elements and aligned via\n // line height, but this would imply more repaints when scrolling\n &__link {\n display: block;\n margin-top: px2rem(16px);\n font-size: px2rem(14px);\n outline-color: var(--md-accent-fg-color);\n outline-offset: px2rem(4px);\n // Hack: save a repaint when tabs are appearing on scrolling up\n backface-visibility: hidden;\n opacity: 0.7;\n transition:\n transform 400ms cubic-bezier(0.1, 0.7, 0.1, 1),\n opacity 250ms;\n\n // Active link and link on focus/hover\n &--active,\n &:focus,\n &:hover {\n color: inherit;\n opacity: 1;\n }\n\n // Delay transitions by a small amount\n @for $i from 2 through 16 {\n .md-tabs__item:nth-child(#{$i}) & {\n transition-delay: 20ms * ($i - 1);\n }\n }\n\n // Hide tabs upon scrolling - disable transition to minimizes repaints\n // while scrolling down, while scrolling up seems to be okay\n .md-tabs[data-md-state=\"hidden\"] & {\n transform: translateY(50%);\n opacity: 0;\n transition:\n transform 0ms 100ms,\n opacity 100ms;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Back-to-top button\n.md-top {\n position: fixed;\n top: px2rem(48px + 16px);\n z-index: 2;\n margin-left: 50%;\n padding: px2rem(8px) px2rem(16px);\n color: var(--md-default-fg-color--light);\n font-size: px2rem(14px);\n background-color: var(--md-default-bg-color);\n border-radius: px2rem(32px);\n outline: none;\n box-shadow:\n 0 px2rem(4px) px2rem(10px) hsla(0, 0%, 0%, 0.1),\n 0 0 px2rem(1px) hsla(0, 0%, 0%, 0.25);\n transform: translate(-50%, 0);\n transition:\n color 125ms,\n background-color 125ms,\n transform 125ms cubic-bezier(0.4, 0, 0.2, 1),\n opacity 125ms;\n\n // [print]: Hide back-to-top button\n @media print {\n display: none;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: 50%;\n margin-left: initial;\n transform: translate(50%, 0);\n }\n\n // Back-to-top button in hidden state\n &[data-md-state=\"hidden\"] {\n transform: translate(-50%, px2rem(4px));\n opacity: 0;\n transition-duration: 0ms;\n pointer-events: none;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n transform: translate(50%, px2rem(4px));\n }\n }\n\n // Back-to-top button on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-bg-color);\n background-color: var(--md-accent-fg-color);\n }\n\n // Inline icon\n svg {\n display: inline-block;\n vertical-align: -0.5em;\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Keyframes\n// ----------------------------------------------------------------------------\n\n// See https://github.com/squidfunk/mkdocs-material/issues/2429\n@keyframes hoverfix {\n 0% {\n pointer-events: none;\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-version-icon: svg-load(\"fontawesome/solid/caret-down.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Version selection\n.md-version {\n flex-shrink: 0;\n height: px2rem(48px);\n font-size: px2rem(16px);\n\n // Current selection\n &__current {\n position: relative;\n // Hack: in general, we would use `vertical-align` to align the version at\n // the bottom with the title, but since the list uses absolute positioning,\n // this won't work consistently. Furthermore, we would need to use inline\n // positioning to align the links, which looks jagged.\n top: px2rem(1px);\n margin-right: px2rem(8px);\n margin-left: px2rem(28px);\n color: inherit;\n outline: none;\n cursor: pointer;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(28px);\n margin-left: px2rem(8px);\n }\n\n // Version selection icon\n &::after {\n display: inline-block;\n width: px2rem(8px);\n height: px2rem(12px);\n margin-left: px2rem(8px);\n background-color: currentColor;\n mask-image: var(--md-version-icon);\n mask-repeat: no-repeat;\n content: \"\";\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(8px);\n margin-left: initial;\n }\n }\n }\n\n // Version selection list\n &__list {\n position: absolute;\n top: px2rem(3px);\n z-index: 1;\n max-height: 0;\n margin: px2rem(4px) px2rem(16px);\n padding: 0;\n overflow: auto;\n color: var(--md-default-fg-color);\n list-style-type: none;\n background-color: var(--md-default-bg-color);\n border-radius: px2rem(2px);\n box-shadow:\n 0 px2rem(4px) px2rem(10px) hsla(0, 0%, 0%, 0.1),\n 0 0 px2rem(1px) hsla(0, 0%, 0%, 0.25);\n opacity: 0;\n transition:\n max-height 0ms 500ms,\n opacity 250ms 250ms;\n scroll-snap-type: y mandatory;\n\n // Version selection list on parent focus/hover\n .md-version:focus-within &,\n .md-version:hover & {\n max-height: px2rem(200px);\n opacity: 1;\n transition:\n max-height 0ms,\n opacity 250ms;\n }\n\n // Fix hover on touch devices\n @media (pointer: coarse) {\n\n // Switch off on hover\n .md-version:hover & {\n animation: hoverfix 250ms forwards;\n }\n\n // Enable on focus\n .md-version:focus-within & {\n animation: none;\n }\n }\n }\n\n // Version selection item\n &__item {\n line-height: px2rem(36px);\n }\n\n // Version selection link\n &__link {\n display: block;\n width: 100%;\n padding-right: px2rem(24px);\n padding-left: px2rem(12px);\n white-space: nowrap;\n outline: none;\n cursor: pointer;\n transition:\n color 250ms,\n background-color 250ms;\n scroll-snap-align: start;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(12px);\n padding-left: px2rem(24px);\n }\n\n // Link on focus/hover\n &:focus,\n &:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Link on focus\n &:focus {\n background-color: var(--md-default-fg-color--lightest);\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n@use \"sass:color\";\n@use \"sass:list\";\n\n// ----------------------------------------------------------------------------\n// Variables\n// ----------------------------------------------------------------------------\n\n/// Admonition flavours\n$admonitions: (\n note: pencil $clr-blue-a200,\n abstract summary tldr: clipboard-text $clr-light-blue-a400,\n info todo: information $clr-cyan-a700,\n tip hint important: fire $clr-teal-a700,\n success check done: check-bold $clr-green-a700,\n question help faq: help-circle $clr-light-green-a700,\n warning caution attention: alert $clr-orange-a400,\n failure fail missing: close-thick $clr-red-a200,\n danger error: lightning-bolt $clr-red-a400,\n bug: bug $clr-pink-a400,\n example: format-list-numbered $clr-deep-purple-a200,\n quote cite: format-quote-close $clr-grey\n) !default;\n\n// ----------------------------------------------------------------------------\n// Rules: layout\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n @each $names, $props in $admonitions {\n --md-admonition-icon--#{nth($names, 1)}:\n svg-load(\"material/#{nth($props, 1)}.svg\");\n }\n}\n\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Admonition\n .admonition {\n margin: px2em(20px, 12.8px) 0;\n padding: 0 px2rem(12px);\n overflow: hidden;\n color: var(--md-admonition-fg-color);\n font-size: px2rem(12.8px);\n page-break-inside: avoid;\n background-color: var(--md-admonition-bg-color);\n border-left: px2rem(4px) solid $clr-blue-a200;\n border-radius: px2rem(2px);\n box-shadow:\n 0 px2rem(4px) px2rem(10px) hsla(0, 0%, 0%, 0.05),\n 0 px2rem(0.5px) px2rem(1px) hsla(0, 0%, 0%, 0.05);\n\n // [print]: Omit shadow as it may lead to rendering errors\n @media print {\n box-shadow: none;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n border-right: px2rem(4px) solid $clr-blue-a200;\n border-left: none;\n }\n\n // Adjust vertical spacing for nested admonitions\n .admonition {\n margin-top: 1em;\n margin-bottom: 1em;\n }\n\n // Adjust spacing for contained table wrappers\n .md-typeset__scrollwrap {\n margin: 1em px2rem(-12px);\n }\n\n // Adjust spacing for contained tables\n .md-typeset__table {\n padding: 0 px2rem(12px);\n }\n\n // Adjust spacing for single-child tabbed block container\n > .tabbed-set:only-child {\n margin-top: 0;\n }\n\n // Adjust spacing on last child\n html & > :last-child {\n margin-bottom: px2rem(12px);\n }\n }\n\n // Admonition title\n .admonition-title {\n position: relative;\n margin: 0 px2rem(-12px) 0 px2rem(-16px);\n padding: px2rem(8px) px2rem(12px) px2rem(8px) px2rem(40px);\n font-weight: 700;\n background-color: color.adjust($clr-blue-a200, $alpha: -0.9);\n border-left: px2rem(4px) solid $clr-blue-a200;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin: 0 px2rem(-16px) 0 px2rem(-12px);\n padding: px2rem(8px) px2rem(40px) px2rem(8px) px2rem(12px);\n border-right: px2rem(4px) solid $clr-blue-a200;\n border-left: none;\n }\n\n // Adjust spacing for title-only admonitions\n html &:last-child {\n margin-bottom: 0;\n }\n\n // Admonition icon\n &::before {\n position: absolute;\n left: px2rem(12px);\n width: px2rem(20px);\n height: px2rem(20px);\n background-color: $clr-blue-a200;\n mask-image: var(--md-admonition-icon--note);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2rem(12px);\n left: initial;\n }\n }\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules: flavours\n// ----------------------------------------------------------------------------\n\n@each $names, $props in $admonitions {\n $name: list.nth($names, 1);\n $tint: list.nth($props, 2);\n\n // Admonition flavour\n .md-typeset .admonition.#{$name} {\n border-color: $tint;\n }\n\n // Admonition flavour title\n .md-typeset .#{$name} > .admonition-title {\n background-color: color.adjust($tint, $alpha: -0.9);\n border-color: $tint;\n\n // Admonition icon\n &::before {\n background-color: $tint;\n mask-image: var(--md-admonition-icon--#{$name});\n mask-repeat: no-repeat;\n mask-size: contain;\n }\n }\n\n // Define synonyms for flavours\n @if length($names) > 1 {\n @for $n from 2 through length($names) {\n .#{nth($names, $n)} {\n @extend .#{$name};\n }\n }\n }\n}\n","// ==========================================================================\n//\n// Name: UI Color Palette\n// Description: The color palette of material design.\n// Version: 2.3.1\n//\n// Author: Denis Malinochkin\n// Git: https://github.com/mrmlnc/material-color\n//\n// twitter: @mrmlnc\n//\n// ==========================================================================\n\n\n//\n// List of base colors\n//\n\n// $clr-red\n// $clr-pink\n// $clr-purple\n// $clr-deep-purple\n// $clr-indigo\n// $clr-blue\n// $clr-light-blue\n// $clr-cyan\n// $clr-teal\n// $clr-green\n// $clr-light-green\n// $clr-lime\n// $clr-yellow\n// $clr-amber\n// $clr-orange\n// $clr-deep-orange\n// $clr-brown\n// $clr-grey\n// $clr-blue-grey\n// $clr-black\n// $clr-white\n\n\n//\n// Red\n//\n\n$clr-red-list: (\n \"base\": #f44336,\n \"50\": #ffebee,\n \"100\": #ffcdd2,\n \"200\": #ef9a9a,\n \"300\": #e57373,\n \"400\": #ef5350,\n \"500\": #f44336,\n \"600\": #e53935,\n \"700\": #d32f2f,\n \"800\": #c62828,\n \"900\": #b71c1c,\n \"a100\": #ff8a80,\n \"a200\": #ff5252,\n \"a400\": #ff1744,\n \"a700\": #d50000\n);\n\n$clr-red: map-get($clr-red-list, \"base\");\n\n$clr-red-50: map-get($clr-red-list, \"50\");\n$clr-red-100: map-get($clr-red-list, \"100\");\n$clr-red-200: map-get($clr-red-list, \"200\");\n$clr-red-300: map-get($clr-red-list, \"300\");\n$clr-red-400: map-get($clr-red-list, \"400\");\n$clr-red-500: map-get($clr-red-list, \"500\");\n$clr-red-600: map-get($clr-red-list, \"600\");\n$clr-red-700: map-get($clr-red-list, \"700\");\n$clr-red-800: map-get($clr-red-list, \"800\");\n$clr-red-900: map-get($clr-red-list, \"900\");\n$clr-red-a100: map-get($clr-red-list, \"a100\");\n$clr-red-a200: map-get($clr-red-list, \"a200\");\n$clr-red-a400: map-get($clr-red-list, \"a400\");\n$clr-red-a700: map-get($clr-red-list, \"a700\");\n\n\n//\n// Pink\n//\n\n$clr-pink-list: (\n \"base\": #e91e63,\n \"50\": #fce4ec,\n \"100\": #f8bbd0,\n \"200\": #f48fb1,\n \"300\": #f06292,\n \"400\": #ec407a,\n \"500\": #e91e63,\n \"600\": #d81b60,\n \"700\": #c2185b,\n \"800\": #ad1457,\n \"900\": #880e4f,\n \"a100\": #ff80ab,\n \"a200\": #ff4081,\n \"a400\": #f50057,\n \"a700\": #c51162\n);\n\n$clr-pink: map-get($clr-pink-list, \"base\");\n\n$clr-pink-50: map-get($clr-pink-list, \"50\");\n$clr-pink-100: map-get($clr-pink-list, \"100\");\n$clr-pink-200: map-get($clr-pink-list, \"200\");\n$clr-pink-300: map-get($clr-pink-list, \"300\");\n$clr-pink-400: map-get($clr-pink-list, \"400\");\n$clr-pink-500: map-get($clr-pink-list, \"500\");\n$clr-pink-600: map-get($clr-pink-list, \"600\");\n$clr-pink-700: map-get($clr-pink-list, \"700\");\n$clr-pink-800: map-get($clr-pink-list, \"800\");\n$clr-pink-900: map-get($clr-pink-list, \"900\");\n$clr-pink-a100: map-get($clr-pink-list, \"a100\");\n$clr-pink-a200: map-get($clr-pink-list, \"a200\");\n$clr-pink-a400: map-get($clr-pink-list, \"a400\");\n$clr-pink-a700: map-get($clr-pink-list, \"a700\");\n\n\n//\n// Purple\n//\n\n$clr-purple-list: (\n \"base\": #9c27b0,\n \"50\": #f3e5f5,\n \"100\": #e1bee7,\n \"200\": #ce93d8,\n \"300\": #ba68c8,\n \"400\": #ab47bc,\n \"500\": #9c27b0,\n \"600\": #8e24aa,\n \"700\": #7b1fa2,\n \"800\": #6a1b9a,\n \"900\": #4a148c,\n \"a100\": #ea80fc,\n \"a200\": #e040fb,\n \"a400\": #d500f9,\n \"a700\": #aa00ff\n);\n\n$clr-purple: map-get($clr-purple-list, \"base\");\n\n$clr-purple-50: map-get($clr-purple-list, \"50\");\n$clr-purple-100: map-get($clr-purple-list, \"100\");\n$clr-purple-200: map-get($clr-purple-list, \"200\");\n$clr-purple-300: map-get($clr-purple-list, \"300\");\n$clr-purple-400: map-get($clr-purple-list, \"400\");\n$clr-purple-500: map-get($clr-purple-list, \"500\");\n$clr-purple-600: map-get($clr-purple-list, \"600\");\n$clr-purple-700: map-get($clr-purple-list, \"700\");\n$clr-purple-800: map-get($clr-purple-list, \"800\");\n$clr-purple-900: map-get($clr-purple-list, \"900\");\n$clr-purple-a100: map-get($clr-purple-list, \"a100\");\n$clr-purple-a200: map-get($clr-purple-list, \"a200\");\n$clr-purple-a400: map-get($clr-purple-list, \"a400\");\n$clr-purple-a700: map-get($clr-purple-list, \"a700\");\n\n\n//\n// Deep purple\n//\n\n$clr-deep-purple-list: (\n \"base\": #673ab7,\n \"50\": #ede7f6,\n \"100\": #d1c4e9,\n \"200\": #b39ddb,\n \"300\": #9575cd,\n \"400\": #7e57c2,\n \"500\": #673ab7,\n \"600\": #5e35b1,\n \"700\": #512da8,\n \"800\": #4527a0,\n \"900\": #311b92,\n \"a100\": #b388ff,\n \"a200\": #7c4dff,\n \"a400\": #651fff,\n \"a700\": #6200ea\n);\n\n$clr-deep-purple: map-get($clr-deep-purple-list, \"base\");\n\n$clr-deep-purple-50: map-get($clr-deep-purple-list, \"50\");\n$clr-deep-purple-100: map-get($clr-deep-purple-list, \"100\");\n$clr-deep-purple-200: map-get($clr-deep-purple-list, \"200\");\n$clr-deep-purple-300: map-get($clr-deep-purple-list, \"300\");\n$clr-deep-purple-400: map-get($clr-deep-purple-list, \"400\");\n$clr-deep-purple-500: map-get($clr-deep-purple-list, \"500\");\n$clr-deep-purple-600: map-get($clr-deep-purple-list, \"600\");\n$clr-deep-purple-700: map-get($clr-deep-purple-list, \"700\");\n$clr-deep-purple-800: map-get($clr-deep-purple-list, \"800\");\n$clr-deep-purple-900: map-get($clr-deep-purple-list, \"900\");\n$clr-deep-purple-a100: map-get($clr-deep-purple-list, \"a100\");\n$clr-deep-purple-a200: map-get($clr-deep-purple-list, \"a200\");\n$clr-deep-purple-a400: map-get($clr-deep-purple-list, \"a400\");\n$clr-deep-purple-a700: map-get($clr-deep-purple-list, \"a700\");\n\n\n//\n// Indigo\n//\n\n$clr-indigo-list: (\n \"base\": #3f51b5,\n \"50\": #e8eaf6,\n \"100\": #c5cae9,\n \"200\": #9fa8da,\n \"300\": #7986cb,\n \"400\": #5c6bc0,\n \"500\": #3f51b5,\n \"600\": #3949ab,\n \"700\": #303f9f,\n \"800\": #283593,\n \"900\": #1a237e,\n \"a100\": #8c9eff,\n \"a200\": #536dfe,\n \"a400\": #3d5afe,\n \"a700\": #304ffe\n);\n\n$clr-indigo: map-get($clr-indigo-list, \"base\");\n\n$clr-indigo-50: map-get($clr-indigo-list, \"50\");\n$clr-indigo-100: map-get($clr-indigo-list, \"100\");\n$clr-indigo-200: map-get($clr-indigo-list, \"200\");\n$clr-indigo-300: map-get($clr-indigo-list, \"300\");\n$clr-indigo-400: map-get($clr-indigo-list, \"400\");\n$clr-indigo-500: map-get($clr-indigo-list, \"500\");\n$clr-indigo-600: map-get($clr-indigo-list, \"600\");\n$clr-indigo-700: map-get($clr-indigo-list, \"700\");\n$clr-indigo-800: map-get($clr-indigo-list, \"800\");\n$clr-indigo-900: map-get($clr-indigo-list, \"900\");\n$clr-indigo-a100: map-get($clr-indigo-list, \"a100\");\n$clr-indigo-a200: map-get($clr-indigo-list, \"a200\");\n$clr-indigo-a400: map-get($clr-indigo-list, \"a400\");\n$clr-indigo-a700: map-get($clr-indigo-list, \"a700\");\n\n\n//\n// Blue\n//\n\n$clr-blue-list: (\n \"base\": #2196f3,\n \"50\": #e3f2fd,\n \"100\": #bbdefb,\n \"200\": #90caf9,\n \"300\": #64b5f6,\n \"400\": #42a5f5,\n \"500\": #2196f3,\n \"600\": #1e88e5,\n \"700\": #1976d2,\n \"800\": #1565c0,\n \"900\": #0d47a1,\n \"a100\": #82b1ff,\n \"a200\": #448aff,\n \"a400\": #2979ff,\n \"a700\": #2962ff\n);\n\n$clr-blue: map-get($clr-blue-list, \"base\");\n\n$clr-blue-50: map-get($clr-blue-list, \"50\");\n$clr-blue-100: map-get($clr-blue-list, \"100\");\n$clr-blue-200: map-get($clr-blue-list, \"200\");\n$clr-blue-300: map-get($clr-blue-list, \"300\");\n$clr-blue-400: map-get($clr-blue-list, \"400\");\n$clr-blue-500: map-get($clr-blue-list, \"500\");\n$clr-blue-600: map-get($clr-blue-list, \"600\");\n$clr-blue-700: map-get($clr-blue-list, \"700\");\n$clr-blue-800: map-get($clr-blue-list, \"800\");\n$clr-blue-900: map-get($clr-blue-list, \"900\");\n$clr-blue-a100: map-get($clr-blue-list, \"a100\");\n$clr-blue-a200: map-get($clr-blue-list, \"a200\");\n$clr-blue-a400: map-get($clr-blue-list, \"a400\");\n$clr-blue-a700: map-get($clr-blue-list, \"a700\");\n\n\n//\n// Light Blue\n//\n\n$clr-light-blue-list: (\n \"base\": #03a9f4,\n \"50\": #e1f5fe,\n \"100\": #b3e5fc,\n \"200\": #81d4fa,\n \"300\": #4fc3f7,\n \"400\": #29b6f6,\n \"500\": #03a9f4,\n \"600\": #039be5,\n \"700\": #0288d1,\n \"800\": #0277bd,\n \"900\": #01579b,\n \"a100\": #80d8ff,\n \"a200\": #40c4ff,\n \"a400\": #00b0ff,\n \"a700\": #0091ea\n);\n\n$clr-light-blue: map-get($clr-light-blue-list, \"base\");\n\n$clr-light-blue-50: map-get($clr-light-blue-list, \"50\");\n$clr-light-blue-100: map-get($clr-light-blue-list, \"100\");\n$clr-light-blue-200: map-get($clr-light-blue-list, \"200\");\n$clr-light-blue-300: map-get($clr-light-blue-list, \"300\");\n$clr-light-blue-400: map-get($clr-light-blue-list, \"400\");\n$clr-light-blue-500: map-get($clr-light-blue-list, \"500\");\n$clr-light-blue-600: map-get($clr-light-blue-list, \"600\");\n$clr-light-blue-700: map-get($clr-light-blue-list, \"700\");\n$clr-light-blue-800: map-get($clr-light-blue-list, \"800\");\n$clr-light-blue-900: map-get($clr-light-blue-list, \"900\");\n$clr-light-blue-a100: map-get($clr-light-blue-list, \"a100\");\n$clr-light-blue-a200: map-get($clr-light-blue-list, \"a200\");\n$clr-light-blue-a400: map-get($clr-light-blue-list, \"a400\");\n$clr-light-blue-a700: map-get($clr-light-blue-list, \"a700\");\n\n\n//\n// Cyan\n//\n\n$clr-cyan-list: (\n \"base\": #00bcd4,\n \"50\": #e0f7fa,\n \"100\": #b2ebf2,\n \"200\": #80deea,\n \"300\": #4dd0e1,\n \"400\": #26c6da,\n \"500\": #00bcd4,\n \"600\": #00acc1,\n \"700\": #0097a7,\n \"800\": #00838f,\n \"900\": #006064,\n \"a100\": #84ffff,\n \"a200\": #18ffff,\n \"a400\": #00e5ff,\n \"a700\": #00b8d4\n);\n\n$clr-cyan: map-get($clr-cyan-list, \"base\");\n\n$clr-cyan-50: map-get($clr-cyan-list, \"50\");\n$clr-cyan-100: map-get($clr-cyan-list, \"100\");\n$clr-cyan-200: map-get($clr-cyan-list, \"200\");\n$clr-cyan-300: map-get($clr-cyan-list, \"300\");\n$clr-cyan-400: map-get($clr-cyan-list, \"400\");\n$clr-cyan-500: map-get($clr-cyan-list, \"500\");\n$clr-cyan-600: map-get($clr-cyan-list, \"600\");\n$clr-cyan-700: map-get($clr-cyan-list, \"700\");\n$clr-cyan-800: map-get($clr-cyan-list, \"800\");\n$clr-cyan-900: map-get($clr-cyan-list, \"900\");\n$clr-cyan-a100: map-get($clr-cyan-list, \"a100\");\n$clr-cyan-a200: map-get($clr-cyan-list, \"a200\");\n$clr-cyan-a400: map-get($clr-cyan-list, \"a400\");\n$clr-cyan-a700: map-get($clr-cyan-list, \"a700\");\n\n\n//\n// Teal\n//\n\n$clr-teal-list: (\n \"base\": #009688,\n \"50\": #e0f2f1,\n \"100\": #b2dfdb,\n \"200\": #80cbc4,\n \"300\": #4db6ac,\n \"400\": #26a69a,\n \"500\": #009688,\n \"600\": #00897b,\n \"700\": #00796b,\n \"800\": #00695c,\n \"900\": #004d40,\n \"a100\": #a7ffeb,\n \"a200\": #64ffda,\n \"a400\": #1de9b6,\n \"a700\": #00bfa5\n);\n\n$clr-teal: map-get($clr-teal-list, \"base\");\n\n$clr-teal-50: map-get($clr-teal-list, \"50\");\n$clr-teal-100: map-get($clr-teal-list, \"100\");\n$clr-teal-200: map-get($clr-teal-list, \"200\");\n$clr-teal-300: map-get($clr-teal-list, \"300\");\n$clr-teal-400: map-get($clr-teal-list, \"400\");\n$clr-teal-500: map-get($clr-teal-list, \"500\");\n$clr-teal-600: map-get($clr-teal-list, \"600\");\n$clr-teal-700: map-get($clr-teal-list, \"700\");\n$clr-teal-800: map-get($clr-teal-list, \"800\");\n$clr-teal-900: map-get($clr-teal-list, \"900\");\n$clr-teal-a100: map-get($clr-teal-list, \"a100\");\n$clr-teal-a200: map-get($clr-teal-list, \"a200\");\n$clr-teal-a400: map-get($clr-teal-list, \"a400\");\n$clr-teal-a700: map-get($clr-teal-list, \"a700\");\n\n\n//\n// Green\n//\n\n$clr-green-list: (\n \"base\": #4caf50,\n \"50\": #e8f5e9,\n \"100\": #c8e6c9,\n \"200\": #a5d6a7,\n \"300\": #81c784,\n \"400\": #66bb6a,\n \"500\": #4caf50,\n \"600\": #43a047,\n \"700\": #388e3c,\n \"800\": #2e7d32,\n \"900\": #1b5e20,\n \"a100\": #b9f6ca,\n \"a200\": #69f0ae,\n \"a400\": #00e676,\n \"a700\": #00c853\n);\n\n$clr-green: map-get($clr-green-list, \"base\");\n\n$clr-green-50: map-get($clr-green-list, \"50\");\n$clr-green-100: map-get($clr-green-list, \"100\");\n$clr-green-200: map-get($clr-green-list, \"200\");\n$clr-green-300: map-get($clr-green-list, \"300\");\n$clr-green-400: map-get($clr-green-list, \"400\");\n$clr-green-500: map-get($clr-green-list, \"500\");\n$clr-green-600: map-get($clr-green-list, \"600\");\n$clr-green-700: map-get($clr-green-list, \"700\");\n$clr-green-800: map-get($clr-green-list, \"800\");\n$clr-green-900: map-get($clr-green-list, \"900\");\n$clr-green-a100: map-get($clr-green-list, \"a100\");\n$clr-green-a200: map-get($clr-green-list, \"a200\");\n$clr-green-a400: map-get($clr-green-list, \"a400\");\n$clr-green-a700: map-get($clr-green-list, \"a700\");\n\n\n//\n// Light green\n//\n\n$clr-light-green-list: (\n \"base\": #8bc34a,\n \"50\": #f1f8e9,\n \"100\": #dcedc8,\n \"200\": #c5e1a5,\n \"300\": #aed581,\n \"400\": #9ccc65,\n \"500\": #8bc34a,\n \"600\": #7cb342,\n \"700\": #689f38,\n \"800\": #558b2f,\n \"900\": #33691e,\n \"a100\": #ccff90,\n \"a200\": #b2ff59,\n \"a400\": #76ff03,\n \"a700\": #64dd17\n);\n\n$clr-light-green: map-get($clr-light-green-list, \"base\");\n\n$clr-light-green-50: map-get($clr-light-green-list, \"50\");\n$clr-light-green-100: map-get($clr-light-green-list, \"100\");\n$clr-light-green-200: map-get($clr-light-green-list, \"200\");\n$clr-light-green-300: map-get($clr-light-green-list, \"300\");\n$clr-light-green-400: map-get($clr-light-green-list, \"400\");\n$clr-light-green-500: map-get($clr-light-green-list, \"500\");\n$clr-light-green-600: map-get($clr-light-green-list, \"600\");\n$clr-light-green-700: map-get($clr-light-green-list, \"700\");\n$clr-light-green-800: map-get($clr-light-green-list, \"800\");\n$clr-light-green-900: map-get($clr-light-green-list, \"900\");\n$clr-light-green-a100: map-get($clr-light-green-list, \"a100\");\n$clr-light-green-a200: map-get($clr-light-green-list, \"a200\");\n$clr-light-green-a400: map-get($clr-light-green-list, \"a400\");\n$clr-light-green-a700: map-get($clr-light-green-list, \"a700\");\n\n\n//\n// Lime\n//\n\n$clr-lime-list: (\n \"base\": #cddc39,\n \"50\": #f9fbe7,\n \"100\": #f0f4c3,\n \"200\": #e6ee9c,\n \"300\": #dce775,\n \"400\": #d4e157,\n \"500\": #cddc39,\n \"600\": #c0ca33,\n \"700\": #afb42b,\n \"800\": #9e9d24,\n \"900\": #827717,\n \"a100\": #f4ff81,\n \"a200\": #eeff41,\n \"a400\": #c6ff00,\n \"a700\": #aeea00\n);\n\n$clr-lime: map-get($clr-lime-list, \"base\");\n\n$clr-lime-50: map-get($clr-lime-list, \"50\");\n$clr-lime-100: map-get($clr-lime-list, \"100\");\n$clr-lime-200: map-get($clr-lime-list, \"200\");\n$clr-lime-300: map-get($clr-lime-list, \"300\");\n$clr-lime-400: map-get($clr-lime-list, \"400\");\n$clr-lime-500: map-get($clr-lime-list, \"500\");\n$clr-lime-600: map-get($clr-lime-list, \"600\");\n$clr-lime-700: map-get($clr-lime-list, \"700\");\n$clr-lime-800: map-get($clr-lime-list, \"800\");\n$clr-lime-900: map-get($clr-lime-list, \"900\");\n$clr-lime-a100: map-get($clr-lime-list, \"a100\");\n$clr-lime-a200: map-get($clr-lime-list, \"a200\");\n$clr-lime-a400: map-get($clr-lime-list, \"a400\");\n$clr-lime-a700: map-get($clr-lime-list, \"a700\");\n\n\n//\n// Yellow\n//\n\n$clr-yellow-list: (\n \"base\": #ffeb3b,\n \"50\": #fffde7,\n \"100\": #fff9c4,\n \"200\": #fff59d,\n \"300\": #fff176,\n \"400\": #ffee58,\n \"500\": #ffeb3b,\n \"600\": #fdd835,\n \"700\": #fbc02d,\n \"800\": #f9a825,\n \"900\": #f57f17,\n \"a100\": #ffff8d,\n \"a200\": #ffff00,\n \"a400\": #ffea00,\n \"a700\": #ffd600\n);\n\n$clr-yellow: map-get($clr-yellow-list, \"base\");\n\n$clr-yellow-50: map-get($clr-yellow-list, \"50\");\n$clr-yellow-100: map-get($clr-yellow-list, \"100\");\n$clr-yellow-200: map-get($clr-yellow-list, \"200\");\n$clr-yellow-300: map-get($clr-yellow-list, \"300\");\n$clr-yellow-400: map-get($clr-yellow-list, \"400\");\n$clr-yellow-500: map-get($clr-yellow-list, \"500\");\n$clr-yellow-600: map-get($clr-yellow-list, \"600\");\n$clr-yellow-700: map-get($clr-yellow-list, \"700\");\n$clr-yellow-800: map-get($clr-yellow-list, \"800\");\n$clr-yellow-900: map-get($clr-yellow-list, \"900\");\n$clr-yellow-a100: map-get($clr-yellow-list, \"a100\");\n$clr-yellow-a200: map-get($clr-yellow-list, \"a200\");\n$clr-yellow-a400: map-get($clr-yellow-list, \"a400\");\n$clr-yellow-a700: map-get($clr-yellow-list, \"a700\");\n\n\n//\n// amber\n//\n\n$clr-amber-list: (\n \"base\": #ffc107,\n \"50\": #fff8e1,\n \"100\": #ffecb3,\n \"200\": #ffe082,\n \"300\": #ffd54f,\n \"400\": #ffca28,\n \"500\": #ffc107,\n \"600\": #ffb300,\n \"700\": #ffa000,\n \"800\": #ff8f00,\n \"900\": #ff6f00,\n \"a100\": #ffe57f,\n \"a200\": #ffd740,\n \"a400\": #ffc400,\n \"a700\": #ffab00\n);\n\n$clr-amber: map-get($clr-amber-list, \"base\");\n\n$clr-amber-50: map-get($clr-amber-list, \"50\");\n$clr-amber-100: map-get($clr-amber-list, \"100\");\n$clr-amber-200: map-get($clr-amber-list, \"200\");\n$clr-amber-300: map-get($clr-amber-list, \"300\");\n$clr-amber-400: map-get($clr-amber-list, \"400\");\n$clr-amber-500: map-get($clr-amber-list, \"500\");\n$clr-amber-600: map-get($clr-amber-list, \"600\");\n$clr-amber-700: map-get($clr-amber-list, \"700\");\n$clr-amber-800: map-get($clr-amber-list, \"800\");\n$clr-amber-900: map-get($clr-amber-list, \"900\");\n$clr-amber-a100: map-get($clr-amber-list, \"a100\");\n$clr-amber-a200: map-get($clr-amber-list, \"a200\");\n$clr-amber-a400: map-get($clr-amber-list, \"a400\");\n$clr-amber-a700: map-get($clr-amber-list, \"a700\");\n\n\n//\n// Orange\n//\n\n$clr-orange-list: (\n \"base\": #ff9800,\n \"50\": #fff3e0,\n \"100\": #ffe0b2,\n \"200\": #ffcc80,\n \"300\": #ffb74d,\n \"400\": #ffa726,\n \"500\": #ff9800,\n \"600\": #fb8c00,\n \"700\": #f57c00,\n \"800\": #ef6c00,\n \"900\": #e65100,\n \"a100\": #ffd180,\n \"a200\": #ffab40,\n \"a400\": #ff9100,\n \"a700\": #ff6d00\n);\n\n$clr-orange: map-get($clr-orange-list, \"base\");\n\n$clr-orange-50: map-get($clr-orange-list, \"50\");\n$clr-orange-100: map-get($clr-orange-list, \"100\");\n$clr-orange-200: map-get($clr-orange-list, \"200\");\n$clr-orange-300: map-get($clr-orange-list, \"300\");\n$clr-orange-400: map-get($clr-orange-list, \"400\");\n$clr-orange-500: map-get($clr-orange-list, \"500\");\n$clr-orange-600: map-get($clr-orange-list, \"600\");\n$clr-orange-700: map-get($clr-orange-list, \"700\");\n$clr-orange-800: map-get($clr-orange-list, \"800\");\n$clr-orange-900: map-get($clr-orange-list, \"900\");\n$clr-orange-a100: map-get($clr-orange-list, \"a100\");\n$clr-orange-a200: map-get($clr-orange-list, \"a200\");\n$clr-orange-a400: map-get($clr-orange-list, \"a400\");\n$clr-orange-a700: map-get($clr-orange-list, \"a700\");\n\n\n//\n// Deep orange\n//\n\n$clr-deep-orange-list: (\n \"base\": #ff5722,\n \"50\": #fbe9e7,\n \"100\": #ffccbc,\n \"200\": #ffab91,\n \"300\": #ff8a65,\n \"400\": #ff7043,\n \"500\": #ff5722,\n \"600\": #f4511e,\n \"700\": #e64a19,\n \"800\": #d84315,\n \"900\": #bf360c,\n \"a100\": #ff9e80,\n \"a200\": #ff6e40,\n \"a400\": #ff3d00,\n \"a700\": #dd2c00\n);\n\n$clr-deep-orange: map-get($clr-deep-orange-list, \"base\");\n\n$clr-deep-orange-50: map-get($clr-deep-orange-list, \"50\");\n$clr-deep-orange-100: map-get($clr-deep-orange-list, \"100\");\n$clr-deep-orange-200: map-get($clr-deep-orange-list, \"200\");\n$clr-deep-orange-300: map-get($clr-deep-orange-list, \"300\");\n$clr-deep-orange-400: map-get($clr-deep-orange-list, \"400\");\n$clr-deep-orange-500: map-get($clr-deep-orange-list, \"500\");\n$clr-deep-orange-600: map-get($clr-deep-orange-list, \"600\");\n$clr-deep-orange-700: map-get($clr-deep-orange-list, \"700\");\n$clr-deep-orange-800: map-get($clr-deep-orange-list, \"800\");\n$clr-deep-orange-900: map-get($clr-deep-orange-list, \"900\");\n$clr-deep-orange-a100: map-get($clr-deep-orange-list, \"a100\");\n$clr-deep-orange-a200: map-get($clr-deep-orange-list, \"a200\");\n$clr-deep-orange-a400: map-get($clr-deep-orange-list, \"a400\");\n$clr-deep-orange-a700: map-get($clr-deep-orange-list, \"a700\");\n\n\n//\n// Brown\n//\n\n$clr-brown-list: (\n \"base\": #795548,\n \"50\": #efebe9,\n \"100\": #d7ccc8,\n \"200\": #bcaaa4,\n \"300\": #a1887f,\n \"400\": #8d6e63,\n \"500\": #795548,\n \"600\": #6d4c41,\n \"700\": #5d4037,\n \"800\": #4e342e,\n \"900\": #3e2723,\n);\n\n$clr-brown: map-get($clr-brown-list, \"base\");\n\n$clr-brown-50: map-get($clr-brown-list, \"50\");\n$clr-brown-100: map-get($clr-brown-list, \"100\");\n$clr-brown-200: map-get($clr-brown-list, \"200\");\n$clr-brown-300: map-get($clr-brown-list, \"300\");\n$clr-brown-400: map-get($clr-brown-list, \"400\");\n$clr-brown-500: map-get($clr-brown-list, \"500\");\n$clr-brown-600: map-get($clr-brown-list, \"600\");\n$clr-brown-700: map-get($clr-brown-list, \"700\");\n$clr-brown-800: map-get($clr-brown-list, \"800\");\n$clr-brown-900: map-get($clr-brown-list, \"900\");\n\n\n//\n// Grey\n//\n\n$clr-grey-list: (\n \"base\": #9e9e9e,\n \"50\": #fafafa,\n \"100\": #f5f5f5,\n \"200\": #eeeeee,\n \"300\": #e0e0e0,\n \"400\": #bdbdbd,\n \"500\": #9e9e9e,\n \"600\": #757575,\n \"700\": #616161,\n \"800\": #424242,\n \"900\": #212121,\n);\n\n$clr-grey: map-get($clr-grey-list, \"base\");\n\n$clr-grey-50: map-get($clr-grey-list, \"50\");\n$clr-grey-100: map-get($clr-grey-list, \"100\");\n$clr-grey-200: map-get($clr-grey-list, \"200\");\n$clr-grey-300: map-get($clr-grey-list, \"300\");\n$clr-grey-400: map-get($clr-grey-list, \"400\");\n$clr-grey-500: map-get($clr-grey-list, \"500\");\n$clr-grey-600: map-get($clr-grey-list, \"600\");\n$clr-grey-700: map-get($clr-grey-list, \"700\");\n$clr-grey-800: map-get($clr-grey-list, \"800\");\n$clr-grey-900: map-get($clr-grey-list, \"900\");\n\n\n//\n// Blue grey\n//\n\n$clr-blue-grey-list: (\n \"base\": #607d8b,\n \"50\": #eceff1,\n \"100\": #cfd8dc,\n \"200\": #b0bec5,\n \"300\": #90a4ae,\n \"400\": #78909c,\n \"500\": #607d8b,\n \"600\": #546e7a,\n \"700\": #455a64,\n \"800\": #37474f,\n \"900\": #263238,\n);\n\n$clr-blue-grey: map-get($clr-blue-grey-list, \"base\");\n\n$clr-blue-grey-50: map-get($clr-blue-grey-list, \"50\");\n$clr-blue-grey-100: map-get($clr-blue-grey-list, \"100\");\n$clr-blue-grey-200: map-get($clr-blue-grey-list, \"200\");\n$clr-blue-grey-300: map-get($clr-blue-grey-list, \"300\");\n$clr-blue-grey-400: map-get($clr-blue-grey-list, \"400\");\n$clr-blue-grey-500: map-get($clr-blue-grey-list, \"500\");\n$clr-blue-grey-600: map-get($clr-blue-grey-list, \"600\");\n$clr-blue-grey-700: map-get($clr-blue-grey-list, \"700\");\n$clr-blue-grey-800: map-get($clr-blue-grey-list, \"800\");\n$clr-blue-grey-900: map-get($clr-blue-grey-list, \"900\");\n\n\n//\n// Black\n//\n\n$clr-black-list: (\n \"base\": #000\n);\n\n$clr-black: map-get($clr-black-list, \"base\");\n\n\n//\n// White\n//\n\n$clr-white-list: (\n \"base\": #fff\n);\n\n$clr-white: map-get($clr-white-list, \"base\");\n\n\n//\n// List for all Colors for looping\n//\n\n$clr-list-all: (\n \"red\": $clr-red-list,\n \"pink\": $clr-pink-list,\n \"purple\": $clr-purple-list,\n \"deep-purple\": $clr-deep-purple-list,\n \"indigo\": $clr-indigo-list,\n \"blue\": $clr-blue-list,\n \"light-blue\": $clr-light-blue-list,\n \"cyan\": $clr-cyan-list,\n \"teal\": $clr-teal-list,\n \"green\": $clr-green-list,\n \"light-green\": $clr-light-green-list,\n \"lime\": $clr-lime-list,\n \"yellow\": $clr-yellow-list,\n \"amber\": $clr-amber-list,\n \"orange\": $clr-orange-list,\n \"deep-orange\": $clr-deep-orange-list,\n \"brown\": $clr-brown-list,\n \"grey\": $clr-grey-list,\n \"blue-grey\": $clr-blue-grey-list,\n \"black\": $clr-black-list,\n \"white\": $clr-white-list\n);\n\n\n//\n// Typography\n//\n\n$clr-ui-display-4: $clr-grey-600;\n$clr-ui-display-3: $clr-grey-600;\n$clr-ui-display-2: $clr-grey-600;\n$clr-ui-display-1: $clr-grey-600;\n$clr-ui-headline: $clr-grey-900;\n$clr-ui-title: $clr-grey-900;\n$clr-ui-subhead-1: $clr-grey-900;\n$clr-ui-body-2: $clr-grey-900;\n$clr-ui-body-1: $clr-grey-900;\n$clr-ui-caption: $clr-grey-600;\n$clr-ui-menu: $clr-grey-900;\n$clr-ui-button: $clr-grey-900;\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-footnotes-icon: svg-load(\"material/keyboard-return.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Footnote container\n .footnote {\n color: var(--md-default-fg-color--light);\n font-size: px2rem(12.8px);\n\n // Footnote list - omit left indentation\n > ol {\n margin-left: 0;\n\n // Footnote item - footnote items can contain lists, so we need to scope\n // the spacing adjustments to the top-level footnote item.\n > li {\n transition: color 125ms;\n\n // Darken color on target\n &:target {\n color: var(--md-default-fg-color);\n }\n\n // Show backreferences on footnote hover\n &:hover .footnote-backref,\n &:target .footnote-backref {\n transform: translateX(0);\n opacity: 1;\n }\n\n // Adjust spacing on first child\n > :first-child {\n margin-top: 0;\n }\n }\n }\n }\n\n // Footnote reference\n .footnote-ref {\n font-weight: 700;\n font-size: px2em(12px, 16px);\n\n // Hack: increase specificity to override default\n html & {\n outline-offset: px2rem(2px);\n }\n }\n\n // Footnote backreference\n .footnote-backref {\n display: inline-block;\n color: var(--md-typeset-a-color);\n // Hack: omit Unicode arrow for replacement with icon\n font-size: 0;\n vertical-align: text-bottom;\n transform: translateX(px2rem(5px));\n opacity: 0;\n transition:\n color 250ms,\n transform 250ms 250ms,\n opacity 125ms 250ms;\n\n // [print]: Show footnote backreferences\n @media print {\n color: var(--md-typeset-a-color);\n transform: translateX(0);\n opacity: 1;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n transform: translateX(px2rem(-5px));\n }\n\n // Adjust color on hover\n &:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Footnote backreference icon\n &::before {\n display: inline-block;\n width: px2rem(16px);\n height: px2rem(16px);\n background-color: currentColor;\n mask-image: var(--md-footnotes-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n\n // Flip icon vertically\n svg {\n transform: scaleX(-1);\n }\n }\n }\n }\n\n // Footnote reference wrapper\n [id^=\"fnref:\"]:target {\n scroll-margin-top: initial;\n margin-top: -1 * px2rem(48px + 24px - 4px);\n padding-top: px2rem(48px + 24px - 4px);\n\n // Show outline for all devices\n > .footnote-ref {\n outline: auto;\n }\n }\n\n // Footnote wrapper\n [id^=\"fn:\"]:target {\n scroll-margin-top: initial;\n margin-top: -1 * px2rem(48px + 24px - 3px);\n padding-top: px2rem(48px + 24px - 3px);\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Headerlink\n .headerlink {\n display: inline-block;\n margin-left: px2rem(10px);\n color: var(--md-default-fg-color--lighter);\n opacity: 0;\n transition:\n color 250ms,\n opacity 125ms;\n\n // [print]: Hide headerlinks\n @media print {\n display: none;\n }\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n margin-right: px2rem(10px);\n margin-left: initial;\n }\n }\n\n // Show headerlinks on parent hover\n :hover > .headerlink,\n :target > .headerlink,\n .headerlink:focus {\n opacity: 1;\n transition:\n color 250ms,\n opacity 125ms;\n }\n\n // Adjust color on parent target or focus/hover\n :target > .headerlink,\n .headerlink:focus,\n .headerlink:hover {\n color: var(--md-accent-fg-color);\n }\n\n // Adjust scroll offset for all elements with `id` attributes - general scroll\n // margin offset for anything that can be targeted. Browser support is pretty\n // decent by now, but Edge <79 and Safari (iOS and macOS) still don't support\n // it properly, so we settle with a cross-browser anchor correction solution.\n :target {\n scroll-margin-top: px2rem(48px + 24px);\n\n // [screen +]: Sticky navigation tabs\n @include break-from-device(screen) {\n\n // Adjust scroll offset for sticky navigation tabs\n .md-header--lifted ~ .md-container & {\n scroll-margin-top: px2rem(96px + 24px);\n }\n }\n }\n\n // Adjust scroll offset for headlines of level 1-3\n h1:target,\n h2:target,\n h3:target {\n scroll-margin-top: initial;\n\n // Anchor correction hack\n &::before {\n display: block;\n margin-top: -1 * px2rem(48px + 24px - 4px);\n padding-top: px2rem(48px + 24px - 4px);\n content: \"\";\n }\n\n // [screen +]: Sticky navigation tabs\n @include break-from-device(screen) {\n\n // Adjust scroll offset for sticky navigation tabs\n .md-header--lifted ~ .md-container & {\n scroll-margin-top: initial;\n\n // Anchor correction hack\n &::before {\n margin-top: -1 * px2rem(96px + 24px - 4px);\n padding-top: px2rem(96px + 24px - 4px);\n }\n }\n }\n }\n\n // Adjust scroll offset for headlines of level 4\n h4:target {\n scroll-margin-top: initial;\n\n // Anchor correction hack\n &::before {\n display: block;\n margin-top: -1 * px2rem(48px + 24px - 3px);\n padding-top: px2rem(48px + 24px - 3px);\n content: \"\";\n }\n\n // [screen +]: Sticky navigation tabs\n @include break-from-device(screen) {\n\n // Adjust scroll offset for sticky navigation tabs\n .md-header--lifted ~ .md-container & {\n scroll-margin-top: initial;\n\n // Anchor correction hack\n &::before {\n margin-top: -1 * px2rem(96px + 24px - 3px);\n padding-top: px2rem(96px + 24px - 3px);\n }\n }\n }\n }\n\n // Adjust scroll offset for headlines of level 5-6\n h5:target,\n h6:target {\n scroll-margin-top: initial;\n\n // Anchor correction hack\n &::before {\n display: block;\n margin-top: -1 * px2rem(48px + 24px);\n padding-top: px2rem(48px + 24px);\n content: \"\";\n }\n\n // [screen +]: Sticky navigation tabs\n @include break-from-device(screen) {\n\n // Adjust scroll offset for sticky navigation tabs\n .md-header--lifted ~ .md-container & {\n scroll-margin-top: initial;\n\n // Anchor correction hack\n &::before {\n margin-top: -1 * px2rem(96px + 24px);\n padding-top: px2rem(96px + 24px);\n }\n }\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Arithmatex container\n div.arithmatex {\n overflow: auto;\n\n // [mobile -]: Align with body copy\n @include break-to-device(mobile) {\n margin: 0 px2rem(-16px);\n }\n\n // Arithmatex content\n > * {\n width: min-content;\n // stylelint-disable-next-line declaration-no-important\n margin: 1em auto !important;\n padding: 0 px2rem(16px);\n touch-action: auto;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Deletion, addition or comment\n del.critic,\n ins.critic,\n .critic.comment {\n box-decoration-break: clone;\n }\n\n // Deletion\n del.critic {\n background-color: var(--md-typeset-del-color);\n }\n\n // Addition\n ins.critic {\n background-color: var(--md-typeset-ins-color);\n }\n\n // Comment\n .critic.comment {\n color: var(--md-code-hl-comment-color);\n\n // Comment opening mark\n &::before {\n content: \"/* \";\n }\n\n // Comment closing mark\n &::after {\n content: \" */\";\n }\n }\n\n // Critic block\n .critic.block {\n display: block;\n margin: 1em 0;\n padding-right: px2rem(16px);\n padding-left: px2rem(16px);\n overflow: auto;\n box-shadow: none;\n\n // Adjust spacing on first child\n > :first-child {\n margin-top: 0.5em;\n }\n\n // Adjust spacing on last child\n > :last-child {\n margin-bottom: 0.5em;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-details-icon: svg-load(\"material/chevron-right.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Details\n details {\n @extend .admonition;\n\n display: flow-root;\n padding-top: 0;\n overflow: visible;\n\n // Details title icon - rotate icon on transition to open state\n &[open] > summary::after {\n transform: rotate(90deg);\n }\n\n // Adjust spacing for details in closed state\n &:not([open]) {\n padding-bottom: 0;\n box-shadow: none;\n\n // Hack: we cannot set `overflow: hidden` on the `details` element (which\n // is why we set it to `overflow: visible`, as the outline would not be\n // visible when focusing. Therefore, we must set the border radius on the\n // summary explicitly.\n > summary {\n border-radius: px2rem(2px);\n }\n }\n\n // Hack: omit margin collapse\n &::after {\n display: table;\n content: \"\";\n }\n }\n\n // Details title\n summary {\n @extend .admonition-title;\n\n display: block;\n min-height: px2rem(20px);\n padding: px2rem(8px) px2rem(36px) px2rem(8px) px2rem(40px);\n border-top-left-radius: px2rem(2px);\n border-top-right-radius: px2rem(2px);\n cursor: pointer;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding: px2rem(8px) px2rem(44px) px2rem(8px) px2rem(36px);\n }\n\n // Show outline for keyboard devices\n &.focus-visible {\n outline-color: var(--md-accent-fg-color);\n outline-offset: px2rem(4px);\n }\n\n // Hide outline for pointer devices\n &:not(.focus-visible) {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n\n // Details marker\n &::after {\n position: absolute;\n top: px2rem(8px);\n right: px2rem(8px);\n width: px2rem(20px);\n height: px2rem(20px);\n background-color: currentColor;\n mask-image: var(--md-details-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n transform: rotate(0deg);\n transition: transform 250ms;\n content: \"\";\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: initial;\n left: px2rem(8px);\n transform: rotate(180deg);\n }\n }\n\n // Hide native details marker\n &::marker,\n &::-webkit-details-marker {\n display: none;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Emoji and icon container\n .emojione,\n .twemoji,\n .gemoji {\n display: inline-flex;\n height: px2em(18px);\n vertical-align: text-top;\n\n // Icon - inlined via mkdocs-material-extensions\n svg {\n width: px2em(18px);\n max-height: 100%;\n fill: currentColor;\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules: syntax highlighting\n// ----------------------------------------------------------------------------\n\n// Code block\n.highlight {\n .o, // Operator\n .ow { // Operator, word\n color: var(--md-code-hl-operator-color);\n }\n\n .p { // Punctuation\n color: var(--md-code-hl-punctuation-color);\n }\n\n .cpf, // Comment, preprocessor file\n .l, // Literal\n .s, // Literal, string\n .sb, // Literal, string backticks\n .sc, // Literal, string char\n .s2, // Literal, string double\n .si, // Literal, string interpol\n .s1, // Literal, string single\n .ss { // Literal, string symbol\n color: var(--md-code-hl-string-color);\n }\n\n .cp, // Comment, pre-processor\n .se, // Literal, string escape\n .sh, // Literal, string heredoc\n .sr, // Literal, string regex\n .sx { // Literal, string other\n color: var(--md-code-hl-special-color);\n }\n\n .m, // Number\n .mb, // Number, binary\n .mf, // Number, float\n .mh, // Number, hex\n .mi, // Number, integer\n .il, // Number, integer long\n .mo { // Number, octal\n color: var(--md-code-hl-number-color);\n }\n\n .k, // Keyword,\n .kd, // Keyword, declaration\n .kn, // Keyword, namespace\n .kp, // Keyword, pseudo\n .kr, // Keyword, reserved\n .kt { // Keyword, type\n color: var(--md-code-hl-keyword-color);\n }\n\n .kc, // Keyword, constant\n .n { // Name\n color: var(--md-code-hl-name-color);\n }\n\n .no, // Name, constant\n .nb, // Name, builtin\n .bp { // Name, builtin pseudo\n color: var(--md-code-hl-constant-color);\n }\n\n .nc, // Name, class\n .ne, // Name, exception\n .nf, // Name, function\n .nn { // Name, namespace\n color: var(--md-code-hl-function-color);\n }\n\n .nd, // Name, decorator\n .ni, // Name, entity\n .nl, // Name, label\n .nt { // Name, tag\n color: var(--md-code-hl-keyword-color);\n }\n\n .c, // Comment\n .cm, // Comment, multiline\n .c1, // Comment, single\n .ch, // Comment, shebang\n .cs, // Comment, special\n .sd { // Literal, string doc\n color: var(--md-code-hl-comment-color);\n }\n\n .na, // Name, attribute\n .nv, // Variable,\n .vc, // Variable, class\n .vg, // Variable, global\n .vi { // Variable, instance\n color: var(--md-code-hl-variable-color);\n }\n\n .ge, // Generic, emph\n .gr, // Generic, error\n .gh, // Generic, heading\n .go, // Generic, output\n .gp, // Generic, prompt\n .gs, // Generic, strong\n .gu, // Generic, subheading\n .gt { // Generic, traceback\n color: var(--md-code-hl-generic-color);\n }\n\n .gd, // Diff, delete\n .gi { // Diff, insert\n margin: 0 px2em(-2px);\n padding: 0 px2em(2px);\n border-radius: px2rem(2px);\n }\n\n .gd { // Diff, delete\n background-color: var(--md-typeset-del-color);\n }\n\n .gi { // Diff, insert\n background-color: var(--md-typeset-ins-color);\n }\n\n // Highlighted line\n .hll {\n display: block;\n margin: 0 px2em(-16px, 13.6px);\n padding: 0 px2em(16px, 13.6px);\n background-color: var(--md-code-hl-color);\n }\n\n // Code block title\n span.filename {\n position: relative;\n display: block;\n margin-top: 1em;\n padding: px2em(10.5px, 13.6px) px2em(16px, 13.6px);\n font-weight: 700;\n font-size: px2em(13.6px);\n background-color: var(--md-code-bg-color);\n border-bottom: px2rem(1px) solid var(--md-default-fg-color--lightest);\n border-top-left-radius: px2rem(2px);\n border-top-right-radius: px2rem(2px);\n\n // Adjust spacing for code block\n + pre {\n margin-top: 0;\n }\n }\n\n // Code block line numbers (inline)\n [data-linenos]::before {\n position: sticky;\n left: px2em(-16px, 13.6px);\n float: left;\n margin-right: px2em(16px, 13.6px);\n margin-left: px2em(-16px, 13.6px);\n padding-left: px2em(16px, 13.6px);\n color: var(--md-default-fg-color--light);\n background-color: var(--md-code-bg-color);\n box-shadow: px2rem(-1px) 0 var(--md-default-fg-color--lightest) inset;\n content: attr(data-linenos);\n user-select: none;\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules: layout\n// ----------------------------------------------------------------------------\n\n// Code block with line numbers\n.highlighttable {\n display: flow-root;\n overflow: hidden;\n\n // Set table elements to block layout, because otherwise the whole flexbox\n // hacking won't work correctly\n tbody,\n td {\n display: block;\n padding: 0;\n }\n\n // We need to use flexbox layout, because otherwise it's not possible to\n // make the code container scroll while keeping the line numbers static\n tr {\n display: flex;\n }\n\n // The pre tags are nested inside a table, so we need to omit the margin\n // because it collapses below all the overflows\n pre {\n margin: 0;\n }\n\n // Code block title container\n th.filename {\n flex-grow: 1;\n padding: 0;\n text-align: left;\n }\n\n // Code block line numbers - disable user selection, so code can be easily\n // copied without accidentally also copying the line numbers\n .linenos {\n padding: px2em(10.5px, 13.6px) px2em(16px, 13.6px);\n padding-right: 0;\n font-size: px2em(13.6px);\n background-color: var(--md-code-bg-color);\n user-select: none;\n }\n\n // Code block line numbers container\n .linenodiv {\n padding-right: px2em(8px, 13.6px);\n box-shadow: px2rem(-1px) 0 var(--md-default-fg-color--lightest) inset;\n\n // Adjust colors and alignment\n pre {\n color: var(--md-default-fg-color--light);\n text-align: right;\n }\n }\n\n // Code block container - stretch to remaining space\n .code {\n flex: 1;\n overflow: hidden;\n }\n}\n\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Code block with line numbers\n .highlighttable {\n margin: 1em 0;\n direction: ltr;\n border-radius: px2rem(2px);\n\n // Omit rounded borders on contained code block\n code {\n border-radius: 0;\n }\n }\n\n // [mobile -]: Align with body copy\n @include break-to-device(mobile) {\n\n // Top-level code block\n > .highlight {\n margin: 1em px2rem(-16px);\n\n // Highlighted line\n .hll {\n margin: 0 px2rem(-16px);\n padding: 0 px2rem(16px);\n }\n\n // Omit rounded borders\n code {\n border-radius: 0;\n }\n }\n\n // Top-level code block with line numbers\n > .highlighttable {\n margin: 1em px2rem(-16px);\n border-radius: 0;\n\n // Highlighted line\n .hll {\n margin: 0 px2rem(-16px);\n padding: 0 px2rem(16px);\n }\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules: legacy implementation (deprecated, removed in v8)\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Tabbed content\n .tabbed-content {\n display: none;\n order: 99;\n width: 100%;\n box-shadow: 0 px2rem(-1px) var(--md-default-fg-color--lightest);\n\n // [print]: Show all tabs (even hidden ones) when printing\n @media print {\n display: block;\n order: initial;\n }\n\n // Code block is the only child of a tab - remove margin and mirror\n // previous (now deprecated) SuperFences code block grouping behavior\n > pre:only-child,\n > .highlight:only-child pre,\n > .highlighttable:only-child {\n margin: 0;\n\n // Omit rounded borders\n > code {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n }\n }\n\n // Adjust spacing for nested tab\n > .tabbed-set {\n margin: 0;\n }\n }\n\n // Tabbed container\n .tabbed-set {\n position: relative;\n display: flex;\n flex-wrap: wrap;\n margin: 1em 0;\n border-radius: px2rem(2px);\n\n // Tab radio button - the Tabbed extension will generate radio buttons with\n // labels, so tabs can be triggered without the necessity for JavaScript.\n // This is pretty cool, as it has great accessibility out-of-the box, so\n // we just hide the radio button and toggle the label color for indication.\n > input {\n position: absolute;\n width: 0;\n height: 0;\n opacity: 0;\n\n // Tab label for checked radio button\n &:checked + label {\n color: var(--md-accent-fg-color);\n border-color: var(--md-accent-fg-color);\n\n // Show tabbed block content\n + .tabbed-content {\n display: block;\n }\n }\n\n // Tab label on focus\n &:focus + label {\n outline-style: auto;\n outline-color: var(--md-accent-fg-color);\n }\n\n // Hide outline for pointer devices\n &:not(.focus-visible) + label {\n outline: none;\n -webkit-tap-highlight-color: transparent;\n }\n }\n\n // Tab label\n > label {\n z-index: 1;\n width: auto;\n padding: px2em(12px, 12.8px) 1.25em px2em(10px, 12.8px);\n color: var(--md-default-fg-color--light);\n font-weight: 700;\n font-size: px2rem(12.8px);\n border-bottom: px2rem(2px) solid transparent;\n cursor: pointer;\n transition: color 250ms;\n\n // Tab label on hover\n &:hover {\n color: var(--md-accent-fg-color);\n }\n }\n }\n}\n\n// ----------------------------------------------------------------------------\n// Placeholders: improve colocation for better compression\n// ----------------------------------------------------------------------------\n\n// Tab label placeholder\n%tabbed-label {\n\n // [screen]: Show active state\n @media screen {\n color: var(--md-accent-fg-color);\n border-color: var(--md-accent-fg-color);\n }\n}\n\n// Tab label on keyboard focus placeholder\n%tabbed-label-focus-visible {\n background-color: var(--md-accent-fg-color--transparent);\n}\n\n// Tab content placeholder\n%tabbed-content {\n display: block;\n}\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset { // stylelint-disable-line\n\n // Tabbed labels\n .tabbed-labels {\n display: flex;\n max-width: 100%;\n overflow: auto;\n box-shadow: 0 px2rem(-1px) var(--md-default-fg-color--lightest) inset;\n scroll-snap-type: x proximity;\n -ms-overflow-style: none; // IE, Edge\n scrollbar-width: none; // Firefox\n\n // [print]: Move one layer up for ordering\n @media print {\n display: contents;\n }\n\n // Webkit scrollbar\n &::-webkit-scrollbar {\n display: none; // Chrome, Safari\n }\n\n // Tab label\n > label {\n z-index: 1;\n flex-shrink: 0;\n width: auto;\n padding: px2em(10px, 12.8px) 1.25em px2em(8px, 12.8px);\n color: var(--md-default-fg-color--light);\n font-weight: 700;\n font-size: px2rem(12.8px);\n white-space: nowrap;\n border-bottom: px2rem(2px) solid transparent;\n scroll-snap-align: start;\n border-top-left-radius: px2rem(2px);\n border-top-right-radius: px2rem(2px);\n cursor: pointer;\n transition:\n background-color 250ms,\n color 250ms;\n\n // [print]: Intersperse labels with containers\n @media print {\n\n // Ensure correct order of labels\n @for $i from 1 through 20 {\n &:nth-child(#{$i}) {\n order: $i;\n }\n }\n }\n\n // Tab label on hover\n &:hover {\n color: var(--md-accent-fg-color);\n }\n }\n }\n\n // [mobile -]: Align with body copy\n @include break-to-device(mobile) {\n\n // Top-level tabbed labels\n > .tabbed-alternate .tabbed-labels {\n max-width: 100vw;\n margin: 0 px2rem(-16px);\n padding-left: px2rem(16px);\n scroll-padding-left: px2rem(16px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: px2rem(16px);\n padding-left: initial;\n scroll-padding-right: px2rem(16px);\n scroll-padding-left: initial;\n }\n\n // Hack: some browsers ignore the right padding on flex containers,\n // see https://bit.ly/3lsPS3S\n &::after {\n padding-right: px2rem(16px);\n content: \"\";\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n padding-right: initial;\n padding-left: px2rem(16px);\n }\n }\n }\n }\n\n // Tabbed container\n .tabbed-alternate {\n flex-direction: column;\n\n // Tabbed content\n .tabbed-content {\n display: initial;\n order: initial;\n width: 100%;\n box-shadow: initial;\n\n // [print]: Move one layer up for ordering\n @media print {\n display: contents;\n }\n }\n\n // Tabbed block\n .tabbed-block {\n display: none;\n\n // [print]: Intersperse labels with containers\n @media print {\n display: block;\n\n // Ensure correct order of containers\n @for $i from 1 through 20 {\n &:nth-child(#{$i}) {\n order: $i;\n }\n }\n }\n\n // Code block is the only child of a tab - remove margin and mirror\n // previous (now deprecated) SuperFences code block grouping behavior\n > pre:only-child,\n > .highlight:only-child pre,\n > .highlighttable:only-child {\n margin: 0;\n\n // Omit rounded borders\n > code {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n }\n }\n\n // Adjust spacing for nested tabbed container\n > .tabbed-set {\n margin: 0;\n }\n }\n\n // Tab label states\n @for $i from 20 through 1 {\n input:nth-child(#{$i}) {\n\n // Tab is active\n &:checked {\n\n // Tab label\n ~ .tabbed-labels > :nth-child(#{$i}) {\n @extend %tabbed-label;\n }\n\n // Tab content\n ~ .tabbed-content > :nth-child(#{$i}) {\n @extend %tabbed-content;\n }\n }\n\n // Tab label on keyboard focus\n &.focus-visible ~ .tabbed-labels > :nth-child(#{$i}) {\n @extend %tabbed-label-focus-visible;\n }\n }\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Icon definitions\n:root {\n --md-tasklist-icon:\n svg-load(\"octicons/check-circle-fill-24.svg\");\n --md-tasklist-icon--checked:\n svg-load(\"octicons/check-circle-fill-24.svg\");\n}\n\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // Tasklist item\n .task-list-item {\n position: relative;\n list-style-type: none;\n\n // Make checkbox items align with normal list items, but position\n // everything in ems for correct layout at smaller font sizes\n [type=\"checkbox\"] {\n position: absolute;\n top: 0.45em;\n left: -2em;\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: -2em;\n left: initial;\n }\n }\n }\n\n // Hide native checkbox, when custom classes are enabled\n .task-list-control [type=\"checkbox\"] {\n z-index: -1;\n opacity: 0;\n }\n\n // Tasklist indicator in unchecked state\n .task-list-indicator::before {\n position: absolute;\n top: 0.15em;\n left: px2em(-24px);\n width: px2em(20px);\n height: px2em(20px);\n background-color: var(--md-default-fg-color--lightest);\n mask-image: var(--md-tasklist-icon);\n mask-repeat: no-repeat;\n mask-size: contain;\n content: \"\";\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n right: px2em(-24px);\n left: initial;\n }\n }\n\n // Tasklist indicator in checked state\n [type=\"checkbox\"]:checked + .task-list-indicator::before {\n background-color: $clr-green-a400;\n mask-image: var(--md-tasklist-icon--checked);\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Scoped in typesetted content to match specificity of regular content\n.md-typeset {\n\n // [tablet +]: Allow for rendering content as sidebars\n @include break-from-device(tablet) {\n\n // Modifier to float block elements\n .inline {\n float: left;\n width: px2rem(234px);\n margin-top: 0;\n margin-right: px2rem(16px);\n margin-bottom: px2rem(16px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: right;\n margin-right: 0;\n margin-left: px2rem(16px);\n }\n\n // Modifier to move to end (ltr: right, rtl: left)\n &.end {\n float: right;\n margin-right: 0;\n margin-left: px2rem(16px);\n\n // Adjust for right-to-left languages\n [dir=\"rtl\"] & {\n float: left;\n margin-right: px2rem(16px);\n margin-left: 0;\n }\n }\n }\n }\n}\n"]} \ No newline at end of file diff --git a/assets/stylesheets/palette.3f5d1f46.min.css b/assets/stylesheets/palette.3f5d1f46.min.css new file mode 100644 index 00000000..8fdf1b26 --- /dev/null +++ b/assets/stylesheets/palette.3f5d1f46.min.css @@ -0,0 +1,2 @@ +[data-md-color-accent=red]{--md-accent-fg-color:#ff1947;--md-accent-fg-color--transparent:rgba(255,25,71,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=pink]{--md-accent-fg-color:#f50056;--md-accent-fg-color--transparent:rgba(245,0,86,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=purple]{--md-accent-fg-color:#df41fb;--md-accent-fg-color--transparent:rgba(223,65,251,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=deep-purple]{--md-accent-fg-color:#7c4dff;--md-accent-fg-color--transparent:rgba(124,77,255,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=indigo]{--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=blue]{--md-accent-fg-color:#4287ff;--md-accent-fg-color--transparent:rgba(66,135,255,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=light-blue]{--md-accent-fg-color:#0091eb;--md-accent-fg-color--transparent:rgba(0,145,235,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=cyan]{--md-accent-fg-color:#00bad6;--md-accent-fg-color--transparent:rgba(0,186,214,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=teal]{--md-accent-fg-color:#00bda4;--md-accent-fg-color--transparent:rgba(0,189,164,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=green]{--md-accent-fg-color:#00c753;--md-accent-fg-color--transparent:rgba(0,199,83,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=light-green]{--md-accent-fg-color:#63de17;--md-accent-fg-color--transparent:rgba(99,222,23,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-accent=lime]{--md-accent-fg-color:#b0eb00;--md-accent-fg-color--transparent:rgba(176,235,0,0.1);--md-accent-bg-color:rgba(0,0,0,0.87);--md-accent-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-accent=yellow]{--md-accent-fg-color:#ffd500;--md-accent-fg-color--transparent:rgba(255,213,0,0.1);--md-accent-bg-color:rgba(0,0,0,0.87);--md-accent-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-accent=amber]{--md-accent-fg-color:#fa0;--md-accent-fg-color--transparent:rgba(255,170,0,0.1);--md-accent-bg-color:rgba(0,0,0,0.87);--md-accent-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-accent=orange]{--md-accent-fg-color:#ff9100;--md-accent-fg-color--transparent:rgba(255,145,0,0.1);--md-accent-bg-color:rgba(0,0,0,0.87);--md-accent-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-accent=deep-orange]{--md-accent-fg-color:#ff6e42;--md-accent-fg-color--transparent:rgba(255,110,66,0.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=red]{--md-primary-fg-color:#ef5552;--md-primary-fg-color--light:#e57171;--md-primary-fg-color--dark:#e53734;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=pink]{--md-primary-fg-color:#e92063;--md-primary-fg-color--light:#ec417a;--md-primary-fg-color--dark:#c3185d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=purple]{--md-primary-fg-color:#ab47bd;--md-primary-fg-color--light:#bb69c9;--md-primary-fg-color--dark:#8c24a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=deep-purple]{--md-primary-fg-color:#7e56c2;--md-primary-fg-color--light:#9574cd;--md-primary-fg-color--dark:#673ab6;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=indigo]{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=blue]{--md-primary-fg-color:#2094f3;--md-primary-fg-color--light:#42a5f5;--md-primary-fg-color--dark:#1975d2;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=light-blue]{--md-primary-fg-color:#02a6f2;--md-primary-fg-color--light:#28b5f6;--md-primary-fg-color--dark:#0287cf;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=cyan]{--md-primary-fg-color:#00bdd6;--md-primary-fg-color--light:#25c5da;--md-primary-fg-color--dark:#0097a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=teal]{--md-primary-fg-color:#009485;--md-primary-fg-color--light:#26a699;--md-primary-fg-color--dark:#007a6c;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=green]{--md-primary-fg-color:#4cae4f;--md-primary-fg-color--light:#68bb6c;--md-primary-fg-color--dark:#398e3d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=light-green]{--md-primary-fg-color:#8bc34b;--md-primary-fg-color--light:#9ccc66;--md-primary-fg-color--dark:#689f38;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=lime]{--md-primary-fg-color:#cbdc38;--md-primary-fg-color--light:#d3e156;--md-primary-fg-color--dark:#b0b52c;--md-primary-bg-color:rgba(0,0,0,0.87);--md-primary-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-primary=yellow]{--md-primary-fg-color:#ffec3d;--md-primary-fg-color--light:#ffee57;--md-primary-fg-color--dark:#fbc02d;--md-primary-bg-color:rgba(0,0,0,0.87);--md-primary-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-primary=amber]{--md-primary-fg-color:#ffc105;--md-primary-fg-color--light:#ffc929;--md-primary-fg-color--dark:#ffa200;--md-primary-bg-color:rgba(0,0,0,0.87);--md-primary-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-primary=orange]{--md-primary-fg-color:#ffa724;--md-primary-fg-color--light:#ffa724;--md-primary-fg-color--dark:#fa8900;--md-primary-bg-color:rgba(0,0,0,0.87);--md-primary-bg-color--light:rgba(0,0,0,0.54)}[data-md-color-primary=deep-orange]{--md-primary-fg-color:#ff6e42;--md-primary-fg-color--light:#ff8a66;--md-primary-fg-color--dark:#f4511f;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=brown]{--md-primary-fg-color:#795649;--md-primary-fg-color--light:#8d6e62;--md-primary-fg-color--dark:#5d4037;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=grey]{--md-primary-fg-color:#757575;--md-primary-fg-color--light:#9e9e9e;--md-primary-fg-color--dark:#616161;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=blue-grey]{--md-primary-fg-color:#546d78;--md-primary-fg-color--light:#607c8a;--md-primary-fg-color--dark:#455a63;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7)}[data-md-color-primary=white]{--md-primary-fg-color:#fff;--md-primary-fg-color--light:hsla(0,0%,100%,0.7);--md-primary-fg-color--dark:rgba(0,0,0,0.07);--md-primary-bg-color:rgba(0,0,0,0.87);--md-primary-bg-color--light:rgba(0,0,0,0.54);--md-typeset-a-color:#4051b5}@media screen and (min-width:60em){[data-md-color-primary=white] .md-search__form{background-color:rgba(0,0,0,.07)}[data-md-color-primary=white] .md-search__form:hover{background-color:rgba(0,0,0,.32)}[data-md-color-primary=white] .md-search__input+.md-search__icon{color:rgba(0,0,0,.87)}}@media screen and (min-width:76.25em){[data-md-color-primary=white] .md-tabs{border-bottom:.05rem solid rgba(0,0,0,.07)}}[data-md-color-primary=black]{--md-primary-fg-color:#000;--md-primary-fg-color--light:rgba(0,0,0,0.54);--md-primary-fg-color--dark:#000;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,0.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=black] .md-header{background-color:#000}@media screen and (max-width:59.9375em){[data-md-color-primary=black] .md-nav__source{background-color:rgba(0,0,0,.87)}}@media screen and (min-width:60em){[data-md-color-primary=black] .md-search__form{background-color:hsla(0,0%,100%,.12)}[data-md-color-primary=black] .md-search__form:hover{background-color:hsla(0,0%,100%,.3)}}@media screen and (max-width:76.1875em){html [data-md-color-primary=black] .md-nav--primary .md-nav__title[for=__drawer]{background-color:#000}}@media screen and (min-width:76.25em){[data-md-color-primary=black] .md-tabs{background-color:#000}}@media screen{[data-md-color-scheme=slate]{--md-hue:232;--md-default-fg-color:hsla(var(--md-hue),75%,95%,1);--md-default-fg-color--light:hsla(var(--md-hue),75%,90%,0.62);--md-default-fg-color--lighter:hsla(var(--md-hue),75%,90%,0.32);--md-default-fg-color--lightest:hsla(var(--md-hue),75%,90%,0.12);--md-default-bg-color:hsla(var(--md-hue),15%,21%,1);--md-default-bg-color--light:hsla(var(--md-hue),15%,21%,0.54);--md-default-bg-color--lighter:hsla(var(--md-hue),15%,21%,0.26);--md-default-bg-color--lightest:hsla(var(--md-hue),15%,21%,0.07);--md-code-fg-color:hsla(var(--md-hue),18%,86%,1);--md-code-bg-color:hsla(var(--md-hue),15%,15%,1);--md-code-hl-color:rgba(66,135,255,0.15);--md-code-hl-number-color:#e6695b;--md-code-hl-special-color:#f06090;--md-code-hl-function-color:#c973d9;--md-code-hl-constant-color:#9383e2;--md-code-hl-keyword-color:#6791e0;--md-code-hl-string-color:#2fb170;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-mark-color:rgba(66,135,255,0.3);--md-typeset-kbd-color:hsla(var(--md-hue),15%,94%,0.12);--md-typeset-kbd-accent-color:hsla(var(--md-hue),15%,94%,0.2);--md-typeset-kbd-border-color:hsla(var(--md-hue),15%,14%,1);--md-typeset-table-color:hsla(var(--md-hue),75%,95%,0.12);--md-admonition-bg-color:hsla(var(--md-hue),0%,100%,0.025);--md-footer-bg-color:hsla(var(--md-hue),15%,12%,0.87);--md-footer-bg-color--dark:hsla(var(--md-hue),15%,10%,1)}[data-md-color-scheme=slate][data-md-color-primary=black],[data-md-color-scheme=slate][data-md-color-primary=white]{--md-typeset-a-color:#5d6cc0}} +/*# sourceMappingURL=palette.3f5d1f46.min.css.map */ \ No newline at end of file diff --git a/assets/stylesheets/palette.3f5d1f46.min.css.map b/assets/stylesheets/palette.3f5d1f46.min.css.map new file mode 100644 index 00000000..c152d96e --- /dev/null +++ b/assets/stylesheets/palette.3f5d1f46.min.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["src/assets/stylesheets/palette/_accent.scss","src/assets/stylesheets/palette.scss","src/assets/stylesheets/palette/_primary.scss","src/assets/stylesheets/utilities/_break.scss","src/assets/stylesheets/palette/_scheme.scss"],"names":[],"mappings":"AA8CE,2BACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,+CCnDN,CDyCE,4BACE,4BAAA,CACA,oDAAA,CAOE,yBAAA,CACA,+CC5CN,CDkCE,8BACE,4BAAA,CACA,sDAAA,CAOE,yBAAA,CACA,+CCrCN,CD2BE,mCACE,4BAAA,CACA,sDAAA,CAOE,yBAAA,CACA,+CC9BN,CDoBE,8BACE,4BAAA,CACA,sDAAA,CAOE,yBAAA,CACA,+CCvBN,CDaE,4BACE,4BAAA,CACA,sDAAA,CAOE,yBAAA,CACA,+CChBN,CDME,kCACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,+CCTN,CDDE,4BACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,+CCFN,CDRE,4BACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,+CCKN,CDfE,6BACE,4BAAA,CACA,oDAAA,CAOE,yBAAA,CACA,+CCYN,CDtBE,mCACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,+CCmBN,CD7BE,4BACE,4BAAA,CACA,qDAAA,CAIE,qCAAA,CACA,4CC6BN,CDpCE,8BACE,4BAAA,CACA,qDAAA,CAIE,qCAAA,CACA,4CCoCN,CD3CE,6BACE,yBAAA,CACA,qDAAA,CAIE,qCAAA,CACA,4CC2CN,CDlDE,8BACE,4BAAA,CACA,qDAAA,CAIE,qCAAA,CACA,4CCkDN,CDzDE,mCACE,4BAAA,CACA,sDAAA,CAOE,yBAAA,CACA,+CCsDN,CC3DE,4BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDwDN,CCnEE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDgEN,CC3EE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDwEN,CCnFE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDgFN,CC3FE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDwFN,CCnGE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDgGN,CC3GE,mCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDwGN,CCnHE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDgHN,CC3HE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDwHN,CCnIE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDgIN,CC3IE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDwIN,CCnJE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,sCAAA,CACA,6CDmJN,CC3JE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,sCAAA,CACA,6CD2JN,CCnKE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,sCAAA,CACA,6CDmKN,CC3KE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,sCAAA,CACA,6CD2KN,CCnLE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDgLN,CC3LE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDwLN,CCnME,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDgMN,CC3ME,kCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,gDDwMN,CC9LA,8BACE,0BAAA,CACA,gDAAA,CACA,4CAAA,CACA,sCAAA,CACA,6CAAA,CAGA,4BD+LF,CE9EI,mCD3GA,+CACE,gCD4LJ,CCzLI,qDACE,gCD2LN,CCtLE,iEACE,qBDwLJ,CACF,CEzFI,sCDxFA,uCACE,0CDoLJ,CACF,CC3KA,8BACE,0BAAA,CACA,6CAAA,CACA,gCAAA,CACA,0BAAA,CACA,gDAAA,CAGA,4BD4KF,CCzKE,yCACE,qBD2KJ,CEvFI,wCD7EA,8CACE,gCDuKJ,CACF,CE/GI,mCDjDA,+CACE,oCDmKJ,CChKI,qDACE,mCDkKN,CACF,CEpGI,wCDtDA,iFACE,qBD6JJ,CACF,CE5HI,sCD1BA,uCACE,qBDyJJ,CACF,CGvSA,cAGE,6BAKE,YAAA,CAGA,mDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CACA,mDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CAGA,gDAAA,CACA,gDAAA,CAGA,wCAAA,CACA,iCAAA,CACA,kCAAA,CACA,mCAAA,CACA,mCAAA,CACA,kCAAA,CACA,iCAAA,CACA,+CAAA,CACA,6DAAA,CACA,gEAAA,CACA,4DAAA,CACA,4DAAA,CACA,6DAAA,CAGA,6CAAA,CAGA,+CAAA,CAGA,4CAAA,CAGA,uDAAA,CACA,6DAAA,CACA,2DAAA,CAGA,yDAAA,CAGA,0DAAA,CAGA,qDAAA,CACA,wDHgRF,CG7QE,oHAIE,4BH4QJ,CACF","file":"src/assets/stylesheets/palette.scss","sourcesContent":["////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n@each $name, $color in (\n \"red\": $clr-red-a400,\n \"pink\": $clr-pink-a400,\n \"purple\": $clr-purple-a200,\n \"deep-purple\": $clr-deep-purple-a200,\n \"indigo\": $clr-indigo-a200,\n \"blue\": $clr-blue-a200,\n \"light-blue\": $clr-light-blue-a700,\n \"cyan\": $clr-cyan-a700,\n \"teal\": $clr-teal-a700,\n \"green\": $clr-green-a700,\n \"light-green\": $clr-light-green-a700,\n \"lime\": $clr-lime-a700,\n \"yellow\": $clr-yellow-a700,\n \"amber\": $clr-amber-a700,\n \"orange\": $clr-orange-a400,\n \"deep-orange\": $clr-deep-orange-a200\n) {\n\n // Color palette\n [data-md-color-accent=\"#{$name}\"] {\n --md-accent-fg-color: hsla(#{hex2hsl($color)}, 1);\n --md-accent-fg-color--transparent: hsla(#{hex2hsl($color)}, 0.1);\n\n // Inverted text for lighter shades\n @if index(\"lime\" \"yellow\" \"amber\" \"orange\", $name) {\n --md-accent-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-accent-bg-color--light: hsla(0, 0%, 0%, 0.54);\n } @else {\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n }\n }\n}\n","[data-md-color-accent=red] {\n --md-accent-fg-color: hsla(348, 100%, 55%, 1);\n --md-accent-fg-color--transparent: hsla(348, 100%, 55%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=pink] {\n --md-accent-fg-color: hsla(339, 100%, 48%, 1);\n --md-accent-fg-color--transparent: hsla(339, 100%, 48%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=purple] {\n --md-accent-fg-color: hsla(291, 96%, 62%, 1);\n --md-accent-fg-color--transparent: hsla(291, 96%, 62%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=deep-purple] {\n --md-accent-fg-color: hsla(256, 100%, 65%, 1);\n --md-accent-fg-color--transparent: hsla(256, 100%, 65%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=indigo] {\n --md-accent-fg-color: hsla(231, 99%, 66%, 1);\n --md-accent-fg-color--transparent: hsla(231, 99%, 66%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=blue] {\n --md-accent-fg-color: hsla(218, 100%, 63%, 1);\n --md-accent-fg-color--transparent: hsla(218, 100%, 63%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=light-blue] {\n --md-accent-fg-color: hsla(203, 100%, 46%, 1);\n --md-accent-fg-color--transparent: hsla(203, 100%, 46%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=cyan] {\n --md-accent-fg-color: hsla(188, 100%, 42%, 1);\n --md-accent-fg-color--transparent: hsla(188, 100%, 42%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=teal] {\n --md-accent-fg-color: hsla(172, 100%, 37%, 1);\n --md-accent-fg-color--transparent: hsla(172, 100%, 37%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=green] {\n --md-accent-fg-color: hsla(145, 100%, 39%, 1);\n --md-accent-fg-color--transparent: hsla(145, 100%, 39%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=light-green] {\n --md-accent-fg-color: hsla(97, 81%, 48%, 1);\n --md-accent-fg-color--transparent: hsla(97, 81%, 48%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-accent=lime] {\n --md-accent-fg-color: hsla(75, 100%, 46%, 1);\n --md-accent-fg-color--transparent: hsla(75, 100%, 46%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-accent-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-accent=yellow] {\n --md-accent-fg-color: hsla(50, 100%, 50%, 1);\n --md-accent-fg-color--transparent: hsla(50, 100%, 50%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-accent-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-accent=amber] {\n --md-accent-fg-color: hsla(40, 100%, 50%, 1);\n --md-accent-fg-color--transparent: hsla(40, 100%, 50%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-accent-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-accent=orange] {\n --md-accent-fg-color: hsla(34, 100%, 50%, 1);\n --md-accent-fg-color--transparent: hsla(34, 100%, 50%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-accent-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-accent=deep-orange] {\n --md-accent-fg-color: hsla(14, 100%, 63%, 1);\n --md-accent-fg-color--transparent: hsla(14, 100%, 63%, 0.1);\n --md-accent-bg-color: hsla(0, 0%, 100%, 1);\n --md-accent-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=red] {\n --md-primary-fg-color: hsl(1, 83%, 63%);\n --md-primary-fg-color--light: hsl(0, 69%, 67%);\n --md-primary-fg-color--dark: hsl(1, 77%, 55%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=pink] {\n --md-primary-fg-color: hsl(340, 82%, 52%);\n --md-primary-fg-color--light: hsl(340, 82%, 59%);\n --md-primary-fg-color--dark: hsl(336, 78%, 43%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=purple] {\n --md-primary-fg-color: hsl(291, 47%, 51%);\n --md-primary-fg-color--light: hsl(291, 47%, 60%);\n --md-primary-fg-color--dark: hsl(287, 65%, 40%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=deep-purple] {\n --md-primary-fg-color: hsl(262, 47%, 55%);\n --md-primary-fg-color--light: hsl(262, 47%, 63%);\n --md-primary-fg-color--dark: hsl(262, 52%, 47%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=indigo] {\n --md-primary-fg-color: hsl(231, 48%, 48%);\n --md-primary-fg-color--light: hsl(231, 44%, 56%);\n --md-primary-fg-color--dark: hsl(232, 54%, 41%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=blue] {\n --md-primary-fg-color: hsl(207, 90%, 54%);\n --md-primary-fg-color--light: hsl(207, 90%, 61%);\n --md-primary-fg-color--dark: hsl(210, 79%, 46%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=light-blue] {\n --md-primary-fg-color: hsl(199, 98%, 48%);\n --md-primary-fg-color--light: hsl(199, 92%, 56%);\n --md-primary-fg-color--dark: hsl(201, 98%, 41%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=cyan] {\n --md-primary-fg-color: hsl(187, 100%, 42%);\n --md-primary-fg-color--light: hsl(187, 71%, 50%);\n --md-primary-fg-color--dark: hsl(186, 100%, 33%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=teal] {\n --md-primary-fg-color: hsl(174, 100%, 29%);\n --md-primary-fg-color--light: hsl(174, 63%, 40%);\n --md-primary-fg-color--dark: hsl(173, 100%, 24%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=green] {\n --md-primary-fg-color: hsl(122, 39%, 49%);\n --md-primary-fg-color--light: hsl(123, 38%, 57%);\n --md-primary-fg-color--dark: hsl(123, 43%, 39%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=light-green] {\n --md-primary-fg-color: hsl(88, 50%, 53%);\n --md-primary-fg-color--light: hsl(88, 50%, 60%);\n --md-primary-fg-color--dark: hsl(92, 48%, 42%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=lime] {\n --md-primary-fg-color: hsl(66, 70%, 54%);\n --md-primary-fg-color--light: hsl(66, 70%, 61%);\n --md-primary-fg-color--dark: hsl(62, 61%, 44%);\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-primary=yellow] {\n --md-primary-fg-color: hsl(54, 100%, 62%);\n --md-primary-fg-color--light: hsl(54, 100%, 67%);\n --md-primary-fg-color--dark: hsl(43, 96%, 58%);\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-primary=amber] {\n --md-primary-fg-color: hsl(45, 100%, 51%);\n --md-primary-fg-color--light: hsl(45, 100%, 58%);\n --md-primary-fg-color--dark: hsl(38, 100%, 50%);\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-primary=orange] {\n --md-primary-fg-color: hsl(36, 100%, 57%);\n --md-primary-fg-color--light: hsl(36, 100%, 57%);\n --md-primary-fg-color--dark: hsl(33, 100%, 49%);\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n}\n\n[data-md-color-primary=deep-orange] {\n --md-primary-fg-color: hsl(14, 100%, 63%);\n --md-primary-fg-color--light: hsl(14, 100%, 70%);\n --md-primary-fg-color--dark: hsl(14, 91%, 54%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=brown] {\n --md-primary-fg-color: hsl(16, 25%, 38%);\n --md-primary-fg-color--light: hsl(16, 18%, 47%);\n --md-primary-fg-color--dark: hsl(14, 26%, 29%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=grey] {\n --md-primary-fg-color: hsl(0, 0%, 46%);\n --md-primary-fg-color--light: hsl(0, 0%, 62%);\n --md-primary-fg-color--dark: hsl(0, 0%, 38%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=blue-grey] {\n --md-primary-fg-color: hsl(199, 18%, 40%);\n --md-primary-fg-color--light: hsl(200, 18%, 46%);\n --md-primary-fg-color--dark: hsl(199, 18%, 33%);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n}\n\n[data-md-color-primary=white] {\n --md-primary-fg-color: hsla(0, 0%, 100%, 1);\n --md-primary-fg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-primary-fg-color--dark: hsla(0, 0%, 0%, 0.07);\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n --md-typeset-a-color: hsla(231, 48%, 48%, 1);\n}\n@media screen and (min-width: 60em) {\n [data-md-color-primary=white] .md-search__form {\n background-color: rgba(0, 0, 0, 0.07);\n }\n [data-md-color-primary=white] .md-search__form:hover {\n background-color: rgba(0, 0, 0, 0.32);\n }\n [data-md-color-primary=white] .md-search__input + .md-search__icon {\n color: rgba(0, 0, 0, 0.87);\n }\n}\n@media screen and (min-width: 76.25em) {\n [data-md-color-primary=white] .md-tabs {\n border-bottom: 0.05rem solid rgba(0, 0, 0, 0.07);\n }\n}\n\n[data-md-color-primary=black] {\n --md-primary-fg-color: hsla(0, 0%, 0%, 1);\n --md-primary-fg-color--light: hsla(0, 0%, 0%, 0.54);\n --md-primary-fg-color--dark: hsla(0, 0%, 0%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-typeset-a-color: hsla(231, 48%, 48%, 1);\n}\n[data-md-color-primary=black] .md-header {\n background-color: black;\n}\n@media screen and (max-width: 59.9375em) {\n [data-md-color-primary=black] .md-nav__source {\n background-color: rgba(0, 0, 0, 0.87);\n }\n}\n@media screen and (min-width: 60em) {\n [data-md-color-primary=black] .md-search__form {\n background-color: rgba(255, 255, 255, 0.12);\n }\n [data-md-color-primary=black] .md-search__form:hover {\n background-color: rgba(255, 255, 255, 0.3);\n }\n}\n@media screen and (max-width: 76.1875em) {\n html [data-md-color-primary=black] .md-nav--primary .md-nav__title[for=__drawer] {\n background-color: black;\n }\n}\n@media screen and (min-width: 76.25em) {\n [data-md-color-primary=black] .md-tabs {\n background-color: black;\n }\n}\n\n@media screen {\n [data-md-color-scheme=slate] {\n --md-hue: 232;\n --md-default-fg-color: hsla(var(--md-hue), 75%, 95%, 1);\n --md-default-fg-color--light: hsla(var(--md-hue), 75%, 90%, 0.62);\n --md-default-fg-color--lighter: hsla(var(--md-hue), 75%, 90%, 0.32);\n --md-default-fg-color--lightest: hsla(var(--md-hue), 75%, 90%, 0.12);\n --md-default-bg-color: hsla(var(--md-hue), 15%, 21%, 1);\n --md-default-bg-color--light: hsla(var(--md-hue), 15%, 21%, 0.54);\n --md-default-bg-color--lighter: hsla(var(--md-hue), 15%, 21%, 0.26);\n --md-default-bg-color--lightest: hsla(var(--md-hue), 15%, 21%, 0.07);\n --md-code-fg-color: hsla(var(--md-hue), 18%, 86%, 1);\n --md-code-bg-color: hsla(var(--md-hue), 15%, 15%, 1);\n --md-code-hl-color: hsla(218, 100%, 63%, 0.15);\n --md-code-hl-number-color: hsla(6, 74%, 63%, 1);\n --md-code-hl-special-color: hsla(340, 83%, 66%, 1);\n --md-code-hl-function-color: hsla(291, 57%, 65%, 1);\n --md-code-hl-constant-color: hsla(250, 62%, 70%, 1);\n --md-code-hl-keyword-color: hsla(219, 66%, 64%, 1);\n --md-code-hl-string-color: hsla(150, 58%, 44%, 1);\n --md-code-hl-name-color: var(--md-code-fg-color);\n --md-code-hl-operator-color: var(--md-default-fg-color--light);\n --md-code-hl-punctuation-color: var(--md-default-fg-color--light);\n --md-code-hl-comment-color: var(--md-default-fg-color--light);\n --md-code-hl-generic-color: var(--md-default-fg-color--light);\n --md-code-hl-variable-color: var(--md-default-fg-color--light);\n --md-typeset-color: var(--md-default-fg-color);\n --md-typeset-a-color: var(--md-primary-fg-color);\n --md-typeset-mark-color: hsla(218, 100%, 63%, 0.3);\n --md-typeset-kbd-color: hsla(var(--md-hue), 15%, 94%, 0.12);\n --md-typeset-kbd-accent-color: hsla(var(--md-hue), 15%, 94%, 0.2);\n --md-typeset-kbd-border-color: hsla(var(--md-hue), 15%, 14%, 1);\n --md-typeset-table-color: hsla(var(--md-hue), 75%, 95%, 0.12);\n --md-admonition-bg-color: hsla(var(--md-hue), 0%, 100%, 0.025);\n --md-footer-bg-color: hsla(var(--md-hue), 15%, 12%, 0.87);\n --md-footer-bg-color--dark: hsla(var(--md-hue), 15%, 10%, 1);\n }\n [data-md-color-scheme=slate][data-md-color-primary=black], [data-md-color-scheme=slate][data-md-color-primary=white] {\n --md-typeset-a-color: hsla(231, 44%, 56%, 1);\n }\n}\n\n/*# sourceMappingURL=palette.css.map */","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n@use \"sass:list\";\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n@each $name, $colors in (\n \"red\": $clr-red-400 $clr-red-300 $clr-red-600,\n \"pink\": $clr-pink-500 $clr-pink-400 $clr-pink-700,\n \"purple\": $clr-purple-400 $clr-purple-300 $clr-purple-600,\n \"deep-purple\": $clr-deep-purple-400 $clr-deep-purple-300 $clr-deep-purple-500,\n \"indigo\": $clr-indigo-500 $clr-indigo-400 $clr-indigo-700,\n \"blue\": $clr-blue-500 $clr-blue-400 $clr-blue-700,\n \"light-blue\": $clr-light-blue-500 $clr-light-blue-400 $clr-light-blue-700,\n \"cyan\": $clr-cyan-500 $clr-cyan-400 $clr-cyan-700,\n \"teal\": $clr-teal-500 $clr-teal-400 $clr-teal-700,\n \"green\": $clr-green-500 $clr-green-400 $clr-green-700,\n \"light-green\": $clr-light-green-500 $clr-light-green-400 $clr-light-green-700,\n \"lime\": $clr-lime-500 $clr-lime-400 $clr-lime-700,\n \"yellow\": $clr-yellow-500 $clr-yellow-400 $clr-yellow-700,\n \"amber\": $clr-amber-500 $clr-amber-400 $clr-amber-700,\n \"orange\": $clr-orange-400 $clr-orange-400 $clr-orange-600,\n \"deep-orange\": $clr-deep-orange-400 $clr-deep-orange-300 $clr-deep-orange-600,\n \"brown\": $clr-brown-500 $clr-brown-400 $clr-brown-700,\n \"grey\": $clr-grey-600 $clr-grey-500 $clr-grey-700,\n \"blue-grey\": $clr-blue-grey-600 $clr-blue-grey-500 $clr-blue-grey-700\n) {\n\n // Color palette\n [data-md-color-primary=\"#{$name}\"] {\n --md-primary-fg-color: hsl(#{hex2hsl(list.nth($colors, 1))});\n --md-primary-fg-color--light: hsl(#{hex2hsl(list.nth($colors, 2))});\n --md-primary-fg-color--dark: hsl(#{hex2hsl(list.nth($colors, 3))});\n\n // Inverted text for lighter shades\n @if index(\"lime\" \"yellow\" \"amber\" \"orange\", $name) {\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n } @else {\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n }\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules: white\n// ----------------------------------------------------------------------------\n\n// Color palette\n[data-md-color-primary=\"white\"] {\n --md-primary-fg-color: hsla(0, 0%, 100%, 1);\n --md-primary-fg-color--light: hsla(0, 0%, 100%, 0.7);\n --md-primary-fg-color--dark: hsla(0, 0%, 0%, 0.07);\n --md-primary-bg-color: hsla(0, 0%, 0%, 0.87);\n --md-primary-bg-color--light: hsla(0, 0%, 0%, 0.54);\n\n // Typeset color shades\n --md-typeset-a-color: hsla(#{hex2hsl($clr-indigo-500)}, 1);\n\n // [tablet portrait +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n\n // Search form\n .md-search__form {\n background-color: hsla(0, 0%, 0%, 0.07);\n\n // Search form on hover\n &:hover {\n background-color: hsla(0, 0%, 0%, 0.32);\n }\n }\n\n // Search icon\n .md-search__input + .md-search__icon {\n color: hsla(0, 0%, 0%, 0.87);\n }\n }\n\n // [screen +]: Add bottom border for tabs\n @include break-from-device(screen) {\n\n // Navigation tabs\n .md-tabs {\n border-bottom: px2rem(1px) solid hsla(0, 0%, 0%, 0.07);\n }\n }\n}\n\n// ----------------------------------------------------------------------------\n// Rules: black\n// ----------------------------------------------------------------------------\n\n// Color palette\n[data-md-color-primary=\"black\"] {\n --md-primary-fg-color: hsla(0, 0%, 0%, 1);\n --md-primary-fg-color--light: hsla(0, 0%, 0%, 0.54);\n --md-primary-fg-color--dark: hsla(0, 0%, 0%, 1);\n --md-primary-bg-color: hsla(0, 0%, 100%, 1);\n --md-primary-bg-color--light: hsla(0, 0%, 100%, 0.7);\n\n // Text color shades\n --md-typeset-a-color: hsla(#{hex2hsl($clr-indigo-500)}, 1);\n\n // Header\n .md-header {\n background-color: hsla(0, 0%, 0%, 1);\n }\n\n // [tablet portrait -]: Layered navigation\n @include break-to-device(tablet portrait) {\n\n // Repository information container\n .md-nav__source {\n background-color: hsla(0, 0%, 0%, 0.87);\n }\n }\n\n // [tablet landscape +]: Header-embedded search\n @include break-from-device(tablet landscape) {\n\n // Search form\n .md-search__form {\n background-color: hsla(0, 0%, 100%, 0.12);\n\n // Search form on hover\n &:hover {\n background-color: hsla(0, 0%, 100%, 0.3);\n }\n }\n }\n\n // [tablet -]: Layered navigation\n @include break-to-device(tablet) {\n\n // Site title in main navigation\n html & .md-nav--primary .md-nav__title[for=\"__drawer\"] {\n background-color: hsla(0, 0%, 0%, 1);\n }\n }\n\n // [screen +]: Set background color for tabs\n @include break-from-device(screen) {\n\n // Navigation tabs\n .md-tabs {\n background-color: hsla(0, 0%, 0%, 1);\n }\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n@use \"sass:list\";\n@use \"sass:map\";\n@use \"sass:math\";\n\n// ----------------------------------------------------------------------------\n// Variables\n// ----------------------------------------------------------------------------\n\n///\n/// Device-specific breakpoints\n///\n/// @example\n/// $break-devices: (\n/// mobile: (\n/// portrait: 220px 479px,\n/// landscape: 480px 719px\n/// ),\n/// tablet: (\n/// portrait: 720px 959px,\n/// landscape: 960px 1219px\n/// ),\n/// screen: (\n/// small: 1220px 1599px,\n/// medium: 1600px 1999px,\n/// large: 2000px\n/// )\n/// );\n///\n$break-devices: () !default;\n\n// ----------------------------------------------------------------------------\n// Helpers\n// ----------------------------------------------------------------------------\n\n///\n/// Choose minimum and maximum device widths\n///\n@function break-select-min-max($devices) {\n $min: 1000000;\n $max: 0;\n @each $key, $value in $devices {\n @while type-of($value) == map {\n $value: break-select-min-max($value);\n }\n @if type-of($value) == list {\n @each $number in $value {\n @if type-of($number) == number {\n $min: math.min($number, $min);\n @if $max {\n $max: math.max($number, $max);\n }\n } @else {\n @error \"Invalid number: #{$number}\";\n }\n }\n } @else if type-of($value) == number {\n $min: math.min($value, $min);\n $max: null;\n } @else {\n @error \"Invalid value: #{$value}\";\n }\n }\n @return $min, $max;\n}\n\n///\n/// Select minimum and maximum widths for a device breakpoint\n///\n@function break-select-device($device) {\n $current: $break-devices;\n @for $n from 1 through length($device) {\n @if type-of($current) == map {\n $current: map.get($current, list.nth($device, $n));\n } @else {\n @error \"Invalid device map: #{$devices}\";\n }\n }\n @if type-of($current) == list or type-of($current) == number {\n $current: (default: $current);\n }\n @return break-select-min-max($current);\n}\n\n// ----------------------------------------------------------------------------\n// Mixins\n// ----------------------------------------------------------------------------\n\n///\n/// A minimum-maximum media query breakpoint\n///\n@mixin break-at($breakpoint) {\n @if type-of($breakpoint) == number {\n @media screen and (min-width: $breakpoint) {\n @content;\n }\n } @else if type-of($breakpoint) == list {\n $min: list.nth($breakpoint, 1);\n $max: list.nth($breakpoint, 2);\n @if type-of($min) == number and type-of($max) == number {\n @media screen and (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n}\n\n///\n/// An orientation media query breakpoint\n///\n@mixin break-at-orientation($breakpoint) {\n @if type-of($breakpoint) == string {\n @media screen and (orientation: $breakpoint) {\n @content;\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n}\n\n///\n/// A maximum-aspect-ratio media query breakpoint\n///\n@mixin break-at-ratio($breakpoint) {\n @if type-of($breakpoint) == number {\n @media screen and (max-aspect-ratio: $breakpoint) {\n @content;\n }\n } @else {\n @error \"Invalid breakpoint: #{$breakpoint}\";\n }\n}\n\n///\n/// A minimum-maximum media query device breakpoint\n///\n@mixin break-at-device($device) {\n @if type-of($device) == string {\n $device: $device,;\n }\n @if type-of($device) == list {\n $breakpoint: break-select-device($device);\n @if list.nth($breakpoint, 2) {\n $min: list.nth($breakpoint, 1);\n $max: list.nth($breakpoint, 2);\n\n @media screen and (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n}\n\n///\n/// A minimum media query device breakpoint\n///\n@mixin break-from-device($device) {\n @if type-of($device) == string {\n $device: $device,;\n }\n @if type-of($device) == list {\n $breakpoint: break-select-device($device);\n $min: list.nth($breakpoint, 1);\n\n @media screen and (min-width: $min) {\n @content;\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n}\n\n///\n/// A maximum media query device breakpoint\n///\n@mixin break-to-device($device) {\n @if type-of($device) == string {\n $device: $device,;\n }\n @if type-of($device) == list {\n $breakpoint: break-select-device($device);\n $max: list.nth($breakpoint, 2);\n\n @media screen and (max-width: $max) {\n @content;\n }\n } @else {\n @error \"Invalid device: #{$device}\";\n }\n}\n","////\n/// Copyright (c) 2016-2021 Martin Donath \n///\n/// Permission is hereby granted, free of charge, to any person obtaining a\n/// copy of this software and associated documentation files (the \"Software\"),\n/// to deal in the Software without restriction, including without limitation\n/// the rights to use, copy, modify, merge, publish, distribute, sublicense,\n/// and/or sell copies of the Software, and to permit persons to whom the\n/// Software is furnished to do so, subject to the following conditions:\n///\n/// The above copyright notice and this permission notice shall be included in\n/// all copies or substantial portions of the Software.\n///\n/// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n/// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL\n/// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n/// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n/// DEALINGS\n////\n\n// ----------------------------------------------------------------------------\n// Rules\n// ----------------------------------------------------------------------------\n\n// Only use dark mode on screens\n@media screen {\n\n // Slate theme, i.e. dark mode\n [data-md-color-scheme=\"slate\"] {\n\n // Slate's hue in the range [0,360] - change this variable to alter the tone\n // of the theme, e.g. to make it more redish or greenish. This is a slate-\n // specific variable, but the same approach may be adapted to custom themes.\n --md-hue: 232;\n\n // Default color shades\n --md-default-fg-color: hsla(var(--md-hue), 75%, 95%, 1);\n --md-default-fg-color--light: hsla(var(--md-hue), 75%, 90%, 0.62);\n --md-default-fg-color--lighter: hsla(var(--md-hue), 75%, 90%, 0.32);\n --md-default-fg-color--lightest: hsla(var(--md-hue), 75%, 90%, 0.12);\n --md-default-bg-color: hsla(var(--md-hue), 15%, 21%, 1);\n --md-default-bg-color--light: hsla(var(--md-hue), 15%, 21%, 0.54);\n --md-default-bg-color--lighter: hsla(var(--md-hue), 15%, 21%, 0.26);\n --md-default-bg-color--lightest: hsla(var(--md-hue), 15%, 21%, 0.07);\n\n // Code color shades\n --md-code-fg-color: hsla(var(--md-hue), 18%, 86%, 1);\n --md-code-bg-color: hsla(var(--md-hue), 15%, 15%, 1);\n\n // Code highlighting color shades\n --md-code-hl-color: hsla(#{hex2hsl($clr-blue-a200)}, 0.15);\n --md-code-hl-number-color: hsla(6, 74%, 63%, 1);\n --md-code-hl-special-color: hsla(340, 83%, 66%, 1);\n --md-code-hl-function-color: hsla(291, 57%, 65%, 1);\n --md-code-hl-constant-color: hsla(250, 62%, 70%, 1);\n --md-code-hl-keyword-color: hsla(219, 66%, 64%, 1);\n --md-code-hl-string-color: hsla(150, 58%, 44%, 1);\n --md-code-hl-name-color: var(--md-code-fg-color);\n --md-code-hl-operator-color: var(--md-default-fg-color--light);\n --md-code-hl-punctuation-color: var(--md-default-fg-color--light);\n --md-code-hl-comment-color: var(--md-default-fg-color--light);\n --md-code-hl-generic-color: var(--md-default-fg-color--light);\n --md-code-hl-variable-color: var(--md-default-fg-color--light);\n\n // Typeset color shades\n --md-typeset-color: var(--md-default-fg-color);\n\n // Typeset `a` color shades\n --md-typeset-a-color: var(--md-primary-fg-color);\n\n // Typeset `mark` color shades\n --md-typeset-mark-color: hsla(#{hex2hsl($clr-blue-a200)}, 0.3);\n\n // Typeset `kbd` color shades\n --md-typeset-kbd-color: hsla(var(--md-hue), 15%, 94%, 0.12);\n --md-typeset-kbd-accent-color: hsla(var(--md-hue), 15%, 94%, 0.2);\n --md-typeset-kbd-border-color: hsla(var(--md-hue), 15%, 14%, 1);\n\n // Typeset `table` color shades\n --md-typeset-table-color: hsla(var(--md-hue), 75%, 95%, 0.12);\n\n // Admonition color shades\n --md-admonition-bg-color: hsla(var(--md-hue), 0%, 100%, 0.025);\n\n // Footer color shades\n --md-footer-bg-color: hsla(var(--md-hue), 15%, 12%, 0.87);\n --md-footer-bg-color--dark: hsla(var(--md-hue), 15%, 10%, 1);\n\n // Black and white primary colors\n &[data-md-color-primary=\"black\"],\n &[data-md-color-primary=\"white\"] {\n\n // Typeset color shades\n --md-typeset-a-color: hsla(#{hex2hsl($clr-indigo-400)}, 1);\n }\n }\n}\n"]} \ No newline at end of file diff --git a/assets/stylesheets/palette.cbb835fc.min.css b/assets/stylesheets/palette.cbb835fc.min.css deleted file mode 100644 index 30f9264c..00000000 --- a/assets/stylesheets/palette.cbb835fc.min.css +++ /dev/null @@ -1 +0,0 @@ -@media screen{[data-md-color-scheme=slate]{--md-hue:232;--md-default-fg-color:hsla(var(--md-hue),75%,95%,1);--md-default-fg-color--light:hsla(var(--md-hue),75%,90%,0.62);--md-default-fg-color--lighter:hsla(var(--md-hue),75%,90%,0.32);--md-default-fg-color--lightest:hsla(var(--md-hue),75%,90%,0.12);--md-default-bg-color:hsla(var(--md-hue),15%,21%,1);--md-default-bg-color--light:hsla(var(--md-hue),15%,21%,0.54);--md-default-bg-color--lighter:hsla(var(--md-hue),15%,21%,0.26);--md-default-bg-color--lightest:hsla(var(--md-hue),15%,21%,0.07);--md-code-fg-color:hsla(var(--md-hue),18%,86%,1);--md-code-bg-color:hsla(var(--md-hue),15%,15%,1);--md-code-hl-color:rgba(66,135,255,.15);--md-code-hl-number-color:#e6695b;--md-code-hl-special-color:#f06090;--md-code-hl-function-color:#c973d9;--md-code-hl-constant-color:#9383e2;--md-code-hl-keyword-color:#6791e0;--md-code-hl-string-color:#2fb170;--md-code-hl-name-color:var(--md-code-fg-color);--md-code-hl-operator-color:var(--md-default-fg-color--light);--md-code-hl-punctuation-color:var(--md-default-fg-color--light);--md-code-hl-comment-color:var(--md-default-fg-color--light);--md-code-hl-generic-color:var(--md-default-fg-color--light);--md-code-hl-variable-color:var(--md-default-fg-color--light);--md-typeset-color:var(--md-default-fg-color);--md-typeset-a-color:var(--md-primary-fg-color);--md-typeset-mark-color:rgba(66,135,255,.3);--md-typeset-kbd-color:hsla(var(--md-hue),15%,94%,0.12);--md-typeset-kbd-accent-color:hsla(var(--md-hue),15%,94%,0.2);--md-typeset-kbd-border-color:hsla(var(--md-hue),15%,14%,1);--md-typeset-table-color:hsla(var(--md-hue),75%,95%,0.12);--md-admonition-fg-color:var(--md-default-fg-color);--md-admonition-bg-color:var(--md-default-bg-color);--md-footer-bg-color:hsla(var(--md-hue),15%,12%,0.87);--md-footer-bg-color--dark:hsla(var(--md-hue),15%,10%,1);--md-shadow-z1:0 0.2rem 0.5rem rgba(0,0,0,.2),0 0 0.05rem rgba(0,0,0,.1);--md-shadow-z2:0 0.2rem 0.5rem rgba(0,0,0,.3),0 0 0.05rem rgba(0,0,0,.25);--md-shadow-z3:0 0.2rem 0.5rem rgba(0,0,0,.4),0 0 0.05rem rgba(0,0,0,.35)}[data-md-color-scheme=slate] img[src$="#gh-light-mode-only"],[data-md-color-scheme=slate] img[src$="#only-light"]{display:none}[data-md-color-scheme=slate] img[src$="#gh-dark-mode-only"],[data-md-color-scheme=slate] img[src$="#only-dark"]{display:initial}[data-md-color-scheme=slate][data-md-color-primary=pink]{--md-typeset-a-color:#ed5487}[data-md-color-scheme=slate][data-md-color-primary=purple]{--md-typeset-a-color:#bd78c9}[data-md-color-scheme=slate][data-md-color-primary=deep-purple]{--md-typeset-a-color:#a682e3}[data-md-color-scheme=slate][data-md-color-primary=indigo]{--md-typeset-a-color:#6c91d5}[data-md-color-scheme=slate][data-md-color-primary=teal]{--md-typeset-a-color:#00ccb8}[data-md-color-scheme=slate][data-md-color-primary=green]{--md-typeset-a-color:#71c174}[data-md-color-scheme=slate][data-md-color-primary=deep-orange]{--md-typeset-a-color:#ff9575}[data-md-color-scheme=slate][data-md-color-primary=brown]{--md-typeset-a-color:#c7846b}[data-md-color-scheme=slate][data-md-color-primary=black],[data-md-color-scheme=slate][data-md-color-primary=blue-grey],[data-md-color-scheme=slate][data-md-color-primary=grey],[data-md-color-scheme=slate][data-md-color-primary=white]{--md-typeset-a-color:#6c91d5}[data-md-color-switching] *,[data-md-color-switching] :after,[data-md-color-switching] :before{transition-duration:0ms!important}}[data-md-color-accent=red]{--md-accent-fg-color:#ff1947;--md-accent-fg-color--transparent:rgba(255,25,71,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=pink]{--md-accent-fg-color:#f50056;--md-accent-fg-color--transparent:rgba(245,0,86,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=purple]{--md-accent-fg-color:#df41fb;--md-accent-fg-color--transparent:rgba(223,65,251,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=deep-purple]{--md-accent-fg-color:#7c4dff;--md-accent-fg-color--transparent:rgba(124,77,255,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=indigo]{--md-accent-fg-color:#526cfe;--md-accent-fg-color--transparent:rgba(82,108,254,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=blue]{--md-accent-fg-color:#4287ff;--md-accent-fg-color--transparent:rgba(66,135,255,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=light-blue]{--md-accent-fg-color:#0091eb;--md-accent-fg-color--transparent:rgba(0,145,235,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=cyan]{--md-accent-fg-color:#00bad6;--md-accent-fg-color--transparent:rgba(0,186,214,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=teal]{--md-accent-fg-color:#00bda4;--md-accent-fg-color--transparent:rgba(0,189,164,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=green]{--md-accent-fg-color:#00c753;--md-accent-fg-color--transparent:rgba(0,199,83,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=light-green]{--md-accent-fg-color:#63de17;--md-accent-fg-color--transparent:rgba(99,222,23,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-accent=lime]{--md-accent-fg-color:#b0eb00;--md-accent-fg-color--transparent:rgba(176,235,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=yellow]{--md-accent-fg-color:#ffd500;--md-accent-fg-color--transparent:rgba(255,213,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=amber]{--md-accent-fg-color:#fa0;--md-accent-fg-color--transparent:rgba(255,170,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=orange]{--md-accent-fg-color:#ff9100;--md-accent-fg-color--transparent:rgba(255,145,0,.1);--md-accent-bg-color:rgba(0,0,0,.87);--md-accent-bg-color--light:rgba(0,0,0,.54)}[data-md-color-accent=deep-orange]{--md-accent-fg-color:#ff6e42;--md-accent-fg-color--transparent:rgba(255,110,66,.1);--md-accent-bg-color:#fff;--md-accent-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=red]{--md-primary-fg-color:#ef5552;--md-primary-fg-color--light:#e57171;--md-primary-fg-color--dark:#e53734;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=pink]{--md-primary-fg-color:#e92063;--md-primary-fg-color--light:#ec417a;--md-primary-fg-color--dark:#c3185d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=purple]{--md-primary-fg-color:#ab47bd;--md-primary-fg-color--light:#bb69c9;--md-primary-fg-color--dark:#8c24a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=deep-purple]{--md-primary-fg-color:#7e56c2;--md-primary-fg-color--light:#9574cd;--md-primary-fg-color--dark:#673ab6;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=indigo]{--md-primary-fg-color:#4051b5;--md-primary-fg-color--light:#5d6cc0;--md-primary-fg-color--dark:#303fa1;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=blue]{--md-primary-fg-color:#2094f3;--md-primary-fg-color--light:#42a5f5;--md-primary-fg-color--dark:#1975d2;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=light-blue]{--md-primary-fg-color:#02a6f2;--md-primary-fg-color--light:#28b5f6;--md-primary-fg-color--dark:#0287cf;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=cyan]{--md-primary-fg-color:#00bdd6;--md-primary-fg-color--light:#25c5da;--md-primary-fg-color--dark:#0097a8;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=teal]{--md-primary-fg-color:#009485;--md-primary-fg-color--light:#26a699;--md-primary-fg-color--dark:#007a6c;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=green]{--md-primary-fg-color:#4cae4f;--md-primary-fg-color--light:#68bb6c;--md-primary-fg-color--dark:#398e3d;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=light-green]{--md-primary-fg-color:#8bc34b;--md-primary-fg-color--light:#9ccc66;--md-primary-fg-color--dark:#689f38;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=lime]{--md-primary-fg-color:#cbdc38;--md-primary-fg-color--light:#d3e156;--md-primary-fg-color--dark:#b0b52c;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=yellow]{--md-primary-fg-color:#ffec3d;--md-primary-fg-color--light:#ffee57;--md-primary-fg-color--dark:#fbc02d;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=amber]{--md-primary-fg-color:#ffc105;--md-primary-fg-color--light:#ffc929;--md-primary-fg-color--dark:#ffa200;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=orange]{--md-primary-fg-color:#ffa724;--md-primary-fg-color--light:#ffa724;--md-primary-fg-color--dark:#fa8900;--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54)}[data-md-color-primary=deep-orange]{--md-primary-fg-color:#ff6e42;--md-primary-fg-color--light:#ff8a66;--md-primary-fg-color--dark:#f4511f;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=brown]{--md-primary-fg-color:#795649;--md-primary-fg-color--light:#8d6e62;--md-primary-fg-color--dark:#5d4037;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7)}[data-md-color-primary=grey]{--md-primary-fg-color:#757575;--md-primary-fg-color--light:#9e9e9e;--md-primary-fg-color--dark:#616161;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=blue-grey]{--md-primary-fg-color:#546d78;--md-primary-fg-color--light:#607c8a;--md-primary-fg-color--dark:#455a63;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=light-green]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#72ad2e}[data-md-color-primary=lime]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#8b990a}[data-md-color-primary=yellow]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#b8a500}[data-md-color-primary=amber]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#d19d00}[data-md-color-primary=orange]:not([data-md-color-scheme=slate]){--md-typeset-a-color:#e68a00}[data-md-color-primary=white]{--md-primary-fg-color:#fff;--md-primary-fg-color--light:hsla(0,0%,100%,.7);--md-primary-fg-color--dark:rgba(0,0,0,.07);--md-primary-bg-color:rgba(0,0,0,.87);--md-primary-bg-color--light:rgba(0,0,0,.54);--md-typeset-a-color:#4051b5}@media screen and (min-width:60em){[data-md-color-primary=white] .md-search__form{background-color:rgba(0,0,0,.07)}[data-md-color-primary=white] .md-search__form:hover{background-color:rgba(0,0,0,.32)}[data-md-color-primary=white] .md-search__input+.md-search__icon{color:rgba(0,0,0,.87)}}@media screen and (min-width:76.25em){[data-md-color-primary=white] .md-tabs{border-bottom:.05rem solid rgba(0,0,0,.07)}}[data-md-color-primary=black]{--md-primary-fg-color:#000;--md-primary-fg-color--light:rgba(0,0,0,.54);--md-primary-fg-color--dark:#000;--md-primary-bg-color:#fff;--md-primary-bg-color--light:hsla(0,0%,100%,.7);--md-typeset-a-color:#4051b5}[data-md-color-primary=black] .md-header{background-color:#000}@media screen and (max-width:59.9375em){[data-md-color-primary=black] .md-nav__source{background-color:rgba(0,0,0,.87)}}@media screen and (min-width:60em){[data-md-color-primary=black] .md-search__form{background-color:hsla(0,0%,100%,.12)}[data-md-color-primary=black] .md-search__form:hover{background-color:hsla(0,0%,100%,.3)}}@media screen and (max-width:76.1875em){html [data-md-color-primary=black] .md-nav--primary .md-nav__title[for=__drawer]{background-color:#000}}@media screen and (min-width:76.25em){[data-md-color-primary=black] .md-tabs{background-color:#000}} \ No newline at end of file diff --git a/assets/stylesheets/palette.cbb835fc.min.css.map b/assets/stylesheets/palette.cbb835fc.min.css.map deleted file mode 100644 index 96e380c8..00000000 --- a/assets/stylesheets/palette.cbb835fc.min.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["src/assets/stylesheets/palette/_scheme.scss","../../../src/assets/stylesheets/palette.scss","src/assets/stylesheets/palette/_accent.scss","src/assets/stylesheets/palette/_primary.scss","src/assets/stylesheets/utilities/_break.scss"],"names":[],"mappings":"AA2BA,cAGE,6BAKE,YAAA,CAGA,mDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CACA,mDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CAGA,gDAAA,CACA,gDAAA,CAGA,uCAAA,CACA,iCAAA,CACA,kCAAA,CACA,mCAAA,CACA,mCAAA,CACA,kCAAA,CACA,iCAAA,CACA,+CAAA,CACA,6DAAA,CACA,gEAAA,CACA,4DAAA,CACA,4DAAA,CACA,6DAAA,CAGA,6CAAA,CAGA,+CAAA,CAGA,2CAAA,CAGA,uDAAA,CACA,6DAAA,CACA,2DAAA,CAGA,yDAAA,CAGA,mDAAA,CACA,mDAAA,CAGA,qDAAA,CACA,wDAAA,CAGA,wEAAA,CAKA,yEAAA,CAKA,yECxDF,CD6DE,kHAEE,YC3DJ,CD+DE,gHAEE,eC7DJ,CDoFE,yDACE,4BClFJ,CDiFE,2DACE,4BC/EJ,CD8EE,gEACE,4BC5EJ,CD2EE,2DACE,4BCzEJ,CDwEE,yDACE,4BCtEJ,CDqEE,0DACE,4BCnEJ,CDkEE,gEACE,4BChEJ,CD+DE,0DACE,4BC7DJ,CD4DE,2OACE,4BCjDJ,CDwDA,+FAGE,iCCtDF,CACF,CCjDE,2BACE,4BAAA,CACA,oDAAA,CAOE,yBAAA,CACA,8CD6CN,CCvDE,4BACE,4BAAA,CACA,mDAAA,CAOE,yBAAA,CACA,8CDoDN,CC9DE,8BACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,8CD2DN,CCrEE,mCACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,8CDkEN,CC5EE,8BACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,8CDyEN,CCnFE,4BACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,8CDgFN,CC1FE,kCACE,4BAAA,CACA,oDAAA,CAOE,yBAAA,CACA,8CDuFN,CCjGE,4BACE,4BAAA,CACA,oDAAA,CAOE,yBAAA,CACA,8CD8FN,CCxGE,4BACE,4BAAA,CACA,oDAAA,CAOE,yBAAA,CACA,8CDqGN,CC/GE,6BACE,4BAAA,CACA,mDAAA,CAOE,yBAAA,CACA,8CD4GN,CCtHE,mCACE,4BAAA,CACA,oDAAA,CAOE,yBAAA,CACA,8CDmHN,CC7HE,4BACE,4BAAA,CACA,oDAAA,CAIE,oCAAA,CACA,2CD6HN,CCpIE,8BACE,4BAAA,CACA,oDAAA,CAIE,oCAAA,CACA,2CDoIN,CC3IE,6BACE,yBAAA,CACA,oDAAA,CAIE,oCAAA,CACA,2CD2IN,CClJE,8BACE,4BAAA,CACA,oDAAA,CAIE,oCAAA,CACA,2CDkJN,CCzJE,mCACE,4BAAA,CACA,qDAAA,CAOE,yBAAA,CACA,8CDsJN,CE3JE,4BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwJN,CEnKE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFgKN,CE3KE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwKN,CEnLE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFgLN,CE3LE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwLN,CEnME,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFgMN,CE3ME,mCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwMN,CEnNE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFgNN,CE3NE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwNN,CEnOE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFgON,CE3OE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwON,CEnPE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,qCAAA,CACA,4CFmPN,CE3PE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,qCAAA,CACA,4CF2PN,CEnQE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,qCAAA,CACA,4CFmQN,CE3QE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,qCAAA,CACA,4CF2QN,CEnRE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFgRN,CE3RE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CFwRN,CEnSE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CAAA,CAKA,4BF4RN,CE5SE,kCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,+CAAA,CAKA,4BFqSN,CEtRE,sEACE,4BFyRJ,CE1RE,+DACE,4BF6RJ,CE9RE,iEACE,4BFiSJ,CElSE,gEACE,4BFqSJ,CEtSE,iEACE,4BFySJ,CEhSA,8BACE,0BAAA,CACA,+CAAA,CACA,2CAAA,CACA,qCAAA,CACA,4CAAA,CAGA,4BFiSF,CGrMI,mCDtFA,+CACE,gCF8RJ,CE3RI,qDACE,gCF6RN,CExRE,iEACE,qBF0RJ,CACF,CGhNI,sCDnEA,uCACE,0CFsRJ,CACF,CE7QA,8BACE,0BAAA,CACA,4CAAA,CACA,gCAAA,CACA,0BAAA,CACA,+CAAA,CAGA,4BF8QF,CE3QE,yCACE,qBF6QJ,CG9MI,wCDxDA,8CACE,gCFyQJ,CACF,CGtOI,mCD5BA,+CACE,oCFqQJ,CElQI,qDACE,mCFoQN,CACF,CG3NI,wCDjCA,iFACE,qBF+PJ,CACF,CGnPI,sCDLA,uCACE,qBF2PJ,CACF","file":"palette.css"} \ No newline at end of file diff --git a/index.html b/index.html index 7a64442f..f6990b28 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ - Index - UPSkilling

    Upskilling

    1.Linux

    1.1.Linux SRE

    1.2.SUSE Linux Administration

    1.3.SUSE Enterprise Storage Foundation

    2.Kubernetes

    2.1.CKA Learning Memo

    Installation

    Docker

    Foundamentals

    Core Kubernetes

    Application Modeling

    Advanced Kubernetes

    Operating Kubernetes

    Topics

    2.2.CKA学习笔记

    安装

    Docker

    基础知识

    核心概念

    应用体系

    进阶概念

    日常维护

    主题讨论

    Demos

    3.Python

    3.1.Python基础

    3.2.Python数据分析基础

    3.3.数据结构和算法

    3.4.Demos

    \ No newline at end of file + Index - UPSkilling

    Upskilling

    1.Linux

    1.1.Linux SRE

    1.2.SUSE Linux Administration

    1.3.SUSE Enterprise Storage Foundation

    2.Kubernetes

    2.1.CKA Learning Memo

    Installation

    Docker

    Foundamentals

    Core Kubernetes

    Application Modeling

    Advanced Kubernetes

    Operating Kubernetes

    Topics

    2.2.CKA学习笔记

    安装

    Docker

    基础知识

    核心概念

    应用体系

    进阶概念

    日常维护

    主题讨论

    Demos

    3.Python

    3.1.Python基础

    3.2.Python数据分析基础

    3.3.数据结构和算法

    3.4.Demos

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/basics/index.html b/k8s/cka_cn/foundamentals/basics/index.html index 73ec8471..f13d6ab2 100644 --- a/k8s/cka_cn/foundamentals/basics/index.html +++ b/k8s/cka_cn/foundamentals/basics/index.html @@ -1,46 +1,46 @@ - kubectl基础 - UPSkilling

    CKA自学笔记7:kubectl基础

    摘要

    了解如何使用kubectl操作Kubernetes集群。

    • via API
    • via kubectl
    • via Dashboard

    检查当前kubeconfig文件配置

    通过命令 kubectl config 检查当前配置文件中的上下文。

    echo $KUBECONFIG
    -kubectl config view
    -kubectl config get-contexts
    -

    获取资源清单

    读取所有支持的资源清单。

    kubectl api-resources
    -

    获取集群状态

    Kubernetes 控制面板运行在 https://<control_plane_ip>:6443

    CoreDNS 运行在 https://<control_plane_ip>:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

    kubectl cluster-info
    -kubectl cluster-info dump
    -

    读取当前资源

    执行命令 kubectl get --help 可以得到get命令的示例和使用方法。

    读取当前控制面板的健康状态。

    kubectl get componentstatuses
    -kubectl get cs
    + kubectl基础 - UPSkilling       

    CKA自学笔记7:kubectl基础

    摘要

    了解如何使用kubectl操作Kubernetes集群。

    • via API
    • via kubectl
    • via Dashboard

    检查当前kubeconfig文件配置

    通过命令 kubectl config 检查当前配置文件中的上下文。

    echo $KUBECONFIG
    +kubectl config view
    +kubectl config get-contexts
    +

    获取资源清单

    读取所有支持的资源清单。

    kubectl api-resources
    +

    获取集群状态

    Kubernetes 控制面板运行在 https://<control_plane_ip>:6443

    CoreDNS 运行在 https://<control_plane_ip>:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

    kubectl cluster-info
    +kubectl cluster-info dump
    +

    读取当前资源

    执行命令 kubectl get --help 可以得到get命令的示例和使用方法。

    读取当前控制面板的健康状态。

    kubectl get componentstatuses
    +kubectl get cs
     

    运行结果:

    NAME                 STATUS    MESSAGE                         ERROR
     etcd-0               Healthy   {"health":"true","reason":""}   
     scheduler            Healthy   ok                              
     controller-manager   Healthy   ok 
    -

    读取节点状态和信息

    kubectl get nodes
    -kubectl get nodes -o wide
    -kubectl describe node cka001
    -

    可以通过命令 kubectl create --help 来获取get命令的帮助和示例。

    创建Namespace

    kubectl create namespace --help
    -kubectl create namespace my-namespace
    -

    提示:

    命名空间Namespace是一个集群,包含了服务。服务可能在一个节点上,也可能不在。

    • Namespace是一种用来组织服务的方式,它可以对服务进行隔离和划分。
    • 不同的Namespace下,可以存在相同的服务名,但是不同的Namespace之间的服务不能直接通信,需要通过Service或Ingress来暴露。
    • 服务是一种提供功能的实体
    • 节点是一种运行服务的物理或虚拟机器

    创建deployment

    在某个Namespace中创建Deployment。

    kubectl -n my-namespace create deployment my-busybox \
    -  --image=busybox \
    -  --replicas=3 \
    -  --port=5701
    -

    创建ClusterRole

    kubectl create clusterrole --help
    +

    读取节点状态和信息

    kubectl get nodes
    +kubectl get nodes -o wide
    +kubectl describe node cka001
    +

    可以通过命令 kubectl create --help 来获取get命令的帮助和示例。

    创建Namespace

    kubectl create namespace --help
    +kubectl create namespace my-namespace
    +

    提示:

    命名空间Namespace是一个集群,包含了服务。服务可能在一个节点上,也可能不在。

    • Namespace是一种用来组织服务的方式,它可以对服务进行隔离和划分。
    • 不同的Namespace下,可以存在相同的服务名,但是不同的Namespace之间的服务不能直接通信,需要通过Service或Ingress来暴露。
    • 服务是一种提供功能的实体
    • 节点是一种运行服务的物理或虚拟机器

    创建deployment

    在某个Namespace中创建Deployment。

    kubectl -n my-namespace create deployment my-busybox \
    +  --image=busybox \
    +  --replicas=3 \
    +  --port=5701
    +

    创建ClusterRole

    kubectl create clusterrole --help
     
    -kubectl create clusterrole pod-creater \
    -  -n my-namespace \
    -  --verb=create \
    -  --resource=deployment \
    -  --resource-name=my-busybox
    -

    创建ServiceAccount

    kubectl create serviceaccount --help
    -kubectl -n my-namespace create serviceaccount my-service-account
    -

    创建RoleBinding

    RoleBinding可以引用同一命名空间中的一个Role,或者全局命名空间中的一个ClusterRole。

    • RoleBinding是一种用来授权角色的资源。
    • Role是一种定义权限的资源,只能在同一命名空间内生效。
    • ClusterRole是一种定义权限的资源,可以在整个集群内生效。
    kubectl create rolebinding --help
    +kubectl create clusterrole pod-creater \
    +  -n my-namespace \
    +  --verb=create \
    +  --resource=deployment \
    +  --resource-name=my-busybox
    +

    创建ServiceAccount

    kubectl create serviceaccount --help
    +kubectl -n my-namespace create serviceaccount my-service-account
    +

    创建RoleBinding

    RoleBinding可以引用同一命名空间中的一个Role,或者全局命名空间中的一个ClusterRole。

    • RoleBinding是一种用来授权角色的资源。
    • Role是一种定义权限的资源,只能在同一命名空间内生效。
    • ClusterRole是一种定义权限的资源,可以在整个集群内生效。
    kubectl create rolebinding --help
     
    -kubectl create rolebinding NAME \
    -  --clusterrole=NAME|--role=NAME \
    -  [--user=username] \
    -  [--group=groupname] \
    -  [--serviceaccount=namespace:serviceaccountname] \
    -  [--dry-run=server|client|none]
    +kubectl create rolebinding NAME \
    +  --clusterrole=NAME|--role=NAME \
    +  [--user=username] \
    +  [--group=groupname] \
    +  [--serviceaccount=namespace:serviceaccountname] \
    +  [--dry-run=server|client|none]
     
    -kubectl create rolebinding my-admin \
    -  --clusterrole=pod-creater \
    -  --serviceaccount=my-namespace:my-service-account
    -

    使用proxy

    我们可以使用kubectl proxy命令来打开一个到API服务器的隧道(tunnel),并使它在本地可用 - 通常是在localhost:8001 / 127.0.0.1:8001。当我想要使用API时,最简单的方法就是获取访问权限。

    运行命令kubectl proxy &并在浏览器中打开http://localhost:8001/api/v1。 只打开http://localhost:8001会返回错误,因为我们只能访问API的某些内容,因此API路径很重要。

    要点是:

    • kubectl proxy命令可以创建一个本地代理,让我们可以访问API服务器。
    • API服务器提供了集群的各种信息和操作。
    • 我们需要指定正确的API路径,才能访问我们想要的资源。
    kubectl proxy &
    +kubectl create rolebinding my-admin \
    +  --clusterrole=pod-creater \
    +  --serviceaccount=my-namespace:my-service-account
    +

    使用proxy

    我们可以使用kubectl proxy命令来打开一个到API服务器的隧道(tunnel),并使它在本地可用 - 通常是在localhost:8001 / 127.0.0.1:8001。当我想要使用API时,最简单的方法就是获取访问权限。

    运行命令kubectl proxy &并在浏览器中打开http://localhost:8001/api/v1。 只打开http://localhost:8001会返回错误,因为我们只能访问API的某些内容,因此API路径很重要。

    要点是:

    • kubectl proxy命令可以创建一个本地代理,让我们可以访问API服务器。
    • API服务器提供了集群的各种信息和操作。
    • 我们需要指定正确的API路径,才能访问我们想要的资源。
    kubectl proxy &
     

    输出结果:

    [1] 102358
     Starting to serve on 127.0.0.1:8001
     

    比如:

    http://127.0.0.1:8001/
    @@ -48,9 +48,9 @@
     http://127.0.0.1:8001/api/v1/namespaces
     http://127.0.0.1:8001/api/v1/namespaces/default
     http://127.0.0.1:8001/api/v1/namespaces/sock-shop/pods
    -

    作为应用程序访问

    如果我们作为应用程序而不是管理员来访问kubernetes,就不能使用kubectl,可以用curl程序来代替kubectl。 我们必须向集群发送HTTP请求,询问可用的节点。

    确保kubectl proxy正在运行,并在http://localhost:8001/上提供服务。

    执行下面的命令时加上一个-v=9的标志,它会显示所有需要的信息。

    要点:

    • 访问(access)是一种获取资源或服务的行为。

    • 应用程序(application)是一种执行特定功能的软件。

    • 作为应用程序访问意味着使用应用程序的身份或凭证来访问。

    • kubernetes是一种管理容器化应用程序的平台。

    • kubectl是一种用来和kubernetes交互的命令行工具。

    • curl是一种用来发送HTTP请求的命令行工具。

    • kubectl proxy可以创建一个本地代理,让我们可以访问kubernetes的API服务器。

    • -v=9是一种用来显示详细信息的选项。

    kubectl get nodes
    -

    在上面命令的输出结果中,我们可以找到对应的curl请求信息。

    curl -v -XGET  \
    -  -H "Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json" \
    -  -H "User-Agent: kubectl/v1.24.1 (linux/amd64) kubernetes/3ddd0f4" \
    -  'https://<control_plane_ip>/api/v1/nodes?limit=500'
    -

    参考信息:

    \ No newline at end of file +

    作为应用程序访问

    如果我们作为应用程序而不是管理员来访问kubernetes,就不能使用kubectl,可以用curl程序来代替kubectl。 我们必须向集群发送HTTP请求,询问可用的节点。

    确保kubectl proxy正在运行,并在http://localhost:8001/上提供服务。

    执行下面的命令时加上一个-v=9的标志,它会显示所有需要的信息。

    要点:

    • 访问(access)是一种获取资源或服务的行为。

    • 应用程序(application)是一种执行特定功能的软件。

    • 作为应用程序访问意味着使用应用程序的身份或凭证来访问。

    • kubernetes是一种管理容器化应用程序的平台。

    • kubectl是一种用来和kubernetes交互的命令行工具。

    • curl是一种用来发送HTTP请求的命令行工具。

    • kubectl proxy可以创建一个本地代理,让我们可以访问kubernetes的API服务器。

    • -v=9是一种用来显示详细信息的选项。

    kubectl get nodes
    +

    在上面命令的输出结果中,我们可以找到对应的curl请求信息。

    curl -v -XGET  \
    +  -H "Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json" \
    +  -H "User-Agent: kubectl/v1.24.1 (linux/amd64) kubernetes/3ddd0f4" \
    +  'https://<control_plane_ip>/api/v1/nodes?limit=500'
    +

    参考信息:

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/casestudy-calico/index.html b/k8s/cka_cn/foundamentals/casestudy-calico/index.html index e5193003..d951849b 100644 --- a/k8s/cka_cn/foundamentals/casestudy-calico/index.html +++ b/k8s/cka_cn/foundamentals/casestudy-calico/index.html @@ -1,26 +1,26 @@ - 安装Calico - UPSkilling

    主题讨论:安装Calico

    演示场景:安装Calico

    这是一个关于如何配置和测试Calico网络的简要步骤:

    • Calico数据库(Datastore):Calico支持使用etcd或Kubernetes API server作为数据存储后端。选择并部署其中一个数据存储后端。
    • 配置IP池:为了为Kubernetes集群中的节点分配IP地址,需要配置IP池。可以通过Calico自定义资源(CRD)来定义IP池。
    • 安装CNI插件:CNI插件负责在节点上创建和删除网络接口,它们是应用程序容器和物理网络之间的桥梁。需要在Kubernetes节点上安装Calico CNI插件。
    • 安装Typha:Typha是Calico中央控制平面的一个组件。它从Kubernetes API server中获取网络策略和其他信息,并将它们分发给所有节点上的calico/node。
    • 安装calico/node:calico/node是一个运行在Kubernetes节点上的守护进程。它管理节点上的网络接口,并为容器分配和释放IP地址。
    • 测试网络:在完成上述步骤后,可以通过在Pod之间进行网络通信来测试Calico网络是否正常工作。可以创建两个运行在不同节点上的Pod,并尝试从一个Pod ping另一个Pod。如果ping成功,则表示Calico网络已成功配置和运行。

    Calico数据库

    为了将Kubernetes用作Calico数据存储库,我们需要定义Calico使用的自定义资源。

    下载并检查Calico自定义资源定义列表,并在文件编辑器中打开它。

    wget https://projectcalico.docs.tigera.io/manifests/crds.yaml
    -

    在 Kubernetes 中创建 Calico 的自定义资源。

    kubectl apply -f crds.yaml
    -

    安装calicoctl

    下载 calicoctl 二进制文件到一个可以访问 Kubernetes 的 Linux 主机上,以直接与 Calico 数据存储交互。

    最新版的calicoctl可以通过git page进行下载,需要用实际版本号替换下面的v3.23.2的版本号。

    wget https://github.com/projectcalico/calico/releases/download/v3.23.3/calicoctl-linux-amd64
    -chmod +x calicoctl-linux-amd64
    -sudo cp calicoctl-linux-amd64 /usr/local/bin/calicoctl
    -

    配置 calicoctl 以访问 Kubernetes。

    echo "export KUBECONFIG=/root/.kube/config" >> ~/.bashrc
    -echo "export DATASTORE_TYPE=kubernetes" >> ~/.bashrc
    + 安装Calico - UPSkilling       

    主题讨论:安装Calico

    演示场景:安装Calico

    这是一个关于如何配置和测试Calico网络的简要步骤:

    • Calico数据库(Datastore):Calico支持使用etcd或Kubernetes API server作为数据存储后端。选择并部署其中一个数据存储后端。
    • 配置IP池:为了为Kubernetes集群中的节点分配IP地址,需要配置IP池。可以通过Calico自定义资源(CRD)来定义IP池。
    • 安装CNI插件:CNI插件负责在节点上创建和删除网络接口,它们是应用程序容器和物理网络之间的桥梁。需要在Kubernetes节点上安装Calico CNI插件。
    • 安装Typha:Typha是Calico中央控制平面的一个组件。它从Kubernetes API server中获取网络策略和其他信息,并将它们分发给所有节点上的calico/node。
    • 安装calico/node:calico/node是一个运行在Kubernetes节点上的守护进程。它管理节点上的网络接口,并为容器分配和释放IP地址。
    • 测试网络:在完成上述步骤后,可以通过在Pod之间进行网络通信来测试Calico网络是否正常工作。可以创建两个运行在不同节点上的Pod,并尝试从一个Pod ping另一个Pod。如果ping成功,则表示Calico网络已成功配置和运行。

    Calico数据库

    为了将Kubernetes用作Calico数据存储库,我们需要定义Calico使用的自定义资源。

    下载并检查Calico自定义资源定义列表,并在文件编辑器中打开它。

    wget https://projectcalico.docs.tigera.io/manifests/crds.yaml
    +

    在 Kubernetes 中创建 Calico 的自定义资源。

    kubectl apply -f crds.yaml
    +

    安装calicoctl

    下载 calicoctl 二进制文件到一个可以访问 Kubernetes 的 Linux 主机上,以直接与 Calico 数据存储交互。

    最新版的calicoctl可以通过git page进行下载,需要用实际版本号替换下面的v3.23.2的版本号。

    wget https://github.com/projectcalico/calico/releases/download/v3.23.3/calicoctl-linux-amd64
    +chmod +x calicoctl-linux-amd64
    +sudo cp calicoctl-linux-amd64 /usr/local/bin/calicoctl
    +

    配置 calicoctl 以访问 Kubernetes。

    echo "export KUBECONFIG=/root/.kube/config" >> ~/.bashrc
    +echo "export DATASTORE_TYPE=kubernetes" >> ~/.bashrc
     
    -echo $KUBECONFIG
    -echo $DATASTORE_TYPE
    -

    执行下面的命令,验证calicoctl能够访问数据库。

    calicoctl get nodes -o wide
    +echo $KUBECONFIG
    +echo $DATASTORE_TYPE
    +

    执行下面的命令,验证calicoctl能够访问数据库。

    calicoctl get nodes -o wide
     

    运行结果类似如下:

    NAME     ASN   IPV4   IPV6   
     cka001                       
     cka002                       
     cka003  
    -

    节点是由 Kubernetes 节点对象支持的,因此我们应该看到与 kubectl get nodes 匹配的名称。

    kubectl get nodes -o wide
    +

    节点是由 Kubernetes 节点对象支持的,因此我们应该看到与 kubectl get nodes 匹配的名称。

    kubectl get nodes -o wide
     

    运行结果:

    NAME     STATUS     ROLES                  AGE   VERSION   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
     cka001   NotReady   control-plane,master   23m   v1.24.0   Ubuntu 20.04.4 LTS   5.4.0-113-generic   containerd://1.5.9
     cka002   NotReady   <none>                 22m   v1.24.0   Ubuntu 20.04.4 LTS   5.4.0-113-generic   containerd://1.5.9
     cka003   NotReady   <none>                 21m   v1.24.0   Ubuntu 20.04.4 LTS   5.4.0-113-generic   containerd://1.5.9
    -

    配置IP池

    一个工作负载(workload)是容器或虚拟机,基于Calico的虚拟网络。 在Kubernetes中,工作负载是Pod。一个工作负载端点(endpoint)是工作负载用来连接Calico网络的虚拟网络接口。

    IP池是Calico为工作负载端点使用的IP地址范围。

    获取集群中当前的IP池。目前,在刚刚安装完之后,它是空的。

    calicoctl get ippools
    +

    配置IP池

    一个工作负载(workload)是容器或虚拟机,基于Calico的虚拟网络。 在Kubernetes中,工作负载是Pod。一个工作负载端点(endpoint)是工作负载用来连接Calico网络的虚拟网络接口。

    IP池是Calico为工作负载端点使用的IP地址范围。

    获取集群中当前的IP池。目前,在刚刚安装完之后,它是空的。

    calicoctl get ippools
     

    运行结果:

    NAME   CIDR   SELECTOR 
    -

    我们通过 kubeadm init 命令指定了 Pod CIDR 为 10.244.0.0/16

    现在,我们为集群创建两个 IP 池(IP pool),每个池之间不能重叠。

    创建IP池ipv4-ippool-1: 10.244.0.0/18

    calicoctl apply -f - <<EOF
    +

    我们通过 kubeadm init 命令指定了 Pod CIDR 为 10.244.0.0/16

    现在,我们为集群创建两个 IP 池(IP pool),每个池之间不能重叠。

    创建IP池ipv4-ippool-1: 10.244.0.0/18

    calicoctl apply -f - <<EOF
     apiVersion: projectcalico.org/v3
     kind: IPPool
     metadata:
    @@ -32,7 +32,7 @@
       disabled: false
       nodeSelector: all()
     EOF
    -

    创建IP池ipv4-ippool-2: 10.244.192.0/19

    calicoctl apply -f - <<EOF
    +

    创建IP池ipv4-ippool-2: 10.244.192.0/19

    calicoctl apply -f - <<EOF
     apiVersion: projectcalico.org/v3
     kind: IPPool
     metadata:
    @@ -44,53 +44,53 @@
       disabled: true
       nodeSelector: all()
     EOF
    -

    查询所创建的IP池。

    calicoctl get ippools -o wide
    +

    查询所创建的IP池。

    calicoctl get ippools -o wide
     

    运行结果:

    NAME            CIDR              NAT    IPIPMODE   VXLANMODE   DISABLED   DISABLEBGPEXPORT   SELECTOR   
     ipv4-ippool-1   10.244.0.0/18     true   Never      Never       false      false              all()      
     ipv4-ippool-2   10.244.192.0/19   true   Never      Never       true       false              all()     
    -

    安装CNI插件

    • 为插件创建Kubernetes用户账户。

    Kubernetes使用容器网络接口(CNI)与像Calico这样的网络提供者进行交互。

    以API形式呈现的,供Kubernetes使用的Calico二进制文件,称为CNI插件,必须安装在Kubernetes集群中的每个节点上。

    CNI插件在创建Pod时与Kubernetes API服务器交互,既要获取附加信息,又要使用有关Pod的信息更新数据存储。

    在Kubernetes *master*节点上,为CNI插件创建一个密钥以进行身份验证并签名证书请求。

    切换到目录 /etc/kubernetes/pki/

    cd /etc/kubernetes/pki/
    -

    生成证书。

    openssl req -newkey rsa:4096 \
    -  -keyout cni.key \
    -  -nodes \
    -  -out cni.csr \
    -  -subj "/CN=calico-cni"
    -

    使用主Kubernetes CA对此证书进行签名。

    sudo openssl x509 -req -in cni.csr \
    -  -CA /etc/kubernetes/pki/ca.crt \
    -  -CAkey /etc/kubernetes/pki/ca.key \
    -  -CAcreateserial \
    -  -out cni.crt \
    -  -days 3650
    +

    安装CNI插件

    • 为插件创建Kubernetes用户账户。

    Kubernetes使用容器网络接口(CNI)与像Calico这样的网络提供者进行交互。

    以API形式呈现的,供Kubernetes使用的Calico二进制文件,称为CNI插件,必须安装在Kubernetes集群中的每个节点上。

    CNI插件在创建Pod时与Kubernetes API服务器交互,既要获取附加信息,又要使用有关Pod的信息更新数据存储。

    在Kubernetes *master*节点上,为CNI插件创建一个密钥以进行身份验证并签名证书请求。

    切换到目录 /etc/kubernetes/pki/

    cd /etc/kubernetes/pki/
    +

    生成证书。

    openssl req -newkey rsa:4096 \
    +  -keyout cni.key \
    +  -nodes \
    +  -out cni.csr \
    +  -subj "/CN=calico-cni"
    +

    使用主Kubernetes CA对此证书进行签名。

    sudo openssl x509 -req -in cni.csr \
    +  -CA /etc/kubernetes/pki/ca.crt \
    +  -CAkey /etc/kubernetes/pki/ca.key \
    +  -CAcreateserial \
    +  -out cni.crt \
    +  -days 3650
     

    输出结果类似如下,用户是 calico-cni

    Signature ok
     subject=CN = calico-cni
     Getting CA Private Key
    -

    赋予当前操作系统用户对文件cni.crt的操作权限。

    sudo chown $(id -u):$(id -g) cni.crt
    -

    保持在/etc/kubernetes/pki/目录中,接下来我们将为CNI插件创建一个kubeconfig文件,用于访问Kubernetes。 将此cni.kubeconfig文件复制到集群中的每个节点。

    APISERVER=$(kubectl config view -o jsonpath='{.clusters[0].cluster.server}')
    +

    赋予当前操作系统用户对文件cni.crt的操作权限。

    sudo chown $(id -u):$(id -g) cni.crt
    +

    保持在/etc/kubernetes/pki/目录中,接下来我们将为CNI插件创建一个kubeconfig文件,用于访问Kubernetes。 将此cni.kubeconfig文件复制到集群中的每个节点。

    APISERVER=$(kubectl config view -o jsonpath='{.clusters[0].cluster.server}')
     
    -echo $APISERVER
    +echo $APISERVER
     
    -kubectl config set-cluster kubernetes \
    -  --certificate-authority=/etc/kubernetes/pki/ca.crt \
    -  --embed-certs=true \
    -  --server=$APISERVER \
    -  --kubeconfig=cni.kubeconfig
    +kubectl config set-cluster kubernetes \
    +  --certificate-authority=/etc/kubernetes/pki/ca.crt \
    +  --embed-certs=true \
    +  --server=$APISERVER \
    +  --kubeconfig=cni.kubeconfig
     
    -kubectl config set-credentials calico-cni \
    -  --client-certificate=cni.crt \
    -  --client-key=cni.key \
    -  --embed-certs=true \
    -  --kubeconfig=cni.kubeconfig
    +kubectl config set-credentials calico-cni \
    +  --client-certificate=cni.crt \
    +  --client-key=cni.key \
    +  --embed-certs=true \
    +  --kubeconfig=cni.kubeconfig
     
    -kubectl config set-context cni@kubernetes \
    -  --cluster=kubernetes \
    -  --user=calico-cni \
    -  --kubeconfig=cni.kubeconfig
    +kubectl config set-context cni@kubernetes \
    +  --cluster=kubernetes \
    +  --user=calico-cni \
    +  --kubeconfig=cni.kubeconfig
     
    -kubectl config use-context cni@kubernetes --kubeconfig=cni.kubeconfig
    -

    查询CNI上下文看起来类似下面的输出。

    kubectl config get-contexts --kubeconfig=cni.kubeconfig
    +kubectl config use-context cni@kubernetes --kubeconfig=cni.kubeconfig
    +

    查询CNI上下文看起来类似下面的输出。

    kubectl config get-contexts --kubeconfig=cni.kubeconfig
     

    输出结果:

    CURRENT   NAME             CLUSTER      AUTHINFO     NAMESPACE
     *         cni@kubernetes   kubernetes   calico-cni 
    -
    • 配置RBAC( Role-Based Access Control)

    为 CNI 插件的 Kubernetes 用户帐户配置 RBAC 角色和角色绑定。这将授予此用户帐户所需的 Kubernetes API 访问权限。

    切换到home路径,作为当前工作目录。

    cd ~
    -

    定义一个集群角色,CNI插件将使用该角色访问Kubernetes。

    kubectl apply -f - <<EOF
    +
    • 配置RBAC( Role-Based Access Control)

    为 CNI 插件的 Kubernetes 用户帐户配置 RBAC 角色和角色绑定。这将授予此用户帐户所需的 Kubernetes API 访问权限。

    切换到home路径,作为当前工作目录。

    cd ~
    +

    定义一个集群角色,CNI插件将使用该角色访问Kubernetes。

    kubectl apply -f - <<EOF
     kind: ClusterRole
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
    @@ -131,23 +131,23 @@
           - get
           - list
     EOF
    -

    把上面创建的集群角色绑定到 calico-cni 用户账户。

    kubectl create clusterrolebinding calico-cni --clusterrole=calico-cni --user=calico-cni
    -
    • 安装插件

    提示:需要在每个节点上执行下面的安装步骤。

    cka001上安装。

    root 用户运行下面的命令。

    sudo su
    -

    安装CNI插件的二进制文件。 下载包链接:https://github.com/projectcalico/cni-plugin/releaseshttps://github.com/containernetworking/plugins/releases

    mkdir -p /opt/cni/bin
    +

    把上面创建的集群角色绑定到 calico-cni 用户账户。

    kubectl create clusterrolebinding calico-cni --clusterrole=calico-cni --user=calico-cni
    +
    • 安装插件

    提示:需要在每个节点上执行下面的安装步骤。

    cka001上安装。

    root 用户运行下面的命令。

    sudo su
    +

    安装CNI插件的二进制文件。 下载包链接:https://github.com/projectcalico/cni-plugin/releaseshttps://github.com/containernetworking/plugins/releases

    mkdir -p /opt/cni/bin
     
    -curl -L -o /opt/cni/bin/calico https://github.com/projectcalico/cni-plugin/releases/download/v3.20.5/calico-amd64
    -chmod 755 /opt/cni/bin/calico
    +curl -L -o /opt/cni/bin/calico https://github.com/projectcalico/cni-plugin/releases/download/v3.20.5/calico-amd64
    +chmod 755 /opt/cni/bin/calico
     
    -curl -L -o /opt/cni/bin/calico-ipam https://github.com/projectcalico/cni-plugin/releases/download/v3.20.5/calico-ipam-amd64
    -chmod 755 /opt/cni/bin/calico-ipam
    +curl -L -o /opt/cni/bin/calico-ipam https://github.com/projectcalico/cni-plugin/releases/download/v3.20.5/calico-ipam-amd64
    +chmod 755 /opt/cni/bin/calico-ipam
     
    -wget https://github.com/containernetworking/plugins/releases/download/v1.1.1/cni-plugins-linux-amd64-v1.1.1.tgz
    -tar xvf cni-plugins-linux-amd64-v1.1.1.tgz -C /opt/cni/bin
    -

    创建配置文件目录。

    mkdir -p /etc/cni/net.d/
    -

    复制前面生成的kubeconfig到我们创建的配置文件目录/etc/cni/net.d/下,改名为calico-kubeconfig,并修改其权限。

    cp /etc/kubernetes/pki/cni.kubeconfig /etc/cni/net.d/calico-kubeconfig
    +wget https://github.com/containernetworking/plugins/releases/download/v1.1.1/cni-plugins-linux-amd64-v1.1.1.tgz
    +tar xvf cni-plugins-linux-amd64-v1.1.1.tgz -C /opt/cni/bin
    +

    创建配置文件目录。

    mkdir -p /etc/cni/net.d/
    +

    复制前面生成的kubeconfig到我们创建的配置文件目录/etc/cni/net.d/下,改名为calico-kubeconfig,并修改其权限。

    cp /etc/kubernetes/pki/cni.kubeconfig /etc/cni/net.d/calico-kubeconfig
     
    -chmod 600 /etc/cni/net.d/calico-kubeconfig
    -

    将下面的内容写入CNI配置文件/etc/cni/net.d/10-calico.conflist中。

    cat > /etc/cni/net.d/10-calico.conflist <<EOF
    +chmod 600 /etc/cni/net.d/calico-kubeconfig
    +

    将下面的内容写入CNI配置文件/etc/cni/net.d/10-calico.conflist中。

    cat > /etc/cni/net.d/10-calico.conflist <<EOF
     {
       "name": "k8s-pod-network",
       "cniVersion": "0.3.1",
    @@ -175,29 +175,29 @@
       ]
     }
     EOF
    -

    将/etc/cni/net.d/calico-kubeconfig配置文件复制到当前操作系统用户(root)的home路径下。

    cp /etc/cni/net.d/calico-kubeconfig ~
    +

    将/etc/cni/net.d/calico-kubeconfig配置文件复制到当前操作系统用户(root)的home路径下。

    cp /etc/cni/net.d/calico-kubeconfig ~
     

    退出 su 的 root用户,返回常规用户,这里是vagrant

    exit
    -

    在节点cka002上安装。

    当前仍然在节点cka001,通过sftp命令把生成的证书从节点cka001上传至节点cka002

    sftp -i cka-key-pair.pem cka002
    +

    在节点cka002上安装。

    当前仍然在节点cka001,通过sftp命令把生成的证书从节点cka001上传至节点cka002

    sftp -i cka-key-pair.pem cka002
     
    -put calico-amd64
    -put calicoctl-linux-amd64
    -put calico-ipam-amd64
    -put calico-kubeconfig
    -put cni-plugins-linux-amd64-v1.1.1.tgz
    -

    通过证书从节点cka001登录到节点cka002

    ssh -i cka-key-pair.pem cka002
    -

    创建目录/opt/cni/bin以存放cni二进制文件。

    mkdir -p /opt/cni/bin
    +put calico-amd64
    +put calicoctl-linux-amd64
    +put calico-ipam-amd64
    +put calico-kubeconfig
    +put cni-plugins-linux-amd64-v1.1.1.tgz
    +

    通过证书从节点cka001登录到节点cka002

    ssh -i cka-key-pair.pem cka002
    +

    创建目录/opt/cni/bin以存放cni二进制文件。

    mkdir -p /opt/cni/bin
     
    -cp calico-amd64 /opt/cni/bin/calico
    -cp calico-ipam-amd64 /opt/cni/bin/calico-ipam
    +cp calico-amd64 /opt/cni/bin/calico
    +cp calico-ipam-amd64 /opt/cni/bin/calico-ipam
     
    -tar xvf cni-plugins-linux-amd64-v1.1.1.tgz -C /opt/cni/bin
    +tar xvf cni-plugins-linux-amd64-v1.1.1.tgz -C /opt/cni/bin
     
    -mkdir -p /etc/cni/net.d/
    +mkdir -p /etc/cni/net.d/
     
    -cp calico-kubeconfig /etc/cni/net.d/calico-kubeconfig
    +cp calico-kubeconfig /etc/cni/net.d/calico-kubeconfig
     
    -chmod 600 /etc/cni/net.d/calico-kubeconfig
    -

    更新CNI配置文件/etc/cni/net.d/10-calico.conflist

    cat > /etc/cni/net.d/10-calico.conflist <<EOF
    +chmod 600 /etc/cni/net.d/calico-kubeconfig
    +

    更新CNI配置文件/etc/cni/net.d/10-calico.conflist

    cat > /etc/cni/net.d/10-calico.conflist <<EOF
     {
       "name": "k8s-pod-network",
       "cniVersion": "0.3.1",
    @@ -226,26 +226,26 @@
     }
     EOF
     

    返回至节点 cka001

    exit
    -

    cka003上安装。

    类似cka002的安装过程,从节点cka001上传证书到节点cka003,并登录到节点cka003完成下面的命令。

    sftp -i cka-key-pair.pem cka003
    -
    put calico-amd64
    -put calicoctl-linux-amd64
    -put calico-ipam-amd64
    -put calico-kubeconfig
    -put cni-plugins-linux-amd64-v1.1.1.tgz
    -
    ssh -i cka-key-pair.pem cka003
    -
    mkdir -p /opt/cni/bin
    +

    cka003上安装。

    类似cka002的安装过程,从节点cka001上传证书到节点cka003,并登录到节点cka003完成下面的命令。

    sftp -i cka-key-pair.pem cka003
    +
    put calico-amd64
    +put calicoctl-linux-amd64
    +put calico-ipam-amd64
    +put calico-kubeconfig
    +put cni-plugins-linux-amd64-v1.1.1.tgz
    +
    ssh -i cka-key-pair.pem cka003
    +
    mkdir -p /opt/cni/bin
     
    -cp calico-amd64 /opt/cni/bin/calico
    -cp calico-ipam-amd64 /opt/cni/bin/calico-ipam
    +cp calico-amd64 /opt/cni/bin/calico
    +cp calico-ipam-amd64 /opt/cni/bin/calico-ipam
     
    -tar xvf cni-plugins-linux-amd64-v1.1.1.tgz -C /opt/cni/bin
    +tar xvf cni-plugins-linux-amd64-v1.1.1.tgz -C /opt/cni/bin
     
    -mkdir -p /etc/cni/net.d/
    +mkdir -p /etc/cni/net.d/
     
    -cp calico-kubeconfig /etc/cni/net.d/calico-kubeconfig
    +cp calico-kubeconfig /etc/cni/net.d/calico-kubeconfig
     
    -chmod 600 /etc/cni/net.d/calico-kubeconfig
    -
    cat > /etc/cni/net.d/10-calico.conflist <<EOF
    +chmod 600 /etc/cni/net.d/calico-kubeconfig
    +
    cat > /etc/cni/net.d/10-calico.conflist <<EOF
     {
       "name": "k8s-pod-network",
       "cniVersion": "0.3.1",
    @@ -274,37 +274,37 @@
     }
     EOF
     

    返回至节点cka001

    exit
    -

    当前工作目录仍然是节点cka001的home目录。

    至此,此时,Kubernetes 节点将变为 Ready 状态,因为 Kubernetes 已安装了网络提供程序和配置。

    kubectl get nodes
    +

    当前工作目录仍然是节点cka001的home目录。

    至此,此时,Kubernetes 节点将变为 Ready 状态,因为 Kubernetes 已安装了网络提供程序和配置。

    kubectl get nodes
     

    运行结果:

    NAME     STATUS   ROLES                  AGE     VERSION
     cka001   Ready    control-plane,master   4h50m   v1.24.0
     cka002   Ready    <none>                 4h49m   v1.24.0
     cka003   Ready    <none>                 4h49m   v1.24.0
    -

    安装Typha

    Typha 处于 Kubernetes API 服务器和每个节点守护进程(如运行在 calico/node 中的 Felix 和 confd)之间。 它监视这些守护进程使用的 Kubernetes 资源和 Calico 自定义资源,每当资源更改时,它会将更新扩散到这些守护进程。 这减少了 Kubernetes API 服务器需要服务的监视数,提高了集群的可扩展性。

    • 准备证书

    下面,我们使用相互认证的TLS来确保calico/node和Typha之间的通信安全。 生成一个证书授权机构(CA)并使用它来为Typha签署证书。

    将当前工作目录改为 /etc/kubernetes/pki/

    cd /etc/kubernetes/pki/
    -

    创建CA证书和密钥。

    openssl req -x509 -newkey rsa:4096 \
    -  -keyout typhaca.key \
    -  -nodes \
    -  -out typhaca.crt \
    -  -subj "/CN=Calico Typha CA" \
    -  -days 365
    -

    把CA证书存放在ConfigMap中,使Typha和calico/node能够访问。

    kubectl create configmap -n kube-system calico-typha-ca --from-file=typhaca.crt
    -

    生成Typha密钥和证书签名请求(certificate signing request,CSR)。

    openssl req -newkey rsa:4096 \
    -  -keyout typha.key \
    -  -nodes \
    -  -out typha.csr \
    -  -subj "/CN=calico-typha"
    -

    证书的通用名称(CN)设置为 calico-typhacalico/node 将被用来验证此名称。

    使用 CA 对 Typha 证书进行签名。

    openssl x509 -req -in typha.csr \
    -  -CA typhaca.crt \
    -  -CAkey typhaca.key \
    -  -CAcreateserial \
    -  -out typha.crt \
    -  -days 365
    +

    安装Typha

    Typha 处于 Kubernetes API 服务器和每个节点守护进程(如运行在 calico/node 中的 Felix 和 confd)之间。 它监视这些守护进程使用的 Kubernetes 资源和 Calico 自定义资源,每当资源更改时,它会将更新扩散到这些守护进程。 这减少了 Kubernetes API 服务器需要服务的监视数,提高了集群的可扩展性。

    • 准备证书

    下面,我们使用相互认证的TLS来确保calico/node和Typha之间的通信安全。 生成一个证书授权机构(CA)并使用它来为Typha签署证书。

    将当前工作目录改为 /etc/kubernetes/pki/

    cd /etc/kubernetes/pki/
    +

    创建CA证书和密钥。

    openssl req -x509 -newkey rsa:4096 \
    +  -keyout typhaca.key \
    +  -nodes \
    +  -out typhaca.crt \
    +  -subj "/CN=Calico Typha CA" \
    +  -days 365
    +

    把CA证书存放在ConfigMap中,使Typha和calico/node能够访问。

    kubectl create configmap -n kube-system calico-typha-ca --from-file=typhaca.crt
    +

    生成Typha密钥和证书签名请求(certificate signing request,CSR)。

    openssl req -newkey rsa:4096 \
    +  -keyout typha.key \
    +  -nodes \
    +  -out typha.csr \
    +  -subj "/CN=calico-typha"
    +

    证书的通用名称(CN)设置为 calico-typhacalico/node 将被用来验证此名称。

    使用 CA 对 Typha 证书进行签名。

    openssl x509 -req -in typha.csr \
    +  -CA typhaca.crt \
    +  -CAkey typhaca.key \
    +  -CAcreateserial \
    +  -out typha.crt \
    +  -days 365
     

    运行结果:

    Signature ok
     subject=CN = calico-typha
     Getting CA Private Key
    -

    将 Typha 密钥和证书存储在一个 secret 中,以便 Typha 可以访问。

    kubectl create secret generic -n kube-system calico-typha-certs --from-file=typha.key --from-file=typha.crt
    -
    • 配置RBAC

    当前工作目录为home路径。

    cd ~
    -

    创建一个Typha使用的ServiceAccount。

    kubectl create serviceaccount -n kube-system calico-typha
    -

    为 Typha 创建一个集群角色,有观察 Calico 数据存储对象的权限。

    kubectl apply -f - <<EOF
    +

    将 Typha 密钥和证书存储在一个 secret 中,以便 Typha 可以访问。

    kubectl create secret generic -n kube-system calico-typha-certs --from-file=typha.key --from-file=typha.crt
    +
    • 配置RBAC

    当前工作目录为home路径。

    cd ~
    +

    创建一个Typha使用的ServiceAccount。

    kubectl create serviceaccount -n kube-system calico-typha
    +

    为 Typha 创建一个集群角色,有观察 Calico 数据存储对象的权限。

    kubectl apply -f - <<EOF
     kind: ClusterRole
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
    @@ -358,8 +358,8 @@
           - create
           - update
     EOF
    -

    将创建的集群角色绑定到calico-typha这个ServiceAccount。

    kubectl create clusterrolebinding calico-typha --clusterrole=calico-typha --serviceaccount=kube-system:calico-typha
    -
    • 安装Deployment

    由于 calico/node 需要 Typha,而 calico/node 负责建立 Pod 网络,所以我们把 Typha 作为主机网络的 Pod 运行,以避免鸡生蛋或蛋生鸡的问题(chicken-and-egg problem)。

    我们运行 3 个 Typha 副本,这样即使在滚动更新期间发生单个故障,也不会使 Typha 不可用。

    kubectl apply -f - <<EOF
    +

    将创建的集群角色绑定到calico-typha这个ServiceAccount。

    kubectl create clusterrolebinding calico-typha --clusterrole=calico-typha --serviceaccount=kube-system:calico-typha
    +
    • 安装Deployment

    由于 calico/node 需要 Typha,而 calico/node 负责建立 Pod 网络,所以我们把 Typha 作为主机网络的 Pod 运行,以避免鸡生蛋或蛋生鸡的问题(chicken-and-egg problem)。

    我们运行 3 个 Typha 副本,这样即使在滚动更新期间发生单个故障,也不会使 Typha 不可用。

    kubectl apply -f - <<EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -448,13 +448,13 @@
             secret:
               secretName: calico-typha-certs
     EOF
    -

    我们设置 TYPHA_CLIENTCNcalico-node,后续将用于 calico/node 证书的通用名称。

    确认 Typha 已经启动并运行了三个实例。

    kubectl get pods -l k8s-app=calico-typha -n kube-system
    +

    我们设置 TYPHA_CLIENTCNcalico-node,后续将用于 calico/node 证书的通用名称。

    确认 Typha 已经启动并运行了三个实例。

    kubectl get pods -l k8s-app=calico-typha -n kube-system
     

    运行结果:

    NAME                           READY   STATUS    RESTARTS   AGE
     calico-typha-5b8669646-b2xnq   1/1     Running   0          20s
     calico-typha-5b8669646-q5glk   0/1     Pending   0          20s
     calico-typha-5b8669646-rvv86   1/1     Running   0          20s
     

    遇到如下错误信息。

    0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 2 node(s) didn't have free ports for the requested pod ports.
    -
    • 安装Service

    calico/node使用Kubernetes Service以获得对Typha的负载均衡访问。

    kubectl apply -f - <<EOF
    +
    • 安装Service

    calico/node使用Kubernetes Service以获得对Typha的负载均衡访问。

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Service
     metadata:
    @@ -471,8 +471,8 @@
       selector:
         k8s-app: calico-typha
     EOF
    -

    验证Typha正在使用TLS。

    TYPHA_CLUSTERIP=$(kubectl get svc -n kube-system calico-typha -o jsonpath='{.spec.clusterIP}')
    -curl https://$TYPHA_CLUSTERIP:5473 -v --cacert /etc/kubernetes/pki/typhaca.crt
    +

    验证Typha正在使用TLS。

    TYPHA_CLUSTERIP=$(kubectl get svc -n kube-system calico-typha -o jsonpath='{.spec.clusterIP}')
    +curl https://$TYPHA_CLUSTERIP:5473 -v --cacert /etc/kubernetes/pki/typhaca.crt
     

    运行结果:

    *   Trying 11.244.91.165:5473...
     * TCP_NODELAY set
     * Connected to 11.244.91.165 (11.244.91.165) port 5473 (#0)
    @@ -495,25 +495,25 @@
     * error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate
     * Closing connection 0
     curl: (35) error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate
    -

    上面的错误信息说明 Typha 正在使用 TLS 证书,且因我们没有提供证书而拒绝连接。 下面我们会使用一个证书部署 calico/node,这样 Typha 就会接受连接了。

    安装calico/node

    calico/node 运行三个守护进程。

    • Felix,Calico的每个节点守护进程
    • BIRD,一个守护进程,使用BGP协议与其他节点交换路由信息
    • confd,一个守护进程,监视Calico数据存储中的配置更改,并更新BIRD的配置文件

    • 准备证书

    切换到目录 /etc/kubernetes/pki/

    cd /etc/kubernetes/pki/
    -

    创建 calico/node 密钥,用于认证 Typha 和证书签名请求 (certificate signing request,CSR)。

    openssl req -newkey rsa:4096 \
    -  -keyout calico-node.key \
    -  -nodes \
    -  -out calico-node.csr \
    -  -subj "/CN=calico-node"
    -

    这个证书的公共名称 (CN) 是 calico-node,这是我们在上一个演示中配置 Typha 接受的名称。

    使用我们前面创建的 CA 对 Felix 证书进行签名。

    openssl x509 -req -in calico-node.csr \
    -  -CA typhaca.crt \
    -  -CAkey typhaca.key \
    -  -CAcreateserial \
    -  -out calico-node.crt \
    -  -days 365
    +

    上面的错误信息说明 Typha 正在使用 TLS 证书,且因我们没有提供证书而拒绝连接。 下面我们会使用一个证书部署 calico/node,这样 Typha 就会接受连接了。

    安装calico/node

    calico/node 运行三个守护进程。

    • Felix,Calico的每个节点守护进程
    • BIRD,一个守护进程,使用BGP协议与其他节点交换路由信息
    • confd,一个守护进程,监视Calico数据存储中的配置更改,并更新BIRD的配置文件

    • 准备证书

    切换到目录 /etc/kubernetes/pki/

    cd /etc/kubernetes/pki/
    +

    创建 calico/node 密钥,用于认证 Typha 和证书签名请求 (certificate signing request,CSR)。

    openssl req -newkey rsa:4096 \
    +  -keyout calico-node.key \
    +  -nodes \
    +  -out calico-node.csr \
    +  -subj "/CN=calico-node"
    +

    这个证书的公共名称 (CN) 是 calico-node,这是我们在上一个演示中配置 Typha 接受的名称。

    使用我们前面创建的 CA 对 Felix 证书进行签名。

    openssl x509 -req -in calico-node.csr \
    +  -CA typhaca.crt \
    +  -CAkey typhaca.key \
    +  -CAcreateserial \
    +  -out calico-node.crt \
    +  -days 365
     

    运行结果:

    Signature ok
     subject=CN = calico-node
     Getting CA Private Key
    -

    将密钥和证书存储在 calico/node 将要访问的 Secret 中。

    kubectl create secret generic -n kube-system calico-node-certs --from-file=calico-node.key --from-file=calico-node.crt
    -
    • 准备RBAC

    切换至当前用户的home目录。

    cd ~
    -

    创建一个 calico/node 要使用的 ServiceAccount。

    kubectl create serviceaccount -n kube-system calico-node
    -

    准备一个集群角色,该角色具有读写Calico数据库对象的权限。

    kubectl apply -f - <<EOF
    +

    将密钥和证书存储在 calico/node 将要访问的 Secret 中。

    kubectl create secret generic -n kube-system calico-node-certs --from-file=calico-node.key --from-file=calico-node.crt
    +
    • 准备RBAC

    切换至当前用户的home目录。

    cd ~
    +

    创建一个 calico/node 要使用的 ServiceAccount。

    kubectl create serviceaccount -n kube-system calico-node
    +

    准备一个集群角色,该角色具有读写Calico数据库对象的权限。

    kubectl apply -f - <<EOF
     kind: ClusterRole
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
    @@ -651,9 +651,9 @@
         verbs:
           - watch
     EOF
    -

    把创建的集群角色绑定到calico-node这个ServiceAccount。

    kubectl create clusterrolebinding calico-node --clusterrole=calico-node --serviceaccount=kube-system:calico-node
    -
    • 安装daemonset

    切换至当前用户的home目录。

    cd ~
    -

    calico/node作为daemonset运行,安装在群集中的每个节点上。

    修改image: calico/node:v3.20.0为实际安装版本。

    创建daemonset。

    kubectl apply -f - <<EOF
    +

    把创建的集群角色绑定到calico-node这个ServiceAccount。

    kubectl create clusterrolebinding calico-node --clusterrole=calico-node --serviceaccount=kube-system:calico-node
    +
    • 安装daemonset

    切换至当前用户的home目录。

    cd ~
    +

    calico/node作为daemonset运行,安装在群集中的每个节点上。

    修改image: calico/node:v3.20.0为实际安装版本。

    创建daemonset。

    kubectl apply -f - <<EOF
     kind: DaemonSet
     apiVersion: apps/v1
     metadata:
    @@ -820,34 +820,34 @@
               secret:
                 secretName: calico-node-certs
     EOF
    -

    验证在集群中每个节点上 calico/node 是否在运行,安装后,一般在几分钟内会变为 Running 状态。

    kubectl get pod -l k8s-app=calico-node -n kube-system
    +

    验证在集群中每个节点上 calico/node 是否在运行,安装后,一般在几分钟内会变为 Running 状态。

    kubectl get pod -l k8s-app=calico-node -n kube-system
     

    运行结果:

    NAME                READY   STATUS    RESTARTS   AGE
     calico-node-4c4sp   1/1     Running   0          40s
     calico-node-j2z6v   1/1     Running   0          40s
     calico-node-vgm9n   1/1     Running   0          40s
    -

    测试网络

    pod之间的ping

    创建三个busybox实例。

    kubectl create deployment pingtest --image=busybox --replicas=3 -- sleep infinity
    -

    查询他们的IP地址。

    kubectl get pods --selector=app=pingtest --output=wide
    +

    测试网络

    pod之间的ping

    创建三个busybox实例。

    kubectl create deployment pingtest --image=busybox --replicas=3 -- sleep infinity
    +

    查询他们的IP地址。

    kubectl get pods --selector=app=pingtest --output=wide
     

    运行结果:

    NAME                        READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
     pingtest-585b76c894-chwjq   1/1     Running   0          7s    10.244.31.1    cka002   <none>           <none>
     pingtest-585b76c894-s2tbs   1/1     Running   0          7s    10.244.31.0    cka002   <none>           <none>
     pingtest-585b76c894-vm9wn   1/1     Running   0          7s    10.244.28.64   cka003   <none>           <none>
    -

    留意第二个和第三个 pod 的 IP 地址。 随后我们会在第一个 pod 中运行 exec 命令。 在第一个 pod 内部,对另外两个 pod 的 IP 地址进行 ping 测试。

    例如:

    kubectl exec -ti pingtest-585b76c894-chwjq -- sh
    -/ # ping 10.244.31.1 -c 4
    -4 packets transmitted, 4 packets received, 0% packet loss
    +

    留意第二个和第三个 pod 的 IP 地址。 随后我们会在第一个 pod 中运行 exec 命令。 在第一个 pod 内部,对另外两个 pod 的 IP 地址进行 ping 测试。

    例如:

    kubectl exec -ti pingtest-585b76c894-chwjq -- sh
    +/ # ping 10.244.31.1 -c 4
    +4 packets transmitted, 4 packets received, 0% packet loss
     
    -/ # ping 10.244.31.0 -c 4
    -4 packets transmitted, 4 packets received, 0% packet loss
    +/ # ping 10.244.31.0 -c 4
    +4 packets transmitted, 4 packets received, 0% packet loss
     
    -/ # ping 10.244.28.64 -c 4
    -4 packets transmitted, 0 packets received, 100% packet loss
    -

    路由检查

    从其中一个节点验证是否能ping通到每个pod的IP地址。例如:

    ip route get 10.244.31.1
    -ip route get 10.244.31.0
    -ip route get 10.244.28.64
    -

    在上面的结果中,示例中的 via <cka001_ip> (它是控制平面)表示此Pod IP的下一跳,这与Pod所在节点的IP地址匹配,符合预期。

    不同IP池的IPAM分配。在前面的演示中,我们创建了两个IP池,但将一个禁用了。

    calicoctl get ippools -o wide
    +/ # ping 10.244.28.64 -c 4
    +4 packets transmitted, 0 packets received, 100% packet loss
    +

    路由检查

    从其中一个节点验证是否能ping通到每个pod的IP地址。例如:

    ip route get 10.244.31.1
    +ip route get 10.244.31.0
    +ip route get 10.244.28.64
    +

    在上面的结果中,示例中的 via <cka001_ip> (它是控制平面)表示此Pod IP的下一跳,这与Pod所在节点的IP地址匹配,符合预期。

    不同IP池的IPAM分配。在前面的演示中,我们创建了两个IP池,但将一个禁用了。

    calicoctl get ippools -o wide
     

    运行结果:

    NAME            CIDR              NAT    IPIPMODE   VXLANMODE   DISABLED   DISABLEBGPEXPORT   SELECTOR   
     ipv4-ippool-1   10.244.0.0/18     true   Never      Never       false      false              all()      
     ipv4-ippool-2   10.244.192.0/19   true   Never      Never       true       false              all()   
    -

    激活第二个IP池。

    calicoctl --allow-version-mismatch apply -f - <<EOF
    +

    激活第二个IP池。

    calicoctl --allow-version-mismatch apply -f - <<EOF
     apiVersion: projectcalico.org/v3
     kind: IPPool
     metadata:
    @@ -859,11 +859,11 @@
       disabled: false
       nodeSelector: all()
     EOF
    -

    查询IP池的状态。

    calicoctl get ippools -o wide
    +

    查询IP池的状态。

    calicoctl get ippools -o wide
     

    运行结果:

    NAME            CIDR              NAT    IPIPMODE   VXLANMODE   DISABLED   DISABLEBGPEXPORT   SELECTOR   
     ipv4-ippool-1   10.244.0.0/18     true   Never      Never       false      false              all()      
     ipv4-ippool-2   10.244.192.0/19   true   Never      Never       false      false              all()      
    -

    创建一个 Pod,以显式方式请求从 pool2 分配一个 IP 地址。

    kubectl apply -f - <<EOF
    +

    创建一个 Pod,以显式方式请求从 pool2 分配一个 IP 地址。

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -879,12 +879,12 @@
         imagePullPolicy: Always
         name: pingtest
     EOF
    -

    验证pod已经从 pool2 分配一个 IP 地址。

    kubectl get pod pingtest-ippool-2 -o wide
    +

    验证pod已经从 pool2 分配一个 IP 地址。

    kubectl get pod pingtest-ippool-2 -o wide
     

    运行结果:

    NAME                READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
     pingtest-ippool-2   1/1     Running   0          18s   10.244.203.192   cka003   <none>           <none>
    -

    连接并进入Pod pingtest-585b76c894-chwjq内部。

    kubectl exec -ti pingtest-585b76c894-chwjq -- sh
    -/ # 10.244.203.192 -c 4
    -4 packets transmitted, 0 packets received, 100% packet loss
    -

    标记: 演示止于此,路由没有安装预期工作,原因查找中。

    删除演示中创建的临时资源。

    kubectl delete deployments.apps pingtest
    -kubectl delete pod pingtest-ippool-2
    -

    参考:End-to-end Calico installation

    \ No newline at end of file +

    连接并进入Pod pingtest-585b76c894-chwjq内部。

    kubectl exec -ti pingtest-585b76c894-chwjq -- sh
    +/ # 10.244.203.192 -c 4
    +4 packets transmitted, 0 packets received, 100% packet loss
    +

    标记: 演示止于此,路由没有安装预期工作,原因查找中。

    删除演示中创建的临时资源。

    kubectl delete deployments.apps pingtest
    +kubectl delete pod pingtest-ippool-2
    +

    参考:End-to-end Calico installation

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/casestudy-health-check/index.html b/k8s/cka_cn/foundamentals/casestudy-health-check/index.html index 0067618e..6f13df3f 100644 --- a/k8s/cka_cn/foundamentals/casestudy-health-check/index.html +++ b/k8s/cka_cn/foundamentals/casestudy-health-check/index.html @@ -1,4 +1,4 @@ - 健康检查 - UPSkilling

    主题讨论:健康检查

    演示场景:

    • 创建 Deployment 和 Service
    • 模拟一个错误(删除 index.html)
    • Pod 处于不健康状态并从 endpoint 列表中删除
    • 修复错误(恢复 index.html)
    • Pod 回到正常状态并重新加入 endpoint 列表

    创建 Deployment 和 Service

    创建Deployment nginx-healthcheck 和Service nginx-healthcheck

    kubectl apply -f - <<EOF
    + 健康检查 - UPSkilling       

    主题讨论:健康检查

    演示场景:

    • 创建 Deployment 和 Service
    • 模拟一个错误(删除 index.html)
    • Pod 处于不健康状态并从 endpoint 列表中删除
    • 修复错误(恢复 index.html)
    • Pod 回到正常状态并重新加入 endpoint 列表

    创建 Deployment 和 Service

    创建Deployment nginx-healthcheck 和Service nginx-healthcheck

    kubectl apply -f - <<EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -47,38 +47,38 @@
       selector:
         name: nginx-healthcheck
     EOF
    -

    查询Pod nginx-healthcheck

    kubectl get pod -owide
    +

    查询Pod nginx-healthcheck

    kubectl get pod -owide
     

    运行结果:

    NAME                                 READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
     nginx-healthcheck-79fc55d944-jw887   1/1     Running   0          9s    10.244.102.14   cka003   <none>           <none>
     nginx-healthcheck-79fc55d944-nwwjc   1/1     Running   0          9s    10.244.112.13   cka002   <none>           <none>
    -

    通过命令curl来访问上面运行结果中pod的IP地址。

    curl 10.244.102.14
    -curl 10.244.112.13
    -

    如果上面命令成功执行,则会返回Nginx中index.html的内容。

    获取前面创建的Service的详细信息。

    kubectl describe svc nginx-healthcheck
    -

    输出结果如下。在 Endpoints 部分我们可以看到2个pod。

    Name:                     nginx-healthcheck
    -Namespace:                dev
    -Labels:                   <none>
    -Annotations:              <none>
    -Selector:                 name=nginx-healthcheck
    -Type:                     NodePort
    -IP Family Policy:         SingleStack
    -IP Families:              IPv4
    -IP:                       11.244.238.20
    -IPs:                      11.244.238.20
    -Port:                     <unset>  80/TCP
    -TargetPort:               80/TCP
    -NodePort:                 <unset>  31795/TCP
    -Endpoints:                10.244.102.14:80,10.244.112.13:80
    -Session Affinity:         None
    -External Traffic Policy:  Cluster
    -Events:                   <none>
    -

    获取Endpoints的信息。

    kubectl get endpoints nginx-healthcheck
    +

    通过命令curl来访问上面运行结果中pod的IP地址。

    curl 10.244.102.14
    +curl 10.244.112.13
    +

    如果上面命令成功执行,则会返回Nginx中index.html的内容。

    获取前面创建的Service的详细信息。

    kubectl describe svc nginx-healthcheck
    +

    输出结果如下。在 Endpoints 部分我们可以看到2个pod。

    Name:                     nginx-healthcheck
    +Namespace:                dev
    +Labels:                   <none>
    +Annotations:              <none>
    +Selector:                 name=nginx-healthcheck
    +Type:                     NodePort
    +IP Family Policy:         SingleStack
    +IP Families:              IPv4
    +IP:                       11.244.238.20
    +IPs:                      11.244.238.20
    +Port:                     <unset>  80/TCP
    +TargetPort:               80/TCP
    +NodePort:                 <unset>  31795/TCP
    +Endpoints:                10.244.102.14:80,10.244.112.13:80
    +Session Affinity:         None
    +External Traffic Policy:  Cluster
    +Events:                   <none>
    +

    获取Endpoints的信息。

    kubectl get endpoints nginx-healthcheck
     

    运行结果

    NAME                ENDPOINTS                           AGE
     nginx-healthcheck   10.244.102.14:80,10.244.112.13:80   72s
    -

    至此,2个pod nginx-healthcheck 都能按照我们的期望正常工作。

    模拟readinessProbe错误

    让我们通过删除 nginx-healthcheck Pod 中的 index.html 文件来模拟错误,观察 readinessProbe 的表现。

    首先,执行 kubectl exec -it <your_pod_name> -- bash 命令以登录到 nginx-healthcheck Pod,并删除 index.html 文件。

    kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash
    -cd /usr/share/nginx/html/
    -rm -rf index.html
    +

    至此,2个pod nginx-healthcheck 都能按照我们的期望正常工作。

    模拟readinessProbe错误

    让我们通过删除 nginx-healthcheck Pod 中的 index.html 文件来模拟错误,观察 readinessProbe 的表现。

    首先,执行 kubectl exec -it <your_pod_name> -- bash 命令以登录到 nginx-healthcheck Pod,并删除 index.html 文件。

    kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash
    +cd /usr/share/nginx/html/
    +rm -rf index.html
     exit
    -

    在执行了删除 nginx-healthcheck Pod 中的 index.html 文件之后,我们检查该 Pod 的状态。

    kubectl describe pod nginx-healthcheck-79fc55d944-jw887
    +

    在执行了删除 nginx-healthcheck Pod 中的 index.html 文件之后,我们检查该 Pod 的状态。

    kubectl describe pod nginx-healthcheck-79fc55d944-jw887
     

    下面的输出结果中,我们可以看到 Readiness probe failed 这个错误事件信息。

    ......
     Events:
       Type     Reason     Age              From               Message
    @@ -88,7 +88,7 @@
       Normal   Created    2m7s             kubelet            Created container nginx-healthcheck
       Normal   Started    2m7s             kubelet            Started container nginx-healthcheck
       Warning  Unhealthy  2s (x2 over 7s)  kubelet            Readiness probe failed: HTTP probe failed with statuscode: 403
    -

    检查另一个pod。

    kubectl describe pod nginx-healthcheck-79fc55d944-nwwjc
    +

    检查另一个pod。

    kubectl describe pod nginx-healthcheck-79fc55d944-nwwjc
     

    下面的输出结果中,没有发现错误。

    ......
     Events:
       Type    Reason     Age    From               Message
    @@ -97,34 +97,34 @@
       Normal  Pulled     3m45s  kubelet            Container image "nginx:latest" already present on machine
       Normal  Created    3m45s  kubelet            Created container nginx-healthcheck
       Normal  Started    3m45s  kubelet            Started container nginx-healthcheck
    -

    现在,通过curl命令来访问2个pod的IP地址,我们来观察会得到怎样的结果。

    curl 10.244.102.14
    -curl 10.244.112.13
    -

    运行结果:

    • curl 10.244.102.14 失败,错误信息是 403 Forbidden
    • curl 10.244.112.13 成功。

    我们现在来查询Nginx service在一个pod失败时的状态。

    kubectl describe svc nginx-healthcheck
    -

    在下面的输出结果中,我们看到Endpoint部分中只有一个pod的信息。

    Name:                     nginx-healthcheck
    -Namespace:                dev
    -Labels:                   <none>
    -Annotations:              <none>
    -Selector:                 name=nginx-healthcheck
    -Type:                     NodePort
    -IP Family Policy:         SingleStack
    -IP Families:              IPv4
    -IP:                       11.244.238.20
    -IPs:                      11.244.238.20
    -Port:                     <unset>  80/TCP
    -TargetPort:               80/TCP
    -NodePort:                 <unset>  31795/TCP
    -Endpoints:                10.244.112.13:80
    -Session Affinity:         None
    -External Traffic Policy:  Cluster
    -Events:                   <none>
    -

    同样的,我们可以通过检查Endpoint的信息,也能发现只有一个pod正在运行。

    kubectl get endpoints nginx-healthcheck 
    +

    现在,通过curl命令来访问2个pod的IP地址,我们来观察会得到怎样的结果。

    curl 10.244.102.14
    +curl 10.244.112.13
    +

    运行结果:

    • curl 10.244.102.14 失败,错误信息是 403 Forbidden
    • curl 10.244.112.13 成功。

    我们现在来查询Nginx service在一个pod失败时的状态。

    kubectl describe svc nginx-healthcheck
    +

    在下面的输出结果中,我们看到Endpoint部分中只有一个pod的信息。

    Name:                     nginx-healthcheck
    +Namespace:                dev
    +Labels:                   <none>
    +Annotations:              <none>
    +Selector:                 name=nginx-healthcheck
    +Type:                     NodePort
    +IP Family Policy:         SingleStack
    +IP Families:              IPv4
    +IP:                       11.244.238.20
    +IPs:                      11.244.238.20
    +Port:                     <unset>  80/TCP
    +TargetPort:               80/TCP
    +NodePort:                 <unset>  31795/TCP
    +Endpoints:                10.244.112.13:80
    +Session Affinity:         None
    +External Traffic Policy:  Cluster
    +Events:                   <none>
    +

    同样的,我们可以通过检查Endpoint的信息,也能发现只有一个pod正在运行。

    kubectl get endpoints nginx-healthcheck 
     

    运行结果:

    NAME                ENDPOINTS          AGE
     nginx-healthcheck   10.244.112.13:80   6m5s
    -

    修复readinessProbe错误

    现在,我们在pod中重新创建 index.html 文件,来修复错误。

    kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash
    +

    修复readinessProbe错误

    现在,我们在pod中重新创建 index.html 文件,来修复错误。

    kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash
     
    -cd /usr/share/nginx/html/
    +cd /usr/share/nginx/html/
     
    -cat > index.html << EOF 
    +cat > index.html << EOF 
     <!DOCTYPE html>
     <html>
     <head>
    @@ -153,24 +153,24 @@
     EOF
     
     exit
    -

    现在我们可以看到两个Pod已经重新加入了Endpoint列表,可以提供服务了。

    kubectl describe svc nginx-healthcheck
    -kubectl get endpoints nginx-healthcheck
    -

    重新通过curl命令访问2个pod的IP地址,我们可以看到它们都已经恢复到正常状态了。

    curl 10.244.102.14
    -curl 10.244.112.13
    -

    再次验证pod的状态。

    kubectl describe pod nginx-healthcheck-79fc55d944-jw887
    -

    结论:

    • 通过删除 index.html 文件,Pod 进入不健康状态并从端点列表中删除。
    • 只有一个健康的 Pod 可以提供正常的服务。

    清除演示中创建的临时资源。

    kubectl delete service nginx-healthcheck
    -kubectl delete deployment nginx-healthcheck
    +

    现在我们可以看到两个Pod已经重新加入了Endpoint列表,可以提供服务了。

    kubectl describe svc nginx-healthcheck
    +kubectl get endpoints nginx-healthcheck
    +

    重新通过curl命令访问2个pod的IP地址,我们可以看到它们都已经恢复到正常状态了。

    curl 10.244.102.14
    +curl 10.244.112.13
    +

    再次验证pod的状态。

    kubectl describe pod nginx-healthcheck-79fc55d944-jw887
    +

    结论:

    • 通过删除 index.html 文件,Pod 进入不健康状态并从端点列表中删除。
    • 只有一个健康的 Pod 可以提供正常的服务。

    清除演示中创建的临时资源。

    kubectl delete service nginx-healthcheck
    +kubectl delete deployment nginx-healthcheck
     

    模拟livenessProbe错误

    重新创建deployment nginx-healthcheck 和service nginx-healthcheck

    Deployment:

    NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
     nginx-healthcheck        0/2     2            0           7s
     

    Pods:

    NAME                                      READY   STATUS    RESTARTS   AGE
     nginx-healthcheck-79fc55d944-lknp9        1/1     Running   0          96s
     nginx-healthcheck-79fc55d944-wntmg        1/1     Running   0          96s
    -

    将 Nginx 默认监听端口从 80 改为 90,以模拟 livenessProbe 失败。livenessProbe 通过端口 80 检查生存状态。

    kubectl exec -it nginx-healthcheck-79fc55d944-lknp9 -- bash
    -root@nginx-healthcheck-79fc55d944-lknp9:/# cd /etc/nginx/conf.d
    -root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# sed -i 's/80/90/g' default.conf
    -root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# nginx -s reload
    -2022/07/24 12:59:45 [notice] 79#79: signal process started
    -

    Pod现在表现为失败状态。

    kubectl describe pod nginx-healthcheck-79fc55d944-lknp9
    +

    将 Nginx 默认监听端口从 80 改为 90,以模拟 livenessProbe 失败。livenessProbe 通过端口 80 检查生存状态。

    kubectl exec -it nginx-healthcheck-79fc55d944-lknp9 -- bash
    +root@nginx-healthcheck-79fc55d944-lknp9:/# cd /etc/nginx/conf.d
    +root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# sed -i 's/80/90/g' default.conf
    +root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# nginx -s reload
    +2022/07/24 12:59:45 [notice] 79#79: signal process started
    +

    Pod现在表现为失败状态。

    kubectl describe pod nginx-healthcheck-79fc55d944-lknp9
     

    在pod的事件信息中,我们可以发现 livenessProbe 错误信息。

    Events:
       Type     Reason     Age                    From               Message
       ----     ------     ----                   ----               -------
    @@ -181,4 +181,4 @@
       Warning  Unhealthy  2m47s (x4 over 2m57s)  kubelet            Readiness probe failed: Get "http://10.244.102.46:80/": dial tcp 10.244.102.46:80: connect: connection refused
       Warning  Unhealthy  2m47s (x3 over 2m57s)  kubelet            Liveness probe failed: dial tcp 10.244.102.46:80: connect: connection refused
       Normal   Killing    2m47s                  kubelet            Container nginx-healthcheck failed liveness probe, will be restarted
    -

    livenessProbe检测到失败后,容器将自动重新启动。我们修改的default.conf文件将被默认文件替换,容器状态将恢复正常。

    \ No newline at end of file +

    livenessProbe检测到失败后,容器将自动重新启动。我们修改的default.conf文件将被默认文件替换,容器状态将恢复正常。

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/casestudy-operation-resources/index.html b/k8s/cka_cn/foundamentals/casestudy-operation-resources/index.html index 68045a59..38d32546 100644 --- a/k8s/cka_cn/foundamentals/casestudy-operation-resources/index.html +++ b/k8s/cka_cn/foundamentals/casestudy-operation-resources/index.html @@ -1,49 +1,49 @@ - Kubernetes资源常见操作 - UPSkilling

    主题讨论:Kubernetes资源常见操作

    演示场景:

    • 节点标签(Node Label)
    • 注解(Annotation)
    • 命名空间(Namespace)
    • ServiceAccount 授权(ServiceAccount Authorization)
    • 授权默认 ServiceAccount 访问 API
    • 部署(Deployment)
    • 暴露服务(Expose Service)
    • 扩展部署(Scale out the Deployment)
    • 滚动升级(Rolling update)
    • 回滚升级(Rolling back update)
    • 事件(Event)
    • 日志记录(Logging)

    节点标签(Node Label)

    • 添加/修改/移出节点标签。
    # Update node label
    -kubectl label node cka002 node=demonode
    + Kubernetes资源常见操作 - UPSkilling       

    主题讨论:Kubernetes资源常见操作

    演示场景:

    • 节点标签(Node Label)
    • 注解(Annotation)
    • 命名空间(Namespace)
    • ServiceAccount 授权(ServiceAccount Authorization)
    • 授权默认 ServiceAccount 访问 API
    • 部署(Deployment)
    • 暴露服务(Expose Service)
    • 扩展部署(Scale out the Deployment)
    • 滚动升级(Rolling update)
    • 回滚升级(Rolling back update)
    • 事件(Event)
    • 日志记录(Logging)

    节点标签(Node Label)

    • 添加/修改/移出节点标签。
    # Update node label
    +kubectl label node cka002 node=demonode
     
     # Get node info with label info
    -kubectl get node --show-labels
    +kubectl get node --show-labels
     
     # Search node by label
    -kubectl get node -l node=demonode
    +kubectl get node -l node=demonode
     
     # Remove a lable of node
    -kubectl label node cka002 node-
    -

    注解(Annotation)

    创建deployment Nginx

    kubectl create deploy nginx --image=nginx:mainline
    -

    获取注解信息

    kubectl describe deployment/nginx
    -

    运行结果:

    ......
    -Labels:                 app=nginx
    -Annotations:            deployment.kubernetes.io/revision: 1
    -Selector:               app=nginx
    -......
    -

    添加新的注解信息。

    kubectl annotate deployment nginx owner=James.H
    -

    再次查询注解信息得到如下结果。

    ......
    -Labels:                 app=nginx
    -Annotations:            deployment.kubernetes.io/revision: 1
    -                        owner: James.H
    -Selector:               app=nginx
    -......
    -

    更新/覆盖注解信息。

    kubectl annotate deployment/nginx owner=K8s --overwrite
    -

    再次查询注解信息得到如下结果。

    ......
    -Annotations:            deployment.kubernetes.io/revision: 1
    -                        owner: K8s
    -Selector:               app=nginx
    -......
    -

    移除注解信息。

    kubectl annotate deployment/nginx owner-
    -

    运行结果:

    ......
    -Labels:                 app=nginx
    -Annotations:            deployment.kubernetes.io/revision: 1
    -Selector:               app=nginx
    -......
    -

    删除上面演示中创建的临时资源。

    kubectl delete deployment nginx
    -

    命名空间(Namespace)

    • 查询当前可用namespace。
    kubectl get namespace
    +kubectl label node cka002 node-
    +

    注解(Annotation)

    创建deployment Nginx

    kubectl create deploy nginx --image=nginx:mainline
    +

    获取注解信息

    kubectl describe deployment/nginx
    +

    运行结果:

    ......
    +Labels:                 app=nginx
    +Annotations:            deployment.kubernetes.io/revision: 1
    +Selector:               app=nginx
    +......
    +

    添加新的注解信息。

    kubectl annotate deployment nginx owner=James.H
    +

    再次查询注解信息得到如下结果。

    ......
    +Labels:                 app=nginx
    +Annotations:            deployment.kubernetes.io/revision: 1
    +                        owner: James.H
    +Selector:               app=nginx
    +......
    +

    更新/覆盖注解信息。

    kubectl annotate deployment/nginx owner=K8s --overwrite
    +

    再次查询注解信息得到如下结果。

    ......
    +Annotations:            deployment.kubernetes.io/revision: 1
    +                        owner: K8s
    +Selector:               app=nginx
    +......
    +

    移除注解信息。

    kubectl annotate deployment/nginx owner-
    +

    运行结果:

    ......
    +Labels:                 app=nginx
    +Annotations:            deployment.kubernetes.io/revision: 1
    +Selector:               app=nginx
    +......
    +

    删除上面演示中创建的临时资源。

    kubectl delete deployment nginx
    +

    命名空间(Namespace)

    • 查询当前可用namespace。
    kubectl get namespace
     

    运行结果:

    NAME              STATUS   AGE
     default           Active   3h45m
     dev               Active   3h11m
     kube-node-lease   Active   3h45m
     kube-public       Active   3h45m
     kube-system       Active   3h45m
    -
    • 查询某个namespace上运行的pod信息。
    kubectl get pod -n kube-system
    +
    • 查询某个namespace上运行的pod信息。
    kubectl get pod -n kube-system
     

    运行结果:

    NAME                                       READY   STATUS    RESTARTS   AGE
     calico-kube-controllers-5c64b68895-jr4nl   1/1     Running   0          3h25m
     calico-node-dsx76                          1/1     Running   0          3h25m
    @@ -58,16 +58,16 @@
     kube-proxy-cm4hc                           1/1     Running   0          3h45m
     kube-proxy-g4w52                           1/1     Running   0          3h41m
     kube-scheduler-cka001                      1/1     Running   0          3h45m
    -
    • 查询所有namespace上的pod信息。
    kubectl get pod --all-namespaces
    -kubectl get pod -A
    -

    ServiceAccount 授权(ServiceAccount Authorization)

    在 Kubernetes 1.23 及更低版本中,当我们创建一个新的命名空间时,Kubernetes 会自动创建一个名为 default 的 ServiceAccount 和一个名为 default-token-xxxxx 的令牌。

    而在 Kubernetes 1.24 中,创建新的命名空间时仅会自动创建一个名为 default 的 ServiceAccount,需要手动创建与 default ServiceAccount 相关联的令牌。

    以下是创建一个名为 dev 的新命名空间的示例,我们可以看到在命名空间 dev 中仅创建了 ServiceAccount:default,没有与 ServiceAccount default 相关联的令牌(secret)。

    kubectl create namespace dev
    -kubectl get serviceaccount -n dev
    -kubectl get secrets -n dev
    -

    有一个默认的集群角色 admin,但是没有将其绑定到任何集群角色绑定(clusterrole binding)中。

    kubectl get clusterrole admin
    -kubectl get clusterrolebinding | grep ClusterRole/admin
    -

    角色Role和角色绑定RoleBinding是基于命名空间的。在命名空间dev中,没有角色和角色绑定。

    kubectl get role -n dev
    -kubectl get rolebinding -n dev
    -

    在 Kubernetes 集群中,Secret 是一个对象,用于存储敏感信息,如用户名、密码和令牌等。Secret 的目标是对凭据进行编码或哈希化。这些凭据可以在各种 Pod 定义文件中重复使用。

    kubernetes.io/service-account-token 类型的 Secret 用于存储标识服务账户的令牌。使用此类型的 Secret 时,需要确保 kubernetes.io/service-account.name 注释设置为现有服务账户名称。

    让我们在 dev 命名空间中为 ServiceAccount default 创建一个令牌。

    kubectl apply -f - << EOF
    +
    • 查询所有namespace上的pod信息。
    kubectl get pod --all-namespaces
    +kubectl get pod -A
    +

    ServiceAccount 授权(ServiceAccount Authorization)

    在 Kubernetes 1.23 及更低版本中,当我们创建一个新的命名空间时,Kubernetes 会自动创建一个名为 default 的 ServiceAccount 和一个名为 default-token-xxxxx 的令牌。

    而在 Kubernetes 1.24 中,创建新的命名空间时仅会自动创建一个名为 default 的 ServiceAccount,需要手动创建与 default ServiceAccount 相关联的令牌。

    以下是创建一个名为 dev 的新命名空间的示例,我们可以看到在命名空间 dev 中仅创建了 ServiceAccount:default,没有与 ServiceAccount default 相关联的令牌(secret)。

    kubectl create namespace dev
    +kubectl get serviceaccount -n dev
    +kubectl get secrets -n dev
    +

    有一个默认的集群角色 admin,但是没有将其绑定到任何集群角色绑定(clusterrole binding)中。

    kubectl get clusterrole admin
    +kubectl get clusterrolebinding | grep ClusterRole/admin
    +

    角色Role和角色绑定RoleBinding是基于命名空间的。在命名空间dev中,没有角色和角色绑定。

    kubectl get role -n dev
    +kubectl get rolebinding -n dev
    +

    在 Kubernetes 集群中,Secret 是一个对象,用于存储敏感信息,如用户名、密码和令牌等。Secret 的目标是对凭据进行编码或哈希化。这些凭据可以在各种 Pod 定义文件中重复使用。

    kubernetes.io/service-account-token 类型的 Secret 用于存储标识服务账户的令牌。使用此类型的 Secret 时,需要确保 kubernetes.io/service-account.name 注释设置为现有服务账户名称。

    让我们在 dev 命名空间中为 ServiceAccount default 创建一个令牌。

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Secret
     metadata:
    @@ -78,23 +78,23 @@
     type: kubernetes.io/service-account-token
     
     EOF
    -

    现在在 dev 命名空间中创建了 ServiceAccount default 和 Secret(令牌) default-token-dev

    kubectl get serviceaccount -n dev
    -kubectl get secrets -n dev
    -

    获取默认 Service Account 的 token,并赋值给环境变量$TOKEN

    TOKEN=$(kubectl -n dev describe secret $(kubectl -n dev get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d ' ')
    -echo $TOKEN
    -

    获取 API Service 地址,并赋值给环境变量$APISERVER

    APISERVER=$(kubectl config view | grep https | cut -f 2- -d ":" | tr -d " ")
    -echo $APISERVER
    -

    通过 API Server 以 JSON 格式获取命名空间 dev 中的 Pod 资源。

    curl $APISERVER/api/v1/namespaces/dev/pods --header "Authorization: Bearer $TOKEN" --insecure
    +

    现在在 dev 命名空间中创建了 ServiceAccount default 和 Secret(令牌) default-token-dev

    kubectl get serviceaccount -n dev
    +kubectl get secrets -n dev
    +

    获取默认 Service Account 的 token,并赋值给环境变量$TOKEN

    TOKEN=$(kubectl -n dev describe secret $(kubectl -n dev get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d ' ')
    +echo $TOKEN
    +

    获取 API Service 地址,并赋值给环境变量$APISERVER

    APISERVER=$(kubectl config view | grep https | cut -f 2- -d ":" | tr -d " ")
    +echo $APISERVER
    +

    通过 API Server 以 JSON 格式获取命名空间 dev 中的 Pod 资源。

    curl $APISERVER/api/v1/namespaces/dev/pods --header "Authorization: Bearer $TOKEN" --insecure
     

    我们将收到“403 forbidden”的错误消息。ServiceAccount default没有访问名称空间dev中的Pod的授权。

    让我们创建一个名为rolebinding-admin的RoleBinding,将集群角色admin绑定到名称空间dev中的ServiceAccount default。 因此,ServiceAccount default被授予在名称空间dev中的管理员授权。

    # Usage:
    -kubectl create rolebinding <rule> --clusterrole=<clusterrule> --serviceaccount=<namespace>:<name> --namespace=<namespace>
    +kubectl create rolebinding <rule> --clusterrole=<clusterrule> --serviceaccount=<namespace>:<name> --namespace=<namespace>
     
     # Crate rolebinding:
    -kubectl create rolebinding rolebinding-admin --clusterrole=admin --serviceaccount=dev:default --namespace=dev
    +kubectl create rolebinding rolebinding-admin --clusterrole=admin --serviceaccount=dev:default --namespace=dev
     

    执行命令 kubectl get rolebinding -n dev,得到类似如下的结果。

    NAME                ROLE                AGE
     rolebinding-admin   ClusterRole/admin   10s
    -

    再次通过 API Server 以 JSON 格式获取命名空间 dev 中的 Pod 资源,成功。

    curl $APISERVER/api/v1/namespaces/dev/pods --header "Authorization: Bearer $TOKEN" --insecure
    -

    删除上面演示中创建的临时资源。

    kubectl delete namespace dev
    -

    部署(Deployment)

    创建一个 Ubuntu Pod 以进行操作,并附加到运行中的 Pod。

    kubectl create -f - << EOF
    +

    再次通过 API Server 以 JSON 格式获取命名空间 dev 中的 Pod 资源,成功。

    curl $APISERVER/api/v1/namespaces/dev/pods --header "Authorization: Bearer $TOKEN" --insecure
    +

    删除上面演示中创建的临时资源。

    kubectl delete namespace dev
    +

    部署(Deployment)

    创建一个 Ubuntu Pod 以进行操作,并附加到运行中的 Pod。

    kubectl create -f - << EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -110,12 +110,12 @@
       restartPolicy: Always
     EOF
     
    -kubectl exec --stdin --tty ubuntu -- /bin/bash
    -

    创建一个 Deployment,选项 --image 指定了一个镜像,选项 --port 指定了外部访问的端口。 在创建 Deployment 的同时也会创建一个 Pod。

    kubectl create deployment myapp --image=docker.io/jocatalin/kubernetes-bootcamp:v1 --replicas=1 --port=8080
    -

    查询deployment的状态。

    kubectl get deployment myapp -o wide
    +kubectl exec --stdin --tty ubuntu -- /bin/bash
    +

    创建一个 Deployment,选项 --image 指定了一个镜像,选项 --port 指定了外部访问的端口。 在创建 Deployment 的同时也会创建一个 Pod。

    kubectl create deployment myapp --image=docker.io/jocatalin/kubernetes-bootcamp:v1 --replicas=1 --port=8080
    +

    查询deployment的状态。

    kubectl get deployment myapp -o wide
     

    输出结果:

    NAME    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS            IMAGES                                       SELECTOR
     myapp   1/1     1            1           79s   kubernetes-bootcamp   docker.io/jocatalin/kubernetes-bootcamp:v1   app=myapp
    -

    查询deployment的详细信息。

    kubectl describe deployment myapp
    +

    查询deployment的详细信息。

    kubectl describe deployment myapp
     

    运行结果:

    Name:                   myapp
     Namespace:              dev
     CreationTimestamp:      Sat, 23 Jul 2022 14:36:43 +0800
    @@ -147,56 +147,56 @@
       Type    Reason             Age   From                   Message
       ----    ------             ----  ----                   -------
       Normal  ScalingReplicaSet  95s   deployment-controller  Scaled up replica set myapp-b5d775f5d to 1
    -

    暴露服务(Expose Service)

    获取上面练习中创建的pod和deployment的信息。

    kubectl get deployment myapp -o wide
    -kubectl get pod -o wide
    +

    暴露服务(Expose Service)

    获取上面练习中创建的pod和deployment的信息。

    kubectl get deployment myapp -o wide
    +kubectl get pod -o wide
     

    运行结果:

    NAME                    READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
     myapp-b5d775f5d-cx8dx   1/1     Running   0          2m34s   10.244.102.7   cka003   <none>           <none>
     

    执行命令curl 10.244.102.7:8080,以发送HTTP请求到pod的端口,得到如下结果。

    Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1
    -

    要使 Pod 可以从外部访问,需要将端口 8080 暴露给节点端口(NodePort)。这需要创建一个相关的 Service。

    kubectl expose deployment myapp --type=NodePort --port=8080
    +

    要使 Pod 可以从外部访问,需要将端口 8080 暴露给节点端口(NodePort)。这需要创建一个相关的 Service。

    kubectl expose deployment myapp --type=NodePort --port=8080
     

    执行命令kubectl get svc myapp -o wide,获取service myapp 的详细信息。

    NAME    TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE   SELECTOR
     myapp   NodePort   11.244.74.3   <none>        8080:30514/TCP   7s    app=myapp
     

    执行命令curl 11.244.74.3:8080,以发送HTTP请求到service的端口,得到如下结果。

    Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-cx8dx | v=1
    -

    获取service的详细信息。

    kubectl get svc myapp -o yaml
    -kubectl describe svc myapp
    +

    获取service的详细信息。

    kubectl get svc myapp -o yaml
    +kubectl describe svc myapp
     

    执行 kubectl get endpoints myapp -o wide 命令以获取相关的 myapp 端点(endpoint)的详细信息。

    NAME    ENDPOINTS           AGE
     myapp   10.244.102.7:8080   43s
     

    提示:

    Endpoint(端点)是一个Kubernetes中的对象,用于存储可以被服务访问的Pod的网络地址和端口信息。 当Service创建时,Kubernetes会自动创建和更新相应的Endpoint。 Endpoint是由kube-proxy自动创建和维护的,并根据选择器匹配对应的Service和Pod。

    能成功的发送HTTP请求到service和节点,说明pod的端口8080被正确的映射到节点的端口32566

    执行命令curl :30514,发送HTTP请求到节点cka003上对应的端口。

    Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1
    -

    登录进入Ubuntu pod,我们可以通过发送HTTP请求到myapp所映射的service、pod和节点的端口。

    kubectl exec --stdin --tty ubuntu -- /bin/bash
    -curl 10.244.102.7:8080
    -curl 11.244.74.3:8080
    -curl <cka003_node_ip>:30514
    -Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1
    -

    扩容部署(Scale out the Deployment)

    Scale out by replicaset. We set three replicasets to scale out deployment myapp. The number of deployment myapp is now three. 通过副本集replicaset进行扩展。我们通过指定副本集的方式,对deployment myapp进行扩展部署,下面例子中,deployment myapp 的副本数是三个。

    kubectl scale deployment myapp --replicas=3
    -

    查询deployment的信息。

    kubectl get deployment myapp
    -

    查询replicaset的信息

    kubectl get replicaset
    -

    滚动升级(Rolling update)

    命令用法:kubectl set image (-f 文件名 | 类型 名称) 容器名称_1=容器镜像_1 ... 容器名称_N=容器镜像_N

    使用命令 kubectl get deployment,我们可以获取deployment myapp 和相关容器 kubernetes-bootcamp

    kubectl get deployment myapp -o wide
    -

    使用命令kubectl set image来更新多个版本的镜像,并使用选项--record将更改记录在部署的注释中。

    kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record
    -

    查询当前replicas的状态。

    kubectl get replicaset -o wide -l app=myapp
    +

    登录进入Ubuntu pod,我们可以通过发送HTTP请求到myapp所映射的service、pod和节点的端口。

    kubectl exec --stdin --tty ubuntu -- /bin/bash
    +curl 10.244.102.7:8080
    +curl 11.244.74.3:8080
    +curl <cka003_node_ip>:30514
    +Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1
    +

    扩容部署(Scale out the Deployment)

    Scale out by replicaset. We set three replicasets to scale out deployment myapp. The number of deployment myapp is now three. 通过副本集replicaset进行扩展。我们通过指定副本集的方式,对deployment myapp进行扩展部署,下面例子中,deployment myapp 的副本数是三个。

    kubectl scale deployment myapp --replicas=3
    +

    查询deployment的信息。

    kubectl get deployment myapp
    +

    查询replicaset的信息

    kubectl get replicaset
    +

    滚动升级(Rolling update)

    命令用法:kubectl set image (-f 文件名 | 类型 名称) 容器名称_1=容器镜像_1 ... 容器名称_N=容器镜像_N

    使用命令 kubectl get deployment,我们可以获取deployment myapp 和相关容器 kubernetes-bootcamp

    kubectl get deployment myapp -o wide
    +

    使用命令kubectl set image来更新多个版本的镜像,并使用选项--record将更改记录在部署的注释中。

    kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record
    +

    查询当前replicas的状态。

    kubectl get replicaset -o wide -l app=myapp
     

    输出结果如下,pod正以新的副本集replicas数量运行。

    NAME               DESIRED   CURRENT   READY   AGE   CONTAINERS            IMAGES                                       SELECTOR
     myapp-5dbd68cc99   1         1         0       8s    kubernetes-bootcamp   docker.io/jocatalin/kubernetes-bootcamp:v2   app=myapp,pod-template-hash=5dbd68cc99
     myapp-b5d775f5d    3         3         3       14m   kubernetes-bootcamp   docker.io/jocatalin/kubernetes-bootcamp:v1   app=myapp,pod-template-hash=b5d775f5d
    -

    我们可以在对应的yaml文件中 metadata.annotations 部分获取变更历史记录。

    kubectl get deployment myapp -o yaml
    -

    运行结果:

    apiVersion: apps/v1
    -kind: Deployment
    -metadata:
    -  annotations:
    -    deployment.kubernetes.io/revision: "2"
    -    kubernetes.io/change-cause: kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2
    -      --record=true
    -  ......
    -

    我们也可以使用命令 kubectl rollout history 获取更新历史记录,并使用特定修订版本号 --revision=<revision_number> 显示详细信息。

    kubectl rollout history deployment/myapp
    +

    我们可以在对应的yaml文件中 metadata.annotations 部分获取变更历史记录。

    kubectl get deployment myapp -o yaml
    +

    运行结果:

    apiVersion: apps/v1
    +kind: Deployment
    +metadata:
    +  annotations:
    +    deployment.kubernetes.io/revision: "2"
    +    kubernetes.io/change-cause: kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2
    +      --record=true
    +  ......
    +

    我们也可以使用命令 kubectl rollout history 获取更新历史记录,并使用特定修订版本号 --revision=<revision_number> 显示详细信息。

    kubectl rollout history deployment/myapp
     

    运行结果:

    deployment.apps/myapp 
    -REVISION  CHANGE-CAUSE
    -1         <none>
    -2         kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true
    -

    获取特定版本回滚历史记录。

    kubectl rollout history deployment/myapp --revision=2
    -

    执行命令 kubectl rollout undo 可以回滚到上一个版本,或使用选项 --to-revision=<revision_number> 回滚到指定的版本。

    kubectl rollout undo deployment/myapp --to-revision=1
    -

    版本 1 现在已经被替换成版本 3了。

    kubectl rollout history deployment/myapp
    +REVISION  CHANGE-CAUSE
    +1         <none>
    +2         kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true
    +

    获取特定版本回滚历史记录。

    kubectl rollout history deployment/myapp --revision=2
    +

    执行命令 kubectl rollout undo 可以回滚到上一个版本,或使用选项 --to-revision=<revision_number> 回滚到指定的版本。

    kubectl rollout undo deployment/myapp --to-revision=1
    +

    版本 1 现在已经被替换成版本 3了。

    kubectl rollout history deployment/myapp
     

    运行结果:

    deployment.apps/myapp 
    -REVISION  CHANGE-CAUSE
    -2         kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true
    -3         <none>
    -

    事件(Event)

    获取指定pod的事件信息。

    kubectl describe pod myapp-b5d775f5d-jlx6g
    +REVISION  CHANGE-CAUSE
    +2         kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true
    +3         <none>
    +

    事件(Event)

    获取指定pod的事件信息。

    kubectl describe pod myapp-b5d775f5d-jlx6g
     

    输出结果:

    ......
     Events:
       Type    Reason     Age   From               Message
    @@ -205,18 +205,18 @@
       Normal  Pulled     53s   kubelet            Container image "docker.io/jocatalin/kubernetes-bootcamp:v1" already present on machine
       Normal  Created    53s   kubelet            Created container kubernetes-bootcamp
       Normal  Started    53s   kubelet            Started container kubernetes-bootcamp
    -

    查询集群的事件信息。

    kubectl get event
    -

    日志记录(Logging)

    查询pod的日志信息。

    kubectl logs -f <pod_name>
    -kubectl logs -f <pod_name> -c <container_name> 
    +

    查询集群的事件信息。

    kubectl get event
    +

    日志记录(Logging)

    查询pod的日志信息。

    kubectl logs -f <pod_name>
    +kubectl logs -f <pod_name> -c <container_name> 
     

    例如:

    kubectl logs -f myapp-b5d775f5d-jlx6g
     

    运行结果:

    Kubernetes Bootcamp App Started At: 2022-07-23T06:54:18.532Z | Running On:  myapp-b5d775f5d-jlx6g
    -

    查询K8s不同组件的日志信息。

    kubectl logs kube-apiserver-cka001 -n kube-system
    -kubectl logs kube-controller-manager-cka001 -n kube-system
    -kubectl logs kube-scheduler-cka001 -n kube-system
    -kubectl logs etcd-cka001 -n kube-system
    -systemctl status kubelet
    -journalctl -fu kubelet
    -kubectl logs kube-proxy-5cdbj -n kube-system
    -

    删除演示中创建的临时资源。

    kubectl delete service myapp
    -kubectl delete deployment myapp
    -
    \ No newline at end of file +

    查询K8s不同组件的日志信息。

    kubectl logs kube-apiserver-cka001 -n kube-system
    +kubectl logs kube-controller-manager-cka001 -n kube-system
    +kubectl logs kube-scheduler-cka001 -n kube-system
    +kubectl logs etcd-cka001 -n kube-system
    +systemctl status kubelet
    +journalctl -fu kubelet
    +kubectl logs kube-proxy-5cdbj -n kube-system
    +

    删除演示中创建的临时资源。

    kubectl delete service myapp
    +kubectl delete deployment myapp
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/clustermgt/index.html b/k8s/cka_cn/foundamentals/clustermgt/index.html index 8595be83..2055002d 100644 --- a/k8s/cka_cn/foundamentals/clustermgt/index.html +++ b/k8s/cka_cn/foundamentals/clustermgt/index.html @@ -1,21 +1,21 @@ - Cluster Management - UPSkilling

    CKA自学笔记24:Cluster Management

    演示场景:etcd Backup and Restore

    • 安装 etcdctl
    • 在备份之前创建 Deployment
    • 备份 etcd
    • 在备份之后创建 Deployment
    • 停止服务
    • 停止 etcd
    • 恢复 etcd
    • 启动服务
    • 验证

    etcd备份和恢复

    安装etcdctl

    下载etcd安装包。

    wget https://github.com/etcd-io/etcd/releases/download/v3.5.3/etcd-v3.5.3-linux-amd64.tar.gz
    -

    解压etcd安装包,并赋予执行权限。

    tar -zxvf etcd-v3.5.3-linux-amd64.tar.gz
    -cp etcd-v3.5.3-linux-amd64/etcdctl /usr/local/bin/
    -sudo chmod u+x /usr/local/bin/etcdctl
    -

    验证:

    etcdctl --help
    -

    创建一个deployment(备份前)

    备份前创建一个deployment。

    kubectl create deployment app-before-backup --image=nginx
    -

    备份etcd

    说明:

    • <CONTROL_PLANE_IP_ADDRESS> 是控制平面节点的实际IP地址。
    • --endpoints:指定 etcd 备份的保存位置,2379 是 etcd 的端口号。
    • --cert:指定 etcd 证书的位置,证书是由 kubeadm 生成并保存在 /etc/kubernetes/pki/etcd/ 目录下的。
    • --key:指定 etcd 证书的私钥的位置,证书是由 kubeadm 生成并保存在 /etc/kubernetes/pki/etcd/ 目录下的。
    • --cacert:指定 etcd 证书的 CA 的位置,证书是由 kubeadm 生成并保存在 /etc/kubernetes/pki/etcd/ 目录下的。
    etcdctl \
    -  --endpoints=https://<CONTROL_PLANE_IP_ADDRESS>:2379 \
    -  --cert=/etc/kubernetes/pki/etcd/server.crt \
    -  --key=/etc/kubernetes/pki/etcd/server.key \
    -  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
    -  snapshot save snapshot-$(date +"%Y%m%d%H%M%S").db
    -

    或者

    etcdctl \
    -  --endpoints=https://<cka001_ip>:2379 \
    -  --cert=/etc/kubernetes/pki/etcd/server.crt \
    -  --key=/etc/kubernetes/pki/etcd/server.key \
    -  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
    -  snapshot save snapshot-$(date +"%Y%m%d%H%M%S").db
    + Cluster Management - UPSkilling       

    CKA自学笔记24:Cluster Management

    演示场景:etcd Backup and Restore

    • 安装 etcdctl
    • 在备份之前创建 Deployment
    • 备份 etcd
    • 在备份之后创建 Deployment
    • 停止服务
    • 停止 etcd
    • 恢复 etcd
    • 启动服务
    • 验证

    etcd备份和恢复

    安装etcdctl

    下载etcd安装包。

    wget https://github.com/etcd-io/etcd/releases/download/v3.5.3/etcd-v3.5.3-linux-amd64.tar.gz
    +

    解压etcd安装包,并赋予执行权限。

    tar -zxvf etcd-v3.5.3-linux-amd64.tar.gz
    +cp etcd-v3.5.3-linux-amd64/etcdctl /usr/local/bin/
    +sudo chmod u+x /usr/local/bin/etcdctl
    +

    验证:

    etcdctl --help
    +

    创建一个deployment(备份前)

    备份前创建一个deployment。

    kubectl create deployment app-before-backup --image=nginx
    +

    备份etcd

    说明:

    • <CONTROL_PLANE_IP_ADDRESS> 是控制平面节点的实际IP地址。
    • --endpoints:指定 etcd 备份的保存位置,2379 是 etcd 的端口号。
    • --cert:指定 etcd 证书的位置,证书是由 kubeadm 生成并保存在 /etc/kubernetes/pki/etcd/ 目录下的。
    • --key:指定 etcd 证书的私钥的位置,证书是由 kubeadm 生成并保存在 /etc/kubernetes/pki/etcd/ 目录下的。
    • --cacert:指定 etcd 证书的 CA 的位置,证书是由 kubeadm 生成并保存在 /etc/kubernetes/pki/etcd/ 目录下的。
    etcdctl \
    +  --endpoints=https://<CONTROL_PLANE_IP_ADDRESS>:2379 \
    +  --cert=/etc/kubernetes/pki/etcd/server.crt \
    +  --key=/etc/kubernetes/pki/etcd/server.key \
    +  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
    +  snapshot save snapshot-$(date +"%Y%m%d%H%M%S").db
    +

    或者

    etcdctl \
    +  --endpoints=https://<cka001_ip>:2379 \
    +  --cert=/etc/kubernetes/pki/etcd/server.crt \
    +  --key=/etc/kubernetes/pki/etcd/server.key \
    +  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
    +  snapshot save snapshot-$(date +"%Y%m%d%H%M%S").db
     

    Output:

    {"level":"info","ts":"2022-07-24T18:51:21.328+0800","caller":"snapshot/v3_snapshot.go:65","msg":"created temporary db file","path":"snapshot-20220724185121.db.part"}
     {"level":"info","ts":"2022-07-24T18:51:21.337+0800","logger":"client","caller":"v3/maintenance.go:211","msg":"opened snapshot stream; downloading"}
     {"level":"info","ts":"2022-07-24T18:51:21.337+0800","caller":"snapshot/v3_snapshot.go:73","msg":"fetching snapshot","endpoint":"https://<cka001_ip>:2379"}
    @@ -23,46 +23,46 @@
     {"level":"info","ts":"2022-07-24T18:51:21.477+0800","caller":"snapshot/v3_snapshot.go:88","msg":"fetched snapshot","endpoint":"https://<cka001_ip>:2379","size":"3.6 MB","took":"now"}
     {"level":"info","ts":"2022-07-24T18:51:21.477+0800","caller":"snapshot/v3_snapshot.go:97","msg":"saved","path":"snapshot-20220724185121.db"}
     Snapshot saved at snapshot-20220724185121.db
    -

    执行命令ls -al在当前目录中读取我们刚刚创建的备份文件。

    -rw-------  1 root root 3616800 Jul 24 18:51 snapshot-20220724185121.db
    -

    创建一个deployment(备份后)

    备份后,我们创建另外一个deployment。

    kubectl create deployment app-after-backup --image=nginx
    -

    删除备份前我们创建的那个deployment。

    kubectl delete deployment app-before-backup
    -

    检查deployment的状态。

    kubectl get deploy
    +

    执行命令ls -al在当前目录中读取我们刚刚创建的备份文件。

    -rw-------  1 root root 3616800 Jul 24 18:51 snapshot-20220724185121.db
    +

    创建一个deployment(备份后)

    备份后,我们创建另外一个deployment。

    kubectl create deployment app-after-backup --image=nginx
    +

    删除备份前我们创建的那个deployment。

    kubectl delete deployment app-before-backup
    +

    检查deployment的状态。

    kubectl get deploy
     

    运行结果:

    NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
     app-after-backup         1/1     1            1           108s
    -

    停止Services

    删除etcd的目录。

    mv /var/lib/etcd/ /var/lib/etcd.bak
    -

    停止 kubelet

    systemctl stop kubelet
    -

    停止 kube-apiserver

    nerdctl -n k8s.io ps -a | grep apiserver
    +

    停止Services

    删除etcd的目录。

    mv /var/lib/etcd/ /var/lib/etcd.bak
    +

    停止 kubelet

    systemctl stop kubelet
    +

    停止 kube-apiserver

    nerdctl -n k8s.io ps -a | grep apiserver
     

    运行结果:

    0c5e69118f1b    registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0             "kube-apiserver --ad…"    32 hours ago    Up                  k8s://kube-system/kube-apiserver-cka001/kube-apiserver
     638bb602c310    registry.aliyuncs.com/google_containers/pause:3.6                          "/pause"                  32 hours ago    Up                  k8s://kube-system/kube-apiserver-cka001
    -

    停止那些仍旧处于 up 状态的容器。

    nerdctl -n k8s.io stop <container_id>
    +

    停止那些仍旧处于 up 状态的容器。

    nerdctl -n k8s.io stop <container_id>
     
    -nerdctl -n k8s.io stop 0c5e69118f1b
    -nerdctl -n k8s.io stop 638bb602c310
    -

    直至没有处于up状态的kube-apiserver

    nerdctl -n k8s.io ps -a | grep apiserver
    +nerdctl -n k8s.io stop 0c5e69118f1b
    +nerdctl -n k8s.io stop 638bb602c310
    +

    直至没有处于up状态的kube-apiserver

    nerdctl -n k8s.io ps -a | grep apiserver
     

    运行结果:

    0c5e69118f1b    registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0             "kube-apiserver --ad…"    32 hours ago    Created             k8s://kube-system/kube-apiserver-cka001/kube-apiserver
     638bb602c310    registry.aliyuncs.com/google_containers/pause:3.6                          "/pause"                  32 hours ago    Created             k8s://kube-system/kube-apiserver-cka001
    -

    停止etcd

    nerdctl -n k8s.io ps -a | grep etcd
    +

    停止etcd

    nerdctl -n k8s.io ps -a | grep etcd
     

    运行结果:

    0965b195f41a    registry.aliyuncs.com/google_containers/etcd:3.5.1-0                       "etcd --advertise-cl…"    32 hours ago    Up                  k8s://kube-system/etcd-cka001/etcd
     9e1bea9f25d1    registry.aliyuncs.com/google_containers/pause:3.6                          "/pause"                  32 hours ago    Up                  k8s://kube-system/etcd-cka001
    -

    停止那些仍旧处于 up 状态的容器。

    nerdctl -n k8s.io stop <container_id>
    +

    停止那些仍旧处于 up 状态的容器。

    nerdctl -n k8s.io stop <container_id>
     
    nerdctl -n k8s.io stop 0965b195f41a
     nerdctl -n k8s.io stop 9e1bea9f25d1
    -

    直至没有处于up状态的kube-apiserver

    nerdctl -n k8s.io ps -a | grep etcd
    +

    直至没有处于up状态的kube-apiserver

    nerdctl -n k8s.io ps -a | grep etcd
     

    运行结果:

    0965b195f41a    registry.aliyuncs.com/google_containers/etcd:3.5.1-0                       "etcd --advertise-cl…"    32 hours ago    Created             k8s://kube-system/etcd-cka001/etcd
     9e1bea9f25d1    registry.aliyuncs.com/google_containers/pause:3.6                          "/pause"                  32 hours ago    Created             k8s://kube-system/etcd-cka001
    -

    恢复etcd

    在控制平面节点上执行恢复操作,使用实际的备份文件,这里是文件 snapshot-20220724185121.db

    etcdctl snapshot restore snapshot-20220724185121.db \
    -    --endpoints=<cka001_ip>:2379 \
    -    --cert=/etc/kubernetes/pki/etcd/server.crt \
    -    --key=/etc/kubernetes/pki/etcd/server.key \
    -    --cacert=/etc/kubernetes/pki/etcd/ca.crt\
    -    --data-dir=/var/lib/etcd
    +

    恢复etcd

    在控制平面节点上执行恢复操作,使用实际的备份文件,这里是文件 snapshot-20220724185121.db

    etcdctl snapshot restore snapshot-20220724185121.db \
    +    --endpoints=<cka001_ip>:2379 \
    +    --cert=/etc/kubernetes/pki/etcd/server.crt \
    +    --key=/etc/kubernetes/pki/etcd/server.key \
    +    --cacert=/etc/kubernetes/pki/etcd/ca.crt\
    +    --data-dir=/var/lib/etcd
     

    运行结果:

    Deprecated: Use `etcdutl snapshot restore` instead.
     
     2022-07-24T18:57:49+08:00       info    snapshot/v3_snapshot.go:248     restoring snapshot      {"path": "snapshot-20220724185121.db", "wal-dir": "/var/lib/etcd/member/wal", "data-dir": "/var/lib/etcd", "snap-dir": "/var/lib/etcd/member/snap", "stack": "go.etcd.io/etcd/etcdutl/v3/snapshot.(*v3Manager).Restore\n\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/snapshot/v3_snapshot.go:254\ngo.etcd.io/etcd/etcdutl/v3/etcdutl.SnapshotRestoreCommandFunc\n\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/etcdutl/snapshot_command.go:147\ngo.etcd.io/etcd/etcdctl/v3/ctlv3/command.snapshotRestoreCommandFunc\n\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/command/snapshot_command.go:129\ngithub.com/spf13/cobra.(*Command).execute\n\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856\ngithub.com/spf13/cobra.(*Command).ExecuteC\n\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960\ngithub.com/spf13/cobra.(*Command).Execute\n\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:897\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.Start\n\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:107\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.MustStart\n\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:111\nmain.main\n\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/main.go:59\nruntime.main\n\t/go/gos/go1.16.15/src/runtime/proc.go:225"}
     2022-07-24T18:57:49+08:00       info    membership/store.go:141 Trimming membership information from the backend...
     2022-07-24T18:57:49+08:00       info    membership/cluster.go:421       added member    {"cluster-id": "cdf818194e3a8c32", "local-member-id": "0", "added-peer-id": "8e9e05c52164694d", "added-peer-peer-urls": ["http://localhost:2380"]}
     2022-07-24T18:57:49+08:00       info    snapshot/v3_snapshot.go:269     restored snapshot       {"path": "snapshot-20220724185121.db", "wal-dir": "/var/lib/etcd/member/wal", "data-dir": "/var/lib/etcd", "snap-dir": "/var/lib/etcd/member/snap"}
    -

    检查被删除的etcd目录是否已经从备份中恢复了。

    tree /var/lib/etcd
    +

    检查被删除的etcd目录是否已经从备份中恢复了。

    tree /var/lib/etcd
     

    运行结果:

    /var/lib/etcd
     └── member
         ├── snap
    @@ -70,10 +70,10 @@
         │   └── db
         └── wal
             └── 0000000000000000-0000000000000000.wal
    -

    启动服务Services

    启动 kubelet。服务 kube-apiserveretcd 也会继 kubelet 启动后被自动启动。

    systemctl start kubelet
    -

    执行下面命令确认所有服务都已经启动和正常运行。

    systemctl status kubelet.service
    -nerdctl -n k8s.io ps -a | grep etcd
    -nerdctl -n k8s.io ps -a | grep apiserver
    +

    启动服务Services

    启动 kubelet。服务 kube-apiserveretcd 也会继 kubelet 启动后被自动启动。

    systemctl start kubelet
    +

    执行下面命令确认所有服务都已经启动和正常运行。

    systemctl status kubelet.service
    +nerdctl -n k8s.io ps -a | grep etcd
    +nerdctl -n k8s.io ps -a | grep apiserver
     

    查看当前 etcd 的状态。

    0965b195f41a    registry.aliyuncs.com/google_containers/etcd:3.5.1-0                       "etcd --advertise-cl…"    32 hours ago     Created             k8s://kube-system/etcd-cka001/etcd
     3b8f37c87782    registry.aliyuncs.com/google_containers/etcd:3.5.1-0                       "etcd --advertise-cl…"    6 seconds ago    Up                  k8s://kube-system/etcd-cka001/etcd
     9e1bea9f25d1    registry.aliyuncs.com/google_containers/pause:3.6                          "/pause"                  32 hours ago     Created             k8s://kube-system/etcd-cka001
    @@ -82,11 +82,11 @@
     281cf4c6670d    registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0             "kube-apiserver --ad…"    14 seconds ago    Up                  k8s://kube-system/kube-apiserver-cka001/kube-apiserver
     5ed8295d92da    registry.aliyuncs.com/google_containers/pause:3.6                          "/pause"                  15 seconds ago    Up                  k8s://kube-system/kube-apiserver-cka001
     638bb602c310    registry.aliyuncs.com/google_containers/pause:3.6                          "/pause"                  32 hours ago      Created             k8s://kube-system/kube-apiserver-cka001
    -

    验证

    检查集群的状态,查看是否pod app-before-backup 存在。

    kubectl get deploy
    +

    验证

    检查集群的状态,查看是否pod app-before-backup 存在。

    kubectl get deploy
     

    运行结果:

    NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
     app-before-backup        1/1     1            1           11m
    -

    集群升级

    演示场景:集群升级

    • 驱逐控制平面节点
    • 检查当前可用的 kubeadm 版本
    • kubeadm 升级到新版本
    • 检查升级计划
    • 应用升级计划以升级到新版本
    • 升级 kubeletkubectl
    • 启用控制平面节点调度
    • 驱逐工作节点
    • 升级 kubeadmkubelet
    • 启用工作节点调度

    参考:kubeadm升级

    升级控制平面

    控制平面准备

    驱逐控制平面节点。

    kubectl drain <control_plane_node_name> --ignore-daemonsets 
    -

    这里是:

    kubectl drain cka001 --ignore-daemonsets 
    +

    集群升级

    演示场景:集群升级

    • 驱逐控制平面节点
    • 检查当前可用的 kubeadm 版本
    • kubeadm 升级到新版本
    • 检查升级计划
    • 应用升级计划以升级到新版本
    • 升级 kubeletkubectl
    • 启用控制平面节点调度
    • 驱逐工作节点
    • 升级 kubeadmkubelet
    • 启用工作节点调度

    参考:kubeadm升级

    升级控制平面

    控制平面准备

    驱逐控制平面节点。

    kubectl drain <control_plane_node_name> --ignore-daemonsets 
    +

    这里是:

    kubectl drain cka001 --ignore-daemonsets 
     

    运行结果:

    node/cka001 cordoned
     WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-dsx76, kube-system/kube-proxy-cm4hc
     evicting pod kube-system/calico-kube-controllers-5c64b68895-jr4nl
    @@ -96,12 +96,12 @@
     pod/coredns-6d8c4cb4d-g4jxc evicted
     pod/coredns-6d8c4cb4d-sqcvj evicted
     node/cka001 drained
    -

    控制平面节点现在处于 SchedulingDisabled 状态。

    kubectl get node -owide
    +

    控制平面节点现在处于 SchedulingDisabled 状态。

    kubectl get node -owide
     

    运行结果:

    NAME     STATUS                     ROLES                  AGE   VERSION   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
     cka001   Ready,SchedulingDisabled   control-plane,master   32h   v1.24.0   Ubuntu 20.04.4 LTS   5.4.0-122-generic   containerd://1.5.9
     cka002   Ready                      <none>                 32h   v1.24.0   Ubuntu 20.04.4 LTS   5.4.0-122-generic   containerd://1.5.9
     cka003   Ready                      <none>                 32h   v1.24.0   Ubuntu 20.04.4 LTS   5.4.0-122-generic   containerd://1.5.9
    -

    查询当前 kubeadm 可用版本。

    apt policy kubeadm
    +

    查询当前 kubeadm 可用版本。

    apt policy kubeadm
     

    输出结果:

    kubeadm:
       Installed: 1.24.0-00
       Candidate: 1.24.3-00
    @@ -122,8 +122,8 @@
          1.23.7-00 500
             500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages
     ......
    -

    升级 kubeadmCandidate: 1.24.2-00 版本。

    sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades
    -

    查询升级计划。

    kubeadm upgrade plan
    +

    升级 kubeadmCandidate: 1.24.2-00 版本。

    sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades
    +

    查询升级计划。

    kubeadm upgrade plan
     

    输出类似下面的升级计划。

    [upgrade/config] Making sure the configuration is correct:
     [upgrade/config] Reading configuration from the cluster...
     [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
    @@ -166,31 +166,31 @@
     kubeproxy.config.k8s.io   v1alpha1          v1alpha1            no
     kubelet.config.k8s.io     v1beta1           v1beta1             no
     _____________________________________________________________________
    -

    控制平面升级

    参考前面的升级计划,我们升级到 v1.24.2 版本。

    kubeadm upgrade apply v1.24.2
    -

    通过选项 --etcd-upgrade=false,我们把etcd排除出当前升级范围。

    kubeadm upgrade apply v1.24.2 --etcd-upgrade=false
    +

    控制平面升级

    参考前面的升级计划,我们升级到 v1.24.2 版本。

    kubeadm upgrade apply v1.24.2
    +

    通过选项 --etcd-upgrade=false,我们把etcd排除出当前升级范围。

    kubeadm upgrade apply v1.24.2 --etcd-upgrade=false
     

    收到下面的信息,则代表上面的升级命令成功了。

    [upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.24.2". Enjoy!
     
     [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so.
    -

    升级 kubeletkubectl

    sudo apt-get -y install kubelet=1.24.2-00 kubectl=1.24.2-00 --allow-downgrades
    -sudo systemctl daemon-reload
    -sudo systemctl restart kubelet
    -

    查询节点当前状态。

    kubectl get node
    +

    升级 kubeletkubectl

    sudo apt-get -y install kubelet=1.24.2-00 kubectl=1.24.2-00 --allow-downgrades
    +sudo systemctl daemon-reload
    +sudo systemctl restart kubelet
    +

    查询节点当前状态。

    kubectl get node
     

    运行结果:

    NAME     STATUS                     ROLES                  AGE   VERSION
     cka001   Ready,SchedulingDisabled   control-plane,master   32h   v1.24.2
     cka002   Ready                      <none>                 32h   v1.24.0
     cka003   Ready                      <none>                 32h   v1.24.0
    -

    After verify that each node is in Ready status, enable node scheduling.

    在确认所有节点都处于Ready状态,则激活scheduling。

    kubectl uncordon <control_plane_node_name>
    -

    这里是:

    kubectl uncordon cka001
    +

    After verify that each node is in Ready status, enable node scheduling.

    在确认所有节点都处于Ready状态,则激活scheduling。

    kubectl uncordon <control_plane_node_name>
    +

    这里是:

    kubectl uncordon cka001
     

    输出结果:

    node/cka001 uncordoned
    -

    再次检查节点状态,确保所有节点都处于Ready状态。

    kubectl get node
    +

    再次检查节点状态,确保所有节点都处于Ready状态。

    kubectl get node
     

    运行结果:

    NAME     STATUS   ROLES                  AGE   VERSION
     cka001   Ready    control-plane,master   32h   v1.24.2
     cka002   Ready    <none>                 32h   v1.24.0
     cka003   Ready    <none>                 32h   v1.24.0
    -

    升级工作节点

    工作节点准备

    登录节点 cka001。 驱逐 Worker 节点,需要显式指定是否删除本地存储。

    kubectl drain <worker_node_name> --ignore-daemonsets --force
    -kubectl drain <worker_node_name> --ignore-daemonsets --delete-emptydir-data --force
    -

    如果遇到关于 emptydir依赖的错误,则执行第二个命令。

    kubectl drain cka002 --ignore-daemonsets --force
    -kubectl drain cka002 --ignore-daemonsets --delete-emptydir-data --force
    +

    升级工作节点

    工作节点准备

    登录节点 cka001。 驱逐 Worker 节点,需要显式指定是否删除本地存储。

    kubectl drain <worker_node_name> --ignore-daemonsets --force
    +kubectl drain <worker_node_name> --ignore-daemonsets --delete-emptydir-data --force
    +

    如果遇到关于 emptydir依赖的错误,则执行第二个命令。

    kubectl drain cka002 --ignore-daemonsets --force
    +kubectl drain cka002 --ignore-daemonsets --delete-emptydir-data --force
     

    输出结果:

    node/cka002 cordoned
     WARNING: deleting Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet: dev/ubuntu; ignoring DaemonSet-managed Pods: kube-system/calico-node-p5rf2, kube-system/kube-proxy-zvs68
     evicting pod ns-netpol/pod-netpol-5b67b6b496-2cgnw
    @@ -210,53 +210,53 @@
     pod/pod-netpol-2-77478d77ff-l6rzm evicted
     pod/ubuntu evicted
     node/cka002 drained
    -

    工作节点升级

    登录节点 cka002

    下载 kubeadmv1.24.2版本。

    sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades
    -

    升级 kubeadm

    sudo kubeadm upgrade node
    -

    升级 kubelet

    sudo apt-get -y install kubelet=1.24.2-00 --allow-downgrades
    -sudo systemctl daemon-reload
    -sudo systemctl restart kubelet
    -

    确认所有节点都处于Ready状态,则激活scheduling。

    kubectl uncordon <worker_node_name>
    -

    这里是:

    kubectl uncordon cka002
    -

    工作节点验证

    查询节点状态。

    kubectl get node
    +

    工作节点升级

    登录节点 cka002

    下载 kubeadmv1.24.2版本。

    sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades
    +

    升级 kubeadm

    sudo kubeadm upgrade node
    +

    升级 kubelet

    sudo apt-get -y install kubelet=1.24.2-00 --allow-downgrades
    +sudo systemctl daemon-reload
    +sudo systemctl restart kubelet
    +

    确认所有节点都处于Ready状态,则激活scheduling。

    kubectl uncordon <worker_node_name>
    +

    这里是:

    kubectl uncordon cka002
    +

    工作节点验证

    查询节点状态。

    kubectl get node
     

    运行结果:

    NAME     STATUS   ROLES                  AGE   VERSION
     cka001   Ready    control-plane,master   32h   v1.24.2
     cka002   Ready    <none>                 32h   v1.24.2
     cka003   Ready    <none>                 32h   v1.24.0
    -

    在节点 cka003 上重复上面的步骤。

    登录节点 cka003。如果遇到关于 emptydir依赖的错误,则执行第二个命令。

    kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --force
    -kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --delete-emptydir-data --force
    -

    登录节点 cka003,执行下面的命令。

    sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades
    +

    在节点 cka003 上重复上面的步骤。

    登录节点 cka003。如果遇到关于 emptydir依赖的错误,则执行第二个命令。

    kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --force
    +kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --delete-emptydir-data --force
    +

    登录节点 cka003,执行下面的命令。

    sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades
     
    -sudo kubeadm upgrade node
    +sudo kubeadm upgrade node
     
    -sudo apt-get -y install kubelet=1.24.2-00 --allow-downgrades
    -sudo systemctl daemon-reload
    -sudo systemctl restart kubelet
    +sudo apt-get -y install kubelet=1.24.2-00 --allow-downgrades
    +sudo systemctl daemon-reload
    +sudo systemctl restart kubelet
     
    -kubectl get node
    -kubectl uncordon cka003
    -

    查询节点状态。

    kubectl get node
    +kubectl get node
    +kubectl uncordon cka003
    +

    查询节点状态。

    kubectl get node
     

    运行结果:

    NAME     STATUS   ROLES                  AGE   VERSION
     cka001   Ready    control-plane,master   32h   v1.24.2
     cka002   Ready    <none>                 32h   v1.24.2
     cka003   Ready    <none>                 32h   v1.24.2
    -

    总结

    在控制面板上的执行步骤:

    kubectl get node -owide
    -kubectl drain cka001 --ignore-daemonsets
    -kubectl get node -owide
    -apt policy kubeadm
    -apt-get -y install kubeadm=1.24.0-00 --allow-downgrades
    -kubeadm upgrade plan
    -kubeadm upgrade apply v1.24.0
    +

    总结

    在控制面板上的执行步骤:

    kubectl get node -owide
    +kubectl drain cka001 --ignore-daemonsets
    +kubectl get node -owide
    +apt policy kubeadm
    +apt-get -y install kubeadm=1.24.0-00 --allow-downgrades
    +kubeadm upgrade plan
    +kubeadm upgrade apply v1.24.0
     # kubeadm upgrade apply v1.24.0 --etcd-upgrade=false
    -apt-get -y install kubelet=1.24.0-00 kubectl=1.24.0-00 --allow-downgrades
    -systemctl daemon-reload
    -systemctl restart kubelet
    -kubectl get node
    -kubectl uncordon cka001
    -

    在工作节点上的执行步骤:

    • 在控制面板上:
    kubectl drain cka002 --ignore-daemonsets
    -
    • 在工作节点上:
    apt-get -y install kubeadm=1.24.1-00 --allow-downgrades
    -kubeadm upgrade node
    -apt-get -y install kubelet=1.24.1-00 --allow-downgrades
    -systemctl daemon-reload
    -systemctl restart kubelet
    -kubectl uncordon cka002
    -

    在其他工作节点上重复上面的步骤。

    \ No newline at end of file +apt-get -y install kubelet=1.24.0-00 kubectl=1.24.0-00 --allow-downgrades +systemctl daemon-reload +systemctl restart kubelet +kubectl get node +kubectl uncordon cka001 +

    在工作节点上的执行步骤:

    • 在控制面板上:
    kubectl drain cka002 --ignore-daemonsets
    +
    • 在工作节点上:
    apt-get -y install kubeadm=1.24.1-00 --allow-downgrades
    +kubeadm upgrade node
    +apt-get -y install kubelet=1.24.1-00 --allow-downgrades
    +systemctl daemon-reload
    +systemctl restart kubelet
    +kubectl uncordon cka002
    +

    在其他工作节点上重复上面的步骤。

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/configuration/index.html b/k8s/cka_cn/foundamentals/configuration/index.html index ac9ca07c..2793d3a9 100644 --- a/k8s/cka_cn/foundamentals/configuration/index.html +++ b/k8s/cka_cn/foundamentals/configuration/index.html @@ -1 +1 @@ - Configuration - UPSkilling

    CKA自学笔记15:Configuration

    \ No newline at end of file + Configuration - UPSkilling

    CKA自学笔记15:Configuration

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/daemonset/index.html b/k8s/cka_cn/foundamentals/daemonset/index.html index b6b87ed8..465bb962 100644 --- a/k8s/cka_cn/foundamentals/daemonset/index.html +++ b/k8s/cka_cn/foundamentals/daemonset/index.html @@ -1,4 +1,4 @@ - DaemonSet - UPSkilling

    CKA自学笔记13:DaemonSet

    演示场景

    • 创建一个DaemonSet
    • 创建的DaemonSet会在每个node节点上运行自己的pod。

    演示

    创建 DaemonSet daemonset-busybox

    kubectl apply -f - << EOF
    + DaemonSet - UPSkilling       

    CKA自学笔记13:DaemonSet

    演示场景

    • 创建一个DaemonSet
    • 创建的DaemonSet会在每个node节点上运行自己的pod。

    演示

    创建 DaemonSet daemonset-busybox

    kubectl apply -f - << EOF
     apiVersion: apps/v1
     kind: DaemonSet
     metadata:
    @@ -26,13 +26,13 @@
             - sleep
             - "10000"
     EOF
    -

    获取DaemonSet的运行状态。

    kubectl get daemonsets daemonset-busybox
    +

    获取DaemonSet的运行状态。

    kubectl get daemonsets daemonset-busybox
     

    运行结果

    NAME                DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
     daemonset-busybox   3         3         3       3            3           <none>          5m33s
    -

    获取 DaemonSet 的 Pod 的状态。这些pod会部署在每个节点node上。

    kubectl get pod -o wide
    -

    运行结果

    NAME                      READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
    -daemonset-busybox-54cj5   1/1     Running   0          44s   10.244.102.4     cka003   <none>           <none>
    -daemonset-busybox-5tl55   1/1     Running   0          44s   10.244.228.197   cka001   <none>           <none>
    -daemonset-busybox-wg225   1/1     Running   0          44s   10.244.112.5     cka002   <none>           <none>
    -

    删除所创建的资源。

    kubectl delete daemonset daemonset-busybox 
    -
    \ No newline at end of file +

    获取 DaemonSet 的 Pod 的状态。这些pod会部署在每个节点node上。

    kubectl get pod -o wide
    +

    运行结果

    NAME                      READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
    +daemonset-busybox-54cj5   1/1     Running   0          44s   10.244.102.4     cka003   <none>           <none>
    +daemonset-busybox-5tl55   1/1     Running   0          44s   10.244.228.197   cka001   <none>           <none>
    +daemonset-busybox-wg225   1/1     Running   0          44s   10.244.112.5     cka002   <none>           <none>
    +

    删除所创建的资源。

    kubectl delete daemonset daemonset-busybox 
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/deployment/index.html b/k8s/cka_cn/foundamentals/deployment/index.html index 2ded85ee..644ec7cc 100644 --- a/k8s/cka_cn/foundamentals/deployment/index.html +++ b/k8s/cka_cn/foundamentals/deployment/index.html @@ -1,38 +1,38 @@ - Deployment - UPSkilling

    CKA自学笔记9:Deployment

    摘要

    修改已有的Deployment,比如,增加端口号等。

    演示

    创建Deployment nginx

    kubectl create deployment nginx --image=nginx
    -

    执行以下命令以获取带有端口号的yaml模板。 选项 --port=8080 指定了该容器暴露的端口号。

    kubectl create deployment nginx --image=nginx --port=8080 --dry-run=client -o yaml
    -

    这样我们就知道了添加端口号的路径,就像下面这样:

    kubectl explain deployment.spec.template.spec.containers.ports.containerPort
    -

    执行下面的命令来修改当前正在运行的Deployment。

    kubectl edit deployment nginx
    -

    添加下面2行来制定8080端口和TCP协议。

    spec:
    -  template:
    -    spec:
    -      containers:
    -      - image: nginx
    -        name: nginx
    -        ports:
    -        - containerPort: 8080
    -          protocol: TCP
    -

    通过命令 kubectl describe deployment <deployment_name>我们可以看到在Deployment中端口号和协议已经被正确添加了。

    Pod Template:
    -  Labels:  app=nginx
    -  Containers:
    -   nginx:
    -    Image:        nginx
    -    Port:         8080/TCP
    -    Host Port:    0/TCP
    -    Environment:  <none>
    -    Mounts:       <none>
    -  Volumes:        <none>
    -

    通过命令 kubectl describe pod <pod_name> 我们可以看到在pod中端口号和协议已经被正确添加了。

    Containers:
    -  nginx:
    -    Container ID:   containerd://af4a1243f981497074b5c006ac55fcf795688399871d1dfe91a095321f5c91aa
    -    Image:          nginx
    -    Image ID:       docker.io/library/nginx@sha256:1761fb5661e4d77e107427d8012ad3a5955007d997e0f4a3d41acc9ff20467c7
    -    Port:           8080/TCP
    -    Host Port:      0/TCP
    -    State:          Running
    -      Started:      Sun, 24 Jul 2022 22:50:12 +0800
    -    Ready:          True
    -    Restart Count:  0
    -    Environment:    <none>
    -    Mounts:
    -      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hftdt (ro)
    -

    以下是Deployment的一些关键字段(使用 kubectl explain ):

    • deployment.spec.revisionHistoryLimit:保留旧的ReplicaSets的数量,以便进行回滚。默认为 10
    • deployment.spec.strategy.type:部署的类型。可以是 RecreateRollingUpdate。默认为 RollingUpdate
    • deployment.spec.strategy.rollingUpdate.maxUnavailable:在更新期间可以不可用的Pod的最大数量。默认为25%
    • deployment.spec.strategy.rollingUpdate.maxSurge:可以安排的Pod数量超出所需Pod数量的最大值。默认为25%。如果 MaxUnavailable0,则此值不能为 0
    • deployment.spec.minReadySeconds:新创建的Pod的最小准备时间(所有容器都没有崩溃),以便被视为可用。默认为0(一旦准备好就会被视为可用)。
    \ No newline at end of file + Deployment - UPSkilling

    CKA自学笔记9:Deployment

    摘要

    修改已有的Deployment,比如,增加端口号等。

    演示

    创建Deployment nginx

    kubectl create deployment nginx --image=nginx
    +

    执行以下命令以获取带有端口号的yaml模板。 选项 --port=8080 指定了该容器暴露的端口号。

    kubectl create deployment nginx --image=nginx --port=8080 --dry-run=client -o yaml
    +

    这样我们就知道了添加端口号的路径,就像下面这样:

    kubectl explain deployment.spec.template.spec.containers.ports.containerPort
    +

    执行下面的命令来修改当前正在运行的Deployment。

    kubectl edit deployment nginx
    +

    添加下面2行来制定8080端口和TCP协议。

    spec:
    +  template:
    +    spec:
    +      containers:
    +      - image: nginx
    +        name: nginx
    +        ports:
    +        - containerPort: 8080
    +          protocol: TCP
    +

    通过命令 kubectl describe deployment <deployment_name>我们可以看到在Deployment中端口号和协议已经被正确添加了。

    Pod Template:
    +  Labels:  app=nginx
    +  Containers:
    +   nginx:
    +    Image:        nginx
    +    Port:         8080/TCP
    +    Host Port:    0/TCP
    +    Environment:  <none>
    +    Mounts:       <none>
    +  Volumes:        <none>
    +

    通过命令 kubectl describe pod <pod_name> 我们可以看到在pod中端口号和协议已经被正确添加了。

    Containers:
    +  nginx:
    +    Container ID:   containerd://af4a1243f981497074b5c006ac55fcf795688399871d1dfe91a095321f5c91aa
    +    Image:          nginx
    +    Image ID:       docker.io/library/nginx@sha256:1761fb5661e4d77e107427d8012ad3a5955007d997e0f4a3d41acc9ff20467c7
    +    Port:           8080/TCP
    +    Host Port:      0/TCP
    +    State:          Running
    +      Started:      Sun, 24 Jul 2022 22:50:12 +0800
    +    Ready:          True
    +    Restart Count:  0
    +    Environment:    <none>
    +    Mounts:
    +      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hftdt (ro)
    +

    以下是Deployment的一些关键字段(使用 kubectl explain ):

    • deployment.spec.revisionHistoryLimit:保留旧的ReplicaSets的数量,以便进行回滚。默认为 10
    • deployment.spec.strategy.type:部署的类型。可以是 RecreateRollingUpdate。默认为 RollingUpdate
    • deployment.spec.strategy.rollingUpdate.maxUnavailable:在更新期间可以不可用的Pod的最大数量。默认为25%
    • deployment.spec.strategy.rollingUpdate.maxSurge:可以安排的Pod数量超出所需Pod数量的最大值。默认为25%。如果 MaxUnavailable0,则此值不能为 0
    • deployment.spec.minReadySeconds:新创建的Pod的最小准备时间(所有容器都没有崩溃),以便被视为可用。默认为0(一旦准备好就会被视为可用)。
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/docker/index.html b/k8s/cka_cn/foundamentals/docker/index.html index e54e9feb..f445a977 100644 --- a/k8s/cka_cn/foundamentals/docker/index.html +++ b/k8s/cka_cn/foundamentals/docker/index.html @@ -1,4 +1,4 @@ - Docker基础 - UPSkilling

    CKA自学笔记4:Docker基础

    摘要

    了解Linux原语的概念和包含的特性。

    安装Docker,了解基本的Docker命令和Dockerfile的使用。

    练习环境

    操作系统:openSUSE 15.3

    cat /etc/os-release
    + Docker基础 - UPSkilling       

    CKA自学笔记4:Docker基础

    摘要

    了解Linux原语的概念和包含的特性。

    安装Docker,了解基本的Docker命令和Dockerfile的使用。

    练习环境

    操作系统:openSUSE 15.3

    cat /etc/os-release
     

    输出结果:

    NAME="openSUSE Leap"
     VERSION="15.3"
     ID="opensuse-leap"
    @@ -9,166 +9,166 @@
     CPE_NAME="cpe:/o:opensuse:leap:15.3"
     BUG_REPORT_URL="https://bugs.opensuse.org"
     HOME_URL="https://www.opensuse.org/"
    -

    Linux原语

    在操作系统中,原语(primitives)是用于创建更复杂功能的基本构建块或操作。在Linux中,有几种常用的原语。包括:

    • 进程(Processes):进程是程序或应用程序的运行实例。它们是Linux中的基本工作单元,由内核管理。

    • 文件(Files):文件是在Linux中存储数据的主要方式。它们可以是文本文件、二进制文件、目录或特殊文件,如设备文件。

    • 信号(Signals):信号是进程之间或进程与内核之间通信的一种方式。它们用于通知进程事件,例如任务完成或错误发生的情况。

    • 套接字(Sockets):套接字是Linux中进程间通信的一种方式。它们允许进程在网络或本地机器上发送和接收数据。

    • 线程(Threads):线程是轻量级的进程,与其父进程共享相同的内存空间和资源。它们通常用于通过允许同时执行多个任务来提高应用程序的性能。

    • 管道(Pipes):管道是一种将一个进程的输出连接到另一个进程的输入的方式。它们允许进程以受控的方式进行通信和交换数据。

    • 信号量(Semaphores):信号量是Linux中控制对共享资源访问的一种方式。它们允许进程协调它们对共享资源的访问,如文件或内存。

    chroot

    chroot使用pivot_root,以实现将*进程*的根目录更改为任何给定的目录。

    a. 模拟容器

    使用chroot命令可以在Linux系统中创建一个容器。该容器可以看作是一个虚拟的根文件系统,其中运行的进程只能访问该根文件系统中的资源。

    例如,以下命令会将当前根文件系统更改为/tmp/myroot目录:

    chroot /tmp/myroot /bin/bash
    -

    这条命令会启动一个新的Bash shell,该shell的根目录为/tmp/myroot

    b. 更改根文件系统

    chroot命令还可用于更改进程的根文件系统。例如,我们可以使用chroot命令启动一个具有另一个根文件系统的进程,而不是系统的默认根文件系统。

    例如,以下命令会将当前目录(即./)作为根目录,并在其中启动一个新的Bash shell:

    sudo chroot . /bin/bash
    +

    Linux原语

    在操作系统中,原语(primitives)是用于创建更复杂功能的基本构建块或操作。在Linux中,有几种常用的原语。包括:

    • 进程(Processes):进程是程序或应用程序的运行实例。它们是Linux中的基本工作单元,由内核管理。

    • 文件(Files):文件是在Linux中存储数据的主要方式。它们可以是文本文件、二进制文件、目录或特殊文件,如设备文件。

    • 信号(Signals):信号是进程之间或进程与内核之间通信的一种方式。它们用于通知进程事件,例如任务完成或错误发生的情况。

    • 套接字(Sockets):套接字是Linux中进程间通信的一种方式。它们允许进程在网络或本地机器上发送和接收数据。

    • 线程(Threads):线程是轻量级的进程,与其父进程共享相同的内存空间和资源。它们通常用于通过允许同时执行多个任务来提高应用程序的性能。

    • 管道(Pipes):管道是一种将一个进程的输出连接到另一个进程的输入的方式。它们允许进程以受控的方式进行通信和交换数据。

    • 信号量(Semaphores):信号量是Linux中控制对共享资源访问的一种方式。它们允许进程协调它们对共享资源的访问,如文件或内存。

    chroot

    chroot使用pivot_root,以实现将*进程*的根目录更改为任何给定的目录。

    a. 模拟容器

    使用chroot命令可以在Linux系统中创建一个容器。该容器可以看作是一个虚拟的根文件系统,其中运行的进程只能访问该根文件系统中的资源。

    例如,以下命令会将当前根文件系统更改为/tmp/myroot目录:

    chroot /tmp/myroot /bin/bash
    +

    这条命令会启动一个新的Bash shell,该shell的根目录为/tmp/myroot

    b. 更改根文件系统

    chroot命令还可用于更改进程的根文件系统。例如,我们可以使用chroot命令启动一个具有另一个根文件系统的进程,而不是系统的默认根文件系统。

    例如,以下命令会将当前目录(即./)作为根目录,并在其中启动一个新的Bash shell:

    sudo chroot . /bin/bash
     

    命名空间

    在Linux操作系统中,Namespace(命名空间)是一种机制,用于隔离不同进程的资源。通过Namespace机制,可以将一组进程及其子进程的视图隔离在一个独立的Namespace中,从而实现进程之间资源隔离的目的。

    下面是一些常见的Namespace类型及其作用:

    1. Mount Namespace:隔离文件系统挂载点。可以使不同进程拥有自己的独立的文件系统视图。

    2. PID Namespace:隔离进程ID号。可以使不同进程拥有自己的进程ID号空间,避免进程之间的PID冲突。

    3. Network Namespace:隔离网络栈。可以使不同进程拥有自己的独立的网络栈,从而避免进程之间的网络冲突。

    4. IPC Namespace:隔离进程间通信(IPC)机制。可以使不同进程拥有自己的独立的IPC空间,从而避免IPC机制带来的资源竞争。

    5. UTS Namespace:隔离主机名和域名。可以使不同进程拥有自己的独立的主机名和域名空间,从而避免进程之间的命名冲突。

    Primitives namespace和Namespace是两个不同的概念。

    Namespace是Linux操作系统提供的一种机制,用于隔离不同进程的资源,以实现进程之间的资源隔离和环境隔离。例如,PID Namespace可以使不同进程拥有自己的独立的PID号空间,避免进程之间的PID冲突;Network Namespace可以使不同进程拥有自己的独立的网络栈,从而避免进程之间的网络冲突等。

    Primitives namespace是一种新的技术概念,它是指将不同的基本操作(例如读写文件、创建进程、网络通信等)作为原语进行隔离和封装,使得应用程序可以在这些隔离的原语上构建出自己的隔离环境。例如,可以通过隔离文件系统读写操作来实现容器级别的文件系统隔离;通过隔离网络通信操作来实现容器级别的网络隔离等。

    因此,Namespace和Primitives namespace是两个不同的概念,虽然它们都可以用于实现隔离和封装的功能,但是Namespace是一种更为通用和底层的机制,Primitives namespace是一种更为高层的抽象概念,通常用于构建容器等应用级别的隔离环境。

    Namespace示例:

    在Linux系统中,可以使用PID Namespace来隔离进程ID号空间,避免进程之间的PID冲突。下面是一个简单的示例:

    # 创建一个新的PID Namespace
    -unshare -p /bin/bash
    +unshare -p /bin/bash
     
     # 在新的PID Namespace中运行一个进程
    -echo $$ # 显示当前进程的PID
    -ps aux # 显示当前进程及其子进程
    +echo $$ # 显示当前进程的PID
    +ps aux # 显示当前进程及其子进程
     

    在上面的示例中,unshare -p命令创建了一个新的PID Namespace,并在其中启动了一个新的bash进程。由于该进程运行在一个独立的PID Namespace中,因此它的PID号与主机上的其他进程不会冲突。在这个新的bash进程中,$$命令显示的是该进程在PID Namespace中的PID号,而ps aux命令只会显示当前PID Namespace中的进程,不会显示主机上的其他进程。

    Primitives Namespace示例:

    在Docker容器中,可以使用Filesystem Namespace来隔离文件系统,使得不同的容器之间拥有独立的文件系统视图。下面是一个简单的示例:

    # 在容器中运行一个命令
    -docker run --rm -it --name mycontainer ubuntu bash
    +docker run --rm -it --name mycontainer ubuntu bash
     
     # 在容器中创建一个文件并退出
    -touch myfile
    +touch myfile
     exit
     
     # 在主机上查看文件
    -ls myfile # myfile文件不存在
    +ls myfile # myfile文件不存在
     
     # 再次进入容器
    -docker start -i mycontainer
    +docker start -i mycontainer
     
     # 在容器中查看文件
    -ls myfile # myfile文件存在
    -

    在上面的示例中,docker run命令启动了一个新的Docker容器,并在其中运行了一个bash进程。由于该容器使用了Filesystem Namespace,因此容器内的文件系统视图与主机上的文件系统视图是隔离的。在容器内创建的文件myfile只存在于容器内部,在主机上是看不到的。当再次进入容器时,myfile文件就可以被看到了。

    总结:

    Namespace是Linux内核提供的机制,而Primitives Namespace则是一种基于Namespace的高层抽象,用于实现应用级别的隔离和封装。Namespace可以用于隔离多种资源,而Primitives Namespace通常用于隔离文件系统、网络、进程等操作的原语。

    控制组

    cgroup,全称为Control Group,即控制组,是Linux内核提供的一种机制,用于限制、记录、隔离和优先级控制一组进程的资源使用。它可以限制进程组的CPU、内存、磁盘、网络等资源的使用,同时也可以记录进程组的资源使用情况和行为。

    cgroup通过将一组进程组织成一个层次结构,将资源分配给不同的cgroup来实现资源限制和优先级控制。每个cgroup可以设置资源限制和控制策略,例如可以限制一个进程组最多使用50%的CPU时间,或者限制一个进程组最多使用100MB的内存等。

    cgroup最初由Google公司开发,后来被Linux内核社区采纳并加入到内核中,成为Linux系统的一部分。它在容器技术、虚拟化、云计算等领域都有广泛的应用。

    下面是cgroup 的一些常见用途:

    1. CPU 限制:使用 cgroup 可以限制进程的 CPU 使用率,避免某个进程占用过多的 CPU 资源导致系统负载过高,从而影响系统稳定性和其他进程的正常运行。

    2. 内存限制:使用 cgroup 可以限制进程的内存使用量,避免某个进程占用过多的内存资源导致系统内存不足,从而影响系统性能和其他进程的正常运行。

    3. IO 限制:使用 cgroup 可以限制进程的 IO 带宽,避免某个进程占用过多的 IO 资源导致其他进程的 IO 操作受到影响,从而影响系统性能和响应速度。

    4. 网络限制:使用 cgroup 可以限制进程的网络带宽,避免某个进程占用过多的网络资源导致网络拥塞,从而影响系统性能和其他进程的正常运行。

    5. 进程控制:使用 cgroup 可以限制进程的启动、停止和调度等行为,从而实现对系统进程的控制和管理。

    6. 资源统计:使用 cgroup 可以实时统计系统中各个进程的资源使用情况,从而帮助管理员了解系统负载状况和各个进程的性能瓶颈,从而采取相应的措施优化系统性能。

    下面是openSUSE中的示例:

    安装需要的软件包:

    sudo zypper install libcgroup-tools
    +ls myfile # myfile文件存在
    +

    在上面的示例中,docker run命令启动了一个新的Docker容器,并在其中运行了一个bash进程。由于该容器使用了Filesystem Namespace,因此容器内的文件系统视图与主机上的文件系统视图是隔离的。在容器内创建的文件myfile只存在于容器内部,在主机上是看不到的。当再次进入容器时,myfile文件就可以被看到了。

    总结:

    Namespace是Linux内核提供的机制,而Primitives Namespace则是一种基于Namespace的高层抽象,用于实现应用级别的隔离和封装。Namespace可以用于隔离多种资源,而Primitives Namespace通常用于隔离文件系统、网络、进程等操作的原语。

    控制组

    cgroup,全称为Control Group,即控制组,是Linux内核提供的一种机制,用于限制、记录、隔离和优先级控制一组进程的资源使用。它可以限制进程组的CPU、内存、磁盘、网络等资源的使用,同时也可以记录进程组的资源使用情况和行为。

    cgroup通过将一组进程组织成一个层次结构,将资源分配给不同的cgroup来实现资源限制和优先级控制。每个cgroup可以设置资源限制和控制策略,例如可以限制一个进程组最多使用50%的CPU时间,或者限制一个进程组最多使用100MB的内存等。

    cgroup最初由Google公司开发,后来被Linux内核社区采纳并加入到内核中,成为Linux系统的一部分。它在容器技术、虚拟化、云计算等领域都有广泛的应用。

    下面是cgroup 的一些常见用途:

    1. CPU 限制:使用 cgroup 可以限制进程的 CPU 使用率,避免某个进程占用过多的 CPU 资源导致系统负载过高,从而影响系统稳定性和其他进程的正常运行。

    2. 内存限制:使用 cgroup 可以限制进程的内存使用量,避免某个进程占用过多的内存资源导致系统内存不足,从而影响系统性能和其他进程的正常运行。

    3. IO 限制:使用 cgroup 可以限制进程的 IO 带宽,避免某个进程占用过多的 IO 资源导致其他进程的 IO 操作受到影响,从而影响系统性能和响应速度。

    4. 网络限制:使用 cgroup 可以限制进程的网络带宽,避免某个进程占用过多的网络资源导致网络拥塞,从而影响系统性能和其他进程的正常运行。

    5. 进程控制:使用 cgroup 可以限制进程的启动、停止和调度等行为,从而实现对系统进程的控制和管理。

    6. 资源统计:使用 cgroup 可以实时统计系统中各个进程的资源使用情况,从而帮助管理员了解系统负载状况和各个进程的性能瓶颈,从而采取相应的措施优化系统性能。

    下面是openSUSE中的示例:

    安装需要的软件包:

    sudo zypper install libcgroup-tools
     

    限制CPU使用上限:

    # 创建新的cgroup 'mygroup'
    -sudo mkdir /sys/fs/cgroup/cpu/mygroup
    +sudo mkdir /sys/fs/cgroup/cpu/mygroup
     
     # 系统会创建默认的一些文件,含初始值,比如CPU使用时间的限额的默认值是-1
    -cat /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us
    +cat /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us
     
     # 设定CPU使用时间上限
    -sudo sh -c "echo 50000 > /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us"
    +sudo sh -c "echo 50000 > /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us"
     
     # 启动一个新的进程,并且关联到
    -sudo cgcreate -g cpu:mygroup
    -sudo cgexec -g cpu:mygroup /bin/bash
    +sudo cgcreate -g cpu:mygroup
    +sudo cgexec -g cpu:mygroup /bin/bash
     

    在上面的例子中,cpu.cfs_quota_us 文件设置了 cgroup 中的进程可以使用的最大 CPU 时间。该值以微秒为单位,因此将其设置为 50000 表示进程最多可以使用单个 CPU 核心的 50%。cgcreatecgexec命令创建并将进程/bin/bash移动到 mygroupcgroup 中。

    限制内存使用上限:

    # 创建新的cgroup 'mygroup'
    -sudo mkdir /sys/fs/cgroup/memory/mygroup
    +sudo mkdir /sys/fs/cgroup/memory/mygroup
     
     # 系统会创建默认的一些文件,含初始值,比如内存使用上限的默认值是9223372036854771712
    -cat /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes
    +cat /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes
     
     # 设置内存使用上限512MB
    -sudo sh -c "echo 536870912 > /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes"
    +sudo sh -c "echo 536870912 > /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes"
     
     # 启动一个新的进程,并且关联到'mygroup'
    -sudo cgcreate -g memory:mygroup
    -sudo cgexec -g memory:mygroup /bin/bash
    +sudo cgcreate -g memory:mygroup
    +sudo cgexec -g memory:mygroup /bin/bash
     

    在上面例子中,memory.limit_in_bytes 文件设置了 cgroup 中进程可以使用的最大内存量。该值以字节为单位,因此将其设置为 536870912 表示进程最多可以使用 512MB 的内存。

    设置优先进程的 I/O 使用率:

    # 创建新cgroup 'mygroup'
    -sudo mkdir /sys/fs/cgroup/blkio/mygroup
    +sudo mkdir /sys/fs/cgroup/blkio/mygroup
     
     # 设置进程最大读和写的速率10MB/s
    -sudo sh -c "echo '8:0 10485760' > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.read_bps_device"
    -sudo sh -c "echo '8:0 10485760' > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.write_bps_device"
    +sudo sh -c "echo '8:0 10485760' > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.read_bps_device"
    +sudo sh -c "echo '8:0 10485760' > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.write_bps_device"
     
     # 启动一个新的进程,并且关联到'mygroup'
    -sudo cgcreate -g blkio:mygroup
    -sudo cgexec -g blkio:mygroup /bin/bash
    +sudo cgcreate -g blkio:mygroup
    +sudo cgexec -g blkio:mygroup /bin/bash
     

    在上面例子中,blkio.throttle.read_bps_deviceblkio.throttle.write_bps_device文件设置了cgroup中进程可以使用的最大读取和写入带宽。该值以每秒字节数为单位,因此将其设置为10485760意味着进程在主设备号:次设备号为8:0的设备(通常是第一个硬盘)上读取或写入的带宽最多为10MB/s。

    8:0 10485760 这个字符串写入到 /sys/fs/cgroup/blkio/mygroup/blkio.throttle.read_bps_device 文件中的作用是限制 mygroup 控制组中关联的块设备(block device)的读取速率。

    在 Linux 中,blkio 控制组子系统可以用来对进程或线程的块设备访问进行限制,如限制读写速率、I/O 优先级等。而 blkio.throttle.read_bps_device 这个文件则用于设置某个块设备的读取速率限制。

    具体来说,8:0 表示设备的主次编号(major:minor),这里是指磁盘 /dev/sda10485760 则是读取速率的限制值,单位是字节/秒。这个值表示 /dev/sda 最大读取速率为 10MB/s,超过这个速率的读取请求会被延迟执行,从而限制了磁盘的读取带宽。

    因此,以上命令的含义是将 mygroup 控制组中关联的 /dev/sda 磁盘的读取速率限制为 10MB/s,从而实现对该控制组中进程或线程对磁盘读取的限制。

    同理,将 8:0 10485760 这个字符串写入到 /sys/fs/cgroup/blkio/mygroup/blkio.throttle.write_bps_device 文件中,以限制 mygroup 控制组中关联的块设备(block device)的写入速率。

    限制一组进程的网络带宽:

    # 创建新的cgroup 'mygroup'
    -sudo mkdir /sys/fs/cgroup/net_cls/mygroup
    +sudo mkdir /sys/fs/cgroup/net_cls/mygroup
     
     # 将此组中的进程的网络类ID设置为“myclass”
    -sudo sh -c "echo 0x10001 > /sys/fs/cgroup/net_cls/mygroup/net_cls.classid"
    -

    上面的例子是将 0x10001 这个十六进制数值写入到/sys/fs/cgroup/net_cls/mygroup/net_cls.classid 文件中,以指定 mygroup 控制组的网络类别标识符(classid)。

    网络类别标识符是 Linux 内核中用来实现流量控制和流量分类的一个机制,它可以将数据包按照不同的类别(class)进行标记和区分,然后在网络设备上针对不同的类别进行不同的处理,如限速、优先级调整等。控制组中的 net_cls 子系统可以用来将进程或线程与网络类别标识符关联起来,从而实现对它们的网络流量进行控制和分类。

    因此,以上命令是将 mygroup 控制组的网络类别标识符设置为 0x10001,这样与该控制组相关联的进程或线程就会被标记为该类别,然后可以通过其他工具(如 tc 命令)对其进行网络流量控制和分类。

    如果遇到对应限制文件不存在,一种可能是需要检查cgroup子系有没有正确统载或者没有启用内存子系统。

    mount | grep cgroup
    +sudo sh -c "echo 0x10001 > /sys/fs/cgroup/net_cls/mygroup/net_cls.classid"
    +

    上面的例子是将 0x10001 这个十六进制数值写入到/sys/fs/cgroup/net_cls/mygroup/net_cls.classid 文件中,以指定 mygroup 控制组的网络类别标识符(classid)。

    网络类别标识符是 Linux 内核中用来实现流量控制和流量分类的一个机制,它可以将数据包按照不同的类别(class)进行标记和区分,然后在网络设备上针对不同的类别进行不同的处理,如限速、优先级调整等。控制组中的 net_cls 子系统可以用来将进程或线程与网络类别标识符关联起来,从而实现对它们的网络流量进行控制和分类。

    因此,以上命令是将 mygroup 控制组的网络类别标识符设置为 0x10001,这样与该控制组相关联的进程或线程就会被标记为该类别,然后可以通过其他工具(如 tc 命令)对其进行网络流量控制和分类。

    如果遇到对应限制文件不存在,一种可能是需要检查cgroup子系有没有正确统载或者没有启用内存子系统。

    mount | grep cgroup
     

    如果 cgroups 文件系统已经挂载,应该会看到输出类似于以下内容()以memory为例):

    cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)
     

    如果没有看到 memory 字段,则表示内存子系统没有启用。可以编辑/etc/default/grub 文件,添加或修改以下行:

    GRUB_CMDLINE_LINUX_DEFAULT="cgroup_enable=memory"
    -

    然后更新 GRUB 配置并重启系统:

    sudo update-grub
    -sudo reboot
    -

    重启后再次检查 /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes 文件是否存在。如果还是不存在,可能需要手动创建它以及其他相关的 cgroups 文件。例如,运行以下命令:

    sudo mkdir /sys/fs/cgroup/memory/mygroup
    -sudo touch /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes
    -

    然后就可以像之前的例子一样设置内存限制了

    Apparmor和SELinux配置文件

    • 安全配置文件,用于控制对资源的访问

    AppArmor 和 SELinux 都是常见的强制访问控制(MAC)机制,可以对进程或应用程序的访问权限进行精细控制。下面分别举例说明这两种机制的配置文件使用。

    1. AppArmor

    AppArmor 的主配置文件是 /etc/apparmor/profiles.d/ 目录下的各个文件,每个文件对应一个应用程序或进程的配置。以 sshd 服务为例,该服务的配置文件是/etc/apparmor.d/usr.sbin.sshd

    该配置文件的内容类似于下面这样:

    # Last Modified: Sun Mar 14 18:53:00 2023
    -#include <tunables/global>
    +

    然后更新 GRUB 配置并重启系统:

    sudo update-grub
    +sudo reboot
    +

    重启后再次检查 /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes 文件是否存在。如果还是不存在,可能需要手动创建它以及其他相关的 cgroups 文件。例如,运行以下命令:

    sudo mkdir /sys/fs/cgroup/memory/mygroup
    +sudo touch /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes
    +

    然后就可以像之前的例子一样设置内存限制了

    Apparmor和SELinux配置文件

    • 安全配置文件,用于控制对资源的访问

    AppArmor 和 SELinux 都是常见的强制访问控制(MAC)机制,可以对进程或应用程序的访问权限进行精细控制。下面分别举例说明这两种机制的配置文件使用。

    1. AppArmor

    AppArmor 的主配置文件是 /etc/apparmor/profiles.d/ 目录下的各个文件,每个文件对应一个应用程序或进程的配置。以 sshd 服务为例,该服务的配置文件是/etc/apparmor.d/usr.sbin.sshd

    该配置文件的内容类似于下面这样:

    # Last Modified: Sun Mar 14 18:53:00 2023
    +#include <tunables/global>
     
     /usr/sbin/sshd {
    -  #include <abstractions/base>
    -  #include <abstractions/nameservice>
    +  #include <abstractions/base>
    +  #include <abstractions/nameservice>
     
    -  # allow read access to user home directories
    +  # allow read access to user home directories
       /home/** r,
     
    -  # allow sshd to execute /usr/bin/which to determine full path of shell
    +  # allow sshd to execute /usr/bin/which to determine full path of shell
       /usr/bin/which ix,
     
    -  # allow sshd to read its own configuration file
    +  # allow sshd to read its own configuration file
       /etc/ssh/sshd_config r,
     
    -  # allow sshd to read the SSH host keys
    +  # allow sshd to read the SSH host keys
       /etc/ssh/ssh_host_* r,
     
    -  # allow sshd to use pam for authentication
    +  # allow sshd to use pam for authentication
       /usr/share/pam/** r,
     
    -  # allow sshd to use nsswitch for name resolution
    +  # allow sshd to use nsswitch for name resolution
       /etc/nsswitch.conf r,
       /etc/hosts r,
       /etc/hostname r,
       /etc/resolv.conf r,
     
    -  # allow sshd to write to its own log file
    +  # allow sshd to write to its own log file
       /var/log/auth.log w,
     
    -  # allow sshd to create and manage pid files
    +  # allow sshd to create and manage pid files
       /var/run/sshd.pid w,
       /var/run/sshd.dir/ w,
       /var/run/sshd.dir/* rw,
     
    -  # allow sshd to access systemd-logind
    +  # allow sshd to access systemd-logind
       /run/systemd/* r,
       /run/systemd/session/*.scope r,
       /run/systemd/sessions/*.scope r,
     
    -  # deny everything else
    +  # deny everything else
       deny /,
     }
     

    该配置文件定义了 /usr/sbin/sshd 进程的权限限制规则,包括允许访问的文件、禁止访问的文件等。其中 #include <abstractions/base> 表示包含了一组通用的权限规则,可以在不同的应用程序配置中重复使用。

    2.SELinux

    SELinux 的主配置文件是 /etc/selinux/config,该文件定义了系统的 SELinux 策略和模式。默认情况下,openSUSE 使用的是 targeted 模式。

    每个进程或应用程序还需要对应一个 SELinux 配置文件,以定义它们的访问权限。以 httpd 服务为例,该服务的 SELinux 配置文件是/etc/selinux/targeted/contexts/httpd.te

    该配置文件的内容类似于下面这样:

    # HTTPD server
    -type httpd_t;
    -type httpd_sys_script_t;
    -init_daemon_domain(httpd_t, httpd_sys_script_t)
    -

    该配置文件定义了 httpd 服务的 SELinux 类型为 httpd_t,并使用了httpd_sys_script_t 作为其初始化域。其中 type 表示 SELinux 类型,init_daemon_domain 则是一个 SELinux 宏,用于定义服务的初始域。

    需要注意的是,在 SELinux 中,访问权限规则不是直接在配置文件中定义的,而是通过访问控制策略和规则进行控制。这些策略和规则可以使用 SELinux 工具集(如 semanagesetseboolrestorecon 等)进行管理和设置。

    比如,在openSUSE中可以看到/etc/selinux/semanage.conf文件和其中的配置。

    内核能力

    内核能力(Kernel capabilities)

    • 没有能力:root可以执行所有操作,其他用户可能什么也做不了
    • 38个细粒度的功能来控制权限

    Kernel capabilities 是 Linux 内核提供的一种机制,用于控制进程对系统资源的访问权限。与传统的 Unix 权限机制不同,Kernel capabilities 可以使管理员在精细控制系统资源访问的同时,避免将过多权限授予进程,提高了系统的安全性。

    在传统 Unix 权限机制中,每个进程都有一个有效用户 ID 和一个有效组 ID,这些 ID 决定了该进程对文件、设备、网络等资源的访问权限。但是,这种权限机制不够灵活,如果要授予进程某些特定的权限,可能需要将所有的权限都授予给它,从而降低了系统的安全性。

    Kernel capabilities 提供了一种更细粒度的权限控制方式。每个进程都有一组 capabilities,每个 capability 表示一种特定的权限。进程可以请求和释放某些 capability,这样就可以将权限授予进程,而不必授予所有权限。

    例如,可以将 CAP_NET_BIND_SERVICEcapability 授予某个进程,这样该进程就可以绑定 1-1023 的端口,而不必具有 root 权限。类似地,可以将 CAP_SYS_ADMINcapability 授予某个进程,这样该进程就可以执行系统管理任务,如挂载文件系统和创建设备节点等。

    Linux 内核提供了一组默认的 capabilities,也可以通过自定义的方式创建新的 capabilities,以便更好地控制系统资源的访问权限。可以使用 setcap命令为二进制文件设置 capabilities。例如,下面的命令将 CAP_NET_RAWcapability 授予 /usr/bin/ping 命令:

    sudo setcap cap_net_raw+ep /usr/bin/ping
    -

    这样,用户就可以使用 ping命令而不必以 root 用户的身份登录。

    除了 CAP_NET_BIND_SERVICECAP_SYS_ADMIN,还有一些其他的 capabilities,以下是一些例子:

    • CAP_DAC_OVERRIDE:允许进程忽略文件权限,可以访问任何文件。
    • CAP_CHOWN:允许进程修改文件的所有者。
    • CAP_SETUIDCAP_SETGID:允许进程修改自己的用户 ID 和组 ID。
    • CAP_NET_ADMIN:允许进程执行网络管理任务,如配置网络接口和路由表等。
    • CAP_SYS_RESOURCE:允许进程修改系统资源限制,如 CPU 时间和内存限制等。

    可以通过命令 man 7 capabilities 来查看系统提供的 capabilities 列表和详细说明。在使用 Kernel capabilities 时,需要注意,只有拥有 CAP_SETFCAPCAP_SYS_ADMINcapability 的进程才能够修改自己或其他进程的 capabilities,这也是为了保护系统的安全性。

    如果执行 setcap 命令时出现 "command not found" 的错误,这通常意味着 setcap 命令所在的包尚未安装。在 openSUSE 中,setcap 命令包含在 libcap-progs 软件包中。

    在 openSUSE 系统中需要安装 libcap-progs 软件包:

    sudo zypper in libcap-progs
    -

    在 Ubuntu/Debian 系统上需要安装 libcap 库:

    sudo apt-get install libcap2-bin
    -

    在 CentOS/RHEL 系统上需要安装 libcap 库:

    sudo yum install libcap-devel
    -

    安装完成后,可以使用 setcap 命令为二进制文件设置 capabilities。如果还是无法找到 setcap 命令,可以尝试使用完整路径 /sbin/setcap 或者 /usr/sbin/setcap。

    seccomp策略

    seccomp(secure computing mode)是 Linux 内核提供的一种安全机制,它可以限制进程能够进行的系统调用。通过使用 seccomp,可以限制进程只能够使用必要的系统调用,从而减少系统被攻击的风险。

    seccomp 策略可以使用 BPF(Berkeley Packet Filter)语言编写,并使用 seccomp() 系统调用加载。以下是一个使用 seccomp 策略限制进程能够进行的系统调用的示例:

    #include <linux/seccomp.h>
    -#include <sys/prctl.h>
    -#include <unistd.h>
    -
    -int main() {
    +type httpd_t;
    +type httpd_sys_script_t;
    +init_daemon_domain(httpd_t, httpd_sys_script_t)
    +

    该配置文件定义了 httpd 服务的 SELinux 类型为 httpd_t,并使用了httpd_sys_script_t 作为其初始化域。其中 type 表示 SELinux 类型,init_daemon_domain 则是一个 SELinux 宏,用于定义服务的初始域。

    需要注意的是,在 SELinux 中,访问权限规则不是直接在配置文件中定义的,而是通过访问控制策略和规则进行控制。这些策略和规则可以使用 SELinux 工具集(如 semanagesetseboolrestorecon 等)进行管理和设置。

    比如,在openSUSE中可以看到/etc/selinux/semanage.conf文件和其中的配置。

    内核能力

    内核能力(Kernel capabilities)

    • 没有能力:root可以执行所有操作,其他用户可能什么也做不了
    • 38个细粒度的功能来控制权限

    Kernel capabilities 是 Linux 内核提供的一种机制,用于控制进程对系统资源的访问权限。与传统的 Unix 权限机制不同,Kernel capabilities 可以使管理员在精细控制系统资源访问的同时,避免将过多权限授予进程,提高了系统的安全性。

    在传统 Unix 权限机制中,每个进程都有一个有效用户 ID 和一个有效组 ID,这些 ID 决定了该进程对文件、设备、网络等资源的访问权限。但是,这种权限机制不够灵活,如果要授予进程某些特定的权限,可能需要将所有的权限都授予给它,从而降低了系统的安全性。

    Kernel capabilities 提供了一种更细粒度的权限控制方式。每个进程都有一组 capabilities,每个 capability 表示一种特定的权限。进程可以请求和释放某些 capability,这样就可以将权限授予进程,而不必授予所有权限。

    例如,可以将 CAP_NET_BIND_SERVICEcapability 授予某个进程,这样该进程就可以绑定 1-1023 的端口,而不必具有 root 权限。类似地,可以将 CAP_SYS_ADMINcapability 授予某个进程,这样该进程就可以执行系统管理任务,如挂载文件系统和创建设备节点等。

    Linux 内核提供了一组默认的 capabilities,也可以通过自定义的方式创建新的 capabilities,以便更好地控制系统资源的访问权限。可以使用 setcap命令为二进制文件设置 capabilities。例如,下面的命令将 CAP_NET_RAWcapability 授予 /usr/bin/ping 命令:

    sudo setcap cap_net_raw+ep /usr/bin/ping
    +

    这样,用户就可以使用 ping命令而不必以 root 用户的身份登录。

    除了 CAP_NET_BIND_SERVICECAP_SYS_ADMIN,还有一些其他的 capabilities,以下是一些例子:

    • CAP_DAC_OVERRIDE:允许进程忽略文件权限,可以访问任何文件。
    • CAP_CHOWN:允许进程修改文件的所有者。
    • CAP_SETUIDCAP_SETGID:允许进程修改自己的用户 ID 和组 ID。
    • CAP_NET_ADMIN:允许进程执行网络管理任务,如配置网络接口和路由表等。
    • CAP_SYS_RESOURCE:允许进程修改系统资源限制,如 CPU 时间和内存限制等。

    可以通过命令 man 7 capabilities 来查看系统提供的 capabilities 列表和详细说明。在使用 Kernel capabilities 时,需要注意,只有拥有 CAP_SETFCAPCAP_SYS_ADMINcapability 的进程才能够修改自己或其他进程的 capabilities,这也是为了保护系统的安全性。

    如果执行 setcap 命令时出现 "command not found" 的错误,这通常意味着 setcap 命令所在的包尚未安装。在 openSUSE 中,setcap 命令包含在 libcap-progs 软件包中。

    在 openSUSE 系统中需要安装 libcap-progs 软件包:

    sudo zypper in libcap-progs
    +

    在 Ubuntu/Debian 系统上需要安装 libcap 库:

    sudo apt-get install libcap2-bin
    +

    在 CentOS/RHEL 系统上需要安装 libcap 库:

    sudo yum install libcap-devel
    +

    安装完成后,可以使用 setcap 命令为二进制文件设置 capabilities。如果还是无法找到 setcap 命令,可以尝试使用完整路径 /sbin/setcap 或者 /usr/sbin/setcap。

    seccomp策略

    seccomp(secure computing mode)是 Linux 内核提供的一种安全机制,它可以限制进程能够进行的系统调用。通过使用 seccomp,可以限制进程只能够使用必要的系统调用,从而减少系统被攻击的风险。

    seccomp 策略可以使用 BPF(Berkeley Packet Filter)语言编写,并使用 seccomp() 系统调用加载。以下是一个使用 seccomp 策略限制进程能够进行的系统调用的示例:

    #include <linux/seccomp.h>
    +#include <sys/prctl.h>
    +#include <unistd.h>
    +
    +int main() {
         // 创建 seccomp 过滤器
    -    struct sock_filter filter[] = {
    -        BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 0),
    -        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_write, 0, 1),
    -        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
    -        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),
    -    };
    -    struct sock_fprog prog = {
    -        .len = sizeof(filter) / sizeof(filter[0]),
    -        .filter = filter,
    -    };
    +    struct sock_filter filter[] = {
    +        BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 0),
    +        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_write, 0, 1),
    +        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
    +        BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),
    +    };
    +    struct sock_fprog prog = {
    +        .len = sizeof(filter) / sizeof(filter[0]),
    +        .filter = filter,
    +    };
     
         // 加载 seccomp 过滤器
    -    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
    -        perror("prctl");
    -        return 1;
    -    }
    +    if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
    +        perror("prctl");
    +        return 1;
    +    }
     
         // 调用 write 系统调用
    -    char buf[] = "Hello, world!";
    -    write(1, buf, sizeof(buf));
    -    return 0;
    -}
    -

    上述代码创建了一个 seccomp 过滤器,仅允许进程调用 write() 系统调用,其他系统调用均会被禁止。可以通过编译并运行上述代码来演示 seccomp 策略的作用。

    需要注意的是,seccomp 策略只能够限制进程进行的系统调用,但不能够限制系统调用的参数或返回值。因此,使用 seccomp 策略时需要特别小心,避免误用或产生漏洞。

    Netlink 是一种 Linux 内核提供的通信机制,用于内核和用户空间进程之间的双向通信(IPC)。Netlink 可以用于许多目的,例如:

    1. 配置网络设备和路由表:使用 Netlink 可以通过用户空间进程修改内核的网络设备和路由表配置,例如添加、删除、修改网络接口、IP 地址、路由等。

    2. 监视网络事件:使用 Netlink 可以实时地从内核获取网络事件的通知,例如网络接口的状态变化、路由的变化等。

    3. 程序间通信:使用 Netlink 可以在用户空间进程之间进行通信,类似于 Unix 域套接字。

    Netlink 机制基于一种特殊的套接字类型(PF_NETLINK)和一个特定的协议(NETLINK)。用户空间进程可以通过创建 Netlink 套接字和内核通信。内核和用户空间进程之间的通信是基于 Netlink 消息的,每个 Netlink 消息包含一个消息头和一个负载(payload),负载可以是任何结构体或二进制数据。

    Netlink 消息的类型和格式由内核定义。用户空间进程需要了解内核的 Netlink 消息格式和类型,才能正确地构造和解析 Netlink 消息。常用的 Netlink 消息类型包括:

    1. RTM_NEWLINK 和 RTM_DELLINK:添加和删除网络接口。

    2. RTM_NEWADDR 和 RTM_DELADDR:添加和删除 IP 地址。

    3. RTM_NEWROUTE 和 RTM_DELROUTE:添加和删除路由。

    4. RTM_NEWNEIGH 和 RTM_DELNEIGH:添加和删除 ARP 表项。

    Netlink 可以使用 C 语言的 socket API 进行编程。

    Netfilter

    Netfilter是Linux内核中的一个子系统,用于在数据包传输过程中进行过滤和操作。它支持对网络数据包进行各种类型的处理,包括过滤、修改、重定向等。Netfilter通过在内核中注册钩子函数,在数据包通过网络栈的不同阶段时进行拦截和处理。

    Netfilter的核心是iptables命令,它可以用来配置Netfilter规则。iptables命令可以用来配置防火墙规则,NAT规则,限制连接速度等。iptables命令通过匹配不同的数据包字段(例如源IP地址、目的IP地址、源端口、目的端口等)来进行过滤。

    除了iptables命令,还有其他一些工具可以用于配置Netfilter规则,例如nftables命令和firewalld服务。这些工具提供了更灵活、更强大的配置选项,可以帮助管理员更好地管理和保护网络安全。

    也可以用于将网络数据包定向到单个容器。

    更多信息可以参考 LXC/LXD

    安装Docker

    参考指导安装Docker引擎。 参考指导安装Docker桌面版。

    下面以openSUSE为例安装Docker引擎。

    sudo zypper in docker
    -

    在安装过程中,在操作系统中会自动创建组docker。 将vagrant用户加入docker组,则vagrant用户可以在下次登录后与本机的Docker守护进程(daemon)进行通信。Docker守护进程监听本地套接字,只能由root用户和docker组的成员访问。

    sudo usermod -aG docker $USER
    -

    启用并启动 Docker 引擎。

    sudo systemctl enable docker.service 
    -sudo systemctl start docker.service 
    -sudo systemctl status docker.service
    -

    下面通过一个容器alpine的例子来演示在目录/opt/test下模拟实现choot。

    mkdir test
    -cd test
    -wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.4-x86_64.tar.gz
    -tar zxvf alpine-minirootfs-3.13.4-x86_64.tar.gz -C alpine-minirootfs/
    -

    查看当前目录结构:

    tree ./test -L 1
    +    char buf[] = "Hello, world!";
    +    write(1, buf, sizeof(buf));
    +    return 0;
    +}
    +

    上述代码创建了一个 seccomp 过滤器,仅允许进程调用 write() 系统调用,其他系统调用均会被禁止。可以通过编译并运行上述代码来演示 seccomp 策略的作用。

    需要注意的是,seccomp 策略只能够限制进程进行的系统调用,但不能够限制系统调用的参数或返回值。因此,使用 seccomp 策略时需要特别小心,避免误用或产生漏洞。

    Netlink 是一种 Linux 内核提供的通信机制,用于内核和用户空间进程之间的双向通信(IPC)。Netlink 可以用于许多目的,例如:

    1. 配置网络设备和路由表:使用 Netlink 可以通过用户空间进程修改内核的网络设备和路由表配置,例如添加、删除、修改网络接口、IP 地址、路由等。

    2. 监视网络事件:使用 Netlink 可以实时地从内核获取网络事件的通知,例如网络接口的状态变化、路由的变化等。

    3. 程序间通信:使用 Netlink 可以在用户空间进程之间进行通信,类似于 Unix 域套接字。

    Netlink 机制基于一种特殊的套接字类型(PF_NETLINK)和一个特定的协议(NETLINK)。用户空间进程可以通过创建 Netlink 套接字和内核通信。内核和用户空间进程之间的通信是基于 Netlink 消息的,每个 Netlink 消息包含一个消息头和一个负载(payload),负载可以是任何结构体或二进制数据。

    Netlink 消息的类型和格式由内核定义。用户空间进程需要了解内核的 Netlink 消息格式和类型,才能正确地构造和解析 Netlink 消息。常用的 Netlink 消息类型包括:

    1. RTM_NEWLINK 和 RTM_DELLINK:添加和删除网络接口。

    2. RTM_NEWADDR 和 RTM_DELADDR:添加和删除 IP 地址。

    3. RTM_NEWROUTE 和 RTM_DELROUTE:添加和删除路由。

    4. RTM_NEWNEIGH 和 RTM_DELNEIGH:添加和删除 ARP 表项。

    Netlink 可以使用 C 语言的 socket API 进行编程。

    Netfilter

    Netfilter是Linux内核中的一个子系统,用于在数据包传输过程中进行过滤和操作。它支持对网络数据包进行各种类型的处理,包括过滤、修改、重定向等。Netfilter通过在内核中注册钩子函数,在数据包通过网络栈的不同阶段时进行拦截和处理。

    Netfilter的核心是iptables命令,它可以用来配置Netfilter规则。iptables命令可以用来配置防火墙规则,NAT规则,限制连接速度等。iptables命令通过匹配不同的数据包字段(例如源IP地址、目的IP地址、源端口、目的端口等)来进行过滤。

    除了iptables命令,还有其他一些工具可以用于配置Netfilter规则,例如nftables命令和firewalld服务。这些工具提供了更灵活、更强大的配置选项,可以帮助管理员更好地管理和保护网络安全。

    也可以用于将网络数据包定向到单个容器。

    更多信息可以参考 LXC/LXD

    安装Docker

    参考指导安装Docker引擎。 参考指导安装Docker桌面版。

    下面以openSUSE为例安装Docker引擎。

    sudo zypper in docker
    +

    在安装过程中,在操作系统中会自动创建组docker。 将vagrant用户加入docker组,则vagrant用户可以在下次登录后与本机的Docker守护进程(daemon)进行通信。Docker守护进程监听本地套接字,只能由root用户和docker组的成员访问。

    sudo usermod -aG docker $USER
    +

    启用并启动 Docker 引擎。

    sudo systemctl enable docker.service 
    +sudo systemctl start docker.service 
    +sudo systemctl status docker.service
    +

    下面通过一个容器alpine的例子来演示在目录/opt/test下模拟实现choot。

    mkdir test
    +cd test
    +wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.4-x86_64.tar.gz
    +tar zxvf alpine-minirootfs-3.13.4-x86_64.tar.gz -C alpine-minirootfs/
    +

    查看当前目录结构:

    tree ./test -L 1
     

    输出结果:

    ./test
     ├── alpine-minirootfs-3.13.4-x86_64.tar.gz
     ├── bin
    @@ -188,81 +188,81 @@
     ├── tmp
     ├── usr
     └── var
    -

    通过命令unshare挂载目录 /opt/test/proc 到某个文件来实现客户子系统。

    sudo mount -t tmpfs tmpfs /opt/test/proc
    -
    sudo unshare --pid --mount-proc=$PWD/test/proc --fork chroot ./test/ /bin/sh
    -/ # ps -ef
    -PID   USER     TIME  COMMAND
    -    1 root      0:00 /bin/sh
    -    2 root      0:00 ps -ef
    -/ # touch 123
    -/ # ls 123
    +

    通过命令unshare挂载目录 /opt/test/proc 到某个文件来实现客户子系统。

    sudo mount -t tmpfs tmpfs /opt/test/proc
    +
    sudo unshare --pid --mount-proc=$PWD/test/proc --fork chroot ./test/ /bin/sh
    +/ # ps -ef
    +PID   USER     TIME  COMMAND
    +    1 root      0:00 /bin/sh
    +    2 root      0:00 ps -ef
    +/ # touch 123
    +/ # ls 123
     123
    -

    文件123在客户子系统中已创建,对应主系统中也可以对其进行读写操作。比如,修改文件123的内容。

    su -
    -ls 123
    -echo hello > 123
    -

    文件123修改后的内容在客户机里面也可见。

    / # cat 123
    +

    文件123在客户子系统中已创建,对应主系统中也可以对其进行读写操作。比如,修改文件123的内容。

    su -
    +ls 123
    +echo hello > 123
    +

    文件123修改后的内容在客户机里面也可见。

    / # cat 123
     hello
    -

    在主系统中再创建两个子目录 /opt/test-1/opt/test-2

    mkdir test-1
    -mkdir test-2
    -

    创建2个客户子系统,并将上面的两个子目录挂在到各自的 /opt/test/home/目录。

    sudo mount --bind /opt/test-1 /opt/test/home/
    -sudo unshare --pid --mount-proc=$PWD/test/proc --fork chroot ./test/ /bin/sh
    -/ # cd /home
    -/home # echo "test-1" > 123.1
    -/home # cat 123.1
    +

    在主系统中再创建两个子目录 /opt/test-1/opt/test-2

    mkdir test-1
    +mkdir test-2
    +

    创建2个客户子系统,并将上面的两个子目录挂在到各自的 /opt/test/home/目录。

    sudo mount --bind /opt/test-1 /opt/test/home/
    +sudo unshare --pid --mount-proc=$PWD/test/proc --fork chroot ./test/ /bin/sh
    +/ # cd /home
    +/home # echo "test-1" > 123.1
    +/home # cat 123.1
     test-1
    -
    sudo mount --bind /opt/test-2 /opt/test/home/
    -sudo unshare --pid --mount-proc=$PWD/test/proc --fork chroot ./test/ /bin/sh
    -/ # cd /home
    -/home # echo "test-2" > 123.2
    -/home # cat 123.2
    +
    sudo mount --bind /opt/test-2 /opt/test/home/
    +sudo unshare --pid --mount-proc=$PWD/test/proc --fork chroot ./test/ /bin/sh
    +/ # cd /home
    +/home # echo "test-2" > 123.2
    +/home # cat 123.2
     test-2
    -
    ll test/home
    -ll test-1/
    -ll test-2/
    -

    通过上面的演示,可以得出结论,两个客户子系统挂在到同一个主系统目录时,子系统时共享主系统目录,并相互影响。

    容器生命周期

    概述

    预先下载下列镜像。

    docker image pull busybox
    -docker image pull nginx
    -docker image pull alpine
    -docker image pull jenkins/jenkins:lts
    -docker image pull golang:1.12-alpine
    -docker image pull golang
    -

    创建并交互式运行一个新的busybox容器,并连接一个伪终端(pseudo terminal)。 在容器内,使用top命令查找/bin/sh正在作为PID为1的进程运行,以及top进程也在运行。 然后,退出容器。

    docker image ls
    -docker run -d -it --name busybox_v1 -v /opt/test:/docker busybox:latest /bin/sh
    -docker container ps -a
    -docker exec -it 185efe490507 /bin/sh
    -/ # top
    -Mem: 3627396K used, 12731512K free, 10080K shrd, 2920K buff, 2999340K cached
    -CPU:  0.0% usr  0.1% sys  0.0% nic 99.8% idle  0.0% io  0.0% irq  0.0% sirq
    -Load average: 0.38 1.09 1.29 2/277 14
    -  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
    -    1     0 root     S     1332  0.0   1  0.0 /bin/sh
    -    8     0 root     S     1332  0.0   2  0.0 /bin/sh
    -   14     8 root     R     1328  0.0   1  0.0 top
    -/ # exitbuild 
    -

    启动一个新的 Nginx 容器,并以独立模式(detached mode)运行。 使用 docker exec 命令在 Nginx 容器中启动另一个 shell(/bin/sh)。 使用 ps 命令查看容器中正在运行的 shps 命令(在上一步执行的)。

    docker run -d -it --name nginx_v1 -v /opt/test:/docker nginx:latest /bin/sh
    -docker container ps -a
    -docker exec -it edb640127a0d /bin/sh
    +
    ll test/home
    +ll test-1/
    +ll test-2/
    +

    通过上面的演示,可以得出结论,两个客户子系统挂在到同一个主系统目录时,子系统时共享主系统目录,并相互影响。

    容器生命周期

    概述

    预先下载下列镜像。

    docker image pull busybox
    +docker image pull nginx
    +docker image pull alpine
    +docker image pull jenkins/jenkins:lts
    +docker image pull golang:1.12-alpine
    +docker image pull golang
    +

    创建并交互式运行一个新的busybox容器,并连接一个伪终端(pseudo terminal)。 在容器内,使用top命令查找/bin/sh正在作为PID为1的进程运行,以及top进程也在运行。 然后,退出容器。

    docker image ls
    +docker run -d -it --name busybox_v1 -v /opt/test:/docker busybox:latest /bin/sh
    +docker container ps -a
    +docker exec -it 185efe490507 /bin/sh
    +/ # top
    +Mem: 3627396K used, 12731512K free, 10080K shrd, 2920K buff, 2999340K cached
    +CPU:  0.0% usr  0.1% sys  0.0% nic 99.8% idle  0.0% io  0.0% irq  0.0% sirq
    +Load average: 0.38 1.09 1.29 2/277 14
    +  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
    +    1     0 root     S     1332  0.0   1  0.0 /bin/sh
    +    8     0 root     S     1332  0.0   2  0.0 /bin/sh
    +   14     8 root     R     1328  0.0   1  0.0 top
    +/ # exitbuild 
    +

    启动一个新的 Nginx 容器,并以独立模式(detached mode)运行。 使用 docker exec 命令在 Nginx 容器中启动另一个 shell(/bin/sh)。 使用 ps 命令查看容器中正在运行的 shps 命令(在上一步执行的)。

    docker run -d -it --name nginx_v1 -v /opt/test:/docker nginx:latest /bin/sh
    +docker container ps -a
    +docker exec -it edb640127a0d /bin/sh
     # ps
    -/bin/sh: 2: ps: not found
    +/bin/sh: 2: ps: not found
     # apt-get update && apt-get install -y procps
     # ps
    -   PID TTY          TIME CMD
    -     8 pts/1    00:00:00 sh
    -   351 pts/1    00:00:00 ps
    +   PID TTY          TIME CMD
    +     8 pts/1    00:00:00 sh
    +   351 pts/1    00:00:00 ps
     # exit
    -

    通过下面命令可以看到2个现在运行中的容器。

    docker container ps -a
    -

    使用 docker logs 命令显示我们刚刚退出的容器的日志。选项 --since 35m 表示显示最近 35 分钟内的日志。

    docker logs nginx_v1 --details --since 35m
    -docker logs busybox_v1 --details --since 35m
    -

    使用 docker stop 命令来停止 nginx 容器。

    docker stop busybox_v1
    -docker stop nginx_v1 
    -docker container ps -a
    -

    使用上述命令docker container ps -a,我们可以获取所有正在运行和已退出的容器列表。使用docker rm将其删除。使用docker rm $(docker ps -aq)来清理主机上的所有容器。请谨慎使用!

    docker rm busybox_v1
    -docker container ps -a
    -

    端口和卷

    现在启动一个新的 nginx 容器,并将 nginx web 服务器的端口导出到 Docker 随机选择的端口。

    我们可以使用命令 docker ps 找出 web 服务器转发到了哪个端口。在主机上使用转发的端口号访问 docker http://localhost:<port#>

    docker container ps -a
    -docker run -d -P --name nginx_v2 nginx:latest
    -docker container ps -a
    -

    Start another nginx container and expose port to 1080 on host as an example via http://localhost:1080. 启动另一个nginx容器,将其端口映射到主机的1080端口,可以通过http://localhost:1080访问。

    docker run -d -p 1080:80 --name nginx_v3 nginx:latest
    -docker container ps -a
    -

    使用docker inspect命令查找镜像暴露的端口号,输出JSON格式文件,网络信息(IP、网关、端口等)是输出JSON格式的一部分。

    docker inspect nginx_v3 
    +

    通过下面命令可以看到2个现在运行中的容器。

    docker container ps -a
    +

    使用 docker logs 命令显示我们刚刚退出的容器的日志。选项 --since 35m 表示显示最近 35 分钟内的日志。

    docker logs nginx_v1 --details --since 35m
    +docker logs busybox_v1 --details --since 35m
    +

    使用 docker stop 命令来停止 nginx 容器。

    docker stop busybox_v1
    +docker stop nginx_v1 
    +docker container ps -a
    +

    使用上述命令docker container ps -a,我们可以获取所有正在运行和已退出的容器列表。使用docker rm将其删除。使用docker rm $(docker ps -aq)来清理主机上的所有容器。请谨慎使用!

    docker rm busybox_v1
    +docker container ps -a
    +

    端口和卷

    现在启动一个新的 nginx 容器,并将 nginx web 服务器的端口导出到 Docker 随机选择的端口。

    我们可以使用命令 docker ps 找出 web 服务器转发到了哪个端口。在主机上使用转发的端口号访问 docker http://localhost:<port#>

    docker container ps -a
    +docker run -d -P --name nginx_v2 nginx:latest
    +docker container ps -a
    +

    Start another nginx container and expose port to 1080 on host as an example via http://localhost:1080. 启动另一个nginx容器,将其端口映射到主机的1080端口,可以通过http://localhost:1080访问。

    docker run -d -p 1080:80 --name nginx_v3 nginx:latest
    +docker container ps -a
    +

    使用docker inspect命令查找镜像暴露的端口号,输出JSON格式文件,网络信息(IP、网关、端口等)是输出JSON格式的一部分。

    docker inspect nginx_v3 
     

    在目录 /opt/test 中创建一个名为 index.html 的文件,其内容如下:

    <html>
     <head>
         <title>Sample Website from my container</title>
    @@ -272,80 +272,80 @@
         <p>This website is served from my <a href="http://www.docker.com" target="_blank">Docker</a> container.</p>
     </body>
     </html>
    -

    启动一个新容器,将主机目录 /opt/test 与容器目录 /usr/share/nginx/html 绑定挂载为一个卷,以便Nginx可以通过 http://localhost:49159/ 发布我们刚创建的html文件,而不是Nginx默认的页面。

    docker run -d -P --mount type=bind,source=/opt/test/,target=/usr/share/nginx/html --name nginx_v3-1 nginx:latest
    -docker container ps -a
    -

    检查Nginx配置文件,查看容器中html主页存储的位置。

    docker exec -it nginx_v3-1 /bin/sh
    +

    启动一个新容器,将主机目录 /opt/test 与容器目录 /usr/share/nginx/html 绑定挂载为一个卷,以便Nginx可以通过 http://localhost:49159/ 发布我们刚创建的html文件,而不是Nginx默认的页面。

    docker run -d -P --mount type=bind,source=/opt/test/,target=/usr/share/nginx/html --name nginx_v3-1 nginx:latest
    +docker container ps -a
    +

    检查Nginx配置文件,查看容器中html主页存储的位置。

    docker exec -it nginx_v3-1 /bin/sh
     # cd /etc/nginx/conf.d
     # ls
     default.conf
     # cat default.conf
    -server {
    -    listen       80;
    -    listen  [::]:80;
    -    server_name  localhost;
    -
    -    #access_log  /var/log/nginx/host.access.log  main;
    -
    -    location / {
    -        root   /usr/share/nginx/html;  <--
    -        index  index.html index.htm;
    -    }
    -
    -    #error_page  404              /404.html;
    -
    -    # redirect server error pages to the static page /50x.html
    -    #
    -    error_page   500 502 503 504  /50x.html;
    -    location = /50x.html {
    -        root   /usr/share/nginx/html;
    -    }
    -
    -    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    -    #
    -    #location ~ \.php$ {
    -    #    proxy_pass   http://127.0.0.1;
    -    #}
    -
    -    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    -    #
    -    #location ~ \.php$ {
    -    #    root           html;
    -    #    fastcgi_pass   127.0.0.1:9000;
    -    #    fastcgi_index  index.php;
    -    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    -    #    include        fastcgi_params;
    -    #}
    -
    -    # deny access to .htaccess files, if Apache's document root
    -    # concurs with nginx's one
    -    #
    -    #location ~ /\.ht {
    -    #    deny  all;
    -    #}
    +server {
    +    listen       80;
    +    listen  [::]:80;
    +    server_name  localhost;
    +
    +    #access_log  /var/log/nginx/host.access.log  main;
    +
    +    location / {
    +        root   /usr/share/nginx/html;  <--
    +        index  index.html index.htm;
    +    }
    +
    +    #error_page  404              /404.html;
    +
    +    # redirect server error pages to the static page /50x.html
    +    #
    +    error_page   500 502 503 504  /50x.html;
    +    location = /50x.html {
    +        root   /usr/share/nginx/html;
    +    }
    +
    +    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    +    #
    +    #location ~ \.php$ {
    +    #    proxy_pass   http://127.0.0.1;
    +    #}
    +
    +    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    +    #
    +    #location ~ \.php$ {
    +    #    root           html;
    +    #    fastcgi_pass   127.0.0.1:9000;
    +    #    fastcgi_index  index.php;
    +    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    +    #    include        fastcgi_params;
    +    #}
    +
    +    # deny access to .htaccess files, if Apache's document root
    +    # concurs with nginx's one
    +    #
    +    #location ~ /\.ht {
    +    #    deny  all;
    +    #}
     }
     # cd /usr/share/nginx/html
     # cat index.html              
    -  <html>
    -  <head>
    -      <title>Sample Website from my container</title>
    -  </head>
    -  <body>
    -      <h1>This is a custom website.</h1>
    -      <p>This website is served from my <a href="http://www.docker.com" target="_blank">Docker</a> container.</p>
    -  </body>
    -  </html>
    +  <html>
    +  <head>
    +      <title>Sample Website from my container</title>
    +  </head>
    +  <body>
    +      <h1>This is a custom website.</h1>
    +      <p>This website is served from my <a href="http://www.docker.com" target="_blank">Docker</a> container.</p>
    +  </body>
    +  </html>
     # 
    -

    推荐使用卷 API 来实现数据持久化,而不是将数据存储在 Docker 容器中。Docker 支持两种挂载方式:

    • 绑定挂载(Bind mounts):
    • 将本地主机目录挂载到容器中的某个路径。
    • 挂载后,目标目录中原有的所有内容将被隐藏。
    • 例如,如果我们想要注入某些配置文件,我们需要自己写对应的配置文件,将其存储在 Docker 主机上的/home/container/config路径下,并将此目录的内容挂载到 /usr/application/config(假设应用程序从此处读取配置)。
    • 命令:docker run --mount type=bind,source=<source path>,target=<container path> …
    • 命名卷(Named volumes):
    • Docker 可以创建一个独立的存储卷,其生命周期独立于容器但仍由 Docker 管理。
    • 在创建时,挂载目标的内容将合并到卷中。
    • 命令:docker run --mount source=<vol name>,target=<container path> …

    如何区分绑定挂载和命名卷?

    • 当指定绝对路径时,Docker 会认为这是一个绑定挂载。
    • 当我们仅提供名称(如相对路径config)时,它会认为这是一个命名卷,并创建一个名为config的卷。

    注:持久存储由主机提供,可以直接是主机文件系统的一部分,也可以是 NFS 挂载。

    Dockerfile

    让我们用 Dockerfile 构建一个镜像,对其进行打标签并上传到镜像仓库。

    获取 Docker 镜像的构建历史记录。

    docker image history nginx:latest 
    -

    创建一个空的目录/opt/tmp-1,进入该目录并在其中创建index.html文件。

    /opt/tmp-1> cat index.html 
    -  <html>
    -  <head>
    -      <title>Sample Website from my container</title>
    -  </head>
    -  <body>
    -      <h1>This is a custom website.</h1>
    -      <p>This website is served from my <a href="http://www.docker.com" target="_blank">Docker</a> container.</p>
    -  </body>
    -  </html>
    +

    推荐使用卷 API 来实现数据持久化,而不是将数据存储在 Docker 容器中。Docker 支持两种挂载方式:

    • 绑定挂载(Bind mounts):
    • 将本地主机目录挂载到容器中的某个路径。
    • 挂载后,目标目录中原有的所有内容将被隐藏。
    • 例如,如果我们想要注入某些配置文件,我们需要自己写对应的配置文件,将其存储在 Docker 主机上的/home/container/config路径下,并将此目录的内容挂载到 /usr/application/config(假设应用程序从此处读取配置)。
    • 命令:docker run --mount type=bind,source=<source path>,target=<container path> …
    • 命名卷(Named volumes):
    • Docker 可以创建一个独立的存储卷,其生命周期独立于容器但仍由 Docker 管理。
    • 在创建时,挂载目标的内容将合并到卷中。
    • 命令:docker run --mount source=<vol name>,target=<container path> …

    如何区分绑定挂载和命名卷?

    • 当指定绝对路径时,Docker 会认为这是一个绑定挂载。
    • 当我们仅提供名称(如相对路径config)时,它会认为这是一个命名卷,并创建一个名为config的卷。

    注:持久存储由主机提供,可以直接是主机文件系统的一部分,也可以是 NFS 挂载。

    Dockerfile

    让我们用 Dockerfile 构建一个镜像,对其进行打标签并上传到镜像仓库。

    获取 Docker 镜像的构建历史记录。

    docker image history nginx:latest 
    +

    创建一个空的目录/opt/tmp-1,进入该目录并在其中创建index.html文件。

    /opt/tmp-1> cat index.html 
    +  <html>
    +  <head>
    +      <title>Sample Website from my container</title>
    +  </head>
    +  <body>
    +      <h1>This is a custom website.</h1>
    +      <p>This website is served from my <a href="http://www.docker.com" target="_blank">Docker</a> container.</p>
    +  </body>
    +  </html>
     

    使用FROM来扩展一个已有的镜像,并指定版本号。

    使用COPY将一个新的默认网站复制到镜像中,例如 /usr/share/nginx/html

    为Nginx创建SSL配置/opt/tmp-1/ssl.conf

    server {
         listen       443 ssl;
         server_name  localhost;
    @@ -358,44 +358,44 @@
             index  index.html index.htm;
         }
     }
    -

    使用OpenSSL创建一个自签名证书,以便SSL/TLS工作。

    使用以下命令创建一个加密密钥和证书。

    openssl req -x509 -nodes -newkey rsa:4096 -keyout nginx.key -out nginx.crt -days 365 -subj "/CN=$(hostname)"
    -

    为了启用加密的HTTPS,我们需要使用EXPOSE指令公开443端口。默认的nginx镜像仅公开端口80,用于非加密的HTTP。

    /opt/tmp-1文件夹中创建以下Dockerfile。

    cat Dockerfile
    +

    使用OpenSSL创建一个自签名证书,以便SSL/TLS工作。

    使用以下命令创建一个加密密钥和证书。

    openssl req -x509 -nodes -newkey rsa:4096 -keyout nginx.key -out nginx.crt -days 365 -subj "/CN=$(hostname)"
    +

    为了启用加密的HTTPS,我们需要使用EXPOSE指令公开443端口。默认的nginx镜像仅公开端口80,用于非加密的HTTP。

    /opt/tmp-1文件夹中创建以下Dockerfile。

    cat Dockerfile
     

    输出:

    FROM nginx:latest
     
    -# copy the custom website into the image
    +# copy the custom website into the image
     COPY index.html /usr/share/nginx/html
     
    -# copy the SSL configuration file into the image
    +# copy the SSL configuration file into the image
     COPY ssl.conf /etc/nginx/conf.d/ssl.conf
     
    -# download the SSL key and certificate into the image
    +# download the SSL key and certificate into the image
     COPY nginx.key /etc/nginx/ssl/
     COPY nginx.crt /etc/nginx/ssl/
     
    -# expose the HTTPS port
    +# expose the HTTPS port
     EXPOSE 443
    -

    至此,我们在目录/opt/tmp-1下有5个文件。

    ls /opt/tmp-1
    +

    至此,我们在目录/opt/tmp-1下有5个文件。

    ls /opt/tmp-1
     

    输出:

    Dockerfile  index.html  nginx.crt  nginx.key  ssl.conf
    -

    使用docker build命令来构建镜像,并将容器的80和443端口转发。

    docker build -t nginx:my1 /opt/tmp-1/
    -docker image ls
    +

    使用docker build命令来构建镜像,并将容器的80和443端口转发。

    docker build -t nginx:my1 /opt/tmp-1/
    +docker image ls
     
    -docker run -d -p 1086:80 -p 1088:443 --name nginx_v5 nginx:my1
    +docker run -d -p 1086:80 -p 1088:443 --name nginx_v5 nginx:my1
     
    -docker container ps -a
    -

    通过下面两个链接来验证上面的变化是否生效。

    DockerHub 注册一个个人账号,启用 Docker Hub 中的访问令牌以进行 CLI 客户端身份验证。

    docker login
    +docker container ps -a
    +

    通过下面两个链接来验证上面的变化是否生效。

    DockerHub 注册一个个人账号,启用 Docker Hub 中的访问令牌以进行 CLI 客户端身份验证。

    docker login
     

    输入用户名和密码。

    Username: <your account id>
     Password: <token>
    -

    给这个镜像加上一个标签,例如:secure_nginx_0001,版本号为 v1。

    docker tag nginx:my1 <your account id>secure_nginx_0001:v1
    -docker push <your account id>secure_nginx_0001:v1
    -docker image ls
    -

    多阶段Dockerfile

    下面的例子是演示一个多阶段(Multi-stage)构建的例子。在Docker的上下文中,多阶段(Multi-stage)意味着我们可以有多个带有FROM关键字的行。

    创建文件夹/opt/tmp-2/opt/tmp-2/tmpl。创建文件edit.htmlview.htmlwiki.go

    文件结构如下:

    tree -l /opt/tmp-2
    +

    给这个镜像加上一个标签,例如:secure_nginx_0001,版本号为 v1。

    docker tag nginx:my1 <your account id>secure_nginx_0001:v1
    +docker push <your account id>secure_nginx_0001:v1
    +docker image ls
    +

    多阶段Dockerfile

    下面的例子是演示一个多阶段(Multi-stage)构建的例子。在Docker的上下文中,多阶段(Multi-stage)意味着我们可以有多个带有FROM关键字的行。

    创建文件夹/opt/tmp-2/opt/tmp-2/tmpl。创建文件edit.htmlview.htmlwiki.go

    文件结构如下:

    tree -l /opt/tmp-2
     

    输出结果:

    .
    -├── tmpl
    -│   ├── edit.html
    -│   └── view.html
    -└── wiki.go
    -

    创建一个新的Dockerfile。

    cat Dockerfile
    -

    文件内容:

    # app builder stage
    +├── tmpl
    +│   ├── edit.html
    +│   └── view.html
    +└── wiki.go
    +

    创建一个新的Dockerfile。

    cat Dockerfile
    +

    文件内容:

    # app builder stage
     FROM golang:1.12-alpine as builder
     
     ## copy the go source code over and build the binary
    @@ -403,27 +403,27 @@
     COPY wiki.go /go/src/wiki.go
     RUN go build wiki.go
     
    -# app exec stage
    -# separate & new image starts here!#
    +# app exec stage
    +# separate & new image starts here!#
     FROM alpine:3.9
     
    -# prepare file system etc
    +# prepare file system etc
     RUN mkdir -p /app/data /app/tmpl && adduser -S -D -H -h /app appuser
     COPY tmpl/* /app/tmpl/
     
    -# get the compiled binary from the previous stage
    +# get the compiled binary from the previous stage
     COPY --from=builder /go/src/wiki /app/wiki
     
    -# prepare runtime env
    +# prepare runtime env
     RUN chown -R appuser /app
     USER appuser
     WORKDIR /app
     
    -# expose app port & set default command
    +# expose app port & set default command
     EXPOSE 8080
     CMD ["/app/wiki"]
    -

    用上一步创建的Dockerfile来创建新景象。

    docker build -t lizard/golang:my1 /opt/tmp-2/
    -

    以独立模式(detached)运行这个镜像,并将容器端口8080转发到主机端口1090

    docker run -d -p 1090:8080 --name golan_v1 lizard/golang:my1
    -

    通过链接 http://localhost:1090 访问这个运行的容器。

    对我们刚刚创建的新的golang镜像进行标签,并且上传到Dockerhub。

    docker tag lizard/golang:my1 <your acccount id>/golang_0001:v1
    -docker push <your acccount id>/golang_0001:v1
    -
    \ No newline at end of file +

    用上一步创建的Dockerfile来创建新景象。

    docker build -t lizard/golang:my1 /opt/tmp-2/
    +

    以独立模式(detached)运行这个镜像,并将容器端口8080转发到主机端口1090

    docker run -d -p 1090:8080 --name golan_v1 lizard/golang:my1
    +

    通过链接 http://localhost:1090 访问这个运行的容器。

    对我们刚刚创建的新的golang镜像进行标签,并且上传到Dockerhub。

    docker tag lizard/golang:my1 <your acccount id>/golang_0001:v1
    +docker push <your acccount id>/golang_0001:v1
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/healthcheck/index.html b/k8s/cka_cn/foundamentals/healthcheck/index.html index d91bccab..d9ee9229 100644 --- a/k8s/cka_cn/foundamentals/healthcheck/index.html +++ b/k8s/cka_cn/foundamentals/healthcheck/index.html @@ -1,4 +1,4 @@ - 健康检查 - UPSkilling

    CKA自学笔记26:健康检查

    Pod和Container的状态

    演示场景:

    • 创建一个有2个容器的pod。

    演示:

    创建一个包含两个容器 nginxbusybox 的 Pod,命名为 multi-pods

    kubectl apply -f - << EOF
    + 健康检查 - UPSkilling       

    CKA自学笔记26:健康检查

    Pod和Container的状态

    演示场景:

    • 创建一个有2个容器的pod。

    演示:

    创建一个包含两个容器 nginxbusybox 的 Pod,命名为 multi-pods

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -14,31 +14,31 @@
       dnsPolicy: ClusterFirst
       restartPolicy: Always
     EOF
    -

    执行下面命令来监控状态,使用选项 --watch。 注意,pod的状态已经从ContainerCreating 变为 NotReady,再变为 CrashLoopBackOff

    kubectl get pod multi-pods --watch
    -

    获取 Pod multi-pods 的详细信息,关注 Containers 部分下的容器状态和 Conditions 部分下的 Pod 状态。

    kubectl describe pod multi-pods
    -

    运行结果(部分):

    ......
    -Containers:
    -  nginx:
    -    ......
    -    State:          Running
    -      Started:      Sat, 23 Jul 2022 15:06:56 +0800
    -    Ready:          True
    -    Restart Count:  0
    -    ......
    -  busybox:
    -    ......
    -    State:          Terminated
    -      Reason:       Completed
    -      Exit Code:    0
    -......
    -Conditions:
    -  Type              Status
    +

    执行下面命令来监控状态,使用选项 --watch。 注意,pod的状态已经从ContainerCreating 变为 NotReady,再变为 CrashLoopBackOff

    kubectl get pod multi-pods --watch
    +

    获取 Pod multi-pods 的详细信息,关注 Containers 部分下的容器状态和 Conditions 部分下的 Pod 状态。

    kubectl describe pod multi-pods
    +

    运行结果(部分):

    ......
    +Containers:
    +  nginx:
    +    ......
    +    State:          Running
    +      Started:      Sat, 23 Jul 2022 15:06:56 +0800
    +    Ready:          True
    +    Restart Count:  0
    +    ......
    +  busybox:
    +    ......
    +    State:          Terminated
    +      Reason:       Completed
    +      Exit Code:    0
    +......
    +Conditions:
    +  Type              Status
       Initialized       True 
       Ready             False 
       ContainersReady   False 
       PodScheduled      True 
     ...... 
    -

    LivenessProbe

    演示场景:

    • 创建一个pod,内含livenessProbe检查。

    演示的详细说明可以查询Kubernetes document

    演示:

    创建yaml文件liveness.yaml,并包含livenessProbe配置,并应用之。

    kubectl apply -f - <<EOF
    +

    LivenessProbe

    演示场景:

    • 创建一个pod,内含livenessProbe检查。

    演示的详细说明可以查询Kubernetes document

    演示:

    创建yaml文件liveness.yaml,并包含livenessProbe配置,并应用之。

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -72,7 +72,7 @@
       Normal   Started    53s                kubelet            Started container liveness
       Warning  Unhealthy  12s (x3 over 22s)  kubelet            Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
       Normal   Killing    12s                kubelet            Container liveness failed liveness probe, will be restarted
    -

    ReadinessProbe

    演示场景:

    • 创建一个pod,内含 readinessProbe 检查。

    演示:

    Readiness探针的配置与liveness探针类似,唯一的区别是使用readinessProbe字段而非livenessProbe字段。

    创建一个名为readiness.yaml的yaml文件并应用其中的readinessProbe配置。

    kubectl apply -f - <<EOF
    +

    ReadinessProbe

    演示场景:

    • 创建一个pod,内含 readinessProbe 检查。

    演示:

    Readiness探针的配置与liveness探针类似,唯一的区别是使用readinessProbe字段而非livenessProbe字段。

    创建一个名为readiness.yaml的yaml文件并应用其中的readinessProbe配置。

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -93,7 +93,7 @@
             initialDelaySeconds: 10
             periodSeconds: 5
     EOF
    -

    pod的Ready状态现在是0/1,即,pod并未成功创建。

    kubectl get pod readiness --watch
    +

    pod的Ready状态现在是0/1,即,pod并未成功创建。

    kubectl get pod readiness --watch
     

    运行结果:

    NAME        READY   STATUS    RESTARTS   AGE
     readiness   0/1     Running   0          15s
     

    执行命令 kubectl describe pod readiness 来检查pod的状态,我们可以看到报错信息Readiness probe failed

    ......
    @@ -106,7 +106,7 @@
       Normal   Created    43s               kubelet            Created container readiness
       Normal   Started    43s               kubelet            Started container readiness
       Warning  Unhealthy  1s (x7 over 31s)  kubelet            Readiness probe failed: cat: can't open '/tmp/healthy': No such file or directory
    -

    Liveness探针不会等待readiness探针成功后才执行。 如果我们想要在执行Liveness探针之前等待一段时间,可以使用initialDelaySecondsstartupProbe

    删除演示中创建的临时资源。

    kubectl delete pod liveness-exec
    -kubectl delete pod multi-pods 
    -kubectl delete pod readiness
    -
    \ No newline at end of file +

    Liveness探针不会等待readiness探针成功后才执行。 如果我们想要在执行Liveness探针之前等待一段时间,可以使用initialDelaySecondsstartupProbe

    删除演示中创建的临时资源。

    kubectl delete pod liveness-exec
    +kubectl delete pod multi-pods 
    +kubectl delete pod readiness
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/helming/index.html b/k8s/cka_cn/foundamentals/helming/index.html index d24edf28..5381afca 100644 --- a/k8s/cka_cn/foundamentals/helming/index.html +++ b/k8s/cka_cn/foundamentals/helming/index.html @@ -1,26 +1,26 @@ - Helm Chart - UPSkilling

    CKA自学笔记27:Helm Chart

    安装Helm

    在节点cka001上安装Helm。

    # https://github.com/helm/helm/releases
    -wget https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz
    -tar -zxvf helm-v3.8.2-linux-amd64.tar.gz
    -cp linux-amd64/helm /usr/bin/
    -rm -rf linux-amd64 helm-v3.8.2-linux-amd64.tar.gz
    -

    或者从链接 https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz 手工下载安装包,并拷贝到节点 cka001上。

    scp -i cka-key-pair.pem ./Package/helm-v3.8.2-linux-amd64.tar.gz root@cka001:/root/
    -
    ssh -i cka-key-pair.pem root@cka001
    -tar -zxvf helm-v3.8.2-linux-amd64.tar.gz
    -cp linux-amd64/helm /usr/bin/
    -rm -rf linux-amd64 helm-v3.8.2-linux-amd64.tar.gz
    -

    Helm用法

    检查 helm 的版本。

    helm version
    + Helm Chart - UPSkilling       

    CKA自学笔记27:Helm Chart

    安装Helm

    在节点cka001上安装Helm。

    # https://github.com/helm/helm/releases
    +wget https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz
    +tar -zxvf helm-v3.8.2-linux-amd64.tar.gz
    +cp linux-amd64/helm /usr/bin/
    +rm -rf linux-amd64 helm-v3.8.2-linux-amd64.tar.gz
    +

    或者从链接 https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz 手工下载安装包,并拷贝到节点 cka001上。

    scp -i cka-key-pair.pem ./Package/helm-v3.8.2-linux-amd64.tar.gz root@cka001:/root/
    +
    ssh -i cka-key-pair.pem root@cka001
    +tar -zxvf helm-v3.8.2-linux-amd64.tar.gz
    +cp linux-amd64/helm /usr/bin/
    +rm -rf linux-amd64 helm-v3.8.2-linux-amd64.tar.gz
    +

    Helm用法

    检查 helm 的版本。

    helm version
     

    运行结果:

    version.BuildInfo{Version:"v3.8.2", GitCommit:"6e3701edea09e5d55a8ca2aae03a68917630e91b", GitTreeState:"clean", GoVersion:"go1.17.5"}
    -

    获取 helm 的帮助信息。

    helm help
    -

    配置 helm 的命令自动补全功能。

    echo "source <(helm completion bash)" >> ~/.bashrc
    -source <(helm completion bash)
    -

    通过Helm安装MySQL

    添加Bitnami Chartes仓库。

    helm repo add bitnami https://charts.bitnami.com/bitnami
    -

    查询当前可用的Chartes仓库。

    helm repo list
    +

    获取 helm 的帮助信息。

    helm help
    +

    配置 helm 的命令自动补全功能。

    echo "source <(helm completion bash)" >> ~/.bashrc
    +source <(helm completion bash)
    +

    通过Helm安装MySQL

    添加Bitnami Chartes仓库。

    helm repo add bitnami https://charts.bitnami.com/bitnami
    +

    查询当前可用的Chartes仓库。

    helm repo list
     

    运行结果:

    NAME    URL
     bitnami https://charts.bitnami.com/bitnami
    -

    同步本地Charts仓库。

    helm repo update
    -

    在Charts仓库中查找bitnami Charts仓库。

    helm search repo bitnami
    -

    在仓库中搜索bitnami/mysql Charts。

    helm search repo bitnami/mysql
    -

    在namespace dev上安装MySQL Chart。

    helm install mysql bitnami/mysql -n dev
    +

    同步本地Charts仓库。

    helm repo update
    +

    在Charts仓库中查找bitnami Charts仓库。

    helm search repo bitnami
    +

    在仓库中搜索bitnami/mysql Charts。

    helm search repo bitnami/mysql
    +

    在namespace dev上安装MySQL Chart。

    helm install mysql bitnami/mysql -n dev
     

    运行结果:

    NAME: mysql
     LAST DEPLOYED: Sun Jul 24 19:37:20 2022
     NAMESPACE: dev
    @@ -56,16 +56,16 @@
       2. To connect to primary service (read/write):
     
           mysql -h mysql.dev.svc.cluster.local -uroot -p"$MYSQL_ROOT_PASSWORD"
    -

    查看当前安装包的信息。

    helm list
    +

    查看当前安装包的信息。

    helm list
     

    运行结果:

    NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
     mysql   dev             1               2022-07-24 19:37:20.710988009 +0800 CST deployed        mysql-9.2.1     8.0.29 
    -

    检查当前安装的mysql版本信息。

    helm status mysql
    -

    检查pod mysql 的状态。

    kubectl get pod
    +

    检查当前安装的mysql版本信息。

    helm status mysql
    +

    检查pod mysql 的状态。

    kubectl get pod
     

    运行结果:

    NAME                                      READY   STATUS    RESTARTS   AGE
     mysql-0                                   1/1     Running   0          72s
     

    部署一个Chart

    下面演示了如何部署一个Chart。

    执行命令 helm create 来初始化一个Chart。

    # Naming conventions of Chart: lowercase a~z and -(minus sign)
    -helm create cka-demo
    -

    目录 cka-demo 会被创建,查看这个目录的结构。

    tree cka-demo/
    +helm create cka-demo
    +

    目录 cka-demo 会被创建,查看这个目录的结构。

    tree cka-demo/
     

    运行结果:

    cka-demo/
     ├── charts
     ├── Chart.yaml
    @@ -80,23 +80,23 @@
     │   └── tests
     │       └── test-connection.yaml
     └── values.yaml
    -

    删除或清空某些文件,我们会在后面重新创建这些文件。

    cd cka-demo
    -rm -rf charts
    -rm -rf templates/tests 
    -rm -rf templates/*.yaml
    -echo "" > values.yaml
    -echo "" > templates/NOTES.txt
    -echo "" > templates/_helpers.tpl
    -cd ..
    -

    目录 cka-demo 的架构现在应该看起来类似下面的结果。

    tree cka-demo/
    +

    删除或清空某些文件,我们会在后面重新创建这些文件。

    cd cka-demo
    +rm -rf charts
    +rm -rf templates/tests 
    +rm -rf templates/*.yaml
    +echo "" > values.yaml
    +echo "" > templates/NOTES.txt
    +echo "" > templates/_helpers.tpl
    +cd ..
    +

    目录 cka-demo 的架构现在应该看起来类似下面的结果。

    tree cka-demo/
     

    运行结果:

    cka-demo/
     ├── Chart.yaml
     ├── templates
     │   ├── _helpers.tpl
     │   └── NOTES.txt
     └── values.yaml
    -

    NOTES.txt

    NOTES.txt 用于向 Chart 用户提供概要信息。在演示中,我们将使用 NOTES.txt 提供关于用户是否通过 CKA 认证的概要信息。

    cd cka-demo/
    -vi templates/NOTES.txt
    +

    NOTES.txt

    NOTES.txt 用于向 Chart 用户提供概要信息。在演示中,我们将使用 NOTES.txt 提供关于用户是否通过 CKA 认证的概要信息。

    cd cka-demo/
    +vi templates/NOTES.txt
     

    添加下面的内容。

    {{- if .Values.passExam }}
     Congratulations!
     
    @@ -110,113 +110,113 @@
     {{- else }}
     Come on! you can do it next time!
     {{- end }}
    -

    部署模版

    下面会使用 Busybox 服务来生成信息。 通过命令 kubectl create deployment --dry-run=client -oyaml 生成 Deployment 的 YAML 文件,并将其内容写入文件 templates/deployment.yaml

    kubectl create deployment cka-demo-busybox --image=busybox:latest --dry-run=client -oyaml > templates/deployment.yaml
    -

    检查deployment的yaml文件templates/deployment.yaml的内容。

    cat templates/deployment.yaml
    -

    运行结果:

    apiVersion: apps/v1
    -kind: Deployment
    -metadata:
    -  creationTimestamp: null
    -  labels:
    -    app: cka-demo-busybox
    -  name: cka-demo-busybox
    -spec:
    -  replicas: 1
    -  selector:
    -    matchLabels:
    -      app: cka-demo-busybox
    -  strategy: {}
    -  template:
    -    metadata:
    -      creationTimestamp: null
    -      labels:
    -        app: cka-demo-busybox
    -    spec:
    -      containers:
    -      - image: busybox:latest
    -        name: busybox
    -        resources: {}
    -status: {}
    -

    编辑修改文件 templates/deployment.yaml

    vi templates/deployment.yaml
    -

    让我们将 .spec.replicas 的值从 1 替换为变量 {{ .Values.replicaCount }},这样我们可以为其他 Deployment 动态分配副本数。

    apiVersion: apps/v1
    -kind: Deployment
    -metadata:
    -  creationTimestamp: null
    -  labels:
    -    app: cka-demo-busybox
    -  name: cka-demo-busybox
    -spec:
    -  replicas: {{ .Values.replicaCount }}
    -  selector:
    -    matchLabels:
    -      app: cka-demo-busybox
    -  strategy: {}
    -  template:
    -    metadata:
    -      creationTimestamp: null
    -      labels:
    -        app: cka-demo-busybox
    -    spec:
    -      containers:
    -      - image: busybox:latest
    -        name: busybox
    -        resources: {}
    -status: {}
    -

    .spec.replicas 将在部署期间被实际的 .Values.replicaCount 值替换。

    现在创建另一个文件 values.yaml 并在文件中添加一个变量 replicaCount,默认值为1。

    强烈建议在文件 values.yaml 中定义的每个值添加注释。

    vi values.yaml
    -

    输出结果:

    # Number of deployment replicas
    +

    部署模版

    下面会使用 Busybox 服务来生成信息。 通过命令 kubectl create deployment --dry-run=client -oyaml 生成 Deployment 的 YAML 文件,并将其内容写入文件 templates/deployment.yaml

    kubectl create deployment cka-demo-busybox --image=busybox:latest --dry-run=client -oyaml > templates/deployment.yaml
    +

    检查deployment的yaml文件templates/deployment.yaml的内容。

    cat templates/deployment.yaml
    +

    运行结果:

    apiVersion: apps/v1
    +kind: Deployment
    +metadata:
    +  creationTimestamp: null
    +  labels:
    +    app: cka-demo-busybox
    +  name: cka-demo-busybox
    +spec:
    +  replicas: 1
    +  selector:
    +    matchLabels:
    +      app: cka-demo-busybox
    +  strategy: {}
    +  template:
    +    metadata:
    +      creationTimestamp: null
    +      labels:
    +        app: cka-demo-busybox
    +    spec:
    +      containers:
    +      - image: busybox:latest
    +        name: busybox
    +        resources: {}
    +status: {}
    +

    编辑修改文件 templates/deployment.yaml

    vi templates/deployment.yaml
    +

    让我们将 .spec.replicas 的值从 1 替换为变量 {{ .Values.replicaCount }},这样我们可以为其他 Deployment 动态分配副本数。

    apiVersion: apps/v1
    +kind: Deployment
    +metadata:
    +  creationTimestamp: null
    +  labels:
    +    app: cka-demo-busybox
    +  name: cka-demo-busybox
    +spec:
    +  replicas: {{ .Values.replicaCount }}
    +  selector:
    +    matchLabels:
    +      app: cka-demo-busybox
    +  strategy: {}
    +  template:
    +    metadata:
    +      creationTimestamp: null
    +      labels:
    +        app: cka-demo-busybox
    +    spec:
    +      containers:
    +      - image: busybox:latest
    +        name: busybox
    +        resources: {}
    +status: {}
    +

    .spec.replicas 将在部署期间被实际的 .Values.replicaCount 值替换。

    现在创建另一个文件 values.yaml 并在文件中添加一个变量 replicaCount,默认值为1。

    强烈建议在文件 values.yaml 中定义的每个值添加注释。

    vi values.yaml
    +

    输出结果:

    # Number of deployment replicas
     replicaCount: 1
    -

    下面对文件 templates/deployment.yaml 添加更多的变量。

    • .metadata.name 的 Release 名称替换为 {{ .Release.Name }},并用在 values.yaml 文件中定义的变量填充。
    • 将标签名称 .metadata.labels 替换为 {{- include "cka-demo.labels" . | nindent 4 }},并用在 _helpers.tpl 文件中定义的标签名称 cka-demo.labels 填充。
    • .spec.replicas 替换为 {{ .Values.replicaCount }},并用在 values.yaml 文件中定义的变量填充。
    • .spec.selector.matchLabels 替换为 {{- include "cka-demo.selectorLabels" . | nindent 6 }} 并使用在 _helpers.tpl 文件中定义的 cka-demo.selectorLabels 进行填充。
    • .spec.template.metadata.labels 替换为 {{- include "cka-demo.selectorLabels" . | nindent 8 }} 并使用在 _helpers.tpl 文件中定义的 cka-demo.selectorLabels 进行填充。
    • .spec.template.spec.containers[0].image 替换为 {{ .Values.image.repository }}{{ .Values.image.tag }} 并使用在 values.yaml 文件中定义的变量填充镜像名称和镜像标签。
    • .spec.template.spec.containers[0].command 替换为一个 if-else 语句,如果 .Values.passExam 为真,则执行在 .Values.passCommand 中定义的命令,否则执行在 .Values.lostCommand 中定义的命令。
    • 使用 .spec.template.spec.containers[0].env 中的 key 作为 ConfigMap 名称的前缀,并使用在 values.yaml 文件中定义的 {{ .Values.studentName }} 进行填充。
    • .spec.template.spec.containers[0].resources 替换为 {{ .Values.resources }} 并使用在 values.yaml 文件中定义的变量进行填充。

    .Release.Name是内置对象,在文件values.yaml中不需要指定。它是由helm install生成的Release。

    移除不必要的行,最终文件看起来类似下面的结果:

    apiVersion: apps/v1
    -kind: Deployment
    -metadata:
    -  name: {{ .Release.Name }}
    -  labels:
    -    {{- include "cka-demo.labels" . | nindent 4 }}
    -spec:
    -  replicas: {{ .Values.replicaCount }}
    -  selector:
    -    matchLabels:
    -      {{- include "cka-demo.selectorLabels" . | nindent 6 }}
    -  template:
    -    metadata:
    -      labels:
    -        {{- include "cka-demo.selectorLabels" . | nindent 8 }}
    -    spec:
    -      containers:
    -      - name: id-generator
    -        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
    -        {{- if .Values.passExam }}
    -        {{- with .Values.passCommand }}
    -        command: {{ range . }}
    -          - {{ . | quote }}
    -          {{- end }}
    -          {{- end }}
    -        {{- else }}
    -        {{- with .Values.lostCommand }}
    -        command: {{ range . }}
    -          - {{ . | quote }}
    -          {{- end }}
    -          {{- end }}
    -        {{- end }}
    -        env:
    -        - name: CKA_SCORE
    -          valueFrom:
    -            configMapKeyRef:
    -              name: {{ .Values.studentName }}-cka-score
    -              key: cka_score
    -        {{- with .Values.resources }}
    -        resources:
    -            {{- toYaml . | nindent 12 }}
    -          {{- end}}
    -      restartPolicy: Always
    -

    更新文件 values.yaml 中变量的默认值。建议逐个添加变量并测试,不要一次添加所有变量。

    vi values.yaml
    -

    运行结果:

    # Number of deployment replicas 
    +

    下面对文件 templates/deployment.yaml 添加更多的变量。

    • .metadata.name 的 Release 名称替换为 {{ .Release.Name }},并用在 values.yaml 文件中定义的变量填充。
    • 将标签名称 .metadata.labels 替换为 {{- include "cka-demo.labels" . | nindent 4 }},并用在 _helpers.tpl 文件中定义的标签名称 cka-demo.labels 填充。
    • .spec.replicas 替换为 {{ .Values.replicaCount }},并用在 values.yaml 文件中定义的变量填充。
    • .spec.selector.matchLabels 替换为 {{- include "cka-demo.selectorLabels" . | nindent 6 }} 并使用在 _helpers.tpl 文件中定义的 cka-demo.selectorLabels 进行填充。
    • .spec.template.metadata.labels 替换为 {{- include "cka-demo.selectorLabels" . | nindent 8 }} 并使用在 _helpers.tpl 文件中定义的 cka-demo.selectorLabels 进行填充。
    • .spec.template.spec.containers[0].image 替换为 {{ .Values.image.repository }}{{ .Values.image.tag }} 并使用在 values.yaml 文件中定义的变量填充镜像名称和镜像标签。
    • .spec.template.spec.containers[0].command 替换为一个 if-else 语句,如果 .Values.passExam 为真,则执行在 .Values.passCommand 中定义的命令,否则执行在 .Values.lostCommand 中定义的命令。
    • 使用 .spec.template.spec.containers[0].env 中的 key 作为 ConfigMap 名称的前缀,并使用在 values.yaml 文件中定义的 {{ .Values.studentName }} 进行填充。
    • .spec.template.spec.containers[0].resources 替换为 {{ .Values.resources }} 并使用在 values.yaml 文件中定义的变量进行填充。

    .Release.Name是内置对象,在文件values.yaml中不需要指定。它是由helm install生成的Release。

    移除不必要的行,最终文件看起来类似下面的结果:

    apiVersion: apps/v1
    +kind: Deployment
    +metadata:
    +  name: {{ .Release.Name }}
    +  labels:
    +    {{- include "cka-demo.labels" . | nindent 4 }}
    +spec:
    +  replicas: {{ .Values.replicaCount }}
    +  selector:
    +    matchLabels:
    +      {{- include "cka-demo.selectorLabels" . | nindent 6 }}
    +  template:
    +    metadata:
    +      labels:
    +        {{- include "cka-demo.selectorLabels" . | nindent 8 }}
    +    spec:
    +      containers:
    +      - name: id-generator
    +        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
    +        {{- if .Values.passExam }}
    +        {{- with .Values.passCommand }}
    +        command: {{ range . }}
    +          - {{ . | quote }}
    +          {{- end }}
    +          {{- end }}
    +        {{- else }}
    +        {{- with .Values.lostCommand }}
    +        command: {{ range . }}
    +          - {{ . | quote }}
    +          {{- end }}
    +          {{- end }}
    +        {{- end }}
    +        env:
    +        - name: CKA_SCORE
    +          valueFrom:
    +            configMapKeyRef:
    +              name: {{ .Values.studentName }}-cka-score
    +              key: cka_score
    +        {{- with .Values.resources }}
    +        resources:
    +            {{- toYaml . | nindent 12 }}
    +          {{- end}}
    +      restartPolicy: Always
    +

    更新文件 values.yaml 中变量的默认值。建议逐个添加变量并测试,不要一次添加所有变量。

    vi values.yaml
    +

    运行结果:

    # Number of deployment replicas 
     replicaCount: 1
     
    -# Image repository and tag
    +# Image repository and tag
     image:
       repository: busybox
       tag: latest
     
    -# Container start command
    +# Container start command
     passCommand:
       - '/bin/sh'
       - '-c'
    @@ -226,7 +226,7 @@
       - '-c'
       - "echo Your CKA score is $(CKA_SCORE), Come on! you can do it next time! ; sleep 86400"
     
    -# Container resources
    +# Container resources
     resources:
       limits:
         cpu: 200m
    @@ -235,24 +235,24 @@
         cpu: 100m
         memory: 128Mi
     
    -# Student Name
    +# Student Name
     studentName: whoareyou
     
    -# Student pass CKA exam or not
    +# Student pass CKA exam or not
     passExam: true
    -

    ConfigMap模版

    ConfigMap被部署中的Deployment所引用,因此我们需要定义ConfigMap的模板。 我们将把ConfigMap的名称和cka_score组合成一个变量,例如name-cka-score

    vi templates/configmap.yaml
    -

    运行结果:

    apiVersion: v1
    -kind: ConfigMap
    -metadata:
    -  name: {{ .Values.studentName }}-cka-score
    -  labels:
    -    {{- include "cka-demo.labels" . | nindent 4 }}
    -data:
    -  cka_score: {{ .Values.ckaScore | quote }}
    -

    studentName已经在values.yaml文件中定义过了,我们只需要添加一个名为ckaScore的变量并给它一个默认值即可。

    vi values.yaml
    -

    运行结果

    # Student CKA Score
    +

    ConfigMap模版

    ConfigMap被部署中的Deployment所引用,因此我们需要定义ConfigMap的模板。 我们将把ConfigMap的名称和cka_score组合成一个变量,例如name-cka-score

    vi templates/configmap.yaml
    +

    运行结果:

    apiVersion: v1
    +kind: ConfigMap
    +metadata:
    +  name: {{ .Values.studentName }}-cka-score
    +  labels:
    +    {{- include "cka-demo.labels" . | nindent 4 }}
    +data:
    +  cka_score: {{ .Values.ckaScore | quote }}
    +

    studentName已经在values.yaml文件中定义过了,我们只需要添加一个名为ckaScore的变量并给它一个默认值即可。

    vi values.yaml
    +

    运行结果

    # Student CKA Score
     ckaScore: 100
    -

    _helpers.tpl

    定义一个通用的模板_helpers.tpl,为Deployment和ConfigMap的标签和选择器标签添加标签。

    vi templates/_helpers.tpl
    +

    _helpers.tpl

    定义一个通用的模板_helpers.tpl,为Deployment和ConfigMap的标签和选择器标签添加标签。

    vi templates/_helpers.tpl
     

    运行结果:

    {{/*
     Common labels
     */}}
    @@ -272,10 +272,10 @@
     app: {{ .Chart.Name }}
     release: {{ .Release.Name }}
     {{- end -}}
    -

    Chart.yaml

    这里我们使用CKA的logo来作为Chart的图标。

    wget https://www.cncf.io/wp-content/uploads/2021/09/kubernetes-cka-color.svg
    -

    编辑修改 Chart.yaml 文件。

    vi Chart.yaml
    +

    Chart.yaml

    这里我们使用CKA的logo来作为Chart的图标。

    wget https://www.cncf.io/wp-content/uploads/2021/09/kubernetes-cka-color.svg
    +

    编辑修改 Chart.yaml 文件。

    vi Chart.yaml
     

    把图标信息添加到Chart.yaml文件末尾。

    icon: file://./kubernetes-cka-color.svg
    -

    把作者信息添加到Chart.yaml文件末尾。

    vi Chart.yaml
    +

    把作者信息添加到Chart.yaml文件末尾。

    vi Chart.yaml
     

    运行结果:

    maintainers:
       - name: James.H
     

    最终的 Chart.yaml 类似如下内容。别忘记更新 appVersion: "v1.23" 为当前Kubernetes的版本。

    apiVersion: v2
    @@ -287,28 +287,28 @@
     maintainers:
       - name: James.H
     icon: file://./kubernetes-cka-color.svg
    -

    Chart Debug

    使用 helm lint 来验证上述变更。

    helm lint
    +

    Chart Debug

    使用 helm lint 来验证上述变更。

    helm lint
     

    运行结果:

    1 chart(s) linted, 0 chart(s) failed
    -

    helm lint 只检查Chart的格式,不检查Manifest文件。

    我们可以使用 helm install --debug --dry-runhelm template 命令来检查生成的 Manifest 是否正确。

    helm template cka-demo ./
    -

    通过命令 helm install --debug --dry-run来模拟安装。我们可以从两个不同的选项(通过或未通过CKA认证)中获得预期的结果。

    helm install --debug --dry-run cka-demo ./ --create-namespace \
    -  -n cka \
    -  --set studentName=kubernetes \
    -  --set ckaScore=99 \
    -  --set passExam=true
    +

    helm lint 只检查Chart的格式,不检查Manifest文件。

    我们可以使用 helm install --debug --dry-runhelm template 命令来检查生成的 Manifest 是否正确。

    helm template cka-demo ./
    +

    通过命令 helm install --debug --dry-run来模拟安装。我们可以从两个不同的选项(通过或未通过CKA认证)中获得预期的结果。

    helm install --debug --dry-run cka-demo ./ --create-namespace \
    +  -n cka \
    +  --set studentName=kubernetes \
    +  --set ckaScore=99 \
    +  --set passExam=true
     
    -helm install --debug --dry-run cka-demo ./ --create-namespace \
    -  -n cka \
    -  --set studentName=kubernetes \
    -  --set ckaScore=0 \
    -  --set passExam=false
    -

    把 Chart 打包成 .tgz 文件,并上传到仓库,例如 Chart Museum 或者 OCI Repo。

    cd ../
    -helm package cka-demo
    +helm install --debug --dry-run cka-demo ./ --create-namespace \
    +  -n cka \
    +  --set studentName=kubernetes \
    +  --set ckaScore=0 \
    +  --set passExam=false
    +

    把 Chart 打包成 .tgz 文件,并上传到仓库,例如 Chart Museum 或者 OCI Repo。

    cd ../
    +helm package cka-demo
     

    运行结果:

    Successfully packaged chart and saved it to: /root/cka-demo-0.1.0.tgz
    -

    至此,我们已经完成了配置一个新的Chart,现在开始安装这个Chart。

    helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \
    -  -n cka \
    -  --set studentName=kubernetes \
    -  --set ckaScore=0 \
    -  --set passExam=false
    +

    至此,我们已经完成了配置一个新的Chart,现在开始安装这个Chart。

    helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \
    +  -n cka \
    +  --set studentName=kubernetes \
    +  --set ckaScore=0 \
    +  --set passExam=false
     

    运行结果:

    NAME: cka-demo
     LAST DEPLOYED: Sun Jul 24 19:58:36 2022
     NAMESPACE: cka
    @@ -317,20 +317,20 @@
     TEST SUITE: None
     NOTES:
     Come on! you can do it next time!
    -

    检查部署情况:

    helm list --all-namespaces
    +

    检查部署情况:

    helm list --all-namespaces
     

    运行结果:

    NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
     cka-demo        cka             1               2022-07-24 19:58:36.272093383 +0800 CST deployed        cka-demo-0.1.0  v1.23      
     mysql           dev             1               2022-07-24 19:37:20.710988009 +0800 CST deployed        mysql-9.2.1     8.0.29  
    -

    如果遇到错误,则需要卸载cka-demo并重新安装它。

    helm uninstall cka-demo -n <your_namespace>
    -

    检查cka-demo的日志。

    kubectl logs -n cka -l app=cka-demo
    +

    如果遇到错误,则需要卸载cka-demo并重新安装它。

    helm uninstall cka-demo -n <your_namespace>
    +

    检查cka-demo的日志。

    kubectl logs -n cka -l app=cka-demo
     

    运行结果

    Your CKA score is 0, Come on! you can do it next time!
    -

    通过其他选项安装 cka-demo

    helm uninstall cka-demo -n cka
    +

    通过其他选项安装 cka-demo

    helm uninstall cka-demo -n cka
     
    -helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \
    -  -n cka \
    -  --set studentName=kubernetes \
    -  --set ckaScore=100 \
    -  --set passExam=true
    +helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \
    +  -n cka \
    +  --set studentName=kubernetes \
    +  --set ckaScore=100 \
    +  --set passExam=true
     

    运行结果:

    NAME: cka-demo
     LAST DEPLOYED: Sun Jul 24 20:01:34 2022
     NAMESPACE: cka
    @@ -347,7 +347,7 @@
     Click the link below to view and download your certificate.
     
     https://trainingportal.linuxfoundation.org/learn/dashboard
    -

    检查 cka-demo 的日志。

    kubectl logs -n cka -l app=cka-demo
    +

    检查 cka-demo 的日志。

    kubectl logs -n cka -l app=cka-demo
     

    运行结果:

    Your CKA score is 100 and your CKA certificate ID number is BQKoVYVhjzl3G
     

    Built-in Objects列表

    Release.Name                              # 发布名称
     Release.Namespace                         # 发布Namespace
    @@ -366,4 +366,4 @@
     Template                                  # 当前模板信息
     Template.Name                             # 当前模板文件路径
     Template.BasePath                         # 当前模板目录路径
    -

    参考:

    \ No newline at end of file +

    参考:

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/hpa/index.html b/k8s/cka_cn/foundamentals/hpa/index.html index 7b9c1a61..6b8484f6 100644 --- a/k8s/cka_cn/foundamentals/hpa/index.html +++ b/k8s/cka_cn/foundamentals/hpa/index.html @@ -1,23 +1,23 @@ - Horizontal Pod Autoscaling (HPA) - UPSkilling

    CKA自学笔记21:Horizontal Pod Autoscaling (HPA)

    演示场景:

    • 安装 Metrics Server 组件
    • 创建 Deployment podinfo 和 Service podinfo 用于压力测试
    • 创建 HPA my-hpa
    • 进行压力测试

    安装Metrics Server

    下载components.yaml文件,来部署Metrics Server。

    wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
    -

    把yaml文件中google的镜像源替换为阿里的镜像源 image: registry.aliyuncs.com/google_containers/metrics-server:v0.6.1

    sed -i 's/k8s\.gcr\.io\/metrics-server\/metrics-server\:v0\.6\.1/registry\.aliyuncs\.com\/google_containers\/metrics-server\:v0\.6\.1/g' components.yaml
    -

    修改deployment metrics-serverargs,添加选项 --kubelet-insecure-tls 以禁用证书验证。

    vi components.yaml
    -

    更新 args

    ......
    -  template:
    -    metadata:
    -      labels:
    -        k8s-app: metrics-server
    -    spec:
    -      containers:
    -      - args:
    -        - --cert-dir=/tmp
    -        - --secure-port=4443
    -        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
    -        - --kubelet-use-node-status-port
    -        - --metric-resolution=15s
    -        - --kubelet-insecure-tls
    -        image: registry.aliyuncs.com/google_containers/metrics-server:v0.6.1
    -......
    -

    应用文件components.yaml来部署metrics-server

    kubectl apply -f components.yaml
    + Horizontal Pod Autoscaling (HPA) - UPSkilling       

    CKA自学笔记21:Horizontal Pod Autoscaling (HPA)

    演示场景:

    • 安装 Metrics Server 组件
    • 创建 Deployment podinfo 和 Service podinfo 用于压力测试
    • 创建 HPA my-hpa
    • 进行压力测试

    安装Metrics Server

    下载components.yaml文件,来部署Metrics Server。

    wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
    +

    把yaml文件中google的镜像源替换为阿里的镜像源 image: registry.aliyuncs.com/google_containers/metrics-server:v0.6.1

    sed -i 's/k8s\.gcr\.io\/metrics-server\/metrics-server\:v0\.6\.1/registry\.aliyuncs\.com\/google_containers\/metrics-server\:v0\.6\.1/g' components.yaml
    +

    修改deployment metrics-serverargs,添加选项 --kubelet-insecure-tls 以禁用证书验证。

    vi components.yaml
    +

    更新 args

    ......
    +  template:
    +    metadata:
    +      labels:
    +        k8s-app: metrics-server
    +    spec:
    +      containers:
    +      - args:
    +        - --cert-dir=/tmp
    +        - --secure-port=4443
    +        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
    +        - --kubelet-use-node-status-port
    +        - --metric-resolution=15s
    +        - --kubelet-insecure-tls
    +        image: registry.aliyuncs.com/google_containers/metrics-server:v0.6.1
    +......
    +

    应用文件components.yaml来部署metrics-server

    kubectl apply -f components.yaml
     

    下面是运行结果,相关资源被创建。

    serviceaccount/metrics-server created
     clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
     clusterrole.rbac.authorization.k8s.io/system:metrics-server created
    @@ -27,15 +27,15 @@
     service/metrics-server created
     deployment.apps/metrics-server created
     apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
    -

    验证 pod metrics-server 是否按预期在正常运行。

    kubectl get pod -n kube-system -owide | grep metrics-server
    +

    验证 pod metrics-server 是否按预期在正常运行。

    kubectl get pod -n kube-system -owide | grep metrics-server
     

    运行结果。关注READY下的状态:1/1 running代表正常运行。

    NAME                                       READY   STATUS    RESTARTS   AGE     IP               NODE     NOMINATED NODE   READINESS GATES
     metrics-server-7fd564dc66-sdhdc            1/1     Running   0          61s     10.244.102.15    cka003   <none>           <none>
    -

    查询每个节点上当前CPU和内存的用量情况。

    kubectl top node
    +

    查询每个节点上当前CPU和内存的用量情况。

    kubectl top node
     

    运行结果:

    NAME     CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
     cka001   595m         29%    1937Mi          50%       
     cka002   75m          3%     1081Mi          28%       
     cka003   79m          3%     1026Mi          26% 
    -

    部署服务podinfo

    创建 Deployment podinfo 和 Service podinfo ,后面会进行更进一步的压力测试。

    kubectl apply -f - << EOF
    +

    部署服务podinfo

    创建 Deployment podinfo 和 Service podinfo ,后面会进行更进一步的压力测试。

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Service
     metadata:
    @@ -88,9 +88,9 @@
                 memory: "256Mi"
                 cpu: "100m"
     EOF
    -

    Config HPA

    创建一个名为 my-hpa 的 HPA,并将其绑定到名为 podinfo 的部署中,设定其 CPU 利用率为 50% 作为触发自动缩放的阈值,最小副本数为 2,最大副本数为 10

    使用以下命令创建 my-hpa HPA:

    kubectl autoscale deployment podinfo --cpu-percent=50 --min=2 --max=10 --name=my-hpa
    -kubectl autoscale deployment podinfo --cpu-percent=50 --min=1 --max=10
    -

    使用 autoscaling/v1 版本的模版来创建HPA my-hpa

    kubectl apply -f - <<EOF
    +

    Config HPA

    创建一个名为 my-hpa 的 HPA,并将其绑定到名为 podinfo 的部署中,设定其 CPU 利用率为 50% 作为触发自动缩放的阈值,最小副本数为 2,最大副本数为 10

    使用以下命令创建 my-hpa HPA:

    kubectl autoscale deployment podinfo --cpu-percent=50 --min=2 --max=10 --name=my-hpa
    +kubectl autoscale deployment podinfo --cpu-percent=50 --min=1 --max=10
    +

    使用 autoscaling/v1 版本的模版来创建HPA my-hpa

    kubectl apply -f - <<EOF
     apiVersion: autoscaling/v1
     kind: HorizontalPodAutoscaler
     metadata:
    @@ -104,7 +104,7 @@
       maxReplicas: 10
       targetCPUUtilizationPercentage: 50
     EOF
    -

    使用 autoscaling/v2 版本的模版来创建HPA my-hpa,在matrics中增加内存控制。

    kubectl apply -f - <<EOF
    +

    使用 autoscaling/v2 版本的模版来创建HPA my-hpa,在matrics中增加内存控制。

    kubectl apply -f - <<EOF
     apiVersion: autoscaling/v2
     kind: HorizontalPodAutoscaler
     metadata:
    @@ -130,12 +130,12 @@
             type: AverageValue
             averageValue: 100Mi
     EOF
    -

    查看HPA的状态。

    kubectl get hpa
    +

    查看HPA的状态。

    kubectl get hpa
     

    查询结果:

    NAME     REFERENCE            TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
     my-hpa   Deployment/podinfo   2%/50%    2         10        2          60s
    -

    提示:

    • metrics.resource 表示要进行自动扩缩容的指标。在与目标值比较之前,这些指标值将被平均。
    • metrics.resource.target.type 表示指标类型是 Utilization、Value 还是 AverageValue。
    • metrics.resource.target.averageUtilization 是所有相关 Pod 资源指标平均值的目标值,表示为 Pod 请求该资源的百分比。当前仅适用于 Resource 指标类型。
    • metrics.resource.target.averageValue (Quantity) 是所有相关 Pod 指标平均值的目标值,以数量形式表示。
    • metrics.resource.target.value (Quantity) 是指标的目标值,以数量形式表示。

    参考:

    压力测试

    安装ab

    这里我们使用 ab 工具模拟 1000 个并发请求。

    ab 命令是一个命令行负载测试和基准测试工具,用于模拟向网站发送高流量。 Apache.org 中对ab的简短定义为:ab 首字母缩写代表 Apache Bench,其中 bench 是 benchmarking 的简写。

    执行下面的命令安装 ab 工具。

    sudo apt install apache2-utils -y
    -

    命令 ab 中最常用的2个选项是 -n-c

    • -n requests:请求次数
    • -c concurrency:并发数
    • -t timelimit:压测时间,单位是秒,默认是50000
    • -p postfile:POST 文件,同时也需要使用选项-T
    • -T content-type:指定 Content-type。Content-type header是POST或PUT数据时用来指定数据类型的header,例如'application/x-www-form-urlencoded'和'text/plain'。默认为'text/plain'。
    • -k:开启 HTTP KeepAlive 特性

    例如:

    ab -n 1000 -c 100 http://www.baidu.com/
    -

    并发压力测试

    对当前节点运行命令 ab 进行1000并发请求模拟。节点端口 31198podinfo 服务的端口。

    ab -c 1000 -t 60 http://127.0.0.1:31198/
    +

    提示:

    • metrics.resource 表示要进行自动扩缩容的指标。在与目标值比较之前,这些指标值将被平均。
    • metrics.resource.target.type 表示指标类型是 Utilization、Value 还是 AverageValue。
    • metrics.resource.target.averageUtilization 是所有相关 Pod 资源指标平均值的目标值,表示为 Pod 请求该资源的百分比。当前仅适用于 Resource 指标类型。
    • metrics.resource.target.averageValue (Quantity) 是所有相关 Pod 指标平均值的目标值,以数量形式表示。
    • metrics.resource.target.value (Quantity) 是指标的目标值,以数量形式表示。

    参考:

    压力测试

    安装ab

    这里我们使用 ab 工具模拟 1000 个并发请求。

    ab 命令是一个命令行负载测试和基准测试工具,用于模拟向网站发送高流量。 Apache.org 中对ab的简短定义为:ab 首字母缩写代表 Apache Bench,其中 bench 是 benchmarking 的简写。

    执行下面的命令安装 ab 工具。

    sudo apt install apache2-utils -y
    +

    命令 ab 中最常用的2个选项是 -n-c

    • -n requests:请求次数
    • -c concurrency:并发数
    • -t timelimit:压测时间,单位是秒,默认是50000
    • -p postfile:POST 文件,同时也需要使用选项-T
    • -T content-type:指定 Content-type。Content-type header是POST或PUT数据时用来指定数据类型的header,例如'application/x-www-form-urlencoded'和'text/plain'。默认为'text/plain'。
    • -k:开启 HTTP KeepAlive 特性

    例如:

    ab -n 1000 -c 100 http://www.baidu.com/
    +

    并发压力测试

    对当前节点运行命令 ab 进行1000并发请求模拟。节点端口 31198podinfo 服务的端口。

    ab -c 1000 -t 60 http://127.0.0.1:31198/
     

    通过命令 kubectl get hpa -w,我们可以看到 CPU 工作负载一直在增加。

    NAME    REFERENCE            TARGETS     MINPODS   MAXPODS   REPLICAS   AGE
     ......
     nginx   Deployment/podinfo   199%/50%    2         10        10         14m
    @@ -145,12 +145,12 @@
     nginx   Deployment/podinfo   728%/50%    2         10        10         15m
     nginx   Deployment/podinfo   119%/50%    2         10        10         15m
     ......
    -

    通过下面命令我们可以看到 Deployment podinfo 被触发了自动扩缩容。

    kubectl get pod
    -kubectl get deployment
    -

    注意,扩容是一个逐步的过程,而不是一个突然的事件来达到最大值。当 CPU 工作负载下降时,它将被缩小到一个平衡的状态。

    kubectl get hpa -w
    +

    通过下面命令我们可以看到 Deployment podinfo 被触发了自动扩缩容。

    kubectl get pod
    +kubectl get deployment
    +

    注意,扩容是一个逐步的过程,而不是一个突然的事件来达到最大值。当 CPU 工作负载下降时,它将被缩小到一个平衡的状态。

    kubectl get hpa -w
     

    几小时后,我们可以看到deployment的缩容结果。

    NAME     REFERENCE            TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
     my-hpa   Deployment/podinfo   2%/50%    2         10        2          60s
    -

    删除演示中所创建的临时资源。

    kubectl delete service podinfo
    -kubectl delete deployment podinfo
    -kubectl delete hpa my-hpa
    -
    \ No newline at end of file +

    删除演示中所创建的临时资源。

    kubectl delete service podinfo
    +kubectl delete deployment podinfo
    +kubectl delete hpa my-hpa
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/ingress/index.html b/k8s/cka_cn/foundamentals/ingress/index.html index 70ed753a..0d2f4a08 100644 --- a/k8s/cka_cn/foundamentals/ingress/index.html +++ b/k8s/cka_cn/foundamentals/ingress/index.html @@ -1,25 +1,25 @@ - Ingress-nginx - UPSkilling

    CKA自学笔记19:Ingress-nginx

    演示场景:

    • 部署Ingress Controller。
    • 创建两个Deployment nginx-app-1nginx-app-2
    • 在运行主机上创建主机目录 /root/html-1/root/html-2 并挂载到两个Deployment上。
    • 创建Service。
    • 创建Service nginx-app-1nginx-app-2并将其映射到相关的Deploymentnginx-app-1nginx-app-2
    • 创建Ingress。
    • 创建Ingress资源nginx-app并将其映射到两个Servicesnginx-app-1nginx-app-1
    • 测试可访问性。
    • 向Ingress中定义的两个主机发送HTTP请求。

    参考:

    部署Ingress控制器

    获取Ingress控制器的yaml文件。最新版本的链接在安装指南中。

    wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml
    -

    修改deploy.yaml文件中镜像源为阿里云的源。

    deploy.yaml文件中需要修改的行:

    image: k8s.gcr.io/ingress-nginx/controller:v1.2.1@sha256:5516d103a9c2ecc4f026efbd4b40662ce22dc1f824fb129ed121460aaa5c47f8
    -image: registry.k8s.io/ingress-nginx/controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5
    -image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
    -

    修改内容:

    • k8s.gcr.io/ingress-nginx/controller 改为 registry.aliyuncs.com/google_containers/nginx-ingress-controller
    • registry.k8s.io/ingress-nginx/controller 改为 registry.aliyuncs.com/google_containers/nginx-ingress-controller
    • k8s.gcr.io/ingress-nginx/kube-webhook-certgen 改为 registry.aliyuncs.com/google_containers/kube-webhook-certgen

    修改命令:

    sed -i 's/k8s.gcr.io\/ingress-nginx\/kube-webhook-certgen/registry.aliyuncs.com\/google\_containers\/kube-webhook-certgen/g' deploy.yaml
    -sed -i 's/k8s.gcr.io\/ingress-nginx\/controller/registry.aliyuncs.com\/google\_containers\/nginx-ingress-controller/g' deploy.yaml
    -

    应用文件 deploy.yaml 来创建 Ingress Nginx。

    一个新的命名空间namespace ingress-nginx 会被创建,Ingress Nginx相关的资源运行在这个namespace上。

    kubectl apply -f deploy.yaml
    -

    查看Pod的状态。

    kubectl get pod -n ingress-nginx
    + Ingress-nginx - UPSkilling       

    CKA自学笔记19:Ingress-nginx

    演示场景:

    • 部署Ingress Controller。
    • 创建两个Deployment nginx-app-1nginx-app-2
    • 在运行主机上创建主机目录 /root/html-1/root/html-2 并挂载到两个Deployment上。
    • 创建Service。
    • 创建Service nginx-app-1nginx-app-2并将其映射到相关的Deploymentnginx-app-1nginx-app-2
    • 创建Ingress。
    • 创建Ingress资源nginx-app并将其映射到两个Servicesnginx-app-1nginx-app-1
    • 测试可访问性。
    • 向Ingress中定义的两个主机发送HTTP请求。

    参考:

    部署Ingress控制器

    获取Ingress控制器的yaml文件。最新版本的链接在安装指南中。

    wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml
    +

    修改deploy.yaml文件中镜像源为阿里云的源。

    deploy.yaml文件中需要修改的行:

    image: k8s.gcr.io/ingress-nginx/controller:v1.2.1@sha256:5516d103a9c2ecc4f026efbd4b40662ce22dc1f824fb129ed121460aaa5c47f8
    +image: registry.k8s.io/ingress-nginx/controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5
    +image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
    +

    修改内容:

    • k8s.gcr.io/ingress-nginx/controller 改为 registry.aliyuncs.com/google_containers/nginx-ingress-controller
    • registry.k8s.io/ingress-nginx/controller 改为 registry.aliyuncs.com/google_containers/nginx-ingress-controller
    • k8s.gcr.io/ingress-nginx/kube-webhook-certgen 改为 registry.aliyuncs.com/google_containers/kube-webhook-certgen

    修改命令:

    sed -i 's/k8s.gcr.io\/ingress-nginx\/kube-webhook-certgen/registry.aliyuncs.com\/google\_containers\/kube-webhook-certgen/g' deploy.yaml
    +sed -i 's/k8s.gcr.io\/ingress-nginx\/controller/registry.aliyuncs.com\/google\_containers\/nginx-ingress-controller/g' deploy.yaml
    +

    应用文件 deploy.yaml 来创建 Ingress Nginx。

    一个新的命名空间namespace ingress-nginx 会被创建,Ingress Nginx相关的资源运行在这个namespace上。

    kubectl apply -f deploy.yaml
    +

    查看Pod的状态。

    kubectl get pod -n ingress-nginx
     

    确保所以pod的运行状态都正常,类似如下结果:

    NAME                                        READY   STATUS      RESTARTS   AGE
     ingress-nginx-admission-create-lgtdj        0/1     Completed   0          49s
     ingress-nginx-admission-patch-nk9fv         0/1     Completed   0          49s
     ingress-nginx-controller-556fbd6d6f-6jl4x   1/1     Running     0          49s
    -

    本地测试方式

    让我们创建一个简单的 Web 服务器和相关的服务:

    kubectl create deployment demo --image=httpd --port=80
    -kubectl expose deployment demo
    -

    接下来创建一个 Ingress 资源。以下示例使用将主机映射到 localhost:

    kubectl create ingress demo-localhost --class=nginx --rule="demo.localdev.me/*=demo:80"
    -

    现在,将本地端口转发到Ingress控制器:

    kubectl port-forward --namespace=ingress-nginx service/ingress-nginx-controller 8080:80
    -

    现在,在另一个终端中访问 http://demo.localdev.me:8080/,我们应该看到一个 HTML 页面,上面写着 "It works!"。

    curl http://demo.localdev.me:8080/
    +

    本地测试方式

    让我们创建一个简单的 Web 服务器和相关的服务:

    kubectl create deployment demo --image=httpd --port=80
    +kubectl expose deployment demo
    +

    接下来创建一个 Ingress 资源。以下示例使用将主机映射到 localhost:

    kubectl create ingress demo-localhost --class=nginx --rule="demo.localdev.me/*=demo:80"
    +

    现在,将本地端口转发到Ingress控制器:

    kubectl port-forward --namespace=ingress-nginx service/ingress-nginx-controller 8080:80
    +

    现在,在另一个终端中访问 http://demo.localdev.me:8080/,我们应该看到一个 HTML 页面,上面写着 "It works!"。

    curl http://demo.localdev.me:8080/
     

    运行结果;

    <html><body><h1>It works!</h1></body></html>
    -

    删除演示中创建的临时资源。

    kubectl delete ingress demo-localhost
    -kubectl delete service demo
    -kubectl delete deployment demo
    -

    创建Deployments

    创建2个deployment nginx-app-1nginx-app-2

    kubectl apply -f - << EOF
    +

    删除演示中创建的临时资源。

    kubectl delete ingress demo-localhost
    +kubectl delete service demo
    +kubectl delete deployment demo
    +

    创建Deployments

    创建2个deployment nginx-app-1nginx-app-2

    kubectl apply -f - << EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -74,19 +74,19 @@
              hostPath:
                path: /opt/html-2
     EOF
    -

    执行命令 kubectl get pod -o wide 来获取pod的状态。 可以看到一个pod运行在节点 cka002,另外一个pod运行在节点cka003

    • Directory /opt/html-2/ is on cka002
    • Directory /opt/html-1/ is on cka002

    通过curl命令来访问这2个pod,收到403 Forbidden错误。

    curl 10.244.102.13
    -curl 10.244.112.19
    -

    登录到节点cka002,执行下面命令,在/opt/html-2/路径下创建文件index.html

    cat <<EOF | sudo tee /opt/html-2/index.html
    +

    执行命令 kubectl get pod -o wide 来获取pod的状态。 可以看到一个pod运行在节点 cka002,另外一个pod运行在节点cka003

    • Directory /opt/html-2/ is on cka002
    • Directory /opt/html-1/ is on cka002

    通过curl命令来访问这2个pod,收到403 Forbidden错误。

    curl 10.244.102.13
    +curl 10.244.112.19
    +

    登录到节点cka002,执行下面命令,在/opt/html-2/路径下创建文件index.html

    cat <<EOF | sudo tee /opt/html-2/index.html
     This is test 2 !!
     EOF
    -

    登录到节点cka003,执行下面命令,在/opt/html-1/路径下创建文件index.html

    cat <<EOF | sudo tee /opt/html-1/index.html
    +

    登录到节点cka003,执行下面命令,在/opt/html-1/路径下创建文件index.html

    cat <<EOF | sudo tee /opt/html-1/index.html
     This is test 1 !!
     EOF
    -

    执行命令kubectl get pod -o wide,再次检查2个pod的状态。

    curl 10.244.102.13
    -curl 10.244.112.19
    +

    执行命令kubectl get pod -o wide,再次检查2个pod的状态。

    curl 10.244.102.13
    +curl 10.244.112.19
     

    现在可以通过curl命令来访问这2个pod了,收到了正确的回复信息。

    This is test 1 !!
     This is test 2 !!
    -

    创建Service

    创建 nginx-app-1nginx-app-2 这2个 Service,并将它们分别映射到相关的 Deployment nginx-app-1nginx-app-2

    kubectl apply -f - << EOF
    +

    创建Service

    创建 nginx-app-1nginx-app-2 这2个 Service,并将它们分别映射到相关的 Deployment nginx-app-1nginx-app-2

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Service
     metadata:
    @@ -111,12 +111,12 @@
      selector:
        app: nginx-app-2
     EOF
    -

    检查刚刚创建的service的状态。

    kubectl get svc -o wide
    -

    尝试通过curl命令来访问刚刚创建的service。

    curl 11.244.165.64
    -curl 11.244.222.177
    +

    检查刚刚创建的service的状态。

    kubectl get svc -o wide
    +

    尝试通过curl命令来访问刚刚创建的service。

    curl 11.244.165.64
    +curl 11.244.222.177
     

    收到了正确的信息,说明访问成功。

    This is test 1 !!
     This is test 2 !!
    -

    创建Ingress

    创建 Ingress 资源 nginx-app,将其映射到我们创建的两个 Service nginx-app-1nginx-app-2,并将其所在的 namespace 改为 default

    kubectl apply -f - << EOF
    +

    创建Ingress

    创建 Ingress 资源 nginx-app,将其映射到我们创建的两个 Service nginx-app-1nginx-app-2,并将其所在的 namespace 改为 default

    kubectl apply -f - << EOF
     apiVersion: networking.k8s.io/v1
     kind: Ingress
     metadata:
    @@ -146,26 +146,26 @@
                 port:
                   number: 80
     EOF
    -

    查看所创建的Ingress资源的状态。

    kubectl get ingress
    -

    可访问性测试

    执行以下命令,来确定 Ingress 控制器正在节点 cka003 上运行。

    kubectl get pod -n ingress-nginx -o wide
    -

    在当前节点上更新 /etc/hosts 文件。 将节点cka003的IP地址与两个主机名app1.comapp1.com进行映射,这些主机名表示Servicesnginx-app-1nginx-app-2。 Ingress Controllers正在节点cka003上运行。

    cat <<EOF | sudo tee -a /etc/hosts
    +

    查看所创建的Ingress资源的状态。

    kubectl get ingress
    +

    可访问性测试

    执行以下命令,来确定 Ingress 控制器正在节点 cka003 上运行。

    kubectl get pod -n ingress-nginx -o wide
    +

    在当前节点上更新 /etc/hosts 文件。 将节点cka003的IP地址与两个主机名app1.comapp1.com进行映射,这些主机名表示Servicesnginx-app-1nginx-app-2。 Ingress Controllers正在节点cka003上运行。

    cat <<EOF | sudo tee -a /etc/hosts
     <cka003_ip>  app1.com
     <cka003_ip>  app2.com
     EOF
    -

    执行以下命令,可以得到 IP 地址或 FQDN。

    kubectl get service ingress-nginx-controller --namespace=ingress-nginx
    -

    在输出结果中可以看到 EXTERNAL-IP 字段。如果该字段像下面一样显示为 <pending>,这意味着 Kubernetes 集群无法提供负载均衡器(通常是因为它不支持 LoadBalancer 类型的服务)。

    由于没有配置阿里云 ELB,因此有以下两个选项可以解决这个问题。

    选项 1:手动将节点 IP 添加到运行 ingress 控制器的节点上。

    执行命令 kubectl get pod -n ingress-nginx -o wide 来查看 ingress 控制器 pod 运行在哪个节点上。

    手动将 cka003 的外部 IP 补丁到 EXTERNAL-IP 字段。

    kubectl patch svc ingress-nginx-controller \
    - --namespace=ingress-nginx \
    - -p '{"spec": {"type": "LoadBalancer", "externalIPs":["<cka003_ip>"]}}'
    -

    选项 2:将 ingress 控制器从 LoadBalancer 类型更改为 NodePort 类型。

    两个 Pod 中各有一个 index.html 文件,Web 服务通过节点 IP 对外暴露。ingress-nginx-controller 作为中心入口点,为来自 Pod 的不同后端服务提供了两个端口。

    发送HTTP请求到在Ingress中定义的2个主机节点。

    curl http://app1.com:30011
    -curl http://app2.com:30011
    +

    执行以下命令,可以得到 IP 地址或 FQDN。

    kubectl get service ingress-nginx-controller --namespace=ingress-nginx
    +

    在输出结果中可以看到 EXTERNAL-IP 字段。如果该字段像下面一样显示为 <pending>,这意味着 Kubernetes 集群无法提供负载均衡器(通常是因为它不支持 LoadBalancer 类型的服务)。

    由于没有配置阿里云 ELB,因此有以下两个选项可以解决这个问题。

    选项 1:手动将节点 IP 添加到运行 ingress 控制器的节点上。

    执行命令 kubectl get pod -n ingress-nginx -o wide 来查看 ingress 控制器 pod 运行在哪个节点上。

    手动将 cka003 的外部 IP 补丁到 EXTERNAL-IP 字段。

    kubectl patch svc ingress-nginx-controller \
    + --namespace=ingress-nginx \
    + -p '{"spec": {"type": "LoadBalancer", "externalIPs":["<cka003_ip>"]}}'
    +

    选项 2:将 ingress 控制器从 LoadBalancer 类型更改为 NodePort 类型。

    两个 Pod 中各有一个 index.html 文件,Web 服务通过节点 IP 对外暴露。ingress-nginx-controller 作为中心入口点,为来自 Pod 的不同后端服务提供了两个端口。

    发送HTTP请求到在Ingress中定义的2个主机节点。

    curl http://app1.com:30011
    +curl http://app2.com:30011
     
    -curl app1.com:30011
    -curl app2.com:30011
    +curl app1.com:30011
    +curl app2.com:30011
     

    可以得到下面的信息,说明访问成功。

    This is test 1 !!
     This is test 2 !!
    -

    删除上面演示中创建的临时资源。

    kubectl delete ingress ingress-nginx-app
    -kubectl delete service nginx-app-1
    -kubectl delete service nginx-app-2
    -kubectl delete deployment nginx-app-1
    -kubectl delete deployment nginx-app-2
    -
    \ No newline at end of file +

    删除上面演示中创建的临时资源。

    kubectl delete ingress ingress-nginx-app
    +kubectl delete service nginx-app-1
    +kubectl delete service nginx-app-2
    +kubectl delete deployment nginx-app-1
    +kubectl delete deployment nginx-app-2
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/job/index.html b/k8s/cka_cn/foundamentals/job/index.html index 067b52a8..65a9c690 100644 --- a/k8s/cka_cn/foundamentals/job/index.html +++ b/k8s/cka_cn/foundamentals/job/index.html @@ -1,4 +1,4 @@ - Job and Cronjob - UPSkilling

    CKA自学笔记14:Job and Cronjob

    Job

    演示场景:

    • 创建Job。

    演示:

    创建Job pi

    kubectl apply -f - << EOF
    + Job and Cronjob - UPSkilling       

    CKA自学笔记14:Job and Cronjob

    Job

    演示场景:

    • 创建Job。

    演示:

    创建Job pi

    kubectl apply -f - << EOF
     apiVersion: batch/v1
     kind: Job
     metadata:
    @@ -13,12 +13,12 @@
           restartPolicy: Never
       backoffLimit: 4
     EOF
    -

    获取Job的详细信息。

    kubectl get jobs
    -

    获取Job的Pod的详细信息。 Completed 的状态代表这个job已经成功完成了。

    kubectl get pod
    -

    获取Job的Pod的日志信息。

    kubectl pi-2s74d
    +

    获取Job的详细信息。

    kubectl get jobs
    +

    获取Job的Pod的详细信息。 Completed 的状态代表这个job已经成功完成了。

    kubectl get pod
    +

    获取Job的Pod的日志信息。

    kubectl pi-2s74d
     3.141592653589793..............
    -

    删除所创建的资源。

    kubectl delete job pi
    -

    Cronjob

    演示场景:

    • 创建Cronjob。

    演示:

    创建Cronjob hello

    kubectl apply -f - << EOF
    +

    删除所创建的资源。

    kubectl delete job pi
    +

    Cronjob

    演示场景:

    • 创建Cronjob。

    演示:

    创建Cronjob hello

    kubectl apply -f - << EOF
     apiVersion: batch/v1
     kind: CronJob
     metadata:
    @@ -38,9 +38,9 @@
             - date ; echo Hello from the kubernetes cluster
           restartPolicy: OnFailure
     EOF
    -

    获取Cronjob的详细信息。

    kubectl get cronjobs -o wide
    +

    获取Cronjob的详细信息。

    kubectl get cronjobs -o wide
     

    运行结果

    NAME    SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE   CONTAINERS   IMAGES    SELECTOR
     hello   */1 * * * *   False     0        <none>          25s   hello        busybox   <none>
    -

    监控Jobs。每隔1分钟,一个新的job会被创建。

    kubectl get jobs -w
    -

    删除创建的资源。

    kubectl delete cronjob hello
    -
    \ No newline at end of file +

    监控Jobs。每隔1分钟,一个新的job会被创建。

    kubectl get jobs -w
    +

    删除创建的资源。

    kubectl delete cronjob hello
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/memo/index.html b/k8s/cka_cn/foundamentals/memo/index.html index f9d20309..3268ecde 100644 --- a/k8s/cka_cn/foundamentals/memo/index.html +++ b/k8s/cka_cn/foundamentals/memo/index.html @@ -1,117 +1,117 @@ - Kubernetes随笔 - UPSkilling

    CKA自学笔记5:Kubernetes随笔

    摘要

    边练习边记录的内容,不是全面系统的,包括下面主要内容:

    • Kubernetes基本概念
    • 组件
    • API
    • 对象
    • 资源
    • 工作负载资源
    • Pod
    • Deployment
    • ReplicaSet
    • StatefulSet
    • DaemonSet
    • Job
    • CronJob
    • 服务资源
    • Service
    • Endpoints
    • 配置和存储资源
    • Storage Class
    • PV
    • Access Modes

    Kubernetes基本概念

    Kubernetes组件

    一个Kubernetes集群由代表控制平面(control plane)的组件和一组称为节点(nodes)的机器组成。

    The components of a Kubernetes cluster

    Kubernetes组件:

    • 控制平面组件 Control Plane Components
    • kube-apiserver:
      • 查询和操作 Kubernetes 中对象的状态。
      • 充当所有资源之间的通信中心(communication hub)。
      • 提供集群安全身份验证、授权和角色分配。
      • 是唯一能连接到 etcd 的组件。
    • etcd:
      • 所有 Kubernetes 对象都存储在 etcd 中。
      • Kubernetes 对象是 Kubernetes 系统中的持久实体(entities),用于表示集群的状态。
    • kube-scheduler:
      • 监视没有分配节点的新创建的 Pod,并为它们选择一个节点来运行。
    • kube-controller-manager:
      • 运行控制器进程。
      • Node controller: 负责警示和响应节点的故障。
      • Job controller: 监视表示一次性任务的 Job 对象,然后创建 Pod 来完成这些任务。
      • Endpoints controller: 填充 Endpoints 对象(即将 Service 和 Pod 连接起来)。
      • Service Account & Token controllers: 为新命名空间创建默认帐户和 API 访问令牌。
    • cloud-controller-manager:
      • 嵌入云特定的控制逻辑,仅运行特定于我们选择的云提供商的控制器,无需自己的基础设施和学习环境。
      • Node controller: 用于检查云提供商,以确定节点在在它停止响应后是否已在云中被删除。
      • Route controller: 用于在底层云基础架构中设置路由。
      • Service controller: 用于创建、更新和删除云提供商负载均衡器。
    • 节点组件 Node Components
    • kubelet:
      • 在集群中每个节点上运行的代理。
      • 管理节点。它确保 Pod 中运行容器。kubelet 向 APIServer 注册和更新节点信息,APIServer 将它们存储到 etcd 中。
      • 管理 Pod。通过 APIServer 监视 Pod,并对 Pod 或 Pod 中的容器采取行动。
      • 在容器级别进行健康检查。
    • kube-proxy:
      • 是在集群中每个节点上运行的网络代理。
      • iptables
      • ipvs
      • 维护节点上的网络规则。
    • 容器运行时Container runtime:
      • 负责运行容器的软件。
    • 插件Addons
    • DNS: 是 DNS 服务器,是所有 Kubernetes 集群所必需的。
    • Web UI(仪表盘):用于 Kubernetes 集群的基于 Web 的用户界面。
    • 容器资源监控:记录有关集中式数据库中容器的通用时间序列度量。
    • Cluster-level Logging:负责将容器日志保存到具有搜索/浏览接口的中央日志存储中。

    可扩展性:

    • 水平扩展(Scaling out)通过添加更多的服务器到架构中,将工作负载分散到更多的机器上。
    • 垂直扩展(Scaling up)通过添加更多的硬盘和内存来增加物理服务器的计算能力。

    Kubernetes API

    REST API是Kubernetes的基本框架。所有组件之间的操作和通信,以及外部用户命令都是由API服务器处理的REST API调用。因此,Kubernetes平台中的所有内容都被视为API对象(API object),并在API中有相应的条目。

    Kubernetes控制平面的核心是API服务器。

    • CRI:容器运行时接口
    • CNI:容器网络接口
    • CSI:容器存储接口

    API服务器公开了一个HTTP API,允许最终用户、集群的不同部分和外部组件彼此通信。

    Kubernetes API允许我们查询和操作Kubernetes中API对象的状态(例如:Pod、Namespace、ConfigMap和Event)。

    Kubernetes API:

    • OpenAPI规范
    • OpenAPI V2
    • OpenAPI V3
    • 持久性。Kubernetes通过将对象的序列化状态写入etcd来存储它们。
    • API组和版本控制。版本控制是在API级别进行的。API资源通过它们的API组、资源类型、命名空间(用于命名空间资源)和名称进行区分。
    • API更改
    • API扩展

    API Version

    API版本和软件版本间存在间接关系。API和发布版本计划描述了API版本和软件版本之间的关系。不同的API版本表示不同的稳定性和支持级别。

    以下是每个级别的摘要:

    • Alpha:
    • 版本名称包含alpha(例如,v1alpha1)。
    • 软件可能包含错误。启用功能可能会暴露错误。某些功能可能默认禁用。
    • 对于某些功能的支持可以随时取消,而不会提前通知。
    • API可能会在以后的软件发布中以不兼容的方式更改,而不会提前通知。
    • 由于错误风险增加和长期支持不足,建议仅在短暂的测试集群中使用该软件。
    • Beta:
    • 版本名称包含beta(例如,v2beta3)。
    • 软件经过充分测试。启用功能被认为是安全的。某些功能默认启用。
    • 对于某些功能的支持不会取消,但细节可能会更改。
    • 对象的模式和/或语义可能会在后续的Beta或稳定版发布中以不兼容的方式更改。当发生这种情况时,将提供迁移说明。模式更改可能需要删除、编辑和重新创建 API对象。编辑过程可能不简单。迁移可能需要停机,以便依赖于该功能的应用程序。
    • 不建议将该软件用于生产用途。后续的发布可能会引入不兼容的更改。如果您有多个可以独立升级的集群,则可以放宽此限制。
    • 注意:请尝试beta功能并提供反馈。功能退出beta后,可能不实际再进行更改。
    • 稳定版:
    • 版本名称为vX,其中X是整数。
    • 功能的稳定版本出现在发布的软件中的许多后续版本中。

    读取当前API的版本命令:

    kubectl api-resources
    -

    API Group

    API组(API groups)使扩展Kubernetes API更加容易。API组在REST路径和序列化对象的apiVersion字段中指定。

    Kubernetes有几个API组:

    • 核心组(也称为遗留legacy)位于REST路径 /api/v1
    • 核心组不作为apiVersion字段的一部分指定,例如 apiVersion: v1。
    • 命名组位于REST路径 /apis/$GROUP_NAME/$VERSION,并使用 apiVersion: $GROUP_NAME/$VERSION(例如 apiVersion: batch/v1)。

    Kubernetes对象

    对象概述

    对象规范(Object Spec):

    • 提供了一个描述所创建资源的特性的说明:其期望的状态

    对象状态(Object Status):

    • 描述了对象的当前状态。

    比如,Deployment是一个可以代表集群上运行的应用程序的对象。

    apiVersion: apps/v1  # 当前用来创建对象的API版本
    -kind: Deployment     # 创建对象的类型
    -metadata:            # 用来区分对象的元数据,比如:名称,UID,命名空间等
    -  name: nginx-deployment
    -spec:                # 期望所创建对象的状态
    -  selector:
    -    matchLabels:
    -      app: nginx
    -  replicas: 2        # 告诉Deployment基于下面的模板template创建2个Pods
    -  template:
    -    metadata:
    -      labels:
    -        app: nginx
    -    spec:
    -      containers:
    -      - name: nginx
    -        image: nginx:1.14.2
    -        ports:
    -        - containerPort: 80
    -

    对象管理

    kubectl 命令行工具支持多种不同的方式来创建和管理 Kubernetes 对象。详细信息请阅读 Kubectl book

    一个 Kubernetes 对象应该仅使用一种技术进行管理。混合使用不同的技术来管理同一个对象会导致非预期的结果。

    三种管理技术:

    • 命令式命令
    • 直接在集群中操作实时对象。
    • kubectl create deployment nginx --image nginx
    • 命令式对象配置
    • kubectl create -f nginx.yaml
    • kubectl delete -f nginx.yaml -f redis.yaml
    • kubectl replace -f nginx.yaml
    • 声明式对象配置
    • kubectl diff -f configs/
    • kubectl apply -f configs/

    对象名称和ID

    集群中的每个对象都有一个在该资源类型中唯一的名称。

    • DNS 子域名
    • 标签名称
    • 路径段名称

    每个 Kubernetes 对象还有一个 UID,在整个集群中是唯一的。

    命名空间

    在Kubernetes中,命名空间提供了一种在单个集群内隔离资源组的机制。

    资源的名称需要在命名空间内是唯一的,但不需要跨命名空间唯一。

    基于命名空间的范围仅适用于命名空间对象(例如部署,服务等),而不适用于集群范围的对象(例如StorageClass,节点,持久卷等)。

    并非所有对象都位于命名空间中。

    Kubernetes从四个初始命名空间开始:

    • default 用于没有其他命名空间的对象的默认命名空间
    • kube-system Kubernetes系统创建的对象的命名空间
    • kube-public 该命名空间是自动创建的,并可由所有用户(包括未经身份验证的用户)读取。此命名空间大多保留供集群使用,以防一些资源应在整个集群范围内公开和可读。此命名空间的公共方面只是一种约定,而不是要求。
    • kube-node-lease 此命名空间保存与每个节点关联的租赁对象。节点租赁允许kubelet发送心跳,以便控制平面可以检测到节点故障。

    查看命名空间:

    • kubectl get namespace

    为请求设置命名空间

    • kubectl run nginx --image=nginx --namespace=<插入命名空间名称>
    • kubectl get pods --namespace=<插入命名空间名称>

    标签和选择器

    标签是附加到对象(例如 Pod)的键/值对。有效的标签键有两个部分:可选的前缀和名称,由斜杠(/)分隔。

    标签旨在用于指定对用户有意义和相关的对象识别属性。

    标签可用于组织和选择对象子集。标签可以在创建对象时附加,随后在任何时候添加和修改。每个对象可以定义一组键/值标签,每个键必须对于给定对象是唯一的。

    标签的示例:

    "metadata": {
    -    "labels": {
    -        "key1" : "value1",
    -        "key2" : "value2"
    -    }
    -}
    -

    与名称和 UID 不同,标签不提供唯一性。通常情况下,我们期望许多对象带有相同的标签。

    目前 API 支持两种类型的选择器:

    • 基于等式的选择器,例如:environment = productiontier != frontend
    • 基于集合的选择器,例如:environment in (production, qa)tier notin (frontend, backend)

    例如:

    kubectl get pods -l environment=production,tier=frontend
    -kubectl get pods -l 'environment in (production),tier in (frontend)'
    -kubectl get pods -l 'environment in (production, qa)'
    -kubectl get pods -l 'environment,environment notin (frontend)'
    -

    注释Annotations

    使用 Kubernetes 注释(Annotations)将任意非标识元数据附加到对象上。 工具和库等客户端可以检索此元数据。

    使用标签或注释将元数据附加到 Kubernetes 对象上。

    • 标签可用于选择对象并查找满足某些条件的对象集合。
    • 注释不用于标识和选择对象。

    注释与标签类似,都是键/值映射。 映射中的键和值必须是字符串。

    例如:

    "metadata": {
    -    "annotations": {
    -      "key1" : "value1",
    -      "key2" : "value2"
    -    }
    -}
    -

    合法的注释键具有两个部分:可选的前缀和名称,由斜杠 (/) 分隔。

    字段选择器

    字段选择器(field selectors)可以根据一个或多个资源字段的值选择Kubernetes资源。

    下面是一些使用字段选择器进行查询筛选的例子:

    metadata.name=my-service
    -metadata.namespace!=default
    -status.phase=Pending
    -

    This kubectl command selects all Pods for which the value of the status.phase field is Running: kubectl get pods --field-selector status.phase=Running

    Supported field selectors vary by Kubernetes resource type. All resource types support the metadata.name and metadata.namespace fields.

    Use the =, ==, and != operators with field selectors (= and == mean the same thing).

    下面 kubectl 命令选择所有状态(phase)字段值为 Running 的 Pod:

    kubectl get pods --field-selector status.phase=Running
    -

    支持的字段选择器因 Kubernetes 资源类型而异。所有资源类型都支持 metadata.namemetadata.namespace 字段。

    在字段选择器中使用 =, ==, 和 != 运算符(=== 表示相同的意思)。

    例如:

    kubectl get ingress --field-selector foo.bar=baz
    + Kubernetes随笔 - UPSkilling       

    CKA自学笔记5:Kubernetes随笔

    摘要

    边练习边记录的内容,不是全面系统的,包括下面主要内容:

    • Kubernetes基本概念
    • 组件
    • API
    • 对象
    • 资源
    • 工作负载资源
    • Pod
    • Deployment
    • ReplicaSet
    • StatefulSet
    • DaemonSet
    • Job
    • CronJob
    • 服务资源
    • Service
    • Endpoints
    • 配置和存储资源
    • Storage Class
    • PV
    • Access Modes

    Kubernetes基本概念

    Kubernetes组件

    一个Kubernetes集群由代表控制平面(control plane)的组件和一组称为节点(nodes)的机器组成。

    The components of a Kubernetes cluster

    Kubernetes组件:

    • 控制平面组件 Control Plane Components
    • kube-apiserver:
      • 查询和操作 Kubernetes 中对象的状态。
      • 充当所有资源之间的通信中心(communication hub)。
      • 提供集群安全身份验证、授权和角色分配。
      • 是唯一能连接到 etcd 的组件。
    • etcd:
      • 所有 Kubernetes 对象都存储在 etcd 中。
      • Kubernetes 对象是 Kubernetes 系统中的持久实体(entities),用于表示集群的状态。
    • kube-scheduler:
      • 监视没有分配节点的新创建的 Pod,并为它们选择一个节点来运行。
    • kube-controller-manager:
      • 运行控制器进程。
      • Node controller: 负责警示和响应节点的故障。
      • Job controller: 监视表示一次性任务的 Job 对象,然后创建 Pod 来完成这些任务。
      • Endpoints controller: 填充 Endpoints 对象(即将 Service 和 Pod 连接起来)。
      • Service Account & Token controllers: 为新命名空间创建默认帐户和 API 访问令牌。
    • cloud-controller-manager:
      • 嵌入云特定的控制逻辑,仅运行特定于我们选择的云提供商的控制器,无需自己的基础设施和学习环境。
      • Node controller: 用于检查云提供商,以确定节点在在它停止响应后是否已在云中被删除。
      • Route controller: 用于在底层云基础架构中设置路由。
      • Service controller: 用于创建、更新和删除云提供商负载均衡器。
    • 节点组件 Node Components
    • kubelet:
      • 在集群中每个节点上运行的代理。
      • 管理节点。它确保 Pod 中运行容器。kubelet 向 APIServer 注册和更新节点信息,APIServer 将它们存储到 etcd 中。
      • 管理 Pod。通过 APIServer 监视 Pod,并对 Pod 或 Pod 中的容器采取行动。
      • 在容器级别进行健康检查。
    • kube-proxy:
      • 是在集群中每个节点上运行的网络代理。
      • iptables
      • ipvs
      • 维护节点上的网络规则。
    • 容器运行时Container runtime:
      • 负责运行容器的软件。
    • 插件Addons
    • DNS: 是 DNS 服务器,是所有 Kubernetes 集群所必需的。
    • Web UI(仪表盘):用于 Kubernetes 集群的基于 Web 的用户界面。
    • 容器资源监控:记录有关集中式数据库中容器的通用时间序列度量。
    • Cluster-level Logging:负责将容器日志保存到具有搜索/浏览接口的中央日志存储中。

    可扩展性:

    • 水平扩展(Scaling out)通过添加更多的服务器到架构中,将工作负载分散到更多的机器上。
    • 垂直扩展(Scaling up)通过添加更多的硬盘和内存来增加物理服务器的计算能力。

    Kubernetes API

    REST API是Kubernetes的基本框架。所有组件之间的操作和通信,以及外部用户命令都是由API服务器处理的REST API调用。因此,Kubernetes平台中的所有内容都被视为API对象(API object),并在API中有相应的条目。

    Kubernetes控制平面的核心是API服务器。

    • CRI:容器运行时接口
    • CNI:容器网络接口
    • CSI:容器存储接口

    API服务器公开了一个HTTP API,允许最终用户、集群的不同部分和外部组件彼此通信。

    Kubernetes API允许我们查询和操作Kubernetes中API对象的状态(例如:Pod、Namespace、ConfigMap和Event)。

    Kubernetes API:

    • OpenAPI规范
    • OpenAPI V2
    • OpenAPI V3
    • 持久性。Kubernetes通过将对象的序列化状态写入etcd来存储它们。
    • API组和版本控制。版本控制是在API级别进行的。API资源通过它们的API组、资源类型、命名空间(用于命名空间资源)和名称进行区分。
    • API更改
    • API扩展

    API Version

    API版本和软件版本间存在间接关系。API和发布版本计划描述了API版本和软件版本之间的关系。不同的API版本表示不同的稳定性和支持级别。

    以下是每个级别的摘要:

    • Alpha:
    • 版本名称包含alpha(例如,v1alpha1)。
    • 软件可能包含错误。启用功能可能会暴露错误。某些功能可能默认禁用。
    • 对于某些功能的支持可以随时取消,而不会提前通知。
    • API可能会在以后的软件发布中以不兼容的方式更改,而不会提前通知。
    • 由于错误风险增加和长期支持不足,建议仅在短暂的测试集群中使用该软件。
    • Beta:
    • 版本名称包含beta(例如,v2beta3)。
    • 软件经过充分测试。启用功能被认为是安全的。某些功能默认启用。
    • 对于某些功能的支持不会取消,但细节可能会更改。
    • 对象的模式和/或语义可能会在后续的Beta或稳定版发布中以不兼容的方式更改。当发生这种情况时,将提供迁移说明。模式更改可能需要删除、编辑和重新创建 API对象。编辑过程可能不简单。迁移可能需要停机,以便依赖于该功能的应用程序。
    • 不建议将该软件用于生产用途。后续的发布可能会引入不兼容的更改。如果您有多个可以独立升级的集群,则可以放宽此限制。
    • 注意:请尝试beta功能并提供反馈。功能退出beta后,可能不实际再进行更改。
    • 稳定版:
    • 版本名称为vX,其中X是整数。
    • 功能的稳定版本出现在发布的软件中的许多后续版本中。

    读取当前API的版本命令:

    kubectl api-resources
    +

    API Group

    API组(API groups)使扩展Kubernetes API更加容易。API组在REST路径和序列化对象的apiVersion字段中指定。

    Kubernetes有几个API组:

    • 核心组(也称为遗留legacy)位于REST路径 /api/v1
    • 核心组不作为apiVersion字段的一部分指定,例如 apiVersion: v1。
    • 命名组位于REST路径 /apis/$GROUP_NAME/$VERSION,并使用 apiVersion: $GROUP_NAME/$VERSION(例如 apiVersion: batch/v1)。

    Kubernetes对象

    对象概述

    对象规范(Object Spec):

    • 提供了一个描述所创建资源的特性的说明:其期望的状态

    对象状态(Object Status):

    • 描述了对象的当前状态。

    比如,Deployment是一个可以代表集群上运行的应用程序的对象。

    apiVersion: apps/v1  # 当前用来创建对象的API版本
    +kind: Deployment     # 创建对象的类型
    +metadata:            # 用来区分对象的元数据,比如:名称,UID,命名空间等
    +  name: nginx-deployment
    +spec:                # 期望所创建对象的状态
    +  selector:
    +    matchLabels:
    +      app: nginx
    +  replicas: 2        # 告诉Deployment基于下面的模板template创建2个Pods
    +  template:
    +    metadata:
    +      labels:
    +        app: nginx
    +    spec:
    +      containers:
    +      - name: nginx
    +        image: nginx:1.14.2
    +        ports:
    +        - containerPort: 80
    +

    对象管理

    kubectl 命令行工具支持多种不同的方式来创建和管理 Kubernetes 对象。详细信息请阅读 Kubectl book

    一个 Kubernetes 对象应该仅使用一种技术进行管理。混合使用不同的技术来管理同一个对象会导致非预期的结果。

    三种管理技术:

    • 命令式命令
    • 直接在集群中操作实时对象。
    • kubectl create deployment nginx --image nginx
    • 命令式对象配置
    • kubectl create -f nginx.yaml
    • kubectl delete -f nginx.yaml -f redis.yaml
    • kubectl replace -f nginx.yaml
    • 声明式对象配置
    • kubectl diff -f configs/
    • kubectl apply -f configs/

    对象名称和ID

    集群中的每个对象都有一个在该资源类型中唯一的名称。

    • DNS 子域名
    • 标签名称
    • 路径段名称

    每个 Kubernetes 对象还有一个 UID,在整个集群中是唯一的。

    命名空间

    在Kubernetes中,命名空间提供了一种在单个集群内隔离资源组的机制。

    资源的名称需要在命名空间内是唯一的,但不需要跨命名空间唯一。

    基于命名空间的范围仅适用于命名空间对象(例如部署,服务等),而不适用于集群范围的对象(例如StorageClass,节点,持久卷等)。

    并非所有对象都位于命名空间中。

    Kubernetes从四个初始命名空间开始:

    • default 用于没有其他命名空间的对象的默认命名空间
    • kube-system Kubernetes系统创建的对象的命名空间
    • kube-public 该命名空间是自动创建的,并可由所有用户(包括未经身份验证的用户)读取。此命名空间大多保留供集群使用,以防一些资源应在整个集群范围内公开和可读。此命名空间的公共方面只是一种约定,而不是要求。
    • kube-node-lease 此命名空间保存与每个节点关联的租赁对象。节点租赁允许kubelet发送心跳,以便控制平面可以检测到节点故障。

    查看命名空间:

    • kubectl get namespace

    为请求设置命名空间

    • kubectl run nginx --image=nginx --namespace=<插入命名空间名称>
    • kubectl get pods --namespace=<插入命名空间名称>

    标签和选择器

    标签是附加到对象(例如 Pod)的键/值对。有效的标签键有两个部分:可选的前缀和名称,由斜杠(/)分隔。

    标签旨在用于指定对用户有意义和相关的对象识别属性。

    标签可用于组织和选择对象子集。标签可以在创建对象时附加,随后在任何时候添加和修改。每个对象可以定义一组键/值标签,每个键必须对于给定对象是唯一的。

    标签的示例:

    "metadata": {
    +    "labels": {
    +        "key1" : "value1",
    +        "key2" : "value2"
    +    }
    +}
    +

    与名称和 UID 不同,标签不提供唯一性。通常情况下,我们期望许多对象带有相同的标签。

    目前 API 支持两种类型的选择器:

    • 基于等式的选择器,例如:environment = productiontier != frontend
    • 基于集合的选择器,例如:environment in (production, qa)tier notin (frontend, backend)

    例如:

    kubectl get pods -l environment=production,tier=frontend
    +kubectl get pods -l 'environment in (production),tier in (frontend)'
    +kubectl get pods -l 'environment in (production, qa)'
    +kubectl get pods -l 'environment,environment notin (frontend)'
    +

    注释Annotations

    使用 Kubernetes 注释(Annotations)将任意非标识元数据附加到对象上。 工具和库等客户端可以检索此元数据。

    使用标签或注释将元数据附加到 Kubernetes 对象上。

    • 标签可用于选择对象并查找满足某些条件的对象集合。
    • 注释不用于标识和选择对象。

    注释与标签类似,都是键/值映射。 映射中的键和值必须是字符串。

    例如:

    "metadata": {
    +    "annotations": {
    +      "key1" : "value1",
    +      "key2" : "value2"
    +    }
    +}
    +

    合法的注释键具有两个部分:可选的前缀和名称,由斜杠 (/) 分隔。

    字段选择器

    字段选择器(field selectors)可以根据一个或多个资源字段的值选择Kubernetes资源。

    下面是一些使用字段选择器进行查询筛选的例子:

    metadata.name=my-service
    +metadata.namespace!=default
    +status.phase=Pending
    +

    This kubectl command selects all Pods for which the value of the status.phase field is Running: kubectl get pods --field-selector status.phase=Running

    Supported field selectors vary by Kubernetes resource type. All resource types support the metadata.name and metadata.namespace fields.

    Use the =, ==, and != operators with field selectors (= and == mean the same thing).

    下面 kubectl 命令选择所有状态(phase)字段值为 Running 的 Pod:

    kubectl get pods --field-selector status.phase=Running
    +

    支持的字段选择器因 Kubernetes 资源类型而异。所有资源类型都支持 metadata.namemetadata.namespace 字段。

    在字段选择器中使用 =, ==, 和 != 运算符(=== 表示相同的意思)。

    例如:

    kubectl get ingress --field-selector foo.bar=baz
     
    -kubectl get services --all-namespaces --field-selector metadata.namespace!=default
    +kubectl get services --all-namespaces --field-selector metadata.namespace!=default
     
    -kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always
    +kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always
     
    -kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default
    -

    Finalizers是*命名空间键*,告诉Kubernetes在满足特定条件之前等待,然后再完全删除标记为*删除*的资源。 Finalizer警告控制器controller清理已删除对象所拥有的资源。

    通常因为某种目的为资源添加Finalizers,强制删除它们可能会导致集群中出现问题。

    与标签类似,所有者引用(Owner references)描述了Kubernetes中对象之间的关系,但用于不同的目的。

    Kubernetes使用所有者引用(而不是标签)来确定集群中哪些Pod需要清理。

    当Kubernetes识别到目标删除的资源上有所有者引用时,它会处理Finalizer。

    所有者和依赖关系

    在 Kubernetes 中,一些对象拥有其他对象。例如,ReplicaSet 是一组 Pod 的所有者。这些被拥有的对象是其所有者的从属对象。

    从属对象具有一个 metadata.ownerReferences 字段,该字段引用其所有者对象。

    有效的所有者引用包括对象名称和与从属对象相同的命名空间中的 UID。

    从属对象还具有一个 ownerReferences.blockOwnerDeletion 字段,该字段具有布尔值,控制特定的从属对象是否可以阻止垃圾回收删除其所有者对象。

    资源

    Kubernetes资源和“意向记录”都以API对象的形式存储,并通过对API的RESTful调用进行修改。

    API允许以声明性方式管理配置。

    用户可以直接与Kubernetes API交互,也可以通过像kubectl这样的工具进行交互。

    核心Kubernetes API具有灵活性,也可以扩展以支持自定义资源。

    • 工作负载资源(Workload Resources)
    • Pod。Pod 是可以在主机上运行的容器集合。
    • PodTemplate。PodTemplate 描述了预定义 pod 的副本模板。
    • ReplicationController。ReplicationController 表示一个复制控制器的配置。
    • ReplicaSet。ReplicaSet 确保在任何给定时间有指定数量的 pod 副本正在运行。
    • Deployment。Deployment 使 Pod 和 ReplicaSet 的声明性更新成为可能。
    • StatefulSet。StatefulSet 表示具有一致标识的 pod 集合。
    • ControllerRevision。ControllerRevision 实现了状态数据的不可变快照。
    • DaemonSet。DaemonSet 表示一个守护进程集的配置。
    • Job。Job 表示单个 job 的配置。
    • CronJob。CronJob 表示单个 cron job 的配置。
    • HorizontalPodAutoscaler。HorizontalPodAutoscaler 表示水平 pod 自动缩放器的配置。
    • HorizontalPodAutoscaler v2beta2。HorizontalPodAutoscaler 是水平 pod 自动缩放器的配置,根据指定的指标自动管理实现比例子资源的任何资源的副本计数。
    • PriorityClass。PriorityClass 定义了从优先级类名称到优先级整数值的映射。
    • 服务资源(Service Resources)
    • Service. Service 是对软件服务(例如mysql)的命名抽象,由代理监听的本地端口(例如3306)和确定哪些Pod将回答通过代理发送的请求的选择器组成。
    • Endpoints. Endpoints 是实现实际服务的一组终结点。
    • EndpointSlice. EndpointSlice 表示实现服务的终结点的子集。
    • Ingress. Ingress 是一组规则,允许入站连接到达由后端定义的终结点。
    • IngressClass. IngressClass 表示 Ingress 的类,由 Ingress Spec 引用。
    • 配置和存储资源(Config and Storage Resources)
    • ConfigMap。ConfigMap保存容器需要使用的配置数据。
    • Secret。Secret保存特定类型的机密数据。
    • Volume。Volume表示Pod中的命名卷,可以被Pod中的任何容器访问。
    • PersistentVolumeClaim。PersistentVolumeClaim是用户对持久卷的请求和声明。
    • PersistentVolume。PersistentVolume(PV)是由管理员提供的存储资源。
    • StorageClass。StorageClass描述可动态分配PersistentVolumes的存储类别的参数。
    • VolumeAttachment。VolumeAttachment记录将指定的卷附加到/从指定节点中分离的意图。
    • CSIDriver。CSIDriver记录集群上部署的容器存储接口(CSI)卷驱动程序的信息。
    • CSINode。CSINode保存有关节点上安装的所有CSI驱动程序的信息。
    • CSIStorageCapacity。CSIStorageCapacity存储一个CSI GetCapacity调用的结果。
    • 认证资源(Authentication Resources)
    • ServiceAccount*。ServiceAccount和下面的信息绑定在一起:
      • 一个可被用户和周边系统理解的名称,用于身份识别
      • 可进行身份验证和授权的主体
      • 一组密钥。
    • TokenRequest*。TokenRequest为给定的ServiceAccount请求一个令牌。
    • TokenReview*。TokenReview尝试对已知用户的令牌进行身份验证。
    • CertificateSigningRequest*。CertificateSigningRequest对象提供了一种通过提交证书签名请求并异步批准和发放来获取x509证书的机制。
    • 授权资源(Authorization Resources)
    • LocalSubjectAccessReview*。LocalSubjectAccessReview检查一个用户或组在给定命名空间中是否能执行某个操作。
    • SelfSubjectAccessReview*。SelfSubjectAccessReview检查当前用户是否能执行某个操作。
    • SelfSubjectRulesReview*。SelfSubjectRulesReview枚举当前用户在一个命名空间内可以执行的操作集合。
    • SubjectAccessReview*。SubjectAccessReview检查一个用户或组是否能执行某个操作。
    • ClusterRole*。ClusterRole是一个集群级别的PolicyRules逻辑分组,可以被RoleBinding或ClusterRoleBinding引用为一个单元。
    • ClusterRoleBinding*。ClusterRoleBinding引用一个ClusterRole,但不包含它。
    • Role*。Role是一个命名空间级别的PolicyRules逻辑分组,可以被RoleBinding引用为一个单元。
    • RoleBinding*。RoleBinding引用一个Role,但不包含它。
    • 策略资源(Policy Resources)
    • LimitRange*。LimitRange为命名空间中每种资源设置资源使用限制。
    • ResourceQuota*。ResourceQuota设置每个命名空间强制执行的总配额限制。
    • NetworkPolicy*。NetworkPolicy描述了一组Pod允许的网络流量。
    • PodDisruptionBudget*。PodDisruptionBudget是一个对象,用于定义对一组Pod可能造成的最大中断。
    • PodSecurityPolicy v1beta1*。PodSecurityPolicy控制对可能影响将应用于Pod和容器的安全上下文的请求的能力。
    • 扩展资源(Extend Resources)
    • CustomResourceDefinition*。CustomResourceDefinition表示应在API服务器上公开的资源。
    • MutatingWebhookConfiguration*。MutatingWebhookConfiguration描述接受或拒绝并可能更改对象的准入Webhook的配置。
    • ValidatingWebhookConfiguration*。ValidatingWebhookConfiguration描述接受或拒绝对象但不更改对象的准入Webhook的配置。
    • 集群资源(Cluster Resources)
    • Node*。Node是Kubernetes中的工作节点。
    • Namespace*。Namespace为名称提供了作用域。
    • Event*。Event是对集群中某个位置发生事件的报告。
    • APIService*。APIService表示特定GroupVersion的服务器。
    • Lease*。Lease定义了租赁的概念。
    • RuntimeClass*。RuntimeClass定义了集群中支持的容器运行时类。
    • FlowSchema v1beta2*。FlowSchema定义了一组流程的架构。
    • PriorityLevelConfiguration v1beta2*。PriorityLevelConfiguration表示优先级级别的配置。
    • Binding*。Binding将一个对象绑定到另一个对象;例如,调度程序将Pod绑定到节点上。
    • ComponentStatus*。ComponentStatus(和ComponentStatusList)保存集群验证信息。

    使用命令 kube api-resources 获取支持的API资源。

    使用命令 kubectl explain RESOURCE [options] 描述与每个支持的API资源相关联的字段。这些字段可以通过简单的JSONPath标识符进行识别:

    kubectl explain binding
    -kubectl explain binding.metadata
    -kubectl explain binding.metadata.name
    -

    工作负载资源

    Pods

    Pod是Kubernetes中可创建和管理的最小部署计算单位。

    Pod是一个包含一个或多个容器、共享存储和网络资源以及如何运行容器的规范的组。

    Pod的内容始终共同定位和共同安排,并在共享环境中运行。

    Pod模拟了一个特定于应用程序的“逻辑主机”:它包含一个或多个相对紧密耦合的应用程序容器。

    在非云环境中,同一物理或虚拟机上执行的应用程序类似于在同一逻辑主机上执行的云应用程序。

    Pod的共享环境是一组Linux命名空间、cgroups和可能的其他隔离要素 - 这些要素与隔离Docker容器的方式相同。

    在Docker概念方面,Pod类似于具有共享命名空间和共享文件系统卷的一组Docker容器。

    通常情况下,甚至是单例Pod,我们都不需要直接创建Pod,而是使用工作负载资源,例如*Deployment*或*Job*来创建它们。如果Pod需要跟踪状态,则可以使用StatefulSet资源。

    Kubernetes集群中的Pod有两种主要用法:

    • 运行单个容器的Pod。
    • 运行需要共同工作的多个容器的Pod。

    “每个Pod一个容器”的模型是最常见的Kubernetes用例;在这种情况下可以将Pod视为单个容器的包装器;Kubernetes管理Pod而不是直接管理容器。

    一个Pod可以封装由多个共同定位、紧密耦合且需要共享资源的容器组成的应用程序。

    这些共同定位的容器形成一个单一的服务整体单元 - 例如,一个容器向公众提供存储在共享卷中的数据,而另一个独立的Sidecar容器刷新或更新这些文件。Pod将这些容器、存储资源和短暂的网络标识包装在一起,作为一个单独的单位。

    在单个Pod中分组多个共同定位和共同管理的容器是相对高级的用例。应该*仅在*容器紧密耦合的特定情况下使用此模式。

    每个Pod都旨在运行给定应用程序的单个实例。如果我们想水平扩展您的应用程序(通过运行更多实例提供更多的总资源),则应该使用多个Pod,每个实例一个Pod。在Kubernetes中,这通常称为*复制*。复制的Pod通常作为工作负载资源及其控制器的一组创建和管理。

    Pod本地提供两种共享资源以供其组成容器使用:网络*和存储*。

    一个Pod可以指定一组共享的存储卷。Pod中的所有容器都可以访问这些共享卷,使这些容器可以共享数据。

    每个Pod为每个地址族分配一个唯一的IP地址。 在一个Pod内,容器共享一个IP地址和端口空间,并可以通过“localhost”找到彼此。想要与运行在不同Pod中的容器交互的容器可以使用IP网络进行通信。

    当创建一个Pod时,新的Pod被调度在集群中的一个节点上运行。Pod保留在该节点上,直到Pod执行完毕、Pod对象被删除、Pod因缺乏资源而被驱逐或节点发生故障。

    在Pod中重新启动一个容器不应与重新启动一个Pod混淆。Pod不是一个进程,而是一个运行容器的环境。Pod会一直保留,直到被删除为止。

    您可以使用工作负载资源(例如Deployment、StatefulSet、DaemonSet)为自己创建和管理多个Pod。资源的控制器处理复制、滚动和在Pod失败时的自动恢复。Pod with multiple containers

    初始化容器

    一些Pod还有初始化容器(Init containers)和应用容器(app containers)。初始化容器在应用容器启动之前运行并完成。

    我们可以在Pod规范中指定初始化容器,同时也可以在容器数组中描述应用容器。

    静态Pod

    静态Pod是直接由特定节点上的kubelet守护程序管理的,API服务器不会观察它们。

    静态Pod始终绑定到特定节点上的一个Kubelet。

    静态Pod的主要用途是运行自托管控制面板:换句话说,使用kubelet监督各个控制面板组件。

    kubelet会自动尝试为每个静态Pod在Kubernetes API服务器上创建一个镜像Pod。这意味着在节点上运行的Pod在API服务器上可见,但无法从那里控制。

    容器探针

    探针是 kubelet 定期对容器执行的一种诊断。

    为执行诊断,kubelet 要么在容器内执行代码,要么发起网络请求。

    使用探针有四种不同的检查容器方式。每个探针必须恰好定义这四种机制中的一种:

    • exec。如果命令以状态代码 0 退出,则将诊断视为成功。
    • grpc。如果响应的状态为 SERVING,则将诊断视为成功。
    • httpGet。如果响应的状态代码大于或等于 200 且小于 400,则将诊断视为成功。
    • tcpSocket。如果端口开放,则将诊断视为成功。

    每个探针有三种结果:

    • 成功
    • 失败
    • 未知

    探针类型:

    • livenessProbe。指示容器是否正在运行。
    • readinessProbe。指示容器是否准备好响应请求。
    • startupProbe。指示容器内的应用程序是否启动。

    Deployment

    ReplicaSet

    ReplicaSet的目的是在任何时候维护一组稳定的副本Pod。因此,它通常用于保证指定数量的相同Pod的可用性。

    我们一般不需要直接操纵ReplicaSet对象:使用Deployment,然后在spec部分中定义您的应用程序。

    可以通过设置replicaset.spec.replicas来指定应同时运行多少个Pod。 ReplicaSet将创建/删除其Pod以匹配此数字。 如果不指定replicaset.spec.replicas,则默认值为1

    StatefulSet

    StatefulSet 特点(又称固定标识):

    • Pod 的名称在创建后不可变。
    • DNS 主机名在创建后不可变。
    • 挂载的卷在创建后不可变。

    StatefulSet 的固定标识在失败、扩展和其他操作后不会改变。

    StatefulSet 的命名约定为:<StatefulSetName>-<Integer>

    StatefulSet 可以自行进行扩展,但是 Deployment 需要依靠 ReplicaSet 进行扩展。

    建议:先将 StatefulSet 减少到 0,而不是直接删除它。

    headless Service 和 governing Service:

    • Headless Service 是一个普通的 Kubernetes Service 对象,其 spec.clusterIP 被设置为 None
    • 当 StatefulSet 的 spec.ServiceName 设置为 headless Service 名称时,StatefulSet 现在是一个 governing Service。

    创建 StatefulSet 的一般过程:

    • 创建 StorageClass。
    • 创建 Headless Service。
    • 基于上述两个创建 StatefulSet。

    DaemonSet

    DaemonSet保证所有(或部分)节点运行Pod的副本。随着节点从集群中删除,这些Pod将被垃圾回收。

    删除DaemonSet将清理它创建的Pod。

    一些典型DaemonSet的用途包括:

    • 在每个节点上运行集群存储守护程序。
    • 在每个节点上运行日志收集守护程序。
    • 在每个节点上运行节点监视守护程序。

    在简单的情况下,每种类型的守护程序将使用覆盖所有节点的一个DaemonSet。

    更复杂的设置可能会为单个守护程序使用多个DaemonSet,但使用不同的标志和/或不同的内存和CPU请求来支持不同的硬件类型。

    DaemonSet控制器调和过程同时检查现有节点和新创建的节点。

    默认情况下,Kubernetes调度程序忽略由DamonSet创建的Pod,并允许它们存在于节点上,直到关闭节点本身。

    在选择节点上运行Pod:

    • 如果您指定daemonset.spec.template.spec.nodeSelector,那么DaemonSet控制器将在与该节点选择器匹配的节点上创建Pod。
    • 如果您指定daemonset.spec.template.spec.affinity,那么DaemonSet控制器将在与该节点亲和力匹配的节点上创建Pod。
    • 如果两者都不指定,则DaemonSet控制器将在所有节点上创建Pod。

    kubectl explain daemonset.spec中没有replicas字段与kubectl explain deployment.spec.replicas相对应。当创建一个DaemonSet时,每个节点将运行*一个* DaemonSet Pod。

    对于服务,通常是无状态的,一般不关心节点在哪里运行,更关心Pod副本的数量,并且我们可以将这些副本/replicas缩放。在这里,滚动更新也将是一个优点。

    当Pod的一个副本必须在某个指定节点上运行时,我们将使用DaemonSet。我们的守护进程Pod还需要在我们的其他Pod之前启动。

    DaemonSet是用于后台服务的简单可扩展性策略。当更多的合适的节点添加到集群时,后台服务将扩展。当节点被删除时,它将自动缩小。

    Job

    CronJob

    服务资源

    Service

    Service是软件服务(例如mysql)的命名抽象,由代理监听的本地端口(例如3306)和确定哪些Pod将回答通过代理发送的请求的选择器组成。

    一个Service的目标Pod集合通常由一个选择器(标签选择器)来确定。

    Service资源的类型包括:

    • ClusterIP Service(默认):可靠的IP、DNS和端口。仅限内部访问。
    • NodePort Service:向外部提供访问。
    • LoadBalancer:基于NodePort,并与云供应商提供的负载平衡集成(例如AWS、GCP等)。
    • ExternalName:访问将被转发到外部服务。

    下面是一个创建简单Service的yaml文件:

    apiVersion: v1
    -kind: Service
    -metadata:
    -  name: nginx-service
    -  labels:
    -    tier: application
    -spec:
    -  ports:
    -  - port: 80
    -    protocol: TCP
    -    targetPort: 8080
    -  selector:
    -    run: nginx
    -  type: NodePort
    -

    下面是一个Service的例子:

    • IP 10.96.17.77 是该服务的 ClusterIP(VIP)。
    • 端口 <unset> 80/TCP 是 Pod 在集群内监听的端口。
    • TargetPort 8080/TCP 是容器内服务应该定向流量到达的端口。
    • NodePort <unset> 31893/TCP 是可以从外部访问的端口。默认范围是 30000~32767。该端口会在整个集群的所有节点上暴露。
    • Endpoints 显示了匹配服务标签的 Pod 列表。
    Name:                     nginx-deployment
    -Namespace:                jh-namespace
    -Labels:                   tier=application
    -Annotations:              <none>
    -Selector:                 run=nginx
    -Type:                     NodePort
    -IP Family Policy:         SingleStack
    -IP Families:              IPv4
    -IP:                       10.96.17.77
    -IPs:                      10.96.17.77
    -Port:                     <unset>  80/TCP
    -TargetPort:               8080/TCP
    -NodePort:                 <unset>  31893/TCP
    -Endpoints:                10.244.1.177:8080,10.244.1.178:8080,10.244.1.179:8080 + 7 more...
    -Session Affinity:         None
    -External Traffic Policy:  Cluster
    -Events:                   <none>
    -

    在 Kubernetes 集群中,基于Deployment coredns 的Service kube-dns提供了集群 DNS 服务。

    服务注册:

    • Kubernetes 使用集群 DNS 作为服务注册。
    • 注册是基于 Service 而非 Pod 的。
    • 集群 DNS(CoreDNS)主动监视和发现新服务。
    • Service 名称、IP、端口将被注册。

    Service 注册的过程如下:

    • 将新的 Service POST 到 API Server。
    • 为新的 Service 分配 ClusterIP。
    • 将新的 Service 配置信息保存到 etcd 中。
    • 创建与新 Service 关联的带有相关 Pod IP 的 endpoints。
    • 通过 ClusterDNS 探索新的 Service。
    • 创建 DNS 信息。
    • kube-proxy 获取 Service 配置信息。
    • 创建 IPSV 规则。

    Service 发现的过程。

    • 请求一个 Service 名称的 DNS 名称解析。
    • 收到 ClusterIP。
    • 访问 ClusterIP。
    • 没有路由器。将请求转发到 Pod 的默认网关。
    • 将请求转发到节点。
    • 没有路由器。将请求转发到节点的默认网关。
    • 节点内核继续处理请求。
    • 使用 IPSV 规则捕获请求。
    • 将目标 Pod 的 IP 放入请求的目标 IP 中。
    • 请求到达目标 Pod。

    FQDN格式为:<object-name>.<namespace>.svc.cluster.local。我们称<object-name>为非限定名称或简短名称。 命名空间可以隔离集群的地址空间。同时,它还可以用于实现访问控制和资源配额。

    获取Pod中的DNS配置。 nameserver的IP与kube-dns服务的ClusterIP相同,这是用于DNS请求或服务发现请求的众所周知的IP。

    $ kubectl get service kube-dns -n kube-system
    -NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
    -kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   7d7h
    +kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default
    +

    Finalizers是*命名空间键*,告诉Kubernetes在满足特定条件之前等待,然后再完全删除标记为*删除*的资源。 Finalizer警告控制器controller清理已删除对象所拥有的资源。

    通常因为某种目的为资源添加Finalizers,强制删除它们可能会导致集群中出现问题。

    与标签类似,所有者引用(Owner references)描述了Kubernetes中对象之间的关系,但用于不同的目的。

    Kubernetes使用所有者引用(而不是标签)来确定集群中哪些Pod需要清理。

    当Kubernetes识别到目标删除的资源上有所有者引用时,它会处理Finalizer。

    所有者和依赖关系

    在 Kubernetes 中,一些对象拥有其他对象。例如,ReplicaSet 是一组 Pod 的所有者。这些被拥有的对象是其所有者的从属对象。

    从属对象具有一个 metadata.ownerReferences 字段,该字段引用其所有者对象。

    有效的所有者引用包括对象名称和与从属对象相同的命名空间中的 UID。

    从属对象还具有一个 ownerReferences.blockOwnerDeletion 字段,该字段具有布尔值,控制特定的从属对象是否可以阻止垃圾回收删除其所有者对象。

    资源

    Kubernetes资源和“意向记录”都以API对象的形式存储,并通过对API的RESTful调用进行修改。

    API允许以声明性方式管理配置。

    用户可以直接与Kubernetes API交互,也可以通过像kubectl这样的工具进行交互。

    核心Kubernetes API具有灵活性,也可以扩展以支持自定义资源。

    • 工作负载资源(Workload Resources)
    • Pod。Pod 是可以在主机上运行的容器集合。
    • PodTemplate。PodTemplate 描述了预定义 pod 的副本模板。
    • ReplicationController。ReplicationController 表示一个复制控制器的配置。
    • ReplicaSet。ReplicaSet 确保在任何给定时间有指定数量的 pod 副本正在运行。
    • Deployment。Deployment 使 Pod 和 ReplicaSet 的声明性更新成为可能。
    • StatefulSet。StatefulSet 表示具有一致标识的 pod 集合。
    • ControllerRevision。ControllerRevision 实现了状态数据的不可变快照。
    • DaemonSet。DaemonSet 表示一个守护进程集的配置。
    • Job。Job 表示单个 job 的配置。
    • CronJob。CronJob 表示单个 cron job 的配置。
    • HorizontalPodAutoscaler。HorizontalPodAutoscaler 表示水平 pod 自动缩放器的配置。
    • HorizontalPodAutoscaler v2beta2。HorizontalPodAutoscaler 是水平 pod 自动缩放器的配置,根据指定的指标自动管理实现比例子资源的任何资源的副本计数。
    • PriorityClass。PriorityClass 定义了从优先级类名称到优先级整数值的映射。
    • 服务资源(Service Resources)
    • Service. Service 是对软件服务(例如mysql)的命名抽象,由代理监听的本地端口(例如3306)和确定哪些Pod将回答通过代理发送的请求的选择器组成。
    • Endpoints. Endpoints 是实现实际服务的一组终结点。
    • EndpointSlice. EndpointSlice 表示实现服务的终结点的子集。
    • Ingress. Ingress 是一组规则,允许入站连接到达由后端定义的终结点。
    • IngressClass. IngressClass 表示 Ingress 的类,由 Ingress Spec 引用。
    • 配置和存储资源(Config and Storage Resources)
    • ConfigMap。ConfigMap保存容器需要使用的配置数据。
    • Secret。Secret保存特定类型的机密数据。
    • Volume。Volume表示Pod中的命名卷,可以被Pod中的任何容器访问。
    • PersistentVolumeClaim。PersistentVolumeClaim是用户对持久卷的请求和声明。
    • PersistentVolume。PersistentVolume(PV)是由管理员提供的存储资源。
    • StorageClass。StorageClass描述可动态分配PersistentVolumes的存储类别的参数。
    • VolumeAttachment。VolumeAttachment记录将指定的卷附加到/从指定节点中分离的意图。
    • CSIDriver。CSIDriver记录集群上部署的容器存储接口(CSI)卷驱动程序的信息。
    • CSINode。CSINode保存有关节点上安装的所有CSI驱动程序的信息。
    • CSIStorageCapacity。CSIStorageCapacity存储一个CSI GetCapacity调用的结果。
    • 认证资源(Authentication Resources)
    • ServiceAccount*。ServiceAccount和下面的信息绑定在一起:
      • 一个可被用户和周边系统理解的名称,用于身份识别
      • 可进行身份验证和授权的主体
      • 一组密钥。
    • TokenRequest*。TokenRequest为给定的ServiceAccount请求一个令牌。
    • TokenReview*。TokenReview尝试对已知用户的令牌进行身份验证。
    • CertificateSigningRequest*。CertificateSigningRequest对象提供了一种通过提交证书签名请求并异步批准和发放来获取x509证书的机制。
    • 授权资源(Authorization Resources)
    • LocalSubjectAccessReview*。LocalSubjectAccessReview检查一个用户或组在给定命名空间中是否能执行某个操作。
    • SelfSubjectAccessReview*。SelfSubjectAccessReview检查当前用户是否能执行某个操作。
    • SelfSubjectRulesReview*。SelfSubjectRulesReview枚举当前用户在一个命名空间内可以执行的操作集合。
    • SubjectAccessReview*。SubjectAccessReview检查一个用户或组是否能执行某个操作。
    • ClusterRole*。ClusterRole是一个集群级别的PolicyRules逻辑分组,可以被RoleBinding或ClusterRoleBinding引用为一个单元。
    • ClusterRoleBinding*。ClusterRoleBinding引用一个ClusterRole,但不包含它。
    • Role*。Role是一个命名空间级别的PolicyRules逻辑分组,可以被RoleBinding引用为一个单元。
    • RoleBinding*。RoleBinding引用一个Role,但不包含它。
    • 策略资源(Policy Resources)
    • LimitRange*。LimitRange为命名空间中每种资源设置资源使用限制。
    • ResourceQuota*。ResourceQuota设置每个命名空间强制执行的总配额限制。
    • NetworkPolicy*。NetworkPolicy描述了一组Pod允许的网络流量。
    • PodDisruptionBudget*。PodDisruptionBudget是一个对象,用于定义对一组Pod可能造成的最大中断。
    • PodSecurityPolicy v1beta1*。PodSecurityPolicy控制对可能影响将应用于Pod和容器的安全上下文的请求的能力。
    • 扩展资源(Extend Resources)
    • CustomResourceDefinition*。CustomResourceDefinition表示应在API服务器上公开的资源。
    • MutatingWebhookConfiguration*。MutatingWebhookConfiguration描述接受或拒绝并可能更改对象的准入Webhook的配置。
    • ValidatingWebhookConfiguration*。ValidatingWebhookConfiguration描述接受或拒绝对象但不更改对象的准入Webhook的配置。
    • 集群资源(Cluster Resources)
    • Node*。Node是Kubernetes中的工作节点。
    • Namespace*。Namespace为名称提供了作用域。
    • Event*。Event是对集群中某个位置发生事件的报告。
    • APIService*。APIService表示特定GroupVersion的服务器。
    • Lease*。Lease定义了租赁的概念。
    • RuntimeClass*。RuntimeClass定义了集群中支持的容器运行时类。
    • FlowSchema v1beta2*。FlowSchema定义了一组流程的架构。
    • PriorityLevelConfiguration v1beta2*。PriorityLevelConfiguration表示优先级级别的配置。
    • Binding*。Binding将一个对象绑定到另一个对象;例如,调度程序将Pod绑定到节点上。
    • ComponentStatus*。ComponentStatus(和ComponentStatusList)保存集群验证信息。

    使用命令 kube api-resources 获取支持的API资源。

    使用命令 kubectl explain RESOURCE [options] 描述与每个支持的API资源相关联的字段。这些字段可以通过简单的JSONPath标识符进行识别:

    kubectl explain binding
    +kubectl explain binding.metadata
    +kubectl explain binding.metadata.name
    +

    工作负载资源

    Pods

    Pod是Kubernetes中可创建和管理的最小部署计算单位。

    Pod是一个包含一个或多个容器、共享存储和网络资源以及如何运行容器的规范的组。

    Pod的内容始终共同定位和共同安排,并在共享环境中运行。

    Pod模拟了一个特定于应用程序的“逻辑主机”:它包含一个或多个相对紧密耦合的应用程序容器。

    在非云环境中,同一物理或虚拟机上执行的应用程序类似于在同一逻辑主机上执行的云应用程序。

    Pod的共享环境是一组Linux命名空间、cgroups和可能的其他隔离要素 - 这些要素与隔离Docker容器的方式相同。

    在Docker概念方面,Pod类似于具有共享命名空间和共享文件系统卷的一组Docker容器。

    通常情况下,甚至是单例Pod,我们都不需要直接创建Pod,而是使用工作负载资源,例如*Deployment*或*Job*来创建它们。如果Pod需要跟踪状态,则可以使用StatefulSet资源。

    Kubernetes集群中的Pod有两种主要用法:

    • 运行单个容器的Pod。
    • 运行需要共同工作的多个容器的Pod。

    “每个Pod一个容器”的模型是最常见的Kubernetes用例;在这种情况下可以将Pod视为单个容器的包装器;Kubernetes管理Pod而不是直接管理容器。

    一个Pod可以封装由多个共同定位、紧密耦合且需要共享资源的容器组成的应用程序。

    这些共同定位的容器形成一个单一的服务整体单元 - 例如,一个容器向公众提供存储在共享卷中的数据,而另一个独立的Sidecar容器刷新或更新这些文件。Pod将这些容器、存储资源和短暂的网络标识包装在一起,作为一个单独的单位。

    在单个Pod中分组多个共同定位和共同管理的容器是相对高级的用例。应该*仅在*容器紧密耦合的特定情况下使用此模式。

    每个Pod都旨在运行给定应用程序的单个实例。如果我们想水平扩展您的应用程序(通过运行更多实例提供更多的总资源),则应该使用多个Pod,每个实例一个Pod。在Kubernetes中,这通常称为*复制*。复制的Pod通常作为工作负载资源及其控制器的一组创建和管理。

    Pod本地提供两种共享资源以供其组成容器使用:网络*和存储*。

    一个Pod可以指定一组共享的存储卷。Pod中的所有容器都可以访问这些共享卷,使这些容器可以共享数据。

    每个Pod为每个地址族分配一个唯一的IP地址。 在一个Pod内,容器共享一个IP地址和端口空间,并可以通过“localhost”找到彼此。想要与运行在不同Pod中的容器交互的容器可以使用IP网络进行通信。

    当创建一个Pod时,新的Pod被调度在集群中的一个节点上运行。Pod保留在该节点上,直到Pod执行完毕、Pod对象被删除、Pod因缺乏资源而被驱逐或节点发生故障。

    在Pod中重新启动一个容器不应与重新启动一个Pod混淆。Pod不是一个进程,而是一个运行容器的环境。Pod会一直保留,直到被删除为止。

    您可以使用工作负载资源(例如Deployment、StatefulSet、DaemonSet)为自己创建和管理多个Pod。资源的控制器处理复制、滚动和在Pod失败时的自动恢复。Pod with multiple containers

    初始化容器

    一些Pod还有初始化容器(Init containers)和应用容器(app containers)。初始化容器在应用容器启动之前运行并完成。

    我们可以在Pod规范中指定初始化容器,同时也可以在容器数组中描述应用容器。

    静态Pod

    静态Pod是直接由特定节点上的kubelet守护程序管理的,API服务器不会观察它们。

    静态Pod始终绑定到特定节点上的一个Kubelet。

    静态Pod的主要用途是运行自托管控制面板:换句话说,使用kubelet监督各个控制面板组件。

    kubelet会自动尝试为每个静态Pod在Kubernetes API服务器上创建一个镜像Pod。这意味着在节点上运行的Pod在API服务器上可见,但无法从那里控制。

    容器探针

    探针是 kubelet 定期对容器执行的一种诊断。

    为执行诊断,kubelet 要么在容器内执行代码,要么发起网络请求。

    使用探针有四种不同的检查容器方式。每个探针必须恰好定义这四种机制中的一种:

    • exec。如果命令以状态代码 0 退出,则将诊断视为成功。
    • grpc。如果响应的状态为 SERVING,则将诊断视为成功。
    • httpGet。如果响应的状态代码大于或等于 200 且小于 400,则将诊断视为成功。
    • tcpSocket。如果端口开放,则将诊断视为成功。

    每个探针有三种结果:

    • 成功
    • 失败
    • 未知

    探针类型:

    • livenessProbe。指示容器是否正在运行。
    • readinessProbe。指示容器是否准备好响应请求。
    • startupProbe。指示容器内的应用程序是否启动。

    Deployment

    ReplicaSet

    ReplicaSet的目的是在任何时候维护一组稳定的副本Pod。因此,它通常用于保证指定数量的相同Pod的可用性。

    我们一般不需要直接操纵ReplicaSet对象:使用Deployment,然后在spec部分中定义您的应用程序。

    可以通过设置replicaset.spec.replicas来指定应同时运行多少个Pod。 ReplicaSet将创建/删除其Pod以匹配此数字。 如果不指定replicaset.spec.replicas,则默认值为1

    StatefulSet

    StatefulSet 特点(又称固定标识):

    • Pod 的名称在创建后不可变。
    • DNS 主机名在创建后不可变。
    • 挂载的卷在创建后不可变。

    StatefulSet 的固定标识在失败、扩展和其他操作后不会改变。

    StatefulSet 的命名约定为:<StatefulSetName>-<Integer>

    StatefulSet 可以自行进行扩展,但是 Deployment 需要依靠 ReplicaSet 进行扩展。

    建议:先将 StatefulSet 减少到 0,而不是直接删除它。

    headless Service 和 governing Service:

    • Headless Service 是一个普通的 Kubernetes Service 对象,其 spec.clusterIP 被设置为 None
    • 当 StatefulSet 的 spec.ServiceName 设置为 headless Service 名称时,StatefulSet 现在是一个 governing Service。

    创建 StatefulSet 的一般过程:

    • 创建 StorageClass。
    • 创建 Headless Service。
    • 基于上述两个创建 StatefulSet。

    DaemonSet

    DaemonSet保证所有(或部分)节点运行Pod的副本。随着节点从集群中删除,这些Pod将被垃圾回收。

    删除DaemonSet将清理它创建的Pod。

    一些典型DaemonSet的用途包括:

    • 在每个节点上运行集群存储守护程序。
    • 在每个节点上运行日志收集守护程序。
    • 在每个节点上运行节点监视守护程序。

    在简单的情况下,每种类型的守护程序将使用覆盖所有节点的一个DaemonSet。

    更复杂的设置可能会为单个守护程序使用多个DaemonSet,但使用不同的标志和/或不同的内存和CPU请求来支持不同的硬件类型。

    DaemonSet控制器调和过程同时检查现有节点和新创建的节点。

    默认情况下,Kubernetes调度程序忽略由DamonSet创建的Pod,并允许它们存在于节点上,直到关闭节点本身。

    在选择节点上运行Pod:

    • 如果您指定daemonset.spec.template.spec.nodeSelector,那么DaemonSet控制器将在与该节点选择器匹配的节点上创建Pod。
    • 如果您指定daemonset.spec.template.spec.affinity,那么DaemonSet控制器将在与该节点亲和力匹配的节点上创建Pod。
    • 如果两者都不指定,则DaemonSet控制器将在所有节点上创建Pod。

    kubectl explain daemonset.spec中没有replicas字段与kubectl explain deployment.spec.replicas相对应。当创建一个DaemonSet时,每个节点将运行*一个* DaemonSet Pod。

    对于服务,通常是无状态的,一般不关心节点在哪里运行,更关心Pod副本的数量,并且我们可以将这些副本/replicas缩放。在这里,滚动更新也将是一个优点。

    当Pod的一个副本必须在某个指定节点上运行时,我们将使用DaemonSet。我们的守护进程Pod还需要在我们的其他Pod之前启动。

    DaemonSet是用于后台服务的简单可扩展性策略。当更多的合适的节点添加到集群时,后台服务将扩展。当节点被删除时,它将自动缩小。

    Job

    CronJob

    服务资源

    Service

    Service是软件服务(例如mysql)的命名抽象,由代理监听的本地端口(例如3306)和确定哪些Pod将回答通过代理发送的请求的选择器组成。

    一个Service的目标Pod集合通常由一个选择器(标签选择器)来确定。

    Service资源的类型包括:

    • ClusterIP Service(默认):可靠的IP、DNS和端口。仅限内部访问。
    • NodePort Service:向外部提供访问。
    • LoadBalancer:基于NodePort,并与云供应商提供的负载平衡集成(例如AWS、GCP等)。
    • ExternalName:访问将被转发到外部服务。

    下面是一个创建简单Service的yaml文件:

    apiVersion: v1
    +kind: Service
    +metadata:
    +  name: nginx-service
    +  labels:
    +    tier: application
    +spec:
    +  ports:
    +  - port: 80
    +    protocol: TCP
    +    targetPort: 8080
    +  selector:
    +    run: nginx
    +  type: NodePort
    +

    下面是一个Service的例子:

    • IP 10.96.17.77 是该服务的 ClusterIP(VIP)。
    • 端口 <unset> 80/TCP 是 Pod 在集群内监听的端口。
    • TargetPort 8080/TCP 是容器内服务应该定向流量到达的端口。
    • NodePort <unset> 31893/TCP 是可以从外部访问的端口。默认范围是 30000~32767。该端口会在整个集群的所有节点上暴露。
    • Endpoints 显示了匹配服务标签的 Pod 列表。
    Name:                     nginx-deployment
    +Namespace:                jh-namespace
    +Labels:                   tier=application
    +Annotations:              <none>
    +Selector:                 run=nginx
    +Type:                     NodePort
    +IP Family Policy:         SingleStack
    +IP Families:              IPv4
    +IP:                       10.96.17.77
    +IPs:                      10.96.17.77
    +Port:                     <unset>  80/TCP
    +TargetPort:               8080/TCP
    +NodePort:                 <unset>  31893/TCP
    +Endpoints:                10.244.1.177:8080,10.244.1.178:8080,10.244.1.179:8080 + 7 more...
    +Session Affinity:         None
    +External Traffic Policy:  Cluster
    +Events:                   <none>
    +

    在 Kubernetes 集群中,基于Deployment coredns 的Service kube-dns提供了集群 DNS 服务。

    服务注册:

    • Kubernetes 使用集群 DNS 作为服务注册。
    • 注册是基于 Service 而非 Pod 的。
    • 集群 DNS(CoreDNS)主动监视和发现新服务。
    • Service 名称、IP、端口将被注册。

    Service 注册的过程如下:

    • 将新的 Service POST 到 API Server。
    • 为新的 Service 分配 ClusterIP。
    • 将新的 Service 配置信息保存到 etcd 中。
    • 创建与新 Service 关联的带有相关 Pod IP 的 endpoints。
    • 通过 ClusterDNS 探索新的 Service。
    • 创建 DNS 信息。
    • kube-proxy 获取 Service 配置信息。
    • 创建 IPSV 规则。

    Service 发现的过程。

    • 请求一个 Service 名称的 DNS 名称解析。
    • 收到 ClusterIP。
    • 访问 ClusterIP。
    • 没有路由器。将请求转发到 Pod 的默认网关。
    • 将请求转发到节点。
    • 没有路由器。将请求转发到节点的默认网关。
    • 节点内核继续处理请求。
    • 使用 IPSV 规则捕获请求。
    • 将目标 Pod 的 IP 放入请求的目标 IP 中。
    • 请求到达目标 Pod。

    FQDN格式为:<object-name>.<namespace>.svc.cluster.local。我们称<object-name>为非限定名称或简短名称。 命名空间可以隔离集群的地址空间。同时,它还可以用于实现访问控制和资源配额。

    获取Pod中的DNS配置。 nameserver的IP与kube-dns服务的ClusterIP相同,这是用于DNS请求或服务发现请求的众所周知的IP。

    $ kubectl get service kube-dns -n kube-system
    +NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
    +kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   7d7h
     
     
    -$ kubectl exec -it nginx-5f5496dc9-bv5dx -- /bin/bash
    -root@nginx-5f5496dc9-bv5dx:/# cat /etc/resolv.conf
    -search jh-namespace.svc.cluster.local svc.cluster.local cluster.local
    -nameserver 10.96.0.10
    -options ndots:5
    -

    读取 kube-dns信息:

    $ kubectl describe service kube-dns -n kube-system
    -Name:              kube-dns
    -Namespace:         kube-system
    -Labels:            k8s-app=kube-dns
    -                   kubernetes.io/cluster-service=true
    -                   kubernetes.io/name=CoreDNS
    -Annotations:       prometheus.io/port: 9153
    -                   prometheus.io/scrape: true
    -Selector:          k8s-app=kube-dns
    -Type:              ClusterIP
    -IP Family Policy:  SingleStack
    -IP Families:       IPv4
    -IP:                10.96.0.10
    -IPs:               10.96.0.10
    -Port:              dns  53/UDP
    -TargetPort:        53/UDP
    -Endpoints:         10.244.0.2:53,10.244.0.3:53
    -Port:              dns-tcp  53/TCP
    -TargetPort:        53/TCP
    -Endpoints:         10.244.0.2:53,10.244.0.3:53
    -Port:              metrics  9153/TCP
    -TargetPort:        9153/TCP
    -Endpoints:         10.244.0.2:9153,10.244.0.3:9153
    -Session Affinity:  None
    -Events:            <none>
    -

    Endpoints

    Endpoints是一组实现实际服务的端点集合。

    当创建服务时,它会与一个Endpoint对象相关联,可以使用命令 kubectl get endpoints <service_name> 获取。

    匹配服务标签的Pod列表维护为Endpoint对象,添加新的匹配Pod并删除不匹配的Pod。

    配置和存储资源

    emptyDir

    emptyDir卷是在Pod分配到节点时首先创建的,并且只要该Pod在该节点上运行,它就会存在。

    emptyDir卷最初为空。

    Pod中的所有容器都可以读取和写入emptyDir卷中的相同文件,尽管该卷可以在每个容器中以相同或不同的路径挂载。

    当由于任何原因从节点中删除Pod时,emptyDir中的数据将永久删除。

    容器崩溃不会将Pod从节点中删除。 emptyDir卷中的数据可以在容器崩溃时安全保留。

    用途:

    • 临时空间,例如基于磁盘的归并排序
    • 为了从崩溃中恢复而进行的长时间计算的检查点
    • 保存内容管理器容器提取的文件,同时Web服务器容器提供数据

    hostPath

    hostPath 卷将主机节点文件系统中的文件或目录挂载到 Pod 中。这不是大多数 Pod 都需要的,但对于某些应用程序来说,它提供了一个强大的逃生口。

    hostPath 卷存在许多安全风险,因此在可能的情况下最好避免使用 HostPath。当必须使用 HostPath 卷时,应将其范围限定为仅所需的文件或目录,并以只读方式挂载。

    如果通过 AdmissionPolicy 限制 HostPath 访问特定目录,则必须要求 volumeMounts 使用 readOnly 挂载,以使策略生效。

    用途:

    • 与 DaemonSet 一起运行,例如,EFK Fluentd 挂载本地主机的日志目录以收集主机日志信息。
    • 通过使用 hostPath 卷在特定节点上运行,可以获得高性能的磁盘 I/O。
    • 运行需要访问 Docker 内部的容器;使用 /var/lib/docker 的 hostPath。
    • 在容器中运行 cAdvisor;使用 /sys 的 hostPath。
    • 允许 Pod 指定给定的 hostPath 是否应该在 Pod 运行之前存在,是否应该创建它以及它应该存在的内容。

    Storage Class

    StorageClass 部署和实现的步骤如下:

    • 创建 Kubernetes 集群和后端存储。
    • 确保 Kubernetes 中的 provisioner/plugin 可用。
    • 创建一个 StorageClass 对象并将其链接到后端存储。StorageClass 将自动创建相关的 PV。
    • 创建一个 PVC 对象并将其链接到我们创建的 StorageClass。
    • 部署一个 Pod 并使用 PVC 卷。

    PV

    PV回收策略:

    • 保留 (Retain)
    • 删除 (Delete)
    • 回收 (Recycle)

    PV in-tree类型:

    • hostPath
    • local
    • NFS
    • CSI

    Access Modes

    Access Modes(访问模式)中,spec.accessModes 定义了 PV 的挂载选项:

    • ReadWriteOnce(RWO):一个 PV 只能被一个读写模式的 PVC 挂载,类似于块设备。
    • ReadWriteMany(RWM):一个 PV 可以被多个读写模式的 PVC 挂载,例如 NFS。
    • ReadOnlyMany(ROM):一个 PV 可以被多个只读模式的 PVC 挂载。
    • ReadWriteOncePod(RWOP):只支持 CSI 类型的 PV,只能被单个 Pod 挂载。

    一个 PV 只能设置一种选项。Pod 挂载 PVC,而不是 PV。

    \ No newline at end of file +$ kubectl exec -it nginx-5f5496dc9-bv5dx -- /bin/bash +root@nginx-5f5496dc9-bv5dx:/# cat /etc/resolv.conf +search jh-namespace.svc.cluster.local svc.cluster.local cluster.local +nameserver 10.96.0.10 +options ndots:5 +

    读取 kube-dns信息:

    $ kubectl describe service kube-dns -n kube-system
    +Name:              kube-dns
    +Namespace:         kube-system
    +Labels:            k8s-app=kube-dns
    +                   kubernetes.io/cluster-service=true
    +                   kubernetes.io/name=CoreDNS
    +Annotations:       prometheus.io/port: 9153
    +                   prometheus.io/scrape: true
    +Selector:          k8s-app=kube-dns
    +Type:              ClusterIP
    +IP Family Policy:  SingleStack
    +IP Families:       IPv4
    +IP:                10.96.0.10
    +IPs:               10.96.0.10
    +Port:              dns  53/UDP
    +TargetPort:        53/UDP
    +Endpoints:         10.244.0.2:53,10.244.0.3:53
    +Port:              dns-tcp  53/TCP
    +TargetPort:        53/TCP
    +Endpoints:         10.244.0.2:53,10.244.0.3:53
    +Port:              metrics  9153/TCP
    +TargetPort:        9153/TCP
    +Endpoints:         10.244.0.2:9153,10.244.0.3:9153
    +Session Affinity:  None
    +Events:            <none>
    +

    Endpoints

    Endpoints是一组实现实际服务的端点集合。

    当创建服务时,它会与一个Endpoint对象相关联,可以使用命令 kubectl get endpoints <service_name> 获取。

    匹配服务标签的Pod列表维护为Endpoint对象,添加新的匹配Pod并删除不匹配的Pod。

    配置和存储资源

    emptyDir

    emptyDir卷是在Pod分配到节点时首先创建的,并且只要该Pod在该节点上运行,它就会存在。

    emptyDir卷最初为空。

    Pod中的所有容器都可以读取和写入emptyDir卷中的相同文件,尽管该卷可以在每个容器中以相同或不同的路径挂载。

    当由于任何原因从节点中删除Pod时,emptyDir中的数据将永久删除。

    容器崩溃不会将Pod从节点中删除。 emptyDir卷中的数据可以在容器崩溃时安全保留。

    用途:

    • 临时空间,例如基于磁盘的归并排序
    • 为了从崩溃中恢复而进行的长时间计算的检查点
    • 保存内容管理器容器提取的文件,同时Web服务器容器提供数据

    hostPath

    hostPath 卷将主机节点文件系统中的文件或目录挂载到 Pod 中。这不是大多数 Pod 都需要的,但对于某些应用程序来说,它提供了一个强大的逃生口。

    hostPath 卷存在许多安全风险,因此在可能的情况下最好避免使用 HostPath。当必须使用 HostPath 卷时,应将其范围限定为仅所需的文件或目录,并以只读方式挂载。

    如果通过 AdmissionPolicy 限制 HostPath 访问特定目录,则必须要求 volumeMounts 使用 readOnly 挂载,以使策略生效。

    用途:

    • 与 DaemonSet 一起运行,例如,EFK Fluentd 挂载本地主机的日志目录以收集主机日志信息。
    • 通过使用 hostPath 卷在特定节点上运行,可以获得高性能的磁盘 I/O。
    • 运行需要访问 Docker 内部的容器;使用 /var/lib/docker 的 hostPath。
    • 在容器中运行 cAdvisor;使用 /sys 的 hostPath。
    • 允许 Pod 指定给定的 hostPath 是否应该在 Pod 运行之前存在,是否应该创建它以及它应该存在的内容。

    Storage Class

    StorageClass 部署和实现的步骤如下:

    • 创建 Kubernetes 集群和后端存储。
    • 确保 Kubernetes 中的 provisioner/plugin 可用。
    • 创建一个 StorageClass 对象并将其链接到后端存储。StorageClass 将自动创建相关的 PV。
    • 创建一个 PVC 对象并将其链接到我们创建的 StorageClass。
    • 部署一个 Pod 并使用 PVC 卷。

    PV

    PV回收策略:

    • 保留 (Retain)
    • 删除 (Delete)
    • 回收 (Recycle)

    PV in-tree类型:

    • hostPath
    • local
    • NFS
    • CSI

    Access Modes

    Access Modes(访问模式)中,spec.accessModes 定义了 PV 的挂载选项:

    • ReadWriteOnce(RWO):一个 PV 只能被一个读写模式的 PVC 挂载,类似于块设备。
    • ReadWriteMany(RWM):一个 PV 可以被多个读写模式的 PVC 挂载,例如 NFS。
    • ReadOnlyMany(ROM):一个 PV 可以被多个只读模式的 PVC 挂载。
    • ReadWriteOncePod(RWOP):只支持 CSI 类型的 PV,只能被单个 Pod 挂载。

    一个 PV 只能设置一种选项。Pod 挂载 PVC,而不是 PV。

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/namespace/index.html b/k8s/cka_cn/foundamentals/namespace/index.html index 4612ff2f..611ce0eb 100644 --- a/k8s/cka_cn/foundamentals/namespace/index.html +++ b/k8s/cka_cn/foundamentals/namespace/index.html @@ -1,14 +1,14 @@ - Namespace - UPSkilling

    CKA自学笔记11:Namespace

    演示场景

    • 获取namespace列表
    • 创建新的namespace
    • 给namespace设定标签
    • 删除一个namespace

    演示

    获取当前namespace列表。

    kubectl get namespace
    -

    获取当前namespace列表和对应标签信息。

    kubectl get ns --show-labels
    -

    创建一个namespace cka

    kubectl create namespace cka
    -

    给新创建的namespace cka设定标签。

    kubectl label ns cka cka=true
    -

    在namespace cka 上创建 Nginx Deployment。

    kubectl create deploy nginx --image=nginx --namespace cka
    -

    在namespace cka上检查正在运行的deployment和pod。

    kubectl get deploy,pod -n cka
    + Namespace - UPSkilling       

    CKA自学笔记11:Namespace

    演示场景

    • 获取namespace列表
    • 创建新的namespace
    • 给namespace设定标签
    • 删除一个namespace

    演示

    获取当前namespace列表。

    kubectl get namespace
    +

    获取当前namespace列表和对应标签信息。

    kubectl get ns --show-labels
    +

    创建一个namespace cka

    kubectl create namespace cka
    +

    给新创建的namespace cka设定标签。

    kubectl label ns cka cka=true
    +

    在namespace cka 上创建 Nginx Deployment。

    kubectl create deploy nginx --image=nginx --namespace cka
    +

    在namespace cka上检查正在运行的deployment和pod。

    kubectl get deploy,pod -n cka
     

    运行结果:

    NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
     deployment.apps/nginx   1/1     1            1           2m14s
     
     NAME                         READY   STATUS    RESTARTS   AGE
     pod/nginx-85b98978db-bmkhf   1/1     Running   0          2m14s
    -

    删除namespace cka,则所有运行在这个namespace上的资源都会被删除。

    kubectl delete ns cka
    -

    如果在删除某个namespace时遇到状态一直是Terminating,则可以尝试用下面的方法解决。

    kubectl get namespace $NAMESPACE -o json | sed -e 's/"kubernetes"//' | kubectl replace --raw "/api/v1/namespaces$NAMESPACE/finalize" -f -
    -
    \ No newline at end of file +

    删除namespace cka,则所有运行在这个namespace上的资源都会被删除。

    kubectl delete ns cka
    +

    如果在删除某个namespace时遇到状态一直是Terminating,则可以尝试用下面的方法解决。

    kubectl get namespace $NAMESPACE -o json | sed -e 's/"kubernetes"//' | kubectl replace --raw "/api/v1/namespaces$NAMESPACE/finalize" -f -
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/networkpolicy/index.html b/k8s/cka_cn/foundamentals/networkpolicy/index.html index 472bccb8..4b29bbe5 100644 --- a/k8s/cka_cn/foundamentals/networkpolicy/index.html +++ b/k8s/cka_cn/foundamentals/networkpolicy/index.html @@ -1,5 +1,5 @@ - Network Policy - UPSkilling

    CKA自学笔记23:Network Policy

    用Calico替换Flannel

    演示场景:

    • 卸载Flannel
    • 安装Calico

    演示:

    如果在安装过程中已经安装了 Calico,则可以忽略这部分内容。

    卸载Flannel

    kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/v0.18.1/Documentation/kube-flannel.yml
    -

    或者

    kubectl delete -f kube-flannel.yml
    + Network Policy - UPSkilling       

    CKA自学笔记23:Network Policy

    用Calico替换Flannel

    演示场景:

    • 卸载Flannel
    • 安装Calico

    演示:

    如果在安装过程中已经安装了 Calico,则可以忽略这部分内容。

    卸载Flannel

    kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/v0.18.1/Documentation/kube-flannel.yml
    +

    或者

    kubectl delete -f kube-flannel.yml
     

    输出:

    Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
     podsecuritypolicy.policy "psp.flannel.unprivileged" deleted
     clusterrole.rbac.authorization.k8s.io "flannel" deleted
    @@ -7,10 +7,10 @@
     serviceaccount "flannel" deleted
     configmap "kube-flannel-cfg" deleted
     daemonset.apps "kube-flannel-ds" deleted
    -

    在所有节点上清除iptables设置。

    rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni
    -iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    -

    重新登录主机节点,例如 cka001,安装Calico,

    curl https://docs.projectcalico.org/manifests/calico.yaml -O
    -kubectl apply -f calico.yaml
    +

    在所有节点上清除iptables设置。

    rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni
    +iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    +

    重新登录主机节点,例如 cka001,安装Calico,

    curl https://docs.projectcalico.org/manifests/calico.yaml -O
    +kubectl apply -f calico.yaml
     

    Output:

    configmap/calico-config created
     customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
     customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
    @@ -38,20 +38,20 @@
     deployment.apps/calico-kube-controllers created
     serviceaccount/calico-kube-controllers created
     poddisruptionbudget.policy/calico-kube-controllers created
    -

    验证Calico安装状态,确保在每个节点上都正常运行。

    kubectl get pod -n kube-system | grep calico
    +

    验证Calico安装状态,确保在每个节点上都正常运行。

    kubectl get pod -n kube-system | grep calico
     

    输出结果:

    NAME                                       READY   STATUS        RESTARTS   AGE
     calico-kube-controllers-7bc6547ffb-tjfcg   1/1     Running       0          30m
     calico-node-7x8jm                          1/1     Running       0          30m
     calico-node-cwxj5                          1/1     Running       0          30m
     calico-node-rq978                          1/1     Running       0          30m
     

    如果遇到任何错误,首先检查容器container日志。

    # Get Container ID
    -crictl ps
    +crictl ps
     
     # Get log info
    -crictl logs <your_container_id>
    -

    由于我们将 CNI 从 Flannel 更改为 Calico,我们需要删除所有 Pod,所有 Pod 都将自动重新创建。

    kubectl delete pod -A --all
    -

    查询所有pod都状态,确保他们都正常运行。

    kubectl get pod -A
    -

    入站规则(Inbound Rules)

    演示场景:

    • 创建用于测试的工作负载。
    • 禁止所有入站流量。
    • 允许特定的入站流量。
    • 验证NetworkPolicy。

    创建测试工作负载

    创建三个 Deployment,名称为 pod-netpol-1pod-netpol-2pod-netpol-3,它们都基于镜像 busybox

    kubectl apply -f - << EOF
    +crictl logs <your_container_id>
    +

    由于我们将 CNI 从 Flannel 更改为 Calico,我们需要删除所有 Pod,所有 Pod 都将自动重新创建。

    kubectl delete pod -A --all
    +

    查询所有pod都状态,确保他们都正常运行。

    kubectl get pod -A
    +

    入站规则(Inbound Rules)

    演示场景:

    • 创建用于测试的工作负载。
    • 禁止所有入站流量。
    • 允许特定的入站流量。
    • 验证NetworkPolicy。

    创建测试工作负载

    创建三个 Deployment,名称为 pod-netpol-1pod-netpol-2pod-netpol-3,它们都基于镜像 busybox

    kubectl apply -f - << EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -115,18 +115,18 @@
             name: busybox
             command: ["sh", "-c", "sleep 1h"]       
     EOF
    -

    检查pod的IP地址:

    kubectl get pod -owide
    +

    检查pod的IP地址:

    kubectl get pod -owide
     

    输出结果:

    NAME                                      READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
     pod-netpol-1-6494f6bf8b-n58r9             1/1     Running   0          29s   10.244.102.30   cka003   <none>           <none>
     pod-netpol-2-77478d77ff-l6rzm             1/1     Running   0          29s   10.244.112.30   cka002   <none>           <none>
     pod-netpol-3-68977dcb48-ql5s6             1/1     Running   0          29s   10.244.102.31   cka003   <none>           <none>
    -

    登录进入pod pod-netpol-1

    kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh
    -

    执行命令 ping,确保 pod-netpol-2pod-netpol-3 可互相访问。

    / # ping 10.244.112.30 
    -3 packets transmitted, 3 packets received, 0% packet loss
    +

    登录进入pod pod-netpol-1

    kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh
    +

    执行命令 ping,确保 pod-netpol-2pod-netpol-3 可互相访问。

    / # ping 10.244.112.30 
    +3 packets transmitted, 3 packets received, 0% packet loss
     
    -/ # ping 10.244.102.31
    -3 packets transmitted, 3 packets received, 0% packet loss
    -

    禁止所有入站流量

    创建策略,禁止所有入站流量。

    kubectl apply -f - << EOF
    +/ # ping 10.244.102.31
    +3 packets transmitted, 3 packets received, 0% packet loss
    +

    禁止所有入站流量

    创建策略,禁止所有入站流量。

    kubectl apply -f - << EOF
     apiVersion: networking.k8s.io/v1
     kind: NetworkPolicy
     metadata:
    @@ -136,13 +136,13 @@
       policyTypes:
       - Ingress
     EOF
    -

    再次登录进入pod pod-netpol-1

    kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh
    -

    Execute command ping that pod-netpol-2 and pod-netpol-3 are both unreachable as expected. 执行命令 ping,和我们预期一样,pod-netpol-2pod-netpol-3 此时互相无法访问。

    / # ping 10.244.112.30
    -3 packets transmitted, 0 packets received, 100% packet loss
    +

    再次登录进入pod pod-netpol-1

    kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh
    +

    Execute command ping that pod-netpol-2 and pod-netpol-3 are both unreachable as expected. 执行命令 ping,和我们预期一样,pod-netpol-2pod-netpol-3 此时互相无法访问。

    / # ping 10.244.112.30
    +3 packets transmitted, 0 packets received, 100% packet loss
     
    -/ # ping 10.244.102.31
    -3 packets transmitted, 0 packets received, 100% packet loss
    -

    允许特定的入站流量

    创建 NetworkPolicy,允许来自 pod-netpol-1pod-netpol-2 的入站流量。

    kubectl apply -f - <<EOF
    +/ # ping 10.244.102.31
    +3 packets transmitted, 0 packets received, 100% packet loss
    +

    允许特定的入站流量

    创建 NetworkPolicy,允许来自 pod-netpol-1pod-netpol-2 的入站流量。

    kubectl apply -f - <<EOF
     apiVersion: networking.k8s.io/v1
     kind: NetworkPolicy
     metadata:
    @@ -159,14 +159,14 @@
             matchLabels:
               app: pod-netpol-1
     EOF
    -

    验证NetworkPolicy

    再次登录进入pod pod-netpol-1

    kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh
    -

    和我们设定的预期一致,pod-netpol-2可以访问,但是pod-netpol-3仍然无法访问。

    / # ping 10.244.112.30
    -3 packets transmitted, 3 packets received, 0% packet loss
    +

    验证NetworkPolicy

    再次登录进入pod pod-netpol-1

    kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh
    +

    和我们设定的预期一致,pod-netpol-2可以访问,但是pod-netpol-3仍然无法访问。

    / # ping 10.244.112.30
    +3 packets transmitted, 3 packets received, 0% packet loss
     
    -/ # ping 10.244.102.8
    -3 packets transmitted, 0 packets received, 100% packet loss
    -

    跨namespace的入站流量

    演示场景:

    • 创建工作负载和测试的namespace
    • 创建允许 Ingress 的 NetworkPolicy
    • 验证 NetworkPolicy

    创建测试工作负载和namespace

    创建namespace ns-netpol

    kubectl create ns ns-netpol
    -

    创建 deployment pod-netpol

    kubectl apply -f - << EOF
    +/ # ping 10.244.102.8
    +3 packets transmitted, 0 packets received, 100% packet loss
    +

    跨namespace的入站流量

    演示场景:

    • 创建工作负载和测试的namespace
    • 创建允许 Ingress 的 NetworkPolicy
    • 验证 NetworkPolicy

    创建测试工作负载和namespace

    创建namespace ns-netpol

    kubectl create ns ns-netpol
    +

    创建 deployment pod-netpol

    kubectl apply -f - << EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -189,13 +189,13 @@
             name: busybox
             command: ["sh", "-c", "sleep 1h"]
     EOF
    -

    在新的namespace上检查pod的运行状态。

    kubectl get pod -n ns-netpol
    +

    在新的namespace上检查pod的运行状态。

    kubectl get pod -n ns-netpol
     

    输出结果:

    NAME                          READY   STATUS    RESTARTS   AGE
     pod-netpol-5b67b6b496-2cgnw   1/1     Running   0          9s
    -

    连接登入pod pod-netpol

    kubectl exec -it pod-netpol-5b67b6b496-2cgnw -n ns-netpol -- sh
    -

    在namespace dev 中 ping pod-netpol-210.244.112.30)。

    ping 10.244.112.30
    +

    连接登入pod pod-netpol

    kubectl exec -it pod-netpol-5b67b6b496-2cgnw -n ns-netpol -- sh
    +

    在namespace dev 中 ping pod-netpol-210.244.112.30)。

    ping 10.244.112.30
     

    运行结果,pod无法访问。

    3 packets transmitted, 0 packets received, 100% packet loss
    -

    创建允许入站流量的Ingress

    创建 NetworkPolicy,允许来自namespace pod-netpol 中的所有 Pod 访问namespace dev 中的 pod-netpol-2

    kubectl apply -f - <<EOF
    +

    创建允许入站流量的Ingress

    创建 NetworkPolicy,允许来自namespace pod-netpol 中的所有 Pod 访问namespace dev 中的 pod-netpol-2

    kubectl apply -f - <<EOF
     apiVersion: networking.k8s.io/v1
     kind: NetworkPolicy
     metadata:
    @@ -212,20 +212,20 @@
             matchLabels:
               allow: to-pod-netpol-2
     EOF
    -

    验证策略

    登录进入pod pod-netpol

    kubectl exec -it pod-netpol-5b67b6b496-2cgnw -n ns-netpol -- sh
    -

    尝试在namespace dev 中对 pod-netpol-2 (10.244.112.30) 执行 ping 命令。

    ping 10.244.112.30
    +

    验证策略

    登录进入pod pod-netpol

    kubectl exec -it pod-netpol-5b67b6b496-2cgnw -n ns-netpol -- sh
    +

    尝试在namespace dev 中对 pod-netpol-2 (10.244.112.30) 执行 ping 命令。

    ping 10.244.112.30
     

    运行结果如下,依然无法访问。

    3 packets transmitted, 0 packets received, 100% packet loss
    -

    我们允许的入站流量是来自带有标签 allow: to-pod-netpol-2 的命名空间,但命名空间 ns-netpol 没有这个标签,我们需要给它打上标签。

    kubectl label ns ns-netpol allow=to-pod-netpol-2
    -

    登录进入pod pod-netpol

    kubectl exec -it pod-netpol-5b67b6b496-2cgnw -n ns-netpol -- sh
    -

    尝试在namespace dev 中对 pod-netpol-2 (10.244.112.30) 执行 ping 命令。

    ping 10.244.112.30
    +

    我们允许的入站流量是来自带有标签 allow: to-pod-netpol-2 的命名空间,但命名空间 ns-netpol 没有这个标签,我们需要给它打上标签。

    kubectl label ns ns-netpol allow=to-pod-netpol-2
    +

    登录进入pod pod-netpol

    kubectl exec -it pod-netpol-5b67b6b496-2cgnw -n ns-netpol -- sh
    +

    尝试在namespace dev 中对 pod-netpol-2 (10.244.112.30) 执行 ping 命令。

    ping 10.244.112.30
     

    运行结果如下,可以访问。

    3 packets transmitted, 3 packets received, 0% packet loss
    -

    注意,我们也可以使用命名空间的默认标签。

    NetworkPolicy

    Ingress演示场景:

    • 创建两个namespace my-ns-1my-ns-2
    • my-ns-1 中创建两个部署,nginx 监听端口 80tomcat 监听端口 8080
    • 在namespace my-ns-1 中创建 NetworkPolicy my-networkpolicy-1,以允许从namespace my-ns-1 访问端口 8080
    • 验证对 nginx 端口 80tomcat 端口 8080 的访问。
    • 编辑 NetworkPolicy,以允许从命名空间 my-ns-2 访问端口 8080
    • 验证对 nginx 端口 80tomcat 端口 8080 的访问。

    演示:

    创建2个namespaces。

    kubectl create namespace my-ns-1
    -kubectl create namespace my-ns-2
    -

    在namespace my-ns-1上创建deployment。

    kubectl create deployment my-nginx --image=nginx --namespace=my-ns-1 --port=80
    -kubectl create deployment my-tomcat --image=tomcat --namespace=my-ns-1 --port=8080
    -

    查询2个namespace的标签,例如:kubernetes.io/metadata.name=my-ns-1, kubernetes.io/metadata.name=my-ns-2.

    kubectl get namespace my-ns-1 --show-labels  
    -kubectl get namespace my-ns-2 --show-labels   
    -

    创建 NetworkPolicy,允许从 my-ns-2 访问 my-ns-1 上监听 8080 端口的 Pod。

    参考:yaml文件模版

    kubectl apply -f - << EOF
    +

    注意,我们也可以使用命名空间的默认标签。

    NetworkPolicy

    Ingress演示场景:

    • 创建两个namespace my-ns-1my-ns-2
    • my-ns-1 中创建两个部署,nginx 监听端口 80tomcat 监听端口 8080
    • 在namespace my-ns-1 中创建 NetworkPolicy my-networkpolicy-1,以允许从namespace my-ns-1 访问端口 8080
    • 验证对 nginx 端口 80tomcat 端口 8080 的访问。
    • 编辑 NetworkPolicy,以允许从命名空间 my-ns-2 访问端口 8080
    • 验证对 nginx 端口 80tomcat 端口 8080 的访问。

    演示:

    创建2个namespaces。

    kubectl create namespace my-ns-1
    +kubectl create namespace my-ns-2
    +

    在namespace my-ns-1上创建deployment。

    kubectl create deployment my-nginx --image=nginx --namespace=my-ns-1 --port=80
    +kubectl create deployment my-tomcat --image=tomcat --namespace=my-ns-1 --port=8080
    +

    查询2个namespace的标签,例如:kubernetes.io/metadata.name=my-ns-1, kubernetes.io/metadata.name=my-ns-2.

    kubectl get namespace my-ns-1 --show-labels  
    +kubectl get namespace my-ns-2 --show-labels   
    +

    创建 NetworkPolicy,允许从 my-ns-2 访问 my-ns-1 上监听 8080 端口的 Pod。

    参考:yaml文件模版

    kubectl apply -f - << EOF
     apiVersion: networking.k8s.io/v1
     kind: NetworkPolicy
     metadata:
    @@ -245,12 +245,12 @@
             - protocol: TCP
               port: 8080
     EOF
    -

    查询 deployment 和 pod 的状态。

    kubectl get deployment,pod -n my-ns-1 -o wide
    -

    在namespace my-ns-1 中创建一个临时的 Pod。

    登录进入到这个 Pod,执行下面2个命令,验证访问。

    • 运行 curl <nginx_ip>:80 失败
    • 运行 curl <tomcat_ip>:80 成功
    kubectl run centos --image=centos -n my-ns-1 -- "/bin/sh" "-c" "sleep 3600"
    -kubectl exec -it mycentos -n my-ns-1 -- bash
    -

    在namespace my-ns-2 中创建一个临时 Pod,然后连接到该 Pod 并验证访问。

    • 命令 curl <nginx_ip>:80 失败
    • 命令 curl <tomcat_ip>:80 失败。
    kubectl run centos --image=centos -n my-ns-2 -- "/bin/sh" "-c" "sleep 3600"
    -kubectl exec -it mycentos -n my-ns-2 -- bash
    -

    修改 my-networkpolicy-1, 把 ingress.from.namespaceSelector.matchLabels 的值改为 my-ns-2

    登录进入namespace my-ns-2上的临时pod,验证访问。

    • 命令 curl <nginx_ip>:80 失败
    • 命令 curl <tomcat_ip>:80 成功
    kubectl exec -it mycentos -n my-ns-2 -- bash
    -

    删除演示中创建的临时资源。

    kubectl delete namespace my-ns-1
    -kubectl delete namespace my-ns-2
    -
    \ No newline at end of file +

    查询 deployment 和 pod 的状态。

    kubectl get deployment,pod -n my-ns-1 -o wide
    +

    在namespace my-ns-1 中创建一个临时的 Pod。

    登录进入到这个 Pod,执行下面2个命令,验证访问。

    • 运行 curl <nginx_ip>:80 失败
    • 运行 curl <tomcat_ip>:80 成功
    kubectl run centos --image=centos -n my-ns-1 -- "/bin/sh" "-c" "sleep 3600"
    +kubectl exec -it mycentos -n my-ns-1 -- bash
    +

    在namespace my-ns-2 中创建一个临时 Pod,然后连接到该 Pod 并验证访问。

    • 命令 curl <nginx_ip>:80 失败
    • 命令 curl <tomcat_ip>:80 失败。
    kubectl run centos --image=centos -n my-ns-2 -- "/bin/sh" "-c" "sleep 3600"
    +kubectl exec -it mycentos -n my-ns-2 -- bash
    +

    修改 my-networkpolicy-1, 把 ingress.from.namespaceSelector.matchLabels 的值改为 my-ns-2

    登录进入namespace my-ns-2上的临时pod,验证访问。

    • 命令 curl <nginx_ip>:80 失败
    • 命令 curl <tomcat_ip>:80 成功
    kubectl exec -it mycentos -n my-ns-2 -- bash
    +

    删除演示中创建的临时资源。

    kubectl delete namespace my-ns-1
    +kubectl delete namespace my-ns-2
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/overview/index.html b/k8s/cka_cn/foundamentals/overview/index.html index 1763ae28..5cfdf0f3 100644 --- a/k8s/cka_cn/foundamentals/overview/index.html +++ b/k8s/cka_cn/foundamentals/overview/index.html @@ -1,7 +1,7 @@ - Kubernetes集群概览 - UPSkilling

    CKA自学笔记6:Kubernetes集群概览

    摘要

    包含下面内容:

    • 容器层
    • Kubernetes层

    提示:

    后续实验环境都是使用在阿里云部署的Ubuntu三节点集群,三个节点分别为 cka001cka002cka003

    容器层

    场景:

    使用Containerd服务,通过命令nerdctl来管理我们的镜像和容器,这与Docker的概念相同。

    • Get namespace.
    • Get containers.
    • Get images.
    • Get volumes.
    • Get overall status.
    • Get network status.

    演示:

    读取命名空间namespaces。

    sudo nerdctl namespace ls
    + Kubernetes集群概览 - UPSkilling       

    CKA自学笔记6:Kubernetes集群概览

    摘要

    包含下面内容:

    • 容器层
    • Kubernetes层

    提示:

    后续实验环境都是使用在阿里云部署的Ubuntu三节点集群,三个节点分别为 cka001cka002cka003

    容器层

    场景:

    使用Containerd服务,通过命令nerdctl来管理我们的镜像和容器,这与Docker的概念相同。

    • Get namespace.
    • Get containers.
    • Get images.
    • Get volumes.
    • Get overall status.
    • Get network status.

    演示:

    读取命名空间namespaces。

    sudo nerdctl namespace ls
     

    运行结果:

    NAME      CONTAINERS    IMAGES    VOLUMES    LABELS
     k8s.io    21            30        0      
    -

    读取命名空间 k8s.io下的容器。

    sudo nerdctl -n k8s.io ps
    +

    读取命名空间 k8s.io下的容器。

    sudo nerdctl -n k8s.io ps
     

    运行结果:

    CONTAINER ID    IMAGE                                                                      COMMAND                   CREATED         STATUS    PORTS    NAMES
     0a3625f22f65    registry.aliyuncs.com/google_containers/pause:3.6                          "/pause"                  16 hours ago    Up                 k8s://kube-system/coredns-74586cf9b6-4jwmk
     121af2ecd1a1    registry.aliyuncs.com/google_containers/coredns:v1.8.6                     "/coredns -conf /etc…"    16 hours ago    Up                 k8s://kube-system/coredns-74586cf9b6-c5mll/coredns
    @@ -19,12 +19,12 @@
     cdc041b4791e    registry.aliyuncs.com/google_containers/etcd:3.5.3-0                       "etcd --advertise-cl…"    16 hours ago    Up                 k8s://kube-system/etcd-cka001/etcd
     e0c59abadf2e    registry.aliyuncs.com/google_containers/pause:3.6                          "/pause"                  16 hours ago    Up                 k8s://kube-system/kube-proxy-dmj2t
     e0d2e5f6ccff    registry.aliyuncs.com/google_containers/pause:3.6                          "/pause"                  16 hours ago    Up                 k8s://kube-system/kube-apiserver-cka001
    -

    读取命名空间 k8s.io下的镜像。

    sudo nerdctl -n k8s.io image ls -a
    -

    读取命名空间 k8s.io下的卷Volume。初始化安装后,该命名空间下没有任何卷。

    sudo nerdctl -n k8s.io volume ls
    -

    读取集群状态。

    sudo nerdctl stats
    -

    读取网络状态。

    sudo nerdctl network ls
    -sudo nerdctl network inspect bridge
    -sudo nerdctl network inspect k8s-pod-network
    +

    读取命名空间 k8s.io下的镜像。

    sudo nerdctl -n k8s.io image ls -a
    +

    读取命名空间 k8s.io下的卷Volume。初始化安装后,该命名空间下没有任何卷。

    sudo nerdctl -n k8s.io volume ls
    +

    读取集群状态。

    sudo nerdctl stats
    +

    读取网络状态。

    sudo nerdctl network ls
    +sudo nerdctl network inspect bridge
    +sudo nerdctl network inspect k8s-pod-network
     

    运行结果:

    NETWORK ID    NAME               FILE
                   k8s-pod-network    /etc/cni/net.d/10-calico.conflist
     0             bridge             /etc/cni/net.d/nerdctl-bridge.conflist
    @@ -35,14 +35,14 @@
     tunl0@NONE           : inet 10.244.228.192/32 scope global tunl0
     cali96e32d88db2@if4  :
     cali93613212490@if4  :
    -

    nerdctl-bridge.conflist文件的作用是:

    • 定义了nerdctl使用的默认桥接CNI网络的配置,包括网络名称、子网、网关、IP分配策略等12
    • 使得nerdctl可以使用docker run -it --rm alpine这样的命令来运行一个容器,并自动分配一个10.4.0.0/24网段的IP地址13
    • 使得nerdctl可以支持一些基本的CNI插件,如bridge, portmap, firewall, tuning12

    Kubernetes层

    场景:

    • 节点Nodes
    • 命名空间Namespaces
    • 系统Pods

    演示:

    读取节点状态:

    kubectl get node -o wide
    -

    在三个节点上有四个初始的命名空间。

    kubectl get namespace -A
    -

    运行结果:

    NAME              STATUS   AGE
    -default           Active   56m
    -kube-node-lease   Active   56m
    -kube-public       Active   56m
    -kube-system       Active   56m
    -

    在三个节点上的初始化Pod。

    kubectl get pod -A -o wide
    +

    nerdctl-bridge.conflist文件的作用是:

    • 定义了nerdctl使用的默认桥接CNI网络的配置,包括网络名称、子网、网关、IP分配策略等12
    • 使得nerdctl可以使用docker run -it --rm alpine这样的命令来运行一个容器,并自动分配一个10.4.0.0/24网段的IP地址13
    • 使得nerdctl可以支持一些基本的CNI插件,如bridge, portmap, firewall, tuning12

    Kubernetes层

    场景:

    • 节点Nodes
    • 命名空间Namespaces
    • 系统Pods

    演示:

    读取节点状态:

    kubectl get node -o wide
    +

    在三个节点上有四个初始的命名空间。

    kubectl get namespace -A
    +

    运行结果:

    NAME              STATUS   AGE
    +default           Active   56m
    +kube-node-lease   Active   56m
    +kube-public       Active   56m
    +kube-system       Active   56m
    +

    在三个节点上的初始化Pod。

    kubectl get pod -A -o wide
     

    运行结果:

    NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE   NODE     NOMINATED NODE   READINESS GATES
     kube-system   calico-kube-controllers-555bc4b957-l8bn2   1/1     Running   0          15h   cka003   <none>           <none>
     kube-system   calico-node-255pc                          1/1     Running   0          15h   cka003   <none>           <none>
    @@ -57,4 +57,4 @@
     kube-system   kube-proxy-n77zw                           1/1     Running   0          15h   cka002   <none>           <none>
     kube-system   kube-proxy-qs6rf                           1/1     Running   0          15h   cka003   <none>           <none>
     kube-system   kube-scheduler-cka001                      1/1     Running   0          15h   cka001   <none>           <none>
    -

    总结: 下面列出了初始集群中主节点和所有节点中所包含的容器和Pod的关系。

    • Master node:
    • CoreDNS: 2 Pod
    • etcd: 1 Pod
    • apiserver: 1 Pod
    • controller-manager: 1 Pod
    • scheduler: 1 Pod
    • Calico Controller: 1 Pod
    • All nodes:
    • Calico Node: 1 Pod each
    • Proxy: 1 Pod each

    参考:

    \ No newline at end of file +

    总结: 下面列出了初始集群中主节点和所有节点中所包含的容器和Pod的关系。

    • Master node:
    • CoreDNS: 2 Pod
    • etcd: 1 Pod
    • apiserver: 1 Pod
    • controller-manager: 1 Pod
    • scheduler: 1 Pod
    • Calico Controller: 1 Pod
    • All nodes:
    • Calico Node: 1 Pod each
    • Proxy: 1 Pod each

    参考:

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/persistence/index.html b/k8s/cka_cn/foundamentals/persistence/index.html index dabc0129..38081e86 100644 --- a/k8s/cka_cn/foundamentals/persistence/index.html +++ b/k8s/cka_cn/foundamentals/persistence/index.html @@ -1,4 +1,4 @@ - Persistence - UPSkilling

    CKA自学笔记17:Persistence

    摘要

    演示场景:

    • 创建一个类型为 emptyDir 的卷来创建 Pod,Pod 中的容器将会挂载在运行节点上的默认目录 /var/lib/kubelet/pods/ 中。
    • 创建一个类型为 hostPath 的卷来创建 Deployment,Deployment 中的容器将会挂载在运行节点上定义的目录 hostPath: 中。
    • 创建 PV 和 PVC:
    • 设置 NFS 服务器并共享 /nfsdata/ 目录。
    • 创建 PV mysql-pv 并映射到共享目录 /nfsdata/,同时设置 StorageClassName 为 nfs
    • 创建 PVC mysql-pvc 并映射到 StorageClassName 为 nfs 的 PV 上。
    • 创建 Deployment mysql 来使用 PVC mysql-pvc
    • 创建 StorageClass:
    • 创建 ServiceAccount nfs-client-provisioner
    • 创建 ClusterRole nfs-client-provisioner-runner 和 Role leader-locking-nfs-client-provisioner,并将其绑定到 ServiceAccount 上,以便该 ServiceAccount 可以操作下一步中创建的 Deployment。
    • 创建 Deployment nfs-client-provisioner 来添加连接到 NFS 服务器的信息,例如 PROVISIONER_NAMEk8s-sigs.io/nfs-subdir-external-provisioner
    • 创建 StorageClass nfs-client 并链接到 provisioner: k8s-sigs.io/nfs-subdir-external-provisioner,相关的 PV 会自动创建。
    • 创建 PVC nfs-pvc-from-sc 并映射到 StorageClass nfs-client 上的 PV。
    • 配置Configuration:
    • 创建一个 ConfigMap 以包含文件的内容,并将此 ConfigMap 挂载到 Pod 中的特定文件中。
    • 创建一个 ConfigMap 来包含用户名和密码,并在 Pod 中使用它们。
    • 在 Pod 中将 ConfigMap 用作环境变量。

    建议:

    • 首先删除 PVC,然后再删除 PV。
    • 如果删除 PVC 时遇到 Terminating 状态,使用 kubectl edit pvc <your_pvc_name> 命令,然后删除 finalize: <your_value>

    emptyDir

    创建一个名为 hello-producer 的 Pod,并使用 emptyDir 类型的 Volume。

    cat > pod-emptydir.yaml <<EOF
    + Persistence - UPSkilling       

    CKA自学笔记17:Persistence

    摘要

    演示场景:

    • 创建一个类型为 emptyDir 的卷来创建 Pod,Pod 中的容器将会挂载在运行节点上的默认目录 /var/lib/kubelet/pods/ 中。
    • 创建一个类型为 hostPath 的卷来创建 Deployment,Deployment 中的容器将会挂载在运行节点上定义的目录 hostPath: 中。
    • 创建 PV 和 PVC:
    • 设置 NFS 服务器并共享 /nfsdata/ 目录。
    • 创建 PV mysql-pv 并映射到共享目录 /nfsdata/,同时设置 StorageClassName 为 nfs
    • 创建 PVC mysql-pvc 并映射到 StorageClassName 为 nfs 的 PV 上。
    • 创建 Deployment mysql 来使用 PVC mysql-pvc
    • 创建 StorageClass:
    • 创建 ServiceAccount nfs-client-provisioner
    • 创建 ClusterRole nfs-client-provisioner-runner 和 Role leader-locking-nfs-client-provisioner,并将其绑定到 ServiceAccount 上,以便该 ServiceAccount 可以操作下一步中创建的 Deployment。
    • 创建 Deployment nfs-client-provisioner 来添加连接到 NFS 服务器的信息,例如 PROVISIONER_NAMEk8s-sigs.io/nfs-subdir-external-provisioner
    • 创建 StorageClass nfs-client 并链接到 provisioner: k8s-sigs.io/nfs-subdir-external-provisioner,相关的 PV 会自动创建。
    • 创建 PVC nfs-pvc-from-sc 并映射到 StorageClass nfs-client 上的 PV。
    • 配置Configuration:
    • 创建一个 ConfigMap 以包含文件的内容,并将此 ConfigMap 挂载到 Pod 中的特定文件中。
    • 创建一个 ConfigMap 来包含用户名和密码,并在 Pod 中使用它们。
    • 在 Pod 中将 ConfigMap 用作环境变量。

    建议:

    • 首先删除 PVC,然后再删除 PV。
    • 如果删除 PVC 时遇到 Terminating 状态,使用 kubectl edit pvc <your_pvc_name> 命令,然后删除 finalize: <your_value>

    emptyDir

    创建一个名为 hello-producer 的 Pod,并使用 emptyDir 类型的 Volume。

    cat > pod-emptydir.yaml <<EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -19,23 +19,23 @@
        emptyDir: {}
     EOF
     
    -kubectl apply -f pod-emptydir.yaml
    -

    查看Pod hello-producer的状态。

    kubectl get pod hello-producer -owide
    +kubectl apply -f pod-emptydir.yaml
    +

    查看Pod hello-producer的状态。

    kubectl get pod hello-producer -owide
     

    Pod hello-producer 运行在节点node cka003上。

    NAME             READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
     hello-producer   1/1     Running   0          6s    10.244.102.24   cka003   <none>           <none>
    -

    登录 cka003,因为 Pod hello-producer 正在该节点上运行。

    crictl 命令设置环境变量 CONTAINER_RUNTIME_ENDPOINT。建议在所有节点上执行相同的操作。

    export CONTAINER_RUNTIME_ENDPOINT=unix:///run/containerd/containerd.sock
    -

    运行命令 crictl ps 来获取 Pod hello-producer 的容器 ID。

    crictl ps |grep hello-producer
    +

    登录 cka003,因为 Pod hello-producer 正在该节点上运行。

    crictl 命令设置环境变量 CONTAINER_RUNTIME_ENDPOINT。建议在所有节点上执行相同的操作。

    export CONTAINER_RUNTIME_ENDPOINT=unix:///run/containerd/containerd.sock
    +

    运行命令 crictl ps 来获取 Pod hello-producer 的容器 ID。

    crictl ps |grep hello-producer
     

    容器 producer 的ID是 05f5e1bb6a1bb

    CONTAINER           IMAGE               CREATED             STATE               NAME                ATTEMPT             POD ID              POD
     50058afb3cba5       62aedd01bd852       About an hour ago   Running             producer            0                   e6953bd4833a7       hello-producer
    -

    运行命令 crictl inspect,获取已挂载的 shared-volume 的路径,它是 emptyDir 类型的。

    crictl inspect 50058afb3cba5 | grep source | grep empty
    +

    运行命令 crictl inspect,获取已挂载的 shared-volume 的路径,它是 emptyDir 类型的。

    crictl inspect 50058afb3cba5 | grep source | grep empty
     

    运行结果

    "source": "/var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume",
    -

    修改路径为上面获取到的 shared-volume 的挂载路径。然后我们会看到文件 hello 中的内容 hello world

    cd /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume
    -cat hello
    -

    Pod内的路径/producer_dir被挂载到了本地宿主机路径/var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume

    我们在Pod内创建的文件/producer_dir/hello实际上在宿主机本地路径中。

    让我们删除容器producer,容器producer将以新的容器ID重新启动,而文件hello仍将存在。

    crictl ps
    -crictl stop <your_container_id>
    -crictl rm <your_container_id>
    -

    现在删除Pod hello-producer,容器producer会被删除,文件hello也会被删除。

    kubectl delete pod hello-producer 
    -

    hostPath

    应用以下 yaml 文件创建一个 MySQL Pod 并挂载一个 hostPath。 将主机目录 /tmp/mysql 挂载到 Pod 目录 /var/lib/mysql。 在本地检查是否存在目录 /tmp/mysql,如果不存在,则执行命令 mkdir /tmp/mysql 创建它。

    cat > mysql-hostpath.yaml <<EOF
    +

    修改路径为上面获取到的 shared-volume 的挂载路径。然后我们会看到文件 hello 中的内容 hello world

    cd /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume
    +cat hello
    +

    Pod内的路径/producer_dir被挂载到了本地宿主机路径/var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume

    我们在Pod内创建的文件/producer_dir/hello实际上在宿主机本地路径中。

    让我们删除容器producer,容器producer将以新的容器ID重新启动,而文件hello仍将存在。

    crictl ps
    +crictl stop <your_container_id>
    +crictl rm <your_container_id>
    +

    现在删除Pod hello-producer,容器producer会被删除,文件hello也会被删除。

    kubectl delete pod hello-producer 
    +

    hostPath

    应用以下 yaml 文件创建一个 MySQL Pod 并挂载一个 hostPath。 将主机目录 /tmp/mysql 挂载到 Pod 目录 /var/lib/mysql。 在本地检查是否存在目录 /tmp/mysql,如果不存在,则执行命令 mkdir /tmp/mysql 创建它。

    cat > mysql-hostpath.yaml <<EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -67,41 +67,41 @@
            name: mysql-vol
     EOF
     
    -kubectl apply -f mysql-hostpath.yaml
    -

    验证 MySQL 可用性。

    检查 MySQL Pod 的状态。需要记录 Pod 的名称和其所运行的节点。

    kubectl get pod -l app=mysql -o wide
    +kubectl apply -f mysql-hostpath.yaml
    +

    验证 MySQL 可用性。

    检查 MySQL Pod 的状态。需要记录 Pod 的名称和其所运行的节点。

    kubectl get pod -l app=mysql -o wide
     

    运行结果

    NAME                     READY   STATUS              RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
     mysql-749c8ddd67-h2rgs   0/1     ContainerCreating   0          28s   <none>   cka003   <none>           <none>
    -

    在MySQL Pod运行的节点登陆进入pod内部。

    kubectl exec -it <your_pod_name> -- bash
    -

    在 Pod 中,进入 /var/lib/mysql 目录,该目录中的所有文件都与节点 cka003/tmp/mysql 目录中的所有文件相同。

    连接到 Pod 中的数据库。

    mysql -h 127.0.0.1 -uroot -ppassword
    -

    执行下面命令对数据库进行简单的操作。

    mysql> show databases;
    -mysql> connect mysql;
    -mysql> show tables;
    -mysql> exit
    -

    PV和PVC

    下面的演示中,我们将使用NFS作为后端存储来演示如何部署PV和PVC。

    设置NFS共享

    1. 安装nfs-kernel-server

    登录到节点cka002。配置Worker cka002成为NFS服务器。

    sudo apt-get install -y nfs-kernel-server
    -

    2.配置共享目录

    创建共享文件夹。

    mkdir /nfsdata
    -

    编辑文件/etc/exports,添加一行/nfsdata *(rw,sync,no_root_squash)

    cat >> /etc/exports << EOF
    +

    在MySQL Pod运行的节点登陆进入pod内部。

    kubectl exec -it <your_pod_name> -- bash
    +

    在 Pod 中,进入 /var/lib/mysql 目录,该目录中的所有文件都与节点 cka003/tmp/mysql 目录中的所有文件相同。

    连接到 Pod 中的数据库。

    mysql -h 127.0.0.1 -uroot -ppassword
    +

    执行下面命令对数据库进行简单的操作。

    mysql> show databases;
    +mysql> connect mysql;
    +mysql> show tables;
    +mysql> exit
    +

    PV和PVC

    下面的演示中,我们将使用NFS作为后端存储来演示如何部署PV和PVC。

    设置NFS共享

    1. 安装nfs-kernel-server

    登录到节点cka002。配置Worker cka002成为NFS服务器。

    sudo apt-get install -y nfs-kernel-server
    +

    2.配置共享目录

    创建共享文件夹。

    mkdir /nfsdata
    +

    编辑文件/etc/exports,添加一行/nfsdata *(rw,sync,no_root_squash)

    cat >> /etc/exports << EOF
     /nfsdata *(rw,sync,no_root_squash)
     EOF
    -

    有许多不同的NFS共享选项,例如:

    • *:对所有IP或特定IP可访问。
    • rw:作为读写共享。请注意,正常的Linux权限仍然适用。(请注意,这是默认选项。)
    • ro:作为只读共享。
    • sync:文件数据更改会立即写入磁盘,这会影响性能,但不太可能导致数据丢失。在某些发行版上,这是默认选项。
    • async:与sync相反,文件数据更改最初写入内存。这提高了性能,但更容易导致数据丢失。在某些发行版上,这是默认选项。
    • root_squash:将NFS客户端的root用户和组帐户映射到匿名帐户,通常是nobody帐户或nfsnobody帐户。有关更多详细信息,请参见本文后续的“用户ID映射”。(请注意,这是默认选项。)
    • no_root_squash:将NFS客户端的root用户和组帐户映射到本地root和组帐户。

    我们将使用基于Linux服务器之间的nfsrpcbind服务的无密码远程挂载,而不是基于smb服务。首先,这两台服务器必须授权、安装并设置nfs和rpcbind服务,设置共享目录,启动服务,并在客户端上进行挂载。

    启动rpcbind服务。

    sudo systemctl enable rpcbind
    -sudo systemctl restart rpcbind
    -

    启动nfs服务。

    sudo systemctl enable nfs-server
    -sudo systemctl start nfs-server
    -

    如果/etc/exports文件被修改,我们需要运行下面的命令使之生效。

    exportfs -ra
    -

    运行结果

    exportfs: /etc/exports [1]: Neither 'subtree_check' or 'no_subtree_check' specified for export "*:/nfsdata".
    -  Assuming default behaviour ('no_subtree_check').
    -  NOTE: this default has changed since nfs-utils version 1.0.x
    -

    检查共享目录是否已经被正确配置了。

    showmount -e
    +

    有许多不同的NFS共享选项,例如:

    • *:对所有IP或特定IP可访问。
    • rw:作为读写共享。请注意,正常的Linux权限仍然适用。(请注意,这是默认选项。)
    • ro:作为只读共享。
    • sync:文件数据更改会立即写入磁盘,这会影响性能,但不太可能导致数据丢失。在某些发行版上,这是默认选项。
    • async:与sync相反,文件数据更改最初写入内存。这提高了性能,但更容易导致数据丢失。在某些发行版上,这是默认选项。
    • root_squash:将NFS客户端的root用户和组帐户映射到匿名帐户,通常是nobody帐户或nfsnobody帐户。有关更多详细信息,请参见本文后续的“用户ID映射”。(请注意,这是默认选项。)
    • no_root_squash:将NFS客户端的root用户和组帐户映射到本地root和组帐户。

    我们将使用基于Linux服务器之间的nfsrpcbind服务的无密码远程挂载,而不是基于smb服务。首先,这两台服务器必须授权、安装并设置nfs和rpcbind服务,设置共享目录,启动服务,并在客户端上进行挂载。

    启动rpcbind服务。

    sudo systemctl enable rpcbind
    +sudo systemctl restart rpcbind
    +

    启动nfs服务。

    sudo systemctl enable nfs-server
    +sudo systemctl start nfs-server
    +

    如果/etc/exports文件被修改,我们需要运行下面的命令使之生效。

    exportfs -ra
    +

    运行结果

    exportfs: /etc/exports [1]: Neither 'subtree_check' or 'no_subtree_check' specified for export "*:/nfsdata".
    +  Assuming default behaviour ('no_subtree_check').
    +  NOTE: this default has changed since nfs-utils version 1.0.x
    +

    检查共享目录是否已经被正确配置了。

    showmount -e
     

    如果看到下面的结果,则说明共享目录已经被正确配置了。

    Export list for cka002:
     /nfsdata *
    -

    3.安装NFS客户端

    在所有节点上安装NFS客户端。

    sudo apt-get install -y nfs-common
    -

    4.验证NFS服务

    登录到任何一个节点来验证NFS服务是否正确工作,以及NFS服务所共享到目录是否可见。 登陆到cka001,并检查cka002的共享目录状态。

    showmount -e cka002
    -

    如果得到类似下面的结果,则说明NFS服务正常工作,包括共享目录。

    Export list for cka002:
    -/nfsdata *
    -

    5.挂载NFS共享目录

    执行下面命令,挂载NFS共享目录到任何一个非NFS服务器节点,比如cka001 or cka003

    mkdir /remote-nfs-dir
    -mount -t nfs cka002:/nfsdata /remote-nfs-dir/
    -

    执行命令df -h来检查NFS挂载点是否正确,类似下面的结果。

    Filesystem       Size  Used Avail Use% Mounted on
    -cka002:/nfsdata   40G  5.8G   32G  16% /remote-nfs-dir
    -

    创建 PV

    创建一个 PV mysql-pv。 将 NFS 服务器 IP 替换为实际的 IP(这里是 <cka002_ip>),它是运行 NFS 服务器 cka002 的 IP。

    kubectl apply -f - <<EOF
    +

    3.安装NFS客户端

    在所有节点上安装NFS客户端。

    sudo apt-get install -y nfs-common
    +

    4.验证NFS服务

    登录到任何一个节点来验证NFS服务是否正确工作,以及NFS服务所共享到目录是否可见。 登陆到cka001,并检查cka002的共享目录状态。

    showmount -e cka002
    +

    如果得到类似下面的结果,则说明NFS服务正常工作,包括共享目录。

    Export list for cka002:
    +/nfsdata *
    +

    5.挂载NFS共享目录

    执行下面命令,挂载NFS共享目录到任何一个非NFS服务器节点,比如cka001 or cka003

    mkdir /remote-nfs-dir
    +mount -t nfs cka002:/nfsdata /remote-nfs-dir/
    +

    执行命令df -h来检查NFS挂载点是否正确,类似下面的结果。

    Filesystem       Size  Used Avail Use% Mounted on
    +cka002:/nfsdata   40G  5.8G   32G  16% /remote-nfs-dir
    +

    创建 PV

    创建一个 PV mysql-pv。 将 NFS 服务器 IP 替换为实际的 IP(这里是 <cka002_ip>),它是运行 NFS 服务器 cka002 的 IP。

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: PersistentVolume
     metadata:
    @@ -117,10 +117,10 @@
        path: /nfsdata/
        server: <cka002_ip>
     EOF
    -

    执行下面的命令,检查创建的PV。

    kubectl get pv
    -

    运行结果

    NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
    -mysql-pv   1Gi        RWO            Retain           Available           nfs                     19s
    -

    创建 PVC

    创建 PVC mysql-pvc 并指定存储大小、访问模式和存储类。 PVC mysql-pvc 将通过存储类名称自动与 PV 绑定。

    kubectl apply -f - <<EOF
    +

    执行下面的命令,检查创建的PV。

    kubectl get pv
    +

    运行结果

    NAME       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
    +mysql-pv   1Gi        RWO            Retain           Available           nfs                     19s
    +

    创建 PVC

    创建 PVC mysql-pvc 并指定存储大小、访问模式和存储类。 PVC mysql-pvc 将通过存储类名称自动与 PV 绑定。

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: PersistentVolumeClaim
     metadata:
    @@ -133,7 +133,7 @@
           storage: 1Gi
       storageClassName: nfs
     EOF
    -

    消费 PVC

    更新Deployment mysql 来使用之前创建的PVC mysql-pvc

    kubectl apply -f - <<EOF
    +

    消费 PVC

    更新Deployment mysql 来使用之前创建的PVC mysql-pvc

    kubectl apply -f - <<EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -165,7 +165,7 @@
            persistentVolumeClaim:
             claimName: mysql-pvc
     EOF
    -

    现在我们可以看到 MySQL 文件已经移动到了 cka002/nfsdata 目录下。

    StorageClass

    配置RBAC权限

    RBAC(Role-Based Access Control,基于角色的访问控制)是 Kubernetes 中的一种授权机制,用于限制用户对资源的访问权限。 我们可以为 Kubernetes 集群中的用户分配不同的角色,以限制他们在集群中的操作。

    要配置 RBAC 授权,需要执行以下步骤:

    1. 为用户创建帐户
    2. 为帐户创建角色
    3. 为角色授予权限
    4. 将角色绑定到帐户

    这些步骤中的每一步都需要创建 Kubernetes 对象,例如 ServiceAccountRoleClusterRoleRoleBindingClusterRoleBinding

    RBAC权限使用rbac.authorization.k8s.io API组来驱动授权决策,允许我们通过Kubernetes API动态配置策略。

    • ServiceAccount:nfs-client-provisioner
    • 命名空间:dev
    • ClusterRole:nfs-client-provisioner-runner。在节点、pv、pvc、sc和事件上授予授权(authorization)。
    • ClusterRoleBinding:run-nfs-client-provisioner,将上述ClusterRole绑定到上述ServiceAccount。
    • Role:leader-locking-nfs-client-provisioner。在endpoint上授予权限。
    • RoleBinding:leader-locking-nfs-client-provisioner,将上述Role绑定到上述ServiceAccount。

    创建RBAC权限。

    cat > nfs-provisioner-rbac.yaml <<EOF
    +

    现在我们可以看到 MySQL 文件已经移动到了 cka002/nfsdata 目录下。

    StorageClass

    配置RBAC权限

    RBAC(Role-Based Access Control,基于角色的访问控制)是 Kubernetes 中的一种授权机制,用于限制用户对资源的访问权限。 我们可以为 Kubernetes 集群中的用户分配不同的角色,以限制他们在集群中的操作。

    要配置 RBAC 授权,需要执行以下步骤:

    1. 为用户创建帐户
    2. 为帐户创建角色
    3. 为角色授予权限
    4. 将角色绑定到帐户

    这些步骤中的每一步都需要创建 Kubernetes 对象,例如 ServiceAccountRoleClusterRoleRoleBindingClusterRoleBinding

    RBAC权限使用rbac.authorization.k8s.io API组来驱动授权决策,允许我们通过Kubernetes API动态配置策略。

    • ServiceAccount:nfs-client-provisioner
    • 命名空间:dev
    • ClusterRole:nfs-client-provisioner-runner。在节点、pv、pvc、sc和事件上授予授权(authorization)。
    • ClusterRoleBinding:run-nfs-client-provisioner,将上述ClusterRole绑定到上述ServiceAccount。
    • Role:leader-locking-nfs-client-provisioner。在endpoint上授予权限。
    • RoleBinding:leader-locking-nfs-client-provisioner,将上述Role绑定到上述ServiceAccount。

    创建RBAC权限。

    cat > nfs-provisioner-rbac.yaml <<EOF
     apiVersion: v1
     kind: ServiceAccount
     metadata:
    @@ -237,8 +237,8 @@
     EOF
     
     
    -kubectl apply -f nfs-provisioner-rbac.yaml
    -

    创建Provisioner的Deloyment

    "Provisioner" 可以翻译成 "提供程序",这个词可以指为 Kubernetes 集群中提供各种资源的服务程序,如动态存储卷提供程序 (Dynamic Provisioner)、网络存储卷提供程序 (CSI Driver) 等。

    创建 nfs-client-provisioner 部署,使用挂载到 <cka002_ip>(cka002) 上的 /nfsdata 目录的卷 nfs-client-root。 把 NFS 服务器的 IP 替换为实际的 IP 地址即可(这里用 <cka002_ip> 表示)。

    cat > nfs-provisioner-deployment.yaml <<EOF
    +kubectl apply -f nfs-provisioner-rbac.yaml
    +

    创建Provisioner的Deloyment

    "Provisioner" 可以翻译成 "提供程序",这个词可以指为 Kubernetes 集群中提供各种资源的服务程序,如动态存储卷提供程序 (Dynamic Provisioner)、网络存储卷提供程序 (CSI Driver) 等。

    创建 nfs-client-provisioner 部署,使用挂载到 <cka002_ip>(cka002) 上的 /nfsdata 目录的卷 nfs-client-root。 把 NFS 服务器的 IP 替换为实际的 IP 地址即可(这里用 <cka002_ip> 表示)。

    cat > nfs-provisioner-deployment.yaml <<EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -276,20 +276,20 @@
                 path: /nfsdata
     EOF
     
    -kubectl apply -f nfs-provisioner-deployment.yaml
    -

    创建 NFS StorageClass

    创建 StorageClass nfs-client,定义 NFS 子目录外部 provisioner 的 Kubernetes Storage Class。

    执行下面的命令编辑nfs-storageclass.yaml文件。

    vi nfs-storageclass.yaml
    -

    添加下面的信息来配置 NFS StorageClass。

    apiVersion: storage.k8s.io/v1
    -kind: StorageClass
    +kubectl apply -f nfs-provisioner-deployment.yaml
    +

    创建 NFS StorageClass

    创建 StorageClass nfs-client,定义 NFS 子目录外部 provisioner 的 Kubernetes Storage Class。

    执行下面的命令编辑nfs-storageclass.yaml文件。

    vi nfs-storageclass.yaml
    +

    添加下面的信息来配置 NFS StorageClass。

    apiVersion: storage.k8s.io/v1
    +kind: StorageClass
     metadata:
    -  name: nfs-client
    -  annotations:
    -    storageclass.kubernetes.io/is-default-class: "true"
    -provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
    +  name: nfs-client
    +  annotations:
    +    storageclass.kubernetes.io/is-default-class: "true"
    +provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
     parameters:
    -  pathPattern: "${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}"
    -  onDelete: delete
    +  pathPattern: "${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}"
    +  onDelete: delete
     

    应用上面的yaml文件,使之生效。

    kubectl apply -f nfs-storageclass.yaml
    -

    创建PVC

    创建 PVC nfs-pvc-from-sc

    kubectl apply -f - <<EOF
    +

    创建PVC

    创建 PVC nfs-pvc-from-sc

    kubectl apply -f - <<EOF
     kind: PersistentVolumeClaim
     apiVersion: v1
     metadata:
    @@ -302,15 +302,15 @@
         requests:
           storage: 1Gi
     EOF
    -

    查看所创建的 PVC nfs-pvc-from-sc 的状态。

    kubectl get pvc nfs-pvc-from-sc
    +

    查看所创建的 PVC nfs-pvc-from-sc 的状态。

    kubectl get pvc nfs-pvc-from-sc
     

    PVC nfs-pvc-from-sc 的当前状态是 Pending.

    NAME              STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
     nfs-pvc-from-sc   Pending                                      nfs-client     112s
    -

    检查 Pending 状态的原因。

    kubectl describe pvc nfs-pvc-from-sc
    +

    检查 Pending 状态的原因。

    kubectl describe pvc nfs-pvc-from-sc
     

    下面的信息说明 PVC nfs-pvc-from-sc 处于挂起状态,在等待卷(volume)创建完成。

    Events:
       Type    Reason                Age               From                         Message
       ----    ------                ----              ----                         -------
       Normal  ExternalProvisioning  9s (x6 over 84s)  persistentvolume-controller  waiting for a volume to be created, either by external provisioner "k8s-sigs.io/nfs-subdir-external-provisioner" or manually created by system administrator
    -

    消费PVC

    创建 Deployment mysql-with-sc-pvc 以使用 PVC nfs-pvc-from-sc

    kubectl apply -f - <<EOF
    +

    消费PVC

    创建 Deployment mysql-with-sc-pvc 以使用 PVC nfs-pvc-from-sc

    kubectl apply -f - <<EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -341,20 +341,20 @@
             persistentVolumeClaim:
               claimName: nfs-pvc-from-sc
     EOF
    -

    检查 Deployment mysql-with-sc-pvc 的状态。

    kubectl get deployment mysql-with-sc-pvc -o wide
    +

    检查 Deployment mysql-with-sc-pvc 的状态。

    kubectl get deployment mysql-with-sc-pvc -o wide
     

    运行结果:

    NAME                READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES      SELECTOR
     mysql-with-sc-pvc   1/1     1            1           16s   mysql        mysql:8.0   app=mysql
    -

    使用 Deployment mysql-with-sc-pvc 消费 PVC nfs-pvc-from-sc 后,PVC 的状态从 Pending 变为了 Bound

    kubectl get pvc nfs-pvc-from-sc
    +

    使用 Deployment mysql-with-sc-pvc 消费 PVC nfs-pvc-from-sc 后,PVC 的状态从 Pending 变为了 Bound

    kubectl get pvc nfs-pvc-from-sc
     

    运行结果:

    NAME              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
     nfs-pvc-from-sc   Bound    pvc-edf70dff-7407-4b38-aac9-9c2dd6a84316   1Gi        RWX            nfs-client     52m
    -

    检查相关 Pod 的状态。注意,Pod mysql-with-sc-pvc-7c97d875f8-dwfkc 运行在 cka003 上。

    kubectl get pod -o wide -l app=mysql
    +

    检查相关 Pod 的状态。注意,Pod mysql-with-sc-pvc-7c97d875f8-dwfkc 运行在 cka003 上。

    kubectl get pod -o wide -l app=mysql
     

    运行结果:

    NAME                                 READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
     mysql-774db46945-h82kk               1/1     Running   0          69m     10.244.112.26   cka002   <none>           <none>
     mysql-with-sc-pvc-7c97d875f8-wkvr9   1/1     Running   0          3m37s   10.244.102.27   cka003   <none>           <none>
    -

    我们现在来查看 NFS 服务器 cka002 上的共享目录 /nfsdata/

    ll /nfsdata/
    -

    NFS 服务器 cka002 上的共享目录 /nfsdata/ 下有了2个子目录,与其他2个节点上的目录 /remote-nfs-dir/ 下的内容是一致。

    drwxrwxrwx  6 systemd-coredump root 4096 Jul 23 23:35 dev/
    -drwxr-xr-x  6 systemd-coredump root 4096 Jul 23 22:29 mysqldata/
    -

    命名空间Namespace的名称作为目录名在 /nfsdata/ 目录下用于挂载到 Pod 中。 默认情况下,命名空间Namespace名称将用于挂载点。 如果我们想要使用自定义的文件夹来代替,我们需要声明一个 nfs.io/storage-path 注释,例如下面的例子。

    在命名空间 kube-system 上创建 PVC test-claim,并消费 nfs-client 卷。

    kubectl apply -f - <<EOF
    +

    我们现在来查看 NFS 服务器 cka002 上的共享目录 /nfsdata/

    ll /nfsdata/
    +

    NFS 服务器 cka002 上的共享目录 /nfsdata/ 下有了2个子目录,与其他2个节点上的目录 /remote-nfs-dir/ 下的内容是一致。

    drwxrwxrwx  6 systemd-coredump root 4096 Jul 23 23:35 dev/
    +drwxr-xr-x  6 systemd-coredump root 4096 Jul 23 22:29 mysqldata/
    +

    命名空间Namespace的名称作为目录名在 /nfsdata/ 目录下用于挂载到 Pod 中。 默认情况下,命名空间Namespace名称将用于挂载点。 如果我们想要使用自定义的文件夹来代替,我们需要声明一个 nfs.io/storage-path 注释,例如下面的例子。

    在命名空间 kube-system 上创建 PVC test-claim,并消费 nfs-client 卷。

    kubectl apply -f - <<EOF
     kind: PersistentVolumeClaim
     apiVersion: v1
     metadata:
    @@ -370,54 +370,54 @@
         requests:
           storage: 1Gi
     EOF
    -

    在上述情况下, PVC 创建在 kube-system 命名空间中,因此我们可以在节点 cka002 上的 kube-system 目录下看到 test-path 目录。

    执行下面的命令,来查看目录 /nfsdata/ 的整体目录结构。

    tree -L 1 /nfsdata/ 
    +

    在上述情况下, PVC 创建在 kube-system 命名空间中,因此我们可以在节点 cka002 上的 kube-system 目录下看到 test-path 目录。

    执行下面的命令,来查看目录 /nfsdata/ 的整体目录结构。

    tree -L 1 /nfsdata/ 
     

    运行结果:

    /nfsdata/
     ├── dev
     ├── kube-system
     └── mysqldata
    -

    注意:

    上述规则遵循了 nfs-subdir-external-provisioner 实现,可能与其他provisioner不同。

    参考:

    nfs-subdir-external-provisioner 项目的详细信息。

    配置Configuration

    ConfigMap

    创建 ConfigMap cm-nginx 来配置文件 nginx.conf

    vi configmap.yaml
    -

    把下面的内容粘贴到文件nginx.conf中。

    apiVersion: v1
    -kind: ConfigMap
    -metadata:
    -  labels:
    -    cattle.io/creator: norman
    -  name: cm-nginx
    -  namespace: dev
    -data:
    -  nginx.conf: |-
    -    user  nginx;
    -    worker_processes  2;
    +

    注意:

    上述规则遵循了 nfs-subdir-external-provisioner 实现,可能与其他provisioner不同。

    参考:

    nfs-subdir-external-provisioner 项目的详细信息。

    配置Configuration

    ConfigMap

    创建 ConfigMap cm-nginx 来配置文件 nginx.conf

    vi configmap.yaml
    +

    把下面的内容粘贴到文件nginx.conf中。

    apiVersion: v1
    +kind: ConfigMap
    +metadata:
    +  labels:
    +    cattle.io/creator: norman
    +  name: cm-nginx
    +  namespace: dev
    +data:
    +  nginx.conf: |-
    +    user  nginx;
    +    worker_processes  2;
     
    -    error_log  /var/log/nginx/error.log warn;
    -    pid        /var/run/nginx.pid;
    +    error_log  /var/log/nginx/error.log warn;
    +    pid        /var/run/nginx.pid;
     
     
    -    events {
    -        worker_connections  1024;
    -    }
    +    events {
    +        worker_connections  1024;
    +    }
     
     
    -    http {
    -        include       /etc/nginx/mime.types;
    -        default_type  application/octet-stream;
    +    http {
    +        include       /etc/nginx/mime.types;
    +        default_type  application/octet-stream;
     
    -        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    -                          '$status $body_bytes_sent "$http_referer" '
    -                          '"$http_user_agent" "$http_x_forwarded_for"';
    +        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    +                          '$status $body_bytes_sent "$http_referer" '
    +                          '"$http_user_agent" "$http_x_forwarded_for"';
     
    -        access_log  /var/log/nginx/access.log  main;
    +        access_log  /var/log/nginx/access.log  main;
     
    -        sendfile        on;
    -        #tcp_nopush     on;
    +        sendfile        on;
    +        #tcp_nopush     on;
     
    -        keepalive_timeout  65;
    +        keepalive_timeout  65;
     
    -        #gzip  on;
    +        #gzip  on;
     
    -        include /etc/nginx/conf.d/*.conf;
    -    }
    -

    应用文件configmap.yaml,创建ConfigMap。

    kubectl apply -f configmap.yaml
    -

    创建Pod nginx-with-cm

    kubectl apply -f - <<EOF
    +        include /etc/nginx/conf.d/*.conf;
    +    }
    +

    应用文件configmap.yaml,创建ConfigMap。

    kubectl apply -f configmap.yaml
    +

    创建Pod nginx-with-cm

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -435,14 +435,14 @@
        configMap:
          name: cm-nginx
     EOF
    -

    提示:

    • 默认情况下,要挂载 ConfigMap,Kubernetes 会覆盖挂载点的所有内容。我们可以使用 volumeMounts.subPath 来指定只覆盖在 mountPath 中定义的 nginx.conf 文件。
    • 如果我们使用 volumeMounts.subPath 来挂载一个容器卷,Kubernetes 将不会进行热更新以反映实时更新。

    把从外部挂载的 nginx.conf 文件和上面的文件进行比较,以验证它是否已经被加载到容器中。

    kubectl exec -it nginx-with-cm -- sh 
    -cat /etc/nginx/nginx.conf
    -

    Secret

    用base64方式编码密码。

    echo -n admin | base64  
    +

    提示:

    • 默认情况下,要挂载 ConfigMap,Kubernetes 会覆盖挂载点的所有内容。我们可以使用 volumeMounts.subPath 来指定只覆盖在 mountPath 中定义的 nginx.conf 文件。
    • 如果我们使用 volumeMounts.subPath 来挂载一个容器卷,Kubernetes 将不会进行热更新以反映实时更新。

    把从外部挂载的 nginx.conf 文件和上面的文件进行比较,以验证它是否已经被加载到容器中。

    kubectl exec -it nginx-with-cm -- sh 
    +cat /etc/nginx/nginx.conf
    +

    Secret

    用base64方式编码密码。

    echo -n admin | base64  
     YWRtaW4=
     
    -echo -n 123456 | base64
    +echo -n 123456 | base64
     MTIzNDU2
    -

    创建Secret mysecret

    kubectl apply -f - <<EOF
    +

    创建Secret mysecret

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Secret
     metadata:
    @@ -451,7 +451,7 @@
       username: YWRtaW4=
       password: MTIzNDU2
     EOF
    -

    使用卷将 Secret 挂载(注入,injection)到 Pod 中。

    kubectl apply -f - <<EOF
    +

    使用卷将 Secret 挂载(注入,injection)到 Pod 中。

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -472,25 +472,25 @@
        secret:
         secretName: mysecret
     EOF
    -

    让我们登录进入到Pod busybox-with-secret内部,以验证 mysecret 的两个数据元素(usernamepassword)是否已成功挂载到Pod中的路径 /tmp/secret

    kubectl exec -it busybox-with-secret -- sh
    -

    执行下面的命令,我们可以看到mysecret 的两个数据元素(usernamepassword)已经以文件形式存在于目录/tmp/secret下。

    / # ls -l /tmp/secret/
    -lrwxrwxrwx    1 root     root            15 Jul 23 16:30 password -> ..data/password
    -lrwxrwxrwx    1 root     root            15 Jul 23 16:30 username -> ..data/username
    -

    而且我们可以看到这2个数据元素(usernamepassword)的内容就是我们预先定义的。

    / # cat /tmp/secret/username
    +

    让我们登录进入到Pod busybox-with-secret内部,以验证 mysecret 的两个数据元素(usernamepassword)是否已成功挂载到Pod中的路径 /tmp/secret

    kubectl exec -it busybox-with-secret -- sh
    +

    执行下面的命令,我们可以看到mysecret 的两个数据元素(usernamepassword)已经以文件形式存在于目录/tmp/secret下。

    / # ls -l /tmp/secret/
    +lrwxrwxrwx    1 root     root            15 Jul 23 16:30 password -> ..data/password
    +lrwxrwxrwx    1 root     root            15 Jul 23 16:30 username -> ..data/username
    +

    而且我们可以看到这2个数据元素(usernamepassword)的内容就是我们预先定义的。

    / # cat /tmp/secret/username
     admin
     
    -/ # cat /tmp/secret/password
    +/ # cat /tmp/secret/password
     123456
    -

    拓展案例

    多种方法创建ConfigMap

    我们可以通过文件、目录、或者值来创建ConfigMap。

    下面我们创建ConfigMap colors,包含:

    • 四个文件,文件名是四个颜色。
    • 一个文件,文件名是最喜欢的颜色。
    mkdir configmap
    -cd configmap
    -mkdir primary
    +

    拓展案例

    多种方法创建ConfigMap

    我们可以通过文件、目录、或者值来创建ConfigMap。

    下面我们创建ConfigMap colors,包含:

    • 四个文件,文件名是四个颜色。
    • 一个文件,文件名是最喜欢的颜色。
    mkdir configmap
    +cd configmap
    +mkdir primary
     
    -echo c > primary/cyan
    -echo m > primary/magenta
    -echo y > primary/yellow
    -echo k > primary/black
    -echo "known as key" >> primary/black
    -echo blue > favorite
    +echo c > primary/cyan
    +echo m > primary/magenta
    +echo y > primary/yellow
    +echo k > primary/black
    +echo "known as key" >> primary/black
    +echo blue > favorite
     

    执行命令tree configmap,可以看到类似下面的文件目录结构。

    configmap
     ├── favorite
     └── primary
    @@ -498,32 +498,32 @@
         ├── cyan
         ├── magenta
         └── yellow
    -

    创建一个 ConfigMap,引用上面我们创建的文件。确保我们现在在路径 ~/configmap 下。

    kubectl create configmap colors \
    ---from-literal=text=black  \
    ---from-file=./favorite  \
    +

    创建一个 ConfigMap,引用上面我们创建的文件。确保我们现在在路径 ~/configmap 下。

    kubectl create configmap colors \
    +--from-literal=text=black  \
    +--from-file=./favorite  \
     --from-file=./primary/
    -

    查看ConfigMap colors的内容。

    kubectl get configmap colors -o yaml
    -

    运行结果:

    apiVersion: v1
    +

    查看ConfigMap colors的内容。

    kubectl get configmap colors -o yaml
    +

    运行结果:

    apiVersion: v1
     data:
    -  black: |
    -    k
    -    known as key
    -  cyan: |
    -    c
    -  favorite: |
    -    blue
    -  magenta: |
    -    m
    -  text: black
    -  yellow: |
    -    y
    -kind: ConfigMap
    +  black: |
    +    k
    +    known as key
    +  cyan: |
    +    c
    +  favorite: |
    +    blue
    +  magenta: |
    +    m
    +  text: black
    +  yellow: |
    +    y
    +kind: ConfigMap
     metadata:
    -  creationTimestamp: "2022-07-12T16:38:27Z"
    -  name: colors
    -  namespace: dev
    -  resourceVersion: "2377258"
    -  uid: d5ab133f-5e4d-41d4-bc9e-2bbb22a872a1
    +  creationTimestamp: "2022-07-12T16:38:27Z"
    +  name: colors
    +  namespace: dev
    +  resourceVersion: "2377258"
    +  uid: d5ab133f-5e4d-41d4-bc9e-2bbb22a872a1
     

    通过ConfigMap设定环境变量

    继续上面的例子,现在我们准备创建一个名为pod-configmap-env的Pod,设置环境变量ilike并从ConfigMap colors中分配值favorite

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Pod
    @@ -540,10 +540,10 @@
               name: colors
               key: favorite
     EOF
    -

    连接并进入Pod pod-configmap-env内部。

    kubectl exec -it pod-configmap-env -- bash
    -

    验证环境变量 ilike 的值是 blue,这是 ConfigMap colorsfavorite 值。

    root@pod-configmap-env:/# echo $ilike
    +

    连接并进入Pod pod-configmap-env内部。

    kubectl exec -it pod-configmap-env -- bash
    +

    验证环境变量 ilike 的值是 blue,这是 ConfigMap colorsfavorite 值。

    root@pod-configmap-env:/# echo $ilike
     blue
    -

    我们还可以使用 ConfigMap 的所有键值对来设置 Pod 的环境变量。

    kubectl apply -f - << EOF
    +

    我们还可以使用 ConfigMap 的所有键值对来设置 Pod 的环境变量。

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -556,11 +556,11 @@
         - configMapRef:
             name: colors
     EOF
    -

    连接并进入Pod pod-configmap-env-2内部。

    kubectl exec -it pod-configmap-env-2 -- bash
    -

    验证环境变量的值是我们在ConfigMap colors所定义的键值对。

    root@pod-configmap-env-2:/# echo $black
    -k known as key
    -root@pod-configmap-env-2:/# echo $cyan
    +

    连接并进入Pod pod-configmap-env-2内部。

    kubectl exec -it pod-configmap-env-2 -- bash
    +

    验证环境变量的值是我们在ConfigMap colors所定义的键值对。

    root@pod-configmap-env-2:/# echo $black
    +k known as key
    +root@pod-configmap-env-2:/# echo $cyan
     c
    -root@pod-configmap-env-2:/# echo $favorite
    +root@pod-configmap-env-2:/# echo $favorite
     blue
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/pod/index.html b/k8s/cka_cn/foundamentals/pod/index.html index 11e21f34..4262a6ff 100644 --- a/k8s/cka_cn/foundamentals/pod/index.html +++ b/k8s/cka_cn/foundamentals/pod/index.html @@ -1,4 +1,4 @@ - Pod - UPSkilling

    CKA自学笔记8:Pod

    摘要

    练习目标:

    • 创建pod
    • 追踪pod
    • pod标签
    • 静态pod
    • 多容器pod
    • 含初始化容器的pod

    创建Pod

    创建Pod my-first-podl

    kubectl apply -f - << EOF
    + Pod - UPSkilling       

    CKA自学笔记8:Pod

    摘要

    练习目标:

    • 创建pod
    • 追踪pod
    • pod标签
    • 静态pod
    • 多容器pod
    • 含初始化容器的pod

    创建Pod

    创建Pod my-first-podl

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -10,58 +10,58 @@
         ports:
         - containerPort: 80
     EOF
    -

    验证刚刚创建的pod的状态。

    kubectl get pods -o wide
    -

    追踪pod

    检查刚刚创建的pod的日志。

    kubectl logs my-first-pod
    -

    如果日志或者其他命令输出的信息不足以帮助我们查找根本原因,我们可以通过kubectl exec -it <my-pod> -- bash来进入pod内部进行分析。

    kubectl exec -it my-first-pod -- bash
    -root@my-first-pod:/# ls
    -root@my-first-pod:/# cd bin
    -root@my-first-pod:/bin# ls
    -root@my-first-pod:/bin# exit
    -

    执行命令kubectl explain pod.spec可以得到pod对应的yaml文件中Spec区段的内容。

    我们可以查看 Pod 资源的官方 API 参考文档,或者使用 kubectl explain pod 命令行获取该资源的描述信息。通过在资源类型后添加 .<field>,explain 命令会提供该指定字段的更多详细信息。

    kubectl explain pod.kind
    -kubectl explain pod.spec
    -kubectl explain pod.spec.containers
    -kubectl explain pod.spec.containers.name
    -

    pod的标签

    通过选项 --show-labels来获得pod的标签。

    kubectl get pods
    -kubectl get pods --show-labels
    -

    给pod pod my-first-pod添加2个标签。

    kubectl label pod my-first-pod nginx=mainline
    -kubectl label pod my-first-pod env=demo
    -kubectl get pods --show-labels
    -

    通过标签来查找pod。

    kubectl get pod -l env=demo
    -kubectl get pod -l env=demo,nginx=mainline
    -kubectl get pod -l env=training
    -

    移除pod的标签。

    kubectl label pods my-first-pod env-
    -kubectl get pods --show-labels
    -

    描述 Pod。

    kubectl describe pod my-first-pod
    -

    删除pod. 运行命令 watch kubectl get pods 来获取pod的状态。

    kubectl delete pod my-first-pod
    -watch kubectl get pods
    -

    静态pod

    演示场景:

    • 创建一个静态pod。

    • kubectl 会自动检查 /etc/kubernetes/manifests/ 中的 YAML 文件,并在检测到后创建静态 Pod。

    演示:

    查看系统初始化后已经存在的静态pod。

    ll /etc/kubernetes/manifests/
    +

    验证刚刚创建的pod的状态。

    kubectl get pods -o wide
    +

    追踪pod

    检查刚刚创建的pod的日志。

    kubectl logs my-first-pod
    +

    如果日志或者其他命令输出的信息不足以帮助我们查找根本原因,我们可以通过kubectl exec -it <my-pod> -- bash来进入pod内部进行分析。

    kubectl exec -it my-first-pod -- bash
    +root@my-first-pod:/# ls
    +root@my-first-pod:/# cd bin
    +root@my-first-pod:/bin# ls
    +root@my-first-pod:/bin# exit
    +

    执行命令kubectl explain pod.spec可以得到pod对应的yaml文件中Spec区段的内容。

    我们可以查看 Pod 资源的官方 API 参考文档,或者使用 kubectl explain pod 命令行获取该资源的描述信息。通过在资源类型后添加 .<field>,explain 命令会提供该指定字段的更多详细信息。

    kubectl explain pod.kind
    +kubectl explain pod.spec
    +kubectl explain pod.spec.containers
    +kubectl explain pod.spec.containers.name
    +

    pod的标签

    通过选项 --show-labels来获得pod的标签。

    kubectl get pods
    +kubectl get pods --show-labels
    +

    给pod pod my-first-pod添加2个标签。

    kubectl label pod my-first-pod nginx=mainline
    +kubectl label pod my-first-pod env=demo
    +kubectl get pods --show-labels
    +

    通过标签来查找pod。

    kubectl get pod -l env=demo
    +kubectl get pod -l env=demo,nginx=mainline
    +kubectl get pod -l env=training
    +

    移除pod的标签。

    kubectl label pods my-first-pod env-
    +kubectl get pods --show-labels
    +

    描述 Pod。

    kubectl describe pod my-first-pod
    +

    删除pod. 运行命令 watch kubectl get pods 来获取pod的状态。

    kubectl delete pod my-first-pod
    +watch kubectl get pods
    +

    静态pod

    演示场景:

    • 创建一个静态pod。

    • kubectl 会自动检查 /etc/kubernetes/manifests/ 中的 YAML 文件,并在检测到后创建静态 Pod。

    演示:

    查看系统初始化后已经存在的静态pod。

    ll /etc/kubernetes/manifests/
     

    运行结果:

    -rw------- 1 root root 2292 Jul 23 10:45 etcd.yaml
     -rw------- 1 root root 3889 Jul 23 10:45 kube-apiserver.yaml
     -rw------- 1 root root 3395 Jul 23 10:45 kube-controller-manager.yaml
     -rw------- 1 root root 1464 Jul 23 10:45 kube-scheduler.yaml
    -

    /etc/kubernetes/manifests/目录中创建yaml文件my-nginx.yaml,一旦文件创建完成,静态Pod my-nginx 将会被自动创建。

    kubectl run my-nginx --image=nginx:mainline --dry-run=client -n default -oyaml | sudo tee /etc/kubernetes/manifests/my-nginx.yaml
    -

    检查 Pod my-nginx 的状态。Pod 名称中包含节点名称 cka001,这意味着该 Pod 正在节点 cka001 上运行。

    kubectl get pod -o wide
    +

    /etc/kubernetes/manifests/目录中创建yaml文件my-nginx.yaml,一旦文件创建完成,静态Pod my-nginx 将会被自动创建。

    kubectl run my-nginx --image=nginx:mainline --dry-run=client -n default -oyaml | sudo tee /etc/kubernetes/manifests/my-nginx.yaml
    +

    检查 Pod my-nginx 的状态。Pod 名称中包含节点名称 cka001,这意味着该 Pod 正在节点 cka001 上运行。

    kubectl get pod -o wide
     

    运行结果:

    NAME              READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
     my-nginx-cka001   1/1     Running   0          20s   10.244.228.196   cka001   <none>           <none>
    -

    删除 /etc/kubernetes/manifests/my-nginx.yaml 这个 yaml 文件,对应的静态 Pod my-nginx 将会被自动删除。

    sudo rm /etc/kubernetes/manifests/my-nginx.yaml 
    -

    多容器Pod

    演示场景:

    • 创建多容器Pod
    • 描述该Pod
    • 检查Pod的日志
    • 检查容器的日志

    演示:

    创建一个名为multi-container-pod的Pod,包含多个容器:container-1-nginxcontainer-2-alpine

    kubectl apply -f - << EOF
    -apiVersion: v1
    -kind: Pod
    -metadata:
    -  name: multi-container-pod
    -spec:
    -  containers:
    -  - name: container-1-nginx
    -    image: nginx
    -    ports:
    +

    删除 /etc/kubernetes/manifests/my-nginx.yaml 这个 yaml 文件,对应的静态 Pod my-nginx 将会被自动删除。

    sudo rm /etc/kubernetes/manifests/my-nginx.yaml 
    +

    多容器Pod

    演示场景:

    • 创建多容器Pod
    • 描述该Pod
    • 检查Pod的日志
    • 检查容器的日志

    演示:

    创建一个名为multi-container-pod的Pod,包含多个容器:container-1-nginxcontainer-2-alpine

    kubectl apply -f - << EOF
    +apiVersion: v1
    +kind: Pod
    +metadata:
    +  name: multi-container-pod
    +spec:
    +  containers:
    +  - name: container-1-nginx
    +    image: nginx
    +    ports:
         - containerPort: 80  
    -  - name: container-2-alpine
    -    image: alpine
    -    command: ["watch", "wget", "-qO-", "localhost"]
    -EOF
    -

    获取pod状态。

    kubectl get pod multi-container-pod
    +  - name: container-2-alpine
    +    image: alpine
    +    command: ["watch", "wget", "-qO-", "localhost"]
    +EOF
    +

    获取pod状态。

    kubectl get pod multi-container-pod
     

    运行结果

    
    -

    获取pod的详细信息。

    kubectl describe pod multi-container-pod
    +

    获取pod的详细信息。

    kubectl describe pod multi-container-pod
     

    运行结果:

    .......
     Events:
       Type    Reason     Age   From               Message
    @@ -75,29 +75,29 @@
       Normal  Pulled     14s   kubelet            Successfully pulled image "alpine" in 7.776104353s
       Normal  Created    14s   kubelet            Created container container-2-alpine
       Normal  Started    14s   kubelet            Started container container-2-alpine
    -

    对于多容器 Pod,如果我们想通过命令 kubectl logs <pod_name> <container_name> 获取 Pod 的日志,需要指定容器名称。如果不指定容器名称,将会收到错误信息。

    kubectl logs multi-container-pod
    -

    运行结果

    error: a container name must be specified for pod multi-container-pod, choose one of: [container-1-nginx container-2-alpine]
    -

    指定容器名称,我们可以得到对应的日志信息。

    kubectl logs multi-container-pod container-1-nginx
    +

    对于多容器 Pod,如果我们想通过命令 kubectl logs <pod_name> <container_name> 获取 Pod 的日志,需要指定容器名称。如果不指定容器名称,将会收到错误信息。

    kubectl logs multi-container-pod
    +

    运行结果

    error: a container name must be specified for pod multi-container-pod, choose one of: [container-1-nginx container-2-alpine]
    +

    指定容器名称,我们可以得到对应的日志信息。

    kubectl logs multi-container-pod container-1-nginx
     

    运行结果

    ......
    -::1 - - [23/Jul/2022:04:06:37 +0000] "GET / HTTP/1.1" 200 615 "-" "Wget" "-"
    -

    如果我们需要使用命令 kubectl exec -it <pod_name> -c <container_name> -- <commands> 登录到 Pod 中,同样需要指定容器名称。如果没有指定容器名称,会出现错误。

    kubectl exec -it multi-container-pod -c container-1-nginx -- /bin/bash
    -root@multi-container-pod:/# ls
    -

    删除上面练习中创建的pod。

    kubectl delete pod multi-container-pod
    -

    下面是一个基本的yaml文件用来创建多容器pod。

    kubectl apply -f - << EOF
    -apiVersion: v1
    -kind: Pod
    -metadata:
    -  name: my-multi-pod
    -spec:
    -  containers:
    -  - image: nginx
    -    name: nginx
    -  - image: memcached
    -    name: memcached
    -  - image: redis
    -    name: redis
    -EOF
    -

    演示场景:

    • 创建一个名为my-busybox的Pod,并在其中添加一个名为container-1-busybox的容器。该容器将把消息写入到文件/var/log/my-pod-busybox.log中。
    • 向Pod my-busybox中添加另一个容器container-2-busybox(Sidecar)。Sidecar容器从文件/var/log/my-pod-busybox.log中读取消息。
    • 提示:创建一个Volume来存储日志文件,并与两个容器共享。

    演示:

    创建一个名为 my-busybox 的 Pod,其中包含一个容器 container-1-busybox

    kubectl apply -f - << EOF
    +::1 - - [23/Jul/2022:04:06:37 +0000] "GET / HTTP/1.1" 200 615 "-" "Wget" "-"
    +

    如果我们需要使用命令 kubectl exec -it <pod_name> -c <container_name> -- <commands> 登录到 Pod 中,同样需要指定容器名称。如果没有指定容器名称,会出现错误。

    kubectl exec -it multi-container-pod -c container-1-nginx -- /bin/bash
    +root@multi-container-pod:/# ls
    +

    删除上面练习中创建的pod。

    kubectl delete pod multi-container-pod
    +

    下面是一个基本的yaml文件用来创建多容器pod。

    kubectl apply -f - << EOF
    +apiVersion: v1
    +kind: Pod
    +metadata:
    +  name: my-multi-pod
    +spec:
    +  containers:
    +  - image: nginx
    +    name: nginx
    +  - image: memcached
    +    name: memcached
    +  - image: redis
    +    name: redis
    +EOF
    +

    演示场景:

    • 创建一个名为my-busybox的Pod,并在其中添加一个名为container-1-busybox的容器。该容器将把消息写入到文件/var/log/my-pod-busybox.log中。
    • 向Pod my-busybox中添加另一个容器container-2-busybox(Sidecar)。Sidecar容器从文件/var/log/my-pod-busybox.log中读取消息。
    • 提示:创建一个Volume来存储日志文件,并与两个容器共享。

    演示:

    创建一个名为 my-busybox 的 Pod,其中包含一个容器 container-1-busybox

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -118,159 +118,159 @@
             sleep 1;
           done
     EOF
    -

    在 Kubernetes 文档中搜索 emptyDir。 参考以下模板用于 emptyDirhttps://kubernetes.io/zh-cn/docs/concepts/storage/volumes/

    将以下新功能添加到 Pod 中:

    • Volume:
    • 卷名称:logfile
    • 类型:emptyDir
    • 更新现有容器:
    • name: container-1-busybox
    • volumeMounts
      • name: logfile
      • mounthPath: /var/log
    • 添加新容器:
    • name: container-2-busybox
    • image: busybox
    • args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log']
    • volumeMounts:
      • name: logfile
      • mountPath: /var/log
    kubectl get pod my-busybox -o yaml > my-busybox.yaml
    -vi my-busybox.yaml
    -kubectl delete pod my-busybox 
    -kubectl apply -f my-busybox.yaml
    -kubectl logs my-busybox -c container-2-busybox
    -

    更新后的文件my-busybox.yaml如下:

    apiVersion: v1
    -kind: Pod
    -metadata:
    -  annotations:
    -    cni.projectcalico.org/containerID: 89644b6b073cd152f94b4cae7bdea6bbc3292cf59afd4f28102bd74f0205c9e4
    -    cni.projectcalico.org/podIP: 10.244.102.20/32
    -    cni.projectcalico.org/podIPs: 10.244.102.20/32
    -    kubectl.kubernetes.io/last-applied-configuration: |
    -      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"my-busybox","namespace":"dev"},"spec":{"containers":[{"args":["/bin/sh","-c","i=0; while true; do\n  echo \"Hello message from container-1: \" \u003e\u003e /var/log/my-pod-busybox.log;\n  i=1;\n  sleep 1;\ndone\n"],"image":"busybox","name":"container-1-busybox"}]}}
    -  creationTimestamp: "2022-07-29T22:58:27Z"
    -  name: my-busybox
    -  namespace: dev
    -  resourceVersion: "1185720"
    -  uid: c5e62a16-4459-4828-a441-7d1471b89a56
    -spec:
    -  containers:
    -  - name: container-2-busybox
    -    image: busybox
    -    args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log']
    -    volumeMounts:
    -    - name: logfile
    -      mountPath: /var/log
    -  - args:
    -    - /bin/sh
    -    - -c
    -    - |
    -      i=0; while true; do
    -        echo "Hello message from container-1: $i" >> /var/log/my-pod-busybox.log;
    -        i=1;
    -        sleep 1;
    -      done
    -    image: busybox
    -    imagePullPolicy: Always
    -    name: container-1-busybox
    -    resources: {}
    -    terminationMessagePath: /dev/termination-log
    -    terminationMessagePolicy: File
    -    volumeMounts:
    -    - name: logfile
    -      mountPath: /var/log
    -    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
    -      name: kube-api-access-mhxlf
    -      readOnly: true
    -  dnsPolicy: ClusterFirst
    -  enableServiceLinks: true
    -  nodeName: cka003
    -  preemptionPolicy: PreemptLowerPriority
    -  priority: 0
    -  restartPolicy: Always
    -  schedulerName: default-scheduler
    -  securityContext: {}
    -  serviceAccount: default
    -  serviceAccountName: default
    -  terminationGracePeriodSeconds: 30
    -  tolerations:
    -  - effect: NoExecute
    -    key: node.kubernetes.io/not-ready
    -    operator: Exists
    -    tolerationSeconds: 300
    -  - effect: NoExecute
    -    key: node.kubernetes.io/unreachable
    -    operator: Exists
    -    tolerationSeconds: 300
    -  volumes:
    -  - name: logfile
    -    emptyDir: {}
    -  - name: kube-api-access-mhxlf
    -    projected:
    -      defaultMode: 420
    -      sources:
    -      - serviceAccountToken:
    -          expirationSeconds: 3607
    -          path: token
    -      - configMap:
    -          items:
    -          - key: ca.crt
    -            path: ca.crt
    -          name: kube-root-ca.crt
    -      - downwardAPI:
    -          items:
    -          - fieldRef:
    -              apiVersion: v1
    -              fieldPath: metadata.namespace
    -            path: namespace
    -status:
    -  conditions:
    -  - lastProbeTime: null
    -    lastTransitionTime: "2022-07-29T22:58:27Z"
    -    status: "True"
    -    type: Initialized
    -  - lastProbeTime: null
    -    lastTransitionTime: "2022-07-29T22:58:30Z"
    -    status: "True"
    -    type: Ready
    -  - lastProbeTime: null
    -    lastTransitionTime: "2022-07-29T22:58:30Z"
    -    status: "True"
    -    type: ContainersReady
    -  - lastProbeTime: null
    -    lastTransitionTime: "2022-07-29T22:58:27Z"
    -    status: "True"
    -    type: PodScheduled
    -  containerStatuses:
    -  - containerID: containerd://fd42d4ba4d94d8918d8846327b1db2328be13c5f93f381877ff0228ed7b5468d
    -    image: docker.io/library/busybox:latest
    -    imageID: docker.io/library/busybox@sha256:0e97a8ca6955f22dbc7db9e9dbe970971f423541e52c34b8cb96ccc88d6a3883
    -    lastState: {}
    -    name: container-1-busybox
    -    ready: true
    -    restartCount: 0
    -    started: true
    -    state:
    -      running:
    -        startedAt: "2022-07-29T22:58:30Z"
    -  hostIP: <cka003_ip>
    -  phase: Running
    -  podIP: 10.244.102.20
    -  podIPs:
    -  - ip: 10.244.102.20
    -  qosClass: BestEffort
    -  startTime: "2022-07-29T22:58:27Z"
    -

    清理上面练习中创建的pod。

    kubectl delete pod my-busybox
    -

    含初始化容器Pod

    演示场景:

    • 创建拥有两个初始化容器的 Pod myapp-pod
    • myapp-container
    • init-mydb
    • 创建两个服务:
    • myservice
    • mydb

    演示预期结论:

    • myapp-container等待服务myservice启动,以解析名称myservice.dev.svc.cluster.local
    • init-mydb等待服务mydb启动,以解析名称mydb.dev.svc.cluster.local

    演示:

    创建名为myapp-pod.yaml的yaml文件,并添加以下内容。 注意:由于命令$(cat /var/.....将被视为主机变量,因此我们不能使用echo生成该文件。它是容器本身的变量。

    vi myapp-pod.yaml
    -

    文件内容

    apiVersion: v1
    -kind: Pod
    -metadata:
    -  name: myapp-pod
    -  labels:
    -    app: myapp
    -spec:
    -  containers:
    -  - name: myapp-container
    -    image: busybox:1.28
    -    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
    -  initContainers:
    -  - name: init-myservice
    -    image: busybox:1.28
    -    command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
    -  - name: init-mydb
    -    image: busybox:1.28
    -    command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
    -

    用上面创建的yaml文件创建Pod myapp-pod

    kubectl apply -f myapp-pod.yaml
    -

    检查pod的状态。

    kubectl get pod myapp-pod
    +

    在 Kubernetes 文档中搜索 emptyDir。 参考以下模板用于 emptyDirhttps://kubernetes.io/zh-cn/docs/concepts/storage/volumes/

    将以下新功能添加到 Pod 中:

    • Volume:
    • 卷名称:logfile
    • 类型:emptyDir
    • 更新现有容器:
    • name: container-1-busybox
    • volumeMounts
      • name: logfile
      • mounthPath: /var/log
    • 添加新容器:
    • name: container-2-busybox
    • image: busybox
    • args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log']
    • volumeMounts:
      • name: logfile
      • mountPath: /var/log
    kubectl get pod my-busybox -o yaml > my-busybox.yaml
    +vi my-busybox.yaml
    +kubectl delete pod my-busybox 
    +kubectl apply -f my-busybox.yaml
    +kubectl logs my-busybox -c container-2-busybox
    +

    更新后的文件my-busybox.yaml如下:

    apiVersion: v1
    +kind: Pod
    +metadata:
    +  annotations:
    +    cni.projectcalico.org/containerID: 89644b6b073cd152f94b4cae7bdea6bbc3292cf59afd4f28102bd74f0205c9e4
    +    cni.projectcalico.org/podIP: 10.244.102.20/32
    +    cni.projectcalico.org/podIPs: 10.244.102.20/32
    +    kubectl.kubernetes.io/last-applied-configuration: |
    +      {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"my-busybox","namespace":"dev"},"spec":{"containers":[{"args":["/bin/sh","-c","i=0; while true; do\n  echo \"Hello message from container-1: \" \u003e\u003e /var/log/my-pod-busybox.log;\n  i=1;\n  sleep 1;\ndone\n"],"image":"busybox","name":"container-1-busybox"}]}}
    +  creationTimestamp: "2022-07-29T22:58:27Z"
    +  name: my-busybox
    +  namespace: dev
    +  resourceVersion: "1185720"
    +  uid: c5e62a16-4459-4828-a441-7d1471b89a56
    +spec:
    +  containers:
    +  - name: container-2-busybox
    +    image: busybox
    +    args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log']
    +    volumeMounts:
    +    - name: logfile
    +      mountPath: /var/log
    +  - args:
    +    - /bin/sh
    +    - -c
    +    - |
    +      i=0; while true; do
    +        echo "Hello message from container-1: $i" >> /var/log/my-pod-busybox.log;
    +        i=1;
    +        sleep 1;
    +      done
    +    image: busybox
    +    imagePullPolicy: Always
    +    name: container-1-busybox
    +    resources: {}
    +    terminationMessagePath: /dev/termination-log
    +    terminationMessagePolicy: File
    +    volumeMounts:
    +    - name: logfile
    +      mountPath: /var/log
    +    - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
    +      name: kube-api-access-mhxlf
    +      readOnly: true
    +  dnsPolicy: ClusterFirst
    +  enableServiceLinks: true
    +  nodeName: cka003
    +  preemptionPolicy: PreemptLowerPriority
    +  priority: 0
    +  restartPolicy: Always
    +  schedulerName: default-scheduler
    +  securityContext: {}
    +  serviceAccount: default
    +  serviceAccountName: default
    +  terminationGracePeriodSeconds: 30
    +  tolerations:
    +  - effect: NoExecute
    +    key: node.kubernetes.io/not-ready
    +    operator: Exists
    +    tolerationSeconds: 300
    +  - effect: NoExecute
    +    key: node.kubernetes.io/unreachable
    +    operator: Exists
    +    tolerationSeconds: 300
    +  volumes:
    +  - name: logfile
    +    emptyDir: {}
    +  - name: kube-api-access-mhxlf
    +    projected:
    +      defaultMode: 420
    +      sources:
    +      - serviceAccountToken:
    +          expirationSeconds: 3607
    +          path: token
    +      - configMap:
    +          items:
    +          - key: ca.crt
    +            path: ca.crt
    +          name: kube-root-ca.crt
    +      - downwardAPI:
    +          items:
    +          - fieldRef:
    +              apiVersion: v1
    +              fieldPath: metadata.namespace
    +            path: namespace
    +status:
    +  conditions:
    +  - lastProbeTime: null
    +    lastTransitionTime: "2022-07-29T22:58:27Z"
    +    status: "True"
    +    type: Initialized
    +  - lastProbeTime: null
    +    lastTransitionTime: "2022-07-29T22:58:30Z"
    +    status: "True"
    +    type: Ready
    +  - lastProbeTime: null
    +    lastTransitionTime: "2022-07-29T22:58:30Z"
    +    status: "True"
    +    type: ContainersReady
    +  - lastProbeTime: null
    +    lastTransitionTime: "2022-07-29T22:58:27Z"
    +    status: "True"
    +    type: PodScheduled
    +  containerStatuses:
    +  - containerID: containerd://fd42d4ba4d94d8918d8846327b1db2328be13c5f93f381877ff0228ed7b5468d
    +    image: docker.io/library/busybox:latest
    +    imageID: docker.io/library/busybox@sha256:0e97a8ca6955f22dbc7db9e9dbe970971f423541e52c34b8cb96ccc88d6a3883
    +    lastState: {}
    +    name: container-1-busybox
    +    ready: true
    +    restartCount: 0
    +    started: true
    +    state:
    +      running:
    +        startedAt: "2022-07-29T22:58:30Z"
    +  hostIP: <cka003_ip>
    +  phase: Running
    +  podIP: 10.244.102.20
    +  podIPs:
    +  - ip: 10.244.102.20
    +  qosClass: BestEffort
    +  startTime: "2022-07-29T22:58:27Z"
    +

    清理上面练习中创建的pod。

    kubectl delete pod my-busybox
    +

    含初始化容器Pod

    演示场景:

    • 创建拥有两个初始化容器的 Pod myapp-pod
    • myapp-container
    • init-mydb
    • 创建两个服务:
    • myservice
    • mydb

    演示预期结论:

    • myapp-container等待服务myservice启动,以解析名称myservice.dev.svc.cluster.local
    • init-mydb等待服务mydb启动,以解析名称mydb.dev.svc.cluster.local

    演示:

    创建名为myapp-pod.yaml的yaml文件,并添加以下内容。 注意:由于命令$(cat /var/.....将被视为主机变量,因此我们不能使用echo生成该文件。它是容器本身的变量。

    vi myapp-pod.yaml
    +

    文件内容

    apiVersion: v1
    +kind: Pod
    +metadata:
    +  name: myapp-pod
    +  labels:
    +    app: myapp
    +spec:
    +  containers:
    +  - name: myapp-container
    +    image: busybox:1.28
    +    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
    +  initContainers:
    +  - name: init-myservice
    +    image: busybox:1.28
    +    command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
    +  - name: init-mydb
    +    image: busybox:1.28
    +    command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
    +

    用上面创建的yaml文件创建Pod myapp-pod

    kubectl apply -f myapp-pod.yaml
    +

    检查pod的状态。

    kubectl get pod myapp-pod
     

    运行结果:

    NAME        READY   STATUS     RESTARTS   AGE
     myapp-pod   0/1     Init:0/2   0          12m
    -

    检查Pod,可以看到两个错误:

    • nslookup: 无法解析'myservice.dev.svc.cluster.local'
    • Pod "myapp-pod"中的容器“init-mydb”正在等待启动:PodInitializing
    kubectl logs myapp-pod -c init-myservice # Inspect the first init container
    -kubectl logs myapp-pod -c init-mydb      # Inspect the second init container
    -

    在这个时候,这些 init 容器将等待发现名为 mydbmyservice 的服务。

    创建 mydbmyservice 服务:

    kubectl apply -f - << EOF
    +

    检查Pod,可以看到两个错误:

    • nslookup: 无法解析'myservice.dev.svc.cluster.local'
    • Pod "myapp-pod"中的容器“init-mydb”正在等待启动:PodInitializing
    kubectl logs myapp-pod -c init-myservice # Inspect the first init container
    +kubectl logs myapp-pod -c init-mydb      # Inspect the second init container
    +

    在这个时候,这些 init 容器将等待发现名为 mydbmyservice 的服务。

    创建 mydbmyservice 服务:

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Service
     metadata:
    @@ -291,13 +291,13 @@
         port: 80
         targetPort: 9377
     EOF
    -

    查看创建的服务的状态。

    kubectl get service
    +

    查看创建的服务的状态。

    kubectl get service
     

    创建的2个服务都是运行状态。

    NAME        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
     mydb        ClusterIP   11.244.239.149   <none>        80/TCP    6s
     myservice   ClusterIP   11.244.116.126   <none>        80/TCP    6s
    -

    再次查看pod的状态。

    kubectl get pod myapp-pod -o wide
    +

    再次查看pod的状态。

    kubectl get pod myapp-pod -o wide
     

    pod已经正常运行了。

    NAME        READY   STATUS     RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
     myapp-pod   0/1     Init:0/2   0          2m40s   10.244.112.2   cka002   <none>           <none>
    -

    现在我们可以看到那些初始化容器都已经完成,myapp-pod Pod 进入了 Running 状态。

    删除上面练习中创建的pod。

    kubectl delete service mydb myservice 
    -kubectl delete pod myapp-pod 
    -

    参考:

    \ No newline at end of file +

    现在我们可以看到那些初始化容器都已经完成,myapp-pod Pod 进入了 Running 状态。

    删除上面练习中创建的pod。

    kubectl delete service mydb myservice 
    +kubectl delete pod myapp-pod 
    +

    参考:

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/policy/index.html b/k8s/cka_cn/foundamentals/policy/index.html index c767b218..9b920995 100644 --- a/k8s/cka_cn/foundamentals/policy/index.html +++ b/k8s/cka_cn/foundamentals/policy/index.html @@ -1,5 +1,5 @@ - Policy - UPSkilling

    CKA自学笔记22:Policy

    ResourceQuota

    演示场景:

    • 为namespace quota-object-example 创建资源配额ResourceQuota object-quota-demo
    • 为 NodePort 测试 ResourceQuota object-quota-demo
    • 为 PVC 测试 ResourceQuota object-quota-demo

    Create Namespace

    创建Namespace。

    kubectl create ns quota-object-example
    -

    创建ResourceQuota

    为namespace quota-object-example 创建资源配额ResourceQuota object-quota-demo。 在该namespace中,我们只能创建 1 个永久卷PVC、1 个负载均衡LoadBalancer服务,不能创建 NodePort 服务。

    kubectl apply -f - <<EOF
    + Policy - UPSkilling       

    CKA自学笔记22:Policy

    ResourceQuota

    演示场景:

    • 为namespace quota-object-example 创建资源配额ResourceQuota object-quota-demo
    • 为 NodePort 测试 ResourceQuota object-quota-demo
    • 为 PVC 测试 ResourceQuota object-quota-demo

    Create Namespace

    创建Namespace。

    kubectl create ns quota-object-example
    +

    创建ResourceQuota

    为namespace quota-object-example 创建资源配额ResourceQuota object-quota-demo。 在该namespace中,我们只能创建 1 个永久卷PVC、1 个负载均衡LoadBalancer服务,不能创建 NodePort 服务。

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: ResourceQuota
     metadata:
    @@ -11,25 +11,25 @@
         services.loadbalancers: "2"
         services.nodeports: "0"
     EOF
    -

    检查配额

    kubectl get resourcequota object-quota-demo --namespace=quota-object-example --output=yaml
    -

    主要信息摘录如下:

    spec:
    -  hard:
    -    persistentvolumeclaims: "1"
    -    services.loadbalancers: "2"
    -    services.nodeports: "0"
    -status:
    -  hard:
    -    persistentvolumeclaims: "1"
    -    services.loadbalancers: "2"
    -    services.nodeports: "0"
    -  used:
    -    persistentvolumeclaims: "0"
    -    services.loadbalancers: "0"
    -    services.nodeports: "0"
    -

    针对NodePort的额度测试

    在namespace quota-object-example 中创建一个 Deployment ns-quota-test

    kubectl create deployment ns-quota-test --image nginx --namespace=quota-object-example
    -

    通过 NodePort 将 Deployment 暴露出来。

    kubectl expose deployment ns-quota-test --port=80 --type=NodePort --namespace=quota-object-example
    +

    检查配额

    kubectl get resourcequota object-quota-demo --namespace=quota-object-example --output=yaml
    +

    主要信息摘录如下:

    spec:
    +  hard:
    +    persistentvolumeclaims: "1"
    +    services.loadbalancers: "2"
    +    services.nodeports: "0"
    +status:
    +  hard:
    +    persistentvolumeclaims: "1"
    +    services.loadbalancers: "2"
    +    services.nodeports: "0"
    +  used:
    +    persistentvolumeclaims: "0"
    +    services.loadbalancers: "0"
    +    services.nodeports: "0"
    +

    针对NodePort的额度测试

    在namespace quota-object-example 中创建一个 Deployment ns-quota-test

    kubectl create deployment ns-quota-test --image nginx --namespace=quota-object-example
    +

    通过 NodePort 将 Deployment 暴露出来。

    kubectl expose deployment ns-quota-test --port=80 --type=NodePort --namespace=quota-object-example
     

    没有意外,我们得到下面的错误,因为我们设置了 Quota services.nodeports: 0

    Error from server (Forbidden): services "ns-quota-test" is forbidden: exceeded quota: object-quota-demo, requested: services.nodeports=1, used: services.nodeports=0, limited: services.nodeports=0
    -

    针对PVC的额度测试

    在namespace quota-object-example 中创建一个 PVC pvc-quota-demo

    kubectl applly -f - << EOF
    +

    针对PVC的额度测试

    在namespace quota-object-example 中创建一个 PVC pvc-quota-demo

    kubectl applly -f - << EOF
     kind: PersistentVolumeClaim
     apiVersion: v1
     metadata:
    @@ -43,23 +43,23 @@
         requests:
           storage: 3Gi
     EOF
    -

    检查配额信息。

    kubectl get resourcequota object-quota-demo --namespace=quota-object-example --output=yaml
    -

    这里设置了 persistentvolumeclaims1,并且配额也是 1。如果我们再次创建 PVC,则会收到 403 错误。

    spec:
    -  hard:
    -    persistentvolumeclaims: "1"
    -    services.loadbalancers: "2"
    -    services.nodeports: "0"
    -status:
    -  hard:
    -    persistentvolumeclaims: "1"
    -    services.loadbalancers: "2"
    -    services.nodeports: "0"
    -  used:
    -    persistentvolumeclaims: "1"
    -    services.loadbalancers: "0"
    -    services.nodeports: "0"
    -

    LimitRange

    演示场景:

    • Create LimitRange cpu-limit-range to define range of CPU Request and CPU Limit for a Container.
    • Test LimitRange cpu-limit-range via Pod.
    • Scenario 1: Pod without specified limits
    • Scenario 2: Pod with CPU limit, without CPU Request
    • Scenario 3: Pod with CPU Request onlyl, without CPU Limits

    • 创建 cpu-limit-range 限制范围,用于设定容器 CPU 请求和 CPU 限制的范围。

    • 通过 Pod 测试 cpu-limit-range 限制范围。
    • 方案1:没有限制的 Pod
    • 方案2:只有 CPU 限制,但没有 CPU 请求限制的 Pod
    • 方案3:只有 CPU 请求限制,但没有 CPU 限制的 Pod

    演示背景:

    LimitRange 提供了以下约束:

    • 强制限制 namespace 内每个 Pod 或容器的最小和最大计算资源使用情况。
    • 强制限制 namespace 内每个 PersistentVolumeClaim 的最小和最大存储请求。
    • 在 namespace 内为某个资源的请求和限制之间设置比率。
    • 在 namespace 中设置默认的计算资源请求/限制,并在运行时自动将它们注入到容器中。

    设置LimitRange

    创建namespace default-cpu-example 用于下面的演示。

    kubectl create namespace default-cpu-example
    -

    创建 LimitRange cpu-limit-range,用于定义容器的 CPU 请求和 CPU 限制范围。 应用此 LimitRange 资源后,CPU 限制将影响所有新创建的 Pod。

    kubectl apply -f - << EOF
    +

    检查配额信息。

    kubectl get resourcequota object-quota-demo --namespace=quota-object-example --output=yaml
    +

    这里设置了 persistentvolumeclaims1,并且配额也是 1。如果我们再次创建 PVC,则会收到 403 错误。

    spec:
    +  hard:
    +    persistentvolumeclaims: "1"
    +    services.loadbalancers: "2"
    +    services.nodeports: "0"
    +status:
    +  hard:
    +    persistentvolumeclaims: "1"
    +    services.loadbalancers: "2"
    +    services.nodeports: "0"
    +  used:
    +    persistentvolumeclaims: "1"
    +    services.loadbalancers: "0"
    +    services.nodeports: "0"
    +

    LimitRange

    演示场景:

    • Create LimitRange cpu-limit-range to define range of CPU Request and CPU Limit for a Container.
    • Test LimitRange cpu-limit-range via Pod.
    • Scenario 1: Pod without specified limits
    • Scenario 2: Pod with CPU limit, without CPU Request
    • Scenario 3: Pod with CPU Request onlyl, without CPU Limits

    • 创建 cpu-limit-range 限制范围,用于设定容器 CPU 请求和 CPU 限制的范围。

    • 通过 Pod 测试 cpu-limit-range 限制范围。
    • 方案1:没有限制的 Pod
    • 方案2:只有 CPU 限制,但没有 CPU 请求限制的 Pod
    • 方案3:只有 CPU 请求限制,但没有 CPU 限制的 Pod

    演示背景:

    LimitRange 提供了以下约束:

    • 强制限制 namespace 内每个 Pod 或容器的最小和最大计算资源使用情况。
    • 强制限制 namespace 内每个 PersistentVolumeClaim 的最小和最大存储请求。
    • 在 namespace 内为某个资源的请求和限制之间设置比率。
    • 在 namespace 中设置默认的计算资源请求/限制,并在运行时自动将它们注入到容器中。

    设置LimitRange

    创建namespace default-cpu-example 用于下面的演示。

    kubectl create namespace default-cpu-example
    +

    创建 LimitRange cpu-limit-range,用于定义容器的 CPU 请求和 CPU 限制范围。 应用此 LimitRange 资源后,CPU 限制将影响所有新创建的 Pod。

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: LimitRange
     metadata:
    @@ -73,7 +73,7 @@
           cpu: 0.5
         type: Container
     EOF
    -

    通过Pod进行测试

    • 场景1: 没有限制的pod。

    创建一个没有限制的pod。

    kubectl apply -f - << EOF
    +

    通过Pod进行测试

    • 场景1: 没有限制的pod。

    创建一个没有限制的pod。

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -84,18 +84,18 @@
       - name: default-cpu-demo-ctr
         image: nginx
     EOF
    -

    验证我们创建的Pod的详细信息。Pod将从namespace中继承CPU Limit和CPU Request作为其默认值。

    kubectl get pod default-cpu-demo --output=yaml --namespace=default-cpu-example
    -

    输出yaml文件的部分内容:

    spec:
    -  containers:
    -  - image: nginx
    -    imagePullPolicy: Always
    -    name: default-cpu-demo-ctr
    -    resources:
    -      limits:
    -        cpu: "1"
    -      requests:
    -        cpu: 500m
    -
    • 场景2: 只有 CPU 限制,但没有 CPU 请求限制的 Pod

    创建一个带有 CPU 限制但没有 CPU 请求的 Pod。

    kubectl apply -f - <<EOF
    +

    验证我们创建的Pod的详细信息。Pod将从namespace中继承CPU Limit和CPU Request作为其默认值。

    kubectl get pod default-cpu-demo --output=yaml --namespace=default-cpu-example
    +

    输出yaml文件的部分内容:

    spec:
    +  containers:
    +  - image: nginx
    +    imagePullPolicy: Always
    +    name: default-cpu-demo-ctr
    +    resources:
    +      limits:
    +        cpu: "1"
    +      requests:
    +        cpu: 500m
    +
    • 场景2: 只有 CPU 限制,但没有 CPU 请求限制的 Pod

    创建一个带有 CPU 限制但没有 CPU 请求的 Pod。

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -110,19 +110,19 @@
             cpu: "1"
     EOF
     
    -kubectl apply -f default-cpu-demo-limit.yaml
    -

    验证我们创建的 Pod 的细节。Pod 从namespace中继承 CPU 请求作为其默认值,并指定自己的 CPU 限制。

    kubectl get pod default-cpu-demo-limit --output=yaml --namespace=default-cpu-example
    -

    输出的yaml文件部分内容:

    spec:
    -  containers:
    -  - image: nginx
    -    imagePullPolicy: Always
    -    name: default-cpu-demo-limit-ctr
    -    resources:
    -      limits:
    -        cpu: "1"
    -      requests:
    -        cpu: "1"
    -
    • 场景3: 只有 CPU 请求限制,但没有 CPU 限制的 Pod

    创建一个只有 CPU 请求限制,但没有 CPU 限制的 Pod

    kubectl apply -f - <<EOF
    +kubectl apply -f default-cpu-demo-limit.yaml
    +

    验证我们创建的 Pod 的细节。Pod 从namespace中继承 CPU 请求作为其默认值,并指定自己的 CPU 限制。

    kubectl get pod default-cpu-demo-limit --output=yaml --namespace=default-cpu-example
    +

    输出的yaml文件部分内容:

    spec:
    +  containers:
    +  - image: nginx
    +    imagePullPolicy: Always
    +    name: default-cpu-demo-limit-ctr
    +    resources:
    +      limits:
    +        cpu: "1"
    +      requests:
    +        cpu: "1"
    +
    • 场景3: 只有 CPU 请求限制,但没有 CPU 限制的 Pod

    创建一个只有 CPU 请求限制,但没有 CPU 限制的 Pod

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -136,15 +136,15 @@
           requests:
             cpu: "0.75"
     EOF
    -

    验证我们创建的 Pod 的详细信息。Pod 从命名空间继承了 CPU Limits 作为其默认值,并指定了自己的 CPU Requests。

    kubectl get pod default-cpu-demo-request --output=yaml --namespace=default-cpu-example
    -

    输出的yaml文件部分内容:

    spec:
    -  containers:
    -  - image: nginx
    -    imagePullPolicy: Always
    -    name: default-cpu-demo-request-ctr
    -    resources:
    -      limits:
    -        cpu: "1"
    -      requests:
    -        cpu: 750m
    -
    \ No newline at end of file +

    验证我们创建的 Pod 的详细信息。Pod 从命名空间继承了 CPU Limits 作为其默认值,并指定了自己的 CPU Requests。

    kubectl get pod default-cpu-demo-request --output=yaml --namespace=default-cpu-example
    +

    输出的yaml文件部分内容:

    spec:
    +  containers:
    +  - image: nginx
    +    imagePullPolicy: Always
    +    name: default-cpu-demo-request-ctr
    +    resources:
    +      limits:
    +        cpu: "1"
    +      requests:
    +        cpu: 750m
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/rbac/index.html b/k8s/cka_cn/foundamentals/rbac/index.html index 919f9d7c..7c87004a 100644 --- a/k8s/cka_cn/foundamentals/rbac/index.html +++ b/k8s/cka_cn/foundamentals/rbac/index.html @@ -1,8 +1,8 @@ - RBAC鉴权 - UPSkilling

    CKA自学笔记18:RBAC鉴权

    摘要

    演示场景:

    1. 为一个集群创建不同的配置文件。
    2. 使用 cfssl 为每个配置文件生成证书。
    3. 创建新的 kubeconfig 文件,包含所有配置文件和相应的用户。
    4. 将旧的和新的 kubeconfig 文件合并到新的 kubeconfig 文件中。我们可以切换不同的上下文来进行进一步的演示。

    基本概念

    • 基于角色的访问控制(Role-based access control,RBAC)是一种基于组织中个人用户角色的访问计算机或网络资源的方法。
    • 当使用客户端证书认证时,我们可以通过 easyrsa、openssl 或 cfssl 手动生成证书。

    建议:

    • kubeconfig 的目的是为不同用户授予不同集群的权限。
    • 不同的上下文将链接到不同的集群。
    • 不建议将多个用户的上下文放在一个 kubeconfig 中使用同一个集群。
    • 建议为一个用户使用一个 kubeconfig 文件。

    安装cfssl

    安装 cfssl

    apt install golang-cfssl
    -

    设置多个上下文

    当前上下文

    执行命令 kubectl config 查询当前使用的上下文(contenxt)。

    kubectl config get-contexts
    + RBAC鉴权 - UPSkilling       

    CKA自学笔记18:RBAC鉴权

    摘要

    演示场景:

    1. 为一个集群创建不同的配置文件。
    2. 使用 cfssl 为每个配置文件生成证书。
    3. 创建新的 kubeconfig 文件,包含所有配置文件和相应的用户。
    4. 将旧的和新的 kubeconfig 文件合并到新的 kubeconfig 文件中。我们可以切换不同的上下文来进行进一步的演示。

    基本概念

    • 基于角色的访问控制(Role-based access control,RBAC)是一种基于组织中个人用户角色的访问计算机或网络资源的方法。
    • 当使用客户端证书认证时,我们可以通过 easyrsa、openssl 或 cfssl 手动生成证书。

    建议:

    • kubeconfig 的目的是为不同用户授予不同集群的权限。
    • 不同的上下文将链接到不同的集群。
    • 不建议将多个用户的上下文放在一个 kubeconfig 中使用同一个集群。
    • 建议为一个用户使用一个 kubeconfig 文件。

    安装cfssl

    安装 cfssl

    apt install golang-cfssl
    +

    设置多个上下文

    当前上下文

    执行命令 kubectl config 查询当前使用的上下文(contenxt)。

    kubectl config get-contexts
     

    我们可以得到类似如下集群的关键信息。

    • 集群名称:kubernetes
    • 系统账号:kubenetes-admin
    • 当前上下文名称:kubernetes-admin@kubernetes(格式为 <system_account>@<cluster_name>
    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
     *         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   dev
    -

    创建CA配置文件

    CA(Certificate Authority)配置文件(config file)是一个用于存储证书颁发机构(CA)信息的文件。 在使用TLS/SSL加密通信时,需要使用证书来验证通信双方的身份。 而CA则是负责签发和验证证书的机构,因此在建立TLS/SSL连接时需要先验证CA的信任关系,以保证证书的有效性。 CA文件中存储了CA的公钥信息和其他相关的配置信息。 在Kubernetes中,使用CA文件来验证证书的有效性和授权访问。

    查看目录/etc/kubernetes/pki及其子目录的结构情况。

    tree /etc/kubernetes/pki
    +

    创建CA配置文件

    CA(Certificate Authority)配置文件(config file)是一个用于存储证书颁发机构(CA)信息的文件。 在使用TLS/SSL加密通信时,需要使用证书来验证通信双方的身份。 而CA则是负责签发和验证证书的机构,因此在建立TLS/SSL连接时需要先验证CA的信任关系,以保证证书的有效性。 CA文件中存储了CA的公钥信息和其他相关的配置信息。 在Kubernetes中,使用CA文件来验证证书的有效性和授权访问。

    查看目录/etc/kubernetes/pki及其子目录的结构情况。

    tree /etc/kubernetes/pki
     

    运行结果,下面是Kubernetes初始安装后的文件结构的示例内容。

    /etc/kubernetes/pki
     ├── apiserver.crt
     ├── apiserver-etcd-client.crt
    @@ -27,9 +27,9 @@
     ├── front-proxy-client.key
     ├── sa.key
     └── sa.pub
    -

    进入目录/etc/kubernetes/pki,即当前工作目录。

    cd /etc/kubernetes/pki
    -

    检查文件ca-config.json是否已经存在与当前工作目录。

    ll ca-config.json
    -

    如果不存在,则创建这个文件。

    • 我们可以添加多个配置文件来指定不同的过期日期、场景、参数等。
    • 配置文件将用于签署证书。
    • 87600小时大约是10年。

    这里我们将在ca-config.json文件中添加一个名为dev的配置文件。

    cat > ca-config.json <<EOF
    +

    进入目录/etc/kubernetes/pki,即当前工作目录。

    cd /etc/kubernetes/pki
    +

    检查文件ca-config.json是否已经存在与当前工作目录。

    ll ca-config.json
    +

    如果不存在,则创建这个文件。

    • 我们可以添加多个配置文件来指定不同的过期日期、场景、参数等。
    • 配置文件将用于签署证书。
    • 87600小时大约是10年。

    这里我们将在ca-config.json文件中添加一个名为dev的配置文件。

    cat > ca-config.json <<EOF
     {
       "signing": {
         "default": {
    @@ -49,7 +49,7 @@
       }
     }
     EOF
    -

    创建证书签名请求 (CSR) 文件

    证书签名请求(CSR)资源用于请求由指定签名者签署的证书,此后可以在最终签署之前批准或拒绝请求。

    设置CSR的CNO属性很重要。

    • CN是请求CSR的用户的名称。
    • O是此用户将属于的组。我们可以参考RBAC以了解标准组。

    保持当前工作目录为/etc/kubernetes/pki

    创建CSR文件cka-dev-csr.jsonCN 代表 cka-devO 代表 k8s

    cat > cka-dev-csr.json <<EOF
    +

    创建证书签名请求 (CSR) 文件

    证书签名请求(CSR)资源用于请求由指定签名者签署的证书,此后可以在最终签署之前批准或拒绝请求。

    设置CSR的CNO属性很重要。

    • CN是请求CSR的用户的名称。
    • O是此用户将属于的组。我们可以参考RBAC以了解标准组。

    保持当前工作目录为/etc/kubernetes/pki

    创建CSR文件cka-dev-csr.jsonCN 代表 cka-devO 代表 k8s

    cat > cka-dev-csr.json <<EOF
     {
       "CN": "cka-dev",
       "hosts": [],
    @@ -68,131 +68,131 @@
       ]
     }
     EOF
    -

    为我们之前定义的配置文件生成证书和密钥。 使用cfssljson -bare cka-dev命令会生成两个文件,cka-dev.pem作为公钥,cka-dev-key.pem作为私钥。

    cfssl gencert -ca=ca.crt -ca-key=ca.key -config=ca-config.json -profile=dev cka-dev-csr.json | cfssljson -bare cka-dev
    -

    验证这2个文件已经成功创建出来了。

    ll -tr | grep cka-dev
    +

    为我们之前定义的配置文件生成证书和密钥。 使用cfssljson -bare cka-dev命令会生成两个文件,cka-dev.pem作为公钥,cka-dev-key.pem作为私钥。

    cfssl gencert -ca=ca.crt -ca-key=ca.key -config=ca-config.json -profile=dev cka-dev-csr.json | cfssljson -bare cka-dev
    +

    验证这2个文件已经成功创建出来了。

    ll -tr | grep cka-dev
     

    运行结果:

    -rw-r--r-- 1 root root  222 Jul 24 08:49 cka-dev-csr.json
     -rw-r--r-- 1 root root 1281 Jul 24 09:14 cka-dev.pem
     -rw------- 1 root root 1675 Jul 24 09:14 cka-dev-key.pem
     -rw-r--r-- 1 root root 1001 Jul 24 09:14 cka-dev.csr
    -

    创建kubeconfig文件

    获取控制平面的IP地址(如:<cka001_ip>)来拼接出环境变量APISERVER的值,如:https://<control_plane_ip>:<port>

    kubectl get node -owide
    +

    创建kubeconfig文件

    获取控制平面的IP地址(如:<cka001_ip>)来拼接出环境变量APISERVER的值,如:https://<control_plane_ip>:<port>

    kubectl get node -owide
     

    运行结果:

    NAME     STATUS   ROLES                  AGE   VERSION  OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
     cka001   Ready    control-plane,master   14h   v1.24.0  Ubuntu 20.04.4 LTS   5.4.0-122-generic   containerd://1.5.9
     cka002   Ready    <none>                 14h   v1.24.0  Ubuntu 20.04.4 LTS   5.4.0-122-generic   containerd://1.5.9
     cka003   Ready    <none>                 14h   v1.24.0  Ubuntu 20.04.4 LTS   5.4.0-122-generic   containerd://1.5.9
    -

    设定并输出环境变量APISERVER

    echo "export APISERVER=\"https://<cka001_ip>:6443\"" >> ~/.bashrc
    -source ~/.bashrc
    -

    验证环境变量APISERVER的值。

    echo $APISERVER
    +

    设定并输出环境变量APISERVER

    echo "export APISERVER=\"https://<cka001_ip>:6443\"" >> ~/.bashrc
    +source ~/.bashrc
    +

    验证环境变量APISERVER的值。

    echo $APISERVER
     

    运行结果:

    https://<cka001_ip>:6443
    -

    设置集群

    保持当前工作目录为 /etc/kubernetes/pki

    生成kubeconfig文件。

    kubectl config set-cluster kubernetes \
    -  --certificate-authority=/etc/kubernetes/pki/ca.crt \
    -  --embed-certs=true \
    -  --server=${APISERVER} \
    -  --kubeconfig=cka-dev.kubeconfig
    -

    现在我们生成了新的配置文件 cka-dev.kubeconfig

    ll -tr | grep cka-dev
    +

    设置集群

    保持当前工作目录为 /etc/kubernetes/pki

    生成kubeconfig文件。

    kubectl config set-cluster kubernetes \
    +  --certificate-authority=/etc/kubernetes/pki/ca.crt \
    +  --embed-certs=true \
    +  --server=${APISERVER} \
    +  --kubeconfig=cka-dev.kubeconfig
    +

    现在我们生成了新的配置文件 cka-dev.kubeconfig

    ll -tr | grep cka-dev
     

    输出结果:

    -rw-r--r-- 1 root root  222 Jul 24 08:49 cka-dev-csr.json
     -rw-r--r-- 1 root root 1281 Jul 24 09:14 cka-dev.pem
     -rw------- 1 root root 1675 Jul 24 09:14 cka-dev-key.pem
     -rw-r--r-- 1 root root 1001 Jul 24 09:14 cka-dev.csr
     -rw------- 1 root root 1671 Jul 24 09:16 cka-dev.kubeconfig
    -

    读取配置文件cka-dev.kubeconfig的内容。

    cat cka-dev.kubeconfig
    -

    输出的内容:

    apiVersion: v1
    -clusters:
    -- cluster:
    -    certificate-authority-data: <your_key>
    -    server: https://<cka001_ip>:6443
    -  name: kubernetes
    -contexts: null
    -current-context: ""
    -kind: Config
    -preferences: {}
    -users: null
    -

    配置用户

    在文件cka-dev.kubeconfig中,用户信息这部分是空的。

    下面我们配置一个用户cka-dev

    kubectl config set-credentials cka-dev \
    -  --client-certificate=/etc/kubernetes/pki/cka-dev.pem \
    -  --client-key=/etc/kubernetes/pki/cka-dev-key.pem \
    -  --embed-certs=true \
    -  --kubeconfig=cka-dev.kubeconfig
    -

    现在,用户信息已经被添加到配置文件cka-dev.kubeconfig中了。

    cat cka-dev.kubeconfig
    -

    输出结果:

    apiVersion: v1
    -clusters:
    -- cluster:
    -    certificate-authority-data: <your_key>
    -    server: https://<cka001_ip>:6443
    -  name: kubernetes
    -contexts: null
    -current-context: ""
    -kind: Config
    -preferences: {}
    -users:
    -- name: cka-dev
    -  user:
    -    client-certificate-data: <your_key>
    -    client-key-data: <your_key>
    -

    至此我们得到了一个完整的配置文件cka-dev.kubeconfig。 由于我们没有在 kubeconfig 文件中设置当前上下文,当我们使用它来获取节点信息时,会收到以下错误。

    kubectl --kubeconfig=cka-dev.kubeconfig get nodes
    +

    读取配置文件cka-dev.kubeconfig的内容。

    cat cka-dev.kubeconfig
    +

    输出的内容:

    apiVersion: v1
    +clusters:
    +- cluster:
    +    certificate-authority-data: <your_key>
    +    server: https://<cka001_ip>:6443
    +  name: kubernetes
    +contexts: null
    +current-context: ""
    +kind: Config
    +preferences: {}
    +users: null
    +

    配置用户

    在文件cka-dev.kubeconfig中,用户信息这部分是空的。

    下面我们配置一个用户cka-dev

    kubectl config set-credentials cka-dev \
    +  --client-certificate=/etc/kubernetes/pki/cka-dev.pem \
    +  --client-key=/etc/kubernetes/pki/cka-dev-key.pem \
    +  --embed-certs=true \
    +  --kubeconfig=cka-dev.kubeconfig
    +

    现在,用户信息已经被添加到配置文件cka-dev.kubeconfig中了。

    cat cka-dev.kubeconfig
    +

    输出结果:

    apiVersion: v1
    +clusters:
    +- cluster:
    +    certificate-authority-data: <your_key>
    +    server: https://<cka001_ip>:6443
    +  name: kubernetes
    +contexts: null
    +current-context: ""
    +kind: Config
    +preferences: {}
    +users:
    +- name: cka-dev
    +  user:
    +    client-certificate-data: <your_key>
    +    client-key-data: <your_key>
    +

    至此我们得到了一个完整的配置文件cka-dev.kubeconfig。 由于我们没有在 kubeconfig 文件中设置当前上下文,当我们使用它来获取节点信息时,会收到以下错误。

    kubectl --kubeconfig=cka-dev.kubeconfig get nodes
     

    运行结果:

    The connection to the server localhost:8080 was refused - did you specify the right host or port?
    -

    当前上下文内容是空白。

    kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts
    +

    当前上下文内容是空白。

    kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts
     

    输出结果:

    CURRENT   NAME   CLUSTER   AUTHINFO   NAMESPACE
    -

    配置上下文

    配置上下文。

    kubectl config set-context dev --cluster=kubernetes --user=cka-dev  --kubeconfig=cka-dev.kubeconfig
    -

    现在我们配置了上下文,但其中CURRENT仍然是空白。

    kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts
    +

    配置上下文

    配置上下文。

    kubectl config set-context dev --cluster=kubernetes --user=cka-dev  --kubeconfig=cka-dev.kubeconfig
    +

    现在我们配置了上下文,但其中CURRENT仍然是空白。

    kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts
     

    运行结果:

    CURRENT   NAME   CLUSTER      AUTHINFO   NAMESPACE
               dev    kubernetes   cka-dev 
    -

    设置默认上下文。上下文将为多集群环境中的集群和用户链接,并且我们可以切换到不同的集群。

    kubectl --kubeconfig=cka-dev.kubeconfig config use-context dev
    -

    验证

    现在CURRENT已经被标记为*了,这就说明当前上下文已经配置好了。

    kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts
    +

    设置默认上下文。上下文将为多集群环境中的集群和用户链接,并且我们可以切换到不同的集群。

    kubectl --kubeconfig=cka-dev.kubeconfig config use-context dev
    +

    验证

    现在CURRENT已经被标记为*了,这就说明当前上下文已经配置好了。

    kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts
     

    运行结果:

    CURRENT   NAME   CLUSTER      AUTHINFO   NAMESPACE
     *         dev    kubernetes   cka-dev      
    -

    因为用户 cka-dev 在该集群中没有授权,所以当我们尝试获取 Pod 或 Node 的信息时,会收到“禁止访问(forbidden)”错误。

    kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get pod 
    -kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get node
    -

    合并kubeconfig文件

    拷贝当前配置文件,作为备份。

    cp ~/.kube/config ~/.kube/config.old 
    -

    把两个配置文件合并成一个新的配置文件,并存放在/tmp/config

    KUBECONFIG=~/.kube/config:/etc/kubernetes/pki/cka-dev.kubeconfig  kubectl config view --flatten > /tmp/config
    -

    用合并后的新配置文件替换老的配置文件。

    mv /tmp/config ~/.kube/config
    -

    新的配置文件~/.kube/config类似如下。

    apiVersion: v1
    -clusters:
    -- cluster:
    -    certificate-authority-data: <your_key>
    -    server: https://<cka001_ip>:6443
    -  name: kubernetes
    -contexts:
    -- context:
    -    cluster: kubernetes
    -    user: cka-dev
    -  name: dev
    -- context:
    -    cluster: kubernetes
    -    user: kubernetes-admin
    -  name: kubernetes-admin@kubernetes
    -current-context: kubernetes-admin@kubernetes
    -kind: Config
    -preferences: {}
    -users:
    -- name: cka-dev
    -  user:
    -    client-certificate-data: <your_key>
    -    client-key-data: <your_key>
    -- name: kubernetes-admin
    -  user:
    -    client-certificate-data: <your_key>
    -    client-key-data: <your_key>
    -

    检查基于新的配置文件下的当前上下文。

    kubectl config get-contexts
    +

    因为用户 cka-dev 在该集群中没有授权,所以当我们尝试获取 Pod 或 Node 的信息时,会收到“禁止访问(forbidden)”错误。

    kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get pod 
    +kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get node
    +

    合并kubeconfig文件

    拷贝当前配置文件,作为备份。

    cp ~/.kube/config ~/.kube/config.old 
    +

    把两个配置文件合并成一个新的配置文件,并存放在/tmp/config

    KUBECONFIG=~/.kube/config:/etc/kubernetes/pki/cka-dev.kubeconfig  kubectl config view --flatten > /tmp/config
    +

    用合并后的新配置文件替换老的配置文件。

    mv /tmp/config ~/.kube/config
    +

    新的配置文件~/.kube/config类似如下。

    apiVersion: v1
    +clusters:
    +- cluster:
    +    certificate-authority-data: <your_key>
    +    server: https://<cka001_ip>:6443
    +  name: kubernetes
    +contexts:
    +- context:
    +    cluster: kubernetes
    +    user: cka-dev
    +  name: dev
    +- context:
    +    cluster: kubernetes
    +    user: kubernetes-admin
    +  name: kubernetes-admin@kubernetes
    +current-context: kubernetes-admin@kubernetes
    +kind: Config
    +preferences: {}
    +users:
    +- name: cka-dev
    +  user:
    +    client-certificate-data: <your_key>
    +    client-key-data: <your_key>
    +- name: kubernetes-admin
    +  user:
    +    client-certificate-data: <your_key>
    +    client-key-data: <your_key>
    +

    检查基于新的配置文件下的当前上下文。

    kubectl config get-contexts
     

    当前上下文是系统默认配置kubernetes-admin@kubernetes

    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
               dev                           kubernetes   cka-dev            
     *         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   dev
    -

    命名空间和上下文

    查询当前命名空间namespace列表和对应标签label的信息。

    kubectl get ns --show-labels
    -

    创建namespace cka

    kubectl create namespace cka
    -

    使用以下命令更新上下文信息,例如,更新默认命名空间等。

    kubectl config set-context <context name> --cluster=<cluster name> --namespace=<namespace name> --user=<user name> 
    -

    下面针对每个上下文context设定默认的namespace。

    kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin
    -kubectl config set-context dev --cluster=kubernetes --namespace=cka --user=cka-dev
    -

    检查当前上下文context的信息。

    kubectl config get-contexts
    +

    命名空间和上下文

    查询当前命名空间namespace列表和对应标签label的信息。

    kubectl get ns --show-labels
    +

    创建namespace cka

    kubectl create namespace cka
    +

    使用以下命令更新上下文信息,例如,更新默认命名空间等。

    kubectl config set-context <context name> --cluster=<cluster name> --namespace=<namespace name> --user=<user name> 
    +

    下面针对每个上下文context设定默认的namespace。

    kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin
    +kubectl config set-context dev --cluster=kubernetes --namespace=cka --user=cka-dev
    +

    检查当前上下文context的信息。

    kubectl config get-contexts
     

    输出结果:

    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
               dev                           kubernetes   cka-dev            cka
     *         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   dev
    -

    通过下面的命令,可以切换到新的context。

    kubectl config use-contexts <context name>
    -

    例如:

    kubectl config use-context dev
    -

    检查上面的变更是否生效。

    kubectl config get-contexts
    +

    通过下面的命令,可以切换到新的context。

    kubectl config use-contexts <context name>
    +

    例如:

    kubectl config use-context dev
    +

    检查上面的变更是否生效。

    kubectl config get-contexts
     

    运行结果;

    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
     *         dev            kubernetes   cka-dev            cka
               kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   dev
    -

    Be noted, four users beginning with cka-dev created don't have any authorizations, e.g., access namespaces, get pods, etc.. Referring RBAC to grant their authorizations.

    注意:前面创建的以cka-dev开头的用户实际没有任何权限,例如访问命名空间、获取 pod 等,下面将通过 RBAC 授予他们授权。

    角色Role和角色绑定RoleBinding

    将当前工作上下文切换到 kubernetes-admin@kubernetes

    kubectl config use-context kubernetes-admin@kubernetes
    -

    使用带有选项--dry-run=client-o yamlkubectl create role命令,生成创建角色role的 yaml 模板。

    kubectl create role admin-dev --resource=pods --verb=get --verb=list --verb=watch --dry-run=client -o yaml
    -

    在namespace cka上创建角色role admin-dev

    kubectl apply -f - << EOF
    +

    Be noted, four users beginning with cka-dev created don't have any authorizations, e.g., access namespaces, get pods, etc.. Referring RBAC to grant their authorizations.

    注意:前面创建的以cka-dev开头的用户实际没有任何权限,例如访问命名空间、获取 pod 等,下面将通过 RBAC 授予他们授权。

    角色Role和角色绑定RoleBinding

    将当前工作上下文切换到 kubernetes-admin@kubernetes

    kubectl config use-context kubernetes-admin@kubernetes
    +

    使用带有选项--dry-run=client-o yamlkubectl create role命令,生成创建角色role的 yaml 模板。

    kubectl create role admin-dev --resource=pods --verb=get --verb=list --verb=watch --dry-run=client -o yaml
    +

    在namespace cka上创建角色role admin-dev

    kubectl apply -f - << EOF
     apiVersion: rbac.authorization.k8s.io/v1
     kind: Role
     metadata:
    @@ -208,8 +208,8 @@
       - watch
       - list
     EOF
    -

    使用带有选项--dry-run=client-o yamlkubectl create rolebinding命令,生成创建角色绑定rolebinding的 yaml 模板。

    kubectl create rolebinding admin --role=admin-dev --user=cka-dev --dry-run=client -o yaml
    -

    在namespace cka上创建一个角色绑定rolebinding admin

    kubectl apply -f - << EOF
    +

    使用带有选项--dry-run=client-o yamlkubectl create rolebinding命令,生成创建角色绑定rolebinding的 yaml 模板。

    kubectl create rolebinding admin --role=admin-dev --user=cka-dev --dry-run=client -o yaml
    +

    在namespace cka上创建一个角色绑定rolebinding admin

    kubectl apply -f - << EOF
     apiVersion: rbac.authorization.k8s.io/v1
     kind: RoleBinding
     metadata:
    @@ -224,13 +224,13 @@
       kind: User
       name: cka-dev
     EOF
    -

    验证namespace cka上的用户cka-dev的权限。

    切换到上下文dev

    kubectl config use-context dev
    -

    查询namespace cka上pod的状态,成功!

    kubectl get pod -n cka
    -

    查询namespace kube-system上pod的状态,失败!因为前面添加的权限仅限于namespace cka

    kubectl get pod -n kube-system
    -

    查询节点node的状态,失败!因为在角色role里面我们只定义了pod这一种资源。

    kubectl get node
    -

    在namespace dev上创建一个pod,失败!因为我们在只有对pod的get,watch,list三种操作权限,没有create 权限。

    kubectl run nginx --image=nginx -n cka
    -

    集群角色ClusterRole和集群角色绑定ClusterRoleBinding

    切换到上下文kubernetes-admin@kubernetes

    kubectl config use-context kubernetes-admin@kubernetes
    -

    创建一个名为 nodes-admin 的 ClusterRole,它授予 getwatchlistnodes 资源的授权。

    kubectl apply -f - <<EOF
    +

    验证namespace cka上的用户cka-dev的权限。

    切换到上下文dev

    kubectl config use-context dev
    +

    查询namespace cka上pod的状态,成功!

    kubectl get pod -n cka
    +

    查询namespace kube-system上pod的状态,失败!因为前面添加的权限仅限于namespace cka

    kubectl get pod -n kube-system
    +

    查询节点node的状态,失败!因为在角色role里面我们只定义了pod这一种资源。

    kubectl get node
    +

    在namespace dev上创建一个pod,失败!因为我们在只有对pod的get,watch,list三种操作权限,没有create 权限。

    kubectl run nginx --image=nginx -n cka
    +

    集群角色ClusterRole和集群角色绑定ClusterRoleBinding

    切换到上下文kubernetes-admin@kubernetes

    kubectl config use-context kubernetes-admin@kubernetes
    +

    创建一个名为 nodes-admin 的 ClusterRole,它授予 getwatchlistnodes 资源的授权。

    kubectl apply -f - <<EOF
     kind: ClusterRole
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
    @@ -245,7 +245,7 @@
       - watch
       - list
     EOF
    -

    将 ClusterRole nodes-admin 绑定到用户 cka-dev

    kubectl apply -f - << EOF
    +

    将 ClusterRole nodes-admin 绑定到用户 cka-dev

    kubectl apply -f - << EOF
     kind: ClusterRoleBinding
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
    @@ -259,13 +259,13 @@
       name: nodes-admin
       apiGroup: rbac.authorization.k8s.io
     EOF
    -

    切换到上下文到 dev。验证权限。

    kubectl config use-context dev
    -

    查询节点node信息,成功!

    kubectl get node
    -

    切换到系统的上下文kubernetes-admin@kubernetes

    kubectl config use-context kubernetes-admin@kubernetes 
    -

    集群角色ClusterRole和ServiceAccount

    演示场景:

    • 创建一个 ClusterRole,该 ClusterRole 有权创建 Deployment、StatefulSet 和 DaemonSet。
    • 将该 ClusterRole 绑定到一个 ServiceAccount 上。

    Demo:

    kubectl create namespace my-namespace
    -kubectl -n my-namespace create serviceaccount my-sa
    -kubectl create clusterrole my-clusterrole --verb=create --resource=deployments,statefulsets,daemonsets
    -kubectl -n my-namespace create rolebinding my-clusterrolebinding --clusterrole=my-clusterrole --serviceaccount=my-namespace:my-sa
    -

    删除演示中创建的临时资源。

    kubectl delete namespace my-namespace 
    -kubectl delete clusterrole my-clusterrole
    -

    建议:

    1. 一个RoleBinding可以引用同一命名空间中的任何Role。
    2. 一个RoleBinding可以引用ClusterRole并将其绑定到RoleBinding所在的命名空间。
    3. 如果要将ClusterRole绑定到集群中的所有命名空间,则使用ClusterRoleBinding。
    4. 使用RoleBinding绑定ClusterRole是为了重用ClusterRole以授权命名空间资源,避免为相同授权创建重复的命名空间角色。
    \ No newline at end of file +

    切换到上下文到 dev。验证权限。

    kubectl config use-context dev
    +

    查询节点node信息,成功!

    kubectl get node
    +

    切换到系统的上下文kubernetes-admin@kubernetes

    kubectl config use-context kubernetes-admin@kubernetes 
    +

    集群角色ClusterRole和ServiceAccount

    演示场景:

    • 创建一个 ClusterRole,该 ClusterRole 有权创建 Deployment、StatefulSet 和 DaemonSet。
    • 将该 ClusterRole 绑定到一个 ServiceAccount 上。

    Demo:

    kubectl create namespace my-namespace
    +kubectl -n my-namespace create serviceaccount my-sa
    +kubectl create clusterrole my-clusterrole --verb=create --resource=deployments,statefulsets,daemonsets
    +kubectl -n my-namespace create rolebinding my-clusterrolebinding --clusterrole=my-clusterrole --serviceaccount=my-namespace:my-sa
    +

    删除演示中创建的临时资源。

    kubectl delete namespace my-namespace 
    +kubectl delete clusterrole my-clusterrole
    +

    建议:

    1. 一个RoleBinding可以引用同一命名空间中的任何Role。
    2. 一个RoleBinding可以引用ClusterRole并将其绑定到RoleBinding所在的命名空间。
    3. 如果要将ClusterRole绑定到集群中的所有命名空间,则使用ClusterRoleBinding。
    4. 使用RoleBinding绑定ClusterRole是为了重用ClusterRole以授权命名空间资源,避免为相同授权创建重复的命名空间角色。
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/scheduling/index.html b/k8s/cka_cn/foundamentals/scheduling/index.html index 6d6ebcbe..9b63b976 100644 --- a/k8s/cka_cn/foundamentals/scheduling/index.html +++ b/k8s/cka_cn/foundamentals/scheduling/index.html @@ -1,6 +1,6 @@ - Scheduling - UPSkilling

    CKA自学笔记20:Scheduling

    演示场景:

    • 为 Pod 配置 nodeSelector
    • 为 Node 配置 nodeName
    • 使用 podAffinity 来分组 Pod。

    • 污点Taints和容忍Tolerations

    • 设置污点Taint
    • 设置容忍Toleration
    • 移除污点Taint

    nodeSelector

    Let's assume the scenario below.

    • We have a group of high performance servers.
    • Some applications require high performance computing.
    • These applicaiton need to be scheduled and running on those high performance servers.

    We can leverage Kubernetes attributes node label and nodeSelector to group resources as a whole for scheduling to meet above requirement.

    假设以下场景:

    • 我们有一组高性能服务器。
    • 一些应用需要高性能计算。
    • 这些应用需要被调度并在高性能服务器上运行。

    我们可以利用 Kubernetes 的 labelnodeSelector 属性来将资源作为一个整体进行分组,以满足上面的需求。

    1.给节点设标签

    给节点 cka002 设定标签值 Configuration=hight

    kubectl label node cka002 configuration=hight
    -

    执行下面的命令进行验证,我们会看看到节点cka002上有了标签信息configuration=hight

    kubectl get node --show-labels
    -

    2.给pod配置nodeSelector

    创建一个 Pod 并使用 nodeSelector 将该 Pod 调度到指定的节点上。

    kubectl apply -f - <<EOF
    + Scheduling - UPSkilling       

    CKA自学笔记20:Scheduling

    演示场景:

    • 为 Pod 配置 nodeSelector
    • 为 Node 配置 nodeName
    • 使用 podAffinity 来分组 Pod。

    • 污点Taints和容忍Tolerations

    • 设置污点Taint
    • 设置容忍Toleration
    • 移除污点Taint

    nodeSelector

    Let's assume the scenario below.

    • We have a group of high performance servers.
    • Some applications require high performance computing.
    • These applicaiton need to be scheduled and running on those high performance servers.

    We can leverage Kubernetes attributes node label and nodeSelector to group resources as a whole for scheduling to meet above requirement.

    假设以下场景:

    • 我们有一组高性能服务器。
    • 一些应用需要高性能计算。
    • 这些应用需要被调度并在高性能服务器上运行。

    我们可以利用 Kubernetes 的 labelnodeSelector 属性来将资源作为一个整体进行分组,以满足上面的需求。

    1.给节点设标签

    给节点 cka002 设定标签值 Configuration=hight

    kubectl label node cka002 configuration=hight
    +

    执行下面的命令进行验证,我们会看看到节点cka002上有了标签信息configuration=hight

    kubectl get node --show-labels
    +

    2.给pod配置nodeSelector

    创建一个 Pod 并使用 nodeSelector 将该 Pod 调度到指定的节点上。

    kubectl apply -f - <<EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -26,10 +26,10 @@
          nodeSelector:
            configuration: hight
     EOF
    -

    检查pod mysql-nodeselector 运行状态。

    kubectl get pod -l app=mysql -o wide |  grep mysql-nodeselector
    +

    检查pod mysql-nodeselector 运行状态。

    kubectl get pod -l app=mysql -o wide |  grep mysql-nodeselector
     

    下面的执行结果说明pod mysql-nodeselector 正运行在节点 cka002 上。

    NAME                                  READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
     mysql-nodeselector-6b7d9c875d-vs8mk   1/1     Running   0          7s     10.244.112.29   cka002   <none>           <none>
    -

    nodeName

    注意,nodeName 具有最高优先级,因为它不是由 Scheduler 进行调度的。

    创建一个 Pod nginx-nodename,并将其指定在 cka003 节点上。

    kubectl apply -f - <<EOF
    +

    nodeName

    注意,nodeName 具有最高优先级,因为它不是由 Scheduler 进行调度的。

    创建一个 Pod nginx-nodename,并将其指定在 cka003 节点上。

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -40,10 +40,10 @@
         image: nginx
       nodeName: cka003
     EOF
    -

    验证pod nginx-nodename 是否运行在节点 ckc003 上。

    kubectl get pod -owide |grep nginx-nodename
    +

    验证pod nginx-nodename 是否运行在节点 ckc003 上。

    kubectl get pod -owide |grep nginx-nodename
     

    运行结果:

    NAME                                      READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
     nginx-nodename                            1/1     Running   0          8s     10.244.102.29   cka003   <none>           <none>
    -

    Affinity

    在 Kubernetes 集群中,有些 Pod 需要频繁与其他 Pod 进行交互。在这种情况下,建议将这些 Pod 调度到同一个节点上运行。例如,两个 Pod:NginxMysql,如果它们频繁通信,则需要在同一个节点上部署它们。

    基于pod之间的关系,我们可以使用 podAffinity 进行选择。

    podAffinity 有两种调度类型:

    • requiredDuringSchedulingIgnoredDuringExecution(硬亲和)
    • preferredDuringSchedulingIgnoredDuringExecution(软亲和)

    可以使用以下类型设置 topologyKey

    • kubernetes.io/hostname #NodeName
    • failure-domain.beta.kubernetes.io/zone #区域 Zone
    • failure-domain.beta.kubernetes.io/region # 区域 Zone

    我们可以设置节点标签来对节点的名称/区域进行分类,这样就可以被 podAffinity 所使用。

    创建pod Nginx

    kubectl apply -f - <<EOF
    +

    Affinity

    在 Kubernetes 集群中,有些 Pod 需要频繁与其他 Pod 进行交互。在这种情况下,建议将这些 Pod 调度到同一个节点上运行。例如,两个 Pod:NginxMysql,如果它们频繁通信,则需要在同一个节点上部署它们。

    基于pod之间的关系,我们可以使用 podAffinity 进行选择。

    podAffinity 有两种调度类型:

    • requiredDuringSchedulingIgnoredDuringExecution(硬亲和)
    • preferredDuringSchedulingIgnoredDuringExecution(软亲和)

    可以使用以下类型设置 topologyKey

    • kubernetes.io/hostname #NodeName
    • failure-domain.beta.kubernetes.io/zone #区域 Zone
    • failure-domain.beta.kubernetes.io/region # 区域 Zone

    我们可以设置节点标签来对节点的名称/区域进行分类,这样就可以被 podAffinity 所使用。

    创建pod Nginx

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -55,7 +55,7 @@
       - name: nginx
         image: nginx
     EOF
    -

    创建pod MySql

    kubectl apply -f - <<EOF
    +

    创建pod MySql

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -80,8 +80,8 @@
                 - nginx
             topologyKey: kubernetes.io/hostname
     EOF
    -

    由于我们配置了 podAffinity,因此 Pod mysql 将会被调度到和 Pod nginx 相同的节点上,标签为 app:nginx

    通过命令 kubectl get pod -o wide 我们可以看到这两个 Pod 正在运行在节点 cka002 上。

    Taints & Tolerations

    概念

    节点的affinity是Pod的属性,可以将它们吸引到一组节点中(作为首选项或硬性要求)。Taints的作用相反——它们允许节点排斥一组Pod。

    Tolerations应用于Pod。Tolerations允许调度器安排具有匹配Taints的Pod,但并不保证一定能够调度:调度器还会评估其他参数作为其功能的一部分。

    Taints和tolerations共同确保Pod不会被调度到不合适的节点上。一个或多个Taints会应用于节点;这标志着该节点不应接受不容忍这些Taints的Pod。

    在生产环境中,我们通常为控制平面节点配置Taints(实际上,大多数K8s安装工具会自动向控制平面节点添加Taints),因为控制平面仅运行Kubernetes系统组件。如果将其用于运行应用程序Pod,很容易消耗资源。最终,控制平面节点将崩溃。如果我们需要稍后将其他系统组件添加到控制平面节点,则可以为相应的系统组件Pod配置Tolerations以容忍Taints。

    设置Taints

    cka003 节点设置为 Taint 节点。将状态设置为 NoSchedule,这不会影响已在 cka003 上运行的现有 Pod。

    kubectl taint nodes cka003 key=value:NoSchedule
    -

    设置Tolerations

    我们可以使用 Tolerations 让 Pod 调度到一个 Taint 节点上。

    kubectl apply -f - <<EOF
    +

    由于我们配置了 podAffinity,因此 Pod mysql 将会被调度到和 Pod nginx 相同的节点上,标签为 app:nginx

    通过命令 kubectl get pod -o wide 我们可以看到这两个 Pod 正在运行在节点 cka002 上。

    Taints & Tolerations

    概念

    节点的affinity是Pod的属性,可以将它们吸引到一组节点中(作为首选项或硬性要求)。Taints的作用相反——它们允许节点排斥一组Pod。

    Tolerations应用于Pod。Tolerations允许调度器安排具有匹配Taints的Pod,但并不保证一定能够调度:调度器还会评估其他参数作为其功能的一部分。

    Taints和tolerations共同确保Pod不会被调度到不合适的节点上。一个或多个Taints会应用于节点;这标志着该节点不应接受不容忍这些Taints的Pod。

    在生产环境中,我们通常为控制平面节点配置Taints(实际上,大多数K8s安装工具会自动向控制平面节点添加Taints),因为控制平面仅运行Kubernetes系统组件。如果将其用于运行应用程序Pod,很容易消耗资源。最终,控制平面节点将崩溃。如果我们需要稍后将其他系统组件添加到控制平面节点,则可以为相应的系统组件Pod配置Tolerations以容忍Taints。

    设置Taints

    cka003 节点设置为 Taint 节点。将状态设置为 NoSchedule,这不会影响已在 cka003 上运行的现有 Pod。

    kubectl taint nodes cka003 key=value:NoSchedule
    +

    设置Tolerations

    我们可以使用 Tolerations 让 Pod 调度到一个 Taint 节点上。

    kubectl apply -f - <<EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -110,6 +110,6 @@
             value: "value"
             effect: "NoSchedule"
     EOF
    -

    Deployment mysql-tolerations的Pod使用了tolerations设置,并被调度到了节点 cka003 上,而该节点是一个被污点化taint的节点。

    kubectl get pod -o wide | grep mysql-tolerations
    -

    取消Taints

    kubectl taint nodes cka003 key-
    -
    \ No newline at end of file +

    Deployment mysql-tolerations的Pod使用了tolerations设置,并被调度到了节点 cka003 上,而该节点是一个被污点化taint的节点。

    kubectl get pod -o wide | grep mysql-tolerations
    +

    取消Taints

    kubectl taint nodes cka003 key-
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/secrets/index.html b/k8s/cka_cn/foundamentals/secrets/index.html index b98dac56..a22ec403 100644 --- a/k8s/cka_cn/foundamentals/secrets/index.html +++ b/k8s/cka_cn/foundamentals/secrets/index.html @@ -1 +1 @@ - secrets - UPSkilling

    CKA自学笔记16:secrets

    \ No newline at end of file + secrets - UPSkilling

    CKA自学笔记16:secrets

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/service/index.html b/k8s/cka_cn/foundamentals/service/index.html index 8992afa6..b0f54aca 100644 --- a/k8s/cka_cn/foundamentals/service/index.html +++ b/k8s/cka_cn/foundamentals/service/index.html @@ -1,4 +1,4 @@ - Service - UPSkilling

    CKA自学笔记10:Service

    摘要

    演示场景:

    • 创建名为httpd-app的Deployment。
    • 创建类型为 ClusterIPhttpd-app服务,默认类型是 ClusterIP,只能内部访问。
    • 验证对Pod的IP和服务的集群IP的访问。
    • httpd-app服务类型更新为 NodePort,不需要对 httpd-app这个Deployment进行任何更改。
    • 验证节点node的访问。对节点node对访问将被路由到Pod,从而实现从外部访问我们创建的服务httpd-app
    • 创建无头服务(Headless Service)web 和 有状态副本集(StatefulSet)web
    • 服务的内部流量策略。

    NodePort可以翻译为“节点端口”,是一种Service的类型,可以通过在每个节点上打开一个端口,将Service暴露到集群外部。

    ClusterIP可以翻译为“集群IP”,也是一种Service的类型,为Service提供了一个虚拟IP地址,可以在集群内部进行访问。这个IP地址通常由集群中的Kubernetes代理自动分配,并且只能在集群内部使用。

    ClusterIP

    创建Service

    创建Deployment http-app

    创建Service httpd-app并通过标签选择器(Label Selector)关联到Development http-app。 Service的类型是ClusterIP,这是Service的默认类型,只限于内部访问。

    kubectl apply -f - <<EOF
    + Service - UPSkilling       

    CKA自学笔记10:Service

    摘要

    演示场景:

    • 创建名为httpd-app的Deployment。
    • 创建类型为 ClusterIPhttpd-app服务,默认类型是 ClusterIP,只能内部访问。
    • 验证对Pod的IP和服务的集群IP的访问。
    • httpd-app服务类型更新为 NodePort,不需要对 httpd-app这个Deployment进行任何更改。
    • 验证节点node的访问。对节点node对访问将被路由到Pod,从而实现从外部访问我们创建的服务httpd-app
    • 创建无头服务(Headless Service)web 和 有状态副本集(StatefulSet)web
    • 服务的内部流量策略。

    NodePort可以翻译为“节点端口”,是一种Service的类型,可以通过在每个节点上打开一个端口,将Service暴露到集群外部。

    ClusterIP可以翻译为“集群IP”,也是一种Service的类型,为Service提供了一个虚拟IP地址,可以在集群内部进行访问。这个IP地址通常由集群中的Kubernetes代理自动分配,并且只能在集群内部使用。

    ClusterIP

    创建Service

    创建Deployment http-app

    创建Service httpd-app并通过标签选择器(Label Selector)关联到Development http-app。 Service的类型是ClusterIP,这是Service的默认类型,只限于内部访问。

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Service
     metadata:
    @@ -41,22 +41,22 @@
     NAME                             READY   STATUS    RESTARTS   AGE    IP              NODE     NOMINATED NODE   READINESS GATES
     pod/httpd-app-6496d888c9-4nb6z   1/1     Running   0          77s    10.244.102.21   cka003   <none>           <none>
     pod/httpd-app-6496d888c9-b7xht   1/1     Running   0          77s    10.244.112.19   cka002   <none>           <none>
    -

    执行下面的命令,验证对pod的IP地址的访问。

    curl 10.244.102.21
    -curl 10.244.112.19
    +

    执行下面的命令,验证对pod的IP地址的访问。

    curl 10.244.102.21
    +curl 10.244.112.19
     

    可以得到下面的信息,说明访问成功。

    <html><body><h1>It works!</h1></body></html>
    -

    执行下面的命令,验证通过端口对ClusterIP的访问。

    curl 11.244.247.7:80
    +

    执行下面的命令,验证通过端口对ClusterIP的访问。

    curl 11.244.247.7:80
     

    可以得到下面的信息,说明访问成功。

    <html><body><h1>It works!</h1></body></html>
    -

    暴露Service

    创建一个临时的Pod nslookup,并附加到它以验证DNS解析。选项--rm表示在退出后删除该Pod。

    kubectl run -it nslookup --rm --image=busybox:1.28
    +

    暴露Service

    创建一个临时的Pod nslookup,并附加到它以验证DNS解析。选项--rm表示在退出后删除该Pod。

    kubectl run -it nslookup --rm --image=busybox:1.28
     

    连接到这个Pod后,运行命令 nslookup httpd-app。我们会收到 httpd-app 服务的 ClusterIP 和完整的域名。

    / # nslookup httpd-app
     Server:    11.244.0.10
     Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local
     
     Name:      httpd-app
     Address 1: 11.244.247.7 httpd-app.dev.svc.cluster.local
    -

    我们可以通过执行命令 kubectl get pod -o wide 来在新的终端中检查临时 Pod nslookup 的 IP 地址。Pod nslookup 的 IP 地址为 10.244.112.20

    kubectl get pod nslookup
    +

    我们可以通过执行命令 kubectl get pod -o wide 来在新的终端中检查临时 Pod nslookup 的 IP 地址。Pod nslookup 的 IP 地址为 10.244.112.20

    kubectl get pod nslookup
     

    运行结果

    NAME       READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
     nslookup   1/1     Running   0          2m44s   10.244.112.20   cka002   <none>           <none>
    -

    NodePort

    创建并应用文件 svc-nodeport.yaml 来创建Service httpd-app

    kubectl apply -f - <<EOF
    +

    NodePort

    创建并应用文件 svc-nodeport.yaml 来创建Service httpd-app

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Service
     metadata:
    @@ -94,11 +94,11 @@
     deployment.apps/httpd-app unchanged
     

    通过命令kubectl get svc来检查Service httpd-app,其中:

    • Service的IP地址不变。
    • Service的类型变为NodePort
    • Service的端口号从80/TCP变为80:30080/TCP
    NAME        TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
     httpd-app   NodePort   11.244.247.7   <none>        80:30080/TCP   18m
    -

    在每个节点node上执行命令curl <your_node_ip>:30080,测试对Service httpd-app的联通性。

    curl <node1_ip>:30080
    -curl <node2_ip>:30080
    -curl <node3_ip>:30080
    +

    在每个节点node上执行命令curl <your_node_ip>:30080,测试对Service httpd-app的联通性。

    curl <node1_ip>:30080
    +curl <node2_ip>:30080
    +curl <node3_ip>:30080
     

    可以得到下面的信息,说明访问成功。

    <html><body><h1>It works!</h1></body></html>
    -

    Headless Service

    创建Headless Service web 和StatefulSet web.

    kubectl apply -f - <<EOF
    +

    Headless Service

    创建Headless Service web 和StatefulSet web.

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Service
     metadata:
    @@ -138,22 +138,22 @@
     

    执行命令kubectl get pod -owide -l app=web检查刚才创建的pod。

    NAME    READY   STATUS    RESTARTS   AGE   IP              NODE     NOMINATED NODE   READINESS GATES
     web-0   1/1     Running   0          9s    10.244.102.22   cka003   <none>           <none>
     web-1   1/1     Running   0          6s    10.244.112.21   cka002   <none>           <none>
    -

    执行命令kubectl describe svc -l app=web,检查创建的Service的详细信息。

    Name:              web
    -Namespace:         dev
    -Labels:            app=web
    -Annotations:       <none>
    -Selector:          app=web
    -Type:              ClusterIP
    -IP Family Policy:  SingleStack
    -IP Families:       IPv4
    -IP:                None
    -IPs:               None
    -Port:              web  80/TCP
    -TargetPort:        80/TCP
    -Endpoints:         10.244.102.22:80,10.244.112.21:80
    -Session Affinity:  None
    -Events:            <none>
    -

    连接到临时Pod nslookup,通过 nslookup 来验证DNS到解析。

    kubectl run -it nslookup --rm --image=busybox:1.28
    +

    执行命令kubectl describe svc -l app=web,检查创建的Service的详细信息。

    Name:              web
    +Namespace:         dev
    +Labels:            app=web
    +Annotations:       <none>
    +Selector:          app=web
    +Type:              ClusterIP
    +IP Family Policy:  SingleStack
    +IP Families:       IPv4
    +IP:                None
    +IPs:               None
    +Port:              web  80/TCP
    +TargetPort:        80/TCP
    +Endpoints:         10.244.102.22:80,10.244.112.21:80
    +Session Affinity:  None
    +Events:            <none>
    +

    连接到临时Pod nslookup,通过 nslookup 来验证DNS到解析。

    kubectl run -it nslookup --rm --image=busybox:1.28
     

    通过 nslookup 命令访问Headless Service web,我们可以得到2个pod的IP地址,注意不是集群IP地址ClusterIP(因为是Headless Service)。

    / # nslookup web
     Server:    11.244.0.10
     Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local
    @@ -174,10 +174,10 @@
     
     Name:      web-1.web
     Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local
    -

    删除上面创建的临时资源。

    kubectl delete sts web
    -kubectl delete service httpd-app web
    -kubectl delete deployment httpd-app 
    -

    服务内部流量策略

    Service Internal Traffic Policy(服务内部流量策略)是Kubernetes中一种用于控制服务内部流量的策略。它的主要目的是控制Service对象中Pod的访问策略。

    在Kubernetes中,Service对象将一个虚拟IP地址绑定到一组Pod上,以便可以通过这个虚拟IP地址来访问这组Pod。Service对象在某种程度上像负载均衡器,可以将请求流量路由到其下面的Pod。 Service对象通常会使用以下两种类型之一来路由流量:

    • ClusterIP:此类型的Service只能从同一Kubernetes集群内的其他Pod访问,因为它是在Kubernetes集群内部路由请求流量的。
    • NodePort:此类型的Service在所有节点上公开了一个静态端口,从而可以从集群外部访问它。但是,它仍然可以从集群内部访问。

    Service Internal Traffic Policy定义了Pod如何访问同一个Service中的其他Pod。可以将其设置为以下三个选项之一:

    • Cluster:这是默认设置,它允许Service中的任何Pod都可以访问另一个Pod。
    • Local:此选项允许Pod仅访问在同一节点上运行的其他Pod。如果Pod需要快速的、低延迟的网络访问,可以使用此选项。
    • Disabled:此选项将完全禁止Service内部的流量。它适用于特定的环境和部署中。

    演示场景:

    • 模拟 Service 内部流量策略的工作方式。
    • 预期结果:
    • 通过设置 Service 的 internalTrafficPolicy: Local,Service 只会将流量路由到 Pod 所在的节点内部。

    演示目的:

    • Service Internal Traffic Policy(服务内部流量策略)可以限制内部流量仅路由到同一节点中的终端节点。
    • 这里的“内部”流量是指源自当前集群中的Pod的流量。
    • 通过将其 .spec.internalTrafficPolicy 设置为 Local,可以告诉 kube-proxy 仅对集群内部流量使用本地节点的终端节点。
    • 对于位于没有给定服务的终端节点的节点上的Pod,即使服务在其他节点上有终端节点,该服务也会被视为在该节点上没有终端节点(对于该节点上的Pod)。

    演示:

    创建 Deployment my-nginx 和 Service my-nginx.

    kubectl apply -f - << EOF
    +

    删除上面创建的临时资源。

    kubectl delete sts web
    +kubectl delete service httpd-app web
    +kubectl delete deployment httpd-app 
    +

    服务内部流量策略

    Service Internal Traffic Policy(服务内部流量策略)是Kubernetes中一种用于控制服务内部流量的策略。它的主要目的是控制Service对象中Pod的访问策略。

    在Kubernetes中,Service对象将一个虚拟IP地址绑定到一组Pod上,以便可以通过这个虚拟IP地址来访问这组Pod。Service对象在某种程度上像负载均衡器,可以将请求流量路由到其下面的Pod。 Service对象通常会使用以下两种类型之一来路由流量:

    • ClusterIP:此类型的Service只能从同一Kubernetes集群内的其他Pod访问,因为它是在Kubernetes集群内部路由请求流量的。
    • NodePort:此类型的Service在所有节点上公开了一个静态端口,从而可以从集群外部访问它。但是,它仍然可以从集群内部访问。

    Service Internal Traffic Policy定义了Pod如何访问同一个Service中的其他Pod。可以将其设置为以下三个选项之一:

    • Cluster:这是默认设置,它允许Service中的任何Pod都可以访问另一个Pod。
    • Local:此选项允许Pod仅访问在同一节点上运行的其他Pod。如果Pod需要快速的、低延迟的网络访问,可以使用此选项。
    • Disabled:此选项将完全禁止Service内部的流量。它适用于特定的环境和部署中。

    演示场景:

    • 模拟 Service 内部流量策略的工作方式。
    • 预期结果:
    • 通过设置 Service 的 internalTrafficPolicy: Local,Service 只会将流量路由到 Pod 所在的节点内部。

    演示目的:

    • Service Internal Traffic Policy(服务内部流量策略)可以限制内部流量仅路由到同一节点中的终端节点。
    • 这里的“内部”流量是指源自当前集群中的Pod的流量。
    • 通过将其 .spec.internalTrafficPolicy 设置为 Local,可以告诉 kube-proxy 仅对集群内部流量使用本地节点的终端节点。
    • 对于位于没有给定服务的终端节点的节点上的Pod,即使服务在其他节点上有终端节点,该服务也会被视为在该节点上没有终端节点(对于该节点上的Pod)。

    演示:

    创建 Deployment my-nginx 和 Service my-nginx.

    kubectl apply -f - << EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -213,8 +213,8 @@
     EOF
     

    使用命令 kubectl get pod -o wide,我们可以得知 Deployment my-nginx 的 Pod 正在运行在 cka003 节点上。

    NAME                                      READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
     my-nginx-cf54cdbf7-bscf8                  1/1     Running   0          9h      10.244.112.63   cka002   <none>           <none>
    -

    让我们从 cka001 发送 http 请求到运行在 cka002 上的 Pod。 我们将收到 Welcome to nginx! 信息,这意味着该 Pod 可以从其他节点访问。

    curl 11.244.163.60
    -

    现在来修改Service my-nginx并指定internalTrafficPolicy: Local

    kubectl apply -f - << EOF
    +

    让我们从 cka001 发送 http 请求到运行在 cka002 上的 Pod。 我们将收到 Welcome to nginx! 信息,这意味着该 Pod 可以从其他节点访问。

    curl 11.244.163.60
    +

    现在来修改Service my-nginx并指定internalTrafficPolicy: Local

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Service
     metadata:
    @@ -229,22 +229,22 @@
         run: my-nginx
       internalTrafficPolicy: Local
     EOF
    -

    Let's send http request from cka001 to the http request to the Pod again. We will receive curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused error information.

    我们再次从cka001发送http请求到该Pod。 我们将收到错误信息curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused

    curl 11.244.163.60
    -

    让我们登录到 cka002 节点并再次向 Pod 发送 HTTP 请求。 我们将收到 Welcome to nginx! 的信息。

    curl 11.244.163.60
    -

    演示结论:

    • 设置 Service 的 internalTrafficPolicy: Local 后,Service 只会将流量路由到当前 Pod 所在的节点内部的 Pod。

    演示场景:

    • 创建一个nginx Deployment
    • 添加nginx Pod的端口号和别名
    • 使用本地流量将Deployment暴露出去。

    演示:

    使用端口号为80创建my-nginx Deployment。

    kubectl create deployment my-nginx --image=nginx --port=80
    -

    修改Deployment。

    kubectl edit deployment my-nginx
    -

    my-nginx Deployment中添加端口别名 http

    请参考以下部署的 YAML 模板链接:https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

        spec:
    -      containers:
    -      - image: nginx
    -        imagePullPolicy: Always
    -        name: nginx
    -        ports:
    -        - containerPort: 80
    -          protocol: TCP
    -          name: http
    -

    使用 NodePort 类型暴露 deployment。

    kubectl expose deployment my-nginx --port=80 --target-port=http --name=my-nginx-svc --type=NodePort
    -

    修改service,把 internalTrafficPolicyCluster 改为 Local

    kubectl edit svc my-nginx-svc 
    -

    验证访问。 注意,Pod 正在运行在节点 cka003 上。我们将看到以下预期结果。

    curl <deployment_pod_ip>:80    # succeed on node cka003. internalTrafficPolicy is effective.
    -curl <service_cluster_ip>:80   # succeed on all nodes.
    -curl <node_ip>:<ext_port>      # succeed on all nodes.
    -
    \ No newline at end of file +

    Let's send http request from cka001 to the http request to the Pod again. We will receive curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused error information.

    我们再次从cka001发送http请求到该Pod。 我们将收到错误信息curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused

    curl 11.244.163.60
    +

    让我们登录到 cka002 节点并再次向 Pod 发送 HTTP 请求。 我们将收到 Welcome to nginx! 的信息。

    curl 11.244.163.60
    +

    演示结论:

    • 设置 Service 的 internalTrafficPolicy: Local 后,Service 只会将流量路由到当前 Pod 所在的节点内部的 Pod。

    演示场景:

    • 创建一个nginx Deployment
    • 添加nginx Pod的端口号和别名
    • 使用本地流量将Deployment暴露出去。

    演示:

    使用端口号为80创建my-nginx Deployment。

    kubectl create deployment my-nginx --image=nginx --port=80
    +

    修改Deployment。

    kubectl edit deployment my-nginx
    +

    my-nginx Deployment中添加端口别名 http

    请参考以下部署的 YAML 模板链接:https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

        spec:
    +      containers:
    +      - image: nginx
    +        imagePullPolicy: Always
    +        name: nginx
    +        ports:
    +        - containerPort: 80
    +          protocol: TCP
    +          name: http
    +

    使用 NodePort 类型暴露 deployment。

    kubectl expose deployment my-nginx --port=80 --target-port=http --name=my-nginx-svc --type=NodePort
    +

    修改service,把 internalTrafficPolicyCluster 改为 Local

    kubectl edit svc my-nginx-svc 
    +

    验证访问。 注意,Pod 正在运行在节点 cka003 上。我们将看到以下预期结果。

    curl <deployment_pod_ip>:80    # succeed on node cka003. internalTrafficPolicy is effective.
    +curl <service_cluster_ip>:80   # succeed on all nodes.
    +curl <node_ip>:<ext_port>      # succeed on all nodes.
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/statefulset/index.html b/k8s/cka_cn/foundamentals/statefulset/index.html index ef399e2c..2010a55d 100644 --- a/k8s/cka_cn/foundamentals/statefulset/index.html +++ b/k8s/cka_cn/foundamentals/statefulset/index.html @@ -1,4 +1,4 @@ - StatefulSet - UPSkilling

    CKA自学笔记12:StatefulSet

    演示场景

    • 创建一个 Headless Service nginx 和一个StatefulSet web
    • 扩展 StatefulSet web

    演示

    创建一个 Headless Service nginx 和一个StatefulSet web

    kubectl apply -f - << EOF
    + StatefulSet - UPSkilling       

    CKA自学笔记12:StatefulSet

    演示场景

    • 创建一个 Headless Service nginx 和一个StatefulSet web
    • 扩展 StatefulSet web

    演示

    创建一个 Headless Service nginx 和一个StatefulSet web

    kubectl apply -f - << EOF
     ---
     apiVersion: v1
     kind: Service
    @@ -36,11 +36,11 @@
             - containerPort: 80
               name: web
     EOF
    -

    读取上一步创建的StatefulSet Pod 的详细信息。

    kubectl get pod | grep web
    -

    运行结果

    NAME    READY   STATUS    RESTARTS   AGE
    -web-0   1/1     Running   0          27s
    -web-1   1/1     Running   0          10s
    -

    使用命令 kubectl edit sts web 更新现有的 StatefulSet。 只有以下字段可以更新:replicasimagerolling updateslabelsresource request/limitannotations

    注意:当 StatefulSet Pod 在当前节点中死亡时,不会自动在其他节点中创建副本。

    扩展 StatefulSet。 将 StatefulSet web 的副本数扩展到 5

    kubectl scale sts web --replicas=5
    -

    参考:

    Partition表示在更新期间应将 StatefulSet 划分为哪个序号。 在滚动更新期间,从序号 Replicas-1 到 Partition 的所有 Pod 都会更新。 从序号 Partition-1 到 0 的所有 Pod 都保持不变。这对于进行金丝雀部署非常有用。默认值为0。

    命令:kubectl explain statefulsets.spec.updateStrategy.rollingUpdate.partition

    金丝雀部署是一种软件部署技术,其中在将新功能或版本发布给更大的用户子集或所有用户之前,先将其发布给生产中的一小部分用户。 这种技术是低风险的,因为新功能最初只部署给少量用户。 "Canary"一词源自旧的煤矿技术,当时金丝雀被用作空气中毒素的早期探测器。 在金丝雀部署中,目标环境中的所有基础设施都会以小阶段进行更新。 它用于测试新功能和升级以查看它们如何处理生产环境。

    删除所创建的资源。

    kubectl delete sts web
    -kubectl delete service nginx
    -
    \ No newline at end of file +

    读取上一步创建的StatefulSet Pod 的详细信息。

    kubectl get pod | grep web
    +

    运行结果

    NAME    READY   STATUS    RESTARTS   AGE
    +web-0   1/1     Running   0          27s
    +web-1   1/1     Running   0          10s
    +

    使用命令 kubectl edit sts web 更新现有的 StatefulSet。 只有以下字段可以更新:replicasimagerolling updateslabelsresource request/limitannotations

    注意:当 StatefulSet Pod 在当前节点中死亡时,不会自动在其他节点中创建副本。

    扩展 StatefulSet。 将 StatefulSet web 的副本数扩展到 5

    kubectl scale sts web --replicas=5
    +

    参考:

    Partition表示在更新期间应将 StatefulSet 划分为哪个序号。 在滚动更新期间,从序号 Replicas-1 到 Partition 的所有 Pod 都会更新。 从序号 Partition-1 到 0 的所有 Pod 都保持不变。这对于进行金丝雀部署非常有用。默认值为0。

    命令:kubectl explain statefulsets.spec.updateStrategy.rollingUpdate.partition

    金丝雀部署是一种软件部署技术,其中在将新功能或版本发布给更大的用户子集或所有用户之前,先将其发布给生产中的一小部分用户。 这种技术是低风险的,因为新功能最初只部署给少量用户。 "Canary"一词源自旧的煤矿技术,当时金丝雀被用作空气中毒素的早期探测器。 在金丝雀部署中,目标环境中的所有基础设施都会以小阶段进行更新。 它用于测试新功能和升级以查看它们如何处理生产环境。

    删除所创建的资源。

    kubectl delete sts web
    +kubectl delete service nginx
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/foundamentals/troubleshooting/index.html b/k8s/cka_cn/foundamentals/troubleshooting/index.html index 3d11fe54..337f711f 100644 --- a/k8s/cka_cn/foundamentals/troubleshooting/index.html +++ b/k8s/cka_cn/foundamentals/troubleshooting/index.html @@ -1,6 +1,6 @@ - Troubleshooting - UPSkilling

    CKA自学笔记25:Troubleshooting

    事件

    演示场景:

    • 描述pod以获取事件信息。

    演示:

    命令用法:

    kubectl describe <resource_type> <resource_name> --namespace=<namespace_name>
    -

    查询pod的事件信息。

    创建一个Tomcat的pod。

    kubectl run tomcat --image=tomcat
    -

    查询pod的事件信息。

    kubectl describe pod/tomcat
    + Troubleshooting - UPSkilling       

    CKA自学笔记25:Troubleshooting

    事件

    演示场景:

    • 描述pod以获取事件信息。

    演示:

    命令用法:

    kubectl describe <resource_type> <resource_name> --namespace=<namespace_name>
    +

    查询pod的事件信息。

    创建一个Tomcat的pod。

    kubectl run tomcat --image=tomcat
    +

    查询pod的事件信息。

    kubectl describe pod/tomcat
     

    得到类似下面的事件信息。

    Events:
       Type    Reason     Age   From               Message
       ----    ------     ----  ----               -------
    @@ -9,7 +9,7 @@
       Normal  Pulled     21s   kubelet            Successfully pulled image "tomcat" in 33.134162692s
       Normal  Created    19s   kubelet            Created container tomcat
       Normal  Started    19s   kubelet            Started container tomcat
    -

    查询namespace的事件信息。

    kubectl get events -n <your_namespace_name>
    +

    查询namespace的事件信息。

    kubectl get events -n <your_namespace_name>
     

    得到类似下面的默认namespace的事件信息。

    LAST SEEN   TYPE      REASON           OBJECT                          MESSAGE
     70s         Warning   FailedGetScale   horizontalpodautoscaler/nginx   deployments/scale.apps "podinfo" not found
     2m16s       Normal    Scheduled        pod/tomcat                      Successfully assigned dev/tomcat to cka002
    @@ -17,26 +17,26 @@
     102s        Normal    Pulled           pod/tomcat                      Successfully pulled image "tomcat" in 33.134162692s
     100s        Normal    Created          pod/tomcat                      Created container tomcat
     100s        Normal    Started          pod/tomcat                      Started container tomcat
    -

    得到类似下面的所有的namespace的事件信息。

    kubectl get events -A
    -

    日志

    演示场景:

    • 查询pod的日志

    命令用法:

    kubectl logs <pod_name> -n <namespace_name>
    -

    选项:

    • --tail <n>: 显示输出的最近 <n> 行。
    • -f:实时流式显示输出。

    显示输出的最近100行输出。

    kubectl logs -f tomcat --tail 100
    -

    如果是一个多容器pod,则使用选项-c来指定某个特定的容器。

    kubectl logs -f tomcat --tail 100 -c tomcat
    -

    节点可用性

    查看可用节点

    演示场景:

    • 查看节点可用性

    演示:

    方式1:

    kubectl describe node | grep -i taint
    -

    手工方式检查日志,下面的例子说明2个节点处于不可用状态。

    Taints:             node-role.kubernetes.io/control-plane:NoSchedule
    -Taints:             <none>
    -Taints:             <none>
    -

    方式2:

    kubectl describe node | grep -i taint |grep -vc NoSchedule
    -

    这里我们会得到相同的结果,2个节点处于不可用状态。这里的-v表示排除,-c表示计数。

    查看不可用节点

    演示场景:

    当我们在Worker节点 cka002 上停止 kubelet 服务时,

    • 每个节点的状态是什么?
    • 通过 nerdctl 命令更改了哪些容器?
    • 通过命令 kubectl get pod -owide -A 查看的Pod状态是什么?

    演示:

    cka002节点上执行命令systemctl stop kubelet.service

    cka001cka003上执行命令kubectl get node,可以看到cka002的状态从Ready变为NotReady

    cka002上执行命令nerdctl -n k8s.io container ls,可以看到所有容器都仍在运行,包括Pod my-first-pod

    cka002上执行命令systemctl start kubelet.service

    结论:

    • 节点状态由Ready变为NotReady
    • 对于那些类似calicokube-proxy这样的 DaemonSet Pod,它们专门在每个节点上运行。在kubelet停止后它们不会被终止。
    • Pod my-first-pod 的状态在每个节点上仍然显示为 Terminating,因为状态无法通过apiservercka002同步到其他节点,因为kubelet已停止。
    • Pod的状态由控制器标记并由kubelet回收。
    • 当我们在cka003上启动kubelet服务时,Pod my-first-pod 将完全在cka002上被终止。

    此外,让我们创建一个副本数为3的Deployment。其中两个副本运行在cka003上,另一个副本运行在cka002上。

    kubectl get pod -o wide -w
    +

    得到类似下面的所有的namespace的事件信息。

    kubectl get events -A
    +

    日志

    演示场景:

    • 查询pod的日志

    命令用法:

    kubectl logs <pod_name> -n <namespace_name>
    +

    选项:

    • --tail <n>: 显示输出的最近 <n> 行。
    • -f:实时流式显示输出。

    显示输出的最近100行输出。

    kubectl logs -f tomcat --tail 100
    +

    如果是一个多容器pod,则使用选项-c来指定某个特定的容器。

    kubectl logs -f tomcat --tail 100 -c tomcat
    +

    节点可用性

    查看可用节点

    演示场景:

    • 查看节点可用性

    演示:

    方式1:

    kubectl describe node | grep -i taint
    +

    手工方式检查日志,下面的例子说明2个节点处于不可用状态。

    Taints:             node-role.kubernetes.io/control-plane:NoSchedule
    +Taints:             <none>
    +Taints:             <none>
    +

    方式2:

    kubectl describe node | grep -i taint |grep -vc NoSchedule
    +

    这里我们会得到相同的结果,2个节点处于不可用状态。这里的-v表示排除,-c表示计数。

    查看不可用节点

    演示场景:

    当我们在Worker节点 cka002 上停止 kubelet 服务时,

    • 每个节点的状态是什么?
    • 通过 nerdctl 命令更改了哪些容器?
    • 通过命令 kubectl get pod -owide -A 查看的Pod状态是什么?

    演示:

    cka002节点上执行命令systemctl stop kubelet.service

    cka001cka003上执行命令kubectl get node,可以看到cka002的状态从Ready变为NotReady

    cka002上执行命令nerdctl -n k8s.io container ls,可以看到所有容器都仍在运行,包括Pod my-first-pod

    cka002上执行命令systemctl start kubelet.service

    结论:

    • 节点状态由Ready变为NotReady
    • 对于那些类似calicokube-proxy这样的 DaemonSet Pod,它们专门在每个节点上运行。在kubelet停止后它们不会被终止。
    • Pod my-first-pod 的状态在每个节点上仍然显示为 Terminating,因为状态无法通过apiservercka002同步到其他节点,因为kubelet已停止。
    • Pod的状态由控制器标记并由kubelet回收。
    • 当我们在cka003上启动kubelet服务时,Pod my-first-pod 将完全在cka002上被终止。

    此外,让我们创建一个副本数为3的Deployment。其中两个副本运行在cka003上,另一个副本运行在cka002上。

    kubectl get pod -o wide -w
     

    运行结果

    NAME                               READY   STATUS    RESTARTS   AGE    IP           NODE     NOMINATED NODE   READINESS GATES
     nginx-deployment-9d745469b-2xdk4   1/1     Running   0          2m8s   10.244.2.3   cka003   <none>           <none>
     nginx-deployment-9d745469b-4gvmr   1/1     Running   0          2m8s   10.244.2.4   cka003   <none>           <none>
     nginx-deployment-9d745469b-5j927   1/1     Running   0          2m8s   10.244.1.3   cka002   <none>           <none>
    -

    在我们停止 cka003 上的 kubelet 服务后,原先在 cka003 上运行的两个副本会被终止,然后会自动在 cka002 上创建两个新的副本并运行。

    监控指标

    演示场景:

    • 查询pod的监控指标

    演示:

    查询节点的健康信息。

    kubectl top node
    +

    在我们停止 cka003 上的 kubelet 服务后,原先在 cka003 上运行的两个副本会被终止,然后会自动在 cka002 上创建两个新的副本并运行。

    监控指标

    演示场景:

    • 查询pod的监控指标

    演示:

    查询节点的健康信息。

    kubectl top node
     

    运行结果:

    NAME     CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
     cka001   147m         7%     1940Mi          50%
     cka002   62m          3%     2151Mi          56%
     cka003   63m          3%     1825Mi          47%
    -

    查询pod的监控指标。

    kubectl top pod
    +

    查询pod的监控指标。

    kubectl top pod
     

    运行结果:

    NAME                                      CPU(cores)   MEMORY(bytes)   
     busybox-with-secret                       0m           0Mi
     mysql                                     2m           366Mi
    @@ -53,8 +53,8 @@
     pod-configmap-env                         0m           3Mi
     pod-configmap-env-2                       0m           3Mi
     tomcat                                    1m           58Mi
    -

    通过选项--sort-by,对输出结果按照CPU或者内存用量进行排序。

    kubectl top pod --sort-by=cpu
    -kubectl top pod --sort-by=memory
    +

    通过选项--sort-by,对输出结果按照CPU或者内存用量进行排序。

    kubectl top pod --sort-by=cpu
    +kubectl top pod --sort-by=memory
     

    运行结果:

    NAME                                      CPU(cores)   MEMORY(bytes)   
     nfs-client-provisioner-699db7fd58-bccqs   2m           7Mi
     mysql                                     2m           366Mi
    @@ -71,22 +71,22 @@
     pod-configmap-env                         0m           3Mi
     pod-configmap-env-2                       0m           3Mi
     busybox-with-secret                       0m           0Mi
    -

    节点驱逐

    节点的可调度性

    演示场景:

    • 节点调度

    演示:

    禁止一个节点的调度。

    kubectl cordon <node_name>
    -

    举例:

    kubectl cordon cka003
    +

    节点驱逐

    节点的可调度性

    演示场景:

    • 节点调度

    演示:

    禁止一个节点的调度。

    kubectl cordon <node_name>
    +

    举例:

    kubectl cordon cka003
     

    输出结果,节点状态如下:

    NAME     STATUS                     ROLES                  AGE   VERSION
     cka001   Ready                      control-plane,master   18d   v1.24.0
     cka002   Ready                      <none>                 18d   v1.24.0
     cka003   Ready,SchedulingDisabled   <none>                 18d   v1.24.0
    -

    激活一个节点的调度。

    kubectl uncordon <node_name>
    -

    举例:

    kubectl uncordon cka003
    +

    激活一个节点的调度。

    kubectl uncordon <node_name>
    +

    举例:

    kubectl uncordon cka003
     

    输出结果,节点状态如下:

    NAME     STATUS   ROLES                  AGE   VERSION
     cka001   Ready    control-plane,master   18d   v1.24.0
     cka002   Ready    <none>                 18d   v1.24.0
     cka003   Ready    <none>                 18d   v1.24.0
    -

    驱逐节点

    演示内容:

    • 驱逐节点 cka003

    演示:

    获取当前运行pod的列表。

    kubectl get pod -o wide
    +

    驱逐节点

    演示内容:

    • 驱逐节点 cka003

    演示:

    获取当前运行pod的列表。

    kubectl get pod -o wide
     

    其中有一个pod运行在节点cka003上。

    NAME                                      READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
     nfs-client-provisioner-86d7fb78b6-xk8nw   1/1     Running   0          22h   10.244.102.3   cka003   <none>           <none>
    -

    驱逐节点 cka003

    kubectl drain cka003 --ignore-daemonsets --delete-emptydir-data --force
    +

    驱逐节点 cka003

    kubectl drain cka003 --ignore-daemonsets --delete-emptydir-data --force
     

    输出结果:

    node/cka003 cordoned
     WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-tr22l, kube-system/kube-proxy-g76kg
     evicting pod dev/nfs-client-provisioner-86d7fb78b6-xk8nw
    @@ -94,7 +94,7 @@
     pod/nfs-client-provisioner-86d7fb78b6-xk8nw evicted
     pod/cka-demo-64f88f7f46-dkxmk evicted
     node/cka003 drained
    -

    再次查看pod的状态。

    kubectl get pod -o wide
    +

    再次查看pod的状态。

    kubectl get pod -o wide
     

    先前运行在节点cka003上的pod现在正运行在节点cka002上。

    NAME                                      READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
     nfs-client-provisioner-86d7fb78b6-k8xnl   1/1     Running   0          2m20s   10.244.112.4   cka002   <none>           <none>
    -

    备注:

    • cordon命令已经包含在drain命令中,不需要在执行drain之前单独执行cordon来禁止node的调度。
    \ No newline at end of file +

    备注:

    • cordon命令已经包含在drain命令中,不需要在执行drain之前单独执行cordon来禁止node的调度。
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/installation/aliyun-ubuntu/index.html b/k8s/cka_cn/installation/aliyun-ubuntu/index.html index 61ae72fe..46c3e6a7 100644 --- a/k8s/cka_cn/installation/aliyun-ubuntu/index.html +++ b/k8s/cka_cn/installation/aliyun-ubuntu/index.html @@ -1,46 +1,46 @@ - 阿里云ECS安装Kubernetes - UPSkilling

    CKA自学笔记3:阿里云ECS安装Kubernetes

    摘要

    在阿里云ECS装三台Ubuntu虚拟机。在Ubuntu虚拟机中安装基于Containerd的Kubernetes系统,并分别配置一个主节点Master和两个工作节点Worker,。

    准备工作

    注册阿里云账号: Alibaba Cloud home console。注意保留访问密钥key文件,只能导出一次,当前练习中key文件是aliyun-root

    参考下面配置注册申请三个ECS(Elastic Computer Service)服务实例:

    • 主机:2vCPU+4GiB
    • 操作系统:Ubuntu 20.04 x86_64
    • 实例类型:ecs.sn1.medium
    • 实例名称:cka001, cka002, cka003
    • 网络配置:both public IPs and private IPs
    • 最大网络带宽:100Mbps (Peak Value)
    • 云盘:40GiB
    • 支付方式:抢占式实例

    在本地打开终端窗口,通过密钥文件aliyun-root访问远程ECS节点 cka001

    ssh -i aliyun-root root@cka001
    -

    创建一个普通用户,用来安装Kubernetes,当前练习中创建用户 vagrant,且修改该用户的主要组为 sudo 次要组包含 root

    adduser vagrant
    -usermod -g sudo vagrant
    -usermod -a -G root vagrant
    + 阿里云ECS安装Kubernetes - UPSkilling       

    CKA自学笔记3:阿里云ECS安装Kubernetes

    摘要

    在阿里云ECS装三台Ubuntu虚拟机。在Ubuntu虚拟机中安装基于Containerd的Kubernetes系统,并分别配置一个主节点Master和两个工作节点Worker,。

    准备工作

    注册阿里云账号: Alibaba Cloud home console。注意保留访问密钥key文件,只能导出一次,当前练习中key文件是aliyun-root

    参考下面配置注册申请三个ECS(Elastic Computer Service)服务实例:

    • 主机:2vCPU+4GiB
    • 操作系统:Ubuntu 20.04 x86_64
    • 实例类型:ecs.sn1.medium
    • 实例名称:cka001, cka002, cka003
    • 网络配置:both public IPs and private IPs
    • 最大网络带宽:100Mbps (Peak Value)
    • 云盘:40GiB
    • 支付方式:抢占式实例

    在本地打开终端窗口,通过密钥文件aliyun-root访问远程ECS节点 cka001

    ssh -i aliyun-root root@cka001
    +

    创建一个普通用户,用来安装Kubernetes,当前练习中创建用户 vagrant,且修改该用户的主要组为 sudo 次要组包含 root

    adduser vagrant
    +usermod -g sudo vagrant
    +usermod -a -G root vagrant
     

    新开一个本地终端窗口,为用户vagrant创建密钥key。

    # Windows
     ssh-keygen.exe
     
     # Linux
     ssh-keygen
    -

    上面的命令会生成2个文件,当前练习中这2个文件是 aliyun-vagrant and aliyun-vagrant.pub

    通过sftp命令将公钥文件 aliyun-vagrant.pub 上传到远程节点 cka001

    sftp -i aliyun-root root@cka001
    -put aliyun-vagrant.pub
    -

    新开一个终端窗口,用root的密钥登录cka001节点。 将上一步上传的密钥文件aliyun-vagrant.pub/root目录拷贝到 /home/vagrant/.ssh/。 将公钥文件 aliyun-vagrant.pub 重命名为 authorized_keys。 更改文件authorized_keys 的所有者owner为 vagrant. 更改文件authorized_keys 的主要组为 sudo

    mkdir /home/vagrant/.ssh/
    -mv aliyun-james.pub /home/vagrant/.ssh/authorized_keys
    -chown vagrant.sudo /home/vagrant/.ssh/authorized_keys
    -chmod 600 /home/vagrant/.ssh/authorized_keys
    -

    检查文件 /etc/ssh/sshd_config,确定密码登录验证参数asswordAuthentication设定为no,即只能通过证书远程登录。

    cat /etc/ssh/sshd_config
    -

    新开一个终端窗口,使用用户vagrant登录远程节点cka001,验证用户vagrant能通过前面创建的证书登录节点cka001

    ssh -i aliyun-vagrant vagrant@cka001
    -

    重复上述步骤,通过sftp命令将公钥文件 aliyun-vagrant.pub分别上传到远程节点 cka002cka003,且完成同样的配置,使用户vagrant也能通过密钥文件登录远程节点 cka002cka003

    至此,用户 vagrant 可以通过密钥文件aliyun-vagrant从本地终端窗口登录远程节点 cka001, cka002cka003

    下面所有步骤都是通过用户 vagrant完成。

    初始化ECS节点

    配置文件/etc/hosts

    更新所有ECS节点的文件/etc/hosts,添加其他节点的私有IP(private IP)。

    vi /etc/hosts
    -

    禁用firewall

    在所有节点上禁用防火墙。

    sudo ufw disable
    -

    检查防火墙状态。

    sudo ufw status verbose
    -

    关闭swap

    在所有节点上关闭swap。

    sudo swapoff -a
    -

    设置时区和地域

    在所有节点设定时区和地域。这一布在初始化ECS时候已经完成。可以通过下面命令进行设定。

    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    -sudo echo 'LANG="en_US.UTF-8"' >> /etc/profile
    -source /etc/profile
    -

    通过下面命令检查时区和地域的设置。

    ll /etc/localtime
    +

    上面的命令会生成2个文件,当前练习中这2个文件是 aliyun-vagrant and aliyun-vagrant.pub

    通过sftp命令将公钥文件 aliyun-vagrant.pub 上传到远程节点 cka001

    sftp -i aliyun-root root@cka001
    +put aliyun-vagrant.pub
    +

    新开一个终端窗口,用root的密钥登录cka001节点。 将上一步上传的密钥文件aliyun-vagrant.pub/root目录拷贝到 /home/vagrant/.ssh/。 将公钥文件 aliyun-vagrant.pub 重命名为 authorized_keys。 更改文件authorized_keys 的所有者owner为 vagrant. 更改文件authorized_keys 的主要组为 sudo

    mkdir /home/vagrant/.ssh/
    +mv aliyun-james.pub /home/vagrant/.ssh/authorized_keys
    +chown vagrant.sudo /home/vagrant/.ssh/authorized_keys
    +chmod 600 /home/vagrant/.ssh/authorized_keys
    +

    检查文件 /etc/ssh/sshd_config,确定密码登录验证参数asswordAuthentication设定为no,即只能通过证书远程登录。

    cat /etc/ssh/sshd_config
    +

    新开一个终端窗口,使用用户vagrant登录远程节点cka001,验证用户vagrant能通过前面创建的证书登录节点cka001

    ssh -i aliyun-vagrant vagrant@cka001
    +

    重复上述步骤,通过sftp命令将公钥文件 aliyun-vagrant.pub分别上传到远程节点 cka002cka003,且完成同样的配置,使用户vagrant也能通过密钥文件登录远程节点 cka002cka003

    至此,用户 vagrant 可以通过密钥文件aliyun-vagrant从本地终端窗口登录远程节点 cka001, cka002cka003

    下面所有步骤都是通过用户 vagrant完成。

    初始化ECS节点

    配置文件/etc/hosts

    更新所有ECS节点的文件/etc/hosts,添加其他节点的私有IP(private IP)。

    vi /etc/hosts
    +

    禁用firewall

    在所有节点上禁用防火墙。

    sudo ufw disable
    +

    检查防火墙状态。

    sudo ufw status verbose
    +

    关闭swap

    在所有节点上关闭swap。

    sudo swapoff -a
    +

    设置时区和地域

    在所有节点设定时区和地域。这一布在初始化ECS时候已经完成。可以通过下面命令进行设定。

    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    +sudo echo 'LANG="en_US.UTF-8"' >> /etc/profile
    +source /etc/profile
    +

    通过下面命令检查时区和地域的设置。

    ll /etc/localtime
     
    lrwxrwxrwx 1 root root 33 Jul  5 14:51 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
    -

    内核设置

    在所有节点上执行下面的命令以配置内核。

    使用模块overlay:

    创建Containerd服务配置文件 /etc/modules-load.d/containerd.conf ,如果已存在则跳过这一步。配置这个文件的目的是为了加载模块 overlaybr_netfilter到内核中。

    服务Containerd依赖模块overlay 实现overlay-filesystem文件系统功能。

    Linux中的overlay模块提供了创建两个目录的合并视图的能力,这两个目录称为层。它经常被用于实现联合挂载,这是一种将两个或更多目录一起挂载的方式,就像它们是一个目录一样(union-filesystems)。

    overlay模块在容器技术中被广泛使用,比如Docker,因为它允许多个容器共享基础镜像,同时保持它们自己的文件系统。

    要使用overlay模块,需要两个目录:较低的目录(lower directory)和较高的目录(upper directory)。较低的目录通常是只读的,包含原始文件,而较高的目录是可读写的,包含对文件的更改。当请求文件时,overlay模块首先查找上层目录,如果未找到,则查找下层目录。

    比如:

    创建两个目录,一个用于较低的目录,一个用于较高的目录。然后使用overlay文件系统类型将它们挂载起来:

    sudo mkdir /lower sudo mkdir /upper sudo mount -t overlay overlay -o lowerdir=/lower,upperdir=/upper /merged
    -

    在上面的例子中,两个目录的合并视图被创建在/merged目录中。在/merged目录中对文件所做的任何更改都存储在上层目录中,而原始文件仍然在下层目录中。

    使用模块br_netfilter:

    br_netfilter是Linux内核中的一个模块,它提供了一种机制来过滤网桥的网络流量。该模块允许管理员配置规则,以允许或拒绝特定的网络流量通过网桥。

    网桥是一种网络设备,它可以连接多个网络段,并转发流量以使不同的网络段之间通信。br_netfilter模块可以用来限制或过滤这些流量。

    当启用了br_netfilter模块时,它会自动启用一个称为bridge-nf的功能,该功能将在网络流量通过网桥时应用规则。管理员可以使用iptables等工具来配置这些规则。例如,我们可以设定允许从一个网络段到另一个网络段的流量,或者拒绝来自特定IP地址或端口的流量。

    在Kubernetes中,br_netfilter模块主要用于启用Kubernetes服务的流量转发和负载均衡。这些服务使用了Linux内核中的iptables规则来管理流量,这些规则是通过br_netfilter模块实现的。

    具体来说,当我们在Kubernetes集群中创建一个服务时,该服务将分配一个虚拟IP地址,用于代表服务。然后,通过iptables规则,将这个虚拟IP地址映射到一个或多个后端Pod的IP地址,以便在需要时将流量路由到这些Pod。

    在这个过程中,br_netfilter模块负责监视服务的流量,并根据iptables规则进行转发和负载均衡。这包括过滤来自不受信任源的流量以及限制服务的访问权限。

    需要注意的是,为了启用Kubernetes服务的流量转发和负载均衡,br_netfilter模块必须在所有节点上启用,并且必须配置正确的iptables规则。

    由于br_netfilter模块的作用非常关键,因此在升级或更改系统时需要特别注意它的配置和状态。

    下面命令将模块overlaybr_netfilter添加到配置文件containerd.conf中。

    cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
    +

    内核设置

    在所有节点上执行下面的命令以配置内核。

    使用模块overlay:

    创建Containerd服务配置文件 /etc/modules-load.d/containerd.conf ,如果已存在则跳过这一步。配置这个文件的目的是为了加载模块 overlaybr_netfilter到内核中。

    服务Containerd依赖模块overlay 实现overlay-filesystem文件系统功能。

    Linux中的overlay模块提供了创建两个目录的合并视图的能力,这两个目录称为层。它经常被用于实现联合挂载,这是一种将两个或更多目录一起挂载的方式,就像它们是一个目录一样(union-filesystems)。

    overlay模块在容器技术中被广泛使用,比如Docker,因为它允许多个容器共享基础镜像,同时保持它们自己的文件系统。

    要使用overlay模块,需要两个目录:较低的目录(lower directory)和较高的目录(upper directory)。较低的目录通常是只读的,包含原始文件,而较高的目录是可读写的,包含对文件的更改。当请求文件时,overlay模块首先查找上层目录,如果未找到,则查找下层目录。

    比如:

    创建两个目录,一个用于较低的目录,一个用于较高的目录。然后使用overlay文件系统类型将它们挂载起来:

    sudo mkdir /lower sudo mkdir /upper sudo mount -t overlay overlay -o lowerdir=/lower,upperdir=/upper /merged
    +

    在上面的例子中,两个目录的合并视图被创建在/merged目录中。在/merged目录中对文件所做的任何更改都存储在上层目录中,而原始文件仍然在下层目录中。

    使用模块br_netfilter:

    br_netfilter是Linux内核中的一个模块,它提供了一种机制来过滤网桥的网络流量。该模块允许管理员配置规则,以允许或拒绝特定的网络流量通过网桥。

    网桥是一种网络设备,它可以连接多个网络段,并转发流量以使不同的网络段之间通信。br_netfilter模块可以用来限制或过滤这些流量。

    当启用了br_netfilter模块时,它会自动启用一个称为bridge-nf的功能,该功能将在网络流量通过网桥时应用规则。管理员可以使用iptables等工具来配置这些规则。例如,我们可以设定允许从一个网络段到另一个网络段的流量,或者拒绝来自特定IP地址或端口的流量。

    在Kubernetes中,br_netfilter模块主要用于启用Kubernetes服务的流量转发和负载均衡。这些服务使用了Linux内核中的iptables规则来管理流量,这些规则是通过br_netfilter模块实现的。

    具体来说,当我们在Kubernetes集群中创建一个服务时,该服务将分配一个虚拟IP地址,用于代表服务。然后,通过iptables规则,将这个虚拟IP地址映射到一个或多个后端Pod的IP地址,以便在需要时将流量路由到这些Pod。

    在这个过程中,br_netfilter模块负责监视服务的流量,并根据iptables规则进行转发和负载均衡。这包括过滤来自不受信任源的流量以及限制服务的访问权限。

    需要注意的是,为了启用Kubernetes服务的流量转发和负载均衡,br_netfilter模块必须在所有节点上启用,并且必须配置正确的iptables规则。

    由于br_netfilter模块的作用非常关键,因此在升级或更改系统时需要特别注意它的配置和状态。

    下面命令将模块overlaybr_netfilter添加到配置文件containerd.conf中。

    cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
     overlay
     br_netfilter
     EOF
    -

    手工加载模块overlaybr_netfilter

    sudo modprobe overlay
    -sudo modprobe br_netfilter
    -

    验证模块是否已被加载。

    lsmod | grep br_netfilter
    -

    创建文件 99-kubernetes-cri.conf 用来配置Kubernetes CRI。

    Kubernetes CRI (Container Runtime Interface) 是 Kubernetes 用于管理容器的插件架构。它定义了容器运行时所需的 API 和契约,使得 Kubernetes 可以与任何符合该接口标准的容器运行时交互。

    CRI 最初于 Kubernetes 1.5 版本中引入,作为将容器运行时从 kubelet 中解耦出来的一种方法。在 Kubernetes 中,kubelet 是运行在节点上的主要代理程序,它负责在节点上运行容器并与 Kubernetes API 交互。通过引入 CRI,kubelet 可以使用不同的容器运行时(如 Docker、CRI-O、containerd 等)来运行容器,而无需了解容器运行时的内部细节。这种解耦使得 Kubernetes 更加灵活和可扩展,并使容器运行时的维护更加简单。

    总之,Kubernetes CRI 定义了 Kubernetes 与容器运行时之间的接口,使得 Kubernetes 可以使用不同的容器运行时来管理容器,并使 Kubernetes 更加灵活和可扩展。

    设置参数 net/bridge/bridge-nf-call-iptables=1 ,使 Linux 桥接模块上运行的容器能够通过 iptables 进行网络包过滤(filtering)和转发(forwarding)。

    这个参数的作用是让 Linux 网络桥接能够支持 iptables 的 NAT(Network Address Translation)和过滤功能。具体来说,当容器网络流量通过 Linux 网桥桥接到宿主机网络时,如果这个参数为 1,则 iptables 规则将被应用到容器的网络流量上。如果设置为 0,则不会应用 iptables 规则,这可能会导致容器网络的不稳定性。

    参考Why net/bridge/bridge-nf-call-iptables=1 need to be enable by Kubernetes)。

    IP转发(IP forwarding)也被称为路由(routing)。在Linux中,它也被称为内核IP转发,因为它使用内核变量net.ipv4.ip_forward来启用或禁用IP转发功能。默认值为ip_forward=0。因此,Linux的IP转发功能默认情况下是被禁用的。

    cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
    +

    手工加载模块overlaybr_netfilter

    sudo modprobe overlay
    +sudo modprobe br_netfilter
    +

    验证模块是否已被加载。

    lsmod | grep br_netfilter
    +

    创建文件 99-kubernetes-cri.conf 用来配置Kubernetes CRI。

    Kubernetes CRI (Container Runtime Interface) 是 Kubernetes 用于管理容器的插件架构。它定义了容器运行时所需的 API 和契约,使得 Kubernetes 可以与任何符合该接口标准的容器运行时交互。

    CRI 最初于 Kubernetes 1.5 版本中引入,作为将容器运行时从 kubelet 中解耦出来的一种方法。在 Kubernetes 中,kubelet 是运行在节点上的主要代理程序,它负责在节点上运行容器并与 Kubernetes API 交互。通过引入 CRI,kubelet 可以使用不同的容器运行时(如 Docker、CRI-O、containerd 等)来运行容器,而无需了解容器运行时的内部细节。这种解耦使得 Kubernetes 更加灵活和可扩展,并使容器运行时的维护更加简单。

    总之,Kubernetes CRI 定义了 Kubernetes 与容器运行时之间的接口,使得 Kubernetes 可以使用不同的容器运行时来管理容器,并使 Kubernetes 更加灵活和可扩展。

    设置参数 net/bridge/bridge-nf-call-iptables=1 ,使 Linux 桥接模块上运行的容器能够通过 iptables 进行网络包过滤(filtering)和转发(forwarding)。

    这个参数的作用是让 Linux 网络桥接能够支持 iptables 的 NAT(Network Address Translation)和过滤功能。具体来说,当容器网络流量通过 Linux 网桥桥接到宿主机网络时,如果这个参数为 1,则 iptables 规则将被应用到容器的网络流量上。如果设置为 0,则不会应用 iptables 规则,这可能会导致容器网络的不稳定性。

    参考Why net/bridge/bridge-nf-call-iptables=1 need to be enable by Kubernetes)。

    IP转发(IP forwarding)也被称为路由(routing)。在Linux中,它也被称为内核IP转发,因为它使用内核变量net.ipv4.ip_forward来启用或禁用IP转发功能。默认值为ip_forward=0。因此,Linux的IP转发功能默认情况下是被禁用的。

    cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
     net.bridge.bridge-nf-call-iptables  = 1
     net.ipv4.ip_forward                 = 1
     net.bridge.bridge-nf-call-ip6tables = 1
     EOF
    -

    命令sysctl 从目录 /proc/sys 读取信息。/proc/sys是一个虚拟目录,其中包含可用于查看和设置当前内核参数的文件对象。

    通过sysctl -w net.ipv4.ip_forward=1命令,更改立即生效,但不是永久的。在系统重启后,将加载默认值。要永久设置参数,需要将设置写入/etc/sysctl.conf/etc/sysctl.d目录中的另一个配置文件:

    sudo sysctl --system
    -

    验证参数是否生效。

    sysctl net.ipv4.ip_forward
    -

    安装Containerd

    在所有节点上安装Containerd服务。参考资料:containerd for Ops and Admins

    安装前备份Ubuntu安装源配置文件。

    sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
    -

    添加合适的安装源。基于阿里ECS的Ubuntu 20.04,已经预配置了阿里内部的源,这一步只需要检查一下是否阿里源已配置。

    cat > /etc/apt/sources.list << EOF
    +

    命令sysctl 从目录 /proc/sys 读取信息。/proc/sys是一个虚拟目录,其中包含可用于查看和设置当前内核参数的文件对象。

    通过sysctl -w net.ipv4.ip_forward=1命令,更改立即生效,但不是永久的。在系统重启后,将加载默认值。要永久设置参数,需要将设置写入/etc/sysctl.conf/etc/sysctl.d目录中的另一个配置文件:

    sudo sysctl --system
    +

    验证参数是否生效。

    sysctl net.ipv4.ip_forward
    +

    安装Containerd

    在所有节点上安装Containerd服务。参考资料:containerd for Ops and Admins

    安装前备份Ubuntu安装源配置文件。

    sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
    +

    添加合适的安装源。基于阿里ECS的Ubuntu 20.04,已经预配置了阿里内部的源,这一步只需要检查一下是否阿里源已配置。

    cat > /etc/apt/sources.list << EOF
     deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted
     deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted
     deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted
    @@ -62,10 +62,10 @@
     # deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse
     # deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse
     EOF
    -

    安装Containered。

    sudo apt-get update && sudo apt-get install -y containerd
    -

    配置Containerd。修改文件 /etc/containerd/config.toml

    sudo mkdir -p /etc/containerd
    -containerd config default | sudo tee /etc/containerd/config.toml
    -sudo vi /etc/containerd/config.toml
    +

    安装Containered。

    sudo apt-get update && sudo apt-get install -y containerd
    +

    配置Containerd。修改文件 /etc/containerd/config.toml

    sudo mkdir -p /etc/containerd
    +containerd config default | sudo tee /etc/containerd/config.toml
    +sudo vi /etc/containerd/config.toml
     

    修改参数sandbox_image 的值为"registry.aliyuncs.com/google_containers/pause:3.6"。 修改参数SystemdCgroup的值为true

    [plugins]
       [plugins."io.containerd.gc.v1.scheduler"]
     
    @@ -81,114 +81,114 @@
     
               [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
                 SystemdCgroup = true
    -

    重启Containerd服务。

    sudo systemctl restart containerd
    -sudo systemctl status containerd
    -

    安装nerdctl

    在所有节点上安装nerdctl服务。

    nerdctl 服务支持Contanerd所提供的容器化特性,特别是一些Docker不具备的新特性。

    二进制安装包可以通过这个链接取得: Releases · containerd/nerdctl · GitHub

    wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-0.22.2-linux-amd64.tar.gz
    -tar -zxvf nerdctl-0.22.2-linux-amd64.tar.gz
    -sudo cp nerdctl /usr/bin/
    -

    验证nerdctl服务。

    sudo nerdctl --help
    -

    列出初始安装Kubernetes时的容器container列表。

    nerdctl -n k8s.io ps
    -

    安装kubeadm

    在所有节点上安装Kubeadm,kubectl,kubelet。

    安装和升级Ubuntu系统依赖包 apt-transport-https, ca-certificates, curl

    sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl
    -

    安装gpg证书。

    curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - 
    -

    添加Kubernetes安装源。

    cat << EOF > /etc/apt/sources.list.d/kubernetes.list
    +

    重启Containerd服务。

    sudo systemctl restart containerd
    +sudo systemctl status containerd
    +

    安装nerdctl

    在所有节点上安装nerdctl服务。

    nerdctl 服务支持Contanerd所提供的容器化特性,特别是一些Docker不具备的新特性。

    二进制安装包可以通过这个链接取得: Releases · containerd/nerdctl · GitHub

    wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-0.22.2-linux-amd64.tar.gz
    +tar -zxvf nerdctl-0.22.2-linux-amd64.tar.gz
    +sudo cp nerdctl /usr/bin/
    +

    验证nerdctl服务。

    sudo nerdctl --help
    +

    列出初始安装Kubernetes时的容器container列表。

    nerdctl -n k8s.io ps
    +

    安装kubeadm

    在所有节点上安装Kubeadm,kubectl,kubelet。

    安装和升级Ubuntu系统依赖包 apt-transport-https, ca-certificates, curl

    sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl
    +

    安装gpg证书。

    curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - 
    +

    添加Kubernetes安装源。

    cat << EOF > /etc/apt/sources.list.d/kubernetes.list
     deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
     EOF
    -

    安装和升级Ubuntu系统依赖包。

    sudo apt-get update
    -sudo apt-get install ebtables
    -sudo apt-get install libxtables12
    -sudo apt-get upgrade iptables
    -

    检查当前可用的kubeadm版本。

    apt policy kubeadm
    -

    当前安装1.24.0-00 版本的kubeadm,后续会升级到 1.24.2 版本。

    sudo apt-get -y install kubelet=1.24.0-00 kubeadm=1.24.0-00 kubectl=1.24.0-00 --allow-downgrades
    -

    配置主节点

    kubeadm初始化

    在承担主节点的虚拟机里配置控制平面(Control Plane)。

    检查kubeadm 当前默认配置参数。

    kubeadm config print init-defaults
    -

    类似结果如下。保存默认配置的结果,后续会作为参考。

    apiVersion: kubeadm.k8s.io/v1beta3
    -bootstrapTokens:
    -- groups:
    -  - system:bootstrappers:kubeadm:default-node-token
    -  token: abcdef.0123456789abcdef
    -  ttl: 24h0m0s
    -  usages:
    -  - signing
    -  - authentication
    -kind: InitConfiguration
    -localAPIEndpoint:
    -  advertiseAddress: 1.2.3.4
    -  bindPort: 6443
    -nodeRegistration:
    -  criSocket: unix:///var/run/containerd/containerd.sock
    -  imagePullPolicy: IfNotPresent
    -  name: node
    -  taints: null
    ----
    -apiServer:
    -  timeoutForControlPlane: 4m0s
    -apiVersion: kubeadm.k8s.io/v1beta3
    -certificatesDir: /etc/kubernetes/pki
    -clusterName: kubernetes
    -controllerManager: {}
    -dns: {}
    -etcd:
    -  local:
    -    dataDir: /var/lib/etcd
    -imageRepository: k8s.gcr.io
    -kind: ClusterConfiguration
    -kubernetesVersion: 1.24.0
    -networking:
    -  dnsDomain: cluster.local
    -  serviceSubnet: 10.96.0.0/12
    -scheduler: {}
    -

    模拟安装和正式安装。

    通过命令 kubeadm init 进行主节点的初始化,下面是这个命令主要参数的说明,特别是网络参数的三个选择。

    • --pod-network-cidr:
    • 指定pod使用的IP地址范围。如果指定了该参数,则Control Plane会自动讲指定的CIDR分配给每个节点。
    • IP地址段 10.244.0.0/16 是Flannel网络组件默认的地址范围。如果需要修改Flannel的IP地址段,需要在这里指定,且在部署Flannel时也要保持一致的IP段。
    • --apiserver-bind-port:
    • API服务(API Server)的端口,默认时6443。
    • --service-cidr:
    • 指定服务(service)的IP地址段,默认是10.96.0.0/12

    提示:

    • 服务VIPs(service VIPs),也称作集群IP(Cluster IP),通过参数 --service-cidr指定。
    • podCIDR,也称为endpoint IP,通过参数 --pod-network-cidr指定。

    有4种典型的网络问题:

    • 高度耦合的容器与容器之间的通信:这可以通过Pod(podCIDR)和本地主机通信来解决。
    • Pod对Pod通信(Pod-to-Pod):
    • 也被称为容器对容器通信(container-to-container)。
    • 在Flannel网络插件中的示例流程是:Pod → veth对 → cni0 → flannel.1 → 宿主机eth0 → 宿主机eth0 → flannel.1 → cni0 → veth对 → Pod。
    • Pod对Service通信(Pod-to-Service):
    • 流程: Pod → 内核 → Service iptables → Service → Pod iptables → Pod。
    • 外部对Service通信(External-to-Service):
    • 负载均衡器: SLB → NodePort → Service → Pod。

    kube-proxy 是对iptables负责,不是网络流量(traffic)。

    • kube-proxy是Kubernetes集群中的一个组件,负责为Service提供代理服务,同时也是Kubernetes网络模型中的重要组成部分之一。kube-proxy会在每个节点上启动一个代理进程,通过监听Kubernetes API Server的Service和Endpoint的变化来维护一个本地的Service和Endpoint的缓存。当有请求到达某个Service时,kube-proxy会根据该Service的类型(ClusterIP、NodePort、LoadBalancer、ExternalName)和端口号,生成相应的iptables规则,将请求转发给Service所代理的后端Pod。

    • iptables是Linux系统中的一个重要网络工具,可以设置IP包的过滤、转发和修改规则,可以实现网络层的防火墙、NAT等功能。在Kubernetes集群中,kube-proxy通过生成和更新iptables规则,来实现Service和Endpoint之间的转发和代理。具体来说,kube-proxy会为每个Service创建三条iptables规则链(nat表中的KUBE-SERVICES和KUBE-NODEPORTS链,以及filter表中的KUBE-SVC-XXXXX链),通过这些规则链,将请求转发到相应的Pod或者Service上。

    • 因此,kube-proxy和iptables是紧密相关的两个组件,通过iptables规则来实现Service和Pod之间的转发和代理。这种实现方式具有可扩展性和高可用性,同时也提供了一种灵活的网络模型,可以方便地实现服务发现、负载均衡等功能。

    sudo kubeadm init \
    -  --dry-run \
    -  --pod-network-cidr=10.244.0.0/16 \
    -  --service-cidr 11.244.0.0/16 \
    -  --image-repository=registry.aliyuncs.com/google_containers \
    -  --kubernetes-version=v1.24.0
    +

    安装和升级Ubuntu系统依赖包。

    sudo apt-get update
    +sudo apt-get install ebtables
    +sudo apt-get install libxtables12
    +sudo apt-get upgrade iptables
    +

    检查当前可用的kubeadm版本。

    apt policy kubeadm
    +

    当前安装1.24.0-00 版本的kubeadm,后续会升级到 1.24.2 版本。

    sudo apt-get -y install kubelet=1.24.0-00 kubeadm=1.24.0-00 kubectl=1.24.0-00 --allow-downgrades
    +

    配置主节点

    kubeadm初始化

    在承担主节点的虚拟机里配置控制平面(Control Plane)。

    检查kubeadm 当前默认配置参数。

    kubeadm config print init-defaults
    +

    类似结果如下。保存默认配置的结果,后续会作为参考。

    apiVersion: kubeadm.k8s.io/v1beta3
    +bootstrapTokens:
    +- groups:
    +  - system:bootstrappers:kubeadm:default-node-token
    +  token: abcdef.0123456789abcdef
    +  ttl: 24h0m0s
    +  usages:
    +  - signing
    +  - authentication
    +kind: InitConfiguration
    +localAPIEndpoint:
    +  advertiseAddress: 1.2.3.4
    +  bindPort: 6443
    +nodeRegistration:
    +  criSocket: unix:///var/run/containerd/containerd.sock
    +  imagePullPolicy: IfNotPresent
    +  name: node
    +  taints: null
    +---
    +apiServer:
    +  timeoutForControlPlane: 4m0s
    +apiVersion: kubeadm.k8s.io/v1beta3
    +certificatesDir: /etc/kubernetes/pki
    +clusterName: kubernetes
    +controllerManager: {}
    +dns: {}
    +etcd:
    +  local:
    +    dataDir: /var/lib/etcd
    +imageRepository: k8s.gcr.io
    +kind: ClusterConfiguration
    +kubernetesVersion: 1.24.0
    +networking:
    +  dnsDomain: cluster.local
    +  serviceSubnet: 10.96.0.0/12
    +scheduler: {}
    +

    模拟安装和正式安装。

    通过命令 kubeadm init 进行主节点的初始化,下面是这个命令主要参数的说明,特别是网络参数的三个选择。

    • --pod-network-cidr:
    • 指定pod使用的IP地址范围。如果指定了该参数,则Control Plane会自动讲指定的CIDR分配给每个节点。
    • IP地址段 10.244.0.0/16 是Flannel网络组件默认的地址范围。如果需要修改Flannel的IP地址段,需要在这里指定,且在部署Flannel时也要保持一致的IP段。
    • --apiserver-bind-port:
    • API服务(API Server)的端口,默认时6443。
    • --service-cidr:
    • 指定服务(service)的IP地址段,默认是10.96.0.0/12

    提示:

    • 服务VIPs(service VIPs),也称作集群IP(Cluster IP),通过参数 --service-cidr指定。
    • podCIDR,也称为endpoint IP,通过参数 --pod-network-cidr指定。

    有4种典型的网络问题:

    • 高度耦合的容器与容器之间的通信:这可以通过Pod(podCIDR)和本地主机通信来解决。
    • Pod对Pod通信(Pod-to-Pod):
    • 也被称为容器对容器通信(container-to-container)。
    • 在Flannel网络插件中的示例流程是:Pod → veth对 → cni0 → flannel.1 → 宿主机eth0 → 宿主机eth0 → flannel.1 → cni0 → veth对 → Pod。
    • Pod对Service通信(Pod-to-Service):
    • 流程: Pod → 内核 → Service iptables → Service → Pod iptables → Pod。
    • 外部对Service通信(External-to-Service):
    • 负载均衡器: SLB → NodePort → Service → Pod。

    kube-proxy 是对iptables负责,不是网络流量(traffic)。

    • kube-proxy是Kubernetes集群中的一个组件,负责为Service提供代理服务,同时也是Kubernetes网络模型中的重要组成部分之一。kube-proxy会在每个节点上启动一个代理进程,通过监听Kubernetes API Server的Service和Endpoint的变化来维护一个本地的Service和Endpoint的缓存。当有请求到达某个Service时,kube-proxy会根据该Service的类型(ClusterIP、NodePort、LoadBalancer、ExternalName)和端口号,生成相应的iptables规则,将请求转发给Service所代理的后端Pod。

    • iptables是Linux系统中的一个重要网络工具,可以设置IP包的过滤、转发和修改规则,可以实现网络层的防火墙、NAT等功能。在Kubernetes集群中,kube-proxy通过生成和更新iptables规则,来实现Service和Endpoint之间的转发和代理。具体来说,kube-proxy会为每个Service创建三条iptables规则链(nat表中的KUBE-SERVICES和KUBE-NODEPORTS链,以及filter表中的KUBE-SVC-XXXXX链),通过这些规则链,将请求转发到相应的Pod或者Service上。

    • 因此,kube-proxy和iptables是紧密相关的两个组件,通过iptables规则来实现Service和Pod之间的转发和代理。这种实现方式具有可扩展性和高可用性,同时也提供了一种灵活的网络模型,可以方便地实现服务发现、负载均衡等功能。

    sudo kubeadm init \
    +  --dry-run \
    +  --pod-network-cidr=10.244.0.0/16 \
    +  --service-cidr 11.244.0.0/16 \
    +  --image-repository=registry.aliyuncs.com/google_containers \
    +  --kubernetes-version=v1.24.0
     
    -sudo kubeadm init \
    -  --pod-network-cidr=10.244.0.0/16 \
    -  --service-cidr 11.244.0.0/16 \
    -  --image-repository=registry.aliyuncs.com/google_containers \
    -  --kubernetes-version=v1.24.0
    +sudo kubeadm init \
    +  --pod-network-cidr=10.244.0.0/16 \
    +  --service-cidr 11.244.0.0/16 \
    +  --image-repository=registry.aliyuncs.com/google_containers \
    +  --kubernetes-version=v1.24.0
     
    -sudo kubeadm init \
    -  --pod-network-cidr=10.244.0.0/16 \
    -  --service-cidr 11.244.0.0/16 \
    -  --kubernetes-version=v1.24.0
    -

    kubeconfig文件

    给当前安装用户配置 kubeconfig 文件(当前例子是用户vagrant)。

    mkdir -p $HOME/.kube
    -sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    -sudo chown $(id -u):$(id -g) $HOME/.kube/config
    -

    Kubernetes 提供了一个命令行工具kubectl,用于使用 Kubernetes API 与 Kubernetes 集群的控制平面进行通信。

    kubectl 控制 Kubernetes cluster manager(集群管理器)。

    对于配置,kubectl 在 $HOME/.kube目录中查找一个名为 config 的文件,该文件是由 kubeadm init生成的文件 /etc/kubernetes/admin.conf的副本。

    我们可以通过设置 KUBECONFIG环境变量或设置 --kubeconfig flag标志来指定其他 kubeconfig 文件。如果 KUBECONFIG 环境变量不存在,kubectl 将使用默认的 kubeconfig 文件 $HOME/.kube/config

    kubeconfig 文件中的 context(上下文) 元素用于将访问参数分组到一个方便的名称下。每个上下文都有三个参数:集群、命名空间和用户。默认情况下,kubectl 命令行工具使用当前上下文中的参数与集群通信。

    文件.kube/config的例子:

    apiVersion: v1
    -clusters:
    -- cluster:
    -    certificate-authority-data: <certificate string>
    -    server: https://<eth0 ip>:6443
    -  name: <cluster name>
    -contexts:
    -- context:
    -    cluster: <cluster name>
    -    namespace: <namespace name>
    -    user: <user name>
    -  name: <context user>@<context name>
    -current-context: <context name>
    -kind: Config
    -preferences: {}
    -users:
    -- name: <user name>
    -  user:
    -    client-certificate-data: <certificate string>
    -    client-key-data: <certificate string>
    -

    读取当前上下文:

    kubectl config get-contexts
    +sudo kubeadm init \
    +  --pod-network-cidr=10.244.0.0/16 \
    +  --service-cidr 11.244.0.0/16 \
    +  --kubernetes-version=v1.24.0
    +

    kubeconfig文件

    给当前安装用户配置 kubeconfig 文件(当前例子是用户vagrant)。

    mkdir -p $HOME/.kube
    +sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    +sudo chown $(id -u):$(id -g) $HOME/.kube/config
    +

    Kubernetes 提供了一个命令行工具kubectl,用于使用 Kubernetes API 与 Kubernetes 集群的控制平面进行通信。

    kubectl 控制 Kubernetes cluster manager(集群管理器)。

    对于配置,kubectl 在 $HOME/.kube目录中查找一个名为 config 的文件,该文件是由 kubeadm init生成的文件 /etc/kubernetes/admin.conf的副本。

    我们可以通过设置 KUBECONFIG环境变量或设置 --kubeconfig flag标志来指定其他 kubeconfig 文件。如果 KUBECONFIG 环境变量不存在,kubectl 将使用默认的 kubeconfig 文件 $HOME/.kube/config

    kubeconfig 文件中的 context(上下文) 元素用于将访问参数分组到一个方便的名称下。每个上下文都有三个参数:集群、命名空间和用户。默认情况下,kubectl 命令行工具使用当前上下文中的参数与集群通信。

    文件.kube/config的例子:

    apiVersion: v1
    +clusters:
    +- cluster:
    +    certificate-authority-data: <certificate string>
    +    server: https://<eth0 ip>:6443
    +  name: <cluster name>
    +contexts:
    +- context:
    +    cluster: <cluster name>
    +    namespace: <namespace name>
    +    user: <user name>
    +  name: <context user>@<context name>
    +current-context: <context name>
    +kind: Config
    +preferences: {}
    +users:
    +- name: <user name>
    +  user:
    +    client-certificate-data: <certificate string>
    +    client-key-data: <certificate string>
    +

    读取当前上下文:

    kubectl config get-contexts
     

    运行结果:

    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
     *         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   
    -

    配置工作节点

    使用 kubeadm token 来生成加入集群的令牌(token)和哈西值(hash value)。

    kubeadm token create --print-join-command
    +

    配置工作节点

    使用 kubeadm token 来生成加入集群的令牌(token)和哈西值(hash value)。

    kubeadm token create --print-join-command
     

    在所有工作节点上执行下面的命令,将工作节点加入Kubernetes集群。

    # kubeadm join <your master node eth0 ip>:6443 --token <token generated by kubeadm init> --discovery-token-ca-cert-hash <hash key generated by kubeadm init>
    -

    执行下面命令检查所有节点的状态。 当前所有节点的状态都是 NotReady。目前不需要做什么,后面我们会安装相关的网络服务(Calico 或 Flannel),各节点的状态就会变成Ready状态。

    安装Calico或Flannel

    在控制平面Control Plane上安装Calico或者Flannel。如果需要配置网络策略,则选择Calico。

    安装Flannel

    Flannel 是为 Kubernetes 设计的一种简单易用的配置三层网络的方法。

    部署Flannel:

    kube-flannel.yml 中,我们可以获取 Flannel 的默认网络设置,它与我们在使用 kubeadm 初始化集群时指定的参数 --pod-network-cidr=10.244.0.0/16 相同。

      net-conf.json: |
    -    {
    -      "Network": "10.244.0.0/16",
    -      "Backend": {
    -        "Type": "vxlan"
    -      }
    -    }
    -

    创建Flannel服务。

    apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    +

    执行下面命令检查所有节点的状态。 当前所有节点的状态都是 NotReady。目前不需要做什么,后面我们会安装相关的网络服务(Calico 或 Flannel),各节点的状态就会变成Ready状态。

    安装Calico或Flannel

    在控制平面Control Plane上安装Calico或者Flannel。如果需要配置网络策略,则选择Calico。

    安装Flannel

    Flannel 是为 Kubernetes 设计的一种简单易用的配置三层网络的方法。

    部署Flannel:

    kube-flannel.yml 中,我们可以获取 Flannel 的默认网络设置,它与我们在使用 kubeadm 初始化集群时指定的参数 --pod-network-cidr=10.244.0.0/16 相同。

      net-conf.json: |
    +    {
    +      "Network": "10.244.0.0/16",
    +      "Backend": {
    +        "Type": "vxlan"
    +      }
    +    }
    +

    创建Flannel服务。

    apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
     

    输出结果:

    Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
     podsecuritypolicy.policy/psp.flannel.unprivileged created
     clusterrole.rbac.authorization.k8s.io/flannel created
    @@ -196,8 +196,8 @@
     serviceaccount/flannel created
     configmap/kube-flannel-cfg created
     daemonset.apps/kube-flannel-ds created
    -

    安装Calico

    安装指导手册:End-to-end Calico installation

    下载并安装Calico服务。

    curl https://docs.projectcalico.org/manifests/calico.yaml -O
    -kubectl apply -f calico.yaml
    +

    安装Calico

    安装指导手册:End-to-end Calico installation

    下载并安装Calico服务。

    curl https://docs.projectcalico.org/manifests/calico.yaml -O
    +kubectl apply -f calico.yaml
     

    输出结果:

    configmap/calico-config created
     customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
     customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
    @@ -225,24 +225,24 @@
     deployment.apps/calico-kube-controllers created
     serviceaccount/calico-kube-controllers created
     poddisruptionbudget.policy/calico-kube-controllers created
    -

    验证Calico服务状态:

    kubectl get pod -n kube-system | grep calico
    -

    输出结果:

    calico-kube-controllers-555bc4b957-l8bn2   0/1     Pending    0          28s
    -calico-node-255pc                          0/1     Init:1/3   0          29s
    -calico-node-7tmnb                          0/1     Init:1/3   0          29s
    -calico-node-w8nvl                          0/1     Init:1/3   0          29s
    -

    检查集群的网络状态:

    sudo nerdctl network ls
    +

    验证Calico服务状态:

    kubectl get pod -n kube-system | grep calico
    +

    输出结果:

    calico-kube-controllers-555bc4b957-l8bn2   0/1     Pending    0          28s
    +calico-node-255pc                          0/1     Init:1/3   0          29s
    +calico-node-7tmnb                          0/1     Init:1/3   0          29s
    +calico-node-w8nvl                          0/1     Init:1/3   0          29s
    +

    检查集群的网络状态:

    sudo nerdctl network ls
     

    输出结果:

    NETWORK ID    NAME               FILE
                   k8s-pod-network    /etc/cni/net.d/10-calico.conflist
     0             bridge             /etc/cni/net.d/nerdctl-bridge.conflist
                   host               
                   none 
    -

    检查集群状态

    在主节点上执行命令kubectl cluster-info 可以得到下面的信息:

    • 控制平面(control plane)运行在 https://<mster node ip>:6443
    • CoreDNS服务运行在 https://<mster node ip>:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    kubectl cluster-info
    -

    查看节点运行状态。此时,所有节点都是Ready的正常状态了。

    • OS Image: Ubuntu 20.04.4 LTS
    • Kernel Version: 5.4.0-122-generic
    • Container Runtime: containerd://1.5.9
    kubectl get nodes -owide
    +

    检查集群状态

    在主节点上执行命令kubectl cluster-info 可以得到下面的信息:

    • 控制平面(control plane)运行在 https://<mster node ip>:6443
    • CoreDNS服务运行在 https://<mster node ip>:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    kubectl cluster-info
    +

    查看节点运行状态。此时,所有节点都是Ready的正常状态了。

    • OS Image: Ubuntu 20.04.4 LTS
    • Kernel Version: 5.4.0-122-generic
    • Container Runtime: containerd://1.5.9
    kubectl get nodes -owide
     

    输出结果:

    NAME     STATUS   ROLES           AGE     VERSION
     cka001   Ready    control-plane   13m     v1.24.0
     cka002   Ready    <none>          8m35s   v1.24.0
     cka003   Ready    <none>          8m26s   v1.24.0
    -

    查看Pods的状态。

    kubectl get pod -A
    +

    查看Pods的状态。

    kubectl get pod -A
     

    输出结果:

    NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
     kube-system   calico-kube-controllers-555bc4b957-l8bn2   1/1     Running   0          7m18s
     kube-system   calico-node-255pc                          1/1     Running   0          7m19s
    @@ -257,39 +257,39 @@
     kube-system   kube-proxy-n77zw                           1/1     Running   0          11m
     kube-system   kube-proxy-qs6rf                           1/1     Running   0          11m
     kube-system   kube-scheduler-cka001                      1/1     Running   0          15m
    -

    更新安装

    Bash自动补全

    在每个节点上配置Bash自动补全功能。

    参考指导设置 kubectl 自动补全功能auto-completion

    apt install -y bash-completion
    +

    更新安装

    Bash自动补全

    在每个节点上配置Bash自动补全功能。

    参考指导设置 kubectl 自动补全功能auto-completion

    apt install -y bash-completion
     
    -source /usr/share/bash-completion/bash_completion
    -source <(kubectl completion bash)
    +source /usr/share/bash-completion/bash_completion
    +source <(kubectl completion bash)
     
    -echo "source <(kubectl completion bash)" >> ~/.bashrc
    -source ~/.bashrc
    -

    别名

    如果我们为 kubectl 设置一个别名,我们可以通过一些方法来扩展 shell 自动补全功能,使其能够与该别名一起使用。

    一种方法是在 Bash shell 配置文件(如 .bashrc 或 .bash_profile)中设置别名,并为该别名指定 kubectl 的完整路径。例如,可以在 .bashrc 文件中添加以下内容:

    alias k='path/to/kubectl'
    -

    然后,可以使用以下命令重新加载 .bashrc 文件:

    source ~/.bashrc
    -

    接下来,可以使用k命令来代替kubectl命令,并在其后面添加相应的参数和选项。当使用自动补全功能时,Bash shell 会自动将k别名转换为 kubectl 的完整路径,并对其进行自动补全。

    另一种方法是使用 Bash shell 内置的 complete 函数来为别名设置自动补全功能。例如,可以在 .bashrc 文件中添加以下内容:

    echo 'alias k=kubectl' >>~/.bashrc
    -echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
    -

    这将为别名k设置自动补全功能,并将其与 kubectl 的自动补全函数__start_kubectl关联起来。这样,当用户在k命令后输入Tab键时,Bash shell 会自动调用__start_kubectl函数,并为用户提供相应的自动补全建议。

    更新默认Context

    查看当前的 context 列表:

    kubectl config get-contexts 
    +echo "source <(kubectl completion bash)" >> ~/.bashrc
    +source ~/.bashrc
    +

    别名

    如果我们为 kubectl 设置一个别名,我们可以通过一些方法来扩展 shell 自动补全功能,使其能够与该别名一起使用。

    一种方法是在 Bash shell 配置文件(如 .bashrc 或 .bash_profile)中设置别名,并为该别名指定 kubectl 的完整路径。例如,可以在 .bashrc 文件中添加以下内容:

    alias k='path/to/kubectl'
    +

    然后,可以使用以下命令重新加载 .bashrc 文件:

    source ~/.bashrc
    +

    接下来,可以使用k命令来代替kubectl命令,并在其后面添加相应的参数和选项。当使用自动补全功能时,Bash shell 会自动将k别名转换为 kubectl 的完整路径,并对其进行自动补全。

    另一种方法是使用 Bash shell 内置的 complete 函数来为别名设置自动补全功能。例如,可以在 .bashrc 文件中添加以下内容:

    echo 'alias k=kubectl' >>~/.bashrc
    +echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
    +

    这将为别名k设置自动补全功能,并将其与 kubectl 的自动补全函数__start_kubectl关联起来。这样,当用户在k命令后输入Tab键时,Bash shell 会自动调用__start_kubectl函数,并为用户提供相应的自动补全建议。

    更新默认Context

    查看当前的 context 列表:

    kubectl config get-contexts 
     

    这个命令会列出所有可用的 context 列表,并标记出当前正在使用的 context。

    类似下面结果:

    • kubernetes-admin@kubernetes是Context名。
    • kubernetes是集群名。
    • kubernetes-admin是用户名。
    • 当前例子中没有指定名称空间。
    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
     *         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin 
     

    更新context。例如,更新context的默认名称空间等。

    # Usage:
    -kubectl config set-context <context name> --cluster=<cluster name> --namespace=<namespace name> --user=<user name> 
    +kubectl config set-context <context name> --cluster=<cluster name> --namespace=<namespace name> --user=<user name> 
     
     # Set default namespace
    -kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin
    +kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin
     

    在不同的context之间切换。

    # Usage:
    -kubectl config use-context <context name>
    +kubectl config use-context <context name>
     
     # Switch to new context
    -kubectl config use-context kubernetes-admin@kubernetes
    -

    参考资料:

    重置集群

    注意:下面的操作会重置当前集群(删除集群)。

    删除集群中所有节点。

    kubeadm reset
    -

    清除iptables中已定义的规则。

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    -

    清除IPVS中定义的规则(如果使用IPVS)。

    ipvsadm --clear 
    -

    排错

    错误1

    报错信息:

    The connection to the server <master>:6443 was refused - did you specify the right host or port?

    解决尝试:

    Reference

    检查文件kubeconfig的内容和文件路径是否正确。

    检查环境变量设置。

    env | grep -i kub
    -

    检查容器运行状态。

    sudo systemctl status containerd.service 
    -

    检查kubelet服务。

    sudo systemctl status kubelet.service 
    -

    检查6443端口监听状态。

    netstat -pnlt | grep 6443
    -

    检查防火墙状态。

    sudo systemctl status firewalld.service
    -

    检查kubelet日志。

    journalctl -xeu kubelet
    -

    错误2

    报错信息:

    "Container runtime network not ready" networkReady="NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized"

    尝试方法:

    重启Containerd服务。

    sudo systemctl restart containerd
    -sudo systemctl status containerd
    -
    \ No newline at end of file +kubectl config use-context kubernetes-admin@kubernetes +

    参考资料:

    重置集群

    注意:下面的操作会重置当前集群(删除集群)。

    删除集群中所有节点。

    kubeadm reset
    +

    清除iptables中已定义的规则。

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    +

    清除IPVS中定义的规则(如果使用IPVS)。

    ipvsadm --clear 
    +

    排错

    错误1

    报错信息:

    The connection to the server <master>:6443 was refused - did you specify the right host or port?

    解决尝试:

    Reference

    检查文件kubeconfig的内容和文件路径是否正确。

    检查环境变量设置。

    env | grep -i kub
    +

    检查容器运行状态。

    sudo systemctl status containerd.service 
    +

    检查kubelet服务。

    sudo systemctl status kubelet.service 
    +

    检查6443端口监听状态。

    netstat -pnlt | grep 6443
    +

    检查防火墙状态。

    sudo systemctl status firewalld.service
    +

    检查kubelet日志。

    journalctl -xeu kubelet
    +

    错误2

    报错信息:

    "Container runtime network not ready" networkReady="NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized"

    尝试方法:

    重启Containerd服务。

    sudo systemctl restart containerd
    +sudo systemctl status containerd
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/installation/multiple-local/index.html b/k8s/cka_cn/installation/multiple-local/index.html index e18857de..82d14ea9 100644 --- a/k8s/cka_cn/installation/multiple-local/index.html +++ b/k8s/cka_cn/installation/multiple-local/index.html @@ -1,76 +1,76 @@ - 多节点虚拟机安装Kubernetes - UPSkilling

    CKA自学笔记2:多节点虚拟机安装Kubernetes

    摘要

    在本地Windows环境中,通过VMWare安装三台Ubuntu虚拟机。在Ubuntu虚拟机中安装基于Containerd的Kubernetes系统,并分别配置一个主节点Master和两个工作节点Worker。

    本地虚拟机设置

    VMWare 设置

    • VMnet1: host-only模式, 网络subnet: 192.168.150.0/24
    • VMnet8: NAT模式, 网络subnet: 11.0.1.0/24

    通过VMWare创建客户虚拟机。

    • 内存:4 GB
    • CPU:1 CPUs with 2 Cores
    • 操作系统:Ubuntu Server 22.04
    • 网络:NAT

    提示:

    当前练习中,Kubernetes是基于Containerd,不是Docker。

    Ubuntu预配置

    注意:下面的任务,需要在每台虚拟机中执行一次。以下简称虚拟机为节点。

    在所有节点中创建用户vagrant

    sudo adduser vagrant
    -sudo usermod -g sudo vagrant
    -sudo usermod -a -G root vagrant
    -sudo passwd vagrant
    -

    在所有节点中设置用户root的密码。

    sudo passwd root
    -

    修改ssh服务的配置文件。开放root用户通过ssh登录(默认是禁用的)。

    sudo vi /etc/ssh/sshd_config
    + 多节点虚拟机安装Kubernetes - UPSkilling       

    CKA自学笔记2:多节点虚拟机安装Kubernetes

    摘要

    在本地Windows环境中,通过VMWare安装三台Ubuntu虚拟机。在Ubuntu虚拟机中安装基于Containerd的Kubernetes系统,并分别配置一个主节点Master和两个工作节点Worker。

    本地虚拟机设置

    VMWare 设置

    • VMnet1: host-only模式, 网络subnet: 192.168.150.0/24
    • VMnet8: NAT模式, 网络subnet: 11.0.1.0/24

    通过VMWare创建客户虚拟机。

    • 内存:4 GB
    • CPU:1 CPUs with 2 Cores
    • 操作系统:Ubuntu Server 22.04
    • 网络:NAT

    提示:

    当前练习中,Kubernetes是基于Containerd,不是Docker。

    Ubuntu预配置

    注意:下面的任务,需要在每台虚拟机中执行一次。以下简称虚拟机为节点。

    在所有节点中创建用户vagrant

    sudo adduser vagrant
    +sudo usermod -g sudo vagrant
    +sudo usermod -a -G root vagrant
    +sudo passwd vagrant
    +

    在所有节点中设置用户root的密码。

    sudo passwd root
    +

    修改ssh服务的配置文件。开放root用户通过ssh登录(默认是禁用的)。

    sudo vi /etc/ssh/sshd_config
     

    把参数 PermitRootLogin的值从prohibit-password 改为yes

    PermitRootLogin yes
    -#PermitRootLogin prohibit-password
    -

    重新启动sshd服务。

    sudo systemctl restart sshd
    -

    更改主机名,这里是ubu1.

    sudo hostnamectl set-hostname ubu1
    -sudo hostnamectl set-hostname ubu1 --pretty
    -

    验证主机名是否被正确修改了,比如改为ubu1

    cat /etc/machine-info
    -

    验证主机名是否被正确修改了,比如改为ubu1

    cat /etc/hostname
    -

    验证主机IP地址127.0.1.1 已经配置给当前节点,比如ubu1。同时,在所有节点的 /etc/hosts文件中添加其他节点的IP和主机对应信息。

    sudo vi /etc/hosts
    +#PermitRootLogin prohibit-password
    +

    重新启动sshd服务。

    sudo systemctl restart sshd
    +

    更改主机名,这里是ubu1.

    sudo hostnamectl set-hostname ubu1
    +sudo hostnamectl set-hostname ubu1 --pretty
    +

    验证主机名是否被正确修改了,比如改为ubu1

    cat /etc/machine-info
    +

    验证主机名是否被正确修改了,比如改为ubu1

    cat /etc/hostname
    +

    验证主机IP地址127.0.1.1 已经配置给当前节点,比如ubu1。同时,在所有节点的 /etc/hosts文件中添加其他节点的IP和主机对应信息。

    sudo vi /etc/hosts
     

    以当前练习为例,修改后的/etc/hosts文件类似如下内容。

    127.0.1.1 ubu1
     11.0.1.129 ubu1
     11.0.1.130 ubu2
     11.0.1.131 ubu3
     11.0.1.132 ubu4
    -

    创建文件/etc/netplan/00-installer-config.yaml

    sudo vi /etc/netplan/00-installer-config.yaml
    -

    更新此文件,设定当前节点使用固定IP地址,比如,11.0.1.129

    network:
    -  ethernets:
    -    ens33:
    -      dhcp4: false
    -      addresses:
    -      - 11.0.1.129/24
    -      nameservers:
    -        addresses:
    -        - 11.0.1.2
    -      routes:
    -      - to: default
    -        via: 11.0.1.2
    -  version: 2
    -

    执行下面命令时,使上述改动生效。注意,当前ssh连接会因此而断开。

    sudo netplan apply
    -

    在所有节点禁用交换分区swap和防火墙firewall。

    sudo swapoff -a
    -sudo ufw disable
    -sudo ufw status verbose
    -

    在所有节点的文件 /etc/fstab中注释掉涉及swap的那一行,修改后需要重启当前节点。

    sudo vi /etc/fstab
    +

    创建文件/etc/netplan/00-installer-config.yaml

    sudo vi /etc/netplan/00-installer-config.yaml
    +

    更新此文件,设定当前节点使用固定IP地址,比如,11.0.1.129

    network:
    +  ethernets:
    +    ens33:
    +      dhcp4: false
    +      addresses:
    +      - 11.0.1.129/24
    +      nameservers:
    +        addresses:
    +        - 11.0.1.2
    +      routes:
    +      - to: default
    +        via: 11.0.1.2
    +  version: 2
    +

    执行下面命令时,使上述改动生效。注意,当前ssh连接会因此而断开。

    sudo netplan apply
    +

    在所有节点禁用交换分区swap和防火墙firewall。

    sudo swapoff -a
    +sudo ufw disable
    +sudo ufw status verbose
    +

    在所有节点的文件 /etc/fstab中注释掉涉及swap的那一行,修改后需要重启当前节点。

    sudo vi /etc/fstab
     

    修改后的结果类似如下。

    /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1
    -# /swap.img     none    swap    sw      0       0
    -

    在所有节点设置统一的时区。

    sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    +# /swap.img     none    swap    sw      0       0
    +

    在所有节点设置统一的时区。

    sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
     
    -sudo cp /etc/profile /etc/profile.bak
    -echo 'LANG="en_US.UTF-8"' | sudo tee -a /etc/profile
    +sudo cp /etc/profile /etc/profile.bak
    +echo 'LANG="en_US.UTF-8"' | sudo tee -a /etc/profile
     
    -source /etc/profile
    +source /etc/profile
     

    执行命令 ll /etc/localtime来验证时区是否修改正确。

    lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
    -

    在所有节点修改内核设置。

    cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
    +

    在所有节点修改内核设置。

    cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
     overlay
     br_netfilter
     EOF
    -

    手动将需要的这2个模块载入内核。

    sudo modprobe overlay
    -sudo modprobe br_netfilter
    -

    在所有节点修改网络设置。

    cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
    +

    手动将需要的这2个模块载入内核。

    sudo modprobe overlay
    +sudo modprobe br_netfilter
    +

    在所有节点修改网络设置。

    cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
     net.bridge.bridge-nf-call-iptables  = 1
     net.ipv4.ip_forward                 = 1
     net.bridge.bridge-nf-call-ip6tables = 1
     EOF
    -

    生效上述修改。

    sudo sysctl --system
    -

    注意:

    重启当前节点,节点重启后,用账号vagrant 做如下验证,确保上述修改已生效。

    • IP地址。
      ip addr list
    -
    • 主机名。
    cat /etc/machine-info
    -cat /etc/hostname
    +

    生效上述修改。

    sudo sysctl --system
    +

    注意:

    重启当前节点,节点重启后,用账号vagrant 做如下验证,确保上述修改已生效。

    • IP地址。
      ip addr list
    +
    • 主机名。
    cat /etc/machine-info
    +cat /etc/hostname
     hostname
    -
    • 防火墙。
    sudo ufw status verbose
    -
    • 内核。
    lsmod | grep -i overlay
    -lsmod | grep -i br_netfilter
    -
    • 网络。
    sudo sysctl -a | grep -i net.bridge.bridge-nf-call-ip*
    -sudo sysctl -a | grep -i net.ipv4.ip_forward
    -

    安装Containerd

    在所有节点上安装Containerd服务。

    备份Ubuntu安装源的原文件。

    sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
    -

    安装Containered。

    sudo apt-get update && sudo apt-get install -y containerd
    -

    修改文件/etc/containerd/config.toml来配置Contanerd服务,如果没有,就创建这个文件。

    sudo mkdir -p /etc/containerd
    -containerd config default | sudo tee /etc/containerd/config.toml
    -sudo vi /etc/containerd/config.toml
    +
    • 防火墙。
    sudo ufw status verbose
    +
    • 内核。
    lsmod | grep -i overlay
    +lsmod | grep -i br_netfilter
    +
    • 网络。
    sudo sysctl -a | grep -i net.bridge.bridge-nf-call-ip*
    +sudo sysctl -a | grep -i net.ipv4.ip_forward
    +

    安装Containerd

    在所有节点上安装Containerd服务。

    备份Ubuntu安装源的原文件。

    sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
    +

    安装Containered。

    sudo apt-get update && sudo apt-get install -y containerd
    +

    修改文件/etc/containerd/config.toml来配置Contanerd服务,如果没有,就创建这个文件。

    sudo mkdir -p /etc/containerd
    +containerd config default | sudo tee /etc/containerd/config.toml
    +sudo vi /etc/containerd/config.toml
     

    更新sandbox_image的值为"registry.aliyuncs.com/google_containers/pause:3.6",以使用国内阿里云的源。 更新SystemdCgroup 的值为 true,以使用Cgroup。

    [plugins]
       [plugins."io.containerd.gc.v1.scheduler"]
     
    @@ -86,100 +86,100 @@
     
               [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
                 SystemdCgroup = true
    -

    重启Containerd 服务。

    sudo systemctl restart containerd
    -sudo systemctl status containerd
    -

    安装nerdctl

    在所有节点上安装nerdctl服务。

    nerdctl 服务支持Contanerd所提供的容器化特性,特别是一些Docker不具备的新特性。

    二进制安装包可以通过这个链接取得: https://github.com/containerd/nerdctl/releases

    wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-0.22.2-linux-amd64.tar.gz
    -tar -zxvf nerdctl-0.22.2-linux-amd64.tar.gz
    -sudo cp nerdctl /usr/bin/
    -

    验证nerdctl服务。

    sudo nerdctl --help
    -

    列出初始安装Kubernetes时的容器container列表。

    sudo nerdctl -n k8s.io ps
    -

    安装Kubernetes

    在所有节点上安装Kubeadm,kubectl,kubelet。

    安装和升级Ubuntu系统依赖包。

    sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl
    -sudo apt-get update
    -sudo apt-get install ebtables
    -sudo apt-get install libxtables12
    -sudo apt-get upgrade iptables
    -

    安装gpg证书。

    curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - 
    -

    添加Kubernetes安装源。

    cat << EOF > /etc/apt/sources.list.d/kubernetes.list
    +

    重启Containerd 服务。

    sudo systemctl restart containerd
    +sudo systemctl status containerd
    +

    安装nerdctl

    在所有节点上安装nerdctl服务。

    nerdctl 服务支持Contanerd所提供的容器化特性,特别是一些Docker不具备的新特性。

    二进制安装包可以通过这个链接取得: https://github.com/containerd/nerdctl/releases

    wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-0.22.2-linux-amd64.tar.gz
    +tar -zxvf nerdctl-0.22.2-linux-amd64.tar.gz
    +sudo cp nerdctl /usr/bin/
    +

    验证nerdctl服务。

    sudo nerdctl --help
    +

    列出初始安装Kubernetes时的容器container列表。

    sudo nerdctl -n k8s.io ps
    +

    安装Kubernetes

    在所有节点上安装Kubeadm,kubectl,kubelet。

    安装和升级Ubuntu系统依赖包。

    sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl
    +sudo apt-get update
    +sudo apt-get install ebtables
    +sudo apt-get install libxtables12
    +sudo apt-get upgrade iptables
    +

    安装gpg证书。

    curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - 
    +

    添加Kubernetes安装源。

    cat << EOF > /etc/apt/sources.list.d/kubernetes.list
     deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
     EOF
    -

    检查当前kubeadm的版本。

    apt policy kubeadm
    -

    安装1.24.1-00 版本的kubeadm.

    sudo apt-get -y install kubelet=1.24.1-00 kubeadm=1.24.1-00 kubectl=1.24.1-00 --allow-downgrades
    -

    配置主节点

    kubeadm初始化

    在承担主节点的虚拟机里配置控制平面(Control Plane)。

    检查kubeadm当前默认配置参数。

    kubeadm config print init-defaults
    -

    类似结果如下。保存默认配置的结果,后续会作为参考。

    apiVersion: kubeadm.k8s.io/v1beta3
    -bootstrapTokens:
    -- groups:
    -  - system:bootstrappers:kubeadm:default-node-token
    -  token: abcdef.0123456789abcdef
    -  ttl: 24h0m0s
    -  usages:
    -  - signing
    -  - authentication
    -kind: InitConfiguration
    -localAPIEndpoint:
    -  advertiseAddress: 1.2.3.4
    -  bindPort: 6443
    -nodeRegistration:
    -  criSocket: unix:///var/run/containerd/containerd.sock
    -  imagePullPolicy: IfNotPresent
    -  name: node
    -  taints: null
    ----
    -apiServer:
    -  timeoutForControlPlane: 4m0s
    -apiVersion: kubeadm.k8s.io/v1beta3
    -certificatesDir: /etc/kubernetes/pki
    -clusterName: kubernetes
    -controllerManager: {}
    -dns: {}
    -etcd:
    -  local:
    -    dataDir: /var/lib/etcd
    -imageRepository: k8s.gcr.io
    -kind: ClusterConfiguration
    -kubernetesVersion: 1.24.0
    -networking:
    -  dnsDomain: cluster.local
    -  serviceSubnet: 10.96.0.0/12
    -scheduler: {}
    -

    模拟安装和正式安装。

    通过命令 kubeadm init 进行主节点的初始化,下面是这个命令主要参数的说明,特别是网络参数的三个选择。

    • --pod-network-cidr:
    • 指定pod使用的IP地址范围。如果指定了该参数,则Control Plane会自动讲指定的CIDR分配给每个节点。
    • IP地址段 10.244.0.0/16 是Flannel网络组件默认的地址范围。如果需要修改Flannel的IP地址段,需要在这里指定,且在部署Flannel时也要保持一致的IP段。
    • --apiserver-bind-port:
    • API服务(API Server)的端口,默认时6443。
    • --service-cidr:
    • 指定服务(service)的IP地址段,默认是10.96.0.0/12

    提示:

    • 服务VIPs(service VIPs),也称作集群IP(Cluster IP),通过参数 --service-cidr指定。
    • podCIDR,也称为endpoint IP,通过参数 --pod-network-cidr指定。

    有4种典型的网络问题:

    • 高度耦合的容器与容器之间的通信:这可以通过Pod(podCIDR)和本地主机通信来解决。
    • Pod对Pod通信(Pod-to-Pod):
    • 也被称为容器对容器通信(container-to-container)。
    • 在Flannel网络插件中的示例流程是:Pod → veth对 → cni0 → flannel.1 → 宿主机eth0 → 宿主机eth0 → flannel.1 → cni0 → veth对 → Pod。
    • Pod对Service通信(Pod-to-Service):
    • 流程: Pod → 内核 → Service iptables → Service → Pod iptables → Pod。
    • 外部对Service通信(External-to-Service):
    • 负载均衡器: SLB → NodePort → Service → Pod。

    kube-proxy 是对iptables负责,不是网络流量(traffic)。

    • kube-proxy是Kubernetes集群中的一个组件,负责为Service提供代理服务,同时也是Kubernetes网络模型中的重要组成部分之一。kube-proxy会在每个节点上启动一个代理进程,通过监听Kubernetes API Server的Service和Endpoint的变化来维护一个本地的Service和Endpoint的缓存。当有请求到达某个Service时,kube-proxy会根据该Service的类型(ClusterIP、NodePort、LoadBalancer、ExternalName)和端口号,生成相应的iptables规则,将请求转发给Service所代理的后端Pod。

    • iptables是Linux系统中的一个重要网络工具,可以设置IP包的过滤、转发和修改规则,可以实现网络层的防火墙、NAT等功能。在Kubernetes集群中,kube-proxy通过生成和更新iptables规则,来实现Service和Endpoint之间的转发和代理。具体来说,kube-proxy会为每个Service创建三条iptables规则链(nat表中的KUBE-SERVICES和KUBE-NODEPORTS链,以及filter表中的KUBE-SVC-XXXXX链),通过这些规则链,将请求转发到相应的Pod或者Service上。

    • 因此,kube-proxy和iptables是紧密相关的两个组件,通过iptables规则来实现Service和Pod之间的转发和代理。这种实现方式具有可扩展性和高可用性,同时也提供了一种灵活的网络模型,可以方便地实现服务发现、负载均衡等功能。

    sudo kubeadm init \
    -  --dry-run \
    -  --pod-network-cidr=10.244.0.0/16 \
    -  --service-cidr=192.244.0.0/16 \
    -  --image-repository=registry.aliyuncs.com/google_containers \
    -  --kubernetes-version=v1.24.0
    +

    检查当前kubeadm的版本。

    apt policy kubeadm
    +

    安装1.24.1-00 版本的kubeadm.

    sudo apt-get -y install kubelet=1.24.1-00 kubeadm=1.24.1-00 kubectl=1.24.1-00 --allow-downgrades
    +

    配置主节点

    kubeadm初始化

    在承担主节点的虚拟机里配置控制平面(Control Plane)。

    检查kubeadm当前默认配置参数。

    kubeadm config print init-defaults
    +

    类似结果如下。保存默认配置的结果,后续会作为参考。

    apiVersion: kubeadm.k8s.io/v1beta3
    +bootstrapTokens:
    +- groups:
    +  - system:bootstrappers:kubeadm:default-node-token
    +  token: abcdef.0123456789abcdef
    +  ttl: 24h0m0s
    +  usages:
    +  - signing
    +  - authentication
    +kind: InitConfiguration
    +localAPIEndpoint:
    +  advertiseAddress: 1.2.3.4
    +  bindPort: 6443
    +nodeRegistration:
    +  criSocket: unix:///var/run/containerd/containerd.sock
    +  imagePullPolicy: IfNotPresent
    +  name: node
    +  taints: null
    +---
    +apiServer:
    +  timeoutForControlPlane: 4m0s
    +apiVersion: kubeadm.k8s.io/v1beta3
    +certificatesDir: /etc/kubernetes/pki
    +clusterName: kubernetes
    +controllerManager: {}
    +dns: {}
    +etcd:
    +  local:
    +    dataDir: /var/lib/etcd
    +imageRepository: k8s.gcr.io
    +kind: ClusterConfiguration
    +kubernetesVersion: 1.24.0
    +networking:
    +  dnsDomain: cluster.local
    +  serviceSubnet: 10.96.0.0/12
    +scheduler: {}
    +

    模拟安装和正式安装。

    通过命令 kubeadm init 进行主节点的初始化,下面是这个命令主要参数的说明,特别是网络参数的三个选择。

    • --pod-network-cidr:
    • 指定pod使用的IP地址范围。如果指定了该参数,则Control Plane会自动讲指定的CIDR分配给每个节点。
    • IP地址段 10.244.0.0/16 是Flannel网络组件默认的地址范围。如果需要修改Flannel的IP地址段,需要在这里指定,且在部署Flannel时也要保持一致的IP段。
    • --apiserver-bind-port:
    • API服务(API Server)的端口,默认时6443。
    • --service-cidr:
    • 指定服务(service)的IP地址段,默认是10.96.0.0/12

    提示:

    • 服务VIPs(service VIPs),也称作集群IP(Cluster IP),通过参数 --service-cidr指定。
    • podCIDR,也称为endpoint IP,通过参数 --pod-network-cidr指定。

    有4种典型的网络问题:

    • 高度耦合的容器与容器之间的通信:这可以通过Pod(podCIDR)和本地主机通信来解决。
    • Pod对Pod通信(Pod-to-Pod):
    • 也被称为容器对容器通信(container-to-container)。
    • 在Flannel网络插件中的示例流程是:Pod → veth对 → cni0 → flannel.1 → 宿主机eth0 → 宿主机eth0 → flannel.1 → cni0 → veth对 → Pod。
    • Pod对Service通信(Pod-to-Service):
    • 流程: Pod → 内核 → Service iptables → Service → Pod iptables → Pod。
    • 外部对Service通信(External-to-Service):
    • 负载均衡器: SLB → NodePort → Service → Pod。

    kube-proxy 是对iptables负责,不是网络流量(traffic)。

    • kube-proxy是Kubernetes集群中的一个组件,负责为Service提供代理服务,同时也是Kubernetes网络模型中的重要组成部分之一。kube-proxy会在每个节点上启动一个代理进程,通过监听Kubernetes API Server的Service和Endpoint的变化来维护一个本地的Service和Endpoint的缓存。当有请求到达某个Service时,kube-proxy会根据该Service的类型(ClusterIP、NodePort、LoadBalancer、ExternalName)和端口号,生成相应的iptables规则,将请求转发给Service所代理的后端Pod。

    • iptables是Linux系统中的一个重要网络工具,可以设置IP包的过滤、转发和修改规则,可以实现网络层的防火墙、NAT等功能。在Kubernetes集群中,kube-proxy通过生成和更新iptables规则,来实现Service和Endpoint之间的转发和代理。具体来说,kube-proxy会为每个Service创建三条iptables规则链(nat表中的KUBE-SERVICES和KUBE-NODEPORTS链,以及filter表中的KUBE-SVC-XXXXX链),通过这些规则链,将请求转发到相应的Pod或者Service上。

    • 因此,kube-proxy和iptables是紧密相关的两个组件,通过iptables规则来实现Service和Pod之间的转发和代理。这种实现方式具有可扩展性和高可用性,同时也提供了一种灵活的网络模型,可以方便地实现服务发现、负载均衡等功能。

    sudo kubeadm init \
    +  --dry-run \
    +  --pod-network-cidr=10.244.0.0/16 \
    +  --service-cidr=192.244.0.0/16 \
    +  --image-repository=registry.aliyuncs.com/google_containers \
    +  --kubernetes-version=v1.24.0
     
    -sudo kubeadm init \
    -  --pod-network-cidr=10.244.0.0/16 \
    -  --service-cidr=192.244.0.0/16 \
    -  --image-repository=registry.aliyuncs.com/google_containers \
    -  --kubernetes-version=v1.24.0
    -

    kubeconfig文件

    给当前安装用户配置 kubeconfig 文件(当前例子是用户vagrant)。

    mkdir -p $HOME/.kube
    -sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    -sudo chown $(id -u):$(id -g) $HOME/.kube/config
    -

    Kubernetes 提供了一个命令行工具kubectl,用于使用 Kubernetes API 与 Kubernetes 集群的控制平面进行通信。

    kubectl 控制 Kubernetes cluster manager(集群管理器)。

    对于配置,kubectl 在 $HOME/.kube目录中查找一个名为 config 的文件,该文件是由 kubeadm init生成的文件 /etc/kubernetes/admin.conf的副本。

    我们可以通过设置 KUBECONFIG环境变量或设置 --kubeconfig flag标志来指定其他 kubeconfig 文件。如果 KUBECONFIG 环境变量不存在,kubectl 将使用默认的 kubeconfig 文件 $HOME/.kube/config

    kubeconfig 文件中的 context(上下文) 元素用于将访问参数分组到一个方便的名称下。每个上下文都有三个参数:集群、命名空间和用户。默认情况下,kubectl 命令行工具使用当前上下文中的参数与集群通信。

    文件.kube/config的例子:

    apiVersion: v1
    -clusters:
    -- cluster:
    -    certificate-authority-data: <certificate string>
    -    server: https://<eth0 ip>:6443
    -  name: <cluster name>
    -contexts:
    -- context:
    -    cluster: <cluster name>
    -    namespace: <namespace name>
    -    user: <user name>
    -  name: <context user>@<context name>
    -current-context: <context name>
    -kind: Config
    -preferences: {}
    -users:
    -- name: <user name>
    -  user:
    -    client-certificate-data: <certificate string>
    -    client-key-data: <certificate string>
    -

    读取当前上下文:

    kubectl config get-contexts
    +sudo kubeadm init \
    +  --pod-network-cidr=10.244.0.0/16 \
    +  --service-cidr=192.244.0.0/16 \
    +  --image-repository=registry.aliyuncs.com/google_containers \
    +  --kubernetes-version=v1.24.0
    +

    kubeconfig文件

    给当前安装用户配置 kubeconfig 文件(当前例子是用户vagrant)。

    mkdir -p $HOME/.kube
    +sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    +sudo chown $(id -u):$(id -g) $HOME/.kube/config
    +

    Kubernetes 提供了一个命令行工具kubectl,用于使用 Kubernetes API 与 Kubernetes 集群的控制平面进行通信。

    kubectl 控制 Kubernetes cluster manager(集群管理器)。

    对于配置,kubectl 在 $HOME/.kube目录中查找一个名为 config 的文件,该文件是由 kubeadm init生成的文件 /etc/kubernetes/admin.conf的副本。

    我们可以通过设置 KUBECONFIG环境变量或设置 --kubeconfig flag标志来指定其他 kubeconfig 文件。如果 KUBECONFIG 环境变量不存在,kubectl 将使用默认的 kubeconfig 文件 $HOME/.kube/config

    kubeconfig 文件中的 context(上下文) 元素用于将访问参数分组到一个方便的名称下。每个上下文都有三个参数:集群、命名空间和用户。默认情况下,kubectl 命令行工具使用当前上下文中的参数与集群通信。

    文件.kube/config的例子:

    apiVersion: v1
    +clusters:
    +- cluster:
    +    certificate-authority-data: <certificate string>
    +    server: https://<eth0 ip>:6443
    +  name: <cluster name>
    +contexts:
    +- context:
    +    cluster: <cluster name>
    +    namespace: <namespace name>
    +    user: <user name>
    +  name: <context user>@<context name>
    +current-context: <context name>
    +kind: Config
    +preferences: {}
    +users:
    +- name: <user name>
    +  user:
    +    client-certificate-data: <certificate string>
    +    client-key-data: <certificate string>
    +

    读取当前上下文:

    kubectl config get-contexts
     

    运行结果:

    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
     *         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   
    -

    安装Calico

    参考安装指导 End-to-end Calico installation

    快速安装手册 QuickStart

    安装 Calico:

    kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/tigera-operator.yaml
    +

    安装Calico

    参考安装指导 End-to-end Calico installation

    快速安装手册 QuickStart

    安装 Calico:

    kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/tigera-operator.yaml
     

    运行结果:

    namespace/tigera-operator created
     customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
     customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
    @@ -206,24 +206,24 @@
     clusterrole.rbac.authorization.k8s.io/tigera-operator created
     clusterrolebinding.rbac.authorization.k8s.io/tigera-operator created
     deployment.apps/tigera-operator created
    -
    kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/calicoctl.yaml
    +
    kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/calicoctl.yaml
     

    运行结果:

    serviceaccount/calicoctl created
     pod/calicoctl created
     clusterrole.rbac.authorization.k8s.io/calicoctl created
     clusterrolebinding.rbac.authorization.k8s.io/calicoctl created
    -

    验证Calico的状态。Calico的初始化过程可能需要几分钟时间完成。

    kubectl get pod -n kube-system | grep calico
    +

    验证Calico的状态。Calico的初始化过程可能需要几分钟时间完成。

    kubectl get pod -n kube-system | grep calico
     

    运行结果:

    calico-kube-controllers-555bc4b957-l8bn2   0/1     Pending    0          28s
     calico-node-255pc                          0/1     Init:1/3   0          29s
     calico-node-7tmnb                          0/1     Init:1/3   0          29s
     calico-node-w8nvl                          0/1     Init:1/3   0          29s
    -

    验证网络状态。

    sudo nerdctl network ls
    +

    验证网络状态。

    sudo nerdctl network ls
     

    运行结果:

    NETWORK ID      NAME               FILE
                     k8s-pod-network    /etc/cni/net.d/10-calico.conflist
     17f29b073143    bridge             /etc/cni/net.d/nerdctl-bridge.conflist
                     host               
                     none 
    -

    配置工作节点

    使用 kubeadm token 来生成加入集群的令牌(token)和哈西值(hash value)。

    kubeadm token create --print-join-command
    -

    命令用法:

    sudo kubeadm join <your master node eth0 ip>:6443 --token <token generated by kubeadm init> --discovery-token-ca-cert-hash <hash key generated by kubeadm init>
    +

    配置工作节点

    使用 kubeadm token 来生成加入集群的令牌(token)和哈西值(hash value)。

    kubeadm token create --print-join-command
    +

    命令用法:

    sudo kubeadm join <your master node eth0 ip>:6443 --token <token generated by kubeadm init> --discovery-token-ca-cert-hash <hash key generated by kubeadm init>
     

    运行结果:

    [preflight] Running pre-flight checks
             [WARNING SystemVerification]: missing optional cgroups: blkio
     [preflight] Reading configuration from the cluster...
    @@ -238,44 +238,44 @@
     * The Kubelet was informed of the new secure connection details.
     
     Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
    -

    检查集群状态

    查看 Kubernetes 集群的信息,包括集群 API Server 的地址、Kubernetes DNS 服务的地址等。

    kubectl cluster-info
    +

    检查集群状态

    查看 Kubernetes 集群的信息,包括集群 API Server 的地址、Kubernetes DNS 服务的地址等。

    kubectl cluster-info
     

    运行结果:

    bKubernetes control plane is running at https://11.0.1.129:6443
     CoreDNS is running at https://11.0.1.129:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
     To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
    -

    列出集群中所有节点的详细信息,包括节点名称、节点 IP、节点标签、节点状态等。

    kubectl get nodes -owide
    -

    列出 Kubernetes 集群中所有 Namespace 下的 Pod。

    kubectl get pod -A
    -

    更新安装

    Bash自动补全

    在每个节点上配置Bash自动补全功能。

    参考指导设置 kubectl 自动补全功能auto-completion

    apt install -y bash-completion
    +

    列出集群中所有节点的详细信息,包括节点名称、节点 IP、节点标签、节点状态等。

    kubectl get nodes -owide
    +

    列出 Kubernetes 集群中所有 Namespace 下的 Pod。

    kubectl get pod -A
    +

    更新安装

    Bash自动补全

    在每个节点上配置Bash自动补全功能。

    参考指导设置 kubectl 自动补全功能auto-completion

    apt install -y bash-completion
     
    -source /usr/share/bash-completion/bash_completion
    -source <(kubectl completion bash)
    +source /usr/share/bash-completion/bash_completion
    +source <(kubectl completion bash)
     
    -echo "source <(kubectl completion bash)" >> ~/.bashrc
    -source ~/.bashrc
    -

    别名

    如果我们为 kubectl 设置一个别名,我们可以通过一些方法来扩展 shell 自动补全功能,使其能够与该别名一起使用。

    一种方法是在 Bash shell 配置文件(如 .bashrc 或 .bash_profile)中设置别名,并为该别名指定 kubectl 的完整路径。例如,可以在 .bashrc 文件中添加以下内容:

    alias k='path/to/kubectl'
    -

    然后,可以使用以下命令重新加载 .bashrc 文件:

    source ~/.bashrc
    -

    接下来,可以使用k命令来代替kubectl命令,并在其后面添加相应的参数和选项。当使用自动补全功能时,Bash shell 会自动将k别名转换为 kubectl 的完整路径,并对其进行自动补全。

    另一种方法是使用 Bash shell 内置的 complete 函数来为别名设置自动补全功能。例如,可以在 .bashrc 文件中添加以下内容:

    echo 'alias k=kubectl' >>~/.bashrc
    -echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
    -

    这将为别名k设置自动补全功能,并将其与 kubectl 的自动补全函数__start_kubectl关联起来。这样,当用户在k命令后输入Tab键时,Bash shell 会自动调用__start_kubectl函数,并为用户提供相应的自动补全建议。

    更新默认Context

    查看当前的 context 列表:

    kubectl config get-contexts 
    +echo "source <(kubectl completion bash)" >> ~/.bashrc
    +source ~/.bashrc
    +

    别名

    如果我们为 kubectl 设置一个别名,我们可以通过一些方法来扩展 shell 自动补全功能,使其能够与该别名一起使用。

    一种方法是在 Bash shell 配置文件(如 .bashrc 或 .bash_profile)中设置别名,并为该别名指定 kubectl 的完整路径。例如,可以在 .bashrc 文件中添加以下内容:

    alias k='path/to/kubectl'
    +

    然后,可以使用以下命令重新加载 .bashrc 文件:

    source ~/.bashrc
    +

    接下来,可以使用k命令来代替kubectl命令,并在其后面添加相应的参数和选项。当使用自动补全功能时,Bash shell 会自动将k别名转换为 kubectl 的完整路径,并对其进行自动补全。

    另一种方法是使用 Bash shell 内置的 complete 函数来为别名设置自动补全功能。例如,可以在 .bashrc 文件中添加以下内容:

    echo 'alias k=kubectl' >>~/.bashrc
    +echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
    +

    这将为别名k设置自动补全功能,并将其与 kubectl 的自动补全函数__start_kubectl关联起来。这样,当用户在k命令后输入Tab键时,Bash shell 会自动调用__start_kubectl函数,并为用户提供相应的自动补全建议。

    更新默认Context

    查看当前的 context 列表:

    kubectl config get-contexts 
     

    这个命令会列出所有可用的 context 列表,并标记出当前正在使用的 context。

    类似下面结果:

    • kubernetes-admin@kubernetes是Context名。
    • kubernetes是集群名。
    • kubernetes-admin是用户名。
    • 当前例子中没有指定名称空间。
    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
     *         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin 
     

    更新context。例如,更新context的默认名称空间等。

    # Usage:
    -kubectl config set-context <context name> --cluster=<cluster name> --namespace=<namespace name> --user=<user name> 
    +kubectl config set-context <context name> --cluster=<cluster name> --namespace=<namespace name> --user=<user name> 
     
     # Set default namespace
    -kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin
    +kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin
     

    在不同的context之间切换。

    # Usage:
    -kubectl config use-context <context name>
    +kubectl config use-context <context name>
     
     # Switch to new context
    -kubectl config use-context kubernetes-admin@kubernetes
    -

    参考资料: *kubectl * commandline

    安装Helm

    Helm 是 Kubernetes 的包管理工具,它不随 Kubernetes 一起提供。

    Helm 有三个核心概念:

    • Chart(图表)是 Helm 的软件包,它包含了在 Kubernetes 集群中运行应用程序、工具或服务所需的所有资源定义。可以将其视为 Kubernetes 的 Homebrew 公式、Apt dpkg 或 Yum RPM 文件等等。
    • Repository(仓库)是图表可以被收集和共享的地方,类似于 Perl 的 CPAN 存储库或 Fedora 的软件包数据库,但用于 Kubernetes 软件包。
    • Release(发布)是在 Kubernetes 集群中运行的图表实例。一个图表通常可以在同一集群中安装多次,并且每次安装都会创建一个新的发布。以 MySQL 图表为例,如果想要在集群中运行两个数据库,则可以安装该图表两次,每次安装都会创建一个新的发布,每个发布都有自己的发布名称。

    参考文档:

    Helm客户端安装:

    curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
    -chmod 700 get_helm.sh
    +kubectl config use-context kubernetes-admin@kubernetes
    +

    参考资料: *kubectl * commandline

    安装Helm

    Helm 是 Kubernetes 的包管理工具,它不随 Kubernetes 一起提供。

    Helm 有三个核心概念:

    • Chart(图表)是 Helm 的软件包,它包含了在 Kubernetes 集群中运行应用程序、工具或服务所需的所有资源定义。可以将其视为 Kubernetes 的 Homebrew 公式、Apt dpkg 或 Yum RPM 文件等等。
    • Repository(仓库)是图表可以被收集和共享的地方,类似于 Perl 的 CPAN 存储库或 Fedora 的软件包数据库,但用于 Kubernetes 软件包。
    • Release(发布)是在 Kubernetes 集群中运行的图表实例。一个图表通常可以在同一集群中安装多次,并且每次安装都会创建一个新的发布。以 MySQL 图表为例,如果想要在集群中运行两个数据库,则可以安装该图表两次,每次安装都会创建一个新的发布,每个发布都有自己的发布名称。

    参考文档:

    Helm客户端安装:

    curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
    +chmod 700 get_helm.sh
     ./get_helm.sh
     

    运行结果:

    Downloading https://get.helm.sh/helm-v3.9.1-linux-amd64.tar.gz
     Verifying checksum... Done.
     Preparing to install helm into /usr/local/bin
     helm installed into /usr/local/bin/helm
    -

    提示: *helm init 在Helm 3中已取消,且Tiller也一同取消。今后在集群中使用Helm时不再需要安装Tiller。 * helm search可以用来搜索两种不同类型的资源: *helm search hubArtifact Hub中搜索,这个hub里列出来自数十个不同仓库的 Helm Chart。 * helm search repo 命令用于搜索已添加到本地 Helm 客户端的仓库(使用 helm repo add 命令)。此搜索是在本地数据上进行的,不需要公共网络连接。

    参考资料:Helming development

    重置集群

    注意:下面的操作会重置当前集群(删除集群)。

    删除集群中所有节点。

    kubeadm reset
    -

    清除iptables中已定义的规则。

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    -

    清除IPVS中定义的规则(如果使用IPVS)。

    ipvsadm --clear
    -
    \ No newline at end of file +

    提示: *helm init 在Helm 3中已取消,且Tiller也一同取消。今后在集群中使用Helm时不再需要安装Tiller。 * helm search可以用来搜索两种不同类型的资源: *helm search hubArtifact Hub中搜索,这个hub里列出来自数十个不同仓库的 Helm Chart。 * helm search repo 命令用于搜索已添加到本地 Helm 客户端的仓库(使用 helm repo add 命令)。此搜索是在本地数据上进行的,不需要公共网络连接。

    参考资料:Helming development

    重置集群

    注意:下面的操作会重置当前集群(删除集群)。

    删除集群中所有节点。

    kubeadm reset
    +

    清除iptables中已定义的规则。

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    +

    清除IPVS中定义的规则(如果使用IPVS)。

    ipvsadm --clear
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_cn/installation/single-local/index.html b/k8s/cka_cn/installation/single-local/index.html index febc38d6..3351550d 100644 --- a/k8s/cka_cn/installation/single-local/index.html +++ b/k8s/cka_cn/installation/single-local/index.html @@ -1,122 +1,122 @@ - 单节点虚拟机安装Kubernetes - UPSkilling

    CKA自学笔记1:单节点虚拟机安装Kubernetes

    摘要

    在本地Windows环境中,通过VMWare安装Ubuntu虚拟机。在Ubuntu虚拟机中安装基于Docker的Kubernetes系统。在该虚拟机中同时配置主节点Master和工作节点Worker。

    本地虚拟机设置

    VMWare虚拟机设置。

    • VMnet1: host-only模式, 网络subnet: 192.168.150.0/24
    • VMnet8: NAT模式, 网络subnet: 11.0.1.0/24

    通过VMWare创建客户机。

    • 内存:4 GB
    • CPU:2 CPUs with 2 Cores
    • 操作系统:Ubuntu Server 22.04
    • 网络:NAT

    Kubernetes运行在Docker上。

    Ubuntu预配置

    创建用户 vagrant

    sudo adduser vagrant
    -sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd vagrant
    -sudo passwd vagrant
    -

    设置用户 root的密码。

    sudo passwd root
    -

    更新客户机的主机名,这里是 ubusvr

    sudo hostnamectl set-hostname ubusvr
    -sudo hostnamectl set-hostname ubusvr --pretty
    -

    验证主机名是否已成功更新为 ubusvr

    cat /etc/machine-info
    -cat /etc/hostname
    -

    验证主机IP地址127.0.1.1 已经配置给当前虚拟机ubusvr

    cat /etc/hosts
    + 单节点虚拟机安装Kubernetes - UPSkilling       

    CKA自学笔记1:单节点虚拟机安装Kubernetes

    摘要

    在本地Windows环境中,通过VMWare安装Ubuntu虚拟机。在Ubuntu虚拟机中安装基于Docker的Kubernetes系统。在该虚拟机中同时配置主节点Master和工作节点Worker。

    本地虚拟机设置

    VMWare虚拟机设置。

    • VMnet1: host-only模式, 网络subnet: 192.168.150.0/24
    • VMnet8: NAT模式, 网络subnet: 11.0.1.0/24

    通过VMWare创建客户机。

    • 内存:4 GB
    • CPU:2 CPUs with 2 Cores
    • 操作系统:Ubuntu Server 22.04
    • 网络:NAT

    Kubernetes运行在Docker上。

    Ubuntu预配置

    创建用户 vagrant

    sudo adduser vagrant
    +sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd vagrant
    +sudo passwd vagrant
    +

    设置用户 root的密码。

    sudo passwd root
    +

    更新客户机的主机名,这里是 ubusvr

    sudo hostnamectl set-hostname ubusvr
    +sudo hostnamectl set-hostname ubusvr --pretty
    +

    验证主机名是否已成功更新为 ubusvr

    cat /etc/machine-info
    +cat /etc/hostname
    +

    验证主机IP地址127.0.1.1 已经配置给当前虚拟机ubusvr

    cat /etc/hosts
     
    127.0.0.1 localhost
     127.0.1.1 ubusrv
     
    -# The following lines are desirable for IPv6 capable hosts
    +# The following lines are desirable for IPv6 capable hosts
     ::1     ip6-localhost ip6-loopback
     fe00::0 ip6-localnet
     ff00::0 ip6-mcastprefix
     ff02::1 ip6-allnodes
     ff02::2 ip6-allrouters
    -

    设置客户机为固定IP地址,这里是11.0.1.136

    sudo vi 00-installer-config.yaml
    -
    network:
    -  ethernets:
    -    ens33:
    -      dhcp4: false
    -      addresses:
    -      - 11.0.1.136/24
    -      nameservers:
    -        addresses:
    -        - 11.0.1.2
    -      routes:
    -      - to: default
    -        via: 11.0.1.2
    -  version: 2
    -
    sudo netplan apply
    -

    禁用交换分区swap。

    sudo swapoff -a
    -sudo ufw disable
    -sudo ufw status verbose
    +

    设置客户机为固定IP地址,这里是11.0.1.136

    sudo vi 00-installer-config.yaml
    +
    network:
    +  ethernets:
    +    ens33:
    +      dhcp4: false
    +      addresses:
    +      - 11.0.1.136/24
    +      nameservers:
    +        addresses:
    +        - 11.0.1.2
    +      routes:
    +      - to: default
    +        via: 11.0.1.2
    +  version: 2
    +
    sudo netplan apply
    +

    禁用交换分区swap。

    sudo swapoff -a
    +sudo ufw disable
    +sudo ufw status verbose
     

    注释掉文件/etc/fstab的最后一行,即禁用交换分区。需要重启客户机使之生效。

    /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1
    -# /swap.img     none    swap    sw      0       0
    -

    设置客户机时区。

    sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    -sudo echo 'LANG="en_US.UTF-8"' >> /etc/profile
    -source /etc/profile
    +# /swap.img     none    swap    sw      0       0
    +

    设置客户机时区。

    sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    +sudo echo 'LANG="en_US.UTF-8"' >> /etc/profile
    +source /etc/profile
     

    执行命令 ll /etc/localtime验证时区是否已正确设置并生效。

    lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
    -

    客户机内核设置。

    cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
    +

    客户机内核设置。

    cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
     overlay
     br_netfilter
     EOF
    -
    sudo modprobe overlay
    -sudo modprobe br_netfilter
    -
    cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
    +
    sudo modprobe overlay
    +sudo modprobe br_netfilter
    +
    cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
     net.bridge.bridge-nf-call-iptables  = 1
     net.ipv4.ip_forward                 = 1
     net.bridge.bridge-nf-call-ip6tables = 1
     EOF
    -
    sudo sysctl --system
    -

    安装Docker

    参考帮助

    sudo apt-get install \
    -ca-certificates \
    -curl \
    -gnupg \
    +
    sudo sysctl --system
    +

    安装Docker

    参考帮助

    sudo apt-get install \
    +ca-certificates \
    +curl \
    +gnupg \
     lsb-release
    -
    sudo mkdir -p /etc/apt/keyrings
    +
    sudo mkdir -p /etc/apt/keyrings
     
    -curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
     
    -sudo chmod a+r /etc/apt/keyrings/docker.gpg
    +sudo chmod a+r /etc/apt/keyrings/docker.gpg
     
    -echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    -
    sudo apt-get update
    +echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    +
    sudo apt-get update
     
    -sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
    -
    sudo systemctl status docker.service
    +sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
    +
    sudo systemctl status docker.service
     
    -sudo systemctl status containerd.service
    -
    sudo groupadd docker
    -sudo usermod -aG docker $USER
    -

    设置Containerd。

    containerd config default | sudo tee /etc/containerd/config.toml
    -sudo vi /etc/containerd/config.toml
    -
    sudo systemctl restart containerd
    -sudo systemctl status containerd
    -

    安装Kubernetes

    安装kubeadm

    sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl
    +sudo systemctl status containerd.service
    +
    sudo groupadd docker
    +sudo usermod -aG docker $USER
    +

    设置Containerd。

    containerd config default | sudo tee /etc/containerd/config.toml
    +sudo vi /etc/containerd/config.toml
    +
    sudo systemctl restart containerd
    +sudo systemctl status containerd
    +

    安装Kubernetes

    安装kubeadm

    sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl
     
    -curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - 
    +curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - 
     
    -cat << EOF > /etc/apt/sources.list.d/kubernetes.list
    +cat << EOF > /etc/apt/sources.list.d/kubernetes.list
     deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
     EOF
     
    -sudo apt-get update
    -sudo apt-get install ebtables
    -sudo apt-get install libxtables12
    -sudo apt-get upgrade iptables
    -
    apt policy kubeadm
    -
    sudo apt-get -y install kubelet=1.23.8-00 kubeadm=1.23.8-00 kubectl=1.23.8-00 --allow-downgrades
    -

    配置主节点(Master)。

    sudo kubeadm config print init-defaults
    -

    安装预演Dry run。

    sudo kubeadm init --dry-run --pod-network-cidr=10.244.0.0/16 --image-repository=registry.aliyuncs.com/google_containers --kubernetes-version=v1.23.8
    -

    安装。

    sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --image-repository=registry.aliyuncs.com/google_containers --kubernetes-version=v1.23.8
    -
    mkdir -p $HOME/.kube
    -sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    -sudo chown $(id -u):$(id -g) $HOME/.kube/config
    -

    安装Flannel。如果需要考虑网络策略,则安装Calico。参照阿里云ECS中Install Calico or Flannel部分。

    kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    -

    配置工作节点(Worker Node)。

    kubeadm join <your master node eth0 ip>:6443 --token <token generated by kubeadm init> --discovery-token-ca-cert-hash <hash key generated by kubeadm init>
    -
    kubeadm join 11.0.1.136:6443 --token 6zqh1u.8b4afzc2ov4e7iuj \
    -  --discovery-token-ca-cert-hash sha256:815fdb9dd9e3ae0af07ffaf6c216964388098b150ef01ee3ae900c261a429d24
    -

    在所有节点上配置bash自动补全功能。

    sudo apt install -y bash-completion
    -source /usr/share/bash-completion/bash_completion
    -source <(kubectl completion bash)
    -echo "source <(kubectl completion bash)" >> ~/.bashrc
    -

    在所有节点上定义别名(alias)。

    echo 'alias k=kubectl' >>~/.bashrc
    -echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
    -

    查看当前集群状态。

    kubectl cluster-info
    -kubectl get nodes -owide
    -kubectl get pod -A
    -

    安装Helm

    安装Helm客户端。

    curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
    -
    chmod 700 get_helm.sh
    +sudo apt-get update
    +sudo apt-get install ebtables
    +sudo apt-get install libxtables12
    +sudo apt-get upgrade iptables
    +
    apt policy kubeadm
    +
    sudo apt-get -y install kubelet=1.23.8-00 kubeadm=1.23.8-00 kubectl=1.23.8-00 --allow-downgrades
    +

    配置主节点(Master)。

    sudo kubeadm config print init-defaults
    +

    安装预演Dry run。

    sudo kubeadm init --dry-run --pod-network-cidr=10.244.0.0/16 --image-repository=registry.aliyuncs.com/google_containers --kubernetes-version=v1.23.8
    +

    安装。

    sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --image-repository=registry.aliyuncs.com/google_containers --kubernetes-version=v1.23.8
    +
    mkdir -p $HOME/.kube
    +sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    +sudo chown $(id -u):$(id -g) $HOME/.kube/config
    +

    安装Flannel。如果需要考虑网络策略,则安装Calico。参照阿里云ECS中Install Calico or Flannel部分。

    kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    +

    配置工作节点(Worker Node)。

    kubeadm join <your master node eth0 ip>:6443 --token <token generated by kubeadm init> --discovery-token-ca-cert-hash <hash key generated by kubeadm init>
    +
    kubeadm join 11.0.1.136:6443 --token 6zqh1u.8b4afzc2ov4e7iuj \
    +  --discovery-token-ca-cert-hash sha256:815fdb9dd9e3ae0af07ffaf6c216964388098b150ef01ee3ae900c261a429d24
    +

    在所有节点上配置bash自动补全功能。

    sudo apt install -y bash-completion
    +source /usr/share/bash-completion/bash_completion
    +source <(kubectl completion bash)
    +echo "source <(kubectl completion bash)" >> ~/.bashrc
    +

    在所有节点上定义别名(alias)。

    echo 'alias k=kubectl' >>~/.bashrc
    +echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
    +

    查看当前集群状态。

    kubectl cluster-info
    +kubectl get nodes -owide
    +kubectl get pod -A
    +

    安装Helm

    安装Helm客户端。

    curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
    +
    chmod 700 get_helm.sh
     
    ./get_helm.sh
     

    输出结果:

    Downloading https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz
     Verifying checksum... Done.
     Preparing to install helm into /usr/local/bin
     helm installed into /usr/local/bin/helm
    -

    重置集群

    注意:下面的操作会重置当前集群(删除集群)。

    删除集群中所有节点。

    kubeadm reset
    -

    清除iptables中已定义的规则。

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    -

    清除IPVS中定义的规则(如果使用IPVS)。

    ipvsadm --clear
    -
    \ No newline at end of file +

    重置集群

    注意:下面的操作会重置当前集群(删除集群)。

    删除集群中所有节点。

    kubeadm reset
    +

    清除iptables中已定义的规则。

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    +

    清除IPVS中定义的规则(如果使用IPVS)。

    ipvsadm --clear
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/basics/index.html b/k8s/cka_en/foundamentals/basics/index.html index 054a7183..8bb28dfa 100644 --- a/k8s/cka_en/foundamentals/basics/index.html +++ b/k8s/cka_en/foundamentals/basics/index.html @@ -1,4 +1,4 @@ - kubectl basics - UPSkilling

    kubectl basics

    Scenario: get to know how to operate Kubernetes cluster using kubectl.

    • via API
    • via kubectl
    • via Dashboard

    Demo:

    Check current kubeconfig file

    Use the kubectl config command to get current context of configuration file.

    echo $KUBECONFIG
    + kubectl basics - UPSkilling       

    kubectl basics

    Scenario: get to know how to operate Kubernetes cluster using kubectl.

    • via API
    • via kubectl
    • via Dashboard

    Demo:

    Check current kubeconfig file

    Use the kubectl config command to get current context of configuration file.

    echo $KUBECONFIG
     kubectl config view
     kubectl config get-contexts
     

    Get resource list

    Get a complete list of supported resources

    kubectl api-resources
    @@ -40,7 +40,7 @@
     kubectl create rolebinding my-admin \
       --clusterrole=pod-creater \
       --serviceaccount=my-namespace:my-service-account
    -

    Use the proxy

    We can use kubectl proxy command to open a tunnel to the API server and make it available locally - usually on localhost:8001 / 127.0.0.1:8001. When I want to explore the API, this is an easy way to gain access.

    Run the command kubectl proxy & and open http://localhost:8001/api/v1 in browser. Just opening http://localhost:8001 will return an error because we are only allowed to access certain parts of the API. Hence the API path is important

    kubectl proxy &
    +

    Use the proxy

    We can use kubectl proxy command to open a tunnel to the API server and make it available locally - usually on localhost:8001 / 127.0.0.1:8001. When I want to explore the API, this is an easy way to gain access.

    Run the command kubectl proxy & and open http://localhost:8001/api/v1 in browser. Just opening http://localhost:8001 will return an error because we are only allowed to access certain parts of the API. Hence the API path is important

    kubectl proxy &
     

    Output

    [1] 102358
     Starting to serve on 127.0.0.1:8001
     

    Example, get available API groups and so on via below link:

    http://127.0.0.1:8001/
    @@ -48,9 +48,9 @@
     http://127.0.0.1:8001/api/v1/namespaces
     http://127.0.0.1:8001/api/v1/namespaces/default
     http://127.0.0.1:8001/api/v1/namespaces/sock-shop/pods
    -

    Access as application

    If we access kubernetes as an application rather than an administrator, we cannot use the kubectl. Instead of kubectl we can use the program curl. We have to send HTTP requests to the cluster. asking for the available nodes.

    Make sure kubectl proxy is running and serving on http://localhost:8001/.

    Execute command below with a -v=9 flag, it shows all the information needed.

    kubectl get nodes
    +

    Access as application

    If we access kubernetes as an application rather than an administrator, we cannot use the kubectl. Instead of kubectl we can use the program curl. We have to send HTTP requests to the cluster. asking for the available nodes.

    Make sure kubectl proxy is running and serving on http://localhost:8001/.

    Execute command below with a -v=9 flag, it shows all the information needed.

    kubectl get nodes
     

    Go through the command's output and find the correct curl request below.

    curl -v -XGET  \
       -H "Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json" \
       -H "User-Agent: kubectl/v1.24.1 (linux/amd64) kubernetes/3ddd0f4" \
       'https://<control_plane_ip>/api/v1/nodes?limit=500'
    -

    Reference

    *There is a forum-like page hosted by K8s with lots of information around kubectl and how to use it best. * Manage multiple clusters and multiple config files *kubectl command documentation * Shell autocompletion *kubectl cheat sheet * jsonpath in kubectl * kubectl

    \ No newline at end of file +

    Reference

    *There is a forum-like page hosted by K8s with lots of information around kubectl and how to use it best. * Manage multiple clusters and multiple config files *kubectl command documentation * Shell autocompletion *kubectl cheat sheet * jsonpath in kubectl * kubectl

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/casestudy-calico/index.html b/k8s/cka_en/foundamentals/casestudy-calico/index.html index bd32a0df..be13e2f5 100644 --- a/k8s/cka_en/foundamentals/casestudy-calico/index.html +++ b/k8s/cka_en/foundamentals/casestudy-calico/index.html @@ -1,4 +1,4 @@ - Calico Installation - UPSkilling

    Case Study: Install Calico

    Scenario: Install Calico

    • Calico Datastore
    • Configure IP Pools
    • Install CNI plugin
    • Install Typha
    • Install calico/node
    • Test networking

    The Calico Datastore

    In order to use Kubernetes as the Calico datastore, we need to define the custom resources Calico uses.

    Download and examine the list of Calico custom resource definitions, and open it in a file editor.

    wget https://projectcalico.docs.tigera.io/manifests/crds.yaml
    + Calico Installation - UPSkilling       

    Case Study: Install Calico

    Scenario: Install Calico

    • Calico Datastore
    • Configure IP Pools
    • Install CNI plugin
    • Install Typha
    • Install calico/node
    • Test networking

    The Calico Datastore

    In order to use Kubernetes as the Calico datastore, we need to define the custom resources Calico uses.

    Download and examine the list of Calico custom resource definitions, and open it in a file editor.

    wget https://projectcalico.docs.tigera.io/manifests/crds.yaml
     

    Create the custom resource definitions in Kubernetes.

    kubectl apply -f crds.yaml
     

    Install calicoctl. To interact directly with the Calico datastore, use the calicoctl client tool.

    Download the calicoctl binary to a Linux host with access to Kubernetes. The latest release of calicoctl can be found in the git page and replace below v3.23.2 by actual release number.

    wget https://github.com/projectcalico/calico/releases/download/v3.23.3/calicoctl-linux-amd64
     chmod +x calicoctl-linux-amd64
    @@ -48,12 +48,12 @@
     
    NAME            CIDR              NAT    IPIPMODE   VXLANMODE   DISABLED   DISABLEBGPEXPORT   SELECTOR   
     ipv4-ippool-1   10.244.0.0/18     true   Never      Never       false      false              all()      
     ipv4-ippool-2   10.244.192.0/19   true   Never      Never       true       false              all()     
    -

    Install CNI plugin

    • Provision Kubernetes user account for the plugin.

    Kubernetes uses the Container Network Interface (CNI) to interact with networking providers like Calico. The Calico binary that presents this API to Kubernetes is called the CNI plugin and must be installed on every node in the Kubernetes cluster.

    The CNI plugin interacts with the Kubernetes API server while creating pods, both to obtain additional information and to update the datastore with information about the pod.

    On the Kubernetes master node, create a key for the CNI plugin to authenticate with and certificate signing request.

    Change to directory /etc/kubernetes/pki/.

    cd /etc/kubernetes/pki/
    -
    openssl req -newkey rsa:4096 \
    -  -keyout cni.key \
    -  -nodes \
    -  -out cni.csr \
    -  -subj "/CN=calico-cni"
    +

    Install CNI plugin

    • Provision Kubernetes user account for the plugin.

    Kubernetes uses the Container Network Interface (CNI) to interact with networking providers like Calico. The Calico binary that presents this API to Kubernetes is called the CNI plugin and must be installed on every node in the Kubernetes cluster.

    The CNI plugin interacts with the Kubernetes API server while creating pods, both to obtain additional information and to update the datastore with information about the pod.

    On the Kubernetes master node, create a key for the CNI plugin to authenticate with and certificate signing request.

    Change to directory /etc/kubernetes/pki/.

    cd /etc/kubernetes/pki/
    +
    openssl req -newkey rsa:4096 \
    +  -keyout cni.key \
    +  -nodes \
    +  -out cni.csr \
    +  -subj "/CN=calico-cni"
     

    We will sign this certificate using the main Kubernetes CA.

    sudo openssl x509 -req -in cni.csr \
       -CA /etc/kubernetes/pki/ca.crt \
       -CAkey /etc/kubernetes/pki/ca.key \
    @@ -89,8 +89,8 @@
     

    The context for CNI looks like below.

    kubectl config get-contexts --kubeconfig=cni.kubeconfig
     
    CURRENT   NAME             CLUSTER      AUTHINFO     NAMESPACE
     *         cni@kubernetes   kubernetes   calico-cni 
    -
    • Provision RBAC

    Change to home directory

    cd ~
    -

    Define a cluster role the CNI plugin will use to access Kubernetes.

    kubectl apply -f - <<EOF
    +
    • Provision RBAC

    Change to home directory

    cd ~
    +

    Define a cluster role the CNI plugin will use to access Kubernetes.

    kubectl apply -f - <<EOF
     kind: ClusterRole
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
    @@ -146,7 +146,7 @@
     

    Copy the kubeconfig from the previous section

    cp /etc/kubernetes/pki/cni.kubeconfig /etc/cni/net.d/calico-kubeconfig
     
     chmod 600 /etc/cni/net.d/calico-kubeconfig
    -

    Write the CNI configuration

    cat > /etc/cni/net.d/10-calico.conflist <<EOF
    +

    Write the CNI configuration

    cat > /etc/cni/net.d/10-calico.conflist <<EOF
     {
       "name": "k8s-pod-network",
       "cniVersion": "0.3.1",
    @@ -300,9 +300,9 @@
     subject=CN = calico-typha
     Getting CA Private Key
     

    Store the Typha key and certificate in a secret that Typha will access

    kubectl create secret generic -n kube-system calico-typha-certs --from-file=typha.key --from-file=typha.crt
    -
    • Provision RBAC

    Change to home directory.

    cd ~
    -

    Create a ServiceAccount that will be used to run Typha.

    kubectl create serviceaccount -n kube-system calico-typha
    -

    Define a cluster role for Typha with permission to watch Calico datastore objects.

    kubectl apply -f - <<EOF
    +
    • Provision RBAC

    Change to home directory.

    cd ~
    +

    Create a ServiceAccount that will be used to run Typha.

    kubectl create serviceaccount -n kube-system calico-typha
    +

    Define a cluster role for Typha with permission to watch Calico datastore objects.

    kubectl apply -f - <<EOF
     kind: ClusterRole
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
    @@ -357,7 +357,7 @@
           - update
     EOF
     

    Bind the cluster role to the calico-typha ServiceAccount.

    kubectl create clusterrolebinding calico-typha --clusterrole=calico-typha --serviceaccount=kube-system:calico-typha
    -
    • Install Deployment

    Since Typha is required by calico/node, and calico/node establishes the pod network, we run Typha as a host networked pod to avoid a chicken-and-egg problem. We run 3 replicas of Typha so that even during a rolling update, a single failure does not make Typha unavailable.

    kubectl apply -f - <<EOF
    +
    • Install Deployment

    Since Typha is required by calico/node, and calico/node establishes the pod network, we run Typha as a host networked pod to avoid a chicken-and-egg problem. We run 3 replicas of Typha so that even during a rolling update, a single failure does not make Typha unavailable.

    kubectl apply -f - <<EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -509,9 +509,9 @@
     subject=CN = calico-node
     Getting CA Private Key
     

    Store the key and certificate in a Secret that calico/node will access.

    kubectl create secret generic -n kube-system calico-node-certs --from-file=calico-node.key --from-file=calico-node.crt
    -
    • Provision RBAC

    Change to home directory.

    cd ~
    -

    Create the ServiceAccount that calico/node will run as.

    kubectl create serviceaccount -n kube-system calico-node
    -

    Provision a cluster role with permissions to read and modify Calico datastore objects

    kubectl apply -f - <<EOF
    +
    • Provision RBAC

    Change to home directory.

    cd ~
    +

    Create the ServiceAccount that calico/node will run as.

    kubectl create serviceaccount -n kube-system calico-node
    +

    Provision a cluster role with permissions to read and modify Calico datastore objects

    kubectl apply -f - <<EOF
     kind: ClusterRole
     apiVersion: rbac.authorization.k8s.io/v1
     metadata:
    @@ -650,8 +650,8 @@
           - watch
     EOF
     

    Bind the cluster role to the calico-node ServiceAccount

    kubectl create clusterrolebinding calico-node --clusterrole=calico-node --serviceaccount=kube-system:calico-node
    -
    • Install daemon set

    Change to home directory.

    cd ~
    -

    calico/node runs as a daemon set so that it is installed on every node in the cluster.

    Change image: calico/node:v3.20.0 to right version.

    Create the daemon set

    kubectl apply -f - <<EOF
    +
    • Install daemon set

    Change to home directory.

    cd ~
    +

    calico/node runs as a daemon set so that it is installed on every node in the cluster.

    Change image: calico/node:v3.20.0 to right version.

    Create the daemon set

    kubectl apply -f - <<EOF
     kind: DaemonSet
     apiVersion: apps/v1
     metadata:
    @@ -861,7 +861,7 @@
     

    Result

    NAME            CIDR              NAT    IPIPMODE   VXLANMODE   DISABLED   DISABLEBGPEXPORT   SELECTOR   
     ipv4-ippool-1   10.244.0.0/18     true   Never      Never       false      false              all()      
     ipv4-ippool-2   10.244.192.0/19   true   Never      Never       false      false              all()      
    -

    Create a pod, explicitly requesting an address from pool2

    kubectl apply -f - <<EOF
    +

    Create a pod, explicitly requesting an address from pool2

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -880,9 +880,9 @@
     

    Verify it has an IP address from pool2

    kubectl get pod pingtest-ippool-2 -o wide
     

    Result

    NAME                READY   STATUS    RESTARTS   AGE   IP               NODE     NOMINATED NODE   READINESS GATES
     pingtest-ippool-2   1/1     Running   0          18s   10.244.203.192   cka003   <none>           <none>
    -

    Let's attach to the Pod pingtest-585b76c894-chwjq again.

    kubectl exec -ti pingtest-585b76c894-chwjq -- sh
    -/ # 10.244.203.192 -c 4
    -4 packets transmitted, 0 packets received, 100% packet loss
    -

    Mark here. it's failed. Need further check why the route does not work.

    Clean up

    kubectl delete deployments.apps pingtest
    -kubectl delete pod pingtest-ippool-2
    -

    Reference

    \ No newline at end of file +

    Let's attach to the Pod pingtest-585b76c894-chwjq again.

    kubectl exec -ti pingtest-585b76c894-chwjq -- sh
    +/ # 10.244.203.192 -c 4
    +4 packets transmitted, 0 packets received, 100% packet loss
    +

    Mark here. it's failed. Need further check why the route does not work.

    Clean up

    kubectl delete deployments.apps pingtest
    +kubectl delete pod pingtest-ippool-2
    +

    Reference

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/casestudy-health-check/index.html b/k8s/cka_en/foundamentals/casestudy-health-check/index.html index 09fd91f7..bf759a0e 100644 --- a/k8s/cka_en/foundamentals/casestudy-health-check/index.html +++ b/k8s/cka_en/foundamentals/casestudy-health-check/index.html @@ -1,4 +1,4 @@ - Health Check - UPSkilling

    Case Study: Health Check

    Scenario:

    • Create Deployment and Service
    • Simulate an error (delete index.html)
    • Pod is in unhealth status and is removed from endpoint list
    • Fix the error (revert the index.html)
    • Pod is back to normal and in endpoint list

    Create Deployment and Service

    Create Deployment nginx-healthcheck and Service nginx-healthcheck.

    kubectl apply -f - <<EOF
    + Health Check - UPSkilling       

    Case Study: Health Check

    Scenario:

    • Create Deployment and Service
    • Simulate an error (delete index.html)
    • Pod is in unhealth status and is removed from endpoint list
    • Fix the error (revert the index.html)
    • Pod is back to normal and in endpoint list

    Create Deployment and Service

    Create Deployment nginx-healthcheck and Service nginx-healthcheck.

    kubectl apply -f - <<EOF
     apiVersion: apps/v1
     kind: Deployment
     metadata:
    @@ -120,11 +120,11 @@
     

    Same result we can get by checking information of Endpoints, which is only Pod is running.

    kubectl get endpoints nginx-healthcheck 
     

    Output:

    NAME                ENDPOINTS          AGE
     nginx-healthcheck   10.244.112.13:80   6m5s
    -

    Fix readinessProbe Failure

    Let's re-create the index.html file again in the Pod.

    kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash
    +

    Fix readinessProbe Failure

    Let's re-create the index.html file again in the Pod.

    kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash
     
    -cd /usr/share/nginx/html/
    +cd /usr/share/nginx/html/
     
    -cat > index.html << EOF 
    +cat > index.html << EOF 
     <!DOCTYPE html>
     <html>
     <head>
    @@ -158,17 +158,17 @@
     

    Re-access Pod IP via curl command and we can see both are back to normal status.

    curl 10.244.102.14
     curl 10.244.112.13
     

    Verify the Pod status again.

    kubectl describe pod nginx-healthcheck-79fc55d944-jw887
    -

    Conclusion:

    • By delete the index.html file, the Pod is in unhealth status and is removed from endpoint list.
    • One one health Pod can provide normal service.

    Clean up

    kubectl delete service nginx-healthcheck
    -kubectl delete deployment nginx-healthcheck
    +

    Conclusion:

    • By delete the index.html file, the Pod is in unhealth status and is removed from endpoint list.
    • One one health Pod can provide normal service.

    Clean up

    kubectl delete service nginx-healthcheck
    +kubectl delete deployment nginx-healthcheck
     

    Simulate livenessProbe Failure

    Re-create Deployment nginx-healthcheck and Service nginx-healthcheck.

    Deployment:

    NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
     nginx-healthcheck        0/2     2            0           7s
     

    Pods:

    NAME                                      READY   STATUS    RESTARTS   AGE
     nginx-healthcheck-79fc55d944-lknp9        1/1     Running   0          96s
     nginx-healthcheck-79fc55d944-wntmg        1/1     Running   0          96s
     

    Change nginx default listening port from 80 to 90 to simulate livenessProbe Failure. livenessProbe check the live status via port 80.

    kubectl exec -it nginx-healthcheck-79fc55d944-lknp9 -- bash
    -root@nginx-healthcheck-79fc55d944-lknp9:/# cd /etc/nginx/conf.d
    -root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# sed -i 's/80/90/g' default.conf
    -root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# nginx -s reload
    +root@nginx-healthcheck-79fc55d944-lknp9:/# cd /etc/nginx/conf.d
    +root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# sed -i 's/80/90/g' default.conf
    +root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# nginx -s reload
     2022/07/24 12:59:45 [notice] 79#79: signal process started
     

    The Pod runs into failure.

    kubectl describe pod nginx-healthcheck-79fc55d944-lknp9
     

    We can see livenessProbe failed error event message.

    Events:
    @@ -181,4 +181,4 @@
       Warning  Unhealthy  2m47s (x4 over 2m57s)  kubelet            Readiness probe failed: Get "http://10.244.102.46:80/": dial tcp 10.244.102.46:80: connect: connection refused
       Warning  Unhealthy  2m47s (x3 over 2m57s)  kubelet            Liveness probe failed: dial tcp 10.244.102.46:80: connect: connection refused
       Normal   Killing    2m47s                  kubelet            Container nginx-healthcheck failed liveness probe, will be restarted
    -

    Once failure detected by livenessProbe, the container will restarted again automatically. The default.conf we modified will be replaced by default file and the container status is up and normal.

    \ No newline at end of file +

    Once failure detected by livenessProbe, the container will restarted again automatically. The default.conf we modified will be replaced by default file and the container status is up and normal.

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/casestudy-operation-resources/index.html b/k8s/cka_en/foundamentals/casestudy-operation-resources/index.html index 864b24ca..5fae9c8c 100644 --- a/k8s/cka_en/foundamentals/casestudy-operation-resources/index.html +++ b/k8s/cka_en/foundamentals/casestudy-operation-resources/index.html @@ -1,13 +1,13 @@ - Operations on Resources - UPSkilling

    Case Study: Operations on Resources

    Scenario:

    • Node Label
    • Annotation
    • Namespace
    • ServiceAccount Authorization
    • Grant API access authorization to default ServiceAccount
    • Deployment
    • Expose Service
    • Scale out the Deployment
    • Rolling update
    • Rolling back update
    • Event
    • Logging

    Node Label

    • Add/update/remove node Label.
    # Update node label
    + Operations on Resources - UPSkilling       

    Case Study: Operations on Resources

    Scenario:

    • Node Label
    • Annotation
    • Namespace
    • ServiceAccount Authorization
    • Grant API access authorization to default ServiceAccount
    • Deployment
    • Expose Service
    • Scale out the Deployment
    • Rolling update
    • Rolling back update
    • Event
    • Logging

    Node Label

    • Add/update/remove node Label.
    # Update node label
     kubectl label node cka002 node=demonode
     
    -# Get node info with label info
    +# Get node info with label info
     kubectl get node --show-labels
     
    -# Search node by label
    +# Search node by label
     kubectl get node -l node=demonode
     
    -# Remove a lable of node
    +# Remove a lable of node
     kubectl label node cka002 node-
     

    Annotation

    Create Nginx deployment

    kubectl create deploy nginx --image=nginx:mainline
     

    Get Annotation info.

    kubectl describe deployment/nginx
    @@ -88,7 +88,7 @@
     

    We will receive 403 forbidden error message. The ServiceAccount default does not have authorization to access pod in namespace dev.

    Let's create a rolebinding rolebinding-admin to bind cluster role admin to service account default in namespapce dev. Hence service account default is granted adminstrator authorization in namespace dev.

    # Usage:
     kubectl create rolebinding <rule> --clusterrole=<clusterrule> --serviceaccount=<namespace>:<name> --namespace=<namespace>
     
    -# Crate rolebinding:
    +# Crate rolebinding:
     kubectl create rolebinding rolebinding-admin --clusterrole=admin --serviceaccount=dev:default --namespace=dev
     

    Result looks like below by executing kubectl get rolebinding -n dev.

    NAME                ROLE                AGE
     rolebinding-admin   ClusterRole/admin   10s
    @@ -178,14 +178,14 @@
     myapp-5dbd68cc99   1         1         0       8s    kubernetes-bootcamp   docker.io/jocatalin/kubernetes-bootcamp:v2   app=myapp,pod-template-hash=5dbd68cc99
     myapp-b5d775f5d    3         3         3       14m   kubernetes-bootcamp   docker.io/jocatalin/kubernetes-bootcamp:v1   app=myapp,pod-template-hash=b5d775f5d
     

    We can get the change history under metadata.annotations.

    kubectl get deployment myapp -o yaml
    -

    Result

    apiVersion: apps/v1
    -kind: Deployment
    -metadata:
    -  annotations:
    -    deployment.kubernetes.io/revision: "2"
    -    kubernetes.io/change-cause: kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2
    -      --record=true
    -  ......
    +

    Result

    apiVersion: apps/v1
    +kind: Deployment
    +metadata:
    +  annotations:
    +    deployment.kubernetes.io/revision: "2"
    +    kubernetes.io/change-cause: kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2
    +      --record=true
    +  ......
     

    We can also get the change history by command kubectl rollout history, and show details with specific revision --revision=<revision_number>.

    kubectl rollout history deployment/myapp
     

    Result

    deployment.apps/myapp 
     REVISION  CHANGE-CAUSE
    @@ -221,4 +221,4 @@
     kubectl logs kube-proxy-5cdbj -n kube-system
     

    Clean up.

    kubectl delete service myapp
     kubectl delete deployment myapp
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/clustermgt/index.html b/k8s/cka_en/foundamentals/clustermgt/index.html index 1fc781a7..a0109b71 100644 --- a/k8s/cka_en/foundamentals/clustermgt/index.html +++ b/k8s/cka_en/foundamentals/clustermgt/index.html @@ -1,4 +1,4 @@ - Cluster Management - UPSkilling

    Cluster Management

    Scenario: etcd Backup and Restore

    • Install etcdctl
    • Create Deployment Before Backup
    • Backup etcd
    • Create Deployment After Backup
    • Stop Services
    • Stop etcd
    • Restore etcd
    • Start Services
    • Verify

    etcd Backup and Restore

    Install etcdctl

    Download etcd package from Github.

    wget https://github.com/etcd-io/etcd/releases/download/v3.5.3/etcd-v3.5.3-linux-amd64.tar.gz
    + Cluster Management - UPSkilling       

    Cluster Management

    Scenario: etcd Backup and Restore

    • Install etcdctl
    • Create Deployment Before Backup
    • Backup etcd
    • Create Deployment After Backup
    • Stop Services
    • Stop etcd
    • Restore etcd
    • Start Services
    • Verify

    etcd Backup and Restore

    Install etcdctl

    Download etcd package from Github.

    wget https://github.com/etcd-io/etcd/releases/download/v3.5.3/etcd-v3.5.3-linux-amd64.tar.gz
     

    Unzip and grant execute permission.

    tar -zxvf etcd-v3.5.3-linux-amd64.tar.gz
     cp etcd-v3.5.3-linux-amd64/etcdctl /usr/local/bin/
     sudo chmod u+x /usr/local/bin/etcdctl
    @@ -246,7 +246,7 @@
     apt-get -y install kubeadm=1.24.0-00 --allow-downgrades
     kubeadm upgrade plan
     kubeadm upgrade apply v1.24.0
    -# kubeadm upgrade apply v1.24.0 --etcd-upgrade=false
    +# kubeadm upgrade apply v1.24.0 --etcd-upgrade=false
     apt-get -y install kubelet=1.24.0-00 kubectl=1.24.0-00 --allow-downgrades
     systemctl daemon-reload
     systemctl restart kubelet
    @@ -259,4 +259,4 @@
     systemctl daemon-reload
     systemctl restart kubelet
     kubectl uncordon cka002
    -
    • Repeat for other Worker nodes
    \ No newline at end of file +
    • Repeat for other Worker nodes
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/configuration/index.html b/k8s/cka_en/foundamentals/configuration/index.html index 0e4118a7..8bb51f4f 100644 --- a/k8s/cka_en/foundamentals/configuration/index.html +++ b/k8s/cka_en/foundamentals/configuration/index.html @@ -1 +1 @@ - Configuration - UPSkilling

    Configuration

    \ No newline at end of file + Configuration - UPSkilling

    Configuration

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/daemonset/index.html b/k8s/cka_en/foundamentals/daemonset/index.html index 26d5616b..061e62b6 100644 --- a/k8s/cka_en/foundamentals/daemonset/index.html +++ b/k8s/cka_en/foundamentals/daemonset/index.html @@ -1,4 +1,4 @@ - DaemonSet - UPSkilling

    DaemonSet

    Scenario:

    • Create DaemonSet.
    • The DaemonSet will run its pod on each node.

    Demo:

    Create DaemonSet daemonset-busybox.

    kubectl apply -f - << EOF
    + DaemonSet - UPSkilling       

    DaemonSet

    Scenario:

    • Create DaemonSet.
    • The DaemonSet will run its pod on each node.

    Demo:

    Create DaemonSet daemonset-busybox.

    kubectl apply -f - << EOF
     apiVersion: apps/v1
     kind: DaemonSet
     metadata:
    @@ -35,4 +35,4 @@
     daemonset-busybox-5tl55   1/1     Running   0          44s   10.244.228.197   cka001   <none>           <none>
     daemonset-busybox-wg225   1/1     Running   0          44s   10.244.112.5     cka002   <none>           <none>
     

    Clean up.

    kubectl delete daemonset daemonset-busybox 
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/deployment/index.html b/k8s/cka_en/foundamentals/deployment/index.html index 44dc3987..3f0559a4 100644 --- a/k8s/cka_en/foundamentals/deployment/index.html +++ b/k8s/cka_en/foundamentals/deployment/index.html @@ -1,38 +1,38 @@ - Deployment - UPSkilling

    Deployment

    Scenario:

    • Modify Existing Deployment, e.g., add port number in below demo.

    Demo:

    Create Deployment nginx.

    kubectl create deployment nginx --image=nginx
    -

    Execute command below to get yaml template with port number. The option --port=8080 specified the port that this container exposes.

    kubectl create deployment nginx --image=nginx --port=8080 --dry-run=client -o yaml
    -

    Then we get to know the path to add port number, like below.

    kubectl explain deployment.spec.template.spec.containers.ports.containerPort
    -

    Execute command below to edit the Deployemnt.

    kubectl edit deployment nginx
    -

    Add below two lines to specify port number with 8080 and protocol is TCP.

    spec:
    -  template:
    -    spec:
    -      containers:
    -      - image: nginx
    -        name: nginx
    -        ports:
    -        - containerPort: 8080
    -          protocol: TCP
    -

    Use command kubectl describe deployment <deployment_name>, we can see the port number was added.

    Pod Template:
    -  Labels:  app=nginx
    -  Containers:
    -   nginx:
    -    Image:        nginx
    -    Port:         8080/TCP
    -    Host Port:    0/TCP
    -    Environment:  <none>
    -    Mounts:       <none>
    -  Volumes:        <none>
    -

    With command kubectl describe pod <pod_name>, we can see the port number was added.

    Containers:
    -  nginx:
    -    Container ID:   containerd://af4a1243f981497074b5c006ac55fcf795688399871d1dfe91a095321f5c91aa
    -    Image:          nginx
    -    Image ID:       docker.io/library/nginx@sha256:1761fb5661e4d77e107427d8012ad3a5955007d997e0f4a3d41acc9ff20467c7
    -    Port:           8080/TCP
    -    Host Port:      0/TCP
    -    State:          Running
    -      Started:      Sun, 24 Jul 2022 22:50:12 +0800
    -    Ready:          True
    -    Restart Count:  0
    -    Environment:    <none>
    -    Mounts:
    -      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hftdt (ro)
    -

    Info: Some key fields of deployment (use kubectl explain):

    • deployment.spec.revisionHistoryLimit: The number of old ReplicaSets to retain to allow rollback. Defaults to 10.
    • deployment.spec.strategy.type: Type of deployment. Can be Recreate or RollingUpdate. Default is RollingUpdate.
    • deployment.spec.strategy.rollingUpdate.maxUnavailable: The maximum number of pods that can be unavailable during the update. Defaults to 25%.
    • deployment.spec.strategy.rollingUpdate.maxSurge: The maximum number of pods that can be scheduled above the desired number of pods. Defaults to 25%. This can not be 0 if MaxUnavailable is 0.
    • deployment.spec.minReadySeconds: Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready).
    \ No newline at end of file + Deployment - UPSkilling

    Deployment

    Scenario:

    • Modify Existing Deployment, e.g., add port number in below demo.

    Demo:

    Create Deployment nginx.

    kubectl create deployment nginx --image=nginx
    +

    Execute command below to get yaml template with port number. The option --port=8080 specified the port that this container exposes.

    kubectl create deployment nginx --image=nginx --port=8080 --dry-run=client -o yaml
    +

    Then we get to know the path to add port number, like below.

    kubectl explain deployment.spec.template.spec.containers.ports.containerPort
    +

    Execute command below to edit the Deployemnt.

    kubectl edit deployment nginx
    +

    Add below two lines to specify port number with 8080 and protocol is TCP.

    spec:
    +  template:
    +    spec:
    +      containers:
    +      - image: nginx
    +        name: nginx
    +        ports:
    +        - containerPort: 8080
    +          protocol: TCP
    +

    Use command kubectl describe deployment <deployment_name>, we can see the port number was added.

    Pod Template:
    +  Labels:  app=nginx
    +  Containers:
    +   nginx:
    +    Image:        nginx
    +    Port:         8080/TCP
    +    Host Port:    0/TCP
    +    Environment:  <none>
    +    Mounts:       <none>
    +  Volumes:        <none>
    +

    With command kubectl describe pod <pod_name>, we can see the port number was added.

    Containers:
    +  nginx:
    +    Container ID:   containerd://af4a1243f981497074b5c006ac55fcf795688399871d1dfe91a095321f5c91aa
    +    Image:          nginx
    +    Image ID:       docker.io/library/nginx@sha256:1761fb5661e4d77e107427d8012ad3a5955007d997e0f4a3d41acc9ff20467c7
    +    Port:           8080/TCP
    +    Host Port:      0/TCP
    +    State:          Running
    +      Started:      Sun, 24 Jul 2022 22:50:12 +0800
    +    Ready:          True
    +    Restart Count:  0
    +    Environment:    <none>
    +    Mounts:
    +      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hftdt (ro)
    +

    Info: Some key fields of deployment (use kubectl explain):

    • deployment.spec.revisionHistoryLimit: The number of old ReplicaSets to retain to allow rollback. Defaults to 10.
    • deployment.spec.strategy.type: Type of deployment. Can be Recreate or RollingUpdate. Default is RollingUpdate.
    • deployment.spec.strategy.rollingUpdate.maxUnavailable: The maximum number of pods that can be unavailable during the update. Defaults to 25%.
    • deployment.spec.strategy.rollingUpdate.maxSurge: The maximum number of pods that can be scheduled above the desired number of pods. Defaults to 25%. This can not be 0 if MaxUnavailable is 0.
    • deployment.spec.minReadySeconds: Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready).
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/docker/index.html b/k8s/cka_en/foundamentals/docker/index.html index e9fc18b8..5d781d94 100644 --- a/k8s/cka_en/foundamentals/docker/index.html +++ b/k8s/cka_en/foundamentals/docker/index.html @@ -1,4 +1,4 @@ - Fundamentals - UPSkilling

    Docker Fundamentals

    Demo environment

    Linux: openSUSE 15.3

    cat /etc/os-release
    + Fundamentals - UPSkilling       

    Docker Fundamentals

    Demo environment

    Linux: openSUSE 15.3

    cat /etc/os-release
     

    Output

    NAME="openSUSE Leap"
     VERSION="15.3"
     ID="opensuse-leap"
    @@ -9,11 +9,11 @@
     CPE_NAME="cpe:/o:opensuse:leap:15.3"
     BUG_REPORT_URL="https://bugs.opensuse.org"
     HOME_URL="https://www.opensuse.org/"
    -

    Linux Primitives

    chroot(using pivot_root)

    • Changes the root directory for a process to any given directory

    namespaces

    • Different processes see different environments even though they are on the same host/OS
    • mnt (mount points)
    • pid (process tree)
    • net (network interfaces and connectivity)
    • ipc (interprocess communication framework)
    • uts (unix timesharing - domain name, hostname, etc.)
    • uid (user IDs and mappings)

    cgroups(control groups)

    • manage/limit resource allocation to individual processes
    • Prioritization of processes

    Apparmor and SELinux profiles

    • Security profiles to govern access to resources

    Kernel capabilities

    • without capabilities: root can do everything, everybody else may do nothing
    • 38 granular facilities to control privileges

    seccomp policies

    • Limitation of allowed kernel syscalls
    • Unallowed syscalls lead to process termination

    Netlink

    • A Linux kernel interface used for inter-process communication (IPC) between both the kernel and userspace processes, and between different userspace processes.

    Netfilter

    • A framework provided by the Linux kernel that allows various networking-related operations
    • Packet filtering, network address translation, and port translation(iptables/nftables)
    • used to direct network packages to individual containers

    More inforamtion could refer to LXC/LXD

    Let's download an image alpine to simulate an root file system under /opt/test folder.

    mkdir test
    -cd test
    -wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.4-x86_64.tar.gz
    -tar zxvf alpine-minirootfs-3.13.4-x86_64.tar.gz -C alpine-minirootfs/
    -

    Current directory structure.

    tree ./test -L 1
    +

    Linux Primitives

    chroot(using pivot_root)

    • Changes the root directory for a process to any given directory

    namespaces

    • Different processes see different environments even though they are on the same host/OS
    • mnt (mount points)
    • pid (process tree)
    • net (network interfaces and connectivity)
    • ipc (interprocess communication framework)
    • uts (unix timesharing - domain name, hostname, etc.)
    • uid (user IDs and mappings)

    cgroups(control groups)

    • manage/limit resource allocation to individual processes
    • Prioritization of processes

    Apparmor and SELinux profiles

    • Security profiles to govern access to resources

    Kernel capabilities

    • without capabilities: root can do everything, everybody else may do nothing
    • 38 granular facilities to control privileges

    seccomp policies

    • Limitation of allowed kernel syscalls
    • Unallowed syscalls lead to process termination

    Netlink

    • A Linux kernel interface used for inter-process communication (IPC) between both the kernel and userspace processes, and between different userspace processes.

    Netfilter

    • A framework provided by the Linux kernel that allows various networking-related operations
    • Packet filtering, network address translation, and port translation(iptables/nftables)
    • used to direct network packages to individual containers

    More inforamtion could refer to LXC/LXD

    Let's download an image alpine to simulate an root file system under /opt/test folder.

    mkdir test
    +cd test
    +wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.4-x86_64.tar.gz
    +tar zxvf alpine-minirootfs-3.13.4-x86_64.tar.gz -C alpine-minirootfs/
    +

    Current directory structure.

    tree ./test -L 1
     

    Output

    ./test
     ├── alpine-minirootfs-3.13.4-x86_64.tar.gz
     ├── bin
    @@ -33,75 +33,75 @@
     ├── tmp
     ├── usr
     └── var
    -

    Mount folder /opt/test/proc to a file and use command unshare to build a guest system.

    sudo mount -t tmpfs tmpfs /opt/test/proc
    -
    sudo unshare --pid --mount-proc=$PWD/test/proc --fork chroot ./test/ /bin/sh
    -/ # ps -ef
    -PID   USER     TIME  COMMAND
    -    1 root      0:00 /bin/sh
    -    2 root      0:00 ps -ef
    -/ # touch 123
    -/ # ls 123
    +

    Mount folder /opt/test/proc to a file and use command unshare to build a guest system.

    sudo mount -t tmpfs tmpfs /opt/test/proc
    +
    sudo unshare --pid --mount-proc=$PWD/test/proc --fork chroot ./test/ /bin/sh
    +/ # ps -ef
    +PID   USER     TIME  COMMAND
    +    1 root      0:00 /bin/sh
    +    2 root      0:00 ps -ef
    +/ # touch 123
    +/ # ls 123
     123
    -

    The file 123 created in guest system is accessable and writable from host system.

    su -
    -ls 123
    -echo hello > 123
    -

    We will see above change in guest system.

    / # cat 123
    +

    The file 123 created in guest system is accessable and writable from host system.

    su -
    +ls 123
    +echo hello > 123
    +

    We will see above change in guest system.

    / # cat 123
     hello
    -

    Let's create two folders /opt/test-1 and /opt/test-2.

    mkdir test-1
    -mkdir test-2
    -

    Create two guests system. Mount /opt/test/home/ to different folders for different guests.

    sudo mount --bind /opt/test-1 /opt/test/home/
    -sudo unshare --pid --mount-proc=$PWD/test/proc --fork chroot ./test/ /bin/sh
    -/ # cd /home
    -/home # echo "test-1" > 123.1
    -/home # cat 123.1
    +

    Let's create two folders /opt/test-1 and /opt/test-2.

    mkdir test-1
    +mkdir test-2
    +

    Create two guests system. Mount /opt/test/home/ to different folders for different guests.

    sudo mount --bind /opt/test-1 /opt/test/home/
    +sudo unshare --pid --mount-proc=$PWD/test/proc --fork chroot ./test/ /bin/sh
    +/ # cd /home
    +/home # echo "test-1" > 123.1
    +/home # cat 123.1
     test-1
    -
    sudo mount --bind /opt/test-2 /opt/test/home/
    -sudo unshare --pid --mount-proc=$PWD/test/proc --fork chroot ./test/ /bin/sh
    -/ # cd /home
    -/home # echo "test-2" > 123.2
    -/home # cat 123.2
    +
    sudo mount --bind /opt/test-2 /opt/test/home/
    +sudo unshare --pid --mount-proc=$PWD/test/proc --fork chroot ./test/ /bin/sh
    +/ # cd /home
    +/home # echo "test-2" > 123.2
    +/home # cat 123.2
     test-2
    -
    ll test/home
    -ll test-1/
    -ll test-2/
    -

    With above demo, the conclusion is that two guests share same home folder on host system and will impact each other.

    Installing Docker

    Install Docker engine by referring the guide, and Docker Desktop by referring the guide.

    Install engine via openSUSE repository automatically.

    sudo zypper in docker
    -

    The docker group is automatically created at package installation time. The user can communicate with the local Docker daemon upon its next login. The Docker daemon listens on a local socket which is accessible only by the root user and by the members of the docker group.

    Add current user to docker group.

    sudo usermod -aG docker $USER
    -

    Enable and start Docker engine.

    sudo systemctl enable docker.service 
    -sudo systemctl start docker.service 
    -sudo systemctl status docker.service
    -

    Container lifecycle

    Overview

    Pull down below images in advance.

    docker image pull busybox
    -docker image pull nginx
    -docker image pull alpine
    -docker image pull jenkins/jenkins:lts
    -docker image pull golang:1.12-alpine
    -docker image pull golang
    -

    Download some docker images. Create and run a new busybox container interactively and connect a pseudo terminal to it. Inside the container, use the top command to find out that /bin/sh is running as process with the PID 1 and top process is also running. After that, just exit.

    docker image ls
    -docker run -d -it --name busybox_v1 -v /opt/test:/docker busybox:latest /bin/sh
    -docker container ps -a
    -docker exec -it 185efe490507 /bin/sh
    -/ # top
    -Mem: 3627396K used, 12731512K free, 10080K shrd, 2920K buff, 2999340K cached
    -CPU:  0.0% usr  0.1% sys  0.0% nic 99.8% idle  0.0% io  0.0% irq  0.0% sirq
    -Load average: 0.38 1.09 1.29 2/277 14
    -  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
    -    1     0 root     S     1332  0.0   1  0.0 /bin/sh
    -    8     0 root     S     1332  0.0   2  0.0 /bin/sh
    -   14     8 root     R     1328  0.0   1  0.0 top
    -/ # exitbuild 
    -

    Start a new nginx container in detached mode. Use the docker exec command to start another shell (/bin/sh) in the nginx container. Use ps to find out that sh and ps commands are running in your container.

    docker run -d -it --name nginx_v1 -v /opt/test:/docker nginx:latest /bin/sh
    -docker container ps -a
    -docker exec -it edb640127a0d /bin/sh
    +
    ll test/home
    +ll test-1/
    +ll test-2/
    +

    With above demo, the conclusion is that two guests share same home folder on host system and will impact each other.

    Installing Docker

    Install Docker engine by referring the guide, and Docker Desktop by referring the guide.

    Install engine via openSUSE repository automatically.

    sudo zypper in docker
    +

    The docker group is automatically created at package installation time. The user can communicate with the local Docker daemon upon its next login. The Docker daemon listens on a local socket which is accessible only by the root user and by the members of the docker group.

    Add current user to docker group.

    sudo usermod -aG docker $USER
    +

    Enable and start Docker engine.

    sudo systemctl enable docker.service 
    +sudo systemctl start docker.service 
    +sudo systemctl status docker.service
    +

    Container lifecycle

    Overview

    Pull down below images in advance.

    docker image pull busybox
    +docker image pull nginx
    +docker image pull alpine
    +docker image pull jenkins/jenkins:lts
    +docker image pull golang:1.12-alpine
    +docker image pull golang
    +

    Download some docker images. Create and run a new busybox container interactively and connect a pseudo terminal to it. Inside the container, use the top command to find out that /bin/sh is running as process with the PID 1 and top process is also running. After that, just exit.

    docker image ls
    +docker run -d -it --name busybox_v1 -v /opt/test:/docker busybox:latest /bin/sh
    +docker container ps -a
    +docker exec -it 185efe490507 /bin/sh
    +/ # top
    +Mem: 3627396K used, 12731512K free, 10080K shrd, 2920K buff, 2999340K cached
    +CPU:  0.0% usr  0.1% sys  0.0% nic 99.8% idle  0.0% io  0.0% irq  0.0% sirq
    +Load average: 0.38 1.09 1.29 2/277 14
    +  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
    +    1     0 root     S     1332  0.0   1  0.0 /bin/sh
    +    8     0 root     S     1332  0.0   2  0.0 /bin/sh
    +   14     8 root     R     1328  0.0   1  0.0 top
    +/ # exitbuild 
    +

    Start a new nginx container in detached mode. Use the docker exec command to start another shell (/bin/sh) in the nginx container. Use ps to find out that sh and ps commands are running in your container.

    docker run -d -it --name nginx_v1 -v /opt/test:/docker nginx:latest /bin/sh
    +docker container ps -a
    +docker exec -it edb640127a0d /bin/sh
     # ps
    -/bin/sh: 2: ps: not found
    +/bin/sh: 2: ps: not found
     # apt-get update && apt-get install -y procps
     # ps
    -   PID TTY          TIME CMD
    -     8 pts/1    00:00:00 sh
    -   351 pts/1    00:00:00 ps
    +   PID TTY          TIME CMD
    +     8 pts/1    00:00:00 sh
    +   351 pts/1    00:00:00 ps
     # exit
    -

    Now we have two running containers below.

    docker container ps -a
    -

    Let's use docker logs to display the logs of the container we just exited from. The option --since 35m means display log in last 35 minutes.

    docker logs nginx_v1 --details --since 35m
    -docker logs busybox_v1 --details --since 35m
    +

    Now we have two running containers below.

    docker container ps -a
    +

    Let's use docker logs to display the logs of the container we just exited from. The option --since 35m means display log in last 35 minutes.

    docker logs nginx_v1 --details --since 35m
    +docker logs busybox_v1 --details --since 35m
     

    Let's make use of this to create a new stage:

    Use the docker stop command to end your nginx container.

    docker stop busybox_v1
     docker stop nginx_v1 
     docker container ps -a
    @@ -125,56 +125,56 @@
     

    Start a new container that bind-mounts host directory /opt/test to container directory /usr/share/nginx/html as a volume, so that NGINX will publish the HTML file wee just created instead of its default message via http://localhost:49159/ below.

    docker run -d -P --mount type=bind,source=/opt/test/,target=/usr/share/nginx/html --name nginx_v3-1 nginx:latest
     docker container ps -a
     

    Check nginx config file on where is the html home page stored in container.

    docker exec -it nginx_v3-1 /bin/sh
    -# cd /etc/nginx/conf.d
    +# cd /etc/nginx/conf.d
     # ls
     default.conf
    -# cat default.conf
    +# cat default.conf
     server {
         listen       80;
         listen  [::]:80;
         server_name  localhost;
     
    -    #access_log  /var/log/nginx/host.access.log  main;
    +    #access_log  /var/log/nginx/host.access.log  main;
     
         location / {
             root   /usr/share/nginx/html;  <--
             index  index.html index.htm;
         }
     
    -    #error_page  404              /404.html;
    +    #error_page  404              /404.html;
     
    -    # redirect server error pages to the static page /50x.html
    +    # redirect server error pages to the static page /50x.html
         #
         error_page   500 502 503 504  /50x.html;
         location = /50x.html {
             root   /usr/share/nginx/html;
         }
     
    -    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    +    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
         #
    -    #location ~ \.php$ {
    -    #    proxy_pass   http://127.0.0.1;
    +    #location ~ \.php$ {
    +    #    proxy_pass   http://127.0.0.1;
         #}
     
    -    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    +    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
         #
    -    #location ~ \.php$ {
    -    #    root           html;
    -    #    fastcgi_pass   127.0.0.1:9000;
    -    #    fastcgi_index  index.php;
    -    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    -    #    include        fastcgi_params;
    +    #location ~ \.php$ {
    +    #    root           html;
    +    #    fastcgi_pass   127.0.0.1:9000;
    +    #    fastcgi_index  index.php;
    +    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    +    #    include        fastcgi_params;
         #}
     
    -    # deny access to .htaccess files, if Apache's document root
    -    # concurs with nginx's one
    +    # deny access to .htaccess files, if Apache's document root
    +    # concurs with nginx's one
         #
    -    #location ~ /\.ht {
    -    #    deny  all;
    +    #location ~ /\.ht {
    +    #    deny  all;
         #}
     }
    -# cd /usr/share/nginx/html
    -# cat index.html              
    +# cd /usr/share/nginx/html
    +# cat index.html              
       <html>
       <head>
           <title>Sample Website from my container</title>
    @@ -213,14 +213,14 @@
     

    Output

    FROM nginx:latest
     
     # copy the custom website into the image
    -COPY index.html /usr/share/nginx/html
    +COPY index.html /usr/share/nginx/html
     
     # copy the SSL configuration file into the image
    -COPY ssl.conf /etc/nginx/conf.d/ssl.conf
    +COPY ssl.conf /etc/nginx/conf.d/ssl.conf
     
     # download the SSL key and certificate into the image
    -COPY nginx.key /etc/nginx/ssl/
    -COPY nginx.crt /etc/nginx/ssl/
    +COPY nginx.key /etc/nginx/ssl/
    +COPY nginx.crt /etc/nginx/ssl/
     
     # expose the HTTPS port
     EXPOSE 443
    @@ -238,7 +238,7 @@
     

    Tag the image to give image a nice name and a release number as tag, e.g., name is secure_nginx_0001, tag is v1.

    docker tag nginx:my1 <your account id>secure_nginx_0001:v1
     docker push <your account id>secure_nginx_0001:v1
     docker image ls
    -

    Multi-stage Dockerfile

    Let's show an example of multi-stage build. The multi-stage in the context of Docker means, we can have more than one line with a FROM keyword.

    Create folder /opt/tmp-2 and /opt/tmp-2/tmpl.

    Create files edit.html, view.html, wiki.go and structure likes below.

    tree -l /opt/tmp-2
    +

    Multi-stage Dockerfile

    Let's show an example of multi-stage build. The multi-stage in the context of Docker means, we can have more than one line with a FROM keyword.

    Create folder /opt/tmp-2 and /opt/tmp-2/tmpl.

    Create files edit.html, view.html, wiki.go and structure likes below.

    tree -l /opt/tmp-2
     
    .
     ├── tmpl
     │   ├── edit.html
    @@ -250,22 +250,22 @@
     
     ## copy the go source code over and build the binary
     WORKDIR /go/src
    -COPY wiki.go /go/src/wiki.go
    -RUN go build wiki.go
    +COPY wiki.go /go/src/wiki.go
    +RUN go build wiki.go
     
     # app exec stage
     # separate & new image starts here!#
     FROM alpine:3.9
     
     # prepare file system etc
    -RUN mkdir -p /app/data /app/tmpl && adduser -S -D -H -h /app appuser
    -COPY tmpl/* /app/tmpl/
    +RUN mkdir -p /app/data /app/tmpl && adduser -S -D -H -h /app appuser
    +COPY tmpl/* /app/tmpl/
     
     # get the compiled binary from the previous stage
    -COPY --from=builder /go/src/wiki /app/wiki
    +COPY --from=builder /go/src/wiki /app/wiki
     
     # prepare runtime env
    -RUN chown -R appuser /app
    +RUN chown -R appuser /app
     USER appuser
     WORKDIR /app
     
    @@ -276,4 +276,4 @@
     

    Run the image in detached mode, create a port forwarding from port 8080 in the container to port 1090 on the host.

    docker run -d -p 1090:8080 --name golan_v1 lizard/golang:my1
     

    Access the container via link http://localhost:1090

    Tab the golang image we created and push it to DockerHub.

    docker tag lizard/golang:my1 <your acccount id>/golang_0001:v1
     docker push <your acccount id>/golang_0001:v1
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/healthcheck/index.html b/k8s/cka_en/foundamentals/healthcheck/index.html index e78eaf36..b0a5422b 100644 --- a/k8s/cka_en/foundamentals/healthcheck/index.html +++ b/k8s/cka_en/foundamentals/healthcheck/index.html @@ -1,4 +1,4 @@ - Health Check - UPSkilling

    Health Check

    Status of Pod and Container

    Scenario: Create a pod with two containers.

    Demo:

    Create a Pod multi-pods with two containers nginx and busybox.

    kubectl apply -f - << EOF
    + Health Check - UPSkilling       

    Health Check

    Status of Pod and Container

    Scenario: Create a pod with two containers.

    Demo:

    Create a Pod multi-pods with two containers nginx and busybox.

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -109,4 +109,4 @@
     

    Liveness probes do not wait for readiness probes to succeed. If we want to wait before executing a liveness probe you should use initialDelaySeconds or a startupProbe.

    Clean up.

    kubectl delete pod liveness-exec
     kubectl delete pod multi-pods 
     kubectl delete pod readiness
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/helming/index.html b/k8s/cka_en/foundamentals/helming/index.html index dbe6853d..a54e4ac6 100644 --- a/k8s/cka_en/foundamentals/helming/index.html +++ b/k8s/cka_en/foundamentals/helming/index.html @@ -1,4 +1,4 @@ - Helming - UPSkilling

    Helm Chart

    Install Helm

    Install Helm on cka001.

    # https://github.com/helm/helm/releases
    + Helming - UPSkilling       

    Helm Chart

    Install Helm

    Install Helm on cka001.

    # https://github.com/helm/helm/releases
     wget https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz
     tar -zxvf helm-v3.8.2-linux-amd64.tar.gz
     cp linux-amd64/helm /usr/bin/
    @@ -63,7 +63,7 @@
     

    Check mysql Pod status.

    kubectl get pod
     

    Result

    NAME                                      READY   STATUS    RESTARTS   AGE
     mysql-0                                   1/1     Running   0          72s
    -

    Develop a Chart

    Below is a demo on how to develop a Chart.

    Execute helm create to initiate a Chart:

    # Naming conventions of Chart: lowercase a~z and -(minus sign)
    +

    Develop a Chart

    Below is a demo on how to develop a Chart.

    Execute helm create to initiate a Chart:

    # Naming conventions of Chart: lowercase a~z and -(minus sign)
     helm create cka-demo
     

    A folder cka-demo was created. Check the folder structure.

    tree cka-demo/
     

    Output

    cka-demo/
    @@ -112,111 +112,111 @@
     {{- end }}
     

    Deployment Template

    Let's use Busybox service to generate information. We use kubectl create deployment --dry-run=client -oyaml to generate Deployment yaml file and write it the yaml file content into file templates/deployment.yaml.

    kubectl create deployment cka-demo-busybox --image=busybox:latest --dry-run=client -oyaml > templates/deployment.yaml
     

    Check content of deployment yaml file templates/deployment.yaml.

    cat templates/deployment.yaml
    -
    apiVersion: apps/v1
    -kind: Deployment
    -metadata:
    -  creationTimestamp: null
    -  labels:
    -    app: cka-demo-busybox
    -  name: cka-demo-busybox
    -spec:
    -  replicas: 1
    -  selector:
    -    matchLabels:
    -      app: cka-demo-busybox
    -  strategy: {}
    -  template:
    -    metadata:
    -      creationTimestamp: null
    -      labels:
    -        app: cka-demo-busybox
    -    spec:
    -      containers:
    -      - image: busybox:latest
    -        name: busybox
    -        resources: {}
    -status: {}
    +
    apiVersion: apps/v1
    +kind: Deployment
    +metadata:
    +  creationTimestamp: null
    +  labels:
    +    app: cka-demo-busybox
    +  name: cka-demo-busybox
    +spec:
    +  replicas: 1
    +  selector:
    +    matchLabels:
    +      app: cka-demo-busybox
    +  strategy: {}
    +  template:
    +    metadata:
    +      creationTimestamp: null
    +      labels:
    +        app: cka-demo-busybox
    +    spec:
    +      containers:
    +      - image: busybox:latest
    +        name: busybox
    +        resources: {}
    +status: {}
     

    Edit file templates/deployment.yaml.

    vi templates/deployment.yaml
    -

    Let's replace value of .spec.replicas from 1 to a variable {{ .Values.replicaCount }}, so we can dynamicly assign replicas number for other Deployment.

    apiVersion: apps/v1
    -kind: Deployment
    -metadata:
    -  creationTimestamp: null
    -  labels:
    -    app: cka-demo-busybox
    -  name: cka-demo-busybox
    -spec:
    -  replicas: {{ .Values.replicaCount }}
    -  selector:
    -    matchLabels:
    -      app: cka-demo-busybox
    -  strategy: {}
    -  template:
    -    metadata:
    -      creationTimestamp: null
    -      labels:
    -        app: cka-demo-busybox
    -    spec:
    -      containers:
    -      - image: busybox:latest
    -        name: busybox
    -        resources: {}
    -status: {}
    +

    Let's replace value of .spec.replicas from 1 to a variable {{ .Values.replicaCount }}, so we can dynamicly assign replicas number for other Deployment.

    apiVersion: apps/v1
    +kind: Deployment
    +metadata:
    +  creationTimestamp: null
    +  labels:
    +    app: cka-demo-busybox
    +  name: cka-demo-busybox
    +spec:
    +  replicas: {{ .Values.replicaCount }}
    +  selector:
    +    matchLabels:
    +      app: cka-demo-busybox
    +  strategy: {}
    +  template:
    +    metadata:
    +      creationTimestamp: null
    +      labels:
    +        app: cka-demo-busybox
    +    spec:
    +      containers:
    +      - image: busybox:latest
    +        name: busybox
    +        resources: {}
    +status: {}
     

    The .spec.replicas will be replaced by actula value of .Values.replicaCount during deployment.

    Let's create another file values.yaml and add a variable replicaCount with default value 1 into the file. Strong recommended to add comments for each value we defined in file values.yaml.

    vi values.yaml
    -
    # Number of deployment replicas
    +
    # Number of deployment replicas
     replicaCount: 1
    -

    Let's add more variables into file templates/deployment.yaml.

    • Replace Release name .metadata.name by {{ .Release.Name }} and filled with variable defined in file values.yaml.
    • Replace label name .metadata.labels by {{- include "cka-demo.labels" . | nindent 4 }}, and filled with labels name cka-demo.labels defined in file _helpers.tpl.
    • Replace .spec.replicas by {{ .Values.replicaCount }} and filled with variable defined in file values.yaml.
    • Replace .spec.selector.matchLabels by {{- include "cka-demo.selectorLabels" . | nindent 6 }} and filled with cka-demo.selectorLabels defined in file _helpers.tpl.
    • Replace .spec.template.metadata.labels by {{- include "cka-demo.selectorLabels" . | nindent 8 }} and filled with cka-demo.selectorLabels defined in file _helpers.tpl.
    • Replace .spec.template.spec.containers[0].image by {{ .Values.image.repository }} and {{ .Values.image.tag }} and filled with variables defined in values.yaml for image name and image tag.
    • Replace .spec.template.spec.containers[0].command and add if-else statement, if .Values.passExam is true, execute commands defined in .Values.passCommand, if false, execute commands defined in .Values.lostCommand.
    • Use key from ConfigMap from .spec.template.spec.containers[0].env as prefix of ConfigMap name and filled with {{ .Values.studentName }} defined in file values.yaml.
    • Replace .spec.template.spec.containers[0].resources by {{ .Values.resources }} and filled with variable defined in file values.yaml.

    The .Release.Name is built-in object, no need to be specified in file values.yaml. It's generated by Release by helm install.

    Remove unused lines and final one looks like below.

    apiVersion: apps/v1
    -kind: Deployment
    -metadata:
    -  name: {{ .Release.Name }}
    -  labels:
    -    {{- include "cka-demo.labels" . | nindent 4 }}
    -spec:
    -  replicas: {{ .Values.replicaCount }}
    -  selector:
    -    matchLabels:
    -      {{- include "cka-demo.selectorLabels" . | nindent 6 }}
    -  template:
    -    metadata:
    -      labels:
    -        {{- include "cka-demo.selectorLabels" . | nindent 8 }}
    -    spec:
    -      containers:
    -      - name: id-generator
    -        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
    -        {{- if .Values.passExam }}
    -        {{- with .Values.passCommand }}
    -        command: {{ range . }}
    -          - {{ . | quote }}
    -          {{- end }}
    -          {{- end }}
    -        {{- else }}
    -        {{- with .Values.lostCommand }}
    -        command: {{ range . }}
    -          - {{ . | quote }}
    -          {{- end }}
    -          {{- end }}
    -        {{- end }}
    -        env:
    -        - name: CKA_SCORE
    -          valueFrom:
    -            configMapKeyRef:
    -              name: {{ .Values.studentName }}-cka-score
    -              key: cka_score
    -        {{- with .Values.resources }}
    -        resources:
    -            {{- toYaml . | nindent 12 }}
    -          {{- end}}
    -      restartPolicy: Always
    +

    Let's add more variables into file templates/deployment.yaml.

    • Replace Release name .metadata.name by {{ .Release.Name }} and filled with variable defined in file values.yaml.
    • Replace label name .metadata.labels by {{- include "cka-demo.labels" . | nindent 4 }}, and filled with labels name cka-demo.labels defined in file _helpers.tpl.
    • Replace .spec.replicas by {{ .Values.replicaCount }} and filled with variable defined in file values.yaml.
    • Replace .spec.selector.matchLabels by {{- include "cka-demo.selectorLabels" . | nindent 6 }} and filled with cka-demo.selectorLabels defined in file _helpers.tpl.
    • Replace .spec.template.metadata.labels by {{- include "cka-demo.selectorLabels" . | nindent 8 }} and filled with cka-demo.selectorLabels defined in file _helpers.tpl.
    • Replace .spec.template.spec.containers[0].image by {{ .Values.image.repository }} and {{ .Values.image.tag }} and filled with variables defined in values.yaml for image name and image tag.
    • Replace .spec.template.spec.containers[0].command and add if-else statement, if .Values.passExam is true, execute commands defined in .Values.passCommand, if false, execute commands defined in .Values.lostCommand.
    • Use key from ConfigMap from .spec.template.spec.containers[0].env as prefix of ConfigMap name and filled with {{ .Values.studentName }} defined in file values.yaml.
    • Replace .spec.template.spec.containers[0].resources by {{ .Values.resources }} and filled with variable defined in file values.yaml.

    The .Release.Name is built-in object, no need to be specified in file values.yaml. It's generated by Release by helm install.

    Remove unused lines and final one looks like below.

    apiVersion: apps/v1
    +kind: Deployment
    +metadata:
    +  name: {{ .Release.Name }}
    +  labels:
    +    {{- include "cka-demo.labels" . | nindent 4 }}
    +spec:
    +  replicas: {{ .Values.replicaCount }}
    +  selector:
    +    matchLabels:
    +      {{- include "cka-demo.selectorLabels" . | nindent 6 }}
    +  template:
    +    metadata:
    +      labels:
    +        {{- include "cka-demo.selectorLabels" . | nindent 8 }}
    +    spec:
    +      containers:
    +      - name: id-generator
    +        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
    +        {{- if .Values.passExam }}
    +        {{- with .Values.passCommand }}
    +        command: {{ range . }}
    +          - {{ . | quote }}
    +          {{- end }}
    +          {{- end }}
    +        {{- else }}
    +        {{- with .Values.lostCommand }}
    +        command: {{ range . }}
    +          - {{ . | quote }}
    +          {{- end }}
    +          {{- end }}
    +        {{- end }}
    +        env:
    +        - name: CKA_SCORE
    +          valueFrom:
    +            configMapKeyRef:
    +              name: {{ .Values.studentName }}-cka-score
    +              key: cka_score
    +        {{- with .Values.resources }}
    +        resources:
    +            {{- toYaml . | nindent 12 }}
    +          {{- end}}
    +      restartPolicy: Always
     

    Update file values.yaml with variables default values. Suggestions:add variables one and test one, don't add all at one time.

    vi values.yaml
    -
    # Number of deployment replicas 
    +
    # Number of deployment replicas 
     replicaCount: 1
     
    -# Image repository and tag
    +# Image repository and tag
     image:
       repository: busybox
       tag: latest
     
    -# Container start command
    +# Container start command
     passCommand:
       - '/bin/sh'
       - '-c'
    @@ -226,7 +226,7 @@
       - '-c'
       - "echo Your CKA score is $(CKA_SCORE), Come on! you can do it next time! ; sleep 86400"
     
    -# Container resources
    +# Container resources
     resources:
       limits:
         cpu: 200m
    @@ -235,22 +235,22 @@
         cpu: 100m
         memory: 128Mi
     
    -# Student Name
    +# Student Name
     studentName: whoareyou
     
    -# Student pass CKA exam or not
    +# Student pass CKA exam or not
     passExam: true
     

    ConfigMap Template

    ConfigMap is referred in the Deployment, hence we need define the ConfigMap template. We will combine name of ConfigMap and cka_score as a variable, like name-cka-score.

    vi templates/configmap.yaml
    -
    apiVersion: v1
    -kind: ConfigMap
    -metadata:
    -  name: {{ .Values.studentName }}-cka-score
    -  labels:
    -    {{- include "cka-demo.labels" . | nindent 4 }}
    -data:
    -  cka_score: {{ .Values.ckaScore | quote }}
    +
    apiVersion: v1
    +kind: ConfigMap
    +metadata:
    +  name: {{ .Values.studentName }}-cka-score
    +  labels:
    +    {{- include "cka-demo.labels" . | nindent 4 }}
    +data:
    +  cka_score: {{ .Values.ckaScore | quote }}
     

    The studentName was already defined in file values.yaml, we just need add ckaScore with default value.

    vi values.yaml
    -
    # Student CKA Score
    +
    # Student CKA Score
     ckaScore: 100
     

    _helpers.tpl

    Define a common template _helpers.tpl to add labels and labels of Selector for labels of Deployment and ConfigMap.

    vi templates/_helpers.tpl
     
    {{/*
    @@ -278,15 +278,15 @@
     

    Add author info for the Chart

    vi Chart.yaml
     
    maintainers:
       - name: James.H
    -

    Final Chart.yaml looks like below. Don't forget to update appVersion: "v1.23" to current Kubernetes API version.

    apiVersion: v2
    -name: cka-demo
    -description: A Helm chart for CKA demo.
    -type: application
    -version: 0.1.0
    -appVersion: "v1.23"
    -maintainers:
    -  - name: James.H
    -icon: file://./kubernetes-cka-color.svg
    +

    Final Chart.yaml looks like below. Don't forget to update appVersion: "v1.23" to current Kubernetes API version.

    apiVersion: v2
    +name: cka-demo
    +description: A Helm chart for CKA demo.
    +type: application
    +version: 0.1.0
    +appVersion: "v1.23"
    +maintainers:
    +  - name: James.H
    +icon: file://./kubernetes-cka-color.svg
     

    Chart Debug

    Use helm lint to verify above change.

    helm lint
     
    1 chart(s) linted, 0 chart(s) failed
     

    helm lint only check format of Chart, won't check Manifest file.

    We can use helm install --debug --dry-run or helm template to check Manifest output in order to verify all yaml files are correct or not.

    helm template cka-demo ./
    @@ -366,4 +366,4 @@
     Template                                  # 当前模板信息
     Template.Name                             # 当前模板文件路径
     Template.BasePath                         # 当前模板目录路径
    -

    Reference:

    \ No newline at end of file +

    Reference:

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/hpa/index.html b/k8s/cka_en/foundamentals/hpa/index.html index b990b833..6240fc2e 100644 --- a/k8s/cka_en/foundamentals/hpa/index.html +++ b/k8s/cka_en/foundamentals/hpa/index.html @@ -1,22 +1,22 @@ - Horizontal Pod Autoscaling - UPSkilling

    Horizontal Pod Autoscaling (HPA)

    Scenario:

    • Install Metrics Server component
    • Create Deployment podinfo and Service podinfo for stress testing
    • Create HPA my-hpa
    • Stress Testing

    Demo:

    Install Metrics Server component

    Download yaml file for Metrics Server component

    wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
    + Horizontal Pod Autoscaling - UPSkilling       

    Horizontal Pod Autoscaling (HPA)

    Scenario:

    • Install Metrics Server component
    • Create Deployment podinfo and Service podinfo for stress testing
    • Create HPA my-hpa
    • Stress Testing

    Demo:

    Install Metrics Server component

    Download yaml file for Metrics Server component

    wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
     

    Replace Google image by Aliyun image image: registry.aliyuncs.com/google_containers/metrics-server:v0.6.1.

    sed -i 's/k8s\.gcr\.io\/metrics-server\/metrics-server\:v0\.6\.1/registry\.aliyuncs\.com\/google_containers\/metrics-server\:v0\.6\.1/g' components.yaml
     

    Change arg of deployment metrics-server by adding --kubelet-insecure-tls to disable tls certificate validation.

    vi components.yaml
    -

    Updated arg of metrics-server is below.

    ......
    -  template:
    -    metadata:
    -      labels:
    -        k8s-app: metrics-server
    -    spec:
    -      containers:
    -      - args:
    -        - --cert-dir=/tmp
    -        - --secure-port=4443
    -        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
    -        - --kubelet-use-node-status-port
    -        - --metric-resolution=15s
    -        - --kubelet-insecure-tls
    -        image: registry.aliyuncs.com/google_containers/metrics-server:v0.6.1
    -......
    +

    Updated arg of metrics-server is below.

    ......
    +  template:
    +    metadata:
    +      labels:
    +        k8s-app: metrics-server
    +    spec:
    +      containers:
    +      - args:
    +        - --cert-dir=/tmp
    +        - --secure-port=4443
    +        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
    +        - --kubelet-use-node-status-port
    +        - --metric-resolution=15s
    +        - --kubelet-insecure-tls
    +        image: registry.aliyuncs.com/google_containers/metrics-server:v0.6.1
    +......
     

    Appy the yaml file components.yaml to deploy metrics-server.

    kubectl apply -f components.yaml
     

    Below resources were crested.

    serviceaccount/metrics-server created
     clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
    @@ -158,4 +158,4 @@
     

    Clean up.

    kubectl delete service podinfo
     kubectl delete deployment podinfo
     kubectl delete hpa my-hpa
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/ingress/index.html b/k8s/cka_en/foundamentals/ingress/index.html index 5e31da3a..6f14d608 100644 --- a/k8s/cka_en/foundamentals/ingress/index.html +++ b/k8s/cka_en/foundamentals/ingress/index.html @@ -1,4 +1,4 @@ - Ingress - UPSkilling

    Ingress-nginx

    Scenario

    *Deploy Ingress Controller. * Create two deployment nginx-app-1 and nginx-app-2. *Host directory /root/html-1 and /root/html-2 will be created and mounted to two Deployments on running host. * Create Service. *Create Service nginx-app-1 and nginx-app-2 and map to related Deployment nginx-app-1 and nginx-app-2. * Create Ingress. *Create Ingress resource nginx-app and map to two Services nginx-app-1 and nginx-app-1. * Test Accessibility. * Send HTTP request to two hosts defined in Ingress

    Reference

    *Github ingress-nginx * Installation Guide

    Deploy Ingress Controller

    Get Ingress Controller yaml file. The latest version link is in Installation Guide.

    wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml
    + Ingress - UPSkilling       

    Ingress-nginx

    Scenario

    *Deploy Ingress Controller. * Create two deployment nginx-app-1 and nginx-app-2. *Host directory /root/html-1 and /root/html-2 will be created and mounted to two Deployments on running host. * Create Service. *Create Service nginx-app-1 and nginx-app-2 and map to related Deployment nginx-app-1 and nginx-app-2. * Create Ingress. *Create Ingress resource nginx-app and map to two Services nginx-app-1 and nginx-app-1. * Test Accessibility. * Send HTTP request to two hosts defined in Ingress

    Reference

    *Github ingress-nginx * Installation Guide

    Deploy Ingress Controller

    Get Ingress Controller yaml file. The latest version link is in Installation Guide.

    wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml
     

    Below two images's sources needto be changed to Aliyun.

    image: k8s.gcr.io/ingress-nginx/controller:v1.2.1@sha256:5516d103a9c2ecc4f026efbd4b40662ce22dc1f824fb129ed121460aaa5c47f8
     image: registry.k8s.io/ingress-nginx/controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5
     
    image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
    @@ -168,4 +168,4 @@
     kubectl delete service nginx-app-2
     kubectl delete deployment nginx-app-1
     kubectl delete deployment nginx-app-2
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/job/index.html b/k8s/cka_en/foundamentals/job/index.html index c7c29812..294bbf28 100644 --- a/k8s/cka_en/foundamentals/job/index.html +++ b/k8s/cka_en/foundamentals/job/index.html @@ -1,4 +1,4 @@ - Job and Cronjob - UPSkilling

    Job and Cronjob

    Job

    Scenario

    • Create Job.

    Demo:

    Create Job pi.

    kubectl apply -f - << EOF
    + Job and Cronjob - UPSkilling       

    Job and Cronjob

    Job

    Scenario

    • Create Job.

    Demo:

    Create Job pi.

    kubectl apply -f - << EOF
     apiVersion: batch/v1
     kind: Job
     metadata:
    @@ -43,4 +43,4 @@
     hello   */1 * * * *   False     0        <none>          25s   hello        busybox   <none>
     

    Monitor Jobs. Every 1 minute a new job will be created.

    kubectl get jobs -w
     

    Clean up

    kubectl delete cronjob hello
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/kyma/index.html b/k8s/cka_en/foundamentals/kyma/index.html index 276a6c2e..de29d94c 100644 --- a/k8s/cka_en/foundamentals/kyma/index.html +++ b/k8s/cka_en/foundamentals/kyma/index.html @@ -1,4 +1,4 @@ - Kyma - UPSkilling

    Kyma

    Deploy Kyma on control plane node.

    Install Kyma CLI

    Install Kyma CLI on Linux, run:

    curl -Lo kyma.tar.gz "https://github.com/kyma-project/cli/releases/download/$(curl -s https://api.github.com/repos/kyma-project/cli/releases/latest | grep tag_name | cut -d '"' -f 4)/kyma_Linux_x86_64.tar.gz"
    + Kyma - UPSkilling       

    Kyma

    Deploy Kyma on control plane node.

    Install Kyma CLI

    Install Kyma CLI on Linux, run:

    curl -Lo kyma.tar.gz "https://github.com/kyma-project/cli/releases/download/$(curl -s https://api.github.com/repos/kyma-project/cli/releases/latest | grep tag_name | cut -d '"' -f 4)/kyma_Linux_x86_64.tar.gz"
     mkdir /opt/kyma-release
     tar -C /opt/kyma-release -zxvf kyma.tar.gz
     chmod +x /opt/kyma-release/kyma
    @@ -30,4 +30,4 @@
       - name: "serverless"
       - name: "application-connector"
         namespace: "kyma-integration"
    -

    Reference:

    By default, Kyma is installed with the default chart values defined in the values.yaml files. You can also control the allocation of resources, such as memory and CPU, that the components consume by installing Kyma with the following pre-defined profiles:

    • Evaluation needs limited resources and is suited for trial purposes.
    • Production is configured for high availability and scalability. It requires more resources than the evaluation profile but is a better choice for production workload.

    Install Kyma

    To see a complete list of all Kyma components go to the components.yaml file. Install specific components kyma deploy --components-file {COMPONENTS_FILE_PATH}

    \ No newline at end of file +

    Reference:

    By default, Kyma is installed with the default chart values defined in the values.yaml files. You can also control the allocation of resources, such as memory and CPU, that the components consume by installing Kyma with the following pre-defined profiles:

    • Evaluation needs limited resources and is suited for trial purposes.
    • Production is configured for high availability and scalability. It requires more resources than the evaluation profile but is a better choice for production workload.

    Install Kyma

    To see a complete list of all Kyma components go to the components.yaml file. Install specific components kyma deploy --components-file {COMPONENTS_FILE_PATH}

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/memo/index.html b/k8s/cka_en/foundamentals/memo/index.html index cbe25683..13b7c0a4 100644 --- a/k8s/cka_en/foundamentals/memo/index.html +++ b/k8s/cka_en/foundamentals/memo/index.html @@ -1,59 +1,59 @@ - Memo - UPSkilling

    Kubernetes Learning Memo

    Basic Concepts of Kubernetes

    Kubernetes Components

    A Kubernetes cluster consists of the components that represent the control plane and a set of machines called nodes.

    The components of a Kubernetes cluster

    Kubernetes Components:

    • Control Plane Components
    • kube-apiserver:
      • query and manipulate the state of objects in Kubernetes.
      • play as "communication hub" among all resources in cluster.
      • provide cluster security authentication, authorization, and role assignment.
      • the only one can connect to etcd.
    • etcd:
      • all Kubernetes objects are stored on etcd.
      • Kubernetes objects are persistent entities in the Kubernetes system, which are used to represent the state of your cluster.
    • kube-scheduler:
      • watches for newly created Pods with no assigned node, and selects a node for them to run on.
    • kube-controller-manager: runs controller processes.
      • Node controller: Responsible for noticing and responding when nodes go down.
      • Job controller: Watches for Job objects that represent one-off tasks, then creates Pods to run those tasks to completion.
      • Endpoints controller: Populates the Endpoints object (that is, joins Services & Pods).
      • Service Account & Token controllers: Create default accounts and API access tokens for new namespaces.
    • cloud-controller-manager: embeds cloud-specific control logic and only runs controllers that are specific to your cloud provider, no need for own premises and learning environment.
      • Node controller: For checking the cloud provider to determine if a node has been deleted in the cloud after it stops responding
      • Route controller: For setting up routes in the underlying cloud infrastructure
      • Service controller: For creating, updating and deleting cloud provider load balancers
    • Node Components
    • kubelet:
      • An agent that runs on each node in the cluster.
      • Manage node. It makes sure that containers are running in a Pod. kubelet registers and updates nodes information to APIServer, and APIServer stores them into etcd.
      • Manage pod. Watch pod via APIServer, and action on pods or containers in pods.
      • Health check at container level.
    • kube-proxy:
      • is a network proxy that runs on each node in cluster.
      • iptables
      • ipvs
      • maintains network rules on nodes.
    • Container runtime:
      • is the software that is responsible for running containers.
    • Addons
    • DNS: is a DNS server and required by all Kubernetes clusters.
    • Web UI (Dashboard): web-based UI for Kubernetes clusters.
    • Container Resource Monitoring: records generic time-series metrics about containers in a central database
    • Cluster-level Logging: is responsible for saving container logs to a central log store with search/browsing interface.

    Scalability:

    • Scaling out (horizontal scaling) by adding more servers to your architecture to spread the workload across more machines.
    • Scaling up (vertical scaling) by adding more hard drives and memory to increase the computing capacity of physical servers.

    Kubernetes API

    The REST API is the fundamental fabric of Kubernetes. All operations and communications between components, and external user commands are REST API calls that the API Server handles. Consequently, everything in the Kubernetes platform is treated as an API object and has a corresponding entry in the API.

    The core of Kubernetes' control plane is the API server.

    • CRI: Container Runtime Interface
    • CNI: Container Network Interface
    • CSI: Container Storage Interface

    The API server exposes an HTTP API that lets end users, different parts of cluster, and external components communicate with one another.

    The Kubernetes API lets we query and manipulate the state of API objects in Kubernetes (for example: Pods, Namespaces, ConfigMaps, and Events).

    Kubernetes API:

    • OpenAPI specification
    • OpenAPI V2
    • OpenAPI V3
    • Persistence. Kubernetes stores the serialized state of objects by writing them into etcd.
    • API groups and versioning. Versioning is done at the API level. API resources are distinguished by their API group, resource type, namespace (for namespaced resources), and name.
    • API changes
    • API Extension

    API Version

    The API versioning and software versioning are indirectly related. The API and release versioning proposal describes the relationship between API versioning and software versioning. Different API versions indicate different levels of stability and support.

    Here's a summary of each level:

    • Alpha:
    • The version names contain alpha (for example, v1alpha1).
    • The software may contain bugs. Enabling a feature may expose bugs. A feature may be disabled by default.
    • The support for a feature may be dropped at any time without notice.
    • The API may change in incompatible ways in a later software release without notice.
    • The software is recommended for use only in short-lived testing clusters, due to increased risk of bugs and lack of long-term support.
    • Beta:
    • The version names contain beta (for example, v2beta3).
    • The software is well tested. Enabling a feature is considered safe. Features are enabled by default.
    • The support for a feature will not be dropped, though the details may change.
    • The schema and/or semantics of objects may change in incompatible ways in a subsequent beta or stable release. When this happens, migration instructions are provided. Schema changes may require deleting, editing, and re-creating API objects. The editing process may not be straightforward. The migration may require downtime for applications that rely on the feature.
    • The software is not recommended for production uses. Subsequent releases may introduce incompatible changes. If you have multiple clusters which can be upgraded independently, you may be able to relax this restriction. Note: Please try beta features and provide feedback. After the features exit beta, it may not be practical to make more changes.
    • Stable:
    • The version name is vX where X is an integer.
    • The stable versions of features appear in released software for many subsequent versions.

    Command to get current API

    kubectl api-resources
    -

    API Group

    API groups make it easier to extend the Kubernetes API. The API group is specified in a REST path and in the apiVersion field of a serialized object.

    There are several API groups in Kubernetes:

    • The core (also called legacy) group is found at REST path /api/v1.
    • The core group is not specified as part of the apiVersion field, for example, apiVersion: v1.
    • The named groups are at REST path /apis/$GROUP_NAME/$VERSION and use apiVersion: $GROUP_NAME/$VERSION (for example, apiVersion: batch/v1).

    Kubernetes Objects

    Objects Overview

    • Object Spec:
    • providing a description of the characteristics the resource created to have: its desired state.
    • Object Status:
    • describes the current state of the object.

    Example of Deployment as an object that can represent an application running on cluster.

    apiVersion: apps/v1  # Which version of the Kubernetes API you're using to create this object
    -kind: Deployment     # What kind of object you want to create
    -metadata:            # Data that helps uniquely identify the object, including a name string, UID, and optional namespace
    -  name: nginx-deployment
    -spec:                # What state you desire for the object
    -  selector:
    -    matchLabels:
    -      app: nginx
    -  replicas: 2 # tells deployment to run 2 pods matching the template
    -  template:
    -    metadata:
    -      labels:
    -        app: nginx
    -    spec:
    -      containers:
    -      - name: nginx
    -        image: nginx:1.14.2
    -        ports:
    -        - containerPort: 80
    -

    Object Management

    The kubectl command-line tool supports several different ways to create and manage Kubernetes objects. Read the Kubectl book for details.

    A Kubernetes object should be managed using ONLY one technique. Mixing and matching techniques for the same object results in undefined behavior.

    Three management techniques:

    • Imperative commands
    • operates directly on live objects in a cluster.
    • kubectl create deployment nginx --image nginx
    • Imperative object configuration
    • kubectl create -f nginx.yaml
    • kubectl delete -f nginx.yaml -f redis.yaml
    • kubectl replace -f nginx.yaml
    • Declarative object configuration
    • kubectl diff -f configs/
    • kubectl apply -f configs/

    Object Names and IDs

    Each object in your cluster has a Name that is unique for that type of resource.

    • DNS Subdomain Names
    • Label Names
    • Path Segment Names

    Every Kubernetes object also has a UID that is unique across the whole cluster.

    Namespaces

    In Kubernetes, namespaces provides a mechanism for isolating groups of resources within a single cluster.

    Names of resources need to be unique within a namespace, but not across namespaces.

    Namespace-based scoping is applicable only for namespaced objects (e.g. Deployments, Services, etc) and not for cluster-wide objects (e.g. StorageClass, Nodes, PersistentVolumes, etc)

    Not All Objects are in a Namespace.

    Kubernetes starts with four initial namespaces:

    • default The default namespace for objects with no other namespace
    • kube-system The namespace for objects created by the Kubernetes system
    • kube-public This namespace is created automatically and is readable by all users (including those not authenticated). This namespace is mostly reserved for cluster usage, in case that some resources should be visible and readable publicly throughout the whole cluster. The public aspect of this namespace is only a convention, not a requirement.
    • kube-node-lease This namespace holds Lease objects associated with each node. Node leases allow the kubelet to send heartbeats so that the control plane can detect node failure.

    Viewing namespaces:

    • kubectl get namespace

    Setting the namespace for a request

    • kubectl run nginx --image=nginx --namespace=<insert-namespace-name-here>
    • kubectl get pods --namespace=<insert-namespace-name-here>

    Labels and Selectors

    Labels are key/value pairs that are attached to objects, such as pods. Valid label keys have two segments: an optional prefix and name, separated by a slash (/).

    Labels are intended to be used to specify identifying attributes of objects that are meaningful and relevant to users.

    Labels can be used to organize and to select subsets of objects. Labels can be attached to objects at creation time and subsequently added and modified at any time. Each object can have a set of key/value labels defined. Each Key must be unique for a given object.

    Example of labels:

    "metadata": {
    -    "labels": {
    -        "key1" : "value1",
    -        "key2" : "value2"
    -    }
    -}
    + Memo - UPSkilling       

    Kubernetes Learning Memo

    Basic Concepts of Kubernetes

    Kubernetes Components

    A Kubernetes cluster consists of the components that represent the control plane and a set of machines called nodes.

    The components of a Kubernetes cluster

    Kubernetes Components:

    • Control Plane Components
    • kube-apiserver:
      • query and manipulate the state of objects in Kubernetes.
      • play as "communication hub" among all resources in cluster.
      • provide cluster security authentication, authorization, and role assignment.
      • the only one can connect to etcd.
    • etcd:
      • all Kubernetes objects are stored on etcd.
      • Kubernetes objects are persistent entities in the Kubernetes system, which are used to represent the state of your cluster.
    • kube-scheduler:
      • watches for newly created Pods with no assigned node, and selects a node for them to run on.
    • kube-controller-manager: runs controller processes.
      • Node controller: Responsible for noticing and responding when nodes go down.
      • Job controller: Watches for Job objects that represent one-off tasks, then creates Pods to run those tasks to completion.
      • Endpoints controller: Populates the Endpoints object (that is, joins Services & Pods).
      • Service Account & Token controllers: Create default accounts and API access tokens for new namespaces.
    • cloud-controller-manager: embeds cloud-specific control logic and only runs controllers that are specific to your cloud provider, no need for own premises and learning environment.
      • Node controller: For checking the cloud provider to determine if a node has been deleted in the cloud after it stops responding
      • Route controller: For setting up routes in the underlying cloud infrastructure
      • Service controller: For creating, updating and deleting cloud provider load balancers
    • Node Components
    • kubelet:
      • An agent that runs on each node in the cluster.
      • Manage node. It makes sure that containers are running in a Pod. kubelet registers and updates nodes information to APIServer, and APIServer stores them into etcd.
      • Manage pod. Watch pod via APIServer, and action on pods or containers in pods.
      • Health check at container level.
    • kube-proxy:
      • is a network proxy that runs on each node in cluster.
      • iptables
      • ipvs
      • maintains network rules on nodes.
    • Container runtime:
      • is the software that is responsible for running containers.
    • Addons
    • DNS: is a DNS server and required by all Kubernetes clusters.
    • Web UI (Dashboard): web-based UI for Kubernetes clusters.
    • Container Resource Monitoring: records generic time-series metrics about containers in a central database
    • Cluster-level Logging: is responsible for saving container logs to a central log store with search/browsing interface.

    Scalability:

    • Scaling out (horizontal scaling) by adding more servers to your architecture to spread the workload across more machines.
    • Scaling up (vertical scaling) by adding more hard drives and memory to increase the computing capacity of physical servers.

    Kubernetes API

    The REST API is the fundamental fabric of Kubernetes. All operations and communications between components, and external user commands are REST API calls that the API Server handles. Consequently, everything in the Kubernetes platform is treated as an API object and has a corresponding entry in the API.

    The core of Kubernetes' control plane is the API server.

    • CRI: Container Runtime Interface
    • CNI: Container Network Interface
    • CSI: Container Storage Interface

    The API server exposes an HTTP API that lets end users, different parts of cluster, and external components communicate with one another.

    The Kubernetes API lets we query and manipulate the state of API objects in Kubernetes (for example: Pods, Namespaces, ConfigMaps, and Events).

    Kubernetes API:

    • OpenAPI specification
    • OpenAPI V2
    • OpenAPI V3
    • Persistence. Kubernetes stores the serialized state of objects by writing them into etcd.
    • API groups and versioning. Versioning is done at the API level. API resources are distinguished by their API group, resource type, namespace (for namespaced resources), and name.
    • API changes
    • API Extension

    API Version

    The API versioning and software versioning are indirectly related. The API and release versioning proposal describes the relationship between API versioning and software versioning. Different API versions indicate different levels of stability and support.

    Here's a summary of each level:

    • Alpha:
    • The version names contain alpha (for example, v1alpha1).
    • The software may contain bugs. Enabling a feature may expose bugs. A feature may be disabled by default.
    • The support for a feature may be dropped at any time without notice.
    • The API may change in incompatible ways in a later software release without notice.
    • The software is recommended for use only in short-lived testing clusters, due to increased risk of bugs and lack of long-term support.
    • Beta:
    • The version names contain beta (for example, v2beta3).
    • The software is well tested. Enabling a feature is considered safe. Features are enabled by default.
    • The support for a feature will not be dropped, though the details may change.
    • The schema and/or semantics of objects may change in incompatible ways in a subsequent beta or stable release. When this happens, migration instructions are provided. Schema changes may require deleting, editing, and re-creating API objects. The editing process may not be straightforward. The migration may require downtime for applications that rely on the feature.
    • The software is not recommended for production uses. Subsequent releases may introduce incompatible changes. If you have multiple clusters which can be upgraded independently, you may be able to relax this restriction. Note: Please try beta features and provide feedback. After the features exit beta, it may not be practical to make more changes.
    • Stable:
    • The version name is vX where X is an integer.
    • The stable versions of features appear in released software for many subsequent versions.

    Command to get current API

    kubectl api-resources
    +

    API Group

    API groups make it easier to extend the Kubernetes API. The API group is specified in a REST path and in the apiVersion field of a serialized object.

    There are several API groups in Kubernetes:

    • The core (also called legacy) group is found at REST path /api/v1.
    • The core group is not specified as part of the apiVersion field, for example, apiVersion: v1.
    • The named groups are at REST path /apis/$GROUP_NAME/$VERSION and use apiVersion: $GROUP_NAME/$VERSION (for example, apiVersion: batch/v1).

    Kubernetes Objects

    Objects Overview

    • Object Spec:
    • providing a description of the characteristics the resource created to have: its desired state.
    • Object Status:
    • describes the current state of the object.

    Example of Deployment as an object that can represent an application running on cluster.

    apiVersion: apps/v1  # Which version of the Kubernetes API you're using to create this object
    +kind: Deployment     # What kind of object you want to create
    +metadata:            # Data that helps uniquely identify the object, including a name string, UID, and optional namespace
    +  name: nginx-deployment
    +spec:                # What state you desire for the object
    +  selector:
    +    matchLabels:
    +      app: nginx
    +  replicas: 2 # tells deployment to run 2 pods matching the template
    +  template:
    +    metadata:
    +      labels:
    +        app: nginx
    +    spec:
    +      containers:
    +      - name: nginx
    +        image: nginx:1.14.2
    +        ports:
    +        - containerPort: 80
    +

    Object Management

    The kubectl command-line tool supports several different ways to create and manage Kubernetes objects. Read the Kubectl book for details.

    A Kubernetes object should be managed using ONLY one technique. Mixing and matching techniques for the same object results in undefined behavior.

    Three management techniques:

    • Imperative commands
    • operates directly on live objects in a cluster.
    • kubectl create deployment nginx --image nginx
    • Imperative object configuration
    • kubectl create -f nginx.yaml
    • kubectl delete -f nginx.yaml -f redis.yaml
    • kubectl replace -f nginx.yaml
    • Declarative object configuration
    • kubectl diff -f configs/
    • kubectl apply -f configs/

    Object Names and IDs

    Each object in your cluster has a Name that is unique for that type of resource.

    • DNS Subdomain Names
    • Label Names
    • Path Segment Names

    Every Kubernetes object also has a UID that is unique across the whole cluster.

    Namespaces

    In Kubernetes, namespaces provides a mechanism for isolating groups of resources within a single cluster.

    Names of resources need to be unique within a namespace, but not across namespaces.

    Namespace-based scoping is applicable only for namespaced objects (e.g. Deployments, Services, etc) and not for cluster-wide objects (e.g. StorageClass, Nodes, PersistentVolumes, etc)

    Not All Objects are in a Namespace.

    Kubernetes starts with four initial namespaces:

    • default The default namespace for objects with no other namespace
    • kube-system The namespace for objects created by the Kubernetes system
    • kube-public This namespace is created automatically and is readable by all users (including those not authenticated). This namespace is mostly reserved for cluster usage, in case that some resources should be visible and readable publicly throughout the whole cluster. The public aspect of this namespace is only a convention, not a requirement.
    • kube-node-lease This namespace holds Lease objects associated with each node. Node leases allow the kubelet to send heartbeats so that the control plane can detect node failure.

    Viewing namespaces:

    • kubectl get namespace

    Setting the namespace for a request

    • kubectl run nginx --image=nginx --namespace=<insert-namespace-name-here>
    • kubectl get pods --namespace=<insert-namespace-name-here>

    Labels and Selectors

    Labels are key/value pairs that are attached to objects, such as pods. Valid label keys have two segments: an optional prefix and name, separated by a slash (/).

    Labels are intended to be used to specify identifying attributes of objects that are meaningful and relevant to users.

    Labels can be used to organize and to select subsets of objects. Labels can be attached to objects at creation time and subsequently added and modified at any time. Each object can have a set of key/value labels defined. Each Key must be unique for a given object.

    Example of labels:

    "metadata": {
    +    "labels": {
    +        "key1" : "value1",
    +        "key2" : "value2"
    +    }
    +}
     

    Unlike names and UIDs, labels do not provide uniqueness. In general, we expect many objects to carry the same label(s).

    The API currently supports two types of selectors:

    • equality-based, e.g., environment = production, tier != frontend
    • set-based, e.g., environment in (production, qa), tier notin (frontend, backend)

    Sample commands:

    kubectl get pods -l environment=production,tier=frontend
     kubectl get pods -l 'environment in (production),tier in (frontend)'
     kubectl get pods -l 'environment in (production, qa)'
     kubectl get pods -l 'environment,environment notin (frontend)'
    -

    Annotations

    Use Kubernetes annotations to attach arbitrary non-identifying metadata to objects. Clients such as tools and libraries can retrieve this metadata.

    Use either labels or annotations to attach metadata to Kubernetes objects.

    • Labels can be used to select objects and to find collections of objects that satisfy certain conditions.
    • Annotations are not used to identify and select objects.

    Annotations, like labels, are key/value maps. The keys and the values in the map must be strings.

    "metadata": {
    -    "annotations": {
    -      "key1" : "value1",
    -      "key2" : "value2"
    -    }
    -}
    +

    Annotations

    Use Kubernetes annotations to attach arbitrary non-identifying metadata to objects. Clients such as tools and libraries can retrieve this metadata.

    Use either labels or annotations to attach metadata to Kubernetes objects.

    • Labels can be used to select objects and to find collections of objects that satisfy certain conditions.
    • Annotations are not used to identify and select objects.

    Annotations, like labels, are key/value maps. The keys and the values in the map must be strings.

    "metadata": {
    +    "annotations": {
    +      "key1" : "value1",
    +      "key2" : "value2"
    +    }
    +}
     

    Valid annotation keys have two segments: an optional prefix and name, separated by a slash (/).

    Field Selectors

    Field selectors let you select Kubernetes resources based on the value of one or more resource fields.

    Here are some examples of field selector queries:

    metadata.name=my-service
     metadata.namespace!=default
     status.phase=Pending
     

    This kubectl command selects all Pods for which the value of the status.phase field is Running: kubectl get pods --field-selector status.phase=Running

    Supported field selectors vary by Kubernetes resource type. All resource types support the metadata.name and metadata.namespace fields.

    Use the =, ==, and != operators with field selectors (= and == mean the same thing).

    For example:

    kubectl get ingress --field-selector foo.bar=baz

    With operators, kubectl get services --all-namespaces --field-selector metadata.namespace!=default

    Chained selectors, kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always

    Multiple resource types, kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default

    Finalizers

    Finalizers are namespaced keys that tell Kubernetes to wait until specific conditions are met before it fully deletes resources marked for deletion. Finalizers alert controllers to clean up resources the deleted object owned.

    Finalizers are usually added to resources for a reason, so forcefully removing them can lead to issues in the cluster.

    Like labels, owner references describe the relationships between objects in Kubernetes, but are used for a different purpose.

    Kubernetes uses the owner references (not labels) to determine which Pods in the cluster need cleanup.

    Kubernetes processes finalizers when it identifies owner references on a resource targeted for deletion.

    Owners and Dependents

    In Kubernetes, some objects are owners of other objects. For example, a ReplicaSet is the owner of a set of Pods. These owned objects are dependents of their owner.

    Dependent objects have a metadata.ownerReferences field that references their owner object.

    A valid owner reference consists of the object name and a UID within the same namespace as the dependent object.

    Dependent objects also have an ownerReferences.blockOwnerDeletion field that takes a boolean value and controls whether specific dependents can block garbage collection from deleting their owner object.

    Resource

    Kubernetes resources and "records of intent" are all stored as API objects, and modified via RESTful calls to the API. The API allows configuration to be managed in a declarative way. Users can interact with the Kubernetes API directly, or via tools like kubectl. The core Kubernetes API is flexible and can also be extended to support custom resources.

    • Workload Resources
    • Pod. Pod is a collection of containers that can run on a host.
    • PodTemplate. PodTemplate describes a template for creating copies of a predefined pod.
    • ReplicationController. ReplicationController represents the configuration of a replication controller.
    • ReplicaSet. ReplicaSet ensures that a specified number of pod replicas are running at any given time.
    • Deployment. Deployment enables declarative updates for Pods and ReplicaSets.
    • StatefulSet. StatefulSet represents a set of pods with consistent identities.
    • ControllerRevision. ControllerRevision implements an immutable snapshot of state data.
    • DaemonSet. DaemonSet represents the configuration of a daemon set.
    • Job. Job represents the configuration of a single job.
    • CronJob. CronJob represents the configuration of a single cron job.
    • HorizontalPodAutoscaler. configuration of a horizontal pod autoscaler.
    • HorizontalPodAutoscaler. HorizontalPodAutoscaler is the configuration for a horizontal pod autoscaler, which automatically manages the replica count of any resource implementing the scale subresource based on the metrics specified.
    • HorizontalPodAutoscaler v2beta2. HorizontalPodAutoscaler is the configuration for a horizontal pod autoscaler, which automatically manages the replica count of any resource implementing the scale subresource based on the metrics specified.
    • PriorityClass. PriorityClass defines mapping from a priority class name to the priority integer value.
    • Service Resources
    • Service. Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy.
    • Endpoints. Endpoints is a collection of endpoints that implement the actual service.
    • EndpointSlice. EndpointSlice represents a subset of the endpoints that implement a service.
    • Ingress. Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend.
    • IngressClass. IngressClass represents the class of the Ingress, referenced by the Ingress Spec.
    • Config and Storage Resources
    • ConfigMap. ConfigMap holds configuration data for pods to consume.
    • Secret. Secret holds secret data of a certain type.
    • Volume. Volume represents a named volume in a pod that may be accessed by any container in the pod.
    • PersistentVolumeClaim. PersistentVolumeClaim is a user's request for and claim to a persistent volume.
    • PersistentVolume. PersistentVolume (PV) is a storage resource provisioned by an administrator.
    • StorageClass. StorageClass describes the parameters for a class of storage for which PersistentVolumes can be dynamically provisioned.
    • VolumeAttachment. VolumeAttachment captures the intent to attach or detach the specified volume to/from the specified node.
    • CSIDriver. CSIDriver captures information about a Container Storage Interface (CSI) volume driver deployed on the cluster.
    • CSINode. CSINode holds information about all CSI drivers installed on a node.
    • CSIStorageCapacity. CSIStorageCapacity stores the result of one CSI GetCapacity call.
    • Authentication Resources
    • ServiceAccount. ServiceAccount binds together:
      • a name, understood by users, and perhaps by peripheral systems, for an identity
      • a principal that can be authenticated and authorized
      • a set of secrets.
    • TokenRequest. TokenRequest requests a token for a given service account.
    • TokenReview. TokenReview attempts to authenticate a token to a known user.
    • CertificateSigningRequest. CertificateSigningRequest objects provide a mechanism to obtain x509 certificates by submitting a certificate signing request, and having it asynchronously approved and issued.
    • Authorization Resources
    • LocalSubjectAccessReview. LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace.
    • SelfSubjectAccessReview. SelfSubjectAccessReview checks whether or the current user can perform an action.
    • SelfSubjectRulesReview. SelfSubjectRulesReview enumerates the set of actions the current user can perform within a namespace.
    • SubjectAccessReview. SubjectAccessReview checks whether or not a user or group can perform an action.
    • ClusterRole. ClusterRole is a cluster level, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding or ClusterRoleBinding.
    • ClusterRoleBinding. ClusterRoleBinding references a ClusterRole, but not contain it.
    • Role. Role is a namespaced, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding.
    • RoleBinding. RoleBinding references a role, but does not contain it.
    • Policy Resources
    • LimitRange. LimitRange sets resource usage limits for each kind of resource in a Namespace.
    • ResourceQuota. ResourceQuota sets aggregate quota restrictions enforced per namespace.
    • NetworkPolicy. NetworkPolicy describes what network traffic is allowed for a set of Pods.
    • PodDisruptionBudget. PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods.
    • PodSecurityPolicy v1beta1. PodSecurityPolicy governs the ability to make requests that affect the Security Context that will be applied to a pod and container.
    • Extend Resources
    • CustomResourceDefinition. CustomResourceDefinition represents a resource that should be exposed on the API server.
    • MutatingWebhookConfiguration. MutatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and may change the object.
    • *ValidatingWebhookConfiguration(). ValidatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and object without changing it.
    • Cluster Resources
    • Node. Node is a worker node in Kubernetes.
    • Namespace. Namespace provides a scope for Names.
    • Event. Event is a report of an event somewhere in the cluster.
    • APIService. APIService represents a server for a particular GroupVersion.
    • Lease. Lease defines a lease concept.
    • RuntimeClass. RuntimeClass defines a class of container runtime supported in the cluster.
    • FlowSchema v1beta2. FlowSchema defines the schema of a group of flows.
    • PriorityLevelConfiguration v1beta2. PriorityLevelConfiguration represents the configuration of a priority level.
    • Binding. Binding ties one object to another; for example, a pod is bound to a node by a scheduler.
    • ComponentStatus. ComponentStatus (and ComponentStatusList) holds the cluster validation info.

    Command kube api-resources to get the supported API resources.

    Command kubectl explain RESOURCE [options] describes the fields associated with each supported API resource. Fields are identified via a simple JSONPath identifier:

    kubectl explain binding
     kubectl explain binding.metadata
     kubectl explain binding.metadata.name
    -

    Workload Resources

    Pods

    Pods are the smallest deployable units of computing that you can create and manage in Kubernetes.

    A Pod is a group of one or more containers, with shared storage and network resources, and a specification for how to run the containers.

    A Pod's contents are always co-located and co-scheduled, and run in a shared context.

    A Pod models an application-specific "logical host": it contains one or more application containers which are relatively tightly coupled.

    In non-cloud contexts, applications executed on the same physical or virtual machine are analogous to cloud applications executed on the same logical host.

    The shared context of a Pod is a set of Linux namespaces, cgroups, and potentially other facets of isolation - the same things that isolate a Docker container.

    In terms of Docker concepts, a Pod is similar to a group of Docker containers with shared namespaces and shared filesystem volumes.

    Usually you don't need to create Pods directly, even singleton Pods. Instead, create them using workload resources such as Deployment or Job. If your Pods need to track state, consider the StatefulSet resource.

    Pods in a Kubernetes cluster are used in two main ways:

    • Pods that run a single container.
    • Pods that run multiple containers that need to work together.

    The "one-container-per-Pod" model is the most common Kubernetes use case; in this case, you can think of a Pod as a wrapper around a single container; Kubernetes manages Pods rather than managing the containers directly.

    A Pod can encapsulate an application composed of multiple co-located containers that are tightly coupled and need to share resources.

    These co-located containers form a single cohesive unit of service—for example, one container serving data stored in a shared volume to the public, while a separate sidecar container refreshes or updates those files. The Pod wraps these containers, storage resources, and an ephemeral network identity together as a single unit.

    Grouping multiple co-located and co-managed containers in a single Pod is a relatively advanced use case. You should use this pattern only in specific instances in which your containers are tightly coupled.

    Each Pod is meant to run a single instance of a given application. If you want to scale your application horizontally (to provide more overall resources by running more instances), you should use multiple Pods, one for each instance. In Kubernetes, this is typically referred to as replication. Replicated Pods are usually created and managed as a group by a workload resource and its controller.

    Pods natively provide two kinds of shared resources for their constituent containers: networking and storage.

    A Pod can specify a set of shared storage volumes. All containers in the Pod can access the shared volumes, allowing those containers to share data.

    Each Pod is assigned a unique IP address for each address family. Within a Pod, containers share an IP address and port space, and can find each other via localhost. Containers that want to interact with a container running in a different Pod can use IP networking to communicate.

    When a Pod gets created, the new Pod is scheduled to run on a Node in your cluster. The Pod remains on that node until the Pod finishes execution, the Pod object is deleted, the Pod is evicted for lack of resources, or the node fails.

    Restarting a container in a Pod should not be confused with restarting a Pod. A Pod is not a process, but an environment for running container(s). A Pod persists until it is deleted.

    You can use workload resources (e.g., Deployment, StatefulSet, DaemonSet) to create and manage multiple Pods for you. A controller for the resource handles replication and rollout and automatic healing in case of Pod failure.

    Pod with multiple containers

    InitContainer

    Some Pods have init containers as well as app containers. Init containers run and complete before the app containers are started.

    You can specify init containers in the Pod specification alongside the containers array (which describes app containers).

    Static Pod

    Static Pods are managed directly by the kubelet daemon on a specific node, without the API server observing them.

    Static Pods are always bound to one Kubelet on a specific node.

    The main use for static Pods is to run a self-hosted control plane: in other words, using the kubelet to supervise the individual control plane components.

    The kubelet automatically tries to create a mirror Pod on the Kubernetes API server for each static Pod. This means that the Pods running on a node are visible on the API server, but cannot be controlled from there.

    Container probes

    A probe is a diagnostic performed periodically by the kubelet on a container.

    To perform a diagnostic, the kubelet either executes code within the container, or makes a network request.

    There are four different ways to check a container using a probe. Each probe must define exactly one of these four mechanisms:

    • exec. The diagnostic is considered successful if the command exits with a status code of 0.
    • grpc. The diagnostic is considered successful if the status of the response is SERVING.
    • httpGet. The diagnostic is considered successful if the response has a status code greater than or equal to 200 and less than 400.
    • tcpSocket. The diagnostic is considered successful if the port is open.

    Each probe has one of three results:

    • Success
    • Failure
    • Unknown

    Types of probe:

    • livenessProbe. Indicates whether the container is running.
    • readinessProbe. Indicates whether the container is ready to respond to requests.
    • startupProbe. Indicates whether the application within the container is started.

    Deployment

    ReplicaSet

    A ReplicaSet’s purpose is to maintain a stable set of replica Pods running at any given time. As such, it is often used to guarantee the availability of a specified number of identical Pods.

    You may never need to manipulate ReplicaSet objects: use a Deployment instead, and define your application in the spec section.

    You can specify how many Pods should run concurrently by setting replicaset.spec.replicas. The ReplicaSet will create/delete its Pods to match this number. If you do not specify replicaset.spec.replicas, then it defaults to 1.

    StatefulSet

    StatefulSet Characteristics (aka, stick ID):

    • Pod's name is immutable after created.
    • DNS hostname is immutable after created.
    • Mounted volume is immutable after created.

    Stick ID of StatefulSet won't be changed after failure, scaling, and other operations.

    Naming convention of StatefulSet: <StatefulSetName>-<Integer>.

    StatefulSet can be scalling by itsself, but Deployment need rely on ReplicaSet for scalling.

    Recommendation: reduce StatefulSet to 0 first instead of delete it directly.

    headless Service and governing Service:

    • Headless Service is a normal Kubernetes Service object that its spec.clusterIP is set to None.
    • When spec.ServiceName of StatefulSet is set to the headless Service name, the StatefulSet is now a governing Service.

    General procedure to create a StatefulSet:

    • Create a StorageClass
    • Create Headless Service
    • Create StatefulSet based on above two.

    DaemonSet

    A DaemonSet ensures that all (or some) Nodes run a copy of a Pod. As nodes are removed from the cluster, those Pods are garbage collected.

    Deleting a DaemonSet will clean up the Pods it created.

    Some typical uses of a DaemonSet are:

    • running a cluster storage daemon on every node
    • running a logs collection daemon on every node
    • running a node monitoring daemon on every node

    In a simple case, one DaemonSet, covering all nodes, would be used for each type of daemon.

    A more complex setup might use multiple DaemonSets for a single type of daemon, but with different flags and/or different memory and cpu requests for different hardware types.

    The DaemonSet controller reconciliation process reviews both existing nodes and newly created nodes.

    By default, the Kubernetes scheduler ignores the pods created by the DamonSet, and lets them exist on the node until the node itself is shut down.

    Running Pods on select Nodes:

    • If you specify a daemonset.spec.template.spec.nodeSelector, then the DaemonSet controller will create Pods on nodes which match that node selector.
    • If you specify a daemonset.spec.template.spec.affinity, then DaemonSet controller will create Pods on nodes which match that node affinity.
    • If you do not specify either, then the DaemonSet controller will create Pods on all nodes.

    There is no field replicas in kubectl explain daemonset.spec against with kubectl explain deployment.spec.replicas. When a DaemonSet is created, each node will have one DaemonSet Pod running.

    We’ll use a Deployment/ReplicaSet for services, mostly stateless, where we don’t care where the node is running, but we care more about the number of copies of our pod is running, and we can scale those copies/replicas up or down. Rolling updates would also be a benefit here.

    We’ll use a DaemonSet when a copy of our pod must be running on the specific nodes that we require. Our daemon pod also needs to start before any of our other pods.

    A DaemonSet is a simple scalability strategy for background services. When more eligible nodes are added to the cluster, the background service scales up. When nodes are removed, it will automatically scale down.

    Job

    CronJob

    Service Resource

    Service

    Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy.

    The set of Pods targeted by a Service is usually determined by a selector (label selector).

    Type of service resource:

    • ClusterIP Service (default): Reliable IP, DNS, and Port. Internal acess only.
    • NodePort Service: Expose to external access.
    • LoadBalancer: Based on NodePort and integrated with loader balance provided by cloud venders (e.g., AWS, GCP, etc.).
    • ExternalName: Acces will be trafficed to external service.

    Here is an example of yaml file to create a Service.

    apiVersion: v1
    -kind: Service
    -metadata:
    -  name: nginx-service
    -  labels:
    -    tier: application
    -spec:
    -  ports:
    -  - port: 80
    -    protocol: TCP
    -    targetPort: 8080
    -  selector:
    -    run: nginx
    -  type: NodePort
    +

    Workload Resources

    Pods

    Pods are the smallest deployable units of computing that you can create and manage in Kubernetes.

    A Pod is a group of one or more containers, with shared storage and network resources, and a specification for how to run the containers.

    A Pod's contents are always co-located and co-scheduled, and run in a shared context.

    A Pod models an application-specific "logical host": it contains one or more application containers which are relatively tightly coupled.

    In non-cloud contexts, applications executed on the same physical or virtual machine are analogous to cloud applications executed on the same logical host.

    The shared context of a Pod is a set of Linux namespaces, cgroups, and potentially other facets of isolation - the same things that isolate a Docker container.

    In terms of Docker concepts, a Pod is similar to a group of Docker containers with shared namespaces and shared filesystem volumes.

    Usually you don't need to create Pods directly, even singleton Pods. Instead, create them using workload resources such as Deployment or Job. If your Pods need to track state, consider the StatefulSet resource.

    Pods in a Kubernetes cluster are used in two main ways:

    • Pods that run a single container.
    • Pods that run multiple containers that need to work together.

    The "one-container-per-Pod" model is the most common Kubernetes use case; in this case, you can think of a Pod as a wrapper around a single container; Kubernetes manages Pods rather than managing the containers directly.

    A Pod can encapsulate an application composed of multiple co-located containers that are tightly coupled and need to share resources.

    These co-located containers form a single cohesive unit of service—for example, one container serving data stored in a shared volume to the public, while a separate sidecar container refreshes or updates those files. The Pod wraps these containers, storage resources, and an ephemeral network identity together as a single unit.

    Grouping multiple co-located and co-managed containers in a single Pod is a relatively advanced use case. You should use this pattern only in specific instances in which your containers are tightly coupled.

    Each Pod is meant to run a single instance of a given application. If you want to scale your application horizontally (to provide more overall resources by running more instances), you should use multiple Pods, one for each instance. In Kubernetes, this is typically referred to as replication. Replicated Pods are usually created and managed as a group by a workload resource and its controller.

    Pods natively provide two kinds of shared resources for their constituent containers: networking and storage.

    A Pod can specify a set of shared storage volumes. All containers in the Pod can access the shared volumes, allowing those containers to share data.

    Each Pod is assigned a unique IP address for each address family. Within a Pod, containers share an IP address and port space, and can find each other via localhost. Containers that want to interact with a container running in a different Pod can use IP networking to communicate.

    When a Pod gets created, the new Pod is scheduled to run on a Node in your cluster. The Pod remains on that node until the Pod finishes execution, the Pod object is deleted, the Pod is evicted for lack of resources, or the node fails.

    Restarting a container in a Pod should not be confused with restarting a Pod. A Pod is not a process, but an environment for running container(s). A Pod persists until it is deleted.

    You can use workload resources (e.g., Deployment, StatefulSet, DaemonSet) to create and manage multiple Pods for you. A controller for the resource handles replication and rollout and automatic healing in case of Pod failure.

    Pod with multiple containers

    InitContainer

    Some Pods have init containers as well as app containers. Init containers run and complete before the app containers are started.

    You can specify init containers in the Pod specification alongside the containers array (which describes app containers).

    Static Pod

    Static Pods are managed directly by the kubelet daemon on a specific node, without the API server observing them.

    Static Pods are always bound to one Kubelet on a specific node.

    The main use for static Pods is to run a self-hosted control plane: in other words, using the kubelet to supervise the individual control plane components.

    The kubelet automatically tries to create a mirror Pod on the Kubernetes API server for each static Pod. This means that the Pods running on a node are visible on the API server, but cannot be controlled from there.

    Container probes

    A probe is a diagnostic performed periodically by the kubelet on a container.

    To perform a diagnostic, the kubelet either executes code within the container, or makes a network request.

    There are four different ways to check a container using a probe. Each probe must define exactly one of these four mechanisms:

    • exec. The diagnostic is considered successful if the command exits with a status code of 0.
    • grpc. The diagnostic is considered successful if the status of the response is SERVING.
    • httpGet. The diagnostic is considered successful if the response has a status code greater than or equal to 200 and less than 400.
    • tcpSocket. The diagnostic is considered successful if the port is open.

    Each probe has one of three results:

    • Success
    • Failure
    • Unknown

    Types of probe:

    • livenessProbe. Indicates whether the container is running.
    • readinessProbe. Indicates whether the container is ready to respond to requests.
    • startupProbe. Indicates whether the application within the container is started.

    Deployment

    ReplicaSet

    A ReplicaSet’s purpose is to maintain a stable set of replica Pods running at any given time. As such, it is often used to guarantee the availability of a specified number of identical Pods.

    You may never need to manipulate ReplicaSet objects: use a Deployment instead, and define your application in the spec section.

    You can specify how many Pods should run concurrently by setting replicaset.spec.replicas. The ReplicaSet will create/delete its Pods to match this number. If you do not specify replicaset.spec.replicas, then it defaults to 1.

    StatefulSet

    StatefulSet Characteristics (aka, stick ID):

    • Pod's name is immutable after created.
    • DNS hostname is immutable after created.
    • Mounted volume is immutable after created.

    Stick ID of StatefulSet won't be changed after failure, scaling, and other operations.

    Naming convention of StatefulSet: <StatefulSetName>-<Integer>.

    StatefulSet can be scalling by itsself, but Deployment need rely on ReplicaSet for scalling.

    Recommendation: reduce StatefulSet to 0 first instead of delete it directly.

    headless Service and governing Service:

    • Headless Service is a normal Kubernetes Service object that its spec.clusterIP is set to None.
    • When spec.ServiceName of StatefulSet is set to the headless Service name, the StatefulSet is now a governing Service.

    General procedure to create a StatefulSet:

    • Create a StorageClass
    • Create Headless Service
    • Create StatefulSet based on above two.

    DaemonSet

    A DaemonSet ensures that all (or some) Nodes run a copy of a Pod. As nodes are removed from the cluster, those Pods are garbage collected.

    Deleting a DaemonSet will clean up the Pods it created.

    Some typical uses of a DaemonSet are:

    • running a cluster storage daemon on every node
    • running a logs collection daemon on every node
    • running a node monitoring daemon on every node

    In a simple case, one DaemonSet, covering all nodes, would be used for each type of daemon.

    A more complex setup might use multiple DaemonSets for a single type of daemon, but with different flags and/or different memory and cpu requests for different hardware types.

    The DaemonSet controller reconciliation process reviews both existing nodes and newly created nodes.

    By default, the Kubernetes scheduler ignores the pods created by the DamonSet, and lets them exist on the node until the node itself is shut down.

    Running Pods on select Nodes:

    • If you specify a daemonset.spec.template.spec.nodeSelector, then the DaemonSet controller will create Pods on nodes which match that node selector.
    • If you specify a daemonset.spec.template.spec.affinity, then DaemonSet controller will create Pods on nodes which match that node affinity.
    • If you do not specify either, then the DaemonSet controller will create Pods on all nodes.

    There is no field replicas in kubectl explain daemonset.spec against with kubectl explain deployment.spec.replicas. When a DaemonSet is created, each node will have one DaemonSet Pod running.

    We’ll use a Deployment/ReplicaSet for services, mostly stateless, where we don’t care where the node is running, but we care more about the number of copies of our pod is running, and we can scale those copies/replicas up or down. Rolling updates would also be a benefit here.

    We’ll use a DaemonSet when a copy of our pod must be running on the specific nodes that we require. Our daemon pod also needs to start before any of our other pods.

    A DaemonSet is a simple scalability strategy for background services. When more eligible nodes are added to the cluster, the background service scales up. When nodes are removed, it will automatically scale down.

    Job

    CronJob

    Service Resource

    Service

    Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy.

    The set of Pods targeted by a Service is usually determined by a selector (label selector).

    Type of service resource:

    • ClusterIP Service (default): Reliable IP, DNS, and Port. Internal acess only.
    • NodePort Service: Expose to external access.
    • LoadBalancer: Based on NodePort and integrated with loader balance provided by cloud venders (e.g., AWS, GCP, etc.).
    • ExternalName: Acces will be trafficed to external service.

    Here is an example of yaml file to create a Service.

    apiVersion: v1
    +kind: Service
    +metadata:
    +  name: nginx-service
    +  labels:
    +    tier: application
    +spec:
    +  ports:
    +  - port: 80
    +    protocol: TCP
    +    targetPort: 8080
    +  selector:
    +    run: nginx
    +  type: NodePort
     

    Here is an example of Service.

    • IP10.96.17.77 is ClusterIP(VIP) of the service
    • Port <unset> 80/TCP is the port on Pod that service listening within the cluster.
    • TargetPort 8080/TCP is the port on the container that the service should direct traffic to.
    • NodePort <unset> 31893/TCP is the port that can be accessed outside. Default range is 30000~32767. The port is exposed across all nodes in cluster.
    • Endpoints show the list of Pods matched the service labels.
    Name:                     nginx-deployment
     Namespace:                jh-namespace
     Labels:                   tier=application
    @@ -71,17 +71,17 @@
     Session Affinity:         None
     External Traffic Policy:  Cluster
     Events:                   <none>
    -

    Service kube-dns beyond Deployment coredns provides cluster DNS service in Kubernetes cluster.

    Service registration:

    • Kubernetes uses cluster DNS as service registration.
    • Registration is Service based, not Pod based.
    • Cluster DNS (CoreDNS) is monitoring and discvering new service actively.
    • Service Name, IP, Port will be registered.

    Procedure of Service registration.

    • POST new Service to API Server.
    • Assign ClusterIP to the new Service.
    • Save new Service configuration info to etcd.
    • Create endpoints with related Pod IPs associated with the new Service.
    • Explore the new Service by ClusterDNS.
    • Create DNS info.
    • kube-proxy fetch Service configration info.
    • Create IPSV rule.

    Procedure of Service discovery.

    • Request DNS name resolution for a Service name.
    • Receive ClusterIP.
    • Traffic access to ClusterIP.
    • No router. Forward request to Pod's default gateway.
    • Forward request to node.
    • No router. Forward request to Node's default gateway.
    • Proceed the request by Node kernel.
    • Trap the request by IPSV rule.
    • Put destination Pod's IP into the request's destination IP.
    • The request arrives destination Pod.

    FQDN format: <object-name>.<namespace>.svc.cluster.local. We call <object-name> as unqualified name, or short name. Namespaces can segregate the cluster's address space. At the same time, it can also be used to implement access control and resource quotas.

    Get DNS configuration in a Pod. The IP of nameserver is same with ClusterIP of kube-dns Service, which is well-known IP for request of DNS or service discovery.

    root@cka001:/etc# kubectl get service kube-dns -n kube-system
    +

    Service kube-dns beyond Deployment coredns provides cluster DNS service in Kubernetes cluster.

    Service registration:

    • Kubernetes uses cluster DNS as service registration.
    • Registration is Service based, not Pod based.
    • Cluster DNS (CoreDNS) is monitoring and discvering new service actively.
    • Service Name, IP, Port will be registered.

    Procedure of Service registration.

    • POST new Service to API Server.
    • Assign ClusterIP to the new Service.
    • Save new Service configuration info to etcd.
    • Create endpoints with related Pod IPs associated with the new Service.
    • Explore the new Service by ClusterDNS.
    • Create DNS info.
    • kube-proxy fetch Service configration info.
    • Create IPSV rule.

    Procedure of Service discovery.

    • Request DNS name resolution for a Service name.
    • Receive ClusterIP.
    • Traffic access to ClusterIP.
    • No router. Forward request to Pod's default gateway.
    • Forward request to node.
    • No router. Forward request to Node's default gateway.
    • Proceed the request by Node kernel.
    • Trap the request by IPSV rule.
    • Put destination Pod's IP into the request's destination IP.
    • The request arrives destination Pod.

    FQDN format: <object-name>.<namespace>.svc.cluster.local. We call <object-name> as unqualified name, or short name. Namespaces can segregate the cluster's address space. At the same time, it can also be used to implement access control and resource quotas.

    Get DNS configuration in a Pod. The IP of nameserver is same with ClusterIP of kube-dns Service, which is well-known IP for request of DNS or service discovery.

    root@cka001:/etc# kubectl get service kube-dns -n kube-system
     NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
     kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   7d7h
     
     
    -root@cka001:~# kubectl exec -it nginx-5f5496dc9-bv5dx -- /bin/bash
    -root@nginx-5f5496dc9-bv5dx:/# cat /etc/resolv.conf
    +root@cka001:~# kubectl exec -it nginx-5f5496dc9-bv5dx -- /bin/bash
    +root@nginx-5f5496dc9-bv5dx:/# cat /etc/resolv.conf
     search jh-namespace.svc.cluster.local svc.cluster.local cluster.local
     nameserver 10.96.0.10
     options ndots:5
    -

    Get information of kube-dns.

    root@cka001:~# kubectl describe service kube-dns -n kube-system
    +

    Get information of kube-dns.

    root@cka001:~# kubectl describe service kube-dns -n kube-system
     Name:              kube-dns
     Namespace:         kube-system
     Labels:            k8s-app=kube-dns
    @@ -106,4 +106,4 @@
     Endpoints:         10.244.0.2:9153,10.244.0.3:9153
     Session Affinity:  None
     Events:            <none>
    -

    Endpoints

    Endpoints is a collection of endpoints that implement the actual service.

    When a service is created, it associates with a Endpoint object, kubectl get endpoints <service_name>.

    A list of matched Pod by service label is maintained as Endpoint object, add new matched Pods and remove not matched Pods.

    Config and Storage Resources

    Volumes

    emptyDir

    An emptyDir volume is first created when a Pod is assigned to a node, and exists as long as that Pod is running on that node.

    The emptyDir volume is initially empty.

    All containers in the Pod can read and write the same files in the emptyDir volume, though that volume can be mounted at the same or different paths in each container.

    When a Pod is removed from a node for any reason, the data in the emptyDir is deleted permanently.

    A container crashing does not remove a Pod from a node. The data in an emptyDir volume is safe across container crashes.

    Usage:

    • scratch space, such as for a disk-based merge sort
    • checkpointing a long computation for recovery from crashes
    • holding files that a content-manager container fetches while a webserver container serves the data

    hostPath

    A hostPath volume mounts a file or directory from the host node's filesystem into your Pod. This is not something that most Pods will need, but it offers a powerful escape hatch for some applications.

    hostPath volumes present many security risks, and it is a best practice to avoid the use of HostPaths when possible. When a HostPath volume MUST be used, it should be scoped to only the required file or directory, and mounted as ReadOnly.

    If restricting HostPath access to specific directories through AdmissionPolicy, volumeMounts MUST be required to use readOnly mounts for the policy to be effective.

    Usage:

    • Running together with DaemonSet, e.g., EFK Fluentd mount log directory of local host in order to collect host log information.
    • Running on a specific node by using hostPath volumne, which can get high performance disk I/O.
    • Running a container that needs access to Docker internals; use a hostPath of /var/lib/docker.
    • Running cAdvisor in a container; use a hostPath of /sys.
    • Allowing a Pod to specify whether a given hostPath should exist prior to the Pod running, whether it should be created, and what it should exist as.

    Storage Class

    Procedure of StorageClass deployment and implementation:

    • Create Kubernetes cluster and backend storage.
    • Make sure the provisioner/plugin is ready in Kubernetes.
    • Create a StorageClass object to link to backend storage. The StorageClass will create related PV automatically.
    • Create a PVC object to link to the StorageClass we created.
    • Deploy a Pod and use the PVC volume.

    PV

    PV Recycle Policy.

    • Retain.
    • Delete.
    • Recycle.

    PV in-tree type:

    • hostPath
    • local
    • NFS
    • CSI

    Access Modes

    spec.accessModes defines mount option of a PV:

    • ReadWriteOnce(RWO). A PV can be mounted only to a PVC with read/write mode, like block device.
    • ReadWriteMany(RWM). A PV can be mounted to more than one PVC with read/write mode, like NFS.
    • ReadOnlyMany(ROM). A PV can be mounted to more than one PVC with read only mode.
    • ReadWriteOncePod (RWOP). Only support CSI type PV, can be mounted by single Pod.

    A PV can only be set with one option. Pod mount PVC, not PV.

    \ No newline at end of file +

    Endpoints

    Endpoints is a collection of endpoints that implement the actual service.

    When a service is created, it associates with a Endpoint object, kubectl get endpoints <service_name>.

    A list of matched Pod by service label is maintained as Endpoint object, add new matched Pods and remove not matched Pods.

    Config and Storage Resources

    Volumes

    emptyDir

    An emptyDir volume is first created when a Pod is assigned to a node, and exists as long as that Pod is running on that node.

    The emptyDir volume is initially empty.

    All containers in the Pod can read and write the same files in the emptyDir volume, though that volume can be mounted at the same or different paths in each container.

    When a Pod is removed from a node for any reason, the data in the emptyDir is deleted permanently.

    A container crashing does not remove a Pod from a node. The data in an emptyDir volume is safe across container crashes.

    Usage:

    • scratch space, such as for a disk-based merge sort
    • checkpointing a long computation for recovery from crashes
    • holding files that a content-manager container fetches while a webserver container serves the data

    hostPath

    A hostPath volume mounts a file or directory from the host node's filesystem into your Pod. This is not something that most Pods will need, but it offers a powerful escape hatch for some applications.

    hostPath volumes present many security risks, and it is a best practice to avoid the use of HostPaths when possible. When a HostPath volume MUST be used, it should be scoped to only the required file or directory, and mounted as ReadOnly.

    If restricting HostPath access to specific directories through AdmissionPolicy, volumeMounts MUST be required to use readOnly mounts for the policy to be effective.

    Usage:

    • Running together with DaemonSet, e.g., EFK Fluentd mount log directory of local host in order to collect host log information.
    • Running on a specific node by using hostPath volumne, which can get high performance disk I/O.
    • Running a container that needs access to Docker internals; use a hostPath of /var/lib/docker.
    • Running cAdvisor in a container; use a hostPath of /sys.
    • Allowing a Pod to specify whether a given hostPath should exist prior to the Pod running, whether it should be created, and what it should exist as.

    Storage Class

    Procedure of StorageClass deployment and implementation:

    • Create Kubernetes cluster and backend storage.
    • Make sure the provisioner/plugin is ready in Kubernetes.
    • Create a StorageClass object to link to backend storage. The StorageClass will create related PV automatically.
    • Create a PVC object to link to the StorageClass we created.
    • Deploy a Pod and use the PVC volume.

    PV

    PV Recycle Policy.

    • Retain.
    • Delete.
    • Recycle.

    PV in-tree type:

    • hostPath
    • local
    • NFS
    • CSI

    Access Modes

    spec.accessModes defines mount option of a PV:

    • ReadWriteOnce(RWO). A PV can be mounted only to a PVC with read/write mode, like block device.
    • ReadWriteMany(RWM). A PV can be mounted to more than one PVC with read/write mode, like NFS.
    • ReadOnlyMany(ROM). A PV can be mounted to more than one PVC with read only mode.
    • ReadWriteOncePod (RWOP). Only support CSI type PV, can be mounted by single Pod.

    A PV can only be set with one option. Pod mount PVC, not PV.

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/namespace/index.html b/k8s/cka_en/foundamentals/namespace/index.html index addb6486..10d3634e 100644 --- a/k8s/cka_en/foundamentals/namespace/index.html +++ b/k8s/cka_en/foundamentals/namespace/index.html @@ -1,4 +1,4 @@ - Namespace - UPSkilling

    Namespace

    Scenario:

    • Get namespace list
    • Create new namespace
    • Label a namespace
    • Delete a namespace

    Demo:

    Get list of Namespace

    kubectl get namespace
    + Namespace - UPSkilling       

    Namespace

    Scenario:

    • Get namespace list
    • Create new namespace
    • Label a namespace
    • Delete a namespace

    Demo:

    Get list of Namespace

    kubectl get namespace
     

    Get list of Namespace with Label information.

    kubectl get ns --show-labels
     

    Create a Namespace

    kubectl create namespace cka
     

    Label the new created Namespace cka.

    kubectl label ns cka cka=true
    @@ -11,4 +11,4 @@
     pod/nginx-85b98978db-bmkhf   1/1     Running   0          2m14s
     

    Delete namespace cka. All resources in the namespaces will be gone.

    kubectl delete ns cka
     

    Tip:

    • Kubernetes Namespaces stuck in Terminating status.
    kubectl get namespace $NAMESPACE -o json | sed -e 's/"kubernetes"//' | kubectl replace --raw "/api/v1/namespaces/$NAMESPACE/finalize" -f -
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/networkpolicy/index.html b/k8s/cka_en/foundamentals/networkpolicy/index.html index 9f945505..848c1840 100644 --- a/k8s/cka_en/foundamentals/networkpolicy/index.html +++ b/k8s/cka_en/foundamentals/networkpolicy/index.html @@ -1,4 +1,4 @@ - Network Policy - UPSkilling

    Network Policy

    Replace Flannel by Calico

    Scenario

    • Remove Flannel
    • Install Calico

    Demo:

    If Calico was installed at the installation phase, ignore this section.

    Delete Flannel

    kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/v0.18.1/Documentation/kube-flannel.yml
    + Network Policy - UPSkilling       

    Network Policy

    Replace Flannel by Calico

    Scenario

    • Remove Flannel
    • Install Calico

    Demo:

    If Calico was installed at the installation phase, ignore this section.

    Delete Flannel

    kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/v0.18.1/Documentation/kube-flannel.yml
     
    or
    kubectl delete -f kube-flannel.yml
     
    Output:
    Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
     podsecuritypolicy.policy "psp.flannel.unprivileged" deleted
    @@ -44,10 +44,10 @@
     calico-node-7x8jm                          1/1     Running       0          30m
     calico-node-cwxj5                          1/1     Running       0          30m
     calico-node-rq978                          1/1     Running       0          30m
    -

    If facing any error, check log in the Container.

    # Get Container ID
    +

    If facing any error, check log in the Container.

    # Get Container ID
     crictl ps
     
    -# Get log info
    +# Get log info
     crictl logs <your_container_id>
     

    As we change CNI from Flannel to Calico, we need delete all Pods. All of Pods will be created automatically again.

    kubectl delete pod -A --all
     

    Make sure all Pods are up and running successfully.

    kubectl get pod -A
    @@ -253,4 +253,4 @@
     

    Edit my-networkpolicy-1 to change ingress.from.namespaceSelector.matchLabels to my-ns-2.

    Attach to temp pod on namespace my-ns-2. Verify the access. Command curl <nginx_ip>:80 failed. Command curl <tomcat_ip>:80 succeed.

    kubectl exec -it mycentos -n my-ns-2 -- bash
     

    Clean up:

    kubectl delete namespace my-ns-1
     kubectl delete namespace my-ns-2
    -

    \ No newline at end of file +

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/overview/index.html b/k8s/cka_en/foundamentals/overview/index.html index bbfccf67..a65b51f8 100644 --- a/k8s/cka_en/foundamentals/overview/index.html +++ b/k8s/cka_en/foundamentals/overview/index.html @@ -1,4 +1,4 @@ - Overview - UPSkilling

    Cluster Overview

    Contents

    Information:

    Container Layer

    Scenario: Use Containerd service to manage our images and containers via command nerdctl, which is same concept with Docker.

    • Get namespace.
    • Get containers.
    • Get images.
    • Get volumes.
    • Get overall status.
    • Get network status.

    Demo:

    Get namespaces.

    sudo nerdctl namespace ls
    + Overview - UPSkilling       

    Cluster Overview

    Contents

    Information:

    Container Layer

    Scenario: Use Containerd service to manage our images and containers via command nerdctl, which is same concept with Docker.

    • Get namespace.
    • Get containers.
    • Get images.
    • Get volumes.
    • Get overall status.
    • Get network status.

    Demo:

    Get namespaces.

    sudo nerdctl namespace ls
     

    Result

    NAME      CONTAINERS    IMAGES    VOLUMES    LABELS
     k8s.io    21            30        0      
     

    Get containers under specific namespace k8s.io.

    sudo nerdctl -n k8s.io ps
    @@ -57,4 +57,4 @@
     kube-system   kube-proxy-n77zw                           1/1     Running   0          15h   cka002   <none>           <none>
     kube-system   kube-proxy-qs6rf                           1/1     Running   0          15h   cka003   <none>           <none>
     kube-system   kube-scheduler-cka001                      1/1     Running   0          15h   cka001   <none>           <none>
    -

    Summary:

    Below shows the relationship between containers and pods.

    • Master node:
    • CoreDNS: 2 Pod
    • etcd: 1 Pod
    • apiserver: 1 Pod
    • controller-manager: 1 Pod
    • scheduler: 1 Pod
    • Calico Controller: 1 Pod
    • All nodes:
    • Calico Node: 1 Pod each
    • Proxy: 1 Pod each

    Reference

    \ No newline at end of file +

    Summary:

    Below shows the relationship between containers and pods.

    • Master node:
    • CoreDNS: 2 Pod
    • etcd: 1 Pod
    • apiserver: 1 Pod
    • controller-manager: 1 Pod
    • scheduler: 1 Pod
    • Calico Controller: 1 Pod
    • All nodes:
    • Calico Node: 1 Pod each
    • Proxy: 1 Pod each

    Reference

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/persistence/index.html b/k8s/cka_en/foundamentals/persistence/index.html index db404266..bb9fb52b 100644 --- a/k8s/cka_en/foundamentals/persistence/index.html +++ b/k8s/cka_en/foundamentals/persistence/index.html @@ -1,4 +1,4 @@ - Persistence - UPSkilling

    Persistence

    Scenario

    • Creat Pod with emptyDir type Volume. Container in the Pod will mount default directory /var/lib/kubelet/pods/ on running node.
    • Create Deployment Deployment with hostPath type volume. Container in the Deployment will mount directory defined in hostPath: on running node.
    • PV and PVC.
    • Set up NFS Server and share folder /nfsdata/.
    • Create PV mysql-pv to link to the share folder /nfsdata/ and set StorageClassName nfs.
    • Create PVC mysql-pvc mapped with StorageClassName nfs.
    • Create Deployment mysql to consume PVC mysql-pvc.
    • StorageClass
    • Create ServiceAccount nfs-client-provisioner.
    • Create ClusterRole nfs-client-provisioner-runner and Role leader-locking-nfs-client-provisioner and bind them to the ServiceAccount so the ServiceAccount has authorization to operate the Deployment created in next step.
    • Create Deployment nfs-client-provisioner to to add connection information for your NFS server, e.g, PROVISIONER_NAME is k8s-sigs.io/ nfs-subdir-external-provisioner
    • Create StorageClass nfs-client link to provisioner: k8s-sigs.io/nfs-subdir-external-provisioner. Releated PV is created automatically.
    • Create PVC nfs-pvc-from-sc mapped to PV and StorageClass nfs-client.
    • Configuration
    • Create a ConfigMap for content of a file, and mount this ConfigMap to a specific file in a Pod.
    • Create a ConfigMap for username and password, and consume them within a Pod.
    • Use ConfigMap as environment variables in Pod.

    Tips

    • Delete PVC first, then delete PV.
    • If facing Terminating status when delete a PVC, use kubectl edit pvc <your_pvc_name> and remove finalize: <your_value>.

    emptyDir

    Create a Pod hello-producer with emptyDir type Volume.

    cat > pod-emptydir.yaml <<EOF
    + Persistence - UPSkilling       

    Persistence

    Scenario

    • Creat Pod with emptyDir type Volume. Container in the Pod will mount default directory /var/lib/kubelet/pods/ on running node.
    • Create Deployment Deployment with hostPath type volume. Container in the Deployment will mount directory defined in hostPath: on running node.
    • PV and PVC.
    • Set up NFS Server and share folder /nfsdata/.
    • Create PV mysql-pv to link to the share folder /nfsdata/ and set StorageClassName nfs.
    • Create PVC mysql-pvc mapped with StorageClassName nfs.
    • Create Deployment mysql to consume PVC mysql-pvc.
    • StorageClass
    • Create ServiceAccount nfs-client-provisioner.
    • Create ClusterRole nfs-client-provisioner-runner and Role leader-locking-nfs-client-provisioner and bind them to the ServiceAccount so the ServiceAccount has authorization to operate the Deployment created in next step.
    • Create Deployment nfs-client-provisioner to to add connection information for your NFS server, e.g, PROVISIONER_NAME is k8s-sigs.io/ nfs-subdir-external-provisioner
    • Create StorageClass nfs-client link to provisioner: k8s-sigs.io/nfs-subdir-external-provisioner. Releated PV is created automatically.
    • Create PVC nfs-pvc-from-sc mapped to PV and StorageClass nfs-client.
    • Configuration
    • Create a ConfigMap for content of a file, and mount this ConfigMap to a specific file in a Pod.
    • Create a ConfigMap for username and password, and consume them within a Pod.
    • Use ConfigMap as environment variables in Pod.

    Tips

    • Delete PVC first, then delete PV.
    • If facing Terminating status when delete a PVC, use kubectl edit pvc <your_pvc_name> and remove finalize: <your_value>.

    emptyDir

    Create a Pod hello-producer with emptyDir type Volume.

    cat > pod-emptydir.yaml <<EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -166,7 +166,7 @@
            persistentVolumeClaim:
             claimName: mysql-pvc
     EOF
    -

    Now we can see MySQL files were moved to directory /nfsdata on cka002

    StorageClass

    Configure RBAC Authorization

    RBAC authorization uses the rbac.authorization.k8s.io API group to drive authorization decisions, allowing you to dynamically configure policies through the Kubernetes API.

    • ServiceAccount: nfs-client-provisioner
    • namespace: dev

    • ClusterRole: nfs-client-provisioner-runner. Grant authorization on node, pv, pvc, sc, event.

    • ClusterRoleBinding: run-nfs-client-provisioner, bind above ClusterRole to above ServiceAccount.

    • Role: leader-locking-nfs-client-provisioner. Grant authorization on endpoint.

    • RoleBinding: leader-locking-nfs-client-provisioner, bind above Role to above ServiceAccount.

    Create RBAC Authorization.

    cat > nfs-provisioner-rbac.yaml <<EOF
    +

    Now we can see MySQL files were moved to directory /nfsdata on cka002

    StorageClass

    Configure RBAC Authorization

    RBAC authorization uses the rbac.authorization.k8s.io API group to drive authorization decisions, allowing you to dynamically configure policies through the Kubernetes API.

    • ServiceAccount: nfs-client-provisioner
    • namespace: dev

    • ClusterRole: nfs-client-provisioner-runner. Grant authorization on node, pv, pvc, sc, event.

    • ClusterRoleBinding: run-nfs-client-provisioner, bind above ClusterRole to above ServiceAccount.

    • Role: leader-locking-nfs-client-provisioner. Grant authorization on endpoint.

    • RoleBinding: leader-locking-nfs-client-provisioner, bind above Role to above ServiceAccount.

    Create RBAC Authorization.

    cat > nfs-provisioner-rbac.yaml <<EOF
     apiVersion: v1
     kind: ServiceAccount
     metadata:
    @@ -238,7 +238,7 @@
     EOF
     
     
    -kubectl apply -f nfs-provisioner-rbac.yaml
    +kubectl apply -f nfs-provisioner-rbac.yaml
     

    Create Provisioner's Deloyment

    Create Deloyment nfs-client-provisioner by consuming volume nfs-client-root mapped to /nfsdata on <cka002_ip>(cka002). Replace NFS server IP with actual IP (here is <cka002_ip>)

    cat > nfs-provisioner-deployment.yaml <<EOF
     apiVersion: apps/v1
     kind: Deployment
    @@ -279,16 +279,16 @@
     
     kubectl apply -f nfs-provisioner-deployment.yaml
     

    Create NFS StorageClass

    Create StorageClass nfs-client. Define the NFS subdir external provisioner's Kubernetes Storage Class.

    vi nfs-storageclass.yaml
    -

    And add below info to create NFS StorageClass.

    apiVersion: storage.k8s.io/v1
    -kind: StorageClass
    -metadata:
    -  name: nfs-client
    -  annotations:
    -    storageclass.kubernetes.io/is-default-class: "true"
    -provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
    -parameters:
    -  pathPattern: "${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}"
    -  onDelete: delete
    +

    And add below info to create NFS StorageClass.

    apiVersion: storage.k8s.io/v1
    +kind: StorageClass
    +metadata:
    +  name: nfs-client
    +  annotations:
    +    storageclass.kubernetes.io/is-default-class: "true"
    +provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
    +parameters:
    +  pathPattern: "${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}"
    +  onDelete: delete
     

    Apply the yaml file.

    kubectl apply -f nfs-storageclass.yaml
     

    Create PVC

    Create PVC nfs-pvc-from-sc.

    kubectl apply -f - <<EOF
     kind: PersistentVolumeClaim
    @@ -377,46 +377,46 @@
     ├── kube-system
     └── mysqldata
     

    Please be noted that above rule is following nfs-subdir-external-provisioner implementation. It's may be different with other provisioner.

    Detail about nfs-subdir-external-provisioner project is here

    Configuration

    ConfigMap

    Create ConfigMap cm-nginx to define content of nginx.conf.

    vi configmap.yaml
    -

    Paste below content.

    apiVersion: v1
    -kind: ConfigMap
    -metadata:
    -  labels:
    -    cattle.io/creator: norman
    -  name: cm-nginx
    -  namespace: dev
    -data:
    -  nginx.conf: |-
    -    user  nginx;
    -    worker_processes  2;
    +

    Paste below content.

    apiVersion: v1
    +kind: ConfigMap
    +metadata:
    +  labels:
    +    cattle.io/creator: norman
    +  name: cm-nginx
    +  namespace: dev
    +data:
    +  nginx.conf: |-
    +    user  nginx;
    +    worker_processes  2;
     
    -    error_log  /var/log/nginx/error.log warn;
    -    pid        /var/run/nginx.pid;
    +    error_log  /var/log/nginx/error.log warn;
    +    pid        /var/run/nginx.pid;
     
     
    -    events {
    -        worker_connections  1024;
    -    }
    +    events {
    +        worker_connections  1024;
    +    }
     
     
    -    http {
    -        include       /etc/nginx/mime.types;
    -        default_type  application/octet-stream;
    +    http {
    +        include       /etc/nginx/mime.types;
    +        default_type  application/octet-stream;
     
    -        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    -                          '$status $body_bytes_sent "$http_referer" '
    -                          '"$http_user_agent" "$http_x_forwarded_for"';
    +        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    +                          '$status $body_bytes_sent "$http_referer" '
    +                          '"$http_user_agent" "$http_x_forwarded_for"';
     
    -        access_log  /var/log/nginx/access.log  main;
    +        access_log  /var/log/nginx/access.log  main;
     
    -        sendfile        on;
    -        #tcp_nopush     on;
    +        sendfile        on;
    +        #tcp_nopush     on;
     
    -        keepalive_timeout  65;
    +        keepalive_timeout  65;
     
    -        #gzip  on;
    +        #gzip  on;
     
    -        include /etc/nginx/conf.d/*.conf;
    -    }
    +        include /etc/nginx/conf.d/*.conf;
    +    }
     

    Apply the ConfigMap.

    kubectl apply -f configmap.yaml
     

    Create Pod nginx-with-cm.

    kubectl apply -f - <<EOF
     apiVersion: v1
    @@ -504,27 +504,27 @@
     --from-file=./favorite  \
     --from-file=./primary/
     

    Check content of the ConfigMap colors.

    kubectl get configmap colors -o yaml
    -
    apiVersion: v1
    -data:
    -  black: |
    -    k
    -    known as key
    -  cyan: |
    -    c
    -  favorite: |
    -    blue
    -  magenta: |
    -    m
    -  text: black
    -  yellow: |
    -    y
    -kind: ConfigMap
    -metadata:
    -  creationTimestamp: "2022-07-12T16:38:27Z"
    -  name: colors
    -  namespace: dev
    -  resourceVersion: "2377258"
    -  uid: d5ab133f-5e4d-41d4-bc9e-2bbb22a872a1
    +
    apiVersion: v1
    +data:
    +  black: |
    +    k
    +    known as key
    +  cyan: |
    +    c
    +  favorite: |
    +    blue
    +  magenta: |
    +    m
    +  text: black
    +  yellow: |
    +    y
    +kind: ConfigMap
    +metadata:
    +  creationTimestamp: "2022-07-12T16:38:27Z"
    +  name: colors
    +  namespace: dev
    +  resourceVersion: "2377258"
    +  uid: d5ab133f-5e4d-41d4-bc9e-2bbb22a872a1
     

    Set environment variable via ConfigMap

    Here we will create a Pod pod-configmap-env and set the environment variable ilike and assign value of favorite from ConfigMap colors.

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Pod
    @@ -564,4 +564,4 @@
     c
     root@pod-configmap-env-2:/# echo $favorite
     blue
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/pod/index.html b/k8s/cka_en/foundamentals/pod/index.html index 68969bd1..1cc997ed 100644 --- a/k8s/cka_en/foundamentals/pod/index.html +++ b/k8s/cka_en/foundamentals/pod/index.html @@ -1,4 +1,4 @@ - Pod - UPSkilling

    Work on pod

    Create pod

    Create pod my-first-podl.

    kubectl apply -f - << EOF
    + Pod - UPSkilling       

    Work on pod

    Create pod

    Create pod my-first-podl.

    kubectl apply -f - << EOF
     apiVersion: v1
     kind: Pod
     metadata:
    @@ -14,7 +14,7 @@
     

    Track pod

    Check logs of the pod just created.

    kubectl logs my-first-pod
     

    In case logs or describe or any other of the output generating commands don't help us to get to the root cause of an issue, we can use use kubectl exec -it <my-pod> -- bash command to look into it ourselves.

    kubectl exec -it my-first-pod -- bash
     root@my-first-pod:/# ls
    -root@my-first-pod:/# cd bin
    +root@my-first-pod:/# cd bin
     root@my-first-pod:/bin# ls
     root@my-first-pod:/bin# exit
     

    Execute command kubectl explain pod.spec will get details of Spec segment of Pod kind in yaml file.

    We can check the official API reference of the pod resource for help or use kubectl explain pod to get a command-line based description of the resource. By appending .<field> to the resource type, the explain command will provide more details on the specified field.

    kubectl explain pod.kind
    @@ -301,4 +301,4 @@
     myapp-pod   0/1     Init:0/2   0          2m40s   10.244.112.2   cka002   <none>           <none>
     

    We now see that those init containers complete, and that the myapp-pod Pod moves into the Running state.

    Clean up.

    kubectl delete service mydb myservice 
     kubectl delete pod myapp-pod 
    -

    References:

    \ No newline at end of file +

    References:

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/policy/index.html b/k8s/cka_en/foundamentals/policy/index.html index bd8a5543..5d8061a7 100644 --- a/k8s/cka_en/foundamentals/policy/index.html +++ b/k8s/cka_en/foundamentals/policy/index.html @@ -1,4 +1,4 @@ - Policy - UPSkilling

    Policy

    ResourceQuota

    Scenario:

    • Create ResourceQuota object-quota-demo for namespace quota-object-example.
    • Test ResourceQuota object-quota-demo for NodePort
    • Test ResourceQuota object-quota-demo for PVC

    Create Namespace

    Ceate a Namespace

    kubectl create ns quota-object-example
    + Policy - UPSkilling       

    Policy

    ResourceQuota

    Scenario:

    • Create ResourceQuota object-quota-demo for namespace quota-object-example.
    • Test ResourceQuota object-quota-demo for NodePort
    • Test ResourceQuota object-quota-demo for PVC

    Create Namespace

    Ceate a Namespace

    kubectl create ns quota-object-example
     

    Create ResourceQuota for Namespace

    Create ResourceQuota object-quota-demo for namespace quota-object-example. Within the namespace, we can only create 1 PVC, 1 LoadBalancer Service, can not create NodePort Service.

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: ResourceQuota
    @@ -12,20 +12,20 @@
         services.nodeports: "0"
     EOF
     

    Check Quota status

    kubectl get resourcequota object-quota-demo --namespace=quota-object-example --output=yaml
    -

    Key information is below.

    spec:
    -  hard:
    -    persistentvolumeclaims: "1"
    -    services.loadbalancers: "2"
    -    services.nodeports: "0"
    -status:
    -  hard:
    -    persistentvolumeclaims: "1"
    -    services.loadbalancers: "2"
    -    services.nodeports: "0"
    -  used:
    -    persistentvolumeclaims: "0"
    -    services.loadbalancers: "0"
    -    services.nodeports: "0"
    +

    Key information is below.

    spec:
    +  hard:
    +    persistentvolumeclaims: "1"
    +    services.loadbalancers: "2"
    +    services.nodeports: "0"
    +status:
    +  hard:
    +    persistentvolumeclaims: "1"
    +    services.loadbalancers: "2"
    +    services.nodeports: "0"
    +  used:
    +    persistentvolumeclaims: "0"
    +    services.loadbalancers: "0"
    +    services.nodeports: "0"
     

    Test Quota for NodePort

    Create a Deployment ns-quota-test on namespace quota-object-example.

    kubectl create deployment ns-quota-test --image nginx --namespace=quota-object-example
     

    Expose the Deployment via NodePort

    kubectl expose deployment ns-quota-test --port=80 --type=NodePort --namespace=quota-object-example
     

    We receive below error, which is expected because we set Quota services.nodeports: 0.

    Error from server (Forbidden): services "ns-quota-test" is forbidden: exceeded quota: object-quota-demo, requested: services.nodeports=1, used: services.nodeports=0, limited: services.nodeports=0
    @@ -44,20 +44,20 @@
           storage: 3Gi
     EOF
     

    Check the Quota status.

    kubectl get resourcequota object-quota-demo --namespace=quota-object-example --output=yaml
    -

    Here persistentvolumeclaims is used 1, and the quota is also 1. If we create PVC again, will receive 403 error.

    spec:
    -  hard:
    -    persistentvolumeclaims: "1"
    -    services.loadbalancers: "2"
    -    services.nodeports: "0"
    -status:
    -  hard:
    -    persistentvolumeclaims: "1"
    -    services.loadbalancers: "2"
    -    services.nodeports: "0"
    -  used:
    -    persistentvolumeclaims: "1"
    -    services.loadbalancers: "0"
    -    services.nodeports: "0"
    +

    Here persistentvolumeclaims is used 1, and the quota is also 1. If we create PVC again, will receive 403 error.

    spec:
    +  hard:
    +    persistentvolumeclaims: "1"
    +    services.loadbalancers: "2"
    +    services.nodeports: "0"
    +status:
    +  hard:
    +    persistentvolumeclaims: "1"
    +    services.loadbalancers: "2"
    +    services.nodeports: "0"
    +  used:
    +    persistentvolumeclaims: "1"
    +    services.loadbalancers: "0"
    +    services.nodeports: "0"
     

    LimitRange

    Scenario:

    • Create LimitRange cpu-limit-range to define range of CPU Request and CPU Limit for a Container.
    • Test LimitRange cpu-limit-range via Pod.
    • Scenario 1: Pod without specified limits
    • Scenario 2: Pod with CPU limit, without CPU Request
    • Scenario 3: Pod with CPU Request onlyl, without CPU Limits

    Background:

    A LimitRange provides constraints that can:

    • Enforce minimum and maximum compute resources usage per Pod or Container in a namespace.
    • Enforce minimum and maximum storage request per PersistentVolumeClaim in a namespace.
    • Enforce a ratio between request and limit for a resource in a namespace.
    • Set default request/limit for compute resources in a namespace and automatically inject them to Containers at runtime.

    Set LimitRange

    Create a Namespace default-cpu-example for demo.

    kubectl create namespace default-cpu-example
     

    Create LimitRange cpu-limit-range to define range of CPU Request and CPU Limit for a Container. After apply LimitRange resource, the CPU limitation will affect all new created Pods.

    kubectl apply -f - << EOF
     apiVersion: v1
    @@ -85,16 +85,16 @@
         image: nginx
     EOF
     

    Verify details of the Pod we created. The Pod inherits the both CPU Limits and CPU Requests from namespace as its default.

    kubectl get pod default-cpu-demo --output=yaml --namespace=default-cpu-example
    -
    spec:
    -  containers:
    -  - image: nginx
    -    imagePullPolicy: Always
    -    name: default-cpu-demo-ctr
    -    resources:
    -      limits:
    -        cpu: "1"
    -      requests:
    -        cpu: 500m
    +
    spec:
    +  containers:
    +  - image: nginx
    +    imagePullPolicy: Always
    +    name: default-cpu-demo-ctr
    +    resources:
    +      limits:
    +        cpu: "1"
    +      requests:
    +        cpu: 500m
     
    • Scenario 2: Pod with CPU limit, without CPU Request

    Create Pod with specified CPU limits only.

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Pod
    @@ -112,16 +112,16 @@
     
     kubectl apply -f default-cpu-demo-limit.yaml
     

    Verify details of the Pod we created. The Pod inherits the CPU Request from namespace as its default and specifies own CPU Limits.

    kubectl get pod default-cpu-demo-limit --output=yaml --namespace=default-cpu-example
    -
    spec:
    -  containers:
    -  - image: nginx
    -    imagePullPolicy: Always
    -    name: default-cpu-demo-limit-ctr
    -    resources:
    -      limits:
    -        cpu: "1"
    -      requests:
    -        cpu: "1"
    +
    spec:
    +  containers:
    +  - image: nginx
    +    imagePullPolicy: Always
    +    name: default-cpu-demo-limit-ctr
    +    resources:
    +      limits:
    +        cpu: "1"
    +      requests:
    +        cpu: "1"
     
    • Scenario 3: Pod with CPU Request onlyl, without CPU Limits

    Create Pod with specified CPU Request only.

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Pod
    @@ -137,14 +137,14 @@
             cpu: "0.75"
     EOF
     

    Verify details of the Pod we created. The Pod inherits the CPU Limits from namespace as its default and specifies own CPU Requests.

    kubectl get pod default-cpu-demo-request --output=yaml --namespace=default-cpu-example
    -
    spec:
    -  containers:
    -  - image: nginx
    -    imagePullPolicy: Always
    -    name: default-cpu-demo-request-ctr
    -    resources:
    -      limits:
    -        cpu: "1"
    -      requests:
    -        cpu: 750m
    -
    \ No newline at end of file +
    spec:
    +  containers:
    +  - image: nginx
    +    imagePullPolicy: Always
    +    name: default-cpu-demo-request-ctr
    +    resources:
    +      limits:
    +        cpu: "1"
    +      requests:
    +        cpu: 750m
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/rbac/index.html b/k8s/cka_en/foundamentals/rbac/index.html index 199d29d3..7c199d16 100644 --- a/k8s/cka_en/foundamentals/rbac/index.html +++ b/k8s/cka_en/foundamentals/rbac/index.html @@ -1,4 +1,4 @@ - Role Based Access Control (RBAC) - UPSkilling

    Role Based Access Control (RBAC)

    Scenario

    1. Create differnet profiles for one cluster.
    2. Use cfssl generate certificates for each profile.
    3. Create new kubeconfig file with all profiles and associated users.
    4. Merge old and new kubeconfig files into new kubeconfig file. We can switch different context for further demo.

    Background

    • Role-based access control (RBAC) is a method of regulating access to computer or network resources based on the roles of individual users within the organization.
    • When using client certificate authentication, we can generate certificates manually through easyrsa, openssl or cfssl.

    Best-Pracice

    • The purpose of kubeconfig is to grant different authorizations to different users for different clusters.
    • Different contexts will link to different clusters.
    • It's not recommended to put multiple users' contexts for one cluster in one kubeconfig.
    • It's recommended to use one kubeconfig file for one user.

    Install cfssl

    Install cfssl tool

    apt install golang-cfssl
    + Role Based Access Control (RBAC) - UPSkilling       

    Role Based Access Control (RBAC)

    Scenario

    1. Create differnet profiles for one cluster.
    2. Use cfssl generate certificates for each profile.
    3. Create new kubeconfig file with all profiles and associated users.
    4. Merge old and new kubeconfig files into new kubeconfig file. We can switch different context for further demo.

    Background

    • Role-based access control (RBAC) is a method of regulating access to computer or network resources based on the roles of individual users within the organization.
    • When using client certificate authentication, we can generate certificates manually through easyrsa, openssl or cfssl.

    Best-Pracice

    • The purpose of kubeconfig is to grant different authorizations to different users for different clusters.
    • Different contexts will link to different clusters.
    • It's not recommended to put multiple users' contexts for one cluster in one kubeconfig.
    • It's recommended to use one kubeconfig file for one user.

    Install cfssl

    Install cfssl tool

    apt install golang-cfssl
     

    Set Multiple Contexts

    Current Context

    Execute command kubectl config to get current contenxt.

    kubectl config get-contexts
     

    We get below key information of the cluster.

    • Cluster Name: kubernetes
    • System account: kubenetes-admin
    • Current context name: kubernetes-admin@kubernetes (format: <system_account>@<cluster_name>)
    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
     *         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   dev
    @@ -95,38 +95,38 @@
     -rw-r--r-- 1 root root 1001 Jul 24 09:14 cka-dev.csr
     -rw------- 1 root root 1671 Jul 24 09:16 cka-dev.kubeconfig
     

    Get content of file cka-dev.kubeconfig.

    cat cka-dev.kubeconfig
    -
    apiVersion: v1
    -clusters:
    -- cluster:
    -    certificate-authority-data: <your_key>
    -    server: https://<cka001_ip>:6443
    -  name: kubernetes
    -contexts: null
    -current-context: ""
    -kind: Config
    -preferences: {}
    -users: null
    +
    apiVersion: v1
    +clusters:
    +- cluster:
    +    certificate-authority-data: <your_key>
    +    server: https://<cka001_ip>:6443
    +  name: kubernetes
    +contexts: null
    +current-context: ""
    +kind: Config
    +preferences: {}
    +users: null
     

    2.Set up user

    In file cka-dev.kubeconfig, user info is null.

    Set up user cka-dev.

    kubectl config set-credentials cka-dev \
       --client-certificate=/etc/kubernetes/pki/cka-dev.pem \
       --client-key=/etc/kubernetes/pki/cka-dev-key.pem \
       --embed-certs=true \
       --kubeconfig=cka-dev.kubeconfig
     

    Now file cka-dev.kubeconfig was updated and user information was added.

    cat cka-dev.kubeconfig
    -
    apiVersion: v1
    -clusters:
    -- cluster:
    -    certificate-authority-data: <your_key>
    -    server: https://<cka001_ip>:6443
    -  name: kubernetes
    -contexts: null
    -current-context: ""
    -kind: Config
    -preferences: {}
    -users:
    -- name: cka-dev
    -  user:
    -    client-certificate-data: <your_key>
    -    client-key-data: <your_key>
    +
    apiVersion: v1
    +clusters:
    +- cluster:
    +    certificate-authority-data: <your_key>
    +    server: https://<cka001_ip>:6443
    +  name: kubernetes
    +contexts: null
    +current-context: ""
    +kind: Config
    +preferences: {}
    +users:
    +- name: cka-dev
    +  user:
    +    client-certificate-data: <your_key>
    +    client-key-data: <your_key>
     

    Now we have a complete kubeconfig file cka-dev.kubeconfig. When we use it to get node information, receive error below because we did not set up current-context in kubeconfig file.

    kubectl --kubeconfig=cka-dev.kubeconfig get nodes
     
    The connection to the server localhost:8080 was refused - did you specify the right host or port?
     

    Current contents is empty.

    kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts
    @@ -271,4 +271,4 @@
     kubectl -n my-namespace create rolebinding my-clusterrolebinding --clusterrole=my-clusterrole --serviceaccount=my-namespace:my-sa
     

    Clean up.

    kubectl delete namespace my-namespace 
     kubectl delete clusterrole my-clusterrole
    -

    Hints

    1. A RoleBinding may reference any Role in the same namespace.
    2. A RoleBinding can reference a ClusterRole and bind that ClusterRole to the namespace of the RoleBinding.
    3. If you want to bind a ClusterRole to all the namespaces in your cluster, you use a ClusterRoleBinding.
    4. Use RoleBinding to bind ClusterRole is to reuse the ClusterRole for namespaced resources, avoid duplicated namespaced roles for same authorization.
    \ No newline at end of file +

    Hints

    1. A RoleBinding may reference any Role in the same namespace.
    2. A RoleBinding can reference a ClusterRole and bind that ClusterRole to the namespace of the RoleBinding.
    3. If you want to bind a ClusterRole to all the namespaces in your cluster, you use a ClusterRoleBinding.
    4. Use RoleBinding to bind ClusterRole is to reuse the ClusterRole for namespaced resources, avoid duplicated namespaced roles for same authorization.
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/scheduling/index.html b/k8s/cka_en/foundamentals/scheduling/index.html index ac3d7ef5..396f36f8 100644 --- a/k8s/cka_en/foundamentals/scheduling/index.html +++ b/k8s/cka_en/foundamentals/scheduling/index.html @@ -1,4 +1,4 @@ - Scheduling - UPSkilling

    Scheduling

    Scenario:

    • Configure nodeSelector for Pod.
    • Configure nodeName for Node.
    • Use podAffinity to group Pods.
    • Taints & Tolerations
    • Set Taints
    • Set Tolerations
    • Remove Taints

    nodeSelector

    Let's assume the scenario below.

    • We have a group of high performance servers.
    • Some applications require high performance computing.
    • These applicaiton need to be scheduled and running on those high performance servers.

    We can leverage Kubernetes attributes node label and nodeSelector to group resources as a whole for scheduling to meet above requirement.

    1.Label Node

    Let's label cka002 with Configuration=hight.

    kubectl label node cka002 configuration=hight
    + Scheduling - UPSkilling       

    Scheduling

    Scenario:

    • Configure nodeSelector for Pod.
    • Configure nodeName for Node.
    • Use podAffinity to group Pods.
    • Taints & Tolerations
    • Set Taints
    • Set Tolerations
    • Remove Taints

    nodeSelector

    Let's assume the scenario below.

    • We have a group of high performance servers.
    • Some applications require high performance computing.
    • These applicaiton need to be scheduled and running on those high performance servers.

    We can leverage Kubernetes attributes node label and nodeSelector to group resources as a whole for scheduling to meet above requirement.

    1.Label Node

    Let's label cka002 with Configuration=hight.

    kubectl label node cka002 configuration=hight
     

    Verify. We wil see the label configuration=hight on cka002.

    kubectl get node --show-labels
     

    2.Configure nodeSelector for Pod

    Create a Pod and use nodeSelector to schedule the Pod running on specified node.

    kubectl apply -f - <<EOF
     apiVersion: apps/v1
    @@ -112,4 +112,4 @@
     EOF
     

    The Pod of Deployment mysql-tolerations is scheduled and running on node cka003 with tolerations setting, which is a taint node.

    kubectl get pod -o wide | grep mysql-tolerations
     

    Remove Taints

    kubectl taint nodes cka003 key-
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/secrets/index.html b/k8s/cka_en/foundamentals/secrets/index.html index 2531e2e1..89a0c6d9 100644 --- a/k8s/cka_en/foundamentals/secrets/index.html +++ b/k8s/cka_en/foundamentals/secrets/index.html @@ -1 +1 @@ - Secrets - UPSkilling

    Secrets

    \ No newline at end of file + Secrets - UPSkilling

    Secrets

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/service/index.html b/k8s/cka_en/foundamentals/service/index.html index 3a6366a9..3eae2aa0 100644 --- a/k8s/cka_en/foundamentals/service/index.html +++ b/k8s/cka_en/foundamentals/service/index.html @@ -1,4 +1,4 @@ - Service - UPSkilling

    Service

    Scenario:

    • Create Deployment httpd-app.
    • Create Service httpd-app with type ClusterIP, which is default type and accessable internally.
    • Verify the access to Pod IP and Service ClusterIP.
    • Update Service httpd-app with type NodePort. No change to the Deployment httpd-app.
    • Verify the access to Node. The access will route to Pod. The service is now accesable from outside.
    • Create Headless Service web and StatefulSet web.
    • Service Internal Traffic Policy

    ClusterIP

    Create Service

    Create a Deployment http-app. Create a Service httpd-app link to Development http-app by Label Selector.

    Service type is ClusterIP, which is default type and accessable internally.

    kubectl apply -f - <<EOF
    + Service - UPSkilling       

    Service

    Scenario:

    • Create Deployment httpd-app.
    • Create Service httpd-app with type ClusterIP, which is default type and accessable internally.
    • Verify the access to Pod IP and Service ClusterIP.
    • Update Service httpd-app with type NodePort. No change to the Deployment httpd-app.
    • Verify the access to Node. The access will route to Pod. The service is now accesable from outside.
    • Create Headless Service web and StatefulSet web.
    • Service Internal Traffic Policy

    ClusterIP

    Create Service

    Create a Deployment http-app. Create a Service httpd-app link to Development http-app by Label Selector.

    Service type is ClusterIP, which is default type and accessable internally.

    kubectl apply -f - <<EOF
     apiVersion: v1
     kind: Service
     metadata:
    @@ -233,18 +233,18 @@
     

    Let's log onto cka002 and the http request to the Pod again. We will receive Welcome to nginx! information,

    curl 11.244.163.60
     

    Conclution

    With setting Service internalTrafficPolicy: Local, the Service only route internal traffic within the nodes that Pods are running.

    Scenario

    *Create a nginx deployment * Add port number and alias name of the nginx Pod. * Expose the deployment with internal traffic to local only.

    Demo:

    Create deployment my-nginx with port number 80.

    kubectl create deployment my-nginx --image=nginx --port=80
     

    Edit deployment.

    kubectl edit deployment my-nginx
    -

    Add port alias name http. Refer to the link for deployment yaml template https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

        spec:
    -      containers:
    -      - image: nginx
    -        imagePullPolicy: Always
    -        name: nginx
    -        ports:
    -        - containerPort: 80
    -          protocol: TCP
    -          name: http
    +

    Add port alias name http. Refer to the link for deployment yaml template https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

        spec:
    +      containers:
    +      - image: nginx
    +        imagePullPolicy: Always
    +        name: nginx
    +        ports:
    +        - containerPort: 80
    +          protocol: TCP
    +          name: http
     

    Expose the deployment with NodePort type.

    kubectl expose deployment my-nginx --port=80 --target-port=http --name=my-nginx-svc --type=NodePort
     

    Edit the service. Change internalTrafficPolicy from Cluster to Local.

    kubectl edit svc my-nginx-svc 
     

    Verify the access. Note, the pod is running on node cka003. We will see below expected results.

    curl <deployment_pod_ip>:80    # succeed on node cka003. internalTrafficPolicy is effective.
     curl <service_cluster_ip>:80   # succeed on all nodes.
     curl <node_ip>:<ext_port>      # succeed on all nodes.
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/statefulset/index.html b/k8s/cka_en/foundamentals/statefulset/index.html index ddec1995..c2dbff24 100644 --- a/k8s/cka_en/foundamentals/statefulset/index.html +++ b/k8s/cka_en/foundamentals/statefulset/index.html @@ -1,4 +1,4 @@ - StatefulSet - UPSkilling

    StatefulSet

    Scenario:

    • Create Headless Service nginx and StatefulSet web
    • Scale out StatefulSet web

    Demo:

    Create Headless Service nginx and StatefulSet web.

    kubectl apply -f - << EOF
    + StatefulSet - UPSkilling       

    StatefulSet

    Scenario:

    • Create Headless Service nginx and StatefulSet web
    • Scale out StatefulSet web

    Demo:

    Create Headless Service nginx and StatefulSet web.

    kubectl apply -f - << EOF
     ---
     apiVersion: v1
     kind: Service
    @@ -43,4 +43,4 @@
     

    Use command kubectl edit sts web to update an existing StatefulSet. ONLY these fields can be updated: replicasimagerolling updateslabelsresource request/limit and annotations.

    Note: When StatefulSet Pod is dead in current node, no copies will be created in other node automatically.

    Scale out StatefulSet.

    Scale StatefulSet web to 5 Replicas.

    kubectl scale sts web --replicas=5
     

    Info

    • Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched.
    • This is helpful in being able to do a canary based deployment.
    • The default value is 0.
    • Command: kubectl explain statefulsets.spec.updateStrategy.rollingUpdate.partition

    Clean up.

    kubectl delete sts web
     kubectl delete service nginx
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/foundamentals/troubleshooting/index.html b/k8s/cka_en/foundamentals/troubleshooting/index.html index 22c0e35a..143f6887 100644 --- a/k8s/cka_en/foundamentals/troubleshooting/index.html +++ b/k8s/cka_en/foundamentals/troubleshooting/index.html @@ -1,4 +1,4 @@ - Troubleshooting - UPSkilling

    Troubleshooting

    Event

    Scenario

    • Describe pod to get event information.

    Demo:

    Usage:

    kubectl describe <resource_type> <resource_name> --namespace=<namespace_name>
    + Troubleshooting - UPSkilling       

    Troubleshooting

    Event

    Scenario

    • Describe pod to get event information.

    Demo:

    Usage:

    kubectl describe <resource_type> <resource_name> --namespace=<namespace_name>
     

    Get event information of a Pod

    Create a Tomcat Pod.

    kubectl run tomcat --image=tomcat
     

    Check event of above deplyment.

    kubectl describe pod/tomcat
     

    Get below event information.

    Events:
    @@ -26,7 +26,7 @@
     Taints:             <none>
     Taints:             <none>
     

    Option 2:

    kubectl describe node | grep -i taint |grep -vc NoSchedule
    -

    We will get same result 2. Here -v means exclude, -c count numbers.

    Node NotReady

    Scenario: When we stop kubelet service on worker node cka002,

    • What's the status of each node?
    • What's containers changed via command nerdctl?
    • What's pods status via command kubectl get pod -owide -A?

    Demo:

    Execute command systemctl stop kubelet.service on cka002.

    Execute command kubectl get node on either cka001 or cka003, the status of cka002 is NotReady.

    Execute command nerdctl -n k8s.io container ls on cka002 and we can observe all containers are still up and running, including the pod my-first-pod.

    Execute command systemctl start kubelet.service on cka002.

    Conclusion:

    • The node status is changed to NotReady from Ready.
    • For those DaemonSet pods, like calicokube-proxy, are exclusively running on each node. They won't be terminated after kubelet is down.
    • The status of pod my-first-pod keeps showing Terminating on each node because status can not be synced to other nodes via apiserver from cka002 because kubelet is down.
    • The status of pod is marked by controller and recycled by kubelet.
    • When we start kubelet service on cka003, the pod my-first-pod will be termiated completely on cka002.

    In addition, let's create a deployment with 3 replicas. Two are running on cka003 and one is running on cka002.

    root@cka001:~# kubectl get pod -o wide -w
    +

    We will get same result 2. Here -v means exclude, -c count numbers.

    Node NotReady

    Scenario: When we stop kubelet service on worker node cka002,

    • What's the status of each node?
    • What's containers changed via command nerdctl?
    • What's pods status via command kubectl get pod -owide -A?

    Demo:

    Execute command systemctl stop kubelet.service on cka002.

    Execute command kubectl get node on either cka001 or cka003, the status of cka002 is NotReady.

    Execute command nerdctl -n k8s.io container ls on cka002 and we can observe all containers are still up and running, including the pod my-first-pod.

    Execute command systemctl start kubelet.service on cka002.

    Conclusion:

    • The node status is changed to NotReady from Ready.
    • For those DaemonSet pods, like calicokube-proxy, are exclusively running on each node. They won't be terminated after kubelet is down.
    • The status of pod my-first-pod keeps showing Terminating on each node because status can not be synced to other nodes via apiserver from cka002 because kubelet is down.
    • The status of pod is marked by controller and recycled by kubelet.
    • When we start kubelet service on cka003, the pod my-first-pod will be termiated completely on cka002.

    In addition, let's create a deployment with 3 replicas. Two are running on cka003 and one is running on cka002.

    root@cka001:~# kubectl get pod -o wide -w
     NAME                               READY   STATUS    RESTARTS   AGE    IP           NODE     NOMINATED NODE   READINESS GATES
     nginx-deployment-9d745469b-2xdk4   1/1     Running   0          2m8s   10.244.2.3   cka003   <none>           <none>
     nginx-deployment-9d745469b-4gvmr   1/1     Running   0          2m8s   10.244.2.4   cka003   <none>           <none>
    @@ -37,7 +37,7 @@
     cka002   62m          3%     2151Mi          56%
     cka003   63m          3%     1825Mi          47%
     

    Get Pod monitoring information

    kubectl top pod
    -

    Output:

    root@cka001:~# kubectl top pod
    +

    Output:

    root@cka001:~# kubectl top pod
     NAME                                      CPU(cores)   MEMORY(bytes)   
     busybox-with-secret                       0m           0Mi
     mysql                                     2m           366Mi
    @@ -98,4 +98,4 @@
     

    Check pod status again.

    kubectl get pod -o wide
     

    The pod is running on cka002 now.

    NAME                                      READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
     nfs-client-provisioner-86d7fb78b6-k8xnl   1/1     Running   0          2m20s   10.244.112.4   cka002   <none>           <none>
    -

    Note

    • cordon is included in drain, no need additional step to cordon node before drain node.
    \ No newline at end of file +

    Note

    • cordon is included in drain, no need additional step to cordon node before drain node.
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/installation/aliyun-ubuntu/index.html b/k8s/cka_en/installation/aliyun-ubuntu/index.html index 1b24bbc4..48828e34 100644 --- a/k8s/cka_en/installation/aliyun-ubuntu/index.html +++ b/k8s/cka_en/installation/aliyun-ubuntu/index.html @@ -1,45 +1,45 @@ - Installation on Aliyun ECS - UPSkilling

    Installation on Aliyun Ubuntu

    Preparation

    Register Aliyun account via Alibaba Cloud home console.

    Request three Elastic Computer Service(ECS) instances with below sizing:

    • System: 2vCPU+4GiB
    • OS: Ubuntu 20.04 x86_64
    • Instance Type: ecs.sn1.medium
    • Instance Name: cka001, cka002, cka003
    • Network: both public IPs and private IPs
    • Maximum Bandwidth: 100Mbps (Peak Value)
    • Cloud disk: 40GiB
    • Billing Method: Preemptible instance (spot price)

    Open a local terminal, log onto remote ECS cka001 using the key pair (e.g., aliyun-root) from Aliyun cloud.

    ssh -i aliyun-root root@cka001
    -

    Create a common user (e.g., james), and set primary group as sudo and other group as root.

    adduser james
    -usermod -g sudo james
    -usermod -a -G root james
    + Installation on Aliyun ECS - UPSkilling       

    Installation on Aliyun Ubuntu

    Preparation

    Register Aliyun account via Alibaba Cloud home console.

    Request three Elastic Computer Service(ECS) instances with below sizing:

    • System: 2vCPU+4GiB
    • OS: Ubuntu 20.04 x86_64
    • Instance Type: ecs.sn1.medium
    • Instance Name: cka001, cka002, cka003
    • Network: both public IPs and private IPs
    • Maximum Bandwidth: 100Mbps (Peak Value)
    • Cloud disk: 40GiB
    • Billing Method: Preemptible instance (spot price)

    Open a local terminal, log onto remote ECS cka001 using the key pair (e.g., aliyun-root) from Aliyun cloud.

    ssh -i aliyun-root root@cka001
    +

    Create a common user (e.g., james), and set primary group as sudo and other group as root.

    adduser james
    +usermod -g sudo james
    +usermod -a -G root james
     

    Back to the local terminal, generate key for common user james by below command.

    # Windows
     ssh-keygen.exe
     
     # Linux
     ssh-keygen
    -

    Two files will be created, e.g., aliyun-james and aliyun-james.pub

    Upload the public key aliyun-james.pub to remote cka001 using sftp command.

    sftp -i aliyun-root root@cka001
    -put aliyun-james.pub
    -

    Log onto remote ECS cka001 using root account again. Move the key aliyun-james.pub to /home/james/.ssh/. Rename file aliyun-james.pub to authorized_keys. Change ower of file authorized_keys to james. Change default group of file authorized_keys to sudo.

    mkdir /home/james/.ssh/
    -mv aliyun-james.pub /home/james/.ssh/authorized_keys
    -chown james.sudo /home/james/.ssh/authorized_keys
    -chmod 600 /home/james/.ssh/authorized_keys
    -

    Check file /etc/ssh/sshd_config, make sure password authentication is disabled PasswordAuthentication no

    cat /etc/ssh/sshd_config
    -

    Back to the local terminal, use james to log onto remote cka001.

    ssh -i aliyun-james james@cka001
    -

    Upload the public key aliyun-james.pub to remote cka002 and cka003 using sftp command and do the same set up on cka002 and cka003 in order to enable user james to log onto cka002 and cka003.

    Till now, user james can log onto cka001, cka002 and cka003 using key aliyun-james.

    All demo below will be done by user james.

    Initialize VMs

    Configure /etc/hosts file

    Add private IPs in the /etc/hosts file in all VMs.

    vi /etc/hosts
    -

    Disable firewall

    Disable firewall by command ufw disable in all VMs.

    Disable swap on Ubuntu.

    sudo ufw disable
    -

    Check status of swap on Ubuntu.

    sudo ufw status verbose
    -

    Turn off swap

    Turn off swap in all VMs.

    sudo swapoff -a
    -

    Set timezone and locale

    Set timezone and local for all VMs. This step was already done during Aliyun ECS installation.

    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    -sudo echo 'LANG="en_US.UTF-8"' >> /etc/profile
    -source /etc/profile
    -

    Something like this:

    ll /etc/localtime
    -
    lrwxrwxrwx 1 root root 33 Jul  5 14:51 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
    -

    Kernel setting

    Perform below kernel setting in all VMs.

    Create file /etc/modules-load.d/containerd.conf to set up containerd configure file. It's to load two modules overlay and br_netfilter.

    Service containerd depends on overlay filesystem. Sometimes referred to as union-filesystems. An overlay-filesystem tries to present a filesystem which is the result over overlaying one filesystem on top of the other.

    The br_netfilter module is required to enable transparent masquerading and to facilitate Virtual Extensible LAN (VxLAN) traffic for communication between Kubernetes pods across the cluster.

    cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
    +

    Two files will be created, e.g., aliyun-james and aliyun-james.pub

    Upload the public key aliyun-james.pub to remote cka001 using sftp command.

    sftp -i aliyun-root root@cka001
    +put aliyun-james.pub
    +

    Log onto remote ECS cka001 using root account again. Move the key aliyun-james.pub to /home/james/.ssh/. Rename file aliyun-james.pub to authorized_keys. Change ower of file authorized_keys to james. Change default group of file authorized_keys to sudo.

    mkdir /home/james/.ssh/
    +mv aliyun-james.pub /home/james/.ssh/authorized_keys
    +chown james.sudo /home/james/.ssh/authorized_keys
    +chmod 600 /home/james/.ssh/authorized_keys
    +

    Check file /etc/ssh/sshd_config, make sure password authentication is disabled PasswordAuthentication no

    cat /etc/ssh/sshd_config
    +

    Back to the local terminal, use james to log onto remote cka001.

    ssh -i aliyun-james james@cka001
    +

    Upload the public key aliyun-james.pub to remote cka002 and cka003 using sftp command and do the same set up on cka002 and cka003 in order to enable user james to log onto cka002 and cka003.

    Till now, user james can log onto cka001, cka002 and cka003 using key aliyun-james.

    All demo below will be done by user james.

    Initialize VMs

    Configure /etc/hosts file

    Add private IPs in the /etc/hosts file in all VMs.

    vi /etc/hosts
    +

    Disable firewall

    Disable firewall by command ufw disable in all VMs.

    Disable swap on Ubuntu.

    sudo ufw disable
    +

    Check status of swap on Ubuntu.

    sudo ufw status verbose
    +

    Turn off swap

    Turn off swap in all VMs.

    sudo swapoff -a
    +

    Set timezone and locale

    Set timezone and local for all VMs. This step was already done during Aliyun ECS installation.

    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    +sudo echo 'LANG="en_US.UTF-8"' >> /etc/profile
    +source /etc/profile
    +

    Something like this:

    ll /etc/localtime
    +
    lrwxrwxrwx 1 root root 33 Jul  5 14:51 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
    +

    Kernel setting

    Perform below kernel setting in all VMs.

    Create file /etc/modules-load.d/containerd.conf to set up containerd configure file. It's to load two modules overlay and br_netfilter.

    Service containerd depends on overlay filesystem. Sometimes referred to as union-filesystems. An overlay-filesystem tries to present a filesystem which is the result over overlaying one filesystem on top of the other.

    The br_netfilter module is required to enable transparent masquerading and to facilitate Virtual Extensible LAN (VxLAN) traffic for communication between Kubernetes pods across the cluster.

    cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
     overlay
     br_netfilter
     EOF
    -

    Load overlay and br_netfilter modules.

    sudo modprobe overlay
    -sudo modprobe br_netfilter
    -

    Verify

    lsmod | grep br_netfilter
    -

    Create file 99-kubernetes-cri.conf to set up configure file for Kubernetes CRI.

    Set net/bridge/bridge-nf-call-iptables=1 to ensure simple configurations (like Docker with a bridge) work correctly with the iptables proxy. Why net/bridge/bridge-nf-call-iptables=1 need to be enable by Kubernetes.

    IP forwarding is also known as routing. When it comes to Linux, it may also be called Kernel IP forwarding because it uses the kernel variable net.ipv4.ip_forward to enable or disable the IP forwarding feature. The default preset value is ip_forward=0. Hence, the Linux IP forwarding feature is disabled by default.

    cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
    +

    Load overlay and br_netfilter modules.

    sudo modprobe overlay
    +sudo modprobe br_netfilter
    +

    Verify

    lsmod | grep br_netfilter
    +

    Create file 99-kubernetes-cri.conf to set up configure file for Kubernetes CRI.

    Set net/bridge/bridge-nf-call-iptables=1 to ensure simple configurations (like Docker with a bridge) work correctly with the iptables proxy. Why net/bridge/bridge-nf-call-iptables=1 need to be enable by Kubernetes.

    IP forwarding is also known as routing. When it comes to Linux, it may also be called Kernel IP forwarding because it uses the kernel variable net.ipv4.ip_forward to enable or disable the IP forwarding feature. The default preset value is ip_forward=0. Hence, the Linux IP forwarding feature is disabled by default.

    cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
     net.bridge.bridge-nf-call-iptables  = 1
     net.ipv4.ip_forward                 = 1
     net.bridge.bridge-nf-call-ip6tables = 1
     EOF
    -

    The sysctl command reads the information from the /proc/sys directory. /proc/sys is a virtual directory that contains file objects that can be used to view and set the current kernel parameters.

    By commadn sysctl -w net.ipv4.ip_forward=1, the change takes effect immediately, but it is not persistent. After a system reboot, the default value is loaded. Write the settings to /etc/sysctl.conf is to set a parameter permanently, you’ll need to or another configuration file in the /etc/sysctl.d directory:

    sudo sysctl --system
    -

    Verify.

    sysctl net.ipv4.ip_forward
    -

    Install Containerd

    Install Containerd sevice for all VMs.

    Backup source file.

    sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
    -

    Add proper repo sources. For ECS with Ubuntu 20.04 version created by Aliyun, this step is not needed.

    cat > /etc/apt/sources.list << EOF
    +

    The sysctl command reads the information from the /proc/sys directory. /proc/sys is a virtual directory that contains file objects that can be used to view and set the current kernel parameters.

    By commadn sysctl -w net.ipv4.ip_forward=1, the change takes effect immediately, but it is not persistent. After a system reboot, the default value is loaded. Write the settings to /etc/sysctl.conf is to set a parameter permanently, you’ll need to or another configuration file in the /etc/sysctl.d directory:

    sudo sysctl --system
    +

    Verify.

    sysctl net.ipv4.ip_forward
    +

    Install Containerd

    Install Containerd sevice for all VMs.

    Backup source file.

    sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
    +

    Add proper repo sources. For ECS with Ubuntu 20.04 version created by Aliyun, this step is not needed.

    cat > /etc/apt/sources.list << EOF
     deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted
     deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted
     deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted
    @@ -61,10 +61,10 @@
     # deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse
     # deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse
     EOF
    -

    Install Containered.

    sudo apt-get update && sudo apt-get install -y containerd
    -

    Configure Containerd. Modify file /etc/containerd/config.toml.

    sudo mkdir -p /etc/containerd
    -containerd config default | sudo tee /etc/containerd/config.toml
    -sudo vi /etc/containerd/config.toml
    +

    Install Containered.

    sudo apt-get update && sudo apt-get install -y containerd
    +

    Configure Containerd. Modify file /etc/containerd/config.toml.

    sudo mkdir -p /etc/containerd
    +containerd config default | sudo tee /etc/containerd/config.toml
    +sudo vi /etc/containerd/config.toml
     

    Update sandbox_image with new value "registry.aliyuncs.com/google_containers/pause:3.6". Update SystemdCgroup with new value true.

    [plugins]
       [plugins."io.containerd.gc.v1.scheduler"]
     
    @@ -80,115 +80,115 @@
     
               [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
                 SystemdCgroup = true
    -

    Restart Containerd service.

    sudo systemctl restart containerd
    -sudo systemctl status containerd
    -

    Install nerdctl

    Install nerdctl sevice fro all VMs.

    The goal of nerdctl is to facilitate experimenting the cutting-edge features of containerd that are not present in Docker.

    Get the release from the link https://github.com/containerd/nerdctl/releases.

    wget https://github.com/containerd/nerdctl/releases/download/v0.22.0/nerdctl-0.22.0-linux-amd64.tar.gz
    -tar -zxvf nerdctl-0.22.0-linux-amd64.tar.gz
    -sudo cp nerdctl /usr/bin/
    -sudo cp containerd-rootless* /usr/bin/
    -

    Verify nerdctl.

    nerdctl --help
    -

    To list local Kubernetes containers.

    nerdctl -n k8s.io ps
    -

    Install kubeadm

    Update apt-transport-https, ca-certificates, and curl.

    sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl
    -

    Install gpg certificate.

    sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg
    -

    Add Kubernetes repo. Just choose one of below command and execute.

    echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ \
    -  kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
    -

    Update and install dependencied packages.

    sudo apt-get update
    -sudo apt-get install ebtables
    -sudo apt-get install libxtables12
    -sudo apt-get upgrade iptables
    -

    Check available versions of kubeadm.

    apt policy kubeadm
    -

    Install 1.24.0-00 version of kubeadm and will upgrade to 1.24.2 later.

    sudo apt-get -y install kubelet=1.24.0-00 kubeadm=1.24.0-00 kubectl=1.24.0-00 --allow-downgrades
    -

    Setup Master Node

    kubeadm init

    Set up Control Plane on VM playing master node.

    Check kubeadm default parameters for initialization.

    kubeadm config print init-defaults
    -

    Reuslt:

    apiVersion: kubeadm.k8s.io/v1beta3
    -bootstrapTokens:
    -- groups:
    -  - system:bootstrappers:kubeadm:default-node-token
    -  token: abcdef.0123456789abcdef
    -  ttl: 24h0m0s
    -  usages:
    -  - signing
    -  - authentication
    -kind: InitConfiguration
    -localAPIEndpoint:
    -  advertiseAddress: 1.2.3.4
    -  bindPort: 6443
    -nodeRegistration:
    -  criSocket: unix:///var/run/containerd/containerd.sock
    -  imagePullPolicy: IfNotPresent
    -  name: node
    -  taints: null
    ----
    -apiServer:
    -  timeoutForControlPlane: 4m0s
    -apiVersion: kubeadm.k8s.io/v1beta3
    -certificatesDir: /etc/kubernetes/pki
    -clusterName: kubernetes
    -controllerManager: {}
    -dns: {}
    -etcd:
    -  local:
    -    dataDir: /var/lib/etcd
    -imageRepository: k8s.gcr.io
    -kind: ClusterConfiguration
    -kubernetesVersion: 1.24.0
    -networking:
    -  dnsDomain: cluster.local
    -  serviceSubnet: 10.96.0.0/12
    -scheduler: {}
    -

    Dry rune and run. Save the output, which will be used later on work nodes.

    With kubeadm init to initiate cluster, we need understand below three options about network.

    • --pod-network-cidr:
    • Specify range of IP addresses for the pod network. If set, the control plane will automatically allocate CIDRs for every node.
    • Be noted that 10.244.0.0/16 is default range of flannel. If it's changed here, please do change the same when deploy Flannel.
    • --apiserver-bind-port:
    • Port for the API Server to bind to. (default 6443)
    • --service-cidr:
    • Use alternative range of IP address for service VIPs. (default "10.96.0.0/12")

    Note:

    • service VIPs (a.k.a. Cluster IP), specified by option --service-cidr.
    • podCIDR (a.k.a. endpoint IP),specified by option --pod-network-cidr.

    There are 4 distinct networking problems to address:

    • Highly-coupled container-to-container communications: this is solved by Pods (podCIDR) and localhost communications.
    • Pod-to-Pod communications:
    • a.k.a. container-to-container.
    • Example with Flannel, the flow is: Pod → veth pair → cni0 → flannel.1 → host eth0 → host eth0 → flannel.1 → cni0 → veth pair → Pod.
    • Pod-to-Service communications:
    • Flow: Pod → Kernel → Servive iptables → service → Pod iptables → Pod
    • External-to-Service communications:
    • LoadBalancer: SLB → NodePort → Service → Pod

    kube-proxy is responsible for iptables, not traffic.

    sudo kubeadm init \
    -  --dry-run \
    -  --pod-network-cidr=10.244.0.0/16 \
    -  --service-cidr 11.244.0.0/16 \
    -  --image-repository=registry.aliyuncs.com/google_containers \
    -  --kubernetes-version=v1.24.0
    +

    Restart Containerd service.

    sudo systemctl restart containerd
    +sudo systemctl status containerd
    +

    Install nerdctl

    Install nerdctl sevice fro all VMs.

    The goal of nerdctl is to facilitate experimenting the cutting-edge features of containerd that are not present in Docker.

    Get the release from the link https://github.com/containerd/nerdctl/releases.

    wget https://github.com/containerd/nerdctl/releases/download/v0.22.0/nerdctl-0.22.0-linux-amd64.tar.gz
    +tar -zxvf nerdctl-0.22.0-linux-amd64.tar.gz
    +sudo cp nerdctl /usr/bin/
    +sudo cp containerd-rootless* /usr/bin/
    +

    Verify nerdctl.

    nerdctl --help
    +

    To list local Kubernetes containers.

    nerdctl -n k8s.io ps
    +

    Install kubeadm

    Update apt-transport-https, ca-certificates, and curl.

    sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl
    +

    Install gpg certificate.

    sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg
    +

    Add Kubernetes repo. Just choose one of below command and execute.

    echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ \
    +  kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
    +

    Update and install dependencied packages.

    sudo apt-get update
    +sudo apt-get install ebtables
    +sudo apt-get install libxtables12
    +sudo apt-get upgrade iptables
    +

    Check available versions of kubeadm.

    apt policy kubeadm
    +

    Install 1.24.0-00 version of kubeadm and will upgrade to 1.24.2 later.

    sudo apt-get -y install kubelet=1.24.0-00 kubeadm=1.24.0-00 kubectl=1.24.0-00 --allow-downgrades
    +

    Setup Master Node

    kubeadm init

    Set up Control Plane on VM playing master node.

    Check kubeadm default parameters for initialization.

    kubeadm config print init-defaults
    +

    Reuslt:

    apiVersion: kubeadm.k8s.io/v1beta3
    +bootstrapTokens:
    +- groups:
    +  - system:bootstrappers:kubeadm:default-node-token
    +  token: abcdef.0123456789abcdef
    +  ttl: 24h0m0s
    +  usages:
    +  - signing
    +  - authentication
    +kind: InitConfiguration
    +localAPIEndpoint:
    +  advertiseAddress: 1.2.3.4
    +  bindPort: 6443
    +nodeRegistration:
    +  criSocket: unix:///var/run/containerd/containerd.sock
    +  imagePullPolicy: IfNotPresent
    +  name: node
    +  taints: null
    +---
    +apiServer:
    +  timeoutForControlPlane: 4m0s
    +apiVersion: kubeadm.k8s.io/v1beta3
    +certificatesDir: /etc/kubernetes/pki
    +clusterName: kubernetes
    +controllerManager: {}
    +dns: {}
    +etcd:
    +  local:
    +    dataDir: /var/lib/etcd
    +imageRepository: k8s.gcr.io
    +kind: ClusterConfiguration
    +kubernetesVersion: 1.24.0
    +networking:
    +  dnsDomain: cluster.local
    +  serviceSubnet: 10.96.0.0/12
    +scheduler: {}
    +

    Dry rune and run. Save the output, which will be used later on work nodes.

    With kubeadm init to initiate cluster, we need understand below three options about network.

    • --pod-network-cidr:
    • Specify range of IP addresses for the pod network. If set, the control plane will automatically allocate CIDRs for every node.
    • Be noted that 10.244.0.0/16 is default range of flannel. If it's changed here, please do change the same when deploy Flannel.
    • --apiserver-bind-port:
    • Port for the API Server to bind to. (default 6443)
    • --service-cidr:
    • Use alternative range of IP address for service VIPs. (default "10.96.0.0/12")

    Note:

    • service VIPs (a.k.a. Cluster IP), specified by option --service-cidr.
    • podCIDR (a.k.a. endpoint IP),specified by option --pod-network-cidr.

    There are 4 distinct networking problems to address:

    • Highly-coupled container-to-container communications: this is solved by Pods (podCIDR) and localhost communications.
    • Pod-to-Pod communications:
    • a.k.a. container-to-container.
    • Example with Flannel, the flow is: Pod → veth pair → cni0 → flannel.1 → host eth0 → host eth0 → flannel.1 → cni0 → veth pair → Pod.
    • Pod-to-Service communications:
    • Flow: Pod → Kernel → Servive iptables → service → Pod iptables → Pod
    • External-to-Service communications:
    • LoadBalancer: SLB → NodePort → Service → Pod

    kube-proxy is responsible for iptables, not traffic.

    sudo kubeadm init \
    +  --dry-run \
    +  --pod-network-cidr=10.244.0.0/16 \
    +  --service-cidr 11.244.0.0/16 \
    +  --image-repository=registry.aliyuncs.com/google_containers \
    +  --kubernetes-version=v1.24.0
     
    -sudo kubeadm init \
    -  --pod-network-cidr=10.244.0.0/16 \
    -  --service-cidr 11.244.0.0/16 \
    -  --image-repository=registry.aliyuncs.com/google_containers \
    -  --kubernetes-version=v1.24.0
    +sudo kubeadm init \
    +  --pod-network-cidr=10.244.0.0/16 \
    +  --service-cidr 11.244.0.0/16 \
    +  --image-repository=registry.aliyuncs.com/google_containers \
    +  --kubernetes-version=v1.24.0
     
    -sudo kubeadm init \
    -  --pod-network-cidr=10.244.0.0/16 \
    -  --service-cidr 11.244.0.0/16 \
    -  --kubernetes-version=v1.24.0
    -

    kubeconfig file

    Set kubeconfig file for current user (here it's james).

    mkdir -p $HOME/.kube
    -sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    -sudo chown $(id -u):$(id -g) $HOME/.kube/config
    -

    Kubernetes provides a command line tool kubectl for communicating with a Kubernetes cluster's control plane, using the Kubernetes API.

    kubectl controls the Kubernetes cluster manager.

    For configuration, kubectl looks for a file named config in the $HOME/.kube directory, which is a copy of file /etc/kubernetes/admin.conf generated by kubeadm init.

    We can specify other kubeconfig files by setting the KUBECONFIG environment variable or by setting the --kubeconfig flag. If the KUBECONFIG environment variable doesn't exist, kubectl uses the default kubeconfig file, $HOME/.kube/config.

    A context element in a kubeconfig file is used to group access parameters under a convenient name. Each context has three parameters: cluster, namespace, and user. By default, the kubectl command-line tool uses parameters from the current context to communicate with the cluster.

    A sample of .kube/config.

    apiVersion: v1
    -clusters:
    -- cluster:
    -    certificate-authority-data: <certificate string>
    -    server: https://<eth0 ip>:6443
    -  name: <cluster name>
    -contexts:
    -- context:
    -    cluster: <cluster name>
    -    namespace: <namespace name>
    -    user: <user name>
    -  name: <context user>@<context name>
    -current-context: <context name>
    -kind: Config
    -preferences: {}
    -users:
    -- name: <user name>
    -  user:
    -    client-certificate-data: <certificate string>
    -    client-key-data: <certificate string>
    -

    To get the current context:

    kubectl config get-contexts
    -

    Result

    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
    -*         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   
    +sudo kubeadm init \
    +  --pod-network-cidr=10.244.0.0/16 \
    +  --service-cidr 11.244.0.0/16 \
    +  --kubernetes-version=v1.24.0
    +

    kubeconfig file

    Set kubeconfig file for current user (here it's james).

    mkdir -p $HOME/.kube
    +sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    +sudo chown $(id -u):$(id -g) $HOME/.kube/config
    +

    Kubernetes provides a command line tool kubectl for communicating with a Kubernetes cluster's control plane, using the Kubernetes API.

    kubectl controls the Kubernetes cluster manager.

    For configuration, kubectl looks for a file named config in the $HOME/.kube directory, which is a copy of file /etc/kubernetes/admin.conf generated by kubeadm init.

    We can specify other kubeconfig files by setting the KUBECONFIG environment variable or by setting the --kubeconfig flag. If the KUBECONFIG environment variable doesn't exist, kubectl uses the default kubeconfig file, $HOME/.kube/config.

    A context element in a kubeconfig file is used to group access parameters under a convenient name. Each context has three parameters: cluster, namespace, and user. By default, the kubectl command-line tool uses parameters from the current context to communicate with the cluster.

    A sample of .kube/config.

    apiVersion: v1
    +clusters:
    +- cluster:
    +    certificate-authority-data: <certificate string>
    +    server: https://<eth0 ip>:6443
    +  name: <cluster name>
    +contexts:
    +- context:
    +    cluster: <cluster name>
    +    namespace: <namespace name>
    +    user: <user name>
    +  name: <context user>@<context name>
    +current-context: <context name>
    +kind: Config
    +preferences: {}
    +users:
    +- name: <user name>
    +  user:
    +    client-certificate-data: <certificate string>
    +    client-key-data: <certificate string>
    +

    To get the current context:

    kubectl config get-contexts
    +

    Result

    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
    +*         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   
     

    Setup Work Nodes

    Perform on all VMs playing work nodes.

    # kubeadm join <your master node eth0 ip>:6443 --token <token generated by kubeadm init> --discovery-token-ca-cert-hash <hash key generated by kubeadm init>
    -

    Use kubeadm token to generate the join token and hash value.

    kubeadm token create --print-join-command
    -

    Execute the command generated above on each node that we want to join the cluster as Worker node.

    Verify status on master node. All nodes' status is NotReady. Leave it at the moment and continue to install network plugin.

    kubectl get node -o wide
    -

    Install Calico or Flannel

    Choose Calico or Flannel on control plane node.

    For NetworkPolicy purpose, choose Calico.

    Install Flannel

    Flannel is a simple and easy way to configure a layer 3 network fabric designed for Kubernetes.

    Deploy Flannel.

    In the kube-flannel.yml we can get the default network setting of Flannel, which is same with --pod-network-cidr=10.244.0.0/16 we defined before when we initiated kubeadm.

      net-conf.json: |
    -    {
    -      "Network": "10.244.0.0/16",
    -      "Backend": {
    -        "Type": "vxlan"
    -      }
    -    }
    -

    Create Flannel

    apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    +

    Use kubeadm token to generate the join token and hash value.

    kubeadm token create --print-join-command
    +

    Execute the command generated above on each node that we want to join the cluster as Worker node.

    Verify status on master node. All nodes' status is NotReady. Leave it at the moment and continue to install network plugin.

    kubectl get node -o wide
    +

    Install Calico or Flannel

    Choose Calico or Flannel on control plane node.

    For NetworkPolicy purpose, choose Calico.

    Install Flannel

    Flannel is a simple and easy way to configure a layer 3 network fabric designed for Kubernetes.

    Deploy Flannel.

    In the kube-flannel.yml we can get the default network setting of Flannel, which is same with --pod-network-cidr=10.244.0.0/16 we defined before when we initiated kubeadm.

      net-conf.json: |
    +    {
    +      "Network": "10.244.0.0/16",
    +      "Backend": {
    +        "Type": "vxlan"
    +      }
    +    }
    +

    Create Flannel

    apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
     

    Result

    Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
     podsecuritypolicy.policy/psp.flannel.unprivileged created
     clusterrole.rbac.authorization.k8s.io/flannel created
    @@ -196,8 +196,8 @@
     serviceaccount/flannel created
     configmap/kube-flannel-cfg created
     daemonset.apps/kube-flannel-ds created
    -

    Install Calico

    Here is guidance of End-to-end Calico installation. Detail practice demo, can be found in section "Install Calico" of "A1.Discussion" below.

    Install Calico

    curl https://docs.projectcalico.org/manifests/calico.yaml -O
    -kubectl apply -f calico.yaml
    +

    Install Calico

    Here is guidance of End-to-end Calico installation. Detail practice demo, can be found in section "Install Calico" of "A1.Discussion" below.

    Install Calico

    curl https://docs.projectcalico.org/manifests/calico.yaml -O
    +kubectl apply -f calico.yaml
     

    Result

    configmap/calico-config created
     customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
     customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
    @@ -225,24 +225,24 @@
     deployment.apps/calico-kube-controllers created
     serviceaccount/calico-kube-controllers created
     poddisruptionbudget.policy/calico-kube-controllers created
    -

    Verify status of Calico.

    kubectl get pod -n kube-system | grep calico
    +

    Verify status of Calico.

    kubectl get pod -n kube-system | grep calico
     

    Result

    calico-kube-controllers-555bc4b957-l8bn2   0/1     Pending    0          28s
     calico-node-255pc                          0/1     Init:1/3   0          29s
     calico-node-7tmnb                          0/1     Init:1/3   0          29s
     calico-node-w8nvl                          0/1     Init:1/3   0          29s
    -

    Verify network status.

    sudo nerdctl network ls
    +

    Verify network status.

    sudo nerdctl network ls
     

    Result

    NETWORK ID    NAME               FILE
                   k8s-pod-network    /etc/cni/net.d/10-calico.conflist
     0             bridge             /etc/cni/net.d/nerdctl-bridge.conflist
                   host               
                   none 
    -

    Check Cluster Status

    Perform kubectl cluster-info command on master node we will get below information.

    • Kubernetes control plane is running at https://<mster node ip>:6443
    • CoreDNS is running at https://<mster node ip>:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    kubectl cluster-info
    -

    Get nodes status.

    kubectl get nodes -owide
    +

    Check Cluster Status

    Perform kubectl cluster-info command on master node we will get below information.

    • Kubernetes control plane is running at https://<mster node ip>:6443
    • CoreDNS is running at https://<mster node ip>:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    kubectl cluster-info
    +

    Get nodes status.

    kubectl get nodes -owide
     

    All nodes are up with normal status.

    • OS Image: Ubuntu 20.04.4 LTS
    • Kernel Version: 5.4.0-122-generic
    • Container Runtime: containerd://1.5.9
    NAME     STATUS   ROLES           AGE     VERSION
     cka001   Ready    control-plane   13m     v1.24.0
     cka002   Ready    <none>          8m35s   v1.24.0
     cka003   Ready    <none>          8m26s   v1.24.0
    -

    Get pods status

    kubectl get pod -A
    +

    Get pods status

    kubectl get pod -A
     

    Result:

    NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
     kube-system   calico-kube-controllers-555bc4b957-l8bn2   1/1     Running   0          7m18s
     kube-system   calico-node-255pc                          1/1     Running   0          7m19s
    @@ -257,7 +257,7 @@
     kube-system   kube-proxy-n77zw                           1/1     Running   0          11m
     kube-system   kube-proxy-qs6rf                           1/1     Running   0          11m
     kube-system   kube-scheduler-cka001                      1/1     Running   0          15m
    -

    Reset cluster

    CAUTION: below steps will destroy current cluster.

    Delete all nodes in the cluster.

    kubeadm reset
    +

    Reset cluster

    CAUTION: below steps will destroy current cluster.

    Delete all nodes in the cluster.

    kubeadm reset
     

    Output:

    [reset] Reading configuration from the cluster...
     [reset] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
     W0717 08:15:17.411992 3913615 preflight.go:55] [reset] WARNING: Changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted.
    @@ -279,31 +279,31 @@
     
     The reset process does not clean your kubeconfig files and you must remove them manually.
     Please, check the contents of the $HOME/.kube/config file.
    -

    Clean up network setting

    rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni
    -

    Clean up rule of iptables.

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    -

    Clean up rule of IPVS if using IPVS.

    ipvsadm --clear
    -

    Troubleshooting

    Issue 1

    The connection to the server <master>:6443 was refused - did you specify the right host or port?

    Try:

    Reference

    Check if the kubeconfig file is update to udpate and exists in right place.

    Check environment setting.

    env | grep -i kub
    -

    Check container status.

    sudo systemctl status containerd.service 
    -

    Check kubelet service.

    sudo systemctl status kubelet.service 
    -

    Check port listening status.

    netstat -pnlt | grep 6443
    -

    Check firewall status.

    sudo systemctl status firewalld.service
    -

    Check log.

    journalctl -xeu kubelet
    -

    Issue 2

    "Container runtime network not ready" networkReady="NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized"

    Try:

    Restart Containerd service.

    sudo systemctl restart containerd
    -sudo systemctl status containerd
    -

    Post Installation

    Bash Autocomplete

    On each node.

    Set kubectl auto-completion following the guideline.

    apt install -y bash-completion
    -source /usr/share/bash-completion/bash_completion
    -source <(kubectl completion bash)
    -echo "source <(kubectl completion bash)" >> ~/.bashrc
    -

    Alias

    If we set an alias for kubectl, we can extend shell completion to work with that alias:

    echo 'alias k=kubectl' >>~/.bashrc
    -echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
    -

    Update Default Context

    Get current context.

    kubectl config get-contexts 
    +

    Clean up network setting

    rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni
    +

    Clean up rule of iptables.

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    +

    Clean up rule of IPVS if using IPVS.

    ipvsadm --clear
    +

    Troubleshooting

    Issue 1

    The connection to the server <master>:6443 was refused - did you specify the right host or port?

    Try:

    Reference

    Check if the kubeconfig file is update to udpate and exists in right place.

    Check environment setting.

    env | grep -i kub
    +

    Check container status.

    sudo systemctl status containerd.service 
    +

    Check kubelet service.

    sudo systemctl status kubelet.service 
    +

    Check port listening status.

    netstat -pnlt | grep 6443
    +

    Check firewall status.

    sudo systemctl status firewalld.service
    +

    Check log.

    journalctl -xeu kubelet
    +

    Issue 2

    "Container runtime network not ready" networkReady="NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized"

    Try:

    Restart Containerd service.

    sudo systemctl restart containerd
    +sudo systemctl status containerd
    +

    Post Installation

    Bash Autocomplete

    On each node.

    Set kubectl auto-completion following the guideline.

    apt install -y bash-completion
    +source /usr/share/bash-completion/bash_completion
    +source <(kubectl completion bash)
    +echo "source <(kubectl completion bash)" >> ~/.bashrc
    +

    Alias

    If we set an alias for kubectl, we can extend shell completion to work with that alias:

    echo 'alias k=kubectl' >>~/.bashrc
    +echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
    +

    Update Default Context

    Get current context.

    kubectl config get-contexts 
     

    In below result, we know:

    • Contenxt name is kubernetes-admin@kubernetes.
    • Cluster name is kubernetes.
    • User is kubernetes-admin.
    • No namespace explicitly defined.
    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
     *         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin 
     

    To set a context with new update, e.g, update default namespace, etc..

    # Usage:
    -kubectl config set-context <context name> --cluster=<cluster name> --namespace=<namespace name> --user=<user name> 
    +kubectl config set-context <context name> --cluster=<cluster name> --namespace=<namespace name> --user=<user name> 
     
     # Set default namespace
    -kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin
    -

    To switch to a new context.

    kubectl config use-context <context name>
    -
    kubectl config use-context kubernetes-admin@kubernetes
    -

    Reference of kubectl and commandline.

    \ No newline at end of file +kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin +

    To switch to a new context.

    kubectl config use-context <context name>
    +
    kubectl config use-context kubernetes-admin@kubernetes
    +

    Reference of kubectl and commandline.

    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/installation/multiple-local/index.html b/k8s/cka_en/installation/multiple-local/index.html index 398a64de..17fc0747 100644 --- a/k8s/cka_en/installation/multiple-local/index.html +++ b/k8s/cka_en/installation/multiple-local/index.html @@ -1,75 +1,75 @@ - Multiple Nodes Installation - UPSkilling

    Multiple Nodes Installation

    Local VM setting

    VMWare Setting.

    • VMnet1: host-only, subnet: 192.168.150.0/24
    • VMnet8: NAT, subnet: 11.0.1.0/24

    Create guest machine with VMWare Player.

    • 4 GB RAM
    • 1 CPUs with 2 Cores
    • Ubuntu Server 22.04
    • NAT

    Info:

    • Kubernetes running on Containerd.

    Ubuntu Post Installation

    Info:

    • Log onto each VM with the account created during Ubuntu installation, and perform below tasks on every VM.

    Create user vagrant on all guests.

    sudo adduser vagrant
    -sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd,root vagrant
    -sudo passwd vagrant
    -

    Set password for root on all guests.

    sudo passwd root
    -

    Enable root ssh logon.

    sudo vi /etc/ssh/sshd_config
    + Multiple Nodes Installation - UPSkilling       

    Multiple Nodes Installation

    Local VM setting

    VMWare Setting.

    • VMnet1: host-only, subnet: 192.168.150.0/24
    • VMnet8: NAT, subnet: 11.0.1.0/24

    Create guest machine with VMWare Player.

    • 4 GB RAM
    • 1 CPUs with 2 Cores
    • Ubuntu Server 22.04
    • NAT

    Info:

    • Kubernetes running on Containerd.

    Ubuntu Post Installation

    Info:

    • Log onto each VM with the account created during Ubuntu installation, and perform below tasks on every VM.

    Create user vagrant on all guests.

    sudo adduser vagrant
    +sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd,root vagrant
    +sudo passwd vagrant
    +

    Set password for root on all guests.

    sudo passwd root
    +

    Enable root ssh logon.

    sudo vi /etc/ssh/sshd_config
     

    Update parameter PermitRootLogin from prohibit-password to yes.

    PermitRootLogin yes
    -#PermitRootLogin prohibit-password
    -

    Restart the sshd service.

    sudo systemctl restart sshd
    -

    Change host name, e.g., ubu1.

    sudo hostnamectl set-hostname ubu1
    -sudo hostnamectl set-hostname ubu1 --pretty
    -

    Verify if the hostname is set to expected name, e.g., ubu1.

    cat /etc/machine-info
    -

    Verify if the hostname is set to expected name, e.g., ubu1.

    cat /etc/hostname
    +#PermitRootLogin prohibit-password
    +

    Restart the sshd service.

    sudo systemctl restart sshd
    +

    Change host name, e.g., ubu1.

    sudo hostnamectl set-hostname ubu1
    +sudo hostnamectl set-hostname ubu1 --pretty
    +

    Verify if the hostname is set to expected name, e.g., ubu1.

    cat /etc/machine-info
    +

    Verify if the hostname is set to expected name, e.g., ubu1.

    cat /etc/hostname
     

    Verify if the hostname of 127.0.1.1 is set to expected name, e.g., ubu1. And add all nodes into the file /etc/hosts.

    sudo vi /etc/hosts
     

    Related setting looks like below.

    127.0.1.1 ubu1
     11.0.1.129 ubu1
     11.0.1.130 ubu2
     11.0.1.131 ubu3
     11.0.1.132 ubu4
    -

    Create file /etc/netplan/00-installer-config.yaml.

    sudo vi /etc/netplan/00-installer-config.yaml
    -

    Update it with information below to set VM with fixed IP with actual IP address, e.g, 11.0.1.129.

    network:
    -  ethernets:
    -    ens33:
    -      dhcp4: false
    -      addresses:
    -      - 11.0.1.129/24
    -      nameservers:
    -        addresses:
    -        - 11.0.1.2
    -      routes:
    -      - to: default
    -        via: 11.0.1.2
    -  version: 2
    -

    Effect above change.

    sudo netplan apply
    -

    Attention:

    • The current ssh connection will be broken due to network setting change.

    Disable swap and firewall on all nodes.

    sudo swapoff -a
    -sudo ufw disable
    -sudo ufw status verbose
    -

    And comment the last line of swap setting in file /etc/fstab. Need reboot guest here.

    sudo vi /etc/fstab
    +

    Create file /etc/netplan/00-installer-config.yaml.

    sudo vi /etc/netplan/00-installer-config.yaml
    +

    Update it with information below to set VM with fixed IP with actual IP address, e.g, 11.0.1.129.

    network:
    +  ethernets:
    +    ens33:
    +      dhcp4: false
    +      addresses:
    +      - 11.0.1.129/24
    +      nameservers:
    +        addresses:
    +        - 11.0.1.2
    +      routes:
    +      - to: default
    +        via: 11.0.1.2
    +  version: 2
    +

    Effect above change.

    sudo netplan apply
    +

    Attention:

    • The current ssh connection will be broken due to network setting change.

    Disable swap and firewall on all nodes.

    sudo swapoff -a
    +sudo ufw disable
    +sudo ufw status verbose
    +

    And comment the last line of swap setting in file /etc/fstab. Need reboot guest here.

    sudo vi /etc/fstab
     

    Result likes below.

    /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1
    -# /swap.img     none    swap    sw      0       0
    -

    Setup timezone on all nodes

    sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    +# /swap.img     none    swap    sw      0       0
    +

    Setup timezone on all nodes

    sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
     
    -sudo cp /etc/profile /etc/profile.bak
    -echo 'LANG="en_US.UTF-8"' | sudo tee -a /etc/profile
    +sudo cp /etc/profile /etc/profile.bak
    +echo 'LANG="en_US.UTF-8"' | sudo tee -a /etc/profile
     
    -source /etc/profile
    +source /etc/profile
     

    Something like this after execute command ll /etc/localtime

    lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
    -

    Kernel setting.

    cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
    +

    Kernel setting.

    cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
     overlay
     br_netfilter
     EOF
    -

    Load to kernel.

    sudo modprobe overlay
    -sudo modprobe br_netfilter
    -

    Network setting.

    cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
    +

    Load to kernel.

    sudo modprobe overlay
    +sudo modprobe br_netfilter
    +

    Network setting.

    cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
     net.bridge.bridge-nf-call-iptables  = 1
     net.ipv4.ip_forward                 = 1
     net.bridge.bridge-nf-call-ip6tables = 1
     EOF
    -

    Effect changes above.

    sudo sysctl --system
    -

    Attention:

    • Reboot the VM.

    Attention:

    • Log onto the VM with account vagrant to verify if above changes were updated as expected.
    • IP address.
    ip addr list
    -
    • Hostname.
    cat /etc/machine-info
    -cat /etc/hostname
    +

    Effect changes above.

    sudo sysctl --system
    +

    Attention:

    • Reboot the VM.

    Attention:

    • Log onto the VM with account vagrant to verify if above changes were updated as expected.
    • IP address.
    ip addr list
    +
    • Hostname.
    cat /etc/machine-info
    +cat /etc/hostname
     hostname
    -
    • Firewall.
    sudo ufw status verbose
    -
    • Kernel setting.
    lsmod | grep -i overlay
    -lsmod | grep -i br_netfilter
    -
    • Network setting.
    sudo sysctl -a | grep -i net.bridge.bridge-nf-call-ip*
    -sudo sysctl -a | grep -i net.ipv4.ip_forward
    -

    Install Containerd

    Install Containerd sevice on all nodes.

    Backup source file.

    sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
    -

    Install Containered.

    sudo apt-get update && sudo apt-get install -y containerd
    -

    Configure Containerd. Modify file /etc/containerd/config.toml.

    sudo mkdir -p /etc/containerd
    -containerd config default | sudo tee /etc/containerd/config.toml
    -sudo vi /etc/containerd/config.toml
    +
    • Firewall.
    sudo ufw status verbose
    +
    • Kernel setting.
    lsmod | grep -i overlay
    +lsmod | grep -i br_netfilter
    +
    • Network setting.
    sudo sysctl -a | grep -i net.bridge.bridge-nf-call-ip*
    +sudo sysctl -a | grep -i net.ipv4.ip_forward
    +

    Install Containerd

    Install Containerd sevice on all nodes.

    Backup source file.

    sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
    +

    Install Containered.

    sudo apt-get update && sudo apt-get install -y containerd
    +

    Configure Containerd. Modify file /etc/containerd/config.toml.

    sudo mkdir -p /etc/containerd
    +containerd config default | sudo tee /etc/containerd/config.toml
    +sudo vi /etc/containerd/config.toml
     

    Update sandbox_image with new value "registry.aliyuncs.com/google_containers/pause:3.6". Update SystemdCgroup with new value true.

    [plugins]
       [plugins."io.containerd.gc.v1.scheduler"]
     
    @@ -85,99 +85,99 @@
     
               [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
                 SystemdCgroup = true
    -

    Restart Containerd service.

    sudo systemctl restart containerd
    -sudo systemctl status containerd
    -

    Install nerdctl

    Install nerdctl sevice on all nodes.

    The goal of nerdctl is to facilitate experimenting the cutting-edge features of containerd that are not present in Docker.

    Binaries are available here: https://github.com/containerd/nerdctl/releases

    wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-0.22.2-linux-amd64.tar.gz
    -tar -zxvf nerdctl-0.22.2-linux-amd64.tar.gz
    -sudo cp nerdctl /usr/bin/
    -

    Verify nerdctl.

    sudo nerdctl --help
    -

    To list local Kubernetes containers.

    sudo nerdctl -n k8s.io ps
    -

    Install Kubernetes

    Install Kubernetes on all nodes.

    Install dependencied packages.

    sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl
    -

    Install gpg certificate.

    sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg
    -

    Add Kubernetes repo.

    echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
    -

    Update and install dependencied packages.

    sudo apt-get update
    -sudo apt-get install ebtables
    -sudo apt-get install libxtables12
    -sudo apt-get upgrade iptables
    -

    Check available versions of kubeadm.

    apt policy kubeadm
    -

    Install 1.24.1-00 version.

    sudo apt-get -y install kubelet=1.24.1-00 kubeadm=1.24.1-00 kubectl=1.24.1-00 --allow-downgrades
    -

    Setup Master Node

    kubeadm init

    Set up Control Plane on VM playing master node.

    Check kubeadm default parameters for initialization.

    kubeadm config print init-defaults
    -

    Reuslt:

    apiVersion: kubeadm.k8s.io/v1beta3
    -bootstrapTokens:
    -- groups:
    -  - system:bootstrappers:kubeadm:default-node-token
    -  token: abcdef.0123456789abcdef
    -  ttl: 24h0m0s
    -  usages:
    -  - signing
    -  - authentication
    -kind: InitConfiguration
    -localAPIEndpoint:
    -  advertiseAddress: 1.2.3.4
    -  bindPort: 6443
    -nodeRegistration:
    -  criSocket: unix:///var/run/containerd/containerd.sock
    -  imagePullPolicy: IfNotPresent
    -  name: node
    -  taints: null
    ----
    -apiServer:
    -  timeoutForControlPlane: 4m0s
    -apiVersion: kubeadm.k8s.io/v1beta3
    -certificatesDir: /etc/kubernetes/pki
    -clusterName: kubernetes
    -controllerManager: {}
    -dns: {}
    -etcd:
    -  local:
    -    dataDir: /var/lib/etcd
    -imageRepository: k8s.gcr.io
    -kind: ClusterConfiguration
    -kubernetesVersion: 1.24.0
    -networking:
    -  dnsDomain: cluster.local
    -  serviceSubnet: 10.96.0.0/12
    -scheduler: {}
    -

    Dry rune and run. Save the output, which will be used later on work nodes.

    With kubeadm init to initiate cluster, we need understand below three options about network.

    • --pod-network-cidr:
    • Specify range of IP addresses for the pod network. If set, the control plane will automatically allocate CIDRs for every node.
    • Be noted that 10.244.0.0/16 is default range of flannel. If it's changed here, please do change the same when deploy Flannel.
    • --apiserver-bind-port:
    • Port for the API Server to bind to. (default 6443)
    • --service-cidr:
    • Use alternative range of IP address for service VIPs. (default "10.96.0.0/12")

    Note:

    • service VIPs (a.k.a. Cluster IP), specified by option --service-cidr.
    • podCIDR (a.k.a. endpoint IP),specified by option --pod-network-cidr.

    There are 4 distinct networking problems to address:

    • Highly-coupled container-to-container communications: this is solved by Pods (podCIDR) and localhost communications.
    • Pod-to-Pod communications:
    • a.k.a. container-to-container.
    • Example with Flannel, the flow is: Pod → veth pair → cni0 → flannel.1 → host eth0 → host eth0 → flannel.1 → cni0 → veth pair → Pod.
    • Pod-to-Service communications:
    • Flow: Pod → Kernel → Servive iptables → service → Pod iptables → Pod
    • External-to-Service communications:
    • LoadBalancer: SLB → NodePort → Service → Pod

    kube-proxy is responsible for iptables, not traffic.

    sudo kubeadm init \
    -  --dry-run \
    -  --pod-network-cidr=10.244.0.0/16 \
    -  --service-cidr=192.244.0.0/16 \
    -  --image-repository=registry.aliyuncs.com/google_containers \
    -  --kubernetes-version=v1.24.1
    +

    Restart Containerd service.

    sudo systemctl restart containerd
    +sudo systemctl status containerd
    +

    Install nerdctl

    Install nerdctl sevice on all nodes.

    The goal of nerdctl is to facilitate experimenting the cutting-edge features of containerd that are not present in Docker.

    Binaries are available here: https://github.com/containerd/nerdctl/releases

    wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-0.22.2-linux-amd64.tar.gz
    +tar -zxvf nerdctl-0.22.2-linux-amd64.tar.gz
    +sudo cp nerdctl /usr/bin/
    +

    Verify nerdctl.

    sudo nerdctl --help
    +

    To list local Kubernetes containers.

    sudo nerdctl -n k8s.io ps
    +

    Install Kubernetes

    Install Kubernetes on all nodes.

    Install dependencied packages.

    sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl
    +

    Install gpg certificate.

    sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg
    +

    Add Kubernetes repo.

    echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
    +

    Update and install dependencied packages.

    sudo apt-get update
    +sudo apt-get install ebtables
    +sudo apt-get install libxtables12
    +sudo apt-get upgrade iptables
    +

    Check available versions of kubeadm.

    apt policy kubeadm
    +

    Install 1.24.1-00 version.

    sudo apt-get -y install kubelet=1.24.1-00 kubeadm=1.24.1-00 kubectl=1.24.1-00 --allow-downgrades
    +

    Setup Master Node

    kubeadm init

    Set up Control Plane on VM playing master node.

    Check kubeadm default parameters for initialization.

    kubeadm config print init-defaults
    +

    Reuslt:

    apiVersion: kubeadm.k8s.io/v1beta3
    +bootstrapTokens:
    +- groups:
    +  - system:bootstrappers:kubeadm:default-node-token
    +  token: abcdef.0123456789abcdef
    +  ttl: 24h0m0s
    +  usages:
    +  - signing
    +  - authentication
    +kind: InitConfiguration
    +localAPIEndpoint:
    +  advertiseAddress: 1.2.3.4
    +  bindPort: 6443
    +nodeRegistration:
    +  criSocket: unix:///var/run/containerd/containerd.sock
    +  imagePullPolicy: IfNotPresent
    +  name: node
    +  taints: null
    +---
    +apiServer:
    +  timeoutForControlPlane: 4m0s
    +apiVersion: kubeadm.k8s.io/v1beta3
    +certificatesDir: /etc/kubernetes/pki
    +clusterName: kubernetes
    +controllerManager: {}
    +dns: {}
    +etcd:
    +  local:
    +    dataDir: /var/lib/etcd
    +imageRepository: k8s.gcr.io
    +kind: ClusterConfiguration
    +kubernetesVersion: 1.24.0
    +networking:
    +  dnsDomain: cluster.local
    +  serviceSubnet: 10.96.0.0/12
    +scheduler: {}
    +

    Dry rune and run. Save the output, which will be used later on work nodes.

    With kubeadm init to initiate cluster, we need understand below three options about network.

    • --pod-network-cidr:
    • Specify range of IP addresses for the pod network. If set, the control plane will automatically allocate CIDRs for every node.
    • Be noted that 10.244.0.0/16 is default range of flannel. If it's changed here, please do change the same when deploy Flannel.
    • --apiserver-bind-port:
    • Port for the API Server to bind to. (default 6443)
    • --service-cidr:
    • Use alternative range of IP address for service VIPs. (default "10.96.0.0/12")

    Note:

    • service VIPs (a.k.a. Cluster IP), specified by option --service-cidr.
    • podCIDR (a.k.a. endpoint IP),specified by option --pod-network-cidr.

    There are 4 distinct networking problems to address:

    • Highly-coupled container-to-container communications: this is solved by Pods (podCIDR) and localhost communications.
    • Pod-to-Pod communications:
    • a.k.a. container-to-container.
    • Example with Flannel, the flow is: Pod → veth pair → cni0 → flannel.1 → host eth0 → host eth0 → flannel.1 → cni0 → veth pair → Pod.
    • Pod-to-Service communications:
    • Flow: Pod → Kernel → Servive iptables → service → Pod iptables → Pod
    • External-to-Service communications:
    • LoadBalancer: SLB → NodePort → Service → Pod

    kube-proxy is responsible for iptables, not traffic.

    sudo kubeadm init \
    +  --dry-run \
    +  --pod-network-cidr=10.244.0.0/16 \
    +  --service-cidr=192.244.0.0/16 \
    +  --image-repository=registry.aliyuncs.com/google_containers \
    +  --kubernetes-version=v1.24.1
     
    -sudo kubeadm init \
    -  --pod-network-cidr=10.244.0.0/16 \
    -  --service-cidr=192.244.0.0/16 \
    -  --image-repository=registry.aliyuncs.com/google_containers \
    -  --kubernetes-version=v1.24.1
    -

    kubeconfig file

    Set kubeconfig file for current user (here it's vagrant).

    mkdir -p $HOME/.kube
    -sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    -sudo chown $(id -u):$(id -g) $HOME/.kube/config
    -

    Kubernetes provides a command line tool kubectl for communicating with a Kubernetes cluster's control plane, using the Kubernetes API.

    kubectl controls the Kubernetes cluster manager.

    For configuration, kubectl looks for a file named config in the $HOME/.kube directory, which is a copy of file /etc/kubernetes/admin.conf generated by kubeadm init.

    We can specify other kubeconfig files by setting the KUBECONFIG environment variable or by setting the --kubeconfig flag. If the KUBECONFIG environment variable doesn't exist, kubectl uses the default kubeconfig file, $HOME/.kube/config.

    A context element in a kubeconfig file is used to group access parameters under a convenient name. Each context has three parameters: cluster, namespace, and user. By default, the kubectl command-line tool uses parameters from the current context to communicate with the cluster.

    A sample of .kube/config.

    apiVersion: v1
    -clusters:
    -- cluster:
    -    certificate-authority-data: <certificate string>
    -    server: https://<eth0 ip>:6443
    -  name: <cluster name>
    -contexts:
    -- context:
    -    cluster: <cluster name>
    -    namespace: <namespace name>
    -    user: <user name>
    -  name: <context user>@<context name>
    -current-context: <context name>
    -kind: Config
    -preferences: {}
    -users:
    -- name: <user name>
    -  user:
    -    client-certificate-data: <certificate string>
    -    client-key-data: <certificate string>
    -

    To get the current context:

    kubectl config get-contexts
    +sudo kubeadm init \
    +  --pod-network-cidr=10.244.0.0/16 \
    +  --service-cidr=192.244.0.0/16 \
    +  --image-repository=registry.aliyuncs.com/google_containers \
    +  --kubernetes-version=v1.24.1
    +

    kubeconfig file

    Set kubeconfig file for current user (here it's vagrant).

    mkdir -p $HOME/.kube
    +sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    +sudo chown $(id -u):$(id -g) $HOME/.kube/config
    +

    Kubernetes provides a command line tool kubectl for communicating with a Kubernetes cluster's control plane, using the Kubernetes API.

    kubectl controls the Kubernetes cluster manager.

    For configuration, kubectl looks for a file named config in the $HOME/.kube directory, which is a copy of file /etc/kubernetes/admin.conf generated by kubeadm init.

    We can specify other kubeconfig files by setting the KUBECONFIG environment variable or by setting the --kubeconfig flag. If the KUBECONFIG environment variable doesn't exist, kubectl uses the default kubeconfig file, $HOME/.kube/config.

    A context element in a kubeconfig file is used to group access parameters under a convenient name. Each context has three parameters: cluster, namespace, and user. By default, the kubectl command-line tool uses parameters from the current context to communicate with the cluster.

    A sample of .kube/config.

    apiVersion: v1
    +clusters:
    +- cluster:
    +    certificate-authority-data: <certificate string>
    +    server: https://<eth0 ip>:6443
    +  name: <cluster name>
    +contexts:
    +- context:
    +    cluster: <cluster name>
    +    namespace: <namespace name>
    +    user: <user name>
    +  name: <context user>@<context name>
    +current-context: <context name>
    +kind: Config
    +preferences: {}
    +users:
    +- name: <user name>
    +  user:
    +    client-certificate-data: <certificate string>
    +    client-key-data: <certificate string>
    +

    To get the current context:

    kubectl config get-contexts
     

    Result

    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
     *         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin   
    -

    Install Calico

    Here is guidance of End-to-end Calico installation. Detail practice demo, can be found in section "Install Calico" of "A1.Discussion" below.

    Install Calico

    curl https://docs.projectcalico.org/manifests/calico.yaml -O
    -kubectl apply -f calico.yaml
    +

    Install Calico

    Here is guidance of End-to-end Calico installation. Detail practice demo, can be found in section "Install Calico" of "A1.Discussion" below.

    Install Calico

    curl https://docs.projectcalico.org/manifests/calico.yaml -O
    +kubectl apply -f calico.yaml
     

    Result

    configmap/calico-config created
     customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
     customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
    @@ -205,19 +205,19 @@
     deployment.apps/calico-kube-controllers created
     serviceaccount/calico-kube-controllers created
     poddisruptionbudget.policy/calico-kube-controllers created
    -

    Verify status of Calico. It may take minutes to complete initialization.

    kubectl get pod -n kube-system | grep calico
    +

    Verify status of Calico. It may take minutes to complete initialization.

    kubectl get pod -n kube-system | grep calico
     

    Result

    calico-kube-controllers-555bc4b957-l8bn2   0/1     Pending    0          28s
     calico-node-255pc                          0/1     Init:1/3   0          29s
     calico-node-7tmnb                          0/1     Init:1/3   0          29s
     calico-node-w8nvl                          0/1     Init:1/3   0          29s
    -

    Verify network status.

    sudo nerdctl network ls
    +

    Verify network status.

    sudo nerdctl network ls
     

    Result

    NETWORK ID      NAME               FILE
                     k8s-pod-network    /etc/cni/net.d/10-calico.conflist
     17f29b073143    bridge             /etc/cni/net.d/nerdctl-bridge.conflist
                     host               
                     none 
    -

    Setup Work Nodes

    Use kubeadm token to generate the join token and hash value.

    kubeadm token create --print-join-command
    -

    Command usage:

    sudo kubeadm join <your master node eth0 ip>:6443 --token <token generated by kubeadm init> --discovery-token-ca-cert-hash <hash key generated by kubeadm init>
    +

    Setup Work Nodes

    Use kubeadm token to generate the join token and hash value.

    kubeadm token create --print-join-command
    +

    Command usage:

    sudo kubeadm join <your master node eth0 ip>:6443 --token <token generated by kubeadm init> --discovery-token-ca-cert-hash <hash key generated by kubeadm init>
     

    Result looks like below.

    [preflight] Running pre-flight checks
             [WARNING SystemVerification]: missing optional cgroups: blkio
     [preflight] Reading configuration from the cluster...
    @@ -232,39 +232,39 @@
     * The Kubelet was informed of the new secure connection details.
     
     Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
    -

    Check Cluster Status

    Cluster info:

    kubectl cluster-info
    +

    Check Cluster Status

    Cluster info:

    kubectl cluster-info
     

    Output

    Kubernetes control plane is running at https://11.0.1.129:6443
     CoreDNS is running at https://11.0.1.129:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
     To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
    -

    Node info:

    kubectl get nodes -owide
    -

    Pod info:

    kubectl get pod -A
    -

    Post Installation

    Bash Autocomplete

    On each node.

    Set kubectl auto-completion following the guideline.

    apt install -y bash-completion
    +

    Node info:

    kubectl get nodes -owide
    +

    Pod info:

    kubectl get pod -A
    +

    Post Installation

    Bash Autocomplete

    On each node.

    Set kubectl auto-completion following the guideline.

    apt install -y bash-completion
     
    -source /usr/share/bash-completion/bash_completion
    -source <(kubectl completion bash)
    +source /usr/share/bash-completion/bash_completion
    +source <(kubectl completion bash)
     
    -echo "source <(kubectl completion bash)" >> ~/.bashrc
    -source ~/.bashrc
    -

    Alias

    If we set an alias for kubectl, we can extend shell completion to work with that alias:

    echo 'alias k=kubectl' >>~/.bashrc
    -echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
    -

    Update Default Context

    Get current context.

    kubectl config get-contexts 
    +echo "source <(kubectl completion bash)" >> ~/.bashrc
    +source ~/.bashrc
    +

    Alias

    If we set an alias for kubectl, we can extend shell completion to work with that alias:

    echo 'alias k=kubectl' >>~/.bashrc
    +echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
    +

    Update Default Context

    Get current context.

    kubectl config get-contexts 
     

    In below result, we know:

    • Contenxt name is kubernetes-admin@kubernetes.
    • Cluster name is kubernetes.
    • User is kubernetes-admin.
    • No namespace explicitly defined.
    CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
     *         kubernetes-admin@kubernetes   kubernetes   kubernetes-admin 
     

    To set a context with new update, e.g, update default namespace, etc..

    # Usage:
    -kubectl config set-context <context name> --cluster=<cluster name> --namespace=<namespace name> --user=<user name> 
    +kubectl config set-context <context name> --cluster=<cluster name> --namespace=<namespace name> --user=<user name> 
     
     # Set default namespace
    -kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin
    -

    To switch to a new context.

    kubectl config use-context <context name>
    -
    kubectl config use-context kubernetes-admin@kubernetes
    -

    Reference:

    Install Helm

    Helm is the Kubernetes package manager. It doesn't come with Kubernetes.

    Three concepts of helm:

    • A Chart is a Helm package.
    • It contains all of the resource definitions necessary to run an application, tool, or service inside of a Kubernetes cluster.
    • Think of it like the Kubernetes equivalent of a Homebrew formula, an Apt dpkg, or a Yum RPM file.
    • A Repository is the place where charts can be collected and shared.
    • It's like Perl's CPAN archive or the Fedora Package Database, but for Kubernetes packages.
    • A Release is an instance of a chart running in a Kubernetes cluster.
    • One chart can often be installed many times into the same cluster. And each time it is installed, a new release is created.
    • Consider a MySQL chart. If you want two databases running in your cluster, you can install that chart twice. Each one will have its own release, which will in turn have its own release name.

    Reference:

    Helm Client Installation:

    curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
    -chmod 700 get_helm.sh
    +kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin
    +

    To switch to a new context.

    kubectl config use-context <context name>
    +
    kubectl config use-context kubernetes-admin@kubernetes
    +

    Reference:

    Install Helm

    Helm is the Kubernetes package manager. It doesn't come with Kubernetes.

    Three concepts of helm:

    • A Chart is a Helm package.
    • It contains all of the resource definitions necessary to run an application, tool, or service inside of a Kubernetes cluster.
    • Think of it like the Kubernetes equivalent of a Homebrew formula, an Apt dpkg, or a Yum RPM file.
    • A Repository is the place where charts can be collected and shared.
    • It's like Perl's CPAN archive or the Fedora Package Database, but for Kubernetes packages.
    • A Release is an instance of a chart running in a Kubernetes cluster.
    • One chart can often be installed many times into the same cluster. And each time it is installed, a new release is created.
    • Consider a MySQL chart. If you want two databases running in your cluster, you can install that chart twice. Each one will have its own release, which will in turn have its own release name.

    Reference:

    Helm Client Installation:

    curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
    +chmod 700 get_helm.sh
     ./get_helm.sh
     

    Output:

    Downloading https://get.helm.sh/helm-v3.9.1-linux-amd64.tar.gz
     Verifying checksum... Done.
     Preparing to install helm into /usr/local/bin
     helm installed into /usr/local/bin/helm
    -

    Note:

    • helm init does not exist in Helm 3, following the removal of Tiller. You no longer need to install Tiller in your cluster in order to use Helm.
    • helm search can be used to search two different types of source:
    • helm search hub searches the Artifact Hub, which lists helm charts from dozens of different repositories.
    • helm search repo searches the repositories that you have added to your local helm client (with helm repo add). This search is done over local data, and no public network connection is needed.

    Reference:

    Reset cluster

    Caution: below steps will destroy current cluster.

    Delete all nodes in the cluster.

    kubeadm reset
    -

    Clean up rule of iptables.

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    -

    Clean up rule of IPVS if using IPVS.

    ipvsadm --clear
    -
    \ No newline at end of file +

    Note:

    • helm init does not exist in Helm 3, following the removal of Tiller. You no longer need to install Tiller in your cluster in order to use Helm.
    • helm search can be used to search two different types of source:
    • helm search hub searches the Artifact Hub, which lists helm charts from dozens of different repositories.
    • helm search repo searches the repositories that you have added to your local helm client (with helm repo add). This search is done over local data, and no public network connection is needed.

    Reference:

    Reset cluster

    Caution: below steps will destroy current cluster.

    Delete all nodes in the cluster.

    kubeadm reset
    +

    Clean up rule of iptables.

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    +

    Clean up rule of IPVS if using IPVS.

    ipvsadm --clear
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/cka_en/installation/single-local/index.html b/k8s/cka_en/installation/single-local/index.html index 3d71955a..040d9277 100644 --- a/k8s/cka_en/installation/single-local/index.html +++ b/k8s/cka_en/installation/single-local/index.html @@ -1,118 +1,118 @@ - Single Node Installation - UPSkilling

    Single Node Installation

    Local VM setting

    VMWare Setting.

    • VMnet1: host-only, subnet: 192.168.150.0/24
    • VMnet8: NAT, subnet: 11.0.1.0/24

    Create guest machine with VMWare Player.

    • 4 GB RAM
    • 2 CPUs with 2 Cores
    • Ubuntu Server 22.04
    • NAT

    Kubernetes running on Docker.

    Ubuntu Post Installation

    Create user vagrant.

    sudo adduser vagrant
    -sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd vagrant
    -sudo passwd vagrant
    -

    Set password for root.

    sudo passwd root
    -

    Update guest's hostname. Here it's ubusvr.

    sudo hostnamectl set-hostname ubusvr
    -sudo hostnamectl set-hostname ubusvr --pretty
    -

    Verify if the hostname is set to ubusvr.

    cat /etc/machine-info
    -

    Verify if the hostname is set to ubusvr.

    cat /etc/hostname
    -

    Verify if the hostname of 127.0.1.1 is set to ubusvr.

    cat /etc/hosts
    -
    127.0.0.1 localhost
    -127.0.1.1 ubusrv
    + Single Node Installation - UPSkilling       

    Single Node Installation

    Local VM setting

    VMWare Setting.

    • VMnet1: host-only, subnet: 192.168.150.0/24
    • VMnet8: NAT, subnet: 11.0.1.0/24

    Create guest machine with VMWare Player.

    • 4 GB RAM
    • 2 CPUs with 2 Cores
    • Ubuntu Server 22.04
    • NAT

    Kubernetes running on Docker.

    Ubuntu Post Installation

    Create user vagrant.

    sudo adduser vagrant
    +sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd vagrant
    +sudo passwd vagrant
    +

    Set password for root.

    sudo passwd root
    +

    Update guest's hostname. Here it's ubusvr.

    sudo hostnamectl set-hostname ubusvr
    +sudo hostnamectl set-hostname ubusvr --pretty
    +

    Verify if the hostname is set to ubusvr.

    cat /etc/machine-info
    +

    Verify if the hostname is set to ubusvr.

    cat /etc/hostname
    +

    Verify if the hostname of 127.0.1.1 is set to ubusvr.

    cat /etc/hosts
    +
    127.0.0.1 localhost
    +127.0.1.1 ubusrv
     
     # The following lines are desirable for IPv6 capable hosts
    -::1     ip6-localhost ip6-loopback
    -fe00::0 ip6-localnet
    -ff00::0 ip6-mcastprefix
    -ff02::1 ip6-allnodes
    -ff02::2 ip6-allrouters
    -

    Set guest with fix ip, e.g, 11.0.1.136.

    sudo vi 00-installer-config.yaml
    +::1     ip6-localhost ip6-loopback
    +fe00::0 ip6-localnet
    +ff00::0 ip6-mcastprefix
    +ff02::1 ip6-allnodes
    +ff02::2 ip6-allrouters
    +

    Set guest with fix ip, e.g, 11.0.1.136.

    sudo vi 00-installer-config.yaml
     
    network:
    -  ethernets:
    -    ens33:
    -      dhcp4: false
    -      addresses:
    -      - 11.0.1.136/24
    -      nameservers:
    -        addresses:
    -        - 11.0.1.2
    -      routes:
    -      - to: default
    -        via: 11.0.1.2
    -  version: 2
    -
    sudo netplan apply
    -

    Disable swap

    sudo swapoff -a
    -sudo ufw disable
    -sudo ufw status verbose
    -

    And comment the last line of swap setting in file /etc/fstab. Need reboot guest here.

    /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1
    +  ethernets:
    +    ens33:
    +      dhcp4: false
    +      addresses:
    +      - 11.0.1.136/24
    +      nameservers:
    +        addresses:
    +        - 11.0.1.2
    +      routes:
    +      - to: default
    +        via: 11.0.1.2
    +  version: 2
    +
    sudo netplan apply
    +

    Disable swap

    sudo swapoff -a
    +sudo ufw disable
    +sudo ufw status verbose
    +

    And comment the last line of swap setting in file /etc/fstab. Need reboot guest here.

    /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1
     # /swap.img     none    swap    sw      0       0
    -

    Setup timezone

    sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    -sudo echo 'LANG="en_US.UTF-8"' >> /etc/profile
    -source /etc/profile
    -

    Something like this after execute command ll /etc/localtime

    lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
    -

    Kernel setting

    cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
    +

    Setup timezone

    sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
    +sudo echo 'LANG="en_US.UTF-8"' >> /etc/profile
    +source /etc/profile
    +

    Something like this after execute command ll /etc/localtime

    lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
    +

    Kernel setting

    cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
     overlay
     br_netfilter
     EOF
    -
    sudo modprobe overlay
    -sudo modprobe br_netfilter
    -
    cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
    +
    sudo modprobe overlay
    +sudo modprobe br_netfilter
    +
    cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
     net.bridge.bridge-nf-call-iptables  = 1
     net.ipv4.ip_forward                 = 1
     net.bridge.bridge-nf-call-ip6tables = 1
     EOF
    -
    sudo sysctl --system
    -

    Install Docker

    Reference

    sudo apt-get install \
    -ca-certificates \
    -curl \
    -gnupg \
    +
    sudo sysctl --system
    +

    Install Docker

    Reference

    sudo apt-get install \
    +ca-certificates \
    +curl \
    +gnupg \
     lsb-release
    -
    sudo mkdir -p /etc/apt/keyrings
    +
    sudo mkdir -p /etc/apt/keyrings
     
    -curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
    +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
     
    -sudo chmod a+r /etc/apt/keyrings/docker.gpg
    +sudo chmod a+r /etc/apt/keyrings/docker.gpg
     
    -echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    -
    sudo apt-get update
    +echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    +
    sudo apt-get update
     
    -sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
    -
    sudo systemctl status docker.service
    +sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
    +
    sudo systemctl status docker.service
     
    -sudo systemctl status containerd.service
    -
    sudo groupadd docker
    -sudo usermod -aG docker $USER
    -

    Setup Containerd

    containerd config default | sudo tee /etc/containerd/config.toml
    -sudo vi /etc/containerd/config.toml
    -
    sudo systemctl restart containerd
    -sudo systemctl status containerd
    -

    Install Kubernetes

    Install kubeadm

    sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl
    -
    sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg
    +sudo systemctl status containerd.service
    +
    sudo groupadd docker
    +sudo usermod -aG docker $USER
    +

    Setup Containerd

    containerd config default | sudo tee /etc/containerd/config.toml
    +sudo vi /etc/containerd/config.toml
    +
    sudo systemctl restart containerd
    +sudo systemctl status containerd
    +

    Install Kubernetes

    Install kubeadm

    sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl
    +
    sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg
     
    -echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
    -
    sudo apt-get update
    -sudo apt-get install ebtables
    -sudo apt-get install libxtables12
    -sudo apt-get upgrade iptables
    -
    apt policy kubeadm
    -
    sudo apt-get -y install kubelet=1.23.8-00 kubeadm=1.23.8-00 kubectl=1.23.8-00 --allow-downgrades
    -

    Setup Master Node

    sudo kubeadm config print init-defaults
    -

    Dry run

    sudo kubeadm init --dry-run --pod-network-cidr=10.244.0.0/16 --image-repository=registry.aliyuncs.com/google_containers --kubernetes-version=v1.23.8
    -

    Run

    sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --image-repository=registry.aliyuncs.com/google_containers --kubernetes-version=v1.23.8
    -
    mkdir -p $HOME/.kube
    -sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    -sudo chown $(id -u):$(id -g) $HOME/.kube/config
    -

    Install Flannel. If NetworkPolicy is the case, then install Calico. Refer to the "Install Calico or Flannel" of below section "Installation on Aliyun Ubuntu".

    kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    -

    Setup on Worker Node

    Command usage:

    kubeadm join <your master node eth0 ip>:6443 --token <token generated by kubeadm init> --discovery-token-ca-cert-hash <hash key generated by kubeadm init>
    -
    kubeadm join 11.0.1.136:6443 --token 6zqh1u.8b4afzc2ov4e7iuj \
    -  --discovery-token-ca-cert-hash sha256:815fdb9dd9e3ae0af07ffaf6c216964388098b150ef01ee3ae900c261a429d24
    -

    Setup bash auto completion on all nodes

    sudo apt install -y bash-completion
    -source /usr/share/bash-completion/bash_completion
    -source <(kubectl completion bash)
    -echo "source <(kubectl completion bash)" >> ~/.bashrc
    -

    Create alias

    echo 'alias k=kubectl' >>~/.bashrc
    -echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
    -

    Check Cluster Status

    kubectl cluster-info
    -kubectl get nodes -owide
    -kubectl get pod -A
    -

    Reset cluster

    CAUTION: below steps will destroy current cluster.

    Delete all nodes in the cluster.

    kubeadm reset
    -

    Clean up rule of iptables.

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    -

    Clean up rule of IPVS if using IPVS.

    ipvsadm --clear
    -

    Install Helm

    Helm Client Installation:

    curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
    -
    chmod 700 get_helm.sh
    +echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
    +
    sudo apt-get update
    +sudo apt-get install ebtables
    +sudo apt-get install libxtables12
    +sudo apt-get upgrade iptables
    +
    apt policy kubeadm
    +
    sudo apt-get -y install kubelet=1.23.8-00 kubeadm=1.23.8-00 kubectl=1.23.8-00 --allow-downgrades
    +

    Setup Master Node

    sudo kubeadm config print init-defaults
    +

    Dry run

    sudo kubeadm init --dry-run --pod-network-cidr=10.244.0.0/16 --image-repository=registry.aliyuncs.com/google_containers --kubernetes-version=v1.23.8
    +

    Run

    sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --image-repository=registry.aliyuncs.com/google_containers --kubernetes-version=v1.23.8
    +
    mkdir -p $HOME/.kube
    +sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    +sudo chown $(id -u):$(id -g) $HOME/.kube/config
    +

    Install Flannel. If NetworkPolicy is the case, then install Calico. Refer to the "Install Calico or Flannel" of below section "Installation on Aliyun Ubuntu".

    kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
    +

    Setup on Worker Node

    Command usage:

    kubeadm join <your master node eth0 ip>:6443 --token <token generated by kubeadm init> --discovery-token-ca-cert-hash <hash key generated by kubeadm init>
    +
    kubeadm join 11.0.1.136:6443 --token 6zqh1u.8b4afzc2ov4e7iuj \
    +  --discovery-token-ca-cert-hash sha256:815fdb9dd9e3ae0af07ffaf6c216964388098b150ef01ee3ae900c261a429d24
    +

    Setup bash auto completion on all nodes

    sudo apt install -y bash-completion
    +source /usr/share/bash-completion/bash_completion
    +source <(kubectl completion bash)
    +echo "source <(kubectl completion bash)" >> ~/.bashrc
    +

    Create alias

    echo 'alias k=kubectl' >>~/.bashrc
    +echo 'complete -o default -F __start_kubectl k' >>~/.bashrc
    +

    Check Cluster Status

    kubectl cluster-info
    +kubectl get nodes -owide
    +kubectl get pod -A
    +

    Reset cluster

    CAUTION: below steps will destroy current cluster.

    Delete all nodes in the cluster.

    kubeadm reset
    +

    Clean up rule of iptables.

    iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
    +

    Clean up rule of IPVS if using IPVS.

    ipvsadm --clear
    +

    Install Helm

    Helm Client Installation:

    curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
    +
    chmod 700 get_helm.sh
     
    ./get_helm.sh
    -

    Output:

    Downloading https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz
    -Verifying checksum... Done.
    -Preparing to install helm into /usr/local/bin
    -helm installed into /usr/local/bin/helm
    -
    \ No newline at end of file +

    Output:

    Downloading https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz
    +Verifying checksum... Done.
    +Preparing to install helm into /usr/local/bin
    +helm installed into /usr/local/bin/helm
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/demo/cap_on_kyma/index.html b/k8s/demo/cap_on_kyma/index.html index 43b588da..9bbb330a 100644 --- a/k8s/demo/cap_on_kyma/index.html +++ b/k8s/demo/cap_on_kyma/index.html @@ -1,101 +1,101 @@ - Build CAP Application on Kyma - UPSkilling

    Build CAP Application on Kyma

    This is the memo of self-practice following the tutorials from Deploy Your CAP Application on SAP BTP Kyma Runtime.

    Prerequisites:

    Tasks:

    • Configure Kyma in SAP Business Technology Platform (SAP BTP) subaccount and prepare Kyma development environment.
    • Create an HDI container for an SAP HANA Cloud instance on Cloud Foundry and create credentials for this SAP HANA cloud instance in Kyma cluster.
    • Develop a business application using SAP Cloud Application Programming Model (CAP).
    • Start on local environment, enhance it with an SAP Fiori UI, add business logic to it, and also roles and authorization check.
    • Add a Helm chart to the application, build docker images, push them to your container registry, and deploy your application to your Kyma cluster on SAP BTP.

    Local environment:

    • Applel Silicon M1 chipset
    • macOS 12.6 (command sw_vers)
    • Nodejs version:
    • CDS version:
    • jq - for JSON processing in CLI (brew install jq)

    SAP BTP subaccount configuration

    For the SAP BTP free tier, the recommendation is as well to use an AWS-based subaccount. Kyma runtime in the free tier is only available on AWS.

    Choose the entitlements for the subdomain:

    • Alert Notification: Standard plan
    • Continuous Integration & Delivery: default (Application) or the trial (Application) or free (Application) plans which are not charged
    • Kyma runtime: any available plan in the list (trial and free are not charged)
    • Launchpad Service: standard (Application) or free (Application)
    • SAP HANA Cloud: hana
    • SAP HANA Schemas & HDI Containers: hdi-shared

    Set up local BTP environment

    Here we will use btp command to set up cloud environment. Details we can refer to help document Working with Environments Using the btp CLI.

    Download BTP CLI package btp-cli-darwin-amd64-<ver_num>.tar.gz via link and unpackage it.

    tar xvf btp-cli-darwin-amd64-<ver_num>.tar.gz
    -

    A new subfolder darwin-amd64 will be created in current path and a bin file btp is under the subfolder. Move file btp to folder /usr/local/bin/.

    sudo mv ./darwin-amd64/btp /usr/local/bin/
    -

    Log on to the subaccount on BTP.

    btp login --url https://cpcli.cf.eu10.hana.ondemand.com --subdomain <your_subdomain> --user <your_registered_email_address>
    -

    Configuration file was stored at /Users/$USER/Library/Application Support/.btp/config.json. In Linux, the configuration file is on /home/$USER/.config/.btp/config.json. We can get current user via command echo $USER.

    Tips:

    • Commands are executed in the target, unless specified otherwise using a parameter. To change the target, use btp target.
    • For an explanation of the targeting mechanism, use btp help target.

    Get the subaccount ID in BTP and we will know that kyma and cloundfoundry are available in current trial account.

    btp list accounts/available-environment --subaccount <your_subaccount_id>
    -

    Get details about an environment available for a subaccount

    btp get accounts/available-environment --subaccount <your_subaccount_id> --environment cloudfoundry --service cloudfoundry --plan standard
    -btp get accounts/available-environment --subaccount <your_subaccount_id> --environment kyma --service kymaruntime --plan trial
    -

    Get status running instances. Here we will also get environment ID of running instances.

    btp list accounts/environment-instance --subaccount <your_subaccount_id>
    -

    Delete a running instance if needed.

    btp delete accounts/environment-instance <environment_ID> --subaccount <your_subaccount_id>
    -

    Create Kyma instance.

    btp create accounts/environment-instance --subaccount <your_subaccount_id> --environment kyma --service kymaruntime --plan trial --parameters '{"name": "<your_kyma_instance_name>"}'
    -btp get accounts/environment-instance <environment_ID> --subaccount <your_subaccount_id>
    -

    Create CloudFoundry instance

    btp create accounts/environment-instance --subaccount <your_subaccount_id> --environment cloudfoundry --service cloudfoundry --plan standard --parameters '{"instance_name": "<your_cf_instance_name>"}'
    -btp get accounts/environment-instance <environment_ID> --subaccount <your_subaccount_id>
    -

    Log onto CF to create space DEV by providing API endpoint, Email and Password, which are ready in the subaccount overview page.

    cf login
    -cf create-space DEV
    -

    Install Homebrew

    Refer to installation guide.

    Set environment variables

    export HOMEBREW_BREW_GIT_REMOTE="https://mirrors.ustc.edu.cn/brew.git"
    -export HOMEBREW_CORE_GIT_REMOTE="https://mirrors.ustc.edu.cn/homebrew-core.git"
    -export HOMEBREW_BOTTLE_DOMAIN="https://mirrors.ustc.edu.cn/homebrew-bottles"
    -

    Install Homebrew

    /bin/bash -c "$(curl -fsSL https://github.com/Homebrew/install/raw/HEAD/install.sh)"
    -

    Add below in file ~/.zprofile.

    export HOMEBREW_BREW_GIT_REMOTE="https://mirrors.ustc.edu.cn/brew.git"
    -export HOMEBREW_CORE_GIT_REMOTE="https://mirrors.ustc.edu.cn/homebrew-core.git"
    -export HOMEBREW_BOTTLE_DOMAIN="https://mirrors.ustc.edu.cn/homebrew-bottles"
    -eval "$(/opt/homebrew/bin/brew shellenv)"
    -

    Make it effected.

    source ~/.zprofile
    -

    Install kubetcl

    The kubectl installation guide

    curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/arm64/kubectl"
    -chmod +x ./kubectl
    -sudo mv ./kubectl /usr/local/bin/kubectl
    -sudo chown root: /usr/local/bin/kubectl
    -kubectl version --client
    -

    Install plugin oidc-login.

    curl -fsSLO https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-darwin_arm64.tar.gz
    -tar xvf krew-darwin_arm64.tar.gz
    -./krew-darwin_arm64 install krew
    -

    Add the $HOME/.krew/bin directory to the PATH environment variable by updating ~/.zprofile.

    export PATH=$HOME/.krew/bin:$PATH:$PATH
    -

    Make it effected

    source ~/.zprofile
    -

    Run kubectl krew to check the installation.

    Install/uninstall plugin oidc-login.

    kubectl krew install oidc-login
    -kubectl krew uninstall oidc-login
    -

    SAP Kyma runtime

    In the Overview area of your subaccount open the Link to dashboard link which appears next to the Console URL under the Kyma Environment area. At the top left of the window choose the Clusters Overview drop down and choose your cluster. In the Clusters Overview window choose the Download Kubeconfig for your Kyma runtime to download your KUBECONFIG.

    Add below to ~/.zprofile to set the kubeconfig to an environment variable.

    export KUBECONFIG=<your_full_path_of_kubeconfig_file>
    -

    Make above change effected.

    source ~/.zprofile
    -
    chmod 600 <your_full_path_of_kubeconfig_file>
    -

    Test connection between kubectl and Kyma on BTP.

    kubectl cluster-info
    -

    Install Node.js

    Refer to installation guide

    brew search node
    -brew install node@16
    -brew unlink node
    -brew link node@16
    -node -v
    -

    Install SQLite

    Install SQLite via brew.

    brew search sqlite
    -brew install sqlite
    -

    Add below to ~/.zprofile

    export PATH=/opt/homebrew/opt/sqlite/bin:$PATH
    -

    Make it effected

    source ~/.zprofile
    -

    Install Xcode

    (For macOS) We have to install Command-Line Tools for Xcode, cause some node modules need binary modules (node-gyp).

    xcode-select --install
    -xcode-select --help
    -

    Install Git

    Refer to installation guide.

    brew install git
    -git version
    -

    Install SAPUI5

    Install the UI5 CLI.

    npm search --global @ui5/cli
    -npm install --global @ui5/cli
    -npm list --global @ui5/cli
    -ui5 --version
    -
    npm search --global grunt-cli
    -npm install --global grunt-cli
    -npm list --global grunt-cli
    -

    Install CF CLI

    Refer to installation guide.

    brew install cloudfoundry/tap/cf-cli@8
    -cf --version
    -

    Install CAP Tooling

    See the details in the CAP documentation.

    npm search --global @sap/cds-dk
    -npm install --global @sap/cds-dk
    -npm list --global @sap/cds-dk
    -cds --version
    -

    Install VSCode

    In VS Code, invoke the Command Palette ( View → Command Palette or ⇧⌘P) and type shell command to find the Shell Command: Install 'code' command in PATH.

    Install SAP CDS Language Support extension.

    Install SAP Fiori tools - Extension Pack extension.

    Install Yeoman

    Yeoman is a tool for scaffolding web apps. You’ll need it if you want to carry out the tutorial Add the SAP Launchpad Service.

    npm install --global yo
    -yo --version
    -

    Install Docker

    brew install docker --cask
    -

    Install Helm

    Refer to installation guide

    brew install helm
    -

    Install Paketo(pack)

    Refer to installation guide.

    brew install buildpacks/tap/pack
    -

    Install Rancher Desktop

    Download the Rancher Desktop installer for macOS from the release page. Refer to installation guide.

    Download tutorial

    Go to tutorial root directory and clone the code.

    git clone https://github.com/SAP-samples/cloud-cap-risk-management tutorial
    -

    Initialize the project

    Install required Node.js modules in the app directory cpapp.

    cd app
    -cds init
    -npm install
    -cds watch
    -

    Add files to the project

    Copy the file schema.cds from templates/create-cap-application/db to the db folder of the app. It creates two entities in the namespace sap.ui.riskmanagement: Risks and Mitigations.

    Copy the file risk-service.cds from templates/create-cap-application/srv to the srv folder of the app. It creates a new service RiskService in the namespace sap.ui.riskmanagement. This service exposes two entities: Risks and Mitigations, which are exposing the entities of the database schema we've created in the step before.

    Copy the folder data from templates/create-cap-application/db to the db folder of the app. There are two comma-separated value (CSV) files that contain local data for both the Risks and the Mitigations entities.

    Use Fiori Application Generator (VSCode extension) to generate Risk UI with Fiori element template. The generation will create a risks and a webapp folder with a Component.js file in the app folder of the project.

    Copy the file risks-service-ui.cds from templates/create-ui-fiori-elements/srv to the srv folder of the app. It defines annotations to show a work list with some columns and the data from the service in the Risk UI.

    Edit app/risks/webapp/manifest.json file to make the header fields editable, that is, shows title and description in Risk UI.

    Copy the file risk-service.js from templates/cap-business-logic/srvto the srv folder of the app. It now shows the work list in Risk UI with the columns Priority and Impact with color and an icon, depending on the amount in Impact.

    Use Fiori Application Generator (VSCode extension) to generate Migration UI with Fiori free-style template. The generation will create a migrations and a webapp folder with a Component.js file in the app folder of the project.

    Update file cpapp/app/mitigations/webapp/view/Worklist.view.xml to show Description, Owner, and Timeline columns, as well as in detail object page.

    Till now, our risks and mitigations application have been generated by the SAP Fiori Tools Generator and can be started independently. They are launched without a launch page.

    Copy the file launchpage.html from templates/launchpage/app to the app folder of the app. There are two applications in the launch page with URLs that point to the respective apps. We now see the Mitigations app next to the Risks app on the launch page.

    Open the file srv/risk-service.cds and add role restrictions to entities.

    Copy the file templates/cap-roles/.cdsrc.json to the project directory cpapp. The file defines two users risk.viewer@tester.sap.com and risk.manager@tester.sap.com. The default password can be found in the file .cdsrc.json.

    We will see the CAP server to show above applications via link http://localhost:4004.

    Prepare Kyma Development Environment

    Execute cds version to make sure the package.json is using @sap/cds 6.0.1 or newer and we have @sap/cds-dk 6.0.1 or newer globally installed.

    Create namespace on Kyma.

    kubectl create namespace risk-management
    -

    Switch to the namespace.

    kubectl config set-context --current --namespace risk-management
    + Build CAP Application on Kyma - UPSkilling       

    Build CAP Application on Kyma

    This is the memo of self-practice following the tutorials from Deploy Your CAP Application on SAP BTP Kyma Runtime.

    Prerequisites:

    Tasks:

    • Configure Kyma in SAP Business Technology Platform (SAP BTP) subaccount and prepare Kyma development environment.
    • Create an HDI container for an SAP HANA Cloud instance on Cloud Foundry and create credentials for this SAP HANA cloud instance in Kyma cluster.
    • Develop a business application using SAP Cloud Application Programming Model (CAP).
    • Start on local environment, enhance it with an SAP Fiori UI, add business logic to it, and also roles and authorization check.
    • Add a Helm chart to the application, build docker images, push them to your container registry, and deploy your application to your Kyma cluster on SAP BTP.

    Local environment:

    • Applel Silicon M1 chipset
    • macOS 12.6 (command sw_vers)
    • Nodejs version:
    • CDS version:
    • jq - for JSON processing in CLI (brew install jq)

    SAP BTP subaccount configuration

    For the SAP BTP free tier, the recommendation is as well to use an AWS-based subaccount. Kyma runtime in the free tier is only available on AWS.

    Choose the entitlements for the subdomain:

    • Alert Notification: Standard plan
    • Continuous Integration & Delivery: default (Application) or the trial (Application) or free (Application) plans which are not charged
    • Kyma runtime: any available plan in the list (trial and free are not charged)
    • Launchpad Service: standard (Application) or free (Application)
    • SAP HANA Cloud: hana
    • SAP HANA Schemas & HDI Containers: hdi-shared

    Set up local BTP environment

    Here we will use btp command to set up cloud environment. Details we can refer to help document Working with Environments Using the btp CLI.

    Download BTP CLI package btp-cli-darwin-amd64-<ver_num>.tar.gz via link and unpackage it.

    tar xvf btp-cli-darwin-amd64-<ver_num>.tar.gz
    +

    A new subfolder darwin-amd64 will be created in current path and a bin file btp is under the subfolder. Move file btp to folder /usr/local/bin/.

    sudo mv ./darwin-amd64/btp /usr/local/bin/
    +

    Log on to the subaccount on BTP.

    btp login --url https://cpcli.cf.eu10.hana.ondemand.com --subdomain <your_subdomain> --user <your_registered_email_address>
    +

    Configuration file was stored at /Users/$USER/Library/Application Support/.btp/config.json. In Linux, the configuration file is on /home/$USER/.config/.btp/config.json. We can get current user via command echo $USER.

    Tips:

    • Commands are executed in the target, unless specified otherwise using a parameter. To change the target, use btp target.
    • For an explanation of the targeting mechanism, use btp help target.

    Get the subaccount ID in BTP and we will know that kyma and cloundfoundry are available in current trial account.

    btp list accounts/available-environment --subaccount <your_subaccount_id>
    +

    Get details about an environment available for a subaccount

    btp get accounts/available-environment --subaccount <your_subaccount_id> --environment cloudfoundry --service cloudfoundry --plan standard
    +btp get accounts/available-environment --subaccount <your_subaccount_id> --environment kyma --service kymaruntime --plan trial
    +

    Get status running instances. Here we will also get environment ID of running instances.

    btp list accounts/environment-instance --subaccount <your_subaccount_id>
    +

    Delete a running instance if needed.

    btp delete accounts/environment-instance <environment_ID> --subaccount <your_subaccount_id>
    +

    Create Kyma instance.

    btp create accounts/environment-instance --subaccount <your_subaccount_id> --environment kyma --service kymaruntime --plan trial --parameters '{"name": "<your_kyma_instance_name>"}'
    +btp get accounts/environment-instance <environment_ID> --subaccount <your_subaccount_id>
    +

    Create CloudFoundry instance

    btp create accounts/environment-instance --subaccount <your_subaccount_id> --environment cloudfoundry --service cloudfoundry --plan standard --parameters '{"instance_name": "<your_cf_instance_name>"}'
    +btp get accounts/environment-instance <environment_ID> --subaccount <your_subaccount_id>
    +

    Log onto CF to create space DEV by providing API endpoint, Email and Password, which are ready in the subaccount overview page.

    cf login
    +cf create-space DEV
    +

    Install Homebrew

    Refer to installation guide.

    Set environment variables

    export HOMEBREW_BREW_GIT_REMOTE="https://mirrors.ustc.edu.cn/brew.git"
    +export HOMEBREW_CORE_GIT_REMOTE="https://mirrors.ustc.edu.cn/homebrew-core.git"
    +export HOMEBREW_BOTTLE_DOMAIN="https://mirrors.ustc.edu.cn/homebrew-bottles"
    +

    Install Homebrew

    /bin/bash -c "$(curl -fsSL https://github.com/Homebrew/install/raw/HEAD/install.sh)"
    +

    Add below in file ~/.zprofile.

    export HOMEBREW_BREW_GIT_REMOTE="https://mirrors.ustc.edu.cn/brew.git"
    +export HOMEBREW_CORE_GIT_REMOTE="https://mirrors.ustc.edu.cn/homebrew-core.git"
    +export HOMEBREW_BOTTLE_DOMAIN="https://mirrors.ustc.edu.cn/homebrew-bottles"
    +eval "$(/opt/homebrew/bin/brew shellenv)"
    +

    Make it effected.

    source ~/.zprofile
    +

    Install kubetcl

    The kubectl installation guide

    curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/arm64/kubectl"
    +chmod +x ./kubectl
    +sudo mv ./kubectl /usr/local/bin/kubectl
    +sudo chown root: /usr/local/bin/kubectl
    +kubectl version --client
    +

    Install plugin oidc-login.

    curl -fsSLO https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-darwin_arm64.tar.gz
    +tar xvf krew-darwin_arm64.tar.gz
    +./krew-darwin_arm64 install krew
    +

    Add the $HOME/.krew/bin directory to the PATH environment variable by updating ~/.zprofile.

    export PATH=$HOME/.krew/bin:$PATH:$PATH
    +

    Make it effected

    source ~/.zprofile
    +

    Run kubectl krew to check the installation.

    Install/uninstall plugin oidc-login.

    kubectl krew install oidc-login
    +kubectl krew uninstall oidc-login
    +

    SAP Kyma runtime

    In the Overview area of your subaccount open the Link to dashboard link which appears next to the Console URL under the Kyma Environment area. At the top left of the window choose the Clusters Overview drop down and choose your cluster. In the Clusters Overview window choose the Download Kubeconfig for your Kyma runtime to download your KUBECONFIG.

    Add below to ~/.zprofile to set the kubeconfig to an environment variable.

    export KUBECONFIG=<your_full_path_of_kubeconfig_file>
    +

    Make above change effected.

    source ~/.zprofile
    +
    chmod 600 <your_full_path_of_kubeconfig_file>
    +

    Test connection between kubectl and Kyma on BTP.

    kubectl cluster-info
    +

    Install Node.js

    Refer to installation guide

    brew search node
    +brew install node@16
    +brew unlink node
    +brew link node@16
    +node -v
    +

    Install SQLite

    Install SQLite via brew.

    brew search sqlite
    +brew install sqlite
    +

    Add below to ~/.zprofile

    export PATH=/opt/homebrew/opt/sqlite/bin:$PATH
    +

    Make it effected

    source ~/.zprofile
    +

    Install Xcode

    (For macOS) We have to install Command-Line Tools for Xcode, cause some node modules need binary modules (node-gyp).

    xcode-select --install
    +xcode-select --help
    +

    Install Git

    Refer to installation guide.

    brew install git
    +git version
    +

    Install SAPUI5

    Install the UI5 CLI.

    npm search --global @ui5/cli
    +npm install --global @ui5/cli
    +npm list --global @ui5/cli
    +ui5 --version
    +
    npm search --global grunt-cli
    +npm install --global grunt-cli
    +npm list --global grunt-cli
    +

    Install CF CLI

    Refer to installation guide.

    brew install cloudfoundry/tap/cf-cli@8
    +cf --version
    +

    Install CAP Tooling

    See the details in the CAP documentation.

    npm search --global @sap/cds-dk
    +npm install --global @sap/cds-dk
    +npm list --global @sap/cds-dk
    +cds --version
    +

    Install VSCode

    In VS Code, invoke the Command Palette ( View → Command Palette or ⇧⌘P) and type shell command to find the Shell Command: Install 'code' command in PATH.

    Install SAP CDS Language Support extension.

    Install SAP Fiori tools - Extension Pack extension.

    Install Yeoman

    Yeoman is a tool for scaffolding web apps. You’ll need it if you want to carry out the tutorial Add the SAP Launchpad Service.

    npm install --global yo
    +yo --version
    +

    Install Docker

    brew install docker --cask
    +

    Install Helm

    Refer to installation guide

    brew install helm
    +

    Install Paketo(pack)

    Refer to installation guide.

    brew install buildpacks/tap/pack
    +

    Install Rancher Desktop

    Download the Rancher Desktop installer for macOS from the release page. Refer to installation guide.

    Download tutorial

    Go to tutorial root directory and clone the code.

    git clone https://github.com/SAP-samples/cloud-cap-risk-management tutorial
    +

    Initialize the project

    Install required Node.js modules in the app directory cpapp.

    cd app
    +cds init
    +npm install
    +cds watch
    +

    Add files to the project

    Copy the file schema.cds from templates/create-cap-application/db to the db folder of the app. It creates two entities in the namespace sap.ui.riskmanagement: Risks and Mitigations.

    Copy the file risk-service.cds from templates/create-cap-application/srv to the srv folder of the app. It creates a new service RiskService in the namespace sap.ui.riskmanagement. This service exposes two entities: Risks and Mitigations, which are exposing the entities of the database schema we've created in the step before.

    Copy the folder data from templates/create-cap-application/db to the db folder of the app. There are two comma-separated value (CSV) files that contain local data for both the Risks and the Mitigations entities.

    Use Fiori Application Generator (VSCode extension) to generate Risk UI with Fiori element template. The generation will create a risks and a webapp folder with a Component.js file in the app folder of the project.

    Copy the file risks-service-ui.cds from templates/create-ui-fiori-elements/srv to the srv folder of the app. It defines annotations to show a work list with some columns and the data from the service in the Risk UI.

    Edit app/risks/webapp/manifest.json file to make the header fields editable, that is, shows title and description in Risk UI.

    Copy the file risk-service.js from templates/cap-business-logic/srvto the srv folder of the app. It now shows the work list in Risk UI with the columns Priority and Impact with color and an icon, depending on the amount in Impact.

    Use Fiori Application Generator (VSCode extension) to generate Migration UI with Fiori free-style template. The generation will create a migrations and a webapp folder with a Component.js file in the app folder of the project.

    Update file cpapp/app/mitigations/webapp/view/Worklist.view.xml to show Description, Owner, and Timeline columns, as well as in detail object page.

    Till now, our risks and mitigations application have been generated by the SAP Fiori Tools Generator and can be started independently. They are launched without a launch page.

    Copy the file launchpage.html from templates/launchpage/app to the app folder of the app. There are two applications in the launch page with URLs that point to the respective apps. We now see the Mitigations app next to the Risks app on the launch page.

    Open the file srv/risk-service.cds and add role restrictions to entities.

    Copy the file templates/cap-roles/.cdsrc.json to the project directory cpapp. The file defines two users risk.viewer@tester.sap.com and risk.manager@tester.sap.com. The default password can be found in the file .cdsrc.json.

    We will see the CAP server to show above applications via link http://localhost:4004.

    Prepare Kyma Development Environment

    Execute cds version to make sure the package.json is using @sap/cds 6.0.1 or newer and we have @sap/cds-dk 6.0.1 or newer globally installed.

    Create namespace on Kyma.

    kubectl create namespace risk-management
    +

    Switch to the namespace.

    kubectl config set-context --current --namespace risk-management
     

    Create container registry secret.

    Copy the folder scripts from templates/Kyma-Prepare-Dev-Environment to the project root folder cpapp.

    In the root folder cpapp of the project, run the script to create the secret.

    ./scripts/create-container-registry-secret.sh
     

    Need provide below input:

    docker-server=https://registry-1.docker.io
     docker-username=<your_registered_docker_username>
     docker-email=<your_registered_docker_email>
     docker-password=<your_api_token>
    -

    Verify

    kubectl get secret
    -

    Set Up SAP HANA Cloud for Kyma

    Add SAP HANA support to your project. This adds the db module for SAP HANA access to the package.json file. Execute the command below in the project root directory cpapp.

    cds add hana --for production
    -

    Verify the access to both CF and Kyma by executing below commands.

    cf login
    -
    kubectl cluster-info
    -

    Create HANA Cloud instance cpapp-db in CloudFoundry DEV namespace. The admin user id is DBADMIN.

    In the root folder cpapp of the project, execute:

    ./scripts/create-db-secret.sh cpapp-db
    -

    Get the host name pattern of the cluster with the following command. Result looks like *.c-<xyz123>.sap.kyma.ondemand.com.

    kubectl get gateway -n kyma-system kyma-gateway -o jsonpath='{.spec.servers[0].hosts[0]}'
    -

    The script will:

    • Create service key cpapp-db-key for HANA Cloud service instance cpapp-db as <your_btp_registered_email>.
    • Create Kubernetes secret cpapp-db for HANA DB instance. View it using kubectl get secret cpapp-db -o yaml.

    User Authentication and Authorization (XSUAA) Setup

    Set up XSUAA.

    cds add xsuaa --for production
    -

    Above command will do:

    • Adds the XSUAA service to the package.json file of the project
    • Creates the XSUAA security configuration xs-security.json for the project

    Add Helm Chart

    Add Helm Chart.

    cds add helm
    -

    Get docker server URL by command:

    cat ~/.docker/config.json
    -

    Get the image pull secret for container registry. In the demo, it's container-registry.

    kubectl get secret
    -

    Get the host name pattern of the cluster.

    kubectl get gateway -n kyma-system kyma-gateway -o jsonpath='{.spec.servers[0].hosts[0]}'
    +

    Verify

    kubectl get secret
    +

    Set Up SAP HANA Cloud for Kyma

    Add SAP HANA support to your project. This adds the db module for SAP HANA access to the package.json file. Execute the command below in the project root directory cpapp.

    cds add hana --for production
    +

    Verify the access to both CF and Kyma by executing below commands.

    cf login
    +
    kubectl cluster-info
    +

    Create HANA Cloud instance cpapp-db in CloudFoundry DEV namespace. The admin user id is DBADMIN.

    In the root folder cpapp of the project, execute:

    ./scripts/create-db-secret.sh cpapp-db
    +

    Get the host name pattern of the cluster with the following command. Result looks like *.c-<xyz123>.sap.kyma.ondemand.com.

    kubectl get gateway -n kyma-system kyma-gateway -o jsonpath='{.spec.servers[0].hosts[0]}'
    +

    The script will:

    • Create service key cpapp-db-key for HANA Cloud service instance cpapp-db as <your_btp_registered_email>.
    • Create Kubernetes secret cpapp-db for HANA DB instance. View it using kubectl get secret cpapp-db -o yaml.

    User Authentication and Authorization (XSUAA) Setup

    Set up XSUAA.

    cds add xsuaa --for production
    +

    Above command will do:

    • Adds the XSUAA service to the package.json file of the project
    • Creates the XSUAA security configuration xs-security.json for the project

    Add Helm Chart

    Add Helm Chart.

    cds add helm
    +

    Get docker server URL by command:

    cat ~/.docker/config.json
    +

    Get the image pull secret for container registry. In the demo, it's container-registry.

    kubectl get secret
    +

    Get the host name pattern of the cluster.

    kubectl get gateway -n kyma-system kyma-gateway -o jsonpath='{.spec.servers[0].hosts[0]}'
     

    Open the file chart/values.yaml:

    • Replace the placeholder <your-container-registry> with docker server URL https://docker.io/.
    • Set imagePullSecret with value name: container-registry.
    • Add host name of the cluster without leading *..
    • Add the binding db pointing to the SAP HANA Cloud instance secret cpapp-db.
    • Point the binding hana of the SAP HANA Cloud instance secret cpapp-db.
    • Add the Authorization and Trust Management service to allow user login.

    Deploy CAP Application to Kyma

    Build docker image.

    CONTAINER_REGISTRY=https://index.docker.io/v1
     CONTAINER_REGISTRY=https://registry-1.docker.io/yuhuihu
     CONTAINER_REGISTRY=yuhuihu
    -

    CAP build.

    cds build --production
    -

    Build CAP service.

    pack build $CONTAINER_REGISTRY/cpapp-srv --path gen/srv \
    - --buildpack gcr.io/paketo-buildpacks/nodejs \
    - --builder paketobuildpacks/builder:base
    -
    \ No newline at end of file +

    CAP build.

    cds build --production
    +

    Build CAP service.

    pack build $CONTAINER_REGISTRY/cpapp-srv --path gen/srv \
    + --buildpack gcr.io/paketo-buildpacks/nodejs \
    + --builder paketobuildpacks/builder:base
    +
    Back to top
    \ No newline at end of file diff --git a/k8s/index.html b/k8s/index.html index 2275e3ea..7b00413d 100644 --- a/k8s/index.html +++ b/k8s/index.html @@ -1 +1 @@ - Index - UPSkilling

    我的Kubernetes学习心得

    作为一种开源的容器编排系统,Kubernetes 为运行在容器中的应用程序提供了一种管理方式。Kubernetes 具有很多强大的功能,例如自动化部署、负载均衡、自动扩展、自动恢复等。

    公司内部的云平台也在从Cloud Foundry环境开始向基于Kubernetes的Kyma环境延展,再加上各种媒体对Kubernetes的介绍,是我开始了解Kubernetes的外部动因。

    内部动因,则是源于2022年春节期间参加了公司内部的一周Kubernetes基础培训,因为授课内容是英语,所以有很多细节在培训中是get不到的,主要还是语言能力不够强。当时的目标只是跟着完成讲师课堂演示。

    从3月开始,我在网上了参考了别人的Kubernetes的学习心得和路线图,决定以CKA(certificate of Kubernetes administration)认证作为当前学习的目标,利用B站的视频,参考官方文档,开始从头开始学习Kubernetes的基础知识。

    下面准备CKA考试的一些心得体会:

    1. 学习 Kubernetes 前,需要了解容器技术和 Docker,或者说要有容器化的基本概念和思想方法,因为 Kubernetes 是基于容器技术构建的。
    2. 学习 Kubernetes 时,需要掌握其核心概念,例如 Pod、ReplicaSet、Deployment、Service 等。这些概念是理解 Kubernetes 的基础,也是后续实际应用中的重要部分。
    3. 学习 Kubernetes 时,需要掌握 yaml 文件的编写方法,特别是那些基本资源的yaml文件,要能做到不借助帮助文档就能写出框架,否则考试时做不完题目的。
    4. 学习 Kubernetes 时,需要掌握 kubectl 命令的使用,常用资源相关的命令,也要做到不借助帮助文档就能写出,否则考试时也是做不完题目的。
    5. 学习 Kubernetes 时,需要掌握其网络和存储配置,例如 Service、Ingress、PersistentVolume、PersistentVolumeClaim 等,这些都是考试重点内容,要熟悉yaml特性,能按不同的要求进行拓展和变更。
    6. 部署和管理 Kubernetes 集群也是一个重点,我是在阿里云上买了3个ECS作为实验环境。

    我的CKA的笔记分中文和英文两种。英文笔记是基于第一次参加公司培训的知识结构做的,在备考过程中逐步完善的。中文笔记是在2023年4月份基于英文笔记自己翻译过来的,并发布在我的知乎专栏上,翻译过程还是比较难的,很多英语内容找不到合适的中文表达方式,不过对于计算机行业来讲,使用英语阅读专业资料应该是一个共识。

    参考笔记,并完成笔记中的练习,再熟练使用yaml文件和kubectl命令,通过考试没什么困难。

    \ No newline at end of file + Index - UPSkilling

    我的Kubernetes学习心得

    作为一种开源的容器编排系统,Kubernetes 为运行在容器中的应用程序提供了一种管理方式。Kubernetes 具有很多强大的功能,例如自动化部署、负载均衡、自动扩展、自动恢复等。

    公司内部的云平台也在从Cloud Foundry环境开始向基于Kubernetes的Kyma环境延展,再加上各种媒体对Kubernetes的介绍,是我开始了解Kubernetes的外部动因。

    内部动因,则是源于2022年春节期间参加了公司内部的一周Kubernetes基础培训,因为授课内容是英语,所以有很多细节在培训中是get不到的,主要还是语言能力不够强。当时的目标只是跟着完成讲师课堂演示。

    从3月开始,我在网上了参考了别人的Kubernetes的学习心得和路线图,决定以CKA(certificate of Kubernetes administration)认证作为当前学习的目标,利用B站的视频,参考官方文档,开始从头开始学习Kubernetes的基础知识。

    下面准备CKA考试的一些心得体会:

    1. 学习 Kubernetes 前,需要了解容器技术和 Docker,或者说要有容器化的基本概念和思想方法,因为 Kubernetes 是基于容器技术构建的。
    2. 学习 Kubernetes 时,需要掌握其核心概念,例如 Pod、ReplicaSet、Deployment、Service 等。这些概念是理解 Kubernetes 的基础,也是后续实际应用中的重要部分。
    3. 学习 Kubernetes 时,需要掌握 yaml 文件的编写方法,特别是那些基本资源的yaml文件,要能做到不借助帮助文档就能写出框架,否则考试时做不完题目的。
    4. 学习 Kubernetes 时,需要掌握 kubectl 命令的使用,常用资源相关的命令,也要做到不借助帮助文档就能写出,否则考试时也是做不完题目的。
    5. 学习 Kubernetes 时,需要掌握其网络和存储配置,例如 Service、Ingress、PersistentVolume、PersistentVolumeClaim 等,这些都是考试重点内容,要熟悉yaml特性,能按不同的要求进行拓展和变更。
    6. 部署和管理 Kubernetes 集群也是一个重点,我是在阿里云上买了3个ECS作为实验环境。

    我的CKA的笔记分中文和英文两种。英文笔记是基于第一次参加公司培训的知识结构做的,在备考过程中逐步完善的。中文笔记是在2023年4月份基于英文笔记自己翻译过来的,并发布在我的知乎专栏上,翻译过程还是比较难的,很多英语内容找不到合适的中文表达方式,不过对于计算机行业来讲,使用英语阅读专业资料应该是一个共识。

    参考笔记,并完成笔记中的练习,再熟练使用yaml文件和kubectl命令,通过考试没什么困难。

    Back to top
    \ No newline at end of file diff --git a/linux/Administration/01/index.html b/linux/Administration/01/index.html index 3476ebb7..a0bbd0b0 100644 --- a/linux/Administration/01/index.html +++ b/linux/Administration/01/index.html @@ -1,85 +1,85 @@ - Linux File System Overview - UPSkilling

    Linux File System Overview

    Linux File System Overview

    Filesystem Hierarchy Standard (FHS), which is part of the LSB (Linux Standards Base) specifications.

    The Root directory "/". Refers to the highest layer of the file system tree. This root partition is mounted first at system boot. All programs that are run at system startup must be in this partition.

    The following directories must be in the root partition:

    • /bin - User binaries. 基本程序
      • Contains executables required when no other file systems are mounted. For example, programs required for system booting, working with files and configuration.
      • /bin/bash - The bash shell
      • /bin/cat - Display file contents
      • /bin/cp - Copy files
      • /bin/dd - Copy files byte-wise
      • /bin/gzip - Compress files
      • /bin/mount - Mount file systems
      • /bin/rm - Delete files
      • /bin/vi - Edit files
    • /sbin - System binaries. 系统程序
      • Contains programs important for system administration. 存放系统管理的程序
      • Typically are intended to be run by the root user and therefore it is not in the regular users path. 默认是root用户有权限执行
      • Some important files:
        • /sbin/yast - Administration tool
        • /sbin/fdisk* - Modifies partitions
        • /sbin/fsck* - File system check 不能在运行的系统上面直接执行fsck,损坏根文件系统,需要umount
        • /sbin/mkfs - Creates file systems
        • /sbin/shutdown - Shuts down the system
    • /dev - Device files
      • Each system hardware component is represented (except network cards, which are kernel modules). 以太网卡是内核模块,其他硬件都以设备dev的方式展现
      • Applications read from and write to these files to address hardware components.
      • Two kinds of device files:
        • Character-oriented – Sequential devices (printer, tape and mouse) 字符设备
        • Block-oriented – Hard disks and DVDs 块设备
      • Connections to device drivers are implemented in the kernel using channels called major device numbers. 与设备驱动程序的连接通过内核中称为主设备号的通道实现。
      • When using ls -l the file size is replaced with the device numbers, such as 8, 0.
      • In the past these files were created manually using the mknod command. Today they are created automatically (by udev) when the devices are discovered by the kernel.
      • Some important device files:
        • Null device: - /dev/null
        • Zero device: - /dev/zero
        • System Console: - /dev/console
        • Virtual Terminal: - /dev/tty1
        • Serial ports - /dev/ttyS0
        • Parallel port: - /dev/lp0
        • Floppy disk drive: - /dev/fd0
        • Hard drive: - /dev/sda
        • Hard disk partition: - /dev/sda1
        • CD-ROM drive: - /dev/scd0
    • /etc - Configuration files
      • Contains system and services configuration files. 存放系统和服务的配置文件
      • Most of these files are ASCII files. 大部分都是ASCII文件
      • Normal users can read most of these by default. This can be a security issue since some of these files contain passwords so it important that these files are only readable by the rootuser. 普通用户可以默认读取其中的大部分内容。 这可能是一个安全问题,因为其中一些文件包含密码,因此重要的是这些文件只能由root用户读取
      • No executables can be put here according to the FHS, however subdirectories may contain shell scripts. 根据FHS,此处不能放置任何可执行文件,但子目录可能包含shell脚本。
      • Almost every installed service has at least one configuration file in /etc or a subdirectory. 几乎每个已安装的服务在/ etc或子目录中至少有一个配置文件。
      • Some important configuration files:
        • /etc/SuSE-release - Version of installed system
        • /etc/DIR_COLORS - Colors for the ls command
        • /etc/fstab - For file systems to be mounted
        • /etc/profile - Shell login script
        • /etc/passwd - User database, except passwords
        • /etc/shadow - Password and password info
        • /etc/group - Database of user groups
        • /etc/cups/* - For the CUPS printing system (CUPS=Common UNIX Printing System)
        • /etc/hosts - Host names to IP addresses
        • /etc/motd - Message after login
        • /etc/issue - Message before login
        • /etc/sysconfig/* - System configuration files
    • /lib - Libraries.
      • Many programs have common functions they need. The functions can be kept in a shared library.
      • Libraries are called shared objects and end with the .so extension. 共享库
      • Libraries in /lib are used by programs in /bin and /sbin.
      • There are additional libraries in subdirectories.
      • Kernel modules are located in /lib/modules.
    • /lib64 - 64-Bit Libraries. Similar to the /lib directory.
      • This is an architecture dependent directory.
      • Some systems support different binary formats and keep different versions of the same shared library.
    • /usr - Contains application programs, graphical interface files, libraries, local programs, documentation and more.
      • /usr means Unix System Resources. Examples:
      • /usr/X11R6/ - X Window System Files
      • /usr/bin/ - Almost all executables
      • /usr/lib/ - Libraries and application directories
      • /usr/local/ - Locally installed programs (i.e. on local system if /usr is mounted from the network). The content is not overwritten by system updates. 下面3个目录在初始安装后是空的
        • /usr/local/bin-
        • /usr/local/sbin-
        • /usr/local/lib-
      • /usr/sbin/ - System administration programs
      • /usr/share/doc/ - Documentation
      • /usr/src/ - Source code of kernel and programs
        • /usr/src/linux-
      • /usr/share/man/ - Manual pages
    • /opt - Optional Application Directory
      • Where optional or third party applications that are not considered to be “part of the distribution” store their static files.
      • Applications considered to be “part of the distribution” are usually installed under /usr/lib/ rather than /opt.
      • At installation a directory is created for each application's files with the name of the application. Example:
        • /opt/novell-
    • /boot - The Boot Directory
      • /boot/grub2 - Contains static boot loader files for GRUB2. (GRUB = Grand Unified Boot Loader)
      • Contains the kernel and initrd file identified with the links vmlinuz and initrd.
    • /root - Administrator's Home Directory
      • The root user's home directory. Not under /home with regular users' home directories.
      • Needs to be in the root partition so that root can always log in with his configured environment.
    • /home - User Directories
      • Every system user has an assigned file area which becomes the current working directory after log in. By default they exist in /home.
      • The files and directories in /home could be in a separate partition or on another computer on the network.
      • The user profile and configuration files are found here:
        • .profile - Private user login script
        • .bashrc - Configuration file for bash
        • .bash_history - Previous commands run in bash
    • /run/media/<user>/* - Mount Point for Removable Media
      • SLE 12 creates directories here for mounting removable media. The name depends on the device that is mounted/discovered. Examples:
        • /run/media/media_name/ (Created if labeled media is inserted)
        • /run/media/cdrom/-
        • /run/media/dvd/-
        • /run/media/usbdisk/-
    • /mnt - Temporarily Mounted File Systems 文件系统临时挂载点
      • Standard directory for integrating file systems that are used temporarily.
      • File systems are mounted using the mount command and removed using the umount command.
      • Subdirectories do not exist by default and are not automatically created.
    • /srv - Service Data Directories
      • Contains subdirectories for various services. Examples: 存放各种服务的数据
        • /srv/www - for the Apache Web Server
        • /srv/ftp - for an FTP server
    • /var - Variable Files
      • Contains files that can be modified while the system is running. 在系统运行过程中会被修改的文件
      • Important subdirectories:
        • /var/lib/ - Variable libraries, like databases 可变库文件
        • /var/log/ - Services log files 日志文件
        • /var/run/ - Information on running processes 运行中的线程的信息
        • /var/spool/ - Queues (printers, email)
          • /var/spool/mail-
          • /var/spool/cron-
        • /var/lock/ - Lock files for multiuser access
        • /var/cache-
        • /var/mail-
    • /tmp - Temporary Area
      • Where programs create temporary files while they are running
    • /proc - Process Files
      • A virtual file system that exists only in memory and is used to display the current state of processes running on the system. (Takes no space - file size always 0) 虚拟文件系统,不占间,大小* 始终零,显示当前进程的状态信息
      • Directories containing information about individual processes are named according to the PID number of the process.
      • Some values can be modified to change how things are running in real time. Any changes made are lost at reboot. Examples: 有些值可以临时在线更改生效,但重启后丢失
        • /proc/cpuinfo/ - Processor information
        • /proc/dma/ - Use of DMA ports
        • /proc/interrupts/ - Use of interrupts
        • /proc/ioports/ - Use of I/O ports
        • /proc/filesystems/ - File system formats the kernel knows
        • /proc/modules/ - Active modules
        • /proc/mounts/ - Mounted file systems
        • /proc/net/* - Network information and statistics
        • /proc/partitions/ - Existing partitions
        • /proc/bus/pci/ - Connected PCI devices
        • /proc/bus/scsi/ - Connected SCSI devices
        • /proc/sys/* - System and kernel information
        • /proc/version - Kernel version
    • /sys - System Information Directory A virtual file system that exists only in memory. Takes no space so file size always 0 虚拟文件系统 Provides information on:
      • hardware buses
      • hardware devices
      • active devices
      • drivers

    Lab: Explore Filesystem Hierarchy

    Show the directory structure of the /data folder hierarchy of current logon user:

    mySUSE:~ # tree /data
    + Linux File System Overview - UPSkilling       

    Linux File System Overview

    Linux File System Overview

    Filesystem Hierarchy Standard (FHS), which is part of the LSB (Linux Standards Base) specifications.

    The Root directory "/". Refers to the highest layer of the file system tree. This root partition is mounted first at system boot. All programs that are run at system startup must be in this partition.

    The following directories must be in the root partition:

    • /bin - User binaries. 基本程序
      • Contains executables required when no other file systems are mounted. For example, programs required for system booting, working with files and configuration.
      • /bin/bash - The bash shell
      • /bin/cat - Display file contents
      • /bin/cp - Copy files
      • /bin/dd - Copy files byte-wise
      • /bin/gzip - Compress files
      • /bin/mount - Mount file systems
      • /bin/rm - Delete files
      • /bin/vi - Edit files
    • /sbin - System binaries. 系统程序
      • Contains programs important for system administration. 存放系统管理的程序
      • Typically are intended to be run by the root user and therefore it is not in the regular users path. 默认是root用户有权限执行
      • Some important files:
        • /sbin/yast - Administration tool
        • /sbin/fdisk* - Modifies partitions
        • /sbin/fsck* - File system check 不能在运行的系统上面直接执行fsck,损坏根文件系统,需要umount
        • /sbin/mkfs - Creates file systems
        • /sbin/shutdown - Shuts down the system
    • /dev - Device files
      • Each system hardware component is represented (except network cards, which are kernel modules). 以太网卡是内核模块,其他硬件都以设备dev的方式展现
      • Applications read from and write to these files to address hardware components.
      • Two kinds of device files:
        • Character-oriented – Sequential devices (printer, tape and mouse) 字符设备
        • Block-oriented – Hard disks and DVDs 块设备
      • Connections to device drivers are implemented in the kernel using channels called major device numbers. 与设备驱动程序的连接通过内核中称为主设备号的通道实现。
      • When using ls -l the file size is replaced with the device numbers, such as 8, 0.
      • In the past these files were created manually using the mknod command. Today they are created automatically (by udev) when the devices are discovered by the kernel.
      • Some important device files:
        • Null device: - /dev/null
        • Zero device: - /dev/zero
        • System Console: - /dev/console
        • Virtual Terminal: - /dev/tty1
        • Serial ports - /dev/ttyS0
        • Parallel port: - /dev/lp0
        • Floppy disk drive: - /dev/fd0
        • Hard drive: - /dev/sda
        • Hard disk partition: - /dev/sda1
        • CD-ROM drive: - /dev/scd0
    • /etc - Configuration files
      • Contains system and services configuration files. 存放系统和服务的配置文件
      • Most of these files are ASCII files. 大部分都是ASCII文件
      • Normal users can read most of these by default. This can be a security issue since some of these files contain passwords so it important that these files are only readable by the rootuser. 普通用户可以默认读取其中的大部分内容。 这可能是一个安全问题,因为其中一些文件包含密码,因此重要的是这些文件只能由root用户读取
      • No executables can be put here according to the FHS, however subdirectories may contain shell scripts. 根据FHS,此处不能放置任何可执行文件,但子目录可能包含shell脚本。
      • Almost every installed service has at least one configuration file in /etc or a subdirectory. 几乎每个已安装的服务在/ etc或子目录中至少有一个配置文件。
      • Some important configuration files:
        • /etc/SuSE-release - Version of installed system
        • /etc/DIR_COLORS - Colors for the ls command
        • /etc/fstab - For file systems to be mounted
        • /etc/profile - Shell login script
        • /etc/passwd - User database, except passwords
        • /etc/shadow - Password and password info
        • /etc/group - Database of user groups
        • /etc/cups/* - For the CUPS printing system (CUPS=Common UNIX Printing System)
        • /etc/hosts - Host names to IP addresses
        • /etc/motd - Message after login
        • /etc/issue - Message before login
        • /etc/sysconfig/* - System configuration files
    • /lib - Libraries.
      • Many programs have common functions they need. The functions can be kept in a shared library.
      • Libraries are called shared objects and end with the .so extension. 共享库
      • Libraries in /lib are used by programs in /bin and /sbin.
      • There are additional libraries in subdirectories.
      • Kernel modules are located in /lib/modules.
    • /lib64 - 64-Bit Libraries. Similar to the /lib directory.
      • This is an architecture dependent directory.
      • Some systems support different binary formats and keep different versions of the same shared library.
    • /usr - Contains application programs, graphical interface files, libraries, local programs, documentation and more.
      • /usr means Unix System Resources. Examples:
      • /usr/X11R6/ - X Window System Files
      • /usr/bin/ - Almost all executables
      • /usr/lib/ - Libraries and application directories
      • /usr/local/ - Locally installed programs (i.e. on local system if /usr is mounted from the network). The content is not overwritten by system updates. 下面3个目录在初始安装后是空的
        • /usr/local/bin-
        • /usr/local/sbin-
        • /usr/local/lib-
      • /usr/sbin/ - System administration programs
      • /usr/share/doc/ - Documentation
      • /usr/src/ - Source code of kernel and programs
        • /usr/src/linux-
      • /usr/share/man/ - Manual pages
    • /opt - Optional Application Directory
      • Where optional or third party applications that are not considered to be “part of the distribution” store their static files.
      • Applications considered to be “part of the distribution” are usually installed under /usr/lib/ rather than /opt.
      • At installation a directory is created for each application's files with the name of the application. Example:
        • /opt/novell-
    • /boot - The Boot Directory
      • /boot/grub2 - Contains static boot loader files for GRUB2. (GRUB = Grand Unified Boot Loader)
      • Contains the kernel and initrd file identified with the links vmlinuz and initrd.
    • /root - Administrator's Home Directory
      • The root user's home directory. Not under /home with regular users' home directories.
      • Needs to be in the root partition so that root can always log in with his configured environment.
    • /home - User Directories
      • Every system user has an assigned file area which becomes the current working directory after log in. By default they exist in /home.
      • The files and directories in /home could be in a separate partition or on another computer on the network.
      • The user profile and configuration files are found here:
        • .profile - Private user login script
        • .bashrc - Configuration file for bash
        • .bash_history - Previous commands run in bash
    • /run/media/<user>/* - Mount Point for Removable Media
      • SLE 12 creates directories here for mounting removable media. The name depends on the device that is mounted/discovered. Examples:
        • /run/media/media_name/ (Created if labeled media is inserted)
        • /run/media/cdrom/-
        • /run/media/dvd/-
        • /run/media/usbdisk/-
    • /mnt - Temporarily Mounted File Systems 文件系统临时挂载点
      • Standard directory for integrating file systems that are used temporarily.
      • File systems are mounted using the mount command and removed using the umount command.
      • Subdirectories do not exist by default and are not automatically created.
    • /srv - Service Data Directories
      • Contains subdirectories for various services. Examples: 存放各种服务的数据
        • /srv/www - for the Apache Web Server
        • /srv/ftp - for an FTP server
    • /var - Variable Files
      • Contains files that can be modified while the system is running. 在系统运行过程中会被修改的文件
      • Important subdirectories:
        • /var/lib/ - Variable libraries, like databases 可变库文件
        • /var/log/ - Services log files 日志文件
        • /var/run/ - Information on running processes 运行中的线程的信息
        • /var/spool/ - Queues (printers, email)
          • /var/spool/mail-
          • /var/spool/cron-
        • /var/lock/ - Lock files for multiuser access
        • /var/cache-
        • /var/mail-
    • /tmp - Temporary Area
      • Where programs create temporary files while they are running
    • /proc - Process Files
      • A virtual file system that exists only in memory and is used to display the current state of processes running on the system. (Takes no space - file size always 0) 虚拟文件系统,不占间,大小* 始终零,显示当前进程的状态信息
      • Directories containing information about individual processes are named according to the PID number of the process.
      • Some values can be modified to change how things are running in real time. Any changes made are lost at reboot. Examples: 有些值可以临时在线更改生效,但重启后丢失
        • /proc/cpuinfo/ - Processor information
        • /proc/dma/ - Use of DMA ports
        • /proc/interrupts/ - Use of interrupts
        • /proc/ioports/ - Use of I/O ports
        • /proc/filesystems/ - File system formats the kernel knows
        • /proc/modules/ - Active modules
        • /proc/mounts/ - Mounted file systems
        • /proc/net/* - Network information and statistics
        • /proc/partitions/ - Existing partitions
        • /proc/bus/pci/ - Connected PCI devices
        • /proc/bus/scsi/ - Connected SCSI devices
        • /proc/sys/* - System and kernel information
        • /proc/version - Kernel version
    • /sys - System Information Directory A virtual file system that exists only in memory. Takes no space so file size always 0 虚拟文件系统 Provides information on:
      • hardware buses
      • hardware devices
      • active devices
      • drivers

    Lab: Explore Filesystem Hierarchy

    Show the directory structure of the /data folder hierarchy of current logon user:

    mySUSE:~ # tree /data
     /data
    -└── linktype
    -    ├── file
    -    ├── hardlinkfile1
    -    ├── hardlinkfile2
    -    ├── symlinkfile1 -> file
    -    ├── symlinkfile1-1 -> symlinkfile1
    -    └── symlinkfile2 -> file
    -

    Show only directories in the /data hierarchhy, not the files in them:

    mySUSE:~ # tree -d /data
    +└── linktype
    +    ├── file
    +    ├── hardlinkfile1
    +    ├── hardlinkfile2
    +    ├── symlinkfile1 -> file
    +    ├── symlinkfile1-1 -> symlinkfile1
    +    └── symlinkfile2 -> file
    +

    Show only directories in the /data hierarchhy, not the files in them:

    mySUSE:~ # tree -d /data
     /data
    -└── linktype
    -

    Show the files and directories in the /data hierarchy, including the full path and filename of each object.

    mySUSE:~ # tree -f /data
    +└── linktype
    +

    Show the files and directories in the /data hierarchy, including the full path and filename of each object.

    mySUSE:~ # tree -f /data
     /data
    -└── /data/linktype
    -    ├── /data/linktype/file
    -    ├── /data/linktype/hardlinkfile1
    -    ├── /data/linktype/hardlinkfile2
    -    ├── /data/linktype/symlinkfile1 -> file
    -    ├── /data/linktype/symlinkfile1-1 -> symlinkfile1
    -└── /data/linktype/symlinkfile2 -> file
    -

    Seven Different types of files

    Normal files, examples:

    • ASCII text files
    • Executable files
    • Graphics files

    Directories

    • Organize files on the disk
    • Contain files and subdirectories
    • Implement the hierarchical file system

    Links

    • Hard links
      • Secondary file names for files on the disk
      • Multiple file names referencing a single inode
      • Referenced file must reside in the same file system
    • Symbolic links:
      • References to other files on the disk
      • The inode contains a reference to another file name
      • .Referenced files can exist in the same file system or in other file systems
      • A symbolic link can reference a non-existent file (broken link)

    Sockets - Used for two-way communication between processes. 套接字

    Pipes (FIFOs) - Used for one-way communication from one process to another. 管道

    Block Devices 块设备

    Character Devices 字符设备

    Hard links: A hard link is a directory reference, or pointer, to a file on a storage volume. The name associated with the file is a label stored in a directory structure that refers the operating system to the file data. As such, more than one name can be associated with the same file. When accessed through different names, any changes made will affect the same file data. 硬链接是存储卷上文件的目录引用或指针。 文件名是存储在目录结构中的标签,目录结构指向文件数据。 因此,可以将多个文件名与同一文件关联。 通过不同的文件名访问时,所做的任何更改都是针对源文件数据。

    Symbolic links: A symbolic link contains a text string that is interpreted and followed by the operating system as a path to another file or directory. It is a file on its own and can exist independently of its target. If a symbolic link is deleted, its target remains unaffected. If the target is moved, renamed or deleted, any symbolic link that used to point to it continues to exist but now points to a non-existing file. 符号链接包含一个文本字符串,操作系统将其解释并作为另一个文件或目录的路径。 它本身就是一个文件,可以独立于目标而存在。 如果删除了符号链接,则其目标不受影响。 如果移动,重命名或删除目标,则用于指向它的任何符号链接将继续存在,但现在指向不存在的文件。

    Hard links can only be used when both the file and the link are in the same file system (on the same partition), because inode numbers are only unique within the same file system. You create a hard link by using the ln command, which points to the inode of an already existing file. Thereafter, the file can be accessed under both names–that of the file and that of the link, and you can no longer discern which name existed first or how the original file and the link differ. 仅当文件和链接文件位于同一文件系统(在同一分区上)时,才能使用硬链接,因为inode编号在同一文件系统中仅是唯一的。 您可以使用ln命令创建硬链接,该命令指向已存在文件的inode。 此后,可以在文件的名称和链接的名称下访问文件,并且无法再识别首先存在的名称或原始文件和链接的不同之处。

    You can create a symbolic link with the ln command and the -s option. A symbolic link is assigned its own inode—the link refers to a file, so a distinction can always be made between the link and the actual file. 软连接可以针对目录,硬连接只能针对文件。

    A file system is essentially a database that is used to keep track of files in a volume. For normal files, data blocks are allocated to store the file's data, an inode is allocated to point to the data blocks as well as store the metadata about the file and then a file name is assigned to the inode. A hard link is a secondary file name associated with an existing inode. For symbolic links, a new inode is allocated with a new file name associated with it but the inode references another file name rather than referencing datablocks. 文件系统本质上是一个用于跟踪卷中文件的数据库。 对于普通文件,分配数据块以存储文件的数据,分配inode以指向数据块以及存储关于文件的元数据,然后将文件名分配给inode。 硬链接是与现有inode关联的辅助文件名。 对于符号链接,将为新的inode分配一个与之关联的新文件名,但inode引用另一个文件名而不是引用数据块。

    A good way to see the relationship between file names and inodes is to use the ls -il command. The typical size of an inode is 128 Bit and data blocks can range in size from 1k, 2k, 4k or larger depending on the file system type. 查看文件名和inode之间关系的好方法是使用ls -il命令。inode的典型大小为128位,数据块的大小范围可以是1k,2k,4k或更大,具体取决于文件系统类型。

    硬链接相当于增加了一个登记项,使得原来的文件多了一个名字,至于inode都没变。所谓的登记项其实是目录文件中的一个条目(目录项),使用hard link 是让多个不同的目录项指向同一个文件的inode,没有多余的内容需要存储在磁盘扇区中,所以hardlink不占用额外的空间。

    符号链接有单独的inode,在inode中存放另一个文件的路径而不是文件数据,所以符号链接会占用额外的空间。

    Create original file

    mySUSE:/data/linktype # echo "it's original file" > file
    -mySUSE:/data/linktype # l
    --rw-r--r-- 1 root root 19 Mar 28 15:20 file
    -

    Create hardlink file (注意file、hardlinkfile1、hardlinkfile2的link位置的数值的变化[红色])

    mySUSE:/data/linktype # ln file hardlinkfile1
    -mySUSE:/data/linktype # ln -s file symlinkfile1
    -mySUSE:/data/linktype # ln -s file symlinkfile2
    +└── /data/linktype
    +    ├── /data/linktype/file
    +    ├── /data/linktype/hardlinkfile1
    +    ├── /data/linktype/hardlinkfile2
    +    ├── /data/linktype/symlinkfile1 -> file
    +    ├── /data/linktype/symlinkfile1-1 -> symlinkfile1
    +└── /data/linktype/symlinkfile2 -> file
    +

    Seven Different types of files

    Normal files, examples:

    • ASCII text files
    • Executable files
    • Graphics files

    Directories

    • Organize files on the disk
    • Contain files and subdirectories
    • Implement the hierarchical file system

    Links

    • Hard links
      • Secondary file names for files on the disk
      • Multiple file names referencing a single inode
      • Referenced file must reside in the same file system
    • Symbolic links:
      • References to other files on the disk
      • The inode contains a reference to another file name
      • .Referenced files can exist in the same file system or in other file systems
      • A symbolic link can reference a non-existent file (broken link)

    Sockets - Used for two-way communication between processes. 套接字

    Pipes (FIFOs) - Used for one-way communication from one process to another. 管道

    Block Devices 块设备

    Character Devices 字符设备

    Hard links: A hard link is a directory reference, or pointer, to a file on a storage volume. The name associated with the file is a label stored in a directory structure that refers the operating system to the file data. As such, more than one name can be associated with the same file. When accessed through different names, any changes made will affect the same file data. 硬链接是存储卷上文件的目录引用或指针。 文件名是存储在目录结构中的标签,目录结构指向文件数据。 因此,可以将多个文件名与同一文件关联。 通过不同的文件名访问时,所做的任何更改都是针对源文件数据。

    Symbolic links: A symbolic link contains a text string that is interpreted and followed by the operating system as a path to another file or directory. It is a file on its own and can exist independently of its target. If a symbolic link is deleted, its target remains unaffected. If the target is moved, renamed or deleted, any symbolic link that used to point to it continues to exist but now points to a non-existing file. 符号链接包含一个文本字符串,操作系统将其解释并作为另一个文件或目录的路径。 它本身就是一个文件,可以独立于目标而存在。 如果删除了符号链接,则其目标不受影响。 如果移动,重命名或删除目标,则用于指向它的任何符号链接将继续存在,但现在指向不存在的文件。

    Hard links can only be used when both the file and the link are in the same file system (on the same partition), because inode numbers are only unique within the same file system. You create a hard link by using the ln command, which points to the inode of an already existing file. Thereafter, the file can be accessed under both names–that of the file and that of the link, and you can no longer discern which name existed first or how the original file and the link differ. 仅当文件和链接文件位于同一文件系统(在同一分区上)时,才能使用硬链接,因为inode编号在同一文件系统中仅是唯一的。 您可以使用ln命令创建硬链接,该命令指向已存在文件的inode。 此后,可以在文件的名称和链接的名称下访问文件,并且无法再识别首先存在的名称或原始文件和链接的不同之处。

    You can create a symbolic link with the ln command and the -s option. A symbolic link is assigned its own inode—the link refers to a file, so a distinction can always be made between the link and the actual file. 软连接可以针对目录,硬连接只能针对文件。

    A file system is essentially a database that is used to keep track of files in a volume. For normal files, data blocks are allocated to store the file's data, an inode is allocated to point to the data blocks as well as store the metadata about the file and then a file name is assigned to the inode. A hard link is a secondary file name associated with an existing inode. For symbolic links, a new inode is allocated with a new file name associated with it but the inode references another file name rather than referencing datablocks. 文件系统本质上是一个用于跟踪卷中文件的数据库。 对于普通文件,分配数据块以存储文件的数据,分配inode以指向数据块以及存储关于文件的元数据,然后将文件名分配给inode。 硬链接是与现有inode关联的辅助文件名。 对于符号链接,将为新的inode分配一个与之关联的新文件名,但inode引用另一个文件名而不是引用数据块。

    A good way to see the relationship between file names and inodes is to use the ls -il command. The typical size of an inode is 128 Bit and data blocks can range in size from 1k, 2k, 4k or larger depending on the file system type. 查看文件名和inode之间关系的好方法是使用ls -il命令。inode的典型大小为128位,数据块的大小范围可以是1k,2k,4k或更大,具体取决于文件系统类型。

    硬链接相当于增加了一个登记项,使得原来的文件多了一个名字,至于inode都没变。所谓的登记项其实是目录文件中的一个条目(目录项),使用hard link 是让多个不同的目录项指向同一个文件的inode,没有多余的内容需要存储在磁盘扇区中,所以hardlink不占用额外的空间。

    符号链接有单独的inode,在inode中存放另一个文件的路径而不是文件数据,所以符号链接会占用额外的空间。

    Create original file

    mySUSE:/data/linktype # echo "it's original file" > file
    +mySUSE:/data/linktype # l
    +-rw-r--r-- 1 root root 19 Mar 28 15:20 file
    +

    Create hardlink file (注意file、hardlinkfile1、hardlinkfile2的link位置的数值的变化[红色])

    mySUSE:/data/linktype # ln file hardlinkfile1
    +mySUSE:/data/linktype # ln -s file symlinkfile1
    +mySUSE:/data/linktype # ln -s file symlinkfile2
     
    -mySUSE:/data/linktype # l
    --rw-r--r-- 2 root root 19 Mar 28 15:20 file
    --rw-r--r-- 2 root root 19 Mar 28 15:20 hardlinkfile1
    -lrwxrwxrwx 1 root root  4 Mar 28 15:21 symlinkfile1 -> file
    -lrwxrwxrwx 1 root root  4 Mar 28 15:23 symlinkfile2 -> file
    +mySUSE:/data/linktype # l
    +-rw-r--r-- 2 root root 19 Mar 28 15:20 file
    +-rw-r--r-- 2 root root 19 Mar 28 15:20 hardlinkfile1
    +lrwxrwxrwx 1 root root  4 Mar 28 15:21 symlinkfile1 -> file
    +lrwxrwxrwx 1 root root  4 Mar 28 15:23 symlinkfile2 -> file
     
    -mySUSE:/data/linktype # ln file hardlinkfile2
    +mySUSE:/data/linktype # ln file hardlinkfile2
     
    -mySUSE:/data/linktype # l
    --rw-r--r-- 3 root root  19 Mar 28 15:20 file (包括自己,一共有3个硬链接)
    --rw-r--r-- 3 root root  19 Mar 28 15:20 hardlinkfile1 (继承了原文件的硬链接数量)
    --rw-r--r-- 3 root root  19 Mar 28 15:20 hardlinkfile2 (继承了原文件的硬链接数量)
    -lrwxrwxrwx 1 root root   4 Mar 28 15:21 symlinkfile1 -> file
    -lrwxrwxrwx 1 root root   4 Mar 28 15:23 symlinkfile2 -> file
    -

    Modify content of file (original file). Content change were shown in all hard/soft link files

    mySUSE:/data/linktype # echo "add oneline" >> file
    +mySUSE:/data/linktype # l
    +-rw-r--r-- 3 root root  19 Mar 28 15:20 file (包括自己,一共有3个硬链接)
    +-rw-r--r-- 3 root root  19 Mar 28 15:20 hardlinkfile1 (继承了原文件的硬链接数量)
    +-rw-r--r-- 3 root root  19 Mar 28 15:20 hardlinkfile2 (继承了原文件的硬链接数量)
    +lrwxrwxrwx 1 root root   4 Mar 28 15:21 symlinkfile1 -> file
    +lrwxrwxrwx 1 root root   4 Mar 28 15:23 symlinkfile2 -> file
    +

    Modify content of file (original file). Content change were shown in all hard/soft link files

    mySUSE:/data/linktype # echo "add oneline" >> file
     
    -mySUSE:/data/linktype # cat file
    +mySUSE:/data/linktype # cat file
     it's original file
     add oneline
     
     mySUSE:/data/linktype # cat hardlinkfile1
    -it's original file
    -add oneline
    +it's original file
    +add oneline
     
    -mySUSE:/data/linktype # cat hardlinkfile2
    +mySUSE:/data/linktype # cat hardlinkfile2
     it's original file
     add oneline
     
     mySUSE:/data/linktype # cat symlinkfile1
    -it's original file
    -add oneline
    +it's original file
    +add oneline
     
    -mySUSE:/data/linktype # cat symlinkfile2
    -it's original file
    -add oneline
    -

    To view the value stored in a symbolic link use the command readlink.

    mySUSE:/data/linktype # ln -s symlinkfile1 symlinkfile1-1
    +mySUSE:/data/linktype # cat symlinkfile2
    +it's original file
    +add oneline
    +

    To view the value stored in a symbolic link use the command readlink.

    mySUSE:/data/linktype # ln -s symlinkfile1 symlinkfile1-1
     
    -mySUSE:/data/linktype # ls -il
    -258 -rw-r--r-- 3 root root 31 Mar 28 15:42 file
    -258 -rw-r--r-- 3 root root 31 Mar 28 15:42 hardlinkfile1
    -258 -rw-r--r-- 3 root root 31 Mar 28 15:42 hardlinkfile2
    -259 lrwxrwxrwx 1 root root  4 Mar 28 15:21 symlinkfile1 -> file
    -265 lrwxrwxrwx 1 root root 12 Mar 28 15:49 symlinkfile1-1 -> symlinkfile1
    -260 lrwxrwxrwx 1 root root  4 Mar 28 15:23 symlinkfile2 -> file
    +mySUSE:/data/linktype # ls -il
    +258 -rw-r--r-- 3 root root 31 Mar 28 15:42 file
    +258 -rw-r--r-- 3 root root 31 Mar 28 15:42 hardlinkfile1
    +258 -rw-r--r-- 3 root root 31 Mar 28 15:42 hardlinkfile2
    +259 lrwxrwxrwx 1 root root  4 Mar 28 15:21 symlinkfile1 -> file
    +265 lrwxrwxrwx 1 root root 12 Mar 28 15:49 symlinkfile1-1 -> symlinkfile1
    +260 lrwxrwxrwx 1 root root  4 Mar 28 15:23 symlinkfile2 -> file
     
    -mySUSE:/data/linktype # readlink symlinkfile1
    +mySUSE:/data/linktype # readlink symlinkfile1
     file
     
    -mySUSE:/data/linktype # readlink symlinkfile2
    +mySUSE:/data/linktype # readlink symlinkfile2
     file
     
    -mySUSE:/data/linktype # readlink symlinkfile1-1
    -symlinkfile1  (注意:这仍然是一个符号链接文件)
    +mySUSE:/data/linktype # readlink symlinkfile1-1
    +symlinkfile1  (注意:这仍然是一个符号链接文件)
     
    -mySUSE:/data/linktype # readlink -f symlinkfile1-1(参数-f可以直接定位真正的源文件)
    -/data/linktype/file (注意:这才是真正的原文件)
    -

    Linux Device File

    Represent hardware (except network cards). Each piece of hardware is represented by a device file. Network cards are interfaces. (区别)

    Link between hardware devices and the kernel drivers 设备文件把内核驱动和物理硬件设备连接起来

    Kernel drivers read from and write to the device file 内核驱动程序对设备文件进行读写来实现对硬件的读写

    The kernel gets the data to the actual hardware in the correct format 内核以正确的格式对物理设备进行读写

    Types:

    • Block Devices. A block device reads/writes information in (normally) 512 byte large blocks.
    • Character Devices. A character device reads/writes information character wise. Character devices provide unbuffered access directly to a hardware device. 直接读写,不通过缓存
      • Sometimes referred to as raw devices. 裸设备(注意:裸设备被视为字符设备,不是块设备)
      • any different options for character devices, making their use and application wide and varied.
    • Created automatically by the OS (udev) when the device is discovered by the kernel. 内核直接创建对应硬件的设备文件
    \ No newline at end of file +mySUSE:/data/linktype # readlink -f symlinkfile1-1(参数-f可以直接定位真正的源文件) +/data/linktype/file (注意:这才是真正的原文件) +

    Linux Device File

    Represent hardware (except network cards). Each piece of hardware is represented by a device file. Network cards are interfaces. (区别)

    Link between hardware devices and the kernel drivers 设备文件把内核驱动和物理硬件设备连接起来

    Kernel drivers read from and write to the device file 内核驱动程序对设备文件进行读写来实现对硬件的读写

    The kernel gets the data to the actual hardware in the correct format 内核以正确的格式对物理设备进行读写

    Types:

    • Block Devices. A block device reads/writes information in (normally) 512 byte large blocks.
    • Character Devices. A character device reads/writes information character wise. Character devices provide unbuffered access directly to a hardware device. 直接读写,不通过缓存
      • Sometimes referred to as raw devices. 裸设备(注意:裸设备被视为字符设备,不是块设备)
      • any different options for character devices, making their use and application wide and varied.
    • Created automatically by the OS (udev) when the device is discovered by the kernel. 内核直接创建对应硬件的设备文件
    Back to top
    \ No newline at end of file diff --git a/linux/Administration/02/index.html b/linux/Administration/02/index.html index 5d667f15..45783924 100644 --- a/linux/Administration/02/index.html +++ b/linux/Administration/02/index.html @@ -1,11 +1,11 @@ - Useful Commands - UPSkilling

    Useful Commands

    Some common abbreviations

    Abbreviations Description
    . represents the current directory
    .. represents the parent directory
    ~ represents the home directory
    ~username represents the home directory of user username

    Software package documentation

    /usr/share/doc/packages/
    + Useful Commands - UPSkilling       

    Useful Commands

    Some common abbreviations

    Abbreviations Description
    . represents the current directory
    .. represents the parent directory
    ~ represents the home directory
    ~username represents the home directory of user username

    Software package documentation

    /usr/share/doc/packages/
     

    Release Notes

    /usr/share/doc/release-notes/
    -

    Command help

    <command> -h or <command> --help
    +

    Command help

    <command> -h or <command> --help
     # tree --help
    -

    Manual pages

    man [section] command
    +

    Manual pages

    man [section] command
     # man 5 crontab
     # man
    -/sestion options
    +/sestion options
     
    Show tree command manual:
    # man tree
     

    List for keywords:

    # man -k keyword
     

    Force mandb to update. Normally this is done daily via a cron job.

    # mandb
    @@ -25,57 +25,57 @@
     * Detailed listing with -l option
     * Output is recursive, including all subdirectories with -R option
     * With option -F After each name, a character indicates the file type (“/” for directories, “*” for executable files, “|” for FIFO files, “@” symbolic link).
    -

    cp command

    Copy a file or directory

    Syntax: cp [option] <source> <destination>

    • Option -a : Copies a directory and subdirectories (compare -R); symbolic links, file permissions, owners, and time stamps are not changed. 它保留符号链接、文件属性,并复制目录下的所有内容。其作用等于-dpR参数组合。
    • Option -I : Asks before overwriting.
    • Option -R, -r : Copies directories recursively (the directory and any subdirectories). 递归拷贝,包含子目录及(隐含)文件,继承目标目录的权限和属性等
    • Option -l : Makes hardlinks instead of copying (创建硬链接的另外一个方法)
    • Option -s : Makes symbolic instead of copying (创建符号链接的另外一个方法)
    • Option -u : Copies a file only when the source file is newer than the destination file or when the destination file is missing.
    • Option -p : 连同档案的属性一起复制过去,包括修改时间、访问权限、所有者组等,而非使用预设属性;

    Labs:

    • Initiate directories and files
      mySUSE:~ # su - pmgr
      -pmgr@mySUSE:~> mkdir /data/program
      -pmgr@mySUSE:~> mkdir /data/program/general
      -pmgr@mySUSE:~> mkdir /data/program/general/staffing
      -pmgr@mySUSE:~> touch /data/program/general/program_scope
      -pmgr@mySUSE:~> touch /data/program/general/staffing/assignment
      +

      cp command

      Copy a file or directory

      Syntax: cp [option] <source> <destination>

      • Option -a : Copies a directory and subdirectories (compare -R); symbolic links, file permissions, owners, and time stamps are not changed. 它保留符号链接、文件属性,并复制目录下的所有内容。其作用等于-dpR参数组合。
      • Option -I : Asks before overwriting.
      • Option -R, -r : Copies directories recursively (the directory and any subdirectories). 递归拷贝,包含子目录及(隐含)文件,继承目标目录的权限和属性等
      • Option -l : Makes hardlinks instead of copying (创建硬链接的另外一个方法)
      • Option -s : Makes symbolic instead of copying (创建符号链接的另外一个方法)
      • Option -u : Copies a file only when the source file is newer than the destination file or when the destination file is missing.
      • Option -p : 连同档案的属性一起复制过去,包括修改时间、访问权限、所有者组等,而非使用预设属性;

      Labs:

      • Initiate directories and files
        mySUSE:~ # su - pmgr
        +pmgr@mySUSE:~> mkdir /data/program
        +pmgr@mySUSE:~> mkdir /data/program/general
        +pmgr@mySUSE:~> mkdir /data/program/general/staffing
        +pmgr@mySUSE:~> touch /data/program/general/program_scope
        +pmgr@mySUSE:~> touch /data/program/general/staffing/assignment
         
        -mySUSE:~ # su - pm1
        -pm1@mySUSE:~> mkdir /data/project1
        -pm1@mySUSE:~> mkdir /data/project1/iot
        -pm1@mySUSE:~> mkdir /data/project1/iot/bigdata
        -pm1@mySUSE:~> touch /data/project1/iot/devicelist
        -pm1@mySUSE:~> touch /data/project1/iot/bigdata/math_lib
        +mySUSE:~ # su - pm1
        +pm1@mySUSE:~> mkdir /data/project1
        +pm1@mySUSE:~> mkdir /data/project1/iot
        +pm1@mySUSE:~> mkdir /data/project1/iot/bigdata
        +pm1@mySUSE:~> touch /data/project1/iot/devicelist
        +pm1@mySUSE:~> touch /data/project1/iot/bigdata/math_lib
         
        -mySUSE:~ # su - pm2
        -pm2@mySUSE:~> mkdir /data/project2
        -pm2@mySUSE:~> mkdir /data/project2/erp
        -pm2@mySUSE:~> mkdir /data/project2/erp/fin
        -pm2@mySUSE:~> touch /data/project2/erp/erp_vision
        -pm2@mySUSE:~> touch /data/project2/erp/fin/fin_ar
        -pm2@mySUSE:~> chmod g+w /data/project2/erp/erp_vision
        +mySUSE:~ # su - pm2
        +pm2@mySUSE:~> mkdir /data/project2
        +pm2@mySUSE:~> mkdir /data/project2/erp
        +pm2@mySUSE:~> mkdir /data/project2/erp/fin
        +pm2@mySUSE:~> touch /data/project2/erp/erp_vision
        +pm2@mySUSE:~> touch /data/project2/erp/fin/fin_ar
        +pm2@mySUSE:~> chmod g+w /data/project2/erp/erp_vision
         
        -pmgr@mySUSE:~> ln /data/project2/erp/erp_vision /data/program/general/p2_erp_version 
        -    (创建硬链接,当前用户需要对源文件erp_vision有w权限)
        -pmgr@mySUSE:~> ln -s /data/project1/iot/devicelist /data/program/general/p1_devicelist 
        -    (创建符号链接,不验证当前用户是否对源文件devicelist有权限)
        +pmgr@mySUSE:~> ln /data/project2/erp/erp_vision /data/program/general/p2_erp_version 
        +    (创建硬链接,当前用户需要对源文件erp_vision有w权限)
        +pmgr@mySUSE:~> ln -s /data/project1/iot/devicelist /data/program/general/p1_devicelist 
        +    (创建符号链接,不验证当前用户是否对源文件devicelist有权限)
         
        -mySUSE:~ # tree /data
        +mySUSE:~ # tree /data
         /data
        -├── program
        -│   └── general
        -│       ├── p1_devicelist -> /data/project1/iot/devicelist
        -│       ├── p2_erp_version
        -│       ├── program_scope
        -│       └── staffing
        -│           └── assignment
        -├── project1
        -│   └── iot
        -│       ├── bigdata
        -│       │   └── math_lib
        -│       └── devicelist
        -└── project2
        -    └── erp
        -        ├── erp_vision
        -        └── fin
        -            └── fin_ar
        +├── program
        +│   └── general
        +│       ├── p1_devicelist -> /data/project1/iot/devicelist
        +│       ├── p2_erp_version
        +│       ├── program_scope
        +│       └── staffing
        +│           └── assignment
        +├── project1
        +│   └── iot
        +│       ├── bigdata
        +│          └── math_lib
        +│       └── devicelist
        +└── project2
        +    └── erp
        +        ├── erp_vision
        +        └── fin
        +            └── fin_ar
         
        -pmgr@mySUSE:~> cp -R /data/project1 /data/program/ 
        -    (/data/program/project1的用户和组都继承了/data/program/)
        -pmgr@mySUSE:~> cp -a /data/project2 /data/program/
        -    (/data/program/project2的用户继承了/data/program/,但组还是保留原来的)
        +pmgr@mySUSE:~> cp -R /data/project1 /data/program/ 
        +    (/data/program/project1的用户和组都继承了/data/program/)
        +pmgr@mySUSE:~> cp -a /data/project2 /data/program/
        +    (/data/program/project2的用户继承了/data/program/,但组还是保留原来的)
         

      mv command

      Move or rename a file or directory

      • Option -i : Asks for confirmation before moving or renaming a file. This prevents existing files with the same name from being overwritten.
      • Option -u : Only moves files that are newer than the target files of the same name.
        pmgr@mySUSE:/data/program/general> cp program_scope ./staffing/
         pmgr@mySUSE:/data/program/general> mv -i program_scope ./staffing/
         mv: overwrite './staffing/program_scope'? n
        @@ -336,4 +336,4 @@
         pmgr@dcmaster:/data/program/general> egrep Linux *
         general.conf:Linux
         grep: staffing: Is a directory
        -

    \ No newline at end of file +

    Back to top
    \ No newline at end of file diff --git a/linux/Administration/03/index.html b/linux/Administration/03/index.html index 271cc059..4411090a 100644 --- a/linux/Administration/03/index.html +++ b/linux/Administration/03/index.html @@ -1 +1 @@ - Shell - UPSkilling
    \ No newline at end of file + Shell - UPSkilling
    Back to top
    \ No newline at end of file diff --git a/linux/SES/linux_ses_demo/index.html b/linux/SES/linux_ses_demo/index.html index a4d2feb4..0b02ec2a 100644 --- a/linux/SES/linux_ses_demo/index.html +++ b/linux/SES/linux_ses_demo/index.html @@ -1,4 +1,4 @@ - SUSE Enterprise Storage Basic Operation - UPSkilling

    SUSE Enterprise Storage 6 Installation and Basic Operation

    1. Installation

    1.1. Environment Setup

    In this demo, I use below environment, including VM setting and software installed.

    All VMs installed here was built on a physical host 10.58.121.68.

    Host Server:
    + SUSE Enterprise Storage Basic Operation - UPSkilling       

    SUSE Enterprise Storage 6 Installation and Basic Operation

    1. Installation

    1.1. Environment Setup

    In this demo, I use below environment, including VM setting and software installed.

    All VMs installed here was built on a physical host 10.58.121.68.

    Host Server:
         10.58.121.68  root / rootroot
     
     Account
    @@ -3202,4 +3202,4 @@
     Enter WORKGROUP\joesmb's password:   ---> 123
     tree connect failed: NT_STATUS_BAD_NETWORK_NAME
     

    You should see output similar to the following: Try “help” to get a list of possible commands.

    smb: \>
    -

    \ No newline at end of file +

    Back to top
    \ No newline at end of file diff --git a/linux/SES/linux_ses_memo/index.html b/linux/SES/linux_ses_memo/index.html index fd2202ad..06ce8383 100644 --- a/linux/SES/linux_ses_memo/index.html +++ b/linux/SES/linux_ses_memo/index.html @@ -1,4 +1,4 @@ - SUSE Enterprise Storage Foundation - UPSkilling

    SUSE Enterprise Storage Foundation

    Ceph’s RADOS

    Everything in Ceph is stored in the RADOS cluster as Objects.

    Ceph’s RADOS:

    • Reliable
    • Autonomous
    • Distributed
    • Object
    • Store

    Ceph’s RADOS is composed of storage devices represented as:

    • Raw storage device with LVM (BlueStore)
    • Standard filesystem (FileStore)

    The Object Storage Daemon (OSD) integrates each disk device as part of the RADOS cluster.

    Object Storage Daemon

    Ceph architecture

    Ceph is made of two groups of core components

    • The RADOS cluster

      • Provides the clustered object storage
      • Native Object Access methods
    • Gateways

      • Access to the object store via standard protocols
      • librados
      • Direct access to the object store using a native API
      • Examples:
        • iSCSI Gateway (block) -- IGW - iSCSI is a storage area network (SAN) protocol.
          • Exports RADOS Block Device (--RBD) (images as iSCSI disks).
          • iSCSI access to RDB images.
          • lrbd is no longer used in SES6.
        • RADOS Gateway (object) -- RGW
          • Is an object storage interface built on top of librados
        • CephFS (file)
          • A MetaData Service (MDS) is required.
          • Direct access to RADOS (no LIBRADOS layer)
          • Traditional filesystem interface.
        • NFS Ganesha (object, file)
          • Provides NFS exports to:
            • RGW buckets for access the object store
            • The CephFS filesystem

    Client access the storage services of the cluster via Gateways and Librados

    The librados API allows interaction with the following daemons:

    • The Ceph Monitor, which maintains a master copy of the cluster map

    The Ceph OSD Daemon (OSD), which stores data as objects on a storage node.

    Enhanced SES Architecture Diagram

    Enhanced SES Architecture Diagram

    Object Storage

    • The state of the art of distributed SDS storage
    • Unstructured, to better accommodate large files and large quantities of files
    • For large files and large quantities of files, it performs far better than other storage mechanisms
    • Agile, scalable, extensible, and very customizable
    • Invisible to the end-user, ideal for backends
    • Perfect for systemic, application-based use cases. Not necessarily perfect for direct Human use
    • Through associated metadata, ideal for computational analytics
      • And CRUSH takes full advantage of this (CRUSH = Controllable Replication Under Scalable Hashing)
    • Ceph Object Storage supports two interfaces:
      • S3-compatible
      • Swift-compatible
    • Object-based storage has become the standard backend storage mechanism for nearly all modern Enterprise Storage Solutions.

    Ceph OSDs (Object Storage Daemon)

    • A Ceph OSD (object storage daemon, ceph-osd) stores data, handles data replication, recovery, rebalancing, and provides some monitoring information to Ceph Monitors and Managers by checking other Ceph OSD Daemons for a heartbeat.
      • The Ceph Storage Cluster receives data from Ceph Clients.
      • Clients (dedicated access points, e.g., gateway) could be a Ceph Block Device, Ceph Object Storage, the Ceph Filesystem or a custom implementation using librados.
        • The client requests the cluster status from a monitor node
        • The client uses the status information to identify the location of objects in the cluster
        • The client accesses the objects directly via the OSD node
      • The OSD then stores the data as objects. Each object corresponds to a file in a filesystem which is stored on an OSD.
    • The OSD Daemons take care of the reads and writes on the storage disks.
    • When OSDs are deployed in SES5 the default is to use BlueStore which uses the raw disk and does not require a linux file system to be placed on the disk before it can be used.
    • OSD Daemons store all data as objects in a flat namespace, i.e. no hierarchy of directories.
    • At least 3 Ceph OSDs are normally required for redundancy and high availability.

    Ceph Mons (Monitor Servers)

    • A Ceph Monitor (ceph-mon) maintains maps of the cluster state, including
      • Monitor Map
      • Manager Map
      • OSD Map
      • PG Map
      • CRUSH Map
      • Epoch
    • These maps are critical cluster state required for Ceph daemons to coordinate with each other. Monitors are also responsible for managing authentication between daemons and clients.
    • At least 3 monitors are normally required for redundancy and high availability. An odd number of MONs is required (Paxos requires). Typically 5 is sufficient for mid or large size cluster.
      • Paxos is an algorithm used for cluster durability.
      • Leader MON expects 50% quality to create quorum.
      • Lowest IP address becomes leader. After new leader selected, all MONs polled for epoch.
      • Leader Mon provides lease to non-leader MONs.
    • MONs are NOT in the data path. They merely serve maps to clients so that the client can go directly to the appropriate OSD storage daemon. Monitor nodes MONs do not serve objects to clients

    Ceph MGRs (Manager Daemon)

    • A Ceph Manager daemon (ceph-mgr) is responsible for keeping track of runtime metrics and the current state of the Ceph cluster, including
      • storage utilization
      • current performance metrics
      • system load
    • The Ceph Manager daemons also host python-based plugins to manage and expose Ceph cluster information, including a web-based dashboard and REST API.
    • At least two managers are normally required for high availability.
    • MON/MGR daemons are required to run on the same node in SES

    Ceph MDS (Metadata)

    • A Ceph Metadata Server (MDS, ceph-mds) stores metadata on behalf of the Ceph Filesystem.
    • Ceph Metadata Servers allow POSIX file system users to execute basic commands, for example ls -al without placing an large load on the Ceph Storage Cluster.

    Ceph Admin Node

    • The Admin node fills the “master” and “admin” roles for DeepSea.
    • Salt is central to SES. SES’s deployment and life-cycle management tool.
    • The Admin node keeps master Ceph authentication keys.
    • Prometheus and Grafana provide cluster monitoring and data graphs

    Ceph Dashboard

    • Runs as a Ceph Manager module; runs via the MON/MGR node.

    Client Access

    • Object Storage (RADOSGW or RGW)
    • Block Storage (RDB). RBD is built on top of librados.
    • CephFS
    • iSCSI Gateway
    • NFS Ganesha
    • SMB/CIFS
    • Native protocols via librados

    Client Access

    Objects in Ceph

    • Everything stored in the Ceph cluster is an object. Default object size is 4MB.
    • Each object has a unique ID. ID is unique across the entire cluster.
    • Objects have associated metadata, in Key: Value pairs.
    • In Ceph we use Storage Pools to organize or arrange our objects.
      • Pools are logical partitions to manage objects
      • Parameters to manage Pools
        • Number of data replicas (Replica pools), or configuration of Erasure Code (size) (Erasure Code pools)
          • Erasure Code is an alternative to Replication
            • SIZE for Erasure Coding is K+M
            • K = Data chunks, M = “Parity” chunks
            • EC reduces the hit to raw storage capacity
            • EC incurs a greater hit to CPU on the OSDs as a tradeoff
        • Placement Groups (PG)
          • PG is used to manage objects within a pool.
          • PGs are associated with OSDs for data placement
          • PGs are a central feature of CRUSH that help to provide data durability by way of distribution
          • No PG is owned by an OSD. (And an OSD is not owned by a PG.)
          • PGs are just randomly assigned by CRUSH through all of the OSDs to spread the distribution of data
          • Locating data among PGs is all handled economically, deterministically by way of CRUSH calculations
          • PGs are subdivisions of pools
          • Number of PGs = (Number of OSDs * 100) / Size (Size = either num of replicas, or K+M)
            • The final PG number must be a power of 2
          • The default number of PGs for a new pool is 8 (it's too small for enterprise solution)
          • In general, PG and PGP numbers should be the same
            • pg_num is the number of placement groups for the pool (placement group, 存储池的目录个数 )
            • pgp_num is the number of placement groups that will be considered for placement (placement group for placement purpose, pg可用的osd排列组合数量)
            • 仅增大pg_num:
              • 因为pgp_num没变,pg的osd组合仍只能从当前pgp_num种组合里面挑选,导致新增的pg和旧pg会有重复的osd组合,该现象称之为分裂;此时pg和osd的映射没有变;
            • 继续增大pgp_num,使其等于pg_num:
              • 旧pg没有变化,但新增pg的osd组合发生变化,即开始重新分布
            • Placement Group (PG) 归置组状态
              1. Creating
                • 创建存储池时,它会创建指定数量的归置组。
                • ceph 在创建一或多个归置组时会显示 creating。
                • 创建完后,在其归置组的 Acting Set 里的 OSD 将建立互联。
                • 一旦互联完成,归置组状态应该变为 active+clean,意思是ceph 客户端可以向归置组写入数据了。
              2. peering
                • ceph 为归置组建立互联时,会让存储归置组副本的 OSD 之间就其中的对象和元数据状态达成一致。
                • ceph 完成了互联,也就意味着存储着归置组的 OSD 就其当前状态达成了一致。
                • 然而,互联过程的完成并不能表明各副本都有了数据的最新版本。
              3. active
                • ceph 完成互联进程后,一归置组就可变为 active。
                • active 状态通常意味着在主归置组和副本中的数据都可以读写。
              4. clean
                • 某一归置组处于 clean 状态时,主 OSD 和副本 OSD 已成功互联,并且没有偏离的归置组。
                • ceph 已把归置组中的对象复制了规定次数。
              5. degraded
                • 当客户端向主 OSD 写入数据时,由主 OSD 负责把副本写入其余复制 OSD。
                • 主 OSD 把对象写入复制 OSD 后,在没收到成功完成的确认前,主 OSD 会一直停留在 degraded 状态。
                • 归置组状态可以是 active+degraded 状态,原因在于一 OSD 即使没所有对象也可以处于 active 状态。
                • 如果一OSD 挂了,ceph 会把相关的归置组都标记为 degraded。
                • 那个 OSD 重生后,它们必须重新互联。
                • 然而,如果归置组仍处于 active 状态,即便它处于 degraded 状态,客户端还可以向其写入新对象。
                • 如果一 OSD 挂了,且 degraded 状态持续,ceph 会把 down 的 OSD 标记为在集群外(out)、并把那些 down 掉的 OSD 上的数据重映射到其它 OSD。
                • 从标记为 down 到 out 的时间间隔由 mon osd down out interval 控制,默认是 300 秒。
                • 归置组也会被降级(degraded),因为归置组找不到本应存在于归置组中的一或多个对象,这时,你不能读或写找不到的对象,但仍能访问其它位于降级归置组中的对象。
              6. recovering
                • ceph 被设计为可容错,可抵御一定规模的软、硬件问题。
                • 当某 OSD 挂了(down)时,其内容版本会落后于归置组内的其它副本。
                • 它重生(up)时,归置组内容必须更新,以反映当前状态。
                • 在此期间,OSD 在recovering 状态。
                • 一次硬件失败可能牵连多个 OSD。比如一个机柜的网络交换机失败了,这会导致多个主机落后于集群的当前状态,问题解决后每一个 OSD 都必须恢复。
                • ceph 提供了很多选项来均衡资源竞争,如新服务请求、恢复数据对象和恢复归置组到当前状态。
                • osd recovery delay start 选项允许一 OSD 在开始恢复进程前,先重启、重建互联、甚至处理一些重放请求。
                • osd recovery threads 选项限制恢复进程的线程数,默认为 1 线程。
                • osd recovery thread timeout 设置线程超时,因为多个OSD 可能交替失败、重启和重建互联。
                • osd recovery max active 选项限制一 OSD 最多同时接受多少请求,以防它压力过大而不能正常服务。
                • osd recovery max chunk 选项限制恢复数据块尺寸,以防网络拥塞。
              7. back filling
                • 有新 OSD 加入集群时,CRUSH 会把现有集群内的归置组重分配给它。
                • 强制新 OSD 立即接受重分配的归置组会使之过载,用归置组回填可使这个过程在后台开始。
                • 回填完成后,新 OSD 准备好时就可以对外服务了。
              8. remapped
                • 某一归置组的 Acting Set 变更时,数据要从旧集合迁移到新的。
                • 主 OSD 要花费一些时间才能提供服务,所以它可以让老的主 OSD 持续服务、直到归置组迁移完。
                • 数据迁移完后,主 OSD 会映射到新 acting set。
              9. stale
                • 虽然 ceph 用心跳来保证主机和守护进程在运行,但是 ceph-osd 仍有可能进入 stuck 状态,它们没有按时报告其状态(如网络瞬断)。
                • 默认OSD 守护进程每半秒(0.5)会一次报告其归置组、出流量、引导和失败统计状态,此频率高于心跳阀值。
                • 如果一归置组的主 OSD 所在的 acting set 没能向监视器报告、或者其它监视器已经报告了那个主 OSD 已 down,监视器们就会把此归置组标记为 stale。
                • 启动集群时,会经常看到 stale 状态,直到互联完成。
                • 集群运行一阵后,如果还能看到有归置组位于 stale 状态,就说明那些归置组的主 OSD 挂了(down)、或没在向监视器报告统计信息。
          • Each pool has its own autoscaler settings
          • The PG balancer optimizes the placement of PGs across OSD
            • crush-compat mode
              • It's default mode
              • Uses the compat weight-set feature
            • upmap mode.
              • It's perfect mode, which an equal number of PGs on each OSD
              • Use fine-grained control over the PG mapping
        • Snapshots
        • Rulesets to manage CRUSH placement
          • Each pool has a defined CRUSH ruleset
            • A CRUSH ruleset is a definition of how the OSDs organize data
            • This allows configuration of data distribution to be managed per pool
            • A single CRUSH ruleset can be reused by multiple pools
            • A ruleset can take into account: 需要考虑的点
              • physical layout of nodes in the cluster
              • organization of network infrastructure
              • selection of OSDs backed by SSDs versus HDDs, etc
          • Each pool can use either Replication or Erasure Coding
            • Replication is the original, default approach to resiliency
          • Erasure Coded pools have an EC Profile assigned
            • Different than CRUSH rulesets, but similar: define how OSDs organize data
            • The profile defines K, M values; encoding method/plugin; etc

    Placement Group

    CRUSH (Controllable Replication Under Scalable Hashing)

    • CRUSH is a key piece of the Ceph storage solution
    • With the CRUSH algorithm used by Ceph:
      • Data is not centrally stored, it is distributed
      • CRUSH calculates the storage location for each object dynamically
      • No requirement to store a global index of object locations

    CRUSH Algorithm

    • The CRUSH algorithm deterministically calculates the location of any object in the Ceph RADOS cluster
    • Overhead is low and calculation is performed by each client
    • As no metadata store is required, CRUSH removes the limitations of traditional metadata based management
    • No direct control over the placement of your data in the cluster
    • Higher CPU requirements

    CRUSH Maps and Rulesets

    • CRUSH Rulesets are the named sets of rules:
      • Combining all of the customizable CRUSH behavior settings
      • Assigned to pool to govern how the pool’s data is distributed in the cluster
    • CRUSH Maps are central to how Ceph distributes data, and maintaining the durability of the data
      • When the cluster is deployed, Ceph creates a simple default ruleset for replicated pools: replicated_rule
    • CRUSH behavior depends on the behaviors and performance of storage devices
    • CRUSH Maps should be crafted to take advantage of those behaviors
    • Rulesets should be used to clearly identify how the devices in your environment should be employed
    • Device Classes exist to indicate performance behavior: hdd, ssd, nvme
    • Ceph OSDs will automatically set the Device Class of a storage device when the OSD is started
    • Working with CRUSH Map Rulesets
      • List the OSDs, which host each OSD belongs to:
        • ceph osd tree
        • ceph osd df tree
        • ceph osd df tree -f json-pretty
      • Find the host of a specific OSD:
        • ceph osd find 8
      • Show the existing defined rulesets:
        • ceph osd crush rule ls
      • Examine the definition of an existing ruleset:
        • ceph osd crush rule dump <rulesetname>
      • There are 3 options for creating a new ruleset:
        • simple
        • replicated
        • erasure
      • Creating new rulesets:
        • ceph osd crush rule create-replicated <name>
        • ceph osd crush rule create-erasure <name> <ec_profile>
      • Create a new ruleset using a Device Class:
        • create-replicated <name> <root> <failure-domain-level> <device-class>
        • <root>
          • Description : The name of the node under which data should be placed.
          • Type : String
          • Example : default (rarely would you need to make this different than “default”)
        • <failure-domain-type> or <failure-doamin-level>
          • Description : The type of CRUSH node (bucket) across which replicas should be separated.
          • Type : String
          • Example : rack
        • <device-class>
          • Description : The device class data should be placed on.
          • Type : String
          • Example : ssd

    CRUSH Weight

    • You may need to move data around
      • New nodes
      • degraded nodes
      • rebalancing
    • View the current CRUSH weights
      • ceph osd crush tree
      • ceph osd df tree
    • Change the weight for an OSD

      • ceph osd crush reweight <osd.N> <weight>
    • The important difference between ceph osd reweight and ceph osd crush reweight

      • "ceph osd crush reweight" sets the CRUSH weight of the OSD. This weight is an arbitrary value (generally the size of the disk in TB or something) and controls how much data the system tries to allocate to the OSD.
      • "ceph osd reweight" sets an override weight on the OSD. This value is in the range 0 to 1, and forces CRUSH to re-place (1-weight) of the data that would otherwise live on this drive. It does not change the weights assigned to the buckets above the OSD, and is a corrective measure in case the normal CRUSH distribution isn’t working out quite right.
      • "ceph osd reweight" is temporary. "ceph osd crush reweight" is sticky, permanent (until you change it again).
      • Setting a weight of an OSD to 0 is effectively setting the OSD "out" - you don’t want it to store data.

    The Monitor’s Cluster Map contains

    • Monitor Map
      • Unique Cluster ID, details of each Mon node, current epoch, date/time of last change
    • OSD Map
      • Contains the cluster fsid, when the map was created and last modified, a list of pools, replica sizes, PG numbers, a list of OSDs and their status
    • PG Map
      • Contains the PG version, its time stamp, the last OSD map epoch, the full ratios, and details on each placement group such as the PG ID, the Up Set, the Acting Set, the state of the PG (e.g., active + clean), and data usage statistics for each pool
    • MDS Map
      • Contains the current MDS map epoch, references to pool(s) for storing metadata, list of MDS servers, and which metadata servers are up and in
    • CRUSH Map
    • Contains a list of storage devices, the failure domain hierarchy (e.g., device, host, rack, row, room, etc.), and rules for traversing the hierarchy when storing data

    CRUSH Hierarchy

    • The CRUSH Map includes details of physical & network infrastructure
    • The CRUSH Map hierarchy is defined by a storage architect
    • The default hierarchical list of infrastructure elements: (Hierarchy of CRUSH buckets)
      • OSD
      • host
      • chassis 刀片机箱
      • rack 机架
      • row
      • pdu 电源分配单元
      • pod 性能优化的数据中心(Performance Optimize Datacenter),基于标准化设施的最佳实践,每个POD内IT部分包含的5000台服务器,分属到200个机架,如果以每台服务器400W功率计算的话,每个机柜需要10KW的供电,即每个POD的IT负载容量是2MW。
      • room
      • datacenter
      • region
      • root
    • CRUSH is the algorithm and calculation for distributing data through the cluster.
    • CRUSH Map obviously plays a part in how those CRUSH calculations work.

    CRUSH Hierarchy

    CRUSH Map Sections (Six main sections)

    • tunables: adjustments to legacy behavior
    • devices: The list of OSDs (usually no customization needed) ○ "device class" is meaningful; useful in relation to creating/using CRUSH rulesets ○ Standard "device class" values are "hdd.", "ssd.", and "nvme." ○ Example: device 7 osd.7
    • types: types of buckets (usually no customization needed)
    • buckets: the most functional, customizable aspect of the Map ○ A bucket typically represents a physical location in the cluster, has a “type” ○ Nodes (containers such as hosts) and leaves (storage devices such as OSDs)
    • rules: define policies of how data should be distributed ○ The behind-the-scenes rules that CRUSH follows for data placement ○ IMPORTANT: this is NOT the same as the "ruleset". In fact, a ruleset is the combined set of all of these six Map sections.
    • choose_args (optional): Rarely used exceptional settings to adjust weights
    • From the documentation: "choose_args are alternative weights associated with the hierarchy that have been adjusted to optimize data placement. A single choose_args map can be used for the entire cluster, or one can be created for each individual pool."

    buckets

    Erasure Coding

    • In information theory : an erasure code is a forward error correction (FEC, 前向纠错) code for the binary erasure channel, which transforms a message of k symbols into a longer message (code word) with n symbols such that the original message can be recovered from a subset of the n symbols.
      • The fraction r = k/n is called the code rate
      • The fraction k’/k, where k’ denotes the number of symbols required for recovery, is called reception efficiency
    • Another (easier) way of describing EC: It’s like RAID in Clustered Storage

    Erasure Coding in SES

    • The default resilience strategy in SES is simple replication * SES Simple replication has overheads, size=3 means 3 times the storage requirements
    • Simplistic EC details:
      • k = number of “data” chunks, split across “k” number of OSDs
      • m = number of “parity” chunks, split across “m” number of OSDs
        • Ceph calls these “coding chunks”
      • r (size) = k + m
    admin:~ # ceph osd crush rule ls
    + SUSE Enterprise Storage Foundation - UPSkilling       

    SUSE Enterprise Storage Foundation

    Ceph’s RADOS

    Everything in Ceph is stored in the RADOS cluster as Objects.

    Ceph’s RADOS:

    • Reliable
    • Autonomous
    • Distributed
    • Object
    • Store

    Ceph’s RADOS is composed of storage devices represented as:

    • Raw storage device with LVM (BlueStore)
    • Standard filesystem (FileStore)

    The Object Storage Daemon (OSD) integrates each disk device as part of the RADOS cluster.

    Object Storage Daemon

    Ceph architecture

    Ceph is made of two groups of core components

    • The RADOS cluster

      • Provides the clustered object storage
      • Native Object Access methods
    • Gateways

      • Access to the object store via standard protocols
      • librados
      • Direct access to the object store using a native API
      • Examples:
        • iSCSI Gateway (block) -- IGW - iSCSI is a storage area network (SAN) protocol.
          • Exports RADOS Block Device (--RBD) (images as iSCSI disks).
          • iSCSI access to RDB images.
          • lrbd is no longer used in SES6.
        • RADOS Gateway (object) -- RGW
          • Is an object storage interface built on top of librados
        • CephFS (file)
          • A MetaData Service (MDS) is required.
          • Direct access to RADOS (no LIBRADOS layer)
          • Traditional filesystem interface.
        • NFS Ganesha (object, file)
          • Provides NFS exports to:
            • RGW buckets for access the object store
            • The CephFS filesystem

    Client access the storage services of the cluster via Gateways and Librados

    The librados API allows interaction with the following daemons:

    • The Ceph Monitor, which maintains a master copy of the cluster map

    The Ceph OSD Daemon (OSD), which stores data as objects on a storage node.

    Enhanced SES Architecture Diagram

    Enhanced SES Architecture Diagram

    Object Storage

    • The state of the art of distributed SDS storage
    • Unstructured, to better accommodate large files and large quantities of files
    • For large files and large quantities of files, it performs far better than other storage mechanisms
    • Agile, scalable, extensible, and very customizable
    • Invisible to the end-user, ideal for backends
    • Perfect for systemic, application-based use cases. Not necessarily perfect for direct Human use
    • Through associated metadata, ideal for computational analytics
      • And CRUSH takes full advantage of this (CRUSH = Controllable Replication Under Scalable Hashing)
    • Ceph Object Storage supports two interfaces:
      • S3-compatible
      • Swift-compatible
    • Object-based storage has become the standard backend storage mechanism for nearly all modern Enterprise Storage Solutions.

    Ceph OSDs (Object Storage Daemon)

    • A Ceph OSD (object storage daemon, ceph-osd) stores data, handles data replication, recovery, rebalancing, and provides some monitoring information to Ceph Monitors and Managers by checking other Ceph OSD Daemons for a heartbeat.
      • The Ceph Storage Cluster receives data from Ceph Clients.
      • Clients (dedicated access points, e.g., gateway) could be a Ceph Block Device, Ceph Object Storage, the Ceph Filesystem or a custom implementation using librados.
        • The client requests the cluster status from a monitor node
        • The client uses the status information to identify the location of objects in the cluster
        • The client accesses the objects directly via the OSD node
      • The OSD then stores the data as objects. Each object corresponds to a file in a filesystem which is stored on an OSD.
    • The OSD Daemons take care of the reads and writes on the storage disks.
    • When OSDs are deployed in SES5 the default is to use BlueStore which uses the raw disk and does not require a linux file system to be placed on the disk before it can be used.
    • OSD Daemons store all data as objects in a flat namespace, i.e. no hierarchy of directories.
    • At least 3 Ceph OSDs are normally required for redundancy and high availability.

    Ceph Mons (Monitor Servers)

    • A Ceph Monitor (ceph-mon) maintains maps of the cluster state, including
      • Monitor Map
      • Manager Map
      • OSD Map
      • PG Map
      • CRUSH Map
      • Epoch
    • These maps are critical cluster state required for Ceph daemons to coordinate with each other. Monitors are also responsible for managing authentication between daemons and clients.
    • At least 3 monitors are normally required for redundancy and high availability. An odd number of MONs is required (Paxos requires). Typically 5 is sufficient for mid or large size cluster.
      • Paxos is an algorithm used for cluster durability.
      • Leader MON expects 50% quality to create quorum.
      • Lowest IP address becomes leader. After new leader selected, all MONs polled for epoch.
      • Leader Mon provides lease to non-leader MONs.
    • MONs are NOT in the data path. They merely serve maps to clients so that the client can go directly to the appropriate OSD storage daemon. Monitor nodes MONs do not serve objects to clients

    Ceph MGRs (Manager Daemon)

    • A Ceph Manager daemon (ceph-mgr) is responsible for keeping track of runtime metrics and the current state of the Ceph cluster, including
      • storage utilization
      • current performance metrics
      • system load
    • The Ceph Manager daemons also host python-based plugins to manage and expose Ceph cluster information, including a web-based dashboard and REST API.
    • At least two managers are normally required for high availability.
    • MON/MGR daemons are required to run on the same node in SES

    Ceph MDS (Metadata)

    • A Ceph Metadata Server (MDS, ceph-mds) stores metadata on behalf of the Ceph Filesystem.
    • Ceph Metadata Servers allow POSIX file system users to execute basic commands, for example ls -al without placing an large load on the Ceph Storage Cluster.

    Ceph Admin Node

    • The Admin node fills the “master” and “admin” roles for DeepSea.
    • Salt is central to SES. SES’s deployment and life-cycle management tool.
    • The Admin node keeps master Ceph authentication keys.
    • Prometheus and Grafana provide cluster monitoring and data graphs

    Ceph Dashboard

    • Runs as a Ceph Manager module; runs via the MON/MGR node.

    Client Access

    • Object Storage (RADOSGW or RGW)
    • Block Storage (RDB). RBD is built on top of librados.
    • CephFS
    • iSCSI Gateway
    • NFS Ganesha
    • SMB/CIFS
    • Native protocols via librados

    Client Access

    Objects in Ceph

    • Everything stored in the Ceph cluster is an object. Default object size is 4MB.
    • Each object has a unique ID. ID is unique across the entire cluster.
    • Objects have associated metadata, in Key: Value pairs.
    • In Ceph we use Storage Pools to organize or arrange our objects.
      • Pools are logical partitions to manage objects
      • Parameters to manage Pools
        • Number of data replicas (Replica pools), or configuration of Erasure Code (size) (Erasure Code pools)
          • Erasure Code is an alternative to Replication
            • SIZE for Erasure Coding is K+M
            • K = Data chunks, M = “Parity” chunks
            • EC reduces the hit to raw storage capacity
            • EC incurs a greater hit to CPU on the OSDs as a tradeoff
        • Placement Groups (PG)
          • PG is used to manage objects within a pool.
          • PGs are associated with OSDs for data placement
          • PGs are a central feature of CRUSH that help to provide data durability by way of distribution
          • No PG is owned by an OSD. (And an OSD is not owned by a PG.)
          • PGs are just randomly assigned by CRUSH through all of the OSDs to spread the distribution of data
          • Locating data among PGs is all handled economically, deterministically by way of CRUSH calculations
          • PGs are subdivisions of pools
          • Number of PGs = (Number of OSDs * 100) / Size (Size = either num of replicas, or K+M)
            • The final PG number must be a power of 2
          • The default number of PGs for a new pool is 8 (it's too small for enterprise solution)
          • In general, PG and PGP numbers should be the same
            • pg_num is the number of placement groups for the pool (placement group, 存储池的目录个数 )
            • pgp_num is the number of placement groups that will be considered for placement (placement group for placement purpose, pg可用的osd排列组合数量)
            • 仅增大pg_num:
              • 因为pgp_num没变,pg的osd组合仍只能从当前pgp_num种组合里面挑选,导致新增的pg和旧pg会有重复的osd组合,该现象称之为分裂;此时pg和osd的映射没有变;
            • 继续增大pgp_num,使其等于pg_num:
              • 旧pg没有变化,但新增pg的osd组合发生变化,即开始重新分布
            • Placement Group (PG) 归置组状态
              1. Creating
                • 创建存储池时,它会创建指定数量的归置组。
                • ceph 在创建一或多个归置组时会显示 creating。
                • 创建完后,在其归置组的 Acting Set 里的 OSD 将建立互联。
                • 一旦互联完成,归置组状态应该变为 active+clean,意思是ceph 客户端可以向归置组写入数据了。
              2. peering
                • ceph 为归置组建立互联时,会让存储归置组副本的 OSD 之间就其中的对象和元数据状态达成一致。
                • ceph 完成了互联,也就意味着存储着归置组的 OSD 就其当前状态达成了一致。
                • 然而,互联过程的完成并不能表明各副本都有了数据的最新版本。
              3. active
                • ceph 完成互联进程后,一归置组就可变为 active。
                • active 状态通常意味着在主归置组和副本中的数据都可以读写。
              4. clean
                • 某一归置组处于 clean 状态时,主 OSD 和副本 OSD 已成功互联,并且没有偏离的归置组。
                • ceph 已把归置组中的对象复制了规定次数。
              5. degraded
                • 当客户端向主 OSD 写入数据时,由主 OSD 负责把副本写入其余复制 OSD。
                • 主 OSD 把对象写入复制 OSD 后,在没收到成功完成的确认前,主 OSD 会一直停留在 degraded 状态。
                • 归置组状态可以是 active+degraded 状态,原因在于一 OSD 即使没所有对象也可以处于 active 状态。
                • 如果一OSD 挂了,ceph 会把相关的归置组都标记为 degraded。
                • 那个 OSD 重生后,它们必须重新互联。
                • 然而,如果归置组仍处于 active 状态,即便它处于 degraded 状态,客户端还可以向其写入新对象。
                • 如果一 OSD 挂了,且 degraded 状态持续,ceph 会把 down 的 OSD 标记为在集群外(out)、并把那些 down 掉的 OSD 上的数据重映射到其它 OSD。
                • 从标记为 down 到 out 的时间间隔由 mon osd down out interval 控制,默认是 300 秒。
                • 归置组也会被降级(degraded),因为归置组找不到本应存在于归置组中的一或多个对象,这时,你不能读或写找不到的对象,但仍能访问其它位于降级归置组中的对象。
              6. recovering
                • ceph 被设计为可容错,可抵御一定规模的软、硬件问题。
                • 当某 OSD 挂了(down)时,其内容版本会落后于归置组内的其它副本。
                • 它重生(up)时,归置组内容必须更新,以反映当前状态。
                • 在此期间,OSD 在recovering 状态。
                • 一次硬件失败可能牵连多个 OSD。比如一个机柜的网络交换机失败了,这会导致多个主机落后于集群的当前状态,问题解决后每一个 OSD 都必须恢复。
                • ceph 提供了很多选项来均衡资源竞争,如新服务请求、恢复数据对象和恢复归置组到当前状态。
                • osd recovery delay start 选项允许一 OSD 在开始恢复进程前,先重启、重建互联、甚至处理一些重放请求。
                • osd recovery threads 选项限制恢复进程的线程数,默认为 1 线程。
                • osd recovery thread timeout 设置线程超时,因为多个OSD 可能交替失败、重启和重建互联。
                • osd recovery max active 选项限制一 OSD 最多同时接受多少请求,以防它压力过大而不能正常服务。
                • osd recovery max chunk 选项限制恢复数据块尺寸,以防网络拥塞。
              7. back filling
                • 有新 OSD 加入集群时,CRUSH 会把现有集群内的归置组重分配给它。
                • 强制新 OSD 立即接受重分配的归置组会使之过载,用归置组回填可使这个过程在后台开始。
                • 回填完成后,新 OSD 准备好时就可以对外服务了。
              8. remapped
                • 某一归置组的 Acting Set 变更时,数据要从旧集合迁移到新的。
                • 主 OSD 要花费一些时间才能提供服务,所以它可以让老的主 OSD 持续服务、直到归置组迁移完。
                • 数据迁移完后,主 OSD 会映射到新 acting set。
              9. stale
                • 虽然 ceph 用心跳来保证主机和守护进程在运行,但是 ceph-osd 仍有可能进入 stuck 状态,它们没有按时报告其状态(如网络瞬断)。
                • 默认OSD 守护进程每半秒(0.5)会一次报告其归置组、出流量、引导和失败统计状态,此频率高于心跳阀值。
                • 如果一归置组的主 OSD 所在的 acting set 没能向监视器报告、或者其它监视器已经报告了那个主 OSD 已 down,监视器们就会把此归置组标记为 stale。
                • 启动集群时,会经常看到 stale 状态,直到互联完成。
                • 集群运行一阵后,如果还能看到有归置组位于 stale 状态,就说明那些归置组的主 OSD 挂了(down)、或没在向监视器报告统计信息。
          • Each pool has its own autoscaler settings
          • The PG balancer optimizes the placement of PGs across OSD
            • crush-compat mode
              • It's default mode
              • Uses the compat weight-set feature
            • upmap mode.
              • It's perfect mode, which an equal number of PGs on each OSD
              • Use fine-grained control over the PG mapping
        • Snapshots
        • Rulesets to manage CRUSH placement
          • Each pool has a defined CRUSH ruleset
            • A CRUSH ruleset is a definition of how the OSDs organize data
            • This allows configuration of data distribution to be managed per pool
            • A single CRUSH ruleset can be reused by multiple pools
            • A ruleset can take into account: 需要考虑的点
              • physical layout of nodes in the cluster
              • organization of network infrastructure
              • selection of OSDs backed by SSDs versus HDDs, etc
          • Each pool can use either Replication or Erasure Coding
            • Replication is the original, default approach to resiliency
          • Erasure Coded pools have an EC Profile assigned
            • Different than CRUSH rulesets, but similar: define how OSDs organize data
            • The profile defines K, M values; encoding method/plugin; etc

    Placement Group

    CRUSH (Controllable Replication Under Scalable Hashing)

    • CRUSH is a key piece of the Ceph storage solution
    • With the CRUSH algorithm used by Ceph:
      • Data is not centrally stored, it is distributed
      • CRUSH calculates the storage location for each object dynamically
      • No requirement to store a global index of object locations

    CRUSH Algorithm

    • The CRUSH algorithm deterministically calculates the location of any object in the Ceph RADOS cluster
    • Overhead is low and calculation is performed by each client
    • As no metadata store is required, CRUSH removes the limitations of traditional metadata based management
    • No direct control over the placement of your data in the cluster
    • Higher CPU requirements

    CRUSH Maps and Rulesets

    • CRUSH Rulesets are the named sets of rules:
      • Combining all of the customizable CRUSH behavior settings
      • Assigned to pool to govern how the pool’s data is distributed in the cluster
    • CRUSH Maps are central to how Ceph distributes data, and maintaining the durability of the data
      • When the cluster is deployed, Ceph creates a simple default ruleset for replicated pools: replicated_rule
    • CRUSH behavior depends on the behaviors and performance of storage devices
    • CRUSH Maps should be crafted to take advantage of those behaviors
    • Rulesets should be used to clearly identify how the devices in your environment should be employed
    • Device Classes exist to indicate performance behavior: hdd, ssd, nvme
    • Ceph OSDs will automatically set the Device Class of a storage device when the OSD is started
    • Working with CRUSH Map Rulesets
      • List the OSDs, which host each OSD belongs to:
        • ceph osd tree
        • ceph osd df tree
        • ceph osd df tree -f json-pretty
      • Find the host of a specific OSD:
        • ceph osd find 8
      • Show the existing defined rulesets:
        • ceph osd crush rule ls
      • Examine the definition of an existing ruleset:
        • ceph osd crush rule dump <rulesetname>
      • There are 3 options for creating a new ruleset:
        • simple
        • replicated
        • erasure
      • Creating new rulesets:
        • ceph osd crush rule create-replicated <name>
        • ceph osd crush rule create-erasure <name> <ec_profile>
      • Create a new ruleset using a Device Class:
        • create-replicated <name> <root> <failure-domain-level> <device-class>
        • <root>
          • Description : The name of the node under which data should be placed.
          • Type : String
          • Example : default (rarely would you need to make this different than “default”)
        • <failure-domain-type> or <failure-doamin-level>
          • Description : The type of CRUSH node (bucket) across which replicas should be separated.
          • Type : String
          • Example : rack
        • <device-class>
          • Description : The device class data should be placed on.
          • Type : String
          • Example : ssd

    CRUSH Weight

    • You may need to move data around
      • New nodes
      • degraded nodes
      • rebalancing
    • View the current CRUSH weights
      • ceph osd crush tree
      • ceph osd df tree
    • Change the weight for an OSD

      • ceph osd crush reweight <osd.N> <weight>
    • The important difference between ceph osd reweight and ceph osd crush reweight

      • "ceph osd crush reweight" sets the CRUSH weight of the OSD. This weight is an arbitrary value (generally the size of the disk in TB or something) and controls how much data the system tries to allocate to the OSD.
      • "ceph osd reweight" sets an override weight on the OSD. This value is in the range 0 to 1, and forces CRUSH to re-place (1-weight) of the data that would otherwise live on this drive. It does not change the weights assigned to the buckets above the OSD, and is a corrective measure in case the normal CRUSH distribution isn’t working out quite right.
      • "ceph osd reweight" is temporary. "ceph osd crush reweight" is sticky, permanent (until you change it again).
      • Setting a weight of an OSD to 0 is effectively setting the OSD "out" - you don’t want it to store data.

    The Monitor’s Cluster Map contains

    • Monitor Map
      • Unique Cluster ID, details of each Mon node, current epoch, date/time of last change
    • OSD Map
      • Contains the cluster fsid, when the map was created and last modified, a list of pools, replica sizes, PG numbers, a list of OSDs and their status
    • PG Map
      • Contains the PG version, its time stamp, the last OSD map epoch, the full ratios, and details on each placement group such as the PG ID, the Up Set, the Acting Set, the state of the PG (e.g., active + clean), and data usage statistics for each pool
    • MDS Map
      • Contains the current MDS map epoch, references to pool(s) for storing metadata, list of MDS servers, and which metadata servers are up and in
    • CRUSH Map
    • Contains a list of storage devices, the failure domain hierarchy (e.g., device, host, rack, row, room, etc.), and rules for traversing the hierarchy when storing data

    CRUSH Hierarchy

    • The CRUSH Map includes details of physical & network infrastructure
    • The CRUSH Map hierarchy is defined by a storage architect
    • The default hierarchical list of infrastructure elements: (Hierarchy of CRUSH buckets)
      • OSD
      • host
      • chassis 刀片机箱
      • rack 机架
      • row
      • pdu 电源分配单元
      • pod 性能优化的数据中心(Performance Optimize Datacenter),基于标准化设施的最佳实践,每个POD内IT部分包含的5000台服务器,分属到200个机架,如果以每台服务器400W功率计算的话,每个机柜需要10KW的供电,即每个POD的IT负载容量是2MW。
      • room
      • datacenter
      • region
      • root
    • CRUSH is the algorithm and calculation for distributing data through the cluster.
    • CRUSH Map obviously plays a part in how those CRUSH calculations work.

    CRUSH Hierarchy

    CRUSH Map Sections (Six main sections)

    • tunables: adjustments to legacy behavior
    • devices: The list of OSDs (usually no customization needed) ○ "device class" is meaningful; useful in relation to creating/using CRUSH rulesets ○ Standard "device class" values are "hdd.", "ssd.", and "nvme." ○ Example: device 7 osd.7
    • types: types of buckets (usually no customization needed)
    • buckets: the most functional, customizable aspect of the Map ○ A bucket typically represents a physical location in the cluster, has a “type” ○ Nodes (containers such as hosts) and leaves (storage devices such as OSDs)
    • rules: define policies of how data should be distributed ○ The behind-the-scenes rules that CRUSH follows for data placement ○ IMPORTANT: this is NOT the same as the "ruleset". In fact, a ruleset is the combined set of all of these six Map sections.
    • choose_args (optional): Rarely used exceptional settings to adjust weights
    • From the documentation: "choose_args are alternative weights associated with the hierarchy that have been adjusted to optimize data placement. A single choose_args map can be used for the entire cluster, or one can be created for each individual pool."

    buckets

    Erasure Coding

    • In information theory : an erasure code is a forward error correction (FEC, 前向纠错) code for the binary erasure channel, which transforms a message of k symbols into a longer message (code word) with n symbols such that the original message can be recovered from a subset of the n symbols.
      • The fraction r = k/n is called the code rate
      • The fraction k’/k, where k’ denotes the number of symbols required for recovery, is called reception efficiency
    • Another (easier) way of describing EC: It’s like RAID in Clustered Storage

    Erasure Coding in SES

    • The default resilience strategy in SES is simple replication * SES Simple replication has overheads, size=3 means 3 times the storage requirements
    • Simplistic EC details:
      • k = number of “data” chunks, split across “k” number of OSDs
      • m = number of “parity” chunks, split across “m” number of OSDs
        • Ceph calls these “coding chunks”
      • r (size) = k + m
    admin:~ # ceph osd crush rule ls
     replicated_rule
     

    Replication vs Erasure Code

    • Replication (default):
      • Use Case: active data
      • Simple and fast
      • Uses more disk space
    • Erasure coding:
      • Use Case: archive data, more static data
      • Calculates recovery data (needs more CPU power)
      • Definable redundancy level
    • Example: K data chunks = 2 , M code chunks = 1
      • Similar to a replication size of 2
      • But with only 50% more raw storage consumed
    • Example: for 1GB of effective storage
      • replication pool of size of 2 needs 2GB raw storage
      • erasure coded pool with k=2/m=1 only requires 1.5GB raw storage

    EC Overwrites

    • Historically, EC only works properly with Objects
      • EC only allowed appends; overwrites were not allowed
      • Works perfectly for objects in buckets
      • but doesn’t work well with Block or CephFS
    • With recent releases of SES, EC can work well with Block and CephFS
      • Facilitated by “EC Overwrites” feature
      • Store data in an EC Pool, and store object metadata in a Replicated Pool
      • Requires a little extra work when defining pools, but worth it
      • ceph osd pool set allow_ec_overwrites true

    EC Profiles

    • Using Erasure Coding, each Pool is assigned an EC Profile
      • Multiple pools can share a single Profile
      • The profile is just a definition
    • Each Profile has multiple settings
      • The common required settings for all Profiles are K, M
    • EC Profiles must be created before EC Pools can be created
      • Created from the Dashboard or CLI
    • Once an EC Profile is created, you can create a CRUSH Ruleset based on the EC profile
    • Once a pool is created, its EC Profile properties cannot be changed
    • Main profile parameters
      • K:
      • M:
      • stripe_unit - allows you to adjust the size of the data chunk
        • Default size is 4K
        • stripe_unit : size of data striped across devices; default 4K
        • This variable can also be set in the master configuration (osd_erasure_code_stripe_unit)
    • EC plugins - choose your favorite EC algorithm via a plugin
      • jerasure/gf-complete (default, free, open, and very fast) (www.jerasure.org)
      • ISA (Intel library; optimized for modern Intel processors) (only runs on Intel processors)
      • LRC (“Locally Repairable Code”; layers over existing plugins)
      • SHEC (“Shingled EC”; trades extra storage for recovery efficiency)
      • CLAY (“Coupled LAYer”; good for reduced network traffic)

    Creating Erasure Code Profiles and Pools

    • Syntax: ceph osd erasure-code-profile OPTIONS
      • Option Description
        • get - view details of an existing EC profile
        • set - set a profile (create a profile), requires k and m values, with optional values such as ruleset, plugin. Once you create a profile, you can’t change it.
          • ceph osd erasure-code-profile set <name> k=<int> m=<int> [plugin=<plugin>] [stripe_unit=<string>]
        • ls - list profiles
        • rm - Remove an EC profile
          • ceph osd erasure-code-profile rm <name>
      • Common example (below)
      • The default profile ‒ 2+1=3; data is written over 3 OSDs ‒ Two data chunks ‒ One code (parity) chunk ‒ Uses jerasure plugin with standard Reed/Solomon (reed_sol_van) technique
      • Setting a Custom EC Profile
        • Option: ‒ Profile name ‒ K : number of stripes required ‒ M : number of failed units
        • Example:
          • ceph osd erasure-code-profile set example-profile k=8 m=2 ruleset-failure-domain=host
          • ruleset-failure-domain = crush bucket level for failure
    admin:/etc/ceph #  ceph osd erasure-code-profile \
     set common_profile \
    @@ -116,4 +116,4 @@
     
     admin:~ # ceph dashboard ac-user-show admin
     {"username": "admin", "password": "$2b$12$4lC/AU7jc6midTZufj4P4.rBtVzRGf7Zy7fUbD6G9YfdfVEwkwuUy", "roles": ["administrator"], "name": null "email":null"lastUpdate": 1601874928}
    -
  • Health from the Dashboard

    • Cluster Status
    • Monitors
    • OSDs
    • Manager Daemons
    • Hosts
    • Object Gateways
    • Metadata Service
    • iSCSI Gateways
  • Cluster Performance from Dashboard

    • Client IOPS
    • Client Throughput
    • Client Read/Write
    • Recovery Throughput
    • Scrub
  • Performance Data

    • Hosts: Overall Performance
    • Monitors: Performance Counters
    • OSDs: Relative Read/Write bar graphs, and Overall Performance
    • Pools: Relative Read/Write bar graphs, and Overall Performance
    • Block images: Overall Performance
    • CephFS: Performance Details
    • RGW: Overall Performance
  • Cluster Capacity from Dashboard

    • Capacity data:
    • Number of Pools
    • Raw Capacity
    • Number of Objects (Ceph objects, not user objects from RGW)
    • Placement Groups per OSD
    • Placement Group Status
  • Basic Troubleshooting

    Ceph Logs

    • Logs normally stored in /var/log/ceph/
    • No real logs on the admin node
    • Each service has its own log on the MON, Storage and Gateway nodes
    • Logs handled routinely by logrotate
    • Ceph has logs that are stored to files and in memory (triggered by event or manual request)
    • There are 21 different levels of logging: 0-20 (0 is no logging; 20 is the most verbose logging)
    • There are many subsystems that do their own logging, and can be configured independently
      • Most common: mon, osd, mgr, rados, rbd, mds, rgw
      • Others: asok, auth, client, filestore, journal, monc, ms, paxos, and more
    • There are only 3 types of daemons: osd, mon, mds
    • Using Tell to Change Log Levels

    1) Check the Dashboard and Health.

    Common commands

    • ceph status
    • ceph osd status
    • ceph osd df
    • ceph osd utilization
    • ceph osd pool stats
    • ceph osd tree
    • ceph pg stat

    2) Network Troubleshooting

    • Always be sure that the network (and related services) are working properly
    • Ceph depends heavily on tightly synchronized time; make sure network time services are working on each node
    • DNS hostnames are similarly essential

    3) Check the Logs

    • Go to the node of the component implicated in HEALTH

    4: Raise the DEBUG Level. Follow this simple formula:

    • Raise the debug level (a little each time until you see the problem)
    • Check the logs
    • Repeat as necessary
    • Don’t forget to restore the debug level back to its normal level

    5) Check the Storage Device

    If the problem is with an OSD or a storage device, go straight to the device:

    • hdparm
    • smartctl

    And check out the details of the combination of OSD and storage device:

    • lsblk
    • /var/lib/ceph/osd/

    6) Scrub (or not)

    Sometimes simply scrubbing an OSD or PG can cause the checksum-ing process to reveal problems

    • At least some problems can be made more clear with the result of scrub and/or deep-scrub
    • Even doing a scrub can kick Ceph into fixing the problem itself

    And don’t forget ceph osd repair

    On the other hand, sometimes Scrub can make things worse. If you suspect Scrub is part of the problem, turn it off:

    • ceph osd set noscrub
    • ceph osd unset noscrub

    7) Placement Groups

    When Placement Groups cause problems: * ceph pg dump summary * ceph pg dump pools * ceph pg dump_jason * ceph pg dump | less

    Followed by a strategic “repair” of the PG * ceph pg repair <pgid>

    8) Running supportconfig

    • YaST Support Module
    • From CLI: supportconfig
    • The collected data is stored in a file called /var/log/nts_<hostname>_<datetime>.txz
    \ No newline at end of file +
  • Health from the Dashboard

    • Cluster Status
    • Monitors
    • OSDs
    • Manager Daemons
    • Hosts
    • Object Gateways
    • Metadata Service
    • iSCSI Gateways
  • Cluster Performance from Dashboard

    • Client IOPS
    • Client Throughput
    • Client Read/Write
    • Recovery Throughput
    • Scrub
  • Performance Data

    • Hosts: Overall Performance
    • Monitors: Performance Counters
    • OSDs: Relative Read/Write bar graphs, and Overall Performance
    • Pools: Relative Read/Write bar graphs, and Overall Performance
    • Block images: Overall Performance
    • CephFS: Performance Details
    • RGW: Overall Performance
  • Cluster Capacity from Dashboard

    • Capacity data:
    • Number of Pools
    • Raw Capacity
    • Number of Objects (Ceph objects, not user objects from RGW)
    • Placement Groups per OSD
    • Placement Group Status
  • Basic Troubleshooting

    Ceph Logs

    • Logs normally stored in /var/log/ceph/
    • No real logs on the admin node
    • Each service has its own log on the MON, Storage and Gateway nodes
    • Logs handled routinely by logrotate
    • Ceph has logs that are stored to files and in memory (triggered by event or manual request)
    • There are 21 different levels of logging: 0-20 (0 is no logging; 20 is the most verbose logging)
    • There are many subsystems that do their own logging, and can be configured independently
      • Most common: mon, osd, mgr, rados, rbd, mds, rgw
      • Others: asok, auth, client, filestore, journal, monc, ms, paxos, and more
    • There are only 3 types of daemons: osd, mon, mds
    • Using Tell to Change Log Levels

    1) Check the Dashboard and Health.

    Common commands

    • ceph status
    • ceph osd status
    • ceph osd df
    • ceph osd utilization
    • ceph osd pool stats
    • ceph osd tree
    • ceph pg stat

    2) Network Troubleshooting

    • Always be sure that the network (and related services) are working properly
    • Ceph depends heavily on tightly synchronized time; make sure network time services are working on each node
    • DNS hostnames are similarly essential

    3) Check the Logs

    • Go to the node of the component implicated in HEALTH

    4: Raise the DEBUG Level. Follow this simple formula:

    • Raise the debug level (a little each time until you see the problem)
    • Check the logs
    • Repeat as necessary
    • Don’t forget to restore the debug level back to its normal level

    5) Check the Storage Device

    If the problem is with an OSD or a storage device, go straight to the device:

    • hdparm
    • smartctl

    And check out the details of the combination of OSD and storage device:

    • lsblk
    • /var/lib/ceph/osd/

    6) Scrub (or not)

    Sometimes simply scrubbing an OSD or PG can cause the checksum-ing process to reveal problems

    • At least some problems can be made more clear with the result of scrub and/or deep-scrub
    • Even doing a scrub can kick Ceph into fixing the problem itself

    And don’t forget ceph osd repair

    On the other hand, sometimes Scrub can make things worse. If you suspect Scrub is part of the problem, turn it off:

    • ceph osd set noscrub
    • ceph osd unset noscrub

    7) Placement Groups

    When Placement Groups cause problems: * ceph pg dump summary * ceph pg dump pools * ceph pg dump_jason * ceph pg dump | less

    Followed by a strategic “repair” of the PG * ceph pg repair <pgid>

    8) Running supportconfig

    • YaST Support Module
    • From CLI: supportconfig
    • The collected data is stored in a file called /var/log/nts_<hostname>_<datetime>.txz
    Back to top
    \ No newline at end of file diff --git a/linux/SRE/01-fundamentals/index.html b/linux/SRE/01-fundamentals/index.html index 75bc29e6..37f1e444 100644 --- a/linux/SRE/01-fundamentals/index.html +++ b/linux/SRE/01-fundamentals/index.html @@ -1,46 +1,46 @@ - 第一章 Linux基础 - UPSkilling

    第一章 Linux基础

    1.官方文档

    Rocky Linux Instructional Books

    openSUSE Documentation

    Ubuntu Documentation

    2.系统环境

    2.1.Rocky

    使用版本:Rocky 9.0

    从网站下载Rocky系统ISO镜像,或者通过wget命令下载Rocky系统ISO镜像。

    wget https://download.rockylinux.org/pub/rocky/9.0/isos/x86_64/Rocky-9.0-x86_64-dvd.iso
    + 第一章 Linux基础 - UPSkilling       

    第一章 Linux基础

    1.官方文档

    Rocky Linux Instructional Books

    openSUSE Documentation

    Ubuntu Documentation

    2.系统环境

    2.1.Rocky

    使用版本:Rocky 9.0

    从网站下载Rocky系统ISO镜像,或者通过wget命令下载Rocky系统ISO镜像。

    wget https://download.rockylinux.org/pub/rocky/9.0/isos/x86_64/Rocky-9.0-x86_64-dvd.iso
     

    安装时我选择了激活root用户,选择了Server模式安装(没有GUI)。

    root登录,执行下面命令修改sudo权限。

    visudo
    -

    并激活下面一行(不设密码,方便练习):

    %wheel  ALL=(ALL)       NOPASSWD: ALL
    -

    创建用户vagrant,并设置wheel为主要组和修改密码。

    adduser vagrant
    -usermod -g wheel vagrant
    -passwd vagrant
    -

    设定hostname(包括别名),并查看结果。

    hostnamectl set-hostname --static "rocky9"
    -hostnamectl set-hostname --pretty "rocky9"
    +

    并激活下面一行(不设密码,方便练习):

    %wheel  ALL=(ALL)       NOPASSWD: ALL
    +

    创建用户vagrant,并设置wheel为主要组和修改密码。

    adduser vagrant
    +usermod -g wheel vagrant
    +passwd vagrant
    +

    设定hostname(包括别名),并查看结果。

    hostnamectl set-hostname --static "rocky9"
    +hostnamectl set-hostname --pretty "rocky9"
     
     hostnamectl
    -cat /etc/hostname
    -

    小贴士:

    由systemd控制的主机名的服务配置信息:/usr/lib/systemd/system/systemd-hostnamed.service

    Rocky的软件源的配置信息保存在目录/etc/yum.repos.d/下。如果访问默认源比较慢,可以更新阿里源或者科大源。

    更换阿里源。

    sed -e 's|^mirrorlist=|#mirrorlist=|g' \
    -    -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
    -    -i.bak \
    -    /etc/yum.repos.d/Rocky-*.repo
    -

    更换科大源。

    sed -e 's|^mirrorlist=|#mirrorlist=|g' \
    -    -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.ustc.edu.cn/rocky|g' \
    -    -i.bak \
    -    /etc/yum.repos.d/rocky-extras.repo \
    -    /etc/yum.repos.d/rocky.repo
    -

    刷新缓存。

    dnf makecache
    -

    2.2.Ubuntu

    使用版本:Ubuntu 2204

    设定root用户的密码。

    sudo passwd root
    -

    通过安装时已创建的用户vagrant登录。执行下面命令修改sudo权限。

    sudo visudo
    +cat /etc/hostname
    +

    小贴士:

    由systemd控制的主机名的服务配置信息:/usr/lib/systemd/system/systemd-hostnamed.service

    Rocky的软件源的配置信息保存在目录/etc/yum.repos.d/下。如果访问默认源比较慢,可以更新阿里源或者科大源。

    更换阿里源。

    sed -e 's|^mirrorlist=|#mirrorlist=|g' \
    +    -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
    +    -i.bak \
    +    /etc/yum.repos.d/Rocky-*.repo
    +

    更换科大源。

    sed -e 's|^mirrorlist=|#mirrorlist=|g' \
    +    -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.ustc.edu.cn/rocky|g' \
    +    -i.bak \
    +    /etc/yum.repos.d/rocky-extras.repo \
    +    /etc/yum.repos.d/rocky.repo
    +

    刷新缓存。

    dnf makecache
    +

    2.2.Ubuntu

    使用版本:Ubuntu 2204

    设定root用户的密码。

    sudo passwd root
    +

    通过安装时已创建的用户vagrant登录。执行下面命令修改sudo权限。

    sudo visudo
     

    添加vagrant到特权用户(Rocky和openSUSE不需要添加),并激活sudo一行(不设密码,方便练习):

    # User privilege specification
    -root    ALL=(ALL:ALL) ALL
    -vagrant ALL=(ALL:ALL) ALL
    +root    ALL=(ALL:ALL) ALL
    +vagrant ALL=(ALL:ALL) ALL
     
     # Allow members of group sudo to execute any command
    -sudo    ALL=(ALL:ALL) NOPASSWD: ALL
    -

    修改用户vagrant的主要组为sudo

    sudo usermod -g sudo vagrant
    -

    修改主机名和别名。

    sudo hostnamectl set-hostname ubuntu2204
    -sudo hostnamectl set-hostname ubuntu2204 --pretty
    -

    小贴士:

    如何处理Username is not in the sudoers file. This incident will be reported问题。

    如果没有初始化root用户的密码,且当前用户也无法执行sudo命令,可以通过下面步骤通过recovery救援模式进行恢复。

    • shift键开机,进入grub启动菜单。(VMWare也适用)
    • 向下移动高亮条,选择菜单Advanced options for Ubuntu,并确认回车。
    • 选择带有recovery mode的内核,确认回车。
    • 向下移动高亮条,选择菜单root Drop to root shell prompt,并确认回车。
    • 回车确认press Enter for maintenance
    • 出现root的命令提示符后,执行命令mount -o rw,remount /
    • 执行命令passwdroot设定密码。
    • 执行命令adduser username sudo把指定用户加入sudo组。
    • 执行命令visudo进行必要的修正或修改。

    2.3.openSUSE

    使用版本:Leap 15.4

    选择服务器模式安装,无图形界面。安装中不创建用户。

    创建用户vagrant,并设置wheel为主要组。

    useradd -m -g wheel -G root -c "vagrant" vagrant
    -passwd vagrant
    -

    执行visudo命令,激活下面一行,添加sudo权限。

    %wheel ALL=(ALL) NOPASSWD: ALL
    -

    修改主机名和别名。

    sudo hostnamectl set-hostname lizard
    -sudo hostnamectl set-hostname lizard --pretty
    -

    3.常用命令

    说明:

    默认当前操作用户为vagrant

    3.1.修改提示符风格

    执行下面命令可以看到当前系统的命令提示符格式。

    echo $PS1
    +sudo    ALL=(ALL:ALL) NOPASSWD: ALL
    +

    修改用户vagrant的主要组为sudo

    sudo usermod -g sudo vagrant
    +

    修改主机名和别名。

    sudo hostnamectl set-hostname ubuntu2204
    +sudo hostnamectl set-hostname ubuntu2204 --pretty
    +

    小贴士:

    如何处理Username is not in the sudoers file. This incident will be reported问题。

    如果没有初始化root用户的密码,且当前用户也无法执行sudo命令,可以通过下面步骤通过recovery救援模式进行恢复。

    • shift键开机,进入grub启动菜单。(VMWare也适用)
    • 向下移动高亮条,选择菜单Advanced options for Ubuntu,并确认回车。
    • 选择带有recovery mode的内核,确认回车。
    • 向下移动高亮条,选择菜单root Drop to root shell prompt,并确认回车。
    • 回车确认press Enter for maintenance
    • 出现root的命令提示符后,执行命令mount -o rw,remount /
    • 执行命令passwdroot设定密码。
    • 执行命令adduser username sudo把指定用户加入sudo组。
    • 执行命令visudo进行必要的修正或修改。

    2.3.openSUSE

    使用版本:Leap 15.4

    选择服务器模式安装,无图形界面。安装中不创建用户。

    创建用户vagrant,并设置wheel为主要组。

    useradd -m -g wheel -G root -c "vagrant" vagrant
    +passwd vagrant
    +

    执行visudo命令,激活下面一行,添加sudo权限。

    %wheel ALL=(ALL) NOPASSWD: ALL
    +

    修改主机名和别名。

    sudo hostnamectl set-hostname lizard
    +sudo hostnamectl set-hostname lizard --pretty
    +

    3.常用命令

    说明:

    默认当前操作用户为vagrant

    3.1.修改提示符风格

    执行下面命令可以看到当前系统的命令提示符格式。

    echo $PS1
     

    各系统默认设置是有差异的。

    # Rocky
    -[\u@\h \W]\$
    +[\u@\h \W]\$
     
     # Ubuntu
    -\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$
    +\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$
     
     # openSUSE
     \u@\h:\w>
    @@ -68,58 +68,58 @@
     # openSUSE
     PS1="\[\e[37;40m\][\[\e[32;40m\]\u\[\e[35;40m\]@\h:\[\e[36;40m\]\w\[\e[0m\]]\$ "
     

    将上述PS1的设定,追加到当前用户的~/.bashrc文件末尾,以实现对当前用户的提示符风格做持久保存。

    3.2.Linux的内外部命令

    内部命令 (internal command)实际上是shell程序的一部分,包含的是一些比较简单的linux系统命令,这些命令由shell程序识别并在shell程序内部完成运行,通常在linux系统加载运行时shell就被加载并驻留在系统内存中。

    外部命令 (external command)是linux系统中的实用程序部分,系统加载时并不随系统一起被加载到内存中,而是在需要时才将其调用内存。通常外部命令的实体并不包含在shell中,但是其命令执行过程是由shell程序控制的。

    比如:

    执行命令type -t cp,系统返回结果是file,外部命令。

    执行命令type -t cd,系统返回结果builtin,内部命令。

    执行命令enable -a cp,系统返回-bash: enable: cp: not a shell builtin,也可以判断是否为内部命令。

    对于内部命令,可以通过enable命令来启用或者禁用。

    # 禁用cd命令
    -enable -n cd
    +enable -n cd
     
     # 查看所有被禁用的命令
    -enable -n
    +enable -n
     
     # 启用cd命令
    -enable cd
    -

    对于命令,可以通过whereis命令来查看路径。

    whereis cp
    -whereis cd
    +enable cd
    +

    对于命令,可以通过whereis命令来查看路径。

    whereis cp
    +whereis cd
     

    3.3.CPU信息

    lscpu
    -cat /proc/cpuinfo
    +cat /proc/cpuinfo
     

    3.4.内存使用状态

    free
    -cat /proc/meminfo
    +cat /proc/meminfo
     

    3.5.硬盘和分区情况

    lsblk
    -

    openSUSE在VMWare默认安装的状态:

    NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
    -sda      8:0    0  200G  0 disk 
    -├─sda1   8:1    0    8M  0 part 
    -├─sda2   8:2    0  198G  0 part /home
    -│                               /var
    -│                               /opt
    -│                               /usr/local
    -│                               /root
    -│                               /tmp
    -│                               /srv
    -│                               /boot/grub2/x86_64-efi
    -│                               /boot/grub2/i386-pc
    -│                               /.snapshots
    -│                               /
    -└─sda3   8:3    0    2G  0 part [SWAP]
    -sr0     11:0    1  3.8G  0 rom 
    -

    Ubuntu在VMWare默认安装的状态:

    NAME                      MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
    -loop0                       7:0    0 61.9M  1 loop /snap/core20/1405
    -loop1                       7:1    0 63.2M  1 loop /snap/core20/1623
    -loop2                       7:2    0 79.9M  1 loop /snap/lxd/22923
    -loop3                       7:3    0   48M  1 loop /snap/snapd/17029
    -loop4                       7:4    0  103M  1 loop /snap/lxd/23541
    -loop5                       7:5    0   48M  1 loop /snap/snapd/17336
    -sda                         8:0    0   50G  0 disk 
    -├─sda1                      8:1    0    1M  0 part 
    -├─sda2                      8:2    0    2G  0 part /boot
    -└─sda3                      8:3    0   48G  0 part 
    -  └─ubuntu--vg-ubuntu--lv 253:0    0   24G  0 lvm  /
    -sr0                        11:0    1  1.4G  0 rom 
    -

    Rocky在VMWare默认安装的状态:

    NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
    -sda           8:0    0   50G  0 disk 
    -├─sda1        8:1    0    1G  0 part /boot
    -└─sda2        8:2    0   49G  0 part 
    -  ├─rl-root 253:0    0 45.1G  0 lvm  /
    -  └─rl-swap 253:1    0  3.9G  0 lvm  [SWAP]
    -sr0          11:0    1  7.9G  0 rom
    +

    openSUSE在VMWare默认安装的状态:

    NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
    +sda      8:0    0  200G  0 disk 
    +├─sda1   8:1    0    8M  0 part 
    +├─sda2   8:2    0  198G  0 part /home
    +│                               /var
    +│                               /opt
    +│                               /usr/local
    +│                               /root
    +│                               /tmp
    +│                               /srv
    +│                               /boot/grub2/x86_64-efi
    +│                               /boot/grub2/i386-pc
    +│                               /.snapshots
    +│                               /
    +└─sda3   8:3    0    2G  0 part [SWAP]
    +sr0     11:0    1  3.8G  0 rom 
    +

    Ubuntu在VMWare默认安装的状态:

    NAME                      MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
    +loop0                       7:0    0 61.9M  1 loop /snap/core20/1405
    +loop1                       7:1    0 63.2M  1 loop /snap/core20/1623
    +loop2                       7:2    0 79.9M  1 loop /snap/lxd/22923
    +loop3                       7:3    0   48M  1 loop /snap/snapd/17029
    +loop4                       7:4    0  103M  1 loop /snap/lxd/23541
    +loop5                       7:5    0   48M  1 loop /snap/snapd/17336
    +sda                         8:0    0   50G  0 disk 
    +├─sda1                      8:1    0    1M  0 part 
    +├─sda2                      8:2    0    2G  0 part /boot
    +└─sda3                      8:3    0   48G  0 part 
    +  └─ubuntu--vg-ubuntu--lv 253:0    0   24G  0 lvm  /
    +sr0                        11:0    1  1.4G  0 rom 
    +

    Rocky在VMWare默认安装的状态:

    NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
    +sda           8:0    0   50G  0 disk 
    +├─sda1        8:1    0    1G  0 part /boot
    +└─sda2        8:2    0   49G  0 part 
    +  ├─rl-root 253:0    0 45.1G  0 lvm  /
    +  └─rl-swap 253:1    0  3.9G  0 lvm  [SWAP]
    +sr0          11:0    1  7.9G  0 rom
     

    3.6.系统架构信息

    arch
    -

    openSUSE,Ubuntu和Rocky的返回结果都是x86_64

    3.7.内核版本

    uname -r
    +

    openSUSE,Ubuntu和Rocky的返回结果都是x86_64

    3.7.内核版本

    uname -r
     

    三个发行版返回的结果不尽相同:

    # openSUSE
     5.14.21-150400.24.21-default
     
    @@ -128,113 +128,113 @@
     
     # Rocky
     5.14.0-70.17.1.el9_0.x86_64
    -

    3.8.操作系统版本

    cat /etc/os-release
    -cat /etc/issue
    +

    3.8.操作系统版本

    cat /etc/os-release
    +cat /etc/issue
     
     # Rocky 9
    -sudo cat /etc/redhat-release
    -
    lsb-release -a
    -lsb_release -cs
    -lsb_release -is
    -lsb_release -rs
    -

    在openSUSE中,需要安装lsb-release包。执行lsb-release -alsb_release -a返回的结果是一样的。

    sudo zypper in lsb-release
    -

    在Ubuntu中,需要安装lsb-release包。只能执行lsb_release -a

    sudo apt install lsb-release
    +sudo cat /etc/redhat-release
    +
    lsb-release -a
    +lsb_release -cs
    +lsb_release -is
    +lsb_release -rs
    +

    在openSUSE中,需要安装lsb-release包。执行lsb-release -alsb_release -a返回的结果是一样的。

    sudo zypper in lsb-release
    +

    在Ubuntu中,需要安装lsb-release包。只能执行lsb_release -a

    sudo apt install lsb-release
     

    在Rocky 9中,找不到lsb-release相关的包。

    3.9.日期和时间

    显示默认格式的当前日期。

    date
     

    三个系统的默认日期格式略有不同。

    # openSUSE
    -Mon 24 Oct 2022 09:28:06 AM CST
    +Mon 24 Oct 2022 09:28:06 AM CST
     
     # Ubuntu
    -Mon Oct 24 01:28:09 AM UTC 2022
    +Mon Oct 24 01:28:09 AM UTC 2022
     
     # Rocky
    -Mon Oct 24 09:24:01 AM CST 2022
    -

    显示自1970-01-01 00:00:00 UTC到当前的秒数。

    date +%s
    -

    将上一命令中的描述转换为系统默认日期格式。

    date -d @`date +%s`
    -date --date=@'1666575347'
    -

    显示硬件时钟。

    hwclock 也被称为 Real Time Clock (RTC)。

    在Rocky9中,clock有一个软连接指向hwclock/usr/sbin/clock -> hwclock。在openSUSE和Ubuntu中只有hwclock

    ll /usr/sbin/clock
    -ll /usr/sbin/hwclock
    -

    读取RTC时间。

    sudo hwclock --get
    -sudo hwclock -r
    -

    校准时间:

    • -s, –hctosys : 以RTC硬件时间来校准系统时间。
    • -w, –systohoc : 以系统时间来校准RTC硬件时间。

    显示当前系统时区。

    ll /etc/localtime
    -

    系统可能会返回不同结果,例如:

    /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
    -/etc/localtime -> /usr/share/zoneinfo/Etc/UTC
    -

    显示当前可以时区列表。

    timedatectl list-timezones
    -timedatectl list-timezones | grep -i Asia
    -

    修改当前系统时区。

    sudo timedatectl set-timezone Asia/Shanghai
    -

    显示日历。

    cal -y
    -

    openSUSE和Rocky中,使用cal命令需要安装util-linux包。 Ubuntu中,使用cal命令需要安装ncal包。

    sudo apt install ncal
    -
    -sudo zypper se util-linux
    -sudo yum install util-linux
    +Mon Oct 24 09:24:01 AM CST 2022
    +

    显示自1970-01-01 00:00:00 UTC到当前的秒数。

    date +%s
    +

    将上一命令中的描述转换为系统默认日期格式。

    date -d @`date +%s`
    +date --date=@'1666575347'
    +

    显示硬件时钟。

    hwclock 也被称为 Real Time Clock (RTC)。

    在Rocky9中,clock有一个软连接指向hwclock/usr/sbin/clock -> hwclock。在openSUSE和Ubuntu中只有hwclock

    ll /usr/sbin/clock
    +ll /usr/sbin/hwclock
    +

    读取RTC时间。

    sudo hwclock --get
    +sudo hwclock -r
    +

    校准时间:

    • -s, –hctosys : 以RTC硬件时间来校准系统时间。
    • -w, –systohoc : 以系统时间来校准RTC硬件时间。

    显示当前系统时区。

    ll /etc/localtime
    +

    系统可能会返回不同结果,例如:

    /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
    +/etc/localtime -> /usr/share/zoneinfo/Etc/UTC
    +

    显示当前可以时区列表。

    timedatectl list-timezones
    +timedatectl list-timezones | grep -i Asia
    +

    修改当前系统时区。

    sudo timedatectl set-timezone Asia/Shanghai
    +

    显示日历。

    cal -y
    +

    openSUSE和Rocky中,使用cal命令需要安装util-linux包。 Ubuntu中,使用cal命令需要安装ncal包。

    sudo apt install ncal
    +
    +sudo zypper se util-linux
    +sudo yum install util-linux
     

    3.10.用户登录信息

    • whoami:当前登录用户
    • who:系统当前所有的登录会话
    • w:系统当前所有的登录会话及所作的操作

    提示:

    MOTD is the abbreviation of "Message Of The Day", and it is used to display a message when a remote user login to the Linux Operating system using SSH. Linux administrators often need to display different messages on the login of the user, like displaying custom information about the server or any necessary information.

    编辑文件/etc/motd可以自定义"Message Of The Day"的信息。

    Ubuntu 2204新安装后没有这个文件,需要自己创建。 openSUSE新安装后有预定义的信息。 Rocky9 新安装后有该文件,空白文件无内容。

    3.11.会话管理工具

    screen工具

    • screen -S <your_name> (Create new screen session)
    • screen -ls (list current screen sessions)
    • screen -x <your_name> (Attach to existing screeen session, sync between both)
    • screen -r <your_name> (Reattach existing screen session)

    tmux工具

    tmux 是指 Terminal Multiplexer.

    安装tmux工具。

    # Rocky
    -sudo yum install tmux
    +sudo yum install tmux
     
     # Ubuntu
    -sudo apt install tmux
    +sudo apt install tmux
     
     # openSUSE
    -sudo zypper in tmux
    -

    常用方法:

    • tmux new -s <your_name> (Create new session)
    • tmux detach (Detach current session)
    • tmux ls (list current sessions)
    • tmux attach -t <your_name> (Reattach existing session)
    • tmux switch -t <your_name> (Switch to another session)
    • tmux kill-session -t <your_name> (Kill existing session)
    • tmux list-keys (List all short keys)
    • tmux list-commands (List commands and parameters)
    • tmux info (List all sessions info)
    • tmux split-window (Split window)

    3.12.echo命令

    echo命令中可以输出变量,如果变量是用是单引号引起来,表示这个变量不用IFS替换!!

    • echo "Home=$HOME"的输出结果是Home=/home/vagrant
    • echo 'Home=$HOME'的输出结果是Home=$HOME

    echo -e启用\字符的解释功能,比如:

    • echo -e "a\x0Ab",输出字符ab,中间\x0A代表十六进制OA(即回车)
    • echo -e "\x4A \x41 \x4D \x45 \x53",输出结果是J A M E S

    提示:

    以通过man 7 ascii来查看各进制的含义。

    echo -e输出带颜色字符。

    示例:

    echo -e "\e[35m 紫色 \e[0m"
    -echo -e "\e[43m 黄底 \e[0m"
    -echo -e "\e[93m 黑底黄字 \e[0m"
    +sudo zypper in tmux
    +

    常用方法:

    • tmux new -s <your_name> (Create new session)
    • tmux detach (Detach current session)
    • tmux ls (list current sessions)
    • tmux attach -t <your_name> (Reattach existing session)
    • tmux switch -t <your_name> (Switch to another session)
    • tmux kill-session -t <your_name> (Kill existing session)
    • tmux list-keys (List all short keys)
    • tmux list-commands (List commands and parameters)
    • tmux info (List all sessions info)
    • tmux split-window (Split window)

    3.12.echo命令

    echo命令中可以输出变量,如果变量是用是单引号引起来,表示这个变量不用IFS替换!!

    • echo "Home=$HOME"的输出结果是Home=/home/vagrant
    • echo 'Home=$HOME'的输出结果是Home=$HOME

    echo -e启用\字符的解释功能,比如:

    • echo -e "a\x0Ab",输出字符ab,中间\x0A代表十六进制OA(即回车)
    • echo -e "\x4A \x41 \x4D \x45 \x53",输出结果是J A M E S

    提示:

    以通过man 7 ascii来查看各进制的含义。

    echo -e输出带颜色字符。

    示例:

    echo -e "\e[35m 紫色 \e[0m"
    +echo -e "\e[43m 黄底 \e[0m"
    +echo -e "\e[93m 黑底黄字 \e[0m"
     

    参考信息:

    字体颜色:

    • \e[30m: 黑色
    • \e[31m: 红色
    • \e[32m: 绿色
    • \e[33m: 黄色
    • \e[34m: 蓝色
    • \e[35m: 紫色
    • \e[36m: 青色
    • \e[37m: 白色
    • \e[40m: 黑底
    • \e[41m: 红底
    • \e[42m: 绿底
    • \e[43m: 黄底
    • \e[44m: 蓝底
    • \e[45m: 紫底
    • \e[46m: 青底
    • \e[47m: 白底

    背景颜色:

    • \e[90m: 黑底黑字
    • \e[91m: 黑底红字
    • \e[92m: 黑底绿字
    • \e[93m: 黑底黄字
    • \e[94m: 黑底蓝字
    • \e[95m: 黑底紫字
    • \e[96m: 黑底青字
    • \e[97m: 黑底白字

    控制属性:

    • \e[0m 关闭所有属性
    • \e[1m 设置高亮度
    • \e[4m 下划线
    • \e[5m 闪烁
    • \e[7m 反显,撞色显示,显示为白字黑底,或者显示为黑底白字
    • \e[8m 消影,字符颜色将会与背景颜色相同
    • \e[nA 光标上移 n 行
    • \e[nB 光标下移 n 行
    • \e[nC 光标右移 n 行
    • \e[nD 光标左移 n 行
    • \e[y;xH 设置光标位置
    • \e[2J 清屏
    • \e[K 清除从光标到行尾的内容
    • \e[s 保存光标位置
    • \e[u 恢复光标位置
    • \e[?25 隐藏光标
    • \e[?25h 显示光标

    3.13.man命令

    安装包:

    # openSUSE
    -sudo zypper install man-pages man-pages-zh_CN man-pages-posix
    +sudo zypper install man-pages man-pages-zh_CN man-pages-posix
     
     # Rocky
    -sudo yum install man-pages
    +sudo yum install man-pages
     
     # Ubuntu
    -sudo apt install man-db manpages-posix manpages manpages-zh
    -sudo apt install manpages-dev manpages-posix-dev
    +sudo apt install man-db manpages-posix manpages manpages-zh
    +sudo apt install manpages-dev manpages-posix-dev
     

    更新mandb

    mandb
     

    查找某个命令的man信息,例如查找crontab命令的信息。

    # 精确查找
    -man -f crontab
    -whatis crontab
    +man -f crontab
    +whatis crontab
     
     # 模糊查询
    -man -k crontab
    -apropos crontab
    +man -k crontab
    +apropos crontab
     

    输出结果如下:

    crontab (5)          - files used to schedule the execution of programs
     crontab (1)          - maintains crontab files for individual users
     crontab (1p)         - schedule periodic background work
     

    查找crontab第5章的内容,则可以执行:

    man 5 crontab
     

    常用快捷键示例s:

    • 1G : go to the 1st line
    • 10G : go to the 10th line
    • G : go to the end of the page
    • /^SELinux : search the word SELinux
    • /section OPTIONS : go to the section OPTIONS

    3.14.tr命令

    tr命令可以对来自标准输入的字符进行替换、压缩和删除。它可以将一组字符变成另一组字符。

    格式:tr [OPTION]... SET1 [SET2]

    举例:

    # 将输入字符由大写转换为小写
    -$ echo "HELLO WORLD" | tr 'A-Z' 'a-z'
    -hello world
    +$ echo "HELLO WORLD" | tr 'A-Z' 'a-z'
    +hello world
     
     # 删除出现的数字
    -$ echo "HELLO 1234 WORLD 4567" | tr -d '0-9'
    -HELLO  WORLD
    +$ echo "HELLO 1234 WORLD 4567" | tr -d '0-9'
    +HELLO  WORLD
     
     # 从输入文本中将不在补集中的所有字符删除(只保留数字1,2,3,4,5)
    -$ echo "HELLO 1234 WORLD 4567" | tr -d -c '1-5'
    +$ echo "HELLO 1234 WORLD 4567" | tr -d -c '1-5'
     123445
     
     # 将连续重复的字符以单独一个字符表示
    -$ echo "HELLOOO 1222235555555554" | tr -s 'O215'
    -HELLO 12354
    +$ echo "HELLOOO 1222235555555554" | tr -s 'O215'
    +HELLO 12354
     
     # 删除由于Windows文件造成的'^M'字符
    -$ cat file.txt | tr -s '\r' '\n' > new.txt
    -$ cat file.txt | tr -d '\r' > new.txt
    +$ cat file.txt | tr -s '\r' '\n' > new.txt
    +$ cat file.txt | tr -d '\r' > new.txt
     
     # 将换行符替换成制表符
    -$ cat file.txt | tr '\n' '\t' > new.txt
    +$ cat file.txt | tr '\n' '\t' > new.txt
     
     # 将大写字母转换为小写字母
    -$ echo "HELLO 1234 WORLD 4567" | tr '[:upper:]' '[:lower:]'
    -hello 1234 world 4567
    +$ echo "HELLO 1234 WORLD 4567" | tr '[:upper:]' '[:lower:]'
    +hello 1234 world 4567
     

    3.15.tee命令

    tee命令基于标准输入读取数据,标准输出或文件写入数据。

    举例:

    # ping命令的输出,不仅输出到屏幕,也同时写入文件output.txt中(覆盖式写入)。
    -$ ping www.baidu.com | tee output.txt
    +$ ping www.baidu.com | tee output.txt
     
     # ping命令的输出,不仅输出到屏幕,也同时写入文件output.txt中(追加式写入)。
    -$ ping www.baidu.com | tee -a output.txt
    +$ ping www.baidu.com | tee -a output.txt
     
     # ping命令的输出,不仅输出到屏幕,也同时写入多个文件中(覆盖式写入)。
    -$ ping www.baidu.com | tee output1.txt output2.txt output3.txt
    +$ ping www.baidu.com | tee output1.txt output2.txt output3.txt
     
     # ls命令的输出写入文件output.txt中,并作为wc命令的输入。
    -$ ls *.txt | tee output.txt | wc -l
    +$ ls *.txt | tee output.txt | wc -l
     4
     # cat output.txt
     f1.txt
    @@ -242,73 +242,73 @@
     output.txt
     test.txt
     

    技巧:

    在vi使用中,通过tee命令提升文件写入权限。

    比如非root用户执行vi /etc/hosts,在vi中使用:w !sudo tee %可以提高权限保存这个文件。

    3.16.语言环境LANG

    安装语言包。

    # Ubuntu
    -sudo apt install locales-all
    +sudo apt install locales-all
     
     # Rocky
    -sudo yum install glibc-langpack-zh.x86_64
    +sudo yum install glibc-langpack-zh.x86_64
     
     # openSUSE
    -sudo zypper install glibc-locale glibc-locale-32bit glibc-locale-base
    -

    查看当前语言设置:

    echo $LANG
    +sudo zypper install glibc-locale glibc-locale-32bit glibc-locale-base
    +

    查看当前语言设置:

    echo $LANG
     
    -locale -a
    -locale -k LC_TIME
    +locale -a
    +locale -k LC_TIME
     
    -localectl status
    -localectl list-locales
    +localectl status
    +localectl list-locales
     

    全局locale配置(Global locale settings)。

    # openSUSE & Rocky
    -sudo cat /etc/locale.conf
    +sudo cat /etc/locale.conf
     
     # Ubuntu
    -sudo cat /etc/default/locale
    -

    临时修改当前session的locale。

    LANG="zh_CN.utf8" 
    -

    永久修改locale设置。

    sudo localectl set-locale LANG=zh_CN.utf8
    -

    修改回原设置。

    sudo localectl set-locale LANG=en_US.utf8
    +sudo cat /etc/default/locale
    +

    临时修改当前session的locale。

    LANG="zh_CN.utf8" 
    +

    永久修改locale设置。

    sudo localectl set-locale LANG=zh_CN.utf8
    +

    修改回原设置。

    sudo localectl set-locale LANG=en_US.utf8
     

    Tips:

    • Mac OS ssh登陆Linux是终端提示/usr/bin/manpath: can't set the locale; make sure $LC_* and $LANG are correct
    • 解决方法:在本地mac电脑上修改/etc/ssh/ssh_config或者/etc/ssh/ssh_config文件,删除掉或者注释掉这一行配置内容 # SendEnv LANG LC_*
    • 如果使用的是Iterm2,可以打开iterm2preferences -> Profiles -> Terminal菜单里关闭Set locale variables automatically选项。

    3.17.符号$用法

    符号$的用法:

    • $,获取变零值。
    x=1
    -echo $x
    -echo "$x"
    +echo $x
    +echo "$x"
     

    建议使用"$x",以避免shell编程中产生歧义。如下例:

    s="this is a string"
    -echo $s
    -echo "this is a string"
    -

    执行[ $s == "this is a string" ]会报错,这是实际生成的比较式this is a string == "this is a string"。 我们预期的是"this is a string" == "this is a string",所以需要改成[ "$s" == "this is a string" ]

    • $0, $1, $n, $#

    生成一个测试脚本。

    echo 'echo $0 $1 $2 $#' > test.sh
    -chmod 755 test.sh
    -

    验证各个参数位置。

    ./test.sh a b c d e
    -

    输出结果:

    ./test.sh a b 5
    +echo $s
    +echo "this is a string"
    +

    执行[ $s == "this is a string" ]会报错,这是实际生成的比较式this is a string == "this is a string"。 我们预期的是"this is a string" == "this is a string",所以需要改成[ "$s" == "this is a string" ]

    • $0, $1, $n, $#

    生成一个测试脚本。

    echo 'echo $0 $1 $2 $#' > test.sh
    +chmod 755 test.sh
    +

    验证各个参数位置。

    ./test.sh a b c d e
    +

    输出结果:

    ./test.sh a b 5
     

    结论:

    • $0输出脚本文件名;
    • $1输出第一个参数;
    • $2输出第二个参数;
    • $#输出参数个数。

    • ${}

    ${}用于区分变量的边界。

    下面例子中,$abc无结果输出,${a}bc输出结果stringbc,通过{}指定了某个字符属于变量。

    a="string"
    -echo ${a}bc
    -echo $abc
    +echo ${a}bc
    +echo $abc
     
    • ${#}

    ${#}是返回变量值的长度。

    s='this is a string'
    -echo "$s"
    -echo "${#s}"
    +echo "$s"
    +echo "${#s}"
     

    命令echo "${#s}"输出结果是字串this is a string的长度16

    • $?

    $?是返回上一命令是否成功的状态,0代表成功,非零代表失败。

    ls是一个命令,所以返回值是0tom是一个不存在的命令,则返回127

    ls
    -echo $?
    +echo $?
     
     tom
    -echo $?
    -
    • $()

    $()等同于反引号。echo $(ls)等同于执行ls命令。

    $()的弊端是,不是所有的类unix系统都支持,反引号是肯定支持的。

    $()的优势是直观,在转移处理时,比反引号直观容易些。

    echo $(ls)
    +echo $?
    +
    • $()

    $()等同于反引号。echo $(ls)等同于执行ls命令。

    $()的弊端是,不是所有的类unix系统都支持,反引号是肯定支持的。

    $()的优势是直观,在转移处理时,比反引号直观容易些。

    echo $(ls)
     # test.sh
     
    -echo $(cat $(ls))
    +echo $(cat $(ls))
     # echo $0 $1 $2 $#
    -

    上述嵌套格式中,ls命令的输出,是cat命令的输入,可以进行多层嵌套,内层命令的输出是外层命令的输入。

    • $[]

    $[]是表达式计算。

    echo $[3 + 2]
    -
    • $-

    $-显示shell当前所使用的选项。

    执行echo $-,输出结果himBHs。himBH每一个字符是一个shell的选项。

    • $!

    $!获取最后一个运行的后台进程的pid。

    比如执行cat test.sh &,结果中会包含一个pid号,马上着执行echo $!,如果2个命令间隔之间没有其他后台进程执行,则可以得到和前面一致的pid号。

    • !$

    !$返回上一条命令的最后一个参数。

    执行./test.sh a b c iamhere,得到结果./test.sh a b 4。 执行echo !$,得到2个结果,echo iamhereiamhere

    • !!

    !!输出上一条命令,并执行。

    !!会先输出上一条命令cat test.sh,然后再执行这条命令,第二行即执行结果。

    [vagrant@lizard:~]$ cat test.sh 
    -echo $0 $1 $2 $#
    -[vagrant@lizard:~]$ !!
    -cat test.sh 
    -echo $0 $1 $2 $#
    -
    • $$

    $$ 输出当前进程的pid。

    echo $$
    -
    • $@ & $*

    $@$*是对传入参数的不同体现,$@是以变量形式引用传入参数,$*是以数组的形式引用传入参数。

    创建一个文件script.sh包含下面的脚本。并添加执行权限chmod 755 script.sh

    echo '$@以变量方式引用传入参数:'
    -
    -for x in "$@"
    +

    上述嵌套格式中,ls命令的输出,是cat命令的输入,可以进行多层嵌套,内层命令的输出是外层命令的输入。

    • $[]

    $[]是表达式计算。

    echo $[3 + 2]
    +
    • $-

    $-显示shell当前所使用的选项。

    执行echo $-,输出结果himBHs。himBH每一个字符是一个shell的选项。

    • $!

    $!获取最后一个运行的后台进程的pid。

    比如执行cat test.sh &,结果中会包含一个pid号,马上着执行echo $!,如果2个命令间隔之间没有其他后台进程执行,则可以得到和前面一致的pid号。

    • !$

    !$返回上一条命令的最后一个参数。

    执行./test.sh a b c iamhere,得到结果./test.sh a b 4。 执行echo !$,得到2个结果,echo iamhereiamhere

    • !!

    !!输出上一条命令,并执行。

    !!会先输出上一条命令cat test.sh,然后再执行这条命令,第二行即执行结果。

    [vagrant@lizard:~]$ cat test.sh 
    +echo $0 $1 $2 $#
    +[vagrant@lizard:~]$ !!
    +cat test.sh 
    +echo $0 $1 $2 $#
    +
    • $$

    $$ 输出当前进程的pid。

    echo $$
    +
    • $@ & $*

    $@$*是对传入参数的不同体现,$@是以变量形式引用传入参数,$*是以数组的形式引用传入参数。

    创建一个文件script.sh包含下面的脚本。并添加执行权限chmod 755 script.sh

    echo '$@以变量方式引用传入参数:'
    +
    +for x in "$@"
     do
    -  echo $x
    +  echo $x
     done
     
    -echo '$*以数组的形式引用传入参数:'
    +echo '$*以数组的形式引用传入参数:'
     
    -for x in "$*"
    +for x in "$*"
     do
    -  echo $x
    +  echo $x
     done
     

    输出结果:

    $@以变量方式引用传入参数:
     a
    @@ -317,5 +317,5 @@
     5
     d
     $*以数组的形式引用传入参数:
    -a b 3 5 d
    -
    \ No newline at end of file +a b 3 5 d +
    Back to top
    \ No newline at end of file diff --git a/linux/SRE/02-filesystem/index.html b/linux/SRE/02-filesystem/index.html index a3894b21..647200d6 100644 --- a/linux/SRE/02-filesystem/index.html +++ b/linux/SRE/02-filesystem/index.html @@ -1,6 +1,6 @@ - 第二章 文件系统 - UPSkilling

    第二章 文件系统

    文件系统层次标准(Filesystem Hierarchy Standard, FHS),它是Linux 标准库(Linux Standards Base, LSB)规范的一部分。

    根目录/指文件系统树的最高层。 根分区在系统启动时首先挂载。 系统启动时运行的所有程序都必须在此分区中。

    1.主要目录

    以下目录必须在根分区中:

    • /bin - 用户基本程序。
    • 包含未挂载其他文件系统时所需的可执行文件。 例如,系统启动、处理文件和配置所需的程序。
    • 不能关联到独立分区,操作系统启动即会调用的程序。
    • /bin/bash - bash脚本处理
    • /bin/cat - 显示文件内容
    • /bin/cp - 拷贝文件
    • /bin/dd - 拷贝文件(基于字节byte)
    • /bin/gzip - 压缩文件
    • /bin/mount - 挂载文件系统
    • /bin/rm - 删除文件
    • /bin/vi - 文件编辑
    • /sbin - 系统基本程序。
    • 包含基本系统管理的程序。
    • 默认是root用户有权限执行,因此它不在常规用户路径中。
    • 不能关联到独立分区,操作系统启动即会调用的程序
    • 一些重要管理程序:
      • /sbin/fdisk* - 管理硬盘分区
      • /sbin/fsck* - 文件系统检查。不能在运行的系统上面直接执行fsck,损坏根文件系统,执行前需要umount
      • /sbin/mkfs - 创建文件系统
      • /sbin/shutdown - 关闭系统
    • /dev - 设备文件
    • 以太网卡是内核模块,其他硬件都以设备dev的方式展现。
    • 应用程序读取和写入这些文件以操作使用硬件组件。
    • 两种类型设备文件:
      • 字符设备(Character-oriented)– 序列设备(打印机,磁带机,鼠标等)
      • 块设备(Block-oriented)– 硬盘,DVD等
    • 与设备驱动程序的连接通过内核中称为主设备号的通道实现。
    • 过去,这些文件是使用mknod命令手动创建的。 现在当内核发现设备时,它们会由udev自动创建。
    • 一些重要的设备文件:
      • Null设备: - /dev/null
      • Zero设备: - /dev/zero
      • 系统终端: - /dev/console
      • 虚拟终端: - /dev/tty1
      • 串行端口 - /dev/ttyS0
      • 并行端口: - /dev/lp0
      • 软盘驱动器: - /dev/fd0
      • 硬盘驱动器: - /dev/sda
      • 硬盘分区: - /dev/sda1
      • CD-ROM驱动器: - /dev/scd0
    • /etc - 配置文件
    • 存放系统和服务的配置文件。
    • 大部分都是ASCII文件
    • 普通用户可以默认读取其中的大部分内容。 这会带来一个潜在的全问题,因为其中一些文件包含密码,因此重要的是要确保这些文件只能由root用户读取。
    • 根据FHS标准,此处不能放置任何可执行文件,但子目录可能包含shell脚本。
    • 几乎每个已安装的服务在/etc或其子目录中至少有一个配置文件。
    • 一些重要的配置文件:
      • /etc/os-release - 系统版本信息
      • /etc/DIR_COLORS - ls命令中的颜色配置信息(openSUSE和Rocky)
      • /etc/fstab - 配置要挂载的文件系统
      • /etc/profile - Shell登录脚本
      • /etc/passwd - 用户信息集合(不含密码)
      • /etc/shadow - 密码和相关信息
      • /etc/group - 用户组信息集合
      • /etc/cups/* - 用于CUPS打印系统(CUPS=Common UNIX Printing System)
      • /etc/hosts - 主机名机器IP地址
      • /etc/motd - 登录后显示的欢迎信息
      • /etc/issue - 登录前显示的欢迎信息
      • /etc/sysconfig/* - 系统配置文件
    • /lib - 库(Libraries)
    • 许多程序都具有一些通用功能。 这些通用功能可以保存在共享库中。
    • 共享库中文件的扩展名是.so
    • 目录/lib包含的共享库文件主要是被/bin/sbin目录包含的程序所调用。
    • 目录/lib的子目录包含一些额外需要的共享库。
    • 内核模块存储在目录/lib/modules
    • /lib64 - 64位共享库(64-Bit Libraries),类似目录/lib
    • 这个目录因系统架构不同而不同。
    • 一些系统支持不同的二进制格式并保留同一个共享库的不同版本。
    • /usr - 包含应用程序、图形界面文件、库、本地程序、文档等。
    • /usr 即 Unix System Resources. 例如:
    • /usr/X11R6/ - X Window 系统文件
    • /usr/bin/ - 几乎包含所有可执行文件
    • /usr/lib/ - 包含库和应用程序
    • /usr/lib64/ - 包含64位库和应用程序
    • /usr/include/ - 包含C程序的头文件(head file)
    • /usr/local/ - 包含本地安装程序。这个目录下的内容不会被系统升级所覆盖。下面3个目录在初始安装后是空的。
      • /usr/local/bin-
      • /usr/local/sbin-
      • /usr/local/lib-
    • /usr/sbin/ - 系统管理程序
    • /usr/src/ - 内核和应用程序的源代码
      • /usr/src/linux-
    • /usr/share/ - 结构化独立数据
      • /usr/share/doc/ - 文档
      • /usr/share/man/ - man命令使用的内容
    • /opt - 第三方应用程序目录
    • 各发行版包含的应用程序一般存储在目录/usr/lib/
    • 各发行版可选程序,或第三方应用程序则存储在目录/opt
    • 在安装时,会为每个应用程序的文件创建一个目录,其中包含应用程序的名称。比如:
      • /opt/novell-
    • /boot - 引导目录
    • /boot/grub2 - 包含GRUB2的静态引导加载程序文件(GRUB = Grand Unified Boot Loader)。
    • 包含以链接 vmlinuz 和 initrd 标识的内核和 initrd 文件。
    • /root - 管理员的主目录(home directory)。
    • root用户的主目录。其他用户的主目录是在目录/home下。
    • root用户的登录环境配置保存至/root分区中。
    • /home - 用户主目录
    • 每个系统用户都有一个分配的文件区域,该文件区域在登录后成为当前工作目录。 默认情况下,它们存在于/home中。
    • /home中的文件和目录可以位于单独的分区中,也可以位于网络上的另一台计算机上。
    • 用户配置信息和配置文件(user profile and configuration files)主要有:
      • .profile - 用户私有登录脚本
      • .bashrc - bash的配置文件
      • .bash_history - bash环境下保持命令历史记录
    • run - 应用程序状态文件
    • 为应用程序提供了一个标准位置来存储它们需要的临时文件,例如套接字和进程ID。 这些文件不能存储在/tmp中,因为/tmp中的文件可能会被删除。
    • /run/media/<user>/* - 可移动设备的挂载点,例如:
      • /run/media/media_name/
      • /run/media/cdrom/-
      • /run/media/dvd/-
      • /run/media/usbdisk/-
    • /mnt - 文件系统临时挂载点
    • 用于挂载临时使用的文件系统的目录。
    • 文件系统使用 mount 命令挂载,使用 umount 命令删除。
    • 子目录默认不存在,也不会自动创建。
    • /srv - 服务数据目录
    • 存放各种服务的数据,比如:
      • /srv/www - 用于存放 Apache Web Server 的数据
      • /srv/ftp - 用于存放 FTP server 的数据
    • /var - 可变文件(Variable Files)
    • 在系统运行过程中会被修改的文件
    • Important subdirectories:
      • /var/lib/ - 可变库文件,应用程序状态信息数据
      • /var/log/ - 日志文件
      • /var/run/ - 运行中的进程的信息
      • /var/lock/ - 多用户访问时的锁文件
      • /var/cache- 应用程序缓存数据目录
      • /var/opt - 专为/opt下的应用程序存储可变数据
      • /var/mail-
      • /var/spool/ - 应用程序数据池,比如:打印机,邮件
      • /var/spool/mail-
      • /var/spool/cron-
    • /tmp - 临时文件
    • 程序在运行时创建临时文件的位置
    • /proc - 进程文件
    • 虚拟文件系统,不占空间,大小始终为零,保持当前进程的状态信息
    • 包含有关各个进程的信息的目录,根据进程的 PID 号命名
    • 有些值可以临时在线更改生效,但重启后丢失
      • /proc/cpuinfo/ - Processor information
      • /proc/dma/ - Use of DMA ports
      • /proc/interrupts/ - Use of interrupts
      • /proc/ioports/ - Use of I/O ports
      • /proc/filesystems/ - File system formats the kernel knows
      • /proc/modules/ - Active modules
      • /proc/mounts/ - Mounted file systems
      • /proc/net/* - Network information and statistics
      • /proc/partitions/ - Existing partitions
      • /proc/bus/pci/ - Connected PCI devices
      • /proc/bus/scsi/ - Connected SCSI devices
      • /proc/sys/* - System and kernel information
      • /proc/version - Kernel version
    • /sys - 系统信息目录
    • 虚拟文件系统,仅存在于内存中,文件大小为零。主要提供如下信息:
      • 硬件总线(hardware buses)
      • 硬件设备(hardware devices)
      • 有源设备(active devices)
      • 驱动程序(drivers)

    2.文件操作命令

    2.1.显示当前工作目录

    pwd命令(print working directory):

    • -L: 显示链接路径
    • -P:显示真实物理路径

    2.2.相对和绝对路径

    对于绝对路径/etc/firewalld/policies,可以通过下面命令得到该路径的基名policies和目录名/etc/firewalld

    basename /etc/firewalld/policies
    -dirname /etc/firewalld/policies
    -

    2.3.更改目录

    .指当前目录,即pwd命令所返回的目录。

    ..指当前目录的上一级目录,及当前目录的父目录。

    • 切换至父目录:cd ..

    • 切换至当前用户主目录:cd ~

    • 切换至上次工作目录:cd -

    • echo $PWD:当前工作目录

    • echo $OLDPWD:上次工作目录

    2.4.列出目录内容

    ls命令:

    • -a 显示所有文件及目录 (. 开头的隐藏文件也会列出)
    • -A-a ,但不列出 . (目前目录) 及 .. (父目录)
    • -l 除文件名称外,亦将文件型态、权限、拥有者、文件大小等资讯详细列出
    • -r 将文件以相反次序显示(原定依英文字母次序)
    • -t 将文件依建立时间之先后次序列出
    • -F 在列出的文件名称后加一符号;例如可执行档则加 "*", 目录则加 "/"
    • -R 递归列出子目录
    • -S 按文件大小排序,从大到小
    • -1 按一个文件一行列出
    • -t 按文件时间排序,最新的在前
    • -U 不排序输出,按目录存放顺序列出
    • -u 配合-lt,按访问时间排序并显示;配合-l,显示访问时间并按名称排序; 否则按访问时间排序,最新的在前
    • -X 按文件扩展名字母顺序排序输出
    • -F 对不同类型文件显示时附加不同的符号,* / = > @ |之一

    ls命令查看不同文件是的颜色,由/etc/DIR_COLORS和变量@LS_COLORS定义。

    2.5.文件状态stat

    每个文件有三个时间戳:

    • 访问时间 Access Time atime : 读取文件内容。
    • 修改时间 Modify Time mtime : 改变文件内容(数据)。
    • 改变时间 Change Time ctime : 元数据发生改变。

    读取三个时间戳的命令stat

    stat /etc/fstab
    + 第二章 文件系统 - UPSkilling       

    第二章 文件系统

    文件系统层次标准(Filesystem Hierarchy Standard, FHS),它是Linux 标准库(Linux Standards Base, LSB)规范的一部分。

    根目录/指文件系统树的最高层。 根分区在系统启动时首先挂载。 系统启动时运行的所有程序都必须在此分区中。

    1.主要目录

    以下目录必须在根分区中:

    • /bin - 用户基本程序。
    • 包含未挂载其他文件系统时所需的可执行文件。 例如,系统启动、处理文件和配置所需的程序。
    • 不能关联到独立分区,操作系统启动即会调用的程序。
    • /bin/bash - bash脚本处理
    • /bin/cat - 显示文件内容
    • /bin/cp - 拷贝文件
    • /bin/dd - 拷贝文件(基于字节byte)
    • /bin/gzip - 压缩文件
    • /bin/mount - 挂载文件系统
    • /bin/rm - 删除文件
    • /bin/vi - 文件编辑
    • /sbin - 系统基本程序。
    • 包含基本系统管理的程序。
    • 默认是root用户有权限执行,因此它不在常规用户路径中。
    • 不能关联到独立分区,操作系统启动即会调用的程序
    • 一些重要管理程序:
      • /sbin/fdisk* - 管理硬盘分区
      • /sbin/fsck* - 文件系统检查。不能在运行的系统上面直接执行fsck,损坏根文件系统,执行前需要umount
      • /sbin/mkfs - 创建文件系统
      • /sbin/shutdown - 关闭系统
    • /dev - 设备文件
    • 以太网卡是内核模块,其他硬件都以设备dev的方式展现。
    • 应用程序读取和写入这些文件以操作使用硬件组件。
    • 两种类型设备文件:
      • 字符设备(Character-oriented)– 序列设备(打印机,磁带机,鼠标等)
      • 块设备(Block-oriented)– 硬盘,DVD等
    • 与设备驱动程序的连接通过内核中称为主设备号的通道实现。
    • 过去,这些文件是使用mknod命令手动创建的。 现在当内核发现设备时,它们会由udev自动创建。
    • 一些重要的设备文件:
      • Null设备: - /dev/null
      • Zero设备: - /dev/zero
      • 系统终端: - /dev/console
      • 虚拟终端: - /dev/tty1
      • 串行端口 - /dev/ttyS0
      • 并行端口: - /dev/lp0
      • 软盘驱动器: - /dev/fd0
      • 硬盘驱动器: - /dev/sda
      • 硬盘分区: - /dev/sda1
      • CD-ROM驱动器: - /dev/scd0
    • /etc - 配置文件
    • 存放系统和服务的配置文件。
    • 大部分都是ASCII文件
    • 普通用户可以默认读取其中的大部分内容。 这会带来一个潜在的全问题,因为其中一些文件包含密码,因此重要的是要确保这些文件只能由root用户读取。
    • 根据FHS标准,此处不能放置任何可执行文件,但子目录可能包含shell脚本。
    • 几乎每个已安装的服务在/etc或其子目录中至少有一个配置文件。
    • 一些重要的配置文件:
      • /etc/os-release - 系统版本信息
      • /etc/DIR_COLORS - ls命令中的颜色配置信息(openSUSE和Rocky)
      • /etc/fstab - 配置要挂载的文件系统
      • /etc/profile - Shell登录脚本
      • /etc/passwd - 用户信息集合(不含密码)
      • /etc/shadow - 密码和相关信息
      • /etc/group - 用户组信息集合
      • /etc/cups/* - 用于CUPS打印系统(CUPS=Common UNIX Printing System)
      • /etc/hosts - 主机名机器IP地址
      • /etc/motd - 登录后显示的欢迎信息
      • /etc/issue - 登录前显示的欢迎信息
      • /etc/sysconfig/* - 系统配置文件
    • /lib - 库(Libraries)
    • 许多程序都具有一些通用功能。 这些通用功能可以保存在共享库中。
    • 共享库中文件的扩展名是.so
    • 目录/lib包含的共享库文件主要是被/bin/sbin目录包含的程序所调用。
    • 目录/lib的子目录包含一些额外需要的共享库。
    • 内核模块存储在目录/lib/modules
    • /lib64 - 64位共享库(64-Bit Libraries),类似目录/lib
    • 这个目录因系统架构不同而不同。
    • 一些系统支持不同的二进制格式并保留同一个共享库的不同版本。
    • /usr - 包含应用程序、图形界面文件、库、本地程序、文档等。
    • /usr 即 Unix System Resources. 例如:
    • /usr/X11R6/ - X Window 系统文件
    • /usr/bin/ - 几乎包含所有可执行文件
    • /usr/lib/ - 包含库和应用程序
    • /usr/lib64/ - 包含64位库和应用程序
    • /usr/include/ - 包含C程序的头文件(head file)
    • /usr/local/ - 包含本地安装程序。这个目录下的内容不会被系统升级所覆盖。下面3个目录在初始安装后是空的。
      • /usr/local/bin-
      • /usr/local/sbin-
      • /usr/local/lib-
    • /usr/sbin/ - 系统管理程序
    • /usr/src/ - 内核和应用程序的源代码
      • /usr/src/linux-
    • /usr/share/ - 结构化独立数据
      • /usr/share/doc/ - 文档
      • /usr/share/man/ - man命令使用的内容
    • /opt - 第三方应用程序目录
    • 各发行版包含的应用程序一般存储在目录/usr/lib/
    • 各发行版可选程序,或第三方应用程序则存储在目录/opt
    • 在安装时,会为每个应用程序的文件创建一个目录,其中包含应用程序的名称。比如:
      • /opt/novell-
    • /boot - 引导目录
    • /boot/grub2 - 包含GRUB2的静态引导加载程序文件(GRUB = Grand Unified Boot Loader)。
    • 包含以链接 vmlinuz 和 initrd 标识的内核和 initrd 文件。
    • /root - 管理员的主目录(home directory)。
    • root用户的主目录。其他用户的主目录是在目录/home下。
    • root用户的登录环境配置保存至/root分区中。
    • /home - 用户主目录
    • 每个系统用户都有一个分配的文件区域,该文件区域在登录后成为当前工作目录。 默认情况下,它们存在于/home中。
    • /home中的文件和目录可以位于单独的分区中,也可以位于网络上的另一台计算机上。
    • 用户配置信息和配置文件(user profile and configuration files)主要有:
      • .profile - 用户私有登录脚本
      • .bashrc - bash的配置文件
      • .bash_history - bash环境下保持命令历史记录
    • run - 应用程序状态文件
    • 为应用程序提供了一个标准位置来存储它们需要的临时文件,例如套接字和进程ID。 这些文件不能存储在/tmp中,因为/tmp中的文件可能会被删除。
    • /run/media/<user>/* - 可移动设备的挂载点,例如:
      • /run/media/media_name/
      • /run/media/cdrom/-
      • /run/media/dvd/-
      • /run/media/usbdisk/-
    • /mnt - 文件系统临时挂载点
    • 用于挂载临时使用的文件系统的目录。
    • 文件系统使用 mount 命令挂载,使用 umount 命令删除。
    • 子目录默认不存在,也不会自动创建。
    • /srv - 服务数据目录
    • 存放各种服务的数据,比如:
      • /srv/www - 用于存放 Apache Web Server 的数据
      • /srv/ftp - 用于存放 FTP server 的数据
    • /var - 可变文件(Variable Files)
    • 在系统运行过程中会被修改的文件
    • Important subdirectories:
      • /var/lib/ - 可变库文件,应用程序状态信息数据
      • /var/log/ - 日志文件
      • /var/run/ - 运行中的进程的信息
      • /var/lock/ - 多用户访问时的锁文件
      • /var/cache- 应用程序缓存数据目录
      • /var/opt - 专为/opt下的应用程序存储可变数据
      • /var/mail-
      • /var/spool/ - 应用程序数据池,比如:打印机,邮件
      • /var/spool/mail-
      • /var/spool/cron-
    • /tmp - 临时文件
    • 程序在运行时创建临时文件的位置
    • /proc - 进程文件
    • 虚拟文件系统,不占空间,大小始终为零,保持当前进程的状态信息
    • 包含有关各个进程的信息的目录,根据进程的 PID 号命名
    • 有些值可以临时在线更改生效,但重启后丢失
      • /proc/cpuinfo/ - Processor information
      • /proc/dma/ - Use of DMA ports
      • /proc/interrupts/ - Use of interrupts
      • /proc/ioports/ - Use of I/O ports
      • /proc/filesystems/ - File system formats the kernel knows
      • /proc/modules/ - Active modules
      • /proc/mounts/ - Mounted file systems
      • /proc/net/* - Network information and statistics
      • /proc/partitions/ - Existing partitions
      • /proc/bus/pci/ - Connected PCI devices
      • /proc/bus/scsi/ - Connected SCSI devices
      • /proc/sys/* - System and kernel information
      • /proc/version - Kernel version
    • /sys - 系统信息目录
    • 虚拟文件系统,仅存在于内存中,文件大小为零。主要提供如下信息:
      • 硬件总线(hardware buses)
      • 硬件设备(hardware devices)
      • 有源设备(active devices)
      • 驱动程序(drivers)

    2.文件操作命令

    2.1.显示当前工作目录

    pwd命令(print working directory):

    • -L: 显示链接路径
    • -P:显示真实物理路径

    2.2.相对和绝对路径

    对于绝对路径/etc/firewalld/policies,可以通过下面命令得到该路径的基名policies和目录名/etc/firewalld

    basename /etc/firewalld/policies
    +dirname /etc/firewalld/policies
    +

    2.3.更改目录

    .指当前目录,即pwd命令所返回的目录。

    ..指当前目录的上一级目录,及当前目录的父目录。

    • 切换至父目录:cd ..

    • 切换至当前用户主目录:cd ~

    • 切换至上次工作目录:cd -

    • echo $PWD:当前工作目录

    • echo $OLDPWD:上次工作目录

    2.4.列出目录内容

    ls命令:

    • -a 显示所有文件及目录 (. 开头的隐藏文件也会列出)
    • -A-a ,但不列出 . (目前目录) 及 .. (父目录)
    • -l 除文件名称外,亦将文件型态、权限、拥有者、文件大小等资讯详细列出
    • -r 将文件以相反次序显示(原定依英文字母次序)
    • -t 将文件依建立时间之先后次序列出
    • -F 在列出的文件名称后加一符号;例如可执行档则加 "*", 目录则加 "/"
    • -R 递归列出子目录
    • -S 按文件大小排序,从大到小
    • -1 按一个文件一行列出
    • -t 按文件时间排序,最新的在前
    • -U 不排序输出,按目录存放顺序列出
    • -u 配合-lt,按访问时间排序并显示;配合-l,显示访问时间并按名称排序; 否则按访问时间排序,最新的在前
    • -X 按文件扩展名字母顺序排序输出
    • -F 对不同类型文件显示时附加不同的符号,* / = > @ |之一

    ls命令查看不同文件是的颜色,由/etc/DIR_COLORS和变量@LS_COLORS定义。

    2.5.文件状态stat

    每个文件有三个时间戳:

    • 访问时间 Access Time atime : 读取文件内容。
    • 修改时间 Modify Time mtime : 改变文件内容(数据)。
    • 改变时间 Change Time ctime : 元数据发生改变。

    读取三个时间戳的命令stat

    stat /etc/fstab
     

    输出结果:

      File: /etc/fstab
       Size: 927             Blocks: 8          IO Block: 4096   regular file
     Device: 30h/48d Inode: 263         Links: 1
    @@ -15,503 +15,503 @@
     

    运行命令file -f list.txt,结果如下:

    /etc/:      directory
     /bin:       directory
     /etc/issue: symbolic link to ../run/issue
    -

    2.7.文件编码转换

    iconv命令用于将一种编码中的某些文本转换为另一种编码。 如果没有提供输入文件,则它从标准输入中读取。 同样,如果没有给出输出文件,那么它会写入标准输出。 如果没有提供 from-encodingto-encoding,则它使用当前本地的字符编码。

    将文本从 ISO 8859-15 字符编码转换为 UTF-8,读入input.txt,输出output.txt

    iconv -f ISO-8859-15 -t UTF-8 < input.txt > output.txt
    -

    从 UTF-8 转换为 ASCII,尽可能进行音译(transliterating):

    echo abc ß α € àḃç | iconv -f UTF-8 -t ASCII//TRANSLIT
    +

    2.7.文件编码转换

    iconv命令用于将一种编码中的某些文本转换为另一种编码。 如果没有提供输入文件,则它从标准输入中读取。 同样,如果没有给出输出文件,那么它会写入标准输出。 如果没有提供 from-encodingto-encoding,则它使用当前本地的字符编码。

    将文本从 ISO 8859-15 字符编码转换为 UTF-8,读入input.txt,输出output.txt

    iconv -f ISO-8859-15 -t UTF-8 < input.txt > output.txt
    +

    从 UTF-8 转换为 ASCII,尽可能进行音译(transliterating):

    echo abc ß α  àḃç | iconv -f UTF-8 -t ASCII//TRANSLIT
     

    运行结果:

    abc ss ? EUR abc
    -

    2.8.通配符

    通配符,指包含这些字符的字符串

    • ? :表示任意一个字符
    • * :表示任意长度的任意字符
    • [] :匹配指定范围内任意一个字符
    • [abcd]:匹配abcd中的任何一个字符
    • [a-z]:匹配范围a到z内任意一个字符
    • [!abcd]:不匹配括号里面任何一个字符
    • {} :表示生成序列,以逗号分割,不能有空格

    示例:

    $ touch file_{a..z}.txt
    -$ touch file_{A..Z}.txt
    -
    -$ ls
    -file_a.txt  file_C.txt  file_f.txt  file_H.txt  file_k.txt  file_M.txt  file_p.txt  file_R.txt  file_u.txt  file_W.txt  file_z.txt
    -file_A.txt  file_d.txt  file_F.txt  file_i.txt  file_K.txt  file_n.txt  file_P.txt  file_s.txt  file_U.txt  file_x.txt  file_Z.txt
    -file_b.txt  file_D.txt  file_g.txt  file_I.txt  file_l.txt  file_N.txt  file_q.txt  file_S.txt  file_v.txt  file_X.txt
    -file_B.txt  file_e.txt  file_G.txt  file_j.txt  file_L.txt  file_o.txt  file_Q.txt  file_t.txt  file_V.txt  file_y.txt
    -file_c.txt  file_E.txt  file_h.txt  file_J.txt  file_m.txt  file_O.txt  file_r.txt  file_T.txt  file_w.txt  file_Y.txt
    -
    -$ ls file_[a..d].*
    -file_a.txt  file_d.txt
    -
    -$ ls file_[a...d].*
    -file_a.txt  file_d.txt
    -
    -$ ls file_[ad].*
    -file_a.txt  file_d.txt
    -
    -$ ls file_[a-c].*
    -file_a.txt  file_A.txt  file_b.txt  file_B.txt  file_c.txt
    -
    -$ ls file_[a-C].*
    -file_a.txt  file_A.txt  file_b.txt  file_B.txt  file_c.txt  file_C.txt
    -
    -$ ls file_[!d-W].*
    -file_a.txt  file_b.txt  file_c.txt  file_x.txt  file_y.txt  file_z.txt
    -file_A.txt  file_B.txt  file_C.txt  file_X.txt  file_Y.txt  file_Z.txt
    -

    比较有无*的区别:

    $ ls -a *
    -file_a.txt  file_D.txt  file_h.txt  file_K.txt  file_o.txt  file_R.txt  file_v.txt  file_Y.txt
    -file_A.txt  file_e.txt  file_H.txt  file_l.txt  file_O.txt  file_s.txt  file_V.txt  file_z.txt
    -file_b.txt  file_E.txt  file_i.txt  file_L.txt  file_p.txt  file_S.txt  file_w.txt  file_Z.txt
    -file_B.txt  file_f.txt  file_I.txt  file_m.txt  file_P.txt  file_t.txt  file_W.txt
    -file_c.txt  file_F.txt  file_j.txt  file_M.txt  file_q.txt  file_T.txt  file_x.txt
    -file_C.txt  file_g.txt  file_J.txt  file_n.txt  file_Q.txt  file_u.txt  file_X.txt
    -file_d.txt  file_G.txt  file_k.txt  file_N.txt  file_r.txt  file_U.txt  file_y.txt
    -
    -$ ls -a
    -.           file_C.txt  file_g.txt  file_J.txt  file_n.txt  file_Q.txt  file_u.txt  file_X.txt
    -..          file_d.txt  file_G.txt  file_k.txt  file_N.txt  file_r.txt  file_U.txt  file_y.txt
    -file_a.txt  file_D.txt  file_h.txt  file_K.txt  file_o.txt  file_R.txt  file_v.txt  file_Y.txt
    -file_A.txt  file_e.txt  file_H.txt  file_l.txt  file_O.txt  file_s.txt  file_V.txt  file_z.txt
    -file_b.txt  file_E.txt  file_i.txt  file_L.txt  file_p.txt  file_S.txt  file_w.txt  file_Z.txt
    -file_B.txt  file_f.txt  file_I.txt  file_m.txt  file_P.txt  file_t.txt  file_W.txt
    -file_c.txt  file_F.txt  file_j.txt  file_M.txt  file_q.txt  file_T.txt  file_x.txt
    -

    2.9.字符集

    • [:alpha:]:表示所有的字母(不区分大小写),效果同[a-z]
    • [:digit:]:表示任意单个数字,效果同[0-9]
    • [:xdigit:]:表示十六进制数字
    • [:lower:]:表示任意单个小写字母
    • [:upper:]:表示任意单个大写字母
    • [:alnum:]:表示任意单个字母或数字
    • [:blank:]:表示空白字符(空格和制表符)
    • [:space:]:表示包括空格、制表符(水平和垂直)、换行符、回车符等各种类型的空白,比[:blank:]范围更广
    • [:cntrl:]:表示不可打印的控制字符(退格、删除、警铃等)
    • [:graph:]:表示可打印的非空白字符
    • [:print:]:表示可打印字符
    • [:punct:]:表示标点符号

    举例:

    • ls -d [[:alpha:]]ls -d [a-Z]:显示当前目录下所有单个字母的目录和文件
    • ls -d *[[:digit:]]ls -d *[0-9]:显示当前目录下所有以数字结尾的目录和文件
    • ls [[:lower:]].txt:显示当前目录下所有以单个小写字母为名的.txt格式的文件
    • ls -d [[:alnum:]]:显示当前目录下所有单个字母(不区分大小写)或数字为名的目录或文件

    2.10.特殊符号

    • | :管道符,或者(正则)
    • > :输出重定向
    • >> :输出追加重定向
    • < :输入重定向
    • << :追加输入重定向
    • ~ :当前用户家目录
    • $() :引用命令被执行后的结果
    • $ :以...结尾(正则)
    • ^ :以...开头(正则)
    • * :匹配全部字符,通配符
    • ? :任意一个字符,通配符
    • # :注释
    • & :让程序或脚本切换到后台执行
    • && :并且,同时成立
    • [] :表示一个范围(正则,通配符)
    • {} :产生一个序列(通配符)
    • . :当前目录的硬链接
    • .. :上级目录的硬链接

    2.11.刷新文件时间touch

    touch命令可以创建空文件,也可以刷新文件时间。参数如下:

    • -a:仅改变atimectime
    • -m:仅改变mtimectime
    • -t [[CC]YY]MMDDhhmm[.ss]:指定atimemtime
    • -c:如果文件不存在,则不创建
    $ touch file1
    -$ touch file2
    -
    -$ ll
    --rw-r--r--. 1 vagrant wheel 5 Nov  8 20:49 file1
    --rw-r--r--. 1 vagrant wheel 0 Nov  8 20:28 file2
    -

    创建文件file-non.log,如果不存在则不创建。

    touch -c file-non.log
    -

    更新file1的时间和file2一致。

    $ touch -r file1 file2
    -
    -$ ll
    --rw-r--r--. 1 vagrant wheel 5 Nov  8 20:49 file1
    --rw-r--r--. 1 vagrant wheel 0 Nov  8 20:49 file2
    -

    指定file2的时间。202210012135.25代表YYYYMMDDHHMM.SS

    $ touch -t 202210012135.25 file2
    -
    -$ ll
    --rw-r--r--. 1 vagrant wheel 5 Nov  8 20:49 file1
    --rw-r--r--. 1 vagrant wheel 0 Oct  1 21:35 file2
    -
    -$ stat file2
    -  File: file2
    -  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
    -Device: fd02h/64770d    Inode: 140         Links: 1
    -Access: (0644/-rw-r--r--)  Uid: ( 1000/ vagrant)   Gid: (   10/   wheel)
    -Context: unconfined_u:object_r:user_home_t:s0
    -Access: 2022-10-01 21:35:25.000000000 +0800
    -Modify: 2022-10-01 21:35:25.000000000 +0800
    -Change: 2022-11-08 20:56:18.306315887 +0800
    - Birth: 2022-11-08 20:28:37.809551441 +0800
    -

    2.12.复制文件和目录cp

    cp命令:Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.

    常用参数:

    • -a:归档,相当于-dR --preserv=all参数组合,常用于备份。
    • -d:不复制原文件,只复制链接名。相当于--no-dereference --preserve=links参数组合。
    • -f:覆盖已经存在的目标文件。
    • -i:覆盖目标文件之前给出提示。
    • -p:除复制文件的内容外,也复制文件权限,时间戳,属主属组。相当于--preserve=mode,ownership,timestamps
    • -r, -R, --recursive:递归复制目录所包含的全部内容。
    • -l:不复制文件,只是生成硬链接文件。

    参数--preserv可选项:

    • mode:权限
    • ownership:属主属组
    • timestamp
    • links
    • xattr
    • context
    • all

    创建测试目录。

    cd ~
    -mkdir test
    -

    对比参数-p的差别。

    $ cp /etc/issue ~/test/issue1
    -$ cp -p /etc/issue ~/test/issue1
    -$ sudo cp /etc/issue ~/test/issue3
    -$ sudo cp -p /etc/issue ~/test/issue4
    -
    -$ ll ~/test
    --rw-r--r--. 1 vagrant wheel 23 Nov  8 22:25 issue1
    --rw-r--r--. 1 vagrant wheel 23 Jul 21 01:10 issue2
    --rw-r--r--. 1 root    root  23 Nov  8 22:43 issue3
    --rw-r--r--. 1 root    root  23 Jul 21 01:10 issue4
    -
    -$ ll /etc/issue
    --rw-r--r--. 1 root root 23 Jul 21 01:10 /etc/issue
    -

    对比参数-r

    $ sudo cp /etc/sysconfig/ ~/test
    -cp: -r not specified; omitting directory '/etc/sysconfig/'
    -
    -$ sudo cp -r /etc/sysconfig/ ~/test
    -
    -$ tree -L 2 ~/test
    +

    2.8.通配符

    通配符,指包含这些字符的字符串

    • ? :表示任意一个字符
    • * :表示任意长度的任意字符
    • [] :匹配指定范围内任意一个字符
    • [abcd]:匹配abcd中的任何一个字符
    • [a-z]:匹配范围a到z内任意一个字符
    • [!abcd]:不匹配括号里面任何一个字符
    • {} :表示生成序列,以逗号分割,不能有空格

    示例:

    $ touch file_{a..z}.txt
    +$ touch file_{A..Z}.txt
    +
    +$ ls
    +file_a.txt  file_C.txt  file_f.txt  file_H.txt  file_k.txt  file_M.txt  file_p.txt  file_R.txt  file_u.txt  file_W.txt  file_z.txt
    +file_A.txt  file_d.txt  file_F.txt  file_i.txt  file_K.txt  file_n.txt  file_P.txt  file_s.txt  file_U.txt  file_x.txt  file_Z.txt
    +file_b.txt  file_D.txt  file_g.txt  file_I.txt  file_l.txt  file_N.txt  file_q.txt  file_S.txt  file_v.txt  file_X.txt
    +file_B.txt  file_e.txt  file_G.txt  file_j.txt  file_L.txt  file_o.txt  file_Q.txt  file_t.txt  file_V.txt  file_y.txt
    +file_c.txt  file_E.txt  file_h.txt  file_J.txt  file_m.txt  file_O.txt  file_r.txt  file_T.txt  file_w.txt  file_Y.txt
    +
    +$ ls file_[a..d].*
    +file_a.txt  file_d.txt
    +
    +$ ls file_[a...d].*
    +file_a.txt  file_d.txt
    +
    +$ ls file_[ad].*
    +file_a.txt  file_d.txt
    +
    +$ ls file_[a-c].*
    +file_a.txt  file_A.txt  file_b.txt  file_B.txt  file_c.txt
    +
    +$ ls file_[a-C].*
    +file_a.txt  file_A.txt  file_b.txt  file_B.txt  file_c.txt  file_C.txt
    +
    +$ ls file_[!d-W].*
    +file_a.txt  file_b.txt  file_c.txt  file_x.txt  file_y.txt  file_z.txt
    +file_A.txt  file_B.txt  file_C.txt  file_X.txt  file_Y.txt  file_Z.txt
    +

    比较有无*的区别:

    $ ls -a *
    +file_a.txt  file_D.txt  file_h.txt  file_K.txt  file_o.txt  file_R.txt  file_v.txt  file_Y.txt
    +file_A.txt  file_e.txt  file_H.txt  file_l.txt  file_O.txt  file_s.txt  file_V.txt  file_z.txt
    +file_b.txt  file_E.txt  file_i.txt  file_L.txt  file_p.txt  file_S.txt  file_w.txt  file_Z.txt
    +file_B.txt  file_f.txt  file_I.txt  file_m.txt  file_P.txt  file_t.txt  file_W.txt
    +file_c.txt  file_F.txt  file_j.txt  file_M.txt  file_q.txt  file_T.txt  file_x.txt
    +file_C.txt  file_g.txt  file_J.txt  file_n.txt  file_Q.txt  file_u.txt  file_X.txt
    +file_d.txt  file_G.txt  file_k.txt  file_N.txt  file_r.txt  file_U.txt  file_y.txt
    +
    +$ ls -a
    +.           file_C.txt  file_g.txt  file_J.txt  file_n.txt  file_Q.txt  file_u.txt  file_X.txt
    +..          file_d.txt  file_G.txt  file_k.txt  file_N.txt  file_r.txt  file_U.txt  file_y.txt
    +file_a.txt  file_D.txt  file_h.txt  file_K.txt  file_o.txt  file_R.txt  file_v.txt  file_Y.txt
    +file_A.txt  file_e.txt  file_H.txt  file_l.txt  file_O.txt  file_s.txt  file_V.txt  file_z.txt
    +file_b.txt  file_E.txt  file_i.txt  file_L.txt  file_p.txt  file_S.txt  file_w.txt  file_Z.txt
    +file_B.txt  file_f.txt  file_I.txt  file_m.txt  file_P.txt  file_t.txt  file_W.txt
    +file_c.txt  file_F.txt  file_j.txt  file_M.txt  file_q.txt  file_T.txt  file_x.txt
    +

    2.9.字符集

    • [:alpha:]:表示所有的字母(不区分大小写),效果同[a-z]
    • [:digit:]:表示任意单个数字,效果同[0-9]
    • [:xdigit:]:表示十六进制数字
    • [:lower:]:表示任意单个小写字母
    • [:upper:]:表示任意单个大写字母
    • [:alnum:]:表示任意单个字母或数字
    • [:blank:]:表示空白字符(空格和制表符)
    • [:space:]:表示包括空格、制表符(水平和垂直)、换行符、回车符等各种类型的空白,比[:blank:]范围更广
    • [:cntrl:]:表示不可打印的控制字符(退格、删除、警铃等)
    • [:graph:]:表示可打印的非空白字符
    • [:print:]:表示可打印字符
    • [:punct:]:表示标点符号

    举例:

    • ls -d [[:alpha:]]ls -d [a-Z]:显示当前目录下所有单个字母的目录和文件
    • ls -d *[[:digit:]]ls -d *[0-9]:显示当前目录下所有以数字结尾的目录和文件
    • ls [[:lower:]].txt:显示当前目录下所有以单个小写字母为名的.txt格式的文件
    • ls -d [[:alnum:]]:显示当前目录下所有单个字母(不区分大小写)或数字为名的目录或文件

    2.10.特殊符号

    • | :管道符,或者(正则)
    • > :输出重定向
    • >> :输出追加重定向
    • < :输入重定向
    • << :追加输入重定向
    • ~ :当前用户家目录
    • $() :引用命令被执行后的结果
    • $ :以...结尾(正则)
    • ^ :以...开头(正则)
    • * :匹配全部字符,通配符
    • ? :任意一个字符,通配符
    • # :注释
    • & :让程序或脚本切换到后台执行
    • && :并且,同时成立
    • [] :表示一个范围(正则,通配符)
    • {} :产生一个序列(通配符)
    • . :当前目录的硬链接
    • .. :上级目录的硬链接

    2.11.刷新文件时间touch

    touch命令可以创建空文件,也可以刷新文件时间。参数如下:

    • -a:仅改变atimectime
    • -m:仅改变mtimectime
    • -t [[CC]YY]MMDDhhmm[.ss]:指定atimemtime
    • -c:如果文件不存在,则不创建
    $ touch file1
    +$ touch file2
    +
    +$ ll
    +-rw-r--r--. 1 vagrant wheel 5 Nov  8 20:49 file1
    +-rw-r--r--. 1 vagrant wheel 0 Nov  8 20:28 file2
    +

    创建文件file-non.log,如果不存在则不创建。

    touch -c file-non.log
    +

    更新file1的时间和file2一致。

    $ touch -r file1 file2
    +
    +$ ll
    +-rw-r--r--. 1 vagrant wheel 5 Nov  8 20:49 file1
    +-rw-r--r--. 1 vagrant wheel 0 Nov  8 20:49 file2
    +

    指定file2的时间。202210012135.25代表YYYYMMDDHHMM.SS

    $ touch -t 202210012135.25 file2
    +
    +$ ll
    +-rw-r--r--. 1 vagrant wheel 5 Nov  8 20:49 file1
    +-rw-r--r--. 1 vagrant wheel 0 Oct  1 21:35 file2
    +
    +$ stat file2
    +  File: file2
    +  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
    +Device: fd02h/64770d    Inode: 140         Links: 1
    +Access: (0644/-rw-r--r--)  Uid: ( 1000/ vagrant)   Gid: (   10/   wheel)
    +Context: unconfined_u:object_r:user_home_t:s0
    +Access: 2022-10-01 21:35:25.000000000 +0800
    +Modify: 2022-10-01 21:35:25.000000000 +0800
    +Change: 2022-11-08 20:56:18.306315887 +0800
    + Birth: 2022-11-08 20:28:37.809551441 +0800
    +

    2.12.复制文件和目录cp

    cp命令:Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.

    常用参数:

    • -a:归档,相当于-dR --preserv=all参数组合,常用于备份。
    • -d:不复制原文件,只复制链接名。相当于--no-dereference --preserve=links参数组合。
    • -f:覆盖已经存在的目标文件。
    • -i:覆盖目标文件之前给出提示。
    • -p:除复制文件的内容外,也复制文件权限,时间戳,属主属组。相当于--preserve=mode,ownership,timestamps
    • -r, -R, --recursive:递归复制目录所包含的全部内容。
    • -l:不复制文件,只是生成硬链接文件。

    参数--preserv可选项:

    • mode:权限
    • ownership:属主属组
    • timestamp
    • links
    • xattr
    • context
    • all

    创建测试目录。

    cd ~
    +mkdir test
    +

    对比参数-p的差别。

    $ cp /etc/issue ~/test/issue1
    +$ cp -p /etc/issue ~/test/issue1
    +$ sudo cp /etc/issue ~/test/issue3
    +$ sudo cp -p /etc/issue ~/test/issue4
    +
    +$ ll ~/test
    +-rw-r--r--. 1 vagrant wheel 23 Nov  8 22:25 issue1
    +-rw-r--r--. 1 vagrant wheel 23 Jul 21 01:10 issue2
    +-rw-r--r--. 1 root    root  23 Nov  8 22:43 issue3
    +-rw-r--r--. 1 root    root  23 Jul 21 01:10 issue4
    +
    +$ ll /etc/issue
    +-rw-r--r--. 1 root root 23 Jul 21 01:10 /etc/issue
    +

    对比参数-r

    $ sudo cp /etc/sysconfig/ ~/test
    +cp: -r not specified; omitting directory '/etc/sysconfig/'
    +
    +$ sudo cp -r /etc/sysconfig/ ~/test
    +
    +$ tree -L 2 ~/test
     /home/vagrant/test
    -├── issue1
    -├── issue2
    -├── issue3
    -├── issue4
    -└── sysconfig
    -    ├── anaconda
    -    ├── atd
    -    ├── chronyd
    -    ├── cpupower
    -    ├── crond
    -    ├── firewalld
    -    ├── irqbalance
    -    ├── kdump
    -    ├── kernel
    -    ├── man-db
    -    ├── network
    -    ├── network-scripts
    -    ├── nftables.conf
    -    ├── raid-check
    -    ├── rsyslog
    -    ├── run-parts
    -    ├── samba
    -    ├── selinux -> ../selinux/config
    -    ├── smartmontools
    -    └── sshd
    -

    参数-b,如果目标文件存在,复制前先将原文件复制并以~结尾。

    $ ll /etc/motd
    --rw-r--r--. 1 root root 0 Jun 23  2020 /etc/motd
    -
    -$ ll ~/test/issue1
    --rw-r--r--. 1 vagrant wheel 23 Nov  8 22:25 /home/vagrant/test/issue1
    -
    -$ cp -b /etc/motd ~/test/issue
    -$ cp -b /etc/motd ~/test/issue1 
    -
    -$ ll ~/test
    --rw-r--r--. 1 vagrant wheel    0 Nov  8 23:00 issue
    --rw-r--r--. 1 vagrant wheel    0 Nov  8 22:57 issue1
    --rw-r--r--. 1 vagrant wheel   23 Nov  8 22:25 issue1~
    --rw-r--r--. 1 vagrant wheel   23 Jul 21 01:10 issue2
    --rw-r--r--. 1 root    root    23 Nov  8 22:43 issue3
    --rw-r--r--. 1 root    root    23 Jul 21 01:10 issue4
    -drwxr-xr-x. 3 root    root  4096 Nov  8 22:49 sysconfig
    -

    参数--backup=numbered会在复制原文件时加上数字序号,序号1代表原始的文件。

    $ cp --backup=numbered /etc/motd ~/test/issue2
    -$ cp --backup=numbered /etc/motd ~/test/issue2
    -$ cp --backup=numbered /etc/motd ~/test/issue2
    -
    -$ ll ~/test
    --rw-r--r--. 1 vagrant wheel    0 Nov  8 23:00 issue
    --rw-r--r--. 1 vagrant wheel    0 Nov  8 22:57 issue1
    --rw-r--r--. 1 vagrant wheel   23 Nov  8 22:25 issue1~
    --rw-r--r--. 1 vagrant wheel    0 Nov  8 23:09 issue2
    --rw-r--r--. 1 vagrant wheel   23 Jul 21 01:10 issue2.~1~
    --rw-r--r--. 1 vagrant wheel    0 Nov  8 23:09 issue2.~2~
    --rw-r--r--. 1 vagrant wheel    0 Nov  8 23:09 issue2.~3~
    --rw-r--r--. 1 root    root    23 Nov  8 22:43 issue3
    --rw-r--r--. 1 root    root    23 Jul 21 01:10 issue4
    -drwxr-xr-x. 3 root    root  4096 Nov  8 22:49 sysconfig
    -

    2.13.移动文件和目录mv

    mv命令。Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.

    常用参数:

    • -v:显示命令执行的信息。
    • -i:交互式,比如,重名覆盖时会提升是否确认。
    • -b:覆盖时创建备份。默认情况下,移动文件将会覆盖已存在的目标文件。

    移动多个文件到某个目录。

    mv file1 file2 file3 ~/dest
    -mv file* ~/dest
    -

    移动目录。

    mv ~/test ~/dest/new/one/
    -

    重命名文件和目录。

    mv file1 file2
    -mv ~/test ~/dest
    -

    2.14.重命名文件和目录rename

    rename命令。分为perl版本和C语言版本。 区分方法: rename --version。如果返回结果中包含 util-linux,说明是C语言版本, 反之是Perl版本。 openSUSE和Rocy是C语言版本,Ubuntu是Perl版本。

    举例:修改当前目录所有扩展名为s的文件改为扩展名为gz

    $ touch file{1..3}.s
    -
    -$ rename -v '.s' '.gz' *.s
    -$ rename -v ".s" ".gz" *.s
    +├── issue1
    +├── issue2
    +├── issue3
    +├── issue4
    +└── sysconfig
    +    ├── anaconda
    +    ├── atd
    +    ├── chronyd
    +    ├── cpupower
    +    ├── crond
    +    ├── firewalld
    +    ├── irqbalance
    +    ├── kdump
    +    ├── kernel
    +    ├── man-db
    +    ├── network
    +    ├── network-scripts
    +    ├── nftables.conf
    +    ├── raid-check
    +    ├── rsyslog
    +    ├── run-parts
    +    ├── samba
    +    ├── selinux -> ../selinux/config
    +    ├── smartmontools
    +    └── sshd
    +

    参数-b,如果目标文件存在,复制前先将原文件复制并以~结尾。

    $ ll /etc/motd
    +-rw-r--r--. 1 root root 0 Jun 23  2020 /etc/motd
    +
    +$ ll ~/test/issue1
    +-rw-r--r--. 1 vagrant wheel 23 Nov  8 22:25 /home/vagrant/test/issue1
    +
    +$ cp -b /etc/motd ~/test/issue
    +$ cp -b /etc/motd ~/test/issue1 
    +
    +$ ll ~/test
    +-rw-r--r--. 1 vagrant wheel    0 Nov  8 23:00 issue
    +-rw-r--r--. 1 vagrant wheel    0 Nov  8 22:57 issue1
    +-rw-r--r--. 1 vagrant wheel   23 Nov  8 22:25 issue1~
    +-rw-r--r--. 1 vagrant wheel   23 Jul 21 01:10 issue2
    +-rw-r--r--. 1 root    root    23 Nov  8 22:43 issue3
    +-rw-r--r--. 1 root    root    23 Jul 21 01:10 issue4
    +drwxr-xr-x. 3 root    root  4096 Nov  8 22:49 sysconfig
    +

    参数--backup=numbered会在复制原文件时加上数字序号,序号1代表原始的文件。

    $ cp --backup=numbered /etc/motd ~/test/issue2
    +$ cp --backup=numbered /etc/motd ~/test/issue2
    +$ cp --backup=numbered /etc/motd ~/test/issue2
    +
    +$ ll ~/test
    +-rw-r--r--. 1 vagrant wheel    0 Nov  8 23:00 issue
    +-rw-r--r--. 1 vagrant wheel    0 Nov  8 22:57 issue1
    +-rw-r--r--. 1 vagrant wheel   23 Nov  8 22:25 issue1~
    +-rw-r--r--. 1 vagrant wheel    0 Nov  8 23:09 issue2
    +-rw-r--r--. 1 vagrant wheel   23 Jul 21 01:10 issue2.~1~
    +-rw-r--r--. 1 vagrant wheel    0 Nov  8 23:09 issue2.~2~
    +-rw-r--r--. 1 vagrant wheel    0 Nov  8 23:09 issue2.~3~
    +-rw-r--r--. 1 root    root    23 Nov  8 22:43 issue3
    +-rw-r--r--. 1 root    root    23 Jul 21 01:10 issue4
    +drwxr-xr-x. 3 root    root  4096 Nov  8 22:49 sysconfig
    +

    2.13.移动文件和目录mv

    mv命令。Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY.

    常用参数:

    • -v:显示命令执行的信息。
    • -i:交互式,比如,重名覆盖时会提升是否确认。
    • -b:覆盖时创建备份。默认情况下,移动文件将会覆盖已存在的目标文件。

    移动多个文件到某个目录。

    mv file1 file2 file3 ~/dest
    +mv file* ~/dest
    +

    移动目录。

    mv ~/test ~/dest/new/one/
    +

    重命名文件和目录。

    mv file1 file2
    +mv ~/test ~/dest
    +

    2.14.重命名文件和目录rename

    rename命令。分为perl版本和C语言版本。 区分方法: rename --version。如果返回结果中包含 util-linux,说明是C语言版本, 反之是Perl版本。 openSUSE和Rocy是C语言版本,Ubuntu是Perl版本。

    举例:修改当前目录所有扩展名为s的文件改为扩展名为gz

    $ touch file{1..3}.s
    +
    +$ rename -v '.s' '.gz' *.s
    +$ rename -v ".s" ".gz" *.s
     `file1.txt' -> `file1.html'
     `file2.txt' -> `file2.html'
     `file3.txt' -> `file3.html'
    -

    在Ubuntu上完成同样任务,则需要使用正则。

    rename -v "s/s/gz/g" *.s
    -

    2.15.删除文件rm

    rm命令。建议使用mv命令代替rm命令。

    2.16.目录操作命令

    创建目录:mkdir

    删除空目录:rmdir

    删除非空目录:rm -r

    显示目录树:tree

    2.17.练习

    • 显示/etc目录下所有以l开头,以一个小写字母结尾,且中间出现至少一位数字的文件或目录列表。
    ls -d /etc/l*[0-9]*[a-z]
    -ls -d /etc/l*[[:digit:]]*[[:lower:]]
    -

    如果无符合条件的记录返回,可以手工创建一个符合条件的文件和目录。

    sudo touch /etc/lam4you
    -sudo mkdir /etc/lam5you
    -

    验证后删除。

    sudo rm /etc/lam4you
    -sudo rm -rf /etc/lam5you
    -
    • 显示/etc目录下以任意一位数字开头,且以非数字结尾的文件或目录列表。
    ls /etc/[0-9]*[!0-9]
    -ls /etc/[[:digit:]]*[^[:digit:]]
    -

    如果无符合条件的记录返回,可以手工创建一个符合条件的文件和目录。

    sudo touch /etc/5am4yo.
    -sudo mkdir /etc/5am5yo.
    -

    验证后删除。

    sudo rm /etc/5am4yo.
    -sudo rm -rf /etc/5am5yo.
    -
    • 显示/etc目录下以非字母开头,后面跟了一个字母及其它任意长度任意字符的文件或目录列表。
    ls /etc/[!a-zA-Z][a-zA-Z]*
    -ls /etc/[^[:alpha:]][[:alpha:]]*
    -

    如果无符合条件的记录返回,可以手工创建一个符合条件的文件和目录。

    sudo touch /etc/5Ato3
    -sudo mkdir /etc/6dog6
    -

    验证后删除。

    sudo rm /etc/5Ato3
    -sudo rm -rf /etc/6dog6
    -
    • 显示/etc目录下,所有以rc开头,并后面是0-6之间的数字,其它为任意字符的文件或目录列表。
    ls /etc/rc[0-6]*
    -

    如果无符合条件的记录返回,可以手工创建一个符合条件的文件和目录。

    sudo touch /etc/rc5come
    -sudo mkdir /etc/rc0123
    -

    验证后删除。

    sudo rm /etc/rc5come
    -sudo rm -rf /etc/rc0123
    -
    • 显示/etc目录下,所有以.conf结尾,且以mnrp开头的文件或目录列表。
    ls /etc/[mnrp]*.conf
    -
    • 只显示/root下的隐藏文件和目录列表。
    ls .*
    -
    • 只显示/etc下非隐藏目录列表。
    ls /etc/[^.]*/
    -
    • /etc目录下所有文件,备份到~/test/目录下,并要求子目录格式为backupYYYY-mm-dd,备份过程可见。
    sudo cp -av /etc/ ~/test/backup`date +%F`
    -sudo cp -av /etc/ ~/test/backup`date +%F_%H-%M-%S`
    -
    • 创建目录~/testdir/dir1/x~/testdir/dir1/y~/testdir/dir1/x/a~/testdir/dir1/x/b~/testdir/dir1/y/a~/testdir/dir1/y/b
    $ mkdir -p ~/testdir/dir1/{x,y}/{a,b}
    -
    -$ tree ~/testdir/dir1/
    +

    在Ubuntu上完成同样任务,则需要使用正则。

    rename -v "s/s/gz/g" *.s
    +

    2.15.删除文件rm

    rm命令。建议使用mv命令代替rm命令。

    2.16.目录操作命令

    创建目录:mkdir

    删除空目录:rmdir

    删除非空目录:rm -r

    显示目录树:tree

    2.17.练习

    • 显示/etc目录下所有以l开头,以一个小写字母结尾,且中间出现至少一位数字的文件或目录列表。
    ls -d /etc/l*[0-9]*[a-z]
    +ls -d /etc/l*[[:digit:]]*[[:lower:]]
    +

    如果无符合条件的记录返回,可以手工创建一个符合条件的文件和目录。

    sudo touch /etc/lam4you
    +sudo mkdir /etc/lam5you
    +

    验证后删除。

    sudo rm /etc/lam4you
    +sudo rm -rf /etc/lam5you
    +
    • 显示/etc目录下以任意一位数字开头,且以非数字结尾的文件或目录列表。
    ls /etc/[0-9]*[!0-9]
    +ls /etc/[[:digit:]]*[^[:digit:]]
    +

    如果无符合条件的记录返回,可以手工创建一个符合条件的文件和目录。

    sudo touch /etc/5am4yo.
    +sudo mkdir /etc/5am5yo.
    +

    验证后删除。

    sudo rm /etc/5am4yo.
    +sudo rm -rf /etc/5am5yo.
    +
    • 显示/etc目录下以非字母开头,后面跟了一个字母及其它任意长度任意字符的文件或目录列表。
    ls /etc/[!a-zA-Z][a-zA-Z]*
    +ls /etc/[^[:alpha:]][[:alpha:]]*
    +

    如果无符合条件的记录返回,可以手工创建一个符合条件的文件和目录。

    sudo touch /etc/5Ato3
    +sudo mkdir /etc/6dog6
    +

    验证后删除。

    sudo rm /etc/5Ato3
    +sudo rm -rf /etc/6dog6
    +
    • 显示/etc目录下,所有以rc开头,并后面是0-6之间的数字,其它为任意字符的文件或目录列表。
    ls /etc/rc[0-6]*
    +

    如果无符合条件的记录返回,可以手工创建一个符合条件的文件和目录。

    sudo touch /etc/rc5come
    +sudo mkdir /etc/rc0123
    +

    验证后删除。

    sudo rm /etc/rc5come
    +sudo rm -rf /etc/rc0123
    +
    • 显示/etc目录下,所有以.conf结尾,且以mnrp开头的文件或目录列表。
    ls /etc/[mnrp]*.conf
    +
    • 只显示/root下的隐藏文件和目录列表。
    ls .*
    +
    • 只显示/etc下非隐藏目录列表。
    ls /etc/[^.]*/
    +
    • /etc目录下所有文件,备份到~/test/目录下,并要求子目录格式为backupYYYY-mm-dd,备份过程可见。
    sudo cp -av /etc/ ~/test/backup`date +%F`
    +sudo cp -av /etc/ ~/test/backup`date +%F_%H-%M-%S`
    +
    • 创建目录~/testdir/dir1/x~/testdir/dir1/y~/testdir/dir1/x/a~/testdir/dir1/x/b~/testdir/dir1/y/a~/testdir/dir1/y/b
    $ mkdir -p ~/testdir/dir1/{x,y}/{a,b}
    +
    +$ tree ~/testdir/dir1/
     /home/vagrant/testdir/dir1/
    -├── x
    -│   ├── a
    -│   └── b
    -└── y
    -  ├── a
    -  └── b
    -
    • 创建目录~/testdir/dir2/x~/testdir/dir2/y~/testdir/dir2/x/a~/testdir/dir2/x/b
    $ mkdir -p ~/testdir/dir2/{x/{a,b},y}
    -
    -$ tree ~/testdir/dir2/
    +├── x
    +│   ├── a
    +│   └── b
    +└── y
    +  ├── a
    +  └── b
    +
    • 创建目录~/testdir/dir2/x~/testdir/dir2/y~/testdir/dir2/x/a~/testdir/dir2/x/b
    $ mkdir -p ~/testdir/dir2/{x/{a,b},y}
    +
    +$ tree ~/testdir/dir2/
     /home/vagrant/testdir/dir2/
    -├── x
    -│   ├── a
    -│   └── b
    -└── y
    -
    • 创建目录~/testdir/dir3~/testdir/dir4~/testdir/dir5~/testdir/dir5/dir6~/testdir/dir5/dir7
    $ mkdir -p ~/testdir/dir{3,4,5/dir{6,7}}
    +├── x
    +│   ├── a
    +│   └── b
    +└── y
    +
    • 创建目录~/testdir/dir3~/testdir/dir4~/testdir/dir5~/testdir/dir5/dir6~/testdir/dir5/dir7
    $ mkdir -p ~/testdir/dir{3,4,5/dir{6,7}}
     
    -$ tree ~/testdir
    +$ tree ~/testdir
     /home/vagrant/testdir
    -├── dir1
    -│   ├── x
    -│   │   ├── a
    -│   │   └── b
    -│   └── y
    -│       ├── a
    -│       └── b
    -├── dir2
    -│   ├── x
    -│   │   ├── a
    -│   │   └── b
    -│   └── y
    -├── dir3
    -├── dir4
    -└── dir5
    - ├── dir6
    - └── dir7
    -

    3.七种文件类型

    • 普通文件(Normal Files)
    • ASCII 文本文件
    • 可执行文件
    • 图形文件
    • 目录(Directories)
    • 组织规划磁盘上的文件
    • 包含文件和子目录
    • 实现分层文件系统
    • 链接(Links)
    • 硬链接(Hard links)
      • 磁盘上文件的辅助文件名
      • 多个文件名引用单个inode
      • 引用的文件必须存在于同一个文件系统中
    • 符号链接(Symbolic links)
      • 对磁盘上其他文件的引用
      • inode包含对另一个文件名的引用
      • 被引用的文件可以存在于同一个文件系统中,也可以存在于其他文件系统中
      • 符号链接可以引用不存在的文件(断开的链接)
    • 套接字Sockets - 用于进程之间的双向通信。
    • 管道(Pipes)(FIFOs) - 用于从一个进程到另一个进程的单向通信。
    • 块设备(Block Devices)
    • 字符设备(Character Devices)

    3.1.inode结构

    文件储存在硬盘上,硬盘的最小存储单位叫做“扇区”(Sector)。每个扇区储存512字节(相当于0.5KB)。

    操作系统读取硬盘的时候,不是一个一个扇区读取,而是一次性连续读取多个扇区,我们称为读取一个“块”(block)。

    常见的block的大小是4KB(连续八个sector组成一个block)。

    多个扇区组成的block是文件存取的*最小单位*。

    文件数据储存在block中,文件的元信息,比如文件的创建者、创建日期、文大小等,存储在inode,即“索引节点”。

    每一个文件都有对应的inode,里面包含了与该文件有关的一些信息。注意,除了文件名以外的其它文件信息,都存在inode之中。

    inode包含文件的元信息主要有:

    • 文件的字节数
    • 文件拥有者的 User ID
    • 文件的 Group ID
    • 文件的读、写、执行权限
    • 文件的时间戳,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间。
    • 链接数,即有多少文件名指向这个inode
    • 文件数据block的位置

    查看inode信息的命令stat

    $ stat file1
    -  File: file1
    -  Size: 5               Blocks: 8          IO Block: 4096   regular file
    -Device: fd02h/64770d    Inode: 143         Links: 1
    -Access: (0644/-rw-r--r--)  Uid: ( 1000/ vagrant)   Gid: (   10/   wheel)
    -Context: unconfined_u:object_r:user_home_t:s0
    -Access: 2022-11-08 20:49:26.019678244 +0800
    -Modify: 2022-11-08 20:49:26.019678244 +0800
    -Change: 2022-11-08 20:49:26.028678455 +0800
    - Birth: 2022-11-08 20:49:26.019678244 +0800
    -

    格式化硬盘时,操作系统会自动将硬盘分成两个区域。一个是数据区,存放文件数据。另一个是inode区(inode table),存放inode所包含的文件的元信息。

    每个inode节点的大小,一般是128字节或256字节。inode节点的总数,在格式化时就确定了,一般是每1KB或每2KB就设置一个inode。

    假定一块1GB的硬盘,如果每个inode节点的大小为128字节,且每1KB就设置一个inode,则inode table的大小就会达到128MB,占整块硬盘的12.8%。

    通过df命令查看每个硬盘分区的inode总数和已经使用的数量。 由于每个文件都必须有一个inode,因此有可能发生inode已经用光,但是硬盘还未存满的情况,也就无法在硬盘上创建新文件。

    $ df -i
    -Filesystem                         Inodes IUsed   IFree IUse% Mounted on
    -tmpfs                              497897   872  497025    1% /run
    -/dev/mapper/ubuntu--vg-ubuntu--lv 3211264 81473 3129791    3% /
    -tmpfs                              497897     1  497896    1% /dev/shm
    -tmpfs                              497897     3  497894    1% /run/lock
    -/dev/sda2                          131072   316  130756    1% /boot
    -tmpfs                               99579    25   99554    1% /run/user/1000
    -

    下面命令可以查看每个inode节点的大小:

    $ sudo dumpe2fs -h /dev/sda2 | grep "Inode size"
    -dumpe2fs 1.46.5 (30-Dec-2021)
    -Inode size:               256
    -

    每个inode都有一个号码,操作系统用inode号码来识别不同的文件,注意,不是通过文件名来识别不同文件。从操作系统角度看,文件名只是inode号码对一个别名。

    用户通过文件名,打开某个文件的过程,操作系统分成三步完成: 首先,系统找到这个文件名对应的inode号码。 其次,通过inode号,获取inode信息。 第三,通过inode信息,找到文件数据所在的block,读出数据。

    通过ls -i命令,可以得到文件对应的inode号:

    $ ls -i file1
    -143 file1
    -

    目录(directory)也是一种文件。打开目录,实际上就是打开目录文件。

    目录文件的结构是由一个包含一系列目录项(dirent)的列表组成。 每个目录项由两部分组成:所包含文件的文件名,以及该文件名对应的inode号。

    命令ls -i列出整个目录文件,即文件名和inode号:

    $ ls -i
    -143 file1  140 file2  139 test
    -
    -$ ls -il
    -143 -rw-r--r--. 1 vagrant wheel    5 Nov  8 20:49 file1
    -140 -rw-r--r--. 1 vagrant wheel    0 Oct  1 21:35 file2
    -139 drwxr-xr-x. 5 vagrant wheel 4096 Nov  9 22:00 test
    -

    3.2.链接类型

    硬链接(Hard links)硬链接是存储卷上文件的目录引用或指针。 文件名是存储在目录结构中的标签,目录结构指向文件数据。 因此,可以将多个文件名与同一文件关联。 通过不同的文件名访问时,所做的任何更改都是针对源文件数据。

    符号链接(Symbolic links): 符号链接包含一个文本字符串,操作系统将其解释为另一个文件或目录。 它本身就是一个文件,可以独立于目标而存在。 如果删除了符号链接,则其目标文件或目录不受影响。 如果移动,重命名或删除目标文件或目录,则用于指向它的任何符号链接将继续存在,但指向的是一个不存在的文件。

    仅当文件和链接文件位于同一文件系统(在同一分区上)时,才能使用硬链接,因为inode编号在同一文件系统中仅是唯一的。 可以使用ln命令创建硬链接,指向已存在文件的inode,可以通过文件名或者硬链接名访问文件。

    可以使用ln -s选项创建符号链接。 一个符号链接会被分配一个单独的inode,并指向一个文件,所以可以明显区分符号链接文件和实际文件。

    文件系统本质上是一个用于跟踪分区卷中的文件的数据库。 对于普通文件,分配数据块以存储文件的数据,分配inode以指向数据块以及存储关于文件的元数据,然后将文件名分配给inode。 硬链接是与现有inode关联的辅助文件名。 对于符号链接,将为新的inode分配一个与之关联的新文件名,但inode引用另一个文件名而不是引用数据块。

    查看文件名和inode之间关系的一个方法是使用ls -il命令。inode的典型大小为128位,数据块的大小范围可以是1k,2k,4k或更大,具体取决于文件系统类型。

    软连接可以针对目录,硬连接只能针对文件。

    硬链接相当于增加了一个登记项,使得原来的文件多了一个名字,至于inode都没变。所谓的登记项其实是目录文件中的一个条目(目录项),使用hard link 是让多个不同的目录项指向同一个文件的inode,没有多余的内容需要存储在磁盘扇区中,所以hardlink不占用额外的空间。

    符号链接有单独的inode,在inode中存放另一个文件的路径而不是文件数据,所以符号链接会占用额外的空间。

    特征 硬链接 符号链接
    本质 同一个文件 不是同一个文件
    跨设备 不支持 支持
    inode 相同 不同
    链接数 创建硬链接,链接数会增加,删除则减少 创建或删除,链接数都不变
    文件夹 不支持 支持
    相对路径 原始文件的相对路径是相对于当前工作目录 原始文件的相对路径是相对于链接文件的相对路径
    删除源文件 只是链接数减少,链接文件访问不受影响 链接文件将无法访问
    文件类型 和源文件相同 链接文件,和源文件无关
    文件大小 和源文件相同 源文件的路径的长度

    3.3.设备文件

    设备文件(Device File)表示硬件(网卡除外)。 每个硬件都由一个设备文件表示。 网卡是接口。

    设备文件把内核驱动和物理硬件设备连接起来。 内核驱动程序通过对设备文件进行读写(正确的格式)来实现对硬件的读写。

    类型:

    • 块设备(Block Devices):块设备(通常)在512字节的大块中读取/写入信息。
    • 字符设备(Character Devices):字符设备以字符方式读取/写入信息。 字符设备直接提供对硬件设备的无缓冲访问。
    • 有时称为裸设备(raw devices)。(注意:裸设备被视为字符设备,不是块设备)
    • 通过辅以不同选项,可以广泛而多样地应用和使用字符设备。
    • 当内核发现设备时由操作系统udev自动创建。

    3.4.练习

    目标:以Rocky 9为例。

    • 查看软/硬链接文件的特征。
    • 查看目录结构。

    可以通过下面命令得到当前系统的2级目录的结构。

    tree -L 2 -d /
    -

    创建练习目录。

    mkdir data
    -mkdir -p data/typelink
    -cd data
    -

    创建硬链接。注意:filehardlinkfile1hardlinkfile2 文件的链接位置的数值的变化)

    echo "it's original file" > file
    -ln file hardlinkfile1
    -ln -s file symlinkfile1
    -ln -s file symlinkfile2
    -

    执行ls -l命令可以得到下面的结果:

    -rw-r--r--. 2 vagrant wheel 19 Nov  1 10:42 file
    --rw-r--r--. 2 vagrant wheel 19 Nov  1 10:42 hardlinkfile1
    -lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile1 -> file
    -lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile2 -> file
    -

    创建另外一个硬链接。

    ln file hardlinkfile2
    -

    执行ls -l命令可以得到下面的结果:

    -rw-r--r--. 3 vagrant wheel  19 Nov  1 10:42 file
    --rw-r--r--. 3 vagrant wheel  19 Nov  1 10:42 hardlinkfile1
    --rw-r--r--. 3 vagrant wheel  19 Nov  1 10:42 hardlinkfile2
    -lrwxrwxrwx. 1 vagrant wheel   4 Nov  1 10:43 symlinkfile1 -> file
    -lrwxrwxrwx. 1 vagrant wheel   4 Nov  1 10:43 symlinkfile2 -> file
    -

    修改file文件的内容。

    echo "add oneline" >> file
    -

    通过命令cat file查看当前file的内容。

    it's original file
    -add oneline
    -

    通过下面的命令,可以看到所以软/硬链接文件内容都更新了,和file文件更新后的内容保持一致。

    cat hardlinkfile1
    -cat hardlinkfile2
    -cat symlinkfile1
    -cat symlinkfile2
    -

    对文件symlinkfile1再创建新的软连接。

    ln -s symlinkfile1 symlinkfile1-1
    -

    通过命令ls -il查看现在的目录信息。

    67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 file
    -67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile1
    -67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile2
    -67274681 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile1 -> file
    -67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov  1 11:20 symlinkfile1-1 -> symlinkfile1
    -67274682 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile2 -> file
    -

    读取软链接文件的源文件信息

    readlink symlinkfile1
    -readlink symlinkfile2
    -

    注意,对于symlinkfile1-1的情况有些不同。

    readlink symlinkfile1-1
    -

    上面命令返回结果symlinkfile1仍然是一个符号链接文件。通过readlink -f可以直接定位真正的源文件。

    readlink -f symlinkfile1-1
    -

    上面的返回结果/data/linktype/filesymlinkfile1-1真正的源文件。

    显示data目录下的文件和子目录:

    cd ~
    -tree ./data
    +├── dir1
    +│   ├── x
    +│      ├── a
    +│      └── b
    +│   └── y
    +│       ├── a
    +│       └── b
    +├── dir2
    +│   ├── x
    +│      ├── a
    +│      └── b
    +│   └── y
    +├── dir3
    +├── dir4
    +└── dir5
    + ├── dir6
    + └── dir7
    +

    3.七种文件类型

    • 普通文件(Normal Files)
    • ASCII 文本文件
    • 可执行文件
    • 图形文件
    • 目录(Directories)
    • 组织规划磁盘上的文件
    • 包含文件和子目录
    • 实现分层文件系统
    • 链接(Links)
    • 硬链接(Hard links)
      • 磁盘上文件的辅助文件名
      • 多个文件名引用单个inode
      • 引用的文件必须存在于同一个文件系统中
    • 符号链接(Symbolic links)
      • 对磁盘上其他文件的引用
      • inode包含对另一个文件名的引用
      • 被引用的文件可以存在于同一个文件系统中,也可以存在于其他文件系统中
      • 符号链接可以引用不存在的文件(断开的链接)
    • 套接字Sockets - 用于进程之间的双向通信。
    • 管道(Pipes)(FIFOs) - 用于从一个进程到另一个进程的单向通信。
    • 块设备(Block Devices)
    • 字符设备(Character Devices)

    3.1.inode结构

    文件储存在硬盘上,硬盘的最小存储单位叫做“扇区”(Sector)。每个扇区储存512字节(相当于0.5KB)。

    操作系统读取硬盘的时候,不是一个一个扇区读取,而是一次性连续读取多个扇区,我们称为读取一个“块”(block)。

    常见的block的大小是4KB(连续八个sector组成一个block)。

    多个扇区组成的block是文件存取的*最小单位*。

    文件数据储存在block中,文件的元信息,比如文件的创建者、创建日期、文大小等,存储在inode,即“索引节点”。

    每一个文件都有对应的inode,里面包含了与该文件有关的一些信息。注意,除了文件名以外的其它文件信息,都存在inode之中。

    inode包含文件的元信息主要有:

    • 文件的字节数
    • 文件拥有者的 User ID
    • 文件的 Group ID
    • 文件的读、写、执行权限
    • 文件的时间戳,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间。
    • 链接数,即有多少文件名指向这个inode
    • 文件数据block的位置

    查看inode信息的命令stat

    $ stat file1
    +  File: file1
    +  Size: 5               Blocks: 8          IO Block: 4096   regular file
    +Device: fd02h/64770d    Inode: 143         Links: 1
    +Access: (0644/-rw-r--r--)  Uid: ( 1000/ vagrant)   Gid: (   10/   wheel)
    +Context: unconfined_u:object_r:user_home_t:s0
    +Access: 2022-11-08 20:49:26.019678244 +0800
    +Modify: 2022-11-08 20:49:26.019678244 +0800
    +Change: 2022-11-08 20:49:26.028678455 +0800
    + Birth: 2022-11-08 20:49:26.019678244 +0800
    +

    格式化硬盘时,操作系统会自动将硬盘分成两个区域。一个是数据区,存放文件数据。另一个是inode区(inode table),存放inode所包含的文件的元信息。

    每个inode节点的大小,一般是128字节或256字节。inode节点的总数,在格式化时就确定了,一般是每1KB或每2KB就设置一个inode。

    假定一块1GB的硬盘,如果每个inode节点的大小为128字节,且每1KB就设置一个inode,则inode table的大小就会达到128MB,占整块硬盘的12.8%。

    通过df命令查看每个硬盘分区的inode总数和已经使用的数量。 由于每个文件都必须有一个inode,因此有可能发生inode已经用光,但是硬盘还未存满的情况,也就无法在硬盘上创建新文件。

    $ df -i
    +Filesystem                         Inodes IUsed   IFree IUse% Mounted on
    +tmpfs                              497897   872  497025    1% /run
    +/dev/mapper/ubuntu--vg-ubuntu--lv 3211264 81473 3129791    3% /
    +tmpfs                              497897     1  497896    1% /dev/shm
    +tmpfs                              497897     3  497894    1% /run/lock
    +/dev/sda2                          131072   316  130756    1% /boot
    +tmpfs                               99579    25   99554    1% /run/user/1000
    +

    下面命令可以查看每个inode节点的大小:

    $ sudo dumpe2fs -h /dev/sda2 | grep "Inode size"
    +dumpe2fs 1.46.5 (30-Dec-2021)
    +Inode size:               256
    +

    每个inode都有一个号码,操作系统用inode号码来识别不同的文件,注意,不是通过文件名来识别不同文件。从操作系统角度看,文件名只是inode号码对一个别名。

    用户通过文件名,打开某个文件的过程,操作系统分成三步完成: 首先,系统找到这个文件名对应的inode号码。 其次,通过inode号,获取inode信息。 第三,通过inode信息,找到文件数据所在的block,读出数据。

    通过ls -i命令,可以得到文件对应的inode号:

    $ ls -i file1
    +143 file1
    +

    目录(directory)也是一种文件。打开目录,实际上就是打开目录文件。

    目录文件的结构是由一个包含一系列目录项(dirent)的列表组成。 每个目录项由两部分组成:所包含文件的文件名,以及该文件名对应的inode号。

    命令ls -i列出整个目录文件,即文件名和inode号:

    $ ls -i
    +143 file1  140 file2  139 test
    +
    +$ ls -il
    +143 -rw-r--r--. 1 vagrant wheel    5 Nov  8 20:49 file1
    +140 -rw-r--r--. 1 vagrant wheel    0 Oct  1 21:35 file2
    +139 drwxr-xr-x. 5 vagrant wheel 4096 Nov  9 22:00 test
    +

    3.2.链接类型

    硬链接(Hard links)硬链接是存储卷上文件的目录引用或指针。 文件名是存储在目录结构中的标签,目录结构指向文件数据。 因此,可以将多个文件名与同一文件关联。 通过不同的文件名访问时,所做的任何更改都是针对源文件数据。

    符号链接(Symbolic links): 符号链接包含一个文本字符串,操作系统将其解释为另一个文件或目录。 它本身就是一个文件,可以独立于目标而存在。 如果删除了符号链接,则其目标文件或目录不受影响。 如果移动,重命名或删除目标文件或目录,则用于指向它的任何符号链接将继续存在,但指向的是一个不存在的文件。

    仅当文件和链接文件位于同一文件系统(在同一分区上)时,才能使用硬链接,因为inode编号在同一文件系统中仅是唯一的。 可以使用ln命令创建硬链接,指向已存在文件的inode,可以通过文件名或者硬链接名访问文件。

    可以使用ln -s选项创建符号链接。 一个符号链接会被分配一个单独的inode,并指向一个文件,所以可以明显区分符号链接文件和实际文件。

    文件系统本质上是一个用于跟踪分区卷中的文件的数据库。 对于普通文件,分配数据块以存储文件的数据,分配inode以指向数据块以及存储关于文件的元数据,然后将文件名分配给inode。 硬链接是与现有inode关联的辅助文件名。 对于符号链接,将为新的inode分配一个与之关联的新文件名,但inode引用另一个文件名而不是引用数据块。

    查看文件名和inode之间关系的一个方法是使用ls -il命令。inode的典型大小为128位,数据块的大小范围可以是1k,2k,4k或更大,具体取决于文件系统类型。

    软连接可以针对目录,硬连接只能针对文件。

    硬链接相当于增加了一个登记项,使得原来的文件多了一个名字,至于inode都没变。所谓的登记项其实是目录文件中的一个条目(目录项),使用hard link 是让多个不同的目录项指向同一个文件的inode,没有多余的内容需要存储在磁盘扇区中,所以hardlink不占用额外的空间。

    符号链接有单独的inode,在inode中存放另一个文件的路径而不是文件数据,所以符号链接会占用额外的空间。

    特征 硬链接 符号链接
    本质 同一个文件 不是同一个文件
    跨设备 不支持 支持
    inode 相同 不同
    链接数 创建硬链接,链接数会增加,删除则减少 创建或删除,链接数都不变
    文件夹 不支持 支持
    相对路径 原始文件的相对路径是相对于当前工作目录 原始文件的相对路径是相对于链接文件的相对路径
    删除源文件 只是链接数减少,链接文件访问不受影响 链接文件将无法访问
    文件类型 和源文件相同 链接文件,和源文件无关
    文件大小 和源文件相同 源文件的路径的长度

    3.3.设备文件

    设备文件(Device File)表示硬件(网卡除外)。 每个硬件都由一个设备文件表示。 网卡是接口。

    设备文件把内核驱动和物理硬件设备连接起来。 内核驱动程序通过对设备文件进行读写(正确的格式)来实现对硬件的读写。

    类型:

    • 块设备(Block Devices):块设备(通常)在512字节的大块中读取/写入信息。
    • 字符设备(Character Devices):字符设备以字符方式读取/写入信息。 字符设备直接提供对硬件设备的无缓冲访问。
    • 有时称为裸设备(raw devices)。(注意:裸设备被视为字符设备,不是块设备)
    • 通过辅以不同选项,可以广泛而多样地应用和使用字符设备。
    • 当内核发现设备时由操作系统udev自动创建。

    3.4.练习

    目标:以Rocky 9为例。

    • 查看软/硬链接文件的特征。
    • 查看目录结构。

    可以通过下面命令得到当前系统的2级目录的结构。

    tree -L 2 -d /
    +

    创建练习目录。

    mkdir data
    +mkdir -p data/typelink
    +cd data
    +

    创建硬链接。注意:filehardlinkfile1hardlinkfile2 文件的链接位置的数值的变化)

    echo "it's original file" > file
    +ln file hardlinkfile1
    +ln -s file symlinkfile1
    +ln -s file symlinkfile2
    +

    执行ls -l命令可以得到下面的结果:

    -rw-r--r--. 2 vagrant wheel 19 Nov  1 10:42 file
    +-rw-r--r--. 2 vagrant wheel 19 Nov  1 10:42 hardlinkfile1
    +lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile1 -> file
    +lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile2 -> file
    +

    创建另外一个硬链接。

    ln file hardlinkfile2
    +

    执行ls -l命令可以得到下面的结果:

    -rw-r--r--. 3 vagrant wheel  19 Nov  1 10:42 file
    +-rw-r--r--. 3 vagrant wheel  19 Nov  1 10:42 hardlinkfile1
    +-rw-r--r--. 3 vagrant wheel  19 Nov  1 10:42 hardlinkfile2
    +lrwxrwxrwx. 1 vagrant wheel   4 Nov  1 10:43 symlinkfile1 -> file
    +lrwxrwxrwx. 1 vagrant wheel   4 Nov  1 10:43 symlinkfile2 -> file
    +

    修改file文件的内容。

    echo "add oneline" >> file
    +

    通过命令cat file查看当前file的内容。

    it's original file
    +add oneline
    +

    通过下面的命令,可以看到所以软/硬链接文件内容都更新了,和file文件更新后的内容保持一致。

    cat hardlinkfile1
    +cat hardlinkfile2
    +cat symlinkfile1
    +cat symlinkfile2
    +

    对文件symlinkfile1再创建新的软连接。

    ln -s symlinkfile1 symlinkfile1-1
    +

    通过命令ls -il查看现在的目录信息。

    67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 file
    +67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile1
    +67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile2
    +67274681 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile1 -> file
    +67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov  1 11:20 symlinkfile1-1 -> symlinkfile1
    +67274682 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile2 -> file
    +

    读取软链接文件的源文件信息

    readlink symlinkfile1
    +readlink symlinkfile2
    +

    注意,对于symlinkfile1-1的情况有些不同。

    readlink symlinkfile1-1
    +

    上面命令返回结果symlinkfile1仍然是一个符号链接文件。通过readlink -f可以直接定位真正的源文件。

    readlink -f symlinkfile1-1
    +

    上面的返回结果/data/linktype/filesymlinkfile1-1真正的源文件。

    显示data目录下的文件和子目录:

    cd ~
    +tree ./data
     

    运行结果:

    ./data
    -├── file
    -├── hardlinkfile1
    -├── hardlinkfile2
    -├── symlinkfile1 -> file
    -├── symlinkfile1-1 -> symlinkfile1
    -├── symlinkfile2 -> file
    -└── typelink
    -

    只显示data目录下的子目录:

    tree -d ./data
    +├── file
    +├── hardlinkfile1
    +├── hardlinkfile2
    +├── symlinkfile1 -> file
    +├── symlinkfile1-1 -> symlinkfile1
    +├── symlinkfile2 -> file
    +└── typelink
    +

    只显示data目录下的子目录:

    tree -d ./data
     

    运行结果:

    ./data
    -└── typelink
    -

    显示data目录下的文件和子目录,包含全目录:

    tree -f ./data
    +└── typelink
    +

    显示data目录下的文件和子目录,包含全目录:

    tree -f ./data
     

    运行结果:

    ./data
    -├── ./data/file
    -├── ./data/hardlinkfile1
    -├── ./data/hardlinkfile2
    -├── ./data/symlinkfile1 -> file
    -├── ./data/symlinkfile1-1 -> symlinkfile1
    -├── ./data/symlinkfile2 -> file
    -└── ./data/typelink
    -

    4.文件属性说明

    执行命令ls -ihl,可以得到下面的输出结果(Rocky 9)。

    67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 file
    -67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile1
    -67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile2
    -67274681 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile1 -> file
    -67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov  1 11:20 symlinkfile1-1 -> symlinkfile1
    -67274682 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile2 -> file
    -33555262 drwxr-xr-x. 2 vagrant wheel  6 Nov  1 11:30 typelink
    -

    67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11:14 file为例:

    • 67274680: inode 索引节点编号。
    • -rw-r--r--:文件类型及权限
    • -:文件类型,例子中出现了三种,-ld
      • -:普通文件
      • d:目录
      • l:符号链接文件(link)
      • b:块设备(block)
      • c:字符设备(character)
      • p:管道文件(pipe)
      • s:套接字文件(socket)
    • rw-r--r--:文件权限,从左到右依次为:
      • rw-:文件属主权限,例子中是vagrant
      • r--:文件属组的权限,例子中是wheel
      • r--:其他组的权限。
    • .:这个点表示文件带有SELinux的安全上下文(SELinux Contexts)。关闭SELinux,新创建的文件就不会再有这个点了。但是,以前创建的文件本来有这个点的还会显示这个点(虽然SELinux不起作用了)。
    • 3:硬链接数,例子中filehardlinkfile1hardlinkfile2之间是硬链接,所以这三个文件的硬链接数都是3
    • vagrant:文件属主
    • wheel:文件属组
    • 31:文件或目录的大小
    • Nov 1 11:14:文件或目录的创建日期和时间
    • file:文件或目录名称

    下面是命令ls -ihl在openSUSE和Ubuntu上的显示结果。

    $ ls -ihl
    -233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 file
    -233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 hardlinkfile1
    -233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 hardlinkfile2
    -233648 lrwxrwxrwx 1 vagrant wheel  4 Nov  1 15:52 symlinkfile1 -> file
    -233650 lrwxrwxrwx 1 vagrant wheel 12 Nov  1 15:52 symlinkfile1-1 -> symlinkfile1
    -233649 lrwxrwxrwx 1 vagrant wheel  4 Nov  1 15:52 symlinkfile2 -> file
    -233646 drwxr-xr-x 1 vagrant wheel  0 Nov  1 15:51 typelink
    -

    5.标准输入输出

    标准输入输出,即I/O,I/O的I是Input,O是output。

    • I:从外部设备输入到内存
    • O:从内存输出到外部设备

    标准输入和标准输出是用于IO的,它们属于外部设备(逻辑上的外部设备),不是内存。

    linux中一切设备皆是文件!因此标准输入和输出本质就是文件,外部设备以文件形式表现。

    在Linux系统中,标准输入和标准输出对应的文件是/dev/stdin/dev/stdout这两个文件。

    从标准输入读,从逻辑上讲,就是打开/dev/stdin这个文件,并读入文件内容。 输出到标准输出,从逻辑上讲,就是打开/dev/stdout这个文件,并把内容输出到这个文件里去。

    这里强调的是“逻辑上”,因为/dev/stdin/dev/stdout这2个文件本身不是设备文件。Linux中设备是文件,但是文件不一定是设备。 因此,操作/dev/stdin和/dev/stdout`这2个文件,实际上是操作两个文件存放地址对应的设备文件。

    通过下面命令可以看到标准输入输出文件的特点,他们虽然在/dev目录下,都是以l开头的链接文件,指向的是另一个文件的地址。

    $ ls -l /dev/std*
    -lrwxrwxrwx 1 root root 15 Nov 13 10:39 /dev/stderr -> /proc/self/fd/2
    -lrwxrwxrwx 1 root root 15 Nov 13 10:39 /dev/stdin -> /proc/self/fd/0
    -lrwxrwxrwx 1 root root 15 Nov 13 10:39 /dev/stdout -> /proc/self/fd/1
    +├── ./data/file
    +├── ./data/hardlinkfile1
    +├── ./data/hardlinkfile2
    +├── ./data/symlinkfile1 -> file
    +├── ./data/symlinkfile1-1 -> symlinkfile1
    +├── ./data/symlinkfile2 -> file
    +└── ./data/typelink
    +

    4.文件属性说明

    执行命令ls -ihl,可以得到下面的输出结果(Rocky 9)。

    67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 file
    +67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile1
    +67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile2
    +67274681 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile1 -> file
    +67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov  1 11:20 symlinkfile1-1 -> symlinkfile1
    +67274682 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile2 -> file
    +33555262 drwxr-xr-x. 2 vagrant wheel  6 Nov  1 11:30 typelink
    +

    67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11:14 file为例:

    • 67274680: inode 索引节点编号。
    • -rw-r--r--:文件类型及权限
    • -:文件类型,例子中出现了三种,-ld
      • -:普通文件
      • d:目录
      • l:符号链接文件(link)
      • b:块设备(block)
      • c:字符设备(character)
      • p:管道文件(pipe)
      • s:套接字文件(socket)
    • rw-r--r--:文件权限,从左到右依次为:
      • rw-:文件属主权限,例子中是vagrant
      • r--:文件属组的权限,例子中是wheel
      • r--:其他组的权限。
    • .:这个点表示文件带有SELinux的安全上下文(SELinux Contexts)。关闭SELinux,新创建的文件就不会再有这个点了。但是,以前创建的文件本来有这个点的还会显示这个点(虽然SELinux不起作用了)。
    • 3:硬链接数,例子中filehardlinkfile1hardlinkfile2之间是硬链接,所以这三个文件的硬链接数都是3
    • vagrant:文件属主
    • wheel:文件属组
    • 31:文件或目录的大小
    • Nov 1 11:14:文件或目录的创建日期和时间
    • file:文件或目录名称

    下面是命令ls -ihl在openSUSE和Ubuntu上的显示结果。

    $ ls -ihl
    +233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 file
    +233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 hardlinkfile1
    +233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 hardlinkfile2
    +233648 lrwxrwxrwx 1 vagrant wheel  4 Nov  1 15:52 symlinkfile1 -> file
    +233650 lrwxrwxrwx 1 vagrant wheel 12 Nov  1 15:52 symlinkfile1-1 -> symlinkfile1
    +233649 lrwxrwxrwx 1 vagrant wheel  4 Nov  1 15:52 symlinkfile2 -> file
    +233646 drwxr-xr-x 1 vagrant wheel  0 Nov  1 15:51 typelink
    +

    5.标准输入输出

    标准输入输出,即I/O,I/O的I是Input,O是output。

    • I:从外部设备输入到内存
    • O:从内存输出到外部设备

    标准输入和标准输出是用于IO的,它们属于外部设备(逻辑上的外部设备),不是内存。

    linux中一切设备皆是文件!因此标准输入和输出本质就是文件,外部设备以文件形式表现。

    在Linux系统中,标准输入和标准输出对应的文件是/dev/stdin/dev/stdout这两个文件。

    从标准输入读,从逻辑上讲,就是打开/dev/stdin这个文件,并读入文件内容。 输出到标准输出,从逻辑上讲,就是打开/dev/stdout这个文件,并把内容输出到这个文件里去。

    这里强调的是“逻辑上”,因为/dev/stdin/dev/stdout这2个文件本身不是设备文件。Linux中设备是文件,但是文件不一定是设备。 因此,操作/dev/stdin和/dev/stdout`这2个文件,实际上是操作两个文件存放地址对应的设备文件。

    通过下面命令可以看到标准输入输出文件的特点,他们虽然在/dev目录下,都是以l开头的链接文件,指向的是另一个文件的地址。

    $ ls -l /dev/std*
    +lrwxrwxrwx 1 root root 15 Nov 13 10:39 /dev/stderr -> /proc/self/fd/2
    +lrwxrwxrwx 1 root root 15 Nov 13 10:39 /dev/stdin -> /proc/self/fd/0
    +lrwxrwxrwx 1 root root 15 Nov 13 10:39 /dev/stdout -> /proc/self/fd/1
     
     # Rocky
    -$ ll /proc/self/fd/
    -lrwx------. 1 vagrant wheel 64 Nov 13 22:38 0 -> /dev/pts/0
    -lrwx------. 1 vagrant wheel 64 Nov 13 22:38 1 -> /dev/pts/0
    -lrwx------. 1 vagrant wheel 64 Nov 13 22:38 2 -> /dev/pts/0
    -lr-x------. 1 vagrant wheel 64 Nov 13 22:38 3 -> /proc/1702/fd
    +$ ll /proc/self/fd/
    +lrwx------. 1 vagrant wheel 64 Nov 13 22:38 0 -> /dev/pts/0
    +lrwx------. 1 vagrant wheel 64 Nov 13 22:38 1 -> /dev/pts/0
    +lrwx------. 1 vagrant wheel 64 Nov 13 22:38 2 -> /dev/pts/0
    +lr-x------. 1 vagrant wheel 64 Nov 13 22:38 3 -> /proc/1702/fd
     
     # Ubuntu
    -$ ll /proc/self/fd/
    -lrwx------ 1 vagrant sudo 64 Nov 13 14:38 0 -> /dev/pts/0
    -lrwx------ 1 vagrant sudo 64 Nov 13 14:38 1 -> /dev/pts/0
    -lrwx------ 1 vagrant sudo 64 Nov 13 14:38 2 -> /dev/pts/0
    -lr-x------ 1 vagrant sudo 64 Nov 13 14:38 3 -> /proc/2062/fd/
    +$ ll /proc/self/fd/
    +lrwx------ 1 vagrant sudo 64 Nov 13 14:38 0 -> /dev/pts/0
    +lrwx------ 1 vagrant sudo 64 Nov 13 14:38 1 -> /dev/pts/0
    +lrwx------ 1 vagrant sudo 64 Nov 13 14:38 2 -> /dev/pts/0
    +lr-x------ 1 vagrant sudo 64 Nov 13 14:38 3 -> /proc/2062/fd/
     
     # openSUSE
    -$ ll /proc/self/fd/*
    -ls: cannot access '/proc/self/fd/255': No such file or directory
    -ls: cannot access '/proc/self/fd/3': No such file or directory
    -lrwx------ 1 vagrant wheel 64 Nov 13 22:37 /proc/self/fd/0 -> /dev/pts/0
    -lrwx------ 1 vagrant wheel 64 Nov 13 22:37 /proc/self/fd/1 -> /dev/pts/0
    -lrwx------ 1 vagrant wheel 64 Nov 13 22:37 /proc/self/fd/2 -> /dev/pts/0
    -

    Linux进程默认会打开的三个文件:

    • 标准输入/dev/stdin,描述符为 0,默认是键盘输入。
    • 标准输出/dev/stdout,描述符为 1,默认是输出到屏幕。
    • 标准输出/dev/stderr,描述符为 2,默认是输出到屏幕。

    以Rocky为例,创建file.py文件。

    $ cat > file.py <<EOF
    +$ ll /proc/self/fd/*
    +ls: cannot access '/proc/self/fd/255': No such file or directory
    +ls: cannot access '/proc/self/fd/3': No such file or directory
    +lrwx------ 1 vagrant wheel 64 Nov 13 22:37 /proc/self/fd/0 -> /dev/pts/0
    +lrwx------ 1 vagrant wheel 64 Nov 13 22:37 /proc/self/fd/1 -> /dev/pts/0
    +lrwx------ 1 vagrant wheel 64 Nov 13 22:37 /proc/self/fd/2 -> /dev/pts/0
    +

    Linux进程默认会打开的三个文件:

    • 标准输入/dev/stdin,描述符为 0,默认是键盘输入。
    • 标准输出/dev/stdout,描述符为 1,默认是输出到屏幕。
    • 标准输出/dev/stderr,描述符为 2,默认是输出到屏幕。

    以Rocky为例,创建file.py文件。

    $ cat > file.py <<EOF
     import time
     f = open('test.txt', 'r')
     time.sleep(1000)
     EOF
    -

    创建test.txt文件。

    echo "hello" > test.txt
    -

    运行file.py程序。

    python3 file.py
    -

    打开新的终端窗口,执行下面命令,得到python3这个程序运行的process ID。其中可以看到有一个来自文件test.txt被程序file.py打开(输入)。

    $ pidof python3
    -1739 788
    -
    -$ sudo ls -l /proc/788/fd/
    -lr-x------. 1 root root 64 Nov 13 23:00 0 -> /dev/null
    -l-wx------. 1 root root 64 Nov 13 23:00 1 -> /dev/null
    -lrwx------. 1 root root 64 Nov 13 23:00 10 -> 'socket:[24677]'
    -lrwx------. 1 root root 64 Nov 13 23:00 11 -> 'socket:[24678]'
    -l-wx------. 1 root root 64 Nov 13 23:00 2 -> /dev/null
    -l-wx------. 1 root root 64 Nov 13 10:41 3 -> /var/log/firewalld
    -lrwx------. 1 root root 64 Nov 13 23:00 4 -> 'socket:[23421]'
    -lrwx------. 1 root root 64 Nov 13 23:00 5 -> 'anon_inode:[eventfd]'
    -lrwx------. 1 root root 64 Nov 13 23:00 6 -> 'socket:[24586]'
    -lr-x------. 1 root root 64 Nov 13 23:00 7 -> anon_inode:inotify
    -lrwx------. 1 root root 64 Nov 13 23:00 8 -> 'anon_inode:[eventfd]'
    -lrwx------. 1 root root 64 Nov 13 23:00 9 -> '/memfd:libffi (deleted)'
    -
    -$ sudo ls -l /proc/1739/fd/
    -lrwx------. 1 vagrant wheel 64 Nov 13 23:00 0 -> /dev/pts/0
    -lrwx------. 1 vagrant wheel 64 Nov 13 23:00 1 -> /dev/pts/0
    -lrwx------. 1 vagrant wheel 64 Nov 13 23:00 2 -> /dev/pts/0
    -lr-x------. 1 vagrant wheel 64 Nov 13 23:00 3 -> /home/vagrant/test.txt
    -

    在Ubuntu中运行file.py程序,pidof会取得3个process IDs。

    $ pidof python3
    -2128 924 873
    -
    -$ sudo ls -l /proc/2128/fd/
    -lrwx------ 1 vagrant sudo 64 Nov 13 15:10 0 -> /dev/pts/0
    -lrwx------ 1 vagrant sudo 64 Nov 13 15:10 1 -> /dev/pts/0
    -lrwx------ 1 vagrant sudo 64 Nov 13 15:10 2 -> /dev/pts/0
    -lr-x------ 1 vagrant sudo 64 Nov 13 15:10 3 -> /home/vagrant/test.txt
    -
    -$ sudo ls -l /proc/924/fd/
    -lr-x------ 1 root root 64 Nov 13 15:11 0 -> /dev/null
    -lrwx------ 1 root root 64 Nov 13 15:11 1 -> 'socket:[31593]'
    -lrwx------ 1 root root 64 Nov 13 15:11 2 -> 'socket:[31593]'
    -l-wx------ 1 root root 64 Nov 13 02:40 3 -> /var/log/unattended-upgrades/unattended-upgrades-shutdown.log
    -lrwx------ 1 root root 64 Nov 13 15:11 4 -> 'socket:[31652]'
    -lrwx------ 1 root root 64 Nov 13 15:11 5 -> 'anon_inode:[eventfd]'
    -lrwx------ 1 root root 64 Nov 13 15:11 6 -> 'anon_inode:[eventfd]'
    -lrwx------ 1 root root 64 Nov 13 15:11 7 -> 'socket:[31657]'
    -l-wx------ 1 root root 64 Nov 13 15:11 8 -> /run/systemd/inhibit/1.ref
    -lrwx------ 1 root root 64 Nov 13 15:11 9 -> 'socket:[31658]'
    -
    -$ sudo ls -l /proc/873/fd/
    -lr-x------ 1 root root 64 Nov 13 15:11 0 -> /dev/null
    -lrwx------ 1 root root 64 Nov 13 15:11 1 -> 'socket:[31412]'
    -lrwx------ 1 root root 64 Nov 13 15:11 2 -> 'socket:[31412]'
    -lrwx------ 1 root root 64 Nov 13 02:40 3 -> 'socket:[31650]'
    -lrwx------ 1 root root 64 Nov 13 15:11 4 -> 'anon_inode:[eventfd]'
    -lrwx------ 1 root root 64 Nov 13 15:11 5 -> 'socket:[31663]'
    -lrwx------ 1 root root 64 Nov 13 15:11 6 -> 'socket:[31664]'
    -

    openSUSE需要安装包sysvinit-tools才能使用pidof命令。

    sudo zypper in sysvinit-tools
    -

    由于openSUSE中pidof python3只返回一个process ID,所以可以简化命令行得到process ID的详细信息。

    $ sudo ls -l /proc/`pidof python3`/fd/
    -lrwx------ 1 vagrant wheel 64 Nov 13 23:21 0 -> /dev/pts/0
    -lrwx------ 1 vagrant wheel 64 Nov 13 23:21 1 -> /dev/pts/0
    -lrwx------ 1 vagrant wheel 64 Nov 13 23:21 2 -> /dev/pts/0
    -lr-x------ 1 vagrant wheel 64 Nov 13 23:21 3 -> /home/vagrant/test.txt
    -

    参考:

    当键盘和鼠标等设备通过串口直接连接到计算机时,这种连接称为TTY。 伪终端pseudoterminal(缩写为“pty”)是一对提供双向通信通道的虚拟字符设备。 通道的一端称为主端master; 另一端称为从端slave。

    /dev/pts表示与伪终端pseudoterminal的主端master或从端slave相关的master文件,操作系统将其保存为/dev/ptmx文件。 telnetssh等程序能够仿 端用户> 与它们的交互,虽然本质上是与文件/dev/ptmx进行交互,但呈现给用户的却是好像运行在真正的终端窗口一样,从端的文件是主端的输入。

    伪终端进程在Linux中被存储在/dev/pts/目录下。/dev/pts/目录下的内容是一些特殊的目录,由Linux内核所创建。

    每个唯一的终端窗口都与/dev/pts系统中的一个Linuxpts条目相关。

    下面返回的结果说明有2个远程终端连接到当前的机器。

    $ ll /dev/pts/
    -crw--w----. 1 vagrant tty  136, 0 Nov 13 23:18 0
    -crw--w----. 1 vagrant tty  136, 1 Nov 13 23:48 1
    -c---------. 1 root    root   5, 2 Nov 13 10:41 ptmx
    -

    也可以通过w命令看到2个终端进程。

    $ w
    - 23:55:05 up 13:14,  2 users,  load average: 0.00, 0.00, 0.00
    -USER     TTY        LOGIN@   IDLE   JCPU   PCPU WHAT
    -vagrant  pts/0     10:51   37:03   0.05s  0.05s -bash
    -vagrant  pts/1     23:48    0.00s  0.03s  0.00s w
    +

    创建test.txt文件。

    echo "hello" > test.txt
    +

    运行file.py程序。

    python3 file.py
    +

    打开新的终端窗口,执行下面命令,得到python3这个程序运行的process ID。其中可以看到有一个来自文件test.txt被程序file.py打开(输入)。

    $ pidof python3
    +1739 788
    +
    +$ sudo ls -l /proc/788/fd/
    +lr-x------. 1 root root 64 Nov 13 23:00 0 -> /dev/null
    +l-wx------. 1 root root 64 Nov 13 23:00 1 -> /dev/null
    +lrwx------. 1 root root 64 Nov 13 23:00 10 -> 'socket:[24677]'
    +lrwx------. 1 root root 64 Nov 13 23:00 11 -> 'socket:[24678]'
    +l-wx------. 1 root root 64 Nov 13 23:00 2 -> /dev/null
    +l-wx------. 1 root root 64 Nov 13 10:41 3 -> /var/log/firewalld
    +lrwx------. 1 root root 64 Nov 13 23:00 4 -> 'socket:[23421]'
    +lrwx------. 1 root root 64 Nov 13 23:00 5 -> 'anon_inode:[eventfd]'
    +lrwx------. 1 root root 64 Nov 13 23:00 6 -> 'socket:[24586]'
    +lr-x------. 1 root root 64 Nov 13 23:00 7 -> anon_inode:inotify
    +lrwx------. 1 root root 64 Nov 13 23:00 8 -> 'anon_inode:[eventfd]'
    +lrwx------. 1 root root 64 Nov 13 23:00 9 -> '/memfd:libffi (deleted)'
    +
    +$ sudo ls -l /proc/1739/fd/
    +lrwx------. 1 vagrant wheel 64 Nov 13 23:00 0 -> /dev/pts/0
    +lrwx------. 1 vagrant wheel 64 Nov 13 23:00 1 -> /dev/pts/0
    +lrwx------. 1 vagrant wheel 64 Nov 13 23:00 2 -> /dev/pts/0
    +lr-x------. 1 vagrant wheel 64 Nov 13 23:00 3 -> /home/vagrant/test.txt
    +

    在Ubuntu中运行file.py程序,pidof会取得3个process IDs。

    $ pidof python3
    +2128 924 873
    +
    +$ sudo ls -l /proc/2128/fd/
    +lrwx------ 1 vagrant sudo 64 Nov 13 15:10 0 -> /dev/pts/0
    +lrwx------ 1 vagrant sudo 64 Nov 13 15:10 1 -> /dev/pts/0
    +lrwx------ 1 vagrant sudo 64 Nov 13 15:10 2 -> /dev/pts/0
    +lr-x------ 1 vagrant sudo 64 Nov 13 15:10 3 -> /home/vagrant/test.txt
    +
    +$ sudo ls -l /proc/924/fd/
    +lr-x------ 1 root root 64 Nov 13 15:11 0 -> /dev/null
    +lrwx------ 1 root root 64 Nov 13 15:11 1 -> 'socket:[31593]'
    +lrwx------ 1 root root 64 Nov 13 15:11 2 -> 'socket:[31593]'
    +l-wx------ 1 root root 64 Nov 13 02:40 3 -> /var/log/unattended-upgrades/unattended-upgrades-shutdown.log
    +lrwx------ 1 root root 64 Nov 13 15:11 4 -> 'socket:[31652]'
    +lrwx------ 1 root root 64 Nov 13 15:11 5 -> 'anon_inode:[eventfd]'
    +lrwx------ 1 root root 64 Nov 13 15:11 6 -> 'anon_inode:[eventfd]'
    +lrwx------ 1 root root 64 Nov 13 15:11 7 -> 'socket:[31657]'
    +l-wx------ 1 root root 64 Nov 13 15:11 8 -> /run/systemd/inhibit/1.ref
    +lrwx------ 1 root root 64 Nov 13 15:11 9 -> 'socket:[31658]'
    +
    +$ sudo ls -l /proc/873/fd/
    +lr-x------ 1 root root 64 Nov 13 15:11 0 -> /dev/null
    +lrwx------ 1 root root 64 Nov 13 15:11 1 -> 'socket:[31412]'
    +lrwx------ 1 root root 64 Nov 13 15:11 2 -> 'socket:[31412]'
    +lrwx------ 1 root root 64 Nov 13 02:40 3 -> 'socket:[31650]'
    +lrwx------ 1 root root 64 Nov 13 15:11 4 -> 'anon_inode:[eventfd]'
    +lrwx------ 1 root root 64 Nov 13 15:11 5 -> 'socket:[31663]'
    +lrwx------ 1 root root 64 Nov 13 15:11 6 -> 'socket:[31664]'
    +

    openSUSE需要安装包sysvinit-tools才能使用pidof命令。

    sudo zypper in sysvinit-tools
    +

    由于openSUSE中pidof python3只返回一个process ID,所以可以简化命令行得到process ID的详细信息。

    $ sudo ls -l /proc/`pidof python3`/fd/
    +lrwx------ 1 vagrant wheel 64 Nov 13 23:21 0 -> /dev/pts/0
    +lrwx------ 1 vagrant wheel 64 Nov 13 23:21 1 -> /dev/pts/0
    +lrwx------ 1 vagrant wheel 64 Nov 13 23:21 2 -> /dev/pts/0
    +lr-x------ 1 vagrant wheel 64 Nov 13 23:21 3 -> /home/vagrant/test.txt
    +

    参考:

    当键盘和鼠标等设备通过串口直接连接到计算机时,这种连接称为TTY。 伪终端pseudoterminal(缩写为“pty”)是一对提供双向通信通道的虚拟字符设备。 通道的一端称为主端master; 另一端称为从端slave。

    /dev/pts表示与伪终端pseudoterminal的主端master或从端slave相关的master文件,操作系统将其保存为/dev/ptmx文件。 telnetssh等程序能够仿 端用户> 与它们的交互,虽然本质上是与文件/dev/ptmx进行交互,但呈现给用户的却是好像运行在真正的终端窗口一样,从端的文件是主端的输入。

    伪终端进程在Linux中被存储在/dev/pts/目录下。/dev/pts/目录下的内容是一些特殊的目录,由Linux内核所创建。

    每个唯一的终端窗口都与/dev/pts系统中的一个Linuxpts条目相关。

    下面返回的结果说明有2个远程终端连接到当前的机器。

    $ ll /dev/pts/
    +crw--w----. 1 vagrant tty  136, 0 Nov 13 23:18 0
    +crw--w----. 1 vagrant tty  136, 1 Nov 13 23:48 1
    +c---------. 1 root    root   5, 2 Nov 13 10:41 ptmx
    +

    也可以通过w命令看到2个终端进程。

    $ w
    + 23:55:05 up 13:14,  2 users,  load average: 0.00, 0.00, 0.00
    +USER     TTY        LOGIN@   IDLE   JCPU   PCPU WHAT
    +vagrant  pts/0     10:51   37:03   0.05s  0.05s -bash
    +vagrant  pts/1     23:48    0.00s  0.03s  0.00s w
     

    单个伪终端pseudoterminal可以同时接收来自不同的程序的输出。 多个程序同时对一个伪终端pseudoterminal进行读取会引起混淆。

    存储在/dev/pts目录中的文件是抽象文件而不是真实文件,是伪终端中执行程序时临时存储的数据。 打开/dev/pts下的文件通常没有什么实际意义。

    6.重定向和管道

    6.1.输入重定向

    常用命令格式:

    • command < file:将指定文件file作为命令的输入设备。
    • command << delimiter:表示从标准输入设备(键盘)中读入,直到遇到分界符delimiter停止(读入的数据不包括分界符),这里的分界符可以理解为自定义的字符串。
    • command < file1 > file2:将file1作为命令的输入设备,该命令的执行结果输出到file2中。
    # 输出文件file.py内容(输入设备是键盘)
    -$ cat file.py
    +$ cat file.py
     
     # 输出文件file.py内容(输入设备是文件file.py)
    -$ cat < file.py
    +$ cat < file.py
     
     # 指定分界符(这里是EOF),读取键盘输入内容,直到遇到指定分界符为止,将所读取的内容输出到文件file.py。
    -$ cat > file.py <<EOF
    +$ cat > file.py <<EOF
     import time
     f = open('test.txt', 'r')
     time.sleep(1000)
     EOF
     
     # 读取文件file.py内容,输出到新文件new.py。
    -$ cat < file.py > new.py
    -

    6.2.输出重定向

    输出重定向分为标准输出重定向和错误输出重定向两种。

    常用命令格式:

    • command > file:将命令command执行的标准输出结果重定向输出到指定的文件file中,如果该文件已包含数据,会清空原有数据,再写入新数据。
    • command 2> file:将命令command执行的错误输出结果重定向到指定的文件file中,如果该文件中已包含数据,会清空原有数据,再写入新数据。
    • command >> file:将命令command执行的标准输出结果重定向输出到指定的文件file中,如果该文件已包含数据,新数据将追加写入到原有内容的后面。
    • command 2>> file:将命令command执行的错误输出结果重定向到指定的文件file中,如果该文件中已包含数据,新数据将追加写入到原有内容的后面。
    • command >> file 2>&1 或者 command &>> file:将标准输出或者错误输出写入到指定文件file中,如果该文件中已包含数据,新数据将追加写入到原有内容的后面。

    注意:上面的file可以是一个普通文件,也可以使用一个特殊的文件/dev/null/dev/null并不保存数据,被写入/dev/null的数据最终都会丢失。

    举例:2个python文件存在,其他2个无扩展名的文件不存在。

    ls file.py > out
    -ls file 2> out.err
    +$ cat < file.py > new.py
    +

    6.2.输出重定向

    输出重定向分为标准输出重定向和错误输出重定向两种。

    常用命令格式:

    • command > file:将命令command执行的标准输出结果重定向输出到指定的文件file中,如果该文件已包含数据,会清空原有数据,再写入新数据。
    • command 2> file:将命令command执行的错误输出结果重定向到指定的文件file中,如果该文件中已包含数据,会清空原有数据,再写入新数据。
    • command >> file:将命令command执行的标准输出结果重定向输出到指定的文件file中,如果该文件已包含数据,新数据将追加写入到原有内容的后面。
    • command 2>> file:将命令command执行的错误输出结果重定向到指定的文件file中,如果该文件中已包含数据,新数据将追加写入到原有内容的后面。
    • command >> file 2>&1 或者 command &>> file:将标准输出或者错误输出写入到指定文件file中,如果该文件中已包含数据,新数据将追加写入到原有内容的后面。

    注意:上面的file可以是一个普通文件,也可以使用一个特殊的文件/dev/null/dev/null并不保存数据,被写入/dev/null的数据最终都会丢失。

    举例:2个python文件存在,其他2个无扩展名的文件不存在。

    ls file.py > out
    +ls file 2> out.err
     
    -ls new.py >> out
    -ls new 2>> out.err
    -

    可以得到预期的结果。两个错误记录都被追加到out.err文件中。两个成功执行的命令的返回结果也输出到out文件中。

    $ccat out
    +ls new.py >> out
    +ls new 2>> out.err
    +

    可以得到预期的结果。两个错误记录都被追加到out.err文件中。两个成功执行的命令的返回结果也输出到out文件中。

    $ccat out
     file.py
     new.py
     
    -$ cat out.err
    -ls: cannot access 'file': No such file or directory
    -ls: cannot access 'new': No such file or directory
    -

    上例命令也可以合并。

    ls file.py > out 2> out.err
    -ls file >> out 2>> out.err
    -

    2>&1格式举例:

    $ ls file >> out.txt 2>&1
    -$ cat out.txt
    -ls: cannot access 'file': No such file or directory
    -
    -$ ls file.py &>> out.txt
    -$ cat out.txt
    -ls: cannot access 'file': No such file or directory
    +$ cat out.err
    +ls: cannot access 'file': No such file or directory
    +ls: cannot access 'new': No such file or directory
    +

    上例命令也可以合并。

    ls file.py > out 2> out.err
    +ls file >> out 2>> out.err
    +

    2>&1格式举例:

    $ ls file >> out.txt 2>&1
    +$ cat out.txt
    +ls: cannot access 'file': No such file or directory
    +
    +$ ls file.py &>> out.txt
    +$ cat out.txt
    +ls: cannot access 'file': No such file or directory
     file.py
    -

    6.3.特殊重定向

    格式:command1 < <(command2)

    tr 'a-z' 'A-Z' < <(echo "Hello World")
    -

    应用:修改密码

    密码保存在passwd.txt文件中,并严格限制改文件的权限。 通过参数--stdin实现模拟键盘输入操作输入用户名。

    在Rocky中可以使用--stdin参数。

    passwd --stdin vagrant < passwd.txt
    -

    在openSUSE和Ubuntu中,--stdin参数无法识别。可以改用下面的方法。

    echo passwd.txt | chpasswd
    -

    其中passwd.txt的格式为username:password

    参考:

    Here-document(Here-doc):输入的文本块重定向至标准输入流,直至遇到特殊的文件结束标记符为止(文件结束标记符可以是任意的唯一的字符串,但大部分人都默认使用 EOF)。

    cat <<EOF
    +

    6.3.特殊重定向

    格式:command1 < <(command2)

    tr 'a-z' 'A-Z' < <(echo "Hello World")
    +

    应用:修改密码

    密码保存在passwd.txt文件中,并严格限制改文件的权限。 通过参数--stdin实现模拟键盘输入操作输入用户名。

    在Rocky中可以使用--stdin参数。

    passwd --stdin vagrant < passwd.txt
    +

    在openSUSE和Ubuntu中,--stdin参数无法识别。可以改用下面的方法。

    echo passwd.txt | chpasswd
    +

    其中passwd.txt的格式为username:password

    参考:

    Here-document(Here-doc):输入的文本块重定向至标准输入流,直至遇到特殊的文件结束标记符为止(文件结束标记符可以是任意的唯一的字符串,但大部分人都默认使用 EOF)。

    cat <<EOF
     This is line1
     Another line
     Finally 3rd line
     EOF
    -

    文本块中含有tab键。

    cat <<-EOF
    +

    文本块中含有tab键。

    cat <<-EOF
         This message is indented
             This message is double indented
     EOF
    -

    文本块中含有参数。

    cat <<EOF
    +

    文本块中含有参数。

    cat <<EOF
     Hello ${USER}
     EOF
    -

    文本块中含有命令。

    cat <<EOF
    +

    文本块中含有命令。

    cat <<EOF
     Hello! It is currently: $(date)
     EOF
    -

    Here-string:与Here-doc相似,但是它只有一个字符串,或者几个被引号括起来的字符串。

    基本用法。

    cat <<< "This is a string"
    +

    Here-string:与Here-doc相似,但是它只有一个字符串,或者几个被引号括起来的字符串。

    基本用法。

    cat <<< "This is a string"
     

    使用变量。

    WELCOME_MESSAGE="Welcome!"
    -cat <<< $WELCOME_MESSAGE
    -

    使用参数。

    cat <<< "Welcome! ${USER}"
    -

    7.管道

    Linux中使用竖线|连接多个命令,这被称为管道符。

    当在两个命令之间设置管道时,管道符|左边命令的输出就变成了右边命令的输入。管道符|左边正确的输出才能被右边处理,管道符|右边不能处理左边错误的输出。

    重定向和管道的区别:重定向操作符>将命令与文件连接起来,用文件来接收命令的输出;而管道符|将命令与命令连接起来,用右边命令来接收左边命令的输出。

    $ ls | tr 'a-z' 'A-Z'
    +cat <<< $WELCOME_MESSAGE
    +

    使用参数。

    cat <<< "Welcome! ${USER}"
    +

    7.管道

    Linux中使用竖线|连接多个命令,这被称为管道符。

    当在两个命令之间设置管道时,管道符|左边命令的输出就变成了右边命令的输入。管道符|左边正确的输出才能被右边处理,管道符|右边不能处理左边错误的输出。

    重定向和管道的区别:重定向操作符>将命令与文件连接起来,用文件来接收命令的输出;而管道符|将命令与命令连接起来,用右边命令来接收左边命令的输出。

    $ ls | tr 'a-z' 'A-Z'
     BIN
     F1.TXT
     F2.TXT
    @@ -520,4 +520,4 @@
     OUT
     OUT.ERR
     TEST.TXT
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/linux/SRE/03-identity-security/index.html b/linux/SRE/03-identity-security/index.html index 9cf3b98a..779f7078 100644 --- a/linux/SRE/03-identity-security/index.html +++ b/linux/SRE/03-identity-security/index.html @@ -1,118 +1,118 @@ - 第三章 身份与安全 - UPSkilling

    第三章 身份与安全

    1.用户、组、权限

    用户和组

    • 用户user和组group在Linux系统中以数字形式进行管理。
    • 用户被分配的号码称为用户ID(UID)。
    • 每个Linux系统都有一个特权用户,即root用户。 root是系统管理员。 此用户的UID始终为0。
    • 普通用户的UID编号(默认情况下)为1000。
    • 每个组也分配了一个称为组ID(GID)的编号。
    • 每个用户有一个主要组(primary group),有零个或者任意个附加组(supplementary group)。

    以openSUSE为例:

    • UID
    • 0: root
    • 1 – 99: System
    • 100 – 499: System accounts
    • ≥ 1000: Normal (unprivileged) accounts

    • GID

    • 0: root
    • 1 – 99: System Groups
    • 100 – 499: Dynamically Allocated System Groups
    • ≥ 1000: Normal Groups

    举例:

    $ id postfix
    -uid=51(postfix) gid=51(postfix) groups=482(mail),59(maildrop),51(postfix)
    + 第三章 身份与安全 - UPSkilling       

    第三章 身份与安全

    1.用户、组、权限

    用户和组

    • 用户user和组group在Linux系统中以数字形式进行管理。
    • 用户被分配的号码称为用户ID(UID)。
    • 每个Linux系统都有一个特权用户,即root用户。 root是系统管理员。 此用户的UID始终为0。
    • 普通用户的UID编号(默认情况下)为1000。
    • 每个组也分配了一个称为组ID(GID)的编号。
    • 每个用户有一个主要组(primary group),有零个或者任意个附加组(supplementary group)。

    以openSUSE为例:

    • UID
    • 0: root
    • 1 – 99: System
    • 100 – 499: System accounts
    • ≥ 1000: Normal (unprivileged) accounts

    • GID

    • 0: root
    • 1 – 99: System Groups
    • 100 – 499: Dynamically Allocated System Groups
    • ≥ 1000: Normal Groups

    举例:

    $ id postfix
    +uid=51(postfix) gid=51(postfix) groups=482(mail),59(maildrop),51(postfix)
     
    -$ id vagrant
    -uid=1000(vagrant) gid=478(wheel) groups=0(root),478(wheel)
    -

    提示:

    UID和GID等编号规则,是在文件/etc/login.defs中约定的。

    2.SELinux

    Security-Enhanced Linux (SELinux) 是一种Linux系统的安全架构,它允许管理员更好地控制谁可以访问系统。 SELinux于2000年向开源社区发布,并于2003年集成到上游 Linux 内核中。

    SELinux为系统上的应用程序、进程和文件定义了访问控制。 它使用安全策略(一组规则告诉SELinux什么可以访问或不可以访问)来强制执行策略允许的访问。

    当称为主体(subject)的应用程序或进程请求访问对象(如文件)时,SELinux会检查访问向量缓存(AVC, Access Vector Cache),其中缓存了主体和对象的权限。

    如果SELinux无法根据缓存的权限做出访问决定,它会将请求发送到安全服务器。 安全服务器检查应用程序或进程和文件的安全上下文。 从SELinux策略数据库应用安全上下文(Security context),然后授予或拒绝许可。 如果权限被拒绝,avc: denied消息将在/var/log.messages中体现。

    传统上,Linux和UNIX系统都使用DAC(Discretionary Access Control)。 SELinux是Linux的MAC(Mandatory Access Control)系统的一个示例。

    在DAC方式下,文件和进程有自己的属主(所有者)。 用户可以拥有一个文件,一个组也可以拥有一个文件,或者其他人。 用户可以更改自己文件的权限。root用户对DAC系统具有完全访问控制权。

    但是在像SELinux这样的MAC系统上,对于访问的管理是通过设置策略来实现的。即使用户主目录上的DAC设置发生更改,用于防止其他用户或进程访问该目录的SELinux策略也将继续确保系统安全。

    MAC方式是控制一个进程对具体文件系统上面的文件或目录是否拥有访问权限。判断进程是否可以访问文件或目录的依据,取决于SELinux中设定的很多策略规则。

    访问控制列表 (ACL,Access Control List) 为文件系统提供了一种额外的、更灵活的权限机制。 它旨在协助 UNIX 文件权限。ACL允许授予任何用户或组对任何磁盘资源的权限。ACL适用于在不使某个用户成为组成员的情况下,仍旧授予一些读或写访问权限。

    下面示例对比说明了SELinux和ACL在文件属性展现上的特点。

    • -rwxr-xr-- vagrant wheel :没有selinux上下文,没有ACL
    • -rwx--xr-x+ vagrant wheel :只有ACL,没有selinux上下文
    • -rw-r--r--. vagrant wheel :只有selinux上下文,没有ACL
    • -rwxrwxr--+ vagrant wheel :有selinux上下文,有ACL

    2.1.SELinux主要概念

    • 用户(Users):
    • SELinux的用户不等同与Linux用户。
    • SELinux用户以后缀_u结尾。

    • 角色(Roles):

    • 角色Roles是由策略Policies定义的,角色决定了使用哪个策略。
    • SELinux角色以后缀_r结尾。

    • 类型(Types):

    • SELinux是类型强制的,类型Types决定进程能否访问某个文件。
    • SELinux类型是以后缀_t结尾。

    • 上下文(Contexts):

    • 用来标记进程和文件。分别是用户Users,角色Roles,类型Types,范围Ranges。
    • 格式:user:role:type:range

    • 文件类型(Object Classes):

    • 每个文件类型Types都对应一套策略Policies。策略Policies决定了进程对这类文件的访问权限。
    • 访问权限有4种:

      • 创建create
      • 读取read
      • 写入write
      • 删除unlink(注意,这里不是链接的意思)
    • 规则(Rules)

    • 格式:allow user_t user_home_t:file {create read write unlink};
    • 含义:user_t类型对user_home_t类型有创建create,读取read,写入write,删除unlink权限。

    2.2.SELinux in openSUSE

    作为SELinux的替代品,2005年被Novell收购的Immunix公司开发了AppArmor。SUSE在openSUSE Leap中提供对SELinux框架的支持。这并不意味着openSUSE Leap的默认安装会在不久的将来从AppArmor切换到SELinux。

    添加SELinux的源。可以从https://download.opensuse.org/repositories/security:/SELinux/下载对应的策略policy。

    sudo zypper ar -f https://download.opensuse.org/repositories/security:/SELinux/openSUSE_Factory/ Security-SELinux
    +$ id vagrant
    +uid=1000(vagrant) gid=478(wheel) groups=0(root),478(wheel)
    +

    提示:

    UID和GID等编号规则,是在文件/etc/login.defs中约定的。

    2.SELinux

    Security-Enhanced Linux (SELinux) 是一种Linux系统的安全架构,它允许管理员更好地控制谁可以访问系统。 SELinux于2000年向开源社区发布,并于2003年集成到上游 Linux 内核中。

    SELinux为系统上的应用程序、进程和文件定义了访问控制。 它使用安全策略(一组规则告诉SELinux什么可以访问或不可以访问)来强制执行策略允许的访问。

    当称为主体(subject)的应用程序或进程请求访问对象(如文件)时,SELinux会检查访问向量缓存(AVC, Access Vector Cache),其中缓存了主体和对象的权限。

    如果SELinux无法根据缓存的权限做出访问决定,它会将请求发送到安全服务器。 安全服务器检查应用程序或进程和文件的安全上下文。 从SELinux策略数据库应用安全上下文(Security context),然后授予或拒绝许可。 如果权限被拒绝,avc: denied消息将在/var/log.messages中体现。

    传统上,Linux和UNIX系统都使用DAC(Discretionary Access Control)。 SELinux是Linux的MAC(Mandatory Access Control)系统的一个示例。

    在DAC方式下,文件和进程有自己的属主(所有者)。 用户可以拥有一个文件,一个组也可以拥有一个文件,或者其他人。 用户可以更改自己文件的权限。root用户对DAC系统具有完全访问控制权。

    但是在像SELinux这样的MAC系统上,对于访问的管理是通过设置策略来实现的。即使用户主目录上的DAC设置发生更改,用于防止其他用户或进程访问该目录的SELinux策略也将继续确保系统安全。

    MAC方式是控制一个进程对具体文件系统上面的文件或目录是否拥有访问权限。判断进程是否可以访问文件或目录的依据,取决于SELinux中设定的很多策略规则。

    访问控制列表 (ACL,Access Control List) 为文件系统提供了一种额外的、更灵活的权限机制。 它旨在协助 UNIX 文件权限。ACL允许授予任何用户或组对任何磁盘资源的权限。ACL适用于在不使某个用户成为组成员的情况下,仍旧授予一些读或写访问权限。

    下面示例对比说明了SELinux和ACL在文件属性展现上的特点。

    • -rwxr-xr-- vagrant wheel :没有selinux上下文,没有ACL
    • -rwx--xr-x+ vagrant wheel :只有ACL,没有selinux上下文
    • -rw-r--r--. vagrant wheel :只有selinux上下文,没有ACL
    • -rwxrwxr--+ vagrant wheel :有selinux上下文,有ACL

    2.1.SELinux主要概念

    • 用户(Users):
    • SELinux的用户不等同与Linux用户。
    • SELinux用户以后缀_u结尾。

    • 角色(Roles):

    • 角色Roles是由策略Policies定义的,角色决定了使用哪个策略。
    • SELinux角色以后缀_r结尾。

    • 类型(Types):

    • SELinux是类型强制的,类型Types决定进程能否访问某个文件。
    • SELinux类型是以后缀_t结尾。

    • 上下文(Contexts):

    • 用来标记进程和文件。分别是用户Users,角色Roles,类型Types,范围Ranges。
    • 格式:user:role:type:range

    • 文件类型(Object Classes):

    • 每个文件类型Types都对应一套策略Policies。策略Policies决定了进程对这类文件的访问权限。
    • 访问权限有4种:

      • 创建create
      • 读取read
      • 写入write
      • 删除unlink(注意,这里不是链接的意思)
    • 规则(Rules)

    • 格式:allow user_t user_home_t:file {create read write unlink};
    • 含义:user_t类型对user_home_t类型有创建create,读取read,写入write,删除unlink权限。

    2.2.SELinux in openSUSE

    作为SELinux的替代品,2005年被Novell收购的Immunix公司开发了AppArmor。SUSE在openSUSE Leap中提供对SELinux框架的支持。这并不意味着openSUSE Leap的默认安装会在不久的将来从AppArmor切换到SELinux。

    添加SELinux的源。可以从https://download.opensuse.org/repositories/security:/SELinux/下载对应的策略policy。

    sudo zypper ar -f https://download.opensuse.org/repositories/security:/SELinux/openSUSE_Factory/ Security-SELinux
     

    安装C++等基础开发包:

    # 列出当前可安装的Pattern
    -sudo zypper pt
    +sudo zypper pt
     
     # 安装下面几个开发相关的Pattern
    -sudo zypper in -t pattern devel_C_C++ devel_basis devel_kernel
    -

    安装SELinux packages:

    zypper se --search-descriptions selinux
    -sudo zypper in restorecond policycoreutils setools-console
    -sudo zypper in selinux-tools libselinux-devel
    -

    安装SELinux policy:

    sudo zypper in selinux-policy-targeted selinux-policy-devel selinux-autorelabel
    -

    更新GRUB2 bootloader(GRUB2引导加载程序):

    编辑文件/etc/default/grub,添加下面内容到GRUB_CMDLINE_LINUX_DEFAULT=这一行:

    security=selinux selinux=1
    +sudo zypper in -t pattern devel_C_C++ devel_basis devel_kernel
    +

    安装SELinux packages:

    zypper se --search-descriptions selinux
    +sudo zypper in restorecond policycoreutils setools-console
    +sudo zypper in selinux-tools libselinux-devel
    +

    安装SELinux policy:

    sudo zypper in selinux-policy-targeted selinux-policy-devel selinux-autorelabel
    +

    更新GRUB2 bootloader(GRUB2引导加载程序):

    编辑文件/etc/default/grub,添加下面内容到GRUB_CMDLINE_LINUX_DEFAULT=这一行:

    security=selinux selinux=1
     

    记录这一行的原始信息:

    GRUB_CMDLINE_LINUX_DEFAULT="splash=silent resume=/dev/disk/by-uuid/47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 preempt=full mitigations=auto quiet security=apparmor"
    -

    运行下面的命令生成新的GRUB2引导加载程序配置文件。

    sudo grub2-mkconfig -o /boot/grub2/grub.cfg
    -

    编辑文件/etc/selinux/config 并设置 SELINUX=permissive来启用SElinux。这与前面GRUB2的启动配置是一致的。 如文件不存在,则创建。

    $ sudo cat /etc/selinux/config
    +

    运行下面的命令生成新的GRUB2引导加载程序配置文件。

    sudo grub2-mkconfig -o /boot/grub2/grub.cfg
    +

    编辑文件/etc/selinux/config 并设置 SELINUX=permissive来启用SElinux。这与前面GRUB2的启动配置是一致的。 如文件不存在,则创建。

    $ sudo cat /etc/selinux/config
     SELINUX=permissive
     SELINUXTYPE=targeted
    -

    重启系统。系统启动可能需要一些时间,SELinux需要给整个文件系统重新进行标签化。

    重启后,运行下面的命令来查看SELinux是否运行正常。

    $ sudo getenforce
    +

    重启系统。系统启动可能需要一些时间,SELinux需要给整个文件系统重新进行标签化。

    重启后,运行下面的命令来查看SELinux是否运行正常。

    $ sudo getenforce
     Permissive
    -
    $ sudo sestatus -v
    -SELinux status:                 enabled
    -SELinuxfs mount:                /sys/fs/selinux
    -SELinux root directory:         /etc/selinux
    -Loaded policy name:             targeted
    -Current mode:                   permissive
    -Mode from config file:          permissive
    -Policy MLS status:              enabled
    -Policy deny_unknown status:     allowed
    -Memory protection checking:     requested (insecure)
    -Max kernel policy version:      33
    -
    -Process contexts:
    -Current context:                unconfined_u:unconfined_r:unconfined_t:s0
    -Init context:                   system_u:system_r:kernel_t:s0
    -/sbin/agetty                    system_u:system_r:kernel_t:s0
    -/usr/sbin/sshd                  system_u:system_r:kernel_t:s0
    -
    -File contexts:
    -Controlling terminal:           unconfined_u:object_r:devpts_t:s0
    -/etc/passwd                     system_u:object_r:unlabeled_t:s0
    -/etc/shadow                     system_u:object_r:unlabeled_t:s0
    -/bin/bash                       system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0
    -/bin/login                      system_u:object_r:unlabeled_t:s0
    -/bin/sh                         system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0
    -/sbin/agetty                    system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0
    -/sbin/init                      system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0
    -/usr/sbin/sshd                  system_u:object_r:unlabeled_t:s0
    -

    参考:

    GRUB2引导加载程序中添加的三个参数的解释:

    security=selinux: This option tells the kernel to use SELinux and not AppArmor.

    selinux=1: This option switches on SELinux.

    enforcing=0: This option puts SELinux in permissive mode. In this mode, SELinux is fully functional, but does not enforce any of the security settings in the policy. Use this mode for testing and configuring your system. To switch on SELinux protection, when the system is fully operational, change the option to enforcing=1 and add SELINUX=enforcing in /etc/selinux/config.

    小贴士:

    在首次启用SELinux后,如果只在grub2里面添加selinux=1,通过getenforce命令看的SELinux一直就是disabled的状态,需要手工创建/etc/selinux/config文件添加配置才行。感觉grub2里面无需设置,直接配置/etc/selinux/config文件。不确定这个想法是否正确。

    在grub2中设定selinux=1,在/etc/selinux/config文件中:

    • 设定SELINUX=permissive,重启后通过getenforce命令看到的是permissive。
    • 设定SELINUX=disabled,则重启后getenforce命令看到的是disabled。

    这说明配置文件后启动,覆盖了内核设置。

    注意,如果仅仅完成了上面的enable SELinux,立刻设定SELINUX=enforcing,会引起ssh无法登录,错误信息是/bin/bash: Permission denied

    配置SELinux。

    $ sudo semanage boolean -l
    -Failed to use semanage
    -

    添加下面内容到.bashrc文件。

    export PATH=/usr/local/bin:/home/$USER/.local/bin:$PATH
    -

    更新pip3.

    pip3 install --upgrade pip
    -

    安装下面几个包

    sudo zypper in libselinux libselinux-devel
    -sudo zypper in python3-semanage
    -sudo zypper in libsemanage-devel libsemanage-devel-static
    -sudo zypper in policycoreutils-python-utils
    -sudo zypper in cross-x86_64-linux-glibc-devel glibc-utils glibc-profile
    -
    -sudo zypper in policycoreutils-devel
    +
    $ sudo sestatus -v
    +SELinux status:                 enabled
    +SELinuxfs mount:                /sys/fs/selinux
    +SELinux root directory:         /etc/selinux
    +Loaded policy name:             targeted
    +Current mode:                   permissive
    +Mode from config file:          permissive
    +Policy MLS status:              enabled
    +Policy deny_unknown status:     allowed
    +Memory protection checking:     requested (insecure)
    +Max kernel policy version:      33
    +
    +Process contexts:
    +Current context:                unconfined_u:unconfined_r:unconfined_t:s0
    +Init context:                   system_u:system_r:kernel_t:s0
    +/sbin/agetty                    system_u:system_r:kernel_t:s0
    +/usr/sbin/sshd                  system_u:system_r:kernel_t:s0
    +
    +File contexts:
    +Controlling terminal:           unconfined_u:object_r:devpts_t:s0
    +/etc/passwd                     system_u:object_r:unlabeled_t:s0
    +/etc/shadow                     system_u:object_r:unlabeled_t:s0
    +/bin/bash                       system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0
    +/bin/login                      system_u:object_r:unlabeled_t:s0
    +/bin/sh                         system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0
    +/sbin/agetty                    system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0
    +/sbin/init                      system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0
    +/usr/sbin/sshd                  system_u:object_r:unlabeled_t:s0
    +

    参考:

    GRUB2引导加载程序中添加的三个参数的解释:

    security=selinux: This option tells the kernel to use SELinux and not AppArmor.

    selinux=1: This option switches on SELinux.

    enforcing=0: This option puts SELinux in permissive mode. In this mode, SELinux is fully functional, but does not enforce any of the security settings in the policy. Use this mode for testing and configuring your system. To switch on SELinux protection, when the system is fully operational, change the option to enforcing=1 and add SELINUX=enforcing in /etc/selinux/config.

    小贴士:

    在首次启用SELinux后,如果只在grub2里面添加selinux=1,通过getenforce命令看的SELinux一直就是disabled的状态,需要手工创建/etc/selinux/config文件添加配置才行。感觉grub2里面无需设置,直接配置/etc/selinux/config文件。不确定这个想法是否正确。

    在grub2中设定selinux=1,在/etc/selinux/config文件中:

    • 设定SELINUX=permissive,重启后通过getenforce命令看到的是permissive。
    • 设定SELINUX=disabled,则重启后getenforce命令看到的是disabled。

    这说明配置文件后启动,覆盖了内核设置。

    注意,如果仅仅完成了上面的enable SELinux,立刻设定SELINUX=enforcing,会引起ssh无法登录,错误信息是/bin/bash: Permission denied

    配置SELinux。

    $ sudo semanage boolean -l
    +Failed to use semanage
    +

    添加下面内容到.bashrc文件。

    export PATH=/usr/local/bin:/home/$USER/.local/bin:$PATH
    +

    更新pip3.

    pip3 install --upgrade pip
    +

    安装下面几个包

    sudo zypper in libselinux libselinux-devel
    +sudo zypper in python3-semanage
    +sudo zypper in libsemanage-devel libsemanage-devel-static
    +sudo zypper in policycoreutils-python-utils
    +sudo zypper in cross-x86_64-linux-glibc-devel glibc-utils glibc-profile
    +
    +sudo zypper in policycoreutils-devel
     

    2.3.SELinux in Ubuntu

    2.4.SELinux in Rocky

    3.用户和组的配置文件

    • /etc/passwd:用户及其属性信息(用户名,UID,主组ID等)
    • /etc/shadow:用户密码机器属性
    • /etc/group:组及其属性
    • /etc/gshadow:组密码及其属性

    3.1./etc/passwd

    格式说明:

    vagrant:x:1001:474:vagrant:/home/vagrant:/bin/bash
    -[-----] - [--] [-] [-----] [-----------] [-------]
    -   |    |  |    |     |          |           +--------> 7. Login shell
    -   |    |  |    |     |          +--------------------> 6. Home directory
    -   |    |  |    |     +-------------------------------> 5. GECOS or the full name of the user
    -   |    |  |    +-------------------------------------> 4. GID
    -   |    |  +------------------------------------------> 3. UID
    -   |    +---------------------------------------------> 2. Password
    -   +--------------------------------------------------> 1. Username
    +[-----] - [--] [-] [-----] [-----------] [-------]
    +   |    |  |    |     |          |           +--------> 7. Login shell
    +   |    |  |    |     |          +--------------------> 6. Home directory
    +   |    |  |    |     +-------------------------------> 5. GECOS or the full name of the user
    +   |    |  |    +-------------------------------------> 4. GID
    +   |    |  +------------------------------------------> 3. UID
    +   |    +---------------------------------------------> 2. Password
    +   +--------------------------------------------------> 1. Username
     

    3.2./etc/shadow

    格式说明:

    vagrant:$6$.n.:17736:0:99999:7:::
    -[-----] [----] [---] - [---] ----
    -|         |      |   |   |   |||+-----------> 9. Unused
    -|         |      |   |   |   ||+------------> 8. Expiration date since Jan 1, 1970
    -|         |      |   |   |   |+-------------> 7. Inactivity period 密码过期后的宽限期
    -|         |      |   |   |   +--------------> 6. Warning period, default 7 days
    -|         |      |   |   +------------------> 5. Maximum password age
    -|         |      |   +----------------------> 4. Minimum password age
    -|         |      +--------------------------> 3. Last password change since Jan 1, 1970
    -|         +---------------------------------> 2. Encrypted Password
    -+-------------------------------------------> 1. Username
    +[-----] [----] [---] - [---] ----
    +|         |      |   |   |   |||+-----------> 9. Unused
    +|         |      |   |   |   ||+------------> 8. Expiration date since Jan 1, 1970
    +|         |      |   |   |   |+-------------> 7. Inactivity period 密码过期后的宽限期
    +|         |      |   |   |   +--------------> 6. Warning period, default 7 days
    +|         |      |   |   +------------------> 5. Maximum password age
    +|         |      |   +----------------------> 4. Minimum password age
    +|         |      +--------------------------> 3. Last password change since Jan 1, 1970
    +|         +---------------------------------> 2. Encrypted Password
    ++-------------------------------------------> 1. Username
     

    3.3./etc/group

    格式说明:

    audio:x:492:pulse
    -[---] - [-] [---]
    -  |   |  |    +----> 4. username-list, who have this group as their supplementary
    -  |   |  +---------> 3. GID
    -  |   +------------> 2. group-password. Real password is in /etc/gshadow
    -  +----------------> 1. groupname
    +[---] - [-] [---]
    +  |   |  |    +----> 4. username-list, who have this group as their supplementary
    +  |   |  +---------> 3. GID
    +  |   +------------> 2. group-password. Real password is in /etc/gshadow
    +  +----------------> 1. groupname
     

    3.4./etc/gshadow

    格式说明:

    general:!!:shelley:juan,bob
    -[-----] -- [-----] [------]
    -   |     |     |       +-------> 4. group members (in a comma delimited list)
    -   |     |     +---------------> 3. group adminstrators (in a comma delimited list)
    -   |     +---------------------> 2. encrypted password. `!`, `!!`, and null
    -   +---------------------------> 1. group name
    +[-----] -- [-----] [------]
    +   |     |     |       +-------> 4. group members (in a comma delimited list)
    +   |     |     +---------------> 3. group adminstrators (in a comma delimited list)
    +   |     +---------------------> 2. encrypted password. `!`, `!!`, and null
    +   +---------------------------> 1. group name
     

    Encrypted password

    • !:no user is allowed to access the group using the newgrp command.
    • !!:the same as a value of ! — however, it also indicates that a password has never been set before.
    • null:only group members can log into the group.

    3.5.生成随机密码

    # 通过`/dev/urandom`生成随机数,通过`tr -dc`过滤随机数,只保留字母和数字,通过`head -c`保留指定位数
    -$ tr -dc '[:alnum:]' < /dev/urandom | head -c 12
    +$ tr -dc '[:alnum:]' < /dev/urandom | head -c 12
     xFw7vfma54D8
     
    -$ openssl rand -base64 9
    +$ openssl rand -base64 9
     I5TZXJfpd3Pg
    -

    3.6.vipw/vigr/pwck/grpck命令

    vipwvigr命令分别编辑文件/etc/passwd/etc/group。 如果指定了-s标志,这些命令将分别编辑其文件的影子(安全)版本:/etc/shadow/etc/gshadowvipwvigr命令在编辑文件时会设置锁以防止文件损坏。 vipwvigr命令会首先尝试环境变量$VISUAL,然后是环境变量$EDITOR,最后是默认编辑器vi

    sudo vipw
    -sudo vipw -s
    -sudo vigr
    -sudo vigr -s
    +

    3.6.vipw/vigr/pwck/grpck命令

    vipwvigr命令分别编辑文件/etc/passwd/etc/group。 如果指定了-s标志,这些命令将分别编辑其文件的影子(安全)版本:/etc/shadow/etc/gshadowvipwvigr命令在编辑文件时会设置锁以防止文件损坏。 vipwvigr命令会首先尝试环境变量$VISUAL,然后是环境变量$EDITOR,最后是默认编辑器vi

    sudo vipw
    +sudo vipw -s
    +sudo vigr
    +sudo vigr -s
     

    pwck命令实现验证系统认证信息的完整性。 检查/etc/passwd/etc/shadow中的所有条目每个字段是否具有正确的格式和有效数据。 系统会提示用户删除格式不正确或存在其他错误的条目。

    pwck返回值:

    • 0: success
    • 1: invalid command syntax
    • 2: one or more bad password entries
    • 3: can’t open password files
    • 4: can’t lock password files
    • 5: can’t update password files

    grpck命令实现验证系统认证信息的完整性。 检查/etc/group/etc/gshadow中的所有条目每个字段是否具有正确的格式和有效数据。 系统会提示用户删除格式不正确或存在其他错误的条目。

    grpck返回值:

    • 0: success
    • 1: invalid command syntax
    • 2: one or more bad group entries
    • 3: can’t open group files
    • 4: can’t lock group files
    • 5: can’t update group files

    4.用户管理

    用户管理命令:

    • useradd
    • usermod
    • userdel

    4.1.创建用户useradd

    举例:

    # 普通用户
    -$ useradd -m -g wheel -G root -c "vagrant" vagrant
    +$ useradd -m -g wheel -G root -c "vagrant" vagrant
     
     # 非交互用户
    -$ useradd -r -u 48 -g apache -d /var/www -s /sbin/nologin -g postfix -c "Apache" apache 2>/dev/null
    +$ useradd -r -u 48 -g apache -d /var/www -s /sbin/nologin -g postfix -c "Apache" apache 2>/dev/null
     

    useradd命令的默认值是在/etc/default/useradd文件中设定。

    openSUSE的/etc/default/useradd文件内容:

    GROUP=100
     HOME=/home
    -INACTIVE=-1              # 对应/etc/shadow文件第7列,Inactivity period,密码过期后的宽限期,-1表示不限制
    -EXPIRE=                  # 对应/etc/shadow文件第8列,Expiration date since Jan 1, 1970,即账号有效期
    +INACTIVE=-1              # 对应/etc/shadow文件第7列,Inactivity period,密码过期后的宽限期,-1表示不限制
    +EXPIRE=                  # 对应/etc/shadow文件第8列,Expiration date since Jan 1, 1970,即账号有效期
     SHELL=/bin/bash
    -SKEL=/etc/skel           # 用于生成用户主目录的模版文件
    +SKEL=/etc/skel           # 用于生成用户主目录的模版文件
     USRSKEL=/usr/etc/skel
     CREATE_MAIL_SPOOL=yes
     

    Rocky的/etc/default/useradd文件内容:

    GROUP=100
    @@ -123,172 +123,172 @@
     SKEL=/etc/skel
     CREATE_MAIL_SPOOL=yes
     

    在Ubuntu中/etc/default/useradd文件只有下面这一行。

    SHELL=/bin/sh
    -

    4.1.1.批量创建用户newusers

    格式:newusers <filename>。其中文件<filename>的格式如下:

    <Username>:<Password>:<UID>:<GID>:<User Info>:<Home Dir>:<Default Shell>
    -

    举例,创建文件users.txt

    $ cat ~/users.txt
    +

    4.1.1.批量创建用户newusers

    格式:newusers <filename>。其中文件<filename>的格式如下:

    <Username>:<Password>:<UID>:<GID>:<User Info>:<Home Dir>:<Default Shell>
    +

    举例,创建文件users.txt

    $ cat ~/users.txt
     tester1:123:600:1530:"Test User1,testuser1@abc.com":/home/tester1:/bin/bash
     tester2:123:601:1529:::/bin/bash
     tester3:123:::::
     tester4:123::::/home/tester4:/bin/tsh
    -

    看结果:

    $ cat /etc/passwd | grep tester
    +

    看结果:

    $ cat /etc/passwd | grep tester
     tester1:x:600:1530:"Test User1,testuser1@abc.com":/home/tester1:/bin/bash
     tester2:x:601:1529:::/bin/bash
     tester3:x:1001:1001:::
     tester4:x:1002:1002::/home/tester4:/bin/tsh
     
    -$ cat /etc/group | grep tester
    +$ cat /etc/group | grep tester
     tester1:*:1530:
     tester2:*:1529:
     tester3:*:1001:
     tester4:*:1002:
     
    -$ sudo cat /etc/shadow | grep tester
    +$ sudo cat /etc/shadow | grep tester
     tester1:!:19321:0:99999:7:::
     tester2:!:19321:0:99999:7:::
     tester3:!:19321:0:99999:7:::
     tester4:!:19321:0:99999:7:::
     
    -$ ls -ld /home/tester*
    -drwxr-xr-x. 1 tester1 tester1 0 Nov 26 00:32 /home/tester1
    -drwxr-xr-x. 1 tester4 tester4 0 Nov 26 00:32 /home/tester4
    -

    4.1.2.批量修改密码chpasswd

    不同方法:

    echo username:password | chpasswd
    +$ ls -ld /home/tester*
    +drwxr-xr-x. 1 tester1 tester1 0 Nov 26 00:32 /home/tester1
    +drwxr-xr-x. 1 tester4 tester4 0 Nov 26 00:32 /home/tester4
    +

    4.1.2.批量修改密码chpasswd

    不同方法:

    echo username:password | chpasswd
     
    -chpasswd < file.txt  # file.txt每行的格式是username:password
    +chpasswd < file.txt  # file.txt每行的格式是username:password
     
    -paste -d ":" user.txt passwd.txt | chpasswd
    -

    参数-e:口令以加密的方式传递。否则口令以明文的形式传递。

    注意:

    • 用户名username必须是已存在的用户
    • 普通用户没有使用这个指令的权限
    • 如果输入文件是按非加密方式传递的话,请对该文件进行适当的加密。
    • 指令文件不能有空行

    举例:

    echo tester1:112233 | sudo chpasswd
    -
    $ cat chpasswd.txt
    +paste -d ":" user.txt passwd.txt | chpasswd
    +

    参数-e:口令以加密的方式传递。否则口令以明文的形式传递。

    注意:

    • 用户名username必须是已存在的用户
    • 普通用户没有使用这个指令的权限
    • 如果输入文件是按非加密方式传递的话,请对该文件进行适当的加密。
    • 指令文件不能有空行

    举例:

    echo tester1:112233 | sudo chpasswd
    +
    $ cat chpasswd.txt
     tester1:112233
     tester2:33445566
     
    -$ sudo chpasswd < chpasswd.txt
    -

    4.1.3.生成加密密码openssl passwd

    命令openssl passwd格式可以如下方法获得。

    $ man -f passwd
    -passwd (1)           - change user password
    -passwd (1ssl)        - compute password hashes
    -passwd (5)           - password file
    -
    -$ man passwd
    -Man: find all matching manual pages (set MAN_POSIXLY_CORRECT to avoid this)
    - * passwd (1)
    -   passwd (5)
    -   passwd (1ssl)
    -Man: What manual page do you want?
    -Man: 1ssl
    +$ sudo chpasswd < chpasswd.txt
    +

    4.1.3.生成加密密码openssl passwd

    命令openssl passwd格式可以如下方法获得。

    $ man -f passwd
    +passwd (1)           - change user password
    +passwd (1ssl)        - compute password hashes
    +passwd (5)           - password file
    +
    +$ man passwd
    +Man: find all matching manual pages (set MAN_POSIXLY_CORRECT to avoid this)
    + * passwd (1)
    +   passwd (5)
    +   passwd (1ssl)
    +Man: What manual page do you want?
    +Man: 1ssl
     

    举例(这里用<your_pwsswd_string>代替实际密码):

    # 基于给定字串newpasswd生成sha256加密码,
    -$ openssl passwd -6 newpasswd
    +$ openssl passwd -6 newpasswd
     <your_pwsswd_string>
     
     # 创建新用户tester5,赋予加密密码
    -$ useradd -p '<your_pwsswd_string>' tester1
    +$ useradd -p '<your_pwsswd_string>' tester1
     
     # 读取用户tester5的密码,可以验证是否和之前的一致
    -$ sudo getent shadow tester5
    +$ sudo getent shadow tester5
     tester5:<your_pwsswd_string>:19321:0:99999:7:::
    -

    4.2.修改用户属性usermod

    添加用户到附加组

    usermod -a -G GROUP USER
    -usermod -a -G GROUP1,GROUP2,GROUP3 USER
    -

    修改用户主组

    usermod -a -g GROUP USER
    -

    修改用户信息

    usermod -c "GECOS Comments" USER
    -

    修改用户主目录,使用绝对路径,-m参数会把原主目录的内容移动到新主目录。

    usermod -d NEW_HOME_DIR USER
    -usermod -d NEW_HOME_DIR -m USER
    -

    修改用户shell

    usermod -s SHELL USER
    -

    修改用户UID

    usermod -u UID USER
    -

    修改用户名(不常用),同时也需要修改用户主目录。

    usermod -l NEW_USER USER
    -

    修改用户过期属性,日期格式是YYYY-MM-DD

    usermod -e DATE USER
    -

    如果设定永不过期,则置空日期:

    usermod -e "" USER
    -

    查看当前用户的过期日期

    $ sudo chage -l vagrant
    -Last password change     : Oct 30, 2022
    -Password expires     : never
    -Password inactive     : never
    -Account expires      : never
    -Minimum number of days between password change  : 0
    -Maximum number of days between password change  : 99999
    -Number of days of warning before password expires : 7
    -

    锁定用户。 此命令将在加密密码前插入一个感叹号 (!) 标记。 当/etc/shadow文件中的密码字段包含感叹号时,用户将无法使用密码验证登录系统。 其他登录方法仍然允许,例如基于密钥的身份验证或切换到用户。 如果要锁定账户并禁用所有登录方式,还需要将到期日期设置为1。

    usermod -L USER
    -usermod -L -e 1 USER
    -

    解锁用户

    usermod -U USER
    -

    4.3.删除用户userdel

    userdel命令执行时,会读取/etc/login.defs文件的内容。 此文件中定义的属性会覆盖userdel的默认行为。 如果在此文件中将USERGROUPS_ENAB设置为yesuserdel将删除与用户同名的组,前提是没有其他用户是该组的成员。

    userdel命令从/etc/passwd/etc/shadow文件中删除用户条目。

    userdel命令删除用户帐户时,一般不会删除用户主目录和邮件假脱机mail spool目录。 使用-r选项强制删除用户的主目录和邮件假脱机目录。

    如果要删除的用户仍然处于登录状态,或者有属于该用户的正在运行的进程,则userdel命令不允许删除该用户。

    使用-f选项强制删除用户帐户,即使用户仍然登录或有属于该用户的正在运行的进程也是如此。

    userdel USER
    -userdel -r USER
    -

    4.4.查看用户信息id

    类Unix操作系统中的每个用户都由一个不同的整数标识,这个唯一的数字称为UserID。

    为进程process定义了三种类型的UID,可以根据任务的权限动态更改。

    定义的三种不同类型的UID是:

    1. 真实用户ID(Real UserId):对于一个进程,Real UserId就是启动它的用户的 UserID。 它定义了这个进程可以访问哪些文件。
    2. 有效用户名(Effective UserID):它通常与 Real UserID 相同,但有时会更改为使非特权用户能够访问那些只能由特权用户(如root)访问的文件。
    3. 保存的用户ID(Saved UserID) :当一个以提升的权限(通常是root)运行的进程需要做一些低权限的任务时使用,可以通过临时切换到非特权帐户来实现。在执行低权限任务时,有效的UID被更改为某个较低权限的值,并且euid被保存到已保存的userID(suid)中,以便在任务完成时用于切换回特权帐户。

    在一个终端窗口执行下面命令,暂停在新密码输入这一步。

    $ ls -ltr /usr/bin/passwd
    --rwsr-xr-x. 1 root shadow 65208 May  8  2022 /usr/bin/passwd
    -
    -$ passwd
    -Changing password for vagrant.
    -Current password:
    -New password:
    -

    新开一个终端窗口。

    $ ps -a | grep passwd
    -  3040 pts/0    00:00:00 passwd
    -
    -$ ps -eo pid,euid,ruid | grep 3040
    -  3040     0  1000
    -

    上面输出可以看出,passwd这个进程的Effective UserID是0。Real UserId是1000.

    id命令查看用户有效的UID和GID。

    查看当前用户的信息:

    $ id
    -uid=1000(vagrant) gid=478(wheel) groups=478(wheel),0(root) context=unconfined_u:unconfined_r:unconfined_t:s0
    -

    查看指定用户的信息:

    $ id vagrant
    -uid=1000(vagrant) gid=478(wheel) groups=0(root),478(wheel)
    -

    查看当前用户的GID:

    $ id -g
    +

    4.2.修改用户属性usermod

    添加用户到附加组

    usermod -a -G GROUP USER
    +usermod -a -G GROUP1,GROUP2,GROUP3 USER
    +

    修改用户主组

    usermod -a -g GROUP USER
    +

    修改用户信息

    usermod -c "GECOS Comments" USER
    +

    修改用户主目录,使用绝对路径,-m参数会把原主目录的内容移动到新主目录。

    usermod -d NEW_HOME_DIR USER
    +usermod -d NEW_HOME_DIR -m USER
    +

    修改用户shell

    usermod -s SHELL USER
    +

    修改用户UID

    usermod -u UID USER
    +

    修改用户名(不常用),同时也需要修改用户主目录。

    usermod -l NEW_USER USER
    +

    修改用户过期属性,日期格式是YYYY-MM-DD

    usermod -e DATE USER
    +

    如果设定永不过期,则置空日期:

    usermod -e "" USER
    +

    查看当前用户的过期日期

    $ sudo chage -l vagrant
    +Last password change     : Oct 30, 2022
    +Password expires     : never
    +Password inactive     : never
    +Account expires      : never
    +Minimum number of days between password change  : 0
    +Maximum number of days between password change  : 99999
    +Number of days of warning before password expires : 7
    +

    锁定用户。 此命令将在加密密码前插入一个感叹号 (!) 标记。 当/etc/shadow文件中的密码字段包含感叹号时,用户将无法使用密码验证登录系统。 其他登录方法仍然允许,例如基于密钥的身份验证或切换到用户。 如果要锁定账户并禁用所有登录方式,还需要将到期日期设置为1。

    usermod -L USER
    +usermod -L -e 1 USER
    +

    解锁用户

    usermod -U USER
    +

    4.3.删除用户userdel

    userdel命令执行时,会读取/etc/login.defs文件的内容。 此文件中定义的属性会覆盖userdel的默认行为。 如果在此文件中将USERGROUPS_ENAB设置为yesuserdel将删除与用户同名的组,前提是没有其他用户是该组的成员。

    userdel命令从/etc/passwd/etc/shadow文件中删除用户条目。

    userdel命令删除用户帐户时,一般不会删除用户主目录和邮件假脱机mail spool目录。 使用-r选项强制删除用户的主目录和邮件假脱机目录。

    如果要删除的用户仍然处于登录状态,或者有属于该用户的正在运行的进程,则userdel命令不允许删除该用户。

    使用-f选项强制删除用户帐户,即使用户仍然登录或有属于该用户的正在运行的进程也是如此。

    userdel USER
    +userdel -r USER
    +

    4.4.查看用户信息id

    类Unix操作系统中的每个用户都由一个不同的整数标识,这个唯一的数字称为UserID。

    为进程process定义了三种类型的UID,可以根据任务的权限动态更改。

    定义的三种不同类型的UID是:

    1. 真实用户ID(Real UserId):对于一个进程,Real UserId就是启动它的用户的 UserID。 它定义了这个进程可以访问哪些文件。
    2. 有效用户名(Effective UserID):它通常与 Real UserID 相同,但有时会更改为使非特权用户能够访问那些只能由特权用户(如root)访问的文件。
    3. 保存的用户ID(Saved UserID) :当一个以提升的权限(通常是root)运行的进程需要做一些低权限的任务时使用,可以通过临时切换到非特权帐户来实现。在执行低权限任务时,有效的UID被更改为某个较低权限的值,并且euid被保存到已保存的userID(suid)中,以便在任务完成时用于切换回特权帐户。

    在一个终端窗口执行下面命令,暂停在新密码输入这一步。

    $ ls -ltr /usr/bin/passwd
    +-rwsr-xr-x. 1 root shadow 65208 May  8  2022 /usr/bin/passwd
    +
    +$ passwd
    +Changing password for vagrant.
    +Current password:
    +New password:
    +

    新开一个终端窗口。

    $ ps -a | grep passwd
    +  3040 pts/0    00:00:00 passwd
    +
    +$ ps -eo pid,euid,ruid | grep 3040
    +  3040     0  1000
    +

    上面输出可以看出,passwd这个进程的Effective UserID是0。Real UserId是1000.

    id命令查看用户有效的UID和GID。

    查看当前用户的信息:

    $ id
    +uid=1000(vagrant) gid=478(wheel) groups=478(wheel),0(root) context=unconfined_u:unconfined_r:unconfined_t:s0
    +

    查看指定用户的信息:

    $ id vagrant
    +uid=1000(vagrant) gid=478(wheel) groups=0(root),478(wheel)
    +

    查看当前用户的GID:

    $ id -g
     478
    -

    查看当前用户的UID:

    $ id -u
    +

    查看当前用户的UID:

    $ id -u
     1000
    -

    查看当前用户所有组的GID:

    $ id -G
    -478 0
    -

    查看当前用户名:

    $ id -un
    +

    查看当前用户所有组的GID:

    $ id -G
    +478 0
    +

    查看当前用户名:

    $ id -un
     vagrant
    -

    查看当前用户的GID

    $ id -ur
    +

    查看当前用户的GID

    $ id -ur
     1000
    -

    只有SELinux激活后才有

    $ id -Z
    +

    只有SELinux激活后才有

    $ id -Z
     unconfined_u:unconfined_r:unconfined_t:s0
    -

    类似于whoami命令

    $ id -znG
    +

    类似于whoami命令

    $ id -znG
     wheelroot
    -

    4.5.切换用户su

    命令su - username是登录式切换用户。会读取目标用户的配置文件,切换至目标用户的主目录。

    命令su username是非登录式切换用户。不读取目标用户的配置文件,不改变当前工作目录。

    切换成root用户,并使用zsh shell。

    su -s /usr/bin/zsh
    -su -s /usr/bin/zsh root
    -

    切换成tester1用户,使用bash shell

    su - tester1 -s /bin/bash
    -su - -s /bin/bash tester1
    -

    保留当前用户环境不变。

    su -p root
    -

    不交互式切换用户,只用目标用户执行某些命令。

    su -c ps
    -su - root -c "getent passwd"
    -su - root -s /bin/bash -c "getent passwd"
    +

    4.5.切换用户su

    命令su - username是登录式切换用户。会读取目标用户的配置文件,切换至目标用户的主目录。

    命令su username是非登录式切换用户。不读取目标用户的配置文件,不改变当前工作目录。

    切换成root用户,并使用zsh shell。

    su -s /usr/bin/zsh
    +su -s /usr/bin/zsh root
    +

    切换成tester1用户,使用bash shell

    su - tester1 -s /bin/bash
    +su - -s /bin/bash tester1
    +

    保留当前用户环境不变。

    su -p root
    +

    不交互式切换用户,只用目标用户执行某些命令。

    su -c ps
    +su - root -c "getent passwd"
    +su - root -s /bin/bash -c "getent passwd"
     

    root用户切换至其他用户不需要密码,非root用户切换其他用户需要密码。

    4.6.设置密码

    4.6.1.passwd

    修改当前用户自己的密码:

    passwd
    -

    修改其他用户的密码:

    sudo passwd root
    -

    查看某个用户密码状态:

    $ sudo passwd -S root
    -root P 10/30/2022 -1 -1 -1 -1
    -
    -$ sudo passwd -S vagrant
    -vagrant P 10/30/2022 0 99999 7 -1
    -

    检查全部用户的密码状态:

    sudo passwd -Sa
    -

    密码状态说明:

    Username  Status  Date Last Changed  Minimum Age  Maximum Age  Warning Period   Inactivity Period
    -vagrant     P       10/30/2022          0               99999           7                -1
    -root        P       10/30/2022          -1              -1              -1               -1
    -

    Status的描述:

    • P: Usable password
    • NP: No password
    • L: Locked password

    Age的一些特殊值:

    • 9999: Never expires
    • 0: Can be changed at anytime
    • -1: Not active

    强制要求用户下次登录时修改密码:

    $ sudo passwd -e tester1
    -
    -$ sudo passwd -S tester1
    -tester1 P 01/01/1970 0 99999 7 -1
    -

    用户tester1的密码日期已经被改成01/01/1970了。这个日期算是Unix的“纪元(epoch)”日期,意味着Unix的日期起点,0天。

    锁定某个用户:

    $ sudo passwd -l tester1
    -
    -$ sudo passwd -S tester1
    -tester1 L 01/01/1970 0 99999 7 -1
    -

    此时用户tester1的状态栏已经变成了L,锁定状态。

    解锁某个用户:

    $ sudo passwd -u tester1
    -
    -$ sudo passwd -S tester1
    -tester1 P 01/01/1970 0 99999 7 -1
    -

    此时用户tester1的状态栏已经从L变回了P,解除了锁定状态。

    删除用户密码。这个操作慎重,密码删除后该用户可以不需要密码就能访问系统。

    $ sudo passwd -d tester1
    -
    -$ sudo passwd -S tester1
    -tester1 NP 01/01/1970 0 99999 7 -1
    -

    此时用户tester1的状态栏是NP

    4.6.2.pwgen

    安装包。

    mkpasswd命令有歧义,2个同名命令实现不同功能,生成随机密码建议使用pwgen命令。Rocky9没有找到pwgen包。

    sudo zypper in pwgen
    -sudo apt install pwgen
    -

    随机生成长度8位安全密码。

    pwgen -s -1
    -

    随机生成长度14位安全密码。

    pwgen -s -1 14
    -

    随机生成2个长度15位安全密码。

    pwgen -s -1 15 2
    -

    随机生成5个密码,长度10位,每个密码至少含一个特殊字符,结果以列形式输出。

    pwgen -s -1 -y 10 5
    -

    生成长度8,含有数字,含有大小写字母的密码4个,列打印

    pwgen -s -n -c -C -1 8 4
    -

    生成长度8,不含数字,只含小写字母,列打印

    pwgen -s -c -A -0 -1 8 4
    -

    生成长度16,含有数字,含有大小写字母,含有特殊字符的密码3个,行打印

    pwgen -s -n -c -y -1 16 3
    -

    生成长度80,不含元音和数字,至少含有一个大写字母,行打印

    pwgen -s -v -c -0 80 1
    -

    4.6.3.非交互式设置密码

    方法1:

    $ echo -e '123456\n123456' | sudo passwd tester1
    -New password: BAD PASSWORD: it is too simplistic/systematic
    -BAD PASSWORD: is too simple
    -Retype new password: passwd: password updated successfully
    -

    方法2:

    Rocky中可以使用下面方法。

    pwgen -ncy1 16 1 | tee passwd.txt | sudo passwd --stdin tester1
    -

    openSUSE和Ubuntu可以用下面方法。

    echo "tester1:"`pwgen -ncy1 16 1` | tee passwd.txt | sudo chpasswd
    -

    方法3:根据预先给定的用户列表,批量生成密码。

    $ cat > user-list.txt <<EOF
    +

    修改其他用户的密码:

    sudo passwd root
    +

    查看某个用户密码状态:

    $ sudo passwd -S root
    +root P 10/30/2022 -1 -1 -1 -1
    +
    +$ sudo passwd -S vagrant
    +vagrant P 10/30/2022 0 99999 7 -1
    +

    检查全部用户的密码状态:

    sudo passwd -Sa
    +

    密码状态说明:

    Username  Status  Date Last Changed  Minimum Age  Maximum Age  Warning Period   Inactivity Period
    +vagrant     P       10/30/2022          0               99999           7                -1
    +root        P       10/30/2022          -1              -1              -1               -1
    +

    Status的描述:

    • P: Usable password
    • NP: No password
    • L: Locked password

    Age的一些特殊值:

    • 9999: Never expires
    • 0: Can be changed at anytime
    • -1: Not active

    强制要求用户下次登录时修改密码:

    $ sudo passwd -e tester1
    +
    +$ sudo passwd -S tester1
    +tester1 P 01/01/1970 0 99999 7 -1
    +

    用户tester1的密码日期已经被改成01/01/1970了。这个日期算是Unix的“纪元(epoch)”日期,意味着Unix的日期起点,0天。

    锁定某个用户:

    $ sudo passwd -l tester1
    +
    +$ sudo passwd -S tester1
    +tester1 L 01/01/1970 0 99999 7 -1
    +

    此时用户tester1的状态栏已经变成了L,锁定状态。

    解锁某个用户:

    $ sudo passwd -u tester1
    +
    +$ sudo passwd -S tester1
    +tester1 P 01/01/1970 0 99999 7 -1
    +

    此时用户tester1的状态栏已经从L变回了P,解除了锁定状态。

    删除用户密码。这个操作慎重,密码删除后该用户可以不需要密码就能访问系统。

    $ sudo passwd -d tester1
    +
    +$ sudo passwd -S tester1
    +tester1 NP 01/01/1970 0 99999 7 -1
    +

    此时用户tester1的状态栏是NP

    4.6.2.pwgen

    安装包。

    mkpasswd命令有歧义,2个同名命令实现不同功能,生成随机密码建议使用pwgen命令。Rocky9没有找到pwgen包。

    sudo zypper in pwgen
    +sudo apt install pwgen
    +

    随机生成长度8位安全密码。

    pwgen -s -1
    +

    随机生成长度14位安全密码。

    pwgen -s -1 14
    +

    随机生成2个长度15位安全密码。

    pwgen -s -1 15 2
    +

    随机生成5个密码,长度10位,每个密码至少含一个特殊字符,结果以列形式输出。

    pwgen -s -1 -y 10 5
    +

    生成长度8,含有数字,含有大小写字母的密码4个,列打印

    pwgen -s -n -c -C -1 8 4
    +

    生成长度8,不含数字,只含小写字母,列打印

    pwgen -s -c -A -0 -1 8 4
    +

    生成长度16,含有数字,含有大小写字母,含有特殊字符的密码3个,行打印

    pwgen -s -n -c -y -1 16 3
    +

    生成长度80,不含元音和数字,至少含有一个大写字母,行打印

    pwgen -s -v -c -0 80 1
    +

    4.6.3.非交互式设置密码

    方法1:

    $ echo -e '123456\n123456' | sudo passwd tester1
    +New password: BAD PASSWORD: it is too simplistic/systematic
    +BAD PASSWORD: is too simple
    +Retype new password: passwd: password updated successfully
    +

    方法2:

    Rocky中可以使用下面方法。

    pwgen -ncy1 16 1 | tee passwd.txt | sudo passwd --stdin tester1
    +

    openSUSE和Ubuntu可以用下面方法。

    echo "tester1:"`pwgen -ncy1 16 1` | tee passwd.txt | sudo chpasswd
    +

    方法3:根据预先给定的用户列表,批量生成密码。

    $ cat > user-list.txt <<EOF
     user0
     user1
     user2
    @@ -301,131 +301,131 @@
     user9
     EOF
     
    -$ for i in $(cat user-list.txt); do sudo useradd $i; echo "$i:"`pwgen -s -1 15 1` | tee passwd_$i.txt | sudo chpasswd; done
    -
    -$ for i in $(cat user-list.txt); do sudo userdel $i; done
    -

    4.7.设置用户密码策略

    命令chage修改用户密码策略。

    总结:

    • -d: Last password change : 上一次密码更改的日期。
    • -M: Password expires : 密码保持有效的最大天数。基于Last password change日期计算。设为-1表示不过期。
    • -I: Password inactive : 密码失效时间,在Password expires后,直至账号锁定之间的天数。设为-1表示不过期。
    • -E: Account expires : 帐号到期的日期。到期后,此帐号将不可用。设为-1表示不过期。
    • -m: Minimum number of days between password change : 两次改变密码之间相距的最小天数。
    • -M: Maximum number of days between password change : 两次改变密码之间相距的最大天数。
    • -W: Number of days of warning before password expires : 用户密码到期前,提前收到警告信息的天数。

    显示用户密码策略(时效信息):

    $ sudo chage -l tester1
    -Last password change     : Nov 27, 2022
    -Password expires     : never
    -Password inactive     : never
    -Account expires      : never
    -Minimum number of days between password change  : 0
    -Maximum number of days between password change  : 99999
    -Number of days of warning before password expires : 7
    -

    设置用户密码的最后修改日期:

    $ sudo chage -d 2022-11-11 tester1
    -
    -$ sudo chage -l tester1
    -Last password change     : Nov 11, 2022
    -Password expires     : never
    -Password inactive     : never
    -Account expires      : never
    -Minimum number of days between password change  : 0
    -Maximum number of days between password change  : 99999
    -Number of days of warning before password expires : 7
    -

    设置用户账号的过期日期:

    $ sudo chage -E 2022-12-31 tester1
    -
    -$ sudo chage -l tester1
    -Last password change     : Nov 11, 2022
    -Password expires     : never
    -Password inactive     : never
    -Account expires      : Dec 31, 2022
    -Minimum number of days between password change  : 0
    -Maximum number of days between password change  : 99999
    -Number of days of warning before password expires : 7
    -

    设置用户密码最小/最大修改天数。注意,密码过期日期Password expires是按照max days来计算的。

    $ sudo chage -M 35 tester1
    -$ sudo chage -m 30 tester1
    -
    -$ sudo chage -l tester1
    -Last password change     : Nov 11, 2022
    -Password expires     : Dec 16, 2022
    -Password inactive     : never
    -Account expires      : Dec 31, 2022
    -Minimum number of days between password change  : 30
    -Maximum number of days between password change  : 35
    -Number of days of warning before password expires : 7
    -

    设置用户账号在密码过期Password expires后,直至账号锁定之间的天数,即密码失效时间Password inactive。

    $ sudo chage -I 3 tester1
    -
    -$ sudo chage -l tester1
    -Last password change     : Nov 11, 2022
    -Password expires     : Dec 16, 2022
    -Password inactive     : Dec 19, 2022
    -Account expires      : Dec 31, 2022
    -Minimum number of days between password change  : 30
    -Maximum number of days between password change  : 35
    -Number of days of warning before password expires : 7
    -

    设置用户密码到期前,提前收到警告信息的天数。默认值是7天。

    $ sudo chage -W 5 tester1
    -
    -$ sudo chage -l tester1
    -Last password change     : Nov 11, 2022
    -Password expires     : Dec 16, 2022
    -Password inactive     : Dec 19, 2022
    -Account expires      : Dec 31, 2022
    -Minimum number of days between password change  : 30
    -Maximum number of days between password change  : 35
    -Number of days of warning before password expires : 5
    -

    5.组管理

    组管理命令:

    • groupadd
    • groupmod
    • groupdel
    • groupmems

    5.1.创建组groupadd

    创建普通组。

    sudo groupadd developers
    -

    创建系统组,并指定GID。

    sudo groupadd -g 48 -r apache
    -sudo groupadd -g 1100 -r developers
    -

    覆盖配置文件/ect/login.defs

    groupadd -K GID_MIN=500 -K GID_MAX=700
    -

    5.2.修改组groupmod

    命令groupmod涉及下面这些文件:

    /etc/group: Group Account Information. /etc/gshadow: Secured group account information. /etc/login.def: Shadow passwd suite configuration. /etc/passwd: User account information.

    组改名:

    sudo groupmod -n group_new group_old
    -

    5.3.删除组groupdel

    命令groupdel涉及下面这些文件:

    • /etc/group : It contains the account information of the Group.
    • /etc/gshadow: It contains the secure group account information.

    如果组中包含有用户,则必须先删除这些用户后,才能删除组。

    sudo groupdel group_name
    -

    5.4.更改组成员和密码gpasswd

    命令gpasswd用来修改组成员和密码。

    涉及到的文件:

    • /etc/group: Group account information.
    • /etc/gshadow: Secure group account information.

    给组developers设密码。

    sudo gpasswd developers
    -

    取消组developers密码。

    sudo gpasswd -r developers
    -

    给组developers添加用户。

    sudo gpasswd -a tester1,tester2,tester3 developers
    -

    从组developers中删除用户。

    sudo gpasswd -d tester3 developers
    -

    设定用户tester1成为组developers的管理员。

    sudo gpasswd -A tester1 developers
    +$ for i in $(cat user-list.txt); do sudo useradd $i; echo "$i:"`pwgen -s -1 15 1` | tee passwd_$i.txt | sudo chpasswd; done
    +
    +$ for i in $(cat user-list.txt); do sudo userdel $i; done
    +

    4.7.设置用户密码策略

    命令chage修改用户密码策略。

    总结:

    • -d: Last password change : 上一次密码更改的日期。
    • -M: Password expires : 密码保持有效的最大天数。基于Last password change日期计算。设为-1表示不过期。
    • -I: Password inactive : 密码失效时间,在Password expires后,直至账号锁定之间的天数。设为-1表示不过期。
    • -E: Account expires : 帐号到期的日期。到期后,此帐号将不可用。设为-1表示不过期。
    • -m: Minimum number of days between password change : 两次改变密码之间相距的最小天数。
    • -M: Maximum number of days between password change : 两次改变密码之间相距的最大天数。
    • -W: Number of days of warning before password expires : 用户密码到期前,提前收到警告信息的天数。

    显示用户密码策略(时效信息):

    $ sudo chage -l tester1
    +Last password change     : Nov 27, 2022
    +Password expires     : never
    +Password inactive     : never
    +Account expires      : never
    +Minimum number of days between password change  : 0
    +Maximum number of days between password change  : 99999
    +Number of days of warning before password expires : 7
    +

    设置用户密码的最后修改日期:

    $ sudo chage -d 2022-11-11 tester1
    +
    +$ sudo chage -l tester1
    +Last password change     : Nov 11, 2022
    +Password expires     : never
    +Password inactive     : never
    +Account expires      : never
    +Minimum number of days between password change  : 0
    +Maximum number of days between password change  : 99999
    +Number of days of warning before password expires : 7
    +

    设置用户账号的过期日期:

    $ sudo chage -E 2022-12-31 tester1
    +
    +$ sudo chage -l tester1
    +Last password change     : Nov 11, 2022
    +Password expires     : never
    +Password inactive     : never
    +Account expires      : Dec 31, 2022
    +Minimum number of days between password change  : 0
    +Maximum number of days between password change  : 99999
    +Number of days of warning before password expires : 7
    +

    设置用户密码最小/最大修改天数。注意,密码过期日期Password expires是按照max days来计算的。

    $ sudo chage -M 35 tester1
    +$ sudo chage -m 30 tester1
    +
    +$ sudo chage -l tester1
    +Last password change     : Nov 11, 2022
    +Password expires     : Dec 16, 2022
    +Password inactive     : never
    +Account expires      : Dec 31, 2022
    +Minimum number of days between password change  : 30
    +Maximum number of days between password change  : 35
    +Number of days of warning before password expires : 7
    +

    设置用户账号在密码过期Password expires后,直至账号锁定之间的天数,即密码失效时间Password inactive。

    $ sudo chage -I 3 tester1
    +
    +$ sudo chage -l tester1
    +Last password change     : Nov 11, 2022
    +Password expires     : Dec 16, 2022
    +Password inactive     : Dec 19, 2022
    +Account expires      : Dec 31, 2022
    +Minimum number of days between password change  : 30
    +Maximum number of days between password change  : 35
    +Number of days of warning before password expires : 7
    +

    设置用户密码到期前,提前收到警告信息的天数。默认值是7天。

    $ sudo chage -W 5 tester1
    +
    +$ sudo chage -l tester1
    +Last password change     : Nov 11, 2022
    +Password expires     : Dec 16, 2022
    +Password inactive     : Dec 19, 2022
    +Account expires      : Dec 31, 2022
    +Minimum number of days between password change  : 30
    +Maximum number of days between password change  : 35
    +Number of days of warning before password expires : 5
    +

    5.组管理

    组管理命令:

    • groupadd
    • groupmod
    • groupdel
    • groupmems

    5.1.创建组groupadd

    创建普通组。

    sudo groupadd developers
    +

    创建系统组,并指定GID。

    sudo groupadd -g 48 -r apache
    +sudo groupadd -g 1100 -r developers
    +

    覆盖配置文件/ect/login.defs

    groupadd -K GID_MIN=500 -K GID_MAX=700
    +

    5.2.修改组groupmod

    命令groupmod涉及下面这些文件:

    /etc/group: Group Account Information. /etc/gshadow: Secured group account information. /etc/login.def: Shadow passwd suite configuration. /etc/passwd: User account information.

    组改名:

    sudo groupmod -n group_new group_old
    +

    5.3.删除组groupdel

    命令groupdel涉及下面这些文件:

    • /etc/group : It contains the account information of the Group.
    • /etc/gshadow: It contains the secure group account information.

    如果组中包含有用户,则必须先删除这些用户后,才能删除组。

    sudo groupdel group_name
    +

    5.4.更改组成员和密码gpasswd

    命令gpasswd用来修改组成员和密码。

    涉及到的文件:

    • /etc/group: Group account information.
    • /etc/gshadow: Secure group account information.

    给组developers设密码。

    sudo gpasswd developers
    +

    取消组developers密码。

    sudo gpasswd -r developers
    +

    给组developers添加用户。

    sudo gpasswd -a tester1,tester2,tester3 developers
    +

    从组developers中删除用户。

    sudo gpasswd -d tester3 developers
    +

    设定用户tester1成为组developers的管理员。

    sudo gpasswd -A tester1 developers
     

    注意:添加用户到某一个组 也可以通过usermod -G group_name user_name这个实现,但是该用户以前的组会被清空掉。 所以,如果要添加一个用户到一个新组,同时希望保留该用户以前的组时,使用gpasswd这个命令来添加用户到新组中。

    5.5.修改组成员groupmems

    使用命令groupmems,需要安装软件包。

    # openSUSE
    -sudo zypper in libvshadow-tools
    +sudo zypper in libvshadow-tools
     # Ubuntu
    -sudo apt install libvshadow-utils
    +sudo apt install libvshadow-utils
     # Rocky
    -sudo yum search shadow-utils
    -

    添加用户到组。

    $ sudo groupmems -a tester1 -g developers
    -$ sudo groupmems -a tester2 -g developers
    +sudo yum search shadow-utils
    +

    添加用户到组。

    $ sudo groupmems -a tester1 -g developers
    +$ sudo groupmems -a tester2 -g developers
     
    -$ cat /etc/group | grep developers
    +$ cat /etc/group | grep developers
     developers:x:1002:tester1,tester2
    -

    从组中删除用户。

    $ sudo groupmems -d tester2 -g developers
    +

    从组中删除用户。

    $ sudo groupmems -d tester2 -g developers
     
    -$ cat /etc/group | grep developers
    +$ cat /etc/group | grep developers
     developers:x:1002:tester1
    -

    列出组中用户。

    $ sudo groupmems -l -g developers
    +

    列出组中用户。

    $ sudo groupmems -l -g developers
     tester1
    -

    切换当前组为developers_sre,添加用户tester2到当前组,可以不用在后续命令中使用-g指定组。

    $ sudo groupmems -g developers_sre
    +

    切换当前组为developers_sre,添加用户tester2到当前组,可以不用在后续命令中使用-g指定组。

    $ sudo groupmems -g developers_sre
     
    -$ sudo groupmems -a tester2
    +$ sudo groupmems -a tester2
     
    -$ sudo groupmems -l
    +$ sudo groupmems -l
     tester2
    -

    切换当前组为developers_sre,从当前组中删除所有用户(这里无法指定某用户)。

    sudo groupmems -g developers_sre
    -sudo groupmems -p
    -

    5.6.查看组关系group

    显示当前用户所属主的信息。

    $ whoami
    +

    切换当前组为developers_sre,从当前组中删除所有用户(这里无法指定某用户)。

    sudo groupmems -g developers_sre
    +sudo groupmems -p
    +

    5.6.查看组关系group

    显示当前用户所属主的信息。

    $ whoami
     vagrant
     
    -$ groups
    -sudo adm cdrom dip plugdev lxd
    -

    查看指定用户所属组的信息。

    $ groups vagrant
    -vagrant : sudo adm cdrom dip plugdev lxd
    -

    6.练习

    创建用户gentoo,附加组为binroot,默认shell为/bin/csh,注释信息为"Gentoo Distribution"

    sudo useradd -G bin,root -s /bin/csh -c "Gentoo Distribution" gentoo
    -

    创建下面的用户、组和组成员关系

    • 名字为webs的组
    • 用户nginx,使用webs作为附属组
    • 用户varnish,也使用webs作为附属组
    • 用户mysql,不可交互登录系统,且不是webs的成员,nginxvarnishmysql密码都是opensuse
    sudo groupadd webs
    -sudo useradd -G webs nginx
    -sudo useradd -G webs varnish
    -sudo useradd -s /sbin/nologin mysql
    -
    -echo "nginx:opensuse" | sudo chpasswd
    -echo -e "opensuse\nopensuse" | sudo passwd varnish
    -echo "mysql:opensuse" | sudo chpasswd
    -

    查看UID、GID范围的配置文件,修改为501-60000。并查看密码加密算法

    $ cat /etc/login.defs
    +$ groups
    +sudo adm cdrom dip plugdev lxd
    +

    查看指定用户所属组的信息。

    $ groups vagrant
    +vagrant : sudo adm cdrom dip plugdev lxd
    +

    6.练习

    创建用户gentoo,附加组为binroot,默认shell为/bin/csh,注释信息为"Gentoo Distribution"

    sudo useradd -G bin,root -s /bin/csh -c "Gentoo Distribution" gentoo
    +

    创建下面的用户、组和组成员关系

    • 名字为webs的组
    • 用户nginx,使用webs作为附属组
    • 用户varnish,也使用webs作为附属组
    • 用户mysql,不可交互登录系统,且不是webs的成员,nginxvarnishmysql密码都是opensuse
    sudo groupadd webs
    +sudo useradd -G webs nginx
    +sudo useradd -G webs varnish
    +sudo useradd -s /sbin/nologin mysql
    +
    +echo "nginx:opensuse" | sudo chpasswd
    +echo -e "opensuse\nopensuse" | sudo passwd varnish
    +echo "mysql:opensuse" | sudo chpasswd
    +

    查看UID、GID范围的配置文件,修改为501-60000。并查看密码加密算法

    $ cat /etc/login.defs
     ...
    -GID_MIN    1000
    -GID_MAX   60000
    +GID_MIN    1000
    +GID_MAX   60000
     ...
    -UID_MIN    1000
    -UID_MAX   60000
    +UID_MIN    1000
    +UID_MAX   60000
     ...
    -ENCRYPT_METHOD SHA512
    +ENCRYPT_METHOD SHA512
     ...
    -

    查看创建用户时的模板配置文件

    $ cat /etc/default/useradd
    +

    查看创建用户时的模板配置文件

    $ cat /etc/default/useradd
     # useradd defaults file
     GROUP=100
     HOME=/home
    @@ -435,10 +435,10 @@
     SKEL=/etc/skel
     USRSKEL=/usr/etc/skel
     CREATE_MAIL_SPOOL=yes
    -

    创建一个新用户webuser,指定登录时起始目录/www,同时加入apache附加组中,指定UID为999且不检查uid唯一性。

    sudo useradd -d /www -G apache -u 999 -o webuser
    -

    修改创建用户时的默认设置,主目录/www,默认shell csh。查看创建用户的配置文件是否更改,若更改则恢复默认值

    $ sudo useradd -Db /www -s /bin/csh
    +

    创建一个新用户webuser,指定登录时起始目录/www,同时加入apache附加组中,指定UID为999且不检查uid唯一性。

    sudo useradd -d /www -G apache -u 999 -o webuser
    +

    修改创建用户时的默认设置,主目录/www,默认shell csh。查看创建用户的配置文件是否更改,若更改则恢复默认值

    $ sudo useradd -Db /www -s /bin/csh
     
    -$ sudo cat /etc/default/useradd
    +$ sudo cat /etc/default/useradd
     # useradd defaults file
     GROUP=100
     HOME=/www
    @@ -449,511 +449,511 @@
     USRSKEL=/usr/etc/skel
     CREATE_MAIL_SPOOL=yes
     
    -$ sudo useradd -Db /home -s /bin/bash
    -

    批量创建用户admin1admin2admin3

    $ cat > user.txt <<EOF
    +$ sudo useradd -Db /home -s /bin/bash
    +

    批量创建用户admin1admin2admin3

    $ cat > user.txt <<EOF
     admin1
     admin2
     admin3
     EOF
     
    -$ for i in $(cat user.txt); do sudo useradd $i; echo "$i:"`pwgen -s -1 15 1` | tee passwd_$i.txt | sudo chpasswd; done
    -

    只查看用户admin2admin3/etc/passwd的配置信息。

    $ getent passwd admin2 admin3
    +$ for i in $(cat user.txt); do sudo useradd $i; echo "$i:"`pwgen -s -1 15 1` | tee passwd_$i.txt | sudo chpasswd; done
    +

    只查看用户admin2admin3/etc/passwd的配置信息。

    $ getent passwd admin2 admin3
     admin2:x:1019:100::/home/admin2:/bin/bash
     admin3:x:1020:100::/home/admin3:/bin/bash
    -

    修改admin2用户UID为2002、主组root、添加新的附加组apache且保留旧的附加组。然后锁定用户。

    $ sudo usermod -u 2002 -g root -G apache -a admin2
    -$ sudo usermod -L admin2
    +

    修改admin2用户UID为2002、主组root、添加新的附加组apache且保留旧的附加组。然后锁定用户。

    $ sudo usermod -u 2002 -g root -G apache -a admin2
    +$ sudo usermod -L admin2
     
    -$ getent passwd admin2
    +$ getent passwd admin2
     admin2:x:2002:0::/home/admin2:/bin/bash
     
    -$ sudo passwd -S admin2
    -admin2 L 11/27/2022 0 99999 7 -1
    -

    修改用户admin2用户名为smith,设置账号过期时间为2022-12-31

    $ sudo usermod -l smith -e 2022-12-31 admin2
    -
    -$ sudo chage -l smith
    -Last password change     : Nov 27, 2022
    -Password expires     : never
    -Password inactive     : never
    -Account expires      : Dec 31, 2022
    -Minimum number of days between password change  : 0
    -Maximum number of days between password change  : 99999
    -Number of days of warning before password expires : 7
    -

    admin1设置密码hello,然后指定新的主目录并把旧目录移动过去。

    sudo usermod -d /home/admin_new -m admin1
    -echo "admin1:hello" | sudo chpasswd 
    -

    显示smith用户UID、GID、显示用户名、显示用户所属组ID

    $ id -u smith
    +$ sudo passwd -S admin2
    +admin2 L 11/27/2022 0 99999 7 -1
    +

    修改用户admin2用户名为smith,设置账号过期时间为2022-12-31

    $ sudo usermod -l smith -e 2022-12-31 admin2
    +
    +$ sudo chage -l smith
    +Last password change     : Nov 27, 2022
    +Password expires     : never
    +Password inactive     : never
    +Account expires      : Dec 31, 2022
    +Minimum number of days between password change  : 0
    +Maximum number of days between password change  : 99999
    +Number of days of warning before password expires : 7
    +

    admin1设置密码hello,然后指定新的主目录并把旧目录移动过去。

    sudo usermod -d /home/admin_new -m admin1
    +echo "admin1:hello" | sudo chpasswd 
    +

    显示smith用户UID、GID、显示用户名、显示用户所属组ID

    $ id -u smith
     2002
     
    -$ id -g smith
    +$ id -g smith
     0
     
    -$ id -un smith
    +$ id -un smith
     smith
     
    -$ id -gn smith
    +$ id -gn smith
     root
    -

    锁定smith用两种方法

    sudo passwd -l smith
    -sudo usermod -L smith
    -

    指定admin3的密码最短使用日期为5天,最常使用日期为10天,提前2天提示修改密码。

    $ sudo chage -M 10 -m 5 -W 2 admin3
    -
    -$ sudo chage -l admin3
    -Last password change     : Nov 27, 2022
    -Password expires     : Dec 07, 2022
    -Password inactive     : never
    -Account expires      : never
    -Minimum number of days between password change  : 5
    -Maximum number of days between password change  : 10
    -Number of days of warning before password expires : 2
    -

    创建系统组newadm,指定GID为66

    sudo groupadd -r -g 66 newadm
    -

    修改newadm组名为newgrp 修改GID为67

    sudo groupmod -n newgrp -g 67 newadm
    -

    将用户admin1添加进组newgrp,然后删除组newgrp

    sudo usermod -g newgrp admin1
    -sudo groupdel -f newgrp
    -

    设置smith用户的详细描述,然后用finger查看。

    $ chfn smith
    -
    -$ finger smith
    -Login: smith             Name:
    -Directory: /home/admin2              Shell: /bin/bash
    -Never logged in.
    -No Mail.
    -No Plan.
    -

    删除用户admin1,并删除其主目录。

    sudo userdel -r admin1
    -sudo userdel -r admin2
    -

    7.权限管理

    执行命令ls -ihl,可以得到下面的输出结果(Rocky 9)。

    67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 file
    -67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile1
    -67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile2
    -67274681 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile1 -> file
    -67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov  1 11:20 symlinkfile1-1 -> symlinkfile1
    -67274682 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile2 -> file
    -33555262 drwxr-xr-x. 2 vagrant wheel  6 Nov  1 11:30 typelink
    -

    67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11:14 file为例:

    • 67274680: inode 索引节点编号。
    • -rw-r--r--:文件类型及权限
    • -:文件类型,例子中出现了三种,-ld
      • -:普通文件
      • d:目录
      • l:符号链接文件(link)
      • b:块设备(block)
      • c:字符设备(character)
      • p:管道文件(pipe)
      • s:套接字文件(socket)
    • rw-r--r--:文件权限,从左到右依次为:(用户的最终权限,是从左向右匹配,一旦匹配则权限立即生效,不再向右继续匹配)
      • rw-:文件属主权限(u),例子中是vagrant
      • r--:文件属组的权限(g),例子中是wheel
      • r--:其他组的权限(o)。
    • .:这个点表示文件带有SELinux的安全上下文(SELinux Contexts)。关闭SELinux,新创建的文件就不会再有这个点了。但是,以前创建的文件本来有这个点的还会显示这个点(虽然SELinux不起作用了)。
    • 3:硬链接数,例子中filehardlinkfile1hardlinkfile2之间是硬链接,所以这三个文件的硬链接数都是3
    • vagrant:文件属主owner
    • wheel:文件属组group
    • 31:文件或目录的大小
    • Nov 1 11:14:文件或目录的创建日期和时间
    • file:文件或目录名称

    下面是命令ls -ihl在openSUSE和Ubuntu上的显示结果。

    $ ls -ihl
    -233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 file
    -233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 hardlinkfile1
    -233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 hardlinkfile2
    -233648 lrwxrwxrwx 1 vagrant wheel  4 Nov  1 15:52 symlinkfile1 -> file
    -233650 lrwxrwxrwx 1 vagrant wheel 12 Nov  1 15:52 symlinkfile1-1 -> symlinkfile1
    -233649 lrwxrwxrwx 1 vagrant wheel  4 Nov  1 15:52 symlinkfile2 -> file
    -233646 drwxr-xr-x 1 vagrant wheel  0 Nov  1 15:51 typelink
    -

    7.1.修改属主chown

    chown命令修改文件属主(所有者,owner)。

    修改文件属主为root。

    $ ll f1.txt
    --rw-r--r--. 1 vagrant wheel 41 Nov 14 22:23 f1.txt
    -
    -$ sudo chown root f1.txt
    -
    -$ ll f1.txt
    --rw-r--r--. 1 root wheel 41 Nov 14 22:23 f1.txt
    -

    修改文件的属组为bin。

    $ sudo chown :bin f1.txt
    -
    -$ ll f1.txt
    --rw-r--r--. 1 root bin 41 Nov 14 22:23 f1.txt
    -

    同时修改文件的属主和属组。

    $ sudo chown vagrant.wheel f1.txt
    -
    -$ ll f1.txt
    --rw-r--r--. 1 vagrant wheel 41 Nov 14 22:23 f1.txt
    -

    参照某文件修改另一文件的属性。

    $ ll file.py
    --rw-r--r--. 1 vagrant wheel  56 Nov 13 22:50 file.py
    -
    -$ ll user.txt
    --rw-r--r--. 1 root bin 21 Nov 27 23:59 user.txt
    -
    -$ sudo chown root.bin user.txt
    -
    -$ sudo chown --reference=user.txt file.py
    -
    -$ ll file.py
    --rw-r--r--. 1 root bin 56 Nov 13 22:50 file.py
    -

    递归修改所有子目录及文件的属主和属组。

    sudo chown -R vagrant.wheel ~
    -

    7.2.修改属组chgrp

    修改目录的属组。

    sudo chgrp bin ~~
    -

    修改目录及子目录及文件的属组。

    sudo chgrp -R bin ~~
    -

    7.3.文件和目录权限

    文件:

    • r:可以读取该文件内容,比如通过cat命令。
    • w:可以修改该文件内容,可以只有w而没有r
    • x:可以把该文件提请内核启动为一个进程,即可以执行该文件(该文件的内容必须是可以执行)。

    目录:(对目录而言,通常需要给rx权限)(从目录角度看,目录内文件列表等于目录节点的内容)

    • r:能看文件列表,但不能访问所含文件的内容及其属性信息,包括inode号。
    • w:能在该目录内创建和删除文件,不由目录内文件本身的权限决定。
    • x:能cd进目录,能通过ls -l filestat file查看该目录中制定文件的元数据。
    • X:表示只有当该文件是个子目录或者该文件已经被设定过为可执行。

    • 有只读权限的用户不能用cd进入该目录,还必须有执行权限才能进入。

    • 有执行权限的用户只有在知道文件名,并拥有读权利的情况下才可以访问目录下的文件。
    • 必须有读和执行权限才可以ls列出目录清单,或使用cd命令进入目录。
    • 有目录的写权限,可以创建、删除或修改目录下的任何文件或子目录,即使使该文件或子目录属于其他用户也是如此。

    常用权限例子:

    -rw------- (600) 只有所有者才有读和写的权限
    --rw-r--r-- (644) 只有所有者才有读和写的权限,组和其他人只有读的权限
    --rwx------ (700) 只有所有者才有读,写,执行的权限
    --rwxr-xr-x (755) 只有所有者才有读,写,执行的权限,组和其他人只有读和执行的权限
    --rwx--x--x (711) 只有所有者才有读,写,执行的权限,组和其他人只有执行的权限
    --rw-rw-rw- (666) 每个人都有读写的权限
    --rwxrwxrwx (777) 每个人都有读写和执行的权限
    -

    7.4.权限修改chmod

    命令格式:

    chmod [-cfvR] [--help] [--version] mode file
    +

    锁定smith用两种方法

    sudo passwd -l smith
    +sudo usermod -L smith
    +

    指定admin3的密码最短使用日期为5天,最常使用日期为10天,提前2天提示修改密码。

    $ sudo chage -M 10 -m 5 -W 2 admin3
    +
    +$ sudo chage -l admin3
    +Last password change     : Nov 27, 2022
    +Password expires     : Dec 07, 2022
    +Password inactive     : never
    +Account expires      : never
    +Minimum number of days between password change  : 5
    +Maximum number of days between password change  : 10
    +Number of days of warning before password expires : 2
    +

    创建系统组newadm,指定GID为66

    sudo groupadd -r -g 66 newadm
    +

    修改newadm组名为newgrp 修改GID为67

    sudo groupmod -n newgrp -g 67 newadm
    +

    将用户admin1添加进组newgrp,然后删除组newgrp

    sudo usermod -g newgrp admin1
    +sudo groupdel -f newgrp
    +

    设置smith用户的详细描述,然后用finger查看。

    $ chfn smith
    +
    +$ finger smith
    +Login: smith             Name:
    +Directory: /home/admin2              Shell: /bin/bash
    +Never logged in.
    +No Mail.
    +No Plan.
    +

    删除用户admin1,并删除其主目录。

    sudo userdel -r admin1
    +sudo userdel -r admin2
    +

    7.权限管理

    执行命令ls -ihl,可以得到下面的输出结果(Rocky 9)。

    67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 file
    +67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile1
    +67274680 -rw-r--r--. 3 vagrant wheel 31 Nov  1 11:14 hardlinkfile2
    +67274681 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile1 -> file
    +67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov  1 11:20 symlinkfile1-1 -> symlinkfile1
    +67274682 lrwxrwxrwx. 1 vagrant wheel  4 Nov  1 10:43 symlinkfile2 -> file
    +33555262 drwxr-xr-x. 2 vagrant wheel  6 Nov  1 11:30 typelink
    +

    67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11:14 file为例:

    • 67274680: inode 索引节点编号。
    • -rw-r--r--:文件类型及权限
    • -:文件类型,例子中出现了三种,-ld
      • -:普通文件
      • d:目录
      • l:符号链接文件(link)
      • b:块设备(block)
      • c:字符设备(character)
      • p:管道文件(pipe)
      • s:套接字文件(socket)
    • rw-r--r--:文件权限,从左到右依次为:(用户的最终权限,是从左向右匹配,一旦匹配则权限立即生效,不再向右继续匹配)
      • rw-:文件属主权限(u),例子中是vagrant
      • r--:文件属组的权限(g),例子中是wheel
      • r--:其他组的权限(o)。
    • .:这个点表示文件带有SELinux的安全上下文(SELinux Contexts)。关闭SELinux,新创建的文件就不会再有这个点了。但是,以前创建的文件本来有这个点的还会显示这个点(虽然SELinux不起作用了)。
    • 3:硬链接数,例子中filehardlinkfile1hardlinkfile2之间是硬链接,所以这三个文件的硬链接数都是3
    • vagrant:文件属主owner
    • wheel:文件属组group
    • 31:文件或目录的大小
    • Nov 1 11:14:文件或目录的创建日期和时间
    • file:文件或目录名称

    下面是命令ls -ihl在openSUSE和Ubuntu上的显示结果。

    $ ls -ihl
    +233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 file
    +233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 hardlinkfile1
    +233647 -rw-r--r-- 3 vagrant wheel 31 Nov  1 15:52 hardlinkfile2
    +233648 lrwxrwxrwx 1 vagrant wheel  4 Nov  1 15:52 symlinkfile1 -> file
    +233650 lrwxrwxrwx 1 vagrant wheel 12 Nov  1 15:52 symlinkfile1-1 -> symlinkfile1
    +233649 lrwxrwxrwx 1 vagrant wheel  4 Nov  1 15:52 symlinkfile2 -> file
    +233646 drwxr-xr-x 1 vagrant wheel  0 Nov  1 15:51 typelink
    +

    7.1.修改属主chown

    chown命令修改文件属主(所有者,owner)。

    修改文件属主为root。

    $ ll f1.txt
    +-rw-r--r--. 1 vagrant wheel 41 Nov 14 22:23 f1.txt
    +
    +$ sudo chown root f1.txt
    +
    +$ ll f1.txt
    +-rw-r--r--. 1 root wheel 41 Nov 14 22:23 f1.txt
    +

    修改文件的属组为bin。

    $ sudo chown :bin f1.txt
    +
    +$ ll f1.txt
    +-rw-r--r--. 1 root bin 41 Nov 14 22:23 f1.txt
    +

    同时修改文件的属主和属组。

    $ sudo chown vagrant.wheel f1.txt
    +
    +$ ll f1.txt
    +-rw-r--r--. 1 vagrant wheel 41 Nov 14 22:23 f1.txt
    +

    参照某文件修改另一文件的属性。

    $ ll file.py
    +-rw-r--r--. 1 vagrant wheel  56 Nov 13 22:50 file.py
    +
    +$ ll user.txt
    +-rw-r--r--. 1 root bin 21 Nov 27 23:59 user.txt
    +
    +$ sudo chown root.bin user.txt
    +
    +$ sudo chown --reference=user.txt file.py
    +
    +$ ll file.py
    +-rw-r--r--. 1 root bin 56 Nov 13 22:50 file.py
    +

    递归修改所有子目录及文件的属主和属组。

    sudo chown -R vagrant.wheel ~
    +

    7.2.修改属组chgrp

    修改目录的属组。

    sudo chgrp bin ~~
    +

    修改目录及子目录及文件的属组。

    sudo chgrp -R bin ~~
    +

    7.3.文件和目录权限

    文件:

    • r:可以读取该文件内容,比如通过cat命令。
    • w:可以修改该文件内容,可以只有w而没有r
    • x:可以把该文件提请内核启动为一个进程,即可以执行该文件(该文件的内容必须是可以执行)。

    目录:(对目录而言,通常需要给rx权限)(从目录角度看,目录内文件列表等于目录节点的内容)

    • r:能看文件列表,但不能访问所含文件的内容及其属性信息,包括inode号。
    • w:能在该目录内创建和删除文件,不由目录内文件本身的权限决定。
    • x:能cd进目录,能通过ls -l filestat file查看该目录中制定文件的元数据。
    • X:表示只有当该文件是个子目录或者该文件已经被设定过为可执行。

    • 有只读权限的用户不能用cd进入该目录,还必须有执行权限才能进入。

    • 有执行权限的用户只有在知道文件名,并拥有读权利的情况下才可以访问目录下的文件。
    • 必须有读和执行权限才可以ls列出目录清单,或使用cd命令进入目录。
    • 有目录的写权限,可以创建、删除或修改目录下的任何文件或子目录,即使使该文件或子目录属于其他用户也是如此。

    常用权限例子:

    -rw------- (600) 只有所有者才有读和写的权限
    +-rw-r--r-- (644) 只有所有者才有读和写的权限,组和其他人只有读的权限
    +-rwx------ (700) 只有所有者才有读,写,执行的权限
    +-rwxr-xr-x (755) 只有所有者才有读,写,执行的权限,组和其他人只有读和执行的权限
    +-rwx--x--x (711) 只有所有者才有读,写,执行的权限,组和其他人只有执行的权限
    +-rw-rw-rw- (666) 每个人都有读写的权限
    +-rwxrwxrwx (777) 每个人都有读写和执行的权限
    +

    7.4.权限修改chmod

    命令格式:

    chmod [-cfvR] [--help] [--version] mode file
     

    mode字串格式为:

    [ugoa][+-=][rwxXst]
    -

    who:

    • u文件所有者
    • g文件所有者所在组
    • o其他用户
    • a所有用户,相当于ugo

    operator:

    • +为指定的用户类型增加权限
    • -去除指定用户类型的权限
    • =设置指定用户权限的设置,即将用户类型的所有权限重新设置

    permission:

    • r设置为可读权限
    • w设置为可写权限
    • x设置为可执行权限
    • X特殊执行权限,只有当文件为目录文件,或者其他类型的用户有可执行权限时,才将文件权限设置可执行
    • s当文件被执行时,根据who参数指定的用户类型设置文件的setuid或者setgid权限
    • t设置粘贴位,只有超级用户可以设置该位,只有文件所有者u可以使用该位。

    示例:

    将文件file1.txt设为所有人皆可读取。

    chmod ugo+r file1.txt
    -

    将文件file1.txt设为所有人皆可读取。

    chmod a+r file1.txt
    -

    将文件file1.txtfile2.txt设为该文件属主和属组都可写入,但其他用户不可写入。

    chmod ug+w,o-w file1.txt file2.txt
    -

    ex1.py文件属主增加可执行权限。

    chmod u+x ex1.py
    -

    将目前目录下的所有文件与子目录皆设为任何人可读取。

    chmod -R a+r *
    -

    file的所有用户增加读权限

    chmod a+r file
    -

    删除file的所有用户的执行权限

    chmod a-x file
    -

    file的所有用户增加读写权限

    chmod a+rw file
    -

    file的所有用户增加读写执行权限

    chmod +rwx file
    -

    file的属主设置读写权限,清空属组和其他用户对file的所有权限(空格代表无权限)

    chmod u=rw,go= file
    -

    对目录docs和其子目录中的所有文件给属主增加读权限,而对属组和其他用户删除读权限

    chmod -R u+r,go-r docs
    -

    file的属主和属组设置读写权限, 为其他用户设置读权限

    chmod 664 file
    -

    file的属主设置读写执行权限,相当于u=rwx(4+2+1),设置属组读和执行权限,相当于go=rx(4+1 & 4+1)。0没有特殊模式

    chmod 0755 file
    -

    4设置了设置用户ID位,剩下的相当于u=rwx(4+2+1)和go=rx(4+1 & 4+1)。

    chmod 4755 file
    -

    删除可执行权限对path/以及其所有的目录(不包括文件)的所有用户,使用-type f匹配文件

    find path/ -type d -exec chmod a-x {} \;
    -

    允许所有用户浏览或通过目录path/

    find path/ -type d -exec chmod a+x {} \;
    -

    7.5.默认权限umask

    umask的值,定义了所有新建的文件和目录的初始权限的。

    查看当前权限掩码:

    $ umask
    +

    who:

    • u文件所有者
    • g文件所有者所在组
    • o其他用户
    • a所有用户,相当于ugo

    operator:

    • +为指定的用户类型增加权限
    • -去除指定用户类型的权限
    • =设置指定用户权限的设置,即将用户类型的所有权限重新设置

    permission:

    • r设置为可读权限
    • w设置为可写权限
    • x设置为可执行权限
    • X特殊执行权限,只有当文件为目录文件,或者其他类型的用户有可执行权限时,才将文件权限设置可执行
    • s当文件被执行时,根据who参数指定的用户类型设置文件的setuid或者setgid权限
    • t设置粘贴位,只有超级用户可以设置该位,只有文件所有者u可以使用该位。

    示例:

    将文件file1.txt设为所有人皆可读取。

    chmod ugo+r file1.txt
    +

    将文件file1.txt设为所有人皆可读取。

    chmod a+r file1.txt
    +

    将文件file1.txtfile2.txt设为该文件属主和属组都可写入,但其他用户不可写入。

    chmod ug+w,o-w file1.txt file2.txt
    +

    ex1.py文件属主增加可执行权限。

    chmod u+x ex1.py
    +

    将目前目录下的所有文件与子目录皆设为任何人可读取。

    chmod -R a+r *
    +

    file的所有用户增加读权限

    chmod a+r file
    +

    删除file的所有用户的执行权限

    chmod a-x file
    +

    file的所有用户增加读写权限

    chmod a+rw file
    +

    file的所有用户增加读写执行权限

    chmod +rwx file
    +

    file的属主设置读写权限,清空属组和其他用户对file的所有权限(空格代表无权限)

    chmod u=rw,go= file
    +

    对目录docs和其子目录中的所有文件给属主增加读权限,而对属组和其他用户删除读权限

    chmod -R u+r,go-r docs
    +

    file的属主和属组设置读写权限, 为其他用户设置读权限

    chmod 664 file
    +

    file的属主设置读写执行权限,相当于u=rwx(4+2+1),设置属组读和执行权限,相当于go=rx(4+1 & 4+1)。0没有特殊模式

    chmod 0755 file
    +

    4设置了设置用户ID位,剩下的相当于u=rwx(4+2+1)和go=rx(4+1 & 4+1)。

    chmod 4755 file
    +

    删除可执行权限对path/以及其所有的目录(不包括文件)的所有用户,使用-type f匹配文件

    find path/ -type d -exec chmod a-x {} \;
    +

    允许所有用户浏览或通过目录path/

    find path/ -type d -exec chmod a+x {} \;
    +

    7.5.默认权限umask

    umask的值,定义了所有新建的文件和目录的初始权限的。

    查看当前权限掩码:

    $ umask
     0022
    -

    在不考虑umask的情况下,文件的默认权限是666(rw-rw-rw-),目录的默认权限是777(rwxrwxrwx)。

    umask的值为0022的情况下,文件的默认权限是644(rw-r--r--),目录的默认权限是755(rwxr-xr-x)。

    计算方法:

     Files: 
    -  (Default) 6 6 6
    -  (umask)   0 2 2
    -  ----------------
    -  (Result)  6 4 4
    -
    -  Directories: 
    -  (Default) 7 7 7
    -  (umask)   0 2 2
    -  ----------------
    -    (Result)  7 5 5
    -

    如果umask的值为0077的情况下,文件的默认权限是600(rw-------),目录的默认权限是700(rwx------)。

    计算方法:

     Files: 
    -  (Default) 6 6 6
    -  (umask)   0 7 7
    -  ----------------
    -  (Result)  6 0 0
    -
    -  Directories: 
    -  (Default) 7 7 7
    -  (umask)   0 7 7
    -  ----------------
    -    (Result)  7 0 0
    -

    举例:

    $ umask 022
    -$ touch file2
    -$ ll file2
    --rw-r--r--. 1 vagrant wheel 0 Nov 28 23:13 file2
    -
    -$ umask 077
    -$ touch file1
    -$ ll file1
    --rw-------. 1 vagrant wheel 0 Nov 28 23:12 file1
    -
    $ umask 022
    -$ mkdir ./tmp1
    -$ umask 077
    -$ mkdir ./tmp2
    -
    -$ ls -dl tmp*
    -drwxr-xr-x. 1 vagrant wheel 0 Nov 28 23:14 tmp1
    -drwx------. 1 vagrant wheel 0 Nov 28 23:14 tmp2
    -

    7.6.特殊权限

    除了三种常见的权限rwx,还有三种特殊权限:SUID,SGID,Sticky。

    SUID:属主s权限,称为Set UID

    • 前提:进程有属主和属组,文件有属主和属组
    • 任何可执行程序文件能不能启动为进程,取决于发起者对程序文件是否拥有执行权限。
    • 启动为进程之后,其进程的属主为发起者。
    • 进程访问文件是的权限,取决于进程的发起者。

    • 只对二进制可执行程序文件有效。当执行该文件时,发起者将自动具有该文件所有者的权限。

    • 对目录无效。
    $ ll file1
    --rw-------. 1 vagrant wheel   0 Nov 28 23:12 file1
    -
    -$ sudo chmod u+s file1
    -
    -$ ll file1
    --rwS------. 1 vagrant wheel 0 Nov 28 23:12 file1
    -

    如果属主的x位上是-,则在属主的x位上标记大写S,否则标记小写s。如下:

    $ chmod 777 file1
    -
    -$ ll file1
    --rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23:12 file1
    -
    -$ sudo chmod u+s file1
    -
    -$ ll file1
    --rwsrwxrwx. 1 vagrant wheel 0 Nov 28 23:12 file1
    -

    下面2组命令实现同样效果。

    sudo chmod 4xxx file1
    -
    -chmod 777 file1
    -sudo chmod u+s file1
    -

    取消SUID。

    sudo chmod u-s file1
    -

    SGID:属组s权限,称为Set GID

    • 如果作用于二进制可执行文件上,当执行该文件为进程之后,发起者将自动具有该文件所属组的权限,进程的属组为发起者的属组。
    • 如果作用于目录上,则该目录下新建立的目录和文件都自动从此目录继承。
    $ sudo chmod g+s file2
    -
    -$ ll file2
    --rw-r-Sr--. 1 vagrant wheel 0 Nov 28 23:13 file2
    -

    如果属组的x位上是-,则在属组的x位上标记大写S,否则标记小写s。如下:

    $ chmod 777 file2
    -
    -$ ll file2
    --rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23:13 file2
    -
    -$ sudo chmod g+s file2
    -
    -$ ll file2
    --rwxrwsrwx. 1 vagrant wheel 0 Nov 28 23:13 file2
    -

    下面2组命令实现同样效果。

    sudo chmod 2xxx file2
    -
    -chmod 777 file2
    -sudo chmod g+s file2
    -

    取消SGID。

    sudo chmod g-s file2
    -

    对于目录,下面演示可以看到目录下的文件和子目录的继承性。

    $ ll -d data
    -drwxr-xr-x. 1 vagrant bin 0 Nov 28 20:55 data
    -
    -$ sudo chmod g+s .~
    -
    -$ ll -d data
    -drwxr-sr-x. 1 vagrant bin 0 Nov 28 20:55 data
    -
    -$ cd data
    -$ touch file2
    -$ ll file2
    --rw-r--r--. 1 vagrant bin 0 Nov 29 21:10 file2
    -
    -$ mkdir tmp3
    -$ ll -d tmp3
    -drwxr-sr-x. 1 vagrant bin 0 Nov 29 21:10 tmp3
    -

    Sticky Bit:简称为SBIT权限

    • 只针对目录有效。它表示只能让其属主以及root可以删除、重命名、移动该目录下的文件。
    • Sticky设置在文件上无意义。

    如果其他的x位上是-,则在其他的x位上标记大写T,否则标记小写t

    $ ll -d .~
    -drwxr-sr-x. 1 vagrant bin 18 Nov 29 21:10 .~
    -
    -$ sudo chmod o+t .~
    -
    -$ ll -d .~
    -drwxr-sr-t. 1 vagrant bin 18 Nov 29 21:10 .~
    -
    -$ cd data
    -$ touch file1
    -$ mkdir tmp1
    -
    -$ ll file1
    --rw-r--r--. 1 vagrant bin 0 Nov 29 21:37 file1
    -$ ll -d tmp1
    -drwxr-sr-x. 1 vagrant bin 0 Nov 29 21:37 tmp1
    -

    特殊权限设置数字法:

    设置SUID

                  User    Group   Others
    -              r w s   r w s   r w x
    -              r w S
    -    BIN 100   1 1 1   1 1 1   1 1 1
    -              1 1 0
    -    OCT   4       7       7       7
    -                  6
    -

    设置SGID

                  User    Group   Others
    -              r w x   r w s   r w x
    -              r w S
    -    BIN 010   1 1 1   1 1 1   1 1 1
    -                      1 1 0
    -    OCT   2       7       7       7
    -                          6
    -

    设置Sticky Bit - SBIT

                  User    Group   Others
    -              r w x   r w x   r w t
    -                      r w T
    -    BIN 001   1 1 1   1 1 1   1 1 1
    -                              1 1 0
    -    OCT   1       7       7       7
    -                                  6
    -

    7.7.设定文件特殊属性chattr

    命令格式:chattr [ -RVf ] [ -v version ] [ mode ] files...

    其中mode的字串格式:{+|-|=}[aAcCdDeijsStTu]

    属性i

    • 如果对文件设置i属性,那么不允许对文件进行删除、改名,也不能添加和修改数据;
    • 如果对目录设置i属性,那么只能修改目录下文件中的数据,但不允许建立和删除文件;

    在openSUSE下执行,分区文件类型是btrfs格式。

    $ touch filetest
    -$ lsattr filetest
    ----------------------- filetest
    -
    -$ chattr +i filetest
    -chattr: Operation not permitted while setting flags on filetest
    -$ sudo chattr +i filetest
    -
    -$ lsattr filetest
    -----i----------------- filetest
    -
    -$ rm filetest
    -rm: cannot remove 'filetest': Operation not permitted
    -$ sudo rm filetest
    -rm: cannot remove 'filetest': Operation not permitted
    -
    -$ echo "test" >> filetest
    --bash: filetest: Operation not permitted
    -$ sudo echo "test" >> filetest
    --bash: filetest: Operation not permitted
    -
    -$ sudo chattr -i filetest
    -

    属性a

    • 如果对文件设置a属性,那么只能在文件中増加数据,但是不能删除和修改数据;
    • 如果对目录设置a属性,那么只允许在目录中建立和修改文件,但是不允许删除文件;

    在openSUSE下执行,分区文件类型是btrfs格式。

    lsattr filetest
    ----------------------- filetest
    -$ chattr +a filetest
    -chattr: Operation not permitted while setting flags on filetest
    -$ sudo chattr +a filetest
    -
    -$ echo "test" >> filetest
    -
    -$ rm filetest
    -rm: cannot remove 'filetest': Operation not permitted
    -$ sudo rm filetest
    -rm: cannot remove 'filetest': Operation not permitted
    -
    -$ sudo chattr -a filetest
    -

    属性u

    • 设置此属性的文件或目录,在删除时,其内容会被保存,以保证后期能够恢复,常用来防止意外删除文件或目录。

    在Ubuntu下执行,分区文件类型是ext4格式。

    $ touch filetest
    -$ sudo chattr +u filetest
    -
    -$ lsattr filetest
    --u------------e------- filetest
    -
    -$ rm filetest
    -

    属性s

    • u相反,删除文件或目录时,会被彻底删除(直接从硬盘上删除,然后用0填充所占用的区域),不可恢复。

    提示:

    命令chattrlsattr的可操作属性依赖于文件所处分区的文件系统类型,例如,ext4和xfs的结果会有不同。

    历史:命令chattr(用于操作属性)和lsattr(用于列出属性)最初专用于第二个扩展文件系统系列(ext2、ext3、ext4),并且作为e2fsprogs包的一部分提供。然而,此功能已全部或部分扩展到许多其他系统,包括 XFS、ReiserFS、JFS 和 OCFS2。 btrfs 文件系统包括属性功能,包括C标志,由于与CoW相关的性能较慢,它关闭了btrfs的内置写时复制 (CoW) 功能。

    8.访问控制列表ACL

    8.1.ACL

    ACL的全称是Access Control List。

    传统的POSIX权限概念使用三种用户类型来分配文件系统中的权限:所有者Owning Owner,所有者组Owning Group和其他用户Other Users。可以为每个用户类型设置三个权限位,赋予读(r),写(w)和执行(x)的权限。

    • 所有者Owning Owner权限(属主权限)
    • 属组Owning Group权限
    • 其他(经过身份验证的)用户Other Users的权限

    传统的三种权限适用于大多数实际案例。但是,对于更复杂的场景或更高级的应用程序,系统管理员必须使用许多技巧来规避传统权限的限制。

    访问控制列表ACL提供了对传统文件权限概念的扩展。它们允许我们为单个用户或组分配权限,即使这些用户或组与原始所有者或属组不对应。

    ACL是Linux内核的一项功能,支持Ext⅔/4,XFS和BtrFS文件系统以及其他文件系统。

    使用ACL,我们可以创建复杂的方案,而无需在应用程序级别上去实现复杂的权限模型。在使用提供Samba文件和打印服务的Linux服务器替换Windows服务器的情况下,ACL的优势非常明显。由于Samba支持ACL,因此可以在Linux服务器和Windows中配置用户权限。

    通过ACL来允许对所有者用户之外的单个用户进行文件写权限是一种简单的方案。使用传统方法,我们必须创建一个新组,使两个用户成为该组的成员,将该文件的所有组更改为新组,然后授予该组文件的写权限。创建组并使两个用户成为该组的成员则需要利用root权限来实现。

    使用ACL,我们可以通过使所有者和指定用户对文件具有写权限来实现相同的结果。

    此方法的另一个优点是系统管理员无需参与创建组。用户可以自己决定授予谁访问其文件的权限。

    提示:

    使用ACL时ls的输出结果会发生变化。添加一个加号+ 来说明已为此文件定义ACL,且定义ACL后,所显示的属组权限是ACL掩码的值,而不再是原来属组的权限。

    8.2.ACL的基本类型

    • Minimal ACLs(最小ACL)(实际用途:与POSIX权限相同)
    • 与文件模式权限位等效的ACL称为最小ACL
    • 分三种类型的ACL条目,这些对应于文件和目录的传统权限位
      • Owning User 所有者
      • Owning Group 所有者组
      • Others 其他组
    • Extended ACLs(扩展ACL)
    • 具有多于上述三个ACL条目的ACL称为扩展ACL
    • 扩展ACL还包含掩码条目,可以包含任意数量的指定用户和指定组条目

    8.3.ACL术语

    • 用户类(User classes)。 传统的POSIX权限概念使用三种用户类来分配文件系统中的权限:所有者Owning Owner,所有者组Owning Group和其他用户Other Users。可以为每个用户类型设置三个权限位,赋予读(r),写(w)和执行(x)的权限。
    • Owner class 所有者类
    • Group class 组类
    • Other class 其他类
    • ACL访问权限(Access ACL):确定各种文件系统对象(文件和目录)的用户和组的访问权限。
    • 默认ACL(Default ACL):只能应用于目录。 它们确定文件系统对象在创建时从其父目录继承的权限。
    • ACL条目(ACL entry):
    • 每个ACL由一组ACL条目组成。
    • ACL条目包含类型(type),条目引用的用户或组的限定符(qualifier),以及一组权限(permissions)。
    • 对于某些条目类型,未定义组或用户的限定符。

    The mapping of minimal ACLs

    8.4.ACL权限分类

    • Named user 指定用户: Lets you assign permissions to individual users. 允许我们为指定用户分配权限。
    • Named group 指定组: Lets you assign permissions to individual groups. 允许我们为制定组分配权限。
    • Mask 掩码: Lets you limit the permissions granted to named users or groups. 允许我们限制给予指定用户或指定组的权限。

    所以可能的ACL类型

    Type Text Form
    owner user::rwx
    named user user:name:rwx
    owning group group::rwx
    named group group:name:rwx
    mask mask::rwx
    other other::rwx

    与POSIX.1权限模型不同,组类group class可以包含具有不同权限集的ACL条目,因此单独的组类权限不再足以表示它包含的所有ACL条目的所有详细权限。

    因此,组类型权限的含义被重新定义。在新语义下,组类型权限表示组类中的任何条目将授予的权限的**上限**(upper bound)。 此上限属性可确保在使用ACL控制后,应用程序不会突然或者意外地授予额外的权限。

    在最小ACL中,组类权限与所有者组权限相同。在扩展ACL中,组类可以包含其他用户或组的条目。这会导致一个问题:这些附加条目中的一些可能拥有未包含在所有者组条目(owning group entry)中的权限,因此所有者组条目权限可能与组类权限(group class)不同。

    通过掩码(mask entry)解决了这个问题。

    • 使用最小ACL,组类权限映射到所有者组条目权限。With minimal ACLs, the group class permissions map to the owning group entry permissions.
    • 使用扩展ACL时,组类权限映射到掩码条目权限,而所有者组条目仍定义拥有组权限。With extended ACLs, the group class permissions map to the mask entry permissions, whereas the owning group entry still defines the owning group permissions.

    8.5.ACL操作命令

    设定ACL权限:setfacl

    • Syntax: setfacl [OPTIONS] [ACL-ENTRIES] <file>
    • Option Description
    • -m: Add or modify an ACL entry
    • -x: Remove an ACL entry
    • -d: Set a default ACL
    • -b: Remove all extended ACL entries
    • -M: restore ACLs that have been written to a file

    注意:--set选项会把原有的ACL项都删除,用新的替代,所以一定要包含UGO的设置,不能像-m医院只添加ACL。

    setfacl --set u::rw,u:vagrant:rw,g::r,o::- file1
    -

    读取ACL权限:getfacl

    • Syntax: getfacl [OPTIONS] <file>
    • Option Description
    • -a: Display the file access control list
    • -d: Display the default access control list
    • -R: List the ACLs of all files and directories recursively

    8.6.ACL实例解析

    8.6.1.实例描述

    • 项目目录~/project1
    • 项目经理pm1对这个目录拥有访问和修改权限
    • 项目成员tm1可以访问和修改这个目录
    • 非项目成员tm2不能访问~/project1目录。
    • 项目目录~/project1的权限规划
    • 项目经理pm1是这个目录的属主,权限为rwx
    • 项目经理pm1属于project1
    • 项目成员tm1pm1在同一个project1组,权限是rw
    • 其他人的权限设定为0
    • 项目临时成员tm2的权限需求
    • 能访问project1目录,但只能具有rx权限

    解决方法

    • 当出现这种情况时,普通权限中的三种身份(owner,group,others)就不能解决这个问题,而ACL权限可以。 在使用ACL权限给用户tm2陚予权限时,tm2既不是~/project1目录的属主,也不是属组,仅仅赋予用户tm2针对~/project1目录的r-x权限, 属于单独指定用户并单独分配权限,解决了用户身份不足的问题。

    拓展问题

    • ~/project1目录添加其他组project2的访问权限
    • 通过mask来调整用户tm2实际有效权限
    • 默认ACL权限
    • 递归ACL权限
    • 删除ACL权限

    8.6.2.初始化环境

    创建测试用户

    $ whoami
    +

    在不考虑umask的情况下,文件的默认权限是666(rw-rw-rw-),目录的默认权限是777(rwxrwxrwx)。

    umask的值为0022的情况下,文件的默认权限是644(rw-r--r--),目录的默认权限是755(rwxr-xr-x)。

    计算方法:

     Files: 
    +  (Default) 6 6 6
    +  (umask)   0 2 2
    +  ----------------
    +  (Result)  6 4 4
    +
    +  Directories: 
    +  (Default) 7 7 7
    +  (umask)   0 2 2
    +  ----------------
    +    (Result)  7 5 5
    +

    如果umask的值为0077的情况下,文件的默认权限是600(rw-------),目录的默认权限是700(rwx------)。

    计算方法:

     Files: 
    +  (Default) 6 6 6
    +  (umask)   0 7 7
    +  ----------------
    +  (Result)  6 0 0
    +
    +  Directories: 
    +  (Default) 7 7 7
    +  (umask)   0 7 7
    +  ----------------
    +    (Result)  7 0 0
    +

    举例:

    $ umask 022
    +$ touch file2
    +$ ll file2
    +-rw-r--r--. 1 vagrant wheel 0 Nov 28 23:13 file2
    +
    +$ umask 077
    +$ touch file1
    +$ ll file1
    +-rw-------. 1 vagrant wheel 0 Nov 28 23:12 file1
    +
    $ umask 022
    +$ mkdir ./tmp1
    +$ umask 077
    +$ mkdir ./tmp2
    +
    +$ ls -dl tmp*
    +drwxr-xr-x. 1 vagrant wheel 0 Nov 28 23:14 tmp1
    +drwx------. 1 vagrant wheel 0 Nov 28 23:14 tmp2
    +

    7.6.特殊权限

    除了三种常见的权限rwx,还有三种特殊权限:SUID,SGID,Sticky。

    SUID:属主s权限,称为Set UID

    • 前提:进程有属主和属组,文件有属主和属组
    • 任何可执行程序文件能不能启动为进程,取决于发起者对程序文件是否拥有执行权限。
    • 启动为进程之后,其进程的属主为发起者。
    • 进程访问文件是的权限,取决于进程的发起者。

    • 只对二进制可执行程序文件有效。当执行该文件时,发起者将自动具有该文件所有者的权限。

    • 对目录无效。
    $ ll file1
    +-rw-------. 1 vagrant wheel   0 Nov 28 23:12 file1
    +
    +$ sudo chmod u+s file1
    +
    +$ ll file1
    +-rwS------. 1 vagrant wheel 0 Nov 28 23:12 file1
    +

    如果属主的x位上是-,则在属主的x位上标记大写S,否则标记小写s。如下:

    $ chmod 777 file1
    +
    +$ ll file1
    +-rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23:12 file1
    +
    +$ sudo chmod u+s file1
    +
    +$ ll file1
    +-rwsrwxrwx. 1 vagrant wheel 0 Nov 28 23:12 file1
    +

    下面2组命令实现同样效果。

    sudo chmod 4xxx file1
    +
    +chmod 777 file1
    +sudo chmod u+s file1
    +

    取消SUID。

    sudo chmod u-s file1
    +

    SGID:属组s权限,称为Set GID

    • 如果作用于二进制可执行文件上,当执行该文件为进程之后,发起者将自动具有该文件所属组的权限,进程的属组为发起者的属组。
    • 如果作用于目录上,则该目录下新建立的目录和文件都自动从此目录继承。
    $ sudo chmod g+s file2
    +
    +$ ll file2
    +-rw-r-Sr--. 1 vagrant wheel 0 Nov 28 23:13 file2
    +

    如果属组的x位上是-,则在属组的x位上标记大写S,否则标记小写s。如下:

    $ chmod 777 file2
    +
    +$ ll file2
    +-rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23:13 file2
    +
    +$ sudo chmod g+s file2
    +
    +$ ll file2
    +-rwxrwsrwx. 1 vagrant wheel 0 Nov 28 23:13 file2
    +

    下面2组命令实现同样效果。

    sudo chmod 2xxx file2
    +
    +chmod 777 file2
    +sudo chmod g+s file2
    +

    取消SGID。

    sudo chmod g-s file2
    +

    对于目录,下面演示可以看到目录下的文件和子目录的继承性。

    $ ll -d data
    +drwxr-xr-x. 1 vagrant bin 0 Nov 28 20:55 data
    +
    +$ sudo chmod g+s .~
    +
    +$ ll -d data
    +drwxr-sr-x. 1 vagrant bin 0 Nov 28 20:55 data
    +
    +$ cd data
    +$ touch file2
    +$ ll file2
    +-rw-r--r--. 1 vagrant bin 0 Nov 29 21:10 file2
    +
    +$ mkdir tmp3
    +$ ll -d tmp3
    +drwxr-sr-x. 1 vagrant bin 0 Nov 29 21:10 tmp3
    +

    Sticky Bit:简称为SBIT权限

    • 只针对目录有效。它表示只能让其属主以及root可以删除、重命名、移动该目录下的文件。
    • Sticky设置在文件上无意义。

    如果其他的x位上是-,则在其他的x位上标记大写T,否则标记小写t

    $ ll -d .~
    +drwxr-sr-x. 1 vagrant bin 18 Nov 29 21:10 .~
    +
    +$ sudo chmod o+t .~
    +
    +$ ll -d .~
    +drwxr-sr-t. 1 vagrant bin 18 Nov 29 21:10 .~
    +
    +$ cd data
    +$ touch file1
    +$ mkdir tmp1
    +
    +$ ll file1
    +-rw-r--r--. 1 vagrant bin 0 Nov 29 21:37 file1
    +$ ll -d tmp1
    +drwxr-sr-x. 1 vagrant bin 0 Nov 29 21:37 tmp1
    +

    特殊权限设置数字法:

    设置SUID

                  User    Group   Others
    +              r w s   r w s   r w x
    +              r w S
    +    BIN 100   1 1 1   1 1 1   1 1 1
    +              1 1 0
    +    OCT   4       7       7       7
    +                  6
    +

    设置SGID

                  User    Group   Others
    +              r w x   r w s   r w x
    +              r w S
    +    BIN 010   1 1 1   1 1 1   1 1 1
    +                      1 1 0
    +    OCT   2       7       7       7
    +                          6
    +

    设置Sticky Bit - SBIT

                  User    Group   Others
    +              r w x   r w x   r w t
    +                      r w T
    +    BIN 001   1 1 1   1 1 1   1 1 1
    +                              1 1 0
    +    OCT   1       7       7       7
    +                                  6
    +

    7.7.设定文件特殊属性chattr

    命令格式:chattr [ -RVf ] [ -v version ] [ mode ] files...

    其中mode的字串格式:{+|-|=}[aAcCdDeijsStTu]

    属性i

    • 如果对文件设置i属性,那么不允许对文件进行删除、改名,也不能添加和修改数据;
    • 如果对目录设置i属性,那么只能修改目录下文件中的数据,但不允许建立和删除文件;

    在openSUSE下执行,分区文件类型是btrfs格式。

    $ touch filetest
    +$ lsattr filetest
    +---------------------- filetest
    +
    +$ chattr +i filetest
    +chattr: Operation not permitted while setting flags on filetest
    +$ sudo chattr +i filetest
    +
    +$ lsattr filetest
    +----i----------------- filetest
    +
    +$ rm filetest
    +rm: cannot remove 'filetest': Operation not permitted
    +$ sudo rm filetest
    +rm: cannot remove 'filetest': Operation not permitted
    +
    +$ echo "test" >> filetest
    +-bash: filetest: Operation not permitted
    +$ sudo echo "test" >> filetest
    +-bash: filetest: Operation not permitted
    +
    +$ sudo chattr -i filetest
    +

    属性a

    • 如果对文件设置a属性,那么只能在文件中増加数据,但是不能删除和修改数据;
    • 如果对目录设置a属性,那么只允许在目录中建立和修改文件,但是不允许删除文件;

    在openSUSE下执行,分区文件类型是btrfs格式。

    lsattr filetest
    +---------------------- filetest
    +$ chattr +a filetest
    +chattr: Operation not permitted while setting flags on filetest
    +$ sudo chattr +a filetest
    +
    +$ echo "test" >> filetest
    +
    +$ rm filetest
    +rm: cannot remove 'filetest': Operation not permitted
    +$ sudo rm filetest
    +rm: cannot remove 'filetest': Operation not permitted
    +
    +$ sudo chattr -a filetest
    +

    属性u

    • 设置此属性的文件或目录,在删除时,其内容会被保存,以保证后期能够恢复,常用来防止意外删除文件或目录。

    在Ubuntu下执行,分区文件类型是ext4格式。

    $ touch filetest
    +$ sudo chattr +u filetest
    +
    +$ lsattr filetest
    +-u------------e------- filetest
    +
    +$ rm filetest
    +

    属性s

    • u相反,删除文件或目录时,会被彻底删除(直接从硬盘上删除,然后用0填充所占用的区域),不可恢复。

    提示:

    命令chattrlsattr的可操作属性依赖于文件所处分区的文件系统类型,例如,ext4和xfs的结果会有不同。

    历史:命令chattr(用于操作属性)和lsattr(用于列出属性)最初专用于第二个扩展文件系统系列(ext2、ext3、ext4),并且作为e2fsprogs包的一部分提供。然而,此功能已全部或部分扩展到许多其他系统,包括 XFS、ReiserFS、JFS 和 OCFS2。 btrfs 文件系统包括属性功能,包括C标志,由于与CoW相关的性能较慢,它关闭了btrfs的内置写时复制 (CoW) 功能。

    8.访问控制列表ACL

    8.1.ACL

    ACL的全称是Access Control List。

    传统的POSIX权限概念使用三种用户类型来分配文件系统中的权限:所有者Owning Owner,所有者组Owning Group和其他用户Other Users。可以为每个用户类型设置三个权限位,赋予读(r),写(w)和执行(x)的权限。

    • 所有者Owning Owner权限(属主权限)
    • 属组Owning Group权限
    • 其他(经过身份验证的)用户Other Users的权限

    传统的三种权限适用于大多数实际案例。但是,对于更复杂的场景或更高级的应用程序,系统管理员必须使用许多技巧来规避传统权限的限制。

    访问控制列表ACL提供了对传统文件权限概念的扩展。它们允许我们为单个用户或组分配权限,即使这些用户或组与原始所有者或属组不对应。

    ACL是Linux内核的一项功能,支持Ext⅔/4,XFS和BtrFS文件系统以及其他文件系统。

    使用ACL,我们可以创建复杂的方案,而无需在应用程序级别上去实现复杂的权限模型。在使用提供Samba文件和打印服务的Linux服务器替换Windows服务器的情况下,ACL的优势非常明显。由于Samba支持ACL,因此可以在Linux服务器和Windows中配置用户权限。

    通过ACL来允许对所有者用户之外的单个用户进行文件写权限是一种简单的方案。使用传统方法,我们必须创建一个新组,使两个用户成为该组的成员,将该文件的所有组更改为新组,然后授予该组文件的写权限。创建组并使两个用户成为该组的成员则需要利用root权限来实现。

    使用ACL,我们可以通过使所有者和指定用户对文件具有写权限来实现相同的结果。

    此方法的另一个优点是系统管理员无需参与创建组。用户可以自己决定授予谁访问其文件的权限。

    提示:

    使用ACL时ls的输出结果会发生变化。添加一个加号+ 来说明已为此文件定义ACL,且定义ACL后,所显示的属组权限是ACL掩码的值,而不再是原来属组的权限。

    8.2.ACL的基本类型

    • Minimal ACLs(最小ACL)(实际用途:与POSIX权限相同)
    • 与文件模式权限位等效的ACL称为最小ACL
    • 分三种类型的ACL条目,这些对应于文件和目录的传统权限位
      • Owning User 所有者
      • Owning Group 所有者组
      • Others 其他组
    • Extended ACLs(扩展ACL)
    • 具有多于上述三个ACL条目的ACL称为扩展ACL
    • 扩展ACL还包含掩码条目,可以包含任意数量的指定用户和指定组条目

    8.3.ACL术语

    • 用户类(User classes)。 传统的POSIX权限概念使用三种用户类来分配文件系统中的权限:所有者Owning Owner,所有者组Owning Group和其他用户Other Users。可以为每个用户类型设置三个权限位,赋予读(r),写(w)和执行(x)的权限。
    • Owner class 所有者类
    • Group class 组类
    • Other class 其他类
    • ACL访问权限(Access ACL):确定各种文件系统对象(文件和目录)的用户和组的访问权限。
    • 默认ACL(Default ACL):只能应用于目录。 它们确定文件系统对象在创建时从其父目录继承的权限。
    • ACL条目(ACL entry):
    • 每个ACL由一组ACL条目组成。
    • ACL条目包含类型(type),条目引用的用户或组的限定符(qualifier),以及一组权限(permissions)。
    • 对于某些条目类型,未定义组或用户的限定符。

    The mapping of minimal ACLs

    8.4.ACL权限分类

    • Named user 指定用户: Lets you assign permissions to individual users. 允许我们为指定用户分配权限。
    • Named group 指定组: Lets you assign permissions to individual groups. 允许我们为制定组分配权限。
    • Mask 掩码: Lets you limit the permissions granted to named users or groups. 允许我们限制给予指定用户或指定组的权限。

    所以可能的ACL类型

    Type Text Form
    owner user::rwx
    named user user:name:rwx
    owning group group::rwx
    named group group:name:rwx
    mask mask::rwx
    other other::rwx

    与POSIX.1权限模型不同,组类group class可以包含具有不同权限集的ACL条目,因此单独的组类权限不再足以表示它包含的所有ACL条目的所有详细权限。

    因此,组类型权限的含义被重新定义。在新语义下,组类型权限表示组类中的任何条目将授予的权限的**上限**(upper bound)。 此上限属性可确保在使用ACL控制后,应用程序不会突然或者意外地授予额外的权限。

    在最小ACL中,组类权限与所有者组权限相同。在扩展ACL中,组类可以包含其他用户或组的条目。这会导致一个问题:这些附加条目中的一些可能拥有未包含在所有者组条目(owning group entry)中的权限,因此所有者组条目权限可能与组类权限(group class)不同。

    通过掩码(mask entry)解决了这个问题。

    • 使用最小ACL,组类权限映射到所有者组条目权限。With minimal ACLs, the group class permissions map to the owning group entry permissions.
    • 使用扩展ACL时,组类权限映射到掩码条目权限,而所有者组条目仍定义拥有组权限。With extended ACLs, the group class permissions map to the mask entry permissions, whereas the owning group entry still defines the owning group permissions.

    8.5.ACL操作命令

    设定ACL权限:setfacl

    • Syntax: setfacl [OPTIONS] [ACL-ENTRIES] <file>
    • Option Description
    • -m: Add or modify an ACL entry
    • -x: Remove an ACL entry
    • -d: Set a default ACL
    • -b: Remove all extended ACL entries
    • -M: restore ACLs that have been written to a file

    注意:--set选项会把原有的ACL项都删除,用新的替代,所以一定要包含UGO的设置,不能像-m医院只添加ACL。

    setfacl --set u::rw,u:vagrant:rw,g::r,o::- file1
    +

    读取ACL权限:getfacl

    • Syntax: getfacl [OPTIONS] <file>
    • Option Description
    • -a: Display the file access control list
    • -d: Display the default access control list
    • -R: List the ACLs of all files and directories recursively

    8.6.ACL实例解析

    8.6.1.实例描述

    • 项目目录~/project1
    • 项目经理pm1对这个目录拥有访问和修改权限
    • 项目成员tm1可以访问和修改这个目录
    • 非项目成员tm2不能访问~/project1目录。
    • 项目目录~/project1的权限规划
    • 项目经理pm1是这个目录的属主,权限为rwx
    • 项目经理pm1属于project1
    • 项目成员tm1pm1在同一个project1组,权限是rw
    • 其他人的权限设定为0
    • 项目临时成员tm2的权限需求
    • 能访问project1目录,但只能具有rx权限

    解决方法

    • 当出现这种情况时,普通权限中的三种身份(owner,group,others)就不能解决这个问题,而ACL权限可以。 在使用ACL权限给用户tm2陚予权限时,tm2既不是~/project1目录的属主,也不是属组,仅仅赋予用户tm2针对~/project1目录的r-x权限, 属于单独指定用户并单独分配权限,解决了用户身份不足的问题。

    拓展问题

    • ~/project1目录添加其他组project2的访问权限
    • 通过mask来调整用户tm2实际有效权限
    • 默认ACL权限
    • 递归ACL权限
    • 删除ACL权限

    8.6.2.初始化环境

    创建测试用户

    $ whoami
     vagrant
     
    -$ sudo groupadd project1
    -$ sudo groupadd project2
    +$ sudo groupadd project1
    +$ sudo groupadd project2
     
    -$ sudo useradd -m -g project1 pm1
    -$ sudo useradd -m -g project1 tm1
    -$ sudo useradd -m -g project2 tm2
    +$ sudo useradd -m -g project1 pm1
    +$ sudo useradd -m -g project1 tm1
    +$ sudo useradd -m -g project2 tm2
     
    -$ sudo passwd pm1
    -$ sudo passwd tm1
    -$ sudo passwd tm2
    +$ sudo passwd pm1
    +$ sudo passwd tm1
    +$ sudo passwd tm2
     
    -$ cat /etc/group
    +$ cat /etc/group
     ......
     project1:x:1535:
     project2:x:1536:
     ......
     
    -$ cat /etc/passwd
    +$ cat /etc/passwd
     ......
     pm1:x:2003:1535::/home/pm1:/bin/bash
     tm1:x:2004:1535::/home/tm1:/bin/bash
     tm2:x:2005:1536::/home/tm2:/bin/bash
     ......
    -

    创建测试目录project1, 指定project1目录的权限,创建测试文件file1

    $ su - pm1
    -$ cd ~
    +

    创建测试目录project1, 指定project1目录的权限,创建测试文件file1

    $ su - pm1
    +$ cd ~
     
    -$ mkdir project1
    +$ mkdir project1
     
    -$ ls -dl project1
    -drwxr-xr-x. 1 pm1 project1 0 Dec  4 06:25 project1
    +$ ls -dl project1
    +drwxr-xr-x. 1 pm1 project1 0 Dec  4 06:25 project1
     
    -$ chmod 770 project1/
    +$ chmod 770 project1/
     
    -$ ls -dl project1
    -drwxrwx---. 1 pm1 project1 0 Dec  4 06:25 project1
    +$ ls -dl project1
    +drwxrwx---. 1 pm1 project1 0 Dec  4 06:25 project1
     
    -$ echo "hello from $USER" > ./project1/file1
    +$ echo "hello from $USER" > ./project1/file1
     
    -$  cat ./project1/file1
    -hello from pm1
    -

    目录project1当前权限快照

    • 属主:pm1,对~/project1目录有rwx权限
    • 属组:project1,包含用户pm1tm1,对~/project1目录有rwx权限
    • 其他组:没有访问权限

    目录~/project1当前的ACL快照

    $ getfacl ./project1/
    +$  cat ./project1/file1
    +hello from pm1
    +

    目录project1当前权限快照

    • 属主:pm1,对~/project1目录有rwx权限
    • 属组:project1,包含用户pm1tm1,对~/project1目录有rwx权限
    • 其他组:没有访问权限

    目录~/project1当前的ACL快照

    $ getfacl ./project1/
     # file: home/pm1/project1/
     # owner: pm1
     # group: project1
     user::rwx
     group::rwx
     other::---
    -

    8.6.3.添加ACL权限

    ~/project1目录添加新用户tm2,权限为rwx。目录~/project1的更新后的权限位变成了drwxrwx---+

    $ su - pm1
    +

    8.6.3.添加ACL权限

    ~/project1目录添加新用户tm2,权限为rwx。目录~/project1的更新后的权限位变成了drwxrwx---+

    $ su - pm1
     
    -$ setfacl -m u:tm2:rx ./project1/
    +$ setfacl -m u:tm2:rx ./project1/
     
    -$ ls -dl ./project1
    -drwxrwx---+ 1 pm1 project1 0 Dec  4 06:25 project1
    +$ ls -dl ./project1
    +drwxrwx---+ 1 pm1 project1 0 Dec  4 06:25 project1
     
    -$ getfacl ~/project1/
    +$ getfacl ~/project1/
     # file: project1   (文件名)
     # owner: pm1       (Owner 文件属主)
     # group: project1  (Owing Group 文件属组)
    -user::rwx          (Ower文件属主的权限,用户名栏是空的,说明是属主Owner的权限)
    -user:tm2:r-x       (Named User 指定用户的权限,用户tm2的权限)
    -group::rwx         (Owing Group 文件属组的权限,组名栏是空的,说明是属组的权限)
    -                   (Named Group 指定用户组的权限,此时未指定)
    -mask::rwx          (mask权限)
    -other::---         (其他人other的权限)
    -

    ~/project1目录添加新组project2的权限rwx

    $ su - pm1
    +user::rwx          (Ower文件属主的权限,用户名栏是空的,说明是属主Owner的权限)
    +user:tm2:r-x       (Named User 指定用户的权限,用户tm2的权限)
    +group::rwx         (Owing Group 文件属组的权限,组名栏是空的,说明是属组的权限)
    +                   (Named Group 指定用户组的权限,此时未指定)
    +mask::rwx          (mask权限)
    +other::---         (其他人other的权限)
    +

    ~/project1目录添加新组project2的权限rwx

    $ su - pm1
     
    -$ setfacl -m g:project2:rwx ./project1/
    +$ setfacl -m g:project2:rwx ./project1/
     
    -$ ls -dl ./project1
    -drwxrwx---+ 1 pm1 project1 0 Dec  4 06:46 ./project1
    +$ ls -dl ./project1
    +drwxrwx---+ 1 pm1 project1 0 Dec  4 06:46 ./project1
     
    -$ getfacl ./project1
    +$ getfacl ./project1
     # file: project1
     # owner: pm1
     # group: project1
     user::rwx
    -user:tm2:r-x         (用户tm2拥有了r-x权限)
    +user:tm2:r-x         (用户tm2拥有了r-x权限)
     group::rwx
    -group:project2:rwx   (用户组project2拥有了rwx权限)
    +group:project2:rwx   (用户组project2拥有了rwx权限)
     mask::rwx
     other::---
    -

    有效权限的计算:

    当前~/project1目录的maskrwxtm2的权限是r-x,二者进行AND操作,tm2的实际权限是r-x

       tm2: r - x (1 0 1)
    -  mask: r w x (1 1 1)
    +

    有效权限的计算:

    当前~/project1目录的maskrwxtm2的权限是r-x,二者进行AND操作,tm2的实际权限是r-x

       tm2: r - x (1 0 1)
    +  mask: r w x (1 1 1)
     ---------------------
    -result: r - x (1 0 1)
    -

    对照下面的规则,验证用户tm2~/project1目录的实际权限。

    su - tm2
    -

    能进入目录project1,说明当前用户具有目录project1r-x权限。

    $ whoami
    +result: r - x (1 0 1)
    +

    对照下面的规则,验证用户tm2~/project1目录的实际权限。

    su - tm2
    +

    能进入目录project1,说明当前用户具有目录project1r-x权限。

    $ whoami
     tm2
     
    -$ cd /home/pm1/project1/
    -

    能列出目录project1下文件列表,可以查看文件file的内容,说明当前用户具有目录project1r-x权限。

    $ pwd
    +$ cd /home/pm1/project1/
    +

    能列出目录project1下文件列表,可以查看文件file的内容,说明当前用户具有目录project1r-x权限。

    $ pwd
     /home/pm1/project1
     
    -$ whoami
    +$ whoami
     tm2
     
    -$ ls -l
    --rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
    +$ ls -l
    +-rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
     
    -$ cat file1
    -hello from pm1
    -

    对目录project1不具有w权限,所以无法创建、删除或修改目录下的任何文件或子目录。

    $ pwd
    +$ cat file1
    +hello from pm1
    +

    对目录project1不具有w权限,所以无法创建、删除或修改目录下的任何文件或子目录。

    $ pwd
     /home/pm1/project1
     
    -$ whoami
    +$ whoami
     tm2
     
    -$ touch file2
    -touch: cannot touch 'file2': Permission denied
    +$ touch file2
    +touch: cannot touch 'file2': Permission denied
     
    -$ echo "hello from $USER" >> file1
    --bash: file1: Permission denied
    -

    8.6.4.修改mask权限

    调整~/project1目录的maskr--,则tm2的实际权限是r--

    $ su - pm1
    -$ cd ~
    -$ setfacl -m m::r ./project1/
    +$ echo "hello from $USER" >> file1
    +-bash: file1: Permission denied
    +

    8.6.4.修改mask权限

    调整~/project1目录的maskr--,则tm2的实际权限是r--

    $ su - pm1
    +$ cd ~
    +$ setfacl -m m::r ./project1/
     
    -$ getfacl ./project1/
    +$ getfacl ./project1/
     # file: project1/
     # owner: pm1
     # group: project1
     user::rwx
    -user:tm2:r-x          #effective:r--  (用户tm2的实际有效权限变为r--)
    -group::rwx            #effective:r--  (属组project1组的实际有效权限变为r--)
    -group:project2:rwx    #effective:r--  (其他组project2组的实际有效权限变为r--)
    -mask::r--                             (mask变化,导致上述两个group的有效权限都发生了变化)
    +user:tm2:r-x          #effective:r--  (用户tm2的实际有效权限变为r--)
    +group::rwx            #effective:r--  (属组project1组的实际有效权限变为r--)
    +group:project2:rwx    #effective:r--  (其他组project2组的实际有效权限变为r--)
    +mask::r--                             (mask变化,导致上述两个group的有效权限都发生了变化)
     other::---
    -

    有效权限的计算:

    当前~/project1目录的maskr--,用户tm2、组project2的实际权限是r--

       tm2: r - w (1 0 1)
    -  mask: r - - (1 0 0)
    +

    有效权限的计算:

    当前~/project1目录的maskr--,用户tm2、组project2的实际权限是r--

       tm2: r - w (1 0 1)
    +  mask: r - - (1 0 0)
     ---------------------
    -result: r - - (1 0 0)
    -

    提示:

    用户和用户组所设定的权限必须在mask权限设定的范围之内才能生效,mask权限就是最大有效权限。

    8.6.5.有效权限分析

    在POSIX权限模型和ACL权限叠加作用下,用户的实际权限分析。

    $ getfacl ./project1/
    +result: r - - (1 0 0)
    +

    提示:

    用户和用户组所设定的权限必须在mask权限设定的范围之内才能生效,mask权限就是最大有效权限。

    8.6.5.有效权限分析

    在POSIX权限模型和ACL权限叠加作用下,用户的实际权限分析。

    $ getfacl ./project1/
     # file: project1/
     # owner: pm1                            <----Owner
     # group: project1                       <----owning group
    -user::rwx                               <----owner's permissions
    -user:tm2:r-x          #effective:r--    <----named user's permissions
    -group::rwx            #effective:r--    <----owning group's permissions
    -group:project2:rwx    #effective:r--    <----named group's permissions
    -mask::r--                               <----masks for named user and named group
    +user::rwx                               <----owner's permissions
    +user:tm2:r-x          #effective:r--    <----named user's permissions
    +group::rwx            #effective:r--    <----owning group's permissions
    +group:project2:rwx    #effective:r--    <----named group's permissions
    +mask::r--                               <----masks for named user and named group
     other::---
     default:user::rwx
     default:user:tm2:r-x
     default:group::rwx
     default:mask::rwx
     default:other::---
    -

    所有者ower和其他用户other条目中定义的权限总是有效的。上例中的user条目和other条目。 除了掩码条目,所有其他条目(比如指定用户named user)可以是有效的或被屏蔽的。

    指定用户(named user),所有者组(owning group)或指定组(named group)以及掩码mask条目中定义的权限,有效权限是他们权限进行逻辑AND后的结果,而不是单独的掩码中定义的权限或者各自条目中定义的权。

    有效权限计算方法如下,注意,ls命令中显示出来的权限,与实际的ACL权限是有差别的。

            tm2: r - w (1 0 1)
    -      group: r w x (1 1 1)
    -named group: r w x (1 1 1)
    -       mask: r - - (1 0 0)
    +

    所有者ower和其他用户other条目中定义的权限总是有效的。上例中的user条目和other条目。 除了掩码条目,所有其他条目(比如指定用户named user)可以是有效的或被屏蔽的。

    指定用户(named user),所有者组(owning group)或指定组(named group)以及掩码mask条目中定义的权限,有效权限是他们权限进行逻辑AND后的结果,而不是单独的掩码中定义的权限或者各自条目中定义的权。

    有效权限计算方法如下,注意,ls命令中显示出来的权限,与实际的ACL权限是有差别的。

            tm2: r - w (1 0 1)
    +      group: r w x (1 1 1)
    +named group: r w x (1 1 1)
    +       mask: r - - (1 0 0)
     ---------------------------
    -     result: r - - (1 0 0)
    -

    小贴士:

    与文件模式权限位等效的ACL称为最小ACL,即POSIX传统权限。

    含掩码mask等其他权限条目的ACL称为扩展ACL。

    在最小和扩展ACL情形下,所有者类权限(owner)都是映射到ACL的所有者条目。 其他类权限映射到其各自的ACL条目。

    在扩展ACL情形下,组类权限的映射是不同的。

    对于没有掩码的最小ACL,组类权限将映射到ACL所有者组条目。

    对于带有掩码的扩展ACL,组类权限将映射到掩码条目。

    通过权限位进行分配的权限代表了通过ACL进行分配的权限的上限。 没有在这里体现的任何权限,要么不在ACL中,要么无效。

    对权限位所做的更改将由ACL反映,反之亦然。

    8.6.6.默认ACL权限

    $ su - pm1
    +     result: r - - (1 0 0)
    +

    小贴士:

    与文件模式权限位等效的ACL称为最小ACL,即POSIX传统权限。

    含掩码mask等其他权限条目的ACL称为扩展ACL。

    在最小和扩展ACL情形下,所有者类权限(owner)都是映射到ACL的所有者条目。 其他类权限映射到其各自的ACL条目。

    在扩展ACL情形下,组类权限的映射是不同的。

    对于没有掩码的最小ACL,组类权限将映射到ACL所有者组条目。

    对于带有掩码的扩展ACL,组类权限将映射到掩码条目。

    通过权限位进行分配的权限代表了通过ACL进行分配的权限的上限。 没有在这里体现的任何权限,要么不在ACL中,要么无效。

    对权限位所做的更改将由ACL反映,反之亦然。

    8.6.6.默认ACL权限

    $ su - pm1
     
    -$ touch ./project1/file2
    -$ mkdir ./project1/cloud
    +$ touch ./project1/file2
    +$ mkdir ./project1/cloud
     
    -$ ll ./project1/
    -drwxr-xr-x. 1 pm1 project1  0 Dec  4 08:52 cloud
    --rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
    --rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
    +$ ll ./project1/
    +drwxr-xr-x. 1 pm1 project1  0 Dec  4 08:52 cloud
    +-rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
    +-rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
     
    -$ ll -d project1/
    -drwxr-----+ 1 pm1 project1 30 Dec  4 08:52 project1/
    -

    文件file1和目录cloud没有继承project1目录的ACL权限。

    提示:

    默认 ACL限只对目录生效。 默认ACL权限的作用是:如果给父目录设定了默认 ACL 权限,那么父目录中所有新建的子文件都会继承父目录的ACL权限。

    下面增加~/project1目录的默认ACL权限。

    $ su - pm1
    -$ cd ~
    +$ ll -d project1/
    +drwxr-----+ 1 pm1 project1 30 Dec  4 08:52 project1/
    +

    文件file1和目录cloud没有继承project1目录的ACL权限。

    提示:

    默认 ACL限只对目录生效。 默认ACL权限的作用是:如果给父目录设定了默认 ACL 权限,那么父目录中所有新建的子文件都会继承父目录的ACL权限。

    下面增加~/project1目录的默认ACL权限。

    $ su - pm1
    +$ cd ~
     
    -$ getfacl ./project1/
    +$ getfacl ./project1/
     # file: project1/
     # owner: pm1
     # group: project1
     user::rwx
    -user:tm2:r-x          #effective:r--
    -group::rwx            #effective:r--
    -group:project2:rwx    #effective:r--
    +user:tm2:r-x          #effective:r--
    +group::rwx            #effective:r--
    +group:project2:rwx    #effective:r--
     mask::r--
     other::---
     
    -$ setfacl -m d:u:tm2:rx ./project1/
    +$ setfacl -m d:u:tm2:rx ./project1/
     
    -$ getfacl ./project1/
    +$ getfacl ./project1/
     # file: project1/
     # owner: pm1
     # group: project1
     user::rwx
    -user:tm2:r-x         #effective:r--
    -group::rwx           #effective:r--
    -group:project2:rwx   #effective:r--
    +user:tm2:r-x         #effective:r--
    +group::rwx           #effective:r--
    +group:project2:rwx   #effective:r--
     mask::r--
     other::---
     default:user::rwx
    @@ -961,26 +961,26 @@
     default:group::rwx
     default:mask::rwx
     default:other::---
    -

    创建新子目录leonardo,就继承了~/project1目录的default ACL权限设定。

    注意,默认ACL权限是针对新建立的文件生效的,目录cloud和文件file1并没有因为增加了父目录的默认ACL设定而继承默认ACL权限设定.

    $ su - pm1
    -$ cd ~
    -$ mkdir ./project1/leonardo
    -
    -$ ll ./project1/
    -drwxr-xr-x. 1 pm1 project1  0 Dec  4 08:52 cloud
    --rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
    --rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
    -drwxrwx---+ 1 pm1 project1  0 Dec  4 09:07 leonardo
    -

    8.6.7.递归ACL权限

    递归 ACL 权限,是指父目录在设定ACL权限时,所有的子目录也会拥有相同的ACL权限。

    $ su - pm1
    -$ cd ~
    -
    -$ getfacl ./project1/
    +

    创建新子目录leonardo,就继承了~/project1目录的default ACL权限设定。

    注意,默认ACL权限是针对新建立的文件生效的,目录cloud和文件file1并没有因为增加了父目录的默认ACL设定而继承默认ACL权限设定.

    $ su - pm1
    +$ cd ~
    +$ mkdir ./project1/leonardo
    +
    +$ ll ./project1/
    +drwxr-xr-x. 1 pm1 project1  0 Dec  4 08:52 cloud
    +-rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
    +-rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
    +drwxrwx---+ 1 pm1 project1  0 Dec  4 09:07 leonardo
    +

    8.6.7.递归ACL权限

    递归 ACL 权限,是指父目录在设定ACL权限时,所有的子目录也会拥有相同的ACL权限。

    $ su - pm1
    +$ cd ~
    +
    +$ getfacl ./project1/
     # file: project1/
     # owner: pm1
     # group: project1
     user::rwx
    -user:tm2:r-x          #effective:r--
    -group::rwx            #effective:r--
    -group:project2:rwx    #effective:r--
    +user:tm2:r-x          #effective:r--
    +group::rwx            #effective:r--
    +group:project2:rwx    #effective:r--
     mask::r--
     other::---
     default:user::rwx
    @@ -989,19 +989,19 @@
     default:mask::rwx
     default:other::---
     
    -$ setfacl -m d:u:tm2:rx -R ./project1/
    +$ setfacl -m d:u:tm2:rx -R ./project1/
     
    -$ ll ./project1
    -drwxr-xr-x+ 1 pm1 project1  0 Dec  4 08:52 cloud
    --rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
    --rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
    -drwxrwx---+ 1 pm1 project1  0 Dec  4 09:07 leonardo
    -

    8.6.8.删除ACL权限

    删除用户tm2的ACL权限。

    $ su - pm1
    -$ cd ~
    +$ ll ./project1
    +drwxr-xr-x+ 1 pm1 project1  0 Dec  4 08:52 cloud
    +-rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
    +-rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
    +drwxrwx---+ 1 pm1 project1  0 Dec  4 09:07 leonardo
    +

    8.6.8.删除ACL权限

    删除用户tm2的ACL权限。

    $ su - pm1
    +$ cd ~
     
    -$ setfacl -x u:tm2 ./project1/
    +$ setfacl -x u:tm2 ./project1/
     
    -$ getfacl ./project1/
    +$ getfacl ./project1/
     # file: project1/
     # owner: pm1
     # group: project1
    @@ -1015,9 +1015,9 @@
     default:group::rwx
     default:mask::rwx
     default:other::---
    -

    删除所有的ACL权限。

    $ setfacl -b ./project1
    +

    删除所有的ACL权限。

    $ setfacl -b ./project1
     
    -$ getfacl ./project1
    +$ getfacl ./project1
     # file: project1/
     # owner: pm1
     # group: project1
    @@ -1025,31 +1025,31 @@
     group::rwx
     other::---
     
    -$ ll ./project1
    -drwxr-xr-x+ 1 pm1 project1  0 Dec  4 08:52 cloud
    --rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
    --rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
    -drwxrwx---+ 1 pm1 project1  0 Dec  4 09:07 leonardo
    -

    递归删除全部ACL权限。

    $ setfacl -b -R ./project1
    -
    -$ ll ./project1/
    -total 4
    -drwxr-xr-x. 1 pm1 project1  0 Dec  4 08:52 cloud
    --rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
    --rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
    -drwxrwx---. 1 pm1 project1  0 Dec  4 09:07 leonardo
    -

    8.7.ACL目录实例解析

    8.7.1.目录ACL

    切换到pm1用户,在其主目录中,基于不同的掩码创建2个子目录。

    $ su - pm1
    -
    -$ umask 0022
    -$ mkdir mydir1
    -
    -$ umask 0027
    -$ mkdir mydir2
    -
    -$ ll -d mydir*
    -drwxr-xr-x. 1 pm1 project1 0 Dec  4 12:30 mydir1
    -drwxr-x---. 1 pm1 project1 0 Dec  4 12:31 mydir2
    -

    这2个目录当前的ACL状态如下:

    $ getfacl mydir1
    +$ ll ./project1
    +drwxr-xr-x+ 1 pm1 project1  0 Dec  4 08:52 cloud
    +-rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
    +-rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
    +drwxrwx---+ 1 pm1 project1  0 Dec  4 09:07 leonardo
    +

    递归删除全部ACL权限。

    $ setfacl -b -R ./project1
    +
    +$ ll ./project1/
    +total 4
    +drwxr-xr-x. 1 pm1 project1  0 Dec  4 08:52 cloud
    +-rw-r--r--. 1 pm1 project1 15 Dec  4 07:15 file1
    +-rw-r--r--. 1 pm1 project1  0 Dec  4 08:52 file2
    +drwxrwx---. 1 pm1 project1  0 Dec  4 09:07 leonardo
    +

    8.7.ACL目录实例解析

    8.7.1.目录ACL

    切换到pm1用户,在其主目录中,基于不同的掩码创建2个子目录。

    $ su - pm1
    +
    +$ umask 0022
    +$ mkdir mydir1
    +
    +$ umask 0027
    +$ mkdir mydir2
    +
    +$ ll -d mydir*
    +drwxr-xr-x. 1 pm1 project1 0 Dec  4 12:30 mydir1
    +drwxr-x---. 1 pm1 project1 0 Dec  4 12:31 mydir2
    +

    这2个目录当前的ACL状态如下:

    $ getfacl mydir1
     # file: mydir1
     # owner: pm1
     # group: project1
    @@ -1057,17 +1057,17 @@
     group::r-x
     other::r-x
     
    -$ getfacl mydir2
    +$ getfacl mydir2
     # file: mydir2
     # owner: pm1
     # group: project1
     user::rwx
     group::r-x
     other::---
    -

    修改目录mydir2的ACL。

    $ setfacl -m u:tm2:rwx,g:project2:rwx mydir2
    +

    修改目录mydir2的ACL。

    $ setfacl -m u:tm2:rwx,g:project2:rwx mydir2
     
    -$ getfacl mydir2
    -getfacl mydir2
    +$ getfacl mydir2
    +getfacl mydir2
     # file: mydir2
     # owner: pm1
     # group: project1
    @@ -1078,29 +1078,29 @@
     mask::rwx
     other::---
     
    -$ ll -d mydir2
    -drwxrwx---+ 1 pm1 project1 0 Dec  4 12:31 mydir2
    -

    现在,用户tm2和组project2对目录mydir2都具有rwx权限,传统POSIX权限和ACL权限一致。

    现在对mydir2目录组权限撤销w权限。 用户tm2和组project2对目录mydir2的有效权限变成了r-x。 mask也受组权限变化影响,变成了r-x

    $ chmod g-w mydir2
    +$ ll -d mydir2
    +drwxrwx---+ 1 pm1 project1 0 Dec  4 12:31 mydir2
    +

    现在,用户tm2和组project2对目录mydir2都具有rwx权限,传统POSIX权限和ACL权限一致。

    现在对mydir2目录组权限撤销w权限。 用户tm2和组project2对目录mydir2的有效权限变成了r-x。 mask也受组权限变化影响,变成了r-x

    $ chmod g-w mydir2
     
    -$ ll -d mydir2
    -drwxr-x---+ 1 pm1 project1 0 Dec  4 12:31 mydir2
    +$ ll -d mydir2
    +drwxr-x---+ 1 pm1 project1 0 Dec  4 12:31 mydir2
     
    -$ getfacl mydir2
    +$ getfacl mydir2
     # file: mydir2
     # owner: pm1
     # group: project1
     user::rwx
    -user:tm2:rwx          #effective:r-x
    +user:tm2:rwx          #effective:r-x
     group::r-x
    -group:project2:rwx    #effective:r-x
    +group:project2:rwx    #effective:r-x
     mask::r-x
     other::---
    -

    通过chmodsetfacl两种不同的方法对目录mydir2的组权限进行修改,在ls命令中体现是一样的,对组的实际有效权限的影响也是一样的。

    chmod修改的是maskmask只影响除所有者和other的之外的人和组的最大权限,mask需要与用户的权限进行逻辑与运算后,才能变成有效权限,用户或组的设置必须在mask权限设定范围内才会生效。

    setfacl可以不修改mask的情况下只修改owning group的权限,下面的例子说明了这一情况。POSIX组权限仍然是rwx,但ACL中所有者组的权限变成了r--

    $ setfacl -m g::r mydir2
    +

    通过chmodsetfacl两种不同的方法对目录mydir2的组权限进行修改,在ls命令中体现是一样的,对组的实际有效权限的影响也是一样的。

    chmod修改的是maskmask只影响除所有者和other的之外的人和组的最大权限,mask需要与用户的权限进行逻辑与运算后,才能变成有效权限,用户或组的设置必须在mask权限设定范围内才会生效。

    setfacl可以不修改mask的情况下只修改owning group的权限,下面的例子说明了这一情况。POSIX组权限仍然是rwx,但ACL中所有者组的权限变成了r--

    $ setfacl -m g::r mydir2
     
    -$ ll -d mydir2
    -drwxrwx---+ 1 pm1 project1 0 Dec  4 12:31 mydir2
    +$ ll -d mydir2
    +drwxrwx---+ 1 pm1 project1 0 Dec  4 12:31 mydir2
     
    -$ getfacl mydir2
    +$ getfacl mydir2
     # file: mydir2
     # owner: pm1
     # group: project1
    @@ -1110,9 +1110,9 @@
     group:project2:rwx
     mask::rwx
     other::---
    -

    8.7.2.目录的默认ACL

    目录可以具有默认ACL,这是一种特殊的ACL,用于定义目录下的对象在创建时继承的访问权限。默认ACL会影响子目录和文件。

    目录的默认ACL的权限有两种不同的方式传递给其中的文件和子目录:

    • 子目录继承父目录的默认ACL,既作为自己的默认ACL,又作为自己的访问ACL。
    • 文件继承目录默认ACL作为其自己的访问ACL。

    创建文件系统对象的所有系统函数都使用mode参数,该参数定义了新创建的文件系统对象的访问权限。

    • 如果父目录没有默认ACL,则根据umask的设置设置权限位。
    • 如果父目录存在默认ACL,则分配给新对象的权限位则是mode参数权限与默认ACL中定义的权限的逻辑与的结果。在这种情况下,忽略umask命令。
    • 默认ACL不会立即影响访问权限。它们仅在创建文件系统对象时才起作用。这些新对象仅从其父目录的默认ACL继承权限。
    • 命令mkdir在创建目录时会继承默认ACL。
    $ su - pm1
    +

    8.7.2.目录的默认ACL

    目录可以具有默认ACL,这是一种特殊的ACL,用于定义目录下的对象在创建时继承的访问权限。默认ACL会影响子目录和文件。

    目录的默认ACL的权限有两种不同的方式传递给其中的文件和子目录:

    • 子目录继承父目录的默认ACL,既作为自己的默认ACL,又作为自己的访问ACL。
    • 文件继承目录默认ACL作为其自己的访问ACL。

    创建文件系统对象的所有系统函数都使用mode参数,该参数定义了新创建的文件系统对象的访问权限。

    • 如果父目录没有默认ACL,则根据umask的设置设置权限位。
    • 如果父目录存在默认ACL,则分配给新对象的权限位则是mode参数权限与默认ACL中定义的权限的逻辑与的结果。在这种情况下,忽略umask命令。
    • 默认ACL不会立即影响访问权限。它们仅在创建文件系统对象时才起作用。这些新对象仅从其父目录的默认ACL继承权限。
    • 命令mkdir在创建目录时会继承默认ACL。
    $ su - pm1
     
    -$ getfacl mydir2
    +$ getfacl mydir2
     # file: mydir2
     # owner: pm1
     # group: project1
    @@ -1123,20 +1123,20 @@
     mask::rwx
     other::---
     
    -$ mkdir ./mydir2/sub1
    +$ mkdir ./mydir2/sub1
     
    -$ ll ./mydir2
    -drwxr-x---. 1 pm1 project1 0 Dec  4 13:23 sub1
    +$ ll ./mydir2
    +drwxr-x---. 1 pm1 project1 0 Dec  4 13:23 sub1
     
    -$ setfacl -d -m g:project2:-w- mydir2
    +$ setfacl -d -m g:project2:-w- mydir2
     
    -$ mkdir ./mydir2/sub2
    +$ mkdir ./mydir2/sub2
     
    -$ ll ./mydir2
    -drwxr-x---. 1 pm1 project1 0 Dec  4 13:23 sub1
    -drwxrw----+ 1 pm1 project1 0 Dec  4 13:27 sub2
    +$ ll ./mydir2
    +drwxr-x---. 1 pm1 project1 0 Dec  4 13:23 sub1
    +drwxrw----+ 1 pm1 project1 0 Dec  4 13:27 sub2
     
    -$ getfacl ./mydir2/sub2
    +$ getfacl ./mydir2/sub2
     # file: mydir2/sub2
     # owner: pm1
     # group: project1
    @@ -1150,10 +1150,10 @@
     default:group:project2:-w-
     default:mask::rw-
     default:other::---
    -

    在对mydir2目录添加默认ACL前,创建子目录sub1,添加后创建子目录sub2。可以观察到sub2到继承了mydir2的默认ACL。

    $ su - tm2
    +

    在对mydir2目录添加默认ACL前,创建子目录sub1,添加后创建子目录sub2。可以观察到sub2到继承了mydir2的默认ACL。

    $ su - tm2
     
    -$ cd /home/pm1/mydir2/sub2
    --bash: cd: /home/pm1/mydir2/sub2: Permission denied
    +$ cd /home/pm1/mydir2/sub2
    +-bash: cd: /home/pm1/mydir2/sub2: Permission denied
     

    上例中,默认ACL中指定组project2只具有w权限,所以无法执行cd命令进入该目录。 这说明模式值mode中给予的权限r被屏蔽了,只保留了ACL中最小的权限w

    8.8.ACL检查逻辑

    ACL检查顺序:

    • Owner
    • Named user
    • Owning group
    • Named group
    • Other
    If
      进程的用户标识是Owner,则owner的ACL条目决定访问权限
     else if
    @@ -1172,4 +1172,4 @@
      如果进程匹配到named user,owning group,或者named group条目中包含所申请的权限,且maks条目也包含所申请的权限,则授予权限
     else
      拒绝权限申请
    -

    实际应用举例:

    • udev使用ACL给予登录到图形界面的用户访问设备的权限,例如DVD驱动器
    • 某些应用程序不支持ACL
    • Star Archiver是一个完全保留ACL的备份应用程序,其他人可能会也可能不会保留它
    • 许多编辑器和文件管理器不允许在应用程序中查看或设置ACL
    \ No newline at end of file +

    实际应用举例:

    • udev使用ACL给予登录到图形界面的用户访问设备的权限,例如DVD驱动器
    • 某些应用程序不支持ACL
    • Star Archiver是一个完全保留ACL的备份应用程序,其他人可能会也可能不会保留它
    • 许多编辑器和文件管理器不允许在应用程序中查看或设置ACL
    Back to top
    \ No newline at end of file diff --git a/linux/SRE/04-TextTools/index.html b/linux/SRE/04-TextTools/index.html index e2128c04..aad992bf 100644 --- a/linux/SRE/04-TextTools/index.html +++ b/linux/SRE/04-TextTools/index.html @@ -1,26 +1,26 @@ - 第四章 文本编辑 - UPSkilling

    第四章 文本编辑

    1.文本编辑器

    1.1.vim工具

    vim命令格式:

    • +# file: 打开文件后,让光标处于第#行首,+默认行尾
    • +/PATTERN file: 打开文件有,让光标处于第一个被PATTERN匹配到的行首
    • -b file: 二进制方式打开文件
    • -d file1 file2 ...: 比较多个文件,相当于vimdiff
    • -m file: 只读方式打开文件
    • -e file: 进入ex模式,相当于ex file
    • -y file:

    vim三种常见模式:

    • 普通模式Normal或命令模式
    • 插入Insert或编辑模式
    • 扩展命令模式Extended Command

    三种模式切换

    • 命令模式→插入模式
    • i:insert,在光标处输入
    • I:在光标所在行首输入
    • a:append,在光标处后面输入
    • A:在光标所在行尾输入
    • o:在光标所在行的下方打开一个新行
    • O:在光标所在行的上方打开一个新行
    • 插入模式→ ESC → 命令模式
    • 命令模式→ : → 扩展命令模式
    • 扩展命令模式→ ESC, enter → 命令模式

    扩展命令模式常用命令:

    • :wq: 保存文件并退出
    • :w: 保存文件
    • :w filename: 写入指定文件,相当于另存为
    • :q!: 放弃任何修改并退出
    • ZQ: 无条件退出
    • :join: 合并多行
    • J: 合并两行

    设置:(可以在/etc/vimrc文件中配置)

    • :set textwidth: 设置文本宽度(从左向右计数)
    • :set wrapmargin=#: 设置行边距(从右向左计数)
    • :set endofline: 设置文件结束符
    • :set noendofline: 取消文件结束符
    • :set wrap: 自动换行
    • :set nowrap: 取消自动换行
    • :set number: 显示行号
    • :set nonumber: 取消显示行号
    • :set list: 进入List Mode,显示Tab ^I,换行符,和$显示
    • :set nolist: 退出List Mode
    • :set ignorecase: 忽略字符的大小写
    • :set noic: 不忽略字符大小写
    • :set autoindent: 启用自动缩进
    • :set noai: 关闭自动缩进
    • :set hlsearch: 启用高亮搜索
    • :set nohlsearch: 关闭高亮搜索
    • :set fileformat=dos: 启用windows格式
    • :set fileformat=unix: 启用unix格式
    • :set expandtab: 启用空格代替TAB,默认8个空格代替一个TAB
    • :set noexpandtab: 关闭空格代替TAB
    • :set tabstop=#: 指定#个空格代替一个TAB
    • :set shiftwidth=#: 设置#个缩进宽度
    • :set cursorline: 设置光标所在行的表示线
    • :set cursorline: 关闭光标所在行的表示线
    • :set key=PASSWORD: 启用密码保护
    • :set key=: 关闭密码保护
    • :help option-list: 获取帮助

    查找

    • /pattern: 从光标开始处向文件尾搜索pattern
    • ?pattern: 从光标开始处向文件首搜索pattern
    • n: 在同一方向重复上一次搜索命令
    • N: 在反方向上重复上一次搜索命令
    • #: 向上完整匹配光标下的单词, 相当于?word
    • *: 向下完整匹配光标下的单词, 相当于/word
    • %: 查找对应的( [ {匹配
    • nfx: 在当前行查找光标后第n个x(一般直接fx)

    替换

    • :%s/\n//g: 删除换行符
    • :s/p1/p2/g: 将当前行中所有p1均用p2替代, 无g,则只替换第一个
    • :s/p1/p2/c: 查找替换要求确认
    • :n1,n2s/p1/p2/g: 将第n1至n2行中所有p1均用p2替代
    • :%s/p1/p2/g: 全局,使用p2替换p1
    • :%s/p1/p2/gc: 替换前询问
    • :n,$s/vivian/sky/: 替换第n行开始到最后一行中每一行的第一个vivian为sky,n为数字
    • :.,$s/vivian/sky/g: 替换当前行开始到最后一行中每一行所有vivian为sky
    • :s/vivian\//sky\//: 替换当前行第一个vivian/为sky/,可以使用\作为转义符
    • :1,$s/^/some string/: 在文件的第一行至最后一行的行首前插入some string
    • :%s/$/some string/g: 在整个文件每一行的行尾添加some string
    • :%s/\s\+$//: 去掉所有的行尾空格,“\s”表示空白字符(空格和制表符),“+”对前面的字符匹配一次或多次(越多越好),“\(”匹配行尾(使用“\$”表示单纯的“\)”字符)
    • :%s/\s∗\n\+/\r/: 去掉所有的空白行,“\(”和“\)”对表达式进行分组,使其被视作一个不可分割的整体
    • :%s!\s*//.*!!: 去掉所有的“//”注释
    • :%s!\s*/\*\_.\{-}\*/\s*!!g: 去掉所有的“/**/”注释
    • :%s= *$==: 将所有行尾多余的空格删除
    • :g/^\s*$/d: 将所有不包含字符(空格也不包含)的空行删除
    • r: 替换当前字符
    • R: 替换当前字符及其后的字符,直至按ESC键

    编辑

    • h: 光标左移一个字符[回退键Backspace]
    • l: 光标右移一个字符[空格键Space]
    • K: 光标上移一行
    • j: 光标下移一行
    • w: 光标跳到下个word的第一个字母(包括标点符号) [常用]
    • W: 移到下一个字的开头,忽略标点符号
    • B: 光标回到上个word的第一个字母
    • B: 移到前一个字的开头,忽略标点符号 BACK
    • E: 光标跳到下个word的最后一个字母
    • E: 移到下一个字的结尾,忽略标点符号 END
    • 0: 移到当前一行的开始[Home]
    • $: 移到当前一行的最后[End]
    • ^: 命令将光标移动到当前行的第一个非空白字符上
    • g_: 到本行最后一个不是blank字符的位置
    • Enter: 光标下移一行
    • n+: 光标下移n行【按上档键 数字shift +】
    • n-: 光标上移n行
    • G: 移到文件的最后一行
    • nG或者:n: 移到文件的第n行
    • gg: 移动到文档的开始
    • [[: 文件开始位置——开始行
    • ]]: 文件结束位置——末尾行
    • H: 光标移至屏幕顶行HEAD。光标定位在显示屏的第一行
    • M: 移到屏幕的中间行开头 Middle。光标定位在显示屏的中间
    • L: 移到屏幕的最后一行LAST。光标定位在显示屏的最后一行
    • (: 光标移至句首
    • ): 光标移至句尾
    • {: 移到段落的开头
    • }: 移到下一个段落的开头
    • %: 匹配括号移动,包括 (, {, [.(需要把光标先移到括号上)跳转到与之匹配的括号处
    • *#: 匹配光标当前所在的单词,移动光标到下一个(或上一个)匹配单词(*是下一个,#是上一个)
    • zf: 折叠(需加方向键)
    • zo: 展开(空格也可以展开)
    • CTRL+u: 向文件首翻半屏up
    • CTRL+d: 向文件尾翻半屏down
    • CTRL+f: 向文件尾翻一屏 forward (fact整屏去两行)
    • CTRL+b: 向文件首翻一屏back (fact整屏去两行)
    • CTRL-]: 跳转到当前光标所在单词对应的主题
    • CTRL-O: 回到前一个位置
    • SHIFT+V: 选择整行
    • zz: 命令会把当前行置为屏幕正中央(z字取其象形意义模拟一张纸的折叠及变形位置重置)
    • zt: 命令会把当前行置于屏幕顶端(top)
    • zb: 命令会把当前行置于屏幕底端(bottom)
    • 50%: 光标定位在文件的中间
    • `: 跳转到最近光标定位的位置(只能记忆最近两个位置) 反引号
    • I: 在光标前开始插入字符 insert
    • I: 在当前行首开始插入字符
    • A: 在光标位置后开始加字 append
    • A: 在光标所在行的最后面开始加字
    • O: 在光标下加一空白行并开始加字 open
    • O: 在光标上加一空白行并开始加字
    • R: 替换当前字符
    • R: 替换当前字符及其后的字符【当前及其后字符被覆盖】
    • S: 默认删除光标所在字符,输入内容插入之= xi
    • S: 默认删除当前行内容,输入内容作为当前行新内容= dd+o
    • nx: 删除由光标位置起始后的n个字符(含光标位置)x =dl(删除当前光标下的字符)
    • nX: 删除由光标位置起始前的n个字符(含光标位置)X =dh(删除当前光标左边的字符)
    • d0: 删至行首
    • d$: 删至行尾
    • dfa: 表示删除从当前光标到光标后面的第一个a字符之间的内容
    • D: 代表d$(删除到行尾的内容)
    • C: 代表c$(修改到行尾的内容)
    • ndw: 删除光标处开始及其后的n-1个字
    • ndb: 删除光标处开始及其前的n-1个字
    • diw: 删除当前光标所在的word(不包括空白字符),意为Delete Inner Word 两个符号之间的单词
    • daw: 删除当前光标所在的word(包括空白字符),意为Delete A Word
    • ndd: 删除当前行及其后n-1行
    • :n1,n2 d: 将 n1行到n2行之间的内容删除
    • dG: 删除当前行至文件尾的内容
    • Dgg: 删除当前行至文件头的内容
    • d+enter: 删除2行【包括光标一行】
    • cw: 删除当前字,并进入输入模式【很好用,快速更改一个单词】相当于dw+i
    • ncw: 删除当前字及其后的n-1个字,并进入输入模式\修改指定数目的字
    • cc: 删除当前行,并进入输入模式
    • ncc: 删除当前行及其后的n-1行,并进入输入模式
    • guw: 光标下的单词变为小写
    • gUw: 光标下的单词变为大写
    • xp: 左右交换光标处两字符的位置
    • ga: 显示光标下的字符在当前使用的encoding下的内码
    • nyl: 复制n个字符(也可nyh)
    • yw: 复制一个单词
    • y0: 表示拷贝从当前光标到光标所在行首的内容
    • y$: 复制从当前位置到行尾
    • yfa: 表示拷贝从当前光标到光标后面的第一个a字符之间的内容
    • yG: 复制从所在行到最后一行
    • nyy: 将光标所在位置开始的n行数据复制暂存, 复制一整行
    • CTRL+v 方向y: 列选择模式,复制选择的很多行:先使用V进入visual模式,然后j向下移动到你想复制的行为止,然后y
    • p: 复制暂存数据在光标的下一行
    • P: 复制暂存数据在光标的上一行
    • :n1,n2 co n3: 将n1行到n2行之间的内容拷贝到第n3+1行【n3行的下一行】
    • :n1,n2 m n3: 将n1行到n2行之间的内容移至到第n3行下
    • J: 把下一行的数据连接到本行之后, 多一空格
    • ~: 改变当前光标下字符的大小写

    其他

    • .: 重复前一指令
    • u: 取消前一指令undo, :u也行,一般不用,操作太多
    • Ctrl + r: 恢复【只对u有效】redo
    • Ctrl + l: 刷新屏幕显示
    • Ctrl+v 然后 ctrl+A是^A Ctrl+I是\t: 输入特殊字符
    • Ctrl+v然后用j、k、l、h或方向键上下选中多列,之后 I I a A r x等,最后按esc,生效: Vim列操作

    VIM Cheet Sheet

    2.文本处理工具

    2.1.显示文本内容cat

    命令cat主要参数说明:

    • -E:显示行结束符$
    • -A:显示所有控制符
    • -n:对显示出的每一行进行编号
    • -b:非空行编号
    • -s:压缩连续的空行成一行

    举例:

    cat -nA user-list.txt
    -     1  user0$
    -     2  user1$
    -     3  user2$
    -     4  user3$
    -     5  user4$
    -     6  user5$
    -     7  user6$
    -     8  user7$
    -     9  user8$
    -    10  user9$
    -

    2.2.显示文本行号nl

    相当于命令cat -b

    命令nl主要参数说明:

    • -b :指定行号指定的方式,主要有两种:
    • -b a :表示不论是否为空行,也同样列出行号(类似 cat -n);
    • -b t :如果有空行,空的那一行不要列出行号(默认值);
    • -n :列出行号表示的方法,主要有三种:
    • -n ln :行号在屏幕的最左方显示;没有前导0;
    • -n rn :行号在自己栏位的最右方显示,没有前导0;
    • -n rz :行号在自己栏位的最右方显示,有前导0;
    • -w :行号栏位的占用的位数。
    • -p :在逻辑定界符处不重新开始计

    举例:

    $ nl -b a -n rz user-list.txt
    -000001  user0
    -000002  user1
    -000003  user2
    -000004  user3
    -000005  user4
    -000006  user5
    -000007  user6
    -000008  user7
    -000009  user8
    -000010  user9
    -

    2.3.逆向显示文本内容tac

    命令tac逆向显示文本内容。

    举例:

    $ tac user-list.txt
    + 第四章 文本编辑 - UPSkilling       

    第四章 文本编辑

    1.文本编辑器

    1.1.vim工具

    vim命令格式:

    • +# file: 打开文件后,让光标处于第#行首,+默认行尾
    • +/PATTERN file: 打开文件有,让光标处于第一个被PATTERN匹配到的行首
    • -b file: 二进制方式打开文件
    • -d file1 file2 ...: 比较多个文件,相当于vimdiff
    • -m file: 只读方式打开文件
    • -e file: 进入ex模式,相当于ex file
    • -y file:

    vim三种常见模式:

    • 普通模式Normal或命令模式
    • 插入Insert或编辑模式
    • 扩展命令模式Extended Command

    三种模式切换

    • 命令模式→插入模式
    • i:insert,在光标处输入
    • I:在光标所在行首输入
    • a:append,在光标处后面输入
    • A:在光标所在行尾输入
    • o:在光标所在行的下方打开一个新行
    • O:在光标所在行的上方打开一个新行
    • 插入模式→ ESC → 命令模式
    • 命令模式→ : → 扩展命令模式
    • 扩展命令模式→ ESC, enter → 命令模式

    扩展命令模式常用命令:

    • :wq: 保存文件并退出
    • :w: 保存文件
    • :w filename: 写入指定文件,相当于另存为
    • :q!: 放弃任何修改并退出
    • ZQ: 无条件退出
    • :join: 合并多行
    • J: 合并两行

    设置:(可以在/etc/vimrc文件中配置)

    • :set textwidth: 设置文本宽度(从左向右计数)
    • :set wrapmargin=#: 设置行边距(从右向左计数)
    • :set endofline: 设置文件结束符
    • :set noendofline: 取消文件结束符
    • :set wrap: 自动换行
    • :set nowrap: 取消自动换行
    • :set number: 显示行号
    • :set nonumber: 取消显示行号
    • :set list: 进入List Mode,显示Tab ^I,换行符,和$显示
    • :set nolist: 退出List Mode
    • :set ignorecase: 忽略字符的大小写
    • :set noic: 不忽略字符大小写
    • :set autoindent: 启用自动缩进
    • :set noai: 关闭自动缩进
    • :set hlsearch: 启用高亮搜索
    • :set nohlsearch: 关闭高亮搜索
    • :set fileformat=dos: 启用windows格式
    • :set fileformat=unix: 启用unix格式
    • :set expandtab: 启用空格代替TAB,默认8个空格代替一个TAB
    • :set noexpandtab: 关闭空格代替TAB
    • :set tabstop=#: 指定#个空格代替一个TAB
    • :set shiftwidth=#: 设置#个缩进宽度
    • :set cursorline: 设置光标所在行的表示线
    • :set cursorline: 关闭光标所在行的表示线
    • :set key=PASSWORD: 启用密码保护
    • :set key=: 关闭密码保护
    • :help option-list: 获取帮助

    查找

    • /pattern: 从光标开始处向文件尾搜索pattern
    • ?pattern: 从光标开始处向文件首搜索pattern
    • n: 在同一方向重复上一次搜索命令
    • N: 在反方向上重复上一次搜索命令
    • #: 向上完整匹配光标下的单词, 相当于?word
    • *: 向下完整匹配光标下的单词, 相当于/word
    • %: 查找对应的( [ {匹配
    • nfx: 在当前行查找光标后第n个x(一般直接fx)

    替换

    • :%s/\n//g: 删除换行符
    • :s/p1/p2/g: 将当前行中所有p1均用p2替代, 无g,则只替换第一个
    • :s/p1/p2/c: 查找替换要求确认
    • :n1,n2s/p1/p2/g: 将第n1至n2行中所有p1均用p2替代
    • :%s/p1/p2/g: 全局,使用p2替换p1
    • :%s/p1/p2/gc: 替换前询问
    • :n,$s/vivian/sky/: 替换第n行开始到最后一行中每一行的第一个vivian为sky,n为数字
    • :.,$s/vivian/sky/g: 替换当前行开始到最后一行中每一行所有vivian为sky
    • :s/vivian\//sky\//: 替换当前行第一个vivian/为sky/,可以使用\作为转义符
    • :1,$s/^/some string/: 在文件的第一行至最后一行的行首前插入some string
    • :%s/$/some string/g: 在整个文件每一行的行尾添加some string
    • :%s/\s\+$//: 去掉所有的行尾空格,“\s”表示空白字符(空格和制表符),“+”对前面的字符匹配一次或多次(越多越好),“\(”匹配行尾(使用“\$”表示单纯的“\)”字符)
    • :%s/\s∗\n\+/\r/: 去掉所有的空白行,“\(”和“\)”对表达式进行分组,使其被视作一个不可分割的整体
    • :%s!\s*//.*!!: 去掉所有的“//”注释
    • :%s!\s*/\*\_.\{-}\*/\s*!!g: 去掉所有的“/**/”注释
    • :%s= *$==: 将所有行尾多余的空格删除
    • :g/^\s*$/d: 将所有不包含字符(空格也不包含)的空行删除
    • r: 替换当前字符
    • R: 替换当前字符及其后的字符,直至按ESC键

    编辑

    • h: 光标左移一个字符[回退键Backspace]
    • l: 光标右移一个字符[空格键Space]
    • K: 光标上移一行
    • j: 光标下移一行
    • w: 光标跳到下个word的第一个字母(包括标点符号) [常用]
    • W: 移到下一个字的开头,忽略标点符号
    • B: 光标回到上个word的第一个字母
    • B: 移到前一个字的开头,忽略标点符号 BACK
    • E: 光标跳到下个word的最后一个字母
    • E: 移到下一个字的结尾,忽略标点符号 END
    • 0: 移到当前一行的开始[Home]
    • $: 移到当前一行的最后[End]
    • ^: 命令将光标移动到当前行的第一个非空白字符上
    • g_: 到本行最后一个不是blank字符的位置
    • Enter: 光标下移一行
    • n+: 光标下移n行【按上档键 数字shift +】
    • n-: 光标上移n行
    • G: 移到文件的最后一行
    • nG或者:n: 移到文件的第n行
    • gg: 移动到文档的开始
    • [[: 文件开始位置——开始行
    • ]]: 文件结束位置——末尾行
    • H: 光标移至屏幕顶行HEAD。光标定位在显示屏的第一行
    • M: 移到屏幕的中间行开头 Middle。光标定位在显示屏的中间
    • L: 移到屏幕的最后一行LAST。光标定位在显示屏的最后一行
    • (: 光标移至句首
    • ): 光标移至句尾
    • {: 移到段落的开头
    • }: 移到下一个段落的开头
    • %: 匹配括号移动,包括 (, {, [.(需要把光标先移到括号上)跳转到与之匹配的括号处
    • *#: 匹配光标当前所在的单词,移动光标到下一个(或上一个)匹配单词(*是下一个,#是上一个)
    • zf: 折叠(需加方向键)
    • zo: 展开(空格也可以展开)
    • CTRL+u: 向文件首翻半屏up
    • CTRL+d: 向文件尾翻半屏down
    • CTRL+f: 向文件尾翻一屏 forward (fact整屏去两行)
    • CTRL+b: 向文件首翻一屏back (fact整屏去两行)
    • CTRL-]: 跳转到当前光标所在单词对应的主题
    • CTRL-O: 回到前一个位置
    • SHIFT+V: 选择整行
    • zz: 命令会把当前行置为屏幕正中央(z字取其象形意义模拟一张纸的折叠及变形位置重置)
    • zt: 命令会把当前行置于屏幕顶端(top)
    • zb: 命令会把当前行置于屏幕底端(bottom)
    • 50%: 光标定位在文件的中间
    • `: 跳转到最近光标定位的位置(只能记忆最近两个位置) 反引号
    • I: 在光标前开始插入字符 insert
    • I: 在当前行首开始插入字符
    • A: 在光标位置后开始加字 append
    • A: 在光标所在行的最后面开始加字
    • O: 在光标下加一空白行并开始加字 open
    • O: 在光标上加一空白行并开始加字
    • R: 替换当前字符
    • R: 替换当前字符及其后的字符【当前及其后字符被覆盖】
    • S: 默认删除光标所在字符,输入内容插入之= xi
    • S: 默认删除当前行内容,输入内容作为当前行新内容= dd+o
    • nx: 删除由光标位置起始后的n个字符(含光标位置)x =dl(删除当前光标下的字符)
    • nX: 删除由光标位置起始前的n个字符(含光标位置)X =dh(删除当前光标左边的字符)
    • d0: 删至行首
    • d$: 删至行尾
    • dfa: 表示删除从当前光标到光标后面的第一个a字符之间的内容
    • D: 代表d$(删除到行尾的内容)
    • C: 代表c$(修改到行尾的内容)
    • ndw: 删除光标处开始及其后的n-1个字
    • ndb: 删除光标处开始及其前的n-1个字
    • diw: 删除当前光标所在的word(不包括空白字符),意为Delete Inner Word 两个符号之间的单词
    • daw: 删除当前光标所在的word(包括空白字符),意为Delete A Word
    • ndd: 删除当前行及其后n-1行
    • :n1,n2 d: 将 n1行到n2行之间的内容删除
    • dG: 删除当前行至文件尾的内容
    • Dgg: 删除当前行至文件头的内容
    • d+enter: 删除2行【包括光标一行】
    • cw: 删除当前字,并进入输入模式【很好用,快速更改一个单词】相当于dw+i
    • ncw: 删除当前字及其后的n-1个字,并进入输入模式\修改指定数目的字
    • cc: 删除当前行,并进入输入模式
    • ncc: 删除当前行及其后的n-1行,并进入输入模式
    • guw: 光标下的单词变为小写
    • gUw: 光标下的单词变为大写
    • xp: 左右交换光标处两字符的位置
    • ga: 显示光标下的字符在当前使用的encoding下的内码
    • nyl: 复制n个字符(也可nyh)
    • yw: 复制一个单词
    • y0: 表示拷贝从当前光标到光标所在行首的内容
    • y$: 复制从当前位置到行尾
    • yfa: 表示拷贝从当前光标到光标后面的第一个a字符之间的内容
    • yG: 复制从所在行到最后一行
    • nyy: 将光标所在位置开始的n行数据复制暂存, 复制一整行
    • CTRL+v 方向y: 列选择模式,复制选择的很多行:先使用V进入visual模式,然后j向下移动到你想复制的行为止,然后y
    • p: 复制暂存数据在光标的下一行
    • P: 复制暂存数据在光标的上一行
    • :n1,n2 co n3: 将n1行到n2行之间的内容拷贝到第n3+1行【n3行的下一行】
    • :n1,n2 m n3: 将n1行到n2行之间的内容移至到第n3行下
    • J: 把下一行的数据连接到本行之后, 多一空格
    • ~: 改变当前光标下字符的大小写

    其他

    • .: 重复前一指令
    • u: 取消前一指令undo, :u也行,一般不用,操作太多
    • Ctrl + r: 恢复【只对u有效】redo
    • Ctrl + l: 刷新屏幕显示
    • Ctrl+v 然后 ctrl+A是^A Ctrl+I是\t: 输入特殊字符
    • Ctrl+v然后用j、k、l、h或方向键上下选中多列,之后 I I a A r x等,最后按esc,生效: Vim列操作

    VIM Cheet Sheet

    2.文本处理工具

    2.1.显示文本内容cat

    命令cat主要参数说明:

    • -E:显示行结束符$
    • -A:显示所有控制符
    • -n:对显示出的每一行进行编号
    • -b:非空行编号
    • -s:压缩连续的空行成一行

    举例:

    cat -nA user-list.txt
    +     1  user0$
    +     2  user1$
    +     3  user2$
    +     4  user3$
    +     5  user4$
    +     6  user5$
    +     7  user6$
    +     8  user7$
    +     9  user8$
    +    10  user9$
    +

    2.2.显示文本行号nl

    相当于命令cat -b

    命令nl主要参数说明:

    • -b :指定行号指定的方式,主要有两种:
    • -b a :表示不论是否为空行,也同样列出行号(类似 cat -n);
    • -b t :如果有空行,空的那一行不要列出行号(默认值);
    • -n :列出行号表示的方法,主要有三种:
    • -n ln :行号在屏幕的最左方显示;没有前导0;
    • -n rn :行号在自己栏位的最右方显示,没有前导0;
    • -n rz :行号在自己栏位的最右方显示,有前导0;
    • -w :行号栏位的占用的位数。
    • -p :在逻辑定界符处不重新开始计

    举例:

    $ nl -b a -n rz user-list.txt
    +000001  user0
    +000002  user1
    +000003  user2
    +000004  user3
    +000005  user4
    +000006  user5
    +000007  user6
    +000008  user7
    +000009  user8
    +000010  user9
    +

    2.3.逆向显示文本内容tac

    命令tac逆向显示文本内容。

    举例:

    $ tac user-list.txt
     user9
     user8
     user7
    @@ -31,7 +31,7 @@
     user2
     user1
     user0
    -

    举例:

    $ seq 10 | tac
    +

    举例:

    $ seq 10 | tac
     10
     9
     8
    @@ -42,7 +42,7 @@
     3
     2
     1
    -

    2.4.逆向显示同行内容rev

    命令rev逆向显示同一行的内容。

    举例:

    $ rev user-list.txt
    +

    2.4.逆向显示同行内容rev

    命令rev逆向显示同一行的内容。

    举例:

    $ rev user-list.txt
     0resu
     1resu
     2resu
    @@ -53,20 +53,20 @@
     7resu
     8resu
     9resu
    -

    举例:

    $ echo {1..10} | rev
    -01 9 8 7 6 5 4 3 2 1
    -

    2.5.显示非文本文件内容hexdump

    命令hexdump命令一般用来查看“二进制”文件的十六进制编码

    举例:

    $ hexdump -C -n 32 cp
    -00000000  7f 45 4c 46 02 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
    -00000010  03 00 3e 00 01 00 00 00  e0 48 00 00 00 00 00 00  |..>......H......|
    +

    举例:

    $ echo {1..10} | rev
    +01 9 8 7 6 5 4 3 2 1
    +

    2.5.显示非文本文件内容hexdump

    命令hexdump命令一般用来查看“二进制”文件的十六进制编码

    举例:

    $ hexdump -C -n 32 cp
    +00000000  7f 45 4c 46 02 01 01 00  00 00 00 00 00 00 00 00  |.ELF............|
    +00000010  03 00 3e 00 01 00 00 00  e0 48 00 00 00 00 00 00  |..>......H......|
     00000020
    -

    2.6.分页查看文件内容

    命令moreless可以实现分页查看文件内容。

    命令less配合管道符使用。

    tree -d /etc | less
    -

    2.7.显示文件头部内容head

    命令head显示文件头部内容。

    • head -c 20 cp: 显示文件前20字节内容
    • head -n 20 zdiff: 显示文件前20行内容
    • head -20 zdiff: 显示文件前20行内容
    $ echo "我是谁" | head -c3
    +

    2.6.分页查看文件内容

    命令moreless可以实现分页查看文件内容。

    命令less配合管道符使用。

    tree -d /etc | less
    +

    2.7.显示文件头部内容head

    命令head显示文件头部内容。

    • head -c 20 cp: 显示文件前20字节内容
    • head -n 20 zdiff: 显示文件前20行内容
    • head -20 zdiff: 显示文件前20行内容
    $ echo "我是谁" | head -c3
     我
     
    -$ echo "我是谁" | head -c6
    +$ echo "我是谁" | head -c6
     我是
    -
    cat /dev/urandom | tr -dc '[:alnum]' | head -c 10 | tee passwd.txt
    -
    $ cat user-list.txt
    +
    cat /dev/urandom | tr -dc '[:alnum]' | head -c 10 | tee passwd.txt
    +
    $ cat user-list.txt
     user0
     user1
     user2
    @@ -78,7 +78,7 @@
     user8
     user9
     
    -$ head -n -3 user-list.txt
    +$ head -n -3 user-list.txt
     user0
     user1
     user2
    @@ -86,44 +86,44 @@
     user4
     user5
     user6
    -

    2.8.显示文件尾部内容tail

    命令tail显示文件头部内容。

    • tail -c 200 cp: 显示文件尾部200个字节的内容
    • tail -n 3 user-list.txt: 显示文件最后3行
    • tail -n -3 user-list.txt: 显示从-3行到文件结束(即最后三行)
    • tail -3 user-list.txt: 显示文件最后3行
    • tail -f /var/log/messages: 跟踪显示文件redo.log文件内容,当文件删除,再建同名文件,无法继续追踪
    • tail -F /var/log/messages: 跟踪显示文件redo.log文件内容,当文件删除,再建同名文件,继续追踪

    2.9.按列抽取文本cut

    命令cut可以提取文本文件或者stdin数据的指定列内容。

    选项:

    • -f : 通过指定哪一个字段进行提取。cut命令使用“TAB”作为默认的字段分隔符
    • -d : “TAB”是默认的分隔符,使用此选项可以更改为其他的分隔符
    • --complement : 此选项用于排除所指定的字段
    • --output-delimiter=STRING : 指定输出内容的分隔符
    • -c: 按字符切割

    取/etc/passwd文件第1列内容,以:为分隔符(只取前三行)

    $ cut -d ':' -f 1 /etc/passwd | head -3
    +

    2.8.显示文件尾部内容tail

    命令tail显示文件头部内容。

    • tail -c 200 cp: 显示文件尾部200个字节的内容
    • tail -n 3 user-list.txt: 显示文件最后3行
    • tail -n -3 user-list.txt: 显示从-3行到文件结束(即最后三行)
    • tail -3 user-list.txt: 显示文件最后3行
    • tail -f /var/log/messages: 跟踪显示文件redo.log文件内容,当文件删除,再建同名文件,无法继续追踪
    • tail -F /var/log/messages: 跟踪显示文件redo.log文件内容,当文件删除,再建同名文件,继续追踪

    2.9.按列抽取文本cut

    命令cut可以提取文本文件或者stdin数据的指定列内容。

    选项:

    • -f : 通过指定哪一个字段进行提取。cut命令使用“TAB”作为默认的字段分隔符
    • -d : “TAB”是默认的分隔符,使用此选项可以更改为其他的分隔符
    • --complement : 此选项用于排除所指定的字段
    • --output-delimiter=STRING : 指定输出内容的分隔符
    • -c: 按字符切割

    取/etc/passwd文件第1列内容,以:为分隔符(只取前三行)

    $ cut -d ':' -f 1 /etc/passwd | head -3
     root
     messagebus
     systemd-network
    -

    取/etc/passwd文件第1和6列内容,以:为分隔符(只取前三行)

    cut -d ':' -f 1,6 /etc/passwd | head -3
    +

    取/etc/passwd文件第1和6列内容,以:为分隔符(只取前三行)

    cut -d ':' -f 1,6 /etc/passwd | head -3
     root:/root
     messagebus:/run/dbus
     systemd-network:/
    -

    取/etc/passwd文件第1到3列以及第6列内容,以:为分隔符(只取前三行)

    $ cut -d ':' -f 1-3,6 /etc/passwd | head -3
    +

    取/etc/passwd文件第1到3列以及第6列内容,以:为分隔符(只取前三行)

    $ cut -d ':' -f 1-3,6 /etc/passwd | head -3
     root:x:0:/root
     messagebus:x:499:/run/dbus
     systemd-network:x:497:/
    -

    下面使用--output-delimiter选项,把输出结果中的分隔符:全部替换成---

    $ cat /etc/passwd | sort | head -3
    +

    下面使用--output-delimiter选项,把输出结果中的分隔符:全部替换成---

    $ cat /etc/passwd | sort | head -3
     admin3:x:1020:100::/home/admin3:/bin/bash
    -at:x:25:25:Batch jobs daemon:/var/spool/atjobs:/usr/sbin/nologin
    +at:x:25:25:Batch jobs daemon:/var/spool/atjobs:/usr/sbin/nologin
     bin:x:1:1:bin:/bin:/usr/sbin/nologin
     
    -$ cut -d ":" -f 1,7 /etc/passwd | sort | head -3
    +$ cut -d ":" -f 1,7 /etc/passwd | sort | head -3
     admin3:/bin/bash
     at:/usr/sbin/nologin
     bin:/usr/sbin/nologin
     
    -$ cut -d ":" -f 1,7 --output-delimiter="---" /etc/passwd | sort | head -3
    +$ cut -d ":" -f 1,7 --output-delimiter="---" /etc/passwd | sort | head -3
     admin3---/bin/bash
     at---/usr/sbin/nologin
     bin---/usr/sbin/nologin
    -

    --output-delimiter选项也可以利用来进行计算。

    $ echo {1..10} | cut -d " " -f 1-10 --output-delimiter="+" | bc
    +

    --output-delimiter选项也可以利用来进行计算。

    $ echo {1..10} | cut -d " " -f 1-10 --output-delimiter="+" | bc
     55
    -

    ifconfig命令中截取当前主机的ip地址。(openSUSE需要安装包net-tools-deprecated

    $ ifconfig | head -2 | tail -1
    -        inet 192.168.10.210  netmask 255.255.255.0  broadcast 192.168.10.255
    +

    ifconfig命令中截取当前主机的ip地址。(openSUSE需要安装包net-tools-deprecated

    $ ifconfig | head -2 | tail -1
    +        inet 192.168.10.210  netmask 255.255.255.0  broadcast 192.168.10.255
     
    -$ ifconfig | head -2 | tail -1 | cut -d " " -f 10
    +$ ifconfig | head -2 | tail -1 | cut -d " " -f 10
     192.168.10.210
    -

    或者

    $ ip addr list | grep eth0 | tail -1 | cut -d " " -f 6
    +

    或者

    $ ip addr list | grep eth0 | tail -1 | cut -d " " -f 6
     192.168.10.210/24
    -

    基于上面结果,可以尝试通过--complement参数,以/为分隔符,排除第二列24,只输出第一列IP地址。

    ip addr list | grep eth0 | tail -1 | cut -d " " -f 6 | cut -d "/" --complement -f 2
    +

    基于上面结果,可以尝试通过--complement参数,以/为分隔符,排除第二列24,只输出第一列IP地址。

    ip addr list | grep eth0 | tail -1 | cut -d " " -f 6 | cut -d "/" --complement -f 2
     192.168.10.210
    -

    显示df命令输出中的分区使用率。

    $ df | tr -s ' ' | cut -d ' ' -f 5 | tr -d %
    +

    显示df命令输出中的分区使用率。

    $ df | tr -s ' ' | cut -d ' ' -f 5 | tr -d %
     Use
     0
     0
    @@ -141,7 +141,7 @@
     8
     8
     0
    -

    方法2:先把空格全部替换成%,再去重。

    df | tr -s ' ' % | cut -d % -f 5
    +

    方法2:先把空格全部替换成%,再去重。

    df | tr -s ' ' % | cut -d % -f 5
     Use
     0
     0
    @@ -159,20 +159,20 @@
     8
     8
     0
    -

    2.10.合并多个文件paste

    命令paste常用选项:

    • -d:指定分隔符,默认是TAB
    • -s:所有行合成一行显示

    生成alpha.logseq.log

    for i in {a..z}; do echo $i >> alpha.log; done
    -
    -seq 10 > seq.log
    -

    paste命令合并这2个文件。

    $ paste alpha.log seq.log
    -a       1
    -b       2
    -c       3
    -d       4
    -e       5
    -f       6
    -g       7
    -h       8
    -i       9
    -j       10
    +

    2.10.合并多个文件paste

    命令paste常用选项:

    • -d:指定分隔符,默认是TAB
    • -s:所有行合成一行显示

    生成alpha.logseq.log

    for i in {a..z}; do echo $i >> alpha.log; done
    +
    +seq 10 > seq.log
    +

    paste命令合并这2个文件。

    $ paste alpha.log seq.log
    +a       1
    +b       2
    +c       3
    +d       4
    +e       5
    +f       6
    +g       7
    +h       8
    +i       9
    +j       10
     k
     l
     m
    @@ -190,7 +190,7 @@
     y
     z
     
    -$ paste -d ":" alpha.log seq.log
    +$ paste -d ":" alpha.log seq.log
     a:1
     b:2
     c:3
    @@ -217,268 +217,268 @@
     x:
     y:
     z:
    -

    原文件都是列输出,改成行输出。

    $ paste -d "-" -s alpha.log
    +

    原文件都是列输出,改成行输出。

    $ paste -d "-" -s alpha.log
     a-b-c-d-e-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z
     
    -$ paste -d "-" -s seq.log
    +$ paste -d "-" -s seq.log
     
    -$ paste -d ":" -s alpha.log seq.log
    +$ paste -d ":" -s alpha.log seq.log
     a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z
     1:2:3:4:5:6:7:8:9:10
     
    -$ paste -d ":" -s seq.log alpha.log
    +$ paste -d ":" -s seq.log alpha.log
     1:2:3:4:5:6:7:8:9:10
     a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z
    -

    2.11.文本统计数据wc

    常用选项:

    • -l:只计数行数
    • -w:只计数单词总数
    • -c:只计数字节总数
    • -m:只计数字符总数
    • -L:显示文件中最长行的长度
    $ cat text
    -Tom, 20, Shanghai
    -Jack, 30, Beijing
    -Smith, 40, Guangzhou
    -
    -$ wc text  # 行数 单词数 字节数
    - 3  9 57 text
    -
    -$ wc -l text
    -3 text
    -
    -$ wc -w text
    -9 text
    -
    -$ wc -c text
    -57 text
    -
    -$ wc -m text
    -57 text
    -
    -$ wc -L text
    -20 text
    -

    对比两种不同合并的方法。

    $ cat text1 text2
    -Tom, 20, Shanghai
    -Jack, 30, Beijing
    -Smith, 40, Guangzhou
    -Tom, 20, Shanghai
    -Jack, 30, Beijing
    -Leo, 40, Guangzhou
    -
    -$ paste text1 text2
    -Tom, 20, Shanghai       Tom, 20, Shanghai
    -Jack, 30, Beijing       Jack, 30, Beijing
    -Smith, 40, Guangzhou    Leo, 40, Guangzhou
    -

    2.12.文本排序sort

    命令sort把整理过的文本显示在stdout上,不改变原文件。

    常用选项:

    • -r:执行反方向(从上至下)排序
    • -R:随机排序
    • -n:按数字大小排序
    • -h:人类可读排序,如:2K,1G
    • -f:排序时将小写字母视为大写字母
    • -u:排序时合并重复项
    • -t c:使用c作为字段分隔符
    • -k #:按照以c为分隔符的第#列来排序

    举例:以,为分隔符,读取text文件内容中第1,3列,对输出结果以,为分隔符,按第二列排序(正序和反序)。

    $ cat text
    -Tom, 20, Shanghai
    -Jack, 30, Beijing
    -Smith, 40, Guangzhou
    -
    -$ cut -d "," -f 1,3 text | sort -t "," -k 1
    -Jack, Beijing
    -Smith, Guangzhou
    -Tom, Shanghai
    -
    -$ cut -d "," -f 1,3 text | sort -t "," -k 1 -r
    -Tom, Shanghai
    -Smith, Guangzhou
    -Jack, Beijing
    -

    把文件text1和文件text2合并后去重输出。

    $ cat text2
    -Tom, 20, Shanghai
    -Jack, 30, Beijing
    -Leo, 40, Guangzhou
    -
    -$ cat text1
    -Tom, 20, Shanghai
    -Jack, 30, Beijing
    -Smith, 40, Guangzhou
    -
    -$ cat text1 text2
    -Tom, 20, Shanghai
    -Jack, 30, Beijing
    -Smith, 40, Guangzhou
    -Tom, 20, Shanghai
    -Jack, 30, Beijing
    -Leo, 40, Guangzhou
    -

    并集,重复行只保留一行。前面2个命令是同样含义(相同的排序列),第三个命令中对不同列进行了排序,导致去重结果不同。

    $ cat text1 text2 | sort -u
    -Jack, 30, Beijing
    -Leo, 40, Guangzhou
    -Smith, 40, Guangzhou
    -Tom, 20, Shanghai
    -
    -$ cat text1 text2 | sort -t "," -k 1 -u
    -Jack, 30, Beijing
    -Leo, 40, Guangzhou
    -Smith, 40, Guangzhou
    -Tom, 20, Shanghai
    -
    -$ cat text1 text2 | sort -t "," -k 2 -u
    -Tom, 20, Shanghai
    -Jack, 30, Beijing
    -Smith, 40, Guangzhou
    -

    2.13.去重uniq

    命令uniq从输入中删除前后相邻重复的行。经常与sort命令结合使用。

    主要参数:

    • -c:显示每行重复出现的次数
    • -d:仅显示重复的行
    • -u:仅显示不重复的行

    举例,注意只有对相邻行进行去重。

    $ cat text3
    -test 30
    -Hello 95
    -Hello 95
    -Linux 85
    -Linux 85
    -Hello 95
    -test 30
    -
    -$ uniq text3
    -test 30
    -Hello 95
    -Linux 85
    -Hello 95
    -test 30
    -

    把文件text1和文件text2合并后,进行交集和并集,并去重。

    $ cat text1
    -Tom, 20, Shanghai
    -Jack, 30, Beijing
    -Smith, 40, Guangzhou
    -
    -$ cat text2
    -Tom, 20, Shanghai
    -Jack, 30, Beijing
    -Leo, 40, Guangzhou
    +

    2.11.文本统计数据wc

    常用选项:

    • -l:只计数行数
    • -w:只计数单词总数
    • -c:只计数字节总数
    • -m:只计数字符总数
    • -L:显示文件中最长行的长度
    $ cat text
    +Tom, 20, Shanghai
    +Jack, 30, Beijing
    +Smith, 40, Guangzhou
    +
    +$ wc text  # 行数 单词数 字节数
    + 3  9 57 text
    +
    +$ wc -l text
    +3 text
    +
    +$ wc -w text
    +9 text
    +
    +$ wc -c text
    +57 text
    +
    +$ wc -m text
    +57 text
    +
    +$ wc -L text
    +20 text
    +

    对比两种不同合并的方法。

    $ cat text1 text2
    +Tom, 20, Shanghai
    +Jack, 30, Beijing
    +Smith, 40, Guangzhou
    +Tom, 20, Shanghai
    +Jack, 30, Beijing
    +Leo, 40, Guangzhou
    +
    +$ paste text1 text2
    +Tom, 20, Shanghai       Tom, 20, Shanghai
    +Jack, 30, Beijing       Jack, 30, Beijing
    +Smith, 40, Guangzhou    Leo, 40, Guangzhou
    +

    2.12.文本排序sort

    命令sort把整理过的文本显示在stdout上,不改变原文件。

    常用选项:

    • -r:执行反方向(从上至下)排序
    • -R:随机排序
    • -n:按数字大小排序
    • -h:人类可读排序,如:2K,1G
    • -f:排序时将小写字母视为大写字母
    • -u:排序时合并重复项
    • -t c:使用c作为字段分隔符
    • -k #:按照以c为分隔符的第#列来排序

    举例:以,为分隔符,读取text文件内容中第1,3列,对输出结果以,为分隔符,按第二列排序(正序和反序)。

    $ cat text
    +Tom, 20, Shanghai
    +Jack, 30, Beijing
    +Smith, 40, Guangzhou
    +
    +$ cut -d "," -f 1,3 text | sort -t "," -k 1
    +Jack, Beijing
    +Smith, Guangzhou
    +Tom, Shanghai
    +
    +$ cut -d "," -f 1,3 text | sort -t "," -k 1 -r
    +Tom, Shanghai
    +Smith, Guangzhou
    +Jack, Beijing
    +

    把文件text1和文件text2合并后去重输出。

    $ cat text2
    +Tom, 20, Shanghai
    +Jack, 30, Beijing
    +Leo, 40, Guangzhou
    +
    +$ cat text1
    +Tom, 20, Shanghai
    +Jack, 30, Beijing
    +Smith, 40, Guangzhou
    +
    +$ cat text1 text2
    +Tom, 20, Shanghai
    +Jack, 30, Beijing
    +Smith, 40, Guangzhou
    +Tom, 20, Shanghai
    +Jack, 30, Beijing
    +Leo, 40, Guangzhou
    +

    并集,重复行只保留一行。前面2个命令是同样含义(相同的排序列),第三个命令中对不同列进行了排序,导致去重结果不同。

    $ cat text1 text2 | sort -u
    +Jack, 30, Beijing
    +Leo, 40, Guangzhou
    +Smith, 40, Guangzhou
    +Tom, 20, Shanghai
    +
    +$ cat text1 text2 | sort -t "," -k 1 -u
    +Jack, 30, Beijing
    +Leo, 40, Guangzhou
    +Smith, 40, Guangzhou
    +Tom, 20, Shanghai
    +
    +$ cat text1 text2 | sort -t "," -k 2 -u
    +Tom, 20, Shanghai
    +Jack, 30, Beijing
    +Smith, 40, Guangzhou
    +

    2.13.去重uniq

    命令uniq从输入中删除前后相邻重复的行。经常与sort命令结合使用。

    主要参数:

    • -c:显示每行重复出现的次数
    • -d:仅显示重复的行
    • -u:仅显示不重复的行

    举例,注意只有对相邻行进行去重。

    $ cat text3
    +test 30
    +Hello 95
    +Hello 95
    +Linux 85
    +Linux 85
    +Hello 95
    +test 30
    +
    +$ uniq text3
    +test 30
    +Hello 95
    +Linux 85
    +Hello 95
    +test 30
    +

    把文件text1和文件text2合并后,进行交集和并集,并去重。

    $ cat text1
    +Tom, 20, Shanghai
    +Jack, 30, Beijing
    +Smith, 40, Guangzhou
    +
    +$ cat text2
    +Tom, 20, Shanghai
    +Jack, 30, Beijing
    +Leo, 40, Guangzhou
     
     # 并集,按首列排序去重
    -$ cat text1 text2 | sort | uniq
    -Jack, 30, Beijing
    -Leo, 40, Guangzhou
    -Smith, 40, Guangzhou
    -Tom, 20, Shanghai
    +$ cat text1 text2 | sort | uniq
    +Jack, 30, Beijing
    +Leo, 40, Guangzhou
    +Smith, 40, Guangzhou
    +Tom, 20, Shanghai
     
     # 交集
    -$ cat text1 text2 | sort | uniq -d
    -Jack, 30, Beijing
    -Tom, 20, Shanghai
    +$ cat text1 text2 | sort | uniq -d
    +Jack, 30, Beijing
    +Tom, 20, Shanghai
     
     # 差集
    -$ cat text1 text2 | sort | uniq -u
    -Leo, 40, Guangzhou
    -Smith, 40, Guangzhou
    -

    查看并发连接数最多的远程主机IP。

    $ ss -nt
    -State         Recv-Q         Send-Q                    Local Address:Port                      Peer Address:Port          Process
    -ESTAB         0              0                        192.168.10.210:22                      192.168.10.210:41650
    -ESTAB         0              0                        192.168.10.210:22                      192.168.10.201:65330
    -ESTAB         0              64                       192.168.10.210:22                      192.168.10.201:63289
    -ESTAB         0              0                        192.168.10.210:41650                   192.168.10.210:22
    -ESTAB         0              0                        192.168.10.210:47992                   192.168.10.210:22
    -ESTAB         0              0                        192.168.10.210:60268                   192.168.10.210:22
    -ESTAB         0              0                        192.168.10.210:22                      192.168.10.201:65327
    -ESTAB         0              0                        192.168.10.210:35758                   192.168.10.220:22
    -ESTAB         0              0                        192.168.10.210:22                      192.168.10.210:56818
    -ESTAB         0              0                        192.168.10.210:56818                   192.168.10.210:22
    -ESTAB         0              0                        192.168.10.210:48006                   192.168.10.210:22
    -ESTAB         0              0                        192.168.10.210:22                      192.168.10.210:60268
    -ESTAB         0              0                        192.168.10.210:22                      192.168.10.220:33896
    -ESTAB         0              0                        192.168.10.210:22                      192.168.10.201:65324
    -ESTAB         0              0                        192.168.10.210:22                      192.168.10.210:47992
    -ESTAB         0              0                        192.168.10.210:59554                   192.168.10.210:22
    -ESTAB         0              0                        192.168.10.210:22                      192.168.10.210:59554
    -ESTAB         0              0                        192.168.10.210:22                      192.168.10.210:48006
    -
    -$ ss -nt | tr -s " " ":" | cut -d ":" -f 6,7 | sort | uniq -c | sort -nr | head -n 1
    -      6 192.168.10.210:22
    -

    2.14.文本比较

    2.14.1.diff

    命令diff比较两个文件之间的区别。

    常用选项:

    • -u:以统一的方式来显示文件内容的不同
    • -y:以并列的方式显示文件的异同之处
    • -W:在使用-y参数时,指定栏宽
    • -c:显示全部内文,并标出不同之处
    • -N:缺失文件以空文件处理

    举例:

    $ cat text5 # 文件尾部没有空行
    +$ cat text1 text2 | sort | uniq -u
    +Leo, 40, Guangzhou
    +Smith, 40, Guangzhou
    +

    查看并发连接数最多的远程主机IP。

    $ ss -nt
    +State         Recv-Q         Send-Q                    Local Address:Port                      Peer Address:Port          Process
    +ESTAB         0              0                        192.168.10.210:22                      192.168.10.210:41650
    +ESTAB         0              0                        192.168.10.210:22                      192.168.10.201:65330
    +ESTAB         0              64                       192.168.10.210:22                      192.168.10.201:63289
    +ESTAB         0              0                        192.168.10.210:41650                   192.168.10.210:22
    +ESTAB         0              0                        192.168.10.210:47992                   192.168.10.210:22
    +ESTAB         0              0                        192.168.10.210:60268                   192.168.10.210:22
    +ESTAB         0              0                        192.168.10.210:22                      192.168.10.201:65327
    +ESTAB         0              0                        192.168.10.210:35758                   192.168.10.220:22
    +ESTAB         0              0                        192.168.10.210:22                      192.168.10.210:56818
    +ESTAB         0              0                        192.168.10.210:56818                   192.168.10.210:22
    +ESTAB         0              0                        192.168.10.210:48006                   192.168.10.210:22
    +ESTAB         0              0                        192.168.10.210:22                      192.168.10.210:60268
    +ESTAB         0              0                        192.168.10.210:22                      192.168.10.220:33896
    +ESTAB         0              0                        192.168.10.210:22                      192.168.10.201:65324
    +ESTAB         0              0                        192.168.10.210:22                      192.168.10.210:47992
    +ESTAB         0              0                        192.168.10.210:59554                   192.168.10.210:22
    +ESTAB         0              0                        192.168.10.210:22                      192.168.10.210:59554
    +ESTAB         0              0                        192.168.10.210:22                      192.168.10.210:48006
    +
    +$ ss -nt | tr -s " " ":" | cut -d ":" -f 6,7 | sort | uniq -c | sort -nr | head -n 1
    +      6 192.168.10.210:22
    +

    2.14.文本比较

    2.14.1.diff

    命令diff比较两个文件之间的区别。

    常用选项:

    • -u:以统一的方式来显示文件内容的不同
    • -y:以并列的方式显示文件的异同之处
    • -W:在使用-y参数时,指定栏宽
    • -c:显示全部内文,并标出不同之处
    • -N:缺失文件以空文件处理

    举例:

    $ cat text5 # 文件尾部没有空行
     1001
     1002
     1003
     
    -$ cat text6 # 文件尾部没有空行
    +$ cat text6 # 文件尾部没有空行
     1001
     1002
     1003a
     1004
    -

    显示不同。3c3,4代表两个文件在第3,4行有不同。

    $ diff text5 text6
    +

    显示不同。3c3,4代表两个文件在第3,4行有不同。

    $ diff text5 text6
     3c3,4
    -< 1003
    +< 1003
     ---
    -> 1003a
    -> 1004
    -

    以统一格式输出比较结果。

    • 前2行是文件信息。其中---表示变动前的文件,+++表示变动后的文件。
    • 变动的位置用两个@作为起首和结束,@@ -1,3 +1,4 @@
    • -1,3中,-表示第一个文件,即text5。第一个文件从第1行开始连续3行。
    • +1,4中,+表示第二个文件,即text6。即,第二个文件从第1行开始连续4行。
    $ diff -u text5 text6
    ---- text5    2022-12-07 08:07:05.927805722 +0800
    -+++ text6    2022-12-07 08:07:24.692234585 +0800
    -@@ -1,3 +1,4 @@
    - 1001
    - 1002
    +> 1003a
    +> 1004
    +

    以统一格式输出比较结果。

    • 前2行是文件信息。其中---表示变动前的文件,+++表示变动后的文件。
    • 变动的位置用两个@作为起首和结束,@@ -1,3 +1,4 @@
    • -1,3中,-表示第一个文件,即text5。第一个文件从第1行开始连续3行。
    • +1,4中,+表示第二个文件,即text6。即,第二个文件从第1行开始连续4行。
    $ diff -u text5 text6
    +--- text5    2022-12-07 08:07:05.927805722 +0800
    ++++ text6    2022-12-07 08:07:24.692234585 +0800
    +@@ -1,3 +1,4 @@
    + 1001
    + 1002
     -1003
     +1003a
     +1004
    -

    以上下文方式输出比较结果。标有!代表差异行。

    $ diff -c text5 text6
    -*** text5    2022-12-07 08:24:08.867168414 +0800
    ---- text6    2022-12-07 08:24:13.939284243 +0800
    +

    以上下文方式输出比较结果。标有!代表差异行。

    $ diff -c text5 text6
    +*** text5    2022-12-07 08:24:08.867168414 +0800
    +--- text6    2022-12-07 08:24:13.939284243 +0800
     ***************
    -*** 1,3 ****
    -  1001
    -  1002
    -! 1003
    ---- 1,4 ----
    -  1001
    -  1002
    -! 1003a
    -! 1004
    -

    并排格式输出比较结果。

    • |表示前后2个文件内容有不同
    • <表示后面文件比前面文件少了1行内容
    • >表示后面文件比前面文件多了1行内容
    $ diff -y -W 50 text5 text6
    -1001        1001
    -1002        1002
    -1003      | 1003a
    -        > 1004
    -

    比较文件夹内容。注意,只比较内容,不比较时间戳。

    $ mkdir dir1
    -$ mkdir dir2
    -
    -$ cd dir1
    -$ touch file1
    -$ touch file2
    -$ cp file1 file2 ../dir2/
    -$ echo "hello" > file3
    -
    -$ cd ../dir2
    -$ touch file3
    -$ touch file4
    -
    -$ diff dir1 dir2
    +*** 1,3 ****
    +  1001
    +  1002
    +! 1003
    +--- 1,4 ----
    +  1001
    +  1002
    +! 1003a
    +! 1004
    +

    并排格式输出比较结果。

    • |表示前后2个文件内容有不同
    • <表示后面文件比前面文件少了1行内容
    • >表示后面文件比前面文件多了1行内容
    $ diff -y -W 50 text5 text6
    +1001        1001
    +1002        1002
    +1003      | 1003a
    +        > 1004
    +

    比较文件夹内容。注意,只比较内容,不比较时间戳。

    $ mkdir dir1
    +$ mkdir dir2
    +
    +$ cd dir1
    +$ touch file1
    +$ touch file2
    +$ cp file1 file2 ../dir2/
    +$ echo "hello" > file3
    +
    +$ cd ../dir2
    +$ touch file3
    +$ touch file4
    +
    +$ diff dir1 dir2
     1d0
    -< hello
    -Only in dir2: file4
    -

    2.14.2.patch

    命令patch复制其他文件中的内容。命令格式:

    patch -p[num] < patchfile
    -patch [options] originalfile patchfile 
    -

    当特定软件有可用的安全修复程序时,我们通常会使用 yumapt-getzypper等包管理工具进行二进制升级。

    但如果我们是通过从源代码编译安装软件的情况下,我们需要下载安全补丁并将其应用于原始源代码并重新编译软件。

    这就是我们使用 diff 创建补丁文件(patch file),并使用 patch命令应用它。

    补丁文件是一个文本文件,其中包含同一文件(或同一源代码树)的两个版本之间的差异。 补丁文件是使用 diff命令创建的。

    继续上例。

    将文件text5的内容同步到文件text6,然后撤销补丁。注意区分源文件和目标文件。

    $ cat text5
    +< hello
    +Only in dir2: file4
    +

    2.14.2.patch

    命令patch复制其他文件中的内容。命令格式:

    patch -p[num] < patchfile
    +patch [options] originalfile patchfile 
    +

    当特定软件有可用的安全修复程序时,我们通常会使用 yumapt-getzypper等包管理工具进行二进制升级。

    但如果我们是通过从源代码编译安装软件的情况下,我们需要下载安全补丁并将其应用于原始源代码并重新编译软件。

    这就是我们使用 diff 创建补丁文件(patch file),并使用 patch命令应用它。

    补丁文件是一个文本文件,其中包含同一文件(或同一源代码树)的两个版本之间的差异。 补丁文件是使用 diff命令创建的。

    继续上例。

    将文件text5的内容同步到文件text6,然后撤销补丁。注意区分源文件和目标文件。

    $ cat text5
     1001
     1002
     1003
     
    -$ cat text6
    +$ cat text6
     1001
     1002
     1003a
     1004
     
     # 生成补丁文件
    -$ diff -ruN text5 text6 > patchfile
    -
    -$ cat patchfile
    ---- text5    2022-12-07 08:24:08.867168414 +0800
    -+++ text6    2022-12-07 08:24:13.939284243 +0800
    -@@ -1,3 +1,4 @@
    - 1001
    - 1002
    +$ diff -ruN text5 text6 > patchfile
    +
    +$ cat patchfile
    +--- text5    2022-12-07 08:24:08.867168414 +0800
    ++++ text6    2022-12-07 08:24:13.939284243 +0800
    +@@ -1,3 +1,4 @@
    + 1001
    + 1002
     -1003
     +1003a
     +1004
     
     # 不指明目标文件,则默认给diff命令中的源文件进行打补丁
    -$ patch < patchfile
    -patching file text5
    +$ patch < patchfile
    +patching file text5
     
    -$ cat text5
    +$ cat text5
     1001
     1002
     1003a
     1004
     
    -$ cat text6
    +$ cat text6
     1001
     1002
     1003a
     1004
     
     # 撤销补丁
    -patch -R < patchfile
    -patching file text5
    +patch -R < patchfile
    +patching file text5
     
     # cat text5
     1001
    @@ -486,155 +486,155 @@
     1003
     
     # 给text6文件打补丁(用text5的文件内容覆盖text6的内容)
    -$ patch text6 patchfile
    -patching file text6
    -Reversed (or previously applied) patch detected!  Assume -R? [n] y
    +$ patch text6 patchfile
    +patching file text6
    +Reversed (or previously applied) patch detected!  Assume -R? [n] y
     
    -$ cat text6
    +$ cat text6
     1001
     1002
     1003
     
     # 撤销给text6文件打的补丁(恢复text6文件补丁前的内容)
    -$ patch -R text6 patchfile
    -patching file text6
    -Unreversed patch detected!  Ignore -R? [n] y
    +$ patch -R text6 patchfile
    +patching file text6
    +Unreversed patch detected!  Ignore -R? [n] y
     
    -$ cat text6
    +$ cat text6
     1001
     1002
     1003a
     1004
    -

    使用-b参数,在patch前先备份源文件。

    $ patch -b < patchfile
    -patching file text5
    +

    使用-b参数,在patch前先备份源文件。

    $ patch -b < patchfile
    +patching file text5
     
    -$ cat text5
    +$ cat text5
     1001
     1002
     1003a
     1004
     
    -$ cat text5.orig
    +$ cat text5.orig
     1001
     1002
     1003
     
    -$ cat text6.orig
    +$ cat text6.orig
     1001
     1002
     1003
     
    -$ patch -R < patchfile
    -patching file text5
    -

    在-b参数中加入-V参数,指定备份文件名的格式,如下,会得到文件text5.~1~

    $patch -b -V numbered < patchfile
    -patching file text5
    +$ patch -R < patchfile
    +patching file text5
    +

    在-b参数中加入-V参数,指定备份文件名的格式,如下,会得到文件text5.~1~

    $patch -b -V numbered < patchfile
    +patching file text5
     
    -$ cat text5
    +$ cat text5
     1001
     1002
     1003a
     1004
     
    -$ cat text5.~1~
    +$ cat text5.~1~
     1001
     1002
     1003
    -

    试运行,不做实际更改。

    patch --dry-run < patchfile
    +

    试运行,不做实际更改。

    patch --dry-run < patchfile
     

    对目录打补丁。

    • 执行diffpatch命令是在当前用户vagrant的主目录下,绝对路径是/home/vagrant
    • diff命令中,源目录是/home/vagrant/dir1。目标目录是/home/vagrant/dir2
    • -p3是告诉patch命令忽略上面绝对路径中前三个斜杠/
    • patch命令中用diff的目标目录去覆盖源目录。互换会报错。
    • -R:撤销补丁。
    # file3和file4有内容
    -$ tree ./dir1
    +$ tree ./dir1
     ./dir1
    -├── file1
    -├── file2
    -├── file3
    -└── subdir1
    -  └── file4
    +├── file1
    +├── file2
    +├── file3
    +└── subdir1
    +  └── file4
     
     
     都是空文件
     
    -$ tree ./dir2
    +$ tree ./dir2
     ./dir2
    -├── file1
    -├── file2
    -├── file3
    -└── subdir1
    - └── file4
    -
    -$ diff -ruN /home/vagrant/dir1 /home/vagrant/dir2 > patchdir
    -
    -$ cat patchdir
    -diff -ruN /home/vagrant/dir1/file3 /home/vagrant/dir2/file3
    ---- /home/vagrant/dir1/file3 2022-12-07 08:42:33.108418336 +0800
    -+++ /home/vagrant/dir2/file3 2022-12-07 21:25:48.156056360 +0800
    -@@ -1 +0,0 @@
    +├── file1
    +├── file2
    +├── file3
    +└── subdir1
    + └── file4
    +
    +$ diff -ruN /home/vagrant/dir1 /home/vagrant/dir2 > patchdir
    +
    +$ cat patchdir
    +diff -ruN /home/vagrant/dir1/file3 /home/vagrant/dir2/file3
    +--- /home/vagrant/dir1/file3 2022-12-07 08:42:33.108418336 +0800
    ++++ /home/vagrant/dir2/file3 2022-12-07 21:25:48.156056360 +0800
    +@@ -1 +0,0 @@
     -hello
    -diff -ruN /home/vagrant/dir1/subdir1/file4 /home/vagrant/dir2/subdir1/file4
    ---- /home/vagrant/dir1/subdir1/file4 2022-12-07 21:15:09.689912160 +0800
    -+++ /home/vagrant/dir2/subdir1/file4 2022-12-07 21:26:55.405546177 +0800
    -@@ -1 +0,0 @@
    +diff -ruN /home/vagrant/dir1/subdir1/file4 /home/vagrant/dir2/subdir1/file4
    +--- /home/vagrant/dir1/subdir1/file4 2022-12-07 21:15:09.689912160 +0800
    ++++ /home/vagrant/dir2/subdir1/file4 2022-12-07 21:26:55.405546177 +0800
    +@@ -1 +0,0 @@
     -/home/vagrant/dir1/subdir1
     
     # 用dir2的内容覆盖dir1的内容
     
    -$ patch -p3 < patchdir
    -patching file dir1/file3
    -patching file dir1/subdir1/file4
    +$ patch -p3 < patchdir
    +patching file dir1/file3
    +patching file dir1/subdir1/file4
     
     # 现在dir1目录下的内容已经被dir2目录覆盖了。file3和file4都是空文件
     
    -$ ll ./dir1
    -total 0
    --rw-r--r--. 1 vagrant wheel 0 Dec 7 08:34 file1
    --rw-r--r--. 1 vagrant wheel 0 Dec 7 08:35 file2
    --rw-r--r--. 1 vagrant wheel 0 Dec 7 21:40 file3
    -drwxr-xr-x. 1 vagrant wheel 10 Dec 7 21:40 subdir1
    +$ ll ./dir1
    +total 0
    +-rw-r--r--. 1 vagrant wheel 0 Dec 7 08:34 file1
    +-rw-r--r--. 1 vagrant wheel 0 Dec 7 08:35 file2
    +-rw-r--r--. 1 vagrant wheel 0 Dec 7 21:40 file3
    +drwxr-xr-x. 1 vagrant wheel 10 Dec 7 21:40 subdir1
     
    -$ ll ./dir1/subdir1
    -total 0
    --rw-r--r--. 1 vagrant wheel 0 Dec 7 21:40 file4
    +$ ll ./dir1/subdir1
    +total 0
    +-rw-r--r--. 1 vagrant wheel 0 Dec 7 21:40 file4
     
     # 撤销补丁,file3和file4已经恢复为原文件
     
    -$ patch -R -p3 < patchdir
    -patching file dir1/file3
    -patching file dir1/subdir1/file4
    +$ patch -R -p3 < patchdir
    +patching file dir1/file3
    +patching file dir1/subdir1/file4
     
    -$ ll ./dir1
    --rw-r--r--. 1 vagrant wheel 0 Dec 7 08:34 file1
    --rw-r--r--. 1 vagrant wheel 0 Dec 7 08:35 file2
    --rw-r--r--. 1 vagrant wheel 6 Dec 7 21:45 file3
    -drwxr-xr-x. 1 vagrant wheel 10 Dec 7 21:45 subdir1
    +$ ll ./dir1
    +-rw-r--r--. 1 vagrant wheel 0 Dec 7 08:34 file1
    +-rw-r--r--. 1 vagrant wheel 0 Dec 7 08:35 file2
    +-rw-r--r--. 1 vagrant wheel 6 Dec 7 21:45 file3
    +drwxr-xr-x. 1 vagrant wheel 10 Dec 7 21:45 subdir1
     
    -$ ll ./dir1/subdir1
    --rw-r--r--. 1 vagrant wheel 27 Dec 7 21:45 file4
    +$ ll ./dir1/subdir1
    +-rw-r--r--. 1 vagrant wheel 27 Dec 7 21:45 file4
     
     # 用dir1的内容覆盖dir2的内容,系统拒绝。
     
    -patch dir2 -p3 < patchdir
    -File dir2 is not a regular file -- refusing to patch
    -1 out of 1 hunk ignored -- saving rejects to file dir2.rej
    -File dir2 is not a regular file -- refusing to patch
    -1 out of 1 hunk ignored -- saving rejects to file dir2.rej
    +patch dir2 -p3 < patchdir
    +File dir2 is not a regular file -- refusing to patch
    +1 out of 1 hunk ignored -- saving rejects to file dir2.rej
    +File dir2 is not a regular file -- refusing to patch
    +1 out of 1 hunk ignored -- saving rejects to file dir2.rej
     
    -$ patch /home/vagrant/dir2 -p3 < patchdir
    -File /home/vagrant/dir2 is not a regular file -- refusing to patch
    -1 out of 1 hunk ignored -- saving rejects to file /home/vagrant/dir2.rej
    -File /home/vagrant/dir2 is not a regular file -- refusing to patch
    -1 out of 1 hunk ignored -- saving rejects to file /home/vagrant/dir2.rej
    -

    2.14.3.vimdiff

    命令vimdiff相当于vim -d

    举例:

    vimdiff text1 text2
    -

    2.14.4.cmp

    命令cmp查看二进制文件的不同。

    $ cmp cp grep
    -cp grep differ: byte 25, line 1
    +$ patch /home/vagrant/dir2 -p3 < patchdir
    +File /home/vagrant/dir2 is not a regular file -- refusing to patch
    +1 out of 1 hunk ignored -- saving rejects to file /home/vagrant/dir2.rej
    +File /home/vagrant/dir2 is not a regular file -- refusing to patch
    +1 out of 1 hunk ignored -- saving rejects to file /home/vagrant/dir2.rej
    +

    2.14.3.vimdiff

    命令vimdiff相当于vim -d

    举例:

    vimdiff text1 text2
    +

    2.14.4.cmp

    命令cmp查看二进制文件的不同。

    $ cmp cp grep
    +cp grep differ: byte 25, line 1
     
    -$ cmp /usr/bin/ls /usr/bin/dir
    -/usr/bin/ls /usr/bin/dir differ: byte 613, line 1
    +$ cmp /usr/bin/ls /usr/bin/dir
    +/usr/bin/ls /usr/bin/dir differ: byte 613, line 1
     
     # 跳过前735个字节,输出后面30个字节内容
     
    -$ hexdump -s 735 -Cn 30 /usr/bin/ls
    -000002df 00 00 00 00 00 5d 00 00 00 50 00 00 00 68 00 00 |.....]...P...h..|
    -000002ef 00 6a 00 00 00 4f 00 00 00 00 00 00 00 1d |.j...O........|
    -000002fd $ hexdump -s 735 -Cn 30 /usr/bin/dir
    -000002df 00 00 00 00 00 5d 00 00 00 50 00 00 00 68 00 00 |.....]...P...h..|
    -000002ef 00 6a 00 00 00 4f 00 00 00 00 00 00 00 1d |.j...O........|
    +$ hexdump -s 735 -Cn 30 /usr/bin/ls
    +000002df 00 00 00 00 00 5d 00 00 00 50 00 00 00 68 00 00 |.....]...P...h..|
    +000002ef 00 6a 00 00 00 4f 00 00 00 00 00 00 00 1d |.j...O........|
    +000002fd $ hexdump -s 735 -Cn 30 /usr/bin/dir
    +000002df 00 00 00 00 00 5d 00 00 00 50 00 00 00 68 00 00 |.....]...P...h..|
    +000002ef 00 6a 00 00 00 4f 00 00 00 00 00 00 00 1d |.j...O........|
     000002fd
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/linux/SRE/05-RegExpress/index.html b/linux/SRE/05-RegExpress/index.html index bc5a449a..392766cc 100644 --- a/linux/SRE/05-RegExpress/index.html +++ b/linux/SRE/05-RegExpress/index.html @@ -1,95 +1,95 @@ - 第五章 正则表达式 - UPSkilling

    第五章 正则表达式

    正则表达式分两类:

    • 基本正则表达式(Basic Regular Expression, 又叫Basic RegEx,简称BREs)
    • 扩展正则表达式(Extended Regular Expression, 又叫Extended RegEx,简称EREs)
    • Perl正则表达式(Perl Regular Expression, 又叫Perl RegEx 简称PREs

    基本的正则表达式和扩展正则表达式的区别就是元字符的不同。

    5.1.基本正则表达式符号

    ^:表示以某个字符开始 $:表示以某个字符结尾 .:表示匹配一个且只匹配一个字符 *:表示匹配前边一个字符出现0次或者多次 []:表示匹配括号内的多个字符信息,一个一个匹配 .*:表示匹配所有,空行也会进行匹配 [^]:表示不匹配括号内的每一个字符 ^$:表示匹配空行信息 \:将有特殊含义的字符转义为通配符

    5.2.扩展正则表达式符号

    +:表示前一个字符出现一次或一次以上 ?:表示前一个字符出现0次或者一次以上 |:表示或者的关系,匹配多个信息 ():匹配一个整体信息,也可以接后项引用 {}:定义前边字符出现几次

    提示:

    grep -E 或者egrep只是表示扩展正则,不代表加了e就表示转义了。 当grep使用扩展正则的符号时候需要用\转义为通配符才能使用。

    5.3.字符匹配

    • [:alpha:]:表示所有的字母(不区分大小写),效果同[a-z]
    • [:digit:]:表示任意单个数字,效果同[0-9]
    • [:xdigit:]:表示十六进制数字
    • [:lower:]:表示任意单个小写字母
    • [:upper:]:表示任意单个大写字母
    • [:alnum:]:表示任意单个字母或数字
    • [:blank:]:表示空白字符(空格和制表符)
    • [:space:]:表示包括空格、制表符(水平和垂直)、换行符、回车符等各种类型的空白,比[:blank:]范围更广
    • [:cntrl:]:表示不可打印的控制字符(退格、删除、警铃等)
    • [:graph:]:表示可打印的非空白字符
    • [:print:]:表示可打印字符
    • [:punct:]:表示标点符号

    5.4.位置标记

    位置标记锚点(position marker anchor)是标识字符串位置的正则表达式。默认情况下,正则表达式所匹配的字符可以出现在字符串中任何位置。

    • ^:行首锚定,指定了匹配正则表达式的文本必须起始于字符串的首部。
    • 例如:^tux能够匹配以tux起始的行
    • $:行尾锚定,指定了匹配正则表达式的文本必须结束于目标字符串的尾部。
    • \<\b:词首锚定,用于单词模式匹配左侧。(单词是有字母、数字、下划线组成)
    • \>\b:词尾锚定,用于单词模式匹配右侧。(单词是有字母、数字、下划线组成)
    • ^PATTERN$:用模式PATTERN匹配整行。
    • ^$:匹配空行。
    • ^[[:space:]]*$:匹配空白行(整行)。
    • \<PATTERN\>:匹配整个单词。(单词是有字母、数字、下划线组成)

    关于行首锚定和词首锚定,对比下面例子。词尾锚定也是类似情况。 ;-都被认定为单词分隔符。

    # 符合词首匹配
    -$ echo "tux_01-tux02" | grep '\<tux'
    + 第五章 正则表达式 - UPSkilling       

    第五章 正则表达式

    正则表达式分两类:

    • 基本正则表达式(Basic Regular Expression, 又叫Basic RegEx,简称BREs)
    • 扩展正则表达式(Extended Regular Expression, 又叫Extended RegEx,简称EREs)
    • Perl正则表达式(Perl Regular Expression, 又叫Perl RegEx 简称PREs

    基本的正则表达式和扩展正则表达式的区别就是元字符的不同。

    5.1.基本正则表达式符号

    ^:表示以某个字符开始 $:表示以某个字符结尾 .:表示匹配一个且只匹配一个字符 *:表示匹配前边一个字符出现0次或者多次 []:表示匹配括号内的多个字符信息,一个一个匹配 .*:表示匹配所有,空行也会进行匹配 [^]:表示不匹配括号内的每一个字符 ^$:表示匹配空行信息 \:将有特殊含义的字符转义为通配符

    5.2.扩展正则表达式符号

    +:表示前一个字符出现一次或一次以上 ?:表示前一个字符出现0次或者一次以上 |:表示或者的关系,匹配多个信息 ():匹配一个整体信息,也可以接后项引用 {}:定义前边字符出现几次

    提示:

    grep -E 或者egrep只是表示扩展正则,不代表加了e就表示转义了。 当grep使用扩展正则的符号时候需要用\转义为通配符才能使用。

    5.3.字符匹配

    • [:alpha:]:表示所有的字母(不区分大小写),效果同[a-z]
    • [:digit:]:表示任意单个数字,效果同[0-9]
    • [:xdigit:]:表示十六进制数字
    • [:lower:]:表示任意单个小写字母
    • [:upper:]:表示任意单个大写字母
    • [:alnum:]:表示任意单个字母或数字
    • [:blank:]:表示空白字符(空格和制表符)
    • [:space:]:表示包括空格、制表符(水平和垂直)、换行符、回车符等各种类型的空白,比[:blank:]范围更广
    • [:cntrl:]:表示不可打印的控制字符(退格、删除、警铃等)
    • [:graph:]:表示可打印的非空白字符
    • [:print:]:表示可打印字符
    • [:punct:]:表示标点符号

    5.4.位置标记

    位置标记锚点(position marker anchor)是标识字符串位置的正则表达式。默认情况下,正则表达式所匹配的字符可以出现在字符串中任何位置。

    • ^:行首锚定,指定了匹配正则表达式的文本必须起始于字符串的首部。
    • 例如:^tux能够匹配以tux起始的行
    • $:行尾锚定,指定了匹配正则表达式的文本必须结束于目标字符串的尾部。
    • \<\b:词首锚定,用于单词模式匹配左侧。(单词是有字母、数字、下划线组成)
    • \>\b:词尾锚定,用于单词模式匹配右侧。(单词是有字母、数字、下划线组成)
    • ^PATTERN$:用模式PATTERN匹配整行。
    • ^$:匹配空行。
    • ^[[:space:]]*$:匹配空白行(整行)。
    • \<PATTERN\>:匹配整个单词。(单词是有字母、数字、下划线组成)

    关于行首锚定和词首锚定,对比下面例子。词尾锚定也是类似情况。 ;-都被认定为单词分隔符。

    # 符合词首匹配
    +$ echo "tux_01-tux02" | grep '\<tux'
     tux_01-tux02
     
     # 符合词首匹配
    -$ echo "xut_01-tux02" | grep '\<tux'
    +$ echo "xut_01-tux02" | grep '\<tux'
     xut_01-tux02
     
     # 符合行首匹配
    -$ echo "xut_01;tux02" | grep '\<tux'
    +$ echo "xut_01;tux02" | grep '\<tux'
     xut_01;tux02
     
     # 符合行首匹配
    -$ echo "tux_01-tux02" | grep '^tux'
    +$ echo "tux_01-tux02" | grep '^tux'
     tux_01-tux02
     
     # 不符合行首匹配
    -$ echo "xut_01-tux02" | grep '^tux'
    -

    5.5.标识符

    标识符是正则表达式的基础组成部分。它定义了那些为了匹配正则表达式,必须存在(或不存在)的字符。

    • A字符:正则表达式必须匹配该字符。
    • 例如:A能够匹配字符A
    • .:匹配任意一个字符。
    • 例如:Hack.能够匹配HacklHacki,但是不能匹配Hackl2Hackil,它只能匹配单个字符。
    • []:匹配中括号内的任意一个字符。中括号内可以是一个字符组或字符范围
    • 例如:coo[kl]能够匹配cookcool
    • 例如:[0-9]匹配任意单个数字
    • 例如:[.0-9]匹配.或任意单个数字(中括号内的.就代表字符.,不代表任意单个字符)
    • [^]:匹配不在中括号内的任意一个字符。中括号内可以是一个字符组或字符范围
    • 例如:9[^01]能够匹配9293,但是不匹配9190
    • 例如:A[^0-9]匹配A以及随后除数字外的任意单个字符
    • \s:匹配任何空白字符,包括空格、制表符、换页等。等价于[\f\r\t\v]
    • \S:匹配任何非空白字符,等价于[^\f\r\t\v]
    • \w:匹配一个字母、数字、下划线、汉字、其他国家文字字符,等价于[_[:alnum:]字]
    • \W:匹配一个非字母、数字、下划线、汉字、其他国家文字字符,等价于[^_[:alnum:]字]

    5.6.数量修饰符

    一个标识符可以出现一次、多次或是不出现。数量修饰符定义了模式可以出现的次数。

    • ?:匹配之前的项0次或1次。
    • 例如:colou?r能够匹配colorcolour,但是不能匹配colouur
    • *:匹配之前的项0次或多次。
    • 例如:co*l能够匹配colcoool
    • 例如:goo*gle能匹配0个或多个o,如:goglegooglegoooglegooooooooogle等。
    • 例如:gooo*gle,则可以匹配googlegoooglegooooooooogle等,对比上面等差别。
    • +:匹配之前的项1次或多次。
    • 例如:Rollno-9+能够匹配Rollno-99Rollno-9,但是不能匹配Rollno-
    • 例如:colou+r能够匹配colourcolouur,不能匹配color
    • 例如:goo\+gle能够匹配1个或多个o,如:googlegoooglegoooogle等。
    • .*:匹配任意长度等任意字符。相当于通配符中的*
    • {n}:匹配之前的项n次。
    • 例如:[0-9]{3}能够匹配任意的三位数。
    • 例如:[0-9]{3}可以扩展为[0-9][0-9][0-9]
    • {n}:之前的项至少需要匹配n次。
    • 例如:[0-9]{2,}能够匹配任意一个两位或更多位的数字。
    • 例如:go\{2,\}gle能够匹配2个或者多个o,如googlegooooogle等,不能匹配gogle
    • {n,m}:之前的项所必须匹配的最小n次数和最大m次数。
    • 例如:[0-9]{2,5}能够匹配两位数到五位数之间的任意一个数字。

    5.7.分组

    有一些特殊字符可以调整正则表达式的匹配方式。

    • \:转义字符可以转义特殊字符。
    • 例如:a\.b能够匹配a.b,但不能匹配ajb。因为\忽略了.的特殊意义。
    • ():将括号中的内容视为一个整体。
    • 例如:ma(tri)?x 能够匹配maxmatrix
    • 例如:\(root\)+
    • 后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部变量中,这些变量名方式为:\1\2\3
    • \1:表示从左侧起第一个左括号以及与之匹配的右括号之间的模式所匹配到的字符
      • 例如:\(string1\(string2\)\)\1string1\(string2\)\2string2
    • \0:表示正则表达式匹配的所有字符
    • |:指定了一种选择结构,可以匹配|两边的任意一项。
    • 例如:Oct (1st|2nd)能够匹配Oct 1stOct 2nd

    举例:匹配正负数

    $ echo -1 -2 12 -125 23 | grep '\-\?[0-9]\+' 
    --1 -2 12 -125 3log 23 it4u
    +$ echo "xut_01-tux02" | grep '^tux'
    +

    5.5.标识符

    标识符是正则表达式的基础组成部分。它定义了那些为了匹配正则表达式,必须存在(或不存在)的字符。

    • A字符:正则表达式必须匹配该字符。
    • 例如:A能够匹配字符A
    • .:匹配任意一个字符。
    • 例如:Hack.能够匹配HacklHacki,但是不能匹配Hackl2Hackil,它只能匹配单个字符。
    • []:匹配中括号内的任意一个字符。中括号内可以是一个字符组或字符范围
    • 例如:coo[kl]能够匹配cookcool
    • 例如:[0-9]匹配任意单个数字
    • 例如:[.0-9]匹配.或任意单个数字(中括号内的.就代表字符.,不代表任意单个字符)
    • [^]:匹配不在中括号内的任意一个字符。中括号内可以是一个字符组或字符范围
    • 例如:9[^01]能够匹配9293,但是不匹配9190
    • 例如:A[^0-9]匹配A以及随后除数字外的任意单个字符
    • \s:匹配任何空白字符,包括空格、制表符、换页等。等价于[\f\r\t\v]
    • \S:匹配任何非空白字符,等价于[^\f\r\t\v]
    • \w:匹配一个字母、数字、下划线、汉字、其他国家文字字符,等价于[_[:alnum:]字]
    • \W:匹配一个非字母、数字、下划线、汉字、其他国家文字字符,等价于[^_[:alnum:]字]

    5.6.数量修饰符

    一个标识符可以出现一次、多次或是不出现。数量修饰符定义了模式可以出现的次数。

    • ?:匹配之前的项0次或1次。
    • 例如:colou?r能够匹配colorcolour,但是不能匹配colouur
    • *:匹配之前的项0次或多次。
    • 例如:co*l能够匹配colcoool
    • 例如:goo*gle能匹配0个或多个o,如:goglegooglegoooglegooooooooogle等。
    • 例如:gooo*gle,则可以匹配googlegoooglegooooooooogle等,对比上面等差别。
    • +:匹配之前的项1次或多次。
    • 例如:Rollno-9+能够匹配Rollno-99Rollno-9,但是不能匹配Rollno-
    • 例如:colou+r能够匹配colourcolouur,不能匹配color
    • 例如:goo\+gle能够匹配1个或多个o,如:googlegoooglegoooogle等。
    • .*:匹配任意长度等任意字符。相当于通配符中的*
    • {n}:匹配之前的项n次。
    • 例如:[0-9]{3}能够匹配任意的三位数。
    • 例如:[0-9]{3}可以扩展为[0-9][0-9][0-9]
    • {n}:之前的项至少需要匹配n次。
    • 例如:[0-9]{2,}能够匹配任意一个两位或更多位的数字。
    • 例如:go\{2,\}gle能够匹配2个或者多个o,如googlegooooogle等,不能匹配gogle
    • {n,m}:之前的项所必须匹配的最小n次数和最大m次数。
    • 例如:[0-9]{2,5}能够匹配两位数到五位数之间的任意一个数字。

    5.7.分组

    有一些特殊字符可以调整正则表达式的匹配方式。

    • \:转义字符可以转义特殊字符。
    • 例如:a\.b能够匹配a.b,但不能匹配ajb。因为\忽略了.的特殊意义。
    • ():将括号中的内容视为一个整体。
    • 例如:ma(tri)?x 能够匹配maxmatrix
    • 例如:\(root\)+
    • 后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部变量中,这些变量名方式为:\1\2\3
    • \1:表示从左侧起第一个左括号以及与之匹配的右括号之间的模式所匹配到的字符
      • 例如:\(string1\(string2\)\)\1string1\(string2\)\2string2
    • \0:表示正则表达式匹配的所有字符
    • |:指定了一种选择结构,可以匹配|两边的任意一项。
    • 例如:Oct (1st|2nd)能够匹配Oct 1stOct 2nd

    举例:匹配正负数

    $ echo -1 -2 12 -125 23 | grep '\-\?[0-9]\+' 
    +-1 -2 12 -125 3log 23 it4u
     
    -$ echo -1 -2 12 -125 3log 23 it4u | grep '\-\?[0-9]\+'
    --1 -2 12 -125 3log 23 it4u
    +$ echo -1 -2 12 -125 3log 23 it4u | grep '\-\?[0-9]\+'
    +-1 -2 12 -125 3log 23 it4u
     
    -$ echo -1 -2 12 -125 3log 23 it4u | grep '\-\?[0-9]*'
    --1 -2 12 -125 3log 23 it4u
    +$ echo -1 -2 12 -125 3log 23 it4u | grep '\-\?[0-9]*'
    +-1 -2 12 -125 3log 23 it4u
     
    -$ echo -1 -2 12 -125 3log 23 it4u | grep -E '\-\?[0-9]\+'
    +$ echo -1 -2 12 -125 3log 23 it4u | grep -E '\-\?[0-9]\+'
     
     
    -$ echo -1 -2 12 -125 3log 23 it4u | grep -E -- '-?[0-9]+'
    --1 -2 12 -125 3log 23 it4u
    +$ echo -1 -2 12 -125 3log 23 it4u | grep -E -- '-?[0-9]+'
    +-1 -2 12 -125 3log 23 it4u
     
    -$ echo -1 -2 12 -125 3log 23 it4u | grep -E '(-)?[0-9]+'
    --1 -2 12 -125 3log 23 it4u
    -

    举例:获取IP地址

    ifconfig eth0
    -eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
    -        inet 192.168.10.210  netmask 255.255.255.0  broadcast 192.168.10.255
    -        inet6 fe80::20c:29ff:fea4:e17a  prefixlen 64  scopeid 0x20<link>
    -        ether 00:0c:29:a4:e1:7a  txqueuelen 1000  (Ethernet)
    -        RX packets 7654  bytes 635932 (621.0 KiB)
    -        RX errors 0  dropped 1  overruns 0  frame 0
    -        TX packets 1934  bytes 279649 (273.0 KiB)
    -        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    +$ echo -1 -2 12 -125 3log 23 it4u | grep -E '(-)?[0-9]+'
    +-1 -2 12 -125 3log 23 it4u
    +

    举例:获取IP地址

    ifconfig eth0
    +eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
    +        inet 192.168.10.210  netmask 255.255.255.0  broadcast 192.168.10.255
    +        inet6 fe80::20c:29ff:fea4:e17a  prefixlen 64  scopeid 0x20<link>
    +        ether 00:0c:29:a4:e1:7a  txqueuelen 1000  (Ethernet)
    +        RX packets 7654  bytes 635932 (621.0 KiB)
    +        RX errors 0  dropped 1  overruns 0  frame 0
    +        TX packets 1934  bytes 279649 (273.0 KiB)
    +        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
     
    -$ ifconfig eth0 | grep netmask | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
    +$ ifconfig eth0 | grep netmask | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
     192.168.10.210
     255.255.255.0
     192.168.10.255
     
    -$ ifconfig eth0 | grep netmask | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | head -n 1
    +$ ifconfig eth0 | grep netmask | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | head -n 1
     192.168.10.210
     
    -$ ifconfig eth0 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
    +$ ifconfig eth0 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'
     192.168.10.210
     255.255.255.0
     192.168.10.255
     
    -ifconfig eth0 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | head -n 1
    +ifconfig eth0 | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | head -n 1
     192.168.10.210
    -

    匹配空行和非空行:

    grep '^$' /etc/profile
    -grep -v '^$' /etc/profile
    -

    匹配非空行和非#开头的行:(三种方法)

    grep -v '^$' /etc/profile | grep -v '^#'
    -grep -v '^$\|#' /etc/profile
    -grep '^[^$#]' /etc/profile
    -

    注意,如果写成下面这样,则不会过滤掉空行,[$]会被视为$符号。 所以正则表达式的元字符放在中括号[]内就被视为普通字符。

    grep -v '^[$#]' /etc/profile
    -

    5.8.三剑客grep命令

    格式:

    • grep [OPTIONS] PATTERN [FILE...]
    • grep [OPTIONS] -e PATTERN ... [FILE...]
    • grep [OPTIONS] -f FILE ... [FILE...]

    参数:

    • -n:显示过滤出来的文件在文件当中的行号
    • -c:显示匹配到的行数
    • -o:只显示匹配到的内容
    • -q:静默输出(一般用在shell脚本当中,通过echo $?查看命令执行结果,0表示成功,非0表示失败))
    • -i:忽略大小写
    • -v:反向查找
    • -w:匹配某个词词:在Linux中,词为一连串字母、数字和下划线组成的字符串
    • -E:使用扩展正则
    • -R:递归查询
    • -l:只打印文件路径

    扩展参数:

    • -A:显示匹配到的数据的后几n行
    • -B:显示匹配到的数据的前几n行
    • -C:显示匹配到的数据的前后各几n行

    示例:

    匹配用户:

    grep root /etc/passwd
    +

    匹配空行和非空行:

    grep '^$' /etc/profile
    +grep -v '^$' /etc/profile
    +

    匹配非空行和非#开头的行:(三种方法)

    grep -v '^$' /etc/profile | grep -v '^#'
    +grep -v '^$\|#' /etc/profile
    +grep '^[^$#]' /etc/profile
    +

    注意,如果写成下面这样,则不会过滤掉空行,[$]会被视为$符号。 所以正则表达式的元字符放在中括号[]内就被视为普通字符。

    grep -v '^[$#]' /etc/profile
    +

    5.8.三剑客grep命令

    格式:

    • grep [OPTIONS] PATTERN [FILE...]
    • grep [OPTIONS] -e PATTERN ... [FILE...]
    • grep [OPTIONS] -f FILE ... [FILE...]

    参数:

    • -n:显示过滤出来的文件在文件当中的行号
    • -c:显示匹配到的行数
    • -o:只显示匹配到的内容
    • -q:静默输出(一般用在shell脚本当中,通过echo $?查看命令执行结果,0表示成功,非0表示失败))
    • -i:忽略大小写
    • -v:反向查找
    • -w:匹配某个词词:在Linux中,词为一连串字母、数字和下划线组成的字符串
    • -E:使用扩展正则
    • -R:递归查询
    • -l:只打印文件路径

    扩展参数:

    • -A:显示匹配到的数据的后几n行
    • -B:显示匹配到的数据的前几n行
    • -C:显示匹配到的数据的前后各几n行

    示例:

    匹配用户:

    grep root /etc/passwd
     root:x:0:0:root:/root:/bin/bash
     
    -$ grep "USER" /etc/passwd
    +$ grep "USER" /etc/passwd
     
    -$ grep "$USER" /etc/passwd
    +$ grep "$USER" /etc/passwd
     vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash
     
    -$ grep '$USER' /etc/passwd
    -

    匹配关键字:

    $ grep processor /proc/cpuinfo
    -processor       : 0
    -processor       : 1
    +$ grep '$USER' /etc/passwd
    +

    匹配关键字:

    $ grep processor /proc/cpuinfo
    +processor       : 0
    +processor       : 1
     
    -$ grep -o processor /proc/cpuinfo
    +$ grep -o processor /proc/cpuinfo
     processor
     processor
     
    -$ grep "cpu family" /proc/cpuinfo
    -cpu family      : 6
    -cpu family      : 6
    +$ grep "cpu family" /proc/cpuinfo
    +cpu family      : 6
    +cpu family      : 6
     
    -$ grep -o "cpu family" /proc/cpuinfo
    -cpu family
    -cpu family
    +$ grep -o "cpu family" /proc/cpuinfo
    +cpu family
    +cpu family
     

    通过grep进行文件比较。

    # 最后一行是空行
    -$ cat f1
    +$ cat f1
     a
     b
     1
    @@ -97,7 +97,7 @@
     
     
     # 最后一行是空行
    -$ cat f2
    +$ cat f2
     b
     e
     f
    @@ -107,7 +107,7 @@
     
     
     # 高亮显示相同内容的行,包含最后一行空行
    -$ grep -f f1 f2
    +$ grep -f f1 f2
     b
     e
     f
    @@ -117,52 +117,52 @@
     
     
     # 只显示相同内容的行,包含最后一行空行
    -$ grep -wf f1 f2
    +$ grep -wf f1 f2
     b
     c
     1
     
     
     # 只显示不同内容的行
    -$ grep -wvf f1 f2
    +$ grep -wvf f1 f2
     e
     f
     2
     

    提示:

    grep -wvf f1 f2 或者grep -w -v -f f1 f2中,-f只能作为最后一个参数,否则会报错。

    体会基本正则和扩展正则的差异。

    例1:转义。

    # 下面几个命令返回的结果是一样的。
    -$ grep "root\|bash" /etc/passwd
    -$ grep -E "root|bash" /etc/passwd
    -$ grep -e "root" -e "bash" /etc/passwd
    +$ grep "root\|bash" /etc/passwd
    +$ grep -E "root|bash" /etc/passwd
    +$ grep -e "root" -e "bash" /etc/passwd
     
     # 下面的命令没有匹配结果返回。
    -$ grep "root|bash" /etc/passwd
    -

    例2:下面4个命令返回同样的结果。

    grep "root" /etc/passwd
    -grep -E "root" /etc/passwd
    -grep "\<root\>" /etc/passwd
    -grep -E "\<root\>" /etc/passwd
    -

    例3:行首行尾锚定。

    $ grep "^\(.*\)\>.*\<\1$" /etc/passwd
    -$ grep -E "^(.*)\>.*\<\1$" /etc/passwd
    -$ egrep "^(.*)\>.*\<\1$" /etc/passwd
    +$ grep "root|bash" /etc/passwd
    +

    例2:下面4个命令返回同样的结果。

    grep "root" /etc/passwd
    +grep -E "root" /etc/passwd
    +grep "\<root\>" /etc/passwd
    +grep -E "\<root\>" /etc/passwd
    +

    例3:行首行尾锚定。

    $ grep "^\(.*\)\>.*\<\1$" /etc/passwd
    +$ grep -E "^(.*)\>.*\<\1$" /etc/passwd
    +$ egrep "^(.*)\>.*\<\1$" /etc/passwd
     sync:x:5:0:sync:/sbin:/bin/sync
     shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
     halt:x:7:0:halt:/sbin:/sbin/halt
    -

    例4:三种方法求和计算,运用grepcutbcpaste命令。

    $cat age
    +

    例4:三种方法求和计算,运用grepcutbcpaste命令。

    $cat age
     Jason=20
     Tom=30
     Jack=40
     
     # 方法1
    -$ cat age | cut -d "=" -f 2 | tr "\n" + | grep -Eo ".*[0-9]" | bc
    +$ cat age | cut -d "=" -f 2 | tr "\n" + | grep -Eo ".*[0-9]" | bc
     90
     
     # 方法2
    -$ grep -Eo "[0-9]+" age | tr "\n" + | grep -Eo ".*[0-9]" | bc
    +$ grep -Eo "[0-9]+" age | tr "\n" + | grep -Eo ".*[0-9]" | bc
     90
     
     # 方法3
    -$  grep -Eo "[0-9]+" age | paste -s -d "+" | bc
    +$  grep -Eo "[0-9]+" age | paste -s -d "+" | bc
     90
    -

    5.9.三剑客sed命令

    sed是stream editor的缩写,中文称之为“流编辑器”。 sed命令是一个面向行处理的工具,它以“行”为处理单位,针对每一行进行处理,处理后的结果会输出到标准输出STDOUT,不会对读取的文件做任何修改。

    sed的工作原理:

    sed命令是面向“行”进行处理的,每一次处理一行内容。 处理时,sed会把要处理的行存储在缓冲区中,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。这个缓冲区被称为“模式空间”(pattern space)。

    保持空间(hold space)

    sed的保持空间像一个长期储存, 可以把获取的信息储存到其中,待后续调用。不能直接对保持空间进行操作, 而是将保持空间的内容复制或者添加到模式空间进行操作。

    非交互式批量修改文件。

    sed命令格式:

    sed [option] command file
    -

    option常用选项:

    • -n:不输出模式pattern的内容到屏幕(即不自动打印)
    • -e:多点编辑
    • -f filename:从指定文件读取编辑脚本
    • -r-E:使用扩展正则表达式
    • -i .bak:备份文件并原处编辑
    • -s:将多个文件视为独立文件,而不是单个连续的长文件流
    • -ir: 不支持
    • -i -r: 支持
    • -ri: 支持
    • -ni: 危险选项,会清空文件

    command部分可以分为两部分:

    • 范围设定,可以采用两种不同的方式来表达:

    • 指定行数:如:

      • 3,5表示第3、4、5行
      • 5,$表示第5行至文件最后一行
    • 模式匹配:如:

      • /^[^dD]/表示匹配行首不是以dD开头的行
    • 动作处理,下面是常用的动作:

    • a:新增, a后面的字串会在新的一行出现(当前行的下一行)

    • i:插入, i后面的字串会在新的一行出现(当前行的上一行)
    • r filename:读取指定文件fllename的内容,追加到当前行的下一行
    • R filename:读取指定文件fllename的一行,追加到当前行的下一行
    • d:删除该行
    • p:打印该行
    • Ip:忽略大小写输出
    • w filename:写入到指定文件filename中。
    • s/regexp/replacement/:取代,用replacement取代正则regexp匹配到的内容
    • =:为模式pattern中的匹配行打印行号
    • !:为模式pattern中的匹配行取反操作
    • q:结束或退出sed

    创建一个testfile文件。

    $ cat <<EOF > testfile
    +

    5.9.三剑客sed命令

    sed是stream editor的缩写,中文称之为“流编辑器”。 sed命令是一个面向行处理的工具,它以“行”为处理单位,针对每一行进行处理,处理后的结果会输出到标准输出STDOUT,不会对读取的文件做任何修改。

    sed的工作原理:

    sed命令是面向“行”进行处理的,每一次处理一行内容。 处理时,sed会把要处理的行存储在缓冲区中,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。这个缓冲区被称为“模式空间”(pattern space)。

    保持空间(hold space)

    sed的保持空间像一个长期储存, 可以把获取的信息储存到其中,待后续调用。不能直接对保持空间进行操作, 而是将保持空间的内容复制或者添加到模式空间进行操作。

    非交互式批量修改文件。

    sed命令格式:

    sed [option] command file
    +

    option常用选项:

    • -n:不输出模式pattern的内容到屏幕(即不自动打印)
    • -e:多点编辑
    • -f filename:从指定文件读取编辑脚本
    • -r-E:使用扩展正则表达式
    • -i .bak:备份文件并原处编辑
    • -s:将多个文件视为独立文件,而不是单个连续的长文件流
    • -ir: 不支持
    • -i -r: 支持
    • -ri: 支持
    • -ni: 危险选项,会清空文件

    command部分可以分为两部分:

    • 范围设定,可以采用两种不同的方式来表达:

    • 指定行数:如:

      • 3,5表示第3、4、5行
      • 5,$表示第5行至文件最后一行
    • 模式匹配:如:

      • /^[^dD]/表示匹配行首不是以dD开头的行
    • 动作处理,下面是常用的动作:

    • a:新增, a后面的字串会在新的一行出现(当前行的下一行)

    • i:插入, i后面的字串会在新的一行出现(当前行的上一行)
    • r filename:读取指定文件fllename的内容,追加到当前行的下一行
    • R filename:读取指定文件fllename的一行,追加到当前行的下一行
    • d:删除该行
    • p:打印该行
    • Ip:忽略大小写输出
    • w filename:写入到指定文件filename中。
    • s/regexp/replacement/:取代,用replacement取代正则regexp匹配到的内容
    • =:为模式pattern中的匹配行打印行号
    • !:为模式pattern中的匹配行取反操作
    • q:结束或退出sed

    创建一个testfile文件。

    $ cat <<EOF > testfile
     HELLO LINUX!
     Linux is a free unix-type opterating system.
     This is a linux testfile!
    @@ -174,215 +174,215 @@
     Wiki
     EOF
     

    匹配定位文件testfile第二行,并输出(包含匹配第二行和输出第二行)。

    # nl testfile | sed '2p'
    -     1    HELLO LINUX!
    -     2    Linux is a free unix-type opterating system.
    -     2    Linux is a free unix-type opterating system.
    -     3    This is a linux testfile!
    -     4    Linux test
    -     5    Google
    -     6    Taobao
    -     7    Banbooob
    -     8    Tesetfile
    -     9    Wiki
    +     1    HELLO LINUX!
    +     2    Linux is a free unix-type opterating system.
    +     2    Linux is a free unix-type opterating system.
    +     3    This is a linux testfile!
    +     4    Linux test
    +     5    Google
    +     6    Taobao
    +     7    Banbooob
    +     8    Tesetfile
    +     9    Wiki
     

    匹配定位文件testfile第二行,不输出。

    # nl testfile | sed -n '2p'
    -     2    Linux is a free unix-type opterating system.
    -

    匹配定位文件testfile最后一行。

    $ nl testfile | sed -n '$p'
    -     9    Wiki
    +     2    Linux is a free unix-type opterating system.
    +

    匹配定位文件testfile最后一行。

    $ nl testfile | sed -n '$p'
    +     9    Wiki
     

    匹配定位文件testfile倒数第二行。

    # sed -n "$(echo $[`cat testfile | wc -l`-1])p" testfile
     Tesetfile
    -

    testfile的内容列出第2~3行,并且打印行号。

    $  nl testfile | sed -n '2,3p'
    -     2  Linux is a free unix-type opterating system.
    -     3  This is a linux testfile!
    -

    testfile的内容从第2行开始,向后输出额外的3行,并且打印行号。

    $ nl testfile | sed -n '2,+3p'
    -     2  Linux is a free unix-type opterating system.
    -     3  This is a linux testfile!
    -     4  Linux test
    -     5  Google
    -

    testfile的内容从第2行开始,向后以2为步进单位输出所有匹配行,并且打印行号(即,从第2行开始输出偶数行)。

    nl testfile | sed -n '2~2p'
    -     2  Linux is a free unix-type opterating system.
    -     4  Linux test
    -     6  Taobao
    -     8  Tesetfile
    -

    testfile的内容从第2行开始,向后以2为步进单位删除所有匹配行,输出剩余行,并且打印行号(即,从第2行开始删除偶数行,输出奇数行)。

    $ nl testfile | sed '2~2d'
    -     1  HELLO LINUX!
    -     3  This is a linux testfile!
    -     5  Google
    -     7  Banbooob
    -     9  Wiki
    -

    testfile的内容输出,删除第2行和第5行,并打印行号。

    $ nl testfile | sed -e '2d' -e '5d'
    -$ nl testfile | sed -e '2d;5d'
    -$ nl testfile | sed '2d;5d'
    -     1  HELLO LINUX!
    -     3  This is a linux testfile!
    -     4  Linux test
    -     6  Taobao
    -     7  Banbooob
    -     8  Tesetfile
    -     9  Wiki
    -

    testfile的内容输出,输出区间是从行首L的行到行首G的行结束。不修改原文件。 如果行首匹配不到,则无结果输出;如果行尾匹配不到,则输出到文件结束。

    $ sed -n '/^L/,/^G/p' testfile
    -Linux is a free unix-type opterating system.
    -This is a linux testfile!
    -Linux test
    +

    testfile的内容列出第2~3行,并且打印行号。

    $  nl testfile | sed -n '2,3p'
    +     2  Linux is a free unix-type opterating system.
    +     3  This is a linux testfile!
    +

    testfile的内容从第2行开始,向后输出额外的3行,并且打印行号。

    $ nl testfile | sed -n '2,+3p'
    +     2  Linux is a free unix-type opterating system.
    +     3  This is a linux testfile!
    +     4  Linux test
    +     5  Google
    +

    testfile的内容从第2行开始,向后以2为步进单位输出所有匹配行,并且打印行号(即,从第2行开始输出偶数行)。

    nl testfile | sed -n '2~2p'
    +     2  Linux is a free unix-type opterating system.
    +     4  Linux test
    +     6  Taobao
    +     8  Tesetfile
    +

    testfile的内容从第2行开始,向后以2为步进单位删除所有匹配行,输出剩余行,并且打印行号(即,从第2行开始删除偶数行,输出奇数行)。

    $ nl testfile | sed '2~2d'
    +     1  HELLO LINUX!
    +     3  This is a linux testfile!
    +     5  Google
    +     7  Banbooob
    +     9  Wiki
    +

    testfile的内容输出,删除第2行和第5行,并打印行号。

    $ nl testfile | sed -e '2d' -e '5d'
    +$ nl testfile | sed -e '2d;5d'
    +$ nl testfile | sed '2d;5d'
    +     1  HELLO LINUX!
    +     3  This is a linux testfile!
    +     4  Linux test
    +     6  Taobao
    +     7  Banbooob
    +     8  Tesetfile
    +     9  Wiki
    +

    testfile的内容输出,输出区间是从行首L的行到行首G的行结束。不修改原文件。 如果行首匹配不到,则无结果输出;如果行尾匹配不到,则输出到文件结束。

    $ sed -n '/^L/,/^G/p' testfile
    +Linux is a free unix-type opterating system.
    +This is a linux testfile!
    +Linux test
     Google
    -

    testfile的内容输出,且在第6行后加上I love Linux。不修改原文件。

    $ sed -e '6a I love Linux' testfile
    -HELLO LINUX!
    -Linux is a free unix-type opterating system.
    -This is a linux testfile!
    -Linux test
    +

    testfile的内容输出,且在第6行后加上I love Linux。不修改原文件。

    $ sed -e '6a I love Linux' testfile
    +HELLO LINUX!
    +Linux is a free unix-type opterating system.
    +This is a linux testfile!
    +Linux test
     Google
     Taobao
    -I love Linux
    +I love Linux
     Banbooob
     Tesetfile
     Wiki
    -

    testfile的内容列出并且打印行号,且在第6行后添加I love Linux。不修改原文件。

    $ nl testfile | sed '6a I love Linux'
    -$ nl testfile | sed '6a\I love Linux'
    -     1    HELLO LINUX!
    -     2    Linux is a free unix-type opterating system.
    -     3    This is a linux testfile!
    -     4    Linux test
    -     5    Google
    -     6    Taobao
    -I love Linux
    -     7    Banbooob
    -     8    Tesetfile
    -     9    Wiki
    -

    testfile的内容列出并且打印行号,且在第3行前添加I am a journer learner。不修改原文件。

    $ nl testfile | sed '3i\I am a journer learner'
    -     1    HELLO LINUX!
    -     2    Linux is a free unix-type opterating system.
    -I am a journer learner
    -     3    This is a linux testfile!
    -     4    Linux test
    -     5    Google
    -     6    Taobao
    -     7    Banbooob
    -     8    Tesetfile
    -     9    Wiki
    -

    testfile的内容列出并且打印行号,且在第3行前添加三行内容Add line 1Add line 2Add line 3。用符合\进行换行。不修改原文件。

    $ nl testfile | sed '3i\Add line 1 \
    +

    testfile的内容列出并且打印行号,且在第6行后添加I love Linux。不修改原文件。

    $ nl testfile | sed '6a I love Linux'
    +$ nl testfile | sed '6a\I love Linux'
    +     1    HELLO LINUX!
    +     2    Linux is a free unix-type opterating system.
    +     3    This is a linux testfile!
    +     4    Linux test
    +     5    Google
    +     6    Taobao
    +I love Linux
    +     7    Banbooob
    +     8    Tesetfile
    +     9    Wiki
    +

    testfile的内容列出并且打印行号,且在第3行前添加I am a journer learner。不修改原文件。

    $ nl testfile | sed '3i\I am a journer learner'
    +     1    HELLO LINUX!
    +     2    Linux is a free unix-type opterating system.
    +I am a journer learner
    +     3    This is a linux testfile!
    +     4    Linux test
    +     5    Google
    +     6    Taobao
    +     7    Banbooob
    +     8    Tesetfile
    +     9    Wiki
    +

    testfile的内容列出并且打印行号,且在第3行前添加三行内容Add line 1Add line 2Add line 3。用符合\进行换行。不修改原文件。

    $ nl testfile | sed '3i\Add line 1 \
     Add line 2 \
     Add line 3'
    -     1    HELLO LINUX!
    -     2    Linux is a free unix-type opterating system.
    -Add line 1
    -Add line 2
    -Add line 3
    -     3    This is a linux testfile!
    -     4    Linux test
    -     5    Google
    -     6    Taobao
    -     7    Banbooob
    -     8    Tesetfile
    -     9    Wiki
    -

    testfile的内容列出并且打印行号,且将第2-5行的内容取代成为replaced。不修改原文件。

    $ nl testfile | sed '2,5c\replaced'
    -$ nl testfile | sed '2,5c replaced'
    -$ nl testfile | sed '2,5creplaced'
    -     1    HELLO LINUX!
    +     1    HELLO LINUX!
    +     2    Linux is a free unix-type opterating system.
    +Add line 1
    +Add line 2
    +Add line 3
    +     3    This is a linux testfile!
    +     4    Linux test
    +     5    Google
    +     6    Taobao
    +     7    Banbooob
    +     8    Tesetfile
    +     9    Wiki
    +

    testfile的内容列出并且打印行号,且将第2-5行的内容取代成为replaced。不修改原文件。

    $ nl testfile | sed '2,5c\replaced'
    +$ nl testfile | sed '2,5c replaced'
    +$ nl testfile | sed '2,5creplaced'
    +     1    HELLO LINUX!
     replaced
    -     6    Taobao
    -     7    Banbooob
    -     8    Tesetfile
    -     9    Wiki
    -

    testfile的内容列出并且打印行号,且删除第2~5行。不修改原文件。

    $ nl testfile | sed '2,5d'
    -     1    HELLO LINUX!
    -     6    Taobao
    -     7    Banbooob
    -     8    Tesetfile
    -     9    Wiki
    -

    testfile的内容列出并且打印行号,且删除第5行到最后一行。

    $ nl testfile | sed '5,$d'
    -     1    HELLO LINUX!
    -     2    Linux is a free unix-type opterating system.
    -     3    This is a linux testfile!
    -     4    Linux test
    -

    匹配定位文件testfile中包含关键字linux的行。

    $ sed -n '/linux/p' testfile
    -This is a linux testfile!
    -

    匹配定位命令df输出中以/dev/sd关键字开头的行。(需要转义符\

    $ df | sed -n '/^\/dev\/sd/p'
    -/dev/sda2      102750208 7077280  92055312   8% /
    -/dev/sda2      102750208 7077280  92055312   8% /.snapshots
    -/dev/sda2      102750208 7077280  92055312   8% /home
    -/dev/sda2      102750208 7077280  92055312   8% /opt
    -/dev/sda2      102750208 7077280  92055312   8% /root
    -/dev/sda2      102750208 7077280  92055312   8% /boot/grub2/x86_64-efi
    -/dev/sda2      102750208 7077280  92055312   8% /boot/grub2/i386-pc
    -/dev/sda2      102750208 7077280  92055312   8% /srv
    -/dev/sda2      102750208 7077280  92055312   8% /tmp
    -/dev/sda2      102750208 7077280  92055312   8% /usr/local
    -/dev/sda2      102750208 7077280  92055312   8% /var
    -

    匹配定位命令df输出中不以/dev/sd关键字开头的行。通过!p进行求反输出。

    $ df | sed -n '/^\/dev\/sd/!p'
    -Filesystem     1K-blocks    Used Available Use% Mounted on
    -devtmpfs            4096       0      4096   0% /dev
    -tmpfs            1971208       0   1971208   0% /dev/shm
    -tmpfs             788484    9612    778872   2% /run
    -tmpfs               4096       0      4096   0% /sys/fs/cgroup
    -tmpfs             394240       0    394240   0% /run/user/1000
    -

    匹配定位命令df输出中不以/dev/sdtmp关键字开头的行。

    $ df | sed '/^\/dev\/sd/d;/^tmp/d'
    -Filesystem     1K-blocks    Used Available Use% Mounted on
    -devtmpfs            4096       0      4096   0% /dev
    -
    -$ df | grep -Ev '^\/dev\/sd|^tmp'
    -Filesystem     1K-blocks    Used Available Use% Mounted on
    -devtmpfs            4096       0      4096   0% /dev
    -

    搜索文件testfile所有包含oo关键字的行并匹配输出。不修改原文件。

    $ sed -n '/ooo/p' testfile
    +     6    Taobao
    +     7    Banbooob
    +     8    Tesetfile
    +     9    Wiki
    +

    testfile的内容列出并且打印行号,且删除第2~5行。不修改原文件。

    $ nl testfile | sed '2,5d'
    +     1    HELLO LINUX!
    +     6    Taobao
    +     7    Banbooob
    +     8    Tesetfile
    +     9    Wiki
    +

    testfile的内容列出并且打印行号,且删除第5行到最后一行。

    $ nl testfile | sed '5,$d'
    +     1    HELLO LINUX!
    +     2    Linux is a free unix-type opterating system.
    +     3    This is a linux testfile!
    +     4    Linux test
    +

    匹配定位文件testfile中包含关键字linux的行。

    $ sed -n '/linux/p' testfile
    +This is a linux testfile!
    +

    匹配定位命令df输出中以/dev/sd关键字开头的行。(需要转义符\

    $ df | sed -n '/^\/dev\/sd/p'
    +/dev/sda2      102750208 7077280  92055312   8% /
    +/dev/sda2      102750208 7077280  92055312   8% /.snapshots
    +/dev/sda2      102750208 7077280  92055312   8% /home
    +/dev/sda2      102750208 7077280  92055312   8% /opt
    +/dev/sda2      102750208 7077280  92055312   8% /root
    +/dev/sda2      102750208 7077280  92055312   8% /boot/grub2/x86_64-efi
    +/dev/sda2      102750208 7077280  92055312   8% /boot/grub2/i386-pc
    +/dev/sda2      102750208 7077280  92055312   8% /srv
    +/dev/sda2      102750208 7077280  92055312   8% /tmp
    +/dev/sda2      102750208 7077280  92055312   8% /usr/local
    +/dev/sda2      102750208 7077280  92055312   8% /var
    +

    匹配定位命令df输出中不以/dev/sd关键字开头的行。通过!p进行求反输出。

    $ df | sed -n '/^\/dev\/sd/!p'
    +Filesystem     1K-blocks    Used Available Use% Mounted on
    +devtmpfs            4096       0      4096   0% /dev
    +tmpfs            1971208       0   1971208   0% /dev/shm
    +tmpfs             788484    9612    778872   2% /run
    +tmpfs               4096       0      4096   0% /sys/fs/cgroup
    +tmpfs             394240       0    394240   0% /run/user/1000
    +

    匹配定位命令df输出中不以/dev/sdtmp关键字开头的行。

    $ df | sed '/^\/dev\/sd/d;/^tmp/d'
    +Filesystem     1K-blocks    Used Available Use% Mounted on
    +devtmpfs            4096       0      4096   0% /dev
    +
    +$ df | grep -Ev '^\/dev\/sd|^tmp'
    +Filesystem     1K-blocks    Used Available Use% Mounted on
    +devtmpfs            4096       0      4096   0% /dev
    +

    搜索文件testfile所有包含oo关键字的行并匹配输出。不修改原文件。

    $ sed -n '/ooo/p' testfile
     Banbooob
     
    -$ sed -n '/oo/p' testfile
    +$ sed -n '/oo/p' testfile
     Google
     Banbooob
    -

    搜索文件testfile所有包含oo关键字的行并删除。不修改原文件。

    $ sed '/oo/d' testfile
    -HELLO LINUX!
    -Linux is a free unix-type opterating system.
    -This is a linux testfile!
    -Linux test
    +

    搜索文件testfile所有包含oo关键字的行并删除。不修改原文件。

    $ sed '/oo/d' testfile
    +HELLO LINUX!
    +Linux is a free unix-type opterating system.
    +This is a linux testfile!
    +Linux test
     Taobao
     Tesetfile
     Wiki
    -

    搜索文件testfile所有包含oo的行,把oo替换为kk,再输出这行。不修改原文件。

    $ sed -n '/oo/{s/oo/kk/;p;q}' testfile
    -$ sed -ne '/oo/{s/oo/kk/;p;q}' testfile
    +

    搜索文件testfile所有包含oo的行,把oo替换为kk,再输出这行。不修改原文件。

    $ sed -n '/oo/{s/oo/kk/;p;q}' testfile
    +$ sed -ne '/oo/{s/oo/kk/;p;q}' testfile
     Gkkgle
    -

    testfile的每行中第一次出现ao的替换成HH

    $ sed 's/ao/HH/' testfile
    -HELLO LINUX!
    -Linux is a free unix-type opterating system.
    -This is a linux testfile!
    -Linux test
    +

    testfile的每行中第一次出现ao的替换成HH

    $ sed 's/ao/HH/' testfile
    +HELLO LINUX!
    +Linux is a free unix-type opterating system.
    +This is a linux testfile!
    +Linux test
     Google
     THHbao
     Banbooob
     Tesetfile
     Wiki
    -

    下面是把testfile的匹配到ao的行替换成HH

    sed '/ao/cHH' testfile
    -HELLO LINUX!
    +

    下面是把testfile的匹配到ao的行替换成HH

    sed '/ao/cHH' testfile
    +HELLO LINUX!
     SUSE
    -This is a linux testfile!
    +This is a linux testfile!
     SUSE
     Google
     Taobao
     Banbooob
     Tesetfile
     Wiki
    -

    搜索文件testfile所有包含ao的全部替换成HHg表示全局匹配。不修改原文件。

    $ sed -e 's/ao/HH/g' testfile
    -$ sed 's/ao/HH/g' testfile
    -HELLO LINUX!
    -Linux is a free unix-type opterating system.
    -This is a linux testfile!
    -Linux test
    +

    搜索文件testfile所有包含ao的全部替换成HHg表示全局匹配。不修改原文件。

    $ sed -e 's/ao/HH/g' testfile
    +$ sed 's/ao/HH/g' testfile
    +HELLO LINUX!
    +Linux is a free unix-type opterating system.
    +This is a linux testfile!
    +Linux test
     Google
     THHbHH
     Banbooob
     Tesetfile
     Wiki
    -

    在文件/etc/passwd中查找匹配所有符合r开头t结尾且中间含任意两个字符的行,并在t字母后添加er

    $ sed -nr 's/r..t/&er/gp' /etc/passwd
    +

    在文件/etc/passwd中查找匹配所有符合r开头t结尾且中间含任意两个字符的行,并在t字母后添加er

    $ sed -nr 's/r..t/&er/gp' /etc/passwd
     rooter:x:0:0:rooter:/rooter:/bin/bash
    -lp:x:493:487:Printering daemon:/var/spool/lpd:/usr/sbin/nologin
    -tftp:x:487:474:TFTP account:/srv/terftpboot:/bin/false
    +lp:x:493:487:Printering daemon:/var/spool/lpd:/usr/sbin/nologin
    +tftp:x:487:474:TFTP account:/srv/terftpboot:/bin/false
     vagranter:x:1000:478:vagranter:/home/vagranter:/bin/bash
     tester1:x:600:1530:"Test User1,terestuser1@abc.com":/home/tester1:/bin/bash
     

    将上述结果和原始内容进行对比,能更好的理解s/r..t/&er的操作。

    rooter:x:0:0:rooter:/rooter:/bin/bash
     root:x:0:0:root:/root:/bin/bash
     
    -lp:x:493:487:Printering daemon:/var/spool/lpd:/usr/sbin/nologin
    -lp:x:493:487:Printing daemon:/var/spool/lpd:/usr/sbin/nologin
    +lp:x:493:487:Printering daemon:/var/spool/lpd:/usr/sbin/nologin
    +lp:x:493:487:Printing daemon:/var/spool/lpd:/usr/sbin/nologin
     
    -tftp:x:487:474:TFTP account:/srv/terftpboot:/bin/false
    -tftp:x:487:474:TFTP account:/srv/tftpboot:/bin/false
    +tftp:x:487:474:TFTP account:/srv/terftpboot:/bin/false
    +tftp:x:487:474:TFTP account:/srv/tftpboot:/bin/false
     
     vagranter:x:1000:478:vagranter:/home/vagranter:/bin/bash
     vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash
    @@ -390,100 +390,100 @@
     tester1:x:600:1530:"Test User1,terestuser1@abc.com":/home/tester1:/bin/bash
     tester1:x:600:1530:"Test User1,testuser1@abc.com":/home/tester1:/bin/bash
     

    体会&的位置不同的不同含义。

    # 附加在root单词后
    -$ sed -n 's/root/&superman/p' /etc/passwd
    +$ sed -n 's/root/&superman/p' /etc/passwd
     rootsuperman:x:0:0:root:/root:/bin/bash
     
     # 附加在root单词前
    -$ sed -n 's/root/superman&/p' /etc/passwd
    +$ sed -n 's/root/superman&/p' /etc/passwd
     supermanroot:x:0:0:root:/root:/bin/bash
    -

    使用参数-i进行源文件修改。

    $ sed -i 's/ao/HH/' testfile
    -$ cat testfile
    -HELLO LINUX!
    -Linux is a free unix-type opterating system.
    -This is a linux testfile!
    -Linux test
    +

    使用参数-i进行源文件修改。

    $ sed -i 's/ao/HH/' testfile
    +$ cat testfile
    +HELLO LINUX!
    +Linux is a free unix-type opterating system.
    +This is a linux testfile!
    +Linux test
     Google
     THHbao
     Banbooob
     Tesetfile
     Wiki
    -

    源文件修改前,备份在新文件testfile.new

    $ sed -i.new 's/ao/HH/' testfile
    +

    源文件修改前,备份在新文件testfile.new

    $ sed -i.new 's/ao/HH/' testfile
     
    -$ cat testfile.new
    -HELLO LINUX!
    -Linux is a free unix-type opterating system.
    -This is a linux testfile!
    -Linux test
    +$ cat testfile.new
    +HELLO LINUX!
    +Linux is a free unix-type opterating system.
    +This is a linux testfile!
    +Linux test
     Google
     Taobao
     Banbooob
     Tesetfile
     Wiki
     
    -$ cat testfile
    -HELLO LINUX!
    -Linux is a free unix-type opterating system.
    -This is a linux testfile!
    -Linux test
    +$ cat testfile
    +HELLO LINUX!
    +Linux is a free unix-type opterating system.
    +This is a linux testfile!
    +Linux test
     Google
     THHbao
     Banbooob
     Tesetfile
     Wiki
    -

    范例:除指定文件外,其余都删除。

    $ touch {1..9}file.txt
    +

    范例:除指定文件外,其余都删除。

    $ touch {1..9}file.txt
     
    -$ ls
    -1file.txt  2file.txt  3file.txt  4file.txt  5file.txt  6file.txt  7file.txt  8file.txt  9file.txt
    +$ ls
    +1file.txt  2file.txt  3file.txt  4file.txt  5file.txt  6file.txt  7file.txt  8file.txt  9file.txt
     
    -$ ls | grep -E '(3|5|7)file\.txt'
    +$ ls | grep -E '(3|5|7)file\.txt'
     3file.txt
     5file.txt
     7file.txt
     
    -$ ls | grep -Ev '(3|5|7)file\.txt'
    +$ ls | grep -Ev '(3|5|7)file\.txt'
     1file.txt
     2file.txt
     4file.txt
     6file.txt
     8file.txt
     9file.txt
    -

    下面四种方法实现同样的功能

    $ rm `ls | grep -Ev '(3|5|7)file\.txt'`
    -$ ls | sed -n '/^[357]file.txt/!p' | xargs rm
    -$ ls | grep -Ev '(3|5|7)file\.txt' | sed -n 's/.*/rm &/p' | bash
    -$ ls | grep -Ev '(3|5|7)file\.txt' | sed -En 's/(.*)/rm &/p' | bash
    -$ ls | grep -Ev '(3|5|7)file\.txt' | sed -En 's/(.*)/rm \1/p' | bash
    -
    -$ ls
    -3file.txt  5file.txt  7file.txt
    -

    后向引用\0 \1 \2等。

    $ $echo 123456789 | sed -nE 's/(123)(456)(789)/\1/p'
    +

    下面四种方法实现同样的功能

    $ rm `ls | grep -Ev '(3|5|7)file\.txt'`
    +$ ls | sed -n '/^[357]file.txt/!p' | xargs rm
    +$ ls | grep -Ev '(3|5|7)file\.txt' | sed -n 's/.*/rm &/p' | bash
    +$ ls | grep -Ev '(3|5|7)file\.txt' | sed -En 's/(.*)/rm &/p' | bash
    +$ ls | grep -Ev '(3|5|7)file\.txt' | sed -En 's/(.*)/rm \1/p' | bash
    +
    +$ ls
    +3file.txt  5file.txt  7file.txt
    +

    后向引用\0 \1 \2等。

    $ $echo 123456789 | sed -nE 's/(123)(456)(789)/\1/p'
     123
     
    -$  echo 123456789 | sed -nE 's/(123)(456)(789)/\2/p'
    +$  echo 123456789 | sed -nE 's/(123)(456)(789)/\2/p'
     456
     
    -$ echo 123456789 | sed -nE 's/(123)(456)(789)/\3/p'
    +$ echo 123456789 | sed -nE 's/(123)(456)(789)/\3/p'
     789
     
    -$ echo 123456789 | sed -nE 's/(123)(456)(789)/\3\1\2/p'
    +$ echo 123456789 | sed -nE 's/(123)(456)(789)/\3\1\2/p'
     789123456
     
    -$ echo 123456789 | sed -nE 's/(123)(456)(789)/\1xyz\2/p'
    +$ echo 123456789 | sed -nE 's/(123)(456)(789)/\1xyz\2/p'
     123xyz456
    -

    范例:获取分区利用率

    $ df | sed -En '/^\/dev\/sd/p'
    -/dev/sda2      102750208 7079236  92053692   8% /
    -/dev/sda2      102750208 7079236  92053692   8% /.snapshots
    -/dev/sda2      102750208 7079236  92053692   8% /boot/grub2/i386-pc
    -/dev/sda2      102750208 7079236  92053692   8% /boot/grub2/x86_64-efi
    -/dev/sda2      102750208 7079236  92053692   8% /home
    -/dev/sda2      102750208 7079236  92053692   8% /opt
    -/dev/sda2      102750208 7079236  92053692   8% /root
    -/dev/sda2      102750208 7079236  92053692   8% /srv
    -/dev/sda2      102750208 7079236  92053692   8% /usr/local
    -/dev/sda2      102750208 7079236  92053692   8% /tmp
    -/dev/sda2      102750208 7079236  92053692   8% /var
    -
    -$ df | sed -En '/^\/dev\/sd/s@.*([0-9]+)%.*@\1@p'
    -$ df | sed -En '/^\/dev\/sd/s#.*([0-9]+)%.*#\1#p'
    +

    范例:获取分区利用率

    $ df | sed -En '/^\/dev\/sd/p'
    +/dev/sda2      102750208 7079236  92053692   8% /
    +/dev/sda2      102750208 7079236  92053692   8% /.snapshots
    +/dev/sda2      102750208 7079236  92053692   8% /boot/grub2/i386-pc
    +/dev/sda2      102750208 7079236  92053692   8% /boot/grub2/x86_64-efi
    +/dev/sda2      102750208 7079236  92053692   8% /home
    +/dev/sda2      102750208 7079236  92053692   8% /opt
    +/dev/sda2      102750208 7079236  92053692   8% /root
    +/dev/sda2      102750208 7079236  92053692   8% /srv
    +/dev/sda2      102750208 7079236  92053692   8% /usr/local
    +/dev/sda2      102750208 7079236  92053692   8% /tmp
    +/dev/sda2      102750208 7079236  92053692   8% /var
    +
    +$ df | sed -En '/^\/dev\/sd/s@.*([0-9]+)%.*@\1@p'
    +$ df | sed -En '/^\/dev\/sd/s#.*([0-9]+)%.*#\1#p'
     # df | sed -En '/^\/dev\/sd/s/.*([0-9]+)%.*/\1/p'
     8
     8
    @@ -496,126 +496,126 @@
     8
     8
     8
    -

    体会下面空格和括弧带来的不同。

    $ df | sed -En '/^\/dev\/sd/s# .*([0-9]+)%.*# \1#p'
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -
    -$ df | sed -En '/^\/dev\/sd/s#( .*)([0-9]+)%.*# \1#p'
    -/dev/sda2       102750208 7079804  92053156
    -/dev/sda2       102750208 7079804  92053156
    -/dev/sda2       102750208 7079804  92053156
    -/dev/sda2       102750208 7079804  92053156
    -/dev/sda2       102750208 7079804  92053156
    -/dev/sda2       102750208 7079804  92053156
    -/dev/sda2       102750208 7079804  92053156
    -/dev/sda2       102750208 7079804  92053156
    -/dev/sda2       102750208 7079804  92053156
    -/dev/sda2       102750208 7079804  92053156
    -/dev/sda2       102750208 7079804  92053156
    -
    -$ df | sed -En '/^\/dev\/sd/s#( .*)([0-9]+)%.*# \2#p'
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -

    范例:取得当前IP地址。

    $ ifconfig eth0
    -eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
    -        inet 192.168.10.210  netmask 255.255.255.0  broadcast 192.168.10.255
    -        inet6 fe80::20c:29ff:fea4:e17a  prefixlen 64  scopeid 0x20<link>
    -        ether 00:0c:29:a4:e1:7a  txqueuelen 1000  (Ethernet)
    -        RX packets 22923  bytes 1658298 (1.5 MiB)
    -        RX errors 0  dropped 0  overruns 0  frame 0
    -        TX packets 3763  bytes 442641 (432.2 KiB)
    -        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    -
    -$ ip addr show eth0
    -2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    -    link/ether 00:0c:29:a4:e1:7a brd ff:ff:ff:ff:ff:ff
    -    altname enp2s1
    -    altname ens33
    -    inet 192.168.10.210/24 brd 192.168.10.255 scope global eth0
    -       valid_lft forever preferred_lft forever
    -    inet6 fe80::20c:29ff:fea4:e17a/64 scope link
    -       valid_lft forever preferred_lft forever
    -
    -
    -$ ifconfig eth0 | sed -En '2s/[^0-9]+([0-9.]+).*/\1/p'
    -$ ifconfig eth0 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*/\1/p'
    -$ ifconfig eth0 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*$/\1/p'
    -$ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.*//p'
    -$ ifconfig eth0 | sed -n '2s/^.*inet //;s/ netmask.*//p'
    -$ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\2/p'
    +

    体会下面空格和括弧带来的不同。

    $ df | sed -En '/^\/dev\/sd/s# .*([0-9]+)%.*# \1#p'
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +
    +$ df | sed -En '/^\/dev\/sd/s#( .*)([0-9]+)%.*# \1#p'
    +/dev/sda2       102750208 7079804  92053156
    +/dev/sda2       102750208 7079804  92053156
    +/dev/sda2       102750208 7079804  92053156
    +/dev/sda2       102750208 7079804  92053156
    +/dev/sda2       102750208 7079804  92053156
    +/dev/sda2       102750208 7079804  92053156
    +/dev/sda2       102750208 7079804  92053156
    +/dev/sda2       102750208 7079804  92053156
    +/dev/sda2       102750208 7079804  92053156
    +/dev/sda2       102750208 7079804  92053156
    +/dev/sda2       102750208 7079804  92053156
    +
    +$ df | sed -En '/^\/dev\/sd/s#( .*)([0-9]+)%.*# \2#p'
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +

    范例:取得当前IP地址。

    $ ifconfig eth0
    +eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
    +        inet 192.168.10.210  netmask 255.255.255.0  broadcast 192.168.10.255
    +        inet6 fe80::20c:29ff:fea4:e17a  prefixlen 64  scopeid 0x20<link>
    +        ether 00:0c:29:a4:e1:7a  txqueuelen 1000  (Ethernet)
    +        RX packets 22923  bytes 1658298 (1.5 MiB)
    +        RX errors 0  dropped 0  overruns 0  frame 0
    +        TX packets 3763  bytes 442641 (432.2 KiB)
    +        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    +
    +$ ip addr show eth0
    +2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    +    link/ether 00:0c:29:a4:e1:7a brd ff:ff:ff:ff:ff:ff
    +    altname enp2s1
    +    altname ens33
    +    inet 192.168.10.210/24 brd 192.168.10.255 scope global eth0
    +       valid_lft forever preferred_lft forever
    +    inet6 fe80::20c:29ff:fea4:e17a/64 scope link
    +       valid_lft forever preferred_lft forever
    +
    +
    +$ ifconfig eth0 | sed -En '2s/[^0-9]+([0-9.]+).*/\1/p'
    +$ ifconfig eth0 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*/\1/p'
    +$ ifconfig eth0 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*$/\1/p'
    +$ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.*//p'
    +$ ifconfig eth0 | sed -n '2s/^.*inet //;s/ netmask.*//p'
    +$ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\2/p'
     192.168.10.210
     192.168.10.210
     192.168.10.210
    -

    使用\0输出全部变量。

    $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\0/p'
    -        inet 192.168.10.210  netmask 255.255.255.0  broadcast 192.168.10.255
    +

    使用\0输出全部变量。

    $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\0/p'
    +        inet 192.168.10.210  netmask 255.255.255.0  broadcast 192.168.10.255
     
    -$ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\1/p'
    -        inet
    +$ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\1/p'
    +        inet
     
    -$ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\2/p'
    +$ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\2/p'
     192.168.10.210
     
    -$ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\3/p'
    -netmask 255.255.255.0  broadcast 192.168.10.255
    -

    对比下面两个指令的匹配差异。

    $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/ netmask.*//p'
    +$ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\3/p'
    +netmask 255.255.255.0  broadcast 192.168.10.255
    +

    对比下面两个指令的匹配差异。

    $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/ netmask.*//p'
     192.168.10.210
     
    -$ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.* //p'
    -192.168.10.210  192.168.10.255
    +$ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.* //p'
    +192.168.10.210  192.168.10.255
     
    -$ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask .*//p'
    +$ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask .*//p'
     192.168.10.210
     
    -$ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.*//p'
    +$ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.*//p'
     192.168.10.210
     

    范例:取基名和目录名。 (/etc/sysconfig/network-scripts/目录在Rocky9中默认已创建,在openSUSE和Ubuntu中没有)

    # 取目录名
    -$ echo "/etc/sysconfig/network-scripts/" | sed -E 's#(^/.*/)([^/]+/?)#\1#'
    -$ echo "/etc/sysconfig/network-scripts/" | sed -E 's/(^\/.*\/)([^\/]+\/?)/\1/'
    +$ echo "/etc/sysconfig/network-scripts/" | sed -E 's#(^/.*/)([^/]+/?)#\1#'
    +$ echo "/etc/sysconfig/network-scripts/" | sed -E 's/(^\/.*\/)([^\/]+\/?)/\1/'
     /etc/sysconfig/
     # 取基名
    -$ echo "/etc/sysconfig/network-scripts/" | sed -E 's#(^/.*/)([^/]+/?)#\2#'
    -$ echo "/etc/sysconfig/network-scripts/" | sed -E 's/(^\/.*\/)([^\/]+\/?)/\2/'
    +$ echo "/etc/sysconfig/network-scripts/" | sed -E 's#(^/.*/)([^/]+/?)#\2#'
    +$ echo "/etc/sysconfig/network-scripts/" | sed -E 's/(^\/.*\/)([^\/]+\/?)/\2/'
     network-scripts/
     
     # 取目录名
    -$ echo "/etc/sysconfig/network-scripts/dummyfile" | sed -E 's#(^/.*/)([^/]+/?)#\1#'
    -$ echo "/etc/sysconfig/network-scripts/dummyfille" | sed -E 's/(^\/.*\/)([^\/]+\/?)/\1/'
    +$ echo "/etc/sysconfig/network-scripts/dummyfile" | sed -E 's#(^/.*/)([^/]+/?)#\1#'
    +$ echo "/etc/sysconfig/network-scripts/dummyfille" | sed -E 's/(^\/.*\/)([^\/]+\/?)/\1/'
     /etc/sysconfig/network-scripts/
     # 取基名
    -$ echo "/etc/sysconfig/network-scripts/dummyfile" | sed -E 's#(^/.*/)([^/]+/?)#\2#'
    -$ echo "/etc/sysconfig/network-scripts/dummyfille" | sed -E 's/(^\/.*\/)([^\/]+\/?)/\2/'
    +$ echo "/etc/sysconfig/network-scripts/dummyfile" | sed -E 's#(^/.*/)([^/]+/?)#\2#'
    +$ echo "/etc/sysconfig/network-scripts/dummyfille" | sed -E 's/(^\/.*\/)([^\/]+\/?)/\2/'
     dummyfille
    -

    范例:取文件名和文件扩展名

    $ echo 1_.file.tar.gz | sed -En 's/(.*)\.([^.]+)$/\1/p'
    -$ echo 1_.file.tar.gz | sed -En 's@(.*)\.([^.]+)$@\1@p'
    +

    范例:取文件名和文件扩展名

    $ echo 1_.file.tar.gz | sed -En 's/(.*)\.([^.]+)$/\1/p'
    +$ echo 1_.file.tar.gz | sed -En 's@(.*)\.([^.]+)$@\1@p'
     1_.file.tar
     
    -$ echo 1_.file.tar.gz | sed -En 's/(.*)\.([^.]+)$/\2/p'
    -$ echo 1_.file.tar.gz | sed -En 's@(.*)\.([^.]+)$@\2@p'
    +$ echo 1_.file.tar.gz | sed -En 's/(.*)\.([^.]+)$/\2/p'
    +$ echo 1_.file.tar.gz | sed -En 's@(.*)\.([^.]+)$@\2@p'
     gz
    -
    $ echo 1_.file.tar.gz | grep -Eo '.*\.'
    +
    $ echo 1_.file.tar.gz | grep -Eo '.*\.'
     1_.file.tar.
     
    -$ echo 1_.file.tar.gz | grep -Eo '[^.]+$'
    +$ echo 1_.file.tar.gz | grep -Eo '[^.]+$'
     gz
    -

    范例:将非#开头的行添加#

    $ cat <<EOF > testfile
    +

    范例:将非#开头的行添加#

    $ cat <<EOF > testfile
     HELLO LINUX!
     Linux is a free unix-type opterating system.
     This is a linux testfile!
    @@ -627,8 +627,8 @@
     #Wiki
     EOF
     
    -$ sed -En 's/^[^#]/#&/p' testfile
    -$ sed -En 's/^[^#](.*)/#\1/p' testfile
    +$ sed -En 's/^[^#]/#&/p' testfile
    +$ sed -En 's/^[^#](.*)/#\1/p' testfile
     #HELLO LINUX!
     #Linux is a free unix-type opterating system.
     #This is a linux testfile!
    @@ -636,7 +636,7 @@
     #Google
     #Taobao
     #Banbooob
    -

    范例:将#开头的行删除#

    $ cat <<EOF > testfile
    +

    范例:将#开头的行删除#

    $ cat <<EOF > testfile
     HELLO LINUX!
     Linux is a free unix-type opterating system.
     This is a linux testfile!
    @@ -648,26 +648,26 @@
     #Wiki
     EOF
     
    -$ sed -Ei.bak '/^#/s/^#//' testfile
    +$ sed -Ei.bak '/^#/s/^#//' testfile
     
    -$ cat testfile
    -HELLO LINUX!
    -Linux is a free unix-type opterating system.
    -This is a linux testfile!
    -Linux test
    +$ cat testfile
    +HELLO LINUX!
    +Linux is a free unix-type opterating system.
    +This is a linux testfile!
    +Linux test
     Google
     Taobao
     Banbooob
     Tesetfile
     Wiki
    -

    sed保持空间(hold space)的例子:

    • d:删除pattern space的内容,开始下一个循环。

    • D:如果模式空间保护换行符,则删除直到第一个换行符到模式空间中的文本,并不读取新的输入行,而使用合成的模式空间重新启动循环。如果模式空间不包含换行符,则类似d命令启动正常的新循环。

    • hH:复制/追加模式空间的内容到保持空间。

    • gG:复制/追加保持空间的内容到模式空间。

    • nN:复制/追加匹配到的下一行到模式空间。

    • p:打印当前模式空间内容。

    • P:打印模式空间开头至\n的内容,并追加到默认输出之前。

    • x:交换保持空间和模式空间的内容.

    举例解读1:

    1. seq 10命令输出1~10个数字,每个数字一行。

    2. sed命令读取第一行1到模式空间。因为参数-n,所以读取到的1不打印到屏幕。

    3. 执行n命令,即读取匹配到的下一行到模式空间,即把第二行的2读取并覆盖到模式空间。

    4. 执行p命令,把2输出到屏幕。

    5. 以此类推,读取第三行的3到模式空间,执行n命令,将第四行的4读取并覆盖到模式空间。执行p命令,输出4到屏幕。

    6. 以此类推。

    $ seq 10 | sed -n 'n;p'
    +

    sed保持空间(hold space)的例子:

    • d:删除pattern space的内容,开始下一个循环。

    • D:如果模式空间保护换行符,则删除直到第一个换行符到模式空间中的文本,并不读取新的输入行,而使用合成的模式空间重新启动循环。如果模式空间不包含换行符,则类似d命令启动正常的新循环。

    • hH:复制/追加模式空间的内容到保持空间。

    • gG:复制/追加保持空间的内容到模式空间。

    • nN:复制/追加匹配到的下一行到模式空间。

    • p:打印当前模式空间内容。

    • P:打印模式空间开头至\n的内容,并追加到默认输出之前。

    • x:交换保持空间和模式空间的内容.

    举例解读1:

    1. seq 10命令输出1~10个数字,每个数字一行。

    2. sed命令读取第一行1到模式空间。因为参数-n,所以读取到的1不打印到屏幕。

    3. 执行n命令,即读取匹配到的下一行到模式空间,即把第二行的2读取并覆盖到模式空间。

    4. 执行p命令,把2输出到屏幕。

    5. 以此类推,读取第三行的3到模式空间,执行n命令,将第四行的4读取并覆盖到模式空间。执行p命令,输出4到屏幕。

    6. 以此类推。

    $ seq 10 | sed -n 'n;p'
     2
     4
     6
     8
     10
     
    -seq 10 | sed 'n;p'
    +seq 10 | sed 'n;p'
     1
     2
     2
    @@ -683,13 +683,13 @@
     9
     10
     10
    -

    举例解读2:

    • seq 10命令输出1~10个数字,每个数字一行。

    • sed命令读取第一行到1到模式空间(覆盖)。

    • 执行命令N,即读取下一行,即第二行的2,追加到模式空间。所以当前模式空间有12这2行记录。

    • 执行s/\n//,把模式空间中的第一行的1后面的\n替换为空,即,原来模式空间的两行12现在合并为一行,即12

    • 读取第三行的3到模式空间(覆盖)。

    • 执行命令N,即读取下一行,即第四行的4,追加到模式空间。所以当前模式空间有34这2行记录。

    • 执行s/\n//,把模式空间中的第一行3后面的\n替换为空,即,原来模式空间的两行34现在合并为一行,即34

    • 以此类推。

    $ seq 10 | sed 'N;s/\n//'
    +

    举例解读2:

    • seq 10命令输出1~10个数字,每个数字一行。

    • sed命令读取第一行到1到模式空间(覆盖)。

    • 执行命令N,即读取下一行,即第二行的2,追加到模式空间。所以当前模式空间有12这2行记录。

    • 执行s/\n//,把模式空间中的第一行的1后面的\n替换为空,即,原来模式空间的两行12现在合并为一行,即12

    • 读取第三行的3到模式空间(覆盖)。

    • 执行命令N,即读取下一行,即第四行的4,追加到模式空间。所以当前模式空间有34这2行记录。

    • 执行s/\n//,把模式空间中的第一行3后面的\n替换为空,即,原来模式空间的两行34现在合并为一行,即34

    • 以此类推。

    $ seq 10 | sed 'N;s/\n//'
     12
     34
     56
     78
     910
    -

    举例解读3:

    • seq 10命令输出1~10个数字,每个数字一行。

    • sed命令读取第一行到1到模式空间(覆盖)。

    • 执行!G,即对第一行的1不执行G命令。

    • 执行h命令,即把1从模式空间覆盖至保持空间。至此,保持空间和模式空间都存有1

    • 执行$!d,即不是最后一行就从模式空间删除,所以把1从模式空间中删除。

    • sed命令读取第二行到2到模式空间(覆盖)。

    • 执行!G,即对第二行的2执行G命令,把1从保持空间追加到模式空间。至此,保持空间存有1,模式空间存有21

    • 执行h命令,即把21从模式空间覆盖至保持空间。至此,保持空间和模式空间都存有21

    • 执行$!d,即不是最后一行就从模式空间删除,所以把21从模式空间中删除。

    • 以此类推,直至读取最后一行10。此时,模式空间是10,保持空间存有987654321

    • 执行!G,即对最后一行的10执行G命令,把987654321从保持空间追加到模式空间。至此,保持空间存有987654321。,模式空间存有10987654321

    • 执行h命令,即把10987654321从模式空间覆盖至保持空间。至此,保持空间和模式空间都存有10987654321

    • 执行$!d,当前是最后一行,所以不从模式空间删除当前内容。

    • 输出模式空间内容至屏幕。即10~1。

    $ seq 10 | sed '1!G;h;$!d'
    +

    举例解读3:

    • seq 10命令输出1~10个数字,每个数字一行。

    • sed命令读取第一行到1到模式空间(覆盖)。

    • 执行!G,即对第一行的1不执行G命令。

    • 执行h命令,即把1从模式空间覆盖至保持空间。至此,保持空间和模式空间都存有1

    • 执行$!d,即不是最后一行就从模式空间删除,所以把1从模式空间中删除。

    • sed命令读取第二行到2到模式空间(覆盖)。

    • 执行!G,即对第二行的2执行G命令,把1从保持空间追加到模式空间。至此,保持空间存有1,模式空间存有21

    • 执行h命令,即把21从模式空间覆盖至保持空间。至此,保持空间和模式空间都存有21

    • 执行$!d,即不是最后一行就从模式空间删除,所以把21从模式空间中删除。

    • 以此类推,直至读取最后一行10。此时,模式空间是10,保持空间存有987654321

    • 执行!G,即对最后一行的10执行G命令,把987654321从保持空间追加到模式空间。至此,保持空间存有987654321。,模式空间存有10987654321

    • 执行h命令,即把10987654321从模式空间覆盖至保持空间。至此,保持空间和模式空间都存有10987654321

    • 执行$!d,当前是最后一行,所以不从模式空间删除当前内容。

    • 输出模式空间内容至屏幕。即10~1。

    $ seq 10 | sed '1!G;h;$!d'
     10
     9
     8
    @@ -700,21 +700,21 @@
     3
     2
     1
    -

    其他一些例子:

    $ seq 10 | sed -n '/3/{g;1!p;};h'
    +

    其他一些例子:

    $ seq 10 | sed -n '/3/{g;1!p;};h'
     2
    -$ seq 10 | sed -nr '/3/{n;p}'
    +$ seq 10 | sed -nr '/3/{n;p}'
     4
    -$ seq 10 | sed 'N;D'
    +$ seq 10 | sed 'N;D'
     10
    -$ seq 10 | sed '3h;9G;9!d'
    +$ seq 10 | sed '3h;9G;9!d'
     9
     3
    -$ seq 10 | sed '$!N;$!D'
    +$ seq 10 | sed '$!N;$!D'
     9
     10
    -$ seq 10 | sed '$!d'
    +$ seq 10 | sed '$!d'
     10
    -$ seq 10 | sed 'G'
    +$ seq 10 | sed 'G'
     1
     
     2
    @@ -735,7 +735,7 @@
     
     10
     
    -$ seq 10 | sed 'g'
    +$ seq 10 | sed 'g'
     
     
     
    @@ -746,7 +746,7 @@
     
     
     
    -$ seq 10 | sed '/^$/d;G'
    +$ seq 10 | sed '/^$/d;G'
     1
     
     2
    @@ -767,13 +767,13 @@
     
     10
     
    -$ seq 10 | sed 'n;d'
    +$ seq 10 | sed 'n;d'
     1
     3
     5
     7
     9
    -$ seq 10 | sed -n '1!G;h;$p'
    +$ seq 10 | sed -n '1!G;h;$p'
     10
     9
     8
    @@ -784,192 +784,192 @@
     3
     2
     1
    -

    5.10.三剑客awk命令

    awk是一个文本分析工具。grep擅长查找,sed擅长编辑,awk擅长数据分析并生成报告。

    awk的名称得自于它的创始人Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。

    awk有3个不同版本: awknawkgawk。我们说的awk一般指gawkgawkawk的GNU版本。

    awk把文件逐行读入,以空格为默认分隔符将每行切片,再对切片进行分析处理。

    5.10.1.命令格式

    awk 'pattern{action statements;...}' {filenames}

    • pattern表示awk在数据中查找的内容。是要表示的正则表达式,用斜杠括起来。

    • action是在找到匹配内容时所执行的一系列命令。

    • -F:指定分隔符,后面紧跟单引号,单引号内是分隔符。如不加-F选项,则以空格或者tab作为分隔符。

    • -v:var=value,变量赋值。

    提示:

    • -F ""指定空字符串作为字段分隔符,从而将输入字符串中的每个字符作为一个独立的字段进行处理。然后,使用循环遍历每个字段,如果字段中包含数字,则将其添加到str1变量中。最后,打印str1的值。
    • -F ''中的两个单引号之间没有提供有效的字段分隔符。在awk中,字段分隔符必须是一个非空字符串。

    示例:第一个和第三个命令是正确的。

    $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F "" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
    +

    5.10.三剑客awk命令

    awk是一个文本分析工具。grep擅长查找,sed擅长编辑,awk擅长数据分析并生成报告。

    awk的名称得自于它的创始人Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。

    awk有3个不同版本: awknawkgawk。我们说的awk一般指gawkgawkawk的GNU版本。

    awk把文件逐行读入,以空格为默认分隔符将每行切片,再对切片进行分析处理。

    5.10.1.命令格式

    awk 'pattern{action statements;...}' {filenames}

    • pattern表示awk在数据中查找的内容。是要表示的正则表达式,用斜杠括起来。

    • action是在找到匹配内容时所执行的一系列命令。

    • -F:指定分隔符,后面紧跟单引号,单引号内是分隔符。如不加-F选项,则以空格或者tab作为分隔符。

    • -v:var=value,变量赋值。

    提示:

    • -F ""指定空字符串作为字段分隔符,从而将输入字符串中的每个字符作为一个独立的字段进行处理。然后,使用循环遍历每个字段,如果字段中包含数字,则将其添加到str1变量中。最后,打印str1的值。
    • -F ''中的两个单引号之间没有提供有效的字段分隔符。在awk中,字段分隔符必须是一个非空字符串。

    示例:第一个和第三个命令是正确的。

    $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F "" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
     05989233334455
    -$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F"" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
    +$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F"" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
     
    -$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
    +$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
     05989233334455
    -$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F'' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
    -

    5.10.2.工作过程

    1. 执行BEGIN{action;...}语句块中的语句。

    2. BEGIN语句块再awk读入输入流之前被执行。

    3. 是可选语句块。

    4. 包含初始化变量,打印输出表格的表头等语句。

    5. 从文件或者标准输入stdin读取一行,然后执行pattern{action;...}语句块。从第一行开始到最后一行,逐行扫描文件,重复这个动作,直到文件或者输入流全部被读取完毕。

    6. 可选语句块。

    7. 如果没有提供pattern语句块,则默认执行{print}。

    8. 当读至文件或者输入流末尾时,执行END{action;...}语句块,比如打印所有行的分析结果这类汇总信息。也是一个可选语句块。

    5.10.3.分隔符、域和记录

    • 有分隔符分隔的字段(列column,域field),标记$1$2$3、...、$n称为域标识,$0为所有域。注意,和shell变量中的$不同。

    • 每一行成为记录(record)。

    • 如果省略action,则默认执行print $0操作。

    5.10.4.常用action分类

    • Output statements: print, printf

    • Expressions: 算术、比较表达式

    • Compund statements: 组合语句

    • Control statements: if, while语句

    • Input statements:

    动作print

    格式:print item1, item2, ...

    说明:

    • 逗号分隔符

    • 输出item可以是字符串,也可以是数值,是当前记录的字段、变量或awk表达式。

    • 如果省略item,相当于print $0

    • 固定字符需要用双引号,而变量和数字不需要。

    示例:

    $ seq 5 |awk '{print "hello awk"}'
    -hello awk
    -hello awk
    -hello awk
    -hello awk
    -hello awk
    -
    -$ seq 5 |awk '{print 3*5}'
    +$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F'' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
    +

    5.10.2.工作过程

    1. 执行BEGIN{action;...}语句块中的语句。

    2. BEGIN语句块再awk读入输入流之前被执行。

    3. 是可选语句块。

    4. 包含初始化变量,打印输出表格的表头等语句。

    5. 从文件或者标准输入stdin读取一行,然后执行pattern{action;...}语句块。从第一行开始到最后一行,逐行扫描文件,重复这个动作,直到文件或者输入流全部被读取完毕。

    6. 可选语句块。

    7. 如果没有提供pattern语句块,则默认执行{print}。

    8. 当读至文件或者输入流末尾时,执行END{action;...}语句块,比如打印所有行的分析结果这类汇总信息。也是一个可选语句块。

    5.10.3.分隔符、域和记录

    • 有分隔符分隔的字段(列column,域field),标记$1$2$3、...、$n称为域标识,$0为所有域。注意,和shell变量中的$不同。

    • 每一行成为记录(record)。

    • 如果省略action,则默认执行print $0操作。

    5.10.4.常用action分类

    • Output statements: print, printf

    • Expressions: 算术、比较表达式

    • Compund statements: 组合语句

    • Control statements: if, while语句

    • Input statements:

    动作print

    格式:print item1, item2, ...

    说明:

    • 逗号分隔符

    • 输出item可以是字符串,也可以是数值,是当前记录的字段、变量或awk表达式。

    • 如果省略item,相当于print $0

    • 固定字符需要用双引号,而变量和数字不需要。

    示例:

    $ seq 5 |awk '{print "hello awk"}'
    +hello awk
    +hello awk
    +hello awk
    +hello awk
    +hello awk
    +
    +$ seq 5 |awk '{print 3*5}'
     15
     15
     15
     15
     15
     
    -$ awk -F':' '{print "hello"}' /etc/passwd |head -5
    +$ awk -F':' '{print "hello"}' /etc/passwd |head -5
     hello
     hello
     hello
     hello
     hello
     
    -$ awk -F':' '{print}' /etc/passwd |head -5
    +$ awk -F':' '{print}' /etc/passwd |head -5
     root:x:0:0:root:/root:/bin/bash
    -messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false
    -systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin
    -systemd-timesync:x:496:496:systemd Time Synchronization:/:/usr/sbin/nologin
    +messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false
    +systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin
    +systemd-timesync:x:496:496:systemd Time Synchronization:/:/usr/sbin/nologin
     nobody:x:65534:65534:nobody:/var/lib/nobody:/bin/bash
     
    -$ awk -F':' '{print $0}' /etc/passwd |head -5
    +$ awk -F':' '{print $0}' /etc/passwd |head -5
     root:x:0:0:root:/root:/bin/bash
    -messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false
    -systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin
    -systemd-timesync:x:496:496:systemd Time Synchronization:/:/usr/sbin/nologin
    +messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false
    +systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin
    +systemd-timesync:x:496:496:systemd Time Synchronization:/:/usr/sbin/nologin
     nobody:x:65534:65534:nobody:/var/lib/nobody:/bin/bash
     
    -$ awk -F':' '{print $1,$3}' /etc/passwd |head -5
    -root 0
    -messagebus 499
    -systemd-network 497
    -systemd-timesync 496
    -nobody 65534
    -
    -$ awk -F':' '{print $1"\t"$3}' /etc/passwd |head -5
    -root    0
    -messagebus    499
    -systemd-network    497
    -systemd-timesync    496
    -nobody    65534
    -
    -
    -$ grep "^UUID" /etc/fstab |awk '{print $2,$3}'
    -/ btrfs
    -/var btrfs
    -/usr/local btrfs
    -/tmp btrfs
    -/srv btrfs
    -/root btrfs
    -/opt btrfs
    -/home btrfs
    -/boot/grub2/x86_64-efi btrfs
    -/boot/grub2/i386-pc btrfs
    -/.snapshots btrfs
    -swap swap
    -

    示例:读取分区利用率。

    分隔符中的定义[[:space:]]+|%的含义,一个或多个空格或者%作为分隔符。

    $ df |awk '{print $1,$5}'
    -Filesystem Use%
    -devtmpfs 0%
    -tmpfs 0%
    -tmpfs 2%
    -tmpfs 0%
    -/dev/sda2 8%
    -/dev/sda2 8%
    -/dev/sda2 8%
    -/dev/sda2 8%
    -/dev/sda2 8%
    -/dev/sda2 8%
    -/dev/sda2 8%
    -/dev/sda2 8%
    -/dev/sda2 8%
    -/dev/sda2 8%
    -/dev/sda2 8%
    -tmpfs 0%
    -
    -$ df |grep '^/dev/sd' |awk -F'[[:space:]]+|%' '{print $1,$5}'
    -$ df |grep '^/dev/sd' |awk -F' +|%' '{print $1,$5}'
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -/dev/sda2 8
    -

    示例:读取ifconfig输出结果中的ip地址。

    $ ifconfig eth0 | sed -n '2p' |awk '/netmask/{print $2}'
    +$ awk -F':' '{print $1,$3}' /etc/passwd |head -5
    +root 0
    +messagebus 499
    +systemd-network 497
    +systemd-timesync 496
    +nobody 65534
    +
    +$ awk -F':' '{print $1"\t"$3}' /etc/passwd |head -5
    +root    0
    +messagebus    499
    +systemd-network    497
    +systemd-timesync    496
    +nobody    65534
    +
    +
    +$ grep "^UUID" /etc/fstab |awk '{print $2,$3}'
    +/ btrfs
    +/var btrfs
    +/usr/local btrfs
    +/tmp btrfs
    +/srv btrfs
    +/root btrfs
    +/opt btrfs
    +/home btrfs
    +/boot/grub2/x86_64-efi btrfs
    +/boot/grub2/i386-pc btrfs
    +/.snapshots btrfs
    +swap swap
    +

    示例:读取分区利用率。

    分隔符中的定义[[:space:]]+|%的含义,一个或多个空格或者%作为分隔符。

    $ df |awk '{print $1,$5}'
    +Filesystem Use%
    +devtmpfs 0%
    +tmpfs 0%
    +tmpfs 2%
    +tmpfs 0%
    +/dev/sda2 8%
    +/dev/sda2 8%
    +/dev/sda2 8%
    +/dev/sda2 8%
    +/dev/sda2 8%
    +/dev/sda2 8%
    +/dev/sda2 8%
    +/dev/sda2 8%
    +/dev/sda2 8%
    +/dev/sda2 8%
    +/dev/sda2 8%
    +tmpfs 0%
    +
    +$ df |grep '^/dev/sd' |awk -F'[[:space:]]+|%' '{print $1,$5}'
    +$ df |grep '^/dev/sd' |awk -F' +|%' '{print $1,$5}'
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +/dev/sda2 8
    +

    示例:读取ifconfig输出结果中的ip地址。

    $ ifconfig eth0 | sed -n '2p' |awk '/netmask/{print $2}'
     192.168.10.210
     
    -$ ifconfig eth0 | sed -n '2p' |awk '{print $2}'
    +$ ifconfig eth0 | sed -n '2p' |awk '{print $2}'
     192.168.10.210
    -

    5.10.5.模式Pattern

    根据pattern条件,过滤匹配的行,再做处理。

    • 如果未指定,即空模式,则匹配每一行。

    • /regular expression/,仅处理能够模式匹配到的行(即结果为真),需要用/进行括起来。

    • 结果为真,即非0值、非空字符串

    • 结果为假,即0值、空字符串

    示例:空模式

    awk -F":" '{print $1, $3}' /etc/passwd |head -n5
    -root 0
    -messagebus 499
    -systemd-network 497
    -systemd-timesync 496
    -nobody 65534
    -

    示例:非空模式

    $ seq 5 | awk '0'
    -$ seq 5 | awk '1'
    +

    5.10.5.模式Pattern

    根据pattern条件,过滤匹配的行,再做处理。

    • 如果未指定,即空模式,则匹配每一行。

    • /regular expression/,仅处理能够模式匹配到的行(即结果为真),需要用/进行括起来。

    • 结果为真,即非0值、非空字符串

    • 结果为假,即0值、空字符串

    示例:空模式

    awk -F":" '{print $1, $3}' /etc/passwd |head -n5
    +root 0
    +messagebus 499
    +systemd-network 497
    +systemd-timesync 496
    +nobody 65534
    +

    示例:非空模式

    $ seq 5 | awk '0'
    +$ seq 5 | awk '1'
     1
     2
     3
     4
     5
    -$ seq 5 | awk '2'
    +$ seq 5 | awk '2'
     1
     2
     3
     4
     5
    -$ seq 5 | awk '"true"'
    +$ seq 5 | awk '"true"'
     1
     2
     3
     4
     5
    -$ seq 5 | awk '"false"'
    +$ seq 5 | awk '"false"'
     1
     2
     3
     4
     5
    -$ seq 5 | awk 'true'
    -$ seq 5 | awk 'false'
    -$ seq 5 | awk ''
    -$ seq 5 | awk '""'
    -$ seq 5 | awk '"0"'
    +$ seq 5 | awk 'true'
    +$ seq 5 | awk 'false'
    +$ seq 5 | awk ''
    +$ seq 5 | awk '""'
    +$ seq 5 | awk '"0"'
     1
     2
     3
     4
     5
    -

    体会下面变量的值和正确使用变量(字符串还是变量?)

    $ seq 5 | awk '"test"'
    +

    体会下面变量的值和正确使用变量(字符串还是变量?)

    $ seq 5 | awk '"test"'
     1
     2
     3
     4
     5
    -$ seq 5 | awk 'test'
    -$ seq 5 | awk -v test=0 '"test"'
    -$ seq 5 | awk -v test=0 'test'
    -$ seq 5 | awk -v test="0" 'test'
    -$ seq 5 | awk -v test="0" '"test"'
    +$ seq 5 | awk 'test'
    +$ seq 5 | awk -v test=0 '"test"'
    +$ seq 5 | awk -v test=0 'test'
    +$ seq 5 | awk -v test="0" 'test'
    +$ seq 5 | awk -v test="0" '"test"'
     1
     2
     3
     4
     5
    -$ seq 5 | awk -v test=1 'test'
    +$ seq 5 | awk -v test=1 'test'
     1
     2
     3
     4
     5
    -

    体会下面的与非判断。

    $ awk '1' /etc/passwd |head -n3
    +

    体会下面的与非判断。

    $ awk '1' /etc/passwd |head -n3
     root:x:0:0:root:/root:/bin/bash
    -messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false
    -systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin
    -$ awk '0' /etc/passwd |head -n3
    -$ awk '!1' /etc/passwd |head -n3
    -$ awk '!0' /etc/passwd |head -n3
    +messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false
    +systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin
    +$ awk '0' /etc/passwd |head -n3
    +$ awk '!1' /etc/passwd |head -n3
    +$ awk '!0' /etc/passwd |head -n3
     root:x:0:0:root:/root:/bin/bash
    -messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false
    -systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin
    +messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false
    +systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin
     
    # i没有赋值,为假,没有输出
    -$ seq 5 |awk 'i'
    +$ seq 5 |awk 'i'
     # i赋值为0,为假,没有输出
    -$ seq 5 |awk 'i=0'
    +$ seq 5 |awk 'i=0'
     # i赋值为1,为真,输出第一行结果,以此类推,每行都为真,输出全部seq的结果
    -$ seq 5 |awk 'i=1'
    +$ seq 5 |awk 'i=1'
     1
     2
     3
    @@ -979,80 +979,80 @@
     # 第二次初始i为真,!i则为假,赋值给i,所以i为假,不输出seq第2行结果
     # 第三次初始i为假,!i则为真,赋值给i,所以i为真,输出seq第3行结果
     # 以此类推,输出seq结果的奇数行
    -$ seq 5 |awk 'i=!i'
    +$ seq 5 |awk 'i=!i'
     1
     3
     5
     # 与上例的区别在于i初始值未真,第一次的i值为假,不输出seq第1行结果
     # 第二次i的初始值为假,通过i=!i变为真,所以输出seq的第2行结果
     # 以此类推,输出seq结果的偶数行
    -$ seq 5 |awk -v i=1 'i=!i'
    +$ seq 5 |awk -v i=1 'i=!i'
     2
     4
     # 输出计数行
    -$ seq 5 |awk -v i=0 'i=!i'
    +$ seq 5 |awk -v i=0 'i=!i'
     1
     3
     5
     # 只输出i的值,不输出seq的值
    -$ seq 5 |awk '{i=!i;print i}'
    +$ seq 5 |awk '{i=!i;print i}'
     1
     0
     1
     0
     1
    -$ seq 5 |awk '{i=!i}'
    -$ seq 5 |awk '(i=!i)'
    +$ seq 5 |awk '{i=!i}'
    +$ seq 5 |awk '(i=!i)'
     1
     3
     5
    -$ seq 5 |awk '!(i=!i)'
    +$ seq 5 |awk '!(i=!i)'
     2
     4
    -

    5.10.6.截取片段

    示例:

    $ head -n2 /etc/passwd |awk -F ':' '{print $0}'
    +

    5.10.6.截取片段

    示例:

    $ head -n2 /etc/passwd |awk -F ':' '{print $0}'
     root:x:0:0:root:/root:/bin/bash
    -messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false
    +messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false
     
    -$ head -n2 /etc/passwd |awk -F ':' '{print $2}'
    +$ head -n2 /etc/passwd |awk -F ':' '{print $2}'
     x
     x
     
    -$ head -n2 /etc/passwd |awk -F ':' '{print $1}'
    +$ head -n2 /etc/passwd |awk -F ':' '{print $1}'
     root
     messagebus
    -
    $ head -n2 /etc/passwd |awk -F ':' '{print $1"#"$2"#"$3"#"$4}'
    +
    $ head -n2 /etc/passwd |awk -F ':' '{print $1"#"$2"#"$3"#"$4}'
     root#x#0#0
     messagebus#x#499#499
    -

    5.10.7.操作符

    5.10.7.1.算数操作符

    x+yx-yx*yx/yx^yx%y

    -x:转换为负数

    +x:将字符串转换为数值

    列值之间进行算术运算。

    $ awk -F ':' '{$7=$3+$4;print $1,$3,$4,$7}' /etc/passwd |head -n5
    -root 0 0 0
    -messagebus 499 499 998
    -systemd-network 497 497 994
    -systemd-timesync 496 496 992
    -nobody 65534 65534 131068
    -

    计算某个列的总和。 END表示所有的行都已经执行。

    $ awk -F ':' '{(total=total+$3)}; END {print total}' /etc/passwd
    +

    5.10.7.操作符

    5.10.7.1.算数操作符

    x+yx-yx*yx/yx^yx%y

    -x:转换为负数

    +x:将字符串转换为数值

    列值之间进行算术运算。

    $ awk -F ':' '{$7=$3+$4;print $1,$3,$4,$7}' /etc/passwd |head -n5
    +root 0 0 0
    +messagebus 499 499 998
    +systemd-network 497 497 994
    +systemd-timesync 496 496 992
    +nobody 65534 65534 131068
    +

    计算某个列的总和。 END表示所有的行都已经执行。

    $ awk -F ':' '{(total=total+$3)}; END {print total}' /etc/passwd
     103011
    -

    5.10.7.2.字符串操作符

    没有操作符号,字符串连接。

    5.10.7.3.赋值操作符

    =+=-=*=/=%=^=++--

    示例:

    $ awk 'BEGIN{print i}'
    +

    5.10.7.2.字符串操作符

    没有操作符号,字符串连接。

    5.10.7.3.赋值操作符

    =+=-=*=/=%=^=++--

    示例:

    $ awk 'BEGIN{print i}'
     
    -$ awk 'BEGIN{print i++}' #从0开始
    +$ awk 'BEGIN{print i++}' #从0开始
     0
    -$ awk 'BEGIN{print ++i}'
    +$ awk 'BEGIN{print ++i}'
     1
     
    -$ awk 'BEGIN{print i++, i}'
    -0 1
    -$ awk 'BEGIN{i=0;print i++, i}'
    -0 1
    -
    -$ awk 'BEGIN{print ++i, i}'
    -1 1
    -$ awk 'BEGIN{i=0;print ++i, i}'
    -1 1
    -
    -$ awk 'BEGIN{i=0;print i, i++}'
    -0 0
    -$ awk 'BEGIN{i=0;print i, ++i}'
    -0 1
    -
    $ seq 10
    +$ awk 'BEGIN{print i++, i}'
    +0 1
    +$ awk 'BEGIN{i=0;print i++, i}'
    +0 1
    +
    +$ awk 'BEGIN{print ++i, i}'
    +1 1
    +$ awk 'BEGIN{i=0;print ++i, i}'
    +1 1
    +
    +$ awk 'BEGIN{i=0;print i, i++}'
    +0 0
    +$ awk 'BEGIN{i=0;print i, ++i}'
    +0 1
    +
    $ seq 10
     1
     2
     3
    @@ -1064,7 +1064,7 @@
     9
     10
     # n从0开始计数,输出的是n值,不是seq的输出结果
    -$ seq 10 |awk '{print n++}'
    +$ seq 10 |awk '{print n++}'
     0
     1
     2
    @@ -1078,7 +1078,7 @@
     # seq=1时,初始n未赋值,为假,不输出seq结果,n++为真
     # seq=2时,n为真,输出seq结果,n++为真
     # 后续n++都为真,所以seq的结果出了第一行由于n为假没有输出,其他行都输出
    -$ seq 10 |awk 'n++'
    +$ seq 10 |awk 'n++'
     2
     3
     4
    @@ -1089,7 +1089,7 @@
     9
     10
     # 参考上例,n初始未赋值,但执行++n后为真,所以输出第一行,后续行都输出因为n一直为真
    -$ seq 10 |awk '++n'
    +$ seq 10 |awk '++n'
     1
     2
     3
    @@ -1101,68 +1101,68 @@
     9
     10
     
    # n=0时++n=1,!++n=0,输出第0行
    -$ awk -v n=0 '!++n' /etc/passwd
    +$ awk -v n=0 '!++n' /etc/passwd
     
     # n=0时n++=1,!n++=1,输出第1行
    -$ awk -v n=0 '!n++' /etc/passwd
    +$ awk -v n=0 '!n++' /etc/passwd
     root:x:0:0:root:/root:/bin/bash
     
    -$ awk -v n=0 '!n++{print n}' /etc/passwd
    +$ awk -v n=0 '!n++{print n}' /etc/passwd
     1
     # 无结果输出
    -$ awk -v n=0 '!++n{print n}' /etc/passwd
    -$ awk -v n=1 '!n++{print n}' /etc/passwd
    +$ awk -v n=0 '!++n{print n}' /etc/passwd
    +$ awk -v n=1 '!n++{print n}' /etc/passwd
     
    -$ awk -v n=0 '!n++' /etc/passwd
    +$ awk -v n=0 '!n++' /etc/passwd
     root:x:0:0:root:/root:/bin/bash
     # 无结果输出
    -$ awk -v n=1 '!n++' /etc/passwd
    -$ awk -v n=2 '!n++' /etc/passwd
    -

    5.10.7.4.比较操作符

    使用 == 代表等于,即精确匹配。类似还有 >>=<<=!=符号。

    :为分隔符,匹配第三列的值为1000的行。

    $ awk -F ':' '$3=="100"' /etc/passwd
    +$ awk -v n=1 '!n++' /etc/passwd
    +$ awk -v n=2 '!n++' /etc/passwd
    +

    5.10.7.4.比较操作符

    使用 == 代表等于,即精确匹配。类似还有 >>=<<=!=符号。

    :为分隔符,匹配第三列的值为1000的行。

    $ awk -F ':' '$3=="100"' /etc/passwd
     vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash
    -

    在和数字比较时,若把要比较的数字用双引号引起来,awk会按字符处理,不加双引号,则会按数字处理。

    $ awk -F ':' '$3<="100"' /etc/passwd
    +

    在和数字比较时,若把要比较的数字用双引号引起来,awk会按字符处理,不加双引号,则会按数字处理。

    $ awk -F ':' '$3<="100"' /etc/passwd
     root:x:0:0:root:/root:/bin/bash
     bin:x:1:1:bin:/bin:/usr/sbin/nologin
     
    -$ awk -F ':' '$3<=100' /etc/passwd
    +$ awk -F ':' '$3<=100' /etc/passwd
     root:x:0:0:root:/root:/bin/bash
    -postfix:x:51:51:Postfix Daemon:/var/spool/postfix:/usr/sbin/nologin
    -man:x:13:62:Manual pages viewer:/var/lib/empty:/usr/sbin/nologin
    +postfix:x:51:51:Postfix Daemon:/var/spool/postfix:/usr/sbin/nologin
    +man:x:13:62:Manual pages viewer:/var/lib/empty:/usr/sbin/nologin
     daemon:x:2:2:Daemon:/sbin:/usr/sbin/nologin
    -at:x:25:25:Batch jobs daemon:/var/spool/atjobs:/usr/sbin/nologin
    +at:x:25:25:Batch jobs daemon:/var/spool/atjobs:/usr/sbin/nologin
     bin:x:1:1:bin:/bin:/usr/sbin/nologin
    -
    awk -F ':' '{if ($1=="root") {print $0}}' /etc/passwd
    -
    awk -F ':' '$7!="/bin/false"' /etc/passwd
    -awk -F ':' '$3<$2' /etc/passwd
    -

    5.10.7.5.逻辑操作符

    && 表示“并且”

    ||表示“或者”

    !表示“非”(取反)

    awk -F ':' '$3>10 && $3<100' /etc/passwd
    -awk -F ':' '$3>10 || $3<100' /etc/passwd
    -awk -F ':' '($3==0)' /etc/passwd
    -awk -F ':' '!($3==0)' /etc/passwd
    -

    注意下面对字符和数值进行取反操作的结果。

    $ awk 'BEGIN{print i}'
    -
    -$ awk 'BEGIN{print !i}'
    +
    awk -F ':' '{if ($1=="root") {print $0}}' /etc/passwd
    +
    awk -F ':' '$7!="/bin/false"' /etc/passwd
    +awk -F ':' '$3<$2' /etc/passwd
    +

    5.10.7.5.逻辑操作符

    && 表示“并且”

    ||表示“或者”

    !表示“非”(取反)

    awk -F ':' '$3>10 && $3<100' /etc/passwd
    +awk -F ':' '$3>10 || $3<100' /etc/passwd
    +awk -F ':' '($3==0)' /etc/passwd
    +awk -F ':' '!($3==0)' /etc/passwd
    +

    注意下面对字符和数值进行取反操作的结果。

    $ awk 'BEGIN{print i}'
    +
    +$ awk 'BEGIN{print !i}'
     1
    -$ awk -v i=10 'BEGIN{print i}'
    +$ awk -v i=10 'BEGIN{print i}'
     10
    -$ awk -v i=10 'BEGIN{print !i}'
    +$ awk -v i=10 'BEGIN{print !i}'
     0
    -$ awk -v i=-5 'BEGIN{print i}'
    +$ awk -v i=-5 'BEGIN{print i}'
     -5
    -$ awk -v i=-5 'BEGIN{print !i}'
    +$ awk -v i=-5 'BEGIN{print !i}'
     0
    -$ awk -v i="abc" 'BEGIN{print i}'
    +$ awk -v i="abc" 'BEGIN{print i}'
     abc
    -$ awk -v i="abc" 'BEGIN{print !i}'
    +$ awk -v i="abc" 'BEGIN{print !i}'
     0
    -$ awk -v i=abc 'BEGIN{print i}'
    +$ awk -v i=abc 'BEGIN{print i}'
     abc
    -$ awk -v i=abc 'BEGIN{print !i}'
    +$ awk -v i=abc 'BEGIN{print !i}'
     0
    -$ awk -v i="" 'BEGIN{print i}'
    +$ awk -v i="" 'BEGIN{print i}'
     
    -$ awk -v i="" 'BEGIN{print !i}'
    +$ awk -v i="" 'BEGIN{print !i}'
     1
    -

    在分隔符定义中使用正则表达式。

    $ df |awk -F" +|%" '{print $5}'
    +

    在分隔符定义中使用正则表达式。

    $ df |awk -F" +|%" '{print $5}'
     Use
     0
     0
    @@ -1180,7 +1180,7 @@
     8
     8
     0
    -$ df |awk -F"[[:space:]]+|%" '{print $5}'
    +$ df |awk -F"[[:space:]]+|%" '{print $5}'
     Use
     0
     0
    @@ -1198,34 +1198,34 @@
     8
     8
     0
    -

    5.10.7.6.三目条件表达式

    格式:selector?if-true-expression:if-false-expression

    $ awk -F':' '{$3>1000?usertype="Common User":usertype="Superuser";printf"%-20s:%12s\n", $1, usertype}' /etc/passwd |head -n5
    -root                :   Superuser
    -messagebus          :   Superuser
    -systemd-network     :   Superuser
    -systemd-timesync    :   Superuser
    -nobody              : Common User
    -

    5.10.7.8.模式匹配符

    ~:左右是否匹配

    !~:左右是否不匹配

    示例:

    匹配文件中指定字符串root的所有行,类似grep命令,但没有高亮显示。

    $ awk '/root/' /etc/passwd
    +

    5.10.7.6.三目条件表达式

    格式:selector?if-true-expression:if-false-expression

    $ awk -F':' '{$3>1000?usertype="Common User":usertype="Superuser";printf"%-20s:%12s\n", $1, usertype}' /etc/passwd |head -n5
    +root                :   Superuser
    +messagebus          :   Superuser
    +systemd-network     :   Superuser
    +systemd-timesync    :   Superuser
    +nobody              : Common User
    +

    5.10.7.8.模式匹配符

    ~:左右是否匹配

    !~:左右是否不匹配

    示例:

    匹配文件中指定字符串root的所有行,类似grep命令,但没有高亮显示。

    $ awk '/root/' /etc/passwd
     root:x:0:0:root:/root:/bin/bash
    -

    :为分隔符,匹配第一列$1中包含指定字符串oo的行。~是代表左右匹配。

    $ awk -F ':' '$1 ~/oo/' /etc/passwd
    +

    :为分隔符,匹配第一列$1中包含指定字符串oo的行。~是代表左右匹配。

    $ awk -F ':' '$1 ~/oo/' /etc/passwd
     root:x:0:0:root:/root:/bin/bash
    -gentoo:x:1014:100:Gentoo Distribution:/home/gentoo:/bin/csh
    -

    :为分隔符,匹配所有列$0(整行)中包含root行的第一列$1

    $ awk -F: '$0 ~/root/{print $1}' /etc/passwd
    -$ awk -F: '$0 ~"root"{print $1}' /etc/passwd
    +gentoo:x:1014:100:Gentoo Distribution:/home/gentoo:/bin/csh
    +

    :为分隔符,匹配所有列$0(整行)中包含root行的第一列$1

    $ awk -F: '$0 ~/root/{print $1}' /etc/passwd
    +$ awk -F: '$0 ~"root"{print $1}' /etc/passwd
     root
     daemon
     _cvmsroot
    -

    :为分隔符,匹配所有列$0(整行)中以root开头行的第一列$1

    $ awk -F: '$0 ~"^root"{print $1}' /etc/passwd
    -$ awk -F: '$0 ~/^root/{print $1}' /etc/passwd
    +

    :为分隔符,匹配所有列$0(整行)中以root开头行的第一列$1

    $ awk -F: '$0 ~"^root"{print $1}' /etc/passwd
    +$ awk -F: '$0 ~/^root/{print $1}' /etc/passwd
     root
    -

    :为分隔符,匹配所有列$0(整行)中不以root开头行的第一列$1

    awk -F: '$0 !~/^root/{print $1}' /etc/passwd
    -awk -F: '$0 ~/^[^root]/{print $1}' /etc/passwd
    -

    多条件匹配,以:为分隔符,匹配所有含有rootftp的行,并打印第1、3列。

    awk -F ':' '/root/ {print $1,$3} /bin/ {print $1,$3}' /etc/passwd
    -

    多条件匹配,以:为分隔符,匹配第一列中含有rootbin的行,并打印第1、3列。

    $ awk -F ':' '$1 ~/root/ {print $1,$3} $1 ~/bin/ {print $1,$3}' /etc/passwd
    -root 0
    -bin 1
    -

    :为分隔符,匹配第三列$3中值为0的行。

    $ awk -F":" '$3==0' /etc/passwd
    +

    :为分隔符,匹配所有列$0(整行)中不以root开头行的第一列$1

    awk -F: '$0 !~/^root/{print $1}' /etc/passwd
    +awk -F: '$0 ~/^[^root]/{print $1}' /etc/passwd
    +

    多条件匹配,以:为分隔符,匹配所有含有rootftp的行,并打印第1、3列。

    awk -F ':' '/root/ {print $1,$3} /bin/ {print $1,$3}' /etc/passwd
    +

    多条件匹配,以:为分隔符,匹配第一列中含有rootbin的行,并打印第1、3列。

    $ awk -F ':' '$1 ~/root/ {print $1,$3} $1 ~/bin/ {print $1,$3}' /etc/passwd
    +root 0
    +bin 1
    +

    :为分隔符,匹配第三列$3中值为0的行。

    $ awk -F":" '$3==0' /etc/passwd
     root:x:0:0:root:/root:/bin/bash
    -

    以至少一个空格或%为分隔符,匹配以/dev/sd开头的行,打印第五列。

    $ df |awk -F"[[:space:]]+|%" '$0 ~ /^\/dev\/sd/{print $5}'
    +

    以至少一个空格或%为分隔符,匹配以/dev/sd开头的行,打印第五列。

    $ df |awk -F"[[:space:]]+|%" '$0 ~ /^\/dev\/sd/{print $5}'
     8
     8
     8
    @@ -1237,142 +1237,142 @@
     8
     8
     8
    -

    读取ifconfig eth0输出结果的第二行NR==2的第二列$2

    $ ifconfig eth0 |awk 'NR==2{print $2}'
    +

    读取ifconfig eth0输出结果的第二行NR==2的第二列$2

    $ ifconfig eth0 |awk 'NR==2{print $2}'
     192.168.10.210
    -

    5.10.8.变量

    5.10.8.1.内置变量

    awk常用的变量有FSOFSNFNR

    FS用来定义输入字段分隔符,默认为空白字符。与-F 选项功能类似,同时使用会报错。

    OFS用来定义输出字段分隔符,默认为空白字符。

    RS指定输入时的换行符。

    ORS指定符号在输出时替换换行符。

    NF 表示用分隔符分隔后一共有多少列。

    NR 表示行号。

    FNR表示个文件分别计数各自记录的编号。

    FILENAME表示当前文件名。

    ARGC表示命令行参数的个数。

    ARVC以数组形式保存命令行所给定的各参数,每个参数:ARGV[0],......。

    FS的用法:

    $ awk -v FS=':' '{print $1, FS, $3}' /etc/passwd | head -n5
    -root : 0
    -messagebus : 499
    -systemd-network : 497
    +

    5.10.8.变量

    5.10.8.1.内置变量

    awk常用的变量有FSOFSNFNR

    FS用来定义输入字段分隔符,默认为空白字符。与-F 选项功能类似,同时使用会报错。

    OFS用来定义输出字段分隔符,默认为空白字符。

    RS指定输入时的换行符。

    ORS指定符号在输出时替换换行符。

    NF 表示用分隔符分隔后一共有多少列。

    NR 表示行号。

    FNR表示个文件分别计数各自记录的编号。

    FILENAME表示当前文件名。

    ARGC表示命令行参数的个数。

    ARVC以数组形式保存命令行所给定的各参数,每个参数:ARGV[0],......。

    FS的用法:

    $ awk -v FS=':' '{print $1, FS, $3}' /etc/passwd | head -n5
    +root : 0
    +messagebus : 499
    +systemd-network : 497
     
    -$ awk -F: '{print $1FS$3}' /etc/passwd | head -n3
    +$ awk -F: '{print $1FS$3}' /etc/passwd | head -n3
     root:0
     messagebus:499
     systemd-network:497
    -
    $ S=:;awk -v FS=$S '{print $1FS$3}' /etc/passwd | head -n3
    +
    $ S=:;awk -v FS=$S '{print $1FS$3}' /etc/passwd | head -n3
     root:0
     messagebus:499
     systemd-network:497
     systemd-timesync:496
     nobody:65534
     
    -$ S=:;awk -F$S '{print $1FS$3}' /etc/passwd | head -n3
    +$ S=:;awk -F$S '{print $1FS$3}' /etc/passwd | head -n3
     root:0
     messagebus:499
     systemd-network:497
    -

    FS-F 选项功同时使用会冲突,-F的优先级更高。

    $ awk -v FS=':' -F';' '{print $1FS$3}' /etc/passwd | head -n3
    +

    FS-F 选项功同时使用会冲突,-F的优先级更高。

    $ awk -v FS=':' -F';' '{print $1FS$3}' /etc/passwd | head -n3
     root:x:0:0:root:/root:/bin/bash;
    -messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false;
    -systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin;
    +messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false;
    +systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin;
     
    -$ awk -v FS=';' -F':' '{print $1FS$3}' /etc/passwd | head -n3
    +$ awk -v FS=';' -F':' '{print $1FS$3}' /etc/passwd | head -n3
     root:0
     messagebus:499
     systemd-network:497
    -

    OFS的用法:

    :为分隔符,打印第1、3、4列第内容,并以#为分隔符。

    $ awk -F ':' '{OFS="#"} {print $1,$3,$4}' /etc/passwd | head -n5
    +

    OFS的用法:

    :为分隔符,打印第1、3、4列第内容,并以#为分隔符。

    $ awk -F ':' '{OFS="#"} {print $1,$3,$4}' /etc/passwd | head -n5
     root#0#0
     messagebus#499#499
     systemd-network#497#497
     systemd-timesync#496#496
     nobody#65534#65534
     
    -$ awk -v FS=':' -v OFS='#' '{print $1,$3,$4}' /etc/passwd | head -n5
    +$ awk -v FS=':' -v OFS='#' '{print $1,$3,$4}' /etc/passwd | head -n5
     root#0#0
     messagebus#499#499
     systemd-network#497#497
     systemd-timesync#496#496
     nobody#65534#65534
    -

    :为分隔符,当第三列大于等于5000时,打印第1、2、3、4列第内容,并以#为分隔符。

    $ awk -F ':' '{OFS="#"} {if ($3>=5000) {print $1,$2,$3,$4}}' /etc/passwd
    +

    :为分隔符,当第三列大于等于5000时,打印第1、2、3、4列第内容,并以#为分隔符。

    $ awk -F ':' '{OFS="#"} {if ($3>=5000) {print $1,$2,$3,$4}}' /etc/passwd
     nobody#x#65534#65534
     

    RS的用法:

    # 以空格为换行标志
    -$ awk -v RS=' ' '{print $0}' /etc/passwd |head -n3
    +$ awk -v RS=' ' '{print $0}' /etc/passwd |head -n3
     root:x:0:0:root:/root:/bin/bash
     messagebus:x:499:499:User
     for
     
     # 以冒号为换行标志
    -$ awk -v RS=':' '{print $0}' /etc/passwd |head -n3
    +$ awk -v RS=':' '{print $0}' /etc/passwd |head -n3
     root
     x
     0
     

    ORS的用法:

    # 以冒号为换行标志,替换成###
    -$ awk -v RS=':' -v ORS='###' '{print $0}' /etc/passwd |head -n3
    +$ awk -v RS=':' -v ORS='###' '{print $0}' /etc/passwd |head -n3
     root###x###0###0###root###/root###/bin/bash
    -messagebus###x###499###499###User for D-Bus###/run/dbus###/usr/bin/false
    -systemd-network###x###497###497###systemd Network Management###/###/usr/sbin/nologin
    -

    NF 的用法:

    其中 NF 是多少列,$NF 是最后一列的值。

    下例中以:为分隔符一共分为7列,最后一列的值是$NF

    $ awk -F ':' '{print $NF}' /etc/passwd | head -n2
    +messagebus###x###499###499###User for D-Bus###/run/dbus###/usr/bin/false
    +systemd-network###x###497###497###systemd Network Management###/###/usr/sbin/nologin
    +

    NF 的用法:

    其中 NF 是多少列,$NF 是最后一列的值。

    下例中以:为分隔符一共分为7列,最后一列的值是$NF

    $ awk -F ':' '{print $NF}' /etc/passwd | head -n2
     /bin/bash
     /usr/bin/false
     
    -$ awk -F ':' '{print NF}' /etc/passwd | head -n2
    +$ awk -F ':' '{print NF}' /etc/passwd | head -n2
     7
     7
    -
    $ ss -nt |grep "^ESTAB" |awk -F"[[:space:]]+|:" '{print $(NF-2)}'
    +
    $ ss -nt |grep "^ESTAB" |awk -F"[[:space:]]+|:" '{print $(NF-2)}'
     192.168.10.103
     
    -$ ss -nt |awk -F"[[:space:]]+|:" '/^ESTAB/{print $(NF-2)}'
    +$ ss -nt |awk -F"[[:space:]]+|:" '/^ESTAB/{print $(NF-2)}'
     192.168.10.103
    -

    NR 的用法:

    通过NR输出行号。以:为分隔符,打印前三行的行号。

    $ awk -F ':' '{print NR}' /etc/passwd |head -n3
    +

    NR 的用法:

    通过NR输出行号。以:为分隔符,打印前三行的行号。

    $ awk -F ':' '{print NR}' /etc/passwd |head -n3
     1
     2
     3
    -

    取奇、偶数行。

    $ seq 10 |awk 'NR%2==0'
    +

    取奇、偶数行。

    $ seq 10 |awk 'NR%2==0'
     2
     4
     6
     8
     10
    -$ seq 10 |awk 'NR%2==1'
    +$ seq 10 |awk 'NR%2==1'
     1
     3
     5
     7
     9
    -

    通过NR设定行号条件。以:为分隔符,打印第40行以后的行内容。

    $ awk 'NR>45' /etc/passwd
    +

    通过NR设定行号条件。以:为分隔符,打印第40行以后的行内容。

    $ awk 'NR>45' /etc/passwd
     admin3:x:1020:100::/home/admin3:/bin/bash
     smith:x:2002:0:,,,:/home/admin2:/bin/bash
     pm1:x:2003:1535::/home/pm1:/bin/bash
     tm1:x:2004:1535::/home/tm1:/bin/bash
     tm2:x:2005:1536::/home/tm2:/bin/bash
     
    -$ awk -F ':' 'NR>45' /etc/passwd
    +$ awk -F ':' 'NR>45' /etc/passwd
     admin3:x:1020:100::/home/admin3:/bin/bash
     smith:x:2002:0:,,,:/home/admin2:/bin/bash
     pm1:x:2003:1535::/home/pm1:/bin/bash
     tm1:x:2004:1535::/home/tm1:/bin/bash
     tm2:x:2005:1536::/home/tm2:/bin/bash
     
    -$ awk -F ':' 'NR>45 {print NR,$1,$3}' /etc/passwd
    -46 admin3 1020
    -47 smith 2002
    -48 pm1 2003
    -49 tm1 2004
    -50 tm2 2005
    +$ awk -F ':' 'NR>45 {print NR,$1,$3}' /etc/passwd
    +46 admin3 1020
    +47 smith 2002
    +48 pm1 2003
    +49 tm1 2004
    +50 tm2 2005
     
    -$ awk -F ':' 'BEGIN{print NR}' /etc/passwd
    +$ awk -F ':' 'BEGIN{print NR}' /etc/passwd
     0
     
    -$ awk -F ':' 'END{print NR}' /etc/passwd
    +$ awk -F ':' 'END{print NR}' /etc/passwd
     50
    -
    $ ifconfig eth0 |awk '/netmask/{print $0}'
    -        inet 192.168.10.210  netmask 255.255.255.0  broadcast 192.168.10.255
    +
    $ ifconfig eth0 |awk '/netmask/{print $0}'
    +        inet 192.168.10.210  netmask 255.255.255.0  broadcast 192.168.10.255
     
    -$ ifconfig eth0 |awk '/netmask/{print $1}'
    +$ ifconfig eth0 |awk '/netmask/{print $1}'
     inet
     
    -$ ifconfig eth0 |awk '/netmask/{print $2}'
    +$ ifconfig eth0 |awk '/netmask/{print $2}'
     192.168.10.210
     
    -$ ifconfig eth0 |awk 'NR==2{print $0}'
    -        inet 192.168.10.210  netmask 255.255.255.0  broadcast 192.168.10.255
    +$ ifconfig eth0 |awk 'NR==2{print $0}'
    +        inet 192.168.10.210  netmask 255.255.255.0  broadcast 192.168.10.255
     
    -$ ifconfig eth0 |awk 'NR==2{print $1}'
    +$ ifconfig eth0 |awk 'NR==2{print $1}'
     inet
     
    -$ ifconfig eth0 |awk 'NR==2{print $2}'
    +$ ifconfig eth0 |awk 'NR==2{print $2}'
     192.168.10.210
    -

    通过NR 与列匹配一起使用。

    $ awk -F ':' 'NR<5 && $1 ~/roo/' /etc/passwd
    +

    通过NR 与列匹配一起使用。

    $ awk -F ':' 'NR<5 && $1 ~/roo/' /etc/passwd
     root:x:0:0:root:/root:/bin/bash
    -

    FNR的用法:

    $ awk '{print FNR}' /etc/fstab /etc/networks
    +

    FNR的用法:

    $ awk '{print FNR}' /etc/fstab /etc/networks
     1
     2
     3
    @@ -1395,54 +1395,54 @@
     8
     9
     10
    -
    $ awk '{print NR, $0}' /etc/fstab /etc/networks
    -1 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /                       btrfs  defaults                      0  0
    -2 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /var                    btrfs  subvol=/@/var                 0  0
    -3 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /usr/local              btrfs  subvol=/@/usr/local           0  0
    -4 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /tmp                    btrfs  subvol=/@/tmp                 0  0
    -5 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /srv                    btrfs  subvol=/@/srv                 0  0
    -6 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /root                   btrfs  subvol=/@/root                0  0
    -7 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /opt                    btrfs  subvol=/@/opt                 0  0
    -8 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /home                   btrfs  subvol=/@/home                0  0
    -9 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /boot/grub2/x86_64-efi  btrfs  subvol=/@/boot/grub2/x86_64-efi  0  0
    -10 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /boot/grub2/i386-pc     btrfs  subvol=/@/boot/grub2/i386-pc  0  0
    -11 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /.snapshots             btrfs  subvol=/@/.snapshots          0  0
    -12 UUID=47c36ad7-f49f-4ecd-9b72-4801c5bb3a04  swap                    swap   defaults                      0  0
    -13 #
    -14 # networks    This file describes a number of netname-to-address
    -15 #        mappings for the TCP/IP subsystem.  It is mostly
    -16 #        used at boot time, when no name servers are running.
    -17 #
    +
    $ awk '{print NR, $0}' /etc/fstab /etc/networks
    +1 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /                       btrfs  defaults                      0  0
    +2 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /var                    btrfs  subvol=/@/var                 0  0
    +3 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /usr/local              btrfs  subvol=/@/usr/local           0  0
    +4 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /tmp                    btrfs  subvol=/@/tmp                 0  0
    +5 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /srv                    btrfs  subvol=/@/srv                 0  0
    +6 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /root                   btrfs  subvol=/@/root                0  0
    +7 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /opt                    btrfs  subvol=/@/opt                 0  0
    +8 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /home                   btrfs  subvol=/@/home                0  0
    +9 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /boot/grub2/x86_64-efi  btrfs  subvol=/@/boot/grub2/x86_64-efi  0  0
    +10 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /boot/grub2/i386-pc     btrfs  subvol=/@/boot/grub2/i386-pc  0  0
    +11 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /.snapshots             btrfs  subvol=/@/.snapshots          0  0
    +12 UUID=47c36ad7-f49f-4ecd-9b72-4801c5bb3a04  swap                    swap   defaults                      0  0
    +13 #
    +14 # networks    This file describes a number of netname-to-address
    +15 #        mappings for the TCP/IP subsystem.  It is mostly
    +16 #        used at boot time, when no name servers are running.
    +17 #
     18
    -19 loopback    127.0.0.0
    -20 link-local    169.254.0.0
    +19 loopback    127.0.0.0
    +20 link-local    169.254.0.0
     21
    -22 # End.
    -
    -$ awk '{print FNR, $0}' /etc/fstab /etc/networks
    -1 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /                       btrfs  defaults                      0  0
    -2 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /var                    btrfs  subvol=/@/var                 0  0
    -3 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /usr/local              btrfs  subvol=/@/usr/local           0  0
    -4 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /tmp                    btrfs  subvol=/@/tmp                 0  0
    -5 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /srv                    btrfs  subvol=/@/srv                 0  0
    -6 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /root                   btrfs  subvol=/@/root                0  0
    -7 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /opt                    btrfs  subvol=/@/opt                 0  0
    -8 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /home                   btrfs  subvol=/@/home                0  0
    -9 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /boot/grub2/x86_64-efi  btrfs  subvol=/@/boot/grub2/x86_64-efi  0  0
    -10 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /boot/grub2/i386-pc     btrfs  subvol=/@/boot/grub2/i386-pc  0  0
    -11 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /.snapshots             btrfs  subvol=/@/.snapshots          0  0
    -12 UUID=47c36ad7-f49f-4ecd-9b72-4801c5bb3a04  swap                    swap   defaults                      0  0
    -1 #
    -2 # networks    This file describes a number of netname-to-address
    -3 #        mappings for the TCP/IP subsystem.  It is mostly
    -4 #        used at boot time, when no name servers are running.
    -5 #
    +22 # End.
    +
    +$ awk '{print FNR, $0}' /etc/fstab /etc/networks
    +1 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /                       btrfs  defaults                      0  0
    +2 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /var                    btrfs  subvol=/@/var                 0  0
    +3 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /usr/local              btrfs  subvol=/@/usr/local           0  0
    +4 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /tmp                    btrfs  subvol=/@/tmp                 0  0
    +5 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /srv                    btrfs  subvol=/@/srv                 0  0
    +6 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /root                   btrfs  subvol=/@/root                0  0
    +7 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /opt                    btrfs  subvol=/@/opt                 0  0
    +8 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /home                   btrfs  subvol=/@/home                0  0
    +9 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /boot/grub2/x86_64-efi  btrfs  subvol=/@/boot/grub2/x86_64-efi  0  0
    +10 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /boot/grub2/i386-pc     btrfs  subvol=/@/boot/grub2/i386-pc  0  0
    +11 UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /.snapshots             btrfs  subvol=/@/.snapshots          0  0
    +12 UUID=47c36ad7-f49f-4ecd-9b72-4801c5bb3a04  swap                    swap   defaults                      0  0
    +1 #
    +2 # networks    This file describes a number of netname-to-address
    +3 #        mappings for the TCP/IP subsystem.  It is mostly
    +4 #        used at boot time, when no name servers are running.
    +5 #
     6
    -7 loopback    127.0.0.0
    -8 link-local    169.254.0.0
    +7 loopback    127.0.0.0
    +8 link-local    169.254.0.0
     9
    -10 # End.
    -

    FILENAME的用法:

    $ awk '{print FILENAME}' /etc/fstab
    +10 # End.
    +

    FILENAME的用法:

    $ awk '{print FILENAME}' /etc/fstab
     /etc/fstab
     /etc/fstab
     /etc/fstab
    @@ -1456,30 +1456,30 @@
     /etc/fstab
     /etc/fstab
     
    -$ awk '{print FNR, FILENAME, $0}' /etc/fstab /etc/networks
    -1 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /                       btrfs  defaults                      0  0
    -2 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /var                    btrfs  subvol=/@/var                 0  0
    -3 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /usr/local              btrfs  subvol=/@/usr/local           0  0
    -4 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /tmp                    btrfs  subvol=/@/tmp                 0  0
    -5 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /srv                    btrfs  subvol=/@/srv                 0  0
    -6 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /root                   btrfs  subvol=/@/root                0  0
    -7 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /opt                    btrfs  subvol=/@/opt                 0  0
    -8 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /home                   btrfs  subvol=/@/home                0  0
    -9 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /boot/grub2/x86_64-efi  btrfs  subvol=/@/boot/grub2/x86_64-efi  0  0
    -10 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /boot/grub2/i386-pc     btrfs  subvol=/@/boot/grub2/i386-pc  0  0
    -11 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /.snapshots             btrfs  subvol=/@/.snapshots          0  0
    -12 /etc/fstab UUID=47c36ad7-f49f-4ecd-9b72-4801c5bb3a04  swap                    swap   defaults                      0  0
    -1 /etc/networks #
    -2 /etc/networks # networks    This file describes a number of netname-to-address
    -3 /etc/networks #        mappings for the TCP/IP subsystem.  It is mostly
    -4 /etc/networks #        used at boot time, when no name servers are running.
    -5 /etc/networks #
    -6 /etc/networks
    -7 /etc/networks loopback    127.0.0.0
    -8 /etc/networks link-local    169.254.0.0
    -9 /etc/networks
    -10 /etc/networks # End.
    -

    ARGC的用法:

    每个变量的名字通过ARGV获取。

    $ awk '{print ARGC}' /etc/fstab /etc/issue
    +$ awk '{print FNR, FILENAME, $0}' /etc/fstab /etc/networks
    +1 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /                       btrfs  defaults                      0  0
    +2 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /var                    btrfs  subvol=/@/var                 0  0
    +3 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /usr/local              btrfs  subvol=/@/usr/local           0  0
    +4 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /tmp                    btrfs  subvol=/@/tmp                 0  0
    +5 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /srv                    btrfs  subvol=/@/srv                 0  0
    +6 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /root                   btrfs  subvol=/@/root                0  0
    +7 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /opt                    btrfs  subvol=/@/opt                 0  0
    +8 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /home                   btrfs  subvol=/@/home                0  0
    +9 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /boot/grub2/x86_64-efi  btrfs  subvol=/@/boot/grub2/x86_64-efi  0  0
    +10 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /boot/grub2/i386-pc     btrfs  subvol=/@/boot/grub2/i386-pc  0  0
    +11 /etc/fstab UUID=5ffa8dbd-473e-4308-804a-0033c3b5f7af  /.snapshots             btrfs  subvol=/@/.snapshots          0  0
    +12 /etc/fstab UUID=47c36ad7-f49f-4ecd-9b72-4801c5bb3a04  swap                    swap   defaults                      0  0
    +1 /etc/networks #
    +2 /etc/networks # networks    This file describes a number of netname-to-address
    +3 /etc/networks #        mappings for the TCP/IP subsystem.  It is mostly
    +4 /etc/networks #        used at boot time, when no name servers are running.
    +5 /etc/networks #
    +6 /etc/networks
    +7 /etc/networks loopback    127.0.0.0
    +8 /etc/networks link-local    169.254.0.0
    +9 /etc/networks
    +10 /etc/networks # End.
    +

    ARGC的用法:

    每个变量的名字通过ARGV获取。

    $ awk '{print ARGC}' /etc/fstab /etc/issue
     3
     3
     3
    @@ -1498,99 +1498,99 @@
     3
     3
     
    -$ awk 'BEGIN{print ARGC}' /etc/fstab /etc/issue
    +$ awk 'BEGIN{print ARGC}' /etc/fstab /etc/issue
     3
    -

    ARGV的用法:

    $ awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/issue
    +

    ARGV的用法:

    $ awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/issue
     awk
    -$ awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/issue
    +$ awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/issue
     /etc/fstab
    -$ awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/issue
    +$ awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/issue
     /etc/issue
    -$ awk 'BEGIN{print ARGV[3]}' /etc/fstab /etc/issue
    -

    5.10.8.2.自定义变量

    自定义变量是区分字符大小写的,使用下面的方式进行赋值。

    • -v var=value

    • 在program中直接定义

    举例:

    $ awk -v t1=t2="hello awk" 'BEGIN{print t1, t2}'
    -t2=hello awk
    -$ awk -v t1=t2="hello awk" 'BEGIN{t1=t2="gawk"; print t1, t2}'
    -gawk gawk
    -$ awk 'BEGIN{t1=t2="hello awk"; print t1, t2}'
    -hello awk hello awk
    -
    $ awk -v t1="hello awk" '{print t1}' /etc/issue
    -hello awk
    -hello awk
    -hello awk
    -hello awk
    -hello awk
    -$ awk -v t1="hello awk" 'BEGIN{print t1}' /etc/issue
    -hello awk
    -$ awk -v t1="hello awk" 'BEGIN{print t1}'
    -hello awk
    -
    $ awk -F: '{sex="male"; print $1, sex, age; age=28}' /etc/passwd |head -n3
    -root male
    -messagebus male 28
    -systemd-network male 28
    -
    $ cat <<EOF > awkscript
    +$ awk 'BEGIN{print ARGV[3]}' /etc/fstab /etc/issue
    +

    5.10.8.2.自定义变量

    自定义变量是区分字符大小写的,使用下面的方式进行赋值。

    • -v var=value

    • 在program中直接定义

    举例:

    $ awk -v t1=t2="hello awk" 'BEGIN{print t1, t2}'
    +t2=hello awk
    +$ awk -v t1=t2="hello awk" 'BEGIN{t1=t2="gawk"; print t1, t2}'
    +gawk gawk
    +$ awk 'BEGIN{t1=t2="hello awk"; print t1, t2}'
    +hello awk hello awk
    +
    $ awk -v t1="hello awk" '{print t1}' /etc/issue
    +hello awk
    +hello awk
    +hello awk
    +hello awk
    +hello awk
    +$ awk -v t1="hello awk" 'BEGIN{print t1}' /etc/issue
    +hello awk
    +$ awk -v t1="hello awk" 'BEGIN{print t1}'
    +hello awk
    +
    $ awk -F: '{sex="male"; print $1, sex, age; age=28}' /etc/passwd |head -n3
    +root male
    +messagebus male 28
    +systemd-network male 28
    +
    $ cat <<EOF > awkscript
     {print script,$1,$2}
     EOF
     
    -$ awk -F: -f awkscript script="awk" /etc/passwd |head -n2
    -awk root x
    -awk messagebus x
    -

    动作printf

    动作printf可以实现格式化输出。

    格式:printf "FORMAT", item1, item2, ......

    说明:

    • 必须指定FORMAT

    • 不会自动换行,需要显式给出换行控制符\n

    • FORMAT中需要分别为后面每个item指定格式符。

    格式符:与item是一一对应的

    • %s:显示字符串

    • %d, %i:显示十进制整数

    • %f:显示为浮点数

    • %e, %E:显示科学计数法数值

    • %c:显示字符的ASCII码

    • %g, %G:以科学计数法或浮点形式显示数值

    • %u:无符号整数

    • %%:显示%自身

    修饰符:

    • #[.#]:第一个数字控制显示的宽度,第二个#表示小数点后精度,如%3.1f

    • -:左对齐(默认右对齐),如%-15s

    • +:显示数值的正负符号,如%+d

    示例:

    $ awk -F: '{printf "%s", $1}' /etc/passwd |head -n3
    +$ awk -F: -f awkscript script="awk" /etc/passwd |head -n2
    +awk root x
    +awk messagebus x
    +

    动作printf

    动作printf可以实现格式化输出。

    格式:printf "FORMAT", item1, item2, ......

    说明:

    • 必须指定FORMAT

    • 不会自动换行,需要显式给出换行控制符\n

    • FORMAT中需要分别为后面每个item指定格式符。

    格式符:与item是一一对应的

    • %s:显示字符串

    • %d, %i:显示十进制整数

    • %f:显示为浮点数

    • %e, %E:显示科学计数法数值

    • %c:显示字符的ASCII码

    • %g, %G:以科学计数法或浮点形式显示数值

    • %u:无符号整数

    • %%:显示%自身

    修饰符:

    • #[.#]:第一个数字控制显示的宽度,第二个#表示小数点后精度,如%3.1f

    • -:左对齐(默认右对齐),如%-15s

    • +:显示数值的正负符号,如%+d

    示例:

    $ awk -F: '{printf "%s", $1}' /etc/passwd |head -n3
     rootmessagebussystemd-networksystemd-timesyncnobodymailchronypostfixmanlpgamesftpdaemonrpcnscdpolkitdattftpftpsecurebinstatdsshdvagrantpesignsvntester1tester2tester3tester4tester5user0user1user2user3user4user5user6user7user8user9gentoonginxvarnishmysqlwebuseradmin3smithpm1tm1tm2
     
    -$ awk -F: '{printf "%s\n", $1}' /etc/passwd |head -n3
    +$ awk -F: '{printf "%s\n", $1}' /etc/passwd |head -n3
     root
     messagebus
     systemd-network
     
    -$ awk -F: '{printf "%20s\n", $1}' /etc/passwd |head -n3
    -                root
    -          messagebus
    -     systemd-network
    +$ awk -F: '{printf "%20s\n", $1}' /etc/passwd |head -n3
    +                root
    +          messagebus
    +     systemd-network
     
    -$ awk -F: '{printf "%-20s\n", $1}' /etc/passwd |head -n3
    +$ awk -F: '{printf "%-20s\n", $1}' /etc/passwd |head -n3
     root
     messagebus
     systemd-network
     
    -$ awk -F: '{printf "%-20s %10d\n", $1, $3}' /etc/passwd |head -n3
    -root                          0
    -messagebus                  499
    -systemd-network             497
    -
    $ awk -F: '{printf "Username: %s\n", $1}' /etc/passwd |head -n3
    -Username: root
    -Username: messagebus
    -Username: systemd-network
    -
    -$ awk -F: '{printf "Username: %s UID:%d\n", $1, $3}' /etc/passwd |head -n3
    -Username: root UID:0
    -Username: messagebus UID:499
    -Username: systemd-network UID:497
    -
    -$ awk -F: '{printf "Username: %25s UID:%d\n", $1, $3}' /etc/passwd |head -n3
    -Username:                      root UID:0
    -Username:                messagebus UID:499
    -Username:           systemd-network UID:497
    -
    -$ awk -F: '{printf "Username: %-25s UID:%d\n", $1, $3}' /etc/passwd |head -n3
    -Username: root                      UID:0
    -Username: messagebus                UID:499
    -Username: systemd-network           UID:497
    -

    5.10.9.BEGIN/END

    示例:

    awk -F":" 'BEGIN{printf "--------------------------------\n%-20s|%10s|\n--------------------------------\n", "Username", "UID"}{printf "%-20s|%-10d|\n--------------------------------\n", $1, $3}END{print "end"}' /etc/passwd
    +$ awk -F: '{printf "%-20s %10d\n", $1, $3}' /etc/passwd |head -n3
    +root                          0
    +messagebus                  499
    +systemd-network             497
    +
    $ awk -F: '{printf "Username: %s\n", $1}' /etc/passwd |head -n3
    +Username: root
    +Username: messagebus
    +Username: systemd-network
    +
    +$ awk -F: '{printf "Username: %s UID:%d\n", $1, $3}' /etc/passwd |head -n3
    +Username: root UID:0
    +Username: messagebus UID:499
    +Username: systemd-network UID:497
    +
    +$ awk -F: '{printf "Username: %25s UID:%d\n", $1, $3}' /etc/passwd |head -n3
    +Username:                      root UID:0
    +Username:                messagebus UID:499
    +Username:           systemd-network UID:497
    +
    +$ awk -F: '{printf "Username: %-25s UID:%d\n", $1, $3}' /etc/passwd |head -n3
    +Username: root                      UID:0
    +Username: messagebus                UID:499
    +Username: systemd-network           UID:497
    +

    5.10.9.BEGIN/END

    示例:

    awk -F":" 'BEGIN{printf "--------------------------------\n%-20s|%10s|\n--------------------------------\n", "Username", "UID"}{printf "%-20s|%-10d|\n--------------------------------\n", $1, $3}END{print "end"}' /etc/passwd
     --------------------------------
    -Username            |       UID|
    +Username            |       UID|
     --------------------------------
    -root                |0         |
    +root                |0         |
     --------------------------------
    -daemon              |1         |
    +daemon              |1         |
     --------------------------------
    -bin                 |2         |
    +bin                 |2         |
     -------------------------------
    -... ...
    +... ...
     --------------------------------
    -mfe                 |997       |
    +mfe                 |997       |
     --------------------------------
     end
    -

    5.10.10.常用控制语句

    • {statements;...} 组合语句

    • if(condition){statements;...}

    • if(condition){statements;...} else(statements;...)

    • switch(expression){case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2;......;default: statementn}

    • while(condition){statements;...}

    • do(statements;...) while{condition}

    • for(expr1;expr2;expr3) {statements;...}

    • break

    • continue

    • exit

    if-else示例:

    $ cat <<EOF > score.txt
    +

    5.10.10.常用控制语句

    • {statements;...} 组合语句

    • if(condition){statements;...}

    • if(condition){statements;...} else(statements;...)

    • switch(expression){case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2;......;default: statementn}

    • while(condition){statements;...}

    • do(statements;...) while{condition}

    • for(expr1;expr2;expr3) {statements;...}

    • break

    • continue

    • exit

    if-else示例:

    $ cat <<EOF > score.txt
     Name  Score
     Tom   100
     Jack  91
    @@ -1598,118 +1598,118 @@
     Jim   51
     EOF
     
    -$ awk 'NR!=1{score=$2;if($2>=80){print $1, "Good"}else if($2>=60){print $1, "Pass"}else{print $1, "failed"}}'
    +$ awk 'NR!=1{score=$2;if($2>=80){print $1, "Good"}else if($2>=60){print $1, "Pass"}else{print $1, "failed"}}'
     score.txt
    -Tom Good
    -Jack Good
    -Bill Good
    -Jim failed
    -

    switch示例:

    $ awk 'NR!=1{switch($2){case 100:print $1,"good"; case 60:print $1,"Pass"; default:print $1,"others"}}' score.txt
    -Tom good
    -Tom Pass
    -Tom others
    -Jack others
    -Bill others
    -Jim others
    -

    while示例:

    $ awk 'BEGIN{i=0;sum=0;while(i<=100){sum+=i;i++};print sum}'
    +Tom Good
    +Jack Good
    +Bill Good
    +Jim failed
    +

    switch示例:

    $ awk 'NR!=1{switch($2){case 100:print $1,"good"; case 60:print $1,"Pass"; default:print $1,"others"}}' score.txt
    +Tom good
    +Tom Pass
    +Tom others
    +Jack others
    +Bill others
    +Jim others
    +

    while示例:

    $ awk 'BEGIN{i=0;sum=0;while(i<=100){sum+=i;i++};print sum}'
     5050
    -

    do-while示例:

    $ awk 'BEGIN{i=0;sum=0;do{sum+=i;i++}while(i<101);print sum}'
    +

    do-while示例:

    $ awk 'BEGIN{i=0;sum=0;do{sum+=i;i++}while(i<101);print sum}'
     5050
    -

    for示例:

    $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){sum+=i};print sum}'
    +

    for示例:

    $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){sum+=i};print sum}'
     5050
    -

    命令效率比较:

    $ time(awk 'BEGIN{i=0;sum=0;while(i<=100000){sum+=i;i++};print sum}')
    +

    命令效率比较:

    $ time(awk 'BEGIN{i=0;sum=0;while(i<=100000){sum+=i;i++};print sum}')
     5000050000
     
    -real    0m0.028s
    -user    0m0.027s
    -sys    0m0.001s
    +real    0m0.028s
    +user    0m0.027s
    +sys    0m0.001s
     
    -$ time(seq -s+ 1000000 |bc)
    +$ time(seq -s+ 1000000 |bc)
     500000500000
     
    -real    0m0.329s
    -user    0m0.240s
    -sys    0m0.094s
    +real    0m0.329s
    +user    0m0.240s
    +sys    0m0.094s
     
    -$ time(awk 'BEGIN{i=0;sum=0;for(i=1;i<=1000000;i++){sum+=i};print sum}')
    +$ time(awk 'BEGIN{i=0;sum=0;for(i=1;i<=1000000;i++){sum+=i};print sum}')
     500000500000
     
    -real    0m0.050s
    -user    0m0.046s
    -sys    0m0.004s
    -

    contine示例:中断当前循环,进入下一次循环。

    $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){if(i==50)continue;sum+=i};print sum}'
    +real    0m0.050s
    +user    0m0.046s
    +sys    0m0.004s
    +

    contine示例:中断当前循环,进入下一次循环。

    $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){if(i==50)continue;sum+=i};print sum}'
     5000
    -

    contine示例:中断整个循环。

    $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){if(i==50)break;sum+=i};print sum}'
    +

    contine示例:中断整个循环。

    $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){if(i==50)break;sum+=i};print sum}'
     1225
    -

    next示例:提前结束对本行处理,直接进入下一行处理(注,awk自循环,并非前面的for或while循环)

    $ awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd  # 奇数行打印
    -root 0
    -systemd-timesync 496
    -nobody 65534
    -chrony 494
    -games 492
    -daemon 2
    -rpc 490
    -polkitd 488
    -ftpsecure 486
    -sshd 484
    -vagrant 1000
    -svn 482
    -tester1 600
    -tester4 1002
    -user0 1004
    -user2 1006
    -user4 1008
    -user6 1010
    -user8 1012
    -gentoo 1014
    -varnish 1016
    -webuser 666
    -admin3 1020
    -smith 2002
    -tm1 2004
    -
    -$ awk -F: '{if($3%2==0)next;print $1,$3}' /etc/passwd  # 偶数行打印
    -messagebus 499
    -systemd-network 497
    -mail 495
    -postfix 51
    -man 13
    -lp 493
    -ftp 491
    -nscd 489
    -at 25
    -tftp 487
    -bin 1
    -statd 485
    -pesign 483
    -tester2 601
    -tester3 1001
    -tester5 1003
    -user1 1005
    -user3 1007
    -user5 1009
    -user7 1011
    -user9 1013
    -nginx 1015
    -mysql 1017
    -pm1 2003
    -tm2 2005
    -

    5.10.11.数组

    关联数组是一种数据结构,也称为字典或映射。与传统的数组不同,关联数组的索引可以是任何类型的数据,例如字符串或对象,而不仅仅是整数。

    提示:

    在计算机编程中,除了关联数组,还有其他几种常见的数组类型,包括:

    1. 线性数组(或称为索引数组):这是最常见的数组类型,其中每个元素都有一个数字索引,可以用来快速访问数组中的元素。例如,在C语言中,数组的每个元素都可以通过数组下标来访问。
    2. 多维数组:多维数组是一种数组,其中每个元素也是一个数组。在二维数组中,每个元素都有两个索引(例如,行和列),可以用于访问数组中的元素。在高维数组中,每个元素都具有更多的索引。
    3. 动态数组:动态数组是一种可以动态调整大小的数组。在许多编程语言中,动态数组可以动态分配内存,以便在程序运行时根据需要调整数组的大小。
    4. 向量:向量是一种数组,其中每个元素都是相同的数据类型。向量通常用于执行数学运算或处理大量数字数据。

    awk中使用数组时,通常会将某些值与一个字符串相关联,以便在需要时可以通过该字符串快速地检索该值。 awk的数组是一个关联数组,其中每个元素都由一个唯一的键值和一个对应的值组成。键值(或称为索引)可以是任何类型的字符串。

    数组可以通过以下语法进行声明:

    array_name[index] = value
    -

    其中,array_name是数组的名称,index是元素的索引值,value是元素的值。

    例如,以下是一个包含三个元素的关联数组的示例:

    array["apple"] = 1
    -array["banana"] = 2
    -array["orange"] = 3
    -

    在上面的示例中,array是一个关联数组,其索引为字符串类型,而值为整数类型。可以使用以下的方式访问该数组中的元素:

    value = array["apple"]
    -

    在上面的示例中,value的值将为1,因为array["apple"]的值为1

    以下是用awk命令来创建上面那个包含三个元素的关联数组,遍历并输出数组值:

    awk 'BEGIN { array["apple"]=1; array["banana"]=2; array["orange"]=3; for(i in array){print array[i]}}'
    +

    next示例:提前结束对本行处理,直接进入下一行处理(注,awk自循环,并非前面的for或while循环)

    $ awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd  # 奇数行打印
    +root 0
    +systemd-timesync 496
    +nobody 65534
    +chrony 494
    +games 492
    +daemon 2
    +rpc 490
    +polkitd 488
    +ftpsecure 486
    +sshd 484
    +vagrant 1000
    +svn 482
    +tester1 600
    +tester4 1002
    +user0 1004
    +user2 1006
    +user4 1008
    +user6 1010
    +user8 1012
    +gentoo 1014
    +varnish 1016
    +webuser 666
    +admin3 1020
    +smith 2002
    +tm1 2004
    +
    +$ awk -F: '{if($3%2==0)next;print $1,$3}' /etc/passwd  # 偶数行打印
    +messagebus 499
    +systemd-network 497
    +mail 495
    +postfix 51
    +man 13
    +lp 493
    +ftp 491
    +nscd 489
    +at 25
    +tftp 487
    +bin 1
    +statd 485
    +pesign 483
    +tester2 601
    +tester3 1001
    +tester5 1003
    +user1 1005
    +user3 1007
    +user5 1009
    +user7 1011
    +user9 1013
    +nginx 1015
    +mysql 1017
    +pm1 2003
    +tm2 2005
    +

    5.10.11.数组

    关联数组是一种数据结构,也称为字典或映射。与传统的数组不同,关联数组的索引可以是任何类型的数据,例如字符串或对象,而不仅仅是整数。

    提示:

    在计算机编程中,除了关联数组,还有其他几种常见的数组类型,包括:

    1. 线性数组(或称为索引数组):这是最常见的数组类型,其中每个元素都有一个数字索引,可以用来快速访问数组中的元素。例如,在C语言中,数组的每个元素都可以通过数组下标来访问。
    2. 多维数组:多维数组是一种数组,其中每个元素也是一个数组。在二维数组中,每个元素都有两个索引(例如,行和列),可以用于访问数组中的元素。在高维数组中,每个元素都具有更多的索引。
    3. 动态数组:动态数组是一种可以动态调整大小的数组。在许多编程语言中,动态数组可以动态分配内存,以便在程序运行时根据需要调整数组的大小。
    4. 向量:向量是一种数组,其中每个元素都是相同的数据类型。向量通常用于执行数学运算或处理大量数字数据。

    awk中使用数组时,通常会将某些值与一个字符串相关联,以便在需要时可以通过该字符串快速地检索该值。 awk的数组是一个关联数组,其中每个元素都由一个唯一的键值和一个对应的值组成。键值(或称为索引)可以是任何类型的字符串。

    数组可以通过以下语法进行声明:

    array_name[index] = value
    +

    其中,array_name是数组的名称,index是元素的索引值,value是元素的值。

    例如,以下是一个包含三个元素的关联数组的示例:

    array["apple"] = 1
    +array["banana"] = 2
    +array["orange"] = 3
    +

    在上面的示例中,array是一个关联数组,其索引为字符串类型,而值为整数类型。可以使用以下的方式访问该数组中的元素:

    value = array["apple"]
    +

    在上面的示例中,value的值将为1,因为array["apple"]的值为1

    以下是用awk命令来创建上面那个包含三个元素的关联数组,遍历并输出数组值:

    awk 'BEGIN { array["apple"]=1; array["banana"]=2; array["orange"]=3; for(i in array){print array[i]}}'
     3
     1
     2
    -

    下面例子中,我们互换了数组的键和值。

    $ awk 'BEGIN {arr[1]="apple";arr[2]="banana";arr[3]="orange";for(i in arr){print arr[i]}}'
    +

    下面例子中,我们互换了数组的键和值。

    $ awk 'BEGIN {arr[1]="apple";arr[2]="banana";arr[3]="orange";for(i in arr){print arr[i]}}'
     apple
     banana
     orange
    -

    在上面的示例中,i是数组arr的索引值,arr[i]是数组中对应的元素值。通过这种方式可以循环遍历整个数组,并输出其中的元素。

    除了使用循环遍历数组之外,还可以使用length函数获取数组中元素的数量。例如:

    $ awk 'BEGIN { arr[1]="apple"; arr[2]="banana"; arr[3]="orange"; print length(arr) }'
    +

    在上面的示例中,i是数组arr的索引值,arr[i]是数组中对应的元素值。通过这种方式可以循环遍历整个数组,并输出其中的元素。

    除了使用循环遍历数组之外,还可以使用length函数获取数组中元素的数量。例如:

    $ awk 'BEGIN { arr[1]="apple"; arr[2]="banana"; arr[3]="orange"; print length(arr) }'
     3
    -

    上面的示例将输出数字3,表示数组arr中包含三个元素。

    举例:去重复记录。 line是数组名,$0awk读取的当前行的内容。 line[$0]等价于line["a"]line["b"],......。

    我们看执行过程:

    1. awk读入第1行;
    2. 执行line["a"],值为空;
    3. 求反,则第一行的值变为true,即!line["a"]=true
    4. !line["a"]true,则打印当前行,即输出a到屏幕;
    5. 执行line["a"]++,注意第2步中line["a"]的值是空,执行++后值变为1
    6. 同理,我们可以看到第2,3,4行都输出了。
    7. 当读入第5行时(第二个a),执行line["a"],值为1!line["a"]=0,即false;则不打印当前行,即不输出a到屏幕;执行++后值变为2
    8. 当读入第8行时(第三个a),执行line["a"],值为2!line["a"]=0,即false;则不打印当前行,即不输出a到屏幕;执行++后值变为3
    9. 以此类推,读入第二个bcde,都不会再输出到屏幕,从而实现去重输出到功能。
    $ cat > test << EOF
    +

    上面的示例将输出数字3,表示数组arr中包含三个元素。

    举例:去重复记录。 line是数组名,$0awk读取的当前行的内容。 line[$0]等价于line["a"]line["b"],......。

    我们看执行过程:

    1. awk读入第1行;
    2. 执行line["a"],值为空;
    3. 求反,则第一行的值变为true,即!line["a"]=true
    4. !line["a"]true,则打印当前行,即输出a到屏幕;
    5. 执行line["a"]++,注意第2步中line["a"]的值是空,执行++后值变为1
    6. 同理,我们可以看到第2,3,4行都输出了。
    7. 当读入第5行时(第二个a),执行line["a"],值为1!line["a"]=0,即false;则不打印当前行,即不输出a到屏幕;执行++后值变为2
    8. 当读入第8行时(第三个a),执行line["a"],值为2!line["a"]=0,即false;则不打印当前行,即不输出a到屏幕;执行++后值变为3
    9. 以此类推,读入第二个bcde,都不会再输出到屏幕,从而实现去重输出到功能。
    $ cat > test << EOF
     a
     b
     c
    @@ -1723,25 +1723,25 @@
     e
     EOF
     
    -$ awk '!line[$0]++' test
    +$ awk '!line[$0]++' test
     a
     b
     c
     d
     e
    -

    举例:判断数组索引是否存在。 方法:<your_var> in array0表示不存在,1表示存在。

    $ awk 'BEGIN{array["i"]="x";array["j"]="j";print "i" in array, "y" in array}'
    -1 0
    -$ awk 'BEGIN{array["i"]="x";array["j"]="j";if("i" in array){print "exits!"}else{print "not exists!"}}'
    +

    举例:判断数组索引是否存在。 方法:<your_var> in array0表示不存在,1表示存在。

    $ awk 'BEGIN{array["i"]="x";array["j"]="j";print "i" in array, "y" in array}'
    +1 0
    +$ awk 'BEGIN{array["i"]="x";array["j"]="j";if("i" in array){print "exits!"}else{print "not exists!"}}'
     exits!
    -$ awk 'BEGIN{array["i"]="x";array["j"]="j";if("abc" in array){print "exits!"}else{print "not exists!"}}'
    -not exists!
    -

    举例:遍历数组中每个元素。 方法:for(your_var in array){your_for_body},注意,your_var会遍历每个索引。

    $ awk 'BEGIN{weekday["mon"]="Monday";weekday["tue"]="Tuesday";for(i in weekday){print i,weekday[i]}}'
    -tue Tuesday
    -mon Monday
    -$ awk 'BEGIN{weekday["mon"]="Monday";weekday["tue"]="Tuesday";for(i in weekday){print i": "weekday[i]}}'
    -tue: Tuesday
    -mon: Monday
    -

    注意下面的换行写法,不需要反斜杠\

    $ awk 'BEGIN{
    +$ awk 'BEGIN{array["i"]="x";array["j"]="j";if("abc" in array){print "exits!"}else{print "not exists!"}}'
    +not exists!
    +

    举例:遍历数组中每个元素。 方法:for(your_var in array){your_for_body},注意,your_var会遍历每个索引。

    $ awk 'BEGIN{weekday["mon"]="Monday";weekday["tue"]="Tuesday";for(i in weekday){print i,weekday[i]}}'
    +tue Tuesday
    +mon Monday
    +$ awk 'BEGIN{weekday["mon"]="Monday";weekday["tue"]="Tuesday";for(i in weekday){print i": "weekday[i]}}'
    +tue: Tuesday
    +mon: Monday
    +

    注意下面的换行写法,不需要反斜杠\

    $ awk 'BEGIN{
     arr["x"]="welcome"
     arr["y"]="to"
     arr["z"]="Shanghai"
    @@ -1749,115 +1749,115 @@
      print i, arr[i]
     }
     }'
    -x welcome
    -y to
    -z Shanghai
    -

    示例:格式化输出用户名和密码。

    $ awk -F: '{user[$1]=$3}END{for (i in user){print "Username: " i, "UID: " user[i]}}' /etc/passwd
    -Username: sshd UID: 476
    -Username: rpc UID: 482
    -Username: tftp UID: 488
    -Username: usbmux UID: 480
    -Username: srvGeoClue UID: 487
    +x welcome
    +y to
    +z Shanghai
    +

    示例:格式化输出用户名和密码。

    $ awk -F: '{user[$1]=$3}END{for (i in user){print "Username: " i, "UID: " user[i]}}' /etc/passwd
    +Username: sshd UID: 476
    +Username: rpc UID: 482
    +Username: tftp UID: 488
    +Username: usbmux UID: 480
    +Username: srvGeoClue UID: 487
     ......
     

    示例:显示主机连接状态出现的次数。

    # 传统方法
    -$ ss -ant| awk 'NR>=2{print $1}'| sort| uniq -c
    -$ ss -ant| awk 'NR!=1{print $1}'| sort| uniq -c
    -      1 ESTAB
    -      6 LISTEN
    +$ ss -ant| awk 'NR>=2{print $1}'| sort| uniq -c
    +$ ss -ant| awk 'NR!=1{print $1}'| sort| uniq -c
    +      1 ESTAB
    +      6 LISTEN
     
     # 使用awk数组
    -$ ss -ant| awk 'NR>=2{state[$1]++}END{for(i in state){print state[i], i}}'
    -$ ss -ant| awk 'NR!=1{state[$1]++}END{for(i in state){print state[i], i}}'
    -6 LISTEN
    -1 ESTAB
    -

    5.10.12.awk函数

    参考:awk函数官网

    5.10.12.1.内置函数

    awk中,函数是一种用于执行特定任务或计算特定值的可重用代码块。 awk提供了许多内置函数,可以用于处理文本数据、执行数学运算、操作字符串等。

    以下是一些常用的awk函数示例:

    • length(string):返回字符串的长度。
    $ awk 'BEGIN { str = "Hello World"; len = length(str); print len }'
    +$ ss -ant| awk 'NR>=2{state[$1]++}END{for(i in state){print state[i], i}}'
    +$ ss -ant| awk 'NR!=1{state[$1]++}END{for(i in state){print state[i], i}}'
    +6 LISTEN
    +1 ESTAB
    +

    5.10.12.awk函数

    参考:awk函数官网

    5.10.12.1.内置函数

    awk中,函数是一种用于执行特定任务或计算特定值的可重用代码块。 awk提供了许多内置函数,可以用于处理文本数据、执行数学运算、操作字符串等。

    以下是一些常用的awk函数示例:

    • length(string):返回字符串的长度。
    $ awk 'BEGIN { str = "Hello World"; len = length(str); print len }'
     11
    -
    $ cut -d: -f1 /etc/passwd | awk '{print length($1)}' | head -3
    +
    $ cut -d: -f1 /etc/passwd | awk '{print length($1)}' | head -3
     4
     10
     15
    -
    • substr(string, start, length):从指定位置开始提取字符串的子串。
    $ awk 'BEGIN { str = "Hello World"; substring = substr(str, 7, 5); print substring }'
    +
    • substr(string, start, length):从指定位置开始提取字符串的子串。
    $ awk 'BEGIN { str = "Hello World"; substring = substr(str, 7, 5); print substring }'
     World
     
    • sub(regexp, replacement [, target]):从字符串target中搜索匹配regexp的内容,并把第一个匹配的内容替换为replacement。懒惰模式。 注意:sub()函数在原始字符串上进行替换操作,并返回替换的次数。
    # 在原始字符串中,第一个匹配到的"at"被替换为"ith",因此输出结果中的"at"变为"ith",其他地方的"at"保持不变
    -$ awk 'BEGIN { str = "water, water, everywhere"; sub(/at/, "ith", str); print str }'
    -wither, water, everywhere
    +$ awk 'BEGIN { str = "water, water, everywhere"; sub(/at/, "ith", str); print str }'
    +wither, water, everywhere
     # 返回匹配次数
    -$ awk 'BEGIN { str = "water, water, everywhere"; str_new = sub(/at/, "ith", str); print str_new }'
    +$ awk 'BEGIN { str = "water, water, everywhere"; str_new = sub(/at/, "ith", str); print str_new }'
     1
    -
    $ echo "2023:15:35 08:15:26" | awk 'sub(/:/, "-", $0)'
    -2023-15:35 08:15:26
    -$ echo "2023:15:35 08:15:26" | awk 'sub(/:/, "-", $1)'
    -2023-15:35 08:15:26
    -$ echo "2023:15:35 08:15:26" | awk 'sub(/:/, "-", $2)'
    -2023:15:35 08-15:26
    +
    $ echo "2023:15:35 08:15:26" | awk 'sub(/:/, "-", $0)'
    +2023-15:35 08:15:26
    +$ echo "2023:15:35 08:15:26" | awk 'sub(/:/, "-", $1)'
    +2023-15:35 08:15:26
    +$ echo "2023:15:35 08:15:26" | awk 'sub(/:/, "-", $2)'
    +2023:15:35 08-15:26
     
    • gsub(regexp, replacement [, target]):从字符串target中搜索匹配regexp的内容,并把全部匹配的内容替换为replacement。贪婪模式。
    # 在原始字符串中,将所有匹配到的"at"被替换为"ith"
    -$ awk 'BEGIN { str = "water, water, everywhere"; gsub(/at/, "ith", str); print str }'
    -wither, wither, everywhere
    +$ awk 'BEGIN { str = "water, water, everywhere"; gsub(/at/, "ith", str); print str }'
    +wither, wither, everywhere
     # 返回匹配次数
    -$ awk 'BEGIN { str = "water, water, everywhere"; str_new = gsub(/at/, "ith", str); print str_new }'
    +$ awk 'BEGIN { str = "water, water, everywhere"; str_new = gsub(/at/, "ith", str); print str_new }'
     2
    -
    $ echo "2023:15:35 08:15:26" | awk 'gsub(/:/, "-", $0)'
    -2023-15-35 08-15-26
    -$ echo "2023:15:35 08:15:26" | awk 'gsub(/:/, "-", $1)'
    -2023-15-35 08:15:26
    -$ echo "2023:15:35 08:15:26" | awk 'gsub(/:/, "-", $2)'
    -2023:15:35 08-15-26
    -
    • split(string, array, delimiter):将字符串string按指定分隔符delimiter拆分成数组array的元素。 注意:第一个索引值为1,第二个索引值为2.
    $ awk 'BEGIN { str = "apple,banana,orange"; split(str, fruits, ","); print fruits[2] }'
    +
    $ echo "2023:15:35 08:15:26" | awk 'gsub(/:/, "-", $0)'
    +2023-15-35 08-15-26
    +$ echo "2023:15:35 08:15:26" | awk 'gsub(/:/, "-", $1)'
    +2023-15-35 08:15:26
    +$ echo "2023:15:35 08:15:26" | awk 'gsub(/:/, "-", $2)'
    +2023:15:35 08-15-26
    +
    • split(string, array, delimiter):将字符串string按指定分隔符delimiter拆分成数组array的元素。 注意:第一个索引值为1,第二个索引值为2.
    $ awk 'BEGIN { str = "apple,banana,orange"; split(str, fruits, ","); print fruits[2] }'
     banana
    -
    $ head -n2 /etc/passwd | awk '{split($0, array, ":")}END{print array[1]}'
    +
    $ head -n2 /etc/passwd | awk '{split($0, array, ":")}END{print array[1]}'
     messagebus
    -$ head -n2 /etc/passwd | awk '{split($0, array, ":")}END{print array[2]}'
    +$ head -n2 /etc/passwd | awk '{split($0, array, ":")}END{print array[2]}'
     x
    -$ head -n2 /etc/passwd | awk '{split($0, array, ":")}END{print array[3]}'
    +$ head -n2 /etc/passwd | awk '{split($0, array, ":")}END{print array[3]}'
     499
    -$ head -n2 /etc/passwd | awk '{split($0, array, ":")}END{print array[7]}'
    +$ head -n2 /etc/passwd | awk '{split($0, array, ":")}END{print array[7]}'
     /usr/bin/false
    -
    • index(string, search):在字符串中查找指定子串的位置。
    $ awk 'BEGIN { str = "Hello World"; pos = index(str, "World"); print pos }'
    +
    • index(string, search):在字符串中查找指定子串的位置。
    $ awk 'BEGIN { str = "Hello World"; pos = index(str, "World"); print pos }'
     7
    -
    • sprintf(format, expression):根据指定的格式将表达式转换为字符串。
    $ awk 'BEGIN { num = 3.14159; str = sprintf("%.2f", num); print str }'
    +
    • sprintf(format, expression):根据指定的格式将表达式转换为字符串。
    $ awk 'BEGIN { num = 3.14159; str = sprintf("%.2f", num); print str }'
     3.14
    -
    • rand():返回一个随机数,值在01之间均匀分布。这个值可以是0,但不会是1。从下面的例子可以看出,运行结果都是一样的,所以产生随机数的种子是一样的。
    $ awk 'BEGIN{print rand()}'
    +
    • rand():返回一个随机数,值在01之间均匀分布。这个值可以是0,但不会是1。从下面的例子可以看出,运行结果都是一样的,所以产生随机数的种子是一样的。
    $ awk 'BEGIN{print rand()}'
     0.924046
    -$ awk 'BEGIN{print rand()}'
    +$ awk 'BEGIN{print rand()}'
     0.924046
    -$ awk 'BEGIN{print rand()}'
    +$ awk 'BEGIN{print rand()}'
     0.924046
    -
    • srand():配合rand()函数,生成随机数种子。
    $ awk 'BEGIN{srand();print rand()}'
    +
    • srand():配合rand()函数,生成随机数种子。
    $ awk 'BEGIN{srand();print rand()}'
     0.112006
    -$ awk 'BEGIN{srand();print rand()}'
    +$ awk 'BEGIN{srand();print rand()}'
     0.663431
    -$  awk 'BEGIN{srand();print rand()}'
    +$  awk 'BEGIN{srand();print rand()}'
     0.541305
    -
    • int():返回整数。
    $ awk 'BEGIN{srand();print int(rand()*100)}'
    +
    • int():返回整数。
    $ awk 'BEGIN{srand();print int(rand()*100)}'
     84
    -$ awk 'BEGIN{srand();print int(rand()*100)}'
    +$ awk 'BEGIN{srand();print int(rand()*100)}'
     66
    -$ awk 'BEGIN{srand();print int(rand()*100)}'
    +$ awk 'BEGIN{srand();print int(rand()*100)}'
     8
     
    • system(command):执行command命令(可以是任何有效的Shell命令)并返回命令的退出状态码。允许在awk脚本中执行外部命令,并获取命令执行的结果。
    # 执行ls -l命令,并将命令的退出状态码存储在status变量中,并打印status变量的值
    -$ awk 'BEGIN { status = system("ls -l"); print "Exit status:", status }'
    -total 0
    -drwxr-xr-x 1 vagrant users 70 Jan  2 15:54 Desktop
    -drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Documents
    -drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Downloads
    -drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Music
    -drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Pictures
    -drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Public
    -drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Templates
    -drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Videos
    -drwxr-xr-x 1 vagrant users  0 Mar 15  2022 bin
    -Exit status: 0
    -
    $ awk 'BEGIN{score=100; system("echo your score is " score)}'
    -your score is 100
    -
    • systime():当前时间到1970年1月1日到秒数
    $ awk 'BEGIN{print systime()}'
    +$ awk 'BEGIN { status = system("ls -l"); print "Exit status:", status }'
    +total 0
    +drwxr-xr-x 1 vagrant users 70 Jan  2 15:54 Desktop
    +drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Documents
    +drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Downloads
    +drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Music
    +drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Pictures
    +drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Public
    +drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Templates
    +drwxr-xr-x 1 vagrant users  0 Jan  2 15:54 Videos
    +drwxr-xr-x 1 vagrant users  0 Mar 15  2022 bin
    +Exit status: 0
    +
    $ awk 'BEGIN{score=100; system("echo your score is " score)}'
    +your score is 100
    +
    • systime():当前时间到1970年1月1日到秒数
    $ awk 'BEGIN{print systime()}'
     1684158395
     
    • strftime(format, timestamp):将时间戳timestamp转换为指定格式format的日期和时间字符串。timestamp通常是一个以秒为单位表示的整数。

    常见的格式化字符串选项:

    • %Y:四位数的年份(例如:2023)
    • %m:两位数的月份(01-12)
    • %d:两位数的日期(01-31)
    • %H:两位数的小时(00-23)
    • %M:两位数的分钟(00-59)
    • %S:两位数的秒(00-60)
    • %Z:时区名称(例如:GMT)
    # 将当前时间戳转换为格式为"YYYY-MM-DD HH:MM:SS"的日期和时间字符串
    -$ awk 'BEGIN { timestamp = systime(); str = strftime("%Y-%m-%d %H:%M:%S", timestamp); print str }'
    -2023-05-15 22:01:35
    +$ awk 'BEGIN { timestamp = systime(); str = strftime("%Y-%m-%d %H:%M:%S", timestamp); print str }'
    +2023-05-15 22:01:35
     # 将当前时间戳的前一小时(3600秒)转换为格式为"YYYY-MM-DD HH:MM:SS"的日期和时间字符串
    -$ awk 'BEGIN { timestamp = systime()-3600; str = strftime("%Y-%m-%d %H:%M:%S", timestamp); print str }'
    -2023-05-15 21:01:43
    -

    5.10.12.2.自定义函数

    举例:

    $ cat > func.awk << EOF
    +$ awk 'BEGIN { timestamp = systime()-3600; str = strftime("%Y-%m-%d %H:%M:%S", timestamp); print str }'
    +2023-05-15 21:01:43
    +

    5.10.12.2.自定义函数

    举例:

    $ cat > func.awk << EOF
     function max(x,y){
       x>y?var=x:var=y
       return var
    @@ -1865,9 +1865,9 @@
     BEGIN{print max(a,b)}
     EOF
     
    -$ awk -v a=30 -v b=20 -f func.awk
    +$ awk -v a=30 -v b=20 -f func.awk
     30
    -

    举例:

    在下面的例子中,我们定义了一个名为square()的自定义函数,它接受一个参数x,并返回x的平方。然后,在主代码块中,我们声明了一个变量num并赋值为5。接下来,我们调用了自定义函数square(),传递num作为参数,并将返回值存储在变量result中。最后,我们打印出result的值。

    $ cat > func.awk << EOF
    +

    举例:

    在下面的例子中,我们定义了一个名为square()的自定义函数,它接受一个参数x,并返回x的平方。然后,在主代码块中,我们声明了一个变量num并赋值为5。接下来,我们调用了自定义函数square(),传递num作为参数,并将返回值存储在变量result中。最后,我们打印出result的值。

    $ cat > func.awk << EOF
     # 自定义函数:计算平方
     function square(x) {
       return x * x;
    @@ -1881,9 +1881,9 @@
     }
     EOF
     
    -$ awk -f func.awk
    +$ awk -f func.awk
     平方结果:25
    -

    举例:

    $ cat > func.awk << EOF
    +

    举例:

    $ cat > func.awk << EOF
     # 自定义函数:计算数组平均值
     function calculateAverage(arr, size) {
       sum = 0;
    @@ -1910,28 +1910,28 @@
     }
     EOF
     
    -$ awk -f func.awk
    +$ awk -f func.awk
     数组的平均值:30
     

    5.10.12.3.awk脚本

    举例:

    # 注意转义
    -$ cat > passwd.awk << EOF
    +$ cat > passwd.awk << EOF
     {if(\$3>=1000)print \$1,\$3}
     EOF
     
    -$ awk -F: -f passwd.awk /etc/passwd
    -nobody 65534
    -vagrant 1000
    -

    上面例子也可以写成如下脚步格式。

    $ cat > test.awk << EOF
    +$ awk -F: -f passwd.awk /etc/passwd
    +nobody 65534
    +vagrant 1000
    +

    上面例子也可以写成如下脚步格式。

    $ cat > test.awk << EOF
     #!/bin/awk -f
     # This is an awk script
     {if(\$3>=1000)print \$1,\$3}
     EOF
     
    -$ chmod +x test.awk
    -$ ./test.awk -F: /etc/passwd
    -nobody 65534
    -vagrant 1000
    +$ chmod +x test.awk
    +$ ./test.awk -F: /etc/passwd
    +nobody 65534
    +vagrant 1000
     

    向awk脚本传递参数:

    格式:awkfile var=value var2=value2 ... inputfile

    说明:

    • 上面格式变量在BEGIN过程中不可用,直到首行输入完成以后,变量才可用。
    • 可以通过-v参数,让awk在执行BEGIN之前得到变量。
    • 命令行中每一个指定的变量都需要一个-v参数。

    举例:

    # x=100在BEGIN{print x}区段可用
    -$ awk -v x=100 'BEGIN{print x}{print x+100}' /etc/hosts
    +$ awk -v x=100 'BEGIN{print x}{print x+100}' /etc/hosts
     100
     200
     200
    @@ -1957,10 +1957,10 @@
     200
     200
     # 不加-v则x=100在BEGIN{print x}区段不可用
    -$ awk x=100 'BEGIN{print x}{print x+100}' /etc/hosts
    -awk: fatal: cannot open file `BEGIN{print x}{print x+100}' for reading (No such file or directory)
    +$ awk x=100 'BEGIN{print x}{print x+100}' /etc/hosts
    +awk: fatal: cannot open file `BEGIN{print x}{print x+100}' for reading (No such file or directory)
     # 修正上面的错误,将x=100放在后面,因为没有-v,所以x=100在BEGIN{print x}区段不可用,第一行输出空白
    -$ awk 'BEGIN{print x}{print x+100}' x=100 /etc/hosts
    +$ awk 'BEGIN{print x}{print x+100}' x=100 /etc/hosts
     
     200
     200
    @@ -1985,96 +1985,96 @@
     200
     200
     200
    -

    5.11.小练习

    • 显示/proc/meminfo文件中以大小s开头的行,要求使用两种方法。
    cat /proc/meminfo | grep -i "^s"
    -cat /proc/meminfo | grep "^[sS]"
    -
    • 显示/etc/passwd文件中不以/bin/bash结尾的行。
    grep -v "/bin/bash$" /etc/passwd
    -
    • 显示用户rpc默认的shell程序。
    $ grep "rpc" /etc/passwd | cut -d ":" -f 7
    +

    5.11.小练习

    • 显示/proc/meminfo文件中以大小s开头的行,要求使用两种方法。
    cat /proc/meminfo | grep -i "^s"
    +cat /proc/meminfo | grep "^[sS]"
    +
    • 显示/etc/passwd文件中不以/bin/bash结尾的行。
    grep -v "/bin/bash$" /etc/passwd
    +
    • 显示用户rpc默认的shell程序。
    $ grep "rpc" /etc/passwd | cut -d ":" -f 7
     /sbin/nologin
    -
    • 找出/etc/passwd中的两位或三位数。
    grep -Eo "[:digit:]{2,3}" /etc/passwd
    -grep -Eo "[0-9]{2,3}" /etc/passwd
    +
    • 找出/etc/passwd中的两位或三位数。
    grep -Eo "[:digit:]{2,3}" /etc/passwd
    +grep -Eo "[0-9]{2,3}" /etc/passwd
     

    这里用到了{},属于扩展正则符号,所以要用-E

    • 显示Rocky 9的/etc/grub2.cfg文件中,至少以一个空白字符开头的且后面有非空白字符的行。(注:/etc/grub2.cfg在openSUSE和Ubuntu中没有)
    # 不含首字符为tab
    -$ sudo grep "^ " /etc/grub2.cfg
    +$ sudo grep "^ " /etc/grub2.cfg
     
     # 包含首字符为tab
    -$ sudo grep "^[[:space:]]" /etc/grub2.cfg
    -
    • 找出netstat -tan命令结果中以LISTEN后跟任意多个空白字符结尾的行。
    netstat -tan | grep -E "LISTEN[[:space:]]+"
    -
    • 显示Rocky 9上所有UID小于1000以内的用户名和UID。
    cat /etc/passwd | cut -d ":" -f 1,3 | grep -E "\:[0-9]{1,3}$"
    -grep -E "\:[0-9]{1,3}\:[0-9]{1,}" /etc/passwd | cut -d ":" -f 1,3
    -
    • 在Rocky 9上显示文件/etc/passwd用户名和shell同名的行。
    $ grep -E "^([[:alnum:]]+\b).*\1$" /etc/passwd
    +$ sudo grep "^[[:space:]]" /etc/grub2.cfg
    +
    • 找出netstat -tan命令结果中以LISTEN后跟任意多个空白字符结尾的行。
    netstat -tan | grep -E "LISTEN[[:space:]]+"
    +
    • 显示Rocky 9上所有UID小于1000以内的用户名和UID。
    cat /etc/passwd | cut -d ":" -f 1,3 | grep -E "\:[0-9]{1,3}$"
    +grep -E "\:[0-9]{1,3}\:[0-9]{1,}" /etc/passwd | cut -d ":" -f 1,3
    +
    • 在Rocky 9上显示文件/etc/passwd用户名和shell同名的行。
    $ grep -E "^([[:alnum:]]+\b).*\1$" /etc/passwd
     sync:x:5:0:sync:/sbin:/bin/sync
     shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
     halt:x:7:0:halt:/sbin:/sbin/halt
    -
    • 利用dfgrep,取出磁盘各分区利用率,并从大到小排序。
    $ df | tr -s " " | cut -d " " -f 1,5 | sort -n -t " " -k 2
    -devtmpfs 0%
    -Filesystem Use%
    -tmpfs 0%
    -tmpfs 0%
    -/dev/mapper/rl-home 1%
    -tmpfs 2%
    -/dev/mapper/rl-root 5%
    -/dev/nvme0n1p1 23%
    -
    • 显示三个用户rootsyncbin的UID和默认shell。
    $ grep "^root:\|^sync:\|^bin:" /etc/passwd | cut -d ":" -f 1,7
    +
    • 利用dfgrep,取出磁盘各分区利用率,并从大到小排序。
    $ df | tr -s " " | cut -d " " -f 1,5 | sort -n -t " " -k 2
    +devtmpfs 0%
    +Filesystem Use%
    +tmpfs 0%
    +tmpfs 0%
    +/dev/mapper/rl-home 1%
    +tmpfs 2%
    +/dev/mapper/rl-root 5%
    +/dev/nvme0n1p1 23%
    +
    • 显示三个用户rootsyncbin的UID和默认shell。
    $ grep "^root:\|^sync:\|^bin:" /etc/passwd | cut -d ":" -f 1,7
     root:/bin/bash
     bin:/usr/sbin/nologin
     
    • 使用egrep取出/etc/default-1/text_2/local.3/grub中其基名和目录名。
    # 基名
    -$ echo "/etc/default-1/text_2/local.3/grub" | egrep -io "[[:alpha:]]+$"
    +$ echo "/etc/default-1/text_2/local.3/grub" | egrep -io "[[:alpha:]]+$"
     grub
     
     # 目录名
    -$  echo "/etc/default-1/text_2/local.3/grub" | egrep -io "/([[:alpha:]]+.|_?[[:alpha:]]|[[:alnum:]]+/){7}"
    -/etc/default-1/text_2/local.3/ 
    -
    • 统计last命令中以vagrant登录的每个主机IP地址登录次数。
    $ last | grep vagrant | tr -s " " | cut -d " " -f 3 | grep -E "([0-9]{1,3}\.){1,3}[0-9]{1,3}" | sort -n | uniq -c
    -    24 192.168.10.107
    -    38 192.168.10.109
    -    17 192.168.10.201
    -     6 192.168.10.210
    -     2 192.168.10.220
    +$  echo "/etc/default-1/text_2/local.3/grub" | egrep -io "/([[:alpha:]]+.|_?[[:alpha:]]|[[:alnum:]]+/){7}"
    +/etc/default-1/text_2/local.3/ 
    +
    • 统计last命令中以vagrant登录的每个主机IP地址登录次数。
    $ last | grep vagrant | tr -s " " | cut -d " " -f 3 | grep -E "([0-9]{1,3}\.){1,3}[0-9]{1,3}" | sort -n | uniq -c
    +    24 192.168.10.107
    +    38 192.168.10.109
    +    17 192.168.10.201
    +     6 192.168.10.210
    +     2 192.168.10.220
     
    • 利用扩展正则表达式分别表示0-9、10-99、100-199、200-249、250-255。
    [0-9]|[0-9]{2}|1[0-9]{2}|2[0-4][0-9]|25[0-5]
    -
    • 显示ifconfig命令结果中所有IPv4地址。
    $ ifconfig | grep -Eo "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v "^255"
    +
    • 显示ifconfig命令结果中所有IPv4地址。
    $ ifconfig | grep -Eo "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v "^255"
     192.168.10.210
     192.168.10.255
     127.0.0.1
    -
    • 显示ip addr命令结果中所有IPv4地址。
    $ ip addr show eth0 | grep inet | grep eth0 | tr -s " " | cut -d " " -f 3 | cut -d "/" -f 1
    +
    • 显示ip addr命令结果中所有IPv4地址。
    $ ip addr show eth0 | grep inet | grep eth0 | tr -s " " | cut -d " " -f 3 | cut -d "/" -f 1
     192.168.10.210
     
    -$ ip addr show | grep -Eo "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v "^255"
    +$ ip addr show | grep -Eo "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -v "^255"
     127.0.0.1
     192.168.10.210
     192.168.10.255
    -
    • 将此字符串Welcome to the linux world中的每个字符去重并排序,重复次数多的排到前面。
    $ echo "Welcome to the linux world" | grep -o [[:alpha:]] | sort | uniq -c | sort -nr
    -     3 o
    -     3 l
    -     3 e
    -     2 t
    -     1 x
    -     1 W
    -     1 w
    -     1 u
    -     1 r
    -     1 n
    -     1 m
    -     1 i
    -     1 h
    -     1 d
    -     1 c
    -
    • 删除/etc/default/grub文件中所有以空白开头的行行首的空白字符。
    sed '/^$/d' /etc/default/grub
    -
    • 删除/etc/default/grub文件中所有以#开头,后面至少跟一个空白字符的行的行首的#和空白字符。
    sed -r '/#[[:space:]]+/d;/#/d' /etc/default/grub
    -

    上面输出结果中包含空白行。

    若输出中删除空白行,则:

    sed -r '/#[[:space:]]+/d;/#/d;/^$/d' /etc/default/grub
    -
    • /etc/fstab每一行行首增加#号。
    sed -r 's/(.*)/#&/' /etc/fstab
    -
    • /etc/fstab文件中不以#开头的行的行首增加#号(包括空行)。
    sed -r 's/^[^#].*/#&/' -r 's/^$/#/' /etc/default/grub
    -
    • 通过命令rpm -qa --last |awk -F ' ' '{print $1}'得到最新安装的包列表。统计所有x86_64结尾的安装包名以.分隔倒数第二个字段的重复次数。
    $ rpm -qa --last |awk -F ' ' '{print $1}' |sed -nr '/x86_64$/s@.*\.(.*)\.x86_64@\1@p' |sort -r |uniq -c
    -     75 el9_0
    -    563 el9
    -      3 7
    -      1 5
    -      2 4
    -      2 3
    -     10 2
    -     29 1
    -
    • 在openSUSE中统计/etc/rc.status文件中每个单词的出现次数,并排序(用grep和sed两种方法分别实现)。
    grep -Eo "[a-zA-Z]+" /etc/rc.status |sort |uniq -c
    -
    -cat /etc/rc.status |sed -r 's/[^[:alpha:]]+/\n/g' |sed '/^$/d' |sort |uniq -c |sort -nr
    -
    • 将文本文件的n和n+1行合并为一行,n为奇数行。
    $ cat <<EOF > sed.txt
    +
    • 将此字符串Welcome to the linux world中的每个字符去重并排序,重复次数多的排到前面。
    $ echo "Welcome to the linux world" | grep -o [[:alpha:]] | sort | uniq -c | sort -nr
    +     3 o
    +     3 l
    +     3 e
    +     2 t
    +     1 x
    +     1 W
    +     1 w
    +     1 u
    +     1 r
    +     1 n
    +     1 m
    +     1 i
    +     1 h
    +     1 d
    +     1 c
    +
    • 删除/etc/default/grub文件中所有以空白开头的行行首的空白字符。
    sed '/^$/d' /etc/default/grub
    +
    • 删除/etc/default/grub文件中所有以#开头,后面至少跟一个空白字符的行的行首的#和空白字符。
    sed -r '/#[[:space:]]+/d;/#/d' /etc/default/grub
    +

    上面输出结果中包含空白行。

    若输出中删除空白行,则:

    sed -r '/#[[:space:]]+/d;/#/d;/^$/d' /etc/default/grub
    +
    • /etc/fstab每一行行首增加#号。
    sed -r 's/(.*)/#&/' /etc/fstab
    +
    • /etc/fstab文件中不以#开头的行的行首增加#号(包括空行)。
    sed -r 's/^[^#].*/#&/' -r 's/^$/#/' /etc/default/grub
    +
    • 通过命令rpm -qa --last |awk -F ' ' '{print $1}'得到最新安装的包列表。统计所有x86_64结尾的安装包名以.分隔倒数第二个字段的重复次数。
    $ rpm -qa --last |awk -F ' ' '{print $1}' |sed -nr '/x86_64$/s@.*\.(.*)\.x86_64@\1@p' |sort -r |uniq -c
    +     75 el9_0
    +    563 el9
    +      3 7
    +      1 5
    +      2 4
    +      2 3
    +     10 2
    +     29 1
    +
    • 在openSUSE中统计/etc/rc.status文件中每个单词的出现次数,并排序(用grep和sed两种方法分别实现)。
    grep -Eo "[a-zA-Z]+" /etc/rc.status |sort |uniq -c
    +
    +cat /etc/rc.status |sed -r 's/[^[:alpha:]]+/\n/g' |sed '/^$/d' |sort |uniq -c |sort -nr
    +
    • 将文本文件的n和n+1行合并为一行,n为奇数行。
    $ cat <<EOF > sed.txt
     1aa
     2bb
     3cc
    @@ -2084,26 +2084,26 @@
     7gg
     EOF
     
    -$ sed -n 'N;s/\n//p' sed.txt
    +$ sed -n 'N;s/\n//p' sed.txt
     1aa2bb
     3cc4dd
     5ee6ff
     
    -$ sed 'N;s/\n//' sed.txt
    +$ sed 'N;s/\n//' sed.txt
     1aa2bb
     3cc4dd
     5ee6ff
     7gg
    -
    • 对一串数字进行求和。
    $ cat <<EOF > number.txt
    +
    • 对一串数字进行求和。
    $ cat <<EOF > number.txt
     1 2 3 4 5 6
     EOF
    -
    $ tr ' ' + < number.txt | bc
    +
    $ tr ' ' + < number.txt | bc
     21
    -$ sum=0;for i in `cat number.txt`;do let sum+=i;done;echo $sum
    +$ sum=0;for i in `cat number.txt`;do let sum+=i;done;echo $sum
     21
    -$ awk '{sum=0;for(i=1;i<=NF;i++){sum+=i};print sum}' number.txt
    +$ awk '{sum=0;for(i=1;i<=NF;i++){sum+=i};print sum}' number.txt
     21
    -
    • 取出字符串中的数字。
    $ echo 'kdajl;3k8jd33la5kj23f90ld02sakjflakjdslf' | awk -F "" '
    +
    • 取出字符串中的数字。
    $ echo 'kdajl;3k8jd33la5kj23f90ld02sakjflakjdslf' | awk -F "" '
     {
       for(i=1;i<=NF;i++)
       {
    @@ -2115,7 +2115,7 @@
       print str
     }'
     38335239002
    -
    • host.log文件内容如下,提取.edu.cn前面的主机名,并回写到该文件中。
    $ cat > host.log << EOF
    +
    • host.log文件内容如下,提取.edu.cn前面的主机名,并回写到该文件中。
    $ cat > host.log << EOF
     1 www.edu.cn
     2 blog.edu.cn
     3 learning.edu.cn
    @@ -2131,7 +2131,7 @@
     EOF
     
     # 对比
    -$ awk -F'[ .]' '{print $1}' host.log
    +$ awk -F'[ .]' '{print $1}' host.log
     1
     2
     3
    @@ -2144,7 +2144,7 @@
     10
     11
     12
    -$ awk -F'[ .]' '{print $2}' host.log
    +$ awk -F'[ .]' '{print $2}' host.log
     www
     blog
     learning
    @@ -2159,20 +2159,20 @@
     www
     
     # 以空格或者.为分隔符,打印第二列(主机名),追加写入原文件
    -$ awk -F'[ .]' '{print $2}' host.log >> host.log
    -$ cat host.log
    -1 www.edu.cn
    -2 blog.edu.cn
    -3 learning.edu.cn
    -4 java.edu.cn
    -5 nodejs.edu.cn
    -6 k8s.eud.cn
    -7 linux.edu.cn
    -8 python.edu.cn
    -9 learning.edu.cn
    -10 java.edu.cn
    -11 nodejs.edu.cn
    -12 www.edu.cn
    +$ awk -F'[ .]' '{print $2}' host.log >> host.log
    +$ cat host.log
    +1 www.edu.cn
    +2 blog.edu.cn
    +3 learning.edu.cn
    +4 java.edu.cn
    +5 nodejs.edu.cn
    +6 k8s.eud.cn
    +7 linux.edu.cn
    +8 python.edu.cn
    +9 learning.edu.cn
    +10 java.edu.cn
    +11 nodejs.edu.cn
    +12 www.edu.cn
     www
     blog
     learning
    @@ -2186,76 +2186,76 @@
     nodejs
     www
     
    • 统计文件/etc/fstab中每个文件系统类型出现的次数。
    # 以UUID开头,一个或多个空格为分隔符,读取第三列(即文件系统类型)并计数。
    -$ awk -F' +' '/^UUID/{fs[$3]++}END{for(i in fs){print i, fs[i]}}' /etc/fstab
    -swap 1
    -btrfs 10
    -vfat 1
    +$ awk -F' +' '/^UUID/{fs[$3]++}END{for(i in fs){print i, fs[i]}}' /etc/fstab
    +swap 1
    +btrfs 10
    +vfat 1
     
     # 方法2
    -$ awk -F' +' '/^UUID/{print $3}' /etc/fstab | uniq -c
    -     10 btrfs
    -      1 swap
    -      1 vfat
    -
    • 统计文件/etc/fstab中每个单词出现的次数。
    $ awk -F"[^[:alpha:]]" '{for(i=1;i<=NF;i++)word[$i]++}END{for(a in word)if(a!="")print a,word[a]}' /etc/fstab
    -swap 2
    -B 1
    -srv 2
    -btrfs 10
    -snapshots 2
    -vfat 1
    -opt 2
    -cbaef 10
    -UUID 12
    -E 1
    -ecf 1
    -CD 1
    -cf 1
    -arm 2
    -a 11
    -c 2
    -tmp 2
    -usr 2
    -var 2
    -afa 20
    -home 2
    -d 10
    -utf 1
    -e 2
    -efi 3
    -grub 2
    -boot 3
    -subvol 9
    -root 2
    -local 2
    -defaults 2
    -f 10
    +$ awk -F' +' '/^UUID/{print $3}' /etc/fstab | uniq -c
    +     10 btrfs
    +      1 swap
    +      1 vfat
    +
    • 统计文件/etc/fstab中每个单词出现的次数。
    $ awk -F"[^[:alpha:]]" '{for(i=1;i<=NF;i++)word[$i]++}END{for(a in word)if(a!="")print a,word[a]}' /etc/fstab
    +swap 2
    +B 1
    +srv 2
    +btrfs 10
    +snapshots 2
    +vfat 1
    +opt 2
    +cbaef 10
    +UUID 12
    +E 1
    +ecf 1
    +CD 1
    +cf 1
    +arm 2
    +a 11
    +c 2
    +tmp 2
    +usr 2
    +var 2
    +afa 20
    +home 2
    +d 10
    +utf 1
    +e 2
    +efi 3
    +grub 2
    +boot 3
    +subvol 9
    +root 2
    +local 2
    +defaults 2
    +f 10
     
    • 提取字符串Yd$@C#M05MD9&8923+Vip3wZ!33*44&55中所有的数字。
    # 对比单引号和双引号的区别。
    -$  echo "Yd$@C#M05MD9&8923+Vip3wZ!33*44&55"
    -echo "Yd$@C#M05MD9&8923+Vip3wZcgcreate -g cpu:mygroup44&55"
    -YdC#M05MD9&8923+Vip3wZcgcreate -g cpu:mygroup44&55
    -$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'
    +$  echo "Yd$@C#M05MD9&8923+Vip3wZ!33*44&55"
    +echo "Yd$@C#M05MD9&8923+Vip3wZcgcreate -g cpu:mygroup44&55"
    +YdC#M05MD9&8923+Vip3wZcgcreate -g cpu:mygroup44&55
    +$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'
     Yd$@C#M05MD9&8923+Vip3wZ!33*44&55
     
    -$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk '{gsub(/[^0-9]/,"");print $0}'
    +$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk '{gsub(/[^0-9]/,"");print $0}'
     05989233334455
     
    -$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F'[^0-9]' '{for(i=1;i<=NF;i++){printf "%s", $i}}'
    +$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F'[^0-9]' '{for(i=1;i<=NF;i++){printf "%s", $i}}'
     05989233334455
     
    -$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F "" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
    +$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F "" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
     05989233334455
    -$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
    +$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
     # 注意,如果写成如下格式,则报错。
    -$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F'' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
    +$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F'' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
     # 注意,如果写成如下格式,则输出原字符串。
    -$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F ' ' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
    -
    • 生成500个随机数,保存到文件random.txt中,格式为100,20,61,98...,取出其中最大整数和最小整数。
    $ str=""; for ((i=1; i<=500; i++)); do if [ $i -ne 500 ]; then str+="$RANDOM,"; else str+="$RANDOM"; fi; done; echo "$str" > random.txt
    -$ cat random.txt
    +$ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55'|awk -F ' ' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'
    +
    • 生成500个随机数,保存到文件random.txt中,格式为100,20,61,98...,取出其中最大整数和最小整数。
    $ str=""; for ((i=1; i<=500; i++)); do if [ $i -ne 500 ]; then str+="$RANDOM,"; else str+="$RANDOM"; fi; done; echo "$str" > random.txt
    +$ cat random.txt
     11308,8764,2075,9411,......
    -$ awk -F, '{max=$1;min=$1;for(i=1;i<=NF;i++){if($i>max){max=$i}else{if($i<min){min=$i}}}}END{print "The max:" max, "The min:" min}' random.txt
    -The max:32696 The min:20
    -
    • 监控某个IP并发连接超过200时,调用防火墙命令封掉该IP,每5分钟监控一次。防火墙命令iptables -A INPUT -s IP -j REJECT
    ss -nt | awk -F " +|:" 'NR!=1{ip[$(NF-2)]++}END{for(i in ip){if(ip[i]>200){system("iptables -A INPUT -s " i " -j REJECT;")}}}'
    -
    • 将下面内容中FQDN取出,并根据其进行计数,从高到低排序。
    $ cat > fqdn.txt << EOF
    +$ awk -F, '{max=$1;min=$1;for(i=1;i<=NF;i++){if($i>max){max=$i}else{if($i<min){min=$i}}}}END{print "The max:" max, "The min:" min}' random.txt
    +The max:32696 The min:20
    +
    • 监控某个IP并发连接超过200时,调用防火墙命令封掉该IP,每5分钟监控一次。防火墙命令iptables -A INPUT -s IP -j REJECT
    ss -nt | awk -F " +|:" 'NR!=1{ip[$(NF-2)]++}END{for(i in ip){if(ip[i]>200){system("iptables -A INPUT -s " i " -j REJECT;")}}}'
    +
    • 将下面内容中FQDN取出,并根据其进行计数,从高到低排序。
    $ cat > fqdn.txt << EOF
     http://mail.edu.com/index.html
     http://www.edu.com/test.html
     http://study.edu.com/index.html
    @@ -2264,24 +2264,24 @@
     http://blog.edu.com/20080102.html
     EOF
     
    -$ awk -F"/" '{url[$3]++}END{for(i in url){print url[i], i}}' fqdn.txt|sort -nr
    -2 www.edu.com
    -2 blog.edu.com
    -1 study.edu.com
    -1 mail.edu.com
    -
    • 将以下⽂本以inode为标记,对inode相同的counts进⾏累加,并且统计出同一inode中,beginnumber的最小值和endnumber的最大值。
    inode|beginnumber|endnumber|counts| 
    -106|3363120000|3363129999|10000| 
    -106|3368560000|3368579999|20000| 
    -310|3337000000|3337000100|101| 
    -310|3342950000|3342959999|10000| 
    -310|3362120960|3362120961|2| 
    -311|3313460102|3313469999|9898| 
    -311|3313470000|3313499999|30000| 
    -311|3362120962|3362120963|2| 
    -

    输出的结果格式为:

    310|3337000000|3362120961|10103| 
    -311|3313460102|3362120963|39900| 
    +$ awk -F"/" '{url[$3]++}END{for(i in url){print url[i], i}}' fqdn.txt|sort -nr
    +2 www.edu.com
    +2 blog.edu.com
    +1 study.edu.com
    +1 mail.edu.com
    +
    • 将以下⽂本以inode为标记,对inode相同的counts进⾏累加,并且统计出同一inode中,beginnumber的最小值和endnumber的最大值。
    inode|beginnumber|endnumber|counts| 
    +106|3363120000|3363129999|10000| 
    +106|3368560000|3368579999|20000| 
    +310|3337000000|3337000100|101| 
    +310|3342950000|3342959999|10000| 
    +310|3362120960|3362120961|2| 
    +311|3313460102|3313469999|9898| 
    +311|3313470000|3313499999|30000| 
    +311|3362120962|3362120963|2| 
    +

    输出的结果格式为:

    310|3337000000|3362120961|10103| 
    +311|3313460102|3362120963|39900| 
     106|3363120000|3368579999|30000|
    -
    $ cat > inode.text << EOF
    +
    $ cat > inode.text << EOF
     inode|beginnumber|endnumber|counts| 
     106|3363120000|3363129999|10000| 
     106|3368560000|3368579999|20000| 
    @@ -2293,8 +2293,8 @@
     311|3362120962|3362120963|2| 
     EOF
     
    -$ awk -F'|' -v OFS='|' '/^[0-9]/{inode[$1]++; if(!bn[$1]){bn[$1]=$2}else if(bn[$1]>$2) {bn[$1]=$2}; if(en[$1]<$3)en[$1]=$3;cnt[$1]+=$(NF-1)} END{for(i in inode)print i,bn[i],en[i],cnt[i]}' inode.text
    +$ awk -F'|' -v OFS='|' '/^[0-9]/{inode[$1]++; if(!bn[$1]){bn[$1]=$2}else if(bn[$1]>$2) {bn[$1]=$2}; if(en[$1]<$3)en[$1]=$3;cnt[$1]+=$(NF-1)} END{for(i in inode)print i,bn[i],en[i],cnt[i]}' inode.text
     106|3363120000|3368579999|30000
     310|3337000000|3362120961|10103
     311|3313460102|3362120963|39900
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/linux/SRE/06-FileLookup/index.html b/linux/SRE/06-FileLookup/index.html index d05708ef..c44f6c3d 100644 --- a/linux/SRE/06-FileLookup/index.html +++ b/linux/SRE/06-FileLookup/index.html @@ -1,11 +1,11 @@ - 第六章 文件查找 - UPSkilling

    第六章 文件查找

    常用文件查找命令:

    locate命令

    locate 是一个在 Linux 系统上用于快速搜索文件和目录的命令。它使用预先构建的文件数据库/var/lib/mlocate/mlocate.db进行搜索,因此比直接在文件系统上搜索要快得多。

    使用 updatedb 命令手动更新文件数据库/var/lib/mlocate/mlocate.db,索引构建过程需要遍历整个根文件系统,很消耗资源。 注意,由于 locate 使用预先构建的文件数据库,因此在更新文件数据库之前,新创建或移动的文件可能不会立即出现在搜索结果中。

    在openSUSE 15中默认没有安装,需要手动安装下面的软件包。

    sudo zypper ref
    -sudo zypper in mlocate
    -sudo updatedb
    -

    locate 命令的特点:

    • 查找速度快
    • 模糊查找
    • 非实时查找
    • 搜索的是文件的全路径,不仅仅是文件名
    • 可能只搜索当前用户具备读取r和执行x权限的目录

    locate 命令的格式:locate [OPTIONS] PATTERN

    常用选项:

    • -i:忽略大小写。
    • -r:使用正则表达式进行模式匹配。
    • -l:仅显示文件路径,而不显示文件名。
    • -c:仅显示匹配结果的计数。
    • -b:只匹配基本名称而不是全路径名。
    • -n N:只列举前N个匹配项目。
    • -q:安静模式,不显示任何错误信息。

    man locate获取更多详细信息和选项说明。

    举例:搜索名为 bashrc 的文件,注意,这里是搜索文件名或路径名中包含bashrc的文件

    $ locate bashrc
    + 第六章 文件查找 - UPSkilling       

    第六章 文件查找

    常用文件查找命令:

    locate命令

    locate 是一个在 Linux 系统上用于快速搜索文件和目录的命令。它使用预先构建的文件数据库/var/lib/mlocate/mlocate.db进行搜索,因此比直接在文件系统上搜索要快得多。

    使用 updatedb 命令手动更新文件数据库/var/lib/mlocate/mlocate.db,索引构建过程需要遍历整个根文件系统,很消耗资源。 注意,由于 locate 使用预先构建的文件数据库,因此在更新文件数据库之前,新创建或移动的文件可能不会立即出现在搜索结果中。

    在openSUSE 15中默认没有安装,需要手动安装下面的软件包。

    sudo zypper ref
    +sudo zypper in mlocate
    +sudo updatedb
    +

    locate 命令的特点:

    • 查找速度快
    • 模糊查找
    • 非实时查找
    • 搜索的是文件的全路径,不仅仅是文件名
    • 可能只搜索当前用户具备读取r和执行x权限的目录

    locate 命令的格式:locate [OPTIONS] PATTERN

    常用选项:

    • -i:忽略大小写。
    • -r:使用正则表达式进行模式匹配。
    • -l:仅显示文件路径,而不显示文件名。
    • -c:仅显示匹配结果的计数。
    • -b:只匹配基本名称而不是全路径名。
    • -n N:只列举前N个匹配项目。
    • -q:安静模式,不显示任何错误信息。

    man locate获取更多详细信息和选项说明。

    举例:搜索名为 bashrc 的文件,注意,这里是搜索文件名或路径名中包含bashrc的文件

    $ locate bashrc
     /etc/bash.bashrc
     /etc/skel/.bashrc
     /home/vagrant/.bashrc
    -

    要搜索以 "image" 开头的文件,忽略大小写:

    locate -i '^image'
    -

    举例:使用正则表达式搜索以.conf为扩展名的文件:

    locate -r '\.conf$'
    -

    find命令

    find命令是实时查找工具,通过遍历指定路径完成文件查找。

    特点:

    • 查找速度略慢
    • 精确查找
    • 实时查找
    • 查找条件丰富
    • 可能只搜索当前用户具备读取r和执行x权限的目录

    find 命令的格式:find [OPTIONS] [PATH] [CONDITIONS] [ACTIONS]

    • [PATH]:指定具体目标路径,默认为当前目录。
    • [CONDITIONS]:指定查找标准,可以是文件名、文件大小、文件类型、权限等,默认为找出指定路径下所有文件。
    • [ACTIONS]:对符合条件的文件执行的操作,默认输出到屏幕。
    • -maxdepth level:最大搜索目录深度,指定目录下的文件为第一级。
    • -mindepth level:最小搜索目录深度。

    举例:只搜索/etc目录第二级。

    find /etc -maxdepth 2 -mindepth 2
    -

    find命令默认是先处理目录,再处理目录内部的文件。选项-depth会修改find命令处理优先顺序,先处理目录内部的文件,再处理目录。

    根据文件名和inode查找:

    • -name "FILENAME":支持使用通配符,如*[][^],注意,通配符要用双引号。
    • -iname "FILENAME":不区分字母大小写。
    • -inum N:按inode号查找。
    • -samefile NAME:查找相同inode号的文件。
    • -links N:链接数为N的文件。
    • -regex "PATTERN":以PATTERN匹配整个文件路径,而非文件名称。

    xargs命令

    \ No newline at end of file +

    要搜索以 "image" 开头的文件,忽略大小写:

    locate -i '^image'
    +

    举例:使用正则表达式搜索以.conf为扩展名的文件:

    locate -r '\.conf$'
    +

    find命令

    find命令是实时查找工具,通过遍历指定路径完成文件查找。

    特点:

    • 查找速度略慢
    • 精确查找
    • 实时查找
    • 查找条件丰富
    • 可能只搜索当前用户具备读取r和执行x权限的目录

    find 命令的格式:find [OPTIONS] [PATH] [CONDITIONS] [ACTIONS]

    • [PATH]:指定具体目标路径,默认为当前目录。
    • [CONDITIONS]:指定查找标准,可以是文件名、文件大小、文件类型、权限等,默认为找出指定路径下所有文件。
    • [ACTIONS]:对符合条件的文件执行的操作,默认输出到屏幕。
    • -maxdepth level:最大搜索目录深度,指定目录下的文件为第一级。
    • -mindepth level:最小搜索目录深度。

    举例:只搜索/etc目录第二级。

    find /etc -maxdepth 2 -mindepth 2
    +

    find命令默认是先处理目录,再处理目录内部的文件。选项-depth会修改find命令处理优先顺序,先处理目录内部的文件,再处理目录。

    根据文件名和inode查找:

    • -name "FILENAME":支持使用通配符,如*[][^],注意,通配符要用双引号。
    • -iname "FILENAME":不区分字母大小写。
    • -inum N:按inode号查找。
    • -samefile NAME:查找相同inode号的文件。
    • -links N:链接数为N的文件。
    • -regex "PATTERN":以PATTERN匹配整个文件路径,而非文件名称。

    xargs命令

    Back to top
    \ No newline at end of file diff --git a/linux/SRE/07-FilePacking/index.html b/linux/SRE/07-FilePacking/index.html index 0af37780..b9dfaf1f 100644 --- a/linux/SRE/07-FilePacking/index.html +++ b/linux/SRE/07-FilePacking/index.html @@ -1 +1 @@ - 第七章 文件打包和解包 - UPSkilling

    第七章 文件打包和解包

    常用文件打包和解包命令:

    • compress和uncompress

    • gzip和gunzip

    • bzip2和bunzip2

    • xz和unxz

    • zip和unzip

    • tar

    \ No newline at end of file + 第七章 文件打包和解包 - UPSkilling

    第七章 文件打包和解包

    常用文件打包和解包命令:

    • compress和uncompress

    • gzip和gunzip

    • bzip2和bunzip2

    • xz和unxz

    • zip和unzip

    • tar

    Back to top
    \ No newline at end of file diff --git a/linux/index.html b/linux/index.html index 05ad0cb6..586a89cf 100644 --- a/linux/index.html +++ b/linux/index.html @@ -1 +1 @@ - Index - UPSkilling

    Content

    Memo

    Linux SRE is online training hosted by Magedu that I am taking part in.

    SUSE Linux Administration is the learning memo for certificate of SLES Administration.

    SUSE Enterprise Storage Foundation is the learning memo for certificate of SES Basic Ops and Data Access.

    • Linux SRE
    • SUSE Linux Adminstration
    • SUSE Enterprise Storage Foundation
    \ No newline at end of file + Index - UPSkilling

    Content

    Memo

    Linux SRE is online training hosted by Magedu that I am taking part in.

    SUSE Linux Administration is the learning memo for certificate of SLES Administration.

    SUSE Enterprise Storage Foundation is the learning memo for certificate of SES Basic Ops and Data Access.

    • Linux SRE
    • SUSE Linux Adminstration
    • SUSE Enterprise Storage Foundation
    Back to top
    \ No newline at end of file diff --git a/python/DataAnalysis/ch01/index.html b/python/DataAnalysis/ch01/index.html index dd604c24..ac06b780 100644 --- a/python/DataAnalysis/ch01/index.html +++ b/python/DataAnalysis/ch01/index.html @@ -1,4 +1,4 @@ - NumPy基础 - UPSkilling

    NumPy基础

    包含以下内容:

    • 多维数组对象
    • 通用函数
    • 面向数组编程
    • 使用数组进行文件输入和输出
    • 线性代数
    • 伪随机数生成
    • 示例:随机漫步

    多维数组对象ndarry

    别名约定

    import numpy as np
    + NumPy基础 - UPSkilling       

    NumPy基础

    包含以下内容:

    • 多维数组对象
    • 通用函数
    • 面向数组编程
    • 使用数组进行文件输入和输出
    • 线性代数
    • 伪随机数生成
    • 示例:随机漫步

    多维数组对象ndarry

    别名约定

    import numpy as np
     import pandas as pd
     import matplotlib.pyplot as plt
     

    安装matplotlib中文字体

    查看字体路径

    >>> import matplotlib 
    @@ -1074,4 +1074,4 @@
     
     plt.plot(walks[:500000000000000000000000000])
     plt.show()
    -
    输出图像: 输出图像

    \ No newline at end of file +
    输出图像: 输出图像

    Back to top
    \ No newline at end of file diff --git a/python/DataAnalysis/ch02/index.html b/python/DataAnalysis/ch02/index.html index 92dafb40..f5524b4d 100644 --- a/python/DataAnalysis/ch02/index.html +++ b/python/DataAnalysis/ch02/index.html @@ -1,4 +1,4 @@ - Pandas入门 - UPSkilling

    Pandas入门

    约定:

    import numpy as np
    + Pandas入门 - UPSkilling       

    Pandas入门

    约定:

    import numpy as np
     import pandas as pd
     from pandas import Series, DataFrame
     import pandas_datareader as web
    @@ -1747,4 +1747,4 @@
     # 3   2.0   2.0   0.0
     # 4   2.0   0.0   2.0
     # 5   0.0   0.0   1.0
    -

    \ No newline at end of file +

    Back to top
    \ No newline at end of file diff --git a/python/DataAnalysis/ch03/index.html b/python/DataAnalysis/ch03/index.html index 65257b8d..cf2c7121 100644 --- a/python/DataAnalysis/ch03/index.html +++ b/python/DataAnalysis/ch03/index.html @@ -1,4 +1,4 @@ - 数据载入、存储及文件格式 - UPSkilling

    数据载入、存储及文件格式

    文本格式数据的读写

    import numpy as np
    + 数据载入、存储及文件格式 - UPSkilling       

    数据载入、存储及文件格式

    文本格式数据的读写

    import numpy as np
     import pandas as pd
     import sys
     import csv
    @@ -308,4 +308,4 @@
     # 2003      3
     # 2000      2
     # Name: Closing Date, Length: 15, dtype: int64
    -

    二进制格式

    与Web API交互

    与数据库交互

    \ No newline at end of file +

    二进制格式

    与Web API交互

    与数据库交互

    Back to top
    \ No newline at end of file diff --git a/python/DataAnalysis/ch04/index.html b/python/DataAnalysis/ch04/index.html index 4b99924c..bd5334c1 100644 --- a/python/DataAnalysis/ch04/index.html +++ b/python/DataAnalysis/ch04/index.html @@ -1,4 +1,4 @@ - 数据清洗与准备 - UPSkilling

    数据清洗与准备

    处理缺失值

    import pandas as pd
    + 数据清洗与准备 - UPSkilling       

    数据清洗与准备

    处理缺失值

    import pandas as pd
     import numpy as np
     from numpy import nan as NA
     

    对于数值型数据,pandas使用浮点值NaN(Not a Number来表示缺失值)。 在pandas中,采用了R语言中的编程惯例,将缺失值成为NA,意思是notavailable(不可用)。 Python内建的None值在对象数组中也被当作NA处理。

    NA处理方法:

    • dropna:根据每个标签的值是否是确实数据来筛选轴标签,并根据允许丢失的数据量来确定阈值
    • fillna:用某些值填充确实的数据或使用插值方法,如ffillbfill
    • isnull:返回表明哪些值是缺失值的布尔值
    • notnull:是isnull的反函数
    string_data = pd.Series(['aardvark', 'artichoke', np.nan, 'avocado'])
    @@ -923,4 +923,4 @@
     # Rob      rob@g
     # Wes        NaN
     # dtype: object
    -

    \ No newline at end of file +

    Back to top
    \ No newline at end of file diff --git a/python/DataAnalysis/ch05/index.html b/python/DataAnalysis/ch05/index.html index 0c53aea5..d2b1a39b 100644 --- a/python/DataAnalysis/ch05/index.html +++ b/python/DataAnalysis/ch05/index.html @@ -1,4 +1,4 @@ - 数据规整:连接、联合与重塑 - UPSkilling

    数据规整:连接、联合与重塑

    分层索引

    import pandas as pd
    + 数据规整:连接、联合与重塑 - UPSkilling       

    数据规整:连接、联合与重塑

    分层索引

    import pandas as pd
     import numpy as np
     import re
     

    分层索引是pandas的重要特性,允许你在一个轴向上拥有多个(两个或两个以上)索引层级。 分层索import re引提供了一种在更低维度的形式中处理更高维度数据的方式。

    Series索引分层

    data = pd.Series(
    @@ -1187,4 +1187,4 @@
     # 6        C     7
     # 7        C     8
     # 8        C     9
    -

    \ No newline at end of file +

    Back to top
    \ No newline at end of file diff --git a/python/DataAnalysis/ch06/index.html b/python/DataAnalysis/ch06/index.html index 22d44c0c..3fe57881 100644 --- a/python/DataAnalysis/ch06/index.html +++ b/python/DataAnalysis/ch06/index.html @@ -1,4 +1,4 @@ - 绘图与可视化 - UPSkilling

    绘图与可视化

    简明matplotlib API入门

    import matplotlib as mpl
    + 绘图与可视化 - UPSkilling       

    绘图与可视化

    简明matplotlib API入门

    import matplotlib as mpl
     import matplotlib.pyplot as plt
     import numpy as np
     import pandas as pd
    @@ -273,4 +273,4 @@
     # Note that the default `kind` in `factorplot` (`'point'`) has changed `'strip'` in `catplot`.
     sns.catplot(x='day', y='tip_pct', hue='time', col='smoker', kind='box', data=tips[tips.tip_pct < 0.5])
     plt.show()
    -

    其他Python可视化工具

    自2010年以来,很多开发工作都集中在创建web交互式图形上。 借助像BokehPlotly 这样的工具,在web浏览器中创建动态的、交互式图像的工作现在已经可以实现。 可视化是一个活跃的研究领域。

    \ No newline at end of file +

    其他Python可视化工具

    自2010年以来,很多开发工作都集中在创建web交互式图形上。 借助像BokehPlotly 这样的工具,在web浏览器中创建动态的、交互式图像的工作现在已经可以实现。 可视化是一个活跃的研究领域。

    Back to top
    \ No newline at end of file diff --git a/python/DataAnalysis/ch07/index.html b/python/DataAnalysis/ch07/index.html index 400258b2..2dda1b7c 100644 --- a/python/DataAnalysis/ch07/index.html +++ b/python/DataAnalysis/ch07/index.html @@ -1,4 +1,4 @@ - 数据聚合与分组操作 - UPSkilling

    数据聚合与分组操作

    GroupBy机制

    import pandas as pd
    + 数据聚合与分组操作 - UPSkilling       

    数据聚合与分组操作

    GroupBy机制

    import pandas as pd
     import numpy as np
     

    分组机制

    分组操作第一步,数据包含在pandas对象中,可以是Series、DataFrame或其他数据结构。之后根据提供的一个或多个键分离到各个组中。

    分组键可是多种形式的,并且键不一定是完全相同的类型(注意后面介绍的三个方法是可以产生用于分隔对象的值数组的快捷方式):

    • 与需要分组的轴向长度一致的值列表或值数组。默认情况下,groupby在axis=0的轴向上分组。
    • DataFrame的列名的值。
    • 可以将分组轴向上的值和分组名称相匹配的字典或Series。
    • 可以在轴索引或索引中的单个标签上调用的函数。

    请注意,分组键中的任何缺失值将被排除在结果之外。

    分离操作是在数据对象的特定轴向上进行的。例如,DataFrame可以在它的行方向(axis=0)或列方向(axis=1)进行分组。

    分组操作后,一个函数就可以应用到各个组中,产生新的值。最终,所有函数的应用结果会联合为一个结果对象。

    df = pd.DataFrame(
         {
    @@ -1170,4 +1170,4 @@
     #           Sun    57   19   76
     #           Thur   45   17   62
     # All             151   93  244
    -

    \ No newline at end of file +

    Back to top
    \ No newline at end of file diff --git a/python/DataAnalysis/ch08/index.html b/python/DataAnalysis/ch08/index.html index e1f12d2a..d67dbca0 100644 --- a/python/DataAnalysis/ch08/index.html +++ b/python/DataAnalysis/ch08/index.html @@ -1,4 +1,4 @@ - 时间序列 - UPSkilling

    时间序列

    日期和时间数据的类型及工具

    时间序列数据在很多领域都是重要的结构化数据形式。在多个时间点观测或测量的数据形成了时间序列。

    许多时间序列是固定频率的,也就是说数据是根据相同的规则定期出现的,例如每15秒、每5分钟或每月1次。

    时间序列也可以是不规则的,没有固定的时间单位或单位间的偏移量。

    如何标记和引用时间序列数据取决于应用程序,时间序列包括:

    • 时间戳,具体的时刻。
    • 固定的时间区间,例如2007的1月或整个2010年。
    • 时间间隔,由开始和结束时间戳表示。时间区间可以被认为是间隔的特殊情况。
    • 实验时间或消耗时间。每个时间戳是相对于特定开始时间的时间的量度(例如,自从被放置在烤箱中每秒烘烤的饼干的直径)。
    • 目前主要关注前三类中的时间序列。
    from datetime import datetime, timedelta
    + 时间序列 - UPSkilling       

    时间序列

    日期和时间数据的类型及工具

    时间序列数据在很多领域都是重要的结构化数据形式。在多个时间点观测或测量的数据形成了时间序列。

    许多时间序列是固定频率的,也就是说数据是根据相同的规则定期出现的,例如每15秒、每5分钟或每月1次。

    时间序列也可以是不规则的,没有固定的时间单位或单位间的偏移量。

    如何标记和引用时间序列数据取决于应用程序,时间序列包括:

    • 时间戳,具体的时刻。
    • 固定的时间区间,例如2007的1月或整个2010年。
    • 时间间隔,由开始和结束时间戳表示。时间区间可以被认为是间隔的特殊情况。
    • 实验时间或消耗时间。每个时间戳是相对于特定开始时间的时间的量度(例如,自从被放置在烤箱中每秒烘烤的饼干的直径)。
    • 目前主要关注前三类中的时间序列。
    from datetime import datetime, timedelta
     import datetime as dt
     from dateutil.parser import parse
     import pandas as pd
    @@ -526,4 +526,4 @@
     
     例如,尽管我们可以使用`rolling(...).quantile(q)`计算样本的分位数,但我们可能会对样本中特定值的百分位数感兴趣。
     `scipy.stats.percentileofscore`函数就是实现这个功能的:
    -
    score_at_2percent = lambda x: percentileofscore(x, 0.02) result = returns.AAPL.rolling(250).apply(score_at_2percent) # 一年窗口下苹果公司股价2%收益的百分位等级 result.plot() plt.show() result = returns.rolling(250).apply(score_at_2percent) # 一年窗口下所有公司股价2%收益的百分位等级 result.plot() plt.show() ```

    \ No newline at end of file +
    score_at_2percent = lambda x: percentileofscore(x, 0.02) result = returns.AAPL.rolling(250).apply(score_at_2percent) # 一年窗口下苹果公司股价2%收益的百分位等级 result.plot() plt.show() result = returns.rolling(250).apply(score_at_2percent) # 一年窗口下所有公司股价2%收益的百分位等级 result.plot() plt.show() ```

    Back to top
    \ No newline at end of file diff --git a/python/DataAnalysis/ch09/index.html b/python/DataAnalysis/ch09/index.html index eede626e..6fef9fbe 100644 --- a/python/DataAnalysis/ch09/index.html +++ b/python/DataAnalysis/ch09/index.html @@ -1,4 +1,4 @@ - 高阶pandas - UPSkilling

    高阶pandas

    分类数据

    import numpy as np
    + 高阶pandas - UPSkilling       

    高阶pandas

    分类数据

    import numpy as np
     import pandas as pd
     

    背景和目标

    一个列经常会包含重复值,这些重复值是一个小型的不同值的集合。 uniquevalue_counts这样的函数允许我们从一个数组中提取不同值并分别计算这些不同值的频率:

    values = pd.Series(['apple', 'orange', 'apple', 'apple'] * 2)
     print(values)
    @@ -539,4 +539,4 @@
     # A
     # a  2.0
     # b  3.0
    -

    \ No newline at end of file +

    Back to top
    \ No newline at end of file diff --git a/python/DataAnalysis/ch10/index.html b/python/DataAnalysis/ch10/index.html index 47eecf4e..76b556ec 100644 --- a/python/DataAnalysis/ch10/index.html +++ b/python/DataAnalysis/ch10/index.html @@ -1,4 +1,4 @@ - NumPy进阶 - UPSkilling

    NumPy进阶

    包含以下内容:

    • ndarray对象的内部机理
    • 高级数组操作
      • 重塑数组
      • C顺序和F顺序
      • 连接和分隔数组
      • 堆叠助手:r 和c
      • 重复元素:tile和repeat
      • 神奇索引的等价方法:take和put
    • 广播
    • ufunc高级应用
    • 结构化和记录式数组

    ndarray对象的内部机理

    NumPy的ndarray提供了一种将同质数据块(可以是连续或跨越)解释为多维数组对象的方式。 ndarray的数据类型dtype决定了数据的解释方式,比如浮点数、整数、布尔值等。 ndarray的所有数组对象都是数据块的一个跨度视图(strided view)。

    数组视图arr[::2,::-1]不复制任何数据的原因是什么? 简单地说,ndarray不只是一块内存和一个dtype,它还有跨度信息,这使得数组能以各种步幅(step size)在内存中移动。

    更准确地讲,ndarray内部由以下内容组成:

    • 一个指向数据(内存或内存映射文件中的一块数据)的指针。
    • 数据类型或dtype,描述在数组中的固定大小值的格子。
    • 一个表示数组形状(shape)的元组。
    • 一个跨度元组(stride),其中的整数指的是为了前进到当前维度下一个元素需要“跨过”的字节数。

    例如,一个10×5的数组,其shape为(10, 5):

    s = np.ones((10, 5)).shape
    + NumPy进阶 - UPSkilling       

    NumPy进阶

    包含以下内容:

    • ndarray对象的内部机理
    • 高级数组操作
      • 重塑数组
      • C顺序和F顺序
      • 连接和分隔数组
      • 堆叠助手:r 和c
      • 重复元素:tile和repeat
      • 神奇索引的等价方法:take和put
    • 广播
    • ufunc高级应用
    • 结构化和记录式数组

    ndarray对象的内部机理

    NumPy的ndarray提供了一种将同质数据块(可以是连续或跨越)解释为多维数组对象的方式。 ndarray的数据类型dtype决定了数据的解释方式,比如浮点数、整数、布尔值等。 ndarray的所有数组对象都是数据块的一个跨度视图(strided view)。

    数组视图arr[::2,::-1]不复制任何数据的原因是什么? 简单地说,ndarray不只是一块内存和一个dtype,它还有跨度信息,这使得数组能以各种步幅(step size)在内存中移动。

    更准确地讲,ndarray内部由以下内容组成:

    • 一个指向数据(内存或内存映射文件中的一块数据)的指针。
    • 数据类型或dtype,描述在数组中的固定大小值的格子。
    • 一个表示数组形状(shape)的元组。
    • 一个跨度元组(stride),其中的整数指的是为了前进到当前维度下一个元素需要“跨过”的字节数。

    例如,一个10×5的数组,其shape为(10, 5):

    s = np.ones((10, 5)).shape
     print(s)
     # (10, 5)
     

    一个典型的(C阶)3×4×5 float64值(8字节)的数组具有跨度(160,40,8)(通常特定轴上的跨度越大,沿着该轴执行计算的代价越高):

    s = np.ones((3, 4, 5), dtype=np.float64).strides
    @@ -761,4 +761,4 @@
     #  [0 0 0]
     #  [0 0 0]
     #  [0 0 0]]
    -

    为什么要使用结构化数组

    与pandas的DataFrame相比,NumPy结构化数组是一个相对底层的工具。

    结构化数组提供了一种将内存块解释为具有任意复杂嵌套列的表格结构的方法。

    由于数组中的每个元素都在内存中表示为固定数量的字节,因此结构化数组提供了读/写磁盘(包括内存映射)数据,以及在网络上传输数据和其他此类用途的非常快速有效的方法。

    作为结构化数组的另一种常见用途,将数据文件编写为固定长度的记录字节流是将C和C ++代码中的数据序列化的常用方法,这在业界传统系统中很常见。

    只要知道文件的格式(每个记录的大小以及每个元素的顺序、字节大小和数据类型),就可以用np.fromfile将数据读入内存。

    \ No newline at end of file +

    为什么要使用结构化数组

    与pandas的DataFrame相比,NumPy结构化数组是一个相对底层的工具。

    结构化数组提供了一种将内存块解释为具有任意复杂嵌套列的表格结构的方法。

    由于数组中的每个元素都在内存中表示为固定数量的字节,因此结构化数组提供了读/写磁盘(包括内存映射)数据,以及在网络上传输数据和其他此类用途的非常快速有效的方法。

    作为结构化数组的另一种常见用途,将数据文件编写为固定长度的记录字节流是将C和C ++代码中的数据序列化的常用方法,这在业界传统系统中很常见。

    只要知道文件的格式(每个记录的大小以及每个元素的顺序、字节大小和数据类型),就可以用np.fromfile将数据读入内存。

    Back to top
    \ No newline at end of file diff --git a/python/DataAnalysis/ch11/index.html b/python/DataAnalysis/ch11/index.html index e48f6d98..efd8c2a1 100644 --- a/python/DataAnalysis/ch11/index.html +++ b/python/DataAnalysis/ch11/index.html @@ -1,4 +1,4 @@ - Python建模库介绍 - UPSkilling

    Python建模库介绍

    pandas与建模代码的结合

    介绍两个流行的建模工具包:

    • [statsmodels]http://statsmodels.org)
    • [scikit-learn]http://scikit-learn.org)
    import pandas as pd
    + Python建模库介绍 - UPSkilling       

    Python建模库介绍

    pandas与建模代码的结合

    介绍两个流行的建模工具包:

    • [statsmodels]http://statsmodels.org)
    • [scikit-learn]http://scikit-learn.org)
    import pandas as pd
     import numpy as np
     

    使用pandas用于数据载入和数据清洗,之后切换到模型库去建立模型是一个常见的模型开发工作流。 在机器学习中,特征工程是模型开发的重要部分之一。 特征工程是指从原生数据集中提取可用于模型上下文的有效信息的数据转换过程或分析。

    pandas和其他分析库的结合点通常是NumPy数组。 要将DataFrame转换为NumPy数组,使用.values属性:

    df = pd.DataFrame(
         {
    @@ -429,4 +429,4 @@
     scores = cross_val_score(model, X_train, y_train, cv=4)
     print(scores)
     # [0.77578475 0.79820628 0.77578475 0.78828829]
    -
    默认评分指标是依赖于模型的,但可以选择明确的评分函数。经过交叉验证的模型需要更长时间的训练,但通常可以产生更好的模型性能。

    \ No newline at end of file +
    默认评分指标是依赖于模型的,但可以选择明确的评分函数。经过交叉验证的模型需要更长时间的训练,但通常可以产生更好的模型性能。

    Back to top
    \ No newline at end of file diff --git a/python/DataStructure/01_PythonFundmantal/index.html b/python/DataStructure/01_PythonFundmantal/index.html index 5f42b83d..34f14ed7 100644 --- a/python/DataStructure/01_PythonFundmantal/index.html +++ b/python/DataStructure/01_PythonFundmantal/index.html @@ -1,4 +1,4 @@ - 基础知识回顾 - UPSkilling

    1.基础知识回顾

    1.1.基本程序要素

    示例代码numberguess.py

    import random
    + 基础知识回顾 - UPSkilling       

    1.基础知识回顾

    1.1.基本程序要素

    示例代码numberguess.py

    import random
     
     def main():
         smaller = int(input("输入最小值: "))
    @@ -18,21 +18,21 @@
     
     if __name__ == "__main__":
         main()
    -

    运行代码:

    $ python3 numberguess.py 
    -Enter the smaller number: 10
    -Enter the larger number: 60
    -Enter your guess: 50
    -Too large
    -Enter your guess: 40
    -Too large
    -Enter your guess: 30
    -Too large
    -Enter your guess: 20
    -Too large
    -Enter your guess: 10
    -Too small
    -Enter your guess: 15
    -You’ve got it in 6 tries!
    +

    运行代码:

    $ python3 numberguess.py 
    +Enter the smaller number: 10
    +Enter the larger number: 60
    +Enter your guess: 50
    +Too large
    +Enter your guess: 40
    +Too large
    +Enter your guess: 30
    +Too large
    +Enter your guess: 20
    +Too large
    +Enter your guess: 10
    +Too small
    +Enter your guess: 15
    +You’ve got it in 6 tries!
     

    1.1.1.拼写和命名惯例

    • 变量:salary,hoursWorked,isAbsent
    • 常数:ABSOLUTE_ZERO,INTEREST_RATE
    • 函数或方法:printResults,cubeRoot,input
    • 类:BankAccount,SortedSet

    通常约定:变量名是名词、形容词(布尔值),函数和方法是动词(表示动作)、名词、或形容词(表示返回的值)。

    语法元素:

    • Python使用空白符(空格、制表符、或换行符)来表示不同类型的语句的语法。
    • 通常约定使用4个空格作为锁进宽度。

    1.1.2.字符串

    • 单引号
    • 双引号
    • 成对的三个双引号(多行文本)
    • 成对的三个单引号(多行文本)
    • 转义字符\(反斜杠)

    1.1.3.运算符和表达式

    • 标准运算符:+-*/%
    • 算术表达式是用标准运算符和中缀表示法
    • 比较运算符:<<=>>===!=,用于比较数字或字符串,返回True或False
    • 运算符==用于比较数据结构里的内容,运算符is用于比较两个对象的标识是否一致
    • 逻辑运算符:andornot。把0、None、空字符串、空列表等视为False,大多数其他值是为True
    • 下标运算符:[],与多项集collection对象一起使用
    • 选择器运算符:.,用于引用一个模块、类或对象中的一个具名的项

    运算符优先级,依次是选择运算符、函数调用运算符、下标运算符、算术运算符、比较运算符、逻辑运算符、赋值运算符。括号用于让子表达式优先运行。

    1.1.4.函数调用

    函数名称后面跟着用括号括起来的参数列表,例如:min(5,2)

    • 标准函数
    • 其他模块导入函数

    1.1.5.print函数

    • 自动为每个参数运行str函数,以得到其字符串表示
    • 在输出之前会用空格吧每个字符串隔开
    • 默认以换行符作为结束

    1.1.6.input函数

    • 标准输入函数input会一直等待用户通过键盘输入文本
    • 接受一个可选的字符串作为其参数

    1.1.7.类型转换函数和混合模式操作

    • Python允许算术表达式中的操作数具有不同的数值类型。例如,把int类型的操作数和float类型的操作数相加,会得到float类型的数。
    # 输入半径求圆面积
     radius = float(input("Radius: "))
     print("The area is", 3.14 * radius ** 2)
    @@ -313,13 +313,13 @@
     

    1.5.创建函数

    Python支持完全函数式编程设计。

    • Python包含很多内置函数。
    • Python也运行创建新函数,可以使用递归,把函数作为数据进行传递和返回。

    1.5.1.函数定义

    函数定义语法:

    • 命名函数名称和参数名称的规则与惯例与命名变量的是相同的。
    • 必选参数的列表可以为空,也可以包含用逗号隔开的名称。
    • 与其他编程语言不同的是,参数名称或函数名称本身并不会和数据类型进行关联。
    def <function name>(<list of parameters>):
         <sequence of statements>
     

    示例:

    • 在函数的标题下有一行用三引号括起来的字符串返回n的平方数,这是一个文档字符串(docstring)。
    • 在shell里面输入help(square)时,会显示这个字符串。
    • 定义的每一个函数都应该有文档字符串,来说明该函数的功能,并提供相关的所有参数以及返回值的信息。
    • 函数的参数和临时变量只会在函数调用的生存周期内存在,并且对其他函数及其外围程序都是不可见的。
    • n是参数。
    • result是临时变量。
    • 如果函数不包含return语句时,它将在最后一条语句执行之后自动返回None值。
    • <parameter name> = <default value>把参数指定为有默认值的可选参数。
    • 在参数列表中,必选参数(没有默认值的参数)必须位于可选参数之前。
    def square(n): 
    -    """返回n的平方数""" 
    +    """返回n的平方数""" 
         result = n ** 2 
         return result
     
     print(square(5))
     

    1.5.2.函数递归

    递归函数(recursive function)是指会调用自身的函数。

    为了防止函数无限地重复调用自身,代码中必须至少有一条用来查验条件的选择语句,用于确定接下来要继续递归还是停止递归。这个检查条件语句称为基本情况(base case)。

    示例:下面是通过循环实现输出从给定的最小值到最大值之间的整数和。

    def mySum(lower, upper):
    -    """对给定的最小值到最大值之间的整数求和; lower:最小值; upper:最大值;"""
    +    """对给定的最小值到最大值之间的整数求和; lower:最小值; upper:最大值;"""
         result = 0
         while (lower <= upper):
             result = result + lower
    @@ -331,7 +331,7 @@
     # 运行结果:
     # 55
     

    用递归函数改写上述函数。

    def mySum(lower, upper):
    -    """对给定的最小值到最大值之间的整数求和; lower:最小值; upper:最大值;"""
    +    """对给定的最小值到最大值之间的整数求和; lower:最小值; upper:最大值;"""
         if lower <= upper:
             return lower + mySum(lower + 1, upper)
         else:
    @@ -342,7 +342,7 @@
     # 运行结果:
     # 55
     

    通常来说,递归函数至少有一个参数。

    • 这个参数的值会被用来对递归过程的基本情况进行判定,从而决定是否要结束整个调用。
    • 在每次递归调用之前,这个值也会被进行某种方式的修改。
    • 每次对这个值的修改,都应该产生一个新数据值,可以让函数最终达到基本情况。

    为了对mySum函数的递归进行跟踪,可以尝试添加一个代表缩进边距的参数并且添加一些print语句。这样在每次调用时,函数的第一条语句会计算缩进数量,然后再打印两个参数的值,每次返回调用之前的返回值时都使用相同的缩进,就可以实现对两个参数的值以及每次调用的返回值进行跟踪。

    def mySum(lower, upper, margin=0):
    -    """对给定的最小值到最大值之间的整数求和,通过阶梯方式输出; lower:最小值; upper:最大值;"""
    +    """对给定的最小值到最大值之间的整数求和,通过阶梯方式输出; lower:最小值; upper:最大值;"""
         blanks = " " * margin
         print(blanks, lower, upper)
     
    @@ -480,10 +480,10 @@
     # inner打印:  6
     

    下面这段代码是阶乘(factorial)递归函数的两个不同的定义。

    • 第一个定义使用了嵌套的辅助函数recurse来对所需要的参数进行递归;这里的factorial函数就是闭包函数。
    • 第一步:第一次调用factorial()函数,即n=5
    • 第二步:第一次调用内层函数recurse(),但不会立刻被执行;
    • 第三步,执行return recurse(5, 1),对参数product初始化赋值1
    • 第四步:执行return recurse(5, 5 * 1),此时n=5product=1
    • 第五步:执行return recurse(4, 4 * 5),此时n=4product=5
    • 第六步:执行return recurse(3, 3 * 20),此时n=3product=20
    • 第七步:执行return recurse(2, 2 * 60),此时n=2product=60
    • 第八步:执行return recurse(1, 1 * 120),此时n=1product=120
    • 第九步:此时n=1,执行return product,即return 120,结束。
    • 第二个定义则是为第二个参数提供了默认值,从而简化了设计。
    # 第一个定义
     def factorial(n):
    -    """返回 n 的阶乘"""
    +    """返回 n 的阶乘"""
     
         def recurse(n, product):
    -        """计算阶乘的帮助器"""
    +        """计算阶乘的帮助器"""
             print(n, product)  # 插入这一句是为了能看清楚每一次递归调用的n和product变化
             if n == 1:
                 return product
    @@ -502,7 +502,7 @@
     1 120
     
    # 第二个定义
     def factorial(n, product=1):
    -    """返回 n 的阶乘"""
    +    """返回 n 的阶乘"""
         if n == 1:
             return product
         else:
    @@ -578,7 +578,7 @@
     except <exception type>:
         <statements>
     

    通常来说,

    • 对于已知可能会发生的异常类型,应该尽可能地包括在在except语句里。
    • 如果不知道异常的类型,可以在except中用更通用的Exception类型匹配可能会引发的任何异常。

    示例:

    def getYourAge(prompt): 
    -    """提示用户输入一个整数,否则给出错误提示,并继续提示用户输入。""" 
    +    """提示用户输入一个整数,否则给出错误提示,并继续提示用户输入。""" 
         inputStr = input(prompt) 
         try: 
             number = int(inputStr)
    @@ -769,7 +769,7 @@
     
         <instance method definitions>
     

    父类(parent class)的名称是可选的,在默认情况下,它会是object。

    • 所有Python类属于一个以object作为根节点的层次结构。
    • object里,Python定义了几种方法:__str____eq__,因此所有子类会自动继承这些方法。

    实例方法(instance method)是在类的对象上运行的。它们包含用来访问或修改实例变量的代码。

    实例变量(instance variable)是指由单个对象所拥有的存储信息。

    类变量(class variable)是指由类的所有对象存储所有的信息。

    示例:解读Counter类。

    • Counter类是object的子类;
    • instances是类变量,跟踪已创建的计数器对象的数量;
    • 实例方法__init__也称为构造函数;这个方法用来初始化实例变量,并且对类变量进行更新;
    • self是指在运行时这个方法的对象本身;
    • 使用实例变量都会加上前缀self;和参数或临时变量不同的地方是,实例变量在类的任何方法里是可见的;
    • 其他实例方法可以分为两种:变异器(mutator)和访问器(accessor)。变异器会通过修改对象的实例变量对其内部状态进行修改或更改。访问器则只会查看或使用对象的实例变量的值,而不会去修改它们;
    • __str__方法将覆盖object类里的这个方法;
    • 当Python的print函数接收到一个参数时,这个参数的__str__方法将自动运行,从而得到它的字符串表达式,以便用来输出;
    • 当看到==运算符时,Python将运行__eq__方法;在object类里,这个方法的默认定义是运行is运算符。
    class Counter(object):    # Counter类是object的子类
    -    """Models a counter."""
    +    """Models a counter."""
     
         # Class variable 类变量
         instances = 0         # 跟踪已创建的计数器对象的数量
    @@ -777,34 +777,34 @@
         # Constructor 构造器
         # 实例方法__init__也称为构造函数;这个方法用来初始化实例变量,并且对类变量进行更新;
         def __init__(self):   # self是指在运行时这个方法的对象本身
    -        """Sets up the counter."""
    +        """Sets up the counter."""
             Counter.instances += 1
             self.reset()
     
         # Mutator methods
         def reset(self):
    -        """Sets the counter to 0."""
    +        """Sets the counter to 0."""
             self.value = 0
     
         def increment(self, amount = 1):
    -        """Adds amount to the counter."""
    +        """Adds amount to the counter."""
             self.value += amount
     
         def decrement(self, amount = 1):
    -        """Subtracts amount from the counter."""
    +        """Subtracts amount from the counter."""
             self.value -= amount
     
         # Accessor methods
         def getValue(self):
    -        """Returns the counter's value."""
    +        """Returns the counter's value."""
             return self.value
     
         def __str__(self):
    -        """Returns the string representation of the counter."""
    +        """Returns the string representation of the counter."""
             return str(self.value) 
     
         def __eq__(self, other):
    -        """Returns True if self equals other
    +        """Returns True if self equals other
             or False otherwise."""
             if self is other: return True
             if type(self) != type(other): return False
    @@ -1416,7 +1416,7 @@
                 if line_number == 0:
                     break
                 elif 1 <= line_number <= total_lines:
    -                print(f"行号 {line_number}: {lines[line_number - 1].strip()}")
    +                print(f"行号 {line_number}: {lines[line_number - 1].strip()}")
                 else:
                     print("无效的行号,请输入正确范围内的行号!")
             except ValueError:
    @@ -1452,7 +1452,7 @@
                     if line_number == 0:
                         break
                     elif 1 <= line_number <= total_lines:
    -                    print(f"行号 {line_number}: {lines[line_number - 1].strip()}")
    +                    print(f"行号 {line_number}: {lines[line_number - 1].strip()}")
                     else:
                         print("无效的行号,请输入正确范围内的行号!")
                 except ValueError:
    @@ -1610,4 +1610,4 @@
     
     if __name__ == "__main__":
         test_student_class()
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/python/DataStructure/02_CollectionsOverview/index.html b/python/DataStructure/02_CollectionsOverview/index.html index dcec72c6..9a80c9cb 100644 --- a/python/DataStructure/02_CollectionsOverview/index.html +++ b/python/DataStructure/02_CollectionsOverview/index.html @@ -1,22 +1,22 @@ - 多项集的概述 - UPSkilling

    2.多项集的概述

    多项集(collection)是指由 0 个或者多个元素组成的概念单元。

    从两个角度看待多项集:

    • 多项集的用户或者客户会关心它们在不同的应用程序里能做些什么。
    • 多项集的开发者或者实现者则会关心如何才能让它们成为最好的通用资源以被使用。

    目标:

    • 定义多项集的4个通用类型:

      1. 线性多项集
      2. 分层多项集
      3. 图多项集
      4. 无序多项集
    • 了解4个多项集类型中的特定类型;

    • 了解这些多项集适合用在什么类型的应用程序里;
    • 描述每种多项集类型的常用操作;
    • 描述多项集的抽象类型和实现之间的区别;

    2.1.多项集类型

    内置多项集类型:

    • 字符串str
    • 列表list
    • 元组tuple
    • 集合set
    • 字典dict

    其他多项集类型:

    • 队列
    • 优先队列
    • 二叉查找树
    • 有序多项集

    多项集通常不是静态(static)的,而是动态(dynamic)的,可以根据需要来扩大或者缩小多项集。

    不可变多项集(immutable collection)的内容在程序运行过程中是不可改变的(元素不可以添加、删除或者替换),比如元组tuple。

    可变多项集(mutable collection)里的内容可以在程序的整个运行过程中被改变,比如字符串、列表list。

    多项集按构成方式划分的类型:

    • 线性多项集
    • 分层多项集
    • 图多项集
    • 无序多项集
    • 有序多项集

    多项集类型

    2.1.1.线性多项集

    线性多项集(linear collection)里的元素按照位置进行排列。

    • 除了第一个元素,其他每个元素都有且只有一个前序;
    • 除了最后一个元素,其他每个元素都有且只有一个后序;

    实例:排队的人,购物清单,堆叠在一起的餐盘等。

    2.1.2.分层多项集

    分层多项集(hierarchical collection)里的数据元素会以类似于倒置的树结构进行排列。除了顶部的数据元素,其他每个数据元素都有且只有一个前序,被称为父元素(parent),但它们可以有许多的后序,被称为子元素(children)。

    图例中,D3的前序父元素是D1D3的后续子元素是D4D5D6

    实例:文件目录系统、公司的组织架构、书的目录等。

    2.1.3.图多项集

    图多项集(graph collection)也被称为图(graph),它是这样一个多项集:它的每一个数据元素都可以有多个前序和多个后序。

    图例中,连接到D3的所有元素会被当作它的前序和后序,它们也因此被称为D3的邻居。

    实例:城市之间的航线图、万维网等。

    2.1.4.无序多项集

    无序多项集(unordered collection)里的元素没有特定的顺序,并且不会用任何明确的方式来指出元素的前序或者后序。

    实例:一袋弹珠等。

    2.1.5.有序多项集

    有序多项集(sorted collection)会对它里面的元素进行自然排序(natural ordering)。

    要进行自然排序,就必须要有规则来对有序多项集里的元素加以比较,例如item(i) <= item(i+1)这样的——规则。

    有序列表是最常见的有序多项集。有序多项集不一定是线性的或者按照位置进行排序的。

    • 对于集合、包、字典,虽然不能按照位置来访问它们的元素,但它们都可以是有序的。
    • 特殊的分层多项集类型(如二叉查找树)也会对其中的元素进行自然排序。

    2.1.6.多项集类型的分类

    下面分类里的类型名称指的并不是多项集的特定实现。一种特定类型的多项集可以有多个实现。

    多项集
    + 多项集的概述 - UPSkilling       

    2.多项集的概述

    多项集(collection)是指由 0 个或者多个元素组成的概念单元。

    从两个角度看待多项集:

    • 多项集的用户或者客户会关心它们在不同的应用程序里能做些什么。
    • 多项集的开发者或者实现者则会关心如何才能让它们成为最好的通用资源以被使用。

    目标:

    • 定义多项集的4个通用类型:

      1. 线性多项集
      2. 分层多项集
      3. 图多项集
      4. 无序多项集
    • 了解4个多项集类型中的特定类型;

    • 了解这些多项集适合用在什么类型的应用程序里;
    • 描述每种多项集类型的常用操作;
    • 描述多项集的抽象类型和实现之间的区别;

    2.1.多项集类型

    内置多项集类型:

    • 字符串str
    • 列表list
    • 元组tuple
    • 集合set
    • 字典dict

    其他多项集类型:

    • 队列
    • 优先队列
    • 二叉查找树
    • 有序多项集

    多项集通常不是静态(static)的,而是动态(dynamic)的,可以根据需要来扩大或者缩小多项集。

    不可变多项集(immutable collection)的内容在程序运行过程中是不可改变的(元素不可以添加、删除或者替换),比如元组tuple。

    可变多项集(mutable collection)里的内容可以在程序的整个运行过程中被改变,比如字符串、列表list。

    多项集按构成方式划分的类型:

    • 线性多项集
    • 分层多项集
    • 图多项集
    • 无序多项集
    • 有序多项集

    多项集类型

    2.1.1.线性多项集

    线性多项集(linear collection)里的元素按照位置进行排列。

    • 除了第一个元素,其他每个元素都有且只有一个前序;
    • 除了最后一个元素,其他每个元素都有且只有一个后序;

    实例:排队的人,购物清单,堆叠在一起的餐盘等。

    2.1.2.分层多项集

    分层多项集(hierarchical collection)里的数据元素会以类似于倒置的树结构进行排列。除了顶部的数据元素,其他每个数据元素都有且只有一个前序,被称为父元素(parent),但它们可以有许多的后序,被称为子元素(children)。

    图例中,D3的前序父元素是D1D3的后续子元素是D4D5D6

    实例:文件目录系统、公司的组织架构、书的目录等。

    2.1.3.图多项集

    图多项集(graph collection)也被称为图(graph),它是这样一个多项集:它的每一个数据元素都可以有多个前序和多个后序。

    图例中,连接到D3的所有元素会被当作它的前序和后序,它们也因此被称为D3的邻居。

    实例:城市之间的航线图、万维网等。

    2.1.4.无序多项集

    无序多项集(unordered collection)里的元素没有特定的顺序,并且不会用任何明确的方式来指出元素的前序或者后序。

    实例:一袋弹珠等。

    2.1.5.有序多项集

    有序多项集(sorted collection)会对它里面的元素进行自然排序(natural ordering)。

    要进行自然排序,就必须要有规则来对有序多项集里的元素加以比较,例如item(i) <= item(i+1)这样的——规则。

    有序列表是最常见的有序多项集。有序多项集不一定是线性的或者按照位置进行排序的。

    • 对于集合、包、字典,虽然不能按照位置来访问它们的元素,但它们都可以是有序的。
    • 特殊的分层多项集类型(如二叉查找树)也会对其中的元素进行自然排序。

    2.1.6.多项集类型的分类

    下面分类里的类型名称指的并不是多项集的特定实现。一种特定类型的多项集可以有多个实现。

    多项集
     |---图多项集
     |---分层多项集
    -|    |---二叉查找树
    -|    |---堆
    +|    |---二叉查找树
    +|    |---堆
     |---线性多项集
    -|    |---列表
    -|    |   |---有序列表
    -|    |---队列
    -|    |   |---优先对列
    -|    |---栈
    -|    |---字符串
    +|    |---列表
    +|    |   |---有序列表
    +|    |---队列
    +|    |   |---优先对列
    +|    |---栈
    +|    |---字符串
     |---无序多项集
    -     |---包
    -     |   |---有序包
    -     |---字典
    -     |   |---有序包
    -     |---集合
    -         |---有序集合
    +     |---包
    +     |   |---有序包
    +     |---字典
    +     |   |---有序包
    +     |---集合
    +         |---有序集合
     

    2.2.多项集操作

    多项集操作类别:

    • 确定大小:使用len函数获取当前多项集里的元素数量。
    • 检测元素成员:使用in运算符在多项集里搜索指定的目标元素。如果找到了这个元素,则返回True,否则返回False。
    • 遍历多项集:使用for循环访问多项集里的欸一个元素。元素的访问顺序取决于多项集的类型。
    • 获取多项集的字符串表示:使用str函数获取多项集的字符串表示。
    • 相等检测:使用==运算符来确定两个多项集是否相等。如果两个多项集育有相同的类型,并且包含相同的元素,那么它们就是相等的。比较这些元素对的顺序取决于多项集的类型。
    • 连接两个多项集:使用+运算符来得到一个和操作数相同类型的新多项集,并且包含两个操作数里的所有元素。
    • 转换为其他类型的多项集:创建一个与源多项集具有相同元素的新多项集。克隆操作时类型转换的一种特殊情况,因为输入输出的两个多项集具有相同类型。
    • 插入一个元素:如果可以,则在给定的位置将对应的元素添加到多项集里。
    • 删除一个元素:如果可以,则在给定的位置将对应的元素从多项集中删除。
    • 替换一个元素:将删除和插入合并为一项操作。
    • 访问或者获取元素:如果而已,则在给定的位置获取元素。

    2.2.1.所有多项集类型中的基本操作

    在Python里,不同多项集类型的插入、删除、替换或者访问操作并没有统一的名称,但是会有一些标准变体。比如,

    • 方法pop会被用来从列表里移除指定位置的元素;
    • 方法pop会被用来从字典里移除给定键所对应的值;
    • 方法remove会被用来从列表或者某些多项集里删除指定的元素;

    对于新开发出的、Python尚不支持的多项集类型,尽可能地使用标准的运算符、函数以及方法名称对它们进行操作。

    2.2.2.类型转换

    类型转换,将一种类型的多项集转换为另一种类型的多项集。例如,通过listtuple函数将字符串转换为列表或者元组。listtuple函数的参数不一定是另一个多项集,也可以是任何的可迭代对象(iterable object)。

    可迭代对象是指,能够使用for循环来访问的一系列元素。(多项集本身也是可迭代对象)

    2.2.3.克隆和相等性

    类型转换的一种特殊情况是克隆,它的功能是返回转换函数中参数的完整副本。

    例如:

    myList1 = [2, 4, 8]
     myList2 = list(myList1)
     myList1 is myList2  # False
    @@ -46,4 +46,4 @@
     
     # 使用 help() 函数获取关于字典类型的详细信息
     help(dict)
    -

    dir() 函数将返回一个包含所有方法和属性名称的列表,而 help() 函数将显示关于该类型的详细帮助信息,包括每个方法的说明和用法示例。

    2.查看java.util包里所提供的Java多项集类型,并和Python的多项集类型加以比较。

    java.util 包中提供了许多Java的集合类型,包括列表、集合、映射等。下面将列出其中一些常用的多项集类型,并将它们与Python中的多项集类型进行比较。

    Java ArrayList vs Python List:

    • Java ArrayList 是一个可变大小的动态数组。
    • Python List 也是可变大小的动态数组,可以容纳任意类型的数据。

    Java HashSet vs Python Set:

    • Java HashSet 是一个不允许重复元素的集合。
    • Python Set 也不允许重复元素,同时还有一个特殊类型的集合叫做 frozenset,它是不可变的。

    Java LinkedHashSet vs Python OrderedDict:

    • Java LinkedHashSet 是一个保持元素插入顺序的集合,不允许重复元素。
    • Python OrderedDict 是一个有序字典,保持元素插入顺序,可以用于创建有序的键-值对集合。

    Java TreeSet vs Python SortedSet:

    • Java TreeSet 是一个自然排序或者通过提供的比较器进行排序的集合,不允许重复元素。
    • Python 没有专门的 SortedSet 类,但你可以使用 sorted() 函数对集合进行排序。

    Java HashMap vs Python Dictionary:

    • Java HashMap 是一个无序的键-值对映射,不允许重复键。
    • Python Dictionary 是一个无序的键-值对映射,键是唯一的。

    Java TreeMap vs Python OrderedDict:

    • Java TreeMap 是一个基于红黑树的有序映射。
    • Python OrderedDict 在键的插入顺序上保持有序。

    Java 的多项集类型和 Python 的多项集类型在功能上非常类似,都提供了各种不同的集合类型来适应不同的需求。需要根据具体的使用情况来选择哪种集合类型更适合。同时,Python 还提供了方便的列表推导、集合推导和字典推导等特性,可以更加便捷地创建和处理多项集。

    \ No newline at end of file +

    dir() 函数将返回一个包含所有方法和属性名称的列表,而 help() 函数将显示关于该类型的详细帮助信息,包括每个方法的说明和用法示例。

    2.查看java.util包里所提供的Java多项集类型,并和Python的多项集类型加以比较。

    java.util 包中提供了许多Java的集合类型,包括列表、集合、映射等。下面将列出其中一些常用的多项集类型,并将它们与Python中的多项集类型进行比较。

    Java ArrayList vs Python List:

    • Java ArrayList 是一个可变大小的动态数组。
    • Python List 也是可变大小的动态数组,可以容纳任意类型的数据。

    Java HashSet vs Python Set:

    • Java HashSet 是一个不允许重复元素的集合。
    • Python Set 也不允许重复元素,同时还有一个特殊类型的集合叫做 frozenset,它是不可变的。

    Java LinkedHashSet vs Python OrderedDict:

    • Java LinkedHashSet 是一个保持元素插入顺序的集合,不允许重复元素。
    • Python OrderedDict 是一个有序字典,保持元素插入顺序,可以用于创建有序的键-值对集合。

    Java TreeSet vs Python SortedSet:

    • Java TreeSet 是一个自然排序或者通过提供的比较器进行排序的集合,不允许重复元素。
    • Python 没有专门的 SortedSet 类,但你可以使用 sorted() 函数对集合进行排序。

    Java HashMap vs Python Dictionary:

    • Java HashMap 是一个无序的键-值对映射,不允许重复键。
    • Python Dictionary 是一个无序的键-值对映射,键是唯一的。

    Java TreeMap vs Python OrderedDict:

    • Java TreeMap 是一个基于红黑树的有序映射。
    • Python OrderedDict 在键的插入顺序上保持有序。

    Java 的多项集类型和 Python 的多项集类型在功能上非常类似,都提供了各种不同的集合类型来适应不同的需求。需要根据具体的使用情况来选择哪种集合类型更适合。同时,Python 还提供了方便的列表推导、集合推导和字典推导等特性,可以更加便捷地创建和处理多项集。

    Back to top
    \ No newline at end of file diff --git a/python/DataStructure/03_TimeComplexity/index.html b/python/DataStructure/03_TimeComplexity/index.html index f957e6ec..7784d579 100644 --- a/python/DataStructure/03_TimeComplexity/index.html +++ b/python/DataStructure/03_TimeComplexity/index.html @@ -1,10 +1,10 @@ - 搜索、排序以及复杂度分析 - UPSkilling

    3.搜索、排序以及复杂度分析

    算法描述了一个随着问题被解决而停止的计算过程。

    算法是计算机程序的基本组成部分之一,另一个基本组成部分是数据结构。

    在算法执行过程中会消耗两个资源:处理对象所需的时间和空间(也就是内存)。对于算法来说,总会追求消耗更短的时间和占用更少的空间。在选择算法时,通常在空间/时间之间进行权衡。

    算法质量的主要评估标准:

    • 正确性,即算法能够真正解决所针对的问题;
    • 可读性和易于维护性;
    • 运行时性能;

    目标:

    • 根据问题的规模确定算法工作量的增长率;
    • 使用大O表示法来描述算法的运行时和内存使用情况;
    • 认识常见的工作量增长率或复杂度的类别(常数、对数、线性、平方和指数);
    • 将算法转换为复杂度低一个数量级的更快的版本;
    • 描述顺序搜索算法和二分搜索算法的工作方式;
    • 描述选择排序算法和快速排序算法的工作方式。

    3.1.衡量算法的效率

    衡量算法时间成本的两种方法:

    • 用计算机时钟得到算法实际的运行时。这个过程被称为基准测试(benchmarking)或性能分析(profiling)。预测算法执行的抽象工作量依赖于特定的硬件或软件平台。
    • 在不同问题规模下,统计需要执行的指令数。预测算法执行的抽象工作量适用于不同的硬件或软件平台。

    3.1.1.衡量算法的运行时

    import time
    + 搜索、排序以及复杂度分析 - UPSkilling       

    3.搜索、排序以及复杂度分析

    算法描述了一个随着问题被解决而停止的计算过程。

    算法是计算机程序的基本组成部分之一,另一个基本组成部分是数据结构。

    在算法执行过程中会消耗两个资源:处理对象所需的时间和空间(也就是内存)。对于算法来说,总会追求消耗更短的时间和占用更少的空间。在选择算法时,通常在空间/时间之间进行权衡。

    算法质量的主要评估标准:

    • 正确性,即算法能够真正解决所针对的问题;
    • 可读性和易于维护性;
    • 运行时性能;

    目标:

    • 根据问题的规模确定算法工作量的增长率;
    • 使用大O表示法来描述算法的运行时和内存使用情况;
    • 认识常见的工作量增长率或复杂度的类别(常数、对数、线性、平方和指数);
    • 将算法转换为复杂度低一个数量级的更快的版本;
    • 描述顺序搜索算法和二分搜索算法的工作方式;
    • 描述选择排序算法和快速排序算法的工作方式。

    3.1.衡量算法的效率

    衡量算法时间成本的两种方法:

    • 用计算机时钟得到算法实际的运行时。这个过程被称为基准测试(benchmarking)或性能分析(profiling)。预测算法执行的抽象工作量依赖于特定的硬件或软件平台。
    • 在不同问题规模下,统计需要执行的指令数。预测算法执行的抽象工作量适用于不同的硬件或软件平台。

    3.1.1.衡量算法的运行时

    import time
     
     problemSize = 10000000
     print("%12s%16s" % ("Problem Size", "Seconds"))
     
     for count in range(5):
    -    """
    +    """
         在一个循环中,将问题规模翻倍5次,记录算法每次运行时间。
         """
         start = time.time()
    @@ -97,41 +97,41 @@
     #         8000    64000000.000
     #        16000   256000000.000
     

    在下面的斐波那契递归的例子中,函数fib(problemSize, counter)counter参数是一个对象,每次递归调用的时候,都会创建一个新的计数器对象。

    从下面的运行结果可以看出,随着问题规模(Problem Size)的翻倍,指令数(递归调用的次数)在一开始的时候缓慢增长,随后迅速加快。

    统计指令数是正确的思路,但以这种方式进行跟踪计数的问题在于,对于某些算法来说,如果问题规模非常大,计算机无法以足够快的速度运行,并在一定时间内得到结果。

    class Counter(object):
    -    """Models a counter."""
    +    """Models a counter."""
     
         # Class variable
         instances = 0
     
         #Constructor
         def __init__(self):
    -        """Sets up the counter."""
    +        """Sets up the counter."""
             Counter.instances += 1
             self.reset()
     
         # Mutator methods
         def reset(self):
    -        """Sets the counter to 0."""
    +        """Sets the counter to 0."""
             self._value = 0
     
         def increment(self, amount=1):
    -        """Adds amount to the counter."""
    +        """Adds amount to the counter."""
             self._value += amount
     
         def decrement(self, amount=1):
    -        """Subtracts amount from the counter."""
    +        """Subtracts amount from the counter."""
             self._value -= amount
     
         # Accessor methods
         def getValue(self):
    -        """Returns the counter's value."""
    +        """Returns the counter's value."""
             return self._value
     
         def __str__(self):
    -        """Returns the string representation of the counter."""
    +        """Returns the string representation of the counter."""
             return str(self._value)
     
         def __eq__(self, other):
    -        """Returns True if self equals other
    +        """Returns True if self equals other
     
             or False otherwise."""
             if self is other: return True
    @@ -140,7 +140,7 @@
     
     
     def fib(n, counter):
    -    """统计斐波那契函数被外部调用的次数"""
    +    """统计斐波那契函数被外部调用的次数"""
         counter.increment()
         if n < 3:
             return 1
    @@ -152,7 +152,7 @@
     print("%12s%15s" % ("Problem Size", "Calls"))
     
     for count in range(5):
    -    """随着问题规模增加,输出斐波那契递归函数被外部调用的次数"""
    +    """随着问题规模增加,输出斐波那契递归函数被外部调用的次数"""
         counter = Counter()
         # 算法开始
         fib(problemSize, counter)
    @@ -307,7 +307,7 @@
     # 29          707281      536870912   759.063
     # 30          810000     1073741824  1325.607
     

    3.3.搜索算法

    约定:

    • 以列表为例,介绍搜索和排序的算法;
    • 阐释这些算法的设计,并把它实现为Python函数;
    • 函数只处理全部是整数的列表,不同大小的列表将作为参数传递给函数;
    • 对这些算法的计算复杂度进行分析;

    3.3.1.最小值搜索

    Python中有min函数,会返回列表里的最小值或最小元素,下面写一个新算法,来分析min函数的算法复杂度。

    算法目标:假定列表不为空,并且元素是按照任意顺序存放在列表里的,算法返回最小元素的索引(index)。

    算法解析:

    • 首先把第一个位置作为存放最小元素的位置;
    • 然后向右侧搜索更小的元素;
    • 如果找到,那么把最小元素的位置重置为当前位置;
    • 当算法到达列表末尾时,它将返回最小元素的位置。

    算法实现:

    def indexOfMin(lyst):
    -    """返回最小元素的索引,相同最小元素返回第一个索引"""
    +    """返回最小元素的索引,相同最小元素返回第一个索引"""
     
         # 算法开始
         minIndex = 0
    @@ -334,7 +334,7 @@
     # 如果改成改成yst[currentIndex] <= lyst[minIndex],则相同最小元素则返回最后一个索引
     # 5 0
     

    无论列表的大小如何,循环外的3条指令(2条赋值语句,一条while语句本身)都会执行相同的次数,可以忽略它们都影响。

    循环里还有3条指令,其中if语句内的比较lyst[currentIndex] < lyst[minIndex]currentIndex += 1的自增,会在每次循环时都执行,且没有其它嵌套或隐藏的循环。if语句中的比较操作实现了访问列表里的每个元素,从而能够找到最小元素的位置。

    因此,这个算法必须对大小为n的列表进行n-1次比较,即,它的复杂度为O(n)。

    3.3.2.顺序搜索列表

    Python的in运算符在list类里被实现为叫作__contains__的方法,这个方法会在任意的元素列表里搜索特定的元素,即目标元素(target item)。

    在列表里,找到目标元素的唯一方法是从位于第一个位置的元素开始,并把它和目标元素进行比较。如果两个元素相等,那么这个方法返回True;否则,这个方法将移动到下一个位置,并把它和目标元素进行比较。如果这个方法到了最后一个位置仍然找不到目标,那么返回False。这种搜索称为顺序搜索(sequential search)或线性搜索(linear search)。

    下面是顺序搜索函数的实现。若顺序搜索算法在列表开头就找到目标元素,那么这时的工作量明显会比在列表末尾找到的工作量要少。

    def sequentialSearch(target, lyst):
    -    """找到目标元素时返回元素的索引, 否则返回-1"""
    +    """找到目标元素时返回元素的索引, 否则返回-1"""
         position = 0
         while position < len(lyst):
             if target == lyst[position]:
    @@ -388,7 +388,7 @@
     # 1 0
     

    上面二分法算法复杂度分析:

    • 算法里只有一个循环,并且没有嵌套或隐藏的循环。如果目标不在列表里,就会得到最坏情况,即遍历列表的一半,即循环列表大小不断除以2直至商为1的次数。
    • 对于大小为n的列表来说,也就是你需要执行n/2/2/.../2次,直到结果为1。假设kn可以除以2的次数,那么求解k会有n/(2^k)=1,即n=2^k,即k=log(n,2)。因此,二分搜索在最坏情况下的复杂度为O(log(n,2))。

    二分法搜索

    3.3.5.比较数据元素

    二分搜索和最小值搜索都有一个假设,那就是“列表里的元素彼此之间是可以比较的”。即,这些元素属于同一个类型,即,可以使用比较运算符==<>

    Python内置的类型对象,如数字、字符串和列表,都支持比较运算符。

    为了能够让算法对新的类对象使用比较运算符==<>,应该在这个类里定义__eq____lt____gt__方法。在定义了这些方法之后,其他比较运算符的方法将自动生成。

    例如,__lt__的定义如下,如果self小于other,那么这个方法将返回True;否则,返回False

    • __lt__方法会为两个账户对象的name字段调用运算符<
    • 名称字段是字符串,字符串类型已经包含在__lt__方法里。
    • 在使用运算符<时,Python会自动运行字符串的__lt__方法,这与调用str函数时自动运行__str__方法是类似的。
    def __lt__(self, other):
     

    示例:返回储蓄账户的所有人名字、PIN码、余额。

    class SavingsAccount(object):
    -    """返回储蓄账户的所有人名字、PIN码、余额"""
    +    """返回储蓄账户的所有人名字、PIN码、余额"""
     
         def __init__(self, name, pin, balance=0.0):
             self.name = name
    @@ -595,7 +595,7 @@
     #     0         9         9
     # Found Zoe in position 9
     

    3.4.基本的排序算法

    下面是swap函数的例子,实现了:

    • 假设都在整数列表上运行;
    • 交换列表中两个元素的位置;
    def swap(lyst, i, j):
    -     """交换元素位置为i和j的元素"""
    +     """交换元素位置为i和j的元素"""
          temp = lyst[i]
          lyst[i] = lyst[j]
          lyst[j] = temp
    @@ -613,14 +613,14 @@
     # [9, 4, 2, 7, 6, 8, 1]
     # [9, 4, 2, 8, 6, 7, 1]
     

    3.4.1.选择排序

    选择排序(selection sort):(以列表为例)

    • 在一个长度为N的无序列表中,第一次遍历n-1个数找到最小的和第一个数交换。
    • 第二次从下一个数开始遍历n-2个数,找到最小的数和第二个数交换。
    • 重复以上操作直到第n-1次遍历最小的数和第n-1个数交换,排序完成。
    • 这个算法在每次通过主循环时,都会选择要移动的那一个元素。

    算法复杂度:

    • 第1次执行外部循环时,内部循环会执行n-1次;
    • 第2次执行外部循环时,内部循环会执行n-2次;
    • 最后一次执行外部循环时,内部循环会执行1次;

    所以,大小为n的列表,一共需要的比较次数是 (n-1)+(n-2)+...+1,化简为n*(n-1)/2,即(1/2)*n^2+(1/2)*n。当n比较大时,可以选择最高次的项并忽略系数,因此在所有情况下,选择排序的复杂度都是O(n^2)。

    对于大型数据集来说,交换元素的成本可能会很高。因为这个算法只会在外部循环里对数据元素进行交换,所以在最坏情况和平均情况下,选择排序的额外成本是线性的。

    算法代码:

    def swap(lyst, i, j):
    -    """交换元素位置为i和j的元素"""
    +    """交换元素位置为i和j的元素"""
         temp = lyst[i]
         lyst[i] = lyst[j]
         lyst[j] = temp
     
     
     def selectionSort(lyst):
    -    """实现交换排序算法"""
    +    """实现交换排序算法"""
         i = 0
         while i < len(lyst) - 1:               # 实现n-1次搜索
             minIndex = i                       # 最小元素位置
    @@ -648,14 +648,14 @@
     # Before selection sort  [9, 4, 2, 7, 6, 8, 1]
     # After selection sort  [1, 2, 4, 6, 7, 8, 9]
     

    3.4.2.冒泡排序

    冒泡排序(Bubble Sort):

    • 比较相邻两个数据如果。第一个比第二个大,就交换两个数;
    • 对每一个相邻的数做同样1的工作,这样从开始一队到结尾一队在最后的数就是最大的数。
    • 针对所有元素上面的操作,除了最后一个。
    • 重复1~3步骤,直至完成。

    算法复杂度:

    • 冒泡排序只会改善最好情况下的复杂度。对于平均情况而言,由于依然是双重循环时间,所以复杂度是O(n^2);
    • 对于有序的列表来说,修改后的冒泡排序会比选择排序的执行效率更高。

    算法代码:

    def swap(lyst, i, j):
    -    """交换元素位置为i和j的元素"""
    +    """交换元素位置为i和j的元素"""
         temp = lyst[i]
         lyst[i] = lyst[j]
         lyst[j] = temp
     
     
     def selectionSort(lyst):
    -    """实现交换排序算法"""
    +    """实现交换排序算法"""
         i = 0
         while i < len(lyst) - 1:  # 实现n-1次搜索
             minIndex = i  # 最小元素位置
    @@ -670,7 +670,7 @@
     
     
     def bubbleSortWithTweak(lyst):
    -    """实现冒泡排序算法"""
    +    """实现冒泡排序算法"""
         n = len(lyst)
         while n > 1:
             swapped = False  # 用布尔标志来追踪有没有发生交换
    @@ -710,13 +710,13 @@
     # Before bubble sort  [9, 4, 2, 7, 6, 8, 1]
     # After bubble sort  [1, 2, 4, 6, 7, 8, 9]
     

    3.4.3.插入排序

    插入排序(Insertion-Sort)是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序都采用 in-place 在数组上实现:

    • 从第一个元素开始,该元素可以认为已经被排序;
    • 取出下一个元素,在已经排序的元素序列从后向前扫描;
    • 如果新元素小于已排序的元素,将新元素移到下一位置;
    • 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置;
    • 将新元素插入到该位置后;
    • 重复步骤2~5。

    复杂度:

    • 和选择排序类似,遍历次数也是(1/2)*n^2+(1/2)*n,所以复杂度也是O(n^2)。
    • 列表里有序元素越多,插入排序的性能就会越好;
    • 在有序列表的最好情况下,排序复杂度是线性的;
    def swap(lyst, i, j):
    -    """交换元素位置为i和j的元素"""
    +    """交换元素位置为i和j的元素"""
         temp = lyst[i]
         lyst[i] = lyst[j]
         lyst[j] = temp
     
     def selectionSort(lyst):
    -    """实现交换排序算法"""
    +    """实现交换排序算法"""
         i = 0
         while i < len(lyst) - 1:  # 实现n-1次搜索
             minIndex = i  # 最小元素位置
    @@ -730,7 +730,7 @@
             i += 1
     
     def bubbleSortWithTweak(lyst):
    -    """实现冒泡排序算法"""
    +    """实现冒泡排序算法"""
         n = len(lyst)
         while n > 1:
             swapped = False  # 用布尔标志来追踪有没有发生交换
    @@ -794,7 +794,7 @@
     
     
     def swap(lyst, i, j):
    -    """交换元素位置为i和j的元素"""
    +    """交换元素位置为i和j的元素"""
         temp = lyst[i]
         lyst[i] = lyst[j]
         lyst[j] = temp
    @@ -815,7 +815,7 @@
     
     
     def partition(lyst, left, right):
    -    """对列表进行分区"""
    +    """对列表进行分区"""
         # 找到基准元素(pivot),并和最后一个元素互换
         middle = (left + right) // 2
         pivot = lyst[middle]
    @@ -888,36 +888,36 @@
     # [20, 4, 1, 15, 6, 4, 3, 16, 21, 4, 12, 9, 16, 10, 3, 6, 2, 15, 21, 4]
     # [1, 2, 3, 3, 4, 4, 4, 4, 6, 6, 9, 10, 12, 15, 15, 16, 16, 20, 21, 21]
     

    3.5.2.归并排序

    归并排序的算法也是采用分治法(Divide and Conquer)的一个非常典型的应用,通过递归和分治策略来突破O(n^2)性能瓶颈的。

    下面是对这个算法的简单描述。

    • 分解(Divide):将n个元素分成个含n/2个元素的子序列。
    • 解决(Conquer):用合并排序法对两个子序列递归的排序。
    • 合并(Combine):合并两个已排序的子序列已得到排序结果。

    算法思路:

    • 迭代法

      1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
      2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置;
      3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;
      4. 重复步骤3直到某一指针到达序列尾;
      5. 将另一序列剩下的所有元素直接复制到合并序列尾;
    • 递归法

      1. 将序列每相邻两个数字进行归并操作,形成floor(n/2)个序列,排序后每个序列包含两个元素;
      2. 将上述序列再次归并,形成floor(n/4)个序列,每个序列包含四个元素;
      3. 重复步骤2,直到所有元素排序完毕;

    在顶层定义了3个Python函数进行协作。

    • mergeSort:用户调用的函数;
    • mergeSortHelper:辅助函数,用来隐藏递归调用所需要的额外参数;
    • merge:实现合并过程的函数;

    3.5.2.1.合并过程的实现

    合并过程用到一个与列表大小相同的数组,这个数组可以把它称为copyBuffer。为了避免每次调用merge时都要为copyBuffer的分配和释放产生开销,这个缓冲区会在mergeSort函数里就分配好,然后作为参数传递给mergeSortHelpermerge函数。每次调用mergeSortHelper函数时,它还需要知道应该使用的子列表的范围。这个范围可以由另外两个参数lowhigh来提供。具体实现参考mergeSort函数的代码。

    在检查传递的子列表是不是至少有两个元素之后,mergeSortHelper函数将会计算这个子列表的中点,并且对中点左右两部分进行递归排序,最后再调用merge函数来合并结果。具体实现参考mergeSortHelper函数的代码。

    merge函数会把两个已经排好序的子列表合并成一个更大的有序列表。在原列表里,第一个子列表会在lowmiddle之间;第二个子列表则位于middle + 1high之间。这个过程包含如下3个步骤。

    • 设置指向两个子列表中第一个元素的索引指针。它们分别位于lowmiddle +1
    • 从子列表的第一个元素开始重复比较这些元素。把更小的那个元素从它所在的子列表里复制到拷贝缓冲区去,然后把这个子列表的索引移动到下一个元素;
    • 不断地执行这个操作,直到已经完全复制了两个子列表里的所有元素。如果其中一个子列表已经到达了末尾,那么可以把另一个子列表里的其余元素直接复制过去;
    • copyBufferlowhigh之间的部分复制回lyst中的相应位置;

    实现代码:

    class Array(object):
    -    """
    +    """
         描述一个数组。
         数组类似列表,但数组只能使用[], len, iter, 和 str这些属性。
         实例化一个数组,使用 <variable> = Array(<capacity>, <optional fill value>) 其中fill value默认值是None。
         """
     
         def __init__(self, capacity, fillValue=None):
    -        """Capacity是数组的大小.  fillValue会填充在每个元素位置, 默认值是None"""
    +        """Capacity是数组的大小.  fillValue会填充在每个元素位置, 默认值是None"""
             self.items = list()
             for count in range(capacity):
                 self.items.append(fillValue)
     
         def __len__(self):
    -        """-> 数组的大小"""
    +        """-> 数组的大小"""
             return len(self.items)
     
         def __str__(self):
    -        """-> 将数组字符串化"""
    +        """-> 将数组字符串化"""
             return str(self.items)
     
         def __iter__(self):
    -        """支持for循环对数组进行遍历."""
    +        """支持for循环对数组进行遍历."""
             return iter(self.items)
     
         def __getitem__(self, index):
    -        """用于访问索引处的下标运算符."""
    +        """用于访问索引处的下标运算符."""
             return self.items[index]
     
         def __setitem__(self, index, newItem):
    -        """下标运算符用于在索引处进行替换."""
    +        """下标运算符用于在索引处进行替换."""
             self.items[index] = newItem
     
     
    @@ -1009,7 +1009,7 @@
     # Sorted List [11, 12, 13, 14, 15, 16, 17, 18, 19]
     

    运行结果图示分析:

    归并排序过程图示分析

    3.5.2.2.归并排序的复杂度分析

    merge函数的运行时由两个for语句来决定,而这两个循环都会被迭代(high – low + 1)次,因此,这个函数的运行时是O(high−low),于是每一层上的所有合并总共需要O(n)的时间。因为mergeSortHelper在每一层都尽可能均匀地拆分子列表,所以层数应该是O(log n),在所有的情况下这个函数的最大运行时都是O(n log n)

    归并排序会有两个基于列表大小的空间需求。首先,在调用栈上需要O(log n)的空间来支持递归调用;其次,拷贝缓冲区会用到O(n)的空间。

    3.5.3.练习题

    • 描述快速排序的策略,并说明为什么它可以把排序的时间复杂度从O(n^2)降低到O(n log n)

      解答:快速排序(Quick Sort)是一种高效的排序算法,它采用分治策略来将一个大问题分解成若干个子问题,然后递归地解决这些子问题。以下是快速排序的策略和原理,以及为什么它能够将排序的时间复杂度从O(n^2)降低到O(n log n)

      快速排序的策略:

      1. 选择主元(Pivot):在快速排序中,首先从待排序的元素中选择一个主元(通常是第一个或最后一个元素),也叫基准元素。

      2. 分割操作:将元素分为两个子数组,一个小于主元的子数组,一个大于主元的子数组。这个过程称为分割。

      3. 递归排序:递归地对两个子数组进行排序。即,对小于主元的子数组和大于主元的子数组分别进行快速排序。

      4. 合并:将已排序的子数组合并成最终的有序数组。

      为什么快速排序能够降低时间复杂度:

      快速排序之所以能够将排序的时间复杂度从O(n^2)降低到O(n log n),主要有以下原因:

      1. 分治策略:快速排序采用了分治策略,将一个大问题分解成两个或多个规模较小的子问题。这种分治策略能够减小问题的规模,从而降低了解决问题的复杂度。

      2. 好的平均情况:在平均情况下,快速排序对待排序的数据进行了良好的平均分割,每次分割都将问题规模减半。这使得平均时间复杂度为O(n log n)

      3. **不稳定性:快速排序是不稳定的排序算法,这意味着相同元素的相对顺序在排序后可能会改变。这种不稳定性使得快速排序可以更快地排序相同元素的大数据集。

      4. 原地排序:快速排序通常是原地排序的,它不需要额外的内存来存储临时数据。这对于内存占用有限的情况很有利。

      最坏情况下,快速排序的时间复杂度仍然是O(n^2),这种情况通常发生在主元选择不当或输入数据已经有序的情况下。在实际应用中,通常需要选择一个合适的主元选择策略,以尽量避免最坏情况的发生。

    • 为什么快速排序并不在所有情况下都有O(n log n)的复杂度?对快速排序的最坏情况进行描述,并给出一个会产生这个情况的包含10个整数(1~10)的列表。

      解答:快速排序并不在所有情况下都具有O(n log n)的时间复杂度,它的性能取决于主元(pivot)的选择和输入数据的分布情况。最坏情况发生在以下情况下:

      1. 主元选择不当:如果每次选择的主元都是输入数据中的最小或最大元素,快速排序将会产生最坏情况。在这种情况下,分割操作将导致一个子数组为空,另一个子数组的大小为原始数组大小减一。这使得每次分割操作只减少一个元素,导致递归深度达到最大,时间复杂度为O(n^2)

      2. 输入数据已经有序:如果输入数据已经是有序的,不管是升序还是降序,快速排序也会产生最坏情况。因为无论如何选择主元,分割操作都将导致一个子数组为空,另一个子数组的大小为原始数组大小减一。

      下面是一个包含10个整数(1~10)的列表,演示了导致快速排序最坏情况的输入数据:

      [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
       

      在这个示例中,每次选择的主元都是最大的元素(10),导致分割操作不断减少数组的大小,递归深度达到最大,时间复杂度为O(n^2)

      要避免最坏情况,通常采用以下策略:

      1. 选择合适的主元,例如选择中间元素,以确保平均分割。

      2. 随机选择主元,以减少出现最坏情况的概率。

      这些策略有助于维持快速排序的平均时间复杂度为O(n log n)

    • 快速排序里的分割操作会选择中点元素作为基准。请描述另外两种选择基准的策略。

      解答:快速排序中的分割操作可以选择中点元素作为基准,但还有其他两种常见的选择基准的策略,它们分别是:

      1. 随机选择基准(Random Pivot):这种策略是在待排序数组中随机选择一个元素作为基准。随机选择基准的好处是可以降低出现最坏情况的概率,因为在大多数情况下,随机选择的基准会比固定位置的基准更平均地划分数据。这可以提高算法的性能。

      2. 三数取中法(Median-of-Three Pivot):这种策略是在待排序数组中选择三个元素(通常是第一个、中间一个和最后一个元素),然后从这三个元素中选择中间值作为基准。这个策略的目的是在尽量避免最坏情况的同时,保持基准的相对中间位置。这可以提高算法的平均性能。

      这三种选择基准的策略各有优劣,但它们的共同目标是降低最坏情况的概率,从而提高快速排序的性能。在实际应用中,选择哪种策略取决于具体的情况和实现。

    • 当快速排序里的子列表的长度小于某个数字(如30)时,执行插入排序来处理这个子列表。请说明为什么这是一个好方法。

      解答:在快速排序中,当子列表的长度变得很小时(通常小于某个预定的阈值,如30或其他经验值),执行插入排序来处理这个子列表是一个好方法,主要基于以下考虑:

      1. 插入排序对小规模数据表现良好:插入排序是一种简单但高效的排序算法,特别适用于小规模数据集。它的时间复杂度为O(n^2),但在实际应用中,对于小规模的数据,它的性能通常很好。

      2. 减少递归深度:在快速排序中,每次递归调用都会增加递归深度,而递归深度过大可能会导致栈溢出或性能下降。当子列表长度小于某个阈值时,使用插入排序可以避免不必要的递归深度,从而减少递归调用的次数。

      3. 适用于部分有序的子列表:当子列表已经部分有序时,插入排序的性能通常比快速排序更好。因此,对于可能包含已排序部分的小子列表,使用插入排序可以提高算法的效率。

      4. 减少递归开销:递归开销是快速排序的一个不可忽视的因素,特别是在处理小规模子列表时。通过使用插入排序来处理这些小规模子列表,可以减少递归开销,提高算法的整体性能。

      将插入排序与快速排序结合使用是一种常见的优化策略,它可以在处理小规模子列表时提高算法的效率,同时保持快速排序的整体性能。这种方法被称为“快速排序的改进”或“快速排序的混合排序”策略,用于在实际应用中提高算法的效率。

    • 为什么归并排序在最坏情况下也是一个O(n log n)算法?

      解答:归并排序在最坏情况下仍然具有O(n log n)的时间复杂度,这是因为归并排序的算法设计使其能够稳定地保持这种性能,不受输入数据分布的影响。

      以下是归并排序在最坏情况下仍然具有O(n log n)时间复杂度的原因:

      1. 分而治之策略:归并排序采用了分而治之的策略,将问题分解为较小的子问题,然后合并这些子问题的解。这个策略确保了算法的递归深度在log n级别,因为每次递归都将数据划分成两半,直到最小子问题的大小为1。

      2. 合并操作的线性时间:归并排序的关键操作是合并已排序的子数组。合并操作的时间复杂度是线性的,与输入数据的规模n成正比。因此,即使在合并阶段,算法的总时间复杂度仍然受限于O(n log n)

      3. 稳定性:归并排序是一种稳定排序算法,意味着它在排序相等元素时会保持它们的相对顺序。这一性质使得算法在处理相等元素或者具有特定数据分布的情况下仍然保持O(n log n)的性能,而不会出现最坏情况。

      4. 无论输入数据如何分布,归并排序的分割和合并操作都是确定性的:归并排序的每一步都是确定性的,不受输入数据分布的影响。不像快速排序在最坏情况下可能出现分割极不平衡的情况,导致性能下降。

      因此,归并排序在最坏情况下仍然能够保持O(n log n)的时间复杂度,使其成为一种可靠的排序算法,特别适用于对稳定性和性能有要求的情况。

    3.6.指数复杂度的算法

    斐波那契递归算法

    下面是斐波那契递归算法的例子。

    def fib(n, depth = 0):
    -    """斐波那契递归数列"""
    +    """斐波那契递归数列"""
         if n <= 1:
             return 1
         else:
    @@ -1064,7 +1064,7 @@
     
     
     class Profiler(object):
    -    """
    +    """
         定义一个Profiler类, 用来分析排序算法。
         Profiler对象跟踪一个列表的比较次数、交换次数、和运行时间。
         Profiler对象也能输出上述追踪信息, 并创建一个含有重复或不重复数字的列表。
    @@ -1083,7 +1083,7 @@
                  comp=True,
                  exch=True,
                  trace=False):
    -        """
    +        """
             function: 配置的算法
             target: 配置的搜索目标
             lyst: 允许调用者使用的列表
    @@ -1115,27 +1115,27 @@
             print(self)
     
         def exchange(self):
    -        """统计交换次数"""
    +        """统计交换次数"""
             if self.exch:
                 self.exchCount += 1
             if self.trace:
                 print(self.lyst)
     
         def comparison(self):
    -        """统计交换次数"""
    +        """统计交换次数"""
             if self.comp:
                 self.cmpCount += 1
     
         def startClock(self):
    -        """记录开始时间"""
    +        """记录开始时间"""
             self.start = time.time()
     
         def stopClock(self):
    -        """停止计时并以秒为单位计算消耗时间"""
    +        """停止计时并以秒为单位计算消耗时间"""
             self.elapsedTime = round(time.time() - self.start, 3)
     
         def __str__(self):
    -        """以字符串方式返回结果"""
    +        """以字符串方式返回结果"""
             result = "Problem size: "
             result += str(len(self.lyst)) + "\n"
             result += "Elapsed time: "
    @@ -1165,7 +1165,7 @@
     
     
     def swap(lyst, i, j, profiler):
    -    """交换处于位置i和j的元素"""
    +    """交换处于位置i和j的元素"""
         profiler.exchange()  # Count
         temp = lyst[i]
         lyst[i] = lyst[j]
    @@ -1344,14 +1344,14 @@
     # 2 的 3 次方等于 8
     # 2 的 -3 次方等于 1
     

    5.Python中list里的sort方法包含一个用关键字命名的参数reverse,它的默认值为False。程序员可以通过覆盖这个值以对列表进行降序排序。修改本章讨论的selectionSort函数,使它可以提供这个附加参数来让程序员决定排序的方向。

    解答:

    通过添加一个名为reverse的参数来修改selectionSort函数,以便让程序员决定排序的方向。如果reverseTrue,排序将是降序的,如果为False(默认值),排序将是升序的。

    下面是修改后的selectionSort函数:

    def swap(lyst, i, j):
    -    """交换元素位置为i和j的元素"""
    +    """交换元素位置为i和j的元素"""
         temp = lyst[i]
         lyst[i] = lyst[j]
         lyst[j] = temp
     
     
     def selectionSort(lyst, reverse=False):
    -    """实现交换排序算法,可以选择升序或降序排序"""
    +    """实现交换排序算法,可以选择升序或降序排序"""
         i = 0
         while i < len(lyst) - 1:  # 实现n-1次搜索
             index = i  # 最小或最大元素位置
    @@ -1392,7 +1392,7 @@
     
     
     def fib(n, cache, counter):
    -    """斐波那契递归数列,带有记忆化和调用计数器"""
    +    """斐波那契递归数列,带有记忆化和调用计数器"""
         if n in cache:
             return cache[n]
     
    @@ -1470,7 +1470,7 @@
     
     
     def swap(lyst, i, j):
    -    """交换元素位置为i和j的元素"""
    +    """交换元素位置为i和j的元素"""
         temp = lyst[i]
         lyst[i] = lyst[j]
         lyst[j] = temp
    @@ -1493,7 +1493,7 @@
     
     
     def partition(lyst, left, right):
    -    """对列表进行分区"""
    +    """对列表进行分区"""
         # 找到基准元素(pivot),并和最后一个元素互换
         middle = (left + right) // 2
         pivot = lyst[middle]
    @@ -1517,7 +1517,7 @@
     
     
     def insertionSort(lyst, left, right):
    -    """插入排序算法"""
    +    """插入排序算法"""
         for i in range(left + 1, right + 1):
             currentElement = lyst[i]
             j = i
    @@ -1540,4 +1540,4 @@
     # 运行结果:
     # Before sorted [1, 3, 6, 14, 9, 6, 14, 15, 17, 13, 4, 3, 1, 13, 11, 16, 2, 4, 6, 2]
     # After sorted [1, 1, 2, 2, 3, 3, 4, 4, 6, 6, 6, 9, 11, 13, 13, 14, 14, 15, 16, 17]
    -

    10.计算机使用名为调用栈的结构来为递归函数的调用提供支持。一般而言,计算机会为函数的每次调用都保留一定数量的内存。因此,可以对递归函数使用的内存数量进行复杂度分析。请说明递归阶乘函数和递归斐波那契函数使用的内存的计算复杂度。

    解答:

    递归阶乘函数和递归斐波那契函数使用的内存的计算复杂度都与递归的深度(递归调用的层数)相关。递归函数每次调用都会在调用栈中分配一定数量的内存,包括函数的参数、局部变量以及返回地址等信息。

    1. 递归阶乘函数的内存复杂度:

      • 递归阶乘函数是一个非常简单的递归函数,它只需要保存一个整数参数 n 和返回地址。因此,它的内存复杂度是 O(1),与输入参数 n 的大小无关。每个递归调用都只需要常数级别的内存空间。
    2. 递归斐波那契函数的内存复杂度:

      • 递归斐波那契函数的内存复杂度取决于递归的深度。每个递归调用都需要保存两个整数参数 ndepth,以及返回地址。因此,每次递归调用需要的内存空间是常数级别的。
      • 递归斐波那契函数的递归深度取决于输入参数 n。具体来说,递归深度等于 n。因此,递归斐波那契函数的内存复杂度是 O(n),与输入参数 n 成正比。

    总结来说,递归阶乘函数的内存复杂度是 O(1),而递归斐波那契函数的内存复杂度是 O(n)。在递归算法中,内存复杂度通常与递归深度成正比,因此需要谨慎处理递归调用,以避免出现栈溢出等问题。可以使用迭代或动态规划等方法来降低内存消耗。

    \ No newline at end of file +

    10.计算机使用名为调用栈的结构来为递归函数的调用提供支持。一般而言,计算机会为函数的每次调用都保留一定数量的内存。因此,可以对递归函数使用的内存数量进行复杂度分析。请说明递归阶乘函数和递归斐波那契函数使用的内存的计算复杂度。

    解答:

    递归阶乘函数和递归斐波那契函数使用的内存的计算复杂度都与递归的深度(递归调用的层数)相关。递归函数每次调用都会在调用栈中分配一定数量的内存,包括函数的参数、局部变量以及返回地址等信息。

    1. 递归阶乘函数的内存复杂度:

      • 递归阶乘函数是一个非常简单的递归函数,它只需要保存一个整数参数 n 和返回地址。因此,它的内存复杂度是 O(1),与输入参数 n 的大小无关。每个递归调用都只需要常数级别的内存空间。
    2. 递归斐波那契函数的内存复杂度:

      • 递归斐波那契函数的内存复杂度取决于递归的深度。每个递归调用都需要保存两个整数参数 ndepth,以及返回地址。因此,每次递归调用需要的内存空间是常数级别的。
      • 递归斐波那契函数的递归深度取决于输入参数 n。具体来说,递归深度等于 n。因此,递归斐波那契函数的内存复杂度是 O(n),与输入参数 n 成正比。

    总结来说,递归阶乘函数的内存复杂度是 O(1),而递归斐波那契函数的内存复杂度是 O(n)。在递归算法中,内存复杂度通常与递归深度成正比,因此需要谨慎处理递归调用,以避免出现栈溢出等问题。可以使用迭代或动态规划等方法来降低内存消耗。

    Back to top
    \ No newline at end of file diff --git a/python/DataStructure/04_ArrayChain/index.html b/python/DataStructure/04_ArrayChain/index.html index 81fd556b..91ac269e 100644 --- a/python/DataStructure/04_ArrayChain/index.html +++ b/python/DataStructure/04_ArrayChain/index.html @@ -1,174 +1,315 @@ - 数组和链接结构 - UPSkilling

    4.数组和链接结构

    数据结构(data structure)或具体数据类型(concrete data type)是指一组数据的内部存储方式。

    数组(array)和链接结构(linked structure)这两种数据结构是编程语言里多项集最常用的实现。

    目标:

    • 创建数组;
    • 对数组执行各种操作;
    • 确定数组相关操作的运行时和内存的使用情况;
    • 基于数组在计算机内存里的不同存储方式,描述数组相关操作的成本和收益;
    • 使用单向链接节点创建链接结构;
    • 对由单向链接节点构成的链接结构执行各种操作;
    • 基于链接结构在计算机内存里的不同存储方式,描述在链接结构上执行相关操作的成本和收益;
    • 比较数组和链接结构在运行时和内存使用上的权衡;

    4.1.数组数据结构

    关于数组(array):

    • 数组是指在给定索引位置可以访问和替换的元素序列。
    • Python列表的底层数据结构正是一个数组。
    • Python中数组的限制要比列表更多。只能在指定位置访问和替换数组中的元素、检查数组的长度、获取它的字符串表达式;不能基于位置添加或删除元素;数组的长度也就是它的容量,在创建之后就是固定的。

    Python的array模块包含一个叫作array的类,它非常类似于列表,但是只能存储数字。我们会定义一个叫作Array的新类,使用列表保存元素,存储任何类型的元素。

    下面的示例定义了一个数组以及对应用法。

    class Array(object):
    -    """
    -    描述一个数组。
    -    数组类似列表,但数组只能使用[], len, iter, 和 str这些属性。
    -    实例化一个数组,使用 <variable> = Array(<capacity>, <optional fill value>) 其中fill value默认值是None。
    -    """
    + 数组和链接结构 - UPSkilling       

    4.数组和链接结构

    数据结构(data structure)或具体数据类型(concrete data type)是指一组数据的内部存储方式。

    数组(array)和链接结构(linked structure)这两种数据结构是编程语言里多项集最常用的实现。

    目标:

    • 创建数组;
    • 对数组执行各种操作;
    • 确定数组相关操作的运行时和内存的使用情况;
    • 基于数组在计算机内存里的不同存储方式,描述数组相关操作的成本和收益;
    • 使用单向链接节点创建链接结构;
    • 对由单向链接节点构成的链接结构执行各种操作;
    • 基于链接结构在计算机内存里的不同存储方式,描述在链接结构上执行相关操作的成本和收益;
    • 比较数组和链接结构在运行时和内存使用上的权衡;

    4.1.数组数据结构

    关于数组(array):

    • 数组是指在给定索引位置可以访问和替换的元素序列。
    • Python列表的底层数据结构正是一个数组。
    • Python中数组的限制要比列表更多。只能在指定位置访问和替换数组中的元素、检查数组的长度、获取它的字符串表达式;不能基于位置添加或删除元素;数组的长度也就是它的容量,在创建之后就是固定的。

    4.1.1.随机访问和连续内存

    通过下标操作或索引操作实现对数组在指定位置对元素进行存储或检索。

    数组索引是随机访问(random access)操作,而在随机访问时,计算机总会执行固定的步骤来获取第i个元素的位置。因此,不论数组有多大,访问第一个元素所需的时间和访问最后一个元素所需要的时间都是相同的。

    计算机通过分配一块连续内存(contiguous memory)单元来存储数组里的元素,从而支持对数组的随机访问。

    由于数组里的元素地址都是按照数字顺序进行排列的,因此可以通过添加两个值来计算出数组元素的机器地址,它们是数组的基地址(base address)以及元素的偏移量(offset)。其中,数组的基地址就是第一个元素的机器地址,而元素的偏移量就是它的索引值再乘以一个代表数组元素所需内存单元数的常量(在Python里,这个值始终是1)。

    简而言之,Python数组里的索引操作包括下面两个步骤:

    • 得到数组内存块的基地址。
    • 将索引值添加到这个地址并返回。

    4.1.2.静态内存和动态内存

    在比较老的编程语言(如FORTRAN或Pascal)里,数组是静态数据结构。在这种情况下,数组的长度或容量在编译时就确定了,程序员需要申请足够多的内存来满足在数组里存储可能有最大数量元素的情况,这样做会浪费大量的内存。

    像Java和C++这类的现代编程语言会允许程序员创建动态数组(dynamic array),从而为这个问题提供了一种补救方法。和静态数组相似的是,动态数组也会占用一块连续内存,并支持随机访问。动态数组的长度只在运行时才知道,在动态数组实例化的时候指定它的长度。在Python里实现的Array类的行为也是这样的。

    我们可以通过另一种方法在运行时根据应用程序的数据要求来调整数组的长度,这些调整会由Python列表自动进行。这时,数组有以下3种不同形式。

    • 在程序启动时创建一个具有合理默认大小的数组。
    • 当数组无法容纳更多数据时,创建一个更大的新数组,并把旧数组里的数据元素传输给它。
    • 如果数组在浪费内存(应用程序删除了一些数据),那么用类似的方式减小数组的长度。

    4.1.3.物理尺寸和逻辑尺寸

    数组的物理尺寸(physical size)是指数组单元的总数,或者创建数组时指定其容量的那个数字;

    数组的逻辑尺寸(logical size)是指当前应用程序使用的元素数量。

    当数组被填满的时候,我们不需要担心它们的不同。当数组被部分填满的时候,未被填充的内存单元里的数据对当前应用程序是没有用的,我们称之垃圾内容(garbage)。在大多数应用程序里,我们是要注意对数组的物理尺寸和逻辑尺寸进行追踪。通常来说,逻辑尺寸和物理尺寸会反映出有关数组状态的几个重点。

    • 如果逻辑尺寸为0,那么数组就为空。也就是说,这个数组不包含任何数据元素。
    • 如果并非上述情况,在任何情况下,数组中最后一个元素的索引都是它的逻辑尺寸减1。
    • 如果逻辑尺寸等于物理尺寸,那么表示数组已被填满了。

    4.1.4.练习题

    1.请说明随机访问的工作原理,以及这个操作这么快的原因。

    解答:随机访问是一种计算机存储系统中的读取或写入数据的操作,其中数据可以通过直接跳转到其存储位置而不需要顺序扫描来访问。这与顺序访问不同,后者需要按顺序遍历数据以找到所需的信息。随机访问的工作原理如下:

    • 存储介质:计算机内存和硬盘等存储设备都支持随机访问。这些存储介质中的数据通常被划分为块或扇区,并且每个块或扇区都有一个唯一的地址或索引。
    • 访问地址:为了进行随机访问,计算机需要知道要访问的数据的地址。这个地址可以是内存中的特定位置,也可以是硬盘上的某个扇区的地址。
    • 寻址和传输:计算机使用存储设备的控制器或存储器管理单元来查找数据的地址。一旦找到了正确的地址,存储设备会将数据传输到计算机的内存中供处理器使用。
    • 访问速度:随机访问之所以如此快速,是因为计算机内存和现代硬盘驱动器等存储设备都经过了优化,可以快速响应访问请求。这些设备使用了高速缓存、读写头、寻道机构等技术来最小化数据访问的延迟。

    原因:

    • 存储设备的物理结构:计算机内存和硬盘等存储设备的物理结构被设计成可以随机访问的。内存中的每个地址都可以瞬间访问,而硬盘上的扇区也可以通过磁头寻道和旋转磁盘等机制迅速访问。
    • 高速缓存:现代计算机内存和处理器都配备了高速缓存(例如,CPU缓存)。这些高速缓存存储了最近访问的数据,可以快速提供给处理器,从而降低了访问延迟。
    • 存储器管理:操作系统和存储设备的控制器会管理存储器的访问,以确保数据可以高效地被访问和传输。这包括了磁盘调度算法、内存分页等策略。
    • 技术进步:硬件制造技术的进步和存储设备的优化使得随机访问速度更快。例如,固态硬盘(SSD)的出现显著提高了数据的随机访问速度。

    总之,随机访问之所以如此快速,是因为计算机内存和存储设备的物理和技术特性使其能够以高效、迅速的方式访问数据。这种访问速度对于计算机的性能和响应时间至关重要。

    2.数组和Python列表之间有什么区别?

    解答:数组和Python列表之间有几个关键区别,这些区别在数据结构、功能和用途上存在差异:

    • 数据类型:
      • 数组:通常要求所有元素具有相同的数据类型。这是因为数组在内存中以紧凑的方式存储数据,需要知道每个元素的大小以便进行随机访问。
      • Python列表:Python的列表可以容纳不同数据类型的元素,因为它们是动态类型的。
    • 内存管理:
      • 数组:通常在创建时需要指定固定大小,因此在内存中会分配一块连续的空间,这使得数组对于高效的随机访问非常适用。
      • Python列表:Python的列表是动态的,它们可以根据需要自动扩展或缩小。这导致了一些额外的内存开销,因为列表需要更多的空间来管理元素的添加和删除。
    • 性能:
      • 数组:由于内存布局连续,因此数组通常在访问元素时更快。数组还支持更多的底层操作,如位操作。
      • Python列表:Python列表更加灵活,但在某些情况下可能会导致性能下降,特别是当涉及大量元素的插入和删除操作时。
    • 操作和方法:
      • 数组:通常提供一组基本操作,如读取和写入元素,以及一些数学运算,如向量化操作。
      • Python列表:Python列表提供了更丰富的方法和操作,包括元素的插入、删除、追加、切片、连接等。
    • 语言依赖性:
      • 数组:数组通常是编程语言的一部分,具有固定的语法和语义。
      • Python列表:Python的列表是Python标准库的一部分,与Python的动态特性相适应。
    • 适用场景:
      • 数组:适用于需要高效随机访问的情况,如数值计算、图像处理等。
      • Python列表:适用于更广泛的应用,特别是在编写Python代码时,因为它们更灵活且易于使用。

    总之,数组和Python列表都有自己的优势和适用场景。选择使用哪种数据结构取决于具体的需求和编程语言。在Python中,通常会优先选择使用列表,因为它们更方便,而在其他编程语言中,如C或Java,数组可能更为常见。

    在这里需要说明一个概念。在Python中,术语"数组"通常指的是NumPy库中的数组对象,而"列表"指的是Python的内置列表(list)数据结构。这两者之间有以下区别:

    • 数据类型:
      • 数组(NumPy数组):NumPy库提供了一个多维数组对象,它可以包含相同数据类型的元素,并支持高级数学、科学和工程计算。NumPy数组的元素类型通常是固定的,例如,可以是整数、浮点数、复数等。这些数组是高性能的,支持向量化操作。
      • 列表(Python列表):Python的内置列表是一种通用的、动态类型的数据结构,可以包含不同数据类型的元素,例如整数、浮点数、字符串、对象等。列表可以动态扩展和缩小,并提供了丰富的内置方法和操作。
    • 性能:
      • 数组(NumPy数组):NumPy数组通常比Python列表更高效,特别是在进行数值计算和科学计算时。它们内部使用了C语言实现,支持向量化操作,因此在大规模数据处理中通常更快。
      • 列表(Python列表):Python列表虽然灵活,但性能相对较低,不适合大规模的数值计算。它们的元素类型可以不同,这意味着需要更多的内存和处理时间来管理元素。
    • 库依赖:
      • 数组(NumPy数组):使用NumPy库需要安装NumPy模块。NumPy是Python中用于数值计算的核心库,广泛应用于科学计算、机器学习等领域。
      • 列表(Python列表):Python的内置列表是Python标准库的一部分,无需额外安装。
    • 功能:
      • 数组(NumPy数组):NumPy数组提供了许多数学和科学计算函数,如线性代数、傅立叶变换、统计分析等。它们适用于处理大量数值数据。
      • 列表(Python列表):Python列表提供了通用的数据容器,用于存储和管理各种类型的数据,但不提供专门的数学和科学计算功能。

    如果需要进行数值计算、科学计算或数据分析,通常会使用NumPy数组。如果只是需要一个通用的数据容器,用于存储和管理数据,那么Python列表通常足够了。

    3.请说明数组的物理尺寸和逻辑尺寸之间的区别。

    解答:"物理尺寸"和"逻辑尺寸"通常用于描述数据结构中的两个不同方面:

    • 物理尺寸(Physical Size):
      • 物理尺寸是指数据结构实际占用的内存空间或存储介质中的空间大小。
      • 它表示数据结构在计算机内存或磁盘中所占据的实际字节数。
      • 物理尺寸与数据结构的存储方式、数据类型以及计算机架构有关。
    • 逻辑尺寸(Logical Size):
      • 逻辑尺寸是指数据结构中包含的元素数量或数据项的数量。
      • 它表示数据结构内部的元素数量或数据项的个数,不涉及实际的存储大小。
      • 逻辑尺寸通常用于描述数据结构的容量、规模或维度。

    这两个概念之间的关系如下:

    • 一个数据结构可以具有固定的物理尺寸(占据固定数量的字节),但其逻辑尺寸可以根据实际存储的元素数量而变化。
    • 物理尺寸通常是由计算机硬件和操作系统管理的,而逻辑尺寸则是程序员根据数据结构的设计来管理的。

    举例来说,一个整数数组可以具有固定的物理尺寸,例如4字节/整数,但它的逻辑尺寸可以是数组中整数的数量,可以是0个、10个、100个等等。因此,逻辑尺寸描述了数组可以容纳的元素数量,而物理尺寸描述了实际占用的内存空间。

    在数据结构的设计和使用中,了解和管理物理尺寸和逻辑尺寸对于有效地利用计算机资源非常重要。

    4.2.数组的操作

    Python的array模块包含一个叫作array的类,它非常类似于列表,但是只能存储数字。我们会定义一个叫作Array的新类,使用列表保存元素,存储任何类型的元素。

    下面的示例定义了一个数组类Array,下面对数组的一些操作的代码实现也已经包含在下面的代码中。其中:

    • 数组默认的物理尺寸(也就是容量)是5
    • 数组的初始逻辑尺寸是0
    class Array(object):
    +    """描述一个数组。"""
     
         def __init__(self, capacity, fillValue=None):
    -        """Capacity是数组的大小.  fillValue会填充在每个元素位置, 默认值是None"""
    +        """Capacity是数组的大小.  fillValue会填充在每个元素位置, 默认值是None"""
    +        # 初始化数组的逻辑尺寸和物理尺寸
    +        self.logicalSize = 0
    +        self.capacity = capacity
    +        self.fillValue = fillValue
    +        #初始化内部数组,并填充元素值
             self.items = list()
             for count in range(capacity):
                 self.items.append(fillValue)
     
         def __len__(self):
    -        """-> 数组的大小"""
    +        """返回数组的大小"""
             return len(self.items)
     
         def __str__(self):
    -        """-> 将数组字符串化"""
    -        return str(self.items)
    +        """将数组字符串化并返回"""
    +        result = ""
    +        for index in range(self.size()):
    +            result += str(self.items[index]) + " "
    +        return result
    +
    +    def size(self):
    +        """返回数组的逻辑尺寸"""
    +        return self.logicalSize
     
         def __iter__(self):
    -        """支持for循环对数组进行遍历."""
    +        """支持for循环对数组进行遍历."""
    +        print("__iter__ called")  # 仅用来测试何时__iter__会被调用
             return iter(self.items)
     
         def __getitem__(self, index):
    -        """用于访问索引处的下标运算符."""
    +        """
    +        用于访问索引处的下标运算符.
    +        先决条件: 0 <= index < size()
    +        """
    +        if index < 0 or index >= self.size():
    +            raise IndexError("读取操作出错, 数组索引越界(不在数组逻辑边界范围内)")
    +
             return self.items[index]
     
         def __setitem__(self, index, newItem):
    -        """下标运算符用于在索引处进行替换."""
    +        """
    +        下标运算符用于在索引处进行替换.
    +        先决条件: 0 <= index < size()
    +        """
    +        if index < 0 or index >= self.size():
    +            raise IndexError("更新操作出错, 数组索引越界(不在数组逻辑边界范围内)")
             self.items[index] = newItem
     
    -
    -def main(size=10):
    -    my_array = Array(5)
    -    print("The array is: ", my_array)
    -    print("__len__() of the array: ", my_array.__len__())
    -    print("len() of the arry: ", len(my_array))
    -
    -    for i in range(len(my_array)):
    -        my_array[i] = i
    -
    -    for i in my_array:
    -        print(my_array[i], end=" ")
    +    def __eq__(self, other):
    +        """
    +        两个数组相等则返回True,否则返回False
    +        """
    +        # 判断两个数组是否是同一个对象,注意,不是它们的值是否相等
    +        if self is other:
    +            return True
    +        # 判断两个对象类型是否一样
    +        if type(self) != type(other):
    +            return False
    +        # 判断两个数组大小是否一样
    +        if self.size() != other.size():
    +            return False
    +        # 比较两个数组的值是否一样
    +        for index in range(self.size()):
    +            if self[index] != other[index]:
    +                return False
    +        return True
    +
    +    def grow(self):
    +        """增大数组物理尺寸"""
    +        # 基于当前物理尺寸加倍,并将fillValue赋值底层列表的新元素
    +        for count in range(len(self)):
    +            self.items.append(self.fillValue)
    +
    +    def insert(self, index, newItem):
    +        """在数组指定索引处插入新元素"""
    +        # 当数组的物理尺寸和逻辑尺寸一样时,则增加物理尺寸
    +        if self.size() == len(self):
    +            self.grow()
    +        # 插入新元素
    +        # 当插入位置大于或等于最大逻辑位置,则在数组末端插入新元素
    +        # 当插入位置介于数组逻辑位置的中间,则从插入位置起将剩余数组元素向尾部平移一个位置
    +        if index >= self.size():
    +            self.items[self.size()] = newItem
    +        else:
    +            index = max(index, 0)
    +
    +            # 将数组元素向尾部平移一个位置
    +            for i in range(self.size(), index, -1):
    +                self.items[i] = self.items[i - 1]
    +
    +            # 插入新元素
    +            self.items[index] = newItem
    +
    +        # 增加数组的逻辑尺寸
    +        self.logicalSize += 1
    +
    +    def shrink(self):
    +        """
    +        减少数组的物理尺寸
    +        当:
    +        - 数组的逻辑尺寸小于或等于其物理尺寸的1/4
    +        - 并且它的物理尺寸至少是这个数组建立时默认容量的2倍时
    +        则把数组的物理尺寸减小到原来的一半,并且也不会小于其默认容量
    +        """
    +        # 在逻辑尺寸和物理尺寸的一半之间选择最大值作为数组收缩后的物理尺寸
    +        newSize = max(self.capacity, len(self) // 2)
    +        # 释放多余的数组空间
    +        for count in range(len(self) - newSize):
    +            self.items.pop()
    +
    +    def pop(self, index):
    +        """
    +        删除指定索引值的数组元素,并返回删除的数组元素值
    +        先决条件: 0 <= index < size()
    +        """
    +        if index < 0 or index >= self.size():
    +            raise IndexError("删除操作出错, 数组索引越界(不在数组逻辑边界范围内)")
    +
    +        # 保存即将被删除的数组元素值
    +        itemToReturn = self.items[index]
    +
    +        # 将数组元素向头部平移一个位置
    +        for i in range(index, self.size() - 1):
    +            self.items[i] = self.items[i + 1]
    +
    +        # 将数组尾部的空余位赋值fillValue,默认是None
    +        self.items[self.size() - 1] = self.fillValue
    +
    +        # 减少数组逻辑尺寸
    +        self.logicalSize -= 1
    +
    +        # 减少数组物理尺寸
    +        # 当:
    +        # - 数组的逻辑尺寸小于或等于其物理尺寸的1/4
    +        # - 并且它的物理尺寸至少是这个数组建立时默认容量的2倍时
    +        # 则把数组的物理尺寸减小到原来的一半,并且也不会小于其默认容量
    +        if self.size() <= len(self) // 4 and len(self) > self.capacity:
    +            self.shrink()
    +
    +        # 返回被删除元素的值
    +        print(f'Item {itemToReturn} was deleted')
    +        return itemToReturn
    +
    +
    +def main():
    +    # 初始化空数组
    +    DEFAULT_CAPACITY = 5
    +    my_arr = Array(DEFAULT_CAPACITY)
    +
    +    # 打印输出数组初始信息
    +    print("Physical size:", len(my_arr))
    +    print("Logical size:", my_arr.size())
    +    print("Initial items:", my_arr.items)
    +
    +    # 初始化数组元素
    +    print('------')
    +    for item in range(4):
    +        my_arr.insert(0, item)  # 在数组头部插入,每插入一次都需要向后移动已有数组元素
    +    print("Items(logical):", my_arr)
    +    print("Items(physical):", my_arr.items)
    +
    +    # 在数组中间插入新元素
    +    print('------')
    +    my_arr.insert(3, 99)
    +    print("Items(logical):", my_arr)
    +    print("Items(physical):", my_arr.items)
    +
    +    # 在数组逻辑尺寸外插入新元素
    +    print('------')
    +    my_arr.insert(20, 88)
    +    print("Items(logical):", my_arr)
    +    print("Items(physical):", my_arr.items)
    +
    +    # 删除数组元素
    +    print('------')
    +    my_arr.pop(3)
    +    my_arr.pop(3)
    +    print("Items(logical):", my_arr)
    +    print("Items(physical):", my_arr.items)
    +
    +    # 清空数组元素
    +    print('------')
    +    for count in range(my_arr.size()):
    +        my_arr.pop(0)
    +    print("Items(logical):", my_arr)
    +    print("Items(physical):", my_arr.items)
    +
    +    # 数组元素已经全部删除,逻辑尺寸为零,下面命令返回错误
    +    # print('------')
    +    # print(my_arr.pop(0))
    +
    +    # 数组比较
    +    # 初始化数组
    +    print('------')
    +    arr_a = Array(5)
    +    for item in range(4):
    +        arr_a.insert(0, item)
    +    arr_b = arr_a
    +    arr_c = Array(5)
    +    for item in range(4):
    +        arr_c.insert(0, item)
    +    arr_d = []
    +
    +    print("arr_a(physical):", arr_a.items)
    +    print("arr_b(physical):", arr_b.items)
    +    print("arr_c(physical):", arr_c.items)
    +    print("arr_d(physical):", arr_d)
    +
    +    print("arr_a == arr_b:", arr_a == arr_b)
    +    print("arr_a is arr_b:", arr_a is arr_b)
    +    print("arr_a == arr_c:", arr_a == arr_c)
    +    print("arr_a is arr_c:", arr_a is arr_c)
    +
    +    arr_c.insert(10, 10)
    +    print("arr_a == arr_c:", arr_a == arr_c)
    +    arr_c.pop(arr_c.size() - 1)
    +    arr_c[2] = 6
    +    print("arr_a == arr_c:", arr_a == arr_c)
    +
    +    print("arr_a == arr_d:", arr_a == arr_d)
     
     
     if __name__ == "__main__":
         main()
     
    -# 运行结果:
    -# The array is [None, None, None, None, None]
    -# __len__() of the array: 5
    -# len() of the arry: 5
    -# 0 1 2 3 4
    -

    4.1.1.随机访问和连续内存

    通过下标操作或索引操作实现对数组在指定位置对元素进行存储或检索。

    数组索引是随机访问(random access)操作,而在随机访问时,计算机总会执行固定的步骤来获取第i个元素的位置。因此,不论数组有多大,访问第一个元素所需的时间和访问最后一个元素所需要的时间都是相同的。

    计算机通过分配一块连续内存(contiguous memory)单元来存储数组里的元素,从而支持对数组的随机访问。

    由于数组里的元素地址都是按照数字顺序进行排列的,因此可以通过添加两个值来计算出数组元素的机器地址,它们是数组的基地址(base address)以及元素的偏移量(offset)。其中,数组的基地址就是第一个元素的机器地址,而元素的偏移量就是它的索引值再乘以一个代表数组元素所需内存单元数的常量(在Python里,这个值始终是1)。

    简而言之,Python数组里的索引操作包括下面两个步骤:

    • 得到数组内存块的基地址。
    • 将索引值添加到这个地址并返回。

    4.1.2.静态内存和动态内存

    在比较老的编程语言(如FORTRAN或Pascal)里,数组是静态数据结构。在这种情况下,数组的长度或容量在编译时就确定了,程序员需要申请足够多的内存来满足在数组里存储可能有最大数量元素的情况,这样做会浪费大量的内存。

    像Java和C++这类的现代编程语言会允许程序员创建动态数组(dynamic array),从而为这个问题提供了一种补救方法。和静态数组相似的是,动态数组也会占用一块连续内存,并支持随机访问。动态数组的长度只在运行时才知道,在动态数组实例化的时候指定它的长度。在Python里实现的Array类的行为也是这样的。

    我们可以通过另一种方法在运行时根据应用程序的数据要求来调整数组的长度,这些调整会由Python列表自动进行。这时,数组有以下3种不同形式。

    • 在程序启动时创建一个具有合理默认大小的数组。
    • 当数组无法容纳更多数据时,创建一个更大的新数组,并把旧数组里的数据元素传输给它。
    • 如果数组在浪费内存(应用程序删除了一些数据),那么用类似的方式减小数组的长度。

    4.1.3.物理尺寸和逻辑尺寸

    数组的物理尺寸(physical size)是指数组单元的总数,或者创建数组时指定其容量的那个数字;

    数组的逻辑尺寸(logical size)是指当前应用程序使用的元素数量。

    当数组被填满的时候,我们不需要担心它们的不同。当数组被部分填满的时候,未被填充的内存单元里的数据对当前应用程序是没有用的,我们称之垃圾内容(garbage)。在大多数应用程序里,我们是要注意对数组的物理尺寸和逻辑尺寸进行追踪。通常来说,逻辑尺寸和物理尺寸会反映出有关数组状态的几个重点。

    • 如果逻辑尺寸为0,那么数组就为空。也就是说,这个数组不包含任何数据元素。
    • 如果并非上述情况,在任何情况下,数组中最后一个元素的索引都是它的逻辑尺寸减1。
    • 如果逻辑尺寸等于物理尺寸,那么表示数组已被填满了。

    4.1.4.练习题

    1.请说明随机访问的工作原理,以及这个操作这么快的原因。

    解答:随机访问是一种计算机存储系统中的读取或写入数据的操作,其中数据可以通过直接跳转到其存储位置而不需要顺序扫描来访问。这与顺序访问不同,后者需要按顺序遍历数据以找到所需的信息。随机访问的工作原理如下:

    • 存储介质:计算机内存和硬盘等存储设备都支持随机访问。这些存储介质中的数据通常被划分为块或扇区,并且每个块或扇区都有一个唯一的地址或索引。
    • 访问地址:为了进行随机访问,计算机需要知道要访问的数据的地址。这个地址可以是内存中的特定位置,也可以是硬盘上的某个扇区的地址。
    • 寻址和传输:计算机使用存储设备的控制器或存储器管理单元来查找数据的地址。一旦找到了正确的地址,存储设备会将数据传输到计算机的内存中供处理器使用。
    • 访问速度:随机访问之所以如此快速,是因为计算机内存和现代硬盘驱动器等存储设备都经过了优化,可以快速响应访问请求。这些设备使用了高速缓存、读写头、寻道机构等技术来最小化数据访问的延迟。

    原因:

    • 存储设备的物理结构:计算机内存和硬盘等存储设备的物理结构被设计成可以随机访问的。内存中的每个地址都可以瞬间访问,而硬盘上的扇区也可以通过磁头寻道和旋转磁盘等机制迅速访问。
    • 高速缓存:现代计算机内存和处理器都配备了高速缓存(例如,CPU缓存)。这些高速缓存存储了最近访问的数据,可以快速提供给处理器,从而降低了访问延迟。
    • 存储器管理:操作系统和存储设备的控制器会管理存储器的访问,以确保数据可以高效地被访问和传输。这包括了磁盘调度算法、内存分页等策略。
    • 技术进步:硬件制造技术的进步和存储设备的优化使得随机访问速度更快。例如,固态硬盘(SSD)的出现显著提高了数据的随机访问速度。

    总之,随机访问之所以如此快速,是因为计算机内存和存储设备的物理和技术特性使其能够以高效、迅速的方式访问数据。这种访问速度对于计算机的性能和响应时间至关重要。

    2.数组和Python列表之间有什么区别?

    解答:数组和Python列表之间有几个关键区别,这些区别在数据结构、功能和用途上存在差异:

    • 数据类型:
      • 数组:通常要求所有元素具有相同的数据类型。这是因为数组在内存中以紧凑的方式存储数据,需要知道每个元素的大小以便进行随机访问。
      • Python列表:Python的列表可以容纳不同数据类型的元素,因为它们是动态类型的。
    • 内存管理:
      • 数组:通常在创建时需要指定固定大小,因此在内存中会分配一块连续的空间,这使得数组对于高效的随机访问非常适用。
      • Python列表:Python的列表是动态的,它们可以根据需要自动扩展或缩小。这导致了一些额外的内存开销,因为列表需要更多的空间来管理元素的添加和删除。
    • 性能:
      • 数组:由于内存布局连续,因此数组通常在访问元素时更快。数组还支持更多的底层操作,如位操作。
      • Python列表:Python列表更加灵活,但在某些情况下可能会导致性能下降,特别是当涉及大量元素的插入和删除操作时。
    • 操作和方法:
      • 数组:通常提供一组基本操作,如读取和写入元素,以及一些数学运算,如向量化操作。
      • Python列表:Python列表提供了更丰富的方法和操作,包括元素的插入、删除、追加、切片、连接等。
    • 语言依赖性:
      • 数组:数组通常是编程语言的一部分,具有固定的语法和语义。
      • Python列表:Python的列表是Python标准库的一部分,与Python的动态特性相适应。
    • 适用场景:
      • 数组:适用于需要高效随机访问的情况,如数值计算、图像处理等。
      • Python列表:适用于更广泛的应用,特别是在编写Python代码时,因为它们更灵活且易于使用。

    总之,数组和Python列表都有自己的优势和适用场景。选择使用哪种数据结构取决于具体的需求和编程语言。在Python中,通常会优先选择使用列表,因为它们更方便,而在其他编程语言中,如C或Java,数组可能更为常见。

    在这里需要说明一个概念。在Python中,术语"数组"通常指的是NumPy库中的数组对象,而"列表"指的是Python的内置列表(list)数据结构。这两者之间有以下区别:

    • 数据类型:
      • 数组(NumPy数组):NumPy库提供了一个多维数组对象,它可以包含相同数据类型的元素,并支持高级数学、科学和工程计算。NumPy数组的元素类型通常是固定的,例如,可以是整数、浮点数、复数等。这些数组是高性能的,支持向量化操作。
      • 列表(Python列表):Python的内置列表是一种通用的、动态类型的数据结构,可以包含不同数据类型的元素,例如整数、浮点数、字符串、对象等。列表可以动态扩展和缩小,并提供了丰富的内置方法和操作。
    • 性能:
      • 数组(NumPy数组):NumPy数组通常比Python列表更高效,特别是在进行数值计算和科学计算时。它们内部使用了C语言实现,支持向量化操作,因此在大规模数据处理中通常更快。
      • 列表(Python列表):Python列表虽然灵活,但性能相对较低,不适合大规模的数值计算。它们的元素类型可以不同,这意味着需要更多的内存和处理时间来管理元素。
    • 库依赖:
      • 数组(NumPy数组):使用NumPy库需要安装NumPy模块。NumPy是Python中用于数值计算的核心库,广泛应用于科学计算、机器学习等领域。
      • 列表(Python列表):Python的内置列表是Python标准库的一部分,无需额外安装。
    • 功能:
      • 数组(NumPy数组):NumPy数组提供了许多数学和科学计算函数,如线性代数、傅立叶变换、统计分析等。它们适用于处理大量数值数据。
      • 列表(Python列表):Python列表提供了通用的数据容器,用于存储和管理各种类型的数据,但不提供专门的数学和科学计算功能。

    如果需要进行数值计算、科学计算或数据分析,通常会使用NumPy数组。如果只是需要一个通用的数据容器,用于存储和管理数据,那么Python列表通常足够了。

    3.请说明数组的物理尺寸和逻辑尺寸之间的区别。

    解答:"物理尺寸"和"逻辑尺寸"通常用于描述数据结构中的两个不同方面:

    • 物理尺寸(Physical Size):
      • 物理尺寸是指数据结构实际占用的内存空间或存储介质中的空间大小。
      • 它表示数据结构在计算机内存或磁盘中所占据的实际字节数。
      • 物理尺寸与数据结构的存储方式、数据类型以及计算机架构有关。
    • 逻辑尺寸(Logical Size):
      • 逻辑尺寸是指数据结构中包含的元素数量或数据项的数量。
      • 它表示数据结构内部的元素数量或数据项的个数,不涉及实际的存储大小。
      • 逻辑尺寸通常用于描述数据结构的容量、规模或维度。

    这两个概念之间的关系如下:

    • 一个数据结构可以具有固定的物理尺寸(占据固定数量的字节),但其逻辑尺寸可以根据实际存储的元素数量而变化。
    • 物理尺寸通常是由计算机硬件和操作系统管理的,而逻辑尺寸则是程序员根据数据结构的设计来管理的。

    举例来说,一个整数数组可以具有固定的物理尺寸,例如4字节/整数,但它的逻辑尺寸可以是数组中整数的数量,可以是0个、10个、100个等等。因此,逻辑尺寸描述了数组可以容纳的元素数量,而物理尺寸描述了实际占用的内存空间。

    在数据结构的设计和使用中,了解和管理物理尺寸和逻辑尺寸对于有效地利用计算机资源非常重要。

    4.2.数组的操作

    在下面的例子里,我们假定有下面这些数据配置。

    DEFAULT_CAPACITY = 5  # 数组默认的物理尺寸(也就是容量)是5
    -logicalSize = 0  # 数组的初始逻辑尺寸是0
    -a = Array(DEFAULT_CAPACITY)
    -

    4.2.1.增大数组的尺寸

    当数组的逻辑尺寸等于它的物理尺寸时,如果要插入新的元素,就需要增大数组的尺寸。 如果需要为数组提供更多内存,Python的list类型会在调用insert或append方法时执行这个操作。

    调整数组尺寸的过程包含如下3个步骤。

    • 创建一个更大的新数组。
    • 将数据从旧数组中复制到新数组。
    • 将指向旧数组的变量指向新数组对象。

    下面代码实现。

    class Array(object):
    -    ...
    -
    -def main(size=10):
    -    DEFAULT_CAPACITY = 5
    -    logicalSize = 0
    -    my_array = Array(DEFAULT_CAPACITY)
    -
    -    print("Initial array is: ", my_array)
    -    print("Len of the array: ", my_array.__len__())
    -
    -    for i in range(len(my_array)):
    -        my_array[i] = i
    -
    -    print("The array is: ", my_array.items)
    -
    -    # 增大数组物理尺寸
    -    if logicalSize == len(my_array):
    +# 运行结果
    +# Physical size: 5
    +# Logical size: 0
    +# Initial items: [None, None, None, None, None]
    +# ------
    +# Items(logical): 3 2 1 0
    +# Items(physical): [3, 2, 1, 0, None]
    +# ------
    +# Items(logical): 3 2 1 99 0
    +# Items(physical): [3, 2, 1, 99, 0]
    +# ------
    +# Items(logical): 3 2 1 99 0 88
    +# Items(physical): [3, 2, 1, 99, 0, 88, None, None, None, None]
    +# ------
    +# Item 99 was deleted
    +# Item 0 was deleted
    +# Items(logical): 3 2 1 88
    +# Items(physical): [3, 2, 1, 88, None, None, None, None, None, None]
    +# ------
    +# Item 3 was deleted
    +# Item 2 was deleted
    +# Item 1 was deleted
    +# Item 88 was deleted
    +# Items(logical):
    +# Items(physical): [None, None, None, None, None]
    +# ------
    +# IndexError: 删除操作出错, 数组索引越界(不在数组逻辑边界范围内)
    +# ------
    +# arr_a(physical): [3, 2, 1, 0, None]
    +# arr_b(physical): [3, 2, 1, 0, None]
    +# arr_c(physical): [3, 2, 1, 0, None]
    +# arr_d(physical): []
    +# arr_a == arr_b: True
    +# arr_a is arr_b: True
    +# arr_a == arr_c: True
    +# arr_a is arr_c: False
    +# arr_a == arr_c: False
    +# Item 10 was deleted
    +# arr_a == arr_c: False
    +# arr_a == arr_d: False
    +

    4.2.1.增大数组的尺寸

    当数组的逻辑尺寸等于它的物理尺寸时,如果要插入新的元素,就需要增大数组的物理尺寸。 如果需要为数组提供更多内存,Python的list类型会在调用insert或append方法时执行这个操作。

    调整数组物理尺寸的过程包含如下3个步骤。

    • 创建一个更大的新数组。
    • 将数据从旧数组中复制到新数组。
    • 将指向旧数组的变量指向新数组对象。

    下面代码实现。

    # 增大数组物理尺寸
    +if logicalSize == len(my_array):
    +    temp = Array(len(my_array) + 1)  # 创建一个新数组
    +    for i in range(logicalSize):
    +        temp[i] = my_array[i]  # 从原数组复制内容到新数组
    +    my_array = temp  # 把新数组赋值给原数组
    +

    在上面代码中,通过temp[i] = my_array[i]来调整数组尺寸,这个复制操作的数量是线性增长的。因此,将n个元素添加到数组里的总时间复杂度是1+2+3...+n,也就是n(n+1)/2,因此是O(n^2)

    在上面的代码中,通过temp = Array(len(my_array) + 1)对数组进行动态扩展,对性能会产生一些可能的影响:

    • 时间复杂度:动态扩展数组通常需要复制现有数据到新的内存位置,这将涉及到元素的复制操作。这些操作的时间复杂度取决于数组的长度,通常是O(n),其中n是数组的长度。因此,当数组需要扩展时,可能会产生一些额外的时间开销。
    • 空间复杂度:动态扩展数组会占用额外的内存空间,因为需要分配新的内存块来容纳扩展后的数组。这可能会导致内存碎片化,特别是在频繁扩展和缩小数组时。
    • 扩展频率:扩展数组的频率会影响性能。如果数组需要频繁扩展,那么复制和内存分配的开销会更加显著,从而降低性能。因此,在设计数据结构时,通常会考虑初始容量和扩展策略,以减少不必要的扩展次数。
    • Amortized Analysis:一些数据结构,例如Python的列表(list),采用摊还分析来平摊动态扩展的开销。这意味着虽然某些操作可能会花费O(n)的时间,但这些开销在一系列操作中被分摊,平均下来仍然保持较低的复杂度。这可以在一定程度上缓解性能问题。

    动态扩展数组会引入一些性能开销,但在实际应用中,这种开销通常是可以接受的。为了优化性能,可以考虑以下几点策略,需要根据具体应用的需求和性能要求来权衡这些因素:

    • 预先分配足够的初始容量,以减少扩展的频率。
    • 使用摊还分析来平摊开销。
    • 考虑使用其他数据结构,如链表,对插入和删除操作的性能更加友好。

    下面,尝试在每次增大数组尺寸时把数组尺寸翻倍,代码实现如下:

    # 增大数组物理尺寸
    +while logicalSize < DEFAULT_CAPACITY * 2:
    +    logicalSize += 1
    +    if logicalSize == len(my_array):  # 触发条件
             temp = Array(len(my_array) + 1)  # 创建一个新数组
             for i in range(logicalSize):
                 temp[i] = my_array[i]  # 从原数组复制内容到新数组
             my_array = temp  # 把新数组赋值给原数组
    -
    -
    -if __name__ == "__main__":
    -    main()
    -

    在上面代码中,通过temp[i] = my_array[i]来调整数组尺寸,这个复制操作的数量是线性增长的。因此,将n个元素添加到数组里的总时间复杂度是1+2+3...+n,也就是n(n+1)/2,因此是O(n^2)

    在上面的代码中,通过temp = Array(len(my_array) + 1)对数组进行动态扩展,对性能会产生一些可能的影响:

    • 时间复杂度:动态扩展数组通常需要复制现有数据到新的内存位置,这将涉及到元素的复制操作。这些操作的时间复杂度取决于数组的长度,通常是O(n),其中n是数组的长度。因此,当数组需要扩展时,可能会产生一些额外的时间开销。
    • 空间复杂度:动态扩展数组会占用额外的内存空间,因为需要分配新的内存块来容纳扩展后的数组。这可能会导致内存碎片化,特别是在频繁扩展和缩小数组时。
    • 扩展频率:扩展数组的频率会影响性能。如果数组需要频繁扩展,那么复制和内存分配的开销会更加显著,从而降低性能。因此,在设计数据结构时,通常会考虑初始容量和扩展策略,以减少不必要的扩展次数。
    • Amortized Analysis:一些数据结构,例如Python的列表(list),采用摊还分析来平摊动态扩展的开销。这意味着虽然某些操作可能会花费O(n)的时间,但这些开销在一系列操作中被分摊,平均下来仍然保持较低的复杂度。这可以在一定程度上缓解性能问题。

    动态扩展数组会引入一些性能开销,但在实际应用中,这种开销通常是可以接受的。为了优化性能,可以考虑以下几点策略,需要根据具体应用的需求和性能要求来权衡这些因素:

    • 预先分配足够的初始容量,以减少扩展的频率。
    • 使用摊还分析来平摊开销。
    • 考虑使用其他数据结构,如链表,对插入和删除操作的性能更加友好。

    下面,尝试在每次增大数组尺寸时把数组尺寸翻倍,代码实现如下:

    class Array(object):
    -    ...
    -
    -def main(size=10):
    -    # 初始值
    -    DEFAULT_CAPACITY = 5
    -    logicalSize = 0
    -    my_array = Array(DEFAULT_CAPACITY)
    -
    -    # 打印输出初始数组信息
    -    print("Initial array is: ", my_array)
    -    print("Len of the array: ", my_array.__len__())
    -
    -    # 给数组赋值
    -    for i in range(len(my_array)):
    -        my_array[i] = i
    -
    -    print("The array is: ", my_array.items)  # 打印输出数组
    -
    -    # 增大数组物理尺寸
    -    while logicalSize < DEFAULT_CAPACITY * 2:
    -        logicalSize += 1
    -        if logicalSize == len(my_array):  # 触发条件
    -            temp = Array(len(my_array) + 1)  # 创建一个新数组
    -            for i in range(logicalSize):
    -                temp[i] = my_array[i]  # 从原数组复制内容到新数组
    -            my_array = temp  # 把新数组赋值给原数组
    -
    -    print("The array after increased is: ", my_array.items)  # 打印输出数组
    -
    -if __name__ == "__main__":
    -    main()
    -
    -# 运行结果:
    -# Initial array is:  [None, None, None, None, None]
    -# Len of the array:  5
    -# The array is:  [0, 1, 2, 3, 4]
    -# The array after increased is:  [0, 1, 2, 3, 4, None, None, None, None, None, None]
    -

    将数组尺寸翻倍来扩展数组的方式是一种常见的策略,通常用于减少动态数组的频繁扩展次数,以提高性能。这种方式的操作时间复杂度主要取决于扩展操作的频率和元素的复制成本。

    • 摊还分析:对于将数组尺寸翻倍的策略,摊还分析表明,每次扩展操作的摊还时间复杂度仍然是常数时间的(通常是O(1)),这意味着平均下来,每次扩展的开销是固定的,而不会随数组的大小线性增加。
    • 操作时间:假设数组需要扩展,那么将数组尺寸翻倍需要分配新的内存块并复制现有元素,这个操作的时间复杂度是O(n),其中n是数组的当前大小。然而,由于扩展操作不是每次都执行的,而是当数组已满时才执行,因此可以认为这个操作的摊还时间是常数时间,即O(1)。
    • 空间复杂度:将数组尺寸翻倍会占用额外的内存空间,但随着数组的增长,额外内存的占用相对于数组本身的大小来说是有限的。通常情况下,这种占用可以接受。

    总结,将数组尺寸翻倍的策略可以显著减少动态数组的扩展次数,从而提高性能。虽然每次扩展操作可能会花费一些时间和额外内存,但这些开销在一系列操作中被平摊,平均下来是常数时间。这是一种高效的动态数组实现方式,常见于许多编程语言的标准库中,包括Python的列表(list)。

    在增加数组的长度时,每次增加一个内存单元,与每次增大数组尺寸时把数组尺寸翻倍相比,后者的方法通常更高效。

    • 每次增加一个内存单元:这种方式在每次添加新元素时都需要分配额外的内存,导致数组尺寸的增长是线性的。如果频繁添加元素,这将导致大量的内存分配和数据复制操作,因此时间复杂度会变得相对较高。
    • 每次增大数组尺寸时把数组尺寸翻倍:这是一种更高效的策略。在这种方式下,每次扩展操作都会增加数组的尺寸,但增幅是指数级的,而不是线性的。这意味着随着数组的增长,扩展操作的频率会减少,因为数组能够容纳更多元素。这样,虽然每次扩展操作需要复制更多的元素,但它们的摊还时间复杂度仍然是常数时间,因为它们不是每次都执行的。

    总结,将数组尺寸翻倍的策略通常更高效,因为它可以减少频繁的内存分配和复制操作,降低了时间复杂度。这是许多动态数组实现的常见做法,包括Python的列表(list)。

    4.2.2.减小数组的尺寸

    如果减小数组的逻辑尺寸,就会浪费相应的内存单元。因此,当删除某一个元素,如果未使用的内存单元数达到或超过了某个阈值(如数组物理尺寸的¾)时,则应该减小物理尺寸了。如果浪费的内存超过特定阈值,那么Python的list类型会在调用pop方法时执行减小数组物理尺寸的操作。

    减小数组尺寸的过程与增大数组尺寸的过程相反,步骤如下:

    • 创建一个更小的新数组。
    • 将数据从旧数组中复制到新数组。
    • 将指向旧数组的变量指向新数组对象。

    下面的代码实现了减小数组尺寸。

    当数组的逻辑尺寸小于或等于其物理尺寸的¼,并且它的物理尺寸至少是这个数组建立时默认容量的2倍时,则下面的算法把数组的物理尺寸减小到原来的一半,并且也不会小于其默认容量。

    def main(size=10):
    -    # 初始值
    -    DEFAULT_CAPACITY = 5
    -    logicalSize = 0
    -    my_array = Array(DEFAULT_CAPACITY)
    -
    -    # 打印输出初始数组信息
    -    print("Initial array is: ", my_array)
    -    print("Len of the array: ", my_array.__len__())
    -
    -    # 给数组赋值
    -    for i in range(len(my_array)):
    -        my_array[i] = i
    -
    -    print("The array is: ", my_array.items)  # 打印输出数组
    -
    -    # 增大数组物理尺寸
    -    while logicalSize < DEFAULT_CAPACITY * 2:
    -        logicalSize += 1
    -        if logicalSize == len(my_array):  # 触发条件
    -            temp = Array(len(my_array) + 1)  # 创建一个新数组
    -            for i in range(logicalSize):
    -                temp[i] = my_array[i]  # 从原数组复制内容到新数组
    -            my_array = temp  # 把新数组赋值给原数组
    -
    -    print("The array after increased is: ", my_array.items)  # 打印输出数组
    -
    -    # 减小数组物理尺寸
    -    while logicalSize > len(my_array) // 4:
    -        logicalSize -= 1
    -        if logicalSize <= len(my_array) // 4 and len(my_array) >= DEFAULT_CAPACITY * 2:  # 触发条件
    -            temp = Array(len(my_array) // 2)  # 创建一个新数组
    -            for i in range(logicalSize):
    -                temp[i] = my_array[i]  # 从原数组复制内容到新数组
    -            my_array = temp  # 把新数组赋值给原数组
    -
    -    print("The array after decreased is: ", my_array.items)  # 打印输出数组
    -
    -if __name__ == "__main__":
    -    main()
    -
    -# 运行结果:
    -# Initial array is:  [None, None, None, None, None]
    -# Len of the array:  5
    -# The array is:  [0, 1, 2, 3, 4]
    -# The array after increased is:  [0, 1, 2, 3, 4, None, None, None, None, None, None]
    -# The array after decreased is:  [0, 1, None, None, None]
    -

    按照上面算法减少数组的尺寸,我们可以分析其时间和空间复杂度如下:

    时间复杂度:主要涉及两个操作:

    • 创建新数组并将元素从旧数组复制到新数组;
    • 将旧数组引用更改为新数组。

    复制操作的时间复杂度取决于数组的物理尺寸,可以表示为O(n),其中n是数组的当前物理尺寸。引用更改是一个常数时间操作,不影响时间复杂度。所以,整体的时间复杂度是O(n)

    空间复杂度:空间复杂度也涉及两个方面:

    • 创建新数组的内存消耗,其空间复杂度是O(N);
    • 引用更改所需的常数额外空间,通常忽略不计。

    所以,总的空间复杂度是O(n)

    这个算法策略会在适当的时候减小数组的物理尺寸,以减少内存占用,但仍然保持着数组的动态性。时间复杂度和空间复杂度都与当前数组的物理尺寸成线性关系,因此是线性的,这是一种有效的策略来优化内存使用。同时,保留了一定的冗余空间,以避免频繁地扩展和缩小数组,从而提高了性能。

    4.2.3.将元素插入增大的数组

    4.2.4.从数组里删除元素

    4.2.5.复杂度的权衡:时间、空间和数组

    4.2.6.练习题

    1.请说明为什么插入或删除给定元素时必须要移动数组里的某些元素。

    2.在插入过程中,移动数组元素时,要先移动哪个元素?先移动插入位置的元素,还是最后一个元素?为什么?

    3.如果插入位置是数组的逻辑末尾,请说明这个插入操作的运行时复杂度。

    4.假设数组当前包含14个元素,它的负载因子为0.70,那么它的物理容量是多少?

    4.3.二维数组(网格)

    4.3.1.使用网格

    4.3.2.创建并初始化网格

    4.3.3.定义Grid类

    4.3.4.参差不齐的网格和多维数组

    4.3.5.练习题

    1.什么是二维数组(网格)?

    2.请描述一个可能会用到二维数组的应用程序。

    3.编写一个程序,使之可以在Grid对象里搜索一个负整数。循环应该在遇到网格里的第一个负整数的地方终止,这时变量row和column应该被设置为这个负数的位置。如果在网格里找不到负数,那么变量row和column应该等于网格的行数和列数。

    4.说说运行下面这段代码后网格里的内容是什么。

    matrix = Grid(3, 3)
    +

    将数组尺寸翻倍来扩展数组的方式是一种常见的策略,通常用于减少动态数组的频繁扩展次数,以提高性能。这种方式的操作时间复杂度主要取决于扩展操作的频率和元素的复制成本。

    • 摊还分析:对于将数组尺寸翻倍的策略,摊还分析表明,每次扩展操作的摊还时间复杂度仍然是常数时间的(通常是O(1)),这意味着平均下来,每次扩展的开销是固定的,而不会随数组的大小线性增加。
    • 操作时间:假设数组需要扩展,那么将数组尺寸翻倍需要分配新的内存块并复制现有元素,这个操作的时间复杂度是O(n),其中n是数组的当前大小。然而,由于扩展操作不是每次都执行的,而是当数组已满时才执行,因此可以认为这个操作的摊还时间是常数时间,即O(1)。
    • 空间复杂度:将数组尺寸翻倍会占用额外的内存空间,但随着数组的增长,额外内存的占用相对于数组本身的大小来说是有限的。通常情况下,这种占用可以接受。

    总结,将数组尺寸翻倍的策略可以显著减少动态数组的扩展次数,从而提高性能。虽然每次扩展操作可能会花费一些时间和额外内存,但这些开销在一系列操作中被平摊,平均下来是常数时间。这是一种高效的动态数组实现方式,常见于许多编程语言的标准库中,包括Python的列表(list)。

    在增加数组的长度时,每次增加一个内存单元,与每次增大数组尺寸时把数组尺寸翻倍相比,后者的方法通常更高效。

    • 每次增加一个内存单元:这种方式在每次添加新元素时都需要分配额外的内存,导致数组尺寸的增长是线性的。如果频繁添加元素,这将导致大量的内存分配和数据复制操作,因此时间复杂度会变得相对较高。
    • 每次增大数组尺寸时把数组尺寸翻倍:这是一种更高效的策略。在这种方式下,每次扩展操作都会增加数组的尺寸,但增幅是指数级的,而不是线性的。这意味着随着数组的增长,扩展操作的频率会减少,因为数组能够容纳更多元素。这样,虽然每次扩展操作需要复制更多的元素,但它们的摊还时间复杂度仍然是常数时间,因为它们不是每次都执行的。

    总结,将数组尺寸翻倍的策略通常更高效,因为它可以减少频繁的内存分配和复制操作,降低了时间复杂度。这是许多动态数组实现的常见做法,包括Python的列表(list)。

    Array类实现中,是通过下面代码段实现的数组物理尺寸增加的,即将数组尺寸翻倍。

        def grow(self):
    +        """增大数组物理尺寸"""
    +        # 基于当前物理尺寸加倍,并将fillValue赋值底层列表的新元素
    +        for count in range(len(self)):
    +            self.items.append(self.fillValue)
    +

    4.2.2.减小数组的尺寸

    如果减小数组的逻辑尺寸,就会浪费相应的内存单元。因此,当删除某一个元素,如果未使用的内存单元数达到或超过了某个阈值(如数组物理尺寸的¾)时,则应该减小物理尺寸了。如果浪费的内存超过特定阈值,那么Python的list类型会在调用pop方法时执行减小数组物理尺寸的操作。

    减小数组尺寸的过程与增大数组尺寸的过程相反,步骤如下:

    • 创建一个更小的新数组。
    • 将数据从旧数组中复制到新数组。
    • 将指向旧数组的变量指向新数组对象。

    下面的代码实现了减小数组尺寸。

    当数组的逻辑尺寸小于或等于其物理尺寸的¼,并且它的物理尺寸至少是这个数组建立时默认容量的2倍时,则下面的算法把数组的物理尺寸减小到原来的一半,并且也不会小于其默认容量。

    # 减小数组物理尺寸
    +while logicalSize > len(my_array) // 4:
    +    logicalSize -= 1
    +    if logicalSize <= len(my_array) // 4 and len(my_array) >= DEFAULT_CAPACITY * 2:  # 触发条件
    +        temp = Array(len(my_array) // 2)  # 创建一个新数组
    +        for i in range(logicalSize):
    +            temp[i] = my_array[i]  # 从原数组复制内容到新数组
    +        my_array = temp  # 把新数组赋值给原数组
    +

    按照上面算法减少数组的尺寸,我们可以分析其时间和空间复杂度如下:

    时间复杂度:主要涉及两个操作:

    • 创建新数组并将元素从旧数组复制到新数组;
    • 将旧数组引用更改为新数组。

    复制操作的时间复杂度取决于数组的物理尺寸,可以表示为O(n),其中n是数组的当前物理尺寸。引用更改是一个常数时间操作,不影响时间复杂度。所以,整体的时间复杂度是O(n)

    空间复杂度:空间复杂度也涉及两个方面:

    • 创建新数组的内存消耗,其空间复杂度是O(N);
    • 引用更改所需的常数额外空间,通常忽略不计。

    所以,总的空间复杂度是O(n)

    这个算法策略会在适当的时候减小数组的物理尺寸,以减少内存占用,但仍然保持着数组的动态性。时间复杂度和空间复杂度都与当前数组的物理尺寸成线性关系,因此是线性的,这是一种有效的策略来优化内存使用。同时,保留了一定的冗余空间,以避免频繁地扩展和缩小数组,从而提高了性能。

    下面是在Array类中实现减小数组的物理尺寸的代码。

        def shrink(self):
    +        """
    +        减少数组的物理尺寸
    +        当:
    +        - 数组的逻辑尺寸小于或等于其物理尺寸的1/4
    +        - 并且它的物理尺寸至少是这个数组建立时默认容量的2倍时
    +        则把数组的物理尺寸减小到原来的一半,并且也不会小于其默认容量
    +        """
    +        # 在逻辑尺寸和物理尺寸的一半之间选择最大值作为数组收缩后的物理尺寸
    +        newSize = max(self.capacity, len(self) // 2)
    +        # 释放多余的数组空间
    +        for count in range(len(self) - newSize):
    +            self.items.pop()
    +

    4.2.3.将元素插入增大的数组

    把元素插入数组中和替换数组里的元素是不一样的。

    替换数组元素时,元素已在一个给定的索引位置,对这个位置进行简单复制即可,数组的逻辑尺寸并不会改变。

    插入数组元素时,需要完成下面4个步骤:

    • 在插入元素之前先检查可以使用的空间,根据需要来增大数组的物理尺寸。
    • 将数组里从逻辑结尾到目标索引的所有元素向后移动。这个过程会在目标索引位置处为新元素留下一个空格。
    • 将新元素分配到目标索引位置。
    • 将逻辑尺寸加1。

    4.2.4.从数组里删除元素

    4.2.5.复杂度的权衡:时间、空间和数组

    4.2.6.练习题

    1.请说明为什么插入或删除给定元素时必须要移动数组里的某些元素。

    2.在插入过程中,移动数组元素时,要先移动哪个元素?先移动插入位置的元素,还是最后一个元素?为什么?

    3.如果插入位置是数组的逻辑末尾,请说明这个插入操作的运行时复杂度。

    4.假设数组当前包含14个元素,它的负载因子为0.70,那么它的物理容量是多少?

    4.3.二维数组(网格)

    4.3.1.使用网格

    4.3.2.创建并初始化网格

    4.3.3.定义Grid类

    4.3.4.参差不齐的网格和多维数组

    4.3.5.练习题

    1.什么是二维数组(网格)?

    2.请描述一个可能会用到二维数组的应用程序。

    3.编写一个程序,使之可以在Grid对象里搜索一个负整数。循环应该在遇到网格里的第一个负整数的地方终止,这时变量row和column应该被设置为这个负数的位置。如果在网格里找不到负数,那么变量row和column应该等于网格的行数和列数。

    4.说说运行下面这段代码后网格里的内容是什么。

    matrix = Grid(3, 3)
     for row in range(matrix.getHeight()):
          for column in range(matrix.getWidth()):
              matrix[row][column] = row * column
    -

    5.编写一段代码以创建一个参差不齐的网格,它的行分别用来存储3个、6个和9个元素。

    6.提供一个把Grid类用作数据结构来实现三维array类的策略。

    7.编写一段代码:这段代码会把三维数组里每个单元的值都初始化为它的3个索引位置。例如,如果位置是(深度、行、列),则对于位置(2、3、3)来说,它的值就是233。

    8.编写一段代码:这段代码可以显示出三维数组里的所有元素。打印出的每一行数据都应该代表给定行和列里的所有元素,而深度将从第一个位置向后递归到最后一个位置。遍历应该从第1行、第1列以及第一个深度位置开始,依次遍历所有的深度、列和行。

    4.4.链接结构

    4.4.1.单向链接结构和双向链接结构

    4.4.2.非连续内存和节点

    4.4.3.定义单向链接节点类

    4.4.4.使用单向链接节点类

    4.4.5.练习题

    1.用框和指针绘制测试程序里第一个循环所创建的节点的示意图。

    2.当节点变量引用的是None时,如果程序员尝试访问节点的数据字段,则会发生什么?如何防止这种情况的发生?

    3.编写一段代码:这段代码会把一个被填满的数组里的元素都转移为单向链接结构里的数据。这个操作应保留元素的顺序不变。

    4.5.单向链接结构上的操作

    4.5.1.遍历

    4.5.2.搜索

    4.5.3.替换

    4.5.4.在开始处插入

    4.5.5.在结尾处插入

    4.5.6.在开始处删除

    4.5.7.在结尾处删除

    4.5.8.在任意位置处插入

    4.5.9.在任意位置处删除

    4.5.10.复杂度的权衡:时间、空间和单向链接结构

    4.5.11.练习题

    1.假设已经找到了从单向链接结构里删除元素的位置,请说明从这个时候开始完成删除操作的运行时复杂度。

    2.可以对单向链接结构里按顺序排列的元素执行二分搜索吗?如果不可以,为什么?

    3.请说明为什么Python列表会使用数组而不是链接结构来保存它的元素。

    4.6.链接上的变化

    4.6.1.包含虚拟头节点的环状链接结构

    4.6.2.双向链接结构

    4.6.3.练习题

    1.包含虚拟头节点的环状链接结构给程序员带来了什么好处?

    2.和单向链接结构相比,请描述双向链接结构的一个好处和一个额外开销。

    4.7.小结

    • 数据结构是一个表示多项集里所包含数据的对象。
    • 数组是一种在常数时间内支持对位置逐项随机访问的数据结构。在创建数组时,会为它分配若干个用来存放数据的内存空间,并且数组的长度会保持不变。插入和删除操作需要移动数据元素,并且可能需要创建一个新的、更大或更小的数组。
    • 二维数组里的每个数据值都位于矩形网格的行和列上。
    • 链接结构是由0个或多个节点组成的数据结构。每个节点都包含一个数据元素和一个或多个指向其他节点的链接。
    • 单向链接结构的节点包含数据元素和到下一个节点的链接。双向链接结构里的节点还包含到前一个节点的链接。
    • 在链接结构里进行插入或删除操作不需要移动数据元素,每次最多只会创建一个节点。但是,在链接结构里执行插入、删除和访问操作需要的时间复杂度都是线性的。
    • 在链接结构里使用头节点可以简化某些操作,如添加或删除元素。

    4.8.复习题

    1.数组和链接结构都是:

    • 抽象数据类型(ADT)
    • 数据结构

    2.数组的长度:

    • 在创建之后大小是固定的
    • 在创建之后大小可以增加或减少

    3.在数组里进行随机访问支持在:

    • 常数时间里访问数据
    • 线性时间里访问数据

    4.单向链接结构里的数据包含在:

    • 单元里
    • 节点里

    5.对单向链接结构执行的大多数操作都需要:

    • 常数时间
    • 线性时间

    6.从以下哪种类型里删除第一个元素需要常数时间:

    • 数组
    • 单向链接结构

    7.在下面哪种情况下,数组里使用的内存会少于单向链接结构的:

    • 不到一半的位置放置了数据
    • 一半以上的位置放置了数据

    8.当数组的内存不足以保存数据时,最好创建一个新的数组,这个新数组应该:

    • 大小比旧数组多1个位置
    • 大小是旧数组的2倍

    9.对于单向链接结构,当你在什么地方执行插入操作会得到最坏情况下的运行时:

    • 在结构的开头
    • 在结构的末尾

    10.双向链接结构让程序员可以移动到:

    • 给定节点的后一个节点或前一个节点
    • 给定节点的后一个节点

    4.9.编程练习

    在前6个项目里,你将修改在本章定义的Array类,从而让它更像Python的list类。对于这些项目的答案,请包含你对Array类所做修改的代码测试。

    1.为Array类添加一个实例变量logicalSize。这个变量的初始值为0,用来记录数组里当前已经包含的元素数量。然后为Array类添加size()方法,这个方法用来返回数组的逻辑尺寸。__len__方法依然会返回数组的容量,也就是它的物理尺寸。

    2.为Array类的__getitem__和__setitem__方法添加先验条件。它们的先验条件是0<=index < size()。如果不满足先验条件,就引发异常。

    3.将growshrink方法添加到Array类。它们能够基于本章所讨论的策略来增加或减少数组里所包含的列表长度。在实现时,要保证数组的物理尺寸不会缩小到用户指定的容量之下,并且在增加数组尺寸时,数组的内存单元将会用默认值来填充。

    4.将方法insertpop添加到Array类中。它们基于本章已经讨论过的策略,在需要的时候对数组的长度进行调整。insert方法会接收一个位置和一个元素值作为参数,然后把这个元素插入指定的位置。如果位置大于或等于数组的逻辑尺寸,那么这个方法会把元素插入数组里当前可获得的最后一个元素之后。pop方法会接收一个位置作为参数,然后删除并返回这个位置的元素。pop方法的先验条件是0<=index < size()pop方法还应该把腾出来的数组内存单元重置为填充值。

    5.将方法__eq__添加到Array类中。当Array对象作为==运算符的左操作数时,Python会运行这个方法。如果这个方法的参数也是一个Array对象,并且它的逻辑尺寸和左操作数相同,且在两个数组里每个逻辑位置上的元素都相等,那么这个方法会返回True;否则,这个方法返回False

    6.为了让Array类和列表一样,应该删除__iter__方法的当前实现。请解释这为什么是一个好建议,并说明在这个情况下应该如何对__str__方法进行修改。

    7.Matrix类可以执行线性代数里的某些运算,比如矩阵运算。开发一个使用内置运算符进行算术运算的Matrix类,这个Matrix类应扩展自Grid类。在接下来的4个项目里,你应定义一些用来操作链接结构的函数。在解答的过程中,你应该继续使用本章定义的NodeTwoWayNode类。创建一个测试模块以包含你的函数定义和用来测试它们的代码。

    8.定义一个叫作length的函数(不是len),这个函数会接受一个单向链接结构作为参数,并能够返回结构里的元素数量。

    9.定义一个叫作insert的函数,这个函数具有把元素插入单向链接结构中指定位置的功能。这个函数有3个参数:元素、位置以及一个链接结构(这个链接结构可能为空)。这个函数能够返回修改之后的链接结构。如果传递的位置大于或等于链接结构的长度,那么这个函数会把元素插入它的末尾。这个函数的调用示例是head =insert(1,data,head),其中head是一个变量,这个变量要么为空链接,要么指向链接结构的第一个节点。

    10.定义一个叫作pop的函数,这个函数能够在单向链接结构的指定位置上删除元素。这个函数的第一个参数是位置,它的先验条件是0<=position<结构的长度。它的第二个参数是一个链接结构,很明显它不应该为空。这个函数将会返回一个元组,包含修改后的链接结构和删除的元素。它的调用示例是(head, item) = pop(1,head)

    11.定义一个函数makeTwoWay,这个函数会接受一个单向链接结构作为参数,然后生成并返回一个包含单向链接结构里的元素的双向链接结构。(注意:这个函数不应该对作为参数的链接结构进行任何修改。)

    \ No newline at end of file +

    5.编写一段代码以创建一个参差不齐的网格,它的行分别用来存储3个、6个和9个元素。

    6.提供一个把Grid类用作数据结构来实现三维array类的策略。

    7.编写一段代码:这段代码会把三维数组里每个单元的值都初始化为它的3个索引位置。例如,如果位置是(深度、行、列),则对于位置(2、3、3)来说,它的值就是233。

    8.编写一段代码:这段代码可以显示出三维数组里的所有元素。打印出的每一行数据都应该代表给定行和列里的所有元素,而深度将从第一个位置向后递归到最后一个位置。遍历应该从第1行、第1列以及第一个深度位置开始,依次遍历所有的深度、列和行。

    4.4.链接结构

    4.4.1.单向链接结构和双向链接结构

    4.4.2.非连续内存和节点

    4.4.3.定义单向链接节点类

    4.4.4.使用单向链接节点类

    4.4.5.练习题

    1.用框和指针绘制测试程序里第一个循环所创建的节点的示意图。

    2.当节点变量引用的是None时,如果程序员尝试访问节点的数据字段,则会发生什么?如何防止这种情况的发生?

    3.编写一段代码:这段代码会把一个被填满的数组里的元素都转移为单向链接结构里的数据。这个操作应保留元素的顺序不变。

    4.5.单向链接结构上的操作

    4.5.1.遍历

    4.5.2.搜索

    4.5.3.替换

    4.5.4.在开始处插入

    4.5.5.在结尾处插入

    4.5.6.在开始处删除

    4.5.7.在结尾处删除

    4.5.8.在任意位置处插入

    4.5.9.在任意位置处删除

    4.5.10.复杂度的权衡:时间、空间和单向链接结构

    4.5.11.练习题

    1.假设已经找到了从单向链接结构里删除元素的位置,请说明从这个时候开始完成删除操作的运行时复杂度。

    2.可以对单向链接结构里按顺序排列的元素执行二分搜索吗?如果不可以,为什么?

    3.请说明为什么Python列表会使用数组而不是链接结构来保存它的元素。

    4.6.链接上的变化

    4.6.1.包含虚拟头节点的环状链接结构

    4.6.2.双向链接结构

    4.6.3.练习题

    1.包含虚拟头节点的环状链接结构给程序员带来了什么好处?

    2.和单向链接结构相比,请描述双向链接结构的一个好处和一个额外开销。

    4.7.小结

    • 数据结构是一个表示多项集里所包含数据的对象。
    • 数组是一种在常数时间内支持对位置逐项随机访问的数据结构。在创建数组时,会为它分配若干个用来存放数据的内存空间,并且数组的长度会保持不变。插入和删除操作需要移动数据元素,并且可能需要创建一个新的、更大或更小的数组。
    • 二维数组里的每个数据值都位于矩形网格的行和列上。
    • 链接结构是由0个或多个节点组成的数据结构。每个节点都包含一个数据元素和一个或多个指向其他节点的链接。
    • 单向链接结构的节点包含数据元素和到下一个节点的链接。双向链接结构里的节点还包含到前一个节点的链接。
    • 在链接结构里进行插入或删除操作不需要移动数据元素,每次最多只会创建一个节点。但是,在链接结构里执行插入、删除和访问操作需要的时间复杂度都是线性的。
    • 在链接结构里使用头节点可以简化某些操作,如添加或删除元素。

    4.8.复习题

    1.数组和链接结构都是:

    • 抽象数据类型(ADT)
    • 数据结构

    2.数组的长度:

    • 在创建之后大小是固定的
    • 在创建之后大小可以增加或减少

    3.在数组里进行随机访问支持在:

    • 常数时间里访问数据
    • 线性时间里访问数据

    4.单向链接结构里的数据包含在:

    • 单元里
    • 节点里

    5.对单向链接结构执行的大多数操作都需要:

    • 常数时间
    • 线性时间

    6.从以下哪种类型里删除第一个元素需要常数时间:

    • 数组
    • 单向链接结构

    7.在下面哪种情况下,数组里使用的内存会少于单向链接结构的:

    • 不到一半的位置放置了数据
    • 一半以上的位置放置了数据

    8.当数组的内存不足以保存数据时,最好创建一个新的数组,这个新数组应该:

    • 大小比旧数组多1个位置
    • 大小是旧数组的2倍

    9.对于单向链接结构,当你在什么地方执行插入操作会得到最坏情况下的运行时:

    • 在结构的开头
    • 在结构的末尾

    10.双向链接结构让程序员可以移动到:

    • 给定节点的后一个节点或前一个节点
    • 给定节点的后一个节点

    4.9.编程练习

    在前6个项目里,你将修改在本章定义的Array类,从而让它更像Python的list类。对于这些项目的答案,请包含你对Array类所做修改的代码测试。

    1.为Array类添加一个实例变量logicalSize。这个变量的初始值为0,用来记录数组里当前已经包含的元素数量。然后为Array类添加size()方法,这个方法用来返回数组的逻辑尺寸。__len__方法依然会返回数组的容量,也就是它的物理尺寸。

    2.为Array类的__getitem__和__setitem__方法添加先验条件。它们的先验条件是0<=index < size()。如果不满足先验条件,就引发异常。

    3.将growshrink方法添加到Array类。它们能够基于本章所讨论的策略来增加或减少数组里所包含的列表长度。在实现时,要保证数组的物理尺寸不会缩小到用户指定的容量之下,并且在增加数组尺寸时,数组的内存单元将会用默认值来填充。

    4.将方法insertpop添加到Array类中。它们基于本章已经讨论过的策略,在需要的时候对数组的长度进行调整。insert方法会接收一个位置和一个元素值作为参数,然后把这个元素插入指定的位置。如果位置大于或等于数组的逻辑尺寸,那么这个方法会把元素插入数组里当前可获得的最后一个元素之后。pop方法会接收一个位置作为参数,然后删除并返回这个位置的元素。pop方法的先验条件是0<=index < size()pop方法还应该把腾出来的数组内存单元重置为填充值。

    5.将方法__eq__添加到Array类中。当Array对象作为==运算符的左操作数时,Python会运行这个方法。如果这个方法的参数也是一个Array对象,并且它的逻辑尺寸和左操作数相同,且在两个数组里每个逻辑位置上的元素都相等,那么这个方法会返回True;否则,这个方法返回False

    6.为了让Array类和列表一样,应该删除__iter__方法的当前实现。请解释这为什么是一个好建议,并说明在这个情况下应该如何对__str__方法进行修改。

    7.Matrix类可以执行线性代数里的某些运算,比如矩阵运算。开发一个使用内置运算符进行算术运算的Matrix类,这个Matrix类应扩展自Grid类。在接下来的4个项目里,你应定义一些用来操作链接结构的函数。在解答的过程中,你应该继续使用本章定义的NodeTwoWayNode类。创建一个测试模块以包含你的函数定义和用来测试它们的代码。

    8.定义一个叫作length的函数(不是len),这个函数会接受一个单向链接结构作为参数,并能够返回结构里的元素数量。

    9.定义一个叫作insert的函数,这个函数具有把元素插入单向链接结构中指定位置的功能。这个函数有3个参数:元素、位置以及一个链接结构(这个链接结构可能为空)。这个函数能够返回修改之后的链接结构。如果传递的位置大于或等于链接结构的长度,那么这个函数会把元素插入它的末尾。这个函数的调用示例是head =insert(1,data,head),其中head是一个变量,这个变量要么为空链接,要么指向链接结构的第一个节点。

    10.定义一个叫作pop的函数,这个函数能够在单向链接结构的指定位置上删除元素。这个函数的第一个参数是位置,它的先验条件是0<=position<结构的长度。它的第二个参数是一个链接结构,很明显它不应该为空。这个函数将会返回一个元组,包含修改后的链接结构和删除的元素。它的调用示例是(head, item) = pop(1,head)

    11.定义一个函数makeTwoWay,这个函数会接受一个单向链接结构作为参数,然后生成并返回一个包含单向链接结构里的元素的双向链接结构。(注意:这个函数不应该对作为参数的链接结构进行任何修改。)

    Back to top
    \ No newline at end of file diff --git a/python/DataStructure/05_InterfacePolymorphism/index.html b/python/DataStructure/05_InterfacePolymorphism/index.html index 35745b9a..e8886803 100644 --- a/python/DataStructure/05_InterfacePolymorphism/index.html +++ b/python/DataStructure/05_InterfacePolymorphism/index.html @@ -1,5 +1,5 @@ - 接口、实现和多态 - UPSkilling

    5.接口、实现和多态

    目标:

    • 为给定的多项集类型开发接口;
    • 按照多项集类型的接口实现多个类;
    • 对给定多项集类型的不同实现评估运行时和内存使用情况的权衡;
    • 实现一个简单的迭代器;
    • 使用方法对包和集合进行操作;
    • 判断包或集合是否适合在给定的应用程序里使用;
    • 将包的实现转换成有序包的实现。

    5.1.开发接口

    5.1.1.设计包接口

    5.1.2.指定参数和返回值

    5.2.构造函数和类的实现

    5.2.1.前置条件、后置条件、异常和文档

    5.2.2.在Python里编写接口

    练习题 1.包里的元素是有序的,还是无序的?

    2.哪些操作会出现在所有多项集的接口里?

    3.哪个方法负责创建多项集对象?

    4.请说出接口与实现分离的3个原因。

    5.3.开发基于数组的实现

    5.3.1.选择并初始化数据结构

    5.3.2.先完成简单的方法

    5.3.3.完成迭代器

    5.3.4.完成使用迭代器的方法

    5.3.5.in运算符和__contains__方法

    5.3.6.完成remove方法

    5.3.7.练习题

    1.解释多项集类的__init__方法的作用。

    2.为什么调用方法比直接在类里引用实例变量更好?

    3.对于ArrayBag的__init__方法,展示如何通过调用clear方法来简化代码。

    4.解释为什么__iter__方法可能会是多项集类里最有用的方法。

    5.解释为什么在ArrayBag类中不用包含__contains__方法。

    5.4.开发基于链接的实现

    5.4.1.初始化数据结构

    5.4.2.完成迭代器

    5.4.3.完成clear和add方法

    5.4.4.完成remove方法

    5.4.5.练习题

    1.假设a是一个数组包,b是一个链接包,它们都不包含任何元素。请描述在这种情况下它们在内存使用上的差异。

    2.为什么链接包仍然需要一个单独的实例变量来记录它的逻辑尺寸?

    3.为什么从链接包里删除元素之后,程序员不用担心出现内存浪费的情况?

    5.5.两种包实现的运行时性能

    5.6.测试包的两种实现

    5.7.使用UML绘制包资源

    5.8.小结

    • 接口是用户的软件资源可以使用的一组操作。
    • 接口里的元素是函数和方法的定义以及它们的文档。
    • 前置条件是指在函数或方法可以正确完成任务之前必须要满足的条件。
    • 后置条件是指在函数或方法正确完成任务之后必须为真的条件。
    • 设计良好的软件系统会把接口和它的实现分开。
    • 实现是指满足接口的函数、方法或类。
    • 多项集类型可以通过接口进行指定。
    • 多项集类型可以有几个不同的实现类。
    • 多态是指在两个或多个实现里使用相同的运算符、函数名称或方法名称。多态函数的示例是strlen;多态运算符的示例是+==;多态方法的示例包括add和isEmpty
    • 包多项集类型是无序的,并且支持添加、删除和访问其元素等操作。
    • 类图是一种描述类与类之间关系的可视化表示方法。
    • 组合表示两个类之间整体与局部的关系。
    • 聚合表示两个类之间一对多的关系。
    • UML是一种描述软件资源之间关系的可视化表示方法。

    5.9.复习题

    1.包是:

    • 线性多项集
    • 无序多项集

    2.用来设置对象实例变量的初始状态的方法是:

    • __init__方法
    • __str__方法

    3.让程序员可以访问多项集里所有元素的方法是:

    • __init__方法
    • __iter__方法

    4.改变对象内部状态的方法是:

    • 访问器方法
    • 变异器方法

    5.一组可以被类的客户端使用的方法集称为:

    • 实现
    • 接口

    6.多态用来代表的术语是:

    • 多个类里相同的方法名称
    • 用来存储另一个类里所包含数据的类

    7.组合是指:

    • 两个类之间部分与整体关系
    • 两个类之间多对一关系

    8.包中add方法的平均运行时为:

    • O(n)
    • O(k)

    9.包中remove方法的平均运行时为:

    • O(n)
    • O(k)

    10.在什么情况下,数组包实现会比链接包实现使用更少的内存:

    • 含有少于一半的数据
    • 含有一半以上的数据

    5.10.编程练习

    1.对于两个包实现,确定==操作的运行时。可以预见到,这里有几种情况需要分析。

    2.对于包的两个实现,确定+运算符的运行时。

    3.编码ArrayBagadd方法的代码,从而可以在需要的时候对数组尺寸进行调整。

    4.编码ArrayBagremove方法的代码,从而可以在需要的时候对数组尺寸进行调整。

    5.在ArrayBagLinkedBag类里添加clone方法。这个方法在调用的时候,不会接收任何参数,并且会返回当前包类型的一个完整副本。在下面这段代码的最后,变量bag2将包含数字234

    bag1 = ArrayBag([2,3,4])
    + 接口、实现和多态 - UPSkilling       

    5.接口、实现和多态

    目标:

    • 为给定的多项集类型开发接口;
    • 按照多项集类型的接口实现多个类;
    • 对给定多项集类型的不同实现评估运行时和内存使用情况的权衡;
    • 实现一个简单的迭代器;
    • 使用方法对包和集合进行操作;
    • 判断包或集合是否适合在给定的应用程序里使用;
    • 将包的实现转换成有序包的实现。

    5.1.开发接口

    5.1.1.设计包接口

    5.1.2.指定参数和返回值

    5.2.构造函数和类的实现

    5.2.1.前置条件、后置条件、异常和文档

    5.2.2.在Python里编写接口

    练习题 1.包里的元素是有序的,还是无序的?

    2.哪些操作会出现在所有多项集的接口里?

    3.哪个方法负责创建多项集对象?

    4.请说出接口与实现分离的3个原因。

    5.3.开发基于数组的实现

    5.3.1.选择并初始化数据结构

    5.3.2.先完成简单的方法

    5.3.3.完成迭代器

    5.3.4.完成使用迭代器的方法

    5.3.5.in运算符和__contains__方法

    5.3.6.完成remove方法

    5.3.7.练习题

    1.解释多项集类的__init__方法的作用。

    2.为什么调用方法比直接在类里引用实例变量更好?

    3.对于ArrayBag的__init__方法,展示如何通过调用clear方法来简化代码。

    4.解释为什么__iter__方法可能会是多项集类里最有用的方法。

    5.解释为什么在ArrayBag类中不用包含__contains__方法。

    5.4.开发基于链接的实现

    5.4.1.初始化数据结构

    5.4.2.完成迭代器

    5.4.3.完成clear和add方法

    5.4.4.完成remove方法

    5.4.5.练习题

    1.假设a是一个数组包,b是一个链接包,它们都不包含任何元素。请描述在这种情况下它们在内存使用上的差异。

    2.为什么链接包仍然需要一个单独的实例变量来记录它的逻辑尺寸?

    3.为什么从链接包里删除元素之后,程序员不用担心出现内存浪费的情况?

    5.5.两种包实现的运行时性能

    5.6.测试包的两种实现

    5.7.使用UML绘制包资源

    5.8.小结

    • 接口是用户的软件资源可以使用的一组操作。
    • 接口里的元素是函数和方法的定义以及它们的文档。
    • 前置条件是指在函数或方法可以正确完成任务之前必须要满足的条件。
    • 后置条件是指在函数或方法正确完成任务之后必须为真的条件。
    • 设计良好的软件系统会把接口和它的实现分开。
    • 实现是指满足接口的函数、方法或类。
    • 多项集类型可以通过接口进行指定。
    • 多项集类型可以有几个不同的实现类。
    • 多态是指在两个或多个实现里使用相同的运算符、函数名称或方法名称。多态函数的示例是strlen;多态运算符的示例是+==;多态方法的示例包括add和isEmpty
    • 包多项集类型是无序的,并且支持添加、删除和访问其元素等操作。
    • 类图是一种描述类与类之间关系的可视化表示方法。
    • 组合表示两个类之间整体与局部的关系。
    • 聚合表示两个类之间一对多的关系。
    • UML是一种描述软件资源之间关系的可视化表示方法。

    5.9.复习题

    1.包是:

    • 线性多项集
    • 无序多项集

    2.用来设置对象实例变量的初始状态的方法是:

    • __init__方法
    • __str__方法

    3.让程序员可以访问多项集里所有元素的方法是:

    • __init__方法
    • __iter__方法

    4.改变对象内部状态的方法是:

    • 访问器方法
    • 变异器方法

    5.一组可以被类的客户端使用的方法集称为:

    • 实现
    • 接口

    6.多态用来代表的术语是:

    • 多个类里相同的方法名称
    • 用来存储另一个类里所包含数据的类

    7.组合是指:

    • 两个类之间部分与整体关系
    • 两个类之间多对一关系

    8.包中add方法的平均运行时为:

    • O(n)
    • O(k)

    9.包中remove方法的平均运行时为:

    • O(n)
    • O(k)

    10.在什么情况下,数组包实现会比链接包实现使用更少的内存:

    • 含有少于一半的数据
    • 含有一半以上的数据

    5.10.编程练习

    1.对于两个包实现,确定==操作的运行时。可以预见到,这里有几种情况需要分析。

    2.对于包的两个实现,确定+运算符的运行时。

    3.编码ArrayBagadd方法的代码,从而可以在需要的时候对数组尺寸进行调整。

    4.编码ArrayBagremove方法的代码,从而可以在需要的时候对数组尺寸进行调整。

    5.在ArrayBagLinkedBag类里添加clone方法。这个方法在调用的时候,不会接收任何参数,并且会返回当前包类型的一个完整副本。在下面这段代码的最后,变量bag2将包含数字234

    bag1 = ArrayBag([2,3,4])
     bag2 = bag1.clone()
     bag1 == bag2    # Returns True
     bag1 is bag2    # Returns False
    -

    6.集合是一个无序多项集,并且和包具有相同的接口。但是在集合里,元素是唯一的,而包里可以包含重复的物品。定义一个基于数组的叫作ArraySet的多项集新类。如果集合里的元素已经存在了,那么add方法将会忽略这个元素。

    7.使用链接节点定义一个叫作LinkedSet的多项集新类来实现集合类型。如果集合里的元素已经存在了,那么add方法将会忽略这个元素。

    8.有序包的行为和普通包的是一样的,但是它能够让用户在使用for循环时按照升序访问里面的元素。因此,添加到这个包类型里的元素,都必须具有一定的顺序并且支持比较运算符。这种类型元素的简单例子是:字符串和整数。定义一个支持这个功能的叫作ArraySortedBag的新类。和ArrayBag一样,这个新类会基于数组,但是它的in操作现在可以在对数时间里运行。要完成这一点,ArraySortedBag必须将新添加的元素按照顺序放到数组里。最简单的办法是修改add方法,从而让新元素插入适当的位置;然后,添加__contains__方法来提供新的且更有效的搜索;最后,要把对ArrayBag的所有引用都替换为ArraySortedBag。(提示:把代码从ArrayBag类中复制到一个新文件里,然后在这个新文件里开始修改。)

    9.确定ArraySortedBagadd方法的运行时。

    10.Python的for循环可以让程序员在循环迭代多项集的时候对它执行添加或删除元素的操作。一些设计人员担心在迭代过程中对多项集的结构进行修改可能会导致程序崩溃。有一种修改策略是通过禁止在迭代期间对多项集进行变异来让for循环成为只读。你可以通过对变异操作进行计数,并且判断这个计数有没有在多项集的__iter__方法的任意节拍中被增加来检测这种类型的变异。当发生这种情况时,就可以引发异常从而避免计算的继续进行。把这个机制添加到ArrayBag类里。可以添加一个叫作modCount的新实例变量,这个实例变量会在__init__方法里设置为0;然后,每个变异器方法都会递增这个变量;最后,__iter__方法有一个叫作modCount的临时变量,这个临时变量的初始值是实例变量self.modCount的值。在__iter__方法里返回一个元素后,如果这两个修改过的计数器值不相等,就立即引发异常。用一个程序来测试你的修改,从而保证满足相应的需求。

    \ No newline at end of file +

    6.集合是一个无序多项集,并且和包具有相同的接口。但是在集合里,元素是唯一的,而包里可以包含重复的物品。定义一个基于数组的叫作ArraySet的多项集新类。如果集合里的元素已经存在了,那么add方法将会忽略这个元素。

    7.使用链接节点定义一个叫作LinkedSet的多项集新类来实现集合类型。如果集合里的元素已经存在了,那么add方法将会忽略这个元素。

    8.有序包的行为和普通包的是一样的,但是它能够让用户在使用for循环时按照升序访问里面的元素。因此,添加到这个包类型里的元素,都必须具有一定的顺序并且支持比较运算符。这种类型元素的简单例子是:字符串和整数。定义一个支持这个功能的叫作ArraySortedBag的新类。和ArrayBag一样,这个新类会基于数组,但是它的in操作现在可以在对数时间里运行。要完成这一点,ArraySortedBag必须将新添加的元素按照顺序放到数组里。最简单的办法是修改add方法,从而让新元素插入适当的位置;然后,添加__contains__方法来提供新的且更有效的搜索;最后,要把对ArrayBag的所有引用都替换为ArraySortedBag。(提示:把代码从ArrayBag类中复制到一个新文件里,然后在这个新文件里开始修改。)

    9.确定ArraySortedBagadd方法的运行时。

    10.Python的for循环可以让程序员在循环迭代多项集的时候对它执行添加或删除元素的操作。一些设计人员担心在迭代过程中对多项集的结构进行修改可能会导致程序崩溃。有一种修改策略是通过禁止在迭代期间对多项集进行变异来让for循环成为只读。你可以通过对变异操作进行计数,并且判断这个计数有没有在多项集的__iter__方法的任意节拍中被增加来检测这种类型的变异。当发生这种情况时,就可以引发异常从而避免计算的继续进行。把这个机制添加到ArrayBag类里。可以添加一个叫作modCount的新实例变量,这个实例变量会在__init__方法里设置为0;然后,每个变异器方法都会递增这个变量;最后,__iter__方法有一个叫作modCount的临时变量,这个临时变量的初始值是实例变量self.modCount的值。在__iter__方法里返回一个元素后,如果这两个修改过的计数器值不相等,就立即引发异常。用一个程序来测试你的修改,从而保证满足相应的需求。

    Back to top
    \ No newline at end of file diff --git a/python/DataStructure/06_InheritanceAbstractClass/index.html b/python/DataStructure/06_InheritanceAbstractClass/index.html index 09744fe9..37466f97 100644 --- a/python/DataStructure/06_InheritanceAbstractClass/index.html +++ b/python/DataStructure/06_InheritanceAbstractClass/index.html @@ -1 +1 @@ - 继承与抽象类 - UPSkilling

    继承与抽象类

    \ No newline at end of file + 继承与抽象类 - UPSkilling

    继承与抽象类

    Back to top
    \ No newline at end of file diff --git a/python/DataStructure/code/tmp.py b/python/DataStructure/code/tmp.py index 955b0497..2068db55 100644 --- a/python/DataStructure/code/tmp.py +++ b/python/DataStructure/code/tmp.py @@ -1,81 +1,270 @@ class Array(object): - """ - 描述一个数组。 - 数组类似列表,但数组只能使用[], len, iter, 和 str这些属性。 - 实例化一个数组,使用 = Array(, ) 其中fill value默认值是None。 - """ + """描述一个数组。""" def __init__(self, capacity, fillValue=None): """Capacity是数组的大小. fillValue会填充在每个元素位置, 默认值是None""" + # 初始化数组的逻辑尺寸和物理尺寸 + self.logicalSize = 0 + self.capacity = capacity + self.fillValue = fillValue + #初始化内部数组,并填充元素值 self.items = list() for count in range(capacity): self.items.append(fillValue) def __len__(self): - """-> 数组的大小""" + """返回数组的大小""" return len(self.items) def __str__(self): - """-> 将数组字符串化""" - return str(self.items) + """将数组字符串化并返回""" + result = "" + for index in range(self.size()): + result += str(self.items[index]) + " " + return result + + def size(self): + """返回数组的逻辑尺寸""" + return self.logicalSize def __iter__(self): """支持for循环对数组进行遍历.""" + print("__iter__ called") # 仅用来测试何时__iter__会被调用 return iter(self.items) def __getitem__(self, index): - """用于访问索引处的下标运算符.""" + """ + 用于访问索引处的下标运算符. + 先决条件: 0 <= index < size() + """ + if index < 0 or index >= self.size(): + raise IndexError("读取操作出错, 数组索引越界(不在数组逻辑边界范围内)") + return self.items[index] def __setitem__(self, index, newItem): - """下标运算符用于在索引处进行替换.""" + """ + 下标运算符用于在索引处进行替换. + 先决条件: 0 <= index < size() + """ + if index < 0 or index >= self.size(): + raise IndexError("更新操作出错, 数组索引越界(不在数组逻辑边界范围内)") self.items[index] = newItem + def __eq__(self, other): + """ + 两个数组相等则返回True,否则返回False + """ + # 判断两个数组是否是同一个对象,注意,不是它们的值是否相等 + if self is other: + return True + # 判断两个对象类型是否一样 + if type(self) != type(other): + return False + # 判断两个数组大小是否一样 + if self.size() != other.size(): + return False + # 比较两个数组的值是否一样 + for index in range(self.size()): + if self[index] != other[index]: + return False + return True + + def grow(self): + """增大数组物理尺寸""" + # 基于当前物理尺寸加倍,并将fillValue赋值底层列表的新元素 + for count in range(len(self)): + self.items.append(self.fillValue) + + def insert(self, index, newItem): + """在数组指定索引处插入新元素""" + # 当数组的物理尺寸和逻辑尺寸一样时,则增加物理尺寸 + if self.size() == len(self): + self.grow() + # 插入新元素 + # 当插入位置大于或等于最大逻辑位置,则在数组末端插入新元素 + # 当插入位置介于数组逻辑位置的中间,则从插入位置起将剩余数组元素向尾部平移一个位置 + if index >= self.size(): + self.items[self.size()] = newItem + else: + index = max(index, 0) + + # 将数组元素向尾部平移一个位置 + for i in range(self.size(), index, -1): + self.items[i] = self.items[i - 1] + + # 插入新元素 + self.items[index] = newItem + + # 增加数组的逻辑尺寸 + self.logicalSize += 1 + + def shrink(self): + """ + 减少数组的物理尺寸 + 当: + - 数组的逻辑尺寸小于或等于其物理尺寸的1/4 + - 并且它的物理尺寸至少是这个数组建立时默认容量的2倍时 + 则把数组的物理尺寸减小到原来的一半,并且也不会小于其默认容量 + """ + # 在逻辑尺寸和物理尺寸的一半之间选择最大值作为数组收缩后的物理尺寸 + newSize = max(self.capacity, len(self) // 2) + # 释放多余的数组空间 + for count in range(len(self) - newSize): + self.items.pop() + + def pop(self, index): + """ + 删除指定索引值的数组元素,并返回删除的数组元素值 + 先决条件: 0 <= index < size() + """ + if index < 0 or index >= self.size(): + raise IndexError("删除操作出错, 数组索引越界(不在数组逻辑边界范围内)") + + # 保存即将被删除的数组元素值 + itemToReturn = self.items[index] + + # 将数组元素向头部平移一个位置 + for i in range(index, self.size() - 1): + self.items[i] = self.items[i + 1] + + # 将数组尾部的空余位赋值fillValue,默认是None + self.items[self.size() - 1] = self.fillValue + + # 减少数组逻辑尺寸 + self.logicalSize -= 1 + + # 减少数组物理尺寸 + # 当: + # - 数组的逻辑尺寸小于或等于其物理尺寸的1/4 + # - 并且它的物理尺寸至少是这个数组建立时默认容量的2倍时 + # 则把数组的物理尺寸减小到原来的一半,并且也不会小于其默认容量 + if self.size() <= len(self) // 4 and len(self) > self.capacity: + self.shrink() + + # 返回被删除元素的值 + print(f'Item {itemToReturn} was deleted') + return itemToReturn -def main(size=10): - # 初始值 + +def main(): + # 初始化空数组 DEFAULT_CAPACITY = 5 - logicalSize = 0 - my_array = Array(DEFAULT_CAPACITY) - - # 打印输出初始数组信息 - print("Initial array is: ", my_array) - print("Len of the array: ", my_array.__len__()) - - # 给数组赋值 - for i in range(len(my_array)): - my_array[i] = i - - print("The array is: ", my_array.items) # 打印输出数组 - - # 增大数组物理尺寸 - while logicalSize < DEFAULT_CAPACITY * 2: - logicalSize += 1 - if logicalSize == len(my_array): # 触发条件 - temp = Array(len(my_array) + 1) # 创建一个新数组 - for i in range(logicalSize): - temp[i] = my_array[i] # 从原数组复制内容到新数组 - my_array = temp # 把新数组赋值给原数组 - - print("The array after increased is: ", my_array.items) # 打印输出数组 - - # 减小数组物理尺寸 - while logicalSize > len(my_array) // 4: - logicalSize -= 1 - if logicalSize <= len(my_array) // 4 and len(my_array) >= DEFAULT_CAPACITY * 2: # 触发条件 - temp = Array(len(my_array) // 2) # 创建一个新数组 - for i in range(logicalSize): - temp[i] = my_array[i] # 从原数组复制内容到新数组 - my_array = temp # 把新数组赋值给原数组 - - print("The array after decreased is: ", my_array.items) # 打印输出数组 + my_arr = Array(DEFAULT_CAPACITY) + + # 打印输出数组初始信息 + print("Physical size:", len(my_arr)) + print("Logical size:", my_arr.size()) + print("Initial items:", my_arr.items) + + # 初始化数组元素 + print('------') + for item in range(4): + my_arr.insert(0, item) # 在数组头部插入,每插入一次都需要向后移动已有数组元素 + print("Items(logical):", my_arr) + print("Items(physical):", my_arr.items) + + # 在数组中间插入新元素 + print('------') + my_arr.insert(3, 99) + print("Items(logical):", my_arr) + print("Items(physical):", my_arr.items) + + # 在数组逻辑尺寸外插入新元素 + print('------') + my_arr.insert(20, 88) + print("Items(logical):", my_arr) + print("Items(physical):", my_arr.items) + + # 删除数组元素 + print('------') + my_arr.pop(3) + my_arr.pop(3) + print("Items(logical):", my_arr) + print("Items(physical):", my_arr.items) + + # 清空数组元素 + print('------') + for count in range(my_arr.size()): + my_arr.pop(0) + print("Items(logical):", my_arr) + print("Items(physical):", my_arr.items) + + # 数组元素已经全部删除,逻辑尺寸为零,下面命令返回错误 + # print('------') + # print(my_arr.pop(0)) + + # 数组比较 + # 初始化数组 + print('------') + arr_a = Array(5) + for item in range(4): + arr_a.insert(0, item) + arr_b = arr_a + arr_c = Array(5) + for item in range(4): + arr_c.insert(0, item) + arr_d = [] + + print("arr_a(physical):", arr_a.items) + print("arr_b(physical):", arr_b.items) + print("arr_c(physical):", arr_c.items) + print("arr_d(physical):", arr_d) + + print("arr_a == arr_b:", arr_a == arr_b) + print("arr_a is arr_b:", arr_a is arr_b) + print("arr_a == arr_c:", arr_a == arr_c) + print("arr_a is arr_c:", arr_a is arr_c) + + arr_c.insert(10, 10) + print("arr_a == arr_c:", arr_a == arr_c) + arr_c.pop(arr_c.size() - 1) + arr_c[2] = 6 + print("arr_a == arr_c:", arr_a == arr_c) + + print("arr_a == arr_d:", arr_a == arr_d) + if __name__ == "__main__": main() -# 运行结果: -# Initial array is: [None, None, None, None, None] -# Len of the array: 5 -# The array is: [0, 1, 2, 3, 4] -# The array after increased is: [0, 1, 2, 3, 4, None, None, None, None, None, None] -# The array after decreased is: [0, 1, None, None, None] +# 运行结果 +# Physical size: 5 +# Logical size: 0 +# Initial items: [None, None, None, None, None] +# ------ +# Items(logical): 3 2 1 0 +# Items(physical): [3, 2, 1, 0, None] +# ------ +# Items(logical): 3 2 1 99 0 +# Items(physical): [3, 2, 1, 99, 0] +# ------ +# Items(logical): 3 2 1 99 0 88 +# Items(physical): [3, 2, 1, 99, 0, 88, None, None, None, None] +# ------ +# Item 99 was deleted +# Item 0 was deleted +# Items(logical): 3 2 1 88 +# Items(physical): [3, 2, 1, 88, None, None, None, None, None, None] +# ------ +# Item 3 was deleted +# Item 2 was deleted +# Item 1 was deleted +# Item 88 was deleted +# Items(logical): +# Items(physical): [None, None, None, None, None] +# ------ +# IndexError: 删除操作出错, 数组索引越界(不在数组逻辑边界范围内) +# ------ +# arr_a(physical): [3, 2, 1, 0, None] +# arr_b(physical): [3, 2, 1, 0, None] +# arr_c(physical): [3, 2, 1, 0, None] +# arr_d(physical): [] +# arr_a == arr_b: True +# arr_a is arr_b: True +# arr_a == arr_c: True +# arr_a is arr_c: False +# arr_a == arr_c: False +# Item 10 was deleted +# arr_a == arr_c: False +# arr_a == arr_d: False \ No newline at end of file diff --git a/python/Demo/CourseSystem/index.html b/python/Demo/CourseSystem/index.html index 01c64c51..37e06646 100644 --- a/python/Demo/CourseSystem/index.html +++ b/python/Demo/CourseSystem/index.html @@ -1,4 +1,4 @@ - 选课系统 - UPSkilling

    选课系统

    任务需求

    角色:学校、学员、课程、讲师

    要求:

    1. 创建北京、上海2所学校。
    2. 创建Linux、Python、go三个课程,Linux和Python在北京开,go在上海开。
    3. 课程包含周期、价格,通过学校创建课程。
    4. 通过学校创建班级,班级关联课程、讲师。
    5. 创建讲师。
    6. 创建学员时,选择学校,关联班级。
    7. 创建讲师角色(不需要关联学校)。
    8. 提供两个角色接口。
      1. 学员视图:可以注册,交学费,选择班级。
      2. 讲师视图:讲师可以管理自己的班级,上课时选择班级,查看班级学员列表,修改所管理的学员的成绩。
      3. 管理视图:创建讲师,创建班级,创建课程。
    9. 上述操作所产生的数据通过pickle保存到文件。

    需求分析

    1. 管理视图

      1. 注册
      2. 登录
      3. 创建学校
      4. 创建课程(先选择学校)
      5. 创建讲师
    2. 学员视图

      1. 注册
      2. 登录功能
      3. 选择校区
      4. 选择课程(先选择校区,在选择校区中的某一门课程,选择课程即选择班级)
        • 学生选择课程,课程也选择学生
      5. 查看分数
      6. 交学费
    3. 讲师视图

      1. 登录
      2. 查看教授课程
      3. 选择教授课程
      4. 查看课程下的学生
      5. 修改学生分数

    架构设计(三层架构)

    • 用户视图层
    • 用于与用户进行交互。
    • 实现简单的逻辑判断,比如注册功能中两次密码是否一致的校验。
    • core
      • src.py 主视图
      • admin.py: 管理视图
      • student.py: 学员视图
      • teacher.py: 讲师视图
    • 逻辑接口层
    • 核心业务逻辑的处理
    • interface
      • admin_interface.py
      • studeng_interface.py
      • teacher_interface.py
    • 数据处理层
    • 数据处理,比如增删改查。
    • db
      • models.py
      • db_handler.py
      • pickle保存对象
      • object → pickle

    文件结构

    /--conf/
    + 选课系统 - UPSkilling       

    选课系统

    任务需求

    角色:学校、学员、课程、讲师

    要求:

    1. 创建北京、上海2所学校。
    2. 创建Linux、Python、go三个课程,Linux和Python在北京开,go在上海开。
    3. 课程包含周期、价格,通过学校创建课程。
    4. 通过学校创建班级,班级关联课程、讲师。
    5. 创建讲师。
    6. 创建学员时,选择学校,关联班级。
    7. 创建讲师角色(不需要关联学校)。
    8. 提供两个角色接口。
      1. 学员视图:可以注册,交学费,选择班级。
      2. 讲师视图:讲师可以管理自己的班级,上课时选择班级,查看班级学员列表,修改所管理的学员的成绩。
      3. 管理视图:创建讲师,创建班级,创建课程。
    9. 上述操作所产生的数据通过pickle保存到文件。

    需求分析

    1. 管理视图

      1. 注册
      2. 登录
      3. 创建学校
      4. 创建课程(先选择学校)
      5. 创建讲师
    2. 学员视图

      1. 注册
      2. 登录功能
      3. 选择校区
      4. 选择课程(先选择校区,在选择校区中的某一门课程,选择课程即选择班级)
        • 学生选择课程,课程也选择学生
      5. 查看分数
      6. 交学费
    3. 讲师视图

      1. 登录
      2. 查看教授课程
      3. 选择教授课程
      4. 查看课程下的学生
      5. 修改学生分数

    架构设计(三层架构)

    • 用户视图层
    • 用于与用户进行交互。
    • 实现简单的逻辑判断,比如注册功能中两次密码是否一致的校验。
    • core
      • src.py 主视图
      • admin.py: 管理视图
      • student.py: 学员视图
      • teacher.py: 讲师视图
    • 逻辑接口层
    • 核心业务逻辑的处理
    • interface
      • admin_interface.py
      • studeng_interface.py
      • teacher_interface.py
    • 数据处理层
    • 数据处理,比如增删改查。
    • db
      • models.py
      • db_handler.py
      • pickle保存对象
      • object → pickle

    文件结构

    /--conf/
     |    |--settings.py
     |
     |--core/
    @@ -22,4 +22,4 @@
     |    |--common.py
     |
     |--start.py
    -

    选课系统总结

    1.管理员

    1.1.注册

    1. 用户再视图层输入用户名和密码,交给接口层。
    2. 接口层调用数据层中的models.get()进行校验。
    3. 若不存在则创建,并讲注册成功返回给视图层。

    1.2.登录

    1. 用户在视图层输入用户名和密码,交给接口层。
    2. 接口层调用数据层中的models.get()进行校验。
    3. 若不存在则创建,并讲注册成功返回给视图层。

    1.3.创建学校

    1. 让用户输入学校名和学校地址。
    2. 调用管理员接口创建学校。
    3. 判断学校是否存在,若存在,不创建。
    4. 若不存在,则调用接口层创建学校,获取管理员对象的创建学校方法保持学校对象。
    5. 将结果返回给视图层。

    1.4.创建课程

    1. 获取所有学校,并打印,让用户选择。
    2. 获取用户选择的学校与创建的课程,交给接口层。
    3. 接口层调用管理员对象中的创建课程方法,保存课程对象。
    4. 课程需要绑定给学校对象,最终将创建成功的结果返回给视图层。

    1.5.创建老师

    1. 用户输入老师名称。
    2. 调用接口层,接口层中设置默认密码123,调用数据层。
    3. 判断老师是否存在,不存在则调用管理员对象中的创建老师方法。
    4. 保存老师对象,并将结果返回给视图层。

    2.学生

    2.1.注册

    同上

    2.2.登录

    同上

    2.3.选择学校

    1. 获取所有学校,让学生选择,并将选择的学校传给接口层。
    2. 接口层判断当前学生是否选择学校。
    3. 若没有选择,则调用学生对象中的添加学校方法。
    4. 将添加后消息返回给视图层。

    2.4.选择课程

    1. 先获取当前学生所在学校的所有课程,并选择。
    2. 接口层将选择后的课程,调用数据层的添加课程方法保存。
    3. 学生对象中课程列表添加课程,设置课程分数,默认为0.
    4. 最终将结果返回给视图层。

    2.5.查看成绩

    1. 直接调用接口层。
    2. 接口层调用数据层中的查看成绩方法。
    3. 返回成绩给视图层并打印。

    3.老师

    3.1.登录

    同上

    3.2.查看教授课程

    1. 直接调用接口层,获取老师对象下课程列表数据。
    2. 若有则打印,没有则退出。

    3.3.选择教授课程

    1. 调用接口层中的选择教授课程接口,调用数据层中改课程下所有的学生,返回给视图层。
    2. 打印所有的课程,让老师选择,若老师课程中有该课程则不添加。
    3. 没有,则嗲用老师对象中的添加课程方法进行添加。

    3.4.查看课程下的学生

    1. 直接获取老师对象下所有的课程,选择课程。
    2. 从老师对象中,调用查看课程下学生的方法,获取课程对象下的所有学生,返回给视图层。
    3. 视图层打印该课程下所有的学生。

    3.5.修改学生分数

    1. 直接获取老师对象下所有的课程。
    2. 从老师对象中,调用查看课程下学生方法,获取课程对象下所有的学生,返回给视图层。
    3. 视图层打印改课程下所有的学生,并让用户选择需要分数的学生。
    4. 嗲用老师修改分数接口,获取老师对象,调用对象中修改分数方法。
    5. 获取学生对象中的分数字典,进行修改。

    3.4.查看成绩

    示意图

    课程系统示意图

    参考代码

    代码

    \ No newline at end of file +

    选课系统总结

    1.管理员

    1.1.注册

    1. 用户再视图层输入用户名和密码,交给接口层。
    2. 接口层调用数据层中的models.get()进行校验。
    3. 若不存在则创建,并讲注册成功返回给视图层。

    1.2.登录

    1. 用户在视图层输入用户名和密码,交给接口层。
    2. 接口层调用数据层中的models.get()进行校验。
    3. 若不存在则创建,并讲注册成功返回给视图层。

    1.3.创建学校

    1. 让用户输入学校名和学校地址。
    2. 调用管理员接口创建学校。
    3. 判断学校是否存在,若存在,不创建。
    4. 若不存在,则调用接口层创建学校,获取管理员对象的创建学校方法保持学校对象。
    5. 将结果返回给视图层。

    1.4.创建课程

    1. 获取所有学校,并打印,让用户选择。
    2. 获取用户选择的学校与创建的课程,交给接口层。
    3. 接口层调用管理员对象中的创建课程方法,保存课程对象。
    4. 课程需要绑定给学校对象,最终将创建成功的结果返回给视图层。

    1.5.创建老师

    1. 用户输入老师名称。
    2. 调用接口层,接口层中设置默认密码123,调用数据层。
    3. 判断老师是否存在,不存在则调用管理员对象中的创建老师方法。
    4. 保存老师对象,并将结果返回给视图层。

    2.学生

    2.1.注册

    同上

    2.2.登录

    同上

    2.3.选择学校

    1. 获取所有学校,让学生选择,并将选择的学校传给接口层。
    2. 接口层判断当前学生是否选择学校。
    3. 若没有选择,则调用学生对象中的添加学校方法。
    4. 将添加后消息返回给视图层。

    2.4.选择课程

    1. 先获取当前学生所在学校的所有课程,并选择。
    2. 接口层将选择后的课程,调用数据层的添加课程方法保存。
    3. 学生对象中课程列表添加课程,设置课程分数,默认为0.
    4. 最终将结果返回给视图层。

    2.5.查看成绩

    1. 直接调用接口层。
    2. 接口层调用数据层中的查看成绩方法。
    3. 返回成绩给视图层并打印。

    3.老师

    3.1.登录

    同上

    3.2.查看教授课程

    1. 直接调用接口层,获取老师对象下课程列表数据。
    2. 若有则打印,没有则退出。

    3.3.选择教授课程

    1. 调用接口层中的选择教授课程接口,调用数据层中改课程下所有的学生,返回给视图层。
    2. 打印所有的课程,让老师选择,若老师课程中有该课程则不添加。
    3. 没有,则嗲用老师对象中的添加课程方法进行添加。

    3.4.查看课程下的学生

    1. 直接获取老师对象下所有的课程,选择课程。
    2. 从老师对象中,调用查看课程下学生的方法,获取课程对象下的所有学生,返回给视图层。
    3. 视图层打印该课程下所有的学生。

    3.5.修改学生分数

    1. 直接获取老师对象下所有的课程。
    2. 从老师对象中,调用查看课程下学生方法,获取课程对象下所有的学生,返回给视图层。
    3. 视图层打印改课程下所有的学生,并让用户选择需要分数的学生。
    4. 嗲用老师修改分数接口,获取老师对象,调用对象中修改分数方法。
    5. 获取学生对象中的分数字典,进行修改。

    3.4.查看成绩

    示意图

    课程系统示意图

    参考代码

    代码

    Back to top
    \ No newline at end of file diff --git a/python/Foundation/Algorithms/index.html b/python/Foundation/Algorithms/index.html index 1be98dde..3da7cf85 100644 --- a/python/Foundation/Algorithms/index.html +++ b/python/Foundation/Algorithms/index.html @@ -1,4 +1,4 @@ - Python数据结构和算法 - UPSkilling

    Python数据结构和算法

    参考书目:

    • "Problem Solving with Algorithms and Data Structures Using Python (Second Edition)" by Bradley N.Miller and David L.Ranum.

    大O记法

    算法分析是一种独立于实现的算法度量方法。

    数量级(order of magnitude)常被称作大O记法(O指order),记作O(f(n))。它提供了步骤数的一个有用的近似方法。f(n)函数为T(n)函数中起决定性作用的部分提供了简单的表示。

    大O记法使得算法可以根据随问题规模增长而起主导作用的部分进行归类。

    异序词检测问题

    如果一个字符串只是重排了另一个字符串的字符,那么这个字符串就是另一个的异序词。

    方案1:清点法

    清点第1个字符串的每个字符,看看它们是否都出现在第2个字符串中。 在字符列表中检查第1个字符串中的每个字符,如果找到了,就替换掉。

    这个方案的时间复杂度是O(n^2)。

    def allotropyWord_1(s1, s2):
    + Python数据结构和算法 - UPSkilling       

    Python数据结构和算法

    参考书目:

    • "Problem Solving with Algorithms and Data Structures Using Python (Second Edition)" by Bradley N.Miller and David L.Ranum.

    大O记法

    算法分析是一种独立于实现的算法度量方法。

    数量级(order of magnitude)常被称作大O记法(O指order),记作O(f(n))。它提供了步骤数的一个有用的近似方法。f(n)函数为T(n)函数中起决定性作用的部分提供了简单的表示。

    大O记法使得算法可以根据随问题规模增长而起主导作用的部分进行归类。

    异序词检测问题

    如果一个字符串只是重排了另一个字符串的字符,那么这个字符串就是另一个的异序词。

    方案1:清点法

    清点第1个字符串的每个字符,看看它们是否都出现在第2个字符串中。 在字符列表中检查第1个字符串中的每个字符,如果找到了,就替换掉。

    这个方案的时间复杂度是O(n^2)。

    def allotropyWord_1(s1, s2):
         list_a = list(s2)
     
         pos1 = 0
    @@ -280,4 +280,4 @@
         simqueue.dequeue()
     
     return simqueue.dequeue()
    -

    if name == 'main': hotPotato(["Bill", "David", "Susan", "Jane", "Ken", "Brad"], 7)

    ```

    运行结果如下,最后只剩Susan。设定不同的num(这里是7)会得到不同的结果。

    python 'Susan'

    打印任务

    双端队列

    列表

    \ No newline at end of file +

    if name == 'main': hotPotato(["Bill", "David", "Susan", "Jane", "Ken", "Brad"], 7)

    ```

    运行结果如下,最后只剩Susan。设定不同的num(这里是7)会得到不同的结果。

    python 'Susan'

    打印任务

    双端队列

    列表

    Back to top
    \ No newline at end of file diff --git a/python/Foundation/ch00/index.html b/python/Foundation/ch00/index.html index 63df1bab..651fd84b 100644 --- a/python/Foundation/ch00/index.html +++ b/python/Foundation/ch00/index.html @@ -1,80 +1,80 @@ - Python安装 - UPSkilling

    Python安装

    Python环境

    这里使用系统自带的Python环境:

    • 主机:VMWare虚拟机
    • 操作系统(Guest):openSUSE 15.3
    • Python版本:3.6.15(openSUSE自带)

    检查Python版本

    $ python --version
    -Python 2.7.18
    + Python安装 - UPSkilling       

    Python安装

    Python环境

    这里使用系统自带的Python环境:

    • 主机:VMWare虚拟机
    • 操作系统(Guest):openSUSE 15.3
    • Python版本:3.6.15(openSUSE自带)

    检查Python版本

    $ python --version
    +Python 2.7.18
     
    -$ python3 --version
    -Python 3.6.15
    -

    升级pip

    $ pip3 install --upgrade pip
    +$ python3 --version
    +Python 3.6.15
    +

    升级pip

    $ pip3 install --upgrade pip
     
    -$ pip --version
    -pip 21.3.1 from /home/james/.local/lib/python3.6/site-packages/pip (python 3.6)
    +$ pip --version
    +pip 21.3.1 from /home/james/.local/lib/python3.6/site-packages/pip (python 3.6)
     
    -$ pip3 --version
    -pip 21.3.1 from /home/james/.local/lib/python3.6/site-packages/pip (python 3.6)
    -

    pip国内源

    安装Python包(指定源)

    pip3 install jinja2 -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install Django -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install sqlite_utils -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install pymongo -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install numpy  -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install matplotlib  -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install scikit-learn  -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install xlrd  -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install pandas  -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install pydotplus  -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install seaborn  -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install selenium  -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install mlxtend  -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install pandas-datareader -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install lxml -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install beautifulsoup4 -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install html5lib -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install tables -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install openpyxl -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install sqlalchemy -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install statsmodels -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install patsy -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install numba -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install jason -i https://mirrors.aliyun.com/pypi/simple/
    -pip3 install openpyxl -i https://mirrors.aliyun.com/pypi/simple/
    -

    源码编译方法

    下面是源码编译方式自行安装Python的方法,以3.9.6版本为例。

    官网下载python3.9.6 (连接

    解压安装包

    tar xvf Python-3.9.6.tgz
    -

    安装路径为 /opt/Python-3.9.6/,需要把安装路径的owner改为当前用户,否则后期python编译以及使用pip安装python包会报错。

    chown -R james.wheel /opt/Python-3.9.6
    -

    在安装前的一些建议

    • 在openSUSE中把开发包都安装一下,特别是c和c++的开发包。这些都是Python编译的依赖包。
    • 在openSUSE中安装sqlite3.
    • 使用openSUSE自带的openSSL,如果自行编译openSSL,在编译Python时会遇到一些未知问题。

    编译和安装:

    cd /opt/Python-3.9.6
    -sudo ./configure --enable-optimizations --with-ensurepip=install
    -sudo make
    -sudo make test
    -sudo make install
    -

    修改系统默认Python的配置,将python3指向新安装的Python。需要修改的路径有2个,/usr/bin/python3/usr/local/bin/

    /usr/bin/python3重新指向新安装的Python。

    sudo rm /usr/bin/python3
    -sudo ln -s /opt/Python-3.9.6/python /usr/bin/python3
    -

    检查/usr/local/bin/目录下的python文件是否指向新安装的Pyton。默认是编译安装完成后已经被修改了。

    $ ls -l /usr/local/bin/python*
    -lrwxrwxrwx 1 root root        9 Jul 25 02:15 python3 -> python3.9
    --rwxr-xr-x 1 root root 17645928 Jul 25 02:14 python3.9
    --rwxr-xr-x 1 root root     3087 Jul 25 02:15 python3.9-config
    -lrwxrwxrwx 1 root root       16 Jul 25 02:15 python3-config -> python3.9-config
    -

    验证python的版本。

    $ python
    -Python 2.7.18 (default, Mar 04 2021, 23:25:57) [GCC] on linux2
    +$ pip3 --version
    +pip 21.3.1 from /home/james/.local/lib/python3.6/site-packages/pip (python 3.6)
    +

    pip国内源

    安装Python包(指定源)

    pip3 install jinja2 -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install Django -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install sqlite_utils -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install pymongo -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install numpy  -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install matplotlib  -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install scikit-learn  -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install xlrd  -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install pandas  -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install pydotplus  -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install seaborn  -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install selenium  -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install mlxtend  -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install pandas-datareader -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install lxml -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install beautifulsoup4 -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install html5lib -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install tables -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install openpyxl -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install sqlalchemy -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install statsmodels -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install patsy -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install numba -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install jason -i https://mirrors.aliyun.com/pypi/simple/
    +pip3 install openpyxl -i https://mirrors.aliyun.com/pypi/simple/
    +

    源码编译方法

    下面是源码编译方式自行安装Python的方法,以3.9.6版本为例。

    官网下载python3.9.6 (连接

    解压安装包

    tar xvf Python-3.9.6.tgz
    +

    安装路径为 /opt/Python-3.9.6/,需要把安装路径的owner改为当前用户,否则后期python编译以及使用pip安装python包会报错。

    chown -R james.wheel /opt/Python-3.9.6
    +

    在安装前的一些建议

    • 在openSUSE中把开发包都安装一下,特别是c和c++的开发包。这些都是Python编译的依赖包。
    • 在openSUSE中安装sqlite3.
    • 使用openSUSE自带的openSSL,如果自行编译openSSL,在编译Python时会遇到一些未知问题。

    编译和安装:

    cd /opt/Python-3.9.6
    +sudo ./configure --enable-optimizations --with-ensurepip=install
    +sudo make
    +sudo make test
    +sudo make install
    +

    修改系统默认Python的配置,将python3指向新安装的Python。需要修改的路径有2个,/usr/bin/python3/usr/local/bin/

    /usr/bin/python3重新指向新安装的Python。

    sudo rm /usr/bin/python3
    +sudo ln -s /opt/Python-3.9.6/python /usr/bin/python3
    +

    检查/usr/local/bin/目录下的python文件是否指向新安装的Pyton。默认是编译安装完成后已经被修改了。

    $ ls -l /usr/local/bin/python*
    +lrwxrwxrwx 1 root root        9 Jul 25 02:15 python3 -> python3.9
    +-rwxr-xr-x 1 root root 17645928 Jul 25 02:14 python3.9
    +-rwxr-xr-x 1 root root     3087 Jul 25 02:15 python3.9-config
    +lrwxrwxrwx 1 root root       16 Jul 25 02:15 python3-config -> python3.9-config
    +

    验证python的版本。

    $ python
    +Python 2.7.18 (default, Mar 04 2021, 23:25:57) [GCC] on linux2
     
    -$ python3
    -Python 3.9.6 (default, Jul 25 2021, 02:13:27) [GCC 7.5.0] on linux
    -

    添加下面的环境变量到配置文件/etc/profile.local

    export PATH=/usr/local/bin:/home/$USER/.local/bin:$PATH
    -

    并执行下面的命令使之生效。

    source /etc/profile.local
    -

    下面修改pip的配置。

    $ whereis pip
    -pip: /usr/bin/pip /usr/bin/pip3.6 /usr/local/bin/pip3.9
    -

    通过下面可以看到pip实际指向的是系统默认的3.6版本。

    $ l /usr/bin/pip*
    -lrwxrwxrwx 1 root root     21 Dec  4  2020 /usr/bin/pip -> /etc/alternatives/pip*
    --rwxr-xr-x 1 root root    367 Dec  4  2020 /usr/bin/pip3*
    --rwxr-xr-x 1 root root    371 Dec  4  2020 /usr/bin/pip3.6*
    --rwxr-xr-x 1 root root  10608 Jun 10 06:15 /usr/bin/pipewire*
    --rwxr-xr-x 1 root root 720208 Jun 10 06:15 /usr/bin/pipewire-media-session*
    +$ python3
    +Python 3.9.6 (default, Jul 25 2021, 02:13:27) [GCC 7.5.0] on linux
    +

    添加下面的环境变量到配置文件/etc/profile.local

    export PATH=/usr/local/bin:/home/$USER/.local/bin:$PATH
    +

    并执行下面的命令使之生效。

    source /etc/profile.local
    +

    下面修改pip的配置。

    $ whereis pip
    +pip: /usr/bin/pip /usr/bin/pip3.6 /usr/local/bin/pip3.9
    +

    通过下面可以看到pip实际指向的是系统默认的3.6版本。

    $ l /usr/bin/pip*
    +lrwxrwxrwx 1 root root     21 Dec  4  2020 /usr/bin/pip -> /etc/alternatives/pip*
    +-rwxr-xr-x 1 root root    367 Dec  4  2020 /usr/bin/pip3*
    +-rwxr-xr-x 1 root root    371 Dec  4  2020 /usr/bin/pip3.6*
    +-rwxr-xr-x 1 root root  10608 Jun 10 06:15 /usr/bin/pipewire*
    +-rwxr-xr-x 1 root root 720208 Jun 10 06:15 /usr/bin/pipewire-media-session*
     
    -james@lizard:/opt> l /etc/alternatives/pip*
    -lrwxrwxrwx 1 root root 15 Jul 24 20:24 /etc/alternatives/pip -> /usr/bin/pip3.6*
    -

    检查一下当前pip在alternative里面的设置。

    $ sudo update-alternatives --display pip
    -pip - auto mode
    -  link best version is /usr/bin/pip3.6
    -  link currently points to /usr/bin/pip3.6
    -  link pip is /usr/bin/pip
    -/usr/bin/pip3.6 - priority 36
    -

    删除老版本,添加新版本。

    $ sudo update-alternatives --remove pip /usr/bin/pip3.6
    +james@lizard:/opt> l /etc/alternatives/pip*
    +lrwxrwxrwx 1 root root 15 Jul 24 20:24 /etc/alternatives/pip -> /usr/bin/pip3.6*
    +

    检查一下当前pip在alternative里面的设置。

    $ sudo update-alternatives --display pip
    +pip - auto mode
    +  link best version is /usr/bin/pip3.6
    +  link currently points to /usr/bin/pip3.6
    +  link pip is /usr/bin/pip
    +/usr/bin/pip3.6 - priority 36
    +

    删除老版本,添加新版本。

    $ sudo update-alternatives --remove pip /usr/bin/pip3.6
     
    -$ sudo update-alternatives --install /usr/bin/pip pip /usr/bin/pip3.9 100
    -update-alternatives: using /usr/bin/pip3.9 to provide /usr/bin/pip (pip) in auto mode
    -
    \ No newline at end of file +$ sudo update-alternatives --install /usr/bin/pip pip /usr/bin/pip3.9 100 +update-alternatives: using /usr/bin/pip3.9 to provide /usr/bin/pip (pip) in auto mode +
    Back to top
    \ No newline at end of file diff --git a/python/Foundation/ch01/index.html b/python/Foundation/ch01/index.html index f2ead6a1..06523660 100644 --- a/python/Foundation/ch01/index.html +++ b/python/Foundation/ch01/index.html @@ -1,4 +1,4 @@ - Python语言基础 - UPSkilling

    Python语言基础

    1. Python数据类型(6个)

    6个Python数据类型:

    • 数值型(number):表示数据组成为数字
    • 整型(int)
      • 十进制
      • 八进制
      • 十六进制
    • 浮点型(float)
    • 布尔型(bool)
    • 复数性(complex)
    • 字符型(string):表示数据组成是字符
    • 列表(list):用来表示一组有序元素,后期数据可以修改 ['A','B','C']
    • 元组(tuple):用来表示一组有序元素,后期数据不可修改 ('A','B','C','1')
    • 集合(set):一组数据无序不重复元素 set([1,2,3,4])
    • 字典(dictionary):用键值对的形式保存一组元素 {'A':7,'B':1,'C':9}

    可迭代对象(Iterable):

    An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an iter() method or with a getitem() method that implements Sequence semantics.

    序列(Sequence):

    An iterable which supports efficient element access using integer indices via the getitem() special method and defines a len() method that returns the length of the sequence. Some built-in sequence types are list, str, tuple, and bytes. Note that dict also supports getitem() and len(), but is considered a mapping rather than a sequence because the lookups use arbitrary immutable keys rather than integers.

    迭代器(Iterator):

    An object representing a stream of data. Repeated calls to the iterator’s next() method (or passing it to the built-in function next()) return successive items in the stream. When no more data are available a StopIteration exception is raised instead. At this point, the iterator object is exhausted and any further calls to its next() method just raise StopIteration again. Iterators are required to have an iter() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a list) produces a fresh new iterator each time you pass it to the iter() function or use it in a for loop. Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container.

    可变数据(immutable)

    • 列表(list)
    • 字典(dictionary)
    • 集合(set)。

    不可变数据(immutable)

    • 数字(number)
    • 字符(string)
    • 元组(tuple)

    可迭代(iterable)

    • 字符(string)
    • 元组(tuple)
    • 列表(list)
    • 字典(dictionary)
    • 集合(set)

    序列

    • 有序序列:字符(string),元组(tuple),列表(list)
    • 无序序列:字典(dictionary),集合(set)

    Python序列类型最常见的分类就是可变和不可变序列。但另外一种分类方式也很有用,那就是把它们分为**扁平序列**和**容器序列**。前者的体积更小、速度更快而且用起来更简单,但是它只能保存一些原子性的数据,比如数字、字符和字节。容器序列则比较灵活,但是当容器序列遇到可变对象时,就需要格外小心,因为这种组合时常会出现一些“意外”,特别是带嵌套的数据结构出现时,更需要验证代码的正确性。

    Python中的变量、常量和字面量

    • 变量
    • 变量是用于在内存中存储数据的命名位置。可以将变量视为保存数据的容器,这些数据可以在后面程序中进行更改。例如:number = 10。从例子中可以看到,Python使用赋值运算符=为变量赋值。
    • 常量
    • 常量也是一种变量,只是其值一旦赋予后无法更改。可以将常量视为保存了以后无法更改的信息的容器。
    • 在Python中,常量通常是在模块中声明和分配的。在这里,模块是一个包含变量,函数等的新文件,该文件被导入到主文件中。在模块内部,用所有大写字母写的常量和下划线将单词分开。实际上,我们不在Python中使用常量。用大写字母命名它们是一种将其与普通变量分开的一种约定,但是,实际上并不能阻止重新分配。
    • 字面量(literal)
    • 字面量是以变量或常量给出的原始数据(其实就是指变量的常数值,字面上所看到的值)。在Python中字面量类型如下:
      • 数字字面量。数字字面量是不可变的(不可更改)。数字字面量可以属于3种不同的数值类型:Integer,Float 和 Complex。例如:float_1 = 10.5是属于Float字面量。
      • 字符串字面量是由引号括起来的一系列字符。我们可以对字符串使用单引号,双引号 或 三引号。并且,字符字面量是用单引号或双引号引起来的单个字符。例如:strings = "This is Python"
      • 布尔字面量。布尔字面量可以具有两个值中的任何一个:TrueFalse。例如:a = True + 4
      • 特殊字面量。Python包含一个特殊字面量,即 None
      • 字面量集。有四种不同的字面量集合:列表字面量,元组字面量,字典字面量 和 集合字面量。

    1.1 数值型(number)

    例子:

    a, b, c, d = 20, 5.5, True, 4+3j
    + Python语言基础 - UPSkilling       

    Python语言基础

    1. Python数据类型(6个)

    6个Python数据类型:

    • 数值型(number):表示数据组成为数字
    • 整型(int)
      • 十进制
      • 八进制
      • 十六进制
    • 浮点型(float)
    • 布尔型(bool)
    • 复数性(complex)
    • 字符型(string):表示数据组成是字符
    • 列表(list):用来表示一组有序元素,后期数据可以修改 ['A','B','C']
    • 元组(tuple):用来表示一组有序元素,后期数据不可修改 ('A','B','C','1')
    • 集合(set):一组数据无序不重复元素 set([1,2,3,4])
    • 字典(dictionary):用键值对的形式保存一组元素 {'A':7,'B':1,'C':9}

    可迭代对象(Iterable):

    An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an iter() method or with a getitem() method that implements Sequence semantics.

    序列(Sequence):

    An iterable which supports efficient element access using integer indices via the getitem() special method and defines a len() method that returns the length of the sequence. Some built-in sequence types are list, str, tuple, and bytes. Note that dict also supports getitem() and len(), but is considered a mapping rather than a sequence because the lookups use arbitrary immutable keys rather than integers.

    迭代器(Iterator):

    An object representing a stream of data. Repeated calls to the iterator’s next() method (or passing it to the built-in function next()) return successive items in the stream. When no more data are available a StopIteration exception is raised instead. At this point, the iterator object is exhausted and any further calls to its next() method just raise StopIteration again. Iterators are required to have an iter() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a list) produces a fresh new iterator each time you pass it to the iter() function or use it in a for loop. Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container.

    可变数据(immutable)

    • 列表(list)
    • 字典(dictionary)
    • 集合(set)。

    不可变数据(immutable)

    • 数字(number)
    • 字符(string)
    • 元组(tuple)

    可迭代(iterable)

    • 字符(string)
    • 元组(tuple)
    • 列表(list)
    • 字典(dictionary)
    • 集合(set)

    序列

    • 有序序列:字符(string),元组(tuple),列表(list)
    • 无序序列:字典(dictionary),集合(set)

    Python序列类型最常见的分类就是可变和不可变序列。但另外一种分类方式也很有用,那就是把它们分为**扁平序列**和**容器序列**。前者的体积更小、速度更快而且用起来更简单,但是它只能保存一些原子性的数据,比如数字、字符和字节。容器序列则比较灵活,但是当容器序列遇到可变对象时,就需要格外小心,因为这种组合时常会出现一些“意外”,特别是带嵌套的数据结构出现时,更需要验证代码的正确性。

    Python中的变量、常量和字面量

    • 变量
    • 变量是用于在内存中存储数据的命名位置。可以将变量视为保存数据的容器,这些数据可以在后面程序中进行更改。例如:number = 10。从例子中可以看到,Python使用赋值运算符=为变量赋值。
    • 常量
    • 常量也是一种变量,只是其值一旦赋予后无法更改。可以将常量视为保存了以后无法更改的信息的容器。
    • 在Python中,常量通常是在模块中声明和分配的。在这里,模块是一个包含变量,函数等的新文件,该文件被导入到主文件中。在模块内部,用所有大写字母写的常量和下划线将单词分开。实际上,我们不在Python中使用常量。用大写字母命名它们是一种将其与普通变量分开的一种约定,但是,实际上并不能阻止重新分配。
    • 字面量(literal)
    • 字面量是以变量或常量给出的原始数据(其实就是指变量的常数值,字面上所看到的值)。在Python中字面量类型如下:
      • 数字字面量。数字字面量是不可变的(不可更改)。数字字面量可以属于3种不同的数值类型:Integer,Float 和 Complex。例如:float_1 = 10.5是属于Float字面量。
      • 字符串字面量是由引号括起来的一系列字符。我们可以对字符串使用单引号,双引号 或 三引号。并且,字符字面量是用单引号或双引号引起来的单个字符。例如:strings = "This is Python"
      • 布尔字面量。布尔字面量可以具有两个值中的任何一个:TrueFalse。例如:a = True + 4
      • 特殊字面量。Python包含一个特殊字面量,即 None
      • 字面量集。有四种不同的字面量集合:列表字面量,元组字面量,字典字面量 和 集合字面量。

    1.1 数值型(number)

    例子:

    a, b, c, d = 20, 5.5, True, 4+3j
     
     print(a, b, c, d)
     # 20 5.5 True (4+3j)
    @@ -159,7 +159,7 @@
     people = [person1, person2]
     
     for person in people:
    -    fstring = f'{"She" if person.get("gender") == "female" else "He"} is watching TV.'
    +    fstring = f'{"She" if person.get("gender") == "female" else "He"} is watching TV.'
         print(fstring)
     
     # He is watching TV.
    @@ -213,7 +213,7 @@
     
     # Debug调试
     number = 2
    -print(f'{number = }')
    +print(f'{number = }')
     # number = 2
     

    1.3 列表(list)

    列表是 Python 内置的一种数据结构,是一种有序的集合,用来存储一连串元素的容器。列表中元素类型可以不相同,它支持数字、字符串等。

    列表的每个值都有对应的索引值,索引值从0开始。

    列表切片:

    使用切片符号可以对大多数序列类型选取其子集。

    起始位置start的索引是包含的,而结束位置stop的索引并不包含(左闭右开)。

    步进值step可以在第二个冒号后面使用,意思是每隔多少个数取一个值 。

    color = ['red', 'green', 'blue', 'yellow', 'white', 'black']
     
    @@ -1160,4 +1160,4 @@
     # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
     

    5. 三元表达式

    value = true-expr if condition else false-expr

    x = 5
     print('non-negative' if x >= 0 else 'negative')  # non-negative
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/python/Foundation/ch02/index.html b/python/Foundation/ch02/index.html index bb0bf191..4ea71555 100644 --- a/python/Foundation/ch02/index.html +++ b/python/Foundation/ch02/index.html @@ -1,4 +1,4 @@ - Python打包和解包 - UPSkilling

    Python打包和解包

    解包Unpacking

    Python 允许变量的元组(或列表)出现在赋值操作的左侧。

    元组中的每个变量都可以从赋值右侧的可迭代对象(iterable)中接收一个值(或者更多,如果我们使用 * 运算符)。 Python 中的解包是指一种操作,该操作包括在单个赋值语句中将可迭代的值分配给变量的元组(或列表)。

    在 Python 中,可以在赋值运算符=的左侧放置一个变量元组,在右侧放置一个值元组。 右边的值将根据它们在元组中的位置自动分配给左边的变量。 这在 Python 中通常称为元组解包。

    如下示例:

    >>> (a, b, c) = (1, 2, 3)
    + Python打包和解包 - UPSkilling       

    Python打包和解包

    解包Unpacking

    Python 允许变量的元组(或列表)出现在赋值操作的左侧。

    元组中的每个变量都可以从赋值右侧的可迭代对象(iterable)中接收一个值(或者更多,如果我们使用 * 运算符)。 Python 中的解包是指一种操作,该操作包括在单个赋值语句中将可迭代的值分配给变量的元组(或列表)。

    在 Python 中,可以在赋值运算符=的左侧放置一个变量元组,在右侧放置一个值元组。 右边的值将根据它们在元组中的位置自动分配给左边的变量。 这在 Python 中通常称为元组解包。

    如下示例:

    >>> (a, b, c) = (1, 2, 3)
     >>> a
     1
     >>> b
    @@ -205,14 +205,14 @@
     {'a': 'A', 'e': 'e', 'i': 'i', 'o': 'o', 'u': 'u', 'b': 'B', 'c': 'C'}
     

    通过 For-Loops 解包

    我们还可以在 for 循环的上下文中使用可迭代解包。 当我们运行 for 循环时,在每次循环迭代中将其可迭代对象中的一项(item)分配给目标变量。 如果要分配的项(item)是可迭代的,那么我们可以使用元组作为目标变量,通过循环将可迭代对象解包到目标变量的元组中。

    例如,我们可以构建一个包含两个元素的元组的列表。 每个元组将包含产品名称、价格和销售单位,我们通过 for 循环遍历每个元组元素来计算每个产品的收入。

    >>> sales = [('Pencle', 0.22, 1500), ('Notebook', 1.30, 550), ('Eraser', 0.75, 1000)]
     >>> for items in sales:
    -...     print(f"Income for {items[0]} is: {items[1] * items[2]}")
    +...     print(f"Income for {items[0]} is: {items[1] * items[2]}")
     ... 
     Income for Pencle is: 330.0
     Income for Notebook is: 715.0
     Income for Eraser is: 750.0
     

    我们可以使用索引来访问每个元组的各个元素。下面的示例代码中,在 for 循环使用解包,这也是 Python 中解包的一种实现。

    >>> sales = [('Pencle', 0.22, 1500), ('Notebook', 1.30, 550), ('Eraser', 0.75, 1000)]
     >>> for product, price, sold_units in sales:
    -...     print(f"Income for {product} is: {price * sold_units}")
    +...     print(f"Income for {product} is: {price * sold_units}")
     ... 
     Income for Pencle is: 330.0
     Income for Notebook is: 715.0
    @@ -277,4 +277,4 @@
     Welcome to...
     (1, 2, 3)
     {'Site': 'CloudAcademy.com'}
    -

    总结

    可迭代解包(iterable unpacking)这个特性允许我们将一个可迭代对象解包成几个变量。 另一方面,打包包括使用解包运算符 * 将多个值赋到一个变量中。

    可迭代解包(iterable unpacking)也可以用来进行并行赋值和变量之间的值交换,也可以用在 for 循环、函数调用和函数定义中。

    \ No newline at end of file +

    总结

    可迭代解包(iterable unpacking)这个特性允许我们将一个可迭代对象解包成几个变量。 另一方面,打包包括使用解包运算符 * 将多个值赋到一个变量中。

    可迭代解包(iterable unpacking)也可以用来进行并行赋值和变量之间的值交换,也可以用在 for 循环、函数调用和函数定义中。

    Back to top
    \ No newline at end of file diff --git a/python/Foundation/ch03/index.html b/python/Foundation/ch03/index.html index 3c780ce0..909b430d 100644 --- a/python/Foundation/ch03/index.html +++ b/python/Foundation/ch03/index.html @@ -1,4 +1,4 @@ - Python内置函数及文件 - UPSkilling

    Python内置函数及文件

    1. 匿名(Lambda)函数

    匿名函数是一种通过单个语句生成函数的方式,其结果是返回值。匿名函数使用lambda关键字定义,该关键字仅表达“我们声明一个匿名函数”的意思。

    lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个表达式的值。

    语法格式:lambda arg1,arg2,arg3… :<表达式>

    f = lambda x, y: x * y
    + Python内置函数及文件 - UPSkilling       

    Python内置函数及文件

    1. 匿名(Lambda)函数

    匿名函数是一种通过单个语句生成函数的方式,其结果是返回值。匿名函数使用lambda关键字定义,该关键字仅表达“我们声明一个匿名函数”的意思。

    lambda 函数可以接收任意多个参数 (包括可选参数) 并且返回单个表达式的值。

    语法格式:lambda arg1,arg2,arg3… :<表达式>

    f = lambda x, y: x * y
     print(f(2, 3))  
     # 6
     
    @@ -856,4 +856,4 @@
     running f1()
     running f2()
     running f3()
    -

    register在模块中其他函数之前运行(两次)。调用register时,传给它的参数是被装饰的函数,例如function f1 at 0x7f70847bec80>。加载模块后,registry中有两个被装饰函数的引用:f1f2。这两个函数,以及f3,只在main明确调用它们时才执行。

    由此得,函数装饰器在导入模块时立即执行,而被装饰的函数只在明确调用时运行,即Python中提到的**导入时**和**运行时**之间的区别。

    上面例子中装饰器函数与被装饰的函数在同一个模块中定义。实际应用中,装饰器通常在一个模块中定义,然后应用到其他模块中的函数上。

    上面例子中register装饰器返回的函数与通过参数传入的相同。实际应用中,大多数装饰器会在内部定义一个函数,然后将其返回。

    \ No newline at end of file +

    register在模块中其他函数之前运行(两次)。调用register时,传给它的参数是被装饰的函数,例如function f1 at 0x7f70847bec80>。加载模块后,registry中有两个被装饰函数的引用:f1f2。这两个函数,以及f3,只在main明确调用它们时才执行。

    由此得,函数装饰器在导入模块时立即执行,而被装饰的函数只在明确调用时运行,即Python中提到的**导入时**和**运行时**之间的区别。

    上面例子中装饰器函数与被装饰的函数在同一个模块中定义。实际应用中,装饰器通常在一个模块中定义,然后应用到其他模块中的函数上。

    上面例子中register装饰器返回的函数与通过参数传入的相同。实际应用中,大多数装饰器会在内部定义一个函数,然后将其返回。

    Back to top
    \ No newline at end of file diff --git a/python/Foundation/ch04/index.html b/python/Foundation/ch04/index.html index 4d76f95d..284dcd0c 100644 --- a/python/Foundation/ch04/index.html +++ b/python/Foundation/ch04/index.html @@ -1,4 +1,4 @@ - Python面向对象概念 - UPSkilling

    Python面向对象概念

    类(class)把数据与功能绑定在一起。创建新类就是创建新的对象类型(type of object),从而创建该类型的新实例(instances)。 类实例具有多种保持自身状态的属性(attributes)。 类实例还支持(由类定义的)修改自身状态的方法(methods)。

    Python的类支持所有面向对象编程(OOP)的标准特性:

    • 类继承(class inheritance)机制支持多个基类(base classes);
    • 派生类(derived class)可以覆盖基类的任何方法(methods);
    • 类的方法可以调用基类中相同名称的方法
    • 对象可以包含任意数量和类型的数据。
    • 类(class)和模块(module)都拥有动态特性(dynamic nature):在运行时创建,创建后也可以修改。

    名称Names和对象Objects

    对象之间相互独立,多个名称(names)(在多个作用域内)可以绑定到同一个对象。 其他语言称之为别名(alias)。 别名在某些方面就像指针。例如,传递对象的代价很小,因为实现只传递一个指针;如果函数修改了作为参数传递的对象,调用者就可以看到更改。

    作用域Scopes和命名空间Namespaces

    **命名空间(namespace)**是一个从名字到对象的映射。 当前大部分命名空间都由 Python 字典实现。

    下面是几个命名空间的例子:

    • 存放内置函数的集合(包含abs()这样的函数,和内建的异常等);
    • 模块中的全局名称;
    • 函数调用中的局部名称;

    从某种意义上说,对象的属性集合(the set of attributes of an object)也是一种命名空间的形式

    关于命名空间的重要一点是,不同命名空间中的名称之间绝对没有关系; 例如,在两个不同的模块中都可以定义一个maximize函数而不会产生混淆,但在调用maximize函数时必须必须在其前面加上模块名称。

    任何跟在一个点号之后的名称都称为**属性(attribute)**。例如,在表达式z.real中,real是对象z的一个属性。

    按严格的说法,对模块(module)中的名称的引用(reference)都属于属性引用(attribute reference): 在表达式modname.funcname中,modname是一个模块对象(module object)而funcname是它的一个属性。 在此情况下在模块的属性(module’s attribute)和模块中定义的全局名称之间正好存在一个直观的映射:它们共享相同的命名空间。 但存在一个例外。 模块对象有一个只读属性__dict__,它返回用于实现模块命名空间的字典;__dict__是属性但不是全局名称。 使用这个将违反命名空间实现的抽象,应当仅被用于事后调试器之类的场合。

    **属性(attribute)**可以是只读或者可写的,所以可以对属性进行赋值,例如modname.the_answer = 42。 删除属性可以用del语句,例如,del modname.the_answer将会从名为modname的对象中移除the_answer属性。

    命名空间在不同时刻被创建,拥有不同的生存期(lifetimes)。包含内置名称(built-in names)的命名空间是在Python解释器启动时创建的,永远不会被删除。

    模块的全局命名空间(global namespace)在模块定义被读入时创建;通常,模块命名空间也会持续到解释器退出。 被解释器的顶层调用(top-level invocation)执行的语句,从一个脚本文件读取或交互式地读取,被认为是__main__模块调用的一部分,因此它们拥有自己的全局命名空间。 内置名称(built-in names)实际上也存在于一个模块中,这个模块被称作builtins

    一个函数的本地命名空间(local namespace)在这个函数被调用时创建,并在函数返回或抛出一个无法在该函数内部处理的错误时被删除。 每次递归调用(recursive invocations)都会有它自己的本地命名空间。

    一个**作用域(scope)**是一个命名空间可直接访问(directly accessible)的Python程序的代码区域。 这里的 “可直接访问” 意味着不加任何限定的名称引用会在命名空间中进行查找。

    虽然作用域是静态地确定的,但它们会被动态地使用。 在代码执行期间的任何时刻,会有3或4个的嵌套作用域供命名空间直接访问:

    • 最先搜索的最内部作用域包含局部名称
    • 从最近的封闭作用域开始搜索的任何封闭函数的作用域包含非局部名称,也包括非全局名称
    • 倒数第二个作用域包含当前模块的全局名称
    • 最外面的作用域(最后搜索)是包含内置名称的命名空间

    如果一个名称被声明为全局变量,则所有引用和赋值将直接指向该模块全局名称所在的中间作用域。 如果要重新绑定在最内层作用域以外的变量,可以使用nonlocal语句声明为非本地变量。 如果没有被声明为非本地变量,这些变量将是只读的。给这样的变量赋新值只会在最内层作用域中创建一个*新的*局部变量,而同名的外部全局变量将保持不变。

    通常,当前局部作用域(local scope)将引用当前函数作用域的名称(local name)。 在函数作用域以外,当前局部作用域将引用与全局作用域相一致的命名空间:模块的命名空间(the module’s namespace)。

    定义一个类,是在本地局部命名空间内建一个新的命名空间。

    在一个模块(module )内定义的函数的作用域就是该模块的命名空间,无论该函数从什么地方或以什么别名被调用。 另一方面,实际的名称搜索是在运行时动态完成的。 但是,Python正在朝着“编译时静态名称解析”的方向发展,因此不要过于依赖动态名称解析!事实上,局部变量已经是被静态确定了。

    如果不存在生效的globalnonlocal语句,则对名称的赋值总是会进入最内层作用域。赋值不会复制数据,是将名称绑定到对象。 删除也是如此:语句del x会从局部作用域所引用的命名空间中移除对x的绑定。事实上,所有引入新名称的操作都是使用局部作用域。特别地,import语句和函数定义会在局部作用域中绑定模块或函数名称。

    global语句可被用来表明特定变量存在于全局作用域,并且应当在全局作用域中被**重新**绑定;

    nonlocal语句表明特定变量生存于外层作用域中,并且应当在其所处的外层作用域中被**重新**绑定。

    看下面的例子:

    • 局部赋值(local assignment,这是默认状态)不会改变scope_testspam的绑定。
    • nonlocal赋值会改变scope_testspam的绑定。
    • global赋值会改变模块层级的绑定,即,global spam重新绑定了spam的全局定义,从spam = "spam out of func"变成了spam = "global spam"。如果注释掉def do_global()这一段代码,则spam = "spam out of func"起作用。
    spam = "spam out of func"
    + Python面向对象概念 - UPSkilling       

    Python面向对象概念

    类(class)把数据与功能绑定在一起。创建新类就是创建新的对象类型(type of object),从而创建该类型的新实例(instances)。 类实例具有多种保持自身状态的属性(attributes)。 类实例还支持(由类定义的)修改自身状态的方法(methods)。

    Python的类支持所有面向对象编程(OOP)的标准特性:

    • 类继承(class inheritance)机制支持多个基类(base classes);
    • 派生类(derived class)可以覆盖基类的任何方法(methods);
    • 类的方法可以调用基类中相同名称的方法
    • 对象可以包含任意数量和类型的数据。
    • 类(class)和模块(module)都拥有动态特性(dynamic nature):在运行时创建,创建后也可以修改。

    名称Names和对象Objects

    对象之间相互独立,多个名称(names)(在多个作用域内)可以绑定到同一个对象。 其他语言称之为别名(alias)。 别名在某些方面就像指针。例如,传递对象的代价很小,因为实现只传递一个指针;如果函数修改了作为参数传递的对象,调用者就可以看到更改。

    作用域Scopes和命名空间Namespaces

    **命名空间(namespace)**是一个从名字到对象的映射。 当前大部分命名空间都由 Python 字典实现。

    下面是几个命名空间的例子:

    • 存放内置函数的集合(包含abs()这样的函数,和内建的异常等);
    • 模块中的全局名称;
    • 函数调用中的局部名称;

    从某种意义上说,对象的属性集合(the set of attributes of an object)也是一种命名空间的形式

    关于命名空间的重要一点是,不同命名空间中的名称之间绝对没有关系; 例如,在两个不同的模块中都可以定义一个maximize函数而不会产生混淆,但在调用maximize函数时必须必须在其前面加上模块名称。

    任何跟在一个点号之后的名称都称为**属性(attribute)**。例如,在表达式z.real中,real是对象z的一个属性。

    按严格的说法,对模块(module)中的名称的引用(reference)都属于属性引用(attribute reference): 在表达式modname.funcname中,modname是一个模块对象(module object)而funcname是它的一个属性。 在此情况下在模块的属性(module’s attribute)和模块中定义的全局名称之间正好存在一个直观的映射:它们共享相同的命名空间。 但存在一个例外。 模块对象有一个只读属性__dict__,它返回用于实现模块命名空间的字典;__dict__是属性但不是全局名称。 使用这个将违反命名空间实现的抽象,应当仅被用于事后调试器之类的场合。

    **属性(attribute)**可以是只读或者可写的,所以可以对属性进行赋值,例如modname.the_answer = 42。 删除属性可以用del语句,例如,del modname.the_answer将会从名为modname的对象中移除the_answer属性。

    命名空间在不同时刻被创建,拥有不同的生存期(lifetimes)。包含内置名称(built-in names)的命名空间是在Python解释器启动时创建的,永远不会被删除。

    模块的全局命名空间(global namespace)在模块定义被读入时创建;通常,模块命名空间也会持续到解释器退出。 被解释器的顶层调用(top-level invocation)执行的语句,从一个脚本文件读取或交互式地读取,被认为是__main__模块调用的一部分,因此它们拥有自己的全局命名空间。 内置名称(built-in names)实际上也存在于一个模块中,这个模块被称作builtins

    一个函数的本地命名空间(local namespace)在这个函数被调用时创建,并在函数返回或抛出一个无法在该函数内部处理的错误时被删除。 每次递归调用(recursive invocations)都会有它自己的本地命名空间。

    一个**作用域(scope)**是一个命名空间可直接访问(directly accessible)的Python程序的代码区域。 这里的 “可直接访问” 意味着不加任何限定的名称引用会在命名空间中进行查找。

    虽然作用域是静态地确定的,但它们会被动态地使用。 在代码执行期间的任何时刻,会有3或4个的嵌套作用域供命名空间直接访问:

    • 最先搜索的最内部作用域包含局部名称
    • 从最近的封闭作用域开始搜索的任何封闭函数的作用域包含非局部名称,也包括非全局名称
    • 倒数第二个作用域包含当前模块的全局名称
    • 最外面的作用域(最后搜索)是包含内置名称的命名空间

    如果一个名称被声明为全局变量,则所有引用和赋值将直接指向该模块全局名称所在的中间作用域。 如果要重新绑定在最内层作用域以外的变量,可以使用nonlocal语句声明为非本地变量。 如果没有被声明为非本地变量,这些变量将是只读的。给这样的变量赋新值只会在最内层作用域中创建一个*新的*局部变量,而同名的外部全局变量将保持不变。

    通常,当前局部作用域(local scope)将引用当前函数作用域的名称(local name)。 在函数作用域以外,当前局部作用域将引用与全局作用域相一致的命名空间:模块的命名空间(the module’s namespace)。

    定义一个类,是在本地局部命名空间内建一个新的命名空间。

    在一个模块(module )内定义的函数的作用域就是该模块的命名空间,无论该函数从什么地方或以什么别名被调用。 另一方面,实际的名称搜索是在运行时动态完成的。 但是,Python正在朝着“编译时静态名称解析”的方向发展,因此不要过于依赖动态名称解析!事实上,局部变量已经是被静态确定了。

    如果不存在生效的globalnonlocal语句,则对名称的赋值总是会进入最内层作用域。赋值不会复制数据,是将名称绑定到对象。 删除也是如此:语句del x会从局部作用域所引用的命名空间中移除对x的绑定。事实上,所有引入新名称的操作都是使用局部作用域。特别地,import语句和函数定义会在局部作用域中绑定模块或函数名称。

    global语句可被用来表明特定变量存在于全局作用域,并且应当在全局作用域中被**重新**绑定;

    nonlocal语句表明特定变量生存于外层作用域中,并且应当在其所处的外层作用域中被**重新**绑定。

    看下面的例子:

    • 局部赋值(local assignment,这是默认状态)不会改变scope_testspam的绑定。
    • nonlocal赋值会改变scope_testspam的绑定。
    • global赋值会改变模块层级的绑定,即,global spam重新绑定了spam的全局定义,从spam = "spam out of func"变成了spam = "global spam"。如果注释掉def do_global()这一段代码,则spam = "spam out of func"起作用。
    spam = "spam out of func"
     
     def scope_test():
     
    @@ -39,7 +39,7 @@
         ...
         <statement-N>
     

    在实践中,类定义内的语句通常都是函数定义,但也允许有其他语句。在类内部的函数定义通常具有一种特有形式的参数列表,这是约定的方法规范(conventions for methods)。

    编译过程中,进入一个类的内部,将创建一个新的命名空间,一个局部作用域。因此,所有对类内部局部变量的赋值都是在这个新的命名空间之内,包括新定义的函数名称。

    当正常离开一个类时,编译过程将创建一个类对象(class object),封装了类定义所创建的命名空间里的内容。

    最初的(在进入类定义之前起作用的)局部作用域将重新生效,类对象(class object)将在这里被绑定到类定义头部所声明的类名称 (在上面的示例中是ClassName)。

    类对象 Class Objects

    类对象支持两种操作:属性引用(attribute references)和实例化(instantiation)。

    属性引用(attribute references) 使用Python中属性引用的标准语法: obj.name

    存在于类命名空间中的所有名称,类对象被创建时同时被创建了,这些就是有效的属性名称。因此,如果类定义是如下所示,那么MyClass.iMyClass.f就是有效的属性引用,将分别返回一个整数和一个函数对象。

    类属性也可以被赋值,因此可以通过赋值来更改MyClass.i的值。__doc__也是一个有效的属性,将返回所属类的文档字符串: "A simple example class"。

    class MyClass:
    -    """A simple example class"""
    +    """A simple example class"""
         i = 12345
     
         def f(self):
    @@ -54,7 +54,7 @@
     print(MyClass.i)
     # 10
     

    类的**实例化(instantiation)**使用函数表示法。 可以把类对象(class object)看作是一个不带参数的函数,这个函数返回了该类的一个新实例。

    在下面的例子中,x = MyClass()创建了MyClass()这个类的一个实例,并赋值给局部变量x

    实例化操作(调用类对象)会创建一个空对象。许多类会创建带有特定初始状态的自定义实例。为此类定义中需要包含一个名为__init__()的特殊方法。

    当一个类定义了__init__()方法时,类的实例化操作会自动为新创建的类实例调用__init__()。 更新上面的例子,注意__dict__两次返回的不同的字典。复习一下,在命名空间中提到,__dict__是属性但不是全局名称,返回用于实现模块命名空间的字典。

    class MyClass:
    -    """A simple example class"""
    +    """A simple example class"""
         i = 12345
     
         def f(self):
    @@ -83,7 +83,7 @@
     print(x.r, x.i)
     # 3.0 -4.5
     

    实例对象 Instance Objects

    对实例对象唯一的操作是属性引用。有两种有效的属性名称:数据属性(data attributes)和方法(methods)。

    **数据属性(data attributes)**类似于实例变量,数据属性不需要声明。像局部变量一样,数据属性将在第一次被赋值时产生。 例如,如果x是上面创建的MyClass的实例,则以下代码段将打印数值16,且没有留下关于x.counter的痕迹。

    class MyClass:
    -    """A simple example class"""
    +    """A simple example class"""
         i = 12345
     
         def f(self):
    @@ -110,7 +110,7 @@
     print(x.__dict__)
     # {'data': []}
     

    另一类实例属性引用称为**方法(methods)。 方法是隶属于对象的**函数

    在Python中,方法这个术语并不是类实例所特有的,其他对象也可以有方法。 例如,列表对象(list objects)具有append, insert, remove, sort等方法。

    在以下讨论中,我们使用方法一词将专指类实例对象的方法,除非另外明确说明。

    实例对象的有效方法名称依赖于其所属的类。 根据定义,一个类定义中所包含的所有函数对象(function objects)都称为属性。

    因此在上面的示例中,x.f是有效的方法引用,因为MyClass.f是一个函数,而x.i不是方法,因为MyClass.i不是函数。但是x.fMyClass.f并不是一回事,x.f是一个**方法对象**,而MyClass.f是一个**函数对象**。差别在于f()是否与实例绑定,未绑定,就是函数,绑定,就是方法。

    class MyClass:
    -    """A simple example class"""
    +    """A simple example class"""
         i = 12345
     
         def f(self):
    @@ -284,7 +284,7 @@
     sorted(set(dir(func)) - set(dir(obj)))
     # ['__annotations__', '__call__', '__closure__', '__code__', '__defaults__', '__get__', '__globals__', '__kwdefaults__', '__name__', '__qualname__']
     

    下表总结了用户定义的函数的属性。

    用户定义的函数的属性

    下面的例子是演示了在指定长度附近截断字符串的函数,以及提取关于函数参数的信息的方法。

    参数名称在__code__.co_varnames中,但这里面也包含函数定义体中创建的局部变量。因此,参数名称是前N个字符串,N的值由__code__.co_argcount确定,例子里面N是2,即参数名称是textmax_len,局部变量是endspace_beforespace_after

    def clip(text, max_len=80):
    -    """
    +    """
         Get sub-string by the first blank before or after specified position.
         rfind() 返回字符串最后一次出现的位置,如果没有匹配项则返回 -1.
         """
    @@ -342,7 +342,7 @@
     # 1 : text = <class 'inspect._empty'>
     # 1 : max_len = 80
     

    函数注解。

    Python 3 提供了一种句法,用于为函数声明中的参数和返回值附加元数据。对上例添加注解后如下所示,二者唯一的区别在第一行。

    函数声明中的各个参数可以在:之后增加注解表达式。 如果参数有默认值,注解放在参数名和=号之间。 如果想注解返回值,在)和函数声明末尾的:之间添加->和一个表达式。那个表达式可以是任何类型。 注解中最常用的类型是类(如strint)和字符串(如'int > 0')。在下例中,max_len参数的注解用的是字符串。

    注解不会做任何处理,只是存储在函数的__annotations__属性(一个字典)中。换句话说,注解对Python解释器没有任何意义。注解只是元数据,可以供IDE、框架和装饰器等工具使用。

    return键保存的是返回值注解,即下例中函数声明里以->标记的部分。

    def clip(text:str, max_len:'int > 0'=80) -> str:
    -    """
    +    """
         Get sub-string by the first blank before or after specified position.
         rfind() 返回字符串最后一次出现的位置,如果没有匹配项则返回 -1.
         """
    @@ -384,4 +384,4 @@
     
     # <class 'str'> : text = <class 'inspect._empty'>
     # 'int > 0'     : max_len = 80
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/python/Foundation/ch05/index.html b/python/Foundation/ch05/index.html index 33a478da..02fcc517 100644 --- a/python/Foundation/ch05/index.html +++ b/python/Foundation/ch05/index.html @@ -1,4 +1,4 @@ - Python面向对象三大特性 - UPSkilling

    Python面向对象三大特性

    Python面向对象三大特性:

    • 封装
    • 继承
    • 多态

    封装 Encapsulation

    封装是使用特殊的语法,对成员属性和成员方法进行包装,限制一些访问和操作,达到保护和隐藏的目的。

    封装机制保证了类内部数据结构的完整性,因为使用类的用户无法直接看到类中的数据结构,只能使用类允许公开的数据,很好地避免了外部对内部数据的影响,提高了程序的可维护性。

    对一个类实现良好的封装,用户只能借助暴露出来的类方法来访问数据,可以在这些暴露的方法中加入适当的控制逻辑,即可控制用户对类中属性或方法的操作。

    对类进行良好的封装,主要是内部使用封装的成员,也提高了代码的复用性。

    类成员封装的级别:

    • 公有的(public)
    • 保护的(protected),在Python中并没有实现protected封装,属于开发者的约定俗成。
    • 私有的(private),在Python中private封装是通过改名策略来实现的,并不是真正的私有化。
    访问限制 共有的public 受保护的protected 私有的private
    在类的内部 OK OK OK
    在类的外部 OK No (Python中可以) No

    看下面的例子。(参考私有变量Private Variables)

    • name是共有属性,可以在外部调用tom.name。
    • _age是受保护的属性,理论上在外部是不可调用的,但在Python中是可以调用的tom._age
    • __phone是私有属性,在外部是不可调用的,tom.__get_phone()报错“属性不存在”。
    • 对应方法也是类似。
    • 在类的内部对受保护对象和私有对象没有访问限制。_get_age可以调用私有属性__phone
    class Person():
    + Python面向对象三大特性 - UPSkilling       

    Python面向对象三大特性

    Python面向对象三大特性:

    • 封装
    • 继承
    • 多态

    封装 Encapsulation

    封装是使用特殊的语法,对成员属性和成员方法进行包装,限制一些访问和操作,达到保护和隐藏的目的。

    封装机制保证了类内部数据结构的完整性,因为使用类的用户无法直接看到类中的数据结构,只能使用类允许公开的数据,很好地避免了外部对内部数据的影响,提高了程序的可维护性。

    对一个类实现良好的封装,用户只能借助暴露出来的类方法来访问数据,可以在这些暴露的方法中加入适当的控制逻辑,即可控制用户对类中属性或方法的操作。

    对类进行良好的封装,主要是内部使用封装的成员,也提高了代码的复用性。

    类成员封装的级别:

    • 公有的(public)
    • 保护的(protected),在Python中并没有实现protected封装,属于开发者的约定俗成。
    • 私有的(private),在Python中private封装是通过改名策略来实现的,并不是真正的私有化。
    访问限制 共有的public 受保护的protected 私有的private
    在类的内部 OK OK OK
    在类的外部 OK No (Python中可以) No

    看下面的例子。(参考私有变量Private Variables)

    • name是共有属性,可以在外部调用tom.name。
    • _age是受保护的属性,理论上在外部是不可调用的,但在Python中是可以调用的tom._age
    • __phone是私有属性,在外部是不可调用的,tom.__get_phone()报错“属性不存在”。
    • 对应方法也是类似。
    • 在类的内部对受保护对象和私有对象没有访问限制。_get_age可以调用私有属性__phone
    class Person():
         name = 'name'  # public
         _age = 0  # protected
         __phone = 'phone'  # private
    @@ -183,7 +183,7 @@
     

    总结:

    1. 继承结构要尽量简单,不要过于复杂。
    2. 推荐使用minxins机制,在多继承背景下,满足继承的什么是什么的关系(is-a)

    多继承关系的minxins机制

    看下面例子,如果在Vehicle类中定义了fly的方法,会导致Car(Vehicle)的继承关系出现矛盾,汽车并不会飞,但按照上述继承关系,汽车也能飞了。 但是如果民航飞机和直升机都各自写自己的飞行fly方法,又违背了代码尽可能重用的原则。

    class Vehicle:  # 交通工具
     
         def fly(self):
    -        '''
    +        '''
             飞行功能相应的代码        
             '''
             print("I am flying")
    @@ -211,7 +211,7 @@
     class FlyableMixin:
     
         def fly(self):
    -        '''
    +        '''
             飞行功能相应的代码        
             '''
             print("I am flying")
    @@ -696,7 +696,7 @@
         next(it)
     StopIteration
     

    在了解了迭代器协议(iterator protocol)的机制后,给类添加迭代器就很容易了。 定义一个 __iter__() 方法来返回一个带有 __next__() 方法的对象。 如果类已定义了 __next__(),则 __iter__() 可以简单地返回 self:

    class Reverse:
    -    """Iterator for looping over a sequence backwards."""
    +    """Iterator for looping over a sequence backwards."""
     
         def __init__(self, data):
             self.data = data
    @@ -815,7 +815,7 @@
     
     
     class StandfordProfessor(object, metaclass=Mymeta):
    -    """
    +    """
         Documentation of class StanfordTeacher
         """
     
    @@ -839,4 +839,4 @@
     
     StandfordProfessor.mro()
     # [<class '__main__.StandfordProfessor'>, <class 'object'>]
    -
    \ No newline at end of file +
    Back to top
    \ No newline at end of file diff --git a/python/index.html b/python/index.html index 1d95fdd1..413bd9ab 100644 --- a/python/index.html +++ b/python/index.html @@ -1 +1 @@ - Index - UPSkilling

    Content

    Memo

    Python学习的笔记。

    • Python基础知识,来源于参加的各种在线基础课程汇集而成。
    • 《利用Python进行数据分析(原书第2版)》(Python for Data Analysis, 2rd Edition)学习笔记,作者的github链接Python For Data Analysis
    • 《数据结构(Python语言描述)(第2版)》(Fundamentals of Python: Data Structures 2nd Edition)学习笔记。
    • 小程序演示,来源于参加的各种在线基础课程。
    \ No newline at end of file + Index - UPSkilling

    Content

    Memo

    Python学习的笔记。

    • Python基础知识,来源于参加的各种在线基础课程汇集而成。
    • 《利用Python进行数据分析(原书第2版)》(Python for Data Analysis, 2rd Edition)学习笔记,作者的github链接Python For Data Analysis
    • 《数据结构(Python语言描述)(第2版)》(Fundamentals of Python: Data Structures 2nd Edition)学习笔记。
    • 小程序演示,来源于参加的各种在线基础课程。
    Back to top
    \ No newline at end of file diff --git a/search/search_index.json b/search/search_index.json index 87ab80fc..2714944a 100644 --- a/search/search_index.json +++ b/search/search_index.json @@ -1 +1 @@ -{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Upskilling \u00b6 1.Linux \u00b6 1.1.Linux SRE \u00b6 \u7b2c\u4e00\u7ae0 Linux\u57fa\u7840 \u7b2c\u4e8c\u7ae0 \u6587\u4ef6\u7cfb\u7edf \u7b2c\u4e09\u7ae0 \u8eab\u4efd\u4e0e\u5b89\u5168 \u7b2c\u56db\u7ae0 \u6587\u672c\u7f16\u8f91 \u7b2c\u4e94\u7ae0 \u6b63\u5219\u8868\u8fbe\u5f0f \u7b2c\u516d\u7ae0 \u6587\u4ef6\u67e5\u627e \u7b2c\u4e03\u7ae0 \u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305 1.2.SUSE Linux Administration \u00b6 Linux File System Overview Useful Commands Shell 1.3.SUSE Enterprise Storage Foundation \u00b6 SUSE Enterprise Storage Foundation SUSE Enterprise Storage Basic Operation 2.Kubernetes \u00b6 2.1.CKA Learning Memo \u00b6 Installation Single Node Installation Multiple Nodes Installation Installation on Aliyun ECS Docker Fundamentals Foundamentals Memo Overview kubectl basics Core Kubernetes Pod Deployment Service Application Modeling Namespace StatefulSet DaemonSet Job and Cronjob Configuration Secrets Persistence Role Based Access Control (RBAC) Ingress Advanced Kubernetes Scheduling Horizontal Pod Autoscaling Policy Network Policy Cluster Management Operating Kubernetes Troubleshooting Health Check Helming Topics Operations on Resources Health Check Calico Installation Kyma 2.2.CKA\u5b66\u4e60\u7b14\u8bb0 \u00b6 \u5b89\u88c5 \u5355\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes \u591a\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes \u963f\u91cc\u4e91ECS\u5b89\u88c5Kubernetes Docker Docker\u57fa\u7840 \u57fa\u7840\u77e5\u8bc6 Kubernetes\u968f\u7b14 Kubernetes\u96c6\u7fa4\u6982\u89c8 kubectl\u57fa\u7840 \u6838\u5fc3\u6982\u5ff5 Pod Deployment Service \u5e94\u7528\u4f53\u7cfb Namespace StatefulSet DaemonSet Job and Cronjob Configuration secrets Persistence RBAC\u9274\u6743 Ingress-nginx \u8fdb\u9636\u6982\u5ff5 Scheduling Horizontal Pod Autoscaling (HPA) Policy Network Policy Cluster Management \u65e5\u5e38\u7ef4\u62a4 Troubleshooting \u5065\u5eb7\u68c0\u67e5 Helm Chart \u4e3b\u9898\u8ba8\u8bba Kubernetes\u8d44\u6e90\u5e38\u89c1\u64cd\u4f5c \u5065\u5eb7\u68c0\u67e5 \u5b89\u88c5Calico Demos Build CAP Application on Kyma 3.Python \u00b6 3.1.Python\u57fa\u7840 \u00b6 Python\u5b89\u88c5 Python\u8bed\u8a00\u57fa\u7840 Python\u6253\u5305\u548c\u89e3\u5305 Python\u5185\u7f6e\u51fd\u6570\u53ca\u6587\u4ef6 Python\u9762\u5411\u5bf9\u8c61\u6982\u5ff5 Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027 Python\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5 3.2.Python\u6570\u636e\u5206\u6790\u57fa\u7840 \u00b6 NumPy\u57fa\u7840 NumPy\u8fdb\u9636 Pandas\u5165\u95e8 \u6570\u636e\u8f7d\u5165\u3001\u5b58\u50a8\u53ca\u6587\u4ef6\u683c\u5f0f \u6570\u636e\u6e05\u6d17\u4e0e\u51c6\u5907 \u6570\u636e\u89c4\u6574\uff1a\u8fde\u63a5\u3001\u8054\u5408\u4e0e\u91cd\u5851 \u7ed8\u56fe\u4e0e\u53ef\u89c6\u5316 \u6570\u636e\u805a\u5408\u4e0e\u5206\u7ec4\u64cd\u4f5c \u65f6\u95f4\u5e8f\u5217 \u9ad8\u9636pandas Python\u5efa\u6a21\u5e93\u4ecb\u7ecd 3.3.\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5 \u00b6 1.\u57fa\u7840\u77e5\u8bc6\u56de\u987e 2.\u591a\u9879\u96c6\u7684\u6982\u8ff0 3.\u641c\u7d22\u3001\u6392\u5e8f\u4ee5\u53ca\u590d\u6742\u5ea6\u5206\u6790 4.\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784 5.\u63a5\u53e3\u3001\u5b9e\u73b0\u548c\u591a\u6001 6.\u7ee7\u627f\u4e0e\u62bd\u8c61\u7c7b 3.4.Demos \u00b6 \u9009\u8bfe\u7cfb\u7edf","title":"Index"},{"location":"#upskilling","text":"","title":"Upskilling"},{"location":"#1linux","text":"","title":"1.Linux"},{"location":"#11linux-sre","text":"\u7b2c\u4e00\u7ae0 Linux\u57fa\u7840 \u7b2c\u4e8c\u7ae0 \u6587\u4ef6\u7cfb\u7edf \u7b2c\u4e09\u7ae0 \u8eab\u4efd\u4e0e\u5b89\u5168 \u7b2c\u56db\u7ae0 \u6587\u672c\u7f16\u8f91 \u7b2c\u4e94\u7ae0 \u6b63\u5219\u8868\u8fbe\u5f0f \u7b2c\u516d\u7ae0 \u6587\u4ef6\u67e5\u627e \u7b2c\u4e03\u7ae0 \u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305","title":"1.1.Linux SRE"},{"location":"#12suse-linux-administration","text":"Linux File System Overview Useful Commands Shell","title":"1.2.SUSE Linux Administration"},{"location":"#13suse-enterprise-storage-foundation","text":"SUSE Enterprise Storage Foundation SUSE Enterprise Storage Basic Operation","title":"1.3.SUSE Enterprise Storage Foundation"},{"location":"#2kubernetes","text":"","title":"2.Kubernetes"},{"location":"#21cka-learning-memo","text":"Installation Single Node Installation Multiple Nodes Installation Installation on Aliyun ECS Docker Fundamentals Foundamentals Memo Overview kubectl basics Core Kubernetes Pod Deployment Service Application Modeling Namespace StatefulSet DaemonSet Job and Cronjob Configuration Secrets Persistence Role Based Access Control (RBAC) Ingress Advanced Kubernetes Scheduling Horizontal Pod Autoscaling Policy Network Policy Cluster Management Operating Kubernetes Troubleshooting Health Check Helming Topics Operations on Resources Health Check Calico Installation Kyma","title":"2.1.CKA Learning Memo"},{"location":"#22cka","text":"\u5b89\u88c5 \u5355\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes \u591a\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes \u963f\u91cc\u4e91ECS\u5b89\u88c5Kubernetes Docker Docker\u57fa\u7840 \u57fa\u7840\u77e5\u8bc6 Kubernetes\u968f\u7b14 Kubernetes\u96c6\u7fa4\u6982\u89c8 kubectl\u57fa\u7840 \u6838\u5fc3\u6982\u5ff5 Pod Deployment Service \u5e94\u7528\u4f53\u7cfb Namespace StatefulSet DaemonSet Job and Cronjob Configuration secrets Persistence RBAC\u9274\u6743 Ingress-nginx \u8fdb\u9636\u6982\u5ff5 Scheduling Horizontal Pod Autoscaling (HPA) Policy Network Policy Cluster Management \u65e5\u5e38\u7ef4\u62a4 Troubleshooting \u5065\u5eb7\u68c0\u67e5 Helm Chart \u4e3b\u9898\u8ba8\u8bba Kubernetes\u8d44\u6e90\u5e38\u89c1\u64cd\u4f5c \u5065\u5eb7\u68c0\u67e5 \u5b89\u88c5Calico Demos Build CAP Application on Kyma","title":"2.2.CKA\u5b66\u4e60\u7b14\u8bb0"},{"location":"#3python","text":"","title":"3.Python"},{"location":"#31python","text":"Python\u5b89\u88c5 Python\u8bed\u8a00\u57fa\u7840 Python\u6253\u5305\u548c\u89e3\u5305 Python\u5185\u7f6e\u51fd\u6570\u53ca\u6587\u4ef6 Python\u9762\u5411\u5bf9\u8c61\u6982\u5ff5 Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027 Python\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5","title":"3.1.Python\u57fa\u7840"},{"location":"#32python","text":"NumPy\u57fa\u7840 NumPy\u8fdb\u9636 Pandas\u5165\u95e8 \u6570\u636e\u8f7d\u5165\u3001\u5b58\u50a8\u53ca\u6587\u4ef6\u683c\u5f0f \u6570\u636e\u6e05\u6d17\u4e0e\u51c6\u5907 \u6570\u636e\u89c4\u6574\uff1a\u8fde\u63a5\u3001\u8054\u5408\u4e0e\u91cd\u5851 \u7ed8\u56fe\u4e0e\u53ef\u89c6\u5316 \u6570\u636e\u805a\u5408\u4e0e\u5206\u7ec4\u64cd\u4f5c \u65f6\u95f4\u5e8f\u5217 \u9ad8\u9636pandas Python\u5efa\u6a21\u5e93\u4ecb\u7ecd","title":"3.2.Python\u6570\u636e\u5206\u6790\u57fa\u7840"},{"location":"#33","text":"1.\u57fa\u7840\u77e5\u8bc6\u56de\u987e 2.\u591a\u9879\u96c6\u7684\u6982\u8ff0 3.\u641c\u7d22\u3001\u6392\u5e8f\u4ee5\u53ca\u590d\u6742\u5ea6\u5206\u6790 4.\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784 5.\u63a5\u53e3\u3001\u5b9e\u73b0\u548c\u591a\u6001 6.\u7ee7\u627f\u4e0e\u62bd\u8c61\u7c7b","title":"3.3.\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5"},{"location":"#34demos","text":"\u9009\u8bfe\u7cfb\u7edf","title":"3.4.Demos"},{"location":"about/","text":"About \u00b6 What's past is prologue. It\u2019s never too late to do. You may also visit my posts on zhihu . --From Shanghai China","title":"About"},{"location":"about/#about","text":"What's past is prologue. It\u2019s never too late to do. You may also visit my posts on zhihu . --From Shanghai China","title":"About"},{"location":"k8s/","text":"\u6211\u7684Kubernetes\u5b66\u4e60\u5fc3\u5f97 \u00b6 \u4f5c\u4e3a\u4e00\u79cd\u5f00\u6e90\u7684\u5bb9\u5668\u7f16\u6392\u7cfb\u7edf\uff0cKubernetes \u4e3a\u8fd0\u884c\u5728\u5bb9\u5668\u4e2d\u7684\u5e94\u7528\u7a0b\u5e8f\u63d0\u4f9b\u4e86\u4e00\u79cd\u7ba1\u7406\u65b9\u5f0f\u3002Kubernetes \u5177\u6709\u5f88\u591a\u5f3a\u5927\u7684\u529f\u80fd\uff0c\u4f8b\u5982\u81ea\u52a8\u5316\u90e8\u7f72\u3001\u8d1f\u8f7d\u5747\u8861\u3001\u81ea\u52a8\u6269\u5c55\u3001\u81ea\u52a8\u6062\u590d\u7b49\u3002 \u516c\u53f8\u5185\u90e8\u7684\u4e91\u5e73\u53f0\u4e5f\u5728\u4eceCloud Foundry\u73af\u5883\u5f00\u59cb\u5411\u57fa\u4e8eKubernetes\u7684Kyma\u73af\u5883\u5ef6\u5c55\uff0c\u518d\u52a0\u4e0a\u5404\u79cd\u5a92\u4f53\u5bf9Kubernetes\u7684\u4ecb\u7ecd\uff0c\u662f\u6211\u5f00\u59cb\u4e86\u89e3Kubernetes\u7684\u5916\u90e8\u52a8\u56e0\u3002 \u5185\u90e8\u52a8\u56e0\uff0c\u5219\u662f\u6e90\u4e8e2022\u5e74\u6625\u8282\u671f\u95f4\u53c2\u52a0\u4e86\u516c\u53f8\u5185\u90e8\u7684\u4e00\u5468Kubernetes\u57fa\u7840\u57f9\u8bad\uff0c\u56e0\u4e3a\u6388\u8bfe\u5185\u5bb9\u662f\u82f1\u8bed\uff0c\u6240\u4ee5\u6709\u5f88\u591a\u7ec6\u8282\u5728\u57f9\u8bad\u4e2d\u662fget\u4e0d\u5230\u7684\uff0c\u4e3b\u8981\u8fd8\u662f\u8bed\u8a00\u80fd\u529b\u4e0d\u591f\u5f3a\u3002\u5f53\u65f6\u7684\u76ee\u6807\u53ea\u662f\u8ddf\u7740\u5b8c\u6210\u8bb2\u5e08\u8bfe\u5802\u6f14\u793a\u3002 \u4ece3\u6708\u5f00\u59cb\uff0c\u6211\u5728\u7f51\u4e0a\u4e86\u53c2\u8003\u4e86\u522b\u4eba\u7684Kubernetes\u7684\u5b66\u4e60\u5fc3\u5f97\u548c\u8def\u7ebf\u56fe\uff0c\u51b3\u5b9a\u4ee5CKA\uff08certificate of Kubernetes administration\uff09\u8ba4\u8bc1\u4f5c\u4e3a\u5f53\u524d\u5b66\u4e60\u7684\u76ee\u6807\uff0c\u5229\u7528B\u7ad9\u7684\u89c6\u9891\uff0c\u53c2\u8003\u5b98\u65b9\u6587\u6863\uff0c\u5f00\u59cb\u4ece\u5934\u5f00\u59cb\u5b66\u4e60Kubernetes\u7684\u57fa\u7840\u77e5\u8bc6\u3002 \u4e0b\u9762\u51c6\u5907CKA\u8003\u8bd5\u7684\u4e00\u4e9b\u5fc3\u5f97\u4f53\u4f1a\uff1a \u5b66\u4e60 Kubernetes \u524d\uff0c\u9700\u8981\u4e86\u89e3\u5bb9\u5668\u6280\u672f\u548c Docker\uff0c\u6216\u8005\u8bf4\u8981\u6709\u5bb9\u5668\u5316\u7684\u57fa\u672c\u6982\u5ff5\u548c\u601d\u60f3\u65b9\u6cd5\uff0c\u56e0\u4e3a Kubernetes \u662f\u57fa\u4e8e\u5bb9\u5668\u6280\u672f\u6784\u5efa\u7684\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1\u5176\u6838\u5fc3\u6982\u5ff5\uff0c\u4f8b\u5982 Pod\u3001ReplicaSet\u3001Deployment\u3001Service \u7b49\u3002\u8fd9\u4e9b\u6982\u5ff5\u662f\u7406\u89e3 Kubernetes \u7684\u57fa\u7840\uff0c\u4e5f\u662f\u540e\u7eed\u5b9e\u9645\u5e94\u7528\u4e2d\u7684\u91cd\u8981\u90e8\u5206\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1 yaml \u6587\u4ef6\u7684\u7f16\u5199\u65b9\u6cd5\uff0c\u7279\u522b\u662f\u90a3\u4e9b\u57fa\u672c\u8d44\u6e90\u7684yaml\u6587\u4ef6\uff0c\u8981\u80fd\u505a\u5230\u4e0d\u501f\u52a9\u5e2e\u52a9\u6587\u6863\u5c31\u80fd\u5199\u51fa\u6846\u67b6\uff0c\u5426\u5219\u8003\u8bd5\u65f6\u505a\u4e0d\u5b8c\u9898\u76ee\u7684\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1 kubectl \u547d\u4ee4\u7684\u4f7f\u7528\uff0c\u5e38\u7528\u8d44\u6e90\u76f8\u5173\u7684\u547d\u4ee4\uff0c\u4e5f\u8981\u505a\u5230\u4e0d\u501f\u52a9\u5e2e\u52a9\u6587\u6863\u5c31\u80fd\u5199\u51fa\uff0c\u5426\u5219\u8003\u8bd5\u65f6\u4e5f\u662f\u505a\u4e0d\u5b8c\u9898\u76ee\u7684\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1\u5176\u7f51\u7edc\u548c\u5b58\u50a8\u914d\u7f6e\uff0c\u4f8b\u5982 Service\u3001Ingress\u3001PersistentVolume\u3001PersistentVolumeClaim \u7b49\uff0c\u8fd9\u4e9b\u90fd\u662f\u8003\u8bd5\u91cd\u70b9\u5185\u5bb9\uff0c\u8981\u719f\u6089yaml\u7279\u6027\uff0c\u80fd\u6309\u4e0d\u540c\u7684\u8981\u6c42\u8fdb\u884c\u62d3\u5c55\u548c\u53d8\u66f4\u3002 \u90e8\u7f72\u548c\u7ba1\u7406 Kubernetes \u96c6\u7fa4\u4e5f\u662f\u4e00\u4e2a\u91cd\u70b9\uff0c\u6211\u662f\u5728\u963f\u91cc\u4e91\u4e0a\u4e70\u4e863\u4e2aECS\u4f5c\u4e3a\u5b9e\u9a8c\u73af\u5883\u3002 \u6211\u7684CKA\u7684\u7b14\u8bb0\u5206\u4e2d\u6587\u548c\u82f1\u6587\u4e24\u79cd\u3002\u82f1\u6587\u7b14\u8bb0\u662f\u57fa\u4e8e\u7b2c\u4e00\u6b21\u53c2\u52a0\u516c\u53f8\u57f9\u8bad\u7684\u77e5\u8bc6\u7ed3\u6784\u505a\u7684\uff0c\u5728\u5907\u8003\u8fc7\u7a0b\u4e2d\u9010\u6b65\u5b8c\u5584\u7684\u3002\u4e2d\u6587\u7b14\u8bb0\u662f\u57282023\u5e744\u6708\u4efd\u57fa\u4e8e\u82f1\u6587\u7b14\u8bb0\u81ea\u5df1\u7ffb\u8bd1\u8fc7\u6765\u7684\uff0c\u5e76\u53d1\u5e03\u5728\u6211\u7684\u77e5\u4e4e\u4e13\u680f\u4e0a\uff0c\u7ffb\u8bd1\u8fc7\u7a0b\u8fd8\u662f\u6bd4\u8f83\u96be\u7684\uff0c\u5f88\u591a\u82f1\u8bed\u5185\u5bb9\u627e\u4e0d\u5230\u5408\u9002\u7684\u4e2d\u6587\u8868\u8fbe\u65b9\u5f0f\uff0c\u4e0d\u8fc7\u5bf9\u4e8e\u8ba1\u7b97\u673a\u884c\u4e1a\u6765\u8bb2\uff0c\u4f7f\u7528\u82f1\u8bed\u9605\u8bfb\u4e13\u4e1a\u8d44\u6599\u5e94\u8be5\u662f\u4e00\u4e2a\u5171\u8bc6\u3002 \u53c2\u8003\u7b14\u8bb0\uff0c\u5e76\u5b8c\u6210\u7b14\u8bb0\u4e2d\u7684\u7ec3\u4e60\uff0c\u518d\u719f\u7ec3\u4f7f\u7528yaml\u6587\u4ef6\u548ckubectl\u547d\u4ee4\uff0c\u901a\u8fc7\u8003\u8bd5\u6ca1\u4ec0\u4e48\u56f0\u96be\u3002","title":"Index"},{"location":"k8s/#kubernetes","text":"\u4f5c\u4e3a\u4e00\u79cd\u5f00\u6e90\u7684\u5bb9\u5668\u7f16\u6392\u7cfb\u7edf\uff0cKubernetes \u4e3a\u8fd0\u884c\u5728\u5bb9\u5668\u4e2d\u7684\u5e94\u7528\u7a0b\u5e8f\u63d0\u4f9b\u4e86\u4e00\u79cd\u7ba1\u7406\u65b9\u5f0f\u3002Kubernetes \u5177\u6709\u5f88\u591a\u5f3a\u5927\u7684\u529f\u80fd\uff0c\u4f8b\u5982\u81ea\u52a8\u5316\u90e8\u7f72\u3001\u8d1f\u8f7d\u5747\u8861\u3001\u81ea\u52a8\u6269\u5c55\u3001\u81ea\u52a8\u6062\u590d\u7b49\u3002 \u516c\u53f8\u5185\u90e8\u7684\u4e91\u5e73\u53f0\u4e5f\u5728\u4eceCloud Foundry\u73af\u5883\u5f00\u59cb\u5411\u57fa\u4e8eKubernetes\u7684Kyma\u73af\u5883\u5ef6\u5c55\uff0c\u518d\u52a0\u4e0a\u5404\u79cd\u5a92\u4f53\u5bf9Kubernetes\u7684\u4ecb\u7ecd\uff0c\u662f\u6211\u5f00\u59cb\u4e86\u89e3Kubernetes\u7684\u5916\u90e8\u52a8\u56e0\u3002 \u5185\u90e8\u52a8\u56e0\uff0c\u5219\u662f\u6e90\u4e8e2022\u5e74\u6625\u8282\u671f\u95f4\u53c2\u52a0\u4e86\u516c\u53f8\u5185\u90e8\u7684\u4e00\u5468Kubernetes\u57fa\u7840\u57f9\u8bad\uff0c\u56e0\u4e3a\u6388\u8bfe\u5185\u5bb9\u662f\u82f1\u8bed\uff0c\u6240\u4ee5\u6709\u5f88\u591a\u7ec6\u8282\u5728\u57f9\u8bad\u4e2d\u662fget\u4e0d\u5230\u7684\uff0c\u4e3b\u8981\u8fd8\u662f\u8bed\u8a00\u80fd\u529b\u4e0d\u591f\u5f3a\u3002\u5f53\u65f6\u7684\u76ee\u6807\u53ea\u662f\u8ddf\u7740\u5b8c\u6210\u8bb2\u5e08\u8bfe\u5802\u6f14\u793a\u3002 \u4ece3\u6708\u5f00\u59cb\uff0c\u6211\u5728\u7f51\u4e0a\u4e86\u53c2\u8003\u4e86\u522b\u4eba\u7684Kubernetes\u7684\u5b66\u4e60\u5fc3\u5f97\u548c\u8def\u7ebf\u56fe\uff0c\u51b3\u5b9a\u4ee5CKA\uff08certificate of Kubernetes administration\uff09\u8ba4\u8bc1\u4f5c\u4e3a\u5f53\u524d\u5b66\u4e60\u7684\u76ee\u6807\uff0c\u5229\u7528B\u7ad9\u7684\u89c6\u9891\uff0c\u53c2\u8003\u5b98\u65b9\u6587\u6863\uff0c\u5f00\u59cb\u4ece\u5934\u5f00\u59cb\u5b66\u4e60Kubernetes\u7684\u57fa\u7840\u77e5\u8bc6\u3002 \u4e0b\u9762\u51c6\u5907CKA\u8003\u8bd5\u7684\u4e00\u4e9b\u5fc3\u5f97\u4f53\u4f1a\uff1a \u5b66\u4e60 Kubernetes \u524d\uff0c\u9700\u8981\u4e86\u89e3\u5bb9\u5668\u6280\u672f\u548c Docker\uff0c\u6216\u8005\u8bf4\u8981\u6709\u5bb9\u5668\u5316\u7684\u57fa\u672c\u6982\u5ff5\u548c\u601d\u60f3\u65b9\u6cd5\uff0c\u56e0\u4e3a Kubernetes \u662f\u57fa\u4e8e\u5bb9\u5668\u6280\u672f\u6784\u5efa\u7684\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1\u5176\u6838\u5fc3\u6982\u5ff5\uff0c\u4f8b\u5982 Pod\u3001ReplicaSet\u3001Deployment\u3001Service \u7b49\u3002\u8fd9\u4e9b\u6982\u5ff5\u662f\u7406\u89e3 Kubernetes \u7684\u57fa\u7840\uff0c\u4e5f\u662f\u540e\u7eed\u5b9e\u9645\u5e94\u7528\u4e2d\u7684\u91cd\u8981\u90e8\u5206\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1 yaml \u6587\u4ef6\u7684\u7f16\u5199\u65b9\u6cd5\uff0c\u7279\u522b\u662f\u90a3\u4e9b\u57fa\u672c\u8d44\u6e90\u7684yaml\u6587\u4ef6\uff0c\u8981\u80fd\u505a\u5230\u4e0d\u501f\u52a9\u5e2e\u52a9\u6587\u6863\u5c31\u80fd\u5199\u51fa\u6846\u67b6\uff0c\u5426\u5219\u8003\u8bd5\u65f6\u505a\u4e0d\u5b8c\u9898\u76ee\u7684\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1 kubectl \u547d\u4ee4\u7684\u4f7f\u7528\uff0c\u5e38\u7528\u8d44\u6e90\u76f8\u5173\u7684\u547d\u4ee4\uff0c\u4e5f\u8981\u505a\u5230\u4e0d\u501f\u52a9\u5e2e\u52a9\u6587\u6863\u5c31\u80fd\u5199\u51fa\uff0c\u5426\u5219\u8003\u8bd5\u65f6\u4e5f\u662f\u505a\u4e0d\u5b8c\u9898\u76ee\u7684\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1\u5176\u7f51\u7edc\u548c\u5b58\u50a8\u914d\u7f6e\uff0c\u4f8b\u5982 Service\u3001Ingress\u3001PersistentVolume\u3001PersistentVolumeClaim \u7b49\uff0c\u8fd9\u4e9b\u90fd\u662f\u8003\u8bd5\u91cd\u70b9\u5185\u5bb9\uff0c\u8981\u719f\u6089yaml\u7279\u6027\uff0c\u80fd\u6309\u4e0d\u540c\u7684\u8981\u6c42\u8fdb\u884c\u62d3\u5c55\u548c\u53d8\u66f4\u3002 \u90e8\u7f72\u548c\u7ba1\u7406 Kubernetes \u96c6\u7fa4\u4e5f\u662f\u4e00\u4e2a\u91cd\u70b9\uff0c\u6211\u662f\u5728\u963f\u91cc\u4e91\u4e0a\u4e70\u4e863\u4e2aECS\u4f5c\u4e3a\u5b9e\u9a8c\u73af\u5883\u3002 \u6211\u7684CKA\u7684\u7b14\u8bb0\u5206\u4e2d\u6587\u548c\u82f1\u6587\u4e24\u79cd\u3002\u82f1\u6587\u7b14\u8bb0\u662f\u57fa\u4e8e\u7b2c\u4e00\u6b21\u53c2\u52a0\u516c\u53f8\u57f9\u8bad\u7684\u77e5\u8bc6\u7ed3\u6784\u505a\u7684\uff0c\u5728\u5907\u8003\u8fc7\u7a0b\u4e2d\u9010\u6b65\u5b8c\u5584\u7684\u3002\u4e2d\u6587\u7b14\u8bb0\u662f\u57282023\u5e744\u6708\u4efd\u57fa\u4e8e\u82f1\u6587\u7b14\u8bb0\u81ea\u5df1\u7ffb\u8bd1\u8fc7\u6765\u7684\uff0c\u5e76\u53d1\u5e03\u5728\u6211\u7684\u77e5\u4e4e\u4e13\u680f\u4e0a\uff0c\u7ffb\u8bd1\u8fc7\u7a0b\u8fd8\u662f\u6bd4\u8f83\u96be\u7684\uff0c\u5f88\u591a\u82f1\u8bed\u5185\u5bb9\u627e\u4e0d\u5230\u5408\u9002\u7684\u4e2d\u6587\u8868\u8fbe\u65b9\u5f0f\uff0c\u4e0d\u8fc7\u5bf9\u4e8e\u8ba1\u7b97\u673a\u884c\u4e1a\u6765\u8bb2\uff0c\u4f7f\u7528\u82f1\u8bed\u9605\u8bfb\u4e13\u4e1a\u8d44\u6599\u5e94\u8be5\u662f\u4e00\u4e2a\u5171\u8bc6\u3002 \u53c2\u8003\u7b14\u8bb0\uff0c\u5e76\u5b8c\u6210\u7b14\u8bb0\u4e2d\u7684\u7ec3\u4e60\uff0c\u518d\u719f\u7ec3\u4f7f\u7528yaml\u6587\u4ef6\u548ckubectl\u547d\u4ee4\uff0c\u901a\u8fc7\u8003\u8bd5\u6ca1\u4ec0\u4e48\u56f0\u96be\u3002","title":"\u6211\u7684Kubernetes\u5b66\u4e60\u5fc3\u5f97"},{"location":"k8s/cka_cn/foundamentals/basics/","text":"CKA\u81ea\u5b66\u7b14\u8bb07:kubectl\u57fa\u7840 \u00b6 \u6458\u8981 \u00b6 \u4e86\u89e3\u5982\u4f55\u4f7f\u7528 kubectl \u64cd\u4f5cKubernetes\u96c6\u7fa4\u3002 via API via kubectl via Dashboard \u68c0\u67e5\u5f53\u524dkubeconfig\u6587\u4ef6\u914d\u7f6e \u00b6 \u901a\u8fc7\u547d\u4ee4 kubectl config \u68c0\u67e5\u5f53\u524d\u914d\u7f6e\u6587\u4ef6\u4e2d\u7684\u4e0a\u4e0b\u6587\u3002 echo $KUBECONFIG kubectl config view kubectl config get-contexts \u83b7\u53d6\u8d44\u6e90\u6e05\u5355 \u00b6 \u8bfb\u53d6\u6240\u6709\u652f\u6301\u7684\u8d44\u6e90\u6e05\u5355\u3002 kubectl api-resources \u83b7\u53d6\u96c6\u7fa4\u72b6\u6001 \u00b6 Kubernetes \u63a7\u5236\u9762\u677f\u8fd0\u884c\u5728 https://:6443 \u3002 CoreDNS \u8fd0\u884c\u5728 https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy \u3002 kubectl cluster-info kubectl cluster-info dump \u8bfb\u53d6\u5f53\u524d\u8d44\u6e90 \u00b6 \u6267\u884c\u547d\u4ee4 kubectl get --help \u53ef\u4ee5\u5f97\u5230get\u547d\u4ee4\u7684\u793a\u4f8b\u548c\u4f7f\u7528\u65b9\u6cd5\u3002 \u8bfb\u53d6\u5f53\u524d\u63a7\u5236\u9762\u677f\u7684\u5065\u5eb7\u72b6\u6001\u3002 kubectl get componentstatuses kubectl get cs \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS MESSAGE ERROR etcd-0 Healthy {\"health\":\"true\",\"reason\":\"\"} scheduler Healthy ok controller-manager Healthy ok \u8bfb\u53d6\u8282\u70b9\u72b6\u6001\u548c\u4fe1\u606f \u00b6 kubectl get nodes kubectl get nodes -o wide kubectl describe node cka001 \u53ef\u4ee5\u901a\u8fc7\u547d\u4ee4 kubectl create --help \u6765\u83b7\u53d6get\u547d\u4ee4\u7684\u5e2e\u52a9\u548c\u793a\u4f8b\u3002 \u521b\u5efaNamespace \u00b6 kubectl create namespace --help kubectl create namespace my-namespace \u63d0\u793a\uff1a \u547d\u540d\u7a7a\u95f4Namespace\u662f\u4e00\u4e2a\u96c6\u7fa4\uff0c\u5305\u542b\u4e86\u670d\u52a1\u3002\u670d\u52a1\u53ef\u80fd\u5728\u4e00\u4e2a\u8282\u70b9\u4e0a\uff0c\u4e5f\u53ef\u80fd\u4e0d\u5728\u3002 Namespace\u662f\u4e00\u79cd\u7528\u6765\u7ec4\u7ec7\u670d\u52a1\u7684\u65b9\u5f0f\uff0c\u5b83\u53ef\u4ee5\u5bf9\u670d\u52a1\u8fdb\u884c\u9694\u79bb\u548c\u5212\u5206\u3002 \u4e0d\u540c\u7684Namespace\u4e0b\uff0c\u53ef\u4ee5\u5b58\u5728\u76f8\u540c\u7684\u670d\u52a1\u540d\uff0c\u4f46\u662f\u4e0d\u540c\u7684Namespace\u4e4b\u95f4\u7684\u670d\u52a1\u4e0d\u80fd\u76f4\u63a5\u901a\u4fe1\uff0c\u9700\u8981\u901a\u8fc7Service\u6216Ingress\u6765\u66b4\u9732\u3002 \u670d\u52a1\u662f\u4e00\u79cd\u63d0\u4f9b\u529f\u80fd\u7684\u5b9e\u4f53 \u8282\u70b9\u662f\u4e00\u79cd\u8fd0\u884c\u670d\u52a1\u7684\u7269\u7406\u6216\u865a\u62df\u673a\u5668 \u521b\u5efadeployment \u00b6 \u5728\u67d0\u4e2aNamespace\u4e2d\u521b\u5efaDeployment\u3002 kubectl -n my-namespace create deployment my-busybox \\ --image = busybox \\ --replicas = 3 \\ --port = 5701 \u521b\u5efaClusterRole \u00b6 kubectl create clusterrole --help kubectl create clusterrole pod-creater \\ -n my-namespace \\ --verb = create \\ --resource = deployment \\ --resource-name = my-busybox \u521b\u5efaServiceAccount \u00b6 kubectl create serviceaccount --help kubectl -n my-namespace create serviceaccount my-service-account \u521b\u5efaRoleBinding \u00b6 RoleBinding \u53ef\u4ee5\u5f15\u7528\u540c\u4e00\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u4e00\u4e2aRole\uff0c\u6216\u8005\u5168\u5c40\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u4e00\u4e2aClusterRole\u3002 RoleBinding \u662f\u4e00\u79cd\u7528\u6765\u6388\u6743\u89d2\u8272\u7684\u8d44\u6e90\u3002 Role\u662f\u4e00\u79cd\u5b9a\u4e49\u6743\u9650\u7684\u8d44\u6e90\uff0c\u53ea\u80fd\u5728\u540c\u4e00\u547d\u540d\u7a7a\u95f4\u5185\u751f\u6548\u3002 ClusterRole\u662f\u4e00\u79cd\u5b9a\u4e49\u6743\u9650\u7684\u8d44\u6e90\uff0c\u53ef\u4ee5\u5728\u6574\u4e2a\u96c6\u7fa4\u5185\u751f\u6548\u3002 kubectl create rolebinding --help kubectl create rolebinding NAME \\ --clusterrole = NAME | --role = NAME \\ [ --user = username ] \\ [ --group = groupname ] \\ [ --serviceaccount = namespace:serviceaccountname ] \\ [ --dry-run = server | client | none ] kubectl create rolebinding my-admin \\ --clusterrole = pod-creater \\ --serviceaccount = my-namespace:my-service-account \u4f7f\u7528proxy \u00b6 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 kubectl proxy \u547d\u4ee4\u6765\u6253\u5f00\u4e00\u4e2a\u5230API\u670d\u52a1\u5668\u7684\u96a7\u9053\uff08tunnel\uff09\uff0c\u5e76\u4f7f\u5b83\u5728\u672c\u5730\u53ef\u7528 - \u901a\u5e38\u662f\u5728 localhost:8001 / 127.0.0.1:8001 \u3002\u5f53\u6211\u60f3\u8981\u4f7f\u7528API\u65f6\uff0c\u6700\u7b80\u5355\u7684\u65b9\u6cd5\u5c31\u662f\u83b7\u53d6\u8bbf\u95ee\u6743\u9650\u3002 \u8fd0\u884c\u547d\u4ee4 kubectl proxy & \u5e76\u5728\u6d4f\u89c8\u5668\u4e2d\u6253\u5f00 http://localhost:8001/api/v1 \u3002 \u53ea\u6253\u5f00 http://localhost:8001 \u4f1a\u8fd4\u56de\u9519\u8bef\uff0c\u56e0\u4e3a\u6211\u4eec\u53ea\u80fd\u8bbf\u95eeAPI\u7684\u67d0\u4e9b\u5185\u5bb9\uff0c\u56e0\u6b64API\u8def\u5f84\u5f88\u91cd\u8981\u3002 \u8981\u70b9\u662f\uff1a kubectl proxy \u547d\u4ee4\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u672c\u5730\u4ee3\u7406\uff0c\u8ba9\u6211\u4eec\u53ef\u4ee5\u8bbf\u95eeAPI\u670d\u52a1\u5668\u3002 API\u670d\u52a1\u5668\u63d0\u4f9b\u4e86\u96c6\u7fa4\u7684\u5404\u79cd\u4fe1\u606f\u548c\u64cd\u4f5c\u3002 \u6211\u4eec\u9700\u8981\u6307\u5b9a\u6b63\u786e\u7684API\u8def\u5f84\uff0c\u624d\u80fd\u8bbf\u95ee\u6211\u4eec\u60f3\u8981\u7684\u8d44\u6e90\u3002 kubectl proxy & \u8f93\u51fa\u7ed3\u679c\uff1a [1] 102358 Starting to serve on 127.0.0.1:8001 \u6bd4\u5982\uff1a http://127.0.0.1:8001/ http://127.0.0.1:8001/api/v1 http://127.0.0.1:8001/api/v1/namespaces http://127.0.0.1:8001/api/v1/namespaces/default http://127.0.0.1:8001/api/v1/namespaces/sock-shop/pods \u4f5c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u8bbf\u95ee \u00b6 \u5982\u679c\u6211\u4eec\u4f5c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u800c\u4e0d\u662f\u7ba1\u7406\u5458\u6765\u8bbf\u95eekubernetes\uff0c\u5c31\u4e0d\u80fd\u4f7f\u7528 kubectl \uff0c\u53ef\u4ee5\u7528 curl \u7a0b\u5e8f\u6765\u4ee3\u66ff kubectl \u3002 \u6211\u4eec\u5fc5\u987b\u5411\u96c6\u7fa4\u53d1\u9001HTTP\u8bf7\u6c42\uff0c\u8be2\u95ee\u53ef\u7528\u7684\u8282\u70b9\u3002 \u786e\u4fdd kubectl proxy \u6b63\u5728\u8fd0\u884c\uff0c\u5e76\u5728 http://localhost:8001/ \u4e0a\u63d0\u4f9b\u670d\u52a1\u3002 \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u65f6\u52a0\u4e0a\u4e00\u4e2a -v=9 \u7684\u6807\u5fd7\uff0c\u5b83\u4f1a\u663e\u793a\u6240\u6709\u9700\u8981\u7684\u4fe1\u606f\u3002 \u8981\u70b9\uff1a \u8bbf\u95ee\uff08access\uff09\u662f\u4e00\u79cd\u83b7\u53d6\u8d44\u6e90\u6216\u670d\u52a1\u7684\u884c\u4e3a\u3002 \u5e94\u7528\u7a0b\u5e8f\uff08application\uff09\u662f\u4e00\u79cd\u6267\u884c\u7279\u5b9a\u529f\u80fd\u7684\u8f6f\u4ef6\u3002 \u4f5c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u8bbf\u95ee\u610f\u5473\u7740\u4f7f\u7528\u5e94\u7528\u7a0b\u5e8f\u7684\u8eab\u4efd\u6216\u51ed\u8bc1\u6765\u8bbf\u95ee\u3002 kubernetes\u662f\u4e00\u79cd\u7ba1\u7406\u5bb9\u5668\u5316\u5e94\u7528\u7a0b\u5e8f\u7684\u5e73\u53f0\u3002 kubectl \u662f\u4e00\u79cd\u7528\u6765\u548ckubernetes\u4ea4\u4e92\u7684\u547d\u4ee4\u884c\u5de5\u5177\u3002 curl \u662f\u4e00\u79cd\u7528\u6765\u53d1\u9001HTTP\u8bf7\u6c42\u7684\u547d\u4ee4\u884c\u5de5\u5177\u3002 kubectl proxy \u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u672c\u5730\u4ee3\u7406\uff0c\u8ba9\u6211\u4eec\u53ef\u4ee5\u8bbf\u95eekubernetes\u7684API\u670d\u52a1\u5668\u3002 -v=9 \u662f\u4e00\u79cd\u7528\u6765\u663e\u793a\u8be6\u7ec6\u4fe1\u606f\u7684\u9009\u9879\u3002 kubectl get nodes \u5728\u4e0a\u9762\u547d\u4ee4\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u627e\u5230\u5bf9\u5e94\u7684curl\u8bf7\u6c42\u4fe1\u606f\u3002 curl -v -XGET \\ -H \"Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json\" \\ -H \"User-Agent: kubectl/v1.24.1 (linux/amd64) kubernetes/3ddd0f4\" \\ 'https:///api/v1/nodes?limit=500' \u53c2\u8003\u4fe1\u606f\uff1a forum-like page \u662f\u6709K8s\u8fd0\u8425\u7684\u5e73\u53f0\uff0c\u63d0\u4f9b\u4e86\u5f88\u591a\u5173\u4e8e\u5982\u4f55\u4f7f\u7528 kubectl \u7684\u8be6\u7ec6\u4fe1\u606f\u548c\u4f8b\u5b50\u3002 Manage multiple clusters and multiple config files kubectl command documentation Shell autocompletion kubectl cheat sheet jsonpath in kubectl kubectl","title":"kubectl\u57fa\u7840"},{"location":"k8s/cka_cn/foundamentals/basics/#cka7kubectl","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb07:kubectl\u57fa\u7840"},{"location":"k8s/cka_cn/foundamentals/basics/#_1","text":"\u4e86\u89e3\u5982\u4f55\u4f7f\u7528 kubectl \u64cd\u4f5cKubernetes\u96c6\u7fa4\u3002 via API via kubectl via Dashboard","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/basics/#kubeconfig","text":"\u901a\u8fc7\u547d\u4ee4 kubectl config \u68c0\u67e5\u5f53\u524d\u914d\u7f6e\u6587\u4ef6\u4e2d\u7684\u4e0a\u4e0b\u6587\u3002 echo $KUBECONFIG kubectl config view kubectl config get-contexts","title":"\u68c0\u67e5\u5f53\u524dkubeconfig\u6587\u4ef6\u914d\u7f6e"},{"location":"k8s/cka_cn/foundamentals/basics/#_2","text":"\u8bfb\u53d6\u6240\u6709\u652f\u6301\u7684\u8d44\u6e90\u6e05\u5355\u3002 kubectl api-resources","title":"\u83b7\u53d6\u8d44\u6e90\u6e05\u5355"},{"location":"k8s/cka_cn/foundamentals/basics/#_3","text":"Kubernetes \u63a7\u5236\u9762\u677f\u8fd0\u884c\u5728 https://:6443 \u3002 CoreDNS \u8fd0\u884c\u5728 https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy \u3002 kubectl cluster-info kubectl cluster-info dump","title":"\u83b7\u53d6\u96c6\u7fa4\u72b6\u6001"},{"location":"k8s/cka_cn/foundamentals/basics/#_4","text":"\u6267\u884c\u547d\u4ee4 kubectl get --help \u53ef\u4ee5\u5f97\u5230get\u547d\u4ee4\u7684\u793a\u4f8b\u548c\u4f7f\u7528\u65b9\u6cd5\u3002 \u8bfb\u53d6\u5f53\u524d\u63a7\u5236\u9762\u677f\u7684\u5065\u5eb7\u72b6\u6001\u3002 kubectl get componentstatuses kubectl get cs \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS MESSAGE ERROR etcd-0 Healthy {\"health\":\"true\",\"reason\":\"\"} scheduler Healthy ok controller-manager Healthy ok","title":"\u8bfb\u53d6\u5f53\u524d\u8d44\u6e90"},{"location":"k8s/cka_cn/foundamentals/basics/#_5","text":"kubectl get nodes kubectl get nodes -o wide kubectl describe node cka001 \u53ef\u4ee5\u901a\u8fc7\u547d\u4ee4 kubectl create --help \u6765\u83b7\u53d6get\u547d\u4ee4\u7684\u5e2e\u52a9\u548c\u793a\u4f8b\u3002","title":"\u8bfb\u53d6\u8282\u70b9\u72b6\u6001\u548c\u4fe1\u606f"},{"location":"k8s/cka_cn/foundamentals/basics/#namespace","text":"kubectl create namespace --help kubectl create namespace my-namespace \u63d0\u793a\uff1a \u547d\u540d\u7a7a\u95f4Namespace\u662f\u4e00\u4e2a\u96c6\u7fa4\uff0c\u5305\u542b\u4e86\u670d\u52a1\u3002\u670d\u52a1\u53ef\u80fd\u5728\u4e00\u4e2a\u8282\u70b9\u4e0a\uff0c\u4e5f\u53ef\u80fd\u4e0d\u5728\u3002 Namespace\u662f\u4e00\u79cd\u7528\u6765\u7ec4\u7ec7\u670d\u52a1\u7684\u65b9\u5f0f\uff0c\u5b83\u53ef\u4ee5\u5bf9\u670d\u52a1\u8fdb\u884c\u9694\u79bb\u548c\u5212\u5206\u3002 \u4e0d\u540c\u7684Namespace\u4e0b\uff0c\u53ef\u4ee5\u5b58\u5728\u76f8\u540c\u7684\u670d\u52a1\u540d\uff0c\u4f46\u662f\u4e0d\u540c\u7684Namespace\u4e4b\u95f4\u7684\u670d\u52a1\u4e0d\u80fd\u76f4\u63a5\u901a\u4fe1\uff0c\u9700\u8981\u901a\u8fc7Service\u6216Ingress\u6765\u66b4\u9732\u3002 \u670d\u52a1\u662f\u4e00\u79cd\u63d0\u4f9b\u529f\u80fd\u7684\u5b9e\u4f53 \u8282\u70b9\u662f\u4e00\u79cd\u8fd0\u884c\u670d\u52a1\u7684\u7269\u7406\u6216\u865a\u62df\u673a\u5668","title":"\u521b\u5efaNamespace"},{"location":"k8s/cka_cn/foundamentals/basics/#deployment","text":"\u5728\u67d0\u4e2aNamespace\u4e2d\u521b\u5efaDeployment\u3002 kubectl -n my-namespace create deployment my-busybox \\ --image = busybox \\ --replicas = 3 \\ --port = 5701","title":"\u521b\u5efadeployment"},{"location":"k8s/cka_cn/foundamentals/basics/#clusterrole","text":"kubectl create clusterrole --help kubectl create clusterrole pod-creater \\ -n my-namespace \\ --verb = create \\ --resource = deployment \\ --resource-name = my-busybox","title":"\u521b\u5efaClusterRole"},{"location":"k8s/cka_cn/foundamentals/basics/#serviceaccount","text":"kubectl create serviceaccount --help kubectl -n my-namespace create serviceaccount my-service-account","title":"\u521b\u5efaServiceAccount"},{"location":"k8s/cka_cn/foundamentals/basics/#rolebinding","text":"RoleBinding \u53ef\u4ee5\u5f15\u7528\u540c\u4e00\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u4e00\u4e2aRole\uff0c\u6216\u8005\u5168\u5c40\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u4e00\u4e2aClusterRole\u3002 RoleBinding \u662f\u4e00\u79cd\u7528\u6765\u6388\u6743\u89d2\u8272\u7684\u8d44\u6e90\u3002 Role\u662f\u4e00\u79cd\u5b9a\u4e49\u6743\u9650\u7684\u8d44\u6e90\uff0c\u53ea\u80fd\u5728\u540c\u4e00\u547d\u540d\u7a7a\u95f4\u5185\u751f\u6548\u3002 ClusterRole\u662f\u4e00\u79cd\u5b9a\u4e49\u6743\u9650\u7684\u8d44\u6e90\uff0c\u53ef\u4ee5\u5728\u6574\u4e2a\u96c6\u7fa4\u5185\u751f\u6548\u3002 kubectl create rolebinding --help kubectl create rolebinding NAME \\ --clusterrole = NAME | --role = NAME \\ [ --user = username ] \\ [ --group = groupname ] \\ [ --serviceaccount = namespace:serviceaccountname ] \\ [ --dry-run = server | client | none ] kubectl create rolebinding my-admin \\ --clusterrole = pod-creater \\ --serviceaccount = my-namespace:my-service-account","title":"\u521b\u5efaRoleBinding"},{"location":"k8s/cka_cn/foundamentals/basics/#proxy","text":"\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 kubectl proxy \u547d\u4ee4\u6765\u6253\u5f00\u4e00\u4e2a\u5230API\u670d\u52a1\u5668\u7684\u96a7\u9053\uff08tunnel\uff09\uff0c\u5e76\u4f7f\u5b83\u5728\u672c\u5730\u53ef\u7528 - \u901a\u5e38\u662f\u5728 localhost:8001 / 127.0.0.1:8001 \u3002\u5f53\u6211\u60f3\u8981\u4f7f\u7528API\u65f6\uff0c\u6700\u7b80\u5355\u7684\u65b9\u6cd5\u5c31\u662f\u83b7\u53d6\u8bbf\u95ee\u6743\u9650\u3002 \u8fd0\u884c\u547d\u4ee4 kubectl proxy & \u5e76\u5728\u6d4f\u89c8\u5668\u4e2d\u6253\u5f00 http://localhost:8001/api/v1 \u3002 \u53ea\u6253\u5f00 http://localhost:8001 \u4f1a\u8fd4\u56de\u9519\u8bef\uff0c\u56e0\u4e3a\u6211\u4eec\u53ea\u80fd\u8bbf\u95eeAPI\u7684\u67d0\u4e9b\u5185\u5bb9\uff0c\u56e0\u6b64API\u8def\u5f84\u5f88\u91cd\u8981\u3002 \u8981\u70b9\u662f\uff1a kubectl proxy \u547d\u4ee4\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u672c\u5730\u4ee3\u7406\uff0c\u8ba9\u6211\u4eec\u53ef\u4ee5\u8bbf\u95eeAPI\u670d\u52a1\u5668\u3002 API\u670d\u52a1\u5668\u63d0\u4f9b\u4e86\u96c6\u7fa4\u7684\u5404\u79cd\u4fe1\u606f\u548c\u64cd\u4f5c\u3002 \u6211\u4eec\u9700\u8981\u6307\u5b9a\u6b63\u786e\u7684API\u8def\u5f84\uff0c\u624d\u80fd\u8bbf\u95ee\u6211\u4eec\u60f3\u8981\u7684\u8d44\u6e90\u3002 kubectl proxy & \u8f93\u51fa\u7ed3\u679c\uff1a [1] 102358 Starting to serve on 127.0.0.1:8001 \u6bd4\u5982\uff1a http://127.0.0.1:8001/ http://127.0.0.1:8001/api/v1 http://127.0.0.1:8001/api/v1/namespaces http://127.0.0.1:8001/api/v1/namespaces/default http://127.0.0.1:8001/api/v1/namespaces/sock-shop/pods","title":"\u4f7f\u7528proxy"},{"location":"k8s/cka_cn/foundamentals/basics/#_6","text":"\u5982\u679c\u6211\u4eec\u4f5c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u800c\u4e0d\u662f\u7ba1\u7406\u5458\u6765\u8bbf\u95eekubernetes\uff0c\u5c31\u4e0d\u80fd\u4f7f\u7528 kubectl \uff0c\u53ef\u4ee5\u7528 curl \u7a0b\u5e8f\u6765\u4ee3\u66ff kubectl \u3002 \u6211\u4eec\u5fc5\u987b\u5411\u96c6\u7fa4\u53d1\u9001HTTP\u8bf7\u6c42\uff0c\u8be2\u95ee\u53ef\u7528\u7684\u8282\u70b9\u3002 \u786e\u4fdd kubectl proxy \u6b63\u5728\u8fd0\u884c\uff0c\u5e76\u5728 http://localhost:8001/ \u4e0a\u63d0\u4f9b\u670d\u52a1\u3002 \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u65f6\u52a0\u4e0a\u4e00\u4e2a -v=9 \u7684\u6807\u5fd7\uff0c\u5b83\u4f1a\u663e\u793a\u6240\u6709\u9700\u8981\u7684\u4fe1\u606f\u3002 \u8981\u70b9\uff1a \u8bbf\u95ee\uff08access\uff09\u662f\u4e00\u79cd\u83b7\u53d6\u8d44\u6e90\u6216\u670d\u52a1\u7684\u884c\u4e3a\u3002 \u5e94\u7528\u7a0b\u5e8f\uff08application\uff09\u662f\u4e00\u79cd\u6267\u884c\u7279\u5b9a\u529f\u80fd\u7684\u8f6f\u4ef6\u3002 \u4f5c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u8bbf\u95ee\u610f\u5473\u7740\u4f7f\u7528\u5e94\u7528\u7a0b\u5e8f\u7684\u8eab\u4efd\u6216\u51ed\u8bc1\u6765\u8bbf\u95ee\u3002 kubernetes\u662f\u4e00\u79cd\u7ba1\u7406\u5bb9\u5668\u5316\u5e94\u7528\u7a0b\u5e8f\u7684\u5e73\u53f0\u3002 kubectl \u662f\u4e00\u79cd\u7528\u6765\u548ckubernetes\u4ea4\u4e92\u7684\u547d\u4ee4\u884c\u5de5\u5177\u3002 curl \u662f\u4e00\u79cd\u7528\u6765\u53d1\u9001HTTP\u8bf7\u6c42\u7684\u547d\u4ee4\u884c\u5de5\u5177\u3002 kubectl proxy \u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u672c\u5730\u4ee3\u7406\uff0c\u8ba9\u6211\u4eec\u53ef\u4ee5\u8bbf\u95eekubernetes\u7684API\u670d\u52a1\u5668\u3002 -v=9 \u662f\u4e00\u79cd\u7528\u6765\u663e\u793a\u8be6\u7ec6\u4fe1\u606f\u7684\u9009\u9879\u3002 kubectl get nodes \u5728\u4e0a\u9762\u547d\u4ee4\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u627e\u5230\u5bf9\u5e94\u7684curl\u8bf7\u6c42\u4fe1\u606f\u3002 curl -v -XGET \\ -H \"Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json\" \\ -H \"User-Agent: kubectl/v1.24.1 (linux/amd64) kubernetes/3ddd0f4\" \\ 'https:///api/v1/nodes?limit=500' \u53c2\u8003\u4fe1\u606f\uff1a forum-like page \u662f\u6709K8s\u8fd0\u8425\u7684\u5e73\u53f0\uff0c\u63d0\u4f9b\u4e86\u5f88\u591a\u5173\u4e8e\u5982\u4f55\u4f7f\u7528 kubectl \u7684\u8be6\u7ec6\u4fe1\u606f\u548c\u4f8b\u5b50\u3002 Manage multiple clusters and multiple config files kubectl command documentation Shell autocompletion kubectl cheat sheet jsonpath in kubectl kubectl","title":"\u4f5c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u8bbf\u95ee"},{"location":"k8s/cka_cn/foundamentals/casestudy-calico/","text":"\u4e3b\u9898\u8ba8\u8bba:\u5b89\u88c5Calico \u00b6 \u6f14\u793a\u573a\u666f\uff1a\u5b89\u88c5Calico \u8fd9\u662f\u4e00\u4e2a\u5173\u4e8e\u5982\u4f55\u914d\u7f6e\u548c\u6d4b\u8bd5Calico\u7f51\u7edc\u7684\u7b80\u8981\u6b65\u9aa4\uff1a Calico\u6570\u636e\u5e93\uff08Datastore\uff09\uff1aCalico\u652f\u6301\u4f7f\u7528etcd\u6216Kubernetes API server\u4f5c\u4e3a\u6570\u636e\u5b58\u50a8\u540e\u7aef\u3002\u9009\u62e9\u5e76\u90e8\u7f72\u5176\u4e2d\u4e00\u4e2a\u6570\u636e\u5b58\u50a8\u540e\u7aef\u3002 \u914d\u7f6eIP\u6c60\uff1a\u4e3a\u4e86\u4e3aKubernetes\u96c6\u7fa4\u4e2d\u7684\u8282\u70b9\u5206\u914dIP\u5730\u5740\uff0c\u9700\u8981\u914d\u7f6eIP\u6c60\u3002\u53ef\u4ee5\u901a\u8fc7Calico\u81ea\u5b9a\u4e49\u8d44\u6e90\uff08CRD\uff09\u6765\u5b9a\u4e49IP\u6c60\u3002 \u5b89\u88c5CNI\u63d2\u4ef6\uff1aCNI\u63d2\u4ef6\u8d1f\u8d23\u5728\u8282\u70b9\u4e0a\u521b\u5efa\u548c\u5220\u9664\u7f51\u7edc\u63a5\u53e3\uff0c\u5b83\u4eec\u662f\u5e94\u7528\u7a0b\u5e8f\u5bb9\u5668\u548c\u7269\u7406\u7f51\u7edc\u4e4b\u95f4\u7684\u6865\u6881\u3002\u9700\u8981\u5728Kubernetes\u8282\u70b9\u4e0a\u5b89\u88c5Calico CNI\u63d2\u4ef6\u3002 \u5b89\u88c5Typha\uff1aTypha\u662fCalico\u4e2d\u592e\u63a7\u5236\u5e73\u9762\u7684\u4e00\u4e2a\u7ec4\u4ef6\u3002\u5b83\u4eceKubernetes API server\u4e2d\u83b7\u53d6\u7f51\u7edc\u7b56\u7565\u548c\u5176\u4ed6\u4fe1\u606f\uff0c\u5e76\u5c06\u5b83\u4eec\u5206\u53d1\u7ed9\u6240\u6709\u8282\u70b9\u4e0a\u7684calico/node\u3002 \u5b89\u88c5calico/node\uff1acalico/node\u662f\u4e00\u4e2a\u8fd0\u884c\u5728Kubernetes\u8282\u70b9\u4e0a\u7684\u5b88\u62a4\u8fdb\u7a0b\u3002\u5b83\u7ba1\u7406\u8282\u70b9\u4e0a\u7684\u7f51\u7edc\u63a5\u53e3\uff0c\u5e76\u4e3a\u5bb9\u5668\u5206\u914d\u548c\u91ca\u653eIP\u5730\u5740\u3002 \u6d4b\u8bd5\u7f51\u7edc\uff1a\u5728\u5b8c\u6210\u4e0a\u8ff0\u6b65\u9aa4\u540e\uff0c\u53ef\u4ee5\u901a\u8fc7\u5728Pod\u4e4b\u95f4\u8fdb\u884c\u7f51\u7edc\u901a\u4fe1\u6765\u6d4b\u8bd5Calico\u7f51\u7edc\u662f\u5426\u6b63\u5e38\u5de5\u4f5c\u3002\u53ef\u4ee5\u521b\u5efa\u4e24\u4e2a\u8fd0\u884c\u5728\u4e0d\u540c\u8282\u70b9\u4e0a\u7684Pod\uff0c\u5e76\u5c1d\u8bd5\u4ece\u4e00\u4e2aPod ping\u53e6\u4e00\u4e2aPod\u3002\u5982\u679cping\u6210\u529f\uff0c\u5219\u8868\u793aCalico\u7f51\u7edc\u5df2\u6210\u529f\u914d\u7f6e\u548c\u8fd0\u884c\u3002 Calico\u6570\u636e\u5e93 \u00b6 \u4e3a\u4e86\u5c06Kubernetes\u7528\u4f5cCalico\u6570\u636e\u5b58\u50a8\u5e93\uff0c\u6211\u4eec\u9700\u8981\u5b9a\u4e49Calico\u4f7f\u7528\u7684\u81ea\u5b9a\u4e49\u8d44\u6e90\u3002 \u4e0b\u8f7d\u5e76\u68c0\u67e5Calico\u81ea\u5b9a\u4e49\u8d44\u6e90\u5b9a\u4e49\u5217\u8868\uff0c\u5e76\u5728\u6587\u4ef6\u7f16\u8f91\u5668\u4e2d\u6253\u5f00\u5b83\u3002 wget https://projectcalico.docs.tigera.io/manifests/crds.yaml \u5728 Kubernetes \u4e2d\u521b\u5efa Calico \u7684\u81ea\u5b9a\u4e49\u8d44\u6e90\u3002 kubectl apply -f crds.yaml \u5b89\u88c5 calicoctl \u3002 \u4e0b\u8f7d calicoctl \u4e8c\u8fdb\u5236\u6587\u4ef6\u5230\u4e00\u4e2a\u53ef\u4ee5\u8bbf\u95ee Kubernetes \u7684 Linux \u4e3b\u673a\u4e0a\uff0c\u4ee5\u76f4\u63a5\u4e0e Calico \u6570\u636e\u5b58\u50a8\u4ea4\u4e92\u3002 \u6700\u65b0\u7248\u7684calicoctl\u53ef\u4ee5\u901a\u8fc7 git page \u8fdb\u884c\u4e0b\u8f7d\uff0c\u9700\u8981\u7528\u5b9e\u9645\u7248\u672c\u53f7\u66ff\u6362\u4e0b\u9762\u7684 v3.23.2 \u7684\u7248\u672c\u53f7\u3002 wget https://github.com/projectcalico/calico/releases/download/v3.23.3/calicoctl-linux-amd64 chmod +x calicoctl-linux-amd64 sudo cp calicoctl-linux-amd64 /usr/local/bin/calicoctl \u914d\u7f6e calicoctl \u4ee5\u8bbf\u95ee Kubernetes\u3002 echo \"export KUBECONFIG=/root/.kube/config\" >> ~/.bashrc echo \"export DATASTORE_TYPE=kubernetes\" >> ~/.bashrc echo $KUBECONFIG echo $DATASTORE_TYPE \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u9a8c\u8bc1 calicoctl \u80fd\u591f\u8bbf\u95ee\u6570\u636e\u5e93\u3002 calicoctl get nodes -o wide \u8fd0\u884c\u7ed3\u679c\u7c7b\u4f3c\u5982\u4e0b\uff1a NAME ASN IPV4 IPV6 cka001 cka002 cka003 \u8282\u70b9\u662f\u7531 Kubernetes \u8282\u70b9\u5bf9\u8c61\u652f\u6301\u7684\uff0c\u56e0\u6b64\u6211\u4eec\u5e94\u8be5\u770b\u5230\u4e0e kubectl get nodes \u5339\u914d\u7684\u540d\u79f0\u3002 kubectl get nodes -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 NotReady control-plane,master 23m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka002 NotReady 22m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka003 NotReady 21m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 \u914d\u7f6eIP\u6c60 \u00b6 \u4e00\u4e2a\u5de5\u4f5c\u8d1f\u8f7d\uff08workload\uff09\u662f\u5bb9\u5668\u6216\u865a\u62df\u673a\uff0c\u57fa\u4e8eCalico\u7684\u865a\u62df\u7f51\u7edc\u3002 \u5728Kubernetes\u4e2d\uff0c\u5de5\u4f5c\u8d1f\u8f7d\u662fPod\u3002\u4e00\u4e2a\u5de5\u4f5c\u8d1f\u8f7d\u7aef\u70b9\uff08endpoint\uff09\u662f\u5de5\u4f5c\u8d1f\u8f7d\u7528\u6765\u8fde\u63a5Calico\u7f51\u7edc\u7684\u865a\u62df\u7f51\u7edc\u63a5\u53e3\u3002 IP\u6c60\u662fCalico\u4e3a\u5de5\u4f5c\u8d1f\u8f7d\u7aef\u70b9\u4f7f\u7528\u7684IP\u5730\u5740\u8303\u56f4\u3002 \u83b7\u53d6\u96c6\u7fa4\u4e2d\u5f53\u524d\u7684IP\u6c60\u3002\u76ee\u524d\uff0c\u5728\u521a\u521a\u5b89\u88c5\u5b8c\u4e4b\u540e\uff0c\u5b83\u662f\u7a7a\u7684\u3002 calicoctl get ippools \u8fd0\u884c\u7ed3\u679c\uff1a NAME CIDR SELECTOR \u6211\u4eec\u901a\u8fc7 kubeadm init \u547d\u4ee4\u6307\u5b9a\u4e86 Pod CIDR \u4e3a 10.244.0.0/16 \u3002 \u73b0\u5728\uff0c\u6211\u4eec\u4e3a\u96c6\u7fa4\u521b\u5efa\u4e24\u4e2a IP \u6c60\uff08IP pool\uff09\uff0c\u6bcf\u4e2a\u6c60\u4e4b\u95f4\u4e0d\u80fd\u91cd\u53e0\u3002 \u521b\u5efaIP\u6c60 ipv4-ippool-1 : 10.244.0.0/18 calicoctl apply -f - < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < 4h49m v1.24.0 cka003 Ready 4h49m v1.24.0 \u5b89\u88c5Typha \u00b6 Typha \u5904\u4e8e Kubernetes API \u670d\u52a1\u5668\u548c\u6bcf\u4e2a\u8282\u70b9\u5b88\u62a4\u8fdb\u7a0b\uff08\u5982\u8fd0\u884c\u5728 calico/node \u4e2d\u7684 Felix \u548c confd\uff09\u4e4b\u95f4\u3002 \u5b83\u76d1\u89c6\u8fd9\u4e9b\u5b88\u62a4\u8fdb\u7a0b\u4f7f\u7528\u7684 Kubernetes \u8d44\u6e90\u548c Calico \u81ea\u5b9a\u4e49\u8d44\u6e90\uff0c\u6bcf\u5f53\u8d44\u6e90\u66f4\u6539\u65f6\uff0c\u5b83\u4f1a\u5c06\u66f4\u65b0\u6269\u6563\u5230\u8fd9\u4e9b\u5b88\u62a4\u8fdb\u7a0b\u3002 \u8fd9\u51cf\u5c11\u4e86 Kubernetes API \u670d\u52a1\u5668\u9700\u8981\u670d\u52a1\u7684\u76d1\u89c6\u6570\uff0c\u63d0\u9ad8\u4e86\u96c6\u7fa4\u7684\u53ef\u6269\u5c55\u6027\u3002 \u51c6\u5907\u8bc1\u4e66 \u4e0b\u9762\uff0c\u6211\u4eec\u4f7f\u7528\u76f8\u4e92\u8ba4\u8bc1\u7684TLS\u6765\u786e\u4fddcalico/node\u548cTypha\u4e4b\u95f4\u7684\u901a\u4fe1\u5b89\u5168\u3002 \u751f\u6210\u4e00\u4e2a\u8bc1\u4e66\u6388\u6743\u673a\u6784\uff08CA\uff09\u5e76\u4f7f\u7528\u5b83\u6765\u4e3aTypha\u7b7e\u7f72\u8bc1\u4e66\u3002 \u5c06\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u6539\u4e3a /etc/kubernetes/pki/ \u3002 cd /etc/kubernetes/pki/ \u521b\u5efaCA\u8bc1\u4e66\u548c\u5bc6\u94a5\u3002 openssl req -x509 -newkey rsa:4096 \\ -keyout typhaca.key \\ -nodes \\ -out typhaca.crt \\ -subj \"/CN=Calico Typha CA\" \\ -days 365 \u628aCA\u8bc1\u4e66\u5b58\u653e\u5728ConfigMap\u4e2d\uff0c\u4f7fTypha\u548ccalico/node\u80fd\u591f\u8bbf\u95ee\u3002 kubectl create configmap -n kube-system calico-typha-ca --from-file = typhaca.crt \u751f\u6210Typha\u5bc6\u94a5\u548c\u8bc1\u4e66\u7b7e\u540d\u8bf7\u6c42\uff08certificate signing request\uff0cCSR\uff09\u3002 openssl req -newkey rsa:4096 \\ -keyout typha.key \\ -nodes \\ -out typha.csr \\ -subj \"/CN=calico-typha\" \u8bc1\u4e66\u7684\u901a\u7528\u540d\u79f0\uff08CN\uff09\u8bbe\u7f6e\u4e3a calico-typha \u3002 calico/node \u5c06\u88ab\u7528\u6765\u9a8c\u8bc1\u6b64\u540d\u79f0\u3002 \u4f7f\u7528 CA \u5bf9 Typha \u8bc1\u4e66\u8fdb\u884c\u7b7e\u540d\u3002 openssl x509 -req -in typha.csr \\ -CA typhaca.crt \\ -CAkey typhaca.key \\ -CAcreateserial \\ -out typha.crt \\ -days 365 \u8fd0\u884c\u7ed3\u679c\uff1a Signature ok subject=CN = calico-typha Getting CA Private Key \u5c06 Typha \u5bc6\u94a5\u548c\u8bc1\u4e66\u5b58\u50a8\u5728\u4e00\u4e2a secret \u4e2d\uff0c\u4ee5\u4fbf Typha \u53ef\u4ee5\u8bbf\u95ee\u3002 kubectl create secret generic -n kube-system calico-typha-certs --from-file = typha.key --from-file = typha.crt \u914d\u7f6eRBAC \u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u4e3ahome\u8def\u5f84\u3002 cd ~ \u521b\u5efa\u4e00\u4e2aTypha\u4f7f\u7528\u7684ServiceAccount\u3002 kubectl create serviceaccount -n kube-system calico-typha \u4e3a Typha \u521b\u5efa\u4e00\u4e2a\u96c6\u7fa4\u89d2\u8272\uff0c\u6709\u89c2\u5bdf Calico \u6570\u636e\u5b58\u50a8\u5bf9\u8c61\u7684\u6743\u9650\u3002 kubectl apply -f - < pingtest-585b76c894-s2tbs 1/1 Running 0 7s 10.244.31.0 cka002 pingtest-585b76c894-vm9wn 1/1 Running 0 7s 10.244.28.64 cka003 \u7559\u610f\u7b2c\u4e8c\u4e2a\u548c\u7b2c\u4e09\u4e2a pod \u7684 IP \u5730\u5740\u3002 \u968f\u540e\u6211\u4eec\u4f1a\u5728\u7b2c\u4e00\u4e2a pod \u4e2d\u8fd0\u884c exec \u547d\u4ee4\u3002 \u5728\u7b2c\u4e00\u4e2a pod \u5185\u90e8\uff0c\u5bf9\u53e6\u5916\u4e24\u4e2a pod \u7684 IP \u5730\u5740\u8fdb\u884c ping \u6d4b\u8bd5\u3002 \u4f8b\u5982\uff1a kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # ping 10.244.31.1 -c 4 4 packets transmitted, 4 packets received, 0 % packet loss / # ping 10.244.31.0 -c 4 4 packets transmitted, 4 packets received, 0 % packet loss / # ping 10.244.28.64 -c 4 4 packets transmitted, 0 packets received, 100 % packet loss \u8def\u7531\u68c0\u67e5 \u00b6 \u4ece\u5176\u4e2d\u4e00\u4e2a\u8282\u70b9\u9a8c\u8bc1\u662f\u5426\u80fdping\u901a\u5230\u6bcf\u4e2apod\u7684IP\u5730\u5740\u3002\u4f8b\u5982\uff1a ip route get 10 .244.31.1 ip route get 10 .244.31.0 ip route get 10 .244.28.64 \u5728\u4e0a\u9762\u7684\u7ed3\u679c\u4e2d\uff0c\u793a\u4f8b\u4e2d\u7684 via \uff08\u5b83\u662f\u63a7\u5236\u5e73\u9762\uff09\u8868\u793a\u6b64Pod IP\u7684\u4e0b\u4e00\u8df3\uff0c\u8fd9\u4e0ePod\u6240\u5728\u8282\u70b9\u7684IP\u5730\u5740\u5339\u914d\uff0c\u7b26\u5408\u9884\u671f\u3002 \u4e0d\u540cIP\u6c60\u7684IPAM\u5206\u914d\u3002\u5728\u524d\u9762\u7684\u6f14\u793a\u4e2d\uff0c\u6211\u4eec\u521b\u5efa\u4e86\u4e24\u4e2aIP\u6c60\uff0c\u4f46\u5c06\u4e00\u4e2a\u7981\u7528\u4e86\u3002 calicoctl get ippools -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR ipv4-ippool-1 10.244.0.0/18 true Never Never false false all() ipv4-ippool-2 10.244.192.0/19 true Never Never true false all() \u6fc0\u6d3b\u7b2c\u4e8c\u4e2aIP\u6c60\u3002 calicoctl --allow-version-mismatch apply -f - < \u8fde\u63a5\u5e76\u8fdb\u5165Pod pingtest-585b76c894-chwjq \u5185\u90e8\u3002 kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # 10.244.203.192 -c 4 4 packets transmitted, 0 packets received, 100 % packet loss \u6807\u8bb0\uff1a \u6f14\u793a\u6b62\u4e8e\u6b64\uff0c\u8def\u7531\u6ca1\u6709\u5b89\u88c5\u9884\u671f\u5de5\u4f5c\uff0c\u539f\u56e0\u67e5\u627e\u4e2d\u3002 \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete deployments.apps pingtest kubectl delete pod pingtest-ippool-2 \u53c2\u8003\uff1a End-to-end Calico installation","title":"\u5b89\u88c5Calico"},{"location":"k8s/cka_cn/foundamentals/casestudy-calico/#calico","text":"\u6f14\u793a\u573a\u666f\uff1a\u5b89\u88c5Calico \u8fd9\u662f\u4e00\u4e2a\u5173\u4e8e\u5982\u4f55\u914d\u7f6e\u548c\u6d4b\u8bd5Calico\u7f51\u7edc\u7684\u7b80\u8981\u6b65\u9aa4\uff1a Calico\u6570\u636e\u5e93\uff08Datastore\uff09\uff1aCalico\u652f\u6301\u4f7f\u7528etcd\u6216Kubernetes API server\u4f5c\u4e3a\u6570\u636e\u5b58\u50a8\u540e\u7aef\u3002\u9009\u62e9\u5e76\u90e8\u7f72\u5176\u4e2d\u4e00\u4e2a\u6570\u636e\u5b58\u50a8\u540e\u7aef\u3002 \u914d\u7f6eIP\u6c60\uff1a\u4e3a\u4e86\u4e3aKubernetes\u96c6\u7fa4\u4e2d\u7684\u8282\u70b9\u5206\u914dIP\u5730\u5740\uff0c\u9700\u8981\u914d\u7f6eIP\u6c60\u3002\u53ef\u4ee5\u901a\u8fc7Calico\u81ea\u5b9a\u4e49\u8d44\u6e90\uff08CRD\uff09\u6765\u5b9a\u4e49IP\u6c60\u3002 \u5b89\u88c5CNI\u63d2\u4ef6\uff1aCNI\u63d2\u4ef6\u8d1f\u8d23\u5728\u8282\u70b9\u4e0a\u521b\u5efa\u548c\u5220\u9664\u7f51\u7edc\u63a5\u53e3\uff0c\u5b83\u4eec\u662f\u5e94\u7528\u7a0b\u5e8f\u5bb9\u5668\u548c\u7269\u7406\u7f51\u7edc\u4e4b\u95f4\u7684\u6865\u6881\u3002\u9700\u8981\u5728Kubernetes\u8282\u70b9\u4e0a\u5b89\u88c5Calico CNI\u63d2\u4ef6\u3002 \u5b89\u88c5Typha\uff1aTypha\u662fCalico\u4e2d\u592e\u63a7\u5236\u5e73\u9762\u7684\u4e00\u4e2a\u7ec4\u4ef6\u3002\u5b83\u4eceKubernetes API server\u4e2d\u83b7\u53d6\u7f51\u7edc\u7b56\u7565\u548c\u5176\u4ed6\u4fe1\u606f\uff0c\u5e76\u5c06\u5b83\u4eec\u5206\u53d1\u7ed9\u6240\u6709\u8282\u70b9\u4e0a\u7684calico/node\u3002 \u5b89\u88c5calico/node\uff1acalico/node\u662f\u4e00\u4e2a\u8fd0\u884c\u5728Kubernetes\u8282\u70b9\u4e0a\u7684\u5b88\u62a4\u8fdb\u7a0b\u3002\u5b83\u7ba1\u7406\u8282\u70b9\u4e0a\u7684\u7f51\u7edc\u63a5\u53e3\uff0c\u5e76\u4e3a\u5bb9\u5668\u5206\u914d\u548c\u91ca\u653eIP\u5730\u5740\u3002 \u6d4b\u8bd5\u7f51\u7edc\uff1a\u5728\u5b8c\u6210\u4e0a\u8ff0\u6b65\u9aa4\u540e\uff0c\u53ef\u4ee5\u901a\u8fc7\u5728Pod\u4e4b\u95f4\u8fdb\u884c\u7f51\u7edc\u901a\u4fe1\u6765\u6d4b\u8bd5Calico\u7f51\u7edc\u662f\u5426\u6b63\u5e38\u5de5\u4f5c\u3002\u53ef\u4ee5\u521b\u5efa\u4e24\u4e2a\u8fd0\u884c\u5728\u4e0d\u540c\u8282\u70b9\u4e0a\u7684Pod\uff0c\u5e76\u5c1d\u8bd5\u4ece\u4e00\u4e2aPod ping\u53e6\u4e00\u4e2aPod\u3002\u5982\u679cping\u6210\u529f\uff0c\u5219\u8868\u793aCalico\u7f51\u7edc\u5df2\u6210\u529f\u914d\u7f6e\u548c\u8fd0\u884c\u3002","title":"\u4e3b\u9898\u8ba8\u8bba:\u5b89\u88c5Calico"},{"location":"k8s/cka_cn/foundamentals/casestudy-calico/#calico_1","text":"\u4e3a\u4e86\u5c06Kubernetes\u7528\u4f5cCalico\u6570\u636e\u5b58\u50a8\u5e93\uff0c\u6211\u4eec\u9700\u8981\u5b9a\u4e49Calico\u4f7f\u7528\u7684\u81ea\u5b9a\u4e49\u8d44\u6e90\u3002 \u4e0b\u8f7d\u5e76\u68c0\u67e5Calico\u81ea\u5b9a\u4e49\u8d44\u6e90\u5b9a\u4e49\u5217\u8868\uff0c\u5e76\u5728\u6587\u4ef6\u7f16\u8f91\u5668\u4e2d\u6253\u5f00\u5b83\u3002 wget https://projectcalico.docs.tigera.io/manifests/crds.yaml \u5728 Kubernetes \u4e2d\u521b\u5efa Calico \u7684\u81ea\u5b9a\u4e49\u8d44\u6e90\u3002 kubectl apply -f crds.yaml \u5b89\u88c5 calicoctl \u3002 \u4e0b\u8f7d calicoctl \u4e8c\u8fdb\u5236\u6587\u4ef6\u5230\u4e00\u4e2a\u53ef\u4ee5\u8bbf\u95ee Kubernetes \u7684 Linux \u4e3b\u673a\u4e0a\uff0c\u4ee5\u76f4\u63a5\u4e0e Calico \u6570\u636e\u5b58\u50a8\u4ea4\u4e92\u3002 \u6700\u65b0\u7248\u7684calicoctl\u53ef\u4ee5\u901a\u8fc7 git page \u8fdb\u884c\u4e0b\u8f7d\uff0c\u9700\u8981\u7528\u5b9e\u9645\u7248\u672c\u53f7\u66ff\u6362\u4e0b\u9762\u7684 v3.23.2 \u7684\u7248\u672c\u53f7\u3002 wget https://github.com/projectcalico/calico/releases/download/v3.23.3/calicoctl-linux-amd64 chmod +x calicoctl-linux-amd64 sudo cp calicoctl-linux-amd64 /usr/local/bin/calicoctl \u914d\u7f6e calicoctl \u4ee5\u8bbf\u95ee Kubernetes\u3002 echo \"export KUBECONFIG=/root/.kube/config\" >> ~/.bashrc echo \"export DATASTORE_TYPE=kubernetes\" >> ~/.bashrc echo $KUBECONFIG echo $DATASTORE_TYPE \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u9a8c\u8bc1 calicoctl \u80fd\u591f\u8bbf\u95ee\u6570\u636e\u5e93\u3002 calicoctl get nodes -o wide \u8fd0\u884c\u7ed3\u679c\u7c7b\u4f3c\u5982\u4e0b\uff1a NAME ASN IPV4 IPV6 cka001 cka002 cka003 \u8282\u70b9\u662f\u7531 Kubernetes \u8282\u70b9\u5bf9\u8c61\u652f\u6301\u7684\uff0c\u56e0\u6b64\u6211\u4eec\u5e94\u8be5\u770b\u5230\u4e0e kubectl get nodes \u5339\u914d\u7684\u540d\u79f0\u3002 kubectl get nodes -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 NotReady control-plane,master 23m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka002 NotReady 22m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka003 NotReady 21m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9","title":"Calico\u6570\u636e\u5e93"},{"location":"k8s/cka_cn/foundamentals/casestudy-calico/#ip","text":"\u4e00\u4e2a\u5de5\u4f5c\u8d1f\u8f7d\uff08workload\uff09\u662f\u5bb9\u5668\u6216\u865a\u62df\u673a\uff0c\u57fa\u4e8eCalico\u7684\u865a\u62df\u7f51\u7edc\u3002 \u5728Kubernetes\u4e2d\uff0c\u5de5\u4f5c\u8d1f\u8f7d\u662fPod\u3002\u4e00\u4e2a\u5de5\u4f5c\u8d1f\u8f7d\u7aef\u70b9\uff08endpoint\uff09\u662f\u5de5\u4f5c\u8d1f\u8f7d\u7528\u6765\u8fde\u63a5Calico\u7f51\u7edc\u7684\u865a\u62df\u7f51\u7edc\u63a5\u53e3\u3002 IP\u6c60\u662fCalico\u4e3a\u5de5\u4f5c\u8d1f\u8f7d\u7aef\u70b9\u4f7f\u7528\u7684IP\u5730\u5740\u8303\u56f4\u3002 \u83b7\u53d6\u96c6\u7fa4\u4e2d\u5f53\u524d\u7684IP\u6c60\u3002\u76ee\u524d\uff0c\u5728\u521a\u521a\u5b89\u88c5\u5b8c\u4e4b\u540e\uff0c\u5b83\u662f\u7a7a\u7684\u3002 calicoctl get ippools \u8fd0\u884c\u7ed3\u679c\uff1a NAME CIDR SELECTOR \u6211\u4eec\u901a\u8fc7 kubeadm init \u547d\u4ee4\u6307\u5b9a\u4e86 Pod CIDR \u4e3a 10.244.0.0/16 \u3002 \u73b0\u5728\uff0c\u6211\u4eec\u4e3a\u96c6\u7fa4\u521b\u5efa\u4e24\u4e2a IP \u6c60\uff08IP pool\uff09\uff0c\u6bcf\u4e2a\u6c60\u4e4b\u95f4\u4e0d\u80fd\u91cd\u53e0\u3002 \u521b\u5efaIP\u6c60 ipv4-ippool-1 : 10.244.0.0/18 calicoctl apply -f - < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < 4h49m v1.24.0 cka003 Ready 4h49m v1.24.0","title":"\u5b89\u88c5CNI\u63d2\u4ef6"},{"location":"k8s/cka_cn/foundamentals/casestudy-calico/#typha","text":"Typha \u5904\u4e8e Kubernetes API \u670d\u52a1\u5668\u548c\u6bcf\u4e2a\u8282\u70b9\u5b88\u62a4\u8fdb\u7a0b\uff08\u5982\u8fd0\u884c\u5728 calico/node \u4e2d\u7684 Felix \u548c confd\uff09\u4e4b\u95f4\u3002 \u5b83\u76d1\u89c6\u8fd9\u4e9b\u5b88\u62a4\u8fdb\u7a0b\u4f7f\u7528\u7684 Kubernetes \u8d44\u6e90\u548c Calico \u81ea\u5b9a\u4e49\u8d44\u6e90\uff0c\u6bcf\u5f53\u8d44\u6e90\u66f4\u6539\u65f6\uff0c\u5b83\u4f1a\u5c06\u66f4\u65b0\u6269\u6563\u5230\u8fd9\u4e9b\u5b88\u62a4\u8fdb\u7a0b\u3002 \u8fd9\u51cf\u5c11\u4e86 Kubernetes API \u670d\u52a1\u5668\u9700\u8981\u670d\u52a1\u7684\u76d1\u89c6\u6570\uff0c\u63d0\u9ad8\u4e86\u96c6\u7fa4\u7684\u53ef\u6269\u5c55\u6027\u3002 \u51c6\u5907\u8bc1\u4e66 \u4e0b\u9762\uff0c\u6211\u4eec\u4f7f\u7528\u76f8\u4e92\u8ba4\u8bc1\u7684TLS\u6765\u786e\u4fddcalico/node\u548cTypha\u4e4b\u95f4\u7684\u901a\u4fe1\u5b89\u5168\u3002 \u751f\u6210\u4e00\u4e2a\u8bc1\u4e66\u6388\u6743\u673a\u6784\uff08CA\uff09\u5e76\u4f7f\u7528\u5b83\u6765\u4e3aTypha\u7b7e\u7f72\u8bc1\u4e66\u3002 \u5c06\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u6539\u4e3a /etc/kubernetes/pki/ \u3002 cd /etc/kubernetes/pki/ \u521b\u5efaCA\u8bc1\u4e66\u548c\u5bc6\u94a5\u3002 openssl req -x509 -newkey rsa:4096 \\ -keyout typhaca.key \\ -nodes \\ -out typhaca.crt \\ -subj \"/CN=Calico Typha CA\" \\ -days 365 \u628aCA\u8bc1\u4e66\u5b58\u653e\u5728ConfigMap\u4e2d\uff0c\u4f7fTypha\u548ccalico/node\u80fd\u591f\u8bbf\u95ee\u3002 kubectl create configmap -n kube-system calico-typha-ca --from-file = typhaca.crt \u751f\u6210Typha\u5bc6\u94a5\u548c\u8bc1\u4e66\u7b7e\u540d\u8bf7\u6c42\uff08certificate signing request\uff0cCSR\uff09\u3002 openssl req -newkey rsa:4096 \\ -keyout typha.key \\ -nodes \\ -out typha.csr \\ -subj \"/CN=calico-typha\" \u8bc1\u4e66\u7684\u901a\u7528\u540d\u79f0\uff08CN\uff09\u8bbe\u7f6e\u4e3a calico-typha \u3002 calico/node \u5c06\u88ab\u7528\u6765\u9a8c\u8bc1\u6b64\u540d\u79f0\u3002 \u4f7f\u7528 CA \u5bf9 Typha \u8bc1\u4e66\u8fdb\u884c\u7b7e\u540d\u3002 openssl x509 -req -in typha.csr \\ -CA typhaca.crt \\ -CAkey typhaca.key \\ -CAcreateserial \\ -out typha.crt \\ -days 365 \u8fd0\u884c\u7ed3\u679c\uff1a Signature ok subject=CN = calico-typha Getting CA Private Key \u5c06 Typha \u5bc6\u94a5\u548c\u8bc1\u4e66\u5b58\u50a8\u5728\u4e00\u4e2a secret \u4e2d\uff0c\u4ee5\u4fbf Typha \u53ef\u4ee5\u8bbf\u95ee\u3002 kubectl create secret generic -n kube-system calico-typha-certs --from-file = typha.key --from-file = typha.crt \u914d\u7f6eRBAC \u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u4e3ahome\u8def\u5f84\u3002 cd ~ \u521b\u5efa\u4e00\u4e2aTypha\u4f7f\u7528\u7684ServiceAccount\u3002 kubectl create serviceaccount -n kube-system calico-typha \u4e3a Typha \u521b\u5efa\u4e00\u4e2a\u96c6\u7fa4\u89d2\u8272\uff0c\u6709\u89c2\u5bdf Calico \u6570\u636e\u5b58\u50a8\u5bf9\u8c61\u7684\u6743\u9650\u3002 kubectl apply -f - < pingtest-585b76c894-s2tbs 1/1 Running 0 7s 10.244.31.0 cka002 pingtest-585b76c894-vm9wn 1/1 Running 0 7s 10.244.28.64 cka003 \u7559\u610f\u7b2c\u4e8c\u4e2a\u548c\u7b2c\u4e09\u4e2a pod \u7684 IP \u5730\u5740\u3002 \u968f\u540e\u6211\u4eec\u4f1a\u5728\u7b2c\u4e00\u4e2a pod \u4e2d\u8fd0\u884c exec \u547d\u4ee4\u3002 \u5728\u7b2c\u4e00\u4e2a pod \u5185\u90e8\uff0c\u5bf9\u53e6\u5916\u4e24\u4e2a pod \u7684 IP \u5730\u5740\u8fdb\u884c ping \u6d4b\u8bd5\u3002 \u4f8b\u5982\uff1a kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # ping 10.244.31.1 -c 4 4 packets transmitted, 4 packets received, 0 % packet loss / # ping 10.244.31.0 -c 4 4 packets transmitted, 4 packets received, 0 % packet loss / # ping 10.244.28.64 -c 4 4 packets transmitted, 0 packets received, 100 % packet loss","title":"pod\u4e4b\u95f4\u7684ping"},{"location":"k8s/cka_cn/foundamentals/casestudy-calico/#_2","text":"\u4ece\u5176\u4e2d\u4e00\u4e2a\u8282\u70b9\u9a8c\u8bc1\u662f\u5426\u80fdping\u901a\u5230\u6bcf\u4e2apod\u7684IP\u5730\u5740\u3002\u4f8b\u5982\uff1a ip route get 10 .244.31.1 ip route get 10 .244.31.0 ip route get 10 .244.28.64 \u5728\u4e0a\u9762\u7684\u7ed3\u679c\u4e2d\uff0c\u793a\u4f8b\u4e2d\u7684 via \uff08\u5b83\u662f\u63a7\u5236\u5e73\u9762\uff09\u8868\u793a\u6b64Pod IP\u7684\u4e0b\u4e00\u8df3\uff0c\u8fd9\u4e0ePod\u6240\u5728\u8282\u70b9\u7684IP\u5730\u5740\u5339\u914d\uff0c\u7b26\u5408\u9884\u671f\u3002 \u4e0d\u540cIP\u6c60\u7684IPAM\u5206\u914d\u3002\u5728\u524d\u9762\u7684\u6f14\u793a\u4e2d\uff0c\u6211\u4eec\u521b\u5efa\u4e86\u4e24\u4e2aIP\u6c60\uff0c\u4f46\u5c06\u4e00\u4e2a\u7981\u7528\u4e86\u3002 calicoctl get ippools -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR ipv4-ippool-1 10.244.0.0/18 true Never Never false false all() ipv4-ippool-2 10.244.192.0/19 true Never Never true false all() \u6fc0\u6d3b\u7b2c\u4e8c\u4e2aIP\u6c60\u3002 calicoctl --allow-version-mismatch apply -f - < \u8fde\u63a5\u5e76\u8fdb\u5165Pod pingtest-585b76c894-chwjq \u5185\u90e8\u3002 kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # 10.244.203.192 -c 4 4 packets transmitted, 0 packets received, 100 % packet loss \u6807\u8bb0\uff1a \u6f14\u793a\u6b62\u4e8e\u6b64\uff0c\u8def\u7531\u6ca1\u6709\u5b89\u88c5\u9884\u671f\u5de5\u4f5c\uff0c\u539f\u56e0\u67e5\u627e\u4e2d\u3002 \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete deployments.apps pingtest kubectl delete pod pingtest-ippool-2 \u53c2\u8003\uff1a End-to-end Calico installation","title":"\u8def\u7531\u68c0\u67e5"},{"location":"k8s/cka_cn/foundamentals/casestudy-health-check/","text":"\u4e3b\u9898\u8ba8\u8bba:\u5065\u5eb7\u68c0\u67e5 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa Deployment \u548c Service \u6a21\u62df\u4e00\u4e2a\u9519\u8bef\uff08\u5220\u9664 index.html\uff09 Pod \u5904\u4e8e\u4e0d\u5065\u5eb7\u72b6\u6001\u5e76\u4ece endpoint \u5217\u8868\u4e2d\u5220\u9664 \u4fee\u590d\u9519\u8bef\uff08\u6062\u590d index.html\uff09 Pod \u56de\u5230\u6b63\u5e38\u72b6\u6001\u5e76\u91cd\u65b0\u52a0\u5165 endpoint \u5217\u8868 \u521b\u5efa Deployment \u548c Service \u00b6 \u521b\u5efaDeployment nginx-healthcheck \u548cService nginx-healthcheck \u3002 kubectl apply -f - < nginx-healthcheck-79fc55d944-nwwjc 1/1 Running 0 9s 10.244.112.13 cka002 \u901a\u8fc7\u547d\u4ee4 curl \u6765\u8bbf\u95ee\u4e0a\u9762\u8fd0\u884c\u7ed3\u679c\u4e2dpod\u7684IP\u5730\u5740\u3002 curl 10 .244.102.14 curl 10 .244.112.13 \u5982\u679c\u4e0a\u9762\u547d\u4ee4\u6210\u529f\u6267\u884c\uff0c\u5219\u4f1a\u8fd4\u56deNginx\u4e2d index.html \u7684\u5185\u5bb9\u3002 \u83b7\u53d6\u524d\u9762\u521b\u5efa\u7684Service\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl describe svc nginx-healthcheck \u8f93\u51fa\u7ed3\u679c\u5982\u4e0b\u3002\u5728 Endpoints \u90e8\u5206\u6211\u4eec\u53ef\u4ee5\u770b\u52302\u4e2apod\u3002 Name : nginx-healthcheck Namespace : dev Labels : Annotations : Selector : name=nginx-healthcheck Type : NodePort IP Family Policy : SingleStack IP Families : IPv4 IP : 11.244.238.20 IPs : 11.244.238.20 Port : 80/TCP TargetPort : 80/TCP NodePort : 31795/TCP Endpoints : 10.244.102.14:80,10.244.112.13:80 Session Affinity : None External Traffic Policy : Cluster Events : \u83b7\u53d6Endpoints\u7684\u4fe1\u606f\u3002 kubectl get endpoints nginx-healthcheck \u8fd0\u884c\u7ed3\u679c NAME ENDPOINTS AGE nginx-healthcheck 10.244.102.14:80,10.244.112.13:80 72s \u81f3\u6b64\uff0c2\u4e2apod nginx-healthcheck \u90fd\u80fd\u6309\u7167\u6211\u4eec\u7684\u671f\u671b\u6b63\u5e38\u5de5\u4f5c\u3002 \u6a21\u62dfreadinessProbe\u9519\u8bef \u00b6 \u8ba9\u6211\u4eec\u901a\u8fc7\u5220\u9664 nginx-healthcheck Pod \u4e2d\u7684 index.html \u6587\u4ef6\u6765\u6a21\u62df\u9519\u8bef\uff0c\u89c2\u5bdf readinessProbe \u7684\u8868\u73b0\u3002 \u9996\u5148\uff0c\u6267\u884c kubectl exec -it -- bash \u547d\u4ee4\u4ee5\u767b\u5f55\u5230 nginx-healthcheck Pod\uff0c\u5e76\u5220\u9664 index.html \u6587\u4ef6\u3002 kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ rm -rf index.html exit \u5728\u6267\u884c\u4e86\u5220\u9664 nginx-healthcheck Pod \u4e2d\u7684 index.html \u6587\u4ef6\u4e4b\u540e\uff0c\u6211\u4eec\u68c0\u67e5\u8be5 Pod \u7684\u72b6\u6001\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-jw887 \u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230 Readiness probe failed \u8fd9\u4e2a\u9519\u8bef\u4e8b\u4ef6\u4fe1\u606f\u3002 ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m8s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-jw887 to cka003 Normal Pulled 2m7s kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m7s kubelet Created container nginx-healthcheck Normal Started 2m7s kubelet Started container nginx-healthcheck Warning Unhealthy 2s (x2 over 7s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 403 \u68c0\u67e5\u53e6\u4e00\u4e2apod\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-nwwjc \u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6ca1\u6709\u53d1\u73b0\u9519\u8bef\u3002 ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 3m46s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-nwwjc to cka002 Normal Pulled 3m45s kubelet Container image \"nginx:latest\" already present on machine Normal Created 3m45s kubelet Created container nginx-healthcheck Normal Started 3m45s kubelet Started container nginx-healthcheck \u73b0\u5728\uff0c\u901a\u8fc7 curl \u547d\u4ee4\u6765\u8bbf\u95ee2\u4e2apod\u7684IP\u5730\u5740\uff0c\u6211\u4eec\u6765\u89c2\u5bdf\u4f1a\u5f97\u5230\u600e\u6837\u7684\u7ed3\u679c\u3002 curl 10 .244.102.14 curl 10 .244.112.13 \u8fd0\u884c\u7ed3\u679c\uff1a curl 10.244.102.14 \u5931\u8d25\uff0c\u9519\u8bef\u4fe1\u606f\u662f 403 Forbidden \u3002 curl 10.244.112.13 \u6210\u529f\u3002 \u6211\u4eec\u73b0\u5728\u6765\u67e5\u8be2Nginx service\u5728\u4e00\u4e2apod\u5931\u8d25\u65f6\u7684\u72b6\u6001\u3002 kubectl describe svc nginx-healthcheck \u5728\u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6211\u4eec\u770b\u5230Endpoint\u90e8\u5206\u4e2d\u53ea\u6709\u4e00\u4e2apod\u7684\u4fe1\u606f\u3002 Name : nginx-healthcheck Namespace : dev Labels : Annotations : Selector : name=nginx-healthcheck Type : NodePort IP Family Policy : SingleStack IP Families : IPv4 IP : 11.244.238.20 IPs : 11.244.238.20 Port : 80/TCP TargetPort : 80/TCP NodePort : 31795/TCP Endpoints : 10.244.112.13:80 Session Affinity : None External Traffic Policy : Cluster Events : \u540c\u6837\u7684\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u68c0\u67e5Endpoint\u7684\u4fe1\u606f\uff0c\u4e5f\u80fd\u53d1\u73b0\u53ea\u6709\u4e00\u4e2apod\u6b63\u5728\u8fd0\u884c\u3002 kubectl get endpoints nginx-healthcheck \u8fd0\u884c\u7ed3\u679c\uff1a NAME ENDPOINTS AGE nginx-healthcheck 10.244.112.13:80 6m5s \u4fee\u590dreadinessProbe\u9519\u8bef \u00b6 \u73b0\u5728\uff0c\u6211\u4eec\u5728pod\u4e2d\u91cd\u65b0\u521b\u5efa index.html \u6587\u4ef6\uff0c\u6765\u4fee\u590d\u9519\u8bef\u3002 kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ cat > index.html << EOF Welcome to nginx!

    Welcome to nginx!

    If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

    For online documentation and support please refer to nginx.org.
    Commercial support is available at nginx.com.

    Thank you for using nginx.

    EOF exit \u73b0\u5728\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u4e24\u4e2aPod\u5df2\u7ecf\u91cd\u65b0\u52a0\u5165\u4e86Endpoint\u5217\u8868\uff0c\u53ef\u4ee5\u63d0\u4f9b\u670d\u52a1\u4e86\u3002 kubectl describe svc nginx-healthcheck kubectl get endpoints nginx-healthcheck \u91cd\u65b0\u901a\u8fc7 curl \u547d\u4ee4\u8bbf\u95ee2\u4e2apod\u7684IP\u5730\u5740\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5b83\u4eec\u90fd\u5df2\u7ecf\u6062\u590d\u5230\u6b63\u5e38\u72b6\u6001\u4e86\u3002 curl 10 .244.102.14 curl 10 .244.112.13 \u518d\u6b21\u9a8c\u8bc1pod\u7684\u72b6\u6001\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-jw887 \u7ed3\u8bba\uff1a \u901a\u8fc7\u5220\u9664 index.html \u6587\u4ef6\uff0cPod \u8fdb\u5165\u4e0d\u5065\u5eb7\u72b6\u6001\u5e76\u4ece\u7aef\u70b9\u5217\u8868\u4e2d\u5220\u9664\u3002 \u53ea\u6709\u4e00\u4e2a\u5065\u5eb7\u7684 Pod \u53ef\u4ee5\u63d0\u4f9b\u6b63\u5e38\u7684\u670d\u52a1\u3002 \u6e05\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete service nginx-healthcheck kubectl delete deployment nginx-healthcheck \u6a21\u62dflivenessProbe\u9519\u8bef \u00b6 \u91cd\u65b0\u521b\u5efadeployment nginx-healthcheck \u548cservice nginx-healthcheck \u3002 Deployment: NAME READY UP-TO-DATE AVAILABLE AGE nginx-healthcheck 0/2 2 0 7s Pods: NAME READY STATUS RESTARTS AGE nginx-healthcheck-79fc55d944-lknp9 1/1 Running 0 96s nginx-healthcheck-79fc55d944-wntmg 1/1 Running 0 96s \u5c06 Nginx \u9ed8\u8ba4\u76d1\u542c\u7aef\u53e3\u4ece 80 \u6539\u4e3a 90 \uff0c\u4ee5\u6a21\u62df livenessProbe \u5931\u8d25\u3002livenessProbe \u901a\u8fc7\u7aef\u53e3 80 \u68c0\u67e5\u751f\u5b58\u72b6\u6001\u3002 kubectl exec -it nginx-healthcheck-79fc55d944-lknp9 -- bash root@nginx-healthcheck-79fc55d944-lknp9:/# cd /etc/nginx/conf.d root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# sed -i 's/80/90/g' default.conf root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# nginx -s reload 2022 /07/24 12 :59:45 [ notice ] 79 #79: signal process started Pod\u73b0\u5728\u8868\u73b0\u4e3a\u5931\u8d25\u72b6\u6001\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-lknp9 \u5728pod\u7684\u4e8b\u4ef6\u4fe1\u606f\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u53d1\u73b0 livenessProbe \u9519\u8bef\u4fe1\u606f\u3002 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 17m default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-lknp9 to cka003 Normal Pulled 2m47s (x2 over 17m) kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m47s (x2 over 17m) kubelet Created container nginx-healthcheck Normal Started 2m47s (x2 over 17m) kubelet Started container nginx-healthcheck Warning Unhealthy 2m47s (x4 over 2m57s) kubelet Readiness probe failed: Get \"http://10.244.102.46:80/\": dial tcp 10.244.102.46:80: connect: connection refused Warning Unhealthy 2m47s (x3 over 2m57s) kubelet Liveness probe failed: dial tcp 10.244.102.46:80: connect: connection refused Normal Killing 2m47s kubelet Container nginx-healthcheck failed liveness probe, will be restarted \u5f53 livenessProbe \u68c0\u6d4b\u5230\u5931\u8d25\u540e\uff0c\u5bb9\u5668\u5c06\u81ea\u52a8\u91cd\u65b0\u542f\u52a8\u3002\u6211\u4eec\u4fee\u6539\u7684 default.conf \u6587\u4ef6\u5c06\u88ab\u9ed8\u8ba4\u6587\u4ef6\u66ff\u6362\uff0c\u5bb9\u5668\u72b6\u6001\u5c06\u6062\u590d\u6b63\u5e38\u3002","title":"\u5065\u5eb7\u68c0\u67e5"},{"location":"k8s/cka_cn/foundamentals/casestudy-health-check/#_1","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa Deployment \u548c Service \u6a21\u62df\u4e00\u4e2a\u9519\u8bef\uff08\u5220\u9664 index.html\uff09 Pod \u5904\u4e8e\u4e0d\u5065\u5eb7\u72b6\u6001\u5e76\u4ece endpoint \u5217\u8868\u4e2d\u5220\u9664 \u4fee\u590d\u9519\u8bef\uff08\u6062\u590d index.html\uff09 Pod \u56de\u5230\u6b63\u5e38\u72b6\u6001\u5e76\u91cd\u65b0\u52a0\u5165 endpoint \u5217\u8868","title":"\u4e3b\u9898\u8ba8\u8bba:\u5065\u5eb7\u68c0\u67e5"},{"location":"k8s/cka_cn/foundamentals/casestudy-health-check/#deployment-service","text":"\u521b\u5efaDeployment nginx-healthcheck \u548cService nginx-healthcheck \u3002 kubectl apply -f - < nginx-healthcheck-79fc55d944-nwwjc 1/1 Running 0 9s 10.244.112.13 cka002 \u901a\u8fc7\u547d\u4ee4 curl \u6765\u8bbf\u95ee\u4e0a\u9762\u8fd0\u884c\u7ed3\u679c\u4e2dpod\u7684IP\u5730\u5740\u3002 curl 10 .244.102.14 curl 10 .244.112.13 \u5982\u679c\u4e0a\u9762\u547d\u4ee4\u6210\u529f\u6267\u884c\uff0c\u5219\u4f1a\u8fd4\u56deNginx\u4e2d index.html \u7684\u5185\u5bb9\u3002 \u83b7\u53d6\u524d\u9762\u521b\u5efa\u7684Service\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl describe svc nginx-healthcheck \u8f93\u51fa\u7ed3\u679c\u5982\u4e0b\u3002\u5728 Endpoints \u90e8\u5206\u6211\u4eec\u53ef\u4ee5\u770b\u52302\u4e2apod\u3002 Name : nginx-healthcheck Namespace : dev Labels : Annotations : Selector : name=nginx-healthcheck Type : NodePort IP Family Policy : SingleStack IP Families : IPv4 IP : 11.244.238.20 IPs : 11.244.238.20 Port : 80/TCP TargetPort : 80/TCP NodePort : 31795/TCP Endpoints : 10.244.102.14:80,10.244.112.13:80 Session Affinity : None External Traffic Policy : Cluster Events : \u83b7\u53d6Endpoints\u7684\u4fe1\u606f\u3002 kubectl get endpoints nginx-healthcheck \u8fd0\u884c\u7ed3\u679c NAME ENDPOINTS AGE nginx-healthcheck 10.244.102.14:80,10.244.112.13:80 72s \u81f3\u6b64\uff0c2\u4e2apod nginx-healthcheck \u90fd\u80fd\u6309\u7167\u6211\u4eec\u7684\u671f\u671b\u6b63\u5e38\u5de5\u4f5c\u3002","title":"\u521b\u5efa Deployment \u548c Service"},{"location":"k8s/cka_cn/foundamentals/casestudy-health-check/#readinessprobe","text":"\u8ba9\u6211\u4eec\u901a\u8fc7\u5220\u9664 nginx-healthcheck Pod \u4e2d\u7684 index.html \u6587\u4ef6\u6765\u6a21\u62df\u9519\u8bef\uff0c\u89c2\u5bdf readinessProbe \u7684\u8868\u73b0\u3002 \u9996\u5148\uff0c\u6267\u884c kubectl exec -it -- bash \u547d\u4ee4\u4ee5\u767b\u5f55\u5230 nginx-healthcheck Pod\uff0c\u5e76\u5220\u9664 index.html \u6587\u4ef6\u3002 kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ rm -rf index.html exit \u5728\u6267\u884c\u4e86\u5220\u9664 nginx-healthcheck Pod \u4e2d\u7684 index.html \u6587\u4ef6\u4e4b\u540e\uff0c\u6211\u4eec\u68c0\u67e5\u8be5 Pod \u7684\u72b6\u6001\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-jw887 \u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230 Readiness probe failed \u8fd9\u4e2a\u9519\u8bef\u4e8b\u4ef6\u4fe1\u606f\u3002 ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m8s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-jw887 to cka003 Normal Pulled 2m7s kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m7s kubelet Created container nginx-healthcheck Normal Started 2m7s kubelet Started container nginx-healthcheck Warning Unhealthy 2s (x2 over 7s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 403 \u68c0\u67e5\u53e6\u4e00\u4e2apod\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-nwwjc \u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6ca1\u6709\u53d1\u73b0\u9519\u8bef\u3002 ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 3m46s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-nwwjc to cka002 Normal Pulled 3m45s kubelet Container image \"nginx:latest\" already present on machine Normal Created 3m45s kubelet Created container nginx-healthcheck Normal Started 3m45s kubelet Started container nginx-healthcheck \u73b0\u5728\uff0c\u901a\u8fc7 curl \u547d\u4ee4\u6765\u8bbf\u95ee2\u4e2apod\u7684IP\u5730\u5740\uff0c\u6211\u4eec\u6765\u89c2\u5bdf\u4f1a\u5f97\u5230\u600e\u6837\u7684\u7ed3\u679c\u3002 curl 10 .244.102.14 curl 10 .244.112.13 \u8fd0\u884c\u7ed3\u679c\uff1a curl 10.244.102.14 \u5931\u8d25\uff0c\u9519\u8bef\u4fe1\u606f\u662f 403 Forbidden \u3002 curl 10.244.112.13 \u6210\u529f\u3002 \u6211\u4eec\u73b0\u5728\u6765\u67e5\u8be2Nginx service\u5728\u4e00\u4e2apod\u5931\u8d25\u65f6\u7684\u72b6\u6001\u3002 kubectl describe svc nginx-healthcheck \u5728\u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6211\u4eec\u770b\u5230Endpoint\u90e8\u5206\u4e2d\u53ea\u6709\u4e00\u4e2apod\u7684\u4fe1\u606f\u3002 Name : nginx-healthcheck Namespace : dev Labels : Annotations : Selector : name=nginx-healthcheck Type : NodePort IP Family Policy : SingleStack IP Families : IPv4 IP : 11.244.238.20 IPs : 11.244.238.20 Port : 80/TCP TargetPort : 80/TCP NodePort : 31795/TCP Endpoints : 10.244.112.13:80 Session Affinity : None External Traffic Policy : Cluster Events : \u540c\u6837\u7684\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u68c0\u67e5Endpoint\u7684\u4fe1\u606f\uff0c\u4e5f\u80fd\u53d1\u73b0\u53ea\u6709\u4e00\u4e2apod\u6b63\u5728\u8fd0\u884c\u3002 kubectl get endpoints nginx-healthcheck \u8fd0\u884c\u7ed3\u679c\uff1a NAME ENDPOINTS AGE nginx-healthcheck 10.244.112.13:80 6m5s","title":"\u6a21\u62dfreadinessProbe\u9519\u8bef"},{"location":"k8s/cka_cn/foundamentals/casestudy-health-check/#readinessprobe_1","text":"\u73b0\u5728\uff0c\u6211\u4eec\u5728pod\u4e2d\u91cd\u65b0\u521b\u5efa index.html \u6587\u4ef6\uff0c\u6765\u4fee\u590d\u9519\u8bef\u3002 kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ cat > index.html << EOF Welcome to nginx!

    Welcome to nginx!

    If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

    For online documentation and support please refer to nginx.org.
    Commercial support is available at nginx.com.

    Thank you for using nginx.

    EOF exit \u73b0\u5728\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u4e24\u4e2aPod\u5df2\u7ecf\u91cd\u65b0\u52a0\u5165\u4e86Endpoint\u5217\u8868\uff0c\u53ef\u4ee5\u63d0\u4f9b\u670d\u52a1\u4e86\u3002 kubectl describe svc nginx-healthcheck kubectl get endpoints nginx-healthcheck \u91cd\u65b0\u901a\u8fc7 curl \u547d\u4ee4\u8bbf\u95ee2\u4e2apod\u7684IP\u5730\u5740\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5b83\u4eec\u90fd\u5df2\u7ecf\u6062\u590d\u5230\u6b63\u5e38\u72b6\u6001\u4e86\u3002 curl 10 .244.102.14 curl 10 .244.112.13 \u518d\u6b21\u9a8c\u8bc1pod\u7684\u72b6\u6001\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-jw887 \u7ed3\u8bba\uff1a \u901a\u8fc7\u5220\u9664 index.html \u6587\u4ef6\uff0cPod \u8fdb\u5165\u4e0d\u5065\u5eb7\u72b6\u6001\u5e76\u4ece\u7aef\u70b9\u5217\u8868\u4e2d\u5220\u9664\u3002 \u53ea\u6709\u4e00\u4e2a\u5065\u5eb7\u7684 Pod \u53ef\u4ee5\u63d0\u4f9b\u6b63\u5e38\u7684\u670d\u52a1\u3002 \u6e05\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete service nginx-healthcheck kubectl delete deployment nginx-healthcheck","title":"\u4fee\u590dreadinessProbe\u9519\u8bef"},{"location":"k8s/cka_cn/foundamentals/casestudy-health-check/#livenessprobe","text":"\u91cd\u65b0\u521b\u5efadeployment nginx-healthcheck \u548cservice nginx-healthcheck \u3002 Deployment: NAME READY UP-TO-DATE AVAILABLE AGE nginx-healthcheck 0/2 2 0 7s Pods: NAME READY STATUS RESTARTS AGE nginx-healthcheck-79fc55d944-lknp9 1/1 Running 0 96s nginx-healthcheck-79fc55d944-wntmg 1/1 Running 0 96s \u5c06 Nginx \u9ed8\u8ba4\u76d1\u542c\u7aef\u53e3\u4ece 80 \u6539\u4e3a 90 \uff0c\u4ee5\u6a21\u62df livenessProbe \u5931\u8d25\u3002livenessProbe \u901a\u8fc7\u7aef\u53e3 80 \u68c0\u67e5\u751f\u5b58\u72b6\u6001\u3002 kubectl exec -it nginx-healthcheck-79fc55d944-lknp9 -- bash root@nginx-healthcheck-79fc55d944-lknp9:/# cd /etc/nginx/conf.d root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# sed -i 's/80/90/g' default.conf root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# nginx -s reload 2022 /07/24 12 :59:45 [ notice ] 79 #79: signal process started Pod\u73b0\u5728\u8868\u73b0\u4e3a\u5931\u8d25\u72b6\u6001\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-lknp9 \u5728pod\u7684\u4e8b\u4ef6\u4fe1\u606f\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u53d1\u73b0 livenessProbe \u9519\u8bef\u4fe1\u606f\u3002 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 17m default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-lknp9 to cka003 Normal Pulled 2m47s (x2 over 17m) kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m47s (x2 over 17m) kubelet Created container nginx-healthcheck Normal Started 2m47s (x2 over 17m) kubelet Started container nginx-healthcheck Warning Unhealthy 2m47s (x4 over 2m57s) kubelet Readiness probe failed: Get \"http://10.244.102.46:80/\": dial tcp 10.244.102.46:80: connect: connection refused Warning Unhealthy 2m47s (x3 over 2m57s) kubelet Liveness probe failed: dial tcp 10.244.102.46:80: connect: connection refused Normal Killing 2m47s kubelet Container nginx-healthcheck failed liveness probe, will be restarted \u5f53 livenessProbe \u68c0\u6d4b\u5230\u5931\u8d25\u540e\uff0c\u5bb9\u5668\u5c06\u81ea\u52a8\u91cd\u65b0\u542f\u52a8\u3002\u6211\u4eec\u4fee\u6539\u7684 default.conf \u6587\u4ef6\u5c06\u88ab\u9ed8\u8ba4\u6587\u4ef6\u66ff\u6362\uff0c\u5bb9\u5668\u72b6\u6001\u5c06\u6062\u590d\u6b63\u5e38\u3002","title":"\u6a21\u62dflivenessProbe\u9519\u8bef"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/","text":"\u4e3b\u9898\u8ba8\u8bba:Kubernetes\u8d44\u6e90\u5e38\u89c1\u64cd\u4f5c \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u8282\u70b9\u6807\u7b7e\uff08Node Label\uff09 \u6ce8\u89e3\uff08Annotation\uff09 \u547d\u540d\u7a7a\u95f4\uff08Namespace\uff09 ServiceAccount \u6388\u6743\uff08ServiceAccount Authorization\uff09 \u6388\u6743\u9ed8\u8ba4 ServiceAccount \u8bbf\u95ee API \u90e8\u7f72\uff08Deployment\uff09 \u66b4\u9732\u670d\u52a1\uff08Expose Service\uff09 \u6269\u5c55\u90e8\u7f72\uff08Scale out the Deployment\uff09 \u6eda\u52a8\u5347\u7ea7\uff08Rolling update\uff09 \u56de\u6eda\u5347\u7ea7\uff08Rolling back update\uff09 \u4e8b\u4ef6\uff08Event\uff09 \u65e5\u5fd7\u8bb0\u5f55\uff08Logging\uff09 \u8282\u70b9\u6807\u7b7e\uff08Node Label\uff09 \u00b6 \u6dfb\u52a0/\u4fee\u6539/\u79fb\u51fa\u8282\u70b9\u6807\u7b7e\u3002 # Update node label kubectl label node cka002 node = demonode # Get node info with label info kubectl get node --show-labels # Search node by label kubectl get node -l node = demonode # Remove a lable of node kubectl label node cka002 node- \u6ce8\u89e3\uff08Annotation\uff09 \u00b6 \u521b\u5efadeployment Nginx \u3002 kubectl create deploy nginx --image = nginx:mainline \u83b7\u53d6\u6ce8\u89e3\u4fe1\u606f kubectl describe deployment/nginx \u8fd0\u884c\u7ed3\u679c\uff1a ...... Labels : app=nginx Annotations : deployment.kubernetes.io/revision : 1 Selector : app=nginx ...... \u6dfb\u52a0\u65b0\u7684\u6ce8\u89e3\u4fe1\u606f\u3002 kubectl annotate deployment nginx owner = James.H \u518d\u6b21\u67e5\u8be2\u6ce8\u89e3\u4fe1\u606f\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 ...... Labels : app=nginx Annotations : deployment.kubernetes.io/revision : 1 owner : James.H Selector : app=nginx ...... \u66f4\u65b0/\u8986\u76d6\u6ce8\u89e3\u4fe1\u606f\u3002 kubectl annotate deployment/nginx owner = K8s --overwrite \u518d\u6b21\u67e5\u8be2\u6ce8\u89e3\u4fe1\u606f\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 ...... Annotations : deployment.kubernetes.io/revision : 1 owner : K8s Selector : app=nginx ...... \u79fb\u9664\u6ce8\u89e3\u4fe1\u606f\u3002 kubectl annotate deployment/nginx owner- \u8fd0\u884c\u7ed3\u679c\uff1a ...... Labels : app=nginx Annotations : deployment.kubernetes.io/revision : 1 Selector : app=nginx ...... \u5220\u9664\u4e0a\u9762\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete deployment nginx \u547d\u540d\u7a7a\u95f4\uff08Namespace\uff09 \u00b6 \u67e5\u8be2\u5f53\u524d\u53ef\u7528namespace\u3002 kubectl get namespace \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS AGE default Active 3h45m dev Active 3h11m kube-node-lease Active 3h45m kube-public Active 3h45m kube-system Active 3h45m \u67e5\u8be2\u67d0\u4e2anamespace\u4e0a\u8fd0\u884c\u7684pod\u4fe1\u606f\u3002 kubectl get pod -n kube-system \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE calico-kube-controllers-5c64b68895-jr4nl 1/1 Running 0 3h25m calico-node-dsx76 1/1 Running 0 3h25m calico-node-p5rf2 1/1 Running 0 3h25m calico-node-tr22l 1/1 Running 0 3h25m coredns-6d8c4cb4d-g4jxc 1/1 Running 0 3h45m coredns-6d8c4cb4d-sqcvj 1/1 Running 0 3h45m etcd-cka001 1/1 Running 0 3h45m kube-apiserver-cka001 1/1 Running 0 3h45m kube-controller-manager-cka001 1/1 Running 0 3h45m kube-proxy-5cdbj 1/1 Running 0 3h41m kube-proxy-cm4hc 1/1 Running 0 3h45m kube-proxy-g4w52 1/1 Running 0 3h41m kube-scheduler-cka001 1/1 Running 0 3h45m \u67e5\u8be2\u6240\u6709namespace\u4e0a\u7684pod\u4fe1\u606f\u3002 kubectl get pod --all-namespaces kubectl get pod -A ServiceAccount \u6388\u6743\uff08ServiceAccount Authorization\uff09 \u00b6 \u5728 Kubernetes 1.23 \u53ca\u66f4\u4f4e\u7248\u672c\u4e2d\uff0c\u5f53\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u65f6\uff0cKubernetes \u4f1a\u81ea\u52a8\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a default \u7684 ServiceAccount \u548c\u4e00\u4e2a\u540d\u4e3a default-token-xxxxx \u7684\u4ee4\u724c\u3002 \u800c\u5728 Kubernetes 1.24 \u4e2d\uff0c\u521b\u5efa\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u65f6\u4ec5\u4f1a\u81ea\u52a8\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a default \u7684 ServiceAccount\uff0c\u9700\u8981\u624b\u52a8\u521b\u5efa\u4e0e default ServiceAccount \u76f8\u5173\u8054\u7684\u4ee4\u724c\u3002 \u4ee5\u4e0b\u662f\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a dev \u7684\u65b0\u547d\u540d\u7a7a\u95f4\u7684\u793a\u4f8b\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5728\u547d\u540d\u7a7a\u95f4 dev \u4e2d\u4ec5\u521b\u5efa\u4e86 ServiceAccount\uff1a default \uff0c\u6ca1\u6709\u4e0e ServiceAccount default \u76f8\u5173\u8054\u7684\u4ee4\u724c\uff08secret\uff09\u3002 kubectl create namespace dev kubectl get serviceaccount -n dev kubectl get secrets -n dev \u6709\u4e00\u4e2a\u9ed8\u8ba4\u7684\u96c6\u7fa4\u89d2\u8272 admin \uff0c\u4f46\u662f\u6ca1\u6709\u5c06\u5176\u7ed1\u5b9a\u5230\u4efb\u4f55\u96c6\u7fa4\u89d2\u8272\u7ed1\u5b9a\uff08clusterrole binding\uff09\u4e2d\u3002 kubectl get clusterrole admin kubectl get clusterrolebinding | grep ClusterRole/admin \u89d2\u8272Role\u548c\u89d2\u8272\u7ed1\u5b9aRoleBinding\u662f\u57fa\u4e8e\u547d\u540d\u7a7a\u95f4\u7684\u3002\u5728\u547d\u540d\u7a7a\u95f4 dev \u4e2d\uff0c\u6ca1\u6709\u89d2\u8272\u548c\u89d2\u8272\u7ed1\u5b9a\u3002 kubectl get role -n dev kubectl get rolebinding -n dev \u5728 Kubernetes \u96c6\u7fa4\u4e2d\uff0cSecret \u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u7528\u4e8e\u5b58\u50a8\u654f\u611f\u4fe1\u606f\uff0c\u5982\u7528\u6237\u540d\u3001\u5bc6\u7801\u548c\u4ee4\u724c\u7b49\u3002Secret \u7684\u76ee\u6807\u662f\u5bf9\u51ed\u636e\u8fdb\u884c\u7f16\u7801\u6216\u54c8\u5e0c\u5316\u3002\u8fd9\u4e9b\u51ed\u636e\u53ef\u4ee5\u5728\u5404\u79cd Pod \u5b9a\u4e49\u6587\u4ef6\u4e2d\u91cd\u590d\u4f7f\u7528\u3002 kubernetes.io/service-account-token \u7c7b\u578b\u7684 Secret \u7528\u4e8e\u5b58\u50a8\u6807\u8bc6\u670d\u52a1\u8d26\u6237\u7684\u4ee4\u724c\u3002\u4f7f\u7528\u6b64\u7c7b\u578b\u7684 Secret \u65f6\uff0c\u9700\u8981\u786e\u4fdd kubernetes.io/service-account.name \u6ce8\u91ca\u8bbe\u7f6e\u4e3a\u73b0\u6709\u670d\u52a1\u8d26\u6237\u540d\u79f0\u3002 \u8ba9\u6211\u4eec\u5728 dev \u547d\u540d\u7a7a\u95f4\u4e2d\u4e3a ServiceAccount default \u521b\u5efa\u4e00\u4e2a\u4ee4\u724c\u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Secret metadata: name: default-token-dev namespace: dev annotations: kubernetes.io/service-account.name: \"default\" type: kubernetes.io/service-account-token EOF \u73b0\u5728\u5728 dev \u547d\u540d\u7a7a\u95f4\u4e2d\u521b\u5efa\u4e86 ServiceAccount default \u548c Secret\uff08\u4ee4\u724c\uff09 default-token-dev \u3002 kubectl get serviceaccount -n dev kubectl get secrets -n dev \u83b7\u53d6\u9ed8\u8ba4 Service Account \u7684 token\uff0c\u5e76\u8d4b\u503c\u7ed9\u73af\u5883\u53d8\u91cf $TOKEN \u3002 TOKEN = $( kubectl -n dev describe secret $( kubectl -n dev get secrets | grep default | cut -f1 -d ' ' ) | grep -E '^token' | cut -f2 -d ':' | tr -d ' ' ) echo $TOKEN \u83b7\u53d6 API Service \u5730\u5740\uff0c\u5e76\u8d4b\u503c\u7ed9\u73af\u5883\u53d8\u91cf $APISERVER \u3002 APISERVER = $( kubectl config view | grep https | cut -f 2 - -d \":\" | tr -d \" \" ) echo $APISERVER \u901a\u8fc7 API Server \u4ee5 JSON \u683c\u5f0f\u83b7\u53d6\u547d\u540d\u7a7a\u95f4 dev \u4e2d\u7684 Pod \u8d44\u6e90\u3002 curl $APISERVER /api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN \" --insecure \u6211\u4eec\u5c06\u6536\u5230\u201c403 forbidden\u201d\u7684\u9519\u8bef\u6d88\u606f\u3002ServiceAccount default \u6ca1\u6709\u8bbf\u95ee\u540d\u79f0\u7a7a\u95f4 dev \u4e2d\u7684Pod\u7684\u6388\u6743\u3002 \u8ba9\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a rolebinding-admin \u7684RoleBinding\uff0c\u5c06\u96c6\u7fa4\u89d2\u8272 admin \u7ed1\u5b9a\u5230\u540d\u79f0\u7a7a\u95f4 dev \u4e2d\u7684ServiceAccount default \u3002 \u56e0\u6b64\uff0cServiceAccount default \u88ab\u6388\u4e88\u5728\u540d\u79f0\u7a7a\u95f4 dev \u4e2d\u7684\u7ba1\u7406\u5458\u6388\u6743\u3002 # Usage: kubectl create rolebinding --clusterrole = --serviceaccount = : --namespace = # Crate rolebinding: kubectl create rolebinding rolebinding-admin --clusterrole = admin --serviceaccount = dev:default --namespace = dev \u6267\u884c\u547d\u4ee4 kubectl get rolebinding -n dev \uff0c\u5f97\u5230\u7c7b\u4f3c\u5982\u4e0b\u7684\u7ed3\u679c\u3002 NAME ROLE AGE rolebinding-admin ClusterRole/admin 10s \u518d\u6b21\u901a\u8fc7 API Server \u4ee5 JSON \u683c\u5f0f\u83b7\u53d6\u547d\u540d\u7a7a\u95f4 dev \u4e2d\u7684 Pod \u8d44\u6e90\uff0c\u6210\u529f\u3002 curl $APISERVER /api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN \" --insecure \u5220\u9664\u4e0a\u9762\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete namespace dev \u90e8\u7f72\uff08Deployment\uff09 \u00b6 \u521b\u5efa\u4e00\u4e2a Ubuntu Pod \u4ee5\u8fdb\u884c\u64cd\u4f5c\uff0c\u5e76\u9644\u52a0\u5230\u8fd0\u884c\u4e2d\u7684 Pod\u3002 kubectl create -f - << EOF apiVersion: v1 kind: Pod metadata: name: ubuntu labels: app: ubuntu spec: containers: - name: ubuntu image: ubuntu:latest command: [\"/bin/sleep\", \"3650d\"] imagePullPolicy: IfNotPresent restartPolicy: Always EOF kubectl exec --stdin --tty ubuntu -- /bin/bash \u521b\u5efa\u4e00\u4e2a Deployment\uff0c\u9009\u9879 --image \u6307\u5b9a\u4e86\u4e00\u4e2a\u955c\u50cf\uff0c\u9009\u9879 --port \u6307\u5b9a\u4e86\u5916\u90e8\u8bbf\u95ee\u7684\u7aef\u53e3\u3002 \u5728\u521b\u5efa Deployment \u7684\u540c\u65f6\u4e5f\u4f1a\u521b\u5efa\u4e00\u4e2a Pod\u3002 kubectl create deployment myapp --image = docker.io/jocatalin/kubernetes-bootcamp:v1 --replicas = 1 --port = 8080 \u67e5\u8be2deployment\u7684\u72b6\u6001\u3002 kubectl get deployment myapp -o wide \u8f93\u51fa\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR myapp 1/1 1 1 79s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp \u67e5\u8be2deployment\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl describe deployment myapp \u8fd0\u884c\u7ed3\u679c\uff1a Name: myapp Namespace: dev CreationTimestamp: Sat, 23 Jul 2022 14:36:43 +0800 Labels: app=myapp Annotations: deployment.kubernetes.io/revision: 1 Selector: app=myapp Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=myapp Containers: kubernetes-bootcamp: Image: docker.io/jocatalin/kubernetes-bootcamp:v1 Port: 8080/TCP Host Port: 0/TCP Environment: Mounts: Volumes: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: NewReplicaSet: myapp-b5d775f5d (1/1 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 95s deployment-controller Scaled up replica set myapp-b5d775f5d to 1 \u66b4\u9732\u670d\u52a1\uff08Expose Service\uff09 \u00b6 \u83b7\u53d6\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u548cdeployment\u7684\u4fe1\u606f\u3002 kubectl get deployment myapp -o wide kubectl get pod -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-b5d775f5d-cx8dx 1/1 Running 0 2m34s 10.244.102.7 cka003 \u6267\u884c\u547d\u4ee4 curl 10.244.102.7:8080 \uff0c\u4ee5\u53d1\u9001HTTP\u8bf7\u6c42\u5230pod\u7684\u7aef\u53e3\uff0c\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 \u8981\u4f7f Pod \u53ef\u4ee5\u4ece\u5916\u90e8\u8bbf\u95ee\uff0c\u9700\u8981\u5c06\u7aef\u53e3 8080 \u66b4\u9732\u7ed9\u8282\u70b9\u7aef\u53e3\uff08NodePort\uff09\u3002\u8fd9\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u76f8\u5173\u7684 Service\u3002 kubectl expose deployment myapp --type = NodePort --port = 8080 \u6267\u884c\u547d\u4ee4 kubectl get svc myapp -o wide \uff0c\u83b7\u53d6service myapp \u7684\u8be6\u7ec6\u4fe1\u606f\u3002 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR myapp NodePort 11.244.74.3 8080:30514/TCP 7s app=myapp \u6267\u884c\u547d\u4ee4 curl 11.244.74.3:8080 \uff0c\u4ee5\u53d1\u9001HTTP\u8bf7\u6c42\u5230service\u7684\u7aef\u53e3\uff0c\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-cx8dx | v=1 \u83b7\u53d6service\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get svc myapp -o yaml kubectl describe svc myapp \u6267\u884c kubectl get endpoints myapp -o wide \u547d\u4ee4\u4ee5\u83b7\u53d6\u76f8\u5173\u7684 myapp \u7aef\u70b9\uff08endpoint\uff09\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 NAME ENDPOINTS AGE myapp 10.244.102.7:8080 43s \u63d0\u793a\uff1a Endpoint\uff08\u7aef\u70b9\uff09\u662f\u4e00\u4e2aKubernetes\u4e2d\u7684\u5bf9\u8c61\uff0c\u7528\u4e8e\u5b58\u50a8\u53ef\u4ee5\u88ab\u670d\u52a1\u8bbf\u95ee\u7684Pod\u7684\u7f51\u7edc\u5730\u5740\u548c\u7aef\u53e3\u4fe1\u606f\u3002 \u5f53Service\u521b\u5efa\u65f6\uff0cKubernetes\u4f1a\u81ea\u52a8\u521b\u5efa\u548c\u66f4\u65b0\u76f8\u5e94\u7684Endpoint\u3002 Endpoint\u662f\u7531kube-proxy\u81ea\u52a8\u521b\u5efa\u548c\u7ef4\u62a4\u7684\uff0c\u5e76\u6839\u636e\u9009\u62e9\u5668\u5339\u914d\u5bf9\u5e94\u7684Service\u548cPod\u3002 \u80fd\u6210\u529f\u7684\u53d1\u9001HTTP\u8bf7\u6c42\u5230service\u548c\u8282\u70b9\uff0c\u8bf4\u660epod\u7684\u7aef\u53e3 8080 \u88ab\u6b63\u786e\u7684\u6620\u5c04\u5230\u8282\u70b9\u7684\u7aef\u53e3 32566 \u3002 \u6267\u884c\u547d\u4ee4curl :30514\uff0c\u53d1\u9001HTTP\u8bf7\u6c42\u5230\u8282\u70b9 cka003 \u4e0a\u5bf9\u5e94\u7684\u7aef\u53e3\u3002 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 \u767b\u5f55\u8fdb\u5165Ubuntu pod\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u53d1\u9001HTTP\u8bf7\u6c42\u5230 myapp \u6240\u6620\u5c04\u7684service\u3001pod\u548c\u8282\u70b9\u7684\u7aef\u53e3\u3002 kubectl exec --stdin --tty ubuntu -- /bin/bash curl 10 .244.102.7:8080 curl 11 .244.74.3:8080 curl :30514 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v = 1 \u6269\u5bb9\u90e8\u7f72\uff08Scale out the Deployment\uff09 \u00b6 Scale out by replicaset. We set three replicasets to scale out deployment myapp . The number of deployment myapp is now three. \u901a\u8fc7\u526f\u672c\u96c6replicaset\u8fdb\u884c\u6269\u5c55\u3002\u6211\u4eec\u901a\u8fc7\u6307\u5b9a\u526f\u672c\u96c6\u7684\u65b9\u5f0f\uff0c\u5bf9deployment myapp \u8fdb\u884c\u6269\u5c55\u90e8\u7f72\uff0c\u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0cdeployment myapp \u7684\u526f\u672c\u6570\u662f\u4e09\u4e2a\u3002 kubectl scale deployment myapp --replicas = 3 \u67e5\u8be2deployment\u7684\u4fe1\u606f\u3002 kubectl get deployment myapp \u67e5\u8be2replicaset\u7684\u4fe1\u606f kubectl get replicaset \u6eda\u52a8\u5347\u7ea7\uff08Rolling update\uff09 \u00b6 \u547d\u4ee4\u7528\u6cd5\uff1a kubectl set image (-f \u6587\u4ef6\u540d | \u7c7b\u578b \u540d\u79f0) \u5bb9\u5668\u540d\u79f0_1=\u5bb9\u5668\u955c\u50cf_1 ... \u5bb9\u5668\u540d\u79f0_N=\u5bb9\u5668\u955c\u50cf_N \u3002 \u4f7f\u7528\u547d\u4ee4 kubectl get deployment \uff0c\u6211\u4eec\u53ef\u4ee5\u83b7\u53d6deployment myapp \u548c\u76f8\u5173\u5bb9\u5668 kubernetes-bootcamp \u3002 kubectl get deployment myapp -o wide \u4f7f\u7528\u547d\u4ee4 kubectl set image \u6765\u66f4\u65b0\u591a\u4e2a\u7248\u672c\u7684\u955c\u50cf\uff0c\u5e76\u4f7f\u7528\u9009\u9879 --record \u5c06\u66f4\u6539\u8bb0\u5f55\u5728\u90e8\u7f72\u7684\u6ce8\u91ca\u4e2d\u3002 kubectl set image deployment/myapp kubernetes-bootcamp = docker.io/jocatalin/kubernetes-bootcamp:v2 --record \u67e5\u8be2\u5f53\u524dreplicas\u7684\u72b6\u6001\u3002 kubectl get replicaset -o wide -l app = myapp \u8f93\u51fa\u7ed3\u679c\u5982\u4e0b\uff0cpod\u6b63\u4ee5\u65b0\u7684\u526f\u672c\u96c6replicas\u6570\u91cf\u8fd0\u884c\u3002 NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR myapp-5dbd68cc99 1 1 0 8s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v2 app=myapp,pod-template-hash=5dbd68cc99 myapp-b5d775f5d 3 3 3 14m kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp,pod-template-hash=b5d775f5d \u6211\u4eec\u53ef\u4ee5\u5728\u5bf9\u5e94\u7684yaml\u6587\u4ef6\u4e2d metadata.annotations \u90e8\u5206\u83b7\u53d6\u53d8\u66f4\u5386\u53f2\u8bb0\u5f55\u3002 kubectl get deployment myapp -o yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion : apps/v1 kind : Deployment metadata : annotations : deployment.kubernetes.io/revision : \"2\" kubernetes.io/change-cause : kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true ...... \u6211\u4eec\u4e5f\u53ef\u4ee5\u4f7f\u7528\u547d\u4ee4 kubectl rollout history \u83b7\u53d6\u66f4\u65b0\u5386\u53f2\u8bb0\u5f55\uff0c\u5e76\u4f7f\u7528\u7279\u5b9a\u4fee\u8ba2\u7248\u672c\u53f7 --revision= \u663e\u793a\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl rollout history deployment/myapp \u8fd0\u884c\u7ed3\u679c\uff1a deployment.apps/myapp REVISION CHANGE-CAUSE 1 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true \u83b7\u53d6\u7279\u5b9a\u7248\u672c\u56de\u6eda\u5386\u53f2\u8bb0\u5f55\u3002 kubectl rollout history deployment/myapp --revision = 2 \u6267\u884c\u547d\u4ee4 kubectl rollout undo \u53ef\u4ee5\u56de\u6eda\u5230\u4e0a\u4e00\u4e2a\u7248\u672c\uff0c\u6216\u4f7f\u7528\u9009\u9879 --to-revision= \u56de\u6eda\u5230\u6307\u5b9a\u7684\u7248\u672c\u3002 kubectl rollout undo deployment/myapp --to-revision = 1 \u7248\u672c 1 \u73b0\u5728\u5df2\u7ecf\u88ab\u66ff\u6362\u6210\u7248\u672c 3 \u4e86\u3002 kubectl rollout history deployment/myapp \u8fd0\u884c\u7ed3\u679c\uff1a deployment.apps/myapp REVISION CHANGE-CAUSE 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true 3 \u4e8b\u4ef6\uff08Event\uff09 \u00b6 \u83b7\u53d6\u6307\u5b9apod\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl describe pod myapp-b5d775f5d-jlx6g \u8f93\u51fa\u7ed3\u679c\uff1a ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 54s default-scheduler Successfully assigned dev/myapp-b5d775f5d-jlx6g to cka003 Normal Pulled 53s kubelet Container image \"docker.io/jocatalin/kubernetes-bootcamp:v1\" already present on machine Normal Created 53s kubelet Created container kubernetes-bootcamp Normal Started 53s kubelet Started container kubernetes-bootcamp \u67e5\u8be2\u96c6\u7fa4\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl get event \u65e5\u5fd7\u8bb0\u5f55\uff08Logging\uff09 \u00b6 \u67e5\u8be2pod\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl logs -f kubectl logs -f -c \u4f8b\u5982\uff1a kubectl logs -f myapp-b5d775f5d-jlx6g \u8fd0\u884c\u7ed3\u679c\uff1a Kubernetes Bootcamp App Started At: 2022-07-23T06:54:18.532Z | Running On: myapp-b5d775f5d-jlx6g \u67e5\u8be2K8s\u4e0d\u540c\u7ec4\u4ef6\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl logs kube-apiserver-cka001 -n kube-system kubectl logs kube-controller-manager-cka001 -n kube-system kubectl logs kube-scheduler-cka001 -n kube-system kubectl logs etcd-cka001 -n kube-system systemctl status kubelet journalctl -fu kubelet kubectl logs kube-proxy-5cdbj -n kube-system \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete service myapp kubectl delete deployment myapp","title":"Kubernetes\u8d44\u6e90\u5e38\u89c1\u64cd\u4f5c"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#kubernetes","text":"\u6f14\u793a\u573a\u666f\uff1a \u8282\u70b9\u6807\u7b7e\uff08Node Label\uff09 \u6ce8\u89e3\uff08Annotation\uff09 \u547d\u540d\u7a7a\u95f4\uff08Namespace\uff09 ServiceAccount \u6388\u6743\uff08ServiceAccount Authorization\uff09 \u6388\u6743\u9ed8\u8ba4 ServiceAccount \u8bbf\u95ee API \u90e8\u7f72\uff08Deployment\uff09 \u66b4\u9732\u670d\u52a1\uff08Expose Service\uff09 \u6269\u5c55\u90e8\u7f72\uff08Scale out the Deployment\uff09 \u6eda\u52a8\u5347\u7ea7\uff08Rolling update\uff09 \u56de\u6eda\u5347\u7ea7\uff08Rolling back update\uff09 \u4e8b\u4ef6\uff08Event\uff09 \u65e5\u5fd7\u8bb0\u5f55\uff08Logging\uff09","title":"\u4e3b\u9898\u8ba8\u8bba:Kubernetes\u8d44\u6e90\u5e38\u89c1\u64cd\u4f5c"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#node-label","text":"\u6dfb\u52a0/\u4fee\u6539/\u79fb\u51fa\u8282\u70b9\u6807\u7b7e\u3002 # Update node label kubectl label node cka002 node = demonode # Get node info with label info kubectl get node --show-labels # Search node by label kubectl get node -l node = demonode # Remove a lable of node kubectl label node cka002 node-","title":"\u8282\u70b9\u6807\u7b7e\uff08Node Label\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#annotation","text":"\u521b\u5efadeployment Nginx \u3002 kubectl create deploy nginx --image = nginx:mainline \u83b7\u53d6\u6ce8\u89e3\u4fe1\u606f kubectl describe deployment/nginx \u8fd0\u884c\u7ed3\u679c\uff1a ...... Labels : app=nginx Annotations : deployment.kubernetes.io/revision : 1 Selector : app=nginx ...... \u6dfb\u52a0\u65b0\u7684\u6ce8\u89e3\u4fe1\u606f\u3002 kubectl annotate deployment nginx owner = James.H \u518d\u6b21\u67e5\u8be2\u6ce8\u89e3\u4fe1\u606f\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 ...... Labels : app=nginx Annotations : deployment.kubernetes.io/revision : 1 owner : James.H Selector : app=nginx ...... \u66f4\u65b0/\u8986\u76d6\u6ce8\u89e3\u4fe1\u606f\u3002 kubectl annotate deployment/nginx owner = K8s --overwrite \u518d\u6b21\u67e5\u8be2\u6ce8\u89e3\u4fe1\u606f\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 ...... Annotations : deployment.kubernetes.io/revision : 1 owner : K8s Selector : app=nginx ...... \u79fb\u9664\u6ce8\u89e3\u4fe1\u606f\u3002 kubectl annotate deployment/nginx owner- \u8fd0\u884c\u7ed3\u679c\uff1a ...... Labels : app=nginx Annotations : deployment.kubernetes.io/revision : 1 Selector : app=nginx ...... \u5220\u9664\u4e0a\u9762\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete deployment nginx","title":"\u6ce8\u89e3\uff08Annotation\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#namespace","text":"\u67e5\u8be2\u5f53\u524d\u53ef\u7528namespace\u3002 kubectl get namespace \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS AGE default Active 3h45m dev Active 3h11m kube-node-lease Active 3h45m kube-public Active 3h45m kube-system Active 3h45m \u67e5\u8be2\u67d0\u4e2anamespace\u4e0a\u8fd0\u884c\u7684pod\u4fe1\u606f\u3002 kubectl get pod -n kube-system \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE calico-kube-controllers-5c64b68895-jr4nl 1/1 Running 0 3h25m calico-node-dsx76 1/1 Running 0 3h25m calico-node-p5rf2 1/1 Running 0 3h25m calico-node-tr22l 1/1 Running 0 3h25m coredns-6d8c4cb4d-g4jxc 1/1 Running 0 3h45m coredns-6d8c4cb4d-sqcvj 1/1 Running 0 3h45m etcd-cka001 1/1 Running 0 3h45m kube-apiserver-cka001 1/1 Running 0 3h45m kube-controller-manager-cka001 1/1 Running 0 3h45m kube-proxy-5cdbj 1/1 Running 0 3h41m kube-proxy-cm4hc 1/1 Running 0 3h45m kube-proxy-g4w52 1/1 Running 0 3h41m kube-scheduler-cka001 1/1 Running 0 3h45m \u67e5\u8be2\u6240\u6709namespace\u4e0a\u7684pod\u4fe1\u606f\u3002 kubectl get pod --all-namespaces kubectl get pod -A","title":"\u547d\u540d\u7a7a\u95f4\uff08Namespace\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#serviceaccount-serviceaccount-authorization","text":"\u5728 Kubernetes 1.23 \u53ca\u66f4\u4f4e\u7248\u672c\u4e2d\uff0c\u5f53\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u65f6\uff0cKubernetes \u4f1a\u81ea\u52a8\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a default \u7684 ServiceAccount \u548c\u4e00\u4e2a\u540d\u4e3a default-token-xxxxx \u7684\u4ee4\u724c\u3002 \u800c\u5728 Kubernetes 1.24 \u4e2d\uff0c\u521b\u5efa\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u65f6\u4ec5\u4f1a\u81ea\u52a8\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a default \u7684 ServiceAccount\uff0c\u9700\u8981\u624b\u52a8\u521b\u5efa\u4e0e default ServiceAccount \u76f8\u5173\u8054\u7684\u4ee4\u724c\u3002 \u4ee5\u4e0b\u662f\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a dev \u7684\u65b0\u547d\u540d\u7a7a\u95f4\u7684\u793a\u4f8b\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5728\u547d\u540d\u7a7a\u95f4 dev \u4e2d\u4ec5\u521b\u5efa\u4e86 ServiceAccount\uff1a default \uff0c\u6ca1\u6709\u4e0e ServiceAccount default \u76f8\u5173\u8054\u7684\u4ee4\u724c\uff08secret\uff09\u3002 kubectl create namespace dev kubectl get serviceaccount -n dev kubectl get secrets -n dev \u6709\u4e00\u4e2a\u9ed8\u8ba4\u7684\u96c6\u7fa4\u89d2\u8272 admin \uff0c\u4f46\u662f\u6ca1\u6709\u5c06\u5176\u7ed1\u5b9a\u5230\u4efb\u4f55\u96c6\u7fa4\u89d2\u8272\u7ed1\u5b9a\uff08clusterrole binding\uff09\u4e2d\u3002 kubectl get clusterrole admin kubectl get clusterrolebinding | grep ClusterRole/admin \u89d2\u8272Role\u548c\u89d2\u8272\u7ed1\u5b9aRoleBinding\u662f\u57fa\u4e8e\u547d\u540d\u7a7a\u95f4\u7684\u3002\u5728\u547d\u540d\u7a7a\u95f4 dev \u4e2d\uff0c\u6ca1\u6709\u89d2\u8272\u548c\u89d2\u8272\u7ed1\u5b9a\u3002 kubectl get role -n dev kubectl get rolebinding -n dev \u5728 Kubernetes \u96c6\u7fa4\u4e2d\uff0cSecret \u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u7528\u4e8e\u5b58\u50a8\u654f\u611f\u4fe1\u606f\uff0c\u5982\u7528\u6237\u540d\u3001\u5bc6\u7801\u548c\u4ee4\u724c\u7b49\u3002Secret \u7684\u76ee\u6807\u662f\u5bf9\u51ed\u636e\u8fdb\u884c\u7f16\u7801\u6216\u54c8\u5e0c\u5316\u3002\u8fd9\u4e9b\u51ed\u636e\u53ef\u4ee5\u5728\u5404\u79cd Pod \u5b9a\u4e49\u6587\u4ef6\u4e2d\u91cd\u590d\u4f7f\u7528\u3002 kubernetes.io/service-account-token \u7c7b\u578b\u7684 Secret \u7528\u4e8e\u5b58\u50a8\u6807\u8bc6\u670d\u52a1\u8d26\u6237\u7684\u4ee4\u724c\u3002\u4f7f\u7528\u6b64\u7c7b\u578b\u7684 Secret \u65f6\uff0c\u9700\u8981\u786e\u4fdd kubernetes.io/service-account.name \u6ce8\u91ca\u8bbe\u7f6e\u4e3a\u73b0\u6709\u670d\u52a1\u8d26\u6237\u540d\u79f0\u3002 \u8ba9\u6211\u4eec\u5728 dev \u547d\u540d\u7a7a\u95f4\u4e2d\u4e3a ServiceAccount default \u521b\u5efa\u4e00\u4e2a\u4ee4\u724c\u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Secret metadata: name: default-token-dev namespace: dev annotations: kubernetes.io/service-account.name: \"default\" type: kubernetes.io/service-account-token EOF \u73b0\u5728\u5728 dev \u547d\u540d\u7a7a\u95f4\u4e2d\u521b\u5efa\u4e86 ServiceAccount default \u548c Secret\uff08\u4ee4\u724c\uff09 default-token-dev \u3002 kubectl get serviceaccount -n dev kubectl get secrets -n dev \u83b7\u53d6\u9ed8\u8ba4 Service Account \u7684 token\uff0c\u5e76\u8d4b\u503c\u7ed9\u73af\u5883\u53d8\u91cf $TOKEN \u3002 TOKEN = $( kubectl -n dev describe secret $( kubectl -n dev get secrets | grep default | cut -f1 -d ' ' ) | grep -E '^token' | cut -f2 -d ':' | tr -d ' ' ) echo $TOKEN \u83b7\u53d6 API Service \u5730\u5740\uff0c\u5e76\u8d4b\u503c\u7ed9\u73af\u5883\u53d8\u91cf $APISERVER \u3002 APISERVER = $( kubectl config view | grep https | cut -f 2 - -d \":\" | tr -d \" \" ) echo $APISERVER \u901a\u8fc7 API Server \u4ee5 JSON \u683c\u5f0f\u83b7\u53d6\u547d\u540d\u7a7a\u95f4 dev \u4e2d\u7684 Pod \u8d44\u6e90\u3002 curl $APISERVER /api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN \" --insecure \u6211\u4eec\u5c06\u6536\u5230\u201c403 forbidden\u201d\u7684\u9519\u8bef\u6d88\u606f\u3002ServiceAccount default \u6ca1\u6709\u8bbf\u95ee\u540d\u79f0\u7a7a\u95f4 dev \u4e2d\u7684Pod\u7684\u6388\u6743\u3002 \u8ba9\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a rolebinding-admin \u7684RoleBinding\uff0c\u5c06\u96c6\u7fa4\u89d2\u8272 admin \u7ed1\u5b9a\u5230\u540d\u79f0\u7a7a\u95f4 dev \u4e2d\u7684ServiceAccount default \u3002 \u56e0\u6b64\uff0cServiceAccount default \u88ab\u6388\u4e88\u5728\u540d\u79f0\u7a7a\u95f4 dev \u4e2d\u7684\u7ba1\u7406\u5458\u6388\u6743\u3002 # Usage: kubectl create rolebinding --clusterrole = --serviceaccount = : --namespace = # Crate rolebinding: kubectl create rolebinding rolebinding-admin --clusterrole = admin --serviceaccount = dev:default --namespace = dev \u6267\u884c\u547d\u4ee4 kubectl get rolebinding -n dev \uff0c\u5f97\u5230\u7c7b\u4f3c\u5982\u4e0b\u7684\u7ed3\u679c\u3002 NAME ROLE AGE rolebinding-admin ClusterRole/admin 10s \u518d\u6b21\u901a\u8fc7 API Server \u4ee5 JSON \u683c\u5f0f\u83b7\u53d6\u547d\u540d\u7a7a\u95f4 dev \u4e2d\u7684 Pod \u8d44\u6e90\uff0c\u6210\u529f\u3002 curl $APISERVER /api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN \" --insecure \u5220\u9664\u4e0a\u9762\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete namespace dev","title":"ServiceAccount \u6388\u6743\uff08ServiceAccount Authorization\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#deployment","text":"\u521b\u5efa\u4e00\u4e2a Ubuntu Pod \u4ee5\u8fdb\u884c\u64cd\u4f5c\uff0c\u5e76\u9644\u52a0\u5230\u8fd0\u884c\u4e2d\u7684 Pod\u3002 kubectl create -f - << EOF apiVersion: v1 kind: Pod metadata: name: ubuntu labels: app: ubuntu spec: containers: - name: ubuntu image: ubuntu:latest command: [\"/bin/sleep\", \"3650d\"] imagePullPolicy: IfNotPresent restartPolicy: Always EOF kubectl exec --stdin --tty ubuntu -- /bin/bash \u521b\u5efa\u4e00\u4e2a Deployment\uff0c\u9009\u9879 --image \u6307\u5b9a\u4e86\u4e00\u4e2a\u955c\u50cf\uff0c\u9009\u9879 --port \u6307\u5b9a\u4e86\u5916\u90e8\u8bbf\u95ee\u7684\u7aef\u53e3\u3002 \u5728\u521b\u5efa Deployment \u7684\u540c\u65f6\u4e5f\u4f1a\u521b\u5efa\u4e00\u4e2a Pod\u3002 kubectl create deployment myapp --image = docker.io/jocatalin/kubernetes-bootcamp:v1 --replicas = 1 --port = 8080 \u67e5\u8be2deployment\u7684\u72b6\u6001\u3002 kubectl get deployment myapp -o wide \u8f93\u51fa\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR myapp 1/1 1 1 79s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp \u67e5\u8be2deployment\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl describe deployment myapp \u8fd0\u884c\u7ed3\u679c\uff1a Name: myapp Namespace: dev CreationTimestamp: Sat, 23 Jul 2022 14:36:43 +0800 Labels: app=myapp Annotations: deployment.kubernetes.io/revision: 1 Selector: app=myapp Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=myapp Containers: kubernetes-bootcamp: Image: docker.io/jocatalin/kubernetes-bootcamp:v1 Port: 8080/TCP Host Port: 0/TCP Environment: Mounts: Volumes: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: NewReplicaSet: myapp-b5d775f5d (1/1 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 95s deployment-controller Scaled up replica set myapp-b5d775f5d to 1","title":"\u90e8\u7f72\uff08Deployment\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#expose-service","text":"\u83b7\u53d6\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u548cdeployment\u7684\u4fe1\u606f\u3002 kubectl get deployment myapp -o wide kubectl get pod -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-b5d775f5d-cx8dx 1/1 Running 0 2m34s 10.244.102.7 cka003 \u6267\u884c\u547d\u4ee4 curl 10.244.102.7:8080 \uff0c\u4ee5\u53d1\u9001HTTP\u8bf7\u6c42\u5230pod\u7684\u7aef\u53e3\uff0c\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 \u8981\u4f7f Pod \u53ef\u4ee5\u4ece\u5916\u90e8\u8bbf\u95ee\uff0c\u9700\u8981\u5c06\u7aef\u53e3 8080 \u66b4\u9732\u7ed9\u8282\u70b9\u7aef\u53e3\uff08NodePort\uff09\u3002\u8fd9\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u76f8\u5173\u7684 Service\u3002 kubectl expose deployment myapp --type = NodePort --port = 8080 \u6267\u884c\u547d\u4ee4 kubectl get svc myapp -o wide \uff0c\u83b7\u53d6service myapp \u7684\u8be6\u7ec6\u4fe1\u606f\u3002 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR myapp NodePort 11.244.74.3 8080:30514/TCP 7s app=myapp \u6267\u884c\u547d\u4ee4 curl 11.244.74.3:8080 \uff0c\u4ee5\u53d1\u9001HTTP\u8bf7\u6c42\u5230service\u7684\u7aef\u53e3\uff0c\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-cx8dx | v=1 \u83b7\u53d6service\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get svc myapp -o yaml kubectl describe svc myapp \u6267\u884c kubectl get endpoints myapp -o wide \u547d\u4ee4\u4ee5\u83b7\u53d6\u76f8\u5173\u7684 myapp \u7aef\u70b9\uff08endpoint\uff09\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 NAME ENDPOINTS AGE myapp 10.244.102.7:8080 43s \u63d0\u793a\uff1a Endpoint\uff08\u7aef\u70b9\uff09\u662f\u4e00\u4e2aKubernetes\u4e2d\u7684\u5bf9\u8c61\uff0c\u7528\u4e8e\u5b58\u50a8\u53ef\u4ee5\u88ab\u670d\u52a1\u8bbf\u95ee\u7684Pod\u7684\u7f51\u7edc\u5730\u5740\u548c\u7aef\u53e3\u4fe1\u606f\u3002 \u5f53Service\u521b\u5efa\u65f6\uff0cKubernetes\u4f1a\u81ea\u52a8\u521b\u5efa\u548c\u66f4\u65b0\u76f8\u5e94\u7684Endpoint\u3002 Endpoint\u662f\u7531kube-proxy\u81ea\u52a8\u521b\u5efa\u548c\u7ef4\u62a4\u7684\uff0c\u5e76\u6839\u636e\u9009\u62e9\u5668\u5339\u914d\u5bf9\u5e94\u7684Service\u548cPod\u3002 \u80fd\u6210\u529f\u7684\u53d1\u9001HTTP\u8bf7\u6c42\u5230service\u548c\u8282\u70b9\uff0c\u8bf4\u660epod\u7684\u7aef\u53e3 8080 \u88ab\u6b63\u786e\u7684\u6620\u5c04\u5230\u8282\u70b9\u7684\u7aef\u53e3 32566 \u3002 \u6267\u884c\u547d\u4ee4curl :30514\uff0c\u53d1\u9001HTTP\u8bf7\u6c42\u5230\u8282\u70b9 cka003 \u4e0a\u5bf9\u5e94\u7684\u7aef\u53e3\u3002 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 \u767b\u5f55\u8fdb\u5165Ubuntu pod\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u53d1\u9001HTTP\u8bf7\u6c42\u5230 myapp \u6240\u6620\u5c04\u7684service\u3001pod\u548c\u8282\u70b9\u7684\u7aef\u53e3\u3002 kubectl exec --stdin --tty ubuntu -- /bin/bash curl 10 .244.102.7:8080 curl 11 .244.74.3:8080 curl :30514 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v = 1","title":"\u66b4\u9732\u670d\u52a1\uff08Expose Service\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#scale-out-the-deployment","text":"Scale out by replicaset. We set three replicasets to scale out deployment myapp . The number of deployment myapp is now three. \u901a\u8fc7\u526f\u672c\u96c6replicaset\u8fdb\u884c\u6269\u5c55\u3002\u6211\u4eec\u901a\u8fc7\u6307\u5b9a\u526f\u672c\u96c6\u7684\u65b9\u5f0f\uff0c\u5bf9deployment myapp \u8fdb\u884c\u6269\u5c55\u90e8\u7f72\uff0c\u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0cdeployment myapp \u7684\u526f\u672c\u6570\u662f\u4e09\u4e2a\u3002 kubectl scale deployment myapp --replicas = 3 \u67e5\u8be2deployment\u7684\u4fe1\u606f\u3002 kubectl get deployment myapp \u67e5\u8be2replicaset\u7684\u4fe1\u606f kubectl get replicaset","title":"\u6269\u5bb9\u90e8\u7f72\uff08Scale out the Deployment\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#rolling-update","text":"\u547d\u4ee4\u7528\u6cd5\uff1a kubectl set image (-f \u6587\u4ef6\u540d | \u7c7b\u578b \u540d\u79f0) \u5bb9\u5668\u540d\u79f0_1=\u5bb9\u5668\u955c\u50cf_1 ... \u5bb9\u5668\u540d\u79f0_N=\u5bb9\u5668\u955c\u50cf_N \u3002 \u4f7f\u7528\u547d\u4ee4 kubectl get deployment \uff0c\u6211\u4eec\u53ef\u4ee5\u83b7\u53d6deployment myapp \u548c\u76f8\u5173\u5bb9\u5668 kubernetes-bootcamp \u3002 kubectl get deployment myapp -o wide \u4f7f\u7528\u547d\u4ee4 kubectl set image \u6765\u66f4\u65b0\u591a\u4e2a\u7248\u672c\u7684\u955c\u50cf\uff0c\u5e76\u4f7f\u7528\u9009\u9879 --record \u5c06\u66f4\u6539\u8bb0\u5f55\u5728\u90e8\u7f72\u7684\u6ce8\u91ca\u4e2d\u3002 kubectl set image deployment/myapp kubernetes-bootcamp = docker.io/jocatalin/kubernetes-bootcamp:v2 --record \u67e5\u8be2\u5f53\u524dreplicas\u7684\u72b6\u6001\u3002 kubectl get replicaset -o wide -l app = myapp \u8f93\u51fa\u7ed3\u679c\u5982\u4e0b\uff0cpod\u6b63\u4ee5\u65b0\u7684\u526f\u672c\u96c6replicas\u6570\u91cf\u8fd0\u884c\u3002 NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR myapp-5dbd68cc99 1 1 0 8s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v2 app=myapp,pod-template-hash=5dbd68cc99 myapp-b5d775f5d 3 3 3 14m kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp,pod-template-hash=b5d775f5d \u6211\u4eec\u53ef\u4ee5\u5728\u5bf9\u5e94\u7684yaml\u6587\u4ef6\u4e2d metadata.annotations \u90e8\u5206\u83b7\u53d6\u53d8\u66f4\u5386\u53f2\u8bb0\u5f55\u3002 kubectl get deployment myapp -o yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion : apps/v1 kind : Deployment metadata : annotations : deployment.kubernetes.io/revision : \"2\" kubernetes.io/change-cause : kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true ...... \u6211\u4eec\u4e5f\u53ef\u4ee5\u4f7f\u7528\u547d\u4ee4 kubectl rollout history \u83b7\u53d6\u66f4\u65b0\u5386\u53f2\u8bb0\u5f55\uff0c\u5e76\u4f7f\u7528\u7279\u5b9a\u4fee\u8ba2\u7248\u672c\u53f7 --revision= \u663e\u793a\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl rollout history deployment/myapp \u8fd0\u884c\u7ed3\u679c\uff1a deployment.apps/myapp REVISION CHANGE-CAUSE 1 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true \u83b7\u53d6\u7279\u5b9a\u7248\u672c\u56de\u6eda\u5386\u53f2\u8bb0\u5f55\u3002 kubectl rollout history deployment/myapp --revision = 2 \u6267\u884c\u547d\u4ee4 kubectl rollout undo \u53ef\u4ee5\u56de\u6eda\u5230\u4e0a\u4e00\u4e2a\u7248\u672c\uff0c\u6216\u4f7f\u7528\u9009\u9879 --to-revision= \u56de\u6eda\u5230\u6307\u5b9a\u7684\u7248\u672c\u3002 kubectl rollout undo deployment/myapp --to-revision = 1 \u7248\u672c 1 \u73b0\u5728\u5df2\u7ecf\u88ab\u66ff\u6362\u6210\u7248\u672c 3 \u4e86\u3002 kubectl rollout history deployment/myapp \u8fd0\u884c\u7ed3\u679c\uff1a deployment.apps/myapp REVISION CHANGE-CAUSE 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true 3 ","title":"\u6eda\u52a8\u5347\u7ea7\uff08Rolling update\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#event","text":"\u83b7\u53d6\u6307\u5b9apod\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl describe pod myapp-b5d775f5d-jlx6g \u8f93\u51fa\u7ed3\u679c\uff1a ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 54s default-scheduler Successfully assigned dev/myapp-b5d775f5d-jlx6g to cka003 Normal Pulled 53s kubelet Container image \"docker.io/jocatalin/kubernetes-bootcamp:v1\" already present on machine Normal Created 53s kubelet Created container kubernetes-bootcamp Normal Started 53s kubelet Started container kubernetes-bootcamp \u67e5\u8be2\u96c6\u7fa4\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl get event","title":"\u4e8b\u4ef6\uff08Event\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#logging","text":"\u67e5\u8be2pod\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl logs -f kubectl logs -f -c \u4f8b\u5982\uff1a kubectl logs -f myapp-b5d775f5d-jlx6g \u8fd0\u884c\u7ed3\u679c\uff1a Kubernetes Bootcamp App Started At: 2022-07-23T06:54:18.532Z | Running On: myapp-b5d775f5d-jlx6g \u67e5\u8be2K8s\u4e0d\u540c\u7ec4\u4ef6\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl logs kube-apiserver-cka001 -n kube-system kubectl logs kube-controller-manager-cka001 -n kube-system kubectl logs kube-scheduler-cka001 -n kube-system kubectl logs etcd-cka001 -n kube-system systemctl status kubelet journalctl -fu kubelet kubectl logs kube-proxy-5cdbj -n kube-system \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete service myapp kubectl delete deployment myapp","title":"\u65e5\u5fd7\u8bb0\u5f55\uff08Logging\uff09"},{"location":"k8s/cka_cn/foundamentals/clustermgt/","text":"CKA\u81ea\u5b66\u7b14\u8bb024:Cluster Management \u00b6 \u6f14\u793a\u573a\u666f\uff1a etcd Backup and Restore \u5b89\u88c5 etcdctl \u5728\u5907\u4efd\u4e4b\u524d\u521b\u5efa Deployment \u5907\u4efd etcd \u5728\u5907\u4efd\u4e4b\u540e\u521b\u5efa Deployment \u505c\u6b62\u670d\u52a1 \u505c\u6b62 etcd \u6062\u590d etcd \u542f\u52a8\u670d\u52a1 \u9a8c\u8bc1 etcd \u5907\u4efd\u548c\u6062\u590d \u00b6 \u5b89\u88c5 etcdctl \u00b6 \u4e0b\u8f7d etcd \u5b89\u88c5\u5305\u3002 wget https://github.com/etcd-io/etcd/releases/download/v3.5.3/etcd-v3.5.3-linux-amd64.tar.gz \u89e3\u538b etcd \u5b89\u88c5\u5305\uff0c\u5e76\u8d4b\u4e88\u6267\u884c\u6743\u9650\u3002 tar -zxvf etcd-v3.5.3-linux-amd64.tar.gz cp etcd-v3.5.3-linux-amd64/etcdctl /usr/local/bin/ sudo chmod u+x /usr/local/bin/etcdctl \u9a8c\u8bc1\uff1a etcdctl --help \u521b\u5efa\u4e00\u4e2adeployment\uff08\u5907\u4efd\u524d\uff09 \u00b6 \u5907\u4efd\u524d\u521b\u5efa\u4e00\u4e2adeployment\u3002 kubectl create deployment app-before-backup --image = nginx \u5907\u4efd etcd \u00b6 \u8bf4\u660e\uff1a \u662f\u63a7\u5236\u5e73\u9762\u8282\u70b9\u7684\u5b9e\u9645IP\u5730\u5740\u3002 --endpoints \uff1a\u6307\u5b9a etcd \u5907\u4efd\u7684\u4fdd\u5b58\u4f4d\u7f6e\uff0c2379 \u662f etcd \u7684\u7aef\u53e3\u53f7\u3002 --cert \uff1a\u6307\u5b9a etcd \u8bc1\u4e66\u7684\u4f4d\u7f6e\uff0c\u8bc1\u4e66\u662f\u7531 kubeadm \u751f\u6210\u5e76\u4fdd\u5b58\u5728 /etc/kubernetes/pki/etcd/ \u76ee\u5f55\u4e0b\u7684\u3002 --key \uff1a\u6307\u5b9a etcd \u8bc1\u4e66\u7684\u79c1\u94a5\u7684\u4f4d\u7f6e\uff0c\u8bc1\u4e66\u662f\u7531 kubeadm \u751f\u6210\u5e76\u4fdd\u5b58\u5728 /etc/kubernetes/pki/etcd/ \u76ee\u5f55\u4e0b\u7684\u3002 --cacert \uff1a\u6307\u5b9a etcd \u8bc1\u4e66\u7684 CA \u7684\u4f4d\u7f6e\uff0c\u8bc1\u4e66\u662f\u7531 kubeadm \u751f\u6210\u5e76\u4fdd\u5b58\u5728 /etc/kubernetes/pki/etcd/ \u76ee\u5f55\u4e0b\u7684\u3002 etcdctl \\ --endpoints = https://:2379 \\ --cert = /etc/kubernetes/pki/etcd/server.crt \\ --key = /etc/kubernetes/pki/etcd/server.key \\ --cacert = /etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot- $( date + \"%Y%m%d%H%M%S\" ) .db \u6216\u8005 etcdctl \\ --endpoints = https://:2379 \\ --cert = /etc/kubernetes/pki/etcd/server.crt \\ --key = /etc/kubernetes/pki/etcd/server.key \\ --cacert = /etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot- $( date + \"%Y%m%d%H%M%S\" ) .db Output: {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.328+0800\",\"caller\":\"snapshot/v3_snapshot.go:65\",\"msg\":\"created temporary db file\",\"path\":\"snapshot-20220724185121.db.part\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:211\",\"msg\":\"opened snapshot stream; downloading\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"caller\":\"snapshot/v3_snapshot.go:73\",\"msg\":\"fetching snapshot\",\"endpoint\":\"https://:2379\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.415+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:219\",\"msg\":\"completed snapshot read; closing\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:88\",\"msg\":\"fetched snapshot\",\"endpoint\":\"https://:2379\",\"size\":\"3.6 MB\",\"took\":\"now\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:97\",\"msg\":\"saved\",\"path\":\"snapshot-20220724185121.db\"} Snapshot saved at snapshot-20220724185121.db \u6267\u884c\u547d\u4ee4 ls -al \u5728\u5f53\u524d\u76ee\u5f55\u4e2d\u8bfb\u53d6\u6211\u4eec\u521a\u521a\u521b\u5efa\u7684\u5907\u4efd\u6587\u4ef6\u3002 -rw------- 1 root root 3616800 Jul 24 18 :51 snapshot-20220724185121.db \u521b\u5efa\u4e00\u4e2adeployment\uff08\u5907\u4efd\u540e\uff09 \u00b6 \u5907\u4efd\u540e\uff0c\u6211\u4eec\u521b\u5efa\u53e6\u5916\u4e00\u4e2adeployment\u3002 kubectl create deployment app-after-backup --image = nginx \u5220\u9664\u5907\u4efd\u524d\u6211\u4eec\u521b\u5efa\u7684\u90a3\u4e2adeployment\u3002 kubectl delete deployment app-before-backup \u68c0\u67e5deployment\u7684\u72b6\u6001\u3002 kubectl get deploy \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE app-after-backup 1/1 1 1 108s \u505c\u6b62Services \u00b6 \u5220\u9664 etcd \u7684\u76ee\u5f55\u3002 mv /var/lib/etcd/ /var/lib/etcd.bak \u505c\u6b62 kubelet \u3002 systemctl stop kubelet \u505c\u6b62 kube-apiserver \u3002 nerdctl -n k8s.io ps -a | grep apiserver \u8fd0\u884c\u7ed3\u679c\uff1a 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001 \u505c\u6b62\u90a3\u4e9b\u4ecd\u65e7\u5904\u4e8e up \u72b6\u6001\u7684\u5bb9\u5668\u3002 nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0c5e69118f1b nerdctl -n k8s.io stop 638bb602c310 \u76f4\u81f3\u6ca1\u6709\u5904\u4e8e up \u72b6\u6001\u7684 kube-apiserver \u3002 nerdctl -n k8s.io ps -a | grep apiserver \u8fd0\u884c\u7ed3\u679c\uff1a 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001 \u505c\u6b62etcd \u00b6 nerdctl -n k8s.io ps -a | grep etcd \u8fd0\u884c\u7ed3\u679c\uff1a 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/etcd-cka001 \u505c\u6b62\u90a3\u4e9b\u4ecd\u65e7\u5904\u4e8e up \u72b6\u6001\u7684\u5bb9\u5668\u3002 nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0965b195f41a nerdctl -n k8s.io stop 9e1bea9f25d1 \u76f4\u81f3\u6ca1\u6709\u5904\u4e8e up \u72b6\u6001\u7684 kube-apiserver \u3002 nerdctl -n k8s.io ps -a | grep etcd \u8fd0\u884c\u7ed3\u679c\uff1a 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001 \u6062\u590d etcd \u00b6 \u5728\u63a7\u5236\u5e73\u9762\u8282\u70b9\u4e0a\u6267\u884c\u6062\u590d\u64cd\u4f5c\uff0c\u4f7f\u7528\u5b9e\u9645\u7684\u5907\u4efd\u6587\u4ef6\uff0c\u8fd9\u91cc\u662f\u6587\u4ef6 snapshot-20220724185121.db \u3002 etcdctl snapshot restore snapshot-20220724185121.db \\ --endpoints = :2379 \\ --cert = /etc/kubernetes/pki/etcd/server.crt \\ --key = /etc/kubernetes/pki/etcd/server.key \\ --cacert = /etc/kubernetes/pki/etcd/ca.crt \\ --data-dir = /var/lib/etcd \u8fd0\u884c\u7ed3\u679c\uff1a Deprecated: Use `etcdutl snapshot restore` instead. 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:248 restoring snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\", \"stack\": \"go.etcd.io/etcd/etcdutl/v3/snapshot.(*v3Manager).Restore\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/snapshot/v3_snapshot.go:254\\ngo.etcd.io/etcd/etcdutl/v3/etcdutl.SnapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/etcdutl/snapshot_command.go:147\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3/command.snapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/command/snapshot_command.go:129\\ngithub.com/spf13/cobra.(*Command).execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856\\ngithub.com/spf13/cobra.(*Command).ExecuteC\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960\\ngithub.com/spf13/cobra.(*Command).Execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:897\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.Start\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:107\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.MustStart\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:111\\nmain.main\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/main.go:59\\nruntime.main\\n\\t/go/gos/go1.16.15/src/runtime/proc.go:225\"} 2022-07-24T18:57:49+08:00 info membership/store.go:141 Trimming membership information from the backend... 2022-07-24T18:57:49+08:00 info membership/cluster.go:421 added member {\"cluster-id\": \"cdf818194e3a8c32\", \"local-member-id\": \"0\", \"added-peer-id\": \"8e9e05c52164694d\", \"added-peer-peer-urls\": [\"http://localhost:2380\"]} 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:269 restored snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\"} \u68c0\u67e5\u88ab\u5220\u9664\u7684 etcd \u76ee\u5f55\u662f\u5426\u5df2\u7ecf\u4ece\u5907\u4efd\u4e2d\u6062\u590d\u4e86\u3002 tree /var/lib/etcd \u8fd0\u884c\u7ed3\u679c\uff1a /var/lib/etcd \u2514\u2500\u2500 member \u251c\u2500\u2500 snap \u2502 \u251c\u2500\u2500 0000000000000001-0000000000000001.snap \u2502 \u2514\u2500\u2500 db \u2514\u2500\u2500 wal \u2514\u2500\u2500 0000000000000000-0000000000000000.wal \u542f\u52a8\u670d\u52a1Services \u00b6 \u542f\u52a8 kubelet \u3002\u670d\u52a1 kube-apiserver \u548c etcd \u4e5f\u4f1a\u7ee7 kubelet \u542f\u52a8\u540e\u88ab\u81ea\u52a8\u542f\u52a8\u3002 systemctl start kubelet \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u786e\u8ba4\u6240\u6709\u670d\u52a1\u90fd\u5df2\u7ecf\u542f\u52a8\u548c\u6b63\u5e38\u8fd0\u884c\u3002 systemctl status kubelet.service nerdctl -n k8s.io ps -a | grep etcd nerdctl -n k8s.io ps -a | grep apiserver \u67e5\u770b\u5f53\u524d etcd \u7684\u72b6\u6001\u3002 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 3b8f37c87782 registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 6 seconds ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001 fbbbb628a945 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 6 seconds ago Up k8s://kube-system/etcd-cka001 \u67e5\u770b\u5f53\u524d apiserver \u7684\u72b6\u6001\u3002 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 281cf4c6670d registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 14 seconds ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 5ed8295d92da registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 15 seconds ago Up k8s://kube-system/kube-apiserver-cka001 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001 \u9a8c\u8bc1 \u00b6 \u68c0\u67e5\u96c6\u7fa4\u7684\u72b6\u6001\uff0c\u67e5\u770b\u662f\u5426pod app-before-backup \u5b58\u5728\u3002 kubectl get deploy \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE app-before-backup 1/1 1 1 11m \u96c6\u7fa4\u5347\u7ea7 \u00b6 \u6f14\u793a\u573a\u666f\uff1a\u96c6\u7fa4\u5347\u7ea7 \u9a71\u9010\u63a7\u5236\u5e73\u9762\u8282\u70b9 \u68c0\u67e5\u5f53\u524d\u53ef\u7528\u7684 kubeadm \u7248\u672c \u5c06 kubeadm \u5347\u7ea7\u5230\u65b0\u7248\u672c \u68c0\u67e5\u5347\u7ea7\u8ba1\u5212 \u5e94\u7528\u5347\u7ea7\u8ba1\u5212\u4ee5\u5347\u7ea7\u5230\u65b0\u7248\u672c \u5347\u7ea7 kubelet \u548c kubectl \u542f\u7528\u63a7\u5236\u5e73\u9762\u8282\u70b9\u8c03\u5ea6 \u9a71\u9010\u5de5\u4f5c\u8282\u70b9 \u5347\u7ea7 kubeadm \u548c kubelet \u542f\u7528\u5de5\u4f5c\u8282\u70b9\u8c03\u5ea6 \u53c2\u8003\uff1a kubeadm\u5347\u7ea7 \u5347\u7ea7\u63a7\u5236\u5e73\u9762 \u00b6 \u63a7\u5236\u5e73\u9762\u51c6\u5907 \u00b6 \u9a71\u9010\u63a7\u5236\u5e73\u9762\u8282\u70b9\u3002 kubectl drain --ignore-daemonsets \u8fd9\u91cc\u662f\uff1a kubectl drain cka001 --ignore-daemonsets \u8fd0\u884c\u7ed3\u679c\uff1a node/cka001 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-dsx76, kube-system/kube-proxy-cm4hc evicting pod kube-system/calico-kube-controllers-5c64b68895-jr4nl evicting pod kube-system/coredns-6d8c4cb4d-g4jxc evicting pod kube-system/coredns-6d8c4cb4d-sqcvj pod/calico-kube-controllers-5c64b68895-jr4nl evicted pod/coredns-6d8c4cb4d-g4jxc evicted pod/coredns-6d8c4cb4d-sqcvj evicted node/cka001 drained \u63a7\u5236\u5e73\u9762\u8282\u70b9\u73b0\u5728\u5904\u4e8e SchedulingDisabled \u72b6\u6001\u3002 kubectl get node -owide \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 \u67e5\u8be2\u5f53\u524d kubeadm \u53ef\u7528\u7248\u672c\u3002 apt policy kubeadm \u8f93\u51fa\u7ed3\u679c\uff1a kubeadm: Installed: 1.24.0-00 Candidate: 1.24.3-00 Version table: 1.24.3-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.1-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages *** 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 100 /var/lib/dpkg/status 1.23.7-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages ...... \u5347\u7ea7 kubeadm \u5230 Candidate: 1.24.2-00 \u7248\u672c\u3002 sudo apt-get -y install kubeadm = 1 .24.2-00 --allow-downgrades \u67e5\u8be2\u5347\u7ea7\u8ba1\u5212\u3002 kubeadm upgrade plan \u8f93\u51fa\u7c7b\u4f3c\u4e0b\u9762\u7684\u5347\u7ea7\u8ba1\u5212\u3002 [upgrade/config] Making sure the configuration is correct: [upgrade/config] Reading configuration from the cluster... [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [preflight] Running pre-flight checks. [upgrade] Running cluster health checks [upgrade] Fetching available versions to upgrade to [upgrade/versions] Cluster version: v1.24.0 [upgrade/versions] kubeadm version: v1.24.2 I0724 19:05:00.111855 1142460 version.go:255] remote version is much newer: v1.24.3; falling back to: stable-1.23 [upgrade/versions] Target version: v1.24.2 [upgrade/versions] Latest version in the v1.23 series: v1.24.2 Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply': COMPONENT CURRENT TARGET kubelet 3 x v1.24.0 v1.24.2 Upgrade to the latest version in the v1.23 series: COMPONENT CURRENT TARGET kube-apiserver v1.24.0 v1.24.2 kube-controller-manager v1.24.0 v1.24.2 kube-scheduler v1.24.0 v1.24.2 kube-proxy v1.24.0 v1.24.2 CoreDNS v1.8.6 v1.8.6 etcd 3.5.1-0 3.5.1-0 You can now apply the upgrade by executing the following command: kubeadm upgrade apply v1.24.2 _____________________________________________________________________ The table below shows the current state of component configs as understood by this version of kubeadm. Configs that have a \"yes\" mark in the \"MANUAL UPGRADE REQUIRED\" column require manual config upgrade or resetting to kubeadm defaults before a successful upgrade can be performed. The version to manually upgrade to is denoted in the \"PREFERRED VERSION\" column. API GROUP CURRENT VERSION PREFERRED VERSION MANUAL UPGRADE REQUIRED kubeproxy.config.k8s.io v1alpha1 v1alpha1 no kubelet.config.k8s.io v1beta1 v1beta1 no _____________________________________________________________________ \u63a7\u5236\u5e73\u9762\u5347\u7ea7 \u00b6 \u53c2\u8003\u524d\u9762\u7684\u5347\u7ea7\u8ba1\u5212\uff0c\u6211\u4eec\u5347\u7ea7\u5230 v1.24.2 \u7248\u672c\u3002 kubeadm upgrade apply v1.24.2 \u901a\u8fc7\u9009\u9879 --etcd-upgrade=false \uff0c\u6211\u4eec\u628a etcd \u6392\u9664\u51fa\u5f53\u524d\u5347\u7ea7\u8303\u56f4\u3002 kubeadm upgrade apply v1.24.2 --etcd-upgrade = false \u6536\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u5219\u4ee3\u8868\u4e0a\u9762\u7684\u5347\u7ea7\u547d\u4ee4\u6210\u529f\u4e86\u3002 [upgrade/successful] SUCCESS! Your cluster was upgraded to \"v1.24.2\". Enjoy! [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so. \u5347\u7ea7 kubelet \u548c kubectl \u3002 sudo apt-get -y install kubelet = 1 .24.2-00 kubectl = 1 .24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet \u67e5\u8be2\u8282\u70b9\u5f53\u524d\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0 After verify that each node is in Ready status, enable node scheduling. \u5728\u786e\u8ba4\u6240\u6709\u8282\u70b9\u90fd\u5904\u4e8eReady\u72b6\u6001\uff0c\u5219\u6fc0\u6d3bscheduling\u3002 kubectl uncordon \u8fd9\u91cc\u662f\uff1a kubectl uncordon cka001 \u8f93\u51fa\u7ed3\u679c\uff1a node/cka001 uncordoned \u518d\u6b21\u68c0\u67e5\u8282\u70b9\u72b6\u6001\uff0c\u786e\u4fdd\u6240\u6709\u8282\u70b9\u90fd\u5904\u4e8eReady\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0 \u5347\u7ea7\u5de5\u4f5c\u8282\u70b9 \u00b6 \u5de5\u4f5c\u8282\u70b9\u51c6\u5907 \u00b6 \u767b\u5f55\u8282\u70b9 cka001 \u3002 \u9a71\u9010 Worker \u8282\u70b9\uff0c\u9700\u8981\u663e\u5f0f\u6307\u5b9a\u662f\u5426\u5220\u9664\u672c\u5730\u5b58\u50a8\u3002 kubectl drain --ignore-daemonsets --force kubectl drain --ignore-daemonsets --delete-emptydir-data --force \u5982\u679c\u9047\u5230\u5173\u4e8e emptydir \u4f9d\u8d56\u7684\u9519\u8bef\uff0c\u5219\u6267\u884c\u7b2c\u4e8c\u4e2a\u547d\u4ee4\u3002 kubectl drain cka002 --ignore-daemonsets --force kubectl drain cka002 --ignore-daemonsets --delete-emptydir-data --force \u8f93\u51fa\u7ed3\u679c\uff1a node/cka002 cordoned WARNING: deleting Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet: dev/ubuntu; ignoring DaemonSet-managed Pods: kube-system/calico-node-p5rf2, kube-system/kube-proxy-zvs68 evicting pod ns-netpol/pod-netpol-5b67b6b496-2cgnw evicting pod dev/ubuntu evicting pod dev/app-before-backup-66dc9d5cb-6xc8c evicting pod dev/nfs-client-provisioner-86d7fb78b6-2f5dx evicting pod dev/pod-netpol-2-77478d77ff-l6rzm evicting pod ingress-nginx/ingress-nginx-admission-patch-nk9fv evicting pod ingress-nginx/ingress-nginx-admission-create-lgtdj evicting pod kube-system/coredns-6d8c4cb4d-l4kx4 pod/ingress-nginx-admission-create-lgtdj evicted pod/ingress-nginx-admission-patch-nk9fv evicted pod/nfs-client-provisioner-86d7fb78b6-2f5dx evicted pod/app-before-backup-66dc9d5cb-6xc8c evicted pod/coredns-6d8c4cb4d-l4kx4 evicted pod/pod-netpol-5b67b6b496-2cgnw evicted pod/pod-netpol-2-77478d77ff-l6rzm evicted pod/ubuntu evicted node/cka002 drained \u5de5\u4f5c\u8282\u70b9\u5347\u7ea7 \u00b6 \u767b\u5f55\u8282\u70b9 cka002 \u3002 \u4e0b\u8f7d kubeadm \u7684 v1.24.2 \u7248\u672c\u3002 sudo apt-get -y install kubeadm = 1 .24.2-00 --allow-downgrades \u5347\u7ea7 kubeadm \u3002 sudo kubeadm upgrade node \u5347\u7ea7 kubelet \u3002 sudo apt-get -y install kubelet = 1 .24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet \u786e\u8ba4\u6240\u6709\u8282\u70b9\u90fd\u5904\u4e8eReady\u72b6\u6001\uff0c\u5219\u6fc0\u6d3bscheduling\u3002 kubectl uncordon \u8fd9\u91cc\u662f\uff1a kubectl uncordon cka002 \u5de5\u4f5c\u8282\u70b9\u9a8c\u8bc1 \u00b6 \u67e5\u8be2\u8282\u70b9\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.0 \u5728\u8282\u70b9 cka003 \u4e0a\u91cd\u590d\u4e0a\u9762\u7684\u6b65\u9aa4\u3002 \u767b\u5f55\u8282\u70b9 cka003 \u3002\u5982\u679c\u9047\u5230\u5173\u4e8e emptydir \u4f9d\u8d56\u7684\u9519\u8bef\uff0c\u5219\u6267\u884c\u7b2c\u4e8c\u4e2a\u547d\u4ee4\u3002 kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --force kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --delete-emptydir-data --force \u767b\u5f55\u8282\u70b9 cka003 \uff0c\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u3002 sudo apt-get -y install kubeadm = 1 .24.2-00 --allow-downgrades sudo kubeadm upgrade node sudo apt-get -y install kubelet = 1 .24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet kubectl get node kubectl uncordon cka003 \u67e5\u8be2\u8282\u70b9\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.2 \u603b\u7ed3 \u00b6 \u5728\u63a7\u5236\u9762\u677f\u4e0a\u7684\u6267\u884c\u6b65\u9aa4\uff1a kubectl get node -owide kubectl drain cka001 --ignore-daemonsets kubectl get node -owide apt policy kubeadm apt-get -y install kubeadm = 1 .24.0-00 --allow-downgrades kubeadm upgrade plan kubeadm upgrade apply v1.24.0 # kubeadm upgrade apply v1.24.0 --etcd-upgrade=false apt-get -y install kubelet = 1 .24.0-00 kubectl = 1 .24.0-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl get node kubectl uncordon cka001 \u5728\u5de5\u4f5c\u8282\u70b9\u4e0a\u7684\u6267\u884c\u6b65\u9aa4\uff1a \u5728\u63a7\u5236\u9762\u677f\u4e0a\uff1a kubectl drain cka002 --ignore-daemonsets \u5728\u5de5\u4f5c\u8282\u70b9\u4e0a\uff1a apt-get -y install kubeadm = 1 .24.1-00 --allow-downgrades kubeadm upgrade node apt-get -y install kubelet = 1 .24.1-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl uncordon cka002 \u5728\u5176\u4ed6\u5de5\u4f5c\u8282\u70b9\u4e0a\u91cd\u590d\u4e0a\u9762\u7684\u6b65\u9aa4\u3002","title":"Cluster Management"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#cka24cluster-management","text":"\u6f14\u793a\u573a\u666f\uff1a etcd Backup and Restore \u5b89\u88c5 etcdctl \u5728\u5907\u4efd\u4e4b\u524d\u521b\u5efa Deployment \u5907\u4efd etcd \u5728\u5907\u4efd\u4e4b\u540e\u521b\u5efa Deployment \u505c\u6b62\u670d\u52a1 \u505c\u6b62 etcd \u6062\u590d etcd \u542f\u52a8\u670d\u52a1 \u9a8c\u8bc1","title":"CKA\u81ea\u5b66\u7b14\u8bb024:Cluster Management"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#etcd","text":"","title":"etcd\u5907\u4efd\u548c\u6062\u590d"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#etcdctl","text":"\u4e0b\u8f7d etcd \u5b89\u88c5\u5305\u3002 wget https://github.com/etcd-io/etcd/releases/download/v3.5.3/etcd-v3.5.3-linux-amd64.tar.gz \u89e3\u538b etcd \u5b89\u88c5\u5305\uff0c\u5e76\u8d4b\u4e88\u6267\u884c\u6743\u9650\u3002 tar -zxvf etcd-v3.5.3-linux-amd64.tar.gz cp etcd-v3.5.3-linux-amd64/etcdctl /usr/local/bin/ sudo chmod u+x /usr/local/bin/etcdctl \u9a8c\u8bc1\uff1a etcdctl --help","title":"\u5b89\u88c5etcdctl"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#deployment","text":"\u5907\u4efd\u524d\u521b\u5efa\u4e00\u4e2adeployment\u3002 kubectl create deployment app-before-backup --image = nginx","title":"\u521b\u5efa\u4e00\u4e2adeployment\uff08\u5907\u4efd\u524d\uff09"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#etcd_1","text":"\u8bf4\u660e\uff1a \u662f\u63a7\u5236\u5e73\u9762\u8282\u70b9\u7684\u5b9e\u9645IP\u5730\u5740\u3002 --endpoints \uff1a\u6307\u5b9a etcd \u5907\u4efd\u7684\u4fdd\u5b58\u4f4d\u7f6e\uff0c2379 \u662f etcd \u7684\u7aef\u53e3\u53f7\u3002 --cert \uff1a\u6307\u5b9a etcd \u8bc1\u4e66\u7684\u4f4d\u7f6e\uff0c\u8bc1\u4e66\u662f\u7531 kubeadm \u751f\u6210\u5e76\u4fdd\u5b58\u5728 /etc/kubernetes/pki/etcd/ \u76ee\u5f55\u4e0b\u7684\u3002 --key \uff1a\u6307\u5b9a etcd \u8bc1\u4e66\u7684\u79c1\u94a5\u7684\u4f4d\u7f6e\uff0c\u8bc1\u4e66\u662f\u7531 kubeadm \u751f\u6210\u5e76\u4fdd\u5b58\u5728 /etc/kubernetes/pki/etcd/ \u76ee\u5f55\u4e0b\u7684\u3002 --cacert \uff1a\u6307\u5b9a etcd \u8bc1\u4e66\u7684 CA \u7684\u4f4d\u7f6e\uff0c\u8bc1\u4e66\u662f\u7531 kubeadm \u751f\u6210\u5e76\u4fdd\u5b58\u5728 /etc/kubernetes/pki/etcd/ \u76ee\u5f55\u4e0b\u7684\u3002 etcdctl \\ --endpoints = https://:2379 \\ --cert = /etc/kubernetes/pki/etcd/server.crt \\ --key = /etc/kubernetes/pki/etcd/server.key \\ --cacert = /etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot- $( date + \"%Y%m%d%H%M%S\" ) .db \u6216\u8005 etcdctl \\ --endpoints = https://:2379 \\ --cert = /etc/kubernetes/pki/etcd/server.crt \\ --key = /etc/kubernetes/pki/etcd/server.key \\ --cacert = /etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot- $( date + \"%Y%m%d%H%M%S\" ) .db Output: {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.328+0800\",\"caller\":\"snapshot/v3_snapshot.go:65\",\"msg\":\"created temporary db file\",\"path\":\"snapshot-20220724185121.db.part\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:211\",\"msg\":\"opened snapshot stream; downloading\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"caller\":\"snapshot/v3_snapshot.go:73\",\"msg\":\"fetching snapshot\",\"endpoint\":\"https://:2379\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.415+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:219\",\"msg\":\"completed snapshot read; closing\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:88\",\"msg\":\"fetched snapshot\",\"endpoint\":\"https://:2379\",\"size\":\"3.6 MB\",\"took\":\"now\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:97\",\"msg\":\"saved\",\"path\":\"snapshot-20220724185121.db\"} Snapshot saved at snapshot-20220724185121.db \u6267\u884c\u547d\u4ee4 ls -al \u5728\u5f53\u524d\u76ee\u5f55\u4e2d\u8bfb\u53d6\u6211\u4eec\u521a\u521a\u521b\u5efa\u7684\u5907\u4efd\u6587\u4ef6\u3002 -rw------- 1 root root 3616800 Jul 24 18 :51 snapshot-20220724185121.db","title":"\u5907\u4efdetcd"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#deployment_1","text":"\u5907\u4efd\u540e\uff0c\u6211\u4eec\u521b\u5efa\u53e6\u5916\u4e00\u4e2adeployment\u3002 kubectl create deployment app-after-backup --image = nginx \u5220\u9664\u5907\u4efd\u524d\u6211\u4eec\u521b\u5efa\u7684\u90a3\u4e2adeployment\u3002 kubectl delete deployment app-before-backup \u68c0\u67e5deployment\u7684\u72b6\u6001\u3002 kubectl get deploy \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE app-after-backup 1/1 1 1 108s","title":"\u521b\u5efa\u4e00\u4e2adeployment\uff08\u5907\u4efd\u540e\uff09"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#services","text":"\u5220\u9664 etcd \u7684\u76ee\u5f55\u3002 mv /var/lib/etcd/ /var/lib/etcd.bak \u505c\u6b62 kubelet \u3002 systemctl stop kubelet \u505c\u6b62 kube-apiserver \u3002 nerdctl -n k8s.io ps -a | grep apiserver \u8fd0\u884c\u7ed3\u679c\uff1a 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001 \u505c\u6b62\u90a3\u4e9b\u4ecd\u65e7\u5904\u4e8e up \u72b6\u6001\u7684\u5bb9\u5668\u3002 nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0c5e69118f1b nerdctl -n k8s.io stop 638bb602c310 \u76f4\u81f3\u6ca1\u6709\u5904\u4e8e up \u72b6\u6001\u7684 kube-apiserver \u3002 nerdctl -n k8s.io ps -a | grep apiserver \u8fd0\u884c\u7ed3\u679c\uff1a 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001","title":"\u505c\u6b62Services"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#etcd_2","text":"nerdctl -n k8s.io ps -a | grep etcd \u8fd0\u884c\u7ed3\u679c\uff1a 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/etcd-cka001 \u505c\u6b62\u90a3\u4e9b\u4ecd\u65e7\u5904\u4e8e up \u72b6\u6001\u7684\u5bb9\u5668\u3002 nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0965b195f41a nerdctl -n k8s.io stop 9e1bea9f25d1 \u76f4\u81f3\u6ca1\u6709\u5904\u4e8e up \u72b6\u6001\u7684 kube-apiserver \u3002 nerdctl -n k8s.io ps -a | grep etcd \u8fd0\u884c\u7ed3\u679c\uff1a 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001","title":"\u505c\u6b62etcd"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#etcd_3","text":"\u5728\u63a7\u5236\u5e73\u9762\u8282\u70b9\u4e0a\u6267\u884c\u6062\u590d\u64cd\u4f5c\uff0c\u4f7f\u7528\u5b9e\u9645\u7684\u5907\u4efd\u6587\u4ef6\uff0c\u8fd9\u91cc\u662f\u6587\u4ef6 snapshot-20220724185121.db \u3002 etcdctl snapshot restore snapshot-20220724185121.db \\ --endpoints = :2379 \\ --cert = /etc/kubernetes/pki/etcd/server.crt \\ --key = /etc/kubernetes/pki/etcd/server.key \\ --cacert = /etc/kubernetes/pki/etcd/ca.crt \\ --data-dir = /var/lib/etcd \u8fd0\u884c\u7ed3\u679c\uff1a Deprecated: Use `etcdutl snapshot restore` instead. 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:248 restoring snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\", \"stack\": \"go.etcd.io/etcd/etcdutl/v3/snapshot.(*v3Manager).Restore\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/snapshot/v3_snapshot.go:254\\ngo.etcd.io/etcd/etcdutl/v3/etcdutl.SnapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/etcdutl/snapshot_command.go:147\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3/command.snapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/command/snapshot_command.go:129\\ngithub.com/spf13/cobra.(*Command).execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856\\ngithub.com/spf13/cobra.(*Command).ExecuteC\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960\\ngithub.com/spf13/cobra.(*Command).Execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:897\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.Start\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:107\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.MustStart\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:111\\nmain.main\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/main.go:59\\nruntime.main\\n\\t/go/gos/go1.16.15/src/runtime/proc.go:225\"} 2022-07-24T18:57:49+08:00 info membership/store.go:141 Trimming membership information from the backend... 2022-07-24T18:57:49+08:00 info membership/cluster.go:421 added member {\"cluster-id\": \"cdf818194e3a8c32\", \"local-member-id\": \"0\", \"added-peer-id\": \"8e9e05c52164694d\", \"added-peer-peer-urls\": [\"http://localhost:2380\"]} 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:269 restored snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\"} \u68c0\u67e5\u88ab\u5220\u9664\u7684 etcd \u76ee\u5f55\u662f\u5426\u5df2\u7ecf\u4ece\u5907\u4efd\u4e2d\u6062\u590d\u4e86\u3002 tree /var/lib/etcd \u8fd0\u884c\u7ed3\u679c\uff1a /var/lib/etcd \u2514\u2500\u2500 member \u251c\u2500\u2500 snap \u2502 \u251c\u2500\u2500 0000000000000001-0000000000000001.snap \u2502 \u2514\u2500\u2500 db \u2514\u2500\u2500 wal \u2514\u2500\u2500 0000000000000000-0000000000000000.wal","title":"\u6062\u590detcd"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#services_1","text":"\u542f\u52a8 kubelet \u3002\u670d\u52a1 kube-apiserver \u548c etcd \u4e5f\u4f1a\u7ee7 kubelet \u542f\u52a8\u540e\u88ab\u81ea\u52a8\u542f\u52a8\u3002 systemctl start kubelet \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u786e\u8ba4\u6240\u6709\u670d\u52a1\u90fd\u5df2\u7ecf\u542f\u52a8\u548c\u6b63\u5e38\u8fd0\u884c\u3002 systemctl status kubelet.service nerdctl -n k8s.io ps -a | grep etcd nerdctl -n k8s.io ps -a | grep apiserver \u67e5\u770b\u5f53\u524d etcd \u7684\u72b6\u6001\u3002 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 3b8f37c87782 registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 6 seconds ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001 fbbbb628a945 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 6 seconds ago Up k8s://kube-system/etcd-cka001 \u67e5\u770b\u5f53\u524d apiserver \u7684\u72b6\u6001\u3002 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 281cf4c6670d registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 14 seconds ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 5ed8295d92da registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 15 seconds ago Up k8s://kube-system/kube-apiserver-cka001 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001","title":"\u542f\u52a8\u670d\u52a1Services"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_1","text":"\u68c0\u67e5\u96c6\u7fa4\u7684\u72b6\u6001\uff0c\u67e5\u770b\u662f\u5426pod app-before-backup \u5b58\u5728\u3002 kubectl get deploy \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE app-before-backup 1/1 1 1 11m","title":"\u9a8c\u8bc1"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_2","text":"\u6f14\u793a\u573a\u666f\uff1a\u96c6\u7fa4\u5347\u7ea7 \u9a71\u9010\u63a7\u5236\u5e73\u9762\u8282\u70b9 \u68c0\u67e5\u5f53\u524d\u53ef\u7528\u7684 kubeadm \u7248\u672c \u5c06 kubeadm \u5347\u7ea7\u5230\u65b0\u7248\u672c \u68c0\u67e5\u5347\u7ea7\u8ba1\u5212 \u5e94\u7528\u5347\u7ea7\u8ba1\u5212\u4ee5\u5347\u7ea7\u5230\u65b0\u7248\u672c \u5347\u7ea7 kubelet \u548c kubectl \u542f\u7528\u63a7\u5236\u5e73\u9762\u8282\u70b9\u8c03\u5ea6 \u9a71\u9010\u5de5\u4f5c\u8282\u70b9 \u5347\u7ea7 kubeadm \u548c kubelet \u542f\u7528\u5de5\u4f5c\u8282\u70b9\u8c03\u5ea6 \u53c2\u8003\uff1a kubeadm\u5347\u7ea7","title":"\u96c6\u7fa4\u5347\u7ea7"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_3","text":"","title":"\u5347\u7ea7\u63a7\u5236\u5e73\u9762"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_4","text":"\u9a71\u9010\u63a7\u5236\u5e73\u9762\u8282\u70b9\u3002 kubectl drain --ignore-daemonsets \u8fd9\u91cc\u662f\uff1a kubectl drain cka001 --ignore-daemonsets \u8fd0\u884c\u7ed3\u679c\uff1a node/cka001 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-dsx76, kube-system/kube-proxy-cm4hc evicting pod kube-system/calico-kube-controllers-5c64b68895-jr4nl evicting pod kube-system/coredns-6d8c4cb4d-g4jxc evicting pod kube-system/coredns-6d8c4cb4d-sqcvj pod/calico-kube-controllers-5c64b68895-jr4nl evicted pod/coredns-6d8c4cb4d-g4jxc evicted pod/coredns-6d8c4cb4d-sqcvj evicted node/cka001 drained \u63a7\u5236\u5e73\u9762\u8282\u70b9\u73b0\u5728\u5904\u4e8e SchedulingDisabled \u72b6\u6001\u3002 kubectl get node -owide \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 \u67e5\u8be2\u5f53\u524d kubeadm \u53ef\u7528\u7248\u672c\u3002 apt policy kubeadm \u8f93\u51fa\u7ed3\u679c\uff1a kubeadm: Installed: 1.24.0-00 Candidate: 1.24.3-00 Version table: 1.24.3-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.1-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages *** 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 100 /var/lib/dpkg/status 1.23.7-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages ...... \u5347\u7ea7 kubeadm \u5230 Candidate: 1.24.2-00 \u7248\u672c\u3002 sudo apt-get -y install kubeadm = 1 .24.2-00 --allow-downgrades \u67e5\u8be2\u5347\u7ea7\u8ba1\u5212\u3002 kubeadm upgrade plan \u8f93\u51fa\u7c7b\u4f3c\u4e0b\u9762\u7684\u5347\u7ea7\u8ba1\u5212\u3002 [upgrade/config] Making sure the configuration is correct: [upgrade/config] Reading configuration from the cluster... [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [preflight] Running pre-flight checks. [upgrade] Running cluster health checks [upgrade] Fetching available versions to upgrade to [upgrade/versions] Cluster version: v1.24.0 [upgrade/versions] kubeadm version: v1.24.2 I0724 19:05:00.111855 1142460 version.go:255] remote version is much newer: v1.24.3; falling back to: stable-1.23 [upgrade/versions] Target version: v1.24.2 [upgrade/versions] Latest version in the v1.23 series: v1.24.2 Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply': COMPONENT CURRENT TARGET kubelet 3 x v1.24.0 v1.24.2 Upgrade to the latest version in the v1.23 series: COMPONENT CURRENT TARGET kube-apiserver v1.24.0 v1.24.2 kube-controller-manager v1.24.0 v1.24.2 kube-scheduler v1.24.0 v1.24.2 kube-proxy v1.24.0 v1.24.2 CoreDNS v1.8.6 v1.8.6 etcd 3.5.1-0 3.5.1-0 You can now apply the upgrade by executing the following command: kubeadm upgrade apply v1.24.2 _____________________________________________________________________ The table below shows the current state of component configs as understood by this version of kubeadm. Configs that have a \"yes\" mark in the \"MANUAL UPGRADE REQUIRED\" column require manual config upgrade or resetting to kubeadm defaults before a successful upgrade can be performed. The version to manually upgrade to is denoted in the \"PREFERRED VERSION\" column. API GROUP CURRENT VERSION PREFERRED VERSION MANUAL UPGRADE REQUIRED kubeproxy.config.k8s.io v1alpha1 v1alpha1 no kubelet.config.k8s.io v1beta1 v1beta1 no _____________________________________________________________________","title":"\u63a7\u5236\u5e73\u9762\u51c6\u5907"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_5","text":"\u53c2\u8003\u524d\u9762\u7684\u5347\u7ea7\u8ba1\u5212\uff0c\u6211\u4eec\u5347\u7ea7\u5230 v1.24.2 \u7248\u672c\u3002 kubeadm upgrade apply v1.24.2 \u901a\u8fc7\u9009\u9879 --etcd-upgrade=false \uff0c\u6211\u4eec\u628a etcd \u6392\u9664\u51fa\u5f53\u524d\u5347\u7ea7\u8303\u56f4\u3002 kubeadm upgrade apply v1.24.2 --etcd-upgrade = false \u6536\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u5219\u4ee3\u8868\u4e0a\u9762\u7684\u5347\u7ea7\u547d\u4ee4\u6210\u529f\u4e86\u3002 [upgrade/successful] SUCCESS! Your cluster was upgraded to \"v1.24.2\". Enjoy! [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so. \u5347\u7ea7 kubelet \u548c kubectl \u3002 sudo apt-get -y install kubelet = 1 .24.2-00 kubectl = 1 .24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet \u67e5\u8be2\u8282\u70b9\u5f53\u524d\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0 After verify that each node is in Ready status, enable node scheduling. \u5728\u786e\u8ba4\u6240\u6709\u8282\u70b9\u90fd\u5904\u4e8eReady\u72b6\u6001\uff0c\u5219\u6fc0\u6d3bscheduling\u3002 kubectl uncordon \u8fd9\u91cc\u662f\uff1a kubectl uncordon cka001 \u8f93\u51fa\u7ed3\u679c\uff1a node/cka001 uncordoned \u518d\u6b21\u68c0\u67e5\u8282\u70b9\u72b6\u6001\uff0c\u786e\u4fdd\u6240\u6709\u8282\u70b9\u90fd\u5904\u4e8eReady\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0","title":"\u63a7\u5236\u5e73\u9762\u5347\u7ea7"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_6","text":"","title":"\u5347\u7ea7\u5de5\u4f5c\u8282\u70b9"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_7","text":"\u767b\u5f55\u8282\u70b9 cka001 \u3002 \u9a71\u9010 Worker \u8282\u70b9\uff0c\u9700\u8981\u663e\u5f0f\u6307\u5b9a\u662f\u5426\u5220\u9664\u672c\u5730\u5b58\u50a8\u3002 kubectl drain --ignore-daemonsets --force kubectl drain --ignore-daemonsets --delete-emptydir-data --force \u5982\u679c\u9047\u5230\u5173\u4e8e emptydir \u4f9d\u8d56\u7684\u9519\u8bef\uff0c\u5219\u6267\u884c\u7b2c\u4e8c\u4e2a\u547d\u4ee4\u3002 kubectl drain cka002 --ignore-daemonsets --force kubectl drain cka002 --ignore-daemonsets --delete-emptydir-data --force \u8f93\u51fa\u7ed3\u679c\uff1a node/cka002 cordoned WARNING: deleting Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet: dev/ubuntu; ignoring DaemonSet-managed Pods: kube-system/calico-node-p5rf2, kube-system/kube-proxy-zvs68 evicting pod ns-netpol/pod-netpol-5b67b6b496-2cgnw evicting pod dev/ubuntu evicting pod dev/app-before-backup-66dc9d5cb-6xc8c evicting pod dev/nfs-client-provisioner-86d7fb78b6-2f5dx evicting pod dev/pod-netpol-2-77478d77ff-l6rzm evicting pod ingress-nginx/ingress-nginx-admission-patch-nk9fv evicting pod ingress-nginx/ingress-nginx-admission-create-lgtdj evicting pod kube-system/coredns-6d8c4cb4d-l4kx4 pod/ingress-nginx-admission-create-lgtdj evicted pod/ingress-nginx-admission-patch-nk9fv evicted pod/nfs-client-provisioner-86d7fb78b6-2f5dx evicted pod/app-before-backup-66dc9d5cb-6xc8c evicted pod/coredns-6d8c4cb4d-l4kx4 evicted pod/pod-netpol-5b67b6b496-2cgnw evicted pod/pod-netpol-2-77478d77ff-l6rzm evicted pod/ubuntu evicted node/cka002 drained","title":"\u5de5\u4f5c\u8282\u70b9\u51c6\u5907"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_8","text":"\u767b\u5f55\u8282\u70b9 cka002 \u3002 \u4e0b\u8f7d kubeadm \u7684 v1.24.2 \u7248\u672c\u3002 sudo apt-get -y install kubeadm = 1 .24.2-00 --allow-downgrades \u5347\u7ea7 kubeadm \u3002 sudo kubeadm upgrade node \u5347\u7ea7 kubelet \u3002 sudo apt-get -y install kubelet = 1 .24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet \u786e\u8ba4\u6240\u6709\u8282\u70b9\u90fd\u5904\u4e8eReady\u72b6\u6001\uff0c\u5219\u6fc0\u6d3bscheduling\u3002 kubectl uncordon \u8fd9\u91cc\u662f\uff1a kubectl uncordon cka002","title":"\u5de5\u4f5c\u8282\u70b9\u5347\u7ea7"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_9","text":"\u67e5\u8be2\u8282\u70b9\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.0 \u5728\u8282\u70b9 cka003 \u4e0a\u91cd\u590d\u4e0a\u9762\u7684\u6b65\u9aa4\u3002 \u767b\u5f55\u8282\u70b9 cka003 \u3002\u5982\u679c\u9047\u5230\u5173\u4e8e emptydir \u4f9d\u8d56\u7684\u9519\u8bef\uff0c\u5219\u6267\u884c\u7b2c\u4e8c\u4e2a\u547d\u4ee4\u3002 kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --force kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --delete-emptydir-data --force \u767b\u5f55\u8282\u70b9 cka003 \uff0c\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u3002 sudo apt-get -y install kubeadm = 1 .24.2-00 --allow-downgrades sudo kubeadm upgrade node sudo apt-get -y install kubelet = 1 .24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet kubectl get node kubectl uncordon cka003 \u67e5\u8be2\u8282\u70b9\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.2","title":"\u5de5\u4f5c\u8282\u70b9\u9a8c\u8bc1"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_10","text":"\u5728\u63a7\u5236\u9762\u677f\u4e0a\u7684\u6267\u884c\u6b65\u9aa4\uff1a kubectl get node -owide kubectl drain cka001 --ignore-daemonsets kubectl get node -owide apt policy kubeadm apt-get -y install kubeadm = 1 .24.0-00 --allow-downgrades kubeadm upgrade plan kubeadm upgrade apply v1.24.0 # kubeadm upgrade apply v1.24.0 --etcd-upgrade=false apt-get -y install kubelet = 1 .24.0-00 kubectl = 1 .24.0-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl get node kubectl uncordon cka001 \u5728\u5de5\u4f5c\u8282\u70b9\u4e0a\u7684\u6267\u884c\u6b65\u9aa4\uff1a \u5728\u63a7\u5236\u9762\u677f\u4e0a\uff1a kubectl drain cka002 --ignore-daemonsets \u5728\u5de5\u4f5c\u8282\u70b9\u4e0a\uff1a apt-get -y install kubeadm = 1 .24.1-00 --allow-downgrades kubeadm upgrade node apt-get -y install kubelet = 1 .24.1-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl uncordon cka002 \u5728\u5176\u4ed6\u5de5\u4f5c\u8282\u70b9\u4e0a\u91cd\u590d\u4e0a\u9762\u7684\u6b65\u9aa4\u3002","title":"\u603b\u7ed3"},{"location":"k8s/cka_cn/foundamentals/configuration/","text":"CKA\u81ea\u5b66\u7b14\u8bb015:Configuration \u00b6","title":"Configuration"},{"location":"k8s/cka_cn/foundamentals/configuration/#cka15configuration","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb015:Configuration"},{"location":"k8s/cka_cn/foundamentals/daemonset/","text":"CKA\u81ea\u5b66\u7b14\u8bb013:DaemonSet \u00b6 \u6f14\u793a\u573a\u666f \u00b6 \u521b\u5efa\u4e00\u4e2aDaemonSet \u521b\u5efa\u7684DaemonSet\u4f1a\u5728\u6bcf\u4e2anode\u8282\u70b9\u4e0a\u8fd0\u884c\u81ea\u5df1\u7684pod\u3002 \u6f14\u793a \u00b6 \u521b\u5efa DaemonSet daemonset-busybox \u3002 kubectl apply -f - << EOF apiVersion: apps/v1 kind: DaemonSet metadata: name: daemonset-busybox labels: app: daemonset-busybox spec: selector: matchLabels: app: daemonset-busybox template: metadata: labels: app: daemonset-busybox spec: tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: busybox image: busybox:1.28 args: - sleep - \"10000\" EOF \u83b7\u53d6DaemonSet\u7684\u8fd0\u884c\u72b6\u6001\u3002 kubectl get daemonsets daemonset-busybox \u8fd0\u884c\u7ed3\u679c NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset-busybox 3 3 3 3 3 5m33s \u83b7\u53d6 DaemonSet \u7684 Pod \u7684\u72b6\u6001\u3002\u8fd9\u4e9bpod\u4f1a\u90e8\u7f72\u5728\u6bcf\u4e2a\u8282\u70b9node\u4e0a\u3002 kubectl get pod -o wide \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES daemonset-busybox-54cj5 1 /1 Running 0 44s 10 .244.102.4 cka003 daemonset-busybox-5tl55 1 /1 Running 0 44s 10 .244.228.197 cka001 daemonset-busybox-wg225 1 /1 Running 0 44s 10 .244.112.5 cka002 \u5220\u9664\u6240\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete daemonset daemonset-busybox","title":"DaemonSet"},{"location":"k8s/cka_cn/foundamentals/daemonset/#cka13daemonset","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb013:DaemonSet"},{"location":"k8s/cka_cn/foundamentals/daemonset/#_1","text":"\u521b\u5efa\u4e00\u4e2aDaemonSet \u521b\u5efa\u7684DaemonSet\u4f1a\u5728\u6bcf\u4e2anode\u8282\u70b9\u4e0a\u8fd0\u884c\u81ea\u5df1\u7684pod\u3002","title":"\u6f14\u793a\u573a\u666f"},{"location":"k8s/cka_cn/foundamentals/daemonset/#_2","text":"\u521b\u5efa DaemonSet daemonset-busybox \u3002 kubectl apply -f - << EOF apiVersion: apps/v1 kind: DaemonSet metadata: name: daemonset-busybox labels: app: daemonset-busybox spec: selector: matchLabels: app: daemonset-busybox template: metadata: labels: app: daemonset-busybox spec: tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: busybox image: busybox:1.28 args: - sleep - \"10000\" EOF \u83b7\u53d6DaemonSet\u7684\u8fd0\u884c\u72b6\u6001\u3002 kubectl get daemonsets daemonset-busybox \u8fd0\u884c\u7ed3\u679c NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset-busybox 3 3 3 3 3 5m33s \u83b7\u53d6 DaemonSet \u7684 Pod \u7684\u72b6\u6001\u3002\u8fd9\u4e9bpod\u4f1a\u90e8\u7f72\u5728\u6bcf\u4e2a\u8282\u70b9node\u4e0a\u3002 kubectl get pod -o wide \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES daemonset-busybox-54cj5 1 /1 Running 0 44s 10 .244.102.4 cka003 daemonset-busybox-5tl55 1 /1 Running 0 44s 10 .244.228.197 cka001 daemonset-busybox-wg225 1 /1 Running 0 44s 10 .244.112.5 cka002 \u5220\u9664\u6240\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete daemonset daemonset-busybox","title":"\u6f14\u793a"},{"location":"k8s/cka_cn/foundamentals/deployment/","text":"CKA\u81ea\u5b66\u7b14\u8bb09:Deployment \u00b6 \u6458\u8981 \u00b6 \u4fee\u6539\u5df2\u6709\u7684Deployment\uff0c\u6bd4\u5982\uff0c\u589e\u52a0\u7aef\u53e3\u53f7\u7b49\u3002 \u6f14\u793a \u00b6 \u521b\u5efaDeployment nginx \u3002 kubectl create deployment nginx --image = nginx \u6267\u884c\u4ee5\u4e0b\u547d\u4ee4\u4ee5\u83b7\u53d6\u5e26\u6709\u7aef\u53e3\u53f7\u7684yaml\u6a21\u677f\u3002 \u9009\u9879 --port=8080 \u6307\u5b9a\u4e86\u8be5\u5bb9\u5668\u66b4\u9732\u7684\u7aef\u53e3\u53f7\u3002 kubectl create deployment nginx --image = nginx --port = 8080 --dry-run = client -o yaml \u8fd9\u6837\u6211\u4eec\u5c31\u77e5\u9053\u4e86\u6dfb\u52a0\u7aef\u53e3\u53f7\u7684\u8def\u5f84\uff0c\u5c31\u50cf\u4e0b\u9762\u8fd9\u6837\uff1a kubectl explain deployment.spec.template.spec.containers.ports.containerPort \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u6765\u4fee\u6539\u5f53\u524d\u6b63\u5728\u8fd0\u884c\u7684Deployment\u3002 kubectl edit deployment nginx \u6dfb\u52a0\u4e0b\u97622\u884c\u6765\u5236\u5b9a 8080 \u7aef\u53e3\u548c TCP \u534f\u8bae\u3002 spec : template : spec : containers : - image : nginx name : nginx ports : - containerPort : 8080 protocol : TCP \u901a\u8fc7\u547d\u4ee4 kubectl describe deployment \u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5728Deployment\u4e2d\u7aef\u53e3\u53f7\u548c\u534f\u8bae\u5df2\u7ecf\u88ab\u6b63\u786e\u6dfb\u52a0\u4e86\u3002 Pod Template : Labels : app=nginx Containers : nginx : Image : nginx Port : 8080/TCP Host Port : 0/TCP Environment : Mounts : Volumes : \u901a\u8fc7\u547d\u4ee4 kubectl describe pod \u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5728pod\u4e2d\u7aef\u53e3\u53f7\u548c\u534f\u8bae\u5df2\u7ecf\u88ab\u6b63\u786e\u6dfb\u52a0\u4e86\u3002 Containers : nginx : Container ID : containerd://af4a1243f981497074b5c006ac55fcf795688399871d1dfe91a095321f5c91aa Image : nginx Image ID : docker.io/library/nginx@sha256:1761fb5661e4d77e107427d8012ad3a5955007d997e0f4a3d41acc9ff20467c7 Port : 8080/TCP Host Port : 0/TCP State : Running Started : Sun, 24 Jul 2022 22:50:12 +0800 Ready : True Restart Count : 0 Environment : Mounts : /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hftdt (ro) \u4ee5\u4e0b\u662fDeployment\u7684\u4e00\u4e9b\u5173\u952e\u5b57\u6bb5\uff08\u4f7f\u7528 kubectl explain \uff09\uff1a deployment.spec.revisionHistoryLimit \uff1a\u4fdd\u7559\u65e7\u7684 ReplicaSets \u7684\u6570\u91cf\uff0c\u4ee5\u4fbf\u8fdb\u884c\u56de\u6eda\u3002\u9ed8\u8ba4\u4e3a 10 \u3002 deployment.spec.strategy.type \uff1a\u90e8\u7f72\u7684\u7c7b\u578b\u3002\u53ef\u4ee5\u662f Recreate \u6216 RollingUpdate \u3002\u9ed8\u8ba4\u4e3a RollingUpdate \u3002 deployment.spec.strategy.rollingUpdate.maxUnavailable \uff1a\u5728\u66f4\u65b0\u671f\u95f4\u53ef\u4ee5\u4e0d\u53ef\u7528\u7684Pod\u7684\u6700\u5927\u6570\u91cf\u3002\u9ed8\u8ba4\u4e3a 25\uff05 \u3002 deployment.spec.strategy.rollingUpdate.maxSurge \uff1a\u53ef\u4ee5\u5b89\u6392\u7684Pod\u6570\u91cf\u8d85\u51fa\u6240\u9700Pod\u6570\u91cf\u7684\u6700\u5927\u503c\u3002\u9ed8\u8ba4\u4e3a 25\uff05 \u3002\u5982\u679c MaxUnavailable \u4e3a 0 \uff0c\u5219\u6b64\u503c\u4e0d\u80fd\u4e3a 0 \u3002 deployment.spec.minReadySeconds \uff1a\u65b0\u521b\u5efa\u7684Pod\u7684\u6700\u5c0f\u51c6\u5907\u65f6\u95f4\uff08\u6240\u6709\u5bb9\u5668\u90fd\u6ca1\u6709\u5d29\u6e83\uff09\uff0c\u4ee5\u4fbf\u88ab\u89c6\u4e3a\u53ef\u7528\u3002\u9ed8\u8ba4\u4e3a 0 \uff08\u4e00\u65e6\u51c6\u5907\u597d\u5c31\u4f1a\u88ab\u89c6\u4e3a\u53ef\u7528\uff09\u3002","title":"Deployment"},{"location":"k8s/cka_cn/foundamentals/deployment/#cka9deployment","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb09:Deployment"},{"location":"k8s/cka_cn/foundamentals/deployment/#_1","text":"\u4fee\u6539\u5df2\u6709\u7684Deployment\uff0c\u6bd4\u5982\uff0c\u589e\u52a0\u7aef\u53e3\u53f7\u7b49\u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/deployment/#_2","text":"\u521b\u5efaDeployment nginx \u3002 kubectl create deployment nginx --image = nginx \u6267\u884c\u4ee5\u4e0b\u547d\u4ee4\u4ee5\u83b7\u53d6\u5e26\u6709\u7aef\u53e3\u53f7\u7684yaml\u6a21\u677f\u3002 \u9009\u9879 --port=8080 \u6307\u5b9a\u4e86\u8be5\u5bb9\u5668\u66b4\u9732\u7684\u7aef\u53e3\u53f7\u3002 kubectl create deployment nginx --image = nginx --port = 8080 --dry-run = client -o yaml \u8fd9\u6837\u6211\u4eec\u5c31\u77e5\u9053\u4e86\u6dfb\u52a0\u7aef\u53e3\u53f7\u7684\u8def\u5f84\uff0c\u5c31\u50cf\u4e0b\u9762\u8fd9\u6837\uff1a kubectl explain deployment.spec.template.spec.containers.ports.containerPort \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u6765\u4fee\u6539\u5f53\u524d\u6b63\u5728\u8fd0\u884c\u7684Deployment\u3002 kubectl edit deployment nginx \u6dfb\u52a0\u4e0b\u97622\u884c\u6765\u5236\u5b9a 8080 \u7aef\u53e3\u548c TCP \u534f\u8bae\u3002 spec : template : spec : containers : - image : nginx name : nginx ports : - containerPort : 8080 protocol : TCP \u901a\u8fc7\u547d\u4ee4 kubectl describe deployment \u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5728Deployment\u4e2d\u7aef\u53e3\u53f7\u548c\u534f\u8bae\u5df2\u7ecf\u88ab\u6b63\u786e\u6dfb\u52a0\u4e86\u3002 Pod Template : Labels : app=nginx Containers : nginx : Image : nginx Port : 8080/TCP Host Port : 0/TCP Environment : Mounts : Volumes : \u901a\u8fc7\u547d\u4ee4 kubectl describe pod \u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5728pod\u4e2d\u7aef\u53e3\u53f7\u548c\u534f\u8bae\u5df2\u7ecf\u88ab\u6b63\u786e\u6dfb\u52a0\u4e86\u3002 Containers : nginx : Container ID : containerd://af4a1243f981497074b5c006ac55fcf795688399871d1dfe91a095321f5c91aa Image : nginx Image ID : docker.io/library/nginx@sha256:1761fb5661e4d77e107427d8012ad3a5955007d997e0f4a3d41acc9ff20467c7 Port : 8080/TCP Host Port : 0/TCP State : Running Started : Sun, 24 Jul 2022 22:50:12 +0800 Ready : True Restart Count : 0 Environment : Mounts : /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hftdt (ro) \u4ee5\u4e0b\u662fDeployment\u7684\u4e00\u4e9b\u5173\u952e\u5b57\u6bb5\uff08\u4f7f\u7528 kubectl explain \uff09\uff1a deployment.spec.revisionHistoryLimit \uff1a\u4fdd\u7559\u65e7\u7684 ReplicaSets \u7684\u6570\u91cf\uff0c\u4ee5\u4fbf\u8fdb\u884c\u56de\u6eda\u3002\u9ed8\u8ba4\u4e3a 10 \u3002 deployment.spec.strategy.type \uff1a\u90e8\u7f72\u7684\u7c7b\u578b\u3002\u53ef\u4ee5\u662f Recreate \u6216 RollingUpdate \u3002\u9ed8\u8ba4\u4e3a RollingUpdate \u3002 deployment.spec.strategy.rollingUpdate.maxUnavailable \uff1a\u5728\u66f4\u65b0\u671f\u95f4\u53ef\u4ee5\u4e0d\u53ef\u7528\u7684Pod\u7684\u6700\u5927\u6570\u91cf\u3002\u9ed8\u8ba4\u4e3a 25\uff05 \u3002 deployment.spec.strategy.rollingUpdate.maxSurge \uff1a\u53ef\u4ee5\u5b89\u6392\u7684Pod\u6570\u91cf\u8d85\u51fa\u6240\u9700Pod\u6570\u91cf\u7684\u6700\u5927\u503c\u3002\u9ed8\u8ba4\u4e3a 25\uff05 \u3002\u5982\u679c MaxUnavailable \u4e3a 0 \uff0c\u5219\u6b64\u503c\u4e0d\u80fd\u4e3a 0 \u3002 deployment.spec.minReadySeconds \uff1a\u65b0\u521b\u5efa\u7684Pod\u7684\u6700\u5c0f\u51c6\u5907\u65f6\u95f4\uff08\u6240\u6709\u5bb9\u5668\u90fd\u6ca1\u6709\u5d29\u6e83\uff09\uff0c\u4ee5\u4fbf\u88ab\u89c6\u4e3a\u53ef\u7528\u3002\u9ed8\u8ba4\u4e3a 0 \uff08\u4e00\u65e6\u51c6\u5907\u597d\u5c31\u4f1a\u88ab\u89c6\u4e3a\u53ef\u7528\uff09\u3002","title":"\u6f14\u793a"},{"location":"k8s/cka_cn/foundamentals/docker/","text":"CKA\u81ea\u5b66\u7b14\u8bb04:Docker\u57fa\u7840 \u00b6 \u6458\u8981 \u00b6 \u4e86\u89e3Linux\u539f\u8bed\u7684\u6982\u5ff5\u548c\u5305\u542b\u7684\u7279\u6027\u3002 \u5b89\u88c5Docker\uff0c\u4e86\u89e3\u57fa\u672c\u7684Docker\u547d\u4ee4\u548cDockerfile\u7684\u4f7f\u7528\u3002 \u7ec3\u4e60\u73af\u5883 \u00b6 \u64cd\u4f5c\u7cfb\u7edf\uff1aopenSUSE 15.3 cat /etc/os-release \u8f93\u51fa\u7ed3\u679c\uff1a NAME=\"openSUSE Leap\" VERSION=\"15.3\" ID=\"opensuse-leap\" ID_LIKE=\"suse opensuse\" VERSION_ID=\"15.3\" PRETTY_NAME=\"openSUSE Leap 15.3\" ANSI_COLOR=\"0;32\" CPE_NAME=\"cpe:/o:opensuse:leap:15.3\" BUG_REPORT_URL=\"https://bugs.opensuse.org\" HOME_URL=\"https://www.opensuse.org/\" Linux\u539f\u8bed \u00b6 \u5728\u64cd\u4f5c\u7cfb\u7edf\u4e2d\uff0c\u539f\u8bed\uff08primitives\uff09\u662f\u7528\u4e8e\u521b\u5efa\u66f4\u590d\u6742\u529f\u80fd\u7684\u57fa\u672c\u6784\u5efa\u5757\u6216\u64cd\u4f5c\u3002\u5728Linux\u4e2d\uff0c\u6709\u51e0\u79cd\u5e38\u7528\u7684\u539f\u8bed\u3002\u5305\u62ec\uff1a \u8fdb\u7a0b\uff08Processes\uff09\uff1a\u8fdb\u7a0b\u662f\u7a0b\u5e8f\u6216\u5e94\u7528\u7a0b\u5e8f\u7684\u8fd0\u884c\u5b9e\u4f8b\u3002\u5b83\u4eec\u662fLinux\u4e2d\u7684\u57fa\u672c\u5de5\u4f5c\u5355\u5143\uff0c\u7531\u5185\u6838\u7ba1\u7406\u3002 \u6587\u4ef6\uff08Files\uff09\uff1a\u6587\u4ef6\u662f\u5728Linux\u4e2d\u5b58\u50a8\u6570\u636e\u7684\u4e3b\u8981\u65b9\u5f0f\u3002\u5b83\u4eec\u53ef\u4ee5\u662f\u6587\u672c\u6587\u4ef6\u3001\u4e8c\u8fdb\u5236\u6587\u4ef6\u3001\u76ee\u5f55\u6216\u7279\u6b8a\u6587\u4ef6\uff0c\u5982\u8bbe\u5907\u6587\u4ef6\u3002 \u4fe1\u53f7\uff08Signals\uff09\uff1a\u4fe1\u53f7\u662f\u8fdb\u7a0b\u4e4b\u95f4\u6216\u8fdb\u7a0b\u4e0e\u5185\u6838\u4e4b\u95f4\u901a\u4fe1\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u5b83\u4eec\u7528\u4e8e\u901a\u77e5\u8fdb\u7a0b\u4e8b\u4ef6\uff0c\u4f8b\u5982\u4efb\u52a1\u5b8c\u6210\u6216\u9519\u8bef\u53d1\u751f\u7684\u60c5\u51b5\u3002 \u5957\u63a5\u5b57\uff08Sockets\uff09\uff1a\u5957\u63a5\u5b57\u662fLinux\u4e2d\u8fdb\u7a0b\u95f4\u901a\u4fe1\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u5b83\u4eec\u5141\u8bb8\u8fdb\u7a0b\u5728\u7f51\u7edc\u6216\u672c\u5730\u673a\u5668\u4e0a\u53d1\u9001\u548c\u63a5\u6536\u6570\u636e\u3002 \u7ebf\u7a0b\uff08Threads\uff09\uff1a\u7ebf\u7a0b\u662f\u8f7b\u91cf\u7ea7\u7684\u8fdb\u7a0b\uff0c\u4e0e\u5176\u7236\u8fdb\u7a0b\u5171\u4eab\u76f8\u540c\u7684\u5185\u5b58\u7a7a\u95f4\u548c\u8d44\u6e90\u3002\u5b83\u4eec\u901a\u5e38\u7528\u4e8e\u901a\u8fc7\u5141\u8bb8\u540c\u65f6\u6267\u884c\u591a\u4e2a\u4efb\u52a1\u6765\u63d0\u9ad8\u5e94\u7528\u7a0b\u5e8f\u7684\u6027\u80fd\u3002 \u7ba1\u9053\uff08Pipes\uff09\uff1a\u7ba1\u9053\u662f\u4e00\u79cd\u5c06\u4e00\u4e2a\u8fdb\u7a0b\u7684\u8f93\u51fa\u8fde\u63a5\u5230\u53e6\u4e00\u4e2a\u8fdb\u7a0b\u7684\u8f93\u5165\u7684\u65b9\u5f0f\u3002\u5b83\u4eec\u5141\u8bb8\u8fdb\u7a0b\u4ee5\u53d7\u63a7\u7684\u65b9\u5f0f\u8fdb\u884c\u901a\u4fe1\u548c\u4ea4\u6362\u6570\u636e\u3002 \u4fe1\u53f7\u91cf\uff08Semaphores\uff09\uff1a\u4fe1\u53f7\u91cf\u662fLinux\u4e2d\u63a7\u5236\u5bf9\u5171\u4eab\u8d44\u6e90\u8bbf\u95ee\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u5b83\u4eec\u5141\u8bb8\u8fdb\u7a0b\u534f\u8c03\u5b83\u4eec\u5bf9\u5171\u4eab\u8d44\u6e90\u7684\u8bbf\u95ee\uff0c\u5982\u6587\u4ef6\u6216\u5185\u5b58\u3002 chroot \u00b6 chroot\u4f7f\u7528pivot_root\uff0c\u4ee5\u5b9e\u73b0\u5c06*\u8fdb\u7a0b*\u7684\u6839\u76ee\u5f55\u66f4\u6539\u4e3a\u4efb\u4f55\u7ed9\u5b9a\u7684\u76ee\u5f55\u3002 a. \u6a21\u62df\u5bb9\u5668 \u4f7f\u7528 chroot \u547d\u4ee4\u53ef\u4ee5\u5728Linux\u7cfb\u7edf\u4e2d\u521b\u5efa\u4e00\u4e2a\u5bb9\u5668\u3002\u8be5\u5bb9\u5668\u53ef\u4ee5\u770b\u4f5c\u662f\u4e00\u4e2a\u865a\u62df\u7684\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u5176\u4e2d\u8fd0\u884c\u7684\u8fdb\u7a0b\u53ea\u80fd\u8bbf\u95ee\u8be5\u6839\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u8d44\u6e90\u3002 \u4f8b\u5982\uff0c\u4ee5\u4e0b\u547d\u4ee4\u4f1a\u5c06\u5f53\u524d\u6839\u6587\u4ef6\u7cfb\u7edf\u66f4\u6539\u4e3a /tmp/myroot \u76ee\u5f55\uff1a chroot /tmp/myroot /bin/bash \u8fd9\u6761\u547d\u4ee4\u4f1a\u542f\u52a8\u4e00\u4e2a\u65b0\u7684Bash shell\uff0c\u8be5shell\u7684\u6839\u76ee\u5f55\u4e3a /tmp/myroot \u3002 b. \u66f4\u6539\u6839\u6587\u4ef6\u7cfb\u7edf chroot \u547d\u4ee4\u8fd8\u53ef\u7528\u4e8e\u66f4\u6539\u8fdb\u7a0b\u7684\u6839\u6587\u4ef6\u7cfb\u7edf\u3002\u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 chroot \u547d\u4ee4\u542f\u52a8\u4e00\u4e2a\u5177\u6709\u53e6\u4e00\u4e2a\u6839\u6587\u4ef6\u7cfb\u7edf\u7684\u8fdb\u7a0b\uff0c\u800c\u4e0d\u662f\u7cfb\u7edf\u7684\u9ed8\u8ba4\u6839\u6587\u4ef6\u7cfb\u7edf\u3002 \u4f8b\u5982\uff0c\u4ee5\u4e0b\u547d\u4ee4\u4f1a\u5c06\u5f53\u524d\u76ee\u5f55\uff08\u5373 ./ \uff09\u4f5c\u4e3a\u6839\u76ee\u5f55\uff0c\u5e76\u5728\u5176\u4e2d\u542f\u52a8\u4e00\u4e2a\u65b0\u7684Bash shell\uff1a sudo chroot . /bin/bash \u547d\u540d\u7a7a\u95f4 \u00b6 \u5728Linux\u64cd\u4f5c\u7cfb\u7edf\u4e2d\uff0cNamespace\uff08\u547d\u540d\u7a7a\u95f4\uff09\u662f\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u9694\u79bb\u4e0d\u540c\u8fdb\u7a0b\u7684\u8d44\u6e90\u3002\u901a\u8fc7Namespace\u673a\u5236\uff0c\u53ef\u4ee5\u5c06\u4e00\u7ec4\u8fdb\u7a0b\u53ca\u5176\u5b50\u8fdb\u7a0b\u7684\u89c6\u56fe\u9694\u79bb\u5728\u4e00\u4e2a\u72ec\u7acb\u7684Namespace\u4e2d\uff0c\u4ece\u800c\u5b9e\u73b0\u8fdb\u7a0b\u4e4b\u95f4\u8d44\u6e90\u9694\u79bb\u7684\u76ee\u7684\u3002 \u4e0b\u9762\u662f\u4e00\u4e9b\u5e38\u89c1\u7684Namespace\u7c7b\u578b\u53ca\u5176\u4f5c\u7528\uff1a Mount Namespace\uff1a\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\u6302\u8f7d\u70b9\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u3002 PID Namespace\uff1a\u9694\u79bb\u8fdb\u7a0bID\u53f7\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u8fdb\u7a0bID\u53f7\u7a7a\u95f4\uff0c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684PID\u51b2\u7a81\u3002 Network Namespace\uff1a\u9694\u79bb\u7f51\u7edc\u6808\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u7f51\u7edc\u6808\uff0c\u4ece\u800c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684\u7f51\u7edc\u51b2\u7a81\u3002 IPC Namespace\uff1a\u9694\u79bb\u8fdb\u7a0b\u95f4\u901a\u4fe1\uff08IPC\uff09\u673a\u5236\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684IPC\u7a7a\u95f4\uff0c\u4ece\u800c\u907f\u514dIPC\u673a\u5236\u5e26\u6765\u7684\u8d44\u6e90\u7ade\u4e89\u3002 UTS Namespace\uff1a\u9694\u79bb\u4e3b\u673a\u540d\u548c\u57df\u540d\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u4e3b\u673a\u540d\u548c\u57df\u540d\u7a7a\u95f4\uff0c\u4ece\u800c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684\u547d\u540d\u51b2\u7a81\u3002 Primitives namespace\u548cNamespace\u662f\u4e24\u4e2a\u4e0d\u540c\u7684\u6982\u5ff5\u3002 Namespace\u662fLinux\u64cd\u4f5c\u7cfb\u7edf\u63d0\u4f9b\u7684\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u9694\u79bb\u4e0d\u540c\u8fdb\u7a0b\u7684\u8d44\u6e90\uff0c\u4ee5\u5b9e\u73b0\u8fdb\u7a0b\u4e4b\u95f4\u7684\u8d44\u6e90\u9694\u79bb\u548c\u73af\u5883\u9694\u79bb\u3002\u4f8b\u5982\uff0cPID Namespace\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684PID\u53f7\u7a7a\u95f4\uff0c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684PID\u51b2\u7a81\uff1bNetwork Namespace\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u7f51\u7edc\u6808\uff0c\u4ece\u800c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684\u7f51\u7edc\u51b2\u7a81\u7b49\u3002 Primitives namespace\u662f\u4e00\u79cd\u65b0\u7684\u6280\u672f\u6982\u5ff5\uff0c\u5b83\u662f\u6307\u5c06\u4e0d\u540c\u7684\u57fa\u672c\u64cd\u4f5c\uff08\u4f8b\u5982\u8bfb\u5199\u6587\u4ef6\u3001\u521b\u5efa\u8fdb\u7a0b\u3001\u7f51\u7edc\u901a\u4fe1\u7b49\uff09\u4f5c\u4e3a\u539f\u8bed\u8fdb\u884c\u9694\u79bb\u548c\u5c01\u88c5\uff0c\u4f7f\u5f97\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u5728\u8fd9\u4e9b\u9694\u79bb\u7684\u539f\u8bed\u4e0a\u6784\u5efa\u51fa\u81ea\u5df1\u7684\u9694\u79bb\u73af\u5883\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u901a\u8fc7\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\u8bfb\u5199\u64cd\u4f5c\u6765\u5b9e\u73b0\u5bb9\u5668\u7ea7\u522b\u7684\u6587\u4ef6\u7cfb\u7edf\u9694\u79bb\uff1b\u901a\u8fc7\u9694\u79bb\u7f51\u7edc\u901a\u4fe1\u64cd\u4f5c\u6765\u5b9e\u73b0\u5bb9\u5668\u7ea7\u522b\u7684\u7f51\u7edc\u9694\u79bb\u7b49\u3002 \u56e0\u6b64\uff0cNamespace\u548cPrimitives namespace\u662f\u4e24\u4e2a\u4e0d\u540c\u7684\u6982\u5ff5\uff0c\u867d\u7136\u5b83\u4eec\u90fd\u53ef\u4ee5\u7528\u4e8e\u5b9e\u73b0\u9694\u79bb\u548c\u5c01\u88c5\u7684\u529f\u80fd\uff0c\u4f46\u662fNamespace\u662f\u4e00\u79cd\u66f4\u4e3a\u901a\u7528\u548c\u5e95\u5c42\u7684\u673a\u5236\uff0cPrimitives namespace\u662f\u4e00\u79cd\u66f4\u4e3a\u9ad8\u5c42\u7684\u62bd\u8c61\u6982\u5ff5\uff0c\u901a\u5e38\u7528\u4e8e\u6784\u5efa\u5bb9\u5668\u7b49\u5e94\u7528\u7ea7\u522b\u7684\u9694\u79bb\u73af\u5883\u3002 Namespace\u793a\u4f8b\uff1a \u5728Linux\u7cfb\u7edf\u4e2d\uff0c\u53ef\u4ee5\u4f7f\u7528PID Namespace\u6765\u9694\u79bb\u8fdb\u7a0bID\u53f7\u7a7a\u95f4\uff0c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684PID\u51b2\u7a81\u3002\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\uff1a # \u521b\u5efa\u4e00\u4e2a\u65b0\u7684PID Namespace unshare -p /bin/bash # \u5728\u65b0\u7684PID Namespace\u4e2d\u8fd0\u884c\u4e00\u4e2a\u8fdb\u7a0b echo $$ # \u663e\u793a\u5f53\u524d\u8fdb\u7a0b\u7684PID ps aux # \u663e\u793a\u5f53\u524d\u8fdb\u7a0b\u53ca\u5176\u5b50\u8fdb\u7a0b \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c unshare -p \u547d\u4ee4\u521b\u5efa\u4e86\u4e00\u4e2a\u65b0\u7684PID Namespace\uff0c\u5e76\u5728\u5176\u4e2d\u542f\u52a8\u4e86\u4e00\u4e2a\u65b0\u7684bash\u8fdb\u7a0b\u3002\u7531\u4e8e\u8be5\u8fdb\u7a0b\u8fd0\u884c\u5728\u4e00\u4e2a\u72ec\u7acb\u7684PID Namespace\u4e2d\uff0c\u56e0\u6b64\u5b83\u7684PID\u53f7\u4e0e\u4e3b\u673a\u4e0a\u7684\u5176\u4ed6\u8fdb\u7a0b\u4e0d\u4f1a\u51b2\u7a81\u3002\u5728\u8fd9\u4e2a\u65b0\u7684bash\u8fdb\u7a0b\u4e2d\uff0c $$ \u547d\u4ee4\u663e\u793a\u7684\u662f\u8be5\u8fdb\u7a0b\u5728PID Namespace\u4e2d\u7684PID\u53f7\uff0c\u800c ps aux \u547d\u4ee4\u53ea\u4f1a\u663e\u793a\u5f53\u524dPID Namespace\u4e2d\u7684\u8fdb\u7a0b\uff0c\u4e0d\u4f1a\u663e\u793a\u4e3b\u673a\u4e0a\u7684\u5176\u4ed6\u8fdb\u7a0b\u3002 Primitives Namespace\u793a\u4f8b\uff1a \u5728Docker\u5bb9\u5668\u4e2d\uff0c\u53ef\u4ee5\u4f7f\u7528Filesystem Namespace\u6765\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\uff0c\u4f7f\u5f97\u4e0d\u540c\u7684\u5bb9\u5668\u4e4b\u95f4\u62e5\u6709\u72ec\u7acb\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u3002\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\uff1a # \u5728\u5bb9\u5668\u4e2d\u8fd0\u884c\u4e00\u4e2a\u547d\u4ee4 docker run --rm -it --name mycontainer ubuntu bash # \u5728\u5bb9\u5668\u4e2d\u521b\u5efa\u4e00\u4e2a\u6587\u4ef6\u5e76\u9000\u51fa touch myfile exit # \u5728\u4e3b\u673a\u4e0a\u67e5\u770b\u6587\u4ef6 ls myfile # myfile\u6587\u4ef6\u4e0d\u5b58\u5728 # \u518d\u6b21\u8fdb\u5165\u5bb9\u5668 docker start -i mycontainer # \u5728\u5bb9\u5668\u4e2d\u67e5\u770b\u6587\u4ef6 ls myfile # myfile\u6587\u4ef6\u5b58\u5728 \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c docker run \u547d\u4ee4\u542f\u52a8\u4e86\u4e00\u4e2a\u65b0\u7684Docker\u5bb9\u5668\uff0c\u5e76\u5728\u5176\u4e2d\u8fd0\u884c\u4e86\u4e00\u4e2abash\u8fdb\u7a0b\u3002\u7531\u4e8e\u8be5\u5bb9\u5668\u4f7f\u7528\u4e86Filesystem Namespace\uff0c\u56e0\u6b64\u5bb9\u5668\u5185\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u4e0e\u4e3b\u673a\u4e0a\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u662f\u9694\u79bb\u7684\u3002\u5728\u5bb9\u5668\u5185\u521b\u5efa\u7684\u6587\u4ef6 myfile \u53ea\u5b58\u5728\u4e8e\u5bb9\u5668\u5185\u90e8\uff0c\u5728\u4e3b\u673a\u4e0a\u662f\u770b\u4e0d\u5230\u7684\u3002\u5f53\u518d\u6b21\u8fdb\u5165\u5bb9\u5668\u65f6\uff0c myfile \u6587\u4ef6\u5c31\u53ef\u4ee5\u88ab\u770b\u5230\u4e86\u3002 \u603b\u7ed3\uff1a Namespace\u662fLinux\u5185\u6838\u63d0\u4f9b\u7684\u673a\u5236\uff0c\u800cPrimitives Namespace\u5219\u662f\u4e00\u79cd\u57fa\u4e8eNamespace\u7684\u9ad8\u5c42\u62bd\u8c61\uff0c\u7528\u4e8e\u5b9e\u73b0\u5e94\u7528\u7ea7\u522b\u7684\u9694\u79bb\u548c\u5c01\u88c5\u3002Namespace\u53ef\u4ee5\u7528\u4e8e\u9694\u79bb\u591a\u79cd\u8d44\u6e90\uff0c\u800cPrimitives Namespace\u901a\u5e38\u7528\u4e8e\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\u3001\u7f51\u7edc\u3001\u8fdb\u7a0b\u7b49\u64cd\u4f5c\u7684\u539f\u8bed\u3002 \u63a7\u5236\u7ec4 \u00b6 cgroup\uff0c\u5168\u79f0\u4e3aControl Group\uff0c\u5373\u63a7\u5236\u7ec4\uff0c\u662fLinux\u5185\u6838\u63d0\u4f9b\u7684\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u9650\u5236\u3001\u8bb0\u5f55\u3001\u9694\u79bb\u548c\u4f18\u5148\u7ea7\u63a7\u5236\u4e00\u7ec4\u8fdb\u7a0b\u7684\u8d44\u6e90\u4f7f\u7528\u3002\u5b83\u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7ec4\u7684CPU\u3001\u5185\u5b58\u3001\u78c1\u76d8\u3001\u7f51\u7edc\u7b49\u8d44\u6e90\u7684\u4f7f\u7528\uff0c\u540c\u65f6\u4e5f\u53ef\u4ee5\u8bb0\u5f55\u8fdb\u7a0b\u7ec4\u7684\u8d44\u6e90\u4f7f\u7528\u60c5\u51b5\u548c\u884c\u4e3a\u3002 cgroup\u901a\u8fc7\u5c06\u4e00\u7ec4\u8fdb\u7a0b\u7ec4\u7ec7\u6210\u4e00\u4e2a\u5c42\u6b21\u7ed3\u6784\uff0c\u5c06\u8d44\u6e90\u5206\u914d\u7ed9\u4e0d\u540c\u7684cgroup\u6765\u5b9e\u73b0\u8d44\u6e90\u9650\u5236\u548c\u4f18\u5148\u7ea7\u63a7\u5236\u3002\u6bcf\u4e2acgroup\u53ef\u4ee5\u8bbe\u7f6e\u8d44\u6e90\u9650\u5236\u548c\u63a7\u5236\u7b56\u7565\uff0c\u4f8b\u5982\u53ef\u4ee5\u9650\u5236\u4e00\u4e2a\u8fdb\u7a0b\u7ec4\u6700\u591a\u4f7f\u752850%\u7684CPU\u65f6\u95f4\uff0c\u6216\u8005\u9650\u5236\u4e00\u4e2a\u8fdb\u7a0b\u7ec4\u6700\u591a\u4f7f\u7528100MB\u7684\u5185\u5b58\u7b49\u3002 cgroup\u6700\u521d\u7531Google\u516c\u53f8\u5f00\u53d1\uff0c\u540e\u6765\u88abLinux\u5185\u6838\u793e\u533a\u91c7\u7eb3\u5e76\u52a0\u5165\u5230\u5185\u6838\u4e2d\uff0c\u6210\u4e3aLinux\u7cfb\u7edf\u7684\u4e00\u90e8\u5206\u3002\u5b83\u5728\u5bb9\u5668\u6280\u672f\u3001\u865a\u62df\u5316\u3001\u4e91\u8ba1\u7b97\u7b49\u9886\u57df\u90fd\u6709\u5e7f\u6cdb\u7684\u5e94\u7528\u3002 \u4e0b\u9762\u662fcgroup \u7684\u4e00\u4e9b\u5e38\u89c1\u7528\u9014\uff1a CPU \u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684 CPU \u4f7f\u7528\u7387\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684 CPU \u8d44\u6e90\u5bfc\u81f4\u7cfb\u7edf\u8d1f\u8f7d\u8fc7\u9ad8\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u7a33\u5b9a\u6027\u548c\u5176\u4ed6\u8fdb\u7a0b\u7684\u6b63\u5e38\u8fd0\u884c\u3002 \u5185\u5b58\u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684\u5185\u5b58\u4f7f\u7528\u91cf\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684\u5185\u5b58\u8d44\u6e90\u5bfc\u81f4\u7cfb\u7edf\u5185\u5b58\u4e0d\u8db3\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u6027\u80fd\u548c\u5176\u4ed6\u8fdb\u7a0b\u7684\u6b63\u5e38\u8fd0\u884c\u3002 IO \u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684 IO \u5e26\u5bbd\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684 IO \u8d44\u6e90\u5bfc\u81f4\u5176\u4ed6\u8fdb\u7a0b\u7684 IO \u64cd\u4f5c\u53d7\u5230\u5f71\u54cd\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u6027\u80fd\u548c\u54cd\u5e94\u901f\u5ea6\u3002 \u7f51\u7edc\u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684\u7f51\u7edc\u5e26\u5bbd\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684\u7f51\u7edc\u8d44\u6e90\u5bfc\u81f4\u7f51\u7edc\u62e5\u585e\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u6027\u80fd\u548c\u5176\u4ed6\u8fdb\u7a0b\u7684\u6b63\u5e38\u8fd0\u884c\u3002 \u8fdb\u7a0b\u63a7\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684\u542f\u52a8\u3001\u505c\u6b62\u548c\u8c03\u5ea6\u7b49\u884c\u4e3a\uff0c\u4ece\u800c\u5b9e\u73b0\u5bf9\u7cfb\u7edf\u8fdb\u7a0b\u7684\u63a7\u5236\u548c\u7ba1\u7406\u3002 \u8d44\u6e90\u7edf\u8ba1\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u5b9e\u65f6\u7edf\u8ba1\u7cfb\u7edf\u4e2d\u5404\u4e2a\u8fdb\u7a0b\u7684\u8d44\u6e90\u4f7f\u7528\u60c5\u51b5\uff0c\u4ece\u800c\u5e2e\u52a9\u7ba1\u7406\u5458\u4e86\u89e3\u7cfb\u7edf\u8d1f\u8f7d\u72b6\u51b5\u548c\u5404\u4e2a\u8fdb\u7a0b\u7684\u6027\u80fd\u74f6\u9888\uff0c\u4ece\u800c\u91c7\u53d6\u76f8\u5e94\u7684\u63aa\u65bd\u4f18\u5316\u7cfb\u7edf\u6027\u80fd\u3002 \u4e0b\u9762\u662fopenSUSE\u4e2d\u7684\u793a\u4f8b\uff1a \u5b89\u88c5\u9700\u8981\u7684\u8f6f\u4ef6\u5305\uff1a sudo zypper install libcgroup-tools \u9650\u5236CPU\u4f7f\u7528\u4e0a\u9650\uff1a # \u521b\u5efa\u65b0\u7684cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/cpu/mygroup # \u7cfb\u7edf\u4f1a\u521b\u5efa\u9ed8\u8ba4\u7684\u4e00\u4e9b\u6587\u4ef6\uff0c\u542b\u521d\u59cb\u503c\uff0c\u6bd4\u5982CPU\u4f7f\u7528\u65f6\u95f4\u7684\u9650\u989d\u7684\u9ed8\u8ba4\u503c\u662f-1 cat /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us # \u8bbe\u5b9aCPU\u4f7f\u7528\u65f6\u95f4\u4e0a\u9650 sudo sh -c \"echo 50000 > /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us\" # \u542f\u52a8\u4e00\u4e2a\u65b0\u7684\u8fdb\u7a0b\uff0c\u5e76\u4e14\u5173\u8054\u5230 sudo cgcreate -g cpu:mygroup sudo cgexec -g cpu:mygroup /bin/bash \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c cpu.cfs_quota_us \u6587\u4ef6\u8bbe\u7f6e\u4e86 cgroup \u4e2d\u7684\u8fdb\u7a0b\u53ef\u4ee5\u4f7f\u7528\u7684\u6700\u5927 CPU \u65f6\u95f4\u3002\u8be5\u503c\u4ee5\u5fae\u79d2\u4e3a\u5355\u4f4d\uff0c\u56e0\u6b64\u5c06\u5176\u8bbe\u7f6e\u4e3a 50000 \u8868\u793a\u8fdb\u7a0b\u6700\u591a\u53ef\u4ee5\u4f7f\u7528\u5355\u4e2a CPU \u6838\u5fc3\u7684 50%\u3002 cgcreate \u548c cgexec \u547d\u4ee4\u521b\u5efa\u5e76\u5c06\u8fdb\u7a0b /bin/bash \u79fb\u52a8\u5230 mygroup cgroup \u4e2d\u3002 \u9650\u5236\u5185\u5b58\u4f7f\u7528\u4e0a\u9650\uff1a # \u521b\u5efa\u65b0\u7684cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/memory/mygroup # \u7cfb\u7edf\u4f1a\u521b\u5efa\u9ed8\u8ba4\u7684\u4e00\u4e9b\u6587\u4ef6\uff0c\u542b\u521d\u59cb\u503c\uff0c\u6bd4\u5982\u5185\u5b58\u4f7f\u7528\u4e0a\u9650\u7684\u9ed8\u8ba4\u503c\u662f9223372036854771712 cat /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes # \u8bbe\u7f6e\u5185\u5b58\u4f7f\u7528\u4e0a\u9650512MB sudo sh -c \"echo 536870912 > /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes\" # \u542f\u52a8\u4e00\u4e2a\u65b0\u7684\u8fdb\u7a0b\uff0c\u5e76\u4e14\u5173\u8054\u5230'mygroup' sudo cgcreate -g memory:mygroup sudo cgexec -g memory:mygroup /bin/bash \u5728\u4e0a\u9762\u4f8b\u5b50\u4e2d\uff0c memory.limit_in_bytes \u6587\u4ef6\u8bbe\u7f6e\u4e86 cgroup \u4e2d\u8fdb\u7a0b\u53ef\u4ee5\u4f7f\u7528\u7684\u6700\u5927\u5185\u5b58\u91cf\u3002\u8be5\u503c\u4ee5\u5b57\u8282\u4e3a\u5355\u4f4d\uff0c\u56e0\u6b64\u5c06\u5176\u8bbe\u7f6e\u4e3a 536870912 \u8868\u793a\u8fdb\u7a0b\u6700\u591a\u53ef\u4ee5\u4f7f\u7528 512MB \u7684\u5185\u5b58\u3002 \u8bbe\u7f6e\u4f18\u5148\u8fdb\u7a0b\u7684 I/O \u4f7f\u7528\u7387\uff1a # \u521b\u5efa\u65b0cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/blkio/mygroup # \u8bbe\u7f6e\u8fdb\u7a0b\u6700\u5927\u8bfb\u548c\u5199\u7684\u901f\u738710MB/s sudo sh -c \"echo '8:0 10485760' > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.read_bps_device\" sudo sh -c \"echo '8:0 10485760' > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.write_bps_device\" # \u542f\u52a8\u4e00\u4e2a\u65b0\u7684\u8fdb\u7a0b\uff0c\u5e76\u4e14\u5173\u8054\u5230'mygroup' sudo cgcreate -g blkio:mygroup sudo cgexec -g blkio:mygroup /bin/bash \u5728\u4e0a\u9762\u4f8b\u5b50\u4e2d\uff0c blkio.throttle.read_bps_device \u548c blkio.throttle.write_bps_device \u6587\u4ef6\u8bbe\u7f6e\u4e86cgroup\u4e2d\u8fdb\u7a0b\u53ef\u4ee5\u4f7f\u7528\u7684\u6700\u5927\u8bfb\u53d6\u548c\u5199\u5165\u5e26\u5bbd\u3002\u8be5\u503c\u4ee5\u6bcf\u79d2\u5b57\u8282\u6570\u4e3a\u5355\u4f4d\uff0c\u56e0\u6b64\u5c06\u5176\u8bbe\u7f6e\u4e3a10485760\u610f\u5473\u7740\u8fdb\u7a0b\u5728\u4e3b\u8bbe\u5907\u53f7:\u6b21\u8bbe\u5907\u53f7\u4e3a8:0\u7684\u8bbe\u5907\uff08\u901a\u5e38\u662f\u7b2c\u4e00\u4e2a\u786c\u76d8\uff09\u4e0a\u8bfb\u53d6\u6216\u5199\u5165\u7684\u5e26\u5bbd\u6700\u591a\u4e3a10MB/s\u3002 \u5c06 8:0 10485760 \u8fd9\u4e2a\u5b57\u7b26\u4e32\u5199\u5165\u5230 /sys/fs/cgroup/blkio/mygroup/blkio.throttle.read_bps_device \u6587\u4ef6\u4e2d\u7684\u4f5c\u7528\u662f\u9650\u5236 mygroup \u63a7\u5236\u7ec4\u4e2d\u5173\u8054\u7684\u5757\u8bbe\u5907\uff08block device\uff09\u7684\u8bfb\u53d6\u901f\u7387\u3002 \u5728 Linux \u4e2d\uff0c blkio \u63a7\u5236\u7ec4\u5b50\u7cfb\u7edf\u53ef\u4ee5\u7528\u6765\u5bf9\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u7684\u5757\u8bbe\u5907\u8bbf\u95ee\u8fdb\u884c\u9650\u5236\uff0c\u5982\u9650\u5236\u8bfb\u5199\u901f\u7387\u3001I/O \u4f18\u5148\u7ea7\u7b49\u3002\u800c blkio.throttle.read_bps_device \u8fd9\u4e2a\u6587\u4ef6\u5219\u7528\u4e8e\u8bbe\u7f6e\u67d0\u4e2a\u5757\u8bbe\u5907\u7684\u8bfb\u53d6\u901f\u7387\u9650\u5236\u3002 \u5177\u4f53\u6765\u8bf4\uff0c 8:0 \u8868\u793a\u8bbe\u5907\u7684\u4e3b\u6b21\u7f16\u53f7\uff08major:minor\uff09\uff0c\u8fd9\u91cc\u662f\u6307\u78c1\u76d8 /dev/sda \u3002 10485760 \u5219\u662f\u8bfb\u53d6\u901f\u7387\u7684\u9650\u5236\u503c\uff0c\u5355\u4f4d\u662f\u5b57\u8282/\u79d2\u3002\u8fd9\u4e2a\u503c\u8868\u793a /dev/sda \u6700\u5927\u8bfb\u53d6\u901f\u7387\u4e3a 10MB/s\uff0c\u8d85\u8fc7\u8fd9\u4e2a\u901f\u7387\u7684\u8bfb\u53d6\u8bf7\u6c42\u4f1a\u88ab\u5ef6\u8fdf\u6267\u884c\uff0c\u4ece\u800c\u9650\u5236\u4e86\u78c1\u76d8\u7684\u8bfb\u53d6\u5e26\u5bbd\u3002 \u56e0\u6b64\uff0c\u4ee5\u4e0a\u547d\u4ee4\u7684\u542b\u4e49\u662f\u5c06 mygroup \u63a7\u5236\u7ec4\u4e2d\u5173\u8054\u7684 /dev/sda \u78c1\u76d8\u7684\u8bfb\u53d6\u901f\u7387\u9650\u5236\u4e3a 10MB/s\uff0c\u4ece\u800c\u5b9e\u73b0\u5bf9\u8be5\u63a7\u5236\u7ec4\u4e2d\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u5bf9\u78c1\u76d8\u8bfb\u53d6\u7684\u9650\u5236\u3002 \u540c\u7406\uff0c\u5c06 8:0 10485760 \u8fd9\u4e2a\u5b57\u7b26\u4e32\u5199\u5165\u5230 /sys/fs/cgroup/blkio/mygroup/blkio.throttle.write_bps_device \u6587\u4ef6\u4e2d\uff0c\u4ee5\u9650\u5236 mygroup \u63a7\u5236\u7ec4\u4e2d\u5173\u8054\u7684\u5757\u8bbe\u5907\uff08block device\uff09\u7684\u5199\u5165\u901f\u7387\u3002 \u9650\u5236\u4e00\u7ec4\u8fdb\u7a0b\u7684\u7f51\u7edc\u5e26\u5bbd\uff1a # \u521b\u5efa\u65b0\u7684cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/net_cls/mygroup # \u5c06\u6b64\u7ec4\u4e2d\u7684\u8fdb\u7a0b\u7684\u7f51\u7edc\u7c7bID\u8bbe\u7f6e\u4e3a\u201cmyclass\u201d sudo sh -c \"echo 0x10001 > /sys/fs/cgroup/net_cls/mygroup/net_cls.classid\" \u4e0a\u9762\u7684\u4f8b\u5b50\u662f\u5c06 0x10001 \u8fd9\u4e2a\u5341\u516d\u8fdb\u5236\u6570\u503c\u5199\u5165\u5230 /sys/fs/cgroup/net_cls/mygroup/net_cls.classid \u6587\u4ef6\u4e2d\uff0c\u4ee5\u6307\u5b9a mygroup \u63a7\u5236\u7ec4\u7684\u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\uff08classid\uff09\u3002 \u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\u662f Linux \u5185\u6838\u4e2d\u7528\u6765\u5b9e\u73b0\u6d41\u91cf\u63a7\u5236\u548c\u6d41\u91cf\u5206\u7c7b\u7684\u4e00\u4e2a\u673a\u5236\uff0c\u5b83\u53ef\u4ee5\u5c06\u6570\u636e\u5305\u6309\u7167\u4e0d\u540c\u7684\u7c7b\u522b\uff08class\uff09\u8fdb\u884c\u6807\u8bb0\u548c\u533a\u5206\uff0c\u7136\u540e\u5728\u7f51\u7edc\u8bbe\u5907\u4e0a\u9488\u5bf9\u4e0d\u540c\u7684\u7c7b\u522b\u8fdb\u884c\u4e0d\u540c\u7684\u5904\u7406\uff0c\u5982\u9650\u901f\u3001\u4f18\u5148\u7ea7\u8c03\u6574\u7b49\u3002\u63a7\u5236\u7ec4\u4e2d\u7684 net_cls \u5b50\u7cfb\u7edf\u53ef\u4ee5\u7528\u6765\u5c06\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u4e0e\u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\u5173\u8054\u8d77\u6765\uff0c\u4ece\u800c\u5b9e\u73b0\u5bf9\u5b83\u4eec\u7684\u7f51\u7edc\u6d41\u91cf\u8fdb\u884c\u63a7\u5236\u548c\u5206\u7c7b\u3002 \u56e0\u6b64\uff0c\u4ee5\u4e0a\u547d\u4ee4\u662f\u5c06 mygroup \u63a7\u5236\u7ec4\u7684\u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\u8bbe\u7f6e\u4e3a 0x10001 \uff0c\u8fd9\u6837\u4e0e\u8be5\u63a7\u5236\u7ec4\u76f8\u5173\u8054\u7684\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u5c31\u4f1a\u88ab\u6807\u8bb0\u4e3a\u8be5\u7c7b\u522b\uff0c\u7136\u540e\u53ef\u4ee5\u901a\u8fc7\u5176\u4ed6\u5de5\u5177\uff08\u5982 tc \u547d\u4ee4\uff09\u5bf9\u5176\u8fdb\u884c\u7f51\u7edc\u6d41\u91cf\u63a7\u5236\u548c\u5206\u7c7b\u3002 \u5982\u679c\u9047\u5230\u5bf9\u5e94\u9650\u5236\u6587\u4ef6\u4e0d\u5b58\u5728\uff0c\u4e00\u79cd\u53ef\u80fd\u662f\u9700\u8981\u68c0\u67e5cgroup\u5b50\u7cfb\u6709\u6ca1\u6709\u6b63\u786e\u7edf\u8f7d\u6216\u8005\u6ca1\u6709\u542f\u7528\u5185\u5b58\u5b50\u7cfb\u7edf\u3002 mount | grep cgroup \u5982\u679c cgroups \u6587\u4ef6\u7cfb\u7edf\u5df2\u7ecf\u6302\u8f7d\uff0c\u5e94\u8be5\u4f1a\u770b\u5230\u8f93\u51fa\u7c7b\u4f3c\u4e8e\u4ee5\u4e0b\u5185\u5bb9\uff08\uff09\u4ee5memory\u4e3a\u4f8b\uff09\uff1a cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory) \u5982\u679c\u6ca1\u6709\u770b\u5230 memory \u5b57\u6bb5\uff0c\u5219\u8868\u793a\u5185\u5b58\u5b50\u7cfb\u7edf\u6ca1\u6709\u542f\u7528\u3002\u53ef\u4ee5\u7f16\u8f91 /etc/default/grub \u6587\u4ef6\uff0c\u6dfb\u52a0\u6216\u4fee\u6539\u4ee5\u4e0b\u884c\uff1a GRUB_CMDLINE_LINUX_DEFAULT=\"cgroup_enable=memory\" \u7136\u540e\u66f4\u65b0 GRUB \u914d\u7f6e\u5e76\u91cd\u542f\u7cfb\u7edf\uff1a sudo update-grub sudo reboot \u91cd\u542f\u540e\u518d\u6b21\u68c0\u67e5 /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes \u6587\u4ef6\u662f\u5426\u5b58\u5728\u3002\u5982\u679c\u8fd8\u662f\u4e0d\u5b58\u5728\uff0c\u53ef\u80fd\u9700\u8981\u624b\u52a8\u521b\u5efa\u5b83\u4ee5\u53ca\u5176\u4ed6\u76f8\u5173\u7684 cgroups \u6587\u4ef6\u3002\u4f8b\u5982\uff0c\u8fd0\u884c\u4ee5\u4e0b\u547d\u4ee4\uff1a sudo mkdir /sys/fs/cgroup/memory/mygroup sudo touch /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes \u7136\u540e\u5c31\u53ef\u4ee5\u50cf\u4e4b\u524d\u7684\u4f8b\u5b50\u4e00\u6837\u8bbe\u7f6e\u5185\u5b58\u9650\u5236\u4e86 Apparmor\u548cSELinux\u914d\u7f6e\u6587\u4ef6 \u00b6 \u5b89\u5168\u914d\u7f6e\u6587\u4ef6\uff0c\u7528\u4e8e\u63a7\u5236\u5bf9\u8d44\u6e90\u7684\u8bbf\u95ee AppArmor \u548c SELinux \u90fd\u662f\u5e38\u89c1\u7684\u5f3a\u5236\u8bbf\u95ee\u63a7\u5236\uff08MAC\uff09\u673a\u5236\uff0c\u53ef\u4ee5\u5bf9\u8fdb\u7a0b\u6216\u5e94\u7528\u7a0b\u5e8f\u7684\u8bbf\u95ee\u6743\u9650\u8fdb\u884c\u7cbe\u7ec6\u63a7\u5236\u3002\u4e0b\u9762\u5206\u522b\u4e3e\u4f8b\u8bf4\u660e\u8fd9\u4e24\u79cd\u673a\u5236\u7684\u914d\u7f6e\u6587\u4ef6\u4f7f\u7528\u3002 AppArmor AppArmor \u7684\u4e3b\u914d\u7f6e\u6587\u4ef6\u662f /etc/apparmor/profiles.d/ \u76ee\u5f55\u4e0b\u7684\u5404\u4e2a\u6587\u4ef6\uff0c\u6bcf\u4e2a\u6587\u4ef6\u5bf9\u5e94\u4e00\u4e2a\u5e94\u7528\u7a0b\u5e8f\u6216\u8fdb\u7a0b\u7684\u914d\u7f6e\u3002\u4ee5 sshd \u670d\u52a1\u4e3a\u4f8b\uff0c\u8be5\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6\u662f /etc/apparmor.d/usr.sbin.sshd \u3002 \u8be5\u914d\u7f6e\u6587\u4ef6\u7684\u5185\u5bb9\u7c7b\u4f3c\u4e8e\u4e0b\u9762\u8fd9\u6837\uff1a # Last Modified: Sun Mar 14 18 :53:00 2023 # include /usr/sbin/sshd { # include # include # allow read access to user home directories /home/** r, # allow sshd to execute /usr/bin/which to determine full path of shell /usr/bin/which ix, # allow sshd to read its own configuration file /etc/ssh/sshd_config r, # allow sshd to read the SSH host keys /etc/ssh/ssh_host_* r, # allow sshd to use pam for authentication /usr/share/pam/** r, # allow sshd to use nsswitch for name resolution /etc/nsswitch.conf r, /etc/hosts r, /etc/hostname r, /etc/resolv.conf r, # allow sshd to write to its own log file /var/log/auth.log w, # allow sshd to create and manage pid files /var/run/sshd.pid w, /var/run/sshd.dir/ w, /var/run/sshd.dir/* rw, # allow sshd to access systemd-logind /run/systemd/* r, /run/systemd/session/*.scope r, /run/systemd/sessions/*.scope r, # deny everything else deny /, } \u8be5\u914d\u7f6e\u6587\u4ef6\u5b9a\u4e49\u4e86 /usr/sbin/sshd \u8fdb\u7a0b\u7684\u6743\u9650\u9650\u5236\u89c4\u5219\uff0c\u5305\u62ec\u5141\u8bb8\u8bbf\u95ee\u7684\u6587\u4ef6\u3001\u7981\u6b62\u8bbf\u95ee\u7684\u6587\u4ef6\u7b49\u3002\u5176\u4e2d #include \u8868\u793a\u5305\u542b\u4e86\u4e00\u7ec4\u901a\u7528\u7684\u6743\u9650\u89c4\u5219\uff0c\u53ef\u4ee5\u5728\u4e0d\u540c\u7684\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u4e2d\u91cd\u590d\u4f7f\u7528\u3002 2.SELinux SELinux \u7684\u4e3b\u914d\u7f6e\u6587\u4ef6\u662f /etc/selinux/config \uff0c\u8be5\u6587\u4ef6\u5b9a\u4e49\u4e86\u7cfb\u7edf\u7684 SELinux \u7b56\u7565\u548c\u6a21\u5f0f\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0copenSUSE \u4f7f\u7528\u7684\u662f targeted \u6a21\u5f0f\u3002 \u6bcf\u4e2a\u8fdb\u7a0b\u6216\u5e94\u7528\u7a0b\u5e8f\u8fd8\u9700\u8981\u5bf9\u5e94\u4e00\u4e2a SELinux \u914d\u7f6e\u6587\u4ef6\uff0c\u4ee5\u5b9a\u4e49\u5b83\u4eec\u7684\u8bbf\u95ee\u6743\u9650\u3002\u4ee5 httpd \u670d\u52a1\u4e3a\u4f8b\uff0c\u8be5\u670d\u52a1\u7684 SELinux \u914d\u7f6e\u6587\u4ef6\u662f /etc/selinux/targeted/contexts/httpd.te \u3002 \u8be5\u914d\u7f6e\u6587\u4ef6\u7684\u5185\u5bb9\u7c7b\u4f3c\u4e8e\u4e0b\u9762\u8fd9\u6837\uff1a # HTTPD server type httpd_t ; type httpd_sys_script_t ; init_daemon_domain ( httpd_t, httpd_sys_script_t ) \u8be5\u914d\u7f6e\u6587\u4ef6\u5b9a\u4e49\u4e86 httpd \u670d\u52a1\u7684 SELinux \u7c7b\u578b\u4e3a httpd_t \uff0c\u5e76\u4f7f\u7528\u4e86 httpd_sys_script_t \u4f5c\u4e3a\u5176\u521d\u59cb\u5316\u57df\u3002\u5176\u4e2d type \u8868\u793a SELinux \u7c7b\u578b\uff0c init_daemon_domain \u5219\u662f\u4e00\u4e2a SELinux \u5b8f\uff0c\u7528\u4e8e\u5b9a\u4e49\u670d\u52a1\u7684\u521d\u59cb\u57df\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u5728 SELinux \u4e2d\uff0c\u8bbf\u95ee\u6743\u9650\u89c4\u5219\u4e0d\u662f\u76f4\u63a5\u5728\u914d\u7f6e\u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\uff0c\u800c\u662f\u901a\u8fc7\u8bbf\u95ee\u63a7\u5236\u7b56\u7565\u548c\u89c4\u5219\u8fdb\u884c\u63a7\u5236\u3002\u8fd9\u4e9b\u7b56\u7565\u548c\u89c4\u5219\u53ef\u4ee5\u4f7f\u7528 SELinux \u5de5\u5177\u96c6\uff08\u5982 semanage \u3001 setsebool \u3001 restorecon \u7b49\uff09\u8fdb\u884c\u7ba1\u7406\u548c\u8bbe\u7f6e\u3002 \u6bd4\u5982\uff0c\u5728openSUSE\u4e2d\u53ef\u4ee5\u770b\u5230 /etc/selinux/semanage.conf \u6587\u4ef6\u548c\u5176\u4e2d\u7684\u914d\u7f6e\u3002 \u5185\u6838\u80fd\u529b \u00b6 \u5185\u6838\u80fd\u529b\uff08Kernel capabilities\uff09 \u6ca1\u6709\u80fd\u529b\uff1aroot\u53ef\u4ee5\u6267\u884c\u6240\u6709\u64cd\u4f5c\uff0c\u5176\u4ed6\u7528\u6237\u53ef\u80fd\u4ec0\u4e48\u4e5f\u505a\u4e0d\u4e86 38\u4e2a\u7ec6\u7c92\u5ea6\u7684\u529f\u80fd\u6765\u63a7\u5236\u6743\u9650 Kernel capabilities \u662f Linux \u5185\u6838\u63d0\u4f9b\u7684\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u63a7\u5236\u8fdb\u7a0b\u5bf9\u7cfb\u7edf\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u3002\u4e0e\u4f20\u7edf\u7684 Unix \u6743\u9650\u673a\u5236\u4e0d\u540c\uff0cKernel capabilities \u53ef\u4ee5\u4f7f\u7ba1\u7406\u5458\u5728\u7cbe\u7ec6\u63a7\u5236\u7cfb\u7edf\u8d44\u6e90\u8bbf\u95ee\u7684\u540c\u65f6\uff0c\u907f\u514d\u5c06\u8fc7\u591a\u6743\u9650\u6388\u4e88\u8fdb\u7a0b\uff0c\u63d0\u9ad8\u4e86\u7cfb\u7edf\u7684\u5b89\u5168\u6027\u3002 \u5728\u4f20\u7edf Unix \u6743\u9650\u673a\u5236\u4e2d\uff0c\u6bcf\u4e2a\u8fdb\u7a0b\u90fd\u6709\u4e00\u4e2a\u6709\u6548\u7528\u6237 ID \u548c\u4e00\u4e2a\u6709\u6548\u7ec4 ID\uff0c\u8fd9\u4e9b ID \u51b3\u5b9a\u4e86\u8be5\u8fdb\u7a0b\u5bf9\u6587\u4ef6\u3001\u8bbe\u5907\u3001\u7f51\u7edc\u7b49\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u3002\u4f46\u662f\uff0c\u8fd9\u79cd\u6743\u9650\u673a\u5236\u4e0d\u591f\u7075\u6d3b\uff0c\u5982\u679c\u8981\u6388\u4e88\u8fdb\u7a0b\u67d0\u4e9b\u7279\u5b9a\u7684\u6743\u9650\uff0c\u53ef\u80fd\u9700\u8981\u5c06\u6240\u6709\u7684\u6743\u9650\u90fd\u6388\u4e88\u7ed9\u5b83\uff0c\u4ece\u800c\u964d\u4f4e\u4e86\u7cfb\u7edf\u7684\u5b89\u5168\u6027\u3002 Kernel capabilities \u63d0\u4f9b\u4e86\u4e00\u79cd\u66f4\u7ec6\u7c92\u5ea6\u7684\u6743\u9650\u63a7\u5236\u65b9\u5f0f\u3002\u6bcf\u4e2a\u8fdb\u7a0b\u90fd\u6709\u4e00\u7ec4 capabilities\uff0c\u6bcf\u4e2a capability \u8868\u793a\u4e00\u79cd\u7279\u5b9a\u7684\u6743\u9650\u3002\u8fdb\u7a0b\u53ef\u4ee5\u8bf7\u6c42\u548c\u91ca\u653e\u67d0\u4e9b capability\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u5c06\u6743\u9650\u6388\u4e88\u8fdb\u7a0b\uff0c\u800c\u4e0d\u5fc5\u6388\u4e88\u6240\u6709\u6743\u9650\u3002 \u4f8b\u5982\uff0c\u53ef\u4ee5\u5c06 CAP_NET_BIND_SERVICE capability \u6388\u4e88\u67d0\u4e2a\u8fdb\u7a0b\uff0c\u8fd9\u6837\u8be5\u8fdb\u7a0b\u5c31\u53ef\u4ee5\u7ed1\u5b9a 1-1023 \u7684\u7aef\u53e3\uff0c\u800c\u4e0d\u5fc5\u5177\u6709 root \u6743\u9650\u3002\u7c7b\u4f3c\u5730\uff0c\u53ef\u4ee5\u5c06 CAP_SYS_ADMIN capability \u6388\u4e88\u67d0\u4e2a\u8fdb\u7a0b\uff0c\u8fd9\u6837\u8be5\u8fdb\u7a0b\u5c31\u53ef\u4ee5\u6267\u884c\u7cfb\u7edf\u7ba1\u7406\u4efb\u52a1\uff0c\u5982\u6302\u8f7d\u6587\u4ef6\u7cfb\u7edf\u548c\u521b\u5efa\u8bbe\u5907\u8282\u70b9\u7b49\u3002 Linux \u5185\u6838\u63d0\u4f9b\u4e86\u4e00\u7ec4\u9ed8\u8ba4\u7684 capabilities\uff0c\u4e5f\u53ef\u4ee5\u901a\u8fc7\u81ea\u5b9a\u4e49\u7684\u65b9\u5f0f\u521b\u5efa\u65b0\u7684 capabilities\uff0c\u4ee5\u4fbf\u66f4\u597d\u5730\u63a7\u5236\u7cfb\u7edf\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u3002\u53ef\u4ee5\u4f7f\u7528 setcap \u547d\u4ee4\u4e3a\u4e8c\u8fdb\u5236\u6587\u4ef6\u8bbe\u7f6e capabilities\u3002\u4f8b\u5982\uff0c\u4e0b\u9762\u7684\u547d\u4ee4\u5c06 CAP_NET_RAW capability \u6388\u4e88 /usr/bin/ping \u547d\u4ee4\uff1a sudo setcap cap_net_raw+ep /usr/bin/ping \u8fd9\u6837\uff0c\u7528\u6237\u5c31\u53ef\u4ee5\u4f7f\u7528 ping \u547d\u4ee4\u800c\u4e0d\u5fc5\u4ee5 root \u7528\u6237\u7684\u8eab\u4efd\u767b\u5f55\u3002 \u9664\u4e86 CAP_NET_BIND_SERVICE \u548c CAP_SYS_ADMIN \uff0c\u8fd8\u6709\u4e00\u4e9b\u5176\u4ed6\u7684 capabilities\uff0c\u4ee5\u4e0b\u662f\u4e00\u4e9b\u4f8b\u5b50\uff1a CAP_DAC_OVERRIDE \uff1a\u5141\u8bb8\u8fdb\u7a0b\u5ffd\u7565\u6587\u4ef6\u6743\u9650\uff0c\u53ef\u4ee5\u8bbf\u95ee\u4efb\u4f55\u6587\u4ef6\u3002 CAP_CHOWN \uff1a\u5141\u8bb8\u8fdb\u7a0b\u4fee\u6539\u6587\u4ef6\u7684\u6240\u6709\u8005\u3002 CAP_SETUID \u548c CAP_SETGID \uff1a\u5141\u8bb8\u8fdb\u7a0b\u4fee\u6539\u81ea\u5df1\u7684\u7528\u6237 ID \u548c\u7ec4 ID\u3002 CAP_NET_ADMIN \uff1a\u5141\u8bb8\u8fdb\u7a0b\u6267\u884c\u7f51\u7edc\u7ba1\u7406\u4efb\u52a1\uff0c\u5982\u914d\u7f6e\u7f51\u7edc\u63a5\u53e3\u548c\u8def\u7531\u8868\u7b49\u3002 CAP_SYS_RESOURCE \uff1a\u5141\u8bb8\u8fdb\u7a0b\u4fee\u6539\u7cfb\u7edf\u8d44\u6e90\u9650\u5236\uff0c\u5982 CPU \u65f6\u95f4\u548c\u5185\u5b58\u9650\u5236\u7b49\u3002 \u53ef\u4ee5\u901a\u8fc7\u547d\u4ee4 man 7 capabilities \u6765\u67e5\u770b\u7cfb\u7edf\u63d0\u4f9b\u7684 capabilities \u5217\u8868\u548c\u8be6\u7ec6\u8bf4\u660e\u3002\u5728\u4f7f\u7528 Kernel capabilities \u65f6\uff0c\u9700\u8981\u6ce8\u610f\uff0c\u53ea\u6709\u62e5\u6709 CAP_SETFCAP \u6216 CAP_SYS_ADMIN capability \u7684\u8fdb\u7a0b\u624d\u80fd\u591f\u4fee\u6539\u81ea\u5df1\u6216\u5176\u4ed6\u8fdb\u7a0b\u7684 capabilities\uff0c\u8fd9\u4e5f\u662f\u4e3a\u4e86\u4fdd\u62a4\u7cfb\u7edf\u7684\u5b89\u5168\u6027\u3002 \u5982\u679c\u6267\u884c setcap \u547d\u4ee4\u65f6\u51fa\u73b0 \"command not found\" \u7684\u9519\u8bef\uff0c\u8fd9\u901a\u5e38\u610f\u5473\u7740 setcap \u547d\u4ee4\u6240\u5728\u7684\u5305\u5c1a\u672a\u5b89\u88c5\u3002\u5728 openSUSE \u4e2d\uff0csetcap \u547d\u4ee4\u5305\u542b\u5728 libcap-progs \u8f6f\u4ef6\u5305\u4e2d\u3002 \u5728 openSUSE \u7cfb\u7edf\u4e2d\u9700\u8981\u5b89\u88c5 libcap-progs \u8f6f\u4ef6\u5305\uff1a sudo zypper in libcap-progs \u5728 Ubuntu/Debian \u7cfb\u7edf\u4e0a\u9700\u8981\u5b89\u88c5 libcap \u5e93\uff1a sudo apt-get install libcap2-bin \u5728 CentOS/RHEL \u7cfb\u7edf\u4e0a\u9700\u8981\u5b89\u88c5 libcap \u5e93\uff1a sudo yum install libcap-devel \u5b89\u88c5\u5b8c\u6210\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528 setcap \u547d\u4ee4\u4e3a\u4e8c\u8fdb\u5236\u6587\u4ef6\u8bbe\u7f6e capabilities\u3002\u5982\u679c\u8fd8\u662f\u65e0\u6cd5\u627e\u5230 setcap \u547d\u4ee4\uff0c\u53ef\u4ee5\u5c1d\u8bd5\u4f7f\u7528\u5b8c\u6574\u8def\u5f84 /sbin/setcap \u6216\u8005 /usr/sbin/setcap\u3002 seccomp\u7b56\u7565 \u00b6 seccomp\uff08secure computing mode\uff09\u662f Linux \u5185\u6838\u63d0\u4f9b\u7684\u4e00\u79cd\u5b89\u5168\u673a\u5236\uff0c\u5b83\u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u80fd\u591f\u8fdb\u884c\u7684\u7cfb\u7edf\u8c03\u7528\u3002\u901a\u8fc7\u4f7f\u7528 seccomp\uff0c\u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u53ea\u80fd\u591f\u4f7f\u7528\u5fc5\u8981\u7684\u7cfb\u7edf\u8c03\u7528\uff0c\u4ece\u800c\u51cf\u5c11\u7cfb\u7edf\u88ab\u653b\u51fb\u7684\u98ce\u9669\u3002 seccomp \u7b56\u7565\u53ef\u4ee5\u4f7f\u7528 BPF\uff08Berkeley Packet Filter\uff09\u8bed\u8a00\u7f16\u5199\uff0c\u5e76\u4f7f\u7528 seccomp() \u7cfb\u7edf\u8c03\u7528\u52a0\u8f7d\u3002\u4ee5\u4e0b\u662f\u4e00\u4e2a\u4f7f\u7528 seccomp \u7b56\u7565\u9650\u5236\u8fdb\u7a0b\u80fd\u591f\u8fdb\u884c\u7684\u7cfb\u7edf\u8c03\u7528\u7684\u793a\u4f8b\uff1a #include #include #include int main () { // \u521b\u5efa seccomp \u8fc7\u6ee4\u5668 struct sock_filter filter [] = { BPF_STMT ( BPF_LD | BPF_W | BPF_ABS , 0 ), BPF_JUMP ( BPF_JMP | BPF_JEQ | BPF_K , __NR_write , 0 , 1 ), BPF_STMT ( BPF_RET | BPF_K , SECCOMP_RET_ALLOW ), BPF_STMT ( BPF_RET | BPF_K , SECCOMP_RET_KILL ), }; struct sock_fprog prog = { . len = sizeof ( filter ) / sizeof ( filter [ 0 ]), . filter = filter , }; // \u52a0\u8f7d seccomp \u8fc7\u6ee4\u5668 if ( prctl ( PR_SET_SECCOMP , SECCOMP_MODE_FILTER , & prog ) < 0 ) { perror ( \"prctl\" ); return 1 ; } // \u8c03\u7528 write \u7cfb\u7edf\u8c03\u7528 char buf [] = \"Hello, world!\" ; write ( 1 , buf , sizeof ( buf )); return 0 ; } \u4e0a\u8ff0\u4ee3\u7801\u521b\u5efa\u4e86\u4e00\u4e2a seccomp \u8fc7\u6ee4\u5668\uff0c\u4ec5\u5141\u8bb8\u8fdb\u7a0b\u8c03\u7528 write() \u7cfb\u7edf\u8c03\u7528\uff0c\u5176\u4ed6\u7cfb\u7edf\u8c03\u7528\u5747\u4f1a\u88ab\u7981\u6b62\u3002\u53ef\u4ee5\u901a\u8fc7\u7f16\u8bd1\u5e76\u8fd0\u884c\u4e0a\u8ff0\u4ee3\u7801\u6765\u6f14\u793a seccomp \u7b56\u7565\u7684\u4f5c\u7528\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0cseccomp \u7b56\u7565\u53ea\u80fd\u591f\u9650\u5236\u8fdb\u7a0b\u8fdb\u884c\u7684\u7cfb\u7edf\u8c03\u7528\uff0c\u4f46\u4e0d\u80fd\u591f\u9650\u5236\u7cfb\u7edf\u8c03\u7528\u7684\u53c2\u6570\u6216\u8fd4\u56de\u503c\u3002\u56e0\u6b64\uff0c\u4f7f\u7528 seccomp \u7b56\u7565\u65f6\u9700\u8981\u7279\u522b\u5c0f\u5fc3\uff0c\u907f\u514d\u8bef\u7528\u6216\u4ea7\u751f\u6f0f\u6d1e\u3002 Netlink \u00b6 Netlink \u662f\u4e00\u79cd Linux \u5185\u6838\u63d0\u4f9b\u7684\u901a\u4fe1\u673a\u5236\uff0c\u7528\u4e8e\u5185\u6838\u548c\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4e4b\u95f4\u7684\u53cc\u5411\u901a\u4fe1\uff08IPC\uff09\u3002Netlink \u53ef\u4ee5\u7528\u4e8e\u8bb8\u591a\u76ee\u7684\uff0c\u4f8b\u5982\uff1a \u914d\u7f6e\u7f51\u7edc\u8bbe\u5907\u548c\u8def\u7531\u8868\uff1a\u4f7f\u7528 Netlink \u53ef\u4ee5\u901a\u8fc7\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4fee\u6539\u5185\u6838\u7684\u7f51\u7edc\u8bbe\u5907\u548c\u8def\u7531\u8868\u914d\u7f6e\uff0c\u4f8b\u5982\u6dfb\u52a0\u3001\u5220\u9664\u3001\u4fee\u6539\u7f51\u7edc\u63a5\u53e3\u3001IP \u5730\u5740\u3001\u8def\u7531\u7b49\u3002 \u76d1\u89c6\u7f51\u7edc\u4e8b\u4ef6\uff1a\u4f7f\u7528 Netlink \u53ef\u4ee5\u5b9e\u65f6\u5730\u4ece\u5185\u6838\u83b7\u53d6\u7f51\u7edc\u4e8b\u4ef6\u7684\u901a\u77e5\uff0c\u4f8b\u5982\u7f51\u7edc\u63a5\u53e3\u7684\u72b6\u6001\u53d8\u5316\u3001\u8def\u7531\u7684\u53d8\u5316\u7b49\u3002 \u7a0b\u5e8f\u95f4\u901a\u4fe1\uff1a\u4f7f\u7528 Netlink \u53ef\u4ee5\u5728\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4e4b\u95f4\u8fdb\u884c\u901a\u4fe1\uff0c\u7c7b\u4f3c\u4e8e Unix \u57df\u5957\u63a5\u5b57\u3002 Netlink \u673a\u5236\u57fa\u4e8e\u4e00\u79cd\u7279\u6b8a\u7684\u5957\u63a5\u5b57\u7c7b\u578b\uff08PF_NETLINK\uff09\u548c\u4e00\u4e2a\u7279\u5b9a\u7684\u534f\u8bae\uff08NETLINK\uff09\u3002\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u53ef\u4ee5\u901a\u8fc7\u521b\u5efa Netlink \u5957\u63a5\u5b57\u548c\u5185\u6838\u901a\u4fe1\u3002\u5185\u6838\u548c\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4e4b\u95f4\u7684\u901a\u4fe1\u662f\u57fa\u4e8e Netlink \u6d88\u606f\u7684\uff0c\u6bcf\u4e2a Netlink \u6d88\u606f\u5305\u542b\u4e00\u4e2a\u6d88\u606f\u5934\u548c\u4e00\u4e2a\u8d1f\u8f7d\uff08payload\uff09\uff0c\u8d1f\u8f7d\u53ef\u4ee5\u662f\u4efb\u4f55\u7ed3\u6784\u4f53\u6216\u4e8c\u8fdb\u5236\u6570\u636e\u3002 Netlink \u6d88\u606f\u7684\u7c7b\u578b\u548c\u683c\u5f0f\u7531\u5185\u6838\u5b9a\u4e49\u3002\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u9700\u8981\u4e86\u89e3\u5185\u6838\u7684 Netlink \u6d88\u606f\u683c\u5f0f\u548c\u7c7b\u578b\uff0c\u624d\u80fd\u6b63\u786e\u5730\u6784\u9020\u548c\u89e3\u6790 Netlink \u6d88\u606f\u3002\u5e38\u7528\u7684 Netlink \u6d88\u606f\u7c7b\u578b\u5305\u62ec\uff1a RTM_NEWLINK \u548c RTM_DELLINK\uff1a\u6dfb\u52a0\u548c\u5220\u9664\u7f51\u7edc\u63a5\u53e3\u3002 RTM_NEWADDR \u548c RTM_DELADDR\uff1a\u6dfb\u52a0\u548c\u5220\u9664 IP \u5730\u5740\u3002 RTM_NEWROUTE \u548c RTM_DELROUTE\uff1a\u6dfb\u52a0\u548c\u5220\u9664\u8def\u7531\u3002 RTM_NEWNEIGH \u548c RTM_DELNEIGH\uff1a\u6dfb\u52a0\u548c\u5220\u9664 ARP \u8868\u9879\u3002 Netlink \u53ef\u4ee5\u4f7f\u7528 C \u8bed\u8a00\u7684 socket API \u8fdb\u884c\u7f16\u7a0b\u3002 Netfilter \u00b6 Netfilter\u662fLinux\u5185\u6838\u4e2d\u7684\u4e00\u4e2a\u5b50\u7cfb\u7edf\uff0c\u7528\u4e8e\u5728\u6570\u636e\u5305\u4f20\u8f93\u8fc7\u7a0b\u4e2d\u8fdb\u884c\u8fc7\u6ee4\u548c\u64cd\u4f5c\u3002\u5b83\u652f\u6301\u5bf9\u7f51\u7edc\u6570\u636e\u5305\u8fdb\u884c\u5404\u79cd\u7c7b\u578b\u7684\u5904\u7406\uff0c\u5305\u62ec\u8fc7\u6ee4\u3001\u4fee\u6539\u3001\u91cd\u5b9a\u5411\u7b49\u3002Netfilter\u901a\u8fc7\u5728\u5185\u6838\u4e2d\u6ce8\u518c\u94a9\u5b50\u51fd\u6570\uff0c\u5728\u6570\u636e\u5305\u901a\u8fc7\u7f51\u7edc\u6808\u7684\u4e0d\u540c\u9636\u6bb5\u65f6\u8fdb\u884c\u62e6\u622a\u548c\u5904\u7406\u3002 Netfilter\u7684\u6838\u5fc3\u662fiptables\u547d\u4ee4\uff0c\u5b83\u53ef\u4ee5\u7528\u6765\u914d\u7f6eNetfilter\u89c4\u5219\u3002iptables\u547d\u4ee4\u53ef\u4ee5\u7528\u6765\u914d\u7f6e\u9632\u706b\u5899\u89c4\u5219\uff0cNAT\u89c4\u5219\uff0c\u9650\u5236\u8fde\u63a5\u901f\u5ea6\u7b49\u3002iptables\u547d\u4ee4\u901a\u8fc7\u5339\u914d\u4e0d\u540c\u7684\u6570\u636e\u5305\u5b57\u6bb5\uff08\u4f8b\u5982\u6e90IP\u5730\u5740\u3001\u76ee\u7684IP\u5730\u5740\u3001\u6e90\u7aef\u53e3\u3001\u76ee\u7684\u7aef\u53e3\u7b49\uff09\u6765\u8fdb\u884c\u8fc7\u6ee4\u3002 \u9664\u4e86iptables\u547d\u4ee4\uff0c\u8fd8\u6709\u5176\u4ed6\u4e00\u4e9b\u5de5\u5177\u53ef\u4ee5\u7528\u4e8e\u914d\u7f6eNetfilter\u89c4\u5219\uff0c\u4f8b\u5982nftables\u547d\u4ee4\u548cfirewalld\u670d\u52a1\u3002\u8fd9\u4e9b\u5de5\u5177\u63d0\u4f9b\u4e86\u66f4\u7075\u6d3b\u3001\u66f4\u5f3a\u5927\u7684\u914d\u7f6e\u9009\u9879\uff0c\u53ef\u4ee5\u5e2e\u52a9\u7ba1\u7406\u5458\u66f4\u597d\u5730\u7ba1\u7406\u548c\u4fdd\u62a4\u7f51\u7edc\u5b89\u5168\u3002 \u4e5f\u53ef\u4ee5\u7528\u4e8e\u5c06\u7f51\u7edc\u6570\u636e\u5305\u5b9a\u5411\u5230\u5355\u4e2a\u5bb9\u5668\u3002 \u66f4\u591a\u4fe1\u606f\u53ef\u4ee5\u53c2\u8003 LXC/LXD \u3002 \u5b89\u88c5Docker \u00b6 \u53c2\u8003 \u6307\u5bfc \u5b89\u88c5Docker\u5f15\u64ce\u3002 \u53c2\u8003 \u6307\u5bfc \u5b89\u88c5Docker\u684c\u9762\u7248\u3002 \u4e0b\u9762\u4ee5openSUSE\u4e3a\u4f8b\u5b89\u88c5Docker\u5f15\u64ce\u3002 sudo zypper in docker \u5728\u5b89\u88c5\u8fc7\u7a0b\u4e2d\uff0c\u5728\u64cd\u4f5c\u7cfb\u7edf\u4e2d\u4f1a\u81ea\u52a8\u521b\u5efa\u7ec4 docker \u3002 \u5c06vagrant\u7528\u6237\u52a0\u5165docker\u7ec4\uff0c\u5219vagrant\u7528\u6237\u53ef\u4ee5\u5728\u4e0b\u6b21\u767b\u5f55\u540e\u4e0e\u672c\u673a\u7684Docker\u5b88\u62a4\u8fdb\u7a0b\uff08daemon\uff09\u8fdb\u884c\u901a\u4fe1\u3002Docker\u5b88\u62a4\u8fdb\u7a0b\u76d1\u542c\u672c\u5730\u5957\u63a5\u5b57\uff0c\u53ea\u80fd\u7531root\u7528\u6237\u548cdocker\u7ec4\u7684\u6210\u5458\u8bbf\u95ee\u3002 sudo usermod -aG docker $USER \u542f\u7528\u5e76\u542f\u52a8 Docker \u5f15\u64ce\u3002 sudo systemctl enable docker.service sudo systemctl start docker.service sudo systemctl status docker.service \u4e0b\u9762\u901a\u8fc7\u4e00\u4e2a\u5bb9\u5668 alpine \u7684\u4f8b\u5b50\u6765\u6f14\u793a\u5728\u76ee\u5f55 /opt/test \u4e0b\u6a21\u62df\u5b9e\u73b0choot\u3002 mkdir test cd test wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.4-x86_64.tar.gz tar zxvf alpine-minirootfs-3.13.4-x86_64.tar.gz -C alpine-minirootfs/ \u67e5\u770b\u5f53\u524d\u76ee\u5f55\u7ed3\u6784\uff1a tree ./test -L 1 \u8f93\u51fa\u7ed3\u679c\uff1a ./test \u251c\u2500\u2500 alpine-minirootfs-3.13.4-x86_64.tar.gz \u251c\u2500\u2500 bin \u251c\u2500\u2500 dev \u251c\u2500\u2500 etc \u251c\u2500\u2500 home \u251c\u2500\u2500 lib \u251c\u2500\u2500 media \u251c\u2500\u2500 mnt \u251c\u2500\u2500 opt \u251c\u2500\u2500 proc \u251c\u2500\u2500 root \u251c\u2500\u2500 run \u251c\u2500\u2500 sbin \u251c\u2500\u2500 srv \u251c\u2500\u2500 sys \u251c\u2500\u2500 tmp \u251c\u2500\u2500 usr \u2514\u2500\u2500 var \u901a\u8fc7\u547d\u4ee4 unshare \u6302\u8f7d\u76ee\u5f55 /opt/test/proc \u5230\u67d0\u4e2a\u6587\u4ef6\u6765\u5b9e\u73b0\u5ba2\u6237\u5b50\u7cfb\u7edf\u3002 sudo mount -t tmpfs tmpfs /opt/test/proc sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # ps -ef PID USER TIME COMMAND 1 root 0 :00 /bin/sh 2 root 0 :00 ps -ef / # touch 123 / # ls 123 123 \u6587\u4ef6 123 \u5728\u5ba2\u6237\u5b50\u7cfb\u7edf\u4e2d\u5df2\u521b\u5efa\uff0c\u5bf9\u5e94\u4e3b\u7cfb\u7edf\u4e2d\u4e5f\u53ef\u4ee5\u5bf9\u5176\u8fdb\u884c\u8bfb\u5199\u64cd\u4f5c\u3002\u6bd4\u5982\uff0c\u4fee\u6539\u6587\u4ef6 123 \u7684\u5185\u5bb9\u3002 su - ls 123 echo hello > 123 \u6587\u4ef6 123 \u4fee\u6539\u540e\u7684\u5185\u5bb9\u5728\u5ba2\u6237\u673a\u91cc\u9762\u4e5f\u53ef\u89c1\u3002 / # cat 123 hello \u5728\u4e3b\u7cfb\u7edf\u4e2d\u518d\u521b\u5efa\u4e24\u4e2a\u5b50\u76ee\u5f55 /opt/test-1 \u548c /opt/test-2 \u3002 mkdir test-1 mkdir test-2 \u521b\u5efa2\u4e2a\u5ba2\u6237\u5b50\u7cfb\u7edf\uff0c\u5e76\u5c06\u4e0a\u9762\u7684\u4e24\u4e2a\u5b50\u76ee\u5f55\u6302\u5728\u5230\u5404\u81ea\u7684 /opt/test/home/ \u76ee\u5f55\u3002 sudo mount --bind /opt/test-1 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-1\" > 123.1 /home # cat 123.1 test-1 sudo mount --bind /opt/test-2 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-2\" > 123.2 /home # cat 123.2 test-2 ll test/home ll test-1/ ll test-2/ \u901a\u8fc7\u4e0a\u9762\u7684\u6f14\u793a\uff0c\u53ef\u4ee5\u5f97\u51fa\u7ed3\u8bba\uff0c\u4e24\u4e2a\u5ba2\u6237\u5b50\u7cfb\u7edf\u6302\u5728\u5230\u540c\u4e00\u4e2a\u4e3b\u7cfb\u7edf\u76ee\u5f55\u65f6\uff0c\u5b50\u7cfb\u7edf\u65f6\u5171\u4eab\u4e3b\u7cfb\u7edf\u76ee\u5f55\uff0c\u5e76\u76f8\u4e92\u5f71\u54cd\u3002 \u5bb9\u5668\u751f\u547d\u5468\u671f \u00b6 \u6982\u8ff0 \u00b6 \u9884\u5148\u4e0b\u8f7d\u4e0b\u5217\u955c\u50cf\u3002 docker image pull busybox docker image pull nginx docker image pull alpine docker image pull jenkins/jenkins:lts docker image pull golang:1.12-alpine docker image pull golang \u521b\u5efa\u5e76\u4ea4\u4e92\u5f0f\u8fd0\u884c\u4e00\u4e2a\u65b0\u7684busybox\u5bb9\u5668\uff0c\u5e76\u8fde\u63a5\u4e00\u4e2a\u4f2a\u7ec8\u7aef\uff08pseudo terminal\uff09\u3002 \u5728\u5bb9\u5668\u5185\uff0c\u4f7f\u7528 top \u547d\u4ee4\u67e5\u627e /bin/sh \u6b63\u5728\u4f5c\u4e3aPID\u4e3a1\u7684\u8fdb\u7a0b\u8fd0\u884c\uff0c\u4ee5\u53ca top \u8fdb\u7a0b\u4e5f\u5728\u8fd0\u884c\u3002 \u7136\u540e\uff0c\u9000\u51fa\u5bb9\u5668\u3002 docker image ls docker run -d -it --name busybox_v1 -v /opt/test:/docker busybox:latest /bin/sh docker container ps -a docker exec -it 185efe490507 /bin/sh / # top Mem: 3627396K used, 12731512K free, 10080K shrd, 2920K buff, 2999340K cached CPU: 0 .0% usr 0 .1% sys 0 .0% nic 99 .8% idle 0 .0% io 0 .0% irq 0 .0% sirq Load average: 0 .38 1 .09 1 .29 2 /277 14 PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND 1 0 root S 1332 0 .0 1 0 .0 /bin/sh 8 0 root S 1332 0 .0 2 0 .0 /bin/sh 14 8 root R 1328 0 .0 1 0 .0 top / # exitbuild \u542f\u52a8\u4e00\u4e2a\u65b0\u7684 Nginx \u5bb9\u5668\uff0c\u5e76\u4ee5\u72ec\u7acb\u6a21\u5f0f\uff08detached mode\uff09\u8fd0\u884c\u3002 \u4f7f\u7528 docker exec \u547d\u4ee4\u5728 Nginx \u5bb9\u5668\u4e2d\u542f\u52a8\u53e6\u4e00\u4e2a shell\uff08 /bin/sh \uff09\u3002 \u4f7f\u7528 ps \u547d\u4ee4\u67e5\u770b\u5bb9\u5668\u4e2d\u6b63\u5728\u8fd0\u884c\u7684 sh \u548c ps \u547d\u4ee4\uff08\u5728\u4e0a\u4e00\u6b65\u6267\u884c\u7684\uff09\u3002 docker run -d -it --name nginx_v1 -v /opt/test:/docker nginx:latest /bin/sh docker container ps -a docker exec -it edb640127a0d /bin/sh # ps /bin/sh: 2 : ps: not found # apt-get update && apt-get install -y procps # ps PID TTY TIME CMD 8 pts/1 00 :00:00 sh 351 pts/1 00 :00:00 ps # exit \u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u770b\u52302\u4e2a\u73b0\u5728\u8fd0\u884c\u4e2d\u7684\u5bb9\u5668\u3002 docker container ps -a \u4f7f\u7528 docker logs \u547d\u4ee4\u663e\u793a\u6211\u4eec\u521a\u521a\u9000\u51fa\u7684\u5bb9\u5668\u7684\u65e5\u5fd7\u3002\u9009\u9879 --since 35m \u8868\u793a\u663e\u793a\u6700\u8fd1 35 \u5206\u949f\u5185\u7684\u65e5\u5fd7\u3002 docker logs nginx_v1 --details --since 35m docker logs busybox_v1 --details --since 35m \u4f7f\u7528 docker stop \u547d\u4ee4\u6765\u505c\u6b62 nginx \u5bb9\u5668\u3002 docker stop busybox_v1 docker stop nginx_v1 docker container ps -a \u4f7f\u7528\u4e0a\u8ff0\u547d\u4ee4 docker container ps -a \uff0c\u6211\u4eec\u53ef\u4ee5\u83b7\u53d6\u6240\u6709\u6b63\u5728\u8fd0\u884c\u548c\u5df2\u9000\u51fa\u7684\u5bb9\u5668\u5217\u8868\u3002\u4f7f\u7528 docker rm \u5c06\u5176\u5220\u9664\u3002\u4f7f\u7528 docker rm $(docker ps -aq) \u6765\u6e05\u7406\u4e3b\u673a\u4e0a\u7684\u6240\u6709\u5bb9\u5668\u3002\u8bf7\u8c28\u614e\u4f7f\u7528\uff01 docker rm busybox_v1 docker container ps -a \u7aef\u53e3\u548c\u5377 \u00b6 \u73b0\u5728\u542f\u52a8\u4e00\u4e2a\u65b0\u7684 nginx \u5bb9\u5668\uff0c\u5e76\u5c06 nginx web \u670d\u52a1\u5668\u7684\u7aef\u53e3\u5bfc\u51fa\u5230 Docker \u968f\u673a\u9009\u62e9\u7684\u7aef\u53e3\u3002 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u547d\u4ee4 docker ps \u627e\u51fa web \u670d\u52a1\u5668\u8f6c\u53d1\u5230\u4e86\u54ea\u4e2a\u7aef\u53e3\u3002\u5728\u4e3b\u673a\u4e0a\u4f7f\u7528\u8f6c\u53d1\u7684\u7aef\u53e3\u53f7\u8bbf\u95ee docker http://localhost: \u3002 docker container ps -a docker run -d -P --name nginx_v2 nginx:latest docker container ps -a Start another nginx container and expose port to 1080 on host as an example via http://localhost:1080 . \u542f\u52a8\u53e6\u4e00\u4e2anginx\u5bb9\u5668\uff0c\u5c06\u5176\u7aef\u53e3\u6620\u5c04\u5230\u4e3b\u673a\u76841080\u7aef\u53e3\uff0c\u53ef\u4ee5\u901a\u8fc7 http://localhost:1080 \u8bbf\u95ee\u3002 docker run -d -p 1080 :80 --name nginx_v3 nginx:latest docker container ps -a \u4f7f\u7528 docker inspect \u547d\u4ee4\u67e5\u627e\u955c\u50cf\u66b4\u9732\u7684\u7aef\u53e3\u53f7\uff0c\u8f93\u51faJSON\u683c\u5f0f\u6587\u4ef6\uff0c\u7f51\u7edc\u4fe1\u606f\uff08IP\u3001\u7f51\u5173\u3001\u7aef\u53e3\u7b49\uff09\u662f\u8f93\u51faJSON\u683c\u5f0f\u7684\u4e00\u90e8\u5206\u3002 docker inspect nginx_v3 \u5728\u76ee\u5f55 /opt/test \u4e2d\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a index.html \u7684\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u5982\u4e0b\uff1a < html > < head > < title > Sample Website from my container < body > < h1 > This is a custom website. < p > This website is served from my < a href = \"http://www.docker.com\" target = \"_blank\" > Docker container. \u542f\u52a8\u4e00\u4e2a\u65b0\u5bb9\u5668\uff0c\u5c06\u4e3b\u673a\u76ee\u5f55 /opt/test \u4e0e\u5bb9\u5668\u76ee\u5f55 /usr/share/nginx/html \u7ed1\u5b9a\u6302\u8f7d\u4e3a\u4e00\u4e2a\u5377\uff0c\u4ee5\u4fbfNginx\u53ef\u4ee5\u901a\u8fc7 http://localhost:49159/ \u53d1\u5e03\u6211\u4eec\u521a\u521b\u5efa\u7684html\u6587\u4ef6\uff0c\u800c\u4e0d\u662fNginx\u9ed8\u8ba4\u7684\u9875\u9762\u3002 docker run -d -P --mount type = bind,source = /opt/test/,target = /usr/share/nginx/html --name nginx_v3-1 nginx:latest docker container ps -a \u68c0\u67e5Nginx\u914d\u7f6e\u6587\u4ef6\uff0c\u67e5\u770b\u5bb9\u5668\u4e2dhtml\u4e3b\u9875\u5b58\u50a8\u7684\u4f4d\u7f6e\u3002 docker exec -it nginx_v3-1 /bin/sh # cd /etc/nginx/conf.d # ls default.conf # cat default.conf server { listen 80 ; listen [ :: ] :80 ; server_name localhost ; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html ; <-- index index.html index.htm ; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html ; location = /50x.html { root /usr/share/nginx/html ; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \\.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \\.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\\.ht { # deny all; #} } # cd /usr/share/nginx/html # cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    # \u63a8\u8350\u4f7f\u7528\u5377 API \u6765\u5b9e\u73b0\u6570\u636e\u6301\u4e45\u5316\uff0c\u800c\u4e0d\u662f\u5c06\u6570\u636e\u5b58\u50a8\u5728 Docker \u5bb9\u5668\u4e2d\u3002Docker \u652f\u6301\u4e24\u79cd\u6302\u8f7d\u65b9\u5f0f\uff1a \u7ed1\u5b9a\u6302\u8f7d\uff08Bind mounts\uff09\uff1a \u5c06\u672c\u5730\u4e3b\u673a\u76ee\u5f55\u6302\u8f7d\u5230\u5bb9\u5668\u4e2d\u7684\u67d0\u4e2a\u8def\u5f84\u3002 \u6302\u8f7d\u540e\uff0c\u76ee\u6807\u76ee\u5f55\u4e2d\u539f\u6709\u7684\u6240\u6709\u5185\u5bb9\u5c06\u88ab\u9690\u85cf\u3002 \u4f8b\u5982\uff0c\u5982\u679c\u6211\u4eec\u60f3\u8981\u6ce8\u5165\u67d0\u4e9b\u914d\u7f6e\u6587\u4ef6\uff0c\u6211\u4eec\u9700\u8981\u81ea\u5df1\u5199\u5bf9\u5e94\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5c06\u5176\u5b58\u50a8\u5728 Docker \u4e3b\u673a\u4e0a\u7684 /home/container/config \u8def\u5f84\u4e0b\uff0c\u5e76\u5c06\u6b64\u76ee\u5f55\u7684\u5185\u5bb9\u6302\u8f7d\u5230 /usr/application/config \uff08\u5047\u8bbe\u5e94\u7528\u7a0b\u5e8f\u4ece\u6b64\u5904\u8bfb\u53d6\u914d\u7f6e\uff09\u3002 \u547d\u4ee4\uff1a docker run --mount type=bind,source=,target= \u2026 \u547d\u540d\u5377\uff08Named volumes\uff09\uff1a Docker \u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u72ec\u7acb\u7684\u5b58\u50a8\u5377\uff0c\u5176\u751f\u547d\u5468\u671f\u72ec\u7acb\u4e8e\u5bb9\u5668\u4f46\u4ecd\u7531 Docker \u7ba1\u7406\u3002 \u5728\u521b\u5efa\u65f6\uff0c\u6302\u8f7d\u76ee\u6807\u7684\u5185\u5bb9\u5c06\u5408\u5e76\u5230\u5377\u4e2d\u3002 \u547d\u4ee4\uff1a docker run --mount source=,target= \u2026 \u5982\u4f55\u533a\u5206\u7ed1\u5b9a\u6302\u8f7d\u548c\u547d\u540d\u5377\uff1f \u5f53\u6307\u5b9a\u7edd\u5bf9\u8def\u5f84\u65f6\uff0cDocker \u4f1a\u8ba4\u4e3a\u8fd9\u662f\u4e00\u4e2a\u7ed1\u5b9a\u6302\u8f7d\u3002 \u5f53\u6211\u4eec\u4ec5\u63d0\u4f9b\u540d\u79f0\uff08\u5982\u76f8\u5bf9\u8def\u5f84 config \uff09\u65f6\uff0c\u5b83\u4f1a\u8ba4\u4e3a\u8fd9\u662f\u4e00\u4e2a\u547d\u540d\u5377\uff0c\u5e76\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a config \u7684\u5377\u3002 \u6ce8\uff1a\u6301\u4e45\u5b58\u50a8\u7531\u4e3b\u673a\u63d0\u4f9b\uff0c\u53ef\u4ee5\u76f4\u63a5\u662f\u4e3b\u673a\u6587\u4ef6\u7cfb\u7edf\u7684\u4e00\u90e8\u5206\uff0c\u4e5f\u53ef\u4ee5\u662f NFS \u6302\u8f7d\u3002 Dockerfile \u00b6 \u8ba9\u6211\u4eec\u7528 Dockerfile \u6784\u5efa\u4e00\u4e2a\u955c\u50cf\uff0c\u5bf9\u5176\u8fdb\u884c\u6253\u6807\u7b7e\u5e76\u4e0a\u4f20\u5230\u955c\u50cf\u4ed3\u5e93\u3002 \u83b7\u53d6 Docker \u955c\u50cf\u7684\u6784\u5efa\u5386\u53f2\u8bb0\u5f55\u3002 docker image history nginx:latest \u521b\u5efa\u4e00\u4e2a\u7a7a\u7684\u76ee\u5f55 /opt/tmp-1 \uff0c\u8fdb\u5165\u8be5\u76ee\u5f55\u5e76\u5728\u5176\u4e2d\u521b\u5efa index.html \u6587\u4ef6\u3002 /opt/tmp-1> cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    \u4f7f\u7528 FROM \u6765\u6269\u5c55\u4e00\u4e2a\u5df2\u6709\u7684\u955c\u50cf\uff0c\u5e76\u6307\u5b9a\u7248\u672c\u53f7\u3002 \u4f7f\u7528 COPY \u5c06\u4e00\u4e2a\u65b0\u7684\u9ed8\u8ba4\u7f51\u7ad9\u590d\u5236\u5230\u955c\u50cf\u4e2d\uff0c\u4f8b\u5982 /usr/share/nginx/html \u3002 \u4e3aNginx\u521b\u5efaSSL\u914d\u7f6e /opt/tmp-1/ssl.conf \u3002 server { listen 443 ssl; server_name localhost; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; location / { root /usr/share/nginx/html; index index.html index.htm; } } \u4f7f\u7528OpenSSL\u521b\u5efa\u4e00\u4e2a\u81ea\u7b7e\u540d\u8bc1\u4e66\uff0c\u4ee5\u4fbfSSL/TLS\u5de5\u4f5c\u3002 \u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u521b\u5efa\u4e00\u4e2a\u52a0\u5bc6\u5bc6\u94a5\u548c\u8bc1\u4e66\u3002 openssl req -x509 -nodes -newkey rsa:4096 -keyout nginx.key -out nginx.crt -days 365 -subj \"/CN= $( hostname ) \" \u4e3a\u4e86\u542f\u7528\u52a0\u5bc6\u7684HTTPS\uff0c\u6211\u4eec\u9700\u8981\u4f7f\u7528 EXPOSE \u6307\u4ee4\u516c\u5f00 443 \u7aef\u53e3\u3002\u9ed8\u8ba4\u7684nginx\u955c\u50cf\u4ec5\u516c\u5f00\u7aef\u53e3 80 \uff0c\u7528\u4e8e\u975e\u52a0\u5bc6\u7684HTTP\u3002 \u5728 /opt/tmp-1 \u6587\u4ef6\u5939\u4e2d\u521b\u5efa\u4ee5\u4e0bDockerfile\u3002 cat Dockerfile \u8f93\u51fa\uff1a FROM nginx:latest # copy the custom website into the image COPY index.html /usr/share/nginx/html # copy the SSL configuration file into the image COPY ssl.conf /etc/nginx/conf.d/ssl.conf # download the SSL key and certificate into the image COPY nginx.key /etc/nginx/ssl/ COPY nginx.crt /etc/nginx/ssl/ # expose the HTTPS port EXPOSE 443 \u81f3\u6b64\uff0c\u6211\u4eec\u5728\u76ee\u5f55 /opt/tmp-1 \u4e0b\u67095\u4e2a\u6587\u4ef6\u3002 ls /opt/tmp-1 \u8f93\u51fa\uff1a Dockerfile index.html nginx.crt nginx.key ssl.conf \u4f7f\u7528 docker build \u547d\u4ee4\u6765\u6784\u5efa\u955c\u50cf\uff0c\u5e76\u5c06\u5bb9\u5668\u768480\u548c443\u7aef\u53e3\u8f6c\u53d1\u3002 docker build -t nginx:my1 /opt/tmp-1/ docker image ls docker run -d -p 1086 :80 -p 1088 :443 --name nginx_v5 nginx:my1 docker container ps -a \u901a\u8fc7\u4e0b\u9762\u4e24\u4e2a\u94fe\u63a5\u6765\u9a8c\u8bc1\u4e0a\u9762\u7684\u53d8\u5316\u662f\u5426\u751f\u6548\u3002 http://localhost:1086/ https://localhost:1088/ \u5728 DockerHub \u6ce8\u518c\u4e00\u4e2a\u4e2a\u4eba\u8d26\u53f7\uff0c\u542f\u7528 Docker Hub \u4e2d\u7684\u8bbf\u95ee\u4ee4\u724c\u4ee5\u8fdb\u884c CLI \u5ba2\u6237\u7aef\u8eab\u4efd\u9a8c\u8bc1\u3002 docker login \u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002 Username: Password: \u7ed9\u8fd9\u4e2a\u955c\u50cf\u52a0\u4e0a\u4e00\u4e2a\u6807\u7b7e\uff0c\u4f8b\u5982\uff1asecure_nginx_0001\uff0c\u7248\u672c\u53f7\u4e3a v1\u3002 docker tag nginx:my1 secure_nginx_0001:v1 docker push secure_nginx_0001:v1 docker image ls \u591a\u9636\u6bb5Dockerfile \u00b6 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u6f14\u793a\u4e00\u4e2a\u591a\u9636\u6bb5\uff08Multi-stage\uff09\u6784\u5efa\u7684\u4f8b\u5b50\u3002\u5728Docker\u7684\u4e0a\u4e0b\u6587\u4e2d\uff0c\u591a\u9636\u6bb5\uff08Multi-stage\uff09\u610f\u5473\u7740\u6211\u4eec\u53ef\u4ee5\u6709\u591a\u4e2a\u5e26\u6709 FROM \u5173\u952e\u5b57\u7684\u884c\u3002 \u521b\u5efa\u6587\u4ef6\u5939 /opt/tmp-2 \u548c /opt/tmp-2/tmpl \u3002\u521b\u5efa\u6587\u4ef6 edit.html \uff0c view.html \uff0c wiki.go \u3002 \u6587\u4ef6\u7ed3\u6784\u5982\u4e0b\uff1a tree -l /opt/tmp-2 \u8f93\u51fa\u7ed3\u679c\uff1a . \u251c\u2500\u2500 tmpl \u2502 \u251c\u2500\u2500 edit.html \u2502 \u2514\u2500\u2500 view.html \u2514\u2500\u2500 wiki.go \u521b\u5efa\u4e00\u4e2a\u65b0\u7684Dockerfile\u3002 cat Dockerfile \u6587\u4ef6\u5185\u5bb9\uff1a # app builder stage FROM golang:1.12-alpine as builder # # copy the go source code over and build the binary WORKDIR /go/src COPY wiki.go /go/src/wiki.go RUN go build wiki.go # app exec stage # separate & new image starts here!# FROM alpine:3.9 # prepare file system etc RUN mkdir -p /app/data /app/tmpl && adduser -S -D -H -h /app appuser COPY tmpl/* /app/tmpl/ # get the compiled binary from the previous stage COPY --from=builder /go/src/wiki /app/wiki # prepare runtime env RUN chown -R appuser /app USER appuser WORKDIR /app # expose app port & set default command EXPOSE 8080 CMD [\"/app/wiki\"] \u7528\u4e0a\u4e00\u6b65\u521b\u5efa\u7684Dockerfile\u6765\u521b\u5efa\u65b0\u666f\u8c61\u3002 docker build -t lizard/golang:my1 /opt/tmp-2/ \u4ee5\u72ec\u7acb\u6a21\u5f0f\uff08detached\uff09\u8fd0\u884c\u8fd9\u4e2a\u955c\u50cf\uff0c\u5e76\u5c06\u5bb9\u5668\u7aef\u53e3 8080 \u8f6c\u53d1\u5230\u4e3b\u673a\u7aef\u53e3 1090 \u3002 docker run -d -p 1090 :8080 --name golan_v1 lizard/golang:my1 \u901a\u8fc7\u94fe\u63a5 http://localhost:1090 \u8bbf\u95ee\u8fd9\u4e2a\u8fd0\u884c\u7684\u5bb9\u5668\u3002 \u5bf9\u6211\u4eec\u521a\u521a\u521b\u5efa\u7684\u65b0\u7684golang\u955c\u50cf\u8fdb\u884c\u6807\u7b7e\uff0c\u5e76\u4e14\u4e0a\u4f20\u5230Dockerhub\u3002 docker tag lizard/golang:my1 /golang_0001:v1 docker push /golang_0001:v1","title":"Docker\u57fa\u7840"},{"location":"k8s/cka_cn/foundamentals/docker/#cka4docker","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb04:Docker\u57fa\u7840"},{"location":"k8s/cka_cn/foundamentals/docker/#_1","text":"\u4e86\u89e3Linux\u539f\u8bed\u7684\u6982\u5ff5\u548c\u5305\u542b\u7684\u7279\u6027\u3002 \u5b89\u88c5Docker\uff0c\u4e86\u89e3\u57fa\u672c\u7684Docker\u547d\u4ee4\u548cDockerfile\u7684\u4f7f\u7528\u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/docker/#_2","text":"\u64cd\u4f5c\u7cfb\u7edf\uff1aopenSUSE 15.3 cat /etc/os-release \u8f93\u51fa\u7ed3\u679c\uff1a NAME=\"openSUSE Leap\" VERSION=\"15.3\" ID=\"opensuse-leap\" ID_LIKE=\"suse opensuse\" VERSION_ID=\"15.3\" PRETTY_NAME=\"openSUSE Leap 15.3\" ANSI_COLOR=\"0;32\" CPE_NAME=\"cpe:/o:opensuse:leap:15.3\" BUG_REPORT_URL=\"https://bugs.opensuse.org\" HOME_URL=\"https://www.opensuse.org/\"","title":"\u7ec3\u4e60\u73af\u5883"},{"location":"k8s/cka_cn/foundamentals/docker/#linux","text":"\u5728\u64cd\u4f5c\u7cfb\u7edf\u4e2d\uff0c\u539f\u8bed\uff08primitives\uff09\u662f\u7528\u4e8e\u521b\u5efa\u66f4\u590d\u6742\u529f\u80fd\u7684\u57fa\u672c\u6784\u5efa\u5757\u6216\u64cd\u4f5c\u3002\u5728Linux\u4e2d\uff0c\u6709\u51e0\u79cd\u5e38\u7528\u7684\u539f\u8bed\u3002\u5305\u62ec\uff1a \u8fdb\u7a0b\uff08Processes\uff09\uff1a\u8fdb\u7a0b\u662f\u7a0b\u5e8f\u6216\u5e94\u7528\u7a0b\u5e8f\u7684\u8fd0\u884c\u5b9e\u4f8b\u3002\u5b83\u4eec\u662fLinux\u4e2d\u7684\u57fa\u672c\u5de5\u4f5c\u5355\u5143\uff0c\u7531\u5185\u6838\u7ba1\u7406\u3002 \u6587\u4ef6\uff08Files\uff09\uff1a\u6587\u4ef6\u662f\u5728Linux\u4e2d\u5b58\u50a8\u6570\u636e\u7684\u4e3b\u8981\u65b9\u5f0f\u3002\u5b83\u4eec\u53ef\u4ee5\u662f\u6587\u672c\u6587\u4ef6\u3001\u4e8c\u8fdb\u5236\u6587\u4ef6\u3001\u76ee\u5f55\u6216\u7279\u6b8a\u6587\u4ef6\uff0c\u5982\u8bbe\u5907\u6587\u4ef6\u3002 \u4fe1\u53f7\uff08Signals\uff09\uff1a\u4fe1\u53f7\u662f\u8fdb\u7a0b\u4e4b\u95f4\u6216\u8fdb\u7a0b\u4e0e\u5185\u6838\u4e4b\u95f4\u901a\u4fe1\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u5b83\u4eec\u7528\u4e8e\u901a\u77e5\u8fdb\u7a0b\u4e8b\u4ef6\uff0c\u4f8b\u5982\u4efb\u52a1\u5b8c\u6210\u6216\u9519\u8bef\u53d1\u751f\u7684\u60c5\u51b5\u3002 \u5957\u63a5\u5b57\uff08Sockets\uff09\uff1a\u5957\u63a5\u5b57\u662fLinux\u4e2d\u8fdb\u7a0b\u95f4\u901a\u4fe1\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u5b83\u4eec\u5141\u8bb8\u8fdb\u7a0b\u5728\u7f51\u7edc\u6216\u672c\u5730\u673a\u5668\u4e0a\u53d1\u9001\u548c\u63a5\u6536\u6570\u636e\u3002 \u7ebf\u7a0b\uff08Threads\uff09\uff1a\u7ebf\u7a0b\u662f\u8f7b\u91cf\u7ea7\u7684\u8fdb\u7a0b\uff0c\u4e0e\u5176\u7236\u8fdb\u7a0b\u5171\u4eab\u76f8\u540c\u7684\u5185\u5b58\u7a7a\u95f4\u548c\u8d44\u6e90\u3002\u5b83\u4eec\u901a\u5e38\u7528\u4e8e\u901a\u8fc7\u5141\u8bb8\u540c\u65f6\u6267\u884c\u591a\u4e2a\u4efb\u52a1\u6765\u63d0\u9ad8\u5e94\u7528\u7a0b\u5e8f\u7684\u6027\u80fd\u3002 \u7ba1\u9053\uff08Pipes\uff09\uff1a\u7ba1\u9053\u662f\u4e00\u79cd\u5c06\u4e00\u4e2a\u8fdb\u7a0b\u7684\u8f93\u51fa\u8fde\u63a5\u5230\u53e6\u4e00\u4e2a\u8fdb\u7a0b\u7684\u8f93\u5165\u7684\u65b9\u5f0f\u3002\u5b83\u4eec\u5141\u8bb8\u8fdb\u7a0b\u4ee5\u53d7\u63a7\u7684\u65b9\u5f0f\u8fdb\u884c\u901a\u4fe1\u548c\u4ea4\u6362\u6570\u636e\u3002 \u4fe1\u53f7\u91cf\uff08Semaphores\uff09\uff1a\u4fe1\u53f7\u91cf\u662fLinux\u4e2d\u63a7\u5236\u5bf9\u5171\u4eab\u8d44\u6e90\u8bbf\u95ee\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u5b83\u4eec\u5141\u8bb8\u8fdb\u7a0b\u534f\u8c03\u5b83\u4eec\u5bf9\u5171\u4eab\u8d44\u6e90\u7684\u8bbf\u95ee\uff0c\u5982\u6587\u4ef6\u6216\u5185\u5b58\u3002","title":"Linux\u539f\u8bed"},{"location":"k8s/cka_cn/foundamentals/docker/#chroot","text":"chroot\u4f7f\u7528pivot_root\uff0c\u4ee5\u5b9e\u73b0\u5c06*\u8fdb\u7a0b*\u7684\u6839\u76ee\u5f55\u66f4\u6539\u4e3a\u4efb\u4f55\u7ed9\u5b9a\u7684\u76ee\u5f55\u3002 a. \u6a21\u62df\u5bb9\u5668 \u4f7f\u7528 chroot \u547d\u4ee4\u53ef\u4ee5\u5728Linux\u7cfb\u7edf\u4e2d\u521b\u5efa\u4e00\u4e2a\u5bb9\u5668\u3002\u8be5\u5bb9\u5668\u53ef\u4ee5\u770b\u4f5c\u662f\u4e00\u4e2a\u865a\u62df\u7684\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u5176\u4e2d\u8fd0\u884c\u7684\u8fdb\u7a0b\u53ea\u80fd\u8bbf\u95ee\u8be5\u6839\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u8d44\u6e90\u3002 \u4f8b\u5982\uff0c\u4ee5\u4e0b\u547d\u4ee4\u4f1a\u5c06\u5f53\u524d\u6839\u6587\u4ef6\u7cfb\u7edf\u66f4\u6539\u4e3a /tmp/myroot \u76ee\u5f55\uff1a chroot /tmp/myroot /bin/bash \u8fd9\u6761\u547d\u4ee4\u4f1a\u542f\u52a8\u4e00\u4e2a\u65b0\u7684Bash shell\uff0c\u8be5shell\u7684\u6839\u76ee\u5f55\u4e3a /tmp/myroot \u3002 b. \u66f4\u6539\u6839\u6587\u4ef6\u7cfb\u7edf chroot \u547d\u4ee4\u8fd8\u53ef\u7528\u4e8e\u66f4\u6539\u8fdb\u7a0b\u7684\u6839\u6587\u4ef6\u7cfb\u7edf\u3002\u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 chroot \u547d\u4ee4\u542f\u52a8\u4e00\u4e2a\u5177\u6709\u53e6\u4e00\u4e2a\u6839\u6587\u4ef6\u7cfb\u7edf\u7684\u8fdb\u7a0b\uff0c\u800c\u4e0d\u662f\u7cfb\u7edf\u7684\u9ed8\u8ba4\u6839\u6587\u4ef6\u7cfb\u7edf\u3002 \u4f8b\u5982\uff0c\u4ee5\u4e0b\u547d\u4ee4\u4f1a\u5c06\u5f53\u524d\u76ee\u5f55\uff08\u5373 ./ \uff09\u4f5c\u4e3a\u6839\u76ee\u5f55\uff0c\u5e76\u5728\u5176\u4e2d\u542f\u52a8\u4e00\u4e2a\u65b0\u7684Bash shell\uff1a sudo chroot . /bin/bash","title":"chroot"},{"location":"k8s/cka_cn/foundamentals/docker/#_3","text":"\u5728Linux\u64cd\u4f5c\u7cfb\u7edf\u4e2d\uff0cNamespace\uff08\u547d\u540d\u7a7a\u95f4\uff09\u662f\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u9694\u79bb\u4e0d\u540c\u8fdb\u7a0b\u7684\u8d44\u6e90\u3002\u901a\u8fc7Namespace\u673a\u5236\uff0c\u53ef\u4ee5\u5c06\u4e00\u7ec4\u8fdb\u7a0b\u53ca\u5176\u5b50\u8fdb\u7a0b\u7684\u89c6\u56fe\u9694\u79bb\u5728\u4e00\u4e2a\u72ec\u7acb\u7684Namespace\u4e2d\uff0c\u4ece\u800c\u5b9e\u73b0\u8fdb\u7a0b\u4e4b\u95f4\u8d44\u6e90\u9694\u79bb\u7684\u76ee\u7684\u3002 \u4e0b\u9762\u662f\u4e00\u4e9b\u5e38\u89c1\u7684Namespace\u7c7b\u578b\u53ca\u5176\u4f5c\u7528\uff1a Mount Namespace\uff1a\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\u6302\u8f7d\u70b9\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u3002 PID Namespace\uff1a\u9694\u79bb\u8fdb\u7a0bID\u53f7\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u8fdb\u7a0bID\u53f7\u7a7a\u95f4\uff0c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684PID\u51b2\u7a81\u3002 Network Namespace\uff1a\u9694\u79bb\u7f51\u7edc\u6808\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u7f51\u7edc\u6808\uff0c\u4ece\u800c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684\u7f51\u7edc\u51b2\u7a81\u3002 IPC Namespace\uff1a\u9694\u79bb\u8fdb\u7a0b\u95f4\u901a\u4fe1\uff08IPC\uff09\u673a\u5236\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684IPC\u7a7a\u95f4\uff0c\u4ece\u800c\u907f\u514dIPC\u673a\u5236\u5e26\u6765\u7684\u8d44\u6e90\u7ade\u4e89\u3002 UTS Namespace\uff1a\u9694\u79bb\u4e3b\u673a\u540d\u548c\u57df\u540d\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u4e3b\u673a\u540d\u548c\u57df\u540d\u7a7a\u95f4\uff0c\u4ece\u800c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684\u547d\u540d\u51b2\u7a81\u3002 Primitives namespace\u548cNamespace\u662f\u4e24\u4e2a\u4e0d\u540c\u7684\u6982\u5ff5\u3002 Namespace\u662fLinux\u64cd\u4f5c\u7cfb\u7edf\u63d0\u4f9b\u7684\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u9694\u79bb\u4e0d\u540c\u8fdb\u7a0b\u7684\u8d44\u6e90\uff0c\u4ee5\u5b9e\u73b0\u8fdb\u7a0b\u4e4b\u95f4\u7684\u8d44\u6e90\u9694\u79bb\u548c\u73af\u5883\u9694\u79bb\u3002\u4f8b\u5982\uff0cPID Namespace\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684PID\u53f7\u7a7a\u95f4\uff0c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684PID\u51b2\u7a81\uff1bNetwork Namespace\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u7f51\u7edc\u6808\uff0c\u4ece\u800c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684\u7f51\u7edc\u51b2\u7a81\u7b49\u3002 Primitives namespace\u662f\u4e00\u79cd\u65b0\u7684\u6280\u672f\u6982\u5ff5\uff0c\u5b83\u662f\u6307\u5c06\u4e0d\u540c\u7684\u57fa\u672c\u64cd\u4f5c\uff08\u4f8b\u5982\u8bfb\u5199\u6587\u4ef6\u3001\u521b\u5efa\u8fdb\u7a0b\u3001\u7f51\u7edc\u901a\u4fe1\u7b49\uff09\u4f5c\u4e3a\u539f\u8bed\u8fdb\u884c\u9694\u79bb\u548c\u5c01\u88c5\uff0c\u4f7f\u5f97\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u5728\u8fd9\u4e9b\u9694\u79bb\u7684\u539f\u8bed\u4e0a\u6784\u5efa\u51fa\u81ea\u5df1\u7684\u9694\u79bb\u73af\u5883\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u901a\u8fc7\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\u8bfb\u5199\u64cd\u4f5c\u6765\u5b9e\u73b0\u5bb9\u5668\u7ea7\u522b\u7684\u6587\u4ef6\u7cfb\u7edf\u9694\u79bb\uff1b\u901a\u8fc7\u9694\u79bb\u7f51\u7edc\u901a\u4fe1\u64cd\u4f5c\u6765\u5b9e\u73b0\u5bb9\u5668\u7ea7\u522b\u7684\u7f51\u7edc\u9694\u79bb\u7b49\u3002 \u56e0\u6b64\uff0cNamespace\u548cPrimitives namespace\u662f\u4e24\u4e2a\u4e0d\u540c\u7684\u6982\u5ff5\uff0c\u867d\u7136\u5b83\u4eec\u90fd\u53ef\u4ee5\u7528\u4e8e\u5b9e\u73b0\u9694\u79bb\u548c\u5c01\u88c5\u7684\u529f\u80fd\uff0c\u4f46\u662fNamespace\u662f\u4e00\u79cd\u66f4\u4e3a\u901a\u7528\u548c\u5e95\u5c42\u7684\u673a\u5236\uff0cPrimitives namespace\u662f\u4e00\u79cd\u66f4\u4e3a\u9ad8\u5c42\u7684\u62bd\u8c61\u6982\u5ff5\uff0c\u901a\u5e38\u7528\u4e8e\u6784\u5efa\u5bb9\u5668\u7b49\u5e94\u7528\u7ea7\u522b\u7684\u9694\u79bb\u73af\u5883\u3002 Namespace\u793a\u4f8b\uff1a \u5728Linux\u7cfb\u7edf\u4e2d\uff0c\u53ef\u4ee5\u4f7f\u7528PID Namespace\u6765\u9694\u79bb\u8fdb\u7a0bID\u53f7\u7a7a\u95f4\uff0c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684PID\u51b2\u7a81\u3002\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\uff1a # \u521b\u5efa\u4e00\u4e2a\u65b0\u7684PID Namespace unshare -p /bin/bash # \u5728\u65b0\u7684PID Namespace\u4e2d\u8fd0\u884c\u4e00\u4e2a\u8fdb\u7a0b echo $$ # \u663e\u793a\u5f53\u524d\u8fdb\u7a0b\u7684PID ps aux # \u663e\u793a\u5f53\u524d\u8fdb\u7a0b\u53ca\u5176\u5b50\u8fdb\u7a0b \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c unshare -p \u547d\u4ee4\u521b\u5efa\u4e86\u4e00\u4e2a\u65b0\u7684PID Namespace\uff0c\u5e76\u5728\u5176\u4e2d\u542f\u52a8\u4e86\u4e00\u4e2a\u65b0\u7684bash\u8fdb\u7a0b\u3002\u7531\u4e8e\u8be5\u8fdb\u7a0b\u8fd0\u884c\u5728\u4e00\u4e2a\u72ec\u7acb\u7684PID Namespace\u4e2d\uff0c\u56e0\u6b64\u5b83\u7684PID\u53f7\u4e0e\u4e3b\u673a\u4e0a\u7684\u5176\u4ed6\u8fdb\u7a0b\u4e0d\u4f1a\u51b2\u7a81\u3002\u5728\u8fd9\u4e2a\u65b0\u7684bash\u8fdb\u7a0b\u4e2d\uff0c $$ \u547d\u4ee4\u663e\u793a\u7684\u662f\u8be5\u8fdb\u7a0b\u5728PID Namespace\u4e2d\u7684PID\u53f7\uff0c\u800c ps aux \u547d\u4ee4\u53ea\u4f1a\u663e\u793a\u5f53\u524dPID Namespace\u4e2d\u7684\u8fdb\u7a0b\uff0c\u4e0d\u4f1a\u663e\u793a\u4e3b\u673a\u4e0a\u7684\u5176\u4ed6\u8fdb\u7a0b\u3002 Primitives Namespace\u793a\u4f8b\uff1a \u5728Docker\u5bb9\u5668\u4e2d\uff0c\u53ef\u4ee5\u4f7f\u7528Filesystem Namespace\u6765\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\uff0c\u4f7f\u5f97\u4e0d\u540c\u7684\u5bb9\u5668\u4e4b\u95f4\u62e5\u6709\u72ec\u7acb\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u3002\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\uff1a # \u5728\u5bb9\u5668\u4e2d\u8fd0\u884c\u4e00\u4e2a\u547d\u4ee4 docker run --rm -it --name mycontainer ubuntu bash # \u5728\u5bb9\u5668\u4e2d\u521b\u5efa\u4e00\u4e2a\u6587\u4ef6\u5e76\u9000\u51fa touch myfile exit # \u5728\u4e3b\u673a\u4e0a\u67e5\u770b\u6587\u4ef6 ls myfile # myfile\u6587\u4ef6\u4e0d\u5b58\u5728 # \u518d\u6b21\u8fdb\u5165\u5bb9\u5668 docker start -i mycontainer # \u5728\u5bb9\u5668\u4e2d\u67e5\u770b\u6587\u4ef6 ls myfile # myfile\u6587\u4ef6\u5b58\u5728 \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c docker run \u547d\u4ee4\u542f\u52a8\u4e86\u4e00\u4e2a\u65b0\u7684Docker\u5bb9\u5668\uff0c\u5e76\u5728\u5176\u4e2d\u8fd0\u884c\u4e86\u4e00\u4e2abash\u8fdb\u7a0b\u3002\u7531\u4e8e\u8be5\u5bb9\u5668\u4f7f\u7528\u4e86Filesystem Namespace\uff0c\u56e0\u6b64\u5bb9\u5668\u5185\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u4e0e\u4e3b\u673a\u4e0a\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u662f\u9694\u79bb\u7684\u3002\u5728\u5bb9\u5668\u5185\u521b\u5efa\u7684\u6587\u4ef6 myfile \u53ea\u5b58\u5728\u4e8e\u5bb9\u5668\u5185\u90e8\uff0c\u5728\u4e3b\u673a\u4e0a\u662f\u770b\u4e0d\u5230\u7684\u3002\u5f53\u518d\u6b21\u8fdb\u5165\u5bb9\u5668\u65f6\uff0c myfile \u6587\u4ef6\u5c31\u53ef\u4ee5\u88ab\u770b\u5230\u4e86\u3002 \u603b\u7ed3\uff1a Namespace\u662fLinux\u5185\u6838\u63d0\u4f9b\u7684\u673a\u5236\uff0c\u800cPrimitives Namespace\u5219\u662f\u4e00\u79cd\u57fa\u4e8eNamespace\u7684\u9ad8\u5c42\u62bd\u8c61\uff0c\u7528\u4e8e\u5b9e\u73b0\u5e94\u7528\u7ea7\u522b\u7684\u9694\u79bb\u548c\u5c01\u88c5\u3002Namespace\u53ef\u4ee5\u7528\u4e8e\u9694\u79bb\u591a\u79cd\u8d44\u6e90\uff0c\u800cPrimitives Namespace\u901a\u5e38\u7528\u4e8e\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\u3001\u7f51\u7edc\u3001\u8fdb\u7a0b\u7b49\u64cd\u4f5c\u7684\u539f\u8bed\u3002","title":"\u547d\u540d\u7a7a\u95f4"},{"location":"k8s/cka_cn/foundamentals/docker/#_4","text":"cgroup\uff0c\u5168\u79f0\u4e3aControl Group\uff0c\u5373\u63a7\u5236\u7ec4\uff0c\u662fLinux\u5185\u6838\u63d0\u4f9b\u7684\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u9650\u5236\u3001\u8bb0\u5f55\u3001\u9694\u79bb\u548c\u4f18\u5148\u7ea7\u63a7\u5236\u4e00\u7ec4\u8fdb\u7a0b\u7684\u8d44\u6e90\u4f7f\u7528\u3002\u5b83\u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7ec4\u7684CPU\u3001\u5185\u5b58\u3001\u78c1\u76d8\u3001\u7f51\u7edc\u7b49\u8d44\u6e90\u7684\u4f7f\u7528\uff0c\u540c\u65f6\u4e5f\u53ef\u4ee5\u8bb0\u5f55\u8fdb\u7a0b\u7ec4\u7684\u8d44\u6e90\u4f7f\u7528\u60c5\u51b5\u548c\u884c\u4e3a\u3002 cgroup\u901a\u8fc7\u5c06\u4e00\u7ec4\u8fdb\u7a0b\u7ec4\u7ec7\u6210\u4e00\u4e2a\u5c42\u6b21\u7ed3\u6784\uff0c\u5c06\u8d44\u6e90\u5206\u914d\u7ed9\u4e0d\u540c\u7684cgroup\u6765\u5b9e\u73b0\u8d44\u6e90\u9650\u5236\u548c\u4f18\u5148\u7ea7\u63a7\u5236\u3002\u6bcf\u4e2acgroup\u53ef\u4ee5\u8bbe\u7f6e\u8d44\u6e90\u9650\u5236\u548c\u63a7\u5236\u7b56\u7565\uff0c\u4f8b\u5982\u53ef\u4ee5\u9650\u5236\u4e00\u4e2a\u8fdb\u7a0b\u7ec4\u6700\u591a\u4f7f\u752850%\u7684CPU\u65f6\u95f4\uff0c\u6216\u8005\u9650\u5236\u4e00\u4e2a\u8fdb\u7a0b\u7ec4\u6700\u591a\u4f7f\u7528100MB\u7684\u5185\u5b58\u7b49\u3002 cgroup\u6700\u521d\u7531Google\u516c\u53f8\u5f00\u53d1\uff0c\u540e\u6765\u88abLinux\u5185\u6838\u793e\u533a\u91c7\u7eb3\u5e76\u52a0\u5165\u5230\u5185\u6838\u4e2d\uff0c\u6210\u4e3aLinux\u7cfb\u7edf\u7684\u4e00\u90e8\u5206\u3002\u5b83\u5728\u5bb9\u5668\u6280\u672f\u3001\u865a\u62df\u5316\u3001\u4e91\u8ba1\u7b97\u7b49\u9886\u57df\u90fd\u6709\u5e7f\u6cdb\u7684\u5e94\u7528\u3002 \u4e0b\u9762\u662fcgroup \u7684\u4e00\u4e9b\u5e38\u89c1\u7528\u9014\uff1a CPU \u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684 CPU \u4f7f\u7528\u7387\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684 CPU \u8d44\u6e90\u5bfc\u81f4\u7cfb\u7edf\u8d1f\u8f7d\u8fc7\u9ad8\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u7a33\u5b9a\u6027\u548c\u5176\u4ed6\u8fdb\u7a0b\u7684\u6b63\u5e38\u8fd0\u884c\u3002 \u5185\u5b58\u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684\u5185\u5b58\u4f7f\u7528\u91cf\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684\u5185\u5b58\u8d44\u6e90\u5bfc\u81f4\u7cfb\u7edf\u5185\u5b58\u4e0d\u8db3\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u6027\u80fd\u548c\u5176\u4ed6\u8fdb\u7a0b\u7684\u6b63\u5e38\u8fd0\u884c\u3002 IO \u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684 IO \u5e26\u5bbd\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684 IO \u8d44\u6e90\u5bfc\u81f4\u5176\u4ed6\u8fdb\u7a0b\u7684 IO \u64cd\u4f5c\u53d7\u5230\u5f71\u54cd\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u6027\u80fd\u548c\u54cd\u5e94\u901f\u5ea6\u3002 \u7f51\u7edc\u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684\u7f51\u7edc\u5e26\u5bbd\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684\u7f51\u7edc\u8d44\u6e90\u5bfc\u81f4\u7f51\u7edc\u62e5\u585e\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u6027\u80fd\u548c\u5176\u4ed6\u8fdb\u7a0b\u7684\u6b63\u5e38\u8fd0\u884c\u3002 \u8fdb\u7a0b\u63a7\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684\u542f\u52a8\u3001\u505c\u6b62\u548c\u8c03\u5ea6\u7b49\u884c\u4e3a\uff0c\u4ece\u800c\u5b9e\u73b0\u5bf9\u7cfb\u7edf\u8fdb\u7a0b\u7684\u63a7\u5236\u548c\u7ba1\u7406\u3002 \u8d44\u6e90\u7edf\u8ba1\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u5b9e\u65f6\u7edf\u8ba1\u7cfb\u7edf\u4e2d\u5404\u4e2a\u8fdb\u7a0b\u7684\u8d44\u6e90\u4f7f\u7528\u60c5\u51b5\uff0c\u4ece\u800c\u5e2e\u52a9\u7ba1\u7406\u5458\u4e86\u89e3\u7cfb\u7edf\u8d1f\u8f7d\u72b6\u51b5\u548c\u5404\u4e2a\u8fdb\u7a0b\u7684\u6027\u80fd\u74f6\u9888\uff0c\u4ece\u800c\u91c7\u53d6\u76f8\u5e94\u7684\u63aa\u65bd\u4f18\u5316\u7cfb\u7edf\u6027\u80fd\u3002 \u4e0b\u9762\u662fopenSUSE\u4e2d\u7684\u793a\u4f8b\uff1a \u5b89\u88c5\u9700\u8981\u7684\u8f6f\u4ef6\u5305\uff1a sudo zypper install libcgroup-tools \u9650\u5236CPU\u4f7f\u7528\u4e0a\u9650\uff1a # \u521b\u5efa\u65b0\u7684cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/cpu/mygroup # \u7cfb\u7edf\u4f1a\u521b\u5efa\u9ed8\u8ba4\u7684\u4e00\u4e9b\u6587\u4ef6\uff0c\u542b\u521d\u59cb\u503c\uff0c\u6bd4\u5982CPU\u4f7f\u7528\u65f6\u95f4\u7684\u9650\u989d\u7684\u9ed8\u8ba4\u503c\u662f-1 cat /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us # \u8bbe\u5b9aCPU\u4f7f\u7528\u65f6\u95f4\u4e0a\u9650 sudo sh -c \"echo 50000 > /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us\" # \u542f\u52a8\u4e00\u4e2a\u65b0\u7684\u8fdb\u7a0b\uff0c\u5e76\u4e14\u5173\u8054\u5230 sudo cgcreate -g cpu:mygroup sudo cgexec -g cpu:mygroup /bin/bash \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c cpu.cfs_quota_us \u6587\u4ef6\u8bbe\u7f6e\u4e86 cgroup \u4e2d\u7684\u8fdb\u7a0b\u53ef\u4ee5\u4f7f\u7528\u7684\u6700\u5927 CPU \u65f6\u95f4\u3002\u8be5\u503c\u4ee5\u5fae\u79d2\u4e3a\u5355\u4f4d\uff0c\u56e0\u6b64\u5c06\u5176\u8bbe\u7f6e\u4e3a 50000 \u8868\u793a\u8fdb\u7a0b\u6700\u591a\u53ef\u4ee5\u4f7f\u7528\u5355\u4e2a CPU \u6838\u5fc3\u7684 50%\u3002 cgcreate \u548c cgexec \u547d\u4ee4\u521b\u5efa\u5e76\u5c06\u8fdb\u7a0b /bin/bash \u79fb\u52a8\u5230 mygroup cgroup \u4e2d\u3002 \u9650\u5236\u5185\u5b58\u4f7f\u7528\u4e0a\u9650\uff1a # \u521b\u5efa\u65b0\u7684cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/memory/mygroup # \u7cfb\u7edf\u4f1a\u521b\u5efa\u9ed8\u8ba4\u7684\u4e00\u4e9b\u6587\u4ef6\uff0c\u542b\u521d\u59cb\u503c\uff0c\u6bd4\u5982\u5185\u5b58\u4f7f\u7528\u4e0a\u9650\u7684\u9ed8\u8ba4\u503c\u662f9223372036854771712 cat /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes # \u8bbe\u7f6e\u5185\u5b58\u4f7f\u7528\u4e0a\u9650512MB sudo sh -c \"echo 536870912 > /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes\" # \u542f\u52a8\u4e00\u4e2a\u65b0\u7684\u8fdb\u7a0b\uff0c\u5e76\u4e14\u5173\u8054\u5230'mygroup' sudo cgcreate -g memory:mygroup sudo cgexec -g memory:mygroup /bin/bash \u5728\u4e0a\u9762\u4f8b\u5b50\u4e2d\uff0c memory.limit_in_bytes \u6587\u4ef6\u8bbe\u7f6e\u4e86 cgroup \u4e2d\u8fdb\u7a0b\u53ef\u4ee5\u4f7f\u7528\u7684\u6700\u5927\u5185\u5b58\u91cf\u3002\u8be5\u503c\u4ee5\u5b57\u8282\u4e3a\u5355\u4f4d\uff0c\u56e0\u6b64\u5c06\u5176\u8bbe\u7f6e\u4e3a 536870912 \u8868\u793a\u8fdb\u7a0b\u6700\u591a\u53ef\u4ee5\u4f7f\u7528 512MB \u7684\u5185\u5b58\u3002 \u8bbe\u7f6e\u4f18\u5148\u8fdb\u7a0b\u7684 I/O \u4f7f\u7528\u7387\uff1a # \u521b\u5efa\u65b0cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/blkio/mygroup # \u8bbe\u7f6e\u8fdb\u7a0b\u6700\u5927\u8bfb\u548c\u5199\u7684\u901f\u738710MB/s sudo sh -c \"echo '8:0 10485760' > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.read_bps_device\" sudo sh -c \"echo '8:0 10485760' > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.write_bps_device\" # \u542f\u52a8\u4e00\u4e2a\u65b0\u7684\u8fdb\u7a0b\uff0c\u5e76\u4e14\u5173\u8054\u5230'mygroup' sudo cgcreate -g blkio:mygroup sudo cgexec -g blkio:mygroup /bin/bash \u5728\u4e0a\u9762\u4f8b\u5b50\u4e2d\uff0c blkio.throttle.read_bps_device \u548c blkio.throttle.write_bps_device \u6587\u4ef6\u8bbe\u7f6e\u4e86cgroup\u4e2d\u8fdb\u7a0b\u53ef\u4ee5\u4f7f\u7528\u7684\u6700\u5927\u8bfb\u53d6\u548c\u5199\u5165\u5e26\u5bbd\u3002\u8be5\u503c\u4ee5\u6bcf\u79d2\u5b57\u8282\u6570\u4e3a\u5355\u4f4d\uff0c\u56e0\u6b64\u5c06\u5176\u8bbe\u7f6e\u4e3a10485760\u610f\u5473\u7740\u8fdb\u7a0b\u5728\u4e3b\u8bbe\u5907\u53f7:\u6b21\u8bbe\u5907\u53f7\u4e3a8:0\u7684\u8bbe\u5907\uff08\u901a\u5e38\u662f\u7b2c\u4e00\u4e2a\u786c\u76d8\uff09\u4e0a\u8bfb\u53d6\u6216\u5199\u5165\u7684\u5e26\u5bbd\u6700\u591a\u4e3a10MB/s\u3002 \u5c06 8:0 10485760 \u8fd9\u4e2a\u5b57\u7b26\u4e32\u5199\u5165\u5230 /sys/fs/cgroup/blkio/mygroup/blkio.throttle.read_bps_device \u6587\u4ef6\u4e2d\u7684\u4f5c\u7528\u662f\u9650\u5236 mygroup \u63a7\u5236\u7ec4\u4e2d\u5173\u8054\u7684\u5757\u8bbe\u5907\uff08block device\uff09\u7684\u8bfb\u53d6\u901f\u7387\u3002 \u5728 Linux \u4e2d\uff0c blkio \u63a7\u5236\u7ec4\u5b50\u7cfb\u7edf\u53ef\u4ee5\u7528\u6765\u5bf9\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u7684\u5757\u8bbe\u5907\u8bbf\u95ee\u8fdb\u884c\u9650\u5236\uff0c\u5982\u9650\u5236\u8bfb\u5199\u901f\u7387\u3001I/O \u4f18\u5148\u7ea7\u7b49\u3002\u800c blkio.throttle.read_bps_device \u8fd9\u4e2a\u6587\u4ef6\u5219\u7528\u4e8e\u8bbe\u7f6e\u67d0\u4e2a\u5757\u8bbe\u5907\u7684\u8bfb\u53d6\u901f\u7387\u9650\u5236\u3002 \u5177\u4f53\u6765\u8bf4\uff0c 8:0 \u8868\u793a\u8bbe\u5907\u7684\u4e3b\u6b21\u7f16\u53f7\uff08major:minor\uff09\uff0c\u8fd9\u91cc\u662f\u6307\u78c1\u76d8 /dev/sda \u3002 10485760 \u5219\u662f\u8bfb\u53d6\u901f\u7387\u7684\u9650\u5236\u503c\uff0c\u5355\u4f4d\u662f\u5b57\u8282/\u79d2\u3002\u8fd9\u4e2a\u503c\u8868\u793a /dev/sda \u6700\u5927\u8bfb\u53d6\u901f\u7387\u4e3a 10MB/s\uff0c\u8d85\u8fc7\u8fd9\u4e2a\u901f\u7387\u7684\u8bfb\u53d6\u8bf7\u6c42\u4f1a\u88ab\u5ef6\u8fdf\u6267\u884c\uff0c\u4ece\u800c\u9650\u5236\u4e86\u78c1\u76d8\u7684\u8bfb\u53d6\u5e26\u5bbd\u3002 \u56e0\u6b64\uff0c\u4ee5\u4e0a\u547d\u4ee4\u7684\u542b\u4e49\u662f\u5c06 mygroup \u63a7\u5236\u7ec4\u4e2d\u5173\u8054\u7684 /dev/sda \u78c1\u76d8\u7684\u8bfb\u53d6\u901f\u7387\u9650\u5236\u4e3a 10MB/s\uff0c\u4ece\u800c\u5b9e\u73b0\u5bf9\u8be5\u63a7\u5236\u7ec4\u4e2d\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u5bf9\u78c1\u76d8\u8bfb\u53d6\u7684\u9650\u5236\u3002 \u540c\u7406\uff0c\u5c06 8:0 10485760 \u8fd9\u4e2a\u5b57\u7b26\u4e32\u5199\u5165\u5230 /sys/fs/cgroup/blkio/mygroup/blkio.throttle.write_bps_device \u6587\u4ef6\u4e2d\uff0c\u4ee5\u9650\u5236 mygroup \u63a7\u5236\u7ec4\u4e2d\u5173\u8054\u7684\u5757\u8bbe\u5907\uff08block device\uff09\u7684\u5199\u5165\u901f\u7387\u3002 \u9650\u5236\u4e00\u7ec4\u8fdb\u7a0b\u7684\u7f51\u7edc\u5e26\u5bbd\uff1a # \u521b\u5efa\u65b0\u7684cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/net_cls/mygroup # \u5c06\u6b64\u7ec4\u4e2d\u7684\u8fdb\u7a0b\u7684\u7f51\u7edc\u7c7bID\u8bbe\u7f6e\u4e3a\u201cmyclass\u201d sudo sh -c \"echo 0x10001 > /sys/fs/cgroup/net_cls/mygroup/net_cls.classid\" \u4e0a\u9762\u7684\u4f8b\u5b50\u662f\u5c06 0x10001 \u8fd9\u4e2a\u5341\u516d\u8fdb\u5236\u6570\u503c\u5199\u5165\u5230 /sys/fs/cgroup/net_cls/mygroup/net_cls.classid \u6587\u4ef6\u4e2d\uff0c\u4ee5\u6307\u5b9a mygroup \u63a7\u5236\u7ec4\u7684\u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\uff08classid\uff09\u3002 \u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\u662f Linux \u5185\u6838\u4e2d\u7528\u6765\u5b9e\u73b0\u6d41\u91cf\u63a7\u5236\u548c\u6d41\u91cf\u5206\u7c7b\u7684\u4e00\u4e2a\u673a\u5236\uff0c\u5b83\u53ef\u4ee5\u5c06\u6570\u636e\u5305\u6309\u7167\u4e0d\u540c\u7684\u7c7b\u522b\uff08class\uff09\u8fdb\u884c\u6807\u8bb0\u548c\u533a\u5206\uff0c\u7136\u540e\u5728\u7f51\u7edc\u8bbe\u5907\u4e0a\u9488\u5bf9\u4e0d\u540c\u7684\u7c7b\u522b\u8fdb\u884c\u4e0d\u540c\u7684\u5904\u7406\uff0c\u5982\u9650\u901f\u3001\u4f18\u5148\u7ea7\u8c03\u6574\u7b49\u3002\u63a7\u5236\u7ec4\u4e2d\u7684 net_cls \u5b50\u7cfb\u7edf\u53ef\u4ee5\u7528\u6765\u5c06\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u4e0e\u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\u5173\u8054\u8d77\u6765\uff0c\u4ece\u800c\u5b9e\u73b0\u5bf9\u5b83\u4eec\u7684\u7f51\u7edc\u6d41\u91cf\u8fdb\u884c\u63a7\u5236\u548c\u5206\u7c7b\u3002 \u56e0\u6b64\uff0c\u4ee5\u4e0a\u547d\u4ee4\u662f\u5c06 mygroup \u63a7\u5236\u7ec4\u7684\u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\u8bbe\u7f6e\u4e3a 0x10001 \uff0c\u8fd9\u6837\u4e0e\u8be5\u63a7\u5236\u7ec4\u76f8\u5173\u8054\u7684\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u5c31\u4f1a\u88ab\u6807\u8bb0\u4e3a\u8be5\u7c7b\u522b\uff0c\u7136\u540e\u53ef\u4ee5\u901a\u8fc7\u5176\u4ed6\u5de5\u5177\uff08\u5982 tc \u547d\u4ee4\uff09\u5bf9\u5176\u8fdb\u884c\u7f51\u7edc\u6d41\u91cf\u63a7\u5236\u548c\u5206\u7c7b\u3002 \u5982\u679c\u9047\u5230\u5bf9\u5e94\u9650\u5236\u6587\u4ef6\u4e0d\u5b58\u5728\uff0c\u4e00\u79cd\u53ef\u80fd\u662f\u9700\u8981\u68c0\u67e5cgroup\u5b50\u7cfb\u6709\u6ca1\u6709\u6b63\u786e\u7edf\u8f7d\u6216\u8005\u6ca1\u6709\u542f\u7528\u5185\u5b58\u5b50\u7cfb\u7edf\u3002 mount | grep cgroup \u5982\u679c cgroups \u6587\u4ef6\u7cfb\u7edf\u5df2\u7ecf\u6302\u8f7d\uff0c\u5e94\u8be5\u4f1a\u770b\u5230\u8f93\u51fa\u7c7b\u4f3c\u4e8e\u4ee5\u4e0b\u5185\u5bb9\uff08\uff09\u4ee5memory\u4e3a\u4f8b\uff09\uff1a cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory) \u5982\u679c\u6ca1\u6709\u770b\u5230 memory \u5b57\u6bb5\uff0c\u5219\u8868\u793a\u5185\u5b58\u5b50\u7cfb\u7edf\u6ca1\u6709\u542f\u7528\u3002\u53ef\u4ee5\u7f16\u8f91 /etc/default/grub \u6587\u4ef6\uff0c\u6dfb\u52a0\u6216\u4fee\u6539\u4ee5\u4e0b\u884c\uff1a GRUB_CMDLINE_LINUX_DEFAULT=\"cgroup_enable=memory\" \u7136\u540e\u66f4\u65b0 GRUB \u914d\u7f6e\u5e76\u91cd\u542f\u7cfb\u7edf\uff1a sudo update-grub sudo reboot \u91cd\u542f\u540e\u518d\u6b21\u68c0\u67e5 /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes \u6587\u4ef6\u662f\u5426\u5b58\u5728\u3002\u5982\u679c\u8fd8\u662f\u4e0d\u5b58\u5728\uff0c\u53ef\u80fd\u9700\u8981\u624b\u52a8\u521b\u5efa\u5b83\u4ee5\u53ca\u5176\u4ed6\u76f8\u5173\u7684 cgroups \u6587\u4ef6\u3002\u4f8b\u5982\uff0c\u8fd0\u884c\u4ee5\u4e0b\u547d\u4ee4\uff1a sudo mkdir /sys/fs/cgroup/memory/mygroup sudo touch /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes \u7136\u540e\u5c31\u53ef\u4ee5\u50cf\u4e4b\u524d\u7684\u4f8b\u5b50\u4e00\u6837\u8bbe\u7f6e\u5185\u5b58\u9650\u5236\u4e86","title":"\u63a7\u5236\u7ec4"},{"location":"k8s/cka_cn/foundamentals/docker/#apparmorselinux","text":"\u5b89\u5168\u914d\u7f6e\u6587\u4ef6\uff0c\u7528\u4e8e\u63a7\u5236\u5bf9\u8d44\u6e90\u7684\u8bbf\u95ee AppArmor \u548c SELinux \u90fd\u662f\u5e38\u89c1\u7684\u5f3a\u5236\u8bbf\u95ee\u63a7\u5236\uff08MAC\uff09\u673a\u5236\uff0c\u53ef\u4ee5\u5bf9\u8fdb\u7a0b\u6216\u5e94\u7528\u7a0b\u5e8f\u7684\u8bbf\u95ee\u6743\u9650\u8fdb\u884c\u7cbe\u7ec6\u63a7\u5236\u3002\u4e0b\u9762\u5206\u522b\u4e3e\u4f8b\u8bf4\u660e\u8fd9\u4e24\u79cd\u673a\u5236\u7684\u914d\u7f6e\u6587\u4ef6\u4f7f\u7528\u3002 AppArmor AppArmor \u7684\u4e3b\u914d\u7f6e\u6587\u4ef6\u662f /etc/apparmor/profiles.d/ \u76ee\u5f55\u4e0b\u7684\u5404\u4e2a\u6587\u4ef6\uff0c\u6bcf\u4e2a\u6587\u4ef6\u5bf9\u5e94\u4e00\u4e2a\u5e94\u7528\u7a0b\u5e8f\u6216\u8fdb\u7a0b\u7684\u914d\u7f6e\u3002\u4ee5 sshd \u670d\u52a1\u4e3a\u4f8b\uff0c\u8be5\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6\u662f /etc/apparmor.d/usr.sbin.sshd \u3002 \u8be5\u914d\u7f6e\u6587\u4ef6\u7684\u5185\u5bb9\u7c7b\u4f3c\u4e8e\u4e0b\u9762\u8fd9\u6837\uff1a # Last Modified: Sun Mar 14 18 :53:00 2023 # include /usr/sbin/sshd { # include # include # allow read access to user home directories /home/** r, # allow sshd to execute /usr/bin/which to determine full path of shell /usr/bin/which ix, # allow sshd to read its own configuration file /etc/ssh/sshd_config r, # allow sshd to read the SSH host keys /etc/ssh/ssh_host_* r, # allow sshd to use pam for authentication /usr/share/pam/** r, # allow sshd to use nsswitch for name resolution /etc/nsswitch.conf r, /etc/hosts r, /etc/hostname r, /etc/resolv.conf r, # allow sshd to write to its own log file /var/log/auth.log w, # allow sshd to create and manage pid files /var/run/sshd.pid w, /var/run/sshd.dir/ w, /var/run/sshd.dir/* rw, # allow sshd to access systemd-logind /run/systemd/* r, /run/systemd/session/*.scope r, /run/systemd/sessions/*.scope r, # deny everything else deny /, } \u8be5\u914d\u7f6e\u6587\u4ef6\u5b9a\u4e49\u4e86 /usr/sbin/sshd \u8fdb\u7a0b\u7684\u6743\u9650\u9650\u5236\u89c4\u5219\uff0c\u5305\u62ec\u5141\u8bb8\u8bbf\u95ee\u7684\u6587\u4ef6\u3001\u7981\u6b62\u8bbf\u95ee\u7684\u6587\u4ef6\u7b49\u3002\u5176\u4e2d #include \u8868\u793a\u5305\u542b\u4e86\u4e00\u7ec4\u901a\u7528\u7684\u6743\u9650\u89c4\u5219\uff0c\u53ef\u4ee5\u5728\u4e0d\u540c\u7684\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u4e2d\u91cd\u590d\u4f7f\u7528\u3002 2.SELinux SELinux \u7684\u4e3b\u914d\u7f6e\u6587\u4ef6\u662f /etc/selinux/config \uff0c\u8be5\u6587\u4ef6\u5b9a\u4e49\u4e86\u7cfb\u7edf\u7684 SELinux \u7b56\u7565\u548c\u6a21\u5f0f\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0copenSUSE \u4f7f\u7528\u7684\u662f targeted \u6a21\u5f0f\u3002 \u6bcf\u4e2a\u8fdb\u7a0b\u6216\u5e94\u7528\u7a0b\u5e8f\u8fd8\u9700\u8981\u5bf9\u5e94\u4e00\u4e2a SELinux \u914d\u7f6e\u6587\u4ef6\uff0c\u4ee5\u5b9a\u4e49\u5b83\u4eec\u7684\u8bbf\u95ee\u6743\u9650\u3002\u4ee5 httpd \u670d\u52a1\u4e3a\u4f8b\uff0c\u8be5\u670d\u52a1\u7684 SELinux \u914d\u7f6e\u6587\u4ef6\u662f /etc/selinux/targeted/contexts/httpd.te \u3002 \u8be5\u914d\u7f6e\u6587\u4ef6\u7684\u5185\u5bb9\u7c7b\u4f3c\u4e8e\u4e0b\u9762\u8fd9\u6837\uff1a # HTTPD server type httpd_t ; type httpd_sys_script_t ; init_daemon_domain ( httpd_t, httpd_sys_script_t ) \u8be5\u914d\u7f6e\u6587\u4ef6\u5b9a\u4e49\u4e86 httpd \u670d\u52a1\u7684 SELinux \u7c7b\u578b\u4e3a httpd_t \uff0c\u5e76\u4f7f\u7528\u4e86 httpd_sys_script_t \u4f5c\u4e3a\u5176\u521d\u59cb\u5316\u57df\u3002\u5176\u4e2d type \u8868\u793a SELinux \u7c7b\u578b\uff0c init_daemon_domain \u5219\u662f\u4e00\u4e2a SELinux \u5b8f\uff0c\u7528\u4e8e\u5b9a\u4e49\u670d\u52a1\u7684\u521d\u59cb\u57df\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u5728 SELinux \u4e2d\uff0c\u8bbf\u95ee\u6743\u9650\u89c4\u5219\u4e0d\u662f\u76f4\u63a5\u5728\u914d\u7f6e\u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\uff0c\u800c\u662f\u901a\u8fc7\u8bbf\u95ee\u63a7\u5236\u7b56\u7565\u548c\u89c4\u5219\u8fdb\u884c\u63a7\u5236\u3002\u8fd9\u4e9b\u7b56\u7565\u548c\u89c4\u5219\u53ef\u4ee5\u4f7f\u7528 SELinux \u5de5\u5177\u96c6\uff08\u5982 semanage \u3001 setsebool \u3001 restorecon \u7b49\uff09\u8fdb\u884c\u7ba1\u7406\u548c\u8bbe\u7f6e\u3002 \u6bd4\u5982\uff0c\u5728openSUSE\u4e2d\u53ef\u4ee5\u770b\u5230 /etc/selinux/semanage.conf \u6587\u4ef6\u548c\u5176\u4e2d\u7684\u914d\u7f6e\u3002","title":"Apparmor\u548cSELinux\u914d\u7f6e\u6587\u4ef6"},{"location":"k8s/cka_cn/foundamentals/docker/#_5","text":"\u5185\u6838\u80fd\u529b\uff08Kernel capabilities\uff09 \u6ca1\u6709\u80fd\u529b\uff1aroot\u53ef\u4ee5\u6267\u884c\u6240\u6709\u64cd\u4f5c\uff0c\u5176\u4ed6\u7528\u6237\u53ef\u80fd\u4ec0\u4e48\u4e5f\u505a\u4e0d\u4e86 38\u4e2a\u7ec6\u7c92\u5ea6\u7684\u529f\u80fd\u6765\u63a7\u5236\u6743\u9650 Kernel capabilities \u662f Linux \u5185\u6838\u63d0\u4f9b\u7684\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u63a7\u5236\u8fdb\u7a0b\u5bf9\u7cfb\u7edf\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u3002\u4e0e\u4f20\u7edf\u7684 Unix \u6743\u9650\u673a\u5236\u4e0d\u540c\uff0cKernel capabilities \u53ef\u4ee5\u4f7f\u7ba1\u7406\u5458\u5728\u7cbe\u7ec6\u63a7\u5236\u7cfb\u7edf\u8d44\u6e90\u8bbf\u95ee\u7684\u540c\u65f6\uff0c\u907f\u514d\u5c06\u8fc7\u591a\u6743\u9650\u6388\u4e88\u8fdb\u7a0b\uff0c\u63d0\u9ad8\u4e86\u7cfb\u7edf\u7684\u5b89\u5168\u6027\u3002 \u5728\u4f20\u7edf Unix \u6743\u9650\u673a\u5236\u4e2d\uff0c\u6bcf\u4e2a\u8fdb\u7a0b\u90fd\u6709\u4e00\u4e2a\u6709\u6548\u7528\u6237 ID \u548c\u4e00\u4e2a\u6709\u6548\u7ec4 ID\uff0c\u8fd9\u4e9b ID \u51b3\u5b9a\u4e86\u8be5\u8fdb\u7a0b\u5bf9\u6587\u4ef6\u3001\u8bbe\u5907\u3001\u7f51\u7edc\u7b49\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u3002\u4f46\u662f\uff0c\u8fd9\u79cd\u6743\u9650\u673a\u5236\u4e0d\u591f\u7075\u6d3b\uff0c\u5982\u679c\u8981\u6388\u4e88\u8fdb\u7a0b\u67d0\u4e9b\u7279\u5b9a\u7684\u6743\u9650\uff0c\u53ef\u80fd\u9700\u8981\u5c06\u6240\u6709\u7684\u6743\u9650\u90fd\u6388\u4e88\u7ed9\u5b83\uff0c\u4ece\u800c\u964d\u4f4e\u4e86\u7cfb\u7edf\u7684\u5b89\u5168\u6027\u3002 Kernel capabilities \u63d0\u4f9b\u4e86\u4e00\u79cd\u66f4\u7ec6\u7c92\u5ea6\u7684\u6743\u9650\u63a7\u5236\u65b9\u5f0f\u3002\u6bcf\u4e2a\u8fdb\u7a0b\u90fd\u6709\u4e00\u7ec4 capabilities\uff0c\u6bcf\u4e2a capability \u8868\u793a\u4e00\u79cd\u7279\u5b9a\u7684\u6743\u9650\u3002\u8fdb\u7a0b\u53ef\u4ee5\u8bf7\u6c42\u548c\u91ca\u653e\u67d0\u4e9b capability\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u5c06\u6743\u9650\u6388\u4e88\u8fdb\u7a0b\uff0c\u800c\u4e0d\u5fc5\u6388\u4e88\u6240\u6709\u6743\u9650\u3002 \u4f8b\u5982\uff0c\u53ef\u4ee5\u5c06 CAP_NET_BIND_SERVICE capability \u6388\u4e88\u67d0\u4e2a\u8fdb\u7a0b\uff0c\u8fd9\u6837\u8be5\u8fdb\u7a0b\u5c31\u53ef\u4ee5\u7ed1\u5b9a 1-1023 \u7684\u7aef\u53e3\uff0c\u800c\u4e0d\u5fc5\u5177\u6709 root \u6743\u9650\u3002\u7c7b\u4f3c\u5730\uff0c\u53ef\u4ee5\u5c06 CAP_SYS_ADMIN capability \u6388\u4e88\u67d0\u4e2a\u8fdb\u7a0b\uff0c\u8fd9\u6837\u8be5\u8fdb\u7a0b\u5c31\u53ef\u4ee5\u6267\u884c\u7cfb\u7edf\u7ba1\u7406\u4efb\u52a1\uff0c\u5982\u6302\u8f7d\u6587\u4ef6\u7cfb\u7edf\u548c\u521b\u5efa\u8bbe\u5907\u8282\u70b9\u7b49\u3002 Linux \u5185\u6838\u63d0\u4f9b\u4e86\u4e00\u7ec4\u9ed8\u8ba4\u7684 capabilities\uff0c\u4e5f\u53ef\u4ee5\u901a\u8fc7\u81ea\u5b9a\u4e49\u7684\u65b9\u5f0f\u521b\u5efa\u65b0\u7684 capabilities\uff0c\u4ee5\u4fbf\u66f4\u597d\u5730\u63a7\u5236\u7cfb\u7edf\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u3002\u53ef\u4ee5\u4f7f\u7528 setcap \u547d\u4ee4\u4e3a\u4e8c\u8fdb\u5236\u6587\u4ef6\u8bbe\u7f6e capabilities\u3002\u4f8b\u5982\uff0c\u4e0b\u9762\u7684\u547d\u4ee4\u5c06 CAP_NET_RAW capability \u6388\u4e88 /usr/bin/ping \u547d\u4ee4\uff1a sudo setcap cap_net_raw+ep /usr/bin/ping \u8fd9\u6837\uff0c\u7528\u6237\u5c31\u53ef\u4ee5\u4f7f\u7528 ping \u547d\u4ee4\u800c\u4e0d\u5fc5\u4ee5 root \u7528\u6237\u7684\u8eab\u4efd\u767b\u5f55\u3002 \u9664\u4e86 CAP_NET_BIND_SERVICE \u548c CAP_SYS_ADMIN \uff0c\u8fd8\u6709\u4e00\u4e9b\u5176\u4ed6\u7684 capabilities\uff0c\u4ee5\u4e0b\u662f\u4e00\u4e9b\u4f8b\u5b50\uff1a CAP_DAC_OVERRIDE \uff1a\u5141\u8bb8\u8fdb\u7a0b\u5ffd\u7565\u6587\u4ef6\u6743\u9650\uff0c\u53ef\u4ee5\u8bbf\u95ee\u4efb\u4f55\u6587\u4ef6\u3002 CAP_CHOWN \uff1a\u5141\u8bb8\u8fdb\u7a0b\u4fee\u6539\u6587\u4ef6\u7684\u6240\u6709\u8005\u3002 CAP_SETUID \u548c CAP_SETGID \uff1a\u5141\u8bb8\u8fdb\u7a0b\u4fee\u6539\u81ea\u5df1\u7684\u7528\u6237 ID \u548c\u7ec4 ID\u3002 CAP_NET_ADMIN \uff1a\u5141\u8bb8\u8fdb\u7a0b\u6267\u884c\u7f51\u7edc\u7ba1\u7406\u4efb\u52a1\uff0c\u5982\u914d\u7f6e\u7f51\u7edc\u63a5\u53e3\u548c\u8def\u7531\u8868\u7b49\u3002 CAP_SYS_RESOURCE \uff1a\u5141\u8bb8\u8fdb\u7a0b\u4fee\u6539\u7cfb\u7edf\u8d44\u6e90\u9650\u5236\uff0c\u5982 CPU \u65f6\u95f4\u548c\u5185\u5b58\u9650\u5236\u7b49\u3002 \u53ef\u4ee5\u901a\u8fc7\u547d\u4ee4 man 7 capabilities \u6765\u67e5\u770b\u7cfb\u7edf\u63d0\u4f9b\u7684 capabilities \u5217\u8868\u548c\u8be6\u7ec6\u8bf4\u660e\u3002\u5728\u4f7f\u7528 Kernel capabilities \u65f6\uff0c\u9700\u8981\u6ce8\u610f\uff0c\u53ea\u6709\u62e5\u6709 CAP_SETFCAP \u6216 CAP_SYS_ADMIN capability \u7684\u8fdb\u7a0b\u624d\u80fd\u591f\u4fee\u6539\u81ea\u5df1\u6216\u5176\u4ed6\u8fdb\u7a0b\u7684 capabilities\uff0c\u8fd9\u4e5f\u662f\u4e3a\u4e86\u4fdd\u62a4\u7cfb\u7edf\u7684\u5b89\u5168\u6027\u3002 \u5982\u679c\u6267\u884c setcap \u547d\u4ee4\u65f6\u51fa\u73b0 \"command not found\" \u7684\u9519\u8bef\uff0c\u8fd9\u901a\u5e38\u610f\u5473\u7740 setcap \u547d\u4ee4\u6240\u5728\u7684\u5305\u5c1a\u672a\u5b89\u88c5\u3002\u5728 openSUSE \u4e2d\uff0csetcap \u547d\u4ee4\u5305\u542b\u5728 libcap-progs \u8f6f\u4ef6\u5305\u4e2d\u3002 \u5728 openSUSE \u7cfb\u7edf\u4e2d\u9700\u8981\u5b89\u88c5 libcap-progs \u8f6f\u4ef6\u5305\uff1a sudo zypper in libcap-progs \u5728 Ubuntu/Debian \u7cfb\u7edf\u4e0a\u9700\u8981\u5b89\u88c5 libcap \u5e93\uff1a sudo apt-get install libcap2-bin \u5728 CentOS/RHEL \u7cfb\u7edf\u4e0a\u9700\u8981\u5b89\u88c5 libcap \u5e93\uff1a sudo yum install libcap-devel \u5b89\u88c5\u5b8c\u6210\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528 setcap \u547d\u4ee4\u4e3a\u4e8c\u8fdb\u5236\u6587\u4ef6\u8bbe\u7f6e capabilities\u3002\u5982\u679c\u8fd8\u662f\u65e0\u6cd5\u627e\u5230 setcap \u547d\u4ee4\uff0c\u53ef\u4ee5\u5c1d\u8bd5\u4f7f\u7528\u5b8c\u6574\u8def\u5f84 /sbin/setcap \u6216\u8005 /usr/sbin/setcap\u3002","title":"\u5185\u6838\u80fd\u529b"},{"location":"k8s/cka_cn/foundamentals/docker/#seccomp","text":"seccomp\uff08secure computing mode\uff09\u662f Linux \u5185\u6838\u63d0\u4f9b\u7684\u4e00\u79cd\u5b89\u5168\u673a\u5236\uff0c\u5b83\u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u80fd\u591f\u8fdb\u884c\u7684\u7cfb\u7edf\u8c03\u7528\u3002\u901a\u8fc7\u4f7f\u7528 seccomp\uff0c\u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u53ea\u80fd\u591f\u4f7f\u7528\u5fc5\u8981\u7684\u7cfb\u7edf\u8c03\u7528\uff0c\u4ece\u800c\u51cf\u5c11\u7cfb\u7edf\u88ab\u653b\u51fb\u7684\u98ce\u9669\u3002 seccomp \u7b56\u7565\u53ef\u4ee5\u4f7f\u7528 BPF\uff08Berkeley Packet Filter\uff09\u8bed\u8a00\u7f16\u5199\uff0c\u5e76\u4f7f\u7528 seccomp() \u7cfb\u7edf\u8c03\u7528\u52a0\u8f7d\u3002\u4ee5\u4e0b\u662f\u4e00\u4e2a\u4f7f\u7528 seccomp \u7b56\u7565\u9650\u5236\u8fdb\u7a0b\u80fd\u591f\u8fdb\u884c\u7684\u7cfb\u7edf\u8c03\u7528\u7684\u793a\u4f8b\uff1a #include #include #include int main () { // \u521b\u5efa seccomp \u8fc7\u6ee4\u5668 struct sock_filter filter [] = { BPF_STMT ( BPF_LD | BPF_W | BPF_ABS , 0 ), BPF_JUMP ( BPF_JMP | BPF_JEQ | BPF_K , __NR_write , 0 , 1 ), BPF_STMT ( BPF_RET | BPF_K , SECCOMP_RET_ALLOW ), BPF_STMT ( BPF_RET | BPF_K , SECCOMP_RET_KILL ), }; struct sock_fprog prog = { . len = sizeof ( filter ) / sizeof ( filter [ 0 ]), . filter = filter , }; // \u52a0\u8f7d seccomp \u8fc7\u6ee4\u5668 if ( prctl ( PR_SET_SECCOMP , SECCOMP_MODE_FILTER , & prog ) < 0 ) { perror ( \"prctl\" ); return 1 ; } // \u8c03\u7528 write \u7cfb\u7edf\u8c03\u7528 char buf [] = \"Hello, world!\" ; write ( 1 , buf , sizeof ( buf )); return 0 ; } \u4e0a\u8ff0\u4ee3\u7801\u521b\u5efa\u4e86\u4e00\u4e2a seccomp \u8fc7\u6ee4\u5668\uff0c\u4ec5\u5141\u8bb8\u8fdb\u7a0b\u8c03\u7528 write() \u7cfb\u7edf\u8c03\u7528\uff0c\u5176\u4ed6\u7cfb\u7edf\u8c03\u7528\u5747\u4f1a\u88ab\u7981\u6b62\u3002\u53ef\u4ee5\u901a\u8fc7\u7f16\u8bd1\u5e76\u8fd0\u884c\u4e0a\u8ff0\u4ee3\u7801\u6765\u6f14\u793a seccomp \u7b56\u7565\u7684\u4f5c\u7528\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0cseccomp \u7b56\u7565\u53ea\u80fd\u591f\u9650\u5236\u8fdb\u7a0b\u8fdb\u884c\u7684\u7cfb\u7edf\u8c03\u7528\uff0c\u4f46\u4e0d\u80fd\u591f\u9650\u5236\u7cfb\u7edf\u8c03\u7528\u7684\u53c2\u6570\u6216\u8fd4\u56de\u503c\u3002\u56e0\u6b64\uff0c\u4f7f\u7528 seccomp \u7b56\u7565\u65f6\u9700\u8981\u7279\u522b\u5c0f\u5fc3\uff0c\u907f\u514d\u8bef\u7528\u6216\u4ea7\u751f\u6f0f\u6d1e\u3002","title":"seccomp\u7b56\u7565"},{"location":"k8s/cka_cn/foundamentals/docker/#netlink","text":"Netlink \u662f\u4e00\u79cd Linux \u5185\u6838\u63d0\u4f9b\u7684\u901a\u4fe1\u673a\u5236\uff0c\u7528\u4e8e\u5185\u6838\u548c\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4e4b\u95f4\u7684\u53cc\u5411\u901a\u4fe1\uff08IPC\uff09\u3002Netlink \u53ef\u4ee5\u7528\u4e8e\u8bb8\u591a\u76ee\u7684\uff0c\u4f8b\u5982\uff1a \u914d\u7f6e\u7f51\u7edc\u8bbe\u5907\u548c\u8def\u7531\u8868\uff1a\u4f7f\u7528 Netlink \u53ef\u4ee5\u901a\u8fc7\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4fee\u6539\u5185\u6838\u7684\u7f51\u7edc\u8bbe\u5907\u548c\u8def\u7531\u8868\u914d\u7f6e\uff0c\u4f8b\u5982\u6dfb\u52a0\u3001\u5220\u9664\u3001\u4fee\u6539\u7f51\u7edc\u63a5\u53e3\u3001IP \u5730\u5740\u3001\u8def\u7531\u7b49\u3002 \u76d1\u89c6\u7f51\u7edc\u4e8b\u4ef6\uff1a\u4f7f\u7528 Netlink \u53ef\u4ee5\u5b9e\u65f6\u5730\u4ece\u5185\u6838\u83b7\u53d6\u7f51\u7edc\u4e8b\u4ef6\u7684\u901a\u77e5\uff0c\u4f8b\u5982\u7f51\u7edc\u63a5\u53e3\u7684\u72b6\u6001\u53d8\u5316\u3001\u8def\u7531\u7684\u53d8\u5316\u7b49\u3002 \u7a0b\u5e8f\u95f4\u901a\u4fe1\uff1a\u4f7f\u7528 Netlink \u53ef\u4ee5\u5728\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4e4b\u95f4\u8fdb\u884c\u901a\u4fe1\uff0c\u7c7b\u4f3c\u4e8e Unix \u57df\u5957\u63a5\u5b57\u3002 Netlink \u673a\u5236\u57fa\u4e8e\u4e00\u79cd\u7279\u6b8a\u7684\u5957\u63a5\u5b57\u7c7b\u578b\uff08PF_NETLINK\uff09\u548c\u4e00\u4e2a\u7279\u5b9a\u7684\u534f\u8bae\uff08NETLINK\uff09\u3002\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u53ef\u4ee5\u901a\u8fc7\u521b\u5efa Netlink \u5957\u63a5\u5b57\u548c\u5185\u6838\u901a\u4fe1\u3002\u5185\u6838\u548c\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4e4b\u95f4\u7684\u901a\u4fe1\u662f\u57fa\u4e8e Netlink \u6d88\u606f\u7684\uff0c\u6bcf\u4e2a Netlink \u6d88\u606f\u5305\u542b\u4e00\u4e2a\u6d88\u606f\u5934\u548c\u4e00\u4e2a\u8d1f\u8f7d\uff08payload\uff09\uff0c\u8d1f\u8f7d\u53ef\u4ee5\u662f\u4efb\u4f55\u7ed3\u6784\u4f53\u6216\u4e8c\u8fdb\u5236\u6570\u636e\u3002 Netlink \u6d88\u606f\u7684\u7c7b\u578b\u548c\u683c\u5f0f\u7531\u5185\u6838\u5b9a\u4e49\u3002\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u9700\u8981\u4e86\u89e3\u5185\u6838\u7684 Netlink \u6d88\u606f\u683c\u5f0f\u548c\u7c7b\u578b\uff0c\u624d\u80fd\u6b63\u786e\u5730\u6784\u9020\u548c\u89e3\u6790 Netlink \u6d88\u606f\u3002\u5e38\u7528\u7684 Netlink \u6d88\u606f\u7c7b\u578b\u5305\u62ec\uff1a RTM_NEWLINK \u548c RTM_DELLINK\uff1a\u6dfb\u52a0\u548c\u5220\u9664\u7f51\u7edc\u63a5\u53e3\u3002 RTM_NEWADDR \u548c RTM_DELADDR\uff1a\u6dfb\u52a0\u548c\u5220\u9664 IP \u5730\u5740\u3002 RTM_NEWROUTE \u548c RTM_DELROUTE\uff1a\u6dfb\u52a0\u548c\u5220\u9664\u8def\u7531\u3002 RTM_NEWNEIGH \u548c RTM_DELNEIGH\uff1a\u6dfb\u52a0\u548c\u5220\u9664 ARP \u8868\u9879\u3002 Netlink \u53ef\u4ee5\u4f7f\u7528 C \u8bed\u8a00\u7684 socket API \u8fdb\u884c\u7f16\u7a0b\u3002","title":"Netlink"},{"location":"k8s/cka_cn/foundamentals/docker/#netfilter","text":"Netfilter\u662fLinux\u5185\u6838\u4e2d\u7684\u4e00\u4e2a\u5b50\u7cfb\u7edf\uff0c\u7528\u4e8e\u5728\u6570\u636e\u5305\u4f20\u8f93\u8fc7\u7a0b\u4e2d\u8fdb\u884c\u8fc7\u6ee4\u548c\u64cd\u4f5c\u3002\u5b83\u652f\u6301\u5bf9\u7f51\u7edc\u6570\u636e\u5305\u8fdb\u884c\u5404\u79cd\u7c7b\u578b\u7684\u5904\u7406\uff0c\u5305\u62ec\u8fc7\u6ee4\u3001\u4fee\u6539\u3001\u91cd\u5b9a\u5411\u7b49\u3002Netfilter\u901a\u8fc7\u5728\u5185\u6838\u4e2d\u6ce8\u518c\u94a9\u5b50\u51fd\u6570\uff0c\u5728\u6570\u636e\u5305\u901a\u8fc7\u7f51\u7edc\u6808\u7684\u4e0d\u540c\u9636\u6bb5\u65f6\u8fdb\u884c\u62e6\u622a\u548c\u5904\u7406\u3002 Netfilter\u7684\u6838\u5fc3\u662fiptables\u547d\u4ee4\uff0c\u5b83\u53ef\u4ee5\u7528\u6765\u914d\u7f6eNetfilter\u89c4\u5219\u3002iptables\u547d\u4ee4\u53ef\u4ee5\u7528\u6765\u914d\u7f6e\u9632\u706b\u5899\u89c4\u5219\uff0cNAT\u89c4\u5219\uff0c\u9650\u5236\u8fde\u63a5\u901f\u5ea6\u7b49\u3002iptables\u547d\u4ee4\u901a\u8fc7\u5339\u914d\u4e0d\u540c\u7684\u6570\u636e\u5305\u5b57\u6bb5\uff08\u4f8b\u5982\u6e90IP\u5730\u5740\u3001\u76ee\u7684IP\u5730\u5740\u3001\u6e90\u7aef\u53e3\u3001\u76ee\u7684\u7aef\u53e3\u7b49\uff09\u6765\u8fdb\u884c\u8fc7\u6ee4\u3002 \u9664\u4e86iptables\u547d\u4ee4\uff0c\u8fd8\u6709\u5176\u4ed6\u4e00\u4e9b\u5de5\u5177\u53ef\u4ee5\u7528\u4e8e\u914d\u7f6eNetfilter\u89c4\u5219\uff0c\u4f8b\u5982nftables\u547d\u4ee4\u548cfirewalld\u670d\u52a1\u3002\u8fd9\u4e9b\u5de5\u5177\u63d0\u4f9b\u4e86\u66f4\u7075\u6d3b\u3001\u66f4\u5f3a\u5927\u7684\u914d\u7f6e\u9009\u9879\uff0c\u53ef\u4ee5\u5e2e\u52a9\u7ba1\u7406\u5458\u66f4\u597d\u5730\u7ba1\u7406\u548c\u4fdd\u62a4\u7f51\u7edc\u5b89\u5168\u3002 \u4e5f\u53ef\u4ee5\u7528\u4e8e\u5c06\u7f51\u7edc\u6570\u636e\u5305\u5b9a\u5411\u5230\u5355\u4e2a\u5bb9\u5668\u3002 \u66f4\u591a\u4fe1\u606f\u53ef\u4ee5\u53c2\u8003 LXC/LXD \u3002","title":"Netfilter"},{"location":"k8s/cka_cn/foundamentals/docker/#docker","text":"\u53c2\u8003 \u6307\u5bfc \u5b89\u88c5Docker\u5f15\u64ce\u3002 \u53c2\u8003 \u6307\u5bfc \u5b89\u88c5Docker\u684c\u9762\u7248\u3002 \u4e0b\u9762\u4ee5openSUSE\u4e3a\u4f8b\u5b89\u88c5Docker\u5f15\u64ce\u3002 sudo zypper in docker \u5728\u5b89\u88c5\u8fc7\u7a0b\u4e2d\uff0c\u5728\u64cd\u4f5c\u7cfb\u7edf\u4e2d\u4f1a\u81ea\u52a8\u521b\u5efa\u7ec4 docker \u3002 \u5c06vagrant\u7528\u6237\u52a0\u5165docker\u7ec4\uff0c\u5219vagrant\u7528\u6237\u53ef\u4ee5\u5728\u4e0b\u6b21\u767b\u5f55\u540e\u4e0e\u672c\u673a\u7684Docker\u5b88\u62a4\u8fdb\u7a0b\uff08daemon\uff09\u8fdb\u884c\u901a\u4fe1\u3002Docker\u5b88\u62a4\u8fdb\u7a0b\u76d1\u542c\u672c\u5730\u5957\u63a5\u5b57\uff0c\u53ea\u80fd\u7531root\u7528\u6237\u548cdocker\u7ec4\u7684\u6210\u5458\u8bbf\u95ee\u3002 sudo usermod -aG docker $USER \u542f\u7528\u5e76\u542f\u52a8 Docker \u5f15\u64ce\u3002 sudo systemctl enable docker.service sudo systemctl start docker.service sudo systemctl status docker.service \u4e0b\u9762\u901a\u8fc7\u4e00\u4e2a\u5bb9\u5668 alpine \u7684\u4f8b\u5b50\u6765\u6f14\u793a\u5728\u76ee\u5f55 /opt/test \u4e0b\u6a21\u62df\u5b9e\u73b0choot\u3002 mkdir test cd test wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.4-x86_64.tar.gz tar zxvf alpine-minirootfs-3.13.4-x86_64.tar.gz -C alpine-minirootfs/ \u67e5\u770b\u5f53\u524d\u76ee\u5f55\u7ed3\u6784\uff1a tree ./test -L 1 \u8f93\u51fa\u7ed3\u679c\uff1a ./test \u251c\u2500\u2500 alpine-minirootfs-3.13.4-x86_64.tar.gz \u251c\u2500\u2500 bin \u251c\u2500\u2500 dev \u251c\u2500\u2500 etc \u251c\u2500\u2500 home \u251c\u2500\u2500 lib \u251c\u2500\u2500 media \u251c\u2500\u2500 mnt \u251c\u2500\u2500 opt \u251c\u2500\u2500 proc \u251c\u2500\u2500 root \u251c\u2500\u2500 run \u251c\u2500\u2500 sbin \u251c\u2500\u2500 srv \u251c\u2500\u2500 sys \u251c\u2500\u2500 tmp \u251c\u2500\u2500 usr \u2514\u2500\u2500 var \u901a\u8fc7\u547d\u4ee4 unshare \u6302\u8f7d\u76ee\u5f55 /opt/test/proc \u5230\u67d0\u4e2a\u6587\u4ef6\u6765\u5b9e\u73b0\u5ba2\u6237\u5b50\u7cfb\u7edf\u3002 sudo mount -t tmpfs tmpfs /opt/test/proc sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # ps -ef PID USER TIME COMMAND 1 root 0 :00 /bin/sh 2 root 0 :00 ps -ef / # touch 123 / # ls 123 123 \u6587\u4ef6 123 \u5728\u5ba2\u6237\u5b50\u7cfb\u7edf\u4e2d\u5df2\u521b\u5efa\uff0c\u5bf9\u5e94\u4e3b\u7cfb\u7edf\u4e2d\u4e5f\u53ef\u4ee5\u5bf9\u5176\u8fdb\u884c\u8bfb\u5199\u64cd\u4f5c\u3002\u6bd4\u5982\uff0c\u4fee\u6539\u6587\u4ef6 123 \u7684\u5185\u5bb9\u3002 su - ls 123 echo hello > 123 \u6587\u4ef6 123 \u4fee\u6539\u540e\u7684\u5185\u5bb9\u5728\u5ba2\u6237\u673a\u91cc\u9762\u4e5f\u53ef\u89c1\u3002 / # cat 123 hello \u5728\u4e3b\u7cfb\u7edf\u4e2d\u518d\u521b\u5efa\u4e24\u4e2a\u5b50\u76ee\u5f55 /opt/test-1 \u548c /opt/test-2 \u3002 mkdir test-1 mkdir test-2 \u521b\u5efa2\u4e2a\u5ba2\u6237\u5b50\u7cfb\u7edf\uff0c\u5e76\u5c06\u4e0a\u9762\u7684\u4e24\u4e2a\u5b50\u76ee\u5f55\u6302\u5728\u5230\u5404\u81ea\u7684 /opt/test/home/ \u76ee\u5f55\u3002 sudo mount --bind /opt/test-1 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-1\" > 123.1 /home # cat 123.1 test-1 sudo mount --bind /opt/test-2 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-2\" > 123.2 /home # cat 123.2 test-2 ll test/home ll test-1/ ll test-2/ \u901a\u8fc7\u4e0a\u9762\u7684\u6f14\u793a\uff0c\u53ef\u4ee5\u5f97\u51fa\u7ed3\u8bba\uff0c\u4e24\u4e2a\u5ba2\u6237\u5b50\u7cfb\u7edf\u6302\u5728\u5230\u540c\u4e00\u4e2a\u4e3b\u7cfb\u7edf\u76ee\u5f55\u65f6\uff0c\u5b50\u7cfb\u7edf\u65f6\u5171\u4eab\u4e3b\u7cfb\u7edf\u76ee\u5f55\uff0c\u5e76\u76f8\u4e92\u5f71\u54cd\u3002","title":"\u5b89\u88c5Docker"},{"location":"k8s/cka_cn/foundamentals/docker/#_6","text":"","title":"\u5bb9\u5668\u751f\u547d\u5468\u671f"},{"location":"k8s/cka_cn/foundamentals/docker/#_7","text":"\u9884\u5148\u4e0b\u8f7d\u4e0b\u5217\u955c\u50cf\u3002 docker image pull busybox docker image pull nginx docker image pull alpine docker image pull jenkins/jenkins:lts docker image pull golang:1.12-alpine docker image pull golang \u521b\u5efa\u5e76\u4ea4\u4e92\u5f0f\u8fd0\u884c\u4e00\u4e2a\u65b0\u7684busybox\u5bb9\u5668\uff0c\u5e76\u8fde\u63a5\u4e00\u4e2a\u4f2a\u7ec8\u7aef\uff08pseudo terminal\uff09\u3002 \u5728\u5bb9\u5668\u5185\uff0c\u4f7f\u7528 top \u547d\u4ee4\u67e5\u627e /bin/sh \u6b63\u5728\u4f5c\u4e3aPID\u4e3a1\u7684\u8fdb\u7a0b\u8fd0\u884c\uff0c\u4ee5\u53ca top \u8fdb\u7a0b\u4e5f\u5728\u8fd0\u884c\u3002 \u7136\u540e\uff0c\u9000\u51fa\u5bb9\u5668\u3002 docker image ls docker run -d -it --name busybox_v1 -v /opt/test:/docker busybox:latest /bin/sh docker container ps -a docker exec -it 185efe490507 /bin/sh / # top Mem: 3627396K used, 12731512K free, 10080K shrd, 2920K buff, 2999340K cached CPU: 0 .0% usr 0 .1% sys 0 .0% nic 99 .8% idle 0 .0% io 0 .0% irq 0 .0% sirq Load average: 0 .38 1 .09 1 .29 2 /277 14 PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND 1 0 root S 1332 0 .0 1 0 .0 /bin/sh 8 0 root S 1332 0 .0 2 0 .0 /bin/sh 14 8 root R 1328 0 .0 1 0 .0 top / # exitbuild \u542f\u52a8\u4e00\u4e2a\u65b0\u7684 Nginx \u5bb9\u5668\uff0c\u5e76\u4ee5\u72ec\u7acb\u6a21\u5f0f\uff08detached mode\uff09\u8fd0\u884c\u3002 \u4f7f\u7528 docker exec \u547d\u4ee4\u5728 Nginx \u5bb9\u5668\u4e2d\u542f\u52a8\u53e6\u4e00\u4e2a shell\uff08 /bin/sh \uff09\u3002 \u4f7f\u7528 ps \u547d\u4ee4\u67e5\u770b\u5bb9\u5668\u4e2d\u6b63\u5728\u8fd0\u884c\u7684 sh \u548c ps \u547d\u4ee4\uff08\u5728\u4e0a\u4e00\u6b65\u6267\u884c\u7684\uff09\u3002 docker run -d -it --name nginx_v1 -v /opt/test:/docker nginx:latest /bin/sh docker container ps -a docker exec -it edb640127a0d /bin/sh # ps /bin/sh: 2 : ps: not found # apt-get update && apt-get install -y procps # ps PID TTY TIME CMD 8 pts/1 00 :00:00 sh 351 pts/1 00 :00:00 ps # exit \u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u770b\u52302\u4e2a\u73b0\u5728\u8fd0\u884c\u4e2d\u7684\u5bb9\u5668\u3002 docker container ps -a \u4f7f\u7528 docker logs \u547d\u4ee4\u663e\u793a\u6211\u4eec\u521a\u521a\u9000\u51fa\u7684\u5bb9\u5668\u7684\u65e5\u5fd7\u3002\u9009\u9879 --since 35m \u8868\u793a\u663e\u793a\u6700\u8fd1 35 \u5206\u949f\u5185\u7684\u65e5\u5fd7\u3002 docker logs nginx_v1 --details --since 35m docker logs busybox_v1 --details --since 35m \u4f7f\u7528 docker stop \u547d\u4ee4\u6765\u505c\u6b62 nginx \u5bb9\u5668\u3002 docker stop busybox_v1 docker stop nginx_v1 docker container ps -a \u4f7f\u7528\u4e0a\u8ff0\u547d\u4ee4 docker container ps -a \uff0c\u6211\u4eec\u53ef\u4ee5\u83b7\u53d6\u6240\u6709\u6b63\u5728\u8fd0\u884c\u548c\u5df2\u9000\u51fa\u7684\u5bb9\u5668\u5217\u8868\u3002\u4f7f\u7528 docker rm \u5c06\u5176\u5220\u9664\u3002\u4f7f\u7528 docker rm $(docker ps -aq) \u6765\u6e05\u7406\u4e3b\u673a\u4e0a\u7684\u6240\u6709\u5bb9\u5668\u3002\u8bf7\u8c28\u614e\u4f7f\u7528\uff01 docker rm busybox_v1 docker container ps -a","title":"\u6982\u8ff0"},{"location":"k8s/cka_cn/foundamentals/docker/#_8","text":"\u73b0\u5728\u542f\u52a8\u4e00\u4e2a\u65b0\u7684 nginx \u5bb9\u5668\uff0c\u5e76\u5c06 nginx web \u670d\u52a1\u5668\u7684\u7aef\u53e3\u5bfc\u51fa\u5230 Docker \u968f\u673a\u9009\u62e9\u7684\u7aef\u53e3\u3002 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u547d\u4ee4 docker ps \u627e\u51fa web \u670d\u52a1\u5668\u8f6c\u53d1\u5230\u4e86\u54ea\u4e2a\u7aef\u53e3\u3002\u5728\u4e3b\u673a\u4e0a\u4f7f\u7528\u8f6c\u53d1\u7684\u7aef\u53e3\u53f7\u8bbf\u95ee docker http://localhost: \u3002 docker container ps -a docker run -d -P --name nginx_v2 nginx:latest docker container ps -a Start another nginx container and expose port to 1080 on host as an example via http://localhost:1080 . \u542f\u52a8\u53e6\u4e00\u4e2anginx\u5bb9\u5668\uff0c\u5c06\u5176\u7aef\u53e3\u6620\u5c04\u5230\u4e3b\u673a\u76841080\u7aef\u53e3\uff0c\u53ef\u4ee5\u901a\u8fc7 http://localhost:1080 \u8bbf\u95ee\u3002 docker run -d -p 1080 :80 --name nginx_v3 nginx:latest docker container ps -a \u4f7f\u7528 docker inspect \u547d\u4ee4\u67e5\u627e\u955c\u50cf\u66b4\u9732\u7684\u7aef\u53e3\u53f7\uff0c\u8f93\u51faJSON\u683c\u5f0f\u6587\u4ef6\uff0c\u7f51\u7edc\u4fe1\u606f\uff08IP\u3001\u7f51\u5173\u3001\u7aef\u53e3\u7b49\uff09\u662f\u8f93\u51faJSON\u683c\u5f0f\u7684\u4e00\u90e8\u5206\u3002 docker inspect nginx_v3 \u5728\u76ee\u5f55 /opt/test \u4e2d\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a index.html \u7684\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u5982\u4e0b\uff1a < html > < head > < title > Sample Website from my container < body > < h1 > This is a custom website. < p > This website is served from my < a href = \"http://www.docker.com\" target = \"_blank\" > Docker container. \u542f\u52a8\u4e00\u4e2a\u65b0\u5bb9\u5668\uff0c\u5c06\u4e3b\u673a\u76ee\u5f55 /opt/test \u4e0e\u5bb9\u5668\u76ee\u5f55 /usr/share/nginx/html \u7ed1\u5b9a\u6302\u8f7d\u4e3a\u4e00\u4e2a\u5377\uff0c\u4ee5\u4fbfNginx\u53ef\u4ee5\u901a\u8fc7 http://localhost:49159/ \u53d1\u5e03\u6211\u4eec\u521a\u521b\u5efa\u7684html\u6587\u4ef6\uff0c\u800c\u4e0d\u662fNginx\u9ed8\u8ba4\u7684\u9875\u9762\u3002 docker run -d -P --mount type = bind,source = /opt/test/,target = /usr/share/nginx/html --name nginx_v3-1 nginx:latest docker container ps -a \u68c0\u67e5Nginx\u914d\u7f6e\u6587\u4ef6\uff0c\u67e5\u770b\u5bb9\u5668\u4e2dhtml\u4e3b\u9875\u5b58\u50a8\u7684\u4f4d\u7f6e\u3002 docker exec -it nginx_v3-1 /bin/sh # cd /etc/nginx/conf.d # ls default.conf # cat default.conf server { listen 80 ; listen [ :: ] :80 ; server_name localhost ; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html ; <-- index index.html index.htm ; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html ; location = /50x.html { root /usr/share/nginx/html ; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \\.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \\.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\\.ht { # deny all; #} } # cd /usr/share/nginx/html # cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    # \u63a8\u8350\u4f7f\u7528\u5377 API \u6765\u5b9e\u73b0\u6570\u636e\u6301\u4e45\u5316\uff0c\u800c\u4e0d\u662f\u5c06\u6570\u636e\u5b58\u50a8\u5728 Docker \u5bb9\u5668\u4e2d\u3002Docker \u652f\u6301\u4e24\u79cd\u6302\u8f7d\u65b9\u5f0f\uff1a \u7ed1\u5b9a\u6302\u8f7d\uff08Bind mounts\uff09\uff1a \u5c06\u672c\u5730\u4e3b\u673a\u76ee\u5f55\u6302\u8f7d\u5230\u5bb9\u5668\u4e2d\u7684\u67d0\u4e2a\u8def\u5f84\u3002 \u6302\u8f7d\u540e\uff0c\u76ee\u6807\u76ee\u5f55\u4e2d\u539f\u6709\u7684\u6240\u6709\u5185\u5bb9\u5c06\u88ab\u9690\u85cf\u3002 \u4f8b\u5982\uff0c\u5982\u679c\u6211\u4eec\u60f3\u8981\u6ce8\u5165\u67d0\u4e9b\u914d\u7f6e\u6587\u4ef6\uff0c\u6211\u4eec\u9700\u8981\u81ea\u5df1\u5199\u5bf9\u5e94\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5c06\u5176\u5b58\u50a8\u5728 Docker \u4e3b\u673a\u4e0a\u7684 /home/container/config \u8def\u5f84\u4e0b\uff0c\u5e76\u5c06\u6b64\u76ee\u5f55\u7684\u5185\u5bb9\u6302\u8f7d\u5230 /usr/application/config \uff08\u5047\u8bbe\u5e94\u7528\u7a0b\u5e8f\u4ece\u6b64\u5904\u8bfb\u53d6\u914d\u7f6e\uff09\u3002 \u547d\u4ee4\uff1a docker run --mount type=bind,source=,target= \u2026 \u547d\u540d\u5377\uff08Named volumes\uff09\uff1a Docker \u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u72ec\u7acb\u7684\u5b58\u50a8\u5377\uff0c\u5176\u751f\u547d\u5468\u671f\u72ec\u7acb\u4e8e\u5bb9\u5668\u4f46\u4ecd\u7531 Docker \u7ba1\u7406\u3002 \u5728\u521b\u5efa\u65f6\uff0c\u6302\u8f7d\u76ee\u6807\u7684\u5185\u5bb9\u5c06\u5408\u5e76\u5230\u5377\u4e2d\u3002 \u547d\u4ee4\uff1a docker run --mount source=,target= \u2026 \u5982\u4f55\u533a\u5206\u7ed1\u5b9a\u6302\u8f7d\u548c\u547d\u540d\u5377\uff1f \u5f53\u6307\u5b9a\u7edd\u5bf9\u8def\u5f84\u65f6\uff0cDocker \u4f1a\u8ba4\u4e3a\u8fd9\u662f\u4e00\u4e2a\u7ed1\u5b9a\u6302\u8f7d\u3002 \u5f53\u6211\u4eec\u4ec5\u63d0\u4f9b\u540d\u79f0\uff08\u5982\u76f8\u5bf9\u8def\u5f84 config \uff09\u65f6\uff0c\u5b83\u4f1a\u8ba4\u4e3a\u8fd9\u662f\u4e00\u4e2a\u547d\u540d\u5377\uff0c\u5e76\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a config \u7684\u5377\u3002 \u6ce8\uff1a\u6301\u4e45\u5b58\u50a8\u7531\u4e3b\u673a\u63d0\u4f9b\uff0c\u53ef\u4ee5\u76f4\u63a5\u662f\u4e3b\u673a\u6587\u4ef6\u7cfb\u7edf\u7684\u4e00\u90e8\u5206\uff0c\u4e5f\u53ef\u4ee5\u662f NFS \u6302\u8f7d\u3002","title":"\u7aef\u53e3\u548c\u5377"},{"location":"k8s/cka_cn/foundamentals/docker/#dockerfile","text":"\u8ba9\u6211\u4eec\u7528 Dockerfile \u6784\u5efa\u4e00\u4e2a\u955c\u50cf\uff0c\u5bf9\u5176\u8fdb\u884c\u6253\u6807\u7b7e\u5e76\u4e0a\u4f20\u5230\u955c\u50cf\u4ed3\u5e93\u3002 \u83b7\u53d6 Docker \u955c\u50cf\u7684\u6784\u5efa\u5386\u53f2\u8bb0\u5f55\u3002 docker image history nginx:latest \u521b\u5efa\u4e00\u4e2a\u7a7a\u7684\u76ee\u5f55 /opt/tmp-1 \uff0c\u8fdb\u5165\u8be5\u76ee\u5f55\u5e76\u5728\u5176\u4e2d\u521b\u5efa index.html \u6587\u4ef6\u3002 /opt/tmp-1> cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    \u4f7f\u7528 FROM \u6765\u6269\u5c55\u4e00\u4e2a\u5df2\u6709\u7684\u955c\u50cf\uff0c\u5e76\u6307\u5b9a\u7248\u672c\u53f7\u3002 \u4f7f\u7528 COPY \u5c06\u4e00\u4e2a\u65b0\u7684\u9ed8\u8ba4\u7f51\u7ad9\u590d\u5236\u5230\u955c\u50cf\u4e2d\uff0c\u4f8b\u5982 /usr/share/nginx/html \u3002 \u4e3aNginx\u521b\u5efaSSL\u914d\u7f6e /opt/tmp-1/ssl.conf \u3002 server { listen 443 ssl; server_name localhost; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; location / { root /usr/share/nginx/html; index index.html index.htm; } } \u4f7f\u7528OpenSSL\u521b\u5efa\u4e00\u4e2a\u81ea\u7b7e\u540d\u8bc1\u4e66\uff0c\u4ee5\u4fbfSSL/TLS\u5de5\u4f5c\u3002 \u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u521b\u5efa\u4e00\u4e2a\u52a0\u5bc6\u5bc6\u94a5\u548c\u8bc1\u4e66\u3002 openssl req -x509 -nodes -newkey rsa:4096 -keyout nginx.key -out nginx.crt -days 365 -subj \"/CN= $( hostname ) \" \u4e3a\u4e86\u542f\u7528\u52a0\u5bc6\u7684HTTPS\uff0c\u6211\u4eec\u9700\u8981\u4f7f\u7528 EXPOSE \u6307\u4ee4\u516c\u5f00 443 \u7aef\u53e3\u3002\u9ed8\u8ba4\u7684nginx\u955c\u50cf\u4ec5\u516c\u5f00\u7aef\u53e3 80 \uff0c\u7528\u4e8e\u975e\u52a0\u5bc6\u7684HTTP\u3002 \u5728 /opt/tmp-1 \u6587\u4ef6\u5939\u4e2d\u521b\u5efa\u4ee5\u4e0bDockerfile\u3002 cat Dockerfile \u8f93\u51fa\uff1a FROM nginx:latest # copy the custom website into the image COPY index.html /usr/share/nginx/html # copy the SSL configuration file into the image COPY ssl.conf /etc/nginx/conf.d/ssl.conf # download the SSL key and certificate into the image COPY nginx.key /etc/nginx/ssl/ COPY nginx.crt /etc/nginx/ssl/ # expose the HTTPS port EXPOSE 443 \u81f3\u6b64\uff0c\u6211\u4eec\u5728\u76ee\u5f55 /opt/tmp-1 \u4e0b\u67095\u4e2a\u6587\u4ef6\u3002 ls /opt/tmp-1 \u8f93\u51fa\uff1a Dockerfile index.html nginx.crt nginx.key ssl.conf \u4f7f\u7528 docker build \u547d\u4ee4\u6765\u6784\u5efa\u955c\u50cf\uff0c\u5e76\u5c06\u5bb9\u5668\u768480\u548c443\u7aef\u53e3\u8f6c\u53d1\u3002 docker build -t nginx:my1 /opt/tmp-1/ docker image ls docker run -d -p 1086 :80 -p 1088 :443 --name nginx_v5 nginx:my1 docker container ps -a \u901a\u8fc7\u4e0b\u9762\u4e24\u4e2a\u94fe\u63a5\u6765\u9a8c\u8bc1\u4e0a\u9762\u7684\u53d8\u5316\u662f\u5426\u751f\u6548\u3002 http://localhost:1086/ https://localhost:1088/ \u5728 DockerHub \u6ce8\u518c\u4e00\u4e2a\u4e2a\u4eba\u8d26\u53f7\uff0c\u542f\u7528 Docker Hub \u4e2d\u7684\u8bbf\u95ee\u4ee4\u724c\u4ee5\u8fdb\u884c CLI \u5ba2\u6237\u7aef\u8eab\u4efd\u9a8c\u8bc1\u3002 docker login \u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002 Username: Password: \u7ed9\u8fd9\u4e2a\u955c\u50cf\u52a0\u4e0a\u4e00\u4e2a\u6807\u7b7e\uff0c\u4f8b\u5982\uff1asecure_nginx_0001\uff0c\u7248\u672c\u53f7\u4e3a v1\u3002 docker tag nginx:my1 secure_nginx_0001:v1 docker push secure_nginx_0001:v1 docker image ls","title":"Dockerfile"},{"location":"k8s/cka_cn/foundamentals/docker/#dockerfile_1","text":"\u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u6f14\u793a\u4e00\u4e2a\u591a\u9636\u6bb5\uff08Multi-stage\uff09\u6784\u5efa\u7684\u4f8b\u5b50\u3002\u5728Docker\u7684\u4e0a\u4e0b\u6587\u4e2d\uff0c\u591a\u9636\u6bb5\uff08Multi-stage\uff09\u610f\u5473\u7740\u6211\u4eec\u53ef\u4ee5\u6709\u591a\u4e2a\u5e26\u6709 FROM \u5173\u952e\u5b57\u7684\u884c\u3002 \u521b\u5efa\u6587\u4ef6\u5939 /opt/tmp-2 \u548c /opt/tmp-2/tmpl \u3002\u521b\u5efa\u6587\u4ef6 edit.html \uff0c view.html \uff0c wiki.go \u3002 \u6587\u4ef6\u7ed3\u6784\u5982\u4e0b\uff1a tree -l /opt/tmp-2 \u8f93\u51fa\u7ed3\u679c\uff1a . \u251c\u2500\u2500 tmpl \u2502 \u251c\u2500\u2500 edit.html \u2502 \u2514\u2500\u2500 view.html \u2514\u2500\u2500 wiki.go \u521b\u5efa\u4e00\u4e2a\u65b0\u7684Dockerfile\u3002 cat Dockerfile \u6587\u4ef6\u5185\u5bb9\uff1a # app builder stage FROM golang:1.12-alpine as builder # # copy the go source code over and build the binary WORKDIR /go/src COPY wiki.go /go/src/wiki.go RUN go build wiki.go # app exec stage # separate & new image starts here!# FROM alpine:3.9 # prepare file system etc RUN mkdir -p /app/data /app/tmpl && adduser -S -D -H -h /app appuser COPY tmpl/* /app/tmpl/ # get the compiled binary from the previous stage COPY --from=builder /go/src/wiki /app/wiki # prepare runtime env RUN chown -R appuser /app USER appuser WORKDIR /app # expose app port & set default command EXPOSE 8080 CMD [\"/app/wiki\"] \u7528\u4e0a\u4e00\u6b65\u521b\u5efa\u7684Dockerfile\u6765\u521b\u5efa\u65b0\u666f\u8c61\u3002 docker build -t lizard/golang:my1 /opt/tmp-2/ \u4ee5\u72ec\u7acb\u6a21\u5f0f\uff08detached\uff09\u8fd0\u884c\u8fd9\u4e2a\u955c\u50cf\uff0c\u5e76\u5c06\u5bb9\u5668\u7aef\u53e3 8080 \u8f6c\u53d1\u5230\u4e3b\u673a\u7aef\u53e3 1090 \u3002 docker run -d -p 1090 :8080 --name golan_v1 lizard/golang:my1 \u901a\u8fc7\u94fe\u63a5 http://localhost:1090 \u8bbf\u95ee\u8fd9\u4e2a\u8fd0\u884c\u7684\u5bb9\u5668\u3002 \u5bf9\u6211\u4eec\u521a\u521a\u521b\u5efa\u7684\u65b0\u7684golang\u955c\u50cf\u8fdb\u884c\u6807\u7b7e\uff0c\u5e76\u4e14\u4e0a\u4f20\u5230Dockerhub\u3002 docker tag lizard/golang:my1 /golang_0001:v1 docker push /golang_0001:v1","title":"\u591a\u9636\u6bb5Dockerfile"},{"location":"k8s/cka_cn/foundamentals/healthcheck/","text":"CKA\u81ea\u5b66\u7b14\u8bb026:\u5065\u5eb7\u68c0\u67e5 \u00b6 Pod\u548cContainer\u7684\u72b6\u6001 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u67092\u4e2a\u5bb9\u5668\u7684pod\u3002 \u6f14\u793a\uff1a \u521b\u5efa\u4e00\u4e2a\u5305\u542b\u4e24\u4e2a\u5bb9\u5668 nginx \u548c busybox \u7684 Pod\uff0c\u547d\u540d\u4e3a multi-pods \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: labels: run: multi-pods name: multi-pods spec: containers: - image: nginx name: nginx - image: busybox name: busybox dnsPolicy: ClusterFirst restartPolicy: Always EOF \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u6765\u76d1\u63a7\u72b6\u6001\uff0c\u4f7f\u7528\u9009\u9879 --watch \u3002 \u6ce8\u610f\uff0cpod\u7684\u72b6\u6001\u5df2\u7ecf\u4ece ContainerCreating \u53d8\u4e3a NotReady \uff0c\u518d\u53d8\u4e3a CrashLoopBackOff \u3002 kubectl get pod multi-pods --watch \u83b7\u53d6 Pod multi-pods \u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u5173\u6ce8 Containers \u90e8\u5206\u4e0b\u7684\u5bb9\u5668\u72b6\u6001\u548c Conditions \u90e8\u5206\u4e0b\u7684 Pod \u72b6\u6001\u3002 kubectl describe pod multi-pods \u8fd0\u884c\u7ed3\u679c\uff08\u90e8\u5206\uff09\uff1a ...... Containers : nginx : ...... State : Running Started : Sat, 23 Jul 2022 15:06:56 +0800 Ready : True Restart Count : 0 ...... busybox : ...... State : Terminated Reason : Completed Exit Code : 0 ...... Conditions : Type Status Initialized True Ready False ContainersReady False PodScheduled True ...... LivenessProbe \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2apod\uff0c\u5185\u542b livenessProbe \u68c0\u67e5\u3002 \u6f14\u793a\u7684\u8be6\u7ec6\u8bf4\u660e\u53ef\u4ee5\u67e5\u8be2 Kubernetes document \u3002 \u6f14\u793a\uff1a \u521b\u5efayaml\u6587\u4ef6 liveness.yaml \uff0c\u5e76\u5305\u542b livenessProbe \u914d\u7f6e\uff0c\u5e76\u5e94\u7528\u4e4b\u3002 kubectl apply -f - <> ~/.bashrc source < ( helm completion bash ) \u901a\u8fc7Helm\u5b89\u88c5MySQL \u00b6 \u6dfb\u52a0Bitnami Chartes\u4ed3\u5e93\u3002 helm repo add bitnami https://charts.bitnami.com/bitnami \u67e5\u8be2\u5f53\u524d\u53ef\u7528\u7684Chartes\u4ed3\u5e93\u3002 helm repo list \u8fd0\u884c\u7ed3\u679c\uff1a NAME URL bitnami https://charts.bitnami.com/bitnami \u540c\u6b65\u672c\u5730Charts\u4ed3\u5e93\u3002 helm repo update \u5728Charts\u4ed3\u5e93\u4e2d\u67e5\u627ebitnami Charts\u4ed3\u5e93\u3002 helm search repo bitnami \u5728\u4ed3\u5e93\u4e2d\u641c\u7d22bitnami/mysql Charts\u3002 helm search repo bitnami/mysql \u5728namespace dev \u4e0a\u5b89\u88c5MySQL Chart\u3002 helm install mysql bitnami/mysql -n dev \u8fd0\u884c\u7ed3\u679c\uff1a NAME: mysql LAST DEPLOYED: Sun Jul 24 19:37:20 2022 NAMESPACE: dev STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: mysql CHART VERSION: 9.2.1 APP VERSION: 8.0.29 ** Please be patient while the chart is being deployed ** Tip: Watch the deployment status using the command: kubectl get pods -w --namespace dev Services: echo Primary: mysql.dev.svc.cluster.local:3306 Execute the following to get the administrator credentials: echo Username: root MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace dev mysql -o jsonpath=\"{.data.mysql-root-password}\" | base64 -d) To connect to your database: 1. Run a pod that you can use as a client: kubectl run mysql-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mysql:8.0.29-debian-11-r9 --namespace dev --env MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD --command -- bash 2. To connect to primary service (read/write): mysql -h mysql.dev.svc.cluster.local -uroot -p\"$MYSQL_ROOT_PASSWORD\" \u67e5\u770b\u5f53\u524d\u5b89\u88c5\u5305\u7684\u4fe1\u606f\u3002 helm list \u8fd0\u884c\u7ed3\u679c\uff1a NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 \u68c0\u67e5\u5f53\u524d\u5b89\u88c5\u7684mysql\u7248\u672c\u4fe1\u606f\u3002 helm status mysql \u68c0\u67e5pod mysql \u7684\u72b6\u6001\u3002 kubectl get pod \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE mysql-0 1/1 Running 0 72s \u90e8\u7f72\u4e00\u4e2aChart \u00b6 \u4e0b\u9762\u6f14\u793a\u4e86\u5982\u4f55\u90e8\u7f72\u4e00\u4e2aChart\u3002 \u6267\u884c\u547d\u4ee4 helm create \u6765\u521d\u59cb\u5316\u4e00\u4e2aChart\u3002 # Naming conventions of Chart: lowercase a~z and -(minus sign) helm create cka-demo \u76ee\u5f55 cka-demo \u4f1a\u88ab\u521b\u5efa\uff0c\u67e5\u770b\u8fd9\u4e2a\u76ee\u5f55\u7684\u7ed3\u6784\u3002 tree cka-demo/ \u8fd0\u884c\u7ed3\u679c\uff1a cka-demo/ \u251c\u2500\u2500 charts \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 deployment.yaml \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u251c\u2500\u2500 hpa.yaml \u2502 \u251c\u2500\u2500 ingress.yaml \u2502 \u251c\u2500\u2500 NOTES.txt \u2502 \u251c\u2500\u2500 serviceaccount.yaml \u2502 \u251c\u2500\u2500 service.yaml \u2502 \u2514\u2500\u2500 tests \u2502 \u2514\u2500\u2500 test-connection.yaml \u2514\u2500\u2500 values.yaml \u5220\u9664\u6216\u6e05\u7a7a\u67d0\u4e9b\u6587\u4ef6\uff0c\u6211\u4eec\u4f1a\u5728\u540e\u9762\u91cd\u65b0\u521b\u5efa\u8fd9\u4e9b\u6587\u4ef6\u3002 cd cka-demo rm -rf charts rm -rf templates/tests rm -rf templates/*.yaml echo \"\" > values.yaml echo \"\" > templates/NOTES.txt echo \"\" > templates/_helpers.tpl cd .. \u76ee\u5f55 cka-demo \u7684\u67b6\u6784\u73b0\u5728\u5e94\u8be5\u770b\u8d77\u6765\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\u3002 tree cka-demo/ \u8fd0\u884c\u7ed3\u679c\uff1a cka-demo/ \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u2514\u2500\u2500 NOTES.txt \u2514\u2500\u2500 values.yaml NOTES.txt \u00b6 NOTES.txt \u7528\u4e8e\u5411 Chart \u7528\u6237\u63d0\u4f9b\u6982\u8981\u4fe1\u606f\u3002\u5728\u6f14\u793a\u4e2d\uff0c\u6211\u4eec\u5c06\u4f7f\u7528 NOTES.txt \u63d0\u4f9b\u5173\u4e8e\u7528\u6237\u662f\u5426\u901a\u8fc7 CKA \u8ba4\u8bc1\u7684\u6982\u8981\u4fe1\u606f\u3002 cd cka-demo/ vi templates/NOTES.txt \u6dfb\u52a0\u4e0b\u9762\u7684\u5185\u5bb9\u3002 {{- if .Values.passExam }} Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: {{ .Values.ckaScore }} Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard {{- else }} Come on! you can do it next time! {{- end }} \u90e8\u7f72\u6a21\u7248 \u00b6 \u4e0b\u9762\u4f1a\u4f7f\u7528 Busybox \u670d\u52a1\u6765\u751f\u6210\u4fe1\u606f\u3002 \u901a\u8fc7\u547d\u4ee4 kubectl create deployment --dry-run=client -oyaml \u751f\u6210 Deployment \u7684 YAML \u6587\u4ef6\uff0c\u5e76\u5c06\u5176\u5185\u5bb9\u5199\u5165\u6587\u4ef6 templates/deployment.yaml \u3002 kubectl create deployment cka-demo-busybox --image = busybox:latest --dry-run = client -oyaml > templates/deployment.yaml \u68c0\u67e5deployment\u7684yaml\u6587\u4ef6 templates/deployment.yaml \u7684\u5185\u5bb9\u3002 cat templates/deployment.yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : 1 selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} \u7f16\u8f91\u4fee\u6539\u6587\u4ef6 templates/deployment.yaml \u3002 vi templates/deployment.yaml \u8ba9\u6211\u4eec\u5c06 .spec.replicas \u7684\u503c\u4ece 1 \u66ff\u6362\u4e3a\u53d8\u91cf {{ .Values.replicaCount }} \uff0c\u8fd9\u6837\u6211\u4eec\u53ef\u4ee5\u4e3a\u5176\u4ed6 Deployment \u52a8\u6001\u5206\u914d\u526f\u672c\u6570\u3002 apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} .spec.replicas \u5c06\u5728\u90e8\u7f72\u671f\u95f4\u88ab\u5b9e\u9645\u7684 .Values.replicaCount \u503c\u66ff\u6362\u3002 \u73b0\u5728\u521b\u5efa\u53e6\u4e00\u4e2a\u6587\u4ef6 values.yaml \u5e76\u5728\u6587\u4ef6\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u53d8\u91cf replicaCount \uff0c\u9ed8\u8ba4\u503c\u4e3a1\u3002 \u5f3a\u70c8\u5efa\u8bae\u5728\u6587\u4ef6 values.yaml \u4e2d\u5b9a\u4e49\u7684\u6bcf\u4e2a\u503c\u6dfb\u52a0\u6ce8\u91ca\u3002 vi values.yaml \u8f93\u51fa\u7ed3\u679c\uff1a # Number of deployment replicas replicaCount: 1 \u4e0b\u9762\u5bf9\u6587\u4ef6 templates/deployment.yaml \u6dfb\u52a0\u66f4\u591a\u7684\u53d8\u91cf\u3002 \u5c06 .metadata.name \u7684 Release \u540d\u79f0\u66ff\u6362\u4e3a {{ .Release.Name }} \uff0c\u5e76\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u586b\u5145\u3002 \u5c06\u6807\u7b7e\u540d\u79f0 .metadata.labels \u66ff\u6362\u4e3a {{- include \"cka-demo.labels\" . | nindent 4 }} \uff0c\u5e76\u7528\u5728 _helpers.tpl \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u6807\u7b7e\u540d\u79f0 cka-demo.labels \u586b\u5145\u3002 \u5c06 .spec.replicas \u66ff\u6362\u4e3a {{ .Values.replicaCount }} \uff0c\u5e76\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u586b\u5145\u3002 \u5c06 .spec.selector.matchLabels \u66ff\u6362\u4e3a {{- include \"cka-demo.selectorLabels\" . | nindent 6 }} \u5e76\u4f7f\u7528\u5728 _helpers.tpl \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684 cka-demo.selectorLabels \u8fdb\u884c\u586b\u5145\u3002 \u5c06 .spec.template.metadata.labels \u66ff\u6362\u4e3a {{- include \"cka-demo.selectorLabels\" . | nindent 8 }} \u5e76\u4f7f\u7528\u5728 _helpers.tpl \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684 cka-demo.selectorLabels \u8fdb\u884c\u586b\u5145\u3002 \u5c06 .spec.template.spec.containers[0].image \u66ff\u6362\u4e3a {{ .Values.image.repository }} \u548c {{ .Values.image.tag }} \u5e76\u4f7f\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u586b\u5145\u955c\u50cf\u540d\u79f0\u548c\u955c\u50cf\u6807\u7b7e\u3002 \u5c06 .spec.template.spec.containers[0].command \u66ff\u6362\u4e3a\u4e00\u4e2a if-else \u8bed\u53e5\uff0c\u5982\u679c .Values.passExam \u4e3a\u771f\uff0c\u5219\u6267\u884c\u5728 .Values.passCommand \u4e2d\u5b9a\u4e49\u7684\u547d\u4ee4\uff0c\u5426\u5219\u6267\u884c\u5728 .Values.lostCommand \u4e2d\u5b9a\u4e49\u7684\u547d\u4ee4\u3002 \u4f7f\u7528 .spec.template.spec.containers[0].env \u4e2d\u7684 key \u4f5c\u4e3a ConfigMap \u540d\u79f0\u7684\u524d\u7f00\uff0c\u5e76\u4f7f\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684 {{ .Values.studentName }} \u8fdb\u884c\u586b\u5145\u3002 \u5c06 .spec.template.spec.containers[0].resources \u66ff\u6362\u4e3a {{ .Values.resources }} \u5e76\u4f7f\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u8fdb\u884c\u586b\u5145\u3002 .Release.Name \u662f\u5185\u7f6e\u5bf9\u8c61\uff0c\u5728\u6587\u4ef6 values.yaml \u4e2d\u4e0d\u9700\u8981\u6307\u5b9a\u3002\u5b83\u662f\u7531 helm install \u751f\u6210\u7684Release\u3002 \u79fb\u9664\u4e0d\u5fc5\u8981\u7684\u884c\uff0c\u6700\u7ec8\u6587\u4ef6\u770b\u8d77\u6765\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\uff1a apiVersion : apps/v1 kind : Deployment metadata : name : {{ .Release.Name }} labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : {{ - include \"cka-demo.selectorLabels\" . | nindent 6 }} template : metadata : labels : {{ - include \"cka-demo.selectorLabels\" . | nindent 8 }} spec : containers : - name : id-generator image : \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\" {{ - if .Values.passExam }} {{ - with .Values.passCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - else }} {{ - with .Values.lostCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - end }} env : - name : CKA_SCORE valueFrom : configMapKeyRef : name : {{ .Values.studentName }} -cka-score key : cka_score {{ - with .Values.resources }} resources : {{ - toYaml . | nindent 12 }} {{ - end }} restartPolicy : Always \u66f4\u65b0\u6587\u4ef6 values.yaml \u4e2d\u53d8\u91cf\u7684\u9ed8\u8ba4\u503c\u3002\u5efa\u8bae\u9010\u4e2a\u6dfb\u52a0\u53d8\u91cf\u5e76\u6d4b\u8bd5\uff0c\u4e0d\u8981\u4e00\u6b21\u6dfb\u52a0\u6240\u6709\u53d8\u91cf\u3002 vi values.yaml \u8fd0\u884c\u7ed3\u679c\uff1a # Number of deployment replicas replicaCount: 1 # Image repository and tag image: repository: busybox tag: latest # Container start command passCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE) and your CKA certificate ID number is $(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 13; echo) ; sleep 86400\" lostCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE), Come on! you can do it next time! ; sleep 86400\" # Container resources resources: limits: cpu: 200m memory: 256Mi requests: cpu: 100m memory: 128Mi # Student Name studentName: whoareyou # Student pass CKA exam or not passExam: true ConfigMap\u6a21\u7248 \u00b6 ConfigMap\u88ab\u90e8\u7f72\u4e2d\u7684Deployment\u6240\u5f15\u7528\uff0c\u56e0\u6b64\u6211\u4eec\u9700\u8981\u5b9a\u4e49ConfigMap\u7684\u6a21\u677f\u3002 \u6211\u4eec\u5c06\u628aConfigMap\u7684\u540d\u79f0\u548c cka_score \u7ec4\u5408\u6210\u4e00\u4e2a\u53d8\u91cf\uff0c\u4f8b\u5982 name-cka-score \u3002 vi templates/configmap.yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion : v1 kind : ConfigMap metadata : name : {{ .Values.studentName }} -cka-score labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} data : cka_score : {{ .Values.ckaScore | quote }} studentName \u5df2\u7ecf\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u8fc7\u4e86\uff0c\u6211\u4eec\u53ea\u9700\u8981\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a ckaScore \u7684\u53d8\u91cf\u5e76\u7ed9\u5b83\u4e00\u4e2a\u9ed8\u8ba4\u503c\u5373\u53ef\u3002 vi values.yaml \u8fd0\u884c\u7ed3\u679c # Student CKA Score ckaScore: 100 _helpers.tpl \u00b6 \u5b9a\u4e49\u4e00\u4e2a\u901a\u7528\u7684\u6a21\u677f _helpers.tpl \uff0c\u4e3aDeployment\u548cConfigMap\u7684\u6807\u7b7e\u548c\u9009\u62e9\u5668\u6807\u7b7e\u6dfb\u52a0\u6807\u7b7e\u3002 vi templates/_helpers.tpl \u8fd0\u884c\u7ed3\u679c\uff1a {{/* Common labels */}} {{- define \"cka-demo.labels\" -}} {{ include \"cka-demo.selectorLabels\" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end -}} {{/* Selector labels */}} {{- define \"cka-demo.selectorLabels\" -}} app: {{ .Chart.Name }} release: {{ .Release.Name }} {{- end -}} Chart.yaml \u00b6 \u8fd9\u91cc\u6211\u4eec\u4f7f\u7528CKA\u7684logo\u6765\u4f5c\u4e3aChart\u7684\u56fe\u6807\u3002 wget https://www.cncf.io/wp-content/uploads/2021/09/kubernetes-cka-color.svg \u7f16\u8f91\u4fee\u6539 Chart.yaml \u6587\u4ef6\u3002 vi Chart.yaml \u628a\u56fe\u6807\u4fe1\u606f\u6dfb\u52a0\u5230Chart.yaml\u6587\u4ef6\u672b\u5c3e\u3002 icon: file://./kubernetes-cka-color.svg \u628a\u4f5c\u8005\u4fe1\u606f\u6dfb\u52a0\u5230Chart.yaml\u6587\u4ef6\u672b\u5c3e\u3002 vi Chart.yaml \u8fd0\u884c\u7ed3\u679c\uff1a maintainers: - name: James.H \u6700\u7ec8\u7684 Chart.yaml \u7c7b\u4f3c\u5982\u4e0b\u5185\u5bb9\u3002\u522b\u5fd8\u8bb0\u66f4\u65b0 appVersion: \"v1.23\" \u4e3a\u5f53\u524dKubernetes\u7684\u7248\u672c\u3002 apiVersion: v2 name: cka-demo description: A Helm chart for CKA demo. type: application version: 0.1.0 appVersion: \"v1.23\" maintainers: - name: James.H icon: file://./kubernetes-cka-color.svg Chart Debug \u00b6 \u4f7f\u7528 helm lint \u6765\u9a8c\u8bc1\u4e0a\u8ff0\u53d8\u66f4\u3002 helm lint \u8fd0\u884c\u7ed3\u679c\uff1a 1 chart(s) linted, 0 chart(s) failed helm lint \u53ea\u68c0\u67e5Chart\u7684\u683c\u5f0f\uff0c\u4e0d\u68c0\u67e5Manifest\u6587\u4ef6\u3002 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 helm install --debug --dry-run \u6216 helm template \u547d\u4ee4\u6765\u68c0\u67e5\u751f\u6210\u7684 Manifest \u662f\u5426\u6b63\u786e\u3002 helm template cka-demo ./ \u901a\u8fc7\u547d\u4ee4 helm install --debug --dry-run \u6765\u6a21\u62df\u5b89\u88c5\u3002\u6211\u4eec\u53ef\u4ee5\u4ece\u4e24\u4e2a\u4e0d\u540c\u7684\u9009\u9879\uff08\u901a\u8fc7\u6216\u672a\u901a\u8fc7CKA\u8ba4\u8bc1\uff09\u4e2d\u83b7\u5f97\u9884\u671f\u7684\u7ed3\u679c\u3002 helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 99 \\ --set passExam = true helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 0 \\ --set passExam = false \u628a Chart \u6253\u5305\u6210 .tgz \u6587\u4ef6\uff0c\u5e76\u4e0a\u4f20\u5230\u4ed3\u5e93\uff0c\u4f8b\u5982 Chart Museum \u6216\u8005 OCI Repo\u3002 cd ../ helm package cka-demo \u8fd0\u884c\u7ed3\u679c\uff1a Successfully packaged chart and saved it to: /root/cka-demo-0.1.0.tgz \u81f3\u6b64\uff0c\u6211\u4eec\u5df2\u7ecf\u5b8c\u6210\u4e86\u914d\u7f6e\u4e00\u4e2a\u65b0\u7684Chart\uff0c\u73b0\u5728\u5f00\u59cb\u5b89\u88c5\u8fd9\u4e2aChart\u3002 helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 0 \\ --set passExam = false \u8fd0\u884c\u7ed3\u679c\uff1a NAME: cka-demo LAST DEPLOYED: Sun Jul 24 19:58:36 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Come on! you can do it next time! \u68c0\u67e5\u90e8\u7f72\u60c5\u51b5\uff1a helm list --all-namespaces \u8fd0\u884c\u7ed3\u679c\uff1a NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION cka-demo cka 1 2022-07-24 19:58:36.272093383 +0800 CST deployed cka-demo-0.1.0 v1.23 mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 \u5982\u679c\u9047\u5230\u9519\u8bef\uff0c\u5219\u9700\u8981\u5378\u8f7d cka-demo \u5e76\u91cd\u65b0\u5b89\u88c5\u5b83\u3002 helm uninstall cka-demo -n \u68c0\u67e5 cka-demo \u7684\u65e5\u5fd7\u3002 kubectl logs -n cka -l app = cka-demo \u8fd0\u884c\u7ed3\u679c Your CKA score is 0, Come on! you can do it next time! \u901a\u8fc7\u5176\u4ed6\u9009\u9879\u5b89\u88c5 cka-demo \u3002 helm uninstall cka-demo -n cka helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 100 \\ --set passExam = true \u8fd0\u884c\u7ed3\u679c\uff1a NAME: cka-demo LAST DEPLOYED: Sun Jul 24 20:01:34 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: 100 Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard \u68c0\u67e5 cka-demo \u7684\u65e5\u5fd7\u3002 kubectl logs -n cka -l app = cka-demo \u8fd0\u884c\u7ed3\u679c\uff1a Your CKA score is 100 and your CKA certificate ID number is BQKoVYVhjzl3G Built-in Objects\u5217\u8868 Release.Name # \u53d1\u5e03\u540d\u79f0 Release.Namespace # \u53d1\u5e03Namespace Release.Service # \u6e32\u67d3\u6a21\u677f\u7684\u670d\u52a1\uff0c\u5728Helm\u4e2d\u9ed8\u8ba4\u503c\u4e3a\"Helm\" Release.IsUpgrade # \u5982\u679c\u5f53\u524d\u662f\u5347\u7ea7\u6216\u56de\u6eda\uff0c\u8bbe\u7f6e\u4e3atrue Release.IsInstall # \u5982\u679c\u5f53\u524d\u662f\u5b89\u88c5\uff0c\u8bbe\u7f6e\u4e3atrue Release.Revision # \u53d1\u5e03\u7248\u672c\u53f7 Values # \u4ecevalues.yaml\u548c--set\u4f20\u5165\uff0c\u9ed8\u8ba4\u4e3a\u7a7a Chart # \u6240\u6709Chart.yaml\u4e2d\u7684\u5185\u5bb9 Chart.Version # Chart.Maintainers # Files # \u5728chart\u4e2d\u8bbf\u95ee\u975e\u7279\u6b8a\u6587\u4ef6 Capabilities # \u63d0\u4f9b\u5173\u4e8e\u652f\u6301\u80fd\u529b\u7684\u4fe1\u606f\uff08K8s API\u7248\u672c\u3001K8s\u7248\u672c\u3001Helm\u7248\u672c\uff09 Capabilities.KubeVersion # Kubernetes\u7684\u7248\u672c\u53f7 Capabilities.APIVersions.Has \"batch/v1\" # K8s API\u7248\u672c\u5305\u542b\"batch/v1\" Template # \u5f53\u524d\u6a21\u677f\u4fe1\u606f Template.Name # \u5f53\u524d\u6a21\u677f\u6587\u4ef6\u8def\u5f84 Template.BasePath # \u5f53\u524d\u6a21\u677f\u76ee\u5f55\u8def\u5f84 \u53c2\u8003\uff1a Helm \u5b98\u7f51 Helm \u7248\u672c\u652f\u6301\u7b56\u7565 Helm Chart \u8d44\u6e90\u5bf9\u8c61\u5b89\u88c5\u987a\u5e8f","title":"Helm Chart"},{"location":"k8s/cka_cn/foundamentals/helming/#cka27helm-chart","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb027:Helm Chart"},{"location":"k8s/cka_cn/foundamentals/helming/#helm","text":"\u5728\u8282\u70b9 cka001 \u4e0a\u5b89\u88c5Helm\u3002 # https://github.com/helm/helm/releases wget https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz tar -zxvf helm-v3.8.2-linux-amd64.tar.gz cp linux-amd64/helm /usr/bin/ rm -rf linux-amd64 helm-v3.8.2-linux-amd64.tar.gz \u6216\u8005\u4ece\u94fe\u63a5 https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz \u624b\u5de5\u4e0b\u8f7d\u5b89\u88c5\u5305\uff0c\u5e76\u62f7\u8d1d\u5230\u8282\u70b9 cka001 \u4e0a\u3002 scp -i cka-key-pair.pem ./Package/helm-v3.8.2-linux-amd64.tar.gz root@cka001:/root/ ssh -i cka-key-pair.pem root@cka001 tar -zxvf helm-v3.8.2-linux-amd64.tar.gz cp linux-amd64/helm /usr/bin/ rm -rf linux-amd64 helm-v3.8.2-linux-amd64.tar.gz","title":"\u5b89\u88c5Helm"},{"location":"k8s/cka_cn/foundamentals/helming/#helm_1","text":"\u68c0\u67e5 helm \u7684\u7248\u672c\u3002 helm version \u8fd0\u884c\u7ed3\u679c\uff1a version.BuildInfo{Version:\"v3.8.2\", GitCommit:\"6e3701edea09e5d55a8ca2aae03a68917630e91b\", GitTreeState:\"clean\", GoVersion:\"go1.17.5\"} \u83b7\u53d6 helm \u7684\u5e2e\u52a9\u4fe1\u606f\u3002 helm help \u914d\u7f6e helm \u7684\u547d\u4ee4\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 echo \"source <(helm completion bash)\" >> ~/.bashrc source < ( helm completion bash )","title":"Helm\u7528\u6cd5"},{"location":"k8s/cka_cn/foundamentals/helming/#helmmysql","text":"\u6dfb\u52a0Bitnami Chartes\u4ed3\u5e93\u3002 helm repo add bitnami https://charts.bitnami.com/bitnami \u67e5\u8be2\u5f53\u524d\u53ef\u7528\u7684Chartes\u4ed3\u5e93\u3002 helm repo list \u8fd0\u884c\u7ed3\u679c\uff1a NAME URL bitnami https://charts.bitnami.com/bitnami \u540c\u6b65\u672c\u5730Charts\u4ed3\u5e93\u3002 helm repo update \u5728Charts\u4ed3\u5e93\u4e2d\u67e5\u627ebitnami Charts\u4ed3\u5e93\u3002 helm search repo bitnami \u5728\u4ed3\u5e93\u4e2d\u641c\u7d22bitnami/mysql Charts\u3002 helm search repo bitnami/mysql \u5728namespace dev \u4e0a\u5b89\u88c5MySQL Chart\u3002 helm install mysql bitnami/mysql -n dev \u8fd0\u884c\u7ed3\u679c\uff1a NAME: mysql LAST DEPLOYED: Sun Jul 24 19:37:20 2022 NAMESPACE: dev STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: mysql CHART VERSION: 9.2.1 APP VERSION: 8.0.29 ** Please be patient while the chart is being deployed ** Tip: Watch the deployment status using the command: kubectl get pods -w --namespace dev Services: echo Primary: mysql.dev.svc.cluster.local:3306 Execute the following to get the administrator credentials: echo Username: root MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace dev mysql -o jsonpath=\"{.data.mysql-root-password}\" | base64 -d) To connect to your database: 1. Run a pod that you can use as a client: kubectl run mysql-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mysql:8.0.29-debian-11-r9 --namespace dev --env MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD --command -- bash 2. To connect to primary service (read/write): mysql -h mysql.dev.svc.cluster.local -uroot -p\"$MYSQL_ROOT_PASSWORD\" \u67e5\u770b\u5f53\u524d\u5b89\u88c5\u5305\u7684\u4fe1\u606f\u3002 helm list \u8fd0\u884c\u7ed3\u679c\uff1a NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 \u68c0\u67e5\u5f53\u524d\u5b89\u88c5\u7684mysql\u7248\u672c\u4fe1\u606f\u3002 helm status mysql \u68c0\u67e5pod mysql \u7684\u72b6\u6001\u3002 kubectl get pod \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE mysql-0 1/1 Running 0 72s","title":"\u901a\u8fc7Helm\u5b89\u88c5MySQL"},{"location":"k8s/cka_cn/foundamentals/helming/#chart","text":"\u4e0b\u9762\u6f14\u793a\u4e86\u5982\u4f55\u90e8\u7f72\u4e00\u4e2aChart\u3002 \u6267\u884c\u547d\u4ee4 helm create \u6765\u521d\u59cb\u5316\u4e00\u4e2aChart\u3002 # Naming conventions of Chart: lowercase a~z and -(minus sign) helm create cka-demo \u76ee\u5f55 cka-demo \u4f1a\u88ab\u521b\u5efa\uff0c\u67e5\u770b\u8fd9\u4e2a\u76ee\u5f55\u7684\u7ed3\u6784\u3002 tree cka-demo/ \u8fd0\u884c\u7ed3\u679c\uff1a cka-demo/ \u251c\u2500\u2500 charts \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 deployment.yaml \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u251c\u2500\u2500 hpa.yaml \u2502 \u251c\u2500\u2500 ingress.yaml \u2502 \u251c\u2500\u2500 NOTES.txt \u2502 \u251c\u2500\u2500 serviceaccount.yaml \u2502 \u251c\u2500\u2500 service.yaml \u2502 \u2514\u2500\u2500 tests \u2502 \u2514\u2500\u2500 test-connection.yaml \u2514\u2500\u2500 values.yaml \u5220\u9664\u6216\u6e05\u7a7a\u67d0\u4e9b\u6587\u4ef6\uff0c\u6211\u4eec\u4f1a\u5728\u540e\u9762\u91cd\u65b0\u521b\u5efa\u8fd9\u4e9b\u6587\u4ef6\u3002 cd cka-demo rm -rf charts rm -rf templates/tests rm -rf templates/*.yaml echo \"\" > values.yaml echo \"\" > templates/NOTES.txt echo \"\" > templates/_helpers.tpl cd .. \u76ee\u5f55 cka-demo \u7684\u67b6\u6784\u73b0\u5728\u5e94\u8be5\u770b\u8d77\u6765\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\u3002 tree cka-demo/ \u8fd0\u884c\u7ed3\u679c\uff1a cka-demo/ \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u2514\u2500\u2500 NOTES.txt \u2514\u2500\u2500 values.yaml","title":"\u90e8\u7f72\u4e00\u4e2aChart"},{"location":"k8s/cka_cn/foundamentals/helming/#notestxt","text":"NOTES.txt \u7528\u4e8e\u5411 Chart \u7528\u6237\u63d0\u4f9b\u6982\u8981\u4fe1\u606f\u3002\u5728\u6f14\u793a\u4e2d\uff0c\u6211\u4eec\u5c06\u4f7f\u7528 NOTES.txt \u63d0\u4f9b\u5173\u4e8e\u7528\u6237\u662f\u5426\u901a\u8fc7 CKA \u8ba4\u8bc1\u7684\u6982\u8981\u4fe1\u606f\u3002 cd cka-demo/ vi templates/NOTES.txt \u6dfb\u52a0\u4e0b\u9762\u7684\u5185\u5bb9\u3002 {{- if .Values.passExam }} Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: {{ .Values.ckaScore }} Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard {{- else }} Come on! you can do it next time! {{- end }}","title":"NOTES.txt"},{"location":"k8s/cka_cn/foundamentals/helming/#_1","text":"\u4e0b\u9762\u4f1a\u4f7f\u7528 Busybox \u670d\u52a1\u6765\u751f\u6210\u4fe1\u606f\u3002 \u901a\u8fc7\u547d\u4ee4 kubectl create deployment --dry-run=client -oyaml \u751f\u6210 Deployment \u7684 YAML \u6587\u4ef6\uff0c\u5e76\u5c06\u5176\u5185\u5bb9\u5199\u5165\u6587\u4ef6 templates/deployment.yaml \u3002 kubectl create deployment cka-demo-busybox --image = busybox:latest --dry-run = client -oyaml > templates/deployment.yaml \u68c0\u67e5deployment\u7684yaml\u6587\u4ef6 templates/deployment.yaml \u7684\u5185\u5bb9\u3002 cat templates/deployment.yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : 1 selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} \u7f16\u8f91\u4fee\u6539\u6587\u4ef6 templates/deployment.yaml \u3002 vi templates/deployment.yaml \u8ba9\u6211\u4eec\u5c06 .spec.replicas \u7684\u503c\u4ece 1 \u66ff\u6362\u4e3a\u53d8\u91cf {{ .Values.replicaCount }} \uff0c\u8fd9\u6837\u6211\u4eec\u53ef\u4ee5\u4e3a\u5176\u4ed6 Deployment \u52a8\u6001\u5206\u914d\u526f\u672c\u6570\u3002 apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} .spec.replicas \u5c06\u5728\u90e8\u7f72\u671f\u95f4\u88ab\u5b9e\u9645\u7684 .Values.replicaCount \u503c\u66ff\u6362\u3002 \u73b0\u5728\u521b\u5efa\u53e6\u4e00\u4e2a\u6587\u4ef6 values.yaml \u5e76\u5728\u6587\u4ef6\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u53d8\u91cf replicaCount \uff0c\u9ed8\u8ba4\u503c\u4e3a1\u3002 \u5f3a\u70c8\u5efa\u8bae\u5728\u6587\u4ef6 values.yaml \u4e2d\u5b9a\u4e49\u7684\u6bcf\u4e2a\u503c\u6dfb\u52a0\u6ce8\u91ca\u3002 vi values.yaml \u8f93\u51fa\u7ed3\u679c\uff1a # Number of deployment replicas replicaCount: 1 \u4e0b\u9762\u5bf9\u6587\u4ef6 templates/deployment.yaml \u6dfb\u52a0\u66f4\u591a\u7684\u53d8\u91cf\u3002 \u5c06 .metadata.name \u7684 Release \u540d\u79f0\u66ff\u6362\u4e3a {{ .Release.Name }} \uff0c\u5e76\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u586b\u5145\u3002 \u5c06\u6807\u7b7e\u540d\u79f0 .metadata.labels \u66ff\u6362\u4e3a {{- include \"cka-demo.labels\" . | nindent 4 }} \uff0c\u5e76\u7528\u5728 _helpers.tpl \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u6807\u7b7e\u540d\u79f0 cka-demo.labels \u586b\u5145\u3002 \u5c06 .spec.replicas \u66ff\u6362\u4e3a {{ .Values.replicaCount }} \uff0c\u5e76\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u586b\u5145\u3002 \u5c06 .spec.selector.matchLabels \u66ff\u6362\u4e3a {{- include \"cka-demo.selectorLabels\" . | nindent 6 }} \u5e76\u4f7f\u7528\u5728 _helpers.tpl \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684 cka-demo.selectorLabels \u8fdb\u884c\u586b\u5145\u3002 \u5c06 .spec.template.metadata.labels \u66ff\u6362\u4e3a {{- include \"cka-demo.selectorLabels\" . | nindent 8 }} \u5e76\u4f7f\u7528\u5728 _helpers.tpl \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684 cka-demo.selectorLabels \u8fdb\u884c\u586b\u5145\u3002 \u5c06 .spec.template.spec.containers[0].image \u66ff\u6362\u4e3a {{ .Values.image.repository }} \u548c {{ .Values.image.tag }} \u5e76\u4f7f\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u586b\u5145\u955c\u50cf\u540d\u79f0\u548c\u955c\u50cf\u6807\u7b7e\u3002 \u5c06 .spec.template.spec.containers[0].command \u66ff\u6362\u4e3a\u4e00\u4e2a if-else \u8bed\u53e5\uff0c\u5982\u679c .Values.passExam \u4e3a\u771f\uff0c\u5219\u6267\u884c\u5728 .Values.passCommand \u4e2d\u5b9a\u4e49\u7684\u547d\u4ee4\uff0c\u5426\u5219\u6267\u884c\u5728 .Values.lostCommand \u4e2d\u5b9a\u4e49\u7684\u547d\u4ee4\u3002 \u4f7f\u7528 .spec.template.spec.containers[0].env \u4e2d\u7684 key \u4f5c\u4e3a ConfigMap \u540d\u79f0\u7684\u524d\u7f00\uff0c\u5e76\u4f7f\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684 {{ .Values.studentName }} \u8fdb\u884c\u586b\u5145\u3002 \u5c06 .spec.template.spec.containers[0].resources \u66ff\u6362\u4e3a {{ .Values.resources }} \u5e76\u4f7f\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u8fdb\u884c\u586b\u5145\u3002 .Release.Name \u662f\u5185\u7f6e\u5bf9\u8c61\uff0c\u5728\u6587\u4ef6 values.yaml \u4e2d\u4e0d\u9700\u8981\u6307\u5b9a\u3002\u5b83\u662f\u7531 helm install \u751f\u6210\u7684Release\u3002 \u79fb\u9664\u4e0d\u5fc5\u8981\u7684\u884c\uff0c\u6700\u7ec8\u6587\u4ef6\u770b\u8d77\u6765\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\uff1a apiVersion : apps/v1 kind : Deployment metadata : name : {{ .Release.Name }} labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : {{ - include \"cka-demo.selectorLabels\" . | nindent 6 }} template : metadata : labels : {{ - include \"cka-demo.selectorLabels\" . | nindent 8 }} spec : containers : - name : id-generator image : \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\" {{ - if .Values.passExam }} {{ - with .Values.passCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - else }} {{ - with .Values.lostCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - end }} env : - name : CKA_SCORE valueFrom : configMapKeyRef : name : {{ .Values.studentName }} -cka-score key : cka_score {{ - with .Values.resources }} resources : {{ - toYaml . | nindent 12 }} {{ - end }} restartPolicy : Always \u66f4\u65b0\u6587\u4ef6 values.yaml \u4e2d\u53d8\u91cf\u7684\u9ed8\u8ba4\u503c\u3002\u5efa\u8bae\u9010\u4e2a\u6dfb\u52a0\u53d8\u91cf\u5e76\u6d4b\u8bd5\uff0c\u4e0d\u8981\u4e00\u6b21\u6dfb\u52a0\u6240\u6709\u53d8\u91cf\u3002 vi values.yaml \u8fd0\u884c\u7ed3\u679c\uff1a # Number of deployment replicas replicaCount: 1 # Image repository and tag image: repository: busybox tag: latest # Container start command passCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE) and your CKA certificate ID number is $(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 13; echo) ; sleep 86400\" lostCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE), Come on! you can do it next time! ; sleep 86400\" # Container resources resources: limits: cpu: 200m memory: 256Mi requests: cpu: 100m memory: 128Mi # Student Name studentName: whoareyou # Student pass CKA exam or not passExam: true","title":"\u90e8\u7f72\u6a21\u7248"},{"location":"k8s/cka_cn/foundamentals/helming/#configmap","text":"ConfigMap\u88ab\u90e8\u7f72\u4e2d\u7684Deployment\u6240\u5f15\u7528\uff0c\u56e0\u6b64\u6211\u4eec\u9700\u8981\u5b9a\u4e49ConfigMap\u7684\u6a21\u677f\u3002 \u6211\u4eec\u5c06\u628aConfigMap\u7684\u540d\u79f0\u548c cka_score \u7ec4\u5408\u6210\u4e00\u4e2a\u53d8\u91cf\uff0c\u4f8b\u5982 name-cka-score \u3002 vi templates/configmap.yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion : v1 kind : ConfigMap metadata : name : {{ .Values.studentName }} -cka-score labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} data : cka_score : {{ .Values.ckaScore | quote }} studentName \u5df2\u7ecf\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u8fc7\u4e86\uff0c\u6211\u4eec\u53ea\u9700\u8981\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a ckaScore \u7684\u53d8\u91cf\u5e76\u7ed9\u5b83\u4e00\u4e2a\u9ed8\u8ba4\u503c\u5373\u53ef\u3002 vi values.yaml \u8fd0\u884c\u7ed3\u679c # Student CKA Score ckaScore: 100","title":"ConfigMap\u6a21\u7248"},{"location":"k8s/cka_cn/foundamentals/helming/#_helperstpl","text":"\u5b9a\u4e49\u4e00\u4e2a\u901a\u7528\u7684\u6a21\u677f _helpers.tpl \uff0c\u4e3aDeployment\u548cConfigMap\u7684\u6807\u7b7e\u548c\u9009\u62e9\u5668\u6807\u7b7e\u6dfb\u52a0\u6807\u7b7e\u3002 vi templates/_helpers.tpl \u8fd0\u884c\u7ed3\u679c\uff1a {{/* Common labels */}} {{- define \"cka-demo.labels\" -}} {{ include \"cka-demo.selectorLabels\" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end -}} {{/* Selector labels */}} {{- define \"cka-demo.selectorLabels\" -}} app: {{ .Chart.Name }} release: {{ .Release.Name }} {{- end -}}","title":"_helpers.tpl"},{"location":"k8s/cka_cn/foundamentals/helming/#chartyaml","text":"\u8fd9\u91cc\u6211\u4eec\u4f7f\u7528CKA\u7684logo\u6765\u4f5c\u4e3aChart\u7684\u56fe\u6807\u3002 wget https://www.cncf.io/wp-content/uploads/2021/09/kubernetes-cka-color.svg \u7f16\u8f91\u4fee\u6539 Chart.yaml \u6587\u4ef6\u3002 vi Chart.yaml \u628a\u56fe\u6807\u4fe1\u606f\u6dfb\u52a0\u5230Chart.yaml\u6587\u4ef6\u672b\u5c3e\u3002 icon: file://./kubernetes-cka-color.svg \u628a\u4f5c\u8005\u4fe1\u606f\u6dfb\u52a0\u5230Chart.yaml\u6587\u4ef6\u672b\u5c3e\u3002 vi Chart.yaml \u8fd0\u884c\u7ed3\u679c\uff1a maintainers: - name: James.H \u6700\u7ec8\u7684 Chart.yaml \u7c7b\u4f3c\u5982\u4e0b\u5185\u5bb9\u3002\u522b\u5fd8\u8bb0\u66f4\u65b0 appVersion: \"v1.23\" \u4e3a\u5f53\u524dKubernetes\u7684\u7248\u672c\u3002 apiVersion: v2 name: cka-demo description: A Helm chart for CKA demo. type: application version: 0.1.0 appVersion: \"v1.23\" maintainers: - name: James.H icon: file://./kubernetes-cka-color.svg","title":"Chart.yaml"},{"location":"k8s/cka_cn/foundamentals/helming/#chart-debug","text":"\u4f7f\u7528 helm lint \u6765\u9a8c\u8bc1\u4e0a\u8ff0\u53d8\u66f4\u3002 helm lint \u8fd0\u884c\u7ed3\u679c\uff1a 1 chart(s) linted, 0 chart(s) failed helm lint \u53ea\u68c0\u67e5Chart\u7684\u683c\u5f0f\uff0c\u4e0d\u68c0\u67e5Manifest\u6587\u4ef6\u3002 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 helm install --debug --dry-run \u6216 helm template \u547d\u4ee4\u6765\u68c0\u67e5\u751f\u6210\u7684 Manifest \u662f\u5426\u6b63\u786e\u3002 helm template cka-demo ./ \u901a\u8fc7\u547d\u4ee4 helm install --debug --dry-run \u6765\u6a21\u62df\u5b89\u88c5\u3002\u6211\u4eec\u53ef\u4ee5\u4ece\u4e24\u4e2a\u4e0d\u540c\u7684\u9009\u9879\uff08\u901a\u8fc7\u6216\u672a\u901a\u8fc7CKA\u8ba4\u8bc1\uff09\u4e2d\u83b7\u5f97\u9884\u671f\u7684\u7ed3\u679c\u3002 helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 99 \\ --set passExam = true helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 0 \\ --set passExam = false \u628a Chart \u6253\u5305\u6210 .tgz \u6587\u4ef6\uff0c\u5e76\u4e0a\u4f20\u5230\u4ed3\u5e93\uff0c\u4f8b\u5982 Chart Museum \u6216\u8005 OCI Repo\u3002 cd ../ helm package cka-demo \u8fd0\u884c\u7ed3\u679c\uff1a Successfully packaged chart and saved it to: /root/cka-demo-0.1.0.tgz \u81f3\u6b64\uff0c\u6211\u4eec\u5df2\u7ecf\u5b8c\u6210\u4e86\u914d\u7f6e\u4e00\u4e2a\u65b0\u7684Chart\uff0c\u73b0\u5728\u5f00\u59cb\u5b89\u88c5\u8fd9\u4e2aChart\u3002 helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 0 \\ --set passExam = false \u8fd0\u884c\u7ed3\u679c\uff1a NAME: cka-demo LAST DEPLOYED: Sun Jul 24 19:58:36 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Come on! you can do it next time! \u68c0\u67e5\u90e8\u7f72\u60c5\u51b5\uff1a helm list --all-namespaces \u8fd0\u884c\u7ed3\u679c\uff1a NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION cka-demo cka 1 2022-07-24 19:58:36.272093383 +0800 CST deployed cka-demo-0.1.0 v1.23 mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 \u5982\u679c\u9047\u5230\u9519\u8bef\uff0c\u5219\u9700\u8981\u5378\u8f7d cka-demo \u5e76\u91cd\u65b0\u5b89\u88c5\u5b83\u3002 helm uninstall cka-demo -n \u68c0\u67e5 cka-demo \u7684\u65e5\u5fd7\u3002 kubectl logs -n cka -l app = cka-demo \u8fd0\u884c\u7ed3\u679c Your CKA score is 0, Come on! you can do it next time! \u901a\u8fc7\u5176\u4ed6\u9009\u9879\u5b89\u88c5 cka-demo \u3002 helm uninstall cka-demo -n cka helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 100 \\ --set passExam = true \u8fd0\u884c\u7ed3\u679c\uff1a NAME: cka-demo LAST DEPLOYED: Sun Jul 24 20:01:34 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: 100 Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard \u68c0\u67e5 cka-demo \u7684\u65e5\u5fd7\u3002 kubectl logs -n cka -l app = cka-demo \u8fd0\u884c\u7ed3\u679c\uff1a Your CKA score is 100 and your CKA certificate ID number is BQKoVYVhjzl3G Built-in Objects\u5217\u8868 Release.Name # \u53d1\u5e03\u540d\u79f0 Release.Namespace # \u53d1\u5e03Namespace Release.Service # \u6e32\u67d3\u6a21\u677f\u7684\u670d\u52a1\uff0c\u5728Helm\u4e2d\u9ed8\u8ba4\u503c\u4e3a\"Helm\" Release.IsUpgrade # \u5982\u679c\u5f53\u524d\u662f\u5347\u7ea7\u6216\u56de\u6eda\uff0c\u8bbe\u7f6e\u4e3atrue Release.IsInstall # \u5982\u679c\u5f53\u524d\u662f\u5b89\u88c5\uff0c\u8bbe\u7f6e\u4e3atrue Release.Revision # \u53d1\u5e03\u7248\u672c\u53f7 Values # \u4ecevalues.yaml\u548c--set\u4f20\u5165\uff0c\u9ed8\u8ba4\u4e3a\u7a7a Chart # \u6240\u6709Chart.yaml\u4e2d\u7684\u5185\u5bb9 Chart.Version # Chart.Maintainers # Files # \u5728chart\u4e2d\u8bbf\u95ee\u975e\u7279\u6b8a\u6587\u4ef6 Capabilities # \u63d0\u4f9b\u5173\u4e8e\u652f\u6301\u80fd\u529b\u7684\u4fe1\u606f\uff08K8s API\u7248\u672c\u3001K8s\u7248\u672c\u3001Helm\u7248\u672c\uff09 Capabilities.KubeVersion # Kubernetes\u7684\u7248\u672c\u53f7 Capabilities.APIVersions.Has \"batch/v1\" # K8s API\u7248\u672c\u5305\u542b\"batch/v1\" Template # \u5f53\u524d\u6a21\u677f\u4fe1\u606f Template.Name # \u5f53\u524d\u6a21\u677f\u6587\u4ef6\u8def\u5f84 Template.BasePath # \u5f53\u524d\u6a21\u677f\u76ee\u5f55\u8def\u5f84 \u53c2\u8003\uff1a Helm \u5b98\u7f51 Helm \u7248\u672c\u652f\u6301\u7b56\u7565 Helm Chart \u8d44\u6e90\u5bf9\u8c61\u5b89\u88c5\u987a\u5e8f","title":"Chart Debug"},{"location":"k8s/cka_cn/foundamentals/hpa/","text":"CKA\u81ea\u5b66\u7b14\u8bb021:Horizontal Pod Autoscaling (HPA) \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u5b89\u88c5 Metrics Server \u7ec4\u4ef6 \u521b\u5efa Deployment podinfo \u548c Service podinfo \u7528\u4e8e\u538b\u529b\u6d4b\u8bd5 \u521b\u5efa HPA my-hpa \u8fdb\u884c\u538b\u529b\u6d4b\u8bd5 \u5b89\u88c5Metrics Server \u00b6 \u4e0b\u8f7d components.yaml \u6587\u4ef6\uff0c\u6765\u90e8\u7f72Metrics Server\u3002 wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml \u628ayaml\u6587\u4ef6\u4e2dgoogle\u7684\u955c\u50cf\u6e90\u66ff\u6362\u4e3a\u963f\u91cc\u7684\u955c\u50cf\u6e90 image: registry.aliyuncs.com/google_containers/metrics-server:v0.6.1 \u3002 sed -i 's/k8s\\.gcr\\.io\\/metrics-server\\/metrics-server\\:v0\\.6\\.1/registry\\.aliyuncs\\.com\\/google_containers\\/metrics-server\\:v0\\.6\\.1/g' components.yaml \u4fee\u6539deployment metrics-server \u7684 args \uff0c\u6dfb\u52a0\u9009\u9879 --kubelet-insecure-tls \u4ee5\u7981\u7528\u8bc1\u4e66\u9a8c\u8bc1\u3002 vi components.yaml \u66f4\u65b0 args \u3002 ...... template : metadata : labels : k8s-app : metrics-server spec : containers : - args : - --cert-dir=/tmp - --secure-port=4443 - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname - --kubelet-use-node-status-port - --metric-resolution=15s - --kubelet-insecure-tls image : registry.aliyuncs.com/google_containers/metrics-server:v0.6.1 ...... \u5e94\u7528\u6587\u4ef6 components.yaml \u6765\u90e8\u7f72 metrics-server \u3002 kubectl apply -f components.yaml \u4e0b\u9762\u662f\u8fd0\u884c\u7ed3\u679c\uff0c\u76f8\u5173\u8d44\u6e90\u88ab\u521b\u5efa\u3002 serviceaccount/metrics-server created clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created clusterrole.rbac.authorization.k8s.io/system:metrics-server created rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created service/metrics-server created deployment.apps/metrics-server created apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created \u9a8c\u8bc1 pod metrics-server \u662f\u5426\u6309\u9884\u671f\u5728\u6b63\u5e38\u8fd0\u884c\u3002 kubectl get pod -n kube-system -owide | grep metrics-server \u8fd0\u884c\u7ed3\u679c\u3002\u5173\u6ce8READY\u4e0b\u7684\u72b6\u6001\uff1a 1/1 running\u4ee3\u8868\u6b63\u5e38\u8fd0\u884c\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES metrics-server-7fd564dc66-sdhdc 1/1 Running 0 61s 10.244.102.15 cka003 \u67e5\u8be2\u6bcf\u4e2a\u8282\u70b9\u4e0a\u5f53\u524dCPU\u548c\u5185\u5b58\u7684\u7528\u91cf\u60c5\u51b5\u3002 kubectl top node \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 595m 29% 1937Mi 50% cka002 75m 3% 1081Mi 28% cka003 79m 3% 1026Mi 26% \u90e8\u7f72\u670d\u52a1 podinfo \u00b6 \u521b\u5efa Deployment podinfo \u548c Service podinfo \uff0c\u540e\u9762\u4f1a\u8fdb\u884c\u66f4\u8fdb\u4e00\u6b65\u7684\u538b\u529b\u6d4b\u8bd5\u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: podinfo labels: app: podinfo spec: type: NodePort ports: - port: 9898 targetPort: 9898 nodePort: 31198 protocol: TCP selector: app: podinfo --- apiVersion: apps/v1 kind: Deployment metadata: name: podinfo labels: app: podinfo spec: replicas: 2 selector: matchLabels: app: podinfo template: metadata: labels: app: podinfo spec: containers: - name: podinfod image: stefanprodan/podinfo:0.0.1 imagePullPolicy: Always command: - ./podinfo - -port=9898 - -logtostderr=true - -v=2 ports: - containerPort: 9898 protocol: TCP resources: requests: memory: \"32Mi\" cpu: \"10m\" limits: memory: \"256Mi\" cpu: \"100m\" EOF Config HPA \u00b6 \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a my-hpa \u7684 HPA\uff0c\u5e76\u5c06\u5176\u7ed1\u5b9a\u5230\u540d\u4e3a podinfo \u7684\u90e8\u7f72\u4e2d\uff0c\u8bbe\u5b9a\u5176 CPU \u5229\u7528\u7387\u4e3a 50% \u4f5c\u4e3a\u89e6\u53d1\u81ea\u52a8\u7f29\u653e\u7684\u9608\u503c\uff0c\u6700\u5c0f\u526f\u672c\u6570\u4e3a 2 \uff0c\u6700\u5927\u526f\u672c\u6570\u4e3a 10 \u3002 \u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u521b\u5efa my-hpa HPA\uff1a kubectl autoscale deployment podinfo --cpu-percent = 50 --min = 2 --max = 10 --name = my-hpa kubectl autoscale deployment podinfo --cpu-percent = 50 --min = 1 --max = 10 \u4f7f\u7528 autoscaling/v1 \u7248\u672c\u7684\u6a21\u7248\u6765\u521b\u5efaHPA my-hpa \u3002 kubectl apply -f - < \u67e5\u8be2\u6bcf\u4e2a\u8282\u70b9\u4e0a\u5f53\u524dCPU\u548c\u5185\u5b58\u7684\u7528\u91cf\u60c5\u51b5\u3002 kubectl top node \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 595m 29% 1937Mi 50% cka002 75m 3% 1081Mi 28% cka003 79m 3% 1026Mi 26%","title":"\u5b89\u88c5Metrics Server"},{"location":"k8s/cka_cn/foundamentals/hpa/#podinfo","text":"\u521b\u5efa Deployment podinfo \u548c Service podinfo \uff0c\u540e\u9762\u4f1a\u8fdb\u884c\u66f4\u8fdb\u4e00\u6b65\u7684\u538b\u529b\u6d4b\u8bd5\u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: podinfo labels: app: podinfo spec: type: NodePort ports: - port: 9898 targetPort: 9898 nodePort: 31198 protocol: TCP selector: app: podinfo --- apiVersion: apps/v1 kind: Deployment metadata: name: podinfo labels: app: podinfo spec: replicas: 2 selector: matchLabels: app: podinfo template: metadata: labels: app: podinfo spec: containers: - name: podinfod image: stefanprodan/podinfo:0.0.1 imagePullPolicy: Always command: - ./podinfo - -port=9898 - -logtostderr=true - -v=2 ports: - containerPort: 9898 protocol: TCP resources: requests: memory: \"32Mi\" cpu: \"10m\" limits: memory: \"256Mi\" cpu: \"100m\" EOF","title":"\u90e8\u7f72\u670d\u52a1podinfo"},{"location":"k8s/cka_cn/foundamentals/hpa/#config-hpa","text":"\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a my-hpa \u7684 HPA\uff0c\u5e76\u5c06\u5176\u7ed1\u5b9a\u5230\u540d\u4e3a podinfo \u7684\u90e8\u7f72\u4e2d\uff0c\u8bbe\u5b9a\u5176 CPU \u5229\u7528\u7387\u4e3a 50% \u4f5c\u4e3a\u89e6\u53d1\u81ea\u52a8\u7f29\u653e\u7684\u9608\u503c\uff0c\u6700\u5c0f\u526f\u672c\u6570\u4e3a 2 \uff0c\u6700\u5927\u526f\u672c\u6570\u4e3a 10 \u3002 \u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u521b\u5efa my-hpa HPA\uff1a kubectl autoscale deployment podinfo --cpu-percent = 50 --min = 2 --max = 10 --name = my-hpa kubectl autoscale deployment podinfo --cpu-percent = 50 --min = 1 --max = 10 \u4f7f\u7528 autoscaling/v1 \u7248\u672c\u7684\u6a21\u7248\u6765\u521b\u5efaHPA my-hpa \u3002 kubectl apply -f - << body >< h1 > It works! \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete ingress demo-localhost kubectl delete service demo kubectl delete deployment demo \u521b\u5efaDeployments \u00b6 \u521b\u5efa2\u4e2adeployment nginx-app-1 \u548c nginx-app-2 \u3002 kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-1 spec: selector: matchLabels: app: nginx-app-1 replicas: 1 template: metadata: labels: app: nginx-app-1 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-1 --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-2 spec: selector: matchLabels: app: nginx-app-2 replicas: 1 template: metadata: labels: app: nginx-app-2 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-2 EOF \u6267\u884c\u547d\u4ee4 kubectl get pod -o wide \u6765\u83b7\u53d6pod\u7684\u72b6\u6001\u3002 \u53ef\u4ee5\u770b\u5230\u4e00\u4e2apod\u8fd0\u884c\u5728\u8282\u70b9 cka002 \uff0c\u53e6\u5916\u4e00\u4e2apod\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u3002 Directory /opt/html-2/ is on cka002 Directory /opt/html-1/ is on cka002 \u901a\u8fc7 curl \u547d\u4ee4\u6765\u8bbf\u95ee\u8fd92\u4e2apod\uff0c\u6536\u5230 403 Forbidden \u9519\u8bef\u3002 curl 10 .244.102.13 curl 10 .244.112.19 \u767b\u5f55\u5230\u8282\u70b9 cka002 \uff0c\u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u5728 /opt/html-2/ \u8def\u5f84\u4e0b\u521b\u5efa\u6587\u4ef6 index.html \u3002 cat < app1.com app2.com EOF \u6267\u884c\u4ee5\u4e0b\u547d\u4ee4\uff0c\u53ef\u4ee5\u5f97\u5230 IP \u5730\u5740\u6216 FQDN\u3002 kubectl get service ingress-nginx-controller --namespace = ingress-nginx \u5728\u8f93\u51fa\u7ed3\u679c\u4e2d\u53ef\u4ee5\u770b\u5230 EXTERNAL-IP \u5b57\u6bb5\u3002\u5982\u679c\u8be5\u5b57\u6bb5\u50cf\u4e0b\u9762\u4e00\u6837\u663e\u793a\u4e3a \uff0c\u8fd9\u610f\u5473\u7740 Kubernetes \u96c6\u7fa4\u65e0\u6cd5\u63d0\u4f9b\u8d1f\u8f7d\u5747\u8861\u5668\uff08\u901a\u5e38\u662f\u56e0\u4e3a\u5b83\u4e0d\u652f\u6301 LoadBalancer \u7c7b\u578b\u7684\u670d\u52a1\uff09\u3002 \u7531\u4e8e\u6ca1\u6709\u914d\u7f6e\u963f\u91cc\u4e91 ELB\uff0c\u56e0\u6b64\u6709\u4ee5\u4e0b\u4e24\u4e2a\u9009\u9879\u53ef\u4ee5\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u3002 \u9009\u9879 1\uff1a\u624b\u52a8\u5c06\u8282\u70b9 IP \u6dfb\u52a0\u5230\u8fd0\u884c ingress \u63a7\u5236\u5668\u7684\u8282\u70b9\u4e0a\u3002 \u6267\u884c\u547d\u4ee4 kubectl get pod -n ingress-nginx -o wide \u6765\u67e5\u770b ingress \u63a7\u5236\u5668 pod \u8fd0\u884c\u5728\u54ea\u4e2a\u8282\u70b9\u4e0a\u3002 \u624b\u52a8\u5c06 cka003 \u7684\u5916\u90e8 IP \u8865\u4e01\u5230 EXTERNAL-IP \u5b57\u6bb5\u3002 kubectl patch svc ingress-nginx-controller \\ --namespace = ingress-nginx \\ -p '{\"spec\": {\"type\": \"LoadBalancer\", \"externalIPs\":[\"\"]}}' \u9009\u9879 2\uff1a\u5c06 ingress \u63a7\u5236\u5668\u4ece LoadBalancer \u7c7b\u578b\u66f4\u6539\u4e3a NodePort \u7c7b\u578b\u3002 \u4e24\u4e2a Pod \u4e2d\u5404\u6709\u4e00\u4e2a index.html \u6587\u4ef6\uff0cWeb \u670d\u52a1\u901a\u8fc7\u8282\u70b9 IP \u5bf9\u5916\u66b4\u9732\u3002 ingress-nginx-controller \u4f5c\u4e3a\u4e2d\u5fc3\u5165\u53e3\u70b9\uff0c\u4e3a\u6765\u81ea Pod \u7684\u4e0d\u540c\u540e\u7aef\u670d\u52a1\u63d0\u4f9b\u4e86\u4e24\u4e2a\u7aef\u53e3\u3002 \u53d1\u9001HTTP\u8bf7\u6c42\u5230\u5728Ingress\u4e2d\u5b9a\u4e49\u76842\u4e2a\u4e3b\u673a\u8282\u70b9\u3002 curl http://app1.com:30011 curl http://app2.com:30011 curl app1.com:30011 curl app2.com:30011 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002 This is test 1 !! This is test 2 !! \u5220\u9664\u4e0a\u9762\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete ingress ingress-nginx-app kubectl delete service nginx-app-1 kubectl delete service nginx-app-2 kubectl delete deployment nginx-app-1 kubectl delete deployment nginx-app-2","title":"Ingress-nginx"},{"location":"k8s/cka_cn/foundamentals/ingress/#cka19ingress-nginx","text":"\u6f14\u793a\u573a\u666f\uff1a \u90e8\u7f72Ingress Controller\u3002 \u521b\u5efa\u4e24\u4e2aDeployment nginx-app-1 \u548c nginx-app-2 \u3002 \u5728\u8fd0\u884c\u4e3b\u673a\u4e0a\u521b\u5efa\u4e3b\u673a\u76ee\u5f55 /root/html-1 \u548c /root/html-2 \u5e76\u6302\u8f7d\u5230\u4e24\u4e2aDeployment\u4e0a\u3002 \u521b\u5efaService\u3002 \u521b\u5efaService nginx-app-1 \u548c nginx-app-2 \u5e76\u5c06\u5176\u6620\u5c04\u5230\u76f8\u5173\u7684Deployment nginx-app-1 \u548c nginx-app-2 \u3002 \u521b\u5efaIngress\u3002 \u521b\u5efaIngress\u8d44\u6e90 nginx-app \u5e76\u5c06\u5176\u6620\u5c04\u5230\u4e24\u4e2aServices nginx-app-1 \u548c nginx-app-1 \u3002 \u6d4b\u8bd5\u53ef\u8bbf\u95ee\u6027\u3002 \u5411Ingress\u4e2d\u5b9a\u4e49\u7684\u4e24\u4e2a\u4e3b\u673a\u53d1\u9001HTTP\u8bf7\u6c42\u3002 \u53c2\u8003\uff1a Github ingress-nginx Installation Guide","title":"CKA\u81ea\u5b66\u7b14\u8bb019:Ingress-nginx"},{"location":"k8s/cka_cn/foundamentals/ingress/#ingress","text":"\u83b7\u53d6Ingress\u63a7\u5236\u5668\u7684yaml\u6587\u4ef6\u3002\u6700\u65b0\u7248\u672c\u7684\u94fe\u63a5\u5728 \u5b89\u88c5\u6307\u5357 \u4e2d\u3002 wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml \u4fee\u6539 deploy.yaml \u6587\u4ef6\u4e2d\u955c\u50cf\u6e90\u4e3a\u963f\u91cc\u4e91\u7684\u6e90\u3002 deploy.yaml \u6587\u4ef6\u4e2d\u9700\u8981\u4fee\u6539\u7684\u884c\uff1a image : k8s.gcr.io/ingress-nginx/controller:v1.2.1@sha256:5516d103a9c2ecc4f026efbd4b40662ce22dc1f824fb129ed121460aaa5c47f8 image : registry.k8s.io/ingress-nginx/controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5 image : k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660 \u4fee\u6539\u5185\u5bb9\uff1a k8s.gcr.io/ingress-nginx/controller \u6539\u4e3a registry.aliyuncs.com/google_containers/nginx-ingress-controller \u3002 registry.k8s.io/ingress-nginx/controller \u6539\u4e3a registry.aliyuncs.com/google_containers/nginx-ingress-controller \u3002 k8s.gcr.io/ingress-nginx/kube-webhook-certgen \u6539\u4e3a registry.aliyuncs.com/google_containers/kube-webhook-certgen \u3002 \u4fee\u6539\u547d\u4ee4\uff1a sed -i 's/k8s.gcr.io\\/ingress-nginx\\/kube-webhook-certgen/registry.aliyuncs.com\\/google\\_containers\\/kube-webhook-certgen/g' deploy.yaml sed -i 's/k8s.gcr.io\\/ingress-nginx\\/controller/registry.aliyuncs.com\\/google\\_containers\\/nginx-ingress-controller/g' deploy.yaml \u5e94\u7528\u6587\u4ef6 deploy.yaml \u6765\u521b\u5efa Ingress Nginx\u3002 \u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4namespace ingress-nginx \u4f1a\u88ab\u521b\u5efa\uff0cIngress Nginx\u76f8\u5173\u7684\u8d44\u6e90\u8fd0\u884c\u5728\u8fd9\u4e2anamespace\u4e0a\u3002 kubectl apply -f deploy.yaml \u67e5\u770bPod\u7684\u72b6\u6001\u3002 kubectl get pod -n ingress-nginx \u786e\u4fdd\u6240\u4ee5pod\u7684\u8fd0\u884c\u72b6\u6001\u90fd\u6b63\u5e38\uff0c\u7c7b\u4f3c\u5982\u4e0b\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE ingress-nginx-admission-create-lgtdj 0/1 Completed 0 49s ingress-nginx-admission-patch-nk9fv 0/1 Completed 0 49s ingress-nginx-controller-556fbd6d6f-6jl4x 1/1 Running 0 49s","title":"\u90e8\u7f72Ingress\u63a7\u5236\u5668"},{"location":"k8s/cka_cn/foundamentals/ingress/#_1","text":"\u8ba9\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u7b80\u5355\u7684 Web \u670d\u52a1\u5668\u548c\u76f8\u5173\u7684\u670d\u52a1\uff1a kubectl create deployment demo --image = httpd --port = 80 kubectl expose deployment demo \u63a5\u4e0b\u6765\u521b\u5efa\u4e00\u4e2a Ingress \u8d44\u6e90\u3002\u4ee5\u4e0b\u793a\u4f8b\u4f7f\u7528\u5c06\u4e3b\u673a\u6620\u5c04\u5230 localhost: kubectl create ingress demo-localhost --class = nginx --rule = \"demo.localdev.me/*=demo:80\" \u73b0\u5728\uff0c\u5c06\u672c\u5730\u7aef\u53e3\u8f6c\u53d1\u5230Ingress\u63a7\u5236\u5668\uff1a kubectl port-forward --namespace = ingress-nginx service/ingress-nginx-controller 8080 :80 \u73b0\u5728\uff0c\u5728\u53e6\u4e00\u4e2a\u7ec8\u7aef\u4e2d\u8bbf\u95ee http://demo.localdev.me:8080/ \uff0c\u6211\u4eec\u5e94\u8be5\u770b\u5230\u4e00\u4e2a HTML \u9875\u9762\uff0c\u4e0a\u9762\u5199\u7740 \"It works!\"\u3002 curl http://demo.localdev.me:8080/ \u8fd0\u884c\u7ed3\u679c\uff1b < html >< body >< h1 > It works! \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete ingress demo-localhost kubectl delete service demo kubectl delete deployment demo","title":"\u672c\u5730\u6d4b\u8bd5\u65b9\u5f0f"},{"location":"k8s/cka_cn/foundamentals/ingress/#deployments","text":"\u521b\u5efa2\u4e2adeployment nginx-app-1 \u548c nginx-app-2 \u3002 kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-1 spec: selector: matchLabels: app: nginx-app-1 replicas: 1 template: metadata: labels: app: nginx-app-1 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-1 --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-2 spec: selector: matchLabels: app: nginx-app-2 replicas: 1 template: metadata: labels: app: nginx-app-2 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-2 EOF \u6267\u884c\u547d\u4ee4 kubectl get pod -o wide \u6765\u83b7\u53d6pod\u7684\u72b6\u6001\u3002 \u53ef\u4ee5\u770b\u5230\u4e00\u4e2apod\u8fd0\u884c\u5728\u8282\u70b9 cka002 \uff0c\u53e6\u5916\u4e00\u4e2apod\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u3002 Directory /opt/html-2/ is on cka002 Directory /opt/html-1/ is on cka002 \u901a\u8fc7 curl \u547d\u4ee4\u6765\u8bbf\u95ee\u8fd92\u4e2apod\uff0c\u6536\u5230 403 Forbidden \u9519\u8bef\u3002 curl 10 .244.102.13 curl 10 .244.112.19 \u767b\u5f55\u5230\u8282\u70b9 cka002 \uff0c\u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u5728 /opt/html-2/ \u8def\u5f84\u4e0b\u521b\u5efa\u6587\u4ef6 index.html \u3002 cat < app1.com app2.com EOF \u6267\u884c\u4ee5\u4e0b\u547d\u4ee4\uff0c\u53ef\u4ee5\u5f97\u5230 IP \u5730\u5740\u6216 FQDN\u3002 kubectl get service ingress-nginx-controller --namespace = ingress-nginx \u5728\u8f93\u51fa\u7ed3\u679c\u4e2d\u53ef\u4ee5\u770b\u5230 EXTERNAL-IP \u5b57\u6bb5\u3002\u5982\u679c\u8be5\u5b57\u6bb5\u50cf\u4e0b\u9762\u4e00\u6837\u663e\u793a\u4e3a \uff0c\u8fd9\u610f\u5473\u7740 Kubernetes \u96c6\u7fa4\u65e0\u6cd5\u63d0\u4f9b\u8d1f\u8f7d\u5747\u8861\u5668\uff08\u901a\u5e38\u662f\u56e0\u4e3a\u5b83\u4e0d\u652f\u6301 LoadBalancer \u7c7b\u578b\u7684\u670d\u52a1\uff09\u3002 \u7531\u4e8e\u6ca1\u6709\u914d\u7f6e\u963f\u91cc\u4e91 ELB\uff0c\u56e0\u6b64\u6709\u4ee5\u4e0b\u4e24\u4e2a\u9009\u9879\u53ef\u4ee5\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u3002 \u9009\u9879 1\uff1a\u624b\u52a8\u5c06\u8282\u70b9 IP \u6dfb\u52a0\u5230\u8fd0\u884c ingress \u63a7\u5236\u5668\u7684\u8282\u70b9\u4e0a\u3002 \u6267\u884c\u547d\u4ee4 kubectl get pod -n ingress-nginx -o wide \u6765\u67e5\u770b ingress \u63a7\u5236\u5668 pod \u8fd0\u884c\u5728\u54ea\u4e2a\u8282\u70b9\u4e0a\u3002 \u624b\u52a8\u5c06 cka003 \u7684\u5916\u90e8 IP \u8865\u4e01\u5230 EXTERNAL-IP \u5b57\u6bb5\u3002 kubectl patch svc ingress-nginx-controller \\ --namespace = ingress-nginx \\ -p '{\"spec\": {\"type\": \"LoadBalancer\", \"externalIPs\":[\"\"]}}' \u9009\u9879 2\uff1a\u5c06 ingress \u63a7\u5236\u5668\u4ece LoadBalancer \u7c7b\u578b\u66f4\u6539\u4e3a NodePort \u7c7b\u578b\u3002 \u4e24\u4e2a Pod \u4e2d\u5404\u6709\u4e00\u4e2a index.html \u6587\u4ef6\uff0cWeb \u670d\u52a1\u901a\u8fc7\u8282\u70b9 IP \u5bf9\u5916\u66b4\u9732\u3002 ingress-nginx-controller \u4f5c\u4e3a\u4e2d\u5fc3\u5165\u53e3\u70b9\uff0c\u4e3a\u6765\u81ea Pod \u7684\u4e0d\u540c\u540e\u7aef\u670d\u52a1\u63d0\u4f9b\u4e86\u4e24\u4e2a\u7aef\u53e3\u3002 \u53d1\u9001HTTP\u8bf7\u6c42\u5230\u5728Ingress\u4e2d\u5b9a\u4e49\u76842\u4e2a\u4e3b\u673a\u8282\u70b9\u3002 curl http://app1.com:30011 curl http://app2.com:30011 curl app1.com:30011 curl app2.com:30011 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002 This is test 1 !! This is test 2 !! \u5220\u9664\u4e0a\u9762\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete ingress ingress-nginx-app kubectl delete service nginx-app-1 kubectl delete service nginx-app-2 kubectl delete deployment nginx-app-1 kubectl delete deployment nginx-app-2","title":"\u53ef\u8bbf\u95ee\u6027\u6d4b\u8bd5"},{"location":"k8s/cka_cn/foundamentals/job/","text":"CKA\u81ea\u5b66\u7b14\u8bb014:Job and Cronjob \u00b6 Job \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efaJob\u3002 \u6f14\u793a\uff1a \u521b\u5efaJob pi \u3002 kubectl apply -f - << EOF apiVersion: batch/v1 kind: Job metadata: name: pi spec: template: spec: containers: - name: pi image: perl:5.34 command: [\"perl\", \"-Mbignum=bpi\", \"-wle\", \"print bpi(2000)\"] restartPolicy: Never backoffLimit: 4 EOF \u83b7\u53d6Job\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get jobs \u83b7\u53d6Job\u7684Pod\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 Completed \u7684\u72b6\u6001\u4ee3\u8868\u8fd9\u4e2ajob\u5df2\u7ecf\u6210\u529f\u5b8c\u6210\u4e86\u3002 kubectl get pod \u83b7\u53d6Job\u7684Pod\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl pi-2s74d 3 .141592653589793.............. \u5220\u9664\u6240\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete job pi Cronjob \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efaCronjob\u3002 \u6f14\u793a\uff1a \u521b\u5efaCronjob hello \u3002 kubectl apply -f - << EOF apiVersion: batch/v1 kind: CronJob metadata: name: hello spec: schedule: \"*/1 * * * *\" jobTemplate: spec: template: spec: containers: - name: hello image: busybox args: - /bin/sh - -c - date ; echo Hello from the kubernetes cluster restartPolicy: OnFailure EOF \u83b7\u53d6Cronjob\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get cronjobs -o wide \u8fd0\u884c\u7ed3\u679c NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE CONTAINERS IMAGES SELECTOR hello */1 * * * * False 0 25s hello busybox \u76d1\u63a7Jobs\u3002\u6bcf\u96941\u5206\u949f\uff0c\u4e00\u4e2a\u65b0\u7684job\u4f1a\u88ab\u521b\u5efa\u3002 kubectl get jobs -w \u5220\u9664\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete cronjob hello","title":"Job and Cronjob"},{"location":"k8s/cka_cn/foundamentals/job/#cka14job-and-cronjob","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb014:Job and Cronjob"},{"location":"k8s/cka_cn/foundamentals/job/#job","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efaJob\u3002 \u6f14\u793a\uff1a \u521b\u5efaJob pi \u3002 kubectl apply -f - << EOF apiVersion: batch/v1 kind: Job metadata: name: pi spec: template: spec: containers: - name: pi image: perl:5.34 command: [\"perl\", \"-Mbignum=bpi\", \"-wle\", \"print bpi(2000)\"] restartPolicy: Never backoffLimit: 4 EOF \u83b7\u53d6Job\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get jobs \u83b7\u53d6Job\u7684Pod\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 Completed \u7684\u72b6\u6001\u4ee3\u8868\u8fd9\u4e2ajob\u5df2\u7ecf\u6210\u529f\u5b8c\u6210\u4e86\u3002 kubectl get pod \u83b7\u53d6Job\u7684Pod\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl pi-2s74d 3 .141592653589793.............. \u5220\u9664\u6240\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete job pi","title":"Job"},{"location":"k8s/cka_cn/foundamentals/job/#cronjob","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efaCronjob\u3002 \u6f14\u793a\uff1a \u521b\u5efaCronjob hello \u3002 kubectl apply -f - << EOF apiVersion: batch/v1 kind: CronJob metadata: name: hello spec: schedule: \"*/1 * * * *\" jobTemplate: spec: template: spec: containers: - name: hello image: busybox args: - /bin/sh - -c - date ; echo Hello from the kubernetes cluster restartPolicy: OnFailure EOF \u83b7\u53d6Cronjob\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get cronjobs -o wide \u8fd0\u884c\u7ed3\u679c NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE CONTAINERS IMAGES SELECTOR hello */1 * * * * False 0 25s hello busybox \u76d1\u63a7Jobs\u3002\u6bcf\u96941\u5206\u949f\uff0c\u4e00\u4e2a\u65b0\u7684job\u4f1a\u88ab\u521b\u5efa\u3002 kubectl get jobs -w \u5220\u9664\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete cronjob hello","title":"Cronjob"},{"location":"k8s/cka_cn/foundamentals/memo/","text":"CKA\u81ea\u5b66\u7b14\u8bb05:Kubernetes\u968f\u7b14 \u00b6 \u6458\u8981 \u00b6 \u8fb9\u7ec3\u4e60\u8fb9\u8bb0\u5f55\u7684\u5185\u5bb9\uff0c\u4e0d\u662f\u5168\u9762\u7cfb\u7edf\u7684\uff0c\u5305\u62ec\u4e0b\u9762\u4e3b\u8981\u5185\u5bb9\uff1a Kubernetes\u57fa\u672c\u6982\u5ff5 \u7ec4\u4ef6 API \u5bf9\u8c61 \u8d44\u6e90 \u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90 Pod Deployment ReplicaSet StatefulSet DaemonSet Job CronJob \u670d\u52a1\u8d44\u6e90 Service Endpoints \u914d\u7f6e\u548c\u5b58\u50a8\u8d44\u6e90 \u5377 Storage Class PV Access Modes Kubernetes\u57fa\u672c\u6982\u5ff5 \u00b6 Kubernetes\u7ec4\u4ef6 \u00b6 \u4e00\u4e2aKubernetes\u96c6\u7fa4\u7531\u4ee3\u8868\u63a7\u5236\u5e73\u9762\uff08control plane\uff09\u7684\u7ec4\u4ef6\u548c\u4e00\u7ec4\u79f0\u4e3a\u8282\u70b9\uff08nodes\uff09\u7684\u673a\u5668\u7ec4\u6210\u3002 Kubernetes\u7ec4\u4ef6: \u63a7\u5236\u5e73\u9762\u7ec4\u4ef6 Control Plane Components kube-apiserver: \u67e5\u8be2\u548c\u64cd\u4f5c Kubernetes \u4e2d\u5bf9\u8c61\u7684\u72b6\u6001\u3002 \u5145\u5f53\u6240\u6709\u8d44\u6e90\u4e4b\u95f4\u7684\u901a\u4fe1\u4e2d\u5fc3\uff08communication hub\uff09\u3002 \u63d0\u4f9b\u96c6\u7fa4\u5b89\u5168\u8eab\u4efd\u9a8c\u8bc1\u3001\u6388\u6743\u548c\u89d2\u8272\u5206\u914d\u3002 \u662f\u552f\u4e00\u80fd\u8fde\u63a5\u5230 etcd \u7684\u7ec4\u4ef6\u3002 etcd: \u6240\u6709 Kubernetes \u5bf9\u8c61\u90fd\u5b58\u50a8\u5728 etcd \u4e2d\u3002 Kubernetes \u5bf9\u8c61\u662f Kubernetes \u7cfb\u7edf\u4e2d\u7684\u6301\u4e45\u5b9e\u4f53(entities)\uff0c\u7528\u4e8e\u8868\u793a\u96c6\u7fa4\u7684\u72b6\u6001\u3002 kube-scheduler: \u76d1\u89c6\u6ca1\u6709\u5206\u914d\u8282\u70b9\u7684\u65b0\u521b\u5efa\u7684 Pod\uff0c\u5e76\u4e3a\u5b83\u4eec\u9009\u62e9\u4e00\u4e2a\u8282\u70b9\u6765\u8fd0\u884c\u3002 kube-controller-manager: \u8fd0\u884c\u63a7\u5236\u5668\u8fdb\u7a0b\u3002 Node controller : \u8d1f\u8d23\u8b66\u793a\u548c\u54cd\u5e94\u8282\u70b9\u7684\u6545\u969c\u3002 Job controller : \u76d1\u89c6\u8868\u793a\u4e00\u6b21\u6027\u4efb\u52a1\u7684 Job \u5bf9\u8c61\uff0c\u7136\u540e\u521b\u5efa Pod \u6765\u5b8c\u6210\u8fd9\u4e9b\u4efb\u52a1\u3002 Endpoints controller : \u586b\u5145 Endpoints \u5bf9\u8c61\uff08\u5373\u5c06 Service \u548c Pod \u8fde\u63a5\u8d77\u6765\uff09\u3002 Service Account & Token controllers : \u4e3a\u65b0\u547d\u540d\u7a7a\u95f4\u521b\u5efa\u9ed8\u8ba4\u5e10\u6237\u548c API \u8bbf\u95ee\u4ee4\u724c\u3002 cloud-controller-manager: \u5d4c\u5165\u4e91\u7279\u5b9a\u7684\u63a7\u5236\u903b\u8f91\uff0c\u4ec5\u8fd0\u884c\u7279\u5b9a\u4e8e\u6211\u4eec\u9009\u62e9\u7684\u4e91\u63d0\u4f9b\u5546\u7684\u63a7\u5236\u5668\uff0c\u65e0\u9700\u81ea\u5df1\u7684\u57fa\u7840\u8bbe\u65bd\u548c\u5b66\u4e60\u73af\u5883\u3002 Node controller : \u7528\u4e8e\u68c0\u67e5\u4e91\u63d0\u4f9b\u5546\uff0c\u4ee5\u786e\u5b9a\u8282\u70b9\u5728\u5728\u5b83\u505c\u6b62\u54cd\u5e94\u540e\u662f\u5426\u5df2\u5728\u4e91\u4e2d\u88ab\u5220\u9664\u3002 Route controller : \u7528\u4e8e\u5728\u5e95\u5c42\u4e91\u57fa\u7840\u67b6\u6784\u4e2d\u8bbe\u7f6e\u8def\u7531\u3002 Service controller : \u7528\u4e8e\u521b\u5efa\u3001\u66f4\u65b0\u548c\u5220\u9664\u4e91\u63d0\u4f9b\u5546\u8d1f\u8f7d\u5747\u8861\u5668\u3002 \u8282\u70b9\u7ec4\u4ef6 Node Components kubelet: \u5728\u96c6\u7fa4\u4e2d\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u7684\u4ee3\u7406\u3002 \u7ba1\u7406\u8282\u70b9\u3002\u5b83\u786e\u4fdd Pod \u4e2d\u8fd0\u884c\u5bb9\u5668\u3002 kubelet \u5411 APIServer \u6ce8\u518c\u548c\u66f4\u65b0\u8282\u70b9\u4fe1\u606f\uff0cAPIServer \u5c06\u5b83\u4eec\u5b58\u50a8\u5230 etcd \u4e2d\u3002 \u7ba1\u7406 Pod\u3002\u901a\u8fc7 APIServer \u76d1\u89c6 Pod\uff0c\u5e76\u5bf9 Pod \u6216 Pod \u4e2d\u7684\u5bb9\u5668\u91c7\u53d6\u884c\u52a8\u3002 \u5728\u5bb9\u5668\u7ea7\u522b\u8fdb\u884c\u5065\u5eb7\u68c0\u67e5\u3002 kube-proxy: \u662f\u5728\u96c6\u7fa4\u4e2d\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u7684\u7f51\u7edc\u4ee3\u7406\u3002 iptables ipvs \u7ef4\u62a4\u8282\u70b9\u4e0a\u7684\u7f51\u7edc\u89c4\u5219\u3002 \u5bb9\u5668\u8fd0\u884c\u65f6Container runtime\uff1a \u8d1f\u8d23\u8fd0\u884c\u5bb9\u5668\u7684\u8f6f\u4ef6\u3002 \u63d2\u4ef6Addons DNS: \u662f DNS \u670d\u52a1\u5668\uff0c\u662f\u6240\u6709 Kubernetes \u96c6\u7fa4\u6240\u5fc5\u9700\u7684\u3002 Web UI\uff08\u4eea\u8868\u76d8\uff09\uff1a\u7528\u4e8e Kubernetes \u96c6\u7fa4\u7684\u57fa\u4e8e Web \u7684\u7528\u6237\u754c\u9762\u3002 \u5bb9\u5668\u8d44\u6e90\u76d1\u63a7\uff1a\u8bb0\u5f55\u6709\u5173\u96c6\u4e2d\u5f0f\u6570\u636e\u5e93\u4e2d\u5bb9\u5668\u7684\u901a\u7528\u65f6\u95f4\u5e8f\u5217\u5ea6\u91cf\u3002 Cluster-level Logging\uff1a\u8d1f\u8d23\u5c06\u5bb9\u5668\u65e5\u5fd7\u4fdd\u5b58\u5230\u5177\u6709\u641c\u7d22/\u6d4f\u89c8\u63a5\u53e3\u7684\u4e2d\u592e\u65e5\u5fd7\u5b58\u50a8\u4e2d\u3002 \u53ef\u6269\u5c55\u6027\uff1a \u6c34\u5e73\u6269\u5c55\uff08Scaling out\uff09\u901a\u8fc7\u6dfb\u52a0\u66f4\u591a\u7684\u670d\u52a1\u5668\u5230\u67b6\u6784\u4e2d\uff0c\u5c06\u5de5\u4f5c\u8d1f\u8f7d\u5206\u6563\u5230\u66f4\u591a\u7684\u673a\u5668\u4e0a\u3002 \u5782\u76f4\u6269\u5c55\uff08Scaling up\uff09\u901a\u8fc7\u6dfb\u52a0\u66f4\u591a\u7684\u786c\u76d8\u548c\u5185\u5b58\u6765\u589e\u52a0\u7269\u7406\u670d\u52a1\u5668\u7684\u8ba1\u7b97\u80fd\u529b\u3002 Kubernetes API \u00b6 REST API\u662fKubernetes\u7684\u57fa\u672c\u6846\u67b6\u3002\u6240\u6709\u7ec4\u4ef6\u4e4b\u95f4\u7684\u64cd\u4f5c\u548c\u901a\u4fe1\uff0c\u4ee5\u53ca\u5916\u90e8\u7528\u6237\u547d\u4ee4\u90fd\u662f\u7531API\u670d\u52a1\u5668\u5904\u7406\u7684REST API\u8c03\u7528\u3002\u56e0\u6b64\uff0cKubernetes\u5e73\u53f0\u4e2d\u7684\u6240\u6709\u5185\u5bb9\u90fd\u88ab\u89c6\u4e3aAPI\u5bf9\u8c61\uff08API object\uff09\uff0c\u5e76\u5728API\u4e2d\u6709\u76f8\u5e94\u7684\u6761\u76ee\u3002 Kubernetes\u63a7\u5236\u5e73\u9762\u7684\u6838\u5fc3\u662fAPI\u670d\u52a1\u5668\u3002 CRI\uff1a\u5bb9\u5668\u8fd0\u884c\u65f6\u63a5\u53e3 CNI\uff1a\u5bb9\u5668\u7f51\u7edc\u63a5\u53e3 CSI\uff1a\u5bb9\u5668\u5b58\u50a8\u63a5\u53e3 API\u670d\u52a1\u5668\u516c\u5f00\u4e86\u4e00\u4e2aHTTP API\uff0c\u5141\u8bb8\u6700\u7ec8\u7528\u6237\u3001\u96c6\u7fa4\u7684\u4e0d\u540c\u90e8\u5206\u548c\u5916\u90e8\u7ec4\u4ef6\u5f7c\u6b64\u901a\u4fe1\u3002 Kubernetes API\u5141\u8bb8\u6211\u4eec\u67e5\u8be2\u548c\u64cd\u4f5cKubernetes\u4e2dAPI\u5bf9\u8c61\u7684\u72b6\u6001\uff08\u4f8b\u5982\uff1aPod\u3001Namespace\u3001ConfigMap\u548cEvent\uff09\u3002 Kubernetes API\uff1a OpenAPI\u89c4\u8303 OpenAPI V2 OpenAPI V3 \u6301\u4e45\u6027\u3002Kubernetes\u901a\u8fc7\u5c06\u5bf9\u8c61\u7684\u5e8f\u5217\u5316\u72b6\u6001\u5199\u5165etcd\u6765\u5b58\u50a8\u5b83\u4eec\u3002 API\u7ec4\u548c\u7248\u672c\u63a7\u5236\u3002\u7248\u672c\u63a7\u5236\u662f\u5728API\u7ea7\u522b\u8fdb\u884c\u7684\u3002API\u8d44\u6e90\u901a\u8fc7\u5b83\u4eec\u7684API\u7ec4\u3001\u8d44\u6e90\u7c7b\u578b\u3001\u547d\u540d\u7a7a\u95f4\uff08\u7528\u4e8e\u547d\u540d\u7a7a\u95f4\u8d44\u6e90\uff09\u548c\u540d\u79f0\u8fdb\u884c\u533a\u5206\u3002 API\u66f4\u6539 API\u6269\u5c55 API Version \u00b6 API\u7248\u672c\u548c\u8f6f\u4ef6\u7248\u672c\u95f4\u5b58\u5728\u95f4\u63a5\u5173\u7cfb\u3002API\u548c\u53d1\u5e03\u7248\u672c\u8ba1\u5212\u63cf\u8ff0\u4e86API\u7248\u672c\u548c\u8f6f\u4ef6\u7248\u672c\u4e4b\u95f4\u7684\u5173\u7cfb\u3002\u4e0d\u540c\u7684API\u7248\u672c\u8868\u793a\u4e0d\u540c\u7684\u7a33\u5b9a\u6027\u548c\u652f\u6301\u7ea7\u522b\u3002 \u4ee5\u4e0b\u662f\u6bcf\u4e2a\u7ea7\u522b\u7684\u6458\u8981\uff1a Alpha\uff1a \u7248\u672c\u540d\u79f0\u5305\u542balpha\uff08\u4f8b\u5982\uff0cv1alpha1\uff09\u3002 \u8f6f\u4ef6\u53ef\u80fd\u5305\u542b\u9519\u8bef\u3002\u542f\u7528\u529f\u80fd\u53ef\u80fd\u4f1a\u66b4\u9732\u9519\u8bef\u3002\u67d0\u4e9b\u529f\u80fd\u53ef\u80fd\u9ed8\u8ba4\u7981\u7528\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u529f\u80fd\u7684\u652f\u6301\u53ef\u4ee5\u968f\u65f6\u53d6\u6d88\uff0c\u800c\u4e0d\u4f1a\u63d0\u524d\u901a\u77e5\u3002 API\u53ef\u80fd\u4f1a\u5728\u4ee5\u540e\u7684\u8f6f\u4ef6\u53d1\u5e03\u4e2d\u4ee5\u4e0d\u517c\u5bb9\u7684\u65b9\u5f0f\u66f4\u6539\uff0c\u800c\u4e0d\u4f1a\u63d0\u524d\u901a\u77e5\u3002 \u7531\u4e8e\u9519\u8bef\u98ce\u9669\u589e\u52a0\u548c\u957f\u671f\u652f\u6301\u4e0d\u8db3\uff0c\u5efa\u8bae\u4ec5\u5728\u77ed\u6682\u7684\u6d4b\u8bd5\u96c6\u7fa4\u4e2d\u4f7f\u7528\u8be5\u8f6f\u4ef6\u3002 Beta\uff1a \u7248\u672c\u540d\u79f0\u5305\u542bbeta\uff08\u4f8b\u5982\uff0cv2beta3\uff09\u3002 \u8f6f\u4ef6\u7ecf\u8fc7\u5145\u5206\u6d4b\u8bd5\u3002\u542f\u7528\u529f\u80fd\u88ab\u8ba4\u4e3a\u662f\u5b89\u5168\u7684\u3002\u67d0\u4e9b\u529f\u80fd\u9ed8\u8ba4\u542f\u7528\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u529f\u80fd\u7684\u652f\u6301\u4e0d\u4f1a\u53d6\u6d88\uff0c\u4f46\u7ec6\u8282\u53ef\u80fd\u4f1a\u66f4\u6539\u3002 \u5bf9\u8c61\u7684\u6a21\u5f0f\u548c/\u6216\u8bed\u4e49\u53ef\u80fd\u4f1a\u5728\u540e\u7eed\u7684Beta\u6216\u7a33\u5b9a\u7248\u53d1\u5e03\u4e2d\u4ee5\u4e0d\u517c\u5bb9\u7684\u65b9\u5f0f\u66f4\u6539\u3002\u5f53\u53d1\u751f\u8fd9\u79cd\u60c5\u51b5\u65f6\uff0c\u5c06\u63d0\u4f9b\u8fc1\u79fb\u8bf4\u660e\u3002\u6a21\u5f0f\u66f4\u6539\u53ef\u80fd\u9700\u8981\u5220\u9664\u3001\u7f16\u8f91\u548c\u91cd\u65b0\u521b\u5efa API\u5bf9\u8c61\u3002\u7f16\u8f91\u8fc7\u7a0b\u53ef\u80fd\u4e0d\u7b80\u5355\u3002\u8fc1\u79fb\u53ef\u80fd\u9700\u8981\u505c\u673a\uff0c\u4ee5\u4fbf\u4f9d\u8d56\u4e8e\u8be5\u529f\u80fd\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 \u4e0d\u5efa\u8bae\u5c06\u8be5\u8f6f\u4ef6\u7528\u4e8e\u751f\u4ea7\u7528\u9014\u3002\u540e\u7eed\u7684\u53d1\u5e03\u53ef\u80fd\u4f1a\u5f15\u5165\u4e0d\u517c\u5bb9\u7684\u66f4\u6539\u3002\u5982\u679c\u60a8\u6709\u591a\u4e2a\u53ef\u4ee5\u72ec\u7acb\u5347\u7ea7\u7684\u96c6\u7fa4\uff0c\u5219\u53ef\u4ee5\u653e\u5bbd\u6b64\u9650\u5236\u3002 \u6ce8\u610f\uff1a\u8bf7\u5c1d\u8bd5beta\u529f\u80fd\u5e76\u63d0\u4f9b\u53cd\u9988\u3002\u529f\u80fd\u9000\u51fabeta\u540e\uff0c\u53ef\u80fd\u4e0d\u5b9e\u9645\u518d\u8fdb\u884c\u66f4\u6539\u3002 \u7a33\u5b9a\u7248\uff1a \u7248\u672c\u540d\u79f0\u4e3avX\uff0c\u5176\u4e2dX\u662f\u6574\u6570\u3002 \u529f\u80fd\u7684\u7a33\u5b9a\u7248\u672c\u51fa\u73b0\u5728\u53d1\u5e03\u7684\u8f6f\u4ef6\u4e2d\u7684\u8bb8\u591a\u540e\u7eed\u7248\u672c\u4e2d\u3002 \u8bfb\u53d6\u5f53\u524dAPI\u7684\u7248\u672c\u547d\u4ee4\uff1a kubectl api-resources API Group \u00b6 API\u7ec4\uff08API groups\uff09 \u4f7f\u6269\u5c55Kubernetes API\u66f4\u52a0\u5bb9\u6613\u3002API\u7ec4\u5728REST\u8def\u5f84\u548c\u5e8f\u5217\u5316\u5bf9\u8c61\u7684apiVersion\u5b57\u6bb5\u4e2d\u6307\u5b9a\u3002 Kubernetes\u6709\u51e0\u4e2aAPI\u7ec4\uff1a \u6838\u5fc3\u7ec4\uff08\u4e5f\u79f0\u4e3a\u9057\u7559legacy\uff09\u4f4d\u4e8eREST\u8def\u5f84 /api/v1 \u3002 \u6838\u5fc3\u7ec4\u4e0d\u4f5c\u4e3aapiVersion\u5b57\u6bb5\u7684\u4e00\u90e8\u5206\u6307\u5b9a\uff0c\u4f8b\u5982 apiVersion: v1\u3002 \u547d\u540d\u7ec4\u4f4d\u4e8eREST\u8def\u5f84 /apis/$GROUP_NAME/$VERSION \uff0c\u5e76\u4f7f\u7528 apiVersion: $GROUP_NAME/$VERSION \uff08\u4f8b\u5982 apiVersion: batch/v1\uff09\u3002 Kubernetes\u5bf9\u8c61 \u00b6 \u5bf9\u8c61\u6982\u8ff0 \u00b6 \u5bf9\u8c61\u89c4\u8303\uff08Object Spec\uff09\uff1a \u63d0\u4f9b\u4e86\u4e00\u4e2a\u63cf\u8ff0\u6240\u521b\u5efa\u8d44\u6e90\u7684\u7279\u6027\u7684\u8bf4\u660e\uff1a \u5176\u671f\u671b\u7684\u72b6\u6001 \u3002 \u5bf9\u8c61\u72b6\u6001\uff08Object Status\uff09\uff1a \u63cf\u8ff0\u4e86\u5bf9\u8c61\u7684\u5f53\u524d\u72b6\u6001\u3002 \u6bd4\u5982\uff0cDeployment\u662f\u4e00\u4e2a\u53ef\u4ee5\u4ee3\u8868\u96c6\u7fa4\u4e0a\u8fd0\u884c\u7684\u5e94\u7528\u7a0b\u5e8f\u7684\u5bf9\u8c61\u3002 apiVersion : apps/v1 # \u5f53\u524d\u7528\u6765\u521b\u5efa\u5bf9\u8c61\u7684API\u7248\u672c kind : Deployment # \u521b\u5efa\u5bf9\u8c61\u7684\u7c7b\u578b metadata : # \u7528\u6765\u533a\u5206\u5bf9\u8c61\u7684\u5143\u6570\u636e\uff0c\u6bd4\u5982\uff1a\u540d\u79f0\uff0cUID\uff0c\u547d\u540d\u7a7a\u95f4\u7b49 name : nginx-deployment spec : # \u671f\u671b\u6240\u521b\u5efa\u5bf9\u8c61\u7684\u72b6\u6001 selector : matchLabels : app : nginx replicas : 2 # \u544a\u8bc9Deployment\u57fa\u4e8e\u4e0b\u9762\u7684\u6a21\u677ftemplate\u521b\u5efa2\u4e2aPods template : metadata : labels : app : nginx spec : containers : - name : nginx image : nginx:1.14.2 ports : - containerPort : 80 \u5bf9\u8c61\u7ba1\u7406 \u00b6 kubectl \u547d\u4ee4\u884c\u5de5\u5177\u652f\u6301\u591a\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u6765\u521b\u5efa\u548c\u7ba1\u7406 Kubernetes \u5bf9\u8c61\u3002\u8be6\u7ec6\u4fe1\u606f\u8bf7\u9605\u8bfb Kubectl book \u3002 \u4e00\u4e2a Kubernetes \u5bf9\u8c61\u5e94\u8be5\u4ec5\u4f7f\u7528\u4e00\u79cd\u6280\u672f\u8fdb\u884c\u7ba1\u7406\u3002\u6df7\u5408\u4f7f\u7528\u4e0d\u540c\u7684\u6280\u672f\u6765\u7ba1\u7406\u540c\u4e00\u4e2a\u5bf9\u8c61\u4f1a\u5bfc\u81f4\u975e\u9884\u671f\u7684\u7ed3\u679c\u3002 \u4e09\u79cd\u7ba1\u7406\u6280\u672f: \u547d\u4ee4\u5f0f\u547d\u4ee4 \u76f4\u63a5\u5728\u96c6\u7fa4\u4e2d\u64cd\u4f5c\u5b9e\u65f6\u5bf9\u8c61\u3002 kubectl create deployment nginx --image nginx \u547d\u4ee4\u5f0f\u5bf9\u8c61\u914d\u7f6e kubectl create -f nginx.yaml kubectl delete -f nginx.yaml -f redis.yaml kubectl replace -f nginx.yaml \u58f0\u660e\u5f0f\u5bf9\u8c61\u914d\u7f6e kubectl diff -f configs/ kubectl apply -f configs/ \u5bf9\u8c61\u540d\u79f0\u548cID \u00b6 \u96c6\u7fa4\u4e2d\u7684\u6bcf\u4e2a\u5bf9\u8c61\u90fd\u6709\u4e00\u4e2a\u5728\u8be5\u8d44\u6e90\u7c7b\u578b\u4e2d\u552f\u4e00\u7684\u540d\u79f0\u3002 DNS \u5b50\u57df\u540d \u6807\u7b7e\u540d\u79f0 \u8def\u5f84\u6bb5\u540d\u79f0 \u6bcf\u4e2a Kubernetes \u5bf9\u8c61\u8fd8\u6709\u4e00\u4e2a UID\uff0c\u5728\u6574\u4e2a\u96c6\u7fa4\u4e2d\u662f\u552f\u4e00\u7684\u3002 \u547d\u540d\u7a7a\u95f4 \u00b6 \u5728Kubernetes\u4e2d\uff0c\u547d\u540d\u7a7a\u95f4\u63d0\u4f9b\u4e86\u4e00\u79cd\u5728\u5355\u4e2a\u96c6\u7fa4\u5185\u9694\u79bb\u8d44\u6e90\u7ec4\u7684\u673a\u5236\u3002 \u8d44\u6e90\u7684\u540d\u79f0\u9700\u8981\u5728\u547d\u540d\u7a7a\u95f4\u5185\u662f\u552f\u4e00\u7684\uff0c\u4f46\u4e0d\u9700\u8981\u8de8\u547d\u540d\u7a7a\u95f4\u552f\u4e00\u3002 \u57fa\u4e8e\u547d\u540d\u7a7a\u95f4\u7684\u8303\u56f4\u4ec5\u9002\u7528\u4e8e\u547d\u540d\u7a7a\u95f4\u5bf9\u8c61\uff08\u4f8b\u5982\u90e8\u7f72\uff0c\u670d\u52a1\u7b49\uff09\uff0c\u800c\u4e0d\u9002\u7528\u4e8e\u96c6\u7fa4\u8303\u56f4\u7684\u5bf9\u8c61\uff08\u4f8b\u5982StorageClass\uff0c\u8282\u70b9\uff0c\u6301\u4e45\u5377\u7b49\uff09\u3002 \u5e76\u975e\u6240\u6709\u5bf9\u8c61\u90fd\u4f4d\u4e8e\u547d\u540d\u7a7a\u95f4\u4e2d\u3002 Kubernetes\u4ece\u56db\u4e2a\u521d\u59cb\u547d\u540d\u7a7a\u95f4\u5f00\u59cb\uff1a default \u7528\u4e8e\u6ca1\u6709\u5176\u4ed6\u547d\u540d\u7a7a\u95f4\u7684\u5bf9\u8c61\u7684\u9ed8\u8ba4\u547d\u540d\u7a7a\u95f4 kube-system Kubernetes\u7cfb\u7edf\u521b\u5efa\u7684\u5bf9\u8c61\u7684\u547d\u540d\u7a7a\u95f4 kube-public \u8be5\u547d\u540d\u7a7a\u95f4\u662f\u81ea\u52a8\u521b\u5efa\u7684\uff0c\u5e76\u53ef\u7531\u6240\u6709\u7528\u6237\uff08\u5305\u62ec\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\uff09\u8bfb\u53d6\u3002\u6b64\u547d\u540d\u7a7a\u95f4\u5927\u591a\u4fdd\u7559\u4f9b\u96c6\u7fa4\u4f7f\u7528\uff0c\u4ee5\u9632\u4e00\u4e9b\u8d44\u6e90\u5e94\u5728\u6574\u4e2a\u96c6\u7fa4\u8303\u56f4\u5185\u516c\u5f00\u548c\u53ef\u8bfb\u3002\u6b64\u547d\u540d\u7a7a\u95f4\u7684\u516c\u5171\u65b9\u9762\u53ea\u662f\u4e00\u79cd\u7ea6\u5b9a\uff0c\u800c\u4e0d\u662f\u8981\u6c42\u3002 kube-node-lease \u6b64\u547d\u540d\u7a7a\u95f4\u4fdd\u5b58\u4e0e\u6bcf\u4e2a\u8282\u70b9\u5173\u8054\u7684\u79df\u8d41\u5bf9\u8c61\u3002\u8282\u70b9\u79df\u8d41\u5141\u8bb8kubelet\u53d1\u9001\u5fc3\u8df3\uff0c\u4ee5\u4fbf\u63a7\u5236\u5e73\u9762\u53ef\u4ee5\u68c0\u6d4b\u5230\u8282\u70b9\u6545\u969c\u3002 \u67e5\u770b\u547d\u540d\u7a7a\u95f4\uff1a kubectl get namespace \u4e3a\u8bf7\u6c42\u8bbe\u7f6e\u547d\u540d\u7a7a\u95f4 kubectl run nginx --image=nginx --namespace=<\u63d2\u5165\u547d\u540d\u7a7a\u95f4\u540d\u79f0> kubectl get pods --namespace=<\u63d2\u5165\u547d\u540d\u7a7a\u95f4\u540d\u79f0> \u6807\u7b7e\u548c\u9009\u62e9\u5668 \u00b6 \u6807\u7b7e\u662f\u9644\u52a0\u5230\u5bf9\u8c61\uff08\u4f8b\u5982 Pod\uff09\u7684\u952e/\u503c\u5bf9\u3002\u6709\u6548\u7684\u6807\u7b7e\u952e\u6709\u4e24\u4e2a\u90e8\u5206\uff1a\u53ef\u9009\u7684\u524d\u7f00\u548c\u540d\u79f0\uff0c\u7531\u659c\u6760\uff08 / \uff09\u5206\u9694\u3002 \u6807\u7b7e\u65e8\u5728\u7528\u4e8e\u6307\u5b9a\u5bf9\u7528\u6237\u6709\u610f\u4e49\u548c\u76f8\u5173\u7684\u5bf9\u8c61\u8bc6\u522b\u5c5e\u6027\u3002 \u6807\u7b7e\u53ef\u7528\u4e8e\u7ec4\u7ec7\u548c\u9009\u62e9\u5bf9\u8c61\u5b50\u96c6\u3002\u6807\u7b7e\u53ef\u4ee5\u5728\u521b\u5efa\u5bf9\u8c61\u65f6\u9644\u52a0\uff0c\u968f\u540e\u5728\u4efb\u4f55\u65f6\u5019\u6dfb\u52a0\u548c\u4fee\u6539\u3002\u6bcf\u4e2a\u5bf9\u8c61\u53ef\u4ee5\u5b9a\u4e49\u4e00\u7ec4\u952e/\u503c\u6807\u7b7e\uff0c\u6bcf\u4e2a\u952e\u5fc5\u987b\u5bf9\u4e8e\u7ed9\u5b9a\u5bf9\u8c61\u662f\u552f\u4e00\u7684\u3002 \u6807\u7b7e\u7684\u793a\u4f8b\uff1a \"metadata\" : { \"labels\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } \u4e0e\u540d\u79f0\u548c UID \u4e0d\u540c\uff0c\u6807\u7b7e\u4e0d\u63d0\u4f9b\u552f\u4e00\u6027\u3002\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u671f\u671b\u8bb8\u591a\u5bf9\u8c61\u5e26\u6709\u76f8\u540c\u7684\u6807\u7b7e\u3002 \u76ee\u524d API \u652f\u6301\u4e24\u79cd\u7c7b\u578b\u7684\u9009\u62e9\u5668\uff1a \u57fa\u4e8e\u7b49\u5f0f\u7684\u9009\u62e9\u5668\uff0c\u4f8b\u5982\uff1a environment = production \u3001 tier != frontend \u57fa\u4e8e\u96c6\u5408\u7684\u9009\u62e9\u5668\uff0c\u4f8b\u5982\uff1a environment in (production, qa) \u3001 tier notin (frontend, backend) \u4f8b\u5982\uff1a kubectl get pods -l environment = production,tier = frontend kubectl get pods -l 'environment in (production),tier in (frontend)' kubectl get pods -l 'environment in (production, qa)' kubectl get pods -l 'environment,environment notin (frontend)' \u6ce8\u91caAnnotations \u00b6 \u4f7f\u7528 Kubernetes \u6ce8\u91ca\uff08Annotations\uff09\u5c06\u4efb\u610f\u975e\u6807\u8bc6\u5143\u6570\u636e\u9644\u52a0\u5230\u5bf9\u8c61\u4e0a\u3002 \u5de5\u5177\u548c\u5e93\u7b49\u5ba2\u6237\u7aef\u53ef\u4ee5\u68c0\u7d22\u6b64\u5143\u6570\u636e\u3002 \u4f7f\u7528\u6807\u7b7e\u6216\u6ce8\u91ca\u5c06\u5143\u6570\u636e\u9644\u52a0\u5230 Kubernetes \u5bf9\u8c61\u4e0a\u3002 \u6807\u7b7e\u53ef\u7528\u4e8e\u9009\u62e9\u5bf9\u8c61\u5e76\u67e5\u627e\u6ee1\u8db3\u67d0\u4e9b\u6761\u4ef6\u7684\u5bf9\u8c61\u96c6\u5408\u3002 \u6ce8\u91ca\u4e0d\u7528\u4e8e\u6807\u8bc6\u548c\u9009\u62e9\u5bf9\u8c61\u3002 \u6ce8\u91ca\u4e0e\u6807\u7b7e\u7c7b\u4f3c\uff0c\u90fd\u662f\u952e/\u503c\u6620\u5c04\u3002 \u6620\u5c04\u4e2d\u7684\u952e\u548c\u503c\u5fc5\u987b\u662f\u5b57\u7b26\u4e32\u3002 \u4f8b\u5982\uff1a \"metadata\" : { \"annotations\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } \u5408\u6cd5\u7684\u6ce8\u91ca\u952e\u5177\u6709\u4e24\u4e2a\u90e8\u5206\uff1a\u53ef\u9009\u7684\u524d\u7f00\u548c\u540d\u79f0\uff0c\u7531\u659c\u6760 ( / ) \u5206\u9694\u3002 \u5b57\u6bb5\u9009\u62e9\u5668 \u00b6 \u5b57\u6bb5\u9009\u62e9\u5668\uff08field selectors\uff09\u53ef\u4ee5\u6839\u636e\u4e00\u4e2a\u6216\u591a\u4e2a\u8d44\u6e90\u5b57\u6bb5\u7684\u503c\u9009\u62e9Kubernetes\u8d44\u6e90\u3002 \u4e0b\u9762\u662f\u4e00\u4e9b\u4f7f\u7528\u5b57\u6bb5\u9009\u62e9\u5668\u8fdb\u884c\u67e5\u8be2\u7b5b\u9009\u7684\u4f8b\u5b50\uff1a metadata.name=my-service metadata.namespace!=default status.phase=Pending This kubectl command selects all Pods for which the value of the status.phase field is Running: kubectl get pods --field-selector status.phase=Running Supported field selectors vary by Kubernetes resource type. All resource types support the metadata.name and metadata.namespace fields. Use the = , == , and != operators with field selectors ( = and == mean the same thing). \u4e0b\u9762 kubectl \u547d\u4ee4\u9009\u62e9\u6240\u6709\u72b6\u6001(phase)\u5b57\u6bb5\u503c\u4e3a Running \u7684 Pod\uff1a kubectl get pods --field-selector status.phase = Running \u652f\u6301\u7684\u5b57\u6bb5\u9009\u62e9\u5668\u56e0 Kubernetes \u8d44\u6e90\u7c7b\u578b\u800c\u5f02\u3002\u6240\u6709\u8d44\u6e90\u7c7b\u578b\u90fd\u652f\u6301 metadata.name \u548c metadata.namespace \u5b57\u6bb5\u3002 \u5728\u5b57\u6bb5\u9009\u62e9\u5668\u4e2d\u4f7f\u7528 = , == , \u548c != \u8fd0\u7b97\u7b26( = \u548c == \u8868\u793a\u76f8\u540c\u7684\u610f\u601d)\u3002 \u4f8b\u5982\uff1a kubectl get ingress --field-selector foo.bar = baz kubectl get services --all-namespaces --field-selector metadata.namespace! = default kubectl get pods --field-selector = status.phase! = Running,spec.restartPolicy = Always kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace! = default Finalizers\u662f*\u547d\u540d\u7a7a\u95f4\u952e*\uff0c\u544a\u8bc9Kubernetes\u5728\u6ee1\u8db3\u7279\u5b9a\u6761\u4ef6\u4e4b\u524d\u7b49\u5f85\uff0c\u7136\u540e\u518d\u5b8c\u5168\u5220\u9664\u6807\u8bb0\u4e3a*\u5220\u9664*\u7684\u8d44\u6e90\u3002 Finalizer\u8b66\u544a\u63a7\u5236\u5668controller\u6e05\u7406\u5df2\u5220\u9664\u5bf9\u8c61\u6240\u62e5\u6709\u7684\u8d44\u6e90\u3002 \u901a\u5e38\u56e0\u4e3a\u67d0\u79cd\u76ee\u7684\u4e3a\u8d44\u6e90\u6dfb\u52a0Finalizers\uff0c\u5f3a\u5236\u5220\u9664\u5b83\u4eec\u53ef\u80fd\u4f1a\u5bfc\u81f4\u96c6\u7fa4\u4e2d\u51fa\u73b0\u95ee\u9898\u3002 \u4e0e\u6807\u7b7e\u7c7b\u4f3c\uff0c \u6240\u6709\u8005\u5f15\u7528 \uff08Owner references\uff09\u63cf\u8ff0\u4e86Kubernetes\u4e2d\u5bf9\u8c61\u4e4b\u95f4\u7684\u5173\u7cfb\uff0c\u4f46\u7528\u4e8e\u4e0d\u540c\u7684\u76ee\u7684\u3002 Kubernetes\u4f7f\u7528\u6240\u6709\u8005\u5f15\u7528\uff08\u800c\u4e0d\u662f\u6807\u7b7e\uff09\u6765\u786e\u5b9a\u96c6\u7fa4\u4e2d\u54ea\u4e9bPod\u9700\u8981\u6e05\u7406\u3002 \u5f53Kubernetes\u8bc6\u522b\u5230\u76ee\u6807\u5220\u9664\u7684\u8d44\u6e90\u4e0a\u6709\u6240\u6709\u8005\u5f15\u7528\u65f6\uff0c\u5b83\u4f1a\u5904\u7406Finalizer\u3002 \u6240\u6709\u8005\u548c\u4f9d\u8d56\u5173\u7cfb \u00b6 \u5728 Kubernetes \u4e2d\uff0c\u4e00\u4e9b\u5bf9\u8c61\u62e5\u6709\u5176\u4ed6\u5bf9\u8c61\u3002\u4f8b\u5982\uff0cReplicaSet \u662f\u4e00\u7ec4 Pod \u7684\u6240\u6709\u8005\u3002\u8fd9\u4e9b\u88ab\u62e5\u6709\u7684\u5bf9\u8c61\u662f\u5176\u6240\u6709\u8005\u7684\u4ece\u5c5e\u5bf9\u8c61\u3002 \u4ece\u5c5e\u5bf9\u8c61\u5177\u6709\u4e00\u4e2a metadata.ownerReferences \u5b57\u6bb5\uff0c\u8be5\u5b57\u6bb5\u5f15\u7528\u5176\u6240\u6709\u8005\u5bf9\u8c61\u3002 \u6709\u6548\u7684\u6240\u6709\u8005\u5f15\u7528\u5305\u62ec\u5bf9\u8c61\u540d\u79f0\u548c\u4e0e\u4ece\u5c5e\u5bf9\u8c61\u76f8\u540c\u7684\u547d\u540d\u7a7a\u95f4\u4e2d\u7684 UID\u3002 \u4ece\u5c5e\u5bf9\u8c61\u8fd8\u5177\u6709\u4e00\u4e2a ownerReferences.blockOwnerDeletion \u5b57\u6bb5\uff0c\u8be5\u5b57\u6bb5\u5177\u6709\u5e03\u5c14\u503c\uff0c\u63a7\u5236\u7279\u5b9a\u7684\u4ece\u5c5e\u5bf9\u8c61\u662f\u5426\u53ef\u4ee5\u963b\u6b62\u5783\u573e\u56de\u6536\u5220\u9664\u5176\u6240\u6709\u8005\u5bf9\u8c61\u3002 \u8d44\u6e90 \u00b6 Kubernetes\u8d44\u6e90\u548c\u201c\u610f\u5411\u8bb0\u5f55\u201d\u90fd\u4ee5API\u5bf9\u8c61\u7684\u5f62\u5f0f\u5b58\u50a8\uff0c\u5e76\u901a\u8fc7\u5bf9API\u7684RESTful\u8c03\u7528\u8fdb\u884c\u4fee\u6539\u3002 API\u5141\u8bb8\u4ee5\u58f0\u660e\u6027\u65b9\u5f0f\u7ba1\u7406\u914d\u7f6e\u3002 \u7528\u6237\u53ef\u4ee5\u76f4\u63a5\u4e0eKubernetes API\u4ea4\u4e92\uff0c\u4e5f\u53ef\u4ee5\u901a\u8fc7\u50cfkubectl\u8fd9\u6837\u7684\u5de5\u5177\u8fdb\u884c\u4ea4\u4e92\u3002 \u6838\u5fc3Kubernetes API\u5177\u6709\u7075\u6d3b\u6027\uff0c\u4e5f\u53ef\u4ee5\u6269\u5c55\u4ee5\u652f\u6301\u81ea\u5b9a\u4e49\u8d44\u6e90\u3002 \u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\uff08Workload Resources\uff09 Pod \u3002Pod \u662f\u53ef\u4ee5\u5728\u4e3b\u673a\u4e0a\u8fd0\u884c\u7684\u5bb9\u5668\u96c6\u5408\u3002 PodTemplate \u3002PodTemplate \u63cf\u8ff0\u4e86\u9884\u5b9a\u4e49 pod \u7684\u526f\u672c\u6a21\u677f\u3002 ReplicationController \u3002ReplicationController \u8868\u793a\u4e00\u4e2a\u590d\u5236\u63a7\u5236\u5668\u7684\u914d\u7f6e\u3002 ReplicaSet \u3002ReplicaSet \u786e\u4fdd\u5728\u4efb\u4f55\u7ed9\u5b9a\u65f6\u95f4\u6709\u6307\u5b9a\u6570\u91cf\u7684 pod \u526f\u672c\u6b63\u5728\u8fd0\u884c\u3002 Deployment \u3002Deployment \u4f7f Pod \u548c ReplicaSet \u7684\u58f0\u660e\u6027\u66f4\u65b0\u6210\u4e3a\u53ef\u80fd\u3002 StatefulSet \u3002StatefulSet \u8868\u793a\u5177\u6709\u4e00\u81f4\u6807\u8bc6\u7684 pod \u96c6\u5408\u3002 ControllerRevision \u3002ControllerRevision \u5b9e\u73b0\u4e86\u72b6\u6001\u6570\u636e\u7684\u4e0d\u53ef\u53d8\u5feb\u7167\u3002 DaemonSet \u3002DaemonSet \u8868\u793a\u4e00\u4e2a\u5b88\u62a4\u8fdb\u7a0b\u96c6\u7684\u914d\u7f6e\u3002 Job \u3002Job \u8868\u793a\u5355\u4e2a job \u7684\u914d\u7f6e\u3002 CronJob \u3002CronJob \u8868\u793a\u5355\u4e2a cron job \u7684\u914d\u7f6e\u3002 HorizontalPodAutoscaler \u3002HorizontalPodAutoscaler \u8868\u793a\u6c34\u5e73 pod \u81ea\u52a8\u7f29\u653e\u5668\u7684\u914d\u7f6e\u3002 HorizontalPodAutoscaler v2beta2 \u3002HorizontalPodAutoscaler \u662f\u6c34\u5e73 pod \u81ea\u52a8\u7f29\u653e\u5668\u7684\u914d\u7f6e\uff0c\u6839\u636e\u6307\u5b9a\u7684\u6307\u6807\u81ea\u52a8\u7ba1\u7406\u5b9e\u73b0\u6bd4\u4f8b\u5b50\u8d44\u6e90\u7684\u4efb\u4f55\u8d44\u6e90\u7684\u526f\u672c\u8ba1\u6570\u3002 PriorityClass \u3002PriorityClass \u5b9a\u4e49\u4e86\u4ece\u4f18\u5148\u7ea7\u7c7b\u540d\u79f0\u5230\u4f18\u5148\u7ea7\u6574\u6570\u503c\u7684\u6620\u5c04\u3002 \u670d\u52a1\u8d44\u6e90\uff08Service Resources\uff09 Service . Service \u662f\u5bf9\u8f6f\u4ef6\u670d\u52a1\uff08\u4f8b\u5982mysql\uff09\u7684\u547d\u540d\u62bd\u8c61\uff0c\u7531\u4ee3\u7406\u76d1\u542c\u7684\u672c\u5730\u7aef\u53e3\uff08\u4f8b\u59823306\uff09\u548c\u786e\u5b9a\u54ea\u4e9bPod\u5c06\u56de\u7b54\u901a\u8fc7\u4ee3\u7406\u53d1\u9001\u7684\u8bf7\u6c42\u7684\u9009\u62e9\u5668\u7ec4\u6210\u3002 Endpoints . Endpoints \u662f\u5b9e\u73b0\u5b9e\u9645\u670d\u52a1\u7684\u4e00\u7ec4\u7ec8\u7ed3\u70b9\u3002 EndpointSlice . EndpointSlice \u8868\u793a\u5b9e\u73b0\u670d\u52a1\u7684\u7ec8\u7ed3\u70b9\u7684\u5b50\u96c6\u3002 Ingress . Ingress \u662f\u4e00\u7ec4\u89c4\u5219\uff0c\u5141\u8bb8\u5165\u7ad9\u8fde\u63a5\u5230\u8fbe\u7531\u540e\u7aef\u5b9a\u4e49\u7684\u7ec8\u7ed3\u70b9\u3002 IngressClass . IngressClass \u8868\u793a Ingress \u7684\u7c7b\uff0c\u7531 Ingress Spec \u5f15\u7528\u3002 \u914d\u7f6e\u548c\u5b58\u50a8\u8d44\u6e90\uff08Config and Storage Resources\uff09 ConfigMap \u3002ConfigMap\u4fdd\u5b58\u5bb9\u5668\u9700\u8981\u4f7f\u7528\u7684\u914d\u7f6e\u6570\u636e\u3002 Secret \u3002Secret\u4fdd\u5b58\u7279\u5b9a\u7c7b\u578b\u7684\u673a\u5bc6\u6570\u636e\u3002 Volume \u3002Volume\u8868\u793aPod\u4e2d\u7684\u547d\u540d\u5377\uff0c\u53ef\u4ee5\u88abPod\u4e2d\u7684\u4efb\u4f55\u5bb9\u5668\u8bbf\u95ee\u3002 PersistentVolumeClaim \u3002PersistentVolumeClaim\u662f\u7528\u6237\u5bf9\u6301\u4e45\u5377\u7684\u8bf7\u6c42\u548c\u58f0\u660e\u3002 PersistentVolume \u3002PersistentVolume\uff08PV\uff09\u662f\u7531\u7ba1\u7406\u5458\u63d0\u4f9b\u7684\u5b58\u50a8\u8d44\u6e90\u3002 StorageClass \u3002StorageClass\u63cf\u8ff0\u53ef\u52a8\u6001\u5206\u914dPersistentVolumes\u7684\u5b58\u50a8\u7c7b\u522b\u7684\u53c2\u6570\u3002 VolumeAttachment \u3002VolumeAttachment\u8bb0\u5f55\u5c06\u6307\u5b9a\u7684\u5377\u9644\u52a0\u5230/\u4ece\u6307\u5b9a\u8282\u70b9\u4e2d\u5206\u79bb\u7684\u610f\u56fe\u3002 CSIDriver \u3002CSIDriver\u8bb0\u5f55\u96c6\u7fa4\u4e0a\u90e8\u7f72\u7684\u5bb9\u5668\u5b58\u50a8\u63a5\u53e3\uff08CSI\uff09\u5377\u9a71\u52a8\u7a0b\u5e8f\u7684\u4fe1\u606f\u3002 CSINode \u3002CSINode\u4fdd\u5b58\u6709\u5173\u8282\u70b9\u4e0a\u5b89\u88c5\u7684\u6240\u6709CSI\u9a71\u52a8\u7a0b\u5e8f\u7684\u4fe1\u606f\u3002 CSIStorageCapacity \u3002CSIStorageCapacity\u5b58\u50a8\u4e00\u4e2aCSI GetCapacity\u8c03\u7528\u7684\u7ed3\u679c\u3002 \u8ba4\u8bc1\u8d44\u6e90\uff08Authentication Resources\uff09 ServiceAccount*\u3002ServiceAccount\u548c\u4e0b\u9762\u7684\u4fe1\u606f\u7ed1\u5b9a\u5728\u4e00\u8d77\uff1a \u4e00\u4e2a\u53ef\u88ab\u7528\u6237\u548c\u5468\u8fb9\u7cfb\u7edf\u7406\u89e3\u7684\u540d\u79f0\uff0c\u7528\u4e8e\u8eab\u4efd\u8bc6\u522b \u53ef\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u7684\u4e3b\u4f53 \u4e00\u7ec4\u5bc6\u94a5\u3002 TokenRequest*\u3002TokenRequest\u4e3a\u7ed9\u5b9a\u7684ServiceAccount\u8bf7\u6c42\u4e00\u4e2a\u4ee4\u724c\u3002 TokenReview*\u3002TokenReview\u5c1d\u8bd5\u5bf9\u5df2\u77e5\u7528\u6237\u7684\u4ee4\u724c\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u3002 CertificateSigningRequest*\u3002CertificateSigningRequest\u5bf9\u8c61\u63d0\u4f9b\u4e86\u4e00\u79cd\u901a\u8fc7\u63d0\u4ea4\u8bc1\u4e66\u7b7e\u540d\u8bf7\u6c42\u5e76\u5f02\u6b65\u6279\u51c6\u548c\u53d1\u653e\u6765\u83b7\u53d6x509\u8bc1\u4e66\u7684\u673a\u5236\u3002 \u6388\u6743\u8d44\u6e90\uff08Authorization Resources\uff09 LocalSubjectAccessReview*\u3002LocalSubjectAccessReview\u68c0\u67e5\u4e00\u4e2a\u7528\u6237\u6216\u7ec4\u5728\u7ed9\u5b9a\u547d\u540d\u7a7a\u95f4\u4e2d\u662f\u5426\u80fd\u6267\u884c\u67d0\u4e2a\u64cd\u4f5c\u3002 SelfSubjectAccessReview*\u3002SelfSubjectAccessReview\u68c0\u67e5\u5f53\u524d\u7528\u6237\u662f\u5426\u80fd\u6267\u884c\u67d0\u4e2a\u64cd\u4f5c\u3002 SelfSubjectRulesReview*\u3002SelfSubjectRulesReview\u679a\u4e3e\u5f53\u524d\u7528\u6237\u5728\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4\u5185\u53ef\u4ee5\u6267\u884c\u7684\u64cd\u4f5c\u96c6\u5408\u3002 SubjectAccessReview*\u3002SubjectAccessReview\u68c0\u67e5\u4e00\u4e2a\u7528\u6237\u6216\u7ec4\u662f\u5426\u80fd\u6267\u884c\u67d0\u4e2a\u64cd\u4f5c\u3002 ClusterRole*\u3002ClusterRole\u662f\u4e00\u4e2a\u96c6\u7fa4\u7ea7\u522b\u7684PolicyRules\u903b\u8f91\u5206\u7ec4\uff0c\u53ef\u4ee5\u88abRoleBinding\u6216ClusterRoleBinding\u5f15\u7528\u4e3a\u4e00\u4e2a\u5355\u5143\u3002 ClusterRoleBinding*\u3002ClusterRoleBinding\u5f15\u7528\u4e00\u4e2aClusterRole\uff0c\u4f46\u4e0d\u5305\u542b\u5b83\u3002 Role*\u3002Role\u662f\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4\u7ea7\u522b\u7684PolicyRules\u903b\u8f91\u5206\u7ec4\uff0c\u53ef\u4ee5\u88abRoleBinding\u5f15\u7528\u4e3a\u4e00\u4e2a\u5355\u5143\u3002 RoleBinding*\u3002RoleBinding\u5f15\u7528\u4e00\u4e2aRole\uff0c\u4f46\u4e0d\u5305\u542b\u5b83\u3002 \u7b56\u7565\u8d44\u6e90\uff08Policy Resources\uff09 LimitRange*\u3002LimitRange\u4e3a\u547d\u540d\u7a7a\u95f4\u4e2d\u6bcf\u79cd\u8d44\u6e90\u8bbe\u7f6e\u8d44\u6e90\u4f7f\u7528\u9650\u5236\u3002 ResourceQuota*\u3002ResourceQuota\u8bbe\u7f6e\u6bcf\u4e2a\u547d\u540d\u7a7a\u95f4\u5f3a\u5236\u6267\u884c\u7684\u603b\u914d\u989d\u9650\u5236\u3002 NetworkPolicy*\u3002NetworkPolicy\u63cf\u8ff0\u4e86\u4e00\u7ec4Pod\u5141\u8bb8\u7684\u7f51\u7edc\u6d41\u91cf\u3002 PodDisruptionBudget*\u3002PodDisruptionBudget\u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u7528\u4e8e\u5b9a\u4e49\u5bf9\u4e00\u7ec4Pod\u53ef\u80fd\u9020\u6210\u7684\u6700\u5927\u4e2d\u65ad\u3002 PodSecurityPolicy v1beta1*\u3002PodSecurityPolicy\u63a7\u5236\u5bf9\u53ef\u80fd\u5f71\u54cd\u5c06\u5e94\u7528\u4e8ePod\u548c\u5bb9\u5668\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\u7684\u8bf7\u6c42\u7684\u80fd\u529b\u3002 \u6269\u5c55\u8d44\u6e90\uff08Extend Resources\uff09 CustomResourceDefinition*\u3002CustomResourceDefinition\u8868\u793a\u5e94\u5728API\u670d\u52a1\u5668\u4e0a\u516c\u5f00\u7684\u8d44\u6e90\u3002 MutatingWebhookConfiguration*\u3002MutatingWebhookConfiguration\u63cf\u8ff0\u63a5\u53d7\u6216\u62d2\u7edd\u5e76\u53ef\u80fd\u66f4\u6539\u5bf9\u8c61\u7684\u51c6\u5165Webhook\u7684\u914d\u7f6e\u3002 ValidatingWebhookConfiguration*\u3002ValidatingWebhookConfiguration\u63cf\u8ff0\u63a5\u53d7\u6216\u62d2\u7edd\u5bf9\u8c61\u4f46\u4e0d\u66f4\u6539\u5bf9\u8c61\u7684\u51c6\u5165Webhook\u7684\u914d\u7f6e\u3002 \u96c6\u7fa4\u8d44\u6e90\uff08Cluster Resources\uff09 Node*\u3002Node\u662fKubernetes\u4e2d\u7684\u5de5\u4f5c\u8282\u70b9\u3002 Namespace*\u3002Namespace\u4e3a\u540d\u79f0\u63d0\u4f9b\u4e86\u4f5c\u7528\u57df\u3002 Event*\u3002Event\u662f\u5bf9\u96c6\u7fa4\u4e2d\u67d0\u4e2a\u4f4d\u7f6e\u53d1\u751f\u4e8b\u4ef6\u7684\u62a5\u544a\u3002 APIService*\u3002APIService\u8868\u793a\u7279\u5b9aGroupVersion\u7684\u670d\u52a1\u5668\u3002 Lease*\u3002Lease\u5b9a\u4e49\u4e86\u79df\u8d41\u7684\u6982\u5ff5\u3002 RuntimeClass*\u3002RuntimeClass\u5b9a\u4e49\u4e86\u96c6\u7fa4\u4e2d\u652f\u6301\u7684\u5bb9\u5668\u8fd0\u884c\u65f6\u7c7b\u3002 FlowSchema v1beta2*\u3002FlowSchema\u5b9a\u4e49\u4e86\u4e00\u7ec4\u6d41\u7a0b\u7684\u67b6\u6784\u3002 PriorityLevelConfiguration v1beta2*\u3002PriorityLevelConfiguration\u8868\u793a\u4f18\u5148\u7ea7\u7ea7\u522b\u7684\u914d\u7f6e\u3002 Binding*\u3002Binding\u5c06\u4e00\u4e2a\u5bf9\u8c61\u7ed1\u5b9a\u5230\u53e6\u4e00\u4e2a\u5bf9\u8c61\uff1b\u4f8b\u5982\uff0c\u8c03\u5ea6\u7a0b\u5e8f\u5c06Pod\u7ed1\u5b9a\u5230\u8282\u70b9\u4e0a\u3002 ComponentStatus*\u3002ComponentStatus\uff08\u548cComponentStatusList\uff09\u4fdd\u5b58\u96c6\u7fa4\u9a8c\u8bc1\u4fe1\u606f\u3002 \u4f7f\u7528\u547d\u4ee4 kube api-resources \u83b7\u53d6\u652f\u6301\u7684API\u8d44\u6e90\u3002 \u4f7f\u7528\u547d\u4ee4 kubectl explain RESOURCE [options] \u63cf\u8ff0\u4e0e\u6bcf\u4e2a\u652f\u6301\u7684API\u8d44\u6e90\u76f8\u5173\u8054\u7684\u5b57\u6bb5\u3002\u8fd9\u4e9b\u5b57\u6bb5\u53ef\u4ee5\u901a\u8fc7\u7b80\u5355\u7684JSONPath\u6807\u8bc6\u7b26\u8fdb\u884c\u8bc6\u522b\uff1a kubectl explain binding kubectl explain binding.metadata kubectl explain binding.metadata.name \u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90 \u00b6 Pods \u00b6 Pod\u662fKubernetes\u4e2d\u53ef\u521b\u5efa\u548c\u7ba1\u7406\u7684\u6700\u5c0f\u90e8\u7f72\u8ba1\u7b97\u5355\u4f4d\u3002 Pod\u662f\u4e00\u4e2a\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u5bb9\u5668\u3001\u5171\u4eab\u5b58\u50a8\u548c\u7f51\u7edc\u8d44\u6e90\u4ee5\u53ca\u5982\u4f55\u8fd0\u884c\u5bb9\u5668\u7684\u89c4\u8303\u7684\u7ec4\u3002 Pod\u7684\u5185\u5bb9\u59cb\u7ec8\u5171\u540c\u5b9a\u4f4d\u548c\u5171\u540c\u5b89\u6392\uff0c\u5e76\u5728\u5171\u4eab\u73af\u5883\u4e2d\u8fd0\u884c\u3002 Pod\u6a21\u62df\u4e86\u4e00\u4e2a\u7279\u5b9a\u4e8e\u5e94\u7528\u7a0b\u5e8f\u7684\u201c\u903b\u8f91\u4e3b\u673a\u201d\uff1a\u5b83\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u76f8\u5bf9\u7d27\u5bc6\u8026\u5408\u7684\u5e94\u7528\u7a0b\u5e8f\u5bb9\u5668\u3002 \u5728\u975e\u4e91\u73af\u5883\u4e2d\uff0c\u540c\u4e00\u7269\u7406\u6216\u865a\u62df\u673a\u4e0a\u6267\u884c\u7684\u5e94\u7528\u7a0b\u5e8f\u7c7b\u4f3c\u4e8e\u5728\u540c\u4e00\u903b\u8f91\u4e3b\u673a\u4e0a\u6267\u884c\u7684\u4e91\u5e94\u7528\u7a0b\u5e8f\u3002 Pod\u7684\u5171\u4eab\u73af\u5883\u662f\u4e00\u7ec4Linux\u547d\u540d\u7a7a\u95f4\u3001cgroups\u548c\u53ef\u80fd\u7684\u5176\u4ed6\u9694\u79bb\u8981\u7d20 - \u8fd9\u4e9b\u8981\u7d20\u4e0e\u9694\u79bbDocker\u5bb9\u5668\u7684\u65b9\u5f0f\u76f8\u540c\u3002 \u5728Docker\u6982\u5ff5\u65b9\u9762\uff0cPod\u7c7b\u4f3c\u4e8e\u5177\u6709\u5171\u4eab\u547d\u540d\u7a7a\u95f4\u548c\u5171\u4eab\u6587\u4ef6\u7cfb\u7edf\u5377\u7684\u4e00\u7ec4Docker\u5bb9\u5668\u3002 \u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u751a\u81f3\u662f\u5355\u4f8bPod\uff0c\u6211\u4eec\u90fd\u4e0d\u9700\u8981\u76f4\u63a5\u521b\u5efaPod\uff0c\u800c\u662f\u4f7f\u7528\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\uff0c\u4f8b\u5982*Deployment*\u6216*Job*\u6765\u521b\u5efa\u5b83\u4eec\u3002\u5982\u679cPod\u9700\u8981\u8ddf\u8e2a\u72b6\u6001\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528StatefulSet\u8d44\u6e90\u3002 Kubernetes\u96c6\u7fa4\u4e2d\u7684Pod\u6709\u4e24\u79cd\u4e3b\u8981\u7528\u6cd5\uff1a \u8fd0\u884c\u5355\u4e2a\u5bb9\u5668\u7684Pod\u3002 \u8fd0\u884c\u9700\u8981\u5171\u540c\u5de5\u4f5c\u7684\u591a\u4e2a\u5bb9\u5668\u7684Pod\u3002 \u201c\u6bcf\u4e2aPod\u4e00\u4e2a\u5bb9\u5668\u201d\u7684\u6a21\u578b\u662f\u6700\u5e38\u89c1\u7684Kubernetes\u7528\u4f8b\uff1b\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\u53ef\u4ee5\u5c06Pod\u89c6\u4e3a\u5355\u4e2a\u5bb9\u5668\u7684\u5305\u88c5\u5668\uff1bKubernetes\u7ba1\u7406Pod\u800c\u4e0d\u662f\u76f4\u63a5\u7ba1\u7406\u5bb9\u5668\u3002 \u4e00\u4e2aPod\u53ef\u4ee5\u5c01\u88c5\u7531\u591a\u4e2a\u5171\u540c\u5b9a\u4f4d\u3001\u7d27\u5bc6\u8026\u5408\u4e14\u9700\u8981\u5171\u4eab\u8d44\u6e90\u7684\u5bb9\u5668\u7ec4\u6210\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 \u8fd9\u4e9b\u5171\u540c\u5b9a\u4f4d\u7684\u5bb9\u5668\u5f62\u6210\u4e00\u4e2a\u5355\u4e00\u7684\u670d\u52a1\u6574\u4f53\u5355\u5143 - \u4f8b\u5982\uff0c\u4e00\u4e2a\u5bb9\u5668\u5411\u516c\u4f17\u63d0\u4f9b\u5b58\u50a8\u5728\u5171\u4eab\u5377\u4e2d\u7684\u6570\u636e\uff0c\u800c\u53e6\u4e00\u4e2a\u72ec\u7acb\u7684Sidecar\u5bb9\u5668\u5237\u65b0\u6216\u66f4\u65b0\u8fd9\u4e9b\u6587\u4ef6\u3002Pod\u5c06\u8fd9\u4e9b\u5bb9\u5668\u3001\u5b58\u50a8\u8d44\u6e90\u548c\u77ed\u6682\u7684\u7f51\u7edc\u6807\u8bc6\u5305\u88c5\u5728\u4e00\u8d77\uff0c\u4f5c\u4e3a\u4e00\u4e2a\u5355\u72ec\u7684\u5355\u4f4d\u3002 \u5728\u5355\u4e2aPod\u4e2d\u5206\u7ec4\u591a\u4e2a\u5171\u540c\u5b9a\u4f4d\u548c\u5171\u540c\u7ba1\u7406\u7684\u5bb9\u5668\u662f\u76f8\u5bf9\u9ad8\u7ea7\u7684\u7528\u4f8b\u3002\u5e94\u8be5*\u4ec5\u5728*\u5bb9\u5668\u7d27\u5bc6\u8026\u5408\u7684\u7279\u5b9a\u60c5\u51b5\u4e0b\u4f7f\u7528\u6b64\u6a21\u5f0f\u3002 \u6bcf\u4e2aPod\u90fd\u65e8\u5728\u8fd0\u884c\u7ed9\u5b9a\u5e94\u7528\u7a0b\u5e8f\u7684\u5355\u4e2a\u5b9e\u4f8b\u3002\u5982\u679c\u6211\u4eec\u60f3\u6c34\u5e73\u6269\u5c55\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\uff08\u901a\u8fc7\u8fd0\u884c\u66f4\u591a\u5b9e\u4f8b\u63d0\u4f9b\u66f4\u591a\u7684\u603b\u8d44\u6e90\uff09\uff0c\u5219\u5e94\u8be5\u4f7f\u7528\u591a\u4e2aPod\uff0c\u6bcf\u4e2a\u5b9e\u4f8b\u4e00\u4e2aPod\u3002\u5728Kubernetes\u4e2d\uff0c\u8fd9\u901a\u5e38\u79f0\u4e3a*\u590d\u5236*\u3002\u590d\u5236\u7684Pod\u901a\u5e38\u4f5c\u4e3a\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\u53ca\u5176\u63a7\u5236\u5668\u7684\u4e00\u7ec4\u521b\u5efa\u548c\u7ba1\u7406\u3002 Pod\u672c\u5730\u63d0\u4f9b\u4e24\u79cd\u5171\u4eab\u8d44\u6e90\u4ee5\u4f9b\u5176\u7ec4\u6210\u5bb9\u5668\u4f7f\u7528\uff1a \u7f51\u7edc *\u548c \u5b58\u50a8 *\u3002 \u4e00\u4e2aPod\u53ef\u4ee5\u6307\u5b9a\u4e00\u7ec4\u5171\u4eab\u7684\u5b58\u50a8\u5377\u3002Pod\u4e2d\u7684\u6240\u6709\u5bb9\u5668\u90fd\u53ef\u4ee5\u8bbf\u95ee\u8fd9\u4e9b\u5171\u4eab\u5377\uff0c\u4f7f\u8fd9\u4e9b\u5bb9\u5668\u53ef\u4ee5\u5171\u4eab\u6570\u636e\u3002 \u6bcf\u4e2aPod\u4e3a\u6bcf\u4e2a\u5730\u5740\u65cf\u5206\u914d\u4e00\u4e2a\u552f\u4e00\u7684IP\u5730\u5740\u3002 \u5728\u4e00\u4e2aPod\u5185\uff0c\u5bb9\u5668\u5171\u4eab\u4e00\u4e2aIP\u5730\u5740\u548c\u7aef\u53e3\u7a7a\u95f4\uff0c\u5e76\u53ef\u4ee5\u901a\u8fc7\u201clocalhost\u201d\u627e\u5230\u5f7c\u6b64\u3002\u60f3\u8981\u4e0e\u8fd0\u884c\u5728\u4e0d\u540cPod\u4e2d\u7684\u5bb9\u5668\u4ea4\u4e92\u7684\u5bb9\u5668\u53ef\u4ee5\u4f7f\u7528IP\u7f51\u7edc\u8fdb\u884c\u901a\u4fe1\u3002 \u5f53\u521b\u5efa\u4e00\u4e2aPod\u65f6\uff0c\u65b0\u7684Pod\u88ab\u8c03\u5ea6\u5728\u96c6\u7fa4\u4e2d\u7684\u4e00\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u3002Pod\u4fdd\u7559\u5728\u8be5\u8282\u70b9\u4e0a\uff0c\u76f4\u5230Pod\u6267\u884c\u5b8c\u6bd5\u3001Pod\u5bf9\u8c61\u88ab\u5220\u9664\u3001Pod\u56e0\u7f3a\u4e4f\u8d44\u6e90\u800c\u88ab\u9a71\u9010\u6216\u8282\u70b9\u53d1\u751f\u6545\u969c\u3002 \u5728Pod\u4e2d\u91cd\u65b0\u542f\u52a8\u4e00\u4e2a\u5bb9\u5668\u4e0d\u5e94\u4e0e\u91cd\u65b0\u542f\u52a8\u4e00\u4e2aPod\u6df7\u6dc6\u3002Pod\u4e0d\u662f\u4e00\u4e2a\u8fdb\u7a0b\uff0c\u800c\u662f\u4e00\u4e2a\u8fd0\u884c\u5bb9\u5668\u7684\u73af\u5883\u3002Pod\u4f1a\u4e00\u76f4\u4fdd\u7559\uff0c\u76f4\u5230\u88ab\u5220\u9664\u4e3a\u6b62\u3002 \u60a8\u53ef\u4ee5\u4f7f\u7528\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\uff08\u4f8b\u5982Deployment\u3001StatefulSet\u3001DaemonSet\uff09\u4e3a\u81ea\u5df1\u521b\u5efa\u548c\u7ba1\u7406\u591a\u4e2aPod\u3002\u8d44\u6e90\u7684\u63a7\u5236\u5668\u5904\u7406\u590d\u5236\u3001\u6eda\u52a8\u548c\u5728Pod\u5931\u8d25\u65f6\u7684\u81ea\u52a8\u6062\u590d\u3002 \u521d\u59cb\u5316\u5bb9\u5668 \u00b6 \u4e00\u4e9bPod\u8fd8\u6709\u521d\u59cb\u5316\u5bb9\u5668\uff08Init containers\uff09\u548c\u5e94\u7528\u5bb9\u5668\uff08app containers\uff09\u3002\u521d\u59cb\u5316\u5bb9\u5668\u5728\u5e94\u7528\u5bb9\u5668\u542f\u52a8\u4e4b\u524d\u8fd0\u884c\u5e76\u5b8c\u6210\u3002 \u6211\u4eec\u53ef\u4ee5\u5728Pod\u89c4\u8303\u4e2d\u6307\u5b9a\u521d\u59cb\u5316\u5bb9\u5668\uff0c\u540c\u65f6\u4e5f\u53ef\u4ee5\u5728\u5bb9\u5668\u6570\u7ec4\u4e2d\u63cf\u8ff0\u5e94\u7528\u5bb9\u5668\u3002 \u9759\u6001Pod \u00b6 \u9759\u6001Pod\u662f\u76f4\u63a5\u7531\u7279\u5b9a\u8282\u70b9\u4e0a\u7684kubelet\u5b88\u62a4\u7a0b\u5e8f\u7ba1\u7406\u7684\uff0cAPI\u670d\u52a1\u5668\u4e0d\u4f1a\u89c2\u5bdf\u5b83\u4eec\u3002 \u9759\u6001Pod\u59cb\u7ec8\u7ed1\u5b9a\u5230\u7279\u5b9a\u8282\u70b9\u4e0a\u7684\u4e00\u4e2aKubelet\u3002 \u9759\u6001Pod\u7684\u4e3b\u8981\u7528\u9014\u662f\u8fd0\u884c\u81ea\u6258\u7ba1\u63a7\u5236\u9762\u677f\uff1a\u6362\u53e5\u8bdd\u8bf4\uff0c\u4f7f\u7528kubelet\u76d1\u7763\u5404\u4e2a\u63a7\u5236\u9762\u677f\u7ec4\u4ef6\u3002 kubelet\u4f1a\u81ea\u52a8\u5c1d\u8bd5\u4e3a\u6bcf\u4e2a\u9759\u6001Pod\u5728Kubernetes API\u670d\u52a1\u5668\u4e0a\u521b\u5efa\u4e00\u4e2a\u955c\u50cfPod\u3002\u8fd9\u610f\u5473\u7740\u5728\u8282\u70b9\u4e0a\u8fd0\u884c\u7684Pod\u5728API\u670d\u52a1\u5668\u4e0a\u53ef\u89c1\uff0c\u4f46\u65e0\u6cd5\u4ece\u90a3\u91cc\u63a7\u5236\u3002 \u5bb9\u5668\u63a2\u9488 \u00b6 \u63a2\u9488\u662f kubelet \u5b9a\u671f\u5bf9\u5bb9\u5668\u6267\u884c\u7684\u4e00\u79cd\u8bca\u65ad\u3002 \u4e3a\u6267\u884c\u8bca\u65ad\uff0ckubelet \u8981\u4e48\u5728\u5bb9\u5668\u5185\u6267\u884c\u4ee3\u7801\uff0c\u8981\u4e48\u53d1\u8d77\u7f51\u7edc\u8bf7\u6c42\u3002 \u4f7f\u7528\u63a2\u9488\u6709\u56db\u79cd\u4e0d\u540c\u7684\u68c0\u67e5\u5bb9\u5668\u65b9\u5f0f\u3002\u6bcf\u4e2a\u63a2\u9488\u5fc5\u987b\u6070\u597d\u5b9a\u4e49\u8fd9\u56db\u79cd\u673a\u5236\u4e2d\u7684\u4e00\u79cd\uff1a exec \u3002\u5982\u679c\u547d\u4ee4\u4ee5\u72b6\u6001\u4ee3\u7801 0 \u9000\u51fa\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 grpc \u3002\u5982\u679c\u54cd\u5e94\u7684\u72b6\u6001\u4e3a SERVING\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 httpGet \u3002\u5982\u679c\u54cd\u5e94\u7684\u72b6\u6001\u4ee3\u7801\u5927\u4e8e\u6216\u7b49\u4e8e 200 \u4e14\u5c0f\u4e8e 400\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 tcpSocket \u3002\u5982\u679c\u7aef\u53e3\u5f00\u653e\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 \u6bcf\u4e2a\u63a2\u9488\u6709\u4e09\u79cd\u7ed3\u679c\uff1a \u6210\u529f \u5931\u8d25 \u672a\u77e5 \u63a2\u9488\u7c7b\u578b\uff1a livenessProbe \u3002\u6307\u793a\u5bb9\u5668\u662f\u5426\u6b63\u5728\u8fd0\u884c\u3002 readinessProbe \u3002\u6307\u793a\u5bb9\u5668\u662f\u5426\u51c6\u5907\u597d\u54cd\u5e94\u8bf7\u6c42\u3002 startupProbe \u3002\u6307\u793a\u5bb9\u5668\u5185\u7684\u5e94\u7528\u7a0b\u5e8f\u662f\u5426\u542f\u52a8\u3002 Deployment \u00b6 ReplicaSet \u00b6 ReplicaSet\u7684\u76ee\u7684\u662f\u5728\u4efb\u4f55\u65f6\u5019\u7ef4\u62a4\u4e00\u7ec4\u7a33\u5b9a\u7684\u526f\u672cPod\u3002\u56e0\u6b64\uff0c\u5b83\u901a\u5e38\u7528\u4e8e\u4fdd\u8bc1\u6307\u5b9a\u6570\u91cf\u7684\u76f8\u540cPod\u7684\u53ef\u7528\u6027\u3002 \u6211\u4eec\u4e00\u822c\u4e0d\u9700\u8981\u76f4\u63a5\u64cd\u7eb5ReplicaSet\u5bf9\u8c61\uff1a\u4f7f\u7528Deployment\uff0c\u7136\u540e\u5728spec\u90e8\u5206\u4e2d\u5b9a\u4e49\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 \u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e replicaset.spec.replicas \u6765\u6307\u5b9a\u5e94\u540c\u65f6\u8fd0\u884c\u591a\u5c11\u4e2aPod\u3002 ReplicaSet\u5c06\u521b\u5efa/\u5220\u9664\u5176Pod\u4ee5\u5339\u914d\u6b64\u6570\u5b57\u3002 \u5982\u679c\u4e0d\u6307\u5b9a replicaset.spec.replicas \uff0c\u5219\u9ed8\u8ba4\u503c\u4e3a 1 \u3002 StatefulSet \u00b6 StatefulSet \u7279\u70b9\uff08\u53c8\u79f0\u56fa\u5b9a\u6807\u8bc6\uff09\uff1a Pod \u7684\u540d\u79f0\u5728\u521b\u5efa\u540e\u4e0d\u53ef\u53d8\u3002 DNS \u4e3b\u673a\u540d\u5728\u521b\u5efa\u540e\u4e0d\u53ef\u53d8\u3002 \u6302\u8f7d\u7684\u5377\u5728\u521b\u5efa\u540e\u4e0d\u53ef\u53d8\u3002 StatefulSet \u7684\u56fa\u5b9a\u6807\u8bc6\u5728\u5931\u8d25\u3001\u6269\u5c55\u548c\u5176\u4ed6\u64cd\u4f5c\u540e\u4e0d\u4f1a\u6539\u53d8\u3002 StatefulSet \u7684\u547d\u540d\u7ea6\u5b9a\u4e3a\uff1a - \u3002 StatefulSet \u53ef\u4ee5\u81ea\u884c\u8fdb\u884c\u6269\u5c55\uff0c\u4f46\u662f Deployment \u9700\u8981\u4f9d\u9760 ReplicaSet \u8fdb\u884c\u6269\u5c55\u3002 \u5efa\u8bae\uff1a\u5148\u5c06 StatefulSet \u51cf\u5c11\u5230 0\uff0c\u800c\u4e0d\u662f\u76f4\u63a5\u5220\u9664\u5b83\u3002 headless Service \u548c governing Service\uff1a Headless Service \u662f\u4e00\u4e2a\u666e\u901a\u7684 Kubernetes Service \u5bf9\u8c61\uff0c\u5176 spec.clusterIP \u88ab\u8bbe\u7f6e\u4e3a None \u3002 \u5f53 StatefulSet \u7684 spec.ServiceName \u8bbe\u7f6e\u4e3a headless Service \u540d\u79f0\u65f6\uff0cStatefulSet \u73b0\u5728\u662f\u4e00\u4e2a governing Service\u3002 \u521b\u5efa StatefulSet \u7684\u4e00\u822c\u8fc7\u7a0b\uff1a \u521b\u5efa StorageClass\u3002 \u521b\u5efa Headless Service\u3002 \u57fa\u4e8e\u4e0a\u8ff0\u4e24\u4e2a\u521b\u5efa StatefulSet\u3002 DaemonSet \u00b6 DaemonSet\u4fdd\u8bc1\u6240\u6709\uff08\u6216\u90e8\u5206\uff09\u8282\u70b9\u8fd0\u884cPod\u7684\u526f\u672c\u3002\u968f\u7740\u8282\u70b9\u4ece\u96c6\u7fa4\u4e2d\u5220\u9664\uff0c\u8fd9\u4e9bPod\u5c06\u88ab\u5783\u573e\u56de\u6536\u3002 \u5220\u9664DaemonSet\u5c06\u6e05\u7406\u5b83\u521b\u5efa\u7684Pod\u3002 \u4e00\u4e9b\u5178\u578bDaemonSet\u7684\u7528\u9014\u5305\u62ec\uff1a \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u96c6\u7fa4\u5b58\u50a8\u5b88\u62a4\u7a0b\u5e8f\u3002 \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u65e5\u5fd7\u6536\u96c6\u5b88\u62a4\u7a0b\u5e8f\u3002 \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u8282\u70b9\u76d1\u89c6\u5b88\u62a4\u7a0b\u5e8f\u3002 \u5728\u7b80\u5355\u7684\u60c5\u51b5\u4e0b\uff0c\u6bcf\u79cd\u7c7b\u578b\u7684\u5b88\u62a4\u7a0b\u5e8f\u5c06\u4f7f\u7528\u8986\u76d6\u6240\u6709\u8282\u70b9\u7684\u4e00\u4e2aDaemonSet\u3002 \u66f4\u590d\u6742\u7684\u8bbe\u7f6e\u53ef\u80fd\u4f1a\u4e3a\u5355\u4e2a\u5b88\u62a4\u7a0b\u5e8f\u4f7f\u7528\u591a\u4e2aDaemonSet\uff0c\u4f46\u4f7f\u7528\u4e0d\u540c\u7684\u6807\u5fd7\u548c/\u6216\u4e0d\u540c\u7684\u5185\u5b58\u548cCPU\u8bf7\u6c42\u6765\u652f\u6301\u4e0d\u540c\u7684\u786c\u4ef6\u7c7b\u578b\u3002 DaemonSet\u63a7\u5236\u5668\u8c03\u548c\u8fc7\u7a0b\u540c\u65f6\u68c0\u67e5\u73b0\u6709\u8282\u70b9\u548c\u65b0\u521b\u5efa\u7684\u8282\u70b9\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cKubernetes\u8c03\u5ea6\u7a0b\u5e8f\u5ffd\u7565\u7531DamonSet\u521b\u5efa\u7684Pod\uff0c\u5e76\u5141\u8bb8\u5b83\u4eec\u5b58\u5728\u4e8e\u8282\u70b9\u4e0a\uff0c\u76f4\u5230\u5173\u95ed\u8282\u70b9\u672c\u8eab\u3002 \u5728\u9009\u62e9\u8282\u70b9\u4e0a\u8fd0\u884cPod\uff1a \u5982\u679c\u60a8\u6307\u5b9a daemonset.spec.template.spec.nodeSelector \uff0c\u90a3\u4e48DaemonSet\u63a7\u5236\u5668\u5c06\u5728\u4e0e\u8be5\u8282\u70b9\u9009\u62e9\u5668\u5339\u914d\u7684\u8282\u70b9\u4e0a\u521b\u5efaPod\u3002 \u5982\u679c\u60a8\u6307\u5b9a daemonset.spec.template.spec.affinity \uff0c\u90a3\u4e48DaemonSet\u63a7\u5236\u5668\u5c06\u5728\u4e0e\u8be5\u8282\u70b9\u4eb2\u548c\u529b\u5339\u914d\u7684\u8282\u70b9\u4e0a\u521b\u5efaPod\u3002 \u5982\u679c\u4e24\u8005\u90fd\u4e0d\u6307\u5b9a\uff0c\u5219DaemonSet\u63a7\u5236\u5668\u5c06\u5728\u6240\u6709\u8282\u70b9\u4e0a\u521b\u5efaPod\u3002 \u5728 kubectl explain daemonset.spec \u4e2d\u6ca1\u6709 replicas \u5b57\u6bb5\u4e0e kubectl explain deployment.spec.replicas \u76f8\u5bf9\u5e94\u3002\u5f53\u521b\u5efa\u4e00\u4e2aDaemonSet\u65f6\uff0c\u6bcf\u4e2a\u8282\u70b9\u5c06\u8fd0\u884c*\u4e00\u4e2a* DaemonSet Pod\u3002 \u5bf9\u4e8e\u670d\u52a1\uff0c\u901a\u5e38\u662f\u65e0\u72b6\u6001\u7684\uff0c\u4e00\u822c\u4e0d\u5173\u5fc3\u8282\u70b9\u5728\u54ea\u91cc\u8fd0\u884c\uff0c\u66f4\u5173\u5fc3Pod\u526f\u672c\u7684\u6570\u91cf\uff0c\u5e76\u4e14\u6211\u4eec\u53ef\u4ee5\u5c06\u8fd9\u4e9b\u526f\u672c/replicas\u7f29\u653e\u3002\u5728\u8fd9\u91cc\uff0c\u6eda\u52a8\u66f4\u65b0\u4e5f\u5c06\u662f\u4e00\u4e2a\u4f18\u70b9\u3002 \u5f53Pod\u7684\u4e00\u4e2a\u526f\u672c\u5fc5\u987b\u5728\u67d0\u4e2a\u6307\u5b9a\u8282\u70b9\u4e0a\u8fd0\u884c\u65f6\uff0c\u6211\u4eec\u5c06\u4f7f\u7528 DaemonSet \u3002\u6211\u4eec\u7684\u5b88\u62a4\u8fdb\u7a0bPod\u8fd8\u9700\u8981\u5728\u6211\u4eec\u7684\u5176\u4ed6Pod\u4e4b\u524d\u542f\u52a8\u3002 DaemonSet\u662f\u7528\u4e8e\u540e\u53f0\u670d\u52a1\u7684\u7b80\u5355\u53ef\u6269\u5c55\u6027\u7b56\u7565\u3002\u5f53\u66f4\u591a\u7684\u5408\u9002\u7684\u8282\u70b9\u6dfb\u52a0\u5230\u96c6\u7fa4\u65f6\uff0c\u540e\u53f0\u670d\u52a1\u5c06\u6269\u5c55\u3002\u5f53\u8282\u70b9\u88ab\u5220\u9664\u65f6\uff0c\u5b83\u5c06\u81ea\u52a8\u7f29\u5c0f\u3002 Job \u00b6 CronJob \u00b6 \u670d\u52a1\u8d44\u6e90 \u00b6 Service \u00b6 Service\u662f\u8f6f\u4ef6\u670d\u52a1\uff08\u4f8b\u5982mysql\uff09\u7684\u547d\u540d\u62bd\u8c61\uff0c\u7531\u4ee3\u7406\u76d1\u542c\u7684\u672c\u5730\u7aef\u53e3\uff08\u4f8b\u59823306\uff09\u548c\u786e\u5b9a\u54ea\u4e9bPod\u5c06\u56de\u7b54\u901a\u8fc7\u4ee3\u7406\u53d1\u9001\u7684\u8bf7\u6c42\u7684\u9009\u62e9\u5668\u7ec4\u6210\u3002 \u4e00\u4e2aService\u7684\u76ee\u6807Pod\u96c6\u5408\u901a\u5e38\u7531\u4e00\u4e2a\u9009\u62e9\u5668\uff08\u6807\u7b7e\u9009\u62e9\u5668\uff09\u6765\u786e\u5b9a\u3002 Service\u8d44\u6e90\u7684\u7c7b\u578b\u5305\u62ec\uff1a ClusterIP Service\uff08\u9ed8\u8ba4\uff09\uff1a\u53ef\u9760\u7684IP\u3001DNS\u548c\u7aef\u53e3\u3002\u4ec5\u9650\u5185\u90e8\u8bbf\u95ee\u3002 NodePort Service\uff1a\u5411\u5916\u90e8\u63d0\u4f9b\u8bbf\u95ee\u3002 LoadBalancer\uff1a\u57fa\u4e8eNodePort\uff0c\u5e76\u4e0e\u4e91\u4f9b\u5e94\u5546\u63d0\u4f9b\u7684\u8d1f\u8f7d\u5e73\u8861\u96c6\u6210\uff08\u4f8b\u5982AWS\u3001GCP\u7b49\uff09\u3002 ExternalName\uff1a\u8bbf\u95ee\u5c06\u88ab\u8f6c\u53d1\u5230\u5916\u90e8\u670d\u52a1\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u521b\u5efa\u7b80\u5355Service\u7684yaml\u6587\u4ef6\uff1a apiVersion : v1 kind : Service metadata : name : nginx-service labels : tier : application spec : ports : - port : 80 protocol : TCP targetPort : 8080 selector : run : nginx type : NodePort \u4e0b\u9762\u662f\u4e00\u4e2aService\u7684\u4f8b\u5b50\uff1a IP 10.96.17.77 \u662f\u8be5\u670d\u52a1\u7684 ClusterIP(VIP)\u3002 \u7aef\u53e3 80/TCP \u662f Pod \u5728\u96c6\u7fa4\u5185\u76d1\u542c\u7684\u7aef\u53e3\u3002 TargetPort 8080/TCP \u662f\u5bb9\u5668\u5185\u670d\u52a1\u5e94\u8be5\u5b9a\u5411\u6d41\u91cf\u5230\u8fbe\u7684\u7aef\u53e3\u3002 NodePort 31893/TCP \u662f\u53ef\u4ee5\u4ece\u5916\u90e8\u8bbf\u95ee\u7684\u7aef\u53e3\u3002\u9ed8\u8ba4\u8303\u56f4\u662f 30000~32767 \u3002\u8be5\u7aef\u53e3\u4f1a\u5728\u6574\u4e2a\u96c6\u7fa4\u7684\u6240\u6709\u8282\u70b9\u4e0a\u66b4\u9732\u3002 Endpoints \u663e\u793a\u4e86\u5339\u914d\u670d\u52a1\u6807\u7b7e\u7684 Pod \u5217\u8868\u3002 Name : nginx-deployment Namespace : jh-namespace Labels : tier=application Annotations : Selector : run=nginx Type : NodePort IP Family Policy : SingleStack IP Families : IPv4 IP : 10.96.17.77 IPs : 10.96.17.77 Port : 80/TCP TargetPort : 8080/TCP NodePort : 31893/TCP Endpoints : 10.244.1.177:8080,10.244.1.178:8080,10.244.1.179:8080 + 7 more... Session Affinity : None External Traffic Policy : Cluster Events : \u5728 Kubernetes \u96c6\u7fa4\u4e2d\uff0c\u57fa\u4e8eDeployment coredns \u7684Service kube-dns \u63d0\u4f9b\u4e86\u96c6\u7fa4 DNS \u670d\u52a1\u3002 \u670d\u52a1\u6ce8\u518c\uff1a Kubernetes \u4f7f\u7528\u96c6\u7fa4 DNS \u4f5c\u4e3a\u670d\u52a1\u6ce8\u518c\u3002 \u6ce8\u518c\u662f\u57fa\u4e8e Service \u800c\u975e Pod \u7684\u3002 \u96c6\u7fa4 DNS\uff08CoreDNS\uff09\u4e3b\u52a8\u76d1\u89c6\u548c\u53d1\u73b0\u65b0\u670d\u52a1\u3002 Service \u540d\u79f0\u3001IP\u3001\u7aef\u53e3\u5c06\u88ab\u6ce8\u518c\u3002 Service \u6ce8\u518c\u7684\u8fc7\u7a0b\u5982\u4e0b\uff1a \u5c06\u65b0\u7684 Service POST \u5230 API Server\u3002 \u4e3a\u65b0\u7684 Service \u5206\u914d ClusterIP\u3002 \u5c06\u65b0\u7684 Service \u914d\u7f6e\u4fe1\u606f\u4fdd\u5b58\u5230 etcd \u4e2d\u3002 \u521b\u5efa\u4e0e\u65b0 Service \u5173\u8054\u7684\u5e26\u6709\u76f8\u5173 Pod IP \u7684 endpoints\u3002 \u901a\u8fc7 ClusterDNS \u63a2\u7d22\u65b0\u7684 Service\u3002 \u521b\u5efa DNS \u4fe1\u606f\u3002 kube-proxy \u83b7\u53d6 Service \u914d\u7f6e\u4fe1\u606f\u3002 \u521b\u5efa IPSV \u89c4\u5219\u3002 Service \u53d1\u73b0\u7684\u8fc7\u7a0b\u3002 \u8bf7\u6c42\u4e00\u4e2a Service \u540d\u79f0\u7684 DNS \u540d\u79f0\u89e3\u6790\u3002 \u6536\u5230 ClusterIP\u3002 \u8bbf\u95ee ClusterIP\u3002 \u6ca1\u6709\u8def\u7531\u5668\u3002\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230 Pod \u7684\u9ed8\u8ba4\u7f51\u5173\u3002 \u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u8282\u70b9\u3002 \u6ca1\u6709\u8def\u7531\u5668\u3002\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u8282\u70b9\u7684\u9ed8\u8ba4\u7f51\u5173\u3002 \u8282\u70b9\u5185\u6838\u7ee7\u7eed\u5904\u7406\u8bf7\u6c42\u3002 \u4f7f\u7528 IPSV \u89c4\u5219\u6355\u83b7\u8bf7\u6c42\u3002 \u5c06\u76ee\u6807 Pod \u7684 IP \u653e\u5165\u8bf7\u6c42\u7684\u76ee\u6807 IP \u4e2d\u3002 \u8bf7\u6c42\u5230\u8fbe\u76ee\u6807 Pod\u3002 FQDN\u683c\u5f0f\u4e3a\uff1a ..svc.cluster.local \u3002\u6211\u4eec\u79f0 \u4e3a\u975e\u9650\u5b9a\u540d\u79f0\u6216\u7b80\u77ed\u540d\u79f0\u3002 \u547d\u540d\u7a7a\u95f4\u53ef\u4ee5\u9694\u79bb\u96c6\u7fa4\u7684\u5730\u5740\u7a7a\u95f4\u3002\u540c\u65f6\uff0c\u5b83\u8fd8\u53ef\u4ee5\u7528\u4e8e\u5b9e\u73b0\u8bbf\u95ee\u63a7\u5236\u548c\u8d44\u6e90\u914d\u989d\u3002 \u83b7\u53d6Pod\u4e2d\u7684DNS\u914d\u7f6e\u3002 nameserver\u7684IP\u4e0ekube-dns\u670d\u52a1\u7684ClusterIP\u76f8\u540c\uff0c\u8fd9\u662f\u7528\u4e8eDNS\u8bf7\u6c42\u6216\u670d\u52a1\u53d1\u73b0\u8bf7\u6c42\u7684\u4f17\u6240\u5468\u77e5\u7684IP\u3002 $ kubectl get service kube-dns -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT ( S ) AGE kube-dns ClusterIP 10 .96.0.10 53 /UDP,53/TCP,9153/TCP 7d7h $ kubectl exec -it nginx-5f5496dc9-bv5dx -- /bin/bash root@nginx-5f5496dc9-bv5dx:/# cat /etc/resolv.conf search jh-namespace.svc.cluster.local svc.cluster.local cluster.local nameserver 10 .96.0.10 options ndots:5 \u8bfb\u53d6 kube-dns \u4fe1\u606f\uff1a $ kubectl describe service kube-dns -n kube-system Name: kube-dns Namespace: kube-system Labels: k8s-app = kube-dns kubernetes.io/cluster-service = true kubernetes.io/name = CoreDNS Annotations: prometheus.io/port: 9153 prometheus.io/scrape: true Selector: k8s-app = kube-dns Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: 10 .96.0.10 IPs: 10 .96.0.10 Port: dns 53 /UDP TargetPort: 53 /UDP Endpoints: 10 .244.0.2:53,10.244.0.3:53 Port: dns-tcp 53 /TCP TargetPort: 53 /TCP Endpoints: 10 .244.0.2:53,10.244.0.3:53 Port: metrics 9153 /TCP TargetPort: 9153 /TCP Endpoints: 10 .244.0.2:9153,10.244.0.3:9153 Session Affinity: None Events: Endpoints \u00b6 Endpoints\u662f\u4e00\u7ec4\u5b9e\u73b0\u5b9e\u9645\u670d\u52a1\u7684\u7aef\u70b9\u96c6\u5408\u3002 \u5f53\u521b\u5efa\u670d\u52a1\u65f6\uff0c\u5b83\u4f1a\u4e0e\u4e00\u4e2aEndpoint\u5bf9\u8c61\u76f8\u5173\u8054\uff0c\u53ef\u4ee5\u4f7f\u7528\u547d\u4ee4 kubectl get endpoints \u83b7\u53d6\u3002 \u5339\u914d\u670d\u52a1\u6807\u7b7e\u7684Pod\u5217\u8868\u7ef4\u62a4\u4e3aEndpoint\u5bf9\u8c61\uff0c\u6dfb\u52a0\u65b0\u7684\u5339\u914dPod\u5e76\u5220\u9664\u4e0d\u5339\u914d\u7684Pod\u3002 \u914d\u7f6e\u548c\u5b58\u50a8\u8d44\u6e90 \u00b6 \u5377 \u00b6 emptyDir \u00b6 emptyDir \u5377\u662f\u5728Pod\u5206\u914d\u5230\u8282\u70b9\u65f6\u9996\u5148\u521b\u5efa\u7684\uff0c\u5e76\u4e14\u53ea\u8981\u8be5Pod\u5728\u8be5\u8282\u70b9\u4e0a\u8fd0\u884c\uff0c\u5b83\u5c31\u4f1a\u5b58\u5728\u3002 emptyDir \u5377\u6700\u521d\u4e3a\u7a7a\u3002 Pod\u4e2d\u7684\u6240\u6709\u5bb9\u5668\u90fd\u53ef\u4ee5\u8bfb\u53d6\u548c\u5199\u5165 emptyDir \u5377\u4e2d\u7684\u76f8\u540c\u6587\u4ef6\uff0c\u5c3d\u7ba1\u8be5\u5377\u53ef\u4ee5\u5728\u6bcf\u4e2a\u5bb9\u5668\u4e2d\u4ee5\u76f8\u540c\u6216\u4e0d\u540c\u7684\u8def\u5f84\u6302\u8f7d\u3002 \u5f53\u7531\u4e8e\u4efb\u4f55\u539f\u56e0\u4ece\u8282\u70b9\u4e2d\u5220\u9664Pod\u65f6\uff0c emptyDir \u4e2d\u7684\u6570\u636e\u5c06\u6c38\u4e45\u5220\u9664\u3002 \u5bb9\u5668\u5d29\u6e83\u4e0d\u4f1a\u5c06Pod\u4ece\u8282\u70b9\u4e2d\u5220\u9664\u3002 emptyDir \u5377\u4e2d\u7684\u6570\u636e\u53ef\u4ee5\u5728\u5bb9\u5668\u5d29\u6e83\u65f6\u5b89\u5168\u4fdd\u7559\u3002 \u7528\u9014\uff1a \u4e34\u65f6\u7a7a\u95f4\uff0c\u4f8b\u5982\u57fa\u4e8e\u78c1\u76d8\u7684\u5f52\u5e76\u6392\u5e8f \u4e3a\u4e86\u4ece\u5d29\u6e83\u4e2d\u6062\u590d\u800c\u8fdb\u884c\u7684\u957f\u65f6\u95f4\u8ba1\u7b97\u7684\u68c0\u67e5\u70b9 \u4fdd\u5b58\u5185\u5bb9\u7ba1\u7406\u5668\u5bb9\u5668\u63d0\u53d6\u7684\u6587\u4ef6\uff0c\u540c\u65f6Web\u670d\u52a1\u5668\u5bb9\u5668\u63d0\u4f9b\u6570\u636e hostPath \u00b6 hostPath \u5377\u5c06\u4e3b\u673a\u8282\u70b9\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u6302\u8f7d\u5230 Pod \u4e2d\u3002\u8fd9\u4e0d\u662f\u5927\u591a\u6570 Pod \u90fd\u9700\u8981\u7684\uff0c\u4f46\u5bf9\u4e8e\u67d0\u4e9b\u5e94\u7528\u7a0b\u5e8f\u6765\u8bf4\uff0c\u5b83\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5f3a\u5927\u7684\u9003\u751f\u53e3\u3002 hostPath \u5377\u5b58\u5728\u8bb8\u591a\u5b89\u5168\u98ce\u9669\uff0c\u56e0\u6b64\u5728\u53ef\u80fd\u7684\u60c5\u51b5\u4e0b\u6700\u597d\u907f\u514d\u4f7f\u7528 HostPath\u3002\u5f53\u5fc5\u987b\u4f7f\u7528 HostPath \u5377\u65f6\uff0c\u5e94\u5c06\u5176\u8303\u56f4\u9650\u5b9a\u4e3a\u4ec5\u6240\u9700\u7684\u6587\u4ef6\u6216\u76ee\u5f55\uff0c\u5e76\u4ee5\u53ea\u8bfb\u65b9\u5f0f\u6302\u8f7d\u3002 \u5982\u679c\u901a\u8fc7 AdmissionPolicy \u9650\u5236 HostPath \u8bbf\u95ee\u7279\u5b9a\u76ee\u5f55\uff0c\u5219\u5fc5\u987b\u8981\u6c42 volumeMounts \u4f7f\u7528 readOnly \u6302\u8f7d\uff0c\u4ee5\u4f7f\u7b56\u7565\u751f\u6548\u3002 \u7528\u9014\uff1a \u4e0e DaemonSet \u4e00\u8d77\u8fd0\u884c\uff0c\u4f8b\u5982\uff0cEFK Fluentd \u6302\u8f7d\u672c\u5730\u4e3b\u673a\u7684\u65e5\u5fd7\u76ee\u5f55\u4ee5\u6536\u96c6\u4e3b\u673a\u65e5\u5fd7\u4fe1\u606f\u3002 \u901a\u8fc7\u4f7f\u7528 hostPath \u5377\u5728\u7279\u5b9a\u8282\u70b9\u4e0a\u8fd0\u884c\uff0c\u53ef\u4ee5\u83b7\u5f97\u9ad8\u6027\u80fd\u7684\u78c1\u76d8 I/O\u3002 \u8fd0\u884c\u9700\u8981\u8bbf\u95ee Docker \u5185\u90e8\u7684\u5bb9\u5668\uff1b\u4f7f\u7528 /var/lib/docker \u7684 hostPath\u3002 \u5728\u5bb9\u5668\u4e2d\u8fd0\u884c cAdvisor\uff1b\u4f7f\u7528 /sys \u7684 hostPath\u3002 \u5141\u8bb8 Pod \u6307\u5b9a\u7ed9\u5b9a\u7684 hostPath \u662f\u5426\u5e94\u8be5\u5728 Pod \u8fd0\u884c\u4e4b\u524d\u5b58\u5728\uff0c\u662f\u5426\u5e94\u8be5\u521b\u5efa\u5b83\u4ee5\u53ca\u5b83\u5e94\u8be5\u5b58\u5728\u7684\u5185\u5bb9\u3002 Storage Class \u00b6 StorageClass \u90e8\u7f72\u548c\u5b9e\u73b0\u7684\u6b65\u9aa4\u5982\u4e0b\uff1a \u521b\u5efa Kubernetes \u96c6\u7fa4\u548c\u540e\u7aef\u5b58\u50a8\u3002 \u786e\u4fdd Kubernetes \u4e2d\u7684 provisioner/plugin \u53ef\u7528\u3002 \u521b\u5efa\u4e00\u4e2a StorageClass \u5bf9\u8c61\u5e76\u5c06\u5176\u94fe\u63a5\u5230\u540e\u7aef\u5b58\u50a8\u3002StorageClass \u5c06\u81ea\u52a8\u521b\u5efa\u76f8\u5173\u7684 PV\u3002 \u521b\u5efa\u4e00\u4e2a PVC \u5bf9\u8c61\u5e76\u5c06\u5176\u94fe\u63a5\u5230\u6211\u4eec\u521b\u5efa\u7684 StorageClass\u3002 \u90e8\u7f72\u4e00\u4e2a Pod \u5e76\u4f7f\u7528 PVC \u5377\u3002 PV \u00b6 PV\u56de\u6536\u7b56\u7565\uff1a \u4fdd\u7559 (Retain) \u5220\u9664 (Delete) \u56de\u6536 (Recycle) PV in-tree\u7c7b\u578b\uff1a hostPath local NFS CSI Access Modes \u00b6 Access Modes\uff08\u8bbf\u95ee\u6a21\u5f0f\uff09\u4e2d\uff0c spec.accessModes \u5b9a\u4e49\u4e86 PV \u7684\u6302\u8f7d\u9009\u9879\uff1a ReadWriteOnce(RWO)\uff1a\u4e00\u4e2a PV \u53ea\u80fd\u88ab\u4e00\u4e2a\u8bfb\u5199\u6a21\u5f0f\u7684 PVC \u6302\u8f7d\uff0c\u7c7b\u4f3c\u4e8e\u5757\u8bbe\u5907\u3002 ReadWriteMany(RWM)\uff1a\u4e00\u4e2a PV \u53ef\u4ee5\u88ab\u591a\u4e2a\u8bfb\u5199\u6a21\u5f0f\u7684 PVC \u6302\u8f7d\uff0c\u4f8b\u5982 NFS\u3002 ReadOnlyMany(ROM)\uff1a\u4e00\u4e2a PV \u53ef\u4ee5\u88ab\u591a\u4e2a\u53ea\u8bfb\u6a21\u5f0f\u7684 PVC \u6302\u8f7d\u3002 ReadWriteOncePod(RWOP)\uff1a\u53ea\u652f\u6301 CSI \u7c7b\u578b\u7684 PV\uff0c\u53ea\u80fd\u88ab\u5355\u4e2a Pod \u6302\u8f7d\u3002 \u4e00\u4e2a PV \u53ea\u80fd\u8bbe\u7f6e\u4e00\u79cd\u9009\u9879\u3002Pod \u6302\u8f7d PVC\uff0c\u800c\u4e0d\u662f PV\u3002","title":"Kubernetes\u968f\u7b14"},{"location":"k8s/cka_cn/foundamentals/memo/#cka5kubernetes","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb05:Kubernetes\u968f\u7b14"},{"location":"k8s/cka_cn/foundamentals/memo/#_1","text":"\u8fb9\u7ec3\u4e60\u8fb9\u8bb0\u5f55\u7684\u5185\u5bb9\uff0c\u4e0d\u662f\u5168\u9762\u7cfb\u7edf\u7684\uff0c\u5305\u62ec\u4e0b\u9762\u4e3b\u8981\u5185\u5bb9\uff1a Kubernetes\u57fa\u672c\u6982\u5ff5 \u7ec4\u4ef6 API \u5bf9\u8c61 \u8d44\u6e90 \u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90 Pod Deployment ReplicaSet StatefulSet DaemonSet Job CronJob \u670d\u52a1\u8d44\u6e90 Service Endpoints \u914d\u7f6e\u548c\u5b58\u50a8\u8d44\u6e90 \u5377 Storage Class PV Access Modes","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/memo/#kubernetes","text":"","title":"Kubernetes\u57fa\u672c\u6982\u5ff5"},{"location":"k8s/cka_cn/foundamentals/memo/#kubernetes_1","text":"\u4e00\u4e2aKubernetes\u96c6\u7fa4\u7531\u4ee3\u8868\u63a7\u5236\u5e73\u9762\uff08control plane\uff09\u7684\u7ec4\u4ef6\u548c\u4e00\u7ec4\u79f0\u4e3a\u8282\u70b9\uff08nodes\uff09\u7684\u673a\u5668\u7ec4\u6210\u3002 Kubernetes\u7ec4\u4ef6: \u63a7\u5236\u5e73\u9762\u7ec4\u4ef6 Control Plane Components kube-apiserver: \u67e5\u8be2\u548c\u64cd\u4f5c Kubernetes \u4e2d\u5bf9\u8c61\u7684\u72b6\u6001\u3002 \u5145\u5f53\u6240\u6709\u8d44\u6e90\u4e4b\u95f4\u7684\u901a\u4fe1\u4e2d\u5fc3\uff08communication hub\uff09\u3002 \u63d0\u4f9b\u96c6\u7fa4\u5b89\u5168\u8eab\u4efd\u9a8c\u8bc1\u3001\u6388\u6743\u548c\u89d2\u8272\u5206\u914d\u3002 \u662f\u552f\u4e00\u80fd\u8fde\u63a5\u5230 etcd \u7684\u7ec4\u4ef6\u3002 etcd: \u6240\u6709 Kubernetes \u5bf9\u8c61\u90fd\u5b58\u50a8\u5728 etcd \u4e2d\u3002 Kubernetes \u5bf9\u8c61\u662f Kubernetes \u7cfb\u7edf\u4e2d\u7684\u6301\u4e45\u5b9e\u4f53(entities)\uff0c\u7528\u4e8e\u8868\u793a\u96c6\u7fa4\u7684\u72b6\u6001\u3002 kube-scheduler: \u76d1\u89c6\u6ca1\u6709\u5206\u914d\u8282\u70b9\u7684\u65b0\u521b\u5efa\u7684 Pod\uff0c\u5e76\u4e3a\u5b83\u4eec\u9009\u62e9\u4e00\u4e2a\u8282\u70b9\u6765\u8fd0\u884c\u3002 kube-controller-manager: \u8fd0\u884c\u63a7\u5236\u5668\u8fdb\u7a0b\u3002 Node controller : \u8d1f\u8d23\u8b66\u793a\u548c\u54cd\u5e94\u8282\u70b9\u7684\u6545\u969c\u3002 Job controller : \u76d1\u89c6\u8868\u793a\u4e00\u6b21\u6027\u4efb\u52a1\u7684 Job \u5bf9\u8c61\uff0c\u7136\u540e\u521b\u5efa Pod \u6765\u5b8c\u6210\u8fd9\u4e9b\u4efb\u52a1\u3002 Endpoints controller : \u586b\u5145 Endpoints \u5bf9\u8c61\uff08\u5373\u5c06 Service \u548c Pod \u8fde\u63a5\u8d77\u6765\uff09\u3002 Service Account & Token controllers : \u4e3a\u65b0\u547d\u540d\u7a7a\u95f4\u521b\u5efa\u9ed8\u8ba4\u5e10\u6237\u548c API \u8bbf\u95ee\u4ee4\u724c\u3002 cloud-controller-manager: \u5d4c\u5165\u4e91\u7279\u5b9a\u7684\u63a7\u5236\u903b\u8f91\uff0c\u4ec5\u8fd0\u884c\u7279\u5b9a\u4e8e\u6211\u4eec\u9009\u62e9\u7684\u4e91\u63d0\u4f9b\u5546\u7684\u63a7\u5236\u5668\uff0c\u65e0\u9700\u81ea\u5df1\u7684\u57fa\u7840\u8bbe\u65bd\u548c\u5b66\u4e60\u73af\u5883\u3002 Node controller : \u7528\u4e8e\u68c0\u67e5\u4e91\u63d0\u4f9b\u5546\uff0c\u4ee5\u786e\u5b9a\u8282\u70b9\u5728\u5728\u5b83\u505c\u6b62\u54cd\u5e94\u540e\u662f\u5426\u5df2\u5728\u4e91\u4e2d\u88ab\u5220\u9664\u3002 Route controller : \u7528\u4e8e\u5728\u5e95\u5c42\u4e91\u57fa\u7840\u67b6\u6784\u4e2d\u8bbe\u7f6e\u8def\u7531\u3002 Service controller : \u7528\u4e8e\u521b\u5efa\u3001\u66f4\u65b0\u548c\u5220\u9664\u4e91\u63d0\u4f9b\u5546\u8d1f\u8f7d\u5747\u8861\u5668\u3002 \u8282\u70b9\u7ec4\u4ef6 Node Components kubelet: \u5728\u96c6\u7fa4\u4e2d\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u7684\u4ee3\u7406\u3002 \u7ba1\u7406\u8282\u70b9\u3002\u5b83\u786e\u4fdd Pod \u4e2d\u8fd0\u884c\u5bb9\u5668\u3002 kubelet \u5411 APIServer \u6ce8\u518c\u548c\u66f4\u65b0\u8282\u70b9\u4fe1\u606f\uff0cAPIServer \u5c06\u5b83\u4eec\u5b58\u50a8\u5230 etcd \u4e2d\u3002 \u7ba1\u7406 Pod\u3002\u901a\u8fc7 APIServer \u76d1\u89c6 Pod\uff0c\u5e76\u5bf9 Pod \u6216 Pod \u4e2d\u7684\u5bb9\u5668\u91c7\u53d6\u884c\u52a8\u3002 \u5728\u5bb9\u5668\u7ea7\u522b\u8fdb\u884c\u5065\u5eb7\u68c0\u67e5\u3002 kube-proxy: \u662f\u5728\u96c6\u7fa4\u4e2d\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u7684\u7f51\u7edc\u4ee3\u7406\u3002 iptables ipvs \u7ef4\u62a4\u8282\u70b9\u4e0a\u7684\u7f51\u7edc\u89c4\u5219\u3002 \u5bb9\u5668\u8fd0\u884c\u65f6Container runtime\uff1a \u8d1f\u8d23\u8fd0\u884c\u5bb9\u5668\u7684\u8f6f\u4ef6\u3002 \u63d2\u4ef6Addons DNS: \u662f DNS \u670d\u52a1\u5668\uff0c\u662f\u6240\u6709 Kubernetes \u96c6\u7fa4\u6240\u5fc5\u9700\u7684\u3002 Web UI\uff08\u4eea\u8868\u76d8\uff09\uff1a\u7528\u4e8e Kubernetes \u96c6\u7fa4\u7684\u57fa\u4e8e Web \u7684\u7528\u6237\u754c\u9762\u3002 \u5bb9\u5668\u8d44\u6e90\u76d1\u63a7\uff1a\u8bb0\u5f55\u6709\u5173\u96c6\u4e2d\u5f0f\u6570\u636e\u5e93\u4e2d\u5bb9\u5668\u7684\u901a\u7528\u65f6\u95f4\u5e8f\u5217\u5ea6\u91cf\u3002 Cluster-level Logging\uff1a\u8d1f\u8d23\u5c06\u5bb9\u5668\u65e5\u5fd7\u4fdd\u5b58\u5230\u5177\u6709\u641c\u7d22/\u6d4f\u89c8\u63a5\u53e3\u7684\u4e2d\u592e\u65e5\u5fd7\u5b58\u50a8\u4e2d\u3002 \u53ef\u6269\u5c55\u6027\uff1a \u6c34\u5e73\u6269\u5c55\uff08Scaling out\uff09\u901a\u8fc7\u6dfb\u52a0\u66f4\u591a\u7684\u670d\u52a1\u5668\u5230\u67b6\u6784\u4e2d\uff0c\u5c06\u5de5\u4f5c\u8d1f\u8f7d\u5206\u6563\u5230\u66f4\u591a\u7684\u673a\u5668\u4e0a\u3002 \u5782\u76f4\u6269\u5c55\uff08Scaling up\uff09\u901a\u8fc7\u6dfb\u52a0\u66f4\u591a\u7684\u786c\u76d8\u548c\u5185\u5b58\u6765\u589e\u52a0\u7269\u7406\u670d\u52a1\u5668\u7684\u8ba1\u7b97\u80fd\u529b\u3002","title":"Kubernetes\u7ec4\u4ef6"},{"location":"k8s/cka_cn/foundamentals/memo/#kubernetes-api","text":"REST API\u662fKubernetes\u7684\u57fa\u672c\u6846\u67b6\u3002\u6240\u6709\u7ec4\u4ef6\u4e4b\u95f4\u7684\u64cd\u4f5c\u548c\u901a\u4fe1\uff0c\u4ee5\u53ca\u5916\u90e8\u7528\u6237\u547d\u4ee4\u90fd\u662f\u7531API\u670d\u52a1\u5668\u5904\u7406\u7684REST API\u8c03\u7528\u3002\u56e0\u6b64\uff0cKubernetes\u5e73\u53f0\u4e2d\u7684\u6240\u6709\u5185\u5bb9\u90fd\u88ab\u89c6\u4e3aAPI\u5bf9\u8c61\uff08API object\uff09\uff0c\u5e76\u5728API\u4e2d\u6709\u76f8\u5e94\u7684\u6761\u76ee\u3002 Kubernetes\u63a7\u5236\u5e73\u9762\u7684\u6838\u5fc3\u662fAPI\u670d\u52a1\u5668\u3002 CRI\uff1a\u5bb9\u5668\u8fd0\u884c\u65f6\u63a5\u53e3 CNI\uff1a\u5bb9\u5668\u7f51\u7edc\u63a5\u53e3 CSI\uff1a\u5bb9\u5668\u5b58\u50a8\u63a5\u53e3 API\u670d\u52a1\u5668\u516c\u5f00\u4e86\u4e00\u4e2aHTTP API\uff0c\u5141\u8bb8\u6700\u7ec8\u7528\u6237\u3001\u96c6\u7fa4\u7684\u4e0d\u540c\u90e8\u5206\u548c\u5916\u90e8\u7ec4\u4ef6\u5f7c\u6b64\u901a\u4fe1\u3002 Kubernetes API\u5141\u8bb8\u6211\u4eec\u67e5\u8be2\u548c\u64cd\u4f5cKubernetes\u4e2dAPI\u5bf9\u8c61\u7684\u72b6\u6001\uff08\u4f8b\u5982\uff1aPod\u3001Namespace\u3001ConfigMap\u548cEvent\uff09\u3002 Kubernetes API\uff1a OpenAPI\u89c4\u8303 OpenAPI V2 OpenAPI V3 \u6301\u4e45\u6027\u3002Kubernetes\u901a\u8fc7\u5c06\u5bf9\u8c61\u7684\u5e8f\u5217\u5316\u72b6\u6001\u5199\u5165etcd\u6765\u5b58\u50a8\u5b83\u4eec\u3002 API\u7ec4\u548c\u7248\u672c\u63a7\u5236\u3002\u7248\u672c\u63a7\u5236\u662f\u5728API\u7ea7\u522b\u8fdb\u884c\u7684\u3002API\u8d44\u6e90\u901a\u8fc7\u5b83\u4eec\u7684API\u7ec4\u3001\u8d44\u6e90\u7c7b\u578b\u3001\u547d\u540d\u7a7a\u95f4\uff08\u7528\u4e8e\u547d\u540d\u7a7a\u95f4\u8d44\u6e90\uff09\u548c\u540d\u79f0\u8fdb\u884c\u533a\u5206\u3002 API\u66f4\u6539 API\u6269\u5c55","title":"Kubernetes API"},{"location":"k8s/cka_cn/foundamentals/memo/#api-version","text":"API\u7248\u672c\u548c\u8f6f\u4ef6\u7248\u672c\u95f4\u5b58\u5728\u95f4\u63a5\u5173\u7cfb\u3002API\u548c\u53d1\u5e03\u7248\u672c\u8ba1\u5212\u63cf\u8ff0\u4e86API\u7248\u672c\u548c\u8f6f\u4ef6\u7248\u672c\u4e4b\u95f4\u7684\u5173\u7cfb\u3002\u4e0d\u540c\u7684API\u7248\u672c\u8868\u793a\u4e0d\u540c\u7684\u7a33\u5b9a\u6027\u548c\u652f\u6301\u7ea7\u522b\u3002 \u4ee5\u4e0b\u662f\u6bcf\u4e2a\u7ea7\u522b\u7684\u6458\u8981\uff1a Alpha\uff1a \u7248\u672c\u540d\u79f0\u5305\u542balpha\uff08\u4f8b\u5982\uff0cv1alpha1\uff09\u3002 \u8f6f\u4ef6\u53ef\u80fd\u5305\u542b\u9519\u8bef\u3002\u542f\u7528\u529f\u80fd\u53ef\u80fd\u4f1a\u66b4\u9732\u9519\u8bef\u3002\u67d0\u4e9b\u529f\u80fd\u53ef\u80fd\u9ed8\u8ba4\u7981\u7528\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u529f\u80fd\u7684\u652f\u6301\u53ef\u4ee5\u968f\u65f6\u53d6\u6d88\uff0c\u800c\u4e0d\u4f1a\u63d0\u524d\u901a\u77e5\u3002 API\u53ef\u80fd\u4f1a\u5728\u4ee5\u540e\u7684\u8f6f\u4ef6\u53d1\u5e03\u4e2d\u4ee5\u4e0d\u517c\u5bb9\u7684\u65b9\u5f0f\u66f4\u6539\uff0c\u800c\u4e0d\u4f1a\u63d0\u524d\u901a\u77e5\u3002 \u7531\u4e8e\u9519\u8bef\u98ce\u9669\u589e\u52a0\u548c\u957f\u671f\u652f\u6301\u4e0d\u8db3\uff0c\u5efa\u8bae\u4ec5\u5728\u77ed\u6682\u7684\u6d4b\u8bd5\u96c6\u7fa4\u4e2d\u4f7f\u7528\u8be5\u8f6f\u4ef6\u3002 Beta\uff1a \u7248\u672c\u540d\u79f0\u5305\u542bbeta\uff08\u4f8b\u5982\uff0cv2beta3\uff09\u3002 \u8f6f\u4ef6\u7ecf\u8fc7\u5145\u5206\u6d4b\u8bd5\u3002\u542f\u7528\u529f\u80fd\u88ab\u8ba4\u4e3a\u662f\u5b89\u5168\u7684\u3002\u67d0\u4e9b\u529f\u80fd\u9ed8\u8ba4\u542f\u7528\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u529f\u80fd\u7684\u652f\u6301\u4e0d\u4f1a\u53d6\u6d88\uff0c\u4f46\u7ec6\u8282\u53ef\u80fd\u4f1a\u66f4\u6539\u3002 \u5bf9\u8c61\u7684\u6a21\u5f0f\u548c/\u6216\u8bed\u4e49\u53ef\u80fd\u4f1a\u5728\u540e\u7eed\u7684Beta\u6216\u7a33\u5b9a\u7248\u53d1\u5e03\u4e2d\u4ee5\u4e0d\u517c\u5bb9\u7684\u65b9\u5f0f\u66f4\u6539\u3002\u5f53\u53d1\u751f\u8fd9\u79cd\u60c5\u51b5\u65f6\uff0c\u5c06\u63d0\u4f9b\u8fc1\u79fb\u8bf4\u660e\u3002\u6a21\u5f0f\u66f4\u6539\u53ef\u80fd\u9700\u8981\u5220\u9664\u3001\u7f16\u8f91\u548c\u91cd\u65b0\u521b\u5efa API\u5bf9\u8c61\u3002\u7f16\u8f91\u8fc7\u7a0b\u53ef\u80fd\u4e0d\u7b80\u5355\u3002\u8fc1\u79fb\u53ef\u80fd\u9700\u8981\u505c\u673a\uff0c\u4ee5\u4fbf\u4f9d\u8d56\u4e8e\u8be5\u529f\u80fd\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 \u4e0d\u5efa\u8bae\u5c06\u8be5\u8f6f\u4ef6\u7528\u4e8e\u751f\u4ea7\u7528\u9014\u3002\u540e\u7eed\u7684\u53d1\u5e03\u53ef\u80fd\u4f1a\u5f15\u5165\u4e0d\u517c\u5bb9\u7684\u66f4\u6539\u3002\u5982\u679c\u60a8\u6709\u591a\u4e2a\u53ef\u4ee5\u72ec\u7acb\u5347\u7ea7\u7684\u96c6\u7fa4\uff0c\u5219\u53ef\u4ee5\u653e\u5bbd\u6b64\u9650\u5236\u3002 \u6ce8\u610f\uff1a\u8bf7\u5c1d\u8bd5beta\u529f\u80fd\u5e76\u63d0\u4f9b\u53cd\u9988\u3002\u529f\u80fd\u9000\u51fabeta\u540e\uff0c\u53ef\u80fd\u4e0d\u5b9e\u9645\u518d\u8fdb\u884c\u66f4\u6539\u3002 \u7a33\u5b9a\u7248\uff1a \u7248\u672c\u540d\u79f0\u4e3avX\uff0c\u5176\u4e2dX\u662f\u6574\u6570\u3002 \u529f\u80fd\u7684\u7a33\u5b9a\u7248\u672c\u51fa\u73b0\u5728\u53d1\u5e03\u7684\u8f6f\u4ef6\u4e2d\u7684\u8bb8\u591a\u540e\u7eed\u7248\u672c\u4e2d\u3002 \u8bfb\u53d6\u5f53\u524dAPI\u7684\u7248\u672c\u547d\u4ee4\uff1a kubectl api-resources","title":"API Version"},{"location":"k8s/cka_cn/foundamentals/memo/#api-group","text":"API\u7ec4\uff08API groups\uff09 \u4f7f\u6269\u5c55Kubernetes API\u66f4\u52a0\u5bb9\u6613\u3002API\u7ec4\u5728REST\u8def\u5f84\u548c\u5e8f\u5217\u5316\u5bf9\u8c61\u7684apiVersion\u5b57\u6bb5\u4e2d\u6307\u5b9a\u3002 Kubernetes\u6709\u51e0\u4e2aAPI\u7ec4\uff1a \u6838\u5fc3\u7ec4\uff08\u4e5f\u79f0\u4e3a\u9057\u7559legacy\uff09\u4f4d\u4e8eREST\u8def\u5f84 /api/v1 \u3002 \u6838\u5fc3\u7ec4\u4e0d\u4f5c\u4e3aapiVersion\u5b57\u6bb5\u7684\u4e00\u90e8\u5206\u6307\u5b9a\uff0c\u4f8b\u5982 apiVersion: v1\u3002 \u547d\u540d\u7ec4\u4f4d\u4e8eREST\u8def\u5f84 /apis/$GROUP_NAME/$VERSION \uff0c\u5e76\u4f7f\u7528 apiVersion: $GROUP_NAME/$VERSION \uff08\u4f8b\u5982 apiVersion: batch/v1\uff09\u3002","title":"API Group"},{"location":"k8s/cka_cn/foundamentals/memo/#kubernetes_2","text":"","title":"Kubernetes\u5bf9\u8c61"},{"location":"k8s/cka_cn/foundamentals/memo/#_2","text":"\u5bf9\u8c61\u89c4\u8303\uff08Object Spec\uff09\uff1a \u63d0\u4f9b\u4e86\u4e00\u4e2a\u63cf\u8ff0\u6240\u521b\u5efa\u8d44\u6e90\u7684\u7279\u6027\u7684\u8bf4\u660e\uff1a \u5176\u671f\u671b\u7684\u72b6\u6001 \u3002 \u5bf9\u8c61\u72b6\u6001\uff08Object Status\uff09\uff1a \u63cf\u8ff0\u4e86\u5bf9\u8c61\u7684\u5f53\u524d\u72b6\u6001\u3002 \u6bd4\u5982\uff0cDeployment\u662f\u4e00\u4e2a\u53ef\u4ee5\u4ee3\u8868\u96c6\u7fa4\u4e0a\u8fd0\u884c\u7684\u5e94\u7528\u7a0b\u5e8f\u7684\u5bf9\u8c61\u3002 apiVersion : apps/v1 # \u5f53\u524d\u7528\u6765\u521b\u5efa\u5bf9\u8c61\u7684API\u7248\u672c kind : Deployment # \u521b\u5efa\u5bf9\u8c61\u7684\u7c7b\u578b metadata : # \u7528\u6765\u533a\u5206\u5bf9\u8c61\u7684\u5143\u6570\u636e\uff0c\u6bd4\u5982\uff1a\u540d\u79f0\uff0cUID\uff0c\u547d\u540d\u7a7a\u95f4\u7b49 name : nginx-deployment spec : # \u671f\u671b\u6240\u521b\u5efa\u5bf9\u8c61\u7684\u72b6\u6001 selector : matchLabels : app : nginx replicas : 2 # \u544a\u8bc9Deployment\u57fa\u4e8e\u4e0b\u9762\u7684\u6a21\u677ftemplate\u521b\u5efa2\u4e2aPods template : metadata : labels : app : nginx spec : containers : - name : nginx image : nginx:1.14.2 ports : - containerPort : 80","title":"\u5bf9\u8c61\u6982\u8ff0"},{"location":"k8s/cka_cn/foundamentals/memo/#_3","text":"kubectl \u547d\u4ee4\u884c\u5de5\u5177\u652f\u6301\u591a\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u6765\u521b\u5efa\u548c\u7ba1\u7406 Kubernetes \u5bf9\u8c61\u3002\u8be6\u7ec6\u4fe1\u606f\u8bf7\u9605\u8bfb Kubectl book \u3002 \u4e00\u4e2a Kubernetes \u5bf9\u8c61\u5e94\u8be5\u4ec5\u4f7f\u7528\u4e00\u79cd\u6280\u672f\u8fdb\u884c\u7ba1\u7406\u3002\u6df7\u5408\u4f7f\u7528\u4e0d\u540c\u7684\u6280\u672f\u6765\u7ba1\u7406\u540c\u4e00\u4e2a\u5bf9\u8c61\u4f1a\u5bfc\u81f4\u975e\u9884\u671f\u7684\u7ed3\u679c\u3002 \u4e09\u79cd\u7ba1\u7406\u6280\u672f: \u547d\u4ee4\u5f0f\u547d\u4ee4 \u76f4\u63a5\u5728\u96c6\u7fa4\u4e2d\u64cd\u4f5c\u5b9e\u65f6\u5bf9\u8c61\u3002 kubectl create deployment nginx --image nginx \u547d\u4ee4\u5f0f\u5bf9\u8c61\u914d\u7f6e kubectl create -f nginx.yaml kubectl delete -f nginx.yaml -f redis.yaml kubectl replace -f nginx.yaml \u58f0\u660e\u5f0f\u5bf9\u8c61\u914d\u7f6e kubectl diff -f configs/ kubectl apply -f configs/","title":"\u5bf9\u8c61\u7ba1\u7406"},{"location":"k8s/cka_cn/foundamentals/memo/#id","text":"\u96c6\u7fa4\u4e2d\u7684\u6bcf\u4e2a\u5bf9\u8c61\u90fd\u6709\u4e00\u4e2a\u5728\u8be5\u8d44\u6e90\u7c7b\u578b\u4e2d\u552f\u4e00\u7684\u540d\u79f0\u3002 DNS \u5b50\u57df\u540d \u6807\u7b7e\u540d\u79f0 \u8def\u5f84\u6bb5\u540d\u79f0 \u6bcf\u4e2a Kubernetes \u5bf9\u8c61\u8fd8\u6709\u4e00\u4e2a UID\uff0c\u5728\u6574\u4e2a\u96c6\u7fa4\u4e2d\u662f\u552f\u4e00\u7684\u3002","title":"\u5bf9\u8c61\u540d\u79f0\u548cID"},{"location":"k8s/cka_cn/foundamentals/memo/#_4","text":"\u5728Kubernetes\u4e2d\uff0c\u547d\u540d\u7a7a\u95f4\u63d0\u4f9b\u4e86\u4e00\u79cd\u5728\u5355\u4e2a\u96c6\u7fa4\u5185\u9694\u79bb\u8d44\u6e90\u7ec4\u7684\u673a\u5236\u3002 \u8d44\u6e90\u7684\u540d\u79f0\u9700\u8981\u5728\u547d\u540d\u7a7a\u95f4\u5185\u662f\u552f\u4e00\u7684\uff0c\u4f46\u4e0d\u9700\u8981\u8de8\u547d\u540d\u7a7a\u95f4\u552f\u4e00\u3002 \u57fa\u4e8e\u547d\u540d\u7a7a\u95f4\u7684\u8303\u56f4\u4ec5\u9002\u7528\u4e8e\u547d\u540d\u7a7a\u95f4\u5bf9\u8c61\uff08\u4f8b\u5982\u90e8\u7f72\uff0c\u670d\u52a1\u7b49\uff09\uff0c\u800c\u4e0d\u9002\u7528\u4e8e\u96c6\u7fa4\u8303\u56f4\u7684\u5bf9\u8c61\uff08\u4f8b\u5982StorageClass\uff0c\u8282\u70b9\uff0c\u6301\u4e45\u5377\u7b49\uff09\u3002 \u5e76\u975e\u6240\u6709\u5bf9\u8c61\u90fd\u4f4d\u4e8e\u547d\u540d\u7a7a\u95f4\u4e2d\u3002 Kubernetes\u4ece\u56db\u4e2a\u521d\u59cb\u547d\u540d\u7a7a\u95f4\u5f00\u59cb\uff1a default \u7528\u4e8e\u6ca1\u6709\u5176\u4ed6\u547d\u540d\u7a7a\u95f4\u7684\u5bf9\u8c61\u7684\u9ed8\u8ba4\u547d\u540d\u7a7a\u95f4 kube-system Kubernetes\u7cfb\u7edf\u521b\u5efa\u7684\u5bf9\u8c61\u7684\u547d\u540d\u7a7a\u95f4 kube-public \u8be5\u547d\u540d\u7a7a\u95f4\u662f\u81ea\u52a8\u521b\u5efa\u7684\uff0c\u5e76\u53ef\u7531\u6240\u6709\u7528\u6237\uff08\u5305\u62ec\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\uff09\u8bfb\u53d6\u3002\u6b64\u547d\u540d\u7a7a\u95f4\u5927\u591a\u4fdd\u7559\u4f9b\u96c6\u7fa4\u4f7f\u7528\uff0c\u4ee5\u9632\u4e00\u4e9b\u8d44\u6e90\u5e94\u5728\u6574\u4e2a\u96c6\u7fa4\u8303\u56f4\u5185\u516c\u5f00\u548c\u53ef\u8bfb\u3002\u6b64\u547d\u540d\u7a7a\u95f4\u7684\u516c\u5171\u65b9\u9762\u53ea\u662f\u4e00\u79cd\u7ea6\u5b9a\uff0c\u800c\u4e0d\u662f\u8981\u6c42\u3002 kube-node-lease \u6b64\u547d\u540d\u7a7a\u95f4\u4fdd\u5b58\u4e0e\u6bcf\u4e2a\u8282\u70b9\u5173\u8054\u7684\u79df\u8d41\u5bf9\u8c61\u3002\u8282\u70b9\u79df\u8d41\u5141\u8bb8kubelet\u53d1\u9001\u5fc3\u8df3\uff0c\u4ee5\u4fbf\u63a7\u5236\u5e73\u9762\u53ef\u4ee5\u68c0\u6d4b\u5230\u8282\u70b9\u6545\u969c\u3002 \u67e5\u770b\u547d\u540d\u7a7a\u95f4\uff1a kubectl get namespace \u4e3a\u8bf7\u6c42\u8bbe\u7f6e\u547d\u540d\u7a7a\u95f4 kubectl run nginx --image=nginx --namespace=<\u63d2\u5165\u547d\u540d\u7a7a\u95f4\u540d\u79f0> kubectl get pods --namespace=<\u63d2\u5165\u547d\u540d\u7a7a\u95f4\u540d\u79f0>","title":"\u547d\u540d\u7a7a\u95f4"},{"location":"k8s/cka_cn/foundamentals/memo/#_5","text":"\u6807\u7b7e\u662f\u9644\u52a0\u5230\u5bf9\u8c61\uff08\u4f8b\u5982 Pod\uff09\u7684\u952e/\u503c\u5bf9\u3002\u6709\u6548\u7684\u6807\u7b7e\u952e\u6709\u4e24\u4e2a\u90e8\u5206\uff1a\u53ef\u9009\u7684\u524d\u7f00\u548c\u540d\u79f0\uff0c\u7531\u659c\u6760\uff08 / \uff09\u5206\u9694\u3002 \u6807\u7b7e\u65e8\u5728\u7528\u4e8e\u6307\u5b9a\u5bf9\u7528\u6237\u6709\u610f\u4e49\u548c\u76f8\u5173\u7684\u5bf9\u8c61\u8bc6\u522b\u5c5e\u6027\u3002 \u6807\u7b7e\u53ef\u7528\u4e8e\u7ec4\u7ec7\u548c\u9009\u62e9\u5bf9\u8c61\u5b50\u96c6\u3002\u6807\u7b7e\u53ef\u4ee5\u5728\u521b\u5efa\u5bf9\u8c61\u65f6\u9644\u52a0\uff0c\u968f\u540e\u5728\u4efb\u4f55\u65f6\u5019\u6dfb\u52a0\u548c\u4fee\u6539\u3002\u6bcf\u4e2a\u5bf9\u8c61\u53ef\u4ee5\u5b9a\u4e49\u4e00\u7ec4\u952e/\u503c\u6807\u7b7e\uff0c\u6bcf\u4e2a\u952e\u5fc5\u987b\u5bf9\u4e8e\u7ed9\u5b9a\u5bf9\u8c61\u662f\u552f\u4e00\u7684\u3002 \u6807\u7b7e\u7684\u793a\u4f8b\uff1a \"metadata\" : { \"labels\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } \u4e0e\u540d\u79f0\u548c UID \u4e0d\u540c\uff0c\u6807\u7b7e\u4e0d\u63d0\u4f9b\u552f\u4e00\u6027\u3002\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u671f\u671b\u8bb8\u591a\u5bf9\u8c61\u5e26\u6709\u76f8\u540c\u7684\u6807\u7b7e\u3002 \u76ee\u524d API \u652f\u6301\u4e24\u79cd\u7c7b\u578b\u7684\u9009\u62e9\u5668\uff1a \u57fa\u4e8e\u7b49\u5f0f\u7684\u9009\u62e9\u5668\uff0c\u4f8b\u5982\uff1a environment = production \u3001 tier != frontend \u57fa\u4e8e\u96c6\u5408\u7684\u9009\u62e9\u5668\uff0c\u4f8b\u5982\uff1a environment in (production, qa) \u3001 tier notin (frontend, backend) \u4f8b\u5982\uff1a kubectl get pods -l environment = production,tier = frontend kubectl get pods -l 'environment in (production),tier in (frontend)' kubectl get pods -l 'environment in (production, qa)' kubectl get pods -l 'environment,environment notin (frontend)'","title":"\u6807\u7b7e\u548c\u9009\u62e9\u5668"},{"location":"k8s/cka_cn/foundamentals/memo/#annotations","text":"\u4f7f\u7528 Kubernetes \u6ce8\u91ca\uff08Annotations\uff09\u5c06\u4efb\u610f\u975e\u6807\u8bc6\u5143\u6570\u636e\u9644\u52a0\u5230\u5bf9\u8c61\u4e0a\u3002 \u5de5\u5177\u548c\u5e93\u7b49\u5ba2\u6237\u7aef\u53ef\u4ee5\u68c0\u7d22\u6b64\u5143\u6570\u636e\u3002 \u4f7f\u7528\u6807\u7b7e\u6216\u6ce8\u91ca\u5c06\u5143\u6570\u636e\u9644\u52a0\u5230 Kubernetes \u5bf9\u8c61\u4e0a\u3002 \u6807\u7b7e\u53ef\u7528\u4e8e\u9009\u62e9\u5bf9\u8c61\u5e76\u67e5\u627e\u6ee1\u8db3\u67d0\u4e9b\u6761\u4ef6\u7684\u5bf9\u8c61\u96c6\u5408\u3002 \u6ce8\u91ca\u4e0d\u7528\u4e8e\u6807\u8bc6\u548c\u9009\u62e9\u5bf9\u8c61\u3002 \u6ce8\u91ca\u4e0e\u6807\u7b7e\u7c7b\u4f3c\uff0c\u90fd\u662f\u952e/\u503c\u6620\u5c04\u3002 \u6620\u5c04\u4e2d\u7684\u952e\u548c\u503c\u5fc5\u987b\u662f\u5b57\u7b26\u4e32\u3002 \u4f8b\u5982\uff1a \"metadata\" : { \"annotations\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } \u5408\u6cd5\u7684\u6ce8\u91ca\u952e\u5177\u6709\u4e24\u4e2a\u90e8\u5206\uff1a\u53ef\u9009\u7684\u524d\u7f00\u548c\u540d\u79f0\uff0c\u7531\u659c\u6760 ( / ) \u5206\u9694\u3002","title":"\u6ce8\u91caAnnotations"},{"location":"k8s/cka_cn/foundamentals/memo/#_6","text":"\u5b57\u6bb5\u9009\u62e9\u5668\uff08field selectors\uff09\u53ef\u4ee5\u6839\u636e\u4e00\u4e2a\u6216\u591a\u4e2a\u8d44\u6e90\u5b57\u6bb5\u7684\u503c\u9009\u62e9Kubernetes\u8d44\u6e90\u3002 \u4e0b\u9762\u662f\u4e00\u4e9b\u4f7f\u7528\u5b57\u6bb5\u9009\u62e9\u5668\u8fdb\u884c\u67e5\u8be2\u7b5b\u9009\u7684\u4f8b\u5b50\uff1a metadata.name=my-service metadata.namespace!=default status.phase=Pending This kubectl command selects all Pods for which the value of the status.phase field is Running: kubectl get pods --field-selector status.phase=Running Supported field selectors vary by Kubernetes resource type. All resource types support the metadata.name and metadata.namespace fields. Use the = , == , and != operators with field selectors ( = and == mean the same thing). \u4e0b\u9762 kubectl \u547d\u4ee4\u9009\u62e9\u6240\u6709\u72b6\u6001(phase)\u5b57\u6bb5\u503c\u4e3a Running \u7684 Pod\uff1a kubectl get pods --field-selector status.phase = Running \u652f\u6301\u7684\u5b57\u6bb5\u9009\u62e9\u5668\u56e0 Kubernetes \u8d44\u6e90\u7c7b\u578b\u800c\u5f02\u3002\u6240\u6709\u8d44\u6e90\u7c7b\u578b\u90fd\u652f\u6301 metadata.name \u548c metadata.namespace \u5b57\u6bb5\u3002 \u5728\u5b57\u6bb5\u9009\u62e9\u5668\u4e2d\u4f7f\u7528 = , == , \u548c != \u8fd0\u7b97\u7b26( = \u548c == \u8868\u793a\u76f8\u540c\u7684\u610f\u601d)\u3002 \u4f8b\u5982\uff1a kubectl get ingress --field-selector foo.bar = baz kubectl get services --all-namespaces --field-selector metadata.namespace! = default kubectl get pods --field-selector = status.phase! = Running,spec.restartPolicy = Always kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace! = default Finalizers\u662f*\u547d\u540d\u7a7a\u95f4\u952e*\uff0c\u544a\u8bc9Kubernetes\u5728\u6ee1\u8db3\u7279\u5b9a\u6761\u4ef6\u4e4b\u524d\u7b49\u5f85\uff0c\u7136\u540e\u518d\u5b8c\u5168\u5220\u9664\u6807\u8bb0\u4e3a*\u5220\u9664*\u7684\u8d44\u6e90\u3002 Finalizer\u8b66\u544a\u63a7\u5236\u5668controller\u6e05\u7406\u5df2\u5220\u9664\u5bf9\u8c61\u6240\u62e5\u6709\u7684\u8d44\u6e90\u3002 \u901a\u5e38\u56e0\u4e3a\u67d0\u79cd\u76ee\u7684\u4e3a\u8d44\u6e90\u6dfb\u52a0Finalizers\uff0c\u5f3a\u5236\u5220\u9664\u5b83\u4eec\u53ef\u80fd\u4f1a\u5bfc\u81f4\u96c6\u7fa4\u4e2d\u51fa\u73b0\u95ee\u9898\u3002 \u4e0e\u6807\u7b7e\u7c7b\u4f3c\uff0c \u6240\u6709\u8005\u5f15\u7528 \uff08Owner references\uff09\u63cf\u8ff0\u4e86Kubernetes\u4e2d\u5bf9\u8c61\u4e4b\u95f4\u7684\u5173\u7cfb\uff0c\u4f46\u7528\u4e8e\u4e0d\u540c\u7684\u76ee\u7684\u3002 Kubernetes\u4f7f\u7528\u6240\u6709\u8005\u5f15\u7528\uff08\u800c\u4e0d\u662f\u6807\u7b7e\uff09\u6765\u786e\u5b9a\u96c6\u7fa4\u4e2d\u54ea\u4e9bPod\u9700\u8981\u6e05\u7406\u3002 \u5f53Kubernetes\u8bc6\u522b\u5230\u76ee\u6807\u5220\u9664\u7684\u8d44\u6e90\u4e0a\u6709\u6240\u6709\u8005\u5f15\u7528\u65f6\uff0c\u5b83\u4f1a\u5904\u7406Finalizer\u3002","title":"\u5b57\u6bb5\u9009\u62e9\u5668"},{"location":"k8s/cka_cn/foundamentals/memo/#_7","text":"\u5728 Kubernetes \u4e2d\uff0c\u4e00\u4e9b\u5bf9\u8c61\u62e5\u6709\u5176\u4ed6\u5bf9\u8c61\u3002\u4f8b\u5982\uff0cReplicaSet \u662f\u4e00\u7ec4 Pod \u7684\u6240\u6709\u8005\u3002\u8fd9\u4e9b\u88ab\u62e5\u6709\u7684\u5bf9\u8c61\u662f\u5176\u6240\u6709\u8005\u7684\u4ece\u5c5e\u5bf9\u8c61\u3002 \u4ece\u5c5e\u5bf9\u8c61\u5177\u6709\u4e00\u4e2a metadata.ownerReferences \u5b57\u6bb5\uff0c\u8be5\u5b57\u6bb5\u5f15\u7528\u5176\u6240\u6709\u8005\u5bf9\u8c61\u3002 \u6709\u6548\u7684\u6240\u6709\u8005\u5f15\u7528\u5305\u62ec\u5bf9\u8c61\u540d\u79f0\u548c\u4e0e\u4ece\u5c5e\u5bf9\u8c61\u76f8\u540c\u7684\u547d\u540d\u7a7a\u95f4\u4e2d\u7684 UID\u3002 \u4ece\u5c5e\u5bf9\u8c61\u8fd8\u5177\u6709\u4e00\u4e2a ownerReferences.blockOwnerDeletion \u5b57\u6bb5\uff0c\u8be5\u5b57\u6bb5\u5177\u6709\u5e03\u5c14\u503c\uff0c\u63a7\u5236\u7279\u5b9a\u7684\u4ece\u5c5e\u5bf9\u8c61\u662f\u5426\u53ef\u4ee5\u963b\u6b62\u5783\u573e\u56de\u6536\u5220\u9664\u5176\u6240\u6709\u8005\u5bf9\u8c61\u3002","title":"\u6240\u6709\u8005\u548c\u4f9d\u8d56\u5173\u7cfb"},{"location":"k8s/cka_cn/foundamentals/memo/#_8","text":"Kubernetes\u8d44\u6e90\u548c\u201c\u610f\u5411\u8bb0\u5f55\u201d\u90fd\u4ee5API\u5bf9\u8c61\u7684\u5f62\u5f0f\u5b58\u50a8\uff0c\u5e76\u901a\u8fc7\u5bf9API\u7684RESTful\u8c03\u7528\u8fdb\u884c\u4fee\u6539\u3002 API\u5141\u8bb8\u4ee5\u58f0\u660e\u6027\u65b9\u5f0f\u7ba1\u7406\u914d\u7f6e\u3002 \u7528\u6237\u53ef\u4ee5\u76f4\u63a5\u4e0eKubernetes API\u4ea4\u4e92\uff0c\u4e5f\u53ef\u4ee5\u901a\u8fc7\u50cfkubectl\u8fd9\u6837\u7684\u5de5\u5177\u8fdb\u884c\u4ea4\u4e92\u3002 \u6838\u5fc3Kubernetes API\u5177\u6709\u7075\u6d3b\u6027\uff0c\u4e5f\u53ef\u4ee5\u6269\u5c55\u4ee5\u652f\u6301\u81ea\u5b9a\u4e49\u8d44\u6e90\u3002 \u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\uff08Workload Resources\uff09 Pod \u3002Pod \u662f\u53ef\u4ee5\u5728\u4e3b\u673a\u4e0a\u8fd0\u884c\u7684\u5bb9\u5668\u96c6\u5408\u3002 PodTemplate \u3002PodTemplate \u63cf\u8ff0\u4e86\u9884\u5b9a\u4e49 pod \u7684\u526f\u672c\u6a21\u677f\u3002 ReplicationController \u3002ReplicationController \u8868\u793a\u4e00\u4e2a\u590d\u5236\u63a7\u5236\u5668\u7684\u914d\u7f6e\u3002 ReplicaSet \u3002ReplicaSet \u786e\u4fdd\u5728\u4efb\u4f55\u7ed9\u5b9a\u65f6\u95f4\u6709\u6307\u5b9a\u6570\u91cf\u7684 pod \u526f\u672c\u6b63\u5728\u8fd0\u884c\u3002 Deployment \u3002Deployment \u4f7f Pod \u548c ReplicaSet \u7684\u58f0\u660e\u6027\u66f4\u65b0\u6210\u4e3a\u53ef\u80fd\u3002 StatefulSet \u3002StatefulSet \u8868\u793a\u5177\u6709\u4e00\u81f4\u6807\u8bc6\u7684 pod \u96c6\u5408\u3002 ControllerRevision \u3002ControllerRevision \u5b9e\u73b0\u4e86\u72b6\u6001\u6570\u636e\u7684\u4e0d\u53ef\u53d8\u5feb\u7167\u3002 DaemonSet \u3002DaemonSet \u8868\u793a\u4e00\u4e2a\u5b88\u62a4\u8fdb\u7a0b\u96c6\u7684\u914d\u7f6e\u3002 Job \u3002Job \u8868\u793a\u5355\u4e2a job \u7684\u914d\u7f6e\u3002 CronJob \u3002CronJob \u8868\u793a\u5355\u4e2a cron job \u7684\u914d\u7f6e\u3002 HorizontalPodAutoscaler \u3002HorizontalPodAutoscaler \u8868\u793a\u6c34\u5e73 pod \u81ea\u52a8\u7f29\u653e\u5668\u7684\u914d\u7f6e\u3002 HorizontalPodAutoscaler v2beta2 \u3002HorizontalPodAutoscaler \u662f\u6c34\u5e73 pod \u81ea\u52a8\u7f29\u653e\u5668\u7684\u914d\u7f6e\uff0c\u6839\u636e\u6307\u5b9a\u7684\u6307\u6807\u81ea\u52a8\u7ba1\u7406\u5b9e\u73b0\u6bd4\u4f8b\u5b50\u8d44\u6e90\u7684\u4efb\u4f55\u8d44\u6e90\u7684\u526f\u672c\u8ba1\u6570\u3002 PriorityClass \u3002PriorityClass \u5b9a\u4e49\u4e86\u4ece\u4f18\u5148\u7ea7\u7c7b\u540d\u79f0\u5230\u4f18\u5148\u7ea7\u6574\u6570\u503c\u7684\u6620\u5c04\u3002 \u670d\u52a1\u8d44\u6e90\uff08Service Resources\uff09 Service . Service \u662f\u5bf9\u8f6f\u4ef6\u670d\u52a1\uff08\u4f8b\u5982mysql\uff09\u7684\u547d\u540d\u62bd\u8c61\uff0c\u7531\u4ee3\u7406\u76d1\u542c\u7684\u672c\u5730\u7aef\u53e3\uff08\u4f8b\u59823306\uff09\u548c\u786e\u5b9a\u54ea\u4e9bPod\u5c06\u56de\u7b54\u901a\u8fc7\u4ee3\u7406\u53d1\u9001\u7684\u8bf7\u6c42\u7684\u9009\u62e9\u5668\u7ec4\u6210\u3002 Endpoints . Endpoints \u662f\u5b9e\u73b0\u5b9e\u9645\u670d\u52a1\u7684\u4e00\u7ec4\u7ec8\u7ed3\u70b9\u3002 EndpointSlice . EndpointSlice \u8868\u793a\u5b9e\u73b0\u670d\u52a1\u7684\u7ec8\u7ed3\u70b9\u7684\u5b50\u96c6\u3002 Ingress . Ingress \u662f\u4e00\u7ec4\u89c4\u5219\uff0c\u5141\u8bb8\u5165\u7ad9\u8fde\u63a5\u5230\u8fbe\u7531\u540e\u7aef\u5b9a\u4e49\u7684\u7ec8\u7ed3\u70b9\u3002 IngressClass . IngressClass \u8868\u793a Ingress \u7684\u7c7b\uff0c\u7531 Ingress Spec \u5f15\u7528\u3002 \u914d\u7f6e\u548c\u5b58\u50a8\u8d44\u6e90\uff08Config and Storage Resources\uff09 ConfigMap \u3002ConfigMap\u4fdd\u5b58\u5bb9\u5668\u9700\u8981\u4f7f\u7528\u7684\u914d\u7f6e\u6570\u636e\u3002 Secret \u3002Secret\u4fdd\u5b58\u7279\u5b9a\u7c7b\u578b\u7684\u673a\u5bc6\u6570\u636e\u3002 Volume \u3002Volume\u8868\u793aPod\u4e2d\u7684\u547d\u540d\u5377\uff0c\u53ef\u4ee5\u88abPod\u4e2d\u7684\u4efb\u4f55\u5bb9\u5668\u8bbf\u95ee\u3002 PersistentVolumeClaim \u3002PersistentVolumeClaim\u662f\u7528\u6237\u5bf9\u6301\u4e45\u5377\u7684\u8bf7\u6c42\u548c\u58f0\u660e\u3002 PersistentVolume \u3002PersistentVolume\uff08PV\uff09\u662f\u7531\u7ba1\u7406\u5458\u63d0\u4f9b\u7684\u5b58\u50a8\u8d44\u6e90\u3002 StorageClass \u3002StorageClass\u63cf\u8ff0\u53ef\u52a8\u6001\u5206\u914dPersistentVolumes\u7684\u5b58\u50a8\u7c7b\u522b\u7684\u53c2\u6570\u3002 VolumeAttachment \u3002VolumeAttachment\u8bb0\u5f55\u5c06\u6307\u5b9a\u7684\u5377\u9644\u52a0\u5230/\u4ece\u6307\u5b9a\u8282\u70b9\u4e2d\u5206\u79bb\u7684\u610f\u56fe\u3002 CSIDriver \u3002CSIDriver\u8bb0\u5f55\u96c6\u7fa4\u4e0a\u90e8\u7f72\u7684\u5bb9\u5668\u5b58\u50a8\u63a5\u53e3\uff08CSI\uff09\u5377\u9a71\u52a8\u7a0b\u5e8f\u7684\u4fe1\u606f\u3002 CSINode \u3002CSINode\u4fdd\u5b58\u6709\u5173\u8282\u70b9\u4e0a\u5b89\u88c5\u7684\u6240\u6709CSI\u9a71\u52a8\u7a0b\u5e8f\u7684\u4fe1\u606f\u3002 CSIStorageCapacity \u3002CSIStorageCapacity\u5b58\u50a8\u4e00\u4e2aCSI GetCapacity\u8c03\u7528\u7684\u7ed3\u679c\u3002 \u8ba4\u8bc1\u8d44\u6e90\uff08Authentication Resources\uff09 ServiceAccount*\u3002ServiceAccount\u548c\u4e0b\u9762\u7684\u4fe1\u606f\u7ed1\u5b9a\u5728\u4e00\u8d77\uff1a \u4e00\u4e2a\u53ef\u88ab\u7528\u6237\u548c\u5468\u8fb9\u7cfb\u7edf\u7406\u89e3\u7684\u540d\u79f0\uff0c\u7528\u4e8e\u8eab\u4efd\u8bc6\u522b \u53ef\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u7684\u4e3b\u4f53 \u4e00\u7ec4\u5bc6\u94a5\u3002 TokenRequest*\u3002TokenRequest\u4e3a\u7ed9\u5b9a\u7684ServiceAccount\u8bf7\u6c42\u4e00\u4e2a\u4ee4\u724c\u3002 TokenReview*\u3002TokenReview\u5c1d\u8bd5\u5bf9\u5df2\u77e5\u7528\u6237\u7684\u4ee4\u724c\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u3002 CertificateSigningRequest*\u3002CertificateSigningRequest\u5bf9\u8c61\u63d0\u4f9b\u4e86\u4e00\u79cd\u901a\u8fc7\u63d0\u4ea4\u8bc1\u4e66\u7b7e\u540d\u8bf7\u6c42\u5e76\u5f02\u6b65\u6279\u51c6\u548c\u53d1\u653e\u6765\u83b7\u53d6x509\u8bc1\u4e66\u7684\u673a\u5236\u3002 \u6388\u6743\u8d44\u6e90\uff08Authorization Resources\uff09 LocalSubjectAccessReview*\u3002LocalSubjectAccessReview\u68c0\u67e5\u4e00\u4e2a\u7528\u6237\u6216\u7ec4\u5728\u7ed9\u5b9a\u547d\u540d\u7a7a\u95f4\u4e2d\u662f\u5426\u80fd\u6267\u884c\u67d0\u4e2a\u64cd\u4f5c\u3002 SelfSubjectAccessReview*\u3002SelfSubjectAccessReview\u68c0\u67e5\u5f53\u524d\u7528\u6237\u662f\u5426\u80fd\u6267\u884c\u67d0\u4e2a\u64cd\u4f5c\u3002 SelfSubjectRulesReview*\u3002SelfSubjectRulesReview\u679a\u4e3e\u5f53\u524d\u7528\u6237\u5728\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4\u5185\u53ef\u4ee5\u6267\u884c\u7684\u64cd\u4f5c\u96c6\u5408\u3002 SubjectAccessReview*\u3002SubjectAccessReview\u68c0\u67e5\u4e00\u4e2a\u7528\u6237\u6216\u7ec4\u662f\u5426\u80fd\u6267\u884c\u67d0\u4e2a\u64cd\u4f5c\u3002 ClusterRole*\u3002ClusterRole\u662f\u4e00\u4e2a\u96c6\u7fa4\u7ea7\u522b\u7684PolicyRules\u903b\u8f91\u5206\u7ec4\uff0c\u53ef\u4ee5\u88abRoleBinding\u6216ClusterRoleBinding\u5f15\u7528\u4e3a\u4e00\u4e2a\u5355\u5143\u3002 ClusterRoleBinding*\u3002ClusterRoleBinding\u5f15\u7528\u4e00\u4e2aClusterRole\uff0c\u4f46\u4e0d\u5305\u542b\u5b83\u3002 Role*\u3002Role\u662f\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4\u7ea7\u522b\u7684PolicyRules\u903b\u8f91\u5206\u7ec4\uff0c\u53ef\u4ee5\u88abRoleBinding\u5f15\u7528\u4e3a\u4e00\u4e2a\u5355\u5143\u3002 RoleBinding*\u3002RoleBinding\u5f15\u7528\u4e00\u4e2aRole\uff0c\u4f46\u4e0d\u5305\u542b\u5b83\u3002 \u7b56\u7565\u8d44\u6e90\uff08Policy Resources\uff09 LimitRange*\u3002LimitRange\u4e3a\u547d\u540d\u7a7a\u95f4\u4e2d\u6bcf\u79cd\u8d44\u6e90\u8bbe\u7f6e\u8d44\u6e90\u4f7f\u7528\u9650\u5236\u3002 ResourceQuota*\u3002ResourceQuota\u8bbe\u7f6e\u6bcf\u4e2a\u547d\u540d\u7a7a\u95f4\u5f3a\u5236\u6267\u884c\u7684\u603b\u914d\u989d\u9650\u5236\u3002 NetworkPolicy*\u3002NetworkPolicy\u63cf\u8ff0\u4e86\u4e00\u7ec4Pod\u5141\u8bb8\u7684\u7f51\u7edc\u6d41\u91cf\u3002 PodDisruptionBudget*\u3002PodDisruptionBudget\u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u7528\u4e8e\u5b9a\u4e49\u5bf9\u4e00\u7ec4Pod\u53ef\u80fd\u9020\u6210\u7684\u6700\u5927\u4e2d\u65ad\u3002 PodSecurityPolicy v1beta1*\u3002PodSecurityPolicy\u63a7\u5236\u5bf9\u53ef\u80fd\u5f71\u54cd\u5c06\u5e94\u7528\u4e8ePod\u548c\u5bb9\u5668\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\u7684\u8bf7\u6c42\u7684\u80fd\u529b\u3002 \u6269\u5c55\u8d44\u6e90\uff08Extend Resources\uff09 CustomResourceDefinition*\u3002CustomResourceDefinition\u8868\u793a\u5e94\u5728API\u670d\u52a1\u5668\u4e0a\u516c\u5f00\u7684\u8d44\u6e90\u3002 MutatingWebhookConfiguration*\u3002MutatingWebhookConfiguration\u63cf\u8ff0\u63a5\u53d7\u6216\u62d2\u7edd\u5e76\u53ef\u80fd\u66f4\u6539\u5bf9\u8c61\u7684\u51c6\u5165Webhook\u7684\u914d\u7f6e\u3002 ValidatingWebhookConfiguration*\u3002ValidatingWebhookConfiguration\u63cf\u8ff0\u63a5\u53d7\u6216\u62d2\u7edd\u5bf9\u8c61\u4f46\u4e0d\u66f4\u6539\u5bf9\u8c61\u7684\u51c6\u5165Webhook\u7684\u914d\u7f6e\u3002 \u96c6\u7fa4\u8d44\u6e90\uff08Cluster Resources\uff09 Node*\u3002Node\u662fKubernetes\u4e2d\u7684\u5de5\u4f5c\u8282\u70b9\u3002 Namespace*\u3002Namespace\u4e3a\u540d\u79f0\u63d0\u4f9b\u4e86\u4f5c\u7528\u57df\u3002 Event*\u3002Event\u662f\u5bf9\u96c6\u7fa4\u4e2d\u67d0\u4e2a\u4f4d\u7f6e\u53d1\u751f\u4e8b\u4ef6\u7684\u62a5\u544a\u3002 APIService*\u3002APIService\u8868\u793a\u7279\u5b9aGroupVersion\u7684\u670d\u52a1\u5668\u3002 Lease*\u3002Lease\u5b9a\u4e49\u4e86\u79df\u8d41\u7684\u6982\u5ff5\u3002 RuntimeClass*\u3002RuntimeClass\u5b9a\u4e49\u4e86\u96c6\u7fa4\u4e2d\u652f\u6301\u7684\u5bb9\u5668\u8fd0\u884c\u65f6\u7c7b\u3002 FlowSchema v1beta2*\u3002FlowSchema\u5b9a\u4e49\u4e86\u4e00\u7ec4\u6d41\u7a0b\u7684\u67b6\u6784\u3002 PriorityLevelConfiguration v1beta2*\u3002PriorityLevelConfiguration\u8868\u793a\u4f18\u5148\u7ea7\u7ea7\u522b\u7684\u914d\u7f6e\u3002 Binding*\u3002Binding\u5c06\u4e00\u4e2a\u5bf9\u8c61\u7ed1\u5b9a\u5230\u53e6\u4e00\u4e2a\u5bf9\u8c61\uff1b\u4f8b\u5982\uff0c\u8c03\u5ea6\u7a0b\u5e8f\u5c06Pod\u7ed1\u5b9a\u5230\u8282\u70b9\u4e0a\u3002 ComponentStatus*\u3002ComponentStatus\uff08\u548cComponentStatusList\uff09\u4fdd\u5b58\u96c6\u7fa4\u9a8c\u8bc1\u4fe1\u606f\u3002 \u4f7f\u7528\u547d\u4ee4 kube api-resources \u83b7\u53d6\u652f\u6301\u7684API\u8d44\u6e90\u3002 \u4f7f\u7528\u547d\u4ee4 kubectl explain RESOURCE [options] \u63cf\u8ff0\u4e0e\u6bcf\u4e2a\u652f\u6301\u7684API\u8d44\u6e90\u76f8\u5173\u8054\u7684\u5b57\u6bb5\u3002\u8fd9\u4e9b\u5b57\u6bb5\u53ef\u4ee5\u901a\u8fc7\u7b80\u5355\u7684JSONPath\u6807\u8bc6\u7b26\u8fdb\u884c\u8bc6\u522b\uff1a kubectl explain binding kubectl explain binding.metadata kubectl explain binding.metadata.name","title":"\u8d44\u6e90"},{"location":"k8s/cka_cn/foundamentals/memo/#_9","text":"","title":"\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90"},{"location":"k8s/cka_cn/foundamentals/memo/#pods","text":"Pod\u662fKubernetes\u4e2d\u53ef\u521b\u5efa\u548c\u7ba1\u7406\u7684\u6700\u5c0f\u90e8\u7f72\u8ba1\u7b97\u5355\u4f4d\u3002 Pod\u662f\u4e00\u4e2a\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u5bb9\u5668\u3001\u5171\u4eab\u5b58\u50a8\u548c\u7f51\u7edc\u8d44\u6e90\u4ee5\u53ca\u5982\u4f55\u8fd0\u884c\u5bb9\u5668\u7684\u89c4\u8303\u7684\u7ec4\u3002 Pod\u7684\u5185\u5bb9\u59cb\u7ec8\u5171\u540c\u5b9a\u4f4d\u548c\u5171\u540c\u5b89\u6392\uff0c\u5e76\u5728\u5171\u4eab\u73af\u5883\u4e2d\u8fd0\u884c\u3002 Pod\u6a21\u62df\u4e86\u4e00\u4e2a\u7279\u5b9a\u4e8e\u5e94\u7528\u7a0b\u5e8f\u7684\u201c\u903b\u8f91\u4e3b\u673a\u201d\uff1a\u5b83\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u76f8\u5bf9\u7d27\u5bc6\u8026\u5408\u7684\u5e94\u7528\u7a0b\u5e8f\u5bb9\u5668\u3002 \u5728\u975e\u4e91\u73af\u5883\u4e2d\uff0c\u540c\u4e00\u7269\u7406\u6216\u865a\u62df\u673a\u4e0a\u6267\u884c\u7684\u5e94\u7528\u7a0b\u5e8f\u7c7b\u4f3c\u4e8e\u5728\u540c\u4e00\u903b\u8f91\u4e3b\u673a\u4e0a\u6267\u884c\u7684\u4e91\u5e94\u7528\u7a0b\u5e8f\u3002 Pod\u7684\u5171\u4eab\u73af\u5883\u662f\u4e00\u7ec4Linux\u547d\u540d\u7a7a\u95f4\u3001cgroups\u548c\u53ef\u80fd\u7684\u5176\u4ed6\u9694\u79bb\u8981\u7d20 - \u8fd9\u4e9b\u8981\u7d20\u4e0e\u9694\u79bbDocker\u5bb9\u5668\u7684\u65b9\u5f0f\u76f8\u540c\u3002 \u5728Docker\u6982\u5ff5\u65b9\u9762\uff0cPod\u7c7b\u4f3c\u4e8e\u5177\u6709\u5171\u4eab\u547d\u540d\u7a7a\u95f4\u548c\u5171\u4eab\u6587\u4ef6\u7cfb\u7edf\u5377\u7684\u4e00\u7ec4Docker\u5bb9\u5668\u3002 \u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u751a\u81f3\u662f\u5355\u4f8bPod\uff0c\u6211\u4eec\u90fd\u4e0d\u9700\u8981\u76f4\u63a5\u521b\u5efaPod\uff0c\u800c\u662f\u4f7f\u7528\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\uff0c\u4f8b\u5982*Deployment*\u6216*Job*\u6765\u521b\u5efa\u5b83\u4eec\u3002\u5982\u679cPod\u9700\u8981\u8ddf\u8e2a\u72b6\u6001\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528StatefulSet\u8d44\u6e90\u3002 Kubernetes\u96c6\u7fa4\u4e2d\u7684Pod\u6709\u4e24\u79cd\u4e3b\u8981\u7528\u6cd5\uff1a \u8fd0\u884c\u5355\u4e2a\u5bb9\u5668\u7684Pod\u3002 \u8fd0\u884c\u9700\u8981\u5171\u540c\u5de5\u4f5c\u7684\u591a\u4e2a\u5bb9\u5668\u7684Pod\u3002 \u201c\u6bcf\u4e2aPod\u4e00\u4e2a\u5bb9\u5668\u201d\u7684\u6a21\u578b\u662f\u6700\u5e38\u89c1\u7684Kubernetes\u7528\u4f8b\uff1b\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\u53ef\u4ee5\u5c06Pod\u89c6\u4e3a\u5355\u4e2a\u5bb9\u5668\u7684\u5305\u88c5\u5668\uff1bKubernetes\u7ba1\u7406Pod\u800c\u4e0d\u662f\u76f4\u63a5\u7ba1\u7406\u5bb9\u5668\u3002 \u4e00\u4e2aPod\u53ef\u4ee5\u5c01\u88c5\u7531\u591a\u4e2a\u5171\u540c\u5b9a\u4f4d\u3001\u7d27\u5bc6\u8026\u5408\u4e14\u9700\u8981\u5171\u4eab\u8d44\u6e90\u7684\u5bb9\u5668\u7ec4\u6210\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 \u8fd9\u4e9b\u5171\u540c\u5b9a\u4f4d\u7684\u5bb9\u5668\u5f62\u6210\u4e00\u4e2a\u5355\u4e00\u7684\u670d\u52a1\u6574\u4f53\u5355\u5143 - \u4f8b\u5982\uff0c\u4e00\u4e2a\u5bb9\u5668\u5411\u516c\u4f17\u63d0\u4f9b\u5b58\u50a8\u5728\u5171\u4eab\u5377\u4e2d\u7684\u6570\u636e\uff0c\u800c\u53e6\u4e00\u4e2a\u72ec\u7acb\u7684Sidecar\u5bb9\u5668\u5237\u65b0\u6216\u66f4\u65b0\u8fd9\u4e9b\u6587\u4ef6\u3002Pod\u5c06\u8fd9\u4e9b\u5bb9\u5668\u3001\u5b58\u50a8\u8d44\u6e90\u548c\u77ed\u6682\u7684\u7f51\u7edc\u6807\u8bc6\u5305\u88c5\u5728\u4e00\u8d77\uff0c\u4f5c\u4e3a\u4e00\u4e2a\u5355\u72ec\u7684\u5355\u4f4d\u3002 \u5728\u5355\u4e2aPod\u4e2d\u5206\u7ec4\u591a\u4e2a\u5171\u540c\u5b9a\u4f4d\u548c\u5171\u540c\u7ba1\u7406\u7684\u5bb9\u5668\u662f\u76f8\u5bf9\u9ad8\u7ea7\u7684\u7528\u4f8b\u3002\u5e94\u8be5*\u4ec5\u5728*\u5bb9\u5668\u7d27\u5bc6\u8026\u5408\u7684\u7279\u5b9a\u60c5\u51b5\u4e0b\u4f7f\u7528\u6b64\u6a21\u5f0f\u3002 \u6bcf\u4e2aPod\u90fd\u65e8\u5728\u8fd0\u884c\u7ed9\u5b9a\u5e94\u7528\u7a0b\u5e8f\u7684\u5355\u4e2a\u5b9e\u4f8b\u3002\u5982\u679c\u6211\u4eec\u60f3\u6c34\u5e73\u6269\u5c55\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\uff08\u901a\u8fc7\u8fd0\u884c\u66f4\u591a\u5b9e\u4f8b\u63d0\u4f9b\u66f4\u591a\u7684\u603b\u8d44\u6e90\uff09\uff0c\u5219\u5e94\u8be5\u4f7f\u7528\u591a\u4e2aPod\uff0c\u6bcf\u4e2a\u5b9e\u4f8b\u4e00\u4e2aPod\u3002\u5728Kubernetes\u4e2d\uff0c\u8fd9\u901a\u5e38\u79f0\u4e3a*\u590d\u5236*\u3002\u590d\u5236\u7684Pod\u901a\u5e38\u4f5c\u4e3a\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\u53ca\u5176\u63a7\u5236\u5668\u7684\u4e00\u7ec4\u521b\u5efa\u548c\u7ba1\u7406\u3002 Pod\u672c\u5730\u63d0\u4f9b\u4e24\u79cd\u5171\u4eab\u8d44\u6e90\u4ee5\u4f9b\u5176\u7ec4\u6210\u5bb9\u5668\u4f7f\u7528\uff1a \u7f51\u7edc *\u548c \u5b58\u50a8 *\u3002 \u4e00\u4e2aPod\u53ef\u4ee5\u6307\u5b9a\u4e00\u7ec4\u5171\u4eab\u7684\u5b58\u50a8\u5377\u3002Pod\u4e2d\u7684\u6240\u6709\u5bb9\u5668\u90fd\u53ef\u4ee5\u8bbf\u95ee\u8fd9\u4e9b\u5171\u4eab\u5377\uff0c\u4f7f\u8fd9\u4e9b\u5bb9\u5668\u53ef\u4ee5\u5171\u4eab\u6570\u636e\u3002 \u6bcf\u4e2aPod\u4e3a\u6bcf\u4e2a\u5730\u5740\u65cf\u5206\u914d\u4e00\u4e2a\u552f\u4e00\u7684IP\u5730\u5740\u3002 \u5728\u4e00\u4e2aPod\u5185\uff0c\u5bb9\u5668\u5171\u4eab\u4e00\u4e2aIP\u5730\u5740\u548c\u7aef\u53e3\u7a7a\u95f4\uff0c\u5e76\u53ef\u4ee5\u901a\u8fc7\u201clocalhost\u201d\u627e\u5230\u5f7c\u6b64\u3002\u60f3\u8981\u4e0e\u8fd0\u884c\u5728\u4e0d\u540cPod\u4e2d\u7684\u5bb9\u5668\u4ea4\u4e92\u7684\u5bb9\u5668\u53ef\u4ee5\u4f7f\u7528IP\u7f51\u7edc\u8fdb\u884c\u901a\u4fe1\u3002 \u5f53\u521b\u5efa\u4e00\u4e2aPod\u65f6\uff0c\u65b0\u7684Pod\u88ab\u8c03\u5ea6\u5728\u96c6\u7fa4\u4e2d\u7684\u4e00\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u3002Pod\u4fdd\u7559\u5728\u8be5\u8282\u70b9\u4e0a\uff0c\u76f4\u5230Pod\u6267\u884c\u5b8c\u6bd5\u3001Pod\u5bf9\u8c61\u88ab\u5220\u9664\u3001Pod\u56e0\u7f3a\u4e4f\u8d44\u6e90\u800c\u88ab\u9a71\u9010\u6216\u8282\u70b9\u53d1\u751f\u6545\u969c\u3002 \u5728Pod\u4e2d\u91cd\u65b0\u542f\u52a8\u4e00\u4e2a\u5bb9\u5668\u4e0d\u5e94\u4e0e\u91cd\u65b0\u542f\u52a8\u4e00\u4e2aPod\u6df7\u6dc6\u3002Pod\u4e0d\u662f\u4e00\u4e2a\u8fdb\u7a0b\uff0c\u800c\u662f\u4e00\u4e2a\u8fd0\u884c\u5bb9\u5668\u7684\u73af\u5883\u3002Pod\u4f1a\u4e00\u76f4\u4fdd\u7559\uff0c\u76f4\u5230\u88ab\u5220\u9664\u4e3a\u6b62\u3002 \u60a8\u53ef\u4ee5\u4f7f\u7528\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\uff08\u4f8b\u5982Deployment\u3001StatefulSet\u3001DaemonSet\uff09\u4e3a\u81ea\u5df1\u521b\u5efa\u548c\u7ba1\u7406\u591a\u4e2aPod\u3002\u8d44\u6e90\u7684\u63a7\u5236\u5668\u5904\u7406\u590d\u5236\u3001\u6eda\u52a8\u548c\u5728Pod\u5931\u8d25\u65f6\u7684\u81ea\u52a8\u6062\u590d\u3002","title":"Pods"},{"location":"k8s/cka_cn/foundamentals/memo/#_10","text":"\u4e00\u4e9bPod\u8fd8\u6709\u521d\u59cb\u5316\u5bb9\u5668\uff08Init containers\uff09\u548c\u5e94\u7528\u5bb9\u5668\uff08app containers\uff09\u3002\u521d\u59cb\u5316\u5bb9\u5668\u5728\u5e94\u7528\u5bb9\u5668\u542f\u52a8\u4e4b\u524d\u8fd0\u884c\u5e76\u5b8c\u6210\u3002 \u6211\u4eec\u53ef\u4ee5\u5728Pod\u89c4\u8303\u4e2d\u6307\u5b9a\u521d\u59cb\u5316\u5bb9\u5668\uff0c\u540c\u65f6\u4e5f\u53ef\u4ee5\u5728\u5bb9\u5668\u6570\u7ec4\u4e2d\u63cf\u8ff0\u5e94\u7528\u5bb9\u5668\u3002","title":"\u521d\u59cb\u5316\u5bb9\u5668"},{"location":"k8s/cka_cn/foundamentals/memo/#pod","text":"\u9759\u6001Pod\u662f\u76f4\u63a5\u7531\u7279\u5b9a\u8282\u70b9\u4e0a\u7684kubelet\u5b88\u62a4\u7a0b\u5e8f\u7ba1\u7406\u7684\uff0cAPI\u670d\u52a1\u5668\u4e0d\u4f1a\u89c2\u5bdf\u5b83\u4eec\u3002 \u9759\u6001Pod\u59cb\u7ec8\u7ed1\u5b9a\u5230\u7279\u5b9a\u8282\u70b9\u4e0a\u7684\u4e00\u4e2aKubelet\u3002 \u9759\u6001Pod\u7684\u4e3b\u8981\u7528\u9014\u662f\u8fd0\u884c\u81ea\u6258\u7ba1\u63a7\u5236\u9762\u677f\uff1a\u6362\u53e5\u8bdd\u8bf4\uff0c\u4f7f\u7528kubelet\u76d1\u7763\u5404\u4e2a\u63a7\u5236\u9762\u677f\u7ec4\u4ef6\u3002 kubelet\u4f1a\u81ea\u52a8\u5c1d\u8bd5\u4e3a\u6bcf\u4e2a\u9759\u6001Pod\u5728Kubernetes API\u670d\u52a1\u5668\u4e0a\u521b\u5efa\u4e00\u4e2a\u955c\u50cfPod\u3002\u8fd9\u610f\u5473\u7740\u5728\u8282\u70b9\u4e0a\u8fd0\u884c\u7684Pod\u5728API\u670d\u52a1\u5668\u4e0a\u53ef\u89c1\uff0c\u4f46\u65e0\u6cd5\u4ece\u90a3\u91cc\u63a7\u5236\u3002","title":"\u9759\u6001Pod"},{"location":"k8s/cka_cn/foundamentals/memo/#_11","text":"\u63a2\u9488\u662f kubelet \u5b9a\u671f\u5bf9\u5bb9\u5668\u6267\u884c\u7684\u4e00\u79cd\u8bca\u65ad\u3002 \u4e3a\u6267\u884c\u8bca\u65ad\uff0ckubelet \u8981\u4e48\u5728\u5bb9\u5668\u5185\u6267\u884c\u4ee3\u7801\uff0c\u8981\u4e48\u53d1\u8d77\u7f51\u7edc\u8bf7\u6c42\u3002 \u4f7f\u7528\u63a2\u9488\u6709\u56db\u79cd\u4e0d\u540c\u7684\u68c0\u67e5\u5bb9\u5668\u65b9\u5f0f\u3002\u6bcf\u4e2a\u63a2\u9488\u5fc5\u987b\u6070\u597d\u5b9a\u4e49\u8fd9\u56db\u79cd\u673a\u5236\u4e2d\u7684\u4e00\u79cd\uff1a exec \u3002\u5982\u679c\u547d\u4ee4\u4ee5\u72b6\u6001\u4ee3\u7801 0 \u9000\u51fa\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 grpc \u3002\u5982\u679c\u54cd\u5e94\u7684\u72b6\u6001\u4e3a SERVING\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 httpGet \u3002\u5982\u679c\u54cd\u5e94\u7684\u72b6\u6001\u4ee3\u7801\u5927\u4e8e\u6216\u7b49\u4e8e 200 \u4e14\u5c0f\u4e8e 400\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 tcpSocket \u3002\u5982\u679c\u7aef\u53e3\u5f00\u653e\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 \u6bcf\u4e2a\u63a2\u9488\u6709\u4e09\u79cd\u7ed3\u679c\uff1a \u6210\u529f \u5931\u8d25 \u672a\u77e5 \u63a2\u9488\u7c7b\u578b\uff1a livenessProbe \u3002\u6307\u793a\u5bb9\u5668\u662f\u5426\u6b63\u5728\u8fd0\u884c\u3002 readinessProbe \u3002\u6307\u793a\u5bb9\u5668\u662f\u5426\u51c6\u5907\u597d\u54cd\u5e94\u8bf7\u6c42\u3002 startupProbe \u3002\u6307\u793a\u5bb9\u5668\u5185\u7684\u5e94\u7528\u7a0b\u5e8f\u662f\u5426\u542f\u52a8\u3002","title":"\u5bb9\u5668\u63a2\u9488"},{"location":"k8s/cka_cn/foundamentals/memo/#deployment","text":"","title":"Deployment"},{"location":"k8s/cka_cn/foundamentals/memo/#replicaset","text":"ReplicaSet\u7684\u76ee\u7684\u662f\u5728\u4efb\u4f55\u65f6\u5019\u7ef4\u62a4\u4e00\u7ec4\u7a33\u5b9a\u7684\u526f\u672cPod\u3002\u56e0\u6b64\uff0c\u5b83\u901a\u5e38\u7528\u4e8e\u4fdd\u8bc1\u6307\u5b9a\u6570\u91cf\u7684\u76f8\u540cPod\u7684\u53ef\u7528\u6027\u3002 \u6211\u4eec\u4e00\u822c\u4e0d\u9700\u8981\u76f4\u63a5\u64cd\u7eb5ReplicaSet\u5bf9\u8c61\uff1a\u4f7f\u7528Deployment\uff0c\u7136\u540e\u5728spec\u90e8\u5206\u4e2d\u5b9a\u4e49\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 \u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e replicaset.spec.replicas \u6765\u6307\u5b9a\u5e94\u540c\u65f6\u8fd0\u884c\u591a\u5c11\u4e2aPod\u3002 ReplicaSet\u5c06\u521b\u5efa/\u5220\u9664\u5176Pod\u4ee5\u5339\u914d\u6b64\u6570\u5b57\u3002 \u5982\u679c\u4e0d\u6307\u5b9a replicaset.spec.replicas \uff0c\u5219\u9ed8\u8ba4\u503c\u4e3a 1 \u3002","title":"ReplicaSet"},{"location":"k8s/cka_cn/foundamentals/memo/#statefulset","text":"StatefulSet \u7279\u70b9\uff08\u53c8\u79f0\u56fa\u5b9a\u6807\u8bc6\uff09\uff1a Pod \u7684\u540d\u79f0\u5728\u521b\u5efa\u540e\u4e0d\u53ef\u53d8\u3002 DNS \u4e3b\u673a\u540d\u5728\u521b\u5efa\u540e\u4e0d\u53ef\u53d8\u3002 \u6302\u8f7d\u7684\u5377\u5728\u521b\u5efa\u540e\u4e0d\u53ef\u53d8\u3002 StatefulSet \u7684\u56fa\u5b9a\u6807\u8bc6\u5728\u5931\u8d25\u3001\u6269\u5c55\u548c\u5176\u4ed6\u64cd\u4f5c\u540e\u4e0d\u4f1a\u6539\u53d8\u3002 StatefulSet \u7684\u547d\u540d\u7ea6\u5b9a\u4e3a\uff1a - \u3002 StatefulSet \u53ef\u4ee5\u81ea\u884c\u8fdb\u884c\u6269\u5c55\uff0c\u4f46\u662f Deployment \u9700\u8981\u4f9d\u9760 ReplicaSet \u8fdb\u884c\u6269\u5c55\u3002 \u5efa\u8bae\uff1a\u5148\u5c06 StatefulSet \u51cf\u5c11\u5230 0\uff0c\u800c\u4e0d\u662f\u76f4\u63a5\u5220\u9664\u5b83\u3002 headless Service \u548c governing Service\uff1a Headless Service \u662f\u4e00\u4e2a\u666e\u901a\u7684 Kubernetes Service \u5bf9\u8c61\uff0c\u5176 spec.clusterIP \u88ab\u8bbe\u7f6e\u4e3a None \u3002 \u5f53 StatefulSet \u7684 spec.ServiceName \u8bbe\u7f6e\u4e3a headless Service \u540d\u79f0\u65f6\uff0cStatefulSet \u73b0\u5728\u662f\u4e00\u4e2a governing Service\u3002 \u521b\u5efa StatefulSet \u7684\u4e00\u822c\u8fc7\u7a0b\uff1a \u521b\u5efa StorageClass\u3002 \u521b\u5efa Headless Service\u3002 \u57fa\u4e8e\u4e0a\u8ff0\u4e24\u4e2a\u521b\u5efa StatefulSet\u3002","title":"StatefulSet"},{"location":"k8s/cka_cn/foundamentals/memo/#daemonset","text":"DaemonSet\u4fdd\u8bc1\u6240\u6709\uff08\u6216\u90e8\u5206\uff09\u8282\u70b9\u8fd0\u884cPod\u7684\u526f\u672c\u3002\u968f\u7740\u8282\u70b9\u4ece\u96c6\u7fa4\u4e2d\u5220\u9664\uff0c\u8fd9\u4e9bPod\u5c06\u88ab\u5783\u573e\u56de\u6536\u3002 \u5220\u9664DaemonSet\u5c06\u6e05\u7406\u5b83\u521b\u5efa\u7684Pod\u3002 \u4e00\u4e9b\u5178\u578bDaemonSet\u7684\u7528\u9014\u5305\u62ec\uff1a \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u96c6\u7fa4\u5b58\u50a8\u5b88\u62a4\u7a0b\u5e8f\u3002 \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u65e5\u5fd7\u6536\u96c6\u5b88\u62a4\u7a0b\u5e8f\u3002 \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u8282\u70b9\u76d1\u89c6\u5b88\u62a4\u7a0b\u5e8f\u3002 \u5728\u7b80\u5355\u7684\u60c5\u51b5\u4e0b\uff0c\u6bcf\u79cd\u7c7b\u578b\u7684\u5b88\u62a4\u7a0b\u5e8f\u5c06\u4f7f\u7528\u8986\u76d6\u6240\u6709\u8282\u70b9\u7684\u4e00\u4e2aDaemonSet\u3002 \u66f4\u590d\u6742\u7684\u8bbe\u7f6e\u53ef\u80fd\u4f1a\u4e3a\u5355\u4e2a\u5b88\u62a4\u7a0b\u5e8f\u4f7f\u7528\u591a\u4e2aDaemonSet\uff0c\u4f46\u4f7f\u7528\u4e0d\u540c\u7684\u6807\u5fd7\u548c/\u6216\u4e0d\u540c\u7684\u5185\u5b58\u548cCPU\u8bf7\u6c42\u6765\u652f\u6301\u4e0d\u540c\u7684\u786c\u4ef6\u7c7b\u578b\u3002 DaemonSet\u63a7\u5236\u5668\u8c03\u548c\u8fc7\u7a0b\u540c\u65f6\u68c0\u67e5\u73b0\u6709\u8282\u70b9\u548c\u65b0\u521b\u5efa\u7684\u8282\u70b9\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cKubernetes\u8c03\u5ea6\u7a0b\u5e8f\u5ffd\u7565\u7531DamonSet\u521b\u5efa\u7684Pod\uff0c\u5e76\u5141\u8bb8\u5b83\u4eec\u5b58\u5728\u4e8e\u8282\u70b9\u4e0a\uff0c\u76f4\u5230\u5173\u95ed\u8282\u70b9\u672c\u8eab\u3002 \u5728\u9009\u62e9\u8282\u70b9\u4e0a\u8fd0\u884cPod\uff1a \u5982\u679c\u60a8\u6307\u5b9a daemonset.spec.template.spec.nodeSelector \uff0c\u90a3\u4e48DaemonSet\u63a7\u5236\u5668\u5c06\u5728\u4e0e\u8be5\u8282\u70b9\u9009\u62e9\u5668\u5339\u914d\u7684\u8282\u70b9\u4e0a\u521b\u5efaPod\u3002 \u5982\u679c\u60a8\u6307\u5b9a daemonset.spec.template.spec.affinity \uff0c\u90a3\u4e48DaemonSet\u63a7\u5236\u5668\u5c06\u5728\u4e0e\u8be5\u8282\u70b9\u4eb2\u548c\u529b\u5339\u914d\u7684\u8282\u70b9\u4e0a\u521b\u5efaPod\u3002 \u5982\u679c\u4e24\u8005\u90fd\u4e0d\u6307\u5b9a\uff0c\u5219DaemonSet\u63a7\u5236\u5668\u5c06\u5728\u6240\u6709\u8282\u70b9\u4e0a\u521b\u5efaPod\u3002 \u5728 kubectl explain daemonset.spec \u4e2d\u6ca1\u6709 replicas \u5b57\u6bb5\u4e0e kubectl explain deployment.spec.replicas \u76f8\u5bf9\u5e94\u3002\u5f53\u521b\u5efa\u4e00\u4e2aDaemonSet\u65f6\uff0c\u6bcf\u4e2a\u8282\u70b9\u5c06\u8fd0\u884c*\u4e00\u4e2a* DaemonSet Pod\u3002 \u5bf9\u4e8e\u670d\u52a1\uff0c\u901a\u5e38\u662f\u65e0\u72b6\u6001\u7684\uff0c\u4e00\u822c\u4e0d\u5173\u5fc3\u8282\u70b9\u5728\u54ea\u91cc\u8fd0\u884c\uff0c\u66f4\u5173\u5fc3Pod\u526f\u672c\u7684\u6570\u91cf\uff0c\u5e76\u4e14\u6211\u4eec\u53ef\u4ee5\u5c06\u8fd9\u4e9b\u526f\u672c/replicas\u7f29\u653e\u3002\u5728\u8fd9\u91cc\uff0c\u6eda\u52a8\u66f4\u65b0\u4e5f\u5c06\u662f\u4e00\u4e2a\u4f18\u70b9\u3002 \u5f53Pod\u7684\u4e00\u4e2a\u526f\u672c\u5fc5\u987b\u5728\u67d0\u4e2a\u6307\u5b9a\u8282\u70b9\u4e0a\u8fd0\u884c\u65f6\uff0c\u6211\u4eec\u5c06\u4f7f\u7528 DaemonSet \u3002\u6211\u4eec\u7684\u5b88\u62a4\u8fdb\u7a0bPod\u8fd8\u9700\u8981\u5728\u6211\u4eec\u7684\u5176\u4ed6Pod\u4e4b\u524d\u542f\u52a8\u3002 DaemonSet\u662f\u7528\u4e8e\u540e\u53f0\u670d\u52a1\u7684\u7b80\u5355\u53ef\u6269\u5c55\u6027\u7b56\u7565\u3002\u5f53\u66f4\u591a\u7684\u5408\u9002\u7684\u8282\u70b9\u6dfb\u52a0\u5230\u96c6\u7fa4\u65f6\uff0c\u540e\u53f0\u670d\u52a1\u5c06\u6269\u5c55\u3002\u5f53\u8282\u70b9\u88ab\u5220\u9664\u65f6\uff0c\u5b83\u5c06\u81ea\u52a8\u7f29\u5c0f\u3002","title":"DaemonSet"},{"location":"k8s/cka_cn/foundamentals/memo/#job","text":"","title":"Job"},{"location":"k8s/cka_cn/foundamentals/memo/#cronjob","text":"","title":"CronJob"},{"location":"k8s/cka_cn/foundamentals/memo/#_12","text":"","title":"\u670d\u52a1\u8d44\u6e90"},{"location":"k8s/cka_cn/foundamentals/memo/#service","text":"Service\u662f\u8f6f\u4ef6\u670d\u52a1\uff08\u4f8b\u5982mysql\uff09\u7684\u547d\u540d\u62bd\u8c61\uff0c\u7531\u4ee3\u7406\u76d1\u542c\u7684\u672c\u5730\u7aef\u53e3\uff08\u4f8b\u59823306\uff09\u548c\u786e\u5b9a\u54ea\u4e9bPod\u5c06\u56de\u7b54\u901a\u8fc7\u4ee3\u7406\u53d1\u9001\u7684\u8bf7\u6c42\u7684\u9009\u62e9\u5668\u7ec4\u6210\u3002 \u4e00\u4e2aService\u7684\u76ee\u6807Pod\u96c6\u5408\u901a\u5e38\u7531\u4e00\u4e2a\u9009\u62e9\u5668\uff08\u6807\u7b7e\u9009\u62e9\u5668\uff09\u6765\u786e\u5b9a\u3002 Service\u8d44\u6e90\u7684\u7c7b\u578b\u5305\u62ec\uff1a ClusterIP Service\uff08\u9ed8\u8ba4\uff09\uff1a\u53ef\u9760\u7684IP\u3001DNS\u548c\u7aef\u53e3\u3002\u4ec5\u9650\u5185\u90e8\u8bbf\u95ee\u3002 NodePort Service\uff1a\u5411\u5916\u90e8\u63d0\u4f9b\u8bbf\u95ee\u3002 LoadBalancer\uff1a\u57fa\u4e8eNodePort\uff0c\u5e76\u4e0e\u4e91\u4f9b\u5e94\u5546\u63d0\u4f9b\u7684\u8d1f\u8f7d\u5e73\u8861\u96c6\u6210\uff08\u4f8b\u5982AWS\u3001GCP\u7b49\uff09\u3002 ExternalName\uff1a\u8bbf\u95ee\u5c06\u88ab\u8f6c\u53d1\u5230\u5916\u90e8\u670d\u52a1\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u521b\u5efa\u7b80\u5355Service\u7684yaml\u6587\u4ef6\uff1a apiVersion : v1 kind : Service metadata : name : nginx-service labels : tier : application spec : ports : - port : 80 protocol : TCP targetPort : 8080 selector : run : nginx type : NodePort \u4e0b\u9762\u662f\u4e00\u4e2aService\u7684\u4f8b\u5b50\uff1a IP 10.96.17.77 \u662f\u8be5\u670d\u52a1\u7684 ClusterIP(VIP)\u3002 \u7aef\u53e3 80/TCP \u662f Pod \u5728\u96c6\u7fa4\u5185\u76d1\u542c\u7684\u7aef\u53e3\u3002 TargetPort 8080/TCP \u662f\u5bb9\u5668\u5185\u670d\u52a1\u5e94\u8be5\u5b9a\u5411\u6d41\u91cf\u5230\u8fbe\u7684\u7aef\u53e3\u3002 NodePort 31893/TCP \u662f\u53ef\u4ee5\u4ece\u5916\u90e8\u8bbf\u95ee\u7684\u7aef\u53e3\u3002\u9ed8\u8ba4\u8303\u56f4\u662f 30000~32767 \u3002\u8be5\u7aef\u53e3\u4f1a\u5728\u6574\u4e2a\u96c6\u7fa4\u7684\u6240\u6709\u8282\u70b9\u4e0a\u66b4\u9732\u3002 Endpoints \u663e\u793a\u4e86\u5339\u914d\u670d\u52a1\u6807\u7b7e\u7684 Pod \u5217\u8868\u3002 Name : nginx-deployment Namespace : jh-namespace Labels : tier=application Annotations : Selector : run=nginx Type : NodePort IP Family Policy : SingleStack IP Families : IPv4 IP : 10.96.17.77 IPs : 10.96.17.77 Port : 80/TCP TargetPort : 8080/TCP NodePort : 31893/TCP Endpoints : 10.244.1.177:8080,10.244.1.178:8080,10.244.1.179:8080 + 7 more... Session Affinity : None External Traffic Policy : Cluster Events : \u5728 Kubernetes \u96c6\u7fa4\u4e2d\uff0c\u57fa\u4e8eDeployment coredns \u7684Service kube-dns \u63d0\u4f9b\u4e86\u96c6\u7fa4 DNS \u670d\u52a1\u3002 \u670d\u52a1\u6ce8\u518c\uff1a Kubernetes \u4f7f\u7528\u96c6\u7fa4 DNS \u4f5c\u4e3a\u670d\u52a1\u6ce8\u518c\u3002 \u6ce8\u518c\u662f\u57fa\u4e8e Service \u800c\u975e Pod \u7684\u3002 \u96c6\u7fa4 DNS\uff08CoreDNS\uff09\u4e3b\u52a8\u76d1\u89c6\u548c\u53d1\u73b0\u65b0\u670d\u52a1\u3002 Service \u540d\u79f0\u3001IP\u3001\u7aef\u53e3\u5c06\u88ab\u6ce8\u518c\u3002 Service \u6ce8\u518c\u7684\u8fc7\u7a0b\u5982\u4e0b\uff1a \u5c06\u65b0\u7684 Service POST \u5230 API Server\u3002 \u4e3a\u65b0\u7684 Service \u5206\u914d ClusterIP\u3002 \u5c06\u65b0\u7684 Service \u914d\u7f6e\u4fe1\u606f\u4fdd\u5b58\u5230 etcd \u4e2d\u3002 \u521b\u5efa\u4e0e\u65b0 Service \u5173\u8054\u7684\u5e26\u6709\u76f8\u5173 Pod IP \u7684 endpoints\u3002 \u901a\u8fc7 ClusterDNS \u63a2\u7d22\u65b0\u7684 Service\u3002 \u521b\u5efa DNS \u4fe1\u606f\u3002 kube-proxy \u83b7\u53d6 Service \u914d\u7f6e\u4fe1\u606f\u3002 \u521b\u5efa IPSV \u89c4\u5219\u3002 Service \u53d1\u73b0\u7684\u8fc7\u7a0b\u3002 \u8bf7\u6c42\u4e00\u4e2a Service \u540d\u79f0\u7684 DNS \u540d\u79f0\u89e3\u6790\u3002 \u6536\u5230 ClusterIP\u3002 \u8bbf\u95ee ClusterIP\u3002 \u6ca1\u6709\u8def\u7531\u5668\u3002\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230 Pod \u7684\u9ed8\u8ba4\u7f51\u5173\u3002 \u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u8282\u70b9\u3002 \u6ca1\u6709\u8def\u7531\u5668\u3002\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u8282\u70b9\u7684\u9ed8\u8ba4\u7f51\u5173\u3002 \u8282\u70b9\u5185\u6838\u7ee7\u7eed\u5904\u7406\u8bf7\u6c42\u3002 \u4f7f\u7528 IPSV \u89c4\u5219\u6355\u83b7\u8bf7\u6c42\u3002 \u5c06\u76ee\u6807 Pod \u7684 IP \u653e\u5165\u8bf7\u6c42\u7684\u76ee\u6807 IP \u4e2d\u3002 \u8bf7\u6c42\u5230\u8fbe\u76ee\u6807 Pod\u3002 FQDN\u683c\u5f0f\u4e3a\uff1a ..svc.cluster.local \u3002\u6211\u4eec\u79f0 \u4e3a\u975e\u9650\u5b9a\u540d\u79f0\u6216\u7b80\u77ed\u540d\u79f0\u3002 \u547d\u540d\u7a7a\u95f4\u53ef\u4ee5\u9694\u79bb\u96c6\u7fa4\u7684\u5730\u5740\u7a7a\u95f4\u3002\u540c\u65f6\uff0c\u5b83\u8fd8\u53ef\u4ee5\u7528\u4e8e\u5b9e\u73b0\u8bbf\u95ee\u63a7\u5236\u548c\u8d44\u6e90\u914d\u989d\u3002 \u83b7\u53d6Pod\u4e2d\u7684DNS\u914d\u7f6e\u3002 nameserver\u7684IP\u4e0ekube-dns\u670d\u52a1\u7684ClusterIP\u76f8\u540c\uff0c\u8fd9\u662f\u7528\u4e8eDNS\u8bf7\u6c42\u6216\u670d\u52a1\u53d1\u73b0\u8bf7\u6c42\u7684\u4f17\u6240\u5468\u77e5\u7684IP\u3002 $ kubectl get service kube-dns -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT ( S ) AGE kube-dns ClusterIP 10 .96.0.10 53 /UDP,53/TCP,9153/TCP 7d7h $ kubectl exec -it nginx-5f5496dc9-bv5dx -- /bin/bash root@nginx-5f5496dc9-bv5dx:/# cat /etc/resolv.conf search jh-namespace.svc.cluster.local svc.cluster.local cluster.local nameserver 10 .96.0.10 options ndots:5 \u8bfb\u53d6 kube-dns \u4fe1\u606f\uff1a $ kubectl describe service kube-dns -n kube-system Name: kube-dns Namespace: kube-system Labels: k8s-app = kube-dns kubernetes.io/cluster-service = true kubernetes.io/name = CoreDNS Annotations: prometheus.io/port: 9153 prometheus.io/scrape: true Selector: k8s-app = kube-dns Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: 10 .96.0.10 IPs: 10 .96.0.10 Port: dns 53 /UDP TargetPort: 53 /UDP Endpoints: 10 .244.0.2:53,10.244.0.3:53 Port: dns-tcp 53 /TCP TargetPort: 53 /TCP Endpoints: 10 .244.0.2:53,10.244.0.3:53 Port: metrics 9153 /TCP TargetPort: 9153 /TCP Endpoints: 10 .244.0.2:9153,10.244.0.3:9153 Session Affinity: None Events: ","title":"Service"},{"location":"k8s/cka_cn/foundamentals/memo/#endpoints","text":"Endpoints\u662f\u4e00\u7ec4\u5b9e\u73b0\u5b9e\u9645\u670d\u52a1\u7684\u7aef\u70b9\u96c6\u5408\u3002 \u5f53\u521b\u5efa\u670d\u52a1\u65f6\uff0c\u5b83\u4f1a\u4e0e\u4e00\u4e2aEndpoint\u5bf9\u8c61\u76f8\u5173\u8054\uff0c\u53ef\u4ee5\u4f7f\u7528\u547d\u4ee4 kubectl get endpoints \u83b7\u53d6\u3002 \u5339\u914d\u670d\u52a1\u6807\u7b7e\u7684Pod\u5217\u8868\u7ef4\u62a4\u4e3aEndpoint\u5bf9\u8c61\uff0c\u6dfb\u52a0\u65b0\u7684\u5339\u914dPod\u5e76\u5220\u9664\u4e0d\u5339\u914d\u7684Pod\u3002","title":"Endpoints"},{"location":"k8s/cka_cn/foundamentals/memo/#_13","text":"","title":"\u914d\u7f6e\u548c\u5b58\u50a8\u8d44\u6e90"},{"location":"k8s/cka_cn/foundamentals/memo/#_14","text":"","title":"\u5377"},{"location":"k8s/cka_cn/foundamentals/memo/#emptydir","text":"emptyDir \u5377\u662f\u5728Pod\u5206\u914d\u5230\u8282\u70b9\u65f6\u9996\u5148\u521b\u5efa\u7684\uff0c\u5e76\u4e14\u53ea\u8981\u8be5Pod\u5728\u8be5\u8282\u70b9\u4e0a\u8fd0\u884c\uff0c\u5b83\u5c31\u4f1a\u5b58\u5728\u3002 emptyDir \u5377\u6700\u521d\u4e3a\u7a7a\u3002 Pod\u4e2d\u7684\u6240\u6709\u5bb9\u5668\u90fd\u53ef\u4ee5\u8bfb\u53d6\u548c\u5199\u5165 emptyDir \u5377\u4e2d\u7684\u76f8\u540c\u6587\u4ef6\uff0c\u5c3d\u7ba1\u8be5\u5377\u53ef\u4ee5\u5728\u6bcf\u4e2a\u5bb9\u5668\u4e2d\u4ee5\u76f8\u540c\u6216\u4e0d\u540c\u7684\u8def\u5f84\u6302\u8f7d\u3002 \u5f53\u7531\u4e8e\u4efb\u4f55\u539f\u56e0\u4ece\u8282\u70b9\u4e2d\u5220\u9664Pod\u65f6\uff0c emptyDir \u4e2d\u7684\u6570\u636e\u5c06\u6c38\u4e45\u5220\u9664\u3002 \u5bb9\u5668\u5d29\u6e83\u4e0d\u4f1a\u5c06Pod\u4ece\u8282\u70b9\u4e2d\u5220\u9664\u3002 emptyDir \u5377\u4e2d\u7684\u6570\u636e\u53ef\u4ee5\u5728\u5bb9\u5668\u5d29\u6e83\u65f6\u5b89\u5168\u4fdd\u7559\u3002 \u7528\u9014\uff1a \u4e34\u65f6\u7a7a\u95f4\uff0c\u4f8b\u5982\u57fa\u4e8e\u78c1\u76d8\u7684\u5f52\u5e76\u6392\u5e8f \u4e3a\u4e86\u4ece\u5d29\u6e83\u4e2d\u6062\u590d\u800c\u8fdb\u884c\u7684\u957f\u65f6\u95f4\u8ba1\u7b97\u7684\u68c0\u67e5\u70b9 \u4fdd\u5b58\u5185\u5bb9\u7ba1\u7406\u5668\u5bb9\u5668\u63d0\u53d6\u7684\u6587\u4ef6\uff0c\u540c\u65f6Web\u670d\u52a1\u5668\u5bb9\u5668\u63d0\u4f9b\u6570\u636e","title":"emptyDir"},{"location":"k8s/cka_cn/foundamentals/memo/#hostpath","text":"hostPath \u5377\u5c06\u4e3b\u673a\u8282\u70b9\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u6302\u8f7d\u5230 Pod \u4e2d\u3002\u8fd9\u4e0d\u662f\u5927\u591a\u6570 Pod \u90fd\u9700\u8981\u7684\uff0c\u4f46\u5bf9\u4e8e\u67d0\u4e9b\u5e94\u7528\u7a0b\u5e8f\u6765\u8bf4\uff0c\u5b83\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5f3a\u5927\u7684\u9003\u751f\u53e3\u3002 hostPath \u5377\u5b58\u5728\u8bb8\u591a\u5b89\u5168\u98ce\u9669\uff0c\u56e0\u6b64\u5728\u53ef\u80fd\u7684\u60c5\u51b5\u4e0b\u6700\u597d\u907f\u514d\u4f7f\u7528 HostPath\u3002\u5f53\u5fc5\u987b\u4f7f\u7528 HostPath \u5377\u65f6\uff0c\u5e94\u5c06\u5176\u8303\u56f4\u9650\u5b9a\u4e3a\u4ec5\u6240\u9700\u7684\u6587\u4ef6\u6216\u76ee\u5f55\uff0c\u5e76\u4ee5\u53ea\u8bfb\u65b9\u5f0f\u6302\u8f7d\u3002 \u5982\u679c\u901a\u8fc7 AdmissionPolicy \u9650\u5236 HostPath \u8bbf\u95ee\u7279\u5b9a\u76ee\u5f55\uff0c\u5219\u5fc5\u987b\u8981\u6c42 volumeMounts \u4f7f\u7528 readOnly \u6302\u8f7d\uff0c\u4ee5\u4f7f\u7b56\u7565\u751f\u6548\u3002 \u7528\u9014\uff1a \u4e0e DaemonSet \u4e00\u8d77\u8fd0\u884c\uff0c\u4f8b\u5982\uff0cEFK Fluentd \u6302\u8f7d\u672c\u5730\u4e3b\u673a\u7684\u65e5\u5fd7\u76ee\u5f55\u4ee5\u6536\u96c6\u4e3b\u673a\u65e5\u5fd7\u4fe1\u606f\u3002 \u901a\u8fc7\u4f7f\u7528 hostPath \u5377\u5728\u7279\u5b9a\u8282\u70b9\u4e0a\u8fd0\u884c\uff0c\u53ef\u4ee5\u83b7\u5f97\u9ad8\u6027\u80fd\u7684\u78c1\u76d8 I/O\u3002 \u8fd0\u884c\u9700\u8981\u8bbf\u95ee Docker \u5185\u90e8\u7684\u5bb9\u5668\uff1b\u4f7f\u7528 /var/lib/docker \u7684 hostPath\u3002 \u5728\u5bb9\u5668\u4e2d\u8fd0\u884c cAdvisor\uff1b\u4f7f\u7528 /sys \u7684 hostPath\u3002 \u5141\u8bb8 Pod \u6307\u5b9a\u7ed9\u5b9a\u7684 hostPath \u662f\u5426\u5e94\u8be5\u5728 Pod \u8fd0\u884c\u4e4b\u524d\u5b58\u5728\uff0c\u662f\u5426\u5e94\u8be5\u521b\u5efa\u5b83\u4ee5\u53ca\u5b83\u5e94\u8be5\u5b58\u5728\u7684\u5185\u5bb9\u3002","title":"hostPath"},{"location":"k8s/cka_cn/foundamentals/memo/#storage-class","text":"StorageClass \u90e8\u7f72\u548c\u5b9e\u73b0\u7684\u6b65\u9aa4\u5982\u4e0b\uff1a \u521b\u5efa Kubernetes \u96c6\u7fa4\u548c\u540e\u7aef\u5b58\u50a8\u3002 \u786e\u4fdd Kubernetes \u4e2d\u7684 provisioner/plugin \u53ef\u7528\u3002 \u521b\u5efa\u4e00\u4e2a StorageClass \u5bf9\u8c61\u5e76\u5c06\u5176\u94fe\u63a5\u5230\u540e\u7aef\u5b58\u50a8\u3002StorageClass \u5c06\u81ea\u52a8\u521b\u5efa\u76f8\u5173\u7684 PV\u3002 \u521b\u5efa\u4e00\u4e2a PVC \u5bf9\u8c61\u5e76\u5c06\u5176\u94fe\u63a5\u5230\u6211\u4eec\u521b\u5efa\u7684 StorageClass\u3002 \u90e8\u7f72\u4e00\u4e2a Pod \u5e76\u4f7f\u7528 PVC \u5377\u3002","title":"Storage Class"},{"location":"k8s/cka_cn/foundamentals/memo/#pv","text":"PV\u56de\u6536\u7b56\u7565\uff1a \u4fdd\u7559 (Retain) \u5220\u9664 (Delete) \u56de\u6536 (Recycle) PV in-tree\u7c7b\u578b\uff1a hostPath local NFS CSI","title":"PV"},{"location":"k8s/cka_cn/foundamentals/memo/#access-modes","text":"Access Modes\uff08\u8bbf\u95ee\u6a21\u5f0f\uff09\u4e2d\uff0c spec.accessModes \u5b9a\u4e49\u4e86 PV \u7684\u6302\u8f7d\u9009\u9879\uff1a ReadWriteOnce(RWO)\uff1a\u4e00\u4e2a PV \u53ea\u80fd\u88ab\u4e00\u4e2a\u8bfb\u5199\u6a21\u5f0f\u7684 PVC \u6302\u8f7d\uff0c\u7c7b\u4f3c\u4e8e\u5757\u8bbe\u5907\u3002 ReadWriteMany(RWM)\uff1a\u4e00\u4e2a PV \u53ef\u4ee5\u88ab\u591a\u4e2a\u8bfb\u5199\u6a21\u5f0f\u7684 PVC \u6302\u8f7d\uff0c\u4f8b\u5982 NFS\u3002 ReadOnlyMany(ROM)\uff1a\u4e00\u4e2a PV \u53ef\u4ee5\u88ab\u591a\u4e2a\u53ea\u8bfb\u6a21\u5f0f\u7684 PVC \u6302\u8f7d\u3002 ReadWriteOncePod(RWOP)\uff1a\u53ea\u652f\u6301 CSI \u7c7b\u578b\u7684 PV\uff0c\u53ea\u80fd\u88ab\u5355\u4e2a Pod \u6302\u8f7d\u3002 \u4e00\u4e2a PV \u53ea\u80fd\u8bbe\u7f6e\u4e00\u79cd\u9009\u9879\u3002Pod \u6302\u8f7d PVC\uff0c\u800c\u4e0d\u662f PV\u3002","title":"Access Modes"},{"location":"k8s/cka_cn/foundamentals/namespace/","text":"CKA\u81ea\u5b66\u7b14\u8bb011:Namespace \u00b6 \u6f14\u793a\u573a\u666f \u00b6 \u83b7\u53d6namespace\u5217\u8868 \u521b\u5efa\u65b0\u7684namespace \u7ed9namespace\u8bbe\u5b9a\u6807\u7b7e \u5220\u9664\u4e00\u4e2anamespace \u6f14\u793a \u00b6 \u83b7\u53d6\u5f53\u524dnamespace\u5217\u8868\u3002 kubectl get namespace \u83b7\u53d6\u5f53\u524dnamespace\u5217\u8868\u548c\u5bf9\u5e94\u6807\u7b7e\u4fe1\u606f\u3002 kubectl get ns --show-labels \u521b\u5efa\u4e00\u4e2anamespace cka \u3002 kubectl create namespace cka \u7ed9\u65b0\u521b\u5efa\u7684namespace cka \u8bbe\u5b9a\u6807\u7b7e\u3002 kubectl label ns cka cka = true \u5728namespace cka \u4e0a\u521b\u5efa Nginx Deployment\u3002 kubectl create deploy nginx --image = nginx --namespace cka \u5728namespace cka \u4e0a\u68c0\u67e5\u6b63\u5728\u8fd0\u884c\u7684deployment\u548cpod\u3002 kubectl get deploy,pod -n cka \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx 1/1 1 1 2m14s NAME READY STATUS RESTARTS AGE pod/nginx-85b98978db-bmkhf 1/1 Running 0 2m14s \u5220\u9664namespace cka \uff0c\u5219\u6240\u6709\u8fd0\u884c\u5728\u8fd9\u4e2anamespace\u4e0a\u7684\u8d44\u6e90\u90fd\u4f1a\u88ab\u5220\u9664\u3002 kubectl delete ns cka \u5982\u679c\u5728\u5220\u9664\u67d0\u4e2anamespace\u65f6\u9047\u5230\u72b6\u6001\u4e00\u76f4\u662f Terminating \uff0c\u5219\u53ef\u4ee5\u5c1d\u8bd5\u7528\u4e0b\u9762\u7684\u65b9\u6cd5\u89e3\u51b3\u3002 kubectl get namespace $NAMESPACE -o json | sed -e 's/\"kubernetes\"//' | kubectl replace --raw \"/api/v1/namespaces $NAMESPACE /finalize\" -f -","title":"Namespace"},{"location":"k8s/cka_cn/foundamentals/namespace/#cka11namespace","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb011:Namespace"},{"location":"k8s/cka_cn/foundamentals/namespace/#_1","text":"\u83b7\u53d6namespace\u5217\u8868 \u521b\u5efa\u65b0\u7684namespace \u7ed9namespace\u8bbe\u5b9a\u6807\u7b7e \u5220\u9664\u4e00\u4e2anamespace","title":"\u6f14\u793a\u573a\u666f"},{"location":"k8s/cka_cn/foundamentals/namespace/#_2","text":"\u83b7\u53d6\u5f53\u524dnamespace\u5217\u8868\u3002 kubectl get namespace \u83b7\u53d6\u5f53\u524dnamespace\u5217\u8868\u548c\u5bf9\u5e94\u6807\u7b7e\u4fe1\u606f\u3002 kubectl get ns --show-labels \u521b\u5efa\u4e00\u4e2anamespace cka \u3002 kubectl create namespace cka \u7ed9\u65b0\u521b\u5efa\u7684namespace cka \u8bbe\u5b9a\u6807\u7b7e\u3002 kubectl label ns cka cka = true \u5728namespace cka \u4e0a\u521b\u5efa Nginx Deployment\u3002 kubectl create deploy nginx --image = nginx --namespace cka \u5728namespace cka \u4e0a\u68c0\u67e5\u6b63\u5728\u8fd0\u884c\u7684deployment\u548cpod\u3002 kubectl get deploy,pod -n cka \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx 1/1 1 1 2m14s NAME READY STATUS RESTARTS AGE pod/nginx-85b98978db-bmkhf 1/1 Running 0 2m14s \u5220\u9664namespace cka \uff0c\u5219\u6240\u6709\u8fd0\u884c\u5728\u8fd9\u4e2anamespace\u4e0a\u7684\u8d44\u6e90\u90fd\u4f1a\u88ab\u5220\u9664\u3002 kubectl delete ns cka \u5982\u679c\u5728\u5220\u9664\u67d0\u4e2anamespace\u65f6\u9047\u5230\u72b6\u6001\u4e00\u76f4\u662f Terminating \uff0c\u5219\u53ef\u4ee5\u5c1d\u8bd5\u7528\u4e0b\u9762\u7684\u65b9\u6cd5\u89e3\u51b3\u3002 kubectl get namespace $NAMESPACE -o json | sed -e 's/\"kubernetes\"//' | kubectl replace --raw \"/api/v1/namespaces $NAMESPACE /finalize\" -f -","title":"\u6f14\u793a"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/","text":"CKA\u81ea\u5b66\u7b14\u8bb023:Network Policy \u00b6 \u7528Calico\u66ff\u6362Flannel \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u5378\u8f7dFlannel \u5b89\u88c5Calico \u6f14\u793a\uff1a \u5982\u679c\u5728\u5b89\u88c5\u8fc7\u7a0b\u4e2d\u5df2\u7ecf\u5b89\u88c5\u4e86 Calico\uff0c\u5219\u53ef\u4ee5\u5ffd\u7565\u8fd9\u90e8\u5206\u5185\u5bb9\u3002 \u5378\u8f7dFlannel kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/v0.18.1/Documentation/kube-flannel.yml \u6216\u8005 kubectl delete -f kube-flannel.yml \u8f93\u51fa\uff1a Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy \"psp.flannel.unprivileged\" deleted clusterrole.rbac.authorization.k8s.io \"flannel\" deleted clusterrolebinding.rbac.authorization.k8s.io \"flannel\" deleted serviceaccount \"flannel\" deleted configmap \"kube-flannel-cfg\" deleted daemonset.apps \"kube-flannel-ds\" deleted \u5728\u6240\u6709\u8282\u70b9\u4e0a\u6e05\u9664iptables\u8bbe\u7f6e\u3002 rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u91cd\u65b0\u767b\u5f55\u4e3b\u673a\u8282\u70b9\uff0c\u4f8b\u5982 cka001 \uff0c\u5b89\u88c5Calico\uff0c curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Output: configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created \u9a8c\u8bc1Calico\u5b89\u88c5\u72b6\u6001\uff0c\u786e\u4fdd\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u90fd\u6b63\u5e38\u8fd0\u884c\u3002 kubectl get pod -n kube-system | grep calico \u8f93\u51fa\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE calico-kube-controllers-7bc6547ffb-tjfcg 1/1 Running 0 30m calico-node-7x8jm 1/1 Running 0 30m calico-node-cwxj5 1/1 Running 0 30m calico-node-rq978 1/1 Running 0 30m \u5982\u679c\u9047\u5230\u4efb\u4f55\u9519\u8bef\uff0c\u9996\u5148\u68c0\u67e5\u5bb9\u5668container\u65e5\u5fd7\u3002 # Get Container ID crictl ps # Get log info crictl logs \u7531\u4e8e\u6211\u4eec\u5c06 CNI \u4ece Flannel \u66f4\u6539\u4e3a Calico\uff0c\u6211\u4eec\u9700\u8981\u5220\u9664\u6240\u6709 Pod\uff0c\u6240\u6709 Pod \u90fd\u5c06\u81ea\u52a8\u91cd\u65b0\u521b\u5efa\u3002 kubectl delete pod -A --all \u67e5\u8be2\u6240\u6709pod\u90fd\u72b6\u6001\uff0c\u786e\u4fdd\u4ed6\u4eec\u90fd\u6b63\u5e38\u8fd0\u884c\u3002 kubectl get pod -A \u5165\u7ad9\u89c4\u5219\uff08Inbound Rules\uff09 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u7528\u4e8e\u6d4b\u8bd5\u7684\u5de5\u4f5c\u8d1f\u8f7d\u3002 \u7981\u6b62\u6240\u6709\u5165\u7ad9\u6d41\u91cf\u3002 \u5141\u8bb8\u7279\u5b9a\u7684\u5165\u7ad9\u6d41\u91cf\u3002 \u9a8c\u8bc1NetworkPolicy\u3002 \u521b\u5efa\u6d4b\u8bd5\u5de5\u4f5c\u8d1f\u8f7d \u00b6 \u521b\u5efa\u4e09\u4e2a Deployment\uff0c\u540d\u79f0\u4e3a pod-netpol-1 \u3001 pod-netpol-2 \u548c pod-netpol-3 \uff0c\u5b83\u4eec\u90fd\u57fa\u4e8e\u955c\u50cf busybox \u3002 kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-1 name: pod-netpol-1 spec: replicas: 1 selector: matchLabels: app: pod-netpol-1 template: metadata: labels: app: pod-netpol-1 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-2 name: pod-netpol-2 spec: replicas: 1 selector: matchLabels: app: pod-netpol-2 template: metadata: labels: app: pod-netpol-2 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-3 name: pod-netpol-3 spec: replicas: 1 selector: matchLabels: app: pod-netpol-3 template: metadata: labels: app: pod-netpol-3 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] EOF \u68c0\u67e5pod\u7684IP\u5730\u5740\uff1a kubectl get pod -owide \u8f93\u51fa\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-netpol-1-6494f6bf8b-n58r9 1/1 Running 0 29s 10.244.102.30 cka003 pod-netpol-2-77478d77ff-l6rzm 1/1 Running 0 29s 10.244.112.30 cka002 pod-netpol-3-68977dcb48-ql5s6 1/1 Running 0 29s 10.244.102.31 cka003 \u767b\u5f55\u8fdb\u5165pod pod-netpol-1 \u3002 kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh \u6267\u884c\u547d\u4ee4 ping \uff0c\u786e\u4fdd pod-netpol-2 \u548c pod-netpol-3 \u53ef\u4e92\u76f8\u8bbf\u95ee\u3002 / # ping 10.244.112.30 3 packets transmitted, 3 packets received, 0 % packet loss / # ping 10.244.102.31 3 packets transmitted, 3 packets received, 0 % packet loss \u7981\u6b62\u6240\u6709\u5165\u7ad9\u6d41\u91cf \u00b6 \u521b\u5efa\u7b56\u7565\uff0c\u7981\u6b62\u6240\u6709\u5165\u7ad9\u6d41\u91cf\u3002 kubectl apply -f - << EOF apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-ingress spec: podSelector: {} policyTypes: - Ingress EOF \u518d\u6b21\u767b\u5f55\u8fdb\u5165pod pod-netpol-1 \u3002 kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh Execute command ping that pod-netpol-2 and pod-netpol-3 are both unreachable as expected. \u6267\u884c\u547d\u4ee4 ping \uff0c\u548c\u6211\u4eec\u9884\u671f\u4e00\u6837\uff0c pod-netpol-2 \u548c pod-netpol-3 \u6b64\u65f6\u4e92\u76f8\u65e0\u6cd5\u8bbf\u95ee\u3002 / # ping 10.244.112.30 3 packets transmitted, 0 packets received, 100 % packet loss / # ping 10.244.102.31 3 packets transmitted, 0 packets received, 100 % packet loss \u5141\u8bb8\u7279\u5b9a\u7684\u5165\u7ad9\u6d41\u91cf \u00b6 \u521b\u5efa NetworkPolicy\uff0c\u5141\u8bb8\u6765\u81ea pod-netpol-1 \u5230 pod-netpol-2 \u7684\u5165\u7ad9\u6d41\u91cf\u3002 kubectl apply -f - <:80 \u5931\u8d25 \u8fd0\u884c curl :80 \u6210\u529f kubectl run centos --image = centos -n my-ns-1 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-1 -- bash \u5728namespace my-ns-2 \u4e2d\u521b\u5efa\u4e00\u4e2a\u4e34\u65f6 Pod\uff0c\u7136\u540e\u8fde\u63a5\u5230\u8be5 Pod \u5e76\u9a8c\u8bc1\u8bbf\u95ee\u3002 \u547d\u4ee4 curl :80 \u5931\u8d25 \u547d\u4ee4 curl :80 \u5931\u8d25\u3002 kubectl run centos --image = centos -n my-ns-2 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-2 -- bash \u4fee\u6539 my-networkpolicy-1 \uff0c \u628a ingress.from.namespaceSelector.matchLabels \u7684\u503c\u6539\u4e3a my-ns-2 \u3002 \u767b\u5f55\u8fdb\u5165namespace my-ns-2 \u4e0a\u7684\u4e34\u65f6pod\uff0c\u9a8c\u8bc1\u8bbf\u95ee\u3002 \u547d\u4ee4 curl :80 \u5931\u8d25 \u547d\u4ee4 curl :80 \u6210\u529f kubectl exec -it mycentos -n my-ns-2 -- bash \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete namespace my-ns-1 kubectl delete namespace my-ns-2","title":"Network Policy"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/#cka23network-policy","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb023:Network Policy"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/#calicoflannel","text":"\u6f14\u793a\u573a\u666f\uff1a \u5378\u8f7dFlannel \u5b89\u88c5Calico \u6f14\u793a\uff1a \u5982\u679c\u5728\u5b89\u88c5\u8fc7\u7a0b\u4e2d\u5df2\u7ecf\u5b89\u88c5\u4e86 Calico\uff0c\u5219\u53ef\u4ee5\u5ffd\u7565\u8fd9\u90e8\u5206\u5185\u5bb9\u3002 \u5378\u8f7dFlannel kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/v0.18.1/Documentation/kube-flannel.yml \u6216\u8005 kubectl delete -f kube-flannel.yml \u8f93\u51fa\uff1a Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy \"psp.flannel.unprivileged\" deleted clusterrole.rbac.authorization.k8s.io \"flannel\" deleted clusterrolebinding.rbac.authorization.k8s.io \"flannel\" deleted serviceaccount \"flannel\" deleted configmap \"kube-flannel-cfg\" deleted daemonset.apps \"kube-flannel-ds\" deleted \u5728\u6240\u6709\u8282\u70b9\u4e0a\u6e05\u9664iptables\u8bbe\u7f6e\u3002 rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u91cd\u65b0\u767b\u5f55\u4e3b\u673a\u8282\u70b9\uff0c\u4f8b\u5982 cka001 \uff0c\u5b89\u88c5Calico\uff0c curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Output: configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created \u9a8c\u8bc1Calico\u5b89\u88c5\u72b6\u6001\uff0c\u786e\u4fdd\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u90fd\u6b63\u5e38\u8fd0\u884c\u3002 kubectl get pod -n kube-system | grep calico \u8f93\u51fa\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE calico-kube-controllers-7bc6547ffb-tjfcg 1/1 Running 0 30m calico-node-7x8jm 1/1 Running 0 30m calico-node-cwxj5 1/1 Running 0 30m calico-node-rq978 1/1 Running 0 30m \u5982\u679c\u9047\u5230\u4efb\u4f55\u9519\u8bef\uff0c\u9996\u5148\u68c0\u67e5\u5bb9\u5668container\u65e5\u5fd7\u3002 # Get Container ID crictl ps # Get log info crictl logs \u7531\u4e8e\u6211\u4eec\u5c06 CNI \u4ece Flannel \u66f4\u6539\u4e3a Calico\uff0c\u6211\u4eec\u9700\u8981\u5220\u9664\u6240\u6709 Pod\uff0c\u6240\u6709 Pod \u90fd\u5c06\u81ea\u52a8\u91cd\u65b0\u521b\u5efa\u3002 kubectl delete pod -A --all \u67e5\u8be2\u6240\u6709pod\u90fd\u72b6\u6001\uff0c\u786e\u4fdd\u4ed6\u4eec\u90fd\u6b63\u5e38\u8fd0\u884c\u3002 kubectl get pod -A","title":"\u7528Calico\u66ff\u6362Flannel"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/#inbound-rules","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u7528\u4e8e\u6d4b\u8bd5\u7684\u5de5\u4f5c\u8d1f\u8f7d\u3002 \u7981\u6b62\u6240\u6709\u5165\u7ad9\u6d41\u91cf\u3002 \u5141\u8bb8\u7279\u5b9a\u7684\u5165\u7ad9\u6d41\u91cf\u3002 \u9a8c\u8bc1NetworkPolicy\u3002","title":"\u5165\u7ad9\u89c4\u5219\uff08Inbound Rules\uff09"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/#_1","text":"\u521b\u5efa\u4e09\u4e2a Deployment\uff0c\u540d\u79f0\u4e3a pod-netpol-1 \u3001 pod-netpol-2 \u548c pod-netpol-3 \uff0c\u5b83\u4eec\u90fd\u57fa\u4e8e\u955c\u50cf busybox \u3002 kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-1 name: pod-netpol-1 spec: replicas: 1 selector: matchLabels: app: pod-netpol-1 template: metadata: labels: app: pod-netpol-1 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-2 name: pod-netpol-2 spec: replicas: 1 selector: matchLabels: app: pod-netpol-2 template: metadata: labels: app: pod-netpol-2 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-3 name: pod-netpol-3 spec: replicas: 1 selector: matchLabels: app: pod-netpol-3 template: metadata: labels: app: pod-netpol-3 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] EOF \u68c0\u67e5pod\u7684IP\u5730\u5740\uff1a kubectl get pod -owide \u8f93\u51fa\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-netpol-1-6494f6bf8b-n58r9 1/1 Running 0 29s 10.244.102.30 cka003 pod-netpol-2-77478d77ff-l6rzm 1/1 Running 0 29s 10.244.112.30 cka002 pod-netpol-3-68977dcb48-ql5s6 1/1 Running 0 29s 10.244.102.31 cka003 \u767b\u5f55\u8fdb\u5165pod pod-netpol-1 \u3002 kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh \u6267\u884c\u547d\u4ee4 ping \uff0c\u786e\u4fdd pod-netpol-2 \u548c pod-netpol-3 \u53ef\u4e92\u76f8\u8bbf\u95ee\u3002 / # ping 10.244.112.30 3 packets transmitted, 3 packets received, 0 % packet loss / # ping 10.244.102.31 3 packets transmitted, 3 packets received, 0 % packet loss","title":"\u521b\u5efa\u6d4b\u8bd5\u5de5\u4f5c\u8d1f\u8f7d"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/#_2","text":"\u521b\u5efa\u7b56\u7565\uff0c\u7981\u6b62\u6240\u6709\u5165\u7ad9\u6d41\u91cf\u3002 kubectl apply -f - << EOF apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-ingress spec: podSelector: {} policyTypes: - Ingress EOF \u518d\u6b21\u767b\u5f55\u8fdb\u5165pod pod-netpol-1 \u3002 kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh Execute command ping that pod-netpol-2 and pod-netpol-3 are both unreachable as expected. \u6267\u884c\u547d\u4ee4 ping \uff0c\u548c\u6211\u4eec\u9884\u671f\u4e00\u6837\uff0c pod-netpol-2 \u548c pod-netpol-3 \u6b64\u65f6\u4e92\u76f8\u65e0\u6cd5\u8bbf\u95ee\u3002 / # ping 10.244.112.30 3 packets transmitted, 0 packets received, 100 % packet loss / # ping 10.244.102.31 3 packets transmitted, 0 packets received, 100 % packet loss","title":"\u7981\u6b62\u6240\u6709\u5165\u7ad9\u6d41\u91cf"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/#_3","text":"\u521b\u5efa NetworkPolicy\uff0c\u5141\u8bb8\u6765\u81ea pod-netpol-1 \u5230 pod-netpol-2 \u7684\u5165\u7ad9\u6d41\u91cf\u3002 kubectl apply -f - <:80 \u5931\u8d25 \u8fd0\u884c curl :80 \u6210\u529f kubectl run centos --image = centos -n my-ns-1 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-1 -- bash \u5728namespace my-ns-2 \u4e2d\u521b\u5efa\u4e00\u4e2a\u4e34\u65f6 Pod\uff0c\u7136\u540e\u8fde\u63a5\u5230\u8be5 Pod \u5e76\u9a8c\u8bc1\u8bbf\u95ee\u3002 \u547d\u4ee4 curl :80 \u5931\u8d25 \u547d\u4ee4 curl :80 \u5931\u8d25\u3002 kubectl run centos --image = centos -n my-ns-2 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-2 -- bash \u4fee\u6539 my-networkpolicy-1 \uff0c \u628a ingress.from.namespaceSelector.matchLabels \u7684\u503c\u6539\u4e3a my-ns-2 \u3002 \u767b\u5f55\u8fdb\u5165namespace my-ns-2 \u4e0a\u7684\u4e34\u65f6pod\uff0c\u9a8c\u8bc1\u8bbf\u95ee\u3002 \u547d\u4ee4 curl :80 \u5931\u8d25 \u547d\u4ee4 curl :80 \u6210\u529f kubectl exec -it mycentos -n my-ns-2 -- bash \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete namespace my-ns-1 kubectl delete namespace my-ns-2","title":"NetworkPolicy"},{"location":"k8s/cka_cn/foundamentals/overview/","text":"CKA\u81ea\u5b66\u7b14\u8bb06:Kubernetes\u96c6\u7fa4\u6982\u89c8 \u00b6 \u6458\u8981 \u00b6 \u5305\u542b\u4e0b\u9762\u5185\u5bb9\uff1a \u5bb9\u5668\u5c42 Kubernetes\u5c42 \u63d0\u793a\uff1a \u540e\u7eed\u5b9e\u9a8c\u73af\u5883\u90fd\u662f\u4f7f\u7528\u5728\u963f\u91cc\u4e91\u90e8\u7f72\u7684Ubuntu\u4e09\u8282\u70b9\u96c6\u7fa4\uff0c\u4e09\u4e2a\u8282\u70b9\u5206\u522b\u4e3a cka001 \u3001 cka002 \u548c cka003 \u3002 \u5bb9\u5668\u5c42 \u00b6 \u573a\u666f\uff1a \u4f7f\u7528Containerd\u670d\u52a1\uff0c\u901a\u8fc7\u547d\u4ee4 nerdctl \u6765\u7ba1\u7406\u6211\u4eec\u7684\u955c\u50cf\u548c\u5bb9\u5668\uff0c\u8fd9\u4e0eDocker\u7684\u6982\u5ff5\u76f8\u540c\u3002 Get namespace. Get containers. Get images. Get volumes. Get overall status. Get network status. \u6f14\u793a\uff1a \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4namespaces\u3002 sudo nerdctl namespace ls \u8fd0\u884c\u7ed3\u679c\uff1a NAME CONTAINERS IMAGES VOLUMES LABELS k8s.io 21 30 0 \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4 k8s.io \u4e0b\u7684\u5bb9\u5668\u3002 sudo nerdctl -n k8s.io ps \u8fd0\u884c\u7ed3\u679c\uff1a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0a3625f22f65 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk 121af2ecd1a1 registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll/coredns 49f6c7e3efe5 registry.aliyuncs.com/google_containers/kube-proxy:v1.24.0 \"/usr/local/bin/kube\u2026\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t/kube-proxy 4bba5fbd701d registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001 57d47b57eb12 docker.io/calico/node:v3.23.3 \"start_runit\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl/calico-node 5ce4c351a886 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl 6456eef784bf registry.aliyuncs.com/google_containers/kube-scheduler:v1.24.0 \"kube-scheduler --au\u2026\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001/kube-scheduler 6a687305871c registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 7dcb24568574 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll a06b101118b8 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001 a07ef8c3fc3a registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/etcd-cka001 b8566d3e4174 registry.aliyuncs.com/google_containers/kube-controller-manager:v1.24.0 \"kube-controller-man\u2026\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001/kube-controller-manager ca6ac26314ff registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk/coredns cdc041b4791e registry.aliyuncs.com/google_containers/etcd:3.5.3-0 \"etcd --advertise-cl\u2026\" 16 hours ago Up k8s://kube-system/etcd-cka001/etcd e0c59abadf2e registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t e0d2e5f6ccff registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001 \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4 k8s.io \u4e0b\u7684\u955c\u50cf\u3002 sudo nerdctl -n k8s.io image ls -a \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4 k8s.io \u4e0b\u7684\u5377Volume\u3002\u521d\u59cb\u5316\u5b89\u88c5\u540e\uff0c\u8be5\u547d\u540d\u7a7a\u95f4\u4e0b\u6ca1\u6709\u4efb\u4f55\u5377\u3002 sudo nerdctl -n k8s.io volume ls \u8bfb\u53d6\u96c6\u7fa4\u72b6\u6001\u3002 sudo nerdctl stats \u8bfb\u53d6\u7f51\u7edc\u72b6\u6001\u3002 sudo nerdctl network ls sudo nerdctl network inspect bridge sudo nerdctl network inspect k8s-pod-network \u8fd0\u884c\u7ed3\u679c\uff1a NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none Get network interface in host cka001 with command ip addr list . IP pool of 10.4.0.1/24 is ipam and defined in /etc/cni/net.d/nerdctl-bridge.conflist . \u4f7f\u7528\u547d\u4ee4 ip addr list \u83b7\u53d6\u4e3b\u673a cka001 \u7684\u7f51\u7edc\u63a5\u53e3\u3002 10.4.0.1/24 \u7684IP\u6c60\u662f ipam \uff0c\u5728 /etc/cni/net.d/nerdctl-bridge.conflist \u4e2d\u5b9a\u4e49\u3002 lo : inet 127.0.0.1/8 qlen 1000 eth0 : inet /24 brd xxx.xxx.xxx.255 scope global dynamic eth0 tunl0@NONE : inet 10.244.228.192/32 scope global tunl0 cali96e32d88db2@if4 : cali93613212490@if4 : nerdctl-bridge.conflist \u6587\u4ef6\u7684\u4f5c\u7528\u662f\uff1a \u5b9a\u4e49\u4e86nerdctl\u4f7f\u7528\u7684\u9ed8\u8ba4\u6865\u63a5CNI\u7f51\u7edc\u7684\u914d\u7f6e\uff0c\u5305\u62ec\u7f51\u7edc\u540d\u79f0\u3001\u5b50\u7f51\u3001\u7f51\u5173\u3001IP\u5206\u914d\u7b56\u7565\u7b49 1 \uff0c 2 \u3002 \u4f7f\u5f97nerdctl\u53ef\u4ee5\u4f7f\u7528docker run -it --rm alpine\u8fd9\u6837\u7684\u547d\u4ee4\u6765\u8fd0\u884c\u4e00\u4e2a\u5bb9\u5668\uff0c\u5e76\u81ea\u52a8\u5206\u914d\u4e00\u4e2a10.4.0.0/24\u7f51\u6bb5\u7684IP\u5730\u5740 1 \uff0c 3 \u3002 \u4f7f\u5f97nerdctl\u53ef\u4ee5\u652f\u6301\u4e00\u4e9b\u57fa\u672c\u7684CNI\u63d2\u4ef6\uff0c\u5982bridge, portmap, firewall, tuning 1 \uff0c 2 \u3002 Kubernetes\u5c42 \u00b6 \u573a\u666f\uff1a \u8282\u70b9Nodes \u547d\u540d\u7a7a\u95f4Namespaces \u7cfb\u7edfPods \u6f14\u793a\uff1a \u8bfb\u53d6\u8282\u70b9\u72b6\u6001\uff1a kubectl get node -o wide \u5728\u4e09\u4e2a\u8282\u70b9\u4e0a\u6709\u56db\u4e2a\u521d\u59cb\u7684\u547d\u540d\u7a7a\u95f4\u3002 kubectl get namespace -A \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS AGE default Active 56m kube-node-lease Active 56m kube-public Active 56m kube-system Active 56m \u5728\u4e09\u4e2a\u8282\u70b9\u4e0a\u7684\u521d\u59cb\u5316Pod\u3002 kubectl get pod -A -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAMESPACE NAME READY STATUS RESTARTS AGE NODE NOMINATED NODE READINESS GATES kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 15h cka003 kube-system calico-node-255pc 1/1 Running 0 15h cka003 kube-system calico-node-7tmnb 1/1 Running 0 15h cka002 kube-system calico-node-w8nvl 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15h cka001 kube-system etcd-cka001 1/1 Running 0 15h cka001 kube-system kube-apiserver-cka001 1/1 Running 0 15h cka001 kube-system kube-controller-manager-cka001 1/1 Running 0 15h cka001 kube-system kube-proxy-dmj2t 1/1 Running 0 15h cka001 kube-system kube-proxy-n77zw 1/1 Running 0 15h cka002 kube-system kube-proxy-qs6rf 1/1 Running 0 15h cka003 kube-system kube-scheduler-cka001 1/1 Running 0 15h cka001 \u603b\u7ed3\uff1a \u4e0b\u9762\u5217\u51fa\u4e86\u521d\u59cb\u96c6\u7fa4\u4e2d\u4e3b\u8282\u70b9\u548c\u6240\u6709\u8282\u70b9\u4e2d\u6240\u5305\u542b\u7684\u5bb9\u5668\u548cPod\u7684\u5173\u7cfb\u3002 Master node: CoreDNS: 2 Pod etcd: 1 Pod apiserver: 1 Pod controller-manager: 1 Pod scheduler: 1 Pod Calico Controller: 1 Pod All nodes: Calico Node: 1 Pod each Proxy: 1 Pod each \u53c2\u8003\uff1a pause\u5bb9\u5668\uff1a \u6587\u7ae01 and \u6587\u7ae02 . nerdctl","title":"Kubernetes\u96c6\u7fa4\u6982\u89c8"},{"location":"k8s/cka_cn/foundamentals/overview/#cka6kubernetes","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb06:Kubernetes\u96c6\u7fa4\u6982\u89c8"},{"location":"k8s/cka_cn/foundamentals/overview/#_1","text":"\u5305\u542b\u4e0b\u9762\u5185\u5bb9\uff1a \u5bb9\u5668\u5c42 Kubernetes\u5c42 \u63d0\u793a\uff1a \u540e\u7eed\u5b9e\u9a8c\u73af\u5883\u90fd\u662f\u4f7f\u7528\u5728\u963f\u91cc\u4e91\u90e8\u7f72\u7684Ubuntu\u4e09\u8282\u70b9\u96c6\u7fa4\uff0c\u4e09\u4e2a\u8282\u70b9\u5206\u522b\u4e3a cka001 \u3001 cka002 \u548c cka003 \u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/overview/#_2","text":"\u573a\u666f\uff1a \u4f7f\u7528Containerd\u670d\u52a1\uff0c\u901a\u8fc7\u547d\u4ee4 nerdctl \u6765\u7ba1\u7406\u6211\u4eec\u7684\u955c\u50cf\u548c\u5bb9\u5668\uff0c\u8fd9\u4e0eDocker\u7684\u6982\u5ff5\u76f8\u540c\u3002 Get namespace. Get containers. Get images. Get volumes. Get overall status. Get network status. \u6f14\u793a\uff1a \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4namespaces\u3002 sudo nerdctl namespace ls \u8fd0\u884c\u7ed3\u679c\uff1a NAME CONTAINERS IMAGES VOLUMES LABELS k8s.io 21 30 0 \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4 k8s.io \u4e0b\u7684\u5bb9\u5668\u3002 sudo nerdctl -n k8s.io ps \u8fd0\u884c\u7ed3\u679c\uff1a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0a3625f22f65 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk 121af2ecd1a1 registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll/coredns 49f6c7e3efe5 registry.aliyuncs.com/google_containers/kube-proxy:v1.24.0 \"/usr/local/bin/kube\u2026\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t/kube-proxy 4bba5fbd701d registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001 57d47b57eb12 docker.io/calico/node:v3.23.3 \"start_runit\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl/calico-node 5ce4c351a886 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl 6456eef784bf registry.aliyuncs.com/google_containers/kube-scheduler:v1.24.0 \"kube-scheduler --au\u2026\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001/kube-scheduler 6a687305871c registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 7dcb24568574 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll a06b101118b8 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001 a07ef8c3fc3a registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/etcd-cka001 b8566d3e4174 registry.aliyuncs.com/google_containers/kube-controller-manager:v1.24.0 \"kube-controller-man\u2026\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001/kube-controller-manager ca6ac26314ff registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk/coredns cdc041b4791e registry.aliyuncs.com/google_containers/etcd:3.5.3-0 \"etcd --advertise-cl\u2026\" 16 hours ago Up k8s://kube-system/etcd-cka001/etcd e0c59abadf2e registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t e0d2e5f6ccff registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001 \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4 k8s.io \u4e0b\u7684\u955c\u50cf\u3002 sudo nerdctl -n k8s.io image ls -a \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4 k8s.io \u4e0b\u7684\u5377Volume\u3002\u521d\u59cb\u5316\u5b89\u88c5\u540e\uff0c\u8be5\u547d\u540d\u7a7a\u95f4\u4e0b\u6ca1\u6709\u4efb\u4f55\u5377\u3002 sudo nerdctl -n k8s.io volume ls \u8bfb\u53d6\u96c6\u7fa4\u72b6\u6001\u3002 sudo nerdctl stats \u8bfb\u53d6\u7f51\u7edc\u72b6\u6001\u3002 sudo nerdctl network ls sudo nerdctl network inspect bridge sudo nerdctl network inspect k8s-pod-network \u8fd0\u884c\u7ed3\u679c\uff1a NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none Get network interface in host cka001 with command ip addr list . IP pool of 10.4.0.1/24 is ipam and defined in /etc/cni/net.d/nerdctl-bridge.conflist . \u4f7f\u7528\u547d\u4ee4 ip addr list \u83b7\u53d6\u4e3b\u673a cka001 \u7684\u7f51\u7edc\u63a5\u53e3\u3002 10.4.0.1/24 \u7684IP\u6c60\u662f ipam \uff0c\u5728 /etc/cni/net.d/nerdctl-bridge.conflist \u4e2d\u5b9a\u4e49\u3002 lo : inet 127.0.0.1/8 qlen 1000 eth0 : inet /24 brd xxx.xxx.xxx.255 scope global dynamic eth0 tunl0@NONE : inet 10.244.228.192/32 scope global tunl0 cali96e32d88db2@if4 : cali93613212490@if4 : nerdctl-bridge.conflist \u6587\u4ef6\u7684\u4f5c\u7528\u662f\uff1a \u5b9a\u4e49\u4e86nerdctl\u4f7f\u7528\u7684\u9ed8\u8ba4\u6865\u63a5CNI\u7f51\u7edc\u7684\u914d\u7f6e\uff0c\u5305\u62ec\u7f51\u7edc\u540d\u79f0\u3001\u5b50\u7f51\u3001\u7f51\u5173\u3001IP\u5206\u914d\u7b56\u7565\u7b49 1 \uff0c 2 \u3002 \u4f7f\u5f97nerdctl\u53ef\u4ee5\u4f7f\u7528docker run -it --rm alpine\u8fd9\u6837\u7684\u547d\u4ee4\u6765\u8fd0\u884c\u4e00\u4e2a\u5bb9\u5668\uff0c\u5e76\u81ea\u52a8\u5206\u914d\u4e00\u4e2a10.4.0.0/24\u7f51\u6bb5\u7684IP\u5730\u5740 1 \uff0c 3 \u3002 \u4f7f\u5f97nerdctl\u53ef\u4ee5\u652f\u6301\u4e00\u4e9b\u57fa\u672c\u7684CNI\u63d2\u4ef6\uff0c\u5982bridge, portmap, firewall, tuning 1 \uff0c 2 \u3002","title":"\u5bb9\u5668\u5c42"},{"location":"k8s/cka_cn/foundamentals/overview/#kubernetes","text":"\u573a\u666f\uff1a \u8282\u70b9Nodes \u547d\u540d\u7a7a\u95f4Namespaces \u7cfb\u7edfPods \u6f14\u793a\uff1a \u8bfb\u53d6\u8282\u70b9\u72b6\u6001\uff1a kubectl get node -o wide \u5728\u4e09\u4e2a\u8282\u70b9\u4e0a\u6709\u56db\u4e2a\u521d\u59cb\u7684\u547d\u540d\u7a7a\u95f4\u3002 kubectl get namespace -A \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS AGE default Active 56m kube-node-lease Active 56m kube-public Active 56m kube-system Active 56m \u5728\u4e09\u4e2a\u8282\u70b9\u4e0a\u7684\u521d\u59cb\u5316Pod\u3002 kubectl get pod -A -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAMESPACE NAME READY STATUS RESTARTS AGE NODE NOMINATED NODE READINESS GATES kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 15h cka003 kube-system calico-node-255pc 1/1 Running 0 15h cka003 kube-system calico-node-7tmnb 1/1 Running 0 15h cka002 kube-system calico-node-w8nvl 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15h cka001 kube-system etcd-cka001 1/1 Running 0 15h cka001 kube-system kube-apiserver-cka001 1/1 Running 0 15h cka001 kube-system kube-controller-manager-cka001 1/1 Running 0 15h cka001 kube-system kube-proxy-dmj2t 1/1 Running 0 15h cka001 kube-system kube-proxy-n77zw 1/1 Running 0 15h cka002 kube-system kube-proxy-qs6rf 1/1 Running 0 15h cka003 kube-system kube-scheduler-cka001 1/1 Running 0 15h cka001 \u603b\u7ed3\uff1a \u4e0b\u9762\u5217\u51fa\u4e86\u521d\u59cb\u96c6\u7fa4\u4e2d\u4e3b\u8282\u70b9\u548c\u6240\u6709\u8282\u70b9\u4e2d\u6240\u5305\u542b\u7684\u5bb9\u5668\u548cPod\u7684\u5173\u7cfb\u3002 Master node: CoreDNS: 2 Pod etcd: 1 Pod apiserver: 1 Pod controller-manager: 1 Pod scheduler: 1 Pod Calico Controller: 1 Pod All nodes: Calico Node: 1 Pod each Proxy: 1 Pod each \u53c2\u8003\uff1a pause\u5bb9\u5668\uff1a \u6587\u7ae01 and \u6587\u7ae02 . nerdctl","title":"Kubernetes\u5c42"},{"location":"k8s/cka_cn/foundamentals/persistence/","text":"CKA\u81ea\u5b66\u7b14\u8bb017:Persistence \u00b6 \u6458\u8981 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u7c7b\u578b\u4e3a emptyDir \u7684\u5377\u6765\u521b\u5efa Pod\uff0cPod \u4e2d\u7684\u5bb9\u5668\u5c06\u4f1a\u6302\u8f7d\u5728\u8fd0\u884c\u8282\u70b9\u4e0a\u7684\u9ed8\u8ba4\u76ee\u5f55 /var/lib/kubelet/pods/ \u4e2d\u3002 \u521b\u5efa\u4e00\u4e2a\u7c7b\u578b\u4e3a hostPath \u7684\u5377\u6765\u521b\u5efa Deployment\uff0cDeployment \u4e2d\u7684\u5bb9\u5668\u5c06\u4f1a\u6302\u8f7d\u5728\u8fd0\u884c\u8282\u70b9\u4e0a\u5b9a\u4e49\u7684\u76ee\u5f55 hostPath: \u4e2d\u3002 \u521b\u5efa PV \u548c PVC\uff1a \u8bbe\u7f6e NFS \u670d\u52a1\u5668\u5e76\u5171\u4eab /nfsdata/ \u76ee\u5f55\u3002 \u521b\u5efa PV mysql-pv \u5e76\u6620\u5c04\u5230\u5171\u4eab\u76ee\u5f55 /nfsdata/ \uff0c\u540c\u65f6\u8bbe\u7f6e StorageClassName \u4e3a nfs \u3002 \u521b\u5efa PVC mysql-pvc \u5e76\u6620\u5c04\u5230 StorageClassName \u4e3a nfs \u7684 PV \u4e0a\u3002 \u521b\u5efa Deployment mysql \u6765\u4f7f\u7528 PVC mysql-pvc \u3002 \u521b\u5efa StorageClass\uff1a \u521b\u5efa ServiceAccount nfs-client-provisioner \u3002 \u521b\u5efa ClusterRole nfs-client-provisioner-runner \u548c Role leader-locking-nfs-client-provisioner \uff0c\u5e76\u5c06\u5176\u7ed1\u5b9a\u5230 ServiceAccount \u4e0a\uff0c\u4ee5\u4fbf\u8be5 ServiceAccount \u53ef\u4ee5\u64cd\u4f5c\u4e0b\u4e00\u6b65\u4e2d\u521b\u5efa\u7684 Deployment\u3002 \u521b\u5efa Deployment nfs-client-provisioner \u6765\u6dfb\u52a0\u8fde\u63a5\u5230 NFS \u670d\u52a1\u5668\u7684\u4fe1\u606f\uff0c\u4f8b\u5982 PROVISIONER_NAME \u662f k8s-sigs.io/nfs-subdir-external-provisioner \u3002 \u521b\u5efa StorageClass nfs-client \u5e76\u94fe\u63a5\u5230 provisioner: k8s-sigs.io/nfs-subdir-external-provisioner \uff0c\u76f8\u5173\u7684 PV \u4f1a\u81ea\u52a8\u521b\u5efa\u3002 \u521b\u5efa PVC nfs-pvc-from-sc \u5e76\u6620\u5c04\u5230 StorageClass nfs-client \u4e0a\u7684 PV\u3002 \u914d\u7f6eConfiguration\uff1a \u521b\u5efa\u4e00\u4e2a ConfigMap \u4ee5\u5305\u542b\u6587\u4ef6\u7684\u5185\u5bb9\uff0c\u5e76\u5c06\u6b64 ConfigMap \u6302\u8f7d\u5230 Pod \u4e2d\u7684\u7279\u5b9a\u6587\u4ef6\u4e2d\u3002 \u521b\u5efa\u4e00\u4e2a ConfigMap \u6765\u5305\u542b\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u5e76\u5728 Pod \u4e2d\u4f7f\u7528\u5b83\u4eec\u3002 \u5728 Pod \u4e2d\u5c06 ConfigMap \u7528\u4f5c\u73af\u5883\u53d8\u91cf\u3002 \u5efa\u8bae\uff1a \u9996\u5148\u5220\u9664 PVC\uff0c\u7136\u540e\u518d\u5220\u9664 PV\u3002 \u5982\u679c\u5220\u9664 PVC \u65f6\u9047\u5230 Terminating \u72b6\u6001\uff0c\u4f7f\u7528 kubectl edit pvc \u547d\u4ee4\uff0c\u7136\u540e\u5220\u9664 finalize: \u3002 emptyDir \u00b6 \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a hello-producer \u7684 Pod\uff0c\u5e76\u4f7f\u7528 emptyDir \u7c7b\u578b\u7684 Volume\u3002 cat > pod-emptydir.yaml < /producer_dir/hello; sleep 30000 volumes: - name: shared-volume emptyDir: {} EOF kubectl apply -f pod-emptydir.yaml \u67e5\u770bPod hello-producer \u7684\u72b6\u6001\u3002 kubectl get pod hello-producer -owide Pod hello-producer \u8fd0\u884c\u5728\u8282\u70b9node cka003 \u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello-producer 1/1 Running 0 6s 10.244.102.24 cka003 \u767b\u5f55 cka003 \uff0c\u56e0\u4e3a Pod hello-producer \u6b63\u5728\u8be5\u8282\u70b9\u4e0a\u8fd0\u884c\u3002 \u4e3a crictl \u547d\u4ee4\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf CONTAINER_RUNTIME_ENDPOINT \u3002\u5efa\u8bae\u5728\u6240\u6709\u8282\u70b9\u4e0a\u6267\u884c\u76f8\u540c\u7684\u64cd\u4f5c\u3002 export CONTAINER_RUNTIME_ENDPOINT = unix:///run/containerd/containerd.sock \u8fd0\u884c\u547d\u4ee4 crictl ps \u6765\u83b7\u53d6 Pod hello-producer \u7684\u5bb9\u5668 ID\u3002 crictl ps | grep hello-producer \u5bb9\u5668 producer \u7684ID\u662f 05f5e1bb6a1bb \u3002 CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD 50058afb3cba5 62aedd01bd852 About an hour ago Running producer 0 e6953bd4833a7 hello-producer \u8fd0\u884c\u547d\u4ee4 crictl inspect \uff0c\u83b7\u53d6\u5df2\u6302\u8f7d\u7684 shared-volume \u7684\u8def\u5f84\uff0c\u5b83\u662f emptyDir \u7c7b\u578b\u7684\u3002 crictl inspect 50058afb3cba5 | grep source | grep empty \u8fd0\u884c\u7ed3\u679c \"source\": \"/var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume\", \u4fee\u6539\u8def\u5f84\u4e3a\u4e0a\u9762\u83b7\u53d6\u5230\u7684 shared-volume \u7684\u6302\u8f7d\u8def\u5f84\u3002\u7136\u540e\u6211\u4eec\u4f1a\u770b\u5230\u6587\u4ef6 hello \u4e2d\u7684\u5185\u5bb9 hello world \u3002 cd /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume cat hello Pod\u5185\u7684\u8def\u5f84 /producer_dir \u88ab\u6302\u8f7d\u5230\u4e86\u672c\u5730\u5bbf\u4e3b\u673a\u8def\u5f84 /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume \u3002 \u6211\u4eec\u5728Pod\u5185\u521b\u5efa\u7684\u6587\u4ef6 /producer_dir/hello \u5b9e\u9645\u4e0a\u5728\u5bbf\u4e3b\u673a\u672c\u5730\u8def\u5f84\u4e2d\u3002 \u8ba9\u6211\u4eec\u5220\u9664\u5bb9\u5668 producer \uff0c\u5bb9\u5668 producer \u5c06\u4ee5\u65b0\u7684\u5bb9\u5668ID\u91cd\u65b0\u542f\u52a8\uff0c\u800c\u6587\u4ef6 hello \u4ecd\u5c06\u5b58\u5728\u3002 crictl ps crictl stop crictl rm \u73b0\u5728\u5220\u9664Pod hello-producer \uff0c\u5bb9\u5668 producer \u4f1a\u88ab\u5220\u9664\uff0c\u6587\u4ef6 hello \u4e5f\u4f1a\u88ab\u5220\u9664\u3002 kubectl delete pod hello-producer hostPath \u00b6 \u5e94\u7528\u4ee5\u4e0b yaml \u6587\u4ef6\u521b\u5efa\u4e00\u4e2a MySQL Pod \u5e76\u6302\u8f7d\u4e00\u4e2a hostPath \u3002 \u5c06\u4e3b\u673a\u76ee\u5f55 /tmp/mysql \u6302\u8f7d\u5230 Pod \u76ee\u5f55 /var/lib/mysql \u3002 \u5728\u672c\u5730\u68c0\u67e5\u662f\u5426\u5b58\u5728\u76ee\u5f55 /tmp/mysql \uff0c\u5982\u679c\u4e0d\u5b58\u5728\uff0c\u5219\u6267\u884c\u547d\u4ee4 mkdir /tmp/mysql \u521b\u5efa\u5b83\u3002 cat > mysql-hostpath.yaml < cka003 \u5728MySQL Pod\u8fd0\u884c\u7684\u8282\u70b9\u767b\u9646\u8fdb\u5165pod\u5185\u90e8\u3002 kubectl exec -it -- bash \u5728 Pod \u4e2d\uff0c\u8fdb\u5165 /var/lib/mysql \u76ee\u5f55\uff0c\u8be5\u76ee\u5f55\u4e2d\u7684\u6240\u6709\u6587\u4ef6\u90fd\u4e0e\u8282\u70b9 cka003 \u4e0a /tmp/mysql \u76ee\u5f55\u4e2d\u7684\u6240\u6709\u6587\u4ef6\u76f8\u540c\u3002 \u8fde\u63a5\u5230 Pod \u4e2d\u7684\u6570\u636e\u5e93\u3002 mysql -h 127 .0.0.1 -uroot -ppassword \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u5bf9\u6570\u636e\u5e93\u8fdb\u884c\u7b80\u5355\u7684\u64cd\u4f5c\u3002 mysql> show databases ; mysql> connect mysql ; mysql> show tables ; mysql> exit PV\u548cPVC \u00b6 \u4e0b\u9762\u7684\u6f14\u793a\u4e2d\uff0c\u6211\u4eec\u5c06\u4f7f\u7528NFS\u4f5c\u4e3a\u540e\u7aef\u5b58\u50a8\u6765\u6f14\u793a\u5982\u4f55\u90e8\u7f72PV\u548cPVC\u3002 \u8bbe\u7f6eNFS\u5171\u4eab \u00b6 \u5b89\u88c5nfs-kernel-server \u767b\u5f55\u5230\u8282\u70b9 cka002 \u3002\u914d\u7f6eWorker cka002 \u6210\u4e3aNFS\u670d\u52a1\u5668\u3002 sudo apt-get install -y nfs-kernel-server 2.\u914d\u7f6e\u5171\u4eab\u76ee\u5f55 \u521b\u5efa\u5171\u4eab\u6587\u4ef6\u5939\u3002 mkdir /nfsdata \u7f16\u8f91\u6587\u4ef6 /etc/exports \uff0c\u6dfb\u52a0\u4e00\u884c /nfsdata *(rw,sync,no_root_squash) \u3002 cat >> /etc/exports << EOF /nfsdata *(rw,sync,no_root_squash) EOF \u6709\u8bb8\u591a\u4e0d\u540c\u7684NFS\u5171\u4eab\u9009\u9879\uff0c\u4f8b\u5982\uff1a * \uff1a\u5bf9\u6240\u6709IP\u6216\u7279\u5b9aIP\u53ef\u8bbf\u95ee\u3002 rw \uff1a\u4f5c\u4e3a\u8bfb\u5199\u5171\u4eab\u3002\u8bf7\u6ce8\u610f\uff0c\u6b63\u5e38\u7684Linux\u6743\u9650\u4ecd\u7136\u9002\u7528\u3002\uff08\u8bf7\u6ce8\u610f\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002\uff09 ro \uff1a\u4f5c\u4e3a\u53ea\u8bfb\u5171\u4eab\u3002 sync \uff1a\u6587\u4ef6\u6570\u636e\u66f4\u6539\u4f1a\u7acb\u5373\u5199\u5165\u78c1\u76d8\uff0c\u8fd9\u4f1a\u5f71\u54cd\u6027\u80fd\uff0c\u4f46\u4e0d\u592a\u53ef\u80fd\u5bfc\u81f4\u6570\u636e\u4e22\u5931\u3002\u5728\u67d0\u4e9b\u53d1\u884c\u7248\u4e0a\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002 async \uff1a\u4e0esync\u76f8\u53cd\uff0c\u6587\u4ef6\u6570\u636e\u66f4\u6539\u6700\u521d\u5199\u5165\u5185\u5b58\u3002\u8fd9\u63d0\u9ad8\u4e86\u6027\u80fd\uff0c\u4f46\u66f4\u5bb9\u6613\u5bfc\u81f4\u6570\u636e\u4e22\u5931\u3002\u5728\u67d0\u4e9b\u53d1\u884c\u7248\u4e0a\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002 root_squash \uff1a\u5c06NFS\u5ba2\u6237\u7aef\u7684root\u7528\u6237\u548c\u7ec4\u5e10\u6237\u6620\u5c04\u5230\u533f\u540d\u5e10\u6237\uff0c\u901a\u5e38\u662fnobody\u5e10\u6237\u6216nfsnobody\u5e10\u6237\u3002\u6709\u5173\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u89c1\u672c\u6587\u540e\u7eed\u7684\u201c\u7528\u6237ID\u6620\u5c04\u201d\u3002\uff08\u8bf7\u6ce8\u610f\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002\uff09 no_root_squash \uff1a\u5c06NFS\u5ba2\u6237\u7aef\u7684root\u7528\u6237\u548c\u7ec4\u5e10\u6237\u6620\u5c04\u5230\u672c\u5730root\u548c\u7ec4\u5e10\u6237\u3002 \u6211\u4eec\u5c06\u4f7f\u7528\u57fa\u4e8eLinux\u670d\u52a1\u5668\u4e4b\u95f4\u7684 nfs \u548c rpcbind \u670d\u52a1\u7684\u65e0\u5bc6\u7801\u8fdc\u7a0b\u6302\u8f7d\uff0c\u800c\u4e0d\u662f\u57fa\u4e8e smb \u670d\u52a1\u3002\u9996\u5148\uff0c\u8fd9\u4e24\u53f0\u670d\u52a1\u5668\u5fc5\u987b\u6388\u6743\u3001\u5b89\u88c5\u5e76\u8bbe\u7f6enfs\u548crpcbind\u670d\u52a1\uff0c\u8bbe\u7f6e\u5171\u4eab\u76ee\u5f55\uff0c\u542f\u52a8\u670d\u52a1\uff0c\u5e76\u5728\u5ba2\u6237\u7aef\u4e0a\u8fdb\u884c\u6302\u8f7d\u3002 \u542f\u52a8 rpcbind \u670d\u52a1\u3002 sudo systemctl enable rpcbind sudo systemctl restart rpcbind \u542f\u52a8 nfs \u670d\u52a1\u3002 sudo systemctl enable nfs-server sudo systemctl start nfs-server \u5982\u679c /etc/exports \u6587\u4ef6\u88ab\u4fee\u6539\uff0c\u6211\u4eec\u9700\u8981\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u4f7f\u4e4b\u751f\u6548\u3002 exportfs -ra \u8fd0\u884c\u7ed3\u679c exportfs: /etc/exports [ 1 ] : Neither 'subtree_check' or 'no_subtree_check' specified for export \"*:/nfsdata\" . Assuming default behaviour ( 'no_subtree_check' ) . NOTE: this default has changed since nfs-utils version 1 .0.x \u68c0\u67e5\u5171\u4eab\u76ee\u5f55\u662f\u5426\u5df2\u7ecf\u88ab\u6b63\u786e\u914d\u7f6e\u4e86\u3002 showmount -e \u5982\u679c\u770b\u5230\u4e0b\u9762\u7684\u7ed3\u679c\uff0c\u5219\u8bf4\u660e\u5171\u4eab\u76ee\u5f55\u5df2\u7ecf\u88ab\u6b63\u786e\u914d\u7f6e\u4e86\u3002 Export list for cka002: /nfsdata * 3.\u5b89\u88c5NFS\u5ba2\u6237\u7aef \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b89\u88c5NFS\u5ba2\u6237\u7aef\u3002 sudo apt-get install -y nfs-common 4.\u9a8c\u8bc1NFS\u670d\u52a1 \u767b\u5f55\u5230\u4efb\u4f55\u4e00\u4e2a\u8282\u70b9\u6765\u9a8c\u8bc1NFS\u670d\u52a1\u662f\u5426\u6b63\u786e\u5de5\u4f5c\uff0c\u4ee5\u53caNFS\u670d\u52a1\u6240\u5171\u4eab\u5230\u76ee\u5f55\u662f\u5426\u53ef\u89c1\u3002 \u767b\u9646\u5230 cka001 \uff0c\u5e76\u68c0\u67e5 cka002 \u7684\u5171\u4eab\u76ee\u5f55\u72b6\u6001\u3002 showmount -e cka002 \u5982\u679c\u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\uff0c\u5219\u8bf4\u660eNFS\u670d\u52a1\u6b63\u5e38\u5de5\u4f5c\uff0c\u5305\u62ec\u5171\u4eab\u76ee\u5f55\u3002 Export list for cka002: /nfsdata * 5.\u6302\u8f7dNFS\u5171\u4eab\u76ee\u5f55 \u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u6302\u8f7dNFS\u5171\u4eab\u76ee\u5f55\u5230\u4efb\u4f55\u4e00\u4e2a\u975eNFS\u670d\u52a1\u5668\u8282\u70b9\uff0c\u6bd4\u5982 cka001 or cka003 \u3002 mkdir /remote-nfs-dir mount -t nfs cka002:/nfsdata /remote-nfs-dir/ \u6267\u884c\u547d\u4ee4 df -h \u6765\u68c0\u67e5NFS\u6302\u8f7d\u70b9\u662f\u5426\u6b63\u786e\uff0c\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\u3002 Filesystem Size Used Avail Use% Mounted on cka002:/nfsdata 40G 5 .8G 32G 16 % /remote-nfs-dir \u521b\u5efa PV \u00b6 \u521b\u5efa\u4e00\u4e2a PV mysql-pv \u3002 \u5c06 NFS \u670d\u52a1\u5668 IP \u66ff\u6362\u4e3a\u5b9e\u9645\u7684 IP\uff08\u8fd9\u91cc\u662f \uff09\uff0c\u5b83\u662f\u8fd0\u884c NFS \u670d\u52a1\u5668 cka002 \u7684 IP\u3002 kubectl apply -f - < EOF \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u68c0\u67e5\u521b\u5efa\u7684PV\u3002 kubectl get pv \u8fd0\u884c\u7ed3\u679c NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mysql-pv 1Gi RWO Retain Available nfs 19s \u521b\u5efa PVC \u00b6 \u521b\u5efa PVC mysql-pvc \u5e76\u6307\u5b9a\u5b58\u50a8\u5927\u5c0f\u3001\u8bbf\u95ee\u6a21\u5f0f\u548c\u5b58\u50a8\u7c7b\u3002 PVC mysql-pvc \u5c06\u901a\u8fc7\u5b58\u50a8\u7c7b\u540d\u79f0\u81ea\u52a8\u4e0e PV \u7ed1\u5b9a\u3002 kubectl apply -f - < nfs-provisioner-rbac.yaml < ( cka002 ) \u4e0a\u7684 /nfsdata \u76ee\u5f55\u7684\u5377 nfs-client-root \u3002 \u628a NFS \u670d\u52a1\u5668\u7684 IP \u66ff\u6362\u4e3a\u5b9e\u9645\u7684 IP \u5730\u5740\u5373\u53ef\uff08\u8fd9\u91cc\u7528 \u8868\u793a\uff09\u3002 cat > nfs-provisioner-deployment.yaml < - name: NFS_PATH value: /nfsdata volumes: - name: nfs-client-root nfs: server: path: /nfsdata EOF kubectl apply -f nfs-provisioner-deployment.yaml \u521b\u5efa NFS StorageClass \u00b6 \u521b\u5efa StorageClass nfs-client \uff0c\u5b9a\u4e49 NFS \u5b50\u76ee\u5f55\u5916\u90e8 provisioner \u7684 Kubernetes Storage Class\u3002 \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u7f16\u8f91 nfs-storageclass.yaml \u6587\u4ef6\u3002 vi nfs-storageclass.yaml \u6dfb\u52a0\u4e0b\u9762\u7684\u4fe1\u606f\u6765\u914d\u7f6e NFS StorageClass\u3002 apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-client annotations: storageclass.kubernetes.io/is-default-class: \"true\" provisioner: k8s-sigs.io/nfs-subdir-external-provisioner parameters: pathPattern: \" ${ .PVC.namespace } / ${ .PVC.annotations.nfs.io/storage-path } \" onDelete: delete \u5e94\u7528\u4e0a\u9762\u7684yaml\u6587\u4ef6\uff0c\u4f7f\u4e4b\u751f\u6548\u3002 kubectl apply -f nfs-storageclass.yaml \u521b\u5efaPVC \u00b6 \u521b\u5efa PVC nfs-pvc-from-sc \u3002 kubectl apply -f - < mysql-with-sc-pvc-7c97d875f8-wkvr9 1/1 Running 0 3m37s 10.244.102.27 cka003 \u6211\u4eec\u73b0\u5728\u6765\u67e5\u770b NFS \u670d\u52a1\u5668 cka002 \u4e0a\u7684\u5171\u4eab\u76ee\u5f55 /nfsdata/ \u3002 ll /nfsdata/ NFS \u670d\u52a1\u5668 cka002 \u4e0a\u7684\u5171\u4eab\u76ee\u5f55 /nfsdata/ \u4e0b\u6709\u4e862\u4e2a\u5b50\u76ee\u5f55\uff0c\u4e0e\u5176\u4ed62\u4e2a\u8282\u70b9\u4e0a\u7684\u76ee\u5f55 /remote-nfs-dir/ \u4e0b\u7684\u5185\u5bb9\u662f\u4e00\u81f4\u3002 drwxrwxrwx 6 systemd-coredump root 4096 Jul 23 23 :35 dev/ drwxr-xr-x 6 systemd-coredump root 4096 Jul 23 22 :29 mysqldata/ \u547d\u540d\u7a7a\u95f4Namespace\u7684\u540d\u79f0\u4f5c\u4e3a\u76ee\u5f55\u540d\u5728 /nfsdata/ \u76ee\u5f55\u4e0b\u7528\u4e8e\u6302\u8f7d\u5230 Pod \u4e2d\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u547d\u540d\u7a7a\u95f4Namespace\u540d\u79f0\u5c06\u7528\u4e8e\u6302\u8f7d\u70b9\u3002 \u5982\u679c\u6211\u4eec\u60f3\u8981\u4f7f\u7528\u81ea\u5b9a\u4e49\u7684\u6587\u4ef6\u5939\u6765\u4ee3\u66ff\uff0c\u6211\u4eec\u9700\u8981\u58f0\u660e\u4e00\u4e2a nfs.io/storage-path \u6ce8\u91ca\uff0c\u4f8b\u5982\u4e0b\u9762\u7684\u4f8b\u5b50\u3002 \u5728\u547d\u540d\u7a7a\u95f4 kube-system \u4e0a\u521b\u5efa PVC test-claim \uff0c\u5e76\u6d88\u8d39 nfs-client \u5377\u3002 kubectl apply -f - < ..data/password lrwxrwxrwx 1 root root 15 Jul 23 16 :30 username -> ..data/username \u800c\u4e14\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u8fd92\u4e2a\u6570\u636e\u5143\u7d20\uff08 username \u548c password \uff09\u7684\u5185\u5bb9\u5c31\u662f\u6211\u4eec\u9884\u5148\u5b9a\u4e49\u7684\u3002 / # cat /tmp/secret/username admin / # cat /tmp/secret/password 123456 \u62d3\u5c55\u6848\u4f8b \u00b6 \u591a\u79cd\u65b9\u6cd5\u521b\u5efaConfigMap \u00b6 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u6587\u4ef6\u3001\u76ee\u5f55\u3001\u6216\u8005\u503c\u6765\u521b\u5efaConfigMap\u3002 \u4e0b\u9762\u6211\u4eec\u521b\u5efaConfigMap colors \uff0c\u5305\u542b\uff1a \u56db\u4e2a\u6587\u4ef6\uff0c\u6587\u4ef6\u540d\u662f\u56db\u4e2a\u989c\u8272\u3002 \u4e00\u4e2a\u6587\u4ef6\uff0c\u6587\u4ef6\u540d\u662f\u6700\u559c\u6b22\u7684\u989c\u8272\u3002 mkdir configmap cd configmap mkdir primary echo c > primary/cyan echo m > primary/magenta echo y > primary/yellow echo k > primary/black echo \"known as key\" >> primary/black echo blue > favorite \u6267\u884c\u547d\u4ee4 tree configmap \uff0c\u53ef\u4ee5\u770b\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u6587\u4ef6\u76ee\u5f55\u7ed3\u6784\u3002 configmap \u251c\u2500\u2500 favorite \u2514\u2500\u2500 primary \u251c\u2500\u2500 black \u251c\u2500\u2500 cyan \u251c\u2500\u2500 magenta \u2514\u2500\u2500 yellow \u521b\u5efa\u4e00\u4e2a ConfigMap\uff0c\u5f15\u7528\u4e0a\u9762\u6211\u4eec\u521b\u5efa\u7684\u6587\u4ef6\u3002\u786e\u4fdd\u6211\u4eec\u73b0\u5728\u5728\u8def\u5f84 ~/configmap \u4e0b\u3002 kubectl create configmap colors \\ --from-literal = text = black \\ --from-file = ./favorite \\ --from-file = ./primary/ \u67e5\u770bConfigMap colors \u7684\u5185\u5bb9\u3002 kubectl get configmap colors -o yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion: v1 data: black: | k known as key cyan: | c favorite: | blue magenta: | m text: black yellow: | y kind: ConfigMap metadata: creationTimestamp: \"2022-07-12T16:38:27Z\" name: colors namespace: dev resourceVersion: \"2377258\" uid: d5ab133f-5e4d-41d4-bc9e-2bbb22a872a1 \u901a\u8fc7ConfigMap\u8bbe\u5b9a\u73af\u5883\u53d8\u91cf \u00b6 \u7ee7\u7eed\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u73b0\u5728\u6211\u4eec\u51c6\u5907\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a pod-configmap-env \u7684Pod\uff0c\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf ilike \u5e76\u4eceConfigMap colors \u4e2d\u5206\u914d\u503c favorite \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env spec: containers: - name: nginx image: nginx env: - name: ilike valueFrom: configMapKeyRef: name: colors key: favorite EOF \u8fde\u63a5\u5e76\u8fdb\u5165Pod pod-configmap-env \u5185\u90e8\u3002 kubectl exec -it pod-configmap-env -- bash \u9a8c\u8bc1\u73af\u5883\u53d8\u91cf ilike \u7684\u503c\u662f blue \uff0c\u8fd9\u662f ConfigMap colors \u7684 favorite \u503c\u3002 root@pod-configmap-env:/# echo $ilike blue \u6211\u4eec\u8fd8\u53ef\u4ee5\u4f7f\u7528 ConfigMap \u7684\u6240\u6709\u952e\u503c\u5bf9\u6765\u8bbe\u7f6e Pod \u7684\u73af\u5883\u53d8\u91cf\u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env-2 spec: containers: - name: nginx image: nginx envFrom: - configMapRef: name: colors EOF \u8fde\u63a5\u5e76\u8fdb\u5165Pod pod-configmap-env-2 \u5185\u90e8\u3002 kubectl exec -it pod-configmap-env-2 -- bash \u9a8c\u8bc1\u73af\u5883\u53d8\u91cf\u7684\u503c\u662f\u6211\u4eec\u5728ConfigMap colors \u6240\u5b9a\u4e49\u7684\u952e\u503c\u5bf9\u3002 root@pod-configmap-env-2:/# echo $black k known as key root@pod-configmap-env-2:/# echo $cyan c root@pod-configmap-env-2:/# echo $favorite blue","title":"Persistence"},{"location":"k8s/cka_cn/foundamentals/persistence/#cka17persistence","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb017:Persistence"},{"location":"k8s/cka_cn/foundamentals/persistence/#_1","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u7c7b\u578b\u4e3a emptyDir \u7684\u5377\u6765\u521b\u5efa Pod\uff0cPod \u4e2d\u7684\u5bb9\u5668\u5c06\u4f1a\u6302\u8f7d\u5728\u8fd0\u884c\u8282\u70b9\u4e0a\u7684\u9ed8\u8ba4\u76ee\u5f55 /var/lib/kubelet/pods/ \u4e2d\u3002 \u521b\u5efa\u4e00\u4e2a\u7c7b\u578b\u4e3a hostPath \u7684\u5377\u6765\u521b\u5efa Deployment\uff0cDeployment \u4e2d\u7684\u5bb9\u5668\u5c06\u4f1a\u6302\u8f7d\u5728\u8fd0\u884c\u8282\u70b9\u4e0a\u5b9a\u4e49\u7684\u76ee\u5f55 hostPath: \u4e2d\u3002 \u521b\u5efa PV \u548c PVC\uff1a \u8bbe\u7f6e NFS \u670d\u52a1\u5668\u5e76\u5171\u4eab /nfsdata/ \u76ee\u5f55\u3002 \u521b\u5efa PV mysql-pv \u5e76\u6620\u5c04\u5230\u5171\u4eab\u76ee\u5f55 /nfsdata/ \uff0c\u540c\u65f6\u8bbe\u7f6e StorageClassName \u4e3a nfs \u3002 \u521b\u5efa PVC mysql-pvc \u5e76\u6620\u5c04\u5230 StorageClassName \u4e3a nfs \u7684 PV \u4e0a\u3002 \u521b\u5efa Deployment mysql \u6765\u4f7f\u7528 PVC mysql-pvc \u3002 \u521b\u5efa StorageClass\uff1a \u521b\u5efa ServiceAccount nfs-client-provisioner \u3002 \u521b\u5efa ClusterRole nfs-client-provisioner-runner \u548c Role leader-locking-nfs-client-provisioner \uff0c\u5e76\u5c06\u5176\u7ed1\u5b9a\u5230 ServiceAccount \u4e0a\uff0c\u4ee5\u4fbf\u8be5 ServiceAccount \u53ef\u4ee5\u64cd\u4f5c\u4e0b\u4e00\u6b65\u4e2d\u521b\u5efa\u7684 Deployment\u3002 \u521b\u5efa Deployment nfs-client-provisioner \u6765\u6dfb\u52a0\u8fde\u63a5\u5230 NFS \u670d\u52a1\u5668\u7684\u4fe1\u606f\uff0c\u4f8b\u5982 PROVISIONER_NAME \u662f k8s-sigs.io/nfs-subdir-external-provisioner \u3002 \u521b\u5efa StorageClass nfs-client \u5e76\u94fe\u63a5\u5230 provisioner: k8s-sigs.io/nfs-subdir-external-provisioner \uff0c\u76f8\u5173\u7684 PV \u4f1a\u81ea\u52a8\u521b\u5efa\u3002 \u521b\u5efa PVC nfs-pvc-from-sc \u5e76\u6620\u5c04\u5230 StorageClass nfs-client \u4e0a\u7684 PV\u3002 \u914d\u7f6eConfiguration\uff1a \u521b\u5efa\u4e00\u4e2a ConfigMap \u4ee5\u5305\u542b\u6587\u4ef6\u7684\u5185\u5bb9\uff0c\u5e76\u5c06\u6b64 ConfigMap \u6302\u8f7d\u5230 Pod \u4e2d\u7684\u7279\u5b9a\u6587\u4ef6\u4e2d\u3002 \u521b\u5efa\u4e00\u4e2a ConfigMap \u6765\u5305\u542b\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u5e76\u5728 Pod \u4e2d\u4f7f\u7528\u5b83\u4eec\u3002 \u5728 Pod \u4e2d\u5c06 ConfigMap \u7528\u4f5c\u73af\u5883\u53d8\u91cf\u3002 \u5efa\u8bae\uff1a \u9996\u5148\u5220\u9664 PVC\uff0c\u7136\u540e\u518d\u5220\u9664 PV\u3002 \u5982\u679c\u5220\u9664 PVC \u65f6\u9047\u5230 Terminating \u72b6\u6001\uff0c\u4f7f\u7528 kubectl edit pvc \u547d\u4ee4\uff0c\u7136\u540e\u5220\u9664 finalize: \u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/persistence/#emptydir","text":"\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a hello-producer \u7684 Pod\uff0c\u5e76\u4f7f\u7528 emptyDir \u7c7b\u578b\u7684 Volume\u3002 cat > pod-emptydir.yaml < /producer_dir/hello; sleep 30000 volumes: - name: shared-volume emptyDir: {} EOF kubectl apply -f pod-emptydir.yaml \u67e5\u770bPod hello-producer \u7684\u72b6\u6001\u3002 kubectl get pod hello-producer -owide Pod hello-producer \u8fd0\u884c\u5728\u8282\u70b9node cka003 \u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello-producer 1/1 Running 0 6s 10.244.102.24 cka003 \u767b\u5f55 cka003 \uff0c\u56e0\u4e3a Pod hello-producer \u6b63\u5728\u8be5\u8282\u70b9\u4e0a\u8fd0\u884c\u3002 \u4e3a crictl \u547d\u4ee4\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf CONTAINER_RUNTIME_ENDPOINT \u3002\u5efa\u8bae\u5728\u6240\u6709\u8282\u70b9\u4e0a\u6267\u884c\u76f8\u540c\u7684\u64cd\u4f5c\u3002 export CONTAINER_RUNTIME_ENDPOINT = unix:///run/containerd/containerd.sock \u8fd0\u884c\u547d\u4ee4 crictl ps \u6765\u83b7\u53d6 Pod hello-producer \u7684\u5bb9\u5668 ID\u3002 crictl ps | grep hello-producer \u5bb9\u5668 producer \u7684ID\u662f 05f5e1bb6a1bb \u3002 CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD 50058afb3cba5 62aedd01bd852 About an hour ago Running producer 0 e6953bd4833a7 hello-producer \u8fd0\u884c\u547d\u4ee4 crictl inspect \uff0c\u83b7\u53d6\u5df2\u6302\u8f7d\u7684 shared-volume \u7684\u8def\u5f84\uff0c\u5b83\u662f emptyDir \u7c7b\u578b\u7684\u3002 crictl inspect 50058afb3cba5 | grep source | grep empty \u8fd0\u884c\u7ed3\u679c \"source\": \"/var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume\", \u4fee\u6539\u8def\u5f84\u4e3a\u4e0a\u9762\u83b7\u53d6\u5230\u7684 shared-volume \u7684\u6302\u8f7d\u8def\u5f84\u3002\u7136\u540e\u6211\u4eec\u4f1a\u770b\u5230\u6587\u4ef6 hello \u4e2d\u7684\u5185\u5bb9 hello world \u3002 cd /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume cat hello Pod\u5185\u7684\u8def\u5f84 /producer_dir \u88ab\u6302\u8f7d\u5230\u4e86\u672c\u5730\u5bbf\u4e3b\u673a\u8def\u5f84 /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume \u3002 \u6211\u4eec\u5728Pod\u5185\u521b\u5efa\u7684\u6587\u4ef6 /producer_dir/hello \u5b9e\u9645\u4e0a\u5728\u5bbf\u4e3b\u673a\u672c\u5730\u8def\u5f84\u4e2d\u3002 \u8ba9\u6211\u4eec\u5220\u9664\u5bb9\u5668 producer \uff0c\u5bb9\u5668 producer \u5c06\u4ee5\u65b0\u7684\u5bb9\u5668ID\u91cd\u65b0\u542f\u52a8\uff0c\u800c\u6587\u4ef6 hello \u4ecd\u5c06\u5b58\u5728\u3002 crictl ps crictl stop crictl rm \u73b0\u5728\u5220\u9664Pod hello-producer \uff0c\u5bb9\u5668 producer \u4f1a\u88ab\u5220\u9664\uff0c\u6587\u4ef6 hello \u4e5f\u4f1a\u88ab\u5220\u9664\u3002 kubectl delete pod hello-producer","title":"emptyDir"},{"location":"k8s/cka_cn/foundamentals/persistence/#hostpath","text":"\u5e94\u7528\u4ee5\u4e0b yaml \u6587\u4ef6\u521b\u5efa\u4e00\u4e2a MySQL Pod \u5e76\u6302\u8f7d\u4e00\u4e2a hostPath \u3002 \u5c06\u4e3b\u673a\u76ee\u5f55 /tmp/mysql \u6302\u8f7d\u5230 Pod \u76ee\u5f55 /var/lib/mysql \u3002 \u5728\u672c\u5730\u68c0\u67e5\u662f\u5426\u5b58\u5728\u76ee\u5f55 /tmp/mysql \uff0c\u5982\u679c\u4e0d\u5b58\u5728\uff0c\u5219\u6267\u884c\u547d\u4ee4 mkdir /tmp/mysql \u521b\u5efa\u5b83\u3002 cat > mysql-hostpath.yaml < cka003 \u5728MySQL Pod\u8fd0\u884c\u7684\u8282\u70b9\u767b\u9646\u8fdb\u5165pod\u5185\u90e8\u3002 kubectl exec -it -- bash \u5728 Pod \u4e2d\uff0c\u8fdb\u5165 /var/lib/mysql \u76ee\u5f55\uff0c\u8be5\u76ee\u5f55\u4e2d\u7684\u6240\u6709\u6587\u4ef6\u90fd\u4e0e\u8282\u70b9 cka003 \u4e0a /tmp/mysql \u76ee\u5f55\u4e2d\u7684\u6240\u6709\u6587\u4ef6\u76f8\u540c\u3002 \u8fde\u63a5\u5230 Pod \u4e2d\u7684\u6570\u636e\u5e93\u3002 mysql -h 127 .0.0.1 -uroot -ppassword \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u5bf9\u6570\u636e\u5e93\u8fdb\u884c\u7b80\u5355\u7684\u64cd\u4f5c\u3002 mysql> show databases ; mysql> connect mysql ; mysql> show tables ; mysql> exit","title":"hostPath"},{"location":"k8s/cka_cn/foundamentals/persistence/#pvpvc","text":"\u4e0b\u9762\u7684\u6f14\u793a\u4e2d\uff0c\u6211\u4eec\u5c06\u4f7f\u7528NFS\u4f5c\u4e3a\u540e\u7aef\u5b58\u50a8\u6765\u6f14\u793a\u5982\u4f55\u90e8\u7f72PV\u548cPVC\u3002","title":"PV\u548cPVC"},{"location":"k8s/cka_cn/foundamentals/persistence/#nfs","text":"\u5b89\u88c5nfs-kernel-server \u767b\u5f55\u5230\u8282\u70b9 cka002 \u3002\u914d\u7f6eWorker cka002 \u6210\u4e3aNFS\u670d\u52a1\u5668\u3002 sudo apt-get install -y nfs-kernel-server 2.\u914d\u7f6e\u5171\u4eab\u76ee\u5f55 \u521b\u5efa\u5171\u4eab\u6587\u4ef6\u5939\u3002 mkdir /nfsdata \u7f16\u8f91\u6587\u4ef6 /etc/exports \uff0c\u6dfb\u52a0\u4e00\u884c /nfsdata *(rw,sync,no_root_squash) \u3002 cat >> /etc/exports << EOF /nfsdata *(rw,sync,no_root_squash) EOF \u6709\u8bb8\u591a\u4e0d\u540c\u7684NFS\u5171\u4eab\u9009\u9879\uff0c\u4f8b\u5982\uff1a * \uff1a\u5bf9\u6240\u6709IP\u6216\u7279\u5b9aIP\u53ef\u8bbf\u95ee\u3002 rw \uff1a\u4f5c\u4e3a\u8bfb\u5199\u5171\u4eab\u3002\u8bf7\u6ce8\u610f\uff0c\u6b63\u5e38\u7684Linux\u6743\u9650\u4ecd\u7136\u9002\u7528\u3002\uff08\u8bf7\u6ce8\u610f\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002\uff09 ro \uff1a\u4f5c\u4e3a\u53ea\u8bfb\u5171\u4eab\u3002 sync \uff1a\u6587\u4ef6\u6570\u636e\u66f4\u6539\u4f1a\u7acb\u5373\u5199\u5165\u78c1\u76d8\uff0c\u8fd9\u4f1a\u5f71\u54cd\u6027\u80fd\uff0c\u4f46\u4e0d\u592a\u53ef\u80fd\u5bfc\u81f4\u6570\u636e\u4e22\u5931\u3002\u5728\u67d0\u4e9b\u53d1\u884c\u7248\u4e0a\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002 async \uff1a\u4e0esync\u76f8\u53cd\uff0c\u6587\u4ef6\u6570\u636e\u66f4\u6539\u6700\u521d\u5199\u5165\u5185\u5b58\u3002\u8fd9\u63d0\u9ad8\u4e86\u6027\u80fd\uff0c\u4f46\u66f4\u5bb9\u6613\u5bfc\u81f4\u6570\u636e\u4e22\u5931\u3002\u5728\u67d0\u4e9b\u53d1\u884c\u7248\u4e0a\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002 root_squash \uff1a\u5c06NFS\u5ba2\u6237\u7aef\u7684root\u7528\u6237\u548c\u7ec4\u5e10\u6237\u6620\u5c04\u5230\u533f\u540d\u5e10\u6237\uff0c\u901a\u5e38\u662fnobody\u5e10\u6237\u6216nfsnobody\u5e10\u6237\u3002\u6709\u5173\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u89c1\u672c\u6587\u540e\u7eed\u7684\u201c\u7528\u6237ID\u6620\u5c04\u201d\u3002\uff08\u8bf7\u6ce8\u610f\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002\uff09 no_root_squash \uff1a\u5c06NFS\u5ba2\u6237\u7aef\u7684root\u7528\u6237\u548c\u7ec4\u5e10\u6237\u6620\u5c04\u5230\u672c\u5730root\u548c\u7ec4\u5e10\u6237\u3002 \u6211\u4eec\u5c06\u4f7f\u7528\u57fa\u4e8eLinux\u670d\u52a1\u5668\u4e4b\u95f4\u7684 nfs \u548c rpcbind \u670d\u52a1\u7684\u65e0\u5bc6\u7801\u8fdc\u7a0b\u6302\u8f7d\uff0c\u800c\u4e0d\u662f\u57fa\u4e8e smb \u670d\u52a1\u3002\u9996\u5148\uff0c\u8fd9\u4e24\u53f0\u670d\u52a1\u5668\u5fc5\u987b\u6388\u6743\u3001\u5b89\u88c5\u5e76\u8bbe\u7f6enfs\u548crpcbind\u670d\u52a1\uff0c\u8bbe\u7f6e\u5171\u4eab\u76ee\u5f55\uff0c\u542f\u52a8\u670d\u52a1\uff0c\u5e76\u5728\u5ba2\u6237\u7aef\u4e0a\u8fdb\u884c\u6302\u8f7d\u3002 \u542f\u52a8 rpcbind \u670d\u52a1\u3002 sudo systemctl enable rpcbind sudo systemctl restart rpcbind \u542f\u52a8 nfs \u670d\u52a1\u3002 sudo systemctl enable nfs-server sudo systemctl start nfs-server \u5982\u679c /etc/exports \u6587\u4ef6\u88ab\u4fee\u6539\uff0c\u6211\u4eec\u9700\u8981\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u4f7f\u4e4b\u751f\u6548\u3002 exportfs -ra \u8fd0\u884c\u7ed3\u679c exportfs: /etc/exports [ 1 ] : Neither 'subtree_check' or 'no_subtree_check' specified for export \"*:/nfsdata\" . Assuming default behaviour ( 'no_subtree_check' ) . NOTE: this default has changed since nfs-utils version 1 .0.x \u68c0\u67e5\u5171\u4eab\u76ee\u5f55\u662f\u5426\u5df2\u7ecf\u88ab\u6b63\u786e\u914d\u7f6e\u4e86\u3002 showmount -e \u5982\u679c\u770b\u5230\u4e0b\u9762\u7684\u7ed3\u679c\uff0c\u5219\u8bf4\u660e\u5171\u4eab\u76ee\u5f55\u5df2\u7ecf\u88ab\u6b63\u786e\u914d\u7f6e\u4e86\u3002 Export list for cka002: /nfsdata * 3.\u5b89\u88c5NFS\u5ba2\u6237\u7aef \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b89\u88c5NFS\u5ba2\u6237\u7aef\u3002 sudo apt-get install -y nfs-common 4.\u9a8c\u8bc1NFS\u670d\u52a1 \u767b\u5f55\u5230\u4efb\u4f55\u4e00\u4e2a\u8282\u70b9\u6765\u9a8c\u8bc1NFS\u670d\u52a1\u662f\u5426\u6b63\u786e\u5de5\u4f5c\uff0c\u4ee5\u53caNFS\u670d\u52a1\u6240\u5171\u4eab\u5230\u76ee\u5f55\u662f\u5426\u53ef\u89c1\u3002 \u767b\u9646\u5230 cka001 \uff0c\u5e76\u68c0\u67e5 cka002 \u7684\u5171\u4eab\u76ee\u5f55\u72b6\u6001\u3002 showmount -e cka002 \u5982\u679c\u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\uff0c\u5219\u8bf4\u660eNFS\u670d\u52a1\u6b63\u5e38\u5de5\u4f5c\uff0c\u5305\u62ec\u5171\u4eab\u76ee\u5f55\u3002 Export list for cka002: /nfsdata * 5.\u6302\u8f7dNFS\u5171\u4eab\u76ee\u5f55 \u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u6302\u8f7dNFS\u5171\u4eab\u76ee\u5f55\u5230\u4efb\u4f55\u4e00\u4e2a\u975eNFS\u670d\u52a1\u5668\u8282\u70b9\uff0c\u6bd4\u5982 cka001 or cka003 \u3002 mkdir /remote-nfs-dir mount -t nfs cka002:/nfsdata /remote-nfs-dir/ \u6267\u884c\u547d\u4ee4 df -h \u6765\u68c0\u67e5NFS\u6302\u8f7d\u70b9\u662f\u5426\u6b63\u786e\uff0c\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\u3002 Filesystem Size Used Avail Use% Mounted on cka002:/nfsdata 40G 5 .8G 32G 16 % /remote-nfs-dir","title":"\u8bbe\u7f6eNFS\u5171\u4eab"},{"location":"k8s/cka_cn/foundamentals/persistence/#pv","text":"\u521b\u5efa\u4e00\u4e2a PV mysql-pv \u3002 \u5c06 NFS \u670d\u52a1\u5668 IP \u66ff\u6362\u4e3a\u5b9e\u9645\u7684 IP\uff08\u8fd9\u91cc\u662f \uff09\uff0c\u5b83\u662f\u8fd0\u884c NFS \u670d\u52a1\u5668 cka002 \u7684 IP\u3002 kubectl apply -f - < EOF \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u68c0\u67e5\u521b\u5efa\u7684PV\u3002 kubectl get pv \u8fd0\u884c\u7ed3\u679c NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mysql-pv 1Gi RWO Retain Available nfs 19s","title":"\u521b\u5efa PV"},{"location":"k8s/cka_cn/foundamentals/persistence/#pvc","text":"\u521b\u5efa PVC mysql-pvc \u5e76\u6307\u5b9a\u5b58\u50a8\u5927\u5c0f\u3001\u8bbf\u95ee\u6a21\u5f0f\u548c\u5b58\u50a8\u7c7b\u3002 PVC mysql-pvc \u5c06\u901a\u8fc7\u5b58\u50a8\u7c7b\u540d\u79f0\u81ea\u52a8\u4e0e PV \u7ed1\u5b9a\u3002 kubectl apply -f - < nfs-provisioner-rbac.yaml < ( cka002 ) \u4e0a\u7684 /nfsdata \u76ee\u5f55\u7684\u5377 nfs-client-root \u3002 \u628a NFS \u670d\u52a1\u5668\u7684 IP \u66ff\u6362\u4e3a\u5b9e\u9645\u7684 IP \u5730\u5740\u5373\u53ef\uff08\u8fd9\u91cc\u7528 \u8868\u793a\uff09\u3002 cat > nfs-provisioner-deployment.yaml < - name: NFS_PATH value: /nfsdata volumes: - name: nfs-client-root nfs: server: path: /nfsdata EOF kubectl apply -f nfs-provisioner-deployment.yaml","title":"\u521b\u5efaProvisioner\u7684Deloyment"},{"location":"k8s/cka_cn/foundamentals/persistence/#nfs-storageclass","text":"\u521b\u5efa StorageClass nfs-client \uff0c\u5b9a\u4e49 NFS \u5b50\u76ee\u5f55\u5916\u90e8 provisioner \u7684 Kubernetes Storage Class\u3002 \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u7f16\u8f91 nfs-storageclass.yaml \u6587\u4ef6\u3002 vi nfs-storageclass.yaml \u6dfb\u52a0\u4e0b\u9762\u7684\u4fe1\u606f\u6765\u914d\u7f6e NFS StorageClass\u3002 apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-client annotations: storageclass.kubernetes.io/is-default-class: \"true\" provisioner: k8s-sigs.io/nfs-subdir-external-provisioner parameters: pathPattern: \" ${ .PVC.namespace } / ${ .PVC.annotations.nfs.io/storage-path } \" onDelete: delete \u5e94\u7528\u4e0a\u9762\u7684yaml\u6587\u4ef6\uff0c\u4f7f\u4e4b\u751f\u6548\u3002 kubectl apply -f nfs-storageclass.yaml","title":"\u521b\u5efa NFS StorageClass"},{"location":"k8s/cka_cn/foundamentals/persistence/#pvc_2","text":"\u521b\u5efa PVC nfs-pvc-from-sc \u3002 kubectl apply -f - < mysql-with-sc-pvc-7c97d875f8-wkvr9 1/1 Running 0 3m37s 10.244.102.27 cka003 \u6211\u4eec\u73b0\u5728\u6765\u67e5\u770b NFS \u670d\u52a1\u5668 cka002 \u4e0a\u7684\u5171\u4eab\u76ee\u5f55 /nfsdata/ \u3002 ll /nfsdata/ NFS \u670d\u52a1\u5668 cka002 \u4e0a\u7684\u5171\u4eab\u76ee\u5f55 /nfsdata/ \u4e0b\u6709\u4e862\u4e2a\u5b50\u76ee\u5f55\uff0c\u4e0e\u5176\u4ed62\u4e2a\u8282\u70b9\u4e0a\u7684\u76ee\u5f55 /remote-nfs-dir/ \u4e0b\u7684\u5185\u5bb9\u662f\u4e00\u81f4\u3002 drwxrwxrwx 6 systemd-coredump root 4096 Jul 23 23 :35 dev/ drwxr-xr-x 6 systemd-coredump root 4096 Jul 23 22 :29 mysqldata/ \u547d\u540d\u7a7a\u95f4Namespace\u7684\u540d\u79f0\u4f5c\u4e3a\u76ee\u5f55\u540d\u5728 /nfsdata/ \u76ee\u5f55\u4e0b\u7528\u4e8e\u6302\u8f7d\u5230 Pod \u4e2d\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u547d\u540d\u7a7a\u95f4Namespace\u540d\u79f0\u5c06\u7528\u4e8e\u6302\u8f7d\u70b9\u3002 \u5982\u679c\u6211\u4eec\u60f3\u8981\u4f7f\u7528\u81ea\u5b9a\u4e49\u7684\u6587\u4ef6\u5939\u6765\u4ee3\u66ff\uff0c\u6211\u4eec\u9700\u8981\u58f0\u660e\u4e00\u4e2a nfs.io/storage-path \u6ce8\u91ca\uff0c\u4f8b\u5982\u4e0b\u9762\u7684\u4f8b\u5b50\u3002 \u5728\u547d\u540d\u7a7a\u95f4 kube-system \u4e0a\u521b\u5efa PVC test-claim \uff0c\u5e76\u6d88\u8d39 nfs-client \u5377\u3002 kubectl apply -f - < ..data/password lrwxrwxrwx 1 root root 15 Jul 23 16 :30 username -> ..data/username \u800c\u4e14\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u8fd92\u4e2a\u6570\u636e\u5143\u7d20\uff08 username \u548c password \uff09\u7684\u5185\u5bb9\u5c31\u662f\u6211\u4eec\u9884\u5148\u5b9a\u4e49\u7684\u3002 / # cat /tmp/secret/username admin / # cat /tmp/secret/password 123456","title":"Secret"},{"location":"k8s/cka_cn/foundamentals/persistence/#_2","text":"","title":"\u62d3\u5c55\u6848\u4f8b"},{"location":"k8s/cka_cn/foundamentals/persistence/#configmap_1","text":"\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u6587\u4ef6\u3001\u76ee\u5f55\u3001\u6216\u8005\u503c\u6765\u521b\u5efaConfigMap\u3002 \u4e0b\u9762\u6211\u4eec\u521b\u5efaConfigMap colors \uff0c\u5305\u542b\uff1a \u56db\u4e2a\u6587\u4ef6\uff0c\u6587\u4ef6\u540d\u662f\u56db\u4e2a\u989c\u8272\u3002 \u4e00\u4e2a\u6587\u4ef6\uff0c\u6587\u4ef6\u540d\u662f\u6700\u559c\u6b22\u7684\u989c\u8272\u3002 mkdir configmap cd configmap mkdir primary echo c > primary/cyan echo m > primary/magenta echo y > primary/yellow echo k > primary/black echo \"known as key\" >> primary/black echo blue > favorite \u6267\u884c\u547d\u4ee4 tree configmap \uff0c\u53ef\u4ee5\u770b\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u6587\u4ef6\u76ee\u5f55\u7ed3\u6784\u3002 configmap \u251c\u2500\u2500 favorite \u2514\u2500\u2500 primary \u251c\u2500\u2500 black \u251c\u2500\u2500 cyan \u251c\u2500\u2500 magenta \u2514\u2500\u2500 yellow \u521b\u5efa\u4e00\u4e2a ConfigMap\uff0c\u5f15\u7528\u4e0a\u9762\u6211\u4eec\u521b\u5efa\u7684\u6587\u4ef6\u3002\u786e\u4fdd\u6211\u4eec\u73b0\u5728\u5728\u8def\u5f84 ~/configmap \u4e0b\u3002 kubectl create configmap colors \\ --from-literal = text = black \\ --from-file = ./favorite \\ --from-file = ./primary/ \u67e5\u770bConfigMap colors \u7684\u5185\u5bb9\u3002 kubectl get configmap colors -o yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion: v1 data: black: | k known as key cyan: | c favorite: | blue magenta: | m text: black yellow: | y kind: ConfigMap metadata: creationTimestamp: \"2022-07-12T16:38:27Z\" name: colors namespace: dev resourceVersion: \"2377258\" uid: d5ab133f-5e4d-41d4-bc9e-2bbb22a872a1","title":"\u591a\u79cd\u65b9\u6cd5\u521b\u5efaConfigMap"},{"location":"k8s/cka_cn/foundamentals/persistence/#configmap_2","text":"\u7ee7\u7eed\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u73b0\u5728\u6211\u4eec\u51c6\u5907\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a pod-configmap-env \u7684Pod\uff0c\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf ilike \u5e76\u4eceConfigMap colors \u4e2d\u5206\u914d\u503c favorite \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env spec: containers: - name: nginx image: nginx env: - name: ilike valueFrom: configMapKeyRef: name: colors key: favorite EOF \u8fde\u63a5\u5e76\u8fdb\u5165Pod pod-configmap-env \u5185\u90e8\u3002 kubectl exec -it pod-configmap-env -- bash \u9a8c\u8bc1\u73af\u5883\u53d8\u91cf ilike \u7684\u503c\u662f blue \uff0c\u8fd9\u662f ConfigMap colors \u7684 favorite \u503c\u3002 root@pod-configmap-env:/# echo $ilike blue \u6211\u4eec\u8fd8\u53ef\u4ee5\u4f7f\u7528 ConfigMap \u7684\u6240\u6709\u952e\u503c\u5bf9\u6765\u8bbe\u7f6e Pod \u7684\u73af\u5883\u53d8\u91cf\u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env-2 spec: containers: - name: nginx image: nginx envFrom: - configMapRef: name: colors EOF \u8fde\u63a5\u5e76\u8fdb\u5165Pod pod-configmap-env-2 \u5185\u90e8\u3002 kubectl exec -it pod-configmap-env-2 -- bash \u9a8c\u8bc1\u73af\u5883\u53d8\u91cf\u7684\u503c\u662f\u6211\u4eec\u5728ConfigMap colors \u6240\u5b9a\u4e49\u7684\u952e\u503c\u5bf9\u3002 root@pod-configmap-env-2:/# echo $black k known as key root@pod-configmap-env-2:/# echo $cyan c root@pod-configmap-env-2:/# echo $favorite blue","title":"\u901a\u8fc7ConfigMap\u8bbe\u5b9a\u73af\u5883\u53d8\u91cf"},{"location":"k8s/cka_cn/foundamentals/pod/","text":"CKA\u81ea\u5b66\u7b14\u8bb08:Pod \u00b6 \u6458\u8981 \u00b6 \u7ec3\u4e60\u76ee\u6807\uff1a \u521b\u5efapod \u8ffd\u8e2apod pod\u6807\u7b7e \u9759\u6001pod \u591a\u5bb9\u5668pod \u542b\u521d\u59cb\u5316\u5bb9\u5668\u7684pod \u521b\u5efaPod \u00b6 \u521b\u5efaPod my-first-podl \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-first-pod spec: containers: - name: nginx image: nginx:mainline ports: - containerPort: 80 EOF \u9a8c\u8bc1\u521a\u521a\u521b\u5efa\u7684pod\u7684\u72b6\u6001\u3002 kubectl get pods -o wide \u8ffd\u8e2apod \u00b6 \u68c0\u67e5\u521a\u521a\u521b\u5efa\u7684pod\u7684\u65e5\u5fd7\u3002 kubectl logs my-first-pod \u5982\u679c\u65e5\u5fd7\u6216\u8005\u5176\u4ed6\u547d\u4ee4\u8f93\u51fa\u7684\u4fe1\u606f\u4e0d\u8db3\u4ee5\u5e2e\u52a9\u6211\u4eec\u67e5\u627e\u6839\u672c\u539f\u56e0\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7 kubectl exec -it -- bash \u6765\u8fdb\u5165pod\u5185\u90e8\u8fdb\u884c\u5206\u6790\u3002 kubectl exec -it my-first-pod -- bash root@my-first-pod:/# ls root@my-first-pod:/# cd bin root@my-first-pod:/bin# ls root@my-first-pod:/bin# exit \u6267\u884c\u547d\u4ee4 kubectl explain pod.spec \u53ef\u4ee5\u5f97\u5230pod\u5bf9\u5e94\u7684yaml\u6587\u4ef6\u4e2dSpec\u533a\u6bb5\u7684\u5185\u5bb9\u3002 \u6211\u4eec\u53ef\u4ee5\u67e5\u770b Pod \u8d44\u6e90\u7684\u5b98\u65b9 API \u53c2\u8003\u6587\u6863\uff0c\u6216\u8005\u4f7f\u7528 kubectl explain pod \u547d\u4ee4\u884c\u83b7\u53d6\u8be5\u8d44\u6e90\u7684\u63cf\u8ff0\u4fe1\u606f\u3002\u901a\u8fc7\u5728\u8d44\u6e90\u7c7b\u578b\u540e\u6dfb\u52a0 . \uff0cexplain \u547d\u4ee4\u4f1a\u63d0\u4f9b\u8be5\u6307\u5b9a\u5b57\u6bb5\u7684\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl explain pod.kind kubectl explain pod.spec kubectl explain pod.spec.containers kubectl explain pod.spec.containers.name pod\u7684\u6807\u7b7e \u00b6 \u901a\u8fc7\u9009\u9879 --show-labels \u6765\u83b7\u5f97pod\u7684\u6807\u7b7e\u3002 kubectl get pods kubectl get pods --show-labels \u7ed9pod pod my-first-pod \u6dfb\u52a02\u4e2a\u6807\u7b7e\u3002 kubectl label pod my-first-pod nginx = mainline kubectl label pod my-first-pod env = demo kubectl get pods --show-labels \u901a\u8fc7\u6807\u7b7e\u6765\u67e5\u627epod\u3002 kubectl get pod -l env = demo kubectl get pod -l env = demo,nginx = mainline kubectl get pod -l env = training \u79fb\u9664pod\u7684\u6807\u7b7e\u3002 kubectl label pods my-first-pod env- kubectl get pods --show-labels \u63cf\u8ff0 Pod\u3002 kubectl describe pod my-first-pod \u5220\u9664pod. \u8fd0\u884c\u547d\u4ee4 watch kubectl get pods \u6765\u83b7\u53d6pod\u7684\u72b6\u6001\u3002 kubectl delete pod my-first-pod watch kubectl get pods \u9759\u6001pod \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u9759\u6001pod\u3002 kubectl \u4f1a\u81ea\u52a8\u68c0\u67e5 /etc/kubernetes/manifests/ \u4e2d\u7684 YAML \u6587\u4ef6\uff0c\u5e76\u5728\u68c0\u6d4b\u5230\u540e\u521b\u5efa\u9759\u6001 Pod\u3002 \u6f14\u793a\uff1a \u67e5\u770b\u7cfb\u7edf\u521d\u59cb\u5316\u540e\u5df2\u7ecf\u5b58\u5728\u7684\u9759\u6001pod\u3002 ll /etc/kubernetes/manifests/ \u8fd0\u884c\u7ed3\u679c\uff1a -rw------- 1 root root 2292 Jul 23 10:45 etcd.yaml -rw------- 1 root root 3889 Jul 23 10:45 kube-apiserver.yaml -rw------- 1 root root 3395 Jul 23 10:45 kube-controller-manager.yaml -rw------- 1 root root 1464 Jul 23 10:45 kube-scheduler.yaml \u5728 /etc/kubernetes/manifests/ \u76ee\u5f55\u4e2d\u521b\u5efayaml\u6587\u4ef6 my-nginx.yaml \uff0c\u4e00\u65e6\u6587\u4ef6\u521b\u5efa\u5b8c\u6210\uff0c\u9759\u6001Pod my-nginx \u5c06\u4f1a\u88ab\u81ea\u52a8\u521b\u5efa\u3002 kubectl run my-nginx --image = nginx:mainline --dry-run = client -n default -oyaml | sudo tee /etc/kubernetes/manifests/my-nginx.yaml \u68c0\u67e5 Pod my-nginx \u7684\u72b6\u6001\u3002Pod \u540d\u79f0\u4e2d\u5305\u542b\u8282\u70b9\u540d\u79f0 cka001 \uff0c\u8fd9\u610f\u5473\u7740\u8be5 Pod \u6b63\u5728\u8282\u70b9 cka001 \u4e0a\u8fd0\u884c\u3002 kubectl get pod -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cka001 1/1 Running 0 20s 10.244.228.196 cka001 \u5220\u9664 /etc/kubernetes/manifests/my-nginx.yaml \u8fd9\u4e2a yaml \u6587\u4ef6\uff0c\u5bf9\u5e94\u7684\u9759\u6001 Pod my-nginx \u5c06\u4f1a\u88ab\u81ea\u52a8\u5220\u9664\u3002 sudo rm /etc/kubernetes/manifests/my-nginx.yaml \u591a\u5bb9\u5668Pod \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u591a\u5bb9\u5668Pod \u63cf\u8ff0\u8be5Pod \u68c0\u67e5Pod\u7684\u65e5\u5fd7 \u68c0\u67e5\u5bb9\u5668\u7684\u65e5\u5fd7 \u6f14\u793a\uff1a \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a multi-container-pod \u7684Pod\uff0c\u5305\u542b\u591a\u4e2a\u5bb9\u5668\uff1a container-1-nginx \u548c container-2-alpine \u3002 kubectl apply -f - << EOF apiVersion : v1 kind : Pod metadata : name : multi-container-pod spec : containers : - name : container-1-nginx image : nginx ports : - containerPort : 80 - name : container-2-alpine image : alpine command : [ \"watch\" , \"wget\" , \"-qO-\" , \"localhost\" ] EOF \u83b7\u53d6pod\u72b6\u6001\u3002 kubectl get pod multi-container-pod \u8fd0\u884c\u7ed3\u679c \u83b7\u53d6pod\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl describe pod multi-container-pod \u8fd0\u884c\u7ed3\u679c\uff1a ....... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 41s default-scheduler Successfully assigned dev/multi-container-pod to cka002 Normal Pulling 40s kubelet Pulling image \"nginx\" Normal Pulled 23s kubelet Successfully pulled image \"nginx\" in 16.767129903s Normal Created 22s kubelet Created container container-1-nginx Normal Started 22s kubelet Started container container-1-nginx Normal Pulling 22s kubelet Pulling image \"alpine\" Normal Pulled 14s kubelet Successfully pulled image \"alpine\" in 7.776104353s Normal Created 14s kubelet Created container container-2-alpine Normal Started 14s kubelet Started container container-2-alpine \u5bf9\u4e8e\u591a\u5bb9\u5668 Pod\uff0c\u5982\u679c\u6211\u4eec\u60f3\u901a\u8fc7\u547d\u4ee4 kubectl logs \u83b7\u53d6 Pod \u7684\u65e5\u5fd7\uff0c\u9700\u8981\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\u3002\u5982\u679c\u4e0d\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\uff0c\u5c06\u4f1a\u6536\u5230\u9519\u8bef\u4fe1\u606f\u3002 kubectl logs multi-container-pod \u8fd0\u884c\u7ed3\u679c error: a container name must be specified for pod multi-container-pod, choose one of: [ container-1-nginx container-2-alpine ] \u6307\u5b9a\u5bb9\u5668\u540d\u79f0\uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u5230\u5bf9\u5e94\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl logs multi-container-pod container-1-nginx \u8fd0\u884c\u7ed3\u679c ...... ::1 - - [ 23 /Jul/2022:04:06:37 +0000 ] \"GET / HTTP/1.1\" 200 615 \"-\" \"Wget\" \"-\" \u5982\u679c\u6211\u4eec\u9700\u8981\u4f7f\u7528\u547d\u4ee4 kubectl exec -it -c -- \u767b\u5f55\u5230 Pod \u4e2d\uff0c\u540c\u6837\u9700\u8981\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\u3002\u5982\u679c\u6ca1\u6709\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\uff0c\u4f1a\u51fa\u73b0\u9519\u8bef\u3002 kubectl exec -it multi-container-pod -c container-1-nginx -- /bin/bash root@multi-container-pod:/# ls \u5220\u9664\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u3002 kubectl delete pod multi-container-pod \u4e0b\u9762\u662f\u4e00\u4e2a\u57fa\u672c\u7684yaml\u6587\u4ef6\u7528\u6765\u521b\u5efa\u591a\u5bb9\u5668pod\u3002 kubectl apply -f - << EOF apiVersion : v1 kind : Pod metadata : name : my-multi-pod spec : containers : - image : nginx name : nginx - image : memcached name : memcached - image : redis name : redis EOF \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a my-busybox \u7684Pod\uff0c\u5e76\u5728\u5176\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a container-1-busybox \u7684\u5bb9\u5668\u3002\u8be5\u5bb9\u5668\u5c06\u628a\u6d88\u606f\u5199\u5165\u5230\u6587\u4ef6 /var/log/my-pod-busybox.log \u4e2d\u3002 \u5411Pod my-busybox \u4e2d\u6dfb\u52a0\u53e6\u4e00\u4e2a\u5bb9\u5668 container-2-busybox \uff08Sidecar\uff09\u3002Sidecar\u5bb9\u5668\u4ece\u6587\u4ef6 /var/log/my-pod-busybox.log \u4e2d\u8bfb\u53d6\u6d88\u606f\u3002 \u63d0\u793a\uff1a\u521b\u5efa\u4e00\u4e2aVolume\u6765\u5b58\u50a8\u65e5\u5fd7\u6587\u4ef6\uff0c\u5e76\u4e0e\u4e24\u4e2a\u5bb9\u5668\u5171\u4eab\u3002 \u6f14\u793a\uff1a \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a my-busybox \u7684 Pod\uff0c\u5176\u4e2d\u5305\u542b\u4e00\u4e2a\u5bb9\u5668 container-1-busybox \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-busybox spec: containers: - name: container-1-busybox image: busybox args: - /bin/sh - -c - > i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=$((i+1)); sleep 1; done EOF \u5728 Kubernetes \u6587\u6863\u4e2d\u641c\u7d22 emptyDir \u3002 \u53c2\u8003\u4ee5\u4e0b\u6a21\u677f\u7528\u4e8e emptyDir \uff1a https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/ \u5c06\u4ee5\u4e0b\u65b0\u529f\u80fd\u6dfb\u52a0\u5230 Pod \u4e2d\uff1a Volume\uff1a \u5377\u540d\u79f0\uff1a logfile \u7c7b\u578b\uff1a emptyDir \u66f4\u65b0\u73b0\u6709\u5bb9\u5668\uff1a name: container-1-busybox volumeMounts name: logfile mounthPath: /var/log \u6dfb\u52a0\u65b0\u5bb9\u5668\uff1a name: container-2-busybox image: busybox args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log'] volumeMounts: name: logfile mountPath: /var/log kubectl get pod my-busybox -o yaml > my-busybox.yaml vi my-busybox.yaml kubectl delete pod my-busybox kubectl apply -f my-busybox.yaml kubectl logs my-busybox -c container-2-busybox \u66f4\u65b0\u540e\u7684\u6587\u4ef6 my-busybox.yaml \u5982\u4e0b\uff1a apiVersion : v1 kind : Pod metadata : annotations : cni.projectcalico.org/containerID : 89644b6b073cd152f94b4cae7bdea6bbc3292cf59afd4f28102bd74f0205c9e4 cni.projectcalico.org/podIP : 10.244.102.20/32 cni.projectcalico.org/podIPs : 10.244.102.20/32 kubectl.kubernetes.io/last-applied-configuration : | {\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"my-busybox\",\"namespace\":\"dev\"},\"spec\":{\"containers\":[{\"args\":[\"/bin/sh\",\"-c\",\"i=0; while true; do\\n echo \\\"Hello message from container-1: \\\" \\u003e\\u003e /var/log/my-pod-busybox.log;\\n i=1;\\n sleep 1;\\ndone\\n\"],\"image\":\"busybox\",\"name\":\"container-1-busybox\"}]}} creationTimestamp : \"2022-07-29T22:58:27Z\" name : my-busybox namespace : dev resourceVersion : \"1185720\" uid : c5e62a16-4459-4828-a441-7d1471b89a56 spec : containers : - name : container-2-busybox image : busybox args : [ '/bin/sh' , '-c' , 'tail -n+1 -f /var/log/my-pod-busybox.log' ] volumeMounts : - name : logfile mountPath : /var/log - args : - /bin/sh - -c - | i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=1; sleep 1; done image : busybox imagePullPolicy : Always name : container-1-busybox resources : {} terminationMessagePath : /dev/termination-log terminationMessagePolicy : File volumeMounts : - name : logfile mountPath : /var/log - mountPath : /var/run/secrets/kubernetes.io/serviceaccount name : kube-api-access-mhxlf readOnly : true dnsPolicy : ClusterFirst enableServiceLinks : true nodeName : cka003 preemptionPolicy : PreemptLowerPriority priority : 0 restartPolicy : Always schedulerName : default-scheduler securityContext : {} serviceAccount : default serviceAccountName : default terminationGracePeriodSeconds : 30 tolerations : - effect : NoExecute key : node.kubernetes.io/not-ready operator : Exists tolerationSeconds : 300 - effect : NoExecute key : node.kubernetes.io/unreachable operator : Exists tolerationSeconds : 300 volumes : - name : logfile emptyDir : {} - name : kube-api-access-mhxlf projected : defaultMode : 420 sources : - serviceAccountToken : expirationSeconds : 3607 path : token - configMap : items : - key : ca.crt path : ca.crt name : kube-root-ca.crt - downwardAPI : items : - fieldRef : apiVersion : v1 fieldPath : metadata.namespace path : namespace status : conditions : - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:27Z\" status : \"True\" type : Initialized - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:30Z\" status : \"True\" type : Ready - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:30Z\" status : \"True\" type : ContainersReady - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:27Z\" status : \"True\" type : PodScheduled containerStatuses : - containerID : containerd://fd42d4ba4d94d8918d8846327b1db2328be13c5f93f381877ff0228ed7b5468d image : docker.io/library/busybox:latest imageID : docker.io/library/busybox@sha256:0e97a8ca6955f22dbc7db9e9dbe970971f423541e52c34b8cb96ccc88d6a3883 lastState : {} name : container-1-busybox ready : true restartCount : 0 started : true state : running : startedAt : \"2022-07-29T22:58:30Z\" hostIP : phase : Running podIP : 10.244.102.20 podIPs : - ip : 10.244.102.20 qosClass : BestEffort startTime : \"2022-07-29T22:58:27Z\" \u6e05\u7406\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u3002 kubectl delete pod my-busybox \u542b\u521d\u59cb\u5316\u5bb9\u5668Pod \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u62e5\u6709\u4e24\u4e2a\u521d\u59cb\u5316\u5bb9\u5668\u7684 Pod myapp-pod \u3002 myapp-container init-mydb \u521b\u5efa\u4e24\u4e2a\u670d\u52a1\uff1a myservice mydb \u6f14\u793a\u9884\u671f\u7ed3\u8bba\uff1a myapp-container \u7b49\u5f85\u670d\u52a1 myservice \u542f\u52a8\uff0c\u4ee5\u89e3\u6790\u540d\u79f0 myservice.dev.svc.cluster.local init-mydb \u7b49\u5f85\u670d\u52a1 mydb \u542f\u52a8\uff0c\u4ee5\u89e3\u6790\u540d\u79f0 mydb.dev.svc.cluster.local \u3002 \u6f14\u793a\uff1a \u521b\u5efa\u540d\u4e3a myapp-pod.yaml \u7684yaml\u6587\u4ef6\uff0c\u5e76\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\u3002 \u6ce8\u610f\uff1a\u7531\u4e8e\u547d\u4ee4 $(cat /var/..... \u5c06\u88ab\u89c6\u4e3a\u4e3b\u673a\u53d8\u91cf\uff0c\u56e0\u6b64\u6211\u4eec\u4e0d\u80fd\u4f7f\u7528echo\u751f\u6210\u8be5\u6587\u4ef6\u3002\u5b83\u662f\u5bb9\u5668\u672c\u8eab\u7684\u53d8\u91cf\u3002 vi myapp-pod.yaml \u6587\u4ef6\u5185\u5bb9 apiVersion : v1 kind : Pod metadata : name : myapp-pod labels : app : myapp spec : containers : - name : myapp-container image : busybox:1.28 command : [ 'sh' , '-c' , 'echo The app is running! && sleep 3600' ] initContainers : - name : init-myservice image : busybox:1.28 command : [ 'sh' , '-c' , \"until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done\" ] - name : init-mydb image : busybox:1.28 command : [ 'sh' , '-c' , \"until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done\" ] \u7528\u4e0a\u9762\u521b\u5efa\u7684yaml\u6587\u4ef6\u521b\u5efaPod myapp-pod \u3002 kubectl apply -f myapp-pod.yaml \u68c0\u67e5pod\u7684\u72b6\u6001\u3002 kubectl get pod myapp-pod \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE myapp-pod 0/1 Init:0/2 0 12m \u68c0\u67e5Pod\uff0c\u53ef\u4ee5\u770b\u5230\u4e24\u4e2a\u9519\u8bef\uff1a nslookup: \u65e0\u6cd5\u89e3\u6790'myservice.dev.svc.cluster.local' Pod \"myapp-pod\"\u4e2d\u7684\u5bb9\u5668\u201cinit-mydb\u201d\u6b63\u5728\u7b49\u5f85\u542f\u52a8\uff1aPodInitializing kubectl logs myapp-pod -c init-myservice # Inspect the first init container kubectl logs myapp-pod -c init-mydb # Inspect the second init container \u5728\u8fd9\u4e2a\u65f6\u5019\uff0c\u8fd9\u4e9b init \u5bb9\u5668\u5c06\u7b49\u5f85\u53d1\u73b0\u540d\u4e3a mydb \u548c myservice \u7684\u670d\u52a1\u3002 \u521b\u5efa mydb \u548c myservice \u670d\u52a1\uff1a kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: myservice spec: ports: - protocol: TCP port: 80 targetPort: 9376 --- apiVersion: v1 kind: Service metadata: name: mydb spec: ports: - protocol: TCP port: 80 targetPort: 9377 EOF \u67e5\u770b\u521b\u5efa\u7684\u670d\u52a1\u7684\u72b6\u6001\u3002 kubectl get service \u521b\u5efa\u76842\u4e2a\u670d\u52a1\u90fd\u662f\u8fd0\u884c\u72b6\u6001\u3002 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mydb ClusterIP 11.244.239.149 80/TCP 6s myservice ClusterIP 11.244.116.126 80/TCP 6s \u518d\u6b21\u67e5\u770bpod\u7684\u72b6\u6001\u3002 kubectl get pod myapp-pod -o wide pod\u5df2\u7ecf\u6b63\u5e38\u8fd0\u884c\u4e86\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-pod 0/1 Init:0/2 0 2m40s 10.244.112.2 cka002 \u73b0\u5728\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u90a3\u4e9b\u521d\u59cb\u5316\u5bb9\u5668\u90fd\u5df2\u7ecf\u5b8c\u6210\uff0c myapp-pod Pod \u8fdb\u5165\u4e86 Running \u72b6\u6001\u3002 \u5220\u9664\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u3002 kubectl delete service mydb myservice kubectl delete pod myapp-pod \u53c2\u8003\uff1a Pod basics Lifecycle & phases Kubernetes pod design pattern","title":"Pod"},{"location":"k8s/cka_cn/foundamentals/pod/#cka8pod","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb08:Pod"},{"location":"k8s/cka_cn/foundamentals/pod/#_1","text":"\u7ec3\u4e60\u76ee\u6807\uff1a \u521b\u5efapod \u8ffd\u8e2apod pod\u6807\u7b7e \u9759\u6001pod \u591a\u5bb9\u5668pod \u542b\u521d\u59cb\u5316\u5bb9\u5668\u7684pod","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/pod/#pod","text":"\u521b\u5efaPod my-first-podl \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-first-pod spec: containers: - name: nginx image: nginx:mainline ports: - containerPort: 80 EOF \u9a8c\u8bc1\u521a\u521a\u521b\u5efa\u7684pod\u7684\u72b6\u6001\u3002 kubectl get pods -o wide","title":"\u521b\u5efaPod"},{"location":"k8s/cka_cn/foundamentals/pod/#pod_1","text":"\u68c0\u67e5\u521a\u521a\u521b\u5efa\u7684pod\u7684\u65e5\u5fd7\u3002 kubectl logs my-first-pod \u5982\u679c\u65e5\u5fd7\u6216\u8005\u5176\u4ed6\u547d\u4ee4\u8f93\u51fa\u7684\u4fe1\u606f\u4e0d\u8db3\u4ee5\u5e2e\u52a9\u6211\u4eec\u67e5\u627e\u6839\u672c\u539f\u56e0\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7 kubectl exec -it -- bash \u6765\u8fdb\u5165pod\u5185\u90e8\u8fdb\u884c\u5206\u6790\u3002 kubectl exec -it my-first-pod -- bash root@my-first-pod:/# ls root@my-first-pod:/# cd bin root@my-first-pod:/bin# ls root@my-first-pod:/bin# exit \u6267\u884c\u547d\u4ee4 kubectl explain pod.spec \u53ef\u4ee5\u5f97\u5230pod\u5bf9\u5e94\u7684yaml\u6587\u4ef6\u4e2dSpec\u533a\u6bb5\u7684\u5185\u5bb9\u3002 \u6211\u4eec\u53ef\u4ee5\u67e5\u770b Pod \u8d44\u6e90\u7684\u5b98\u65b9 API \u53c2\u8003\u6587\u6863\uff0c\u6216\u8005\u4f7f\u7528 kubectl explain pod \u547d\u4ee4\u884c\u83b7\u53d6\u8be5\u8d44\u6e90\u7684\u63cf\u8ff0\u4fe1\u606f\u3002\u901a\u8fc7\u5728\u8d44\u6e90\u7c7b\u578b\u540e\u6dfb\u52a0 . \uff0cexplain \u547d\u4ee4\u4f1a\u63d0\u4f9b\u8be5\u6307\u5b9a\u5b57\u6bb5\u7684\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl explain pod.kind kubectl explain pod.spec kubectl explain pod.spec.containers kubectl explain pod.spec.containers.name","title":"\u8ffd\u8e2apod"},{"location":"k8s/cka_cn/foundamentals/pod/#pod_2","text":"\u901a\u8fc7\u9009\u9879 --show-labels \u6765\u83b7\u5f97pod\u7684\u6807\u7b7e\u3002 kubectl get pods kubectl get pods --show-labels \u7ed9pod pod my-first-pod \u6dfb\u52a02\u4e2a\u6807\u7b7e\u3002 kubectl label pod my-first-pod nginx = mainline kubectl label pod my-first-pod env = demo kubectl get pods --show-labels \u901a\u8fc7\u6807\u7b7e\u6765\u67e5\u627epod\u3002 kubectl get pod -l env = demo kubectl get pod -l env = demo,nginx = mainline kubectl get pod -l env = training \u79fb\u9664pod\u7684\u6807\u7b7e\u3002 kubectl label pods my-first-pod env- kubectl get pods --show-labels \u63cf\u8ff0 Pod\u3002 kubectl describe pod my-first-pod \u5220\u9664pod. \u8fd0\u884c\u547d\u4ee4 watch kubectl get pods \u6765\u83b7\u53d6pod\u7684\u72b6\u6001\u3002 kubectl delete pod my-first-pod watch kubectl get pods","title":"pod\u7684\u6807\u7b7e"},{"location":"k8s/cka_cn/foundamentals/pod/#pod_3","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u9759\u6001pod\u3002 kubectl \u4f1a\u81ea\u52a8\u68c0\u67e5 /etc/kubernetes/manifests/ \u4e2d\u7684 YAML \u6587\u4ef6\uff0c\u5e76\u5728\u68c0\u6d4b\u5230\u540e\u521b\u5efa\u9759\u6001 Pod\u3002 \u6f14\u793a\uff1a \u67e5\u770b\u7cfb\u7edf\u521d\u59cb\u5316\u540e\u5df2\u7ecf\u5b58\u5728\u7684\u9759\u6001pod\u3002 ll /etc/kubernetes/manifests/ \u8fd0\u884c\u7ed3\u679c\uff1a -rw------- 1 root root 2292 Jul 23 10:45 etcd.yaml -rw------- 1 root root 3889 Jul 23 10:45 kube-apiserver.yaml -rw------- 1 root root 3395 Jul 23 10:45 kube-controller-manager.yaml -rw------- 1 root root 1464 Jul 23 10:45 kube-scheduler.yaml \u5728 /etc/kubernetes/manifests/ \u76ee\u5f55\u4e2d\u521b\u5efayaml\u6587\u4ef6 my-nginx.yaml \uff0c\u4e00\u65e6\u6587\u4ef6\u521b\u5efa\u5b8c\u6210\uff0c\u9759\u6001Pod my-nginx \u5c06\u4f1a\u88ab\u81ea\u52a8\u521b\u5efa\u3002 kubectl run my-nginx --image = nginx:mainline --dry-run = client -n default -oyaml | sudo tee /etc/kubernetes/manifests/my-nginx.yaml \u68c0\u67e5 Pod my-nginx \u7684\u72b6\u6001\u3002Pod \u540d\u79f0\u4e2d\u5305\u542b\u8282\u70b9\u540d\u79f0 cka001 \uff0c\u8fd9\u610f\u5473\u7740\u8be5 Pod \u6b63\u5728\u8282\u70b9 cka001 \u4e0a\u8fd0\u884c\u3002 kubectl get pod -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cka001 1/1 Running 0 20s 10.244.228.196 cka001 \u5220\u9664 /etc/kubernetes/manifests/my-nginx.yaml \u8fd9\u4e2a yaml \u6587\u4ef6\uff0c\u5bf9\u5e94\u7684\u9759\u6001 Pod my-nginx \u5c06\u4f1a\u88ab\u81ea\u52a8\u5220\u9664\u3002 sudo rm /etc/kubernetes/manifests/my-nginx.yaml","title":"\u9759\u6001pod"},{"location":"k8s/cka_cn/foundamentals/pod/#pod_4","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u591a\u5bb9\u5668Pod \u63cf\u8ff0\u8be5Pod \u68c0\u67e5Pod\u7684\u65e5\u5fd7 \u68c0\u67e5\u5bb9\u5668\u7684\u65e5\u5fd7 \u6f14\u793a\uff1a \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a multi-container-pod \u7684Pod\uff0c\u5305\u542b\u591a\u4e2a\u5bb9\u5668\uff1a container-1-nginx \u548c container-2-alpine \u3002 kubectl apply -f - << EOF apiVersion : v1 kind : Pod metadata : name : multi-container-pod spec : containers : - name : container-1-nginx image : nginx ports : - containerPort : 80 - name : container-2-alpine image : alpine command : [ \"watch\" , \"wget\" , \"-qO-\" , \"localhost\" ] EOF \u83b7\u53d6pod\u72b6\u6001\u3002 kubectl get pod multi-container-pod \u8fd0\u884c\u7ed3\u679c \u83b7\u53d6pod\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl describe pod multi-container-pod \u8fd0\u884c\u7ed3\u679c\uff1a ....... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 41s default-scheduler Successfully assigned dev/multi-container-pod to cka002 Normal Pulling 40s kubelet Pulling image \"nginx\" Normal Pulled 23s kubelet Successfully pulled image \"nginx\" in 16.767129903s Normal Created 22s kubelet Created container container-1-nginx Normal Started 22s kubelet Started container container-1-nginx Normal Pulling 22s kubelet Pulling image \"alpine\" Normal Pulled 14s kubelet Successfully pulled image \"alpine\" in 7.776104353s Normal Created 14s kubelet Created container container-2-alpine Normal Started 14s kubelet Started container container-2-alpine \u5bf9\u4e8e\u591a\u5bb9\u5668 Pod\uff0c\u5982\u679c\u6211\u4eec\u60f3\u901a\u8fc7\u547d\u4ee4 kubectl logs \u83b7\u53d6 Pod \u7684\u65e5\u5fd7\uff0c\u9700\u8981\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\u3002\u5982\u679c\u4e0d\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\uff0c\u5c06\u4f1a\u6536\u5230\u9519\u8bef\u4fe1\u606f\u3002 kubectl logs multi-container-pod \u8fd0\u884c\u7ed3\u679c error: a container name must be specified for pod multi-container-pod, choose one of: [ container-1-nginx container-2-alpine ] \u6307\u5b9a\u5bb9\u5668\u540d\u79f0\uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u5230\u5bf9\u5e94\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl logs multi-container-pod container-1-nginx \u8fd0\u884c\u7ed3\u679c ...... ::1 - - [ 23 /Jul/2022:04:06:37 +0000 ] \"GET / HTTP/1.1\" 200 615 \"-\" \"Wget\" \"-\" \u5982\u679c\u6211\u4eec\u9700\u8981\u4f7f\u7528\u547d\u4ee4 kubectl exec -it -c -- \u767b\u5f55\u5230 Pod \u4e2d\uff0c\u540c\u6837\u9700\u8981\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\u3002\u5982\u679c\u6ca1\u6709\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\uff0c\u4f1a\u51fa\u73b0\u9519\u8bef\u3002 kubectl exec -it multi-container-pod -c container-1-nginx -- /bin/bash root@multi-container-pod:/# ls \u5220\u9664\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u3002 kubectl delete pod multi-container-pod \u4e0b\u9762\u662f\u4e00\u4e2a\u57fa\u672c\u7684yaml\u6587\u4ef6\u7528\u6765\u521b\u5efa\u591a\u5bb9\u5668pod\u3002 kubectl apply -f - << EOF apiVersion : v1 kind : Pod metadata : name : my-multi-pod spec : containers : - image : nginx name : nginx - image : memcached name : memcached - image : redis name : redis EOF \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a my-busybox \u7684Pod\uff0c\u5e76\u5728\u5176\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a container-1-busybox \u7684\u5bb9\u5668\u3002\u8be5\u5bb9\u5668\u5c06\u628a\u6d88\u606f\u5199\u5165\u5230\u6587\u4ef6 /var/log/my-pod-busybox.log \u4e2d\u3002 \u5411Pod my-busybox \u4e2d\u6dfb\u52a0\u53e6\u4e00\u4e2a\u5bb9\u5668 container-2-busybox \uff08Sidecar\uff09\u3002Sidecar\u5bb9\u5668\u4ece\u6587\u4ef6 /var/log/my-pod-busybox.log \u4e2d\u8bfb\u53d6\u6d88\u606f\u3002 \u63d0\u793a\uff1a\u521b\u5efa\u4e00\u4e2aVolume\u6765\u5b58\u50a8\u65e5\u5fd7\u6587\u4ef6\uff0c\u5e76\u4e0e\u4e24\u4e2a\u5bb9\u5668\u5171\u4eab\u3002 \u6f14\u793a\uff1a \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a my-busybox \u7684 Pod\uff0c\u5176\u4e2d\u5305\u542b\u4e00\u4e2a\u5bb9\u5668 container-1-busybox \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-busybox spec: containers: - name: container-1-busybox image: busybox args: - /bin/sh - -c - > i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=$((i+1)); sleep 1; done EOF \u5728 Kubernetes \u6587\u6863\u4e2d\u641c\u7d22 emptyDir \u3002 \u53c2\u8003\u4ee5\u4e0b\u6a21\u677f\u7528\u4e8e emptyDir \uff1a https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/ \u5c06\u4ee5\u4e0b\u65b0\u529f\u80fd\u6dfb\u52a0\u5230 Pod \u4e2d\uff1a Volume\uff1a \u5377\u540d\u79f0\uff1a logfile \u7c7b\u578b\uff1a emptyDir \u66f4\u65b0\u73b0\u6709\u5bb9\u5668\uff1a name: container-1-busybox volumeMounts name: logfile mounthPath: /var/log \u6dfb\u52a0\u65b0\u5bb9\u5668\uff1a name: container-2-busybox image: busybox args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log'] volumeMounts: name: logfile mountPath: /var/log kubectl get pod my-busybox -o yaml > my-busybox.yaml vi my-busybox.yaml kubectl delete pod my-busybox kubectl apply -f my-busybox.yaml kubectl logs my-busybox -c container-2-busybox \u66f4\u65b0\u540e\u7684\u6587\u4ef6 my-busybox.yaml \u5982\u4e0b\uff1a apiVersion : v1 kind : Pod metadata : annotations : cni.projectcalico.org/containerID : 89644b6b073cd152f94b4cae7bdea6bbc3292cf59afd4f28102bd74f0205c9e4 cni.projectcalico.org/podIP : 10.244.102.20/32 cni.projectcalico.org/podIPs : 10.244.102.20/32 kubectl.kubernetes.io/last-applied-configuration : | {\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"my-busybox\",\"namespace\":\"dev\"},\"spec\":{\"containers\":[{\"args\":[\"/bin/sh\",\"-c\",\"i=0; while true; do\\n echo \\\"Hello message from container-1: \\\" \\u003e\\u003e /var/log/my-pod-busybox.log;\\n i=1;\\n sleep 1;\\ndone\\n\"],\"image\":\"busybox\",\"name\":\"container-1-busybox\"}]}} creationTimestamp : \"2022-07-29T22:58:27Z\" name : my-busybox namespace : dev resourceVersion : \"1185720\" uid : c5e62a16-4459-4828-a441-7d1471b89a56 spec : containers : - name : container-2-busybox image : busybox args : [ '/bin/sh' , '-c' , 'tail -n+1 -f /var/log/my-pod-busybox.log' ] volumeMounts : - name : logfile mountPath : /var/log - args : - /bin/sh - -c - | i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=1; sleep 1; done image : busybox imagePullPolicy : Always name : container-1-busybox resources : {} terminationMessagePath : /dev/termination-log terminationMessagePolicy : File volumeMounts : - name : logfile mountPath : /var/log - mountPath : /var/run/secrets/kubernetes.io/serviceaccount name : kube-api-access-mhxlf readOnly : true dnsPolicy : ClusterFirst enableServiceLinks : true nodeName : cka003 preemptionPolicy : PreemptLowerPriority priority : 0 restartPolicy : Always schedulerName : default-scheduler securityContext : {} serviceAccount : default serviceAccountName : default terminationGracePeriodSeconds : 30 tolerations : - effect : NoExecute key : node.kubernetes.io/not-ready operator : Exists tolerationSeconds : 300 - effect : NoExecute key : node.kubernetes.io/unreachable operator : Exists tolerationSeconds : 300 volumes : - name : logfile emptyDir : {} - name : kube-api-access-mhxlf projected : defaultMode : 420 sources : - serviceAccountToken : expirationSeconds : 3607 path : token - configMap : items : - key : ca.crt path : ca.crt name : kube-root-ca.crt - downwardAPI : items : - fieldRef : apiVersion : v1 fieldPath : metadata.namespace path : namespace status : conditions : - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:27Z\" status : \"True\" type : Initialized - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:30Z\" status : \"True\" type : Ready - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:30Z\" status : \"True\" type : ContainersReady - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:27Z\" status : \"True\" type : PodScheduled containerStatuses : - containerID : containerd://fd42d4ba4d94d8918d8846327b1db2328be13c5f93f381877ff0228ed7b5468d image : docker.io/library/busybox:latest imageID : docker.io/library/busybox@sha256:0e97a8ca6955f22dbc7db9e9dbe970971f423541e52c34b8cb96ccc88d6a3883 lastState : {} name : container-1-busybox ready : true restartCount : 0 started : true state : running : startedAt : \"2022-07-29T22:58:30Z\" hostIP : phase : Running podIP : 10.244.102.20 podIPs : - ip : 10.244.102.20 qosClass : BestEffort startTime : \"2022-07-29T22:58:27Z\" \u6e05\u7406\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u3002 kubectl delete pod my-busybox","title":"\u591a\u5bb9\u5668Pod"},{"location":"k8s/cka_cn/foundamentals/pod/#pod_5","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u62e5\u6709\u4e24\u4e2a\u521d\u59cb\u5316\u5bb9\u5668\u7684 Pod myapp-pod \u3002 myapp-container init-mydb \u521b\u5efa\u4e24\u4e2a\u670d\u52a1\uff1a myservice mydb \u6f14\u793a\u9884\u671f\u7ed3\u8bba\uff1a myapp-container \u7b49\u5f85\u670d\u52a1 myservice \u542f\u52a8\uff0c\u4ee5\u89e3\u6790\u540d\u79f0 myservice.dev.svc.cluster.local init-mydb \u7b49\u5f85\u670d\u52a1 mydb \u542f\u52a8\uff0c\u4ee5\u89e3\u6790\u540d\u79f0 mydb.dev.svc.cluster.local \u3002 \u6f14\u793a\uff1a \u521b\u5efa\u540d\u4e3a myapp-pod.yaml \u7684yaml\u6587\u4ef6\uff0c\u5e76\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\u3002 \u6ce8\u610f\uff1a\u7531\u4e8e\u547d\u4ee4 $(cat /var/..... \u5c06\u88ab\u89c6\u4e3a\u4e3b\u673a\u53d8\u91cf\uff0c\u56e0\u6b64\u6211\u4eec\u4e0d\u80fd\u4f7f\u7528echo\u751f\u6210\u8be5\u6587\u4ef6\u3002\u5b83\u662f\u5bb9\u5668\u672c\u8eab\u7684\u53d8\u91cf\u3002 vi myapp-pod.yaml \u6587\u4ef6\u5185\u5bb9 apiVersion : v1 kind : Pod metadata : name : myapp-pod labels : app : myapp spec : containers : - name : myapp-container image : busybox:1.28 command : [ 'sh' , '-c' , 'echo The app is running! && sleep 3600' ] initContainers : - name : init-myservice image : busybox:1.28 command : [ 'sh' , '-c' , \"until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done\" ] - name : init-mydb image : busybox:1.28 command : [ 'sh' , '-c' , \"until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done\" ] \u7528\u4e0a\u9762\u521b\u5efa\u7684yaml\u6587\u4ef6\u521b\u5efaPod myapp-pod \u3002 kubectl apply -f myapp-pod.yaml \u68c0\u67e5pod\u7684\u72b6\u6001\u3002 kubectl get pod myapp-pod \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE myapp-pod 0/1 Init:0/2 0 12m \u68c0\u67e5Pod\uff0c\u53ef\u4ee5\u770b\u5230\u4e24\u4e2a\u9519\u8bef\uff1a nslookup: \u65e0\u6cd5\u89e3\u6790'myservice.dev.svc.cluster.local' Pod \"myapp-pod\"\u4e2d\u7684\u5bb9\u5668\u201cinit-mydb\u201d\u6b63\u5728\u7b49\u5f85\u542f\u52a8\uff1aPodInitializing kubectl logs myapp-pod -c init-myservice # Inspect the first init container kubectl logs myapp-pod -c init-mydb # Inspect the second init container \u5728\u8fd9\u4e2a\u65f6\u5019\uff0c\u8fd9\u4e9b init \u5bb9\u5668\u5c06\u7b49\u5f85\u53d1\u73b0\u540d\u4e3a mydb \u548c myservice \u7684\u670d\u52a1\u3002 \u521b\u5efa mydb \u548c myservice \u670d\u52a1\uff1a kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: myservice spec: ports: - protocol: TCP port: 80 targetPort: 9376 --- apiVersion: v1 kind: Service metadata: name: mydb spec: ports: - protocol: TCP port: 80 targetPort: 9377 EOF \u67e5\u770b\u521b\u5efa\u7684\u670d\u52a1\u7684\u72b6\u6001\u3002 kubectl get service \u521b\u5efa\u76842\u4e2a\u670d\u52a1\u90fd\u662f\u8fd0\u884c\u72b6\u6001\u3002 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mydb ClusterIP 11.244.239.149 80/TCP 6s myservice ClusterIP 11.244.116.126 80/TCP 6s \u518d\u6b21\u67e5\u770bpod\u7684\u72b6\u6001\u3002 kubectl get pod myapp-pod -o wide pod\u5df2\u7ecf\u6b63\u5e38\u8fd0\u884c\u4e86\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-pod 0/1 Init:0/2 0 2m40s 10.244.112.2 cka002 \u73b0\u5728\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u90a3\u4e9b\u521d\u59cb\u5316\u5bb9\u5668\u90fd\u5df2\u7ecf\u5b8c\u6210\uff0c myapp-pod Pod \u8fdb\u5165\u4e86 Running \u72b6\u6001\u3002 \u5220\u9664\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u3002 kubectl delete service mydb myservice kubectl delete pod myapp-pod \u53c2\u8003\uff1a Pod basics Lifecycle & phases Kubernetes pod design pattern","title":"\u542b\u521d\u59cb\u5316\u5bb9\u5668Pod"},{"location":"k8s/cka_cn/foundamentals/policy/","text":"CKA\u81ea\u5b66\u7b14\u8bb022:Policy \u00b6 ResourceQuota \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u4e3anamespace quota-object-example \u521b\u5efa\u8d44\u6e90\u914d\u989dResourceQuota object-quota-demo \u3002 \u4e3a NodePort \u6d4b\u8bd5 ResourceQuota object-quota-demo \u3002 \u4e3a PVC \u6d4b\u8bd5 ResourceQuota object-quota-demo \u3002 Create Namespace \u00b6 \u521b\u5efaNamespace\u3002 kubectl create ns quota-object-example \u521b\u5efaResourceQuota \u00b6 \u4e3anamespace quota-object-example \u521b\u5efa\u8d44\u6e90\u914d\u989dResourceQuota object-quota-demo \u3002 \u5728\u8be5namespace\u4e2d\uff0c\u6211\u4eec\u53ea\u80fd\u521b\u5efa 1 \u4e2a\u6c38\u4e45\u5377PVC\u30011 \u4e2a\u8d1f\u8f7d\u5747\u8861LoadBalancer\u670d\u52a1\uff0c\u4e0d\u80fd\u521b\u5efa NodePort \u670d\u52a1\u3002 kubectl apply -f - <@ \uff09 CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev \u521b\u5efaCA\u914d\u7f6e\u6587\u4ef6 \u00b6 CA\uff08Certificate Authority\uff09\u914d\u7f6e\u6587\u4ef6\uff08config file\uff09\u662f\u4e00\u4e2a\u7528\u4e8e\u5b58\u50a8\u8bc1\u4e66\u9881\u53d1\u673a\u6784\uff08CA\uff09\u4fe1\u606f\u7684\u6587\u4ef6\u3002 \u5728\u4f7f\u7528TLS/SSL\u52a0\u5bc6\u901a\u4fe1\u65f6\uff0c\u9700\u8981\u4f7f\u7528\u8bc1\u4e66\u6765\u9a8c\u8bc1\u901a\u4fe1\u53cc\u65b9\u7684\u8eab\u4efd\u3002 \u800cCA\u5219\u662f\u8d1f\u8d23\u7b7e\u53d1\u548c\u9a8c\u8bc1\u8bc1\u4e66\u7684\u673a\u6784\uff0c\u56e0\u6b64\u5728\u5efa\u7acbTLS/SSL\u8fde\u63a5\u65f6\u9700\u8981\u5148\u9a8c\u8bc1CA\u7684\u4fe1\u4efb\u5173\u7cfb\uff0c\u4ee5\u4fdd\u8bc1\u8bc1\u4e66\u7684\u6709\u6548\u6027\u3002 CA\u6587\u4ef6\u4e2d\u5b58\u50a8\u4e86CA\u7684\u516c\u94a5\u4fe1\u606f\u548c\u5176\u4ed6\u76f8\u5173\u7684\u914d\u7f6e\u4fe1\u606f\u3002 \u5728Kubernetes\u4e2d\uff0c\u4f7f\u7528CA\u6587\u4ef6\u6765\u9a8c\u8bc1\u8bc1\u4e66\u7684\u6709\u6548\u6027\u548c\u6388\u6743\u8bbf\u95ee\u3002 \u67e5\u770b\u76ee\u5f55 /etc/kubernetes/pki \u53ca\u5176\u5b50\u76ee\u5f55\u7684\u7ed3\u6784\u60c5\u51b5\u3002 tree /etc/kubernetes/pki \u8fd0\u884c\u7ed3\u679c\uff0c\u4e0b\u9762\u662fKubernetes\u521d\u59cb\u5b89\u88c5\u540e\u7684\u6587\u4ef6\u7ed3\u6784\u7684\u793a\u4f8b\u5185\u5bb9\u3002 /etc/kubernetes/pki \u251c\u2500\u2500 apiserver.crt \u251c\u2500\u2500 apiserver-etcd-client.crt \u251c\u2500\u2500 apiserver-etcd-client.key \u251c\u2500\u2500 apiserver.key \u251c\u2500\u2500 apiserver-kubelet-client.crt \u251c\u2500\u2500 apiserver-kubelet-client.key \u251c\u2500\u2500 ca.crt \u251c\u2500\u2500 ca.key \u251c\u2500\u2500 etcd \u2502 \u251c\u2500\u2500 ca.crt \u2502 \u251c\u2500\u2500 ca.key \u2502 \u251c\u2500\u2500 healthcheck-client.crt \u2502 \u251c\u2500\u2500 healthcheck-client.key \u2502 \u251c\u2500\u2500 peer.crt \u2502 \u251c\u2500\u2500 peer.key \u2502 \u251c\u2500\u2500 server.crt \u2502 \u2514\u2500\u2500 server.key \u251c\u2500\u2500 front-proxy-ca.crt \u251c\u2500\u2500 front-proxy-ca.key \u251c\u2500\u2500 front-proxy-client.crt \u251c\u2500\u2500 front-proxy-client.key \u251c\u2500\u2500 sa.key \u2514\u2500\u2500 sa.pub \u8fdb\u5165\u76ee\u5f55 /etc/kubernetes/pki \uff0c\u5373\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 cd /etc/kubernetes/pki \u68c0\u67e5\u6587\u4ef6 ca-config.json \u662f\u5426\u5df2\u7ecf\u5b58\u5728\u4e0e\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 ll ca-config.json \u5982\u679c\u4e0d\u5b58\u5728\uff0c\u5219\u521b\u5efa\u8fd9\u4e2a\u6587\u4ef6\u3002 \u6211\u4eec\u53ef\u4ee5\u6dfb\u52a0\u591a\u4e2a\u914d\u7f6e\u6587\u4ef6\u6765\u6307\u5b9a\u4e0d\u540c\u7684\u8fc7\u671f\u65e5\u671f\u3001\u573a\u666f\u3001\u53c2\u6570\u7b49\u3002 \u914d\u7f6e\u6587\u4ef6\u5c06\u7528\u4e8e\u7b7e\u7f72\u8bc1\u4e66\u3002 87600 \u5c0f\u65f6\u5927\u7ea6\u662f10\u5e74\u3002 \u8fd9\u91cc\u6211\u4eec\u5c06\u5728 ca-config.json \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a dev \u7684\u914d\u7f6e\u6587\u4ef6\u3002 cat > ca-config.json < cka-dev-csr.json < \uff09\u6765\u62fc\u63a5\u51fa\u73af\u5883\u53d8\u91cf APISERVER \u7684\u503c\uff0c\u5982\uff1a https://: \u3002 kubectl get node -owide \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready control-plane,master 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 \u8bbe\u5b9a\u5e76\u8f93\u51fa\u73af\u5883\u53d8\u91cf APISERVER \u3002 echo \"export APISERVER=\\\"https://:6443\\\"\" >> ~/.bashrc source ~/.bashrc \u9a8c\u8bc1\u73af\u5883\u53d8\u91cf APISERVER \u7684\u503c\u3002 echo $APISERVER \u8fd0\u884c\u7ed3\u679c\uff1a https://:6443 \u8bbe\u7f6e\u96c6\u7fa4 \u00b6 \u4fdd\u6301\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u4e3a /etc/kubernetes/pki \u3002 \u751f\u6210 kubeconfig \u6587\u4ef6\u3002 kubectl config set-cluster kubernetes \\ --certificate-authority = /etc/kubernetes/pki/ca.crt \\ --embed-certs = true \\ --server = ${ APISERVER } \\ --kubeconfig = cka-dev.kubeconfig \u73b0\u5728\u6211\u4eec\u751f\u6210\u4e86\u65b0\u7684\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u3002 ll -tr | grep cka-dev \u8f93\u51fa\u7ed3\u679c\uff1a -rw-r--r-- 1 root root 222 Jul 24 08:49 cka-dev-csr.json -rw-r--r-- 1 root root 1281 Jul 24 09:14 cka-dev.pem -rw------- 1 root root 1675 Jul 24 09:14 cka-dev-key.pem -rw-r--r-- 1 root root 1001 Jul 24 09:14 cka-dev.csr -rw------- 1 root root 1671 Jul 24 09:16 cka-dev.kubeconfig \u8bfb\u53d6\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u7684\u5185\u5bb9\u3002 cat cka-dev.kubeconfig \u8f93\u51fa\u7684\u5185\u5bb9\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : null \u914d\u7f6e\u7528\u6237 \u00b6 \u5728\u6587\u4ef6 cka-dev.kubeconfig \u4e2d\uff0c\u7528\u6237\u4fe1\u606f\u8fd9\u90e8\u5206\u662f\u7a7a\u7684\u3002 \u4e0b\u9762\u6211\u4eec\u914d\u7f6e\u4e00\u4e2a\u7528\u6237 cka-dev \u3002 kubectl config set-credentials cka-dev \\ --client-certificate = /etc/kubernetes/pki/cka-dev.pem \\ --client-key = /etc/kubernetes/pki/cka-dev-key.pem \\ --embed-certs = true \\ --kubeconfig = cka-dev.kubeconfig \u73b0\u5728\uff0c\u7528\u6237\u4fe1\u606f\u5df2\u7ecf\u88ab\u6dfb\u52a0\u5230\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u4e2d\u4e86\u3002 cat cka-dev.kubeconfig \u8f93\u51fa\u7ed3\u679c\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : - name : cka-dev user : client-certificate-data : client-key-data : \u81f3\u6b64\u6211\u4eec\u5f97\u5230\u4e86\u4e00\u4e2a\u5b8c\u6574\u7684\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u3002 \u7531\u4e8e\u6211\u4eec\u6ca1\u6709\u5728 kubeconfig \u6587\u4ef6\u4e2d\u8bbe\u7f6e\u5f53\u524d\u4e0a\u4e0b\u6587\uff0c\u5f53\u6211\u4eec\u4f7f\u7528\u5b83\u6765\u83b7\u53d6\u8282\u70b9\u4fe1\u606f\u65f6\uff0c\u4f1a\u6536\u5230\u4ee5\u4e0b\u9519\u8bef\u3002 kubectl --kubeconfig = cka-dev.kubeconfig get nodes \u8fd0\u884c\u7ed3\u679c\uff1a The connection to the server localhost:8080 was refused - did you specify the right host or port? \u5f53\u524d\u4e0a\u4e0b\u6587\u5185\u5bb9\u662f\u7a7a\u767d\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config get-contexts \u8f93\u51fa\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE \u914d\u7f6e\u4e0a\u4e0b\u6587 \u00b6 \u914d\u7f6e\u4e0a\u4e0b\u6587\u3002 kubectl config set-context dev --cluster = kubernetes --user = cka-dev --kubeconfig = cka-dev.kubeconfig \u73b0\u5728\u6211\u4eec\u914d\u7f6e\u4e86\u4e0a\u4e0b\u6587\uff0c\u4f46\u5176\u4e2d CURRENT \u4ecd\u7136\u662f\u7a7a\u767d\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev \u8bbe\u7f6e\u9ed8\u8ba4\u4e0a\u4e0b\u6587\u3002\u4e0a\u4e0b\u6587\u5c06\u4e3a\u591a\u96c6\u7fa4\u73af\u5883\u4e2d\u7684\u96c6\u7fa4\u548c\u7528\u6237\u94fe\u63a5\uff0c\u5e76\u4e14\u6211\u4eec\u53ef\u4ee5\u5207\u6362\u5230\u4e0d\u540c\u7684\u96c6\u7fa4\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config use-context dev \u9a8c\u8bc1 \u00b6 \u73b0\u5728 CURRENT \u5df2\u7ecf\u88ab\u6807\u8bb0\u4e3a * \u4e86\uff0c\u8fd9\u5c31\u8bf4\u660e\u5f53\u524d\u4e0a\u4e0b\u6587\u5df2\u7ecf\u914d\u7f6e\u597d\u4e86\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev \u56e0\u4e3a\u7528\u6237 cka-dev \u5728\u8be5\u96c6\u7fa4\u4e2d\u6ca1\u6709\u6388\u6743\uff0c\u6240\u4ee5\u5f53\u6211\u4eec\u5c1d\u8bd5\u83b7\u53d6 Pod \u6216 Node \u7684\u4fe1\u606f\u65f6\uff0c\u4f1a\u6536\u5230\u201c\u7981\u6b62\u8bbf\u95ee\uff08forbidden\uff09\u201d\u9519\u8bef\u3002 kubectl --kubeconfig = /etc/kubernetes/pki/cka-dev.kubeconfig get pod kubectl --kubeconfig = /etc/kubernetes/pki/cka-dev.kubeconfig get node \u5408\u5e76kubeconfig\u6587\u4ef6 \u00b6 \u62f7\u8d1d\u5f53\u524d\u914d\u7f6e\u6587\u4ef6\uff0c\u4f5c\u4e3a\u5907\u4efd\u3002 cp ~/.kube/config ~/.kube/config.old \u628a\u4e24\u4e2a\u914d\u7f6e\u6587\u4ef6\u5408\u5e76\u6210\u4e00\u4e2a\u65b0\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5e76\u5b58\u653e\u5728 /tmp/config \u3002 KUBECONFIG = ~/.kube/config:/etc/kubernetes/pki/cka-dev.kubeconfig kubectl config view --flatten > /tmp/config \u7528\u5408\u5e76\u540e\u7684\u65b0\u914d\u7f6e\u6587\u4ef6\u66ff\u6362\u8001\u7684\u914d\u7f6e\u6587\u4ef6\u3002 mv /tmp/config ~/.kube/config \u65b0\u7684\u914d\u7f6e\u6587\u4ef6 ~/.kube/config \u7c7b\u4f3c\u5982\u4e0b\u3002 apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : - context : cluster : kubernetes user : cka-dev name : dev - context : cluster : kubernetes user : kubernetes-admin name : kubernetes-admin@kubernetes current-context : kubernetes-admin@kubernetes kind : Config preferences : {} users : - name : cka-dev user : client-certificate-data : client-key-data : - name : kubernetes-admin user : client-certificate-data : client-key-data : \u68c0\u67e5\u57fa\u4e8e\u65b0\u7684\u914d\u7f6e\u6587\u4ef6\u4e0b\u7684\u5f53\u524d\u4e0a\u4e0b\u6587\u3002 kubectl config get-contexts \u5f53\u524d\u4e0a\u4e0b\u6587\u662f\u7cfb\u7edf\u9ed8\u8ba4\u914d\u7f6e kubernetes-admin@kubernetes \u3002 CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev \u547d\u540d\u7a7a\u95f4\u548c\u4e0a\u4e0b\u6587 \u00b6 \u67e5\u8be2\u5f53\u524d\u547d\u540d\u7a7a\u95f4namespace\u5217\u8868\u548c\u5bf9\u5e94\u6807\u7b7elabel\u7684\u4fe1\u606f\u3002 kubectl get ns --show-labels \u521b\u5efanamespace cka \u3002 kubectl create namespace cka \u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u66f4\u65b0\u4e0a\u4e0b\u6587\u4fe1\u606f\uff0c\u4f8b\u5982\uff0c\u66f4\u65b0\u9ed8\u8ba4\u547d\u540d\u7a7a\u95f4\u7b49\u3002 kubectl config set-context --cluster = --namespace = --user = \u4e0b\u9762\u9488\u5bf9\u6bcf\u4e2a\u4e0a\u4e0b\u6587context\u8bbe\u5b9a\u9ed8\u8ba4\u7684namespace\u3002 kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin kubectl config set-context dev --cluster = kubernetes --namespace = cka --user = cka-dev \u68c0\u67e5\u5f53\u524d\u4e0a\u4e0b\u6587context\u7684\u4fe1\u606f\u3002 kubectl config get-contexts \u8f93\u51fa\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev cka * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev \u901a\u8fc7\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u53ef\u4ee5\u5207\u6362\u5230\u65b0\u7684context\u3002 kubectl config use-contexts \u4f8b\u5982\uff1a kubectl config use-context dev \u68c0\u67e5\u4e0a\u9762\u7684\u53d8\u66f4\u662f\u5426\u751f\u6548\u3002 kubectl config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1b CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev cka kubernetes-admin@kubernetes kubernetes kubernetes-admin dev Be noted, four users beginning with cka-dev created don't have any authorizations, e.g., access namespaces, get pods, etc.. Referring RBAC to grant their authorizations. \u6ce8\u610f\uff1a\u524d\u9762\u521b\u5efa\u7684\u4ee5 cka-dev \u5f00\u5934\u7684\u7528\u6237\u5b9e\u9645\u6ca1\u6709\u4efb\u4f55\u6743\u9650\uff0c\u4f8b\u5982\u8bbf\u95ee\u547d\u540d\u7a7a\u95f4\u3001\u83b7\u53d6 pod \u7b49\uff0c\u4e0b\u9762\u5c06\u901a\u8fc7 RBAC \u6388\u4e88\u4ed6\u4eec\u6388\u6743\u3002 \u89d2\u8272Role\u548c\u89d2\u8272\u7ed1\u5b9aRoleBinding \u00b6 \u5c06\u5f53\u524d\u5de5\u4f5c\u4e0a\u4e0b\u6587\u5207\u6362\u5230 kubernetes-admin@kubernetes \u3002 kubectl config use-context kubernetes-admin@kubernetes \u4f7f\u7528\u5e26\u6709\u9009\u9879 --dry-run=client \u548c -o yaml \u7684 kubectl create role \u547d\u4ee4\uff0c\u751f\u6210\u521b\u5efa\u89d2\u8272role\u7684 yaml \u6a21\u677f\u3002 kubectl create role admin-dev --resource = pods --verb = get --verb = list --verb = watch --dry-run = client -o yaml \u5728namespace cka \u4e0a\u521b\u5efa\u89d2\u8272role admin-dev \u3002 kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: cka name: admin-dev rules: - apiGroups: - \"\" resources: - pods verbs: - get - watch - list EOF \u4f7f\u7528\u5e26\u6709\u9009\u9879 --dry-run=client \u548c -o yaml \u7684 kubectl create rolebinding \u547d\u4ee4\uff0c\u751f\u6210\u521b\u5efa\u89d2\u8272\u7ed1\u5b9arolebinding\u7684 yaml \u6a21\u677f\u3002 kubectl create rolebinding admin --role = admin-dev --user = cka-dev --dry-run = client -o yaml \u5728namespace cka \u4e0a\u521b\u5efa\u4e00\u4e2a\u89d2\u8272\u7ed1\u5b9arolebinding admin \u3002 kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: admin namespace: cka roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: admin-dev subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: cka-dev EOF \u9a8c\u8bc1namespace cka \u4e0a\u7684\u7528\u6237 cka-dev \u7684\u6743\u9650\u3002 \u5207\u6362\u5230\u4e0a\u4e0b\u6587 dev \u3002 kubectl config use-context dev \u67e5\u8be2namespace cka \u4e0apod\u7684\u72b6\u6001\uff0c\u6210\u529f\uff01 kubectl get pod -n cka \u67e5\u8be2namespace kube-system \u4e0apod\u7684\u72b6\u6001\uff0c\u5931\u8d25\uff01\u56e0\u4e3a\u524d\u9762\u6dfb\u52a0\u7684\u6743\u9650\u4ec5\u9650\u4e8enamespace cka \u3002 kubectl get pod -n kube-system \u67e5\u8be2\u8282\u70b9node\u7684\u72b6\u6001\uff0c\u5931\u8d25\uff01\u56e0\u4e3a\u5728\u89d2\u8272role\u91cc\u9762\u6211\u4eec\u53ea\u5b9a\u4e49\u4e86pod\u8fd9\u4e00\u79cd\u8d44\u6e90\u3002 kubectl get node \u5728namespace dev \u4e0a\u521b\u5efa\u4e00\u4e2apod\uff0c\u5931\u8d25\uff01\u56e0\u4e3a\u6211\u4eec\u5728\u53ea\u6709\u5bf9pod\u7684 get , watch , list \u4e09\u79cd\u64cd\u4f5c\u6743\u9650\uff0c\u6ca1\u6709 create \u6743\u9650\u3002 kubectl run nginx --image = nginx -n cka \u96c6\u7fa4\u89d2\u8272ClusterRole\u548c\u96c6\u7fa4\u89d2\u8272\u7ed1\u5b9aClusterRoleBinding \u00b6 \u5207\u6362\u5230\u4e0a\u4e0b\u6587 kubernetes-admin@kubernetes \u3002 kubectl config use-context kubernetes-admin@kubernetes \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a nodes-admin \u7684 ClusterRole\uff0c\u5b83\u6388\u4e88 get \u3001 watch \u3001 list \u5bf9 nodes \u8d44\u6e90\u7684\u6388\u6743\u3002 kubectl apply -f - <@ \uff09 CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev","title":"\u5f53\u524d\u4e0a\u4e0b\u6587"},{"location":"k8s/cka_cn/foundamentals/rbac/#ca","text":"CA\uff08Certificate Authority\uff09\u914d\u7f6e\u6587\u4ef6\uff08config file\uff09\u662f\u4e00\u4e2a\u7528\u4e8e\u5b58\u50a8\u8bc1\u4e66\u9881\u53d1\u673a\u6784\uff08CA\uff09\u4fe1\u606f\u7684\u6587\u4ef6\u3002 \u5728\u4f7f\u7528TLS/SSL\u52a0\u5bc6\u901a\u4fe1\u65f6\uff0c\u9700\u8981\u4f7f\u7528\u8bc1\u4e66\u6765\u9a8c\u8bc1\u901a\u4fe1\u53cc\u65b9\u7684\u8eab\u4efd\u3002 \u800cCA\u5219\u662f\u8d1f\u8d23\u7b7e\u53d1\u548c\u9a8c\u8bc1\u8bc1\u4e66\u7684\u673a\u6784\uff0c\u56e0\u6b64\u5728\u5efa\u7acbTLS/SSL\u8fde\u63a5\u65f6\u9700\u8981\u5148\u9a8c\u8bc1CA\u7684\u4fe1\u4efb\u5173\u7cfb\uff0c\u4ee5\u4fdd\u8bc1\u8bc1\u4e66\u7684\u6709\u6548\u6027\u3002 CA\u6587\u4ef6\u4e2d\u5b58\u50a8\u4e86CA\u7684\u516c\u94a5\u4fe1\u606f\u548c\u5176\u4ed6\u76f8\u5173\u7684\u914d\u7f6e\u4fe1\u606f\u3002 \u5728Kubernetes\u4e2d\uff0c\u4f7f\u7528CA\u6587\u4ef6\u6765\u9a8c\u8bc1\u8bc1\u4e66\u7684\u6709\u6548\u6027\u548c\u6388\u6743\u8bbf\u95ee\u3002 \u67e5\u770b\u76ee\u5f55 /etc/kubernetes/pki \u53ca\u5176\u5b50\u76ee\u5f55\u7684\u7ed3\u6784\u60c5\u51b5\u3002 tree /etc/kubernetes/pki \u8fd0\u884c\u7ed3\u679c\uff0c\u4e0b\u9762\u662fKubernetes\u521d\u59cb\u5b89\u88c5\u540e\u7684\u6587\u4ef6\u7ed3\u6784\u7684\u793a\u4f8b\u5185\u5bb9\u3002 /etc/kubernetes/pki \u251c\u2500\u2500 apiserver.crt \u251c\u2500\u2500 apiserver-etcd-client.crt \u251c\u2500\u2500 apiserver-etcd-client.key \u251c\u2500\u2500 apiserver.key \u251c\u2500\u2500 apiserver-kubelet-client.crt \u251c\u2500\u2500 apiserver-kubelet-client.key \u251c\u2500\u2500 ca.crt \u251c\u2500\u2500 ca.key \u251c\u2500\u2500 etcd \u2502 \u251c\u2500\u2500 ca.crt \u2502 \u251c\u2500\u2500 ca.key \u2502 \u251c\u2500\u2500 healthcheck-client.crt \u2502 \u251c\u2500\u2500 healthcheck-client.key \u2502 \u251c\u2500\u2500 peer.crt \u2502 \u251c\u2500\u2500 peer.key \u2502 \u251c\u2500\u2500 server.crt \u2502 \u2514\u2500\u2500 server.key \u251c\u2500\u2500 front-proxy-ca.crt \u251c\u2500\u2500 front-proxy-ca.key \u251c\u2500\u2500 front-proxy-client.crt \u251c\u2500\u2500 front-proxy-client.key \u251c\u2500\u2500 sa.key \u2514\u2500\u2500 sa.pub \u8fdb\u5165\u76ee\u5f55 /etc/kubernetes/pki \uff0c\u5373\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 cd /etc/kubernetes/pki \u68c0\u67e5\u6587\u4ef6 ca-config.json \u662f\u5426\u5df2\u7ecf\u5b58\u5728\u4e0e\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 ll ca-config.json \u5982\u679c\u4e0d\u5b58\u5728\uff0c\u5219\u521b\u5efa\u8fd9\u4e2a\u6587\u4ef6\u3002 \u6211\u4eec\u53ef\u4ee5\u6dfb\u52a0\u591a\u4e2a\u914d\u7f6e\u6587\u4ef6\u6765\u6307\u5b9a\u4e0d\u540c\u7684\u8fc7\u671f\u65e5\u671f\u3001\u573a\u666f\u3001\u53c2\u6570\u7b49\u3002 \u914d\u7f6e\u6587\u4ef6\u5c06\u7528\u4e8e\u7b7e\u7f72\u8bc1\u4e66\u3002 87600 \u5c0f\u65f6\u5927\u7ea6\u662f10\u5e74\u3002 \u8fd9\u91cc\u6211\u4eec\u5c06\u5728 ca-config.json \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a dev \u7684\u914d\u7f6e\u6587\u4ef6\u3002 cat > ca-config.json < cka-dev-csr.json < \uff09\u6765\u62fc\u63a5\u51fa\u73af\u5883\u53d8\u91cf APISERVER \u7684\u503c\uff0c\u5982\uff1a https://: \u3002 kubectl get node -owide \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready control-plane,master 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 \u8bbe\u5b9a\u5e76\u8f93\u51fa\u73af\u5883\u53d8\u91cf APISERVER \u3002 echo \"export APISERVER=\\\"https://:6443\\\"\" >> ~/.bashrc source ~/.bashrc \u9a8c\u8bc1\u73af\u5883\u53d8\u91cf APISERVER \u7684\u503c\u3002 echo $APISERVER \u8fd0\u884c\u7ed3\u679c\uff1a https://:6443","title":"\u521b\u5efakubeconfig\u6587\u4ef6"},{"location":"k8s/cka_cn/foundamentals/rbac/#_4","text":"\u4fdd\u6301\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u4e3a /etc/kubernetes/pki \u3002 \u751f\u6210 kubeconfig \u6587\u4ef6\u3002 kubectl config set-cluster kubernetes \\ --certificate-authority = /etc/kubernetes/pki/ca.crt \\ --embed-certs = true \\ --server = ${ APISERVER } \\ --kubeconfig = cka-dev.kubeconfig \u73b0\u5728\u6211\u4eec\u751f\u6210\u4e86\u65b0\u7684\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u3002 ll -tr | grep cka-dev \u8f93\u51fa\u7ed3\u679c\uff1a -rw-r--r-- 1 root root 222 Jul 24 08:49 cka-dev-csr.json -rw-r--r-- 1 root root 1281 Jul 24 09:14 cka-dev.pem -rw------- 1 root root 1675 Jul 24 09:14 cka-dev-key.pem -rw-r--r-- 1 root root 1001 Jul 24 09:14 cka-dev.csr -rw------- 1 root root 1671 Jul 24 09:16 cka-dev.kubeconfig \u8bfb\u53d6\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u7684\u5185\u5bb9\u3002 cat cka-dev.kubeconfig \u8f93\u51fa\u7684\u5185\u5bb9\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : null","title":"\u8bbe\u7f6e\u96c6\u7fa4"},{"location":"k8s/cka_cn/foundamentals/rbac/#_5","text":"\u5728\u6587\u4ef6 cka-dev.kubeconfig \u4e2d\uff0c\u7528\u6237\u4fe1\u606f\u8fd9\u90e8\u5206\u662f\u7a7a\u7684\u3002 \u4e0b\u9762\u6211\u4eec\u914d\u7f6e\u4e00\u4e2a\u7528\u6237 cka-dev \u3002 kubectl config set-credentials cka-dev \\ --client-certificate = /etc/kubernetes/pki/cka-dev.pem \\ --client-key = /etc/kubernetes/pki/cka-dev-key.pem \\ --embed-certs = true \\ --kubeconfig = cka-dev.kubeconfig \u73b0\u5728\uff0c\u7528\u6237\u4fe1\u606f\u5df2\u7ecf\u88ab\u6dfb\u52a0\u5230\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u4e2d\u4e86\u3002 cat cka-dev.kubeconfig \u8f93\u51fa\u7ed3\u679c\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : - name : cka-dev user : client-certificate-data : client-key-data : \u81f3\u6b64\u6211\u4eec\u5f97\u5230\u4e86\u4e00\u4e2a\u5b8c\u6574\u7684\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u3002 \u7531\u4e8e\u6211\u4eec\u6ca1\u6709\u5728 kubeconfig \u6587\u4ef6\u4e2d\u8bbe\u7f6e\u5f53\u524d\u4e0a\u4e0b\u6587\uff0c\u5f53\u6211\u4eec\u4f7f\u7528\u5b83\u6765\u83b7\u53d6\u8282\u70b9\u4fe1\u606f\u65f6\uff0c\u4f1a\u6536\u5230\u4ee5\u4e0b\u9519\u8bef\u3002 kubectl --kubeconfig = cka-dev.kubeconfig get nodes \u8fd0\u884c\u7ed3\u679c\uff1a The connection to the server localhost:8080 was refused - did you specify the right host or port? \u5f53\u524d\u4e0a\u4e0b\u6587\u5185\u5bb9\u662f\u7a7a\u767d\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config get-contexts \u8f93\u51fa\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE","title":"\u914d\u7f6e\u7528\u6237"},{"location":"k8s/cka_cn/foundamentals/rbac/#_6","text":"\u914d\u7f6e\u4e0a\u4e0b\u6587\u3002 kubectl config set-context dev --cluster = kubernetes --user = cka-dev --kubeconfig = cka-dev.kubeconfig \u73b0\u5728\u6211\u4eec\u914d\u7f6e\u4e86\u4e0a\u4e0b\u6587\uff0c\u4f46\u5176\u4e2d CURRENT \u4ecd\u7136\u662f\u7a7a\u767d\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev \u8bbe\u7f6e\u9ed8\u8ba4\u4e0a\u4e0b\u6587\u3002\u4e0a\u4e0b\u6587\u5c06\u4e3a\u591a\u96c6\u7fa4\u73af\u5883\u4e2d\u7684\u96c6\u7fa4\u548c\u7528\u6237\u94fe\u63a5\uff0c\u5e76\u4e14\u6211\u4eec\u53ef\u4ee5\u5207\u6362\u5230\u4e0d\u540c\u7684\u96c6\u7fa4\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config use-context dev","title":"\u914d\u7f6e\u4e0a\u4e0b\u6587"},{"location":"k8s/cka_cn/foundamentals/rbac/#_7","text":"\u73b0\u5728 CURRENT \u5df2\u7ecf\u88ab\u6807\u8bb0\u4e3a * \u4e86\uff0c\u8fd9\u5c31\u8bf4\u660e\u5f53\u524d\u4e0a\u4e0b\u6587\u5df2\u7ecf\u914d\u7f6e\u597d\u4e86\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev \u56e0\u4e3a\u7528\u6237 cka-dev \u5728\u8be5\u96c6\u7fa4\u4e2d\u6ca1\u6709\u6388\u6743\uff0c\u6240\u4ee5\u5f53\u6211\u4eec\u5c1d\u8bd5\u83b7\u53d6 Pod \u6216 Node \u7684\u4fe1\u606f\u65f6\uff0c\u4f1a\u6536\u5230\u201c\u7981\u6b62\u8bbf\u95ee\uff08forbidden\uff09\u201d\u9519\u8bef\u3002 kubectl --kubeconfig = /etc/kubernetes/pki/cka-dev.kubeconfig get pod kubectl --kubeconfig = /etc/kubernetes/pki/cka-dev.kubeconfig get node","title":"\u9a8c\u8bc1"},{"location":"k8s/cka_cn/foundamentals/rbac/#kubeconfig_1","text":"\u62f7\u8d1d\u5f53\u524d\u914d\u7f6e\u6587\u4ef6\uff0c\u4f5c\u4e3a\u5907\u4efd\u3002 cp ~/.kube/config ~/.kube/config.old \u628a\u4e24\u4e2a\u914d\u7f6e\u6587\u4ef6\u5408\u5e76\u6210\u4e00\u4e2a\u65b0\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5e76\u5b58\u653e\u5728 /tmp/config \u3002 KUBECONFIG = ~/.kube/config:/etc/kubernetes/pki/cka-dev.kubeconfig kubectl config view --flatten > /tmp/config \u7528\u5408\u5e76\u540e\u7684\u65b0\u914d\u7f6e\u6587\u4ef6\u66ff\u6362\u8001\u7684\u914d\u7f6e\u6587\u4ef6\u3002 mv /tmp/config ~/.kube/config \u65b0\u7684\u914d\u7f6e\u6587\u4ef6 ~/.kube/config \u7c7b\u4f3c\u5982\u4e0b\u3002 apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : - context : cluster : kubernetes user : cka-dev name : dev - context : cluster : kubernetes user : kubernetes-admin name : kubernetes-admin@kubernetes current-context : kubernetes-admin@kubernetes kind : Config preferences : {} users : - name : cka-dev user : client-certificate-data : client-key-data : - name : kubernetes-admin user : client-certificate-data : client-key-data : \u68c0\u67e5\u57fa\u4e8e\u65b0\u7684\u914d\u7f6e\u6587\u4ef6\u4e0b\u7684\u5f53\u524d\u4e0a\u4e0b\u6587\u3002 kubectl config get-contexts \u5f53\u524d\u4e0a\u4e0b\u6587\u662f\u7cfb\u7edf\u9ed8\u8ba4\u914d\u7f6e kubernetes-admin@kubernetes \u3002 CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev","title":"\u5408\u5e76kubeconfig\u6587\u4ef6"},{"location":"k8s/cka_cn/foundamentals/rbac/#_8","text":"\u67e5\u8be2\u5f53\u524d\u547d\u540d\u7a7a\u95f4namespace\u5217\u8868\u548c\u5bf9\u5e94\u6807\u7b7elabel\u7684\u4fe1\u606f\u3002 kubectl get ns --show-labels \u521b\u5efanamespace cka \u3002 kubectl create namespace cka \u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u66f4\u65b0\u4e0a\u4e0b\u6587\u4fe1\u606f\uff0c\u4f8b\u5982\uff0c\u66f4\u65b0\u9ed8\u8ba4\u547d\u540d\u7a7a\u95f4\u7b49\u3002 kubectl config set-context --cluster = --namespace = --user = \u4e0b\u9762\u9488\u5bf9\u6bcf\u4e2a\u4e0a\u4e0b\u6587context\u8bbe\u5b9a\u9ed8\u8ba4\u7684namespace\u3002 kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin kubectl config set-context dev --cluster = kubernetes --namespace = cka --user = cka-dev \u68c0\u67e5\u5f53\u524d\u4e0a\u4e0b\u6587context\u7684\u4fe1\u606f\u3002 kubectl config get-contexts \u8f93\u51fa\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev cka * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev \u901a\u8fc7\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u53ef\u4ee5\u5207\u6362\u5230\u65b0\u7684context\u3002 kubectl config use-contexts \u4f8b\u5982\uff1a kubectl config use-context dev \u68c0\u67e5\u4e0a\u9762\u7684\u53d8\u66f4\u662f\u5426\u751f\u6548\u3002 kubectl config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1b CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev cka kubernetes-admin@kubernetes kubernetes kubernetes-admin dev Be noted, four users beginning with cka-dev created don't have any authorizations, e.g., access namespaces, get pods, etc.. Referring RBAC to grant their authorizations. \u6ce8\u610f\uff1a\u524d\u9762\u521b\u5efa\u7684\u4ee5 cka-dev \u5f00\u5934\u7684\u7528\u6237\u5b9e\u9645\u6ca1\u6709\u4efb\u4f55\u6743\u9650\uff0c\u4f8b\u5982\u8bbf\u95ee\u547d\u540d\u7a7a\u95f4\u3001\u83b7\u53d6 pod \u7b49\uff0c\u4e0b\u9762\u5c06\u901a\u8fc7 RBAC \u6388\u4e88\u4ed6\u4eec\u6388\u6743\u3002","title":"\u547d\u540d\u7a7a\u95f4\u548c\u4e0a\u4e0b\u6587"},{"location":"k8s/cka_cn/foundamentals/rbac/#rolerolebinding","text":"\u5c06\u5f53\u524d\u5de5\u4f5c\u4e0a\u4e0b\u6587\u5207\u6362\u5230 kubernetes-admin@kubernetes \u3002 kubectl config use-context kubernetes-admin@kubernetes \u4f7f\u7528\u5e26\u6709\u9009\u9879 --dry-run=client \u548c -o yaml \u7684 kubectl create role \u547d\u4ee4\uff0c\u751f\u6210\u521b\u5efa\u89d2\u8272role\u7684 yaml \u6a21\u677f\u3002 kubectl create role admin-dev --resource = pods --verb = get --verb = list --verb = watch --dry-run = client -o yaml \u5728namespace cka \u4e0a\u521b\u5efa\u89d2\u8272role admin-dev \u3002 kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: cka name: admin-dev rules: - apiGroups: - \"\" resources: - pods verbs: - get - watch - list EOF \u4f7f\u7528\u5e26\u6709\u9009\u9879 --dry-run=client \u548c -o yaml \u7684 kubectl create rolebinding \u547d\u4ee4\uff0c\u751f\u6210\u521b\u5efa\u89d2\u8272\u7ed1\u5b9arolebinding\u7684 yaml \u6a21\u677f\u3002 kubectl create rolebinding admin --role = admin-dev --user = cka-dev --dry-run = client -o yaml \u5728namespace cka \u4e0a\u521b\u5efa\u4e00\u4e2a\u89d2\u8272\u7ed1\u5b9arolebinding admin \u3002 kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: admin namespace: cka roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: admin-dev subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: cka-dev EOF \u9a8c\u8bc1namespace cka \u4e0a\u7684\u7528\u6237 cka-dev \u7684\u6743\u9650\u3002 \u5207\u6362\u5230\u4e0a\u4e0b\u6587 dev \u3002 kubectl config use-context dev \u67e5\u8be2namespace cka \u4e0apod\u7684\u72b6\u6001\uff0c\u6210\u529f\uff01 kubectl get pod -n cka \u67e5\u8be2namespace kube-system \u4e0apod\u7684\u72b6\u6001\uff0c\u5931\u8d25\uff01\u56e0\u4e3a\u524d\u9762\u6dfb\u52a0\u7684\u6743\u9650\u4ec5\u9650\u4e8enamespace cka \u3002 kubectl get pod -n kube-system \u67e5\u8be2\u8282\u70b9node\u7684\u72b6\u6001\uff0c\u5931\u8d25\uff01\u56e0\u4e3a\u5728\u89d2\u8272role\u91cc\u9762\u6211\u4eec\u53ea\u5b9a\u4e49\u4e86pod\u8fd9\u4e00\u79cd\u8d44\u6e90\u3002 kubectl get node \u5728namespace dev \u4e0a\u521b\u5efa\u4e00\u4e2apod\uff0c\u5931\u8d25\uff01\u56e0\u4e3a\u6211\u4eec\u5728\u53ea\u6709\u5bf9pod\u7684 get , watch , list \u4e09\u79cd\u64cd\u4f5c\u6743\u9650\uff0c\u6ca1\u6709 create \u6743\u9650\u3002 kubectl run nginx --image = nginx -n cka","title":"\u89d2\u8272Role\u548c\u89d2\u8272\u7ed1\u5b9aRoleBinding"},{"location":"k8s/cka_cn/foundamentals/rbac/#clusterroleclusterrolebinding","text":"\u5207\u6362\u5230\u4e0a\u4e0b\u6587 kubernetes-admin@kubernetes \u3002 kubectl config use-context kubernetes-admin@kubernetes \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a nodes-admin \u7684 ClusterRole\uff0c\u5b83\u6388\u4e88 get \u3001 watch \u3001 list \u5bf9 nodes \u8d44\u6e90\u7684\u6388\u6743\u3002 kubectl apply -f - < nodeName \u00b6 \u6ce8\u610f\uff0c nodeName \u5177\u6709\u6700\u9ad8\u4f18\u5148\u7ea7\uff0c\u56e0\u4e3a\u5b83\u4e0d\u662f\u7531 Scheduler \u8fdb\u884c\u8c03\u5ea6\u7684\u3002 \u521b\u5efa\u4e00\u4e2a Pod nginx-nodename \uff0c\u5e76\u5c06\u5176\u6307\u5b9a\u5728 cka003 \u8282\u70b9\u4e0a\u3002 kubectl apply -f - < Affinity \u00b6 \u5728 Kubernetes \u96c6\u7fa4\u4e2d\uff0c\u6709\u4e9b Pod \u9700\u8981\u9891\u7e41\u4e0e\u5176\u4ed6 Pod \u8fdb\u884c\u4ea4\u4e92\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5efa\u8bae\u5c06\u8fd9\u4e9b Pod \u8c03\u5ea6\u5230\u540c\u4e00\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u3002\u4f8b\u5982\uff0c\u4e24\u4e2a Pod\uff1a Nginx \u548c Mysql \uff0c\u5982\u679c\u5b83\u4eec\u9891\u7e41\u901a\u4fe1\uff0c\u5219\u9700\u8981\u5728\u540c\u4e00\u4e2a\u8282\u70b9\u4e0a\u90e8\u7f72\u5b83\u4eec\u3002 \u57fa\u4e8epod\u4e4b\u95f4\u7684\u5173\u7cfb\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 podAffinity \u8fdb\u884c\u9009\u62e9\u3002 podAffinity \u6709\u4e24\u79cd\u8c03\u5ea6\u7c7b\u578b\uff1a requiredDuringSchedulingIgnoredDuringExecution \uff08\u786c\u4eb2\u548c\uff09 preferredDuringSchedulingIgnoredDuringExecution \uff08\u8f6f\u4eb2\u548c\uff09 \u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u7c7b\u578b\u8bbe\u7f6e topologyKey \uff1a kubernetes.io/hostname \uff03NodeName failure-domain.beta.kubernetes.io/zone \uff03\u533a\u57df Zone failure-domain.beta.kubernetes.io/region # \u533a\u57df Zone \u6211\u4eec\u53ef\u4ee5\u8bbe\u7f6e\u8282\u70b9\u6807\u7b7e\u6765\u5bf9\u8282\u70b9\u7684\u540d\u79f0/\u533a\u57df\u8fdb\u884c\u5206\u7c7b\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u88ab podAffinity \u6240\u4f7f\u7528\u3002 \u521b\u5efapod Nginx \u3002 kubectl apply -f - < ","title":"nodeSelector"},{"location":"k8s/cka_cn/foundamentals/scheduling/#nodename","text":"\u6ce8\u610f\uff0c nodeName \u5177\u6709\u6700\u9ad8\u4f18\u5148\u7ea7\uff0c\u56e0\u4e3a\u5b83\u4e0d\u662f\u7531 Scheduler \u8fdb\u884c\u8c03\u5ea6\u7684\u3002 \u521b\u5efa\u4e00\u4e2a Pod nginx-nodename \uff0c\u5e76\u5c06\u5176\u6307\u5b9a\u5728 cka003 \u8282\u70b9\u4e0a\u3002 kubectl apply -f - < ","title":"nodeName"},{"location":"k8s/cka_cn/foundamentals/scheduling/#affinity","text":"\u5728 Kubernetes \u96c6\u7fa4\u4e2d\uff0c\u6709\u4e9b Pod \u9700\u8981\u9891\u7e41\u4e0e\u5176\u4ed6 Pod \u8fdb\u884c\u4ea4\u4e92\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5efa\u8bae\u5c06\u8fd9\u4e9b Pod \u8c03\u5ea6\u5230\u540c\u4e00\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u3002\u4f8b\u5982\uff0c\u4e24\u4e2a Pod\uff1a Nginx \u548c Mysql \uff0c\u5982\u679c\u5b83\u4eec\u9891\u7e41\u901a\u4fe1\uff0c\u5219\u9700\u8981\u5728\u540c\u4e00\u4e2a\u8282\u70b9\u4e0a\u90e8\u7f72\u5b83\u4eec\u3002 \u57fa\u4e8epod\u4e4b\u95f4\u7684\u5173\u7cfb\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 podAffinity \u8fdb\u884c\u9009\u62e9\u3002 podAffinity \u6709\u4e24\u79cd\u8c03\u5ea6\u7c7b\u578b\uff1a requiredDuringSchedulingIgnoredDuringExecution \uff08\u786c\u4eb2\u548c\uff09 preferredDuringSchedulingIgnoredDuringExecution \uff08\u8f6f\u4eb2\u548c\uff09 \u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u7c7b\u578b\u8bbe\u7f6e topologyKey \uff1a kubernetes.io/hostname \uff03NodeName failure-domain.beta.kubernetes.io/zone \uff03\u533a\u57df Zone failure-domain.beta.kubernetes.io/region # \u533a\u57df Zone \u6211\u4eec\u53ef\u4ee5\u8bbe\u7f6e\u8282\u70b9\u6807\u7b7e\u6765\u5bf9\u8282\u70b9\u7684\u540d\u79f0/\u533a\u57df\u8fdb\u884c\u5206\u7c7b\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u88ab podAffinity \u6240\u4f7f\u7528\u3002 \u521b\u5efapod Nginx \u3002 kubectl apply -f - < 80/TCP 14s app=httpd NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/httpd-app-6496d888c9-4nb6z 1/1 Running 0 77s 10.244.102.21 cka003 pod/httpd-app-6496d888c9-b7xht 1/1 Running 0 77s 10.244.112.19 cka002 \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u9a8c\u8bc1\u5bf9pod\u7684IP\u5730\u5740\u7684\u8bbf\u95ee\u3002 curl 10 .244.102.21 curl 10 .244.112.19 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002

    It works!

    \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u9a8c\u8bc1\u901a\u8fc7\u7aef\u53e3\u5bf9ClusterIP\u7684\u8bbf\u95ee\u3002 curl 11 .244.247.7:80 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002

    It works!

    \u66b4\u9732Service \u00b6 \u521b\u5efa\u4e00\u4e2a\u4e34\u65f6\u7684Pod nslookup \uff0c\u5e76\u9644\u52a0\u5230\u5b83\u4ee5\u9a8c\u8bc1DNS\u89e3\u6790\u3002\u9009\u9879 --rm \u8868\u793a\u5728\u9000\u51fa\u540e\u5220\u9664\u8be5Pod\u3002 kubectl run -it nslookup --rm --image = busybox:1.28 \u8fde\u63a5\u5230\u8fd9\u4e2aPod\u540e\uff0c\u8fd0\u884c\u547d\u4ee4 nslookup httpd-app \u3002\u6211\u4eec\u4f1a\u6536\u5230 httpd-app \u670d\u52a1\u7684 ClusterIP \u548c\u5b8c\u6574\u7684\u57df\u540d\u3002 / # nslookup httpd-app Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: httpd-app Address 1: 11.244.247.7 httpd-app.dev.svc.cluster.local \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u6267\u884c\u547d\u4ee4 kubectl get pod -o wide \u6765\u5728\u65b0\u7684\u7ec8\u7aef\u4e2d\u68c0\u67e5\u4e34\u65f6 Pod nslookup \u7684 IP \u5730\u5740\u3002Pod nslookup \u7684 IP \u5730\u5740\u4e3a 10.244.112.20 \u3002 kubectl get pod nslookup \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nslookup 1/1 Running 0 2m44s 10.244.112.20 cka002 NodePort \u00b6 \u521b\u5efa\u5e76\u5e94\u7528\u6587\u4ef6 svc-nodeport.yaml \u6765\u521b\u5efaService httpd-app \u3002 kubectl apply -f - < will update configuration to existing resources. Here the Service httpd-app is changed from ClusterIP to NodePort type. No change to the Deployment httpd-app . \u6211\u4eec\u5c06\u6536\u5230\u4ee5\u4e0b\u8f93\u51fa\u3002 \u5176\u4e2d\uff0c\u547d\u4ee4 kubectl apply -f \u5c06\u66f4\u65b0\u73b0\u6709\u8d44\u6e90\u7684\u914d\u7f6e\u3002 \u5728\u8fd9\u91cc\uff0cService httpd-app \u4ece ClusterIP \u7c7b\u578b\u66f4\u6539\u4e3a NodePort \u7c7b\u578b\u3002 \u5bf9Deployment httpd-app \u6ca1\u6709\u4efb\u4f55\u66f4\u6539\u3002 service/httpd-app configured deployment.apps/httpd-app unchanged \u901a\u8fc7\u547d\u4ee4 kubectl get svc \u6765\u68c0\u67e5Service httpd-app \uff0c\u5176\u4e2d\uff1a Service\u7684IP\u5730\u5740\u4e0d\u53d8\u3002 Service\u7684\u7c7b\u578b\u53d8\u4e3a NodePort \u3002 Service\u7684\u7aef\u53e3\u53f7\u4ece 80/TCP \u53d8\u4e3a 80:30080/TCP \u3002 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpd-app NodePort 11.244.247.7 80:30080/TCP 18m \u5728\u6bcf\u4e2a\u8282\u70b9node\u4e0a\u6267\u884c\u547d\u4ee4 curl :30080 \uff0c\u6d4b\u8bd5\u5bf9Service httpd-app \u7684\u8054\u901a\u6027\u3002 curl :30080 curl :30080 curl :30080 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002

    It works!

    Headless Service \u00b6 \u521b\u5efaHeadless Service web \u548cStatefulSet web . kubectl apply -f - < web-1 1/1 Running 0 6s 10.244.112.21 cka002 \u6267\u884c\u547d\u4ee4 kubectl describe svc -l app=web \uff0c\u68c0\u67e5\u521b\u5efa\u7684Service\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 Name : web Namespace : dev Labels : app=web Annotations : Selector : app=web Type : ClusterIP IP Family Policy : SingleStack IP Families : IPv4 IP : None IPs : None Port : web 80/TCP TargetPort : 80/TCP Endpoints : 10.244.102.22:80,10.244.112.21:80 Session Affinity : None Events : \u8fde\u63a5\u5230\u4e34\u65f6Pod nslookup \uff0c\u901a\u8fc7 nslookup \u6765\u9a8c\u8bc1DNS\u5230\u89e3\u6790\u3002 kubectl run -it nslookup --rm --image = busybox:1.28 \u901a\u8fc7 nslookup \u547d\u4ee4\u8bbf\u95eeHeadless Service web \uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u52302\u4e2apod\u7684IP\u5730\u5740\uff0c\u6ce8\u610f\u4e0d\u662f\u96c6\u7fa4IP\u5730\u5740ClusterIP\uff08\u56e0\u4e3a\u662fHeadless Service\uff09\u3002 / # nslookup web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local Address 2: 10.244.102.22 web-0.web.dev.svc.cluster.local \u6211\u4eec\u4e5f\u53ef\u4ee5\u4f7f\u7528 nslookup \u547d\u4ee4\u6765\u67e5\u627e web-0.web \u548c web-1.web \u3002Headless Service\u7684\u6bcf\u4e2a Pod \u90fd\u6709\u81ea\u5df1\u7684\u670d\u52a1\u540d\u79f0\u7528\u4e8e DNS \u67e5\u627e\u3002 / # nslookup web-0.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.web Address 1: 10.244.102.22 web-0.web.dev.svc.cluster.local / # nslookup web-1.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local \u5220\u9664\u4e0a\u9762\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete sts web kubectl delete service httpd-app web kubectl delete deployment httpd-app \u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7b56\u7565 \u00b6 Service Internal Traffic Policy\uff08\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7b56\u7565\uff09\u662fKubernetes\u4e2d\u4e00\u79cd\u7528\u4e8e\u63a7\u5236\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7684\u7b56\u7565\u3002\u5b83\u7684\u4e3b\u8981\u76ee\u7684\u662f\u63a7\u5236Service\u5bf9\u8c61\u4e2dPod\u7684\u8bbf\u95ee\u7b56\u7565\u3002 \u5728Kubernetes\u4e2d\uff0cService\u5bf9\u8c61\u5c06\u4e00\u4e2a\u865a\u62dfIP\u5730\u5740\u7ed1\u5b9a\u5230\u4e00\u7ec4Pod\u4e0a\uff0c\u4ee5\u4fbf\u53ef\u4ee5\u901a\u8fc7\u8fd9\u4e2a\u865a\u62dfIP\u5730\u5740\u6765\u8bbf\u95ee\u8fd9\u7ec4Pod\u3002Service\u5bf9\u8c61\u5728\u67d0\u79cd\u7a0b\u5ea6\u4e0a\u50cf\u8d1f\u8f7d\u5747\u8861\u5668\uff0c\u53ef\u4ee5\u5c06\u8bf7\u6c42\u6d41\u91cf\u8def\u7531\u5230\u5176\u4e0b\u9762\u7684Pod\u3002 Service\u5bf9\u8c61\u901a\u5e38\u4f1a\u4f7f\u7528\u4ee5\u4e0b\u4e24\u79cd\u7c7b\u578b\u4e4b\u4e00\u6765\u8def\u7531\u6d41\u91cf\uff1a ClusterIP\uff1a\u6b64\u7c7b\u578b\u7684Service\u53ea\u80fd\u4ece\u540c\u4e00Kubernetes\u96c6\u7fa4\u5185\u7684\u5176\u4ed6Pod\u8bbf\u95ee\uff0c\u56e0\u4e3a\u5b83\u662f\u5728Kubernetes\u96c6\u7fa4\u5185\u90e8\u8def\u7531\u8bf7\u6c42\u6d41\u91cf\u7684\u3002 NodePort\uff1a\u6b64\u7c7b\u578b\u7684Service\u5728\u6240\u6709\u8282\u70b9\u4e0a\u516c\u5f00\u4e86\u4e00\u4e2a\u9759\u6001\u7aef\u53e3\uff0c\u4ece\u800c\u53ef\u4ee5\u4ece\u96c6\u7fa4\u5916\u90e8\u8bbf\u95ee\u5b83\u3002\u4f46\u662f\uff0c\u5b83\u4ecd\u7136\u53ef\u4ee5\u4ece\u96c6\u7fa4\u5185\u90e8\u8bbf\u95ee\u3002 Service Internal Traffic Policy\u5b9a\u4e49\u4e86Pod\u5982\u4f55\u8bbf\u95ee\u540c\u4e00\u4e2aService\u4e2d\u7684\u5176\u4ed6Pod\u3002\u53ef\u4ee5\u5c06\u5176\u8bbe\u7f6e\u4e3a\u4ee5\u4e0b\u4e09\u4e2a\u9009\u9879\u4e4b\u4e00\uff1a Cluster\uff1a\u8fd9\u662f\u9ed8\u8ba4\u8bbe\u7f6e\uff0c\u5b83\u5141\u8bb8Service\u4e2d\u7684\u4efb\u4f55Pod\u90fd\u53ef\u4ee5\u8bbf\u95ee\u53e6\u4e00\u4e2aPod\u3002 Local\uff1a\u6b64\u9009\u9879\u5141\u8bb8Pod\u4ec5\u8bbf\u95ee\u5728\u540c\u4e00\u8282\u70b9\u4e0a\u8fd0\u884c\u7684\u5176\u4ed6Pod\u3002\u5982\u679cPod\u9700\u8981\u5feb\u901f\u7684\u3001\u4f4e\u5ef6\u8fdf\u7684\u7f51\u7edc\u8bbf\u95ee\uff0c\u53ef\u4ee5\u4f7f\u7528\u6b64\u9009\u9879\u3002 Disabled\uff1a\u6b64\u9009\u9879\u5c06\u5b8c\u5168\u7981\u6b62Service\u5185\u90e8\u7684\u6d41\u91cf\u3002\u5b83\u9002\u7528\u4e8e\u7279\u5b9a\u7684\u73af\u5883\u548c\u90e8\u7f72\u4e2d\u3002 \u6f14\u793a\u573a\u666f\uff1a \u6a21\u62df Service \u5185\u90e8\u6d41\u91cf\u7b56\u7565\u7684\u5de5\u4f5c\u65b9\u5f0f\u3002 \u9884\u671f\u7ed3\u679c\uff1a \u901a\u8fc7\u8bbe\u7f6e Service \u7684 internalTrafficPolicy: Local \uff0cService \u53ea\u4f1a\u5c06\u6d41\u91cf\u8def\u7531\u5230 Pod \u6240\u5728\u7684\u8282\u70b9\u5185\u90e8\u3002 \u6f14\u793a\u76ee\u7684\uff1a Service Internal Traffic Policy\uff08\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7b56\u7565\uff09\u53ef\u4ee5\u9650\u5236\u5185\u90e8\u6d41\u91cf\u4ec5\u8def\u7531\u5230\u540c\u4e00\u8282\u70b9\u4e2d\u7684\u7ec8\u7aef\u8282\u70b9\u3002 \u8fd9\u91cc\u7684\u201c\u5185\u90e8\u201d\u6d41\u91cf\u662f\u6307\u6e90\u81ea\u5f53\u524d\u96c6\u7fa4\u4e2d\u7684Pod\u7684\u6d41\u91cf\u3002 \u901a\u8fc7\u5c06\u5176 .spec.internalTrafficPolicy \u8bbe\u7f6e\u4e3a Local\uff0c\u53ef\u4ee5\u544a\u8bc9 kube-proxy \u4ec5\u5bf9\u96c6\u7fa4\u5185\u90e8\u6d41\u91cf\u4f7f\u7528\u672c\u5730\u8282\u70b9\u7684\u7ec8\u7aef\u8282\u70b9\u3002 \u5bf9\u4e8e\u4f4d\u4e8e\u6ca1\u6709\u7ed9\u5b9a\u670d\u52a1\u7684\u7ec8\u7aef\u8282\u70b9\u7684\u8282\u70b9\u4e0a\u7684Pod\uff0c\u5373\u4f7f\u670d\u52a1\u5728\u5176\u4ed6\u8282\u70b9\u4e0a\u6709\u7ec8\u7aef\u8282\u70b9\uff0c\u8be5\u670d\u52a1\u4e5f\u4f1a\u88ab\u89c6\u4e3a\u5728\u8be5\u8282\u70b9\u4e0a\u6ca1\u6709\u7ec8\u7aef\u8282\u70b9\uff08\u5bf9\u4e8e\u8be5\u8282\u70b9\u4e0a\u7684Pod\uff09\u3002 \u6f14\u793a\uff1a \u521b\u5efa Deployment my-nginx \u548c Service my-nginx . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx EOF \u4f7f\u7528\u547d\u4ee4 kubectl get pod -o wide \uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u77e5 Deployment my-nginx \u7684 Pod \u6b63\u5728\u8fd0\u884c\u5728 cka003 \u8282\u70b9\u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cf54cdbf7-bscf8 1/1 Running 0 9h 10.244.112.63 cka002 \u8ba9\u6211\u4eec\u4ece cka001 \u53d1\u9001 http \u8bf7\u6c42\u5230\u8fd0\u884c\u5728 cka002 \u4e0a\u7684 Pod\u3002 \u6211\u4eec\u5c06\u6536\u5230 Welcome to nginx! \u4fe1\u606f\uff0c\u8fd9\u610f\u5473\u7740\u8be5 Pod \u53ef\u4ee5\u4ece\u5176\u4ed6\u8282\u70b9\u8bbf\u95ee\u3002 curl 11 .244.163.60 \u73b0\u5728\u6765\u4fee\u6539Service my-nginx \u5e76\u6307\u5b9a internalTrafficPolicy: Local \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx internalTrafficPolicy: Local EOF Let's send http request from cka001 to the http request to the Pod again. We will receive curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused error information. \u6211\u4eec\u518d\u6b21\u4ece cka001 \u53d1\u9001http\u8bf7\u6c42\u5230\u8be5Pod\u3002 \u6211\u4eec\u5c06\u6536\u5230\u9519\u8bef\u4fe1\u606f curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused \u3002 curl 11 .244.163.60 \u8ba9\u6211\u4eec\u767b\u5f55\u5230 cka002 \u8282\u70b9\u5e76\u518d\u6b21\u5411 Pod \u53d1\u9001 HTTP \u8bf7\u6c42\u3002 \u6211\u4eec\u5c06\u6536\u5230 Welcome to nginx! \u7684\u4fe1\u606f\u3002 curl 11 .244.163.60 \u6f14\u793a\u7ed3\u8bba\uff1a \u8bbe\u7f6e Service \u7684 internalTrafficPolicy: Local \u540e\uff0cService \u53ea\u4f1a\u5c06\u6d41\u91cf\u8def\u7531\u5230\u5f53\u524d Pod \u6240\u5728\u7684\u8282\u70b9\u5185\u90e8\u7684 Pod\u3002 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a nginx Deployment \u6dfb\u52a0 nginx Pod\u7684\u7aef\u53e3\u53f7\u548c\u522b\u540d \u4f7f\u7528\u672c\u5730\u6d41\u91cf\u5c06Deployment\u66b4\u9732\u51fa\u53bb\u3002 \u6f14\u793a\uff1a \u4f7f\u7528\u7aef\u53e3\u53f7\u4e3a 80 \u521b\u5efa my-nginx Deployment\u3002 kubectl create deployment my-nginx --image = nginx --port = 80 \u4fee\u6539Deployment\u3002 kubectl edit deployment my-nginx \u5728 my-nginx Deployment\u4e2d\u6dfb\u52a0\u7aef\u53e3\u522b\u540d http \u3002 \u8bf7\u53c2\u8003\u4ee5\u4e0b\u90e8\u7f72\u7684 YAML \u6a21\u677f\u94fe\u63a5\uff1a https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ \u3002 spec : containers : - image : nginx imagePullPolicy : Always name : nginx ports : - containerPort : 80 protocol : TCP name : http \u4f7f\u7528 NodePort \u7c7b\u578b\u66b4\u9732 deployment\u3002 kubectl expose deployment my-nginx --port = 80 --target-port = http --name = my-nginx-svc --type = NodePort \u4fee\u6539service\uff0c\u628a internalTrafficPolicy \u4ece Cluster \u6539\u4e3a Local \u3002 kubectl edit svc my-nginx-svc \u9a8c\u8bc1\u8bbf\u95ee\u3002 \u6ce8\u610f\uff0cPod \u6b63\u5728\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u4e0a\u3002\u6211\u4eec\u5c06\u770b\u5230\u4ee5\u4e0b\u9884\u671f\u7ed3\u679c\u3002 curl :80 # succeed on node cka003. internalTrafficPolicy is effective. curl :80 # succeed on all nodes. curl : # succeed on all nodes.","title":"Service"},{"location":"k8s/cka_cn/foundamentals/service/#cka10service","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb010:Service"},{"location":"k8s/cka_cn/foundamentals/service/#_1","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u540d\u4e3a httpd-app \u7684Deployment\u3002 \u521b\u5efa\u7c7b\u578b\u4e3a ClusterIP \u7684 httpd-app \u670d\u52a1\uff0c\u9ed8\u8ba4\u7c7b\u578b\u662f ClusterIP\uff0c\u53ea\u80fd\u5185\u90e8\u8bbf\u95ee\u3002 \u9a8c\u8bc1\u5bf9Pod\u7684IP\u548c\u670d\u52a1\u7684\u96c6\u7fa4IP\u7684\u8bbf\u95ee\u3002 \u5c06 httpd-app \u670d\u52a1\u7c7b\u578b\u66f4\u65b0\u4e3a NodePort \uff0c\u4e0d\u9700\u8981\u5bf9 httpd-app \u8fd9\u4e2aDeployment\u8fdb\u884c\u4efb\u4f55\u66f4\u6539\u3002 \u9a8c\u8bc1\u8282\u70b9node\u7684\u8bbf\u95ee\u3002\u5bf9\u8282\u70b9node\u5bf9\u8bbf\u95ee\u5c06\u88ab\u8def\u7531\u5230Pod\uff0c\u4ece\u800c\u5b9e\u73b0\u4ece\u5916\u90e8\u8bbf\u95ee\u6211\u4eec\u521b\u5efa\u7684\u670d\u52a1 httpd-app \u3002 \u521b\u5efa\u65e0\u5934\u670d\u52a1\uff08Headless Service\uff09 web \u548c \u6709\u72b6\u6001\u526f\u672c\u96c6\uff08StatefulSet\uff09 web \u3002 \u670d\u52a1\u7684\u5185\u90e8\u6d41\u91cf\u7b56\u7565\u3002 NodePort \u53ef\u4ee5\u7ffb\u8bd1\u4e3a\u201c\u8282\u70b9\u7aef\u53e3\u201d\uff0c\u662f\u4e00\u79cdService\u7684\u7c7b\u578b\uff0c\u53ef\u4ee5\u901a\u8fc7\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u6253\u5f00\u4e00\u4e2a\u7aef\u53e3\uff0c\u5c06Service\u66b4\u9732\u5230\u96c6\u7fa4\u5916\u90e8\u3002 ClusterIP \u53ef\u4ee5\u7ffb\u8bd1\u4e3a\u201c\u96c6\u7fa4IP\u201d\uff0c\u4e5f\u662f\u4e00\u79cdService\u7684\u7c7b\u578b\uff0c\u4e3aService\u63d0\u4f9b\u4e86\u4e00\u4e2a\u865a\u62dfIP\u5730\u5740\uff0c\u53ef\u4ee5\u5728\u96c6\u7fa4\u5185\u90e8\u8fdb\u884c\u8bbf\u95ee\u3002\u8fd9\u4e2aIP\u5730\u5740\u901a\u5e38\u7531\u96c6\u7fa4\u4e2d\u7684Kubernetes\u4ee3\u7406\u81ea\u52a8\u5206\u914d\uff0c\u5e76\u4e14\u53ea\u80fd\u5728\u96c6\u7fa4\u5185\u90e8\u4f7f\u7528\u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/service/#clusterip","text":"","title":"ClusterIP"},{"location":"k8s/cka_cn/foundamentals/service/#service","text":"\u521b\u5efaDeployment http-app \u3002 \u521b\u5efaService httpd-app \u5e76\u901a\u8fc7\u6807\u7b7e\u9009\u62e9\u5668\uff08Label Selector\uff09\u5173\u8054\u5230Development http-app \u3002 Service\u7684\u7c7b\u578b\u662f ClusterIP \uff0c\u8fd9\u662fService\u7684\u9ed8\u8ba4\u7c7b\u578b\uff0c\u53ea\u9650\u4e8e\u5185\u90e8\u8bbf\u95ee\u3002 kubectl apply -f - < 80/TCP 14s app=httpd NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/httpd-app-6496d888c9-4nb6z 1/1 Running 0 77s 10.244.102.21 cka003 pod/httpd-app-6496d888c9-b7xht 1/1 Running 0 77s 10.244.112.19 cka002 \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u9a8c\u8bc1\u5bf9pod\u7684IP\u5730\u5740\u7684\u8bbf\u95ee\u3002 curl 10 .244.102.21 curl 10 .244.112.19 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002

    It works!

    \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u9a8c\u8bc1\u901a\u8fc7\u7aef\u53e3\u5bf9ClusterIP\u7684\u8bbf\u95ee\u3002 curl 11 .244.247.7:80 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002

    It works!

    ","title":"\u521b\u5efaService"},{"location":"k8s/cka_cn/foundamentals/service/#service_1","text":"\u521b\u5efa\u4e00\u4e2a\u4e34\u65f6\u7684Pod nslookup \uff0c\u5e76\u9644\u52a0\u5230\u5b83\u4ee5\u9a8c\u8bc1DNS\u89e3\u6790\u3002\u9009\u9879 --rm \u8868\u793a\u5728\u9000\u51fa\u540e\u5220\u9664\u8be5Pod\u3002 kubectl run -it nslookup --rm --image = busybox:1.28 \u8fde\u63a5\u5230\u8fd9\u4e2aPod\u540e\uff0c\u8fd0\u884c\u547d\u4ee4 nslookup httpd-app \u3002\u6211\u4eec\u4f1a\u6536\u5230 httpd-app \u670d\u52a1\u7684 ClusterIP \u548c\u5b8c\u6574\u7684\u57df\u540d\u3002 / # nslookup httpd-app Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: httpd-app Address 1: 11.244.247.7 httpd-app.dev.svc.cluster.local \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u6267\u884c\u547d\u4ee4 kubectl get pod -o wide \u6765\u5728\u65b0\u7684\u7ec8\u7aef\u4e2d\u68c0\u67e5\u4e34\u65f6 Pod nslookup \u7684 IP \u5730\u5740\u3002Pod nslookup \u7684 IP \u5730\u5740\u4e3a 10.244.112.20 \u3002 kubectl get pod nslookup \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nslookup 1/1 Running 0 2m44s 10.244.112.20 cka002 ","title":"\u66b4\u9732Service"},{"location":"k8s/cka_cn/foundamentals/service/#nodeport","text":"\u521b\u5efa\u5e76\u5e94\u7528\u6587\u4ef6 svc-nodeport.yaml \u6765\u521b\u5efaService httpd-app \u3002 kubectl apply -f - < will update configuration to existing resources. Here the Service httpd-app is changed from ClusterIP to NodePort type. No change to the Deployment httpd-app . \u6211\u4eec\u5c06\u6536\u5230\u4ee5\u4e0b\u8f93\u51fa\u3002 \u5176\u4e2d\uff0c\u547d\u4ee4 kubectl apply -f \u5c06\u66f4\u65b0\u73b0\u6709\u8d44\u6e90\u7684\u914d\u7f6e\u3002 \u5728\u8fd9\u91cc\uff0cService httpd-app \u4ece ClusterIP \u7c7b\u578b\u66f4\u6539\u4e3a NodePort \u7c7b\u578b\u3002 \u5bf9Deployment httpd-app \u6ca1\u6709\u4efb\u4f55\u66f4\u6539\u3002 service/httpd-app configured deployment.apps/httpd-app unchanged \u901a\u8fc7\u547d\u4ee4 kubectl get svc \u6765\u68c0\u67e5Service httpd-app \uff0c\u5176\u4e2d\uff1a Service\u7684IP\u5730\u5740\u4e0d\u53d8\u3002 Service\u7684\u7c7b\u578b\u53d8\u4e3a NodePort \u3002 Service\u7684\u7aef\u53e3\u53f7\u4ece 80/TCP \u53d8\u4e3a 80:30080/TCP \u3002 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpd-app NodePort 11.244.247.7 80:30080/TCP 18m \u5728\u6bcf\u4e2a\u8282\u70b9node\u4e0a\u6267\u884c\u547d\u4ee4 curl :30080 \uff0c\u6d4b\u8bd5\u5bf9Service httpd-app \u7684\u8054\u901a\u6027\u3002 curl :30080 curl :30080 curl :30080 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002

    It works!

    ","title":"NodePort"},{"location":"k8s/cka_cn/foundamentals/service/#headless-service","text":"\u521b\u5efaHeadless Service web \u548cStatefulSet web . kubectl apply -f - < web-1 1/1 Running 0 6s 10.244.112.21 cka002 \u6267\u884c\u547d\u4ee4 kubectl describe svc -l app=web \uff0c\u68c0\u67e5\u521b\u5efa\u7684Service\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 Name : web Namespace : dev Labels : app=web Annotations : Selector : app=web Type : ClusterIP IP Family Policy : SingleStack IP Families : IPv4 IP : None IPs : None Port : web 80/TCP TargetPort : 80/TCP Endpoints : 10.244.102.22:80,10.244.112.21:80 Session Affinity : None Events : \u8fde\u63a5\u5230\u4e34\u65f6Pod nslookup \uff0c\u901a\u8fc7 nslookup \u6765\u9a8c\u8bc1DNS\u5230\u89e3\u6790\u3002 kubectl run -it nslookup --rm --image = busybox:1.28 \u901a\u8fc7 nslookup \u547d\u4ee4\u8bbf\u95eeHeadless Service web \uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u52302\u4e2apod\u7684IP\u5730\u5740\uff0c\u6ce8\u610f\u4e0d\u662f\u96c6\u7fa4IP\u5730\u5740ClusterIP\uff08\u56e0\u4e3a\u662fHeadless Service\uff09\u3002 / # nslookup web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local Address 2: 10.244.102.22 web-0.web.dev.svc.cluster.local \u6211\u4eec\u4e5f\u53ef\u4ee5\u4f7f\u7528 nslookup \u547d\u4ee4\u6765\u67e5\u627e web-0.web \u548c web-1.web \u3002Headless Service\u7684\u6bcf\u4e2a Pod \u90fd\u6709\u81ea\u5df1\u7684\u670d\u52a1\u540d\u79f0\u7528\u4e8e DNS \u67e5\u627e\u3002 / # nslookup web-0.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.web Address 1: 10.244.102.22 web-0.web.dev.svc.cluster.local / # nslookup web-1.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local \u5220\u9664\u4e0a\u9762\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete sts web kubectl delete service httpd-app web kubectl delete deployment httpd-app","title":"Headless Service"},{"location":"k8s/cka_cn/foundamentals/service/#_2","text":"Service Internal Traffic Policy\uff08\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7b56\u7565\uff09\u662fKubernetes\u4e2d\u4e00\u79cd\u7528\u4e8e\u63a7\u5236\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7684\u7b56\u7565\u3002\u5b83\u7684\u4e3b\u8981\u76ee\u7684\u662f\u63a7\u5236Service\u5bf9\u8c61\u4e2dPod\u7684\u8bbf\u95ee\u7b56\u7565\u3002 \u5728Kubernetes\u4e2d\uff0cService\u5bf9\u8c61\u5c06\u4e00\u4e2a\u865a\u62dfIP\u5730\u5740\u7ed1\u5b9a\u5230\u4e00\u7ec4Pod\u4e0a\uff0c\u4ee5\u4fbf\u53ef\u4ee5\u901a\u8fc7\u8fd9\u4e2a\u865a\u62dfIP\u5730\u5740\u6765\u8bbf\u95ee\u8fd9\u7ec4Pod\u3002Service\u5bf9\u8c61\u5728\u67d0\u79cd\u7a0b\u5ea6\u4e0a\u50cf\u8d1f\u8f7d\u5747\u8861\u5668\uff0c\u53ef\u4ee5\u5c06\u8bf7\u6c42\u6d41\u91cf\u8def\u7531\u5230\u5176\u4e0b\u9762\u7684Pod\u3002 Service\u5bf9\u8c61\u901a\u5e38\u4f1a\u4f7f\u7528\u4ee5\u4e0b\u4e24\u79cd\u7c7b\u578b\u4e4b\u4e00\u6765\u8def\u7531\u6d41\u91cf\uff1a ClusterIP\uff1a\u6b64\u7c7b\u578b\u7684Service\u53ea\u80fd\u4ece\u540c\u4e00Kubernetes\u96c6\u7fa4\u5185\u7684\u5176\u4ed6Pod\u8bbf\u95ee\uff0c\u56e0\u4e3a\u5b83\u662f\u5728Kubernetes\u96c6\u7fa4\u5185\u90e8\u8def\u7531\u8bf7\u6c42\u6d41\u91cf\u7684\u3002 NodePort\uff1a\u6b64\u7c7b\u578b\u7684Service\u5728\u6240\u6709\u8282\u70b9\u4e0a\u516c\u5f00\u4e86\u4e00\u4e2a\u9759\u6001\u7aef\u53e3\uff0c\u4ece\u800c\u53ef\u4ee5\u4ece\u96c6\u7fa4\u5916\u90e8\u8bbf\u95ee\u5b83\u3002\u4f46\u662f\uff0c\u5b83\u4ecd\u7136\u53ef\u4ee5\u4ece\u96c6\u7fa4\u5185\u90e8\u8bbf\u95ee\u3002 Service Internal Traffic Policy\u5b9a\u4e49\u4e86Pod\u5982\u4f55\u8bbf\u95ee\u540c\u4e00\u4e2aService\u4e2d\u7684\u5176\u4ed6Pod\u3002\u53ef\u4ee5\u5c06\u5176\u8bbe\u7f6e\u4e3a\u4ee5\u4e0b\u4e09\u4e2a\u9009\u9879\u4e4b\u4e00\uff1a Cluster\uff1a\u8fd9\u662f\u9ed8\u8ba4\u8bbe\u7f6e\uff0c\u5b83\u5141\u8bb8Service\u4e2d\u7684\u4efb\u4f55Pod\u90fd\u53ef\u4ee5\u8bbf\u95ee\u53e6\u4e00\u4e2aPod\u3002 Local\uff1a\u6b64\u9009\u9879\u5141\u8bb8Pod\u4ec5\u8bbf\u95ee\u5728\u540c\u4e00\u8282\u70b9\u4e0a\u8fd0\u884c\u7684\u5176\u4ed6Pod\u3002\u5982\u679cPod\u9700\u8981\u5feb\u901f\u7684\u3001\u4f4e\u5ef6\u8fdf\u7684\u7f51\u7edc\u8bbf\u95ee\uff0c\u53ef\u4ee5\u4f7f\u7528\u6b64\u9009\u9879\u3002 Disabled\uff1a\u6b64\u9009\u9879\u5c06\u5b8c\u5168\u7981\u6b62Service\u5185\u90e8\u7684\u6d41\u91cf\u3002\u5b83\u9002\u7528\u4e8e\u7279\u5b9a\u7684\u73af\u5883\u548c\u90e8\u7f72\u4e2d\u3002 \u6f14\u793a\u573a\u666f\uff1a \u6a21\u62df Service \u5185\u90e8\u6d41\u91cf\u7b56\u7565\u7684\u5de5\u4f5c\u65b9\u5f0f\u3002 \u9884\u671f\u7ed3\u679c\uff1a \u901a\u8fc7\u8bbe\u7f6e Service \u7684 internalTrafficPolicy: Local \uff0cService \u53ea\u4f1a\u5c06\u6d41\u91cf\u8def\u7531\u5230 Pod \u6240\u5728\u7684\u8282\u70b9\u5185\u90e8\u3002 \u6f14\u793a\u76ee\u7684\uff1a Service Internal Traffic Policy\uff08\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7b56\u7565\uff09\u53ef\u4ee5\u9650\u5236\u5185\u90e8\u6d41\u91cf\u4ec5\u8def\u7531\u5230\u540c\u4e00\u8282\u70b9\u4e2d\u7684\u7ec8\u7aef\u8282\u70b9\u3002 \u8fd9\u91cc\u7684\u201c\u5185\u90e8\u201d\u6d41\u91cf\u662f\u6307\u6e90\u81ea\u5f53\u524d\u96c6\u7fa4\u4e2d\u7684Pod\u7684\u6d41\u91cf\u3002 \u901a\u8fc7\u5c06\u5176 .spec.internalTrafficPolicy \u8bbe\u7f6e\u4e3a Local\uff0c\u53ef\u4ee5\u544a\u8bc9 kube-proxy \u4ec5\u5bf9\u96c6\u7fa4\u5185\u90e8\u6d41\u91cf\u4f7f\u7528\u672c\u5730\u8282\u70b9\u7684\u7ec8\u7aef\u8282\u70b9\u3002 \u5bf9\u4e8e\u4f4d\u4e8e\u6ca1\u6709\u7ed9\u5b9a\u670d\u52a1\u7684\u7ec8\u7aef\u8282\u70b9\u7684\u8282\u70b9\u4e0a\u7684Pod\uff0c\u5373\u4f7f\u670d\u52a1\u5728\u5176\u4ed6\u8282\u70b9\u4e0a\u6709\u7ec8\u7aef\u8282\u70b9\uff0c\u8be5\u670d\u52a1\u4e5f\u4f1a\u88ab\u89c6\u4e3a\u5728\u8be5\u8282\u70b9\u4e0a\u6ca1\u6709\u7ec8\u7aef\u8282\u70b9\uff08\u5bf9\u4e8e\u8be5\u8282\u70b9\u4e0a\u7684Pod\uff09\u3002 \u6f14\u793a\uff1a \u521b\u5efa Deployment my-nginx \u548c Service my-nginx . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx EOF \u4f7f\u7528\u547d\u4ee4 kubectl get pod -o wide \uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u77e5 Deployment my-nginx \u7684 Pod \u6b63\u5728\u8fd0\u884c\u5728 cka003 \u8282\u70b9\u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cf54cdbf7-bscf8 1/1 Running 0 9h 10.244.112.63 cka002 \u8ba9\u6211\u4eec\u4ece cka001 \u53d1\u9001 http \u8bf7\u6c42\u5230\u8fd0\u884c\u5728 cka002 \u4e0a\u7684 Pod\u3002 \u6211\u4eec\u5c06\u6536\u5230 Welcome to nginx! \u4fe1\u606f\uff0c\u8fd9\u610f\u5473\u7740\u8be5 Pod \u53ef\u4ee5\u4ece\u5176\u4ed6\u8282\u70b9\u8bbf\u95ee\u3002 curl 11 .244.163.60 \u73b0\u5728\u6765\u4fee\u6539Service my-nginx \u5e76\u6307\u5b9a internalTrafficPolicy: Local \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx internalTrafficPolicy: Local EOF Let's send http request from cka001 to the http request to the Pod again. We will receive curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused error information. \u6211\u4eec\u518d\u6b21\u4ece cka001 \u53d1\u9001http\u8bf7\u6c42\u5230\u8be5Pod\u3002 \u6211\u4eec\u5c06\u6536\u5230\u9519\u8bef\u4fe1\u606f curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused \u3002 curl 11 .244.163.60 \u8ba9\u6211\u4eec\u767b\u5f55\u5230 cka002 \u8282\u70b9\u5e76\u518d\u6b21\u5411 Pod \u53d1\u9001 HTTP \u8bf7\u6c42\u3002 \u6211\u4eec\u5c06\u6536\u5230 Welcome to nginx! \u7684\u4fe1\u606f\u3002 curl 11 .244.163.60 \u6f14\u793a\u7ed3\u8bba\uff1a \u8bbe\u7f6e Service \u7684 internalTrafficPolicy: Local \u540e\uff0cService \u53ea\u4f1a\u5c06\u6d41\u91cf\u8def\u7531\u5230\u5f53\u524d Pod \u6240\u5728\u7684\u8282\u70b9\u5185\u90e8\u7684 Pod\u3002 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a nginx Deployment \u6dfb\u52a0 nginx Pod\u7684\u7aef\u53e3\u53f7\u548c\u522b\u540d \u4f7f\u7528\u672c\u5730\u6d41\u91cf\u5c06Deployment\u66b4\u9732\u51fa\u53bb\u3002 \u6f14\u793a\uff1a \u4f7f\u7528\u7aef\u53e3\u53f7\u4e3a 80 \u521b\u5efa my-nginx Deployment\u3002 kubectl create deployment my-nginx --image = nginx --port = 80 \u4fee\u6539Deployment\u3002 kubectl edit deployment my-nginx \u5728 my-nginx Deployment\u4e2d\u6dfb\u52a0\u7aef\u53e3\u522b\u540d http \u3002 \u8bf7\u53c2\u8003\u4ee5\u4e0b\u90e8\u7f72\u7684 YAML \u6a21\u677f\u94fe\u63a5\uff1a https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ \u3002 spec : containers : - image : nginx imagePullPolicy : Always name : nginx ports : - containerPort : 80 protocol : TCP name : http \u4f7f\u7528 NodePort \u7c7b\u578b\u66b4\u9732 deployment\u3002 kubectl expose deployment my-nginx --port = 80 --target-port = http --name = my-nginx-svc --type = NodePort \u4fee\u6539service\uff0c\u628a internalTrafficPolicy \u4ece Cluster \u6539\u4e3a Local \u3002 kubectl edit svc my-nginx-svc \u9a8c\u8bc1\u8bbf\u95ee\u3002 \u6ce8\u610f\uff0cPod \u6b63\u5728\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u4e0a\u3002\u6211\u4eec\u5c06\u770b\u5230\u4ee5\u4e0b\u9884\u671f\u7ed3\u679c\u3002 curl :80 # succeed on node cka003. internalTrafficPolicy is effective. curl :80 # succeed on all nodes. curl : # succeed on all nodes.","title":"\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7b56\u7565"},{"location":"k8s/cka_cn/foundamentals/statefulset/","text":"CKA\u81ea\u5b66\u7b14\u8bb012:StatefulSet \u00b6 \u6f14\u793a\u573a\u666f \u00b6 \u521b\u5efa\u4e00\u4e2a Headless Service nginx \u548c\u4e00\u4e2aStatefulSet web \u6269\u5c55 StatefulSet web \u6f14\u793a \u00b6 \u521b\u5efa\u4e00\u4e2a Headless Service nginx \u548c\u4e00\u4e2aStatefulSet web kubectl apply -f - << EOF --- apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: \"nginx\" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web EOF \u8bfb\u53d6\u4e0a\u4e00\u6b65\u521b\u5efa\u7684StatefulSet Pod \u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get pod | grep web \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE web-0 1 /1 Running 0 27s web-1 1 /1 Running 0 10s \u4f7f\u7528\u547d\u4ee4 kubectl edit sts web \u66f4\u65b0\u73b0\u6709\u7684 StatefulSet\u3002 \u53ea\u6709\u4ee5\u4e0b\u5b57\u6bb5\u53ef\u4ee5\u66f4\u65b0\uff1a replicas \u3001 image \u3001 rolling updates \u3001 labels \u3001 resource request/limit \u548c annotations \u3002 \u6ce8\u610f\uff1a\u5f53 StatefulSet Pod \u5728\u5f53\u524d\u8282\u70b9\u4e2d\u6b7b\u4ea1\u65f6\uff0c\u4e0d\u4f1a\u81ea\u52a8\u5728\u5176\u4ed6\u8282\u70b9\u4e2d\u521b\u5efa\u526f\u672c\u3002 \u6269\u5c55 StatefulSet\u3002 \u5c06 StatefulSet web \u7684\u526f\u672c\u6570\u6269\u5c55\u5230 5 \u3002 kubectl scale sts web --replicas = 5 \u53c2\u8003\uff1a Partition\u8868\u793a\u5728\u66f4\u65b0\u671f\u95f4\u5e94\u5c06 StatefulSet \u5212\u5206\u4e3a\u54ea\u4e2a\u5e8f\u53f7\u3002 \u5728\u6eda\u52a8\u66f4\u65b0\u671f\u95f4\uff0c\u4ece\u5e8f\u53f7 Replicas-1 \u5230 Partition \u7684\u6240\u6709 Pod \u90fd\u4f1a\u66f4\u65b0\u3002 \u4ece\u5e8f\u53f7 Partition-1 \u5230 0 \u7684\u6240\u6709 Pod \u90fd\u4fdd\u6301\u4e0d\u53d8\u3002\u8fd9\u5bf9\u4e8e\u8fdb\u884c\u91d1\u4e1d\u96c0\u90e8\u7f72\u975e\u5e38\u6709\u7528\u3002\u9ed8\u8ba4\u503c\u4e3a0\u3002 \u547d\u4ee4\uff1a kubectl explain statefulsets.spec.updateStrategy.rollingUpdate.partition \u91d1\u4e1d\u96c0\u90e8\u7f72\u662f\u4e00\u79cd\u8f6f\u4ef6\u90e8\u7f72\u6280\u672f\uff0c\u5176\u4e2d\u5728\u5c06\u65b0\u529f\u80fd\u6216\u7248\u672c\u53d1\u5e03\u7ed9\u66f4\u5927\u7684\u7528\u6237\u5b50\u96c6\u6216\u6240\u6709\u7528\u6237\u4e4b\u524d\uff0c\u5148\u5c06\u5176\u53d1\u5e03\u7ed9\u751f\u4ea7\u4e2d\u7684\u4e00\u5c0f\u90e8\u5206\u7528\u6237\u3002 \u8fd9\u79cd\u6280\u672f\u662f\u4f4e\u98ce\u9669\u7684\uff0c\u56e0\u4e3a\u65b0\u529f\u80fd\u6700\u521d\u53ea\u90e8\u7f72\u7ed9\u5c11\u91cf\u7528\u6237\u3002 \"Canary\"\u4e00\u8bcd\u6e90\u81ea\u65e7\u7684\u7164\u77ff\u6280\u672f\uff0c\u5f53\u65f6\u91d1\u4e1d\u96c0\u88ab\u7528\u4f5c\u7a7a\u6c14\u4e2d\u6bd2\u7d20\u7684\u65e9\u671f\u63a2\u6d4b\u5668\u3002 \u5728\u91d1\u4e1d\u96c0\u90e8\u7f72\u4e2d\uff0c\u76ee\u6807\u73af\u5883\u4e2d\u7684\u6240\u6709\u57fa\u7840\u8bbe\u65bd\u90fd\u4f1a\u4ee5\u5c0f\u9636\u6bb5\u8fdb\u884c\u66f4\u65b0\u3002 \u5b83\u7528\u4e8e\u6d4b\u8bd5\u65b0\u529f\u80fd\u548c\u5347\u7ea7\u4ee5\u67e5\u770b\u5b83\u4eec\u5982\u4f55\u5904\u7406\u751f\u4ea7\u73af\u5883\u3002 \u5220\u9664\u6240\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete sts web kubectl delete service nginx","title":"StatefulSet"},{"location":"k8s/cka_cn/foundamentals/statefulset/#cka12statefulset","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb012:StatefulSet"},{"location":"k8s/cka_cn/foundamentals/statefulset/#_1","text":"\u521b\u5efa\u4e00\u4e2a Headless Service nginx \u548c\u4e00\u4e2aStatefulSet web \u6269\u5c55 StatefulSet web","title":"\u6f14\u793a\u573a\u666f"},{"location":"k8s/cka_cn/foundamentals/statefulset/#_2","text":"\u521b\u5efa\u4e00\u4e2a Headless Service nginx \u548c\u4e00\u4e2aStatefulSet web kubectl apply -f - << EOF --- apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: \"nginx\" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web EOF \u8bfb\u53d6\u4e0a\u4e00\u6b65\u521b\u5efa\u7684StatefulSet Pod \u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get pod | grep web \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE web-0 1 /1 Running 0 27s web-1 1 /1 Running 0 10s \u4f7f\u7528\u547d\u4ee4 kubectl edit sts web \u66f4\u65b0\u73b0\u6709\u7684 StatefulSet\u3002 \u53ea\u6709\u4ee5\u4e0b\u5b57\u6bb5\u53ef\u4ee5\u66f4\u65b0\uff1a replicas \u3001 image \u3001 rolling updates \u3001 labels \u3001 resource request/limit \u548c annotations \u3002 \u6ce8\u610f\uff1a\u5f53 StatefulSet Pod \u5728\u5f53\u524d\u8282\u70b9\u4e2d\u6b7b\u4ea1\u65f6\uff0c\u4e0d\u4f1a\u81ea\u52a8\u5728\u5176\u4ed6\u8282\u70b9\u4e2d\u521b\u5efa\u526f\u672c\u3002 \u6269\u5c55 StatefulSet\u3002 \u5c06 StatefulSet web \u7684\u526f\u672c\u6570\u6269\u5c55\u5230 5 \u3002 kubectl scale sts web --replicas = 5 \u53c2\u8003\uff1a Partition\u8868\u793a\u5728\u66f4\u65b0\u671f\u95f4\u5e94\u5c06 StatefulSet \u5212\u5206\u4e3a\u54ea\u4e2a\u5e8f\u53f7\u3002 \u5728\u6eda\u52a8\u66f4\u65b0\u671f\u95f4\uff0c\u4ece\u5e8f\u53f7 Replicas-1 \u5230 Partition \u7684\u6240\u6709 Pod \u90fd\u4f1a\u66f4\u65b0\u3002 \u4ece\u5e8f\u53f7 Partition-1 \u5230 0 \u7684\u6240\u6709 Pod \u90fd\u4fdd\u6301\u4e0d\u53d8\u3002\u8fd9\u5bf9\u4e8e\u8fdb\u884c\u91d1\u4e1d\u96c0\u90e8\u7f72\u975e\u5e38\u6709\u7528\u3002\u9ed8\u8ba4\u503c\u4e3a0\u3002 \u547d\u4ee4\uff1a kubectl explain statefulsets.spec.updateStrategy.rollingUpdate.partition \u91d1\u4e1d\u96c0\u90e8\u7f72\u662f\u4e00\u79cd\u8f6f\u4ef6\u90e8\u7f72\u6280\u672f\uff0c\u5176\u4e2d\u5728\u5c06\u65b0\u529f\u80fd\u6216\u7248\u672c\u53d1\u5e03\u7ed9\u66f4\u5927\u7684\u7528\u6237\u5b50\u96c6\u6216\u6240\u6709\u7528\u6237\u4e4b\u524d\uff0c\u5148\u5c06\u5176\u53d1\u5e03\u7ed9\u751f\u4ea7\u4e2d\u7684\u4e00\u5c0f\u90e8\u5206\u7528\u6237\u3002 \u8fd9\u79cd\u6280\u672f\u662f\u4f4e\u98ce\u9669\u7684\uff0c\u56e0\u4e3a\u65b0\u529f\u80fd\u6700\u521d\u53ea\u90e8\u7f72\u7ed9\u5c11\u91cf\u7528\u6237\u3002 \"Canary\"\u4e00\u8bcd\u6e90\u81ea\u65e7\u7684\u7164\u77ff\u6280\u672f\uff0c\u5f53\u65f6\u91d1\u4e1d\u96c0\u88ab\u7528\u4f5c\u7a7a\u6c14\u4e2d\u6bd2\u7d20\u7684\u65e9\u671f\u63a2\u6d4b\u5668\u3002 \u5728\u91d1\u4e1d\u96c0\u90e8\u7f72\u4e2d\uff0c\u76ee\u6807\u73af\u5883\u4e2d\u7684\u6240\u6709\u57fa\u7840\u8bbe\u65bd\u90fd\u4f1a\u4ee5\u5c0f\u9636\u6bb5\u8fdb\u884c\u66f4\u65b0\u3002 \u5b83\u7528\u4e8e\u6d4b\u8bd5\u65b0\u529f\u80fd\u548c\u5347\u7ea7\u4ee5\u67e5\u770b\u5b83\u4eec\u5982\u4f55\u5904\u7406\u751f\u4ea7\u73af\u5883\u3002 \u5220\u9664\u6240\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete sts web kubectl delete service nginx","title":"\u6f14\u793a"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/","text":"CKA\u81ea\u5b66\u7b14\u8bb025:Troubleshooting \u00b6 \u4e8b\u4ef6 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u63cf\u8ff0pod\u4ee5\u83b7\u53d6\u4e8b\u4ef6\u4fe1\u606f\u3002 \u6f14\u793a\uff1a \u547d\u4ee4\u7528\u6cd5\uff1a kubectl describe --namespace = \u67e5\u8be2pod\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 \u521b\u5efa\u4e00\u4e2aTomcat\u7684pod\u3002 kubectl run tomcat --image = tomcat \u67e5\u8be2pod\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl describe pod/tomcat \u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 55s default-scheduler Successfully assigned dev/tomcat to cka002 Normal Pulling 54s kubelet Pulling image \"tomcat\" Normal Pulled 21s kubelet Successfully pulled image \"tomcat\" in 33.134162692s Normal Created 19s kubelet Created container tomcat Normal Started 19s kubelet Started container tomcat \u67e5\u8be2namespace\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl get events -n \u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u9ed8\u8ba4namespace\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 LAST SEEN TYPE REASON OBJECT MESSAGE 70s Warning FailedGetScale horizontalpodautoscaler/nginx deployments/scale.apps \"podinfo\" not found 2m16s Normal Scheduled pod/tomcat Successfully assigned dev/tomcat to cka002 2m15s Normal Pulling pod/tomcat Pulling image \"tomcat\" 102s Normal Pulled pod/tomcat Successfully pulled image \"tomcat\" in 33.134162692s 100s Normal Created pod/tomcat Created container tomcat 100s Normal Started pod/tomcat Started container tomcat \u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u6240\u6709\u7684namespace\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl get events -A \u65e5\u5fd7 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u67e5\u8be2pod\u7684\u65e5\u5fd7 \u547d\u4ee4\u7528\u6cd5\uff1a kubectl logs -n \u9009\u9879\uff1a --tail : \u663e\u793a\u8f93\u51fa\u7684\u6700\u8fd1 \u884c\u3002 -f \uff1a\u5b9e\u65f6\u6d41\u5f0f\u663e\u793a\u8f93\u51fa\u3002 \u663e\u793a\u8f93\u51fa\u7684\u6700\u8fd1100\u884c\u8f93\u51fa\u3002 kubectl logs -f tomcat --tail 100 \u5982\u679c\u662f\u4e00\u4e2a\u591a\u5bb9\u5668pod\uff0c\u5219\u4f7f\u7528\u9009\u9879 -c \u6765\u6307\u5b9a\u67d0\u4e2a\u7279\u5b9a\u7684\u5bb9\u5668\u3002 kubectl logs -f tomcat --tail 100 -c tomcat \u8282\u70b9\u53ef\u7528\u6027 \u00b6 \u67e5\u770b\u53ef\u7528\u8282\u70b9 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u67e5\u770b\u8282\u70b9\u53ef\u7528\u6027 \u6f14\u793a\uff1a \u65b9\u5f0f1\uff1a kubectl describe node | grep -i taint \u624b\u5de5\u65b9\u5f0f\u68c0\u67e5\u65e5\u5fd7\uff0c\u4e0b\u9762\u7684\u4f8b\u5b50\u8bf4\u660e2\u4e2a\u8282\u70b9\u5904\u4e8e\u4e0d\u53ef\u7528\u72b6\u6001\u3002 Taints : node-role.kubernetes.io/control-plane:NoSchedule Taints : Taints : \u65b9\u5f0f2\uff1a kubectl describe node | grep -i taint | grep -vc NoSchedule \u8fd9\u91cc\u6211\u4eec\u4f1a\u5f97\u5230\u76f8\u540c\u7684\u7ed3\u679c\uff0c2\u4e2a\u8282\u70b9\u5904\u4e8e\u4e0d\u53ef\u7528\u72b6\u6001\u3002\u8fd9\u91cc\u7684 -v \u8868\u793a\u6392\u9664\uff0c -c \u8868\u793a\u8ba1\u6570\u3002 \u67e5\u770b\u4e0d\u53ef\u7528\u8282\u70b9 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u5f53\u6211\u4eec\u5728Worker\u8282\u70b9 cka002 \u4e0a\u505c\u6b62 kubelet \u670d\u52a1\u65f6\uff0c \u6bcf\u4e2a\u8282\u70b9\u7684\u72b6\u6001\u662f\u4ec0\u4e48\uff1f \u901a\u8fc7 nerdctl \u547d\u4ee4\u66f4\u6539\u4e86\u54ea\u4e9b\u5bb9\u5668\uff1f \u901a\u8fc7\u547d\u4ee4 kubectl get pod -owide -A \u67e5\u770b\u7684Pod\u72b6\u6001\u662f\u4ec0\u4e48\uff1f \u6f14\u793a\uff1a \u5728 cka002 \u8282\u70b9\u4e0a\u6267\u884c\u547d\u4ee4 systemctl stop kubelet.service \u3002 \u5728 cka001 \u6216 cka003 \u4e0a\u6267\u884c\u547d\u4ee4 kubectl get node \uff0c\u53ef\u4ee5\u770b\u5230 cka002 \u7684\u72b6\u6001\u4ece Ready \u53d8\u4e3a NotReady \u3002 \u5728 cka002 \u4e0a\u6267\u884c\u547d\u4ee4 nerdctl -n k8s.io container ls \uff0c\u53ef\u4ee5\u770b\u5230\u6240\u6709\u5bb9\u5668\u90fd\u4ecd\u5728\u8fd0\u884c\uff0c\u5305\u62ecPod my-first-pod \u3002 \u5728 cka002 \u4e0a\u6267\u884c\u547d\u4ee4 systemctl start kubelet.service \u3002 \u7ed3\u8bba\uff1a \u8282\u70b9\u72b6\u6001\u7531 Ready \u53d8\u4e3a NotReady \u3002 \u5bf9\u4e8e\u90a3\u4e9b\u7c7b\u4f3c calico \u3001 kube-proxy \u8fd9\u6837\u7684 DaemonSet Pod\uff0c\u5b83\u4eec\u4e13\u95e8\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u3002\u5728 kubelet \u505c\u6b62\u540e\u5b83\u4eec\u4e0d\u4f1a\u88ab\u7ec8\u6b62\u3002 Pod my-first-pod \u7684\u72b6\u6001\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u4ecd\u7136\u663e\u793a\u4e3a Terminating \uff0c\u56e0\u4e3a\u72b6\u6001\u65e0\u6cd5\u901a\u8fc7 apiserver \u4ece cka002 \u540c\u6b65\u5230\u5176\u4ed6\u8282\u70b9\uff0c\u56e0\u4e3a kubelet \u5df2\u505c\u6b62\u3002 Pod\u7684\u72b6\u6001\u7531\u63a7\u5236\u5668\u6807\u8bb0\u5e76\u7531 kubelet \u56de\u6536\u3002 \u5f53\u6211\u4eec\u5728 cka003 \u4e0a\u542f\u52a8 kubelet \u670d\u52a1\u65f6\uff0cPod my-first-pod \u5c06\u5b8c\u5168\u5728 cka002 \u4e0a\u88ab\u7ec8\u6b62\u3002 \u6b64\u5916\uff0c\u8ba9\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u526f\u672c\u6570\u4e3a3\u7684Deployment\u3002\u5176\u4e2d\u4e24\u4e2a\u526f\u672c\u8fd0\u884c\u5728 cka003 \u4e0a\uff0c\u53e6\u4e00\u4e2a\u526f\u672c\u8fd0\u884c\u5728 cka002 \u4e0a\u3002 kubectl get pod -o wide -w \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-9d745469b-2xdk4 1/1 Running 0 2m8s 10.244.2.3 cka003 nginx-deployment-9d745469b-4gvmr 1/1 Running 0 2m8s 10.244.2.4 cka003 nginx-deployment-9d745469b-5j927 1/1 Running 0 2m8s 10.244.1.3 cka002 \u5728\u6211\u4eec\u505c\u6b62 cka003 \u4e0a\u7684 kubelet \u670d\u52a1\u540e\uff0c\u539f\u5148\u5728 cka003 \u4e0a\u8fd0\u884c\u7684\u4e24\u4e2a\u526f\u672c\u4f1a\u88ab\u7ec8\u6b62\uff0c\u7136\u540e\u4f1a\u81ea\u52a8\u5728 cka002 \u4e0a\u521b\u5efa\u4e24\u4e2a\u65b0\u7684\u526f\u672c\u5e76\u8fd0\u884c\u3002 \u76d1\u63a7\u6307\u6807 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u67e5\u8be2pod\u7684\u76d1\u63a7\u6307\u6807 \u6f14\u793a\uff1a \u67e5\u8be2\u8282\u70b9\u7684\u5065\u5eb7\u4fe1\u606f\u3002 kubectl top node \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 147m 7% 1940Mi 50% cka002 62m 3% 2151Mi 56% cka003 63m 3% 1825Mi 47% \u67e5\u8be2pod\u7684\u76d1\u63a7\u6307\u6807\u3002 kubectl top pod \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) MEMORY(bytes) busybox-with-secret 0m 0Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi tomcat 1m 58Mi \u901a\u8fc7\u9009\u9879 --sort-by \uff0c\u5bf9\u8f93\u51fa\u7ed3\u679c\u6309\u7167CPU\u6216\u8005\u5185\u5b58\u7528\u91cf\u8fdb\u884c\u6392\u5e8f\u3002 kubectl top pod --sort-by = cpu kubectl top pod --sort-by = memory \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) MEMORY(bytes) nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi tomcat 1m 58Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi busybox-with-secret 0m 0Mi \u8282\u70b9\u9a71\u9010 \u00b6 \u8282\u70b9\u7684\u53ef\u8c03\u5ea6\u6027 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u8282\u70b9\u8c03\u5ea6 \u6f14\u793a\uff1a \u7981\u6b62\u4e00\u4e2a\u8282\u70b9\u7684\u8c03\u5ea6\u3002 kubectl cordon \u4e3e\u4f8b\uff1a kubectl cordon cka003 \u8f93\u51fa\u7ed3\u679c\uff0c\u8282\u70b9\u72b6\u6001\u5982\u4e0b\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready,SchedulingDisabled 18d v1.24.0 \u6fc0\u6d3b\u4e00\u4e2a\u8282\u70b9\u7684\u8c03\u5ea6\u3002 kubectl uncordon \u4e3e\u4f8b\uff1a kubectl uncordon cka003 \u8f93\u51fa\u7ed3\u679c\uff0c\u8282\u70b9\u72b6\u6001\u5982\u4e0b\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready 18d v1.24.0 \u9a71\u9010\u8282\u70b9 \u00b6 \u6f14\u793a\u5185\u5bb9\uff1a \u9a71\u9010\u8282\u70b9 cka003 \u6f14\u793a\uff1a \u83b7\u53d6\u5f53\u524d\u8fd0\u884cpod\u7684\u5217\u8868\u3002 kubectl get pod -o wide \u5176\u4e2d\u6709\u4e00\u4e2apod\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-xk8nw 1/1 Running 0 22h 10.244.102.3 cka003 \u9a71\u9010\u8282\u70b9 cka003 \u3002 kubectl drain cka003 --ignore-daemonsets --delete-emptydir-data --force \u8f93\u51fa\u7ed3\u679c\uff1a node/cka003 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-tr22l, kube-system/kube-proxy-g76kg evicting pod dev/nfs-client-provisioner-86d7fb78b6-xk8nw evicting pod cka/cka-demo-64f88f7f46-dkxmk pod/nfs-client-provisioner-86d7fb78b6-xk8nw evicted pod/cka-demo-64f88f7f46-dkxmk evicted node/cka003 drained \u518d\u6b21\u67e5\u770bpod\u7684\u72b6\u6001\u3002 kubectl get pod -o wide \u5148\u524d\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u4e0a\u7684pod\u73b0\u5728\u6b63\u8fd0\u884c\u5728\u8282\u70b9 cka002 \u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-k8xnl 1/1 Running 0 2m20s 10.244.112.4 cka002 \u5907\u6ce8\uff1a cordon \u547d\u4ee4\u5df2\u7ecf\u5305\u542b\u5728 drain \u547d\u4ee4\u4e2d\uff0c\u4e0d\u9700\u8981\u5728\u6267\u884c drain \u4e4b\u524d\u5355\u72ec\u6267\u884c cordon \u6765\u7981\u6b62node\u7684\u8c03\u5ea6\u3002","title":"Troubleshooting"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#cka25troubleshooting","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb025:Troubleshooting"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_1","text":"\u6f14\u793a\u573a\u666f\uff1a \u63cf\u8ff0pod\u4ee5\u83b7\u53d6\u4e8b\u4ef6\u4fe1\u606f\u3002 \u6f14\u793a\uff1a \u547d\u4ee4\u7528\u6cd5\uff1a kubectl describe --namespace = \u67e5\u8be2pod\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 \u521b\u5efa\u4e00\u4e2aTomcat\u7684pod\u3002 kubectl run tomcat --image = tomcat \u67e5\u8be2pod\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl describe pod/tomcat \u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 55s default-scheduler Successfully assigned dev/tomcat to cka002 Normal Pulling 54s kubelet Pulling image \"tomcat\" Normal Pulled 21s kubelet Successfully pulled image \"tomcat\" in 33.134162692s Normal Created 19s kubelet Created container tomcat Normal Started 19s kubelet Started container tomcat \u67e5\u8be2namespace\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl get events -n \u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u9ed8\u8ba4namespace\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 LAST SEEN TYPE REASON OBJECT MESSAGE 70s Warning FailedGetScale horizontalpodautoscaler/nginx deployments/scale.apps \"podinfo\" not found 2m16s Normal Scheduled pod/tomcat Successfully assigned dev/tomcat to cka002 2m15s Normal Pulling pod/tomcat Pulling image \"tomcat\" 102s Normal Pulled pod/tomcat Successfully pulled image \"tomcat\" in 33.134162692s 100s Normal Created pod/tomcat Created container tomcat 100s Normal Started pod/tomcat Started container tomcat \u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u6240\u6709\u7684namespace\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl get events -A","title":"\u4e8b\u4ef6"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_2","text":"\u6f14\u793a\u573a\u666f\uff1a \u67e5\u8be2pod\u7684\u65e5\u5fd7 \u547d\u4ee4\u7528\u6cd5\uff1a kubectl logs -n \u9009\u9879\uff1a --tail : \u663e\u793a\u8f93\u51fa\u7684\u6700\u8fd1 \u884c\u3002 -f \uff1a\u5b9e\u65f6\u6d41\u5f0f\u663e\u793a\u8f93\u51fa\u3002 \u663e\u793a\u8f93\u51fa\u7684\u6700\u8fd1100\u884c\u8f93\u51fa\u3002 kubectl logs -f tomcat --tail 100 \u5982\u679c\u662f\u4e00\u4e2a\u591a\u5bb9\u5668pod\uff0c\u5219\u4f7f\u7528\u9009\u9879 -c \u6765\u6307\u5b9a\u67d0\u4e2a\u7279\u5b9a\u7684\u5bb9\u5668\u3002 kubectl logs -f tomcat --tail 100 -c tomcat","title":"\u65e5\u5fd7"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_3","text":"","title":"\u8282\u70b9\u53ef\u7528\u6027"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_4","text":"\u6f14\u793a\u573a\u666f\uff1a \u67e5\u770b\u8282\u70b9\u53ef\u7528\u6027 \u6f14\u793a\uff1a \u65b9\u5f0f1\uff1a kubectl describe node | grep -i taint \u624b\u5de5\u65b9\u5f0f\u68c0\u67e5\u65e5\u5fd7\uff0c\u4e0b\u9762\u7684\u4f8b\u5b50\u8bf4\u660e2\u4e2a\u8282\u70b9\u5904\u4e8e\u4e0d\u53ef\u7528\u72b6\u6001\u3002 Taints : node-role.kubernetes.io/control-plane:NoSchedule Taints : Taints : \u65b9\u5f0f2\uff1a kubectl describe node | grep -i taint | grep -vc NoSchedule \u8fd9\u91cc\u6211\u4eec\u4f1a\u5f97\u5230\u76f8\u540c\u7684\u7ed3\u679c\uff0c2\u4e2a\u8282\u70b9\u5904\u4e8e\u4e0d\u53ef\u7528\u72b6\u6001\u3002\u8fd9\u91cc\u7684 -v \u8868\u793a\u6392\u9664\uff0c -c \u8868\u793a\u8ba1\u6570\u3002","title":"\u67e5\u770b\u53ef\u7528\u8282\u70b9"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_5","text":"\u6f14\u793a\u573a\u666f\uff1a \u5f53\u6211\u4eec\u5728Worker\u8282\u70b9 cka002 \u4e0a\u505c\u6b62 kubelet \u670d\u52a1\u65f6\uff0c \u6bcf\u4e2a\u8282\u70b9\u7684\u72b6\u6001\u662f\u4ec0\u4e48\uff1f \u901a\u8fc7 nerdctl \u547d\u4ee4\u66f4\u6539\u4e86\u54ea\u4e9b\u5bb9\u5668\uff1f \u901a\u8fc7\u547d\u4ee4 kubectl get pod -owide -A \u67e5\u770b\u7684Pod\u72b6\u6001\u662f\u4ec0\u4e48\uff1f \u6f14\u793a\uff1a \u5728 cka002 \u8282\u70b9\u4e0a\u6267\u884c\u547d\u4ee4 systemctl stop kubelet.service \u3002 \u5728 cka001 \u6216 cka003 \u4e0a\u6267\u884c\u547d\u4ee4 kubectl get node \uff0c\u53ef\u4ee5\u770b\u5230 cka002 \u7684\u72b6\u6001\u4ece Ready \u53d8\u4e3a NotReady \u3002 \u5728 cka002 \u4e0a\u6267\u884c\u547d\u4ee4 nerdctl -n k8s.io container ls \uff0c\u53ef\u4ee5\u770b\u5230\u6240\u6709\u5bb9\u5668\u90fd\u4ecd\u5728\u8fd0\u884c\uff0c\u5305\u62ecPod my-first-pod \u3002 \u5728 cka002 \u4e0a\u6267\u884c\u547d\u4ee4 systemctl start kubelet.service \u3002 \u7ed3\u8bba\uff1a \u8282\u70b9\u72b6\u6001\u7531 Ready \u53d8\u4e3a NotReady \u3002 \u5bf9\u4e8e\u90a3\u4e9b\u7c7b\u4f3c calico \u3001 kube-proxy \u8fd9\u6837\u7684 DaemonSet Pod\uff0c\u5b83\u4eec\u4e13\u95e8\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u3002\u5728 kubelet \u505c\u6b62\u540e\u5b83\u4eec\u4e0d\u4f1a\u88ab\u7ec8\u6b62\u3002 Pod my-first-pod \u7684\u72b6\u6001\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u4ecd\u7136\u663e\u793a\u4e3a Terminating \uff0c\u56e0\u4e3a\u72b6\u6001\u65e0\u6cd5\u901a\u8fc7 apiserver \u4ece cka002 \u540c\u6b65\u5230\u5176\u4ed6\u8282\u70b9\uff0c\u56e0\u4e3a kubelet \u5df2\u505c\u6b62\u3002 Pod\u7684\u72b6\u6001\u7531\u63a7\u5236\u5668\u6807\u8bb0\u5e76\u7531 kubelet \u56de\u6536\u3002 \u5f53\u6211\u4eec\u5728 cka003 \u4e0a\u542f\u52a8 kubelet \u670d\u52a1\u65f6\uff0cPod my-first-pod \u5c06\u5b8c\u5168\u5728 cka002 \u4e0a\u88ab\u7ec8\u6b62\u3002 \u6b64\u5916\uff0c\u8ba9\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u526f\u672c\u6570\u4e3a3\u7684Deployment\u3002\u5176\u4e2d\u4e24\u4e2a\u526f\u672c\u8fd0\u884c\u5728 cka003 \u4e0a\uff0c\u53e6\u4e00\u4e2a\u526f\u672c\u8fd0\u884c\u5728 cka002 \u4e0a\u3002 kubectl get pod -o wide -w \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-9d745469b-2xdk4 1/1 Running 0 2m8s 10.244.2.3 cka003 nginx-deployment-9d745469b-4gvmr 1/1 Running 0 2m8s 10.244.2.4 cka003 nginx-deployment-9d745469b-5j927 1/1 Running 0 2m8s 10.244.1.3 cka002 \u5728\u6211\u4eec\u505c\u6b62 cka003 \u4e0a\u7684 kubelet \u670d\u52a1\u540e\uff0c\u539f\u5148\u5728 cka003 \u4e0a\u8fd0\u884c\u7684\u4e24\u4e2a\u526f\u672c\u4f1a\u88ab\u7ec8\u6b62\uff0c\u7136\u540e\u4f1a\u81ea\u52a8\u5728 cka002 \u4e0a\u521b\u5efa\u4e24\u4e2a\u65b0\u7684\u526f\u672c\u5e76\u8fd0\u884c\u3002","title":"\u67e5\u770b\u4e0d\u53ef\u7528\u8282\u70b9"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_6","text":"\u6f14\u793a\u573a\u666f\uff1a \u67e5\u8be2pod\u7684\u76d1\u63a7\u6307\u6807 \u6f14\u793a\uff1a \u67e5\u8be2\u8282\u70b9\u7684\u5065\u5eb7\u4fe1\u606f\u3002 kubectl top node \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 147m 7% 1940Mi 50% cka002 62m 3% 2151Mi 56% cka003 63m 3% 1825Mi 47% \u67e5\u8be2pod\u7684\u76d1\u63a7\u6307\u6807\u3002 kubectl top pod \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) MEMORY(bytes) busybox-with-secret 0m 0Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi tomcat 1m 58Mi \u901a\u8fc7\u9009\u9879 --sort-by \uff0c\u5bf9\u8f93\u51fa\u7ed3\u679c\u6309\u7167CPU\u6216\u8005\u5185\u5b58\u7528\u91cf\u8fdb\u884c\u6392\u5e8f\u3002 kubectl top pod --sort-by = cpu kubectl top pod --sort-by = memory \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) MEMORY(bytes) nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi tomcat 1m 58Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi busybox-with-secret 0m 0Mi","title":"\u76d1\u63a7\u6307\u6807"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_7","text":"","title":"\u8282\u70b9\u9a71\u9010"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_8","text":"\u6f14\u793a\u573a\u666f\uff1a \u8282\u70b9\u8c03\u5ea6 \u6f14\u793a\uff1a \u7981\u6b62\u4e00\u4e2a\u8282\u70b9\u7684\u8c03\u5ea6\u3002 kubectl cordon \u4e3e\u4f8b\uff1a kubectl cordon cka003 \u8f93\u51fa\u7ed3\u679c\uff0c\u8282\u70b9\u72b6\u6001\u5982\u4e0b\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready,SchedulingDisabled 18d v1.24.0 \u6fc0\u6d3b\u4e00\u4e2a\u8282\u70b9\u7684\u8c03\u5ea6\u3002 kubectl uncordon \u4e3e\u4f8b\uff1a kubectl uncordon cka003 \u8f93\u51fa\u7ed3\u679c\uff0c\u8282\u70b9\u72b6\u6001\u5982\u4e0b\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready 18d v1.24.0","title":"\u8282\u70b9\u7684\u53ef\u8c03\u5ea6\u6027"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_9","text":"\u6f14\u793a\u5185\u5bb9\uff1a \u9a71\u9010\u8282\u70b9 cka003 \u6f14\u793a\uff1a \u83b7\u53d6\u5f53\u524d\u8fd0\u884cpod\u7684\u5217\u8868\u3002 kubectl get pod -o wide \u5176\u4e2d\u6709\u4e00\u4e2apod\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-xk8nw 1/1 Running 0 22h 10.244.102.3 cka003 \u9a71\u9010\u8282\u70b9 cka003 \u3002 kubectl drain cka003 --ignore-daemonsets --delete-emptydir-data --force \u8f93\u51fa\u7ed3\u679c\uff1a node/cka003 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-tr22l, kube-system/kube-proxy-g76kg evicting pod dev/nfs-client-provisioner-86d7fb78b6-xk8nw evicting pod cka/cka-demo-64f88f7f46-dkxmk pod/nfs-client-provisioner-86d7fb78b6-xk8nw evicted pod/cka-demo-64f88f7f46-dkxmk evicted node/cka003 drained \u518d\u6b21\u67e5\u770bpod\u7684\u72b6\u6001\u3002 kubectl get pod -o wide \u5148\u524d\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u4e0a\u7684pod\u73b0\u5728\u6b63\u8fd0\u884c\u5728\u8282\u70b9 cka002 \u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-k8xnl 1/1 Running 0 2m20s 10.244.112.4 cka002 \u5907\u6ce8\uff1a cordon \u547d\u4ee4\u5df2\u7ecf\u5305\u542b\u5728 drain \u547d\u4ee4\u4e2d\uff0c\u4e0d\u9700\u8981\u5728\u6267\u884c drain \u4e4b\u524d\u5355\u72ec\u6267\u884c cordon \u6765\u7981\u6b62node\u7684\u8c03\u5ea6\u3002","title":"\u9a71\u9010\u8282\u70b9"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/","text":"CKA\u81ea\u5b66\u7b14\u8bb03:\u963f\u91cc\u4e91ECS\u5b89\u88c5Kubernetes \u00b6 \u6458\u8981 \u00b6 \u5728\u963f\u91cc\u4e91ECS\u88c5\u4e09\u53f0Ubuntu\u865a\u62df\u673a\u3002\u5728Ubuntu\u865a\u62df\u673a\u4e2d\u5b89\u88c5\u57fa\u4e8eContainerd\u7684Kubernetes\u7cfb\u7edf\uff0c\u5e76\u5206\u522b\u914d\u7f6e\u4e00\u4e2a\u4e3b\u8282\u70b9Master\u548c\u4e24\u4e2a\u5de5\u4f5c\u8282\u70b9Worker\uff0c\u3002 \u51c6\u5907\u5de5\u4f5c \u00b6 \u6ce8\u518c\u963f\u91cc\u4e91\u8d26\u53f7\uff1a Alibaba Cloud home console \u3002\u6ce8\u610f\u4fdd\u7559\u8bbf\u95ee\u5bc6\u94a5key\u6587\u4ef6\uff0c\u53ea\u80fd\u5bfc\u51fa\u4e00\u6b21\uff0c\u5f53\u524d\u7ec3\u4e60\u4e2dkey\u6587\u4ef6\u662f aliyun-root \u3002 \u53c2\u8003\u4e0b\u9762\u914d\u7f6e\u6ce8\u518c\u7533\u8bf7\u4e09\u4e2aECS\uff08Elastic Computer Service\uff09\u670d\u52a1\u5b9e\u4f8b\uff1a \u4e3b\u673a\uff1a2vCPU+4GiB \u64cd\u4f5c\u7cfb\u7edf\uff1aUbuntu 20.04 x86_64 \u5b9e\u4f8b\u7c7b\u578b\uff1aecs.sn1.medium \u5b9e\u4f8b\u540d\u79f0\uff1acka001, cka002, cka003 \u7f51\u7edc\u914d\u7f6e\uff1aboth public IPs and private IPs \u6700\u5927\u7f51\u7edc\u5e26\u5bbd\uff1a100Mbps (Peak Value) \u4e91\u76d8\uff1a40GiB \u652f\u4ed8\u65b9\u5f0f\uff1a\u62a2\u5360\u5f0f\u5b9e\u4f8b \u5728\u672c\u5730\u6253\u5f00\u7ec8\u7aef\u7a97\u53e3\uff0c\u901a\u8fc7\u5bc6\u94a5\u6587\u4ef6 aliyun-root \u8bbf\u95ee\u8fdc\u7a0bECS\u8282\u70b9 cka001 \u3002 ssh -i aliyun-root root@cka001 \u521b\u5efa\u4e00\u4e2a\u666e\u901a\u7528\u6237\uff0c\u7528\u6765\u5b89\u88c5Kubernetes\uff0c\u5f53\u524d\u7ec3\u4e60\u4e2d\u521b\u5efa\u7528\u6237 vagrant \uff0c\u4e14\u4fee\u6539\u8be5\u7528\u6237\u7684\u4e3b\u8981\u7ec4\u4e3a sudo \u6b21\u8981\u7ec4\u5305\u542b root \u3002 adduser vagrant usermod -g sudo vagrant usermod -a -G root vagrant \u65b0\u5f00\u4e00\u4e2a\u672c\u5730\u7ec8\u7aef\u7a97\u53e3\uff0c\u4e3a\u7528\u6237 vagrant \u521b\u5efa\u5bc6\u94a5key\u3002 # Windows ssh-keygen.exe # Linux ssh-keygen \u4e0a\u9762\u7684\u547d\u4ee4\u4f1a\u751f\u62102\u4e2a\u6587\u4ef6\uff0c\u5f53\u524d\u7ec3\u4e60\u4e2d\u8fd92\u4e2a\u6587\u4ef6\u662f aliyun-vagrant and aliyun-vagrant.pub \u901a\u8fc7 sftp \u547d\u4ee4\u5c06\u516c\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u4e0a\u4f20\u5230\u8fdc\u7a0b\u8282\u70b9 cka001 \u3002 sftp -i aliyun-root root@cka001 put aliyun-vagrant.pub \u65b0\u5f00\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\uff0c\u7528 root \u7684\u5bc6\u94a5\u767b\u5f55 cka001 \u8282\u70b9\u3002 \u5c06\u4e0a\u4e00\u6b65\u4e0a\u4f20\u7684\u5bc6\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u4ece /root \u76ee\u5f55\u62f7\u8d1d\u5230 /home/vagrant/.ssh/ \u3002 \u5c06\u516c\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u91cd\u547d\u540d\u4e3a authorized_keys \u3002 \u66f4\u6539\u6587\u4ef6 authorized_keys \u7684\u6240\u6709\u8005owner\u4e3a vagrant . \u66f4\u6539\u6587\u4ef6 authorized_keys \u7684\u4e3b\u8981\u7ec4\u4e3a sudo \u3002 mkdir /home/vagrant/.ssh/ mv aliyun-james.pub /home/vagrant/.ssh/authorized_keys chown vagrant.sudo /home/vagrant/.ssh/authorized_keys chmod 600 /home/vagrant/.ssh/authorized_keys \u68c0\u67e5\u6587\u4ef6 /etc/ssh/sshd_config \uff0c\u786e\u5b9a\u5bc6\u7801\u767b\u5f55\u9a8c\u8bc1\u53c2\u6570 asswordAuthentication \u8bbe\u5b9a\u4e3a no \uff0c\u5373\u53ea\u80fd\u901a\u8fc7\u8bc1\u4e66\u8fdc\u7a0b\u767b\u5f55\u3002 cat /etc/ssh/sshd_config \u65b0\u5f00\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\uff0c\u4f7f\u7528\u7528\u6237vagrant\u767b\u5f55\u8fdc\u7a0b\u8282\u70b9 cka001 \uff0c\u9a8c\u8bc1\u7528\u6237 vagrant \u80fd\u901a\u8fc7\u524d\u9762\u521b\u5efa\u7684\u8bc1\u4e66\u767b\u5f55\u8282\u70b9 cka001 \u3002 ssh -i aliyun-vagrant vagrant@cka001 \u91cd\u590d\u4e0a\u8ff0\u6b65\u9aa4\uff0c\u901a\u8fc7 sftp \u547d\u4ee4\u5c06\u516c\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u5206\u522b\u4e0a\u4f20\u5230\u8fdc\u7a0b\u8282\u70b9 cka002 \u548c cka003 \uff0c\u4e14\u5b8c\u6210\u540c\u6837\u7684\u914d\u7f6e\uff0c\u4f7f\u7528\u6237 vagrant \u4e5f\u80fd\u901a\u8fc7\u5bc6\u94a5\u6587\u4ef6\u767b\u5f55\u8fdc\u7a0b\u8282\u70b9 cka002 \u548c cka003 \u3002 \u81f3\u6b64\uff0c\u7528\u6237 vagrant \u53ef\u4ee5\u901a\u8fc7\u5bc6\u94a5\u6587\u4ef6 aliyun-vagrant \u4ece\u672c\u5730\u7ec8\u7aef\u7a97\u53e3\u767b\u5f55\u8fdc\u7a0b\u8282\u70b9 cka001 , cka002 \u548c cka003 \u3002 \u4e0b\u9762\u6240\u6709\u6b65\u9aa4\u90fd\u662f\u901a\u8fc7\u7528\u6237 vagrant \u5b8c\u6210\u3002 \u521d\u59cb\u5316ECS\u8282\u70b9 \u00b6 \u914d\u7f6e\u6587\u4ef6/etc/hosts \u00b6 \u66f4\u65b0\u6240\u6709ECS\u8282\u70b9\u7684\u6587\u4ef6/etc/hosts\uff0c\u6dfb\u52a0\u5176\u4ed6\u8282\u70b9\u7684\u79c1\u6709IP\uff08private IP\uff09\u3002 vi /etc/hosts \u7981\u7528firewall \u00b6 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u7981\u7528\u9632\u706b\u5899\u3002 sudo ufw disable \u68c0\u67e5\u9632\u706b\u5899\u72b6\u6001\u3002 sudo ufw status verbose \u5173\u95edswap \u00b6 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5173\u95edswap\u3002 sudo swapoff -a \u8bbe\u7f6e\u65f6\u533a\u548c\u5730\u57df \u00b6 \u5728\u6240\u6709\u8282\u70b9\u8bbe\u5b9a\u65f6\u533a\u548c\u5730\u57df\u3002\u8fd9\u4e00\u5e03\u5728\u521d\u59cb\u5316ECS\u65f6\u5019\u5df2\u7ecf\u5b8c\u6210\u3002\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u8fdb\u884c\u8bbe\u5b9a\u3002 ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile \u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u68c0\u67e5\u65f6\u533a\u548c\u5730\u57df\u7684\u8bbe\u7f6e\u3002 ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 5 14:51 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai \u5185\u6838\u8bbe\u7f6e \u00b6 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u4ee5\u914d\u7f6e\u5185\u6838\u3002 \u4f7f\u7528\u6a21\u5757overlay\uff1a \u521b\u5efaContainerd\u670d\u52a1\u914d\u7f6e\u6587\u4ef6 /etc/modules-load.d/containerd.conf \uff0c\u5982\u679c\u5df2\u5b58\u5728\u5219\u8df3\u8fc7\u8fd9\u4e00\u6b65\u3002\u914d\u7f6e\u8fd9\u4e2a\u6587\u4ef6\u7684\u76ee\u7684\u662f\u4e3a\u4e86\u52a0\u8f7d\u6a21\u5757 overlay \u548c br_netfilter \u5230\u5185\u6838\u4e2d\u3002 \u670d\u52a1Containerd\u4f9d\u8d56\u6a21\u5757 overlay \u5b9e\u73b0 overlay-filesystem \u6587\u4ef6\u7cfb\u7edf\u529f\u80fd\u3002 Linux\u4e2d\u7684overlay\u6a21\u5757\u63d0\u4f9b\u4e86\u521b\u5efa\u4e24\u4e2a\u76ee\u5f55\u7684\u5408\u5e76\u89c6\u56fe\u7684\u80fd\u529b\uff0c\u8fd9\u4e24\u4e2a\u76ee\u5f55\u79f0\u4e3a\u5c42\u3002\u5b83\u7ecf\u5e38\u88ab\u7528\u4e8e\u5b9e\u73b0\u8054\u5408\u6302\u8f7d\uff0c\u8fd9\u662f\u4e00\u79cd\u5c06\u4e24\u4e2a\u6216\u66f4\u591a\u76ee\u5f55\u4e00\u8d77\u6302\u8f7d\u7684\u65b9\u5f0f\uff0c\u5c31\u50cf\u5b83\u4eec\u662f\u4e00\u4e2a\u76ee\u5f55\u4e00\u6837\uff08union-filesystems\uff09\u3002 overlay\u6a21\u5757\u5728\u5bb9\u5668\u6280\u672f\u4e2d\u88ab\u5e7f\u6cdb\u4f7f\u7528\uff0c\u6bd4\u5982Docker\uff0c\u56e0\u4e3a\u5b83\u5141\u8bb8\u591a\u4e2a\u5bb9\u5668\u5171\u4eab\u57fa\u7840\u955c\u50cf\uff0c\u540c\u65f6\u4fdd\u6301\u5b83\u4eec\u81ea\u5df1\u7684\u6587\u4ef6\u7cfb\u7edf\u3002 \u8981\u4f7f\u7528overlay\u6a21\u5757\uff0c\u9700\u8981\u4e24\u4e2a\u76ee\u5f55\uff1a\u8f83\u4f4e\u7684\u76ee\u5f55\uff08lower directory\uff09\u548c\u8f83\u9ad8\u7684\u76ee\u5f55\uff08upper directory\uff09\u3002\u8f83\u4f4e\u7684\u76ee\u5f55\u901a\u5e38\u662f\u53ea\u8bfb\u7684\uff0c\u5305\u542b\u539f\u59cb\u6587\u4ef6\uff0c\u800c\u8f83\u9ad8\u7684\u76ee\u5f55\u662f\u53ef\u8bfb\u5199\u7684\uff0c\u5305\u542b\u5bf9\u6587\u4ef6\u7684\u66f4\u6539\u3002\u5f53\u8bf7\u6c42\u6587\u4ef6\u65f6\uff0coverlay\u6a21\u5757\u9996\u5148\u67e5\u627e\u4e0a\u5c42\u76ee\u5f55\uff0c\u5982\u679c\u672a\u627e\u5230\uff0c\u5219\u67e5\u627e\u4e0b\u5c42\u76ee\u5f55\u3002 \u6bd4\u5982\uff1a \u521b\u5efa\u4e24\u4e2a\u76ee\u5f55\uff0c\u4e00\u4e2a\u7528\u4e8e\u8f83\u4f4e\u7684\u76ee\u5f55\uff0c\u4e00\u4e2a\u7528\u4e8e\u8f83\u9ad8\u7684\u76ee\u5f55\u3002\u7136\u540e\u4f7f\u7528overlay\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u5c06\u5b83\u4eec\u6302\u8f7d\u8d77\u6765\uff1a sudo mkdir /lower sudo mkdir /upper sudo mount -t overlay overlay -o lowerdir = /lower,upperdir = /upper /merged \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c\u4e24\u4e2a\u76ee\u5f55\u7684\u5408\u5e76\u89c6\u56fe\u88ab\u521b\u5efa\u5728 /merged \u76ee\u5f55\u4e2d\u3002\u5728 /merged \u76ee\u5f55\u4e2d\u5bf9\u6587\u4ef6\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u5b58\u50a8\u5728\u4e0a\u5c42\u76ee\u5f55\u4e2d\uff0c\u800c\u539f\u59cb\u6587\u4ef6\u4ecd\u7136\u5728\u4e0b\u5c42\u76ee\u5f55\u4e2d\u3002 \u4f7f\u7528\u6a21\u5757br_netfilter\uff1a br_netfilter \u662fLinux\u5185\u6838\u4e2d\u7684\u4e00\u4e2a\u6a21\u5757\uff0c\u5b83\u63d0\u4f9b\u4e86\u4e00\u79cd\u673a\u5236\u6765\u8fc7\u6ee4\u7f51\u6865\u7684\u7f51\u7edc\u6d41\u91cf\u3002\u8be5\u6a21\u5757\u5141\u8bb8\u7ba1\u7406\u5458\u914d\u7f6e\u89c4\u5219\uff0c\u4ee5\u5141\u8bb8\u6216\u62d2\u7edd\u7279\u5b9a\u7684\u7f51\u7edc\u6d41\u91cf\u901a\u8fc7\u7f51\u6865\u3002 \u7f51\u6865\u662f\u4e00\u79cd\u7f51\u7edc\u8bbe\u5907\uff0c\u5b83\u53ef\u4ee5\u8fde\u63a5\u591a\u4e2a\u7f51\u7edc\u6bb5\uff0c\u5e76\u8f6c\u53d1\u6d41\u91cf\u4ee5\u4f7f\u4e0d\u540c\u7684\u7f51\u7edc\u6bb5\u4e4b\u95f4\u901a\u4fe1\u3002 br_netfilter \u6a21\u5757\u53ef\u4ee5\u7528\u6765\u9650\u5236\u6216\u8fc7\u6ee4\u8fd9\u4e9b\u6d41\u91cf\u3002 \u5f53\u542f\u7528\u4e86 br_netfilter \u6a21\u5757\u65f6\uff0c\u5b83\u4f1a\u81ea\u52a8\u542f\u7528\u4e00\u4e2a\u79f0\u4e3a bridge-nf \u7684\u529f\u80fd\uff0c\u8be5\u529f\u80fd\u5c06\u5728\u7f51\u7edc\u6d41\u91cf\u901a\u8fc7\u7f51\u6865\u65f6\u5e94\u7528\u89c4\u5219\u3002\u7ba1\u7406\u5458\u53ef\u4ee5\u4f7f\u7528iptables\u7b49\u5de5\u5177\u6765\u914d\u7f6e\u8fd9\u4e9b\u89c4\u5219\u3002\u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u8bbe\u5b9a\u5141\u8bb8\u4ece\u4e00\u4e2a\u7f51\u7edc\u6bb5\u5230\u53e6\u4e00\u4e2a\u7f51\u7edc\u6bb5\u7684\u6d41\u91cf\uff0c\u6216\u8005\u62d2\u7edd\u6765\u81ea\u7279\u5b9aIP\u5730\u5740\u6216\u7aef\u53e3\u7684\u6d41\u91cf\u3002 \u5728Kubernetes\u4e2d\uff0c br_netfilter \u6a21\u5757\u4e3b\u8981\u7528\u4e8e\u542f\u7528Kubernetes\u670d\u52a1\u7684\u6d41\u91cf\u8f6c\u53d1\u548c\u8d1f\u8f7d\u5747\u8861\u3002\u8fd9\u4e9b\u670d\u52a1\u4f7f\u7528\u4e86Linux\u5185\u6838\u4e2d\u7684iptables\u89c4\u5219\u6765\u7ba1\u7406\u6d41\u91cf\uff0c\u8fd9\u4e9b\u89c4\u5219\u662f\u901a\u8fc7 br_netfilter \u6a21\u5757\u5b9e\u73b0\u7684\u3002 \u5177\u4f53\u6765\u8bf4\uff0c\u5f53\u6211\u4eec\u5728Kubernetes\u96c6\u7fa4\u4e2d\u521b\u5efa\u4e00\u4e2a\u670d\u52a1\u65f6\uff0c\u8be5\u670d\u52a1\u5c06\u5206\u914d\u4e00\u4e2a\u865a\u62dfIP\u5730\u5740\uff0c\u7528\u4e8e\u4ee3\u8868\u670d\u52a1\u3002\u7136\u540e\uff0c\u901a\u8fc7iptables\u89c4\u5219\uff0c\u5c06\u8fd9\u4e2a\u865a\u62dfIP\u5730\u5740\u6620\u5c04\u5230\u4e00\u4e2a\u6216\u591a\u4e2a\u540e\u7aefPod\u7684IP\u5730\u5740\uff0c\u4ee5\u4fbf\u5728\u9700\u8981\u65f6\u5c06\u6d41\u91cf\u8def\u7531\u5230\u8fd9\u4e9bPod\u3002 \u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e2d\uff0c br_netfilter \u6a21\u5757\u8d1f\u8d23\u76d1\u89c6\u670d\u52a1\u7684\u6d41\u91cf\uff0c\u5e76\u6839\u636eiptables\u89c4\u5219\u8fdb\u884c\u8f6c\u53d1\u548c\u8d1f\u8f7d\u5747\u8861\u3002\u8fd9\u5305\u62ec\u8fc7\u6ee4\u6765\u81ea\u4e0d\u53d7\u4fe1\u4efb\u6e90\u7684\u6d41\u91cf\u4ee5\u53ca\u9650\u5236\u670d\u52a1\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u4e3a\u4e86\u542f\u7528Kubernetes\u670d\u52a1\u7684\u6d41\u91cf\u8f6c\u53d1\u548c\u8d1f\u8f7d\u5747\u8861\uff0c br_netfilter \u6a21\u5757\u5fc5\u987b\u5728\u6240\u6709\u8282\u70b9\u4e0a\u542f\u7528\uff0c\u5e76\u4e14\u5fc5\u987b\u914d\u7f6e\u6b63\u786e\u7684iptables\u89c4\u5219\u3002 \u7531\u4e8e br_netfilter \u6a21\u5757\u7684\u4f5c\u7528\u975e\u5e38\u5173\u952e\uff0c\u56e0\u6b64\u5728\u5347\u7ea7\u6216\u66f4\u6539\u7cfb\u7edf\u65f6\u9700\u8981\u7279\u522b\u6ce8\u610f\u5b83\u7684\u914d\u7f6e\u548c\u72b6\u6001\u3002 \u4e0b\u9762\u547d\u4ee4\u5c06\u6a21\u5757 overlay \u548c br_netfilter \u6dfb\u52a0\u5230\u914d\u7f6e\u6587\u4ef6 containerd.conf \u4e2d\u3002 cat < /etc/apt/sources.list << EOF deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multivers deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe # deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse # deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse EOF \u5b89\u88c5Containered\u3002 sudo apt-get update && sudo apt-get install -y containerd \u914d\u7f6eContainerd\u3002\u4fee\u6539\u6587\u4ef6 /etc/containerd/config.toml \u3002 sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml \u4fee\u6539\u53c2\u6570 sandbox_image \u7684\u503c\u4e3a \"registry.aliyuncs.com/google_containers/pause:3.6\" \u3002 \u4fee\u6539\u53c2\u6570 SystemdCgroup \u7684\u503c\u4e3a true \u3002 [plugins] [plugins.\"io.containerd.gc.v1.scheduler\"] [plugins.\"io.containerd.grpc.v1.cri\"] sandbox_image = \"registry.aliyuncs.com/google_containers/pause:3.6\" [plugins.\"io.containerd.grpc.v1.cri\".cni] [plugins.\"io.containerd.grpc.v1.cri\".containerd] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime.options] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc.options] SystemdCgroup = true \u91cd\u542fContainerd\u670d\u52a1\u3002 sudo systemctl restart containerd sudo systemctl status containerd \u5b89\u88c5nerdctl \u00b6 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b89\u88c5nerdctl\u670d\u52a1\u3002 nerdctl \u670d\u52a1\u652f\u6301Contanerd\u6240\u63d0\u4f9b\u7684\u5bb9\u5668\u5316\u7279\u6027\uff0c\u7279\u522b\u662f\u4e00\u4e9bDocker\u4e0d\u5177\u5907\u7684\u65b0\u7279\u6027\u3002 \u4e8c\u8fdb\u5236\u5b89\u88c5\u5305\u53ef\u4ee5\u901a\u8fc7\u8fd9\u4e2a\u94fe\u63a5\u53d6\u5f97: Releases \u00b7 containerd/nerdctl \u00b7 GitHub \u3002 wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-0.22.2-linux-amd64.tar.gz tar -zxvf nerdctl-0.22.2-linux-amd64.tar.gz sudo cp nerdctl /usr/bin/ \u9a8c\u8bc1 nerdctl \u670d\u52a1\u3002 sudo nerdctl --help \u5217\u51fa\u521d\u59cb\u5b89\u88c5Kubernetes\u65f6\u7684\u5bb9\u5668container\u5217\u8868\u3002 nerdctl -n k8s.io ps \u5b89\u88c5kubeadm \u00b6 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b89\u88c5Kubeadm\uff0ckubectl\uff0ckubelet\u3002 \u5b89\u88c5\u548c\u5347\u7ea7Ubuntu\u7cfb\u7edf\u4f9d\u8d56\u5305 apt-transport-https , ca-certificates , curl \u3002 sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl \u5b89\u88c5gpg\u8bc1\u4e66\u3002 curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - \u6dfb\u52a0Kubernetes\u5b89\u88c5\u6e90\u3002 cat << EOF > /etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF \u5b89\u88c5\u548c\u5347\u7ea7Ubuntu\u7cfb\u7edf\u4f9d\u8d56\u5305\u3002 sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables \u68c0\u67e5\u5f53\u524d\u53ef\u7528\u7684 kubeadm \u7248\u672c\u3002 apt policy kubeadm \u5f53\u524d\u5b89\u88c5 1.24.0-00 \u7248\u672c\u7684 kubeadm \uff0c\u540e\u7eed\u4f1a\u5347\u7ea7\u5230 1.24.2 \u7248\u672c\u3002 sudo apt-get -y install kubelet = 1 .24.0-00 kubeadm = 1 .24.0-00 kubectl = 1 .24.0-00 --allow-downgrades \u914d\u7f6e\u4e3b\u8282\u70b9 \u00b6 kubeadm\u521d\u59cb\u5316 \u00b6 \u5728\u627f\u62c5\u4e3b\u8282\u70b9\u7684\u865a\u62df\u673a\u91cc\u914d\u7f6e\u63a7\u5236\u5e73\u9762\uff08Control Plane\uff09\u3002 \u68c0\u67e5 kubeadm \u5f53\u524d\u9ed8\u8ba4\u914d\u7f6e\u53c2\u6570\u3002 kubeadm config print init-defaults \u7c7b\u4f3c\u7ed3\u679c\u5982\u4e0b\u3002\u4fdd\u5b58\u9ed8\u8ba4\u914d\u7f6e\u7684\u7ed3\u679c\uff0c\u540e\u7eed\u4f1a\u4f5c\u4e3a\u53c2\u8003\u3002 apiVersion : kubeadm.k8s.io/v1beta3 bootstrapTokens : - groups : - system:bootstrappers:kubeadm:default-node-token token : abcdef.0123456789abcdef ttl : 24h0m0s usages : - signing - authentication kind : InitConfiguration localAPIEndpoint : advertiseAddress : 1.2.3.4 bindPort : 6443 nodeRegistration : criSocket : unix:///var/run/containerd/containerd.sock imagePullPolicy : IfNotPresent name : node taints : null --- apiServer : timeoutForControlPlane : 4m0s apiVersion : kubeadm.k8s.io/v1beta3 certificatesDir : /etc/kubernetes/pki clusterName : kubernetes controllerManager : {} dns : {} etcd : local : dataDir : /var/lib/etcd imageRepository : k8s.gcr.io kind : ClusterConfiguration kubernetesVersion : 1.24.0 networking : dnsDomain : cluster.local serviceSubnet : 10.96.0.0/12 scheduler : {} \u6a21\u62df\u5b89\u88c5\u548c\u6b63\u5f0f\u5b89\u88c5\u3002 \u901a\u8fc7\u547d\u4ee4 kubeadm init \u8fdb\u884c\u4e3b\u8282\u70b9\u7684\u521d\u59cb\u5316\uff0c\u4e0b\u9762\u662f\u8fd9\u4e2a\u547d\u4ee4\u4e3b\u8981\u53c2\u6570\u7684\u8bf4\u660e\uff0c\u7279\u522b\u662f\u7f51\u7edc\u53c2\u6570\u7684\u4e09\u4e2a\u9009\u62e9\u3002 --pod-network-cidr : \u6307\u5b9apod\u4f7f\u7528\u7684IP\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u6307\u5b9a\u4e86\u8be5\u53c2\u6570\uff0c\u5219Control Plane\u4f1a\u81ea\u52a8\u8bb2\u6307\u5b9a\u7684CIDR\u5206\u914d\u7ed9\u6bcf\u4e2a\u8282\u70b9\u3002 IP\u5730\u5740\u6bb5 10.244.0.0/16 \u662fFlannel\u7f51\u7edc\u7ec4\u4ef6\u9ed8\u8ba4\u7684\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u9700\u8981\u4fee\u6539Flannel\u7684IP\u5730\u5740\u6bb5\uff0c\u9700\u8981\u5728\u8fd9\u91cc\u6307\u5b9a\uff0c\u4e14\u5728\u90e8\u7f72Flannel\u65f6\u4e5f\u8981\u4fdd\u6301\u4e00\u81f4\u7684IP\u6bb5\u3002 --apiserver-bind-port : API\u670d\u52a1\uff08API Server\uff09\u7684\u7aef\u53e3\uff0c\u9ed8\u8ba4\u65f66443\u3002 --service-cidr : \u6307\u5b9a\u670d\u52a1\uff08service\uff09\u7684IP\u5730\u5740\u6bb5\uff0c\u9ed8\u8ba4\u662f 10.96.0.0/12 \u3002 \u63d0\u793a\uff1a \u670d\u52a1VIPs\uff08service VIPs\uff09\uff0c\u4e5f\u79f0\u4f5c\u96c6\u7fa4IP\uff08Cluster IP\uff09\uff0c\u901a\u8fc7\u53c2\u6570 --service-cidr \u6307\u5b9a\u3002 podCIDR\uff0c\u4e5f\u79f0\u4e3aendpoint IP\uff0c\u901a\u8fc7\u53c2\u6570 --pod-network-cidr \u6307\u5b9a\u3002 \u67094\u79cd\u5178\u578b\u7684\u7f51\u7edc\u95ee\u9898\uff1a \u9ad8\u5ea6\u8026\u5408\u7684\u5bb9\u5668\u4e0e\u5bb9\u5668\u4e4b\u95f4\u7684\u901a\u4fe1\uff1a\u8fd9\u53ef\u4ee5\u901a\u8fc7Pod\uff08podCIDR\uff09\u548c\u672c\u5730\u4e3b\u673a\u901a\u4fe1\u6765\u89e3\u51b3\u3002 Pod\u5bf9Pod\u901a\u4fe1\uff08Pod-to-Pod\uff09\uff1a \u4e5f\u88ab\u79f0\u4e3a\u5bb9\u5668\u5bf9\u5bb9\u5668\u901a\u4fe1\uff08container-to-container\uff09\u3002 \u5728Flannel\u7f51\u7edc\u63d2\u4ef6\u4e2d\u7684\u793a\u4f8b\u6d41\u7a0b\u662f\uff1aPod \u2192 veth\u5bf9 \u2192 cni0 \u2192 flannel.1 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 flannel.1 \u2192 cni0 \u2192 veth\u5bf9 \u2192 Pod\u3002 Pod\u5bf9Service\u901a\u4fe1\uff08Pod-to-Service\uff09\uff1a \u6d41\u7a0b: Pod \u2192 \u5185\u6838 \u2192 Service iptables \u2192 Service \u2192 Pod iptables \u2192 Pod\u3002 \u5916\u90e8\u5bf9Service\u901a\u4fe1\uff08External-to-Service\uff09\uff1a \u8d1f\u8f7d\u5747\u8861\u5668: SLB \u2192 NodePort \u2192 Service \u2192 Pod\u3002 kube-proxy \u662f\u5bf9iptables\u8d1f\u8d23\uff0c\u4e0d\u662f\u7f51\u7edc\u6d41\u91cf\uff08traffic\uff09\u3002 kube-proxy \u662fKubernetes\u96c6\u7fa4\u4e2d\u7684\u4e00\u4e2a\u7ec4\u4ef6\uff0c\u8d1f\u8d23\u4e3aService\u63d0\u4f9b\u4ee3\u7406\u670d\u52a1\uff0c\u540c\u65f6\u4e5f\u662fKubernetes\u7f51\u7edc\u6a21\u578b\u4e2d\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\u4e4b\u4e00\u3002 kube-proxy \u4f1a\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u542f\u52a8\u4e00\u4e2a\u4ee3\u7406\u8fdb\u7a0b\uff0c\u901a\u8fc7\u76d1\u542cKubernetes API Server\u7684Service\u548cEndpoint\u7684\u53d8\u5316\u6765\u7ef4\u62a4\u4e00\u4e2a\u672c\u5730\u7684Service\u548cEndpoint\u7684\u7f13\u5b58\u3002\u5f53\u6709\u8bf7\u6c42\u5230\u8fbe\u67d0\u4e2aService\u65f6\uff0c kube-proxy \u4f1a\u6839\u636e\u8be5Service\u7684\u7c7b\u578b\uff08ClusterIP\u3001NodePort\u3001LoadBalancer\u3001ExternalName\uff09\u548c\u7aef\u53e3\u53f7\uff0c\u751f\u6210\u76f8\u5e94\u7684iptables\u89c4\u5219\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u7ed9Service\u6240\u4ee3\u7406\u7684\u540e\u7aefPod\u3002 iptables\u662fLinux\u7cfb\u7edf\u4e2d\u7684\u4e00\u4e2a\u91cd\u8981\u7f51\u7edc\u5de5\u5177\uff0c\u53ef\u4ee5\u8bbe\u7f6eIP\u5305\u7684\u8fc7\u6ee4\u3001\u8f6c\u53d1\u548c\u4fee\u6539\u89c4\u5219\uff0c\u53ef\u4ee5\u5b9e\u73b0\u7f51\u7edc\u5c42\u7684\u9632\u706b\u5899\u3001NAT\u7b49\u529f\u80fd\u3002\u5728Kubernetes\u96c6\u7fa4\u4e2d\uff0c kube-proxy \u901a\u8fc7\u751f\u6210\u548c\u66f4\u65b0iptables\u89c4\u5219\uff0c\u6765\u5b9e\u73b0Service\u548cEndpoint\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u5177\u4f53\u6765\u8bf4\uff0ckube-proxy\u4f1a\u4e3a\u6bcf\u4e2aService\u521b\u5efa\u4e09\u6761iptables\u89c4\u5219\u94fe\uff08nat\u8868\u4e2d\u7684KUBE-SERVICES\u548cKUBE-NODEPORTS\u94fe\uff0c\u4ee5\u53cafilter\u8868\u4e2d\u7684KUBE-SVC-XXXXX\u94fe\uff09\uff0c\u901a\u8fc7\u8fd9\u4e9b\u89c4\u5219\u94fe\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u76f8\u5e94\u7684Pod\u6216\u8005Service\u4e0a\u3002 \u56e0\u6b64\uff0c kube-proxy \u548ciptables\u662f\u7d27\u5bc6\u76f8\u5173\u7684\u4e24\u4e2a\u7ec4\u4ef6\uff0c\u901a\u8fc7iptables\u89c4\u5219\u6765\u5b9e\u73b0Service\u548cPod\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u8fd9\u79cd\u5b9e\u73b0\u65b9\u5f0f\u5177\u6709\u53ef\u6269\u5c55\u6027\u548c\u9ad8\u53ef\u7528\u6027\uff0c\u540c\u65f6\u4e5f\u63d0\u4f9b\u4e86\u4e00\u79cd\u7075\u6d3b\u7684\u7f51\u7edc\u6a21\u578b\uff0c\u53ef\u4ee5\u65b9\u4fbf\u5730\u5b9e\u73b0\u670d\u52a1\u53d1\u73b0\u3001\u8d1f\u8f7d\u5747\u8861\u7b49\u529f\u80fd\u3002 sudo kubeadm init \\ --dry-run \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --kubernetes-version = v1.24.0 kubeconfig\u6587\u4ef6 \u00b6 \u7ed9\u5f53\u524d\u5b89\u88c5\u7528\u6237\u914d\u7f6e kubeconfig \u6587\u4ef6\uff08\u5f53\u524d\u4f8b\u5b50\u662f\u7528\u6237 vagrant \uff09\u3002 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Kubernetes \u63d0\u4f9b\u4e86\u4e00\u4e2a\u547d\u4ee4\u884c\u5de5\u5177 kubectl \uff0c\u7528\u4e8e\u4f7f\u7528 Kubernetes API \u4e0e Kubernetes \u96c6\u7fa4\u7684\u63a7\u5236\u5e73\u9762\u8fdb\u884c\u901a\u4fe1\u3002 kubectl \u63a7\u5236 Kubernetes cluster manager \uff08\u96c6\u7fa4\u7ba1\u7406\u5668\uff09\u3002 \u5bf9\u4e8e\u914d\u7f6e\uff0ckubectl \u5728 $HOME/.kube \u76ee\u5f55\u4e2d\u67e5\u627e\u4e00\u4e2a\u540d\u4e3a config \u7684\u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u662f\u7531 kubeadm init \u751f\u6210\u7684\u6587\u4ef6 /etc/kubernetes/admin.conf \u7684\u526f\u672c\u3002 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e KUBECONFIG \u73af\u5883\u53d8\u91cf\u6216\u8bbe\u7f6e --kubeconfig flag \u6807\u5fd7\u6765\u6307\u5b9a\u5176\u4ed6 kubeconfig \u6587\u4ef6\u3002\u5982\u679c KUBECONFIG \u73af\u5883\u53d8\u91cf\u4e0d\u5b58\u5728\uff0ckubectl \u5c06\u4f7f\u7528\u9ed8\u8ba4\u7684 kubeconfig \u6587\u4ef6 $HOME/.kube/config \u3002 kubeconfig \u6587\u4ef6\u4e2d\u7684 context\uff08\u4e0a\u4e0b\u6587\uff09 \u5143\u7d20\u7528\u4e8e\u5c06\u8bbf\u95ee\u53c2\u6570\u5206\u7ec4\u5230\u4e00\u4e2a\u65b9\u4fbf\u7684\u540d\u79f0\u4e0b\u3002\u6bcf\u4e2a\u4e0a\u4e0b\u6587\u90fd\u6709\u4e09\u4e2a\u53c2\u6570\uff1a\u96c6\u7fa4\u3001\u547d\u540d\u7a7a\u95f4\u548c\u7528\u6237\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0ckubectl \u547d\u4ee4\u884c\u5de5\u5177\u4f7f\u7528\u5f53\u524d\u4e0a\u4e0b\u6587\u4e2d\u7684\u53c2\u6570\u4e0e\u96c6\u7fa4\u901a\u4fe1\u3002 \u6587\u4ef6 .kube/config \u7684\u4f8b\u5b50\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : \u8bfb\u53d6\u5f53\u524d\u4e0a\u4e0b\u6587\uff1a kubectl config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin \u914d\u7f6e\u5de5\u4f5c\u8282\u70b9 \u00b6 \u4f7f\u7528 kubeadm token \u6765\u751f\u6210\u52a0\u5165\u96c6\u7fa4\u7684\u4ee4\u724c\uff08token\uff09\u548c\u54c8\u897f\u503c\uff08hash value\uff09\u3002 kubeadm token create --print-join-command \u5728\u6240\u6709\u5de5\u4f5c\u8282\u70b9\u4e0a\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u5c06\u5de5\u4f5c\u8282\u70b9\u52a0\u5165Kubernetes\u96c6\u7fa4\u3002 # kubeadm join :6443 --token --discovery-token-ca-cert-hash \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u68c0\u67e5\u6240\u6709\u8282\u70b9\u7684\u72b6\u6001\u3002 \u5f53\u524d\u6240\u6709\u8282\u70b9\u7684\u72b6\u6001\u90fd\u662f NotReady \u3002\u76ee\u524d\u4e0d\u9700\u8981\u505a\u4ec0\u4e48\uff0c\u540e\u9762\u6211\u4eec\u4f1a\u5b89\u88c5\u76f8\u5173\u7684\u7f51\u7edc\u670d\u52a1\uff08Calico \u6216 Flannel\uff09\uff0c\u5404\u8282\u70b9\u7684\u72b6\u6001\u5c31\u4f1a\u53d8\u6210Ready\u72b6\u6001\u3002 \u5b89\u88c5Calico\u6216Flannel \u00b6 \u5728\u63a7\u5236\u5e73\u9762Control Plane\u4e0a\u5b89\u88c5Calico\u6216\u8005Flannel\u3002\u5982\u679c\u9700\u8981\u914d\u7f6e\u7f51\u7edc\u7b56\u7565\uff0c\u5219\u9009\u62e9Calico\u3002 \u5b89\u88c5Flannel \u00b6 Flannel \u662f\u4e3a Kubernetes \u8bbe\u8ba1\u7684\u4e00\u79cd\u7b80\u5355\u6613\u7528\u7684\u914d\u7f6e\u4e09\u5c42\u7f51\u7edc\u7684\u65b9\u6cd5\u3002 \u90e8\u7f72Flannel\uff1a \u5728 kube-flannel.yml \u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u83b7\u53d6 Flannel \u7684\u9ed8\u8ba4\u7f51\u7edc\u8bbe\u7f6e\uff0c\u5b83\u4e0e\u6211\u4eec\u5728\u4f7f\u7528 kubeadm \u521d\u59cb\u5316\u96c6\u7fa4\u65f6\u6307\u5b9a\u7684\u53c2\u6570 --pod-network-cidr=10.244.0.0/16 \u76f8\u540c\u3002 net - co nf .jso n : | { \"Network\" : \"10.244.0.0/16\" , \"Backend\" : { \"Type\" : \"vxlan\" } } \u521b\u5efaFlannel\u670d\u52a1\u3002 apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml \u8f93\u51fa\u7ed3\u679c\uff1a Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy/psp.flannel.unprivileged created clusterrole.rbac.authorization.k8s.io/flannel created clusterrolebinding.rbac.authorization.k8s.io/flannel created serviceaccount/flannel created configmap/kube-flannel-cfg created daemonset.apps/kube-flannel-ds created \u5b89\u88c5Calico \u00b6 \u5b89\u88c5\u6307\u5bfc\u624b\u518c\uff1a End-to-end Calico installation \u3002 \u4e0b\u8f7d\u5e76\u5b89\u88c5Calico\u670d\u52a1\u3002 curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml \u8f93\u51fa\u7ed3\u679c\uff1a configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created \u9a8c\u8bc1Calico\u670d\u52a1\u72b6\u6001\uff1a kubectl get pod -n kube-system | grep calico \u8f93\u51fa\u7ed3\u679c\uff1a calico-kube-controllers-555bc4b957-l8bn2 0 /1 Pending 0 28s calico-node-255pc 0 /1 Init:1/3 0 29s calico-node-7tmnb 0 /1 Init:1/3 0 29s calico-node-w8nvl 0 /1 Init:1/3 0 29s \u68c0\u67e5\u96c6\u7fa4\u7684\u7f51\u7edc\u72b6\u6001\uff1a sudo nerdctl network ls \u8f93\u51fa\u7ed3\u679c\uff1a NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none \u68c0\u67e5\u96c6\u7fa4\u72b6\u6001 \u00b6 \u5728\u4e3b\u8282\u70b9\u4e0a\u6267\u884c\u547d\u4ee4 kubectl cluster-info \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff1a \u63a7\u5236\u5e73\u9762\uff08control plane\uff09\u8fd0\u884c\u5728 https://:6443 CoreDNS\u670d\u52a1\u8fd0\u884c\u5728 https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy kubectl cluster-info \u67e5\u770b\u8282\u70b9\u8fd0\u884c\u72b6\u6001\u3002\u6b64\u65f6\uff0c\u6240\u6709\u8282\u70b9\u90fd\u662f Ready \u7684\u6b63\u5e38\u72b6\u6001\u4e86\u3002 OS Image: Ubuntu 20.04.4 LTS Kernel Version: 5.4.0-122-generic Container Runtime: containerd://1.5.9 kubectl get nodes -owide \u8f93\u51fa\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane 13m v1.24.0 cka002 Ready 8m35s v1.24.0 cka003 Ready 8m26s v1.24.0 \u67e5\u770bPods\u7684\u72b6\u6001\u3002 kubectl get pod -A \u8f93\u51fa\u7ed3\u679c\uff1a NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 7m18s kube-system calico-node-255pc 1/1 Running 0 7m19s kube-system calico-node-7tmnb 1/1 Running 0 7m19s kube-system calico-node-w8nvl 1/1 Running 0 7m19s kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15m kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15m kube-system etcd-cka001 1/1 Running 0 15m kube-system kube-apiserver-cka001 1/1 Running 0 15m kube-system kube-controller-manager-cka001 1/1 Running 0 15m kube-system kube-proxy-dmj2t 1/1 Running 0 15m kube-system kube-proxy-n77zw 1/1 Running 0 11m kube-system kube-proxy-qs6rf 1/1 Running 0 11m kube-system kube-scheduler-cka001 1/1 Running 0 15m \u66f4\u65b0\u5b89\u88c5 \u00b6 Bash\u81ea\u52a8\u8865\u5168 \u00b6 \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u914d\u7f6eBash\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 \u53c2\u8003 \u6307\u5bfc \u8bbe\u7f6e kubectl \u81ea\u52a8\u8865\u5168\u529f\u80fdauto-completion \u3002 apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc source ~/.bashrc \u522b\u540d \u00b6 \u5982\u679c\u6211\u4eec\u4e3a kubectl \u8bbe\u7f6e\u4e00\u4e2a\u522b\u540d\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u4e00\u4e9b\u65b9\u6cd5\u6765\u6269\u5c55 shell \u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u4f7f\u5176\u80fd\u591f\u4e0e\u8be5\u522b\u540d\u4e00\u8d77\u4f7f\u7528\u3002 \u4e00\u79cd\u65b9\u6cd5\u662f\u5728 Bash shell \u914d\u7f6e\u6587\u4ef6\uff08\u5982 .bashrc \u6216 .bash_profile\uff09\u4e2d\u8bbe\u7f6e\u522b\u540d\uff0c\u5e76\u4e3a\u8be5\u522b\u540d\u6307\u5b9a kubectl \u7684\u5b8c\u6574\u8def\u5f84\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a alias k = 'path/to/kubectl' \u7136\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u91cd\u65b0\u52a0\u8f7d .bashrc \u6587\u4ef6\uff1a source ~/.bashrc \u63a5\u4e0b\u6765\uff0c\u53ef\u4ee5\u4f7f\u7528 k \u547d\u4ee4\u6765\u4ee3\u66ff kubectl \u547d\u4ee4\uff0c\u5e76\u5728\u5176\u540e\u9762\u6dfb\u52a0\u76f8\u5e94\u7684\u53c2\u6570\u548c\u9009\u9879\u3002\u5f53\u4f7f\u7528\u81ea\u52a8\u8865\u5168\u529f\u80fd\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u5c06 k \u522b\u540d\u8f6c\u6362\u4e3a kubectl \u7684\u5b8c\u6574\u8def\u5f84\uff0c\u5e76\u5bf9\u5176\u8fdb\u884c\u81ea\u52a8\u8865\u5168\u3002 \u53e6\u4e00\u79cd\u65b9\u6cd5\u662f\u4f7f\u7528 Bash shell \u5185\u7f6e\u7684 complete \u51fd\u6570\u6765\u4e3a\u522b\u540d\u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc \u8fd9\u5c06\u4e3a\u522b\u540d k \u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u5e76\u5c06\u5176\u4e0e kubectl \u7684\u81ea\u52a8\u8865\u5168\u51fd\u6570 __start_kubectl \u5173\u8054\u8d77\u6765\u3002\u8fd9\u6837\uff0c\u5f53\u7528\u6237\u5728 k \u547d\u4ee4\u540e\u8f93\u5165Tab\u952e\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u8c03\u7528 __start_kubectl \u51fd\u6570\uff0c\u5e76\u4e3a\u7528\u6237\u63d0\u4f9b\u76f8\u5e94\u7684\u81ea\u52a8\u8865\u5168\u5efa\u8bae\u3002 \u66f4\u65b0\u9ed8\u8ba4Context \u00b6 \u67e5\u770b\u5f53\u524d\u7684 context \u5217\u8868\uff1a kubectl config get-contexts \u8fd9\u4e2a\u547d\u4ee4\u4f1a\u5217\u51fa\u6240\u6709\u53ef\u7528\u7684 context \u5217\u8868\uff0c\u5e76\u6807\u8bb0\u51fa\u5f53\u524d\u6b63\u5728\u4f7f\u7528\u7684 context\u3002 \u7c7b\u4f3c\u4e0b\u9762\u7ed3\u679c\uff1a kubernetes-admin@kubernetes \u662fContext\u540d\u3002 kubernetes \u662f\u96c6\u7fa4\u540d\u3002 kubernetes-admin \u662f\u7528\u6237\u540d\u3002 \u5f53\u524d\u4f8b\u5b50\u4e2d\u6ca1\u6709\u6307\u5b9a\u540d\u79f0\u7a7a\u95f4\u3002 CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin \u66f4\u65b0context\u3002\u4f8b\u5982\uff0c\u66f4\u65b0context\u7684\u9ed8\u8ba4\u540d\u79f0\u7a7a\u95f4\u7b49\u3002 # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin \u5728\u4e0d\u540c\u7684context\u4e4b\u95f4\u5207\u6362\u3002 # Usage: kubectl config use-context # Switch to new context kubectl config use-context kubernetes-admin@kubernetes \u53c2\u8003\u8d44\u6599\uff1a kubectl [commandline \u91cd\u7f6e\u96c6\u7fa4 \u00b6 \u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u64cd\u4f5c\u4f1a\u91cd\u7f6e\u5f53\u524d\u96c6\u7fa4\uff08\u5220\u9664\u96c6\u7fa4\uff09\u3002 \u5220\u9664\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u3002 kubeadm reset \u6e05\u9664 iptables \u4e2d\u5df2\u5b9a\u4e49\u7684\u89c4\u5219\u3002 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u6e05\u9664 IPVS \u4e2d\u5b9a\u4e49\u7684\u89c4\u5219\uff08\u5982\u679c\u4f7f\u7528 IPVS \uff09\u3002 ipvsadm --clear \u6392\u9519 \u00b6 \u9519\u8bef1 \u00b6 \u62a5\u9519\u4fe1\u606f\uff1a The connection to the server :6443 was refused - did you specify the right host or port? \u89e3\u51b3\u5c1d\u8bd5\uff1a Reference \u68c0\u67e5\u6587\u4ef6kubeconfig\u7684\u5185\u5bb9\u548c\u6587\u4ef6\u8def\u5f84\u662f\u5426\u6b63\u786e\u3002 \u68c0\u67e5\u73af\u5883\u53d8\u91cf\u8bbe\u7f6e\u3002 env | grep -i kub \u68c0\u67e5\u5bb9\u5668\u8fd0\u884c\u72b6\u6001\u3002 sudo systemctl status containerd.service \u68c0\u67e5kubelet\u670d\u52a1\u3002 sudo systemctl status kubelet.service \u68c0\u67e5 6443 \u7aef\u53e3\u76d1\u542c\u72b6\u6001\u3002 netstat -pnlt | grep 6443 \u68c0\u67e5\u9632\u706b\u5899\u72b6\u6001\u3002 sudo systemctl status firewalld.service \u68c0\u67e5kubelet\u65e5\u5fd7\u3002 journalctl -xeu kubelet \u9519\u8bef2 \u00b6 \u62a5\u9519\u4fe1\u606f\uff1a \"Container runtime network not ready\" networkReady=\"NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized\" \u5c1d\u8bd5\u65b9\u6cd5\uff1a \u91cd\u542fContainerd\u670d\u52a1\u3002 sudo systemctl restart containerd sudo systemctl status containerd","title":"\u963f\u91cc\u4e91ECS\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#cka3ecskubernetes","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb03:\u963f\u91cc\u4e91ECS\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_1","text":"\u5728\u963f\u91cc\u4e91ECS\u88c5\u4e09\u53f0Ubuntu\u865a\u62df\u673a\u3002\u5728Ubuntu\u865a\u62df\u673a\u4e2d\u5b89\u88c5\u57fa\u4e8eContainerd\u7684Kubernetes\u7cfb\u7edf\uff0c\u5e76\u5206\u522b\u914d\u7f6e\u4e00\u4e2a\u4e3b\u8282\u70b9Master\u548c\u4e24\u4e2a\u5de5\u4f5c\u8282\u70b9Worker\uff0c\u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_2","text":"\u6ce8\u518c\u963f\u91cc\u4e91\u8d26\u53f7\uff1a Alibaba Cloud home console \u3002\u6ce8\u610f\u4fdd\u7559\u8bbf\u95ee\u5bc6\u94a5key\u6587\u4ef6\uff0c\u53ea\u80fd\u5bfc\u51fa\u4e00\u6b21\uff0c\u5f53\u524d\u7ec3\u4e60\u4e2dkey\u6587\u4ef6\u662f aliyun-root \u3002 \u53c2\u8003\u4e0b\u9762\u914d\u7f6e\u6ce8\u518c\u7533\u8bf7\u4e09\u4e2aECS\uff08Elastic Computer Service\uff09\u670d\u52a1\u5b9e\u4f8b\uff1a \u4e3b\u673a\uff1a2vCPU+4GiB \u64cd\u4f5c\u7cfb\u7edf\uff1aUbuntu 20.04 x86_64 \u5b9e\u4f8b\u7c7b\u578b\uff1aecs.sn1.medium \u5b9e\u4f8b\u540d\u79f0\uff1acka001, cka002, cka003 \u7f51\u7edc\u914d\u7f6e\uff1aboth public IPs and private IPs \u6700\u5927\u7f51\u7edc\u5e26\u5bbd\uff1a100Mbps (Peak Value) \u4e91\u76d8\uff1a40GiB \u652f\u4ed8\u65b9\u5f0f\uff1a\u62a2\u5360\u5f0f\u5b9e\u4f8b \u5728\u672c\u5730\u6253\u5f00\u7ec8\u7aef\u7a97\u53e3\uff0c\u901a\u8fc7\u5bc6\u94a5\u6587\u4ef6 aliyun-root \u8bbf\u95ee\u8fdc\u7a0bECS\u8282\u70b9 cka001 \u3002 ssh -i aliyun-root root@cka001 \u521b\u5efa\u4e00\u4e2a\u666e\u901a\u7528\u6237\uff0c\u7528\u6765\u5b89\u88c5Kubernetes\uff0c\u5f53\u524d\u7ec3\u4e60\u4e2d\u521b\u5efa\u7528\u6237 vagrant \uff0c\u4e14\u4fee\u6539\u8be5\u7528\u6237\u7684\u4e3b\u8981\u7ec4\u4e3a sudo \u6b21\u8981\u7ec4\u5305\u542b root \u3002 adduser vagrant usermod -g sudo vagrant usermod -a -G root vagrant \u65b0\u5f00\u4e00\u4e2a\u672c\u5730\u7ec8\u7aef\u7a97\u53e3\uff0c\u4e3a\u7528\u6237 vagrant \u521b\u5efa\u5bc6\u94a5key\u3002 # Windows ssh-keygen.exe # Linux ssh-keygen \u4e0a\u9762\u7684\u547d\u4ee4\u4f1a\u751f\u62102\u4e2a\u6587\u4ef6\uff0c\u5f53\u524d\u7ec3\u4e60\u4e2d\u8fd92\u4e2a\u6587\u4ef6\u662f aliyun-vagrant and aliyun-vagrant.pub \u901a\u8fc7 sftp \u547d\u4ee4\u5c06\u516c\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u4e0a\u4f20\u5230\u8fdc\u7a0b\u8282\u70b9 cka001 \u3002 sftp -i aliyun-root root@cka001 put aliyun-vagrant.pub \u65b0\u5f00\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\uff0c\u7528 root \u7684\u5bc6\u94a5\u767b\u5f55 cka001 \u8282\u70b9\u3002 \u5c06\u4e0a\u4e00\u6b65\u4e0a\u4f20\u7684\u5bc6\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u4ece /root \u76ee\u5f55\u62f7\u8d1d\u5230 /home/vagrant/.ssh/ \u3002 \u5c06\u516c\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u91cd\u547d\u540d\u4e3a authorized_keys \u3002 \u66f4\u6539\u6587\u4ef6 authorized_keys \u7684\u6240\u6709\u8005owner\u4e3a vagrant . \u66f4\u6539\u6587\u4ef6 authorized_keys \u7684\u4e3b\u8981\u7ec4\u4e3a sudo \u3002 mkdir /home/vagrant/.ssh/ mv aliyun-james.pub /home/vagrant/.ssh/authorized_keys chown vagrant.sudo /home/vagrant/.ssh/authorized_keys chmod 600 /home/vagrant/.ssh/authorized_keys \u68c0\u67e5\u6587\u4ef6 /etc/ssh/sshd_config \uff0c\u786e\u5b9a\u5bc6\u7801\u767b\u5f55\u9a8c\u8bc1\u53c2\u6570 asswordAuthentication \u8bbe\u5b9a\u4e3a no \uff0c\u5373\u53ea\u80fd\u901a\u8fc7\u8bc1\u4e66\u8fdc\u7a0b\u767b\u5f55\u3002 cat /etc/ssh/sshd_config \u65b0\u5f00\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\uff0c\u4f7f\u7528\u7528\u6237vagrant\u767b\u5f55\u8fdc\u7a0b\u8282\u70b9 cka001 \uff0c\u9a8c\u8bc1\u7528\u6237 vagrant \u80fd\u901a\u8fc7\u524d\u9762\u521b\u5efa\u7684\u8bc1\u4e66\u767b\u5f55\u8282\u70b9 cka001 \u3002 ssh -i aliyun-vagrant vagrant@cka001 \u91cd\u590d\u4e0a\u8ff0\u6b65\u9aa4\uff0c\u901a\u8fc7 sftp \u547d\u4ee4\u5c06\u516c\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u5206\u522b\u4e0a\u4f20\u5230\u8fdc\u7a0b\u8282\u70b9 cka002 \u548c cka003 \uff0c\u4e14\u5b8c\u6210\u540c\u6837\u7684\u914d\u7f6e\uff0c\u4f7f\u7528\u6237 vagrant \u4e5f\u80fd\u901a\u8fc7\u5bc6\u94a5\u6587\u4ef6\u767b\u5f55\u8fdc\u7a0b\u8282\u70b9 cka002 \u548c cka003 \u3002 \u81f3\u6b64\uff0c\u7528\u6237 vagrant \u53ef\u4ee5\u901a\u8fc7\u5bc6\u94a5\u6587\u4ef6 aliyun-vagrant \u4ece\u672c\u5730\u7ec8\u7aef\u7a97\u53e3\u767b\u5f55\u8fdc\u7a0b\u8282\u70b9 cka001 , cka002 \u548c cka003 \u3002 \u4e0b\u9762\u6240\u6709\u6b65\u9aa4\u90fd\u662f\u901a\u8fc7\u7528\u6237 vagrant \u5b8c\u6210\u3002","title":"\u51c6\u5907\u5de5\u4f5c"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#ecs","text":"","title":"\u521d\u59cb\u5316ECS\u8282\u70b9"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#etchosts","text":"\u66f4\u65b0\u6240\u6709ECS\u8282\u70b9\u7684\u6587\u4ef6/etc/hosts\uff0c\u6dfb\u52a0\u5176\u4ed6\u8282\u70b9\u7684\u79c1\u6709IP\uff08private IP\uff09\u3002 vi /etc/hosts","title":"\u914d\u7f6e\u6587\u4ef6/etc/hosts"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#firewall","text":"\u5728\u6240\u6709\u8282\u70b9\u4e0a\u7981\u7528\u9632\u706b\u5899\u3002 sudo ufw disable \u68c0\u67e5\u9632\u706b\u5899\u72b6\u6001\u3002 sudo ufw status verbose","title":"\u7981\u7528firewall"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#swap","text":"\u5728\u6240\u6709\u8282\u70b9\u4e0a\u5173\u95edswap\u3002 sudo swapoff -a","title":"\u5173\u95edswap"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_3","text":"\u5728\u6240\u6709\u8282\u70b9\u8bbe\u5b9a\u65f6\u533a\u548c\u5730\u57df\u3002\u8fd9\u4e00\u5e03\u5728\u521d\u59cb\u5316ECS\u65f6\u5019\u5df2\u7ecf\u5b8c\u6210\u3002\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u8fdb\u884c\u8bbe\u5b9a\u3002 ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile \u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u68c0\u67e5\u65f6\u533a\u548c\u5730\u57df\u7684\u8bbe\u7f6e\u3002 ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 5 14:51 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai","title":"\u8bbe\u7f6e\u65f6\u533a\u548c\u5730\u57df"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_4","text":"\u5728\u6240\u6709\u8282\u70b9\u4e0a\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u4ee5\u914d\u7f6e\u5185\u6838\u3002 \u4f7f\u7528\u6a21\u5757overlay\uff1a \u521b\u5efaContainerd\u670d\u52a1\u914d\u7f6e\u6587\u4ef6 /etc/modules-load.d/containerd.conf \uff0c\u5982\u679c\u5df2\u5b58\u5728\u5219\u8df3\u8fc7\u8fd9\u4e00\u6b65\u3002\u914d\u7f6e\u8fd9\u4e2a\u6587\u4ef6\u7684\u76ee\u7684\u662f\u4e3a\u4e86\u52a0\u8f7d\u6a21\u5757 overlay \u548c br_netfilter \u5230\u5185\u6838\u4e2d\u3002 \u670d\u52a1Containerd\u4f9d\u8d56\u6a21\u5757 overlay \u5b9e\u73b0 overlay-filesystem \u6587\u4ef6\u7cfb\u7edf\u529f\u80fd\u3002 Linux\u4e2d\u7684overlay\u6a21\u5757\u63d0\u4f9b\u4e86\u521b\u5efa\u4e24\u4e2a\u76ee\u5f55\u7684\u5408\u5e76\u89c6\u56fe\u7684\u80fd\u529b\uff0c\u8fd9\u4e24\u4e2a\u76ee\u5f55\u79f0\u4e3a\u5c42\u3002\u5b83\u7ecf\u5e38\u88ab\u7528\u4e8e\u5b9e\u73b0\u8054\u5408\u6302\u8f7d\uff0c\u8fd9\u662f\u4e00\u79cd\u5c06\u4e24\u4e2a\u6216\u66f4\u591a\u76ee\u5f55\u4e00\u8d77\u6302\u8f7d\u7684\u65b9\u5f0f\uff0c\u5c31\u50cf\u5b83\u4eec\u662f\u4e00\u4e2a\u76ee\u5f55\u4e00\u6837\uff08union-filesystems\uff09\u3002 overlay\u6a21\u5757\u5728\u5bb9\u5668\u6280\u672f\u4e2d\u88ab\u5e7f\u6cdb\u4f7f\u7528\uff0c\u6bd4\u5982Docker\uff0c\u56e0\u4e3a\u5b83\u5141\u8bb8\u591a\u4e2a\u5bb9\u5668\u5171\u4eab\u57fa\u7840\u955c\u50cf\uff0c\u540c\u65f6\u4fdd\u6301\u5b83\u4eec\u81ea\u5df1\u7684\u6587\u4ef6\u7cfb\u7edf\u3002 \u8981\u4f7f\u7528overlay\u6a21\u5757\uff0c\u9700\u8981\u4e24\u4e2a\u76ee\u5f55\uff1a\u8f83\u4f4e\u7684\u76ee\u5f55\uff08lower directory\uff09\u548c\u8f83\u9ad8\u7684\u76ee\u5f55\uff08upper directory\uff09\u3002\u8f83\u4f4e\u7684\u76ee\u5f55\u901a\u5e38\u662f\u53ea\u8bfb\u7684\uff0c\u5305\u542b\u539f\u59cb\u6587\u4ef6\uff0c\u800c\u8f83\u9ad8\u7684\u76ee\u5f55\u662f\u53ef\u8bfb\u5199\u7684\uff0c\u5305\u542b\u5bf9\u6587\u4ef6\u7684\u66f4\u6539\u3002\u5f53\u8bf7\u6c42\u6587\u4ef6\u65f6\uff0coverlay\u6a21\u5757\u9996\u5148\u67e5\u627e\u4e0a\u5c42\u76ee\u5f55\uff0c\u5982\u679c\u672a\u627e\u5230\uff0c\u5219\u67e5\u627e\u4e0b\u5c42\u76ee\u5f55\u3002 \u6bd4\u5982\uff1a \u521b\u5efa\u4e24\u4e2a\u76ee\u5f55\uff0c\u4e00\u4e2a\u7528\u4e8e\u8f83\u4f4e\u7684\u76ee\u5f55\uff0c\u4e00\u4e2a\u7528\u4e8e\u8f83\u9ad8\u7684\u76ee\u5f55\u3002\u7136\u540e\u4f7f\u7528overlay\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u5c06\u5b83\u4eec\u6302\u8f7d\u8d77\u6765\uff1a sudo mkdir /lower sudo mkdir /upper sudo mount -t overlay overlay -o lowerdir = /lower,upperdir = /upper /merged \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c\u4e24\u4e2a\u76ee\u5f55\u7684\u5408\u5e76\u89c6\u56fe\u88ab\u521b\u5efa\u5728 /merged \u76ee\u5f55\u4e2d\u3002\u5728 /merged \u76ee\u5f55\u4e2d\u5bf9\u6587\u4ef6\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u5b58\u50a8\u5728\u4e0a\u5c42\u76ee\u5f55\u4e2d\uff0c\u800c\u539f\u59cb\u6587\u4ef6\u4ecd\u7136\u5728\u4e0b\u5c42\u76ee\u5f55\u4e2d\u3002 \u4f7f\u7528\u6a21\u5757br_netfilter\uff1a br_netfilter \u662fLinux\u5185\u6838\u4e2d\u7684\u4e00\u4e2a\u6a21\u5757\uff0c\u5b83\u63d0\u4f9b\u4e86\u4e00\u79cd\u673a\u5236\u6765\u8fc7\u6ee4\u7f51\u6865\u7684\u7f51\u7edc\u6d41\u91cf\u3002\u8be5\u6a21\u5757\u5141\u8bb8\u7ba1\u7406\u5458\u914d\u7f6e\u89c4\u5219\uff0c\u4ee5\u5141\u8bb8\u6216\u62d2\u7edd\u7279\u5b9a\u7684\u7f51\u7edc\u6d41\u91cf\u901a\u8fc7\u7f51\u6865\u3002 \u7f51\u6865\u662f\u4e00\u79cd\u7f51\u7edc\u8bbe\u5907\uff0c\u5b83\u53ef\u4ee5\u8fde\u63a5\u591a\u4e2a\u7f51\u7edc\u6bb5\uff0c\u5e76\u8f6c\u53d1\u6d41\u91cf\u4ee5\u4f7f\u4e0d\u540c\u7684\u7f51\u7edc\u6bb5\u4e4b\u95f4\u901a\u4fe1\u3002 br_netfilter \u6a21\u5757\u53ef\u4ee5\u7528\u6765\u9650\u5236\u6216\u8fc7\u6ee4\u8fd9\u4e9b\u6d41\u91cf\u3002 \u5f53\u542f\u7528\u4e86 br_netfilter \u6a21\u5757\u65f6\uff0c\u5b83\u4f1a\u81ea\u52a8\u542f\u7528\u4e00\u4e2a\u79f0\u4e3a bridge-nf \u7684\u529f\u80fd\uff0c\u8be5\u529f\u80fd\u5c06\u5728\u7f51\u7edc\u6d41\u91cf\u901a\u8fc7\u7f51\u6865\u65f6\u5e94\u7528\u89c4\u5219\u3002\u7ba1\u7406\u5458\u53ef\u4ee5\u4f7f\u7528iptables\u7b49\u5de5\u5177\u6765\u914d\u7f6e\u8fd9\u4e9b\u89c4\u5219\u3002\u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u8bbe\u5b9a\u5141\u8bb8\u4ece\u4e00\u4e2a\u7f51\u7edc\u6bb5\u5230\u53e6\u4e00\u4e2a\u7f51\u7edc\u6bb5\u7684\u6d41\u91cf\uff0c\u6216\u8005\u62d2\u7edd\u6765\u81ea\u7279\u5b9aIP\u5730\u5740\u6216\u7aef\u53e3\u7684\u6d41\u91cf\u3002 \u5728Kubernetes\u4e2d\uff0c br_netfilter \u6a21\u5757\u4e3b\u8981\u7528\u4e8e\u542f\u7528Kubernetes\u670d\u52a1\u7684\u6d41\u91cf\u8f6c\u53d1\u548c\u8d1f\u8f7d\u5747\u8861\u3002\u8fd9\u4e9b\u670d\u52a1\u4f7f\u7528\u4e86Linux\u5185\u6838\u4e2d\u7684iptables\u89c4\u5219\u6765\u7ba1\u7406\u6d41\u91cf\uff0c\u8fd9\u4e9b\u89c4\u5219\u662f\u901a\u8fc7 br_netfilter \u6a21\u5757\u5b9e\u73b0\u7684\u3002 \u5177\u4f53\u6765\u8bf4\uff0c\u5f53\u6211\u4eec\u5728Kubernetes\u96c6\u7fa4\u4e2d\u521b\u5efa\u4e00\u4e2a\u670d\u52a1\u65f6\uff0c\u8be5\u670d\u52a1\u5c06\u5206\u914d\u4e00\u4e2a\u865a\u62dfIP\u5730\u5740\uff0c\u7528\u4e8e\u4ee3\u8868\u670d\u52a1\u3002\u7136\u540e\uff0c\u901a\u8fc7iptables\u89c4\u5219\uff0c\u5c06\u8fd9\u4e2a\u865a\u62dfIP\u5730\u5740\u6620\u5c04\u5230\u4e00\u4e2a\u6216\u591a\u4e2a\u540e\u7aefPod\u7684IP\u5730\u5740\uff0c\u4ee5\u4fbf\u5728\u9700\u8981\u65f6\u5c06\u6d41\u91cf\u8def\u7531\u5230\u8fd9\u4e9bPod\u3002 \u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e2d\uff0c br_netfilter \u6a21\u5757\u8d1f\u8d23\u76d1\u89c6\u670d\u52a1\u7684\u6d41\u91cf\uff0c\u5e76\u6839\u636eiptables\u89c4\u5219\u8fdb\u884c\u8f6c\u53d1\u548c\u8d1f\u8f7d\u5747\u8861\u3002\u8fd9\u5305\u62ec\u8fc7\u6ee4\u6765\u81ea\u4e0d\u53d7\u4fe1\u4efb\u6e90\u7684\u6d41\u91cf\u4ee5\u53ca\u9650\u5236\u670d\u52a1\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u4e3a\u4e86\u542f\u7528Kubernetes\u670d\u52a1\u7684\u6d41\u91cf\u8f6c\u53d1\u548c\u8d1f\u8f7d\u5747\u8861\uff0c br_netfilter \u6a21\u5757\u5fc5\u987b\u5728\u6240\u6709\u8282\u70b9\u4e0a\u542f\u7528\uff0c\u5e76\u4e14\u5fc5\u987b\u914d\u7f6e\u6b63\u786e\u7684iptables\u89c4\u5219\u3002 \u7531\u4e8e br_netfilter \u6a21\u5757\u7684\u4f5c\u7528\u975e\u5e38\u5173\u952e\uff0c\u56e0\u6b64\u5728\u5347\u7ea7\u6216\u66f4\u6539\u7cfb\u7edf\u65f6\u9700\u8981\u7279\u522b\u6ce8\u610f\u5b83\u7684\u914d\u7f6e\u548c\u72b6\u6001\u3002 \u4e0b\u9762\u547d\u4ee4\u5c06\u6a21\u5757 overlay \u548c br_netfilter \u6dfb\u52a0\u5230\u914d\u7f6e\u6587\u4ef6 containerd.conf \u4e2d\u3002 cat < /etc/apt/sources.list << EOF deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multivers deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe # deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse # deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse EOF \u5b89\u88c5Containered\u3002 sudo apt-get update && sudo apt-get install -y containerd \u914d\u7f6eContainerd\u3002\u4fee\u6539\u6587\u4ef6 /etc/containerd/config.toml \u3002 sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml \u4fee\u6539\u53c2\u6570 sandbox_image \u7684\u503c\u4e3a \"registry.aliyuncs.com/google_containers/pause:3.6\" \u3002 \u4fee\u6539\u53c2\u6570 SystemdCgroup \u7684\u503c\u4e3a true \u3002 [plugins] [plugins.\"io.containerd.gc.v1.scheduler\"] [plugins.\"io.containerd.grpc.v1.cri\"] sandbox_image = \"registry.aliyuncs.com/google_containers/pause:3.6\" [plugins.\"io.containerd.grpc.v1.cri\".cni] [plugins.\"io.containerd.grpc.v1.cri\".containerd] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime.options] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc.options] SystemdCgroup = true \u91cd\u542fContainerd\u670d\u52a1\u3002 sudo systemctl restart containerd sudo systemctl status containerd","title":"\u5b89\u88c5Containerd"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#nerdctl","text":"\u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b89\u88c5nerdctl\u670d\u52a1\u3002 nerdctl \u670d\u52a1\u652f\u6301Contanerd\u6240\u63d0\u4f9b\u7684\u5bb9\u5668\u5316\u7279\u6027\uff0c\u7279\u522b\u662f\u4e00\u4e9bDocker\u4e0d\u5177\u5907\u7684\u65b0\u7279\u6027\u3002 \u4e8c\u8fdb\u5236\u5b89\u88c5\u5305\u53ef\u4ee5\u901a\u8fc7\u8fd9\u4e2a\u94fe\u63a5\u53d6\u5f97: Releases \u00b7 containerd/nerdctl \u00b7 GitHub \u3002 wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-0.22.2-linux-amd64.tar.gz tar -zxvf nerdctl-0.22.2-linux-amd64.tar.gz sudo cp nerdctl /usr/bin/ \u9a8c\u8bc1 nerdctl \u670d\u52a1\u3002 sudo nerdctl --help \u5217\u51fa\u521d\u59cb\u5b89\u88c5Kubernetes\u65f6\u7684\u5bb9\u5668container\u5217\u8868\u3002 nerdctl -n k8s.io ps","title":"\u5b89\u88c5nerdctl"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#kubeadm","text":"\u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b89\u88c5Kubeadm\uff0ckubectl\uff0ckubelet\u3002 \u5b89\u88c5\u548c\u5347\u7ea7Ubuntu\u7cfb\u7edf\u4f9d\u8d56\u5305 apt-transport-https , ca-certificates , curl \u3002 sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl \u5b89\u88c5gpg\u8bc1\u4e66\u3002 curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - \u6dfb\u52a0Kubernetes\u5b89\u88c5\u6e90\u3002 cat << EOF > /etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF \u5b89\u88c5\u548c\u5347\u7ea7Ubuntu\u7cfb\u7edf\u4f9d\u8d56\u5305\u3002 sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables \u68c0\u67e5\u5f53\u524d\u53ef\u7528\u7684 kubeadm \u7248\u672c\u3002 apt policy kubeadm \u5f53\u524d\u5b89\u88c5 1.24.0-00 \u7248\u672c\u7684 kubeadm \uff0c\u540e\u7eed\u4f1a\u5347\u7ea7\u5230 1.24.2 \u7248\u672c\u3002 sudo apt-get -y install kubelet = 1 .24.0-00 kubeadm = 1 .24.0-00 kubectl = 1 .24.0-00 --allow-downgrades","title":"\u5b89\u88c5kubeadm"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_5","text":"","title":"\u914d\u7f6e\u4e3b\u8282\u70b9"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#kubeadm_1","text":"\u5728\u627f\u62c5\u4e3b\u8282\u70b9\u7684\u865a\u62df\u673a\u91cc\u914d\u7f6e\u63a7\u5236\u5e73\u9762\uff08Control Plane\uff09\u3002 \u68c0\u67e5 kubeadm \u5f53\u524d\u9ed8\u8ba4\u914d\u7f6e\u53c2\u6570\u3002 kubeadm config print init-defaults \u7c7b\u4f3c\u7ed3\u679c\u5982\u4e0b\u3002\u4fdd\u5b58\u9ed8\u8ba4\u914d\u7f6e\u7684\u7ed3\u679c\uff0c\u540e\u7eed\u4f1a\u4f5c\u4e3a\u53c2\u8003\u3002 apiVersion : kubeadm.k8s.io/v1beta3 bootstrapTokens : - groups : - system:bootstrappers:kubeadm:default-node-token token : abcdef.0123456789abcdef ttl : 24h0m0s usages : - signing - authentication kind : InitConfiguration localAPIEndpoint : advertiseAddress : 1.2.3.4 bindPort : 6443 nodeRegistration : criSocket : unix:///var/run/containerd/containerd.sock imagePullPolicy : IfNotPresent name : node taints : null --- apiServer : timeoutForControlPlane : 4m0s apiVersion : kubeadm.k8s.io/v1beta3 certificatesDir : /etc/kubernetes/pki clusterName : kubernetes controllerManager : {} dns : {} etcd : local : dataDir : /var/lib/etcd imageRepository : k8s.gcr.io kind : ClusterConfiguration kubernetesVersion : 1.24.0 networking : dnsDomain : cluster.local serviceSubnet : 10.96.0.0/12 scheduler : {} \u6a21\u62df\u5b89\u88c5\u548c\u6b63\u5f0f\u5b89\u88c5\u3002 \u901a\u8fc7\u547d\u4ee4 kubeadm init \u8fdb\u884c\u4e3b\u8282\u70b9\u7684\u521d\u59cb\u5316\uff0c\u4e0b\u9762\u662f\u8fd9\u4e2a\u547d\u4ee4\u4e3b\u8981\u53c2\u6570\u7684\u8bf4\u660e\uff0c\u7279\u522b\u662f\u7f51\u7edc\u53c2\u6570\u7684\u4e09\u4e2a\u9009\u62e9\u3002 --pod-network-cidr : \u6307\u5b9apod\u4f7f\u7528\u7684IP\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u6307\u5b9a\u4e86\u8be5\u53c2\u6570\uff0c\u5219Control Plane\u4f1a\u81ea\u52a8\u8bb2\u6307\u5b9a\u7684CIDR\u5206\u914d\u7ed9\u6bcf\u4e2a\u8282\u70b9\u3002 IP\u5730\u5740\u6bb5 10.244.0.0/16 \u662fFlannel\u7f51\u7edc\u7ec4\u4ef6\u9ed8\u8ba4\u7684\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u9700\u8981\u4fee\u6539Flannel\u7684IP\u5730\u5740\u6bb5\uff0c\u9700\u8981\u5728\u8fd9\u91cc\u6307\u5b9a\uff0c\u4e14\u5728\u90e8\u7f72Flannel\u65f6\u4e5f\u8981\u4fdd\u6301\u4e00\u81f4\u7684IP\u6bb5\u3002 --apiserver-bind-port : API\u670d\u52a1\uff08API Server\uff09\u7684\u7aef\u53e3\uff0c\u9ed8\u8ba4\u65f66443\u3002 --service-cidr : \u6307\u5b9a\u670d\u52a1\uff08service\uff09\u7684IP\u5730\u5740\u6bb5\uff0c\u9ed8\u8ba4\u662f 10.96.0.0/12 \u3002 \u63d0\u793a\uff1a \u670d\u52a1VIPs\uff08service VIPs\uff09\uff0c\u4e5f\u79f0\u4f5c\u96c6\u7fa4IP\uff08Cluster IP\uff09\uff0c\u901a\u8fc7\u53c2\u6570 --service-cidr \u6307\u5b9a\u3002 podCIDR\uff0c\u4e5f\u79f0\u4e3aendpoint IP\uff0c\u901a\u8fc7\u53c2\u6570 --pod-network-cidr \u6307\u5b9a\u3002 \u67094\u79cd\u5178\u578b\u7684\u7f51\u7edc\u95ee\u9898\uff1a \u9ad8\u5ea6\u8026\u5408\u7684\u5bb9\u5668\u4e0e\u5bb9\u5668\u4e4b\u95f4\u7684\u901a\u4fe1\uff1a\u8fd9\u53ef\u4ee5\u901a\u8fc7Pod\uff08podCIDR\uff09\u548c\u672c\u5730\u4e3b\u673a\u901a\u4fe1\u6765\u89e3\u51b3\u3002 Pod\u5bf9Pod\u901a\u4fe1\uff08Pod-to-Pod\uff09\uff1a \u4e5f\u88ab\u79f0\u4e3a\u5bb9\u5668\u5bf9\u5bb9\u5668\u901a\u4fe1\uff08container-to-container\uff09\u3002 \u5728Flannel\u7f51\u7edc\u63d2\u4ef6\u4e2d\u7684\u793a\u4f8b\u6d41\u7a0b\u662f\uff1aPod \u2192 veth\u5bf9 \u2192 cni0 \u2192 flannel.1 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 flannel.1 \u2192 cni0 \u2192 veth\u5bf9 \u2192 Pod\u3002 Pod\u5bf9Service\u901a\u4fe1\uff08Pod-to-Service\uff09\uff1a \u6d41\u7a0b: Pod \u2192 \u5185\u6838 \u2192 Service iptables \u2192 Service \u2192 Pod iptables \u2192 Pod\u3002 \u5916\u90e8\u5bf9Service\u901a\u4fe1\uff08External-to-Service\uff09\uff1a \u8d1f\u8f7d\u5747\u8861\u5668: SLB \u2192 NodePort \u2192 Service \u2192 Pod\u3002 kube-proxy \u662f\u5bf9iptables\u8d1f\u8d23\uff0c\u4e0d\u662f\u7f51\u7edc\u6d41\u91cf\uff08traffic\uff09\u3002 kube-proxy \u662fKubernetes\u96c6\u7fa4\u4e2d\u7684\u4e00\u4e2a\u7ec4\u4ef6\uff0c\u8d1f\u8d23\u4e3aService\u63d0\u4f9b\u4ee3\u7406\u670d\u52a1\uff0c\u540c\u65f6\u4e5f\u662fKubernetes\u7f51\u7edc\u6a21\u578b\u4e2d\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\u4e4b\u4e00\u3002 kube-proxy \u4f1a\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u542f\u52a8\u4e00\u4e2a\u4ee3\u7406\u8fdb\u7a0b\uff0c\u901a\u8fc7\u76d1\u542cKubernetes API Server\u7684Service\u548cEndpoint\u7684\u53d8\u5316\u6765\u7ef4\u62a4\u4e00\u4e2a\u672c\u5730\u7684Service\u548cEndpoint\u7684\u7f13\u5b58\u3002\u5f53\u6709\u8bf7\u6c42\u5230\u8fbe\u67d0\u4e2aService\u65f6\uff0c kube-proxy \u4f1a\u6839\u636e\u8be5Service\u7684\u7c7b\u578b\uff08ClusterIP\u3001NodePort\u3001LoadBalancer\u3001ExternalName\uff09\u548c\u7aef\u53e3\u53f7\uff0c\u751f\u6210\u76f8\u5e94\u7684iptables\u89c4\u5219\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u7ed9Service\u6240\u4ee3\u7406\u7684\u540e\u7aefPod\u3002 iptables\u662fLinux\u7cfb\u7edf\u4e2d\u7684\u4e00\u4e2a\u91cd\u8981\u7f51\u7edc\u5de5\u5177\uff0c\u53ef\u4ee5\u8bbe\u7f6eIP\u5305\u7684\u8fc7\u6ee4\u3001\u8f6c\u53d1\u548c\u4fee\u6539\u89c4\u5219\uff0c\u53ef\u4ee5\u5b9e\u73b0\u7f51\u7edc\u5c42\u7684\u9632\u706b\u5899\u3001NAT\u7b49\u529f\u80fd\u3002\u5728Kubernetes\u96c6\u7fa4\u4e2d\uff0c kube-proxy \u901a\u8fc7\u751f\u6210\u548c\u66f4\u65b0iptables\u89c4\u5219\uff0c\u6765\u5b9e\u73b0Service\u548cEndpoint\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u5177\u4f53\u6765\u8bf4\uff0ckube-proxy\u4f1a\u4e3a\u6bcf\u4e2aService\u521b\u5efa\u4e09\u6761iptables\u89c4\u5219\u94fe\uff08nat\u8868\u4e2d\u7684KUBE-SERVICES\u548cKUBE-NODEPORTS\u94fe\uff0c\u4ee5\u53cafilter\u8868\u4e2d\u7684KUBE-SVC-XXXXX\u94fe\uff09\uff0c\u901a\u8fc7\u8fd9\u4e9b\u89c4\u5219\u94fe\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u76f8\u5e94\u7684Pod\u6216\u8005Service\u4e0a\u3002 \u56e0\u6b64\uff0c kube-proxy \u548ciptables\u662f\u7d27\u5bc6\u76f8\u5173\u7684\u4e24\u4e2a\u7ec4\u4ef6\uff0c\u901a\u8fc7iptables\u89c4\u5219\u6765\u5b9e\u73b0Service\u548cPod\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u8fd9\u79cd\u5b9e\u73b0\u65b9\u5f0f\u5177\u6709\u53ef\u6269\u5c55\u6027\u548c\u9ad8\u53ef\u7528\u6027\uff0c\u540c\u65f6\u4e5f\u63d0\u4f9b\u4e86\u4e00\u79cd\u7075\u6d3b\u7684\u7f51\u7edc\u6a21\u578b\uff0c\u53ef\u4ee5\u65b9\u4fbf\u5730\u5b9e\u73b0\u670d\u52a1\u53d1\u73b0\u3001\u8d1f\u8f7d\u5747\u8861\u7b49\u529f\u80fd\u3002 sudo kubeadm init \\ --dry-run \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --kubernetes-version = v1.24.0","title":"kubeadm\u521d\u59cb\u5316"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#kubeconfig","text":"\u7ed9\u5f53\u524d\u5b89\u88c5\u7528\u6237\u914d\u7f6e kubeconfig \u6587\u4ef6\uff08\u5f53\u524d\u4f8b\u5b50\u662f\u7528\u6237 vagrant \uff09\u3002 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Kubernetes \u63d0\u4f9b\u4e86\u4e00\u4e2a\u547d\u4ee4\u884c\u5de5\u5177 kubectl \uff0c\u7528\u4e8e\u4f7f\u7528 Kubernetes API \u4e0e Kubernetes \u96c6\u7fa4\u7684\u63a7\u5236\u5e73\u9762\u8fdb\u884c\u901a\u4fe1\u3002 kubectl \u63a7\u5236 Kubernetes cluster manager \uff08\u96c6\u7fa4\u7ba1\u7406\u5668\uff09\u3002 \u5bf9\u4e8e\u914d\u7f6e\uff0ckubectl \u5728 $HOME/.kube \u76ee\u5f55\u4e2d\u67e5\u627e\u4e00\u4e2a\u540d\u4e3a config \u7684\u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u662f\u7531 kubeadm init \u751f\u6210\u7684\u6587\u4ef6 /etc/kubernetes/admin.conf \u7684\u526f\u672c\u3002 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e KUBECONFIG \u73af\u5883\u53d8\u91cf\u6216\u8bbe\u7f6e --kubeconfig flag \u6807\u5fd7\u6765\u6307\u5b9a\u5176\u4ed6 kubeconfig \u6587\u4ef6\u3002\u5982\u679c KUBECONFIG \u73af\u5883\u53d8\u91cf\u4e0d\u5b58\u5728\uff0ckubectl \u5c06\u4f7f\u7528\u9ed8\u8ba4\u7684 kubeconfig \u6587\u4ef6 $HOME/.kube/config \u3002 kubeconfig \u6587\u4ef6\u4e2d\u7684 context\uff08\u4e0a\u4e0b\u6587\uff09 \u5143\u7d20\u7528\u4e8e\u5c06\u8bbf\u95ee\u53c2\u6570\u5206\u7ec4\u5230\u4e00\u4e2a\u65b9\u4fbf\u7684\u540d\u79f0\u4e0b\u3002\u6bcf\u4e2a\u4e0a\u4e0b\u6587\u90fd\u6709\u4e09\u4e2a\u53c2\u6570\uff1a\u96c6\u7fa4\u3001\u547d\u540d\u7a7a\u95f4\u548c\u7528\u6237\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0ckubectl \u547d\u4ee4\u884c\u5de5\u5177\u4f7f\u7528\u5f53\u524d\u4e0a\u4e0b\u6587\u4e2d\u7684\u53c2\u6570\u4e0e\u96c6\u7fa4\u901a\u4fe1\u3002 \u6587\u4ef6 .kube/config \u7684\u4f8b\u5b50\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : \u8bfb\u53d6\u5f53\u524d\u4e0a\u4e0b\u6587\uff1a kubectl config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin","title":"kubeconfig\u6587\u4ef6"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_6","text":"\u4f7f\u7528 kubeadm token \u6765\u751f\u6210\u52a0\u5165\u96c6\u7fa4\u7684\u4ee4\u724c\uff08token\uff09\u548c\u54c8\u897f\u503c\uff08hash value\uff09\u3002 kubeadm token create --print-join-command \u5728\u6240\u6709\u5de5\u4f5c\u8282\u70b9\u4e0a\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u5c06\u5de5\u4f5c\u8282\u70b9\u52a0\u5165Kubernetes\u96c6\u7fa4\u3002 # kubeadm join :6443 --token --discovery-token-ca-cert-hash \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u68c0\u67e5\u6240\u6709\u8282\u70b9\u7684\u72b6\u6001\u3002 \u5f53\u524d\u6240\u6709\u8282\u70b9\u7684\u72b6\u6001\u90fd\u662f NotReady \u3002\u76ee\u524d\u4e0d\u9700\u8981\u505a\u4ec0\u4e48\uff0c\u540e\u9762\u6211\u4eec\u4f1a\u5b89\u88c5\u76f8\u5173\u7684\u7f51\u7edc\u670d\u52a1\uff08Calico \u6216 Flannel\uff09\uff0c\u5404\u8282\u70b9\u7684\u72b6\u6001\u5c31\u4f1a\u53d8\u6210Ready\u72b6\u6001\u3002","title":"\u914d\u7f6e\u5de5\u4f5c\u8282\u70b9"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#calicoflannel","text":"\u5728\u63a7\u5236\u5e73\u9762Control Plane\u4e0a\u5b89\u88c5Calico\u6216\u8005Flannel\u3002\u5982\u679c\u9700\u8981\u914d\u7f6e\u7f51\u7edc\u7b56\u7565\uff0c\u5219\u9009\u62e9Calico\u3002","title":"\u5b89\u88c5Calico\u6216Flannel"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#flannel","text":"Flannel \u662f\u4e3a Kubernetes \u8bbe\u8ba1\u7684\u4e00\u79cd\u7b80\u5355\u6613\u7528\u7684\u914d\u7f6e\u4e09\u5c42\u7f51\u7edc\u7684\u65b9\u6cd5\u3002 \u90e8\u7f72Flannel\uff1a \u5728 kube-flannel.yml \u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u83b7\u53d6 Flannel \u7684\u9ed8\u8ba4\u7f51\u7edc\u8bbe\u7f6e\uff0c\u5b83\u4e0e\u6211\u4eec\u5728\u4f7f\u7528 kubeadm \u521d\u59cb\u5316\u96c6\u7fa4\u65f6\u6307\u5b9a\u7684\u53c2\u6570 --pod-network-cidr=10.244.0.0/16 \u76f8\u540c\u3002 net - co nf .jso n : | { \"Network\" : \"10.244.0.0/16\" , \"Backend\" : { \"Type\" : \"vxlan\" } } \u521b\u5efaFlannel\u670d\u52a1\u3002 apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml \u8f93\u51fa\u7ed3\u679c\uff1a Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy/psp.flannel.unprivileged created clusterrole.rbac.authorization.k8s.io/flannel created clusterrolebinding.rbac.authorization.k8s.io/flannel created serviceaccount/flannel created configmap/kube-flannel-cfg created daemonset.apps/kube-flannel-ds created","title":"\u5b89\u88c5Flannel"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#calico","text":"\u5b89\u88c5\u6307\u5bfc\u624b\u518c\uff1a End-to-end Calico installation \u3002 \u4e0b\u8f7d\u5e76\u5b89\u88c5Calico\u670d\u52a1\u3002 curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml \u8f93\u51fa\u7ed3\u679c\uff1a configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created \u9a8c\u8bc1Calico\u670d\u52a1\u72b6\u6001\uff1a kubectl get pod -n kube-system | grep calico \u8f93\u51fa\u7ed3\u679c\uff1a calico-kube-controllers-555bc4b957-l8bn2 0 /1 Pending 0 28s calico-node-255pc 0 /1 Init:1/3 0 29s calico-node-7tmnb 0 /1 Init:1/3 0 29s calico-node-w8nvl 0 /1 Init:1/3 0 29s \u68c0\u67e5\u96c6\u7fa4\u7684\u7f51\u7edc\u72b6\u6001\uff1a sudo nerdctl network ls \u8f93\u51fa\u7ed3\u679c\uff1a NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none","title":"\u5b89\u88c5Calico"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_7","text":"\u5728\u4e3b\u8282\u70b9\u4e0a\u6267\u884c\u547d\u4ee4 kubectl cluster-info \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff1a \u63a7\u5236\u5e73\u9762\uff08control plane\uff09\u8fd0\u884c\u5728 https://:6443 CoreDNS\u670d\u52a1\u8fd0\u884c\u5728 https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy kubectl cluster-info \u67e5\u770b\u8282\u70b9\u8fd0\u884c\u72b6\u6001\u3002\u6b64\u65f6\uff0c\u6240\u6709\u8282\u70b9\u90fd\u662f Ready \u7684\u6b63\u5e38\u72b6\u6001\u4e86\u3002 OS Image: Ubuntu 20.04.4 LTS Kernel Version: 5.4.0-122-generic Container Runtime: containerd://1.5.9 kubectl get nodes -owide \u8f93\u51fa\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane 13m v1.24.0 cka002 Ready 8m35s v1.24.0 cka003 Ready 8m26s v1.24.0 \u67e5\u770bPods\u7684\u72b6\u6001\u3002 kubectl get pod -A \u8f93\u51fa\u7ed3\u679c\uff1a NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 7m18s kube-system calico-node-255pc 1/1 Running 0 7m19s kube-system calico-node-7tmnb 1/1 Running 0 7m19s kube-system calico-node-w8nvl 1/1 Running 0 7m19s kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15m kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15m kube-system etcd-cka001 1/1 Running 0 15m kube-system kube-apiserver-cka001 1/1 Running 0 15m kube-system kube-controller-manager-cka001 1/1 Running 0 15m kube-system kube-proxy-dmj2t 1/1 Running 0 15m kube-system kube-proxy-n77zw 1/1 Running 0 11m kube-system kube-proxy-qs6rf 1/1 Running 0 11m kube-system kube-scheduler-cka001 1/1 Running 0 15m","title":"\u68c0\u67e5\u96c6\u7fa4\u72b6\u6001"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_8","text":"","title":"\u66f4\u65b0\u5b89\u88c5"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#bash","text":"\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u914d\u7f6eBash\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 \u53c2\u8003 \u6307\u5bfc \u8bbe\u7f6e kubectl \u81ea\u52a8\u8865\u5168\u529f\u80fdauto-completion \u3002 apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc source ~/.bashrc","title":"Bash\u81ea\u52a8\u8865\u5168"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_9","text":"\u5982\u679c\u6211\u4eec\u4e3a kubectl \u8bbe\u7f6e\u4e00\u4e2a\u522b\u540d\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u4e00\u4e9b\u65b9\u6cd5\u6765\u6269\u5c55 shell \u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u4f7f\u5176\u80fd\u591f\u4e0e\u8be5\u522b\u540d\u4e00\u8d77\u4f7f\u7528\u3002 \u4e00\u79cd\u65b9\u6cd5\u662f\u5728 Bash shell \u914d\u7f6e\u6587\u4ef6\uff08\u5982 .bashrc \u6216 .bash_profile\uff09\u4e2d\u8bbe\u7f6e\u522b\u540d\uff0c\u5e76\u4e3a\u8be5\u522b\u540d\u6307\u5b9a kubectl \u7684\u5b8c\u6574\u8def\u5f84\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a alias k = 'path/to/kubectl' \u7136\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u91cd\u65b0\u52a0\u8f7d .bashrc \u6587\u4ef6\uff1a source ~/.bashrc \u63a5\u4e0b\u6765\uff0c\u53ef\u4ee5\u4f7f\u7528 k \u547d\u4ee4\u6765\u4ee3\u66ff kubectl \u547d\u4ee4\uff0c\u5e76\u5728\u5176\u540e\u9762\u6dfb\u52a0\u76f8\u5e94\u7684\u53c2\u6570\u548c\u9009\u9879\u3002\u5f53\u4f7f\u7528\u81ea\u52a8\u8865\u5168\u529f\u80fd\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u5c06 k \u522b\u540d\u8f6c\u6362\u4e3a kubectl \u7684\u5b8c\u6574\u8def\u5f84\uff0c\u5e76\u5bf9\u5176\u8fdb\u884c\u81ea\u52a8\u8865\u5168\u3002 \u53e6\u4e00\u79cd\u65b9\u6cd5\u662f\u4f7f\u7528 Bash shell \u5185\u7f6e\u7684 complete \u51fd\u6570\u6765\u4e3a\u522b\u540d\u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc \u8fd9\u5c06\u4e3a\u522b\u540d k \u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u5e76\u5c06\u5176\u4e0e kubectl \u7684\u81ea\u52a8\u8865\u5168\u51fd\u6570 __start_kubectl \u5173\u8054\u8d77\u6765\u3002\u8fd9\u6837\uff0c\u5f53\u7528\u6237\u5728 k \u547d\u4ee4\u540e\u8f93\u5165Tab\u952e\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u8c03\u7528 __start_kubectl \u51fd\u6570\uff0c\u5e76\u4e3a\u7528\u6237\u63d0\u4f9b\u76f8\u5e94\u7684\u81ea\u52a8\u8865\u5168\u5efa\u8bae\u3002","title":"\u522b\u540d"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#context","text":"\u67e5\u770b\u5f53\u524d\u7684 context \u5217\u8868\uff1a kubectl config get-contexts \u8fd9\u4e2a\u547d\u4ee4\u4f1a\u5217\u51fa\u6240\u6709\u53ef\u7528\u7684 context \u5217\u8868\uff0c\u5e76\u6807\u8bb0\u51fa\u5f53\u524d\u6b63\u5728\u4f7f\u7528\u7684 context\u3002 \u7c7b\u4f3c\u4e0b\u9762\u7ed3\u679c\uff1a kubernetes-admin@kubernetes \u662fContext\u540d\u3002 kubernetes \u662f\u96c6\u7fa4\u540d\u3002 kubernetes-admin \u662f\u7528\u6237\u540d\u3002 \u5f53\u524d\u4f8b\u5b50\u4e2d\u6ca1\u6709\u6307\u5b9a\u540d\u79f0\u7a7a\u95f4\u3002 CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin \u66f4\u65b0context\u3002\u4f8b\u5982\uff0c\u66f4\u65b0context\u7684\u9ed8\u8ba4\u540d\u79f0\u7a7a\u95f4\u7b49\u3002 # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin \u5728\u4e0d\u540c\u7684context\u4e4b\u95f4\u5207\u6362\u3002 # Usage: kubectl config use-context # Switch to new context kubectl config use-context kubernetes-admin@kubernetes \u53c2\u8003\u8d44\u6599\uff1a kubectl [commandline","title":"\u66f4\u65b0\u9ed8\u8ba4Context"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_10","text":"\u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u64cd\u4f5c\u4f1a\u91cd\u7f6e\u5f53\u524d\u96c6\u7fa4\uff08\u5220\u9664\u96c6\u7fa4\uff09\u3002 \u5220\u9664\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u3002 kubeadm reset \u6e05\u9664 iptables \u4e2d\u5df2\u5b9a\u4e49\u7684\u89c4\u5219\u3002 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u6e05\u9664 IPVS \u4e2d\u5b9a\u4e49\u7684\u89c4\u5219\uff08\u5982\u679c\u4f7f\u7528 IPVS \uff09\u3002 ipvsadm --clear","title":"\u91cd\u7f6e\u96c6\u7fa4"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_11","text":"","title":"\u6392\u9519"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#1","text":"\u62a5\u9519\u4fe1\u606f\uff1a The connection to the server :6443 was refused - did you specify the right host or port? \u89e3\u51b3\u5c1d\u8bd5\uff1a Reference \u68c0\u67e5\u6587\u4ef6kubeconfig\u7684\u5185\u5bb9\u548c\u6587\u4ef6\u8def\u5f84\u662f\u5426\u6b63\u786e\u3002 \u68c0\u67e5\u73af\u5883\u53d8\u91cf\u8bbe\u7f6e\u3002 env | grep -i kub \u68c0\u67e5\u5bb9\u5668\u8fd0\u884c\u72b6\u6001\u3002 sudo systemctl status containerd.service \u68c0\u67e5kubelet\u670d\u52a1\u3002 sudo systemctl status kubelet.service \u68c0\u67e5 6443 \u7aef\u53e3\u76d1\u542c\u72b6\u6001\u3002 netstat -pnlt | grep 6443 \u68c0\u67e5\u9632\u706b\u5899\u72b6\u6001\u3002 sudo systemctl status firewalld.service \u68c0\u67e5kubelet\u65e5\u5fd7\u3002 journalctl -xeu kubelet","title":"\u9519\u8bef1"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#2","text":"\u62a5\u9519\u4fe1\u606f\uff1a \"Container runtime network not ready\" networkReady=\"NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized\" \u5c1d\u8bd5\u65b9\u6cd5\uff1a \u91cd\u542fContainerd\u670d\u52a1\u3002 sudo systemctl restart containerd sudo systemctl status containerd","title":"\u9519\u8bef2"},{"location":"k8s/cka_cn/installation/multiple-local/","text":"CKA\u81ea\u5b66\u7b14\u8bb02:\u591a\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes \u00b6 \u6458\u8981 \u00b6 \u5728\u672c\u5730Windows\u73af\u5883\u4e2d\uff0c\u901a\u8fc7VMWare\u5b89\u88c5\u4e09\u53f0Ubuntu\u865a\u62df\u673a\u3002\u5728Ubuntu\u865a\u62df\u673a\u4e2d\u5b89\u88c5\u57fa\u4e8eContainerd\u7684Kubernetes\u7cfb\u7edf\uff0c\u5e76\u5206\u522b\u914d\u7f6e\u4e00\u4e2a\u4e3b\u8282\u70b9Master\u548c\u4e24\u4e2a\u5de5\u4f5c\u8282\u70b9Worker\u3002 \u672c\u5730\u865a\u62df\u673a\u8bbe\u7f6e \u00b6 VMWare \u8bbe\u7f6e VMnet1: host-only\u6a21\u5f0f, \u7f51\u7edcsubnet: 192.168.150.0/24 VMnet8: NAT\u6a21\u5f0f, \u7f51\u7edcsubnet: 11.0.1.0/24 \u901a\u8fc7VMWare\u521b\u5efa\u5ba2\u6237\u865a\u62df\u673a\u3002 \u5185\u5b58\uff1a4 GB CPU\uff1a1 CPUs with 2 Cores \u64cd\u4f5c\u7cfb\u7edf\uff1aUbuntu Server 22.04 \u7f51\u7edc\uff1aNAT \u63d0\u793a\uff1a \u5f53\u524d\u7ec3\u4e60\u4e2d\uff0cKubernetes\u662f\u57fa\u4e8eContainerd\uff0c\u4e0d\u662fDocker\u3002 Ubuntu\u9884\u914d\u7f6e \u00b6 \u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u4efb\u52a1\uff0c\u9700\u8981\u5728\u6bcf\u53f0\u865a\u62df\u673a\u4e2d\u6267\u884c\u4e00\u6b21\u3002\u4ee5\u4e0b\u7b80\u79f0\u865a\u62df\u673a\u4e3a\u8282\u70b9\u3002 \u5728\u6240\u6709\u8282\u70b9\u4e2d\u521b\u5efa\u7528\u6237 vagrant \u3002 sudo adduser vagrant sudo usermod -g sudo vagrant sudo usermod -a -G root vagrant sudo passwd vagrant \u5728\u6240\u6709\u8282\u70b9\u4e2d\u8bbe\u7f6e\u7528\u6237 root \u7684\u5bc6\u7801\u3002 sudo passwd root \u4fee\u6539ssh\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6\u3002\u5f00\u653e root \u7528\u6237\u901a\u8fc7ssh\u767b\u5f55\uff08\u9ed8\u8ba4\u662f\u7981\u7528\u7684\uff09\u3002 sudo vi /etc/ssh/sshd_config \u628a\u53c2\u6570 PermitRootLogin \u7684\u503c\u4ece prohibit-password \u6539\u4e3a yes \u3002 PermitRootLogin yes # PermitRootLogin prohibit-password \u91cd\u65b0\u542f\u52a8sshd\u670d\u52a1\u3002 sudo systemctl restart sshd \u66f4\u6539\u4e3b\u673a\u540d\uff0c\u8fd9\u91cc\u662f ubu1 . sudo hostnamectl set-hostname ubu1 sudo hostnamectl set-hostname ubu1 --pretty \u9a8c\u8bc1\u4e3b\u673a\u540d\u662f\u5426\u88ab\u6b63\u786e\u4fee\u6539\u4e86\uff0c\u6bd4\u5982\u6539\u4e3a ubu1 \u3002 cat /etc/machine-info \u9a8c\u8bc1\u4e3b\u673a\u540d\u662f\u5426\u88ab\u6b63\u786e\u4fee\u6539\u4e86\uff0c\u6bd4\u5982\u6539\u4e3a ubu1 \u3002 cat /etc/hostname \u9a8c\u8bc1\u4e3b\u673aIP\u5730\u5740 127.0.1.1 \u5df2\u7ecf\u914d\u7f6e\u7ed9\u5f53\u524d\u8282\u70b9\uff0c\u6bd4\u5982 ubu1 \u3002\u540c\u65f6\uff0c\u5728\u6240\u6709\u8282\u70b9\u7684 /etc/hosts \u6587\u4ef6\u4e2d\u6dfb\u52a0\u5176\u4ed6\u8282\u70b9\u7684IP\u548c\u4e3b\u673a\u5bf9\u5e94\u4fe1\u606f\u3002 sudo vi /etc/hosts \u4ee5\u5f53\u524d\u7ec3\u4e60\u4e3a\u4f8b\uff0c\u4fee\u6539\u540e\u7684 /etc/hosts \u6587\u4ef6\u7c7b\u4f3c\u5982\u4e0b\u5185\u5bb9\u3002 127.0.1.1 ubu1 11.0.1.129 ubu1 11.0.1.130 ubu2 11.0.1.131 ubu3 11.0.1.132 ubu4 \u521b\u5efa\u6587\u4ef6 /etc/netplan/00-installer-config.yaml \u3002 sudo vi /etc/netplan/00-installer-config.yaml \u66f4\u65b0\u6b64\u6587\u4ef6\uff0c\u8bbe\u5b9a\u5f53\u524d\u8282\u70b9\u4f7f\u7528\u56fa\u5b9aIP\u5730\u5740\uff0c\u6bd4\u5982\uff0c 11.0.1.129 \u3002 network : ethernets : ens33 : dhcp4 : false addresses : - 11.0.1.129/24 nameservers : addresses : - 11.0.1.2 routes : - to : default via : 11.0.1.2 version : 2 \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u65f6\uff0c\u4f7f\u4e0a\u8ff0\u6539\u52a8\u751f\u6548\u3002\u6ce8\u610f\uff0c\u5f53\u524dssh\u8fde\u63a5\u4f1a\u56e0\u6b64\u800c\u65ad\u5f00\u3002 sudo netplan apply \u5728\u6240\u6709\u8282\u70b9\u7981\u7528\u4ea4\u6362\u5206\u533aswap\u548c\u9632\u706b\u5899firewall\u3002 sudo swapoff -a sudo ufw disable sudo ufw status verbose \u5728\u6240\u6709\u8282\u70b9\u7684\u6587\u4ef6 /etc/fstab \u4e2d\u6ce8\u91ca\u6389\u6d89\u53caswap\u7684\u90a3\u4e00\u884c\uff0c\u4fee\u6539\u540e\u9700\u8981\u91cd\u542f\u5f53\u524d\u8282\u70b9\u3002 sudo vi /etc/fstab \u4fee\u6539\u540e\u7684\u7ed3\u679c\u7c7b\u4f3c\u5982\u4e0b\u3002 /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 \u5728\u6240\u6709\u8282\u70b9\u8bbe\u7f6e\u7edf\u4e00\u7684\u65f6\u533a\u3002 sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo cp /etc/profile /etc/profile.bak echo 'LANG=\"en_US.UTF-8\"' | sudo tee -a /etc/profile source /etc/profile \u6267\u884c\u547d\u4ee4 ll /etc/localtime \u6765\u9a8c\u8bc1\u65f6\u533a\u662f\u5426\u4fee\u6539\u6b63\u786e\u3002 lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai \u5728\u6240\u6709\u8282\u70b9\u4fee\u6539\u5185\u6838\u8bbe\u7f6e\u3002 cat < /etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF \u68c0\u67e5\u5f53\u524d kubeadm \u7684\u7248\u672c\u3002 apt policy kubeadm \u5b89\u88c5 1.24.1-00 \u7248\u672c\u7684 kubeadm . sudo apt-get -y install kubelet = 1 .24.1-00 kubeadm = 1 .24.1-00 kubectl = 1 .24.1-00 --allow-downgrades \u914d\u7f6e\u4e3b\u8282\u70b9 \u00b6 kubeadm\u521d\u59cb\u5316 \u00b6 \u5728\u627f\u62c5\u4e3b\u8282\u70b9\u7684\u865a\u62df\u673a\u91cc\u914d\u7f6e\u63a7\u5236\u5e73\u9762\uff08Control Plane\uff09\u3002 \u68c0\u67e5 kubeadm \u5f53\u524d\u9ed8\u8ba4\u914d\u7f6e\u53c2\u6570\u3002 kubeadm config print init-defaults \u7c7b\u4f3c\u7ed3\u679c\u5982\u4e0b\u3002\u4fdd\u5b58\u9ed8\u8ba4\u914d\u7f6e\u7684\u7ed3\u679c\uff0c\u540e\u7eed\u4f1a\u4f5c\u4e3a\u53c2\u8003\u3002 apiVersion : kubeadm.k8s.io/v1beta3 bootstrapTokens : - groups : - system:bootstrappers:kubeadm:default-node-token token : abcdef.0123456789abcdef ttl : 24h0m0s usages : - signing - authentication kind : InitConfiguration localAPIEndpoint : advertiseAddress : 1.2.3.4 bindPort : 6443 nodeRegistration : criSocket : unix:///var/run/containerd/containerd.sock imagePullPolicy : IfNotPresent name : node taints : null --- apiServer : timeoutForControlPlane : 4m0s apiVersion : kubeadm.k8s.io/v1beta3 certificatesDir : /etc/kubernetes/pki clusterName : kubernetes controllerManager : {} dns : {} etcd : local : dataDir : /var/lib/etcd imageRepository : k8s.gcr.io kind : ClusterConfiguration kubernetesVersion : 1.24.0 networking : dnsDomain : cluster.local serviceSubnet : 10.96.0.0/12 scheduler : {} \u6a21\u62df\u5b89\u88c5\u548c\u6b63\u5f0f\u5b89\u88c5\u3002 \u901a\u8fc7\u547d\u4ee4 kubeadm init \u8fdb\u884c\u4e3b\u8282\u70b9\u7684\u521d\u59cb\u5316\uff0c\u4e0b\u9762\u662f\u8fd9\u4e2a\u547d\u4ee4\u4e3b\u8981\u53c2\u6570\u7684\u8bf4\u660e\uff0c\u7279\u522b\u662f\u7f51\u7edc\u53c2\u6570\u7684\u4e09\u4e2a\u9009\u62e9\u3002 --pod-network-cidr : \u6307\u5b9apod\u4f7f\u7528\u7684IP\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u6307\u5b9a\u4e86\u8be5\u53c2\u6570\uff0c\u5219Control Plane\u4f1a\u81ea\u52a8\u8bb2\u6307\u5b9a\u7684CIDR\u5206\u914d\u7ed9\u6bcf\u4e2a\u8282\u70b9\u3002 IP\u5730\u5740\u6bb5 10.244.0.0/16 \u662fFlannel\u7f51\u7edc\u7ec4\u4ef6\u9ed8\u8ba4\u7684\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u9700\u8981\u4fee\u6539Flannel\u7684IP\u5730\u5740\u6bb5\uff0c\u9700\u8981\u5728\u8fd9\u91cc\u6307\u5b9a\uff0c\u4e14\u5728\u90e8\u7f72Flannel\u65f6\u4e5f\u8981\u4fdd\u6301\u4e00\u81f4\u7684IP\u6bb5\u3002 --apiserver-bind-port : API\u670d\u52a1\uff08API Server\uff09\u7684\u7aef\u53e3\uff0c\u9ed8\u8ba4\u65f66443\u3002 --service-cidr : \u6307\u5b9a\u670d\u52a1\uff08service\uff09\u7684IP\u5730\u5740\u6bb5\uff0c\u9ed8\u8ba4\u662f 10.96.0.0/12 \u3002 \u63d0\u793a\uff1a \u670d\u52a1VIPs\uff08service VIPs\uff09\uff0c\u4e5f\u79f0\u4f5c\u96c6\u7fa4IP\uff08Cluster IP\uff09\uff0c\u901a\u8fc7\u53c2\u6570 --service-cidr \u6307\u5b9a\u3002 podCIDR\uff0c\u4e5f\u79f0\u4e3aendpoint IP\uff0c\u901a\u8fc7\u53c2\u6570 --pod-network-cidr \u6307\u5b9a\u3002 \u67094\u79cd\u5178\u578b\u7684\u7f51\u7edc\u95ee\u9898\uff1a \u9ad8\u5ea6\u8026\u5408\u7684\u5bb9\u5668\u4e0e\u5bb9\u5668\u4e4b\u95f4\u7684\u901a\u4fe1\uff1a\u8fd9\u53ef\u4ee5\u901a\u8fc7Pod\uff08podCIDR\uff09\u548c\u672c\u5730\u4e3b\u673a\u901a\u4fe1\u6765\u89e3\u51b3\u3002 Pod\u5bf9Pod\u901a\u4fe1\uff08Pod-to-Pod\uff09\uff1a \u4e5f\u88ab\u79f0\u4e3a\u5bb9\u5668\u5bf9\u5bb9\u5668\u901a\u4fe1\uff08container-to-container\uff09\u3002 \u5728Flannel\u7f51\u7edc\u63d2\u4ef6\u4e2d\u7684\u793a\u4f8b\u6d41\u7a0b\u662f\uff1aPod \u2192 veth\u5bf9 \u2192 cni0 \u2192 flannel.1 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 flannel.1 \u2192 cni0 \u2192 veth\u5bf9 \u2192 Pod\u3002 Pod\u5bf9Service\u901a\u4fe1\uff08Pod-to-Service\uff09\uff1a \u6d41\u7a0b: Pod \u2192 \u5185\u6838 \u2192 Service iptables \u2192 Service \u2192 Pod iptables \u2192 Pod\u3002 \u5916\u90e8\u5bf9Service\u901a\u4fe1\uff08External-to-Service\uff09\uff1a \u8d1f\u8f7d\u5747\u8861\u5668: SLB \u2192 NodePort \u2192 Service \u2192 Pod\u3002 kube-proxy \u662f\u5bf9iptables\u8d1f\u8d23\uff0c\u4e0d\u662f\u7f51\u7edc\u6d41\u91cf\uff08traffic\uff09\u3002 kube-proxy \u662fKubernetes\u96c6\u7fa4\u4e2d\u7684\u4e00\u4e2a\u7ec4\u4ef6\uff0c\u8d1f\u8d23\u4e3aService\u63d0\u4f9b\u4ee3\u7406\u670d\u52a1\uff0c\u540c\u65f6\u4e5f\u662fKubernetes\u7f51\u7edc\u6a21\u578b\u4e2d\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\u4e4b\u4e00\u3002 kube-proxy \u4f1a\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u542f\u52a8\u4e00\u4e2a\u4ee3\u7406\u8fdb\u7a0b\uff0c\u901a\u8fc7\u76d1\u542cKubernetes API Server\u7684Service\u548cEndpoint\u7684\u53d8\u5316\u6765\u7ef4\u62a4\u4e00\u4e2a\u672c\u5730\u7684Service\u548cEndpoint\u7684\u7f13\u5b58\u3002\u5f53\u6709\u8bf7\u6c42\u5230\u8fbe\u67d0\u4e2aService\u65f6\uff0c kube-proxy \u4f1a\u6839\u636e\u8be5Service\u7684\u7c7b\u578b\uff08ClusterIP\u3001NodePort\u3001LoadBalancer\u3001ExternalName\uff09\u548c\u7aef\u53e3\u53f7\uff0c\u751f\u6210\u76f8\u5e94\u7684iptables\u89c4\u5219\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u7ed9Service\u6240\u4ee3\u7406\u7684\u540e\u7aefPod\u3002 iptables\u662fLinux\u7cfb\u7edf\u4e2d\u7684\u4e00\u4e2a\u91cd\u8981\u7f51\u7edc\u5de5\u5177\uff0c\u53ef\u4ee5\u8bbe\u7f6eIP\u5305\u7684\u8fc7\u6ee4\u3001\u8f6c\u53d1\u548c\u4fee\u6539\u89c4\u5219\uff0c\u53ef\u4ee5\u5b9e\u73b0\u7f51\u7edc\u5c42\u7684\u9632\u706b\u5899\u3001NAT\u7b49\u529f\u80fd\u3002\u5728Kubernetes\u96c6\u7fa4\u4e2d\uff0c kube-proxy \u901a\u8fc7\u751f\u6210\u548c\u66f4\u65b0iptables\u89c4\u5219\uff0c\u6765\u5b9e\u73b0Service\u548cEndpoint\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u5177\u4f53\u6765\u8bf4\uff0ckube-proxy\u4f1a\u4e3a\u6bcf\u4e2aService\u521b\u5efa\u4e09\u6761iptables\u89c4\u5219\u94fe\uff08nat\u8868\u4e2d\u7684KUBE-SERVICES\u548cKUBE-NODEPORTS\u94fe\uff0c\u4ee5\u53cafilter\u8868\u4e2d\u7684KUBE-SVC-XXXXX\u94fe\uff09\uff0c\u901a\u8fc7\u8fd9\u4e9b\u89c4\u5219\u94fe\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u76f8\u5e94\u7684Pod\u6216\u8005Service\u4e0a\u3002 \u56e0\u6b64\uff0c kube-proxy \u548ciptables\u662f\u7d27\u5bc6\u76f8\u5173\u7684\u4e24\u4e2a\u7ec4\u4ef6\uff0c\u901a\u8fc7iptables\u89c4\u5219\u6765\u5b9e\u73b0Service\u548cPod\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u8fd9\u79cd\u5b9e\u73b0\u65b9\u5f0f\u5177\u6709\u53ef\u6269\u5c55\u6027\u548c\u9ad8\u53ef\u7528\u6027\uff0c\u540c\u65f6\u4e5f\u63d0\u4f9b\u4e86\u4e00\u79cd\u7075\u6d3b\u7684\u7f51\u7edc\u6a21\u578b\uff0c\u53ef\u4ee5\u65b9\u4fbf\u5730\u5b9e\u73b0\u670d\u52a1\u53d1\u73b0\u3001\u8d1f\u8f7d\u5747\u8861\u7b49\u529f\u80fd\u3002 sudo kubeadm init \\ --dry-run \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr = 192 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr = 192 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 kubeconfig\u6587\u4ef6 \u00b6 \u7ed9\u5f53\u524d\u5b89\u88c5\u7528\u6237\u914d\u7f6e kubeconfig \u6587\u4ef6\uff08\u5f53\u524d\u4f8b\u5b50\u662f\u7528\u6237 vagrant \uff09\u3002 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Kubernetes \u63d0\u4f9b\u4e86\u4e00\u4e2a\u547d\u4ee4\u884c\u5de5\u5177 kubectl \uff0c\u7528\u4e8e\u4f7f\u7528 Kubernetes API \u4e0e Kubernetes \u96c6\u7fa4\u7684\u63a7\u5236\u5e73\u9762\u8fdb\u884c\u901a\u4fe1\u3002 kubectl \u63a7\u5236 Kubernetes cluster manager \uff08\u96c6\u7fa4\u7ba1\u7406\u5668\uff09\u3002 \u5bf9\u4e8e\u914d\u7f6e\uff0ckubectl \u5728 $HOME/.kube \u76ee\u5f55\u4e2d\u67e5\u627e\u4e00\u4e2a\u540d\u4e3a config \u7684\u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u662f\u7531 kubeadm init \u751f\u6210\u7684\u6587\u4ef6 /etc/kubernetes/admin.conf \u7684\u526f\u672c\u3002 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e KUBECONFIG \u73af\u5883\u53d8\u91cf\u6216\u8bbe\u7f6e --kubeconfig flag \u6807\u5fd7\u6765\u6307\u5b9a\u5176\u4ed6 kubeconfig \u6587\u4ef6\u3002\u5982\u679c KUBECONFIG \u73af\u5883\u53d8\u91cf\u4e0d\u5b58\u5728\uff0ckubectl \u5c06\u4f7f\u7528\u9ed8\u8ba4\u7684 kubeconfig \u6587\u4ef6 $HOME/.kube/config \u3002 kubeconfig \u6587\u4ef6\u4e2d\u7684 context\uff08\u4e0a\u4e0b\u6587\uff09 \u5143\u7d20\u7528\u4e8e\u5c06\u8bbf\u95ee\u53c2\u6570\u5206\u7ec4\u5230\u4e00\u4e2a\u65b9\u4fbf\u7684\u540d\u79f0\u4e0b\u3002\u6bcf\u4e2a\u4e0a\u4e0b\u6587\u90fd\u6709\u4e09\u4e2a\u53c2\u6570\uff1a\u96c6\u7fa4\u3001\u547d\u540d\u7a7a\u95f4\u548c\u7528\u6237\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0ckubectl \u547d\u4ee4\u884c\u5de5\u5177\u4f7f\u7528\u5f53\u524d\u4e0a\u4e0b\u6587\u4e2d\u7684\u53c2\u6570\u4e0e\u96c6\u7fa4\u901a\u4fe1\u3002 \u6587\u4ef6 .kube/config \u7684\u4f8b\u5b50\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : \u8bfb\u53d6\u5f53\u524d\u4e0a\u4e0b\u6587\uff1a kubectl config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin \u5b89\u88c5Calico \u00b6 \u53c2\u8003\u5b89\u88c5\u6307\u5bfc End-to-end Calico installation \u3002 \u5feb\u901f\u5b89\u88c5\u624b\u518c QuickStart \u5b89\u88c5 Calico\uff1a kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/tigera-operator.yaml \u8fd0\u884c\u7ed3\u679c\uff1a namespace/tigera-operator created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/apiservers.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/imagesets.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/installations.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/tigerastatuses.operator.tigera.io created serviceaccount/tigera-operator created clusterrole.rbac.authorization.k8s.io/tigera-operator created clusterrolebinding.rbac.authorization.k8s.io/tigera-operator created deployment.apps/tigera-operator created kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/calicoctl.yaml \u8fd0\u884c\u7ed3\u679c\uff1a serviceaccount/calicoctl created pod/calicoctl created clusterrole.rbac.authorization.k8s.io/calicoctl created clusterrolebinding.rbac.authorization.k8s.io/calicoctl created \u9a8c\u8bc1Calico\u7684\u72b6\u6001\u3002Calico\u7684\u521d\u59cb\u5316\u8fc7\u7a0b\u53ef\u80fd\u9700\u8981\u51e0\u5206\u949f\u65f6\u95f4\u5b8c\u6210\u3002 kubectl get pod -n kube-system | grep calico \u8fd0\u884c\u7ed3\u679c\uff1a calico-kube-controllers-555bc4b957-l8bn2 0/1 Pending 0 28s calico-node-255pc 0/1 Init:1/3 0 29s calico-node-7tmnb 0/1 Init:1/3 0 29s calico-node-w8nvl 0/1 Init:1/3 0 29s \u9a8c\u8bc1\u7f51\u7edc\u72b6\u6001\u3002 sudo nerdctl network ls \u8fd0\u884c\u7ed3\u679c\uff1a NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 17f29b073143 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none \u914d\u7f6e\u5de5\u4f5c\u8282\u70b9 \u00b6 \u4f7f\u7528 kubeadm token \u6765\u751f\u6210\u52a0\u5165\u96c6\u7fa4\u7684\u4ee4\u724c\uff08token\uff09\u548c\u54c8\u897f\u503c\uff08hash value\uff09\u3002 kubeadm token create --print-join-command \u547d\u4ee4\u7528\u6cd5\uff1a sudo kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> \u8fd0\u884c\u7ed3\u679c\uff1a [preflight] Running pre-flight checks [WARNING SystemVerification]: missing optional cgroups: blkio [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [kubelet-start] Writing kubelet configuration to file \"/var/lib/kubelet/config.yaml\" [kubelet-start] Writing kubelet environment file with flags to file \"/var/lib/kubelet/kubeadm-flags.env\" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster. \u68c0\u67e5\u96c6\u7fa4\u72b6\u6001 \u00b6 \u67e5\u770b Kubernetes \u96c6\u7fa4\u7684\u4fe1\u606f\uff0c\u5305\u62ec\u96c6\u7fa4 API Server \u7684\u5730\u5740\u3001Kubernetes DNS \u670d\u52a1\u7684\u5730\u5740\u7b49\u3002 kubectl cluster-info \u8fd0\u884c\u7ed3\u679c\uff1a bKubernetes control plane is running at https://11.0.1.129:6443 CoreDNS is running at https://11.0.1.129:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. \u5217\u51fa\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u5305\u62ec\u8282\u70b9\u540d\u79f0\u3001\u8282\u70b9 IP\u3001\u8282\u70b9\u6807\u7b7e\u3001\u8282\u70b9\u72b6\u6001\u7b49\u3002 kubectl get nodes -owide \u5217\u51fa Kubernetes \u96c6\u7fa4\u4e2d\u6240\u6709 Namespace \u4e0b\u7684 Pod\u3002 kubectl get pod -A \u66f4\u65b0\u5b89\u88c5 \u00b6 Bash\u81ea\u52a8\u8865\u5168 \u00b6 \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u914d\u7f6eBash\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 \u53c2\u8003 \u6307\u5bfc \u8bbe\u7f6e kubectl \u81ea\u52a8\u8865\u5168\u529f\u80fdauto-completion \u3002 apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc source ~/.bashrc \u522b\u540d \u00b6 \u5982\u679c\u6211\u4eec\u4e3a kubectl \u8bbe\u7f6e\u4e00\u4e2a\u522b\u540d\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u4e00\u4e9b\u65b9\u6cd5\u6765\u6269\u5c55 shell \u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u4f7f\u5176\u80fd\u591f\u4e0e\u8be5\u522b\u540d\u4e00\u8d77\u4f7f\u7528\u3002 \u4e00\u79cd\u65b9\u6cd5\u662f\u5728 Bash shell \u914d\u7f6e\u6587\u4ef6\uff08\u5982 .bashrc \u6216 .bash_profile\uff09\u4e2d\u8bbe\u7f6e\u522b\u540d\uff0c\u5e76\u4e3a\u8be5\u522b\u540d\u6307\u5b9a kubectl \u7684\u5b8c\u6574\u8def\u5f84\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a alias k = 'path/to/kubectl' \u7136\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u91cd\u65b0\u52a0\u8f7d .bashrc \u6587\u4ef6\uff1a source ~/.bashrc \u63a5\u4e0b\u6765\uff0c\u53ef\u4ee5\u4f7f\u7528 k \u547d\u4ee4\u6765\u4ee3\u66ff kubectl \u547d\u4ee4\uff0c\u5e76\u5728\u5176\u540e\u9762\u6dfb\u52a0\u76f8\u5e94\u7684\u53c2\u6570\u548c\u9009\u9879\u3002\u5f53\u4f7f\u7528\u81ea\u52a8\u8865\u5168\u529f\u80fd\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u5c06 k \u522b\u540d\u8f6c\u6362\u4e3a kubectl \u7684\u5b8c\u6574\u8def\u5f84\uff0c\u5e76\u5bf9\u5176\u8fdb\u884c\u81ea\u52a8\u8865\u5168\u3002 \u53e6\u4e00\u79cd\u65b9\u6cd5\u662f\u4f7f\u7528 Bash shell \u5185\u7f6e\u7684 complete \u51fd\u6570\u6765\u4e3a\u522b\u540d\u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc \u8fd9\u5c06\u4e3a\u522b\u540d k \u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u5e76\u5c06\u5176\u4e0e kubectl \u7684\u81ea\u52a8\u8865\u5168\u51fd\u6570 __start_kubectl \u5173\u8054\u8d77\u6765\u3002\u8fd9\u6837\uff0c\u5f53\u7528\u6237\u5728 k \u547d\u4ee4\u540e\u8f93\u5165Tab\u952e\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u8c03\u7528 __start_kubectl \u51fd\u6570\uff0c\u5e76\u4e3a\u7528\u6237\u63d0\u4f9b\u76f8\u5e94\u7684\u81ea\u52a8\u8865\u5168\u5efa\u8bae\u3002 \u66f4\u65b0\u9ed8\u8ba4Context \u00b6 \u67e5\u770b\u5f53\u524d\u7684 context \u5217\u8868\uff1a kubectl config get-contexts \u8fd9\u4e2a\u547d\u4ee4\u4f1a\u5217\u51fa\u6240\u6709\u53ef\u7528\u7684 context \u5217\u8868\uff0c\u5e76\u6807\u8bb0\u51fa\u5f53\u524d\u6b63\u5728\u4f7f\u7528\u7684 context\u3002 \u7c7b\u4f3c\u4e0b\u9762\u7ed3\u679c\uff1a kubernetes-admin@kubernetes \u662fContext\u540d\u3002 kubernetes \u662f\u96c6\u7fa4\u540d\u3002 kubernetes-admin \u662f\u7528\u6237\u540d\u3002 \u5f53\u524d\u4f8b\u5b50\u4e2d\u6ca1\u6709\u6307\u5b9a\u540d\u79f0\u7a7a\u95f4\u3002 CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin \u66f4\u65b0context\u3002\u4f8b\u5982\uff0c\u66f4\u65b0context\u7684\u9ed8\u8ba4\u540d\u79f0\u7a7a\u95f4\u7b49\u3002 # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin \u5728\u4e0d\u540c\u7684context\u4e4b\u95f4\u5207\u6362\u3002 # Usage: kubectl config use-context # Switch to new context kubectl config use-context kubernetes-admin@kubernetes \u53c2\u8003\u8d44\u6599\uff1a * kubectl * commandline \u5b89\u88c5Helm \u00b6 Helm \u662f Kubernetes \u7684\u5305\u7ba1\u7406\u5de5\u5177\uff0c\u5b83\u4e0d\u968f Kubernetes \u4e00\u8d77\u63d0\u4f9b\u3002 Helm \u6709\u4e09\u4e2a\u6838\u5fc3\u6982\u5ff5\uff1a Chart\uff08\u56fe\u8868\uff09\u662f Helm \u7684\u8f6f\u4ef6\u5305\uff0c\u5b83\u5305\u542b\u4e86\u5728 Kubernetes \u96c6\u7fa4\u4e2d\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u3001\u5de5\u5177\u6216\u670d\u52a1\u6240\u9700\u7684\u6240\u6709\u8d44\u6e90\u5b9a\u4e49\u3002\u53ef\u4ee5\u5c06\u5176\u89c6\u4e3a Kubernetes \u7684 Homebrew \u516c\u5f0f\u3001Apt dpkg \u6216 Yum RPM \u6587\u4ef6\u7b49\u7b49\u3002 Repository\uff08\u4ed3\u5e93\uff09\u662f\u56fe\u8868\u53ef\u4ee5\u88ab\u6536\u96c6\u548c\u5171\u4eab\u7684\u5730\u65b9\uff0c\u7c7b\u4f3c\u4e8e Perl \u7684 CPAN \u5b58\u50a8\u5e93\u6216 Fedora \u7684\u8f6f\u4ef6\u5305\u6570\u636e\u5e93\uff0c\u4f46\u7528\u4e8e Kubernetes \u8f6f\u4ef6\u5305\u3002 Release\uff08\u53d1\u5e03\uff09\u662f\u5728 Kubernetes \u96c6\u7fa4\u4e2d\u8fd0\u884c\u7684\u56fe\u8868\u5b9e\u4f8b\u3002\u4e00\u4e2a\u56fe\u8868\u901a\u5e38\u53ef\u4ee5\u5728\u540c\u4e00\u96c6\u7fa4\u4e2d\u5b89\u88c5\u591a\u6b21\uff0c\u5e76\u4e14\u6bcf\u6b21\u5b89\u88c5\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u53d1\u5e03\u3002\u4ee5 MySQL \u56fe\u8868\u4e3a\u4f8b\uff0c\u5982\u679c\u60f3\u8981\u5728\u96c6\u7fa4\u4e2d\u8fd0\u884c\u4e24\u4e2a\u6570\u636e\u5e93\uff0c\u5219\u53ef\u4ee5\u5b89\u88c5\u8be5\u56fe\u8868\u4e24\u6b21\uff0c\u6bcf\u6b21\u5b89\u88c5\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u53d1\u5e03\uff0c\u6bcf\u4e2a\u53d1\u5e03\u90fd\u6709\u81ea\u5df1\u7684\u53d1\u5e03\u540d\u79f0\u3002 \u53c2\u8003\u6587\u6863\uff1a installation guide binary release source code . Helm\u5ba2\u6237\u7aef\u5b89\u88c5\uff1a curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh \u8fd0\u884c\u7ed3\u679c\uff1a Downloading https://get.helm.sh/helm-v3.9.1-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm \u63d0\u793a\uff1a * helm init \u5728Helm 3\u4e2d\u5df2\u53d6\u6d88\uff0c\u4e14Tiller\u4e5f\u4e00\u540c\u53d6\u6d88\u3002\u4eca\u540e\u5728\u96c6\u7fa4\u4e2d\u4f7f\u7528Helm\u65f6\u4e0d\u518d\u9700\u8981\u5b89\u88c5Tiller\u3002 * helm search \u53ef\u4ee5\u7528\u6765\u641c\u7d22\u4e24\u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u8d44\u6e90\uff1a * helm search hub \u5728 Artifact Hub \u4e2d\u641c\u7d22\uff0c\u8fd9\u4e2ahub\u91cc\u5217\u51fa\u6765\u81ea\u6570\u5341\u4e2a\u4e0d\u540c\u4ed3\u5e93\u7684 Helm Chart\u3002 * helm search repo \u547d\u4ee4\u7528\u4e8e\u641c\u7d22\u5df2\u6dfb\u52a0\u5230\u672c\u5730 Helm \u5ba2\u6237\u7aef\u7684\u4ed3\u5e93\uff08\u4f7f\u7528 helm repo add \u547d\u4ee4\uff09\u3002\u6b64\u641c\u7d22\u662f\u5728\u672c\u5730\u6570\u636e\u4e0a\u8fdb\u884c\u7684\uff0c\u4e0d\u9700\u8981\u516c\u5171\u7f51\u7edc\u8fde\u63a5\u3002 \u53c2\u8003\u8d44\u6599\uff1a Helming development \u91cd\u7f6e\u96c6\u7fa4 \u00b6 \u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u64cd\u4f5c\u4f1a\u91cd\u7f6e\u5f53\u524d\u96c6\u7fa4\uff08\u5220\u9664\u96c6\u7fa4\uff09\u3002 \u5220\u9664\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u3002 kubeadm reset \u6e05\u9664 iptables \u4e2d\u5df2\u5b9a\u4e49\u7684\u89c4\u5219\u3002 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u6e05\u9664 IPVS \u4e2d\u5b9a\u4e49\u7684\u89c4\u5219\uff08\u5982\u679c\u4f7f\u7528 IPVS \uff09\u3002 ipvsadm --clear","title":"\u591a\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/multiple-local/#cka2kubernetes","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb02:\u591a\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/multiple-local/#_1","text":"\u5728\u672c\u5730Windows\u73af\u5883\u4e2d\uff0c\u901a\u8fc7VMWare\u5b89\u88c5\u4e09\u53f0Ubuntu\u865a\u62df\u673a\u3002\u5728Ubuntu\u865a\u62df\u673a\u4e2d\u5b89\u88c5\u57fa\u4e8eContainerd\u7684Kubernetes\u7cfb\u7edf\uff0c\u5e76\u5206\u522b\u914d\u7f6e\u4e00\u4e2a\u4e3b\u8282\u70b9Master\u548c\u4e24\u4e2a\u5de5\u4f5c\u8282\u70b9Worker\u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/installation/multiple-local/#_2","text":"VMWare \u8bbe\u7f6e VMnet1: host-only\u6a21\u5f0f, \u7f51\u7edcsubnet: 192.168.150.0/24 VMnet8: NAT\u6a21\u5f0f, \u7f51\u7edcsubnet: 11.0.1.0/24 \u901a\u8fc7VMWare\u521b\u5efa\u5ba2\u6237\u865a\u62df\u673a\u3002 \u5185\u5b58\uff1a4 GB CPU\uff1a1 CPUs with 2 Cores \u64cd\u4f5c\u7cfb\u7edf\uff1aUbuntu Server 22.04 \u7f51\u7edc\uff1aNAT \u63d0\u793a\uff1a \u5f53\u524d\u7ec3\u4e60\u4e2d\uff0cKubernetes\u662f\u57fa\u4e8eContainerd\uff0c\u4e0d\u662fDocker\u3002","title":"\u672c\u5730\u865a\u62df\u673a\u8bbe\u7f6e"},{"location":"k8s/cka_cn/installation/multiple-local/#ubuntu","text":"\u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u4efb\u52a1\uff0c\u9700\u8981\u5728\u6bcf\u53f0\u865a\u62df\u673a\u4e2d\u6267\u884c\u4e00\u6b21\u3002\u4ee5\u4e0b\u7b80\u79f0\u865a\u62df\u673a\u4e3a\u8282\u70b9\u3002 \u5728\u6240\u6709\u8282\u70b9\u4e2d\u521b\u5efa\u7528\u6237 vagrant \u3002 sudo adduser vagrant sudo usermod -g sudo vagrant sudo usermod -a -G root vagrant sudo passwd vagrant \u5728\u6240\u6709\u8282\u70b9\u4e2d\u8bbe\u7f6e\u7528\u6237 root \u7684\u5bc6\u7801\u3002 sudo passwd root \u4fee\u6539ssh\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6\u3002\u5f00\u653e root \u7528\u6237\u901a\u8fc7ssh\u767b\u5f55\uff08\u9ed8\u8ba4\u662f\u7981\u7528\u7684\uff09\u3002 sudo vi /etc/ssh/sshd_config \u628a\u53c2\u6570 PermitRootLogin \u7684\u503c\u4ece prohibit-password \u6539\u4e3a yes \u3002 PermitRootLogin yes # PermitRootLogin prohibit-password \u91cd\u65b0\u542f\u52a8sshd\u670d\u52a1\u3002 sudo systemctl restart sshd \u66f4\u6539\u4e3b\u673a\u540d\uff0c\u8fd9\u91cc\u662f ubu1 . sudo hostnamectl set-hostname ubu1 sudo hostnamectl set-hostname ubu1 --pretty \u9a8c\u8bc1\u4e3b\u673a\u540d\u662f\u5426\u88ab\u6b63\u786e\u4fee\u6539\u4e86\uff0c\u6bd4\u5982\u6539\u4e3a ubu1 \u3002 cat /etc/machine-info \u9a8c\u8bc1\u4e3b\u673a\u540d\u662f\u5426\u88ab\u6b63\u786e\u4fee\u6539\u4e86\uff0c\u6bd4\u5982\u6539\u4e3a ubu1 \u3002 cat /etc/hostname \u9a8c\u8bc1\u4e3b\u673aIP\u5730\u5740 127.0.1.1 \u5df2\u7ecf\u914d\u7f6e\u7ed9\u5f53\u524d\u8282\u70b9\uff0c\u6bd4\u5982 ubu1 \u3002\u540c\u65f6\uff0c\u5728\u6240\u6709\u8282\u70b9\u7684 /etc/hosts \u6587\u4ef6\u4e2d\u6dfb\u52a0\u5176\u4ed6\u8282\u70b9\u7684IP\u548c\u4e3b\u673a\u5bf9\u5e94\u4fe1\u606f\u3002 sudo vi /etc/hosts \u4ee5\u5f53\u524d\u7ec3\u4e60\u4e3a\u4f8b\uff0c\u4fee\u6539\u540e\u7684 /etc/hosts \u6587\u4ef6\u7c7b\u4f3c\u5982\u4e0b\u5185\u5bb9\u3002 127.0.1.1 ubu1 11.0.1.129 ubu1 11.0.1.130 ubu2 11.0.1.131 ubu3 11.0.1.132 ubu4 \u521b\u5efa\u6587\u4ef6 /etc/netplan/00-installer-config.yaml \u3002 sudo vi /etc/netplan/00-installer-config.yaml \u66f4\u65b0\u6b64\u6587\u4ef6\uff0c\u8bbe\u5b9a\u5f53\u524d\u8282\u70b9\u4f7f\u7528\u56fa\u5b9aIP\u5730\u5740\uff0c\u6bd4\u5982\uff0c 11.0.1.129 \u3002 network : ethernets : ens33 : dhcp4 : false addresses : - 11.0.1.129/24 nameservers : addresses : - 11.0.1.2 routes : - to : default via : 11.0.1.2 version : 2 \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u65f6\uff0c\u4f7f\u4e0a\u8ff0\u6539\u52a8\u751f\u6548\u3002\u6ce8\u610f\uff0c\u5f53\u524dssh\u8fde\u63a5\u4f1a\u56e0\u6b64\u800c\u65ad\u5f00\u3002 sudo netplan apply \u5728\u6240\u6709\u8282\u70b9\u7981\u7528\u4ea4\u6362\u5206\u533aswap\u548c\u9632\u706b\u5899firewall\u3002 sudo swapoff -a sudo ufw disable sudo ufw status verbose \u5728\u6240\u6709\u8282\u70b9\u7684\u6587\u4ef6 /etc/fstab \u4e2d\u6ce8\u91ca\u6389\u6d89\u53caswap\u7684\u90a3\u4e00\u884c\uff0c\u4fee\u6539\u540e\u9700\u8981\u91cd\u542f\u5f53\u524d\u8282\u70b9\u3002 sudo vi /etc/fstab \u4fee\u6539\u540e\u7684\u7ed3\u679c\u7c7b\u4f3c\u5982\u4e0b\u3002 /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 \u5728\u6240\u6709\u8282\u70b9\u8bbe\u7f6e\u7edf\u4e00\u7684\u65f6\u533a\u3002 sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo cp /etc/profile /etc/profile.bak echo 'LANG=\"en_US.UTF-8\"' | sudo tee -a /etc/profile source /etc/profile \u6267\u884c\u547d\u4ee4 ll /etc/localtime \u6765\u9a8c\u8bc1\u65f6\u533a\u662f\u5426\u4fee\u6539\u6b63\u786e\u3002 lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai \u5728\u6240\u6709\u8282\u70b9\u4fee\u6539\u5185\u6838\u8bbe\u7f6e\u3002 cat < /etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF \u68c0\u67e5\u5f53\u524d kubeadm \u7684\u7248\u672c\u3002 apt policy kubeadm \u5b89\u88c5 1.24.1-00 \u7248\u672c\u7684 kubeadm . sudo apt-get -y install kubelet = 1 .24.1-00 kubeadm = 1 .24.1-00 kubectl = 1 .24.1-00 --allow-downgrades","title":"\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/multiple-local/#_3","text":"","title":"\u914d\u7f6e\u4e3b\u8282\u70b9"},{"location":"k8s/cka_cn/installation/multiple-local/#kubeadm","text":"\u5728\u627f\u62c5\u4e3b\u8282\u70b9\u7684\u865a\u62df\u673a\u91cc\u914d\u7f6e\u63a7\u5236\u5e73\u9762\uff08Control Plane\uff09\u3002 \u68c0\u67e5 kubeadm \u5f53\u524d\u9ed8\u8ba4\u914d\u7f6e\u53c2\u6570\u3002 kubeadm config print init-defaults \u7c7b\u4f3c\u7ed3\u679c\u5982\u4e0b\u3002\u4fdd\u5b58\u9ed8\u8ba4\u914d\u7f6e\u7684\u7ed3\u679c\uff0c\u540e\u7eed\u4f1a\u4f5c\u4e3a\u53c2\u8003\u3002 apiVersion : kubeadm.k8s.io/v1beta3 bootstrapTokens : - groups : - system:bootstrappers:kubeadm:default-node-token token : abcdef.0123456789abcdef ttl : 24h0m0s usages : - signing - authentication kind : InitConfiguration localAPIEndpoint : advertiseAddress : 1.2.3.4 bindPort : 6443 nodeRegistration : criSocket : unix:///var/run/containerd/containerd.sock imagePullPolicy : IfNotPresent name : node taints : null --- apiServer : timeoutForControlPlane : 4m0s apiVersion : kubeadm.k8s.io/v1beta3 certificatesDir : /etc/kubernetes/pki clusterName : kubernetes controllerManager : {} dns : {} etcd : local : dataDir : /var/lib/etcd imageRepository : k8s.gcr.io kind : ClusterConfiguration kubernetesVersion : 1.24.0 networking : dnsDomain : cluster.local serviceSubnet : 10.96.0.0/12 scheduler : {} \u6a21\u62df\u5b89\u88c5\u548c\u6b63\u5f0f\u5b89\u88c5\u3002 \u901a\u8fc7\u547d\u4ee4 kubeadm init \u8fdb\u884c\u4e3b\u8282\u70b9\u7684\u521d\u59cb\u5316\uff0c\u4e0b\u9762\u662f\u8fd9\u4e2a\u547d\u4ee4\u4e3b\u8981\u53c2\u6570\u7684\u8bf4\u660e\uff0c\u7279\u522b\u662f\u7f51\u7edc\u53c2\u6570\u7684\u4e09\u4e2a\u9009\u62e9\u3002 --pod-network-cidr : \u6307\u5b9apod\u4f7f\u7528\u7684IP\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u6307\u5b9a\u4e86\u8be5\u53c2\u6570\uff0c\u5219Control Plane\u4f1a\u81ea\u52a8\u8bb2\u6307\u5b9a\u7684CIDR\u5206\u914d\u7ed9\u6bcf\u4e2a\u8282\u70b9\u3002 IP\u5730\u5740\u6bb5 10.244.0.0/16 \u662fFlannel\u7f51\u7edc\u7ec4\u4ef6\u9ed8\u8ba4\u7684\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u9700\u8981\u4fee\u6539Flannel\u7684IP\u5730\u5740\u6bb5\uff0c\u9700\u8981\u5728\u8fd9\u91cc\u6307\u5b9a\uff0c\u4e14\u5728\u90e8\u7f72Flannel\u65f6\u4e5f\u8981\u4fdd\u6301\u4e00\u81f4\u7684IP\u6bb5\u3002 --apiserver-bind-port : API\u670d\u52a1\uff08API Server\uff09\u7684\u7aef\u53e3\uff0c\u9ed8\u8ba4\u65f66443\u3002 --service-cidr : \u6307\u5b9a\u670d\u52a1\uff08service\uff09\u7684IP\u5730\u5740\u6bb5\uff0c\u9ed8\u8ba4\u662f 10.96.0.0/12 \u3002 \u63d0\u793a\uff1a \u670d\u52a1VIPs\uff08service VIPs\uff09\uff0c\u4e5f\u79f0\u4f5c\u96c6\u7fa4IP\uff08Cluster IP\uff09\uff0c\u901a\u8fc7\u53c2\u6570 --service-cidr \u6307\u5b9a\u3002 podCIDR\uff0c\u4e5f\u79f0\u4e3aendpoint IP\uff0c\u901a\u8fc7\u53c2\u6570 --pod-network-cidr \u6307\u5b9a\u3002 \u67094\u79cd\u5178\u578b\u7684\u7f51\u7edc\u95ee\u9898\uff1a \u9ad8\u5ea6\u8026\u5408\u7684\u5bb9\u5668\u4e0e\u5bb9\u5668\u4e4b\u95f4\u7684\u901a\u4fe1\uff1a\u8fd9\u53ef\u4ee5\u901a\u8fc7Pod\uff08podCIDR\uff09\u548c\u672c\u5730\u4e3b\u673a\u901a\u4fe1\u6765\u89e3\u51b3\u3002 Pod\u5bf9Pod\u901a\u4fe1\uff08Pod-to-Pod\uff09\uff1a \u4e5f\u88ab\u79f0\u4e3a\u5bb9\u5668\u5bf9\u5bb9\u5668\u901a\u4fe1\uff08container-to-container\uff09\u3002 \u5728Flannel\u7f51\u7edc\u63d2\u4ef6\u4e2d\u7684\u793a\u4f8b\u6d41\u7a0b\u662f\uff1aPod \u2192 veth\u5bf9 \u2192 cni0 \u2192 flannel.1 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 flannel.1 \u2192 cni0 \u2192 veth\u5bf9 \u2192 Pod\u3002 Pod\u5bf9Service\u901a\u4fe1\uff08Pod-to-Service\uff09\uff1a \u6d41\u7a0b: Pod \u2192 \u5185\u6838 \u2192 Service iptables \u2192 Service \u2192 Pod iptables \u2192 Pod\u3002 \u5916\u90e8\u5bf9Service\u901a\u4fe1\uff08External-to-Service\uff09\uff1a \u8d1f\u8f7d\u5747\u8861\u5668: SLB \u2192 NodePort \u2192 Service \u2192 Pod\u3002 kube-proxy \u662f\u5bf9iptables\u8d1f\u8d23\uff0c\u4e0d\u662f\u7f51\u7edc\u6d41\u91cf\uff08traffic\uff09\u3002 kube-proxy \u662fKubernetes\u96c6\u7fa4\u4e2d\u7684\u4e00\u4e2a\u7ec4\u4ef6\uff0c\u8d1f\u8d23\u4e3aService\u63d0\u4f9b\u4ee3\u7406\u670d\u52a1\uff0c\u540c\u65f6\u4e5f\u662fKubernetes\u7f51\u7edc\u6a21\u578b\u4e2d\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\u4e4b\u4e00\u3002 kube-proxy \u4f1a\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u542f\u52a8\u4e00\u4e2a\u4ee3\u7406\u8fdb\u7a0b\uff0c\u901a\u8fc7\u76d1\u542cKubernetes API Server\u7684Service\u548cEndpoint\u7684\u53d8\u5316\u6765\u7ef4\u62a4\u4e00\u4e2a\u672c\u5730\u7684Service\u548cEndpoint\u7684\u7f13\u5b58\u3002\u5f53\u6709\u8bf7\u6c42\u5230\u8fbe\u67d0\u4e2aService\u65f6\uff0c kube-proxy \u4f1a\u6839\u636e\u8be5Service\u7684\u7c7b\u578b\uff08ClusterIP\u3001NodePort\u3001LoadBalancer\u3001ExternalName\uff09\u548c\u7aef\u53e3\u53f7\uff0c\u751f\u6210\u76f8\u5e94\u7684iptables\u89c4\u5219\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u7ed9Service\u6240\u4ee3\u7406\u7684\u540e\u7aefPod\u3002 iptables\u662fLinux\u7cfb\u7edf\u4e2d\u7684\u4e00\u4e2a\u91cd\u8981\u7f51\u7edc\u5de5\u5177\uff0c\u53ef\u4ee5\u8bbe\u7f6eIP\u5305\u7684\u8fc7\u6ee4\u3001\u8f6c\u53d1\u548c\u4fee\u6539\u89c4\u5219\uff0c\u53ef\u4ee5\u5b9e\u73b0\u7f51\u7edc\u5c42\u7684\u9632\u706b\u5899\u3001NAT\u7b49\u529f\u80fd\u3002\u5728Kubernetes\u96c6\u7fa4\u4e2d\uff0c kube-proxy \u901a\u8fc7\u751f\u6210\u548c\u66f4\u65b0iptables\u89c4\u5219\uff0c\u6765\u5b9e\u73b0Service\u548cEndpoint\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u5177\u4f53\u6765\u8bf4\uff0ckube-proxy\u4f1a\u4e3a\u6bcf\u4e2aService\u521b\u5efa\u4e09\u6761iptables\u89c4\u5219\u94fe\uff08nat\u8868\u4e2d\u7684KUBE-SERVICES\u548cKUBE-NODEPORTS\u94fe\uff0c\u4ee5\u53cafilter\u8868\u4e2d\u7684KUBE-SVC-XXXXX\u94fe\uff09\uff0c\u901a\u8fc7\u8fd9\u4e9b\u89c4\u5219\u94fe\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u76f8\u5e94\u7684Pod\u6216\u8005Service\u4e0a\u3002 \u56e0\u6b64\uff0c kube-proxy \u548ciptables\u662f\u7d27\u5bc6\u76f8\u5173\u7684\u4e24\u4e2a\u7ec4\u4ef6\uff0c\u901a\u8fc7iptables\u89c4\u5219\u6765\u5b9e\u73b0Service\u548cPod\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u8fd9\u79cd\u5b9e\u73b0\u65b9\u5f0f\u5177\u6709\u53ef\u6269\u5c55\u6027\u548c\u9ad8\u53ef\u7528\u6027\uff0c\u540c\u65f6\u4e5f\u63d0\u4f9b\u4e86\u4e00\u79cd\u7075\u6d3b\u7684\u7f51\u7edc\u6a21\u578b\uff0c\u53ef\u4ee5\u65b9\u4fbf\u5730\u5b9e\u73b0\u670d\u52a1\u53d1\u73b0\u3001\u8d1f\u8f7d\u5747\u8861\u7b49\u529f\u80fd\u3002 sudo kubeadm init \\ --dry-run \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr = 192 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr = 192 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0","title":"kubeadm\u521d\u59cb\u5316"},{"location":"k8s/cka_cn/installation/multiple-local/#kubeconfig","text":"\u7ed9\u5f53\u524d\u5b89\u88c5\u7528\u6237\u914d\u7f6e kubeconfig \u6587\u4ef6\uff08\u5f53\u524d\u4f8b\u5b50\u662f\u7528\u6237 vagrant \uff09\u3002 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Kubernetes \u63d0\u4f9b\u4e86\u4e00\u4e2a\u547d\u4ee4\u884c\u5de5\u5177 kubectl \uff0c\u7528\u4e8e\u4f7f\u7528 Kubernetes API \u4e0e Kubernetes \u96c6\u7fa4\u7684\u63a7\u5236\u5e73\u9762\u8fdb\u884c\u901a\u4fe1\u3002 kubectl \u63a7\u5236 Kubernetes cluster manager \uff08\u96c6\u7fa4\u7ba1\u7406\u5668\uff09\u3002 \u5bf9\u4e8e\u914d\u7f6e\uff0ckubectl \u5728 $HOME/.kube \u76ee\u5f55\u4e2d\u67e5\u627e\u4e00\u4e2a\u540d\u4e3a config \u7684\u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u662f\u7531 kubeadm init \u751f\u6210\u7684\u6587\u4ef6 /etc/kubernetes/admin.conf \u7684\u526f\u672c\u3002 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e KUBECONFIG \u73af\u5883\u53d8\u91cf\u6216\u8bbe\u7f6e --kubeconfig flag \u6807\u5fd7\u6765\u6307\u5b9a\u5176\u4ed6 kubeconfig \u6587\u4ef6\u3002\u5982\u679c KUBECONFIG \u73af\u5883\u53d8\u91cf\u4e0d\u5b58\u5728\uff0ckubectl \u5c06\u4f7f\u7528\u9ed8\u8ba4\u7684 kubeconfig \u6587\u4ef6 $HOME/.kube/config \u3002 kubeconfig \u6587\u4ef6\u4e2d\u7684 context\uff08\u4e0a\u4e0b\u6587\uff09 \u5143\u7d20\u7528\u4e8e\u5c06\u8bbf\u95ee\u53c2\u6570\u5206\u7ec4\u5230\u4e00\u4e2a\u65b9\u4fbf\u7684\u540d\u79f0\u4e0b\u3002\u6bcf\u4e2a\u4e0a\u4e0b\u6587\u90fd\u6709\u4e09\u4e2a\u53c2\u6570\uff1a\u96c6\u7fa4\u3001\u547d\u540d\u7a7a\u95f4\u548c\u7528\u6237\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0ckubectl \u547d\u4ee4\u884c\u5de5\u5177\u4f7f\u7528\u5f53\u524d\u4e0a\u4e0b\u6587\u4e2d\u7684\u53c2\u6570\u4e0e\u96c6\u7fa4\u901a\u4fe1\u3002 \u6587\u4ef6 .kube/config \u7684\u4f8b\u5b50\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : \u8bfb\u53d6\u5f53\u524d\u4e0a\u4e0b\u6587\uff1a kubectl config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin","title":"kubeconfig\u6587\u4ef6"},{"location":"k8s/cka_cn/installation/multiple-local/#calico","text":"\u53c2\u8003\u5b89\u88c5\u6307\u5bfc End-to-end Calico installation \u3002 \u5feb\u901f\u5b89\u88c5\u624b\u518c QuickStart \u5b89\u88c5 Calico\uff1a kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/tigera-operator.yaml \u8fd0\u884c\u7ed3\u679c\uff1a namespace/tigera-operator created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/apiservers.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/imagesets.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/installations.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/tigerastatuses.operator.tigera.io created serviceaccount/tigera-operator created clusterrole.rbac.authorization.k8s.io/tigera-operator created clusterrolebinding.rbac.authorization.k8s.io/tigera-operator created deployment.apps/tigera-operator created kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/calicoctl.yaml \u8fd0\u884c\u7ed3\u679c\uff1a serviceaccount/calicoctl created pod/calicoctl created clusterrole.rbac.authorization.k8s.io/calicoctl created clusterrolebinding.rbac.authorization.k8s.io/calicoctl created \u9a8c\u8bc1Calico\u7684\u72b6\u6001\u3002Calico\u7684\u521d\u59cb\u5316\u8fc7\u7a0b\u53ef\u80fd\u9700\u8981\u51e0\u5206\u949f\u65f6\u95f4\u5b8c\u6210\u3002 kubectl get pod -n kube-system | grep calico \u8fd0\u884c\u7ed3\u679c\uff1a calico-kube-controllers-555bc4b957-l8bn2 0/1 Pending 0 28s calico-node-255pc 0/1 Init:1/3 0 29s calico-node-7tmnb 0/1 Init:1/3 0 29s calico-node-w8nvl 0/1 Init:1/3 0 29s \u9a8c\u8bc1\u7f51\u7edc\u72b6\u6001\u3002 sudo nerdctl network ls \u8fd0\u884c\u7ed3\u679c\uff1a NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 17f29b073143 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none","title":"\u5b89\u88c5Calico"},{"location":"k8s/cka_cn/installation/multiple-local/#_4","text":"\u4f7f\u7528 kubeadm token \u6765\u751f\u6210\u52a0\u5165\u96c6\u7fa4\u7684\u4ee4\u724c\uff08token\uff09\u548c\u54c8\u897f\u503c\uff08hash value\uff09\u3002 kubeadm token create --print-join-command \u547d\u4ee4\u7528\u6cd5\uff1a sudo kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> \u8fd0\u884c\u7ed3\u679c\uff1a [preflight] Running pre-flight checks [WARNING SystemVerification]: missing optional cgroups: blkio [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [kubelet-start] Writing kubelet configuration to file \"/var/lib/kubelet/config.yaml\" [kubelet-start] Writing kubelet environment file with flags to file \"/var/lib/kubelet/kubeadm-flags.env\" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster.","title":"\u914d\u7f6e\u5de5\u4f5c\u8282\u70b9"},{"location":"k8s/cka_cn/installation/multiple-local/#_5","text":"\u67e5\u770b Kubernetes \u96c6\u7fa4\u7684\u4fe1\u606f\uff0c\u5305\u62ec\u96c6\u7fa4 API Server \u7684\u5730\u5740\u3001Kubernetes DNS \u670d\u52a1\u7684\u5730\u5740\u7b49\u3002 kubectl cluster-info \u8fd0\u884c\u7ed3\u679c\uff1a bKubernetes control plane is running at https://11.0.1.129:6443 CoreDNS is running at https://11.0.1.129:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. \u5217\u51fa\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u5305\u62ec\u8282\u70b9\u540d\u79f0\u3001\u8282\u70b9 IP\u3001\u8282\u70b9\u6807\u7b7e\u3001\u8282\u70b9\u72b6\u6001\u7b49\u3002 kubectl get nodes -owide \u5217\u51fa Kubernetes \u96c6\u7fa4\u4e2d\u6240\u6709 Namespace \u4e0b\u7684 Pod\u3002 kubectl get pod -A","title":"\u68c0\u67e5\u96c6\u7fa4\u72b6\u6001"},{"location":"k8s/cka_cn/installation/multiple-local/#_6","text":"","title":"\u66f4\u65b0\u5b89\u88c5"},{"location":"k8s/cka_cn/installation/multiple-local/#bash","text":"\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u914d\u7f6eBash\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 \u53c2\u8003 \u6307\u5bfc \u8bbe\u7f6e kubectl \u81ea\u52a8\u8865\u5168\u529f\u80fdauto-completion \u3002 apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc source ~/.bashrc","title":"Bash\u81ea\u52a8\u8865\u5168"},{"location":"k8s/cka_cn/installation/multiple-local/#_7","text":"\u5982\u679c\u6211\u4eec\u4e3a kubectl \u8bbe\u7f6e\u4e00\u4e2a\u522b\u540d\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u4e00\u4e9b\u65b9\u6cd5\u6765\u6269\u5c55 shell \u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u4f7f\u5176\u80fd\u591f\u4e0e\u8be5\u522b\u540d\u4e00\u8d77\u4f7f\u7528\u3002 \u4e00\u79cd\u65b9\u6cd5\u662f\u5728 Bash shell \u914d\u7f6e\u6587\u4ef6\uff08\u5982 .bashrc \u6216 .bash_profile\uff09\u4e2d\u8bbe\u7f6e\u522b\u540d\uff0c\u5e76\u4e3a\u8be5\u522b\u540d\u6307\u5b9a kubectl \u7684\u5b8c\u6574\u8def\u5f84\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a alias k = 'path/to/kubectl' \u7136\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u91cd\u65b0\u52a0\u8f7d .bashrc \u6587\u4ef6\uff1a source ~/.bashrc \u63a5\u4e0b\u6765\uff0c\u53ef\u4ee5\u4f7f\u7528 k \u547d\u4ee4\u6765\u4ee3\u66ff kubectl \u547d\u4ee4\uff0c\u5e76\u5728\u5176\u540e\u9762\u6dfb\u52a0\u76f8\u5e94\u7684\u53c2\u6570\u548c\u9009\u9879\u3002\u5f53\u4f7f\u7528\u81ea\u52a8\u8865\u5168\u529f\u80fd\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u5c06 k \u522b\u540d\u8f6c\u6362\u4e3a kubectl \u7684\u5b8c\u6574\u8def\u5f84\uff0c\u5e76\u5bf9\u5176\u8fdb\u884c\u81ea\u52a8\u8865\u5168\u3002 \u53e6\u4e00\u79cd\u65b9\u6cd5\u662f\u4f7f\u7528 Bash shell \u5185\u7f6e\u7684 complete \u51fd\u6570\u6765\u4e3a\u522b\u540d\u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc \u8fd9\u5c06\u4e3a\u522b\u540d k \u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u5e76\u5c06\u5176\u4e0e kubectl \u7684\u81ea\u52a8\u8865\u5168\u51fd\u6570 __start_kubectl \u5173\u8054\u8d77\u6765\u3002\u8fd9\u6837\uff0c\u5f53\u7528\u6237\u5728 k \u547d\u4ee4\u540e\u8f93\u5165Tab\u952e\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u8c03\u7528 __start_kubectl \u51fd\u6570\uff0c\u5e76\u4e3a\u7528\u6237\u63d0\u4f9b\u76f8\u5e94\u7684\u81ea\u52a8\u8865\u5168\u5efa\u8bae\u3002","title":"\u522b\u540d"},{"location":"k8s/cka_cn/installation/multiple-local/#context","text":"\u67e5\u770b\u5f53\u524d\u7684 context \u5217\u8868\uff1a kubectl config get-contexts \u8fd9\u4e2a\u547d\u4ee4\u4f1a\u5217\u51fa\u6240\u6709\u53ef\u7528\u7684 context \u5217\u8868\uff0c\u5e76\u6807\u8bb0\u51fa\u5f53\u524d\u6b63\u5728\u4f7f\u7528\u7684 context\u3002 \u7c7b\u4f3c\u4e0b\u9762\u7ed3\u679c\uff1a kubernetes-admin@kubernetes \u662fContext\u540d\u3002 kubernetes \u662f\u96c6\u7fa4\u540d\u3002 kubernetes-admin \u662f\u7528\u6237\u540d\u3002 \u5f53\u524d\u4f8b\u5b50\u4e2d\u6ca1\u6709\u6307\u5b9a\u540d\u79f0\u7a7a\u95f4\u3002 CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin \u66f4\u65b0context\u3002\u4f8b\u5982\uff0c\u66f4\u65b0context\u7684\u9ed8\u8ba4\u540d\u79f0\u7a7a\u95f4\u7b49\u3002 # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin \u5728\u4e0d\u540c\u7684context\u4e4b\u95f4\u5207\u6362\u3002 # Usage: kubectl config use-context # Switch to new context kubectl config use-context kubernetes-admin@kubernetes \u53c2\u8003\u8d44\u6599\uff1a * kubectl * commandline","title":"\u66f4\u65b0\u9ed8\u8ba4Context"},{"location":"k8s/cka_cn/installation/multiple-local/#helm","text":"Helm \u662f Kubernetes \u7684\u5305\u7ba1\u7406\u5de5\u5177\uff0c\u5b83\u4e0d\u968f Kubernetes \u4e00\u8d77\u63d0\u4f9b\u3002 Helm \u6709\u4e09\u4e2a\u6838\u5fc3\u6982\u5ff5\uff1a Chart\uff08\u56fe\u8868\uff09\u662f Helm \u7684\u8f6f\u4ef6\u5305\uff0c\u5b83\u5305\u542b\u4e86\u5728 Kubernetes \u96c6\u7fa4\u4e2d\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u3001\u5de5\u5177\u6216\u670d\u52a1\u6240\u9700\u7684\u6240\u6709\u8d44\u6e90\u5b9a\u4e49\u3002\u53ef\u4ee5\u5c06\u5176\u89c6\u4e3a Kubernetes \u7684 Homebrew \u516c\u5f0f\u3001Apt dpkg \u6216 Yum RPM \u6587\u4ef6\u7b49\u7b49\u3002 Repository\uff08\u4ed3\u5e93\uff09\u662f\u56fe\u8868\u53ef\u4ee5\u88ab\u6536\u96c6\u548c\u5171\u4eab\u7684\u5730\u65b9\uff0c\u7c7b\u4f3c\u4e8e Perl \u7684 CPAN \u5b58\u50a8\u5e93\u6216 Fedora \u7684\u8f6f\u4ef6\u5305\u6570\u636e\u5e93\uff0c\u4f46\u7528\u4e8e Kubernetes \u8f6f\u4ef6\u5305\u3002 Release\uff08\u53d1\u5e03\uff09\u662f\u5728 Kubernetes \u96c6\u7fa4\u4e2d\u8fd0\u884c\u7684\u56fe\u8868\u5b9e\u4f8b\u3002\u4e00\u4e2a\u56fe\u8868\u901a\u5e38\u53ef\u4ee5\u5728\u540c\u4e00\u96c6\u7fa4\u4e2d\u5b89\u88c5\u591a\u6b21\uff0c\u5e76\u4e14\u6bcf\u6b21\u5b89\u88c5\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u53d1\u5e03\u3002\u4ee5 MySQL \u56fe\u8868\u4e3a\u4f8b\uff0c\u5982\u679c\u60f3\u8981\u5728\u96c6\u7fa4\u4e2d\u8fd0\u884c\u4e24\u4e2a\u6570\u636e\u5e93\uff0c\u5219\u53ef\u4ee5\u5b89\u88c5\u8be5\u56fe\u8868\u4e24\u6b21\uff0c\u6bcf\u6b21\u5b89\u88c5\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u53d1\u5e03\uff0c\u6bcf\u4e2a\u53d1\u5e03\u90fd\u6709\u81ea\u5df1\u7684\u53d1\u5e03\u540d\u79f0\u3002 \u53c2\u8003\u6587\u6863\uff1a installation guide binary release source code . Helm\u5ba2\u6237\u7aef\u5b89\u88c5\uff1a curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh \u8fd0\u884c\u7ed3\u679c\uff1a Downloading https://get.helm.sh/helm-v3.9.1-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm \u63d0\u793a\uff1a * helm init \u5728Helm 3\u4e2d\u5df2\u53d6\u6d88\uff0c\u4e14Tiller\u4e5f\u4e00\u540c\u53d6\u6d88\u3002\u4eca\u540e\u5728\u96c6\u7fa4\u4e2d\u4f7f\u7528Helm\u65f6\u4e0d\u518d\u9700\u8981\u5b89\u88c5Tiller\u3002 * helm search \u53ef\u4ee5\u7528\u6765\u641c\u7d22\u4e24\u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u8d44\u6e90\uff1a * helm search hub \u5728 Artifact Hub \u4e2d\u641c\u7d22\uff0c\u8fd9\u4e2ahub\u91cc\u5217\u51fa\u6765\u81ea\u6570\u5341\u4e2a\u4e0d\u540c\u4ed3\u5e93\u7684 Helm Chart\u3002 * helm search repo \u547d\u4ee4\u7528\u4e8e\u641c\u7d22\u5df2\u6dfb\u52a0\u5230\u672c\u5730 Helm \u5ba2\u6237\u7aef\u7684\u4ed3\u5e93\uff08\u4f7f\u7528 helm repo add \u547d\u4ee4\uff09\u3002\u6b64\u641c\u7d22\u662f\u5728\u672c\u5730\u6570\u636e\u4e0a\u8fdb\u884c\u7684\uff0c\u4e0d\u9700\u8981\u516c\u5171\u7f51\u7edc\u8fde\u63a5\u3002 \u53c2\u8003\u8d44\u6599\uff1a Helming development","title":"\u5b89\u88c5Helm"},{"location":"k8s/cka_cn/installation/multiple-local/#_8","text":"\u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u64cd\u4f5c\u4f1a\u91cd\u7f6e\u5f53\u524d\u96c6\u7fa4\uff08\u5220\u9664\u96c6\u7fa4\uff09\u3002 \u5220\u9664\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u3002 kubeadm reset \u6e05\u9664 iptables \u4e2d\u5df2\u5b9a\u4e49\u7684\u89c4\u5219\u3002 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u6e05\u9664 IPVS \u4e2d\u5b9a\u4e49\u7684\u89c4\u5219\uff08\u5982\u679c\u4f7f\u7528 IPVS \uff09\u3002 ipvsadm --clear","title":"\u91cd\u7f6e\u96c6\u7fa4"},{"location":"k8s/cka_cn/installation/single-local/","text":"CKA\u81ea\u5b66\u7b14\u8bb01:\u5355\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes \u00b6 \u6458\u8981 \u00b6 \u5728\u672c\u5730Windows\u73af\u5883\u4e2d\uff0c\u901a\u8fc7VMWare\u5b89\u88c5Ubuntu\u865a\u62df\u673a\u3002\u5728Ubuntu\u865a\u62df\u673a\u4e2d\u5b89\u88c5\u57fa\u4e8eDocker\u7684Kubernetes\u7cfb\u7edf\u3002\u5728\u8be5\u865a\u62df\u673a\u4e2d\u540c\u65f6\u914d\u7f6e\u4e3b\u8282\u70b9Master\u548c\u5de5\u4f5c\u8282\u70b9Worker\u3002 \u672c\u5730\u865a\u62df\u673a\u8bbe\u7f6e \u00b6 VMWare\u865a\u62df\u673a\u8bbe\u7f6e\u3002 VMnet1: host-only\u6a21\u5f0f, \u7f51\u7edcsubnet: 192.168.150.0/24 VMnet8: NAT\u6a21\u5f0f, \u7f51\u7edcsubnet: 11.0.1.0/24 \u901a\u8fc7VMWare\u521b\u5efa\u5ba2\u6237\u673a\u3002 \u5185\u5b58\uff1a4 GB CPU\uff1a2 CPUs with 2 Cores \u64cd\u4f5c\u7cfb\u7edf\uff1aUbuntu Server 22.04 \u7f51\u7edc\uff1aNAT Kubernetes\u8fd0\u884c\u5728Docker\u4e0a\u3002 Ubuntu\u9884\u914d\u7f6e \u00b6 \u521b\u5efa\u7528\u6237 vagrant \u3002 sudo adduser vagrant sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd vagrant sudo passwd vagrant \u8bbe\u7f6e\u7528\u6237 root \u7684\u5bc6\u7801\u3002 sudo passwd root \u66f4\u65b0\u5ba2\u6237\u673a\u7684\u4e3b\u673a\u540d\uff0c\u8fd9\u91cc\u662f ubusvr \u3002 sudo hostnamectl set-hostname ubusvr sudo hostnamectl set-hostname ubusvr --pretty \u9a8c\u8bc1\u4e3b\u673a\u540d\u662f\u5426\u5df2\u6210\u529f\u66f4\u65b0\u4e3a ubusvr \u3002 cat /etc/machine-info cat /etc/hostname \u9a8c\u8bc1\u4e3b\u673aIP\u5730\u5740 127.0.1.1 \u5df2\u7ecf\u914d\u7f6e\u7ed9\u5f53\u524d\u865a\u62df\u673a ubusvr \u3002 cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 ubusrv # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters \u8bbe\u7f6e\u5ba2\u6237\u673a\u4e3a\u56fa\u5b9aIP\u5730\u5740\uff0c\u8fd9\u91cc\u662f 11.0.1.136 \u3002 sudo vi 00 -installer-config.yaml network : ethernets : ens33 : dhcp4 : false addresses : - 11.0.1.136/24 nameservers : addresses : - 11.0.1.2 routes : - to : default via : 11.0.1.2 version : 2 sudo netplan apply \u7981\u7528\u4ea4\u6362\u5206\u533aswap\u3002 sudo swapoff -a sudo ufw disable sudo ufw status verbose \u6ce8\u91ca\u6389\u6587\u4ef6 /etc/fstab \u7684\u6700\u540e\u4e00\u884c\uff0c\u5373\u7981\u7528\u4ea4\u6362\u5206\u533a\u3002\u9700\u8981\u91cd\u542f\u5ba2\u6237\u673a\u4f7f\u4e4b\u751f\u6548\u3002 /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 \u8bbe\u7f6e\u5ba2\u6237\u673a\u65f6\u533a\u3002 sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile \u6267\u884c\u547d\u4ee4 ll /etc/localtime \u9a8c\u8bc1\u65f6\u533a\u662f\u5426\u5df2\u6b63\u786e\u8bbe\u7f6e\u5e76\u751f\u6548\u3002 lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai \u5ba2\u6237\u673a\u5185\u6838\u8bbe\u7f6e\u3002 cat < /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl status docker.service sudo systemctl status containerd.service sudo groupadd docker sudo usermod -aG docker $USER \u8bbe\u7f6eContainerd\u3002 containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml sudo systemctl restart containerd sudo systemctl status containerd \u5b89\u88c5Kubernetes \u00b6 \u5b89\u88c5kubeadm sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - cat << EOF > /etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables apt policy kubeadm sudo apt-get -y install kubelet = 1 .23.8-00 kubeadm = 1 .23.8-00 kubectl = 1 .23.8-00 --allow-downgrades \u914d\u7f6e\u4e3b\u8282\u70b9\uff08Master\uff09\u3002 sudo kubeadm config print init-defaults \u5b89\u88c5\u9884\u6f14Dry run\u3002 sudo kubeadm init --dry-run --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 \u5b89\u88c5\u3002 sudo kubeadm init --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config \u5b89\u88c5Flannel\u3002\u5982\u679c\u9700\u8981\u8003\u8651\u7f51\u7edc\u7b56\u7565\uff0c\u5219\u5b89\u88c5Calico\u3002\u53c2\u7167 \u963f\u91cc\u4e91ECS \u4e2dInstall Calico or Flannel\u90e8\u5206\u3002 kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml \u914d\u7f6e\u5de5\u4f5c\u8282\u70b9\uff08Worker Node\uff09\u3002 kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> kubeadm join 11 .0.1.136:6443 --token 6zqh1u.8b4afzc2ov4e7iuj \\ --discovery-token-ca-cert-hash sha256:815fdb9dd9e3ae0af07ffaf6c216964388098b150ef01ee3ae900c261a429d24 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u914d\u7f6ebash\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 sudo apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b9a\u4e49\u522b\u540d\uff08alias\uff09\u3002 echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc \u67e5\u770b\u5f53\u524d\u96c6\u7fa4\u72b6\u6001\u3002 kubectl cluster-info kubectl get nodes -owide kubectl get pod -A \u5b89\u88c5Helm \u00b6 \u5b89\u88c5Helm\u5ba2\u6237\u7aef\u3002 curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh \u8f93\u51fa\u7ed3\u679c\uff1a Downloading https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm \u91cd\u7f6e\u96c6\u7fa4 \u00b6 \u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u64cd\u4f5c\u4f1a\u91cd\u7f6e\u5f53\u524d\u96c6\u7fa4\uff08\u5220\u9664\u96c6\u7fa4\uff09\u3002 \u5220\u9664\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u3002 kubeadm reset \u6e05\u9664 iptables \u4e2d\u5df2\u5b9a\u4e49\u7684\u89c4\u5219\u3002 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u6e05\u9664 IPVS \u4e2d\u5b9a\u4e49\u7684\u89c4\u5219\uff08\u5982\u679c\u4f7f\u7528 IPVS \uff09\u3002 ipvsadm --clear","title":"\u5355\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/single-local/#cka1kubernetes","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb01:\u5355\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/single-local/#_1","text":"\u5728\u672c\u5730Windows\u73af\u5883\u4e2d\uff0c\u901a\u8fc7VMWare\u5b89\u88c5Ubuntu\u865a\u62df\u673a\u3002\u5728Ubuntu\u865a\u62df\u673a\u4e2d\u5b89\u88c5\u57fa\u4e8eDocker\u7684Kubernetes\u7cfb\u7edf\u3002\u5728\u8be5\u865a\u62df\u673a\u4e2d\u540c\u65f6\u914d\u7f6e\u4e3b\u8282\u70b9Master\u548c\u5de5\u4f5c\u8282\u70b9Worker\u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/installation/single-local/#_2","text":"VMWare\u865a\u62df\u673a\u8bbe\u7f6e\u3002 VMnet1: host-only\u6a21\u5f0f, \u7f51\u7edcsubnet: 192.168.150.0/24 VMnet8: NAT\u6a21\u5f0f, \u7f51\u7edcsubnet: 11.0.1.0/24 \u901a\u8fc7VMWare\u521b\u5efa\u5ba2\u6237\u673a\u3002 \u5185\u5b58\uff1a4 GB CPU\uff1a2 CPUs with 2 Cores \u64cd\u4f5c\u7cfb\u7edf\uff1aUbuntu Server 22.04 \u7f51\u7edc\uff1aNAT Kubernetes\u8fd0\u884c\u5728Docker\u4e0a\u3002","title":"\u672c\u5730\u865a\u62df\u673a\u8bbe\u7f6e"},{"location":"k8s/cka_cn/installation/single-local/#ubuntu","text":"\u521b\u5efa\u7528\u6237 vagrant \u3002 sudo adduser vagrant sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd vagrant sudo passwd vagrant \u8bbe\u7f6e\u7528\u6237 root \u7684\u5bc6\u7801\u3002 sudo passwd root \u66f4\u65b0\u5ba2\u6237\u673a\u7684\u4e3b\u673a\u540d\uff0c\u8fd9\u91cc\u662f ubusvr \u3002 sudo hostnamectl set-hostname ubusvr sudo hostnamectl set-hostname ubusvr --pretty \u9a8c\u8bc1\u4e3b\u673a\u540d\u662f\u5426\u5df2\u6210\u529f\u66f4\u65b0\u4e3a ubusvr \u3002 cat /etc/machine-info cat /etc/hostname \u9a8c\u8bc1\u4e3b\u673aIP\u5730\u5740 127.0.1.1 \u5df2\u7ecf\u914d\u7f6e\u7ed9\u5f53\u524d\u865a\u62df\u673a ubusvr \u3002 cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 ubusrv # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters \u8bbe\u7f6e\u5ba2\u6237\u673a\u4e3a\u56fa\u5b9aIP\u5730\u5740\uff0c\u8fd9\u91cc\u662f 11.0.1.136 \u3002 sudo vi 00 -installer-config.yaml network : ethernets : ens33 : dhcp4 : false addresses : - 11.0.1.136/24 nameservers : addresses : - 11.0.1.2 routes : - to : default via : 11.0.1.2 version : 2 sudo netplan apply \u7981\u7528\u4ea4\u6362\u5206\u533aswap\u3002 sudo swapoff -a sudo ufw disable sudo ufw status verbose \u6ce8\u91ca\u6389\u6587\u4ef6 /etc/fstab \u7684\u6700\u540e\u4e00\u884c\uff0c\u5373\u7981\u7528\u4ea4\u6362\u5206\u533a\u3002\u9700\u8981\u91cd\u542f\u5ba2\u6237\u673a\u4f7f\u4e4b\u751f\u6548\u3002 /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 \u8bbe\u7f6e\u5ba2\u6237\u673a\u65f6\u533a\u3002 sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile \u6267\u884c\u547d\u4ee4 ll /etc/localtime \u9a8c\u8bc1\u65f6\u533a\u662f\u5426\u5df2\u6b63\u786e\u8bbe\u7f6e\u5e76\u751f\u6548\u3002 lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai \u5ba2\u6237\u673a\u5185\u6838\u8bbe\u7f6e\u3002 cat < /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl status docker.service sudo systemctl status containerd.service sudo groupadd docker sudo usermod -aG docker $USER \u8bbe\u7f6eContainerd\u3002 containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml sudo systemctl restart containerd sudo systemctl status containerd","title":"\u5b89\u88c5Docker"},{"location":"k8s/cka_cn/installation/single-local/#kubernetes","text":"\u5b89\u88c5kubeadm sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - cat << EOF > /etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables apt policy kubeadm sudo apt-get -y install kubelet = 1 .23.8-00 kubeadm = 1 .23.8-00 kubectl = 1 .23.8-00 --allow-downgrades \u914d\u7f6e\u4e3b\u8282\u70b9\uff08Master\uff09\u3002 sudo kubeadm config print init-defaults \u5b89\u88c5\u9884\u6f14Dry run\u3002 sudo kubeadm init --dry-run --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 \u5b89\u88c5\u3002 sudo kubeadm init --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config \u5b89\u88c5Flannel\u3002\u5982\u679c\u9700\u8981\u8003\u8651\u7f51\u7edc\u7b56\u7565\uff0c\u5219\u5b89\u88c5Calico\u3002\u53c2\u7167 \u963f\u91cc\u4e91ECS \u4e2dInstall Calico or Flannel\u90e8\u5206\u3002 kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml \u914d\u7f6e\u5de5\u4f5c\u8282\u70b9\uff08Worker Node\uff09\u3002 kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> kubeadm join 11 .0.1.136:6443 --token 6zqh1u.8b4afzc2ov4e7iuj \\ --discovery-token-ca-cert-hash sha256:815fdb9dd9e3ae0af07ffaf6c216964388098b150ef01ee3ae900c261a429d24 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u914d\u7f6ebash\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 sudo apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b9a\u4e49\u522b\u540d\uff08alias\uff09\u3002 echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc \u67e5\u770b\u5f53\u524d\u96c6\u7fa4\u72b6\u6001\u3002 kubectl cluster-info kubectl get nodes -owide kubectl get pod -A","title":"\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/single-local/#helm","text":"\u5b89\u88c5Helm\u5ba2\u6237\u7aef\u3002 curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh \u8f93\u51fa\u7ed3\u679c\uff1a Downloading https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm","title":"\u5b89\u88c5Helm"},{"location":"k8s/cka_cn/installation/single-local/#_3","text":"\u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u64cd\u4f5c\u4f1a\u91cd\u7f6e\u5f53\u524d\u96c6\u7fa4\uff08\u5220\u9664\u96c6\u7fa4\uff09\u3002 \u5220\u9664\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u3002 kubeadm reset \u6e05\u9664 iptables \u4e2d\u5df2\u5b9a\u4e49\u7684\u89c4\u5219\u3002 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u6e05\u9664 IPVS \u4e2d\u5b9a\u4e49\u7684\u89c4\u5219\uff08\u5982\u679c\u4f7f\u7528 IPVS \uff09\u3002 ipvsadm --clear","title":"\u91cd\u7f6e\u96c6\u7fa4"},{"location":"k8s/cka_en/foundamentals/basics/","text":"kubectl basics \u00b6 Scenario: get to know how to operate Kubernetes cluster using kubectl . via API via kubectl via Dashboard Demo: Check current kubeconfig file \u00b6 Use the kubectl config command to get current context of configuration file. echo $KUBECONFIG kubectl config view kubectl config get-contexts Get resource list \u00b6 Get a complete list of supported resources kubectl api-resources Get cluster status \u00b6 Kubernetes control plane is running at https://:6443 CoreDNS is running at https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy kubectl cluster-info kubectl cluster-info dump Display resources \u00b6 Use kubectl get --help to get examples of displaying one or many resources. Get health status of control plane. kubectl get componentstatuses kubectl get cs Result NAME STATUS MESSAGE ERROR etcd-0 Healthy {\"health\":\"true\",\"reason\":\"\"} scheduler Healthy ok controller-manager Healthy ok Get node status and details \u00b6 kubectl get nodes kubectl get nodes -o wide kubectl describe node cka001 Use command kubectl create --help to get examples of creating resources. Create namespace \u00b6 kubectl create namespace --help kubectl create namespace my-namespace Information Namespace is a cluster, which includes services. Service may be on a node, may be not. Create deployment \u00b6 Create Deployment on the namespace. kubectl -n my-namespace create deployment my-busybox \\ --image=busybox \\ --replicas=3 \\ --port=5701 Create ClusterRole \u00b6 kubectl create clusterrole --help kubectl create clusterrole pod-creater \\ -n my-namespace \\ --verb=create \\ --resource=deployment \\ --resource-name=my-busybox Create ServiceAccount \u00b6 kubectl create serviceaccount --help kubectl -n my-namespace create serviceaccount my-service-account Create RoleBinding \u00b6 Note RoleBinding can reference a Role in the same namespace or a ClusterRole in the global namespace. kubectl create rolebinding --help kubectl create rolebinding NAME \\ --clusterrole=NAME|--role=NAME \\ [--user=username] \\ [--group=groupname] \\ [--serviceaccount=namespace:serviceaccountname] \\ [--dry-run=server|client|none] kubectl create rolebinding my-admin \\ --clusterrole=pod-creater \\ --serviceaccount=my-namespace:my-service-account Use the proxy \u00b6 We can use kubectl proxy command to open a tunnel to the API server and make it available locally - usually on localhost:8001 / 127.0.0.1:8001. When I want to explore the API, this is an easy way to gain access. Run the command kubectl proxy & and open http://localhost:8001/api/v1 in browser. Just opening http://localhost:8001 will return an error because we are only allowed to access certain parts of the API. Hence the API path is important kubectl proxy & Output [1] 102358 Starting to serve on 127.0.0.1:8001 Example, get available API groups and so on via below link: http://127.0.0.1:8001/ http://127.0.0.1:8001/api/v1 http://127.0.0.1:8001/api/v1/namespaces http://127.0.0.1:8001/api/v1/namespaces/default http://127.0.0.1:8001/api/v1/namespaces/sock-shop/pods Access as application \u00b6 If we access kubernetes as an application rather than an administrator, we cannot use the kubectl . Instead of kubectl we can use the program curl . We have to send HTTP requests to the cluster. asking for the available nodes. Make sure kubectl proxy is running and serving on http://localhost:8001/ . Execute command below with a -v=9 flag, it shows all the information needed. kubectl get nodes Go through the command's output and find the correct curl request below. curl -v -XGET \\ -H \"Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json\" \\ -H \"User-Agent: kubectl/v1.24.1 (linux/amd64) kubernetes/3ddd0f4\" \\ 'https:///api/v1/nodes?limit=500' Reference *There is a forum-like page hosted by K8s with lots of information around kubectl and how to use it best. * Manage multiple clusters and multiple config files * kubectl command documentation * Shell autocompletion * kubectl cheat sheet * jsonpath in kubectl * kubectl","title":"kubectl basics"},{"location":"k8s/cka_en/foundamentals/basics/#kubectl-basics","text":"Scenario: get to know how to operate Kubernetes cluster using kubectl . via API via kubectl via Dashboard Demo:","title":"kubectl basics"},{"location":"k8s/cka_en/foundamentals/basics/#check-current-kubeconfig-file","text":"Use the kubectl config command to get current context of configuration file. echo $KUBECONFIG kubectl config view kubectl config get-contexts","title":"Check current kubeconfig file"},{"location":"k8s/cka_en/foundamentals/basics/#get-resource-list","text":"Get a complete list of supported resources kubectl api-resources","title":"Get resource list"},{"location":"k8s/cka_en/foundamentals/basics/#get-cluster-status","text":"Kubernetes control plane is running at https://:6443 CoreDNS is running at https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy kubectl cluster-info kubectl cluster-info dump","title":"Get cluster status"},{"location":"k8s/cka_en/foundamentals/basics/#display-resources","text":"Use kubectl get --help to get examples of displaying one or many resources. Get health status of control plane. kubectl get componentstatuses kubectl get cs Result NAME STATUS MESSAGE ERROR etcd-0 Healthy {\"health\":\"true\",\"reason\":\"\"} scheduler Healthy ok controller-manager Healthy ok","title":"Display resources"},{"location":"k8s/cka_en/foundamentals/basics/#get-node-status-and-details","text":"kubectl get nodes kubectl get nodes -o wide kubectl describe node cka001 Use command kubectl create --help to get examples of creating resources.","title":"Get node status and details"},{"location":"k8s/cka_en/foundamentals/basics/#create-namespace","text":"kubectl create namespace --help kubectl create namespace my-namespace Information Namespace is a cluster, which includes services. Service may be on a node, may be not.","title":"Create namespace"},{"location":"k8s/cka_en/foundamentals/basics/#create-deployment","text":"Create Deployment on the namespace. kubectl -n my-namespace create deployment my-busybox \\ --image=busybox \\ --replicas=3 \\ --port=5701","title":"Create deployment"},{"location":"k8s/cka_en/foundamentals/basics/#create-clusterrole","text":"kubectl create clusterrole --help kubectl create clusterrole pod-creater \\ -n my-namespace \\ --verb=create \\ --resource=deployment \\ --resource-name=my-busybox","title":"Create ClusterRole"},{"location":"k8s/cka_en/foundamentals/basics/#create-serviceaccount","text":"kubectl create serviceaccount --help kubectl -n my-namespace create serviceaccount my-service-account","title":"Create ServiceAccount"},{"location":"k8s/cka_en/foundamentals/basics/#create-rolebinding","text":"Note RoleBinding can reference a Role in the same namespace or a ClusterRole in the global namespace. kubectl create rolebinding --help kubectl create rolebinding NAME \\ --clusterrole=NAME|--role=NAME \\ [--user=username] \\ [--group=groupname] \\ [--serviceaccount=namespace:serviceaccountname] \\ [--dry-run=server|client|none] kubectl create rolebinding my-admin \\ --clusterrole=pod-creater \\ --serviceaccount=my-namespace:my-service-account","title":"Create RoleBinding"},{"location":"k8s/cka_en/foundamentals/basics/#use-the-proxy","text":"We can use kubectl proxy command to open a tunnel to the API server and make it available locally - usually on localhost:8001 / 127.0.0.1:8001. When I want to explore the API, this is an easy way to gain access. Run the command kubectl proxy & and open http://localhost:8001/api/v1 in browser. Just opening http://localhost:8001 will return an error because we are only allowed to access certain parts of the API. Hence the API path is important kubectl proxy & Output [1] 102358 Starting to serve on 127.0.0.1:8001 Example, get available API groups and so on via below link: http://127.0.0.1:8001/ http://127.0.0.1:8001/api/v1 http://127.0.0.1:8001/api/v1/namespaces http://127.0.0.1:8001/api/v1/namespaces/default http://127.0.0.1:8001/api/v1/namespaces/sock-shop/pods","title":"Use the proxy"},{"location":"k8s/cka_en/foundamentals/basics/#access-as-application","text":"If we access kubernetes as an application rather than an administrator, we cannot use the kubectl . Instead of kubectl we can use the program curl . We have to send HTTP requests to the cluster. asking for the available nodes. Make sure kubectl proxy is running and serving on http://localhost:8001/ . Execute command below with a -v=9 flag, it shows all the information needed. kubectl get nodes Go through the command's output and find the correct curl request below. curl -v -XGET \\ -H \"Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json\" \\ -H \"User-Agent: kubectl/v1.24.1 (linux/amd64) kubernetes/3ddd0f4\" \\ 'https:///api/v1/nodes?limit=500' Reference *There is a forum-like page hosted by K8s with lots of information around kubectl and how to use it best. * Manage multiple clusters and multiple config files * kubectl command documentation * Shell autocompletion * kubectl cheat sheet * jsonpath in kubectl * kubectl","title":"Access as application"},{"location":"k8s/cka_en/foundamentals/casestudy-calico/","text":"Case Study: Install Calico \u00b6 Scenario: Install Calico Calico Datastore Configure IP Pools Install CNI plugin Install Typha Install calico/node Test networking The Calico Datastore \u00b6 In order to use Kubernetes as the Calico datastore, we need to define the custom resources Calico uses. Download and examine the list of Calico custom resource definitions, and open it in a file editor. wget https://projectcalico.docs.tigera.io/manifests/crds.yaml Create the custom resource definitions in Kubernetes. kubectl apply -f crds.yaml Install calicoctl . To interact directly with the Calico datastore, use the calicoctl client tool. Download the calicoctl binary to a Linux host with access to Kubernetes. The latest release of calicoctl can be found in the git page and replace below v3.23.2 by actual release number. wget https://github.com/projectcalico/calico/releases/download/v3.23.3/calicoctl-linux-amd64 chmod +x calicoctl-linux-amd64 sudo cp calicoctl-linux-amd64 /usr/local/bin/calicoctl Configure calicoctl to access Kubernetes echo \"export KUBECONFIG=/root/.kube/config\" >> ~/.bashrc echo \"export DATASTORE_TYPE=kubernetes\" >> ~/.bashrc echo $KUBECONFIG echo $DATASTORE_TYPE Verify calicoctl can reach the datastore by running\uff1a calicoctl get nodes -o wide Output similar to below: NAME ASN IPV4 IPV6 cka001 cka002 cka003 Nodes are backed by the Kubernetes node object, so we should see names that match kubectl get nodes . kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 NotReady control-plane,master 23m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka002 NotReady 22m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka003 NotReady 21m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 Configure IP Pools \u00b6 A workload is a container or VM that Calico handles the virtual networking for. In Kubernetes, workloads are pods. A workload endpoint is the virtual network interface a workload uses to connect to the Calico network. IP pools are ranges of IP addresses that Calico uses for workload endpoints. Get current IP pools in the cluster. So far, it's empty after fresh installation. calicoctl get ippools NAME CIDR SELECTOR The Pod CIDR is 10.244.0.0/16 we specified via kubeadm init . Let's create two IP pools for use in the cluster. Each pool can not have any overlaps. ipv4-ippool-1: 10.244.0.0/18 ipv4-ippool-2: 10.244.192.0/19 calicoctl apply -f - < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < 4h49m v1.24.0 cka003 Ready 4h49m v1.24.0 Install Typha \u00b6 Typha sits between the Kubernetes API server and per-node daemons like Felix and confd (running in calico/node). It watches the Kubernetes resources and Calico custom resources used by these daemons, and whenever a resource changes it fans out the update to the daemons. This reduces the number of watches the Kubernetes API server needs to serve and improves scalability of the cluster. Provision Certificates We will use mutually authenticated TLS to ensure that calico/node and Typha communicate securely. We generate a certificate authority (CA) and use it to sign a certificate for Typha. Change to directory /etc/kubernetes/pki/ . cd /etc/kubernetes/pki/ Create the CA certificate and key openssl req -x509 -newkey rsa:4096 \\ -keyout typhaca.key \\ -nodes \\ -out typhaca.crt \\ -subj \"/CN=Calico Typha CA\" \\ -days 365 Store the CA certificate in a ConfigMap that Typha & calico/node will access. kubectl create configmap -n kube-system calico-typha-ca --from-file=typhaca.crt Create the Typha key and certificate signing request (CSR). openssl req -newkey rsa:4096 \\ -keyout typha.key \\ -nodes \\ -out typha.csr \\ -subj \"/CN=calico-typha\" The certificate presents the Common Name (CN) as calico-typha . calico/node will be configured to verify this name. Sign the Typha certificate with the CA. openssl x509 -req -in typha.csr \\ -CA typhaca.crt \\ -CAkey typhaca.key \\ -CAcreateserial \\ -out typha.crt \\ -days 365 Signature ok subject=CN = calico-typha Getting CA Private Key Store the Typha key and certificate in a secret that Typha will access kubectl create secret generic -n kube-system calico-typha-certs --from-file=typha.key --from-file=typha.crt Provision RBAC Change to home directory. cd ~ Create a ServiceAccount that will be used to run Typha. kubectl create serviceaccount -n kube-system calico-typha Define a cluster role for Typha with permission to watch Calico datastore objects. kubectl apply -f - < pingtest-585b76c894-s2tbs 1/1 Running 0 7s 10.244.31.0 cka002 pingtest-585b76c894-vm9wn 1/1 Running 0 7s 10.244.28.64 cka003 Note the IP addresses of the second two pods, then exec into the first one. From inside the pod, ping the other two pod IP addresses. For example: kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # ping 10.244.31.1 -c 4 4 packets transmitted, 4 packets received, 0% packet loss / # ping 10.244.31.0 -c 4 4 packets transmitted, 4 packets received, 0% packet loss / # ping 10.244.28.64 -c 4 4 packets transmitted, 0 packets received, 100% packet loss Check routes \u00b6 From one of the nodes, verify that routes exist to each of the pingtest pods\u2019 IP addresses. For example ip route get 10.244.31.1 ip route get 10.244.31.0 ip route get 10.244.28.64 In the result, the via (it's control-plane) in this example indicates the next-hop for this pod IP, which matches the IP address of the node the pod is scheduled on, as expected. IPAM allocations from different pools. Recall that we created two IP pools, but left one disabled. calicoctl get ippools -o wide Result NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR ipv4-ippool-1 10.244.0.0/18 true Never Never false false all() ipv4-ippool-2 10.244.192.0/19 true Never Never true false all() Enable the second pool. calicoctl --allow-version-mismatch apply -f - < Let's attach to the Pod pingtest-585b76c894-chwjq again. kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # 10.244.203.192 -c 4 4 packets transmitted, 0 packets received, 100 % packet loss Mark here. it's failed. Need further check why the route does not work. Clean up kubectl delete deployments.apps pingtest kubectl delete pod pingtest-ippool-2 Reference End-to-end Calico installation","title":"Calico Installation"},{"location":"k8s/cka_en/foundamentals/casestudy-calico/#case-study-install-calico","text":"Scenario: Install Calico Calico Datastore Configure IP Pools Install CNI plugin Install Typha Install calico/node Test networking","title":"Case Study: Install Calico"},{"location":"k8s/cka_en/foundamentals/casestudy-calico/#the-calico-datastore","text":"In order to use Kubernetes as the Calico datastore, we need to define the custom resources Calico uses. Download and examine the list of Calico custom resource definitions, and open it in a file editor. wget https://projectcalico.docs.tigera.io/manifests/crds.yaml Create the custom resource definitions in Kubernetes. kubectl apply -f crds.yaml Install calicoctl . To interact directly with the Calico datastore, use the calicoctl client tool. Download the calicoctl binary to a Linux host with access to Kubernetes. The latest release of calicoctl can be found in the git page and replace below v3.23.2 by actual release number. wget https://github.com/projectcalico/calico/releases/download/v3.23.3/calicoctl-linux-amd64 chmod +x calicoctl-linux-amd64 sudo cp calicoctl-linux-amd64 /usr/local/bin/calicoctl Configure calicoctl to access Kubernetes echo \"export KUBECONFIG=/root/.kube/config\" >> ~/.bashrc echo \"export DATASTORE_TYPE=kubernetes\" >> ~/.bashrc echo $KUBECONFIG echo $DATASTORE_TYPE Verify calicoctl can reach the datastore by running\uff1a calicoctl get nodes -o wide Output similar to below: NAME ASN IPV4 IPV6 cka001 cka002 cka003 Nodes are backed by the Kubernetes node object, so we should see names that match kubectl get nodes . kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 NotReady control-plane,master 23m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka002 NotReady 22m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka003 NotReady 21m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9","title":"The Calico Datastore"},{"location":"k8s/cka_en/foundamentals/casestudy-calico/#configure-ip-pools","text":"A workload is a container or VM that Calico handles the virtual networking for. In Kubernetes, workloads are pods. A workload endpoint is the virtual network interface a workload uses to connect to the Calico network. IP pools are ranges of IP addresses that Calico uses for workload endpoints. Get current IP pools in the cluster. So far, it's empty after fresh installation. calicoctl get ippools NAME CIDR SELECTOR The Pod CIDR is 10.244.0.0/16 we specified via kubeadm init . Let's create two IP pools for use in the cluster. Each pool can not have any overlaps. ipv4-ippool-1: 10.244.0.0/18 ipv4-ippool-2: 10.244.192.0/19 calicoctl apply -f - < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < 4h49m v1.24.0 cka003 Ready 4h49m v1.24.0","title":"Install CNI plugin"},{"location":"k8s/cka_en/foundamentals/casestudy-calico/#install-typha","text":"Typha sits between the Kubernetes API server and per-node daemons like Felix and confd (running in calico/node). It watches the Kubernetes resources and Calico custom resources used by these daemons, and whenever a resource changes it fans out the update to the daemons. This reduces the number of watches the Kubernetes API server needs to serve and improves scalability of the cluster. Provision Certificates We will use mutually authenticated TLS to ensure that calico/node and Typha communicate securely. We generate a certificate authority (CA) and use it to sign a certificate for Typha. Change to directory /etc/kubernetes/pki/ . cd /etc/kubernetes/pki/ Create the CA certificate and key openssl req -x509 -newkey rsa:4096 \\ -keyout typhaca.key \\ -nodes \\ -out typhaca.crt \\ -subj \"/CN=Calico Typha CA\" \\ -days 365 Store the CA certificate in a ConfigMap that Typha & calico/node will access. kubectl create configmap -n kube-system calico-typha-ca --from-file=typhaca.crt Create the Typha key and certificate signing request (CSR). openssl req -newkey rsa:4096 \\ -keyout typha.key \\ -nodes \\ -out typha.csr \\ -subj \"/CN=calico-typha\" The certificate presents the Common Name (CN) as calico-typha . calico/node will be configured to verify this name. Sign the Typha certificate with the CA. openssl x509 -req -in typha.csr \\ -CA typhaca.crt \\ -CAkey typhaca.key \\ -CAcreateserial \\ -out typha.crt \\ -days 365 Signature ok subject=CN = calico-typha Getting CA Private Key Store the Typha key and certificate in a secret that Typha will access kubectl create secret generic -n kube-system calico-typha-certs --from-file=typha.key --from-file=typha.crt Provision RBAC Change to home directory. cd ~ Create a ServiceAccount that will be used to run Typha. kubectl create serviceaccount -n kube-system calico-typha Define a cluster role for Typha with permission to watch Calico datastore objects. kubectl apply -f - < pingtest-585b76c894-s2tbs 1/1 Running 0 7s 10.244.31.0 cka002 pingtest-585b76c894-vm9wn 1/1 Running 0 7s 10.244.28.64 cka003 Note the IP addresses of the second two pods, then exec into the first one. From inside the pod, ping the other two pod IP addresses. For example: kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # ping 10.244.31.1 -c 4 4 packets transmitted, 4 packets received, 0% packet loss / # ping 10.244.31.0 -c 4 4 packets transmitted, 4 packets received, 0% packet loss / # ping 10.244.28.64 -c 4 4 packets transmitted, 0 packets received, 100% packet loss","title":"Pod to pod pings"},{"location":"k8s/cka_en/foundamentals/casestudy-calico/#check-routes","text":"From one of the nodes, verify that routes exist to each of the pingtest pods\u2019 IP addresses. For example ip route get 10.244.31.1 ip route get 10.244.31.0 ip route get 10.244.28.64 In the result, the via (it's control-plane) in this example indicates the next-hop for this pod IP, which matches the IP address of the node the pod is scheduled on, as expected. IPAM allocations from different pools. Recall that we created two IP pools, but left one disabled. calicoctl get ippools -o wide Result NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR ipv4-ippool-1 10.244.0.0/18 true Never Never false false all() ipv4-ippool-2 10.244.192.0/19 true Never Never true false all() Enable the second pool. calicoctl --allow-version-mismatch apply -f - < Let's attach to the Pod pingtest-585b76c894-chwjq again. kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # 10.244.203.192 -c 4 4 packets transmitted, 0 packets received, 100 % packet loss Mark here. it's failed. Need further check why the route does not work. Clean up kubectl delete deployments.apps pingtest kubectl delete pod pingtest-ippool-2 Reference End-to-end Calico installation","title":"Check routes"},{"location":"k8s/cka_en/foundamentals/casestudy-health-check/","text":"Case Study: Health Check \u00b6 Scenario: Create Deployment and Service Simulate an error (delete index.html) Pod is in unhealth status and is removed from endpoint list Fix the error (revert the index.html) Pod is back to normal and in endpoint list Create Deployment and Service \u00b6 Create Deployment nginx-healthcheck and Service nginx-healthcheck . kubectl apply -f - < nginx-healthcheck-79fc55d944-nwwjc 1/1 Running 0 9s 10.244.112.13 cka002 Access Pod IP via curl command, e.g., above example. curl 10.244.102.14 curl 10.244.112.13 We see a successful index.html content of Nginx below with above example. Check details of Service craeted in above example. kubectl describe svc nginx-healthcheck We will see below output. There are two Pods information listed in Endpoints . Name: nginx-healthcheck Namespace: dev Labels: Annotations: Selector: name=nginx-healthcheck Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 11.244.238.20 IPs: 11.244.238.20 Port: 80/TCP TargetPort: 80/TCP NodePort: 31795/TCP Endpoints: 10.244.102.14:80,10.244.112.13:80 Session Affinity: None External Traffic Policy: Cluster Events: We can also get information of Endpoints. kubectl get endpoints nginx-healthcheck Result NAME ENDPOINTS AGE nginx-healthcheck 10.244.102.14:80,10.244.112.13:80 72s Till now, two nginx-healthcheck Pods are working and providing service as expected. Simulate readinessProbe Failure \u00b6 Let's simulate an error by deleting and index.html file in on of nginx-healthcheck Pod and see what's readinessProbe will do. First, execute kubectl exec -it -- bash to log into nginx-healthcheck Pod, and delete the index.html file. kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ rm -rf index.html exit After that, let's check the status of above Pod that index.html file was deleted. kubectl describe pod nginx-healthcheck-79fc55d944-jw887 We can now see Readiness probe failed error event message. ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m8s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-jw887 to cka003 Normal Pulled 2m7s kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m7s kubelet Created container nginx-healthcheck Normal Started 2m7s kubelet Started container nginx-healthcheck Warning Unhealthy 2s (x2 over 7s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 403 Let's check another Pod. kubectl describe pod nginx-healthcheck-79fc55d944-nwwjc There is no error info. ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 3m46s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-nwwjc to cka002 Normal Pulled 3m45s kubelet Container image \"nginx:latest\" already present on machine Normal Created 3m45s kubelet Created container nginx-healthcheck Normal Started 3m45s kubelet Started container nginx-healthcheck Now, access Pod IP via curl command and see what the result of each Pod. curl 10.244.102.14 curl 10.244.112.13 Result: curl 10.244.102.14 failed with 403 Forbidden error below. curl 10.244.112.13 works well. Let's check current status of Nginx Service after one of Pods runs into failure. kubectl describe svc nginx-healthcheck In below output, there is only one Pod information listed in Endpoint. Name: nginx-healthcheck Namespace: dev Labels: Annotations: Selector: name=nginx-healthcheck Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 11.244.238.20 IPs: 11.244.238.20 Port: 80/TCP TargetPort: 80/TCP NodePort: 31795/TCP Endpoints: 10.244.112.13:80 Session Affinity: None External Traffic Policy: Cluster Events: Same result we can get by checking information of Endpoints, which is only Pod is running. kubectl get endpoints nginx-healthcheck Output: NAME ENDPOINTS AGE nginx-healthcheck 10.244.112.13:80 6m5s Fix readinessProbe Failure \u00b6 Let's re-create the index.html file again in the Pod. kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ cat > index.html << EOF Welcome to nginx!

    Welcome to nginx!

    If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

    For online documentation and support please refer to nginx.org.
    Commercial support is available at nginx.com.

    Thank you for using nginx.

    EOF exit We now can see that two Pods are back to Endpoints to provide service now. kubectl describe svc nginx-healthcheck kubectl get endpoints nginx-healthcheck Re-access Pod IP via curl command and we can see both are back to normal status. curl 10.244.102.14 curl 10.244.112.13 Verify the Pod status again. kubectl describe pod nginx-healthcheck-79fc55d944-jw887 Conclusion: By delete the index.html file, the Pod is in unhealth status and is removed from endpoint list. One one health Pod can provide normal service. Clean up kubectl delete service nginx-healthcheck kubectl delete deployment nginx-healthcheck Simulate livenessProbe Failure \u00b6 Re-create Deployment nginx-healthcheck and Service nginx-healthcheck . Deployment: NAME READY UP-TO-DATE AVAILABLE AGE nginx-healthcheck 0/2 2 0 7s Pods: NAME READY STATUS RESTARTS AGE nginx-healthcheck-79fc55d944-lknp9 1/1 Running 0 96s nginx-healthcheck-79fc55d944-wntmg 1/1 Running 0 96s Change nginx default listening port from 80 to 90 to simulate livenessProbe Failure. livenessProbe check the live status via port 80 . kubectl exec -it nginx-healthcheck-79fc55d944-lknp9 -- bash root@nginx-healthcheck-79fc55d944-lknp9:/# cd /etc/nginx/conf.d root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# sed -i 's/80/90/g' default.conf root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# nginx -s reload 2022/07/24 12:59:45 [notice] 79#79: signal process started The Pod runs into failure. kubectl describe pod nginx-healthcheck-79fc55d944-lknp9 We can see livenessProbe failed error event message. Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 17m default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-lknp9 to cka003 Normal Pulled 2m47s (x2 over 17m) kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m47s (x2 over 17m) kubelet Created container nginx-healthcheck Normal Started 2m47s (x2 over 17m) kubelet Started container nginx-healthcheck Warning Unhealthy 2m47s (x4 over 2m57s) kubelet Readiness probe failed: Get \"http://10.244.102.46:80/\": dial tcp 10.244.102.46:80: connect: connection refused Warning Unhealthy 2m47s (x3 over 2m57s) kubelet Liveness probe failed: dial tcp 10.244.102.46:80: connect: connection refused Normal Killing 2m47s kubelet Container nginx-healthcheck failed liveness probe, will be restarted Once failure detected by livenessProbe , the container will restarted again automatically. The default.conf we modified will be replaced by default file and the container status is up and normal.","title":"Health Check"},{"location":"k8s/cka_en/foundamentals/casestudy-health-check/#case-study-health-check","text":"Scenario: Create Deployment and Service Simulate an error (delete index.html) Pod is in unhealth status and is removed from endpoint list Fix the error (revert the index.html) Pod is back to normal and in endpoint list","title":"Case Study: Health Check"},{"location":"k8s/cka_en/foundamentals/casestudy-health-check/#create-deployment-and-service","text":"Create Deployment nginx-healthcheck and Service nginx-healthcheck . kubectl apply -f - < nginx-healthcheck-79fc55d944-nwwjc 1/1 Running 0 9s 10.244.112.13 cka002 Access Pod IP via curl command, e.g., above example. curl 10.244.102.14 curl 10.244.112.13 We see a successful index.html content of Nginx below with above example. Check details of Service craeted in above example. kubectl describe svc nginx-healthcheck We will see below output. There are two Pods information listed in Endpoints . Name: nginx-healthcheck Namespace: dev Labels: Annotations: Selector: name=nginx-healthcheck Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 11.244.238.20 IPs: 11.244.238.20 Port: 80/TCP TargetPort: 80/TCP NodePort: 31795/TCP Endpoints: 10.244.102.14:80,10.244.112.13:80 Session Affinity: None External Traffic Policy: Cluster Events: We can also get information of Endpoints. kubectl get endpoints nginx-healthcheck Result NAME ENDPOINTS AGE nginx-healthcheck 10.244.102.14:80,10.244.112.13:80 72s Till now, two nginx-healthcheck Pods are working and providing service as expected.","title":"Create Deployment and Service"},{"location":"k8s/cka_en/foundamentals/casestudy-health-check/#simulate-readinessprobe-failure","text":"Let's simulate an error by deleting and index.html file in on of nginx-healthcheck Pod and see what's readinessProbe will do. First, execute kubectl exec -it -- bash to log into nginx-healthcheck Pod, and delete the index.html file. kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ rm -rf index.html exit After that, let's check the status of above Pod that index.html file was deleted. kubectl describe pod nginx-healthcheck-79fc55d944-jw887 We can now see Readiness probe failed error event message. ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m8s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-jw887 to cka003 Normal Pulled 2m7s kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m7s kubelet Created container nginx-healthcheck Normal Started 2m7s kubelet Started container nginx-healthcheck Warning Unhealthy 2s (x2 over 7s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 403 Let's check another Pod. kubectl describe pod nginx-healthcheck-79fc55d944-nwwjc There is no error info. ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 3m46s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-nwwjc to cka002 Normal Pulled 3m45s kubelet Container image \"nginx:latest\" already present on machine Normal Created 3m45s kubelet Created container nginx-healthcheck Normal Started 3m45s kubelet Started container nginx-healthcheck Now, access Pod IP via curl command and see what the result of each Pod. curl 10.244.102.14 curl 10.244.112.13 Result: curl 10.244.102.14 failed with 403 Forbidden error below. curl 10.244.112.13 works well. Let's check current status of Nginx Service after one of Pods runs into failure. kubectl describe svc nginx-healthcheck In below output, there is only one Pod information listed in Endpoint. Name: nginx-healthcheck Namespace: dev Labels: Annotations: Selector: name=nginx-healthcheck Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 11.244.238.20 IPs: 11.244.238.20 Port: 80/TCP TargetPort: 80/TCP NodePort: 31795/TCP Endpoints: 10.244.112.13:80 Session Affinity: None External Traffic Policy: Cluster Events: Same result we can get by checking information of Endpoints, which is only Pod is running. kubectl get endpoints nginx-healthcheck Output: NAME ENDPOINTS AGE nginx-healthcheck 10.244.112.13:80 6m5s","title":"Simulate readinessProbe Failure"},{"location":"k8s/cka_en/foundamentals/casestudy-health-check/#fix-readinessprobe-failure","text":"Let's re-create the index.html file again in the Pod. kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ cat > index.html << EOF Welcome to nginx!

    Welcome to nginx!

    If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

    For online documentation and support please refer to nginx.org.
    Commercial support is available at nginx.com.

    Thank you for using nginx.

    EOF exit We now can see that two Pods are back to Endpoints to provide service now. kubectl describe svc nginx-healthcheck kubectl get endpoints nginx-healthcheck Re-access Pod IP via curl command and we can see both are back to normal status. curl 10.244.102.14 curl 10.244.112.13 Verify the Pod status again. kubectl describe pod nginx-healthcheck-79fc55d944-jw887 Conclusion: By delete the index.html file, the Pod is in unhealth status and is removed from endpoint list. One one health Pod can provide normal service. Clean up kubectl delete service nginx-healthcheck kubectl delete deployment nginx-healthcheck","title":"Fix readinessProbe Failure"},{"location":"k8s/cka_en/foundamentals/casestudy-health-check/#simulate-livenessprobe-failure","text":"Re-create Deployment nginx-healthcheck and Service nginx-healthcheck . Deployment: NAME READY UP-TO-DATE AVAILABLE AGE nginx-healthcheck 0/2 2 0 7s Pods: NAME READY STATUS RESTARTS AGE nginx-healthcheck-79fc55d944-lknp9 1/1 Running 0 96s nginx-healthcheck-79fc55d944-wntmg 1/1 Running 0 96s Change nginx default listening port from 80 to 90 to simulate livenessProbe Failure. livenessProbe check the live status via port 80 . kubectl exec -it nginx-healthcheck-79fc55d944-lknp9 -- bash root@nginx-healthcheck-79fc55d944-lknp9:/# cd /etc/nginx/conf.d root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# sed -i 's/80/90/g' default.conf root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# nginx -s reload 2022/07/24 12:59:45 [notice] 79#79: signal process started The Pod runs into failure. kubectl describe pod nginx-healthcheck-79fc55d944-lknp9 We can see livenessProbe failed error event message. Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 17m default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-lknp9 to cka003 Normal Pulled 2m47s (x2 over 17m) kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m47s (x2 over 17m) kubelet Created container nginx-healthcheck Normal Started 2m47s (x2 over 17m) kubelet Started container nginx-healthcheck Warning Unhealthy 2m47s (x4 over 2m57s) kubelet Readiness probe failed: Get \"http://10.244.102.46:80/\": dial tcp 10.244.102.46:80: connect: connection refused Warning Unhealthy 2m47s (x3 over 2m57s) kubelet Liveness probe failed: dial tcp 10.244.102.46:80: connect: connection refused Normal Killing 2m47s kubelet Container nginx-healthcheck failed liveness probe, will be restarted Once failure detected by livenessProbe , the container will restarted again automatically. The default.conf we modified will be replaced by default file and the container status is up and normal.","title":"Simulate livenessProbe Failure"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/","text":"Case Study: Operations on Resources \u00b6 Scenario: Node Label Annotation Namespace ServiceAccount Authorization Grant API access authorization to default ServiceAccount Deployment Expose Service Scale out the Deployment Rolling update Rolling back update Event Logging Node Label \u00b6 Add/update/remove node Label. # Update node label kubectl label node cka002 node=demonode # Get node info with label info kubectl get node --show-labels # Search node by label kubectl get node -l node=demonode # Remove a lable of node kubectl label node cka002 node- Annotation \u00b6 Create Nginx deployment kubectl create deploy nginx --image=nginx:mainline Get Annotation info. kubectl describe deployment/nginx Result ...... Labels: app=nginx Annotations: deployment.kubernetes.io/revision: 1 Selector: app=nginx ...... Add new Annotation. kubectl annotate deployment nginx owner=James.H Now annotation looks like below. ...... Labels: app=nginx Annotations: deployment.kubernetes.io/revision: 1 owner: James.H Selector: app=nginx ...... Update/Overwrite Annotation. kubectl annotate deployment/nginx owner=K8s --overwrite Now annotation looks like below. ...... Annotations: deployment.kubernetes.io/revision: 1 owner: K8s Selector: app=nginx ...... Remove Annotation kubectl annotate deployment/nginx owner- ...... Labels: app=nginx Annotations: deployment.kubernetes.io/revision: 1 Selector: app=nginx ...... Clean up kubectl delete deployment nginx Namespace \u00b6 Get current available namespaces. kubectl get namespace Result NAME STATUS AGE default Active 3h45m dev Active 3h11m kube-node-lease Active 3h45m kube-public Active 3h45m kube-system Active 3h45m Get Pod under a specific namespace. kubectl get pod -n kube-system Result NAME READY STATUS RESTARTS AGE calico-kube-controllers-5c64b68895-jr4nl 1/1 Running 0 3h25m calico-node-dsx76 1/1 Running 0 3h25m calico-node-p5rf2 1/1 Running 0 3h25m calico-node-tr22l 1/1 Running 0 3h25m coredns-6d8c4cb4d-g4jxc 1/1 Running 0 3h45m coredns-6d8c4cb4d-sqcvj 1/1 Running 0 3h45m etcd-cka001 1/1 Running 0 3h45m kube-apiserver-cka001 1/1 Running 0 3h45m kube-controller-manager-cka001 1/1 Running 0 3h45m kube-proxy-5cdbj 1/1 Running 0 3h41m kube-proxy-cm4hc 1/1 Running 0 3h45m kube-proxy-g4w52 1/1 Running 0 3h41m kube-scheduler-cka001 1/1 Running 0 3h45m Get Pods in all namespaces. kubectl get pod --all-namespaces kubectl get pod -A ServiceAccount Authorization \u00b6 With Kubernetes 1.23 and lower version, when we create a new namespace, Kubernetes will automatically create a ServiceAccount default and a token default-token-xxxxx . With Kubernetes 1.24, only ServiceAccount default is created automatically when a new namespace is created, need manually create a toke linked to the ServiceAccount default . Here is an example to create a new namespace dev , we can see that only ServiceAcccount: default was created in namespace dev , no secretes (token) linked to the ServiceAccount default . kubectl create namespace dev kubectl get serviceaccount -n dev kubectl get secrets -n dev There is a default cluster role admin . But there is no clusterrole binding to the cluster role admin . kubectl get clusterrole admin kubectl get clusterrolebinding | grep ClusterRole/admin Role and rolebinding is namespaces based. On namespace dev , there is no role and rolebinding. kubectl get role -n dev kubectl get rolebinding -n dev A Secret in the Kubernetes cluster is an object and it is used to store sensitive information such as username, password, and token, etc. The objective of Secrets is to encode or hash the credentials. The secrets can be reused in the various Pod definition file. A kubernetes.io/service-account-token type of Secret is used to store a token that identifies a service account. When using this Secret type, you need to ensure that the kubernetes.io/service-account.name annotation is set to an existing service account name. Let's create token for the ServiceAcccount: default in namespace dev . kubectl apply -f - << EOF apiVersion: v1 kind: Secret metadata: name: default-token-dev namespace: dev annotations: kubernetes.io/service-account.name: \"default\" type: kubernetes.io/service-account-token EOF Now we get ServiceAcccount: default and Secret (token) default-token-dev in namespace dev . kubectl get serviceaccount -n dev kubectl get secrets -n dev Get token of the service account default . TOKEN=$(kubectl -n dev describe secret $(kubectl -n dev get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d ' ') echo $TOKEN Get API Service address. APISERVER=$(kubectl config view | grep https | cut -f 2- -d \":\" | tr -d \" \") echo $APISERVER Get Pod resources in namespace dev via API server with JSON layout. curl $APISERVER/api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN\" --insecure We will receive 403 forbidden error message. The ServiceAccount default does not have authorization to access pod in namespace dev . Let's create a rolebinding rolebinding-admin to bind cluster role admin to service account default in namespapce dev . Hence service account default is granted adminstrator authorization in namespace dev . # Usage: kubectl create rolebinding --clusterrole= --serviceaccount=: --namespace= # Crate rolebinding: kubectl create rolebinding rolebinding-admin --clusterrole=admin --serviceaccount=dev:default --namespace=dev Result looks like below by executing kubectl get rolebinding -n dev . NAME ROLE AGE rolebinding-admin ClusterRole/admin 10s Try again, get pod resources in namespace dev via API server with JSON layout. curl $APISERVER/api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN\" --insecure Clean up. kubectl delete namespace dev Deployment \u00b6 Create a Ubuntu Pod for operation. And attach to the running Pod. kubectl create -f - << EOF apiVersion: v1 kind: Pod metadata: name: ubuntu labels: app: ubuntu spec: containers: - name: ubuntu image: ubuntu:latest command: [\"/bin/sleep\", \"3650d\"] imagePullPolicy: IfNotPresent restartPolicy: Always EOF kubectl exec --stdin --tty ubuntu -- /bin/bash Create a deployment, option --image specifies a image\uff0coption --port specifies port for external access. A pod is also created when deployment is created. kubectl create deployment myapp --image=docker.io/jocatalin/kubernetes-bootcamp:v1 --replicas=1 --port=8080 Get deployment status kubectl get deployment myapp -o wide Result NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR myapp 1/1 1 1 79s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp Get detail information of deployment. kubectl describe deployment myapp Result Name: myapp Namespace: dev CreationTimestamp: Sat, 23 Jul 2022 14:36:43 +0800 Labels: app=myapp Annotations: deployment.kubernetes.io/revision: 1 Selector: app=myapp Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=myapp Containers: kubernetes-bootcamp: Image: docker.io/jocatalin/kubernetes-bootcamp:v1 Port: 8080/TCP Host Port: 0/TCP Environment: Mounts: Volumes: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: NewReplicaSet: myapp-b5d775f5d (1/1 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 95s deployment-controller Scaled up replica set myapp-b5d775f5d to 1 Expose Service \u00b6 Get the Pod and Deployment we created just now. kubectl get deployment myapp -o wide kubectl get pod -o wide Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-b5d775f5d-cx8dx 1/1 Running 0 2m34s 10.244.102.7 cka003 Send http request to the Pod curl 10.244.102.7:8080 with below result. Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 To make pod be accessed outside, we need expose port 8080 to a node port. A related service will be created. kubectl expose deployment myapp --type=NodePort --port=8080 Get details of service myapp by executing kubectl get svc myapp -o wide . NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR myapp NodePort 11.244.74.3 8080:30514/TCP 7s app=myapp Send http request to service port. curl 11.244.74.3:8080 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-cx8dx | v=1 Get more details of the service. kubectl get svc myapp -o yaml kubectl describe svc myapp Get details of related endpoint myapp by executing kubectl get endpoints myapp -o wide . NAME ENDPOINTS AGE myapp 10.244.102.7:8080 43s Send http request to the service and node sucessfully. Pod port 8080 is mapped to node port 32566 . Send http request to node port on cka003 . curl :30514 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 Attach to Ubuntu Pod we created and send http request to the Service and Pod and Node of myapp . kubectl exec --stdin --tty ubuntu -- /bin/bash curl 10.244.102.7:8080 curl 11.244.74.3:8080 curl :30514 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 Scale out Deployment \u00b6 Scale out by replicaset. We set three replicasets to scale out deployment myapp . The number of deployment myapp is now three. kubectl scale deployment myapp --replicas=3 Get status of deployment kubectl get deployment myapp Get status of replicaset kubectl get replicaset Rolling update \u00b6 Command usage: kubectl set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N . With the command kubectl get deployment , we will get deployment name myapp and related container name kubernetes-bootcamp . kubectl get deployment myapp -o wide With the command kubectl set image to update image to many versions and log the change under deployment's annotations with option --record . kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record Current replicas status kubectl get replicaset -o wide -l app=myapp Result. Pods are running on new Replicas. NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR myapp-5dbd68cc99 1 1 0 8s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v2 app=myapp,pod-template-hash=5dbd68cc99 myapp-b5d775f5d 3 3 3 14m kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp,pod-template-hash=b5d775f5d We can get the change history under metadata.annotations . kubectl get deployment myapp -o yaml Result apiVersion : apps/v1 kind : Deployment metadata : annotations : deployment.kubernetes.io/revision : \"2\" kubernetes.io/change-cause : kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true ...... We can also get the change history by command kubectl rollout history , and show details with specific revision --revision= . kubectl rollout history deployment/myapp Result deployment.apps/myapp REVISION CHANGE-CAUSE 1 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true Get rollout history with specific revision. kubectl rollout history deployment/myapp --revision=2 Roll back to previous revision with command kubectl rollout undo , or roll back to specific revision with option --to-revision= . kubectl rollout undo deployment/myapp --to-revision=1 Revision 1 was replaced by new revision 3 now. kubectl rollout history deployment/myapp Result deployment.apps/myapp REVISION CHANGE-CAUSE 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true 3 Event \u00b6 Get detail event info of related Pod. kubectl describe pod myapp-b5d775f5d-jlx6g Result looks like below. ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 54s default-scheduler Successfully assigned dev/myapp-b5d775f5d-jlx6g to cka003 Normal Pulled 53s kubelet Container image \"docker.io/jocatalin/kubernetes-bootcamp:v1\" already present on machine Normal Created 53s kubelet Created container kubernetes-bootcamp Normal Started 53s kubelet Started container kubernetes-bootcamp Get detail event info of entire cluster. kubectl get event Logging \u00b6 Get log info of Pod. kubectl logs -f kubectl logs -f -c Get a Pod logs kubectl logs -f myapp-b5d775f5d-jlx6g Kubernetes Bootcamp App Started At: 2022-07-23T06:54:18.532Z | Running On: myapp-b5d775f5d-jlx6g Get log info of K8s components. kubectl logs kube-apiserver-cka001 -n kube-system kubectl logs kube-controller-manager-cka001 -n kube-system kubectl logs kube-scheduler-cka001 -n kube-system kubectl logs etcd-cka001 -n kube-system systemctl status kubelet journalctl -fu kubelet kubectl logs kube-proxy-5cdbj -n kube-system Clean up. kubectl delete service myapp kubectl delete deployment myapp","title":"Operations on Resources"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#case-study-operations-on-resources","text":"Scenario: Node Label Annotation Namespace ServiceAccount Authorization Grant API access authorization to default ServiceAccount Deployment Expose Service Scale out the Deployment Rolling update Rolling back update Event Logging","title":"Case Study: Operations on Resources"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#node-label","text":"Add/update/remove node Label. # Update node label kubectl label node cka002 node=demonode # Get node info with label info kubectl get node --show-labels # Search node by label kubectl get node -l node=demonode # Remove a lable of node kubectl label node cka002 node-","title":"Node Label"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#annotation","text":"Create Nginx deployment kubectl create deploy nginx --image=nginx:mainline Get Annotation info. kubectl describe deployment/nginx Result ...... Labels: app=nginx Annotations: deployment.kubernetes.io/revision: 1 Selector: app=nginx ...... Add new Annotation. kubectl annotate deployment nginx owner=James.H Now annotation looks like below. ...... Labels: app=nginx Annotations: deployment.kubernetes.io/revision: 1 owner: James.H Selector: app=nginx ...... Update/Overwrite Annotation. kubectl annotate deployment/nginx owner=K8s --overwrite Now annotation looks like below. ...... Annotations: deployment.kubernetes.io/revision: 1 owner: K8s Selector: app=nginx ...... Remove Annotation kubectl annotate deployment/nginx owner- ...... Labels: app=nginx Annotations: deployment.kubernetes.io/revision: 1 Selector: app=nginx ...... Clean up kubectl delete deployment nginx","title":"Annotation"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#namespace","text":"Get current available namespaces. kubectl get namespace Result NAME STATUS AGE default Active 3h45m dev Active 3h11m kube-node-lease Active 3h45m kube-public Active 3h45m kube-system Active 3h45m Get Pod under a specific namespace. kubectl get pod -n kube-system Result NAME READY STATUS RESTARTS AGE calico-kube-controllers-5c64b68895-jr4nl 1/1 Running 0 3h25m calico-node-dsx76 1/1 Running 0 3h25m calico-node-p5rf2 1/1 Running 0 3h25m calico-node-tr22l 1/1 Running 0 3h25m coredns-6d8c4cb4d-g4jxc 1/1 Running 0 3h45m coredns-6d8c4cb4d-sqcvj 1/1 Running 0 3h45m etcd-cka001 1/1 Running 0 3h45m kube-apiserver-cka001 1/1 Running 0 3h45m kube-controller-manager-cka001 1/1 Running 0 3h45m kube-proxy-5cdbj 1/1 Running 0 3h41m kube-proxy-cm4hc 1/1 Running 0 3h45m kube-proxy-g4w52 1/1 Running 0 3h41m kube-scheduler-cka001 1/1 Running 0 3h45m Get Pods in all namespaces. kubectl get pod --all-namespaces kubectl get pod -A","title":"Namespace"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#serviceaccount-authorization","text":"With Kubernetes 1.23 and lower version, when we create a new namespace, Kubernetes will automatically create a ServiceAccount default and a token default-token-xxxxx . With Kubernetes 1.24, only ServiceAccount default is created automatically when a new namespace is created, need manually create a toke linked to the ServiceAccount default . Here is an example to create a new namespace dev , we can see that only ServiceAcccount: default was created in namespace dev , no secretes (token) linked to the ServiceAccount default . kubectl create namespace dev kubectl get serviceaccount -n dev kubectl get secrets -n dev There is a default cluster role admin . But there is no clusterrole binding to the cluster role admin . kubectl get clusterrole admin kubectl get clusterrolebinding | grep ClusterRole/admin Role and rolebinding is namespaces based. On namespace dev , there is no role and rolebinding. kubectl get role -n dev kubectl get rolebinding -n dev A Secret in the Kubernetes cluster is an object and it is used to store sensitive information such as username, password, and token, etc. The objective of Secrets is to encode or hash the credentials. The secrets can be reused in the various Pod definition file. A kubernetes.io/service-account-token type of Secret is used to store a token that identifies a service account. When using this Secret type, you need to ensure that the kubernetes.io/service-account.name annotation is set to an existing service account name. Let's create token for the ServiceAcccount: default in namespace dev . kubectl apply -f - << EOF apiVersion: v1 kind: Secret metadata: name: default-token-dev namespace: dev annotations: kubernetes.io/service-account.name: \"default\" type: kubernetes.io/service-account-token EOF Now we get ServiceAcccount: default and Secret (token) default-token-dev in namespace dev . kubectl get serviceaccount -n dev kubectl get secrets -n dev Get token of the service account default . TOKEN=$(kubectl -n dev describe secret $(kubectl -n dev get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d ' ') echo $TOKEN Get API Service address. APISERVER=$(kubectl config view | grep https | cut -f 2- -d \":\" | tr -d \" \") echo $APISERVER Get Pod resources in namespace dev via API server with JSON layout. curl $APISERVER/api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN\" --insecure We will receive 403 forbidden error message. The ServiceAccount default does not have authorization to access pod in namespace dev . Let's create a rolebinding rolebinding-admin to bind cluster role admin to service account default in namespapce dev . Hence service account default is granted adminstrator authorization in namespace dev . # Usage: kubectl create rolebinding --clusterrole= --serviceaccount=: --namespace= # Crate rolebinding: kubectl create rolebinding rolebinding-admin --clusterrole=admin --serviceaccount=dev:default --namespace=dev Result looks like below by executing kubectl get rolebinding -n dev . NAME ROLE AGE rolebinding-admin ClusterRole/admin 10s Try again, get pod resources in namespace dev via API server with JSON layout. curl $APISERVER/api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN\" --insecure Clean up. kubectl delete namespace dev","title":"ServiceAccount Authorization"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#deployment","text":"Create a Ubuntu Pod for operation. And attach to the running Pod. kubectl create -f - << EOF apiVersion: v1 kind: Pod metadata: name: ubuntu labels: app: ubuntu spec: containers: - name: ubuntu image: ubuntu:latest command: [\"/bin/sleep\", \"3650d\"] imagePullPolicy: IfNotPresent restartPolicy: Always EOF kubectl exec --stdin --tty ubuntu -- /bin/bash Create a deployment, option --image specifies a image\uff0coption --port specifies port for external access. A pod is also created when deployment is created. kubectl create deployment myapp --image=docker.io/jocatalin/kubernetes-bootcamp:v1 --replicas=1 --port=8080 Get deployment status kubectl get deployment myapp -o wide Result NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR myapp 1/1 1 1 79s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp Get detail information of deployment. kubectl describe deployment myapp Result Name: myapp Namespace: dev CreationTimestamp: Sat, 23 Jul 2022 14:36:43 +0800 Labels: app=myapp Annotations: deployment.kubernetes.io/revision: 1 Selector: app=myapp Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=myapp Containers: kubernetes-bootcamp: Image: docker.io/jocatalin/kubernetes-bootcamp:v1 Port: 8080/TCP Host Port: 0/TCP Environment: Mounts: Volumes: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: NewReplicaSet: myapp-b5d775f5d (1/1 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 95s deployment-controller Scaled up replica set myapp-b5d775f5d to 1","title":"Deployment"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#expose-service","text":"Get the Pod and Deployment we created just now. kubectl get deployment myapp -o wide kubectl get pod -o wide Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-b5d775f5d-cx8dx 1/1 Running 0 2m34s 10.244.102.7 cka003 Send http request to the Pod curl 10.244.102.7:8080 with below result. Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 To make pod be accessed outside, we need expose port 8080 to a node port. A related service will be created. kubectl expose deployment myapp --type=NodePort --port=8080 Get details of service myapp by executing kubectl get svc myapp -o wide . NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR myapp NodePort 11.244.74.3 8080:30514/TCP 7s app=myapp Send http request to service port. curl 11.244.74.3:8080 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-cx8dx | v=1 Get more details of the service. kubectl get svc myapp -o yaml kubectl describe svc myapp Get details of related endpoint myapp by executing kubectl get endpoints myapp -o wide . NAME ENDPOINTS AGE myapp 10.244.102.7:8080 43s Send http request to the service and node sucessfully. Pod port 8080 is mapped to node port 32566 . Send http request to node port on cka003 . curl :30514 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 Attach to Ubuntu Pod we created and send http request to the Service and Pod and Node of myapp . kubectl exec --stdin --tty ubuntu -- /bin/bash curl 10.244.102.7:8080 curl 11.244.74.3:8080 curl :30514 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1","title":"Expose Service"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#scale-out-deployment","text":"Scale out by replicaset. We set three replicasets to scale out deployment myapp . The number of deployment myapp is now three. kubectl scale deployment myapp --replicas=3 Get status of deployment kubectl get deployment myapp Get status of replicaset kubectl get replicaset","title":"Scale out Deployment"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#rolling-update","text":"Command usage: kubectl set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N . With the command kubectl get deployment , we will get deployment name myapp and related container name kubernetes-bootcamp . kubectl get deployment myapp -o wide With the command kubectl set image to update image to many versions and log the change under deployment's annotations with option --record . kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record Current replicas status kubectl get replicaset -o wide -l app=myapp Result. Pods are running on new Replicas. NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR myapp-5dbd68cc99 1 1 0 8s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v2 app=myapp,pod-template-hash=5dbd68cc99 myapp-b5d775f5d 3 3 3 14m kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp,pod-template-hash=b5d775f5d We can get the change history under metadata.annotations . kubectl get deployment myapp -o yaml Result apiVersion : apps/v1 kind : Deployment metadata : annotations : deployment.kubernetes.io/revision : \"2\" kubernetes.io/change-cause : kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true ...... We can also get the change history by command kubectl rollout history , and show details with specific revision --revision= . kubectl rollout history deployment/myapp Result deployment.apps/myapp REVISION CHANGE-CAUSE 1 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true Get rollout history with specific revision. kubectl rollout history deployment/myapp --revision=2 Roll back to previous revision with command kubectl rollout undo , or roll back to specific revision with option --to-revision= . kubectl rollout undo deployment/myapp --to-revision=1 Revision 1 was replaced by new revision 3 now. kubectl rollout history deployment/myapp Result deployment.apps/myapp REVISION CHANGE-CAUSE 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true 3 ","title":"Rolling update"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#event","text":"Get detail event info of related Pod. kubectl describe pod myapp-b5d775f5d-jlx6g Result looks like below. ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 54s default-scheduler Successfully assigned dev/myapp-b5d775f5d-jlx6g to cka003 Normal Pulled 53s kubelet Container image \"docker.io/jocatalin/kubernetes-bootcamp:v1\" already present on machine Normal Created 53s kubelet Created container kubernetes-bootcamp Normal Started 53s kubelet Started container kubernetes-bootcamp Get detail event info of entire cluster. kubectl get event","title":"Event"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#logging","text":"Get log info of Pod. kubectl logs -f kubectl logs -f -c Get a Pod logs kubectl logs -f myapp-b5d775f5d-jlx6g Kubernetes Bootcamp App Started At: 2022-07-23T06:54:18.532Z | Running On: myapp-b5d775f5d-jlx6g Get log info of K8s components. kubectl logs kube-apiserver-cka001 -n kube-system kubectl logs kube-controller-manager-cka001 -n kube-system kubectl logs kube-scheduler-cka001 -n kube-system kubectl logs etcd-cka001 -n kube-system systemctl status kubelet journalctl -fu kubelet kubectl logs kube-proxy-5cdbj -n kube-system Clean up. kubectl delete service myapp kubectl delete deployment myapp","title":"Logging"},{"location":"k8s/cka_en/foundamentals/clustermgt/","text":"Cluster Management \u00b6 Scenario: etcd Backup and Restore Install etcdctl Create Deployment Before Backup Backup etcd Create Deployment After Backup Stop Services Stop etcd Restore etcd Start Services Verify etcd Backup and Restore \u00b6 Install etcdctl \u00b6 Download etcd package from Github. wget https://github.com/etcd-io/etcd/releases/download/v3.5.3/etcd-v3.5.3-linux-amd64.tar.gz Unzip and grant execute permission. tar -zxvf etcd-v3.5.3-linux-amd64.tar.gz cp etcd-v3.5.3-linux-amd64/etcdctl /usr/local/bin/ sudo chmod u+x /usr/local/bin/etcdctl Verify etcdctl --help Create Deployment Before Backup \u00b6 Create Deployment before backup. kubectl create deployment app-before-backup --image=nginx Backup etcd \u00b6 Usage * is the actual IP address of Control Plane. * --endpoints : specify where to save backup of etcd, 2379 is etcd port. * --cert : sepcify etcd certificate, which was generated by kubeadm and saved in /etc/kubernetes/pki/etcd/ . * --key : specify etcd certificate key, which was generated by kubeadm and saved in /etc/kubernetes/pki/etcd/ . * --cacert : specify etcd certificate CA, which was generated by kubeadm and saved in /etc/kubernetes/pki/etcd/ . etcdctl \\ --endpoints=https://:2379 \\ --cert=/etc/kubernetes/pki/etcd/server.crt \\ --key=/etc/kubernetes/pki/etcd/server.key \\ --cacert=/etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot-$(date +\"%Y%m%d%H%M%S\").db etcdctl \\ --endpoints=https://:2379 \\ --cert=/etc/kubernetes/pki/etcd/server.crt \\ --key=/etc/kubernetes/pki/etcd/server.key \\ --cacert=/etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot-$(date +\"%Y%m%d%H%M%S\").db Output: {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.328+0800\",\"caller\":\"snapshot/v3_snapshot.go:65\",\"msg\":\"created temporary db file\",\"path\":\"snapshot-20220724185121.db.part\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:211\",\"msg\":\"opened snapshot stream; downloading\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"caller\":\"snapshot/v3_snapshot.go:73\",\"msg\":\"fetching snapshot\",\"endpoint\":\"https://:2379\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.415+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:219\",\"msg\":\"completed snapshot read; closing\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:88\",\"msg\":\"fetched snapshot\",\"endpoint\":\"https://:2379\",\"size\":\"3.6 MB\",\"took\":\"now\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:97\",\"msg\":\"saved\",\"path\":\"snapshot-20220724185121.db\"} Snapshot saved at snapshot-20220724185121.db We can get the backup file in current directory with ls -al command. -rw------- 1 root root 3616800 Jul 24 18:51 snapshot-20220724185121.db Create Deployment After Backup \u00b6 Create Deployment after backup. kubectl create deployment app-after-backup --image=nginx Delete Deployment we created before backup. kubectl delete deployment app-before-backup Check Deployment status kubectl get deploy NAME READY UP-TO-DATE AVAILABLE AGE app-after-backup 1/1 1 1 108s Stop Services \u00b6 Delete etcd directory. mv /var/lib/etcd/ /var/lib/etcd.bak Stop kubelet systemctl stop kubelet Stop kube-apiserver nerdctl -n k8s.io ps -a | grep apiserver 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001 Stop those up status containers. nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0c5e69118f1b nerdctl -n k8s.io stop 638bb602c310 No up status kube-apiserver now. nerdctl -n k8s.io ps -a | grep apiserver 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001 Stop etcd \u00b6 nerdctl -n k8s.io ps -a | grep etcd 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/etcd-cka001 Stop those up status containers. nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0965b195f41a nerdctl -n k8s.io stop 9e1bea9f25d1 No up status etcd now. nerdctl -n k8s.io ps -a | grep etcd 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001 Restore etcd \u00b6 Execute the restore operation on Control Plane node with actual backup file, here it's file snapshot-20220724185121.db . etcdctl snapshot restore snapshot-20220724185121.db \\ --endpoints=:2379 \\ --cert=/etc/kubernetes/pki/etcd/server.crt \\ --key=/etc/kubernetes/pki/etcd/server.key \\ --cacert=/etc/kubernetes/pki/etcd/ca.crt\\ --data-dir=/var/lib/etcd Output: Deprecated: Use `etcdutl snapshot restore` instead. 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:248 restoring snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\", \"stack\": \"go.etcd.io/etcd/etcdutl/v3/snapshot.(*v3Manager).Restore\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/snapshot/v3_snapshot.go:254\\ngo.etcd.io/etcd/etcdutl/v3/etcdutl.SnapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/etcdutl/snapshot_command.go:147\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3/command.snapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/command/snapshot_command.go:129\\ngithub.com/spf13/cobra.(*Command).execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856\\ngithub.com/spf13/cobra.(*Command).ExecuteC\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960\\ngithub.com/spf13/cobra.(*Command).Execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:897\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.Start\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:107\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.MustStart\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:111\\nmain.main\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/main.go:59\\nruntime.main\\n\\t/go/gos/go1.16.15/src/runtime/proc.go:225\"} 2022-07-24T18:57:49+08:00 info membership/store.go:141 Trimming membership information from the backend... 2022-07-24T18:57:49+08:00 info membership/cluster.go:421 added member {\"cluster-id\": \"cdf818194e3a8c32\", \"local-member-id\": \"0\", \"added-peer-id\": \"8e9e05c52164694d\", \"added-peer-peer-urls\": [\"http://localhost:2380\"]} 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:269 restored snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\"} Check if etcd folder is back from restore. tree /var/lib/etcd /var/lib/etcd \u2514\u2500\u2500 member \u251c\u2500\u2500 snap \u2502 \u251c\u2500\u2500 0000000000000001-0000000000000001.snap \u2502 \u2514\u2500\u2500 db \u2514\u2500\u2500 wal \u2514\u2500\u2500 0000000000000000-0000000000000000.wal Start Services \u00b6 Start kubelet . The kube-apiserver and etcd will be started automatically by kubelet . systemctl start kubelet Execute below comamnds to make sure services are all up. systemctl status kubelet.service nerdctl -n k8s.io ps -a | grep etcd nerdctl -n k8s.io ps -a | grep apiserver The current status of etcd . 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 3b8f37c87782 registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 6 seconds ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001 fbbbb628a945 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 6 seconds ago Up k8s://kube-system/etcd-cka001 The current status of apiserver . 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 281cf4c6670d registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 14 seconds ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 5ed8295d92da registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 15 seconds ago Up k8s://kube-system/kube-apiserver-cka001 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001 Verify \u00b6 Check cluster status, if the Pod app-before-backup is there. kubectl get deploy Result NAME READY UP-TO-DATE AVAILABLE AGE app-before-backup 1/1 1 1 11m Upgrade \u00b6 Scenario: Upgrade Evict Control Plane node Check current available version of kubeadm Upgrade kubeadm to new version Check upgrade plan Apply upgrade plan to upgrade to new version Upgrade kubelet and kubectl Enable Control Plane node scheduling Evict Worker nodes Upgrade kubeadm and kubelet Enable Worker node scheduling Reference documentation Upgrade Control Plane \u00b6 Preparation \u00b6 Evict Control Plane node. kubectl drain --ignore-daemonsets kubectl drain cka001 --ignore-daemonsets node/cka001 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-dsx76, kube-system/kube-proxy-cm4hc evicting pod kube-system/calico-kube-controllers-5c64b68895-jr4nl evicting pod kube-system/coredns-6d8c4cb4d-g4jxc evicting pod kube-system/coredns-6d8c4cb4d-sqcvj pod/calico-kube-controllers-5c64b68895-jr4nl evicted pod/coredns-6d8c4cb4d-g4jxc evicted pod/coredns-6d8c4cb4d-sqcvj evicted node/cka001 drained The Control Plane node is now in SchedulingDisabled status. kubectl get node -owide Result NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 Check current available version of kubeadm . apt policy kubeadm kubeadm: Installed: 1.24.0-00 Candidate: 1.24.3-00 Version table: 1.24.3-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.1-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages *** 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 100 /var/lib/dpkg/status 1.23.7-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages ...... Upgrade kubeadm to Candidate: 1.24.2-00 version. sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades Check upgrade plan. kubeadm upgrade plan Get below guideline of upgrade. [upgrade/config] Making sure the configuration is correct: [upgrade/config] Reading configuration from the cluster... [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [preflight] Running pre-flight checks. [upgrade] Running cluster health checks [upgrade] Fetching available versions to upgrade to [upgrade/versions] Cluster version: v1.24.0 [upgrade/versions] kubeadm version: v1.24.2 I0724 19:05:00.111855 1142460 version.go:255] remote version is much newer: v1.24.3; falling back to: stable-1.23 [upgrade/versions] Target version: v1.24.2 [upgrade/versions] Latest version in the v1.23 series: v1.24.2 Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply': COMPONENT CURRENT TARGET kubelet 3 x v1.24.0 v1.24.2 Upgrade to the latest version in the v1.23 series: COMPONENT CURRENT TARGET kube-apiserver v1.24.0 v1.24.2 kube-controller-manager v1.24.0 v1.24.2 kube-scheduler v1.24.0 v1.24.2 kube-proxy v1.24.0 v1.24.2 CoreDNS v1.8.6 v1.8.6 etcd 3.5.1-0 3.5.1-0 You can now apply the upgrade by executing the following command: kubeadm upgrade apply v1.24.2 _____________________________________________________________________ The table below shows the current state of component configs as understood by this version of kubeadm. Configs that have a \"yes\" mark in the \"MANUAL UPGRADE REQUIRED\" column require manual config upgrade or resetting to kubeadm defaults before a successful upgrade can be performed. The version to manually upgrade to is denoted in the \"PREFERRED VERSION\" column. API GROUP CURRENT VERSION PREFERRED VERSION MANUAL UPGRADE REQUIRED kubeproxy.config.k8s.io v1alpha1 v1alpha1 no kubelet.config.k8s.io v1beta1 v1beta1 no _____________________________________________________________________ Upgrade Control Plane \u00b6 Refer to upgrade plan, let's upgrade to v1.24.2 version. kubeadm upgrade apply v1.24.2 With option --etcd-upgrade=false , the etcd can be excluded from the upgrade. kubeadm upgrade apply v1.24.2 --etcd-upgrade=false It's successful when receiving below message. [upgrade/successful] SUCCESS! Your cluster was upgraded to \"v1.24.2\". Enjoy! [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so. Upgrade kubelet and kubectl . sudo apt-get -y install kubelet=1.24.2-00 kubectl=1.24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet Get current node status. kubectl get node NAME STATUS ROLES AGE VERSION cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0 After verify that each node is in Ready status, enable node scheduling. kubectl uncordon kubectl uncordon cka001 Output: node/cka001 uncordoned Check node status again. Make sure all nodes are in Ready status. kubectl get node Output: NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0 Upgrade Worker \u00b6 Preparation for Worker \u00b6 Log on to cka001 Evict Worker nodes, explicitly specify to remove local storage if needed. kubectl drain --ignore-daemonsets --force kubectl drain --ignore-daemonsets --delete-emptydir-data --force If have error on dependency of emptydir , use the 2 nd command. kubectl drain cka002 --ignore-daemonsets --force kubectl drain cka002 --ignore-daemonsets --delete-emptydir-data --force node/cka002 cordoned WARNING: deleting Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet: dev/ubuntu; ignoring DaemonSet-managed Pods: kube-system/calico-node-p5rf2, kube-system/kube-proxy-zvs68 evicting pod ns-netpol/pod-netpol-5b67b6b496-2cgnw evicting pod dev/ubuntu evicting pod dev/app-before-backup-66dc9d5cb-6xc8c evicting pod dev/nfs-client-provisioner-86d7fb78b6-2f5dx evicting pod dev/pod-netpol-2-77478d77ff-l6rzm evicting pod ingress-nginx/ingress-nginx-admission-patch-nk9fv evicting pod ingress-nginx/ingress-nginx-admission-create-lgtdj evicting pod kube-system/coredns-6d8c4cb4d-l4kx4 pod/ingress-nginx-admission-create-lgtdj evicted pod/ingress-nginx-admission-patch-nk9fv evicted pod/nfs-client-provisioner-86d7fb78b6-2f5dx evicted pod/app-before-backup-66dc9d5cb-6xc8c evicted pod/coredns-6d8c4cb4d-l4kx4 evicted pod/pod-netpol-5b67b6b496-2cgnw evicted pod/pod-netpol-2-77478d77ff-l6rzm evicted pod/ubuntu evicted node/cka002 drained Upgrade Workers \u00b6 Log on to cka002 . Download kubeadm with version v1.24.2 . sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades Upgrade kubeadm . sudo kubeadm upgrade node Upgrade kubelet . sudo apt-get -y install kubelet=1.24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet Make sure all nodes are in Ready status, then, enable node scheduling. kubectl uncordon kubectl uncordon cka002 Verify Upgrade \u00b6 Check node status. kubectl get node Result NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.0 Repeat the same on node cka003 . Log onto cka001 . If have error on dependency of emptydir , use the 2 nd command. kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --force kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --delete-emptydir-data --force Log onto cka003 and perform below commands. sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades sudo kubeadm upgrade node sudo apt-get -y install kubelet=1.24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet kubectl get node kubectl uncordon cka003 Get final status of all nodes. kubectl get node NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.2 Summary: Control Plane kubectl get node -owide kubectl drain cka001 --ignore-daemonsets kubectl get node -owide apt policy kubeadm apt-get -y install kubeadm=1.24.0-00 --allow-downgrades kubeadm upgrade plan kubeadm upgrade apply v1.24.0 # kubeadm upgrade apply v1.24.0 --etcd-upgrade = false apt-get -y install kubelet=1.24.0-00 kubectl=1.24.0-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl get node kubectl uncordon cka001 Worker Node On Control Plane kubectl drain cka002 --ignore-daemonsets On Workder Node apt-get -y install kubeadm=1.24.1-00 --allow-downgrades kubeadm upgrade node apt-get -y install kubelet=1.24.1-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl uncordon cka002 Repeat for other Worker nodes","title":"Cluster Management"},{"location":"k8s/cka_en/foundamentals/clustermgt/#cluster-management","text":"Scenario: etcd Backup and Restore Install etcdctl Create Deployment Before Backup Backup etcd Create Deployment After Backup Stop Services Stop etcd Restore etcd Start Services Verify","title":"Cluster Management"},{"location":"k8s/cka_en/foundamentals/clustermgt/#etcd-backup-and-restore","text":"","title":"etcd Backup and Restore"},{"location":"k8s/cka_en/foundamentals/clustermgt/#install-etcdctl","text":"Download etcd package from Github. wget https://github.com/etcd-io/etcd/releases/download/v3.5.3/etcd-v3.5.3-linux-amd64.tar.gz Unzip and grant execute permission. tar -zxvf etcd-v3.5.3-linux-amd64.tar.gz cp etcd-v3.5.3-linux-amd64/etcdctl /usr/local/bin/ sudo chmod u+x /usr/local/bin/etcdctl Verify etcdctl --help","title":"Install etcdctl"},{"location":"k8s/cka_en/foundamentals/clustermgt/#create-deployment-before-backup","text":"Create Deployment before backup. kubectl create deployment app-before-backup --image=nginx","title":"Create Deployment Before Backup"},{"location":"k8s/cka_en/foundamentals/clustermgt/#backup-etcd","text":"Usage * is the actual IP address of Control Plane. * --endpoints : specify where to save backup of etcd, 2379 is etcd port. * --cert : sepcify etcd certificate, which was generated by kubeadm and saved in /etc/kubernetes/pki/etcd/ . * --key : specify etcd certificate key, which was generated by kubeadm and saved in /etc/kubernetes/pki/etcd/ . * --cacert : specify etcd certificate CA, which was generated by kubeadm and saved in /etc/kubernetes/pki/etcd/ . etcdctl \\ --endpoints=https://:2379 \\ --cert=/etc/kubernetes/pki/etcd/server.crt \\ --key=/etc/kubernetes/pki/etcd/server.key \\ --cacert=/etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot-$(date +\"%Y%m%d%H%M%S\").db etcdctl \\ --endpoints=https://:2379 \\ --cert=/etc/kubernetes/pki/etcd/server.crt \\ --key=/etc/kubernetes/pki/etcd/server.key \\ --cacert=/etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot-$(date +\"%Y%m%d%H%M%S\").db Output: {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.328+0800\",\"caller\":\"snapshot/v3_snapshot.go:65\",\"msg\":\"created temporary db file\",\"path\":\"snapshot-20220724185121.db.part\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:211\",\"msg\":\"opened snapshot stream; downloading\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"caller\":\"snapshot/v3_snapshot.go:73\",\"msg\":\"fetching snapshot\",\"endpoint\":\"https://:2379\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.415+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:219\",\"msg\":\"completed snapshot read; closing\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:88\",\"msg\":\"fetched snapshot\",\"endpoint\":\"https://:2379\",\"size\":\"3.6 MB\",\"took\":\"now\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:97\",\"msg\":\"saved\",\"path\":\"snapshot-20220724185121.db\"} Snapshot saved at snapshot-20220724185121.db We can get the backup file in current directory with ls -al command. -rw------- 1 root root 3616800 Jul 24 18:51 snapshot-20220724185121.db","title":"Backup etcd"},{"location":"k8s/cka_en/foundamentals/clustermgt/#create-deployment-after-backup","text":"Create Deployment after backup. kubectl create deployment app-after-backup --image=nginx Delete Deployment we created before backup. kubectl delete deployment app-before-backup Check Deployment status kubectl get deploy NAME READY UP-TO-DATE AVAILABLE AGE app-after-backup 1/1 1 1 108s","title":"Create Deployment After Backup"},{"location":"k8s/cka_en/foundamentals/clustermgt/#stop-services","text":"Delete etcd directory. mv /var/lib/etcd/ /var/lib/etcd.bak Stop kubelet systemctl stop kubelet Stop kube-apiserver nerdctl -n k8s.io ps -a | grep apiserver 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001 Stop those up status containers. nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0c5e69118f1b nerdctl -n k8s.io stop 638bb602c310 No up status kube-apiserver now. nerdctl -n k8s.io ps -a | grep apiserver 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001","title":"Stop Services"},{"location":"k8s/cka_en/foundamentals/clustermgt/#stop-etcd","text":"nerdctl -n k8s.io ps -a | grep etcd 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/etcd-cka001 Stop those up status containers. nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0965b195f41a nerdctl -n k8s.io stop 9e1bea9f25d1 No up status etcd now. nerdctl -n k8s.io ps -a | grep etcd 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001","title":"Stop etcd"},{"location":"k8s/cka_en/foundamentals/clustermgt/#restore-etcd","text":"Execute the restore operation on Control Plane node with actual backup file, here it's file snapshot-20220724185121.db . etcdctl snapshot restore snapshot-20220724185121.db \\ --endpoints=:2379 \\ --cert=/etc/kubernetes/pki/etcd/server.crt \\ --key=/etc/kubernetes/pki/etcd/server.key \\ --cacert=/etc/kubernetes/pki/etcd/ca.crt\\ --data-dir=/var/lib/etcd Output: Deprecated: Use `etcdutl snapshot restore` instead. 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:248 restoring snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\", \"stack\": \"go.etcd.io/etcd/etcdutl/v3/snapshot.(*v3Manager).Restore\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/snapshot/v3_snapshot.go:254\\ngo.etcd.io/etcd/etcdutl/v3/etcdutl.SnapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/etcdutl/snapshot_command.go:147\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3/command.snapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/command/snapshot_command.go:129\\ngithub.com/spf13/cobra.(*Command).execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856\\ngithub.com/spf13/cobra.(*Command).ExecuteC\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960\\ngithub.com/spf13/cobra.(*Command).Execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:897\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.Start\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:107\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.MustStart\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:111\\nmain.main\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/main.go:59\\nruntime.main\\n\\t/go/gos/go1.16.15/src/runtime/proc.go:225\"} 2022-07-24T18:57:49+08:00 info membership/store.go:141 Trimming membership information from the backend... 2022-07-24T18:57:49+08:00 info membership/cluster.go:421 added member {\"cluster-id\": \"cdf818194e3a8c32\", \"local-member-id\": \"0\", \"added-peer-id\": \"8e9e05c52164694d\", \"added-peer-peer-urls\": [\"http://localhost:2380\"]} 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:269 restored snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\"} Check if etcd folder is back from restore. tree /var/lib/etcd /var/lib/etcd \u2514\u2500\u2500 member \u251c\u2500\u2500 snap \u2502 \u251c\u2500\u2500 0000000000000001-0000000000000001.snap \u2502 \u2514\u2500\u2500 db \u2514\u2500\u2500 wal \u2514\u2500\u2500 0000000000000000-0000000000000000.wal","title":"Restore etcd"},{"location":"k8s/cka_en/foundamentals/clustermgt/#start-services","text":"Start kubelet . The kube-apiserver and etcd will be started automatically by kubelet . systemctl start kubelet Execute below comamnds to make sure services are all up. systemctl status kubelet.service nerdctl -n k8s.io ps -a | grep etcd nerdctl -n k8s.io ps -a | grep apiserver The current status of etcd . 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 3b8f37c87782 registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 6 seconds ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001 fbbbb628a945 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 6 seconds ago Up k8s://kube-system/etcd-cka001 The current status of apiserver . 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 281cf4c6670d registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 14 seconds ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 5ed8295d92da registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 15 seconds ago Up k8s://kube-system/kube-apiserver-cka001 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001","title":"Start Services"},{"location":"k8s/cka_en/foundamentals/clustermgt/#verify","text":"Check cluster status, if the Pod app-before-backup is there. kubectl get deploy Result NAME READY UP-TO-DATE AVAILABLE AGE app-before-backup 1/1 1 1 11m","title":"Verify"},{"location":"k8s/cka_en/foundamentals/clustermgt/#upgrade","text":"Scenario: Upgrade Evict Control Plane node Check current available version of kubeadm Upgrade kubeadm to new version Check upgrade plan Apply upgrade plan to upgrade to new version Upgrade kubelet and kubectl Enable Control Plane node scheduling Evict Worker nodes Upgrade kubeadm and kubelet Enable Worker node scheduling Reference documentation","title":"Upgrade"},{"location":"k8s/cka_en/foundamentals/clustermgt/#upgrade-control-plane","text":"","title":"Upgrade Control Plane"},{"location":"k8s/cka_en/foundamentals/clustermgt/#preparation","text":"Evict Control Plane node. kubectl drain --ignore-daemonsets kubectl drain cka001 --ignore-daemonsets node/cka001 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-dsx76, kube-system/kube-proxy-cm4hc evicting pod kube-system/calico-kube-controllers-5c64b68895-jr4nl evicting pod kube-system/coredns-6d8c4cb4d-g4jxc evicting pod kube-system/coredns-6d8c4cb4d-sqcvj pod/calico-kube-controllers-5c64b68895-jr4nl evicted pod/coredns-6d8c4cb4d-g4jxc evicted pod/coredns-6d8c4cb4d-sqcvj evicted node/cka001 drained The Control Plane node is now in SchedulingDisabled status. kubectl get node -owide Result NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 Check current available version of kubeadm . apt policy kubeadm kubeadm: Installed: 1.24.0-00 Candidate: 1.24.3-00 Version table: 1.24.3-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.1-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages *** 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 100 /var/lib/dpkg/status 1.23.7-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages ...... Upgrade kubeadm to Candidate: 1.24.2-00 version. sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades Check upgrade plan. kubeadm upgrade plan Get below guideline of upgrade. [upgrade/config] Making sure the configuration is correct: [upgrade/config] Reading configuration from the cluster... [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [preflight] Running pre-flight checks. [upgrade] Running cluster health checks [upgrade] Fetching available versions to upgrade to [upgrade/versions] Cluster version: v1.24.0 [upgrade/versions] kubeadm version: v1.24.2 I0724 19:05:00.111855 1142460 version.go:255] remote version is much newer: v1.24.3; falling back to: stable-1.23 [upgrade/versions] Target version: v1.24.2 [upgrade/versions] Latest version in the v1.23 series: v1.24.2 Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply': COMPONENT CURRENT TARGET kubelet 3 x v1.24.0 v1.24.2 Upgrade to the latest version in the v1.23 series: COMPONENT CURRENT TARGET kube-apiserver v1.24.0 v1.24.2 kube-controller-manager v1.24.0 v1.24.2 kube-scheduler v1.24.0 v1.24.2 kube-proxy v1.24.0 v1.24.2 CoreDNS v1.8.6 v1.8.6 etcd 3.5.1-0 3.5.1-0 You can now apply the upgrade by executing the following command: kubeadm upgrade apply v1.24.2 _____________________________________________________________________ The table below shows the current state of component configs as understood by this version of kubeadm. Configs that have a \"yes\" mark in the \"MANUAL UPGRADE REQUIRED\" column require manual config upgrade or resetting to kubeadm defaults before a successful upgrade can be performed. The version to manually upgrade to is denoted in the \"PREFERRED VERSION\" column. API GROUP CURRENT VERSION PREFERRED VERSION MANUAL UPGRADE REQUIRED kubeproxy.config.k8s.io v1alpha1 v1alpha1 no kubelet.config.k8s.io v1beta1 v1beta1 no _____________________________________________________________________","title":"Preparation"},{"location":"k8s/cka_en/foundamentals/clustermgt/#upgrade-control-plane_1","text":"Refer to upgrade plan, let's upgrade to v1.24.2 version. kubeadm upgrade apply v1.24.2 With option --etcd-upgrade=false , the etcd can be excluded from the upgrade. kubeadm upgrade apply v1.24.2 --etcd-upgrade=false It's successful when receiving below message. [upgrade/successful] SUCCESS! Your cluster was upgraded to \"v1.24.2\". Enjoy! [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so. Upgrade kubelet and kubectl . sudo apt-get -y install kubelet=1.24.2-00 kubectl=1.24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet Get current node status. kubectl get node NAME STATUS ROLES AGE VERSION cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0 After verify that each node is in Ready status, enable node scheduling. kubectl uncordon kubectl uncordon cka001 Output: node/cka001 uncordoned Check node status again. Make sure all nodes are in Ready status. kubectl get node Output: NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0","title":"Upgrade Control Plane"},{"location":"k8s/cka_en/foundamentals/clustermgt/#upgrade-worker","text":"","title":"Upgrade Worker"},{"location":"k8s/cka_en/foundamentals/clustermgt/#preparation-for-worker","text":"Log on to cka001 Evict Worker nodes, explicitly specify to remove local storage if needed. kubectl drain --ignore-daemonsets --force kubectl drain --ignore-daemonsets --delete-emptydir-data --force If have error on dependency of emptydir , use the 2 nd command. kubectl drain cka002 --ignore-daemonsets --force kubectl drain cka002 --ignore-daemonsets --delete-emptydir-data --force node/cka002 cordoned WARNING: deleting Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet: dev/ubuntu; ignoring DaemonSet-managed Pods: kube-system/calico-node-p5rf2, kube-system/kube-proxy-zvs68 evicting pod ns-netpol/pod-netpol-5b67b6b496-2cgnw evicting pod dev/ubuntu evicting pod dev/app-before-backup-66dc9d5cb-6xc8c evicting pod dev/nfs-client-provisioner-86d7fb78b6-2f5dx evicting pod dev/pod-netpol-2-77478d77ff-l6rzm evicting pod ingress-nginx/ingress-nginx-admission-patch-nk9fv evicting pod ingress-nginx/ingress-nginx-admission-create-lgtdj evicting pod kube-system/coredns-6d8c4cb4d-l4kx4 pod/ingress-nginx-admission-create-lgtdj evicted pod/ingress-nginx-admission-patch-nk9fv evicted pod/nfs-client-provisioner-86d7fb78b6-2f5dx evicted pod/app-before-backup-66dc9d5cb-6xc8c evicted pod/coredns-6d8c4cb4d-l4kx4 evicted pod/pod-netpol-5b67b6b496-2cgnw evicted pod/pod-netpol-2-77478d77ff-l6rzm evicted pod/ubuntu evicted node/cka002 drained","title":"Preparation for Worker"},{"location":"k8s/cka_en/foundamentals/clustermgt/#upgrade-workers","text":"Log on to cka002 . Download kubeadm with version v1.24.2 . sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades Upgrade kubeadm . sudo kubeadm upgrade node Upgrade kubelet . sudo apt-get -y install kubelet=1.24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet Make sure all nodes are in Ready status, then, enable node scheduling. kubectl uncordon kubectl uncordon cka002","title":"Upgrade Workers"},{"location":"k8s/cka_en/foundamentals/clustermgt/#verify-upgrade","text":"Check node status. kubectl get node Result NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.0 Repeat the same on node cka003 . Log onto cka001 . If have error on dependency of emptydir , use the 2 nd command. kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --force kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --delete-emptydir-data --force Log onto cka003 and perform below commands. sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades sudo kubeadm upgrade node sudo apt-get -y install kubelet=1.24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet kubectl get node kubectl uncordon cka003 Get final status of all nodes. kubectl get node NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.2 Summary: Control Plane kubectl get node -owide kubectl drain cka001 --ignore-daemonsets kubectl get node -owide apt policy kubeadm apt-get -y install kubeadm=1.24.0-00 --allow-downgrades kubeadm upgrade plan kubeadm upgrade apply v1.24.0 # kubeadm upgrade apply v1.24.0 --etcd-upgrade = false apt-get -y install kubelet=1.24.0-00 kubectl=1.24.0-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl get node kubectl uncordon cka001 Worker Node On Control Plane kubectl drain cka002 --ignore-daemonsets On Workder Node apt-get -y install kubeadm=1.24.1-00 --allow-downgrades kubeadm upgrade node apt-get -y install kubelet=1.24.1-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl uncordon cka002 Repeat for other Worker nodes","title":"Verify Upgrade"},{"location":"k8s/cka_en/foundamentals/configuration/","text":"","title":"Configuration"},{"location":"k8s/cka_en/foundamentals/daemonset/","text":"DaemonSet \u00b6 Scenario: Create DaemonSet. The DaemonSet will run its pod on each node. Demo: Create DaemonSet daemonset-busybox . kubectl apply -f - << EOF apiVersion: apps/v1 kind: DaemonSet metadata: name: daemonset-busybox labels: app: daemonset-busybox spec: selector: matchLabels: app: daemonset-busybox template: metadata: labels: app: daemonset-busybox spec: tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: busybox image: busybox:1.28 args: - sleep - \"10000\" EOF Get status of DaemonSet. kubectl get daemonsets daemonset-busybox Result NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset-busybox 3 3 3 3 3 5m33s Get DaemonSet Pod status. It's deployed on each node. kubectl get pod -o wide Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES daemonset-busybox-54cj5 1/1 Running 0 44s 10.244.102.4 cka003 daemonset-busybox-5tl55 1/1 Running 0 44s 10.244.228.197 cka001 daemonset-busybox-wg225 1/1 Running 0 44s 10.244.112.5 cka002 Clean up. kubectl delete daemonset daemonset-busybox","title":"DaemonSet"},{"location":"k8s/cka_en/foundamentals/daemonset/#daemonset","text":"Scenario: Create DaemonSet. The DaemonSet will run its pod on each node. Demo: Create DaemonSet daemonset-busybox . kubectl apply -f - << EOF apiVersion: apps/v1 kind: DaemonSet metadata: name: daemonset-busybox labels: app: daemonset-busybox spec: selector: matchLabels: app: daemonset-busybox template: metadata: labels: app: daemonset-busybox spec: tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: busybox image: busybox:1.28 args: - sleep - \"10000\" EOF Get status of DaemonSet. kubectl get daemonsets daemonset-busybox Result NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset-busybox 3 3 3 3 3 5m33s Get DaemonSet Pod status. It's deployed on each node. kubectl get pod -o wide Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES daemonset-busybox-54cj5 1/1 Running 0 44s 10.244.102.4 cka003 daemonset-busybox-5tl55 1/1 Running 0 44s 10.244.228.197 cka001 daemonset-busybox-wg225 1/1 Running 0 44s 10.244.112.5 cka002 Clean up. kubectl delete daemonset daemonset-busybox","title":"DaemonSet"},{"location":"k8s/cka_en/foundamentals/deployment/","text":"Deployment \u00b6 Scenario: Modify Existing Deployment, e.g., add port number in below demo. Demo: Create Deployment nginx . kubectl create deployment nginx --image = nginx Execute command below to get yaml template with port number. The option --port=8080 specified the port that this container exposes. kubectl create deployment nginx --image = nginx --port = 8080 --dry-run = client -o yaml Then we get to know the path to add port number, like below. kubectl explain deployment.spec.template.spec.containers.ports.containerPort Execute command below to edit the Deployemnt. kubectl edit deployment nginx Add below two lines to specify port number with 8080 and protocol is TCP . spec : template : spec : containers : - image : nginx name : nginx ports : - containerPort : 8080 protocol : TCP Use command kubectl describe deployment , we can see the port number was added. Pod Template : Labels : app=nginx Containers : nginx : Image : nginx Port : 8080/TCP Host Port : 0/TCP Environment : Mounts : Volumes : With command kubectl describe pod , we can see the port number was added. Containers : nginx : Container ID : containerd://af4a1243f981497074b5c006ac55fcf795688399871d1dfe91a095321f5c91aa Image : nginx Image ID : docker.io/library/nginx@sha256:1761fb5661e4d77e107427d8012ad3a5955007d997e0f4a3d41acc9ff20467c7 Port : 8080/TCP Host Port : 0/TCP State : Running Started : Sun, 24 Jul 2022 22:50:12 +0800 Ready : True Restart Count : 0 Environment : Mounts : /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hftdt (ro) Info: Some key fields of deployment (use kubectl explain ): deployment.spec.revisionHistoryLimit : The number of old ReplicaSets to retain to allow rollback. Defaults to 10 . deployment.spec.strategy.type : Type of deployment. Can be Recreate or RollingUpdate . Default is RollingUpdate . deployment.spec.strategy.rollingUpdate.maxUnavailable : The maximum number of pods that can be unavailable during the update. Defaults to 25%. deployment.spec.strategy.rollingUpdate.maxSurge : The maximum number of pods that can be scheduled above the desired number of pods. Defaults to 25%. This can not be 0 if MaxUnavailable is 0. deployment.spec.minReadySeconds : Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready).","title":"Deployment"},{"location":"k8s/cka_en/foundamentals/deployment/#deployment","text":"Scenario: Modify Existing Deployment, e.g., add port number in below demo. Demo: Create Deployment nginx . kubectl create deployment nginx --image = nginx Execute command below to get yaml template with port number. The option --port=8080 specified the port that this container exposes. kubectl create deployment nginx --image = nginx --port = 8080 --dry-run = client -o yaml Then we get to know the path to add port number, like below. kubectl explain deployment.spec.template.spec.containers.ports.containerPort Execute command below to edit the Deployemnt. kubectl edit deployment nginx Add below two lines to specify port number with 8080 and protocol is TCP . spec : template : spec : containers : - image : nginx name : nginx ports : - containerPort : 8080 protocol : TCP Use command kubectl describe deployment , we can see the port number was added. Pod Template : Labels : app=nginx Containers : nginx : Image : nginx Port : 8080/TCP Host Port : 0/TCP Environment : Mounts : Volumes : With command kubectl describe pod , we can see the port number was added. Containers : nginx : Container ID : containerd://af4a1243f981497074b5c006ac55fcf795688399871d1dfe91a095321f5c91aa Image : nginx Image ID : docker.io/library/nginx@sha256:1761fb5661e4d77e107427d8012ad3a5955007d997e0f4a3d41acc9ff20467c7 Port : 8080/TCP Host Port : 0/TCP State : Running Started : Sun, 24 Jul 2022 22:50:12 +0800 Ready : True Restart Count : 0 Environment : Mounts : /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hftdt (ro) Info: Some key fields of deployment (use kubectl explain ): deployment.spec.revisionHistoryLimit : The number of old ReplicaSets to retain to allow rollback. Defaults to 10 . deployment.spec.strategy.type : Type of deployment. Can be Recreate or RollingUpdate . Default is RollingUpdate . deployment.spec.strategy.rollingUpdate.maxUnavailable : The maximum number of pods that can be unavailable during the update. Defaults to 25%. deployment.spec.strategy.rollingUpdate.maxSurge : The maximum number of pods that can be scheduled above the desired number of pods. Defaults to 25%. This can not be 0 if MaxUnavailable is 0. deployment.spec.minReadySeconds : Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready).","title":"Deployment"},{"location":"k8s/cka_en/foundamentals/docker/","text":"Docker Fundamentals \u00b6 Demo environment \u00b6 Linux: openSUSE 15.3 cat /etc/os-release Output NAME=\"openSUSE Leap\" VERSION=\"15.3\" ID=\"opensuse-leap\" ID_LIKE=\"suse opensuse\" VERSION_ID=\"15.3\" PRETTY_NAME=\"openSUSE Leap 15.3\" ANSI_COLOR=\"0;32\" CPE_NAME=\"cpe:/o:opensuse:leap:15.3\" BUG_REPORT_URL=\"https://bugs.opensuse.org\" HOME_URL=\"https://www.opensuse.org/\" Linux Primitives \u00b6 chroot(using pivot_root) Changes the root directory for a process to any given directory namespaces Different processes see different environments even though they are on the same host/OS mnt (mount points) pid (process tree) net (network interfaces and connectivity) ipc (interprocess communication framework) uts (unix timesharing - domain name, hostname, etc.) uid (user IDs and mappings) cgroups(control groups) manage/limit resource allocation to individual processes Prioritization of processes Apparmor and SELinux profiles Security profiles to govern access to resources Kernel capabilities without capabilities: root can do everything, everybody else may do nothing 38 granular facilities to control privileges seccomp policies Limitation of allowed kernel syscalls Unallowed syscalls lead to process termination Netlink A Linux kernel interface used for inter-process communication (IPC) between both the kernel and userspace processes, and between different userspace processes. Netfilter A framework provided by the Linux kernel that allows various networking-related operations Packet filtering, network address translation, and port translation(iptables/nftables) used to direct network packages to individual containers More inforamtion could refer to LXC/LXD Let's download an image alpine to simulate an root file system under /opt/test folder. mkdir test cd test wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.4-x86_64.tar.gz tar zxvf alpine-minirootfs-3.13.4-x86_64.tar.gz -C alpine-minirootfs/ Current directory structure. tree ./test -L 1 Output ./test \u251c\u2500\u2500 alpine-minirootfs-3.13.4-x86_64.tar.gz \u251c\u2500\u2500 bin \u251c\u2500\u2500 dev \u251c\u2500\u2500 etc \u251c\u2500\u2500 home \u251c\u2500\u2500 lib \u251c\u2500\u2500 media \u251c\u2500\u2500 mnt \u251c\u2500\u2500 opt \u251c\u2500\u2500 proc \u251c\u2500\u2500 root \u251c\u2500\u2500 run \u251c\u2500\u2500 sbin \u251c\u2500\u2500 srv \u251c\u2500\u2500 sys \u251c\u2500\u2500 tmp \u251c\u2500\u2500 usr \u2514\u2500\u2500 var Mount folder /opt/test/proc to a file and use command unshare to build a guest system. sudo mount -t tmpfs tmpfs /opt/test/proc sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # ps -ef PID USER TIME COMMAND 1 root 0 :00 /bin/sh 2 root 0 :00 ps -ef / # touch 123 / # ls 123 123 The file 123 created in guest system is accessable and writable from host system. su - ls 123 echo hello > 123 We will see above change in guest system. / # cat 123 hello Let's create two folders /opt/test-1 and /opt/test-2 . mkdir test-1 mkdir test-2 Create two guests system. Mount /opt/test/home/ to different folders for different guests. sudo mount --bind /opt/test-1 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-1\" > 123.1 /home # cat 123.1 test-1 sudo mount --bind /opt/test-2 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-2\" > 123.2 /home # cat 123.2 test-2 ll test/home ll test-1/ ll test-2/ With above demo, the conclusion is that two guests share same home folder on host system and will impact each other. Installing Docker \u00b6 Install Docker engine by referring the guide , and Docker Desktop by referring the guide . Install engine via openSUSE repository automatically. sudo zypper in docker The docker group is automatically created at package installation time. The user can communicate with the local Docker daemon upon its next login. The Docker daemon listens on a local socket which is accessible only by the root user and by the members of the docker group. Add current user to docker group. sudo usermod -aG docker $USER Enable and start Docker engine. sudo systemctl enable docker.service sudo systemctl start docker.service sudo systemctl status docker.service Container lifecycle \u00b6 Overview \u00b6 Pull down below images in advance. docker image pull busybox docker image pull nginx docker image pull alpine docker image pull jenkins/jenkins:lts docker image pull golang:1.12-alpine docker image pull golang Download some docker images. Create and run a new busybox container interactively and connect a pseudo terminal to it. Inside the container, use the top command to find out that /bin/sh is running as process with the PID 1 and top process is also running. After that, just exit. docker image ls docker run -d -it --name busybox_v1 -v /opt/test:/docker busybox:latest /bin/sh docker container ps -a docker exec -it 185efe490507 /bin/sh / # top Mem: 3627396K used, 12731512K free, 10080K shrd, 2920K buff, 2999340K cached CPU: 0 .0% usr 0 .1% sys 0 .0% nic 99 .8% idle 0 .0% io 0 .0% irq 0 .0% sirq Load average: 0 .38 1 .09 1 .29 2 /277 14 PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND 1 0 root S 1332 0 .0 1 0 .0 /bin/sh 8 0 root S 1332 0 .0 2 0 .0 /bin/sh 14 8 root R 1328 0 .0 1 0 .0 top / # exitbuild Start a new nginx container in detached mode. Use the docker exec command to start another shell ( /bin/sh ) in the nginx container. Use ps to find out that sh and ps commands are running in your container. docker run -d -it --name nginx_v1 -v /opt/test:/docker nginx:latest /bin/sh docker container ps -a docker exec -it edb640127a0d /bin/sh # ps /bin/sh: 2 : ps: not found # apt-get update && apt-get install -y procps # ps PID TTY TIME CMD 8 pts/1 00 :00:00 sh 351 pts/1 00 :00:00 ps # exit Now we have two running containers below. docker container ps -a Let's use docker logs to display the logs of the container we just exited from. The option --since 35m means display log in last 35 minutes. docker logs nginx_v1 --details --since 35m docker logs busybox_v1 --details --since 35m Let's make use of this to create a new stage: Use the docker stop command to end your nginx container. docker stop busybox_v1 docker stop nginx_v1 docker container ps -a With above command docker container ps -a , we get a list of all running and exited containers. Remove them with docker rm. Use docker rm $(docker ps -aq) to clean up all containers on your host. Use it with caution! docker rm busybox_v1 docker container ps -a Ports and volumes \u00b6 Now, let's run an nginx webserver in a container and serve a website to the outside world. Start a new nginx container and export the port of the nginx webserver to a random port that is chosen by Docker. Use command docker ps to find you which port the webserver is forwarded. Access the docker with the forwarded port number on host http://localhost: . docker container ps -a docker run -d -P --name nginx_v2 nginx:latest docker container ps -a Start another nginx container and expose port to 1080 on host as an example via http://localhost:1080 . docker run -d -p 1080:80 --name nginx_v3 nginx:latest docker container ps -a Let's make use of this to create a new stage: Use command docker inspect to find out which port is exposed by the image. Network information (ip, gateway, ports, etc.) is part of the output JSON format. docker inspect nginx_v3 Create a file index.html in folder /opt/test with below sample content. < html > < head > < title > Sample Website from my container < body > < h1 > This is a custom website. < p > This website is served from my < a href = \"http://www.docker.com\" target = \"_blank\" > Docker container. Start a new container that bind-mounts host directory /opt/test to container directory /usr/share/nginx/html as a volume, so that NGINX will publish the HTML file wee just created instead of its default message via http://localhost:49159/ below. docker run -d -P --mount type=bind,source=/opt/test/,target=/usr/share/nginx/html --name nginx_v3-1 nginx:latest docker container ps -a Check nginx config file on where is the html home page stored in container. docker exec -it nginx_v3-1 /bin/sh # cd /etc/nginx/conf.d # ls default.conf # cat default.conf server { listen 80; listen [::]:80; server_name localhost; # access_log /var/log/nginx/host.access.log main ; location / { root /usr/share/nginx/html; <-- index index.html index.htm; } # error_page 404 /404.html ; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } # proxy the PHP scripts to Apache listening on 127 .0.0.1:80 # # location ~ \\. php$ { # proxy_pass http://127.0.0.1 ; # } # pass the PHP scripts to FastCGI server listening on 127 .0.0.1:9000 # # location ~ \\. php$ { # root html ; # fastcgi_pass 127 .0.0.1:9000 ; # fastcgi_index index.php ; # fastcgi_param SCRIPT_FILENAME /scripts $fastcgi_script_name ; # include fastcgi_params ; # } # deny access to .htaccess files, if Apache 's document root # concurs with nginx' s one # # location ~ / \\. ht { # deny all ; # } } # cd /usr/share/nginx/html # cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    # It's recommendable to add a persistence with volumes API, instead of storing data in a docker container. Docker supports 2 ways of mount: Bind mounts: mount a local host directory onto a certain path in the container. Everything that was present before in the target directory is hidden (nature of the bind mount). For example, if you have some configuration you want to inject, write your config file, store it on your docker host at /home/container/config and mount the content of this directory to /usr/application/config (assuming the application reads config from there). Command: docker run --mount type=bind,source=,target= \u2026 Named volumes: docker can create a separated storage volume. Its lifecycle is independent from the container but still managed by docker. Upon creation, the content of the mount target is merged into the volume. Command: docker run --mount source=,target= \u2026 How to differentiate between bind mountbuild s and named volumes? When specifying an absolute path, docker assumes a bind mount. When you just give a name (like in a relative path \u201cconfig\u201d), it will assume a named volume and create a volume \u201cconfig\u201d. Note: Persistent storage is 'provided' by the host. It can be a part of the file system on the host directly but also an NFS mount. Dockerfile \u00b6 Let's build an image with a Dockerfile,build tag it and upload it to a registry. Get docker image build history. docker image history nginx:latest Create an empty directory /opt/tmp-1 , change to the directory and create an sample index.html file in /opt/tmp-1 . /opt/tmp-1> cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    Use FROM to extend an existing image, specify the release number. Use COPY to copy a new default website into the image, e.g., /usr/share/nginx/html Create SSL configuration /opt/tmp-1/ssl.conf for nginx. server { listen 443 ssl; server_name localhost; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; location / { root /usr/share/nginx/html; index index.html index.htm; } } Use OpenSSL to create a self-signed certificate so SSL/TLS to work would work. Use the following command to create an encryption key and a certificate. openssl req -x509 -nodes -newkey rsa:4096 -keyout nginx.key -out nginx.crt -days 365 -subj \"/CN=$(hostname)\" To enable encrypted HTTPS, we need to expose port 443 with the EXPOSE directive. The default nginx image only exposes port 80 for unencrypted HTTP. In summary, we create below Dockerfile in foder /opt/tmp-1 . cat Dockerfile Output FROM nginx:latest # copy the custom website into the image COPY index.html /usr/share/nginx/html # copy the SSL configuration file into the image COPY ssl.conf /etc/nginx/conf.d/ssl.conf # download the SSL key and certificate into the image COPY nginx.key /etc/nginx/ssl/ COPY nginx.crt /etc/nginx/ssl/ # expose the HTTPS port EXPOSE 443 We have five files in foder /opt/tmp-1 till now. ls /opt/tmp-1 Output Dockerfile index.html nginx.crt nginx.key ssl.conf Now let's use the docker build command to build the image, forward the containers ports 80 and 443. docker build -t nginx:my1 /opt/tmp-1/ docker image ls docker run -d -p 1086:80 -p 1088:443 --name nginx_v5 nginx:my1 docker container ps -a Above changes can be validated via below links: http://localhost:1086/ https://localhost:1088/ Register an account in DockerHub and enable access token in Docker Hub for CLI client authentication. docker login Input username and password. Username: Password: Tag the image to give image a nice name and a release number as tag, e.g., name is secure_nginx_0001 , tag is v1 . docker tag nginx:my1 secure_nginx_0001:v1 docker push secure_nginx_0001:v1 docker image ls Multi-stage Dockerfile \u00b6 Let's show an example of multi-stage build. The multi-stage in the context of Docker means, we can have more than one line with a FROM keyword. Create folder /opt/tmp-2 and /opt/tmp-2/tmpl . Create files edit.html , view.html , wiki.go and structure likes below. tree -l /opt/tmp-2 . \u251c\u2500\u2500 tmpl \u2502 \u251c\u2500\u2500 edit.html \u2502 \u2514\u2500\u2500 view.html \u2514\u2500\u2500 wiki.go Create an new Dockerfile that starts cat Dockerfile # app builder stage FROM golang:1.12-alpine as builder ## copy the go source code over and build the binary WORKDIR /go/src COPY wiki.go /go/src/wiki.go RUN go build wiki.go # app exec stage # separate & new image starts here!# FROM alpine:3.9 # prepare file system etc RUN mkdir -p /app/data /app/tmpl && adduser -S -D -H -h /app appuser COPY tmpl/* /app/tmpl/ # get the compiled binary from the previous stage COPY --from = builder /go/src/wiki /app/wiki # prepare runtime env RUN chown -R appuser /app USER appuser WORKDIR /app # expose app port & set default command EXPOSE 8080 CMD [ \"/app/wiki\" ] Build the images by Dockerfile we created above. docker build -t lizard/golang:my1 /opt/tmp-2/ Run the image in detached mode, create a port forwarding from port 8080 in the container to port 1090 on the host. docker run -d -p 1090:8080 --name golan_v1 lizard/golang:my1 Access the container via link http://localhost:1090 Tab the golang image we created and push it to DockerHub. docker tag lizard/golang:my1 /golang_0001:v1 docker push /golang_0001:v1","title":"Fundamentals"},{"location":"k8s/cka_en/foundamentals/docker/#docker-fundamentals","text":"","title":"Docker Fundamentals"},{"location":"k8s/cka_en/foundamentals/docker/#demo-environment","text":"Linux: openSUSE 15.3 cat /etc/os-release Output NAME=\"openSUSE Leap\" VERSION=\"15.3\" ID=\"opensuse-leap\" ID_LIKE=\"suse opensuse\" VERSION_ID=\"15.3\" PRETTY_NAME=\"openSUSE Leap 15.3\" ANSI_COLOR=\"0;32\" CPE_NAME=\"cpe:/o:opensuse:leap:15.3\" BUG_REPORT_URL=\"https://bugs.opensuse.org\" HOME_URL=\"https://www.opensuse.org/\"","title":"Demo environment"},{"location":"k8s/cka_en/foundamentals/docker/#linux-primitives","text":"chroot(using pivot_root) Changes the root directory for a process to any given directory namespaces Different processes see different environments even though they are on the same host/OS mnt (mount points) pid (process tree) net (network interfaces and connectivity) ipc (interprocess communication framework) uts (unix timesharing - domain name, hostname, etc.) uid (user IDs and mappings) cgroups(control groups) manage/limit resource allocation to individual processes Prioritization of processes Apparmor and SELinux profiles Security profiles to govern access to resources Kernel capabilities without capabilities: root can do everything, everybody else may do nothing 38 granular facilities to control privileges seccomp policies Limitation of allowed kernel syscalls Unallowed syscalls lead to process termination Netlink A Linux kernel interface used for inter-process communication (IPC) between both the kernel and userspace processes, and between different userspace processes. Netfilter A framework provided by the Linux kernel that allows various networking-related operations Packet filtering, network address translation, and port translation(iptables/nftables) used to direct network packages to individual containers More inforamtion could refer to LXC/LXD Let's download an image alpine to simulate an root file system under /opt/test folder. mkdir test cd test wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.4-x86_64.tar.gz tar zxvf alpine-minirootfs-3.13.4-x86_64.tar.gz -C alpine-minirootfs/ Current directory structure. tree ./test -L 1 Output ./test \u251c\u2500\u2500 alpine-minirootfs-3.13.4-x86_64.tar.gz \u251c\u2500\u2500 bin \u251c\u2500\u2500 dev \u251c\u2500\u2500 etc \u251c\u2500\u2500 home \u251c\u2500\u2500 lib \u251c\u2500\u2500 media \u251c\u2500\u2500 mnt \u251c\u2500\u2500 opt \u251c\u2500\u2500 proc \u251c\u2500\u2500 root \u251c\u2500\u2500 run \u251c\u2500\u2500 sbin \u251c\u2500\u2500 srv \u251c\u2500\u2500 sys \u251c\u2500\u2500 tmp \u251c\u2500\u2500 usr \u2514\u2500\u2500 var Mount folder /opt/test/proc to a file and use command unshare to build a guest system. sudo mount -t tmpfs tmpfs /opt/test/proc sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # ps -ef PID USER TIME COMMAND 1 root 0 :00 /bin/sh 2 root 0 :00 ps -ef / # touch 123 / # ls 123 123 The file 123 created in guest system is accessable and writable from host system. su - ls 123 echo hello > 123 We will see above change in guest system. / # cat 123 hello Let's create two folders /opt/test-1 and /opt/test-2 . mkdir test-1 mkdir test-2 Create two guests system. Mount /opt/test/home/ to different folders for different guests. sudo mount --bind /opt/test-1 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-1\" > 123.1 /home # cat 123.1 test-1 sudo mount --bind /opt/test-2 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-2\" > 123.2 /home # cat 123.2 test-2 ll test/home ll test-1/ ll test-2/ With above demo, the conclusion is that two guests share same home folder on host system and will impact each other.","title":"Linux Primitives"},{"location":"k8s/cka_en/foundamentals/docker/#installing-docker","text":"Install Docker engine by referring the guide , and Docker Desktop by referring the guide . Install engine via openSUSE repository automatically. sudo zypper in docker The docker group is automatically created at package installation time. The user can communicate with the local Docker daemon upon its next login. The Docker daemon listens on a local socket which is accessible only by the root user and by the members of the docker group. Add current user to docker group. sudo usermod -aG docker $USER Enable and start Docker engine. sudo systemctl enable docker.service sudo systemctl start docker.service sudo systemctl status docker.service","title":"Installing Docker"},{"location":"k8s/cka_en/foundamentals/docker/#container-lifecycle","text":"","title":"Container lifecycle"},{"location":"k8s/cka_en/foundamentals/docker/#overview","text":"Pull down below images in advance. docker image pull busybox docker image pull nginx docker image pull alpine docker image pull jenkins/jenkins:lts docker image pull golang:1.12-alpine docker image pull golang Download some docker images. Create and run a new busybox container interactively and connect a pseudo terminal to it. Inside the container, use the top command to find out that /bin/sh is running as process with the PID 1 and top process is also running. After that, just exit. docker image ls docker run -d -it --name busybox_v1 -v /opt/test:/docker busybox:latest /bin/sh docker container ps -a docker exec -it 185efe490507 /bin/sh / # top Mem: 3627396K used, 12731512K free, 10080K shrd, 2920K buff, 2999340K cached CPU: 0 .0% usr 0 .1% sys 0 .0% nic 99 .8% idle 0 .0% io 0 .0% irq 0 .0% sirq Load average: 0 .38 1 .09 1 .29 2 /277 14 PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND 1 0 root S 1332 0 .0 1 0 .0 /bin/sh 8 0 root S 1332 0 .0 2 0 .0 /bin/sh 14 8 root R 1328 0 .0 1 0 .0 top / # exitbuild Start a new nginx container in detached mode. Use the docker exec command to start another shell ( /bin/sh ) in the nginx container. Use ps to find out that sh and ps commands are running in your container. docker run -d -it --name nginx_v1 -v /opt/test:/docker nginx:latest /bin/sh docker container ps -a docker exec -it edb640127a0d /bin/sh # ps /bin/sh: 2 : ps: not found # apt-get update && apt-get install -y procps # ps PID TTY TIME CMD 8 pts/1 00 :00:00 sh 351 pts/1 00 :00:00 ps # exit Now we have two running containers below. docker container ps -a Let's use docker logs to display the logs of the container we just exited from. The option --since 35m means display log in last 35 minutes. docker logs nginx_v1 --details --since 35m docker logs busybox_v1 --details --since 35m Let's make use of this to create a new stage: Use the docker stop command to end your nginx container. docker stop busybox_v1 docker stop nginx_v1 docker container ps -a With above command docker container ps -a , we get a list of all running and exited containers. Remove them with docker rm. Use docker rm $(docker ps -aq) to clean up all containers on your host. Use it with caution! docker rm busybox_v1 docker container ps -a","title":"Overview"},{"location":"k8s/cka_en/foundamentals/docker/#ports-and-volumes","text":"Now, let's run an nginx webserver in a container and serve a website to the outside world. Start a new nginx container and export the port of the nginx webserver to a random port that is chosen by Docker. Use command docker ps to find you which port the webserver is forwarded. Access the docker with the forwarded port number on host http://localhost: . docker container ps -a docker run -d -P --name nginx_v2 nginx:latest docker container ps -a Start another nginx container and expose port to 1080 on host as an example via http://localhost:1080 . docker run -d -p 1080:80 --name nginx_v3 nginx:latest docker container ps -a Let's make use of this to create a new stage: Use command docker inspect to find out which port is exposed by the image. Network information (ip, gateway, ports, etc.) is part of the output JSON format. docker inspect nginx_v3 Create a file index.html in folder /opt/test with below sample content. < html > < head > < title > Sample Website from my container < body > < h1 > This is a custom website. < p > This website is served from my < a href = \"http://www.docker.com\" target = \"_blank\" > Docker container. Start a new container that bind-mounts host directory /opt/test to container directory /usr/share/nginx/html as a volume, so that NGINX will publish the HTML file wee just created instead of its default message via http://localhost:49159/ below. docker run -d -P --mount type=bind,source=/opt/test/,target=/usr/share/nginx/html --name nginx_v3-1 nginx:latest docker container ps -a Check nginx config file on where is the html home page stored in container. docker exec -it nginx_v3-1 /bin/sh # cd /etc/nginx/conf.d # ls default.conf # cat default.conf server { listen 80; listen [::]:80; server_name localhost; # access_log /var/log/nginx/host.access.log main ; location / { root /usr/share/nginx/html; <-- index index.html index.htm; } # error_page 404 /404.html ; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } # proxy the PHP scripts to Apache listening on 127 .0.0.1:80 # # location ~ \\. php$ { # proxy_pass http://127.0.0.1 ; # } # pass the PHP scripts to FastCGI server listening on 127 .0.0.1:9000 # # location ~ \\. php$ { # root html ; # fastcgi_pass 127 .0.0.1:9000 ; # fastcgi_index index.php ; # fastcgi_param SCRIPT_FILENAME /scripts $fastcgi_script_name ; # include fastcgi_params ; # } # deny access to .htaccess files, if Apache 's document root # concurs with nginx' s one # # location ~ / \\. ht { # deny all ; # } } # cd /usr/share/nginx/html # cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    # It's recommendable to add a persistence with volumes API, instead of storing data in a docker container. Docker supports 2 ways of mount: Bind mounts: mount a local host directory onto a certain path in the container. Everything that was present before in the target directory is hidden (nature of the bind mount). For example, if you have some configuration you want to inject, write your config file, store it on your docker host at /home/container/config and mount the content of this directory to /usr/application/config (assuming the application reads config from there). Command: docker run --mount type=bind,source=,target= \u2026 Named volumes: docker can create a separated storage volume. Its lifecycle is independent from the container but still managed by docker. Upon creation, the content of the mount target is merged into the volume. Command: docker run --mount source=,target= \u2026 How to differentiate between bind mountbuild s and named volumes? When specifying an absolute path, docker assumes a bind mount. When you just give a name (like in a relative path \u201cconfig\u201d), it will assume a named volume and create a volume \u201cconfig\u201d. Note: Persistent storage is 'provided' by the host. It can be a part of the file system on the host directly but also an NFS mount.","title":"Ports and volumes"},{"location":"k8s/cka_en/foundamentals/docker/#dockerfile","text":"Let's build an image with a Dockerfile,build tag it and upload it to a registry. Get docker image build history. docker image history nginx:latest Create an empty directory /opt/tmp-1 , change to the directory and create an sample index.html file in /opt/tmp-1 . /opt/tmp-1> cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    Use FROM to extend an existing image, specify the release number. Use COPY to copy a new default website into the image, e.g., /usr/share/nginx/html Create SSL configuration /opt/tmp-1/ssl.conf for nginx. server { listen 443 ssl; server_name localhost; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; location / { root /usr/share/nginx/html; index index.html index.htm; } } Use OpenSSL to create a self-signed certificate so SSL/TLS to work would work. Use the following command to create an encryption key and a certificate. openssl req -x509 -nodes -newkey rsa:4096 -keyout nginx.key -out nginx.crt -days 365 -subj \"/CN=$(hostname)\" To enable encrypted HTTPS, we need to expose port 443 with the EXPOSE directive. The default nginx image only exposes port 80 for unencrypted HTTP. In summary, we create below Dockerfile in foder /opt/tmp-1 . cat Dockerfile Output FROM nginx:latest # copy the custom website into the image COPY index.html /usr/share/nginx/html # copy the SSL configuration file into the image COPY ssl.conf /etc/nginx/conf.d/ssl.conf # download the SSL key and certificate into the image COPY nginx.key /etc/nginx/ssl/ COPY nginx.crt /etc/nginx/ssl/ # expose the HTTPS port EXPOSE 443 We have five files in foder /opt/tmp-1 till now. ls /opt/tmp-1 Output Dockerfile index.html nginx.crt nginx.key ssl.conf Now let's use the docker build command to build the image, forward the containers ports 80 and 443. docker build -t nginx:my1 /opt/tmp-1/ docker image ls docker run -d -p 1086:80 -p 1088:443 --name nginx_v5 nginx:my1 docker container ps -a Above changes can be validated via below links: http://localhost:1086/ https://localhost:1088/ Register an account in DockerHub and enable access token in Docker Hub for CLI client authentication. docker login Input username and password. Username: Password: Tag the image to give image a nice name and a release number as tag, e.g., name is secure_nginx_0001 , tag is v1 . docker tag nginx:my1 secure_nginx_0001:v1 docker push secure_nginx_0001:v1 docker image ls","title":"Dockerfile"},{"location":"k8s/cka_en/foundamentals/docker/#multi-stage-dockerfile","text":"Let's show an example of multi-stage build. The multi-stage in the context of Docker means, we can have more than one line with a FROM keyword. Create folder /opt/tmp-2 and /opt/tmp-2/tmpl . Create files edit.html , view.html , wiki.go and structure likes below. tree -l /opt/tmp-2 . \u251c\u2500\u2500 tmpl \u2502 \u251c\u2500\u2500 edit.html \u2502 \u2514\u2500\u2500 view.html \u2514\u2500\u2500 wiki.go Create an new Dockerfile that starts cat Dockerfile # app builder stage FROM golang:1.12-alpine as builder ## copy the go source code over and build the binary WORKDIR /go/src COPY wiki.go /go/src/wiki.go RUN go build wiki.go # app exec stage # separate & new image starts here!# FROM alpine:3.9 # prepare file system etc RUN mkdir -p /app/data /app/tmpl && adduser -S -D -H -h /app appuser COPY tmpl/* /app/tmpl/ # get the compiled binary from the previous stage COPY --from = builder /go/src/wiki /app/wiki # prepare runtime env RUN chown -R appuser /app USER appuser WORKDIR /app # expose app port & set default command EXPOSE 8080 CMD [ \"/app/wiki\" ] Build the images by Dockerfile we created above. docker build -t lizard/golang:my1 /opt/tmp-2/ Run the image in detached mode, create a port forwarding from port 8080 in the container to port 1090 on the host. docker run -d -p 1090:8080 --name golan_v1 lizard/golang:my1 Access the container via link http://localhost:1090 Tab the golang image we created and push it to DockerHub. docker tag lizard/golang:my1 /golang_0001:v1 docker push /golang_0001:v1","title":"Multi-stage Dockerfile"},{"location":"k8s/cka_en/foundamentals/healthcheck/","text":"Health Check \u00b6 Status of Pod and Container \u00b6 Scenario: Create a pod with two containers. Demo: Create a Pod multi-pods with two containers nginx and busybox . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: labels: run: multi-pods name: multi-pods spec: containers: - image: nginx name: nginx - image: busybox name: busybox dnsPolicy: ClusterFirst restartPolicy: Always EOF Minotor the status with option --watch . The status of Pod was changed from ContainerCreating to NotReady to CrashLoopBackOff . kubectl get pod multi-pods --watch Get details of the Pod multi-pods , focus on Container's state under segment Containers and Conditions of Pod under segment Conditions . kubectl describe pod multi-pods Result ...... Containers: nginx: ...... State: Running Started: Sat, 23 Jul 2022 15:06:56 +0800 Ready: True Restart Count: 0 ...... busybox: ...... State: Terminated Reason: Completed Exit Code: 0 ...... Conditions: Type Status Initialized True Ready False ContainersReady False PodScheduled True ...... LivenessProbe \u00b6 Scenario: Create pod with livenessProbe check. Detail description of the demo can be found on the Kubernetes document . Demo: Create a yaml file liveness.yaml with livenessProbe setting and apply it. kubectl apply -f - <> ~/.bashrc source <(helm completion bash) Install MySQL from Helm \u00b6 Add bitnami Chartes Repository. helm repo add bitnami https://charts.bitnami.com/bitnami Get current Charts repositories. helm repo list NAME URL bitnami https://charts.bitnami.com/bitnami Sync up local Charts repositories. helm repo update Search bitnami Charts in repositories. helm search repo bitnami Search bitnami/mysql Charts in repositories. helm search repo bitnami/mysql Install MySQL Chart on namespace dev \uff1a helm install mysql bitnami/mysql -n dev Output NAME: mysql LAST DEPLOYED: Sun Jul 24 19:37:20 2022 NAMESPACE: dev STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: mysql CHART VERSION: 9.2.1 APP VERSION: 8.0.29 ** Please be patient while the chart is being deployed ** Tip: Watch the deployment status using the command: kubectl get pods -w --namespace dev Services: echo Primary: mysql.dev.svc.cluster.local:3306 Execute the following to get the administrator credentials: echo Username: root MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace dev mysql -o jsonpath=\"{.data.mysql-root-password}\" | base64 -d) To connect to your database: 1. Run a pod that you can use as a client: kubectl run mysql-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mysql:8.0.29-debian-11-r9 --namespace dev --env MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD --command -- bash 2. To connect to primary service (read/write): mysql -h mysql.dev.svc.cluster.local -uroot -p\"$MYSQL_ROOT_PASSWORD\" Check installed release\uff1a helm list Result NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 Check installed mysql release information. helm status mysql Check mysql Pod status. kubectl get pod Result NAME READY STATUS RESTARTS AGE mysql-0 1/1 Running 0 72s Develop a Chart \u00b6 Below is a demo on how to develop a Chart. Execute helm create to initiate a Chart\uff1a # Naming conventions of Chart: lowercase a~z and - ( minus sign ) helm create cka-demo A folder cka-demo was created. Check the folder structure. tree cka-demo/ Output cka-demo/ \u251c\u2500\u2500 charts \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 deployment.yaml \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u251c\u2500\u2500 hpa.yaml \u2502 \u251c\u2500\u2500 ingress.yaml \u2502 \u251c\u2500\u2500 NOTES.txt \u2502 \u251c\u2500\u2500 serviceaccount.yaml \u2502 \u251c\u2500\u2500 service.yaml \u2502 \u2514\u2500\u2500 tests \u2502 \u2514\u2500\u2500 test-connection.yaml \u2514\u2500\u2500 values.yaml Delete or empty some files, which will be re-created later. cd cka-demo rm -rf charts rm -rf templates/tests rm -rf templates/*.yaml echo \"\" > values.yaml echo \"\" > templates/NOTES.txt echo \"\" > templates/_helpers.tpl cd .. Now new structure looks like below. tree cka-demo/ Output cka-demo/ \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u2514\u2500\u2500 NOTES.txt \u2514\u2500\u2500 values.yaml NOTES.txt \u00b6 NOTES.txt is used to provide summary information to Chart users. In the demo, we will use NOTES.txt to privide summary info about whether the user passed CKA certificate or not. cd cka-demo/ vi templates/NOTES.txt Add below info. {{- if .Values.passExam }} Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: {{ .Values.ckaScore }} Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard {{- else }} Come on! you can do it next time! {{- end }} Deployment Template \u00b6 Let's use Busybox service to generate information. We use kubectl create deployment --dry-run=client -oyaml to generate Deployment yaml file and write it the yaml file content into file templates/deployment.yaml . kubectl create deployment cka-demo-busybox --image=busybox:latest --dry-run=client -oyaml > templates/deployment.yaml Check content of deployment yaml file templates/deployment.yaml . cat templates/deployment.yaml apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : 1 selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} Edit file templates/deployment.yaml . vi templates/deployment.yaml Let's replace value of .spec.replicas from 1 to a variable {{ .Values.replicaCount }} , so we can dynamicly assign replicas number for other Deployment. apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} The .spec.replicas will be replaced by actula value of .Values.replicaCount during deployment. Let's create another file values.yaml and add a variable replicaCount with default value 1 into the file. Strong recommended to add comments for each value we defined in file values.yaml . vi values.yaml # Number of deployment replicas replicaCount: 1 Let's add more variables into file templates/deployment.yaml . Replace Release name .metadata.name by {{ .Release.Name }} and filled with variable defined in file values.yaml . Replace label name .metadata.labels by {{- include \"cka-demo.labels\" . | nindent 4 }} , and filled with labels name cka-demo.labels defined in file _helpers.tpl . Replace .spec.replicas by {{ .Values.replicaCount }} and filled with variable defined in file values.yaml . Replace .spec.selector.matchLabels by {{- include \"cka-demo.selectorLabels\" . | nindent 6 }} and filled with cka-demo.selectorLabels defined in file _helpers.tpl . Replace .spec.template.metadata.labels by {{- include \"cka-demo.selectorLabels\" . | nindent 8 }} and filled with cka-demo.selectorLabels defined in file _helpers.tpl . Replace .spec.template.spec.containers[0].image by {{ .Values.image.repository }} and {{ .Values.image.tag }} and filled with variables defined in values.yaml for image name and image tag. Replace .spec.template.spec.containers[0].command and add if-else statement, if .Values.passExam is true, execute commands defined in .Values.passCommand , if false, execute commands defined in .Values.lostCommand . Use key from ConfigMap from .spec.template.spec.containers[0].env as prefix of ConfigMap name and filled with {{ .Values.studentName }} defined in file values.yaml . Replace .spec.template.spec.containers[0].resources by {{ .Values.resources }} and filled with variable defined in file values.yaml . The .Release.Name is built-in object, no need to be specified in file values.yaml . It's generated by Release by helm install . Remove unused lines and final one looks like below. apiVersion : apps/v1 kind : Deployment metadata : name : {{ .Release.Name }} labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : {{ - include \"cka-demo.selectorLabels\" . | nindent 6 }} template : metadata : labels : {{ - include \"cka-demo.selectorLabels\" . | nindent 8 }} spec : containers : - name : id-generator image : \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\" {{ - if .Values.passExam }} {{ - with .Values.passCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - else }} {{ - with .Values.lostCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - end }} env : - name : CKA_SCORE valueFrom : configMapKeyRef : name : {{ .Values.studentName }} -cka-score key : cka_score {{ - with .Values.resources }} resources : {{ - toYaml . | nindent 12 }} {{ - end }} restartPolicy : Always Update file values.yaml with variables default values. Suggestions\uff1aadd variables one and test one, don't add all at one time. vi values.yaml # Number of deployment replicas replicaCount: 1 # Image repository and tag image: repository: busybox tag: latest # Container start command passCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE) and your CKA certificate ID number is $(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 13; echo) ; sleep 86400\" lostCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE), Come on! you can do it next time! ; sleep 86400\" # Container resources resources: limits: cpu: 200m memory: 256Mi requests: cpu: 100m memory: 128Mi # Student Name studentName: whoareyou # Student pass CKA exam or not passExam: true ConfigMap Template \u00b6 ConfigMap is referred in the Deployment, hence we need define the ConfigMap template. We will combine name of ConfigMap and cka_score as a variable, like name-cka-score . vi templates/configmap.yaml apiVersion : v1 kind : ConfigMap metadata : name : {{ .Values.studentName }} -cka-score labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} data : cka_score : {{ .Values.ckaScore | quote }} The studentName was already defined in file values.yaml , we just need add ckaScore with default value. vi values.yaml # Student CKA Score ckaScore: 100 _helpers.tpl \u00b6 Define a common template _helpers.tpl to add labels and labels of Selector for labels of Deployment and ConfigMap. vi templates/_helpers.tpl {{/* Common labels */}} {{- define \"cka-demo.labels\" -}} {{ include \"cka-demo.selectorLabels\" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end -}} {{/* Selector labels */}} {{- define \"cka-demo.selectorLabels\" -}} app: {{ .Chart.Name }} release: {{ .Release.Name }} {{- end -}} Chart.yaml \u00b6 We use CKA logo as the icon of Chart wget https://www.cncf.io/wp-content/uploads/2021/09/kubernetes-cka-color.svg Edit Chart.yaml file. vi Chart.yaml Append icon info in the file. icon: file://./kubernetes-cka-color.svg Add author info for the Chart vi Chart.yaml maintainers: - name: James.H Final Chart.yaml looks like below. Don't forget to update appVersion: \"v1.23\" to current Kubernetes API version. apiVersion : v2 name : cka-demo description : A Helm chart for CKA demo. type : application version : 0.1.0 appVersion : \"v1.23\" maintainers : - name : James.H icon : file://./kubernetes-cka-color.svg Chart Debug \u00b6 Use helm lint to verify above change. helm lint 1 chart(s) linted, 0 chart(s) failed helm lint only check format of Chart, won't check Manifest file. We can use helm install --debug --dry-run or helm template to check Manifest output in order to verify all yaml files are correct or not. helm template cka-demo ./ Use helm install --debug --dry-run to simulate the installation. We can get expected results from two different options (passed or failed the CKA certificate). helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=99 \\ --set passExam=true helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=0 \\ --set passExam=false Package Chart to .tgz file, and upload to repository, e.g., Chart Museum or OCI Repo. cd ../ helm package cka-demo Successfully packaged chart and saved it to: /root/cka-demo-0.1.0.tgz Till now, we have done our task to develop a Chart. Let's install the Chart. helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=0 \\ --set passExam=false Result NAME: cka-demo LAST DEPLOYED: Sun Jul 24 19:58:36 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Come on! you can do it next time! Check the deployment helm list --all-namespaces Result NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION cka-demo cka 1 2022-07-24 19:58:36.272093383 +0800 CST deployed cka-demo-0.1.0 v1.23 mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 If any error, need to unstall cka-demo and reinstall it. helm uninstall cka-demo -n Check log of cka-demo . kubectl logs -n cka -l app=cka-demo Result Your CKA score is 0, Come on! you can do it next time! Install cka-demo with different options. helm uninstall cka-demo -n cka helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=100 \\ --set passExam=true NAME: cka-demo LAST DEPLOYED: Sun Jul 24 20:01:34 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: 100 Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard Check log of cka-demo . kubectl logs -n cka -l app=cka-demo Your CKA score is 100 and your CKA certificate ID number is BQKoVYVhjzl3G Built-in Objects: Release.Name # \u53d1\u5e03\u540d\u79f0 Release.Namespace # \u53d1\u5e03Namespace Release.Service # \u6e32\u67d3\u6a21\u677f\u7684\u670d\u52a1\uff0c\u5728Helm\u4e2d\u9ed8\u8ba4\u503c\u4e3a\"Helm\" Release.IsUpgrade # \u5982\u679c\u5f53\u524d\u662f\u5347\u7ea7\u6216\u56de\u6eda\uff0c\u8bbe\u7f6e\u4e3atrue Release.IsInstall # \u5982\u679c\u5f53\u524d\u662f\u5b89\u88c5\uff0c\u8bbe\u7f6e\u4e3atrue Release.Revision # \u53d1\u5e03\u7248\u672c\u53f7 Values # \u4ecevalues.yaml\u548c--set\u4f20\u5165\uff0c\u9ed8\u8ba4\u4e3a\u7a7a Chart # \u6240\u6709Chart.yaml\u4e2d\u7684\u5185\u5bb9 Chart.Version # Chart.Maintainers # Files # \u5728chart\u4e2d\u8bbf\u95ee\u975e\u7279\u6b8a\u6587\u4ef6 Capabilities # \u63d0\u4f9b\u5173\u4e8e\u652f\u6301\u80fd\u529b\u7684\u4fe1\u606f\uff08K8s API\u7248\u672c\u3001K8s\u7248\u672c\u3001Helm\u7248\u672c\uff09 Capabilities.KubeVersion # Kubernetes\u7684\u7248\u672c\u53f7 Capabilities.APIVersions.Has \"batch/v1\" # K8s API\u7248\u672c\u5305\u542b\"batch/v1\" Template # \u5f53\u524d\u6a21\u677f\u4fe1\u606f Template.Name # \u5f53\u524d\u6a21\u677f\u6587\u4ef6\u8def\u5f84 Template.BasePath # \u5f53\u524d\u6a21\u677f\u76ee\u5f55\u8def\u5f84 Reference: Helm \u5b98\u7f51 Helm \u7248\u672c\u652f\u6301\u7b56\u7565 Helm Chart \u8d44\u6e90\u5bf9\u8c61\u5b89\u88c5\u987a\u5e8f","title":"Helming"},{"location":"k8s/cka_en/foundamentals/helming/#helm-chart","text":"","title":"Helm Chart"},{"location":"k8s/cka_en/foundamentals/helming/#install-helm","text":"Install Helm on cka001 . # https://github.com/helm/helm/releases wget https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz tar -zxvf helm-v3.8.2-linux-amd64.tar.gz cp linux-amd64/helm /usr/bin/ rm -rf linux-amd64 helm-v3.8.2-linux-amd64.tar.gz Or manually download the file via link https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz , and remote copy to cka001 . scp -i cka-key-pair.pem ./Package/helm-v3.8.2-linux-amd64.tar.gz root@cka001:/root/ ssh -i cka-key-pair.pem root@cka001 tar -zxvf helm-v3.8.2-linux-amd64.tar.gz cp linux-amd64/helm /usr/bin/ rm -rf linux-amd64 helm-v3.8.2-linux-amd64.tar.gz","title":"Install Helm"},{"location":"k8s/cka_en/foundamentals/helming/#usage-of-helm","text":"Check helm version helm version version.BuildInfo{Version:\"v3.8.2\", GitCommit:\"6e3701edea09e5d55a8ca2aae03a68917630e91b\", GitTreeState:\"clean\", GoVersion:\"go1.17.5\"} Get help of helm . helm help Configure auto-completion for helm . echo \"source <(helm completion bash)\" >> ~/.bashrc source <(helm completion bash)","title":"Usage of Helm"},{"location":"k8s/cka_en/foundamentals/helming/#install-mysql-from-helm","text":"Add bitnami Chartes Repository. helm repo add bitnami https://charts.bitnami.com/bitnami Get current Charts repositories. helm repo list NAME URL bitnami https://charts.bitnami.com/bitnami Sync up local Charts repositories. helm repo update Search bitnami Charts in repositories. helm search repo bitnami Search bitnami/mysql Charts in repositories. helm search repo bitnami/mysql Install MySQL Chart on namespace dev \uff1a helm install mysql bitnami/mysql -n dev Output NAME: mysql LAST DEPLOYED: Sun Jul 24 19:37:20 2022 NAMESPACE: dev STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: mysql CHART VERSION: 9.2.1 APP VERSION: 8.0.29 ** Please be patient while the chart is being deployed ** Tip: Watch the deployment status using the command: kubectl get pods -w --namespace dev Services: echo Primary: mysql.dev.svc.cluster.local:3306 Execute the following to get the administrator credentials: echo Username: root MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace dev mysql -o jsonpath=\"{.data.mysql-root-password}\" | base64 -d) To connect to your database: 1. Run a pod that you can use as a client: kubectl run mysql-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mysql:8.0.29-debian-11-r9 --namespace dev --env MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD --command -- bash 2. To connect to primary service (read/write): mysql -h mysql.dev.svc.cluster.local -uroot -p\"$MYSQL_ROOT_PASSWORD\" Check installed release\uff1a helm list Result NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 Check installed mysql release information. helm status mysql Check mysql Pod status. kubectl get pod Result NAME READY STATUS RESTARTS AGE mysql-0 1/1 Running 0 72s","title":"Install MySQL from Helm"},{"location":"k8s/cka_en/foundamentals/helming/#develop-a-chart","text":"Below is a demo on how to develop a Chart. Execute helm create to initiate a Chart\uff1a # Naming conventions of Chart: lowercase a~z and - ( minus sign ) helm create cka-demo A folder cka-demo was created. Check the folder structure. tree cka-demo/ Output cka-demo/ \u251c\u2500\u2500 charts \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 deployment.yaml \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u251c\u2500\u2500 hpa.yaml \u2502 \u251c\u2500\u2500 ingress.yaml \u2502 \u251c\u2500\u2500 NOTES.txt \u2502 \u251c\u2500\u2500 serviceaccount.yaml \u2502 \u251c\u2500\u2500 service.yaml \u2502 \u2514\u2500\u2500 tests \u2502 \u2514\u2500\u2500 test-connection.yaml \u2514\u2500\u2500 values.yaml Delete or empty some files, which will be re-created later. cd cka-demo rm -rf charts rm -rf templates/tests rm -rf templates/*.yaml echo \"\" > values.yaml echo \"\" > templates/NOTES.txt echo \"\" > templates/_helpers.tpl cd .. Now new structure looks like below. tree cka-demo/ Output cka-demo/ \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u2514\u2500\u2500 NOTES.txt \u2514\u2500\u2500 values.yaml","title":"Develop a Chart"},{"location":"k8s/cka_en/foundamentals/helming/#notestxt","text":"NOTES.txt is used to provide summary information to Chart users. In the demo, we will use NOTES.txt to privide summary info about whether the user passed CKA certificate or not. cd cka-demo/ vi templates/NOTES.txt Add below info. {{- if .Values.passExam }} Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: {{ .Values.ckaScore }} Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard {{- else }} Come on! you can do it next time! {{- end }}","title":"NOTES.txt"},{"location":"k8s/cka_en/foundamentals/helming/#deployment-template","text":"Let's use Busybox service to generate information. We use kubectl create deployment --dry-run=client -oyaml to generate Deployment yaml file and write it the yaml file content into file templates/deployment.yaml . kubectl create deployment cka-demo-busybox --image=busybox:latest --dry-run=client -oyaml > templates/deployment.yaml Check content of deployment yaml file templates/deployment.yaml . cat templates/deployment.yaml apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : 1 selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} Edit file templates/deployment.yaml . vi templates/deployment.yaml Let's replace value of .spec.replicas from 1 to a variable {{ .Values.replicaCount }} , so we can dynamicly assign replicas number for other Deployment. apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} The .spec.replicas will be replaced by actula value of .Values.replicaCount during deployment. Let's create another file values.yaml and add a variable replicaCount with default value 1 into the file. Strong recommended to add comments for each value we defined in file values.yaml . vi values.yaml # Number of deployment replicas replicaCount: 1 Let's add more variables into file templates/deployment.yaml . Replace Release name .metadata.name by {{ .Release.Name }} and filled with variable defined in file values.yaml . Replace label name .metadata.labels by {{- include \"cka-demo.labels\" . | nindent 4 }} , and filled with labels name cka-demo.labels defined in file _helpers.tpl . Replace .spec.replicas by {{ .Values.replicaCount }} and filled with variable defined in file values.yaml . Replace .spec.selector.matchLabels by {{- include \"cka-demo.selectorLabels\" . | nindent 6 }} and filled with cka-demo.selectorLabels defined in file _helpers.tpl . Replace .spec.template.metadata.labels by {{- include \"cka-demo.selectorLabels\" . | nindent 8 }} and filled with cka-demo.selectorLabels defined in file _helpers.tpl . Replace .spec.template.spec.containers[0].image by {{ .Values.image.repository }} and {{ .Values.image.tag }} and filled with variables defined in values.yaml for image name and image tag. Replace .spec.template.spec.containers[0].command and add if-else statement, if .Values.passExam is true, execute commands defined in .Values.passCommand , if false, execute commands defined in .Values.lostCommand . Use key from ConfigMap from .spec.template.spec.containers[0].env as prefix of ConfigMap name and filled with {{ .Values.studentName }} defined in file values.yaml . Replace .spec.template.spec.containers[0].resources by {{ .Values.resources }} and filled with variable defined in file values.yaml . The .Release.Name is built-in object, no need to be specified in file values.yaml . It's generated by Release by helm install . Remove unused lines and final one looks like below. apiVersion : apps/v1 kind : Deployment metadata : name : {{ .Release.Name }} labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : {{ - include \"cka-demo.selectorLabels\" . | nindent 6 }} template : metadata : labels : {{ - include \"cka-demo.selectorLabels\" . | nindent 8 }} spec : containers : - name : id-generator image : \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\" {{ - if .Values.passExam }} {{ - with .Values.passCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - else }} {{ - with .Values.lostCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - end }} env : - name : CKA_SCORE valueFrom : configMapKeyRef : name : {{ .Values.studentName }} -cka-score key : cka_score {{ - with .Values.resources }} resources : {{ - toYaml . | nindent 12 }} {{ - end }} restartPolicy : Always Update file values.yaml with variables default values. Suggestions\uff1aadd variables one and test one, don't add all at one time. vi values.yaml # Number of deployment replicas replicaCount: 1 # Image repository and tag image: repository: busybox tag: latest # Container start command passCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE) and your CKA certificate ID number is $(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 13; echo) ; sleep 86400\" lostCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE), Come on! you can do it next time! ; sleep 86400\" # Container resources resources: limits: cpu: 200m memory: 256Mi requests: cpu: 100m memory: 128Mi # Student Name studentName: whoareyou # Student pass CKA exam or not passExam: true","title":"Deployment Template"},{"location":"k8s/cka_en/foundamentals/helming/#configmap-template","text":"ConfigMap is referred in the Deployment, hence we need define the ConfigMap template. We will combine name of ConfigMap and cka_score as a variable, like name-cka-score . vi templates/configmap.yaml apiVersion : v1 kind : ConfigMap metadata : name : {{ .Values.studentName }} -cka-score labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} data : cka_score : {{ .Values.ckaScore | quote }} The studentName was already defined in file values.yaml , we just need add ckaScore with default value. vi values.yaml # Student CKA Score ckaScore: 100","title":"ConfigMap Template"},{"location":"k8s/cka_en/foundamentals/helming/#_helperstpl","text":"Define a common template _helpers.tpl to add labels and labels of Selector for labels of Deployment and ConfigMap. vi templates/_helpers.tpl {{/* Common labels */}} {{- define \"cka-demo.labels\" -}} {{ include \"cka-demo.selectorLabels\" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end -}} {{/* Selector labels */}} {{- define \"cka-demo.selectorLabels\" -}} app: {{ .Chart.Name }} release: {{ .Release.Name }} {{- end -}}","title":"_helpers.tpl"},{"location":"k8s/cka_en/foundamentals/helming/#chartyaml","text":"We use CKA logo as the icon of Chart wget https://www.cncf.io/wp-content/uploads/2021/09/kubernetes-cka-color.svg Edit Chart.yaml file. vi Chart.yaml Append icon info in the file. icon: file://./kubernetes-cka-color.svg Add author info for the Chart vi Chart.yaml maintainers: - name: James.H Final Chart.yaml looks like below. Don't forget to update appVersion: \"v1.23\" to current Kubernetes API version. apiVersion : v2 name : cka-demo description : A Helm chart for CKA demo. type : application version : 0.1.0 appVersion : \"v1.23\" maintainers : - name : James.H icon : file://./kubernetes-cka-color.svg","title":"Chart.yaml"},{"location":"k8s/cka_en/foundamentals/helming/#chart-debug","text":"Use helm lint to verify above change. helm lint 1 chart(s) linted, 0 chart(s) failed helm lint only check format of Chart, won't check Manifest file. We can use helm install --debug --dry-run or helm template to check Manifest output in order to verify all yaml files are correct or not. helm template cka-demo ./ Use helm install --debug --dry-run to simulate the installation. We can get expected results from two different options (passed or failed the CKA certificate). helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=99 \\ --set passExam=true helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=0 \\ --set passExam=false Package Chart to .tgz file, and upload to repository, e.g., Chart Museum or OCI Repo. cd ../ helm package cka-demo Successfully packaged chart and saved it to: /root/cka-demo-0.1.0.tgz Till now, we have done our task to develop a Chart. Let's install the Chart. helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=0 \\ --set passExam=false Result NAME: cka-demo LAST DEPLOYED: Sun Jul 24 19:58:36 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Come on! you can do it next time! Check the deployment helm list --all-namespaces Result NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION cka-demo cka 1 2022-07-24 19:58:36.272093383 +0800 CST deployed cka-demo-0.1.0 v1.23 mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 If any error, need to unstall cka-demo and reinstall it. helm uninstall cka-demo -n Check log of cka-demo . kubectl logs -n cka -l app=cka-demo Result Your CKA score is 0, Come on! you can do it next time! Install cka-demo with different options. helm uninstall cka-demo -n cka helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=100 \\ --set passExam=true NAME: cka-demo LAST DEPLOYED: Sun Jul 24 20:01:34 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: 100 Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard Check log of cka-demo . kubectl logs -n cka -l app=cka-demo Your CKA score is 100 and your CKA certificate ID number is BQKoVYVhjzl3G Built-in Objects: Release.Name # \u53d1\u5e03\u540d\u79f0 Release.Namespace # \u53d1\u5e03Namespace Release.Service # \u6e32\u67d3\u6a21\u677f\u7684\u670d\u52a1\uff0c\u5728Helm\u4e2d\u9ed8\u8ba4\u503c\u4e3a\"Helm\" Release.IsUpgrade # \u5982\u679c\u5f53\u524d\u662f\u5347\u7ea7\u6216\u56de\u6eda\uff0c\u8bbe\u7f6e\u4e3atrue Release.IsInstall # \u5982\u679c\u5f53\u524d\u662f\u5b89\u88c5\uff0c\u8bbe\u7f6e\u4e3atrue Release.Revision # \u53d1\u5e03\u7248\u672c\u53f7 Values # \u4ecevalues.yaml\u548c--set\u4f20\u5165\uff0c\u9ed8\u8ba4\u4e3a\u7a7a Chart # \u6240\u6709Chart.yaml\u4e2d\u7684\u5185\u5bb9 Chart.Version # Chart.Maintainers # Files # \u5728chart\u4e2d\u8bbf\u95ee\u975e\u7279\u6b8a\u6587\u4ef6 Capabilities # \u63d0\u4f9b\u5173\u4e8e\u652f\u6301\u80fd\u529b\u7684\u4fe1\u606f\uff08K8s API\u7248\u672c\u3001K8s\u7248\u672c\u3001Helm\u7248\u672c\uff09 Capabilities.KubeVersion # Kubernetes\u7684\u7248\u672c\u53f7 Capabilities.APIVersions.Has \"batch/v1\" # K8s API\u7248\u672c\u5305\u542b\"batch/v1\" Template # \u5f53\u524d\u6a21\u677f\u4fe1\u606f Template.Name # \u5f53\u524d\u6a21\u677f\u6587\u4ef6\u8def\u5f84 Template.BasePath # \u5f53\u524d\u6a21\u677f\u76ee\u5f55\u8def\u5f84 Reference: Helm \u5b98\u7f51 Helm \u7248\u672c\u652f\u6301\u7b56\u7565 Helm Chart \u8d44\u6e90\u5bf9\u8c61\u5b89\u88c5\u987a\u5e8f","title":"Chart Debug"},{"location":"k8s/cka_en/foundamentals/hpa/","text":"Horizontal Pod Autoscaling (HPA) \u00b6 Scenario: Install Metrics Server component Create Deployment podinfo and Service podinfo for stress testing Create HPA my-hpa Stress Testing Demo: Install Metrics Server component \u00b6 Download yaml file for Metrics Server component wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml Replace Google image by Aliyun image image: registry.aliyuncs.com/google_containers/metrics-server:v0.6.1 . sed -i 's/k8s\\.gcr\\.io\\/metrics-server\\/metrics-server\\:v0\\.6\\.1/registry\\.aliyuncs\\.com\\/google_containers\\/metrics-server\\:v0\\.6\\.1/g' components.yaml Change arg of deployment metrics-server by adding --kubelet-insecure-tls to disable tls certificate validation. vi components.yaml Updated arg of metrics-server is below. ...... template : metadata : labels : k8s-app : metrics-server spec : containers : - args : - --cert-dir=/tmp - --secure-port=4443 - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname - --kubelet-use-node-status-port - --metric-resolution=15s - --kubelet-insecure-tls image : registry.aliyuncs.com/google_containers/metrics-server:v0.6.1 ...... Appy the yaml file components.yaml to deploy metrics-server . kubectl apply -f components.yaml Below resources were crested. serviceaccount/metrics-server created clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created clusterrole.rbac.authorization.k8s.io/system:metrics-server created rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created service/metrics-server created deployment.apps/metrics-server created apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created Verify if metrics-server Pod is running as expected ( 1/1 running) kubectl get pod -n kube-system -owide | grep metrics-server Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES metrics-server-7fd564dc66-sdhdc 1/1 Running 0 61s 10.244.102.15 cka003 Get current usage of CPU, memory of each node. kubectl top node Result: NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 595m 29% 1937Mi 50% cka002 75m 3% 1081Mi 28% cka003 79m 3% 1026Mi 26% Deploy a Service podinfo \u00b6 Create Deployment podinfo and Service podinfo for further stress testing. kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: podinfo labels: app: podinfo spec: type: NodePort ports: - port: 9898 targetPort: 9898 nodePort: 31198 protocol: TCP selector: app: podinfo --- apiVersion: apps/v1 kind: Deployment metadata: name: podinfo labels: app: podinfo spec: replicas: 2 selector: matchLabels: app: podinfo template: metadata: labels: app: podinfo spec: containers: - name: podinfod image: stefanprodan/podinfo:0.0.1 imagePullPolicy: Always command: - ./podinfo - -port=9898 - -logtostderr=true - -v=2 ports: - containerPort: 9898 protocol: TCP resources: requests: memory: \"32Mi\" cpu: \"10m\" limits: memory: \"256Mi\" cpu: \"100m\" EOF Config HPA \u00b6 Create HPA my-hpa by setting CPU threshold 50% to trigger auto-scalling with minimal 2 and maximal 10 Replicas. Use kubectl autoscal to create HPA my-hpa . kubectl autoscale deployment podinfo --cpu-percent=50 --min=1 --max=10 Use autoscaling/v1 version template to crreate HPA my-hpa . kubectl apply -f - < Get current usage of CPU, memory of each node. kubectl top node Result: NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 595m 29% 1937Mi 50% cka002 75m 3% 1081Mi 28% cka003 79m 3% 1026Mi 26%","title":"Install Metrics Server component"},{"location":"k8s/cka_en/foundamentals/hpa/#deploy-a-service-podinfo","text":"Create Deployment podinfo and Service podinfo for further stress testing. kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: podinfo labels: app: podinfo spec: type: NodePort ports: - port: 9898 targetPort: 9898 nodePort: 31198 protocol: TCP selector: app: podinfo --- apiVersion: apps/v1 kind: Deployment metadata: name: podinfo labels: app: podinfo spec: replicas: 2 selector: matchLabels: app: podinfo template: metadata: labels: app: podinfo spec: containers: - name: podinfod image: stefanprodan/podinfo:0.0.1 imagePullPolicy: Always command: - ./podinfo - -port=9898 - -logtostderr=true - -v=2 ports: - containerPort: 9898 protocol: TCP resources: requests: memory: \"32Mi\" cpu: \"10m\" limits: memory: \"256Mi\" cpu: \"100m\" EOF","title":"Deploy a Service podinfo"},{"location":"k8s/cka_en/foundamentals/hpa/#config-hpa","text":"Create HPA my-hpa by setting CPU threshold 50% to trigger auto-scalling with minimal 2 and maximal 10 Replicas. Use kubectl autoscal to create HPA my-hpa . kubectl autoscale deployment podinfo --cpu-percent=50 --min=1 --max=10 Use autoscaling/v1 version template to crreate HPA my-hpa . kubectl apply -f - <

    It works!

    Clean up. kubectl delete ingress demo-localhost kubectl delete service demo kubectl delete deployment demo Create Deployments \u00b6 Create two deployment nginx-app-1 and nginx-app-2 . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-1 spec: selector: matchLabels: app: nginx-app-1 replicas: 1 template: metadata: labels: app: nginx-app-1 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-1 --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-2 spec: selector: matchLabels: app: nginx-app-2 replicas: 1 template: metadata: labels: app: nginx-app-2 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-2 EOF Get status of Pods by executing kubectl get pod -o wide . One pod is running on node cka002 , another pod is running on node cka003 . Directory /opt/html-2/ is on cka002 Directory /opt/html-1/ is on cka002 Access to two Pod via curl. We get 403 Forbidden error. curl 10.244.102.13 curl 10.244.112.19 Log onto node cka002 , create index.html file in path /opt/html-2/ with below command. cat < app1.com app2.com EOF Get IP address or FQDN with the following command: kubectl get service ingress-nginx-controller --namespace=ingress-nginx It will be the EXTERNAL-IP field. If that field shows like below, this means that the Kubernetes cluster wasn't able to provision the load balancer (generally, this is because it doesn't support services of type LoadBalancer). As there is no Aliyun ELB configured, use below two options to make the external IP in place. Option 1: manually add node ip to ingress controller, which the controller pod is running on. Execute command kubectl get pod -n ingress-nginx -o wide to see that ingress controller pod is running on node cka003 . Manually patch the external ip of cak003 to the EXTERNAL-IP field. kubectl patch svc ingress-nginx-controller \\ --namespace=ingress-nginx \\ -p '{\"spec\": {\"type\": \"LoadBalancer\", \"externalIPs\":[\"\"]}}' Option 2: change ingress controller from LoadBalancer to NodePort . Two files index.html are in two Pods, the web services are exposed to outside via node IP. The ingress-nginx-controller plays a central entry point for outside access, and provide two ports for different backend services from Pods. Send HTTP request to two hosts defined in Ingress. curl http://app1.com:30011 curl http://app2.com:30011 curl app1.com:30011 curl app2.com:30011 Get below successful information. This is test 1 !! This is test 2 !! Clean up. kubectl delete ingress ingress-nginx-app kubectl delete service nginx-app-1 kubectl delete service nginx-app-2 kubectl delete deployment nginx-app-1 kubectl delete deployment nginx-app-2","title":"Ingress"},{"location":"k8s/cka_en/foundamentals/ingress/#ingress-nginx","text":"Scenario *Deploy Ingress Controller. * Create two deployment nginx-app-1 and nginx-app-2 . *Host directory /root/html-1 and /root/html-2 will be created and mounted to two Deployments on running host. * Create Service. *Create Service nginx-app-1 and nginx-app-2 and map to related Deployment nginx-app-1 and nginx-app-2 . * Create Ingress. *Create Ingress resource nginx-app and map to two Services nginx-app-1 and nginx-app-1 . * Test Accessibility. * Send HTTP request to two hosts defined in Ingress Reference *Github ingress-nginx * Installation Guide","title":"Ingress-nginx"},{"location":"k8s/cka_en/foundamentals/ingress/#deploy-ingress-controller","text":"Get Ingress Controller yaml file. The latest version link is in Installation Guide . wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml Below two images's sources needto be changed to Aliyun. image: k8s.gcr.io/ingress-nginx/controller:v1.2.1@sha256:5516d103a9c2ecc4f026efbd4b40662ce22dc1f824fb129ed121460aaa5c47f8 image: registry.k8s.io/ingress-nginx/controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5 image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660 From grc.io to Aliyun. k8s.gcr.io/ingress-nginx/controller to registry.aliyuncs.com/google_containers/nginx-ingress-controller registry.k8s.io/ingress-nginx/controller to registry.aliyuncs.com/google_containers/nginx-ingress-controller * k8s.gcr.io/ingress-nginx/kube-webhook-certgen to registry.aliyuncs.com/google_containers/kube-webhook-certgen Commands: sed -i 's/k8s.gcr.io\\/ingress-nginx\\/kube-webhook-certgen/registry.aliyuncs.com\\/google\\_containers\\/kube-webhook-certgen/g' deploy.yaml sed -i 's/k8s.gcr.io\\/ingress-nginx\\/controller/registry.aliyuncs.com\\/google\\_containers\\/nginx-ingress-controller/g' deploy.yaml Apply the yaml file deploy.yaml to create Ingress Nginx. A new namespace ingress-nginx was created and Ingress Nginx resources are running under the new namespace. kubectl apply -f deploy.yaml Check the status of Pod. kubectl get pod -n ingress-nginx Make sure all pods are not in error status, like below. NAME READY STATUS RESTARTS AGE ingress-nginx-admission-create-lgtdj 0/1 Completed 0 49s ingress-nginx-admission-patch-nk9fv 0/1 Completed 0 49s ingress-nginx-controller-556fbd6d6f-6jl4x 1/1 Running 0 49s","title":"Deploy Ingress Controller"},{"location":"k8s/cka_en/foundamentals/ingress/#local-testing","text":"Let's create a simple web server and the associated service: kubectl create deployment demo --image=httpd --port=80 kubectl expose deployment demo Then create an ingress resource. The following example uses a host that maps to localhost: kubectl create ingress demo-localhost --class=nginx --rule=\"demo.localdev.me/*=demo:80\" Now, forward a local port to the ingress controller: kubectl port-forward --namespace=ingress-nginx service/ingress-nginx-controller 8080:80 At this point, open another terminal to access http://demo.localdev.me:8080/ , we should see an HTML page telling you \"It works!\". curl http://demo.localdev.me:8080/ Result

    It works!

    Clean up. kubectl delete ingress demo-localhost kubectl delete service demo kubectl delete deployment demo","title":"Local testing"},{"location":"k8s/cka_en/foundamentals/ingress/#create-deployments","text":"Create two deployment nginx-app-1 and nginx-app-2 . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-1 spec: selector: matchLabels: app: nginx-app-1 replicas: 1 template: metadata: labels: app: nginx-app-1 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-1 --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-2 spec: selector: matchLabels: app: nginx-app-2 replicas: 1 template: metadata: labels: app: nginx-app-2 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-2 EOF Get status of Pods by executing kubectl get pod -o wide . One pod is running on node cka002 , another pod is running on node cka003 . Directory /opt/html-2/ is on cka002 Directory /opt/html-1/ is on cka002 Access to two Pod via curl. We get 403 Forbidden error. curl 10.244.102.13 curl 10.244.112.19 Log onto node cka002 , create index.html file in path /opt/html-2/ with below command. cat < app1.com app2.com EOF Get IP address or FQDN with the following command: kubectl get service ingress-nginx-controller --namespace=ingress-nginx It will be the EXTERNAL-IP field. If that field shows like below, this means that the Kubernetes cluster wasn't able to provision the load balancer (generally, this is because it doesn't support services of type LoadBalancer). As there is no Aliyun ELB configured, use below two options to make the external IP in place. Option 1: manually add node ip to ingress controller, which the controller pod is running on. Execute command kubectl get pod -n ingress-nginx -o wide to see that ingress controller pod is running on node cka003 . Manually patch the external ip of cak003 to the EXTERNAL-IP field. kubectl patch svc ingress-nginx-controller \\ --namespace=ingress-nginx \\ -p '{\"spec\": {\"type\": \"LoadBalancer\", \"externalIPs\":[\"\"]}}' Option 2: change ingress controller from LoadBalancer to NodePort . Two files index.html are in two Pods, the web services are exposed to outside via node IP. The ingress-nginx-controller plays a central entry point for outside access, and provide two ports for different backend services from Pods. Send HTTP request to two hosts defined in Ingress. curl http://app1.com:30011 curl http://app2.com:30011 curl app1.com:30011 curl app2.com:30011 Get below successful information. This is test 1 !! This is test 2 !! Clean up. kubectl delete ingress ingress-nginx-app kubectl delete service nginx-app-1 kubectl delete service nginx-app-2 kubectl delete deployment nginx-app-1 kubectl delete deployment nginx-app-2","title":"Test Accessiblity"},{"location":"k8s/cka_en/foundamentals/job/","text":"Job and Cronjob \u00b6 Job \u00b6 Scenario Create Job. Demo: Create Job pi . kubectl apply -f - << EOF apiVersion: batch/v1 kind: Job metadata: name: pi spec: template: spec: containers: - name: pi image: perl:5.34 command: [\"perl\", \"-Mbignum=bpi\", \"-wle\", \"print bpi(2000)\"] restartPolicy: Never backoffLimit: 4 EOF Get details of Job. kubectl get jobs Get details of Job Pod. The status Completed means the job was done successfully. kubectl get pod Get log info of the Job Pod. kubectl pi-2s74d 3.141592653589793.............. Clean up kubectl delete job pi Cronjob \u00b6 Scenario Create Cronjob. Demo: Create Cronjob hello . kubectl apply -f - << EOF apiVersion: batch/v1 kind: CronJob metadata: name: hello spec: schedule: \"*/1 * * * *\" jobTemplate: spec: template: spec: containers: - name: hello image: busybox args: - /bin/sh - -c - date ; echo Hello from the kubernetes cluster restartPolicy: OnFailure EOF Get detail of Cronjob kubectl get cronjobs -o wide Result NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE CONTAINERS IMAGES SELECTOR hello */1 * * * * False 0 25s hello busybox Monitor Jobs. Every 1 minute a new job will be created. kubectl get jobs -w Clean up kubectl delete cronjob hello","title":"Job and Cronjob"},{"location":"k8s/cka_en/foundamentals/job/#job-and-cronjob","text":"","title":"Job and Cronjob"},{"location":"k8s/cka_en/foundamentals/job/#job","text":"Scenario Create Job. Demo: Create Job pi . kubectl apply -f - << EOF apiVersion: batch/v1 kind: Job metadata: name: pi spec: template: spec: containers: - name: pi image: perl:5.34 command: [\"perl\", \"-Mbignum=bpi\", \"-wle\", \"print bpi(2000)\"] restartPolicy: Never backoffLimit: 4 EOF Get details of Job. kubectl get jobs Get details of Job Pod. The status Completed means the job was done successfully. kubectl get pod Get log info of the Job Pod. kubectl pi-2s74d 3.141592653589793.............. Clean up kubectl delete job pi","title":"Job"},{"location":"k8s/cka_en/foundamentals/job/#cronjob","text":"Scenario Create Cronjob. Demo: Create Cronjob hello . kubectl apply -f - << EOF apiVersion: batch/v1 kind: CronJob metadata: name: hello spec: schedule: \"*/1 * * * *\" jobTemplate: spec: template: spec: containers: - name: hello image: busybox args: - /bin/sh - -c - date ; echo Hello from the kubernetes cluster restartPolicy: OnFailure EOF Get detail of Cronjob kubectl get cronjobs -o wide Result NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE CONTAINERS IMAGES SELECTOR hello */1 * * * * False 0 25s hello busybox Monitor Jobs. Every 1 minute a new job will be created. kubectl get jobs -w Clean up kubectl delete cronjob hello","title":"Cronjob"},{"location":"k8s/cka_en/foundamentals/kyma/","text":"Kyma \u00b6 Deploy Kyma on control plane node. Install Kyma CLI \u00b6 Install Kyma CLI on Linux, run: curl -Lo kyma.tar.gz \"https://github.com/kyma-project/cli/releases/download/$(curl -s https://api.github.com/repos/kyma-project/cli/releases/latest | grep tag_name | cut -d '\"' -f 4)/kyma_Linux_x86_64.tar.gz\" mkdir /opt/kyma-release tar -C /opt/kyma-release -zxvf kyma.tar.gz chmod +x /opt/kyma-release/kyma sudo cp /opt/kyma-release/kyma /usr/local/bin rm -rf kyma-release kyma.tar.gz Reference Install Kyma CLI Install Kyma \u00b6 Use the deploy command to install Kyma. kyma deploy Get file components.yaml to manually install failed components. If no Namespace provided, the default Namespace called kyma-system is used. For example: kyma deploy --component serverless@kyma-integration kyma deploy --component monitoring@kyma-integration kyma deploy --component kiali@kyma-integration File components.yaml looks like below. --- defaultNamespace: kyma-system prerequisites: - name: \"cluster-essentials\" - name: \"istio\" namespace: \"istio-system\" - name: \"certificates\" namespace: \"istio-system\" components: - name: \"istio-resources\" - name: \"logging\" - name: \"telemetry\" - name: \"tracing\" - name: \"kiali\" - name: \"monitoring\" - name: \"eventing\" - name: \"ory\" - name: \"api-gateway\" - name: \"cluster-users\" - name: \"serverless\" - name: \"application-connector\" namespace: \"kyma-integration\" Reference: By default, Kyma is installed with the default chart values defined in the values.yaml files. You can also control the allocation of resources, such as memory and CPU, that the components consume by installing Kyma with the following pre-defined profiles: Evaluation needs limited resources and is suited for trial purposes. Production is configured for high availability and scalability. It requires more resources than the evaluation profile but is a better choice for production workload. Install Kyma To see a complete list of all Kyma components go to the components.yaml file. Install specific components kyma deploy --components-file {COMPONENTS_FILE_PATH}","title":"Kyma"},{"location":"k8s/cka_en/foundamentals/kyma/#kyma","text":"Deploy Kyma on control plane node.","title":"Kyma"},{"location":"k8s/cka_en/foundamentals/kyma/#install-kyma-cli","text":"Install Kyma CLI on Linux, run: curl -Lo kyma.tar.gz \"https://github.com/kyma-project/cli/releases/download/$(curl -s https://api.github.com/repos/kyma-project/cli/releases/latest | grep tag_name | cut -d '\"' -f 4)/kyma_Linux_x86_64.tar.gz\" mkdir /opt/kyma-release tar -C /opt/kyma-release -zxvf kyma.tar.gz chmod +x /opt/kyma-release/kyma sudo cp /opt/kyma-release/kyma /usr/local/bin rm -rf kyma-release kyma.tar.gz Reference Install Kyma CLI","title":"Install Kyma CLI"},{"location":"k8s/cka_en/foundamentals/kyma/#install-kyma","text":"Use the deploy command to install Kyma. kyma deploy Get file components.yaml to manually install failed components. If no Namespace provided, the default Namespace called kyma-system is used. For example: kyma deploy --component serverless@kyma-integration kyma deploy --component monitoring@kyma-integration kyma deploy --component kiali@kyma-integration File components.yaml looks like below. --- defaultNamespace: kyma-system prerequisites: - name: \"cluster-essentials\" - name: \"istio\" namespace: \"istio-system\" - name: \"certificates\" namespace: \"istio-system\" components: - name: \"istio-resources\" - name: \"logging\" - name: \"telemetry\" - name: \"tracing\" - name: \"kiali\" - name: \"monitoring\" - name: \"eventing\" - name: \"ory\" - name: \"api-gateway\" - name: \"cluster-users\" - name: \"serverless\" - name: \"application-connector\" namespace: \"kyma-integration\" Reference: By default, Kyma is installed with the default chart values defined in the values.yaml files. You can also control the allocation of resources, such as memory and CPU, that the components consume by installing Kyma with the following pre-defined profiles: Evaluation needs limited resources and is suited for trial purposes. Production is configured for high availability and scalability. It requires more resources than the evaluation profile but is a better choice for production workload. Install Kyma To see a complete list of all Kyma components go to the components.yaml file. Install specific components kyma deploy --components-file {COMPONENTS_FILE_PATH}","title":"Install Kyma"},{"location":"k8s/cka_en/foundamentals/memo/","text":"Kubernetes Learning Memo \u00b6 Basic Concepts of Kubernetes \u00b6 Kubernetes Components \u00b6 A Kubernetes cluster consists of the components that represent the control plane and a set of machines called nodes . Kubernetes Components : Control Plane Components kube-apiserver: query and manipulate the state of objects in Kubernetes. play as \"communication hub\" among all resources in cluster. provide cluster security authentication, authorization, and role assignment. the only one can connect to etcd . etcd: all Kubernetes objects are stored on etcd. Kubernetes objects are persistent entities in the Kubernetes system, which are used to represent the state of your cluster. kube-scheduler: watches for newly created Pods with no assigned node, and selects a node for them to run on. kube-controller-manager: runs controller processes. Node controller : Responsible for noticing and responding when nodes go down. Job controller : Watches for Job objects that represent one-off tasks, then creates Pods to run those tasks to completion. Endpoints controller : Populates the Endpoints object (that is, joins Services & Pods). Service Account & Token controllers : Create default accounts and API access tokens for new namespaces. cloud-controller-manager: embeds cloud-specific control logic and only runs controllers that are specific to your cloud provider, no need for own premises and learning environment. Node controller : For checking the cloud provider to determine if a node has been deleted in the cloud after it stops responding Route controller : For setting up routes in the underlying cloud infrastructure Service controller : For creating, updating and deleting cloud provider load balancers Node Components kubelet: An agent that runs on each node in the cluster. Manage node. It makes sure that containers are running in a Pod. kubelet registers and updates nodes information to APIServer, and APIServer stores them into etcd . Manage pod. Watch pod via APIServer, and action on pods or containers in pods. Health check at container level. kube-proxy: is a network proxy that runs on each node in cluster. iptables ipvs maintains network rules on nodes. Container runtime: is the software that is responsible for running containers. Addons DNS: is a DNS server and required by all Kubernetes clusters. Web UI (Dashboard): web-based UI for Kubernetes clusters. Container Resource Monitoring: records generic time-series metrics about containers in a central database Cluster-level Logging: is responsible for saving container logs to a central log store with search/browsing interface. Scalability: Scaling out (horizontal scaling) by adding more servers to your architecture to spread the workload across more machines. Scaling up (vertical scaling) by adding more hard drives and memory to increase the computing capacity of physical servers. Kubernetes API \u00b6 The REST API is the fundamental fabric of Kubernetes. All operations and communications between components, and external user commands are REST API calls that the API Server handles. Consequently, everything in the Kubernetes platform is treated as an API object and has a corresponding entry in the API. The core of Kubernetes' control plane is the API server. CRI: Container Runtime Interface CNI: Container Network Interface CSI: Container Storage Interface The API server exposes an HTTP API that lets end users, different parts of cluster, and external components communicate with one another. The Kubernetes API lets we query and manipulate the state of API objects in Kubernetes (for example: Pods, Namespaces, ConfigMaps, and Events). Kubernetes API: OpenAPI specification OpenAPI V2 OpenAPI V3 Persistence. Kubernetes stores the serialized state of objects by writing them into etcd. API groups and versioning. Versioning is done at the API level. API resources are distinguished by their API group, resource type, namespace (for namespaced resources), and name. API changes API Extension API Version \u00b6 The API versioning and software versioning are indirectly related. The API and release versioning proposal describes the relationship between API versioning and software versioning. Different API versions indicate different levels of stability and support. Here's a summary of each level: Alpha: The version names contain alpha (for example, v1alpha1). The software may contain bugs. Enabling a feature may expose bugs. A feature may be disabled by default. The support for a feature may be dropped at any time without notice. The API may change in incompatible ways in a later software release without notice. The software is recommended for use only in short-lived testing clusters, due to increased risk of bugs and lack of long-term support. Beta: The version names contain beta (for example, v2beta3). The software is well tested. Enabling a feature is considered safe. Features are enabled by default. The support for a feature will not be dropped, though the details may change. The schema and/or semantics of objects may change in incompatible ways in a subsequent beta or stable release. When this happens, migration instructions are provided. Schema changes may require deleting, editing, and re-creating API objects. The editing process may not be straightforward. The migration may require downtime for applications that rely on the feature. The software is not recommended for production uses. Subsequent releases may introduce incompatible changes. If you have multiple clusters which can be upgraded independently, you may be able to relax this restriction. Note: Please try beta features and provide feedback. After the features exit beta, it may not be practical to make more changes. Stable: The version name is vX where X is an integer. The stable versions of features appear in released software for many subsequent versions. Command to get current API kubectl api-resources API Group \u00b6 API groups make it easier to extend the Kubernetes API. The API group is specified in a REST path and in the apiVersion field of a serialized object. There are several API groups in Kubernetes: The core (also called legacy) group is found at REST path /api/v1 . The core group is not specified as part of the apiVersion field, for example, apiVersion: v1. The named groups are at REST path /apis/$GROUP_NAME/$VERSION and use apiVersion: $GROUP_NAME/$VERSION (for example, apiVersion: batch/v1). Kubernetes Objects \u00b6 Objects Overview \u00b6 Object Spec: providing a description of the characteristics the resource created to have: its desired state . Object Status: describes the current state of the object. Example of Deployment as an object that can represent an application running on cluster. apiVersion : apps/v1 # Which version of the Kubernetes API you're using to create this object kind : Deployment # What kind of object you want to create metadata : # Data that helps uniquely identify the object, including a name string, UID, and optional namespace name : nginx-deployment spec : # What state you desire for the object selector : matchLabels : app : nginx replicas : 2 # tells deployment to run 2 pods matching the template template : metadata : labels : app : nginx spec : containers : - name : nginx image : nginx:1.14.2 ports : - containerPort : 80 Object Management \u00b6 The kubectl command-line tool supports several different ways to create and manage Kubernetes objects. Read the Kubectl book for details. A Kubernetes object should be managed using ONLY one technique. Mixing and matching techniques for the same object results in undefined behavior. Three management techniques: Imperative commands operates directly on live objects in a cluster. kubectl create deployment nginx --image nginx Imperative object configuration kubectl create -f nginx.yaml kubectl delete -f nginx.yaml -f redis.yaml kubectl replace -f nginx.yaml Declarative object configuration kubectl diff -f configs/ kubectl apply -f configs/ Object Names and IDs \u00b6 Each object in your cluster has a Name that is unique for that type of resource. DNS Subdomain Names Label Names Path Segment Names Every Kubernetes object also has a UID that is unique across the whole cluster. Namespaces \u00b6 In Kubernetes, namespaces provides a mechanism for isolating groups of resources within a single cluster. Names of resources need to be unique within a namespace, but not across namespaces. Namespace-based scoping is applicable only for namespaced objects (e.g. Deployments, Services, etc) and not for cluster-wide objects (e.g. StorageClass, Nodes, PersistentVolumes, etc) Not All Objects are in a Namespace. Kubernetes starts with four initial namespaces: default The default namespace for objects with no other namespace kube-system The namespace for objects created by the Kubernetes system kube-public This namespace is created automatically and is readable by all users (including those not authenticated). This namespace is mostly reserved for cluster usage, in case that some resources should be visible and readable publicly throughout the whole cluster. The public aspect of this namespace is only a convention, not a requirement. kube-node-lease This namespace holds Lease objects associated with each node. Node leases allow the kubelet to send heartbeats so that the control plane can detect node failure. Viewing namespaces: kubectl get namespace Setting the namespace for a request kubectl run nginx --image=nginx --namespace= kubectl get pods --namespace= Labels and Selectors \u00b6 Labels are key/value pairs that are attached to objects, such as pods. Valid label keys have two segments: an optional prefix and name, separated by a slash ( / ). Labels are intended to be used to specify identifying attributes of objects that are meaningful and relevant to users. Labels can be used to organize and to select subsets of objects. Labels can be attached to objects at creation time and subsequently added and modified at any time. Each object can have a set of key/value labels defined. Each Key must be unique for a given object. Example of labels: \"metadata\" : { \"labels\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } Unlike names and UIDs, labels do not provide uniqueness. In general, we expect many objects to carry the same label(s). The API currently supports two types of selectors: equality-based, e.g., environment = production , tier != frontend set-based, e.g., environment in (production, qa) , tier notin (frontend, backend) Sample commands: kubectl get pods -l environment=production,tier=frontend kubectl get pods -l 'environment in (production),tier in (frontend)' kubectl get pods -l 'environment in (production, qa)' kubectl get pods -l 'environment,environment notin (frontend)' Annotations \u00b6 Use Kubernetes annotations to attach arbitrary non-identifying metadata to objects. Clients such as tools and libraries can retrieve this metadata. Use either labels or annotations to attach metadata to Kubernetes objects. Labels can be used to select objects and to find collections of objects that satisfy certain conditions. Annotations are not used to identify and select objects. Annotations, like labels, are key/value maps. The keys and the values in the map must be strings. \"metadata\" : { \"annotations\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } Valid annotation keys have two segments: an optional prefix and name, separated by a slash ( / ). Field Selectors \u00b6 Field selectors let you select Kubernetes resources based on the value of one or more resource fields. Here are some examples of field selector queries: metadata.name=my-service metadata.namespace!=default status.phase=Pending This kubectl command selects all Pods for which the value of the status.phase field is Running: kubectl get pods --field-selector status.phase=Running Supported field selectors vary by Kubernetes resource type. All resource types support the metadata.name and metadata.namespace fields. Use the = , == , and != operators with field selectors ( = and == mean the same thing). For example: kubectl get ingress --field-selector foo.bar=baz With operators, kubectl get services --all-namespaces --field-selector metadata.namespace!=default Chained selectors, kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always Multiple resource types, kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default Finalizers \u00b6 Finalizers are namespaced keys that tell Kubernetes to wait until specific conditions are met before it fully deletes resources marked for deletion . Finalizers alert controllers to clean up resources the deleted object owned. Finalizers are usually added to resources for a reason, so forcefully removing them can lead to issues in the cluster. Like labels, owner references describe the relationships between objects in Kubernetes, but are used for a different purpose. Kubernetes uses the owner references (not labels) to determine which Pods in the cluster need cleanup. Kubernetes processes finalizers when it identifies owner references on a resource targeted for deletion. Owners and Dependents \u00b6 In Kubernetes, some objects are owners of other objects. For example, a ReplicaSet is the owner of a set of Pods. These owned objects are dependents of their owner. Dependent objects have a metadata.ownerReferences field that references their owner object. A valid owner reference consists of the object name and a UID within the same namespace as the dependent object. Dependent objects also have an ownerReferences.blockOwnerDeletion field that takes a boolean value and controls whether specific dependents can block garbage collection from deleting their owner object. Resource \u00b6 Kubernetes resources and \"records of intent\" are all stored as API objects, and modified via RESTful calls to the API. The API allows configuration to be managed in a declarative way. Users can interact with the Kubernetes API directly, or via tools like kubectl. The core Kubernetes API is flexible and can also be extended to support custom resources. Workload Resources Pod . Pod is a collection of containers that can run on a host. PodTemplate . PodTemplate describes a template for creating copies of a predefined pod. ReplicationController . ReplicationController represents the configuration of a replication controller. ReplicaSet . ReplicaSet ensures that a specified number of pod replicas are running at any given time. Deployment . Deployment enables declarative updates for Pods and ReplicaSets. StatefulSet . StatefulSet represents a set of pods with consistent identities. ControllerRevision . ControllerRevision implements an immutable snapshot of state data. DaemonSet . DaemonSet represents the configuration of a daemon set. Job . Job represents the configuration of a single job. CronJob . CronJob represents the configuration of a single cron job. HorizontalPodAutoscaler . configuration of a horizontal pod autoscaler. HorizontalPodAutoscaler . HorizontalPodAutoscaler is the configuration for a horizontal pod autoscaler, which automatically manages the replica count of any resource implementing the scale subresource based on the metrics specified. HorizontalPodAutoscaler v2beta2 . HorizontalPodAutoscaler is the configuration for a horizontal pod autoscaler, which automatically manages the replica count of any resource implementing the scale subresource based on the metrics specified. PriorityClass . PriorityClass defines mapping from a priority class name to the priority integer value. Service Resources Service . Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy. Endpoints . Endpoints is a collection of endpoints that implement the actual service. EndpointSlice . EndpointSlice represents a subset of the endpoints that implement a service. Ingress . Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend. IngressClass . IngressClass represents the class of the Ingress, referenced by the Ingress Spec. Config and Storage Resources ConfigMap . ConfigMap holds configuration data for pods to consume. Secret . Secret holds secret data of a certain type. Volume . Volume represents a named volume in a pod that may be accessed by any container in the pod. PersistentVolumeClaim . PersistentVolumeClaim is a user's request for and claim to a persistent volume. PersistentVolume . PersistentVolume (PV) is a storage resource provisioned by an administrator. StorageClass . StorageClass describes the parameters for a class of storage for which PersistentVolumes can be dynamically provisioned. VolumeAttachment . VolumeAttachment captures the intent to attach or detach the specified volume to/from the specified node. CSIDriver . CSIDriver captures information about a Container Storage Interface (CSI) volume driver deployed on the cluster. CSINode . CSINode holds information about all CSI drivers installed on a node. CSIStorageCapacity . CSIStorageCapacity stores the result of one CSI GetCapacity call. Authentication Resources ServiceAccount . ServiceAccount binds together: a name, understood by users, and perhaps by peripheral systems, for an identity a principal that can be authenticated and authorized a set of secrets. TokenRequest . TokenRequest requests a token for a given service account. TokenReview . TokenReview attempts to authenticate a token to a known user. CertificateSigningRequest . CertificateSigningRequest objects provide a mechanism to obtain x509 certificates by submitting a certificate signing request, and having it asynchronously approved and issued. Authorization Resources LocalSubjectAccessReview . LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace. SelfSubjectAccessReview . SelfSubjectAccessReview checks whether or the current user can perform an action. SelfSubjectRulesReview . SelfSubjectRulesReview enumerates the set of actions the current user can perform within a namespace. SubjectAccessReview . SubjectAccessReview checks whether or not a user or group can perform an action. ClusterRole . ClusterRole is a cluster level, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding or ClusterRoleBinding. ClusterRoleBinding . ClusterRoleBinding references a ClusterRole, but not contain it. Role . Role is a namespaced, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding. RoleBinding . RoleBinding references a role, but does not contain it. Policy Resources LimitRange . LimitRange sets resource usage limits for each kind of resource in a Namespace. ResourceQuota . ResourceQuota sets aggregate quota restrictions enforced per namespace. NetworkPolicy . NetworkPolicy describes what network traffic is allowed for a set of Pods. PodDisruptionBudget . PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods. PodSecurityPolicy v1beta1 . PodSecurityPolicy governs the ability to make requests that affect the Security Context that will be applied to a pod and container. Extend Resources CustomResourceDefinition . CustomResourceDefinition represents a resource that should be exposed on the API server. MutatingWebhookConfiguration . MutatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and may change the object. *ValidatingWebhookConfiguration(). ValidatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and object without changing it. Cluster Resources Node . Node is a worker node in Kubernetes. Namespace . Namespace provides a scope for Names. Event . Event is a report of an event somewhere in the cluster. APIService . APIService represents a server for a particular GroupVersion. Lease . Lease defines a lease concept. RuntimeClass . RuntimeClass defines a class of container runtime supported in the cluster. FlowSchema v1beta2 . FlowSchema defines the schema of a group of flows. PriorityLevelConfiguration v1beta2 . PriorityLevelConfiguration represents the configuration of a priority level. Binding . Binding ties one object to another; for example, a pod is bound to a node by a scheduler. ComponentStatus . ComponentStatus (and ComponentStatusList) holds the cluster validation info. Command kube api-resources to get the supported API resources. Command kubectl explain RESOURCE [options] describes the fields associated with each supported API resource. Fields are identified via a simple JSONPath identifier: kubectl explain binding kubectl explain binding.metadata kubectl explain binding.metadata.name Workload Resources \u00b6 Pods \u00b6 Pods are the smallest deployable units of computing that you can create and manage in Kubernetes. A Pod is a group of one or more containers, with shared storage and network resources, and a specification for how to run the containers. A Pod's contents are always co-located and co-scheduled, and run in a shared context. A Pod models an application-specific \"logical host\": it contains one or more application containers which are relatively tightly coupled. In non-cloud contexts, applications executed on the same physical or virtual machine are analogous to cloud applications executed on the same logical host. The shared context of a Pod is a set of Linux namespaces, cgroups, and potentially other facets of isolation - the same things that isolate a Docker container. In terms of Docker concepts, a Pod is similar to a group of Docker containers with shared namespaces and shared filesystem volumes. Usually you don't need to create Pods directly, even singleton Pods. Instead, create them using workload resources such as Deployment or Job . If your Pods need to track state, consider the StatefulSet resource. Pods in a Kubernetes cluster are used in two main ways: Pods that run a single container. Pods that run multiple containers that need to work together. The \"one-container-per-Pod\" model is the most common Kubernetes use case; in this case, you can think of a Pod as a wrapper around a single container; Kubernetes manages Pods rather than managing the containers directly. A Pod can encapsulate an application composed of multiple co-located containers that are tightly coupled and need to share resources. These co-located containers form a single cohesive unit of service\u2014for example, one container serving data stored in a shared volume to the public, while a separate sidecar container refreshes or updates those files. The Pod wraps these containers, storage resources, and an ephemeral network identity together as a single unit. Grouping multiple co-located and co-managed containers in a single Pod is a relatively advanced use case. You should use this pattern only in specific instances in which your containers are tightly coupled. Each Pod is meant to run a single instance of a given application. If you want to scale your application horizontally (to provide more overall resources by running more instances), you should use multiple Pods, one for each instance. In Kubernetes, this is typically referred to as replication . Replicated Pods are usually created and managed as a group by a workload resource and its controller. Pods natively provide two kinds of shared resources for their constituent containers: networking and storage . A Pod can specify a set of shared storage volumes. All containers in the Pod can access the shared volumes, allowing those containers to share data. Each Pod is assigned a unique IP address for each address family. Within a Pod, containers share an IP address and port space, and can find each other via localhost . Containers that want to interact with a container running in a different Pod can use IP networking to communicate. When a Pod gets created, the new Pod is scheduled to run on a Node in your cluster. The Pod remains on that node until the Pod finishes execution, the Pod object is deleted, the Pod is evicted for lack of resources, or the node fails. Restarting a container in a Pod should not be confused with restarting a Pod. A Pod is not a process, but an environment for running container(s). A Pod persists until it is deleted. You can use workload resources (e.g., Deployment, StatefulSet, DaemonSet) to create and manage multiple Pods for you. A controller for the resource handles replication and rollout and automatic healing in case of Pod failure. InitContainer \u00b6 Some Pods have init containers as well as app containers. Init containers run and complete before the app containers are started. You can specify init containers in the Pod specification alongside the containers array (which describes app containers). Static Pod \u00b6 Static Pods are managed directly by the kubelet daemon on a specific node, without the API server observing them. Static Pods are always bound to one Kubelet on a specific node. The main use for static Pods is to run a self-hosted control plane: in other words, using the kubelet to supervise the individual control plane components. The kubelet automatically tries to create a mirror Pod on the Kubernetes API server for each static Pod. This means that the Pods running on a node are visible on the API server, but cannot be controlled from there. Container probes \u00b6 A probe is a diagnostic performed periodically by the kubelet on a container. To perform a diagnostic, the kubelet either executes code within the container, or makes a network request. There are four different ways to check a container using a probe. Each probe must define exactly one of these four mechanisms: exec . The diagnostic is considered successful if the command exits with a status code of 0. grpc . The diagnostic is considered successful if the status of the response is SERVING. httpGet . The diagnostic is considered successful if the response has a status code greater than or equal to 200 and less than 400. tcpSocket . The diagnostic is considered successful if the port is open. Each probe has one of three results: Success Failure Unknown Types of probe: livenessProbe . Indicates whether the container is running. readinessProbe . Indicates whether the container is ready to respond to requests. startupProbe . Indicates whether the application within the container is started. Deployment \u00b6 ReplicaSet \u00b6 A ReplicaSet\u2019s purpose is to maintain a stable set of replica Pods running at any given time. As such, it is often used to guarantee the availability of a specified number of identical Pods. You may never need to manipulate ReplicaSet objects: use a Deployment instead, and define your application in the spec section. You can specify how many Pods should run concurrently by setting replicaset.spec.replicas . The ReplicaSet will create/delete its Pods to match this number. If you do not specify replicaset.spec.replicas , then it defaults to 1 . StatefulSet \u00b6 StatefulSet Characteristics (aka, stick ID): Pod's name is immutable after created. DNS hostname is immutable after created. Mounted volume is immutable after created. Stick ID of StatefulSet won't be changed after failure, scaling, and other operations. Naming convention of StatefulSet: - . StatefulSet can be scalling by itsself, but Deployment need rely on ReplicaSet for scalling. Recommendation: reduce StatefulSet to 0 first instead of delete it directly. headless Service and governing Service: Headless Service is a normal Kubernetes Service object that its spec.clusterIP is set to None . When spec.ServiceName of StatefulSet is set to the headless Service name, the StatefulSet is now a governing Service. General procedure to create a StatefulSet: Create a StorageClass Create Headless Service Create StatefulSet based on above two. DaemonSet \u00b6 A DaemonSet ensures that all (or some) Nodes run a copy of a Pod. As nodes are removed from the cluster, those Pods are garbage collected. Deleting a DaemonSet will clean up the Pods it created. Some typical uses of a DaemonSet are: running a cluster storage daemon on every node running a logs collection daemon on every node running a node monitoring daemon on every node In a simple case, one DaemonSet, covering all nodes, would be used for each type of daemon. A more complex setup might use multiple DaemonSets for a single type of daemon, but with different flags and/or different memory and cpu requests for different hardware types. The DaemonSet controller reconciliation process reviews both existing nodes and newly created nodes. By default, the Kubernetes scheduler ignores the pods created by the DamonSet, and lets them exist on the node until the node itself is shut down. Running Pods on select Nodes: If you specify a daemonset.spec.template.spec.nodeSelector , then the DaemonSet controller will create Pods on nodes which match that node selector. If you specify a daemonset.spec.template.spec.affinity , then DaemonSet controller will create Pods on nodes which match that node affinity. If you do not specify either, then the DaemonSet controller will create Pods on all nodes. There is no field replicas in kubectl explain daemonset.spec against with kubectl explain deployment.spec.replicas . When a DaemonSet is created, each node will have one DaemonSet Pod running. We\u2019ll use a Deployment / ReplicaSet for services, mostly stateless, where we don\u2019t care where the node is running, but we care more about the number of copies of our pod is running, and we can scale those copies/replicas up or down. Rolling updates would also be a benefit here. We\u2019ll use a DaemonSet when a copy of our pod must be running on the specific nodes that we require. Our daemon pod also needs to start before any of our other pods. A DaemonSet is a simple scalability strategy for background services. When more eligible nodes are added to the cluster, the background service scales up. When nodes are removed, it will automatically scale down. Job \u00b6 CronJob \u00b6 Service Resource \u00b6 Service \u00b6 Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy. The set of Pods targeted by a Service is usually determined by a selector (label selector). Type of service resource: ClusterIP Service (default): Reliable IP, DNS, and Port. Internal acess only. NodePort Service: Expose to external access. LoadBalancer: Based on NodePort and integrated with loader balance provided by cloud venders (e.g., AWS, GCP, etc.). ExternalName: Acces will be trafficed to external service. Here is an example of yaml file to create a Service. apiVersion : v1 kind : Service metadata : name : nginx-service labels : tier : application spec : ports : - port : 80 protocol : TCP targetPort : 8080 selector : run : nginx type : NodePort Here is an example of Service. IP 10.96.17.77 is ClusterIP(VIP) of the service Port 80/TCP is the port on Pod that service listening within the cluster. TargetPort 8080/TCP is the port on the container that the service should direct traffic to. NodePort 31893/TCP is the port that can be accessed outside. Default range is 30000~32767 . The port is exposed across all nodes in cluster. Endpoints show the list of Pods matched the service labels. Name: nginx-deployment Namespace: jh-namespace Labels: tier=application Annotations: Selector: run=nginx Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 10.96.17.77 IPs: 10.96.17.77 Port: 80/TCP TargetPort: 8080/TCP NodePort: 31893/TCP Endpoints: 10.244.1.177:8080,10.244.1.178:8080,10.244.1.179:8080 + 7 more... Session Affinity: None External Traffic Policy: Cluster Events: Service kube-dns beyond Deployment coredns provides cluster DNS service in Kubernetes cluster. Service registration: Kubernetes uses cluster DNS as service registration. Registration is Service based, not Pod based. Cluster DNS (CoreDNS) is monitoring and discvering new service actively. Service Name, IP, Port will be registered. Procedure of Service registration. POST new Service to API Server. Assign ClusterIP to the new Service. Save new Service configuration info to etcd. Create endpoints with related Pod IPs associated with the new Service. Explore the new Service by ClusterDNS. Create DNS info. kube-proxy fetch Service configration info. Create IPSV rule. Procedure of Service discovery. Request DNS name resolution for a Service name. Receive ClusterIP. Traffic access to ClusterIP. No router. Forward request to Pod's default gateway. Forward request to node. No router. Forward request to Node's default gateway. Proceed the request by Node kernel. Trap the request by IPSV rule. Put destination Pod's IP into the request's destination IP. The request arrives destination Pod. FQDN format: ..svc.cluster.local . We call as unqualified name, or short name. Namespaces can segregate the cluster's address space. At the same time, it can also be used to implement access control and resource quotas. Get DNS configuration in a Pod. The IP of nameserver is same with ClusterIP of kube-dns Service, which is well-known IP for request of DNS or service discovery. root@cka001:/etc# kubectl get service kube-dns -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP,9153/TCP 7d7h root@cka001:~# kubectl exec -it nginx-5f5496dc9-bv5dx -- /bin/bash root@nginx-5f5496dc9-bv5dx:/# cat /etc/resolv.conf search jh-namespace.svc.cluster.local svc.cluster.local cluster.local nameserver 10.96.0.10 options ndots:5 Get information of kube-dns . root@cka001:~# kubectl describe service kube-dns -n kube-system Name: kube-dns Namespace: kube-system Labels: k8s-app=kube-dns kubernetes.io/cluster-service=true kubernetes.io/name=CoreDNS Annotations: prometheus.io/port: 9153 prometheus.io/scrape: true Selector: k8s-app=kube-dns Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: 10.96.0.10 IPs: 10.96.0.10 Port: dns 53/UDP TargetPort: 53/UDP Endpoints: 10.244.0.2:53,10.244.0.3:53 Port: dns-tcp 53/TCP TargetPort: 53/TCP Endpoints: 10.244.0.2:53,10.244.0.3:53 Port: metrics 9153/TCP TargetPort: 9153/TCP Endpoints: 10.244.0.2:9153,10.244.0.3:9153 Session Affinity: None Events: Endpoints \u00b6 Endpoints is a collection of endpoints that implement the actual service. When a service is created, it associates with a Endpoint object, kubectl get endpoints . A list of matched Pod by service label is maintained as Endpoint object, add new matched Pods and remove not matched Pods. Config and Storage Resources \u00b6 Volumes \u00b6 emptyDir \u00b6 An emptyDir volume is first created when a Pod is assigned to a node, and exists as long as that Pod is running on that node. The emptyDir volume is initially empty. All containers in the Pod can read and write the same files in the emptyDir volume, though that volume can be mounted at the same or different paths in each container. When a Pod is removed from a node for any reason, the data in the emptyDir is deleted permanently. A container crashing does not remove a Pod from a node. The data in an emptyDir volume is safe across container crashes. Usage: scratch space, such as for a disk-based merge sort checkpointing a long computation for recovery from crashes holding files that a content-manager container fetches while a webserver container serves the data hostPath \u00b6 A hostPath volume mounts a file or directory from the host node's filesystem into your Pod. This is not something that most Pods will need, but it offers a powerful escape hatch for some applications. hostPath volumes present many security risks, and it is a best practice to avoid the use of HostPaths when possible. When a HostPath volume MUST be used, it should be scoped to only the required file or directory, and mounted as ReadOnly. If restricting HostPath access to specific directories through AdmissionPolicy, volumeMounts MUST be required to use readOnly mounts for the policy to be effective. Usage: Running together with DaemonSet, e.g., EFK Fluentd mount log directory of local host in order to collect host log information. Running on a specific node by using hostPath volumne, which can get high performance disk I/O. Running a container that needs access to Docker internals; use a hostPath of /var/lib/docker . Running cAdvisor in a container; use a hostPath of /sys . Allowing a Pod to specify whether a given hostPath should exist prior to the Pod running, whether it should be created, and what it should exist as. Storage Class \u00b6 Procedure of StorageClass deployment and implementation: Create Kubernetes cluster and backend storage. Make sure the provisioner/plugin is ready in Kubernetes. Create a StorageClass object to link to backend storage. The StorageClass will create related PV automatically. Create a PVC object to link to the StorageClass we created. Deploy a Pod and use the PVC volume. PV \u00b6 PV Recycle Policy. Retain. Delete. Recycle. PV in-tree type: hostPath local NFS CSI Access Modes \u00b6 spec.accessModes defines mount option of a PV: ReadWriteOnce(RWO). A PV can be mounted only to a PVC with read/write mode, like block device. ReadWriteMany(RWM). A PV can be mounted to more than one PVC with read/write mode, like NFS. ReadOnlyMany(ROM). A PV can be mounted to more than one PVC with read only mode. ReadWriteOncePod (RWOP). Only support CSI type PV, can be mounted by single Pod. A PV can only be set with one option. Pod mount PVC, not PV.","title":"Memo"},{"location":"k8s/cka_en/foundamentals/memo/#kubernetes-learning-memo","text":"","title":"Kubernetes Learning Memo"},{"location":"k8s/cka_en/foundamentals/memo/#basic-concepts-of-kubernetes","text":"","title":"Basic Concepts of Kubernetes"},{"location":"k8s/cka_en/foundamentals/memo/#kubernetes-components","text":"A Kubernetes cluster consists of the components that represent the control plane and a set of machines called nodes . Kubernetes Components : Control Plane Components kube-apiserver: query and manipulate the state of objects in Kubernetes. play as \"communication hub\" among all resources in cluster. provide cluster security authentication, authorization, and role assignment. the only one can connect to etcd . etcd: all Kubernetes objects are stored on etcd. Kubernetes objects are persistent entities in the Kubernetes system, which are used to represent the state of your cluster. kube-scheduler: watches for newly created Pods with no assigned node, and selects a node for them to run on. kube-controller-manager: runs controller processes. Node controller : Responsible for noticing and responding when nodes go down. Job controller : Watches for Job objects that represent one-off tasks, then creates Pods to run those tasks to completion. Endpoints controller : Populates the Endpoints object (that is, joins Services & Pods). Service Account & Token controllers : Create default accounts and API access tokens for new namespaces. cloud-controller-manager: embeds cloud-specific control logic and only runs controllers that are specific to your cloud provider, no need for own premises and learning environment. Node controller : For checking the cloud provider to determine if a node has been deleted in the cloud after it stops responding Route controller : For setting up routes in the underlying cloud infrastructure Service controller : For creating, updating and deleting cloud provider load balancers Node Components kubelet: An agent that runs on each node in the cluster. Manage node. It makes sure that containers are running in a Pod. kubelet registers and updates nodes information to APIServer, and APIServer stores them into etcd . Manage pod. Watch pod via APIServer, and action on pods or containers in pods. Health check at container level. kube-proxy: is a network proxy that runs on each node in cluster. iptables ipvs maintains network rules on nodes. Container runtime: is the software that is responsible for running containers. Addons DNS: is a DNS server and required by all Kubernetes clusters. Web UI (Dashboard): web-based UI for Kubernetes clusters. Container Resource Monitoring: records generic time-series metrics about containers in a central database Cluster-level Logging: is responsible for saving container logs to a central log store with search/browsing interface. Scalability: Scaling out (horizontal scaling) by adding more servers to your architecture to spread the workload across more machines. Scaling up (vertical scaling) by adding more hard drives and memory to increase the computing capacity of physical servers.","title":"Kubernetes Components"},{"location":"k8s/cka_en/foundamentals/memo/#kubernetes-api","text":"The REST API is the fundamental fabric of Kubernetes. All operations and communications between components, and external user commands are REST API calls that the API Server handles. Consequently, everything in the Kubernetes platform is treated as an API object and has a corresponding entry in the API. The core of Kubernetes' control plane is the API server. CRI: Container Runtime Interface CNI: Container Network Interface CSI: Container Storage Interface The API server exposes an HTTP API that lets end users, different parts of cluster, and external components communicate with one another. The Kubernetes API lets we query and manipulate the state of API objects in Kubernetes (for example: Pods, Namespaces, ConfigMaps, and Events). Kubernetes API: OpenAPI specification OpenAPI V2 OpenAPI V3 Persistence. Kubernetes stores the serialized state of objects by writing them into etcd. API groups and versioning. Versioning is done at the API level. API resources are distinguished by their API group, resource type, namespace (for namespaced resources), and name. API changes API Extension","title":"Kubernetes API"},{"location":"k8s/cka_en/foundamentals/memo/#api-version","text":"The API versioning and software versioning are indirectly related. The API and release versioning proposal describes the relationship between API versioning and software versioning. Different API versions indicate different levels of stability and support. Here's a summary of each level: Alpha: The version names contain alpha (for example, v1alpha1). The software may contain bugs. Enabling a feature may expose bugs. A feature may be disabled by default. The support for a feature may be dropped at any time without notice. The API may change in incompatible ways in a later software release without notice. The software is recommended for use only in short-lived testing clusters, due to increased risk of bugs and lack of long-term support. Beta: The version names contain beta (for example, v2beta3). The software is well tested. Enabling a feature is considered safe. Features are enabled by default. The support for a feature will not be dropped, though the details may change. The schema and/or semantics of objects may change in incompatible ways in a subsequent beta or stable release. When this happens, migration instructions are provided. Schema changes may require deleting, editing, and re-creating API objects. The editing process may not be straightforward. The migration may require downtime for applications that rely on the feature. The software is not recommended for production uses. Subsequent releases may introduce incompatible changes. If you have multiple clusters which can be upgraded independently, you may be able to relax this restriction. Note: Please try beta features and provide feedback. After the features exit beta, it may not be practical to make more changes. Stable: The version name is vX where X is an integer. The stable versions of features appear in released software for many subsequent versions. Command to get current API kubectl api-resources","title":"API Version"},{"location":"k8s/cka_en/foundamentals/memo/#api-group","text":"API groups make it easier to extend the Kubernetes API. The API group is specified in a REST path and in the apiVersion field of a serialized object. There are several API groups in Kubernetes: The core (also called legacy) group is found at REST path /api/v1 . The core group is not specified as part of the apiVersion field, for example, apiVersion: v1. The named groups are at REST path /apis/$GROUP_NAME/$VERSION and use apiVersion: $GROUP_NAME/$VERSION (for example, apiVersion: batch/v1).","title":"API Group"},{"location":"k8s/cka_en/foundamentals/memo/#kubernetes-objects","text":"","title":"Kubernetes Objects"},{"location":"k8s/cka_en/foundamentals/memo/#objects-overview","text":"Object Spec: providing a description of the characteristics the resource created to have: its desired state . Object Status: describes the current state of the object. Example of Deployment as an object that can represent an application running on cluster. apiVersion : apps/v1 # Which version of the Kubernetes API you're using to create this object kind : Deployment # What kind of object you want to create metadata : # Data that helps uniquely identify the object, including a name string, UID, and optional namespace name : nginx-deployment spec : # What state you desire for the object selector : matchLabels : app : nginx replicas : 2 # tells deployment to run 2 pods matching the template template : metadata : labels : app : nginx spec : containers : - name : nginx image : nginx:1.14.2 ports : - containerPort : 80","title":"Objects Overview"},{"location":"k8s/cka_en/foundamentals/memo/#object-management","text":"The kubectl command-line tool supports several different ways to create and manage Kubernetes objects. Read the Kubectl book for details. A Kubernetes object should be managed using ONLY one technique. Mixing and matching techniques for the same object results in undefined behavior. Three management techniques: Imperative commands operates directly on live objects in a cluster. kubectl create deployment nginx --image nginx Imperative object configuration kubectl create -f nginx.yaml kubectl delete -f nginx.yaml -f redis.yaml kubectl replace -f nginx.yaml Declarative object configuration kubectl diff -f configs/ kubectl apply -f configs/","title":"Object Management"},{"location":"k8s/cka_en/foundamentals/memo/#object-names-and-ids","text":"Each object in your cluster has a Name that is unique for that type of resource. DNS Subdomain Names Label Names Path Segment Names Every Kubernetes object also has a UID that is unique across the whole cluster.","title":"Object Names and IDs"},{"location":"k8s/cka_en/foundamentals/memo/#namespaces","text":"In Kubernetes, namespaces provides a mechanism for isolating groups of resources within a single cluster. Names of resources need to be unique within a namespace, but not across namespaces. Namespace-based scoping is applicable only for namespaced objects (e.g. Deployments, Services, etc) and not for cluster-wide objects (e.g. StorageClass, Nodes, PersistentVolumes, etc) Not All Objects are in a Namespace. Kubernetes starts with four initial namespaces: default The default namespace for objects with no other namespace kube-system The namespace for objects created by the Kubernetes system kube-public This namespace is created automatically and is readable by all users (including those not authenticated). This namespace is mostly reserved for cluster usage, in case that some resources should be visible and readable publicly throughout the whole cluster. The public aspect of this namespace is only a convention, not a requirement. kube-node-lease This namespace holds Lease objects associated with each node. Node leases allow the kubelet to send heartbeats so that the control plane can detect node failure. Viewing namespaces: kubectl get namespace Setting the namespace for a request kubectl run nginx --image=nginx --namespace= kubectl get pods --namespace=","title":"Namespaces"},{"location":"k8s/cka_en/foundamentals/memo/#labels-and-selectors","text":"Labels are key/value pairs that are attached to objects, such as pods. Valid label keys have two segments: an optional prefix and name, separated by a slash ( / ). Labels are intended to be used to specify identifying attributes of objects that are meaningful and relevant to users. Labels can be used to organize and to select subsets of objects. Labels can be attached to objects at creation time and subsequently added and modified at any time. Each object can have a set of key/value labels defined. Each Key must be unique for a given object. Example of labels: \"metadata\" : { \"labels\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } Unlike names and UIDs, labels do not provide uniqueness. In general, we expect many objects to carry the same label(s). The API currently supports two types of selectors: equality-based, e.g., environment = production , tier != frontend set-based, e.g., environment in (production, qa) , tier notin (frontend, backend) Sample commands: kubectl get pods -l environment=production,tier=frontend kubectl get pods -l 'environment in (production),tier in (frontend)' kubectl get pods -l 'environment in (production, qa)' kubectl get pods -l 'environment,environment notin (frontend)'","title":"Labels and Selectors"},{"location":"k8s/cka_en/foundamentals/memo/#annotations","text":"Use Kubernetes annotations to attach arbitrary non-identifying metadata to objects. Clients such as tools and libraries can retrieve this metadata. Use either labels or annotations to attach metadata to Kubernetes objects. Labels can be used to select objects and to find collections of objects that satisfy certain conditions. Annotations are not used to identify and select objects. Annotations, like labels, are key/value maps. The keys and the values in the map must be strings. \"metadata\" : { \"annotations\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } Valid annotation keys have two segments: an optional prefix and name, separated by a slash ( / ).","title":"Annotations"},{"location":"k8s/cka_en/foundamentals/memo/#field-selectors","text":"Field selectors let you select Kubernetes resources based on the value of one or more resource fields. Here are some examples of field selector queries: metadata.name=my-service metadata.namespace!=default status.phase=Pending This kubectl command selects all Pods for which the value of the status.phase field is Running: kubectl get pods --field-selector status.phase=Running Supported field selectors vary by Kubernetes resource type. All resource types support the metadata.name and metadata.namespace fields. Use the = , == , and != operators with field selectors ( = and == mean the same thing). For example: kubectl get ingress --field-selector foo.bar=baz With operators, kubectl get services --all-namespaces --field-selector metadata.namespace!=default Chained selectors, kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always Multiple resource types, kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default","title":"Field Selectors"},{"location":"k8s/cka_en/foundamentals/memo/#finalizers","text":"Finalizers are namespaced keys that tell Kubernetes to wait until specific conditions are met before it fully deletes resources marked for deletion . Finalizers alert controllers to clean up resources the deleted object owned. Finalizers are usually added to resources for a reason, so forcefully removing them can lead to issues in the cluster. Like labels, owner references describe the relationships between objects in Kubernetes, but are used for a different purpose. Kubernetes uses the owner references (not labels) to determine which Pods in the cluster need cleanup. Kubernetes processes finalizers when it identifies owner references on a resource targeted for deletion.","title":"Finalizers"},{"location":"k8s/cka_en/foundamentals/memo/#owners-and-dependents","text":"In Kubernetes, some objects are owners of other objects. For example, a ReplicaSet is the owner of a set of Pods. These owned objects are dependents of their owner. Dependent objects have a metadata.ownerReferences field that references their owner object. A valid owner reference consists of the object name and a UID within the same namespace as the dependent object. Dependent objects also have an ownerReferences.blockOwnerDeletion field that takes a boolean value and controls whether specific dependents can block garbage collection from deleting their owner object.","title":"Owners and Dependents"},{"location":"k8s/cka_en/foundamentals/memo/#resource","text":"Kubernetes resources and \"records of intent\" are all stored as API objects, and modified via RESTful calls to the API. The API allows configuration to be managed in a declarative way. Users can interact with the Kubernetes API directly, or via tools like kubectl. The core Kubernetes API is flexible and can also be extended to support custom resources. Workload Resources Pod . Pod is a collection of containers that can run on a host. PodTemplate . PodTemplate describes a template for creating copies of a predefined pod. ReplicationController . ReplicationController represents the configuration of a replication controller. ReplicaSet . ReplicaSet ensures that a specified number of pod replicas are running at any given time. Deployment . Deployment enables declarative updates for Pods and ReplicaSets. StatefulSet . StatefulSet represents a set of pods with consistent identities. ControllerRevision . ControllerRevision implements an immutable snapshot of state data. DaemonSet . DaemonSet represents the configuration of a daemon set. Job . Job represents the configuration of a single job. CronJob . CronJob represents the configuration of a single cron job. HorizontalPodAutoscaler . configuration of a horizontal pod autoscaler. HorizontalPodAutoscaler . HorizontalPodAutoscaler is the configuration for a horizontal pod autoscaler, which automatically manages the replica count of any resource implementing the scale subresource based on the metrics specified. HorizontalPodAutoscaler v2beta2 . HorizontalPodAutoscaler is the configuration for a horizontal pod autoscaler, which automatically manages the replica count of any resource implementing the scale subresource based on the metrics specified. PriorityClass . PriorityClass defines mapping from a priority class name to the priority integer value. Service Resources Service . Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy. Endpoints . Endpoints is a collection of endpoints that implement the actual service. EndpointSlice . EndpointSlice represents a subset of the endpoints that implement a service. Ingress . Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend. IngressClass . IngressClass represents the class of the Ingress, referenced by the Ingress Spec. Config and Storage Resources ConfigMap . ConfigMap holds configuration data for pods to consume. Secret . Secret holds secret data of a certain type. Volume . Volume represents a named volume in a pod that may be accessed by any container in the pod. PersistentVolumeClaim . PersistentVolumeClaim is a user's request for and claim to a persistent volume. PersistentVolume . PersistentVolume (PV) is a storage resource provisioned by an administrator. StorageClass . StorageClass describes the parameters for a class of storage for which PersistentVolumes can be dynamically provisioned. VolumeAttachment . VolumeAttachment captures the intent to attach or detach the specified volume to/from the specified node. CSIDriver . CSIDriver captures information about a Container Storage Interface (CSI) volume driver deployed on the cluster. CSINode . CSINode holds information about all CSI drivers installed on a node. CSIStorageCapacity . CSIStorageCapacity stores the result of one CSI GetCapacity call. Authentication Resources ServiceAccount . ServiceAccount binds together: a name, understood by users, and perhaps by peripheral systems, for an identity a principal that can be authenticated and authorized a set of secrets. TokenRequest . TokenRequest requests a token for a given service account. TokenReview . TokenReview attempts to authenticate a token to a known user. CertificateSigningRequest . CertificateSigningRequest objects provide a mechanism to obtain x509 certificates by submitting a certificate signing request, and having it asynchronously approved and issued. Authorization Resources LocalSubjectAccessReview . LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace. SelfSubjectAccessReview . SelfSubjectAccessReview checks whether or the current user can perform an action. SelfSubjectRulesReview . SelfSubjectRulesReview enumerates the set of actions the current user can perform within a namespace. SubjectAccessReview . SubjectAccessReview checks whether or not a user or group can perform an action. ClusterRole . ClusterRole is a cluster level, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding or ClusterRoleBinding. ClusterRoleBinding . ClusterRoleBinding references a ClusterRole, but not contain it. Role . Role is a namespaced, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding. RoleBinding . RoleBinding references a role, but does not contain it. Policy Resources LimitRange . LimitRange sets resource usage limits for each kind of resource in a Namespace. ResourceQuota . ResourceQuota sets aggregate quota restrictions enforced per namespace. NetworkPolicy . NetworkPolicy describes what network traffic is allowed for a set of Pods. PodDisruptionBudget . PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods. PodSecurityPolicy v1beta1 . PodSecurityPolicy governs the ability to make requests that affect the Security Context that will be applied to a pod and container. Extend Resources CustomResourceDefinition . CustomResourceDefinition represents a resource that should be exposed on the API server. MutatingWebhookConfiguration . MutatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and may change the object. *ValidatingWebhookConfiguration(). ValidatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and object without changing it. Cluster Resources Node . Node is a worker node in Kubernetes. Namespace . Namespace provides a scope for Names. Event . Event is a report of an event somewhere in the cluster. APIService . APIService represents a server for a particular GroupVersion. Lease . Lease defines a lease concept. RuntimeClass . RuntimeClass defines a class of container runtime supported in the cluster. FlowSchema v1beta2 . FlowSchema defines the schema of a group of flows. PriorityLevelConfiguration v1beta2 . PriorityLevelConfiguration represents the configuration of a priority level. Binding . Binding ties one object to another; for example, a pod is bound to a node by a scheduler. ComponentStatus . ComponentStatus (and ComponentStatusList) holds the cluster validation info. Command kube api-resources to get the supported API resources. Command kubectl explain RESOURCE [options] describes the fields associated with each supported API resource. Fields are identified via a simple JSONPath identifier: kubectl explain binding kubectl explain binding.metadata kubectl explain binding.metadata.name","title":"Resource"},{"location":"k8s/cka_en/foundamentals/memo/#workload-resources","text":"","title":"Workload Resources"},{"location":"k8s/cka_en/foundamentals/memo/#pods","text":"Pods are the smallest deployable units of computing that you can create and manage in Kubernetes. A Pod is a group of one or more containers, with shared storage and network resources, and a specification for how to run the containers. A Pod's contents are always co-located and co-scheduled, and run in a shared context. A Pod models an application-specific \"logical host\": it contains one or more application containers which are relatively tightly coupled. In non-cloud contexts, applications executed on the same physical or virtual machine are analogous to cloud applications executed on the same logical host. The shared context of a Pod is a set of Linux namespaces, cgroups, and potentially other facets of isolation - the same things that isolate a Docker container. In terms of Docker concepts, a Pod is similar to a group of Docker containers with shared namespaces and shared filesystem volumes. Usually you don't need to create Pods directly, even singleton Pods. Instead, create them using workload resources such as Deployment or Job . If your Pods need to track state, consider the StatefulSet resource. Pods in a Kubernetes cluster are used in two main ways: Pods that run a single container. Pods that run multiple containers that need to work together. The \"one-container-per-Pod\" model is the most common Kubernetes use case; in this case, you can think of a Pod as a wrapper around a single container; Kubernetes manages Pods rather than managing the containers directly. A Pod can encapsulate an application composed of multiple co-located containers that are tightly coupled and need to share resources. These co-located containers form a single cohesive unit of service\u2014for example, one container serving data stored in a shared volume to the public, while a separate sidecar container refreshes or updates those files. The Pod wraps these containers, storage resources, and an ephemeral network identity together as a single unit. Grouping multiple co-located and co-managed containers in a single Pod is a relatively advanced use case. You should use this pattern only in specific instances in which your containers are tightly coupled. Each Pod is meant to run a single instance of a given application. If you want to scale your application horizontally (to provide more overall resources by running more instances), you should use multiple Pods, one for each instance. In Kubernetes, this is typically referred to as replication . Replicated Pods are usually created and managed as a group by a workload resource and its controller. Pods natively provide two kinds of shared resources for their constituent containers: networking and storage . A Pod can specify a set of shared storage volumes. All containers in the Pod can access the shared volumes, allowing those containers to share data. Each Pod is assigned a unique IP address for each address family. Within a Pod, containers share an IP address and port space, and can find each other via localhost . Containers that want to interact with a container running in a different Pod can use IP networking to communicate. When a Pod gets created, the new Pod is scheduled to run on a Node in your cluster. The Pod remains on that node until the Pod finishes execution, the Pod object is deleted, the Pod is evicted for lack of resources, or the node fails. Restarting a container in a Pod should not be confused with restarting a Pod. A Pod is not a process, but an environment for running container(s). A Pod persists until it is deleted. You can use workload resources (e.g., Deployment, StatefulSet, DaemonSet) to create and manage multiple Pods for you. A controller for the resource handles replication and rollout and automatic healing in case of Pod failure.","title":"Pods"},{"location":"k8s/cka_en/foundamentals/memo/#initcontainer","text":"Some Pods have init containers as well as app containers. Init containers run and complete before the app containers are started. You can specify init containers in the Pod specification alongside the containers array (which describes app containers).","title":"InitContainer"},{"location":"k8s/cka_en/foundamentals/memo/#static-pod","text":"Static Pods are managed directly by the kubelet daemon on a specific node, without the API server observing them. Static Pods are always bound to one Kubelet on a specific node. The main use for static Pods is to run a self-hosted control plane: in other words, using the kubelet to supervise the individual control plane components. The kubelet automatically tries to create a mirror Pod on the Kubernetes API server for each static Pod. This means that the Pods running on a node are visible on the API server, but cannot be controlled from there.","title":"Static Pod"},{"location":"k8s/cka_en/foundamentals/memo/#container-probes","text":"A probe is a diagnostic performed periodically by the kubelet on a container. To perform a diagnostic, the kubelet either executes code within the container, or makes a network request. There are four different ways to check a container using a probe. Each probe must define exactly one of these four mechanisms: exec . The diagnostic is considered successful if the command exits with a status code of 0. grpc . The diagnostic is considered successful if the status of the response is SERVING. httpGet . The diagnostic is considered successful if the response has a status code greater than or equal to 200 and less than 400. tcpSocket . The diagnostic is considered successful if the port is open. Each probe has one of three results: Success Failure Unknown Types of probe: livenessProbe . Indicates whether the container is running. readinessProbe . Indicates whether the container is ready to respond to requests. startupProbe . Indicates whether the application within the container is started.","title":"Container probes"},{"location":"k8s/cka_en/foundamentals/memo/#deployment","text":"","title":"Deployment"},{"location":"k8s/cka_en/foundamentals/memo/#replicaset","text":"A ReplicaSet\u2019s purpose is to maintain a stable set of replica Pods running at any given time. As such, it is often used to guarantee the availability of a specified number of identical Pods. You may never need to manipulate ReplicaSet objects: use a Deployment instead, and define your application in the spec section. You can specify how many Pods should run concurrently by setting replicaset.spec.replicas . The ReplicaSet will create/delete its Pods to match this number. If you do not specify replicaset.spec.replicas , then it defaults to 1 .","title":"ReplicaSet"},{"location":"k8s/cka_en/foundamentals/memo/#statefulset","text":"StatefulSet Characteristics (aka, stick ID): Pod's name is immutable after created. DNS hostname is immutable after created. Mounted volume is immutable after created. Stick ID of StatefulSet won't be changed after failure, scaling, and other operations. Naming convention of StatefulSet: - . StatefulSet can be scalling by itsself, but Deployment need rely on ReplicaSet for scalling. Recommendation: reduce StatefulSet to 0 first instead of delete it directly. headless Service and governing Service: Headless Service is a normal Kubernetes Service object that its spec.clusterIP is set to None . When spec.ServiceName of StatefulSet is set to the headless Service name, the StatefulSet is now a governing Service. General procedure to create a StatefulSet: Create a StorageClass Create Headless Service Create StatefulSet based on above two.","title":"StatefulSet"},{"location":"k8s/cka_en/foundamentals/memo/#daemonset","text":"A DaemonSet ensures that all (or some) Nodes run a copy of a Pod. As nodes are removed from the cluster, those Pods are garbage collected. Deleting a DaemonSet will clean up the Pods it created. Some typical uses of a DaemonSet are: running a cluster storage daemon on every node running a logs collection daemon on every node running a node monitoring daemon on every node In a simple case, one DaemonSet, covering all nodes, would be used for each type of daemon. A more complex setup might use multiple DaemonSets for a single type of daemon, but with different flags and/or different memory and cpu requests for different hardware types. The DaemonSet controller reconciliation process reviews both existing nodes and newly created nodes. By default, the Kubernetes scheduler ignores the pods created by the DamonSet, and lets them exist on the node until the node itself is shut down. Running Pods on select Nodes: If you specify a daemonset.spec.template.spec.nodeSelector , then the DaemonSet controller will create Pods on nodes which match that node selector. If you specify a daemonset.spec.template.spec.affinity , then DaemonSet controller will create Pods on nodes which match that node affinity. If you do not specify either, then the DaemonSet controller will create Pods on all nodes. There is no field replicas in kubectl explain daemonset.spec against with kubectl explain deployment.spec.replicas . When a DaemonSet is created, each node will have one DaemonSet Pod running. We\u2019ll use a Deployment / ReplicaSet for services, mostly stateless, where we don\u2019t care where the node is running, but we care more about the number of copies of our pod is running, and we can scale those copies/replicas up or down. Rolling updates would also be a benefit here. We\u2019ll use a DaemonSet when a copy of our pod must be running on the specific nodes that we require. Our daemon pod also needs to start before any of our other pods. A DaemonSet is a simple scalability strategy for background services. When more eligible nodes are added to the cluster, the background service scales up. When nodes are removed, it will automatically scale down.","title":"DaemonSet"},{"location":"k8s/cka_en/foundamentals/memo/#job","text":"","title":"Job"},{"location":"k8s/cka_en/foundamentals/memo/#cronjob","text":"","title":"CronJob"},{"location":"k8s/cka_en/foundamentals/memo/#service-resource","text":"","title":"Service Resource"},{"location":"k8s/cka_en/foundamentals/memo/#service","text":"Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy. The set of Pods targeted by a Service is usually determined by a selector (label selector). Type of service resource: ClusterIP Service (default): Reliable IP, DNS, and Port. Internal acess only. NodePort Service: Expose to external access. LoadBalancer: Based on NodePort and integrated with loader balance provided by cloud venders (e.g., AWS, GCP, etc.). ExternalName: Acces will be trafficed to external service. Here is an example of yaml file to create a Service. apiVersion : v1 kind : Service metadata : name : nginx-service labels : tier : application spec : ports : - port : 80 protocol : TCP targetPort : 8080 selector : run : nginx type : NodePort Here is an example of Service. IP 10.96.17.77 is ClusterIP(VIP) of the service Port 80/TCP is the port on Pod that service listening within the cluster. TargetPort 8080/TCP is the port on the container that the service should direct traffic to. NodePort 31893/TCP is the port that can be accessed outside. Default range is 30000~32767 . The port is exposed across all nodes in cluster. Endpoints show the list of Pods matched the service labels. Name: nginx-deployment Namespace: jh-namespace Labels: tier=application Annotations: Selector: run=nginx Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 10.96.17.77 IPs: 10.96.17.77 Port: 80/TCP TargetPort: 8080/TCP NodePort: 31893/TCP Endpoints: 10.244.1.177:8080,10.244.1.178:8080,10.244.1.179:8080 + 7 more... Session Affinity: None External Traffic Policy: Cluster Events: Service kube-dns beyond Deployment coredns provides cluster DNS service in Kubernetes cluster. Service registration: Kubernetes uses cluster DNS as service registration. Registration is Service based, not Pod based. Cluster DNS (CoreDNS) is monitoring and discvering new service actively. Service Name, IP, Port will be registered. Procedure of Service registration. POST new Service to API Server. Assign ClusterIP to the new Service. Save new Service configuration info to etcd. Create endpoints with related Pod IPs associated with the new Service. Explore the new Service by ClusterDNS. Create DNS info. kube-proxy fetch Service configration info. Create IPSV rule. Procedure of Service discovery. Request DNS name resolution for a Service name. Receive ClusterIP. Traffic access to ClusterIP. No router. Forward request to Pod's default gateway. Forward request to node. No router. Forward request to Node's default gateway. Proceed the request by Node kernel. Trap the request by IPSV rule. Put destination Pod's IP into the request's destination IP. The request arrives destination Pod. FQDN format: ..svc.cluster.local . We call as unqualified name, or short name. Namespaces can segregate the cluster's address space. At the same time, it can also be used to implement access control and resource quotas. Get DNS configuration in a Pod. The IP of nameserver is same with ClusterIP of kube-dns Service, which is well-known IP for request of DNS or service discovery. root@cka001:/etc# kubectl get service kube-dns -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP,9153/TCP 7d7h root@cka001:~# kubectl exec -it nginx-5f5496dc9-bv5dx -- /bin/bash root@nginx-5f5496dc9-bv5dx:/# cat /etc/resolv.conf search jh-namespace.svc.cluster.local svc.cluster.local cluster.local nameserver 10.96.0.10 options ndots:5 Get information of kube-dns . root@cka001:~# kubectl describe service kube-dns -n kube-system Name: kube-dns Namespace: kube-system Labels: k8s-app=kube-dns kubernetes.io/cluster-service=true kubernetes.io/name=CoreDNS Annotations: prometheus.io/port: 9153 prometheus.io/scrape: true Selector: k8s-app=kube-dns Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: 10.96.0.10 IPs: 10.96.0.10 Port: dns 53/UDP TargetPort: 53/UDP Endpoints: 10.244.0.2:53,10.244.0.3:53 Port: dns-tcp 53/TCP TargetPort: 53/TCP Endpoints: 10.244.0.2:53,10.244.0.3:53 Port: metrics 9153/TCP TargetPort: 9153/TCP Endpoints: 10.244.0.2:9153,10.244.0.3:9153 Session Affinity: None Events: ","title":"Service"},{"location":"k8s/cka_en/foundamentals/memo/#endpoints","text":"Endpoints is a collection of endpoints that implement the actual service. When a service is created, it associates with a Endpoint object, kubectl get endpoints . A list of matched Pod by service label is maintained as Endpoint object, add new matched Pods and remove not matched Pods.","title":"Endpoints"},{"location":"k8s/cka_en/foundamentals/memo/#config-and-storage-resources","text":"","title":"Config and Storage Resources"},{"location":"k8s/cka_en/foundamentals/memo/#volumes","text":"","title":"Volumes"},{"location":"k8s/cka_en/foundamentals/memo/#emptydir","text":"An emptyDir volume is first created when a Pod is assigned to a node, and exists as long as that Pod is running on that node. The emptyDir volume is initially empty. All containers in the Pod can read and write the same files in the emptyDir volume, though that volume can be mounted at the same or different paths in each container. When a Pod is removed from a node for any reason, the data in the emptyDir is deleted permanently. A container crashing does not remove a Pod from a node. The data in an emptyDir volume is safe across container crashes. Usage: scratch space, such as for a disk-based merge sort checkpointing a long computation for recovery from crashes holding files that a content-manager container fetches while a webserver container serves the data","title":"emptyDir"},{"location":"k8s/cka_en/foundamentals/memo/#hostpath","text":"A hostPath volume mounts a file or directory from the host node's filesystem into your Pod. This is not something that most Pods will need, but it offers a powerful escape hatch for some applications. hostPath volumes present many security risks, and it is a best practice to avoid the use of HostPaths when possible. When a HostPath volume MUST be used, it should be scoped to only the required file or directory, and mounted as ReadOnly. If restricting HostPath access to specific directories through AdmissionPolicy, volumeMounts MUST be required to use readOnly mounts for the policy to be effective. Usage: Running together with DaemonSet, e.g., EFK Fluentd mount log directory of local host in order to collect host log information. Running on a specific node by using hostPath volumne, which can get high performance disk I/O. Running a container that needs access to Docker internals; use a hostPath of /var/lib/docker . Running cAdvisor in a container; use a hostPath of /sys . Allowing a Pod to specify whether a given hostPath should exist prior to the Pod running, whether it should be created, and what it should exist as.","title":"hostPath"},{"location":"k8s/cka_en/foundamentals/memo/#storage-class","text":"Procedure of StorageClass deployment and implementation: Create Kubernetes cluster and backend storage. Make sure the provisioner/plugin is ready in Kubernetes. Create a StorageClass object to link to backend storage. The StorageClass will create related PV automatically. Create a PVC object to link to the StorageClass we created. Deploy a Pod and use the PVC volume.","title":"Storage Class"},{"location":"k8s/cka_en/foundamentals/memo/#pv","text":"PV Recycle Policy. Retain. Delete. Recycle. PV in-tree type: hostPath local NFS CSI","title":"PV"},{"location":"k8s/cka_en/foundamentals/memo/#access-modes","text":"spec.accessModes defines mount option of a PV: ReadWriteOnce(RWO). A PV can be mounted only to a PVC with read/write mode, like block device. ReadWriteMany(RWM). A PV can be mounted to more than one PVC with read/write mode, like NFS. ReadOnlyMany(ROM). A PV can be mounted to more than one PVC with read only mode. ReadWriteOncePod (RWOP). Only support CSI type PV, can be mounted by single Pod. A PV can only be set with one option. Pod mount PVC, not PV.","title":"Access Modes"},{"location":"k8s/cka_en/foundamentals/namespace/","text":"Namespace \u00b6 Scenario: Get namespace list Create new namespace Label a namespace Delete a namespace Demo: Get list of Namespace kubectl get namespace Get list of Namespace with Label information. kubectl get ns --show-labels Create a Namespace kubectl create namespace cka Label the new created Namespace cka . kubectl label ns cka cka=true Create Nginx Deployment in Namespace cka . kubectl create deploy nginx --image=nginx --namespace cka Check Deployments and Pods running in namespace cka . kubectl get deploy,pod -n cka Result is below. NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx 1/1 1 1 2m14s NAME READY STATUS RESTARTS AGE pod/nginx-85b98978db-bmkhf 1/1 Running 0 2m14s Delete namespace cka . All resources in the namespaces will be gone. kubectl delete ns cka Tip: Kubernetes Namespaces stuck in Terminating status. kubectl get namespace $NAMESPACE -o json | sed -e 's/\"kubernetes\"//' | kubectl replace --raw \"/api/v1/namespaces/$NAMESPACE/finalize\" -f -","title":"Namespace"},{"location":"k8s/cka_en/foundamentals/namespace/#namespace","text":"Scenario: Get namespace list Create new namespace Label a namespace Delete a namespace Demo: Get list of Namespace kubectl get namespace Get list of Namespace with Label information. kubectl get ns --show-labels Create a Namespace kubectl create namespace cka Label the new created Namespace cka . kubectl label ns cka cka=true Create Nginx Deployment in Namespace cka . kubectl create deploy nginx --image=nginx --namespace cka Check Deployments and Pods running in namespace cka . kubectl get deploy,pod -n cka Result is below. NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx 1/1 1 1 2m14s NAME READY STATUS RESTARTS AGE pod/nginx-85b98978db-bmkhf 1/1 Running 0 2m14s Delete namespace cka . All resources in the namespaces will be gone. kubectl delete ns cka Tip: Kubernetes Namespaces stuck in Terminating status. kubectl get namespace $NAMESPACE -o json | sed -e 's/\"kubernetes\"//' | kubectl replace --raw \"/api/v1/namespaces/$NAMESPACE/finalize\" -f -","title":"Namespace"},{"location":"k8s/cka_en/foundamentals/networkpolicy/","text":"Network Policy \u00b6 Replace Flannel by Calico \u00b6 Scenario Remove Flannel Install Calico Demo: If Calico was installed at the installation phase, ignore this section. Delete Flannel kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/v0.18.1/Documentation/kube-flannel.yml or kubectl delete -f kube-flannel.yml Output: Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy \"psp.flannel.unprivileged\" deleted clusterrole.rbac.authorization.k8s.io \"flannel\" deleted clusterrolebinding.rbac.authorization.k8s.io \"flannel\" deleted serviceaccount \"flannel\" deleted configmap \"kube-flannel-cfg\" deleted daemonset.apps \"kube-flannel-ds\" deleted Clean up iptables for all nodes. rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Log out and log on to host (e.g., cka001) again. Install Calico. curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Output: configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created Verify status of Calico. Make sure all Pods are running kubectl get pod -n kube-system | grep calico Output: NAME READY STATUS RESTARTS AGE calico-kube-controllers-7bc6547ffb-tjfcg 1/1 Running 0 30m calico-node-7x8jm 1/1 Running 0 30m calico-node-cwxj5 1/1 Running 0 30m calico-node-rq978 1/1 Running 0 30m If facing any error, check log in the Container. # Get Container ID crictl ps # Get log info crictl logs As we change CNI from Flannel to Calico, we need delete all Pods. All of Pods will be created automatically again. kubectl delete pod -A --all Make sure all Pods are up and running successfully. kubectl get pod -A Inbound Rules \u00b6 Scenario Create workload for test. Deny For All Ingress Allow For Specific Ingress Verify NetworkPolicy Demo: Create workload for test. \u00b6 Create three Deployments pod-netpol-1 , pod-netpol-2 , pod-netpol-3 based on image busybox . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-1 name: pod-netpol-1 spec: replicas: 1 selector: matchLabels: app: pod-netpol-1 template: metadata: labels: app: pod-netpol-1 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-2 name: pod-netpol-2 spec: replicas: 1 selector: matchLabels: app: pod-netpol-2 template: metadata: labels: app: pod-netpol-2 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-3 name: pod-netpol-3 spec: replicas: 1 selector: matchLabels: app: pod-netpol-3 template: metadata: labels: app: pod-netpol-3 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] EOF Check Pods IP. kubectl get pod -owide Output: NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-netpol-1-6494f6bf8b-n58r9 1/1 Running 0 29s 10.244.102.30 cka003 pod-netpol-2-77478d77ff-l6rzm 1/1 Running 0 29s 10.244.112.30 cka002 pod-netpol-3-68977dcb48-ql5s6 1/1 Running 0 29s 10.244.102.31 cka003 Attach to Pod pod-netpol-1 kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh Execute command ping that pod-netpol-2 and pod-netpol-3 are both reachable. / # ping 10.244.112.30 3 packets transmitted, 3 packets received, 0% packet loss / # ping 10.244.102.31 3 packets transmitted, 3 packets received, 0% packet loss Deny For All Ingress \u00b6 Create deny policy for all ingress. kubectl apply -f - << EOF apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-ingress spec: podSelector: {} policyTypes: - Ingress EOF Attach to Pod pod-netpol-1 again kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh Execute command ping that pod-netpol-2 and pod-netpol-3 are both unreachable as expected. / # ping 10.244.112.30 3 packets transmitted, 0 packets received, 100% packet loss / # ping 10.244.102.31 3 packets transmitted, 0 packets received, 100% packet loss Allow For Specific Ingress \u00b6 Create NetworkPlicy to allow ingress from pod-netpol-1 to pod-netpol-2 . kubectl apply -f - <:80 failed. Command curl :80 succeed. kubectl run centos --image=centos -n my-ns-1 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-1 -- bash Create temp pod on namespace my-ns-2 . Attach to the pod and verify the access. Command curl :80 failed. Command curl :80 failed. kubectl run centos --image=centos -n my-ns-2 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-2 -- bash Edit my-networkpolicy-1 to change ingress.from.namespaceSelector.matchLabels to my-ns-2 . Attach to temp pod on namespace my-ns-2 . Verify the access. Command curl :80 failed. Command curl :80 succeed. kubectl exec -it mycentos -n my-ns-2 -- bash Clean up: kubectl delete namespace my-ns-1 kubectl delete namespace my-ns-2","title":"Network Policy"},{"location":"k8s/cka_en/foundamentals/networkpolicy/#network-policy","text":"","title":"Network Policy"},{"location":"k8s/cka_en/foundamentals/networkpolicy/#replace-flannel-by-calico","text":"Scenario Remove Flannel Install Calico Demo: If Calico was installed at the installation phase, ignore this section. Delete Flannel kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/v0.18.1/Documentation/kube-flannel.yml or kubectl delete -f kube-flannel.yml Output: Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy \"psp.flannel.unprivileged\" deleted clusterrole.rbac.authorization.k8s.io \"flannel\" deleted clusterrolebinding.rbac.authorization.k8s.io \"flannel\" deleted serviceaccount \"flannel\" deleted configmap \"kube-flannel-cfg\" deleted daemonset.apps \"kube-flannel-ds\" deleted Clean up iptables for all nodes. rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Log out and log on to host (e.g., cka001) again. Install Calico. curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Output: configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created Verify status of Calico. Make sure all Pods are running kubectl get pod -n kube-system | grep calico Output: NAME READY STATUS RESTARTS AGE calico-kube-controllers-7bc6547ffb-tjfcg 1/1 Running 0 30m calico-node-7x8jm 1/1 Running 0 30m calico-node-cwxj5 1/1 Running 0 30m calico-node-rq978 1/1 Running 0 30m If facing any error, check log in the Container. # Get Container ID crictl ps # Get log info crictl logs As we change CNI from Flannel to Calico, we need delete all Pods. All of Pods will be created automatically again. kubectl delete pod -A --all Make sure all Pods are up and running successfully. kubectl get pod -A","title":"Replace Flannel by Calico"},{"location":"k8s/cka_en/foundamentals/networkpolicy/#inbound-rules","text":"Scenario Create workload for test. Deny For All Ingress Allow For Specific Ingress Verify NetworkPolicy Demo:","title":"Inbound Rules"},{"location":"k8s/cka_en/foundamentals/networkpolicy/#create-workload-for-test","text":"Create three Deployments pod-netpol-1 , pod-netpol-2 , pod-netpol-3 based on image busybox . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-1 name: pod-netpol-1 spec: replicas: 1 selector: matchLabels: app: pod-netpol-1 template: metadata: labels: app: pod-netpol-1 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-2 name: pod-netpol-2 spec: replicas: 1 selector: matchLabels: app: pod-netpol-2 template: metadata: labels: app: pod-netpol-2 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-3 name: pod-netpol-3 spec: replicas: 1 selector: matchLabels: app: pod-netpol-3 template: metadata: labels: app: pod-netpol-3 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] EOF Check Pods IP. kubectl get pod -owide Output: NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-netpol-1-6494f6bf8b-n58r9 1/1 Running 0 29s 10.244.102.30 cka003 pod-netpol-2-77478d77ff-l6rzm 1/1 Running 0 29s 10.244.112.30 cka002 pod-netpol-3-68977dcb48-ql5s6 1/1 Running 0 29s 10.244.102.31 cka003 Attach to Pod pod-netpol-1 kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh Execute command ping that pod-netpol-2 and pod-netpol-3 are both reachable. / # ping 10.244.112.30 3 packets transmitted, 3 packets received, 0% packet loss / # ping 10.244.102.31 3 packets transmitted, 3 packets received, 0% packet loss","title":"Create workload for test."},{"location":"k8s/cka_en/foundamentals/networkpolicy/#deny-for-all-ingress","text":"Create deny policy for all ingress. kubectl apply -f - << EOF apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-ingress spec: podSelector: {} policyTypes: - Ingress EOF Attach to Pod pod-netpol-1 again kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh Execute command ping that pod-netpol-2 and pod-netpol-3 are both unreachable as expected. / # ping 10.244.112.30 3 packets transmitted, 0 packets received, 100% packet loss / # ping 10.244.102.31 3 packets transmitted, 0 packets received, 100% packet loss","title":"Deny For All Ingress"},{"location":"k8s/cka_en/foundamentals/networkpolicy/#allow-for-specific-ingress","text":"Create NetworkPlicy to allow ingress from pod-netpol-1 to pod-netpol-2 . kubectl apply -f - <:80 failed. Command curl :80 succeed. kubectl run centos --image=centos -n my-ns-1 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-1 -- bash Create temp pod on namespace my-ns-2 . Attach to the pod and verify the access. Command curl :80 failed. Command curl :80 failed. kubectl run centos --image=centos -n my-ns-2 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-2 -- bash Edit my-networkpolicy-1 to change ingress.from.namespaceSelector.matchLabels to my-ns-2 . Attach to temp pod on namespace my-ns-2 . Verify the access. Command curl :80 failed. Command curl :80 succeed. kubectl exec -it mycentos -n my-ns-2 -- bash Clean up: kubectl delete namespace my-ns-1 kubectl delete namespace my-ns-2","title":"NetworkPolicy"},{"location":"k8s/cka_en/foundamentals/overview/","text":"Cluster Overview \u00b6 Contents \u00b6 Container Layer Kubernetes Layer Information: For environment setup, refer to Installation on Aliyun Ubuntu Container Layer \u00b6 Scenario: Use Containerd service to manage our images and containers via command nerdctl , which is same concept with Docker. Get namespace. Get containers. Get images. Get volumes. Get overall status. Get network status. Demo: Get namespaces. sudo nerdctl namespace ls Result NAME CONTAINERS IMAGES VOLUMES LABELS k8s.io 21 30 0 Get containers under specific namespace k8s.io . sudo nerdctl -n k8s.io ps Result CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0a3625f22f65 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk 121af2ecd1a1 registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll/coredns 49f6c7e3efe5 registry.aliyuncs.com/google_containers/kube-proxy:v1.24.0 \"/usr/local/bin/kube\u2026\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t/kube-proxy 4bba5fbd701d registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001 57d47b57eb12 docker.io/calico/node:v3.23.3 \"start_runit\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl/calico-node 5ce4c351a886 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl 6456eef784bf registry.aliyuncs.com/google_containers/kube-scheduler:v1.24.0 \"kube-scheduler --au\u2026\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001/kube-scheduler 6a687305871c registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 7dcb24568574 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll a06b101118b8 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001 a07ef8c3fc3a registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/etcd-cka001 b8566d3e4174 registry.aliyuncs.com/google_containers/kube-controller-manager:v1.24.0 \"kube-controller-man\u2026\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001/kube-controller-manager ca6ac26314ff registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk/coredns cdc041b4791e registry.aliyuncs.com/google_containers/etcd:3.5.3-0 \"etcd --advertise-cl\u2026\" 16 hours ago Up k8s://kube-system/etcd-cka001/etcd e0c59abadf2e registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t e0d2e5f6ccff registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001 Get images. sudo nerdctl -n k8s.io image ls -a Get volumes. After inintial installation, no volume within namespaces. sudo nerdctl -n k8s.io volume ls Get overall status sudo nerdctl stats Get network status. sudo nerdctl network ls sudo nerdctl network inspect bridge sudo nerdctl network inspect k8s-pod-network Result NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none Get network interface in host cka001 with command ip addr list . IP pool of 10.4.0.1/24 is ipam and defined in /etc/cni/net.d/nerdctl-bridge.conflist . lo : inet 127.0.0.1/8 qlen 1000 eth0 : inet /24 brd xxx.xxx.xxx.255 scope global dynamic eth0 tunl0@NONE : inet 10.244.228.192/32 scope global tunl0 cali96e32d88db2@if4 : cali93613212490@if4 : Kubernetes Layer \u00b6 Scenario: Nodes Namespaces System Pods Demo: Information: In the demo, there are three nodes, cka001 , cka002 , and cka003 . Get nodes status. kubectl get node -o wide There are four initial namespaces across three nodes. kubectl get namespace -A Result NAME STATUS AGE default Active 56m kube-node-lease Active 56m kube-public Active 56m kube-system Active 56m There are some initial pods. kubectl get pod -A -o wide Result NAMESPACE NAME READY STATUS RESTARTS AGE NODE NOMINATED NODE READINESS GATES kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 15h cka003 kube-system calico-node-255pc 1/1 Running 0 15h cka003 kube-system calico-node-7tmnb 1/1 Running 0 15h cka002 kube-system calico-node-w8nvl 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15h cka001 kube-system etcd-cka001 1/1 Running 0 15h cka001 kube-system kube-apiserver-cka001 1/1 Running 0 15h cka001 kube-system kube-controller-manager-cka001 1/1 Running 0 15h cka001 kube-system kube-proxy-dmj2t 1/1 Running 0 15h cka001 kube-system kube-proxy-n77zw 1/1 Running 0 15h cka002 kube-system kube-proxy-qs6rf 1/1 Running 0 15h cka003 kube-system kube-scheduler-cka001 1/1 Running 0 15h cka001 Summary: Below shows the relationship between containers and pods. Master node: CoreDNS: 2 Pod etcd: 1 Pod apiserver: 1 Pod controller-manager: 1 Pod scheduler: 1 Pod Calico Controller: 1 Pod All nodes: Calico Node: 1 Pod each Proxy: 1 Pod each Reference Container pause: article and artical . nerdctl","title":"Overview"},{"location":"k8s/cka_en/foundamentals/overview/#cluster-overview","text":"","title":"Cluster Overview"},{"location":"k8s/cka_en/foundamentals/overview/#contents","text":"Container Layer Kubernetes Layer Information: For environment setup, refer to Installation on Aliyun Ubuntu","title":"Contents"},{"location":"k8s/cka_en/foundamentals/overview/#container-layer","text":"Scenario: Use Containerd service to manage our images and containers via command nerdctl , which is same concept with Docker. Get namespace. Get containers. Get images. Get volumes. Get overall status. Get network status. Demo: Get namespaces. sudo nerdctl namespace ls Result NAME CONTAINERS IMAGES VOLUMES LABELS k8s.io 21 30 0 Get containers under specific namespace k8s.io . sudo nerdctl -n k8s.io ps Result CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0a3625f22f65 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk 121af2ecd1a1 registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll/coredns 49f6c7e3efe5 registry.aliyuncs.com/google_containers/kube-proxy:v1.24.0 \"/usr/local/bin/kube\u2026\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t/kube-proxy 4bba5fbd701d registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001 57d47b57eb12 docker.io/calico/node:v3.23.3 \"start_runit\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl/calico-node 5ce4c351a886 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl 6456eef784bf registry.aliyuncs.com/google_containers/kube-scheduler:v1.24.0 \"kube-scheduler --au\u2026\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001/kube-scheduler 6a687305871c registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 7dcb24568574 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll a06b101118b8 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001 a07ef8c3fc3a registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/etcd-cka001 b8566d3e4174 registry.aliyuncs.com/google_containers/kube-controller-manager:v1.24.0 \"kube-controller-man\u2026\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001/kube-controller-manager ca6ac26314ff registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk/coredns cdc041b4791e registry.aliyuncs.com/google_containers/etcd:3.5.3-0 \"etcd --advertise-cl\u2026\" 16 hours ago Up k8s://kube-system/etcd-cka001/etcd e0c59abadf2e registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t e0d2e5f6ccff registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001 Get images. sudo nerdctl -n k8s.io image ls -a Get volumes. After inintial installation, no volume within namespaces. sudo nerdctl -n k8s.io volume ls Get overall status sudo nerdctl stats Get network status. sudo nerdctl network ls sudo nerdctl network inspect bridge sudo nerdctl network inspect k8s-pod-network Result NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none Get network interface in host cka001 with command ip addr list . IP pool of 10.4.0.1/24 is ipam and defined in /etc/cni/net.d/nerdctl-bridge.conflist . lo : inet 127.0.0.1/8 qlen 1000 eth0 : inet /24 brd xxx.xxx.xxx.255 scope global dynamic eth0 tunl0@NONE : inet 10.244.228.192/32 scope global tunl0 cali96e32d88db2@if4 : cali93613212490@if4 :","title":"Container Layer"},{"location":"k8s/cka_en/foundamentals/overview/#kubernetes-layer","text":"Scenario: Nodes Namespaces System Pods Demo: Information: In the demo, there are three nodes, cka001 , cka002 , and cka003 . Get nodes status. kubectl get node -o wide There are four initial namespaces across three nodes. kubectl get namespace -A Result NAME STATUS AGE default Active 56m kube-node-lease Active 56m kube-public Active 56m kube-system Active 56m There are some initial pods. kubectl get pod -A -o wide Result NAMESPACE NAME READY STATUS RESTARTS AGE NODE NOMINATED NODE READINESS GATES kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 15h cka003 kube-system calico-node-255pc 1/1 Running 0 15h cka003 kube-system calico-node-7tmnb 1/1 Running 0 15h cka002 kube-system calico-node-w8nvl 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15h cka001 kube-system etcd-cka001 1/1 Running 0 15h cka001 kube-system kube-apiserver-cka001 1/1 Running 0 15h cka001 kube-system kube-controller-manager-cka001 1/1 Running 0 15h cka001 kube-system kube-proxy-dmj2t 1/1 Running 0 15h cka001 kube-system kube-proxy-n77zw 1/1 Running 0 15h cka002 kube-system kube-proxy-qs6rf 1/1 Running 0 15h cka003 kube-system kube-scheduler-cka001 1/1 Running 0 15h cka001 Summary: Below shows the relationship between containers and pods. Master node: CoreDNS: 2 Pod etcd: 1 Pod apiserver: 1 Pod controller-manager: 1 Pod scheduler: 1 Pod Calico Controller: 1 Pod All nodes: Calico Node: 1 Pod each Proxy: 1 Pod each Reference Container pause: article and artical . nerdctl","title":"Kubernetes Layer"},{"location":"k8s/cka_en/foundamentals/persistence/","text":"Persistence \u00b6 Scenario Creat Pod with emptyDir type Volume. Container in the Pod will mount default directory /var/lib/kubelet/pods/ on running node. Create Deployment Deployment with hostPath type volume. Container in the Deployment will mount directory defined in hostPath: on running node. PV and PVC. Set up NFS Server and share folder /nfsdata/ . Create PV mysql-pv to link to the share folder /nfsdata/ and set StorageClassName nfs . Create PVC mysql-pvc mapped with StorageClassName nfs . Create Deployment mysql to consume PVC mysql-pvc . StorageClass Create ServiceAccount nfs-client-provisioner . Create ClusterRole nfs-client-provisioner-runner and Role leader-locking-nfs-client-provisioner and bind them to the ServiceAccount so the ServiceAccount has authorization to operate the Deployment created in next step. Create Deployment nfs-client-provisioner to to add connection information for your NFS server, e.g, PROVISIONER_NAME is k8s-sigs.io/ nfs-subdir-external-provisioner Create StorageClass nfs-client link to provisioner: k8s-sigs.io/nfs-subdir-external-provisioner . Releated PV is created automatically. Create PVC nfs-pvc-from-sc mapped to PV and StorageClass nfs-client . Configuration Create a ConfigMap for content of a file, and mount this ConfigMap to a specific file in a Pod. Create a ConfigMap for username and password, and consume them within a Pod. Use ConfigMap as environment variables in Pod. Tips Delete PVC first, then delete PV. If facing Terminating status when delete a PVC, use kubectl edit pvc and remove finalize: . emptyDir \u00b6 Create a Pod hello-producer with emptyDir type Volume. cat > pod-emptydir.yaml < /producer_dir/hello; sleep 30000 volumes: - name: shared-volume emptyDir: {} EOF kubectl apply -f pod-emptydir.yaml The Pod hello-producer is running on node cka003 . kubectl get pod hello-producer -owide The Pod is running on node cka003 . NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello-producer 1/1 Running 0 6s 10.244.102.24 cka003 Log onto cka003 because the Pod hello-producer is running on the node. Set up the environment CONTAINER_RUNTIME_ENDPOINT for command crictl . Suggest to do the same for all nodes. export CONTAINER_RUNTIME_ENDPOINT=unix:///run/containerd/containerd.sock Run command crictl ps to get the container ID of Pod hello-producer . crictl ps |grep hello-producer The ID of container producer is 05f5e1bb6a1bb . CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD 50058afb3cba5 62aedd01bd852 About an hour ago Running producer 0 e6953bd4833a7 hello-producer Run command crictl inspect to get the path of mounted shared-volume , which is emptyDir . crictl inspect 50058afb3cba5 | grep source | grep empty The result is below. \"source\": \"/var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume\", Change the path to the path of mounted shared-volume we get above. We will see the content hello world of file hello . cd /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume cat hello The path /producer_dir inside the Pod is mounted to the local host path /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume . The file /producer_dir/hello we created inside the Pod is actually in the host local path. Let's delete the container producer , the container producer will be started again with new container ID and the file hello is still there. crictl ps crictl stop crictl rm Let's delete the Pod hello-producer , the container producer is deleted, file hello is deleted. kubectl delete pod hello-producer hostPath \u00b6 Apply below yaml file to create a MySQL Pod and mount a hostPath . It'll mount host directory /tmp/mysql to Pod directory /var/lib/mysql . Check locally if directory /tmp/mysql is in place. If not, create it using mkdir /tmp/mysql . cat > mysql-hostpath.yaml < cka003 Attach into the MySQL Pod on the running node. kubectl exec -it -- bash Within the Pod, go to directory /var/lib/mysql , all files in the directory are same with all files in directory /tmp/mysql on node cka003 . Connect to the database in the Pod. mysql -h 127.0.0.1 -uroot -ppassword Operate the database. mysql> show databases; mysql> connect mysql; mysql> show tables; mysql> exit PV and PVC \u00b6 Here we will use NFS as backend storage to demo how to deploy PV and PVC. Set up NFS Share \u00b6 Install nfs-kernel-server Log onto cka002 . Choose one Worker cka002 to build NFS server. sudo apt-get install -y nfs-kernel-server Configure Share Folder Create share folder. mkdir /nfsdata Append one line in file /etc/exports . cat >> /etc/exports << EOF /nfsdata *(rw,sync,no_root_squash) EOF There are many different NFS sharing options, including these: * : accessable to all IPs, or specific IPs. rw : Share as read-write. Keep in mind that normal Linux permissions still apply. (Note that this is a default option.) ro : Share as read-only. sync : File data changes are made to disk immediately, which has an impact on performance, but is less likely to result in data loss. On som* `distributions this is the default. async : The opposite of sync; file data changes are made initially to memory. This speeds up performance but is more likely to result in data loss. O* `some distributions this is the default. root_squash : Map the root user and group account from the NFS client to the anonymous accounts, typically either the nobody account or the nfsnobod* `account. See the next section, \u201cUser ID Mapping,\u201d for more details. (Note that this is a default option.) no_root_squash : Map the root user and group account from the NFS client to the local root and group accounts. We will use password-free remote mount based on nfs and rpcbind services between Linux servers, not based on smb service. The two servers must first grant credit, install and set up nfs and rpcbind services on the server side, set the common directory, start the service, and mount it on the client Start rpcbind service. sudo systemctl enable rpcbind sudo systemctl restart rpcbind Start nfs service. sudo systemctl enable nfs-server sudo systemctl start nfs-server Once /etc/exports is changed, we need run below command to make change effected. exportfs -ra Result exportfs: /etc/exports [1]: Neither 'subtree_check' or 'no_subtree_check' specified for export \"*:/nfsdata\". Assuming default behaviour ('no_subtree_check'). NOTE: this default has changed since nfs-utils version 1.0.x Check whether sharefolder is configured. showmount -e And see below output. Export list for cka002: /nfsdata * Install NFS Client Install NFS client on all nodes. sudo apt-get install -y nfs-common Verify NFS Server Log onto any nodes to verify NFS service and sharefolder list. Log onto cka001 and check sharefolder status on cka002 . showmount -e cka002 Below result will be shown if no issues. Export list for cka002: /nfsdata * Mount NFS Execute below command to mount remote NFS folder on any other non-NFS-server node, e.g., cka001 or cka003 . mkdir /remote-nfs-dir mount -t nfs cka002:/nfsdata /remote-nfs-dir/ Use command df -h to verify mount point. Below is the sample output. Filesystem Size Used Avail Use% Mounted on cka002:/nfsdata 40G 5.8G 32G 16% /remote-nfs-dir Create PV \u00b6 Create a PV mysql-pv . Replace the NFS Server IP with actual IP (here is ) that NFS server cka002 is running on. kubectl apply -f - < EOF Check the PV. kubectl get pv The result: NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mysql-pv 1Gi RWO Retain Available nfs 19s Create PVC \u00b6 Create a PVC mysql-pvc and specify storage size, access mode, and storage class. The PVC mysql-pvc will be binded with PV automatically via storage class name. kubectl apply -f - < nfs-provisioner-rbac.yaml < ( cka002 ). Replace NFS server IP with actual IP (here is ) cat > nfs-provisioner-deployment.yaml < - name: NFS_PATH value: /nfsdata volumes: - name: nfs-client-root nfs: server: path: /nfsdata EOF kubectl apply -f nfs-provisioner-deployment.yaml Create NFS StorageClass \u00b6 Create StorageClass nfs-client . Define the NFS subdir external provisioner's Kubernetes Storage Class. vi nfs-storageclass.yaml And add below info to create NFS StorageClass. apiVersion : storage.k8s.io/v1 kind : StorageClass metadata : name : nfs-client annotations : storageclass.kubernetes.io/is-default-class : \"true\" provisioner : k8s-sigs.io/nfs-subdir-external-provisioner parameters : pathPattern : \"${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}\" onDelete : delete Apply the yaml file. kubectl apply -f nfs-storageclass.yaml Create PVC \u00b6 Create PVC nfs-pvc-from-sc . kubectl apply -f - < mysql-with-sc-pvc-7c97d875f8-wkvr9 1/1 Running 0 3m37s 10.244.102.27 cka003 Let's check directory /nfsdata/ on NFS server cka002 . ll /nfsdata/ Two folders were created. Same content of /remote-nfs-dir/ on other nodes. drwxrwxrwx 6 systemd-coredump root 4096 Jul 23 23:35 dev/ drwxr-xr-x 6 systemd-coredump root 4096 Jul 23 22:29 mysqldata/ Namespace name is used as folder name under directory /nfsdata/ and it is mounted to Pod. By default, namespace name will be used at mount point. If we want to use customized folder for that purpose, we need claim an annotation nfs.io/storage-path , e.g., below example. Create PVC test-claim on Namespace kube-system and consume volume nfs-client . kubectl apply -f - < ..data/password lrwxrwxrwx 1 root root 15 Jul 23 16:30 username -> ..data/username And we can get the content of each element, which are predefined before. / # cat /tmp/secret/username admin / # cat /tmp/secret/password 123456 Additional Cases \u00b6 Various way to create ConfigMap \u00b6 ConfigMap can be created by file, directory, or value. Let's create a ConfigMap colors includes: Four files with four color names. One file with favorite color name. mkdir configmap cd configmap mkdir primary echo c > primary/cyan echo m > primary/magenta echo y > primary/yellow echo k > primary/black echo \"known as key\" >> primary/black echo blue > favorite Final structure looks like below via command tree configmap . configmap \u251c\u2500\u2500 favorite \u2514\u2500\u2500 primary \u251c\u2500\u2500 black \u251c\u2500\u2500 cyan \u251c\u2500\u2500 magenta \u2514\u2500\u2500 yellow Create ConfigMap referring above files we created. Make sure we are now in the path ~/configmap . kubectl create configmap colors \\ --from-literal=text=black \\ --from-file=./favorite \\ --from-file=./primary/ Check content of the ConfigMap colors . kubectl get configmap colors -o yaml apiVersion : v1 data : black : | k known as key cyan : | c favorite : | blue magenta : | m text : black yellow : | y kind : ConfigMap metadata : creationTimestamp : \"2022-07-12T16:38:27Z\" name : colors namespace : dev resourceVersion : \"2377258\" uid : d5ab133f-5e4d-41d4-bc9e-2bbb22a872a1 Set environment variable via ConfigMap \u00b6 Here we will create a Pod pod-configmap-env and set the environment variable ilike and assign value of favorite from ConfigMap colors . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env spec: containers: - name: nginx image: nginx env: - name: ilike valueFrom: configMapKeyRef: name: colors key: favorite EOF Attach to the Pod pod-configmap-env . kubectl exec -it pod-configmap-env -- bash Verify the value of env variable ilike is blue , which is the value of favorite of ConfigMap colors . root@pod-configmap-env:/# echo $ ilike blue We can also use all key-value of ConfigMap to set up environment variables of Pod. kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env-2 spec: containers: - name: nginx image: nginx envFrom: - configMapRef: name: colors EOF Attach to the Pod pod-configmap-env-2 . kubectl exec -it pod-configmap-env-2 -- bash Verify the value of env variables based on key-values we defined in ConfigMap colors . root@pod-configmap-env-2:/# echo $ black k known as key root@pod-configmap-env-2:/# echo $ cyan c root@pod-configmap-env-2:/# echo $ favorite blue","title":"Persistence"},{"location":"k8s/cka_en/foundamentals/persistence/#persistence","text":"Scenario Creat Pod with emptyDir type Volume. Container in the Pod will mount default directory /var/lib/kubelet/pods/ on running node. Create Deployment Deployment with hostPath type volume. Container in the Deployment will mount directory defined in hostPath: on running node. PV and PVC. Set up NFS Server and share folder /nfsdata/ . Create PV mysql-pv to link to the share folder /nfsdata/ and set StorageClassName nfs . Create PVC mysql-pvc mapped with StorageClassName nfs . Create Deployment mysql to consume PVC mysql-pvc . StorageClass Create ServiceAccount nfs-client-provisioner . Create ClusterRole nfs-client-provisioner-runner and Role leader-locking-nfs-client-provisioner and bind them to the ServiceAccount so the ServiceAccount has authorization to operate the Deployment created in next step. Create Deployment nfs-client-provisioner to to add connection information for your NFS server, e.g, PROVISIONER_NAME is k8s-sigs.io/ nfs-subdir-external-provisioner Create StorageClass nfs-client link to provisioner: k8s-sigs.io/nfs-subdir-external-provisioner . Releated PV is created automatically. Create PVC nfs-pvc-from-sc mapped to PV and StorageClass nfs-client . Configuration Create a ConfigMap for content of a file, and mount this ConfigMap to a specific file in a Pod. Create a ConfigMap for username and password, and consume them within a Pod. Use ConfigMap as environment variables in Pod. Tips Delete PVC first, then delete PV. If facing Terminating status when delete a PVC, use kubectl edit pvc and remove finalize: .","title":"Persistence"},{"location":"k8s/cka_en/foundamentals/persistence/#emptydir","text":"Create a Pod hello-producer with emptyDir type Volume. cat > pod-emptydir.yaml < /producer_dir/hello; sleep 30000 volumes: - name: shared-volume emptyDir: {} EOF kubectl apply -f pod-emptydir.yaml The Pod hello-producer is running on node cka003 . kubectl get pod hello-producer -owide The Pod is running on node cka003 . NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello-producer 1/1 Running 0 6s 10.244.102.24 cka003 Log onto cka003 because the Pod hello-producer is running on the node. Set up the environment CONTAINER_RUNTIME_ENDPOINT for command crictl . Suggest to do the same for all nodes. export CONTAINER_RUNTIME_ENDPOINT=unix:///run/containerd/containerd.sock Run command crictl ps to get the container ID of Pod hello-producer . crictl ps |grep hello-producer The ID of container producer is 05f5e1bb6a1bb . CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD 50058afb3cba5 62aedd01bd852 About an hour ago Running producer 0 e6953bd4833a7 hello-producer Run command crictl inspect to get the path of mounted shared-volume , which is emptyDir . crictl inspect 50058afb3cba5 | grep source | grep empty The result is below. \"source\": \"/var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume\", Change the path to the path of mounted shared-volume we get above. We will see the content hello world of file hello . cd /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume cat hello The path /producer_dir inside the Pod is mounted to the local host path /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume . The file /producer_dir/hello we created inside the Pod is actually in the host local path. Let's delete the container producer , the container producer will be started again with new container ID and the file hello is still there. crictl ps crictl stop crictl rm Let's delete the Pod hello-producer , the container producer is deleted, file hello is deleted. kubectl delete pod hello-producer","title":"emptyDir"},{"location":"k8s/cka_en/foundamentals/persistence/#hostpath","text":"Apply below yaml file to create a MySQL Pod and mount a hostPath . It'll mount host directory /tmp/mysql to Pod directory /var/lib/mysql . Check locally if directory /tmp/mysql is in place. If not, create it using mkdir /tmp/mysql . cat > mysql-hostpath.yaml < cka003 Attach into the MySQL Pod on the running node. kubectl exec -it -- bash Within the Pod, go to directory /var/lib/mysql , all files in the directory are same with all files in directory /tmp/mysql on node cka003 . Connect to the database in the Pod. mysql -h 127.0.0.1 -uroot -ppassword Operate the database. mysql> show databases; mysql> connect mysql; mysql> show tables; mysql> exit","title":"hostPath"},{"location":"k8s/cka_en/foundamentals/persistence/#pv-and-pvc","text":"Here we will use NFS as backend storage to demo how to deploy PV and PVC.","title":"PV and PVC"},{"location":"k8s/cka_en/foundamentals/persistence/#set-up-nfs-share","text":"Install nfs-kernel-server Log onto cka002 . Choose one Worker cka002 to build NFS server. sudo apt-get install -y nfs-kernel-server Configure Share Folder Create share folder. mkdir /nfsdata Append one line in file /etc/exports . cat >> /etc/exports << EOF /nfsdata *(rw,sync,no_root_squash) EOF There are many different NFS sharing options, including these: * : accessable to all IPs, or specific IPs. rw : Share as read-write. Keep in mind that normal Linux permissions still apply. (Note that this is a default option.) ro : Share as read-only. sync : File data changes are made to disk immediately, which has an impact on performance, but is less likely to result in data loss. On som* `distributions this is the default. async : The opposite of sync; file data changes are made initially to memory. This speeds up performance but is more likely to result in data loss. O* `some distributions this is the default. root_squash : Map the root user and group account from the NFS client to the anonymous accounts, typically either the nobody account or the nfsnobod* `account. See the next section, \u201cUser ID Mapping,\u201d for more details. (Note that this is a default option.) no_root_squash : Map the root user and group account from the NFS client to the local root and group accounts. We will use password-free remote mount based on nfs and rpcbind services between Linux servers, not based on smb service. The two servers must first grant credit, install and set up nfs and rpcbind services on the server side, set the common directory, start the service, and mount it on the client Start rpcbind service. sudo systemctl enable rpcbind sudo systemctl restart rpcbind Start nfs service. sudo systemctl enable nfs-server sudo systemctl start nfs-server Once /etc/exports is changed, we need run below command to make change effected. exportfs -ra Result exportfs: /etc/exports [1]: Neither 'subtree_check' or 'no_subtree_check' specified for export \"*:/nfsdata\". Assuming default behaviour ('no_subtree_check'). NOTE: this default has changed since nfs-utils version 1.0.x Check whether sharefolder is configured. showmount -e And see below output. Export list for cka002: /nfsdata * Install NFS Client Install NFS client on all nodes. sudo apt-get install -y nfs-common Verify NFS Server Log onto any nodes to verify NFS service and sharefolder list. Log onto cka001 and check sharefolder status on cka002 . showmount -e cka002 Below result will be shown if no issues. Export list for cka002: /nfsdata * Mount NFS Execute below command to mount remote NFS folder on any other non-NFS-server node, e.g., cka001 or cka003 . mkdir /remote-nfs-dir mount -t nfs cka002:/nfsdata /remote-nfs-dir/ Use command df -h to verify mount point. Below is the sample output. Filesystem Size Used Avail Use% Mounted on cka002:/nfsdata 40G 5.8G 32G 16% /remote-nfs-dir","title":"Set up NFS Share"},{"location":"k8s/cka_en/foundamentals/persistence/#create-pv","text":"Create a PV mysql-pv . Replace the NFS Server IP with actual IP (here is ) that NFS server cka002 is running on. kubectl apply -f - < EOF Check the PV. kubectl get pv The result: NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mysql-pv 1Gi RWO Retain Available nfs 19s","title":"Create PV"},{"location":"k8s/cka_en/foundamentals/persistence/#create-pvc","text":"Create a PVC mysql-pvc and specify storage size, access mode, and storage class. The PVC mysql-pvc will be binded with PV automatically via storage class name. kubectl apply -f - < nfs-provisioner-rbac.yaml < ( cka002 ). Replace NFS server IP with actual IP (here is ) cat > nfs-provisioner-deployment.yaml < - name: NFS_PATH value: /nfsdata volumes: - name: nfs-client-root nfs: server: path: /nfsdata EOF kubectl apply -f nfs-provisioner-deployment.yaml","title":"Create Provisioner's Deloyment"},{"location":"k8s/cka_en/foundamentals/persistence/#create-nfs-storageclass","text":"Create StorageClass nfs-client . Define the NFS subdir external provisioner's Kubernetes Storage Class. vi nfs-storageclass.yaml And add below info to create NFS StorageClass. apiVersion : storage.k8s.io/v1 kind : StorageClass metadata : name : nfs-client annotations : storageclass.kubernetes.io/is-default-class : \"true\" provisioner : k8s-sigs.io/nfs-subdir-external-provisioner parameters : pathPattern : \"${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}\" onDelete : delete Apply the yaml file. kubectl apply -f nfs-storageclass.yaml","title":"Create NFS StorageClass"},{"location":"k8s/cka_en/foundamentals/persistence/#create-pvc_1","text":"Create PVC nfs-pvc-from-sc . kubectl apply -f - < mysql-with-sc-pvc-7c97d875f8-wkvr9 1/1 Running 0 3m37s 10.244.102.27 cka003 Let's check directory /nfsdata/ on NFS server cka002 . ll /nfsdata/ Two folders were created. Same content of /remote-nfs-dir/ on other nodes. drwxrwxrwx 6 systemd-coredump root 4096 Jul 23 23:35 dev/ drwxr-xr-x 6 systemd-coredump root 4096 Jul 23 22:29 mysqldata/ Namespace name is used as folder name under directory /nfsdata/ and it is mounted to Pod. By default, namespace name will be used at mount point. If we want to use customized folder for that purpose, we need claim an annotation nfs.io/storage-path , e.g., below example. Create PVC test-claim on Namespace kube-system and consume volume nfs-client . kubectl apply -f - < ..data/password lrwxrwxrwx 1 root root 15 Jul 23 16:30 username -> ..data/username And we can get the content of each element, which are predefined before. / # cat /tmp/secret/username admin / # cat /tmp/secret/password 123456","title":"Secret"},{"location":"k8s/cka_en/foundamentals/persistence/#additional-cases","text":"","title":"Additional Cases"},{"location":"k8s/cka_en/foundamentals/persistence/#various-way-to-create-configmap","text":"ConfigMap can be created by file, directory, or value. Let's create a ConfigMap colors includes: Four files with four color names. One file with favorite color name. mkdir configmap cd configmap mkdir primary echo c > primary/cyan echo m > primary/magenta echo y > primary/yellow echo k > primary/black echo \"known as key\" >> primary/black echo blue > favorite Final structure looks like below via command tree configmap . configmap \u251c\u2500\u2500 favorite \u2514\u2500\u2500 primary \u251c\u2500\u2500 black \u251c\u2500\u2500 cyan \u251c\u2500\u2500 magenta \u2514\u2500\u2500 yellow Create ConfigMap referring above files we created. Make sure we are now in the path ~/configmap . kubectl create configmap colors \\ --from-literal=text=black \\ --from-file=./favorite \\ --from-file=./primary/ Check content of the ConfigMap colors . kubectl get configmap colors -o yaml apiVersion : v1 data : black : | k known as key cyan : | c favorite : | blue magenta : | m text : black yellow : | y kind : ConfigMap metadata : creationTimestamp : \"2022-07-12T16:38:27Z\" name : colors namespace : dev resourceVersion : \"2377258\" uid : d5ab133f-5e4d-41d4-bc9e-2bbb22a872a1","title":"Various way to create ConfigMap"},{"location":"k8s/cka_en/foundamentals/persistence/#set-environment-variable-via-configmap","text":"Here we will create a Pod pod-configmap-env and set the environment variable ilike and assign value of favorite from ConfigMap colors . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env spec: containers: - name: nginx image: nginx env: - name: ilike valueFrom: configMapKeyRef: name: colors key: favorite EOF Attach to the Pod pod-configmap-env . kubectl exec -it pod-configmap-env -- bash Verify the value of env variable ilike is blue , which is the value of favorite of ConfigMap colors . root@pod-configmap-env:/# echo $ ilike blue We can also use all key-value of ConfigMap to set up environment variables of Pod. kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env-2 spec: containers: - name: nginx image: nginx envFrom: - configMapRef: name: colors EOF Attach to the Pod pod-configmap-env-2 . kubectl exec -it pod-configmap-env-2 -- bash Verify the value of env variables based on key-values we defined in ConfigMap colors . root@pod-configmap-env-2:/# echo $ black k known as key root@pod-configmap-env-2:/# echo $ cyan c root@pod-configmap-env-2:/# echo $ favorite blue","title":"Set environment variable via ConfigMap"},{"location":"k8s/cka_en/foundamentals/pod/","text":"Work on pod \u00b6 Create pod \u00b6 Create pod my-first-podl . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-first-pod spec: containers: - name: nginx image: nginx:mainline ports: - containerPort: 80 EOF Verify status of the pod just created. kubectl get pods -o wide Track pod \u00b6 Check logs of the pod just created. kubectl logs my-first-pod In case logs or describe or any other of the output generating commands don't help us to get to the root cause of an issue, we can use use kubectl exec -it -- bash command to look into it ourselves. kubectl exec -it my-first-pod -- bash root@my-first-pod:/# ls root@my-first-pod:/# cd bin root@my-first-pod:/bin# ls root@my-first-pod:/bin# exit Execute command kubectl explain pod.spec will get details of Spec segment of Pod kind in yaml file. We can check the official API reference of the pod resource for help or use kubectl explain pod to get a command-line based description of the resource. By appending . to the resource type, the explain command will provide more details on the specified field. kubectl explain pod.kind kubectl explain pod.spec kubectl explain pod.spec.containers kubectl explain pod.spec.containers.name Label pod \u00b6 Get pod's label with option --show-labels . kubectl get pods kubectl get pods --show-labels Add two labels to the pod pod my-first-pod . kubectl label pod my-first-pod nginx=mainline kubectl label pod my-first-pod env=demo kubectl get pods --show-labels Search pod by labels. kubectl get pod -l env=demo kubectl get pod -l env=demo,nginx=mainline kubectl get pod -l env=training Remove label kubectl label pods my-first-pod env- kubectl get pods --show-labels Describe pod. kubectl describe pod my-first-pod Delete pod. Run watch kubectl get pods to monitor the pod status. kubectl delete pod my-first-pod watch kubectl get pods Static Pod \u00b6 Scenario *Create a static pod. * kubectl will automatically check yaml file in /etc/kubernetes/manifests/ and create the static pod once it's detected. Demo: Some system static Pods are already in place. ll /etc/kubernetes/manifests/ Result -rw------- 1 root root 2292 Jul 23 10:45 etcd.yaml -rw------- 1 root root 3889 Jul 23 10:45 kube-apiserver.yaml -rw------- 1 root root 3395 Jul 23 10:45 kube-controller-manager.yaml -rw------- 1 root root 1464 Jul 23 10:45 kube-scheduler.yaml Create yaml file my-nginx.yaml in directory /etc/kubernetes/manifests/ . Once the file is created, the static pod my-nginx is created automatically. kubectl run my-nginx --image=nginx:mainline --dry-run=client -n default -oyaml | sudo tee /etc/kubernetes/manifests/my-nginx.yaml Check status of the Pod my-nginx . The node name cka001 is part of the Pod name, which means the Pod is running on node cka001 . kubectl get pod -o wide Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cka001 1/1 Running 0 20s 10.244.228.196 cka001 Delete the yaml file /etc/kubernetes/manifests/my-nginx.yaml , the static pod will be deleted automatically. sudo rm /etc/kubernetes/manifests/my-nginx.yaml Multi-Container Pod \u00b6 Scenario: Create Multi-Container Pod Describe the Pod Check the log of Pod Check the log of Containers Create a Pod multi-container-pod with multiple container container-1-nginx and container-2-alpine . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: multi-container-pod spec: containers: - name: container-1-nginx image: nginx ports: - containerPort: 80 - name: container-2-alpine image: alpine command: [\"watch\", \"wget\", \"-qO-\", \"localhost\"] EOF Get the status. kubectl get pod multi-container-pod Result NAME READY STATUS RESTARTS AGE multi-container-pod 2/2 Running 0 81s Get details of the pod. kubectl describe pod multi-container-pod Result ....... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 41s default-scheduler Successfully assigned dev/multi-container-pod to cka002 Normal Pulling 40s kubelet Pulling image \"nginx\" Normal Pulled 23s kubelet Successfully pulled image \"nginx\" in 16.767129903s Normal Created 22s kubelet Created container container-1-nginx Normal Started 22s kubelet Started container container-1-nginx Normal Pulling 22s kubelet Pulling image \"alpine\" Normal Pulled 14s kubelet Successfully pulled image \"alpine\" in 7.776104353s Normal Created 14s kubelet Created container container-2-alpine Normal Started 14s kubelet Started container container-2-alpine For multi-container pod, container name is needed if we want to get log of pod via command kubectl logs . Without the container name, we receive error. kubectl logs multi-container-pod Result error: a container name must be specified for pod multi-container-pod, choose one of: [container-1-nginx container-2-alpine] With specified container name, we get the log info. kubectl logs multi-container-pod container-1-nginx Result ...... ::1 - - [23/Jul/2022:04:06:37 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"Wget\" \"-\" Same if we need specify container name to login into the pod via command kubectl exec -it -c -- . kubectl exec -it multi-container-pod -c container-1-nginx -- /bin/bash root@multi-container-pod:/# ls Clean up kubectl delete pod multi-container-pod Quick reference of a simple yaml file to create Multiple Containers. kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-multi-pod spec: containers: - image: nginx name: nginx - image: memcached name: memcached - image: redis name: redis EOF Scenario: Create a Pod my-busybox with a container container-1-busybox . The container will write message to file /var/log/my-pod-busybox.log . Add another container container-2-busybox (Sidecar) to the Pod my-busybox . The sidecar container read message from file /var/log/my-pod-busybox.log . Tips: create a Volume to store the log file, which is shared with two containers. Demo: Create a Pod my-busybox with a container container-1-busybox . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-busybox spec: containers: - name: container-1-busybox image: busybox args: - /bin/sh - -c - > i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=$((i+1)); sleep 1; done EOF Search emptyDir in the Kubernetes documetation. Refer to below template for emptyDir via https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/ Add below new features into the Pod Volume: volume name: logfile type: emptyDir Update existing container: name: container-1-busybox volumeMounts name: logfile mounthPath: /var/log Add new container: name: container-2-busybox image: busybox args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log'] volumeMounts: name: logfile mountPath: /var/log kubectl get pod my-busybox -o yaml > my-busybox.yaml vi my-busybox.yaml kubectl delete pod my-busybox kubectl apply -f my-busybox.yaml kubectl logs my-busybox -c container-2-busybox The final file my-busybox.yaml looks like below. apiVersion: v1 kind: Pod metadata: annotations: cni.projectcalico.org/containerID: 89644b6b073cd152f94b4cae7bdea6bbc3292cf59afd4f28102bd74f0205c9e4 cni.projectcalico.org/podIP: 10.244.102.20/32 cni.projectcalico.org/podIPs: 10.244.102.20/32 kubectl.kubernetes.io/last-applied-configuration: | {\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"my-busybox\",\"namespace\":\"dev\"},\"spec\":{\"containers\":[{\"args\":[\"/bin/sh\",\"-c\",\"i=0; while true; do\\n echo \\\"Hello message from container-1: \\\" \\u003e\\u003e /var/log/my-pod-busybox.log;\\n i=1;\\n sleep 1;\\ndone\\n\"],\"image\":\"busybox\",\"name\":\"container-1-busybox\"}]}} creationTimestamp: \"2022-07-29T22:58:27Z\" name: my-busybox namespace: dev resourceVersion: \"1185720\" uid: c5e62a16-4459-4828-a441-7d1471b89a56 spec: containers: - name: container-2-busybox image: busybox args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log'] volumeMounts: - name: logfile mountPath: /var/log - args: - /bin/sh - -c - | i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=1; sleep 1; done image: busybox imagePullPolicy: Always name: container-1-busybox resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - name: logfile mountPath: /var/log - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: kube-api-access-mhxlf readOnly: true dnsPolicy: ClusterFirst enableServiceLinks: true nodeName: cka003 preemptionPolicy: PreemptLowerPriority priority: 0 restartPolicy: Always schedulerName: default-scheduler securityContext: {} serviceAccount: default serviceAccountName: default terminationGracePeriodSeconds: 30 tolerations: - effect: NoExecute key: node.kubernetes.io/not-ready operator: Exists tolerationSeconds: 300 - effect: NoExecute key: node.kubernetes.io/unreachable operator: Exists tolerationSeconds: 300 volumes: - name: logfile emptyDir: {} - name: kube-api-access-mhxlf projected: defaultMode: 420 sources: - serviceAccountToken: expirationSeconds: 3607 path: token - configMap: items: - key: ca.crt path: ca.crt name: kube-root-ca.crt - downwardAPI: items: - fieldRef: apiVersion: v1 fieldPath: metadata.namespace path: namespace status: conditions: - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:27Z\" status: \"True\" type: Initialized - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:30Z\" status: \"True\" type: Ready - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:30Z\" status: \"True\" type: ContainersReady - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:27Z\" status: \"True\" type: PodScheduled containerStatuses: - containerID: containerd://fd42d4ba4d94d8918d8846327b1db2328be13c5f93f381877ff0228ed7b5468d image: docker.io/library/busybox:latest imageID: docker.io/library/busybox@sha256:0e97a8ca6955f22dbc7db9e9dbe970971f423541e52c34b8cb96ccc88d6a3883 lastState: {} name: container-1-busybox ready: true restartCount: 0 started: true state: running: startedAt: \"2022-07-29T22:58:30Z\" hostIP: phase: Running podIP: 10.244.102.20 podIPs: - ip: 10.244.102.20 qosClass: BestEffort startTime: \"2022-07-29T22:58:27Z\" Clean up: kubectl delete pod my-busybox initContainer Pod \u00b6 Scenario: Create Pod myapp-pod that has two init containers. myapp-container init-mydb Create two Services. myservice mydb Conclusion: myapp-container waits for Service myservice up in order to resolve the name myservice.dev.svc.cluster.local init-mydb waits for Service mydb up in order to resolve the name mydb.dev.svc.cluster.local . Demo: Create Pod myapp-pod with below yaml file. Create yaml file myapp-pod.yaml and add below content. Note: Due to the command $(cat /var/..... will be treated as host variable, we can not use echo to generate the file. It's the variabel in container itself. vi myapp-pod.yaml Content apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp spec: containers: - name: myapp-container image: busybox:1.28 command: ['sh', '-c', 'echo The app is running! && sleep 3600'] initContainers: - name: init-myservice image: busybox:1.28 command: ['sh', '-c', \"until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done\"] - name: init-mydb image: busybox:1.28 command: ['sh', '-c', \"until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done\"] Apply the yaml file to create the Pod. kubectl apply -f myapp-pod.yaml Check Pod status. kubectl get pod myapp-pod Result NAME READY STATUS RESTARTS AGE myapp-pod 0/1 Init:0/2 0 12m Inspect Pods. Get two errors: nslookup: can't resolve 'myservice.dev.svc.cluster.local' container \"init-mydb\" in pod \"myapp-pod\" is waiting to start: PodInitializing kubectl logs myapp-pod -c init-myservice # Inspect the first init container kubectl logs myapp-pod -c init-mydb # Inspect the second init container At this point, those init containers will be waiting to discover Services named mydb and myservice. Create the mydb and myservice services: kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: myservice spec: ports: - protocol: TCP port: 80 targetPort: 9376 --- apiVersion: v1 kind: Service metadata: name: mydb spec: ports: - protocol: TCP port: 80 targetPort: 9377 EOF Get current status of Services. kubectl get service Both of Services are up. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mydb ClusterIP 11.244.239.149 80/TCP 6s myservice ClusterIP 11.244.116.126 80/TCP 6s Get current Pod status. kubectl get pod myapp-pod -o wide The Pod is up. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-pod 0/1 Init:0/2 0 2m40s 10.244.112.2 cka002 We now see that those init containers complete, and that the myapp-pod Pod moves into the Running state. Clean up. kubectl delete service mydb myservice kubectl delete pod myapp-pod References: Pod basics Lifecycle & phases Kubernetes pod design pattern","title":"Pod"},{"location":"k8s/cka_en/foundamentals/pod/#work-on-pod","text":"","title":"Work on pod"},{"location":"k8s/cka_en/foundamentals/pod/#create-pod","text":"Create pod my-first-podl . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-first-pod spec: containers: - name: nginx image: nginx:mainline ports: - containerPort: 80 EOF Verify status of the pod just created. kubectl get pods -o wide","title":"Create pod"},{"location":"k8s/cka_en/foundamentals/pod/#track-pod","text":"Check logs of the pod just created. kubectl logs my-first-pod In case logs or describe or any other of the output generating commands don't help us to get to the root cause of an issue, we can use use kubectl exec -it -- bash command to look into it ourselves. kubectl exec -it my-first-pod -- bash root@my-first-pod:/# ls root@my-first-pod:/# cd bin root@my-first-pod:/bin# ls root@my-first-pod:/bin# exit Execute command kubectl explain pod.spec will get details of Spec segment of Pod kind in yaml file. We can check the official API reference of the pod resource for help or use kubectl explain pod to get a command-line based description of the resource. By appending . to the resource type, the explain command will provide more details on the specified field. kubectl explain pod.kind kubectl explain pod.spec kubectl explain pod.spec.containers kubectl explain pod.spec.containers.name","title":"Track pod"},{"location":"k8s/cka_en/foundamentals/pod/#label-pod","text":"Get pod's label with option --show-labels . kubectl get pods kubectl get pods --show-labels Add two labels to the pod pod my-first-pod . kubectl label pod my-first-pod nginx=mainline kubectl label pod my-first-pod env=demo kubectl get pods --show-labels Search pod by labels. kubectl get pod -l env=demo kubectl get pod -l env=demo,nginx=mainline kubectl get pod -l env=training Remove label kubectl label pods my-first-pod env- kubectl get pods --show-labels Describe pod. kubectl describe pod my-first-pod Delete pod. Run watch kubectl get pods to monitor the pod status. kubectl delete pod my-first-pod watch kubectl get pods","title":"Label pod"},{"location":"k8s/cka_en/foundamentals/pod/#static-pod","text":"Scenario *Create a static pod. * kubectl will automatically check yaml file in /etc/kubernetes/manifests/ and create the static pod once it's detected. Demo: Some system static Pods are already in place. ll /etc/kubernetes/manifests/ Result -rw------- 1 root root 2292 Jul 23 10:45 etcd.yaml -rw------- 1 root root 3889 Jul 23 10:45 kube-apiserver.yaml -rw------- 1 root root 3395 Jul 23 10:45 kube-controller-manager.yaml -rw------- 1 root root 1464 Jul 23 10:45 kube-scheduler.yaml Create yaml file my-nginx.yaml in directory /etc/kubernetes/manifests/ . Once the file is created, the static pod my-nginx is created automatically. kubectl run my-nginx --image=nginx:mainline --dry-run=client -n default -oyaml | sudo tee /etc/kubernetes/manifests/my-nginx.yaml Check status of the Pod my-nginx . The node name cka001 is part of the Pod name, which means the Pod is running on node cka001 . kubectl get pod -o wide Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cka001 1/1 Running 0 20s 10.244.228.196 cka001 Delete the yaml file /etc/kubernetes/manifests/my-nginx.yaml , the static pod will be deleted automatically. sudo rm /etc/kubernetes/manifests/my-nginx.yaml","title":"Static Pod"},{"location":"k8s/cka_en/foundamentals/pod/#multi-container-pod","text":"Scenario: Create Multi-Container Pod Describe the Pod Check the log of Pod Check the log of Containers Create a Pod multi-container-pod with multiple container container-1-nginx and container-2-alpine . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: multi-container-pod spec: containers: - name: container-1-nginx image: nginx ports: - containerPort: 80 - name: container-2-alpine image: alpine command: [\"watch\", \"wget\", \"-qO-\", \"localhost\"] EOF Get the status. kubectl get pod multi-container-pod Result NAME READY STATUS RESTARTS AGE multi-container-pod 2/2 Running 0 81s Get details of the pod. kubectl describe pod multi-container-pod Result ....... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 41s default-scheduler Successfully assigned dev/multi-container-pod to cka002 Normal Pulling 40s kubelet Pulling image \"nginx\" Normal Pulled 23s kubelet Successfully pulled image \"nginx\" in 16.767129903s Normal Created 22s kubelet Created container container-1-nginx Normal Started 22s kubelet Started container container-1-nginx Normal Pulling 22s kubelet Pulling image \"alpine\" Normal Pulled 14s kubelet Successfully pulled image \"alpine\" in 7.776104353s Normal Created 14s kubelet Created container container-2-alpine Normal Started 14s kubelet Started container container-2-alpine For multi-container pod, container name is needed if we want to get log of pod via command kubectl logs . Without the container name, we receive error. kubectl logs multi-container-pod Result error: a container name must be specified for pod multi-container-pod, choose one of: [container-1-nginx container-2-alpine] With specified container name, we get the log info. kubectl logs multi-container-pod container-1-nginx Result ...... ::1 - - [23/Jul/2022:04:06:37 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"Wget\" \"-\" Same if we need specify container name to login into the pod via command kubectl exec -it -c -- . kubectl exec -it multi-container-pod -c container-1-nginx -- /bin/bash root@multi-container-pod:/# ls Clean up kubectl delete pod multi-container-pod Quick reference of a simple yaml file to create Multiple Containers. kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-multi-pod spec: containers: - image: nginx name: nginx - image: memcached name: memcached - image: redis name: redis EOF Scenario: Create a Pod my-busybox with a container container-1-busybox . The container will write message to file /var/log/my-pod-busybox.log . Add another container container-2-busybox (Sidecar) to the Pod my-busybox . The sidecar container read message from file /var/log/my-pod-busybox.log . Tips: create a Volume to store the log file, which is shared with two containers. Demo: Create a Pod my-busybox with a container container-1-busybox . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-busybox spec: containers: - name: container-1-busybox image: busybox args: - /bin/sh - -c - > i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=$((i+1)); sleep 1; done EOF Search emptyDir in the Kubernetes documetation. Refer to below template for emptyDir via https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/ Add below new features into the Pod Volume: volume name: logfile type: emptyDir Update existing container: name: container-1-busybox volumeMounts name: logfile mounthPath: /var/log Add new container: name: container-2-busybox image: busybox args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log'] volumeMounts: name: logfile mountPath: /var/log kubectl get pod my-busybox -o yaml > my-busybox.yaml vi my-busybox.yaml kubectl delete pod my-busybox kubectl apply -f my-busybox.yaml kubectl logs my-busybox -c container-2-busybox The final file my-busybox.yaml looks like below. apiVersion: v1 kind: Pod metadata: annotations: cni.projectcalico.org/containerID: 89644b6b073cd152f94b4cae7bdea6bbc3292cf59afd4f28102bd74f0205c9e4 cni.projectcalico.org/podIP: 10.244.102.20/32 cni.projectcalico.org/podIPs: 10.244.102.20/32 kubectl.kubernetes.io/last-applied-configuration: | {\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"my-busybox\",\"namespace\":\"dev\"},\"spec\":{\"containers\":[{\"args\":[\"/bin/sh\",\"-c\",\"i=0; while true; do\\n echo \\\"Hello message from container-1: \\\" \\u003e\\u003e /var/log/my-pod-busybox.log;\\n i=1;\\n sleep 1;\\ndone\\n\"],\"image\":\"busybox\",\"name\":\"container-1-busybox\"}]}} creationTimestamp: \"2022-07-29T22:58:27Z\" name: my-busybox namespace: dev resourceVersion: \"1185720\" uid: c5e62a16-4459-4828-a441-7d1471b89a56 spec: containers: - name: container-2-busybox image: busybox args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log'] volumeMounts: - name: logfile mountPath: /var/log - args: - /bin/sh - -c - | i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=1; sleep 1; done image: busybox imagePullPolicy: Always name: container-1-busybox resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - name: logfile mountPath: /var/log - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: kube-api-access-mhxlf readOnly: true dnsPolicy: ClusterFirst enableServiceLinks: true nodeName: cka003 preemptionPolicy: PreemptLowerPriority priority: 0 restartPolicy: Always schedulerName: default-scheduler securityContext: {} serviceAccount: default serviceAccountName: default terminationGracePeriodSeconds: 30 tolerations: - effect: NoExecute key: node.kubernetes.io/not-ready operator: Exists tolerationSeconds: 300 - effect: NoExecute key: node.kubernetes.io/unreachable operator: Exists tolerationSeconds: 300 volumes: - name: logfile emptyDir: {} - name: kube-api-access-mhxlf projected: defaultMode: 420 sources: - serviceAccountToken: expirationSeconds: 3607 path: token - configMap: items: - key: ca.crt path: ca.crt name: kube-root-ca.crt - downwardAPI: items: - fieldRef: apiVersion: v1 fieldPath: metadata.namespace path: namespace status: conditions: - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:27Z\" status: \"True\" type: Initialized - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:30Z\" status: \"True\" type: Ready - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:30Z\" status: \"True\" type: ContainersReady - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:27Z\" status: \"True\" type: PodScheduled containerStatuses: - containerID: containerd://fd42d4ba4d94d8918d8846327b1db2328be13c5f93f381877ff0228ed7b5468d image: docker.io/library/busybox:latest imageID: docker.io/library/busybox@sha256:0e97a8ca6955f22dbc7db9e9dbe970971f423541e52c34b8cb96ccc88d6a3883 lastState: {} name: container-1-busybox ready: true restartCount: 0 started: true state: running: startedAt: \"2022-07-29T22:58:30Z\" hostIP: phase: Running podIP: 10.244.102.20 podIPs: - ip: 10.244.102.20 qosClass: BestEffort startTime: \"2022-07-29T22:58:27Z\" Clean up: kubectl delete pod my-busybox","title":"Multi-Container Pod"},{"location":"k8s/cka_en/foundamentals/pod/#initcontainer-pod","text":"Scenario: Create Pod myapp-pod that has two init containers. myapp-container init-mydb Create two Services. myservice mydb Conclusion: myapp-container waits for Service myservice up in order to resolve the name myservice.dev.svc.cluster.local init-mydb waits for Service mydb up in order to resolve the name mydb.dev.svc.cluster.local . Demo: Create Pod myapp-pod with below yaml file. Create yaml file myapp-pod.yaml and add below content. Note: Due to the command $(cat /var/..... will be treated as host variable, we can not use echo to generate the file. It's the variabel in container itself. vi myapp-pod.yaml Content apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp spec: containers: - name: myapp-container image: busybox:1.28 command: ['sh', '-c', 'echo The app is running! && sleep 3600'] initContainers: - name: init-myservice image: busybox:1.28 command: ['sh', '-c', \"until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done\"] - name: init-mydb image: busybox:1.28 command: ['sh', '-c', \"until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done\"] Apply the yaml file to create the Pod. kubectl apply -f myapp-pod.yaml Check Pod status. kubectl get pod myapp-pod Result NAME READY STATUS RESTARTS AGE myapp-pod 0/1 Init:0/2 0 12m Inspect Pods. Get two errors: nslookup: can't resolve 'myservice.dev.svc.cluster.local' container \"init-mydb\" in pod \"myapp-pod\" is waiting to start: PodInitializing kubectl logs myapp-pod -c init-myservice # Inspect the first init container kubectl logs myapp-pod -c init-mydb # Inspect the second init container At this point, those init containers will be waiting to discover Services named mydb and myservice. Create the mydb and myservice services: kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: myservice spec: ports: - protocol: TCP port: 80 targetPort: 9376 --- apiVersion: v1 kind: Service metadata: name: mydb spec: ports: - protocol: TCP port: 80 targetPort: 9377 EOF Get current status of Services. kubectl get service Both of Services are up. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mydb ClusterIP 11.244.239.149 80/TCP 6s myservice ClusterIP 11.244.116.126 80/TCP 6s Get current Pod status. kubectl get pod myapp-pod -o wide The Pod is up. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-pod 0/1 Init:0/2 0 2m40s 10.244.112.2 cka002 We now see that those init containers complete, and that the myapp-pod Pod moves into the Running state. Clean up. kubectl delete service mydb myservice kubectl delete pod myapp-pod References: Pod basics Lifecycle & phases Kubernetes pod design pattern","title":"initContainer Pod"},{"location":"k8s/cka_en/foundamentals/policy/","text":"Policy \u00b6 ResourceQuota \u00b6 Scenario: Create ResourceQuota object-quota-demo for namespace quota-object-example . Test ResourceQuota object-quota-demo for NodePort Test ResourceQuota object-quota-demo for PVC Create Namespace \u00b6 Ceate a Namespace kubectl create ns quota-object-example Create ResourceQuota for Namespace \u00b6 Create ResourceQuota object-quota-demo for namespace quota-object-example . Within the namespace, we can only create 1 PVC, 1 LoadBalancer Service, can not create NodePort Service. kubectl apply -f - <@ ) CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev Create CA Config File \u00b6 Get overview of directory /etc/kubernetes/pki . tree /etc/kubernetes/pki Result /etc/kubernetes/pki \u251c\u2500\u2500 apiserver.crt \u251c\u2500\u2500 apiserver-etcd-client.crt \u251c\u2500\u2500 apiserver-etcd-client.key \u251c\u2500\u2500 apiserver.key \u251c\u2500\u2500 apiserver-kubelet-client.crt \u251c\u2500\u2500 apiserver-kubelet-client.key \u251c\u2500\u2500 ca.crt \u251c\u2500\u2500 ca.key \u251c\u2500\u2500 etcd \u2502 \u251c\u2500\u2500 ca.crt \u2502 \u251c\u2500\u2500 ca.key \u2502 \u251c\u2500\u2500 healthcheck-client.crt \u2502 \u251c\u2500\u2500 healthcheck-client.key \u2502 \u251c\u2500\u2500 peer.crt \u2502 \u251c\u2500\u2500 peer.key \u2502 \u251c\u2500\u2500 server.crt \u2502 \u2514\u2500\u2500 server.key \u251c\u2500\u2500 front-proxy-ca.crt \u251c\u2500\u2500 front-proxy-ca.key \u251c\u2500\u2500 front-proxy-client.crt \u251c\u2500\u2500 front-proxy-client.key \u251c\u2500\u2500 sa.key \u2514\u2500\u2500 sa.pub Change to directory /etc/kubernetes/pki . cd /etc/kubernetes/pki Check if file ca-config.json is in place in current directory. ll ca-config.json If not, create it. We can add multiple profiles to specify different expiry date, scenario, parameters, etc.. Profile will be used to sign certificate. 87600 hours are about 10 years. Here we will create 1 additional profile dev . cat > ca-config.json < cka-dev-csr.json < here) to composite evn variable APISERVER ( https://: ). kubectl get node -owide NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready control-plane,master 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 Export env APISERVER . echo \"export APISERVER=\\\"https://:6443\\\"\" >> ~/.bashrc source ~/.bashrc Verify the setting. echo $APISERVER Output: https://:6443 1.Set up cluster Stay in the directory /etc/kubernetes/pki . Generate kubeconfig file. kubectl config set-cluster kubernetes \\ --certificate-authority=/etc/kubernetes/pki/ca.crt \\ --embed-certs=true \\ --server=${APISERVER} \\ --kubeconfig=cka-dev.kubeconfig Now we get the new config file cka-dev.kubeconfig ll -tr | grep cka-dev Output: -rw-r--r-- 1 root root 222 Jul 24 08:49 cka-dev-csr.json -rw-r--r-- 1 root root 1281 Jul 24 09:14 cka-dev.pem -rw------- 1 root root 1675 Jul 24 09:14 cka-dev-key.pem -rw-r--r-- 1 root root 1001 Jul 24 09:14 cka-dev.csr -rw------- 1 root root 1671 Jul 24 09:16 cka-dev.kubeconfig Get content of file cka-dev.kubeconfig . cat cka-dev.kubeconfig apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : null 2.Set up user In file cka-dev.kubeconfig , user info is null. Set up user cka-dev . kubectl config set-credentials cka-dev \\ --client-certificate=/etc/kubernetes/pki/cka-dev.pem \\ --client-key=/etc/kubernetes/pki/cka-dev-key.pem \\ --embed-certs=true \\ --kubeconfig=cka-dev.kubeconfig Now file cka-dev.kubeconfig was updated and user information was added. cat cka-dev.kubeconfig apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : - name : cka-dev user : client-certificate-data : client-key-data : Now we have a complete kubeconfig file cka-dev.kubeconfig . When we use it to get node information, receive error below because we did not set up current-context in kubeconfig file. kubectl --kubeconfig=cka-dev.kubeconfig get nodes The connection to the server localhost:8080 was refused - did you specify the right host or port? Current contents is empty. kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE 3.Set up Context Set up context. kubectl config set-context dev --cluster=kubernetes --user=cka-dev --kubeconfig=cka-dev.kubeconfig Now we have context now but the CURRENT flag is empty. kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts Output: CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev Set up default context. The context will link clusters and users for multiple clusters environment and we can switch to different cluster. kubectl --kubeconfig=cka-dev.kubeconfig config use-context dev 4.Verify Now CURRENT is marked with * , that is, current-context is set up. kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev Because user cka-dev does not have authorization in the cluster, we will receive forbidden error when we try to get information of Pods or Nodes. kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get pod kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get node Merge kubeconfig files \u00b6 Make a copy of your existing config cp ~/.kube/config ~/.kube/config.old Merge the two config files together into a new config file /tmp/config . KUBECONFIG=~/.kube/config:/etc/kubernetes/pki/cka-dev.kubeconfig kubectl config view --flatten > /tmp/config Replace the old config with the new merged config mv /tmp/config ~/.kube/config Now the new ~/.kube/config looks like below. apiVersion: v1 clusters: - cluster: certificate-authority-data: server: https://:6443 name: kubernetes contexts: - context: cluster: kubernetes user: cka-dev name: dev - context: cluster: kubernetes user: kubernetes-admin name: kubernetes-admin@kubernetes current-context: kubernetes-admin@kubernetes kind: Config preferences: {} users: - name: cka-dev user: client-certificate-data: client-key-data: - name: kubernetes-admin user: client-certificate-data: client-key-data: Verify contexts after kubeconfig merged. kubectl config get-contexts Current context is the system default kubernetes-admin@kubernetes . CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev Namespaces & Contexts \u00b6 Get list of Namespace with Label information. kubectl get ns --show-labels Create Namespace cka . kubectl create namespace cka Use below command to set a context with new update, e.g, update default namespace, etc.. kubectl config set-context --cluster= --namespace= --user= Let's set default namespace to each context. kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin kubectl config set-context dev --cluster=kubernetes --namespace=cka --user=cka-dev Let's check current context information. kubectl config get-contexts Output: CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev cka * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev To switch to a new context, use below command. kubectl config use-contexts For example. kubectl config use-context dev Verify if it's changed as expected. kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev cka kubernetes-admin@kubernetes kubernetes kubernetes-admin dev Be noted, four users beginning with cka-dev created don't have any authorizations, e.g., access namespaces, get pods, etc.. Referring RBAC to grant their authorizations. Role & RoleBinding \u00b6 Switch to context kubernetes-admin@kubernetes . kubectl config use-context kubernetes-admin@kubernetes Use kubectl create role command with option --dry-run=client and -o yaml to generate yaml template for customizing. kubectl create role admin-dev --resource=pods --verb=get --verb=list --verb=watch --dry-run=client -o yaml Create role admin-dev on namespace cka . kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: cka name: admin-dev rules: - apiGroups: - \"\" resources: - pods verbs: - get - watch - list EOF Use kubectl create rolebinding command with option --dry-run=client and -o yaml to generate yaml template for customizing. kubectl create rolebinding admin --role=admin-dev --user=cka-dev --dry-run=client -o yaml Create rolebinding admin on namespace cka . kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: admin namespace: cka roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: admin-dev subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: cka-dev EOF Verify authorzation of user cka-dev on Namespace cka . Switch to context dev . kubectl config use-context dev Get Pods status in Namespace cka . Success! kubectl get pod -n cka Get Pods status in Namespace kube-system . Failed, because the authorzation is only for Namespace cka . kubectl get pod -n kube-system Get Nodes status. Failed, because the role we defined is only for Pod resource. kubectl get node Create a Pod in Namespace dev . Failed because we only have get , watch , list for Pod, no create authorization. kubectl run nginx --image=nginx -n cka ClusterRole & ClusterRoleBinding \u00b6 Switch to context kubernetes-admin@kubernetes . kubectl config use-context kubernetes-admin@kubernetes Create a ClusterRole nodes-admin with authorization get , watch , list for nodes resource. kubectl apply -f - <@ ) CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev","title":"Current Context"},{"location":"k8s/cka_en/foundamentals/rbac/#create-ca-config-file","text":"Get overview of directory /etc/kubernetes/pki . tree /etc/kubernetes/pki Result /etc/kubernetes/pki \u251c\u2500\u2500 apiserver.crt \u251c\u2500\u2500 apiserver-etcd-client.crt \u251c\u2500\u2500 apiserver-etcd-client.key \u251c\u2500\u2500 apiserver.key \u251c\u2500\u2500 apiserver-kubelet-client.crt \u251c\u2500\u2500 apiserver-kubelet-client.key \u251c\u2500\u2500 ca.crt \u251c\u2500\u2500 ca.key \u251c\u2500\u2500 etcd \u2502 \u251c\u2500\u2500 ca.crt \u2502 \u251c\u2500\u2500 ca.key \u2502 \u251c\u2500\u2500 healthcheck-client.crt \u2502 \u251c\u2500\u2500 healthcheck-client.key \u2502 \u251c\u2500\u2500 peer.crt \u2502 \u251c\u2500\u2500 peer.key \u2502 \u251c\u2500\u2500 server.crt \u2502 \u2514\u2500\u2500 server.key \u251c\u2500\u2500 front-proxy-ca.crt \u251c\u2500\u2500 front-proxy-ca.key \u251c\u2500\u2500 front-proxy-client.crt \u251c\u2500\u2500 front-proxy-client.key \u251c\u2500\u2500 sa.key \u2514\u2500\u2500 sa.pub Change to directory /etc/kubernetes/pki . cd /etc/kubernetes/pki Check if file ca-config.json is in place in current directory. ll ca-config.json If not, create it. We can add multiple profiles to specify different expiry date, scenario, parameters, etc.. Profile will be used to sign certificate. 87600 hours are about 10 years. Here we will create 1 additional profile dev . cat > ca-config.json < cka-dev-csr.json < here) to composite evn variable APISERVER ( https://: ). kubectl get node -owide NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready control-plane,master 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 Export env APISERVER . echo \"export APISERVER=\\\"https://:6443\\\"\" >> ~/.bashrc source ~/.bashrc Verify the setting. echo $APISERVER Output: https://:6443 1.Set up cluster Stay in the directory /etc/kubernetes/pki . Generate kubeconfig file. kubectl config set-cluster kubernetes \\ --certificate-authority=/etc/kubernetes/pki/ca.crt \\ --embed-certs=true \\ --server=${APISERVER} \\ --kubeconfig=cka-dev.kubeconfig Now we get the new config file cka-dev.kubeconfig ll -tr | grep cka-dev Output: -rw-r--r-- 1 root root 222 Jul 24 08:49 cka-dev-csr.json -rw-r--r-- 1 root root 1281 Jul 24 09:14 cka-dev.pem -rw------- 1 root root 1675 Jul 24 09:14 cka-dev-key.pem -rw-r--r-- 1 root root 1001 Jul 24 09:14 cka-dev.csr -rw------- 1 root root 1671 Jul 24 09:16 cka-dev.kubeconfig Get content of file cka-dev.kubeconfig . cat cka-dev.kubeconfig apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : null 2.Set up user In file cka-dev.kubeconfig , user info is null. Set up user cka-dev . kubectl config set-credentials cka-dev \\ --client-certificate=/etc/kubernetes/pki/cka-dev.pem \\ --client-key=/etc/kubernetes/pki/cka-dev-key.pem \\ --embed-certs=true \\ --kubeconfig=cka-dev.kubeconfig Now file cka-dev.kubeconfig was updated and user information was added. cat cka-dev.kubeconfig apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : - name : cka-dev user : client-certificate-data : client-key-data : Now we have a complete kubeconfig file cka-dev.kubeconfig . When we use it to get node information, receive error below because we did not set up current-context in kubeconfig file. kubectl --kubeconfig=cka-dev.kubeconfig get nodes The connection to the server localhost:8080 was refused - did you specify the right host or port? Current contents is empty. kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE 3.Set up Context Set up context. kubectl config set-context dev --cluster=kubernetes --user=cka-dev --kubeconfig=cka-dev.kubeconfig Now we have context now but the CURRENT flag is empty. kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts Output: CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev Set up default context. The context will link clusters and users for multiple clusters environment and we can switch to different cluster. kubectl --kubeconfig=cka-dev.kubeconfig config use-context dev 4.Verify Now CURRENT is marked with * , that is, current-context is set up. kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev Because user cka-dev does not have authorization in the cluster, we will receive forbidden error when we try to get information of Pods or Nodes. kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get pod kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get node","title":"Create file kubeconfig"},{"location":"k8s/cka_en/foundamentals/rbac/#merge-kubeconfig-files","text":"Make a copy of your existing config cp ~/.kube/config ~/.kube/config.old Merge the two config files together into a new config file /tmp/config . KUBECONFIG=~/.kube/config:/etc/kubernetes/pki/cka-dev.kubeconfig kubectl config view --flatten > /tmp/config Replace the old config with the new merged config mv /tmp/config ~/.kube/config Now the new ~/.kube/config looks like below. apiVersion: v1 clusters: - cluster: certificate-authority-data: server: https://:6443 name: kubernetes contexts: - context: cluster: kubernetes user: cka-dev name: dev - context: cluster: kubernetes user: kubernetes-admin name: kubernetes-admin@kubernetes current-context: kubernetes-admin@kubernetes kind: Config preferences: {} users: - name: cka-dev user: client-certificate-data: client-key-data: - name: kubernetes-admin user: client-certificate-data: client-key-data: Verify contexts after kubeconfig merged. kubectl config get-contexts Current context is the system default kubernetes-admin@kubernetes . CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev","title":"Merge kubeconfig files"},{"location":"k8s/cka_en/foundamentals/rbac/#namespaces-contexts","text":"Get list of Namespace with Label information. kubectl get ns --show-labels Create Namespace cka . kubectl create namespace cka Use below command to set a context with new update, e.g, update default namespace, etc.. kubectl config set-context --cluster= --namespace= --user= Let's set default namespace to each context. kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin kubectl config set-context dev --cluster=kubernetes --namespace=cka --user=cka-dev Let's check current context information. kubectl config get-contexts Output: CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev cka * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev To switch to a new context, use below command. kubectl config use-contexts For example. kubectl config use-context dev Verify if it's changed as expected. kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev cka kubernetes-admin@kubernetes kubernetes kubernetes-admin dev Be noted, four users beginning with cka-dev created don't have any authorizations, e.g., access namespaces, get pods, etc.. Referring RBAC to grant their authorizations.","title":"Namespaces & Contexts"},{"location":"k8s/cka_en/foundamentals/rbac/#role-rolebinding","text":"Switch to context kubernetes-admin@kubernetes . kubectl config use-context kubernetes-admin@kubernetes Use kubectl create role command with option --dry-run=client and -o yaml to generate yaml template for customizing. kubectl create role admin-dev --resource=pods --verb=get --verb=list --verb=watch --dry-run=client -o yaml Create role admin-dev on namespace cka . kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: cka name: admin-dev rules: - apiGroups: - \"\" resources: - pods verbs: - get - watch - list EOF Use kubectl create rolebinding command with option --dry-run=client and -o yaml to generate yaml template for customizing. kubectl create rolebinding admin --role=admin-dev --user=cka-dev --dry-run=client -o yaml Create rolebinding admin on namespace cka . kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: admin namespace: cka roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: admin-dev subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: cka-dev EOF Verify authorzation of user cka-dev on Namespace cka . Switch to context dev . kubectl config use-context dev Get Pods status in Namespace cka . Success! kubectl get pod -n cka Get Pods status in Namespace kube-system . Failed, because the authorzation is only for Namespace cka . kubectl get pod -n kube-system Get Nodes status. Failed, because the role we defined is only for Pod resource. kubectl get node Create a Pod in Namespace dev . Failed because we only have get , watch , list for Pod, no create authorization. kubectl run nginx --image=nginx -n cka","title":"Role & RoleBinding"},{"location":"k8s/cka_en/foundamentals/rbac/#clusterrole-clusterrolebinding","text":"Switch to context kubernetes-admin@kubernetes . kubectl config use-context kubernetes-admin@kubernetes Create a ClusterRole nodes-admin with authorization get , watch , list for nodes resource. kubectl apply -f - < nodeName \u00b6 Be noted, nodeName has hightest priority as it's not scheduled by Scheduler . Create a Pod nginx-nodename with nodeName=cka003 . kubectl apply -f - < Affinity \u00b6 In Kubernetes cluster, some Pods have frequent interaction with other Pods. With that situation, it's suggested to schedule these Pods running on same node. For example, Two Pods Nginx and Mysql, we need deploy them on one node if they frequently communicate. We can use podAffinity to select Pods based on their relationship. There are two scheduling type of podAffinity . requiredDuringSchedulingIgnoredDuringExecution (\u786c\u4eb2\u548c) preferredDuringSchedulingIgnoredDuringExecution (\u8f6f\u4eb2\u548c) topologyKey could be set by below types: kubernetes.io/hostname \uff03NodeName failure-domain.beta.kubernetes.io/zone \uff03Zone failure-domain.beta.kubernetes.io/region # Region We can set node Label to classify Name/Zone/Region of node, which can be used by podAffinity . Create a Pod Nginx. kubectl apply -f - < ","title":"nodeSelector"},{"location":"k8s/cka_en/foundamentals/scheduling/#nodename","text":"Be noted, nodeName has hightest priority as it's not scheduled by Scheduler . Create a Pod nginx-nodename with nodeName=cka003 . kubectl apply -f - < ","title":"nodeName"},{"location":"k8s/cka_en/foundamentals/scheduling/#affinity","text":"In Kubernetes cluster, some Pods have frequent interaction with other Pods. With that situation, it's suggested to schedule these Pods running on same node. For example, Two Pods Nginx and Mysql, we need deploy them on one node if they frequently communicate. We can use podAffinity to select Pods based on their relationship. There are two scheduling type of podAffinity . requiredDuringSchedulingIgnoredDuringExecution (\u786c\u4eb2\u548c) preferredDuringSchedulingIgnoredDuringExecution (\u8f6f\u4eb2\u548c) topologyKey could be set by below types: kubernetes.io/hostname \uff03NodeName failure-domain.beta.kubernetes.io/zone \uff03Zone failure-domain.beta.kubernetes.io/region # Region We can set node Label to classify Name/Zone/Region of node, which can be used by podAffinity . Create a Pod Nginx. kubectl apply -f - < 80/TCP 14s app=httpd NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/httpd-app-6496d888c9-4nb6z 1/1 Running 0 77s 10.244.102.21 cka003 pod/httpd-app-6496d888c9-b7xht 1/1 Running 0 77s 10.244.112.19 cka002 Verify the access to Pod IPs. curl 10.244.102.21 curl 10.244.112.19 And receive below successful information.

    It works!

    Verify the access via ClusterIP with Port. curl 11.244.247.7:80 And receive below successful information.

    It works!

    Expose Service \u00b6 Create and attach to a temporary Pod nslookup and to verify DNS resolution. The option --rm means delete the Pod after exit. kubectl run -it nslookup --rm --image=busybox:1.28 After attach to the Pod, run command nslookup httpd-app . We receive the ClusterIP of Service httpd-app and full domain name. / # nslookup httpd-app Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: httpd-app Address 1: 11.244.247.7 httpd-app.dev.svc.cluster.local We can check the IP of temporary Pod nslookup in a new terminal by executing command kubectl get pod -o wide . The Pod nslookup has Pod IP 10.244.112.20 . kubectl get pod nslookup Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nslookup 1/1 Running 0 2m44s 10.244.112.20 cka002 NodePort \u00b6 Create and apply yaml file svc-nodeport.yaml to create a Service httpd-app . kubectl apply -f - < will update configuration to existing resources. Here the Service httpd-app is changed from ClusterIP to NodePort type. No change to the Deployment httpd-app . service/httpd-app configured deployment.apps/httpd-app unchanged Check the Service httpd-app via kubectl get svc . IP is the same. Type is changed to NodePort. Port numbers is changed from 80/TCP to 80:30080/TCP . NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpd-app NodePort 11.244.247.7 80:30080/TCP 18m Test the connection to the Service httpd-app via command curl :30080 to each node. curl :30080 curl :30080 curl :30080 We will receive below successful information.

    It works!

    Headless Service \u00b6 Create Headless Service web and StatefulSet web . kubectl apply -f - < web-1 1/1 Running 0 6s 10.244.112.21 cka002 Get details of the Service by command kubectl describe svc -l app=web . Name: web Namespace: dev Labels: app=web Annotations: Selector: app=web Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: None IPs: None Port: web 80/TCP TargetPort: 80/TCP Endpoints: 10.244.102.22:80,10.244.112.21:80 Session Affinity: None Events: Attach to the temporary Pod nslookup and use nslookup to verify DNS resolution. kubectl run -it nslookup --rm --image=busybox:1.28 With nslookup command for Headless Service web , we received two Pod IPs, not ClusterIP due to Headless Service. / # nslookup web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local Address 2: 10.244.102.22 web-0.web.dev.svc.cluster.local We can also use nslookup for web-0.web and web-1.web . Every Pod of Headless Service has own Service Name for DNS lookup. / # nslookup web-0.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.web Address 1: 10.244.102.22 web-0.web.dev.svc.cluster.local / # nslookup web-1.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local Clean up. kubectl delete sts web kubectl delete service httpd-app web kubectl delete deployment httpd-app Service Internal Traffic Policy \u00b6 Scenario Simulate how Service Internal Traffic Policy works. Expected result: With setting Service internalTrafficPolicy: Local , the Service only route internal traffic within the nodes that Pods are running. Backgroud: Service Internal Traffic Policy enables internal traffic restrictions to only route internal traffic to endpoints within the node the traffic originated from. The \"internal\" traffic here refers to traffic originated from Pods in the current cluster. By setting its .spec.internalTrafficPolicy to Local. This tells kube-proxy to only use node local endpoints for cluster internal traffic. For pods on nodes with no endpoints for a given Service, the Service behaves as if it has zero endpoints (for Pods on this node) even if the service does have endpoints on other nodes. Demo: Create Deployment my-nginx and Service my-nginx . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx EOF With command kubectl get pod -o wide , we know the Pod of Deployment my-nginx is running on node cka003 . NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cf54cdbf7-bscf8 1/1 Running 0 9h 10.244.112.63 cka002 Let's send http request from cka001 to the Pod on cka002 . We will receive Welcome to nginx! information, which means the Pod is accessable from other nodes. curl 11.244.163.60 Let's modify the Serivce my-nginx and specify internalTrafficPolicy: Local . kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx internalTrafficPolicy: Local EOF Let's send http request from cka001 to the http request to the Pod again. We will receive curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused error information. curl 11.244.163.60 Let's log onto cka002 and the http request to the Pod again. We will receive Welcome to nginx! information, curl 11.244.163.60 Conclution With setting Service internalTrafficPolicy: Local , the Service only route internal traffic within the nodes that Pods are running. Scenario *Create a nginx deployment * Add port number and alias name of the nginx Pod. * Expose the deployment with internal traffic to local only. Demo: Create deployment my-nginx with port number 80 . kubectl create deployment my-nginx --image=nginx --port=80 Edit deployment. kubectl edit deployment my-nginx Add port alias name http . Refer to the link for deployment yaml template https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ spec : containers : - image : nginx imagePullPolicy : Always name : nginx ports : - containerPort : 80 protocol : TCP name : http Expose the deployment with NodePort type. kubectl expose deployment my-nginx --port=80 --target-port=http --name=my-nginx-svc --type=NodePort Edit the service. Change internalTrafficPolicy from Cluster to Local . kubectl edit svc my-nginx-svc Verify the access. Note, the pod is running on node cka003 . We will see below expected results. curl :80 # succeed on node cka003. internalTrafficPolicy is effective. curl :80 # succeed on all nodes. curl : # succeed on all nodes.","title":"Service"},{"location":"k8s/cka_en/foundamentals/service/#service","text":"Scenario: Create Deployment httpd-app . Create Service httpd-app with type ClusterIP , which is default type and accessable internally. Verify the access to Pod IP and Service ClusterIP. Update Service httpd-app with type NodePort . No change to the Deployment httpd-app . Verify the access to Node. The access will route to Pod. The service is now accesable from outside. Create Headless Service web and StatefulSet web . Service Internal Traffic Policy","title":"Service"},{"location":"k8s/cka_en/foundamentals/service/#clusterip","text":"","title":"ClusterIP"},{"location":"k8s/cka_en/foundamentals/service/#create-service","text":"Create a Deployment http-app . Create a Service httpd-app link to Development http-app by Label Selector. Service type is ClusterIP , which is default type and accessable internally. kubectl apply -f - < 80/TCP 14s app=httpd NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/httpd-app-6496d888c9-4nb6z 1/1 Running 0 77s 10.244.102.21 cka003 pod/httpd-app-6496d888c9-b7xht 1/1 Running 0 77s 10.244.112.19 cka002 Verify the access to Pod IPs. curl 10.244.102.21 curl 10.244.112.19 And receive below successful information.

    It works!

    Verify the access via ClusterIP with Port. curl 11.244.247.7:80 And receive below successful information.

    It works!

    ","title":"Create Service"},{"location":"k8s/cka_en/foundamentals/service/#expose-service","text":"Create and attach to a temporary Pod nslookup and to verify DNS resolution. The option --rm means delete the Pod after exit. kubectl run -it nslookup --rm --image=busybox:1.28 After attach to the Pod, run command nslookup httpd-app . We receive the ClusterIP of Service httpd-app and full domain name. / # nslookup httpd-app Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: httpd-app Address 1: 11.244.247.7 httpd-app.dev.svc.cluster.local We can check the IP of temporary Pod nslookup in a new terminal by executing command kubectl get pod -o wide . The Pod nslookup has Pod IP 10.244.112.20 . kubectl get pod nslookup Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nslookup 1/1 Running 0 2m44s 10.244.112.20 cka002 ","title":"Expose Service"},{"location":"k8s/cka_en/foundamentals/service/#nodeport","text":"Create and apply yaml file svc-nodeport.yaml to create a Service httpd-app . kubectl apply -f - < will update configuration to existing resources. Here the Service httpd-app is changed from ClusterIP to NodePort type. No change to the Deployment httpd-app . service/httpd-app configured deployment.apps/httpd-app unchanged Check the Service httpd-app via kubectl get svc . IP is the same. Type is changed to NodePort. Port numbers is changed from 80/TCP to 80:30080/TCP . NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpd-app NodePort 11.244.247.7 80:30080/TCP 18m Test the connection to the Service httpd-app via command curl :30080 to each node. curl :30080 curl :30080 curl :30080 We will receive below successful information.

    It works!

    ","title":"NodePort"},{"location":"k8s/cka_en/foundamentals/service/#headless-service","text":"Create Headless Service web and StatefulSet web . kubectl apply -f - < web-1 1/1 Running 0 6s 10.244.112.21 cka002 Get details of the Service by command kubectl describe svc -l app=web . Name: web Namespace: dev Labels: app=web Annotations: Selector: app=web Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: None IPs: None Port: web 80/TCP TargetPort: 80/TCP Endpoints: 10.244.102.22:80,10.244.112.21:80 Session Affinity: None Events: Attach to the temporary Pod nslookup and use nslookup to verify DNS resolution. kubectl run -it nslookup --rm --image=busybox:1.28 With nslookup command for Headless Service web , we received two Pod IPs, not ClusterIP due to Headless Service. / # nslookup web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local Address 2: 10.244.102.22 web-0.web.dev.svc.cluster.local We can also use nslookup for web-0.web and web-1.web . Every Pod of Headless Service has own Service Name for DNS lookup. / # nslookup web-0.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.web Address 1: 10.244.102.22 web-0.web.dev.svc.cluster.local / # nslookup web-1.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local Clean up. kubectl delete sts web kubectl delete service httpd-app web kubectl delete deployment httpd-app","title":"Headless Service"},{"location":"k8s/cka_en/foundamentals/service/#service-internal-traffic-policy","text":"Scenario Simulate how Service Internal Traffic Policy works. Expected result: With setting Service internalTrafficPolicy: Local , the Service only route internal traffic within the nodes that Pods are running. Backgroud: Service Internal Traffic Policy enables internal traffic restrictions to only route internal traffic to endpoints within the node the traffic originated from. The \"internal\" traffic here refers to traffic originated from Pods in the current cluster. By setting its .spec.internalTrafficPolicy to Local. This tells kube-proxy to only use node local endpoints for cluster internal traffic. For pods on nodes with no endpoints for a given Service, the Service behaves as if it has zero endpoints (for Pods on this node) even if the service does have endpoints on other nodes. Demo: Create Deployment my-nginx and Service my-nginx . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx EOF With command kubectl get pod -o wide , we know the Pod of Deployment my-nginx is running on node cka003 . NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cf54cdbf7-bscf8 1/1 Running 0 9h 10.244.112.63 cka002 Let's send http request from cka001 to the Pod on cka002 . We will receive Welcome to nginx! information, which means the Pod is accessable from other nodes. curl 11.244.163.60 Let's modify the Serivce my-nginx and specify internalTrafficPolicy: Local . kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx internalTrafficPolicy: Local EOF Let's send http request from cka001 to the http request to the Pod again. We will receive curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused error information. curl 11.244.163.60 Let's log onto cka002 and the http request to the Pod again. We will receive Welcome to nginx! information, curl 11.244.163.60 Conclution With setting Service internalTrafficPolicy: Local , the Service only route internal traffic within the nodes that Pods are running. Scenario *Create a nginx deployment * Add port number and alias name of the nginx Pod. * Expose the deployment with internal traffic to local only. Demo: Create deployment my-nginx with port number 80 . kubectl create deployment my-nginx --image=nginx --port=80 Edit deployment. kubectl edit deployment my-nginx Add port alias name http . Refer to the link for deployment yaml template https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ spec : containers : - image : nginx imagePullPolicy : Always name : nginx ports : - containerPort : 80 protocol : TCP name : http Expose the deployment with NodePort type. kubectl expose deployment my-nginx --port=80 --target-port=http --name=my-nginx-svc --type=NodePort Edit the service. Change internalTrafficPolicy from Cluster to Local . kubectl edit svc my-nginx-svc Verify the access. Note, the pod is running on node cka003 . We will see below expected results. curl :80 # succeed on node cka003. internalTrafficPolicy is effective. curl :80 # succeed on all nodes. curl : # succeed on all nodes.","title":"Service Internal Traffic Policy"},{"location":"k8s/cka_en/foundamentals/statefulset/","text":"StatefulSet \u00b6 Scenario: Create Headless Service nginx and StatefulSet web Scale out StatefulSet web Demo: Create Headless Service nginx and StatefulSet web . kubectl apply -f - << EOF --- apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: \"nginx\" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web EOF Get details of StatefulSet Pod created just now. kubectl get pod | grep web Result NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 27s web-1 1/1 Running 0 10s Use command kubectl edit sts web to update an existing StatefulSet. ONLY these fields can be updated: replicas \u3001 image \u3001 rolling updates \u3001 labels \u3001 resource request/limit and annotations . Note: When StatefulSet Pod is dead in current node, no copies will be created in other node automatically. Scale out StatefulSet. Scale StatefulSet web to 5 Replicas. kubectl scale sts web --replicas=5 Info Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0. Command: kubectl explain statefulsets.spec.updateStrategy.rollingUpdate.partition Clean up. kubectl delete sts web kubectl delete service nginx","title":"StatefulSet"},{"location":"k8s/cka_en/foundamentals/statefulset/#statefulset","text":"Scenario: Create Headless Service nginx and StatefulSet web Scale out StatefulSet web Demo: Create Headless Service nginx and StatefulSet web . kubectl apply -f - << EOF --- apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: \"nginx\" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web EOF Get details of StatefulSet Pod created just now. kubectl get pod | grep web Result NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 27s web-1 1/1 Running 0 10s Use command kubectl edit sts web to update an existing StatefulSet. ONLY these fields can be updated: replicas \u3001 image \u3001 rolling updates \u3001 labels \u3001 resource request/limit and annotations . Note: When StatefulSet Pod is dead in current node, no copies will be created in other node automatically. Scale out StatefulSet. Scale StatefulSet web to 5 Replicas. kubectl scale sts web --replicas=5 Info Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0. Command: kubectl explain statefulsets.spec.updateStrategy.rollingUpdate.partition Clean up. kubectl delete sts web kubectl delete service nginx","title":"StatefulSet"},{"location":"k8s/cka_en/foundamentals/troubleshooting/","text":"Troubleshooting \u00b6 Event \u00b6 Scenario Describe pod to get event information. Demo: Usage: kubectl describe --namespace= Get event information of a Pod Create a Tomcat Pod. kubectl run tomcat --image=tomcat Check event of above deplyment. kubectl describe pod/tomcat Get below event information. Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 55s default-scheduler Successfully assigned dev/tomcat to cka002 Normal Pulling 54s kubelet Pulling image \"tomcat\" Normal Pulled 21s kubelet Successfully pulled image \"tomcat\" in 33.134162692s Normal Created 19s kubelet Created container tomcat Normal Started 19s kubelet Started container tomcat Get event information for a Namespace. kubectl get events -n Get current default namespace event information. LAST SEEN TYPE REASON OBJECT MESSAGE 70s Warning FailedGetScale horizontalpodautoscaler/nginx deployments/scale.apps \"podinfo\" not found 2m16s Normal Scheduled pod/tomcat Successfully assigned dev/tomcat to cka002 2m15s Normal Pulling pod/tomcat Pulling image \"tomcat\" 102s Normal Pulled pod/tomcat Successfully pulled image \"tomcat\" in 33.134162692s 100s Normal Created pod/tomcat Created container tomcat 100s Normal Started pod/tomcat Started container tomcat Get event information for all Namespace. kubectl get events -A Logs \u00b6 Scenario Get log of pod Usage: kubectl logs -n Options: --tail : display only the most recent lines of output -f : streaming the output Get the most recent 100 lines of output. kubectl logs -f tomcat --tail 100 If it's multipPod, use -c to specify Container. kubectl logs -f tomcat --tail 100 -c tomcat Node Availability \u00b6 Check Available Node \u00b6 Scenario Check node availibility. Demo: Option 1: kubectl describe node | grep -i taint Manual check the result, here it's 2 nodes are available Taints: node-role.kubernetes.io/control-plane:NoSchedule Taints: Taints: Option 2: kubectl describe node | grep -i taint |grep -vc NoSchedule We will get same result 2 . Here -v means exclude, -c count numbers. Node NotReady \u00b6 Scenario: When we stop kubelet service on worker node cka002 , What's the status of each node? What's containers changed via command nerdctl ? What's pods status via command kubectl get pod -owide -A ? Demo: Execute command systemctl stop kubelet.service on cka002 . Execute command kubectl get node on either cka001 or cka003 , the status of cka002 is NotReady . Execute command nerdctl -n k8s.io container ls on cka002 and we can observe all containers are still up and running, including the pod my-first-pod . Execute command systemctl start kubelet.service on cka002 . Conclusion: The node status is changed to NotReady from Ready . For those DaemonSet pods, like calico \u3001 kube-proxy , are exclusively running on each node. They won't be terminated after kubelet is down. The status of pod my-first-pod keeps showing Terminating on each node because status can not be synced to other nodes via apiserver from cka002 because kubelet is down. The status of pod is marked by controller and recycled by kubelet . When we start kubelet service on cka003 , the pod my-first-pod will be termiated completely on cka002 . In addition, let's create a deployment with 3 replicas. Two are running on cka003 and one is running on cka002 . root@cka001:~# kubectl get pod -o wide -w NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-9d745469b-2xdk4 1/1 Running 0 2m8s 10.244.2.3 cka003 nginx-deployment-9d745469b-4gvmr 1/1 Running 0 2m8s 10.244.2.4 cka003 nginx-deployment-9d745469b-5j927 1/1 Running 0 2m8s 10.244.1.3 cka002 After we stop kubelet service on cka003 , the two running on cka003 are terminated and another two are created and running on cka002 automatically. Monitoring Indicators \u00b6 Scenario: Get monitoring indicators of pod Demo: Get node monitoring information kubectl top node Output: NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 147m 7% 1940Mi 50% cka002 62m 3% 2151Mi 56% cka003 63m 3% 1825Mi 47% Get Pod monitoring information kubectl top pod Output: root@cka001:~# kubectl top pod NAME CPU(cores) MEMORY(bytes) busybox-with-secret 0m 0Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi tomcat 1m 58Mi Sort output by CPU or Memory using option --sort-by , the field can be either 'cpu' or 'memory'. kubectl top pod --sort-by=cpu kubectl top pod --sort-by=memory Output: NAME CPU(cores) MEMORY(bytes) nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi tomcat 1m 58Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi busybox-with-secret 0m 0Mi Node Eviction \u00b6 Cordon/Uncordon \u00b6 Scenario Scheduling for a node Demo: Disable scheduling for a Node. kubectl cordon Example: kubectl cordon cka003 Node status: NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready,SchedulingDisabled 18d v1.24.0 Enable scheduling for a Node. kubectl uncordon Example: kubectl uncordon cka003 Node status: NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready 18d v1.24.0 Drain Node \u00b6 Scenario Drain the node cka003 Demo: Get list of Pods running. kubectl get pod -o wide We know that a Pod is running on cka003 . NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-xk8nw 1/1 Running 0 22h 10.244.102.3 cka003 Evict node cka003 . kubectl drain cka003 --ignore-daemonsets --delete-emptydir-data --force Output looks like below. node/cka003 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-tr22l, kube-system/kube-proxy-g76kg evicting pod dev/nfs-client-provisioner-86d7fb78b6-xk8nw evicting pod cka/cka-demo-64f88f7f46-dkxmk pod/nfs-client-provisioner-86d7fb78b6-xk8nw evicted pod/cka-demo-64f88f7f46-dkxmk evicted node/cka003 drained Check pod status again. kubectl get pod -o wide The pod is running on cka002 now. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-k8xnl 1/1 Running 0 2m20s 10.244.112.4 cka002 Note cordon is included in drain , no need additional step to cordon node before drain node.","title":"Troubleshooting"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#troubleshooting","text":"","title":"Troubleshooting"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#event","text":"Scenario Describe pod to get event information. Demo: Usage: kubectl describe --namespace= Get event information of a Pod Create a Tomcat Pod. kubectl run tomcat --image=tomcat Check event of above deplyment. kubectl describe pod/tomcat Get below event information. Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 55s default-scheduler Successfully assigned dev/tomcat to cka002 Normal Pulling 54s kubelet Pulling image \"tomcat\" Normal Pulled 21s kubelet Successfully pulled image \"tomcat\" in 33.134162692s Normal Created 19s kubelet Created container tomcat Normal Started 19s kubelet Started container tomcat Get event information for a Namespace. kubectl get events -n Get current default namespace event information. LAST SEEN TYPE REASON OBJECT MESSAGE 70s Warning FailedGetScale horizontalpodautoscaler/nginx deployments/scale.apps \"podinfo\" not found 2m16s Normal Scheduled pod/tomcat Successfully assigned dev/tomcat to cka002 2m15s Normal Pulling pod/tomcat Pulling image \"tomcat\" 102s Normal Pulled pod/tomcat Successfully pulled image \"tomcat\" in 33.134162692s 100s Normal Created pod/tomcat Created container tomcat 100s Normal Started pod/tomcat Started container tomcat Get event information for all Namespace. kubectl get events -A","title":"Event"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#logs","text":"Scenario Get log of pod Usage: kubectl logs -n Options: --tail : display only the most recent lines of output -f : streaming the output Get the most recent 100 lines of output. kubectl logs -f tomcat --tail 100 If it's multipPod, use -c to specify Container. kubectl logs -f tomcat --tail 100 -c tomcat","title":"Logs"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#node-availability","text":"","title":"Node Availability"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#check-available-node","text":"Scenario Check node availibility. Demo: Option 1: kubectl describe node | grep -i taint Manual check the result, here it's 2 nodes are available Taints: node-role.kubernetes.io/control-plane:NoSchedule Taints: Taints: Option 2: kubectl describe node | grep -i taint |grep -vc NoSchedule We will get same result 2 . Here -v means exclude, -c count numbers.","title":"Check Available Node"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#node-notready","text":"Scenario: When we stop kubelet service on worker node cka002 , What's the status of each node? What's containers changed via command nerdctl ? What's pods status via command kubectl get pod -owide -A ? Demo: Execute command systemctl stop kubelet.service on cka002 . Execute command kubectl get node on either cka001 or cka003 , the status of cka002 is NotReady . Execute command nerdctl -n k8s.io container ls on cka002 and we can observe all containers are still up and running, including the pod my-first-pod . Execute command systemctl start kubelet.service on cka002 . Conclusion: The node status is changed to NotReady from Ready . For those DaemonSet pods, like calico \u3001 kube-proxy , are exclusively running on each node. They won't be terminated after kubelet is down. The status of pod my-first-pod keeps showing Terminating on each node because status can not be synced to other nodes via apiserver from cka002 because kubelet is down. The status of pod is marked by controller and recycled by kubelet . When we start kubelet service on cka003 , the pod my-first-pod will be termiated completely on cka002 . In addition, let's create a deployment with 3 replicas. Two are running on cka003 and one is running on cka002 . root@cka001:~# kubectl get pod -o wide -w NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-9d745469b-2xdk4 1/1 Running 0 2m8s 10.244.2.3 cka003 nginx-deployment-9d745469b-4gvmr 1/1 Running 0 2m8s 10.244.2.4 cka003 nginx-deployment-9d745469b-5j927 1/1 Running 0 2m8s 10.244.1.3 cka002 After we stop kubelet service on cka003 , the two running on cka003 are terminated and another two are created and running on cka002 automatically.","title":"Node NotReady"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#monitoring-indicators","text":"Scenario: Get monitoring indicators of pod Demo: Get node monitoring information kubectl top node Output: NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 147m 7% 1940Mi 50% cka002 62m 3% 2151Mi 56% cka003 63m 3% 1825Mi 47% Get Pod monitoring information kubectl top pod Output: root@cka001:~# kubectl top pod NAME CPU(cores) MEMORY(bytes) busybox-with-secret 0m 0Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi tomcat 1m 58Mi Sort output by CPU or Memory using option --sort-by , the field can be either 'cpu' or 'memory'. kubectl top pod --sort-by=cpu kubectl top pod --sort-by=memory Output: NAME CPU(cores) MEMORY(bytes) nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi tomcat 1m 58Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi busybox-with-secret 0m 0Mi","title":"Monitoring Indicators"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#node-eviction","text":"","title":"Node Eviction"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#cordonuncordon","text":"Scenario Scheduling for a node Demo: Disable scheduling for a Node. kubectl cordon Example: kubectl cordon cka003 Node status: NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready,SchedulingDisabled 18d v1.24.0 Enable scheduling for a Node. kubectl uncordon Example: kubectl uncordon cka003 Node status: NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready 18d v1.24.0","title":"Cordon/Uncordon"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#drain-node","text":"Scenario Drain the node cka003 Demo: Get list of Pods running. kubectl get pod -o wide We know that a Pod is running on cka003 . NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-xk8nw 1/1 Running 0 22h 10.244.102.3 cka003 Evict node cka003 . kubectl drain cka003 --ignore-daemonsets --delete-emptydir-data --force Output looks like below. node/cka003 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-tr22l, kube-system/kube-proxy-g76kg evicting pod dev/nfs-client-provisioner-86d7fb78b6-xk8nw evicting pod cka/cka-demo-64f88f7f46-dkxmk pod/nfs-client-provisioner-86d7fb78b6-xk8nw evicted pod/cka-demo-64f88f7f46-dkxmk evicted node/cka003 drained Check pod status again. kubectl get pod -o wide The pod is running on cka002 now. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-k8xnl 1/1 Running 0 2m20s 10.244.112.4 cka002 Note cordon is included in drain , no need additional step to cordon node before drain node.","title":"Drain Node"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/","text":"Installation on Aliyun Ubuntu \u00b6 Preparation \u00b6 Register Aliyun account via Alibaba Cloud home console . Request three Elastic Computer Service(ECS) instances with below sizing: System: 2vCPU+4GiB OS: Ubuntu 20.04 x86_64 Instance Type: ecs.sn1.medium Instance Name: cka001, cka002, cka003 Network: both public IPs and private IPs Maximum Bandwidth: 100Mbps (Peak Value) Cloud disk: 40GiB Billing Method: Preemptible instance (spot price) Open a local terminal, log onto remote ECS cka001 using the key pair (e.g., aliyun-root ) from Aliyun cloud. ssh -i aliyun-root root@cka001 Create a common user (e.g., james ), and set primary group as sudo and other group as root . adduser james usermod -g sudo james usermod -a -G root james Back to the local terminal, generate key for common user james by below command. # Windows ssh-keygen.exe # Linux ssh-keygen Two files will be created, e.g., aliyun-james and aliyun-james.pub Upload the public key aliyun-james.pub to remote cka001 using sftp command. sftp -i aliyun-root root@cka001 put aliyun-james.pub Log onto remote ECS cka001 using root account again. Move the key aliyun-james.pub to /home/james/.ssh/ . Rename file aliyun-james.pub to authorized_keys . Change ower of file authorized_keys to james . Change default group of file authorized_keys to sudo . mkdir /home/james/.ssh/ mv aliyun-james.pub /home/james/.ssh/authorized_keys chown james.sudo /home/james/.ssh/authorized_keys chmod 600 /home/james/.ssh/authorized_keys Check file /etc/ssh/sshd_config , make sure password authentication is disabled PasswordAuthentication no cat /etc/ssh/sshd_config Back to the local terminal, use james to log onto remote cka001 . ssh -i aliyun-james james@cka001 Upload the public key aliyun-james.pub to remote cka002 and cka003 using sftp command and do the same set up on cka002 and cka003 in order to enable user james to log onto cka002 and cka003 . Till now, user james can log onto cka001 , cka002 and cka003 using key aliyun-james . All demo below will be done by user james . Initialize VMs \u00b6 Configure /etc/hosts file \u00b6 Add private IPs in the /etc/hosts file in all VMs. vi /etc/hosts Disable firewall \u00b6 Disable firewall by command ufw disable in all VMs. Disable swap on Ubuntu. sudo ufw disable Check status of swap on Ubuntu. sudo ufw status verbose Turn off swap \u00b6 Turn off swap in all VMs. sudo swapoff -a Set timezone and locale \u00b6 Set timezone and local for all VMs. This step was already done during Aliyun ECS installation. ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile Something like this: ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 5 14 :51 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai Kernel setting \u00b6 Perform below kernel setting in all VMs. Create file /etc/modules-load.d/containerd.conf to set up containerd configure file. It's to load two modules overlay and br_netfilter . Service containerd depends on overlay filesystem. Sometimes referred to as union-filesystems. An overlay-filesystem tries to present a filesystem which is the result over overlaying one filesystem on top of the other. The br_netfilter module is required to enable transparent masquerading and to facilitate Virtual Extensible LAN (VxLAN) traffic for communication between Kubernetes pods across the cluster. cat < /etc/apt/sources.list << EOF deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multivers deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe # deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse # deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse EOF Install Containered. sudo apt-get update && sudo apt-get install -y containerd Configure Containerd. Modify file /etc/containerd/config.toml . sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml Update sandbox_image with new value \"registry.aliyuncs.com/google_containers/pause:3.6\" . Update SystemdCgroup with new value true . [plugins] [plugins.\"io.containerd.gc.v1.scheduler\"] [plugins.\"io.containerd.grpc.v1.cri\"] sandbox_image = \"registry.aliyuncs.com/google_containers/pause:3.6\" [plugins.\"io.containerd.grpc.v1.cri\".cni] [plugins.\"io.containerd.grpc.v1.cri\".containerd] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime.options] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc.options] SystemdCgroup = true Restart Containerd service. sudo systemctl restart containerd sudo systemctl status containerd Install nerdctl \u00b6 Install nerdctl sevice fro all VMs. The goal of nerdctl is to facilitate experimenting the cutting-edge features of containerd that are not present in Docker. Get the release from the link https://github.com/containerd/nerdctl/releases . wget https://github.com/containerd/nerdctl/releases/download/v0.22.0/nerdctl-0.22.0-linux-amd64.tar.gz tar -zxvf nerdctl-0.22.0-linux-amd64.tar.gz sudo cp nerdctl /usr/bin/ sudo cp containerd-rootless* /usr/bin/ Verify nerdctl. nerdctl --help To list local Kubernetes containers. nerdctl -n k8s.io ps Install kubeadm \u00b6 Update apt-transport-https , ca-certificates , and curl . sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl Install gpg certificate. sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg Add Kubernetes repo. Just choose one of below command and execute. echo \"deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ \\ kubernetes-xenial main\" | sudo tee /etc/apt/sources.list.d/kubernetes.list Update and install dependencied packages. sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables Check available versions of kubeadm. apt policy kubeadm Install 1.24.0-00 version of kubeadm and will upgrade to 1.24.2 later. sudo apt-get -y install kubelet = 1 .24.0-00 kubeadm = 1 .24.0-00 kubectl = 1 .24.0-00 --allow-downgrades Setup Master Node \u00b6 kubeadm init \u00b6 Set up Control Plane on VM playing master node. Check kubeadm default parameters for initialization. kubeadm config print init-defaults Reuslt: apiVersion : kubeadm.k8s.io/v1beta3 bootstrapTokens : - groups : - system:bootstrappers:kubeadm:default-node-token token : abcdef.0123456789abcdef ttl : 24h0m0s usages : - signing - authentication kind : InitConfiguration localAPIEndpoint : advertiseAddress : 1.2.3.4 bindPort : 6443 nodeRegistration : criSocket : unix:///var/run/containerd/containerd.sock imagePullPolicy : IfNotPresent name : node taints : null --- apiServer : timeoutForControlPlane : 4m0s apiVersion : kubeadm.k8s.io/v1beta3 certificatesDir : /etc/kubernetes/pki clusterName : kubernetes controllerManager : {} dns : {} etcd : local : dataDir : /var/lib/etcd imageRepository : k8s.gcr.io kind : ClusterConfiguration kubernetesVersion : 1.24.0 networking : dnsDomain : cluster.local serviceSubnet : 10.96.0.0/12 scheduler : {} Dry rune and run. Save the output, which will be used later on work nodes. With kubeadm init to initiate cluster, we need understand below three options about network. --pod-network-cidr : Specify range of IP addresses for the pod network. If set, the control plane will automatically allocate CIDRs for every node. Be noted that 10.244.0.0/16 is default range of flannel. If it's changed here, please do change the same when deploy Flannel . --apiserver-bind-port : Port for the API Server to bind to. (default 6443) --service-cidr : Use alternative range of IP address for service VIPs. (default \"10.96.0.0/12\") Note: service VIPs (a.k.a. Cluster IP), specified by option --service-cidr . podCIDR (a.k.a. endpoint IP)\uff0cspecified by option --pod-network-cidr . There are 4 distinct networking problems to address: Highly-coupled container-to-container communications: this is solved by Pods (podCIDR) and localhost communications. Pod-to-Pod communications: a.k.a. container-to-container. Example with Flannel, the flow is: Pod \u2192 veth pair \u2192 cni0 \u2192 flannel.1 \u2192 host eth0 \u2192 host eth0 \u2192 flannel.1 \u2192 cni0 \u2192 veth pair \u2192 Pod. Pod-to-Service communications: Flow: Pod \u2192 Kernel \u2192 Servive iptables \u2192 service \u2192 Pod iptables \u2192 Pod External-to-Service communications: LoadBalancer: SLB \u2192 NodePort \u2192 Service \u2192 Pod kube-proxy is responsible for iptables, not traffic. sudo kubeadm init \\ --dry-run \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --kubernetes-version = v1.24.0 kubeconfig file \u00b6 Set kubeconfig file for current user (here it's james ). mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Kubernetes provides a command line tool kubectl for communicating with a Kubernetes cluster's control plane, using the Kubernetes API. kubectl controls the Kubernetes cluster manager . For configuration, kubectl looks for a file named config in the $HOME/.kube directory, which is a copy of file /etc/kubernetes/admin.conf generated by kubeadm init . We can specify other kubeconfig files by setting the KUBECONFIG environment variable or by setting the --kubeconfig flag . If the KUBECONFIG environment variable doesn't exist, kubectl uses the default kubeconfig file, $HOME/.kube/config . A context element in a kubeconfig file is used to group access parameters under a convenient name. Each context has three parameters: cluster, namespace, and user. By default, the kubectl command-line tool uses parameters from the current context to communicate with the cluster. A sample of .kube/config . apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : To get the current context: kubectl config get-contexts Result CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin Setup Work Nodes \u00b6 Perform on all VMs playing work nodes. # kubeadm join :6443 --token --discovery-token-ca-cert-hash Use kubeadm token to generate the join token and hash value. kubeadm token create --print-join-command Execute the command generated above on each node that we want to join the cluster as Worker node. Verify status on master node. All nodes' status is NotReady . Leave it at the moment and continue to install network plugin. kubectl get node -o wide Install Calico or Flannel \u00b6 Choose Calico or Flannel on control plane node. For NetworkPolicy purpose, choose Calico. Install Flannel \u00b6 Flannel is a simple and easy way to configure a layer 3 network fabric designed for Kubernetes. Deploy Flannel. In the kube-flannel.yml we can get the default network setting of Flannel, which is same with --pod-network-cidr=10.244.0.0/16 we defined before when we initiated kubeadm . net-conf.json : | { \"Network\": \"10.244.0.0/16\", \"Backend\": { \"Type\": \"vxlan\" } } Create Flannel apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml Result Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy/psp.flannel.unprivileged created clusterrole.rbac.authorization.k8s.io/flannel created clusterrolebinding.rbac.authorization.k8s.io/flannel created serviceaccount/flannel created configmap/kube-flannel-cfg created daemonset.apps/kube-flannel-ds created Install Calico \u00b6 Here is guidance of End-to-end Calico installation . Detail practice demo, can be found in section \"Install Calico\" of \"A1.Discussion\" below. Install Calico curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Result configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created Verify status of Calico. kubectl get pod -n kube-system | grep calico Result calico-kube-controllers-555bc4b957-l8bn2 0/1 Pending 0 28s calico-node-255pc 0/1 Init:1/3 0 29s calico-node-7tmnb 0/1 Init:1/3 0 29s calico-node-w8nvl 0/1 Init:1/3 0 29s Verify network status. sudo nerdctl network ls Result NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none Check Cluster Status \u00b6 Perform kubectl cluster-info command on master node we will get below information. Kubernetes control plane is running at https://:6443 CoreDNS is running at https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy kubectl cluster-info Get nodes status. kubectl get nodes -owide All nodes are up with normal status. OS Image: Ubuntu 20.04.4 LTS Kernel Version: 5.4.0-122-generic Container Runtime: containerd://1.5.9 NAME STATUS ROLES AGE VERSION cka001 Ready control-plane 13m v1.24.0 cka002 Ready 8m35s v1.24.0 cka003 Ready 8m26s v1.24.0 Get pods status kubectl get pod -A Result: NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 7m18s kube-system calico-node-255pc 1/1 Running 0 7m19s kube-system calico-node-7tmnb 1/1 Running 0 7m19s kube-system calico-node-w8nvl 1/1 Running 0 7m19s kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15m kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15m kube-system etcd-cka001 1/1 Running 0 15m kube-system kube-apiserver-cka001 1/1 Running 0 15m kube-system kube-controller-manager-cka001 1/1 Running 0 15m kube-system kube-proxy-dmj2t 1/1 Running 0 15m kube-system kube-proxy-n77zw 1/1 Running 0 11m kube-system kube-proxy-qs6rf 1/1 Running 0 11m kube-system kube-scheduler-cka001 1/1 Running 0 15m Reset cluster \u00b6 CAUTION: below steps will destroy current cluster. Delete all nodes in the cluster. kubeadm reset Output: [reset] Reading configuration from the cluster... [reset] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' W0717 08:15:17.411992 3913615 preflight.go:55] [reset] WARNING: Changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted. [reset] Are you sure you want to proceed? [y/N]: y [preflight] Running pre-flight checks [reset] Stopping the kubelet service [reset] Unmounting mounted directories in \"/var/lib/kubelet\" [reset] Deleting contents of directories: [/etc/kubernetes/manifests /etc/kubernetes/pki] [reset] Deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf] [reset] Deleting contents of stateful directories: [/var/lib/etcd /var/lib/kubelet /var/lib/dockershim /var/run/kubernetes /var/lib/cni] The reset process does not clean CNI configuration. To do so, you must remove /etc/cni/net.d The reset process does not reset or clean up iptables rules or IPVS tables. If you wish to reset iptables, you must do so manually by using the \"iptables\" command. If your cluster was setup to utilize IPVS, run ipvsadm --clear (or similar) to reset your system's IPVS tables. The reset process does not clean your kubeconfig files and you must remove them manually. Please, check the contents of the $HOME/.kube/config file. Clean up network setting rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni Clean up rule of iptables . iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Clean up rule of IPVS if using IPVS . ipvsadm --clear Troubleshooting \u00b6 Issue 1 \u00b6 The connection to the server :6443 was refused - did you specify the right host or port? Try : Reference Check if the kubeconfig file is update to udpate and exists in right place. Check environment setting. env | grep -i kub Check container status. sudo systemctl status containerd.service Check kubelet service. sudo systemctl status kubelet.service Check port listening status. netstat -pnlt | grep 6443 Check firewall status. sudo systemctl status firewalld.service Check log. journalctl -xeu kubelet Issue 2 \u00b6 \"Container runtime network not ready\" networkReady=\"NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized\" Try : Restart Containerd service. sudo systemctl restart containerd sudo systemctl status containerd Post Installation \u00b6 Bash Autocomplete \u00b6 On each node. Set kubectl auto-completion following the guideline . apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc Alias \u00b6 If we set an alias for kubectl, we can extend shell completion to work with that alias: echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc Update Default Context \u00b6 Get current context. kubectl config get-contexts In below result, we know: Contenxt name is kubernetes-admin@kubernetes . Cluster name is kubernetes . User is kubernetes-admin . No namespace explicitly defined. CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin To set a context with new update, e.g, update default namespace, etc.. # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin To switch to a new context. kubectl config use-context kubectl config use-context kubernetes-admin@kubernetes Reference of kubectl and commandline .","title":"Installation on Aliyun ECS"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#installation-on-aliyun-ubuntu","text":"","title":"Installation on Aliyun Ubuntu"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#preparation","text":"Register Aliyun account via Alibaba Cloud home console . Request three Elastic Computer Service(ECS) instances with below sizing: System: 2vCPU+4GiB OS: Ubuntu 20.04 x86_64 Instance Type: ecs.sn1.medium Instance Name: cka001, cka002, cka003 Network: both public IPs and private IPs Maximum Bandwidth: 100Mbps (Peak Value) Cloud disk: 40GiB Billing Method: Preemptible instance (spot price) Open a local terminal, log onto remote ECS cka001 using the key pair (e.g., aliyun-root ) from Aliyun cloud. ssh -i aliyun-root root@cka001 Create a common user (e.g., james ), and set primary group as sudo and other group as root . adduser james usermod -g sudo james usermod -a -G root james Back to the local terminal, generate key for common user james by below command. # Windows ssh-keygen.exe # Linux ssh-keygen Two files will be created, e.g., aliyun-james and aliyun-james.pub Upload the public key aliyun-james.pub to remote cka001 using sftp command. sftp -i aliyun-root root@cka001 put aliyun-james.pub Log onto remote ECS cka001 using root account again. Move the key aliyun-james.pub to /home/james/.ssh/ . Rename file aliyun-james.pub to authorized_keys . Change ower of file authorized_keys to james . Change default group of file authorized_keys to sudo . mkdir /home/james/.ssh/ mv aliyun-james.pub /home/james/.ssh/authorized_keys chown james.sudo /home/james/.ssh/authorized_keys chmod 600 /home/james/.ssh/authorized_keys Check file /etc/ssh/sshd_config , make sure password authentication is disabled PasswordAuthentication no cat /etc/ssh/sshd_config Back to the local terminal, use james to log onto remote cka001 . ssh -i aliyun-james james@cka001 Upload the public key aliyun-james.pub to remote cka002 and cka003 using sftp command and do the same set up on cka002 and cka003 in order to enable user james to log onto cka002 and cka003 . Till now, user james can log onto cka001 , cka002 and cka003 using key aliyun-james . All demo below will be done by user james .","title":"Preparation"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#initialize-vms","text":"","title":"Initialize VMs"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#configure-etchosts-file","text":"Add private IPs in the /etc/hosts file in all VMs. vi /etc/hosts","title":"Configure /etc/hosts file"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#disable-firewall","text":"Disable firewall by command ufw disable in all VMs. Disable swap on Ubuntu. sudo ufw disable Check status of swap on Ubuntu. sudo ufw status verbose","title":"Disable firewall"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#turn-off-swap","text":"Turn off swap in all VMs. sudo swapoff -a","title":"Turn off swap"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#set-timezone-and-locale","text":"Set timezone and local for all VMs. This step was already done during Aliyun ECS installation. ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile Something like this: ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 5 14 :51 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai","title":"Set timezone and locale"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#kernel-setting","text":"Perform below kernel setting in all VMs. Create file /etc/modules-load.d/containerd.conf to set up containerd configure file. It's to load two modules overlay and br_netfilter . Service containerd depends on overlay filesystem. Sometimes referred to as union-filesystems. An overlay-filesystem tries to present a filesystem which is the result over overlaying one filesystem on top of the other. The br_netfilter module is required to enable transparent masquerading and to facilitate Virtual Extensible LAN (VxLAN) traffic for communication between Kubernetes pods across the cluster. cat < /etc/apt/sources.list << EOF deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multivers deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe # deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse # deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse EOF Install Containered. sudo apt-get update && sudo apt-get install -y containerd Configure Containerd. Modify file /etc/containerd/config.toml . sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml Update sandbox_image with new value \"registry.aliyuncs.com/google_containers/pause:3.6\" . Update SystemdCgroup with new value true . [plugins] [plugins.\"io.containerd.gc.v1.scheduler\"] [plugins.\"io.containerd.grpc.v1.cri\"] sandbox_image = \"registry.aliyuncs.com/google_containers/pause:3.6\" [plugins.\"io.containerd.grpc.v1.cri\".cni] [plugins.\"io.containerd.grpc.v1.cri\".containerd] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime.options] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc.options] SystemdCgroup = true Restart Containerd service. sudo systemctl restart containerd sudo systemctl status containerd","title":"Install Containerd"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#install-nerdctl","text":"Install nerdctl sevice fro all VMs. The goal of nerdctl is to facilitate experimenting the cutting-edge features of containerd that are not present in Docker. Get the release from the link https://github.com/containerd/nerdctl/releases . wget https://github.com/containerd/nerdctl/releases/download/v0.22.0/nerdctl-0.22.0-linux-amd64.tar.gz tar -zxvf nerdctl-0.22.0-linux-amd64.tar.gz sudo cp nerdctl /usr/bin/ sudo cp containerd-rootless* /usr/bin/ Verify nerdctl. nerdctl --help To list local Kubernetes containers. nerdctl -n k8s.io ps","title":"Install nerdctl"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#install-kubeadm","text":"Update apt-transport-https , ca-certificates , and curl . sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl Install gpg certificate. sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg Add Kubernetes repo. Just choose one of below command and execute. echo \"deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ \\ kubernetes-xenial main\" | sudo tee /etc/apt/sources.list.d/kubernetes.list Update and install dependencied packages. sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables Check available versions of kubeadm. apt policy kubeadm Install 1.24.0-00 version of kubeadm and will upgrade to 1.24.2 later. sudo apt-get -y install kubelet = 1 .24.0-00 kubeadm = 1 .24.0-00 kubectl = 1 .24.0-00 --allow-downgrades","title":"Install kubeadm"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#setup-master-node","text":"","title":"Setup Master Node"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#kubeadm-init","text":"Set up Control Plane on VM playing master node. Check kubeadm default parameters for initialization. kubeadm config print init-defaults Reuslt: apiVersion : kubeadm.k8s.io/v1beta3 bootstrapTokens : - groups : - system:bootstrappers:kubeadm:default-node-token token : abcdef.0123456789abcdef ttl : 24h0m0s usages : - signing - authentication kind : InitConfiguration localAPIEndpoint : advertiseAddress : 1.2.3.4 bindPort : 6443 nodeRegistration : criSocket : unix:///var/run/containerd/containerd.sock imagePullPolicy : IfNotPresent name : node taints : null --- apiServer : timeoutForControlPlane : 4m0s apiVersion : kubeadm.k8s.io/v1beta3 certificatesDir : /etc/kubernetes/pki clusterName : kubernetes controllerManager : {} dns : {} etcd : local : dataDir : /var/lib/etcd imageRepository : k8s.gcr.io kind : ClusterConfiguration kubernetesVersion : 1.24.0 networking : dnsDomain : cluster.local serviceSubnet : 10.96.0.0/12 scheduler : {} Dry rune and run. Save the output, which will be used later on work nodes. With kubeadm init to initiate cluster, we need understand below three options about network. --pod-network-cidr : Specify range of IP addresses for the pod network. If set, the control plane will automatically allocate CIDRs for every node. Be noted that 10.244.0.0/16 is default range of flannel. If it's changed here, please do change the same when deploy Flannel . --apiserver-bind-port : Port for the API Server to bind to. (default 6443) --service-cidr : Use alternative range of IP address for service VIPs. (default \"10.96.0.0/12\") Note: service VIPs (a.k.a. Cluster IP), specified by option --service-cidr . podCIDR (a.k.a. endpoint IP)\uff0cspecified by option --pod-network-cidr . There are 4 distinct networking problems to address: Highly-coupled container-to-container communications: this is solved by Pods (podCIDR) and localhost communications. Pod-to-Pod communications: a.k.a. container-to-container. Example with Flannel, the flow is: Pod \u2192 veth pair \u2192 cni0 \u2192 flannel.1 \u2192 host eth0 \u2192 host eth0 \u2192 flannel.1 \u2192 cni0 \u2192 veth pair \u2192 Pod. Pod-to-Service communications: Flow: Pod \u2192 Kernel \u2192 Servive iptables \u2192 service \u2192 Pod iptables \u2192 Pod External-to-Service communications: LoadBalancer: SLB \u2192 NodePort \u2192 Service \u2192 Pod kube-proxy is responsible for iptables, not traffic. sudo kubeadm init \\ --dry-run \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --kubernetes-version = v1.24.0","title":"kubeadm init"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#kubeconfig-file","text":"Set kubeconfig file for current user (here it's james ). mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Kubernetes provides a command line tool kubectl for communicating with a Kubernetes cluster's control plane, using the Kubernetes API. kubectl controls the Kubernetes cluster manager . For configuration, kubectl looks for a file named config in the $HOME/.kube directory, which is a copy of file /etc/kubernetes/admin.conf generated by kubeadm init . We can specify other kubeconfig files by setting the KUBECONFIG environment variable or by setting the --kubeconfig flag . If the KUBECONFIG environment variable doesn't exist, kubectl uses the default kubeconfig file, $HOME/.kube/config . A context element in a kubeconfig file is used to group access parameters under a convenient name. Each context has three parameters: cluster, namespace, and user. By default, the kubectl command-line tool uses parameters from the current context to communicate with the cluster. A sample of .kube/config . apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : To get the current context: kubectl config get-contexts Result CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin","title":"kubeconfig file"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#setup-work-nodes","text":"Perform on all VMs playing work nodes. # kubeadm join :6443 --token --discovery-token-ca-cert-hash Use kubeadm token to generate the join token and hash value. kubeadm token create --print-join-command Execute the command generated above on each node that we want to join the cluster as Worker node. Verify status on master node. All nodes' status is NotReady . Leave it at the moment and continue to install network plugin. kubectl get node -o wide","title":"Setup Work Nodes"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#install-calico-or-flannel","text":"Choose Calico or Flannel on control plane node. For NetworkPolicy purpose, choose Calico.","title":"Install Calico or Flannel"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#install-flannel","text":"Flannel is a simple and easy way to configure a layer 3 network fabric designed for Kubernetes. Deploy Flannel. In the kube-flannel.yml we can get the default network setting of Flannel, which is same with --pod-network-cidr=10.244.0.0/16 we defined before when we initiated kubeadm . net-conf.json : | { \"Network\": \"10.244.0.0/16\", \"Backend\": { \"Type\": \"vxlan\" } } Create Flannel apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml Result Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy/psp.flannel.unprivileged created clusterrole.rbac.authorization.k8s.io/flannel created clusterrolebinding.rbac.authorization.k8s.io/flannel created serviceaccount/flannel created configmap/kube-flannel-cfg created daemonset.apps/kube-flannel-ds created","title":"Install Flannel"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#install-calico","text":"Here is guidance of End-to-end Calico installation . Detail practice demo, can be found in section \"Install Calico\" of \"A1.Discussion\" below. Install Calico curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Result configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created Verify status of Calico. kubectl get pod -n kube-system | grep calico Result calico-kube-controllers-555bc4b957-l8bn2 0/1 Pending 0 28s calico-node-255pc 0/1 Init:1/3 0 29s calico-node-7tmnb 0/1 Init:1/3 0 29s calico-node-w8nvl 0/1 Init:1/3 0 29s Verify network status. sudo nerdctl network ls Result NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none","title":"Install Calico"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#check-cluster-status","text":"Perform kubectl cluster-info command on master node we will get below information. Kubernetes control plane is running at https://:6443 CoreDNS is running at https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy kubectl cluster-info Get nodes status. kubectl get nodes -owide All nodes are up with normal status. OS Image: Ubuntu 20.04.4 LTS Kernel Version: 5.4.0-122-generic Container Runtime: containerd://1.5.9 NAME STATUS ROLES AGE VERSION cka001 Ready control-plane 13m v1.24.0 cka002 Ready 8m35s v1.24.0 cka003 Ready 8m26s v1.24.0 Get pods status kubectl get pod -A Result: NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 7m18s kube-system calico-node-255pc 1/1 Running 0 7m19s kube-system calico-node-7tmnb 1/1 Running 0 7m19s kube-system calico-node-w8nvl 1/1 Running 0 7m19s kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15m kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15m kube-system etcd-cka001 1/1 Running 0 15m kube-system kube-apiserver-cka001 1/1 Running 0 15m kube-system kube-controller-manager-cka001 1/1 Running 0 15m kube-system kube-proxy-dmj2t 1/1 Running 0 15m kube-system kube-proxy-n77zw 1/1 Running 0 11m kube-system kube-proxy-qs6rf 1/1 Running 0 11m kube-system kube-scheduler-cka001 1/1 Running 0 15m","title":"Check Cluster Status"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#reset-cluster","text":"CAUTION: below steps will destroy current cluster. Delete all nodes in the cluster. kubeadm reset Output: [reset] Reading configuration from the cluster... [reset] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' W0717 08:15:17.411992 3913615 preflight.go:55] [reset] WARNING: Changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted. [reset] Are you sure you want to proceed? [y/N]: y [preflight] Running pre-flight checks [reset] Stopping the kubelet service [reset] Unmounting mounted directories in \"/var/lib/kubelet\" [reset] Deleting contents of directories: [/etc/kubernetes/manifests /etc/kubernetes/pki] [reset] Deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf] [reset] Deleting contents of stateful directories: [/var/lib/etcd /var/lib/kubelet /var/lib/dockershim /var/run/kubernetes /var/lib/cni] The reset process does not clean CNI configuration. To do so, you must remove /etc/cni/net.d The reset process does not reset or clean up iptables rules or IPVS tables. If you wish to reset iptables, you must do so manually by using the \"iptables\" command. If your cluster was setup to utilize IPVS, run ipvsadm --clear (or similar) to reset your system's IPVS tables. The reset process does not clean your kubeconfig files and you must remove them manually. Please, check the contents of the $HOME/.kube/config file. Clean up network setting rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni Clean up rule of iptables . iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Clean up rule of IPVS if using IPVS . ipvsadm --clear","title":"Reset cluster"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#troubleshooting","text":"","title":"Troubleshooting"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#issue-1","text":"The connection to the server :6443 was refused - did you specify the right host or port? Try : Reference Check if the kubeconfig file is update to udpate and exists in right place. Check environment setting. env | grep -i kub Check container status. sudo systemctl status containerd.service Check kubelet service. sudo systemctl status kubelet.service Check port listening status. netstat -pnlt | grep 6443 Check firewall status. sudo systemctl status firewalld.service Check log. journalctl -xeu kubelet","title":"Issue 1"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#issue-2","text":"\"Container runtime network not ready\" networkReady=\"NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized\" Try : Restart Containerd service. sudo systemctl restart containerd sudo systemctl status containerd","title":"Issue 2"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#post-installation","text":"","title":"Post Installation"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#bash-autocomplete","text":"On each node. Set kubectl auto-completion following the guideline . apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc","title":"Bash Autocomplete"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#alias","text":"If we set an alias for kubectl, we can extend shell completion to work with that alias: echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc","title":"Alias"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#update-default-context","text":"Get current context. kubectl config get-contexts In below result, we know: Contenxt name is kubernetes-admin@kubernetes . Cluster name is kubernetes . User is kubernetes-admin . No namespace explicitly defined. CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin To set a context with new update, e.g, update default namespace, etc.. # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin To switch to a new context. kubectl config use-context kubectl config use-context kubernetes-admin@kubernetes Reference of kubectl and commandline .","title":"Update Default Context"},{"location":"k8s/cka_en/installation/multiple-local/","text":"Multiple Nodes Installation \u00b6 Local VM setting \u00b6 VMWare Setting. VMnet1: host-only, subnet: 192.168.150.0/24 VMnet8: NAT, subnet: 11.0.1.0/24 Create guest machine with VMWare Player. 4 GB RAM 1 CPUs with 2 Cores Ubuntu Server 22.04 NAT Info: Kubernetes running on Containerd. Ubuntu Post Installation \u00b6 Info: Log onto each VM with the account created during Ubuntu installation, and perform below tasks on every VM. Create user vagrant on all guests. sudo adduser vagrant sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd,root vagrant sudo passwd vagrant Set password for root on all guests. sudo passwd root Enable root ssh logon. sudo vi /etc/ssh/sshd_config Update parameter PermitRootLogin from prohibit-password to yes . PermitRootLogin yes # PermitRootLogin prohibit-password Restart the sshd service. sudo systemctl restart sshd Change host name, e.g., ubu1 . sudo hostnamectl set-hostname ubu1 sudo hostnamectl set-hostname ubu1 --pretty Verify if the hostname is set to expected name, e.g., ubu1 . cat /etc/machine-info Verify if the hostname is set to expected name, e.g., ubu1 . cat /etc/hostname Verify if the hostname of 127.0.1.1 is set to expected name, e.g., ubu1 . And add all nodes into the file /etc/hosts . sudo vi /etc/hosts Related setting looks like below. 127.0.1.1 ubu1 11.0.1.129 ubu1 11.0.1.130 ubu2 11.0.1.131 ubu3 11.0.1.132 ubu4 Create file /etc/netplan/00-installer-config.yaml . sudo vi /etc/netplan/00-installer-config.yaml Update it with information below to set VM with fixed IP with actual IP address, e.g, 11.0.1.129 . network : ethernets : ens33 : dhcp4 : false addresses : - 11.0.1.129/24 nameservers : addresses : - 11.0.1.2 routes : - to : default via : 11.0.1.2 version : 2 Effect above change. sudo netplan apply Attention: The current ssh connection will be broken due to network setting change. Disable swap and firewall on all nodes. sudo swapoff -a sudo ufw disable sudo ufw status verbose And comment the last line of swap setting in file /etc/fstab . Need reboot guest here. sudo vi /etc/fstab Result likes below. /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 Setup timezone on all nodes sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo cp /etc/profile /etc/profile.bak echo 'LANG=\"en_US.UTF-8\"' | sudo tee -a /etc/profile source /etc/profile Something like this after execute command ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai Kernel setting. cat < server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : To get the current context: kubectl config get-contexts Result CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin Install Calico \u00b6 Here is guidance of End-to-end Calico installation . Detail practice demo, can be found in section \"Install Calico\" of \"A1.Discussion\" below. Install Calico curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Result configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created Verify status of Calico. It may take minutes to complete initialization. kubectl get pod -n kube-system | grep calico Result calico-kube-controllers-555bc4b957-l8bn2 0/1 Pending 0 28s calico-node-255pc 0/1 Init:1/3 0 29s calico-node-7tmnb 0/1 Init:1/3 0 29s calico-node-w8nvl 0/1 Init:1/3 0 29s Verify network status. sudo nerdctl network ls Result NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 17f29b073143 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none Setup Work Nodes \u00b6 Use kubeadm token to generate the join token and hash value. kubeadm token create --print-join-command Command usage: sudo kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> Result looks like below. [preflight] Running pre-flight checks [WARNING SystemVerification]: missing optional cgroups: blkio [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [kubelet-start] Writing kubelet configuration to file \"/var/lib/kubelet/config.yaml\" [kubelet-start] Writing kubelet environment file with flags to file \"/var/lib/kubelet/kubeadm-flags.env\" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster. Check Cluster Status \u00b6 Cluster info: kubectl cluster-info Output Kubernetes control plane is running at https://11.0.1.129:6443 CoreDNS is running at https://11.0.1.129:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. Node info: kubectl get nodes -owide Pod info: kubectl get pod -A Post Installation \u00b6 Bash Autocomplete \u00b6 On each node. Set kubectl auto-completion following the guideline . apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc source ~/.bashrc Alias \u00b6 If we set an alias for kubectl, we can extend shell completion to work with that alias: echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc Update Default Context \u00b6 Get current context. kubectl config get-contexts In below result, we know: Contenxt name is kubernetes-admin@kubernetes . Cluster name is kubernetes . User is kubernetes-admin . No namespace explicitly defined. CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin To set a context with new update, e.g, update default namespace, etc.. # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin To switch to a new context. kubectl config use-context kubectl config use-context kubernetes-admin@kubernetes Reference: kubectl commandline Install Helm \u00b6 Helm is the Kubernetes package manager. It doesn't come with Kubernetes. Three concepts of helm: A Chart is a Helm package. It contains all of the resource definitions necessary to run an application, tool, or service inside of a Kubernetes cluster. Think of it like the Kubernetes equivalent of a Homebrew formula, an Apt dpkg, or a Yum RPM file. A Repository is the place where charts can be collected and shared. It's like Perl's CPAN archive or the Fedora Package Database, but for Kubernetes packages. A Release is an instance of a chart running in a Kubernetes cluster. One chart can often be installed many times into the same cluster. And each time it is installed, a new release is created. Consider a MySQL chart. If you want two databases running in your cluster, you can install that chart twice. Each one will have its own release, which will in turn have its own release name. Reference: installation guide binary release source code . Helm Client Installation: curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh Output: Downloading https://get.helm.sh/helm-v3.9.1-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm Note: helm init does not exist in Helm 3, following the removal of Tiller. You no longer need to install Tiller in your cluster in order to use Helm. helm search can be used to search two different types of source: helm search hub searches the Artifact Hub , which lists helm charts from dozens of different repositories. helm search repo searches the repositories that you have added to your local helm client (with helm repo add). This search is done over local data, and no public network connection is needed. Reference: Helming development Reset cluster \u00b6 Caution: below steps will destroy current cluster. Delete all nodes in the cluster. kubeadm reset Clean up rule of iptables . iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Clean up rule of IPVS if using IPVS . ipvsadm --clear","title":"Multiple Nodes Installation"},{"location":"k8s/cka_en/installation/multiple-local/#multiple-nodes-installation","text":"","title":"Multiple Nodes Installation"},{"location":"k8s/cka_en/installation/multiple-local/#local-vm-setting","text":"VMWare Setting. VMnet1: host-only, subnet: 192.168.150.0/24 VMnet8: NAT, subnet: 11.0.1.0/24 Create guest machine with VMWare Player. 4 GB RAM 1 CPUs with 2 Cores Ubuntu Server 22.04 NAT Info: Kubernetes running on Containerd.","title":"Local VM setting"},{"location":"k8s/cka_en/installation/multiple-local/#ubuntu-post-installation","text":"Info: Log onto each VM with the account created during Ubuntu installation, and perform below tasks on every VM. Create user vagrant on all guests. sudo adduser vagrant sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd,root vagrant sudo passwd vagrant Set password for root on all guests. sudo passwd root Enable root ssh logon. sudo vi /etc/ssh/sshd_config Update parameter PermitRootLogin from prohibit-password to yes . PermitRootLogin yes # PermitRootLogin prohibit-password Restart the sshd service. sudo systemctl restart sshd Change host name, e.g., ubu1 . sudo hostnamectl set-hostname ubu1 sudo hostnamectl set-hostname ubu1 --pretty Verify if the hostname is set to expected name, e.g., ubu1 . cat /etc/machine-info Verify if the hostname is set to expected name, e.g., ubu1 . cat /etc/hostname Verify if the hostname of 127.0.1.1 is set to expected name, e.g., ubu1 . And add all nodes into the file /etc/hosts . sudo vi /etc/hosts Related setting looks like below. 127.0.1.1 ubu1 11.0.1.129 ubu1 11.0.1.130 ubu2 11.0.1.131 ubu3 11.0.1.132 ubu4 Create file /etc/netplan/00-installer-config.yaml . sudo vi /etc/netplan/00-installer-config.yaml Update it with information below to set VM with fixed IP with actual IP address, e.g, 11.0.1.129 . network : ethernets : ens33 : dhcp4 : false addresses : - 11.0.1.129/24 nameservers : addresses : - 11.0.1.2 routes : - to : default via : 11.0.1.2 version : 2 Effect above change. sudo netplan apply Attention: The current ssh connection will be broken due to network setting change. Disable swap and firewall on all nodes. sudo swapoff -a sudo ufw disable sudo ufw status verbose And comment the last line of swap setting in file /etc/fstab . Need reboot guest here. sudo vi /etc/fstab Result likes below. /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 Setup timezone on all nodes sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo cp /etc/profile /etc/profile.bak echo 'LANG=\"en_US.UTF-8\"' | sudo tee -a /etc/profile source /etc/profile Something like this after execute command ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai Kernel setting. cat < server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : To get the current context: kubectl config get-contexts Result CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin","title":"kubeconfig file"},{"location":"k8s/cka_en/installation/multiple-local/#install-calico","text":"Here is guidance of End-to-end Calico installation . Detail practice demo, can be found in section \"Install Calico\" of \"A1.Discussion\" below. Install Calico curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Result configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created Verify status of Calico. It may take minutes to complete initialization. kubectl get pod -n kube-system | grep calico Result calico-kube-controllers-555bc4b957-l8bn2 0/1 Pending 0 28s calico-node-255pc 0/1 Init:1/3 0 29s calico-node-7tmnb 0/1 Init:1/3 0 29s calico-node-w8nvl 0/1 Init:1/3 0 29s Verify network status. sudo nerdctl network ls Result NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 17f29b073143 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none","title":"Install Calico"},{"location":"k8s/cka_en/installation/multiple-local/#setup-work-nodes","text":"Use kubeadm token to generate the join token and hash value. kubeadm token create --print-join-command Command usage: sudo kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> Result looks like below. [preflight] Running pre-flight checks [WARNING SystemVerification]: missing optional cgroups: blkio [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [kubelet-start] Writing kubelet configuration to file \"/var/lib/kubelet/config.yaml\" [kubelet-start] Writing kubelet environment file with flags to file \"/var/lib/kubelet/kubeadm-flags.env\" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster.","title":"Setup Work Nodes"},{"location":"k8s/cka_en/installation/multiple-local/#check-cluster-status","text":"Cluster info: kubectl cluster-info Output Kubernetes control plane is running at https://11.0.1.129:6443 CoreDNS is running at https://11.0.1.129:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. Node info: kubectl get nodes -owide Pod info: kubectl get pod -A","title":"Check Cluster Status"},{"location":"k8s/cka_en/installation/multiple-local/#post-installation","text":"","title":"Post Installation"},{"location":"k8s/cka_en/installation/multiple-local/#bash-autocomplete","text":"On each node. Set kubectl auto-completion following the guideline . apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc source ~/.bashrc","title":"Bash Autocomplete"},{"location":"k8s/cka_en/installation/multiple-local/#alias","text":"If we set an alias for kubectl, we can extend shell completion to work with that alias: echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc","title":"Alias"},{"location":"k8s/cka_en/installation/multiple-local/#update-default-context","text":"Get current context. kubectl config get-contexts In below result, we know: Contenxt name is kubernetes-admin@kubernetes . Cluster name is kubernetes . User is kubernetes-admin . No namespace explicitly defined. CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin To set a context with new update, e.g, update default namespace, etc.. # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin To switch to a new context. kubectl config use-context kubectl config use-context kubernetes-admin@kubernetes Reference: kubectl commandline","title":"Update Default Context"},{"location":"k8s/cka_en/installation/multiple-local/#install-helm","text":"Helm is the Kubernetes package manager. It doesn't come with Kubernetes. Three concepts of helm: A Chart is a Helm package. It contains all of the resource definitions necessary to run an application, tool, or service inside of a Kubernetes cluster. Think of it like the Kubernetes equivalent of a Homebrew formula, an Apt dpkg, or a Yum RPM file. A Repository is the place where charts can be collected and shared. It's like Perl's CPAN archive or the Fedora Package Database, but for Kubernetes packages. A Release is an instance of a chart running in a Kubernetes cluster. One chart can often be installed many times into the same cluster. And each time it is installed, a new release is created. Consider a MySQL chart. If you want two databases running in your cluster, you can install that chart twice. Each one will have its own release, which will in turn have its own release name. Reference: installation guide binary release source code . Helm Client Installation: curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh Output: Downloading https://get.helm.sh/helm-v3.9.1-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm Note: helm init does not exist in Helm 3, following the removal of Tiller. You no longer need to install Tiller in your cluster in order to use Helm. helm search can be used to search two different types of source: helm search hub searches the Artifact Hub , which lists helm charts from dozens of different repositories. helm search repo searches the repositories that you have added to your local helm client (with helm repo add). This search is done over local data, and no public network connection is needed. Reference: Helming development","title":"Install Helm"},{"location":"k8s/cka_en/installation/multiple-local/#reset-cluster","text":"Caution: below steps will destroy current cluster. Delete all nodes in the cluster. kubeadm reset Clean up rule of iptables . iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Clean up rule of IPVS if using IPVS . ipvsadm --clear","title":"Reset cluster"},{"location":"k8s/cka_en/installation/single-local/","text":"Single Node Installation \u00b6 Local VM setting \u00b6 VMWare Setting. VMnet1: host-only, subnet: 192.168.150.0/24 VMnet8: NAT, subnet: 11.0.1.0/24 Create guest machine with VMWare Player. 4 GB RAM 2 CPUs with 2 Cores Ubuntu Server 22.04 NAT Kubernetes running on Docker. Ubuntu Post Installation \u00b6 Create user vagrant . sudo adduser vagrant sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd vagrant sudo passwd vagrant Set password for root . sudo passwd root Update guest's hostname. Here it's ubusvr . sudo hostnamectl set-hostname ubusvr sudo hostnamectl set-hostname ubusvr --pretty Verify if the hostname is set to ubusvr . cat /etc/machine-info Verify if the hostname is set to ubusvr . cat /etc/hostname Verify if the hostname of 127.0.1.1 is set to ubusvr . cat /etc/hosts 127 .0.0.1 localhost 127 .0.1.1 ubusrv # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters Set guest with fix ip, e.g, 11.0.1.136 . sudo vi 00 -installer-config.yaml network: ethernets: ens33: dhcp4: false addresses: - 11 .0.1.136/24 nameservers: addresses: - 11 .0.1.2 routes: - to: default via: 11 .0.1.2 version: 2 sudo netplan apply Disable swap sudo swapoff -a sudo ufw disable sudo ufw status verbose And comment the last line of swap setting in file /etc/fstab . Need reboot guest here. /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 Setup timezone sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile Something like this after execute command ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 15 22 :00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai Kernel setting cat < /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl status docker.service sudo systemctl status containerd.service sudo groupadd docker sudo usermod -aG docker $USER Setup Containerd containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml sudo systemctl restart containerd sudo systemctl status containerd Install Kubernetes \u00b6 Install kubeadm sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg echo \"deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main\" | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables apt policy kubeadm sudo apt-get -y install kubelet = 1 .23.8-00 kubeadm = 1 .23.8-00 kubectl = 1 .23.8-00 --allow-downgrades Setup Master Node sudo kubeadm config print init-defaults Dry run sudo kubeadm init --dry-run --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 Run sudo kubeadm init --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Install Flannel. If NetworkPolicy is the case, then install Calico. Refer to the \"Install Calico or Flannel\" of below section \"Installation on Aliyun Ubuntu\". kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml Setup on Worker Node Command usage: kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> kubeadm join 11 .0.1.136:6443 --token 6zqh1u.8b4afzc2ov4e7iuj \\ --discovery-token-ca-cert-hash sha256:815fdb9dd9e3ae0af07ffaf6c216964388098b150ef01ee3ae900c261a429d24 Setup bash auto completion on all nodes sudo apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc Create alias echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc Check Cluster Status kubectl cluster-info kubectl get nodes -owide kubectl get pod -A Reset cluster \u00b6 CAUTION: below steps will destroy current cluster. Delete all nodes in the cluster. kubeadm reset Clean up rule of iptables . iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Clean up rule of IPVS if using IPVS . ipvsadm --clear Install Helm \u00b6 Helm Client Installation: curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh Output: Downloading https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm","title":"Single Node Installation"},{"location":"k8s/cka_en/installation/single-local/#single-node-installation","text":"","title":"Single Node Installation"},{"location":"k8s/cka_en/installation/single-local/#local-vm-setting","text":"VMWare Setting. VMnet1: host-only, subnet: 192.168.150.0/24 VMnet8: NAT, subnet: 11.0.1.0/24 Create guest machine with VMWare Player. 4 GB RAM 2 CPUs with 2 Cores Ubuntu Server 22.04 NAT Kubernetes running on Docker.","title":"Local VM setting"},{"location":"k8s/cka_en/installation/single-local/#ubuntu-post-installation","text":"Create user vagrant . sudo adduser vagrant sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd vagrant sudo passwd vagrant Set password for root . sudo passwd root Update guest's hostname. Here it's ubusvr . sudo hostnamectl set-hostname ubusvr sudo hostnamectl set-hostname ubusvr --pretty Verify if the hostname is set to ubusvr . cat /etc/machine-info Verify if the hostname is set to ubusvr . cat /etc/hostname Verify if the hostname of 127.0.1.1 is set to ubusvr . cat /etc/hosts 127 .0.0.1 localhost 127 .0.1.1 ubusrv # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters Set guest with fix ip, e.g, 11.0.1.136 . sudo vi 00 -installer-config.yaml network: ethernets: ens33: dhcp4: false addresses: - 11 .0.1.136/24 nameservers: addresses: - 11 .0.1.2 routes: - to: default via: 11 .0.1.2 version: 2 sudo netplan apply Disable swap sudo swapoff -a sudo ufw disable sudo ufw status verbose And comment the last line of swap setting in file /etc/fstab . Need reboot guest here. /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 Setup timezone sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile Something like this after execute command ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 15 22 :00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai Kernel setting cat < /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl status docker.service sudo systemctl status containerd.service sudo groupadd docker sudo usermod -aG docker $USER Setup Containerd containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml sudo systemctl restart containerd sudo systemctl status containerd","title":"Install Docker"},{"location":"k8s/cka_en/installation/single-local/#install-kubernetes","text":"Install kubeadm sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg echo \"deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main\" | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables apt policy kubeadm sudo apt-get -y install kubelet = 1 .23.8-00 kubeadm = 1 .23.8-00 kubectl = 1 .23.8-00 --allow-downgrades Setup Master Node sudo kubeadm config print init-defaults Dry run sudo kubeadm init --dry-run --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 Run sudo kubeadm init --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Install Flannel. If NetworkPolicy is the case, then install Calico. Refer to the \"Install Calico or Flannel\" of below section \"Installation on Aliyun Ubuntu\". kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml Setup on Worker Node Command usage: kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> kubeadm join 11 .0.1.136:6443 --token 6zqh1u.8b4afzc2ov4e7iuj \\ --discovery-token-ca-cert-hash sha256:815fdb9dd9e3ae0af07ffaf6c216964388098b150ef01ee3ae900c261a429d24 Setup bash auto completion on all nodes sudo apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc Create alias echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc Check Cluster Status kubectl cluster-info kubectl get nodes -owide kubectl get pod -A","title":"Install Kubernetes"},{"location":"k8s/cka_en/installation/single-local/#reset-cluster","text":"CAUTION: below steps will destroy current cluster. Delete all nodes in the cluster. kubeadm reset Clean up rule of iptables . iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Clean up rule of IPVS if using IPVS . ipvsadm --clear","title":"Reset cluster"},{"location":"k8s/cka_en/installation/single-local/#install-helm","text":"Helm Client Installation: curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh Output: Downloading https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm","title":"Install Helm"},{"location":"k8s/demo/cap_on_kyma/","text":"Build CAP Application on Kyma \u00b6 This is the memo of self-practice following the tutorials from Deploy Your CAP Application on SAP BTP Kyma Runtime . Prerequisites: Register account in Developer@SAP . Register trial account in SAP BTP . Tasks: Configure Kyma in SAP Business Technology Platform (SAP BTP) subaccount and prepare Kyma development environment. Create an HDI container for an SAP HANA Cloud instance on Cloud Foundry and create credentials for this SAP HANA cloud instance in Kyma cluster. Develop a business application using SAP Cloud Application Programming Model (CAP). Start on local environment, enhance it with an SAP Fiori UI, add business logic to it, and also roles and authorization check. Add a Helm chart to the application, build docker images, push them to your container registry, and deploy your application to your Kyma cluster on SAP BTP. Local environment: Applel Silicon M1 chipset macOS 12.6 (command sw_vers ) Nodejs version: CDS version: jq - for JSON processing in CLI ( brew install jq ) SAP BTP subaccount configuration \u00b6 For the SAP BTP free tier, the recommendation is as well to use an AWS-based subaccount. Kyma runtime in the free tier is only available on AWS. Choose the entitlements for the subdomain: Alert Notification: Standard plan Continuous Integration & Delivery: default (Application) or the trial (Application) or free (Application) plans which are not charged Kyma runtime: any available plan in the list (trial and free are not charged) Launchpad Service: standard (Application) or free (Application) SAP HANA Cloud: hana SAP HANA Schemas & HDI Containers: hdi-shared Set up local BTP environment \u00b6 Here we will use btp command to set up cloud environment. Details we can refer to help document Working with Environments Using the btp CLI . Download BTP CLI package btp-cli-darwin-amd64-.tar.gz via link and unpackage it. tar xvf btp-cli-darwin-amd64-.tar.gz A new subfolder darwin-amd64 will be created in current path and a bin file btp is under the subfolder. Move file btp to folder /usr/local/bin/ . sudo mv ./darwin-amd64/btp /usr/local/bin/ Log on to the subaccount on BTP. btp login --url https://cpcli.cf.eu10.hana.ondemand.com --subdomain --user Configuration file was stored at /Users/$USER/Library/Application Support/.btp/config.json . In Linux, the configuration file is on /home/$USER/.config/.btp/config.json . We can get current user via command echo $USER . Tips: Commands are executed in the target, unless specified otherwise using a parameter. To change the target, use btp target . For an explanation of the targeting mechanism, use btp help target . Get the subaccount ID in BTP and we will know that kyma and cloundfoundry are available in current trial account. btp list accounts/available-environment --subaccount Get details about an environment available for a subaccount btp get accounts/available-environment --subaccount --environment cloudfoundry --service cloudfoundry --plan standard btp get accounts/available-environment --subaccount --environment kyma --service kymaruntime --plan trial Get status running instances. Here we will also get environment ID of running instances. btp list accounts/environment-instance --subaccount Delete a running instance if needed. btp delete accounts/environment-instance --subaccount Create Kyma instance. btp create accounts/environment-instance --subaccount --environment kyma --service kymaruntime --plan trial --parameters '{\"name\": \"\"}' btp get accounts/environment-instance --subaccount Create CloudFoundry instance btp create accounts/environment-instance --subaccount --environment cloudfoundry --service cloudfoundry --plan standard --parameters '{\"instance_name\": \"\"}' btp get accounts/environment-instance --subaccount Log onto CF to create space DEV by providing API endpoint, Email and Password, which are ready in the subaccount overview page. cf login cf create-space DEV Install Homebrew \u00b6 Refer to installation guide . Set environment variables export HOMEBREW_BREW_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/brew.git\" export HOMEBREW_CORE_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/homebrew-core.git\" export HOMEBREW_BOTTLE_DOMAIN = \"https://mirrors.ustc.edu.cn/homebrew-bottles\" Install Homebrew /bin/bash -c \" $( curl -fsSL https://github.com/Homebrew/install/raw/HEAD/install.sh ) \" Add below in file ~/.zprofile . export HOMEBREW_BREW_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/brew.git\" export HOMEBREW_CORE_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/homebrew-core.git\" export HOMEBREW_BOTTLE_DOMAIN = \"https://mirrors.ustc.edu.cn/homebrew-bottles\" eval \" $( /opt/homebrew/bin/brew shellenv ) \" Make it effected. source ~/.zprofile Install kubetcl \u00b6 The kubectl installation guide curl -LO \"https://dl.k8s.io/release/ $( curl -L -s https://dl.k8s.io/release/stable.txt ) /bin/darwin/arm64/kubectl\" chmod +x ./kubectl sudo mv ./kubectl /usr/local/bin/kubectl sudo chown root: /usr/local/bin/kubectl kubectl version --client Install plugin oidc-login . curl -fsSLO https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-darwin_arm64.tar.gz tar xvf krew-darwin_arm64.tar.gz ./krew-darwin_arm64 install krew Add the $HOME/.krew/bin directory to the PATH environment variable by updating ~/.zprofile . export PATH = $HOME /.krew/bin: $PATH : $PATH Make it effected source ~/.zprofile Run kubectl krew to check the installation. Install/uninstall plugin oidc-login . kubectl krew install oidc-login kubectl krew uninstall oidc-login SAP Kyma runtime \u00b6 In the Overview area of your subaccount open the Link to dashboard link which appears next to the Console URL under the Kyma Environment area. At the top left of the window choose the Clusters Overview drop down and choose your cluster. In the Clusters Overview window choose the Download Kubeconfig for your Kyma runtime to download your KUBECONFIG. Add below to ~/.zprofile to set the kubeconfig to an environment variable. export KUBECONFIG = Make above change effected. source ~/.zprofile chmod 600 Test connection between kubectl and Kyma on BTP. kubectl cluster-info Install Node.js \u00b6 Refer to installation guide brew search node brew install node@16 brew unlink node brew link node@16 node -v Install SQLite \u00b6 Install SQLite via brew . brew search sqlite brew install sqlite Add below to ~/.zprofile export PATH = /opt/homebrew/opt/sqlite/bin: $PATH Make it effected source ~/.zprofile Install Xcode \u00b6 (For macOS) We have to install Command-Line Tools for Xcode , cause some node modules need binary modules (node-gyp). xcode-select --install xcode-select --help Install Git \u00b6 Refer to installation guide . brew install git git version Install SAPUI5 \u00b6 Install the UI5 CLI. npm search --global @ui5/cli npm install --global @ui5/cli npm list --global @ui5/cli ui5 --version npm search --global grunt-cli npm install --global grunt-cli npm list --global grunt-cli Install CF CLI \u00b6 Refer to installation guide . brew install cloudfoundry/tap/cf-cli@8 cf --version Install CAP Tooling \u00b6 See the details in the CAP documentation . npm search --global @sap/cds-dk npm install --global @sap/cds-dk npm list --global @sap/cds-dk cds --version Install VSCode \u00b6 In VS Code, invoke the Command Palette ( View \u2192 Command Palette or \u21e7\u2318P) and type shell command to find the Shell Command: Install 'code' command in PATH . Install SAP CDS Language Support extension. Install SAP Fiori tools - Extension Pack extension. Install Yeoman \u00b6 Yeoman is a tool for scaffolding web apps. You\u2019ll need it if you want to carry out the tutorial Add the SAP Launchpad Service. npm install --global yo yo --version Install Docker \u00b6 brew install docker --cask Install Helm \u00b6 Refer to installation guide brew install helm Install Paketo(pack) \u00b6 Refer to installation guide . brew install buildpacks/tap/pack Install Rancher Desktop \u00b6 Download the Rancher Desktop installer for macOS from the release page . Refer to installation guide . Download tutorial \u00b6 Go to tutorial root directory and clone the code. git clone https://github.com/SAP-samples/cloud-cap-risk-management tutorial Initialize the project \u00b6 Install required Node.js modules in the app directory cpapp . cd app cds init npm install cds watch Add files to the project \u00b6 Copy the file schema.cds from templates/create-cap-application/db to the db folder of the app. It creates two entities in the namespace sap.ui.riskmanagement : Risks and Mitigations . Copy the file risk-service.cds from templates/create-cap-application/srv to the srv folder of the app. It creates a new service RiskService in the namespace sap.ui.riskmanagement . This service exposes two entities: Risks and Mitigations , which are exposing the entities of the database schema we've created in the step before. Copy the folder data from templates/create-cap-application/db to the db folder of the app. There are two comma-separated value (CSV) files that contain local data for both the Risks and the Mitigations entities. Use Fiori Application Generator (VSCode extension) to generate Risk UI with Fiori element template. The generation will create a risks and a webapp folder with a Component.js file in the app folder of the project. Copy the file risks-service-ui.cds from templates/create-ui-fiori-elements/srv to the srv folder of the app. It defines annotations to show a work list with some columns and the data from the service in the Risk UI. Edit app/risks/webapp/manifest.json file to make the header fields editable, that is, shows title and description in Risk UI. Copy the file risk-service.js from templates/cap-business-logic/srv to the srv folder of the app. It now shows the work list in Risk UI with the columns Priority and Impact with color and an icon, depending on the amount in Impact . Use Fiori Application Generator (VSCode extension) to generate Migration UI with Fiori free-style template. The generation will create a migrations and a webapp folder with a Component.js file in the app folder of the project. Update file cpapp/app/mitigations/webapp/view/Worklist.view.xml to show Description , Owner , and Timeline columns, as well as in detail object page. Till now, our risks and mitigations application have been generated by the SAP Fiori Tools Generator and can be started independently. They are launched without a launch page. Copy the file launchpage.html from templates/launchpage/app to the app folder of the app. There are two applications in the launch page with URLs that point to the respective apps. We now see the Mitigations app next to the Risks app on the launch page. Open the file srv/risk-service.cds and add role restrictions to entities. Copy the file templates/cap-roles/.cdsrc.json to the project directory cpapp . The file defines two users risk.viewer@tester.sap.com and risk.manager@tester.sap.com . The default password can be found in the file .cdsrc.json . We will see the CAP server to show above applications via link http://localhost:4004 . Prepare Kyma Development Environment \u00b6 Execute cds version to make sure the package.json is using @sap/cds 6.0.1 or newer and we have @sap/cds-dk 6.0.1 or newer globally installed. Create namespace on Kyma. kubectl create namespace risk-management Switch to the namespace. kubectl config set-context --current --namespace risk-management Create container registry secret. Copy the folder scripts from templates/Kyma-Prepare-Dev-Environment to the project root folder cpapp . In the root folder cpapp of the project, run the script to create the secret. ./scripts/create-container-registry-secret.sh Need provide below input: docker-server = https://registry-1.docker.io docker-username = docker-email = docker-password = Verify kubectl get secret Set Up SAP HANA Cloud for Kyma \u00b6 Add SAP HANA support to your project. This adds the db module for SAP HANA access to the package.json file. Execute the command below in the project root directory cpapp . cds add hana --for production Verify the access to both CF and Kyma by executing below commands. cf login kubectl cluster-info Create HANA Cloud instance cpapp-db in CloudFoundry DEV namespace. The admin user id is DBADMIN . In the root folder cpapp of the project, execute: ./scripts/create-db-secret.sh cpapp-db Get the host name pattern of the cluster with the following command. Result looks like *.c-.sap.kyma.ondemand.com . kubectl get gateway -n kyma-system kyma-gateway -o jsonpath = '{.spec.servers[0].hosts[0]}' The script will: Create service key cpapp-db-key for HANA Cloud service instance cpapp-db as . Create Kubernetes secret cpapp-db for HANA DB instance. View it using kubectl get secret cpapp-db -o yaml . User Authentication and Authorization (XSUAA) Setup \u00b6 Set up XSUAA. cds add xsuaa --for production Above command will do: Adds the XSUAA service to the package.json file of the project Creates the XSUAA security configuration xs-security.json for the project Add Helm Chart \u00b6 Add Helm Chart. cds add helm Get docker server URL by command: cat ~/.docker/config.json Get the image pull secret for container registry. In the demo, it's container-registry . kubectl get secret Get the host name pattern of the cluster. kubectl get gateway -n kyma-system kyma-gateway -o jsonpath = '{.spec.servers[0].hosts[0]}' Open the file chart/values.yaml : Replace the placeholder with docker server URL https://docker.io/ . Set imagePullSecret with value name: container-registry . Add host name of the cluster without leading *. . Add the binding db pointing to the SAP HANA Cloud instance secret cpapp-db . Point the binding hana of the SAP HANA Cloud instance secret cpapp-db . Add the Authorization and Trust Management service to allow user login. Deploy CAP Application to Kyma \u00b6 Build docker image. CONTAINER_REGISTRY = https://index.docker.io/v1 CONTAINER_REGISTRY = https://registry-1.docker.io/yuhuihu CONTAINER_REGISTRY = yuhuihu CAP build. cds build --production Build CAP service. pack build $CONTAINER_REGISTRY /cpapp-srv --path gen/srv \\ --buildpack gcr.io/paketo-buildpacks/nodejs \\ --builder paketobuildpacks/builder:base","title":"Build CAP Application on Kyma"},{"location":"k8s/demo/cap_on_kyma/#build-cap-application-on-kyma","text":"This is the memo of self-practice following the tutorials from Deploy Your CAP Application on SAP BTP Kyma Runtime . Prerequisites: Register account in Developer@SAP . Register trial account in SAP BTP . Tasks: Configure Kyma in SAP Business Technology Platform (SAP BTP) subaccount and prepare Kyma development environment. Create an HDI container for an SAP HANA Cloud instance on Cloud Foundry and create credentials for this SAP HANA cloud instance in Kyma cluster. Develop a business application using SAP Cloud Application Programming Model (CAP). Start on local environment, enhance it with an SAP Fiori UI, add business logic to it, and also roles and authorization check. Add a Helm chart to the application, build docker images, push them to your container registry, and deploy your application to your Kyma cluster on SAP BTP. Local environment: Applel Silicon M1 chipset macOS 12.6 (command sw_vers ) Nodejs version: CDS version: jq - for JSON processing in CLI ( brew install jq )","title":"Build CAP Application on Kyma"},{"location":"k8s/demo/cap_on_kyma/#sap-btp-subaccount-configuration","text":"For the SAP BTP free tier, the recommendation is as well to use an AWS-based subaccount. Kyma runtime in the free tier is only available on AWS. Choose the entitlements for the subdomain: Alert Notification: Standard plan Continuous Integration & Delivery: default (Application) or the trial (Application) or free (Application) plans which are not charged Kyma runtime: any available plan in the list (trial and free are not charged) Launchpad Service: standard (Application) or free (Application) SAP HANA Cloud: hana SAP HANA Schemas & HDI Containers: hdi-shared","title":"SAP BTP subaccount configuration"},{"location":"k8s/demo/cap_on_kyma/#set-up-local-btp-environment","text":"Here we will use btp command to set up cloud environment. Details we can refer to help document Working with Environments Using the btp CLI . Download BTP CLI package btp-cli-darwin-amd64-.tar.gz via link and unpackage it. tar xvf btp-cli-darwin-amd64-.tar.gz A new subfolder darwin-amd64 will be created in current path and a bin file btp is under the subfolder. Move file btp to folder /usr/local/bin/ . sudo mv ./darwin-amd64/btp /usr/local/bin/ Log on to the subaccount on BTP. btp login --url https://cpcli.cf.eu10.hana.ondemand.com --subdomain --user Configuration file was stored at /Users/$USER/Library/Application Support/.btp/config.json . In Linux, the configuration file is on /home/$USER/.config/.btp/config.json . We can get current user via command echo $USER . Tips: Commands are executed in the target, unless specified otherwise using a parameter. To change the target, use btp target . For an explanation of the targeting mechanism, use btp help target . Get the subaccount ID in BTP and we will know that kyma and cloundfoundry are available in current trial account. btp list accounts/available-environment --subaccount Get details about an environment available for a subaccount btp get accounts/available-environment --subaccount --environment cloudfoundry --service cloudfoundry --plan standard btp get accounts/available-environment --subaccount --environment kyma --service kymaruntime --plan trial Get status running instances. Here we will also get environment ID of running instances. btp list accounts/environment-instance --subaccount Delete a running instance if needed. btp delete accounts/environment-instance --subaccount Create Kyma instance. btp create accounts/environment-instance --subaccount --environment kyma --service kymaruntime --plan trial --parameters '{\"name\": \"\"}' btp get accounts/environment-instance --subaccount Create CloudFoundry instance btp create accounts/environment-instance --subaccount --environment cloudfoundry --service cloudfoundry --plan standard --parameters '{\"instance_name\": \"\"}' btp get accounts/environment-instance --subaccount Log onto CF to create space DEV by providing API endpoint, Email and Password, which are ready in the subaccount overview page. cf login cf create-space DEV","title":"Set up local BTP environment"},{"location":"k8s/demo/cap_on_kyma/#install-homebrew","text":"Refer to installation guide . Set environment variables export HOMEBREW_BREW_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/brew.git\" export HOMEBREW_CORE_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/homebrew-core.git\" export HOMEBREW_BOTTLE_DOMAIN = \"https://mirrors.ustc.edu.cn/homebrew-bottles\" Install Homebrew /bin/bash -c \" $( curl -fsSL https://github.com/Homebrew/install/raw/HEAD/install.sh ) \" Add below in file ~/.zprofile . export HOMEBREW_BREW_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/brew.git\" export HOMEBREW_CORE_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/homebrew-core.git\" export HOMEBREW_BOTTLE_DOMAIN = \"https://mirrors.ustc.edu.cn/homebrew-bottles\" eval \" $( /opt/homebrew/bin/brew shellenv ) \" Make it effected. source ~/.zprofile","title":"Install Homebrew"},{"location":"k8s/demo/cap_on_kyma/#install-kubetcl","text":"The kubectl installation guide curl -LO \"https://dl.k8s.io/release/ $( curl -L -s https://dl.k8s.io/release/stable.txt ) /bin/darwin/arm64/kubectl\" chmod +x ./kubectl sudo mv ./kubectl /usr/local/bin/kubectl sudo chown root: /usr/local/bin/kubectl kubectl version --client Install plugin oidc-login . curl -fsSLO https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-darwin_arm64.tar.gz tar xvf krew-darwin_arm64.tar.gz ./krew-darwin_arm64 install krew Add the $HOME/.krew/bin directory to the PATH environment variable by updating ~/.zprofile . export PATH = $HOME /.krew/bin: $PATH : $PATH Make it effected source ~/.zprofile Run kubectl krew to check the installation. Install/uninstall plugin oidc-login . kubectl krew install oidc-login kubectl krew uninstall oidc-login","title":"Install kubetcl"},{"location":"k8s/demo/cap_on_kyma/#sap-kyma-runtime","text":"In the Overview area of your subaccount open the Link to dashboard link which appears next to the Console URL under the Kyma Environment area. At the top left of the window choose the Clusters Overview drop down and choose your cluster. In the Clusters Overview window choose the Download Kubeconfig for your Kyma runtime to download your KUBECONFIG. Add below to ~/.zprofile to set the kubeconfig to an environment variable. export KUBECONFIG = Make above change effected. source ~/.zprofile chmod 600 Test connection between kubectl and Kyma on BTP. kubectl cluster-info","title":"SAP Kyma runtime"},{"location":"k8s/demo/cap_on_kyma/#install-nodejs","text":"Refer to installation guide brew search node brew install node@16 brew unlink node brew link node@16 node -v","title":"Install Node.js"},{"location":"k8s/demo/cap_on_kyma/#install-sqlite","text":"Install SQLite via brew . brew search sqlite brew install sqlite Add below to ~/.zprofile export PATH = /opt/homebrew/opt/sqlite/bin: $PATH Make it effected source ~/.zprofile","title":"Install SQLite"},{"location":"k8s/demo/cap_on_kyma/#install-xcode","text":"(For macOS) We have to install Command-Line Tools for Xcode , cause some node modules need binary modules (node-gyp). xcode-select --install xcode-select --help","title":"Install Xcode"},{"location":"k8s/demo/cap_on_kyma/#install-git","text":"Refer to installation guide . brew install git git version","title":"Install Git"},{"location":"k8s/demo/cap_on_kyma/#install-sapui5","text":"Install the UI5 CLI. npm search --global @ui5/cli npm install --global @ui5/cli npm list --global @ui5/cli ui5 --version npm search --global grunt-cli npm install --global grunt-cli npm list --global grunt-cli","title":"Install SAPUI5"},{"location":"k8s/demo/cap_on_kyma/#install-cf-cli","text":"Refer to installation guide . brew install cloudfoundry/tap/cf-cli@8 cf --version","title":"Install CF CLI"},{"location":"k8s/demo/cap_on_kyma/#install-cap-tooling","text":"See the details in the CAP documentation . npm search --global @sap/cds-dk npm install --global @sap/cds-dk npm list --global @sap/cds-dk cds --version","title":"Install CAP Tooling"},{"location":"k8s/demo/cap_on_kyma/#install-vscode","text":"In VS Code, invoke the Command Palette ( View \u2192 Command Palette or \u21e7\u2318P) and type shell command to find the Shell Command: Install 'code' command in PATH . Install SAP CDS Language Support extension. Install SAP Fiori tools - Extension Pack extension.","title":"Install VSCode"},{"location":"k8s/demo/cap_on_kyma/#install-yeoman","text":"Yeoman is a tool for scaffolding web apps. You\u2019ll need it if you want to carry out the tutorial Add the SAP Launchpad Service. npm install --global yo yo --version","title":"Install Yeoman"},{"location":"k8s/demo/cap_on_kyma/#install-docker","text":"brew install docker --cask","title":"Install Docker"},{"location":"k8s/demo/cap_on_kyma/#install-helm","text":"Refer to installation guide brew install helm","title":"Install Helm"},{"location":"k8s/demo/cap_on_kyma/#install-paketopack","text":"Refer to installation guide . brew install buildpacks/tap/pack","title":"Install Paketo(pack)"},{"location":"k8s/demo/cap_on_kyma/#install-rancher-desktop","text":"Download the Rancher Desktop installer for macOS from the release page . Refer to installation guide .","title":"Install Rancher Desktop"},{"location":"k8s/demo/cap_on_kyma/#download-tutorial","text":"Go to tutorial root directory and clone the code. git clone https://github.com/SAP-samples/cloud-cap-risk-management tutorial","title":"Download tutorial"},{"location":"k8s/demo/cap_on_kyma/#initialize-the-project","text":"Install required Node.js modules in the app directory cpapp . cd app cds init npm install cds watch","title":"Initialize the project"},{"location":"k8s/demo/cap_on_kyma/#add-files-to-the-project","text":"Copy the file schema.cds from templates/create-cap-application/db to the db folder of the app. It creates two entities in the namespace sap.ui.riskmanagement : Risks and Mitigations . Copy the file risk-service.cds from templates/create-cap-application/srv to the srv folder of the app. It creates a new service RiskService in the namespace sap.ui.riskmanagement . This service exposes two entities: Risks and Mitigations , which are exposing the entities of the database schema we've created in the step before. Copy the folder data from templates/create-cap-application/db to the db folder of the app. There are two comma-separated value (CSV) files that contain local data for both the Risks and the Mitigations entities. Use Fiori Application Generator (VSCode extension) to generate Risk UI with Fiori element template. The generation will create a risks and a webapp folder with a Component.js file in the app folder of the project. Copy the file risks-service-ui.cds from templates/create-ui-fiori-elements/srv to the srv folder of the app. It defines annotations to show a work list with some columns and the data from the service in the Risk UI. Edit app/risks/webapp/manifest.json file to make the header fields editable, that is, shows title and description in Risk UI. Copy the file risk-service.js from templates/cap-business-logic/srv to the srv folder of the app. It now shows the work list in Risk UI with the columns Priority and Impact with color and an icon, depending on the amount in Impact . Use Fiori Application Generator (VSCode extension) to generate Migration UI with Fiori free-style template. The generation will create a migrations and a webapp folder with a Component.js file in the app folder of the project. Update file cpapp/app/mitigations/webapp/view/Worklist.view.xml to show Description , Owner , and Timeline columns, as well as in detail object page. Till now, our risks and mitigations application have been generated by the SAP Fiori Tools Generator and can be started independently. They are launched without a launch page. Copy the file launchpage.html from templates/launchpage/app to the app folder of the app. There are two applications in the launch page with URLs that point to the respective apps. We now see the Mitigations app next to the Risks app on the launch page. Open the file srv/risk-service.cds and add role restrictions to entities. Copy the file templates/cap-roles/.cdsrc.json to the project directory cpapp . The file defines two users risk.viewer@tester.sap.com and risk.manager@tester.sap.com . The default password can be found in the file .cdsrc.json . We will see the CAP server to show above applications via link http://localhost:4004 .","title":"Add files to the project"},{"location":"k8s/demo/cap_on_kyma/#prepare-kyma-development-environment","text":"Execute cds version to make sure the package.json is using @sap/cds 6.0.1 or newer and we have @sap/cds-dk 6.0.1 or newer globally installed. Create namespace on Kyma. kubectl create namespace risk-management Switch to the namespace. kubectl config set-context --current --namespace risk-management Create container registry secret. Copy the folder scripts from templates/Kyma-Prepare-Dev-Environment to the project root folder cpapp . In the root folder cpapp of the project, run the script to create the secret. ./scripts/create-container-registry-secret.sh Need provide below input: docker-server = https://registry-1.docker.io docker-username = docker-email = docker-password = Verify kubectl get secret","title":"Prepare Kyma Development Environment"},{"location":"k8s/demo/cap_on_kyma/#set-up-sap-hana-cloud-for-kyma","text":"Add SAP HANA support to your project. This adds the db module for SAP HANA access to the package.json file. Execute the command below in the project root directory cpapp . cds add hana --for production Verify the access to both CF and Kyma by executing below commands. cf login kubectl cluster-info Create HANA Cloud instance cpapp-db in CloudFoundry DEV namespace. The admin user id is DBADMIN . In the root folder cpapp of the project, execute: ./scripts/create-db-secret.sh cpapp-db Get the host name pattern of the cluster with the following command. Result looks like *.c-.sap.kyma.ondemand.com . kubectl get gateway -n kyma-system kyma-gateway -o jsonpath = '{.spec.servers[0].hosts[0]}' The script will: Create service key cpapp-db-key for HANA Cloud service instance cpapp-db as . Create Kubernetes secret cpapp-db for HANA DB instance. View it using kubectl get secret cpapp-db -o yaml .","title":"Set Up SAP HANA Cloud for Kyma"},{"location":"k8s/demo/cap_on_kyma/#user-authentication-and-authorization-xsuaa-setup","text":"Set up XSUAA. cds add xsuaa --for production Above command will do: Adds the XSUAA service to the package.json file of the project Creates the XSUAA security configuration xs-security.json for the project","title":"User Authentication and Authorization (XSUAA) Setup"},{"location":"k8s/demo/cap_on_kyma/#add-helm-chart","text":"Add Helm Chart. cds add helm Get docker server URL by command: cat ~/.docker/config.json Get the image pull secret for container registry. In the demo, it's container-registry . kubectl get secret Get the host name pattern of the cluster. kubectl get gateway -n kyma-system kyma-gateway -o jsonpath = '{.spec.servers[0].hosts[0]}' Open the file chart/values.yaml : Replace the placeholder with docker server URL https://docker.io/ . Set imagePullSecret with value name: container-registry . Add host name of the cluster without leading *. . Add the binding db pointing to the SAP HANA Cloud instance secret cpapp-db . Point the binding hana of the SAP HANA Cloud instance secret cpapp-db . Add the Authorization and Trust Management service to allow user login.","title":"Add Helm Chart"},{"location":"k8s/demo/cap_on_kyma/#deploy-cap-application-to-kyma","text":"Build docker image. CONTAINER_REGISTRY = https://index.docker.io/v1 CONTAINER_REGISTRY = https://registry-1.docker.io/yuhuihu CONTAINER_REGISTRY = yuhuihu CAP build. cds build --production Build CAP service. pack build $CONTAINER_REGISTRY /cpapp-srv --path gen/srv \\ --buildpack gcr.io/paketo-buildpacks/nodejs \\ --builder paketobuildpacks/builder:base","title":"Deploy CAP Application to Kyma"},{"location":"linux/","text":"Content \u00b6 Memo Linux SRE is online training hosted by Magedu that I am taking part in. SUSE Linux Administration is the learning memo for certificate of SLES Administration. SUSE Enterprise Storage Foundation is the learning memo for certificate of SES Basic Ops and Data Access. Linux SRE SUSE Linux Adminstration SUSE Enterprise Storage Foundation","title":"Index"},{"location":"linux/#content","text":"Memo Linux SRE is online training hosted by Magedu that I am taking part in. SUSE Linux Administration is the learning memo for certificate of SLES Administration. SUSE Enterprise Storage Foundation is the learning memo for certificate of SES Basic Ops and Data Access. Linux SRE SUSE Linux Adminstration SUSE Enterprise Storage Foundation","title":"Content"},{"location":"linux/Administration/01/","text":"Linux File System Overview \u00b6 Linux File System Overview \u00b6 Filesystem Hierarchy Standard (FHS), which is part of the LSB (Linux Standards Base) specifications. The Root directory \"/\". Refers to the highest layer of the file system tree. This root partition is mounted first at system boot. All programs that are run at system startup must be in this partition. The following directories must be in the root partition: /bin - User binaries. \u57fa\u672c\u7a0b\u5e8f Contains executables required when no other file systems are mounted. For example, programs required for system booting, working with files and configuration. /bin/bash - The bash shell /bin/cat - Display file contents /bin/cp - Copy files /bin/dd - Copy files byte-wise /bin/gzip - Compress files /bin/mount - Mount file systems /bin/rm - Delete files /bin/vi - Edit files /sbin - System binaries. \u7cfb\u7edf\u7a0b\u5e8f Contains programs important for system administration. \u5b58\u653e\u7cfb\u7edf\u7ba1\u7406\u7684\u7a0b\u5e8f Typically are intended to be run by the root user and therefore it is not in the regular users path. \u9ed8\u8ba4\u662froot\u7528\u6237\u6709\u6743\u9650\u6267\u884c Some important files: /sbin/yast - Administration tool /sbin/fdisk* - Modifies partitions /sbin/fsck* - File system check \u4e0d\u80fd\u5728\u8fd0\u884c\u7684\u7cfb\u7edf\u4e0a\u9762\u76f4\u63a5\u6267\u884cfsck\uff0c\u635f\u574f\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u9700\u8981umount /sbin/mkfs - Creates file systems /sbin/shutdown - Shuts down the system /dev - Device files Each system hardware component is represented (except network cards, which are kernel modules). \u4ee5\u592a\u7f51\u5361\u662f\u5185\u6838\u6a21\u5757\uff0c\u5176\u4ed6\u786c\u4ef6\u90fd\u4ee5\u8bbe\u5907dev\u7684\u65b9\u5f0f\u5c55\u73b0 Applications read from and write to these files to address hardware components. Two kinds of device files: Character-oriented \u2013 Sequential devices (printer, tape and mouse) \u5b57\u7b26\u8bbe\u5907 Block-oriented \u2013 Hard disks and DVDs \u5757\u8bbe\u5907 Connections to device drivers are implemented in the kernel using channels called major device numbers. \u4e0e\u8bbe\u5907\u9a71\u52a8\u7a0b\u5e8f\u7684\u8fde\u63a5\u901a\u8fc7\u5185\u6838\u4e2d\u79f0\u4e3a\u4e3b\u8bbe\u5907\u53f7\u7684\u901a\u9053\u5b9e\u73b0\u3002 When using ls -l the file size is replaced with the device numbers, such as 8, 0. In the past these files were created manually using the mknod command. Today they are created automatically (by udev) when the devices are discovered by the kernel. Some important device files: Null device: - /dev/null Zero device: - /dev/zero System Console: - /dev/console Virtual Terminal: - /dev/tty1 Serial ports - /dev/ttyS0 Parallel port: - /dev/lp0 Floppy disk drive: - /dev/fd0 Hard drive: - /dev/sda Hard disk partition: - /dev/sda1 CD-ROM drive: - /dev/scd0 /etc - Configuration files Contains system and services configuration files. \u5b58\u653e\u7cfb\u7edf\u548c\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6 Most of these files are ASCII files. \u5927\u90e8\u5206\u90fd\u662fASCII\u6587\u4ef6 Normal users can read most of these by default. This can be a security issue since some of these files contain passwords so it important that these files are only readable by the rootuser. \u666e\u901a\u7528\u6237\u53ef\u4ee5\u9ed8\u8ba4\u8bfb\u53d6\u5176\u4e2d\u7684\u5927\u90e8\u5206\u5185\u5bb9\u3002 \u8fd9\u53ef\u80fd\u662f\u4e00\u4e2a\u5b89\u5168\u95ee\u9898\uff0c\u56e0\u4e3a\u5176\u4e2d\u4e00\u4e9b\u6587\u4ef6\u5305\u542b\u5bc6\u7801\uff0c\u56e0\u6b64\u91cd\u8981\u7684\u662f\u8fd9\u4e9b\u6587\u4ef6\u53ea\u80fd\u7531root\u7528\u6237\u8bfb\u53d6 No executables can be put here according to the FHS, however subdirectories may contain shell scripts. \u6839\u636eFHS\uff0c\u6b64\u5904\u4e0d\u80fd\u653e\u7f6e\u4efb\u4f55\u53ef\u6267\u884c\u6587\u4ef6\uff0c\u4f46\u5b50\u76ee\u5f55\u53ef\u80fd\u5305\u542bshell\u811a\u672c\u3002 Almost every installed service has at least one configuration file in /etc or a subdirectory. \u51e0\u4e4e\u6bcf\u4e2a\u5df2\u5b89\u88c5\u7684\u670d\u52a1\u5728/ etc\u6216\u5b50\u76ee\u5f55\u4e2d\u81f3\u5c11\u6709\u4e00\u4e2a\u914d\u7f6e\u6587\u4ef6\u3002 Some important configuration files: /etc/SuSE-release - Version of installed system /etc/DIR_COLORS - Colors for the ls command /etc/fstab - For file systems to be mounted /etc/profile - Shell login script /etc/passwd - User database, except passwords /etc/shadow - Password and password info /etc/group - Database of user groups /etc/cups/* - For the CUPS printing system (CUPS=Common UNIX Printing System) /etc/hosts - Host names to IP addresses /etc/motd - Message after login /etc/issue - Message before login /etc/sysconfig/* - System configuration files /lib - Libraries. Many programs have common functions they need. The functions can be kept in a shared library. Libraries are called shared objects and end with the .so extension. \u5171\u4eab\u5e93 Libraries in /lib are used by programs in /bin and /sbin . There are additional libraries in subdirectories. Kernel modules are located in /lib/modules . /lib64 - 64-Bit Libraries. Similar to the /lib directory. This is an architecture dependent directory. Some systems support different binary formats and keep different versions of the same shared library. /usr - Contains application programs, graphical interface files, libraries, local programs, documentation and more. /usr means Unix System Resources. Examples: /usr/X11R6/ - X Window System Files /usr/bin/ - Almost all executables /usr/lib/ - Libraries and application directories /usr/local/ - Locally installed programs (i.e. on local system if /usr is mounted from the network). The content is not overwritten by system updates. \u4e0b\u97623\u4e2a\u76ee\u5f55\u5728\u521d\u59cb\u5b89\u88c5\u540e\u662f\u7a7a\u7684 /usr/local/bin - /usr/local/sbin - /usr/local/lib - /usr/sbin/ - System administration programs /usr/share/doc/ - Documentation /usr/src/ - Source code of kernel and programs /usr/src/linux - /usr/share/man/ - Manual pages /opt - Optional Application Directory Where optional or third party applications that are not considered to be \u201cpart of the distribution\u201d store their static files. Applications considered to be \u201cpart of the distribution\u201d are usually installed under /usr/lib/ rather than /opt . At installation a directory is created for each application's files with the name of the application. Example: /opt/novell - /boot - The Boot Directory /boot/grub2 - Contains static boot loader files for GRUB2. (GRUB = Grand Unified Boot Loader) Contains the kernel and initrd file identified with the links vmlinuz and initrd. /root - Administrator's Home Directory The root user's home directory. Not under /home with regular users' home directories. Needs to be in the root partition so that root can always log in with his configured environment. /home - User Directories Every system user has an assigned file area which becomes the current working directory after log in. By default they exist in /home . The files and directories in /home could be in a separate partition or on another computer on the network. The user profile and configuration files are found here: .profile - Private user login script .bashrc - Configuration file for bash .bash_history - Previous commands run in bash /run/media//* - Mount Point for Removable Media SLE 12 creates directories here for mounting removable media. The name depends on the device that is mounted/discovered. Examples: /run/media/media_name/ (Created if labeled media is inserted) /run/media/cdrom/ - /run/media/dvd/ - /run/media/usbdisk/ - /mnt - Temporarily Mounted File Systems \u6587\u4ef6\u7cfb\u7edf\u4e34\u65f6\u6302\u8f7d\u70b9 Standard directory for integrating file systems that are used temporarily. File systems are mounted using the mount command and removed using the umount command. Subdirectories do not exist by default and are not automatically created. /srv - Service Data Directories Contains subdirectories for various services. Examples: \u5b58\u653e\u5404\u79cd\u670d\u52a1\u7684\u6570\u636e /srv/www - for the Apache Web Server /srv/ftp - for an FTP server /var - Variable Files Contains files that can be modified while the system is running. \u5728\u7cfb\u7edf\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u4f1a\u88ab\u4fee\u6539\u7684\u6587\u4ef6 Important subdirectories: /var/lib/ - Variable libraries, like databases \u53ef\u53d8\u5e93\u6587\u4ef6 /var/log/ - Services log files \u65e5\u5fd7\u6587\u4ef6 /var/run/ - Information on running processes \u8fd0\u884c\u4e2d\u7684\u7ebf\u7a0b\u7684\u4fe1\u606f /var/spool/ - Queues (printers, email) /var/spool/mail - /var/spool/cron - /var/lock/ - Lock files for multiuser access /var/cache - /var/mail - /tmp - Temporary Area Where programs create temporary files while they are running /proc - Process Files A virtual file system that exists only in memory and is used to display the current state of processes running on the system. (Takes no space - file size always 0) \u865a\u62df\u6587\u4ef6\u7cfb\u7edf\uff0c\u4e0d\u5360\u95f4\uff0c\u5927\u5c0f* \u59cb\u7ec8\u96f6\uff0c\u663e\u793a\u5f53\u524d\u8fdb\u7a0b\u7684\u72b6\u6001\u4fe1\u606f Directories containing information about individual processes are named according to the PID number of the process. Some values can be modified to change how things are running in real time. Any changes made are lost at reboot. Examples: \u6709\u4e9b\u503c\u53ef\u4ee5\u4e34\u65f6\u5728\u7ebf\u66f4\u6539\u751f\u6548\uff0c\u4f46\u91cd\u542f\u540e\u4e22\u5931 /proc/cpuinfo/ - Processor information /proc/dma/ - Use of DMA ports /proc/interrupts/ - Use of interrupts /proc/ioports/ - Use of I/O ports /proc/filesystems/ - File system formats the kernel knows /proc/modules/ - Active modules /proc/mounts/ - Mounted file systems /proc/net/* - Network information and statistics /proc/partitions/ - Existing partitions /proc/bus/pci/ - Connected PCI devices /proc/bus/scsi/ - Connected SCSI devices /proc/sys/* - System and kernel information /proc/version - Kernel version /sys - System Information Directory A virtual file system that exists only in memory. Takes no space so file size always 0 \u865a\u62df\u6587\u4ef6\u7cfb\u7edf Provides information on: hardware buses hardware devices active devices drivers Lab: Explore Filesystem Hierarchy \u00b6 Show the directory structure of the /data folder hierarchy of current logon user: mySUSE:~ # tree /data /data \u2514\u2500\u2500 linktype \u251c\u2500\u2500 file \u251c\u2500\u2500 hardlinkfile1 \u251c\u2500\u2500 hardlinkfile2 \u251c\u2500\u2500 symlinkfile1 -> file \u251c\u2500\u2500 symlinkfile1-1 -> symlinkfile1 \u2514\u2500\u2500 symlinkfile2 -> file Show only directories in the /data hierarchhy, not the files in them: mySUSE:~ # tree -d /data /data \u2514\u2500\u2500 linktype Show the files and directories in the /data hierarchy, including the full path and filename of each object. mySUSE:~ # tree -f /data /data \u2514\u2500\u2500 /data/linktype \u251c\u2500\u2500 /data/linktype/file \u251c\u2500\u2500 /data/linktype/hardlinkfile1 \u251c\u2500\u2500 /data/linktype/hardlinkfile2 \u251c\u2500\u2500 /data/linktype/symlinkfile1 -> file \u251c\u2500\u2500 /data/linktype/symlinkfile1-1 -> symlinkfile1 \u2514\u2500\u2500 /data/linktype/symlinkfile2 -> file Seven Different types of files \u00b6 Normal files , examples: ASCII text files Executable files Graphics files Directories Organize files on the disk Contain files and subdirectories Implement the hierarchical file system Links Hard links Secondary file names for files on the disk Multiple file names referencing a single inode Referenced file must reside in the same file system Symbolic links: References to other files on the disk The inode contains a reference to another file name .Referenced files can exist in the same file system or in other file systems A symbolic link can reference a non-existent file (broken link) Sockets - Used for two-way communication between processes. \u5957\u63a5\u5b57 Pipes (FIFOs) - Used for one-way communication from one process to another. \u7ba1\u9053 Block Devices \u5757\u8bbe\u5907 Character Devices \u5b57\u7b26\u8bbe\u5907 Linux Link Type \u00b6 Hard links : A hard link is a directory reference, or pointer, to a file on a storage volume. The name associated with the file is a label stored in a directory structure that refers the operating system to the file data. As such, more than one name can be associated with the same file. When accessed through different names, any changes made will affect the same file data. \u786c\u94fe\u63a5\u662f\u5b58\u50a8\u5377\u4e0a\u6587\u4ef6\u7684\u76ee\u5f55\u5f15\u7528\u6216\u6307\u9488\u3002 \u6587\u4ef6\u540d\u662f\u5b58\u50a8\u5728\u76ee\u5f55\u7ed3\u6784\u4e2d\u7684\u6807\u7b7e\uff0c\u76ee\u5f55\u7ed3\u6784\u6307\u5411\u6587\u4ef6\u6570\u636e\u3002 \u56e0\u6b64\uff0c\u53ef\u4ee5\u5c06\u591a\u4e2a\u6587\u4ef6\u540d\u4e0e\u540c\u4e00\u6587\u4ef6\u5173\u8054\u3002 \u901a\u8fc7\u4e0d\u540c\u7684\u6587\u4ef6\u540d\u8bbf\u95ee\u65f6\uff0c\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u662f\u9488\u5bf9\u6e90\u6587\u4ef6\u6570\u636e\u3002 Symbolic links : A symbolic link contains a text string that is interpreted and followed by the operating system as a path to another file or directory. It is a file on its own and can exist independently of its target. If a symbolic link is deleted, its target remains unaffected. If the target is moved, renamed or deleted, any symbolic link that used to point to it continues to exist but now points to a non-existing file. \u7b26\u53f7\u94fe\u63a5\u5305\u542b\u4e00\u4e2a\u6587\u672c\u5b57\u7b26\u4e32\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5c06\u5176\u89e3\u91ca\u5e76\u4f5c\u4e3a\u53e6\u4e00\u4e2a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u8def\u5f84\u3002 \u5b83\u672c\u8eab\u5c31\u662f\u4e00\u4e2a\u6587\u4ef6\uff0c\u53ef\u4ee5\u72ec\u7acb\u4e8e\u76ee\u6807\u800c\u5b58\u5728\u3002 \u5982\u679c\u5220\u9664\u4e86\u7b26\u53f7\u94fe\u63a5\uff0c\u5219\u5176\u76ee\u6807\u4e0d\u53d7\u5f71\u54cd\u3002 \u5982\u679c\u79fb\u52a8\uff0c\u91cd\u547d\u540d\u6216\u5220\u9664\u76ee\u6807\uff0c\u5219\u7528\u4e8e\u6307\u5411\u5b83\u7684\u4efb\u4f55\u7b26\u53f7\u94fe\u63a5\u5c06\u7ee7\u7eed\u5b58\u5728\uff0c\u4f46\u73b0\u5728\u6307\u5411\u4e0d\u5b58\u5728\u7684\u6587\u4ef6\u3002 Hard links can only be used when both the file and the link are in the same file system (on the same partition), because inode numbers are only unique within the same file system. You create a hard link by using the ln command, which points to the inode of an already existing file. Thereafter, the file can be accessed under both names\u2013that of the file and that of the link, and you can no longer discern which name existed first or how the original file and the link differ. \u4ec5\u5f53\u6587\u4ef6\u548c\u94fe\u63a5\u6587\u4ef6\u4f4d\u4e8e\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\uff08\u5728\u540c\u4e00\u5206\u533a\u4e0a\uff09\u65f6\uff0c\u624d\u80fd\u4f7f\u7528\u786c\u94fe\u63a5\uff0c\u56e0\u4e3ainode\u7f16\u53f7\u5728\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\u4e2d\u4ec5\u662f\u552f\u4e00\u7684\u3002 \u60a8\u53ef\u4ee5\u4f7f\u7528ln\u547d\u4ee4\u521b\u5efa\u786c\u94fe\u63a5\uff0c\u8be5\u547d\u4ee4\u6307\u5411\u5df2\u5b58\u5728\u6587\u4ef6\u7684inode\u3002 \u6b64\u540e\uff0c\u53ef\u4ee5\u5728\u6587\u4ef6\u7684\u540d\u79f0\u548c\u94fe\u63a5\u7684\u540d\u79f0\u4e0b\u8bbf\u95ee\u6587\u4ef6\uff0c\u5e76\u4e14\u65e0\u6cd5\u518d\u8bc6\u522b\u9996\u5148\u5b58\u5728\u7684\u540d\u79f0\u6216\u539f\u59cb\u6587\u4ef6\u548c\u94fe\u63a5\u7684\u4e0d\u540c\u4e4b\u5904\u3002 You can create a symbolic link with the ln command and the -s option. A symbolic link is assigned its own inode\u2014the link refers to a file, so a distinction can always be made between the link and the actual file. \u8f6f\u8fde\u63a5\u53ef\u4ee5\u9488\u5bf9\u76ee\u5f55\uff0c\u786c\u8fde\u63a5\u53ea\u80fd\u9488\u5bf9\u6587\u4ef6\u3002 A file system is essentially a database that is used to keep track of files in a volume. For normal files, data blocks are allocated to store the file's data, an inode is allocated to point to the data blocks as well as store the metadata about the file and then a file name is assigned to the inode. A hard link is a secondary file name associated with an existing inode. For symbolic links, a new inode is allocated with a new file name associated with it but the inode references another file name rather than referencing datablocks. \u6587\u4ef6\u7cfb\u7edf\u672c\u8d28\u4e0a\u662f\u4e00\u4e2a\u7528\u4e8e\u8ddf\u8e2a\u5377\u4e2d\u6587\u4ef6\u7684\u6570\u636e\u5e93\u3002 \u5bf9\u4e8e\u666e\u901a\u6587\u4ef6\uff0c\u5206\u914d\u6570\u636e\u5757\u4ee5\u5b58\u50a8\u6587\u4ef6\u7684\u6570\u636e\uff0c\u5206\u914dinode\u4ee5\u6307\u5411\u6570\u636e\u5757\u4ee5\u53ca\u5b58\u50a8\u5173\u4e8e\u6587\u4ef6\u7684\u5143\u6570\u636e\uff0c\u7136\u540e\u5c06\u6587\u4ef6\u540d\u5206\u914d\u7ed9inode\u3002 \u786c\u94fe\u63a5\u662f\u4e0e\u73b0\u6709inode\u5173\u8054\u7684\u8f85\u52a9\u6587\u4ef6\u540d\u3002 \u5bf9\u4e8e\u7b26\u53f7\u94fe\u63a5\uff0c\u5c06\u4e3a\u65b0\u7684inode\u5206\u914d\u4e00\u4e2a\u4e0e\u4e4b\u5173\u8054\u7684\u65b0\u6587\u4ef6\u540d\uff0c\u4f46inode\u5f15\u7528\u53e6\u4e00\u4e2a\u6587\u4ef6\u540d\u800c\u4e0d\u662f\u5f15\u7528\u6570\u636e\u5757\u3002 A good way to see the relationship between file names and inodes is to use the ls -il command. The typical size of an inode is 128 Bit and data blocks can range in size from 1k, 2k, 4k or larger depending on the file system type. \u67e5\u770b\u6587\u4ef6\u540d\u548cinode\u4e4b\u95f4\u5173\u7cfb\u7684\u597d\u65b9\u6cd5\u662f\u4f7f\u7528ls -il\u547d\u4ee4\u3002inode\u7684\u5178\u578b\u5927\u5c0f\u4e3a128\u4f4d\uff0c\u6570\u636e\u5757\u7684\u5927\u5c0f\u8303\u56f4\u53ef\u4ee5\u662f1k\uff0c2k\uff0c4k\u6216\u66f4\u5927\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u3002 \u786c\u94fe\u63a5\u76f8\u5f53\u4e8e\u589e\u52a0\u4e86\u4e00\u4e2a\u767b\u8bb0\u9879\uff0c\u4f7f\u5f97\u539f\u6765\u7684\u6587\u4ef6\u591a\u4e86\u4e00\u4e2a\u540d\u5b57\uff0c\u81f3\u4e8einode\u90fd\u6ca1\u53d8\u3002\u6240\u8c13\u7684\u767b\u8bb0\u9879\u5176\u5b9e\u662f\u76ee\u5f55\u6587\u4ef6\u4e2d\u7684\u4e00\u4e2a\u6761\u76ee(\u76ee\u5f55\u9879)\uff0c\u4f7f\u7528hard link \u662f\u8ba9\u591a\u4e2a\u4e0d\u540c\u7684\u76ee\u5f55\u9879\u6307\u5411\u540c\u4e00\u4e2a\u6587\u4ef6\u7684inode\uff0c\u6ca1\u6709\u591a\u4f59\u7684\u5185\u5bb9\u9700\u8981\u5b58\u50a8\u5728\u78c1\u76d8\u6247\u533a\u4e2d\uff0c\u6240\u4ee5hardlink\u4e0d\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 \u7b26\u53f7\u94fe\u63a5\u6709\u5355\u72ec\u7684inode\uff0c\u5728inode\u4e2d\u5b58\u653e\u53e6\u4e00\u4e2a\u6587\u4ef6\u7684\u8def\u5f84\u800c\u4e0d\u662f\u6587\u4ef6\u6570\u636e\uff0c\u6240\u4ee5\u7b26\u53f7\u94fe\u63a5\u4f1a\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 Lab: File Link Type \u00b6 Create original file mySUSE:/data/linktype # echo \"it's original file\" > file mySUSE:/data/linktype # l -rw-r--r-- 1 root root 19 Mar 28 15 :20 file Create hardlink file (\u6ce8\u610ffile\u3001hardlinkfile1\u3001hardlinkfile2\u7684link\u4f4d\u7f6e\u7684\u6570\u503c\u7684\u53d8\u5316[\u7ea2\u8272]) mySUSE:/data/linktype # ln file hardlinkfile1 mySUSE:/data/linktype # ln -s file symlinkfile1 mySUSE:/data/linktype # ln -s file symlinkfile2 mySUSE:/data/linktype # l -rw-r--r-- 2 root root 19 Mar 28 15 :20 file -rw-r--r-- 2 root root 19 Mar 28 15 :20 hardlinkfile1 lrwxrwxrwx 1 root root 4 Mar 28 15 :21 symlinkfile1 -> file lrwxrwxrwx 1 root root 4 Mar 28 15 :23 symlinkfile2 -> file mySUSE:/data/linktype # ln file hardlinkfile2 mySUSE:/data/linktype # l -rw-r--r-- 3 root root 19 Mar 28 15 :20 file ( \u5305\u62ec\u81ea\u5df1\uff0c\u4e00\u5171\u67093\u4e2a\u786c\u94fe\u63a5 ) -rw-r--r-- 3 root root 19 Mar 28 15 :20 hardlinkfile1 ( \u7ee7\u627f\u4e86\u539f\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u91cf ) -rw-r--r-- 3 root root 19 Mar 28 15 :20 hardlinkfile2 ( \u7ee7\u627f\u4e86\u539f\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u91cf ) lrwxrwxrwx 1 root root 4 Mar 28 15 :21 symlinkfile1 -> file lrwxrwxrwx 1 root root 4 Mar 28 15 :23 symlinkfile2 -> file Modify content of file (original file). Content change were shown in all hard/soft link files mySUSE:/data/linktype # echo \"add oneline\" >> file mySUSE:/data/linktype # cat file it 's original file add oneline mySUSE:/data/linktype # cat hardlinkfile1 it' s original file add oneline mySUSE:/data/linktype # cat hardlinkfile2 it 's original file add oneline mySUSE:/data/linktype # cat symlinkfile1 it' s original file add oneline mySUSE:/data/linktype # cat symlinkfile2 it ' s original file add oneline To view the value stored in a symbolic link use the command readlink. mySUSE:/data/linktype # ln -s symlinkfile1 symlinkfile1-1 mySUSE:/data/linktype # ls -il 258 -rw-r--r-- 3 root root 31 Mar 28 15 :42 file 258 -rw-r--r-- 3 root root 31 Mar 28 15 :42 hardlinkfile1 258 -rw-r--r-- 3 root root 31 Mar 28 15 :42 hardlinkfile2 259 lrwxrwxrwx 1 root root 4 Mar 28 15 :21 symlinkfile1 -> file 265 lrwxrwxrwx 1 root root 12 Mar 28 15 :49 symlinkfile1-1 -> symlinkfile1 260 lrwxrwxrwx 1 root root 4 Mar 28 15 :23 symlinkfile2 -> file mySUSE:/data/linktype # readlink symlinkfile1 file mySUSE:/data/linktype # readlink symlinkfile2 file mySUSE:/data/linktype # readlink symlinkfile1-1 symlinkfile1 ( \u6ce8\u610f\uff1a\u8fd9\u4ecd\u7136\u662f\u4e00\u4e2a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6 ) mySUSE:/data/linktype # readlink -f symlinkfile1-1(\u53c2\u6570-f\u53ef\u4ee5\u76f4\u63a5\u5b9a\u4f4d\u771f\u6b63\u7684\u6e90\u6587\u4ef6) /data/linktype/file ( \u6ce8\u610f\uff1a\u8fd9\u624d\u662f\u771f\u6b63\u7684\u539f\u6587\u4ef6 ) Linux Device File \u00b6 Represent hardware (except network cards). Each piece of hardware is represented by a device file. Network cards are interfaces. (\u533a\u522b) Link between hardware devices and the kernel drivers \u8bbe\u5907\u6587\u4ef6\u628a\u5185\u6838\u9a71\u52a8\u548c\u7269\u7406\u786c\u4ef6\u8bbe\u5907\u8fde\u63a5\u8d77\u6765 Kernel drivers read from and write to the device file \u5185\u6838\u9a71\u52a8\u7a0b\u5e8f\u5bf9\u8bbe\u5907\u6587\u4ef6\u8fdb\u884c\u8bfb\u5199\u6765\u5b9e\u73b0\u5bf9\u786c\u4ef6\u7684\u8bfb\u5199 The kernel gets the data to the actual hardware in the correct format \u5185\u6838\u4ee5\u6b63\u786e\u7684\u683c\u5f0f\u5bf9\u7269\u7406\u8bbe\u5907\u8fdb\u884c\u8bfb\u5199 Types: Block Devices. A block device reads/writes information in (normally) 512 byte large blocks. Character Devices. A character device reads/writes information character wise. Character devices provide unbuffered access directly to a hardware device. \u76f4\u63a5\u8bfb\u5199\uff0c\u4e0d\u901a\u8fc7\u7f13\u5b58 Sometimes referred to as raw devices. \u88f8\u8bbe\u5907\uff08\u6ce8\u610f\uff1a\u88f8\u8bbe\u5907\u88ab\u89c6\u4e3a\u5b57\u7b26\u8bbe\u5907\uff0c\u4e0d\u662f\u5757\u8bbe\u5907\uff09 any different options for character devices, making their use and application wide and varied. Created automatically by the OS (udev) when the device is discovered by the kernel. \u5185\u6838\u76f4\u63a5\u521b\u5efa\u5bf9\u5e94\u786c\u4ef6\u7684\u8bbe\u5907\u6587\u4ef6","title":"Linux File System Overview"},{"location":"linux/Administration/01/#linux-file-system-overview","text":"","title":"Linux File System Overview"},{"location":"linux/Administration/01/#linux-file-system-overview_1","text":"Filesystem Hierarchy Standard (FHS), which is part of the LSB (Linux Standards Base) specifications. The Root directory \"/\". Refers to the highest layer of the file system tree. This root partition is mounted first at system boot. All programs that are run at system startup must be in this partition. The following directories must be in the root partition: /bin - User binaries. \u57fa\u672c\u7a0b\u5e8f Contains executables required when no other file systems are mounted. For example, programs required for system booting, working with files and configuration. /bin/bash - The bash shell /bin/cat - Display file contents /bin/cp - Copy files /bin/dd - Copy files byte-wise /bin/gzip - Compress files /bin/mount - Mount file systems /bin/rm - Delete files /bin/vi - Edit files /sbin - System binaries. \u7cfb\u7edf\u7a0b\u5e8f Contains programs important for system administration. \u5b58\u653e\u7cfb\u7edf\u7ba1\u7406\u7684\u7a0b\u5e8f Typically are intended to be run by the root user and therefore it is not in the regular users path. \u9ed8\u8ba4\u662froot\u7528\u6237\u6709\u6743\u9650\u6267\u884c Some important files: /sbin/yast - Administration tool /sbin/fdisk* - Modifies partitions /sbin/fsck* - File system check \u4e0d\u80fd\u5728\u8fd0\u884c\u7684\u7cfb\u7edf\u4e0a\u9762\u76f4\u63a5\u6267\u884cfsck\uff0c\u635f\u574f\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u9700\u8981umount /sbin/mkfs - Creates file systems /sbin/shutdown - Shuts down the system /dev - Device files Each system hardware component is represented (except network cards, which are kernel modules). \u4ee5\u592a\u7f51\u5361\u662f\u5185\u6838\u6a21\u5757\uff0c\u5176\u4ed6\u786c\u4ef6\u90fd\u4ee5\u8bbe\u5907dev\u7684\u65b9\u5f0f\u5c55\u73b0 Applications read from and write to these files to address hardware components. Two kinds of device files: Character-oriented \u2013 Sequential devices (printer, tape and mouse) \u5b57\u7b26\u8bbe\u5907 Block-oriented \u2013 Hard disks and DVDs \u5757\u8bbe\u5907 Connections to device drivers are implemented in the kernel using channels called major device numbers. \u4e0e\u8bbe\u5907\u9a71\u52a8\u7a0b\u5e8f\u7684\u8fde\u63a5\u901a\u8fc7\u5185\u6838\u4e2d\u79f0\u4e3a\u4e3b\u8bbe\u5907\u53f7\u7684\u901a\u9053\u5b9e\u73b0\u3002 When using ls -l the file size is replaced with the device numbers, such as 8, 0. In the past these files were created manually using the mknod command. Today they are created automatically (by udev) when the devices are discovered by the kernel. Some important device files: Null device: - /dev/null Zero device: - /dev/zero System Console: - /dev/console Virtual Terminal: - /dev/tty1 Serial ports - /dev/ttyS0 Parallel port: - /dev/lp0 Floppy disk drive: - /dev/fd0 Hard drive: - /dev/sda Hard disk partition: - /dev/sda1 CD-ROM drive: - /dev/scd0 /etc - Configuration files Contains system and services configuration files. \u5b58\u653e\u7cfb\u7edf\u548c\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6 Most of these files are ASCII files. \u5927\u90e8\u5206\u90fd\u662fASCII\u6587\u4ef6 Normal users can read most of these by default. This can be a security issue since some of these files contain passwords so it important that these files are only readable by the rootuser. \u666e\u901a\u7528\u6237\u53ef\u4ee5\u9ed8\u8ba4\u8bfb\u53d6\u5176\u4e2d\u7684\u5927\u90e8\u5206\u5185\u5bb9\u3002 \u8fd9\u53ef\u80fd\u662f\u4e00\u4e2a\u5b89\u5168\u95ee\u9898\uff0c\u56e0\u4e3a\u5176\u4e2d\u4e00\u4e9b\u6587\u4ef6\u5305\u542b\u5bc6\u7801\uff0c\u56e0\u6b64\u91cd\u8981\u7684\u662f\u8fd9\u4e9b\u6587\u4ef6\u53ea\u80fd\u7531root\u7528\u6237\u8bfb\u53d6 No executables can be put here according to the FHS, however subdirectories may contain shell scripts. \u6839\u636eFHS\uff0c\u6b64\u5904\u4e0d\u80fd\u653e\u7f6e\u4efb\u4f55\u53ef\u6267\u884c\u6587\u4ef6\uff0c\u4f46\u5b50\u76ee\u5f55\u53ef\u80fd\u5305\u542bshell\u811a\u672c\u3002 Almost every installed service has at least one configuration file in /etc or a subdirectory. \u51e0\u4e4e\u6bcf\u4e2a\u5df2\u5b89\u88c5\u7684\u670d\u52a1\u5728/ etc\u6216\u5b50\u76ee\u5f55\u4e2d\u81f3\u5c11\u6709\u4e00\u4e2a\u914d\u7f6e\u6587\u4ef6\u3002 Some important configuration files: /etc/SuSE-release - Version of installed system /etc/DIR_COLORS - Colors for the ls command /etc/fstab - For file systems to be mounted /etc/profile - Shell login script /etc/passwd - User database, except passwords /etc/shadow - Password and password info /etc/group - Database of user groups /etc/cups/* - For the CUPS printing system (CUPS=Common UNIX Printing System) /etc/hosts - Host names to IP addresses /etc/motd - Message after login /etc/issue - Message before login /etc/sysconfig/* - System configuration files /lib - Libraries. Many programs have common functions they need. The functions can be kept in a shared library. Libraries are called shared objects and end with the .so extension. \u5171\u4eab\u5e93 Libraries in /lib are used by programs in /bin and /sbin . There are additional libraries in subdirectories. Kernel modules are located in /lib/modules . /lib64 - 64-Bit Libraries. Similar to the /lib directory. This is an architecture dependent directory. Some systems support different binary formats and keep different versions of the same shared library. /usr - Contains application programs, graphical interface files, libraries, local programs, documentation and more. /usr means Unix System Resources. Examples: /usr/X11R6/ - X Window System Files /usr/bin/ - Almost all executables /usr/lib/ - Libraries and application directories /usr/local/ - Locally installed programs (i.e. on local system if /usr is mounted from the network). The content is not overwritten by system updates. \u4e0b\u97623\u4e2a\u76ee\u5f55\u5728\u521d\u59cb\u5b89\u88c5\u540e\u662f\u7a7a\u7684 /usr/local/bin - /usr/local/sbin - /usr/local/lib - /usr/sbin/ - System administration programs /usr/share/doc/ - Documentation /usr/src/ - Source code of kernel and programs /usr/src/linux - /usr/share/man/ - Manual pages /opt - Optional Application Directory Where optional or third party applications that are not considered to be \u201cpart of the distribution\u201d store their static files. Applications considered to be \u201cpart of the distribution\u201d are usually installed under /usr/lib/ rather than /opt . At installation a directory is created for each application's files with the name of the application. Example: /opt/novell - /boot - The Boot Directory /boot/grub2 - Contains static boot loader files for GRUB2. (GRUB = Grand Unified Boot Loader) Contains the kernel and initrd file identified with the links vmlinuz and initrd. /root - Administrator's Home Directory The root user's home directory. Not under /home with regular users' home directories. Needs to be in the root partition so that root can always log in with his configured environment. /home - User Directories Every system user has an assigned file area which becomes the current working directory after log in. By default they exist in /home . The files and directories in /home could be in a separate partition or on another computer on the network. The user profile and configuration files are found here: .profile - Private user login script .bashrc - Configuration file for bash .bash_history - Previous commands run in bash /run/media//* - Mount Point for Removable Media SLE 12 creates directories here for mounting removable media. The name depends on the device that is mounted/discovered. Examples: /run/media/media_name/ (Created if labeled media is inserted) /run/media/cdrom/ - /run/media/dvd/ - /run/media/usbdisk/ - /mnt - Temporarily Mounted File Systems \u6587\u4ef6\u7cfb\u7edf\u4e34\u65f6\u6302\u8f7d\u70b9 Standard directory for integrating file systems that are used temporarily. File systems are mounted using the mount command and removed using the umount command. Subdirectories do not exist by default and are not automatically created. /srv - Service Data Directories Contains subdirectories for various services. Examples: \u5b58\u653e\u5404\u79cd\u670d\u52a1\u7684\u6570\u636e /srv/www - for the Apache Web Server /srv/ftp - for an FTP server /var - Variable Files Contains files that can be modified while the system is running. \u5728\u7cfb\u7edf\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u4f1a\u88ab\u4fee\u6539\u7684\u6587\u4ef6 Important subdirectories: /var/lib/ - Variable libraries, like databases \u53ef\u53d8\u5e93\u6587\u4ef6 /var/log/ - Services log files \u65e5\u5fd7\u6587\u4ef6 /var/run/ - Information on running processes \u8fd0\u884c\u4e2d\u7684\u7ebf\u7a0b\u7684\u4fe1\u606f /var/spool/ - Queues (printers, email) /var/spool/mail - /var/spool/cron - /var/lock/ - Lock files for multiuser access /var/cache - /var/mail - /tmp - Temporary Area Where programs create temporary files while they are running /proc - Process Files A virtual file system that exists only in memory and is used to display the current state of processes running on the system. (Takes no space - file size always 0) \u865a\u62df\u6587\u4ef6\u7cfb\u7edf\uff0c\u4e0d\u5360\u95f4\uff0c\u5927\u5c0f* \u59cb\u7ec8\u96f6\uff0c\u663e\u793a\u5f53\u524d\u8fdb\u7a0b\u7684\u72b6\u6001\u4fe1\u606f Directories containing information about individual processes are named according to the PID number of the process. Some values can be modified to change how things are running in real time. Any changes made are lost at reboot. Examples: \u6709\u4e9b\u503c\u53ef\u4ee5\u4e34\u65f6\u5728\u7ebf\u66f4\u6539\u751f\u6548\uff0c\u4f46\u91cd\u542f\u540e\u4e22\u5931 /proc/cpuinfo/ - Processor information /proc/dma/ - Use of DMA ports /proc/interrupts/ - Use of interrupts /proc/ioports/ - Use of I/O ports /proc/filesystems/ - File system formats the kernel knows /proc/modules/ - Active modules /proc/mounts/ - Mounted file systems /proc/net/* - Network information and statistics /proc/partitions/ - Existing partitions /proc/bus/pci/ - Connected PCI devices /proc/bus/scsi/ - Connected SCSI devices /proc/sys/* - System and kernel information /proc/version - Kernel version /sys - System Information Directory A virtual file system that exists only in memory. Takes no space so file size always 0 \u865a\u62df\u6587\u4ef6\u7cfb\u7edf Provides information on: hardware buses hardware devices active devices drivers","title":"Linux File System Overview"},{"location":"linux/Administration/01/#lab-explore-filesystem-hierarchy","text":"Show the directory structure of the /data folder hierarchy of current logon user: mySUSE:~ # tree /data /data \u2514\u2500\u2500 linktype \u251c\u2500\u2500 file \u251c\u2500\u2500 hardlinkfile1 \u251c\u2500\u2500 hardlinkfile2 \u251c\u2500\u2500 symlinkfile1 -> file \u251c\u2500\u2500 symlinkfile1-1 -> symlinkfile1 \u2514\u2500\u2500 symlinkfile2 -> file Show only directories in the /data hierarchhy, not the files in them: mySUSE:~ # tree -d /data /data \u2514\u2500\u2500 linktype Show the files and directories in the /data hierarchy, including the full path and filename of each object. mySUSE:~ # tree -f /data /data \u2514\u2500\u2500 /data/linktype \u251c\u2500\u2500 /data/linktype/file \u251c\u2500\u2500 /data/linktype/hardlinkfile1 \u251c\u2500\u2500 /data/linktype/hardlinkfile2 \u251c\u2500\u2500 /data/linktype/symlinkfile1 -> file \u251c\u2500\u2500 /data/linktype/symlinkfile1-1 -> symlinkfile1 \u2514\u2500\u2500 /data/linktype/symlinkfile2 -> file","title":"Lab: Explore Filesystem Hierarchy"},{"location":"linux/Administration/01/#seven-different-types-of-files","text":"Normal files , examples: ASCII text files Executable files Graphics files Directories Organize files on the disk Contain files and subdirectories Implement the hierarchical file system Links Hard links Secondary file names for files on the disk Multiple file names referencing a single inode Referenced file must reside in the same file system Symbolic links: References to other files on the disk The inode contains a reference to another file name .Referenced files can exist in the same file system or in other file systems A symbolic link can reference a non-existent file (broken link) Sockets - Used for two-way communication between processes. \u5957\u63a5\u5b57 Pipes (FIFOs) - Used for one-way communication from one process to another. \u7ba1\u9053 Block Devices \u5757\u8bbe\u5907 Character Devices \u5b57\u7b26\u8bbe\u5907","title":"Seven Different types of files"},{"location":"linux/Administration/01/#linux-link-type","text":"Hard links : A hard link is a directory reference, or pointer, to a file on a storage volume. The name associated with the file is a label stored in a directory structure that refers the operating system to the file data. As such, more than one name can be associated with the same file. When accessed through different names, any changes made will affect the same file data. \u786c\u94fe\u63a5\u662f\u5b58\u50a8\u5377\u4e0a\u6587\u4ef6\u7684\u76ee\u5f55\u5f15\u7528\u6216\u6307\u9488\u3002 \u6587\u4ef6\u540d\u662f\u5b58\u50a8\u5728\u76ee\u5f55\u7ed3\u6784\u4e2d\u7684\u6807\u7b7e\uff0c\u76ee\u5f55\u7ed3\u6784\u6307\u5411\u6587\u4ef6\u6570\u636e\u3002 \u56e0\u6b64\uff0c\u53ef\u4ee5\u5c06\u591a\u4e2a\u6587\u4ef6\u540d\u4e0e\u540c\u4e00\u6587\u4ef6\u5173\u8054\u3002 \u901a\u8fc7\u4e0d\u540c\u7684\u6587\u4ef6\u540d\u8bbf\u95ee\u65f6\uff0c\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u662f\u9488\u5bf9\u6e90\u6587\u4ef6\u6570\u636e\u3002 Symbolic links : A symbolic link contains a text string that is interpreted and followed by the operating system as a path to another file or directory. It is a file on its own and can exist independently of its target. If a symbolic link is deleted, its target remains unaffected. If the target is moved, renamed or deleted, any symbolic link that used to point to it continues to exist but now points to a non-existing file. \u7b26\u53f7\u94fe\u63a5\u5305\u542b\u4e00\u4e2a\u6587\u672c\u5b57\u7b26\u4e32\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5c06\u5176\u89e3\u91ca\u5e76\u4f5c\u4e3a\u53e6\u4e00\u4e2a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u8def\u5f84\u3002 \u5b83\u672c\u8eab\u5c31\u662f\u4e00\u4e2a\u6587\u4ef6\uff0c\u53ef\u4ee5\u72ec\u7acb\u4e8e\u76ee\u6807\u800c\u5b58\u5728\u3002 \u5982\u679c\u5220\u9664\u4e86\u7b26\u53f7\u94fe\u63a5\uff0c\u5219\u5176\u76ee\u6807\u4e0d\u53d7\u5f71\u54cd\u3002 \u5982\u679c\u79fb\u52a8\uff0c\u91cd\u547d\u540d\u6216\u5220\u9664\u76ee\u6807\uff0c\u5219\u7528\u4e8e\u6307\u5411\u5b83\u7684\u4efb\u4f55\u7b26\u53f7\u94fe\u63a5\u5c06\u7ee7\u7eed\u5b58\u5728\uff0c\u4f46\u73b0\u5728\u6307\u5411\u4e0d\u5b58\u5728\u7684\u6587\u4ef6\u3002 Hard links can only be used when both the file and the link are in the same file system (on the same partition), because inode numbers are only unique within the same file system. You create a hard link by using the ln command, which points to the inode of an already existing file. Thereafter, the file can be accessed under both names\u2013that of the file and that of the link, and you can no longer discern which name existed first or how the original file and the link differ. \u4ec5\u5f53\u6587\u4ef6\u548c\u94fe\u63a5\u6587\u4ef6\u4f4d\u4e8e\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\uff08\u5728\u540c\u4e00\u5206\u533a\u4e0a\uff09\u65f6\uff0c\u624d\u80fd\u4f7f\u7528\u786c\u94fe\u63a5\uff0c\u56e0\u4e3ainode\u7f16\u53f7\u5728\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\u4e2d\u4ec5\u662f\u552f\u4e00\u7684\u3002 \u60a8\u53ef\u4ee5\u4f7f\u7528ln\u547d\u4ee4\u521b\u5efa\u786c\u94fe\u63a5\uff0c\u8be5\u547d\u4ee4\u6307\u5411\u5df2\u5b58\u5728\u6587\u4ef6\u7684inode\u3002 \u6b64\u540e\uff0c\u53ef\u4ee5\u5728\u6587\u4ef6\u7684\u540d\u79f0\u548c\u94fe\u63a5\u7684\u540d\u79f0\u4e0b\u8bbf\u95ee\u6587\u4ef6\uff0c\u5e76\u4e14\u65e0\u6cd5\u518d\u8bc6\u522b\u9996\u5148\u5b58\u5728\u7684\u540d\u79f0\u6216\u539f\u59cb\u6587\u4ef6\u548c\u94fe\u63a5\u7684\u4e0d\u540c\u4e4b\u5904\u3002 You can create a symbolic link with the ln command and the -s option. A symbolic link is assigned its own inode\u2014the link refers to a file, so a distinction can always be made between the link and the actual file. \u8f6f\u8fde\u63a5\u53ef\u4ee5\u9488\u5bf9\u76ee\u5f55\uff0c\u786c\u8fde\u63a5\u53ea\u80fd\u9488\u5bf9\u6587\u4ef6\u3002 A file system is essentially a database that is used to keep track of files in a volume. For normal files, data blocks are allocated to store the file's data, an inode is allocated to point to the data blocks as well as store the metadata about the file and then a file name is assigned to the inode. A hard link is a secondary file name associated with an existing inode. For symbolic links, a new inode is allocated with a new file name associated with it but the inode references another file name rather than referencing datablocks. \u6587\u4ef6\u7cfb\u7edf\u672c\u8d28\u4e0a\u662f\u4e00\u4e2a\u7528\u4e8e\u8ddf\u8e2a\u5377\u4e2d\u6587\u4ef6\u7684\u6570\u636e\u5e93\u3002 \u5bf9\u4e8e\u666e\u901a\u6587\u4ef6\uff0c\u5206\u914d\u6570\u636e\u5757\u4ee5\u5b58\u50a8\u6587\u4ef6\u7684\u6570\u636e\uff0c\u5206\u914dinode\u4ee5\u6307\u5411\u6570\u636e\u5757\u4ee5\u53ca\u5b58\u50a8\u5173\u4e8e\u6587\u4ef6\u7684\u5143\u6570\u636e\uff0c\u7136\u540e\u5c06\u6587\u4ef6\u540d\u5206\u914d\u7ed9inode\u3002 \u786c\u94fe\u63a5\u662f\u4e0e\u73b0\u6709inode\u5173\u8054\u7684\u8f85\u52a9\u6587\u4ef6\u540d\u3002 \u5bf9\u4e8e\u7b26\u53f7\u94fe\u63a5\uff0c\u5c06\u4e3a\u65b0\u7684inode\u5206\u914d\u4e00\u4e2a\u4e0e\u4e4b\u5173\u8054\u7684\u65b0\u6587\u4ef6\u540d\uff0c\u4f46inode\u5f15\u7528\u53e6\u4e00\u4e2a\u6587\u4ef6\u540d\u800c\u4e0d\u662f\u5f15\u7528\u6570\u636e\u5757\u3002 A good way to see the relationship between file names and inodes is to use the ls -il command. The typical size of an inode is 128 Bit and data blocks can range in size from 1k, 2k, 4k or larger depending on the file system type. \u67e5\u770b\u6587\u4ef6\u540d\u548cinode\u4e4b\u95f4\u5173\u7cfb\u7684\u597d\u65b9\u6cd5\u662f\u4f7f\u7528ls -il\u547d\u4ee4\u3002inode\u7684\u5178\u578b\u5927\u5c0f\u4e3a128\u4f4d\uff0c\u6570\u636e\u5757\u7684\u5927\u5c0f\u8303\u56f4\u53ef\u4ee5\u662f1k\uff0c2k\uff0c4k\u6216\u66f4\u5927\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u3002 \u786c\u94fe\u63a5\u76f8\u5f53\u4e8e\u589e\u52a0\u4e86\u4e00\u4e2a\u767b\u8bb0\u9879\uff0c\u4f7f\u5f97\u539f\u6765\u7684\u6587\u4ef6\u591a\u4e86\u4e00\u4e2a\u540d\u5b57\uff0c\u81f3\u4e8einode\u90fd\u6ca1\u53d8\u3002\u6240\u8c13\u7684\u767b\u8bb0\u9879\u5176\u5b9e\u662f\u76ee\u5f55\u6587\u4ef6\u4e2d\u7684\u4e00\u4e2a\u6761\u76ee(\u76ee\u5f55\u9879)\uff0c\u4f7f\u7528hard link \u662f\u8ba9\u591a\u4e2a\u4e0d\u540c\u7684\u76ee\u5f55\u9879\u6307\u5411\u540c\u4e00\u4e2a\u6587\u4ef6\u7684inode\uff0c\u6ca1\u6709\u591a\u4f59\u7684\u5185\u5bb9\u9700\u8981\u5b58\u50a8\u5728\u78c1\u76d8\u6247\u533a\u4e2d\uff0c\u6240\u4ee5hardlink\u4e0d\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 \u7b26\u53f7\u94fe\u63a5\u6709\u5355\u72ec\u7684inode\uff0c\u5728inode\u4e2d\u5b58\u653e\u53e6\u4e00\u4e2a\u6587\u4ef6\u7684\u8def\u5f84\u800c\u4e0d\u662f\u6587\u4ef6\u6570\u636e\uff0c\u6240\u4ee5\u7b26\u53f7\u94fe\u63a5\u4f1a\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002","title":"Linux Link Type"},{"location":"linux/Administration/01/#lab-file-link-type","text":"Create original file mySUSE:/data/linktype # echo \"it's original file\" > file mySUSE:/data/linktype # l -rw-r--r-- 1 root root 19 Mar 28 15 :20 file Create hardlink file (\u6ce8\u610ffile\u3001hardlinkfile1\u3001hardlinkfile2\u7684link\u4f4d\u7f6e\u7684\u6570\u503c\u7684\u53d8\u5316[\u7ea2\u8272]) mySUSE:/data/linktype # ln file hardlinkfile1 mySUSE:/data/linktype # ln -s file symlinkfile1 mySUSE:/data/linktype # ln -s file symlinkfile2 mySUSE:/data/linktype # l -rw-r--r-- 2 root root 19 Mar 28 15 :20 file -rw-r--r-- 2 root root 19 Mar 28 15 :20 hardlinkfile1 lrwxrwxrwx 1 root root 4 Mar 28 15 :21 symlinkfile1 -> file lrwxrwxrwx 1 root root 4 Mar 28 15 :23 symlinkfile2 -> file mySUSE:/data/linktype # ln file hardlinkfile2 mySUSE:/data/linktype # l -rw-r--r-- 3 root root 19 Mar 28 15 :20 file ( \u5305\u62ec\u81ea\u5df1\uff0c\u4e00\u5171\u67093\u4e2a\u786c\u94fe\u63a5 ) -rw-r--r-- 3 root root 19 Mar 28 15 :20 hardlinkfile1 ( \u7ee7\u627f\u4e86\u539f\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u91cf ) -rw-r--r-- 3 root root 19 Mar 28 15 :20 hardlinkfile2 ( \u7ee7\u627f\u4e86\u539f\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u91cf ) lrwxrwxrwx 1 root root 4 Mar 28 15 :21 symlinkfile1 -> file lrwxrwxrwx 1 root root 4 Mar 28 15 :23 symlinkfile2 -> file Modify content of file (original file). Content change were shown in all hard/soft link files mySUSE:/data/linktype # echo \"add oneline\" >> file mySUSE:/data/linktype # cat file it 's original file add oneline mySUSE:/data/linktype # cat hardlinkfile1 it' s original file add oneline mySUSE:/data/linktype # cat hardlinkfile2 it 's original file add oneline mySUSE:/data/linktype # cat symlinkfile1 it' s original file add oneline mySUSE:/data/linktype # cat symlinkfile2 it ' s original file add oneline To view the value stored in a symbolic link use the command readlink. mySUSE:/data/linktype # ln -s symlinkfile1 symlinkfile1-1 mySUSE:/data/linktype # ls -il 258 -rw-r--r-- 3 root root 31 Mar 28 15 :42 file 258 -rw-r--r-- 3 root root 31 Mar 28 15 :42 hardlinkfile1 258 -rw-r--r-- 3 root root 31 Mar 28 15 :42 hardlinkfile2 259 lrwxrwxrwx 1 root root 4 Mar 28 15 :21 symlinkfile1 -> file 265 lrwxrwxrwx 1 root root 12 Mar 28 15 :49 symlinkfile1-1 -> symlinkfile1 260 lrwxrwxrwx 1 root root 4 Mar 28 15 :23 symlinkfile2 -> file mySUSE:/data/linktype # readlink symlinkfile1 file mySUSE:/data/linktype # readlink symlinkfile2 file mySUSE:/data/linktype # readlink symlinkfile1-1 symlinkfile1 ( \u6ce8\u610f\uff1a\u8fd9\u4ecd\u7136\u662f\u4e00\u4e2a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6 ) mySUSE:/data/linktype # readlink -f symlinkfile1-1(\u53c2\u6570-f\u53ef\u4ee5\u76f4\u63a5\u5b9a\u4f4d\u771f\u6b63\u7684\u6e90\u6587\u4ef6) /data/linktype/file ( \u6ce8\u610f\uff1a\u8fd9\u624d\u662f\u771f\u6b63\u7684\u539f\u6587\u4ef6 )","title":"Lab: File Link Type"},{"location":"linux/Administration/01/#linux-device-file","text":"Represent hardware (except network cards). Each piece of hardware is represented by a device file. Network cards are interfaces. (\u533a\u522b) Link between hardware devices and the kernel drivers \u8bbe\u5907\u6587\u4ef6\u628a\u5185\u6838\u9a71\u52a8\u548c\u7269\u7406\u786c\u4ef6\u8bbe\u5907\u8fde\u63a5\u8d77\u6765 Kernel drivers read from and write to the device file \u5185\u6838\u9a71\u52a8\u7a0b\u5e8f\u5bf9\u8bbe\u5907\u6587\u4ef6\u8fdb\u884c\u8bfb\u5199\u6765\u5b9e\u73b0\u5bf9\u786c\u4ef6\u7684\u8bfb\u5199 The kernel gets the data to the actual hardware in the correct format \u5185\u6838\u4ee5\u6b63\u786e\u7684\u683c\u5f0f\u5bf9\u7269\u7406\u8bbe\u5907\u8fdb\u884c\u8bfb\u5199 Types: Block Devices. A block device reads/writes information in (normally) 512 byte large blocks. Character Devices. A character device reads/writes information character wise. Character devices provide unbuffered access directly to a hardware device. \u76f4\u63a5\u8bfb\u5199\uff0c\u4e0d\u901a\u8fc7\u7f13\u5b58 Sometimes referred to as raw devices. \u88f8\u8bbe\u5907\uff08\u6ce8\u610f\uff1a\u88f8\u8bbe\u5907\u88ab\u89c6\u4e3a\u5b57\u7b26\u8bbe\u5907\uff0c\u4e0d\u662f\u5757\u8bbe\u5907\uff09 any different options for character devices, making their use and application wide and varied. Created automatically by the OS (udev) when the device is discovered by the kernel. \u5185\u6838\u76f4\u63a5\u521b\u5efa\u5bf9\u5e94\u786c\u4ef6\u7684\u8bbe\u5907\u6587\u4ef6","title":"Linux Device File"},{"location":"linux/Administration/02/","text":"Useful Commands \u00b6 Some common abbreviations \u00b6 Abbreviations Description . represents the current directory .. represents the parent directory ~ represents the home directory ~username represents the home directory of user username Software package documentation \u00b6 /usr/share/doc/packages/ Release Notes \u00b6 /usr/share/doc/release-notes/ Command help \u00b6 -h or --help # tree --help Manual pages \u00b6 man [ section ] command # man 5 crontab # man /sestion options Show tree command manual: # man tree List for keywords: # man -k keyword Force mandb to update. Normally this is done daily via a cron job. # mandb Search for all instances of a command or a file named crontab # man -f crontab # whatis crontab (same output with above command) # man -k crontab # apropos crontab (same output with above command) To go directly to a given man page: # man 5 crontab * 1G : go to the 1 st line * 10G : go to the 10 th line * G : go to the end of the page * /^SELinux : search the word SELinux * /section OPTIONS : go to the section OPTIONS man\u5171\u6709\u4ee5\u4e0b\u51e0\u4e2a\u7ae0\u8282\uff0c\u6bd4\u5982\uff0cman 5 crontab\u5c31\u662f\u8fdb\u5165crontab\u7684\u7b2c5\u7ae0\u8282\uff1a Executable programs or shell commands \uff08\u6807\u51c6\u547d\u4ee4\uff09 System calls (functions provided by the kernel)\uff08\u7cfb\u7edf\u8c03\u7528\uff09 Library calls (functions within program libraries)\uff08\u5e93\u51fd\u6570\uff09 Special files (usually found in /dev)\uff08\u8bbe\u5907\u8bf4\u660e\uff09 File formats and conventions eg /etc/passwd \uff08\u6587\u4ef6\u683c\u5f0f\uff09 Games \uff08\u6e38\u620f\u548c\u5a31\u4e50\uff09 Miscellaneous (including macro packages and conventions)\uff08\u6742\u9879\uff0c\u60ef\u4f8b\u4e0e\u534f\u5b9a\u7b49\u7f51\u7edc\u534f\u5b9a\u3001ASCII code\u7b49\u7b49\u7684\u8aaa\u660e\uff09 System administration commands (usually only for root) \uff08\u7ba1\u7406\u5458\u547d\u4ee4\uff09 Kernel routines [Non standard] \uff08\u5176\u4ed6Linux\u7279\u5b9a\u7684\uff0c\u7528\u6765\u5b58\u653e\u5185\u6838\u4f8b\u884c\u7a0b\u5e8f\u7684\u6587\u6863\u3002\uff09 man\u5e38\u7528\u5feb\u6377\u952e \u7ffb\u5c4f \u5411\u540e\u7ffb\u4e00\u5c4f\uff1aspace(\u7a7a\u683c\u952e) \u5411\u524d\u7ffb\u4e00\u5c4f\uff1ab \u5411\u540e\u7ffb\u4e00\u884c\uff1aEnter(\u56de\u8f66\u952e) \u5411\u524d\u7ffb\u4e00\u884c\uff1ak \u67e5\u627e /\u5173\u952e\u8bcd ?\u5173\u952e\u8bcd n (\u4e0b\u4e00\u4e2a) N (\u524d\u4e00\u4e2a) man \u4e2d\u6587\u5316\u3002\u5728 /etc/profile \u52a0\u5165\u4e0b\u9762alias\uff0c\u53ef\u4ee5\u5728man\u4e2d\u8f93\u51fa\u4e2d\u6587 # For man in zh_CH alias cman='man -M /usr/share/man/zh_CN' Display descriptions: \u00b6 whatis command Info pages: \u00b6 info command # info # info top From the terminal window display the info pages for the info command by entering: # info info Move the cursor to the line referring to (Invoking Info) by pressing Tab Tab Follow the link by pressing Enter Move the cursor to the link Note Custom Key Bindings: by pressing Tab (6 times) Follow the link by pressing Enter Return to the page Note Custom Key Bindings: by typing (lowercase L): l Exit the info file by typing: q pwd command \u00b6 Display the current working directory cd command \u00b6 Change directory ls command \u00b6 Display directory contents * Display hidden files with -a option * Detailed listing with -l option * Output is recursive, including all subdirectories with -R option * With option -F After each name, a character indicates the file type (\u201c/\u201d for directories, \u201c*\u201d for executable files, \u201c|\u201d for FIFO files, \u201c@\u201d symbolic link). cp command \u00b6 Copy a file or directory Syntax: cp [option] Option -a : Copies a directory and subdirectories (compare -R ); symbolic links, file permissions, owners, and time stamps are not changed. \u5b83\u4fdd\u7559\u7b26\u53f7\u94fe\u63a5\u3001\u6587\u4ef6\u5c5e\u6027\uff0c\u5e76\u590d\u5236\u76ee\u5f55\u4e0b\u7684\u6240\u6709\u5185\u5bb9\u3002\u5176\u4f5c\u7528\u7b49\u4e8e-dpR\u53c2\u6570\u7ec4\u5408\u3002 Option -I : Asks before overwriting. Option -R , -r : Copies directories recursively (the directory and any subdirectories). \u9012\u5f52\u62f7\u8d1d\uff0c\u5305\u542b\u5b50\u76ee\u5f55\u53ca\uff08\u9690\u542b\uff09\u6587\u4ef6\uff0c\u7ee7\u627f\u76ee\u6807\u76ee\u5f55\u7684\u6743\u9650\u548c\u5c5e\u6027\u7b49 Option -l : Makes hardlinks instead of copying (\u521b\u5efa\u786c\u94fe\u63a5\u7684\u53e6\u5916\u4e00\u4e2a\u65b9\u6cd5) Option -s : Makes symbolic instead of copying (\u521b\u5efa\u7b26\u53f7\u94fe\u63a5\u7684\u53e6\u5916\u4e00\u4e2a\u65b9\u6cd5) Option -u : Copies a file only when the source file is newer than the destination file or when the destination file is missing. Option -p : \u8fde\u540c\u6863\u6848\u7684\u5c5e\u6027\u4e00\u8d77\u590d\u5236\u8fc7\u53bb\uff0c\u5305\u62ec\u4fee\u6539\u65f6\u95f4\u3001\u8bbf\u95ee\u6743\u9650\u3001\u6240\u6709\u8005\u7ec4\u7b49\uff0c\u800c\u975e\u4f7f\u7528\u9884\u8bbe\u5c5e\u6027\uff1b Labs: Initiate directories and files mySUSE:~ # su - pmgr pmgr@mySUSE:~> mkdir /data/program pmgr@mySUSE:~> mkdir /data/program/general pmgr@mySUSE:~> mkdir /data/program/general/staffing pmgr@mySUSE:~> touch /data/program/general/program_scope pmgr@mySUSE:~> touch /data/program/general/staffing/assignment mySUSE:~ # su - pm1 pm1@mySUSE:~> mkdir /data/project1 pm1@mySUSE:~> mkdir /data/project1/iot pm1@mySUSE:~> mkdir /data/project1/iot/bigdata pm1@mySUSE:~> touch /data/project1/iot/devicelist pm1@mySUSE:~> touch /data/project1/iot/bigdata/math_lib mySUSE:~ # su - pm2 pm2@mySUSE:~> mkdir /data/project2 pm2@mySUSE:~> mkdir /data/project2/erp pm2@mySUSE:~> mkdir /data/project2/erp/fin pm2@mySUSE:~> touch /data/project2/erp/erp_vision pm2@mySUSE:~> touch /data/project2/erp/fin/fin_ar pm2@mySUSE:~> chmod g+w /data/project2/erp/erp_vision pmgr@mySUSE:~> ln /data/project2/erp/erp_vision /data/program/general/p2_erp_version ( \u521b\u5efa\u786c\u94fe\u63a5\uff0c\u5f53\u524d\u7528\u6237\u9700\u8981\u5bf9\u6e90\u6587\u4ef6erp_vision\u6709w\u6743\u9650 ) pmgr@mySUSE:~> ln -s /data/project1/iot/devicelist /data/program/general/p1_devicelist ( \u521b\u5efa\u7b26\u53f7\u94fe\u63a5\uff0c\u4e0d\u9a8c\u8bc1\u5f53\u524d\u7528\u6237\u662f\u5426\u5bf9\u6e90\u6587\u4ef6devicelist\u6709\u6743\u9650 ) mySUSE:~ # tree /data /data \u251c\u2500\u2500 program \u2502 \u2514\u2500\u2500 general \u2502 \u251c\u2500\u2500 p1_devicelist -> /data/project1/iot/devicelist \u2502 \u251c\u2500\u2500 p2_erp_version \u2502 \u251c\u2500\u2500 program_scope \u2502 \u2514\u2500\u2500 staffing \u2502 \u2514\u2500\u2500 assignment \u251c\u2500\u2500 project1 \u2502 \u2514\u2500\u2500 iot \u2502 \u251c\u2500\u2500 bigdata \u2502 \u2502 \u2514\u2500\u2500 math_lib \u2502 \u2514\u2500\u2500 devicelist \u2514\u2500\u2500 project2 \u2514\u2500\u2500 erp \u251c\u2500\u2500 erp_vision \u2514\u2500\u2500 fin \u2514\u2500\u2500 fin_ar pmgr@mySUSE:~> cp -R /data/project1 /data/program/ ( /data/program/project1\u7684\u7528\u6237\u548c\u7ec4\u90fd\u7ee7\u627f\u4e86/data/program/ ) pmgr@mySUSE:~> cp -a /data/project2 /data/program/ ( /data/program/project2\u7684\u7528\u6237\u7ee7\u627f\u4e86/data/program/\uff0c\u4f46\u7ec4\u8fd8\u662f\u4fdd\u7559\u539f\u6765\u7684 ) mv command \u00b6 Move or rename a file or directory Option -i : Asks for confirmation before moving or renaming a file. This prevents existing files with the same name from being overwritten. Option -u : Only moves files that are newer than the target files of the same name. pmgr@mySUSE:/data/program/general> cp program_scope ./staffing/ pmgr@mySUSE:/data/program/general> mv -i program_scope ./staffing/ mv: overwrite './staffing/program_scope'? n rm command \u00b6 Delete a file or directory Option -i : Asks for confirmation before deleting. Option -r : (recursively) Allows full directories to be deleted. Option -f : (force) By default, rm asks for confirmation if the file that should be deleted is read-only. Using this option, the files are deleted without asking for confirmation. mkdir command \u00b6 Create a new directory Option -p lets you create a complete path (\u5c42\u7ea7\u8def\u5f84\u4e00\u6b21\u521b\u5efa) pmgr@mySUSE:/data> mkdir -p industry/utilities pmgr@mySUSE:/data> tree ./industry/ ./industry/ \u2514\u2500\u2500 utilities rmdir command \u00b6 Remove an empty directory. The directory or directories must be empty before you can delete them. ln command \u00b6 Create a link Default: Hard link Symbolic link with -s option Syntax: ln [-s] touch command \u00b6 Change the access and modification times Create an empty file if the given file does not exist. Change the time stamp of a file. Option -a : Changes only the time of the last read access (access time). Option -m : Changes only the time of the last modification (modification time). Option -r file : Sets the time stamp of file instead of the current time. Option -t time : Instead of the current time, sets time (structure: [[CC]YY]MMDDhhmm.[ss] ([Century]Year] Month Day Hour Minute [Seconds], two digits in each)) pmgr@mySUSE:/data/industry> touch readme pmgr@mySUSE:/data/industry> touch -a readme pmgr@mySUSE:/data/industry> touch -m readme pmgr@mySUSE:/data/industry> stat readme File: readme Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: 3dh/61d Inode: 338 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 1003/ pmgr) Gid: ( 1000/ admins) Access: 2019-03-31 10:07:47.489055973 +0800 Modify: 2019-03-31 10:07:58.805109884 +0800 Change: 2019-03-31 10:07:58.805109884 +0800 Birth: - cat command \u00b6 Concatenates files tac command \u00b6 Same as cat, but displays the file(s) in reverse pmgr@mySUSE:/data/industry> cat readme line 1 line 2 line 3 pmgr@mySUSE:/data/industry> tac readme line 3 line 2 line 1 more command \u00b6 Display file contents one page at a time less command \u00b6 Displays file contents for better navigation head command \u00b6 Displays the first 10 lines of a file. To set the number of lines use the -n option pmgr@mySUSE:/data/industry> head readme line 1 line 2 line 3 line 4 line 5 line 6 line 7 line 8 line 9 line 10 pmgr@mySUSE:/data/industry> head -n 5 readme line 1 line 2 line 3 line 4 line 5 tail command \u00b6 Display the last lines of a file To set the number of lines use the -n option To output appended data use -f option, displays a continuously updated view of the last lines of a file. To exit tail -f, press Ctrl+C. pmgr@mySUSE:/data/industry> tail -n 6 readme line 10 line 11 line 12 line 13 line 14 line 15 tar command \u00b6 Create, expand or list archive files Use option c to create an archive Use option f to specify the archive file name Use option v for verbose mode Use option x to extract an archive Use option t to list the content of an archive Use option z to (un-)compress the archive with gzip Use option j to (un-)compress the archive with bzip The /etc directory (include sub-directories) is backed up to the /backup/etc.tar file pmgr@mySUSE:~> tar -cvf /data/backup/project1.tar /data/project1/ pmgr@mySUSE:~> tar -cvf /data/backup/project2.tar /data/project2/ pmgr@mySUSE:~> tar -cv --exclude='*.conf' -f /data/backup/project2a.tar /data/project2/ View the contents of an archive. Some .conf files are excluded in project2a.tar file. pmgr@mySUSE:~> tar -tvf /data/backup/project2.tar drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/fin/ -rw-r--r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/fin/fin_ar -rw-r--r-- pm2/project2 0 2019-03-31 16:47 data/project2/erp/fin/fin.conf -rw-rw-r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/erp_vision -rw-r--r-- pm2/project2 0 2019-03-31 16:47 data/project2/erp/erp.conf -rw-r--r-- pm2/project2 0 2019-03-31 16:47 data/project2/project2.conf pmgr@mySUSE:~> tar -tvf /data/backup/project2a.tar drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/fin/ -rw-r--r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/fin/fin_ar -rw-rw-r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/erp_vision Unpack and write all files in the archive to the current directory. Extract to another directory by using the -C option pmgr@mySUSE:~> mkdir project1.backup pmgr@mySUSE:~> tar -xvf /data/backup/project1.tar -C /data/backup/project1.backup/ Incremental backup with tar command pmgr@mySUSE:~> tar -g snapshot_program -cvf /data/backup/bkp_program_full.tar /data/program/ pmgr@mySUSE:~> tar -tvf /data/backup/bkp_program_full.tar pmgr@mySUSE:~> touch /data/program/general/general.conf pmgr@mySUSE:~> tar -g snapshot_program -cvf /data/backup/bkp_program_inc.tar /data/program/ pmgr@mySUSE:~> rm -rf program/ pmgr@mySUSE:~> tar -xvf /data/backup/bkp_program_inc.tar -C /data/ cpio command \u00b6 Another archiving command gzip command \u00b6 Compress files using the gzip algorithm Option -c : Compresses the file without modifying the original file. The result is written to the standard output (usually the screen). From there, it can be redirected to a file with \u201c>\u201d. Option -d : Decompresses the specified file (gunzip) Option -r : Compresses and decompresses files in all subdirectories. Option -1 to -9, --fast, --best : Controls the compression speed: -1 means --fast and causes a quick compression but produces larger files, -9 corresponds to --best and requires more computing time but produces smaller files. The default setting is -6. gunzip command \u00b6 Expand files compressed with gzip bzip2 command \u00b6 Compress files using the bzip2 algorithm Option -c : Option -d : Decompresses the specified file (bunzip2). Option -1 to -9 : Controls the compression speed: -1 causes a quick compression but produces larger files, -9 requires more computing time but produces smaller files. The default setting is -9 . bunzip2 command \u00b6 Expand files compressed with bzip rsync command \u00b6 Copy only deltas between two directories. A key benefit of using rsync is that when copying data, rsync compares the source and the target directory and transfers only data that has changed or has been created. \u4ec5\u590d\u5236\u4e24\u4e2a\u76ee\u5f55\u4e4b\u95f4\u7684\u589e\u91cf\u3002 \u4f7f\u7528rsync\u7684\u4e00\u4e2a\u4e3b\u8981\u597d\u5904\u662f\uff0c\u5728\u590d\u5236\u6570\u636e\u65f6\uff0crsync\u4f1a\u6bd4\u8f83\u6e90\u76ee\u5f55\u548c\u76ee\u6807\u76ee\u5f55\uff0c\u5e76\u4ec5\u4f20\u8f93\u5df2\u66f4\u6539\u6216\u5df2\u521b\u5efa\u7684\u6570\u636e\u3002 Local or via network \u672c\u5730\u6216\u901a\u8fc7\u7f51\u7edc Uses ssh as default transport \u4f7f\u7528ssh\u4f5c\u4e3a\u9ed8\u8ba4\u4f20\u8f93 Can talk to rsync daemon on the remote machine \u53ef\u4ee5\u4e0e\u8fdc\u7a0b\u8ba1\u7b97\u673a\u4e0a\u7684rsync\u5b88\u62a4\u7a0b\u5e8f\u901a\u4fe1 Note: rsync must be installed on both the source and the target computer for this to work. \u5fc5\u987b\u5728\u6e90\u8ba1\u7b97\u673a\u548c\u76ee\u6807\u8ba1\u7b97\u673a\u4e0a\u5b89\u88c5rsync\u624d\u80fd\u4f7f\u5176\u6b63\u5e38\u5de5\u4f5c\u3002 As the default shell used by rsync is ssh, the -e option only needs to be used when you want to use something else than ssh. \u7531\u4e8ersync\u4f7f\u7528\u7684\u9ed8\u8ba4shell\u662fssh\uff0c\u56e0\u6b64\u53ea\u6709\u5728\u60f3\u8981\u4f7f\u7528\u9664ssh\u4ee5\u5916\u7684\u5176\u4ed6\u5de5\u5177\u65f6\u624d\u9700\u8981\u4f7f\u7528-e\u9009\u9879\u3002 Options Option -a : Puts rsync into the archive mode. The -a option ensures the following are preserved \u4fdd\u7559 in the mirrored copy of the directory: Symbolic links (l option) Access permissions (p option) Owners (o option) Group membership (g option) Time stamp (t option) Option -x : Saves files on one file system only, which means that rsync does not follow symbolic links to other file systems. \u4e0d\u8de8\u6587\u4ef6\u7cfb\u7edf\uff0c\u53ea\u5728\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u5185(don't cross filesyste* undaries) Option -v : Enables the verbose mode. Use this mode to output information about the transferred files and the progress of the copying process. \u8f93\u51fa\u4f20\u8f93\u8fc7\u7a0b\u7684\u7ec6\u8282\u4fe1\u606f Option -z : Compresses the data during the transfer. This is especially useful for remote synchronization. \u538b\u7f29\u65b9\u5f0f\u4f20\u8f93 Option --delete : Deletes files from the mirrored directory that no longer exist in the original directory. Option --exclude-from : Does not back up files listed in an exclude file. Local backup via rsync command pmgr@mySUSE:/data> rsync -av /data/industry/* /data/backup/industry/ sending incremental file list created directory /data/backup/industry readme utilities/ sent 264 bytes received 87 bytes 702.00 bytes/sec total size is 111 speedup is 0.32 pmgr@mySUSE:/data/industry/utilities> touch roadmap.txt pmgr@mySUSE:/data> rsync -av /data/industry/* /data/backup/industry/ sending incremental file list utilities/ utilities/roadmap.txt sent 171 bytes received 39 bytes 420.00 bytes/sec total size is 111 speedup is 0.53 pmgr@mySUSE:/data> rm roadmap.txt pmgr@mySUSE:/data> rsync -av /data/industry/* --delete /data/backup/industry/ sending incremental file list deleting utilities/roadmap.txt utilities/ sent 102 bytes received 41 bytes 286.00 bytes/sec total size is 111 speedup is 0.78 dd command \u00b6 Copies files block by block Used to create disk or partition images Most important options: if =input_file `of``=output_file bs =block_size You can use the dd command to convert and copy files byte-wise. Normally dd reads from the standard input and writes the result to the standard output. But with the appropriate parameters, regular files can be addressed as well. You can copy all kinds of Linux data with this command, including entire hard disk partitions. You can even copy an entire installed system (or just parts of it). Copy file /etc/protocols to protocols.old. The default size for a record is 512 bytes. Below 45+1 means, 45 complete record of standard size and 1 incomplete record (less than 512 bytes pmgr@mySUSE:/data/program> dd if=/etc/protocols of=protocols.old bs=512 45+1 records in 45+1 records out 23259 bytes (23 kB, 23 KiB) copied, 0.000595392 s, 39.1 MB/s \u521b\u5efa\u4e00\u4e2a100M\u7684\u7a7a\u6587\u4ef6 pmgr@mySUSE:/data/program> dd if=/dev/zero of=datafile bs=100M count=2 2+0 records in 2+0 records out 209715200 bytes (210 MB, 200 MiB) copied, 2.79311 s, 75.1 MB/s \u5907\u4efd\u6574\u4e2a\u5206\u533a #dd if=/dev/sda1 of=boot.partition \u5236\u4f5cU\u76d8\u542f\u52a8\u76d8\uff08U\u76d8\u6302\u8f7d\u5230/dev/sdb\uff09 #dd if=/root/diskboot.img of=/dev/sdb bs=125682176 \u5907\u4efd\u786c\u76d8\u4e3b\u5f15\u5bfc\u8bb0\u5f55 #dd if=/dev/sda of=/tmp/mbr_copy bs=512 count=1 \u8fd8\u539f\u786c\u76d8\u4e3b\u5f15\u5bfc\u8bb0\u5f55 #dd if=/disk.mbr of=/dev/hda bs=512 count=1 \u5c06\u5185\u5b58\u91cc\u7684\u6570\u636e\u62f7\u8d1d\u5230root\u76ee\u5f55\u4e0b\u7684mem.bin\u6587\u4ef6 # dd if=/dev/mem of=/root/mem.bin bs=1024 \u62f7\u8d1d\u5149\u76d8\u6570\u636e\u5230root\u6587\u4ef6\u5939\u4e0b\uff0c\u5e76\u4fdd\u5b58\u4e3acd.iso\u6587\u4ef6 # dd if=/dev/cdrom of=/root/cd.iso \u5229\u7528\u968f\u673a\u7684\u6570\u636e\u586b\u5145\u786c\u76d8(\u9500\u6bc1\u786c\u76d8\u6570\u636e) # dd if=/dev/urandom of=/dev/hda1 \u6d4b\u8bd5\u786c\u76d8\u8bfb\u5199\u901f\u5ea6\u3002\u901a\u8fc7\u4e24\u4e2a\u547d\u4ee4\u8f93\u51fa\u7684\u6267\u884c\u65f6\u95f4\uff0c\u53ef\u4ee5\u8ba1\u7b97\u51fa\u6d4b\u8bd5\u786c\u76d8\u7684\u8bfb\uff0f\u5199\u901f\u5ea6\uff1a mySUSE:/data # dd if=/data/program/datafile bs=64k | dd of=/dev/null 3200+0 records in 3200+0 records out 209715200 bytes (210 MB, 200 MiB) copied, 0.67138 s, 312 MB/s 409600+0 records in 409600+0 records out 209715200 bytes (210 MB, 200 MiB) copied, 0.675912 s, 310 MB/s # dd if=/dev/zero of=/data/program/datafile bs=1024 count=100 \u5207\u5272\u5927\u6587\u4ef6bigfile\uff0c\u517198336321\u5b57\u8282\uff0c\u5219\uff1a # dd if=bigfile of=smallfile1 bs=1 count=20000000 # dd if=bigfile of=smallfile2 bs=1 count=20000000 skip=20000000 # dd if=bigfile of=smallfile3 bs=1 count=20000000 skip=40000000 # dd if=bigfile of=smallfile4 bs=1 count=20000000 skip=60000000 # dd if=bigfile of=smallfile5 bs=1 count=18336321 skip=80000000 \u5c06\u5207\u5272\u6587\u4ef6\u7ec4\u88c5 # dd if=smallfile1 of=bigfile bs=1 count=20000000 # dd if=smallfile2 of=bigfile bs=1 count=20000000 seek=20000000 # dd if=smallfile3 of=bigfile bs=1 count=20000000 seek=40000000 # dd if=smallfile4 of=bigfile bs=1 count=20000000 seek=60000000 # dd if=smallfile5 of=bigfile bs=1 count=18336321 seek=80000000 if: \u8981\u5207\u5272\u7684\u5927\u6587\u4ef6\u540d of: \u5207\u5272\u540e\u7684\u5b50\u6587\u4ef6\u540d bs: \u4ee5\u591a\u5c11\u5b57\u8282\u4f5c\u4e3a\u4e00\u4e2a\u5207\u5272\u8bb0\u5f55\u5355\u4f4d count: \u662f\u8981\u5207\u5272\u7684\u5355\u4f4d\u8bb0\u5f55\u6570 skip: \u8bf4\u660e\u5207\u5272\u65f6\u7684\u8d77\u70b9 seek: \u660e\u786e\u6307\u51fa\u5f00\u59cb\u4f4d\u7f6e find command \u00b6 Search for files or directories Syntax: find path criterion [action] The find command has a multitude of options, a few of which are explained here. You can use the following arguments with the command: path: The section of the file system to search (the specified directory and all its subdirectories). If nothing is specified, the file system below the current directory is used. criterion: The properties the file should have (see below) action: Options that influence the following conditions or control the search as a whole The most important actions are: -print (default) -exec command With the -exec option, you can call up another command. This option is frequently used to link find and grep, as in the following: \u627e\u51fagen\u5f00\u5934\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -name gen\\* ./program/general ./program/general/general.conf \u627e\u51fagen\u5f00\u5934\u7684\u6587\u4ef6\uff0c\u5e76\u5728\u6587\u4ef6\u5185\u5bb9\u4e2d\u67e5\u627exen\uff0c\u627e\u5230\u540e\u7ed3\u679c\u8f93\u51faxen pmgr@dcmaster:/data> find . -name gen\\* -type f -exec grep xen {} \\; xen xening The two brackets \u201c{}\u201d stand as placeholders for the file names which are found and passed to the grep command. The semicolon closes the -exec instruction. Because this is a special character, it is masked by placing a backslash in front of it. -ctime [\u00b1]days Searches for files whose last change took place no later than (no earlier than) a specified number of days ago. \u5728\u8fc7\u53bbn\u5929\u5185\u88ab\u4fee\u6539\u8fc7\u7684\u6587\u4ef6 mgr@dcmaster:/data> find . -ctime 1 . ./program/datafile -gid number Searches for files with the numeric GID (Group ID) number. (gid \u662f n) -group name Searches for files that are owned by the group name. Instead of a name, the numeric GID is allowed. (group \u540d\u79f0\u662f name) -name pattern Searches for files whose names contain the given pattern. If the pattern contains meta characters or wild cards, the name must be enclosed by quotation marks. Otherwise thename will be interpreted by the shell and not by find. -newer file Searches for files that were modified more recently than file. \u6bd4\u6587\u4ef6 file \u66f4\u65b0\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -cnewer ./program/datafile . -size [\u00b1]size Matches files that are above or below a certain size. The size (in blocks of 512 bytes) is given as an argument. The suffix \u201cc\u201cswitches to byte and \u201ck\u201d to blocks of 1024bytes. A preceding \u201c+\u201d stands for all larger files and a \u201c-\u201d for all smaller files. (\u6587\u4ef6\u5927\u5c0f \u662f n \u2022 b \u4ee3\u8868 512 \u4f4d\u5143\u7ec4\u7684\u533a\u5757 \u2022 c \u8868\u793a\u5b57\u5143\u6570 \u2022 k \u8868\u793a kilo bytes \u2022 w \u662f\u4e8c\u4e2a\u4f4d\u5143\u7ec4 pmgr@dcmaster:/data> find . -size 20k ./backup/project2.tar -type file_type Searches for a file type. A file type can be one of the following: * c : \u6587\u4ef6\u7c7b\u578b\u662f c \u7684\u6587\u4ef6\u3002 * d: \u76ee\u5f55 * c: \u5b57\u578b\u88c5\u7f6e\u6587\u4ef6 * b: \u533a\u5757\u88c5\u7f6e\u6587\u4ef6 * p: \u5177\u540d\u8d2e\u5217 * f: \u4e00\u822c\u6587\u4ef6 * l: \u7b26\u53f7\u8fde\u7ed3 * s: socket -uid number Searches for files with the numeric UID (User ID) number. -user name Searches for files, which are owned by user name. Instead of a name, the numeric UID is allowed. \u5e38\u7528\u53c2\u6570 mount, -xdev : \u53ea\u68c0\u67e5\u548c\u6307\u5b9a\u76ee\u5f55\u5728\u540c\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u4e0b\u7684\u6587\u4ef6\uff0c\u907f\u514d\u5217\u51fa\u5176\u5b83\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6587\u4ef6 amin n : \u5728\u8fc7\u53bb n \u5206\u949f\u5185\u88ab\u8bfb\u53d6\u8fc7 anewer file : \u6bd4\u6587\u4ef6 file \u66f4\u665a\u88ab\u8bfb\u53d6\u8fc7\u7684\u6587\u4ef6 atime n : \u5728\u8fc7\u53bbn\u5929\u5185\u88ab\u8bfb\u53d6\u8fc7\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -atime 1 ./program/datafile cmin n : \u5728\u8fc7\u53bb n \u5206\u949f\u5185\u88ab\u4fee\u6539\u8fc7 pmgr@dcmaster:/data> find . -cmin 20 empty : \u7a7a\u7684\u6587\u4ef6 ipath p, -path p : \u8def\u5f84\u540d\u79f0\u7b26\u5408 p \u7684\u6587\u4ef6\uff0cipath \u4f1a\u5ffd\u7565\u5927\u5c0f\u5199 name name, -iname name : \u6587\u4ef6\u540d\u79f0\u7b26\u5408 name \u7684\u6587\u4ef6\u3002iname \u4f1a\u5ffd\u7565\u5927\u5c0f\u5199 pid n : process id \u662f n \u7684\u6587\u4ef6 \u67e5\u627e\u5f53\u524d\u76ee\u5f55\u53ca\u5b50\u76ee\u5f55\u4e2d\u6240\u6709\u6587\u4ef6\u957f\u5ea6\u4e3a0\u7684\u666e\u901a\u6587\u4ef6\uff0c\u5e76\u5217\u51fa\u5b83\u4eec\u7684\u5b8c\u6574\u8def\u5f84 pmgr@dcmaster:/data> find . -type f -size 0 -exec ls -l {} \\; \u67e5\u627e\u524d\u76ee\u5f55\u4e2d\u6587\u4ef6\u5c5e\u4e3b\u5177\u6709\u8bfb\u3001\u5199\u6743\u9650\uff0c\u5e76\u4e14\u6587\u4ef6\u6240\u5c5e\u7ec4\u7684\u7528\u6237\u548c\u5176\u4ed6\u7528\u6237\u5177\u6709\u8bfb\u6743\u9650\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -type f -perm 644 -exec ls -l {} \\; \u67e5\u627e/var/log\u76ee\u5f55\u4e2d\u66f4\u6539\u65f6\u95f4\u572817\u65e5\u4ee5\u524d\u7684\u666e\u901a\u6587\u4ef6\uff0c\u5e76\u5728\u5220\u9664\u4e4b\u524d\u8be2\u95ee\u5b83\u4eec pmgr@dcmaster:/data> find /var/log -type f -mtime +17 -ok rm {} \\; \u5c06\u76ee\u524d\u76ee\u5f55\u53ca\u5176\u5b50\u76ee\u5f55\u4e0b\u6240\u6709\u6700\u8fd1 1 \u5929\u5185\u66f4\u65b0\u8fc7\u7684\u6587\u4ef6\u5217\u51fa mgr@dcmaster:/data> find . -ctime 1 \u5c06\u76ee\u524d\u76ee\u5f55\u5176\u5176\u4e0b\u5b50\u76ee\u5f55\u4e2d\u6240\u6709\u4e00\u822c\u6587\u4ef6\u5217\u51fa pmgr@dcmaster:/data> find . -type f \u5c06\u76ee\u524d\u76ee\u5f55\u53ca\u5176\u5b50\u76ee\u5f55\u4e0b\u6240\u6709\u5ef6\u4f38\u6863\u540d\u662fconf \u7684\u6587\u4ef6\u5217\u51fa\u6765 pmgr@dcmaster:/data> find . -name \"*.conf\" which command \u00b6 Searches all paths listed in the variable $PATH and returns the full path of the command The which command searches all paths listed in the variable $PATH for the specified command and returns the full path of the command. In the variable \\(PATH, the most important directoriesare listed where the shell looks for executable files. which\u547d\u4ee4\u641c\u7d22\u53d8\u91cf\\) PATH\u4e2d\u5217\u51fa\u7684\u6240\u6709\u8def\u5f84\u4ee5\u83b7\u53d6\u6307\u5b9a\u547d\u4ee4\uff0c\u5e76\u8fd4\u56de\u547d\u4ee4\u7684\u5b8c\u6574\u8def\u5f84\u3002 The which command is especially useful if several versions of a command exist in different directories and you want to know which version is executed when entered without specifying apath. \u5982\u679c\u547d\u4ee4\u7684\u591a\u4e2a\u7248\u672c\u5b58\u5728\u4e8e\u4e0d\u540c\u7684\u76ee\u5f55\u4e2d\uff0c\u5e76\u4e14\u60a8\u60f3\u77e5\u9053\u5728\u8f93\u5165\u65f6\u6267\u884c\u4e86\u54ea\u4e2a\u7248\u672c\u800c\u672a\u6307\u5b9a\u8def\u5f84\uff0c\u90a3\u4e48which\u547d\u4ee4\u7279\u522b\u6709\u7528\u3002 NOTE: To see the content of a variable, use the echo command Options Description -n<\u6587\u4ef6\u540d\u957f\u5ea6> \u6307\u5b9a\u6587\u4ef6\u540d\u957f\u5ea6\uff0c\u6307\u5b9a\u7684\u957f\u5ea6\u5fc5\u987b\u5927\u4e8e\u6216\u7b49\u4e8e\u6240\u6709\u6587\u4ef6\u4e2d\u6700\u957f\u7684\u6587\u4ef6\u540d\u3002 -p<\u6587\u4ef6\u540d\u957f\u5ea6> \u4e0e-n\u53c2\u6570\u76f8\u540c\uff0c\u4f46\u6b64\u5904\u7684<\u6587\u4ef6\u540d\u957f\u5ea6>\u5305\u62ec\u4e86\u6587\u4ef6\u7684\u8def\u5f84\u3002 -w \u6307\u5b9a\u8f93\u51fa\u65f6\u680f\u4f4d\u7684\u5bbd\u5ea6\u3002 -V \u663e\u793a\u7248\u672c\u4fe1\u606f # which grep /usr/bin/grep # which -V grep GNU which v2.21, Copyright (C) 1999 - 2015 Carlo Wood. GNU which comes with ABSOLUTELY NO WARRANTY; This program is free software; your freedom to use, change and distribute this program is protected by the GPL. whereis command \u00b6 The whereis command returns the binaries (option -b), manual pages (option -m), and the source code (option -s) of the specified command. If no option is used, all this information is returned, provided the information is available. This command is faster than find, but it is less thorough. Attempts to locate the desired program in the standard Linux places, and in the places specified by $PATH and $MANPATH . \u5c1d\u8bd5\u5728\u6807\u51c6Linux\u4f4d\u7f6e\u548c\u6307\u5b9a\u4f4d\u7f6e( \\(PATH\u548c\\) MANPATH)\u627e\u5230\u6240\u9700\u7684\u7a0b\u5e8f Options Description -b \u53ea\u67e5\u627e\u4e8c\u8fdb\u5236\u6587\u4ef6\u3002 -B<\u76ee\u5f55> \u53ea\u5728\u8bbe\u7f6e\u7684\u76ee\u5f55\u4e0b\u67e5\u627e\u4e8c\u8fdb\u5236\u6587\u4ef6\u3002 -f \u4e0d\u663e\u793a\u6587\u4ef6\u540d\u524d\u7684\u8def\u5f84\u540d\u79f0\u3002 -m \u53ea\u67e5\u627e\u8bf4\u660e\u6587\u4ef6\u3002 -M<\u76ee\u5f55> \u53ea\u5728\u8bbe\u7f6e\u7684\u76ee\u5f55\u4e0b\u67e5\u627e\u8bf4\u660e\u6587\u4ef6\u3002 -s \u53ea\u67e5\u627e\u539f\u59cb\u4ee3\u7801\u6587\u4ef6\u3002 -S<\u76ee\u5f55> \u53ea\u5728\u8bbe\u7f6e\u7684\u76ee\u5f55\u4e0b\u67e5\u627e\u539f\u59cb\u4ee3\u7801\u6587\u4ef6\u3002 -u \u67e5\u627e\u4e0d\u5305\u542b\u6307\u5b9a\u7c7b\u578b\u7684\u6587\u4ef6\u3002 \u4ee5\u4e0b\u8f93\u51fa\u4fe1\u606f\u4ece\u5de6\u81f3\u53f3\u5206\u522b\u4e3a\u67e5\u8be2\u7684\u7a0b\u5e8f\u540d\u3001bash\u8def\u5f84\u3001bash\u7684man\u624b\u518c\u9875\u8def\u5f84\u3002 # whereis grep grep: /usr/bin/grep /bin/grep /usr/share/man/man1/grep.1.gz /usr/share/info/grep.info.gz \u663e\u793abash \u547d\u4ee4\u7684\u4e8c\u8fdb\u5236\u7a0b\u5e8f # whereis -b grep grep: /usr/bin/grep /bin/grep \u663e\u793abash \u547d\u4ee4\u7684\u5e2e\u52a9\u6587\u4ef6 # whereis -m grep grep: /usr/share/man/man1/grep.1.gz /usr/share/info/grep.info.gz type command \u00b6 The type command shows what kind of command is executed when you enter it: \u547d\u4ee4\u7684\u7c7b\u578b a shell built-in command (an essential command that is hard coded in the shell), for example type or cd an external command (called by the shell) an alias, for example ls. An alias defines shortcuts and synonyms for commonly used shell commands. a function The -a option delivers all instances of a command bearing this name in the file system. NOTE: If you want to have more information about a file format, you can use the file command. \u4e0d\u9002\u7528\u4e8e\u666e\u901a\u6587\u4ef6 dcmaster:/data/shell # type pwd.txt -bash: type: pwd.txt: not found \u4e0d\u9002\u7528\u4e8e\u81ea\u5b9a\u4e49\u53ef\u6267\u884c\u811a\u672c dcmaster:/data/shell # type math.sh -bash: type: math.sh: not found \u7cfb\u7edf\u547d\u4ee4 dcmaster:/data/shell # type rsync rsync is /usr/bin/rsync \u522b\u540d dcmaster:/data/shell # type l l is aliased to `ls -alF' file command \u00b6 file\u547d\u4ee4\u7528\u4e8e\u8fa8\u8bc6\u6587\u4ef6\u7c7b\u578b -b \u5217\u51fa\u8fa8\u8bc6\u7ed3\u679c\u65f6\uff0c\u4e0d\u663e\u793a\u6587\u4ef6\u540d\u79f0\u3002 -c \u8be6\u7ec6\u663e\u793a\u6307\u4ee4\u6267\u884c\u8fc7\u7a0b\uff0c\u4fbf\u4e8e\u6392\u9519\u6216\u5206\u6790\u7a0b\u5e8f\u6267\u884c\u7684\u60c5\u5f62\u3002 -f <\u540d\u79f0\u6587\u4ef6> \u6307\u5b9a\u540d\u79f0\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u6587\u4ef6\u540d\u79f0\u65f6\uff0c\u8ba9file\u4f9d\u5e8f\u8fa8\u8bc6\u8fd9\u4e9b\u6587\u4ef6\uff0c\u683c\u5f0f\u4e3a\u6bcf\u5217\u4e00\u4e2a\u6587\u4ef6\u540d\u79f0\u3002 -L \u76f4\u63a5\u663e\u793a\u7b26\u53f7\u8fde\u63a5\u6240\u6307\u5411\u7684\u6587\u4ef6\u7684\u7c7b\u522b\u3002 -m<\u9b54\u6cd5\u6570\u5b57\u6587\u4ef6> \u6307\u5b9a\u9b54\u6cd5\u6570\u5b57\u6587\u4ef6\u3002 -v \u663e\u793a\u7248\u672c\u4fe1\u606f\u3002 -z \u5c1d\u8bd5\u53bb\u89e3\u8bfb\u538b\u7f29\u6587\u4ef6\u7684\u5185\u5bb9\u3002 dcmaster:/data/linktype # l -rw-r--r-- 3 root root 44 May 3 09:50 file -rw-r--r-- 3 root root 44 May 3 09:50 hardlinkfile1 -rw-r--r-- 3 root root 44 May 3 09:50 hardlinkfile2 lrwxrwxrwx 1 root root 4 Mar 28 15:21 symlinkfile1 -> file lrwxrwxrwx 1 root root 12 Mar 28 15:49 symlinkfile1-1 -> symlinkfile1 lrwxrwxrwx 1 root root 4 Mar 28 15:23 symlinkfile2 -> file dcmaster:/data/linktype # file hardlinkfile1 hardlinkfile1: ASCII text dcmaster:/data/linktype # file -i hardlinkfile1 hardlinkfile1: text/plain; charset=us-ascii dcmaster:/data/linktype # file /data/linktype/ /data/linktype/: directory dcmaster:/data/linktype # file -L /data/linktype/ /data/linktype/: directory dcmaster:/data/linktype # file -i /data/linktype/ /data/linktype/: inode/directory; charset=binary dcmaster:/data/linktype # file symlinkfile1 symlinkfile1: symbolic link to file dcmaster:/data/linktype # file -i symlinkfile1 symlinkfile1: inode/symlink; charset=binary grep command \u00b6 You can specify search patterns in the form of regular expressions, although the basic grep command is limited in this regard. To search for more complex patterns, use the egrep command (or grep -E ) instead, which accepts extended regular expressions. To avoid having special characters in search patterns interpreted by the shell, enclose the pattern in quotation marks. Syntax: grep [options] search_pattern filename * egrep = grep -E * rgrep \u53c2\u6570 -a \u6216 --text : \u4e0d\u8981\u5ffd\u7565\u4e8c\u8fdb\u5236\u7684\u6570\u636e\u3002 -A<\u663e\u793a\u884c\u6570> \u6216 --after-context=<\u663e\u793a\u884c\u6570> : \u9664\u4e86\u663e\u793a\u7b26\u5408\u8303\u672c\u6837\u5f0f\u7684\u90a3\u4e00\u5217\u4e4b\u5916\uff0c\u5e76\u663e\u793a\u8be5\u884c\u4e4b\u540e\u7684\u5185\u5bb9\u3002 -b \u6216 --byte-offset : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u6807\u793a\u51fa\u8be5\u884c\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u7f16\u53f7\u3002 -B<\u663e\u793a\u884c\u6570> \u6216 --before-context=<\u663e\u793a\u884c\u6570> : \u9664\u4e86\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u5916\uff0c\u5e76\u663e\u793a\u8be5\u884c\u4e4b\u524d\u7684\u5185\u5bb9\u3002 -c \u6216 --count : \u8ba1\u7b97\u7b26\u5408\u6837\u5f0f\u7684\u5217\u6570\u3002 -C<\u663e\u793a\u884c\u6570> \u6216 --context=<\u663e\u793a\u884c\u6570> \u6216 -<\u663e\u793a\u884c\u6570> : \u9664\u4e86\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u5916\uff0c\u5e76\u663e\u793a\u8be5\u884c\u4e4b\u524d\u540e\u7684\u5185\u5bb9\u3002 -d <\u52a8\u4f5c> \u6216 --directories=<\u52a8\u4f5c> : \u5f53\u6307\u5b9a\u8981\u67e5\u627e\u7684\u662f\u76ee\u5f55\u800c\u975e\u6587\u4ef6\u65f6\uff0c\u5fc5\u987b\u4f7f\u7528\u8fd9\u9879\u53c2\u6570\uff0c\u5426\u5219grep\u6307\u4ee4\u5c06\u56de\u62a5\u4fe1\u606f\u5e76\u505c\u6b62\u52a8\u4f5c\u3002 -e<\u8303\u672c\u6837\u5f0f> \u6216 --regexp=<\u8303\u672c\u6837\u5f0f> : \u6307\u5b9a\u5b57\u7b26\u4e32\u505a\u4e3a\u67e5\u627e\u6587\u4ef6\u5185\u5bb9\u7684\u6837\u5f0f\u3002 -E \u6216 --extended-regexp : \u5c06\u6837\u5f0f\u4e3a\u5ef6\u4f38\u7684\u666e\u901a\u8868\u793a\u6cd5\u6765\u4f7f\u7528\u3002 -f<\u89c4\u5219\u6587\u4ef6> \u6216 --file=<\u89c4\u5219\u6587\u4ef6> : \u6307\u5b9a\u89c4\u5219\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u542b\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u89c4\u5219\u6837\u5f0f\uff0c\u8ba9grep\u67e5\u627e\u7b26\u5408\u89c4\u5219\u6761\u4ef6\u7684\u6587\u4ef6\u5185\u5bb9\uff0c\u683c\u5f0f\u4e3a\u6bcf\u884c\u4e00\u4e2a\u89c4\u5219\u6837\u5f0f\u3002 -F \u6216 --fixed-regexp : \u5c06\u6837\u5f0f\u89c6\u4e3a\u56fa\u5b9a\u5b57\u7b26\u4e32\u7684\u5217\u8868\u3002 -G \u6216 --basic-regexp : \u5c06\u6837\u5f0f\u89c6\u4e3a\u666e\u901a\u7684\u8868\u793a\u6cd5\u6765\u4f7f\u7528\u3002 -h \u6216 --no-filename : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u4e0d\u6807\u793a\u8be5\u884c\u6240\u5c5e\u7684\u6587\u4ef6\u540d\u79f0\u3002 -H \u6216 --with-filename : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u8868\u793a\u8be5\u884c\u6240\u5c5e\u7684\u6587\u4ef6\u540d\u79f0\u3002 -i \u6216 --ignore-case : \u5ffd\u7565\u5b57\u7b26\u5927\u5c0f\u5199\u7684\u5dee\u522b\u3002 -l \u6216 --file-with-matches : \u5217\u51fa\u6587\u4ef6\u5185\u5bb9\u7b26\u5408\u6307\u5b9a\u7684\u6837\u5f0f\u7684\u6587\u4ef6\u540d\u79f0\u3002 -L \u6216 --files-without-match : \u5217\u51fa\u6587\u4ef6\u5185\u5bb9\u4e0d\u7b26\u5408\u6307\u5b9a\u7684\u6837\u5f0f\u7684\u6587\u4ef6\u540d\u79f0\u3002 -n \u6216 --line-number : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u6807\u793a\u51fa\u8be5\u884c\u7684\u5217\u6570\u7f16\u53f7\u3002 -o \u6216 --only-matching : \u53ea\u663e\u793a\u5339\u914dPATTERN \u90e8\u5206\u3002 -q \u6216 --quiet\u6216--silent : \u4e0d\u663e\u793a\u4efb\u4f55\u4fe1\u606f\u3002 -r \u6216 --recursive : \u6b64\u53c2\u6570\u7684\u6548\u679c\u548c\u6307\u5b9a\"-d recurse\"\u53c2\u6570\u76f8\u540c\u3002 -s \u6216 --no-messages : \u4e0d\u663e\u793a\u9519\u8bef\u4fe1\u606f\u3002 -v \u6216 --revert-match : \u663e\u793a\u4e0d\u5305\u542b\u5339\u914d\u6587\u672c\u7684\u6240\u6709\u884c\u3002 -V \u6216 --version : \u663e\u793a\u7248\u672c\u4fe1\u606f\u3002 -w \u6216 --word-regexp : \u53ea\u663e\u793a\u5168\u5b57\u7b26\u5408\u7684\u5217\u3002 -x --line-regexp : \u53ea\u663e\u793a\u5168\u5217\u7b26\u5408\u7684\u5217\u3002 -y : \u6b64\u53c2\u6570\u7684\u6548\u679c\u548c\u6307\u5b9a\"-i\"\u53c2\u6570\u76f8\u540c\u3002 \u5728\u5f53\u524d\u76ee\u5f55\u4e2d\uff0c\u67e5\u627e\u540e\u7f00\u6709conf\u5b57\u6837\u7684\u6587\u4ef6\u4e2d\u5305\u542bxen\u5b57\u7b26\u4e32\u7684\u6587\u4ef6\uff0c\u5e76\u6253\u5370\u51fa\u8be5\u5b57\u7b26\u4e32\u7684\u884c\u3002 pmgr@dcmaster:/data/program/general> grep xen *.conf xen xening \u67e5\u627e\u524d\u7f00\u6709gen\u7684\u6587\u4ef6\u5305\u542bxen\u5b57\u7b26\u4e32\u7684\u6587\u4ef6 pmgr@dcmaster:/data/program/general> grep xen gen* xen xening \u4ee5\u9012\u5f52\u7684\u65b9\u5f0f\u67e5\u627e\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u3002\u67e5\u627e\u6307\u5b9a\u76ee\u5f55/data/program/\u53ca\u5176\u5b50\u76ee\u5f55\uff08\u5982\u679c\u5b58\u5728\u5b50\u76ee\u5f55\u7684\u8bdd\uff09\u4e0b\u6240\u6709\u6587\u4ef6\u4e2d\u5305\u542b\u5b57\u7b26\u4e32xen\u7684\u6587\u4ef6\uff0c\u5e76\u6253\u5370\u51fa\u8be5\u5b57\u7b26\u4e32\u6240\u5728\u884c\u7684\u5185\u5bb9 pmgr@dcmaster:/data> grep -r xen /data/program/ ./program/general/general.conf:xen ./program/general/general.conf:xening \u53cd\u5411\u67e5\u627e\u3002\u524d\u9762\u5404\u4e2a\u4f8b\u5b50\u662f\u67e5\u627e\u5e76\u6253\u5370\u51fa\u7b26\u5408\u6761\u4ef6\u7684\u884c\uff0c\u901a\u8fc7 -v \u53c2\u6570\u53ef\u4ee5\u6253\u5370\u51fa\u4e0d\u7b26\u5408\u6761\u4ef6\u884c\u7684\u5185\u5bb9\u3002\u67e5\u627e\u6587\u4ef6\u540d\u4e2d\u5305\u542bxen\u7684\u6587\u4ef6\u4e2d\u4e0d\u5305\u542bxen\u7684\u884c pmgr@dcmaster:/data/program/general> grep -v xen gen* Linux Test test \u67e5\u627e\u5f53\u524d\u76ee\u5f55\u4e0b\u5305\u542b\u5b57\u7b26\u4e32\u201cLinux\u201d\u7684\u6587\u4ef6 pmgr@dcmaster:/data/program/general> grep Linux * general.conf:Linux grep: staffing: Is a directory pmgr@dcmaster:/data/program/general> egrep Linux * general.conf:Linux grep: staffing: Is a directory","title":"Useful Commands"},{"location":"linux/Administration/02/#useful-commands","text":"","title":"Useful Commands"},{"location":"linux/Administration/02/#some-common-abbreviations","text":"Abbreviations Description . represents the current directory .. represents the parent directory ~ represents the home directory ~username represents the home directory of user username","title":"Some common abbreviations"},{"location":"linux/Administration/02/#software-package-documentation","text":"/usr/share/doc/packages/","title":"Software package documentation"},{"location":"linux/Administration/02/#release-notes","text":"/usr/share/doc/release-notes/","title":"Release Notes"},{"location":"linux/Administration/02/#command-help","text":" -h or --help # tree --help","title":"Command help"},{"location":"linux/Administration/02/#manual-pages","text":"man [ section ] command # man 5 crontab # man /sestion options Show tree command manual: # man tree List for keywords: # man -k keyword Force mandb to update. Normally this is done daily via a cron job. # mandb Search for all instances of a command or a file named crontab # man -f crontab # whatis crontab (same output with above command) # man -k crontab # apropos crontab (same output with above command) To go directly to a given man page: # man 5 crontab * 1G : go to the 1 st line * 10G : go to the 10 th line * G : go to the end of the page * /^SELinux : search the word SELinux * /section OPTIONS : go to the section OPTIONS man\u5171\u6709\u4ee5\u4e0b\u51e0\u4e2a\u7ae0\u8282\uff0c\u6bd4\u5982\uff0cman 5 crontab\u5c31\u662f\u8fdb\u5165crontab\u7684\u7b2c5\u7ae0\u8282\uff1a Executable programs or shell commands \uff08\u6807\u51c6\u547d\u4ee4\uff09 System calls (functions provided by the kernel)\uff08\u7cfb\u7edf\u8c03\u7528\uff09 Library calls (functions within program libraries)\uff08\u5e93\u51fd\u6570\uff09 Special files (usually found in /dev)\uff08\u8bbe\u5907\u8bf4\u660e\uff09 File formats and conventions eg /etc/passwd \uff08\u6587\u4ef6\u683c\u5f0f\uff09 Games \uff08\u6e38\u620f\u548c\u5a31\u4e50\uff09 Miscellaneous (including macro packages and conventions)\uff08\u6742\u9879\uff0c\u60ef\u4f8b\u4e0e\u534f\u5b9a\u7b49\u7f51\u7edc\u534f\u5b9a\u3001ASCII code\u7b49\u7b49\u7684\u8aaa\u660e\uff09 System administration commands (usually only for root) \uff08\u7ba1\u7406\u5458\u547d\u4ee4\uff09 Kernel routines [Non standard] \uff08\u5176\u4ed6Linux\u7279\u5b9a\u7684\uff0c\u7528\u6765\u5b58\u653e\u5185\u6838\u4f8b\u884c\u7a0b\u5e8f\u7684\u6587\u6863\u3002\uff09 man\u5e38\u7528\u5feb\u6377\u952e \u7ffb\u5c4f \u5411\u540e\u7ffb\u4e00\u5c4f\uff1aspace(\u7a7a\u683c\u952e) \u5411\u524d\u7ffb\u4e00\u5c4f\uff1ab \u5411\u540e\u7ffb\u4e00\u884c\uff1aEnter(\u56de\u8f66\u952e) \u5411\u524d\u7ffb\u4e00\u884c\uff1ak \u67e5\u627e /\u5173\u952e\u8bcd ?\u5173\u952e\u8bcd n (\u4e0b\u4e00\u4e2a) N (\u524d\u4e00\u4e2a) man \u4e2d\u6587\u5316\u3002\u5728 /etc/profile \u52a0\u5165\u4e0b\u9762alias\uff0c\u53ef\u4ee5\u5728man\u4e2d\u8f93\u51fa\u4e2d\u6587 # For man in zh_CH alias cman='man -M /usr/share/man/zh_CN'","title":"Manual pages"},{"location":"linux/Administration/02/#display-descriptions","text":"whatis command","title":"Display descriptions:"},{"location":"linux/Administration/02/#info-pages","text":"info command # info # info top From the terminal window display the info pages for the info command by entering: # info info Move the cursor to the line referring to (Invoking Info) by pressing Tab Tab Follow the link by pressing Enter Move the cursor to the link Note Custom Key Bindings: by pressing Tab (6 times) Follow the link by pressing Enter Return to the page Note Custom Key Bindings: by typing (lowercase L): l Exit the info file by typing: q","title":"Info pages:"},{"location":"linux/Administration/02/#pwd-command","text":"Display the current working directory","title":"pwd command"},{"location":"linux/Administration/02/#cd-command","text":"Change directory","title":"cd command"},{"location":"linux/Administration/02/#ls-command","text":"Display directory contents * Display hidden files with -a option * Detailed listing with -l option * Output is recursive, including all subdirectories with -R option * With option -F After each name, a character indicates the file type (\u201c/\u201d for directories, \u201c*\u201d for executable files, \u201c|\u201d for FIFO files, \u201c@\u201d symbolic link).","title":"ls command"},{"location":"linux/Administration/02/#cp-command","text":"Copy a file or directory Syntax: cp [option] Option -a : Copies a directory and subdirectories (compare -R ); symbolic links, file permissions, owners, and time stamps are not changed. \u5b83\u4fdd\u7559\u7b26\u53f7\u94fe\u63a5\u3001\u6587\u4ef6\u5c5e\u6027\uff0c\u5e76\u590d\u5236\u76ee\u5f55\u4e0b\u7684\u6240\u6709\u5185\u5bb9\u3002\u5176\u4f5c\u7528\u7b49\u4e8e-dpR\u53c2\u6570\u7ec4\u5408\u3002 Option -I : Asks before overwriting. Option -R , -r : Copies directories recursively (the directory and any subdirectories). \u9012\u5f52\u62f7\u8d1d\uff0c\u5305\u542b\u5b50\u76ee\u5f55\u53ca\uff08\u9690\u542b\uff09\u6587\u4ef6\uff0c\u7ee7\u627f\u76ee\u6807\u76ee\u5f55\u7684\u6743\u9650\u548c\u5c5e\u6027\u7b49 Option -l : Makes hardlinks instead of copying (\u521b\u5efa\u786c\u94fe\u63a5\u7684\u53e6\u5916\u4e00\u4e2a\u65b9\u6cd5) Option -s : Makes symbolic instead of copying (\u521b\u5efa\u7b26\u53f7\u94fe\u63a5\u7684\u53e6\u5916\u4e00\u4e2a\u65b9\u6cd5) Option -u : Copies a file only when the source file is newer than the destination file or when the destination file is missing. Option -p : \u8fde\u540c\u6863\u6848\u7684\u5c5e\u6027\u4e00\u8d77\u590d\u5236\u8fc7\u53bb\uff0c\u5305\u62ec\u4fee\u6539\u65f6\u95f4\u3001\u8bbf\u95ee\u6743\u9650\u3001\u6240\u6709\u8005\u7ec4\u7b49\uff0c\u800c\u975e\u4f7f\u7528\u9884\u8bbe\u5c5e\u6027\uff1b Labs: Initiate directories and files mySUSE:~ # su - pmgr pmgr@mySUSE:~> mkdir /data/program pmgr@mySUSE:~> mkdir /data/program/general pmgr@mySUSE:~> mkdir /data/program/general/staffing pmgr@mySUSE:~> touch /data/program/general/program_scope pmgr@mySUSE:~> touch /data/program/general/staffing/assignment mySUSE:~ # su - pm1 pm1@mySUSE:~> mkdir /data/project1 pm1@mySUSE:~> mkdir /data/project1/iot pm1@mySUSE:~> mkdir /data/project1/iot/bigdata pm1@mySUSE:~> touch /data/project1/iot/devicelist pm1@mySUSE:~> touch /data/project1/iot/bigdata/math_lib mySUSE:~ # su - pm2 pm2@mySUSE:~> mkdir /data/project2 pm2@mySUSE:~> mkdir /data/project2/erp pm2@mySUSE:~> mkdir /data/project2/erp/fin pm2@mySUSE:~> touch /data/project2/erp/erp_vision pm2@mySUSE:~> touch /data/project2/erp/fin/fin_ar pm2@mySUSE:~> chmod g+w /data/project2/erp/erp_vision pmgr@mySUSE:~> ln /data/project2/erp/erp_vision /data/program/general/p2_erp_version ( \u521b\u5efa\u786c\u94fe\u63a5\uff0c\u5f53\u524d\u7528\u6237\u9700\u8981\u5bf9\u6e90\u6587\u4ef6erp_vision\u6709w\u6743\u9650 ) pmgr@mySUSE:~> ln -s /data/project1/iot/devicelist /data/program/general/p1_devicelist ( \u521b\u5efa\u7b26\u53f7\u94fe\u63a5\uff0c\u4e0d\u9a8c\u8bc1\u5f53\u524d\u7528\u6237\u662f\u5426\u5bf9\u6e90\u6587\u4ef6devicelist\u6709\u6743\u9650 ) mySUSE:~ # tree /data /data \u251c\u2500\u2500 program \u2502 \u2514\u2500\u2500 general \u2502 \u251c\u2500\u2500 p1_devicelist -> /data/project1/iot/devicelist \u2502 \u251c\u2500\u2500 p2_erp_version \u2502 \u251c\u2500\u2500 program_scope \u2502 \u2514\u2500\u2500 staffing \u2502 \u2514\u2500\u2500 assignment \u251c\u2500\u2500 project1 \u2502 \u2514\u2500\u2500 iot \u2502 \u251c\u2500\u2500 bigdata \u2502 \u2502 \u2514\u2500\u2500 math_lib \u2502 \u2514\u2500\u2500 devicelist \u2514\u2500\u2500 project2 \u2514\u2500\u2500 erp \u251c\u2500\u2500 erp_vision \u2514\u2500\u2500 fin \u2514\u2500\u2500 fin_ar pmgr@mySUSE:~> cp -R /data/project1 /data/program/ ( /data/program/project1\u7684\u7528\u6237\u548c\u7ec4\u90fd\u7ee7\u627f\u4e86/data/program/ ) pmgr@mySUSE:~> cp -a /data/project2 /data/program/ ( /data/program/project2\u7684\u7528\u6237\u7ee7\u627f\u4e86/data/program/\uff0c\u4f46\u7ec4\u8fd8\u662f\u4fdd\u7559\u539f\u6765\u7684 )","title":"cp command"},{"location":"linux/Administration/02/#mv-command","text":"Move or rename a file or directory Option -i : Asks for confirmation before moving or renaming a file. This prevents existing files with the same name from being overwritten. Option -u : Only moves files that are newer than the target files of the same name. pmgr@mySUSE:/data/program/general> cp program_scope ./staffing/ pmgr@mySUSE:/data/program/general> mv -i program_scope ./staffing/ mv: overwrite './staffing/program_scope'? n","title":"mv command"},{"location":"linux/Administration/02/#rm-command","text":"Delete a file or directory Option -i : Asks for confirmation before deleting. Option -r : (recursively) Allows full directories to be deleted. Option -f : (force) By default, rm asks for confirmation if the file that should be deleted is read-only. Using this option, the files are deleted without asking for confirmation.","title":"rm command"},{"location":"linux/Administration/02/#mkdir-command","text":"Create a new directory Option -p lets you create a complete path (\u5c42\u7ea7\u8def\u5f84\u4e00\u6b21\u521b\u5efa) pmgr@mySUSE:/data> mkdir -p industry/utilities pmgr@mySUSE:/data> tree ./industry/ ./industry/ \u2514\u2500\u2500 utilities","title":"mkdir command"},{"location":"linux/Administration/02/#rmdir-command","text":"Remove an empty directory. The directory or directories must be empty before you can delete them.","title":"rmdir command"},{"location":"linux/Administration/02/#ln-command","text":"Create a link Default: Hard link Symbolic link with -s option Syntax: ln [-s] ","title":"ln command"},{"location":"linux/Administration/02/#touch-command","text":"Change the access and modification times Create an empty file if the given file does not exist. Change the time stamp of a file. Option -a : Changes only the time of the last read access (access time). Option -m : Changes only the time of the last modification (modification time). Option -r file : Sets the time stamp of file instead of the current time. Option -t time : Instead of the current time, sets time (structure: [[CC]YY]MMDDhhmm.[ss] ([Century]Year] Month Day Hour Minute [Seconds], two digits in each)) pmgr@mySUSE:/data/industry> touch readme pmgr@mySUSE:/data/industry> touch -a readme pmgr@mySUSE:/data/industry> touch -m readme pmgr@mySUSE:/data/industry> stat readme File: readme Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: 3dh/61d Inode: 338 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 1003/ pmgr) Gid: ( 1000/ admins) Access: 2019-03-31 10:07:47.489055973 +0800 Modify: 2019-03-31 10:07:58.805109884 +0800 Change: 2019-03-31 10:07:58.805109884 +0800 Birth: -","title":"touch command"},{"location":"linux/Administration/02/#cat-command","text":"Concatenates files","title":"cat command"},{"location":"linux/Administration/02/#tac-command","text":"Same as cat, but displays the file(s) in reverse pmgr@mySUSE:/data/industry> cat readme line 1 line 2 line 3 pmgr@mySUSE:/data/industry> tac readme line 3 line 2 line 1","title":"tac command"},{"location":"linux/Administration/02/#more-command","text":"Display file contents one page at a time","title":"more command"},{"location":"linux/Administration/02/#less-command","text":"Displays file contents for better navigation","title":"less command"},{"location":"linux/Administration/02/#head-command","text":"Displays the first 10 lines of a file. To set the number of lines use the -n option pmgr@mySUSE:/data/industry> head readme line 1 line 2 line 3 line 4 line 5 line 6 line 7 line 8 line 9 line 10 pmgr@mySUSE:/data/industry> head -n 5 readme line 1 line 2 line 3 line 4 line 5","title":"head command"},{"location":"linux/Administration/02/#tail-command","text":"Display the last lines of a file To set the number of lines use the -n option To output appended data use -f option, displays a continuously updated view of the last lines of a file. To exit tail -f, press Ctrl+C. pmgr@mySUSE:/data/industry> tail -n 6 readme line 10 line 11 line 12 line 13 line 14 line 15","title":"tail command"},{"location":"linux/Administration/02/#tar-command","text":"Create, expand or list archive files Use option c to create an archive Use option f to specify the archive file name Use option v for verbose mode Use option x to extract an archive Use option t to list the content of an archive Use option z to (un-)compress the archive with gzip Use option j to (un-)compress the archive with bzip The /etc directory (include sub-directories) is backed up to the /backup/etc.tar file pmgr@mySUSE:~> tar -cvf /data/backup/project1.tar /data/project1/ pmgr@mySUSE:~> tar -cvf /data/backup/project2.tar /data/project2/ pmgr@mySUSE:~> tar -cv --exclude='*.conf' -f /data/backup/project2a.tar /data/project2/ View the contents of an archive. Some .conf files are excluded in project2a.tar file. pmgr@mySUSE:~> tar -tvf /data/backup/project2.tar drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/fin/ -rw-r--r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/fin/fin_ar -rw-r--r-- pm2/project2 0 2019-03-31 16:47 data/project2/erp/fin/fin.conf -rw-rw-r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/erp_vision -rw-r--r-- pm2/project2 0 2019-03-31 16:47 data/project2/erp/erp.conf -rw-r--r-- pm2/project2 0 2019-03-31 16:47 data/project2/project2.conf pmgr@mySUSE:~> tar -tvf /data/backup/project2a.tar drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/fin/ -rw-r--r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/fin/fin_ar -rw-rw-r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/erp_vision Unpack and write all files in the archive to the current directory. Extract to another directory by using the -C option pmgr@mySUSE:~> mkdir project1.backup pmgr@mySUSE:~> tar -xvf /data/backup/project1.tar -C /data/backup/project1.backup/ Incremental backup with tar command pmgr@mySUSE:~> tar -g snapshot_program -cvf /data/backup/bkp_program_full.tar /data/program/ pmgr@mySUSE:~> tar -tvf /data/backup/bkp_program_full.tar pmgr@mySUSE:~> touch /data/program/general/general.conf pmgr@mySUSE:~> tar -g snapshot_program -cvf /data/backup/bkp_program_inc.tar /data/program/ pmgr@mySUSE:~> rm -rf program/ pmgr@mySUSE:~> tar -xvf /data/backup/bkp_program_inc.tar -C /data/","title":"tar command"},{"location":"linux/Administration/02/#cpio-command","text":"Another archiving command","title":"cpio command"},{"location":"linux/Administration/02/#gzip-command","text":"Compress files using the gzip algorithm Option -c : Compresses the file without modifying the original file. The result is written to the standard output (usually the screen). From there, it can be redirected to a file with \u201c>\u201d. Option -d : Decompresses the specified file (gunzip) Option -r : Compresses and decompresses files in all subdirectories. Option -1 to -9, --fast, --best : Controls the compression speed: -1 means --fast and causes a quick compression but produces larger files, -9 corresponds to --best and requires more computing time but produces smaller files. The default setting is -6.","title":"gzip command"},{"location":"linux/Administration/02/#gunzip-command","text":"Expand files compressed with gzip","title":"gunzip command"},{"location":"linux/Administration/02/#bzip2-command","text":"Compress files using the bzip2 algorithm Option -c : Option -d : Decompresses the specified file (bunzip2). Option -1 to -9 : Controls the compression speed: -1 causes a quick compression but produces larger files, -9 requires more computing time but produces smaller files. The default setting is -9 .","title":"bzip2 command"},{"location":"linux/Administration/02/#bunzip2-command","text":"Expand files compressed with bzip","title":"bunzip2 command"},{"location":"linux/Administration/02/#rsync-command","text":"Copy only deltas between two directories. A key benefit of using rsync is that when copying data, rsync compares the source and the target directory and transfers only data that has changed or has been created. \u4ec5\u590d\u5236\u4e24\u4e2a\u76ee\u5f55\u4e4b\u95f4\u7684\u589e\u91cf\u3002 \u4f7f\u7528rsync\u7684\u4e00\u4e2a\u4e3b\u8981\u597d\u5904\u662f\uff0c\u5728\u590d\u5236\u6570\u636e\u65f6\uff0crsync\u4f1a\u6bd4\u8f83\u6e90\u76ee\u5f55\u548c\u76ee\u6807\u76ee\u5f55\uff0c\u5e76\u4ec5\u4f20\u8f93\u5df2\u66f4\u6539\u6216\u5df2\u521b\u5efa\u7684\u6570\u636e\u3002 Local or via network \u672c\u5730\u6216\u901a\u8fc7\u7f51\u7edc Uses ssh as default transport \u4f7f\u7528ssh\u4f5c\u4e3a\u9ed8\u8ba4\u4f20\u8f93 Can talk to rsync daemon on the remote machine \u53ef\u4ee5\u4e0e\u8fdc\u7a0b\u8ba1\u7b97\u673a\u4e0a\u7684rsync\u5b88\u62a4\u7a0b\u5e8f\u901a\u4fe1 Note: rsync must be installed on both the source and the target computer for this to work. \u5fc5\u987b\u5728\u6e90\u8ba1\u7b97\u673a\u548c\u76ee\u6807\u8ba1\u7b97\u673a\u4e0a\u5b89\u88c5rsync\u624d\u80fd\u4f7f\u5176\u6b63\u5e38\u5de5\u4f5c\u3002 As the default shell used by rsync is ssh, the -e option only needs to be used when you want to use something else than ssh. \u7531\u4e8ersync\u4f7f\u7528\u7684\u9ed8\u8ba4shell\u662fssh\uff0c\u56e0\u6b64\u53ea\u6709\u5728\u60f3\u8981\u4f7f\u7528\u9664ssh\u4ee5\u5916\u7684\u5176\u4ed6\u5de5\u5177\u65f6\u624d\u9700\u8981\u4f7f\u7528-e\u9009\u9879\u3002 Options Option -a : Puts rsync into the archive mode. The -a option ensures the following are preserved \u4fdd\u7559 in the mirrored copy of the directory: Symbolic links (l option) Access permissions (p option) Owners (o option) Group membership (g option) Time stamp (t option) Option -x : Saves files on one file system only, which means that rsync does not follow symbolic links to other file systems. \u4e0d\u8de8\u6587\u4ef6\u7cfb\u7edf\uff0c\u53ea\u5728\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u5185(don't cross filesyste* undaries) Option -v : Enables the verbose mode. Use this mode to output information about the transferred files and the progress of the copying process. \u8f93\u51fa\u4f20\u8f93\u8fc7\u7a0b\u7684\u7ec6\u8282\u4fe1\u606f Option -z : Compresses the data during the transfer. This is especially useful for remote synchronization. \u538b\u7f29\u65b9\u5f0f\u4f20\u8f93 Option --delete : Deletes files from the mirrored directory that no longer exist in the original directory. Option --exclude-from : Does not back up files listed in an exclude file. Local backup via rsync command pmgr@mySUSE:/data> rsync -av /data/industry/* /data/backup/industry/ sending incremental file list created directory /data/backup/industry readme utilities/ sent 264 bytes received 87 bytes 702.00 bytes/sec total size is 111 speedup is 0.32 pmgr@mySUSE:/data/industry/utilities> touch roadmap.txt pmgr@mySUSE:/data> rsync -av /data/industry/* /data/backup/industry/ sending incremental file list utilities/ utilities/roadmap.txt sent 171 bytes received 39 bytes 420.00 bytes/sec total size is 111 speedup is 0.53 pmgr@mySUSE:/data> rm roadmap.txt pmgr@mySUSE:/data> rsync -av /data/industry/* --delete /data/backup/industry/ sending incremental file list deleting utilities/roadmap.txt utilities/ sent 102 bytes received 41 bytes 286.00 bytes/sec total size is 111 speedup is 0.78","title":"rsync command"},{"location":"linux/Administration/02/#dd-command","text":"Copies files block by block Used to create disk or partition images Most important options: if =input_file `of``=output_file bs =block_size You can use the dd command to convert and copy files byte-wise. Normally dd reads from the standard input and writes the result to the standard output. But with the appropriate parameters, regular files can be addressed as well. You can copy all kinds of Linux data with this command, including entire hard disk partitions. You can even copy an entire installed system (or just parts of it). Copy file /etc/protocols to protocols.old. The default size for a record is 512 bytes. Below 45+1 means, 45 complete record of standard size and 1 incomplete record (less than 512 bytes pmgr@mySUSE:/data/program> dd if=/etc/protocols of=protocols.old bs=512 45+1 records in 45+1 records out 23259 bytes (23 kB, 23 KiB) copied, 0.000595392 s, 39.1 MB/s \u521b\u5efa\u4e00\u4e2a100M\u7684\u7a7a\u6587\u4ef6 pmgr@mySUSE:/data/program> dd if=/dev/zero of=datafile bs=100M count=2 2+0 records in 2+0 records out 209715200 bytes (210 MB, 200 MiB) copied, 2.79311 s, 75.1 MB/s \u5907\u4efd\u6574\u4e2a\u5206\u533a #dd if=/dev/sda1 of=boot.partition \u5236\u4f5cU\u76d8\u542f\u52a8\u76d8\uff08U\u76d8\u6302\u8f7d\u5230/dev/sdb\uff09 #dd if=/root/diskboot.img of=/dev/sdb bs=125682176 \u5907\u4efd\u786c\u76d8\u4e3b\u5f15\u5bfc\u8bb0\u5f55 #dd if=/dev/sda of=/tmp/mbr_copy bs=512 count=1 \u8fd8\u539f\u786c\u76d8\u4e3b\u5f15\u5bfc\u8bb0\u5f55 #dd if=/disk.mbr of=/dev/hda bs=512 count=1 \u5c06\u5185\u5b58\u91cc\u7684\u6570\u636e\u62f7\u8d1d\u5230root\u76ee\u5f55\u4e0b\u7684mem.bin\u6587\u4ef6 # dd if=/dev/mem of=/root/mem.bin bs=1024 \u62f7\u8d1d\u5149\u76d8\u6570\u636e\u5230root\u6587\u4ef6\u5939\u4e0b\uff0c\u5e76\u4fdd\u5b58\u4e3acd.iso\u6587\u4ef6 # dd if=/dev/cdrom of=/root/cd.iso \u5229\u7528\u968f\u673a\u7684\u6570\u636e\u586b\u5145\u786c\u76d8(\u9500\u6bc1\u786c\u76d8\u6570\u636e) # dd if=/dev/urandom of=/dev/hda1 \u6d4b\u8bd5\u786c\u76d8\u8bfb\u5199\u901f\u5ea6\u3002\u901a\u8fc7\u4e24\u4e2a\u547d\u4ee4\u8f93\u51fa\u7684\u6267\u884c\u65f6\u95f4\uff0c\u53ef\u4ee5\u8ba1\u7b97\u51fa\u6d4b\u8bd5\u786c\u76d8\u7684\u8bfb\uff0f\u5199\u901f\u5ea6\uff1a mySUSE:/data # dd if=/data/program/datafile bs=64k | dd of=/dev/null 3200+0 records in 3200+0 records out 209715200 bytes (210 MB, 200 MiB) copied, 0.67138 s, 312 MB/s 409600+0 records in 409600+0 records out 209715200 bytes (210 MB, 200 MiB) copied, 0.675912 s, 310 MB/s # dd if=/dev/zero of=/data/program/datafile bs=1024 count=100 \u5207\u5272\u5927\u6587\u4ef6bigfile\uff0c\u517198336321\u5b57\u8282\uff0c\u5219\uff1a # dd if=bigfile of=smallfile1 bs=1 count=20000000 # dd if=bigfile of=smallfile2 bs=1 count=20000000 skip=20000000 # dd if=bigfile of=smallfile3 bs=1 count=20000000 skip=40000000 # dd if=bigfile of=smallfile4 bs=1 count=20000000 skip=60000000 # dd if=bigfile of=smallfile5 bs=1 count=18336321 skip=80000000 \u5c06\u5207\u5272\u6587\u4ef6\u7ec4\u88c5 # dd if=smallfile1 of=bigfile bs=1 count=20000000 # dd if=smallfile2 of=bigfile bs=1 count=20000000 seek=20000000 # dd if=smallfile3 of=bigfile bs=1 count=20000000 seek=40000000 # dd if=smallfile4 of=bigfile bs=1 count=20000000 seek=60000000 # dd if=smallfile5 of=bigfile bs=1 count=18336321 seek=80000000 if: \u8981\u5207\u5272\u7684\u5927\u6587\u4ef6\u540d of: \u5207\u5272\u540e\u7684\u5b50\u6587\u4ef6\u540d bs: \u4ee5\u591a\u5c11\u5b57\u8282\u4f5c\u4e3a\u4e00\u4e2a\u5207\u5272\u8bb0\u5f55\u5355\u4f4d count: \u662f\u8981\u5207\u5272\u7684\u5355\u4f4d\u8bb0\u5f55\u6570 skip: \u8bf4\u660e\u5207\u5272\u65f6\u7684\u8d77\u70b9 seek: \u660e\u786e\u6307\u51fa\u5f00\u59cb\u4f4d\u7f6e","title":"dd command"},{"location":"linux/Administration/02/#find-command","text":"Search for files or directories Syntax: find path criterion [action] The find command has a multitude of options, a few of which are explained here. You can use the following arguments with the command: path: The section of the file system to search (the specified directory and all its subdirectories). If nothing is specified, the file system below the current directory is used. criterion: The properties the file should have (see below) action: Options that influence the following conditions or control the search as a whole The most important actions are: -print (default) -exec command With the -exec option, you can call up another command. This option is frequently used to link find and grep, as in the following: \u627e\u51fagen\u5f00\u5934\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -name gen\\* ./program/general ./program/general/general.conf \u627e\u51fagen\u5f00\u5934\u7684\u6587\u4ef6\uff0c\u5e76\u5728\u6587\u4ef6\u5185\u5bb9\u4e2d\u67e5\u627exen\uff0c\u627e\u5230\u540e\u7ed3\u679c\u8f93\u51faxen pmgr@dcmaster:/data> find . -name gen\\* -type f -exec grep xen {} \\; xen xening The two brackets \u201c{}\u201d stand as placeholders for the file names which are found and passed to the grep command. The semicolon closes the -exec instruction. Because this is a special character, it is masked by placing a backslash in front of it. -ctime [\u00b1]days Searches for files whose last change took place no later than (no earlier than) a specified number of days ago. \u5728\u8fc7\u53bbn\u5929\u5185\u88ab\u4fee\u6539\u8fc7\u7684\u6587\u4ef6 mgr@dcmaster:/data> find . -ctime 1 . ./program/datafile -gid number Searches for files with the numeric GID (Group ID) number. (gid \u662f n) -group name Searches for files that are owned by the group name. Instead of a name, the numeric GID is allowed. (group \u540d\u79f0\u662f name) -name pattern Searches for files whose names contain the given pattern. If the pattern contains meta characters or wild cards, the name must be enclosed by quotation marks. Otherwise thename will be interpreted by the shell and not by find. -newer file Searches for files that were modified more recently than file. \u6bd4\u6587\u4ef6 file \u66f4\u65b0\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -cnewer ./program/datafile . -size [\u00b1]size Matches files that are above or below a certain size. The size (in blocks of 512 bytes) is given as an argument. The suffix \u201cc\u201cswitches to byte and \u201ck\u201d to blocks of 1024bytes. A preceding \u201c+\u201d stands for all larger files and a \u201c-\u201d for all smaller files. (\u6587\u4ef6\u5927\u5c0f \u662f n \u2022 b \u4ee3\u8868 512 \u4f4d\u5143\u7ec4\u7684\u533a\u5757 \u2022 c \u8868\u793a\u5b57\u5143\u6570 \u2022 k \u8868\u793a kilo bytes \u2022 w \u662f\u4e8c\u4e2a\u4f4d\u5143\u7ec4 pmgr@dcmaster:/data> find . -size 20k ./backup/project2.tar -type file_type Searches for a file type. A file type can be one of the following: * c : \u6587\u4ef6\u7c7b\u578b\u662f c \u7684\u6587\u4ef6\u3002 * d: \u76ee\u5f55 * c: \u5b57\u578b\u88c5\u7f6e\u6587\u4ef6 * b: \u533a\u5757\u88c5\u7f6e\u6587\u4ef6 * p: \u5177\u540d\u8d2e\u5217 * f: \u4e00\u822c\u6587\u4ef6 * l: \u7b26\u53f7\u8fde\u7ed3 * s: socket -uid number Searches for files with the numeric UID (User ID) number. -user name Searches for files, which are owned by user name. Instead of a name, the numeric UID is allowed. \u5e38\u7528\u53c2\u6570 mount, -xdev : \u53ea\u68c0\u67e5\u548c\u6307\u5b9a\u76ee\u5f55\u5728\u540c\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u4e0b\u7684\u6587\u4ef6\uff0c\u907f\u514d\u5217\u51fa\u5176\u5b83\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6587\u4ef6 amin n : \u5728\u8fc7\u53bb n \u5206\u949f\u5185\u88ab\u8bfb\u53d6\u8fc7 anewer file : \u6bd4\u6587\u4ef6 file \u66f4\u665a\u88ab\u8bfb\u53d6\u8fc7\u7684\u6587\u4ef6 atime n : \u5728\u8fc7\u53bbn\u5929\u5185\u88ab\u8bfb\u53d6\u8fc7\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -atime 1 ./program/datafile cmin n : \u5728\u8fc7\u53bb n \u5206\u949f\u5185\u88ab\u4fee\u6539\u8fc7 pmgr@dcmaster:/data> find . -cmin 20 empty : \u7a7a\u7684\u6587\u4ef6 ipath p, -path p : \u8def\u5f84\u540d\u79f0\u7b26\u5408 p \u7684\u6587\u4ef6\uff0cipath \u4f1a\u5ffd\u7565\u5927\u5c0f\u5199 name name, -iname name : \u6587\u4ef6\u540d\u79f0\u7b26\u5408 name \u7684\u6587\u4ef6\u3002iname \u4f1a\u5ffd\u7565\u5927\u5c0f\u5199 pid n : process id \u662f n \u7684\u6587\u4ef6 \u67e5\u627e\u5f53\u524d\u76ee\u5f55\u53ca\u5b50\u76ee\u5f55\u4e2d\u6240\u6709\u6587\u4ef6\u957f\u5ea6\u4e3a0\u7684\u666e\u901a\u6587\u4ef6\uff0c\u5e76\u5217\u51fa\u5b83\u4eec\u7684\u5b8c\u6574\u8def\u5f84 pmgr@dcmaster:/data> find . -type f -size 0 -exec ls -l {} \\; \u67e5\u627e\u524d\u76ee\u5f55\u4e2d\u6587\u4ef6\u5c5e\u4e3b\u5177\u6709\u8bfb\u3001\u5199\u6743\u9650\uff0c\u5e76\u4e14\u6587\u4ef6\u6240\u5c5e\u7ec4\u7684\u7528\u6237\u548c\u5176\u4ed6\u7528\u6237\u5177\u6709\u8bfb\u6743\u9650\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -type f -perm 644 -exec ls -l {} \\; \u67e5\u627e/var/log\u76ee\u5f55\u4e2d\u66f4\u6539\u65f6\u95f4\u572817\u65e5\u4ee5\u524d\u7684\u666e\u901a\u6587\u4ef6\uff0c\u5e76\u5728\u5220\u9664\u4e4b\u524d\u8be2\u95ee\u5b83\u4eec pmgr@dcmaster:/data> find /var/log -type f -mtime +17 -ok rm {} \\; \u5c06\u76ee\u524d\u76ee\u5f55\u53ca\u5176\u5b50\u76ee\u5f55\u4e0b\u6240\u6709\u6700\u8fd1 1 \u5929\u5185\u66f4\u65b0\u8fc7\u7684\u6587\u4ef6\u5217\u51fa mgr@dcmaster:/data> find . -ctime 1 \u5c06\u76ee\u524d\u76ee\u5f55\u5176\u5176\u4e0b\u5b50\u76ee\u5f55\u4e2d\u6240\u6709\u4e00\u822c\u6587\u4ef6\u5217\u51fa pmgr@dcmaster:/data> find . -type f \u5c06\u76ee\u524d\u76ee\u5f55\u53ca\u5176\u5b50\u76ee\u5f55\u4e0b\u6240\u6709\u5ef6\u4f38\u6863\u540d\u662fconf \u7684\u6587\u4ef6\u5217\u51fa\u6765 pmgr@dcmaster:/data> find . -name \"*.conf\"","title":"find command"},{"location":"linux/Administration/02/#which-command","text":"Searches all paths listed in the variable $PATH and returns the full path of the command The which command searches all paths listed in the variable $PATH for the specified command and returns the full path of the command. In the variable \\(PATH, the most important directoriesare listed where the shell looks for executable files. which\u547d\u4ee4\u641c\u7d22\u53d8\u91cf\\) PATH\u4e2d\u5217\u51fa\u7684\u6240\u6709\u8def\u5f84\u4ee5\u83b7\u53d6\u6307\u5b9a\u547d\u4ee4\uff0c\u5e76\u8fd4\u56de\u547d\u4ee4\u7684\u5b8c\u6574\u8def\u5f84\u3002 The which command is especially useful if several versions of a command exist in different directories and you want to know which version is executed when entered without specifying apath. \u5982\u679c\u547d\u4ee4\u7684\u591a\u4e2a\u7248\u672c\u5b58\u5728\u4e8e\u4e0d\u540c\u7684\u76ee\u5f55\u4e2d\uff0c\u5e76\u4e14\u60a8\u60f3\u77e5\u9053\u5728\u8f93\u5165\u65f6\u6267\u884c\u4e86\u54ea\u4e2a\u7248\u672c\u800c\u672a\u6307\u5b9a\u8def\u5f84\uff0c\u90a3\u4e48which\u547d\u4ee4\u7279\u522b\u6709\u7528\u3002 NOTE: To see the content of a variable, use the echo command Options Description -n<\u6587\u4ef6\u540d\u957f\u5ea6> \u6307\u5b9a\u6587\u4ef6\u540d\u957f\u5ea6\uff0c\u6307\u5b9a\u7684\u957f\u5ea6\u5fc5\u987b\u5927\u4e8e\u6216\u7b49\u4e8e\u6240\u6709\u6587\u4ef6\u4e2d\u6700\u957f\u7684\u6587\u4ef6\u540d\u3002 -p<\u6587\u4ef6\u540d\u957f\u5ea6> \u4e0e-n\u53c2\u6570\u76f8\u540c\uff0c\u4f46\u6b64\u5904\u7684<\u6587\u4ef6\u540d\u957f\u5ea6>\u5305\u62ec\u4e86\u6587\u4ef6\u7684\u8def\u5f84\u3002 -w \u6307\u5b9a\u8f93\u51fa\u65f6\u680f\u4f4d\u7684\u5bbd\u5ea6\u3002 -V \u663e\u793a\u7248\u672c\u4fe1\u606f # which grep /usr/bin/grep # which -V grep GNU which v2.21, Copyright (C) 1999 - 2015 Carlo Wood. GNU which comes with ABSOLUTELY NO WARRANTY; This program is free software; your freedom to use, change and distribute this program is protected by the GPL.","title":"which command"},{"location":"linux/Administration/02/#whereis-command","text":"The whereis command returns the binaries (option -b), manual pages (option -m), and the source code (option -s) of the specified command. If no option is used, all this information is returned, provided the information is available. This command is faster than find, but it is less thorough. Attempts to locate the desired program in the standard Linux places, and in the places specified by $PATH and $MANPATH . \u5c1d\u8bd5\u5728\u6807\u51c6Linux\u4f4d\u7f6e\u548c\u6307\u5b9a\u4f4d\u7f6e( \\(PATH\u548c\\) MANPATH)\u627e\u5230\u6240\u9700\u7684\u7a0b\u5e8f Options Description -b \u53ea\u67e5\u627e\u4e8c\u8fdb\u5236\u6587\u4ef6\u3002 -B<\u76ee\u5f55> \u53ea\u5728\u8bbe\u7f6e\u7684\u76ee\u5f55\u4e0b\u67e5\u627e\u4e8c\u8fdb\u5236\u6587\u4ef6\u3002 -f \u4e0d\u663e\u793a\u6587\u4ef6\u540d\u524d\u7684\u8def\u5f84\u540d\u79f0\u3002 -m \u53ea\u67e5\u627e\u8bf4\u660e\u6587\u4ef6\u3002 -M<\u76ee\u5f55> \u53ea\u5728\u8bbe\u7f6e\u7684\u76ee\u5f55\u4e0b\u67e5\u627e\u8bf4\u660e\u6587\u4ef6\u3002 -s \u53ea\u67e5\u627e\u539f\u59cb\u4ee3\u7801\u6587\u4ef6\u3002 -S<\u76ee\u5f55> \u53ea\u5728\u8bbe\u7f6e\u7684\u76ee\u5f55\u4e0b\u67e5\u627e\u539f\u59cb\u4ee3\u7801\u6587\u4ef6\u3002 -u \u67e5\u627e\u4e0d\u5305\u542b\u6307\u5b9a\u7c7b\u578b\u7684\u6587\u4ef6\u3002 \u4ee5\u4e0b\u8f93\u51fa\u4fe1\u606f\u4ece\u5de6\u81f3\u53f3\u5206\u522b\u4e3a\u67e5\u8be2\u7684\u7a0b\u5e8f\u540d\u3001bash\u8def\u5f84\u3001bash\u7684man\u624b\u518c\u9875\u8def\u5f84\u3002 # whereis grep grep: /usr/bin/grep /bin/grep /usr/share/man/man1/grep.1.gz /usr/share/info/grep.info.gz \u663e\u793abash \u547d\u4ee4\u7684\u4e8c\u8fdb\u5236\u7a0b\u5e8f # whereis -b grep grep: /usr/bin/grep /bin/grep \u663e\u793abash \u547d\u4ee4\u7684\u5e2e\u52a9\u6587\u4ef6 # whereis -m grep grep: /usr/share/man/man1/grep.1.gz /usr/share/info/grep.info.gz","title":"whereis command"},{"location":"linux/Administration/02/#type-command","text":"The type command shows what kind of command is executed when you enter it: \u547d\u4ee4\u7684\u7c7b\u578b a shell built-in command (an essential command that is hard coded in the shell), for example type or cd an external command (called by the shell) an alias, for example ls. An alias defines shortcuts and synonyms for commonly used shell commands. a function The -a option delivers all instances of a command bearing this name in the file system. NOTE: If you want to have more information about a file format, you can use the file command. \u4e0d\u9002\u7528\u4e8e\u666e\u901a\u6587\u4ef6 dcmaster:/data/shell # type pwd.txt -bash: type: pwd.txt: not found \u4e0d\u9002\u7528\u4e8e\u81ea\u5b9a\u4e49\u53ef\u6267\u884c\u811a\u672c dcmaster:/data/shell # type math.sh -bash: type: math.sh: not found \u7cfb\u7edf\u547d\u4ee4 dcmaster:/data/shell # type rsync rsync is /usr/bin/rsync \u522b\u540d dcmaster:/data/shell # type l l is aliased to `ls -alF'","title":"type command"},{"location":"linux/Administration/02/#file-command","text":"file\u547d\u4ee4\u7528\u4e8e\u8fa8\u8bc6\u6587\u4ef6\u7c7b\u578b -b \u5217\u51fa\u8fa8\u8bc6\u7ed3\u679c\u65f6\uff0c\u4e0d\u663e\u793a\u6587\u4ef6\u540d\u79f0\u3002 -c \u8be6\u7ec6\u663e\u793a\u6307\u4ee4\u6267\u884c\u8fc7\u7a0b\uff0c\u4fbf\u4e8e\u6392\u9519\u6216\u5206\u6790\u7a0b\u5e8f\u6267\u884c\u7684\u60c5\u5f62\u3002 -f <\u540d\u79f0\u6587\u4ef6> \u6307\u5b9a\u540d\u79f0\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u6587\u4ef6\u540d\u79f0\u65f6\uff0c\u8ba9file\u4f9d\u5e8f\u8fa8\u8bc6\u8fd9\u4e9b\u6587\u4ef6\uff0c\u683c\u5f0f\u4e3a\u6bcf\u5217\u4e00\u4e2a\u6587\u4ef6\u540d\u79f0\u3002 -L \u76f4\u63a5\u663e\u793a\u7b26\u53f7\u8fde\u63a5\u6240\u6307\u5411\u7684\u6587\u4ef6\u7684\u7c7b\u522b\u3002 -m<\u9b54\u6cd5\u6570\u5b57\u6587\u4ef6> \u6307\u5b9a\u9b54\u6cd5\u6570\u5b57\u6587\u4ef6\u3002 -v \u663e\u793a\u7248\u672c\u4fe1\u606f\u3002 -z \u5c1d\u8bd5\u53bb\u89e3\u8bfb\u538b\u7f29\u6587\u4ef6\u7684\u5185\u5bb9\u3002 dcmaster:/data/linktype # l -rw-r--r-- 3 root root 44 May 3 09:50 file -rw-r--r-- 3 root root 44 May 3 09:50 hardlinkfile1 -rw-r--r-- 3 root root 44 May 3 09:50 hardlinkfile2 lrwxrwxrwx 1 root root 4 Mar 28 15:21 symlinkfile1 -> file lrwxrwxrwx 1 root root 12 Mar 28 15:49 symlinkfile1-1 -> symlinkfile1 lrwxrwxrwx 1 root root 4 Mar 28 15:23 symlinkfile2 -> file dcmaster:/data/linktype # file hardlinkfile1 hardlinkfile1: ASCII text dcmaster:/data/linktype # file -i hardlinkfile1 hardlinkfile1: text/plain; charset=us-ascii dcmaster:/data/linktype # file /data/linktype/ /data/linktype/: directory dcmaster:/data/linktype # file -L /data/linktype/ /data/linktype/: directory dcmaster:/data/linktype # file -i /data/linktype/ /data/linktype/: inode/directory; charset=binary dcmaster:/data/linktype # file symlinkfile1 symlinkfile1: symbolic link to file dcmaster:/data/linktype # file -i symlinkfile1 symlinkfile1: inode/symlink; charset=binary","title":"file command"},{"location":"linux/Administration/02/#grep-command","text":"You can specify search patterns in the form of regular expressions, although the basic grep command is limited in this regard. To search for more complex patterns, use the egrep command (or grep -E ) instead, which accepts extended regular expressions. To avoid having special characters in search patterns interpreted by the shell, enclose the pattern in quotation marks. Syntax: grep [options] search_pattern filename * egrep = grep -E * rgrep \u53c2\u6570 -a \u6216 --text : \u4e0d\u8981\u5ffd\u7565\u4e8c\u8fdb\u5236\u7684\u6570\u636e\u3002 -A<\u663e\u793a\u884c\u6570> \u6216 --after-context=<\u663e\u793a\u884c\u6570> : \u9664\u4e86\u663e\u793a\u7b26\u5408\u8303\u672c\u6837\u5f0f\u7684\u90a3\u4e00\u5217\u4e4b\u5916\uff0c\u5e76\u663e\u793a\u8be5\u884c\u4e4b\u540e\u7684\u5185\u5bb9\u3002 -b \u6216 --byte-offset : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u6807\u793a\u51fa\u8be5\u884c\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u7f16\u53f7\u3002 -B<\u663e\u793a\u884c\u6570> \u6216 --before-context=<\u663e\u793a\u884c\u6570> : \u9664\u4e86\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u5916\uff0c\u5e76\u663e\u793a\u8be5\u884c\u4e4b\u524d\u7684\u5185\u5bb9\u3002 -c \u6216 --count : \u8ba1\u7b97\u7b26\u5408\u6837\u5f0f\u7684\u5217\u6570\u3002 -C<\u663e\u793a\u884c\u6570> \u6216 --context=<\u663e\u793a\u884c\u6570> \u6216 -<\u663e\u793a\u884c\u6570> : \u9664\u4e86\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u5916\uff0c\u5e76\u663e\u793a\u8be5\u884c\u4e4b\u524d\u540e\u7684\u5185\u5bb9\u3002 -d <\u52a8\u4f5c> \u6216 --directories=<\u52a8\u4f5c> : \u5f53\u6307\u5b9a\u8981\u67e5\u627e\u7684\u662f\u76ee\u5f55\u800c\u975e\u6587\u4ef6\u65f6\uff0c\u5fc5\u987b\u4f7f\u7528\u8fd9\u9879\u53c2\u6570\uff0c\u5426\u5219grep\u6307\u4ee4\u5c06\u56de\u62a5\u4fe1\u606f\u5e76\u505c\u6b62\u52a8\u4f5c\u3002 -e<\u8303\u672c\u6837\u5f0f> \u6216 --regexp=<\u8303\u672c\u6837\u5f0f> : \u6307\u5b9a\u5b57\u7b26\u4e32\u505a\u4e3a\u67e5\u627e\u6587\u4ef6\u5185\u5bb9\u7684\u6837\u5f0f\u3002 -E \u6216 --extended-regexp : \u5c06\u6837\u5f0f\u4e3a\u5ef6\u4f38\u7684\u666e\u901a\u8868\u793a\u6cd5\u6765\u4f7f\u7528\u3002 -f<\u89c4\u5219\u6587\u4ef6> \u6216 --file=<\u89c4\u5219\u6587\u4ef6> : \u6307\u5b9a\u89c4\u5219\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u542b\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u89c4\u5219\u6837\u5f0f\uff0c\u8ba9grep\u67e5\u627e\u7b26\u5408\u89c4\u5219\u6761\u4ef6\u7684\u6587\u4ef6\u5185\u5bb9\uff0c\u683c\u5f0f\u4e3a\u6bcf\u884c\u4e00\u4e2a\u89c4\u5219\u6837\u5f0f\u3002 -F \u6216 --fixed-regexp : \u5c06\u6837\u5f0f\u89c6\u4e3a\u56fa\u5b9a\u5b57\u7b26\u4e32\u7684\u5217\u8868\u3002 -G \u6216 --basic-regexp : \u5c06\u6837\u5f0f\u89c6\u4e3a\u666e\u901a\u7684\u8868\u793a\u6cd5\u6765\u4f7f\u7528\u3002 -h \u6216 --no-filename : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u4e0d\u6807\u793a\u8be5\u884c\u6240\u5c5e\u7684\u6587\u4ef6\u540d\u79f0\u3002 -H \u6216 --with-filename : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u8868\u793a\u8be5\u884c\u6240\u5c5e\u7684\u6587\u4ef6\u540d\u79f0\u3002 -i \u6216 --ignore-case : \u5ffd\u7565\u5b57\u7b26\u5927\u5c0f\u5199\u7684\u5dee\u522b\u3002 -l \u6216 --file-with-matches : \u5217\u51fa\u6587\u4ef6\u5185\u5bb9\u7b26\u5408\u6307\u5b9a\u7684\u6837\u5f0f\u7684\u6587\u4ef6\u540d\u79f0\u3002 -L \u6216 --files-without-match : \u5217\u51fa\u6587\u4ef6\u5185\u5bb9\u4e0d\u7b26\u5408\u6307\u5b9a\u7684\u6837\u5f0f\u7684\u6587\u4ef6\u540d\u79f0\u3002 -n \u6216 --line-number : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u6807\u793a\u51fa\u8be5\u884c\u7684\u5217\u6570\u7f16\u53f7\u3002 -o \u6216 --only-matching : \u53ea\u663e\u793a\u5339\u914dPATTERN \u90e8\u5206\u3002 -q \u6216 --quiet\u6216--silent : \u4e0d\u663e\u793a\u4efb\u4f55\u4fe1\u606f\u3002 -r \u6216 --recursive : \u6b64\u53c2\u6570\u7684\u6548\u679c\u548c\u6307\u5b9a\"-d recurse\"\u53c2\u6570\u76f8\u540c\u3002 -s \u6216 --no-messages : \u4e0d\u663e\u793a\u9519\u8bef\u4fe1\u606f\u3002 -v \u6216 --revert-match : \u663e\u793a\u4e0d\u5305\u542b\u5339\u914d\u6587\u672c\u7684\u6240\u6709\u884c\u3002 -V \u6216 --version : \u663e\u793a\u7248\u672c\u4fe1\u606f\u3002 -w \u6216 --word-regexp : \u53ea\u663e\u793a\u5168\u5b57\u7b26\u5408\u7684\u5217\u3002 -x --line-regexp : \u53ea\u663e\u793a\u5168\u5217\u7b26\u5408\u7684\u5217\u3002 -y : \u6b64\u53c2\u6570\u7684\u6548\u679c\u548c\u6307\u5b9a\"-i\"\u53c2\u6570\u76f8\u540c\u3002 \u5728\u5f53\u524d\u76ee\u5f55\u4e2d\uff0c\u67e5\u627e\u540e\u7f00\u6709conf\u5b57\u6837\u7684\u6587\u4ef6\u4e2d\u5305\u542bxen\u5b57\u7b26\u4e32\u7684\u6587\u4ef6\uff0c\u5e76\u6253\u5370\u51fa\u8be5\u5b57\u7b26\u4e32\u7684\u884c\u3002 pmgr@dcmaster:/data/program/general> grep xen *.conf xen xening \u67e5\u627e\u524d\u7f00\u6709gen\u7684\u6587\u4ef6\u5305\u542bxen\u5b57\u7b26\u4e32\u7684\u6587\u4ef6 pmgr@dcmaster:/data/program/general> grep xen gen* xen xening \u4ee5\u9012\u5f52\u7684\u65b9\u5f0f\u67e5\u627e\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u3002\u67e5\u627e\u6307\u5b9a\u76ee\u5f55/data/program/\u53ca\u5176\u5b50\u76ee\u5f55\uff08\u5982\u679c\u5b58\u5728\u5b50\u76ee\u5f55\u7684\u8bdd\uff09\u4e0b\u6240\u6709\u6587\u4ef6\u4e2d\u5305\u542b\u5b57\u7b26\u4e32xen\u7684\u6587\u4ef6\uff0c\u5e76\u6253\u5370\u51fa\u8be5\u5b57\u7b26\u4e32\u6240\u5728\u884c\u7684\u5185\u5bb9 pmgr@dcmaster:/data> grep -r xen /data/program/ ./program/general/general.conf:xen ./program/general/general.conf:xening \u53cd\u5411\u67e5\u627e\u3002\u524d\u9762\u5404\u4e2a\u4f8b\u5b50\u662f\u67e5\u627e\u5e76\u6253\u5370\u51fa\u7b26\u5408\u6761\u4ef6\u7684\u884c\uff0c\u901a\u8fc7 -v \u53c2\u6570\u53ef\u4ee5\u6253\u5370\u51fa\u4e0d\u7b26\u5408\u6761\u4ef6\u884c\u7684\u5185\u5bb9\u3002\u67e5\u627e\u6587\u4ef6\u540d\u4e2d\u5305\u542bxen\u7684\u6587\u4ef6\u4e2d\u4e0d\u5305\u542bxen\u7684\u884c pmgr@dcmaster:/data/program/general> grep -v xen gen* Linux Test test \u67e5\u627e\u5f53\u524d\u76ee\u5f55\u4e0b\u5305\u542b\u5b57\u7b26\u4e32\u201cLinux\u201d\u7684\u6587\u4ef6 pmgr@dcmaster:/data/program/general> grep Linux * general.conf:Linux grep: staffing: Is a directory pmgr@dcmaster:/data/program/general> egrep Linux * general.conf:Linux grep: staffing: Is a directory","title":"grep command"},{"location":"linux/Administration/03/","text":"Shell \u00b6","title":"Shell"},{"location":"linux/Administration/03/#shell","text":"","title":"Shell"},{"location":"linux/SES/linux_ses_demo/","text":"SUSE Enterprise Storage 6 Installation and Basic Operation \u00b6 1. Installation \u00b6 1.1. Environment Setup \u00b6 In this demo, I use below environment, including VM setting and software installed. All VMs installed here was built on a physical host 10.58.121.68 . Host Server: 10.58.121.68 root / rootroot Account root / root123 Gateway: 10.58.120.1 Network Mask: 255.255.254.0 Nameserver: 10.58.32.32 10.33.50.20 Domain Search sha.me.corp dhcp.sha.me.corp me.corp ind.me.corp bgr.me.corp SUSE Server 15 SP1 Extensions and Modules were installed as below. [x] SUSE Enterprise Storage 6 [x] Basesystem Module 15 SP1 x86_64 [x] Server Applications Module 15 SP1 x86_64 Disable Services is as below: AppArmor Firewall Enable Services is as below. SSH Register SLES15.1 to local SMT. # SUSEConnect --url https://smtproxy.ind.me.corp Demo Environment summary is below. Alias Host Name Memory Disk eth0 eth0 mac address sles01 admin (salt-master) 16GB Disk1: 20G 10.58.121.181/23 52:54:00:23:7d:cd sles02 data1 16GB Disk1: 20G 10.58.121.182/23 52:54:00:5f:ce:6f Disk2: 8G Disk3: 8G Disk4: 8G sles03 data2 16GB Disk1: 20G 10.58.121.183/23 52:54:00:6f:f2:23 Disk2: 8G Disk3: 8G Disk4: 8G sles04 data3 16GB Disk1: 20G 10.58.121.184/23 52:54:00:93:4c:67 Disk2: 8G Disk3: 8G Disk4: 8G sles05 data4 16GB Disk1: 20G 10.58.121.185/23 52:54:00:90:b0:b0 Disk2: 8G Disk3: 8G Disk4: 8G sles06 mon1 16GB Disk1: 20G 10.58.121.186/23 52:54:00:46:43:7a sles07 mon2 16GB Disk1: 20G 10.58.121.187/23 52:54:00:00:fe:6b sles08 mon3 16GB Disk1: 20G 10.58.121.188/23 52:54:00:60:a3:92 Add hostname to file /etc/hosts (all nodes) If you do not specify a cluster network during Ceph deployment, it assumes a single public network environment. Make sure that the fully qualified domain name (FQDN) of each node can be resolved to the public network IP address by all other nodes. # vi /etc/hosts 10.58.121.181 admin.sha.me.corp admin salt 10.58.121.182 data1.sha.me.corp data1 10.58.121.183 data2.sha.me.corp data2 10.58.121.184 data3.sha.me.corp data3 10.58.121.185 data4.sha.me.corp data4 10.58.121.186 mon1.sha.me.corp mon1 10.58.121.187 mon2.sha.me.corp mon2 10.58.121.188 mon3.sha.me.corp mon3 Add all nodes as trust ssh access (root account) # cd ~ # ssh-keygen -t rsa # ssh-copy-id -i ~/.ssh/id_rsa.pub root@admin # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data1 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data2 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data3 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data4 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@mon1 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@mon2 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@mon3 # ssh admin.sha.me.corp # ssh data1.sha.me.corp # ssh data2.sha.me.corp # ssh data3.sha.me.corp # ssh data4.sha.me.corp # ssh mon1.sha.me.corp # ssh mon2.sha.me.corp # ssh mon3.sha.me.corp # ssh salt # ssh admin # ssh data1 # ssh data2 # ssh data3 # ssh data4 # ssh mon1 # ssh mon2 # ssh mon3 Disable firewall (all nodes) # sudo /sbin/SuSEfirewall2 off # firewall-cmd --state not running # systemctl stop firewalld.service # systemctl status firewalld.service firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: disabled) Active: inactive (dead) Docs: man:firewalld(1) Disable IPv6 (all nodes) and Set kernel pid to max value (all nodes) # vi /etc/sysctl.conf net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 net.ipv6.conf.lo.disable_ipv6 = 1 kernel.pid_max = 4194303 # sysctl -p Set DEV_ENV=true in /etc/profile.local in all nodes Install basic software (all nodes) # zypper in -y -t pattern yast2_basis base # zypper in -y net-tools vim man sudo tuned irqbalance # zypper in -y ethtool rsyslog iputils less supportutils-plugin-ses # zypper in -y net-tools-deprecated tree wget Configure NTP service (all nodes), Setting via YaST2 and add server cn.pool.ntp.,org . And /etc/chrony.conf file looks like below. admin:~ # cat /etc/chrony.conf # Use public servers from the pool.ntp.org project. pool cn.pool.ntp.org iburst ! pool pool.ntp.org iburst # Record the rate at which the system clock gains/losses time. driftfile /var/lib/chrony/drift # Allow the system clock to be stepped in the first three updates # if its offset is larger than 1 second. makestep 1.0 3 # Enable kernel synchronization of the real-time clock (RTC). rtcsync # Enable hardware timestamping on all interfaces that support it. #hwtimestamp * # Increase the minimum numbgr of selectable sources required to adjust # the system clock. #minsources 2 # Allow NTP client access from local network. #allow 192.168.0.0/16 # Serve time even if not synchronized to a time source. #local stratum 10 # Specify file containing keys for NTP authentication. #keyfile /etc/chrony.keys # Get TAI-UTC offset and leap seconds from the system tz database. #leapsectz right/UTC # Specify directory for log files. logdir /var/log/chrony # Select which information is logged. #log measurements statistics tracking # Also include any directives found in configuration files in /etc/chrony.d include /etc/chrony.d/*.conf Make /etc/chrony.conf effective. # systemctl enable chronyd.service # systemctl restart chronyd.service # systemctl status chronyd.service # chronyc sources 1.2. Install Packages \u00b6 Install salt-minion on all nodes. And start the service. Hostname is in file `/etc/salt/minion_id` # zypper in -y salt-minion Uncomment below to let all nodes know who is master # vi /etc/salt/minion master: salt # systemctl enable salt-minion.service # systemctl start salt-minion.service # systemctl status salt-minion.service Install Ceph in admin node. Check log in /var/log/salt admin:~ # zypper in -y salt-master admin:~ # systemctl enable salt-master.service admin:~ # systemctl start salt-master.service admin:~ # systemctl status salt-master.service Note: ganesha will be installed on mon1, not admin node. admin:~ # zypper se ganesha admin:~ # zypper in nfs-ganesha admin:~ # systemctl enable nfs-ganesha admin:~ # systemctl start nfs-ganesha admin:~ # systemctl status nfs-ganesha admin:~ # cd /var/log/salt List fingerprints of all unaccepted minion keys on the Salt master. admin:~ # salt-key -F Local Keys: master.pem: c0:e5:***:04:c7 master.pub: 43:73:***:6a:34 Unaccepted Keys: admin.sha.me.corp: fe:51:***:b9:48 mon1.sha.me.corp: 94:13:***:91:63 mon2.sha.me.corp: c0:fd:***:39:3f mon3.sha.me.corp: 38:fc:***:2e:05 data1.sha.me.corp: b6:6c:***:63:4f data2.sha.me.corp: ab:14:***:c8:ac data3.sha.me.corp: 90:3f:***:76:3b data4.sha.me.corp: d8:12:***:f1:20 If the minions' fingerprints match, accept them admin:~ # salt-key --accept-all The following keys are going to be accepted: Unaccepted Keys: admin.sha.me.corp mon1.sha.me.corp mon2.sha.me.corp mon3.sha.me.corp data1.sha.me.corp data2.sha.me.corp data3.sha.me.corp data4.sha.me.corp Proceed? [n/Y] Y Key for minion admin.sha.me.corp accepted. Key for minion mon1.sha.me.corp accepted. Key for minion mon2.sha.me.corp accepted. Key for minion mon3.sha.me.corp accepted. Key for minion data1.sha.me.corp accepted. Key for minion data2.sha.me.corp accepted. Key for minion data3.sha.me.corp accepted. Key for minion data4.sha.me.corp accepted. Verify that the keys have been accepted admin:~ # salt-key -F admin:~ # salt-key --list-all Accepted Keys: admin.sha.me.corp data1.sha.me.corp data2.sha.me.corp data3.sha.me.corp data4.sha.me.corp mon1.sha.me.corp mon2.sha.me.corp mon3.sha.me.corp Denied Keys: Unaccepted Keys: Rejected Keys: Zero out all drivers which will be used as OSDs (optional) data1:~ lsblk data1:~ # for I in {b,c,d}; do dd if=/dev/zero of=dev/sd$i bs=512 count=40 oflag=direct; done data2:~ # for I in {b,c,d}; do dd if=/dev/zero of=dev/sd$i bs=512 count=40 oflag=direct; done data3:~ # for I in {b,c,d}; do dd if=/dev/zero of=dev/sd$i bs=512 count=40 oflag=direct; done Install DeepSea admin:~ # zypper in -y deepsea Edit the /srv/pillar/ceph/deepsea_minions.sls file on the Salt master (admin node) and add or replace the following line: admin:~ # vi /srv/pillar/ceph/deepsea_minions.sls # Choose minions with a deepsea grain deepsea_minions: 'G@deepsea:*' #Match all Salt minions in the cluster # Choose all minions # deepsea_minions: '*' #Match all minions with the 'deepsea' grain # Choose custom Salt targeting # deepsea_minions: 'ses*' # deepsea_minions: 'ceph* or salt' Target the Minions Affirm salt-master (admin node) can communicate with the minions. And deploy the grains from admin node to all minions. admin:~ # salt '*' test.ping mon1.sha.me.corp: True data4.sha.me.corp: True data3.sha.me.corp: True data2.sha.me.corp: True data1.sha.me.corp: True mon3.sha.me.corp: True admin.sha.me.corp: True mon2.sha.me.corp: True Apply the 'deepsea' grain to a group of minions, and target with a DeepSea Grain admin:~ # salt '*' grains.append deepsea default data3.sha.me.corp: The val default was already in the list deepsea mon2.sha.me.corp: The val default was already in the list deepsea data1.sha.me.corp: The val default was already in the list deepsea data4.sha.me.corp: The val default was already in the list deepsea data2.sha.me.corp: The val default was already in the list deepsea mon3.sha.me.corp: The val default was already in the list deepsea admin.sha.me.corp: The val default was already in the list deepsea mon1.sha.me.corp: The val default was already in the list deepsea admin:~ # salt -G 'deepsea:*' test.ping (The following command is an equivalent) admin:~ # salt -C 'G@deepsea:*' test.ping admin.sha.me.corp: True data3.sha.me.corp: True mon1.sha.me.corp: True mon2.sha.me.corp: True data2.sha.me.corp: True data4.sha.me.corp: True mon3.sha.me.corp: True data1.sha.me.corp: True 1.3. Stage 0 \u2014 the preparation \u00b6 Run Stage 0\u2014the preparation During this stage, all required updates are applied and your system may be rebooted. If there are errors, re-run the stage. admin:~ # deepsea stage run ceph.stage.0 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.0 admin:~ # salt-run state.orch ceph.stage.prep Run Stage 1\u2014the discovery Here all hardware in your cluster is being detected and necessary information for the Ceph configuration is being collected. The discovery stage collects data from all minions and creates configuration fragments that are stored in the directory /srv/pillar/ceph/proposals . The data are stored in the YAML format in *.sls or *.yml files admin:~ # deepsea stage run ceph.stage.1 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.1 admin:~ # salt-run state.orch ceph.stage.discovery 1.4. Stage 2 \u2014 the configuration \u00b6 Run Stage 2 \u2014 the configuration \u2014 you need to prepare configuration data in a particular format. The assignment follows this pattern: role-ROLE_NAME/PATH/FILES_TO_INCLUDE (NOTE, the parent directory of PATH is /srv/pillar/ceph/ ) To avoid trouble with performance and the upgrade procedure, do not deploy the Ceph OSD, Metadata Server, or Ceph Monitor role to the Admin Node. Monitors, Metadata Server, and gateways can be co-located on the OSD nodes. If you are using CephFS, S3/Swift, iSCSI, at least two instances of the respective roles (Metadata Server, Object Gateway, iSCSI) are required for redundancy and availability. admin:~ # cp /usr/share/doc/packages/deepsea/examples/policy.cfg-rolebased /srv/pillar/ceph/proposals/policy.cfg admin:~ # vi /srv/pillar/ceph/proposals/policy.cfg ## Cluster Assignment # Add all nodes into Ceph cluster cluster-ceph/cluster/*.sls ## Roles # The Admin node fills the \u201cmaster\u201d and \u201cadmin\u201d roles for DeepSea # The master role is mandatory, always add a similar line to the following role-master/cluster/admin*.sls role-admin/cluster/admin*.sls # Monitoring # Cluster monitoring and data graphs, most commonly they run on Admin node # NFS Ganesha is configured via the file /etc/ganesha/ganesha.conf # As additional configuration is required to install NFS Ganesha, you can install NFS Ganesha later. # The following requirements need to be met before DeepSea stages 2 and 4 can be executed to install NFS Ganesha: # a)At least one node needs to be assigned the role-ganesha. # b)You can define only one role-ganesha per minion. # c)NFS Ganesha needs either an Object Gateway or CephFS to work, otherwise the validation will fail in Stage 3. # d)The kernel based NFS needs to be disabled on minions with the role-ganesha role. role-prometheus/cluster/admin*.sls role-grafana/cluster/mon1*.sls # MON # The minion will provide the monitor service to the Ceph cluster role-mon/cluster/mon*.sls # MGR # The Ceph manager daemon which collects all the state information from the whole cluster # Deploy it on all minions where you plan to deploy the Ceph monitor role role-mgr/cluster/mon1*.sls # MDS # The minion will provide the metadata service to support CephFS role-mds/cluster/mon*.sls # IGW # The minion will act as an iSCSI Gateway role-igw/cluster/mon2*.sls # RGW # The minion will act as an Object Gateway role-rgw/cluster/mon3*.sls # Storage # Use this role to specify storage nodes # It points to data1~4 nodes with a wildcard. role-storage/cluster/data*.sls # COMMON # It includes configuration files generated during the discovery (Stage 1) # Accept the default values for common configuration parameters such as fsid and public_network config/stack/default/global.yml config/stack/default/ceph/cluster.yml admin:~ # deepsea stage run ceph.stage.2 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.2 admin:~ # salt-run state.orch ceph.stage.configure After the command succeeds, run below command to view the pillar data for the specified minions admin:~ # salt 'mon*' pillar.items admin:~ # salt '*' saltutil.pillar_refresh Check time server (admin node) (the directory /srv/pillar/ceph/stack was initialized after deepsea installed, but global.yml file was not created yet until stage 2) By default, DeepSea uses the Admin Node as the time server for other cluster nodes. admin:~ # cat /srv/pillar/ceph/stack/default/global.yml (this file will be generated after stage 2) monitoring: prometheus: metric_relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] rule_files: [] scrape_interval: ceph: 10s grafana: 10s node_exporter: 10s prometheus: 10s target_partition: ceph: 1/1 grafana: 1/1 node_exporter: 1/1 prometheus: 1/1 time_server: admin.sha.me.corp Verify network (the directory /srv/pillar/ceph/stack was initialized after deepsea installed, but cluster.yml file was not created until stage 2 ) admin:~ # cat /srv/pillar/ceph/stack/ceph/cluster.yml --nothing admin:~ # cat /srv/pillar/ceph/stack/default/ceph/cluster.yml available_roles: - storage - admin - mon - mds - mgr - igw - grafana - prometheus - storage - rgw - ganesha - client-cephfs - client-radosgw - client-iscsi - client-nfs - benchmark-rbd - benchmark-blockdev - benchmark-fs - master cluster_network: 10.58.120.0/23 fsid: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 public_network: 10.58.120.0/23 Note: customized file will overwrite default one. Default file: /srv/pillar/ceph/stack/default/ceph/cluster.yml Customized file: /srv/pillar/ceph/stack/ceph/cluster.yml Check DriveGroup DriveGroups specify the layouts of OSDs in the Ceph cluster. They are defined in a single file /srv/salt/ceph/configuration/files/drive_groups.yml admin:~ # cat /srv/salt/ceph/configuration/files/drive_groups.yml default_drive_group_name: target: 'data*' <--original: 'I@role:storage' data_devices: all: true admin:~ # salt 'data*' pillar.items | grep -B5 stroage 1.5. Stage 3 \u2014 the deployment \u00b6 Run Stage 3 \u2014 the deployment \u2014 creates a basic Ceph cluster with mandatory Ceph services. This Deployment stage has more than 60 automated steps. Be patient and make sure the stage completes successfully before proceeding. Set dev environment and disable subvolume: admin:~ # vi /srv/pillar/ceph/stack/global.yml admin:~ # vi /srv/pillar/ceph/stack/default/global.yml monitoring: prometheus: metric_relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] rule_files: [] scrape_interval: ceph: 10s grafana: 10s node_exporter: 10s prometheus: 10s target_partition: ceph: 1/1 grafana: 1/1 node_exporter: 1/1 prometheus: 1/1 time_server: admin.sha.me.corp DEV_ENV: True subvolume_init: disabled admin:~ # salt '*' saltutil.pillar_refresh Note: customized file will overwrite default one. Default file: /srv/pillar/ceph/stack/default/global.yml Customized file: /srv/pillar/ceph/stack/global.yml admin:~ # deepsea stage run ceph.stage.3 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.3 admin:~ # salt-run state.orch ceph.stage.deploy After the command succeeds, run the following to check the status: admin:~ # ceph -s Below comands return you a structure of matching disks based on your DriveGroups. (will show available information after stage 3) admin:~ # salt-run disks.Report admin:~ # salt-run disks.list admin:~ # salt-run disks.details 1.6. Stage 4 \u2014 the services \u00b6 Run Stage 4 \u2014 the services \u2014 additional features of Ceph like iSCSI, Object Gateway and CephFS can be installed in this stage. Each is optional. admin:~ # deepsea stage run ceph.stage.4 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.4 admin:~ # salt-run state.orch ceph.stage.services admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log Before logon to dashboard via url, need get credentials first admin:~ # salt-call grains.get dashboard_creds local: ---------- admin: --> the password was changed to mypassword to log on to dashboard admin:~ # ceph mgr services { \"dashboard\": \"https://mon1.sha.me.corp:8443/\", \"prometheus\": \"http://mon1.sha.me.corp:9283/\" } https://10.58.121.186:8443 http://10.58.121.186:9283 admin:~ # watch ceph -s Every 2.0s: ceph -s admin: Mon Oct 5 14:41:51 2020 cluster: id: health: HEALTH_OK services:s: ceph -s mon: 3 daemons, quorum mon1,mon2,mon3 (age 87m) mgr: mon1(active, since 82m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 85m), 12 in (since 85m) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 576 pgs objects: 213 objects, 4.2 KiB usage: 12 GiB used, 84 GiB / 96 GiB avail pgs: 576 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr 1.7. Stage 5 \u2014 the removal stage \u00b6 Run Stage 5 \u2014 the removal stage. This stage is not mandatory and during the initial setup it is usually not needed. In this stage the roles of minions and also the cluster configuration are removed. You need to run this stage when you need to remove a storage node from your cluster. admin:~ # deepsea stage run ceph.stage. 1.8. Installation Guide \u00b6 Deployment Guide (EN) Deployment Guide (ZH) 1.9. Issues during installation \u00b6 [ERROR]: The Salt Master has cached the public key for this node SOLUTION : Restart minions service [ERROR]: This server_id is computed nor by Adler32 neither by CRC32 [QUESTION]: How to change new salt key Stop salt-minion service # systemctl stop salt-minion Delete salt-minion pulic key # rm /etc/salt/pki/minion/minion.pub # rm /etc/salt/pki/minion/minion.pem Change new minion_id admin:~ # echo admin.sha.me.corp > /etc/salt/minion_id data1:~ # echo data1.sha.me.corp > /etc/salt/minion_id data2:~ # echo data2.sha.me.corp > /etc/salt/minion_id data3:~ # echo data3.sha.me.corp > /etc/salt/minion_id data4:~ # echo data4.sha.me.corp > /etc/salt/minion_id mon1:~ # echo mon1.sha.me.corp > /etc/salt/minion_id mon2:~ # echo mon2.sha.me.corp > /etc/salt/minion_id mon3:~ # echo mon3.sha.me.corp > /etc/salt/minion_id Delete old ID on admin node # salt-key -D Restart salt-minion service # systemctl restart salt-minion Accept all new key on admin node admin:~ # salt-key -L admin:~ # salt-key -A or admin:~ # salt-key -a admin.sha.me.corp data1:~ # salt-key -a data1.sha.me.corp data2:~ # salt-key -a data2.sha.me.corp data3:~ # salt-key -a data3.sha.me.corp data4:~ # salt-key -a data4.sha.me.corp mon1:~ # salt-key -a mon1.sha.me.corp mon2:~ # salt-key -a mon2.sha.me.corp mon3:~ # salt-key -a mon3.sha.me.corp [ERROR] ['/var/lib/ceph subvolume missing on mon3.sha.me.corp', '/var/lib/ceph subvolume missing on mon1.sha.me.corp', '/var/lib/ceph subvolume missing on mon2.sha.me.corp', 'See /srv/salt/ceph/subvolume/README.md'] SOLUTION Edit /srv/pillar/ceph/stack/global.yml and add the following line: subvolume_init: disabled Then refresh the Salt pillar and re-run DeepSea stage.3: admin:~ # salt '*' saltutil.refresh_pillar admin:~ # salt-run state.orch ceph.stage.3 After DeepSea successfully finished stage.3, the Ceph Dashboard will be running. Refer to Book \u201cAdministration Guide\u201d, Chapter 20 \u201cCeph Dashboard\u201d for a detailed overview of Ceph Dashboard features. To list nodes running dashboard, run: admin:~ # ceph mgr services | grep dashboard To list admin credentials, run: admin:~ # salt-call grains.get dashboard_creds [ERROR] module function cephprocesses.wait executed on nodes mon1~3 and data1~4 in Stage 0 SOLUTION Check below on all nodes # salt-call cephprocesses.check ERROR: process ceph-mds for role mds is not running ERROR: process radosgw for role rgw is not running admin:~ # ceph -s Clock skew detected on mon ceph (mon.mon2, mon.mon3) Set time server to public server (China) # chronyc sources 1.10. Shutting Down the Whole Ceph Cluster \u00b6 Shut down or disconnect any clients accessing the cluster. To prevent CRUSH from automatically rebalancing the cluster, set the cluster to noout: # ceph osd set noout Other flags you can set per osd: nodown noup noin noout Disable safety measures and run the ceph.shutdown runner: admin:~ # salt-run disengage.safety safety is now disabled for cluster ceph admin:~ # salt-run state.orch ceph.shutdown admin.sha.me.corp_master: Name: set noout - Function: salt.state - Result: Changed Started: - 14:32:14.398022 Duration: 2266.75 ms Name: Shutting down radosgw for rgw - Function: salt.state - Result: Changed Started: - 14:32:16.665452 Duration: 1461.23 ms Name: Shutting down cephfs - Function: salt.state - Result: Changed Started: - 14:32:18.127353 Duration: 30326.193 ms Name: Shutting down iscsi - Function: salt.state - Result: Clean Started: - 14:32:48.454187 Duration: 30142.468 ms Name: Shutting down storage - Function: salt.state - Result: Changed Started: - 14:33:18.597321 Duration: 10841.45 ms Name: Shutting down mgr - Function: salt.state - Result: Changed Started: - 14:33:29.439442 Duration: 29209.141 ms Name: Shutting down mon - Function: salt.state - Result: Changed Started: - 14:33:58.649221 Duration: 30519.97 ms Summary for admin.sha.me.corp_master ------------ Succeeded: 7 (changed=6) Failed: 0 ------------ Total states run: 7 Total run time: 134.767 s Power off all cluster nodes: admin:~ # salt -C 'G@deepsea:*' cmd.run \"shutdown -h\" Broadcast message from root@admin (Sat 2021-03-06 14:40:37 CST): The system is going down for poweroff at Sat 2021-03-06 14:41:37 CST! admin.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. mon2.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data2.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. mon3.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data3.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data4.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. mon1.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data1.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. 1.11. Starting, Stopping, and Restarting Services Using Targets \u00b6 # ls /usr/lib/systemd/system/ceph*.target ceph.target ceph-osd.target ceph-mon.target ceph-mgr.target ceph-mds.target ceph-radosgw.target ceph-rbd-mirror.target To start/stop/restart all Ceph services on the node, run: # systemctl start ceph.target # systemctl stop ceph.target # systemctl restart ceph.target To start/stop/restart all OSDs on the node, run: # systemctl start ceph-osd.target # systemctl stop ceph-osd.target # systemctl restart ceph-osd.target Starting, Stopping, and Restarting Individual Services # systemctl list-unit-files --all --type=service ceph* ceph-osd@.service ceph-mon@.service ceph-mds@.service ceph-mgr@.service ceph-radosgw@.service ceph-rbd-mirror@.service Example : # systemctl status ceph-mon@HOSTNAME.service (e.g., ceph-mon@mon1.service) # systemctl start ceph-osd@1.service # systemctl stop ceph-osd@1.service # systemctl restart ceph-osd@1.service # systemctl status ceph-osd@1.service 1.12. Restarting All Services \u00b6 # salt-run state.orch ceph.restart 1.13. Restarting Specific Services \u00b6 Example: salt-run state.orch ceph.restart.service_name # salt-run state.orch ceph.restart.mon # salt-run state.orch ceph.restart.mgr # salt-run state.orch ceph.restart.osd # salt-run state.orch ceph.restart.mds # salt-run state.orch ceph.restart.rgw # salt-run state.orch ceph.restart.igw # salt-run state.orch ceph.restart.ganesha Default log file path of salt-run: /var/log/salt/master 2. Basic Operation \u00b6 2.1. Pools and Data Placement \u00b6 2.1.1. Enable the PG Autoscaler and Balancer Modules \u00b6 Task 1: View the state of all the Manager Modules \u00b6 List all the existing Manager Modules admin:~ # ceph mgr module ls | less Task 2: List the Existing Pools \u00b6 List the pools that already exist in the cluster admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log List the pools again, but this time using the rados command: admin:~ # rados lspools iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log View the output of placement group autoscale-status command for the pools admin:~ # ceph osd pool autoscale-status Error ENOTSUP: Module 'pg_autoscaler' is not enabled (required by command 'osd pool autoscale-status'): use `ceph mgr module enable pg_autoscaler` to enable it Task 3: Enable the pg_autoscaler module \u00b6 Enable the pg_autoscaler module admin:~ # ceph mgr module enable pg_autoscaler admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 128 32 warn cephfs_data 0 3.0 98256M 0.0000 1.0 256 32 warn cephfs_metadata 7285 3.0 98256M 0.0000 4.0 64 16 warn .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 18078 3.0 98256M 0.0000 1.0 32 warn Note that for the iscsi-images pool the PG_NUM value is 128. And note that the NEW PG_NUM value is 32. The PGs won\u2019t be adjusted automatically because the default setting for the autoscaler is \u201cwarn\u201d. Note the last column (mode) that shows status \u201cwarn\u201d for all the pools. Check current status. \u201chave too many placement groups\u201d. That\u2019s exactly what we want the pg_autoscaler to tell us. admin:~ # ceph health HEALTH_WARN 3 pools have too many placement groups Turn off the pg_autoscaler feature for CephFS pools admin:~ # ceph osd pool set cephfs_data pg_autoscale_mode off set pool 2 pg_autoscale_mode to off admin:~ # ceph osd pool set cephfs_metadata pg_autoscale_mode off set pool 3 pg_autoscale_mode to off admin:~ # ceph health HEALTH_WARN 1 pools have too many placement groups Set the pg_autoscaler mode to \u201con\u201d for the iscs-images pool: admin:~ # ceph osd pool set iscsi-images pg_autoscale_mode on set pool 1 pg_autoscale_mode to on admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 128 32 on cephfs_data 0 3.0 98256M 0.0000 1.0 256 32 off cephfs_metadata 7412 3.0 98256M 0.0000 4.0 64 16 off .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 18078 3.0 98256M 0.0000 1.0 32 warn Turn on the pg_autoscaler feature for CephFS pools admin:~ # ceph osd pool set cephfs_data pg_autoscale_mode on set pool 2 pg_autoscale_mode to on admin:~ # ceph osd pool set cephfs_metadata pg_autoscale_mode on set pool 3 pg_autoscale_mode to on PG numbgrs must always be a power of 2 admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 32 on cephfs_data 0 3.0 98256M 0.0000 1.0 32 off cephfs_metadata 7412 3.0 98256M 0.0000 4.0 16 off .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 35900 3.0 98256M 0.0000 1.0 32 warn Show the cluster health admin:~ # ceph -s cluster: id: health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 4w) mgr: mon1(active, since 46h) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 8w), 12 in (since 8w) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 433 pgs objects: 246 objects, 4.7 KiB usage: 13 GiB used, 83 GiB / 96 GiB avail pgs: 0.462% pgs not active 431 active+clean 2 peering io: client: 45 KiB/s rd, 0 B/s wr, 44 op/s rd, 28 op/s wr Task 4: Turn on the Placement Group balancer feature \u00b6 1). Show the \u201cstatus\u201d of the balancer: admin:~ # ceph balancer status { \"plans\": [], \"active\": false, \"last_optimize_started\": \"\", \"last_optimize_duration\": \"\", \"optimize_result\": \"\", \"mode\": \"none\" } admin:~ # ceph balancer on admin:~ # ceph balancer status { \"plans\": [], \"active\": true, \"last_optimize_started\": \"Mon Jan 4 20:22:57 2021\", \"last_optimize_duration\": \"0:00:00.001379\", \"optimize_result\": \"Please do \\\"ceph balancer mode\\\" to choose a valid mode first\", \"mode\": \"none\" } 2). Set the mode for the balancer to \u201cupmap\u201d: admin:~ # ceph balancer mode upmap Error EPERM: min_compat_client \"jewel\" < \"luminous\", which is required for pg-upmap. Try \"ceph osd set-require-min-compat-client luminous\" before enabling this mode admin:~ # ceph osd set-require-min-compat-client luminous --yes-i-really-mean-it set require_min_compat_client to luminous admin:~ # ceph balancer mode upmap admin:~ # ceph balancer status { \"plans\": [], \"active\": true, \"last_optimize_started\": \"Mon Jan 4 20:23:57 2021\", \"last_optimize_duration\": \"0:00:00.001807\", \"optimize_result\": \"Please do \\\"ceph balancer mode\\\" to choose a valid mode first\", \"mode\": \"upmap\" } 3). Create a balancer optimization plan called basic-plan. Ceph won\u2019t let you do this yet. Because you just recently enabled the pg_autoscaler, Ceph is moving objects around, and the PGs are quite busy with re-peering. admin:~ # ceph balancer optimize basic-plan Error EINVAL: Balancer enabled, disable to optimize manually 4). Show the details of the plan: This shows what \u201cexecute\u201d-ing the plan will do, itemizing which PGs will be affected. admin:~ # ceph balancer show basic-plan Error ENOENT: plan basic-plan not found <--- failed here 5). Show the effectiveness of the plan by comparing the current score for the pre-planned balancing and the score for the planned balancing: admin:~ # ceph balancer eval current cluster score 0.118731 (lower is better) admin:~ # ceph balancer eval basic-plan Error EINVAL: option \"basic-plan\" not a plan or a pool 6). Show the status of the balancer, now with all of these settings having been set, but before putting them into effect: The pg_autoscaler has already optimized the balance of PGs sufficiently. That\u2019s because this cluster is very small and has no significant content stored in it yet. If that\u2019s the case, you would see a message like \u201cError EALREADY: Unable to find further optimization, or pool(s)' pg_num is decreasing, or distribution is already perfect.\u201d If you receive this message, then you will not be able to complete this task. At some later time in the course you may choose to revisit this task to complete it. admin:~ # ceph balancer status { \"plans\": [], \"active\": true, \"last_optimize_started\": \"Mon Jan 4 20:32:59 2021\", \"last_optimize_duration\": \"0:00:00.004170\", \"optimize_result\": \"Unable to find further optimization, or pool(s) pg_num is decreasing, or distribution is already perfect\", \"mode\": \"upmap\" } 7). Set the basic-plan into effect: admin:~ # ceph balancer execute basic-plan Error EINVAL: Balancer enabled, disable to execute a plan 8). Now re-show the current score for the balanced cluster: admin:~ # ceph balancer eval current cluster score 0.118731 (lower is better) 2.1.2. Manipulate Erasure Code Profiles \u00b6 Task 1: Display a list of the current Erasure Code profiles \u00b6 admin:~ # ceph osd erasure-code-profile no valid command found; 4 closest matches: osd erasure-code-profile set { [...]} {--force} osd erasure-code-profile get osd erasure-code-profile rm osd erasure-code-profile ls Error EINVAL: invalid command admin:~ # ceph osd erasure-code-profile ls default Task 2: Examine the details of the default EC profile \u00b6 admin:~ # ceph osd erasure-code-profile get default k=2 m=1 plugin=jerasure technique=reed_sol_van Task 3: Create and remove a new EC profile \u00b6 1. Create a new EC profile from the command line. This is going to be a \u201cbad\u201d profile that will be removed in a moment: admin:~ # ceph osd erasure-code-profile set bad_profile k=2 m=4 plugin=jerasure admin:~ # ceph osd erasure-code-profile ls bad_profile default admin:~ # ceph osd erasure-code-profile get bad_profile crush-device-class= crush-failure-domain=host crush-root=default jerasure-per-chunk-alignment=false k=2 m=4 plugin=jerasure technique=reed_sol_van w=8 admin:~ # ceph osd erasure-code-profile rm bad_profile admin:~ # ceph osd erasure-code-profile ls default Task 4: Create a better EC profile \u00b6 admin:~ # ceph osd erasure-code-profile set usable_profile k=2 m=1 plugin=jerasure technique=reed_sol_van stripe_unit=4K crush-failure-domain=host admin:~ # ceph osd erasure-code-profile get usable_profile crush-device-class= crush-failure-domain=host crush-root=default jerasure-per-chunk-alignment=false k=2 m=1 plugin=jerasure stripe_unit=4K technique=reed_sol_van w=8 2.1.3. Manipulate CRUSH Map Rulesets \u00b6 Task 1: Display a list of the current CRUSH Map rules \u00b6 admin:~ # ceph osd crush rule ls replicated_rule admin:~ # ceph osd crush osd crush rule ls osd crush rule ls-by-class osd crush rule dump {} osd crush dump osd crush set {} osd crush add-bucket { [...]} osd crush rename-bucket osd crush set [...] osd crush add [...] osd crush set-all-straw-buckets-to-straw2 admin:~ # ceph osd crush rule osd crush rule ls osd crush rule ls-by-class osd crush rule dump {} osd crush rule create-simple {firstn|indep} osd crush rule create-replicated {} osd crush rule create-erasure {} osd crush rule rm osd crush rule rename List the existing CRUSH Map rulesets that have been defined according to a particular device class: admin:~ # ceph osd crush rule ls-by-class hdd admin:~ # ceph osd crush rule ls-by-class ssd Error ENOENT: failed to get rules by class 'ssd' admin:~ # ceph osd crush rule ls-by-class nvme Error ENOENT: failed to get rules by class 'nvme' Task 2: Examine the details of the default CRUSH Map rule \u00b6 Show the details of the default CRUSH Map rule with the dump sub-command: The \u201crule_id\u201d and \u201cruleset\u201d values just numbgrs to keep track of rules similar to a DB key id. \u201cmin_size\u201d and \u201cmax_size\u201d are related to how CRUSH behaves when a certain numbgr of replicas are created. The \u201csteps\u201d section is the most functional portion of the rule, providing an ordered set of rules for how CRUSH should behave. Note that there are three \u201cop\u201d parts, one each for \u201ctake\u201d, \u201cchooseleaf_firstn\u201d, and \u201cemit\u201d. \u201ctake\u201d in a replicated rule is always the first step, and \u201cemit\u201d is always the last step. The \u201citem_type\u201d in the \u201ctake\u201d step is the crush_root value, and the \u201chost\u201d in the \u201cchooseleaf_firstn\u201d step is the failure_domain. admin:~ # ceph osd crush rule dump replicated_rule { \"rule_id\": 0, \"rule_name\": \"replicated_rule\", \"ruleset\": 0, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } Task 3: Create and remove a new CRUSH Map rule \u00b6 1). Create a new CRUSH ruleset from the command line.We made two mistakes here: First, we named it \u201cbud\u201d instead of \u201cbad\u201d. admin:~ # ceph osd crush rule create-replicated bud_ruleset default host admin:~ # ceph osd crush rule ls replicated_rule bud_ruleset 2). Rename the ruleset: admin:~ # ceph osd crush rule rename bud_ruleset bad_ruleset admin:~ # ceph osd crush rule ls replicated_rule bad_ruleset 3). The second mistake was that we specified the failure-domain at the host-bucket level. This is technically not a bad thing to do, in fact it would be a common use case. But for this demo we want to set the failure domain at the rack-bucket level. We can\u2019t change a defined CRUSH Map ruleset, so delete the bad one: admin:~ # ceph osd crush rule rm bad_ruleset admin:~ # ceph osd crush rule ls replicated_rule Task 4: Create a better CRUSH Map rule \u00b6 Create a more appropriate CRUSH Map rule from the CLI, that will survive the failure of a rack: admin:~ # ceph osd crush rule create-replicated better_ruleset default rack admin:~ # ceph osd crush rule dump better_ruleset { \"rule_id\": 1, \"rule_name\": \"better_ruleset\", \"ruleset\": 1, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"rack\" }, { \"op\": \"emit\" } ] } Task 5: Create CRUSH Map rules for different classes of devices \u00b6 1). Create two different CRUSH Map rules from the CLI, that will accommodate a slow set of devices (HDDs) and a fast set of devices (SDDs): The error of 2 nd is because the cluster does not have any SSD devices. admin:~ # ceph osd crush rule create-replicated slow_devices default host hdd admin:~ # ceph osd crush rule create-replicated fast_devices default host sdd Error EINVAL: device class sdd does not exist 2). Display the details of the new \u201cslow\u201d rule: admin:~ # ceph osd crush rule dump slow_devices { \"rule_id\": 2, \"rule_name\": \"slow_devices\", \"ruleset\": 2, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -2, \"item_name\": \"default~hdd\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } Task 6: Change the ruleset used by a pool \u00b6 1). Show which CRUSH Map Ruleset is being used by the cephfs_data pool: The rule should be listed as replicated_rule. admin:~ # ceph osd pool get cephfs_data crush_rule crush_rule: replicated_rule 2). Change the cephfs_data pool to use the new CRUSH Map ruleset that you created in the previous task. admin:~ # ceph osd pool set cephfs_data crush_rule better_ruleset set pool 2 crush_rule to better_ruleset 3). Verify that the rule has been changed by re-running the earlier command: admin:~ # ceph osd pool get cephfs_data crush_rule crush_rule: better_ruleset 4). In this demo cluster, making the cephfs_data pool use the \u201cbetter_ruleset\u201d will result in problems. (There\u2019s no rack for the CRUSH Map, and not enough nodes to accommodate the requirement for a large numbgr of PGs.) So change the setting back to the replicated_rule. admin:~ # ceph osd pool set cephfs_data crush_rule replicated_rule set pool 2 crush_rule to replicated_rule admin:~ # ceph osd pool get cephfs_data crush_rule crush_rule: replicated_rule Task 7: Create a CRUSH Map rule enhanced with an EC profile 1). Combine the benefits of Erasure Coding with a CRUSH Map rule: This will only work if you have already created an appropriate EC profile called usable_profile. In this demo you would have done in an earlier exercise. And in this demo you need to tie this ec_rule to the usable_profile, not the better_profile.Or else any pool that you create using the ec_rule will fail due to insufficient resources. admin:~ # ceph osd crush rule create-erasure ec_rule usable_profile Link the CRUSH map rule (ec_rule) to EC profile (usable_profile) created rule ec_rule at 3 P.S., The useable_profile was created by : admin:~ # ceph osd erasure-code-profile set usable_profile k=2 m=1 plugin=jerasure technique=reed_sol_van stripe_unit=4K crush-failure-domain=host 2). Display the details of the EC-enhanced CRUSH Map rule: See the added, extra \u201cop\u201d steps. You might also notice the different values for \u201ctype,\u201d \u201cmin_size,\u201d and \u201cmax_size\u201d than what you saw in the standard replicated rules. admin:~ # ceph osd crush rule dump ec_rule { \"rule_id\": 3, \"rule_name\": \"ec_rule\", \"ruleset\": 3, \"type\": 3, \"min_size\": 3, \"max_size\": 3, \"steps\": [ { \"op\": \"set_chooseleaf_tries\", \"num\": 5 }, { \"op\": \"set_choose_tries\", \"num\": 100 }, { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_indep\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd crush rule ls replicated_rule better_ruleset slow_devices ec_rule admin:~ # ceph osd crush rule create-replicated better_ruleset default rack admin:~ # ceph osd crush rule create-replicated slow_devices default host hdd admin:~ # ceph osd crush rule create-erasure ec_rule usable_profile admin:~ # ceph osd crush rule dump replicated_rule { \"rule_id\": 0, \"rule_name\": \"replicated_rule\", \"ruleset\": 0, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd crush rule dump better_ruleset { \"rule_id\": 1, \"rule_name\": \"better_ruleset\", \"ruleset\": 1, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"rack\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd crush rule dump slow_devices { \"rule_id\": 2, \"rule_name\": \"slow_devices\", \"ruleset\": 2, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -2, \"item_name\": \"default~hdd\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd pool osd pool stats {} osd pool scrub [...] osd pool deep-scrub [...] osd pool repair [...] osd pool force-recovery [...] osd pool force-backfill [...] osd pool cancel-force-recovery [...] osd pool cancel-force-backfill [...] osd pool autoscale-status osd pool mksnap admin:~ # ceph osd pool get size min_size pg_num pgp_num crush_rule Hashpspool Nodelete Nopgchange Nosizechange write_fadvise_dontneed Noscrub nodeep-scrub hit_set_type hit_set_period hit_set_count hit_set_fpp use_gmt_hitset target_max_objects target_max_bytes cache_target_dirty_ratio cache_target_dirty_high_ratio cache_target_full_ratio cache_min_flush_age cache_min_evict_age erasure_code_profile min_read_recency_for_promote All min_write_recency_for_promote fast_read hit_set_grade_decay_rate hit_set_search_last_n scrub_min_interval scrub_max_interval deep_scrub_interval recovery_priority recovery_op_priority scrub_priority compression_mode compression_algorithm compression_required_ratio compression_max_blob_size compression_min_blob_size csum_type csum_min_block csum_max_block allow_ec_overwrites fingerprint_algorithm pg_autoscale_mode pg_autoscale_bias pg_num_min target_size_bytes target_size_ratio 2.1.4. Investigate BlueStore \u00b6 Task 1: Explore the drive_groups.yml configuration \u00b6 After deployment, the drive_groups.yml file is where the storage administrator defines the configuration of the cluster\u2019s storage devices. Note the \u201cdata_devices\u201d parameter. In this demo, \u201call\u201d storage devices are data devices for BlueStore. Note that there are no definitions for \u201cwal_devices\u201d or \u201cdb_devices.\u201d That\u2019s because in this demo environment we don\u2019t have any other \u201cfast\u201d devices that would be appropriate for these roles. Since BlueStore is the default, there is no definition of a \u201cformat\u201d for the devices. Otherwise, a \u201cFormat: bluestore\u201d key-value pair might exist to ensure that BlueStore is used. admin:~ # cd /srv/salt/ceph/configuration/files admin:/srv/salt/ceph/configuration/files # cat drive_groups.yml # default: <- just a name - can be anything # target: 'data*' <- must be resolvable by salt's targeting processor # data_devices: # size: 20G # db_devices: # size: 10G # rotational: 1 # allflash: # target: 'fast_nodes*' # data_devices: # size: 100G # db_devices: # size: 50G # rotational: 0 # This is the default configuration and # will create an OSD on all available drives default: target: 'data*' data_devices: all: true Task 2: Examine a storage host\u2019s storage devices \u00b6 admin:~ # ssh data1 Last login: Tue Jan 5 18:06:40 2021 from 10.58.121.181 Should see 3 devices, which are named ceph LVM-type devices data1:~ # lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 8G 0 disk \u2514\u2500ceph--14c886af--269d--475f--8ee3--f5e4abbb222d-osd--data--38911b2d--f30a--4b09--9010--8dd6fad2fcc6 254:0 0 8G 0 lvm sdb 8:16 0 8G 0 disk \u2514\u2500ceph--9ec4a77a--5d67--4b21--be53--d7e9221082de-osd--data--00cb3dc6--c28b--41ae--95de--efb86da254da 254:1 0 8G 0 lvm sdc 8:32 0 8G 0 disk \u2514\u2500ceph--5eaea8a8--bb68--49dd--a1e3--b82c5464ab1f-osd--data--a4a05f70--53d9--41d4--a273--4f47a088968a 254:2 0 8G 0 lvm sr0 11:0 1 672M 0 rom vda 253:0 0 20G 0 disk \u251c\u2500vda1 253:1 0 8M 0 part \u251c\u2500vda2 253:2 0 18.4G 0 part / \u2514\u2500vda3 253:3 0 1.7G 0 part [SWAP] See the raw ceph devices data1:~ # ls -lad /dev/ceph* drwxr-xr-x 2 root root 60 Oct 5 13:15 /dev/ceph-14c886af-269d-475f-8ee3-f5e4abbb222d drwxr-xr-x 2 root root 60 Oct 5 13:16 /dev/ceph-5eaea8a8-bb68-49dd-a1e3-b82c5464ab1f drwxr-xr-x 2 root root 60 Oct 5 13:15 /dev/ceph-9ec4a77a-5d67-4b21-be53-d7e9221082de Dig down even farther by examining the content of one of the directories, see a symlink to an LVM device-mapper device. All the devices are tied together with LVM. Note that the name of the symlink is named osd-data- . data1:~ # ls -l /dev/ceph-14c886af-269d-475f-8ee3-f5e4abbb222d lrwxrwxrwx 1 ceph ceph 7 Oct 5 13:15 osd-data-38911b2d-f30a-4b09-9010-8dd6fad2fcc6 -> ../dm-0 data1:~ # l /dev/dm* brw-rw---- 1 ceph ceph 254, 0 Jan 5 18:10 /dev/dm-0 brw-rw---- 1 ceph ceph 254, 1 Jan 5 18:10 /dev/dm-1 brw-rw---- 1 ceph ceph 254, 2 Jan 5 18:10 /dev/dm-2 Task 3: Examine a storage host\u2019s OSD details \u00b6 data1:~ # cd /var/lib/ceph/ data1:/var/lib/ceph # ls -l drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-mds drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-mgr drwxr-x--- 1 ceph ceph 24 Oct 5 13:15 bootstrap-osd drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-rbd drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-rbd-mirror drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-rgw drwxr-x--- 1 ceph ceph 12 Oct 5 09:04 crash drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 mds drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 mgr drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 mon drwxr-x--- 1 ceph ceph 38 Oct 5 13:16 osd drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 tmp See 3 different sub-directories, each representing the 3 different OSDs (ceph-2, ceph-6, ceph-10) that are running on this storage server data1:/var/lib/ceph # cd osd/ data1:/var/lib/ceph/osd # ls -l drwxrwxrwt 2 ceph ceph 320 Oct 5 13:16 ceph-10 drwxrwxrwt 2 ceph ceph 320 Oct 5 13:15 ceph-2 drwxrwxrwt 2 ceph ceph 320 Oct 5 13:16 ceph-6 See some functional files associated with the OSD and BlueStore. See a block file, which is a symlink to one of the ceph devices, which stores the raw objects for the OSD. data1:/var/lib/ceph/osd # cd ceph-2 data1:/var/lib/ceph/osd/ceph-2 # ls -l -rw-r--r-- 1 ceph ceph 400 Oct 5 13:15 activate.monmap lrwxrwxrwx 1 ceph ceph 92 Oct 5 13:15 block -> /dev/ceph-14c886af-269d-475f-8ee3-f5e4abbb222d/osd-data-38911b2d-f30a-4b09-9010-8dd6fad2fcc6 -rw------- 1 ceph ceph 2 Oct 5 13:15 bluefs -rw------- 1 ceph ceph 37 Oct 5 13:15 ceph_fsid -rw-r--r-- 1 ceph ceph 37 Oct 5 13:15 fsid -rw------- 1 ceph ceph 55 Oct 5 13:15 keyring -rw------- 1 ceph ceph 8 Oct 5 13:15 kv_backend -rw------- 1 ceph ceph 21 Oct 5 13:15 magic -rw------- 1 ceph ceph 4 Oct 5 13:15 mkfs_done -rw------- 1 ceph ceph 41 Oct 5 13:15 osd_key -rw------- 1 ceph ceph 6 Oct 5 13:15 ready -rw------- 1 ceph ceph 3 Oct 5 13:15 require_osd_release -rw------- 1 ceph ceph 10 Oct 5 13:15 type -rw------- 1 ceph ceph 2 Oct 5 13:15 whoami data1:/var/lib/ceph/osd/ceph-2 # cat ceph_fsid # The unique ID of this Ceph cluster 343ee7d3-232f-4c71-8216-1edbc55ac6e0 data1:/var/lib/ceph/osd/ceph-2 # cat fsid # The unique ID of this OSD 6df58ebc-dbfe-4822-9714-90212c06ea05 data1:/var/lib/ceph/osd/ceph-2 # cat keyring # The Ceph key for this OSD [osd.2] key = data1:/var/lib/ceph/osd/ceph-2 # cat ready # Indication of the readiness of this OSD ready data1:/var/lib/ceph/osd/ceph-2 # cat type # filestore or bluestore (in this case: bluestore) bluestore data1:/var/lib/ceph/osd/ceph-2 # cat whoami # The integer id of this OSD (in this case: 2) 2 Task 4: Display BlueStore information using ceph-bluestore-tool \u00b6 Show BlueStore metadata for osd.2: data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool show-label --path /var/lib/ceph/osd/ceph-2 inferring bluefs devices from bluestore path { \"/var/lib/ceph/osd/ceph-2/block\": { \"osd_uuid\": \"6df58ebc-dbfe-4822-9714-90212c06ea05\", \"size\": 8585740288, \"btime\": \"2020-10-05 13:15:51.227799\", \"description\": \"main\", \"bluefs\": \"1\", \"ceph_fsid\": \"343ee7d3-232f-4c71-8216-1edbc55ac6e0\", \"kv_backend\": \"rocksdb\", \"magic\": \"ceph osd volume v026\", \"mkfs_done\": \"yes\", \"osd_key\": , \"ready\": \"ready\", \"require_osd_release\": \"14\", \"whoami\": \"2\" } Run a manual \u201cscrub\u201d on osd.7 using ceph-blestore-tool. (Received error, the tool won\u2019t allow you to do this while the OSD is running.) data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool fsck --path /var/lib/ceph/osd/ceph-2 error from fsck: (11) Resource temporarily unavailable 2021-01-05 18:32:25.528 7f4abad6e180 -1 bluestore(/var/lib/ceph/osd/ceph-2) _lock_fsid failed to lock /var/lib/ceph/osd/ceph-2/fsid (is another ceph-osd still running?)(11) Resource temporarily unavailable Simulate that the OSD is down, shutdown the OSD: data1:/var/lib/ceph/osd/ceph-2 # systemctl stop ceph-osd@2.service Now run the \u201cfsck\u201d command again. This time the \u201cfsck\u201d has worked, with the output showing: \u201cfsck success\u201d data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool fsck --path /var/lib/ceph/osd/ceph-2 fsck success Restart the OSD: data1:/var/lib/ceph/osd/ceph-2 # systemctl start ceph-osd@2.service data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool show-label --path /var/lib/ceph/osd/ceph-2 inferring bluefs devices from bluestore path { \"/var/lib/ceph/osd/ceph-2/block\": { \"osd_uuid\": \"6df58ebc-dbfe-4822-9714-90212c06ea05\", \"size\": 8585740288, \"btime\": \"2020-10-05 13:15:51.227799\", \"description\": \"main\", \"bluefs\": \"1\", \"ceph_fsid\": \"343ee7d3-232f-4c71-8216-1edbc55ac6e0\", \"kv_backend\": \"rocksdb\", \"magic\": \"ceph osd volume v026\", \"mkfs_done\": \"yes\", \"osd_key\": , \"ready\": \"ready\", \"require_osd_release\": \"14\", \"whoami\": \"2\" } } 2.2. Common Day 1 Tasks Using the CLI \u00b6 Including ollowing topics in relation to the commandline: Users and Ceph Configuration Health commands Erasure Code Profiles CRUSH Map rules Pools Scrubbing OSDs and Placement Groups Manager modules The tell commands 2.2.1. Ceph Users and Configuration \u00b6 Task 1: View the current user keyrings \u00b6 Ceph keyrings are stored in below directory admin:~ # cd /etc/ceph/ admin:/etc/ceph # ls -l -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap The value of 'key' is the key that\u2019s on the keyring. The admin keyring is \u201callow\u201ded all capabilities (permissions) to all services in the cluster, as expected. there are more than just client keys. admin:/etc/ceph # cat ceph.client.admin.keyring [client.admin] key = caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" Display the existing users with the \u201cauth\u201d command: Below two commands are equivalent admin:/etc/ceph # ceph -n client.admin -keyring=/etc/ceph/ceph.client.admin.keyring auth ls -- failed??? no valid command found admin:/etc/ceph # ceph auth ls installed auth entries: mds.mon1 key: caps: [mds] allow * caps: [mgr] allow profile mds caps: [mon] allow profile mds caps: [osd] allow rwx mds.mon2 key: caps: [mds] allow * caps: [mgr] allow profile mds caps: [mon] allow profile mds caps: [osd] allow rwx mds.mon3 key: caps: [mds] allow * caps: [mgr] allow profile mds caps: [mon] allow profile mds caps: [osd] allow rwx osd.0 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.1 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.10 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.11 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.2 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.3 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.4 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.5 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.6 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.7 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.8 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.9 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * client.admin key: caps: [mds] allow * caps: [mgr] allow * caps: [mon] allow * caps: [osd] allow * client.bootstrap-mds key: caps: [mon] allow profile bootstrap-mds client.bootstrap-mgr key: caps: [mon] allow profile bootstrap-mgr client.bootstrap-osd key: caps: [mgr] allow r caps: [mon] allow profile bootstrap-osd client.bootstrap-rbd key: caps: [mon] allow profile bootstrap-rbd client.bootstrap-rbd-mirror key: caps: [mon] allow profile bootstrap-rbd-mirror client.bootstrap-rgw key: caps: [mon] allow profile bootstrap-rgw client.igw.mon2 key: caps: [mgr] allow r caps: [mon] allow * caps: [osd] allow * client.rgw.mon3 key: caps: [mgr] allow r caps: [mon] allow rwx caps: [osd] allow rwx client.storage key: caps: [mon] allow rw mgr.mon1 key: caps: [mds] allow * caps: [mon] allow profile mgr caps: [osd] allow * Task 2: Create a new keyring and associated user \u00b6 1). There are several different ways to create a new keyring and user. This is just one way. Create a new keyring and associated user named James . Remembgr that typically all new users will need read rights for the mon capability, and will need read/write rights for the osd capability, including a specification of rights to a pool. admin:/etc/ceph # ceph-authtool -g -n client.james --cap mon 'allow r' --cap osd 'allow rw pool=iscsi-images' -C /etc/ceph/ceph.client.james.keyring creating /etc/ceph/ceph.client.james.keyring admin:/etc/ceph # l total 16 drwxr-xr-x 1 root root 130 Jan 5 19:31 ./ drwxr-xr-x 1 root root 4392 Oct 5 13:03 ../ -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw------- 1 root root 126 Jan 5 19:31 ceph.client.james.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap 2). Show the content of the newly created keyring: admin:/etc/ceph # cat ceph.client.james.keyring [client.james] key = caps mon = \"allow r\" caps osd = \"allow rw pool=iscsi-images\" 3). Officially add the new keyring to Ceph: admin:/etc/ceph # ceph auth add client.james -i /etc/ceph/ceph.client.james.keyring added key for client.james 4). Show the key information using the \u201cauth\u201d function: admin:/etc/ceph # ceph auth get client.james exported keyring for client.james [client.james] key = caps mon = \"allow r\" caps osd = \"allow rw pool=iscsi-images\" Task 3: Create a client key for RBD \u00b6 1). Change to the directory that contains the ceph keyrings. admin:~ # cd /etc/ceph/ 2). List the content of the directory: Although you see the admin users\u2019s keyring, ceph.client.admin.keyring, there is not yet a file that is appropriate for a specific application to use. Also note that the permissions on the keyring file are quite restrictive: 0600 admin:/etc/ceph # ls -l -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw------- 1 root root 126 Jan 5 19:31 ceph.client.james.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap 3). Show the content of the admin user\u2019s keyring: You will use the value associated with the \u201ckey\u201d key to create a new file. Copy the \u201ckey\u201d value using your favorite method. admin:/etc/ceph # cat ceph.client.admin.keyring [client.admin] key = caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" 4). Open a new file for editing called admin.secret using your favorite editor (such as vi): The name of the file isn\u2019t very important, but naming it this way will help to identify its purpose: it\u2019s a secret key for the admin user. Note that there are many ways to do this. An alternative way is mentioned in the tip below that will do this in one step using grep and awk. admin:/etc/ceph # vi admin.secret 5). Paste the \u201ckey\u201d value into the new file. It will be the only content of the file. It will look like this (in fact it\u2019s probably exactly the same as this, if you\u2019re using the demo environment provided to you): admin:/etc/ceph # cat admin.secret 6). Save the file and exist out of the editor. 7). Change the permissions of the file so that no other user on the host can see the content of the file: admin:/etc/ceph # chmod 0600 admin.secret admin:/etc/ceph # l drwxr-xr-x 1 root root 154 Jan 5 20:03 ./ drwxr-xr-x 1 root root 4392 Oct 5 13:03 ../ -rw------- 1 root root 41 Jan 5 20:03 admin.secret -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw------- 1 root root 126 Jan 5 19:31 ceph.client.james.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap Tip: An alternative way to create this key file is to simply use grep/awk together in one bash command, like this: admin:/etc/ceph # grep \"key =\" ceph.client.admin.keyring | awk -F\" = \" '{ print $2 }' admin:/etc/ceph # grep \"key =\" ceph.client.admin.keyring | awk -F\" = \" '{ print $2 }' > admin.secret admin:/etc/ceph # cat admin.secret Task 4: View the Ceph master configuration file \u00b6 View the content of the file. The file is managed and controlled by DeepSea. The comment makes reference to the control files in the /srv/salt/ceph/configuration/ directory hierarchy. This is a very simple storage cluster. In a more diverse and sophisticated ceph cluster there may be more configuration settings defined. Although this exercise doesn\u2019t call out any more specific information about this configuration file, you may take a moment to consider the content of the file before finishing the task. admin:/etc/ceph # cat ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.186, 10.58.121.187, 10.58.121.188 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] admin:/etc/ceph # ls -l /srv/salt/ceph/configuration/ drwxr-xr-x 1 salt salt 18 Oct 5 13:13 cache drwxr-xr-x 1 root root 38 Oct 5 09:04 check drwxr-xr-x 1 root root 74 Oct 5 09:04 create -rw-r--r-- 1 root root 217 May 14 2020 default-import.sls -rw-r--r-- 1 root root 222 May 14 2020 default.sls drwxr-xr-x 1 root root 276 Oct 5 12:55 files -rw-r--r-- 1 root root 74 May 14 2020 init.sls 2.2.2. Run the Ceph Health Commands \u00b6 Get overall health status admin:~ # ceph health HEALTH_OK admin:~ # ceph -s admin:~ # ceph status cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 5w) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 98m), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 208 pgs objects: 246 objects, 4.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 208 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr Run the \u201cstatus\u201d command for the monitors: admin:~ # ceph mon stat e1: 3 mons at { mon1=[v2:10.58.121.186:3300/0,v1:10.58.121.186:6789/0], mon2=[v2:10.58.121.187:3300/0,v1:10.58.121.187:6789/0], mon3=[v2:10.58.121.188:3300/0,v1:10.58.121.188:6789/0] }, election epoch 22, leader 0 mon1, quorum 0,1,2 mon1,mon2,mon3 Run the \u201cstatus\u201d command for the placement groups: admin:~ # ceph pg stat 208 pgs: 208 active+clean; 4.7 KiB data, 2.1 GiB used, 82 GiB / 96 GiB avail; 852 B/s rd, 0 op/s Run the ceph \u201cstatus\u201d command while watching for changes to the status: admin:~ # ceph -s --watch-debug cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 5w) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 104m), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 208 pgs objects: 246 objects, 4.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 208 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr 2021-01-05 20:20:53.947298 mgr.mon1 [DBG] pgmap v1597415: 208 pgs: 208 active+clean; 4.7 KiB data, 2.1 GiB used, 82 GiB / 96 GiB avail; 852 B/s rd, 0 op/s 2021-01-05 20:20:55.949294 mgr.mon1 [DBG] pgmap v1597416: 208 pgs: 208 active+clean; 4.7 KiB data, 2.1 GiB used, 82 GiB / 96 GiB avail; 1.2 KiB/s rd, 1 op/s ....... 2.2.3. Manipulate Pools \u00b6 Task 1: Display a list of the current pools \u00b6 admin:~ # ceph osd pool ls iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log admin:~ # ceph osd pool ls detail pool 1 'iscsi-images' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 448 lfor 0/448/446 flags hashpspool stripe_width 0 application rbd pool 2 'cephfs_data' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 1395 lfor 0/1374/1372 flags hashpspool stripe_width 0 application cephfs pool 3 'cephfs_metadata' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 1385 lfor 0/975/973 flags hashpspool stripe_width 0 pg_autoscale_bias 4 pg_num_min 16 recovery_priority 5 application cephfs pool 4 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 31 flags hashpspool stripe_width 0 application rgw pool 5 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 33 flags hashpspool stripe_width 0 application rgw pool 6 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 35 flags hashpspool stripe_width 0 application rgw pool 7 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 37 flags hashpspool stripe_width 0 application rgw List pools with their index numbgr. Note how the index numbgr matches the index numbgr of the detail listing above. admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log Task 2: Display the usage data and stats of the current pools \u00b6 Display pool usages. Note again index \u201cID\u201d for the pool. admin:~ # ceph df RAW STORAGE: CLASS SIZE AVAIL USED RAW USED %RAW USED hdd 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 TOTAL 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 POOLS: POOL ID STORED OBJECTS USED %USED MAX AVAIL iscsi-images 1 389 B 2 192 KiB 0 25 GiB cephfs_data 2 0 B 0 0 B 0 25 GiB cephfs_metadata 3 7.2 KiB 48 1.5 MiB 0 25 GiB .rgw.root 4 1.2 KiB 4 768 KiB 0 25 GiB default.rgw.control 5 0 B 8 0 B 0 25 GiB default.rgw.meta 6 381 B 3 576 KiB 0 25 GiB default.rgw.log 7 35 KiB 208 35 KiB 0 25 GiB admin:~ # ceph df detail RAW STORAGE: CLASS SIZE AVAIL USED RAW USED %RAW USED hdd 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 TOTAL 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 POOLS: POOL ID STORED OBJECTS USED %USED MAX AVAIL QUOTA OBJECTS QUOTA BYTES DIRTY USED COMPR UNDER COMPR iscsi-images 1 389 B 2 192 KiB 0 25 GiB N/A N/A 2 0 B 0 B cephfs_data 2 0 B 0 0 B 0 25 GiB N/A N/A 0 0 B 0 B cephfs_metadata 3 7.2 KiB 48 1.5 MiB 0 25 GiB N/A N/A 48 0 B 0 B .rgw.root 4 1.2 KiB 4 768 KiB 0 25 GiB N/A N/A 4 0 B 0 B default.rgw.control 5 0 B 8 0 B 0 25 GiB N/A N/A 8 0 B 0 B default.rgw.meta 6 381 B 3 576 KiB 0 25 GiB N/A N/A 3 0 B 0 B default.rgw.log 7 35 KiB 208 35 KiB 0 25 GiB N/A N/A 208 0 B 0 B Display pool usages using rados command admin:~ # rados df POOL_NAME USED OBJECTS CLONES COPIES MISSING_ON_PRIMARY UNFOUND DEGRADED RD_OPS RD WR_OPS WR USED COMPR UNDER COMPR .rgw.root 768 KiB 4 0 12 0 0 0 40 40 KiB 4 4 KiB 0 B 0 B cephfs_data 0 B 0 0 0 0 0 0 0 0 B 0 0 B 0 B 0 B cephfs_metadata 1.5 MiB 48 0 144 0 0 0 0 0 B 111 42 KiB 0 B 0 B default.rgw.control 0 B 8 0 24 0 0 0 0 0 B 0 0 B 0 B 0 B default.rgw.log 35 KiB 208 0 624 0 0 0 5919671 5.6 GiB 3945118 946 KiB 0 B 0 B default.rgw.meta 576 KiB 3 0 9 0 0 0 38 28 KiB 4 3 KiB 0 B 0 B iscsi-images 192 KiB 2 0 6 0 0 0 4184657 4.0 GiB 8 2 KiB 0 B 0 B total_objects 246 total_used 14 GiB total_avail 82 GiB total_space 96 GiB Show the statistics of the pools: admin:~ # ceph osd pool stats pool iscsi-images id 1 client io 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr pool cephfs_data id 2 nothing is going on pool cephfs_metadata id 3 nothing is going on pool .rgw.root id 4 nothing is going on pool default.rgw.control id 5 nothing is going on pool default.rgw.meta id 6 nothing is going on pool default.rgw.log id 7 nothing is going on Show only the statistics about a specific pool: admin:~ # ceph osd pool stats .rgw.root pool .rgw.root id 4 nothing is going on Show which CRUSH Map ruleset was used to create the .rgw.root pool: admin:~ # ceph osd pool get .rgw.root crush_rule crush_rule: replicated_rule Show the list of all the attributes of a pool that can be queried: admin:~ # ceph osd pool get .rgw.root size min_size pg_num pgp_num crush_rule Hashpspool Nodelete Nopgchange Nosizechange write_fadvise_dontneed noscrub|nodeep-scrub hit_set_type hit_set_period hit_set_count hit_set_fpp use_gmt_hitset target_max_objects target_max_bytes cache_target_dirty_ratio cache_target_dirty_high_ratio cache_target_full_ratio cache_min_flush_age cache_min_evict_age erasure_code_profile min_read_recency_for_promote all|min_write_recency_for_promote fast_read|hit_set_grade_decay_rate hit_set_search_last_n scrub_min_interval scrub_max_interval deep_scrub_interval recovery_priority recovery_op_priority scrub_priority compression_mode compression_algorithm compression_required_ratio compression_max_blob_size compression_min_blob_size csum_type|csum_min_block csum_max_block allow_ec_overwrites fingerprint_algorithm pg_autoscale_mode pg_autoscale_bias pg_num_min target_size_bytes target_size_ratio Task 3: Create two new pools, one replicated, one EC \u00b6 1). Create a new replicated pool that will be used for storing block data for RBD. Use the standard replicated_ruleset CRUSH Map: It would be tempting to the use the better_ruleset, but this demo environment doesn\u2019t have enough resources for that. This is a demo environment, so the PG numbgrs will be low. In your production environments, be sure to assign an appropriately high numbgr, or use the pg_autoscaler manager module. admin:~ # ceph osd pool create rbd_pool 4 4 replicated replicated_rule pool 'rbd_pool' created 2). Tell the cluster that you expect to have this new rbd_pool to use 50% of the total capacity: admin:~ # ceph osd pool set rbd_pool target_size_ratio .5 set pool 8 target_size_ratio to .5 3). Create a new EC pool that will be used for storing RGW buckets and objects. Use the usable_profile Erasure Code profile that was created in an earlier exercise. And use the ec_rule CRUSH Map ruleset that was created in an earlier exercise: admin:~ # ceph osd pool create bucket_pool 4 4 erasure usable_profile ec_rule pool 'bucket_pool' created 4). Tell the cluster that you expect to have this new bucket_pool to use 100GB of data: POOL_TARGET_SIZE_BYTES_OVERCOMMITTED admin:~ # ceph osd pool set bucket_pool target_size_bytes 100000000000 set pool 9 target_size_bytes to 100000000000 5). Enable the PG Autoscaler feature on the two new pools, to ensure that we have an appropriate assignment of placement groups in the demo cluster: This presumes that you completed an earlier exercise that enable the pg_autoscaler manager module. admin:~ # ceph osd pool set bucket_pool pg_autoscale_mode on set pool 9 pg_autoscale_mode to on admin:~ # ceph osd pool set rbd_pool pg_autoscale_mode on set pool 8 pg_autoscale_mode to on 6). Again display a list of all the pools, which will now include the two new pools that you\u2019ve just created: Notice in the detail listing that the two new pools don\u2019t have an application attribute assigned to them. admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log 8 rbd_pool 9 bucket_pool admin:~ # ceph osd pool ls detail pool 1 'iscsi-images' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 448 lfor 0/448/446 flags hashpspool stripe_width 0 application rbd pool 2 'cephfs_data' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 1395 lfor 0/1374/1372 flags hashpspool stripe_width 0 application cephfs pool 3 'cephfs_metadata' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 1385 lfor 0/975/973 flags hashpspool stripe_width 0 pg_autoscale_bias 4 pg_num_min 16 recovery_priority 5 application cephfs pool 4 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 31 flags hashpspool stripe_width 0 application rgw pool 5 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 33 flags hashpspool stripe_width 0 application rgw pool 6 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 35 flags hashpspool stripe_width 0 application rgw pool 7 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 37 flags hashpspool stripe_width 0 application rgw pool 8 'rbd_pool' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 1415 lfor 0/0/1413 flags hashpspool stripe_width 0 target_size_ratio 0.5 pool 9 'bucket_pool' erasure size 3 min_size 2 crush_rule 3 object_hash rjenkins pg_num 4 pgp_num 4 autoscale_mode on last_change 1410 flags hashpspool stripe_width 8192 target_size_bytes 100000000000 7). Check the pg_autoscale status, particularly to see a comparison of how much raw space is being consumed by the two pools: See that the RATE column for all of the replicated pools shows the value of 3.0, while the value for the bucket_pool \u2013 which is an EC pool \u2013 is 1.5. The EC pool, with a K+M of 2+1 consumes considerably less raw storage space. See the TARGET RATIO for the rbd_pool. Notice that the autoscaler has automatically adjusted the numbgr PGs assigned to rbd_pool from \u201c4\u201d to \u201c128\u201d because you told the cluster to have the pool use 50% of the capacity. See the TARGET SIZE for the bucket_pool, roughly 100GB. But the cluster may not have changed the PG_NUM value yet. The autoscaler will adjust the numbgr of PGs gradually, so as not to disrupt the performance too dramatically. While you\u2019re here, you might also notice the RAW CAPACITY column. All pools are expecting to divide the cluster space equally, even though you\u2019ve explicitly told the cluster that rbd_pool and bucket_pool will deviate from that even division. admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 32 on cephfs_data 0 3.0 98256M 0.0000 1.0 32 off cephfs_metadata 7412 3.0 98256M 0.0000 4.0 16 off .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 35900 3.0 98256M 0.0000 1.0 32 warn rbd_pool 0 3.0 98256M 0.0000 0.5000 1.0 32 on bucket_pool 0 95367M 1.5 98256M 1.4559 1.0 4 on Task 4: Assign an application to the two new pools \u00b6 1). Assign the rbd application to the new rbd_pool that you created in the previous task: admin:~ # ceph osd pool application enable rbd_pool rbd enabled application 'rbd' on pool 'rbd_pool' 2). Instruct the cluster to prepare the new rbd_pool for storing block device images: admin:~ # rbd pool init rbd_pool 3). Assign the rgw application to the new bucket_pool that you created in the previous task: admin:~ # ceph osd pool application enable bucket_pool rgw enabled application 'rgw' on pool 'bucket_pool' 4). Display a list of all the pools again, this time noticing that the application attribute is set on the two new pools. admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log 8 rbd_pool 9 bucket_pool admin:~ # ceph osd pool ls detail pool 1 'iscsi-images' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 448 lfor 0/448/446 flags hashpspool stripe_width 0 application rbd pool 2 'cephfs_data' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 1395 lfor 0/1374/1372 flags hashpspool stripe_width 0 application cephfs pool 3 'cephfs_metadata' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 1385 lfor 0/975/973 flags hashpspool stripe_width 0 pg_autoscale_bias 4 pg_num_min 16 recovery_priority 5 application cephfs pool 4 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 31 flags hashpspool stripe_width 0 application rgw pool 5 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 33 flags hashpspool stripe_width 0 application rgw pool 6 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 35 flags hashpspool stripe_width 0 application rgw pool 7 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 37 flags hashpspool stripe_width 0 application rgw pool 8 'rbd_pool' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 1420 lfor 0/0/1413 flags hashpspool,selfmanaged_snaps stripe_width 0 target_size_ratio 0.5 application rbd removed_snaps [1~3] pool 9 'bucket_pool' erasure size 3 min_size 2 crush_rule 3 object_hash rjenkins pg_num 4 pgp_num 4 autoscale_mode on last_change 1422 flags hashpspool stripe_width 8192 target_size_bytes 100000000000 application rgw 5). Another way to display which application is assigned to a pool is: admin:~ # ceph osd pool application get bucket_pool { \"rgw\": {} } admin:~ # ceph osd pool application get rbd_pool { \"rbd\": {} } Task 5: Manage snapshots of the new RGW bucket pool \u00b6 1). Display a list of the snapshots that exist of the bucket_pool that you created in the previous task: The output show that there are \u201c0 snaps.\u201d Right, it is a little funny that you only list the snapshots with rados command; no such functionality exists with the ceph osd pool command. admin:~ # rados -p bucket_pool lssnap 0 snaps 2). Take (make) a snapshot of the rbd_pool: admin:~ # ceph osd pool mksnap bucket_pool brand_new_pool_snapshot created pool bucket_pool snap brand_new_pool_snapshot 3). Display the list of the snapshots again: admin:~ # rados -p bucket_pool lssnap 1 brand_new_pool_snapshot 2021.01.05 22:23:23 1 snaps 4). Remove the snapshot: admin:~ # ceph osd pool rmsnap bucket_pool brand_new_pool_snapshot removed pool bucket_pool snap brand_new_pool_snapshot 5). Display the list of the snapshots again: admin:~ # rados -p bucket_pool lssnap 0 snaps 2.2.4. Maintain consistency of data with Scrub and Repair \u00b6 Scrubbing is like \u201cfsck,\u201d which ensures that OSDs have durable, consistent data. Most of the scrubbing of OSDs happens automatically on a periodic basis. Task 1: Display a few of the Scrub settings \u00b6 1). Show the possible configuration settings related to scrub: If you simply grep for \u201cscrub\u201d you\u2019ll get more than you really want; there are some mon_scrub settings that aren\u2019t related to this exercise. admin:~ # ceph config ls | grep osd_scrub osd_scrub_invalid_stats osd_scrub_during_recovery osd_scrub_begin_hour osd_scrub_end_hour osd_scrub_begin_week_day osd_scrub_end_week_day osd_scrub_load_threshold osd_scrub_min_interval osd_scrub_max_interval osd_scrub_interval_randomize_ratio osd_scrub_backoff_ratio osd_scrub_chunk_min osd_scrub_chunk_max osd_scrub_sleep osd_scrub_auto_repair osd_scrub_auto_repair_num_errors osd_scrub_max_preemptions osd_scrub_priority osd_scrub_cost admin:~ # ceph config ls | grep osd_deep_scrub osd_deep_scrub_interval osd_deep_scrub_randomize_ratio osd_deep_scrub_stride osd_deep_scrub_keys osd_deep_scrub_update_digest_min_age osd_deep_scrub_large_omap_object_key_threshold osd_deep_scrub_large_omap_object_value_sum_threshold admin:~ # ceph config ls | grep scrub mon_warn_pg_not_scrubbed_ratio mon_warn_pg_not_deep_scrubbed_ratio mon_scrub_interval mon_scrub_timeout mon_scrub_max_keys mon_scrub_inject_crc_mismatch mon_scrub_inject_missing_keys osd_op_queue_mclock_scrub_res osd_op_queue_mclock_scrub_wgt osd_op_queue_mclock_scrub_lim osd_scrub_invalid_stats osd_max_scrubs osd_scrub_during_recovery osd_scrub_begin_hour osd_scrub_end_hour osd_scrub_begin_week_day osd_scrub_end_week_day osd_scrub_load_threshold osd_scrub_min_interval osd_scrub_max_interval osd_scrub_interval_randomize_ratio osd_scrub_backoff_ratio osd_scrub_chunk_min osd_scrub_chunk_max osd_scrub_sleep osd_scrub_auto_repair osd_scrub_auto_repair_num_errors osd_scrub_max_preemptions osd_deep_scrub_interval osd_deep_scrub_randomize_ratio osd_deep_scrub_stride osd_deep_scrub_keys osd_deep_scrub_update_digest_min_age osd_deep_scrub_large_omap_object_key_threshold osd_deep_scrub_large_omap_object_value_sum_threshold osd_debug_deep_scrub_sleep osd_scrub_priority osd_scrub_cost osd_requested_scrub_priority mds_max_scrub_ops_in_progress 2). Get the value of a few of the different scrub schedule settings: Note that \u201c0\u201d and \u201c24\u201d are the same setting. admin:~ # ceph config get osd.* osd_scrub_begin_hour 0 admin:~ # ceph config get osd.* osd_scrub_end_hour 24 3). Get the value of the scrub and repair settings: The \u201cauto repair\u201d feature is turned off, and the maximum numbgr of errors that \u201cauto repair\u201d would automatically repair is 5. admin:~ # ceph config get osd.* osd_scrub_auto_repair false admin:~ # ceph config get osd.* osd_scrub_auto_repair_num_errors 5 Task 2: Change the Scrub settings in ceph.conf \u00b6 1). Display the ceph.conf, and verify that the file doesn\u2019t have any settings defined yet that are related to scrub. The settings would be located in the [global] section of the file: # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.186, 10.58.121.187, 10.58.121.188 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] 2). Change to the Salt File Server directory that will have Salt control the master ceph.conf configuration file: admin:~ # cd /srv/salt/ceph/configuration/files/ceph.conf.d/ 3). List the content of the directory: The directory is empty. (Well, there is a README, but no other functional files.) admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ls -l -rw-r--r-- 1 root root 1989 May 14 2020 README 4). Create and edit a new file called global.conf. You don\u2019t have to use vi, but this step uses vi as one way of doing it: Be sure that you spell everything correctly, including the absence of \u201c_\u201d characters; there are spaces. Save the file and exit out of the editor. admin:/srv/salt/ceph/configuration/files/ceph.conf.d # vi global.conf Add the following content to the file: osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 5). Use DeepSea (Salt) to stage the file properly in Salt\u2019s File Server on the Salt Master (admin): admin:/srv/salt/ceph/configuration/files/ceph.conf.d # salt admin* state.apply ceph.configuration.create admin.sha.me.corp: Name: /var/cache/salt/minion/files/base/ceph/configuration - Function: file.absent - Result: Changed Started: - 22:42:34.900173 Duration: 20.891 ms Name: /srv/salt/ceph/configuration/cache/ceph.conf - Function: file.managed - Result: Changed Started: - 22:42:34.921454 Duration: 8576.516 ms Name: find /var/cache/salt/master/jobs -user root -exec chown salt:salt {} ';' - Function: cmd.run - Result: Changed Started: - 22:42:43.535022 Duration: 71.957 ms Summary for admin.sha.me.corp ------------ Succeeded: 3 (changed=3) Failed: 0 ------------ Total states run: 3 Total run time: 8.669 s 6). Using DeepSea (Salt), distribute the new ceph.conf configuration settings to all the nodes in the cluster: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # salt \\* state.apply ceph.configuration mon3.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:07.986661 Duration: 101.977 ms Summary for mon3.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 101.977 ms mon1.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.012479 Duration: 108.888 ms Summary for mon1.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 108.888 ms data3.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.052247 Duration: 98.681 ms Summary for data3.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 98.681 ms admin.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.072402 Duration: 97.231 ms Summary for admin.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 97.231 ms data1.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.076279 Duration: 104.169 ms Summary for data1.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 104.169 ms data4.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.081635 Duration: 105.13 ms Summary for data4.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 105.130 ms mon2.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.155758 Duration: 105.004 ms Summary for mon2.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 105.004 ms data2.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.252200 Duration: 109.552 ms Summary for data2.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 109.552 ms 7). Verify that the new ceph.conf settings have been put into place on the admin node: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # cat /etc/ceph/ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] 8). Also verify that other minions in the cluster have also received the updated configuration file, such as on the mon1 and data2 nodes: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ssh mon1 cat /etc/ceph/ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ssh data1 cat /etc/ceph/ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] 9). Apply the settings of the ceph.conf file to appropriate nodes in the cluster: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ceph config assimilate-conf -i /etc/ceph/ceph.conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_health_preluminous_compat = true mon_health_preluminous_compat_warning = false mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 mon_initial_membgrs = mon1, mon2, mon3 Task 3: Change the Scrub settings directly in the Configuration DB \u00b6 1). Query the configuration database to see the value of \u201cosd_scrub_auto_repair_num_errors\u201d: You changed this value to \u201c10\u201d in the previous Task. admin:~ # ceph config get osd.* osd_scrub_auto_repair_num_errors 10 2). Change the value of \u201cosd_scrub_auto_repair_num_errors\u201d to \u201c8\u201d: admin:~ # ceph config set osd.* osd_scrub_auto_repair_num_errors 8 3). Show that the change has taken immediate effect by re-running the same command that was used in the first step: admin:~ # ceph config get osd.* osd_scrub_auto_repair_num_errors 8 Task 4: Manually scrub and repair an OSD and a PG \u00b6 This won\u2019t do much in this demo environment, because the OSDs aren\u2019t storing very much data. But it\u2019s worth having some practice. 1). Start a scrubbing of one of the OSDs: admin:~ # ceph osd scrub osd.1 instructed osd(s) 1 to scrub 2). Scrub a Placement Group: admin:~ # ceph pg scrub 8.1 instructing pg 8.1 on osd.0 to scrub 3). Repair an OSD: admin:~ # ceph osd repair osd.1 instructed osd(s) 1 to repair 4). Repair a PG: admin:~ # ceph pg repair 8.1 instructing pg 8.1 on osd.0 to repair 5). Show what\u2019s currently happening to the OSD that you instructed to have scrubbed and repaired: admin:~ # ceph osd dump | grep osd.1 max_osd 12 osd.1 up in weight 1 up_from 10 up_thru 1415 down_at 0 last_clean_interval [0,0) v1:10.58.121.185:6800/11157 v1:10.58.121.185:6801/11157 exists,up 32c78078-1878-4fac-9738-00d8bf80deea osd.10 up in weight 1 up_from 18 up_thru 1413 down_at 0 last_clean_interval [0,0) v1:10.58.121.182:6808/11130 v1:10.58.121.182:6809/11130 exists,up 6cb26fdc-09b1-42de-8855-7203931a0101 osd.11 up in weight 1 up_from 18 up_thru 1415 down_at 0 last_clean_interval [0,0) v1:10.58.121.185:6808/11995 v1:10.58.121.185:6809/11995 exists,up cc22107d-0239-4874-8308-6c137c8a0931 6). Show what\u2019s currently happening to the PG that you instructed to have scrubbed and repaired: admin:~ # ceph pg dump | grep \"8\\.1\" dumped all 8.16 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.383909 0'0 1423:27 [6,4,5] 6 [6,4,5] 6 0'0 2021-01-05 20:53:47.314062 0'0 2021-01-05 20:53:47.314062 0 8.17 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:01.044252 0'0 1424:30 [1,6,8] 1 [1,6,8] 1 0'0 2021-01-05 22:57:01.044098 0'0 2021-01-05 22:57:01.044098 0 8.14 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:56:56.081480 0'0 1424:30 [1,2,4] 1 [1,2,4] 1 0'0 2021-01-05 22:56:56.081356 0'0 2021-01-05 22:56:56.081356 0 8.15 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.375386 0'0 1423:27 [3,5,0] 3 [3,5,0] 3 0'0 2021-01-05 20:53:53.231124 0'0 2021-01-05 20:48:05.301705 0 8.12 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.370121 0'0 1423:27 [11,2,8] 11 [11,2,8] 11 0'0 2021-01-05 20:53:48.149449 0'0 2021-01-05 20:48:05.301705 0 2.18 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 16:44:58.986205 0'0 1423:1630 [10,1,8] 10 [10,1,8] 10 0'0 2021-01-05 13:02:00.365382 0'0 2021-01-02 00:38:58.134100 0 8.13 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.387832 0'0 1423:27 [0,8,1] 0 [0,8,1] 0 0'0 2021-01-05 20:53:56.132358 0'0 2021-01-05 20:48:05.301705 0 8.10 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.368416 0'0 1423:27 [11,3,6] 11 [11,3,6] 11 0'0 2021-01-05 20:53:51.152790 0'0 2021-01-05 20:48:05.301705 0 8.11 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.377871 0'0 1423:24 [3,10,5] 3 [3,10,5] 3 0'0 2021-01-05 20:53:45.195257 0'0 2021-01-05 20:48:05.301705 0 8.1e 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.391754 0'0 1423:47 [0,11,8] 0 [0,11,8] 0 0'0 2021-01-05 20:53:55.081582 0'0 2021-01-05 20:48:05.301705 0 8.1 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:56:39.829397 0'0 1424:54 [0,7,10] 0 [0,7,10] 0 0'0 2021-01-05 22:56:39.829241 0'0 2021-01-05 22:56:39.829241 0 8.1f 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.392315 0'0 1423:27 [7,5,9] 7 [7,5,9] 7 0'0 2021-01-05 20:53:59.988252 0'0 2021-01-05 20:48:05.301705 0 5.4 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 18:21:28.179266 0'0 1423:1554 [7,9,6] 7 [7,9,6] 7 0'0 2021-01-05 18:21:28.179166 0'0 2021-01-05 18:21:28.179166 0 5.b 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 18:37:01.467457 0'0 1423:1547 [2,0,11] 2 [2,0,11] 2 0'0 2021-01-04 23:46:58.132824 0'0 2021-01-02 03:35:41.214192 0 8.19 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:06.059090 0'0 1424:30 [1,8,2] 1 [1,8,2] 1 0'0 2021-01-05 22:57:06.058935 0'0 2021-01-05 22:57:06.058935 0 8.18 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:05.097742 0'0 1424:30 [1,3,6] 1 [1,3,6] 1 0'0 2021-01-05 22:57:05.097670 0'0 2021-01-05 22:57:05.097670 0 1.11 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 00:30:18.193988 0'0 1423:1605 [0,8,6] 0 [0,8,6] 0 0'0 2021-01-05 00:30:18.193868 0'0 2020-12-29 06:30:58.897565 0 8.1b 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:13.146469 0'0 1424:30 [1,4,6] 1 [1,4,6] 1 0'0 2021-01-05 22:57:13.146390 0'0 2021-01-05 22:57:13.146390 0 8.1a 1 0 0 0 0 19 0 0 2 2 active+clean 2021-01-05 21:01:16.386166 1420'2 1423:29 [9,11,10] 9 [9,11,10] 9 0'0 2021-01-05 20:53:48.690239 0'0 2021-01-05 20:48:05.301705 0 8.1d 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.388079 0'0 1423:56 [0,2,3] 0 [0,2,3] 0 0'0 2021-01-05 20:53:54.121281 0'0 2021-01-05 20:48:05.301705 0 8.1c 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.385846 0'0 1423:27 [2,11,7] 2 [2,11,7] 2 0'0 2021-01-05 20:53:55.458714 0'0 2021-01-05 20:48:05.301705 0 2.2.5. Manipulate Manager Modules \u00b6 Task 1: Display the list of enabled Manager Modules \u00b6 1). Run the following command to show the list of enabled manager modules: Note that several modules are already enabled, such as: dashboard, iostat, pg_autosclater, prometheus, and restful. Even though they are not listed, the crash module and the balancer module are already enabled by default. admin:~ # ceph mgr module ls | head { \"always_on_modules\": [ \"balancer\", \"crash\", \"devicehealth\", \"orchestrator_cli\", \"progress\", \"rbd_support\", \"status\", \"volumes\" 2). Demonstrate that the crash module is enabled by running its command with no arguments: A list of \u201c7 closest matches\u201d is displayed, representing possible additional arguments to be used with the crash command. The crash module is therefore available. admin:~ # ceph crash crash info crash ls crash ls-new crash post crash prune crash rm crash stat crash json_report crash archive crash archive-all admin:~ # ceph crash stat 0 crashes recorded Task 2: Use the iostat module to display statistics for the IO of the cluster The iostat module is really simple, but very helpful. Run the command: admin:~ # ceph iostat +-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+ | Read | Write | Total | Read IOPS | Write IOPS | Total IOPS | +-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+ | 1024 B/s | 0 B/s | 1024 B/s | 1 | 0 | 1 | | 1024 B/s | 0 B/s | 1024 B/s | 1 | 0 | 1 | | 0 B/s | 0 B/s | 0 B/s | 0 | 0 | 0 | Task 3: Enable and configure the telemetry manager module 1). Enable the telemetry manager module: admin:~ # ceph mgr module enable telemetry 2). Show the various sub-commands that are associated with the telemetry command: A list of \u201c5 closest matches\u201d is displayed, showing various options. admin:~ # ceph telemetry telemetry status telemetry send {ceph|device [ceph|device...]} {} telemetry show { [...]} telemetry show-device telemetry on {} telemetry off 3). Show the status of the telemetry module: Notice that the output is returned as key/value pairs. Notice also that although the module has been enabled (which you accomplished in the first step of this task), the functionality is not enabled (enable=false). And for most of the keys, a null value is set. See that the url value is set to https://telemetry.ceph.com/report. That means that crash reports and other usage information about this cluster are going to be sent to the Ceph Community. admin:~ # ceph telemetry status { \"url\": \"https://telemetry.ceph.com/report\", \"device_url\": \"https://telemetry.ceph.com/device\", \"enabled\": false, \"last_opt_revision\": 1, \"leaderboard\": false, \"description\": null, \"contact\": null, \"organization\": null, \"proxy\": null, \"interval\": 24, \"channel_basic\": true, \"channel_ident\": false, \"channel_crash\": true, \"channel_device\": true, \"last_upload\": null } 4). Set the description, contact, and organization values: admin:~ # ceph config set mgr mgr/telemetry/contact 'JD ' admin:~ # ceph config set mgr mgr/telemetry/description 'Training Cluster' admin:~ # ceph config set mgr mgr/telemetry/organization 'SUSE Training' 5). Display the telemetry data that is collected to be sent: admin:~ # ceph telemetry show | less 6). With the contact information properly set, enable the telemetry functionality: This is a demo cluster with no connection to the internet, so no telemetry data will actually be sent. admin:~ # ceph telemetry on Error EPERM: Telemetry data is licensed under the Community Data License Agreement - Sharing - Version 1.0 (https://cdla.io/sharing-1-0/). To enable, add '--license sharing-1-0' to the 'ceph telemetry on' command. admin:~ # ceph telemetry on --license sharing-1-0 7). Disable the telemetry module: admin:~ # ceph mgr module disable telemetry admin:~ # ceph telemetry show | less Error ENOTSUP: Module 'telemetry' is not enabled (required by command 'telemetry show'): use `ceph mgr module enable telemetry` to enable it Task 4: Briefly attempt to use the crash manager module \u00b6 1). Show (again) the various sub-commands that are associated with the crash command: admin:~ # ceph crash crash info crash ls crash ls-new crash post crash prune crash rm crash stat crash json_report crash archive crash archive-all 2). Show the current status of the crash database, including the numbgr of crash reports that have been collected so far: It\u2019s likely that the numbgr of crashes recorded in the demo environment is 0. admin:~ # ceph crash stat 0 crashes recorded 2.2.6. Introduction to the Tell command \u00b6 Tell is a very powerful command within Ceph to control the cluster. You don\u2019t use it everyday, but you need to know how to use it when the occasion to use it arises. It\u2019s mostly an Advanced Command, but exposure to it now reduces the stress of learning about it in a more advanced setting later. Run the tell command in a few different circumstances to control the behavior of various Ceph services. Task 1: Run a benchmark test on an OSD \u00b6 1). Run the following command to run and see the result of a benchmark test on osd.8: admin:~ # ceph tell osd.8 bench { \"bytes_written\": 1073741824, \"blocksize\": 4194304, \"elapsed_sec\": 3.7797023200000002, \"bytes_per_sec\": 284081055.35676152, \"iops\": 67.730201567831401 } Task 2: Change the protection setting regarding the deletion of pools \u00b6 1). The default behavior in Ceph is that you can\u2019t delete pools. Try to delete a pool: The output says that you have to be VERY careful and provide more arguments in order to delete a pool admin:~ # ceph osd pool delete rbd_pool Error EPERM: WARNING: this will *PERMANENTLY DESTROY* all data stored in pool rbd_pool. If you are *ABSOLUTELY CERTAIN* that is what you want, pass the pool name *twice*, followed by --yes-i-really-really-mean-it. 2). Try deleting the pool again, this time with the extra arguments: Ceph still won\u2019t let you do it because the mon allow pool delete setting has the value of false. admin:~ # ceph osd pool delete rbd_pool rbd_pool --yes-i-really-really-mean-it Error EPERM: pool deletion is disabled; you must first set the mon_allow_pool_delete config option to true before you can destroy a pool 3). Show that the mon allow pool delete setting has the value of false: Indeed, the output shows that the value is false. admin:~ # ceph config get mon.mon\\* mon_allow_pool_delete false 4). Change to value of the setting using injectargs: Note that the \u201c-\u201d and \u201c_\u201d characters can be confusing. And note that the setting is preceded with the double \u201c--\u201d. The injected args must be enclosed in single quotes. You could have done this with ceph config set, but this is an alternative way to directly \u201ctell\u201d the cluster to change a setting. admin:~ # ceph tell mon.\\* injectargs '--mon-allow-pool-delete=true' mon.mon1: injectargs:mon_allow_pool_delete = 'true' mon.mon2: injectargs:mon_allow_pool_delete = 'true' mon.mon3: injectargs:mon_allow_pool_delete = 'true' 2.3. Ceph Dashboard \u00b6 2.3.1. Access Dashboard \u00b6 Task 1: Set the password for the admin user of the Ceph Dashboard \u00b6 1). In a Bash terminal as the root user, show that the Dashboard module is enabled: \u201cdashboard\u201d should be included in the list of \u201cenabled_modules\u201d at the top of the output. admin:~ # ceph mgr module ls | more \"enabled_modules\": [ \"dashboard\", \"iostat\", \"pg_autoscaler\", \"prometheus\", \"restful\" ], 2). Show the valid dashboard users that have already been created by DeepSea during initial deployment: It\u2019s possible that other users will be listed, but at least the \u201cadmin\u201d user should be displayed in the output. admin:~ # ceph dashboard ac-user-show [\"admin\"] 3). Show the \u201cadmin\u201d user\u2019s information as stored in the user database: You can see that the admin user has a password set, but it is stored as a hash. So you don\u2019t really know what the password is, and have no way of discovering it. admin:~ # ceph dashboard ac-user-show admin {\"username\": \"admin\", \"password\": , \"roles\": [\"administrator\"], \"name\": null, \"email\": null, \"lastUpdate\": 1601874928} 4). Change the \u201cadmin\u201d user\u2019s password for the dashboard: This sets the \u201cadmin\u201d user\u2019s password to the string: mypassword admin:~ # ceph dashboard ac-user-set-password admin mypassword {\"username\": \"admin\", \"password\": , \"roles\": [\"administrator\"], \"name\": null, \"email\": null, \"lastUpdate\": 1609860842} admin:~ # Task 3: Visit the Ceph Dashboard URL \u00b6 admin:~ # salt-call grains.get dashboard_creds local: ---------- admin: admin:~ # ceph mgr services { \"dashboard\": \"https://mon1.sha.me.corp:8443/\", \"prometheus\": \"http://mon1.sha.me.corp:9283/\" } admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 25m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 5h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 9 pools, 244 pgs objects: 247 objects, 5.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 244 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr URL: https://mon1.sha.me.corp:8443/ https://10.58.121.186:8443 2.3.2. Explore the Dashboard Health, Performance, Status \u00b6 Dashboard Status Cluster Status Monitors OSDs Manager Daemons Hosts Object Gateway Metadata Service iSCSI Gateway Performance Client IOPS Client Throughput Client Read/Write Recovery Throughput Scrub Capacity Pools Raw Capacity Objects PGs per OSD PG Status [SUSE Enterprise Storage Portal Cluster\u2192Configuration Cluster\u2192Manager Modules Pools\u2192Create Pool 2.4. Storage Data Access \u00b6 2.4.1. Ensure the SES Cluster is Healthy \u00b6 Task 1: Check the Cluster\u2019s health \u00b6 1). Run the following command to check the status (health) of the SES cluster: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 18h) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 23h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 5.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr 2). Evaluate the output. The cluster in this demonstration environment often doesn\u2019t startup correctly due to the nature of a demo environment and it\u2019s less-predictable resources. Depending on whether any of the following tasks are necessary, followup accordingly to ensure that the cluster is healthy before proceeding with the course lectures or any further exercises. 3). Run the following series of commands to restart the Monitor daemons on each of the Monitor nodes: It\u2019s certainly not necessary to restart the monitor daemons on all of the monitor nodes if only one is down. If you prefer, you can take a different approach to starting the daemon on a single monitor node. admin:~ # for h in mon1 mon2 mon3; \\ do \\ ssh $h systemctl restart ceph-mon@$h; \\ done 4). After waiting a few moments for the daemons to restart, check the status again: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 15s) mgr: mon1(active, since 21h) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 26h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 5.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 767 B/s rd, 0 op/s rd, 0 op/s wr 5). Run the following series of commands to restart the Manager daemons on each of the Monitor nodes: admin:~ # for h in mon1 mon2 mon3; \\ do \\ ssh $h systemctl restart ceph-mgr@$h; \\ done 6). After waiting a few moments for the daemons to restart, check the status again: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 8m) mgr: mon1(active, since 18s) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 26h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.1 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr 7). Run the following command to restart the MDS daemon on the MDS node (mon1): admin:~ # ssh mon1 systemctl restart ceph-mds@mon1.service 8). After waiting a few moments for the mds daemon to restart, check the status again: Look for the mds service to be plain active rather than laggy or crashed admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 17m) mgr: mon1(active, since 8m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 26h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.2 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr 9). Verify if the OSDs \u201cup\u201d and running properly. It is only necessary if the output of ceph -s shows that there are fewer than 9 OSDs shown as being \u201cup\u201d. It\u2019s most likely that a storage node is simply not quite fully booted yet, such that the OSD daemons haven\u2019t fully come up. But if you suspect that the solution requires something different than simply waiting a little longer, you should try the following steps. First, identify which server is hosting the down\u2019d OSDs. One way of doing that is with this command: admin:~ # ceph osd tree ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF -1 0.09357 root default -9 0.02339 host data1 2 hdd 0.00780 osd.2 up 1.00000 1.00000 6 hdd 0.00780 osd.6 up 1.00000 1.00000 10 hdd 0.00780 osd.10 up 1.00000 1.00000 -3 0.02339 host data2 0 hdd 0.00780 osd.0 up 1.00000 1.00000 4 hdd 0.00780 osd.4 up 1.00000 1.00000 9 hdd 0.00780 osd.9 up 1.00000 1.00000 -7 0.02339 host data3 3 hdd 0.00780 osd.3 up 1.00000 1.00000 7 hdd 0.00780 osd.7 up 1.00000 1.00000 8 hdd 0.00780 osd.8 up 1.00000 1.00000 -5 0.02339 host data4 1 hdd 0.00780 osd.1 up 1.00000 1.00000 5 hdd 0.00780 osd.5 up 1.00000 1.00000 11 hdd 0.00780 osd.11 up 1.00000 1.00000 Simply try restarting the storage daemon processes on the affected host, such as with this example: admin:~ # ssh data2 systemctl restart ceph-osd@9.service admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 32m) mgr: mon1(active, since 24m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 27s), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.2 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr If the OSD daemon processes are being stubborn and uncooperative, you may choose to reboot the storage virtual machine entirely. This is one way to do that: admin:~ # ssh data1 systemctl reboot After waiting some time for the daemons to get started, verify that all the OSDs are \u201cup\u201d and that the cluster is healthy: admin:~ # ceph osd tree admin:~ # ceph status 10). Run the following command to restart the RADOS Gateway daemon on the node that is hosting the gateway (mon3): admin:~ # ssh mon3 systemctl restart ceph-radosgw@rgw.mon3.service admin:~ # ssh mon3 systemctl status ceph-radosgw@rgw.mon3.service \u25cf ceph-radosgw@rgw.mon3.service - Ceph rados gateway Loaded: loaded (/usr/lib/systemd/system/ceph-radosgw@.service; enabled; vendor preset: disabled) Active: active (running) since Wed 2021-01-06 21:37:53 CST; 23s ago Main PID: 781880 (radosgw) Tasks: 588 CGroup: /system.slice/system-ceph\\x2dradosgw.slice/ceph-radosgw@rgw.mon3.service \u2514\u2500781880 /usr/bin/radosgw -f --cluster ceph --name client.rgw.mon3 --setuser ceph --setgroup ceph Jan 06 21:37:53 mon3 systemd[1]: Started Ceph rados gateway. 11). After waiting a few moments for the daemon to restart, check the status again: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 39m) mgr: mon1(active, since 30m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 6m), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.2 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr 2.4.2. Use the S3 API to Interact with the RADOS Gateway \u00b6 In this lab we used the s3cmd and radosgw-admin utilities to interact with the SUSE Enterprise Storage cluster. We created a new user, a new bucket, and a new file. We then uploaded the file to the cluster and verified that the object gateway stored it to the cluster. Task 1: Using the s3cmd tool and create an S3 user \u00b6 1). As the root user (password is linux) in a shell or terminal, verify that the s3cmd is available on the admin node: You will likely see an error about configuration files missing, etc. This is enough information to validate the utility is installed. admin:~ # pip --version pip 10.0.1 from /usr/lib/python3.6/site-packages/pip (python 3.6) admin:~ # pip install s3cmd Collecting s3cmd Downloading https://files.pythonhosted.org/packages/26/44/19e08f69b2169003f7307565f19449d997895251c6a6566ce21d5d636435/s3cmd-2.1.0-py2.py3-none-any.whl (145kB) 100% | 153kB 2.7MB/s Collecting python-magic (from s3cmd) Downloading https://files.pythonhosted.org/packages/59/77/c76dc35249df428ce2c38a3196e2b2e8f9d2f847a8ca1d4d7a3973c28601/python_magic-0.4.18-py2.py3-none-any.whl Requirement already satisfied: python-dateutil in /usr/lib/python3.6/site-packages (from s3cmd) (2.7.3) Requirement already satisfied: six>=1.5 in /usr/lib/python3.6/site-packages (from python-dateutil->s3cmd) (1.11.0) Installing collected packages: python-magic, s3cmd Successfully installed python-magic-0.4.18 s3cmd-2.1.0 2). Create a new S3 user to be used: The output will include an access_key value and a secret_key value. You will need both of those values in later steps. admin:~ # radosgw-admin user create --uid=s3user --display-name=S3 User --email=s3user@example.net { \"user_id\": \"s3user\", \"display_name\": \"S3\", \"email\": \"s3user@example.net\", \"suspended\": 0, \"max_buckets\": 1000, \"subusers\": [], \"keys\": [ { \"user\": \"s3user\", \"access_key\": , \"secret_key\": } ], \"swift_keys\": [], \"caps\": [], \"op_mask\": \"read, write, delete\", \"default_placement\": \"\", \"default_storage_class\": \"\", \"placement_tags\": [], \"bucket_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"user_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"temp_url_keys\": [], \"type\": \"rgw\", \"mfa_ids\": [] } Retrieve above information admin:~ # radosgw-admin user info --uid=s3user Task 2: Create a new s3cmd configuration file and a new S3 bucket \u00b6 1). Generate a new s3cmd configuration file from a shell on the admin node: Fill in as listed below: admin:~ # cd ~ admin:~ # s3cmd --configure Enter new values or accept defaults in brackets with Enter. Refer to user manual for detailed description of all options. Access key and Secret key are your identifiers for Amazon S3. Leave them empty for using the env variables. Access Key: Secret Key: Default Region [US]: Use \"s3.amazonaws.com\" for S3 Endpoint and not modify it to the target Amazon S3. S3 Endpoint [s3.amazonaws.com]: mon3.sha.me.corp Use \"%(bucket)s.s3.amazonaws.com\" to the target Amazon S3. \"%(bucket)s\" and \"%(location)s\" vars can be used if the target S3 system supports dns based buckets. DNS-style bucket+hostname:port template for accessing a bucket [%(bucket)s.s3.amazonaws.com]: %(bucket)s.mon3.sha.me.corp Encryption password is used to protect your files from reading by unauthorized persons while in transfer to S3 Encryption password: Path to GPG program [/usr/bin/gpg]: When using secure HTTPS protocol all communication with Amazon S3 servers is protected from 3 rd party eavesdropping. This method is slower than plain HTTP, and can only be proxied with Python 2.7 or newer Use HTTPS protocol [Yes]: No On some networks all internet access must go through a HTTP proxy. Try setting it here if you can't connect to S3 directly HTTP Proxy server name: New settings: Access Key: Secret Key: Default Region: US S3 Endpoint: mon3.sha.me.corp DNS-style bucket+hostname:port template for accessing a bucket: %(bucket)s.mon3.sha.me.corp Encryption password: Path to GPG program: /usr/bin/gpg Use HTTPS protocol: False HTTP Proxy server name: HTTP Proxy server port: 0 Test access with supplied credentials? [Y/n] n Save settings? [y/N] y Configuration saved to '/root/.s3cfg' 2). Test the configuration by checking for existing files or directories: Since no buckets or files have been made available for the user, no items are listed and the command returns you to the prompt with no output. This is normal. If there is an error, your configuration may have a typo in it. The configuration file will have been saved as .s3cfg. Edit the file to match the configuration in step one. admin:~ # s3cmd ls 3). Create a new bucket for uploading files to using the s3cmd: You should see feedback that the bucket has been created. Although not technically required by the S3 API, the bucket name needs to be in all uppercase to avoid a bug with the s3cmd tool itself. admin:~ # s3cmd mb s3://S3CMDTEST Bucket 's3://S3CMDTEST/' created admin:~ # s3cmd ls 2021-01-06 14:04 s3://S3CMDTEST (it's GMT timezone) Task3: Create and upload a file to a bucket using the S3 API \u00b6 1). Create a file with a few words of text: admin:~ # echo \"The mountains are beautiful\" > newfile 2). Put the new file into your bucket using s3cmd: You should see the file being uploaded. admin:~ # s3cmd put newfile s3://S3CMDTEST upload: 'newfile' -> 's3://S3CMDTEST/newfile' [1 of 1] 28 of 28 100% in 3s 7.66 B/s done 3). Verify the file is now in your bucket, safely stored in you SES cluster: admin:~ # s3cmd ls s3://S3CMDTEST 2021-01-06 14:11 28 s3://S3CMDTEST/newfile 2.4.3. Use the swift API to Interact with the RADOS Gateway \u00b6 OpenStack packages for SUSE Install and configure the storage nodes for openSUSE and SUSE Linux Enterprise SUSE Package Hub: python-PasteDeploy Enable SUSE Package Hub extension admin:~ # SUSEConnect -p PackageHub/15.1/x86_64 Install python3-PasteDeploy, which is dependency of python-swift installation admin:~ # zypper in python3-PasteDeploy admin:~ # rpm -ivh python3-PyECLib-1.6.0-1.6.x86_64.rpm warning: python3-PyECLib-1.6.0-1.6.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 3dbdc284: NOKEY error: Failed dependencies: python(abi) = 3.8 is needed by python3-PyECLib-1.6.0-1.6.x86_64 rpmlib(PayloadIsZstd) <= 5.4.18-1 is needed by python3-PyECLib-1.6.0-1.6.x86_64 Add OpenStack Swift Repository for SUSE admin:~ # zypper addrepo -f obs://Cloud:OpenStack:Train/SLE_15_SP1 Train admin:~ # zypper in openstack-swift openstack-swift-account openstack-swift-container openstack-swift-object Task 1: Create a swift subuser \u00b6 1). In a shell or terminal as the root user (password of linux) on the admin node, create a new subuser: The output will contain the access and secret keys for the s3user and a secret key for the new swift subuser.. admin:~ # radosgw-admin subuser create --uid=s3user --subuser=s3user:swift --access=full { \"user_id\": \"s3user\", \"display_name\": \"S3\", \"email\": \"s3user@example.net\", \"suspended\": 0, \"max_buckets\": 1000, \"subusers\": [ { \"id\": \"s3user:swift\", \"permissions\": \"full-control\" } ], \"keys\": [ { \"user\": \"s3user\", \"access_key\": , \"secret_key\": } ], \"swift_keys\": [ { \"user\": \"s3user:swift\", \"secret_key\": } ], \"caps\": [], \"op_mask\": \"read, write, delete\", \"default_placement\": \"\", \"default_storage_class\": \"\", \"placement_tags\": [], \"bucket_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"user_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"temp_url_keys\": [], \"type\": \"rgw\", \"mfa_ids\": [] } 2). Verify that the subuser has access to at least one bucket and list the buckets with a swift command: swift -A http://mon3.sha.me.corp/auth/1.0 -U s3user:swift -K '{SECRET_KEY_FROM_STEP_1}' list admin:~ # swift -A http://mon3.sha.me.corp/auth/1.0 -U s3user:swift -K '' list S3CMDTEST Task 2: Use the swift command to access a file created with the S3cmd tool \u00b6 1). Since the S3 API and the swift API are accessing the same SUSE Enterprise Storage cluster, and since the RADOS gateway is built to be inter-operable with both, you can use the swift API to retrieve the object which was uploaded to SES via the S3 API: swift -A http://mon3.example.net/auth/1.0 -U s3user:swift -K '{SECRET_KEY_FROM_STEP_1}' download -a An example of the command is listed here: admin:~ # swift -A http://mon3.sha.me.corp/auth/1.0 -U s3user:swift -K '' download -a Although we have taken a shortcut by using the -a option (meaning grab every object this user has access to), it illustrates the tool\u2019s capability. We\u2019ve uploaded the newfile with S3, we\u2019ve retrieved it with swift. 2.4.4. Create Snapshots on SES using RBD \u00b6 In this lab we worked with rbd images. We mapped an rbd image to a Linux device file, then created a filesystem and mounted it. Then we created snapshots to preserve the images data state at a particular time, and rolled it back to demonstrate functionality. Task 1: Create a new pool for RBD images \u00b6 1). Access https://mon1.pvg.me.corp:8443 or https://10.58.121.186:8443 2). Log in with the following credentials: Username: admin Password: mypassword 3). Click on the Pools tab near the top of the page 4). Click the Create button and use the following in the available fields: Name: rbd-images Pool type: replicated Placement groups: 16 Crush ruleset: replicated_rule Replicted size: 2 Applications: rbd Compression Mode: none 5). Click Create Pool Task 2: Create a new RBD image in the rbd-images pool \u00b6 6). Create a new RBD image using the rbd command: admin:~ # rbd create --size 1024 rbd-images/barfoo 7). Verify the new image has been created in the rbd-images pool: The new image named barfoo should be displayed. admin:~ # rbd ls -p rbd-images barfoo Task 3: Mount the new image on the admin node and create a filesystem \u00b6 1). As the root user in a shell or terminal on the admin node, map the new rbd image to a block device: admin:~ # rbd map rbd-images/barfoo /dev/rbd0 2). Create a filesystem on the newly mapped device: admin:~ # mkfs.ext4 /dev/rbd0 mke2fs 1.43.8 (1-Jan-2018) Discarding device blocks: done Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: 19da6b86-1989-4834-a365-2f654fcce6f6 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done 3). Mount the image to the /mnt directory: admin:~ # mount /dev/rbd0 /mnt admin:~ # l /mnt total 20 drwxr-xr-x 3 root root 4096 Jan 6 23:48 ./ drwxr-xr-x 1 root root 156 Oct 5 08:53 ../ drwx------ 2 root root 16384 Jan 6 23:48 lost+found/ Task 4: Create a file on the new filesystem and snapshot the rbd image and make some additional changes \u00b6 1). Change to the /mnt directory and create a simple file: admin:~ # cd /mnt admin:/mnt # echo \"This is some sample text\" > start.txt 2). List the directories contents to see that the start.txt file has been created on the storage cluster. admin:/mnt # ls -l total 20 drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 3). Create a snapshot of what the rbd image contained: Wait for confirmation that the snapshot has been created. It should only take a few seconds. admin:/mnt # rbd snap create rbd-images/barfoo@begin 4). List the rbd snapshots for the rbd-images/barfoo image: You should see the new snap called begin listed. admin:/mnt # rbd snap ls rbd-images/barfoo SNAPID NAME SIZE PROTECTED TIMESTAMP 4 begin 1 GiB Wed Jan 6 23:51:12 2021 5). Add another file to the filesystem: admin:/mnt # echo \"Some more text\" > end.txt 6). List the contents of the /mnt to verify the existence of two files. admin:/mnt # ls -l total 24 -rw-r--r-- 1 root root 15 Jan 6 23:52 end.txt drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 7). Create a second snapshot of the rbd-images/barfoo image: admin:/mnt # rbd snap create rbd-images/barfoo@finish 8). List the rbd snapshots: There should be begin and finish snapshots. admin:/mnt # rbd snap ls rbd-images/barfoo SNAPID NAME SIZE PROTECTED TIMESTAMP 4 begin 1 GiB Wed Jan 6 23:51:12 2021 5 finish 1 GiB Wed Jan 6 23:53:15 2021 9). List the contents of the /mnt directory again and verify the two files. 10). Rollback the data to the begin snapshot: This process will be relatively quick because the size of the image is small and we have very little data on it. admin:/mnt # rbd snap rollback rbd-images/barfoo@begin Rolling back to snapshot: 100% complete...done. 11). Change to the root user\u2019s home directory, then remount the image in order to see that the rbd image has been rolled back: admin:/mnt # cd ~ admin:~ # umount /mnt admin:~ # mount /dev/rbd0 /mnt 12). List the contents of the /mnt directory to verify that only the start.txt file exists on the image. admin:/mnt # ls -l total 20 drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 13). Rollback the data to the finish snapshot: admin:/mnt # rbd snap rollback rbd-images/barfoo@finish Rolling back to snapshot: 100% complete...done. 14). Unmount and remount the image: admin:/mnt # cd ~ admin:~ # umount /mnt admin:~ # mount /dev/rbd0 /mnt 15). List the contents of the /mnt directory to show it has indeed been rolled back and contains the start.txt and end.txt files admin:/mnt # ls -l total 24 -rw-r--r-- 1 root root 15 Jan 6 23:52 end.txt drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 16). Change to the root user\u2019s home directory and unmount the image: admin:/mnt # cd ~ admin:~ # umount /mnt 2.4.5. Create and manage COW Clones with rbd \u00b6 In this lab you will created a new pool and block device image in the pool. You then mapped the block storage to a linux device and took a snapshot. Finally you protected the snapshot from modification. This would be done so the snapshot can be safely used as a parent cow image which can then be cloned to create new virtual machines. Task 1: Create a new pool \u00b6 1). View the current osds and pools: admin:~ # ceph osd ls 0 1 2 3 4 5 6 7 8 9 10 11 admin:~ # ceph osd pool ls iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log rbd_pool bucket_pool EC_RBD_Pool default.rgw.buckets.index default.rgw.buckets.data rbd-images 2). Create a new pool called cow-pool: admin:~ # ceph osd pool create cow-pool 128 pool 'cow-pool' created 3). List the available pools to view the new pool using either of the following commands: admin:~ # ceph osd pool ls iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log rbd_pool bucket_pool EC_RBD_Pool default.rgw.buckets.index default.rgw.buckets.data rbd-images cow-pool admin:~ # rados lspools iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log rbd_pool bucket_pool EC_RBD_Pool default.rgw.buckets.index default.rgw.buckets.data rbd-images cow-pool Task 2: Create a block device image in a pool 1). Create a format 2 rbd image called cow-base in the cow-pool storage pool with a size of 1GB *Note that the \u2013image-format statement is optional as format 2 is default admin:~ # rbd create -p cow-pool cow-base --size 1024 --image-format 2 2). Check that the image has been created, that the format is 2 and that layering (COW Clones) is supported admin:~ # rbd -p cow-pool list cow-base admin:~ # rbd -p cow-pool info cow-base rbd image 'cow-base': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 269d5b817222aa block_name_prefix: rbd_data.269d5b817222aa format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:12:31 2021 access_timestamp: Thu Jan 7 10:12:31 2021 modify_timestamp: Thu Jan 7 10:12:31 2021 Task 3: Map the block storage image to a Linux host 1). In a shell or terminal as user root open a terminal window. Using the rbd map command, map an rbd device to the block-storage image created above. admin:~ # rbd map -p cow-pool --image cow-base /dev/rbd1 2). View the mapped block devices admin:~ # rbd showmapped id pool namespace image snap device 0 rbd-images barfoo - /dev/rbd0 1 cow-pool cow-base - /dev/rbd1 3). Note the rbd index numbgr (e.g. rbd0, rbd1) associated with the cow-base image: RBD ___1____ 4). View the devices in /dev. Note the device name(s) admin:~ # ls -l /dev/rbd* brw-rw---- 1 root disk 252, 0 Jan 6 23:49 /dev/rbd0 brw-rw---- 1 root disk 252, 16 Jan 7 10:14 /dev/rbd1 /dev/rbd: total 0 drwxr-xr-x 2 root root 60 Jan 7 10:14 cow-pool drwxr-xr-x 2 root root 60 Jan 6 23:48 rbd-images 5). View the block device:(use the device numbgr from step above) admin:~ # fdisk -l /dev/rbd1 Disk /dev/rbd1: 1 GiB, 1073741824 bytes, 2097152 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 4194304 bytes / 4194304 bytes 6). Format the device with an ext4 filesystem: admin:~ # mkfs.ext4 /dev/rbd1 mke2fs 1.43.8 (1-Jan-2018) Discarding device blocks: done Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: 64c9a973-cf31-4239-881f-ec5642bf34e3 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done 7). Mount the block device on the local filesystem: admin:~ # mkdir /mnt/cow-base admin:~ # mount /dev/rbd1 /mnt/cow-base 8). Test the storage access by creating a file: admin:~ # cd /mnt/cow-base admin:/mnt/cow-base # touch base-image-file admin:/mnt/cow-base # ls base-image-file lost+found Task 4: Snapshot the rbd image and protect the snapshot \u00b6 1). List the snapshots in the cow-base image: admin:/mnt/cow-base # rbd snap ls cow-pool/cow-base 2). Create a snapshot of the cow-base rbd image which contains the base-image-file file admin:/mnt/cow-base # rbd snap create cow-pool/cow-base@base-snap 3). List the snapshot: admin:/mnt/cow-base # rbd snap ls cow-pool/cow-base SNAPID NAME SIZE PROTECTED TIMESTAMP 4 base-snap 1 GiB Thu Jan 7 10:37:13 2021 4). This snapshot will form the parent snapshot for COW clone images so you will now protected it from modification: admin:/mnt/cow-base # rbd snap protect cow-pool/cow-base@base-snap admin:/mnt/cow-base # rbd snap ls cow-pool/cow-base SNAPID NAME SIZE PROTECTED TIMESTAMP 4 base-snap 1 GiB yes Thu Jan 7 10:37:13 2021 Task 5: Create writable COW clones from the parent snapshot 1). Create a COW clone from the cow-base with the base-snap snapshot as the parent image admin:/mnt/cow-base # rbd clone cow-pool/cow-base@base-snap cow-pool/cow-image1 2). Check the information for the new image admin:/mnt/cow-base # rbd -p cow-pool --image cow-image1 info rbd image 'cow-image1': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a1209678cad4 block_name_prefix: rbd_data.26a1209678cad4 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:38:58 2021 access_timestamp: Thu Jan 7 10:38:58 2021 modify_timestamp: Thu Jan 7 10:38:58 2021 parent: cow-pool/cow-base@base-snap overlap: 1 GiB 3). Note that the image has details of the parent image and overlap 4). Repeat steps 2 & 3 for an additional image called cow-image2 admin:/mnt/cow-base # rbd clone cow-pool/cow-base@base-snap cow-pool/cow-image2 admin:/mnt/cow-base # rbd -p cow-pool --image cow-image2 info rbd image 'cow-image2': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a2fbcec7b8d9 block_name_prefix: rbd_data.26a2fbcec7b8d9 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:47:28 2021 access_timestamp: Thu Jan 7 10:47:28 2021 modify_timestamp: Thu Jan 7 10:47:28 2021 parent: cow-pool/cow-base@base-snap overlap: 1 GiB Task 6: Test that the COW clones are functional 1). Create a new directory and mount the COW clone called cow-image1 Note the rbd device name and use it to mount the file system admin:/mnt # mkdir /mnt/cow-image1 admin:/mnt # rbd map -p cow-pool --image cow-image1 /dev/rbd2 admin:/mnt # l total 4 drwxr-xr-x 1 root root 36 Jan 7 10:54 ./ drwxr-xr-x 1 root root 156 Oct 5 08:53 ../ drwxr-xr-x 3 root root 4096 Jan 7 10:19 cow-base/ drwxr-xr-x 1 root root 0 Jan 7 10:54 cow-image1/ admin:/mnt # ls -l /dev/rbd* brw-rw---- 1 root disk 252, 0 Jan 6 23:49 /dev/rbd0 brw-rw---- 1 root disk 252, 16 Jan 7 10:18 /dev/rbd1 brw-rw---- 1 root disk 252, 32 Jan 7 10:55 /dev/rbd2 /dev/rbd: total 0 drwxr-xr-x 2 root root 80 Jan 7 10:55 cow-pool drwxr-xr-x 2 root root 60 Jan 6 23:48 rbd-images admin:/mnt # mount /dev/rbd2 /mnt/cow-image1 2). Check that the base-image-file which was created in the parent snapshot is present admin:/mnt # cd /mnt/cow-image1 admin:/mnt/cow-image1 # ls base-image-file lost+found 3). Repeat steps 1 and 2 for cow-image2 admin:/mnt # mkdir /mnt/cow-image2 admin:/mnt # rbd map -p cow-pool --image cow-image2 /dev/rbd3 admin:/mnt # mount /dev/rbd3 /mnt/cow-image2 admin:/mnt # ls ./cow-image2/ base-image-file lost+found --> same file with image1 4). Create a new file in the directory where cow-image1 is mounted admin:/mnt # cd cow-image1 admin:/mnt/cow-image1 # touch additional-file admin:/mnt/cow-image1 # ls additional-file base-image-file lost+found 5). Look in the cow-image2 directory. Although they share the same parent snapshot, you can see that the files contained in each COW image are now different. admin:/mnt # ls ./cow-image2/ base-image-file lost+found Task 7: Flatten a COW Clone and remove the parent image \u00b6 1). Convert the COW clone called cow-image1 to a standalone rbd image Wait while the flatten process completes. Unlike a clone process this is not instantaneous and can take considerable time. admin:/mnt # rbd flatten cow-pool/cow-image1 Image flatten: 100% complete...done. 2). Check to see that the flatten process has removed the link to the parent snapshot admin:/mnt # rbd -p cow-pool --image cow-image1 info rbd image 'cow-image1': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a1209678cad4 block_name_prefix: rbd_data.26a1209678cad4 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:38:58 2021 access_timestamp: Thu Jan 7 10:38:58 2021 modify_timestamp: Thu Jan 7 10:38:58 2021 admin:/mnt # rbd -p cow-pool --image cow-image2 info rbd image 'cow-image2': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a2fbcec7b8d9 block_name_prefix: rbd_data.26a2fbcec7b8d9 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:47:28 2021 access_timestamp: Thu Jan 7 10:47:28 2021 modify_timestamp: Thu Jan 7 10:47:28 2021 parent: cow-pool/cow-base@base-snap overlap: 1 GiB 3). Unmount the images admin:/mnt # umount /mnt/cow-image1 admin:/mnt # umount /mnt/cow-image2 admin:/mnt # umount /mnt/cow-base 2.4.6. Configure iSCSI on SES \u00b6 In this lab an iSCSI Target was configured via the iSCSI gateway on our SUSE Enterprise Storage. An image was added to it. An iSCSI initiator then connected to the target, created a filesystem, and mounted it. Task 1: Create a new RBD image in the iscsi-images pool \u00b6 1). Create a new RBD image using the rbd command: admin:~ # rbd create --size 1024 iscsi-images/fooiscsi 2). Verify the new image has been created in the iscsi-images pool: The new image named fooiscsi should be displayed. admin:~ # rbd ls iscsi-images fooiscsi Task 2: Define a new iSCSI target with the Ceph Dashboard \u00b6 1). Access the Ceph Dashboard and log in: https://mon1.pvg.me.corp:8443 or https://10.58.121.186:8443 Username: admin Password: mypassword 2). Once logged in, click on the Block drop-down item near the top. Select iSCSI. 3). With the Overview tab showing for iSCSI, click on the Targets tab near the top. Note: When clicking on the Targets tab, if you see an error that says something about \u201cUnsupported `ceph-iscsi` config version\u2026\u201d, perform the following steps: 1. Close the browser window where the error occurred 2. Restart the mon1 virtual machine. Do this with the following steps: from the Virtual Machine Manager on your lab machine (not in the admin virtual machine), restart the mon1 virtual machine by right-clicking on the mon1 virtual machine > Shut Down > Reboot 3. Wait at least 30 seconds, then from the admin node, open up the browser again and log in to the Ceph Dashboard: https://mon1.pvg.me.corp:8443 or https://10.58.121.186:8443 Username: admin Password: mypassword 4. Continue the lab as directed below by navigating to the Block > iSCSI section, clicking on the Targets tab, and completing the steps below 4). Click Add. Use the following values: Target IQN: Portals: mon2.example.net:172.17.6.132 Images: iscsi-images/fooiscsi ACL authentication: Click Create Target. Task 3: Access the new iSCSI target from the admin node \u00b6 1). On the admin node, launch YaST either the ncurses or GUI interface, and select the iSCSI Initiator module: YaST > Network Services > iSCSI Initiator 2). Select the Discovered Targets tab (alt-v) 3). Select Discovery at the bottom of the frame (alt-d) 4). Add the ip address of mon2: 10.58.121.187. Leave the port as the default of 3260. Select Next. 5). Once again on the Discovered Targets tab, the mon2 target should be listed. With the new target highlighted, select Connect (alt-e) at the bottom of the frame. 6). Leave the Startup (in YaST2) or On boot (in YaST) value as manual. Select Next. 7). Select OK to exit the iscsi client configuration module 8). To verify that the iscsi device is now connected, use the lsscsi command to list devices: You should see there is one disk of type RBD connected on a device file similar to the following: admin:~ # lsscsi [0:0:0:0] cd/dvd QEMU QEMU DVD-ROM 1.4. /dev/sr0 [2:0:0:0] disk SUSE RBD 4.0 /dev/sda 9). Create an ext4 filesystem on the connected device file: admin:~ # mkfs.ext4 /dev/sda mke2fs 1.43.8 (1-Jan-2018) Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: e3896f7e-0664-4b14-85db-0f77cb234c43 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done 10). Mount the device to /mnt: admin:~ # mount /dev/sda /mnt 11). Use the mount command to list the connected device: admin:/mnt # mount | grep sda /dev/sda on /mnt type ext4 (rw,relatime,stripe=1024,data=ordered) 12).Change the root user\u2019s home directory and unmount the device: admin:/mnt # cd .. admin:/ # umount /mnt 2.4.7. Mount CephFS Provided by SUSE Enterprise Storage \u00b6 In this lab a ceph user was configured to mount the ceph filesystem provided by the SUSE Enterprise Cluster. A keyfile was generated, then used in the process. Task 1: Verify cephfs configuration of the SES cluster \u00b6 1). Cephfs requires two pools for operation: one for data, the other for metadata. Verify that the cluster has two pools for this purpose: admin:~ # ceph fs ls name: cephfs, metadata pool: cephfs_metadata, data pools: [cephfs_data ] Task 2: Create a secret key file for the admin user on the admin node 1). Because cephx authentication is enabled by default on SUSE Enterprise Storage, a secret key will need to be provided to allow access to mount the ceph filesystem. The admin user (identified \u2013 in this case \u2013 on the system as root) on the admin node has a key, but we will need to either provide it on the command line during the mount process (less secure), or put it in a permissions-restricted file and point to the file when mounting (more secure). If we do not specify the key or a file with the key, we will get an error. The following command will return an error: admin:~ # mount -t ceph mon1:6789:/ /mnt 2021-01-07 14:16:36.924 7f45108a9d80 -1 auth: unable to find a keyring on /etc/ceph/ceph.client.guest.keyring,/etc/ceph/ceph.keyring,/etc/ceph/keyring,/etc/ceph/keyring.bin,: (2) No such file or directory mount error 22 = Invalid argument 2). Take secret key value found in the /etc/ceph/ceph.client.admin.keyring file and put it in a new file: admin:~ # cat /etc/ceph/ceph.client.admin.keyring [client.admin] key = caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" 3). Create a new file and paste the secret key value into it: admin:~ # vi /etc/ceph/admin.secret Put the key value into the file and save it. 4). Change the permissions of the file to be read only by the user: admin:~ # ls -l /etc/ceph/admin.secret -r-------- 1 root root 41 Jan 5 20:05 /etc/ceph/admin.secret Task 3: Mount the ceph filesystem on the admin node \u00b6 1). Now that the keyfile is created, we can mount the filesystem: admin:~ # mount -t ceph mon1:6789:/ /mnt -o name=admin,secretfile=/etc/ceph/admin.secret admin:~ # ls -l /mnt total 0 2). Verify that the mount shows as expected: admin:~ # mount | grep ceph 10.58.121.186:6789:/ on /mnt type ceph (rw,relatime,name=admin,secret=,acl) 3). Change to the root user\u2019s home directory and unmount the filesystem: admin:~ # cd ~ admin:~ # umount /mnt 2.4.8. Export an NFS Share from SES with NFS Ganesha \u00b6 Task 0: Install and configure Ganesha (Ganesha config location is not configured. Please set the GANESHA_RADOS_POOL_NAMESPACE setting.) \u00b6 admin:~ # zypper in nfs-ganesha admin:/etc/ganesha # cat ganesha.conf NFSv4 { RecoveryBackend = 'rados_cluster'; #RecoveryBackend = 'rados_ng'; } RADOS_URLS { ceph_conf = '/etc/ceph/ceph.conf'; userid = \"admin\"; watch_url = \"rados://data/ganesha-export-index/conf-nfs1\"; } RADOS_KV { pool = \"metadata\"; namespace = \"ganesha-grace\"; nodeid = \"nfs1\"; } %url rados://data/ganesha-export-index/conf-nfs1 admin:/etc/ganesha # ganesha-rados-grace -p metadata -n ganesha-grace add nfs1 nfs2 nfs3 admin:/etc/ganesha # ganesha-rados-grace -p metadata -n ganesha-grace cur=1 rec=0 ====================================================== nfs1 E nfs2 E nfs3 E http://images.45drives.com/ceph/cephfs/nfs-ganesha-ceph.conf Task 1: Create an NFS export using the Ceph Dashboard \u00b6 1). In a browser, navigate to a monitor to access the Ceph Dashboard and log in: https://10.58.121.186:8443/ Username: admin Password: mypassword 2). Click on the NFS tab near the top of the page 3). Click on the green Add button 4). Click on the Add daemon button to the right and select mon1 5). Complete the configuration with the following values: Storage Backend: Object Gateway Object Storage User: s3user Path: S3CMDTEST NFS Protocol: NFSv3 and NFSv4 checked NFS Tag: Pseudo: /S3BKT Access Type: RW Squash: root_squash Transport Protocol: UDP and TCP checked Clients: Click Submit Task 2: Mount the NFS export on the admin node \u00b6 1). As the root user on the admin node, query the NFS Ganesha gateway node to see what mounts are available: showmount -e mon1 You should see something similar to the following: Export list for mon1: S3CMDTEST (everyone) 2). Mount the available nfs share to the /mnt directory on the admin server: mount -t nfs mon1:/S3BKT /mnt 3). List the nfs mount: mount | grep mnt Note the type listed as nfs4 4). Change to the root user\u2019s home directory and unmount the export: cd umount /mnt 2.4.9. Configure and Mount CIFS \u00b6 In this lab the Samba gateway was configured. A keyring for the Samba gateway was created, the Samba service was modified, and a user created to allow CIFS access to the SES cluster. Task 1: Prepare the CephFS share for CIFS \u00b6 1). In order for CIFS to work in our SES environment, a valid CephFS share must be available. The CephFS lab previously done in this workbook is sufficient. Using the same configuration that we used previously, mount the CephFS share and give permissions to all users at the root of the share: admin:~ # mount -t ceph mon1:6789:/ /mnt -o name=admin,secretfile=/etc/ceph/admin.secret admin:~ # chmod 777 /mnt admin:~ # l /mnt total 0 drwxrwxrwx 2 root root 0 Oct 5 14:30 ./ drwxr-xr-x 1 root root 156 Oct 5 08:53 ../ admin:~ # umount /mnt Task 2: Create a Samba gateway specific keyring on the Ceph admin node and copy it to the Samba gateway node \u00b6 1). A new keyring will be needed for the Samba gateway to allow access to the Ceph cluster. As root, perform the following: admin:~ # ceph auth get-or-create client.samba.gw mon 'allow r' osd 'allow *' mds 'allow *' -o ceph.client.samba.gw.keyring 2). Copy the new keyring to the Samba gateway node: admin:~ # scp ceph.client.samba.gw.keyring mon1:/etc/ceph/ ceph.client.samba.gw.keyring admin:~ # ssh mon1 Last login: Thu Jan 7 14:35:58 2021 from 10.58.121.181 mon1:~ # ls -l /etc/ceph/ total 12 -rw-r--r-- 1 root root 66 Jan 7 15:15 ceph.client.samba.gw.keyring -rw-r--r-- 1 root root 1095 Jan 5 22:44 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap Task 3: Configure Samba on the Samba gateway node \u00b6 1). The /etc/samba/smb.conf file will need to be edited to allow CIFS access to the storage cluster. On the mon1 node, replace all of the contents of the file with the following: admin:~ # ssh mon1 mon1:~ # vi /etc/samba/smb.conf mon1:/etc/samba # cat smb.conf [global] netbios name = SAMBA-GW clustering = no idmap config * : backend = tdb2 passdb backend = tdbsam # disable print server load printers = no smbd: backgroundqueue = no [ceph-smb] path = / vfs objects = ceph ceph: config_file = /etc/ceph/ceph.conf ceph: user_id = samba.gw read only = no oplocks = no kernel share modes = no 2). Create a smb user on the mon1 node named joesmb with a password of mypassword: mon1:/etc/samba # useradd joesmb mon1:/etc/samba # passwd joesmb ---> 123 Add joesmb to the smb password database with a password of mypassword: mon1:/etc/samba # smbpasswd -a joesmb New SMB password: ---> 123 Retype new SMB password: ---> 123 Added user joesmb. 3). Start and enable the smb and nmb daemons on mon1: mon1:/etc/samba # systemctl start smb nmb mon1:/etc/samba # systemctl enable smb nmb Created symlink /etc/systemd/system/multi-user.target.wants/smb.service \u2192 /usr/lib/systemd/system/smb.service. Created symlink /etc/systemd/system/multi-user.target.wants/nmb.service \u2192 /usr/lib/systemd/system/nmb.service. 4). Unmount the filesystem: mon1:~ # umount /mnt umount: /mnt: not mounted. Task 4: Connect a client to the Samba gateway \u00b6 1). On the admin node, verify that the Samba gateway is sharing via CIFS. The password is 123 admin:~ # smbclient -U joesmb -L //mon1 Enter WORKGROUP\\joesmb's password: ---> 123 Sharename Type Comment --------- ---- ------- ceph-smb Disk IPC$ IPC IPC Service (Samba 4.9.5-git.373.26895a83dbf3.44.1-SUSE-oS15.0-x86_64) Reconnecting with SMB1 for workgroup listing. Server Comment --------- ------- Workgroup Master --------- ------- GLOBAL CNPVGVSYB900 WORKGROUP SAMBA-GW 2). Connect to the ceph-smb share as joesmb. The password is 123 admin:~ # smbclient -U joesmb //mon1/ceph-smb Enter WORKGROUP\\joesmb's password: ---> 123 tree connect failed: NT_STATUS_BAD_NETWORK_NAME You should see output similar to the following: Try \u201chelp\u201d to get a list of possible commands. smb: \\>","title":"SUSE Enterprise Storage Basic Operation"},{"location":"linux/SES/linux_ses_demo/#suse-enterprise-storage-6-installation-and-basic-operation","text":"","title":"SUSE Enterprise Storage 6 Installation and Basic Operation"},{"location":"linux/SES/linux_ses_demo/#1-installation","text":"","title":"1. Installation"},{"location":"linux/SES/linux_ses_demo/#11-environment-setup","text":"In this demo, I use below environment, including VM setting and software installed. All VMs installed here was built on a physical host 10.58.121.68 . Host Server: 10.58.121.68 root / rootroot Account root / root123 Gateway: 10.58.120.1 Network Mask: 255.255.254.0 Nameserver: 10.58.32.32 10.33.50.20 Domain Search sha.me.corp dhcp.sha.me.corp me.corp ind.me.corp bgr.me.corp SUSE Server 15 SP1 Extensions and Modules were installed as below. [x] SUSE Enterprise Storage 6 [x] Basesystem Module 15 SP1 x86_64 [x] Server Applications Module 15 SP1 x86_64 Disable Services is as below: AppArmor Firewall Enable Services is as below. SSH Register SLES15.1 to local SMT. # SUSEConnect --url https://smtproxy.ind.me.corp Demo Environment summary is below. Alias Host Name Memory Disk eth0 eth0 mac address sles01 admin (salt-master) 16GB Disk1: 20G 10.58.121.181/23 52:54:00:23:7d:cd sles02 data1 16GB Disk1: 20G 10.58.121.182/23 52:54:00:5f:ce:6f Disk2: 8G Disk3: 8G Disk4: 8G sles03 data2 16GB Disk1: 20G 10.58.121.183/23 52:54:00:6f:f2:23 Disk2: 8G Disk3: 8G Disk4: 8G sles04 data3 16GB Disk1: 20G 10.58.121.184/23 52:54:00:93:4c:67 Disk2: 8G Disk3: 8G Disk4: 8G sles05 data4 16GB Disk1: 20G 10.58.121.185/23 52:54:00:90:b0:b0 Disk2: 8G Disk3: 8G Disk4: 8G sles06 mon1 16GB Disk1: 20G 10.58.121.186/23 52:54:00:46:43:7a sles07 mon2 16GB Disk1: 20G 10.58.121.187/23 52:54:00:00:fe:6b sles08 mon3 16GB Disk1: 20G 10.58.121.188/23 52:54:00:60:a3:92 Add hostname to file /etc/hosts (all nodes) If you do not specify a cluster network during Ceph deployment, it assumes a single public network environment. Make sure that the fully qualified domain name (FQDN) of each node can be resolved to the public network IP address by all other nodes. # vi /etc/hosts 10.58.121.181 admin.sha.me.corp admin salt 10.58.121.182 data1.sha.me.corp data1 10.58.121.183 data2.sha.me.corp data2 10.58.121.184 data3.sha.me.corp data3 10.58.121.185 data4.sha.me.corp data4 10.58.121.186 mon1.sha.me.corp mon1 10.58.121.187 mon2.sha.me.corp mon2 10.58.121.188 mon3.sha.me.corp mon3 Add all nodes as trust ssh access (root account) # cd ~ # ssh-keygen -t rsa # ssh-copy-id -i ~/.ssh/id_rsa.pub root@admin # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data1 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data2 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data3 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data4 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@mon1 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@mon2 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@mon3 # ssh admin.sha.me.corp # ssh data1.sha.me.corp # ssh data2.sha.me.corp # ssh data3.sha.me.corp # ssh data4.sha.me.corp # ssh mon1.sha.me.corp # ssh mon2.sha.me.corp # ssh mon3.sha.me.corp # ssh salt # ssh admin # ssh data1 # ssh data2 # ssh data3 # ssh data4 # ssh mon1 # ssh mon2 # ssh mon3 Disable firewall (all nodes) # sudo /sbin/SuSEfirewall2 off # firewall-cmd --state not running # systemctl stop firewalld.service # systemctl status firewalld.service firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: disabled) Active: inactive (dead) Docs: man:firewalld(1) Disable IPv6 (all nodes) and Set kernel pid to max value (all nodes) # vi /etc/sysctl.conf net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 net.ipv6.conf.lo.disable_ipv6 = 1 kernel.pid_max = 4194303 # sysctl -p Set DEV_ENV=true in /etc/profile.local in all nodes Install basic software (all nodes) # zypper in -y -t pattern yast2_basis base # zypper in -y net-tools vim man sudo tuned irqbalance # zypper in -y ethtool rsyslog iputils less supportutils-plugin-ses # zypper in -y net-tools-deprecated tree wget Configure NTP service (all nodes), Setting via YaST2 and add server cn.pool.ntp.,org . And /etc/chrony.conf file looks like below. admin:~ # cat /etc/chrony.conf # Use public servers from the pool.ntp.org project. pool cn.pool.ntp.org iburst ! pool pool.ntp.org iburst # Record the rate at which the system clock gains/losses time. driftfile /var/lib/chrony/drift # Allow the system clock to be stepped in the first three updates # if its offset is larger than 1 second. makestep 1.0 3 # Enable kernel synchronization of the real-time clock (RTC). rtcsync # Enable hardware timestamping on all interfaces that support it. #hwtimestamp * # Increase the minimum numbgr of selectable sources required to adjust # the system clock. #minsources 2 # Allow NTP client access from local network. #allow 192.168.0.0/16 # Serve time even if not synchronized to a time source. #local stratum 10 # Specify file containing keys for NTP authentication. #keyfile /etc/chrony.keys # Get TAI-UTC offset and leap seconds from the system tz database. #leapsectz right/UTC # Specify directory for log files. logdir /var/log/chrony # Select which information is logged. #log measurements statistics tracking # Also include any directives found in configuration files in /etc/chrony.d include /etc/chrony.d/*.conf Make /etc/chrony.conf effective. # systemctl enable chronyd.service # systemctl restart chronyd.service # systemctl status chronyd.service # chronyc sources","title":"1.1. Environment Setup"},{"location":"linux/SES/linux_ses_demo/#12-install-packages","text":"Install salt-minion on all nodes. And start the service. Hostname is in file `/etc/salt/minion_id` # zypper in -y salt-minion Uncomment below to let all nodes know who is master # vi /etc/salt/minion master: salt # systemctl enable salt-minion.service # systemctl start salt-minion.service # systemctl status salt-minion.service Install Ceph in admin node. Check log in /var/log/salt admin:~ # zypper in -y salt-master admin:~ # systemctl enable salt-master.service admin:~ # systemctl start salt-master.service admin:~ # systemctl status salt-master.service Note: ganesha will be installed on mon1, not admin node. admin:~ # zypper se ganesha admin:~ # zypper in nfs-ganesha admin:~ # systemctl enable nfs-ganesha admin:~ # systemctl start nfs-ganesha admin:~ # systemctl status nfs-ganesha admin:~ # cd /var/log/salt List fingerprints of all unaccepted minion keys on the Salt master. admin:~ # salt-key -F Local Keys: master.pem: c0:e5:***:04:c7 master.pub: 43:73:***:6a:34 Unaccepted Keys: admin.sha.me.corp: fe:51:***:b9:48 mon1.sha.me.corp: 94:13:***:91:63 mon2.sha.me.corp: c0:fd:***:39:3f mon3.sha.me.corp: 38:fc:***:2e:05 data1.sha.me.corp: b6:6c:***:63:4f data2.sha.me.corp: ab:14:***:c8:ac data3.sha.me.corp: 90:3f:***:76:3b data4.sha.me.corp: d8:12:***:f1:20 If the minions' fingerprints match, accept them admin:~ # salt-key --accept-all The following keys are going to be accepted: Unaccepted Keys: admin.sha.me.corp mon1.sha.me.corp mon2.sha.me.corp mon3.sha.me.corp data1.sha.me.corp data2.sha.me.corp data3.sha.me.corp data4.sha.me.corp Proceed? [n/Y] Y Key for minion admin.sha.me.corp accepted. Key for minion mon1.sha.me.corp accepted. Key for minion mon2.sha.me.corp accepted. Key for minion mon3.sha.me.corp accepted. Key for minion data1.sha.me.corp accepted. Key for minion data2.sha.me.corp accepted. Key for minion data3.sha.me.corp accepted. Key for minion data4.sha.me.corp accepted. Verify that the keys have been accepted admin:~ # salt-key -F admin:~ # salt-key --list-all Accepted Keys: admin.sha.me.corp data1.sha.me.corp data2.sha.me.corp data3.sha.me.corp data4.sha.me.corp mon1.sha.me.corp mon2.sha.me.corp mon3.sha.me.corp Denied Keys: Unaccepted Keys: Rejected Keys: Zero out all drivers which will be used as OSDs (optional) data1:~ lsblk data1:~ # for I in {b,c,d}; do dd if=/dev/zero of=dev/sd$i bs=512 count=40 oflag=direct; done data2:~ # for I in {b,c,d}; do dd if=/dev/zero of=dev/sd$i bs=512 count=40 oflag=direct; done data3:~ # for I in {b,c,d}; do dd if=/dev/zero of=dev/sd$i bs=512 count=40 oflag=direct; done Install DeepSea admin:~ # zypper in -y deepsea Edit the /srv/pillar/ceph/deepsea_minions.sls file on the Salt master (admin node) and add or replace the following line: admin:~ # vi /srv/pillar/ceph/deepsea_minions.sls # Choose minions with a deepsea grain deepsea_minions: 'G@deepsea:*' #Match all Salt minions in the cluster # Choose all minions # deepsea_minions: '*' #Match all minions with the 'deepsea' grain # Choose custom Salt targeting # deepsea_minions: 'ses*' # deepsea_minions: 'ceph* or salt' Target the Minions Affirm salt-master (admin node) can communicate with the minions. And deploy the grains from admin node to all minions. admin:~ # salt '*' test.ping mon1.sha.me.corp: True data4.sha.me.corp: True data3.sha.me.corp: True data2.sha.me.corp: True data1.sha.me.corp: True mon3.sha.me.corp: True admin.sha.me.corp: True mon2.sha.me.corp: True Apply the 'deepsea' grain to a group of minions, and target with a DeepSea Grain admin:~ # salt '*' grains.append deepsea default data3.sha.me.corp: The val default was already in the list deepsea mon2.sha.me.corp: The val default was already in the list deepsea data1.sha.me.corp: The val default was already in the list deepsea data4.sha.me.corp: The val default was already in the list deepsea data2.sha.me.corp: The val default was already in the list deepsea mon3.sha.me.corp: The val default was already in the list deepsea admin.sha.me.corp: The val default was already in the list deepsea mon1.sha.me.corp: The val default was already in the list deepsea admin:~ # salt -G 'deepsea:*' test.ping (The following command is an equivalent) admin:~ # salt -C 'G@deepsea:*' test.ping admin.sha.me.corp: True data3.sha.me.corp: True mon1.sha.me.corp: True mon2.sha.me.corp: True data2.sha.me.corp: True data4.sha.me.corp: True mon3.sha.me.corp: True data1.sha.me.corp: True","title":"1.2. Install Packages"},{"location":"linux/SES/linux_ses_demo/#13-stage-0-the-preparation","text":"Run Stage 0\u2014the preparation During this stage, all required updates are applied and your system may be rebooted. If there are errors, re-run the stage. admin:~ # deepsea stage run ceph.stage.0 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.0 admin:~ # salt-run state.orch ceph.stage.prep Run Stage 1\u2014the discovery Here all hardware in your cluster is being detected and necessary information for the Ceph configuration is being collected. The discovery stage collects data from all minions and creates configuration fragments that are stored in the directory /srv/pillar/ceph/proposals . The data are stored in the YAML format in *.sls or *.yml files admin:~ # deepsea stage run ceph.stage.1 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.1 admin:~ # salt-run state.orch ceph.stage.discovery","title":"1.3. Stage 0 \u2014 the preparation"},{"location":"linux/SES/linux_ses_demo/#14-stage-2-the-configuration","text":"Run Stage 2 \u2014 the configuration \u2014 you need to prepare configuration data in a particular format. The assignment follows this pattern: role-ROLE_NAME/PATH/FILES_TO_INCLUDE (NOTE, the parent directory of PATH is /srv/pillar/ceph/ ) To avoid trouble with performance and the upgrade procedure, do not deploy the Ceph OSD, Metadata Server, or Ceph Monitor role to the Admin Node. Monitors, Metadata Server, and gateways can be co-located on the OSD nodes. If you are using CephFS, S3/Swift, iSCSI, at least two instances of the respective roles (Metadata Server, Object Gateway, iSCSI) are required for redundancy and availability. admin:~ # cp /usr/share/doc/packages/deepsea/examples/policy.cfg-rolebased /srv/pillar/ceph/proposals/policy.cfg admin:~ # vi /srv/pillar/ceph/proposals/policy.cfg ## Cluster Assignment # Add all nodes into Ceph cluster cluster-ceph/cluster/*.sls ## Roles # The Admin node fills the \u201cmaster\u201d and \u201cadmin\u201d roles for DeepSea # The master role is mandatory, always add a similar line to the following role-master/cluster/admin*.sls role-admin/cluster/admin*.sls # Monitoring # Cluster monitoring and data graphs, most commonly they run on Admin node # NFS Ganesha is configured via the file /etc/ganesha/ganesha.conf # As additional configuration is required to install NFS Ganesha, you can install NFS Ganesha later. # The following requirements need to be met before DeepSea stages 2 and 4 can be executed to install NFS Ganesha: # a)At least one node needs to be assigned the role-ganesha. # b)You can define only one role-ganesha per minion. # c)NFS Ganesha needs either an Object Gateway or CephFS to work, otherwise the validation will fail in Stage 3. # d)The kernel based NFS needs to be disabled on minions with the role-ganesha role. role-prometheus/cluster/admin*.sls role-grafana/cluster/mon1*.sls # MON # The minion will provide the monitor service to the Ceph cluster role-mon/cluster/mon*.sls # MGR # The Ceph manager daemon which collects all the state information from the whole cluster # Deploy it on all minions where you plan to deploy the Ceph monitor role role-mgr/cluster/mon1*.sls # MDS # The minion will provide the metadata service to support CephFS role-mds/cluster/mon*.sls # IGW # The minion will act as an iSCSI Gateway role-igw/cluster/mon2*.sls # RGW # The minion will act as an Object Gateway role-rgw/cluster/mon3*.sls # Storage # Use this role to specify storage nodes # It points to data1~4 nodes with a wildcard. role-storage/cluster/data*.sls # COMMON # It includes configuration files generated during the discovery (Stage 1) # Accept the default values for common configuration parameters such as fsid and public_network config/stack/default/global.yml config/stack/default/ceph/cluster.yml admin:~ # deepsea stage run ceph.stage.2 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.2 admin:~ # salt-run state.orch ceph.stage.configure After the command succeeds, run below command to view the pillar data for the specified minions admin:~ # salt 'mon*' pillar.items admin:~ # salt '*' saltutil.pillar_refresh Check time server (admin node) (the directory /srv/pillar/ceph/stack was initialized after deepsea installed, but global.yml file was not created yet until stage 2) By default, DeepSea uses the Admin Node as the time server for other cluster nodes. admin:~ # cat /srv/pillar/ceph/stack/default/global.yml (this file will be generated after stage 2) monitoring: prometheus: metric_relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] rule_files: [] scrape_interval: ceph: 10s grafana: 10s node_exporter: 10s prometheus: 10s target_partition: ceph: 1/1 grafana: 1/1 node_exporter: 1/1 prometheus: 1/1 time_server: admin.sha.me.corp Verify network (the directory /srv/pillar/ceph/stack was initialized after deepsea installed, but cluster.yml file was not created until stage 2 ) admin:~ # cat /srv/pillar/ceph/stack/ceph/cluster.yml --nothing admin:~ # cat /srv/pillar/ceph/stack/default/ceph/cluster.yml available_roles: - storage - admin - mon - mds - mgr - igw - grafana - prometheus - storage - rgw - ganesha - client-cephfs - client-radosgw - client-iscsi - client-nfs - benchmark-rbd - benchmark-blockdev - benchmark-fs - master cluster_network: 10.58.120.0/23 fsid: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 public_network: 10.58.120.0/23 Note: customized file will overwrite default one. Default file: /srv/pillar/ceph/stack/default/ceph/cluster.yml Customized file: /srv/pillar/ceph/stack/ceph/cluster.yml Check DriveGroup DriveGroups specify the layouts of OSDs in the Ceph cluster. They are defined in a single file /srv/salt/ceph/configuration/files/drive_groups.yml admin:~ # cat /srv/salt/ceph/configuration/files/drive_groups.yml default_drive_group_name: target: 'data*' <--original: 'I@role:storage' data_devices: all: true admin:~ # salt 'data*' pillar.items | grep -B5 stroage","title":"1.4. Stage 2 \u2014 the configuration"},{"location":"linux/SES/linux_ses_demo/#15-stage-3-the-deployment","text":"Run Stage 3 \u2014 the deployment \u2014 creates a basic Ceph cluster with mandatory Ceph services. This Deployment stage has more than 60 automated steps. Be patient and make sure the stage completes successfully before proceeding. Set dev environment and disable subvolume: admin:~ # vi /srv/pillar/ceph/stack/global.yml admin:~ # vi /srv/pillar/ceph/stack/default/global.yml monitoring: prometheus: metric_relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] rule_files: [] scrape_interval: ceph: 10s grafana: 10s node_exporter: 10s prometheus: 10s target_partition: ceph: 1/1 grafana: 1/1 node_exporter: 1/1 prometheus: 1/1 time_server: admin.sha.me.corp DEV_ENV: True subvolume_init: disabled admin:~ # salt '*' saltutil.pillar_refresh Note: customized file will overwrite default one. Default file: /srv/pillar/ceph/stack/default/global.yml Customized file: /srv/pillar/ceph/stack/global.yml admin:~ # deepsea stage run ceph.stage.3 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.3 admin:~ # salt-run state.orch ceph.stage.deploy After the command succeeds, run the following to check the status: admin:~ # ceph -s Below comands return you a structure of matching disks based on your DriveGroups. (will show available information after stage 3) admin:~ # salt-run disks.Report admin:~ # salt-run disks.list admin:~ # salt-run disks.details","title":"1.5. Stage 3 \u2014 the deployment"},{"location":"linux/SES/linux_ses_demo/#16-stage-4-the-services","text":"Run Stage 4 \u2014 the services \u2014 additional features of Ceph like iSCSI, Object Gateway and CephFS can be installed in this stage. Each is optional. admin:~ # deepsea stage run ceph.stage.4 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.4 admin:~ # salt-run state.orch ceph.stage.services admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log Before logon to dashboard via url, need get credentials first admin:~ # salt-call grains.get dashboard_creds local: ---------- admin: --> the password was changed to mypassword to log on to dashboard admin:~ # ceph mgr services { \"dashboard\": \"https://mon1.sha.me.corp:8443/\", \"prometheus\": \"http://mon1.sha.me.corp:9283/\" } https://10.58.121.186:8443 http://10.58.121.186:9283 admin:~ # watch ceph -s Every 2.0s: ceph -s admin: Mon Oct 5 14:41:51 2020 cluster: id: health: HEALTH_OK services:s: ceph -s mon: 3 daemons, quorum mon1,mon2,mon3 (age 87m) mgr: mon1(active, since 82m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 85m), 12 in (since 85m) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 576 pgs objects: 213 objects, 4.2 KiB usage: 12 GiB used, 84 GiB / 96 GiB avail pgs: 576 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr","title":"1.6. Stage 4 \u2014 the services"},{"location":"linux/SES/linux_ses_demo/#17-stage-5-the-removal-stage","text":"Run Stage 5 \u2014 the removal stage. This stage is not mandatory and during the initial setup it is usually not needed. In this stage the roles of minions and also the cluster configuration are removed. You need to run this stage when you need to remove a storage node from your cluster. admin:~ # deepsea stage run ceph.stage.","title":"1.7. Stage 5 \u2014 the removal stage"},{"location":"linux/SES/linux_ses_demo/#18-installation-guide","text":"Deployment Guide (EN) Deployment Guide (ZH)","title":"1.8. Installation Guide"},{"location":"linux/SES/linux_ses_demo/#19-issues-during-installation","text":"[ERROR]: The Salt Master has cached the public key for this node SOLUTION : Restart minions service [ERROR]: This server_id is computed nor by Adler32 neither by CRC32 [QUESTION]: How to change new salt key Stop salt-minion service # systemctl stop salt-minion Delete salt-minion pulic key # rm /etc/salt/pki/minion/minion.pub # rm /etc/salt/pki/minion/minion.pem Change new minion_id admin:~ # echo admin.sha.me.corp > /etc/salt/minion_id data1:~ # echo data1.sha.me.corp > /etc/salt/minion_id data2:~ # echo data2.sha.me.corp > /etc/salt/minion_id data3:~ # echo data3.sha.me.corp > /etc/salt/minion_id data4:~ # echo data4.sha.me.corp > /etc/salt/minion_id mon1:~ # echo mon1.sha.me.corp > /etc/salt/minion_id mon2:~ # echo mon2.sha.me.corp > /etc/salt/minion_id mon3:~ # echo mon3.sha.me.corp > /etc/salt/minion_id Delete old ID on admin node # salt-key -D Restart salt-minion service # systemctl restart salt-minion Accept all new key on admin node admin:~ # salt-key -L admin:~ # salt-key -A or admin:~ # salt-key -a admin.sha.me.corp data1:~ # salt-key -a data1.sha.me.corp data2:~ # salt-key -a data2.sha.me.corp data3:~ # salt-key -a data3.sha.me.corp data4:~ # salt-key -a data4.sha.me.corp mon1:~ # salt-key -a mon1.sha.me.corp mon2:~ # salt-key -a mon2.sha.me.corp mon3:~ # salt-key -a mon3.sha.me.corp [ERROR] ['/var/lib/ceph subvolume missing on mon3.sha.me.corp', '/var/lib/ceph subvolume missing on mon1.sha.me.corp', '/var/lib/ceph subvolume missing on mon2.sha.me.corp', 'See /srv/salt/ceph/subvolume/README.md'] SOLUTION Edit /srv/pillar/ceph/stack/global.yml and add the following line: subvolume_init: disabled Then refresh the Salt pillar and re-run DeepSea stage.3: admin:~ # salt '*' saltutil.refresh_pillar admin:~ # salt-run state.orch ceph.stage.3 After DeepSea successfully finished stage.3, the Ceph Dashboard will be running. Refer to Book \u201cAdministration Guide\u201d, Chapter 20 \u201cCeph Dashboard\u201d for a detailed overview of Ceph Dashboard features. To list nodes running dashboard, run: admin:~ # ceph mgr services | grep dashboard To list admin credentials, run: admin:~ # salt-call grains.get dashboard_creds [ERROR] module function cephprocesses.wait executed on nodes mon1~3 and data1~4 in Stage 0 SOLUTION Check below on all nodes # salt-call cephprocesses.check ERROR: process ceph-mds for role mds is not running ERROR: process radosgw for role rgw is not running admin:~ # ceph -s Clock skew detected on mon ceph (mon.mon2, mon.mon3) Set time server to public server (China) # chronyc sources","title":"1.9. Issues during installation"},{"location":"linux/SES/linux_ses_demo/#110-shutting-down-the-whole-ceph-cluster","text":"Shut down or disconnect any clients accessing the cluster. To prevent CRUSH from automatically rebalancing the cluster, set the cluster to noout: # ceph osd set noout Other flags you can set per osd: nodown noup noin noout Disable safety measures and run the ceph.shutdown runner: admin:~ # salt-run disengage.safety safety is now disabled for cluster ceph admin:~ # salt-run state.orch ceph.shutdown admin.sha.me.corp_master: Name: set noout - Function: salt.state - Result: Changed Started: - 14:32:14.398022 Duration: 2266.75 ms Name: Shutting down radosgw for rgw - Function: salt.state - Result: Changed Started: - 14:32:16.665452 Duration: 1461.23 ms Name: Shutting down cephfs - Function: salt.state - Result: Changed Started: - 14:32:18.127353 Duration: 30326.193 ms Name: Shutting down iscsi - Function: salt.state - Result: Clean Started: - 14:32:48.454187 Duration: 30142.468 ms Name: Shutting down storage - Function: salt.state - Result: Changed Started: - 14:33:18.597321 Duration: 10841.45 ms Name: Shutting down mgr - Function: salt.state - Result: Changed Started: - 14:33:29.439442 Duration: 29209.141 ms Name: Shutting down mon - Function: salt.state - Result: Changed Started: - 14:33:58.649221 Duration: 30519.97 ms Summary for admin.sha.me.corp_master ------------ Succeeded: 7 (changed=6) Failed: 0 ------------ Total states run: 7 Total run time: 134.767 s Power off all cluster nodes: admin:~ # salt -C 'G@deepsea:*' cmd.run \"shutdown -h\" Broadcast message from root@admin (Sat 2021-03-06 14:40:37 CST): The system is going down for poweroff at Sat 2021-03-06 14:41:37 CST! admin.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. mon2.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data2.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. mon3.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data3.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data4.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. mon1.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data1.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel.","title":"1.10. Shutting Down the Whole Ceph Cluster"},{"location":"linux/SES/linux_ses_demo/#111-starting-stopping-and-restarting-services-using-targets","text":"# ls /usr/lib/systemd/system/ceph*.target ceph.target ceph-osd.target ceph-mon.target ceph-mgr.target ceph-mds.target ceph-radosgw.target ceph-rbd-mirror.target To start/stop/restart all Ceph services on the node, run: # systemctl start ceph.target # systemctl stop ceph.target # systemctl restart ceph.target To start/stop/restart all OSDs on the node, run: # systemctl start ceph-osd.target # systemctl stop ceph-osd.target # systemctl restart ceph-osd.target Starting, Stopping, and Restarting Individual Services # systemctl list-unit-files --all --type=service ceph* ceph-osd@.service ceph-mon@.service ceph-mds@.service ceph-mgr@.service ceph-radosgw@.service ceph-rbd-mirror@.service Example : # systemctl status ceph-mon@HOSTNAME.service (e.g., ceph-mon@mon1.service) # systemctl start ceph-osd@1.service # systemctl stop ceph-osd@1.service # systemctl restart ceph-osd@1.service # systemctl status ceph-osd@1.service","title":"1.11. Starting, Stopping, and Restarting Services Using Targets"},{"location":"linux/SES/linux_ses_demo/#112-restarting-all-services","text":"# salt-run state.orch ceph.restart","title":"1.12. Restarting All Services"},{"location":"linux/SES/linux_ses_demo/#113-restarting-specific-services","text":"Example: salt-run state.orch ceph.restart.service_name # salt-run state.orch ceph.restart.mon # salt-run state.orch ceph.restart.mgr # salt-run state.orch ceph.restart.osd # salt-run state.orch ceph.restart.mds # salt-run state.orch ceph.restart.rgw # salt-run state.orch ceph.restart.igw # salt-run state.orch ceph.restart.ganesha Default log file path of salt-run: /var/log/salt/master","title":"1.13. Restarting Specific Services"},{"location":"linux/SES/linux_ses_demo/#2-basic-operation","text":"","title":"2. Basic Operation"},{"location":"linux/SES/linux_ses_demo/#21-pools-and-data-placement","text":"","title":"2.1. Pools and Data Placement"},{"location":"linux/SES/linux_ses_demo/#211-enable-the-pg-autoscaler-and-balancer-modules","text":"","title":"2.1.1. Enable the PG Autoscaler and Balancer Modules"},{"location":"linux/SES/linux_ses_demo/#task-1-view-the-state-of-all-the-manager-modules","text":"List all the existing Manager Modules admin:~ # ceph mgr module ls | less","title":"Task 1: View the state of all the Manager Modules"},{"location":"linux/SES/linux_ses_demo/#task-2-list-the-existing-pools","text":"List the pools that already exist in the cluster admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log List the pools again, but this time using the rados command: admin:~ # rados lspools iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log View the output of placement group autoscale-status command for the pools admin:~ # ceph osd pool autoscale-status Error ENOTSUP: Module 'pg_autoscaler' is not enabled (required by command 'osd pool autoscale-status'): use `ceph mgr module enable pg_autoscaler` to enable it","title":"Task 2: List the Existing Pools"},{"location":"linux/SES/linux_ses_demo/#task-3-enable-the-pg_autoscaler-module","text":"Enable the pg_autoscaler module admin:~ # ceph mgr module enable pg_autoscaler admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 128 32 warn cephfs_data 0 3.0 98256M 0.0000 1.0 256 32 warn cephfs_metadata 7285 3.0 98256M 0.0000 4.0 64 16 warn .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 18078 3.0 98256M 0.0000 1.0 32 warn Note that for the iscsi-images pool the PG_NUM value is 128. And note that the NEW PG_NUM value is 32. The PGs won\u2019t be adjusted automatically because the default setting for the autoscaler is \u201cwarn\u201d. Note the last column (mode) that shows status \u201cwarn\u201d for all the pools. Check current status. \u201chave too many placement groups\u201d. That\u2019s exactly what we want the pg_autoscaler to tell us. admin:~ # ceph health HEALTH_WARN 3 pools have too many placement groups Turn off the pg_autoscaler feature for CephFS pools admin:~ # ceph osd pool set cephfs_data pg_autoscale_mode off set pool 2 pg_autoscale_mode to off admin:~ # ceph osd pool set cephfs_metadata pg_autoscale_mode off set pool 3 pg_autoscale_mode to off admin:~ # ceph health HEALTH_WARN 1 pools have too many placement groups Set the pg_autoscaler mode to \u201con\u201d for the iscs-images pool: admin:~ # ceph osd pool set iscsi-images pg_autoscale_mode on set pool 1 pg_autoscale_mode to on admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 128 32 on cephfs_data 0 3.0 98256M 0.0000 1.0 256 32 off cephfs_metadata 7412 3.0 98256M 0.0000 4.0 64 16 off .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 18078 3.0 98256M 0.0000 1.0 32 warn Turn on the pg_autoscaler feature for CephFS pools admin:~ # ceph osd pool set cephfs_data pg_autoscale_mode on set pool 2 pg_autoscale_mode to on admin:~ # ceph osd pool set cephfs_metadata pg_autoscale_mode on set pool 3 pg_autoscale_mode to on PG numbgrs must always be a power of 2 admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 32 on cephfs_data 0 3.0 98256M 0.0000 1.0 32 off cephfs_metadata 7412 3.0 98256M 0.0000 4.0 16 off .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 35900 3.0 98256M 0.0000 1.0 32 warn Show the cluster health admin:~ # ceph -s cluster: id: health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 4w) mgr: mon1(active, since 46h) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 8w), 12 in (since 8w) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 433 pgs objects: 246 objects, 4.7 KiB usage: 13 GiB used, 83 GiB / 96 GiB avail pgs: 0.462% pgs not active 431 active+clean 2 peering io: client: 45 KiB/s rd, 0 B/s wr, 44 op/s rd, 28 op/s wr","title":"Task 3: Enable the pg_autoscaler module"},{"location":"linux/SES/linux_ses_demo/#task-4-turn-on-the-placement-group-balancer-feature","text":"1). Show the \u201cstatus\u201d of the balancer: admin:~ # ceph balancer status { \"plans\": [], \"active\": false, \"last_optimize_started\": \"\", \"last_optimize_duration\": \"\", \"optimize_result\": \"\", \"mode\": \"none\" } admin:~ # ceph balancer on admin:~ # ceph balancer status { \"plans\": [], \"active\": true, \"last_optimize_started\": \"Mon Jan 4 20:22:57 2021\", \"last_optimize_duration\": \"0:00:00.001379\", \"optimize_result\": \"Please do \\\"ceph balancer mode\\\" to choose a valid mode first\", \"mode\": \"none\" } 2). Set the mode for the balancer to \u201cupmap\u201d: admin:~ # ceph balancer mode upmap Error EPERM: min_compat_client \"jewel\" < \"luminous\", which is required for pg-upmap. Try \"ceph osd set-require-min-compat-client luminous\" before enabling this mode admin:~ # ceph osd set-require-min-compat-client luminous --yes-i-really-mean-it set require_min_compat_client to luminous admin:~ # ceph balancer mode upmap admin:~ # ceph balancer status { \"plans\": [], \"active\": true, \"last_optimize_started\": \"Mon Jan 4 20:23:57 2021\", \"last_optimize_duration\": \"0:00:00.001807\", \"optimize_result\": \"Please do \\\"ceph balancer mode\\\" to choose a valid mode first\", \"mode\": \"upmap\" } 3). Create a balancer optimization plan called basic-plan. Ceph won\u2019t let you do this yet. Because you just recently enabled the pg_autoscaler, Ceph is moving objects around, and the PGs are quite busy with re-peering. admin:~ # ceph balancer optimize basic-plan Error EINVAL: Balancer enabled, disable to optimize manually 4). Show the details of the plan: This shows what \u201cexecute\u201d-ing the plan will do, itemizing which PGs will be affected. admin:~ # ceph balancer show basic-plan Error ENOENT: plan basic-plan not found <--- failed here 5). Show the effectiveness of the plan by comparing the current score for the pre-planned balancing and the score for the planned balancing: admin:~ # ceph balancer eval current cluster score 0.118731 (lower is better) admin:~ # ceph balancer eval basic-plan Error EINVAL: option \"basic-plan\" not a plan or a pool 6). Show the status of the balancer, now with all of these settings having been set, but before putting them into effect: The pg_autoscaler has already optimized the balance of PGs sufficiently. That\u2019s because this cluster is very small and has no significant content stored in it yet. If that\u2019s the case, you would see a message like \u201cError EALREADY: Unable to find further optimization, or pool(s)' pg_num is decreasing, or distribution is already perfect.\u201d If you receive this message, then you will not be able to complete this task. At some later time in the course you may choose to revisit this task to complete it. admin:~ # ceph balancer status { \"plans\": [], \"active\": true, \"last_optimize_started\": \"Mon Jan 4 20:32:59 2021\", \"last_optimize_duration\": \"0:00:00.004170\", \"optimize_result\": \"Unable to find further optimization, or pool(s) pg_num is decreasing, or distribution is already perfect\", \"mode\": \"upmap\" } 7). Set the basic-plan into effect: admin:~ # ceph balancer execute basic-plan Error EINVAL: Balancer enabled, disable to execute a plan 8). Now re-show the current score for the balanced cluster: admin:~ # ceph balancer eval current cluster score 0.118731 (lower is better)","title":"Task 4: Turn on the Placement Group balancer feature"},{"location":"linux/SES/linux_ses_demo/#212-manipulate-erasure-code-profiles","text":"","title":"2.1.2. Manipulate Erasure Code Profiles"},{"location":"linux/SES/linux_ses_demo/#task-1-display-a-list-of-the-current-erasure-code-profiles","text":"admin:~ # ceph osd erasure-code-profile no valid command found; 4 closest matches: osd erasure-code-profile set { [...]} {--force} osd erasure-code-profile get osd erasure-code-profile rm osd erasure-code-profile ls Error EINVAL: invalid command admin:~ # ceph osd erasure-code-profile ls default","title":"Task 1: Display a list of the current Erasure Code profiles"},{"location":"linux/SES/linux_ses_demo/#task-2-examine-the-details-of-the-default-ec-profile","text":"admin:~ # ceph osd erasure-code-profile get default k=2 m=1 plugin=jerasure technique=reed_sol_van","title":"Task 2: Examine the details of the default EC profile"},{"location":"linux/SES/linux_ses_demo/#task-3-create-and-remove-a-new-ec-profile","text":"1. Create a new EC profile from the command line. This is going to be a \u201cbad\u201d profile that will be removed in a moment: admin:~ # ceph osd erasure-code-profile set bad_profile k=2 m=4 plugin=jerasure admin:~ # ceph osd erasure-code-profile ls bad_profile default admin:~ # ceph osd erasure-code-profile get bad_profile crush-device-class= crush-failure-domain=host crush-root=default jerasure-per-chunk-alignment=false k=2 m=4 plugin=jerasure technique=reed_sol_van w=8 admin:~ # ceph osd erasure-code-profile rm bad_profile admin:~ # ceph osd erasure-code-profile ls default","title":"Task 3: Create and remove a new EC profile"},{"location":"linux/SES/linux_ses_demo/#task-4-create-a-better-ec-profile","text":"admin:~ # ceph osd erasure-code-profile set usable_profile k=2 m=1 plugin=jerasure technique=reed_sol_van stripe_unit=4K crush-failure-domain=host admin:~ # ceph osd erasure-code-profile get usable_profile crush-device-class= crush-failure-domain=host crush-root=default jerasure-per-chunk-alignment=false k=2 m=1 plugin=jerasure stripe_unit=4K technique=reed_sol_van w=8","title":"Task 4: Create a better EC profile"},{"location":"linux/SES/linux_ses_demo/#213-manipulate-crush-map-rulesets","text":"","title":"2.1.3. Manipulate CRUSH Map Rulesets"},{"location":"linux/SES/linux_ses_demo/#task-1-display-a-list-of-the-current-crush-map-rules","text":"admin:~ # ceph osd crush rule ls replicated_rule admin:~ # ceph osd crush osd crush rule ls osd crush rule ls-by-class osd crush rule dump {} osd crush dump osd crush set {} osd crush add-bucket { [...]} osd crush rename-bucket osd crush set [...] osd crush add [...] osd crush set-all-straw-buckets-to-straw2 admin:~ # ceph osd crush rule osd crush rule ls osd crush rule ls-by-class osd crush rule dump {} osd crush rule create-simple {firstn|indep} osd crush rule create-replicated {} osd crush rule create-erasure {} osd crush rule rm osd crush rule rename List the existing CRUSH Map rulesets that have been defined according to a particular device class: admin:~ # ceph osd crush rule ls-by-class hdd admin:~ # ceph osd crush rule ls-by-class ssd Error ENOENT: failed to get rules by class 'ssd' admin:~ # ceph osd crush rule ls-by-class nvme Error ENOENT: failed to get rules by class 'nvme'","title":"Task 1: Display a list of the current CRUSH Map rules"},{"location":"linux/SES/linux_ses_demo/#task-2-examine-the-details-of-the-default-crush-map-rule","text":"Show the details of the default CRUSH Map rule with the dump sub-command: The \u201crule_id\u201d and \u201cruleset\u201d values just numbgrs to keep track of rules similar to a DB key id. \u201cmin_size\u201d and \u201cmax_size\u201d are related to how CRUSH behaves when a certain numbgr of replicas are created. The \u201csteps\u201d section is the most functional portion of the rule, providing an ordered set of rules for how CRUSH should behave. Note that there are three \u201cop\u201d parts, one each for \u201ctake\u201d, \u201cchooseleaf_firstn\u201d, and \u201cemit\u201d. \u201ctake\u201d in a replicated rule is always the first step, and \u201cemit\u201d is always the last step. The \u201citem_type\u201d in the \u201ctake\u201d step is the crush_root value, and the \u201chost\u201d in the \u201cchooseleaf_firstn\u201d step is the failure_domain. admin:~ # ceph osd crush rule dump replicated_rule { \"rule_id\": 0, \"rule_name\": \"replicated_rule\", \"ruleset\": 0, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] }","title":"Task 2: Examine the details of the default CRUSH Map rule"},{"location":"linux/SES/linux_ses_demo/#task-3-create-and-remove-a-new-crush-map-rule","text":"1). Create a new CRUSH ruleset from the command line.We made two mistakes here: First, we named it \u201cbud\u201d instead of \u201cbad\u201d. admin:~ # ceph osd crush rule create-replicated bud_ruleset default host admin:~ # ceph osd crush rule ls replicated_rule bud_ruleset 2). Rename the ruleset: admin:~ # ceph osd crush rule rename bud_ruleset bad_ruleset admin:~ # ceph osd crush rule ls replicated_rule bad_ruleset 3). The second mistake was that we specified the failure-domain at the host-bucket level. This is technically not a bad thing to do, in fact it would be a common use case. But for this demo we want to set the failure domain at the rack-bucket level. We can\u2019t change a defined CRUSH Map ruleset, so delete the bad one: admin:~ # ceph osd crush rule rm bad_ruleset admin:~ # ceph osd crush rule ls replicated_rule","title":"Task 3: Create and remove a new CRUSH Map rule"},{"location":"linux/SES/linux_ses_demo/#task-4-create-a-better-crush-map-rule","text":"Create a more appropriate CRUSH Map rule from the CLI, that will survive the failure of a rack: admin:~ # ceph osd crush rule create-replicated better_ruleset default rack admin:~ # ceph osd crush rule dump better_ruleset { \"rule_id\": 1, \"rule_name\": \"better_ruleset\", \"ruleset\": 1, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"rack\" }, { \"op\": \"emit\" } ] }","title":"Task 4: Create a better CRUSH Map rule"},{"location":"linux/SES/linux_ses_demo/#task-5-create-crush-map-rules-for-different-classes-of-devices","text":"1). Create two different CRUSH Map rules from the CLI, that will accommodate a slow set of devices (HDDs) and a fast set of devices (SDDs): The error of 2 nd is because the cluster does not have any SSD devices. admin:~ # ceph osd crush rule create-replicated slow_devices default host hdd admin:~ # ceph osd crush rule create-replicated fast_devices default host sdd Error EINVAL: device class sdd does not exist 2). Display the details of the new \u201cslow\u201d rule: admin:~ # ceph osd crush rule dump slow_devices { \"rule_id\": 2, \"rule_name\": \"slow_devices\", \"ruleset\": 2, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -2, \"item_name\": \"default~hdd\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] }","title":"Task 5: Create CRUSH Map rules for different classes of devices"},{"location":"linux/SES/linux_ses_demo/#task-6-change-the-ruleset-used-by-a-pool","text":"1). Show which CRUSH Map Ruleset is being used by the cephfs_data pool: The rule should be listed as replicated_rule. admin:~ # ceph osd pool get cephfs_data crush_rule crush_rule: replicated_rule 2). Change the cephfs_data pool to use the new CRUSH Map ruleset that you created in the previous task. admin:~ # ceph osd pool set cephfs_data crush_rule better_ruleset set pool 2 crush_rule to better_ruleset 3). Verify that the rule has been changed by re-running the earlier command: admin:~ # ceph osd pool get cephfs_data crush_rule crush_rule: better_ruleset 4). In this demo cluster, making the cephfs_data pool use the \u201cbetter_ruleset\u201d will result in problems. (There\u2019s no rack for the CRUSH Map, and not enough nodes to accommodate the requirement for a large numbgr of PGs.) So change the setting back to the replicated_rule. admin:~ # ceph osd pool set cephfs_data crush_rule replicated_rule set pool 2 crush_rule to replicated_rule admin:~ # ceph osd pool get cephfs_data crush_rule crush_rule: replicated_rule Task 7: Create a CRUSH Map rule enhanced with an EC profile 1). Combine the benefits of Erasure Coding with a CRUSH Map rule: This will only work if you have already created an appropriate EC profile called usable_profile. In this demo you would have done in an earlier exercise. And in this demo you need to tie this ec_rule to the usable_profile, not the better_profile.Or else any pool that you create using the ec_rule will fail due to insufficient resources. admin:~ # ceph osd crush rule create-erasure ec_rule usable_profile Link the CRUSH map rule (ec_rule) to EC profile (usable_profile) created rule ec_rule at 3 P.S., The useable_profile was created by : admin:~ # ceph osd erasure-code-profile set usable_profile k=2 m=1 plugin=jerasure technique=reed_sol_van stripe_unit=4K crush-failure-domain=host 2). Display the details of the EC-enhanced CRUSH Map rule: See the added, extra \u201cop\u201d steps. You might also notice the different values for \u201ctype,\u201d \u201cmin_size,\u201d and \u201cmax_size\u201d than what you saw in the standard replicated rules. admin:~ # ceph osd crush rule dump ec_rule { \"rule_id\": 3, \"rule_name\": \"ec_rule\", \"ruleset\": 3, \"type\": 3, \"min_size\": 3, \"max_size\": 3, \"steps\": [ { \"op\": \"set_chooseleaf_tries\", \"num\": 5 }, { \"op\": \"set_choose_tries\", \"num\": 100 }, { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_indep\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd crush rule ls replicated_rule better_ruleset slow_devices ec_rule admin:~ # ceph osd crush rule create-replicated better_ruleset default rack admin:~ # ceph osd crush rule create-replicated slow_devices default host hdd admin:~ # ceph osd crush rule create-erasure ec_rule usable_profile admin:~ # ceph osd crush rule dump replicated_rule { \"rule_id\": 0, \"rule_name\": \"replicated_rule\", \"ruleset\": 0, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd crush rule dump better_ruleset { \"rule_id\": 1, \"rule_name\": \"better_ruleset\", \"ruleset\": 1, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"rack\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd crush rule dump slow_devices { \"rule_id\": 2, \"rule_name\": \"slow_devices\", \"ruleset\": 2, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -2, \"item_name\": \"default~hdd\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd pool osd pool stats {} osd pool scrub [...] osd pool deep-scrub [...] osd pool repair [...] osd pool force-recovery [...] osd pool force-backfill [...] osd pool cancel-force-recovery [...] osd pool cancel-force-backfill [...] osd pool autoscale-status osd pool mksnap admin:~ # ceph osd pool get size min_size pg_num pgp_num crush_rule Hashpspool Nodelete Nopgchange Nosizechange write_fadvise_dontneed Noscrub nodeep-scrub hit_set_type hit_set_period hit_set_count hit_set_fpp use_gmt_hitset target_max_objects target_max_bytes cache_target_dirty_ratio cache_target_dirty_high_ratio cache_target_full_ratio cache_min_flush_age cache_min_evict_age erasure_code_profile min_read_recency_for_promote All min_write_recency_for_promote fast_read hit_set_grade_decay_rate hit_set_search_last_n scrub_min_interval scrub_max_interval deep_scrub_interval recovery_priority recovery_op_priority scrub_priority compression_mode compression_algorithm compression_required_ratio compression_max_blob_size compression_min_blob_size csum_type csum_min_block csum_max_block allow_ec_overwrites fingerprint_algorithm pg_autoscale_mode pg_autoscale_bias pg_num_min target_size_bytes target_size_ratio","title":"Task 6: Change the ruleset used by a pool"},{"location":"linux/SES/linux_ses_demo/#214-investigate-bluestore","text":"","title":"2.1.4. Investigate BlueStore"},{"location":"linux/SES/linux_ses_demo/#task-1-explore-the-drive_groupsyml-configuration","text":"After deployment, the drive_groups.yml file is where the storage administrator defines the configuration of the cluster\u2019s storage devices. Note the \u201cdata_devices\u201d parameter. In this demo, \u201call\u201d storage devices are data devices for BlueStore. Note that there are no definitions for \u201cwal_devices\u201d or \u201cdb_devices.\u201d That\u2019s because in this demo environment we don\u2019t have any other \u201cfast\u201d devices that would be appropriate for these roles. Since BlueStore is the default, there is no definition of a \u201cformat\u201d for the devices. Otherwise, a \u201cFormat: bluestore\u201d key-value pair might exist to ensure that BlueStore is used. admin:~ # cd /srv/salt/ceph/configuration/files admin:/srv/salt/ceph/configuration/files # cat drive_groups.yml # default: <- just a name - can be anything # target: 'data*' <- must be resolvable by salt's targeting processor # data_devices: # size: 20G # db_devices: # size: 10G # rotational: 1 # allflash: # target: 'fast_nodes*' # data_devices: # size: 100G # db_devices: # size: 50G # rotational: 0 # This is the default configuration and # will create an OSD on all available drives default: target: 'data*' data_devices: all: true","title":"Task 1: Explore the drive_groups.yml configuration"},{"location":"linux/SES/linux_ses_demo/#task-2-examine-a-storage-hosts-storage-devices","text":"admin:~ # ssh data1 Last login: Tue Jan 5 18:06:40 2021 from 10.58.121.181 Should see 3 devices, which are named ceph LVM-type devices data1:~ # lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 8G 0 disk \u2514\u2500ceph--14c886af--269d--475f--8ee3--f5e4abbb222d-osd--data--38911b2d--f30a--4b09--9010--8dd6fad2fcc6 254:0 0 8G 0 lvm sdb 8:16 0 8G 0 disk \u2514\u2500ceph--9ec4a77a--5d67--4b21--be53--d7e9221082de-osd--data--00cb3dc6--c28b--41ae--95de--efb86da254da 254:1 0 8G 0 lvm sdc 8:32 0 8G 0 disk \u2514\u2500ceph--5eaea8a8--bb68--49dd--a1e3--b82c5464ab1f-osd--data--a4a05f70--53d9--41d4--a273--4f47a088968a 254:2 0 8G 0 lvm sr0 11:0 1 672M 0 rom vda 253:0 0 20G 0 disk \u251c\u2500vda1 253:1 0 8M 0 part \u251c\u2500vda2 253:2 0 18.4G 0 part / \u2514\u2500vda3 253:3 0 1.7G 0 part [SWAP] See the raw ceph devices data1:~ # ls -lad /dev/ceph* drwxr-xr-x 2 root root 60 Oct 5 13:15 /dev/ceph-14c886af-269d-475f-8ee3-f5e4abbb222d drwxr-xr-x 2 root root 60 Oct 5 13:16 /dev/ceph-5eaea8a8-bb68-49dd-a1e3-b82c5464ab1f drwxr-xr-x 2 root root 60 Oct 5 13:15 /dev/ceph-9ec4a77a-5d67-4b21-be53-d7e9221082de Dig down even farther by examining the content of one of the directories, see a symlink to an LVM device-mapper device. All the devices are tied together with LVM. Note that the name of the symlink is named osd-data- . data1:~ # ls -l /dev/ceph-14c886af-269d-475f-8ee3-f5e4abbb222d lrwxrwxrwx 1 ceph ceph 7 Oct 5 13:15 osd-data-38911b2d-f30a-4b09-9010-8dd6fad2fcc6 -> ../dm-0 data1:~ # l /dev/dm* brw-rw---- 1 ceph ceph 254, 0 Jan 5 18:10 /dev/dm-0 brw-rw---- 1 ceph ceph 254, 1 Jan 5 18:10 /dev/dm-1 brw-rw---- 1 ceph ceph 254, 2 Jan 5 18:10 /dev/dm-2","title":"Task 2: Examine a storage host\u2019s storage devices"},{"location":"linux/SES/linux_ses_demo/#task-3-examine-a-storage-hosts-osd-details","text":"data1:~ # cd /var/lib/ceph/ data1:/var/lib/ceph # ls -l drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-mds drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-mgr drwxr-x--- 1 ceph ceph 24 Oct 5 13:15 bootstrap-osd drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-rbd drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-rbd-mirror drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-rgw drwxr-x--- 1 ceph ceph 12 Oct 5 09:04 crash drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 mds drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 mgr drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 mon drwxr-x--- 1 ceph ceph 38 Oct 5 13:16 osd drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 tmp See 3 different sub-directories, each representing the 3 different OSDs (ceph-2, ceph-6, ceph-10) that are running on this storage server data1:/var/lib/ceph # cd osd/ data1:/var/lib/ceph/osd # ls -l drwxrwxrwt 2 ceph ceph 320 Oct 5 13:16 ceph-10 drwxrwxrwt 2 ceph ceph 320 Oct 5 13:15 ceph-2 drwxrwxrwt 2 ceph ceph 320 Oct 5 13:16 ceph-6 See some functional files associated with the OSD and BlueStore. See a block file, which is a symlink to one of the ceph devices, which stores the raw objects for the OSD. data1:/var/lib/ceph/osd # cd ceph-2 data1:/var/lib/ceph/osd/ceph-2 # ls -l -rw-r--r-- 1 ceph ceph 400 Oct 5 13:15 activate.monmap lrwxrwxrwx 1 ceph ceph 92 Oct 5 13:15 block -> /dev/ceph-14c886af-269d-475f-8ee3-f5e4abbb222d/osd-data-38911b2d-f30a-4b09-9010-8dd6fad2fcc6 -rw------- 1 ceph ceph 2 Oct 5 13:15 bluefs -rw------- 1 ceph ceph 37 Oct 5 13:15 ceph_fsid -rw-r--r-- 1 ceph ceph 37 Oct 5 13:15 fsid -rw------- 1 ceph ceph 55 Oct 5 13:15 keyring -rw------- 1 ceph ceph 8 Oct 5 13:15 kv_backend -rw------- 1 ceph ceph 21 Oct 5 13:15 magic -rw------- 1 ceph ceph 4 Oct 5 13:15 mkfs_done -rw------- 1 ceph ceph 41 Oct 5 13:15 osd_key -rw------- 1 ceph ceph 6 Oct 5 13:15 ready -rw------- 1 ceph ceph 3 Oct 5 13:15 require_osd_release -rw------- 1 ceph ceph 10 Oct 5 13:15 type -rw------- 1 ceph ceph 2 Oct 5 13:15 whoami data1:/var/lib/ceph/osd/ceph-2 # cat ceph_fsid # The unique ID of this Ceph cluster 343ee7d3-232f-4c71-8216-1edbc55ac6e0 data1:/var/lib/ceph/osd/ceph-2 # cat fsid # The unique ID of this OSD 6df58ebc-dbfe-4822-9714-90212c06ea05 data1:/var/lib/ceph/osd/ceph-2 # cat keyring # The Ceph key for this OSD [osd.2] key = data1:/var/lib/ceph/osd/ceph-2 # cat ready # Indication of the readiness of this OSD ready data1:/var/lib/ceph/osd/ceph-2 # cat type # filestore or bluestore (in this case: bluestore) bluestore data1:/var/lib/ceph/osd/ceph-2 # cat whoami # The integer id of this OSD (in this case: 2) 2","title":"Task 3: Examine a storage host\u2019s OSD details"},{"location":"linux/SES/linux_ses_demo/#task-4-display-bluestore-information-using-ceph-bluestore-tool","text":"Show BlueStore metadata for osd.2: data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool show-label --path /var/lib/ceph/osd/ceph-2 inferring bluefs devices from bluestore path { \"/var/lib/ceph/osd/ceph-2/block\": { \"osd_uuid\": \"6df58ebc-dbfe-4822-9714-90212c06ea05\", \"size\": 8585740288, \"btime\": \"2020-10-05 13:15:51.227799\", \"description\": \"main\", \"bluefs\": \"1\", \"ceph_fsid\": \"343ee7d3-232f-4c71-8216-1edbc55ac6e0\", \"kv_backend\": \"rocksdb\", \"magic\": \"ceph osd volume v026\", \"mkfs_done\": \"yes\", \"osd_key\": , \"ready\": \"ready\", \"require_osd_release\": \"14\", \"whoami\": \"2\" } Run a manual \u201cscrub\u201d on osd.7 using ceph-blestore-tool. (Received error, the tool won\u2019t allow you to do this while the OSD is running.) data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool fsck --path /var/lib/ceph/osd/ceph-2 error from fsck: (11) Resource temporarily unavailable 2021-01-05 18:32:25.528 7f4abad6e180 -1 bluestore(/var/lib/ceph/osd/ceph-2) _lock_fsid failed to lock /var/lib/ceph/osd/ceph-2/fsid (is another ceph-osd still running?)(11) Resource temporarily unavailable Simulate that the OSD is down, shutdown the OSD: data1:/var/lib/ceph/osd/ceph-2 # systemctl stop ceph-osd@2.service Now run the \u201cfsck\u201d command again. This time the \u201cfsck\u201d has worked, with the output showing: \u201cfsck success\u201d data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool fsck --path /var/lib/ceph/osd/ceph-2 fsck success Restart the OSD: data1:/var/lib/ceph/osd/ceph-2 # systemctl start ceph-osd@2.service data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool show-label --path /var/lib/ceph/osd/ceph-2 inferring bluefs devices from bluestore path { \"/var/lib/ceph/osd/ceph-2/block\": { \"osd_uuid\": \"6df58ebc-dbfe-4822-9714-90212c06ea05\", \"size\": 8585740288, \"btime\": \"2020-10-05 13:15:51.227799\", \"description\": \"main\", \"bluefs\": \"1\", \"ceph_fsid\": \"343ee7d3-232f-4c71-8216-1edbc55ac6e0\", \"kv_backend\": \"rocksdb\", \"magic\": \"ceph osd volume v026\", \"mkfs_done\": \"yes\", \"osd_key\": , \"ready\": \"ready\", \"require_osd_release\": \"14\", \"whoami\": \"2\" } }","title":"Task 4: Display BlueStore information using ceph-bluestore-tool"},{"location":"linux/SES/linux_ses_demo/#22-common-day-1-tasks-using-the-cli","text":"Including ollowing topics in relation to the commandline: Users and Ceph Configuration Health commands Erasure Code Profiles CRUSH Map rules Pools Scrubbing OSDs and Placement Groups Manager modules The tell commands","title":"2.2. Common Day 1 Tasks Using the CLI"},{"location":"linux/SES/linux_ses_demo/#221-ceph-users-and-configuration","text":"","title":"2.2.1. Ceph Users and Configuration"},{"location":"linux/SES/linux_ses_demo/#task-1-view-the-current-user-keyrings","text":"Ceph keyrings are stored in below directory admin:~ # cd /etc/ceph/ admin:/etc/ceph # ls -l -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap The value of 'key' is the key that\u2019s on the keyring. The admin keyring is \u201callow\u201ded all capabilities (permissions) to all services in the cluster, as expected. there are more than just client keys. admin:/etc/ceph # cat ceph.client.admin.keyring [client.admin] key = caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" Display the existing users with the \u201cauth\u201d command: Below two commands are equivalent admin:/etc/ceph # ceph -n client.admin -keyring=/etc/ceph/ceph.client.admin.keyring auth ls -- failed??? no valid command found admin:/etc/ceph # ceph auth ls installed auth entries: mds.mon1 key: caps: [mds] allow * caps: [mgr] allow profile mds caps: [mon] allow profile mds caps: [osd] allow rwx mds.mon2 key: caps: [mds] allow * caps: [mgr] allow profile mds caps: [mon] allow profile mds caps: [osd] allow rwx mds.mon3 key: caps: [mds] allow * caps: [mgr] allow profile mds caps: [mon] allow profile mds caps: [osd] allow rwx osd.0 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.1 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.10 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.11 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.2 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.3 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.4 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.5 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.6 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.7 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.8 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.9 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * client.admin key: caps: [mds] allow * caps: [mgr] allow * caps: [mon] allow * caps: [osd] allow * client.bootstrap-mds key: caps: [mon] allow profile bootstrap-mds client.bootstrap-mgr key: caps: [mon] allow profile bootstrap-mgr client.bootstrap-osd key: caps: [mgr] allow r caps: [mon] allow profile bootstrap-osd client.bootstrap-rbd key: caps: [mon] allow profile bootstrap-rbd client.bootstrap-rbd-mirror key: caps: [mon] allow profile bootstrap-rbd-mirror client.bootstrap-rgw key: caps: [mon] allow profile bootstrap-rgw client.igw.mon2 key: caps: [mgr] allow r caps: [mon] allow * caps: [osd] allow * client.rgw.mon3 key: caps: [mgr] allow r caps: [mon] allow rwx caps: [osd] allow rwx client.storage key: caps: [mon] allow rw mgr.mon1 key: caps: [mds] allow * caps: [mon] allow profile mgr caps: [osd] allow *","title":"Task 1: View the current user keyrings"},{"location":"linux/SES/linux_ses_demo/#task-2-create-a-new-keyring-and-associated-user","text":"1). There are several different ways to create a new keyring and user. This is just one way. Create a new keyring and associated user named James . Remembgr that typically all new users will need read rights for the mon capability, and will need read/write rights for the osd capability, including a specification of rights to a pool. admin:/etc/ceph # ceph-authtool -g -n client.james --cap mon 'allow r' --cap osd 'allow rw pool=iscsi-images' -C /etc/ceph/ceph.client.james.keyring creating /etc/ceph/ceph.client.james.keyring admin:/etc/ceph # l total 16 drwxr-xr-x 1 root root 130 Jan 5 19:31 ./ drwxr-xr-x 1 root root 4392 Oct 5 13:03 ../ -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw------- 1 root root 126 Jan 5 19:31 ceph.client.james.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap 2). Show the content of the newly created keyring: admin:/etc/ceph # cat ceph.client.james.keyring [client.james] key = caps mon = \"allow r\" caps osd = \"allow rw pool=iscsi-images\" 3). Officially add the new keyring to Ceph: admin:/etc/ceph # ceph auth add client.james -i /etc/ceph/ceph.client.james.keyring added key for client.james 4). Show the key information using the \u201cauth\u201d function: admin:/etc/ceph # ceph auth get client.james exported keyring for client.james [client.james] key = caps mon = \"allow r\" caps osd = \"allow rw pool=iscsi-images\"","title":"Task 2: Create a new keyring and associated user"},{"location":"linux/SES/linux_ses_demo/#task-3-create-a-client-key-for-rbd","text":"1). Change to the directory that contains the ceph keyrings. admin:~ # cd /etc/ceph/ 2). List the content of the directory: Although you see the admin users\u2019s keyring, ceph.client.admin.keyring, there is not yet a file that is appropriate for a specific application to use. Also note that the permissions on the keyring file are quite restrictive: 0600 admin:/etc/ceph # ls -l -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw------- 1 root root 126 Jan 5 19:31 ceph.client.james.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap 3). Show the content of the admin user\u2019s keyring: You will use the value associated with the \u201ckey\u201d key to create a new file. Copy the \u201ckey\u201d value using your favorite method. admin:/etc/ceph # cat ceph.client.admin.keyring [client.admin] key = caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" 4). Open a new file for editing called admin.secret using your favorite editor (such as vi): The name of the file isn\u2019t very important, but naming it this way will help to identify its purpose: it\u2019s a secret key for the admin user. Note that there are many ways to do this. An alternative way is mentioned in the tip below that will do this in one step using grep and awk. admin:/etc/ceph # vi admin.secret 5). Paste the \u201ckey\u201d value into the new file. It will be the only content of the file. It will look like this (in fact it\u2019s probably exactly the same as this, if you\u2019re using the demo environment provided to you): admin:/etc/ceph # cat admin.secret 6). Save the file and exist out of the editor. 7). Change the permissions of the file so that no other user on the host can see the content of the file: admin:/etc/ceph # chmod 0600 admin.secret admin:/etc/ceph # l drwxr-xr-x 1 root root 154 Jan 5 20:03 ./ drwxr-xr-x 1 root root 4392 Oct 5 13:03 ../ -rw------- 1 root root 41 Jan 5 20:03 admin.secret -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw------- 1 root root 126 Jan 5 19:31 ceph.client.james.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap Tip: An alternative way to create this key file is to simply use grep/awk together in one bash command, like this: admin:/etc/ceph # grep \"key =\" ceph.client.admin.keyring | awk -F\" = \" '{ print $2 }' admin:/etc/ceph # grep \"key =\" ceph.client.admin.keyring | awk -F\" = \" '{ print $2 }' > admin.secret admin:/etc/ceph # cat admin.secret ","title":"Task 3: Create a client key for RBD"},{"location":"linux/SES/linux_ses_demo/#task-4-view-the-ceph-master-configuration-file","text":"View the content of the file. The file is managed and controlled by DeepSea. The comment makes reference to the control files in the /srv/salt/ceph/configuration/ directory hierarchy. This is a very simple storage cluster. In a more diverse and sophisticated ceph cluster there may be more configuration settings defined. Although this exercise doesn\u2019t call out any more specific information about this configuration file, you may take a moment to consider the content of the file before finishing the task. admin:/etc/ceph # cat ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.186, 10.58.121.187, 10.58.121.188 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] admin:/etc/ceph # ls -l /srv/salt/ceph/configuration/ drwxr-xr-x 1 salt salt 18 Oct 5 13:13 cache drwxr-xr-x 1 root root 38 Oct 5 09:04 check drwxr-xr-x 1 root root 74 Oct 5 09:04 create -rw-r--r-- 1 root root 217 May 14 2020 default-import.sls -rw-r--r-- 1 root root 222 May 14 2020 default.sls drwxr-xr-x 1 root root 276 Oct 5 12:55 files -rw-r--r-- 1 root root 74 May 14 2020 init.sls","title":"Task 4: View the Ceph master configuration file"},{"location":"linux/SES/linux_ses_demo/#222-run-the-ceph-health-commands","text":"Get overall health status admin:~ # ceph health HEALTH_OK admin:~ # ceph -s admin:~ # ceph status cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 5w) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 98m), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 208 pgs objects: 246 objects, 4.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 208 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr Run the \u201cstatus\u201d command for the monitors: admin:~ # ceph mon stat e1: 3 mons at { mon1=[v2:10.58.121.186:3300/0,v1:10.58.121.186:6789/0], mon2=[v2:10.58.121.187:3300/0,v1:10.58.121.187:6789/0], mon3=[v2:10.58.121.188:3300/0,v1:10.58.121.188:6789/0] }, election epoch 22, leader 0 mon1, quorum 0,1,2 mon1,mon2,mon3 Run the \u201cstatus\u201d command for the placement groups: admin:~ # ceph pg stat 208 pgs: 208 active+clean; 4.7 KiB data, 2.1 GiB used, 82 GiB / 96 GiB avail; 852 B/s rd, 0 op/s Run the ceph \u201cstatus\u201d command while watching for changes to the status: admin:~ # ceph -s --watch-debug cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 5w) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 104m), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 208 pgs objects: 246 objects, 4.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 208 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr 2021-01-05 20:20:53.947298 mgr.mon1 [DBG] pgmap v1597415: 208 pgs: 208 active+clean; 4.7 KiB data, 2.1 GiB used, 82 GiB / 96 GiB avail; 852 B/s rd, 0 op/s 2021-01-05 20:20:55.949294 mgr.mon1 [DBG] pgmap v1597416: 208 pgs: 208 active+clean; 4.7 KiB data, 2.1 GiB used, 82 GiB / 96 GiB avail; 1.2 KiB/s rd, 1 op/s .......","title":"2.2.2. Run the Ceph Health Commands"},{"location":"linux/SES/linux_ses_demo/#223-manipulate-pools","text":"","title":"2.2.3. Manipulate Pools"},{"location":"linux/SES/linux_ses_demo/#task-1-display-a-list-of-the-current-pools","text":"admin:~ # ceph osd pool ls iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log admin:~ # ceph osd pool ls detail pool 1 'iscsi-images' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 448 lfor 0/448/446 flags hashpspool stripe_width 0 application rbd pool 2 'cephfs_data' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 1395 lfor 0/1374/1372 flags hashpspool stripe_width 0 application cephfs pool 3 'cephfs_metadata' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 1385 lfor 0/975/973 flags hashpspool stripe_width 0 pg_autoscale_bias 4 pg_num_min 16 recovery_priority 5 application cephfs pool 4 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 31 flags hashpspool stripe_width 0 application rgw pool 5 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 33 flags hashpspool stripe_width 0 application rgw pool 6 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 35 flags hashpspool stripe_width 0 application rgw pool 7 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 37 flags hashpspool stripe_width 0 application rgw List pools with their index numbgr. Note how the index numbgr matches the index numbgr of the detail listing above. admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log","title":"Task 1: Display a list of the current pools"},{"location":"linux/SES/linux_ses_demo/#task-2-display-the-usage-data-and-stats-of-the-current-pools","text":"Display pool usages. Note again index \u201cID\u201d for the pool. admin:~ # ceph df RAW STORAGE: CLASS SIZE AVAIL USED RAW USED %RAW USED hdd 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 TOTAL 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 POOLS: POOL ID STORED OBJECTS USED %USED MAX AVAIL iscsi-images 1 389 B 2 192 KiB 0 25 GiB cephfs_data 2 0 B 0 0 B 0 25 GiB cephfs_metadata 3 7.2 KiB 48 1.5 MiB 0 25 GiB .rgw.root 4 1.2 KiB 4 768 KiB 0 25 GiB default.rgw.control 5 0 B 8 0 B 0 25 GiB default.rgw.meta 6 381 B 3 576 KiB 0 25 GiB default.rgw.log 7 35 KiB 208 35 KiB 0 25 GiB admin:~ # ceph df detail RAW STORAGE: CLASS SIZE AVAIL USED RAW USED %RAW USED hdd 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 TOTAL 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 POOLS: POOL ID STORED OBJECTS USED %USED MAX AVAIL QUOTA OBJECTS QUOTA BYTES DIRTY USED COMPR UNDER COMPR iscsi-images 1 389 B 2 192 KiB 0 25 GiB N/A N/A 2 0 B 0 B cephfs_data 2 0 B 0 0 B 0 25 GiB N/A N/A 0 0 B 0 B cephfs_metadata 3 7.2 KiB 48 1.5 MiB 0 25 GiB N/A N/A 48 0 B 0 B .rgw.root 4 1.2 KiB 4 768 KiB 0 25 GiB N/A N/A 4 0 B 0 B default.rgw.control 5 0 B 8 0 B 0 25 GiB N/A N/A 8 0 B 0 B default.rgw.meta 6 381 B 3 576 KiB 0 25 GiB N/A N/A 3 0 B 0 B default.rgw.log 7 35 KiB 208 35 KiB 0 25 GiB N/A N/A 208 0 B 0 B Display pool usages using rados command admin:~ # rados df POOL_NAME USED OBJECTS CLONES COPIES MISSING_ON_PRIMARY UNFOUND DEGRADED RD_OPS RD WR_OPS WR USED COMPR UNDER COMPR .rgw.root 768 KiB 4 0 12 0 0 0 40 40 KiB 4 4 KiB 0 B 0 B cephfs_data 0 B 0 0 0 0 0 0 0 0 B 0 0 B 0 B 0 B cephfs_metadata 1.5 MiB 48 0 144 0 0 0 0 0 B 111 42 KiB 0 B 0 B default.rgw.control 0 B 8 0 24 0 0 0 0 0 B 0 0 B 0 B 0 B default.rgw.log 35 KiB 208 0 624 0 0 0 5919671 5.6 GiB 3945118 946 KiB 0 B 0 B default.rgw.meta 576 KiB 3 0 9 0 0 0 38 28 KiB 4 3 KiB 0 B 0 B iscsi-images 192 KiB 2 0 6 0 0 0 4184657 4.0 GiB 8 2 KiB 0 B 0 B total_objects 246 total_used 14 GiB total_avail 82 GiB total_space 96 GiB Show the statistics of the pools: admin:~ # ceph osd pool stats pool iscsi-images id 1 client io 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr pool cephfs_data id 2 nothing is going on pool cephfs_metadata id 3 nothing is going on pool .rgw.root id 4 nothing is going on pool default.rgw.control id 5 nothing is going on pool default.rgw.meta id 6 nothing is going on pool default.rgw.log id 7 nothing is going on Show only the statistics about a specific pool: admin:~ # ceph osd pool stats .rgw.root pool .rgw.root id 4 nothing is going on Show which CRUSH Map ruleset was used to create the .rgw.root pool: admin:~ # ceph osd pool get .rgw.root crush_rule crush_rule: replicated_rule Show the list of all the attributes of a pool that can be queried: admin:~ # ceph osd pool get .rgw.root size min_size pg_num pgp_num crush_rule Hashpspool Nodelete Nopgchange Nosizechange write_fadvise_dontneed noscrub|nodeep-scrub hit_set_type hit_set_period hit_set_count hit_set_fpp use_gmt_hitset target_max_objects target_max_bytes cache_target_dirty_ratio cache_target_dirty_high_ratio cache_target_full_ratio cache_min_flush_age cache_min_evict_age erasure_code_profile min_read_recency_for_promote all|min_write_recency_for_promote fast_read|hit_set_grade_decay_rate hit_set_search_last_n scrub_min_interval scrub_max_interval deep_scrub_interval recovery_priority recovery_op_priority scrub_priority compression_mode compression_algorithm compression_required_ratio compression_max_blob_size compression_min_blob_size csum_type|csum_min_block csum_max_block allow_ec_overwrites fingerprint_algorithm pg_autoscale_mode pg_autoscale_bias pg_num_min target_size_bytes target_size_ratio","title":"Task 2: Display the usage data and stats of the current pools"},{"location":"linux/SES/linux_ses_demo/#task-3-create-two-new-pools-one-replicated-one-ec","text":"1). Create a new replicated pool that will be used for storing block data for RBD. Use the standard replicated_ruleset CRUSH Map: It would be tempting to the use the better_ruleset, but this demo environment doesn\u2019t have enough resources for that. This is a demo environment, so the PG numbgrs will be low. In your production environments, be sure to assign an appropriately high numbgr, or use the pg_autoscaler manager module. admin:~ # ceph osd pool create rbd_pool 4 4 replicated replicated_rule pool 'rbd_pool' created 2). Tell the cluster that you expect to have this new rbd_pool to use 50% of the total capacity: admin:~ # ceph osd pool set rbd_pool target_size_ratio .5 set pool 8 target_size_ratio to .5 3). Create a new EC pool that will be used for storing RGW buckets and objects. Use the usable_profile Erasure Code profile that was created in an earlier exercise. And use the ec_rule CRUSH Map ruleset that was created in an earlier exercise: admin:~ # ceph osd pool create bucket_pool 4 4 erasure usable_profile ec_rule pool 'bucket_pool' created 4). Tell the cluster that you expect to have this new bucket_pool to use 100GB of data: POOL_TARGET_SIZE_BYTES_OVERCOMMITTED admin:~ # ceph osd pool set bucket_pool target_size_bytes 100000000000 set pool 9 target_size_bytes to 100000000000 5). Enable the PG Autoscaler feature on the two new pools, to ensure that we have an appropriate assignment of placement groups in the demo cluster: This presumes that you completed an earlier exercise that enable the pg_autoscaler manager module. admin:~ # ceph osd pool set bucket_pool pg_autoscale_mode on set pool 9 pg_autoscale_mode to on admin:~ # ceph osd pool set rbd_pool pg_autoscale_mode on set pool 8 pg_autoscale_mode to on 6). Again display a list of all the pools, which will now include the two new pools that you\u2019ve just created: Notice in the detail listing that the two new pools don\u2019t have an application attribute assigned to them. admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log 8 rbd_pool 9 bucket_pool admin:~ # ceph osd pool ls detail pool 1 'iscsi-images' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 448 lfor 0/448/446 flags hashpspool stripe_width 0 application rbd pool 2 'cephfs_data' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 1395 lfor 0/1374/1372 flags hashpspool stripe_width 0 application cephfs pool 3 'cephfs_metadata' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 1385 lfor 0/975/973 flags hashpspool stripe_width 0 pg_autoscale_bias 4 pg_num_min 16 recovery_priority 5 application cephfs pool 4 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 31 flags hashpspool stripe_width 0 application rgw pool 5 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 33 flags hashpspool stripe_width 0 application rgw pool 6 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 35 flags hashpspool stripe_width 0 application rgw pool 7 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 37 flags hashpspool stripe_width 0 application rgw pool 8 'rbd_pool' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 1415 lfor 0/0/1413 flags hashpspool stripe_width 0 target_size_ratio 0.5 pool 9 'bucket_pool' erasure size 3 min_size 2 crush_rule 3 object_hash rjenkins pg_num 4 pgp_num 4 autoscale_mode on last_change 1410 flags hashpspool stripe_width 8192 target_size_bytes 100000000000 7). Check the pg_autoscale status, particularly to see a comparison of how much raw space is being consumed by the two pools: See that the RATE column for all of the replicated pools shows the value of 3.0, while the value for the bucket_pool \u2013 which is an EC pool \u2013 is 1.5. The EC pool, with a K+M of 2+1 consumes considerably less raw storage space. See the TARGET RATIO for the rbd_pool. Notice that the autoscaler has automatically adjusted the numbgr PGs assigned to rbd_pool from \u201c4\u201d to \u201c128\u201d because you told the cluster to have the pool use 50% of the capacity. See the TARGET SIZE for the bucket_pool, roughly 100GB. But the cluster may not have changed the PG_NUM value yet. The autoscaler will adjust the numbgr of PGs gradually, so as not to disrupt the performance too dramatically. While you\u2019re here, you might also notice the RAW CAPACITY column. All pools are expecting to divide the cluster space equally, even though you\u2019ve explicitly told the cluster that rbd_pool and bucket_pool will deviate from that even division. admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 32 on cephfs_data 0 3.0 98256M 0.0000 1.0 32 off cephfs_metadata 7412 3.0 98256M 0.0000 4.0 16 off .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 35900 3.0 98256M 0.0000 1.0 32 warn rbd_pool 0 3.0 98256M 0.0000 0.5000 1.0 32 on bucket_pool 0 95367M 1.5 98256M 1.4559 1.0 4 on","title":"Task 3: Create two new pools, one replicated, one EC"},{"location":"linux/SES/linux_ses_demo/#task-4-assign-an-application-to-the-two-new-pools","text":"1). Assign the rbd application to the new rbd_pool that you created in the previous task: admin:~ # ceph osd pool application enable rbd_pool rbd enabled application 'rbd' on pool 'rbd_pool' 2). Instruct the cluster to prepare the new rbd_pool for storing block device images: admin:~ # rbd pool init rbd_pool 3). Assign the rgw application to the new bucket_pool that you created in the previous task: admin:~ # ceph osd pool application enable bucket_pool rgw enabled application 'rgw' on pool 'bucket_pool' 4). Display a list of all the pools again, this time noticing that the application attribute is set on the two new pools. admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log 8 rbd_pool 9 bucket_pool admin:~ # ceph osd pool ls detail pool 1 'iscsi-images' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 448 lfor 0/448/446 flags hashpspool stripe_width 0 application rbd pool 2 'cephfs_data' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 1395 lfor 0/1374/1372 flags hashpspool stripe_width 0 application cephfs pool 3 'cephfs_metadata' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 1385 lfor 0/975/973 flags hashpspool stripe_width 0 pg_autoscale_bias 4 pg_num_min 16 recovery_priority 5 application cephfs pool 4 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 31 flags hashpspool stripe_width 0 application rgw pool 5 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 33 flags hashpspool stripe_width 0 application rgw pool 6 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 35 flags hashpspool stripe_width 0 application rgw pool 7 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 37 flags hashpspool stripe_width 0 application rgw pool 8 'rbd_pool' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 1420 lfor 0/0/1413 flags hashpspool,selfmanaged_snaps stripe_width 0 target_size_ratio 0.5 application rbd removed_snaps [1~3] pool 9 'bucket_pool' erasure size 3 min_size 2 crush_rule 3 object_hash rjenkins pg_num 4 pgp_num 4 autoscale_mode on last_change 1422 flags hashpspool stripe_width 8192 target_size_bytes 100000000000 application rgw 5). Another way to display which application is assigned to a pool is: admin:~ # ceph osd pool application get bucket_pool { \"rgw\": {} } admin:~ # ceph osd pool application get rbd_pool { \"rbd\": {} }","title":"Task 4: Assign an application to the two new pools"},{"location":"linux/SES/linux_ses_demo/#task-5-manage-snapshots-of-the-new-rgw-bucket-pool","text":"1). Display a list of the snapshots that exist of the bucket_pool that you created in the previous task: The output show that there are \u201c0 snaps.\u201d Right, it is a little funny that you only list the snapshots with rados command; no such functionality exists with the ceph osd pool command. admin:~ # rados -p bucket_pool lssnap 0 snaps 2). Take (make) a snapshot of the rbd_pool: admin:~ # ceph osd pool mksnap bucket_pool brand_new_pool_snapshot created pool bucket_pool snap brand_new_pool_snapshot 3). Display the list of the snapshots again: admin:~ # rados -p bucket_pool lssnap 1 brand_new_pool_snapshot 2021.01.05 22:23:23 1 snaps 4). Remove the snapshot: admin:~ # ceph osd pool rmsnap bucket_pool brand_new_pool_snapshot removed pool bucket_pool snap brand_new_pool_snapshot 5). Display the list of the snapshots again: admin:~ # rados -p bucket_pool lssnap 0 snaps","title":"Task 5: Manage snapshots of the new RGW bucket pool"},{"location":"linux/SES/linux_ses_demo/#224-maintain-consistency-of-data-with-scrub-and-repair","text":"Scrubbing is like \u201cfsck,\u201d which ensures that OSDs have durable, consistent data. Most of the scrubbing of OSDs happens automatically on a periodic basis.","title":"2.2.4. Maintain consistency of data with Scrub and Repair"},{"location":"linux/SES/linux_ses_demo/#task-1-display-a-few-of-the-scrub-settings","text":"1). Show the possible configuration settings related to scrub: If you simply grep for \u201cscrub\u201d you\u2019ll get more than you really want; there are some mon_scrub settings that aren\u2019t related to this exercise. admin:~ # ceph config ls | grep osd_scrub osd_scrub_invalid_stats osd_scrub_during_recovery osd_scrub_begin_hour osd_scrub_end_hour osd_scrub_begin_week_day osd_scrub_end_week_day osd_scrub_load_threshold osd_scrub_min_interval osd_scrub_max_interval osd_scrub_interval_randomize_ratio osd_scrub_backoff_ratio osd_scrub_chunk_min osd_scrub_chunk_max osd_scrub_sleep osd_scrub_auto_repair osd_scrub_auto_repair_num_errors osd_scrub_max_preemptions osd_scrub_priority osd_scrub_cost admin:~ # ceph config ls | grep osd_deep_scrub osd_deep_scrub_interval osd_deep_scrub_randomize_ratio osd_deep_scrub_stride osd_deep_scrub_keys osd_deep_scrub_update_digest_min_age osd_deep_scrub_large_omap_object_key_threshold osd_deep_scrub_large_omap_object_value_sum_threshold admin:~ # ceph config ls | grep scrub mon_warn_pg_not_scrubbed_ratio mon_warn_pg_not_deep_scrubbed_ratio mon_scrub_interval mon_scrub_timeout mon_scrub_max_keys mon_scrub_inject_crc_mismatch mon_scrub_inject_missing_keys osd_op_queue_mclock_scrub_res osd_op_queue_mclock_scrub_wgt osd_op_queue_mclock_scrub_lim osd_scrub_invalid_stats osd_max_scrubs osd_scrub_during_recovery osd_scrub_begin_hour osd_scrub_end_hour osd_scrub_begin_week_day osd_scrub_end_week_day osd_scrub_load_threshold osd_scrub_min_interval osd_scrub_max_interval osd_scrub_interval_randomize_ratio osd_scrub_backoff_ratio osd_scrub_chunk_min osd_scrub_chunk_max osd_scrub_sleep osd_scrub_auto_repair osd_scrub_auto_repair_num_errors osd_scrub_max_preemptions osd_deep_scrub_interval osd_deep_scrub_randomize_ratio osd_deep_scrub_stride osd_deep_scrub_keys osd_deep_scrub_update_digest_min_age osd_deep_scrub_large_omap_object_key_threshold osd_deep_scrub_large_omap_object_value_sum_threshold osd_debug_deep_scrub_sleep osd_scrub_priority osd_scrub_cost osd_requested_scrub_priority mds_max_scrub_ops_in_progress 2). Get the value of a few of the different scrub schedule settings: Note that \u201c0\u201d and \u201c24\u201d are the same setting. admin:~ # ceph config get osd.* osd_scrub_begin_hour 0 admin:~ # ceph config get osd.* osd_scrub_end_hour 24 3). Get the value of the scrub and repair settings: The \u201cauto repair\u201d feature is turned off, and the maximum numbgr of errors that \u201cauto repair\u201d would automatically repair is 5. admin:~ # ceph config get osd.* osd_scrub_auto_repair false admin:~ # ceph config get osd.* osd_scrub_auto_repair_num_errors 5","title":"Task 1: Display a few of the Scrub settings"},{"location":"linux/SES/linux_ses_demo/#task-2-change-the-scrub-settings-in-cephconf","text":"1). Display the ceph.conf, and verify that the file doesn\u2019t have any settings defined yet that are related to scrub. The settings would be located in the [global] section of the file: # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.186, 10.58.121.187, 10.58.121.188 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] 2). Change to the Salt File Server directory that will have Salt control the master ceph.conf configuration file: admin:~ # cd /srv/salt/ceph/configuration/files/ceph.conf.d/ 3). List the content of the directory: The directory is empty. (Well, there is a README, but no other functional files.) admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ls -l -rw-r--r-- 1 root root 1989 May 14 2020 README 4). Create and edit a new file called global.conf. You don\u2019t have to use vi, but this step uses vi as one way of doing it: Be sure that you spell everything correctly, including the absence of \u201c_\u201d characters; there are spaces. Save the file and exit out of the editor. admin:/srv/salt/ceph/configuration/files/ceph.conf.d # vi global.conf Add the following content to the file: osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 5). Use DeepSea (Salt) to stage the file properly in Salt\u2019s File Server on the Salt Master (admin): admin:/srv/salt/ceph/configuration/files/ceph.conf.d # salt admin* state.apply ceph.configuration.create admin.sha.me.corp: Name: /var/cache/salt/minion/files/base/ceph/configuration - Function: file.absent - Result: Changed Started: - 22:42:34.900173 Duration: 20.891 ms Name: /srv/salt/ceph/configuration/cache/ceph.conf - Function: file.managed - Result: Changed Started: - 22:42:34.921454 Duration: 8576.516 ms Name: find /var/cache/salt/master/jobs -user root -exec chown salt:salt {} ';' - Function: cmd.run - Result: Changed Started: - 22:42:43.535022 Duration: 71.957 ms Summary for admin.sha.me.corp ------------ Succeeded: 3 (changed=3) Failed: 0 ------------ Total states run: 3 Total run time: 8.669 s 6). Using DeepSea (Salt), distribute the new ceph.conf configuration settings to all the nodes in the cluster: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # salt \\* state.apply ceph.configuration mon3.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:07.986661 Duration: 101.977 ms Summary for mon3.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 101.977 ms mon1.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.012479 Duration: 108.888 ms Summary for mon1.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 108.888 ms data3.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.052247 Duration: 98.681 ms Summary for data3.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 98.681 ms admin.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.072402 Duration: 97.231 ms Summary for admin.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 97.231 ms data1.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.076279 Duration: 104.169 ms Summary for data1.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 104.169 ms data4.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.081635 Duration: 105.13 ms Summary for data4.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 105.130 ms mon2.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.155758 Duration: 105.004 ms Summary for mon2.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 105.004 ms data2.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.252200 Duration: 109.552 ms Summary for data2.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 109.552 ms 7). Verify that the new ceph.conf settings have been put into place on the admin node: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # cat /etc/ceph/ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] 8). Also verify that other minions in the cluster have also received the updated configuration file, such as on the mon1 and data2 nodes: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ssh mon1 cat /etc/ceph/ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ssh data1 cat /etc/ceph/ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] 9). Apply the settings of the ceph.conf file to appropriate nodes in the cluster: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ceph config assimilate-conf -i /etc/ceph/ceph.conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_health_preluminous_compat = true mon_health_preluminous_compat_warning = false mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 mon_initial_membgrs = mon1, mon2, mon3","title":"Task 2: Change the Scrub settings in ceph.conf"},{"location":"linux/SES/linux_ses_demo/#task-3-change-the-scrub-settings-directly-in-the-configuration-db","text":"1). Query the configuration database to see the value of \u201cosd_scrub_auto_repair_num_errors\u201d: You changed this value to \u201c10\u201d in the previous Task. admin:~ # ceph config get osd.* osd_scrub_auto_repair_num_errors 10 2). Change the value of \u201cosd_scrub_auto_repair_num_errors\u201d to \u201c8\u201d: admin:~ # ceph config set osd.* osd_scrub_auto_repair_num_errors 8 3). Show that the change has taken immediate effect by re-running the same command that was used in the first step: admin:~ # ceph config get osd.* osd_scrub_auto_repair_num_errors 8","title":"Task 3: Change the Scrub settings directly in the Configuration DB"},{"location":"linux/SES/linux_ses_demo/#task-4-manually-scrub-and-repair-an-osd-and-a-pg","text":"This won\u2019t do much in this demo environment, because the OSDs aren\u2019t storing very much data. But it\u2019s worth having some practice. 1). Start a scrubbing of one of the OSDs: admin:~ # ceph osd scrub osd.1 instructed osd(s) 1 to scrub 2). Scrub a Placement Group: admin:~ # ceph pg scrub 8.1 instructing pg 8.1 on osd.0 to scrub 3). Repair an OSD: admin:~ # ceph osd repair osd.1 instructed osd(s) 1 to repair 4). Repair a PG: admin:~ # ceph pg repair 8.1 instructing pg 8.1 on osd.0 to repair 5). Show what\u2019s currently happening to the OSD that you instructed to have scrubbed and repaired: admin:~ # ceph osd dump | grep osd.1 max_osd 12 osd.1 up in weight 1 up_from 10 up_thru 1415 down_at 0 last_clean_interval [0,0) v1:10.58.121.185:6800/11157 v1:10.58.121.185:6801/11157 exists,up 32c78078-1878-4fac-9738-00d8bf80deea osd.10 up in weight 1 up_from 18 up_thru 1413 down_at 0 last_clean_interval [0,0) v1:10.58.121.182:6808/11130 v1:10.58.121.182:6809/11130 exists,up 6cb26fdc-09b1-42de-8855-7203931a0101 osd.11 up in weight 1 up_from 18 up_thru 1415 down_at 0 last_clean_interval [0,0) v1:10.58.121.185:6808/11995 v1:10.58.121.185:6809/11995 exists,up cc22107d-0239-4874-8308-6c137c8a0931 6). Show what\u2019s currently happening to the PG that you instructed to have scrubbed and repaired: admin:~ # ceph pg dump | grep \"8\\.1\" dumped all 8.16 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.383909 0'0 1423:27 [6,4,5] 6 [6,4,5] 6 0'0 2021-01-05 20:53:47.314062 0'0 2021-01-05 20:53:47.314062 0 8.17 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:01.044252 0'0 1424:30 [1,6,8] 1 [1,6,8] 1 0'0 2021-01-05 22:57:01.044098 0'0 2021-01-05 22:57:01.044098 0 8.14 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:56:56.081480 0'0 1424:30 [1,2,4] 1 [1,2,4] 1 0'0 2021-01-05 22:56:56.081356 0'0 2021-01-05 22:56:56.081356 0 8.15 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.375386 0'0 1423:27 [3,5,0] 3 [3,5,0] 3 0'0 2021-01-05 20:53:53.231124 0'0 2021-01-05 20:48:05.301705 0 8.12 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.370121 0'0 1423:27 [11,2,8] 11 [11,2,8] 11 0'0 2021-01-05 20:53:48.149449 0'0 2021-01-05 20:48:05.301705 0 2.18 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 16:44:58.986205 0'0 1423:1630 [10,1,8] 10 [10,1,8] 10 0'0 2021-01-05 13:02:00.365382 0'0 2021-01-02 00:38:58.134100 0 8.13 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.387832 0'0 1423:27 [0,8,1] 0 [0,8,1] 0 0'0 2021-01-05 20:53:56.132358 0'0 2021-01-05 20:48:05.301705 0 8.10 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.368416 0'0 1423:27 [11,3,6] 11 [11,3,6] 11 0'0 2021-01-05 20:53:51.152790 0'0 2021-01-05 20:48:05.301705 0 8.11 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.377871 0'0 1423:24 [3,10,5] 3 [3,10,5] 3 0'0 2021-01-05 20:53:45.195257 0'0 2021-01-05 20:48:05.301705 0 8.1e 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.391754 0'0 1423:47 [0,11,8] 0 [0,11,8] 0 0'0 2021-01-05 20:53:55.081582 0'0 2021-01-05 20:48:05.301705 0 8.1 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:56:39.829397 0'0 1424:54 [0,7,10] 0 [0,7,10] 0 0'0 2021-01-05 22:56:39.829241 0'0 2021-01-05 22:56:39.829241 0 8.1f 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.392315 0'0 1423:27 [7,5,9] 7 [7,5,9] 7 0'0 2021-01-05 20:53:59.988252 0'0 2021-01-05 20:48:05.301705 0 5.4 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 18:21:28.179266 0'0 1423:1554 [7,9,6] 7 [7,9,6] 7 0'0 2021-01-05 18:21:28.179166 0'0 2021-01-05 18:21:28.179166 0 5.b 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 18:37:01.467457 0'0 1423:1547 [2,0,11] 2 [2,0,11] 2 0'0 2021-01-04 23:46:58.132824 0'0 2021-01-02 03:35:41.214192 0 8.19 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:06.059090 0'0 1424:30 [1,8,2] 1 [1,8,2] 1 0'0 2021-01-05 22:57:06.058935 0'0 2021-01-05 22:57:06.058935 0 8.18 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:05.097742 0'0 1424:30 [1,3,6] 1 [1,3,6] 1 0'0 2021-01-05 22:57:05.097670 0'0 2021-01-05 22:57:05.097670 0 1.11 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 00:30:18.193988 0'0 1423:1605 [0,8,6] 0 [0,8,6] 0 0'0 2021-01-05 00:30:18.193868 0'0 2020-12-29 06:30:58.897565 0 8.1b 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:13.146469 0'0 1424:30 [1,4,6] 1 [1,4,6] 1 0'0 2021-01-05 22:57:13.146390 0'0 2021-01-05 22:57:13.146390 0 8.1a 1 0 0 0 0 19 0 0 2 2 active+clean 2021-01-05 21:01:16.386166 1420'2 1423:29 [9,11,10] 9 [9,11,10] 9 0'0 2021-01-05 20:53:48.690239 0'0 2021-01-05 20:48:05.301705 0 8.1d 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.388079 0'0 1423:56 [0,2,3] 0 [0,2,3] 0 0'0 2021-01-05 20:53:54.121281 0'0 2021-01-05 20:48:05.301705 0 8.1c 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.385846 0'0 1423:27 [2,11,7] 2 [2,11,7] 2 0'0 2021-01-05 20:53:55.458714 0'0 2021-01-05 20:48:05.301705 0","title":"Task 4: Manually scrub and repair an OSD and a PG"},{"location":"linux/SES/linux_ses_demo/#225-manipulate-manager-modules","text":"","title":"2.2.5. Manipulate Manager Modules"},{"location":"linux/SES/linux_ses_demo/#task-1-display-the-list-of-enabled-manager-modules","text":"1). Run the following command to show the list of enabled manager modules: Note that several modules are already enabled, such as: dashboard, iostat, pg_autosclater, prometheus, and restful. Even though they are not listed, the crash module and the balancer module are already enabled by default. admin:~ # ceph mgr module ls | head { \"always_on_modules\": [ \"balancer\", \"crash\", \"devicehealth\", \"orchestrator_cli\", \"progress\", \"rbd_support\", \"status\", \"volumes\" 2). Demonstrate that the crash module is enabled by running its command with no arguments: A list of \u201c7 closest matches\u201d is displayed, representing possible additional arguments to be used with the crash command. The crash module is therefore available. admin:~ # ceph crash crash info crash ls crash ls-new crash post crash prune crash rm crash stat crash json_report crash archive crash archive-all admin:~ # ceph crash stat 0 crashes recorded Task 2: Use the iostat module to display statistics for the IO of the cluster The iostat module is really simple, but very helpful. Run the command: admin:~ # ceph iostat +-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+ | Read | Write | Total | Read IOPS | Write IOPS | Total IOPS | +-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+ | 1024 B/s | 0 B/s | 1024 B/s | 1 | 0 | 1 | | 1024 B/s | 0 B/s | 1024 B/s | 1 | 0 | 1 | | 0 B/s | 0 B/s | 0 B/s | 0 | 0 | 0 | Task 3: Enable and configure the telemetry manager module 1). Enable the telemetry manager module: admin:~ # ceph mgr module enable telemetry 2). Show the various sub-commands that are associated with the telemetry command: A list of \u201c5 closest matches\u201d is displayed, showing various options. admin:~ # ceph telemetry telemetry status telemetry send {ceph|device [ceph|device...]} {} telemetry show { [...]} telemetry show-device telemetry on {} telemetry off 3). Show the status of the telemetry module: Notice that the output is returned as key/value pairs. Notice also that although the module has been enabled (which you accomplished in the first step of this task), the functionality is not enabled (enable=false). And for most of the keys, a null value is set. See that the url value is set to https://telemetry.ceph.com/report. That means that crash reports and other usage information about this cluster are going to be sent to the Ceph Community. admin:~ # ceph telemetry status { \"url\": \"https://telemetry.ceph.com/report\", \"device_url\": \"https://telemetry.ceph.com/device\", \"enabled\": false, \"last_opt_revision\": 1, \"leaderboard\": false, \"description\": null, \"contact\": null, \"organization\": null, \"proxy\": null, \"interval\": 24, \"channel_basic\": true, \"channel_ident\": false, \"channel_crash\": true, \"channel_device\": true, \"last_upload\": null } 4). Set the description, contact, and organization values: admin:~ # ceph config set mgr mgr/telemetry/contact 'JD ' admin:~ # ceph config set mgr mgr/telemetry/description 'Training Cluster' admin:~ # ceph config set mgr mgr/telemetry/organization 'SUSE Training' 5). Display the telemetry data that is collected to be sent: admin:~ # ceph telemetry show | less 6). With the contact information properly set, enable the telemetry functionality: This is a demo cluster with no connection to the internet, so no telemetry data will actually be sent. admin:~ # ceph telemetry on Error EPERM: Telemetry data is licensed under the Community Data License Agreement - Sharing - Version 1.0 (https://cdla.io/sharing-1-0/). To enable, add '--license sharing-1-0' to the 'ceph telemetry on' command. admin:~ # ceph telemetry on --license sharing-1-0 7). Disable the telemetry module: admin:~ # ceph mgr module disable telemetry admin:~ # ceph telemetry show | less Error ENOTSUP: Module 'telemetry' is not enabled (required by command 'telemetry show'): use `ceph mgr module enable telemetry` to enable it","title":"Task 1: Display the list of enabled Manager Modules"},{"location":"linux/SES/linux_ses_demo/#task-4-briefly-attempt-to-use-the-crash-manager-module","text":"1). Show (again) the various sub-commands that are associated with the crash command: admin:~ # ceph crash crash info crash ls crash ls-new crash post crash prune crash rm crash stat crash json_report crash archive crash archive-all 2). Show the current status of the crash database, including the numbgr of crash reports that have been collected so far: It\u2019s likely that the numbgr of crashes recorded in the demo environment is 0. admin:~ # ceph crash stat 0 crashes recorded","title":"Task 4: Briefly attempt to use the crash manager module"},{"location":"linux/SES/linux_ses_demo/#226-introduction-to-the-tell-command","text":"Tell is a very powerful command within Ceph to control the cluster. You don\u2019t use it everyday, but you need to know how to use it when the occasion to use it arises. It\u2019s mostly an Advanced Command, but exposure to it now reduces the stress of learning about it in a more advanced setting later. Run the tell command in a few different circumstances to control the behavior of various Ceph services.","title":"2.2.6. Introduction to the Tell command"},{"location":"linux/SES/linux_ses_demo/#task-1-run-a-benchmark-test-on-an-osd","text":"1). Run the following command to run and see the result of a benchmark test on osd.8: admin:~ # ceph tell osd.8 bench { \"bytes_written\": 1073741824, \"blocksize\": 4194304, \"elapsed_sec\": 3.7797023200000002, \"bytes_per_sec\": 284081055.35676152, \"iops\": 67.730201567831401 }","title":"Task 1: Run a benchmark test on an OSD"},{"location":"linux/SES/linux_ses_demo/#task-2-change-the-protection-setting-regarding-the-deletion-of-pools","text":"1). The default behavior in Ceph is that you can\u2019t delete pools. Try to delete a pool: The output says that you have to be VERY careful and provide more arguments in order to delete a pool admin:~ # ceph osd pool delete rbd_pool Error EPERM: WARNING: this will *PERMANENTLY DESTROY* all data stored in pool rbd_pool. If you are *ABSOLUTELY CERTAIN* that is what you want, pass the pool name *twice*, followed by --yes-i-really-really-mean-it. 2). Try deleting the pool again, this time with the extra arguments: Ceph still won\u2019t let you do it because the mon allow pool delete setting has the value of false. admin:~ # ceph osd pool delete rbd_pool rbd_pool --yes-i-really-really-mean-it Error EPERM: pool deletion is disabled; you must first set the mon_allow_pool_delete config option to true before you can destroy a pool 3). Show that the mon allow pool delete setting has the value of false: Indeed, the output shows that the value is false. admin:~ # ceph config get mon.mon\\* mon_allow_pool_delete false 4). Change to value of the setting using injectargs: Note that the \u201c-\u201d and \u201c_\u201d characters can be confusing. And note that the setting is preceded with the double \u201c--\u201d. The injected args must be enclosed in single quotes. You could have done this with ceph config set, but this is an alternative way to directly \u201ctell\u201d the cluster to change a setting. admin:~ # ceph tell mon.\\* injectargs '--mon-allow-pool-delete=true' mon.mon1: injectargs:mon_allow_pool_delete = 'true' mon.mon2: injectargs:mon_allow_pool_delete = 'true' mon.mon3: injectargs:mon_allow_pool_delete = 'true'","title":"Task 2: Change the protection setting regarding the deletion of pools"},{"location":"linux/SES/linux_ses_demo/#23-ceph-dashboard","text":"","title":"2.3. Ceph Dashboard"},{"location":"linux/SES/linux_ses_demo/#231-access-dashboard","text":"","title":"2.3.1. Access Dashboard"},{"location":"linux/SES/linux_ses_demo/#task-1-set-the-password-for-the-admin-user-of-the-ceph-dashboard","text":"1). In a Bash terminal as the root user, show that the Dashboard module is enabled: \u201cdashboard\u201d should be included in the list of \u201cenabled_modules\u201d at the top of the output. admin:~ # ceph mgr module ls | more \"enabled_modules\": [ \"dashboard\", \"iostat\", \"pg_autoscaler\", \"prometheus\", \"restful\" ], 2). Show the valid dashboard users that have already been created by DeepSea during initial deployment: It\u2019s possible that other users will be listed, but at least the \u201cadmin\u201d user should be displayed in the output. admin:~ # ceph dashboard ac-user-show [\"admin\"] 3). Show the \u201cadmin\u201d user\u2019s information as stored in the user database: You can see that the admin user has a password set, but it is stored as a hash. So you don\u2019t really know what the password is, and have no way of discovering it. admin:~ # ceph dashboard ac-user-show admin {\"username\": \"admin\", \"password\": , \"roles\": [\"administrator\"], \"name\": null, \"email\": null, \"lastUpdate\": 1601874928} 4). Change the \u201cadmin\u201d user\u2019s password for the dashboard: This sets the \u201cadmin\u201d user\u2019s password to the string: mypassword admin:~ # ceph dashboard ac-user-set-password admin mypassword {\"username\": \"admin\", \"password\": , \"roles\": [\"administrator\"], \"name\": null, \"email\": null, \"lastUpdate\": 1609860842} admin:~ #","title":"Task 1: Set the password for the admin user of the Ceph Dashboard"},{"location":"linux/SES/linux_ses_demo/#task-3-visit-the-ceph-dashboard-url","text":"admin:~ # salt-call grains.get dashboard_creds local: ---------- admin: admin:~ # ceph mgr services { \"dashboard\": \"https://mon1.sha.me.corp:8443/\", \"prometheus\": \"http://mon1.sha.me.corp:9283/\" } admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 25m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 5h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 9 pools, 244 pgs objects: 247 objects, 5.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 244 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr URL: https://mon1.sha.me.corp:8443/ https://10.58.121.186:8443","title":"Task 3: Visit the Ceph Dashboard URL"},{"location":"linux/SES/linux_ses_demo/#232-explore-the-dashboard-health-performance-status","text":"Dashboard Status Cluster Status Monitors OSDs Manager Daemons Hosts Object Gateway Metadata Service iSCSI Gateway Performance Client IOPS Client Throughput Client Read/Write Recovery Throughput Scrub Capacity Pools Raw Capacity Objects PGs per OSD PG Status [SUSE Enterprise Storage Portal Cluster\u2192Configuration Cluster\u2192Manager Modules Pools\u2192Create Pool","title":"2.3.2. Explore the Dashboard Health, Performance, Status"},{"location":"linux/SES/linux_ses_demo/#24-storage-data-access","text":"","title":"2.4. Storage Data Access"},{"location":"linux/SES/linux_ses_demo/#241-ensure-the-ses-cluster-is-healthy","text":"","title":"2.4.1. Ensure the SES Cluster is Healthy"},{"location":"linux/SES/linux_ses_demo/#task-1-check-the-clusters-health","text":"1). Run the following command to check the status (health) of the SES cluster: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 18h) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 23h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 5.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr 2). Evaluate the output. The cluster in this demonstration environment often doesn\u2019t startup correctly due to the nature of a demo environment and it\u2019s less-predictable resources. Depending on whether any of the following tasks are necessary, followup accordingly to ensure that the cluster is healthy before proceeding with the course lectures or any further exercises. 3). Run the following series of commands to restart the Monitor daemons on each of the Monitor nodes: It\u2019s certainly not necessary to restart the monitor daemons on all of the monitor nodes if only one is down. If you prefer, you can take a different approach to starting the daemon on a single monitor node. admin:~ # for h in mon1 mon2 mon3; \\ do \\ ssh $h systemctl restart ceph-mon@$h; \\ done 4). After waiting a few moments for the daemons to restart, check the status again: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 15s) mgr: mon1(active, since 21h) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 26h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 5.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 767 B/s rd, 0 op/s rd, 0 op/s wr 5). Run the following series of commands to restart the Manager daemons on each of the Monitor nodes: admin:~ # for h in mon1 mon2 mon3; \\ do \\ ssh $h systemctl restart ceph-mgr@$h; \\ done 6). After waiting a few moments for the daemons to restart, check the status again: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 8m) mgr: mon1(active, since 18s) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 26h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.1 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr 7). Run the following command to restart the MDS daemon on the MDS node (mon1): admin:~ # ssh mon1 systemctl restart ceph-mds@mon1.service 8). After waiting a few moments for the mds daemon to restart, check the status again: Look for the mds service to be plain active rather than laggy or crashed admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 17m) mgr: mon1(active, since 8m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 26h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.2 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr 9). Verify if the OSDs \u201cup\u201d and running properly. It is only necessary if the output of ceph -s shows that there are fewer than 9 OSDs shown as being \u201cup\u201d. It\u2019s most likely that a storage node is simply not quite fully booted yet, such that the OSD daemons haven\u2019t fully come up. But if you suspect that the solution requires something different than simply waiting a little longer, you should try the following steps. First, identify which server is hosting the down\u2019d OSDs. One way of doing that is with this command: admin:~ # ceph osd tree ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF -1 0.09357 root default -9 0.02339 host data1 2 hdd 0.00780 osd.2 up 1.00000 1.00000 6 hdd 0.00780 osd.6 up 1.00000 1.00000 10 hdd 0.00780 osd.10 up 1.00000 1.00000 -3 0.02339 host data2 0 hdd 0.00780 osd.0 up 1.00000 1.00000 4 hdd 0.00780 osd.4 up 1.00000 1.00000 9 hdd 0.00780 osd.9 up 1.00000 1.00000 -7 0.02339 host data3 3 hdd 0.00780 osd.3 up 1.00000 1.00000 7 hdd 0.00780 osd.7 up 1.00000 1.00000 8 hdd 0.00780 osd.8 up 1.00000 1.00000 -5 0.02339 host data4 1 hdd 0.00780 osd.1 up 1.00000 1.00000 5 hdd 0.00780 osd.5 up 1.00000 1.00000 11 hdd 0.00780 osd.11 up 1.00000 1.00000 Simply try restarting the storage daemon processes on the affected host, such as with this example: admin:~ # ssh data2 systemctl restart ceph-osd@9.service admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 32m) mgr: mon1(active, since 24m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 27s), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.2 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr If the OSD daemon processes are being stubborn and uncooperative, you may choose to reboot the storage virtual machine entirely. This is one way to do that: admin:~ # ssh data1 systemctl reboot After waiting some time for the daemons to get started, verify that all the OSDs are \u201cup\u201d and that the cluster is healthy: admin:~ # ceph osd tree admin:~ # ceph status 10). Run the following command to restart the RADOS Gateway daemon on the node that is hosting the gateway (mon3): admin:~ # ssh mon3 systemctl restart ceph-radosgw@rgw.mon3.service admin:~ # ssh mon3 systemctl status ceph-radosgw@rgw.mon3.service \u25cf ceph-radosgw@rgw.mon3.service - Ceph rados gateway Loaded: loaded (/usr/lib/systemd/system/ceph-radosgw@.service; enabled; vendor preset: disabled) Active: active (running) since Wed 2021-01-06 21:37:53 CST; 23s ago Main PID: 781880 (radosgw) Tasks: 588 CGroup: /system.slice/system-ceph\\x2dradosgw.slice/ceph-radosgw@rgw.mon3.service \u2514\u2500781880 /usr/bin/radosgw -f --cluster ceph --name client.rgw.mon3 --setuser ceph --setgroup ceph Jan 06 21:37:53 mon3 systemd[1]: Started Ceph rados gateway. 11). After waiting a few moments for the daemon to restart, check the status again: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 39m) mgr: mon1(active, since 30m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 6m), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.2 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr","title":"Task 1: Check the Cluster\u2019s health"},{"location":"linux/SES/linux_ses_demo/#242-use-the-s3-api-to-interact-with-the-rados-gateway","text":"In this lab we used the s3cmd and radosgw-admin utilities to interact with the SUSE Enterprise Storage cluster. We created a new user, a new bucket, and a new file. We then uploaded the file to the cluster and verified that the object gateway stored it to the cluster.","title":"2.4.2. Use the S3 API to Interact with the RADOS Gateway"},{"location":"linux/SES/linux_ses_demo/#task-1-using-the-s3cmd-tool-and-create-an-s3-user","text":"1). As the root user (password is linux) in a shell or terminal, verify that the s3cmd is available on the admin node: You will likely see an error about configuration files missing, etc. This is enough information to validate the utility is installed. admin:~ # pip --version pip 10.0.1 from /usr/lib/python3.6/site-packages/pip (python 3.6) admin:~ # pip install s3cmd Collecting s3cmd Downloading https://files.pythonhosted.org/packages/26/44/19e08f69b2169003f7307565f19449d997895251c6a6566ce21d5d636435/s3cmd-2.1.0-py2.py3-none-any.whl (145kB) 100% | 153kB 2.7MB/s Collecting python-magic (from s3cmd) Downloading https://files.pythonhosted.org/packages/59/77/c76dc35249df428ce2c38a3196e2b2e8f9d2f847a8ca1d4d7a3973c28601/python_magic-0.4.18-py2.py3-none-any.whl Requirement already satisfied: python-dateutil in /usr/lib/python3.6/site-packages (from s3cmd) (2.7.3) Requirement already satisfied: six>=1.5 in /usr/lib/python3.6/site-packages (from python-dateutil->s3cmd) (1.11.0) Installing collected packages: python-magic, s3cmd Successfully installed python-magic-0.4.18 s3cmd-2.1.0 2). Create a new S3 user to be used: The output will include an access_key value and a secret_key value. You will need both of those values in later steps. admin:~ # radosgw-admin user create --uid=s3user --display-name=S3 User --email=s3user@example.net { \"user_id\": \"s3user\", \"display_name\": \"S3\", \"email\": \"s3user@example.net\", \"suspended\": 0, \"max_buckets\": 1000, \"subusers\": [], \"keys\": [ { \"user\": \"s3user\", \"access_key\": , \"secret_key\": } ], \"swift_keys\": [], \"caps\": [], \"op_mask\": \"read, write, delete\", \"default_placement\": \"\", \"default_storage_class\": \"\", \"placement_tags\": [], \"bucket_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"user_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"temp_url_keys\": [], \"type\": \"rgw\", \"mfa_ids\": [] } Retrieve above information admin:~ # radosgw-admin user info --uid=s3user","title":"Task 1: Using the s3cmd tool and create an S3 user"},{"location":"linux/SES/linux_ses_demo/#task-2-create-a-new-s3cmd-configuration-file-and-a-new-s3-bucket","text":"1). Generate a new s3cmd configuration file from a shell on the admin node: Fill in as listed below: admin:~ # cd ~ admin:~ # s3cmd --configure Enter new values or accept defaults in brackets with Enter. Refer to user manual for detailed description of all options. Access key and Secret key are your identifiers for Amazon S3. Leave them empty for using the env variables. Access Key: Secret Key: Default Region [US]: Use \"s3.amazonaws.com\" for S3 Endpoint and not modify it to the target Amazon S3. S3 Endpoint [s3.amazonaws.com]: mon3.sha.me.corp Use \"%(bucket)s.s3.amazonaws.com\" to the target Amazon S3. \"%(bucket)s\" and \"%(location)s\" vars can be used if the target S3 system supports dns based buckets. DNS-style bucket+hostname:port template for accessing a bucket [%(bucket)s.s3.amazonaws.com]: %(bucket)s.mon3.sha.me.corp Encryption password is used to protect your files from reading by unauthorized persons while in transfer to S3 Encryption password: Path to GPG program [/usr/bin/gpg]: When using secure HTTPS protocol all communication with Amazon S3 servers is protected from 3 rd party eavesdropping. This method is slower than plain HTTP, and can only be proxied with Python 2.7 or newer Use HTTPS protocol [Yes]: No On some networks all internet access must go through a HTTP proxy. Try setting it here if you can't connect to S3 directly HTTP Proxy server name: New settings: Access Key: Secret Key: Default Region: US S3 Endpoint: mon3.sha.me.corp DNS-style bucket+hostname:port template for accessing a bucket: %(bucket)s.mon3.sha.me.corp Encryption password: Path to GPG program: /usr/bin/gpg Use HTTPS protocol: False HTTP Proxy server name: HTTP Proxy server port: 0 Test access with supplied credentials? [Y/n] n Save settings? [y/N] y Configuration saved to '/root/.s3cfg' 2). Test the configuration by checking for existing files or directories: Since no buckets or files have been made available for the user, no items are listed and the command returns you to the prompt with no output. This is normal. If there is an error, your configuration may have a typo in it. The configuration file will have been saved as .s3cfg. Edit the file to match the configuration in step one. admin:~ # s3cmd ls 3). Create a new bucket for uploading files to using the s3cmd: You should see feedback that the bucket has been created. Although not technically required by the S3 API, the bucket name needs to be in all uppercase to avoid a bug with the s3cmd tool itself. admin:~ # s3cmd mb s3://S3CMDTEST Bucket 's3://S3CMDTEST/' created admin:~ # s3cmd ls 2021-01-06 14:04 s3://S3CMDTEST (it's GMT timezone)","title":"Task 2: Create a new s3cmd configuration file and a new S3 bucket"},{"location":"linux/SES/linux_ses_demo/#task3-create-and-upload-a-file-to-a-bucket-using-the-s3-api","text":"1). Create a file with a few words of text: admin:~ # echo \"The mountains are beautiful\" > newfile 2). Put the new file into your bucket using s3cmd: You should see the file being uploaded. admin:~ # s3cmd put newfile s3://S3CMDTEST upload: 'newfile' -> 's3://S3CMDTEST/newfile' [1 of 1] 28 of 28 100% in 3s 7.66 B/s done 3). Verify the file is now in your bucket, safely stored in you SES cluster: admin:~ # s3cmd ls s3://S3CMDTEST 2021-01-06 14:11 28 s3://S3CMDTEST/newfile","title":"Task3: Create and upload a file to a bucket using the S3 API"},{"location":"linux/SES/linux_ses_demo/#243-use-the-swift-api-to-interact-with-the-rados-gateway","text":"OpenStack packages for SUSE Install and configure the storage nodes for openSUSE and SUSE Linux Enterprise SUSE Package Hub: python-PasteDeploy Enable SUSE Package Hub extension admin:~ # SUSEConnect -p PackageHub/15.1/x86_64 Install python3-PasteDeploy, which is dependency of python-swift installation admin:~ # zypper in python3-PasteDeploy admin:~ # rpm -ivh python3-PyECLib-1.6.0-1.6.x86_64.rpm warning: python3-PyECLib-1.6.0-1.6.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 3dbdc284: NOKEY error: Failed dependencies: python(abi) = 3.8 is needed by python3-PyECLib-1.6.0-1.6.x86_64 rpmlib(PayloadIsZstd) <= 5.4.18-1 is needed by python3-PyECLib-1.6.0-1.6.x86_64 Add OpenStack Swift Repository for SUSE admin:~ # zypper addrepo -f obs://Cloud:OpenStack:Train/SLE_15_SP1 Train admin:~ # zypper in openstack-swift openstack-swift-account openstack-swift-container openstack-swift-object","title":"2.4.3. Use the swift API to Interact with the RADOS Gateway"},{"location":"linux/SES/linux_ses_demo/#task-1-create-a-swift-subuser","text":"1). In a shell or terminal as the root user (password of linux) on the admin node, create a new subuser: The output will contain the access and secret keys for the s3user and a secret key for the new swift subuser.. admin:~ # radosgw-admin subuser create --uid=s3user --subuser=s3user:swift --access=full { \"user_id\": \"s3user\", \"display_name\": \"S3\", \"email\": \"s3user@example.net\", \"suspended\": 0, \"max_buckets\": 1000, \"subusers\": [ { \"id\": \"s3user:swift\", \"permissions\": \"full-control\" } ], \"keys\": [ { \"user\": \"s3user\", \"access_key\": , \"secret_key\": } ], \"swift_keys\": [ { \"user\": \"s3user:swift\", \"secret_key\": } ], \"caps\": [], \"op_mask\": \"read, write, delete\", \"default_placement\": \"\", \"default_storage_class\": \"\", \"placement_tags\": [], \"bucket_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"user_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"temp_url_keys\": [], \"type\": \"rgw\", \"mfa_ids\": [] } 2). Verify that the subuser has access to at least one bucket and list the buckets with a swift command: swift -A http://mon3.sha.me.corp/auth/1.0 -U s3user:swift -K '{SECRET_KEY_FROM_STEP_1}' list admin:~ # swift -A http://mon3.sha.me.corp/auth/1.0 -U s3user:swift -K '' list S3CMDTEST","title":"Task 1: Create a swift subuser"},{"location":"linux/SES/linux_ses_demo/#task-2-use-the-swift-command-to-access-a-file-created-with-the-s3cmd-tool","text":"1). Since the S3 API and the swift API are accessing the same SUSE Enterprise Storage cluster, and since the RADOS gateway is built to be inter-operable with both, you can use the swift API to retrieve the object which was uploaded to SES via the S3 API: swift -A http://mon3.example.net/auth/1.0 -U s3user:swift -K '{SECRET_KEY_FROM_STEP_1}' download -a An example of the command is listed here: admin:~ # swift -A http://mon3.sha.me.corp/auth/1.0 -U s3user:swift -K '' download -a Although we have taken a shortcut by using the -a option (meaning grab every object this user has access to), it illustrates the tool\u2019s capability. We\u2019ve uploaded the newfile with S3, we\u2019ve retrieved it with swift.","title":"Task 2: Use the swift command to access a file created with the S3cmd tool"},{"location":"linux/SES/linux_ses_demo/#244-create-snapshots-on-ses-using-rbd","text":"In this lab we worked with rbd images. We mapped an rbd image to a Linux device file, then created a filesystem and mounted it. Then we created snapshots to preserve the images data state at a particular time, and rolled it back to demonstrate functionality.","title":"2.4.4. Create Snapshots on SES using RBD"},{"location":"linux/SES/linux_ses_demo/#task-1-create-a-new-pool-for-rbd-images","text":"1). Access https://mon1.pvg.me.corp:8443 or https://10.58.121.186:8443 2). Log in with the following credentials: Username: admin Password: mypassword 3). Click on the Pools tab near the top of the page 4). Click the Create button and use the following in the available fields: Name: rbd-images Pool type: replicated Placement groups: 16 Crush ruleset: replicated_rule Replicted size: 2 Applications: rbd Compression Mode: none 5). Click Create Pool","title":"Task 1: Create a new pool for RBD images"},{"location":"linux/SES/linux_ses_demo/#task-2-create-a-new-rbd-image-in-the-rbd-images-pool","text":"6). Create a new RBD image using the rbd command: admin:~ # rbd create --size 1024 rbd-images/barfoo 7). Verify the new image has been created in the rbd-images pool: The new image named barfoo should be displayed. admin:~ # rbd ls -p rbd-images barfoo","title":"Task 2: Create a new RBD image in the rbd-images pool"},{"location":"linux/SES/linux_ses_demo/#task-3-mount-the-new-image-on-the-admin-node-and-create-a-filesystem","text":"1). As the root user in a shell or terminal on the admin node, map the new rbd image to a block device: admin:~ # rbd map rbd-images/barfoo /dev/rbd0 2). Create a filesystem on the newly mapped device: admin:~ # mkfs.ext4 /dev/rbd0 mke2fs 1.43.8 (1-Jan-2018) Discarding device blocks: done Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: 19da6b86-1989-4834-a365-2f654fcce6f6 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done 3). Mount the image to the /mnt directory: admin:~ # mount /dev/rbd0 /mnt admin:~ # l /mnt total 20 drwxr-xr-x 3 root root 4096 Jan 6 23:48 ./ drwxr-xr-x 1 root root 156 Oct 5 08:53 ../ drwx------ 2 root root 16384 Jan 6 23:48 lost+found/","title":"Task 3: Mount the new image on the admin node and create a filesystem"},{"location":"linux/SES/linux_ses_demo/#task-4-create-a-file-on-the-new-filesystem-and-snapshot-the-rbd-image-and-make-some-additional-changes","text":"1). Change to the /mnt directory and create a simple file: admin:~ # cd /mnt admin:/mnt # echo \"This is some sample text\" > start.txt 2). List the directories contents to see that the start.txt file has been created on the storage cluster. admin:/mnt # ls -l total 20 drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 3). Create a snapshot of what the rbd image contained: Wait for confirmation that the snapshot has been created. It should only take a few seconds. admin:/mnt # rbd snap create rbd-images/barfoo@begin 4). List the rbd snapshots for the rbd-images/barfoo image: You should see the new snap called begin listed. admin:/mnt # rbd snap ls rbd-images/barfoo SNAPID NAME SIZE PROTECTED TIMESTAMP 4 begin 1 GiB Wed Jan 6 23:51:12 2021 5). Add another file to the filesystem: admin:/mnt # echo \"Some more text\" > end.txt 6). List the contents of the /mnt to verify the existence of two files. admin:/mnt # ls -l total 24 -rw-r--r-- 1 root root 15 Jan 6 23:52 end.txt drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 7). Create a second snapshot of the rbd-images/barfoo image: admin:/mnt # rbd snap create rbd-images/barfoo@finish 8). List the rbd snapshots: There should be begin and finish snapshots. admin:/mnt # rbd snap ls rbd-images/barfoo SNAPID NAME SIZE PROTECTED TIMESTAMP 4 begin 1 GiB Wed Jan 6 23:51:12 2021 5 finish 1 GiB Wed Jan 6 23:53:15 2021 9). List the contents of the /mnt directory again and verify the two files. 10). Rollback the data to the begin snapshot: This process will be relatively quick because the size of the image is small and we have very little data on it. admin:/mnt # rbd snap rollback rbd-images/barfoo@begin Rolling back to snapshot: 100% complete...done. 11). Change to the root user\u2019s home directory, then remount the image in order to see that the rbd image has been rolled back: admin:/mnt # cd ~ admin:~ # umount /mnt admin:~ # mount /dev/rbd0 /mnt 12). List the contents of the /mnt directory to verify that only the start.txt file exists on the image. admin:/mnt # ls -l total 20 drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 13). Rollback the data to the finish snapshot: admin:/mnt # rbd snap rollback rbd-images/barfoo@finish Rolling back to snapshot: 100% complete...done. 14). Unmount and remount the image: admin:/mnt # cd ~ admin:~ # umount /mnt admin:~ # mount /dev/rbd0 /mnt 15). List the contents of the /mnt directory to show it has indeed been rolled back and contains the start.txt and end.txt files admin:/mnt # ls -l total 24 -rw-r--r-- 1 root root 15 Jan 6 23:52 end.txt drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 16). Change to the root user\u2019s home directory and unmount the image: admin:/mnt # cd ~ admin:~ # umount /mnt","title":"Task 4: Create a file on the new filesystem and snapshot the rbd image and make some additional changes"},{"location":"linux/SES/linux_ses_demo/#245-create-and-manage-cow-clones-with-rbd","text":"In this lab you will created a new pool and block device image in the pool. You then mapped the block storage to a linux device and took a snapshot. Finally you protected the snapshot from modification. This would be done so the snapshot can be safely used as a parent cow image which can then be cloned to create new virtual machines.","title":"2.4.5. Create and manage COW Clones with rbd"},{"location":"linux/SES/linux_ses_demo/#task-1-create-a-new-pool","text":"1). View the current osds and pools: admin:~ # ceph osd ls 0 1 2 3 4 5 6 7 8 9 10 11 admin:~ # ceph osd pool ls iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log rbd_pool bucket_pool EC_RBD_Pool default.rgw.buckets.index default.rgw.buckets.data rbd-images 2). Create a new pool called cow-pool: admin:~ # ceph osd pool create cow-pool 128 pool 'cow-pool' created 3). List the available pools to view the new pool using either of the following commands: admin:~ # ceph osd pool ls iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log rbd_pool bucket_pool EC_RBD_Pool default.rgw.buckets.index default.rgw.buckets.data rbd-images cow-pool admin:~ # rados lspools iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log rbd_pool bucket_pool EC_RBD_Pool default.rgw.buckets.index default.rgw.buckets.data rbd-images cow-pool Task 2: Create a block device image in a pool 1). Create a format 2 rbd image called cow-base in the cow-pool storage pool with a size of 1GB *Note that the \u2013image-format statement is optional as format 2 is default admin:~ # rbd create -p cow-pool cow-base --size 1024 --image-format 2 2). Check that the image has been created, that the format is 2 and that layering (COW Clones) is supported admin:~ # rbd -p cow-pool list cow-base admin:~ # rbd -p cow-pool info cow-base rbd image 'cow-base': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 269d5b817222aa block_name_prefix: rbd_data.269d5b817222aa format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:12:31 2021 access_timestamp: Thu Jan 7 10:12:31 2021 modify_timestamp: Thu Jan 7 10:12:31 2021 Task 3: Map the block storage image to a Linux host 1). In a shell or terminal as user root open a terminal window. Using the rbd map command, map an rbd device to the block-storage image created above. admin:~ # rbd map -p cow-pool --image cow-base /dev/rbd1 2). View the mapped block devices admin:~ # rbd showmapped id pool namespace image snap device 0 rbd-images barfoo - /dev/rbd0 1 cow-pool cow-base - /dev/rbd1 3). Note the rbd index numbgr (e.g. rbd0, rbd1) associated with the cow-base image: RBD ___1____ 4). View the devices in /dev. Note the device name(s) admin:~ # ls -l /dev/rbd* brw-rw---- 1 root disk 252, 0 Jan 6 23:49 /dev/rbd0 brw-rw---- 1 root disk 252, 16 Jan 7 10:14 /dev/rbd1 /dev/rbd: total 0 drwxr-xr-x 2 root root 60 Jan 7 10:14 cow-pool drwxr-xr-x 2 root root 60 Jan 6 23:48 rbd-images 5). View the block device:(use the device numbgr from step above) admin:~ # fdisk -l /dev/rbd1 Disk /dev/rbd1: 1 GiB, 1073741824 bytes, 2097152 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 4194304 bytes / 4194304 bytes 6). Format the device with an ext4 filesystem: admin:~ # mkfs.ext4 /dev/rbd1 mke2fs 1.43.8 (1-Jan-2018) Discarding device blocks: done Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: 64c9a973-cf31-4239-881f-ec5642bf34e3 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done 7). Mount the block device on the local filesystem: admin:~ # mkdir /mnt/cow-base admin:~ # mount /dev/rbd1 /mnt/cow-base 8). Test the storage access by creating a file: admin:~ # cd /mnt/cow-base admin:/mnt/cow-base # touch base-image-file admin:/mnt/cow-base # ls base-image-file lost+found","title":"Task 1: Create a new pool"},{"location":"linux/SES/linux_ses_demo/#task-4-snapshot-the-rbd-image-and-protect-the-snapshot","text":"1). List the snapshots in the cow-base image: admin:/mnt/cow-base # rbd snap ls cow-pool/cow-base 2). Create a snapshot of the cow-base rbd image which contains the base-image-file file admin:/mnt/cow-base # rbd snap create cow-pool/cow-base@base-snap 3). List the snapshot: admin:/mnt/cow-base # rbd snap ls cow-pool/cow-base SNAPID NAME SIZE PROTECTED TIMESTAMP 4 base-snap 1 GiB Thu Jan 7 10:37:13 2021 4). This snapshot will form the parent snapshot for COW clone images so you will now protected it from modification: admin:/mnt/cow-base # rbd snap protect cow-pool/cow-base@base-snap admin:/mnt/cow-base # rbd snap ls cow-pool/cow-base SNAPID NAME SIZE PROTECTED TIMESTAMP 4 base-snap 1 GiB yes Thu Jan 7 10:37:13 2021 Task 5: Create writable COW clones from the parent snapshot 1). Create a COW clone from the cow-base with the base-snap snapshot as the parent image admin:/mnt/cow-base # rbd clone cow-pool/cow-base@base-snap cow-pool/cow-image1 2). Check the information for the new image admin:/mnt/cow-base # rbd -p cow-pool --image cow-image1 info rbd image 'cow-image1': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a1209678cad4 block_name_prefix: rbd_data.26a1209678cad4 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:38:58 2021 access_timestamp: Thu Jan 7 10:38:58 2021 modify_timestamp: Thu Jan 7 10:38:58 2021 parent: cow-pool/cow-base@base-snap overlap: 1 GiB 3). Note that the image has details of the parent image and overlap 4). Repeat steps 2 & 3 for an additional image called cow-image2 admin:/mnt/cow-base # rbd clone cow-pool/cow-base@base-snap cow-pool/cow-image2 admin:/mnt/cow-base # rbd -p cow-pool --image cow-image2 info rbd image 'cow-image2': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a2fbcec7b8d9 block_name_prefix: rbd_data.26a2fbcec7b8d9 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:47:28 2021 access_timestamp: Thu Jan 7 10:47:28 2021 modify_timestamp: Thu Jan 7 10:47:28 2021 parent: cow-pool/cow-base@base-snap overlap: 1 GiB Task 6: Test that the COW clones are functional 1). Create a new directory and mount the COW clone called cow-image1 Note the rbd device name and use it to mount the file system admin:/mnt # mkdir /mnt/cow-image1 admin:/mnt # rbd map -p cow-pool --image cow-image1 /dev/rbd2 admin:/mnt # l total 4 drwxr-xr-x 1 root root 36 Jan 7 10:54 ./ drwxr-xr-x 1 root root 156 Oct 5 08:53 ../ drwxr-xr-x 3 root root 4096 Jan 7 10:19 cow-base/ drwxr-xr-x 1 root root 0 Jan 7 10:54 cow-image1/ admin:/mnt # ls -l /dev/rbd* brw-rw---- 1 root disk 252, 0 Jan 6 23:49 /dev/rbd0 brw-rw---- 1 root disk 252, 16 Jan 7 10:18 /dev/rbd1 brw-rw---- 1 root disk 252, 32 Jan 7 10:55 /dev/rbd2 /dev/rbd: total 0 drwxr-xr-x 2 root root 80 Jan 7 10:55 cow-pool drwxr-xr-x 2 root root 60 Jan 6 23:48 rbd-images admin:/mnt # mount /dev/rbd2 /mnt/cow-image1 2). Check that the base-image-file which was created in the parent snapshot is present admin:/mnt # cd /mnt/cow-image1 admin:/mnt/cow-image1 # ls base-image-file lost+found 3). Repeat steps 1 and 2 for cow-image2 admin:/mnt # mkdir /mnt/cow-image2 admin:/mnt # rbd map -p cow-pool --image cow-image2 /dev/rbd3 admin:/mnt # mount /dev/rbd3 /mnt/cow-image2 admin:/mnt # ls ./cow-image2/ base-image-file lost+found --> same file with image1 4). Create a new file in the directory where cow-image1 is mounted admin:/mnt # cd cow-image1 admin:/mnt/cow-image1 # touch additional-file admin:/mnt/cow-image1 # ls additional-file base-image-file lost+found 5). Look in the cow-image2 directory. Although they share the same parent snapshot, you can see that the files contained in each COW image are now different. admin:/mnt # ls ./cow-image2/ base-image-file lost+found","title":"Task 4: Snapshot the rbd image and protect the snapshot"},{"location":"linux/SES/linux_ses_demo/#task-7-flatten-a-cow-clone-and-remove-the-parent-image","text":"1). Convert the COW clone called cow-image1 to a standalone rbd image Wait while the flatten process completes. Unlike a clone process this is not instantaneous and can take considerable time. admin:/mnt # rbd flatten cow-pool/cow-image1 Image flatten: 100% complete...done. 2). Check to see that the flatten process has removed the link to the parent snapshot admin:/mnt # rbd -p cow-pool --image cow-image1 info rbd image 'cow-image1': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a1209678cad4 block_name_prefix: rbd_data.26a1209678cad4 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:38:58 2021 access_timestamp: Thu Jan 7 10:38:58 2021 modify_timestamp: Thu Jan 7 10:38:58 2021 admin:/mnt # rbd -p cow-pool --image cow-image2 info rbd image 'cow-image2': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a2fbcec7b8d9 block_name_prefix: rbd_data.26a2fbcec7b8d9 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:47:28 2021 access_timestamp: Thu Jan 7 10:47:28 2021 modify_timestamp: Thu Jan 7 10:47:28 2021 parent: cow-pool/cow-base@base-snap overlap: 1 GiB 3). Unmount the images admin:/mnt # umount /mnt/cow-image1 admin:/mnt # umount /mnt/cow-image2 admin:/mnt # umount /mnt/cow-base","title":"Task 7: Flatten a COW Clone and remove the parent image"},{"location":"linux/SES/linux_ses_demo/#246-configure-iscsi-on-ses","text":"In this lab an iSCSI Target was configured via the iSCSI gateway on our SUSE Enterprise Storage. An image was added to it. An iSCSI initiator then connected to the target, created a filesystem, and mounted it.","title":"2.4.6. Configure iSCSI on SES"},{"location":"linux/SES/linux_ses_demo/#task-1-create-a-new-rbd-image-in-the-iscsi-images-pool","text":"1). Create a new RBD image using the rbd command: admin:~ # rbd create --size 1024 iscsi-images/fooiscsi 2). Verify the new image has been created in the iscsi-images pool: The new image named fooiscsi should be displayed. admin:~ # rbd ls iscsi-images fooiscsi","title":"Task 1: Create a new RBD image in the iscsi-images pool"},{"location":"linux/SES/linux_ses_demo/#task-2-define-a-new-iscsi-target-with-the-ceph-dashboard","text":"1). Access the Ceph Dashboard and log in: https://mon1.pvg.me.corp:8443 or https://10.58.121.186:8443 Username: admin Password: mypassword 2). Once logged in, click on the Block drop-down item near the top. Select iSCSI. 3). With the Overview tab showing for iSCSI, click on the Targets tab near the top. Note: When clicking on the Targets tab, if you see an error that says something about \u201cUnsupported `ceph-iscsi` config version\u2026\u201d, perform the following steps: 1. Close the browser window where the error occurred 2. Restart the mon1 virtual machine. Do this with the following steps: from the Virtual Machine Manager on your lab machine (not in the admin virtual machine), restart the mon1 virtual machine by right-clicking on the mon1 virtual machine > Shut Down > Reboot 3. Wait at least 30 seconds, then from the admin node, open up the browser again and log in to the Ceph Dashboard: https://mon1.pvg.me.corp:8443 or https://10.58.121.186:8443 Username: admin Password: mypassword 4. Continue the lab as directed below by navigating to the Block > iSCSI section, clicking on the Targets tab, and completing the steps below 4). Click Add. Use the following values: Target IQN: Portals: mon2.example.net:172.17.6.132 Images: iscsi-images/fooiscsi ACL authentication: Click Create Target.","title":"Task 2: Define a new iSCSI target with the Ceph Dashboard"},{"location":"linux/SES/linux_ses_demo/#task-3-access-the-new-iscsi-target-from-the-admin-node","text":"1). On the admin node, launch YaST either the ncurses or GUI interface, and select the iSCSI Initiator module: YaST > Network Services > iSCSI Initiator 2). Select the Discovered Targets tab (alt-v) 3). Select Discovery at the bottom of the frame (alt-d) 4). Add the ip address of mon2: 10.58.121.187. Leave the port as the default of 3260. Select Next. 5). Once again on the Discovered Targets tab, the mon2 target should be listed. With the new target highlighted, select Connect (alt-e) at the bottom of the frame. 6). Leave the Startup (in YaST2) or On boot (in YaST) value as manual. Select Next. 7). Select OK to exit the iscsi client configuration module 8). To verify that the iscsi device is now connected, use the lsscsi command to list devices: You should see there is one disk of type RBD connected on a device file similar to the following: admin:~ # lsscsi [0:0:0:0] cd/dvd QEMU QEMU DVD-ROM 1.4. /dev/sr0 [2:0:0:0] disk SUSE RBD 4.0 /dev/sda 9). Create an ext4 filesystem on the connected device file: admin:~ # mkfs.ext4 /dev/sda mke2fs 1.43.8 (1-Jan-2018) Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: e3896f7e-0664-4b14-85db-0f77cb234c43 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done 10). Mount the device to /mnt: admin:~ # mount /dev/sda /mnt 11). Use the mount command to list the connected device: admin:/mnt # mount | grep sda /dev/sda on /mnt type ext4 (rw,relatime,stripe=1024,data=ordered) 12).Change the root user\u2019s home directory and unmount the device: admin:/mnt # cd .. admin:/ # umount /mnt","title":"Task 3: Access the new iSCSI target from the admin node"},{"location":"linux/SES/linux_ses_demo/#247-mount-cephfs-provided-by-suse-enterprise-storage","text":"In this lab a ceph user was configured to mount the ceph filesystem provided by the SUSE Enterprise Cluster. A keyfile was generated, then used in the process.","title":"2.4.7. Mount CephFS Provided by SUSE Enterprise Storage"},{"location":"linux/SES/linux_ses_demo/#task-1-verify-cephfs-configuration-of-the-ses-cluster","text":"1). Cephfs requires two pools for operation: one for data, the other for metadata. Verify that the cluster has two pools for this purpose: admin:~ # ceph fs ls name: cephfs, metadata pool: cephfs_metadata, data pools: [cephfs_data ] Task 2: Create a secret key file for the admin user on the admin node 1). Because cephx authentication is enabled by default on SUSE Enterprise Storage, a secret key will need to be provided to allow access to mount the ceph filesystem. The admin user (identified \u2013 in this case \u2013 on the system as root) on the admin node has a key, but we will need to either provide it on the command line during the mount process (less secure), or put it in a permissions-restricted file and point to the file when mounting (more secure). If we do not specify the key or a file with the key, we will get an error. The following command will return an error: admin:~ # mount -t ceph mon1:6789:/ /mnt 2021-01-07 14:16:36.924 7f45108a9d80 -1 auth: unable to find a keyring on /etc/ceph/ceph.client.guest.keyring,/etc/ceph/ceph.keyring,/etc/ceph/keyring,/etc/ceph/keyring.bin,: (2) No such file or directory mount error 22 = Invalid argument 2). Take secret key value found in the /etc/ceph/ceph.client.admin.keyring file and put it in a new file: admin:~ # cat /etc/ceph/ceph.client.admin.keyring [client.admin] key = caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" 3). Create a new file and paste the secret key value into it: admin:~ # vi /etc/ceph/admin.secret Put the key value into the file and save it. 4). Change the permissions of the file to be read only by the user: admin:~ # ls -l /etc/ceph/admin.secret -r-------- 1 root root 41 Jan 5 20:05 /etc/ceph/admin.secret","title":"Task 1: Verify cephfs configuration of the SES cluster"},{"location":"linux/SES/linux_ses_demo/#task-3-mount-the-ceph-filesystem-on-the-admin-node","text":"1). Now that the keyfile is created, we can mount the filesystem: admin:~ # mount -t ceph mon1:6789:/ /mnt -o name=admin,secretfile=/etc/ceph/admin.secret admin:~ # ls -l /mnt total 0 2). Verify that the mount shows as expected: admin:~ # mount | grep ceph 10.58.121.186:6789:/ on /mnt type ceph (rw,relatime,name=admin,secret=,acl) 3). Change to the root user\u2019s home directory and unmount the filesystem: admin:~ # cd ~ admin:~ # umount /mnt","title":"Task 3: Mount the ceph filesystem on the admin node"},{"location":"linux/SES/linux_ses_demo/#248-export-an-nfs-share-from-ses-with-nfs-ganesha","text":"","title":"2.4.8. Export an NFS Share from SES with NFS Ganesha"},{"location":"linux/SES/linux_ses_demo/#task-0-install-and-configure-ganesha-ganesha-config-location-is-not-configured-please-set-the-ganesha_rados_pool_namespace-setting","text":"admin:~ # zypper in nfs-ganesha admin:/etc/ganesha # cat ganesha.conf NFSv4 { RecoveryBackend = 'rados_cluster'; #RecoveryBackend = 'rados_ng'; } RADOS_URLS { ceph_conf = '/etc/ceph/ceph.conf'; userid = \"admin\"; watch_url = \"rados://data/ganesha-export-index/conf-nfs1\"; } RADOS_KV { pool = \"metadata\"; namespace = \"ganesha-grace\"; nodeid = \"nfs1\"; } %url rados://data/ganesha-export-index/conf-nfs1 admin:/etc/ganesha # ganesha-rados-grace -p metadata -n ganesha-grace add nfs1 nfs2 nfs3 admin:/etc/ganesha # ganesha-rados-grace -p metadata -n ganesha-grace cur=1 rec=0 ====================================================== nfs1 E nfs2 E nfs3 E http://images.45drives.com/ceph/cephfs/nfs-ganesha-ceph.conf","title":"Task 0: Install and configure Ganesha (Ganesha config location is not configured. Please set the GANESHA_RADOS_POOL_NAMESPACE setting.)"},{"location":"linux/SES/linux_ses_demo/#task-1-create-an-nfs-export-using-the-ceph-dashboard","text":"1). In a browser, navigate to a monitor to access the Ceph Dashboard and log in: https://10.58.121.186:8443/ Username: admin Password: mypassword 2). Click on the NFS tab near the top of the page 3). Click on the green Add button 4). Click on the Add daemon button to the right and select mon1 5). Complete the configuration with the following values: Storage Backend: Object Gateway Object Storage User: s3user Path: S3CMDTEST NFS Protocol: NFSv3 and NFSv4 checked NFS Tag: Pseudo: /S3BKT Access Type: RW Squash: root_squash Transport Protocol: UDP and TCP checked Clients: Click Submit","title":"Task 1: Create an NFS export using the Ceph Dashboard"},{"location":"linux/SES/linux_ses_demo/#task-2-mount-the-nfs-export-on-the-admin-node","text":"1). As the root user on the admin node, query the NFS Ganesha gateway node to see what mounts are available: showmount -e mon1 You should see something similar to the following: Export list for mon1: S3CMDTEST (everyone) 2). Mount the available nfs share to the /mnt directory on the admin server: mount -t nfs mon1:/S3BKT /mnt 3). List the nfs mount: mount | grep mnt Note the type listed as nfs4 4). Change to the root user\u2019s home directory and unmount the export: cd umount /mnt","title":"Task 2: Mount the NFS export on the admin node"},{"location":"linux/SES/linux_ses_demo/#249-configure-and-mount-cifs","text":"In this lab the Samba gateway was configured. A keyring for the Samba gateway was created, the Samba service was modified, and a user created to allow CIFS access to the SES cluster.","title":"2.4.9. Configure and Mount CIFS"},{"location":"linux/SES/linux_ses_demo/#task-1-prepare-the-cephfs-share-for-cifs","text":"1). In order for CIFS to work in our SES environment, a valid CephFS share must be available. The CephFS lab previously done in this workbook is sufficient. Using the same configuration that we used previously, mount the CephFS share and give permissions to all users at the root of the share: admin:~ # mount -t ceph mon1:6789:/ /mnt -o name=admin,secretfile=/etc/ceph/admin.secret admin:~ # chmod 777 /mnt admin:~ # l /mnt total 0 drwxrwxrwx 2 root root 0 Oct 5 14:30 ./ drwxr-xr-x 1 root root 156 Oct 5 08:53 ../ admin:~ # umount /mnt","title":"Task 1: Prepare the CephFS share for CIFS"},{"location":"linux/SES/linux_ses_demo/#task-2-create-a-samba-gateway-specific-keyring-on-the-ceph-admin-node-and-copy-it-to-the-samba-gateway-node","text":"1). A new keyring will be needed for the Samba gateway to allow access to the Ceph cluster. As root, perform the following: admin:~ # ceph auth get-or-create client.samba.gw mon 'allow r' osd 'allow *' mds 'allow *' -o ceph.client.samba.gw.keyring 2). Copy the new keyring to the Samba gateway node: admin:~ # scp ceph.client.samba.gw.keyring mon1:/etc/ceph/ ceph.client.samba.gw.keyring admin:~ # ssh mon1 Last login: Thu Jan 7 14:35:58 2021 from 10.58.121.181 mon1:~ # ls -l /etc/ceph/ total 12 -rw-r--r-- 1 root root 66 Jan 7 15:15 ceph.client.samba.gw.keyring -rw-r--r-- 1 root root 1095 Jan 5 22:44 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap","title":"Task 2: Create a Samba gateway specific keyring on the Ceph admin node and copy it to the Samba gateway node"},{"location":"linux/SES/linux_ses_demo/#task-3-configure-samba-on-the-samba-gateway-node","text":"1). The /etc/samba/smb.conf file will need to be edited to allow CIFS access to the storage cluster. On the mon1 node, replace all of the contents of the file with the following: admin:~ # ssh mon1 mon1:~ # vi /etc/samba/smb.conf mon1:/etc/samba # cat smb.conf [global] netbios name = SAMBA-GW clustering = no idmap config * : backend = tdb2 passdb backend = tdbsam # disable print server load printers = no smbd: backgroundqueue = no [ceph-smb] path = / vfs objects = ceph ceph: config_file = /etc/ceph/ceph.conf ceph: user_id = samba.gw read only = no oplocks = no kernel share modes = no 2). Create a smb user on the mon1 node named joesmb with a password of mypassword: mon1:/etc/samba # useradd joesmb mon1:/etc/samba # passwd joesmb ---> 123 Add joesmb to the smb password database with a password of mypassword: mon1:/etc/samba # smbpasswd -a joesmb New SMB password: ---> 123 Retype new SMB password: ---> 123 Added user joesmb. 3). Start and enable the smb and nmb daemons on mon1: mon1:/etc/samba # systemctl start smb nmb mon1:/etc/samba # systemctl enable smb nmb Created symlink /etc/systemd/system/multi-user.target.wants/smb.service \u2192 /usr/lib/systemd/system/smb.service. Created symlink /etc/systemd/system/multi-user.target.wants/nmb.service \u2192 /usr/lib/systemd/system/nmb.service. 4). Unmount the filesystem: mon1:~ # umount /mnt umount: /mnt: not mounted.","title":"Task 3: Configure Samba on the Samba gateway node"},{"location":"linux/SES/linux_ses_demo/#task-4-connect-a-client-to-the-samba-gateway","text":"1). On the admin node, verify that the Samba gateway is sharing via CIFS. The password is 123 admin:~ # smbclient -U joesmb -L //mon1 Enter WORKGROUP\\joesmb's password: ---> 123 Sharename Type Comment --------- ---- ------- ceph-smb Disk IPC$ IPC IPC Service (Samba 4.9.5-git.373.26895a83dbf3.44.1-SUSE-oS15.0-x86_64) Reconnecting with SMB1 for workgroup listing. Server Comment --------- ------- Workgroup Master --------- ------- GLOBAL CNPVGVSYB900 WORKGROUP SAMBA-GW 2). Connect to the ceph-smb share as joesmb. The password is 123 admin:~ # smbclient -U joesmb //mon1/ceph-smb Enter WORKGROUP\\joesmb's password: ---> 123 tree connect failed: NT_STATUS_BAD_NETWORK_NAME You should see output similar to the following: Try \u201chelp\u201d to get a list of possible commands. smb: \\>","title":"Task 4: Connect a client to the Samba gateway"},{"location":"linux/SES/linux_ses_memo/","text":"SUSE Enterprise Storage Foundation \u00b6 Ceph\u2019s RADOS \u00b6 Everything in Ceph is stored in the RADOS cluster as Objects. Ceph\u2019s RADOS: Reliable Autonomous Distributed Object Store Ceph\u2019s RADOS is composed of storage devices represented as: Raw storage device with LVM (BlueStore) Standard filesystem (FileStore) The Object Storage Daemon (OSD) integrates each disk device as part of the RADOS cluster. Ceph architecture \u00b6 Ceph is made of two groups of core components The RADOS cluster Provides the clustered object storage Native Object Access methods Gateways Access to the object store via standard protocols librados Direct access to the object store using a native API Examples: iSCSI Gateway (block) -- IGW - iSCSI is a storage area network (SAN) protocol. Exports RADOS Block Device (--RBD) (images as iSCSI disks). iSCSI access to RDB images. lrbd is no longer used in SES6. RADOS Gateway (object) -- RGW Is an object storage interface built on top of librados CephFS (file) A MetaData Service (MDS) is required. Direct access to RADOS (no LIBRADOS layer) Traditional filesystem interface. NFS Ganesha (object, file) Provides NFS exports to: RGW buckets for access the object store The CephFS filesystem Client access the storage services of the cluster via Gateways and Librados The librados API allows interaction with the following daemons: The Ceph Monitor, which maintains a master copy of the cluster map The Ceph OSD Daemon (OSD), which stores data as objects on a storage node. Enhanced SES Architecture Diagram \u00b6 Object Storage \u00b6 The state of the art of distributed SDS storage Unstructured, to better accommodate large files and large quantities of files For large files and large quantities of files, it performs far better than other storage mechanisms Agile, scalable, extensible, and very customizable Invisible to the end-user, ideal for backends Perfect for systemic, application-based use cases. Not necessarily perfect for direct Human use Through associated metadata, ideal for computational analytics And CRUSH takes full advantage of this (CRUSH = Controllable Replication Under Scalable Hashing) Ceph Object Storage supports two interfaces: S3-compatible Swift-compatible Object-based storage has become the standard backend storage mechanism for nearly all modern Enterprise Storage Solutions. Ceph OSDs (Object Storage Daemon) \u00b6 A Ceph OSD (object storage daemon, ceph-osd) stores data, handles data replication, recovery, rebalancing, and provides some monitoring information to Ceph Monitors and Managers by checking other Ceph OSD Daemons for a heartbeat. The Ceph Storage Cluster receives data from Ceph Clients. Clients (dedicated access points, e.g., gateway) could be a Ceph Block Device, Ceph Object Storage, the Ceph Filesystem or a custom implementation using librados. The client requests the cluster status from a monitor node The client uses the status information to identify the location of objects in the cluster The client accesses the objects directly via the OSD node The OSD then stores the data as objects. Each object corresponds to a file in a filesystem which is stored on an OSD. The OSD Daemons take care of the reads and writes on the storage disks. When OSDs are deployed in SES5 the default is to use BlueStore which uses the raw disk and does not require a linux file system to be placed on the disk before it can be used. OSD Daemons store all data as objects in a flat namespace, i.e. no hierarchy of directories. At least 3 Ceph OSDs are normally required for redundancy and high availability. Ceph Mons (Monitor Servers) \u00b6 A Ceph Monitor (ceph-mon) maintains maps of the cluster state, including Monitor Map Manager Map OSD Map PG Map CRUSH Map Epoch These maps are critical cluster state required for Ceph daemons to coordinate with each other. Monitors are also responsible for managing authentication between daemons and clients. At least 3 monitors are normally required for redundancy and high availability. An odd number of MONs is required (Paxos requires). Typically 5 is sufficient for mid or large size cluster. Paxos is an algorithm used for cluster durability. Leader MON expects 50% quality to create quorum. Lowest IP address becomes leader. After new leader selected, all MONs polled for epoch. Leader Mon provides lease to non-leader MONs. MONs are NOT in the data path. They merely serve maps to clients so that the client can go directly to the appropriate OSD storage daemon. Monitor nodes MONs do not serve objects to clients Ceph MGRs (Manager Daemon) \u00b6 A Ceph Manager daemon (ceph-mgr) is responsible for keeping track of runtime metrics and the current state of the Ceph cluster, including storage utilization current performance metrics system load The Ceph Manager daemons also host python-based plugins to manage and expose Ceph cluster information, including a web-based dashboard and REST API. At least two managers are normally required for high availability. MON/MGR daemons are required to run on the same node in SES Ceph MDS (Metadata) \u00b6 A Ceph Metadata Server (MDS, ceph-mds) stores metadata on behalf of the Ceph Filesystem. Ceph Metadata Servers allow POSIX file system users to execute basic commands, for example ls -al without placing an large load on the Ceph Storage Cluster. Ceph Admin Node \u00b6 The Admin node fills the \u201cmaster\u201d and \u201cadmin\u201d roles for DeepSea. Salt is central to SES. SES\u2019s deployment and life-cycle management tool. The Admin node keeps master Ceph authentication keys. Prometheus and Grafana provide cluster monitoring and data graphs Ceph Dashboard \u00b6 Runs as a Ceph Manager module; runs via the MON/MGR node. Client Access \u00b6 Object Storage (RADOSGW or RGW) Block Storage (RDB). RBD is built on top of librados. CephFS iSCSI Gateway NFS Ganesha SMB/CIFS Native protocols via librados Objects in Ceph \u00b6 Everything stored in the Ceph cluster is an object. Default object size is 4MB. Each object has a unique ID. ID is unique across the entire cluster. Objects have associated metadata, in Key: Value pairs. In Ceph we use Storage Pools to organize or arrange our objects. Pools are logical partitions to manage objects Parameters to manage Pools Number of data replicas (Replica pools), or configuration of Erasure Code (size) (Erasure Code pools) Erasure Code is an alternative to Replication SIZE for Erasure Coding is K+M K = Data chunks, M = \u201cParity\u201d chunks EC reduces the hit to raw storage capacity EC incurs a greater hit to CPU on the OSDs as a tradeoff Placement Groups (PG) PG is used to manage objects within a pool. PGs are associated with OSDs for data placement PGs are a central feature of CRUSH that help to provide data durability by way of distribution No PG is owned by an OSD. (And an OSD is not owned by a PG.) PGs are just randomly assigned by CRUSH through all of the OSDs to spread the distribution of data Locating data among PGs is all handled economically, deterministically by way of CRUSH calculations PGs are subdivisions of pools Number of PGs = (Number of OSDs * 100) / Size (Size = either num of replicas, or K+M) The final PG number must be a power of 2 The default number of PGs for a new pool is 8 (it's too small for enterprise solution) In general, PG and PGP numbers should be the same pg_num is the number of placement groups for the pool (placement group, \u5b58\u50a8\u6c60\u7684\u76ee\u5f55\u4e2a\u6570 ) pgp_num is the number of placement groups that will be considered for placement (placement group for placement purpose, pg\u53ef\u7528\u7684osd\u6392\u5217\u7ec4\u5408\u6570\u91cf) \u4ec5\u589e\u5927pg_num\uff1a \u56e0\u4e3apgp_num\u6ca1\u53d8\uff0cpg\u7684osd\u7ec4\u5408\u4ecd\u53ea\u80fd\u4ece\u5f53\u524dpgp_num\u79cd\u7ec4\u5408\u91cc\u9762\u6311\u9009\uff0c\u5bfc\u81f4\u65b0\u589e\u7684pg\u548c\u65e7pg\u4f1a\u6709\u91cd\u590d\u7684osd\u7ec4\u5408\uff0c\u8be5\u73b0\u8c61\u79f0\u4e4b\u4e3a\u5206\u88c2\uff1b\u6b64\u65f6pg\u548cosd\u7684\u6620\u5c04\u6ca1\u6709\u53d8\uff1b \u7ee7\u7eed\u589e\u5927pgp_num\uff0c\u4f7f\u5176\u7b49\u4e8epg_num\uff1a \u65e7pg\u6ca1\u6709\u53d8\u5316\uff0c\u4f46\u65b0\u589epg\u7684osd\u7ec4\u5408\u53d1\u751f\u53d8\u5316\uff0c\u5373\u5f00\u59cb\u91cd\u65b0\u5206\u5e03 Placement Group (PG) \u5f52\u7f6e\u7ec4\u72b6\u6001 Creating \u521b\u5efa\u5b58\u50a8\u6c60\u65f6\uff0c\u5b83\u4f1a\u521b\u5efa\u6307\u5b9a\u6570\u91cf\u7684\u5f52\u7f6e\u7ec4\u3002 ceph \u5728\u521b\u5efa\u4e00\u6216\u591a\u4e2a\u5f52\u7f6e\u7ec4\u65f6\u4f1a\u663e\u793a creating\u3002 \u521b\u5efa\u5b8c\u540e\uff0c\u5728\u5176\u5f52\u7f6e\u7ec4\u7684 Acting Set \u91cc\u7684 OSD \u5c06\u5efa\u7acb\u4e92\u8054\u3002 \u4e00\u65e6\u4e92\u8054\u5b8c\u6210\uff0c\u5f52\u7f6e\u7ec4\u72b6\u6001\u5e94\u8be5\u53d8\u4e3a active+clean\uff0c\u610f\u601d\u662fceph \u5ba2\u6237\u7aef\u53ef\u4ee5\u5411\u5f52\u7f6e\u7ec4\u5199\u5165\u6570\u636e\u4e86\u3002 peering ceph \u4e3a\u5f52\u7f6e\u7ec4\u5efa\u7acb\u4e92\u8054\u65f6\uff0c\u4f1a\u8ba9\u5b58\u50a8\u5f52\u7f6e\u7ec4\u526f\u672c\u7684 OSD \u4e4b\u95f4\u5c31\u5176\u4e2d\u7684\u5bf9\u8c61\u548c\u5143\u6570\u636e\u72b6\u6001\u8fbe\u6210\u4e00\u81f4\u3002 ceph \u5b8c\u6210\u4e86\u4e92\u8054\uff0c\u4e5f\u5c31\u610f\u5473\u7740\u5b58\u50a8\u7740\u5f52\u7f6e\u7ec4\u7684 OSD \u5c31\u5176\u5f53\u524d\u72b6\u6001\u8fbe\u6210\u4e86\u4e00\u81f4\u3002 \u7136\u800c\uff0c\u4e92\u8054\u8fc7\u7a0b\u7684\u5b8c\u6210\u5e76\u4e0d\u80fd\u8868\u660e\u5404\u526f\u672c\u90fd\u6709\u4e86\u6570\u636e\u7684\u6700\u65b0\u7248\u672c\u3002 active ceph \u5b8c\u6210\u4e92\u8054\u8fdb\u7a0b\u540e,\u4e00\u5f52\u7f6e\u7ec4\u5c31\u53ef\u53d8\u4e3a active\u3002 active \u72b6\u6001\u901a\u5e38\u610f\u5473\u7740\u5728\u4e3b\u5f52\u7f6e\u7ec4\u548c\u526f\u672c\u4e2d\u7684\u6570\u636e\u90fd\u53ef\u4ee5\u8bfb\u5199\u3002 clean \u67d0\u4e00\u5f52\u7f6e\u7ec4\u5904\u4e8e clean \u72b6\u6001\u65f6\uff0c\u4e3b OSD \u548c\u526f\u672c OSD \u5df2\u6210\u529f\u4e92\u8054\uff0c\u5e76\u4e14\u6ca1\u6709\u504f\u79bb\u7684\u5f52\u7f6e\u7ec4\u3002 ceph \u5df2\u628a\u5f52\u7f6e\u7ec4\u4e2d\u7684\u5bf9\u8c61\u590d\u5236\u4e86\u89c4\u5b9a\u6b21\u6570\u3002 degraded \u5f53\u5ba2\u6237\u7aef\u5411\u4e3b OSD \u5199\u5165\u6570\u636e\u65f6\uff0c\u7531\u4e3b OSD \u8d1f\u8d23\u628a\u526f\u672c\u5199\u5165\u5176\u4f59\u590d\u5236 OSD\u3002 \u4e3b OSD \u628a\u5bf9\u8c61\u5199\u5165\u590d\u5236 OSD \u540e\uff0c\u5728\u6ca1\u6536\u5230\u6210\u529f\u5b8c\u6210\u7684\u786e\u8ba4\u524d\uff0c\u4e3b OSD \u4f1a\u4e00\u76f4\u505c\u7559\u5728 degraded \u72b6\u6001\u3002 \u5f52\u7f6e\u7ec4\u72b6\u6001\u53ef\u4ee5\u662f active+degraded \u72b6\u6001\uff0c\u539f\u56e0\u5728\u4e8e\u4e00 OSD \u5373\u4f7f\u6ca1\u6240\u6709\u5bf9\u8c61\u4e5f\u53ef\u4ee5\u5904\u4e8e active \u72b6\u6001\u3002 \u5982\u679c\u4e00OSD \u6302\u4e86\uff0cceph \u4f1a\u628a\u76f8\u5173\u7684\u5f52\u7f6e\u7ec4\u90fd\u6807\u8bb0\u4e3a degraded\u3002 \u90a3\u4e2a OSD \u91cd\u751f\u540e\uff0c\u5b83\u4eec\u5fc5\u987b\u91cd\u65b0\u4e92\u8054\u3002 \u7136\u800c\uff0c\u5982\u679c\u5f52\u7f6e\u7ec4\u4ecd\u5904\u4e8e active \u72b6\u6001\uff0c\u5373\u4fbf\u5b83\u5904\u4e8e degraded \u72b6\u6001\uff0c\u5ba2\u6237\u7aef\u8fd8\u53ef\u4ee5\u5411\u5176\u5199\u5165\u65b0\u5bf9\u8c61\u3002 \u5982\u679c\u4e00 OSD \u6302\u4e86\uff0c\u4e14 degraded \u72b6\u6001\u6301\u7eed\uff0cceph \u4f1a\u628a down \u7684 OSD \u6807\u8bb0\u4e3a\u5728\u96c6\u7fa4\u5916(out)\u3001\u5e76\u628a\u90a3\u4e9b down \u6389\u7684 OSD \u4e0a\u7684\u6570\u636e\u91cd\u6620\u5c04\u5230\u5176\u5b83 OSD\u3002 \u4ece\u6807\u8bb0\u4e3a down \u5230 out \u7684\u65f6\u95f4\u95f4\u9694\u7531 mon osd down out interval \u63a7\u5236,\u9ed8\u8ba4\u662f 300 \u79d2\u3002 \u5f52\u7f6e\u7ec4\u4e5f\u4f1a\u88ab\u964d\u7ea7(degraded)\uff0c\u56e0\u4e3a\u5f52\u7f6e\u7ec4\u627e\u4e0d\u5230\u672c\u5e94\u5b58\u5728\u4e8e\u5f52\u7f6e\u7ec4\u4e2d\u7684\u4e00\u6216\u591a\u4e2a\u5bf9\u8c61\uff0c\u8fd9\u65f6\uff0c\u4f60\u4e0d\u80fd\u8bfb\u6216\u5199\u627e\u4e0d\u5230\u7684\u5bf9\u8c61\uff0c\u4f46\u4ecd\u80fd\u8bbf\u95ee\u5176\u5b83\u4f4d\u4e8e\u964d\u7ea7\u5f52\u7f6e\u7ec4\u4e2d\u7684\u5bf9\u8c61\u3002 recovering ceph \u88ab\u8bbe\u8ba1\u4e3a\u53ef\u5bb9\u9519\uff0c\u53ef\u62b5\u5fa1\u4e00\u5b9a\u89c4\u6a21\u7684\u8f6f\u3001\u786c\u4ef6\u95ee\u9898\u3002 \u5f53\u67d0 OSD \u6302\u4e86(down)\u65f6\uff0c\u5176\u5185\u5bb9\u7248\u672c\u4f1a\u843d\u540e\u4e8e\u5f52\u7f6e\u7ec4\u5185\u7684\u5176\u5b83\u526f\u672c\u3002 \u5b83\u91cd\u751f(up)\u65f6\uff0c\u5f52\u7f6e\u7ec4\u5185\u5bb9\u5fc5\u987b\u66f4\u65b0\uff0c\u4ee5\u53cd\u6620\u5f53\u524d\u72b6\u6001\u3002 \u5728\u6b64\u671f\u95f4\uff0cOSD \u5728recovering \u72b6\u6001\u3002 \u4e00\u6b21\u786c\u4ef6\u5931\u8d25\u53ef\u80fd\u7275\u8fde\u591a\u4e2a OSD\u3002\u6bd4\u5982\u4e00\u4e2a\u673a\u67dc\u7684\u7f51\u7edc\u4ea4\u6362\u673a\u5931\u8d25\u4e86\uff0c\u8fd9\u4f1a\u5bfc\u81f4\u591a\u4e2a\u4e3b\u673a\u843d\u540e\u4e8e\u96c6\u7fa4\u7684\u5f53\u524d\u72b6\u6001\uff0c\u95ee\u9898\u89e3\u51b3\u540e\u6bcf\u4e00\u4e2a OSD \u90fd\u5fc5\u987b\u6062\u590d\u3002 ceph \u63d0\u4f9b\u4e86\u5f88\u591a\u9009\u9879\u6765\u5747\u8861\u8d44\u6e90\u7ade\u4e89\uff0c\u5982\u65b0\u670d\u52a1\u8bf7\u6c42\u3001\u6062\u590d\u6570\u636e\u5bf9\u8c61\u548c\u6062\u590d\u5f52\u7f6e\u7ec4\u5230\u5f53\u524d\u72b6\u6001\u3002 osd recovery delay start \u9009\u9879\u5141\u8bb8\u4e00 OSD \u5728\u5f00\u59cb\u6062\u590d\u8fdb\u7a0b\u524d\uff0c\u5148\u91cd\u542f\u3001\u91cd\u5efa\u4e92\u8054\u3001\u751a\u81f3\u5904\u7406\u4e00\u4e9b\u91cd\u653e\u8bf7\u6c42\u3002 osd recovery threads \u9009\u9879\u9650\u5236\u6062\u590d\u8fdb\u7a0b\u7684\u7ebf\u7a0b\u6570\uff0c\u9ed8\u8ba4\u4e3a 1 \u7ebf\u7a0b\u3002 osd recovery thread timeout \u8bbe\u7f6e\u7ebf\u7a0b\u8d85\u65f6\uff0c\u56e0\u4e3a\u591a\u4e2aOSD \u53ef\u80fd\u4ea4\u66ff\u5931\u8d25\u3001\u91cd\u542f\u548c\u91cd\u5efa\u4e92\u8054\u3002 osd recovery max active \u9009\u9879\u9650\u5236\u4e00 OSD \u6700\u591a\u540c\u65f6\u63a5\u53d7\u591a\u5c11\u8bf7\u6c42\uff0c\u4ee5\u9632\u5b83\u538b\u529b\u8fc7\u5927\u800c\u4e0d\u80fd\u6b63\u5e38\u670d\u52a1\u3002 osd recovery max chunk \u9009\u9879\u9650\u5236\u6062\u590d\u6570\u636e\u5757\u5c3a\u5bf8\uff0c\u4ee5\u9632\u7f51\u7edc\u62e5\u585e\u3002 back filling \u6709\u65b0 OSD \u52a0\u5165\u96c6\u7fa4\u65f6\uff0cCRUSH \u4f1a\u628a\u73b0\u6709\u96c6\u7fa4\u5185\u7684\u5f52\u7f6e\u7ec4\u91cd\u5206\u914d\u7ed9\u5b83\u3002 \u5f3a\u5236\u65b0 OSD \u7acb\u5373\u63a5\u53d7\u91cd\u5206\u914d\u7684\u5f52\u7f6e\u7ec4\u4f1a\u4f7f\u4e4b\u8fc7\u8f7d\uff0c\u7528\u5f52\u7f6e\u7ec4\u56de\u586b\u53ef\u4f7f\u8fd9\u4e2a\u8fc7\u7a0b\u5728\u540e\u53f0\u5f00\u59cb\u3002 \u56de\u586b\u5b8c\u6210\u540e\uff0c\u65b0 OSD \u51c6\u5907\u597d\u65f6\u5c31\u53ef\u4ee5\u5bf9\u5916\u670d\u52a1\u4e86\u3002 remapped \u67d0\u4e00\u5f52\u7f6e\u7ec4\u7684 Acting Set \u53d8\u66f4\u65f6\uff0c\u6570\u636e\u8981\u4ece\u65e7\u96c6\u5408\u8fc1\u79fb\u5230\u65b0\u7684\u3002 \u4e3b OSD \u8981\u82b1\u8d39\u4e00\u4e9b\u65f6\u95f4\u624d\u80fd\u63d0\u4f9b\u670d\u52a1\uff0c\u6240\u4ee5\u5b83\u53ef\u4ee5\u8ba9\u8001\u7684\u4e3b OSD \u6301\u7eed\u670d\u52a1\u3001\u76f4\u5230\u5f52\u7f6e\u7ec4\u8fc1\u79fb\u5b8c\u3002 \u6570\u636e\u8fc1\u79fb\u5b8c\u540e,\u4e3b OSD \u4f1a\u6620\u5c04\u5230\u65b0 acting set\u3002 stale \u867d\u7136 ceph \u7528\u5fc3\u8df3\u6765\u4fdd\u8bc1\u4e3b\u673a\u548c\u5b88\u62a4\u8fdb\u7a0b\u5728\u8fd0\u884c\uff0c\u4f46\u662f ceph-osd \u4ecd\u6709\u53ef\u80fd\u8fdb\u5165 stuck \u72b6\u6001\uff0c\u5b83\u4eec\u6ca1\u6709\u6309\u65f6\u62a5\u544a\u5176\u72b6\u6001(\u5982\u7f51\u7edc\u77ac\u65ad)\u3002 \u9ed8\u8ba4OSD \u5b88\u62a4\u8fdb\u7a0b\u6bcf\u534a\u79d2(0.5)\u4f1a\u4e00\u6b21\u62a5\u544a\u5176\u5f52\u7f6e\u7ec4\u3001\u51fa\u6d41\u91cf\u3001\u5f15\u5bfc\u548c\u5931\u8d25\u7edf\u8ba1\u72b6\u6001\uff0c\u6b64\u9891\u7387\u9ad8\u4e8e\u5fc3\u8df3\u9600\u503c\u3002 \u5982\u679c\u4e00\u5f52\u7f6e\u7ec4\u7684\u4e3b OSD \u6240\u5728\u7684 acting set \u6ca1\u80fd\u5411\u76d1\u89c6\u5668\u62a5\u544a\u3001\u6216\u8005\u5176\u5b83\u76d1\u89c6\u5668\u5df2\u7ecf\u62a5\u544a\u4e86\u90a3\u4e2a\u4e3b OSD \u5df2 down\uff0c\u76d1\u89c6\u5668\u4eec\u5c31\u4f1a\u628a\u6b64\u5f52\u7f6e\u7ec4\u6807\u8bb0\u4e3a stale\u3002 \u542f\u52a8\u96c6\u7fa4\u65f6\uff0c\u4f1a\u7ecf\u5e38\u770b\u5230 stale \u72b6\u6001\uff0c\u76f4\u5230\u4e92\u8054\u5b8c\u6210\u3002 \u96c6\u7fa4\u8fd0\u884c\u4e00\u9635\u540e\uff0c\u5982\u679c\u8fd8\u80fd\u770b\u5230\u6709\u5f52\u7f6e\u7ec4\u4f4d\u4e8e stale \u72b6\u6001\uff0c\u5c31\u8bf4\u660e\u90a3\u4e9b\u5f52\u7f6e\u7ec4\u7684\u4e3b OSD \u6302\u4e86(down)\u3001\u6216\u6ca1\u5728\u5411\u76d1\u89c6\u5668\u62a5\u544a\u7edf\u8ba1\u4fe1\u606f\u3002 Each pool has its own autoscaler settings The PG balancer optimizes the placement of PGs across OSD crush-compat mode It's default mode Uses the compat weight-set feature upmap mode. It's perfect mode, which an equal number of PGs on each OSD Use fine-grained control over the PG mapping Snapshots Rulesets to manage CRUSH placement Each pool has a defined CRUSH ruleset A CRUSH ruleset is a definition of how the OSDs organize data This allows configuration of data distribution to be managed per pool A single CRUSH ruleset can be reused by multiple pools A ruleset can take into account: \u9700\u8981\u8003\u8651\u7684\u70b9 physical layout of nodes in the cluster organization of network infrastructure selection of OSDs backed by SSDs versus HDDs, etc Each pool can use either Replication or Erasure Coding Replication is the original, default approach to resiliency Erasure Coded pools have an EC Profile assigned Different than CRUSH rulesets, but similar: define how OSDs organize data The profile defines K, M values; encoding method/plugin; etc CRUSH (Controllable Replication Under Scalable Hashing) \u00b6 CRUSH is a key piece of the Ceph storage solution With the CRUSH algorithm used by Ceph: Data is not centrally stored, it is distributed CRUSH calculates the storage location for each object dynamically No requirement to store a global index of object locations CRUSH Algorithm \u00b6 The CRUSH algorithm deterministically calculates the location of any object in the Ceph RADOS cluster Overhead is low and calculation is performed by each client As no metadata store is required, CRUSH removes the limitations of traditional metadata based management No direct control over the placement of your data in the cluster Higher CPU requirements CRUSH Maps and Rulesets \u00b6 CRUSH Rulesets are the named sets of rules: Combining all of the customizable CRUSH behavior settings Assigned to pool to govern how the pool\u2019s data is distributed in the cluster CRUSH Maps are central to how Ceph distributes data, and maintaining the durability of the data When the cluster is deployed, Ceph creates a simple default ruleset for replicated pools: replicated_rule CRUSH behavior depends on the behaviors and performance of storage devices CRUSH Maps should be crafted to take advantage of those behaviors Rulesets should be used to clearly identify how the devices in your environment should be employed Device Classes exist to indicate performance behavior: hdd, ssd, nvme Ceph OSDs will automatically set the Device Class of a storage device when the OSD is started Working with CRUSH Map Rulesets List the OSDs, which host each OSD belongs to: ceph osd tree ceph osd df tree ceph osd df tree -f json-pretty Find the host of a specific OSD: ceph osd find 8 Show the existing defined rulesets: ceph osd crush rule ls Examine the definition of an existing ruleset: ceph osd crush rule dump There are 3 options for creating a new ruleset: simple replicated erasure Creating new rulesets: ceph osd crush rule create-replicated ceph osd crush rule create-erasure Create a new ruleset using a Device Class: create-replicated Description : The name of the node under which data should be placed. Type : String Example : default (rarely would you need to make this different than \u201cdefault\u201d) or Description : The type of CRUSH node (bucket) across which replicas should be separated. Type : String Example : rack Description : The device class data should be placed on. Type : String Example : ssd CRUSH Weight \u00b6 You may need to move data around New nodes degraded nodes rebalancing View the current CRUSH weights ceph osd crush tree ceph osd df tree Change the weight for an OSD ceph osd crush reweight The important difference between ceph osd reweight and ceph osd crush reweight \"ceph osd crush reweight\" sets the CRUSH weight of the OSD. This weight is an arbitrary value (generally the size of the disk in TB or something) and controls how much data the system tries to allocate to the OSD. \"ceph osd reweight\" sets an override weight on the OSD. This value is in the range 0 to 1, and forces CRUSH to re-place (1-weight) of the data that would otherwise live on this drive. It does not change the weights assigned to the buckets above the OSD, and is a corrective measure in case the normal CRUSH distribution isn\u2019t working out quite right. \"ceph osd reweight\" is temporary. \"ceph osd crush reweight\" is sticky, permanent (until you change it again). Setting a weight of an OSD to 0 is effectively setting the OSD \"out\" - you don\u2019t want it to store data. The Monitor\u2019s Cluster Map contains \u00b6 Monitor Map Unique Cluster ID, details of each Mon node, current epoch, date/time of last change OSD Map Contains the cluster fsid, when the map was created and last modified, a list of pools, replica sizes, PG numbers, a list of OSDs and their status PG Map Contains the PG version, its time stamp, the last OSD map epoch, the full ratios, and details on each placement group such as the PG ID, the Up Set, the Acting Set, the state of the PG (e.g., active + clean), and data usage statistics for each pool MDS Map Contains the current MDS map epoch, references to pool(s) for storing metadata, list of MDS servers, and which metadata servers are up and in CRUSH Map Contains a list of storage devices, the failure domain hierarchy (e.g., device, host, rack, row, room, etc.), and rules for traversing the hierarchy when storing data CRUSH Hierarchy \u00b6 The CRUSH Map includes details of physical & network infrastructure The CRUSH Map hierarchy is defined by a storage architect The default hierarchical list of infrastructure elements: (Hierarchy of CRUSH buckets) OSD host chassis \u5200\u7247\u673a\u7bb1 rack \u673a\u67b6 row pdu \u7535\u6e90\u5206\u914d\u5355\u5143 pod \u6027\u80fd\u4f18\u5316\u7684\u6570\u636e\u4e2d\u5fc3(Performance Optimize Datacenter)\uff0c\u57fa\u4e8e\u6807\u51c6\u5316\u8bbe\u65bd\u7684\u6700\u4f73\u5b9e\u8df5\uff0c\u6bcf\u4e2aPOD\u5185IT\u90e8\u5206\u5305\u542b\u76845000\u53f0\u670d\u52a1\u5668\uff0c\u5206\u5c5e\u5230200\u4e2a\u673a\u67b6\uff0c\u5982\u679c\u4ee5\u6bcf\u53f0\u670d\u52a1\u5668400W\u529f\u7387\u8ba1\u7b97\u7684\u8bdd\uff0c\u6bcf\u4e2a\u673a\u67dc\u9700\u898110KW\u7684\u4f9b\u7535\uff0c\u5373\u6bcf\u4e2aPOD\u7684IT\u8d1f\u8f7d\u5bb9\u91cf\u662f2MW\u3002 room datacenter region root CRUSH is the algorithm and calculation for distributing data through the cluster. CRUSH Map obviously plays a part in how those CRUSH calculations work. CRUSH Map Sections (Six main sections) \u00b6 tunables: adjustments to legacy behavior devices: The list of OSDs (usually no customization needed) \u25cb \"device class\" is meaningful; useful in relation to creating/using CRUSH rulesets \u25cb Standard \"device class\" values are \"hdd.\", \"ssd.\", and \"nvme.\" \u25cb Example: device 7 osd.7 types: types of buckets (usually no customization needed) buckets: the most functional, customizable aspect of the Map \u25cb A bucket typically represents a physical location in the cluster, has a \u201ctype\u201d \u25cb Nodes (containers such as hosts) and leaves (storage devices such as OSDs) rules: define policies of how data should be distributed \u25cb The behind-the-scenes rules that CRUSH follows for data placement \u25cb IMPORTANT: this is NOT the same as the \"ruleset\". In fact, a ruleset is the combined set of all of these six Map sections. choose_args (optional): Rarely used exceptional settings to adjust weights From the documentation: \"choose_args are alternative weights associated with the hierarchy that have been adjusted to optimize data placement. A single choose_args map can be used for the entire cluster, or one can be created for each individual pool.\" Erasure Coding \u00b6 In information theory : an erasure code is a forward error correction (FEC, \u524d\u5411\u7ea0\u9519) code for the binary erasure channel, which transforms a message of k symbols into a longer message (code word) with n symbols such that the original message can be recovered from a subset of the n symbols. The fraction r = k/n is called the code rate The fraction k\u2019/k, where k\u2019 denotes the number of symbols required for recovery, is called reception efficiency Another (easier) way of describing EC: It\u2019s like RAID in Clustered Storage Erasure Coding in SES \u00b6 The default resilience strategy in SES is simple replication * SES Simple replication has overheads, size=3 means 3 times the storage requirements Simplistic EC details: k = number of \u201cdata\u201d chunks, split across \u201ck\u201d number of OSDs m = number of \u201cparity\u201d chunks, split across \u201cm\u201d number of OSDs Ceph calls these \u201ccoding chunks\u201d r (size) = k + m admin:~ # ceph osd crush rule ls replicated_rule Replication vs Erasure Code \u00b6 Replication (default): Use Case: active data Simple and fast Uses more disk space Erasure coding: Use Case: archive data, more static data Calculates recovery data (needs more CPU power) Definable redundancy level Example: K data chunks = 2 , M code chunks = 1 Similar to a replication size of 2 But with only 50% more raw storage consumed Example: for 1GB of effective storage replication pool of size of 2 needs 2GB raw storage erasure coded pool with k=2/m=1 only requires 1.5GB raw storage EC Overwrites \u00b6 Historically, EC only works properly with Objects EC only allowed appends; overwrites were not allowed Works perfectly for objects in buckets but doesn\u2019t work well with Block or CephFS With recent releases of SES, EC can work well with Block and CephFS Facilitated by \u201cEC Overwrites\u201d feature Store data in an EC Pool, and store object metadata in a Replicated Pool Requires a little extra work when defining pools, but worth it ceph osd pool set allow_ec_overwrites true EC Profiles \u00b6 Using Erasure Coding, each Pool is assigned an EC Profile Multiple pools can share a single Profile The profile is just a definition Each Profile has multiple settings The common required settings for all Profiles are K, M EC Profiles must be created before EC Pools can be created Created from the Dashboard or CLI Once an EC Profile is created, you can create a CRUSH Ruleset based on the EC profile Once a pool is created, its EC Profile properties cannot be changed Main profile parameters K: M: stripe_unit - allows you to adjust the size of the data chunk Default size is 4K stripe_unit : size of data striped across devices; default 4K This variable can also be set in the master configuration (osd_erasure_code_stripe_unit) EC plugins - choose your favorite EC algorithm via a plugin jerasure/gf-complete (default, free, open, and very fast) (www.jerasure.org) ISA (Intel library; optimized for modern Intel processors) (only runs on Intel processors) LRC (\u201cLocally Repairable Code\u201d; layers over existing plugins) SHEC (\u201cShingled EC\u201d; trades extra storage for recovery efficiency) CLAY (\u201cCoupled LAYer\u201d; good for reduced network traffic) Creating Erasure Code Profiles and Pools \u00b6 Syntax: ceph osd erasure-code-profile OPTIONS Option Description get - view details of an existing EC profile set - set a profile (create a profile), requires k and m values, with optional values such as ruleset, plugin. Once you create a profile, you can\u2019t change it. ceph osd erasure-code-profile set k= m= [plugin=] [stripe_unit=] ls - list profiles rm - Remove an EC profile ceph osd erasure-code-profile rm Common example (below) The default profile \u2012 2+1=3; data is written over 3 OSDs \u2012 Two data chunks \u2012 One code (parity) chunk \u2012 Uses jerasure plugin with standard Reed/Solomon (reed_sol_van) technique Setting a Custom EC Profile Option: \u2012 Profile name \u2012 K : number of stripes required \u2012 M : number of failed units Example: ceph osd erasure-code-profile set example-profile k=8 m=2 ruleset-failure-domain=host ruleset-failure-domain = crush bucket level for failure admin:/etc/ceph # ceph osd erasure-code-profile \\ set common_profile \\ k=4 \\ m=2 \\ plugin=jerasure \\ technique=reed_sol_van \\ stripe_unit=4K \\ crush-root=default \\ crush-failure-domain=rackcrush-device-class=ssd admin:/etc/ceph # ceph osd erasure-code-profile ls default admin:~ # ceph osd erasure-code-profile get default k=2 m=1 plugin=jerasure technique=reed_sol_van Pools Pools are at the heart of Storage Pools are tied to OSDs Display a list of existing pools: ceph osd pool ls or ceph osd lspools View the statistics and characteristics of pools: ceph osd pool stats ceph osd pool stats ceph osd pool get Show usage and related details of existing pools: rados df or ceph df or ceph df detail All storage revolves around Pools Each pool must be dedicated to a purpose: Object, Block, File Must specify # of Placement Groups and PG Placements Must specify whether using Replication or EC Must specify a CRUSH ruleset Create a Replicated Pool Syntax: ceph osd pool create replicated = number of placement groups for the pool = number of PGs for placement; routinely will be the same as pg_num Always a power of 2 Don\u2019t make the number too small; don\u2019t err on the high side, either Practices For a new pool, the pgp_num will generally (likley) just be the same as the pg_num When increasing the PGs in a pool, you may want to retain the smaller pgp_num to minimize rebalancing, and increase pgp_num later when rebalancing is more convenient If decreasing the PGs in a pool, the pgp_num is adjusted automatically Create an EC Pool (using an EC Profile) Syntax: ceph osd pool create erasure Example: ceph osd pool create EC-pool 128 128 erasure my-ec-profile Pools \u2013 Application Assignment Each Pool must have a stated purpose; application This defines which capabilities the Pool must support The applications are: Block (rbd), Object (rgw), and File (cephfs) There are subtypes of cephfs: i.e. cephfs:data, cephfs:metadata Application assignment happens after creating a pool It\u2019s effortless (and required) to assign an application on a new pool ceph osd pool application enable Changing application assignment after a pool is in use is \u201chard\u201d. Not recommended, only to be done as an expert Pools \u2013 Quotas One of the more desirable features of SDS is to set a maximum usage of a Pool - Quotas Prevent the over-use of a pool Set quotas based on number of objects or number of bytes ceph osd pool set-quota max_objects ceph osd pool set-quota max_bytes Show quota settings ceph osd pool get-quota To remove a quota, set the existing quota setting to 0 There are also application-level quotas For rgw and cephfs (not rbd; images are already limited in size) Pool Quotas vs. Application Quotas. When a pool quota nears its limit, the HEALTH mechanisms will display a \u201cPOOL_NEAR_FULL\u201d warning to the storage administrator. When the quota limit has been exceeded, the HEALTH mechanisms will display a \u201cPOOL_FULL\u201d warning to the storage administrator. Applications (clients) don\u2019t always handle the quotas cleanly. In most cases, once the Pool Quota is exceeded, the application will simply stop writing to the pool, and error messages and behavior at the application are inconsistent (if there are any messages at all). Pools \u2013 Snapshots Take (make) a snapshot of an existing pool ceph osd pool mksnap Remove a snapshot of a pool ceph osd pool rmsnap List pool snapshots rados -p lssnap Rollback the pool to an earlier snapshot rados -p rollback Images and cephfs have their own snapshot facilities. Object and Bucket snapshotting features related to rgw don\u2019t exist. Pools Snapshots versus App Snapshots The two different snapshot features cannot be used at the same time on a pool Either Pool Snapshots, or Application Snapshots; not both. (snap_mode = pool versus snap_mode = selfmanaged) Once you commit to pool snapshots for an RBD pool, you can\u2019t change to using RBD snapshots Pros and Cons of each, depending on your Use Case admin:~ # ceph osd pool ls detail -f json-pretty | grep snap_mode \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", BlueStore \u00b6 BlueStore is the default storage backend in SES Highlighted features: compressing, no double-writes, faster checksums Ceph FileStore Model It is not ideal for a specialized purpose like a highly scalable distributed storage system. Only recommend that XFS be used. Both btrfs and ext4 have known bugs. The FileStore model uses cache from the filesystem (XFS). Memory for cache is managed by filesystem kernel module. Ceph BlueStore Model BlueStore consumes raw block devices. Metadata management with RocksDB. BlueStore employs RocksDB\u2019s key/value database in order to manage internal metadata, such as the mapping from object names to block locations on disk. Full data and metadata checksumming. By default all data and metadata written to BlueStore is protected by one or more checksums. A small specialized filesystem called BlueFS. This provides just enough of a filesystem to allow RocksDB to store its \"key/value files\" to share metadata across all the raw device(s) No data or metadata will be read from disk or returned to the user without being verified. Multi-device metadata tiering. BlueStore allows its internal journal (write-ahead log) to be written to a separate, highspeed device (like an SSD, NVMe, or NVDIMM) to increased performance. Efficient copy-on-write. RBD and CephFS snapshots rely on a copy-on-write clone mechanism that is implemented efficiently in BlueStore. BlueStore is a userspace model that provides its own memory management and cache. No need to clear the storage device cache OSDs help facilitate the performance of caching Default: cache the reads, don\u2019t cache the writes RocksDB\uff1a rocksdb\u662ffacebook\u57fa\u4e8eleveldb\u5f00\u53d1\u7684\u4e00\u6b3ekv\u6570\u636e\u5e93\uff0cBlueStore\u5c06\u5143\u6570\u636e\u5168\u90e8\u5b58\u653e\u81f3RocksDB\u4e2d\uff0c\u8fd9\u4e9b\u5143\u6570\u636e\u5305\u62ec\u5b58\u50a8\u9884\u5199\u5f0f\u65e5\u5fd7\u3001\u6570\u636e\u5bf9\u8c61\u5143\u6570\u636e\u3001Ceph\u7684omap\u6570\u636e\u4fe1\u606f\u3001\u4ee5\u53ca\u5206\u914d\u5668\u7684\u5143\u6570\u636e \u3002 BlueRocksEnv\uff1a \u662fRocksDB\u4e0eBlueFS\u4ea4\u4e92\u7684\u63a5\u53e3\uff1bRocksDB\u63d0\u4f9b\u4e86\u6587\u4ef6\u64cd\u4f5c\u7684\u63a5\u53e3EnvWrapper\uff0c\u7528\u6237\u53ef\u4ee5\u901a\u8fc7\u7ee7\u627f\u5b9e\u73b0\u8be5\u63a5\u53e3\u6765\u81ea\u5b9a\u4e49\u5e95\u5c42\u7684\u8bfb\u5199\u64cd\u4f5c\uff0cBlueRocksEnv\u5c31\u662f\u7ee7\u627f\u81eaEnvWrapper\u5b9e\u73b0\u5bf9BlueFS\u7684\u8bfb\u5199\u3002 BlueFS\uff1a BlueFS\u662fBlueStore\u9488\u5bf9RocksDB\u5f00\u53d1\u7684\u8f7b\u91cf\u7ea7\u6587\u4ef6\u7cfb\u7edf\uff0c\u7528\u4e8e\u5b58\u653eRocksDB\u4ea7\u751f\u7684.sst\u548c.log\u7b49\u6587\u4ef6\u3002 BlockDecive\uff1a BlueStore\u629b\u5f03\u4e86\u4f20\u7edf\u7684ext4\u3001xfs\u6587\u4ef6\u7cfb\u7edf\uff0c\u4f7f\u7528\u76f4\u63a5\u7ba1\u7406\u88f8\u76d8\u7684\u65b9\u5f0f\uff1b BlueStore\u652f\u6301\u540c\u65f6\u4f7f\u7528\u591a\u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u8bbe\u5907\uff0c\u5728\u903b\u8f91\u4e0aBlueStore\u5c06\u5b58\u50a8\u7a7a\u95f4\u5212\u5206\u4e3a\u4e09\u5c42\uff1a\u6162\u901f\uff08Slow\uff09\u7a7a\u95f4\u3001\u9ad8\u901f\uff08DB\uff09\u7a7a\u95f4\u3001\u8d85\u9ad8\u901f\uff08WAL\uff09\u7a7a\u95f4\uff0c\u4e0d\u540c\u7684\u7a7a\u95f4\u53ef\u4ee5\u6307\u5b9a\u4f7f\u7528\u4e0d\u540c\u7684\u8bbe\u5907\u7c7b\u578b\uff0c\u5f53\u7136\u4e5f\u53ef\u4f7f\u7528\u540c\u4e00\u5757\u8bbe\u5907\u3002 Allocator\uff1a\u8d1f\u8d23\u88f8\u8bbe\u5907\u7684\u7a7a\u95f4\u7ba1\u7406\uff0c\u53ea\u5728\u5185\u5b58\u505a\u6807\u8bb0\uff0c\u76ee\u524d\u652f\u6301StupidAllocator\u548cBitmapAllocator\u4e24\u79cd\u5206\u914d\u5668,Stupid\u57fa\u4e8eextent\u7684\u65b9\u5f0f\u5b9e\u73b0 Ceph BlueStore with Mixed Devices BlueStore Cache Parameters \u00b6 Under most circumstances, autotune is best bluestore_cache_autotune Description: Automatically tune the ratios assigned to different bluestore caches while respecting minimum values Type: Boolean Required: Yes Default: True (enabled) Related settings: bluestore_cache_autotune_chunk_size, bluestore_cache_autotune_interval, and others bluestore_cache_size Description: The amount of memory BlueStore will use for its cache. If zero, bluestore_cache_size_hdd or bluestore_cache_size_ssd will be used instead. Type: Integer Required: Yes Default: 0 bluestore_cache_size_hdd Description: The default amount of memory BlueStore will use for its cache when backed by an HDD Type: Integer Required: Yes Default: 1 * 1024 * 1024 * 1024 (1 GB) bluestore_cache_size_ssd Description: The default amount of memory BlueStore will use for its cache when backed by an SSD. Type: Integer Required: Yes Default: 3 * 1024 * 1024 * 1024 (3 GB) bluestore_cache_meta_ratio Description: The ratio of cache devoted to metadata. Type: Floating point Default: .01 bluestore_cache_kv_ratio Description: The ratio of cache devoted to key/value data (rocksdb). Type : Floating point Default: .99 bluestore_cache_kv_max Description : The maximum amount of cache devoted to key/value data (rocksdb). Type : Unsigned Integer Default : 512 * 1024*1024 (512 MB) BlueStore Device Types \u00b6 BlueStore has three types of roles for devices: The DATA role: Required: main device (block symlink) stores all object data. If no other types: \u201cdata\u201d device serves all the other roles The DB role: Optional: DB device (block.db symlink) stores metadata in RocksDB Whatever doesn\u2019t fit will spill back onto the \u201cdata\u201d device The Write Ahead Log (WAL/Journal) role: Optional: WAL device (block.wal symlink) stores the internal journal Can combine all 3 roles into one physical device Or combine DB/WAL onto a single device with the DATA device separate Or all three on seperate devices BlueStore Configuration Recommendations \u00b6 Devote DB and WAL to SSD or NVMe Allocate 64 GB to the RocksDB Allocate 4-6 GB to the WAL Assign the \u201cdata\u201d role to the slower (HDD) devices If combining WAL/DB on one device, use a single partition for both You can use a single SSD/NVMe to store multiple journals Architecture Overview of Object, Block, Filesystem Access \u00b6 Object Storage \u00b6 The state of the art of distributed storage Object storage is the Cloud Storage mechanism of choice Unstructured, to better accommodate large files and large quantities of files Ideal for large media files, like streaming videos, audio Scales really well, large capacities Ceph provides access to the storage via all three major data access methods: Block, Object, and File. For the storage backend, Object Storage is ideal Block Storage \u00b6 Traditional Block Storage: Volumes as a collection of blocks Blocks can be of various sizes, but all the same within a volume Typically a filesystem is installed on top of the volume Hard Drives, CDs, USB sticks, etc The standard disk device mechanism for Unix, Linux, Windows, etc. Ceph presents RADOS as block device (RBD = RADOS Block Device) Ceph calls these block devices \u201cimages\u201d Provides clients with access like a \u201cdisk drive\u201d KVM/QEMU; libvirt; or remote Linux system A native Windows client that can access the Block storage of Ceph directly is in progress RADOS Block Device (RBD) \u00b6 RBD is the RADOS Block Device A specific RBD instance in the cluster is called an \u201cimage\u201d RBD images can be accessed by OSs other than linux librbd provides interface for gateways like iSCSI RBD allows the client to decide what to do with the storage Filesystem type; raw disk, such as for a DB; etc RBD images can accommodate 16Eb file system sizes No matter the size, the storage is distributed durably throughout the cluster Data is striped across the RADOS cluster in object sized chunks 4MB default Provides high performance and durability Notable Benefits Ability to mount with Linux or QEMU KVM clients Thinly provisioned Resizable images Image import/export Image copy or rename Read-only snapshots Revert to snapshots Copy on Write clones Useful for standing up lots of virtual machines with same base configuration High performance due to striping across cluster nodes RBD image definition: Defined storage area presented as a block device to a client RBD Storage File Storage \u00b6 POSIX Filesystem via CephFS File access is a significant use case Home directories Historical comfort with files and directories Ease of managing \u201csmall\u201d stuff broadly, in a distributed system A Use Case that\u2019s growing in popularity: HPC CephFS is fast, scalable, and flexible Fits into many existing paradigms, rather seamlessly In particular: NFS, Samba/CIFS But even better: extending Linux filesystems Requires Metadata Service (MDS) for POSIX capabilities SUSE does NOT support any FUSE clients. Ceph Users and Authentication \u00b6 Ceph Users are generally applications; applications that use the storage cluster The must common user is Admin A ceph admin user and credentials must exist Additional users and associated credentials are useful Each user must have credentials to access the storage cluster The most fundamental form of credentials in Ceph is keys Ceph Users and Keys The admin user has rights to all Ceph resources. Other users can be setup to have a subset of rights There are basically two types of Users (Actors): An individual (a person) An application (like a gateway, or some other kind of system) Most users are of the type client, and are represented as a dotted string, such as: client.admin, or client.steve, or client.swift The root linux user on the Admin node is effectively the Admin Ceph user, since the root user has all privileges to all filesystem objects on the Adminnode, including the ceph.client.admin.keyring. The root user on any of the nodes in the cluster can \u201cimpersonate\u201d all of the Ceph clients. Linux user accounts do not have any affect on the Ceph Users as managed in the dashboard. Take care to keep backups of the /etc/ceph/ directory structure, so that you don\u2019t lose these keys/keyrings. Each user must have a key/keyring, for example: /etc/ceph/ceph.client.admin.keyring on the Admin node /etc/ceph/ceph.client.storage.keyring on a storage node admin:/etc/ceph # cat ceph.client.admin.keyring [client.admin] key = AQD6pHpfAAAAABAAHJvkvLhOKZyQxm9lgnR5Qg== caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" data1:/etc/ceph # cat ceph.client.storage.keyring [client.storage] key = AQD8pHpfAAAAABAAHecCBgBsLIyPrJf+27eXUQ== caps mon = \"allow rw\" Ceph Keys and Keyrings A keyring contains one or more keys Each user can have its own keyring A keyring can contain multiple keys Different clients and users must have their own key, but multiple keys can be joined together in a single keyring Normally a key will be contained in a keyring Core Ceph will only recognize and use keys from keyrings Stand-alone keys are useful for other tools, like clients Ceph Authentication List The Admin node (and client.admin) can list all Users ceph auth list Create a Ceph User A typical user will have read rights to MONs, and read/write rights to a pool (osd) ceph auth get/add/get-or-create xxxxxx Create a User with ceph-authtool Create a keyring ceph-authtool -C /etc/ceph/ceph.client.richard.keyring Create a key, and place it on the keyring ceph-authtool --gen-key -n client.richard --cap osd 'allow rw pool=data' --cap mon 'allow r' /etc/ceph/ceph.client.richard.keyring Now officially tell the cluster about the key (add user to the key) ceph auth add client.richard -i /etc/ceph/ceph.client.richard.keyring Authentication with cephx The mechanism for passing keys around is cephx Authentication for users and daemons Does not provide data encryption, only authentication with keys cephx simply ensures the authenticity of actors So that no man-in-the-middle attacks can occur Other authentication mechanisms are theoretically possible Attempts to integrate LDAP and Kerberos have been made \u2026 but they have not come to full fruition yet Ceph Configuration \u00b6 Historically, the Ceph configuration was kept only in a file on the Admin node: /etc/ceph/ceph.conf, and sync'd to MONs and Storage Nodes SES DeepSea manages the ceph.conf file. Don\u2019t edit it directly; use Salt and DeepSea With Ceph Nautilus, most configuration held as objects in the Monitors using Dashboard or CLI for operation Ceph Configuration Stored in the MONs The MONs keep a configuration database Show all the configuration keys: admin:/etc/ceph # ceph config ls |less Show the configuration settings that have been customized. The dumped output also indicates an EXPERTISE LEVEL The keys also have a \u201cwho\u201d attribute. In below case, \"osd.*\" represents the \"who\", which is getting the general setting for all OSDs Ceph Configuration Settings Show configuration settings that have been customized: admin:/etc/ceph # ceph config dump WHO MASK LEVEL OPTION VALUE RO mgr advanced mgr/dashboard/GRAFANA_API_URL https://mon1.pvgl.sap.corp:3000 * mgr advanced mgr/dashboard/RGW_API_ACCESS_KEY M11I3JGQHAQM94CS910K * mgr advanced mgr/dashboard/RGW_API_HOST mon3.pvgl.sap.corp * mgr advanced mgr/dashboard/RGW_API_PORT 80 * mgr advanced mgr/dashboard/RGW_API_SECRET_KEY YWyRc3mayEPiOEUzQ2o76KePSKmVKN4fIWxgqTt6 * mgr advanced mgr/dashboard/RGW_API_USER_ID admin * mgr advanced mgr/dashboard/ssl_server_port 8443 admin:/etc/ceph # ceph config get osd.* osd_max_object_size 134217728 admin:/etc/ceph # ceph config show osd.0 \u2026\u2026 admin:/etc/ceph # ceph config show osd.11 (4 data nodes, 3 osds in each node) \u25cb Each of the configuration settings have default values ceph config show-with-defaults osd.2 | less \u25cb Ceph keeps a log of configuration changes admin:/etc/ceph # ceph config log --- 8 --- 2020-10-05 14:31:51.425902 --- + mgr/mgr/dashboard/RGW_API_USER_ID = admin --- 7 --- 2020-10-05 14:31:50.418622 --- + mgr/mgr/dashboard/RGW_API_HOST = mon3.pvgl.sap.corp --- 6 --- 2020-10-05 14:31:49.398448 --- + mgr/mgr/dashboard/RGW_API_PORT = 80 --- 5 --- 2020-10-05 14:31:48.403965 --- + mgr/mgr/dashboard/RGW_API_SECRET_KEY = YWyRc3mayEPiOEUzQ2o76KePSKmVKN4fIWxgqTt6 --- 4 --- 2020-10-05 14:31:46.905701 --- + mgr/mgr/dashboard/RGW_API_ACCESS_KEY = M11I3JGQHAQM94CS910K --- 3 --- 2020-10-05 13:15:29.530355 --- + mgr/mgr/dashboard/GRAFANA_API_URL = https://mon1.pvgl.sap.corp:3000 --- 2 --- 2020-10-05 13:15:14.349623 --- + mgr/mgr/dashboard/ssl_server_port = 8443 --- 1 --- 2020-10-05 13:13:55.637896 --- Health \u00b6 Show status admin:/etc/ceph # ceph status cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 6w) mgr: mon1(active, since 13d) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 9w), 12 in (since 9w) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 208 pgs objects: 246 objects, 4.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 208 active+clean io: client: 11 KiB/s rd, 0 B/s wr, 11 op/s rd, 6 op/s wr admin:/etc/ceph # ceph health HEALTH_OK admin:/etc/ceph # ceph health detail HEALTH_OK admin:/etc/ceph # ceph mon stat e1: 3 mons at {mon1=[v2:10.58.121.186:3300/0,v1:10.58.121.186:6789/0],mon2=[v2:10.58.121.187:3300/0,v1:10.58.121.187:6789/0],mon3=[v2:10.58.121.188:3300/0v1:10.58.121.188:6789/0]}, election epoch 22, leader 0 mon1, quorum 0,1,2 mon1,mon2,mon3 admin:/etc/ceph # ceph osd stat 12 osds: 12 up (since 9w), 12 in (since 9w); epoch: e1375 admin:/etc/ceph # ceph pg stat 208 pgs: 208 active+clean; 4.7 KiB data, 2.0 GiB used, 82 GiB / 96 GiB avail; 1.2 KiB/s rd, 1 op/s Watch status -w, --watch : Watch live cluster changes --watch-debug : Watch debug events --watch-info : Watch info events --watch-sec : Watch security events --watch-warn : Watch warning events --watch-error : Watch error Scrub and Deep-Scrub \u00b6 \"Scrub\" is the process of doing a data consistency check Basically like running fsck on the cluster In Replicas: compare object metadata among replicas In EC: verify \u201ccode\u201d chunks Manual scrubbing can be done per OSD or per PG. \"osd scrub\" is just a collaborative wrapper of \"pg scrub\". ceph osd scrub osd.11 ceph pg scrub 3.33 \"scrub\" is a light process, daily Checks object size and attributes \"deep-scrub\" is a more thorough process, weekly Reads all data and checks the checksums Scrub \u2013 Manual vs Automatic You can let Ceph just do the default Run scrub daily, run deep-scrub weekly Ceph pays attention to usage and backs off when necessary You can change the defaults for both scrub and deepscrub, examples: osd_scrub_begin_week_day=6 (Saturday) osd_scrub_end_week_day=7 (Sunday) You can manually run scrubbings at any time if you suspect it\u2019s wanted or needed Manual scrubbings are not common Adjustments to Scrub Settings For most circumstances the default behavior of Scrub is adequate See current Scrub configuration settings: ceph config ls | grep osd_scrub ceph config ls | grep osd_deep_scrub ceph config get osd.* osd_scrub_begin_hour Change the settings immediately in the MON DB ceph config set osd.* osd_scrub_begin_hour 23 ceph config set osd.* osd_scrub_end_hour 5 Adjust Settings in ceph.conf with DeepSea To permanently change settings in ceph.conf This is the \u201cold\u201d way, but is still valid Remember that ceph.conf is controlled by DeepSea Add changes to /srv/salt/ceph/configuration/files/ceph.conf.d/global.conf Run the following DeepSea (Salt) commands: salt admin* state.apply ceph.configuration.create salt \\* state.apply ceph.configuration Wait for services/servers to be restarted, or tell Ceph to assimilate the ceph.conf settings now ceph config assimilate-conf -i /etc/ceph/ceph.conf Repair \u00b6 Problems Found by Scrubbing * If data (in an OSD or PG) becomes inconsistent, it will need to be repaired. You can configure scrubbing to automatically repair errors * osd_scrub_auto_repair=True * osd_scrub_auto_repair_num_errors=5 * Manually repair when appropriate * ceph osd repair osd.11 * ceph pg repair 3.33 Ceph Manager Modules \u00b6 Manager Modules help to extend the capabilities of Ceph List of Modules Supported in SES Balancer (always on) rash (always on) Dashboard DeepSea iostat Orchestrator (always on) progress (always on, tech preview) Prometheus RESTful rbd_support (always on) status (always on) telemetry volume (always on) Zabbix (plugin only, not the required agent) Enabling Manager Modules Show a list of Manager Modules ceph mgr module ls | less The output is quite long; best to pipe it through less The top of the output shows those modules that have been enabled The exhaustive output also displays the \u201cAPI\u201d of each module Manager modules are quite easy to enable and disable ceph mgr module enable ceph mgr module disable Show list of services that are active from the Modules ceph mgr services Module Capabilities Each module has its own settings, configuration Once the module is enabled, the ceph command accepts commands for the module No need to run the command as ceph mgr ... Examples: ceph crash stat ceph telemetry show Setting parameters (key/value pairs) of Modules ceph config set mgr mgr/telemetry/contact 'JD ' ceph config set mgr mgr/telemetry/description 'Training Cluster' Ceph Tell \u00b6 Tell commands are actually directed to the target service by way of the MONs ceph tell is a tool to tell a ceph daemon to perform a task \u2026 change a setting \u2026 execute a subroutine The target of ceph tell can be a single daemon or a collection of daemons All MONs: ceph tell mon.* injectargs '--mon-pg-warn-max-per-osd 4096' A specific OSD: ceph tell osd.9 bench ceph tell is the most common way to change logging for troubleshooting ceph tell . injectargs '--debug- ' ceph tell osd.7 injectargs '--debug-osd 20' ceph tell osd.7 config set debug_osd 20 A \u201c/\u201d allows you to change both the file log and memory log settings simultaneously ceph tell mon.3 injectargs '--debug-mon 0/10' (The first is the file parameter, the second is the memory parameter) Since logging can fill space, important to restore settings after investigating ceph tell mon.3 injectargs '--debug-mon 1/5' ceph tell sends its instructions via the Monitors. So what if the MONs are having problems? To avoid running commands through the MONs, go directly to thenode running the daemon ssh storage1 ceph daemon osd.29 config show ceph daemon osd.29 config set debug_osd 0/20 Use with great care Ceph Dashboard \u00b6 What's Ceph Dashboard SES WEB-based Management Interface A Ceph MGR module, built-in to Ceph The open source \"port\" of openATTIC to Ceph. Technically it\u2019s not a port of openATTIC. SUSE and Ceph Community worked on implementing the openATTIC capabilities directly within Ceph Role-based and Multi-User Management of the SES cluster Create, manage, and monitor Pools, RBDs Manage users, access keys, quotas and buckets of RGW Manage NFS exports, iSCSI targets and portals, CephFS View cluster nodes/roles, monitor performance metrics Manage Ceph settings/configuration Reduces the need to understand complex Ceph commands The dashboard is stateless, it will reflect any changes to the Ceph cluster, Highlighted Enterprise Behavior via Ceph Dashboard Uses SSL/TLS By default will use a CA and certificate created by DeepSea or provide your own CA and certificate Can run without SSL/TLS (not recommended) Multi-User and Role Management Variety of mappings, i.e.: read, create, update, delete Single Sign-On, complying with SAML 2.0 Single Sign-On, complying with SAML 2.0 Auditing on the backend, to monitor specific user activity Internationalization (I18N), with a variety of language translations Ceph Dashboard Architecture Backend is based on CherryPy framework (CherryPy is a Minimalist Python Web Framework) Frontend WebUI is based on Angular/TypeScript A custom REST API Monitoring facilitated by Prometheus Visualization of data facilitated by Grafana Dependent upon DBUS, systemd, and systems\u2019 shell Dashboard as Manager Module Ceph Dashboard runs as a Manager module Runs on each MON/MGR node Really only actively available via the active MGR Runs on \u201cstandby\u201d on the standby MGR nodes Standby Dashboards will redirect to active MGR URL Dashboard automatically switches to active MGR node Helpful High Availability feature As a MGR module, enabled and configured by DeepSea Can be disabled if unwanted URL example: https://10.58.121.186:8443 Grafana and Prometheus Prometheus collects various data about the cluster Grafana represents the data as graphs Ceph Dashboard uses both to improve insight into SES Prometheus Open source event monitoring software \"Scrapes\" (collects) data from nodes/services in the cluster Real-time Time series Custom scrapers have been created for Ceph Stores scraped data in memory and on disk Presents data to other software for graphical representation Integrated nicely with Grafana Grafana The leading open source software for time series analytics \"Dashboards\" of panels, graphs, metrics, etc. \"Dashboard\" is a slightly conflicting term, but still meaningful Renders data in a graphical way collected from Prometheus Graphs are customized for use on the Ceph Dashboard Dashboard Users Always need an \u201cAdmin\u201d user for the Dashboard \u00a7 The admin keys of the root user on the \u201cAdmin\u201d node in the cluster Dashboard Users are accounts that relate only to using the Dashboard \u00a7 Not the same as Ceph CLI users and client keys; but could coincide Any person who wants to interact with the storage cluster via the Dashboard must have a user account Variety of Users established by the Admin User, and various permissions based on Admin-defined Roles User Authentication Dashboard Administrators can setup users with specific privileges The privileges and permissions are managed as \"roles\" User accounts can be created directly in the Dashboard Stored as objects in Ceph User accounts can also be tied to other authentication mechanisms: Single Sign-On Service; SAML 2.0 compliant protocol Dashboard accounts can be managed from the Dashboard or from the CLI Example: ceph dashboard ac-user-show [] The Admin Dashboard User (the term \u201cadmin\u201d is used differently in different places) The Dashboard Admin User is not the same as other admins The \u201cadmin\u201d node is obviously not directly tied to any admin user The Admin Dashboard User is created at Deployment time Given a random password by DeepSea You must use the CLI to establish the admin password ceph dashboard ac-user-show admin ceph dashboard ac-user-set-password admin \u25cb The SES Deployment Course has set the password to mypassword admin:~ # ceph dashboard ac-user-show [\"admin\"] admin:~ # ceph dashboard ac-user-show admin {\"username\": \"admin\", \"password\": \"$2b$12$4lC/AU7jc6midTZufj4P4.rBtVzRGf7Zy7fUbD6G9YfdfVEwkwuUy\", \"roles\": [\"administrator\"], \"name\": null \"email\":null\"lastUpdate\": 1601874928} Health from the Dashboard Cluster Status Monitors OSDs Manager Daemons Hosts Object Gateways Metadata Service iSCSI Gateways Cluster Performance from Dashboard Client IOPS Client Throughput Client Read/Write Recovery Throughput Scrub Performance Data Hosts: Overall Performance Monitors: Performance Counters OSDs: Relative Read/Write bar graphs, and Overall Performance Pools: Relative Read/Write bar graphs, and Overall Performance Block images: Overall Performance CephFS: Performance Details RGW: Overall Performance Cluster Capacity from Dashboard Capacity data: Number of Pools Raw Capacity Number of Objects (Ceph objects, not user objects from RGW) Placement Groups per OSD Placement Group Status Basic Troubleshooting \u00b6 Ceph Logs Logs normally stored in /var/log/ceph/ No real logs on the admin node Each service has its own log on the MON, Storage and Gateway nodes Logs handled routinely by logrotate Ceph has logs that are stored to files and in memory (triggered by event or manual request) There are 21 different levels of logging: 0-20 (0 is no logging; 20 is the most verbose logging) There are many subsystems that do their own logging, and can be configured independently Most common: mon, osd, mgr, rados, rbd, mds, rgw Others: asok, auth, client, filestore, journal, monc, ms, paxos, and more There are only 3 types of daemons: osd, mon, mds Using Tell to Change Log Levels 1) Check the Dashboard and Health. Common commands ceph status ceph osd status ceph osd df ceph osd utilization ceph osd pool stats ceph osd tree ceph pg stat 2) Network Troubleshooting Always be sure that the network (and related services) are working properly Ceph depends heavily on tightly synchronized time; make sure network time services are working on each node DNS hostnames are similarly essential 3) Check the Logs Go to the node of the component implicated in HEALTH 4: Raise the DEBUG Level. Follow this simple formula: Raise the debug level (a little each time until you see the problem) Check the logs Repeat as necessary Don\u2019t forget to restore the debug level back to its normal level 5) Check the Storage Device If the problem is with an OSD or a storage device, go straight to the device: hdparm smartctl And check out the details of the combination of OSD and storage device: lsblk /var/lib/ceph/osd/ 6) Scrub (or not) Sometimes simply scrubbing an OSD or PG can cause the checksum-ing process to reveal problems At least some problems can be made more clear with the result of scrub and/or deep-scrub Even doing a scrub can kick Ceph into fixing the problem itself And don\u2019t forget ceph osd repair On the other hand, sometimes Scrub can make things worse. If you suspect Scrub is part of the problem, turn it off: ceph osd set noscrub ceph osd unset noscrub 7) Placement Groups When Placement Groups cause problems: * ceph pg dump summary * ceph pg dump pools * ceph pg dump_jason * ceph pg dump | less Followed by a strategic \u201crepair\u201d of the PG * ceph pg repair 8) Running supportconfig YaST Support Module From CLI: supportconfig The collected data is stored in a file called /var/log/nts__.txz","title":"SUSE Enterprise Storage Foundation"},{"location":"linux/SES/linux_ses_memo/#suse-enterprise-storage-foundation","text":"","title":"SUSE Enterprise Storage Foundation"},{"location":"linux/SES/linux_ses_memo/#cephs-rados","text":"Everything in Ceph is stored in the RADOS cluster as Objects. Ceph\u2019s RADOS: Reliable Autonomous Distributed Object Store Ceph\u2019s RADOS is composed of storage devices represented as: Raw storage device with LVM (BlueStore) Standard filesystem (FileStore) The Object Storage Daemon (OSD) integrates each disk device as part of the RADOS cluster.","title":"Ceph\u2019s RADOS"},{"location":"linux/SES/linux_ses_memo/#ceph-architecture","text":"Ceph is made of two groups of core components The RADOS cluster Provides the clustered object storage Native Object Access methods Gateways Access to the object store via standard protocols librados Direct access to the object store using a native API Examples: iSCSI Gateway (block) -- IGW - iSCSI is a storage area network (SAN) protocol. Exports RADOS Block Device (--RBD) (images as iSCSI disks). iSCSI access to RDB images. lrbd is no longer used in SES6. RADOS Gateway (object) -- RGW Is an object storage interface built on top of librados CephFS (file) A MetaData Service (MDS) is required. Direct access to RADOS (no LIBRADOS layer) Traditional filesystem interface. NFS Ganesha (object, file) Provides NFS exports to: RGW buckets for access the object store The CephFS filesystem Client access the storage services of the cluster via Gateways and Librados The librados API allows interaction with the following daemons: The Ceph Monitor, which maintains a master copy of the cluster map The Ceph OSD Daemon (OSD), which stores data as objects on a storage node.","title":"Ceph architecture"},{"location":"linux/SES/linux_ses_memo/#enhanced-ses-architecture-diagram","text":"","title":"Enhanced SES Architecture Diagram"},{"location":"linux/SES/linux_ses_memo/#object-storage","text":"The state of the art of distributed SDS storage Unstructured, to better accommodate large files and large quantities of files For large files and large quantities of files, it performs far better than other storage mechanisms Agile, scalable, extensible, and very customizable Invisible to the end-user, ideal for backends Perfect for systemic, application-based use cases. Not necessarily perfect for direct Human use Through associated metadata, ideal for computational analytics And CRUSH takes full advantage of this (CRUSH = Controllable Replication Under Scalable Hashing) Ceph Object Storage supports two interfaces: S3-compatible Swift-compatible Object-based storage has become the standard backend storage mechanism for nearly all modern Enterprise Storage Solutions.","title":"Object Storage"},{"location":"linux/SES/linux_ses_memo/#ceph-osds-object-storage-daemon","text":"A Ceph OSD (object storage daemon, ceph-osd) stores data, handles data replication, recovery, rebalancing, and provides some monitoring information to Ceph Monitors and Managers by checking other Ceph OSD Daemons for a heartbeat. The Ceph Storage Cluster receives data from Ceph Clients. Clients (dedicated access points, e.g., gateway) could be a Ceph Block Device, Ceph Object Storage, the Ceph Filesystem or a custom implementation using librados. The client requests the cluster status from a monitor node The client uses the status information to identify the location of objects in the cluster The client accesses the objects directly via the OSD node The OSD then stores the data as objects. Each object corresponds to a file in a filesystem which is stored on an OSD. The OSD Daemons take care of the reads and writes on the storage disks. When OSDs are deployed in SES5 the default is to use BlueStore which uses the raw disk and does not require a linux file system to be placed on the disk before it can be used. OSD Daemons store all data as objects in a flat namespace, i.e. no hierarchy of directories. At least 3 Ceph OSDs are normally required for redundancy and high availability.","title":"Ceph OSDs (Object Storage Daemon)"},{"location":"linux/SES/linux_ses_memo/#ceph-mons-monitor-servers","text":"A Ceph Monitor (ceph-mon) maintains maps of the cluster state, including Monitor Map Manager Map OSD Map PG Map CRUSH Map Epoch These maps are critical cluster state required for Ceph daemons to coordinate with each other. Monitors are also responsible for managing authentication between daemons and clients. At least 3 monitors are normally required for redundancy and high availability. An odd number of MONs is required (Paxos requires). Typically 5 is sufficient for mid or large size cluster. Paxos is an algorithm used for cluster durability. Leader MON expects 50% quality to create quorum. Lowest IP address becomes leader. After new leader selected, all MONs polled for epoch. Leader Mon provides lease to non-leader MONs. MONs are NOT in the data path. They merely serve maps to clients so that the client can go directly to the appropriate OSD storage daemon. Monitor nodes MONs do not serve objects to clients","title":"Ceph Mons (Monitor Servers)"},{"location":"linux/SES/linux_ses_memo/#ceph-mgrs-manager-daemon","text":"A Ceph Manager daemon (ceph-mgr) is responsible for keeping track of runtime metrics and the current state of the Ceph cluster, including storage utilization current performance metrics system load The Ceph Manager daemons also host python-based plugins to manage and expose Ceph cluster information, including a web-based dashboard and REST API. At least two managers are normally required for high availability. MON/MGR daemons are required to run on the same node in SES","title":"Ceph MGRs (Manager Daemon)"},{"location":"linux/SES/linux_ses_memo/#ceph-mds-metadata","text":"A Ceph Metadata Server (MDS, ceph-mds) stores metadata on behalf of the Ceph Filesystem. Ceph Metadata Servers allow POSIX file system users to execute basic commands, for example ls -al without placing an large load on the Ceph Storage Cluster.","title":"Ceph MDS (Metadata)"},{"location":"linux/SES/linux_ses_memo/#ceph-admin-node","text":"The Admin node fills the \u201cmaster\u201d and \u201cadmin\u201d roles for DeepSea. Salt is central to SES. SES\u2019s deployment and life-cycle management tool. The Admin node keeps master Ceph authentication keys. Prometheus and Grafana provide cluster monitoring and data graphs","title":"Ceph Admin Node"},{"location":"linux/SES/linux_ses_memo/#ceph-dashboard","text":"Runs as a Ceph Manager module; runs via the MON/MGR node.","title":"Ceph Dashboard"},{"location":"linux/SES/linux_ses_memo/#client-access","text":"Object Storage (RADOSGW or RGW) Block Storage (RDB). RBD is built on top of librados. CephFS iSCSI Gateway NFS Ganesha SMB/CIFS Native protocols via librados","title":"Client Access"},{"location":"linux/SES/linux_ses_memo/#objects-in-ceph","text":"Everything stored in the Ceph cluster is an object. Default object size is 4MB. Each object has a unique ID. ID is unique across the entire cluster. Objects have associated metadata, in Key: Value pairs. In Ceph we use Storage Pools to organize or arrange our objects. Pools are logical partitions to manage objects Parameters to manage Pools Number of data replicas (Replica pools), or configuration of Erasure Code (size) (Erasure Code pools) Erasure Code is an alternative to Replication SIZE for Erasure Coding is K+M K = Data chunks, M = \u201cParity\u201d chunks EC reduces the hit to raw storage capacity EC incurs a greater hit to CPU on the OSDs as a tradeoff Placement Groups (PG) PG is used to manage objects within a pool. PGs are associated with OSDs for data placement PGs are a central feature of CRUSH that help to provide data durability by way of distribution No PG is owned by an OSD. (And an OSD is not owned by a PG.) PGs are just randomly assigned by CRUSH through all of the OSDs to spread the distribution of data Locating data among PGs is all handled economically, deterministically by way of CRUSH calculations PGs are subdivisions of pools Number of PGs = (Number of OSDs * 100) / Size (Size = either num of replicas, or K+M) The final PG number must be a power of 2 The default number of PGs for a new pool is 8 (it's too small for enterprise solution) In general, PG and PGP numbers should be the same pg_num is the number of placement groups for the pool (placement group, \u5b58\u50a8\u6c60\u7684\u76ee\u5f55\u4e2a\u6570 ) pgp_num is the number of placement groups that will be considered for placement (placement group for placement purpose, pg\u53ef\u7528\u7684osd\u6392\u5217\u7ec4\u5408\u6570\u91cf) \u4ec5\u589e\u5927pg_num\uff1a \u56e0\u4e3apgp_num\u6ca1\u53d8\uff0cpg\u7684osd\u7ec4\u5408\u4ecd\u53ea\u80fd\u4ece\u5f53\u524dpgp_num\u79cd\u7ec4\u5408\u91cc\u9762\u6311\u9009\uff0c\u5bfc\u81f4\u65b0\u589e\u7684pg\u548c\u65e7pg\u4f1a\u6709\u91cd\u590d\u7684osd\u7ec4\u5408\uff0c\u8be5\u73b0\u8c61\u79f0\u4e4b\u4e3a\u5206\u88c2\uff1b\u6b64\u65f6pg\u548cosd\u7684\u6620\u5c04\u6ca1\u6709\u53d8\uff1b \u7ee7\u7eed\u589e\u5927pgp_num\uff0c\u4f7f\u5176\u7b49\u4e8epg_num\uff1a \u65e7pg\u6ca1\u6709\u53d8\u5316\uff0c\u4f46\u65b0\u589epg\u7684osd\u7ec4\u5408\u53d1\u751f\u53d8\u5316\uff0c\u5373\u5f00\u59cb\u91cd\u65b0\u5206\u5e03 Placement Group (PG) \u5f52\u7f6e\u7ec4\u72b6\u6001 Creating \u521b\u5efa\u5b58\u50a8\u6c60\u65f6\uff0c\u5b83\u4f1a\u521b\u5efa\u6307\u5b9a\u6570\u91cf\u7684\u5f52\u7f6e\u7ec4\u3002 ceph \u5728\u521b\u5efa\u4e00\u6216\u591a\u4e2a\u5f52\u7f6e\u7ec4\u65f6\u4f1a\u663e\u793a creating\u3002 \u521b\u5efa\u5b8c\u540e\uff0c\u5728\u5176\u5f52\u7f6e\u7ec4\u7684 Acting Set \u91cc\u7684 OSD \u5c06\u5efa\u7acb\u4e92\u8054\u3002 \u4e00\u65e6\u4e92\u8054\u5b8c\u6210\uff0c\u5f52\u7f6e\u7ec4\u72b6\u6001\u5e94\u8be5\u53d8\u4e3a active+clean\uff0c\u610f\u601d\u662fceph \u5ba2\u6237\u7aef\u53ef\u4ee5\u5411\u5f52\u7f6e\u7ec4\u5199\u5165\u6570\u636e\u4e86\u3002 peering ceph \u4e3a\u5f52\u7f6e\u7ec4\u5efa\u7acb\u4e92\u8054\u65f6\uff0c\u4f1a\u8ba9\u5b58\u50a8\u5f52\u7f6e\u7ec4\u526f\u672c\u7684 OSD \u4e4b\u95f4\u5c31\u5176\u4e2d\u7684\u5bf9\u8c61\u548c\u5143\u6570\u636e\u72b6\u6001\u8fbe\u6210\u4e00\u81f4\u3002 ceph \u5b8c\u6210\u4e86\u4e92\u8054\uff0c\u4e5f\u5c31\u610f\u5473\u7740\u5b58\u50a8\u7740\u5f52\u7f6e\u7ec4\u7684 OSD \u5c31\u5176\u5f53\u524d\u72b6\u6001\u8fbe\u6210\u4e86\u4e00\u81f4\u3002 \u7136\u800c\uff0c\u4e92\u8054\u8fc7\u7a0b\u7684\u5b8c\u6210\u5e76\u4e0d\u80fd\u8868\u660e\u5404\u526f\u672c\u90fd\u6709\u4e86\u6570\u636e\u7684\u6700\u65b0\u7248\u672c\u3002 active ceph \u5b8c\u6210\u4e92\u8054\u8fdb\u7a0b\u540e,\u4e00\u5f52\u7f6e\u7ec4\u5c31\u53ef\u53d8\u4e3a active\u3002 active \u72b6\u6001\u901a\u5e38\u610f\u5473\u7740\u5728\u4e3b\u5f52\u7f6e\u7ec4\u548c\u526f\u672c\u4e2d\u7684\u6570\u636e\u90fd\u53ef\u4ee5\u8bfb\u5199\u3002 clean \u67d0\u4e00\u5f52\u7f6e\u7ec4\u5904\u4e8e clean \u72b6\u6001\u65f6\uff0c\u4e3b OSD \u548c\u526f\u672c OSD \u5df2\u6210\u529f\u4e92\u8054\uff0c\u5e76\u4e14\u6ca1\u6709\u504f\u79bb\u7684\u5f52\u7f6e\u7ec4\u3002 ceph \u5df2\u628a\u5f52\u7f6e\u7ec4\u4e2d\u7684\u5bf9\u8c61\u590d\u5236\u4e86\u89c4\u5b9a\u6b21\u6570\u3002 degraded \u5f53\u5ba2\u6237\u7aef\u5411\u4e3b OSD \u5199\u5165\u6570\u636e\u65f6\uff0c\u7531\u4e3b OSD \u8d1f\u8d23\u628a\u526f\u672c\u5199\u5165\u5176\u4f59\u590d\u5236 OSD\u3002 \u4e3b OSD \u628a\u5bf9\u8c61\u5199\u5165\u590d\u5236 OSD \u540e\uff0c\u5728\u6ca1\u6536\u5230\u6210\u529f\u5b8c\u6210\u7684\u786e\u8ba4\u524d\uff0c\u4e3b OSD \u4f1a\u4e00\u76f4\u505c\u7559\u5728 degraded \u72b6\u6001\u3002 \u5f52\u7f6e\u7ec4\u72b6\u6001\u53ef\u4ee5\u662f active+degraded \u72b6\u6001\uff0c\u539f\u56e0\u5728\u4e8e\u4e00 OSD \u5373\u4f7f\u6ca1\u6240\u6709\u5bf9\u8c61\u4e5f\u53ef\u4ee5\u5904\u4e8e active \u72b6\u6001\u3002 \u5982\u679c\u4e00OSD \u6302\u4e86\uff0cceph \u4f1a\u628a\u76f8\u5173\u7684\u5f52\u7f6e\u7ec4\u90fd\u6807\u8bb0\u4e3a degraded\u3002 \u90a3\u4e2a OSD \u91cd\u751f\u540e\uff0c\u5b83\u4eec\u5fc5\u987b\u91cd\u65b0\u4e92\u8054\u3002 \u7136\u800c\uff0c\u5982\u679c\u5f52\u7f6e\u7ec4\u4ecd\u5904\u4e8e active \u72b6\u6001\uff0c\u5373\u4fbf\u5b83\u5904\u4e8e degraded \u72b6\u6001\uff0c\u5ba2\u6237\u7aef\u8fd8\u53ef\u4ee5\u5411\u5176\u5199\u5165\u65b0\u5bf9\u8c61\u3002 \u5982\u679c\u4e00 OSD \u6302\u4e86\uff0c\u4e14 degraded \u72b6\u6001\u6301\u7eed\uff0cceph \u4f1a\u628a down \u7684 OSD \u6807\u8bb0\u4e3a\u5728\u96c6\u7fa4\u5916(out)\u3001\u5e76\u628a\u90a3\u4e9b down \u6389\u7684 OSD \u4e0a\u7684\u6570\u636e\u91cd\u6620\u5c04\u5230\u5176\u5b83 OSD\u3002 \u4ece\u6807\u8bb0\u4e3a down \u5230 out \u7684\u65f6\u95f4\u95f4\u9694\u7531 mon osd down out interval \u63a7\u5236,\u9ed8\u8ba4\u662f 300 \u79d2\u3002 \u5f52\u7f6e\u7ec4\u4e5f\u4f1a\u88ab\u964d\u7ea7(degraded)\uff0c\u56e0\u4e3a\u5f52\u7f6e\u7ec4\u627e\u4e0d\u5230\u672c\u5e94\u5b58\u5728\u4e8e\u5f52\u7f6e\u7ec4\u4e2d\u7684\u4e00\u6216\u591a\u4e2a\u5bf9\u8c61\uff0c\u8fd9\u65f6\uff0c\u4f60\u4e0d\u80fd\u8bfb\u6216\u5199\u627e\u4e0d\u5230\u7684\u5bf9\u8c61\uff0c\u4f46\u4ecd\u80fd\u8bbf\u95ee\u5176\u5b83\u4f4d\u4e8e\u964d\u7ea7\u5f52\u7f6e\u7ec4\u4e2d\u7684\u5bf9\u8c61\u3002 recovering ceph \u88ab\u8bbe\u8ba1\u4e3a\u53ef\u5bb9\u9519\uff0c\u53ef\u62b5\u5fa1\u4e00\u5b9a\u89c4\u6a21\u7684\u8f6f\u3001\u786c\u4ef6\u95ee\u9898\u3002 \u5f53\u67d0 OSD \u6302\u4e86(down)\u65f6\uff0c\u5176\u5185\u5bb9\u7248\u672c\u4f1a\u843d\u540e\u4e8e\u5f52\u7f6e\u7ec4\u5185\u7684\u5176\u5b83\u526f\u672c\u3002 \u5b83\u91cd\u751f(up)\u65f6\uff0c\u5f52\u7f6e\u7ec4\u5185\u5bb9\u5fc5\u987b\u66f4\u65b0\uff0c\u4ee5\u53cd\u6620\u5f53\u524d\u72b6\u6001\u3002 \u5728\u6b64\u671f\u95f4\uff0cOSD \u5728recovering \u72b6\u6001\u3002 \u4e00\u6b21\u786c\u4ef6\u5931\u8d25\u53ef\u80fd\u7275\u8fde\u591a\u4e2a OSD\u3002\u6bd4\u5982\u4e00\u4e2a\u673a\u67dc\u7684\u7f51\u7edc\u4ea4\u6362\u673a\u5931\u8d25\u4e86\uff0c\u8fd9\u4f1a\u5bfc\u81f4\u591a\u4e2a\u4e3b\u673a\u843d\u540e\u4e8e\u96c6\u7fa4\u7684\u5f53\u524d\u72b6\u6001\uff0c\u95ee\u9898\u89e3\u51b3\u540e\u6bcf\u4e00\u4e2a OSD \u90fd\u5fc5\u987b\u6062\u590d\u3002 ceph \u63d0\u4f9b\u4e86\u5f88\u591a\u9009\u9879\u6765\u5747\u8861\u8d44\u6e90\u7ade\u4e89\uff0c\u5982\u65b0\u670d\u52a1\u8bf7\u6c42\u3001\u6062\u590d\u6570\u636e\u5bf9\u8c61\u548c\u6062\u590d\u5f52\u7f6e\u7ec4\u5230\u5f53\u524d\u72b6\u6001\u3002 osd recovery delay start \u9009\u9879\u5141\u8bb8\u4e00 OSD \u5728\u5f00\u59cb\u6062\u590d\u8fdb\u7a0b\u524d\uff0c\u5148\u91cd\u542f\u3001\u91cd\u5efa\u4e92\u8054\u3001\u751a\u81f3\u5904\u7406\u4e00\u4e9b\u91cd\u653e\u8bf7\u6c42\u3002 osd recovery threads \u9009\u9879\u9650\u5236\u6062\u590d\u8fdb\u7a0b\u7684\u7ebf\u7a0b\u6570\uff0c\u9ed8\u8ba4\u4e3a 1 \u7ebf\u7a0b\u3002 osd recovery thread timeout \u8bbe\u7f6e\u7ebf\u7a0b\u8d85\u65f6\uff0c\u56e0\u4e3a\u591a\u4e2aOSD \u53ef\u80fd\u4ea4\u66ff\u5931\u8d25\u3001\u91cd\u542f\u548c\u91cd\u5efa\u4e92\u8054\u3002 osd recovery max active \u9009\u9879\u9650\u5236\u4e00 OSD \u6700\u591a\u540c\u65f6\u63a5\u53d7\u591a\u5c11\u8bf7\u6c42\uff0c\u4ee5\u9632\u5b83\u538b\u529b\u8fc7\u5927\u800c\u4e0d\u80fd\u6b63\u5e38\u670d\u52a1\u3002 osd recovery max chunk \u9009\u9879\u9650\u5236\u6062\u590d\u6570\u636e\u5757\u5c3a\u5bf8\uff0c\u4ee5\u9632\u7f51\u7edc\u62e5\u585e\u3002 back filling \u6709\u65b0 OSD \u52a0\u5165\u96c6\u7fa4\u65f6\uff0cCRUSH \u4f1a\u628a\u73b0\u6709\u96c6\u7fa4\u5185\u7684\u5f52\u7f6e\u7ec4\u91cd\u5206\u914d\u7ed9\u5b83\u3002 \u5f3a\u5236\u65b0 OSD \u7acb\u5373\u63a5\u53d7\u91cd\u5206\u914d\u7684\u5f52\u7f6e\u7ec4\u4f1a\u4f7f\u4e4b\u8fc7\u8f7d\uff0c\u7528\u5f52\u7f6e\u7ec4\u56de\u586b\u53ef\u4f7f\u8fd9\u4e2a\u8fc7\u7a0b\u5728\u540e\u53f0\u5f00\u59cb\u3002 \u56de\u586b\u5b8c\u6210\u540e\uff0c\u65b0 OSD \u51c6\u5907\u597d\u65f6\u5c31\u53ef\u4ee5\u5bf9\u5916\u670d\u52a1\u4e86\u3002 remapped \u67d0\u4e00\u5f52\u7f6e\u7ec4\u7684 Acting Set \u53d8\u66f4\u65f6\uff0c\u6570\u636e\u8981\u4ece\u65e7\u96c6\u5408\u8fc1\u79fb\u5230\u65b0\u7684\u3002 \u4e3b OSD \u8981\u82b1\u8d39\u4e00\u4e9b\u65f6\u95f4\u624d\u80fd\u63d0\u4f9b\u670d\u52a1\uff0c\u6240\u4ee5\u5b83\u53ef\u4ee5\u8ba9\u8001\u7684\u4e3b OSD \u6301\u7eed\u670d\u52a1\u3001\u76f4\u5230\u5f52\u7f6e\u7ec4\u8fc1\u79fb\u5b8c\u3002 \u6570\u636e\u8fc1\u79fb\u5b8c\u540e,\u4e3b OSD \u4f1a\u6620\u5c04\u5230\u65b0 acting set\u3002 stale \u867d\u7136 ceph \u7528\u5fc3\u8df3\u6765\u4fdd\u8bc1\u4e3b\u673a\u548c\u5b88\u62a4\u8fdb\u7a0b\u5728\u8fd0\u884c\uff0c\u4f46\u662f ceph-osd \u4ecd\u6709\u53ef\u80fd\u8fdb\u5165 stuck \u72b6\u6001\uff0c\u5b83\u4eec\u6ca1\u6709\u6309\u65f6\u62a5\u544a\u5176\u72b6\u6001(\u5982\u7f51\u7edc\u77ac\u65ad)\u3002 \u9ed8\u8ba4OSD \u5b88\u62a4\u8fdb\u7a0b\u6bcf\u534a\u79d2(0.5)\u4f1a\u4e00\u6b21\u62a5\u544a\u5176\u5f52\u7f6e\u7ec4\u3001\u51fa\u6d41\u91cf\u3001\u5f15\u5bfc\u548c\u5931\u8d25\u7edf\u8ba1\u72b6\u6001\uff0c\u6b64\u9891\u7387\u9ad8\u4e8e\u5fc3\u8df3\u9600\u503c\u3002 \u5982\u679c\u4e00\u5f52\u7f6e\u7ec4\u7684\u4e3b OSD \u6240\u5728\u7684 acting set \u6ca1\u80fd\u5411\u76d1\u89c6\u5668\u62a5\u544a\u3001\u6216\u8005\u5176\u5b83\u76d1\u89c6\u5668\u5df2\u7ecf\u62a5\u544a\u4e86\u90a3\u4e2a\u4e3b OSD \u5df2 down\uff0c\u76d1\u89c6\u5668\u4eec\u5c31\u4f1a\u628a\u6b64\u5f52\u7f6e\u7ec4\u6807\u8bb0\u4e3a stale\u3002 \u542f\u52a8\u96c6\u7fa4\u65f6\uff0c\u4f1a\u7ecf\u5e38\u770b\u5230 stale \u72b6\u6001\uff0c\u76f4\u5230\u4e92\u8054\u5b8c\u6210\u3002 \u96c6\u7fa4\u8fd0\u884c\u4e00\u9635\u540e\uff0c\u5982\u679c\u8fd8\u80fd\u770b\u5230\u6709\u5f52\u7f6e\u7ec4\u4f4d\u4e8e stale \u72b6\u6001\uff0c\u5c31\u8bf4\u660e\u90a3\u4e9b\u5f52\u7f6e\u7ec4\u7684\u4e3b OSD \u6302\u4e86(down)\u3001\u6216\u6ca1\u5728\u5411\u76d1\u89c6\u5668\u62a5\u544a\u7edf\u8ba1\u4fe1\u606f\u3002 Each pool has its own autoscaler settings The PG balancer optimizes the placement of PGs across OSD crush-compat mode It's default mode Uses the compat weight-set feature upmap mode. It's perfect mode, which an equal number of PGs on each OSD Use fine-grained control over the PG mapping Snapshots Rulesets to manage CRUSH placement Each pool has a defined CRUSH ruleset A CRUSH ruleset is a definition of how the OSDs organize data This allows configuration of data distribution to be managed per pool A single CRUSH ruleset can be reused by multiple pools A ruleset can take into account: \u9700\u8981\u8003\u8651\u7684\u70b9 physical layout of nodes in the cluster organization of network infrastructure selection of OSDs backed by SSDs versus HDDs, etc Each pool can use either Replication or Erasure Coding Replication is the original, default approach to resiliency Erasure Coded pools have an EC Profile assigned Different than CRUSH rulesets, but similar: define how OSDs organize data The profile defines K, M values; encoding method/plugin; etc","title":"Objects in Ceph"},{"location":"linux/SES/linux_ses_memo/#crush-controllable-replication-under-scalable-hashing","text":"CRUSH is a key piece of the Ceph storage solution With the CRUSH algorithm used by Ceph: Data is not centrally stored, it is distributed CRUSH calculates the storage location for each object dynamically No requirement to store a global index of object locations","title":"CRUSH (Controllable Replication Under Scalable Hashing)"},{"location":"linux/SES/linux_ses_memo/#crush-algorithm","text":"The CRUSH algorithm deterministically calculates the location of any object in the Ceph RADOS cluster Overhead is low and calculation is performed by each client As no metadata store is required, CRUSH removes the limitations of traditional metadata based management No direct control over the placement of your data in the cluster Higher CPU requirements","title":"CRUSH Algorithm"},{"location":"linux/SES/linux_ses_memo/#crush-maps-and-rulesets","text":"CRUSH Rulesets are the named sets of rules: Combining all of the customizable CRUSH behavior settings Assigned to pool to govern how the pool\u2019s data is distributed in the cluster CRUSH Maps are central to how Ceph distributes data, and maintaining the durability of the data When the cluster is deployed, Ceph creates a simple default ruleset for replicated pools: replicated_rule CRUSH behavior depends on the behaviors and performance of storage devices CRUSH Maps should be crafted to take advantage of those behaviors Rulesets should be used to clearly identify how the devices in your environment should be employed Device Classes exist to indicate performance behavior: hdd, ssd, nvme Ceph OSDs will automatically set the Device Class of a storage device when the OSD is started Working with CRUSH Map Rulesets List the OSDs, which host each OSD belongs to: ceph osd tree ceph osd df tree ceph osd df tree -f json-pretty Find the host of a specific OSD: ceph osd find 8 Show the existing defined rulesets: ceph osd crush rule ls Examine the definition of an existing ruleset: ceph osd crush rule dump There are 3 options for creating a new ruleset: simple replicated erasure Creating new rulesets: ceph osd crush rule create-replicated ceph osd crush rule create-erasure Create a new ruleset using a Device Class: create-replicated Description : The name of the node under which data should be placed. Type : String Example : default (rarely would you need to make this different than \u201cdefault\u201d) or Description : The type of CRUSH node (bucket) across which replicas should be separated. Type : String Example : rack Description : The device class data should be placed on. Type : String Example : ssd","title":"CRUSH Maps and Rulesets"},{"location":"linux/SES/linux_ses_memo/#crush-weight","text":"You may need to move data around New nodes degraded nodes rebalancing View the current CRUSH weights ceph osd crush tree ceph osd df tree Change the weight for an OSD ceph osd crush reweight The important difference between ceph osd reweight and ceph osd crush reweight \"ceph osd crush reweight\" sets the CRUSH weight of the OSD. This weight is an arbitrary value (generally the size of the disk in TB or something) and controls how much data the system tries to allocate to the OSD. \"ceph osd reweight\" sets an override weight on the OSD. This value is in the range 0 to 1, and forces CRUSH to re-place (1-weight) of the data that would otherwise live on this drive. It does not change the weights assigned to the buckets above the OSD, and is a corrective measure in case the normal CRUSH distribution isn\u2019t working out quite right. \"ceph osd reweight\" is temporary. \"ceph osd crush reweight\" is sticky, permanent (until you change it again). Setting a weight of an OSD to 0 is effectively setting the OSD \"out\" - you don\u2019t want it to store data.","title":"CRUSH Weight"},{"location":"linux/SES/linux_ses_memo/#the-monitors-cluster-map-contains","text":"Monitor Map Unique Cluster ID, details of each Mon node, current epoch, date/time of last change OSD Map Contains the cluster fsid, when the map was created and last modified, a list of pools, replica sizes, PG numbers, a list of OSDs and their status PG Map Contains the PG version, its time stamp, the last OSD map epoch, the full ratios, and details on each placement group such as the PG ID, the Up Set, the Acting Set, the state of the PG (e.g., active + clean), and data usage statistics for each pool MDS Map Contains the current MDS map epoch, references to pool(s) for storing metadata, list of MDS servers, and which metadata servers are up and in CRUSH Map Contains a list of storage devices, the failure domain hierarchy (e.g., device, host, rack, row, room, etc.), and rules for traversing the hierarchy when storing data","title":"The Monitor\u2019s Cluster Map contains"},{"location":"linux/SES/linux_ses_memo/#crush-hierarchy","text":"The CRUSH Map includes details of physical & network infrastructure The CRUSH Map hierarchy is defined by a storage architect The default hierarchical list of infrastructure elements: (Hierarchy of CRUSH buckets) OSD host chassis \u5200\u7247\u673a\u7bb1 rack \u673a\u67b6 row pdu \u7535\u6e90\u5206\u914d\u5355\u5143 pod \u6027\u80fd\u4f18\u5316\u7684\u6570\u636e\u4e2d\u5fc3(Performance Optimize Datacenter)\uff0c\u57fa\u4e8e\u6807\u51c6\u5316\u8bbe\u65bd\u7684\u6700\u4f73\u5b9e\u8df5\uff0c\u6bcf\u4e2aPOD\u5185IT\u90e8\u5206\u5305\u542b\u76845000\u53f0\u670d\u52a1\u5668\uff0c\u5206\u5c5e\u5230200\u4e2a\u673a\u67b6\uff0c\u5982\u679c\u4ee5\u6bcf\u53f0\u670d\u52a1\u5668400W\u529f\u7387\u8ba1\u7b97\u7684\u8bdd\uff0c\u6bcf\u4e2a\u673a\u67dc\u9700\u898110KW\u7684\u4f9b\u7535\uff0c\u5373\u6bcf\u4e2aPOD\u7684IT\u8d1f\u8f7d\u5bb9\u91cf\u662f2MW\u3002 room datacenter region root CRUSH is the algorithm and calculation for distributing data through the cluster. CRUSH Map obviously plays a part in how those CRUSH calculations work.","title":"CRUSH Hierarchy"},{"location":"linux/SES/linux_ses_memo/#crush-map-sections-six-main-sections","text":"tunables: adjustments to legacy behavior devices: The list of OSDs (usually no customization needed) \u25cb \"device class\" is meaningful; useful in relation to creating/using CRUSH rulesets \u25cb Standard \"device class\" values are \"hdd.\", \"ssd.\", and \"nvme.\" \u25cb Example: device 7 osd.7 types: types of buckets (usually no customization needed) buckets: the most functional, customizable aspect of the Map \u25cb A bucket typically represents a physical location in the cluster, has a \u201ctype\u201d \u25cb Nodes (containers such as hosts) and leaves (storage devices such as OSDs) rules: define policies of how data should be distributed \u25cb The behind-the-scenes rules that CRUSH follows for data placement \u25cb IMPORTANT: this is NOT the same as the \"ruleset\". In fact, a ruleset is the combined set of all of these six Map sections. choose_args (optional): Rarely used exceptional settings to adjust weights From the documentation: \"choose_args are alternative weights associated with the hierarchy that have been adjusted to optimize data placement. A single choose_args map can be used for the entire cluster, or one can be created for each individual pool.\"","title":"CRUSH Map Sections (Six main sections)"},{"location":"linux/SES/linux_ses_memo/#erasure-coding","text":"In information theory : an erasure code is a forward error correction (FEC, \u524d\u5411\u7ea0\u9519) code for the binary erasure channel, which transforms a message of k symbols into a longer message (code word) with n symbols such that the original message can be recovered from a subset of the n symbols. The fraction r = k/n is called the code rate The fraction k\u2019/k, where k\u2019 denotes the number of symbols required for recovery, is called reception efficiency Another (easier) way of describing EC: It\u2019s like RAID in Clustered Storage","title":"Erasure Coding"},{"location":"linux/SES/linux_ses_memo/#erasure-coding-in-ses","text":"The default resilience strategy in SES is simple replication * SES Simple replication has overheads, size=3 means 3 times the storage requirements Simplistic EC details: k = number of \u201cdata\u201d chunks, split across \u201ck\u201d number of OSDs m = number of \u201cparity\u201d chunks, split across \u201cm\u201d number of OSDs Ceph calls these \u201ccoding chunks\u201d r (size) = k + m admin:~ # ceph osd crush rule ls replicated_rule","title":"Erasure Coding in SES"},{"location":"linux/SES/linux_ses_memo/#replication-vs-erasure-code","text":"Replication (default): Use Case: active data Simple and fast Uses more disk space Erasure coding: Use Case: archive data, more static data Calculates recovery data (needs more CPU power) Definable redundancy level Example: K data chunks = 2 , M code chunks = 1 Similar to a replication size of 2 But with only 50% more raw storage consumed Example: for 1GB of effective storage replication pool of size of 2 needs 2GB raw storage erasure coded pool with k=2/m=1 only requires 1.5GB raw storage","title":"Replication vs Erasure Code"},{"location":"linux/SES/linux_ses_memo/#ec-overwrites","text":"Historically, EC only works properly with Objects EC only allowed appends; overwrites were not allowed Works perfectly for objects in buckets but doesn\u2019t work well with Block or CephFS With recent releases of SES, EC can work well with Block and CephFS Facilitated by \u201cEC Overwrites\u201d feature Store data in an EC Pool, and store object metadata in a Replicated Pool Requires a little extra work when defining pools, but worth it ceph osd pool set allow_ec_overwrites true","title":"EC Overwrites"},{"location":"linux/SES/linux_ses_memo/#ec-profiles","text":"Using Erasure Coding, each Pool is assigned an EC Profile Multiple pools can share a single Profile The profile is just a definition Each Profile has multiple settings The common required settings for all Profiles are K, M EC Profiles must be created before EC Pools can be created Created from the Dashboard or CLI Once an EC Profile is created, you can create a CRUSH Ruleset based on the EC profile Once a pool is created, its EC Profile properties cannot be changed Main profile parameters K: M: stripe_unit - allows you to adjust the size of the data chunk Default size is 4K stripe_unit : size of data striped across devices; default 4K This variable can also be set in the master configuration (osd_erasure_code_stripe_unit) EC plugins - choose your favorite EC algorithm via a plugin jerasure/gf-complete (default, free, open, and very fast) (www.jerasure.org) ISA (Intel library; optimized for modern Intel processors) (only runs on Intel processors) LRC (\u201cLocally Repairable Code\u201d; layers over existing plugins) SHEC (\u201cShingled EC\u201d; trades extra storage for recovery efficiency) CLAY (\u201cCoupled LAYer\u201d; good for reduced network traffic)","title":"EC Profiles"},{"location":"linux/SES/linux_ses_memo/#creating-erasure-code-profiles-and-pools","text":"Syntax: ceph osd erasure-code-profile OPTIONS Option Description get - view details of an existing EC profile set - set a profile (create a profile), requires k and m values, with optional values such as ruleset, plugin. Once you create a profile, you can\u2019t change it. ceph osd erasure-code-profile set k= m= [plugin=] [stripe_unit=] ls - list profiles rm - Remove an EC profile ceph osd erasure-code-profile rm Common example (below) The default profile \u2012 2+1=3; data is written over 3 OSDs \u2012 Two data chunks \u2012 One code (parity) chunk \u2012 Uses jerasure plugin with standard Reed/Solomon (reed_sol_van) technique Setting a Custom EC Profile Option: \u2012 Profile name \u2012 K : number of stripes required \u2012 M : number of failed units Example: ceph osd erasure-code-profile set example-profile k=8 m=2 ruleset-failure-domain=host ruleset-failure-domain = crush bucket level for failure admin:/etc/ceph # ceph osd erasure-code-profile \\ set common_profile \\ k=4 \\ m=2 \\ plugin=jerasure \\ technique=reed_sol_van \\ stripe_unit=4K \\ crush-root=default \\ crush-failure-domain=rackcrush-device-class=ssd admin:/etc/ceph # ceph osd erasure-code-profile ls default admin:~ # ceph osd erasure-code-profile get default k=2 m=1 plugin=jerasure technique=reed_sol_van Pools Pools are at the heart of Storage Pools are tied to OSDs Display a list of existing pools: ceph osd pool ls or ceph osd lspools View the statistics and characteristics of pools: ceph osd pool stats ceph osd pool stats ceph osd pool get Show usage and related details of existing pools: rados df or ceph df or ceph df detail All storage revolves around Pools Each pool must be dedicated to a purpose: Object, Block, File Must specify # of Placement Groups and PG Placements Must specify whether using Replication or EC Must specify a CRUSH ruleset Create a Replicated Pool Syntax: ceph osd pool create replicated = number of placement groups for the pool = number of PGs for placement; routinely will be the same as pg_num Always a power of 2 Don\u2019t make the number too small; don\u2019t err on the high side, either Practices For a new pool, the pgp_num will generally (likley) just be the same as the pg_num When increasing the PGs in a pool, you may want to retain the smaller pgp_num to minimize rebalancing, and increase pgp_num later when rebalancing is more convenient If decreasing the PGs in a pool, the pgp_num is adjusted automatically Create an EC Pool (using an EC Profile) Syntax: ceph osd pool create erasure Example: ceph osd pool create EC-pool 128 128 erasure my-ec-profile Pools \u2013 Application Assignment Each Pool must have a stated purpose; application This defines which capabilities the Pool must support The applications are: Block (rbd), Object (rgw), and File (cephfs) There are subtypes of cephfs: i.e. cephfs:data, cephfs:metadata Application assignment happens after creating a pool It\u2019s effortless (and required) to assign an application on a new pool ceph osd pool application enable Changing application assignment after a pool is in use is \u201chard\u201d. Not recommended, only to be done as an expert Pools \u2013 Quotas One of the more desirable features of SDS is to set a maximum usage of a Pool - Quotas Prevent the over-use of a pool Set quotas based on number of objects or number of bytes ceph osd pool set-quota max_objects ceph osd pool set-quota max_bytes Show quota settings ceph osd pool get-quota To remove a quota, set the existing quota setting to 0 There are also application-level quotas For rgw and cephfs (not rbd; images are already limited in size) Pool Quotas vs. Application Quotas. When a pool quota nears its limit, the HEALTH mechanisms will display a \u201cPOOL_NEAR_FULL\u201d warning to the storage administrator. When the quota limit has been exceeded, the HEALTH mechanisms will display a \u201cPOOL_FULL\u201d warning to the storage administrator. Applications (clients) don\u2019t always handle the quotas cleanly. In most cases, once the Pool Quota is exceeded, the application will simply stop writing to the pool, and error messages and behavior at the application are inconsistent (if there are any messages at all). Pools \u2013 Snapshots Take (make) a snapshot of an existing pool ceph osd pool mksnap Remove a snapshot of a pool ceph osd pool rmsnap List pool snapshots rados -p lssnap Rollback the pool to an earlier snapshot rados -p rollback Images and cephfs have their own snapshot facilities. Object and Bucket snapshotting features related to rgw don\u2019t exist. Pools Snapshots versus App Snapshots The two different snapshot features cannot be used at the same time on a pool Either Pool Snapshots, or Application Snapshots; not both. (snap_mode = pool versus snap_mode = selfmanaged) Once you commit to pool snapshots for an RBD pool, you can\u2019t change to using RBD snapshots Pros and Cons of each, depending on your Use Case admin:~ # ceph osd pool ls detail -f json-pretty | grep snap_mode \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\",","title":"Creating Erasure Code Profiles and Pools"},{"location":"linux/SES/linux_ses_memo/#bluestore","text":"BlueStore is the default storage backend in SES Highlighted features: compressing, no double-writes, faster checksums Ceph FileStore Model It is not ideal for a specialized purpose like a highly scalable distributed storage system. Only recommend that XFS be used. Both btrfs and ext4 have known bugs. The FileStore model uses cache from the filesystem (XFS). Memory for cache is managed by filesystem kernel module. Ceph BlueStore Model BlueStore consumes raw block devices. Metadata management with RocksDB. BlueStore employs RocksDB\u2019s key/value database in order to manage internal metadata, such as the mapping from object names to block locations on disk. Full data and metadata checksumming. By default all data and metadata written to BlueStore is protected by one or more checksums. A small specialized filesystem called BlueFS. This provides just enough of a filesystem to allow RocksDB to store its \"key/value files\" to share metadata across all the raw device(s) No data or metadata will be read from disk or returned to the user without being verified. Multi-device metadata tiering. BlueStore allows its internal journal (write-ahead log) to be written to a separate, highspeed device (like an SSD, NVMe, or NVDIMM) to increased performance. Efficient copy-on-write. RBD and CephFS snapshots rely on a copy-on-write clone mechanism that is implemented efficiently in BlueStore. BlueStore is a userspace model that provides its own memory management and cache. No need to clear the storage device cache OSDs help facilitate the performance of caching Default: cache the reads, don\u2019t cache the writes RocksDB\uff1a rocksdb\u662ffacebook\u57fa\u4e8eleveldb\u5f00\u53d1\u7684\u4e00\u6b3ekv\u6570\u636e\u5e93\uff0cBlueStore\u5c06\u5143\u6570\u636e\u5168\u90e8\u5b58\u653e\u81f3RocksDB\u4e2d\uff0c\u8fd9\u4e9b\u5143\u6570\u636e\u5305\u62ec\u5b58\u50a8\u9884\u5199\u5f0f\u65e5\u5fd7\u3001\u6570\u636e\u5bf9\u8c61\u5143\u6570\u636e\u3001Ceph\u7684omap\u6570\u636e\u4fe1\u606f\u3001\u4ee5\u53ca\u5206\u914d\u5668\u7684\u5143\u6570\u636e \u3002 BlueRocksEnv\uff1a \u662fRocksDB\u4e0eBlueFS\u4ea4\u4e92\u7684\u63a5\u53e3\uff1bRocksDB\u63d0\u4f9b\u4e86\u6587\u4ef6\u64cd\u4f5c\u7684\u63a5\u53e3EnvWrapper\uff0c\u7528\u6237\u53ef\u4ee5\u901a\u8fc7\u7ee7\u627f\u5b9e\u73b0\u8be5\u63a5\u53e3\u6765\u81ea\u5b9a\u4e49\u5e95\u5c42\u7684\u8bfb\u5199\u64cd\u4f5c\uff0cBlueRocksEnv\u5c31\u662f\u7ee7\u627f\u81eaEnvWrapper\u5b9e\u73b0\u5bf9BlueFS\u7684\u8bfb\u5199\u3002 BlueFS\uff1a BlueFS\u662fBlueStore\u9488\u5bf9RocksDB\u5f00\u53d1\u7684\u8f7b\u91cf\u7ea7\u6587\u4ef6\u7cfb\u7edf\uff0c\u7528\u4e8e\u5b58\u653eRocksDB\u4ea7\u751f\u7684.sst\u548c.log\u7b49\u6587\u4ef6\u3002 BlockDecive\uff1a BlueStore\u629b\u5f03\u4e86\u4f20\u7edf\u7684ext4\u3001xfs\u6587\u4ef6\u7cfb\u7edf\uff0c\u4f7f\u7528\u76f4\u63a5\u7ba1\u7406\u88f8\u76d8\u7684\u65b9\u5f0f\uff1b BlueStore\u652f\u6301\u540c\u65f6\u4f7f\u7528\u591a\u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u8bbe\u5907\uff0c\u5728\u903b\u8f91\u4e0aBlueStore\u5c06\u5b58\u50a8\u7a7a\u95f4\u5212\u5206\u4e3a\u4e09\u5c42\uff1a\u6162\u901f\uff08Slow\uff09\u7a7a\u95f4\u3001\u9ad8\u901f\uff08DB\uff09\u7a7a\u95f4\u3001\u8d85\u9ad8\u901f\uff08WAL\uff09\u7a7a\u95f4\uff0c\u4e0d\u540c\u7684\u7a7a\u95f4\u53ef\u4ee5\u6307\u5b9a\u4f7f\u7528\u4e0d\u540c\u7684\u8bbe\u5907\u7c7b\u578b\uff0c\u5f53\u7136\u4e5f\u53ef\u4f7f\u7528\u540c\u4e00\u5757\u8bbe\u5907\u3002 Allocator\uff1a\u8d1f\u8d23\u88f8\u8bbe\u5907\u7684\u7a7a\u95f4\u7ba1\u7406\uff0c\u53ea\u5728\u5185\u5b58\u505a\u6807\u8bb0\uff0c\u76ee\u524d\u652f\u6301StupidAllocator\u548cBitmapAllocator\u4e24\u79cd\u5206\u914d\u5668,Stupid\u57fa\u4e8eextent\u7684\u65b9\u5f0f\u5b9e\u73b0 Ceph BlueStore with Mixed Devices","title":"BlueStore"},{"location":"linux/SES/linux_ses_memo/#bluestore-cache-parameters","text":"Under most circumstances, autotune is best bluestore_cache_autotune Description: Automatically tune the ratios assigned to different bluestore caches while respecting minimum values Type: Boolean Required: Yes Default: True (enabled) Related settings: bluestore_cache_autotune_chunk_size, bluestore_cache_autotune_interval, and others bluestore_cache_size Description: The amount of memory BlueStore will use for its cache. If zero, bluestore_cache_size_hdd or bluestore_cache_size_ssd will be used instead. Type: Integer Required: Yes Default: 0 bluestore_cache_size_hdd Description: The default amount of memory BlueStore will use for its cache when backed by an HDD Type: Integer Required: Yes Default: 1 * 1024 * 1024 * 1024 (1 GB) bluestore_cache_size_ssd Description: The default amount of memory BlueStore will use for its cache when backed by an SSD. Type: Integer Required: Yes Default: 3 * 1024 * 1024 * 1024 (3 GB) bluestore_cache_meta_ratio Description: The ratio of cache devoted to metadata. Type: Floating point Default: .01 bluestore_cache_kv_ratio Description: The ratio of cache devoted to key/value data (rocksdb). Type : Floating point Default: .99 bluestore_cache_kv_max Description : The maximum amount of cache devoted to key/value data (rocksdb). Type : Unsigned Integer Default : 512 * 1024*1024 (512 MB)","title":"BlueStore Cache Parameters"},{"location":"linux/SES/linux_ses_memo/#bluestore-device-types","text":"BlueStore has three types of roles for devices: The DATA role: Required: main device (block symlink) stores all object data. If no other types: \u201cdata\u201d device serves all the other roles The DB role: Optional: DB device (block.db symlink) stores metadata in RocksDB Whatever doesn\u2019t fit will spill back onto the \u201cdata\u201d device The Write Ahead Log (WAL/Journal) role: Optional: WAL device (block.wal symlink) stores the internal journal Can combine all 3 roles into one physical device Or combine DB/WAL onto a single device with the DATA device separate Or all three on seperate devices","title":"BlueStore Device Types"},{"location":"linux/SES/linux_ses_memo/#bluestore-configuration-recommendations","text":"Devote DB and WAL to SSD or NVMe Allocate 64 GB to the RocksDB Allocate 4-6 GB to the WAL Assign the \u201cdata\u201d role to the slower (HDD) devices If combining WAL/DB on one device, use a single partition for both You can use a single SSD/NVMe to store multiple journals","title":"BlueStore Configuration Recommendations"},{"location":"linux/SES/linux_ses_memo/#architecture-overview-of-object-block-filesystem-access","text":"","title":"Architecture Overview of Object, Block, Filesystem Access"},{"location":"linux/SES/linux_ses_memo/#object-storage_1","text":"The state of the art of distributed storage Object storage is the Cloud Storage mechanism of choice Unstructured, to better accommodate large files and large quantities of files Ideal for large media files, like streaming videos, audio Scales really well, large capacities Ceph provides access to the storage via all three major data access methods: Block, Object, and File. For the storage backend, Object Storage is ideal","title":"Object Storage"},{"location":"linux/SES/linux_ses_memo/#block-storage","text":"Traditional Block Storage: Volumes as a collection of blocks Blocks can be of various sizes, but all the same within a volume Typically a filesystem is installed on top of the volume Hard Drives, CDs, USB sticks, etc The standard disk device mechanism for Unix, Linux, Windows, etc. Ceph presents RADOS as block device (RBD = RADOS Block Device) Ceph calls these block devices \u201cimages\u201d Provides clients with access like a \u201cdisk drive\u201d KVM/QEMU; libvirt; or remote Linux system A native Windows client that can access the Block storage of Ceph directly is in progress","title":"Block Storage"},{"location":"linux/SES/linux_ses_memo/#rados-block-device-rbd","text":"RBD is the RADOS Block Device A specific RBD instance in the cluster is called an \u201cimage\u201d RBD images can be accessed by OSs other than linux librbd provides interface for gateways like iSCSI RBD allows the client to decide what to do with the storage Filesystem type; raw disk, such as for a DB; etc RBD images can accommodate 16Eb file system sizes No matter the size, the storage is distributed durably throughout the cluster Data is striped across the RADOS cluster in object sized chunks 4MB default Provides high performance and durability Notable Benefits Ability to mount with Linux or QEMU KVM clients Thinly provisioned Resizable images Image import/export Image copy or rename Read-only snapshots Revert to snapshots Copy on Write clones Useful for standing up lots of virtual machines with same base configuration High performance due to striping across cluster nodes RBD image definition: Defined storage area presented as a block device to a client RBD Storage","title":"RADOS Block Device (RBD)"},{"location":"linux/SES/linux_ses_memo/#file-storage","text":"POSIX Filesystem via CephFS File access is a significant use case Home directories Historical comfort with files and directories Ease of managing \u201csmall\u201d stuff broadly, in a distributed system A Use Case that\u2019s growing in popularity: HPC CephFS is fast, scalable, and flexible Fits into many existing paradigms, rather seamlessly In particular: NFS, Samba/CIFS But even better: extending Linux filesystems Requires Metadata Service (MDS) for POSIX capabilities SUSE does NOT support any FUSE clients.","title":"File Storage"},{"location":"linux/SES/linux_ses_memo/#ceph-users-and-authentication","text":"Ceph Users are generally applications; applications that use the storage cluster The must common user is Admin A ceph admin user and credentials must exist Additional users and associated credentials are useful Each user must have credentials to access the storage cluster The most fundamental form of credentials in Ceph is keys Ceph Users and Keys The admin user has rights to all Ceph resources. Other users can be setup to have a subset of rights There are basically two types of Users (Actors): An individual (a person) An application (like a gateway, or some other kind of system) Most users are of the type client, and are represented as a dotted string, such as: client.admin, or client.steve, or client.swift The root linux user on the Admin node is effectively the Admin Ceph user, since the root user has all privileges to all filesystem objects on the Adminnode, including the ceph.client.admin.keyring. The root user on any of the nodes in the cluster can \u201cimpersonate\u201d all of the Ceph clients. Linux user accounts do not have any affect on the Ceph Users as managed in the dashboard. Take care to keep backups of the /etc/ceph/ directory structure, so that you don\u2019t lose these keys/keyrings. Each user must have a key/keyring, for example: /etc/ceph/ceph.client.admin.keyring on the Admin node /etc/ceph/ceph.client.storage.keyring on a storage node admin:/etc/ceph # cat ceph.client.admin.keyring [client.admin] key = AQD6pHpfAAAAABAAHJvkvLhOKZyQxm9lgnR5Qg== caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" data1:/etc/ceph # cat ceph.client.storage.keyring [client.storage] key = AQD8pHpfAAAAABAAHecCBgBsLIyPrJf+27eXUQ== caps mon = \"allow rw\" Ceph Keys and Keyrings A keyring contains one or more keys Each user can have its own keyring A keyring can contain multiple keys Different clients and users must have their own key, but multiple keys can be joined together in a single keyring Normally a key will be contained in a keyring Core Ceph will only recognize and use keys from keyrings Stand-alone keys are useful for other tools, like clients Ceph Authentication List The Admin node (and client.admin) can list all Users ceph auth list Create a Ceph User A typical user will have read rights to MONs, and read/write rights to a pool (osd) ceph auth get/add/get-or-create xxxxxx Create a User with ceph-authtool Create a keyring ceph-authtool -C /etc/ceph/ceph.client.richard.keyring Create a key, and place it on the keyring ceph-authtool --gen-key -n client.richard --cap osd 'allow rw pool=data' --cap mon 'allow r' /etc/ceph/ceph.client.richard.keyring Now officially tell the cluster about the key (add user to the key) ceph auth add client.richard -i /etc/ceph/ceph.client.richard.keyring Authentication with cephx The mechanism for passing keys around is cephx Authentication for users and daemons Does not provide data encryption, only authentication with keys cephx simply ensures the authenticity of actors So that no man-in-the-middle attacks can occur Other authentication mechanisms are theoretically possible Attempts to integrate LDAP and Kerberos have been made \u2026 but they have not come to full fruition yet","title":"Ceph Users and Authentication"},{"location":"linux/SES/linux_ses_memo/#ceph-configuration","text":"Historically, the Ceph configuration was kept only in a file on the Admin node: /etc/ceph/ceph.conf, and sync'd to MONs and Storage Nodes SES DeepSea manages the ceph.conf file. Don\u2019t edit it directly; use Salt and DeepSea With Ceph Nautilus, most configuration held as objects in the Monitors using Dashboard or CLI for operation Ceph Configuration Stored in the MONs The MONs keep a configuration database Show all the configuration keys: admin:/etc/ceph # ceph config ls |less Show the configuration settings that have been customized. The dumped output also indicates an EXPERTISE LEVEL The keys also have a \u201cwho\u201d attribute. In below case, \"osd.*\" represents the \"who\", which is getting the general setting for all OSDs Ceph Configuration Settings Show configuration settings that have been customized: admin:/etc/ceph # ceph config dump WHO MASK LEVEL OPTION VALUE RO mgr advanced mgr/dashboard/GRAFANA_API_URL https://mon1.pvgl.sap.corp:3000 * mgr advanced mgr/dashboard/RGW_API_ACCESS_KEY M11I3JGQHAQM94CS910K * mgr advanced mgr/dashboard/RGW_API_HOST mon3.pvgl.sap.corp * mgr advanced mgr/dashboard/RGW_API_PORT 80 * mgr advanced mgr/dashboard/RGW_API_SECRET_KEY YWyRc3mayEPiOEUzQ2o76KePSKmVKN4fIWxgqTt6 * mgr advanced mgr/dashboard/RGW_API_USER_ID admin * mgr advanced mgr/dashboard/ssl_server_port 8443 admin:/etc/ceph # ceph config get osd.* osd_max_object_size 134217728 admin:/etc/ceph # ceph config show osd.0 \u2026\u2026 admin:/etc/ceph # ceph config show osd.11 (4 data nodes, 3 osds in each node) \u25cb Each of the configuration settings have default values ceph config show-with-defaults osd.2 | less \u25cb Ceph keeps a log of configuration changes admin:/etc/ceph # ceph config log --- 8 --- 2020-10-05 14:31:51.425902 --- + mgr/mgr/dashboard/RGW_API_USER_ID = admin --- 7 --- 2020-10-05 14:31:50.418622 --- + mgr/mgr/dashboard/RGW_API_HOST = mon3.pvgl.sap.corp --- 6 --- 2020-10-05 14:31:49.398448 --- + mgr/mgr/dashboard/RGW_API_PORT = 80 --- 5 --- 2020-10-05 14:31:48.403965 --- + mgr/mgr/dashboard/RGW_API_SECRET_KEY = YWyRc3mayEPiOEUzQ2o76KePSKmVKN4fIWxgqTt6 --- 4 --- 2020-10-05 14:31:46.905701 --- + mgr/mgr/dashboard/RGW_API_ACCESS_KEY = M11I3JGQHAQM94CS910K --- 3 --- 2020-10-05 13:15:29.530355 --- + mgr/mgr/dashboard/GRAFANA_API_URL = https://mon1.pvgl.sap.corp:3000 --- 2 --- 2020-10-05 13:15:14.349623 --- + mgr/mgr/dashboard/ssl_server_port = 8443 --- 1 --- 2020-10-05 13:13:55.637896 ---","title":"Ceph Configuration"},{"location":"linux/SES/linux_ses_memo/#health","text":"Show status admin:/etc/ceph # ceph status cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 6w) mgr: mon1(active, since 13d) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 9w), 12 in (since 9w) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 208 pgs objects: 246 objects, 4.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 208 active+clean io: client: 11 KiB/s rd, 0 B/s wr, 11 op/s rd, 6 op/s wr admin:/etc/ceph # ceph health HEALTH_OK admin:/etc/ceph # ceph health detail HEALTH_OK admin:/etc/ceph # ceph mon stat e1: 3 mons at {mon1=[v2:10.58.121.186:3300/0,v1:10.58.121.186:6789/0],mon2=[v2:10.58.121.187:3300/0,v1:10.58.121.187:6789/0],mon3=[v2:10.58.121.188:3300/0v1:10.58.121.188:6789/0]}, election epoch 22, leader 0 mon1, quorum 0,1,2 mon1,mon2,mon3 admin:/etc/ceph # ceph osd stat 12 osds: 12 up (since 9w), 12 in (since 9w); epoch: e1375 admin:/etc/ceph # ceph pg stat 208 pgs: 208 active+clean; 4.7 KiB data, 2.0 GiB used, 82 GiB / 96 GiB avail; 1.2 KiB/s rd, 1 op/s Watch status -w, --watch : Watch live cluster changes --watch-debug : Watch debug events --watch-info : Watch info events --watch-sec : Watch security events --watch-warn : Watch warning events --watch-error : Watch error","title":"Health"},{"location":"linux/SES/linux_ses_memo/#scrub-and-deep-scrub","text":"\"Scrub\" is the process of doing a data consistency check Basically like running fsck on the cluster In Replicas: compare object metadata among replicas In EC: verify \u201ccode\u201d chunks Manual scrubbing can be done per OSD or per PG. \"osd scrub\" is just a collaborative wrapper of \"pg scrub\". ceph osd scrub osd.11 ceph pg scrub 3.33 \"scrub\" is a light process, daily Checks object size and attributes \"deep-scrub\" is a more thorough process, weekly Reads all data and checks the checksums Scrub \u2013 Manual vs Automatic You can let Ceph just do the default Run scrub daily, run deep-scrub weekly Ceph pays attention to usage and backs off when necessary You can change the defaults for both scrub and deepscrub, examples: osd_scrub_begin_week_day=6 (Saturday) osd_scrub_end_week_day=7 (Sunday) You can manually run scrubbings at any time if you suspect it\u2019s wanted or needed Manual scrubbings are not common Adjustments to Scrub Settings For most circumstances the default behavior of Scrub is adequate See current Scrub configuration settings: ceph config ls | grep osd_scrub ceph config ls | grep osd_deep_scrub ceph config get osd.* osd_scrub_begin_hour Change the settings immediately in the MON DB ceph config set osd.* osd_scrub_begin_hour 23 ceph config set osd.* osd_scrub_end_hour 5 Adjust Settings in ceph.conf with DeepSea To permanently change settings in ceph.conf This is the \u201cold\u201d way, but is still valid Remember that ceph.conf is controlled by DeepSea Add changes to /srv/salt/ceph/configuration/files/ceph.conf.d/global.conf Run the following DeepSea (Salt) commands: salt admin* state.apply ceph.configuration.create salt \\* state.apply ceph.configuration Wait for services/servers to be restarted, or tell Ceph to assimilate the ceph.conf settings now ceph config assimilate-conf -i /etc/ceph/ceph.conf","title":"Scrub and Deep-Scrub"},{"location":"linux/SES/linux_ses_memo/#repair","text":"Problems Found by Scrubbing * If data (in an OSD or PG) becomes inconsistent, it will need to be repaired. You can configure scrubbing to automatically repair errors * osd_scrub_auto_repair=True * osd_scrub_auto_repair_num_errors=5 * Manually repair when appropriate * ceph osd repair osd.11 * ceph pg repair 3.33","title":"Repair"},{"location":"linux/SES/linux_ses_memo/#ceph-manager-modules","text":"Manager Modules help to extend the capabilities of Ceph List of Modules Supported in SES Balancer (always on) rash (always on) Dashboard DeepSea iostat Orchestrator (always on) progress (always on, tech preview) Prometheus RESTful rbd_support (always on) status (always on) telemetry volume (always on) Zabbix (plugin only, not the required agent) Enabling Manager Modules Show a list of Manager Modules ceph mgr module ls | less The output is quite long; best to pipe it through less The top of the output shows those modules that have been enabled The exhaustive output also displays the \u201cAPI\u201d of each module Manager modules are quite easy to enable and disable ceph mgr module enable ceph mgr module disable Show list of services that are active from the Modules ceph mgr services Module Capabilities Each module has its own settings, configuration Once the module is enabled, the ceph command accepts commands for the module No need to run the command as ceph mgr ... Examples: ceph crash stat ceph telemetry show Setting parameters (key/value pairs) of Modules ceph config set mgr mgr/telemetry/contact 'JD ' ceph config set mgr mgr/telemetry/description 'Training Cluster'","title":"Ceph Manager Modules"},{"location":"linux/SES/linux_ses_memo/#ceph-tell","text":"Tell commands are actually directed to the target service by way of the MONs ceph tell is a tool to tell a ceph daemon to perform a task \u2026 change a setting \u2026 execute a subroutine The target of ceph tell can be a single daemon or a collection of daemons All MONs: ceph tell mon.* injectargs '--mon-pg-warn-max-per-osd 4096' A specific OSD: ceph tell osd.9 bench ceph tell is the most common way to change logging for troubleshooting ceph tell . injectargs '--debug- ' ceph tell osd.7 injectargs '--debug-osd 20' ceph tell osd.7 config set debug_osd 20 A \u201c/\u201d allows you to change both the file log and memory log settings simultaneously ceph tell mon.3 injectargs '--debug-mon 0/10' (The first is the file parameter, the second is the memory parameter) Since logging can fill space, important to restore settings after investigating ceph tell mon.3 injectargs '--debug-mon 1/5' ceph tell sends its instructions via the Monitors. So what if the MONs are having problems? To avoid running commands through the MONs, go directly to thenode running the daemon ssh storage1 ceph daemon osd.29 config show ceph daemon osd.29 config set debug_osd 0/20 Use with great care","title":"Ceph Tell"},{"location":"linux/SES/linux_ses_memo/#ceph-dashboard_1","text":"What's Ceph Dashboard SES WEB-based Management Interface A Ceph MGR module, built-in to Ceph The open source \"port\" of openATTIC to Ceph. Technically it\u2019s not a port of openATTIC. SUSE and Ceph Community worked on implementing the openATTIC capabilities directly within Ceph Role-based and Multi-User Management of the SES cluster Create, manage, and monitor Pools, RBDs Manage users, access keys, quotas and buckets of RGW Manage NFS exports, iSCSI targets and portals, CephFS View cluster nodes/roles, monitor performance metrics Manage Ceph settings/configuration Reduces the need to understand complex Ceph commands The dashboard is stateless, it will reflect any changes to the Ceph cluster, Highlighted Enterprise Behavior via Ceph Dashboard Uses SSL/TLS By default will use a CA and certificate created by DeepSea or provide your own CA and certificate Can run without SSL/TLS (not recommended) Multi-User and Role Management Variety of mappings, i.e.: read, create, update, delete Single Sign-On, complying with SAML 2.0 Single Sign-On, complying with SAML 2.0 Auditing on the backend, to monitor specific user activity Internationalization (I18N), with a variety of language translations Ceph Dashboard Architecture Backend is based on CherryPy framework (CherryPy is a Minimalist Python Web Framework) Frontend WebUI is based on Angular/TypeScript A custom REST API Monitoring facilitated by Prometheus Visualization of data facilitated by Grafana Dependent upon DBUS, systemd, and systems\u2019 shell Dashboard as Manager Module Ceph Dashboard runs as a Manager module Runs on each MON/MGR node Really only actively available via the active MGR Runs on \u201cstandby\u201d on the standby MGR nodes Standby Dashboards will redirect to active MGR URL Dashboard automatically switches to active MGR node Helpful High Availability feature As a MGR module, enabled and configured by DeepSea Can be disabled if unwanted URL example: https://10.58.121.186:8443 Grafana and Prometheus Prometheus collects various data about the cluster Grafana represents the data as graphs Ceph Dashboard uses both to improve insight into SES Prometheus Open source event monitoring software \"Scrapes\" (collects) data from nodes/services in the cluster Real-time Time series Custom scrapers have been created for Ceph Stores scraped data in memory and on disk Presents data to other software for graphical representation Integrated nicely with Grafana Grafana The leading open source software for time series analytics \"Dashboards\" of panels, graphs, metrics, etc. \"Dashboard\" is a slightly conflicting term, but still meaningful Renders data in a graphical way collected from Prometheus Graphs are customized for use on the Ceph Dashboard Dashboard Users Always need an \u201cAdmin\u201d user for the Dashboard \u00a7 The admin keys of the root user on the \u201cAdmin\u201d node in the cluster Dashboard Users are accounts that relate only to using the Dashboard \u00a7 Not the same as Ceph CLI users and client keys; but could coincide Any person who wants to interact with the storage cluster via the Dashboard must have a user account Variety of Users established by the Admin User, and various permissions based on Admin-defined Roles User Authentication Dashboard Administrators can setup users with specific privileges The privileges and permissions are managed as \"roles\" User accounts can be created directly in the Dashboard Stored as objects in Ceph User accounts can also be tied to other authentication mechanisms: Single Sign-On Service; SAML 2.0 compliant protocol Dashboard accounts can be managed from the Dashboard or from the CLI Example: ceph dashboard ac-user-show [] The Admin Dashboard User (the term \u201cadmin\u201d is used differently in different places) The Dashboard Admin User is not the same as other admins The \u201cadmin\u201d node is obviously not directly tied to any admin user The Admin Dashboard User is created at Deployment time Given a random password by DeepSea You must use the CLI to establish the admin password ceph dashboard ac-user-show admin ceph dashboard ac-user-set-password admin \u25cb The SES Deployment Course has set the password to mypassword admin:~ # ceph dashboard ac-user-show [\"admin\"] admin:~ # ceph dashboard ac-user-show admin {\"username\": \"admin\", \"password\": \"$2b$12$4lC/AU7jc6midTZufj4P4.rBtVzRGf7Zy7fUbD6G9YfdfVEwkwuUy\", \"roles\": [\"administrator\"], \"name\": null \"email\":null\"lastUpdate\": 1601874928} Health from the Dashboard Cluster Status Monitors OSDs Manager Daemons Hosts Object Gateways Metadata Service iSCSI Gateways Cluster Performance from Dashboard Client IOPS Client Throughput Client Read/Write Recovery Throughput Scrub Performance Data Hosts: Overall Performance Monitors: Performance Counters OSDs: Relative Read/Write bar graphs, and Overall Performance Pools: Relative Read/Write bar graphs, and Overall Performance Block images: Overall Performance CephFS: Performance Details RGW: Overall Performance Cluster Capacity from Dashboard Capacity data: Number of Pools Raw Capacity Number of Objects (Ceph objects, not user objects from RGW) Placement Groups per OSD Placement Group Status","title":"Ceph Dashboard"},{"location":"linux/SES/linux_ses_memo/#basic-troubleshooting","text":"Ceph Logs Logs normally stored in /var/log/ceph/ No real logs on the admin node Each service has its own log on the MON, Storage and Gateway nodes Logs handled routinely by logrotate Ceph has logs that are stored to files and in memory (triggered by event or manual request) There are 21 different levels of logging: 0-20 (0 is no logging; 20 is the most verbose logging) There are many subsystems that do their own logging, and can be configured independently Most common: mon, osd, mgr, rados, rbd, mds, rgw Others: asok, auth, client, filestore, journal, monc, ms, paxos, and more There are only 3 types of daemons: osd, mon, mds Using Tell to Change Log Levels 1) Check the Dashboard and Health. Common commands ceph status ceph osd status ceph osd df ceph osd utilization ceph osd pool stats ceph osd tree ceph pg stat 2) Network Troubleshooting Always be sure that the network (and related services) are working properly Ceph depends heavily on tightly synchronized time; make sure network time services are working on each node DNS hostnames are similarly essential 3) Check the Logs Go to the node of the component implicated in HEALTH 4: Raise the DEBUG Level. Follow this simple formula: Raise the debug level (a little each time until you see the problem) Check the logs Repeat as necessary Don\u2019t forget to restore the debug level back to its normal level 5) Check the Storage Device If the problem is with an OSD or a storage device, go straight to the device: hdparm smartctl And check out the details of the combination of OSD and storage device: lsblk /var/lib/ceph/osd/ 6) Scrub (or not) Sometimes simply scrubbing an OSD or PG can cause the checksum-ing process to reveal problems At least some problems can be made more clear with the result of scrub and/or deep-scrub Even doing a scrub can kick Ceph into fixing the problem itself And don\u2019t forget ceph osd repair On the other hand, sometimes Scrub can make things worse. If you suspect Scrub is part of the problem, turn it off: ceph osd set noscrub ceph osd unset noscrub 7) Placement Groups When Placement Groups cause problems: * ceph pg dump summary * ceph pg dump pools * ceph pg dump_jason * ceph pg dump | less Followed by a strategic \u201crepair\u201d of the PG * ceph pg repair 8) Running supportconfig YaST Support Module From CLI: supportconfig The collected data is stored in a file called /var/log/nts__.txz","title":"Basic Troubleshooting"},{"location":"linux/SRE/01-fundamentals/","text":"\u7b2c\u4e00\u7ae0 Linux\u57fa\u7840 \u00b6 1.\u5b98\u65b9\u6587\u6863 \u00b6 Rocky Linux Instructional Books openSUSE Documentation Ubuntu Documentation 2.\u7cfb\u7edf\u73af\u5883 \u00b6 2.1.Rocky \u00b6 \u4f7f\u7528\u7248\u672c\uff1a Rocky 9.0 \u3002 \u4ece\u7f51\u7ad9\u4e0b\u8f7dRocky\u7cfb\u7edf ISO\u955c\u50cf \uff0c\u6216\u8005\u901a\u8fc7 wget \u547d\u4ee4\u4e0b\u8f7dRocky\u7cfb\u7edfISO\u955c\u50cf\u3002 wget https://download.rockylinux.org/pub/rocky/9.0/isos/x86_64/Rocky-9.0-x86_64-dvd.iso \u5b89\u88c5\u65f6\u6211\u9009\u62e9\u4e86\u6fc0\u6d3b root \u7528\u6237\uff0c\u9009\u62e9\u4e86Server\u6a21\u5f0f\u5b89\u88c5\uff08\u6ca1\u6709GUI\uff09\u3002 \u4ee5 root \u767b\u5f55\uff0c\u6267\u884c\u4e0b\u9762\u547d\u4ee4\u4fee\u6539 sudo \u6743\u9650\u3002 visudo \u5e76\u6fc0\u6d3b\u4e0b\u9762\u4e00\u884c\uff08\u4e0d\u8bbe\u5bc6\u7801\uff0c\u65b9\u4fbf\u7ec3\u4e60\uff09\uff1a %wheel ALL =( ALL ) NOPASSWD: ALL \u521b\u5efa\u7528\u6237 vagrant \uff0c\u5e76\u8bbe\u7f6e wheel \u4e3a\u4e3b\u8981\u7ec4\u548c\u4fee\u6539\u5bc6\u7801\u3002 adduser vagrant usermod -g wheel vagrant passwd vagrant \u8bbe\u5b9ahostname\uff08\u5305\u62ec\u522b\u540d\uff09\uff0c\u5e76\u67e5\u770b\u7ed3\u679c\u3002 hostnamectl set-hostname --static \"rocky9\" hostnamectl set-hostname --pretty \"rocky9\" hostnamectl cat /etc/hostname \u5c0f\u8d34\u58eb\uff1a \u7531systemd\u63a7\u5236\u7684\u4e3b\u673a\u540d\u7684\u670d\u52a1\u914d\u7f6e\u4fe1\u606f\uff1a /usr/lib/systemd/system/systemd-hostnamed.service Rocky\u7684\u8f6f\u4ef6\u6e90\u7684\u914d\u7f6e\u4fe1\u606f\u4fdd\u5b58\u5728\u76ee\u5f55 /etc/yum.repos.d/ \u4e0b\u3002\u5982\u679c\u8bbf\u95ee\u9ed8\u8ba4\u6e90\u6bd4\u8f83\u6162\uff0c\u53ef\u4ee5\u66f4\u65b0\u963f\u91cc\u6e90\u6216\u8005\u79d1\u5927\u6e90\u3002 \u66f4\u6362\u963f\u91cc\u6e90\u3002 sed -e 's|^mirrorlist=|#mirrorlist=|g' \\ -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \\ -i.bak \\ /etc/yum.repos.d/Rocky-*.repo \u66f4\u6362\u79d1\u5927\u6e90\u3002 sed -e 's|^mirrorlist=|#mirrorlist=|g' \\ -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.ustc.edu.cn/rocky|g' \\ -i.bak \\ /etc/yum.repos.d/rocky-extras.repo \\ /etc/yum.repos.d/rocky.repo \u5237\u65b0\u7f13\u5b58\u3002 dnf makecache 2.2.Ubuntu \u00b6 \u4f7f\u7528\u7248\u672c\uff1a Ubuntu 2204 \u3002 \u8bbe\u5b9aroot\u7528\u6237\u7684\u5bc6\u7801\u3002 sudo passwd root \u901a\u8fc7\u5b89\u88c5\u65f6\u5df2\u521b\u5efa\u7684\u7528\u6237 vagrant \u767b\u5f55\u3002\u6267\u884c\u4e0b\u9762\u547d\u4ee4\u4fee\u6539 sudo \u6743\u9650\u3002 sudo visudo \u6dfb\u52a0 vagrant \u5230\u7279\u6743\u7528\u6237\uff08Rocky\u548copenSUSE\u4e0d\u9700\u8981\u6dfb\u52a0\uff09\uff0c\u5e76\u6fc0\u6d3bsudo\u4e00\u884c\uff08\u4e0d\u8bbe\u5bc6\u7801\uff0c\u65b9\u4fbf\u7ec3\u4e60\uff09\uff1a # User privilege specification root ALL =( ALL:ALL ) ALL vagrant ALL =( ALL:ALL ) ALL # Allow members of group sudo to execute any command sudo ALL =( ALL:ALL ) NOPASSWD: ALL \u4fee\u6539\u7528\u6237 vagrant \u7684\u4e3b\u8981\u7ec4\u4e3a sudo \u3002 sudo usermod -g sudo vagrant \u4fee\u6539\u4e3b\u673a\u540d\u548c\u522b\u540d\u3002 sudo hostnamectl set-hostname ubuntu2204 sudo hostnamectl set-hostname ubuntu2204 --pretty \u5c0f\u8d34\u58eb\uff1a \u5982\u4f55\u5904\u7406 Username is not in the sudoers file. This incident will be reported \u95ee\u9898\u3002 \u5982\u679c\u6ca1\u6709\u521d\u59cb\u5316 root \u7528\u6237\u7684\u5bc6\u7801\uff0c\u4e14\u5f53\u524d\u7528\u6237\u4e5f\u65e0\u6cd5\u6267\u884c sudo \u547d\u4ee4\uff0c\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u6b65\u9aa4\u901a\u8fc7recovery\u6551\u63f4\u6a21\u5f0f\u8fdb\u884c\u6062\u590d\u3002 \u6309 shift \u952e\u5f00\u673a\uff0c\u8fdb\u5165grub\u542f\u52a8\u83dc\u5355\u3002\uff08VMWare\u4e5f\u9002\u7528\uff09 \u5411\u4e0b\u79fb\u52a8\u9ad8\u4eae\u6761\uff0c\u9009\u62e9\u83dc\u5355 Advanced options for Ubuntu \uff0c\u5e76\u786e\u8ba4\u56de\u8f66\u3002 \u9009\u62e9\u5e26\u6709 recovery mode \u7684\u5185\u6838\uff0c\u786e\u8ba4\u56de\u8f66\u3002 \u5411\u4e0b\u79fb\u52a8\u9ad8\u4eae\u6761\uff0c\u9009\u62e9\u83dc\u5355 root Drop to root shell prompt \uff0c\u5e76\u786e\u8ba4\u56de\u8f66\u3002 \u56de\u8f66\u786e\u8ba4 press Enter for maintenance \u3002 \u51fa\u73b0 root \u7684\u547d\u4ee4\u63d0\u793a\u7b26\u540e\uff0c\u6267\u884c\u547d\u4ee4 mount -o rw,remount / \u3002 \u6267\u884c\u547d\u4ee4 passwd \u7ed9 root \u8bbe\u5b9a\u5bc6\u7801\u3002 \u6267\u884c\u547d\u4ee4 adduser username sudo \u628a\u6307\u5b9a\u7528\u6237\u52a0\u5165 sudo \u7ec4\u3002 \u6267\u884c\u547d\u4ee4 visudo \u8fdb\u884c\u5fc5\u8981\u7684\u4fee\u6b63\u6216\u4fee\u6539\u3002 2.3.openSUSE \u00b6 \u4f7f\u7528\u7248\u672c\uff1a Leap 15.4 \u3002 \u9009\u62e9\u670d\u52a1\u5668\u6a21\u5f0f\u5b89\u88c5\uff0c\u65e0\u56fe\u5f62\u754c\u9762\u3002\u5b89\u88c5\u4e2d\u4e0d\u521b\u5efa\u7528\u6237\u3002 \u521b\u5efa\u7528\u6237 vagrant \uff0c\u5e76\u8bbe\u7f6e wheel \u4e3a\u4e3b\u8981\u7ec4\u3002 useradd -m -g wheel -G root -c \"vagrant\" vagrant passwd vagrant \u6267\u884c visudo \u547d\u4ee4\uff0c\u6fc0\u6d3b\u4e0b\u9762\u4e00\u884c\uff0c\u6dfb\u52a0 sudo \u6743\u9650\u3002 % wheel ALL =( ALL ) NOPASSWD: ALL \u4fee\u6539\u4e3b\u673a\u540d\u548c\u522b\u540d\u3002 sudo hostnamectl set-hostname lizard sudo hostnamectl set-hostname lizard --pretty 3.\u5e38\u7528\u547d\u4ee4 \u00b6 \u8bf4\u660e\uff1a \u9ed8\u8ba4\u5f53\u524d\u64cd\u4f5c\u7528\u6237\u4e3a vagrant \u3002 3.1.\u4fee\u6539\u63d0\u793a\u7b26\u98ce\u683c \u00b6 \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u770b\u5230\u5f53\u524d\u7cfb\u7edf\u7684\u547d\u4ee4\u63d0\u793a\u7b26\u683c\u5f0f\u3002 echo $PS1 \u5404\u7cfb\u7edf\u9ed8\u8ba4\u8bbe\u7f6e\u662f\u6709\u5dee\u5f02\u7684\u3002 # Rocky [ \\u @ \\h \\W ] \\$ # Ubuntu \\[\\e ] 0 ; \\u @ \\h : \\w\\a\\] ${ debian_chroot :+( $debian_chroot ) } \\[\\0 33 [ 01 ; 32m \\]\\u @ \\h\\[\\0 33 [ 00m \\] : \\[\\0 33 [ 01 ; 34m \\]\\w\\[\\0 33 [ 00m \\]\\$ # openSUSE \\u @ \\h : \\w > \u5c0f\u8d34\u58eb\uff1a bash\u53ef\u8bc6\u522b\u7684\u8f6c\u4e49\u5e8f\u5217\u6709\u4e0b\u9762\u8fd9\u4e9b\uff1a \\u : \u5f53\u524d\u7528\u6237\u7684\u8d26\u53f7\u540d\u79f0 \\h : \u4e3b\u673a\u540d\u7b2c\u4e00\u90e8\u5206 \\H : \u5b8c\u6574\u7684\u4e3b\u673a\u540d\u79f0 \\w : \u5b8c\u6574\u7684\u5de5\u4f5c\u76ee\u5f55\u540d\u79f0\uff08\u5982 \"/home/username/mywork\"\uff09 \\W : \u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u7684\"\u57fa\u540d (basename)\"\uff08\u5982 \"mywork\") \\t : \u663e\u793a\u65f6\u95f4\u4e3a24\u5c0f\u65f6\u683c\u5f0f\uff0c\u5982\uff1aHH:MM:SS \\T : \u663e\u793a\u65f6\u95f4\u4e3a12\u5c0f\u65f6\u683c\u5f0f \\A : \u663e\u793a\u65f6\u95f4\u4e3a24\u5c0f\u65f6\u683c\u5f0f\uff1aHH:MM \\@ : \u5e26\u6709 am/pm \u7684 12 \u5c0f\u65f6\u5236\u65f6\u95f4 \\d : \u4ee3\u8868\u65e5\u671f\uff0c\u683c\u5f0f\u4e3aweekday month date\uff0c\u4f8b\u5982\uff1a\"Mon Aug 1\" \\s : shell \u7684\u540d\u79f0\uff08\u5982 \"bash\") \\v : bash\u7684\u7248\u672c\uff08\u5982 2.04\uff09 \\V : bash\u7684\u7248\u672c\uff08\u5305\u62ec\u8865\u4e01\u7ea7\u522b\uff09 \\n : \u6362\u884c\u7b26 \\r : \u56de\u8f66\u7b26 \\\\ : \u53cd\u659c\u6760 \\a : ASCII \u54cd\u94c3\u5b57\u7b26\uff08\u4e5f\u53ef\u4ee5\u952e\u5165 07 \uff09 \\e : ASCII \u8f6c\u4e49\u5b57\u7b26\uff08\u4e5f\u53ef\u4ee5\u952e\u5165 33 ) \\[ : \u8fd9\u4e2a\u5e8f\u5217\u5e94\u8be5\u51fa\u73b0\u5728\u4e0d\u79fb\u52a8\u5149\u6807\u7684\u5b57\u7b26\u5e8f\u5217\uff08\u5982\u989c\u8272\u8f6c\u4e49\u5e8f\u5217\uff09\u4e4b\u524d\u3002\u5b83\u4f7fbash\u80fd\u591f\u6b63\u786e\u8ba1\u7b97\u81ea\u52a8\u6362\u884c \\] : \u8fd9\u4e2a\u5e8f\u5217\u5e94\u8be5\u51fa\u73b0\u5728\u975e\u6253\u5370\u5b57\u7b26\u5e8f\u5217\u4e4b\u540e \\# : \u4e0b\u8fbe\u7684\u7b2c\u51e0\u4e2a\u547d\u4ee4 \\$ : \u63d0\u793a\u5b57\u7b26\uff0c\u5982\u679c\u662froot\u7528\u6237\uff0c\u63d0\u793a\u7b26\u4e3a # \uff0c\u666e\u901a\u7528\u6237\u5219\u4e3a $ \u5728PS1\u4e2d\u8bbe\u7f6e\u5b57\u7b26\u989c\u8272\u7684\u683c\u5f0f\u4e3a\uff1a [\\e[F;Bm]........[\\e[0m] \uff0c\u5176\u4e2d [\\e[0m] \u4f5c\u4e3a\u989c\u8272\u8bbe\u5b9a\u7684\u7ed3\u675f\u3002 \u5176\u4e2d\"F\"\u4e3a\u5b57\u4f53\u989c\u8272\uff0c\u7f16\u53f7\u4e3a30-37\uff0c\"B\"\u4e3a\u80cc\u666f\u989c\u8272\uff0c\u7f16\u53f7\u4e3a40-47\u3002 \u5c0f\u8d34\u58eb\uff1a \u989c\u8272\u5bf9\u7167\u8868: F:30 , B:40 : \u9ed1\u8272 F:31 , B:41 : \u7ea2\u8272 F:32 , B:42 : \u7eff\u8272 F:33 , B:43 : \u9ec4\u8272 F:34 , B:44 : \u84dd\u8272 F:35 , B:45 : \u7d2b\u7ea2\u8272 F:36 , B:46 : \u9752\u84dd\u8272 F:37 , B:47 : \u767d\u8272 \u4ee5\u4e0b\u9762\u7684PS1\u8bbe\u5b9a\u4e3a\u4f8b\u8bf4\u660e\u989c\u8272\u8bbe\u5b9a\u3002 PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[37;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" \u62c6\u89e3\u5206\u6790\uff1a PS1=\" \\[\\e[37;40m\\] # \u6574\u4e2a\u63d0\u793a\u7b26\u533a\u57df\u524d\u666f\u767d\u8272\uff0c\u80cc\u666f\u9ed1\u8272 [ # \u663e\u793a\u5b57\u7b26[ \\[\\e[32;40m\\] # \u4fee\u9970\u540e\u9762\u7684\\u\uff0c\u524d\u666f\u7eff\u8272\uff0c\u80cc\u666f\u9ed1\u8272 \\u # \u663e\u793a\u5f53\u524d\u7528\u6237\u7684\u8d26\u53f7\u540d\u79f0 \\[\\e[37;40m\\] # \u4fee\u9970\u540e\u9762\u7684\u5b57\u7b26@\u548c\u4e3b\u673a\u540d @ # \u663e\u793a\u5b57\u7b26@ \\h # \u663e\u793a\u4e3b\u673a\u540d : # \u663e\u793a\u5b57\u7b26: \\[\\e[36;40m\\] # \u4fee\u9970\u540e\u9762\u7684\\w\uff0c\u524d\u666f\u9752\u84dd\u8272\uff0c\u80cc\u666f\u9ed1\u8272 \\w # \u663e\u793a\u5b8c\u6574\u5de5\u4f5c\u76ee\u5f55 \\[\\e[0m\\] # \u7ed3\u675f\u989c\u8272\u8bbe\u5b9a ] # \u663e\u793a\u5b57\u7b26] \\$\" # \u5982\u679c\u662froot\u7528\u6237\uff0c\u63d0\u793a\u7b26\u4e3a# \uff0c\u666e\u901a\u7528\u6237\u5219\u4e3a$ \u5bf9\u4e0d\u540c\u4e3b\u673a\u505a\u4e0d\u540c\u8bbe\u7f6e\uff1a # Rocky PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[37;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" # Ubuntu PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[33;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" # openSUSE PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[35;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" \u5c06\u4e0a\u8ff0PS1\u7684\u8bbe\u5b9a\uff0c\u8ffd\u52a0\u5230\u5f53\u524d\u7528\u6237\u7684 ~/.bashrc \u6587\u4ef6\u672b\u5c3e\uff0c\u4ee5\u5b9e\u73b0\u5bf9\u5f53\u524d\u7528\u6237\u7684\u63d0\u793a\u7b26\u98ce\u683c\u505a\u6301\u4e45\u4fdd\u5b58\u3002 3.2.Linux\u7684\u5185\u5916\u90e8\u547d\u4ee4 \u00b6 \u5185\u90e8\u547d\u4ee4 (internal command)\u5b9e\u9645\u4e0a\u662fshell\u7a0b\u5e8f\u7684\u4e00\u90e8\u5206\uff0c\u5305\u542b\u7684\u662f\u4e00\u4e9b\u6bd4\u8f83\u7b80\u5355\u7684linux\u7cfb\u7edf\u547d\u4ee4\uff0c\u8fd9\u4e9b\u547d\u4ee4\u7531shell\u7a0b\u5e8f\u8bc6\u522b\u5e76\u5728shell\u7a0b\u5e8f\u5185\u90e8\u5b8c\u6210\u8fd0\u884c\uff0c\u901a\u5e38\u5728linux\u7cfb\u7edf\u52a0\u8f7d\u8fd0\u884c\u65f6shell\u5c31\u88ab\u52a0\u8f7d\u5e76\u9a7b\u7559\u5728\u7cfb\u7edf\u5185\u5b58\u4e2d\u3002 \u5916\u90e8\u547d\u4ee4 (external command)\u662flinux\u7cfb\u7edf\u4e2d\u7684\u5b9e\u7528\u7a0b\u5e8f\u90e8\u5206\uff0c\u7cfb\u7edf\u52a0\u8f7d\u65f6\u5e76\u4e0d\u968f\u7cfb\u7edf\u4e00\u8d77\u88ab\u52a0\u8f7d\u5230\u5185\u5b58\u4e2d\uff0c\u800c\u662f\u5728\u9700\u8981\u65f6\u624d\u5c06\u5176\u8c03\u7528\u5185\u5b58\u3002\u901a\u5e38\u5916\u90e8\u547d\u4ee4\u7684\u5b9e\u4f53\u5e76\u4e0d\u5305\u542b\u5728shell\u4e2d\uff0c\u4f46\u662f\u5176\u547d\u4ee4\u6267\u884c\u8fc7\u7a0b\u662f\u7531shell\u7a0b\u5e8f\u63a7\u5236\u7684\u3002 \u6bd4\u5982\uff1a \u6267\u884c\u547d\u4ee4 type -t cp \uff0c\u7cfb\u7edf\u8fd4\u56de\u7ed3\u679c\u662f file \uff0c\u5916\u90e8\u547d\u4ee4\u3002 \u6267\u884c\u547d\u4ee4 type -t cd \uff0c\u7cfb\u7edf\u8fd4\u56de\u7ed3\u679c builtin \uff0c\u5185\u90e8\u547d\u4ee4\u3002 \u6267\u884c\u547d\u4ee4 enable -a cp \uff0c\u7cfb\u7edf\u8fd4\u56de -bash: enable: cp: not a shell builtin \uff0c\u4e5f\u53ef\u4ee5\u5224\u65ad\u662f\u5426\u4e3a\u5185\u90e8\u547d\u4ee4\u3002 \u5bf9\u4e8e\u5185\u90e8\u547d\u4ee4\uff0c\u53ef\u4ee5\u901a\u8fc7enable\u547d\u4ee4\u6765\u542f\u7528\u6216\u8005\u7981\u7528\u3002 # \u7981\u7528cd\u547d\u4ee4 enable -n cd # \u67e5\u770b\u6240\u6709\u88ab\u7981\u7528\u7684\u547d\u4ee4 enable -n # \u542f\u7528cd\u547d\u4ee4 enable cd \u5bf9\u4e8e\u547d\u4ee4\uff0c\u53ef\u4ee5\u901a\u8fc7 whereis \u547d\u4ee4\u6765\u67e5\u770b\u8def\u5f84\u3002 whereis cp whereis cd 3.3.CPU\u4fe1\u606f \u00b6 lscpu cat /proc/cpuinfo 3.4.\u5185\u5b58\u4f7f\u7528\u72b6\u6001 \u00b6 free cat /proc/meminfo 3.5.\u786c\u76d8\u548c\u5206\u533a\u60c5\u51b5 \u00b6 lsblk openSUSE\u5728VMWare\u9ed8\u8ba4\u5b89\u88c5\u7684\u72b6\u6001\uff1a NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8 :0 0 200G 0 disk \u251c\u2500sda1 8 :1 0 8M 0 part \u251c\u2500sda2 8 :2 0 198G 0 part /home \u2502 /var \u2502 /opt \u2502 /usr/local \u2502 /root \u2502 /tmp \u2502 /srv \u2502 /boot/grub2/x86_64-efi \u2502 /boot/grub2/i386-pc \u2502 /.snapshots \u2502 / \u2514\u2500sda3 8 :3 0 2G 0 part [ SWAP ] sr0 11 :0 1 3 .8G 0 rom Ubuntu\u5728VMWare\u9ed8\u8ba4\u5b89\u88c5\u7684\u72b6\u6001\uff1a NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7 :0 0 61 .9M 1 loop /snap/core20/1405 loop1 7 :1 0 63 .2M 1 loop /snap/core20/1623 loop2 7 :2 0 79 .9M 1 loop /snap/lxd/22923 loop3 7 :3 0 48M 1 loop /snap/snapd/17029 loop4 7 :4 0 103M 1 loop /snap/lxd/23541 loop5 7 :5 0 48M 1 loop /snap/snapd/17336 sda 8 :0 0 50G 0 disk \u251c\u2500sda1 8 :1 0 1M 0 part \u251c\u2500sda2 8 :2 0 2G 0 part /boot \u2514\u2500sda3 8 :3 0 48G 0 part \u2514\u2500ubuntu--vg-ubuntu--lv 253 :0 0 24G 0 lvm / sr0 11 :0 1 1 .4G 0 rom Rocky\u5728VMWare\u9ed8\u8ba4\u5b89\u88c5\u7684\u72b6\u6001\uff1a NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8 :0 0 50G 0 disk \u251c\u2500sda1 8 :1 0 1G 0 part /boot \u2514\u2500sda2 8 :2 0 49G 0 part \u251c\u2500rl-root 253 :0 0 45 .1G 0 lvm / \u2514\u2500rl-swap 253 :1 0 3 .9G 0 lvm [ SWAP ] sr0 11 :0 1 7 .9G 0 rom 3.6.\u7cfb\u7edf\u67b6\u6784\u4fe1\u606f \u00b6 arch openSUSE\uff0cUbuntu\u548cRocky\u7684\u8fd4\u56de\u7ed3\u679c\u90fd\u662f x86_64 \u3002 3.7.\u5185\u6838\u7248\u672c \u00b6 uname -r \u4e09\u4e2a\u53d1\u884c\u7248\u8fd4\u56de\u7684\u7ed3\u679c\u4e0d\u5c3d\u76f8\u540c\uff1a # openSUSE 5 .14.21-150400.24.21-default # Ubuntu 5 .15.0-52-generic # Rocky 5 .14.0-70.17.1.el9_0.x86_64 3.8.\u64cd\u4f5c\u7cfb\u7edf\u7248\u672c \u00b6 cat /etc/os-release cat /etc/issue # Rocky 9 sudo cat /etc/redhat-release lsb-release -a lsb_release -cs lsb_release -is lsb_release -rs \u5728openSUSE\u4e2d\uff0c\u9700\u8981\u5b89\u88c5 lsb-release \u5305\u3002\u6267\u884c lsb-release -a \u548c lsb_release -a \u8fd4\u56de\u7684\u7ed3\u679c\u662f\u4e00\u6837\u7684\u3002 sudo zypper in lsb-release \u5728Ubuntu\u4e2d\uff0c\u9700\u8981\u5b89\u88c5 lsb-release \u5305\u3002\u53ea\u80fd\u6267\u884c lsb_release -a \u3002 sudo apt install lsb-release \u5728Rocky 9\u4e2d\uff0c\u627e\u4e0d\u5230 lsb-release \u76f8\u5173\u7684\u5305\u3002 3.9.\u65e5\u671f\u548c\u65f6\u95f4 \u00b6 \u663e\u793a\u9ed8\u8ba4\u683c\u5f0f\u7684\u5f53\u524d\u65e5\u671f\u3002 date \u4e09\u4e2a\u7cfb\u7edf\u7684\u9ed8\u8ba4\u65e5\u671f\u683c\u5f0f\u7565\u6709\u4e0d\u540c\u3002 # openSUSE Mon 24 Oct 2022 09 :28:06 AM CST # Ubuntu Mon Oct 24 01 :28:09 AM UTC 2022 # Rocky Mon Oct 24 09 :24:01 AM CST 2022 \u663e\u793a\u81ea1970-01-01 00:00:00 UTC\u5230\u5f53\u524d\u7684\u79d2\u6570\u3002 date +%s \u5c06\u4e0a\u4e00\u547d\u4ee4\u4e2d\u7684\u63cf\u8ff0\u8f6c\u6362\u4e3a\u7cfb\u7edf\u9ed8\u8ba4\u65e5\u671f\u683c\u5f0f\u3002 date -d @ ` date +%s ` date --date = @ '1666575347' \u663e\u793a\u786c\u4ef6\u65f6\u949f\u3002 hwclock \u4e5f\u88ab\u79f0\u4e3a Real Time Clock (RTC)\u3002 \u5728Rocky9\u4e2d\uff0c clock \u6709\u4e00\u4e2a\u8f6f\u8fde\u63a5\u6307\u5411 hwclock \uff1a /usr/sbin/clock -> hwclock \u3002\u5728openSUSE\u548cUbuntu\u4e2d\u53ea\u6709 hwclock \u3002 ll /usr/sbin/clock ll /usr/sbin/hwclock \u8bfb\u53d6RTC\u65f6\u95f4\u3002 sudo hwclock --get sudo hwclock -r \u6821\u51c6\u65f6\u95f4\uff1a -s, \u2013hctosys : \u4ee5RTC\u786c\u4ef6\u65f6\u95f4\u6765\u6821\u51c6\u7cfb\u7edf\u65f6\u95f4\u3002 -w, \u2013systohoc : \u4ee5\u7cfb\u7edf\u65f6\u95f4\u6765\u6821\u51c6RTC\u786c\u4ef6\u65f6\u95f4\u3002 \u663e\u793a\u5f53\u524d\u7cfb\u7edf\u65f6\u533a\u3002 ll /etc/localtime \u7cfb\u7edf\u53ef\u80fd\u4f1a\u8fd4\u56de\u4e0d\u540c\u7ed3\u679c\uff0c\u4f8b\u5982\uff1a /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai /etc/localtime -> /usr/share/zoneinfo/Etc/UTC \u663e\u793a\u5f53\u524d\u53ef\u4ee5\u65f6\u533a\u5217\u8868\u3002 timedatectl list-timezones timedatectl list-timezones | grep -i Asia \u4fee\u6539\u5f53\u524d\u7cfb\u7edf\u65f6\u533a\u3002 sudo timedatectl set-timezone Asia/Shanghai \u663e\u793a\u65e5\u5386\u3002 cal -y openSUSE\u548cRocky\u4e2d\uff0c\u4f7f\u7528 cal \u547d\u4ee4\u9700\u8981\u5b89\u88c5 util-linux \u5305\u3002 Ubuntu\u4e2d\uff0c\u4f7f\u7528 cal \u547d\u4ee4\u9700\u8981\u5b89\u88c5 ncal \u5305\u3002 sudo apt install ncal sudo zypper se util-linux sudo yum install util-linux 3.10.\u7528\u6237\u767b\u5f55\u4fe1\u606f \u00b6 whoami \uff1a\u5f53\u524d\u767b\u5f55\u7528\u6237 who \uff1a\u7cfb\u7edf\u5f53\u524d\u6240\u6709\u7684\u767b\u5f55\u4f1a\u8bdd w \uff1a\u7cfb\u7edf\u5f53\u524d\u6240\u6709\u7684\u767b\u5f55\u4f1a\u8bdd\u53ca\u6240\u4f5c\u7684\u64cd\u4f5c \u63d0\u793a\uff1a MOTD is the abbreviation of \"Message Of The Day\", and it is used to display a message when a remote user login to the Linux Operating system using SSH. Linux administrators often need to display different messages on the login of the user, like displaying custom information about the server or any necessary information. \u7f16\u8f91\u6587\u4ef6 /etc/motd \u53ef\u4ee5\u81ea\u5b9a\u4e49\"Message Of The Day\"\u7684\u4fe1\u606f\u3002 Ubuntu 2204\u65b0\u5b89\u88c5\u540e\u6ca1\u6709\u8fd9\u4e2a\u6587\u4ef6\uff0c\u9700\u8981\u81ea\u5df1\u521b\u5efa\u3002 openSUSE\u65b0\u5b89\u88c5\u540e\u6709\u9884\u5b9a\u4e49\u7684\u4fe1\u606f\u3002 Rocky9 \u65b0\u5b89\u88c5\u540e\u6709\u8be5\u6587\u4ef6\uff0c\u7a7a\u767d\u6587\u4ef6\u65e0\u5185\u5bb9\u3002 3.11.\u4f1a\u8bdd\u7ba1\u7406\u5de5\u5177 \u00b6 screen \u5de5\u5177 screen -S (Create new screen session) screen -ls (list current screen sessions) screen -x (Attach to existing screeen session, sync between both) screen -r (Reattach existing screen session) tmux \u5de5\u5177 tmux \u662f\u6307 Terminal Multiplexer . \u5b89\u88c5 tmux \u5de5\u5177\u3002 # Rocky sudo yum install tmux # Ubuntu sudo apt install tmux # openSUSE sudo zypper in tmux \u5e38\u7528\u65b9\u6cd5\uff1a tmux new -s (Create new session) tmux detach (Detach current session) tmux ls (list current sessions) tmux attach -t (Reattach existing session) tmux switch -t (Switch to another session) tmux kill-session -t (Kill existing session) tmux list-keys (List all short keys) tmux list-commands (List commands and parameters) tmux info (List all sessions info) tmux split-window (Split window) 3.12. echo \u547d\u4ee4 \u00b6 echo \u547d\u4ee4\u4e2d\u53ef\u4ee5\u8f93\u51fa\u53d8\u91cf\uff0c\u5982\u679c\u53d8\u91cf\u662f\u7528\u662f\u5355\u5f15\u53f7\u5f15\u8d77\u6765\uff0c\u8868\u793a\u8fd9\u4e2a\u53d8\u91cf\u4e0d\u7528IFS\u66ff\u6362\uff01\uff01 echo \"Home=$HOME\" \u7684\u8f93\u51fa\u7ed3\u679c\u662f Home=/home/vagrant echo 'Home=$HOME' \u7684\u8f93\u51fa\u7ed3\u679c\u662f Home=$HOME echo -e \u542f\u7528 \\ \u5b57\u7b26\u7684\u89e3\u91ca\u529f\u80fd\uff0c\u6bd4\u5982\uff1a echo -e \"a\\x0Ab\" \uff0c\u8f93\u51fa\u5b57\u7b26 a \u548c b \uff0c\u4e2d\u95f4 \\x0A \u4ee3\u8868\u5341\u516d\u8fdb\u5236 OA \uff08\u5373\u56de\u8f66\uff09 echo -e \"\\x4A \\x41 \\x4D \\x45 \\x53\" \uff0c\u8f93\u51fa\u7ed3\u679c\u662f J A M E S \u63d0\u793a\uff1a \u4ee5\u901a\u8fc7man 7 ascii\u6765\u67e5\u770b\u5404\u8fdb\u5236\u7684\u542b\u4e49\u3002 echo -e \u8f93\u51fa\u5e26\u989c\u8272\u5b57\u7b26\u3002 \u793a\u4f8b\uff1a echo -e \"\\e[35m \u7d2b\u8272 \\e[0m\" echo -e \"\\e[43m \u9ec4\u5e95 \\e[0m\" echo -e \"\\e[93m \u9ed1\u5e95\u9ec4\u5b57 \\e[0m\" \u53c2\u8003\u4fe1\u606f\uff1a \u5b57\u4f53\u989c\u8272\uff1a \\e[30m \uff1a \u9ed1\u8272 \\e[31m \uff1a \u7ea2\u8272 \\e[32m \uff1a \u7eff\u8272 \\e[33m \uff1a \u9ec4\u8272 \\e[34m \uff1a \u84dd\u8272 \\e[35m \uff1a \u7d2b\u8272 \\e[36m \uff1a \u9752\u8272 \\e[37m \uff1a \u767d\u8272 \\e[40m \uff1a \u9ed1\u5e95 \\e[41m \uff1a \u7ea2\u5e95 \\e[42m \uff1a \u7eff\u5e95 \\e[43m \uff1a \u9ec4\u5e95 \\e[44m \uff1a \u84dd\u5e95 \\e[45m \uff1a \u7d2b\u5e95 \\e[46m \uff1a \u9752\u5e95 \\e[47m \uff1a \u767d\u5e95 \u80cc\u666f\u989c\u8272\uff1a \\e[90m \uff1a \u9ed1\u5e95\u9ed1\u5b57 \\e[91m \uff1a \u9ed1\u5e95\u7ea2\u5b57 \\e[92m \uff1a \u9ed1\u5e95\u7eff\u5b57 \\e[93m \uff1a \u9ed1\u5e95\u9ec4\u5b57 \\e[94m \uff1a \u9ed1\u5e95\u84dd\u5b57 \\e[95m \uff1a \u9ed1\u5e95\u7d2b\u5b57 \\e[96m \uff1a \u9ed1\u5e95\u9752\u5b57 \\e[97m \uff1a \u9ed1\u5e95\u767d\u5b57 \u63a7\u5236\u5c5e\u6027\uff1a \\e[0m \u5173\u95ed\u6240\u6709\u5c5e\u6027 \\e[1m \u8bbe\u7f6e\u9ad8\u4eae\u5ea6 \\e[4m \u4e0b\u5212\u7ebf \\e[5m \u95ea\u70c1 \\e[7m \u53cd\u663e\uff0c\u649e\u8272\u663e\u793a\uff0c\u663e\u793a\u4e3a\u767d\u5b57\u9ed1\u5e95\uff0c\u6216\u8005\u663e\u793a\u4e3a\u9ed1\u5e95\u767d\u5b57 \\e[8m \u6d88\u5f71\uff0c\u5b57\u7b26\u989c\u8272\u5c06\u4f1a\u4e0e\u80cc\u666f\u989c\u8272\u76f8\u540c \\e[nA \u5149\u6807\u4e0a\u79fb n \u884c \\e[nB \u5149\u6807\u4e0b\u79fb n \u884c \\e[nC \u5149\u6807\u53f3\u79fb n \u884c \\e[nD \u5149\u6807\u5de6\u79fb n \u884c \\e[y;xH \u8bbe\u7f6e\u5149\u6807\u4f4d\u7f6e \\e[2J \u6e05\u5c4f \\e[K \u6e05\u9664\u4ece\u5149\u6807\u5230\u884c\u5c3e\u7684\u5185\u5bb9 \\e[s \u4fdd\u5b58\u5149\u6807\u4f4d\u7f6e \\e[u \u6062\u590d\u5149\u6807\u4f4d\u7f6e \\e[?25 \u9690\u85cf\u5149\u6807 \\e[?25h \u663e\u793a\u5149\u6807 3.13. man \u547d\u4ee4 \u00b6 \u5b89\u88c5\u5305\uff1a # openSUSE sudo zypper install man-pages man-pages-zh_CN man-pages-posix # Rocky sudo yum install man-pages # Ubuntu sudo apt install man-db manpages-posix manpages manpages-zh sudo apt install manpages-dev manpages-posix-dev \u66f4\u65b0mandb mandb \u67e5\u627e\u67d0\u4e2a\u547d\u4ee4\u7684man\u4fe1\u606f\uff0c\u4f8b\u5982\u67e5\u627e crontab \u547d\u4ee4\u7684\u4fe1\u606f\u3002 # \u7cbe\u786e\u67e5\u627e man -f crontab whatis crontab # \u6a21\u7cca\u67e5\u8be2 man -k crontab apropos crontab \u8f93\u51fa\u7ed3\u679c\u5982\u4e0b\uff1a crontab (5) - files used to schedule the execution of programs crontab (1) - maintains crontab files for individual users crontab (1p) - schedule periodic background work \u67e5\u627ecrontab\u7b2c5\u7ae0\u7684\u5185\u5bb9\uff0c\u5219\u53ef\u4ee5\u6267\u884c\uff1a man 5 crontab \u5e38\u7528\u5feb\u6377\u952e\u793a\u4f8bs\uff1a 1G : go to the 1 st line 10G : go to the 10 th line G : go to the end of the page /^SELinux : search the word SELinux /section OPTIONS : go to the section OPTIONS 3.14. tr \u547d\u4ee4 \u00b6 tr \u547d\u4ee4\u53ef\u4ee5\u5bf9\u6765\u81ea\u6807\u51c6\u8f93\u5165\u7684\u5b57\u7b26\u8fdb\u884c\u66ff\u6362\u3001\u538b\u7f29\u548c\u5220\u9664\u3002\u5b83\u53ef\u4ee5\u5c06\u4e00\u7ec4\u5b57\u7b26\u53d8\u6210\u53e6\u4e00\u7ec4\u5b57\u7b26\u3002 \u683c\u5f0f\uff1a tr [OPTION]... SET1 [SET2] \u4e3e\u4f8b\uff1a # \u5c06\u8f93\u5165\u5b57\u7b26\u7531\u5927\u5199\u8f6c\u6362\u4e3a\u5c0f\u5199 $ echo \"HELLO WORLD\" | tr 'A-Z' 'a-z' hello world # \u5220\u9664\u51fa\u73b0\u7684\u6570\u5b57 $ echo \"HELLO 1234 WORLD 4567\" | tr -d '0-9' HELLO WORLD # \u4ece\u8f93\u5165\u6587\u672c\u4e2d\u5c06\u4e0d\u5728\u8865\u96c6\u4e2d\u7684\u6240\u6709\u5b57\u7b26\u5220\u9664\uff08\u53ea\u4fdd\u7559\u6570\u5b571\uff0c2\uff0c3\uff0c4\uff0c5\uff09 $ echo \"HELLO 1234 WORLD 4567\" | tr -d -c '1-5' 123445 # \u5c06\u8fde\u7eed\u91cd\u590d\u7684\u5b57\u7b26\u4ee5\u5355\u72ec\u4e00\u4e2a\u5b57\u7b26\u8868\u793a $ echo \"HELLOOO 1222235555555554\" | tr -s 'O215' HELLO 12354 # \u5220\u9664\u7531\u4e8eWindows\u6587\u4ef6\u9020\u6210\u7684'^M'\u5b57\u7b26 $ cat file.txt | tr -s '\\r' '\\n' > new.txt $ cat file.txt | tr -d '\\r' > new.txt # \u5c06\u6362\u884c\u7b26\u66ff\u6362\u6210\u5236\u8868\u7b26 $ cat file.txt | tr '\\n' '\\t' > new.txt # \u5c06\u5927\u5199\u5b57\u6bcd\u8f6c\u6362\u4e3a\u5c0f\u5199\u5b57\u6bcd $ echo \"HELLO 1234 WORLD 4567\" | tr '[:upper:]' '[:lower:]' hello 1234 world 4567 3.15. tee \u547d\u4ee4 \u00b6 tee \u547d\u4ee4\u57fa\u4e8e\u6807\u51c6\u8f93\u5165\u8bfb\u53d6\u6570\u636e\uff0c\u6807\u51c6\u8f93\u51fa\u6216\u6587\u4ef6\u5199\u5165\u6570\u636e\u3002 \u4e3e\u4f8b\uff1a # ping\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u4e0d\u4ec5\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4e5f\u540c\u65f6\u5199\u5165\u6587\u4ef6output.txt\u4e2d\uff08\u8986\u76d6\u5f0f\u5199\u5165\uff09\u3002 $ ping www.baidu.com | tee output.txt # ping\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u4e0d\u4ec5\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4e5f\u540c\u65f6\u5199\u5165\u6587\u4ef6output.txt\u4e2d\uff08\u8ffd\u52a0\u5f0f\u5199\u5165\uff09\u3002 $ ping www.baidu.com | tee -a output.txt # ping\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u4e0d\u4ec5\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4e5f\u540c\u65f6\u5199\u5165\u591a\u4e2a\u6587\u4ef6\u4e2d\uff08\u8986\u76d6\u5f0f\u5199\u5165\uff09\u3002 $ ping www.baidu.com | tee output1.txt output2.txt output3.txt # ls\u547d\u4ee4\u7684\u8f93\u51fa\u5199\u5165\u6587\u4ef6output.txt\u4e2d\uff0c\u5e76\u4f5c\u4e3awc\u547d\u4ee4\u7684\u8f93\u5165\u3002 $ ls *.txt | tee output.txt | wc -l 4 # cat output.txt f1.txt f2.txt output.txt test.txt \u6280\u5de7\uff1a \u5728vi\u4f7f\u7528\u4e2d\uff0c\u901a\u8fc7 tee \u547d\u4ee4\u63d0\u5347\u6587\u4ef6\u5199\u5165\u6743\u9650\u3002 \u6bd4\u5982\u975eroot\u7528\u6237\u6267\u884c vi /etc/hosts \uff0c\u5728vi\u4e2d\u4f7f\u7528 :w !sudo tee % \u53ef\u4ee5\u63d0\u9ad8\u6743\u9650\u4fdd\u5b58\u8fd9\u4e2a\u6587\u4ef6\u3002 3.16.\u8bed\u8a00\u73af\u5883LANG \u00b6 \u5b89\u88c5\u8bed\u8a00\u5305\u3002 # Ubuntu sudo apt install locales-all # Rocky sudo yum install glibc-langpack-zh.x86_64 # openSUSE sudo zypper install glibc-locale glibc-locale-32bit glibc-locale-base \u67e5\u770b\u5f53\u524d\u8bed\u8a00\u8bbe\u7f6e\uff1a echo $LANG locale -a locale -k LC_TIME localectl status localectl list-locales \u5168\u5c40locale\u914d\u7f6e(Global locale settings)\u3002 # openSUSE & Rocky sudo cat /etc/locale.conf # Ubuntu sudo cat /etc/default/locale \u4e34\u65f6\u4fee\u6539\u5f53\u524dsession\u7684locale\u3002 LANG = \"zh_CN.utf8\" \u6c38\u4e45\u4fee\u6539locale\u8bbe\u7f6e\u3002 sudo localectl set-locale LANG = zh_CN.utf8 \u4fee\u6539\u56de\u539f\u8bbe\u7f6e\u3002 sudo localectl set-locale LANG = en_US.utf8 Tips: Mac OS ssh\u767b\u9646Linux\u662f\u7ec8\u7aef\u63d0\u793a /usr/bin/manpath: can't set the locale; make sure $LC_* and $LANG are correct \u89e3\u51b3\u65b9\u6cd5\uff1a\u5728\u672c\u5730mac\u7535\u8111\u4e0a\u4fee\u6539/etc/ssh/ssh_config\u6216\u8005/etc/ssh/ssh_config\u6587\u4ef6\uff0c\u5220\u9664\u6389\u6216\u8005\u6ce8\u91ca\u6389\u8fd9\u4e00\u884c\u914d\u7f6e\u5185\u5bb9 # SendEnv LANG LC_* \u3002 \u5982\u679c\u4f7f\u7528\u7684\u662f Iterm2 \uff0c\u53ef\u4ee5\u6253\u5f00 iterm2 \u7684 preferences -> Profiles -> Terminal \u83dc\u5355\u91cc\u5173\u95ed Set locale variables automatically \u9009\u9879\u3002 3.17.\u7b26\u53f7 $ \u7528\u6cd5 \u00b6 \u7b26\u53f7 $ \u7684\u7528\u6cd5\uff1a $ \uff0c\u83b7\u53d6\u53d8\u96f6\u503c\u3002 x = 1 echo $x echo \" $x \" \u5efa\u8bae\u4f7f\u7528\"$x\"\uff0c\u4ee5\u907f\u514dshell\u7f16\u7a0b\u4e2d\u4ea7\u751f\u6b67\u4e49\u3002\u5982\u4e0b\u4f8b\uff1a s = \"this is a string\" echo $s echo \"this is a string\" \u6267\u884c [ $s == \"this is a string\" ] \u4f1a\u62a5\u9519\uff0c\u8fd9\u662f\u5b9e\u9645\u751f\u6210\u7684\u6bd4\u8f83\u5f0f this is a string == \"this is a string\" \u3002 \u6211\u4eec\u9884\u671f\u7684\u662f \"this is a string\" == \"this is a string\" \uff0c\u6240\u4ee5\u9700\u8981\u6539\u6210 [ \"$s\" == \"this is a string\" ] \u3002 $0 , $1 , $n , $# \uff1a \u751f\u6210\u4e00\u4e2a\u6d4b\u8bd5\u811a\u672c\u3002 echo 'echo $0 $1 $2 $#' > test.sh chmod 755 test.sh \u9a8c\u8bc1\u5404\u4e2a\u53c2\u6570\u4f4d\u7f6e\u3002 ./test.sh a b c d e \u8f93\u51fa\u7ed3\u679c\uff1a ./test.sh a b 5 \u7ed3\u8bba\uff1a $0 \u8f93\u51fa\u811a\u672c\u6587\u4ef6\u540d\uff1b $1 \u8f93\u51fa\u7b2c\u4e00\u4e2a\u53c2\u6570\uff1b $2 \u8f93\u51fa\u7b2c\u4e8c\u4e2a\u53c2\u6570\uff1b $# \u8f93\u51fa\u53c2\u6570\u4e2a\u6570\u3002 ${} ${} \u7528\u4e8e\u533a\u5206\u53d8\u91cf\u7684\u8fb9\u754c\u3002 \u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c $abc \u65e0\u7ed3\u679c\u8f93\u51fa\uff0c ${a}bc \u8f93\u51fa\u7ed3\u679c stringbc \uff0c\u901a\u8fc7{}\u6307\u5b9a\u4e86\u67d0\u4e2a\u5b57\u7b26\u5c5e\u4e8e\u53d8\u91cf\u3002 a = \"string\" echo ${ a } bc echo $abc ${#} ${#} \u662f\u8fd4\u56de\u53d8\u91cf\u503c\u7684\u957f\u5ea6\u3002 s = 'this is a string' echo \" $s \" echo \" ${# s } \" \u547d\u4ee4 echo \"${#s}\" \u8f93\u51fa\u7ed3\u679c\u662f\u5b57\u4e32 this is a string \u7684\u957f\u5ea6 16 \u3002 $? $? \u662f\u8fd4\u56de\u4e0a\u4e00\u547d\u4ee4\u662f\u5426\u6210\u529f\u7684\u72b6\u6001\uff0c 0 \u4ee3\u8868\u6210\u529f\uff0c\u975e\u96f6\u4ee3\u8868\u5931\u8d25\u3002 ls \u662f\u4e00\u4e2a\u547d\u4ee4\uff0c\u6240\u4ee5\u8fd4\u56de\u503c\u662f 0 \u3002 tom \u662f\u4e00\u4e2a\u4e0d\u5b58\u5728\u7684\u547d\u4ee4\uff0c\u5219\u8fd4\u56de 127 \u3002 ls echo $? tom echo $? $() $() \u7b49\u540c\u4e8e\u53cd\u5f15\u53f7\u3002 echo $(ls) \u7b49\u540c\u4e8e\u6267\u884c ls \u547d\u4ee4\u3002 $() \u7684\u5f0a\u7aef\u662f\uff0c\u4e0d\u662f\u6240\u6709\u7684\u7c7bunix\u7cfb\u7edf\u90fd\u652f\u6301\uff0c\u53cd\u5f15\u53f7\u662f\u80af\u5b9a\u652f\u6301\u7684\u3002 $() \u7684\u4f18\u52bf\u662f\u76f4\u89c2\uff0c\u5728\u8f6c\u79fb\u5904\u7406\u65f6\uff0c\u6bd4\u53cd\u5f15\u53f7\u76f4\u89c2\u5bb9\u6613\u4e9b\u3002 echo $( ls ) # test.sh echo $( cat $( ls )) # echo $0 $1 $2 $# \u4e0a\u8ff0\u5d4c\u5957\u683c\u5f0f\u4e2d\uff0cls\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u662fcat\u547d\u4ee4\u7684\u8f93\u5165\uff0c\u53ef\u4ee5\u8fdb\u884c\u591a\u5c42\u5d4c\u5957\uff0c\u5185\u5c42\u547d\u4ee4\u7684\u8f93\u51fa\u662f\u5916\u5c42\u547d\u4ee4\u7684\u8f93\u5165\u3002 $[] $[] \u662f\u8868\u8fbe\u5f0f\u8ba1\u7b97\u3002 echo $ [ 3 + 2 ] $- $- \u663e\u793ashell\u5f53\u524d\u6240\u4f7f\u7528\u7684\u9009\u9879\u3002 \u6267\u884c echo $- \uff0c\u8f93\u51fa\u7ed3\u679c himBHs \u3002himBH\u6bcf\u4e00\u4e2a\u5b57\u7b26\u662f\u4e00\u4e2ashell\u7684\u9009\u9879\u3002 $! $! \u83b7\u53d6\u6700\u540e\u4e00\u4e2a\u8fd0\u884c\u7684\u540e\u53f0\u8fdb\u7a0b\u7684pid\u3002 \u6bd4\u5982\u6267\u884c cat test.sh & \uff0c\u7ed3\u679c\u4e2d\u4f1a\u5305\u542b\u4e00\u4e2apid\u53f7\uff0c\u9a6c\u4e0a\u7740\u6267\u884c echo $! \uff0c\u5982\u679c2\u4e2a\u547d\u4ee4\u95f4\u9694\u4e4b\u95f4\u6ca1\u6709\u5176\u4ed6\u540e\u53f0\u8fdb\u7a0b\u6267\u884c\uff0c\u5219\u53ef\u4ee5\u5f97\u5230\u548c\u524d\u9762\u4e00\u81f4\u7684pid\u53f7\u3002 !$ !$ \u8fd4\u56de\u4e0a\u4e00\u6761\u547d\u4ee4\u7684\u6700\u540e\u4e00\u4e2a\u53c2\u6570\u3002 \u6267\u884c ./test.sh a b c iamhere \uff0c\u5f97\u5230\u7ed3\u679c ./test.sh a b 4 \u3002 \u6267\u884c echo !$ \uff0c\u5f97\u52302\u4e2a\u7ed3\u679c\uff0c echo iamhere \u548c iamhere \u3002 !! !! \u8f93\u51fa\u4e0a\u4e00\u6761\u547d\u4ee4\uff0c\u5e76\u6267\u884c\u3002 !! \u4f1a\u5148\u8f93\u51fa\u4e0a\u4e00\u6761\u547d\u4ee4 cat test.sh \uff0c\u7136\u540e\u518d\u6267\u884c\u8fd9\u6761\u547d\u4ee4\uff0c\u7b2c\u4e8c\u884c\u5373\u6267\u884c\u7ed3\u679c\u3002 [ vagrant@lizard:~ ] $ cat test.sh echo $0 $1 $2 $# [ vagrant@lizard:~ ] $ !! cat test.sh echo $0 $1 $2 $# $$ $$ \u8f93\u51fa\u5f53\u524d\u8fdb\u7a0b\u7684pid\u3002 echo $$ $@ & $* $@ \u548c $* \u662f\u5bf9\u4f20\u5165\u53c2\u6570\u7684\u4e0d\u540c\u4f53\u73b0\uff0c $@ \u662f\u4ee5\u53d8\u91cf\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff0c $* \u662f\u4ee5\u6570\u7ec4\u7684\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\u3002 \u521b\u5efa\u4e00\u4e2a\u6587\u4ef6 script.sh \u5305\u542b\u4e0b\u9762\u7684\u811a\u672c\u3002\u5e76\u6dfb\u52a0\u6267\u884c\u6743\u9650 chmod 755 script.sh \u3002 echo '$@\u4ee5\u53d8\u91cf\u65b9\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a' for x in \" $@ \" do echo $x done echo '$*\u4ee5\u6570\u7ec4\u7684\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a' for x in \" $* \" do echo $x done \u8f93\u51fa\u7ed3\u679c\uff1a $@ \u4ee5\u53d8\u91cf\u65b9\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a a b 3 5 d $* \u4ee5\u6570\u7ec4\u7684\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a a b 3 5 d","title":"\u7b2c\u4e00\u7ae0 Linux\u57fa\u7840"},{"location":"linux/SRE/01-fundamentals/#linux","text":"","title":"\u7b2c\u4e00\u7ae0 Linux\u57fa\u7840"},{"location":"linux/SRE/01-fundamentals/#1","text":"Rocky Linux Instructional Books openSUSE Documentation Ubuntu Documentation","title":"1.\u5b98\u65b9\u6587\u6863"},{"location":"linux/SRE/01-fundamentals/#2","text":"","title":"2.\u7cfb\u7edf\u73af\u5883"},{"location":"linux/SRE/01-fundamentals/#21rocky","text":"\u4f7f\u7528\u7248\u672c\uff1a Rocky 9.0 \u3002 \u4ece\u7f51\u7ad9\u4e0b\u8f7dRocky\u7cfb\u7edf ISO\u955c\u50cf \uff0c\u6216\u8005\u901a\u8fc7 wget \u547d\u4ee4\u4e0b\u8f7dRocky\u7cfb\u7edfISO\u955c\u50cf\u3002 wget https://download.rockylinux.org/pub/rocky/9.0/isos/x86_64/Rocky-9.0-x86_64-dvd.iso \u5b89\u88c5\u65f6\u6211\u9009\u62e9\u4e86\u6fc0\u6d3b root \u7528\u6237\uff0c\u9009\u62e9\u4e86Server\u6a21\u5f0f\u5b89\u88c5\uff08\u6ca1\u6709GUI\uff09\u3002 \u4ee5 root \u767b\u5f55\uff0c\u6267\u884c\u4e0b\u9762\u547d\u4ee4\u4fee\u6539 sudo \u6743\u9650\u3002 visudo \u5e76\u6fc0\u6d3b\u4e0b\u9762\u4e00\u884c\uff08\u4e0d\u8bbe\u5bc6\u7801\uff0c\u65b9\u4fbf\u7ec3\u4e60\uff09\uff1a %wheel ALL =( ALL ) NOPASSWD: ALL \u521b\u5efa\u7528\u6237 vagrant \uff0c\u5e76\u8bbe\u7f6e wheel \u4e3a\u4e3b\u8981\u7ec4\u548c\u4fee\u6539\u5bc6\u7801\u3002 adduser vagrant usermod -g wheel vagrant passwd vagrant \u8bbe\u5b9ahostname\uff08\u5305\u62ec\u522b\u540d\uff09\uff0c\u5e76\u67e5\u770b\u7ed3\u679c\u3002 hostnamectl set-hostname --static \"rocky9\" hostnamectl set-hostname --pretty \"rocky9\" hostnamectl cat /etc/hostname \u5c0f\u8d34\u58eb\uff1a \u7531systemd\u63a7\u5236\u7684\u4e3b\u673a\u540d\u7684\u670d\u52a1\u914d\u7f6e\u4fe1\u606f\uff1a /usr/lib/systemd/system/systemd-hostnamed.service Rocky\u7684\u8f6f\u4ef6\u6e90\u7684\u914d\u7f6e\u4fe1\u606f\u4fdd\u5b58\u5728\u76ee\u5f55 /etc/yum.repos.d/ \u4e0b\u3002\u5982\u679c\u8bbf\u95ee\u9ed8\u8ba4\u6e90\u6bd4\u8f83\u6162\uff0c\u53ef\u4ee5\u66f4\u65b0\u963f\u91cc\u6e90\u6216\u8005\u79d1\u5927\u6e90\u3002 \u66f4\u6362\u963f\u91cc\u6e90\u3002 sed -e 's|^mirrorlist=|#mirrorlist=|g' \\ -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \\ -i.bak \\ /etc/yum.repos.d/Rocky-*.repo \u66f4\u6362\u79d1\u5927\u6e90\u3002 sed -e 's|^mirrorlist=|#mirrorlist=|g' \\ -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.ustc.edu.cn/rocky|g' \\ -i.bak \\ /etc/yum.repos.d/rocky-extras.repo \\ /etc/yum.repos.d/rocky.repo \u5237\u65b0\u7f13\u5b58\u3002 dnf makecache","title":"2.1.Rocky"},{"location":"linux/SRE/01-fundamentals/#22ubuntu","text":"\u4f7f\u7528\u7248\u672c\uff1a Ubuntu 2204 \u3002 \u8bbe\u5b9aroot\u7528\u6237\u7684\u5bc6\u7801\u3002 sudo passwd root \u901a\u8fc7\u5b89\u88c5\u65f6\u5df2\u521b\u5efa\u7684\u7528\u6237 vagrant \u767b\u5f55\u3002\u6267\u884c\u4e0b\u9762\u547d\u4ee4\u4fee\u6539 sudo \u6743\u9650\u3002 sudo visudo \u6dfb\u52a0 vagrant \u5230\u7279\u6743\u7528\u6237\uff08Rocky\u548copenSUSE\u4e0d\u9700\u8981\u6dfb\u52a0\uff09\uff0c\u5e76\u6fc0\u6d3bsudo\u4e00\u884c\uff08\u4e0d\u8bbe\u5bc6\u7801\uff0c\u65b9\u4fbf\u7ec3\u4e60\uff09\uff1a # User privilege specification root ALL =( ALL:ALL ) ALL vagrant ALL =( ALL:ALL ) ALL # Allow members of group sudo to execute any command sudo ALL =( ALL:ALL ) NOPASSWD: ALL \u4fee\u6539\u7528\u6237 vagrant \u7684\u4e3b\u8981\u7ec4\u4e3a sudo \u3002 sudo usermod -g sudo vagrant \u4fee\u6539\u4e3b\u673a\u540d\u548c\u522b\u540d\u3002 sudo hostnamectl set-hostname ubuntu2204 sudo hostnamectl set-hostname ubuntu2204 --pretty \u5c0f\u8d34\u58eb\uff1a \u5982\u4f55\u5904\u7406 Username is not in the sudoers file. This incident will be reported \u95ee\u9898\u3002 \u5982\u679c\u6ca1\u6709\u521d\u59cb\u5316 root \u7528\u6237\u7684\u5bc6\u7801\uff0c\u4e14\u5f53\u524d\u7528\u6237\u4e5f\u65e0\u6cd5\u6267\u884c sudo \u547d\u4ee4\uff0c\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u6b65\u9aa4\u901a\u8fc7recovery\u6551\u63f4\u6a21\u5f0f\u8fdb\u884c\u6062\u590d\u3002 \u6309 shift \u952e\u5f00\u673a\uff0c\u8fdb\u5165grub\u542f\u52a8\u83dc\u5355\u3002\uff08VMWare\u4e5f\u9002\u7528\uff09 \u5411\u4e0b\u79fb\u52a8\u9ad8\u4eae\u6761\uff0c\u9009\u62e9\u83dc\u5355 Advanced options for Ubuntu \uff0c\u5e76\u786e\u8ba4\u56de\u8f66\u3002 \u9009\u62e9\u5e26\u6709 recovery mode \u7684\u5185\u6838\uff0c\u786e\u8ba4\u56de\u8f66\u3002 \u5411\u4e0b\u79fb\u52a8\u9ad8\u4eae\u6761\uff0c\u9009\u62e9\u83dc\u5355 root Drop to root shell prompt \uff0c\u5e76\u786e\u8ba4\u56de\u8f66\u3002 \u56de\u8f66\u786e\u8ba4 press Enter for maintenance \u3002 \u51fa\u73b0 root \u7684\u547d\u4ee4\u63d0\u793a\u7b26\u540e\uff0c\u6267\u884c\u547d\u4ee4 mount -o rw,remount / \u3002 \u6267\u884c\u547d\u4ee4 passwd \u7ed9 root \u8bbe\u5b9a\u5bc6\u7801\u3002 \u6267\u884c\u547d\u4ee4 adduser username sudo \u628a\u6307\u5b9a\u7528\u6237\u52a0\u5165 sudo \u7ec4\u3002 \u6267\u884c\u547d\u4ee4 visudo \u8fdb\u884c\u5fc5\u8981\u7684\u4fee\u6b63\u6216\u4fee\u6539\u3002","title":"2.2.Ubuntu"},{"location":"linux/SRE/01-fundamentals/#23opensuse","text":"\u4f7f\u7528\u7248\u672c\uff1a Leap 15.4 \u3002 \u9009\u62e9\u670d\u52a1\u5668\u6a21\u5f0f\u5b89\u88c5\uff0c\u65e0\u56fe\u5f62\u754c\u9762\u3002\u5b89\u88c5\u4e2d\u4e0d\u521b\u5efa\u7528\u6237\u3002 \u521b\u5efa\u7528\u6237 vagrant \uff0c\u5e76\u8bbe\u7f6e wheel \u4e3a\u4e3b\u8981\u7ec4\u3002 useradd -m -g wheel -G root -c \"vagrant\" vagrant passwd vagrant \u6267\u884c visudo \u547d\u4ee4\uff0c\u6fc0\u6d3b\u4e0b\u9762\u4e00\u884c\uff0c\u6dfb\u52a0 sudo \u6743\u9650\u3002 % wheel ALL =( ALL ) NOPASSWD: ALL \u4fee\u6539\u4e3b\u673a\u540d\u548c\u522b\u540d\u3002 sudo hostnamectl set-hostname lizard sudo hostnamectl set-hostname lizard --pretty","title":"2.3.openSUSE"},{"location":"linux/SRE/01-fundamentals/#3","text":"\u8bf4\u660e\uff1a \u9ed8\u8ba4\u5f53\u524d\u64cd\u4f5c\u7528\u6237\u4e3a vagrant \u3002","title":"3.\u5e38\u7528\u547d\u4ee4"},{"location":"linux/SRE/01-fundamentals/#31","text":"\u6267\u884c\u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u770b\u5230\u5f53\u524d\u7cfb\u7edf\u7684\u547d\u4ee4\u63d0\u793a\u7b26\u683c\u5f0f\u3002 echo $PS1 \u5404\u7cfb\u7edf\u9ed8\u8ba4\u8bbe\u7f6e\u662f\u6709\u5dee\u5f02\u7684\u3002 # Rocky [ \\u @ \\h \\W ] \\$ # Ubuntu \\[\\e ] 0 ; \\u @ \\h : \\w\\a\\] ${ debian_chroot :+( $debian_chroot ) } \\[\\0 33 [ 01 ; 32m \\]\\u @ \\h\\[\\0 33 [ 00m \\] : \\[\\0 33 [ 01 ; 34m \\]\\w\\[\\0 33 [ 00m \\]\\$ # openSUSE \\u @ \\h : \\w > \u5c0f\u8d34\u58eb\uff1a bash\u53ef\u8bc6\u522b\u7684\u8f6c\u4e49\u5e8f\u5217\u6709\u4e0b\u9762\u8fd9\u4e9b\uff1a \\u : \u5f53\u524d\u7528\u6237\u7684\u8d26\u53f7\u540d\u79f0 \\h : \u4e3b\u673a\u540d\u7b2c\u4e00\u90e8\u5206 \\H : \u5b8c\u6574\u7684\u4e3b\u673a\u540d\u79f0 \\w : \u5b8c\u6574\u7684\u5de5\u4f5c\u76ee\u5f55\u540d\u79f0\uff08\u5982 \"/home/username/mywork\"\uff09 \\W : \u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u7684\"\u57fa\u540d (basename)\"\uff08\u5982 \"mywork\") \\t : \u663e\u793a\u65f6\u95f4\u4e3a24\u5c0f\u65f6\u683c\u5f0f\uff0c\u5982\uff1aHH:MM:SS \\T : \u663e\u793a\u65f6\u95f4\u4e3a12\u5c0f\u65f6\u683c\u5f0f \\A : \u663e\u793a\u65f6\u95f4\u4e3a24\u5c0f\u65f6\u683c\u5f0f\uff1aHH:MM \\@ : \u5e26\u6709 am/pm \u7684 12 \u5c0f\u65f6\u5236\u65f6\u95f4 \\d : \u4ee3\u8868\u65e5\u671f\uff0c\u683c\u5f0f\u4e3aweekday month date\uff0c\u4f8b\u5982\uff1a\"Mon Aug 1\" \\s : shell \u7684\u540d\u79f0\uff08\u5982 \"bash\") \\v : bash\u7684\u7248\u672c\uff08\u5982 2.04\uff09 \\V : bash\u7684\u7248\u672c\uff08\u5305\u62ec\u8865\u4e01\u7ea7\u522b\uff09 \\n : \u6362\u884c\u7b26 \\r : \u56de\u8f66\u7b26 \\\\ : \u53cd\u659c\u6760 \\a : ASCII \u54cd\u94c3\u5b57\u7b26\uff08\u4e5f\u53ef\u4ee5\u952e\u5165 07 \uff09 \\e : ASCII \u8f6c\u4e49\u5b57\u7b26\uff08\u4e5f\u53ef\u4ee5\u952e\u5165 33 ) \\[ : \u8fd9\u4e2a\u5e8f\u5217\u5e94\u8be5\u51fa\u73b0\u5728\u4e0d\u79fb\u52a8\u5149\u6807\u7684\u5b57\u7b26\u5e8f\u5217\uff08\u5982\u989c\u8272\u8f6c\u4e49\u5e8f\u5217\uff09\u4e4b\u524d\u3002\u5b83\u4f7fbash\u80fd\u591f\u6b63\u786e\u8ba1\u7b97\u81ea\u52a8\u6362\u884c \\] : \u8fd9\u4e2a\u5e8f\u5217\u5e94\u8be5\u51fa\u73b0\u5728\u975e\u6253\u5370\u5b57\u7b26\u5e8f\u5217\u4e4b\u540e \\# : \u4e0b\u8fbe\u7684\u7b2c\u51e0\u4e2a\u547d\u4ee4 \\$ : \u63d0\u793a\u5b57\u7b26\uff0c\u5982\u679c\u662froot\u7528\u6237\uff0c\u63d0\u793a\u7b26\u4e3a # \uff0c\u666e\u901a\u7528\u6237\u5219\u4e3a $ \u5728PS1\u4e2d\u8bbe\u7f6e\u5b57\u7b26\u989c\u8272\u7684\u683c\u5f0f\u4e3a\uff1a [\\e[F;Bm]........[\\e[0m] \uff0c\u5176\u4e2d [\\e[0m] \u4f5c\u4e3a\u989c\u8272\u8bbe\u5b9a\u7684\u7ed3\u675f\u3002 \u5176\u4e2d\"F\"\u4e3a\u5b57\u4f53\u989c\u8272\uff0c\u7f16\u53f7\u4e3a30-37\uff0c\"B\"\u4e3a\u80cc\u666f\u989c\u8272\uff0c\u7f16\u53f7\u4e3a40-47\u3002 \u5c0f\u8d34\u58eb\uff1a \u989c\u8272\u5bf9\u7167\u8868: F:30 , B:40 : \u9ed1\u8272 F:31 , B:41 : \u7ea2\u8272 F:32 , B:42 : \u7eff\u8272 F:33 , B:43 : \u9ec4\u8272 F:34 , B:44 : \u84dd\u8272 F:35 , B:45 : \u7d2b\u7ea2\u8272 F:36 , B:46 : \u9752\u84dd\u8272 F:37 , B:47 : \u767d\u8272 \u4ee5\u4e0b\u9762\u7684PS1\u8bbe\u5b9a\u4e3a\u4f8b\u8bf4\u660e\u989c\u8272\u8bbe\u5b9a\u3002 PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[37;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" \u62c6\u89e3\u5206\u6790\uff1a PS1=\" \\[\\e[37;40m\\] # \u6574\u4e2a\u63d0\u793a\u7b26\u533a\u57df\u524d\u666f\u767d\u8272\uff0c\u80cc\u666f\u9ed1\u8272 [ # \u663e\u793a\u5b57\u7b26[ \\[\\e[32;40m\\] # \u4fee\u9970\u540e\u9762\u7684\\u\uff0c\u524d\u666f\u7eff\u8272\uff0c\u80cc\u666f\u9ed1\u8272 \\u # \u663e\u793a\u5f53\u524d\u7528\u6237\u7684\u8d26\u53f7\u540d\u79f0 \\[\\e[37;40m\\] # \u4fee\u9970\u540e\u9762\u7684\u5b57\u7b26@\u548c\u4e3b\u673a\u540d @ # \u663e\u793a\u5b57\u7b26@ \\h # \u663e\u793a\u4e3b\u673a\u540d : # \u663e\u793a\u5b57\u7b26: \\[\\e[36;40m\\] # \u4fee\u9970\u540e\u9762\u7684\\w\uff0c\u524d\u666f\u9752\u84dd\u8272\uff0c\u80cc\u666f\u9ed1\u8272 \\w # \u663e\u793a\u5b8c\u6574\u5de5\u4f5c\u76ee\u5f55 \\[\\e[0m\\] # \u7ed3\u675f\u989c\u8272\u8bbe\u5b9a ] # \u663e\u793a\u5b57\u7b26] \\$\" # \u5982\u679c\u662froot\u7528\u6237\uff0c\u63d0\u793a\u7b26\u4e3a# \uff0c\u666e\u901a\u7528\u6237\u5219\u4e3a$ \u5bf9\u4e0d\u540c\u4e3b\u673a\u505a\u4e0d\u540c\u8bbe\u7f6e\uff1a # Rocky PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[37;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" # Ubuntu PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[33;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" # openSUSE PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[35;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" \u5c06\u4e0a\u8ff0PS1\u7684\u8bbe\u5b9a\uff0c\u8ffd\u52a0\u5230\u5f53\u524d\u7528\u6237\u7684 ~/.bashrc \u6587\u4ef6\u672b\u5c3e\uff0c\u4ee5\u5b9e\u73b0\u5bf9\u5f53\u524d\u7528\u6237\u7684\u63d0\u793a\u7b26\u98ce\u683c\u505a\u6301\u4e45\u4fdd\u5b58\u3002","title":"3.1.\u4fee\u6539\u63d0\u793a\u7b26\u98ce\u683c"},{"location":"linux/SRE/01-fundamentals/#32linux","text":"\u5185\u90e8\u547d\u4ee4 (internal command)\u5b9e\u9645\u4e0a\u662fshell\u7a0b\u5e8f\u7684\u4e00\u90e8\u5206\uff0c\u5305\u542b\u7684\u662f\u4e00\u4e9b\u6bd4\u8f83\u7b80\u5355\u7684linux\u7cfb\u7edf\u547d\u4ee4\uff0c\u8fd9\u4e9b\u547d\u4ee4\u7531shell\u7a0b\u5e8f\u8bc6\u522b\u5e76\u5728shell\u7a0b\u5e8f\u5185\u90e8\u5b8c\u6210\u8fd0\u884c\uff0c\u901a\u5e38\u5728linux\u7cfb\u7edf\u52a0\u8f7d\u8fd0\u884c\u65f6shell\u5c31\u88ab\u52a0\u8f7d\u5e76\u9a7b\u7559\u5728\u7cfb\u7edf\u5185\u5b58\u4e2d\u3002 \u5916\u90e8\u547d\u4ee4 (external command)\u662flinux\u7cfb\u7edf\u4e2d\u7684\u5b9e\u7528\u7a0b\u5e8f\u90e8\u5206\uff0c\u7cfb\u7edf\u52a0\u8f7d\u65f6\u5e76\u4e0d\u968f\u7cfb\u7edf\u4e00\u8d77\u88ab\u52a0\u8f7d\u5230\u5185\u5b58\u4e2d\uff0c\u800c\u662f\u5728\u9700\u8981\u65f6\u624d\u5c06\u5176\u8c03\u7528\u5185\u5b58\u3002\u901a\u5e38\u5916\u90e8\u547d\u4ee4\u7684\u5b9e\u4f53\u5e76\u4e0d\u5305\u542b\u5728shell\u4e2d\uff0c\u4f46\u662f\u5176\u547d\u4ee4\u6267\u884c\u8fc7\u7a0b\u662f\u7531shell\u7a0b\u5e8f\u63a7\u5236\u7684\u3002 \u6bd4\u5982\uff1a \u6267\u884c\u547d\u4ee4 type -t cp \uff0c\u7cfb\u7edf\u8fd4\u56de\u7ed3\u679c\u662f file \uff0c\u5916\u90e8\u547d\u4ee4\u3002 \u6267\u884c\u547d\u4ee4 type -t cd \uff0c\u7cfb\u7edf\u8fd4\u56de\u7ed3\u679c builtin \uff0c\u5185\u90e8\u547d\u4ee4\u3002 \u6267\u884c\u547d\u4ee4 enable -a cp \uff0c\u7cfb\u7edf\u8fd4\u56de -bash: enable: cp: not a shell builtin \uff0c\u4e5f\u53ef\u4ee5\u5224\u65ad\u662f\u5426\u4e3a\u5185\u90e8\u547d\u4ee4\u3002 \u5bf9\u4e8e\u5185\u90e8\u547d\u4ee4\uff0c\u53ef\u4ee5\u901a\u8fc7enable\u547d\u4ee4\u6765\u542f\u7528\u6216\u8005\u7981\u7528\u3002 # \u7981\u7528cd\u547d\u4ee4 enable -n cd # \u67e5\u770b\u6240\u6709\u88ab\u7981\u7528\u7684\u547d\u4ee4 enable -n # \u542f\u7528cd\u547d\u4ee4 enable cd \u5bf9\u4e8e\u547d\u4ee4\uff0c\u53ef\u4ee5\u901a\u8fc7 whereis \u547d\u4ee4\u6765\u67e5\u770b\u8def\u5f84\u3002 whereis cp whereis cd","title":"3.2.Linux\u7684\u5185\u5916\u90e8\u547d\u4ee4"},{"location":"linux/SRE/01-fundamentals/#33cpu","text":"lscpu cat /proc/cpuinfo","title":"3.3.CPU\u4fe1\u606f"},{"location":"linux/SRE/01-fundamentals/#34","text":"free cat /proc/meminfo","title":"3.4.\u5185\u5b58\u4f7f\u7528\u72b6\u6001"},{"location":"linux/SRE/01-fundamentals/#35","text":"lsblk openSUSE\u5728VMWare\u9ed8\u8ba4\u5b89\u88c5\u7684\u72b6\u6001\uff1a NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8 :0 0 200G 0 disk \u251c\u2500sda1 8 :1 0 8M 0 part \u251c\u2500sda2 8 :2 0 198G 0 part /home \u2502 /var \u2502 /opt \u2502 /usr/local \u2502 /root \u2502 /tmp \u2502 /srv \u2502 /boot/grub2/x86_64-efi \u2502 /boot/grub2/i386-pc \u2502 /.snapshots \u2502 / \u2514\u2500sda3 8 :3 0 2G 0 part [ SWAP ] sr0 11 :0 1 3 .8G 0 rom Ubuntu\u5728VMWare\u9ed8\u8ba4\u5b89\u88c5\u7684\u72b6\u6001\uff1a NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7 :0 0 61 .9M 1 loop /snap/core20/1405 loop1 7 :1 0 63 .2M 1 loop /snap/core20/1623 loop2 7 :2 0 79 .9M 1 loop /snap/lxd/22923 loop3 7 :3 0 48M 1 loop /snap/snapd/17029 loop4 7 :4 0 103M 1 loop /snap/lxd/23541 loop5 7 :5 0 48M 1 loop /snap/snapd/17336 sda 8 :0 0 50G 0 disk \u251c\u2500sda1 8 :1 0 1M 0 part \u251c\u2500sda2 8 :2 0 2G 0 part /boot \u2514\u2500sda3 8 :3 0 48G 0 part \u2514\u2500ubuntu--vg-ubuntu--lv 253 :0 0 24G 0 lvm / sr0 11 :0 1 1 .4G 0 rom Rocky\u5728VMWare\u9ed8\u8ba4\u5b89\u88c5\u7684\u72b6\u6001\uff1a NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8 :0 0 50G 0 disk \u251c\u2500sda1 8 :1 0 1G 0 part /boot \u2514\u2500sda2 8 :2 0 49G 0 part \u251c\u2500rl-root 253 :0 0 45 .1G 0 lvm / \u2514\u2500rl-swap 253 :1 0 3 .9G 0 lvm [ SWAP ] sr0 11 :0 1 7 .9G 0 rom","title":"3.5.\u786c\u76d8\u548c\u5206\u533a\u60c5\u51b5"},{"location":"linux/SRE/01-fundamentals/#36","text":"arch openSUSE\uff0cUbuntu\u548cRocky\u7684\u8fd4\u56de\u7ed3\u679c\u90fd\u662f x86_64 \u3002","title":"3.6.\u7cfb\u7edf\u67b6\u6784\u4fe1\u606f"},{"location":"linux/SRE/01-fundamentals/#37","text":"uname -r \u4e09\u4e2a\u53d1\u884c\u7248\u8fd4\u56de\u7684\u7ed3\u679c\u4e0d\u5c3d\u76f8\u540c\uff1a # openSUSE 5 .14.21-150400.24.21-default # Ubuntu 5 .15.0-52-generic # Rocky 5 .14.0-70.17.1.el9_0.x86_64","title":"3.7.\u5185\u6838\u7248\u672c"},{"location":"linux/SRE/01-fundamentals/#38","text":"cat /etc/os-release cat /etc/issue # Rocky 9 sudo cat /etc/redhat-release lsb-release -a lsb_release -cs lsb_release -is lsb_release -rs \u5728openSUSE\u4e2d\uff0c\u9700\u8981\u5b89\u88c5 lsb-release \u5305\u3002\u6267\u884c lsb-release -a \u548c lsb_release -a \u8fd4\u56de\u7684\u7ed3\u679c\u662f\u4e00\u6837\u7684\u3002 sudo zypper in lsb-release \u5728Ubuntu\u4e2d\uff0c\u9700\u8981\u5b89\u88c5 lsb-release \u5305\u3002\u53ea\u80fd\u6267\u884c lsb_release -a \u3002 sudo apt install lsb-release \u5728Rocky 9\u4e2d\uff0c\u627e\u4e0d\u5230 lsb-release \u76f8\u5173\u7684\u5305\u3002","title":"3.8.\u64cd\u4f5c\u7cfb\u7edf\u7248\u672c"},{"location":"linux/SRE/01-fundamentals/#39","text":"\u663e\u793a\u9ed8\u8ba4\u683c\u5f0f\u7684\u5f53\u524d\u65e5\u671f\u3002 date \u4e09\u4e2a\u7cfb\u7edf\u7684\u9ed8\u8ba4\u65e5\u671f\u683c\u5f0f\u7565\u6709\u4e0d\u540c\u3002 # openSUSE Mon 24 Oct 2022 09 :28:06 AM CST # Ubuntu Mon Oct 24 01 :28:09 AM UTC 2022 # Rocky Mon Oct 24 09 :24:01 AM CST 2022 \u663e\u793a\u81ea1970-01-01 00:00:00 UTC\u5230\u5f53\u524d\u7684\u79d2\u6570\u3002 date +%s \u5c06\u4e0a\u4e00\u547d\u4ee4\u4e2d\u7684\u63cf\u8ff0\u8f6c\u6362\u4e3a\u7cfb\u7edf\u9ed8\u8ba4\u65e5\u671f\u683c\u5f0f\u3002 date -d @ ` date +%s ` date --date = @ '1666575347' \u663e\u793a\u786c\u4ef6\u65f6\u949f\u3002 hwclock \u4e5f\u88ab\u79f0\u4e3a Real Time Clock (RTC)\u3002 \u5728Rocky9\u4e2d\uff0c clock \u6709\u4e00\u4e2a\u8f6f\u8fde\u63a5\u6307\u5411 hwclock \uff1a /usr/sbin/clock -> hwclock \u3002\u5728openSUSE\u548cUbuntu\u4e2d\u53ea\u6709 hwclock \u3002 ll /usr/sbin/clock ll /usr/sbin/hwclock \u8bfb\u53d6RTC\u65f6\u95f4\u3002 sudo hwclock --get sudo hwclock -r \u6821\u51c6\u65f6\u95f4\uff1a -s, \u2013hctosys : \u4ee5RTC\u786c\u4ef6\u65f6\u95f4\u6765\u6821\u51c6\u7cfb\u7edf\u65f6\u95f4\u3002 -w, \u2013systohoc : \u4ee5\u7cfb\u7edf\u65f6\u95f4\u6765\u6821\u51c6RTC\u786c\u4ef6\u65f6\u95f4\u3002 \u663e\u793a\u5f53\u524d\u7cfb\u7edf\u65f6\u533a\u3002 ll /etc/localtime \u7cfb\u7edf\u53ef\u80fd\u4f1a\u8fd4\u56de\u4e0d\u540c\u7ed3\u679c\uff0c\u4f8b\u5982\uff1a /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai /etc/localtime -> /usr/share/zoneinfo/Etc/UTC \u663e\u793a\u5f53\u524d\u53ef\u4ee5\u65f6\u533a\u5217\u8868\u3002 timedatectl list-timezones timedatectl list-timezones | grep -i Asia \u4fee\u6539\u5f53\u524d\u7cfb\u7edf\u65f6\u533a\u3002 sudo timedatectl set-timezone Asia/Shanghai \u663e\u793a\u65e5\u5386\u3002 cal -y openSUSE\u548cRocky\u4e2d\uff0c\u4f7f\u7528 cal \u547d\u4ee4\u9700\u8981\u5b89\u88c5 util-linux \u5305\u3002 Ubuntu\u4e2d\uff0c\u4f7f\u7528 cal \u547d\u4ee4\u9700\u8981\u5b89\u88c5 ncal \u5305\u3002 sudo apt install ncal sudo zypper se util-linux sudo yum install util-linux","title":"3.9.\u65e5\u671f\u548c\u65f6\u95f4"},{"location":"linux/SRE/01-fundamentals/#310","text":"whoami \uff1a\u5f53\u524d\u767b\u5f55\u7528\u6237 who \uff1a\u7cfb\u7edf\u5f53\u524d\u6240\u6709\u7684\u767b\u5f55\u4f1a\u8bdd w \uff1a\u7cfb\u7edf\u5f53\u524d\u6240\u6709\u7684\u767b\u5f55\u4f1a\u8bdd\u53ca\u6240\u4f5c\u7684\u64cd\u4f5c \u63d0\u793a\uff1a MOTD is the abbreviation of \"Message Of The Day\", and it is used to display a message when a remote user login to the Linux Operating system using SSH. Linux administrators often need to display different messages on the login of the user, like displaying custom information about the server or any necessary information. \u7f16\u8f91\u6587\u4ef6 /etc/motd \u53ef\u4ee5\u81ea\u5b9a\u4e49\"Message Of The Day\"\u7684\u4fe1\u606f\u3002 Ubuntu 2204\u65b0\u5b89\u88c5\u540e\u6ca1\u6709\u8fd9\u4e2a\u6587\u4ef6\uff0c\u9700\u8981\u81ea\u5df1\u521b\u5efa\u3002 openSUSE\u65b0\u5b89\u88c5\u540e\u6709\u9884\u5b9a\u4e49\u7684\u4fe1\u606f\u3002 Rocky9 \u65b0\u5b89\u88c5\u540e\u6709\u8be5\u6587\u4ef6\uff0c\u7a7a\u767d\u6587\u4ef6\u65e0\u5185\u5bb9\u3002","title":"3.10.\u7528\u6237\u767b\u5f55\u4fe1\u606f"},{"location":"linux/SRE/01-fundamentals/#311","text":"screen \u5de5\u5177 screen -S (Create new screen session) screen -ls (list current screen sessions) screen -x (Attach to existing screeen session, sync between both) screen -r (Reattach existing screen session) tmux \u5de5\u5177 tmux \u662f\u6307 Terminal Multiplexer . \u5b89\u88c5 tmux \u5de5\u5177\u3002 # Rocky sudo yum install tmux # Ubuntu sudo apt install tmux # openSUSE sudo zypper in tmux \u5e38\u7528\u65b9\u6cd5\uff1a tmux new -s (Create new session) tmux detach (Detach current session) tmux ls (list current sessions) tmux attach -t (Reattach existing session) tmux switch -t (Switch to another session) tmux kill-session -t (Kill existing session) tmux list-keys (List all short keys) tmux list-commands (List commands and parameters) tmux info (List all sessions info) tmux split-window (Split window)","title":"3.11.\u4f1a\u8bdd\u7ba1\u7406\u5de5\u5177"},{"location":"linux/SRE/01-fundamentals/#312echo","text":"echo \u547d\u4ee4\u4e2d\u53ef\u4ee5\u8f93\u51fa\u53d8\u91cf\uff0c\u5982\u679c\u53d8\u91cf\u662f\u7528\u662f\u5355\u5f15\u53f7\u5f15\u8d77\u6765\uff0c\u8868\u793a\u8fd9\u4e2a\u53d8\u91cf\u4e0d\u7528IFS\u66ff\u6362\uff01\uff01 echo \"Home=$HOME\" \u7684\u8f93\u51fa\u7ed3\u679c\u662f Home=/home/vagrant echo 'Home=$HOME' \u7684\u8f93\u51fa\u7ed3\u679c\u662f Home=$HOME echo -e \u542f\u7528 \\ \u5b57\u7b26\u7684\u89e3\u91ca\u529f\u80fd\uff0c\u6bd4\u5982\uff1a echo -e \"a\\x0Ab\" \uff0c\u8f93\u51fa\u5b57\u7b26 a \u548c b \uff0c\u4e2d\u95f4 \\x0A \u4ee3\u8868\u5341\u516d\u8fdb\u5236 OA \uff08\u5373\u56de\u8f66\uff09 echo -e \"\\x4A \\x41 \\x4D \\x45 \\x53\" \uff0c\u8f93\u51fa\u7ed3\u679c\u662f J A M E S \u63d0\u793a\uff1a \u4ee5\u901a\u8fc7man 7 ascii\u6765\u67e5\u770b\u5404\u8fdb\u5236\u7684\u542b\u4e49\u3002 echo -e \u8f93\u51fa\u5e26\u989c\u8272\u5b57\u7b26\u3002 \u793a\u4f8b\uff1a echo -e \"\\e[35m \u7d2b\u8272 \\e[0m\" echo -e \"\\e[43m \u9ec4\u5e95 \\e[0m\" echo -e \"\\e[93m \u9ed1\u5e95\u9ec4\u5b57 \\e[0m\" \u53c2\u8003\u4fe1\u606f\uff1a \u5b57\u4f53\u989c\u8272\uff1a \\e[30m \uff1a \u9ed1\u8272 \\e[31m \uff1a \u7ea2\u8272 \\e[32m \uff1a \u7eff\u8272 \\e[33m \uff1a \u9ec4\u8272 \\e[34m \uff1a \u84dd\u8272 \\e[35m \uff1a \u7d2b\u8272 \\e[36m \uff1a \u9752\u8272 \\e[37m \uff1a \u767d\u8272 \\e[40m \uff1a \u9ed1\u5e95 \\e[41m \uff1a \u7ea2\u5e95 \\e[42m \uff1a \u7eff\u5e95 \\e[43m \uff1a \u9ec4\u5e95 \\e[44m \uff1a \u84dd\u5e95 \\e[45m \uff1a \u7d2b\u5e95 \\e[46m \uff1a \u9752\u5e95 \\e[47m \uff1a \u767d\u5e95 \u80cc\u666f\u989c\u8272\uff1a \\e[90m \uff1a \u9ed1\u5e95\u9ed1\u5b57 \\e[91m \uff1a \u9ed1\u5e95\u7ea2\u5b57 \\e[92m \uff1a \u9ed1\u5e95\u7eff\u5b57 \\e[93m \uff1a \u9ed1\u5e95\u9ec4\u5b57 \\e[94m \uff1a \u9ed1\u5e95\u84dd\u5b57 \\e[95m \uff1a \u9ed1\u5e95\u7d2b\u5b57 \\e[96m \uff1a \u9ed1\u5e95\u9752\u5b57 \\e[97m \uff1a \u9ed1\u5e95\u767d\u5b57 \u63a7\u5236\u5c5e\u6027\uff1a \\e[0m \u5173\u95ed\u6240\u6709\u5c5e\u6027 \\e[1m \u8bbe\u7f6e\u9ad8\u4eae\u5ea6 \\e[4m \u4e0b\u5212\u7ebf \\e[5m \u95ea\u70c1 \\e[7m \u53cd\u663e\uff0c\u649e\u8272\u663e\u793a\uff0c\u663e\u793a\u4e3a\u767d\u5b57\u9ed1\u5e95\uff0c\u6216\u8005\u663e\u793a\u4e3a\u9ed1\u5e95\u767d\u5b57 \\e[8m \u6d88\u5f71\uff0c\u5b57\u7b26\u989c\u8272\u5c06\u4f1a\u4e0e\u80cc\u666f\u989c\u8272\u76f8\u540c \\e[nA \u5149\u6807\u4e0a\u79fb n \u884c \\e[nB \u5149\u6807\u4e0b\u79fb n \u884c \\e[nC \u5149\u6807\u53f3\u79fb n \u884c \\e[nD \u5149\u6807\u5de6\u79fb n \u884c \\e[y;xH \u8bbe\u7f6e\u5149\u6807\u4f4d\u7f6e \\e[2J \u6e05\u5c4f \\e[K \u6e05\u9664\u4ece\u5149\u6807\u5230\u884c\u5c3e\u7684\u5185\u5bb9 \\e[s \u4fdd\u5b58\u5149\u6807\u4f4d\u7f6e \\e[u \u6062\u590d\u5149\u6807\u4f4d\u7f6e \\e[?25 \u9690\u85cf\u5149\u6807 \\e[?25h \u663e\u793a\u5149\u6807","title":"3.12.echo\u547d\u4ee4"},{"location":"linux/SRE/01-fundamentals/#313man","text":"\u5b89\u88c5\u5305\uff1a # openSUSE sudo zypper install man-pages man-pages-zh_CN man-pages-posix # Rocky sudo yum install man-pages # Ubuntu sudo apt install man-db manpages-posix manpages manpages-zh sudo apt install manpages-dev manpages-posix-dev \u66f4\u65b0mandb mandb \u67e5\u627e\u67d0\u4e2a\u547d\u4ee4\u7684man\u4fe1\u606f\uff0c\u4f8b\u5982\u67e5\u627e crontab \u547d\u4ee4\u7684\u4fe1\u606f\u3002 # \u7cbe\u786e\u67e5\u627e man -f crontab whatis crontab # \u6a21\u7cca\u67e5\u8be2 man -k crontab apropos crontab \u8f93\u51fa\u7ed3\u679c\u5982\u4e0b\uff1a crontab (5) - files used to schedule the execution of programs crontab (1) - maintains crontab files for individual users crontab (1p) - schedule periodic background work \u67e5\u627ecrontab\u7b2c5\u7ae0\u7684\u5185\u5bb9\uff0c\u5219\u53ef\u4ee5\u6267\u884c\uff1a man 5 crontab \u5e38\u7528\u5feb\u6377\u952e\u793a\u4f8bs\uff1a 1G : go to the 1 st line 10G : go to the 10 th line G : go to the end of the page /^SELinux : search the word SELinux /section OPTIONS : go to the section OPTIONS","title":"3.13.man\u547d\u4ee4"},{"location":"linux/SRE/01-fundamentals/#314tr","text":"tr \u547d\u4ee4\u53ef\u4ee5\u5bf9\u6765\u81ea\u6807\u51c6\u8f93\u5165\u7684\u5b57\u7b26\u8fdb\u884c\u66ff\u6362\u3001\u538b\u7f29\u548c\u5220\u9664\u3002\u5b83\u53ef\u4ee5\u5c06\u4e00\u7ec4\u5b57\u7b26\u53d8\u6210\u53e6\u4e00\u7ec4\u5b57\u7b26\u3002 \u683c\u5f0f\uff1a tr [OPTION]... SET1 [SET2] \u4e3e\u4f8b\uff1a # \u5c06\u8f93\u5165\u5b57\u7b26\u7531\u5927\u5199\u8f6c\u6362\u4e3a\u5c0f\u5199 $ echo \"HELLO WORLD\" | tr 'A-Z' 'a-z' hello world # \u5220\u9664\u51fa\u73b0\u7684\u6570\u5b57 $ echo \"HELLO 1234 WORLD 4567\" | tr -d '0-9' HELLO WORLD # \u4ece\u8f93\u5165\u6587\u672c\u4e2d\u5c06\u4e0d\u5728\u8865\u96c6\u4e2d\u7684\u6240\u6709\u5b57\u7b26\u5220\u9664\uff08\u53ea\u4fdd\u7559\u6570\u5b571\uff0c2\uff0c3\uff0c4\uff0c5\uff09 $ echo \"HELLO 1234 WORLD 4567\" | tr -d -c '1-5' 123445 # \u5c06\u8fde\u7eed\u91cd\u590d\u7684\u5b57\u7b26\u4ee5\u5355\u72ec\u4e00\u4e2a\u5b57\u7b26\u8868\u793a $ echo \"HELLOOO 1222235555555554\" | tr -s 'O215' HELLO 12354 # \u5220\u9664\u7531\u4e8eWindows\u6587\u4ef6\u9020\u6210\u7684'^M'\u5b57\u7b26 $ cat file.txt | tr -s '\\r' '\\n' > new.txt $ cat file.txt | tr -d '\\r' > new.txt # \u5c06\u6362\u884c\u7b26\u66ff\u6362\u6210\u5236\u8868\u7b26 $ cat file.txt | tr '\\n' '\\t' > new.txt # \u5c06\u5927\u5199\u5b57\u6bcd\u8f6c\u6362\u4e3a\u5c0f\u5199\u5b57\u6bcd $ echo \"HELLO 1234 WORLD 4567\" | tr '[:upper:]' '[:lower:]' hello 1234 world 4567","title":"3.14.tr\u547d\u4ee4"},{"location":"linux/SRE/01-fundamentals/#315tee","text":"tee \u547d\u4ee4\u57fa\u4e8e\u6807\u51c6\u8f93\u5165\u8bfb\u53d6\u6570\u636e\uff0c\u6807\u51c6\u8f93\u51fa\u6216\u6587\u4ef6\u5199\u5165\u6570\u636e\u3002 \u4e3e\u4f8b\uff1a # ping\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u4e0d\u4ec5\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4e5f\u540c\u65f6\u5199\u5165\u6587\u4ef6output.txt\u4e2d\uff08\u8986\u76d6\u5f0f\u5199\u5165\uff09\u3002 $ ping www.baidu.com | tee output.txt # ping\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u4e0d\u4ec5\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4e5f\u540c\u65f6\u5199\u5165\u6587\u4ef6output.txt\u4e2d\uff08\u8ffd\u52a0\u5f0f\u5199\u5165\uff09\u3002 $ ping www.baidu.com | tee -a output.txt # ping\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u4e0d\u4ec5\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4e5f\u540c\u65f6\u5199\u5165\u591a\u4e2a\u6587\u4ef6\u4e2d\uff08\u8986\u76d6\u5f0f\u5199\u5165\uff09\u3002 $ ping www.baidu.com | tee output1.txt output2.txt output3.txt # ls\u547d\u4ee4\u7684\u8f93\u51fa\u5199\u5165\u6587\u4ef6output.txt\u4e2d\uff0c\u5e76\u4f5c\u4e3awc\u547d\u4ee4\u7684\u8f93\u5165\u3002 $ ls *.txt | tee output.txt | wc -l 4 # cat output.txt f1.txt f2.txt output.txt test.txt \u6280\u5de7\uff1a \u5728vi\u4f7f\u7528\u4e2d\uff0c\u901a\u8fc7 tee \u547d\u4ee4\u63d0\u5347\u6587\u4ef6\u5199\u5165\u6743\u9650\u3002 \u6bd4\u5982\u975eroot\u7528\u6237\u6267\u884c vi /etc/hosts \uff0c\u5728vi\u4e2d\u4f7f\u7528 :w !sudo tee % \u53ef\u4ee5\u63d0\u9ad8\u6743\u9650\u4fdd\u5b58\u8fd9\u4e2a\u6587\u4ef6\u3002","title":"3.15.tee\u547d\u4ee4"},{"location":"linux/SRE/01-fundamentals/#316lang","text":"\u5b89\u88c5\u8bed\u8a00\u5305\u3002 # Ubuntu sudo apt install locales-all # Rocky sudo yum install glibc-langpack-zh.x86_64 # openSUSE sudo zypper install glibc-locale glibc-locale-32bit glibc-locale-base \u67e5\u770b\u5f53\u524d\u8bed\u8a00\u8bbe\u7f6e\uff1a echo $LANG locale -a locale -k LC_TIME localectl status localectl list-locales \u5168\u5c40locale\u914d\u7f6e(Global locale settings)\u3002 # openSUSE & Rocky sudo cat /etc/locale.conf # Ubuntu sudo cat /etc/default/locale \u4e34\u65f6\u4fee\u6539\u5f53\u524dsession\u7684locale\u3002 LANG = \"zh_CN.utf8\" \u6c38\u4e45\u4fee\u6539locale\u8bbe\u7f6e\u3002 sudo localectl set-locale LANG = zh_CN.utf8 \u4fee\u6539\u56de\u539f\u8bbe\u7f6e\u3002 sudo localectl set-locale LANG = en_US.utf8 Tips: Mac OS ssh\u767b\u9646Linux\u662f\u7ec8\u7aef\u63d0\u793a /usr/bin/manpath: can't set the locale; make sure $LC_* and $LANG are correct \u89e3\u51b3\u65b9\u6cd5\uff1a\u5728\u672c\u5730mac\u7535\u8111\u4e0a\u4fee\u6539/etc/ssh/ssh_config\u6216\u8005/etc/ssh/ssh_config\u6587\u4ef6\uff0c\u5220\u9664\u6389\u6216\u8005\u6ce8\u91ca\u6389\u8fd9\u4e00\u884c\u914d\u7f6e\u5185\u5bb9 # SendEnv LANG LC_* \u3002 \u5982\u679c\u4f7f\u7528\u7684\u662f Iterm2 \uff0c\u53ef\u4ee5\u6253\u5f00 iterm2 \u7684 preferences -> Profiles -> Terminal \u83dc\u5355\u91cc\u5173\u95ed Set locale variables automatically \u9009\u9879\u3002","title":"3.16.\u8bed\u8a00\u73af\u5883LANG"},{"location":"linux/SRE/01-fundamentals/#317","text":"\u7b26\u53f7 $ \u7684\u7528\u6cd5\uff1a $ \uff0c\u83b7\u53d6\u53d8\u96f6\u503c\u3002 x = 1 echo $x echo \" $x \" \u5efa\u8bae\u4f7f\u7528\"$x\"\uff0c\u4ee5\u907f\u514dshell\u7f16\u7a0b\u4e2d\u4ea7\u751f\u6b67\u4e49\u3002\u5982\u4e0b\u4f8b\uff1a s = \"this is a string\" echo $s echo \"this is a string\" \u6267\u884c [ $s == \"this is a string\" ] \u4f1a\u62a5\u9519\uff0c\u8fd9\u662f\u5b9e\u9645\u751f\u6210\u7684\u6bd4\u8f83\u5f0f this is a string == \"this is a string\" \u3002 \u6211\u4eec\u9884\u671f\u7684\u662f \"this is a string\" == \"this is a string\" \uff0c\u6240\u4ee5\u9700\u8981\u6539\u6210 [ \"$s\" == \"this is a string\" ] \u3002 $0 , $1 , $n , $# \uff1a \u751f\u6210\u4e00\u4e2a\u6d4b\u8bd5\u811a\u672c\u3002 echo 'echo $0 $1 $2 $#' > test.sh chmod 755 test.sh \u9a8c\u8bc1\u5404\u4e2a\u53c2\u6570\u4f4d\u7f6e\u3002 ./test.sh a b c d e \u8f93\u51fa\u7ed3\u679c\uff1a ./test.sh a b 5 \u7ed3\u8bba\uff1a $0 \u8f93\u51fa\u811a\u672c\u6587\u4ef6\u540d\uff1b $1 \u8f93\u51fa\u7b2c\u4e00\u4e2a\u53c2\u6570\uff1b $2 \u8f93\u51fa\u7b2c\u4e8c\u4e2a\u53c2\u6570\uff1b $# \u8f93\u51fa\u53c2\u6570\u4e2a\u6570\u3002 ${} ${} \u7528\u4e8e\u533a\u5206\u53d8\u91cf\u7684\u8fb9\u754c\u3002 \u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c $abc \u65e0\u7ed3\u679c\u8f93\u51fa\uff0c ${a}bc \u8f93\u51fa\u7ed3\u679c stringbc \uff0c\u901a\u8fc7{}\u6307\u5b9a\u4e86\u67d0\u4e2a\u5b57\u7b26\u5c5e\u4e8e\u53d8\u91cf\u3002 a = \"string\" echo ${ a } bc echo $abc ${#} ${#} \u662f\u8fd4\u56de\u53d8\u91cf\u503c\u7684\u957f\u5ea6\u3002 s = 'this is a string' echo \" $s \" echo \" ${# s } \" \u547d\u4ee4 echo \"${#s}\" \u8f93\u51fa\u7ed3\u679c\u662f\u5b57\u4e32 this is a string \u7684\u957f\u5ea6 16 \u3002 $? $? \u662f\u8fd4\u56de\u4e0a\u4e00\u547d\u4ee4\u662f\u5426\u6210\u529f\u7684\u72b6\u6001\uff0c 0 \u4ee3\u8868\u6210\u529f\uff0c\u975e\u96f6\u4ee3\u8868\u5931\u8d25\u3002 ls \u662f\u4e00\u4e2a\u547d\u4ee4\uff0c\u6240\u4ee5\u8fd4\u56de\u503c\u662f 0 \u3002 tom \u662f\u4e00\u4e2a\u4e0d\u5b58\u5728\u7684\u547d\u4ee4\uff0c\u5219\u8fd4\u56de 127 \u3002 ls echo $? tom echo $? $() $() \u7b49\u540c\u4e8e\u53cd\u5f15\u53f7\u3002 echo $(ls) \u7b49\u540c\u4e8e\u6267\u884c ls \u547d\u4ee4\u3002 $() \u7684\u5f0a\u7aef\u662f\uff0c\u4e0d\u662f\u6240\u6709\u7684\u7c7bunix\u7cfb\u7edf\u90fd\u652f\u6301\uff0c\u53cd\u5f15\u53f7\u662f\u80af\u5b9a\u652f\u6301\u7684\u3002 $() \u7684\u4f18\u52bf\u662f\u76f4\u89c2\uff0c\u5728\u8f6c\u79fb\u5904\u7406\u65f6\uff0c\u6bd4\u53cd\u5f15\u53f7\u76f4\u89c2\u5bb9\u6613\u4e9b\u3002 echo $( ls ) # test.sh echo $( cat $( ls )) # echo $0 $1 $2 $# \u4e0a\u8ff0\u5d4c\u5957\u683c\u5f0f\u4e2d\uff0cls\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u662fcat\u547d\u4ee4\u7684\u8f93\u5165\uff0c\u53ef\u4ee5\u8fdb\u884c\u591a\u5c42\u5d4c\u5957\uff0c\u5185\u5c42\u547d\u4ee4\u7684\u8f93\u51fa\u662f\u5916\u5c42\u547d\u4ee4\u7684\u8f93\u5165\u3002 $[] $[] \u662f\u8868\u8fbe\u5f0f\u8ba1\u7b97\u3002 echo $ [ 3 + 2 ] $- $- \u663e\u793ashell\u5f53\u524d\u6240\u4f7f\u7528\u7684\u9009\u9879\u3002 \u6267\u884c echo $- \uff0c\u8f93\u51fa\u7ed3\u679c himBHs \u3002himBH\u6bcf\u4e00\u4e2a\u5b57\u7b26\u662f\u4e00\u4e2ashell\u7684\u9009\u9879\u3002 $! $! \u83b7\u53d6\u6700\u540e\u4e00\u4e2a\u8fd0\u884c\u7684\u540e\u53f0\u8fdb\u7a0b\u7684pid\u3002 \u6bd4\u5982\u6267\u884c cat test.sh & \uff0c\u7ed3\u679c\u4e2d\u4f1a\u5305\u542b\u4e00\u4e2apid\u53f7\uff0c\u9a6c\u4e0a\u7740\u6267\u884c echo $! \uff0c\u5982\u679c2\u4e2a\u547d\u4ee4\u95f4\u9694\u4e4b\u95f4\u6ca1\u6709\u5176\u4ed6\u540e\u53f0\u8fdb\u7a0b\u6267\u884c\uff0c\u5219\u53ef\u4ee5\u5f97\u5230\u548c\u524d\u9762\u4e00\u81f4\u7684pid\u53f7\u3002 !$ !$ \u8fd4\u56de\u4e0a\u4e00\u6761\u547d\u4ee4\u7684\u6700\u540e\u4e00\u4e2a\u53c2\u6570\u3002 \u6267\u884c ./test.sh a b c iamhere \uff0c\u5f97\u5230\u7ed3\u679c ./test.sh a b 4 \u3002 \u6267\u884c echo !$ \uff0c\u5f97\u52302\u4e2a\u7ed3\u679c\uff0c echo iamhere \u548c iamhere \u3002 !! !! \u8f93\u51fa\u4e0a\u4e00\u6761\u547d\u4ee4\uff0c\u5e76\u6267\u884c\u3002 !! \u4f1a\u5148\u8f93\u51fa\u4e0a\u4e00\u6761\u547d\u4ee4 cat test.sh \uff0c\u7136\u540e\u518d\u6267\u884c\u8fd9\u6761\u547d\u4ee4\uff0c\u7b2c\u4e8c\u884c\u5373\u6267\u884c\u7ed3\u679c\u3002 [ vagrant@lizard:~ ] $ cat test.sh echo $0 $1 $2 $# [ vagrant@lizard:~ ] $ !! cat test.sh echo $0 $1 $2 $# $$ $$ \u8f93\u51fa\u5f53\u524d\u8fdb\u7a0b\u7684pid\u3002 echo $$ $@ & $* $@ \u548c $* \u662f\u5bf9\u4f20\u5165\u53c2\u6570\u7684\u4e0d\u540c\u4f53\u73b0\uff0c $@ \u662f\u4ee5\u53d8\u91cf\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff0c $* \u662f\u4ee5\u6570\u7ec4\u7684\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\u3002 \u521b\u5efa\u4e00\u4e2a\u6587\u4ef6 script.sh \u5305\u542b\u4e0b\u9762\u7684\u811a\u672c\u3002\u5e76\u6dfb\u52a0\u6267\u884c\u6743\u9650 chmod 755 script.sh \u3002 echo '$@\u4ee5\u53d8\u91cf\u65b9\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a' for x in \" $@ \" do echo $x done echo '$*\u4ee5\u6570\u7ec4\u7684\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a' for x in \" $* \" do echo $x done \u8f93\u51fa\u7ed3\u679c\uff1a $@ \u4ee5\u53d8\u91cf\u65b9\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a a b 3 5 d $* \u4ee5\u6570\u7ec4\u7684\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a a b 3 5 d","title":"3.17.\u7b26\u53f7$\u7528\u6cd5"},{"location":"linux/SRE/02-filesystem/","text":"\u7b2c\u4e8c\u7ae0 \u6587\u4ef6\u7cfb\u7edf \u00b6 \u6587\u4ef6\u7cfb\u7edf\u5c42\u6b21\u6807\u51c6\uff08Filesystem Hierarchy Standard, FHS\uff09\uff0c\u5b83\u662fLinux \u6807\u51c6\u5e93\uff08Linux Standards Base, LSB\uff09\u89c4\u8303\u7684\u4e00\u90e8\u5206\u3002 \u6839\u76ee\u5f55 / \u6307\u6587\u4ef6\u7cfb\u7edf\u6811\u7684\u6700\u9ad8\u5c42\u3002 \u6839\u5206\u533a\u5728\u7cfb\u7edf\u542f\u52a8\u65f6\u9996\u5148\u6302\u8f7d\u3002 \u7cfb\u7edf\u542f\u52a8\u65f6\u8fd0\u884c\u7684\u6240\u6709\u7a0b\u5e8f\u90fd\u5fc5\u987b\u5728\u6b64\u5206\u533a\u4e2d\u3002 1.\u4e3b\u8981\u76ee\u5f55 \u00b6 \u4ee5\u4e0b\u76ee\u5f55\u5fc5\u987b\u5728\u6839\u5206\u533a\u4e2d\uff1a /bin - \u7528\u6237\u57fa\u672c\u7a0b\u5e8f\u3002 \u5305\u542b\u672a\u6302\u8f7d\u5176\u4ed6\u6587\u4ef6\u7cfb\u7edf\u65f6\u6240\u9700\u7684\u53ef\u6267\u884c\u6587\u4ef6\u3002 \u4f8b\u5982\uff0c\u7cfb\u7edf\u542f\u52a8\u3001\u5904\u7406\u6587\u4ef6\u548c\u914d\u7f6e\u6240\u9700\u7684\u7a0b\u5e8f\u3002 \u4e0d\u80fd\u5173\u8054\u5230\u72ec\u7acb\u5206\u533a\uff0c\u64cd\u4f5c\u7cfb\u7edf\u542f\u52a8\u5373\u4f1a\u8c03\u7528\u7684\u7a0b\u5e8f\u3002 /bin/bash - bash \u811a\u672c\u5904\u7406 /bin/cat - \u663e\u793a\u6587\u4ef6\u5185\u5bb9 /bin/cp - \u62f7\u8d1d\u6587\u4ef6 /bin/dd - \u62f7\u8d1d\u6587\u4ef6\uff08\u57fa\u4e8e\u5b57\u8282byte\uff09 /bin/gzip - \u538b\u7f29\u6587\u4ef6 /bin/mount - \u6302\u8f7d\u6587\u4ef6\u7cfb\u7edf /bin/rm - \u5220\u9664\u6587\u4ef6 /bin/vi - \u6587\u4ef6\u7f16\u8f91 /sbin - \u7cfb\u7edf\u57fa\u672c\u7a0b\u5e8f\u3002 \u5305\u542b\u57fa\u672c\u7cfb\u7edf\u7ba1\u7406\u7684\u7a0b\u5e8f\u3002 \u9ed8\u8ba4\u662froot\u7528\u6237\u6709\u6743\u9650\u6267\u884c\uff0c\u56e0\u6b64\u5b83\u4e0d\u5728\u5e38\u89c4\u7528\u6237\u8def\u5f84\u4e2d\u3002 \u4e0d\u80fd\u5173\u8054\u5230\u72ec\u7acb\u5206\u533a\uff0c\u64cd\u4f5c\u7cfb\u7edf\u542f\u52a8\u5373\u4f1a\u8c03\u7528\u7684\u7a0b\u5e8f \u4e00\u4e9b\u91cd\u8981\u7ba1\u7406\u7a0b\u5e8f\uff1a /sbin/fdisk* - \u7ba1\u7406\u786c\u76d8\u5206\u533a /sbin/fsck* - \u6587\u4ef6\u7cfb\u7edf\u68c0\u67e5\u3002\u4e0d\u80fd\u5728\u8fd0\u884c\u7684\u7cfb\u7edf\u4e0a\u9762\u76f4\u63a5\u6267\u884c fsck \uff0c\u635f\u574f\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u6267\u884c\u524d\u9700\u8981 umount \u3002 /sbin/mkfs - \u521b\u5efa\u6587\u4ef6\u7cfb\u7edf /sbin/shutdown - \u5173\u95ed\u7cfb\u7edf /dev - \u8bbe\u5907\u6587\u4ef6 \u4ee5\u592a\u7f51\u5361\u662f\u5185\u6838\u6a21\u5757\uff0c\u5176\u4ed6\u786c\u4ef6\u90fd\u4ee5\u8bbe\u5907dev\u7684\u65b9\u5f0f\u5c55\u73b0\u3002 \u5e94\u7528\u7a0b\u5e8f\u8bfb\u53d6\u548c\u5199\u5165\u8fd9\u4e9b\u6587\u4ef6\u4ee5\u64cd\u4f5c\u4f7f\u7528\u786c\u4ef6\u7ec4\u4ef6\u3002 \u4e24\u79cd\u7c7b\u578b\u8bbe\u5907\u6587\u4ef6\uff1a \u5b57\u7b26\u8bbe\u5907\uff08Character-oriented\uff09\u2013 \u5e8f\u5217\u8bbe\u5907\uff08\u6253\u5370\u673a\uff0c\u78c1\u5e26\u673a\uff0c\u9f20\u6807\u7b49\uff09 \u5757\u8bbe\u5907\uff08Block-oriented\uff09\u2013 \u786c\u76d8\uff0cDVD\u7b49 \u4e0e\u8bbe\u5907\u9a71\u52a8\u7a0b\u5e8f\u7684\u8fde\u63a5\u901a\u8fc7\u5185\u6838\u4e2d\u79f0\u4e3a\u4e3b\u8bbe\u5907\u53f7\u7684\u901a\u9053\u5b9e\u73b0\u3002 \u8fc7\u53bb\uff0c\u8fd9\u4e9b\u6587\u4ef6\u662f\u4f7f\u7528 mknod \u547d\u4ee4\u624b\u52a8\u521b\u5efa\u7684\u3002 \u73b0\u5728\u5f53\u5185\u6838\u53d1\u73b0\u8bbe\u5907\u65f6\uff0c\u5b83\u4eec\u4f1a\u7531 udev \u81ea\u52a8\u521b\u5efa\u3002 \u4e00\u4e9b\u91cd\u8981\u7684\u8bbe\u5907\u6587\u4ef6\uff1a Null\u8bbe\u5907: - /dev/null Zero\u8bbe\u5907: - /dev/zero \u7cfb\u7edf\u7ec8\u7aef: - /dev/console \u865a\u62df\u7ec8\u7aef: - /dev/tty1 \u4e32\u884c\u7aef\u53e3 - /dev/ttyS0 \u5e76\u884c\u7aef\u53e3: - /dev/lp0 \u8f6f\u76d8\u9a71\u52a8\u5668: - /dev/fd0 \u786c\u76d8\u9a71\u52a8\u5668: - /dev/sda \u786c\u76d8\u5206\u533a: - /dev/sda1 CD-ROM\u9a71\u52a8\u5668: - /dev/scd0 /etc - \u914d\u7f6e\u6587\u4ef6 \u5b58\u653e\u7cfb\u7edf\u548c\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6\u3002 \u5927\u90e8\u5206\u90fd\u662fASCII\u6587\u4ef6 \u666e\u901a\u7528\u6237\u53ef\u4ee5\u9ed8\u8ba4\u8bfb\u53d6\u5176\u4e2d\u7684\u5927\u90e8\u5206\u5185\u5bb9\u3002 \u8fd9\u4f1a\u5e26\u6765\u4e00\u4e2a\u6f5c\u5728\u7684\u5168\u95ee\u9898\uff0c\u56e0\u4e3a\u5176\u4e2d\u4e00\u4e9b\u6587\u4ef6\u5305\u542b\u5bc6\u7801\uff0c\u56e0\u6b64\u91cd\u8981\u7684\u662f\u8981\u786e\u4fdd\u8fd9\u4e9b\u6587\u4ef6\u53ea\u80fd\u7531root\u7528\u6237\u8bfb\u53d6\u3002 \u6839\u636eFHS\u6807\u51c6\uff0c\u6b64\u5904\u4e0d\u80fd\u653e\u7f6e\u4efb\u4f55\u53ef\u6267\u884c\u6587\u4ef6\uff0c\u4f46\u5b50\u76ee\u5f55\u53ef\u80fd\u5305\u542bshell\u811a\u672c\u3002 \u51e0\u4e4e\u6bcf\u4e2a\u5df2\u5b89\u88c5\u7684\u670d\u52a1\u5728 /etc \u6216\u5176\u5b50\u76ee\u5f55\u4e2d\u81f3\u5c11\u6709\u4e00\u4e2a\u914d\u7f6e\u6587\u4ef6\u3002 \u4e00\u4e9b\u91cd\u8981\u7684\u914d\u7f6e\u6587\u4ef6: /etc/os-release - \u7cfb\u7edf\u7248\u672c\u4fe1\u606f /etc/DIR_COLORS - ls \u547d\u4ee4\u4e2d\u7684\u989c\u8272\u914d\u7f6e\u4fe1\u606f\uff08openSUSE\u548cRocky\uff09 /etc/fstab - \u914d\u7f6e\u8981\u6302\u8f7d\u7684\u6587\u4ef6\u7cfb\u7edf /etc/profile - Shell\u767b\u5f55\u811a\u672c /etc/passwd - \u7528\u6237\u4fe1\u606f\u96c6\u5408\uff08\u4e0d\u542b\u5bc6\u7801\uff09 /etc/shadow - \u5bc6\u7801\u548c\u76f8\u5173\u4fe1\u606f /etc/group - \u7528\u6237\u7ec4\u4fe1\u606f\u96c6\u5408 /etc/cups/* - \u7528\u4e8eCUPS\u6253\u5370\u7cfb\u7edf\uff08CUPS=Common UNIX Printing System\uff09 /etc/hosts - \u4e3b\u673a\u540d\u673a\u5668IP\u5730\u5740 /etc/motd - \u767b\u5f55\u540e\u663e\u793a\u7684\u6b22\u8fce\u4fe1\u606f /etc/issue - \u767b\u5f55\u524d\u663e\u793a\u7684\u6b22\u8fce\u4fe1\u606f /etc/sysconfig/* - \u7cfb\u7edf\u914d\u7f6e\u6587\u4ef6 /lib - \u5e93\uff08Libraries\uff09 \u8bb8\u591a\u7a0b\u5e8f\u90fd\u5177\u6709\u4e00\u4e9b\u901a\u7528\u529f\u80fd\u3002 \u8fd9\u4e9b\u901a\u7528\u529f\u80fd\u53ef\u4ee5\u4fdd\u5b58\u5728\u5171\u4eab\u5e93\u4e2d\u3002 \u5171\u4eab\u5e93\u4e2d\u6587\u4ef6\u7684\u6269\u5c55\u540d\u662f .so \u3002 \u76ee\u5f55 /lib \u5305\u542b\u7684\u5171\u4eab\u5e93\u6587\u4ef6\u4e3b\u8981\u662f\u88ab /bin \u548c /sbin \u76ee\u5f55\u5305\u542b\u7684\u7a0b\u5e8f\u6240\u8c03\u7528\u3002 \u76ee\u5f55 /lib \u7684\u5b50\u76ee\u5f55\u5305\u542b\u4e00\u4e9b\u989d\u5916\u9700\u8981\u7684\u5171\u4eab\u5e93\u3002 \u5185\u6838\u6a21\u5757\u5b58\u50a8\u5728\u76ee\u5f55 /lib/modules \u3002 /lib64 - 64\u4f4d\u5171\u4eab\u5e93\uff0864-Bit Libraries\uff09\uff0c\u7c7b\u4f3c\u76ee\u5f55 /lib \u3002 \u8fd9\u4e2a\u76ee\u5f55\u56e0\u7cfb\u7edf\u67b6\u6784\u4e0d\u540c\u800c\u4e0d\u540c\u3002 \u4e00\u4e9b\u7cfb\u7edf\u652f\u6301\u4e0d\u540c\u7684\u4e8c\u8fdb\u5236\u683c\u5f0f\u5e76\u4fdd\u7559\u540c\u4e00\u4e2a\u5171\u4eab\u5e93\u7684\u4e0d\u540c\u7248\u672c\u3002 /usr - \u5305\u542b\u5e94\u7528\u7a0b\u5e8f\u3001\u56fe\u5f62\u754c\u9762\u6587\u4ef6\u3001\u5e93\u3001\u672c\u5730\u7a0b\u5e8f\u3001\u6587\u6863\u7b49\u3002 /usr \u5373 Unix System Resources. \u4f8b\u5982\uff1a /usr/X11R6/ - X Window \u7cfb\u7edf\u6587\u4ef6 /usr/bin/ - \u51e0\u4e4e\u5305\u542b\u6240\u6709\u53ef\u6267\u884c\u6587\u4ef6 /usr/lib/ - \u5305\u542b\u5e93\u548c\u5e94\u7528\u7a0b\u5e8f /usr/lib64/ - \u5305\u542b64\u4f4d\u5e93\u548c\u5e94\u7528\u7a0b\u5e8f /usr/include/ - \u5305\u542bC\u7a0b\u5e8f\u7684\u5934\u6587\u4ef6\uff08head file\uff09 /usr/local/ - \u5305\u542b\u672c\u5730\u5b89\u88c5\u7a0b\u5e8f\u3002\u8fd9\u4e2a\u76ee\u5f55\u4e0b\u7684\u5185\u5bb9\u4e0d\u4f1a\u88ab\u7cfb\u7edf\u5347\u7ea7\u6240\u8986\u76d6\u3002\u4e0b\u97623\u4e2a\u76ee\u5f55\u5728\u521d\u59cb\u5b89\u88c5\u540e\u662f\u7a7a\u7684\u3002 /usr/local/bin - /usr/local/sbin - /usr/local/lib - /usr/sbin/ - \u7cfb\u7edf\u7ba1\u7406\u7a0b\u5e8f /usr/src/ - \u5185\u6838\u548c\u5e94\u7528\u7a0b\u5e8f\u7684\u6e90\u4ee3\u7801 /usr/src/linux - /usr/share/ - \u7ed3\u6784\u5316\u72ec\u7acb\u6570\u636e /usr/share/doc/ - \u6587\u6863 /usr/share/man/ - man \u547d\u4ee4\u4f7f\u7528\u7684\u5185\u5bb9 /opt - \u7b2c\u4e09\u65b9\u5e94\u7528\u7a0b\u5e8f\u76ee\u5f55 \u5404\u53d1\u884c\u7248\u5305\u542b\u7684\u5e94\u7528\u7a0b\u5e8f\u4e00\u822c\u5b58\u50a8\u5728\u76ee\u5f55 /usr/lib/ \u3002 \u5404\u53d1\u884c\u7248\u53ef\u9009\u7a0b\u5e8f\uff0c\u6216\u7b2c\u4e09\u65b9\u5e94\u7528\u7a0b\u5e8f\u5219\u5b58\u50a8\u5728\u76ee\u5f55 /opt \u3002 \u5728\u5b89\u88c5\u65f6\uff0c\u4f1a\u4e3a\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f\u7684\u6587\u4ef6\u521b\u5efa\u4e00\u4e2a\u76ee\u5f55\uff0c\u5176\u4e2d\u5305\u542b\u5e94\u7528\u7a0b\u5e8f\u7684\u540d\u79f0\u3002\u6bd4\u5982\uff1a /opt/novell - /boot - \u5f15\u5bfc\u76ee\u5f55 /boot/grub2 - \u5305\u542bGRUB2\u7684\u9759\u6001\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\u6587\u4ef6\uff08GRUB = Grand Unified Boot Loader\uff09\u3002 \u5305\u542b\u4ee5\u94fe\u63a5 vmlinuz \u548c initrd \u6807\u8bc6\u7684\u5185\u6838\u548c initrd \u6587\u4ef6\u3002 /root - \u7ba1\u7406\u5458\u7684\u4e3b\u76ee\u5f55\uff08home directory\uff09\u3002 root \u7528\u6237\u7684\u4e3b\u76ee\u5f55\u3002\u5176\u4ed6\u7528\u6237\u7684\u4e3b\u76ee\u5f55\u662f\u5728\u76ee\u5f55 /home \u4e0b\u3002 root \u7528\u6237\u7684\u767b\u5f55\u73af\u5883\u914d\u7f6e\u4fdd\u5b58\u81f3 /root \u5206\u533a\u4e2d\u3002 /home - \u7528\u6237\u4e3b\u76ee\u5f55 \u6bcf\u4e2a\u7cfb\u7edf\u7528\u6237\u90fd\u6709\u4e00\u4e2a\u5206\u914d\u7684\u6587\u4ef6\u533a\u57df\uff0c\u8be5\u6587\u4ef6\u533a\u57df\u5728\u767b\u5f55\u540e\u6210\u4e3a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b83\u4eec\u5b58\u5728\u4e8e /home \u4e2d\u3002 /home \u4e2d\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u53ef\u4ee5\u4f4d\u4e8e\u5355\u72ec\u7684\u5206\u533a\u4e2d\uff0c\u4e5f\u53ef\u4ee5\u4f4d\u4e8e\u7f51\u7edc\u4e0a\u7684\u53e6\u4e00\u53f0\u8ba1\u7b97\u673a\u4e0a\u3002 \u7528\u6237\u914d\u7f6e\u4fe1\u606f\u548c\u914d\u7f6e\u6587\u4ef6\uff08user profile and configuration files\uff09\u4e3b\u8981\u6709\uff1a .profile - \u7528\u6237\u79c1\u6709\u767b\u5f55\u811a\u672c .bashrc - bash \u7684\u914d\u7f6e\u6587\u4ef6 .bash_history - bash \u73af\u5883\u4e0b\u4fdd\u6301\u547d\u4ee4\u5386\u53f2\u8bb0\u5f55 run - \u5e94\u7528\u7a0b\u5e8f\u72b6\u6001\u6587\u4ef6 \u4e3a\u5e94\u7528\u7a0b\u5e8f\u63d0\u4f9b\u4e86\u4e00\u4e2a\u6807\u51c6\u4f4d\u7f6e\u6765\u5b58\u50a8\u5b83\u4eec\u9700\u8981\u7684\u4e34\u65f6\u6587\u4ef6\uff0c\u4f8b\u5982\u5957\u63a5\u5b57\u548c\u8fdb\u7a0bID\u3002 \u8fd9\u4e9b\u6587\u4ef6\u4e0d\u80fd\u5b58\u50a8\u5728 /tmp \u4e2d\uff0c\u56e0\u4e3a /tmp \u4e2d\u7684\u6587\u4ef6\u53ef\u80fd\u4f1a\u88ab\u5220\u9664\u3002 /run/media//* - \u53ef\u79fb\u52a8\u8bbe\u5907\u7684\u6302\u8f7d\u70b9\uff0c\u4f8b\u5982\uff1a /run/media/media_name/ /run/media/cdrom/ - /run/media/dvd/ - /run/media/usbdisk/ - /mnt - \u6587\u4ef6\u7cfb\u7edf\u4e34\u65f6\u6302\u8f7d\u70b9 \u7528\u4e8e\u6302\u8f7d\u4e34\u65f6\u4f7f\u7528\u7684\u6587\u4ef6\u7cfb\u7edf\u7684\u76ee\u5f55\u3002 \u6587\u4ef6\u7cfb\u7edf\u4f7f\u7528 mount \u547d\u4ee4\u6302\u8f7d\uff0c\u4f7f\u7528 umount \u547d\u4ee4\u5220\u9664\u3002 \u5b50\u76ee\u5f55\u9ed8\u8ba4\u4e0d\u5b58\u5728\uff0c\u4e5f\u4e0d\u4f1a\u81ea\u52a8\u521b\u5efa\u3002 /srv - \u670d\u52a1\u6570\u636e\u76ee\u5f55 \u5b58\u653e\u5404\u79cd\u670d\u52a1\u7684\u6570\u636e\uff0c\u6bd4\u5982\uff1a /srv/www - \u7528\u4e8e\u5b58\u653e Apache Web Server \u7684\u6570\u636e /srv/ftp - \u7528\u4e8e\u5b58\u653e FTP server \u7684\u6570\u636e /var - \u53ef\u53d8\u6587\u4ef6\uff08Variable Files\uff09 \u5728\u7cfb\u7edf\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u4f1a\u88ab\u4fee\u6539\u7684\u6587\u4ef6 Important subdirectories: /var/lib/ - \u53ef\u53d8\u5e93\u6587\u4ef6\uff0c\u5e94\u7528\u7a0b\u5e8f\u72b6\u6001\u4fe1\u606f\u6570\u636e /var/log/ - \u65e5\u5fd7\u6587\u4ef6 /var/run/ - \u8fd0\u884c\u4e2d\u7684\u8fdb\u7a0b\u7684\u4fe1\u606f /var/lock/ - \u591a\u7528\u6237\u8bbf\u95ee\u65f6\u7684\u9501\u6587\u4ef6 /var/cache - \u5e94\u7528\u7a0b\u5e8f\u7f13\u5b58\u6570\u636e\u76ee\u5f55 /var/opt - \u4e13\u4e3a /opt \u4e0b\u7684\u5e94\u7528\u7a0b\u5e8f\u5b58\u50a8\u53ef\u53d8\u6570\u636e /var/mail - /var/spool/ - \u5e94\u7528\u7a0b\u5e8f\u6570\u636e\u6c60\uff0c\u6bd4\u5982\uff1a\u6253\u5370\u673a\uff0c\u90ae\u4ef6 /var/spool/mail - /var/spool/cron - /tmp - \u4e34\u65f6\u6587\u4ef6 \u7a0b\u5e8f\u5728\u8fd0\u884c\u65f6\u521b\u5efa\u4e34\u65f6\u6587\u4ef6\u7684\u4f4d\u7f6e /proc - \u8fdb\u7a0b\u6587\u4ef6 \u865a\u62df\u6587\u4ef6\u7cfb\u7edf\uff0c\u4e0d\u5360\u7a7a\u95f4\uff0c\u5927\u5c0f\u59cb\u7ec8\u4e3a\u96f6\uff0c\u4fdd\u6301\u5f53\u524d\u8fdb\u7a0b\u7684\u72b6\u6001\u4fe1\u606f \u5305\u542b\u6709\u5173\u5404\u4e2a\u8fdb\u7a0b\u7684\u4fe1\u606f\u7684\u76ee\u5f55\uff0c\u6839\u636e\u8fdb\u7a0b\u7684 PID \u53f7\u547d\u540d \u6709\u4e9b\u503c\u53ef\u4ee5\u4e34\u65f6\u5728\u7ebf\u66f4\u6539\u751f\u6548\uff0c\u4f46\u91cd\u542f\u540e\u4e22\u5931 /proc/cpuinfo/ - Processor information /proc/dma/ - Use of DMA ports /proc/interrupts/ - Use of interrupts /proc/ioports/ - Use of I/O ports /proc/filesystems/ - File system formats the kernel knows /proc/modules/ - Active modules /proc/mounts/ - Mounted file systems /proc/net/* - Network information and statistics /proc/partitions/ - Existing partitions /proc/bus/pci/ - Connected PCI devices /proc/bus/scsi/ - Connected SCSI devices /proc/sys/* - System and kernel information /proc/version - Kernel version /sys - \u7cfb\u7edf\u4fe1\u606f\u76ee\u5f55 \u865a\u62df\u6587\u4ef6\u7cfb\u7edf\uff0c\u4ec5\u5b58\u5728\u4e8e\u5185\u5b58\u4e2d\uff0c\u6587\u4ef6\u5927\u5c0f\u4e3a\u96f6\u3002\u4e3b\u8981\u63d0\u4f9b\u5982\u4e0b\u4fe1\u606f\uff1a \u786c\u4ef6\u603b\u7ebf\uff08hardware buses\uff09 \u786c\u4ef6\u8bbe\u5907\uff08hardware devices\uff09 \u6709\u6e90\u8bbe\u5907\uff08active devices\uff09 \u9a71\u52a8\u7a0b\u5e8f\uff08drivers\uff09 2.\u6587\u4ef6\u64cd\u4f5c\u547d\u4ee4 \u00b6 2.1.\u663e\u793a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55 \u00b6 pwd\u547d\u4ee4\uff08print working directory\uff09: -L: \u663e\u793a\u94fe\u63a5\u8def\u5f84 -P\uff1a\u663e\u793a\u771f\u5b9e\u7269\u7406\u8def\u5f84 2.2.\u76f8\u5bf9\u548c\u7edd\u5bf9\u8def\u5f84 \u00b6 \u5bf9\u4e8e\u7edd\u5bf9\u8def\u5f84 /etc/firewalld/policies \uff0c\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u5f97\u5230\u8be5\u8def\u5f84\u7684\u57fa\u540d policies \u548c\u76ee\u5f55\u540d /etc/firewalld \u3002 basename /etc/firewalld/policies dirname /etc/firewalld/policies 2.3.\u66f4\u6539\u76ee\u5f55 \u00b6 . \u6307\u5f53\u524d\u76ee\u5f55\uff0c\u5373 pwd \u547d\u4ee4\u6240\u8fd4\u56de\u7684\u76ee\u5f55\u3002 .. \u6307\u5f53\u524d\u76ee\u5f55\u7684\u4e0a\u4e00\u7ea7\u76ee\u5f55\uff0c\u53ca\u5f53\u524d\u76ee\u5f55\u7684\u7236\u76ee\u5f55\u3002 \u5207\u6362\u81f3\u7236\u76ee\u5f55\uff1a cd .. \u5207\u6362\u81f3\u5f53\u524d\u7528\u6237\u4e3b\u76ee\u5f55\uff1a cd ~ \u5207\u6362\u81f3\u4e0a\u6b21\u5de5\u4f5c\u76ee\u5f55\uff1a cd - echo $PWD \uff1a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55 echo $OLDPWD \uff1a\u4e0a\u6b21\u5de5\u4f5c\u76ee\u5f55 2.4.\u5217\u51fa\u76ee\u5f55\u5185\u5bb9 \u00b6 ls \u547d\u4ee4\uff1a -a \u663e\u793a\u6240\u6709\u6587\u4ef6\u53ca\u76ee\u5f55 (. \u5f00\u5934\u7684\u9690\u85cf\u6587\u4ef6\u4e5f\u4f1a\u5217\u51fa) -A \u540c -a \uff0c\u4f46\u4e0d\u5217\u51fa . (\u76ee\u524d\u76ee\u5f55) \u53ca .. (\u7236\u76ee\u5f55) -l \u9664\u6587\u4ef6\u540d\u79f0\u5916\uff0c\u4ea6\u5c06\u6587\u4ef6\u578b\u6001\u3001\u6743\u9650\u3001\u62e5\u6709\u8005\u3001\u6587\u4ef6\u5927\u5c0f\u7b49\u8d44\u8baf\u8be6\u7ec6\u5217\u51fa -r \u5c06\u6587\u4ef6\u4ee5\u76f8\u53cd\u6b21\u5e8f\u663e\u793a(\u539f\u5b9a\u4f9d\u82f1\u6587\u5b57\u6bcd\u6b21\u5e8f) -t \u5c06\u6587\u4ef6\u4f9d\u5efa\u7acb\u65f6\u95f4\u4e4b\u5148\u540e\u6b21\u5e8f\u5217\u51fa -F \u5728\u5217\u51fa\u7684\u6587\u4ef6\u540d\u79f0\u540e\u52a0\u4e00\u7b26\u53f7\uff1b\u4f8b\u5982\u53ef\u6267\u884c\u6863\u5219\u52a0 \"*\", \u76ee\u5f55\u5219\u52a0 \"/\" -R \u9012\u5f52\u5217\u51fa\u5b50\u76ee\u5f55 -S \u6309\u6587\u4ef6\u5927\u5c0f\u6392\u5e8f\uff0c\u4ece\u5927\u5230\u5c0f -1 \u6309\u4e00\u4e2a\u6587\u4ef6\u4e00\u884c\u5217\u51fa -t \u6309\u6587\u4ef6\u65f6\u95f4\u6392\u5e8f\uff0c\u6700\u65b0\u7684\u5728\u524d -U \u4e0d\u6392\u5e8f\u8f93\u51fa\uff0c\u6309\u76ee\u5f55\u5b58\u653e\u987a\u5e8f\u5217\u51fa -u \u914d\u5408 -lt \uff0c\u6309\u8bbf\u95ee\u65f6\u95f4\u6392\u5e8f\u5e76\u663e\u793a\uff1b\u914d\u5408 -l \uff0c\u663e\u793a\u8bbf\u95ee\u65f6\u95f4\u5e76\u6309\u540d\u79f0\u6392\u5e8f\uff1b \u5426\u5219\u6309\u8bbf\u95ee\u65f6\u95f4\u6392\u5e8f\uff0c\u6700\u65b0\u7684\u5728\u524d -X \u6309\u6587\u4ef6\u6269\u5c55\u540d\u5b57\u6bcd\u987a\u5e8f\u6392\u5e8f\u8f93\u51fa -F \u5bf9\u4e0d\u540c\u7c7b\u578b\u6587\u4ef6\u663e\u793a\u65f6\u9644\u52a0\u4e0d\u540c\u7684\u7b26\u53f7\uff0c * / = > @ | \u4e4b\u4e00 ls \u547d\u4ee4\u67e5\u770b\u4e0d\u540c\u6587\u4ef6\u662f\u7684\u989c\u8272\uff0c\u7531 /etc/DIR_COLORS \u548c\u53d8\u91cf @LS_COLORS \u5b9a\u4e49\u3002 2.5.\u6587\u4ef6\u72b6\u6001stat \u00b6 \u6bcf\u4e2a\u6587\u4ef6\u6709\u4e09\u4e2a\u65f6\u95f4\u6233\uff1a \u8bbf\u95ee\u65f6\u95f4 Access Time atime : \u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u3002 \u4fee\u6539\u65f6\u95f4 Modify Time mtime : \u6539\u53d8\u6587\u4ef6\u5185\u5bb9\uff08\u6570\u636e\uff09\u3002 \u6539\u53d8\u65f6\u95f4 Change Time ctime : \u5143\u6570\u636e\u53d1\u751f\u6539\u53d8\u3002 \u8bfb\u53d6\u4e09\u4e2a\u65f6\u95f4\u6233\u7684\u547d\u4ee4 stat \uff1a stat /etc/fstab \u8f93\u51fa\u7ed3\u679c\uff1a File: /etc/fstab Size: 927 Blocks: 8 IO Block: 4096 regular file Device: 30h/48d Inode: 263 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2022-10-31 10:26:34.987466959 +0800 Modify: 2022-06-24 14:50:24.387992912 +0800 Change: 2022-06-24 14:50:24.387992912 +0800 Birth: 2022-06-24 14:50:23.755992937 +0800 2.6.\u786e\u5b9a\u6587\u4ef6\u7c7b\u578b \u00b6 \u547d\u4ee4 file \u68c0\u67e5\u6587\u4ef6\u7c7b\u578b\u3002 -b \uff1a\u5217\u51fa\u8fa8\u8bc6\u7ed3\u679c\u65f6\uff0c\u4e0d\u663e\u793a\u6587\u4ef6\u540d\u79f0\u3002 -c \uff1a\u8be6\u7ec6\u663e\u793a\u6307\u4ee4\u6267\u884c\u8fc7\u7a0b\uff0c\u4fbf\u4e8e\u6392\u9519\u6216\u5206\u6790\u7a0b\u5e8f\u6267\u884c\u7684\u60c5\u5f62\u3002 -f <\u540d\u79f0\u6587\u4ef6> \uff1a\u6307\u5b9a\u540d\u79f0\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u6587\u4ef6\u540d\u79f0\u65f6\uff0c\u8ba9file\u4f9d\u5e8f\u8fa8\u8bc6\u8fd9\u4e9b\u6587\u4ef6\uff0c\u683c\u5f0f\u4e3a\u6bcf\u5217\u4e00\u4e2a\u6587\u4ef6\u540d\u79f0\u3002 -L \uff1a \u76f4\u63a5\u663e\u793a\u7b26\u53f7\u8fde\u63a5\u6240\u6307\u5411\u7684\u6587\u4ef6\u7684\u7c7b\u522b\u3002 -v \uff1a \u663e\u793a\u7248\u672c\u4fe1\u606f\u3002 -z \uff1a \u5c1d\u8bd5\u53bb\u89e3\u8bfb\u538b\u7f29\u6587\u4ef6\u7684\u5185\u5bb9\u3002 \u7f16\u8f91\u6587\u4ef6 list.txt \u5305\u542b\u4e00\u4e0b\u5185\u5bb9\uff1a /etc/ /bin /etc/issue \u8fd0\u884c\u547d\u4ee4 file -f list.txt \uff0c\u7ed3\u679c\u5982\u4e0b\uff1a /etc/: directory /bin: directory /etc/issue: symbolic link to ../run/issue 2.7.\u6587\u4ef6\u7f16\u7801\u8f6c\u6362 \u00b6 iconv \u547d\u4ee4\u7528\u4e8e\u5c06\u4e00\u79cd\u7f16\u7801\u4e2d\u7684\u67d0\u4e9b\u6587\u672c\u8f6c\u6362\u4e3a\u53e6\u4e00\u79cd\u7f16\u7801\u3002 \u5982\u679c\u6ca1\u6709\u63d0\u4f9b\u8f93\u5165\u6587\u4ef6\uff0c\u5219\u5b83\u4ece\u6807\u51c6\u8f93\u5165\u4e2d\u8bfb\u53d6\u3002 \u540c\u6837\uff0c\u5982\u679c\u6ca1\u6709\u7ed9\u51fa\u8f93\u51fa\u6587\u4ef6\uff0c\u90a3\u4e48\u5b83\u4f1a\u5199\u5165\u6807\u51c6\u8f93\u51fa\u3002 \u5982\u679c\u6ca1\u6709\u63d0\u4f9b from-encoding \u6216 to-encoding \uff0c\u5219\u5b83\u4f7f\u7528\u5f53\u524d\u672c\u5730\u7684\u5b57\u7b26\u7f16\u7801\u3002 \u5c06\u6587\u672c\u4ece ISO 8859-15 \u5b57\u7b26\u7f16\u7801\u8f6c\u6362\u4e3a UTF-8\uff0c\u8bfb\u5165 input.txt \uff0c\u8f93\u51fa output.txt \u3002 iconv -f ISO-8859-15 -t UTF-8 < input.txt > output.txt \u4ece UTF-8 \u8f6c\u6362\u4e3a ASCII\uff0c\u5c3d\u53ef\u80fd\u8fdb\u884c\u97f3\u8bd1\uff08transliterating\uff09\uff1a echo abc \u00df \u03b1 \u20ac \u00e0\u1e03\u00e7 | iconv -f UTF-8 -t ASCII//TRANSLIT \u8fd0\u884c\u7ed3\u679c\uff1a abc ss ? EUR abc 2.8.\u901a\u914d\u7b26 \u00b6 \u901a\u914d\u7b26\uff0c\u6307\u5305\u542b\u8fd9\u4e9b\u5b57\u7b26\u7684\u5b57\u7b26\u4e32 ? \uff1a\u8868\u793a\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26 * \uff1a\u8868\u793a\u4efb\u610f\u957f\u5ea6\u7684\u4efb\u610f\u5b57\u7b26 [] \uff1a\u5339\u914d\u6307\u5b9a\u8303\u56f4\u5185\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26 [abcd] \uff1a\u5339\u914dabcd\u4e2d\u7684\u4efb\u4f55\u4e00\u4e2a\u5b57\u7b26 [a-z] \uff1a\u5339\u914d\u8303\u56f4a\u5230z\u5185\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26 [!abcd] \uff1a\u4e0d\u5339\u914d\u62ec\u53f7\u91cc\u9762\u4efb\u4f55\u4e00\u4e2a\u5b57\u7b26 {} \uff1a\u8868\u793a\u751f\u6210\u5e8f\u5217\uff0c\u4ee5\u9017\u53f7\u5206\u5272\uff0c\u4e0d\u80fd\u6709\u7a7a\u683c \u793a\u4f8b\uff1a $ touch file_ { a..z } .txt $ touch file_ { A..Z } .txt $ ls file_a.txt file_C.txt file_f.txt file_H.txt file_k.txt file_M.txt file_p.txt file_R.txt file_u.txt file_W.txt file_z.txt file_A.txt file_d.txt file_F.txt file_i.txt file_K.txt file_n.txt file_P.txt file_s.txt file_U.txt file_x.txt file_Z.txt file_b.txt file_D.txt file_g.txt file_I.txt file_l.txt file_N.txt file_q.txt file_S.txt file_v.txt file_X.txt file_B.txt file_e.txt file_G.txt file_j.txt file_L.txt file_o.txt file_Q.txt file_t.txt file_V.txt file_y.txt file_c.txt file_E.txt file_h.txt file_J.txt file_m.txt file_O.txt file_r.txt file_T.txt file_w.txt file_Y.txt $ ls file_ [ a..d ] .* file_a.txt file_d.txt $ ls file_ [ a...d ] .* file_a.txt file_d.txt $ ls file_ [ ad ] .* file_a.txt file_d.txt $ ls file_ [ a-c ] .* file_a.txt file_A.txt file_b.txt file_B.txt file_c.txt $ ls file_ [ a-C ] .* file_a.txt file_A.txt file_b.txt file_B.txt file_c.txt file_C.txt $ ls file_ [ !d-W ] .* file_a.txt file_b.txt file_c.txt file_x.txt file_y.txt file_z.txt file_A.txt file_B.txt file_C.txt file_X.txt file_Y.txt file_Z.txt \u6bd4\u8f83\u6709\u65e0 * \u7684\u533a\u522b\uff1a $ ls -a * file_a.txt file_D.txt file_h.txt file_K.txt file_o.txt file_R.txt file_v.txt file_Y.txt file_A.txt file_e.txt file_H.txt file_l.txt file_O.txt file_s.txt file_V.txt file_z.txt file_b.txt file_E.txt file_i.txt file_L.txt file_p.txt file_S.txt file_w.txt file_Z.txt file_B.txt file_f.txt file_I.txt file_m.txt file_P.txt file_t.txt file_W.txt file_c.txt file_F.txt file_j.txt file_M.txt file_q.txt file_T.txt file_x.txt file_C.txt file_g.txt file_J.txt file_n.txt file_Q.txt file_u.txt file_X.txt file_d.txt file_G.txt file_k.txt file_N.txt file_r.txt file_U.txt file_y.txt $ ls -a . file_C.txt file_g.txt file_J.txt file_n.txt file_Q.txt file_u.txt file_X.txt .. file_d.txt file_G.txt file_k.txt file_N.txt file_r.txt file_U.txt file_y.txt file_a.txt file_D.txt file_h.txt file_K.txt file_o.txt file_R.txt file_v.txt file_Y.txt file_A.txt file_e.txt file_H.txt file_l.txt file_O.txt file_s.txt file_V.txt file_z.txt file_b.txt file_E.txt file_i.txt file_L.txt file_p.txt file_S.txt file_w.txt file_Z.txt file_B.txt file_f.txt file_I.txt file_m.txt file_P.txt file_t.txt file_W.txt file_c.txt file_F.txt file_j.txt file_M.txt file_q.txt file_T.txt file_x.txt 2.9.\u5b57\u7b26\u96c6 \u00b6 [:alpha:] \uff1a\u8868\u793a\u6240\u6709\u7684\u5b57\u6bcd\uff08\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff09\uff0c\u6548\u679c\u540c [a-z] [:digit:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u6570\u5b57\uff0c\u6548\u679c\u540c [0-9] [:xdigit:] \uff1a\u8868\u793a\u5341\u516d\u8fdb\u5236\u6570\u5b57 [:lower:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5c0f\u5199\u5b57\u6bcd [:upper:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5927\u5199\u5b57\u6bcd [:alnum:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5b57\u6bcd\u6216\u6570\u5b57 [:blank:] \uff1a\u8868\u793a\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u548c\u5236\u8868\u7b26\uff09 [:space:] \uff1a\u8868\u793a\u5305\u62ec\u7a7a\u683c\u3001\u5236\u8868\u7b26\uff08\u6c34\u5e73\u548c\u5782\u76f4\uff09\u3001\u6362\u884c\u7b26\u3001\u56de\u8f66\u7b26\u7b49\u5404\u79cd\u7c7b\u578b\u7684\u7a7a\u767d\uff0c\u6bd4 [:blank:] \u8303\u56f4\u66f4\u5e7f [:cntrl:] \uff1a\u8868\u793a\u4e0d\u53ef\u6253\u5370\u7684\u63a7\u5236\u5b57\u7b26\uff08\u9000\u683c\u3001\u5220\u9664\u3001\u8b66\u94c3\u7b49\uff09 [:graph:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u7684\u975e\u7a7a\u767d\u5b57\u7b26 [:print:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u5b57\u7b26 [:punct:] \uff1a\u8868\u793a\u6807\u70b9\u7b26\u53f7 \u4e3e\u4f8b\uff1a ls -d [[:alpha:]] \u5373 ls -d [a-Z] \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u5355\u4e2a\u5b57\u6bcd\u7684\u76ee\u5f55\u548c\u6587\u4ef6 ls -d *[[:digit:]] \u5373 ls -d *[0-9] \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u4ee5\u6570\u5b57\u7ed3\u5c3e\u7684\u76ee\u5f55\u548c\u6587\u4ef6 ls [[:lower:]].txt \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u4ee5\u5355\u4e2a\u5c0f\u5199\u5b57\u6bcd\u4e3a\u540d\u7684.txt\u683c\u5f0f\u7684\u6587\u4ef6 ls -d [[:alnum:]] \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u5355\u4e2a\u5b57\u6bcd\uff08\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff09\u6216\u6570\u5b57\u4e3a\u540d\u7684\u76ee\u5f55\u6216\u6587\u4ef6 2.10.\u7279\u6b8a\u7b26\u53f7 \u00b6 | \uff1a\u7ba1\u9053\u7b26\uff0c\u6216\u8005\uff08\u6b63\u5219\uff09 > \uff1a\u8f93\u51fa\u91cd\u5b9a\u5411 >> \uff1a\u8f93\u51fa\u8ffd\u52a0\u91cd\u5b9a\u5411 < \uff1a\u8f93\u5165\u91cd\u5b9a\u5411 << \uff1a\u8ffd\u52a0\u8f93\u5165\u91cd\u5b9a\u5411 ~ \uff1a\u5f53\u524d\u7528\u6237\u5bb6\u76ee\u5f55 $() \uff1a\u5f15\u7528\u547d\u4ee4\u88ab\u6267\u884c\u540e\u7684\u7ed3\u679c $ \uff1a\u4ee5...\u7ed3\u5c3e\uff08\u6b63\u5219\uff09 ^ \uff1a\u4ee5...\u5f00\u5934\uff08\u6b63\u5219\uff09 * \uff1a\u5339\u914d\u5168\u90e8\u5b57\u7b26\uff0c\u901a\u914d\u7b26 ? \uff1a\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26\uff0c\u901a\u914d\u7b26 # \uff1a\u6ce8\u91ca & \uff1a\u8ba9\u7a0b\u5e8f\u6216\u811a\u672c\u5207\u6362\u5230\u540e\u53f0\u6267\u884c && \uff1a\u5e76\u4e14\uff0c\u540c\u65f6\u6210\u7acb [] \uff1a\u8868\u793a\u4e00\u4e2a\u8303\u56f4\uff08\u6b63\u5219\uff0c\u901a\u914d\u7b26\uff09 {} \uff1a\u4ea7\u751f\u4e00\u4e2a\u5e8f\u5217\uff08\u901a\u914d\u7b26\uff09 . \uff1a\u5f53\u524d\u76ee\u5f55\u7684\u786c\u94fe\u63a5 .. \uff1a\u4e0a\u7ea7\u76ee\u5f55\u7684\u786c\u94fe\u63a5 2.11.\u5237\u65b0\u6587\u4ef6\u65f6\u95f4 touch \u00b6 touch \u547d\u4ee4\u53ef\u4ee5\u521b\u5efa\u7a7a\u6587\u4ef6\uff0c\u4e5f\u53ef\u4ee5\u5237\u65b0\u6587\u4ef6\u65f6\u95f4\u3002\u53c2\u6570\u5982\u4e0b\uff1a -a \uff1a\u4ec5\u6539\u53d8 atime \u548c ctime -m \uff1a\u4ec5\u6539\u53d8 mtime \u548c ctime -t [[CC]YY]MMDDhhmm[.ss] \uff1a\u6307\u5b9a atime \u548c mtime -c \uff1a\u5982\u679c\u6587\u4ef6\u4e0d\u5b58\u5728\uff0c\u5219\u4e0d\u521b\u5efa $ touch file1 $ touch file2 $ ll -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 -rw-r--r--. 1 vagrant wheel 0 Nov 8 20 :28 file2 \u521b\u5efa\u6587\u4ef6file-non.log\uff0c\u5982\u679c\u4e0d\u5b58\u5728\u5219\u4e0d\u521b\u5efa\u3002 touch -c file-non.log \u66f4\u65b0 file1 \u7684\u65f6\u95f4\u548c file2 \u4e00\u81f4\u3002 $ touch -r file1 file2 $ ll -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 -rw-r--r--. 1 vagrant wheel 0 Nov 8 20 :49 file2 \u6307\u5b9a file2 \u7684\u65f6\u95f4\u3002 202210012135.25 \u4ee3\u8868 YYYYMMDDHHMM.SS \u3002 $ touch -t 202210012135 .25 file2 $ ll -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 -rw-r--r--. 1 vagrant wheel 0 Oct 1 21 :35 file2 $ stat file2 File: file2 Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: fd02h/64770d Inode: 140 Links: 1 Access: ( 0644 /-rw-r--r-- ) Uid: ( 1000 / vagrant ) Gid: ( 10 / wheel ) Context: unconfined_u:object_r:user_home_t:s0 Access: 2022 -10-01 21 :35:25.000000000 +0800 Modify: 2022 -10-01 21 :35:25.000000000 +0800 Change: 2022 -11-08 20 :56:18.306315887 +0800 Birth: 2022 -11-08 20 :28:37.809551441 +0800 2.12.\u590d\u5236\u6587\u4ef6\u548c\u76ee\u5f55 cp \u00b6 cp \u547d\u4ee4\uff1aCopy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY. \u5e38\u7528\u53c2\u6570\uff1a -a \uff1a\u5f52\u6863\uff0c\u76f8\u5f53\u4e8e -dR --preserv=all \u53c2\u6570\u7ec4\u5408\uff0c\u5e38\u7528\u4e8e\u5907\u4efd\u3002 -d \uff1a\u4e0d\u590d\u5236\u539f\u6587\u4ef6\uff0c\u53ea\u590d\u5236\u94fe\u63a5\u540d\u3002\u76f8\u5f53\u4e8e --no-dereference --preserve=links \u53c2\u6570\u7ec4\u5408\u3002 -f \uff1a\u8986\u76d6\u5df2\u7ecf\u5b58\u5728\u7684\u76ee\u6807\u6587\u4ef6\u3002 -i \uff1a\u8986\u76d6\u76ee\u6807\u6587\u4ef6\u4e4b\u524d\u7ed9\u51fa\u63d0\u793a\u3002 -p \uff1a\u9664\u590d\u5236\u6587\u4ef6\u7684\u5185\u5bb9\u5916\uff0c\u4e5f\u590d\u5236\u6587\u4ef6\u6743\u9650\uff0c\u65f6\u95f4\u6233\uff0c\u5c5e\u4e3b\u5c5e\u7ec4\u3002\u76f8\u5f53\u4e8e --preserve=mode,ownership,timestamps \u3002 -r, -R, --recursive \uff1a\u9012\u5f52\u590d\u5236\u76ee\u5f55\u6240\u5305\u542b\u7684\u5168\u90e8\u5185\u5bb9\u3002 -l \uff1a\u4e0d\u590d\u5236\u6587\u4ef6\uff0c\u53ea\u662f\u751f\u6210\u786c\u94fe\u63a5\u6587\u4ef6\u3002 \u53c2\u6570 --preserv \u53ef\u9009\u9879\uff1a mode\uff1a\u6743\u9650 ownership\uff1a\u5c5e\u4e3b\u5c5e\u7ec4 timestamp links xattr context all \u521b\u5efa\u6d4b\u8bd5\u76ee\u5f55\u3002 cd ~ mkdir test \u5bf9\u6bd4\u53c2\u6570 -p \u7684\u5dee\u522b\u3002 $ cp /etc/issue ~/test/issue1 $ cp -p /etc/issue ~/test/issue1 $ sudo cp /etc/issue ~/test/issue3 $ sudo cp -p /etc/issue ~/test/issue4 $ ll ~/test -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 issue1 -rw-r--r--. 1 vagrant wheel 23 Jul 21 01 :10 issue2 -rw-r--r--. 1 root root 23 Nov 8 22 :43 issue3 -rw-r--r--. 1 root root 23 Jul 21 01 :10 issue4 $ ll /etc/issue -rw-r--r--. 1 root root 23 Jul 21 01 :10 /etc/issue \u5bf9\u6bd4\u53c2\u6570 -r \u3002 $ sudo cp /etc/sysconfig/ ~/test cp: -r not specified ; omitting directory '/etc/sysconfig/' $ sudo cp -r /etc/sysconfig/ ~/test $ tree -L 2 ~/test /home/vagrant/test \u251c\u2500\u2500 issue1 \u251c\u2500\u2500 issue2 \u251c\u2500\u2500 issue3 \u251c\u2500\u2500 issue4 \u2514\u2500\u2500 sysconfig \u251c\u2500\u2500 anaconda \u251c\u2500\u2500 atd \u251c\u2500\u2500 chronyd \u251c\u2500\u2500 cpupower \u251c\u2500\u2500 crond \u251c\u2500\u2500 firewalld \u251c\u2500\u2500 irqbalance \u251c\u2500\u2500 kdump \u251c\u2500\u2500 kernel \u251c\u2500\u2500 man-db \u251c\u2500\u2500 network \u251c\u2500\u2500 network-scripts \u251c\u2500\u2500 nftables.conf \u251c\u2500\u2500 raid-check \u251c\u2500\u2500 rsyslog \u251c\u2500\u2500 run-parts \u251c\u2500\u2500 samba \u251c\u2500\u2500 selinux -> ../selinux/config \u251c\u2500\u2500 smartmontools \u2514\u2500\u2500 sshd \u53c2\u6570 -b \uff0c\u5982\u679c\u76ee\u6807\u6587\u4ef6\u5b58\u5728\uff0c\u590d\u5236\u524d\u5148\u5c06\u539f\u6587\u4ef6\u590d\u5236\u5e76\u4ee5 ~ \u7ed3\u5c3e\u3002 $ ll /etc/motd -rw-r--r--. 1 root root 0 Jun 23 2020 /etc/motd $ ll ~/test/issue1 -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 /home/vagrant/test/issue1 $ cp -b /etc/motd ~/test/issue $ cp -b /etc/motd ~/test/issue1 $ ll ~/test -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :00 issue -rw-r--r--. 1 vagrant wheel 0 Nov 8 22 :57 issue1 -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 issue1~ -rw-r--r--. 1 vagrant wheel 23 Jul 21 01 :10 issue2 -rw-r--r--. 1 root root 23 Nov 8 22 :43 issue3 -rw-r--r--. 1 root root 23 Jul 21 01 :10 issue4 drwxr-xr-x. 3 root root 4096 Nov 8 22 :49 sysconfig \u53c2\u6570 --backup=numbered \u4f1a\u5728\u590d\u5236\u539f\u6587\u4ef6\u65f6\u52a0\u4e0a\u6570\u5b57\u5e8f\u53f7\uff0c\u5e8f\u53f71\u4ee3\u8868\u539f\u59cb\u7684\u6587\u4ef6\u3002 $ cp --backup = numbered /etc/motd ~/test/issue2 $ cp --backup = numbered /etc/motd ~/test/issue2 $ cp --backup = numbered /etc/motd ~/test/issue2 $ ll ~/test -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :00 issue -rw-r--r--. 1 vagrant wheel 0 Nov 8 22 :57 issue1 -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 issue1~ -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :09 issue2 -rw-r--r--. 1 vagrant wheel 23 Jul 21 01 :10 issue2.~1~ -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :09 issue2.~2~ -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :09 issue2.~3~ -rw-r--r--. 1 root root 23 Nov 8 22 :43 issue3 -rw-r--r--. 1 root root 23 Jul 21 01 :10 issue4 drwxr-xr-x. 3 root root 4096 Nov 8 22 :49 sysconfig 2.13.\u79fb\u52a8\u6587\u4ef6\u548c\u76ee\u5f55 mv \u00b6 mv \u547d\u4ee4\u3002Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY. \u5e38\u7528\u53c2\u6570\uff1a -v \uff1a\u663e\u793a\u547d\u4ee4\u6267\u884c\u7684\u4fe1\u606f\u3002 -i \uff1a\u4ea4\u4e92\u5f0f\uff0c\u6bd4\u5982\uff0c\u91cd\u540d\u8986\u76d6\u65f6\u4f1a\u63d0\u5347\u662f\u5426\u786e\u8ba4\u3002 -b \uff1a\u8986\u76d6\u65f6\u521b\u5efa\u5907\u4efd\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u79fb\u52a8\u6587\u4ef6\u5c06\u4f1a\u8986\u76d6\u5df2\u5b58\u5728\u7684\u76ee\u6807\u6587\u4ef6\u3002 \u79fb\u52a8\u591a\u4e2a\u6587\u4ef6\u5230\u67d0\u4e2a\u76ee\u5f55\u3002 mv file1 file2 file3 ~/dest mv file* ~/dest \u79fb\u52a8\u76ee\u5f55\u3002 mv ~/test ~/dest/new/one/ \u91cd\u547d\u540d\u6587\u4ef6\u548c\u76ee\u5f55\u3002 mv file1 file2 mv ~/test ~/dest 2.14.\u91cd\u547d\u540d\u6587\u4ef6\u548c\u76ee\u5f55 rename \u00b6 rename \u547d\u4ee4\u3002\u5206\u4e3aperl\u7248\u672c\u548cC\u8bed\u8a00\u7248\u672c\u3002 \u533a\u5206\u65b9\u6cd5: rename --version \u3002\u5982\u679c\u8fd4\u56de\u7ed3\u679c\u4e2d\u5305\u542b util-linux \uff0c\u8bf4\u660e\u662fC\u8bed\u8a00\u7248\u672c, \u53cd\u4e4b\u662fPerl\u7248\u672c\u3002 openSUSE\u548cRocy\u662fC\u8bed\u8a00\u7248\u672c\uff0cUbuntu\u662fPerl\u7248\u672c\u3002 \u4e3e\u4f8b\uff1a\u4fee\u6539\u5f53\u524d\u76ee\u5f55\u6240\u6709\u6269\u5c55\u540d\u4e3a s \u7684\u6587\u4ef6\u6539\u4e3a\u6269\u5c55\u540d\u4e3a gz \u3002 $ touch file { 1 ..3 } .s $ rename -v '.s' '.gz' *.s $ rename -v \".s\" \".gz\" *.s ` file1.txt ' -> `file1.html' ` file2.txt ' -> `file2.html' ` file3.txt ' -> `file3.html' \u5728Ubuntu\u4e0a\u5b8c\u6210\u540c\u6837\u4efb\u52a1\uff0c\u5219\u9700\u8981\u4f7f\u7528\u6b63\u5219\u3002 rename -v \"s/s/gz/g\" *.s 2.15.\u5220\u9664\u6587\u4ef6 rm \u00b6 rm \u547d\u4ee4\u3002\u5efa\u8bae\u4f7f\u7528 mv \u547d\u4ee4\u4ee3\u66ff rm \u547d\u4ee4\u3002 2.16.\u76ee\u5f55\u64cd\u4f5c\u547d\u4ee4 \u00b6 \u521b\u5efa\u76ee\u5f55\uff1a mkdir \u5220\u9664\u7a7a\u76ee\u5f55\uff1a rmdir \u5220\u9664\u975e\u7a7a\u76ee\u5f55\uff1a rm -r \u663e\u793a\u76ee\u5f55\u6811\uff1a tree 2.17.\u7ec3\u4e60 \u00b6 \u663e\u793a /etc \u76ee\u5f55\u4e0b\u6240\u6709\u4ee5 l \u5f00\u5934\uff0c\u4ee5\u4e00\u4e2a\u5c0f\u5199\u5b57\u6bcd\u7ed3\u5c3e\uff0c\u4e14\u4e2d\u95f4\u51fa\u73b0\u81f3\u5c11\u4e00\u4f4d\u6570\u5b57\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls -d /etc/l* [ 0 -9 ] * [ a-z ] ls -d /etc/l* [[ :digit: ]] * [[ :lower: ]] \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/lam4you sudo mkdir /etc/lam5you \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/lam4you sudo rm -rf /etc/lam5you \u663e\u793a /etc \u76ee\u5f55\u4e0b\u4ee5\u4efb\u610f\u4e00\u4f4d\u6570\u5b57\u5f00\u5934\uff0c\u4e14\u4ee5\u975e\u6570\u5b57\u7ed3\u5c3e\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ 0 -9 ] * [ !0-9 ] ls /etc/ [[ :digit: ]] * [ ^ [ :digit: ]] \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/5am4yo. sudo mkdir /etc/5am5yo. \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/5am4yo. sudo rm -rf /etc/5am5yo. \u663e\u793a /etc \u76ee\u5f55\u4e0b\u4ee5\u975e\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u9762\u8ddf\u4e86\u4e00\u4e2a\u5b57\u6bcd\u53ca\u5176\u5b83\u4efb\u610f\u957f\u5ea6\u4efb\u610f\u5b57\u7b26\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ !a-zA-Z ][ a-zA-Z ] * ls /etc/ [ ^ [ :alpha: ]][[ :alpha: ]] * \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/5Ato3 sudo mkdir /etc/6dog6 \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/5Ato3 sudo rm -rf /etc/6dog6 \u663e\u793a /etc \u76ee\u5f55\u4e0b\uff0c\u6240\u6709\u4ee5 rc \u5f00\u5934\uff0c\u5e76\u540e\u9762\u662f0-6\u4e4b\u95f4\u7684\u6570\u5b57\uff0c\u5176\u5b83\u4e3a\u4efb\u610f\u5b57\u7b26\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/rc [ 0 -6 ] * \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/rc5come sudo mkdir /etc/rc0123 \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/rc5come sudo rm -rf /etc/rc0123 \u663e\u793a /etc \u76ee\u5f55\u4e0b\uff0c\u6240\u6709\u4ee5 .conf \u7ed3\u5c3e\uff0c\u4e14\u4ee5 m \u3001 n \u3001 r \u3001 p \u5f00\u5934\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ mnrp ] *.conf \u53ea\u663e\u793a /root \u4e0b\u7684\u9690\u85cf\u6587\u4ef6\u548c\u76ee\u5f55\u5217\u8868\u3002 ls .* \u53ea\u663e\u793a/etc\u4e0b\u975e\u9690\u85cf\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ ^. ] */ \u5c06 /etc \u76ee\u5f55\u4e0b\u6240\u6709\u6587\u4ef6\uff0c\u5907\u4efd\u5230 ~/test/ \u76ee\u5f55\u4e0b\uff0c\u5e76\u8981\u6c42\u5b50\u76ee\u5f55\u683c\u5f0f\u4e3a backupYYYY-mm-dd \uff0c\u5907\u4efd\u8fc7\u7a0b\u53ef\u89c1\u3002 sudo cp -av /etc/ ~/test/backup ` date +%F ` sudo cp -av /etc/ ~/test/backup ` date +%F_%H-%M-%S ` \u521b\u5efa\u76ee\u5f55 ~/testdir/dir1/x \uff0c ~/testdir/dir1/y \uff0c ~/testdir/dir1/x/a \uff0c ~/testdir/dir1/x/b \uff0c ~/testdir/dir1/y/a \uff0c ~/testdir/dir1/y/b \u3002 $ mkdir -p ~/testdir/dir1/ { x,y } / { a,b } $ tree ~/testdir/dir1/ /home/vagrant/testdir/dir1/ \u251c\u2500\u2500 x \u2502 \u251c\u2500\u2500 a \u2502 \u2514\u2500\u2500 b \u2514\u2500\u2500 y \u251c\u2500\u2500 a \u2514\u2500\u2500 b \u521b\u5efa\u76ee\u5f55 ~/testdir/dir2/x \uff0c ~/testdir/dir2/y \uff0c ~/testdir/dir2/x/a \uff0c ~/testdir/dir2/x/b \u3002 $ mkdir -p ~/testdir/dir2/ { x/ { a,b } ,y } $ tree ~/testdir/dir2/ /home/vagrant/testdir/dir2/ \u251c\u2500\u2500 x \u2502 \u251c\u2500\u2500 a \u2502 \u2514\u2500\u2500 b \u2514\u2500\u2500 y \u521b\u5efa\u76ee\u5f55 ~/testdir/dir3 \u3001 ~/testdir/dir4 \u3001 ~/testdir/dir5 \u3001 ~/testdir/dir5/dir6 \u3001 ~/testdir/dir5/dir7 \u3002 $ mkdir -p ~/testdir/dir { 3 ,4,5/dir { 6 ,7 }} $ tree ~/testdir /home/vagrant/testdir \u251c\u2500\u2500 dir1 \u2502 \u251c\u2500\u2500 x \u2502 \u2502 \u251c\u2500\u2500 a \u2502 \u2502 \u2514\u2500\u2500 b \u2502 \u2514\u2500\u2500 y \u2502 \u251c\u2500\u2500 a \u2502 \u2514\u2500\u2500 b \u251c\u2500\u2500 dir2 \u2502 \u251c\u2500\u2500 x \u2502 \u2502 \u251c\u2500\u2500 a \u2502 \u2502 \u2514\u2500\u2500 b \u2502 \u2514\u2500\u2500 y \u251c\u2500\u2500 dir3 \u251c\u2500\u2500 dir4 \u2514\u2500\u2500 dir5 \u251c\u2500\u2500 dir6 \u2514\u2500\u2500 dir7 3.\u4e03\u79cd\u6587\u4ef6\u7c7b\u578b \u00b6 \u666e\u901a\u6587\u4ef6\uff08Normal Files\uff09 ASCII \u6587\u672c\u6587\u4ef6 \u53ef\u6267\u884c\u6587\u4ef6 \u56fe\u5f62\u6587\u4ef6 \u76ee\u5f55\uff08Directories\uff09 \u7ec4\u7ec7\u89c4\u5212\u78c1\u76d8\u4e0a\u7684\u6587\u4ef6 \u5305\u542b\u6587\u4ef6\u548c\u5b50\u76ee\u5f55 \u5b9e\u73b0\u5206\u5c42\u6587\u4ef6\u7cfb\u7edf \u94fe\u63a5\uff08Links\uff09 \u786c\u94fe\u63a5\uff08Hard links\uff09 \u78c1\u76d8\u4e0a\u6587\u4ef6\u7684\u8f85\u52a9\u6587\u4ef6\u540d \u591a\u4e2a\u6587\u4ef6\u540d\u5f15\u7528\u5355\u4e2a inode \u5f15\u7528\u7684\u6587\u4ef6\u5fc5\u987b\u5b58\u5728\u4e8e\u540c\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u4e2d \u7b26\u53f7\u94fe\u63a5\uff08Symbolic links\uff09 \u5bf9\u78c1\u76d8\u4e0a\u5176\u4ed6\u6587\u4ef6\u7684\u5f15\u7528 inode \u5305\u542b\u5bf9\u53e6\u4e00\u4e2a\u6587\u4ef6\u540d\u7684\u5f15\u7528 \u88ab\u5f15\u7528\u7684\u6587\u4ef6\u53ef\u4ee5\u5b58\u5728\u4e8e\u540c\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u4e2d\uff0c\u4e5f\u53ef\u4ee5\u5b58\u5728\u4e8e\u5176\u4ed6\u6587\u4ef6\u7cfb\u7edf\u4e2d \u7b26\u53f7\u94fe\u63a5\u53ef\u4ee5\u5f15\u7528\u4e0d\u5b58\u5728\u7684\u6587\u4ef6\uff08\u65ad\u5f00\u7684\u94fe\u63a5\uff09 \u5957\u63a5\u5b57Sockets - \u7528\u4e8e\u8fdb\u7a0b\u4e4b\u95f4\u7684\u53cc\u5411\u901a\u4fe1\u3002 \u7ba1\u9053\uff08Pipes\uff09(FIFOs) - \u7528\u4e8e\u4ece\u4e00\u4e2a\u8fdb\u7a0b\u5230\u53e6\u4e00\u4e2a\u8fdb\u7a0b\u7684\u5355\u5411\u901a\u4fe1\u3002 \u5757\u8bbe\u5907\uff08Block Devices\uff09 \u5b57\u7b26\u8bbe\u5907\uff08Character Devices\uff09 3.1.inode\u7ed3\u6784 \u00b6 \u6587\u4ef6\u50a8\u5b58\u5728\u786c\u76d8\u4e0a\uff0c\u786c\u76d8\u7684\u6700\u5c0f\u5b58\u50a8\u5355\u4f4d\u53eb\u505a\u201c\u6247\u533a\u201d\uff08Sector\uff09\u3002\u6bcf\u4e2a\u6247\u533a\u50a8\u5b58512\u5b57\u8282\uff08\u76f8\u5f53\u4e8e0.5KB\uff09\u3002 \u64cd\u4f5c\u7cfb\u7edf\u8bfb\u53d6\u786c\u76d8\u7684\u65f6\u5019\uff0c\u4e0d\u662f\u4e00\u4e2a\u4e00\u4e2a\u6247\u533a\u8bfb\u53d6\uff0c\u800c\u662f\u4e00\u6b21\u6027\u8fde\u7eed\u8bfb\u53d6\u591a\u4e2a\u6247\u533a\uff0c\u6211\u4eec\u79f0\u4e3a\u8bfb\u53d6\u4e00\u4e2a\u201c\u5757\u201d\uff08block\uff09\u3002 \u5e38\u89c1\u7684block\u7684\u5927\u5c0f\u662f4KB\uff08\u8fde\u7eed\u516b\u4e2asector\u7ec4\u6210\u4e00\u4e2ablock\uff09\u3002 \u591a\u4e2a\u6247\u533a\u7ec4\u6210\u7684block\u662f\u6587\u4ef6\u5b58\u53d6\u7684*\u6700\u5c0f\u5355\u4f4d*\u3002 \u6587\u4ef6\u6570\u636e\u50a8\u5b58\u5728block\u4e2d\uff0c\u6587\u4ef6\u7684\u5143\u4fe1\u606f\uff0c\u6bd4\u5982\u6587\u4ef6\u7684\u521b\u5efa\u8005\u3001\u521b\u5efa\u65e5\u671f\u3001\u6587\u5927\u5c0f\u7b49\uff0c\u5b58\u50a8\u5728inode\uff0c\u5373\u201c\u7d22\u5f15\u8282\u70b9\u201d\u3002 \u6bcf\u4e00\u4e2a\u6587\u4ef6\u90fd\u6709\u5bf9\u5e94\u7684inode\uff0c\u91cc\u9762\u5305\u542b\u4e86\u4e0e\u8be5\u6587\u4ef6\u6709\u5173\u7684\u4e00\u4e9b\u4fe1\u606f\u3002\u6ce8\u610f\uff0c\u9664\u4e86\u6587\u4ef6\u540d\u4ee5\u5916\u7684\u5176\u5b83\u6587\u4ef6\u4fe1\u606f\uff0c\u90fd\u5b58\u5728inode\u4e4b\u4e2d\u3002 inode\u5305\u542b\u6587\u4ef6\u7684\u5143\u4fe1\u606f\u4e3b\u8981\u6709\uff1a \u6587\u4ef6\u7684\u5b57\u8282\u6570 \u6587\u4ef6\u62e5\u6709\u8005\u7684 User ID \u6587\u4ef6\u7684 Group ID \u6587\u4ef6\u7684\u8bfb\u3001\u5199\u3001\u6267\u884c\u6743\u9650 \u6587\u4ef6\u7684\u65f6\u95f4\u6233\uff0c\u5171\u6709\u4e09\u4e2a\uff1actime\u6307inode\u4e0a\u4e00\u6b21\u53d8\u52a8\u7684\u65f6\u95f4\uff0cmtime\u6307\u6587\u4ef6\u5185\u5bb9\u4e0a\u4e00\u6b21\u53d8\u52a8\u7684\u65f6\u95f4\uff0catime\u6307\u6587\u4ef6\u4e0a\u4e00\u6b21\u6253\u5f00\u7684\u65f6\u95f4\u3002 \u94fe\u63a5\u6570\uff0c\u5373\u6709\u591a\u5c11\u6587\u4ef6\u540d\u6307\u5411\u8fd9\u4e2ainode \u6587\u4ef6\u6570\u636eblock\u7684\u4f4d\u7f6e \u67e5\u770binode\u4fe1\u606f\u7684\u547d\u4ee4 stat \uff1a $ stat file1 File: file1 Size: 5 Blocks: 8 IO Block: 4096 regular file Device: fd02h/64770d Inode: 143 Links: 1 Access: ( 0644 /-rw-r--r-- ) Uid: ( 1000 / vagrant ) Gid: ( 10 / wheel ) Context: unconfined_u:object_r:user_home_t:s0 Access: 2022 -11-08 20 :49:26.019678244 +0800 Modify: 2022 -11-08 20 :49:26.019678244 +0800 Change: 2022 -11-08 20 :49:26.028678455 +0800 Birth: 2022 -11-08 20 :49:26.019678244 +0800 \u683c\u5f0f\u5316\u786c\u76d8\u65f6\uff0c\u64cd\u4f5c\u7cfb\u7edf\u4f1a\u81ea\u52a8\u5c06\u786c\u76d8\u5206\u6210\u4e24\u4e2a\u533a\u57df\u3002\u4e00\u4e2a\u662f\u6570\u636e\u533a\uff0c\u5b58\u653e\u6587\u4ef6\u6570\u636e\u3002\u53e6\u4e00\u4e2a\u662finode\u533a\uff08inode table\uff09\uff0c\u5b58\u653einode\u6240\u5305\u542b\u7684\u6587\u4ef6\u7684\u5143\u4fe1\u606f\u3002 \u6bcf\u4e2ainode\u8282\u70b9\u7684\u5927\u5c0f\uff0c\u4e00\u822c\u662f128\u5b57\u8282\u6216256\u5b57\u8282\u3002inode\u8282\u70b9\u7684\u603b\u6570\uff0c\u5728\u683c\u5f0f\u5316\u65f6\u5c31\u786e\u5b9a\u4e86\uff0c\u4e00\u822c\u662f\u6bcf1KB\u6216\u6bcf2KB\u5c31\u8bbe\u7f6e\u4e00\u4e2ainode\u3002 \u5047\u5b9a\u4e00\u57571GB\u7684\u786c\u76d8\uff0c\u5982\u679c\u6bcf\u4e2ainode\u8282\u70b9\u7684\u5927\u5c0f\u4e3a128\u5b57\u8282\uff0c\u4e14\u6bcf1KB\u5c31\u8bbe\u7f6e\u4e00\u4e2ainode\uff0c\u5219inode table\u7684\u5927\u5c0f\u5c31\u4f1a\u8fbe\u5230128MB\uff0c\u5360\u6574\u5757\u786c\u76d8\u768412.8%\u3002 \u901a\u8fc7 df \u547d\u4ee4\u67e5\u770b\u6bcf\u4e2a\u786c\u76d8\u5206\u533a\u7684inode\u603b\u6570\u548c\u5df2\u7ecf\u4f7f\u7528\u7684\u6570\u91cf\u3002 \u7531\u4e8e\u6bcf\u4e2a\u6587\u4ef6\u90fd\u5fc5\u987b\u6709\u4e00\u4e2ainode\uff0c\u56e0\u6b64\u6709\u53ef\u80fd\u53d1\u751finode\u5df2\u7ecf\u7528\u5149\uff0c\u4f46\u662f\u786c\u76d8\u8fd8\u672a\u5b58\u6ee1\u7684\u60c5\u51b5\uff0c\u4e5f\u5c31\u65e0\u6cd5\u5728\u786c\u76d8\u4e0a\u521b\u5efa\u65b0\u6587\u4ef6\u3002 $ df -i Filesystem Inodes IUsed IFree IUse% Mounted on tmpfs 497897 872 497025 1 % /run /dev/mapper/ubuntu--vg-ubuntu--lv 3211264 81473 3129791 3 % / tmpfs 497897 1 497896 1 % /dev/shm tmpfs 497897 3 497894 1 % /run/lock /dev/sda2 131072 316 130756 1 % /boot tmpfs 99579 25 99554 1 % /run/user/1000 \u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u67e5\u770b\u6bcf\u4e2ainode\u8282\u70b9\u7684\u5927\u5c0f\uff1a $ sudo dumpe2fs -h /dev/sda2 | grep \"Inode size\" dumpe2fs 1 .46.5 ( 30 -Dec-2021 ) Inode size: 256 \u6bcf\u4e2ainode\u90fd\u6709\u4e00\u4e2a\u53f7\u7801\uff0c\u64cd\u4f5c\u7cfb\u7edf\u7528inode\u53f7\u7801\u6765\u8bc6\u522b\u4e0d\u540c\u7684\u6587\u4ef6\uff0c\u6ce8\u610f\uff0c\u4e0d\u662f\u901a\u8fc7\u6587\u4ef6\u540d\u6765\u8bc6\u522b\u4e0d\u540c\u6587\u4ef6\u3002\u4ece\u64cd\u4f5c\u7cfb\u7edf\u89d2\u5ea6\u770b\uff0c\u6587\u4ef6\u540d\u53ea\u662finode\u53f7\u7801\u5bf9\u4e00\u4e2a\u522b\u540d\u3002 \u7528\u6237\u901a\u8fc7\u6587\u4ef6\u540d\uff0c\u6253\u5f00\u67d0\u4e2a\u6587\u4ef6\u7684\u8fc7\u7a0b\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5206\u6210\u4e09\u6b65\u5b8c\u6210\uff1a \u9996\u5148\uff0c\u7cfb\u7edf\u627e\u5230\u8fd9\u4e2a\u6587\u4ef6\u540d\u5bf9\u5e94\u7684inode\u53f7\u7801\u3002 \u5176\u6b21\uff0c\u901a\u8fc7inode\u53f7\uff0c\u83b7\u53d6inode\u4fe1\u606f\u3002 \u7b2c\u4e09\uff0c\u901a\u8fc7inode\u4fe1\u606f\uff0c\u627e\u5230\u6587\u4ef6\u6570\u636e\u6240\u5728\u7684block\uff0c\u8bfb\u51fa\u6570\u636e\u3002 \u901a\u8fc7 ls -i \u547d\u4ee4\uff0c\u53ef\u4ee5\u5f97\u5230\u6587\u4ef6\u5bf9\u5e94\u7684inode\u53f7\uff1a $ ls -i file1 143 file1 \u76ee\u5f55\uff08directory\uff09\u4e5f\u662f\u4e00\u79cd\u6587\u4ef6\u3002\u6253\u5f00\u76ee\u5f55\uff0c\u5b9e\u9645\u4e0a\u5c31\u662f\u6253\u5f00\u76ee\u5f55\u6587\u4ef6\u3002 \u76ee\u5f55\u6587\u4ef6\u7684\u7ed3\u6784\u662f\u7531\u4e00\u4e2a\u5305\u542b\u4e00\u7cfb\u5217\u76ee\u5f55\u9879\uff08dirent\uff09\u7684\u5217\u8868\u7ec4\u6210\u3002 \u6bcf\u4e2a\u76ee\u5f55\u9879\u7531\u4e24\u90e8\u5206\u7ec4\u6210\uff1a\u6240\u5305\u542b\u6587\u4ef6\u7684\u6587\u4ef6\u540d\uff0c\u4ee5\u53ca\u8be5\u6587\u4ef6\u540d\u5bf9\u5e94\u7684inode\u53f7\u3002 \u547d\u4ee4 ls -i \u5217\u51fa\u6574\u4e2a\u76ee\u5f55\u6587\u4ef6\uff0c\u5373\u6587\u4ef6\u540d\u548cinode\u53f7\uff1a $ ls -i 143 file1 140 file2 139 test $ ls -il 143 -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 140 -rw-r--r--. 1 vagrant wheel 0 Oct 1 21 :35 file2 139 drwxr-xr-x. 5 vagrant wheel 4096 Nov 9 22 :00 test 3.2.\u94fe\u63a5\u7c7b\u578b \u00b6 \u786c\u94fe\u63a5 \uff08Hard links\uff09\u786c\u94fe\u63a5\u662f\u5b58\u50a8\u5377\u4e0a\u6587\u4ef6\u7684\u76ee\u5f55\u5f15\u7528\u6216\u6307\u9488\u3002 \u6587\u4ef6\u540d\u662f\u5b58\u50a8\u5728\u76ee\u5f55\u7ed3\u6784\u4e2d\u7684\u6807\u7b7e\uff0c\u76ee\u5f55\u7ed3\u6784\u6307\u5411\u6587\u4ef6\u6570\u636e\u3002 \u56e0\u6b64\uff0c\u53ef\u4ee5\u5c06\u591a\u4e2a\u6587\u4ef6\u540d\u4e0e\u540c\u4e00\u6587\u4ef6\u5173\u8054\u3002 \u901a\u8fc7\u4e0d\u540c\u7684\u6587\u4ef6\u540d\u8bbf\u95ee\u65f6\uff0c\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u662f\u9488\u5bf9\u6e90\u6587\u4ef6\u6570\u636e\u3002 \u7b26\u53f7\u94fe\u63a5 \uff08Symbolic links\uff09: \u7b26\u53f7\u94fe\u63a5\u5305\u542b\u4e00\u4e2a\u6587\u672c\u5b57\u7b26\u4e32\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5c06\u5176\u89e3\u91ca\u4e3a\u53e6\u4e00\u4e2a\u6587\u4ef6\u6216\u76ee\u5f55\u3002 \u5b83\u672c\u8eab\u5c31\u662f\u4e00\u4e2a\u6587\u4ef6\uff0c\u53ef\u4ee5\u72ec\u7acb\u4e8e\u76ee\u6807\u800c\u5b58\u5728\u3002 \u5982\u679c\u5220\u9664\u4e86\u7b26\u53f7\u94fe\u63a5\uff0c\u5219\u5176\u76ee\u6807\u6587\u4ef6\u6216\u76ee\u5f55\u4e0d\u53d7\u5f71\u54cd\u3002 \u5982\u679c\u79fb\u52a8\uff0c\u91cd\u547d\u540d\u6216\u5220\u9664\u76ee\u6807\u6587\u4ef6\u6216\u76ee\u5f55\uff0c\u5219\u7528\u4e8e\u6307\u5411\u5b83\u7684\u4efb\u4f55\u7b26\u53f7\u94fe\u63a5\u5c06\u7ee7\u7eed\u5b58\u5728\uff0c\u4f46\u6307\u5411\u7684\u662f\u4e00\u4e2a\u4e0d\u5b58\u5728\u7684\u6587\u4ef6\u3002 \u4ec5\u5f53\u6587\u4ef6\u548c\u94fe\u63a5\u6587\u4ef6\u4f4d\u4e8e\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\uff08\u5728\u540c\u4e00\u5206\u533a\u4e0a\uff09\u65f6\uff0c\u624d\u80fd\u4f7f\u7528\u786c\u94fe\u63a5\uff0c\u56e0\u4e3ainode\u7f16\u53f7\u5728\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\u4e2d\u4ec5\u662f\u552f\u4e00\u7684\u3002 \u53ef\u4ee5\u4f7f\u7528 ln \u547d\u4ee4\u521b\u5efa\u786c\u94fe\u63a5\uff0c\u6307\u5411\u5df2\u5b58\u5728\u6587\u4ef6\u7684inode\uff0c\u53ef\u4ee5\u901a\u8fc7\u6587\u4ef6\u540d\u6216\u8005\u786c\u94fe\u63a5\u540d\u8bbf\u95ee\u6587\u4ef6\u3002 \u53ef\u4ee5\u4f7f\u7528 ln -s \u9009\u9879\u521b\u5efa\u7b26\u53f7\u94fe\u63a5\u3002 \u4e00\u4e2a\u7b26\u53f7\u94fe\u63a5\u4f1a\u88ab\u5206\u914d\u4e00\u4e2a\u5355\u72ec\u7684inode\uff0c\u5e76\u6307\u5411\u4e00\u4e2a\u6587\u4ef6\uff0c\u6240\u4ee5\u53ef\u4ee5\u660e\u663e\u533a\u5206\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\u548c\u5b9e\u9645\u6587\u4ef6\u3002 \u6587\u4ef6\u7cfb\u7edf\u672c\u8d28\u4e0a\u662f\u4e00\u4e2a\u7528\u4e8e\u8ddf\u8e2a\u5206\u533a\u5377\u4e2d\u7684\u6587\u4ef6\u7684\u6570\u636e\u5e93\u3002 \u5bf9\u4e8e\u666e\u901a\u6587\u4ef6\uff0c\u5206\u914d\u6570\u636e\u5757\u4ee5\u5b58\u50a8\u6587\u4ef6\u7684\u6570\u636e\uff0c\u5206\u914dinode\u4ee5\u6307\u5411\u6570\u636e\u5757\u4ee5\u53ca\u5b58\u50a8\u5173\u4e8e\u6587\u4ef6\u7684\u5143\u6570\u636e\uff0c\u7136\u540e\u5c06\u6587\u4ef6\u540d\u5206\u914d\u7ed9inode\u3002 \u786c\u94fe\u63a5\u662f\u4e0e\u73b0\u6709inode\u5173\u8054\u7684\u8f85\u52a9\u6587\u4ef6\u540d\u3002 \u5bf9\u4e8e\u7b26\u53f7\u94fe\u63a5\uff0c\u5c06\u4e3a\u65b0\u7684inode\u5206\u914d\u4e00\u4e2a\u4e0e\u4e4b\u5173\u8054\u7684\u65b0\u6587\u4ef6\u540d\uff0c\u4f46inode\u5f15\u7528\u53e6\u4e00\u4e2a\u6587\u4ef6\u540d\u800c\u4e0d\u662f\u5f15\u7528\u6570\u636e\u5757\u3002 \u67e5\u770b\u6587\u4ef6\u540d\u548cinode\u4e4b\u95f4\u5173\u7cfb\u7684\u4e00\u4e2a\u65b9\u6cd5\u662f\u4f7f\u7528 ls -il \u547d\u4ee4\u3002inode\u7684\u5178\u578b\u5927\u5c0f\u4e3a128\u4f4d\uff0c\u6570\u636e\u5757\u7684\u5927\u5c0f\u8303\u56f4\u53ef\u4ee5\u662f1k\uff0c2k\uff0c4k\u6216\u66f4\u5927\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u3002 \u8f6f\u8fde\u63a5\u53ef\u4ee5\u9488\u5bf9\u76ee\u5f55\uff0c\u786c\u8fde\u63a5\u53ea\u80fd\u9488\u5bf9\u6587\u4ef6\u3002 \u786c\u94fe\u63a5\u76f8\u5f53\u4e8e\u589e\u52a0\u4e86\u4e00\u4e2a\u767b\u8bb0\u9879\uff0c\u4f7f\u5f97\u539f\u6765\u7684\u6587\u4ef6\u591a\u4e86\u4e00\u4e2a\u540d\u5b57\uff0c\u81f3\u4e8einode\u90fd\u6ca1\u53d8\u3002\u6240\u8c13\u7684\u767b\u8bb0\u9879\u5176\u5b9e\u662f\u76ee\u5f55\u6587\u4ef6\u4e2d\u7684\u4e00\u4e2a\u6761\u76ee(\u76ee\u5f55\u9879)\uff0c\u4f7f\u7528hard link \u662f\u8ba9\u591a\u4e2a\u4e0d\u540c\u7684\u76ee\u5f55\u9879\u6307\u5411\u540c\u4e00\u4e2a\u6587\u4ef6\u7684inode\uff0c\u6ca1\u6709\u591a\u4f59\u7684\u5185\u5bb9\u9700\u8981\u5b58\u50a8\u5728\u78c1\u76d8\u6247\u533a\u4e2d\uff0c\u6240\u4ee5hardlink\u4e0d\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 \u7b26\u53f7\u94fe\u63a5\u6709\u5355\u72ec\u7684inode\uff0c\u5728inode\u4e2d\u5b58\u653e\u53e6\u4e00\u4e2a\u6587\u4ef6\u7684\u8def\u5f84\u800c\u4e0d\u662f\u6587\u4ef6\u6570\u636e\uff0c\u6240\u4ee5\u7b26\u53f7\u94fe\u63a5\u4f1a\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 \u7279\u5f81 \u786c\u94fe\u63a5 \u7b26\u53f7\u94fe\u63a5 \u672c\u8d28 \u540c\u4e00\u4e2a\u6587\u4ef6 \u4e0d\u662f\u540c\u4e00\u4e2a\u6587\u4ef6 \u8de8\u8bbe\u5907 \u4e0d\u652f\u6301 \u652f\u6301 inode \u76f8\u540c \u4e0d\u540c \u94fe\u63a5\u6570 \u521b\u5efa\u786c\u94fe\u63a5\uff0c\u94fe\u63a5\u6570\u4f1a\u589e\u52a0\uff0c\u5220\u9664\u5219\u51cf\u5c11 \u521b\u5efa\u6216\u5220\u9664\uff0c\u94fe\u63a5\u6570\u90fd\u4e0d\u53d8 \u6587\u4ef6\u5939 \u4e0d\u652f\u6301 \u652f\u6301 \u76f8\u5bf9\u8def\u5f84 \u539f\u59cb\u6587\u4ef6\u7684\u76f8\u5bf9\u8def\u5f84\u662f\u76f8\u5bf9\u4e8e\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55 \u539f\u59cb\u6587\u4ef6\u7684\u76f8\u5bf9\u8def\u5f84\u662f\u76f8\u5bf9\u4e8e\u94fe\u63a5\u6587\u4ef6\u7684\u76f8\u5bf9\u8def\u5f84 \u5220\u9664\u6e90\u6587\u4ef6 \u53ea\u662f\u94fe\u63a5\u6570\u51cf\u5c11\uff0c\u94fe\u63a5\u6587\u4ef6\u8bbf\u95ee\u4e0d\u53d7\u5f71\u54cd \u94fe\u63a5\u6587\u4ef6\u5c06\u65e0\u6cd5\u8bbf\u95ee \u6587\u4ef6\u7c7b\u578b \u548c\u6e90\u6587\u4ef6\u76f8\u540c \u94fe\u63a5\u6587\u4ef6\uff0c\u548c\u6e90\u6587\u4ef6\u65e0\u5173 \u6587\u4ef6\u5927\u5c0f \u548c\u6e90\u6587\u4ef6\u76f8\u540c \u6e90\u6587\u4ef6\u7684\u8def\u5f84\u7684\u957f\u5ea6 3.3.\u8bbe\u5907\u6587\u4ef6 \u00b6 \u8bbe\u5907\u6587\u4ef6 \uff08Device File\uff09\u8868\u793a\u786c\u4ef6\uff08\u7f51\u5361\u9664\u5916\uff09\u3002 \u6bcf\u4e2a\u786c\u4ef6\u90fd\u7531\u4e00\u4e2a\u8bbe\u5907\u6587\u4ef6\u8868\u793a\u3002 \u7f51\u5361\u662f\u63a5\u53e3\u3002 \u8bbe\u5907\u6587\u4ef6\u628a\u5185\u6838\u9a71\u52a8\u548c\u7269\u7406\u786c\u4ef6\u8bbe\u5907\u8fde\u63a5\u8d77\u6765\u3002 \u5185\u6838\u9a71\u52a8\u7a0b\u5e8f\u901a\u8fc7\u5bf9\u8bbe\u5907\u6587\u4ef6\u8fdb\u884c\u8bfb\u5199\uff08\u6b63\u786e\u7684\u683c\u5f0f\uff09\u6765\u5b9e\u73b0\u5bf9\u786c\u4ef6\u7684\u8bfb\u5199\u3002 \u7c7b\u578b\uff1a \u5757\u8bbe\u5907\uff08Block Devices\uff09\uff1a\u5757\u8bbe\u5907\uff08\u901a\u5e38\uff09\u5728512\u5b57\u8282\u7684\u5927\u5757\u4e2d\u8bfb\u53d6/\u5199\u5165\u4fe1\u606f\u3002 \u5b57\u7b26\u8bbe\u5907\uff08Character Devices\uff09\uff1a\u5b57\u7b26\u8bbe\u5907\u4ee5\u5b57\u7b26\u65b9\u5f0f\u8bfb\u53d6/\u5199\u5165\u4fe1\u606f\u3002 \u5b57\u7b26\u8bbe\u5907\u76f4\u63a5\u63d0\u4f9b\u5bf9\u786c\u4ef6\u8bbe\u5907\u7684\u65e0\u7f13\u51b2\u8bbf\u95ee\u3002 \u6709\u65f6\u79f0\u4e3a\u88f8\u8bbe\u5907\uff08raw devices\uff09\u3002\uff08\u6ce8\u610f\uff1a\u88f8\u8bbe\u5907\u88ab\u89c6\u4e3a\u5b57\u7b26\u8bbe\u5907\uff0c\u4e0d\u662f\u5757\u8bbe\u5907\uff09 \u901a\u8fc7\u8f85\u4ee5\u4e0d\u540c\u9009\u9879\uff0c\u53ef\u4ee5\u5e7f\u6cdb\u800c\u591a\u6837\u5730\u5e94\u7528\u548c\u4f7f\u7528\u5b57\u7b26\u8bbe\u5907\u3002 \u5f53\u5185\u6838\u53d1\u73b0\u8bbe\u5907\u65f6\u7531\u64cd\u4f5c\u7cfb\u7edf udev \u81ea\u52a8\u521b\u5efa\u3002 3.4.\u7ec3\u4e60 \u00b6 \u76ee\u6807\uff1a\u4ee5Rocky 9\u4e3a\u4f8b\u3002 \u67e5\u770b\u8f6f/\u786c\u94fe\u63a5\u6587\u4ef6\u7684\u7279\u5f81\u3002 \u67e5\u770b\u76ee\u5f55\u7ed3\u6784\u3002 \u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u5f97\u5230\u5f53\u524d\u7cfb\u7edf\u76842\u7ea7\u76ee\u5f55\u7684\u7ed3\u6784\u3002 tree -L 2 -d / \u521b\u5efa\u7ec3\u4e60\u76ee\u5f55\u3002 mkdir data mkdir -p data/typelink cd data \u521b\u5efa\u786c\u94fe\u63a5\u3002\u6ce8\u610f\uff1a file \u3001 hardlinkfile1 \u3001 hardlinkfile2 \u6587\u4ef6\u7684\u94fe\u63a5\u4f4d\u7f6e\u7684\u6570\u503c\u7684\u53d8\u5316) echo \"it's original file\" > file ln file hardlinkfile1 ln -s file symlinkfile1 ln -s file symlinkfile2 \u6267\u884c ls -l \u547d\u4ee4\u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u7ed3\u679c\uff1a -rw-r--r--. 2 vagrant wheel 19 Nov 1 10 :42 file -rw-r--r--. 2 vagrant wheel 19 Nov 1 10 :42 hardlinkfile1 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file \u521b\u5efa\u53e6\u5916\u4e00\u4e2a\u786c\u94fe\u63a5\u3002 ln file hardlinkfile2 \u6267\u884c ls -l \u547d\u4ee4\u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u7ed3\u679c\uff1a -rw-r--r--. 3 vagrant wheel 19 Nov 1 10 :42 file -rw-r--r--. 3 vagrant wheel 19 Nov 1 10 :42 hardlinkfile1 -rw-r--r--. 3 vagrant wheel 19 Nov 1 10 :42 hardlinkfile2 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file \u4fee\u6539 file \u6587\u4ef6\u7684\u5185\u5bb9\u3002 echo \"add oneline\" >> file \u901a\u8fc7\u547d\u4ee4 cat file \u67e5\u770b\u5f53\u524d file \u7684\u5185\u5bb9\u3002 it ' s original file add oneline \u901a\u8fc7\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u53ef\u4ee5\u770b\u5230\u6240\u4ee5\u8f6f/\u786c\u94fe\u63a5\u6587\u4ef6\u5185\u5bb9\u90fd\u66f4\u65b0\u4e86\uff0c\u548c file \u6587\u4ef6\u66f4\u65b0\u540e\u7684\u5185\u5bb9\u4fdd\u6301\u4e00\u81f4\u3002 cat hardlinkfile1 cat hardlinkfile2 cat symlinkfile1 cat symlinkfile2 \u5bf9\u6587\u4ef6 symlinkfile1 \u518d\u521b\u5efa\u65b0\u7684\u8f6f\u8fde\u63a5\u3002 ln -s symlinkfile1 symlinkfile1-1 \u901a\u8fc7\u547d\u4ee4 ls -il \u67e5\u770b\u73b0\u5728\u7684\u76ee\u5f55\u4fe1\u606f\u3002 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 file 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile1 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile2 67274681 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file 67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov 1 11 :20 symlinkfile1-1 -> symlinkfile1 67274682 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file \u8bfb\u53d6\u8f6f\u94fe\u63a5\u6587\u4ef6\u7684\u6e90\u6587\u4ef6\u4fe1\u606f readlink symlinkfile1 readlink symlinkfile2 \u6ce8\u610f\uff0c\u5bf9\u4e8e symlinkfile1-1 \u7684\u60c5\u51b5\u6709\u4e9b\u4e0d\u540c\u3002 readlink symlinkfile1-1 \u4e0a\u9762\u547d\u4ee4\u8fd4\u56de\u7ed3\u679c symlinkfile1 \u4ecd\u7136\u662f\u4e00\u4e2a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\u3002\u901a\u8fc7 readlink -f \u53ef\u4ee5\u76f4\u63a5\u5b9a\u4f4d\u771f\u6b63\u7684\u6e90\u6587\u4ef6\u3002 readlink -f symlinkfile1-1 \u4e0a\u9762\u7684\u8fd4\u56de\u7ed3\u679c /data/linktype/file \u662f symlinkfile1-1 \u771f\u6b63\u7684\u6e90\u6587\u4ef6\u3002 \u663e\u793a data \u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\uff1a cd ~ tree ./data \u8fd0\u884c\u7ed3\u679c\uff1a ./data \u251c\u2500\u2500 file \u251c\u2500\u2500 hardlinkfile1 \u251c\u2500\u2500 hardlinkfile2 \u251c\u2500\u2500 symlinkfile1 -> file \u251c\u2500\u2500 symlinkfile1-1 -> symlinkfile1 \u251c\u2500\u2500 symlinkfile2 -> file \u2514\u2500\u2500 typelink \u53ea\u663e\u793a data \u76ee\u5f55\u4e0b\u7684\u5b50\u76ee\u5f55\uff1a tree -d ./data \u8fd0\u884c\u7ed3\u679c\uff1a ./data \u2514\u2500\u2500 typelink \u663e\u793a data \u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\uff0c\u5305\u542b\u5168\u76ee\u5f55\uff1a tree -f ./data \u8fd0\u884c\u7ed3\u679c\uff1a ./data \u251c\u2500\u2500 ./data/file \u251c\u2500\u2500 ./data/hardlinkfile1 \u251c\u2500\u2500 ./data/hardlinkfile2 \u251c\u2500\u2500 ./data/symlinkfile1 -> file \u251c\u2500\u2500 ./data/symlinkfile1-1 -> symlinkfile1 \u251c\u2500\u2500 ./data/symlinkfile2 -> file \u2514\u2500\u2500 ./data/typelink 4.\u6587\u4ef6\u5c5e\u6027\u8bf4\u660e \u00b6 \u6267\u884c\u547d\u4ee4 ls -ihl \uff0c\u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\uff08Rocky 9\uff09\u3002 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 file 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile1 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile2 67274681 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file 67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov 1 11 :20 symlinkfile1-1 -> symlinkfile1 67274682 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file 33555262 drwxr-xr-x. 2 vagrant wheel 6 Nov 1 11 :30 typelink \u4ee5 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11:14 file \u4e3a\u4f8b\uff1a 67274680 : inode \u7d22\u5f15\u8282\u70b9\u7f16\u53f7\u3002 -rw-r--r-- \uff1a\u6587\u4ef6\u7c7b\u578b\u53ca\u6743\u9650 - \uff1a\u6587\u4ef6\u7c7b\u578b\uff0c\u4f8b\u5b50\u4e2d\u51fa\u73b0\u4e86\u4e09\u79cd\uff0c - \uff0c l \u548c d \u3002 - \uff1a\u666e\u901a\u6587\u4ef6 d \uff1a\u76ee\u5f55 l \uff1a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\uff08link\uff09 b \uff1a\u5757\u8bbe\u5907\uff08block\uff09 c \uff1a\u5b57\u7b26\u8bbe\u5907\uff08character\uff09 p \uff1a\u7ba1\u9053\u6587\u4ef6\uff08pipe\uff09 s \uff1a\u5957\u63a5\u5b57\u6587\u4ef6\uff08socket\uff09 rw-r--r-- \uff1a\u6587\u4ef6\u6743\u9650\uff0c\u4ece\u5de6\u5230\u53f3\u4f9d\u6b21\u4e3a\uff1a rw- \uff1a\u6587\u4ef6\u5c5e\u4e3b\u6743\u9650\uff0c\u4f8b\u5b50\u4e2d\u662f vagrant \u3002 r-- \uff1a\u6587\u4ef6\u5c5e\u7ec4\u7684\u6743\u9650\uff0c\u4f8b\u5b50\u4e2d\u662f wheel \u3002 r-- \uff1a\u5176\u4ed6\u7ec4\u7684\u6743\u9650\u3002 . \uff1a\u8fd9\u4e2a\u70b9\u8868\u793a\u6587\u4ef6\u5e26\u6709SELinux\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\uff08SELinux Contexts\uff09\u3002\u5173\u95edSELinux\uff0c\u65b0\u521b\u5efa\u7684\u6587\u4ef6\u5c31\u4e0d\u4f1a\u518d\u6709\u8fd9\u4e2a\u70b9\u4e86\u3002\u4f46\u662f\uff0c\u4ee5\u524d\u521b\u5efa\u7684\u6587\u4ef6\u672c\u6765\u6709\u8fd9\u4e2a\u70b9\u7684\u8fd8\u4f1a\u663e\u793a\u8fd9\u4e2a\u70b9\uff08\u867d\u7136SELinux\u4e0d\u8d77\u4f5c\u7528\u4e86\uff09\u3002 3 \uff1a\u786c\u94fe\u63a5\u6570\uff0c\u4f8b\u5b50\u4e2d file \u548c hardlinkfile1 \u548c hardlinkfile2 \u4e4b\u95f4\u662f\u786c\u94fe\u63a5\uff0c\u6240\u4ee5\u8fd9\u4e09\u4e2a\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u90fd\u662f 3 \u3002 vagrant \uff1a\u6587\u4ef6\u5c5e\u4e3b wheel \uff1a\u6587\u4ef6\u5c5e\u7ec4 31 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u5927\u5c0f Nov 1 11:14 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u521b\u5efa\u65e5\u671f\u548c\u65f6\u95f4 file \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u540d\u79f0 \u4e0b\u9762\u662f\u547d\u4ee4 ls -ihl \u5728openSUSE\u548cUbuntu\u4e0a\u7684\u663e\u793a\u7ed3\u679c\u3002 $ ls -ihl 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 file 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile1 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile2 233648 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile1 -> file 233650 lrwxrwxrwx 1 vagrant wheel 12 Nov 1 15 :52 symlinkfile1-1 -> symlinkfile1 233649 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile2 -> file 233646 drwxr-xr-x 1 vagrant wheel 0 Nov 1 15 :51 typelink 5.\u6807\u51c6\u8f93\u5165\u8f93\u51fa \u00b6 \u6807\u51c6\u8f93\u5165\u8f93\u51fa\uff0c\u5373I/O\uff0cI/O\u7684I\u662fInput\uff0cO\u662foutput\u3002 I\uff1a\u4ece\u5916\u90e8\u8bbe\u5907\u8f93\u5165\u5230\u5185\u5b58 O\uff1a\u4ece\u5185\u5b58\u8f93\u51fa\u5230\u5916\u90e8\u8bbe\u5907 \u6807\u51c6\u8f93\u5165\u548c\u6807\u51c6\u8f93\u51fa\u662f\u7528\u4e8eIO\u7684\uff0c\u5b83\u4eec\u5c5e\u4e8e\u5916\u90e8\u8bbe\u5907\uff08\u903b\u8f91\u4e0a\u7684\u5916\u90e8\u8bbe\u5907\uff09\uff0c\u4e0d\u662f\u5185\u5b58\u3002 linux\u4e2d\u4e00\u5207\u8bbe\u5907\u7686\u662f\u6587\u4ef6\uff01\u56e0\u6b64\u6807\u51c6\u8f93\u5165\u548c\u8f93\u51fa\u672c\u8d28\u5c31\u662f\u6587\u4ef6\uff0c\u5916\u90e8\u8bbe\u5907\u4ee5\u6587\u4ef6\u5f62\u5f0f\u8868\u73b0\u3002 \u5728Linux\u7cfb\u7edf\u4e2d\uff0c\u6807\u51c6\u8f93\u5165\u548c\u6807\u51c6\u8f93\u51fa\u5bf9\u5e94\u7684\u6587\u4ef6\u662f /dev/stdin \u548c /dev/stdout \u8fd9\u4e24\u4e2a\u6587\u4ef6\u3002 \u4ece\u6807\u51c6\u8f93\u5165\u8bfb\uff0c\u4ece\u903b\u8f91\u4e0a\u8bb2\uff0c\u5c31\u662f\u6253\u5f00 /dev/stdin \u8fd9\u4e2a\u6587\u4ef6\uff0c\u5e76\u8bfb\u5165\u6587\u4ef6\u5185\u5bb9\u3002 \u8f93\u51fa\u5230\u6807\u51c6\u8f93\u51fa\uff0c\u4ece\u903b\u8f91\u4e0a\u8bb2\uff0c\u5c31\u662f\u6253\u5f00 /dev/stdout \u8fd9\u4e2a\u6587\u4ef6\uff0c\u5e76\u628a\u5185\u5bb9\u8f93\u51fa\u5230\u8fd9\u4e2a\u6587\u4ef6\u91cc\u53bb\u3002 \u8fd9\u91cc\u5f3a\u8c03\u7684\u662f\u201c\u903b\u8f91\u4e0a\u201d\uff0c\u56e0\u4e3a /dev/stdin \u548c /dev/stdout \u8fd92\u4e2a\u6587\u4ef6\u672c\u8eab\u4e0d\u662f\u8bbe\u5907\u6587\u4ef6\u3002Linux\u4e2d\u8bbe\u5907\u662f\u6587\u4ef6\uff0c\u4f46\u662f\u6587\u4ef6\u4e0d\u4e00\u5b9a\u662f\u8bbe\u5907\u3002 \u56e0\u6b64\uff0c\u64cd\u4f5c /dev/stdin \u548c/dev/stdout`\u8fd92\u4e2a\u6587\u4ef6\uff0c\u5b9e\u9645\u4e0a\u662f\u64cd\u4f5c\u4e24\u4e2a\u6587\u4ef6\u5b58\u653e\u5730\u5740\u5bf9\u5e94\u7684\u8bbe\u5907\u6587\u4ef6\u3002 \u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u770b\u5230\u6807\u51c6\u8f93\u5165\u8f93\u51fa\u6587\u4ef6\u7684\u7279\u70b9\uff0c\u4ed6\u4eec\u867d\u7136\u5728 /dev \u76ee\u5f55\u4e0b\uff0c\u90fd\u662f\u4ee5 l \u5f00\u5934\u7684\u94fe\u63a5\u6587\u4ef6\uff0c\u6307\u5411\u7684\u662f\u53e6\u4e00\u4e2a\u6587\u4ef6\u7684\u5730\u5740\u3002 $ ls -l /dev/std* lrwxrwxrwx 1 root root 15 Nov 13 10 :39 /dev/stderr -> /proc/self/fd/2 lrwxrwxrwx 1 root root 15 Nov 13 10 :39 /dev/stdin -> /proc/self/fd/0 lrwxrwxrwx 1 root root 15 Nov 13 10 :39 /dev/stdout -> /proc/self/fd/1 # Rocky $ ll /proc/self/fd/ lrwx------. 1 vagrant wheel 64 Nov 13 22 :38 0 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 22 :38 1 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 22 :38 2 -> /dev/pts/0 lr-x------. 1 vagrant wheel 64 Nov 13 22 :38 3 -> /proc/1702/fd # Ubuntu $ ll /proc/self/fd/ lrwx------ 1 vagrant sudo 64 Nov 13 14 :38 0 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 14 :38 1 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 14 :38 2 -> /dev/pts/0 lr-x------ 1 vagrant sudo 64 Nov 13 14 :38 3 -> /proc/2062/fd/ # openSUSE $ ll /proc/self/fd/* ls: cannot access '/proc/self/fd/255' : No such file or directory ls: cannot access '/proc/self/fd/3' : No such file or directory lrwx------ 1 vagrant wheel 64 Nov 13 22 :37 /proc/self/fd/0 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 22 :37 /proc/self/fd/1 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 22 :37 /proc/self/fd/2 -> /dev/pts/0 Linux\u8fdb\u7a0b\u9ed8\u8ba4\u4f1a\u6253\u5f00\u7684\u4e09\u4e2a\u6587\u4ef6\uff1a \u6807\u51c6\u8f93\u5165 /dev/stdin \uff0c\u63cf\u8ff0\u7b26\u4e3a 0\uff0c\u9ed8\u8ba4\u662f\u952e\u76d8\u8f93\u5165\u3002 \u6807\u51c6\u8f93\u51fa /dev/stdout \uff0c\u63cf\u8ff0\u7b26\u4e3a 1\uff0c\u9ed8\u8ba4\u662f\u8f93\u51fa\u5230\u5c4f\u5e55\u3002 \u6807\u51c6\u8f93\u51fa /dev/stderr \uff0c\u63cf\u8ff0\u7b26\u4e3a 2\uff0c\u9ed8\u8ba4\u662f\u8f93\u51fa\u5230\u5c4f\u5e55\u3002 \u4ee5Rocky\u4e3a\u4f8b\uff0c\u521b\u5efa file.py \u6587\u4ef6\u3002 $ cat > file.py < test.txt \u8fd0\u884c file.py \u7a0b\u5e8f\u3002 python3 file.py \u6253\u5f00\u65b0\u7684\u7ec8\u7aef\u7a97\u53e3\uff0c\u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u5f97\u5230python3\u8fd9\u4e2a\u7a0b\u5e8f\u8fd0\u884c\u7684process ID\u3002\u5176\u4e2d\u53ef\u4ee5\u770b\u5230\u6709\u4e00\u4e2a\u6765\u81ea\u6587\u4ef6test.txt\u88ab\u7a0b\u5e8ffile.py\u6253\u5f00\uff08\u8f93\u5165\uff09\u3002 $ pidof python3 1739 788 $ sudo ls -l /proc/788/fd/ lr-x------. 1 root root 64 Nov 13 23 :00 0 -> /dev/null l-wx------. 1 root root 64 Nov 13 23 :00 1 -> /dev/null lrwx------. 1 root root 64 Nov 13 23 :00 10 -> 'socket:[24677]' lrwx------. 1 root root 64 Nov 13 23 :00 11 -> 'socket:[24678]' l-wx------. 1 root root 64 Nov 13 23 :00 2 -> /dev/null l-wx------. 1 root root 64 Nov 13 10 :41 3 -> /var/log/firewalld lrwx------. 1 root root 64 Nov 13 23 :00 4 -> 'socket:[23421]' lrwx------. 1 root root 64 Nov 13 23 :00 5 -> 'anon_inode:[eventfd]' lrwx------. 1 root root 64 Nov 13 23 :00 6 -> 'socket:[24586]' lr-x------. 1 root root 64 Nov 13 23 :00 7 -> anon_inode:inotify lrwx------. 1 root root 64 Nov 13 23 :00 8 -> 'anon_inode:[eventfd]' lrwx------. 1 root root 64 Nov 13 23 :00 9 -> '/memfd:libffi (deleted)' $ sudo ls -l /proc/1739/fd/ lrwx------. 1 vagrant wheel 64 Nov 13 23 :00 0 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 23 :00 1 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 23 :00 2 -> /dev/pts/0 lr-x------. 1 vagrant wheel 64 Nov 13 23 :00 3 -> /home/vagrant/test.txt \u5728Ubuntu\u4e2d\u8fd0\u884c file.py \u7a0b\u5e8f\uff0cpidof\u4f1a\u53d6\u5f973\u4e2aprocess IDs\u3002 $ pidof python3 2128 924 873 $ sudo ls -l /proc/2128/fd/ lrwx------ 1 vagrant sudo 64 Nov 13 15 :10 0 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 15 :10 1 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 15 :10 2 -> /dev/pts/0 lr-x------ 1 vagrant sudo 64 Nov 13 15 :10 3 -> /home/vagrant/test.txt $ sudo ls -l /proc/924/fd/ lr-x------ 1 root root 64 Nov 13 15 :11 0 -> /dev/null lrwx------ 1 root root 64 Nov 13 15 :11 1 -> 'socket:[31593]' lrwx------ 1 root root 64 Nov 13 15 :11 2 -> 'socket:[31593]' l-wx------ 1 root root 64 Nov 13 02 :40 3 -> /var/log/unattended-upgrades/unattended-upgrades-shutdown.log lrwx------ 1 root root 64 Nov 13 15 :11 4 -> 'socket:[31652]' lrwx------ 1 root root 64 Nov 13 15 :11 5 -> 'anon_inode:[eventfd]' lrwx------ 1 root root 64 Nov 13 15 :11 6 -> 'anon_inode:[eventfd]' lrwx------ 1 root root 64 Nov 13 15 :11 7 -> 'socket:[31657]' l-wx------ 1 root root 64 Nov 13 15 :11 8 -> /run/systemd/inhibit/1.ref lrwx------ 1 root root 64 Nov 13 15 :11 9 -> 'socket:[31658]' $ sudo ls -l /proc/873/fd/ lr-x------ 1 root root 64 Nov 13 15 :11 0 -> /dev/null lrwx------ 1 root root 64 Nov 13 15 :11 1 -> 'socket:[31412]' lrwx------ 1 root root 64 Nov 13 15 :11 2 -> 'socket:[31412]' lrwx------ 1 root root 64 Nov 13 02 :40 3 -> 'socket:[31650]' lrwx------ 1 root root 64 Nov 13 15 :11 4 -> 'anon_inode:[eventfd]' lrwx------ 1 root root 64 Nov 13 15 :11 5 -> 'socket:[31663]' lrwx------ 1 root root 64 Nov 13 15 :11 6 -> 'socket:[31664]' openSUSE\u9700\u8981\u5b89\u88c5\u5305 sysvinit-tools \u624d\u80fd\u4f7f\u7528 pidof \u547d\u4ee4\u3002 sudo zypper in sysvinit-tools \u7531\u4e8eopenSUSE\u4e2dpidof python3\u53ea\u8fd4\u56de\u4e00\u4e2aprocess ID\uff0c\u6240\u4ee5\u53ef\u4ee5\u7b80\u5316\u547d\u4ee4\u884c\u5f97\u5230process ID\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 $ sudo ls -l /proc/ ` pidof python3 ` /fd/ lrwx------ 1 vagrant wheel 64 Nov 13 23 :21 0 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 23 :21 1 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 23 :21 2 -> /dev/pts/0 lr-x------ 1 vagrant wheel 64 Nov 13 23 :21 3 -> /home/vagrant/test.txt \u53c2\u8003\uff1a \u5f53\u952e\u76d8\u548c\u9f20\u6807\u7b49\u8bbe\u5907\u901a\u8fc7\u4e32\u53e3\u76f4\u63a5\u8fde\u63a5\u5230\u8ba1\u7b97\u673a\u65f6\uff0c\u8fd9\u79cd\u8fde\u63a5\u79f0\u4e3aTTY\u3002 \u4f2a\u7ec8\u7aefpseudoterminal\uff08\u7f29\u5199\u4e3a\u201cpty\u201d\uff09\u662f\u4e00\u5bf9\u63d0\u4f9b\u53cc\u5411\u901a\u4fe1\u901a\u9053\u7684\u865a\u62df\u5b57\u7b26\u8bbe\u5907\u3002 \u901a\u9053\u7684\u4e00\u7aef\u79f0\u4e3a\u4e3b\u7aefmaster\uff1b \u53e6\u4e00\u7aef\u79f0\u4e3a\u4ece\u7aefslave\u3002 /dev/pts \u8868\u793a\u4e0e\u4f2a\u7ec8\u7aefpseudoterminal\u7684\u4e3b\u7aefmaster\u6216\u4ece\u7aefslave\u76f8\u5173\u7684master\u6587\u4ef6\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5c06\u5176\u4fdd\u5b58\u4e3a /dev/ptmx \u6587\u4ef6\u3002 telnet \u548c ssh \u7b49\u7a0b\u5e8f\u80fd\u591f\u4eff \u7aef\u7528\u6237> \u4e0e\u5b83\u4eec\u7684\u4ea4\u4e92\uff0c\u867d\u7136\u672c\u8d28\u4e0a\u662f\u4e0e\u6587\u4ef6 /dev/ptmx \u8fdb\u884c\u4ea4\u4e92\uff0c\u4f46\u5448\u73b0\u7ed9\u7528\u6237\u7684\u5374\u662f\u597d\u50cf\u8fd0\u884c\u5728\u771f\u6b63\u7684\u7ec8\u7aef\u7a97\u53e3\u4e00\u6837\uff0c\u4ece\u7aef\u7684\u6587\u4ef6\u662f\u4e3b\u7aef\u7684\u8f93\u5165\u3002 \u4f2a\u7ec8\u7aef\u8fdb\u7a0b\u5728Linux\u4e2d\u88ab\u5b58\u50a8\u5728 /dev/pts/ \u76ee\u5f55\u4e0b\u3002 /dev/pts/ \u76ee\u5f55\u4e0b\u7684\u5185\u5bb9\u662f\u4e00\u4e9b\u7279\u6b8a\u7684\u76ee\u5f55\uff0c\u7531Linux\u5185\u6838\u6240\u521b\u5efa\u3002 \u6bcf\u4e2a\u552f\u4e00\u7684\u7ec8\u7aef\u7a97\u53e3\u90fd\u4e0e /dev/pts \u7cfb\u7edf\u4e2d\u7684\u4e00\u4e2aLinux pts \u6761\u76ee\u76f8\u5173\u3002 \u4e0b\u9762\u8fd4\u56de\u7684\u7ed3\u679c\u8bf4\u660e\u67092\u4e2a\u8fdc\u7a0b\u7ec8\u7aef\u8fde\u63a5\u5230\u5f53\u524d\u7684\u673a\u5668\u3002 $ ll /dev/pts/ crw--w----. 1 vagrant tty 136 , 0 Nov 13 23 :18 0 crw--w----. 1 vagrant tty 136 , 1 Nov 13 23 :48 1 c---------. 1 root root 5 , 2 Nov 13 10 :41 ptmx \u4e5f\u53ef\u4ee5\u901a\u8fc7 w \u547d\u4ee4\u770b\u52302\u4e2a\u7ec8\u7aef\u8fdb\u7a0b\u3002 $ w 23 :55:05 up 13 :14, 2 users, load average: 0 .00, 0 .00, 0 .00 USER TTY LOGIN@ IDLE JCPU PCPU WHAT vagrant pts/0 10 :51 37 :03 0 .05s 0 .05s -bash vagrant pts/1 23 :48 0 .00s 0 .03s 0 .00s w \u5355\u4e2a\u4f2a\u7ec8\u7aefpseudoterminal\u53ef\u4ee5\u540c\u65f6\u63a5\u6536\u6765\u81ea\u4e0d\u540c\u7684\u7a0b\u5e8f\u7684\u8f93\u51fa\u3002 \u591a\u4e2a\u7a0b\u5e8f\u540c\u65f6\u5bf9\u4e00\u4e2a\u4f2a\u7ec8\u7aefpseudoterminal\u8fdb\u884c\u8bfb\u53d6\u4f1a\u5f15\u8d77\u6df7\u6dc6\u3002 \u5b58\u50a8\u5728 /dev/pts \u76ee\u5f55\u4e2d\u7684\u6587\u4ef6\u662f\u62bd\u8c61\u6587\u4ef6\u800c\u4e0d\u662f\u771f\u5b9e\u6587\u4ef6\uff0c\u662f\u4f2a\u7ec8\u7aef\u4e2d\u6267\u884c\u7a0b\u5e8f\u65f6\u4e34\u65f6\u5b58\u50a8\u7684\u6570\u636e\u3002 \u6253\u5f00 /dev/pts \u4e0b\u7684\u6587\u4ef6\u901a\u5e38\u6ca1\u6709\u4ec0\u4e48\u5b9e\u9645\u610f\u4e49\u3002 6.\u91cd\u5b9a\u5411\u548c\u7ba1\u9053 \u00b6 6.1.\u8f93\u5165\u91cd\u5b9a\u5411 \u00b6 \u5e38\u7528\u547d\u4ee4\u683c\u5f0f\uff1a command < file \uff1a\u5c06\u6307\u5b9a\u6587\u4ef6 file \u4f5c\u4e3a\u547d\u4ee4\u7684\u8f93\u5165\u8bbe\u5907\u3002 command << delimiter \uff1a\u8868\u793a\u4ece\u6807\u51c6\u8f93\u5165\u8bbe\u5907\uff08\u952e\u76d8\uff09\u4e2d\u8bfb\u5165\uff0c\u76f4\u5230\u9047\u5230\u5206\u754c\u7b26 delimiter \u505c\u6b62\uff08\u8bfb\u5165\u7684\u6570\u636e\u4e0d\u5305\u62ec\u5206\u754c\u7b26\uff09\uff0c\u8fd9\u91cc\u7684\u5206\u754c\u7b26\u53ef\u4ee5\u7406\u89e3\u4e3a\u81ea\u5b9a\u4e49\u7684\u5b57\u7b26\u4e32\u3002 command < file1 > file2 \uff1a\u5c06 file1 \u4f5c\u4e3a\u547d\u4ee4\u7684\u8f93\u5165\u8bbe\u5907\uff0c\u8be5\u547d\u4ee4\u7684\u6267\u884c\u7ed3\u679c\u8f93\u51fa\u5230 file2 \u4e2d\u3002 # \u8f93\u51fa\u6587\u4ef6file.py\u5185\u5bb9\uff08\u8f93\u5165\u8bbe\u5907\u662f\u952e\u76d8\uff09 $ cat file.py # \u8f93\u51fa\u6587\u4ef6file.py\u5185\u5bb9\uff08\u8f93\u5165\u8bbe\u5907\u662f\u6587\u4ef6file.py\uff09 $ cat < file.py # \u6307\u5b9a\u5206\u754c\u7b26\uff08\u8fd9\u91cc\u662fEOF\uff09\uff0c\u8bfb\u53d6\u952e\u76d8\u8f93\u5165\u5185\u5bb9\uff0c\u76f4\u5230\u9047\u5230\u6307\u5b9a\u5206\u754c\u7b26\u4e3a\u6b62\uff0c\u5c06\u6240\u8bfb\u53d6\u7684\u5185\u5bb9\u8f93\u51fa\u5230\u6587\u4ef6file.py\u3002 $ cat > file.py < new.py 6.2.\u8f93\u51fa\u91cd\u5b9a\u5411 \u00b6 \u8f93\u51fa\u91cd\u5b9a\u5411\u5206\u4e3a\u6807\u51c6\u8f93\u51fa\u91cd\u5b9a\u5411\u548c\u9519\u8bef\u8f93\u51fa\u91cd\u5b9a\u5411\u4e24\u79cd\u3002 \u5e38\u7528\u547d\u4ee4\u683c\u5f0f\uff1a command > file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u6807\u51c6\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u8f93\u51fa\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u5df2\u5305\u542b\u6570\u636e\uff0c\u4f1a\u6e05\u7a7a\u539f\u6709\u6570\u636e\uff0c\u518d\u5199\u5165\u65b0\u6570\u636e\u3002 command 2> file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u9519\u8bef\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u4e2d\u5df2\u5305\u542b\u6570\u636e\uff0c\u4f1a\u6e05\u7a7a\u539f\u6709\u6570\u636e\uff0c\u518d\u5199\u5165\u65b0\u6570\u636e\u3002 command >> file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u6807\u51c6\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u8f93\u51fa\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u5df2\u5305\u542b\u6570\u636e\uff0c\u65b0\u6570\u636e\u5c06\u8ffd\u52a0\u5199\u5165\u5230\u539f\u6709\u5185\u5bb9\u7684\u540e\u9762\u3002 command 2>> file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u9519\u8bef\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u4e2d\u5df2\u5305\u542b\u6570\u636e\uff0c\u65b0\u6570\u636e\u5c06\u8ffd\u52a0\u5199\u5165\u5230\u539f\u6709\u5185\u5bb9\u7684\u540e\u9762\u3002 command >> file 2>&1 \u6216\u8005 command &>> file \uff1a\u5c06\u6807\u51c6\u8f93\u51fa\u6216\u8005\u9519\u8bef\u8f93\u51fa\u5199\u5165\u5230\u6307\u5b9a\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u4e2d\u5df2\u5305\u542b\u6570\u636e\uff0c\u65b0\u6570\u636e\u5c06\u8ffd\u52a0\u5199\u5165\u5230\u539f\u6709\u5185\u5bb9\u7684\u540e\u9762\u3002 \u6ce8\u610f\uff1a\u4e0a\u9762\u7684 file \u53ef\u4ee5\u662f\u4e00\u4e2a\u666e\u901a\u6587\u4ef6\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u4e00\u4e2a\u7279\u6b8a\u7684\u6587\u4ef6 /dev/null \u3002 /dev/null \u5e76\u4e0d\u4fdd\u5b58\u6570\u636e\uff0c\u88ab\u5199\u5165 /dev/null \u7684\u6570\u636e\u6700\u7ec8\u90fd\u4f1a\u4e22\u5931\u3002 \u4e3e\u4f8b\uff1a2\u4e2apython\u6587\u4ef6\u5b58\u5728\uff0c\u5176\u4ed62\u4e2a\u65e0\u6269\u5c55\u540d\u7684\u6587\u4ef6\u4e0d\u5b58\u5728\u3002 ls file.py > out ls file 2 > out.err ls new.py >> out ls new 2 >> out.err \u53ef\u4ee5\u5f97\u5230\u9884\u671f\u7684\u7ed3\u679c\u3002\u4e24\u4e2a\u9519\u8bef\u8bb0\u5f55\u90fd\u88ab\u8ffd\u52a0\u5230 out.err \u6587\u4ef6\u4e2d\u3002\u4e24\u4e2a\u6210\u529f\u6267\u884c\u7684\u547d\u4ee4\u7684\u8fd4\u56de\u7ed3\u679c\u4e5f\u8f93\u51fa\u5230 out \u6587\u4ef6\u4e2d\u3002 $ccat out file.py new.py $ cat out.err ls: cannot access 'file' : No such file or directory ls: cannot access 'new' : No such file or directory \u4e0a\u4f8b\u547d\u4ee4\u4e5f\u53ef\u4ee5\u5408\u5e76\u3002 ls file.py > out 2 > out.err ls file >> out 2 >> out.err 2>&1 \u683c\u5f0f\u4e3e\u4f8b\uff1a $ ls file >> out.txt 2 > & 1 $ cat out.txt ls: cannot access 'file' : No such file or directory $ ls file.py & >> out.txt $ cat out.txt ls: cannot access 'file' : No such file or directory file.py 6.3.\u7279\u6b8a\u91cd\u5b9a\u5411 \u00b6 \u683c\u5f0f\uff1a command1 < <(command2) tr 'a-z' 'A-Z' < < ( echo \"Hello World\" ) \u5e94\u7528\uff1a\u4fee\u6539\u5bc6\u7801 \u5bc6\u7801\u4fdd\u5b58\u5728 passwd.txt \u6587\u4ef6\u4e2d\uff0c\u5e76\u4e25\u683c\u9650\u5236\u6539\u6587\u4ef6\u7684\u6743\u9650\u3002 \u901a\u8fc7\u53c2\u6570 --stdin \u5b9e\u73b0\u6a21\u62df\u952e\u76d8\u8f93\u5165\u64cd\u4f5c\u8f93\u5165\u7528\u6237\u540d\u3002 \u5728Rocky\u4e2d\u53ef\u4ee5\u4f7f\u7528 --stdin \u53c2\u6570\u3002 passwd --stdin vagrant < passwd.txt \u5728openSUSE\u548cUbuntu\u4e2d\uff0c --stdin \u53c2\u6570\u65e0\u6cd5\u8bc6\u522b\u3002\u53ef\u4ee5\u6539\u7528\u4e0b\u9762\u7684\u65b9\u6cd5\u3002 echo passwd.txt | chpasswd \u5176\u4e2dpasswd.txt\u7684\u683c\u5f0f\u4e3a username:password \u3002 \u53c2\u8003\uff1a Here-document(Here-doc)\uff1a\u8f93\u5165\u7684\u6587\u672c\u5757\u91cd\u5b9a\u5411\u81f3\u6807\u51c6\u8f93\u5165\u6d41\uff0c\u76f4\u81f3\u9047\u5230\u7279\u6b8a\u7684\u6587\u4ef6\u7ed3\u675f\u6807\u8bb0\u7b26\u4e3a\u6b62\uff08\u6587\u4ef6\u7ed3\u675f\u6807\u8bb0\u7b26\u53ef\u4ee5\u662f\u4efb\u610f\u7684\u552f\u4e00\u7684\u5b57\u7b26\u4e32\uff0c\u4f46\u5927\u90e8\u5206\u4eba\u90fd\u9ed8\u8ba4\u4f7f\u7528 EOF \uff09\u3002 cat < \u5c06\u547d\u4ee4\u4e0e\u6587\u4ef6\u8fde\u63a5\u8d77\u6765\uff0c\u7528\u6587\u4ef6\u6765\u63a5\u6536\u547d\u4ee4\u7684\u8f93\u51fa\uff1b\u800c\u7ba1\u9053\u7b26 | \u5c06\u547d\u4ee4\u4e0e\u547d\u4ee4\u8fde\u63a5\u8d77\u6765\uff0c\u7528\u53f3\u8fb9\u547d\u4ee4\u6765\u63a5\u6536\u5de6\u8fb9\u547d\u4ee4\u7684\u8f93\u51fa\u3002 $ ls | tr 'a-z' 'A-Z' BIN F1.TXT F2.TXT FILE.PY NEW.PY OUT OUT.ERR TEST.TXT","title":"\u7b2c\u4e8c\u7ae0 \u6587\u4ef6\u7cfb\u7edf"},{"location":"linux/SRE/02-filesystem/#_1","text":"\u6587\u4ef6\u7cfb\u7edf\u5c42\u6b21\u6807\u51c6\uff08Filesystem Hierarchy Standard, FHS\uff09\uff0c\u5b83\u662fLinux \u6807\u51c6\u5e93\uff08Linux Standards Base, LSB\uff09\u89c4\u8303\u7684\u4e00\u90e8\u5206\u3002 \u6839\u76ee\u5f55 / \u6307\u6587\u4ef6\u7cfb\u7edf\u6811\u7684\u6700\u9ad8\u5c42\u3002 \u6839\u5206\u533a\u5728\u7cfb\u7edf\u542f\u52a8\u65f6\u9996\u5148\u6302\u8f7d\u3002 \u7cfb\u7edf\u542f\u52a8\u65f6\u8fd0\u884c\u7684\u6240\u6709\u7a0b\u5e8f\u90fd\u5fc5\u987b\u5728\u6b64\u5206\u533a\u4e2d\u3002","title":"\u7b2c\u4e8c\u7ae0 \u6587\u4ef6\u7cfb\u7edf"},{"location":"linux/SRE/02-filesystem/#1","text":"\u4ee5\u4e0b\u76ee\u5f55\u5fc5\u987b\u5728\u6839\u5206\u533a\u4e2d\uff1a /bin - \u7528\u6237\u57fa\u672c\u7a0b\u5e8f\u3002 \u5305\u542b\u672a\u6302\u8f7d\u5176\u4ed6\u6587\u4ef6\u7cfb\u7edf\u65f6\u6240\u9700\u7684\u53ef\u6267\u884c\u6587\u4ef6\u3002 \u4f8b\u5982\uff0c\u7cfb\u7edf\u542f\u52a8\u3001\u5904\u7406\u6587\u4ef6\u548c\u914d\u7f6e\u6240\u9700\u7684\u7a0b\u5e8f\u3002 \u4e0d\u80fd\u5173\u8054\u5230\u72ec\u7acb\u5206\u533a\uff0c\u64cd\u4f5c\u7cfb\u7edf\u542f\u52a8\u5373\u4f1a\u8c03\u7528\u7684\u7a0b\u5e8f\u3002 /bin/bash - bash \u811a\u672c\u5904\u7406 /bin/cat - \u663e\u793a\u6587\u4ef6\u5185\u5bb9 /bin/cp - \u62f7\u8d1d\u6587\u4ef6 /bin/dd - \u62f7\u8d1d\u6587\u4ef6\uff08\u57fa\u4e8e\u5b57\u8282byte\uff09 /bin/gzip - \u538b\u7f29\u6587\u4ef6 /bin/mount - \u6302\u8f7d\u6587\u4ef6\u7cfb\u7edf /bin/rm - \u5220\u9664\u6587\u4ef6 /bin/vi - \u6587\u4ef6\u7f16\u8f91 /sbin - \u7cfb\u7edf\u57fa\u672c\u7a0b\u5e8f\u3002 \u5305\u542b\u57fa\u672c\u7cfb\u7edf\u7ba1\u7406\u7684\u7a0b\u5e8f\u3002 \u9ed8\u8ba4\u662froot\u7528\u6237\u6709\u6743\u9650\u6267\u884c\uff0c\u56e0\u6b64\u5b83\u4e0d\u5728\u5e38\u89c4\u7528\u6237\u8def\u5f84\u4e2d\u3002 \u4e0d\u80fd\u5173\u8054\u5230\u72ec\u7acb\u5206\u533a\uff0c\u64cd\u4f5c\u7cfb\u7edf\u542f\u52a8\u5373\u4f1a\u8c03\u7528\u7684\u7a0b\u5e8f \u4e00\u4e9b\u91cd\u8981\u7ba1\u7406\u7a0b\u5e8f\uff1a /sbin/fdisk* - \u7ba1\u7406\u786c\u76d8\u5206\u533a /sbin/fsck* - \u6587\u4ef6\u7cfb\u7edf\u68c0\u67e5\u3002\u4e0d\u80fd\u5728\u8fd0\u884c\u7684\u7cfb\u7edf\u4e0a\u9762\u76f4\u63a5\u6267\u884c fsck \uff0c\u635f\u574f\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u6267\u884c\u524d\u9700\u8981 umount \u3002 /sbin/mkfs - \u521b\u5efa\u6587\u4ef6\u7cfb\u7edf /sbin/shutdown - \u5173\u95ed\u7cfb\u7edf /dev - \u8bbe\u5907\u6587\u4ef6 \u4ee5\u592a\u7f51\u5361\u662f\u5185\u6838\u6a21\u5757\uff0c\u5176\u4ed6\u786c\u4ef6\u90fd\u4ee5\u8bbe\u5907dev\u7684\u65b9\u5f0f\u5c55\u73b0\u3002 \u5e94\u7528\u7a0b\u5e8f\u8bfb\u53d6\u548c\u5199\u5165\u8fd9\u4e9b\u6587\u4ef6\u4ee5\u64cd\u4f5c\u4f7f\u7528\u786c\u4ef6\u7ec4\u4ef6\u3002 \u4e24\u79cd\u7c7b\u578b\u8bbe\u5907\u6587\u4ef6\uff1a \u5b57\u7b26\u8bbe\u5907\uff08Character-oriented\uff09\u2013 \u5e8f\u5217\u8bbe\u5907\uff08\u6253\u5370\u673a\uff0c\u78c1\u5e26\u673a\uff0c\u9f20\u6807\u7b49\uff09 \u5757\u8bbe\u5907\uff08Block-oriented\uff09\u2013 \u786c\u76d8\uff0cDVD\u7b49 \u4e0e\u8bbe\u5907\u9a71\u52a8\u7a0b\u5e8f\u7684\u8fde\u63a5\u901a\u8fc7\u5185\u6838\u4e2d\u79f0\u4e3a\u4e3b\u8bbe\u5907\u53f7\u7684\u901a\u9053\u5b9e\u73b0\u3002 \u8fc7\u53bb\uff0c\u8fd9\u4e9b\u6587\u4ef6\u662f\u4f7f\u7528 mknod \u547d\u4ee4\u624b\u52a8\u521b\u5efa\u7684\u3002 \u73b0\u5728\u5f53\u5185\u6838\u53d1\u73b0\u8bbe\u5907\u65f6\uff0c\u5b83\u4eec\u4f1a\u7531 udev \u81ea\u52a8\u521b\u5efa\u3002 \u4e00\u4e9b\u91cd\u8981\u7684\u8bbe\u5907\u6587\u4ef6\uff1a Null\u8bbe\u5907: - /dev/null Zero\u8bbe\u5907: - /dev/zero \u7cfb\u7edf\u7ec8\u7aef: - /dev/console \u865a\u62df\u7ec8\u7aef: - /dev/tty1 \u4e32\u884c\u7aef\u53e3 - /dev/ttyS0 \u5e76\u884c\u7aef\u53e3: - /dev/lp0 \u8f6f\u76d8\u9a71\u52a8\u5668: - /dev/fd0 \u786c\u76d8\u9a71\u52a8\u5668: - /dev/sda \u786c\u76d8\u5206\u533a: - /dev/sda1 CD-ROM\u9a71\u52a8\u5668: - /dev/scd0 /etc - \u914d\u7f6e\u6587\u4ef6 \u5b58\u653e\u7cfb\u7edf\u548c\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6\u3002 \u5927\u90e8\u5206\u90fd\u662fASCII\u6587\u4ef6 \u666e\u901a\u7528\u6237\u53ef\u4ee5\u9ed8\u8ba4\u8bfb\u53d6\u5176\u4e2d\u7684\u5927\u90e8\u5206\u5185\u5bb9\u3002 \u8fd9\u4f1a\u5e26\u6765\u4e00\u4e2a\u6f5c\u5728\u7684\u5168\u95ee\u9898\uff0c\u56e0\u4e3a\u5176\u4e2d\u4e00\u4e9b\u6587\u4ef6\u5305\u542b\u5bc6\u7801\uff0c\u56e0\u6b64\u91cd\u8981\u7684\u662f\u8981\u786e\u4fdd\u8fd9\u4e9b\u6587\u4ef6\u53ea\u80fd\u7531root\u7528\u6237\u8bfb\u53d6\u3002 \u6839\u636eFHS\u6807\u51c6\uff0c\u6b64\u5904\u4e0d\u80fd\u653e\u7f6e\u4efb\u4f55\u53ef\u6267\u884c\u6587\u4ef6\uff0c\u4f46\u5b50\u76ee\u5f55\u53ef\u80fd\u5305\u542bshell\u811a\u672c\u3002 \u51e0\u4e4e\u6bcf\u4e2a\u5df2\u5b89\u88c5\u7684\u670d\u52a1\u5728 /etc \u6216\u5176\u5b50\u76ee\u5f55\u4e2d\u81f3\u5c11\u6709\u4e00\u4e2a\u914d\u7f6e\u6587\u4ef6\u3002 \u4e00\u4e9b\u91cd\u8981\u7684\u914d\u7f6e\u6587\u4ef6: /etc/os-release - \u7cfb\u7edf\u7248\u672c\u4fe1\u606f /etc/DIR_COLORS - ls \u547d\u4ee4\u4e2d\u7684\u989c\u8272\u914d\u7f6e\u4fe1\u606f\uff08openSUSE\u548cRocky\uff09 /etc/fstab - \u914d\u7f6e\u8981\u6302\u8f7d\u7684\u6587\u4ef6\u7cfb\u7edf /etc/profile - Shell\u767b\u5f55\u811a\u672c /etc/passwd - \u7528\u6237\u4fe1\u606f\u96c6\u5408\uff08\u4e0d\u542b\u5bc6\u7801\uff09 /etc/shadow - \u5bc6\u7801\u548c\u76f8\u5173\u4fe1\u606f /etc/group - \u7528\u6237\u7ec4\u4fe1\u606f\u96c6\u5408 /etc/cups/* - \u7528\u4e8eCUPS\u6253\u5370\u7cfb\u7edf\uff08CUPS=Common UNIX Printing System\uff09 /etc/hosts - \u4e3b\u673a\u540d\u673a\u5668IP\u5730\u5740 /etc/motd - \u767b\u5f55\u540e\u663e\u793a\u7684\u6b22\u8fce\u4fe1\u606f /etc/issue - \u767b\u5f55\u524d\u663e\u793a\u7684\u6b22\u8fce\u4fe1\u606f /etc/sysconfig/* - \u7cfb\u7edf\u914d\u7f6e\u6587\u4ef6 /lib - \u5e93\uff08Libraries\uff09 \u8bb8\u591a\u7a0b\u5e8f\u90fd\u5177\u6709\u4e00\u4e9b\u901a\u7528\u529f\u80fd\u3002 \u8fd9\u4e9b\u901a\u7528\u529f\u80fd\u53ef\u4ee5\u4fdd\u5b58\u5728\u5171\u4eab\u5e93\u4e2d\u3002 \u5171\u4eab\u5e93\u4e2d\u6587\u4ef6\u7684\u6269\u5c55\u540d\u662f .so \u3002 \u76ee\u5f55 /lib \u5305\u542b\u7684\u5171\u4eab\u5e93\u6587\u4ef6\u4e3b\u8981\u662f\u88ab /bin \u548c /sbin \u76ee\u5f55\u5305\u542b\u7684\u7a0b\u5e8f\u6240\u8c03\u7528\u3002 \u76ee\u5f55 /lib \u7684\u5b50\u76ee\u5f55\u5305\u542b\u4e00\u4e9b\u989d\u5916\u9700\u8981\u7684\u5171\u4eab\u5e93\u3002 \u5185\u6838\u6a21\u5757\u5b58\u50a8\u5728\u76ee\u5f55 /lib/modules \u3002 /lib64 - 64\u4f4d\u5171\u4eab\u5e93\uff0864-Bit Libraries\uff09\uff0c\u7c7b\u4f3c\u76ee\u5f55 /lib \u3002 \u8fd9\u4e2a\u76ee\u5f55\u56e0\u7cfb\u7edf\u67b6\u6784\u4e0d\u540c\u800c\u4e0d\u540c\u3002 \u4e00\u4e9b\u7cfb\u7edf\u652f\u6301\u4e0d\u540c\u7684\u4e8c\u8fdb\u5236\u683c\u5f0f\u5e76\u4fdd\u7559\u540c\u4e00\u4e2a\u5171\u4eab\u5e93\u7684\u4e0d\u540c\u7248\u672c\u3002 /usr - \u5305\u542b\u5e94\u7528\u7a0b\u5e8f\u3001\u56fe\u5f62\u754c\u9762\u6587\u4ef6\u3001\u5e93\u3001\u672c\u5730\u7a0b\u5e8f\u3001\u6587\u6863\u7b49\u3002 /usr \u5373 Unix System Resources. \u4f8b\u5982\uff1a /usr/X11R6/ - X Window \u7cfb\u7edf\u6587\u4ef6 /usr/bin/ - \u51e0\u4e4e\u5305\u542b\u6240\u6709\u53ef\u6267\u884c\u6587\u4ef6 /usr/lib/ - \u5305\u542b\u5e93\u548c\u5e94\u7528\u7a0b\u5e8f /usr/lib64/ - \u5305\u542b64\u4f4d\u5e93\u548c\u5e94\u7528\u7a0b\u5e8f /usr/include/ - \u5305\u542bC\u7a0b\u5e8f\u7684\u5934\u6587\u4ef6\uff08head file\uff09 /usr/local/ - \u5305\u542b\u672c\u5730\u5b89\u88c5\u7a0b\u5e8f\u3002\u8fd9\u4e2a\u76ee\u5f55\u4e0b\u7684\u5185\u5bb9\u4e0d\u4f1a\u88ab\u7cfb\u7edf\u5347\u7ea7\u6240\u8986\u76d6\u3002\u4e0b\u97623\u4e2a\u76ee\u5f55\u5728\u521d\u59cb\u5b89\u88c5\u540e\u662f\u7a7a\u7684\u3002 /usr/local/bin - /usr/local/sbin - /usr/local/lib - /usr/sbin/ - \u7cfb\u7edf\u7ba1\u7406\u7a0b\u5e8f /usr/src/ - \u5185\u6838\u548c\u5e94\u7528\u7a0b\u5e8f\u7684\u6e90\u4ee3\u7801 /usr/src/linux - /usr/share/ - \u7ed3\u6784\u5316\u72ec\u7acb\u6570\u636e /usr/share/doc/ - \u6587\u6863 /usr/share/man/ - man \u547d\u4ee4\u4f7f\u7528\u7684\u5185\u5bb9 /opt - \u7b2c\u4e09\u65b9\u5e94\u7528\u7a0b\u5e8f\u76ee\u5f55 \u5404\u53d1\u884c\u7248\u5305\u542b\u7684\u5e94\u7528\u7a0b\u5e8f\u4e00\u822c\u5b58\u50a8\u5728\u76ee\u5f55 /usr/lib/ \u3002 \u5404\u53d1\u884c\u7248\u53ef\u9009\u7a0b\u5e8f\uff0c\u6216\u7b2c\u4e09\u65b9\u5e94\u7528\u7a0b\u5e8f\u5219\u5b58\u50a8\u5728\u76ee\u5f55 /opt \u3002 \u5728\u5b89\u88c5\u65f6\uff0c\u4f1a\u4e3a\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f\u7684\u6587\u4ef6\u521b\u5efa\u4e00\u4e2a\u76ee\u5f55\uff0c\u5176\u4e2d\u5305\u542b\u5e94\u7528\u7a0b\u5e8f\u7684\u540d\u79f0\u3002\u6bd4\u5982\uff1a /opt/novell - /boot - \u5f15\u5bfc\u76ee\u5f55 /boot/grub2 - \u5305\u542bGRUB2\u7684\u9759\u6001\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\u6587\u4ef6\uff08GRUB = Grand Unified Boot Loader\uff09\u3002 \u5305\u542b\u4ee5\u94fe\u63a5 vmlinuz \u548c initrd \u6807\u8bc6\u7684\u5185\u6838\u548c initrd \u6587\u4ef6\u3002 /root - \u7ba1\u7406\u5458\u7684\u4e3b\u76ee\u5f55\uff08home directory\uff09\u3002 root \u7528\u6237\u7684\u4e3b\u76ee\u5f55\u3002\u5176\u4ed6\u7528\u6237\u7684\u4e3b\u76ee\u5f55\u662f\u5728\u76ee\u5f55 /home \u4e0b\u3002 root \u7528\u6237\u7684\u767b\u5f55\u73af\u5883\u914d\u7f6e\u4fdd\u5b58\u81f3 /root \u5206\u533a\u4e2d\u3002 /home - \u7528\u6237\u4e3b\u76ee\u5f55 \u6bcf\u4e2a\u7cfb\u7edf\u7528\u6237\u90fd\u6709\u4e00\u4e2a\u5206\u914d\u7684\u6587\u4ef6\u533a\u57df\uff0c\u8be5\u6587\u4ef6\u533a\u57df\u5728\u767b\u5f55\u540e\u6210\u4e3a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b83\u4eec\u5b58\u5728\u4e8e /home \u4e2d\u3002 /home \u4e2d\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u53ef\u4ee5\u4f4d\u4e8e\u5355\u72ec\u7684\u5206\u533a\u4e2d\uff0c\u4e5f\u53ef\u4ee5\u4f4d\u4e8e\u7f51\u7edc\u4e0a\u7684\u53e6\u4e00\u53f0\u8ba1\u7b97\u673a\u4e0a\u3002 \u7528\u6237\u914d\u7f6e\u4fe1\u606f\u548c\u914d\u7f6e\u6587\u4ef6\uff08user profile and configuration files\uff09\u4e3b\u8981\u6709\uff1a .profile - \u7528\u6237\u79c1\u6709\u767b\u5f55\u811a\u672c .bashrc - bash \u7684\u914d\u7f6e\u6587\u4ef6 .bash_history - bash \u73af\u5883\u4e0b\u4fdd\u6301\u547d\u4ee4\u5386\u53f2\u8bb0\u5f55 run - \u5e94\u7528\u7a0b\u5e8f\u72b6\u6001\u6587\u4ef6 \u4e3a\u5e94\u7528\u7a0b\u5e8f\u63d0\u4f9b\u4e86\u4e00\u4e2a\u6807\u51c6\u4f4d\u7f6e\u6765\u5b58\u50a8\u5b83\u4eec\u9700\u8981\u7684\u4e34\u65f6\u6587\u4ef6\uff0c\u4f8b\u5982\u5957\u63a5\u5b57\u548c\u8fdb\u7a0bID\u3002 \u8fd9\u4e9b\u6587\u4ef6\u4e0d\u80fd\u5b58\u50a8\u5728 /tmp \u4e2d\uff0c\u56e0\u4e3a /tmp \u4e2d\u7684\u6587\u4ef6\u53ef\u80fd\u4f1a\u88ab\u5220\u9664\u3002 /run/media//* - \u53ef\u79fb\u52a8\u8bbe\u5907\u7684\u6302\u8f7d\u70b9\uff0c\u4f8b\u5982\uff1a /run/media/media_name/ /run/media/cdrom/ - /run/media/dvd/ - /run/media/usbdisk/ - /mnt - \u6587\u4ef6\u7cfb\u7edf\u4e34\u65f6\u6302\u8f7d\u70b9 \u7528\u4e8e\u6302\u8f7d\u4e34\u65f6\u4f7f\u7528\u7684\u6587\u4ef6\u7cfb\u7edf\u7684\u76ee\u5f55\u3002 \u6587\u4ef6\u7cfb\u7edf\u4f7f\u7528 mount \u547d\u4ee4\u6302\u8f7d\uff0c\u4f7f\u7528 umount \u547d\u4ee4\u5220\u9664\u3002 \u5b50\u76ee\u5f55\u9ed8\u8ba4\u4e0d\u5b58\u5728\uff0c\u4e5f\u4e0d\u4f1a\u81ea\u52a8\u521b\u5efa\u3002 /srv - \u670d\u52a1\u6570\u636e\u76ee\u5f55 \u5b58\u653e\u5404\u79cd\u670d\u52a1\u7684\u6570\u636e\uff0c\u6bd4\u5982\uff1a /srv/www - \u7528\u4e8e\u5b58\u653e Apache Web Server \u7684\u6570\u636e /srv/ftp - \u7528\u4e8e\u5b58\u653e FTP server \u7684\u6570\u636e /var - \u53ef\u53d8\u6587\u4ef6\uff08Variable Files\uff09 \u5728\u7cfb\u7edf\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u4f1a\u88ab\u4fee\u6539\u7684\u6587\u4ef6 Important subdirectories: /var/lib/ - \u53ef\u53d8\u5e93\u6587\u4ef6\uff0c\u5e94\u7528\u7a0b\u5e8f\u72b6\u6001\u4fe1\u606f\u6570\u636e /var/log/ - \u65e5\u5fd7\u6587\u4ef6 /var/run/ - \u8fd0\u884c\u4e2d\u7684\u8fdb\u7a0b\u7684\u4fe1\u606f /var/lock/ - \u591a\u7528\u6237\u8bbf\u95ee\u65f6\u7684\u9501\u6587\u4ef6 /var/cache - \u5e94\u7528\u7a0b\u5e8f\u7f13\u5b58\u6570\u636e\u76ee\u5f55 /var/opt - \u4e13\u4e3a /opt \u4e0b\u7684\u5e94\u7528\u7a0b\u5e8f\u5b58\u50a8\u53ef\u53d8\u6570\u636e /var/mail - /var/spool/ - \u5e94\u7528\u7a0b\u5e8f\u6570\u636e\u6c60\uff0c\u6bd4\u5982\uff1a\u6253\u5370\u673a\uff0c\u90ae\u4ef6 /var/spool/mail - /var/spool/cron - /tmp - \u4e34\u65f6\u6587\u4ef6 \u7a0b\u5e8f\u5728\u8fd0\u884c\u65f6\u521b\u5efa\u4e34\u65f6\u6587\u4ef6\u7684\u4f4d\u7f6e /proc - \u8fdb\u7a0b\u6587\u4ef6 \u865a\u62df\u6587\u4ef6\u7cfb\u7edf\uff0c\u4e0d\u5360\u7a7a\u95f4\uff0c\u5927\u5c0f\u59cb\u7ec8\u4e3a\u96f6\uff0c\u4fdd\u6301\u5f53\u524d\u8fdb\u7a0b\u7684\u72b6\u6001\u4fe1\u606f \u5305\u542b\u6709\u5173\u5404\u4e2a\u8fdb\u7a0b\u7684\u4fe1\u606f\u7684\u76ee\u5f55\uff0c\u6839\u636e\u8fdb\u7a0b\u7684 PID \u53f7\u547d\u540d \u6709\u4e9b\u503c\u53ef\u4ee5\u4e34\u65f6\u5728\u7ebf\u66f4\u6539\u751f\u6548\uff0c\u4f46\u91cd\u542f\u540e\u4e22\u5931 /proc/cpuinfo/ - Processor information /proc/dma/ - Use of DMA ports /proc/interrupts/ - Use of interrupts /proc/ioports/ - Use of I/O ports /proc/filesystems/ - File system formats the kernel knows /proc/modules/ - Active modules /proc/mounts/ - Mounted file systems /proc/net/* - Network information and statistics /proc/partitions/ - Existing partitions /proc/bus/pci/ - Connected PCI devices /proc/bus/scsi/ - Connected SCSI devices /proc/sys/* - System and kernel information /proc/version - Kernel version /sys - \u7cfb\u7edf\u4fe1\u606f\u76ee\u5f55 \u865a\u62df\u6587\u4ef6\u7cfb\u7edf\uff0c\u4ec5\u5b58\u5728\u4e8e\u5185\u5b58\u4e2d\uff0c\u6587\u4ef6\u5927\u5c0f\u4e3a\u96f6\u3002\u4e3b\u8981\u63d0\u4f9b\u5982\u4e0b\u4fe1\u606f\uff1a \u786c\u4ef6\u603b\u7ebf\uff08hardware buses\uff09 \u786c\u4ef6\u8bbe\u5907\uff08hardware devices\uff09 \u6709\u6e90\u8bbe\u5907\uff08active devices\uff09 \u9a71\u52a8\u7a0b\u5e8f\uff08drivers\uff09","title":"1.\u4e3b\u8981\u76ee\u5f55"},{"location":"linux/SRE/02-filesystem/#2","text":"","title":"2.\u6587\u4ef6\u64cd\u4f5c\u547d\u4ee4"},{"location":"linux/SRE/02-filesystem/#21","text":"pwd\u547d\u4ee4\uff08print working directory\uff09: -L: \u663e\u793a\u94fe\u63a5\u8def\u5f84 -P\uff1a\u663e\u793a\u771f\u5b9e\u7269\u7406\u8def\u5f84","title":"2.1.\u663e\u793a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55"},{"location":"linux/SRE/02-filesystem/#22","text":"\u5bf9\u4e8e\u7edd\u5bf9\u8def\u5f84 /etc/firewalld/policies \uff0c\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u5f97\u5230\u8be5\u8def\u5f84\u7684\u57fa\u540d policies \u548c\u76ee\u5f55\u540d /etc/firewalld \u3002 basename /etc/firewalld/policies dirname /etc/firewalld/policies","title":"2.2.\u76f8\u5bf9\u548c\u7edd\u5bf9\u8def\u5f84"},{"location":"linux/SRE/02-filesystem/#23","text":". \u6307\u5f53\u524d\u76ee\u5f55\uff0c\u5373 pwd \u547d\u4ee4\u6240\u8fd4\u56de\u7684\u76ee\u5f55\u3002 .. \u6307\u5f53\u524d\u76ee\u5f55\u7684\u4e0a\u4e00\u7ea7\u76ee\u5f55\uff0c\u53ca\u5f53\u524d\u76ee\u5f55\u7684\u7236\u76ee\u5f55\u3002 \u5207\u6362\u81f3\u7236\u76ee\u5f55\uff1a cd .. \u5207\u6362\u81f3\u5f53\u524d\u7528\u6237\u4e3b\u76ee\u5f55\uff1a cd ~ \u5207\u6362\u81f3\u4e0a\u6b21\u5de5\u4f5c\u76ee\u5f55\uff1a cd - echo $PWD \uff1a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55 echo $OLDPWD \uff1a\u4e0a\u6b21\u5de5\u4f5c\u76ee\u5f55","title":"2.3.\u66f4\u6539\u76ee\u5f55"},{"location":"linux/SRE/02-filesystem/#24","text":"ls \u547d\u4ee4\uff1a -a \u663e\u793a\u6240\u6709\u6587\u4ef6\u53ca\u76ee\u5f55 (. \u5f00\u5934\u7684\u9690\u85cf\u6587\u4ef6\u4e5f\u4f1a\u5217\u51fa) -A \u540c -a \uff0c\u4f46\u4e0d\u5217\u51fa . (\u76ee\u524d\u76ee\u5f55) \u53ca .. (\u7236\u76ee\u5f55) -l \u9664\u6587\u4ef6\u540d\u79f0\u5916\uff0c\u4ea6\u5c06\u6587\u4ef6\u578b\u6001\u3001\u6743\u9650\u3001\u62e5\u6709\u8005\u3001\u6587\u4ef6\u5927\u5c0f\u7b49\u8d44\u8baf\u8be6\u7ec6\u5217\u51fa -r \u5c06\u6587\u4ef6\u4ee5\u76f8\u53cd\u6b21\u5e8f\u663e\u793a(\u539f\u5b9a\u4f9d\u82f1\u6587\u5b57\u6bcd\u6b21\u5e8f) -t \u5c06\u6587\u4ef6\u4f9d\u5efa\u7acb\u65f6\u95f4\u4e4b\u5148\u540e\u6b21\u5e8f\u5217\u51fa -F \u5728\u5217\u51fa\u7684\u6587\u4ef6\u540d\u79f0\u540e\u52a0\u4e00\u7b26\u53f7\uff1b\u4f8b\u5982\u53ef\u6267\u884c\u6863\u5219\u52a0 \"*\", \u76ee\u5f55\u5219\u52a0 \"/\" -R \u9012\u5f52\u5217\u51fa\u5b50\u76ee\u5f55 -S \u6309\u6587\u4ef6\u5927\u5c0f\u6392\u5e8f\uff0c\u4ece\u5927\u5230\u5c0f -1 \u6309\u4e00\u4e2a\u6587\u4ef6\u4e00\u884c\u5217\u51fa -t \u6309\u6587\u4ef6\u65f6\u95f4\u6392\u5e8f\uff0c\u6700\u65b0\u7684\u5728\u524d -U \u4e0d\u6392\u5e8f\u8f93\u51fa\uff0c\u6309\u76ee\u5f55\u5b58\u653e\u987a\u5e8f\u5217\u51fa -u \u914d\u5408 -lt \uff0c\u6309\u8bbf\u95ee\u65f6\u95f4\u6392\u5e8f\u5e76\u663e\u793a\uff1b\u914d\u5408 -l \uff0c\u663e\u793a\u8bbf\u95ee\u65f6\u95f4\u5e76\u6309\u540d\u79f0\u6392\u5e8f\uff1b \u5426\u5219\u6309\u8bbf\u95ee\u65f6\u95f4\u6392\u5e8f\uff0c\u6700\u65b0\u7684\u5728\u524d -X \u6309\u6587\u4ef6\u6269\u5c55\u540d\u5b57\u6bcd\u987a\u5e8f\u6392\u5e8f\u8f93\u51fa -F \u5bf9\u4e0d\u540c\u7c7b\u578b\u6587\u4ef6\u663e\u793a\u65f6\u9644\u52a0\u4e0d\u540c\u7684\u7b26\u53f7\uff0c * / = > @ | \u4e4b\u4e00 ls \u547d\u4ee4\u67e5\u770b\u4e0d\u540c\u6587\u4ef6\u662f\u7684\u989c\u8272\uff0c\u7531 /etc/DIR_COLORS \u548c\u53d8\u91cf @LS_COLORS \u5b9a\u4e49\u3002","title":"2.4.\u5217\u51fa\u76ee\u5f55\u5185\u5bb9"},{"location":"linux/SRE/02-filesystem/#25stat","text":"\u6bcf\u4e2a\u6587\u4ef6\u6709\u4e09\u4e2a\u65f6\u95f4\u6233\uff1a \u8bbf\u95ee\u65f6\u95f4 Access Time atime : \u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u3002 \u4fee\u6539\u65f6\u95f4 Modify Time mtime : \u6539\u53d8\u6587\u4ef6\u5185\u5bb9\uff08\u6570\u636e\uff09\u3002 \u6539\u53d8\u65f6\u95f4 Change Time ctime : \u5143\u6570\u636e\u53d1\u751f\u6539\u53d8\u3002 \u8bfb\u53d6\u4e09\u4e2a\u65f6\u95f4\u6233\u7684\u547d\u4ee4 stat \uff1a stat /etc/fstab \u8f93\u51fa\u7ed3\u679c\uff1a File: /etc/fstab Size: 927 Blocks: 8 IO Block: 4096 regular file Device: 30h/48d Inode: 263 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2022-10-31 10:26:34.987466959 +0800 Modify: 2022-06-24 14:50:24.387992912 +0800 Change: 2022-06-24 14:50:24.387992912 +0800 Birth: 2022-06-24 14:50:23.755992937 +0800","title":"2.5.\u6587\u4ef6\u72b6\u6001stat"},{"location":"linux/SRE/02-filesystem/#26","text":"\u547d\u4ee4 file \u68c0\u67e5\u6587\u4ef6\u7c7b\u578b\u3002 -b \uff1a\u5217\u51fa\u8fa8\u8bc6\u7ed3\u679c\u65f6\uff0c\u4e0d\u663e\u793a\u6587\u4ef6\u540d\u79f0\u3002 -c \uff1a\u8be6\u7ec6\u663e\u793a\u6307\u4ee4\u6267\u884c\u8fc7\u7a0b\uff0c\u4fbf\u4e8e\u6392\u9519\u6216\u5206\u6790\u7a0b\u5e8f\u6267\u884c\u7684\u60c5\u5f62\u3002 -f <\u540d\u79f0\u6587\u4ef6> \uff1a\u6307\u5b9a\u540d\u79f0\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u6587\u4ef6\u540d\u79f0\u65f6\uff0c\u8ba9file\u4f9d\u5e8f\u8fa8\u8bc6\u8fd9\u4e9b\u6587\u4ef6\uff0c\u683c\u5f0f\u4e3a\u6bcf\u5217\u4e00\u4e2a\u6587\u4ef6\u540d\u79f0\u3002 -L \uff1a \u76f4\u63a5\u663e\u793a\u7b26\u53f7\u8fde\u63a5\u6240\u6307\u5411\u7684\u6587\u4ef6\u7684\u7c7b\u522b\u3002 -v \uff1a \u663e\u793a\u7248\u672c\u4fe1\u606f\u3002 -z \uff1a \u5c1d\u8bd5\u53bb\u89e3\u8bfb\u538b\u7f29\u6587\u4ef6\u7684\u5185\u5bb9\u3002 \u7f16\u8f91\u6587\u4ef6 list.txt \u5305\u542b\u4e00\u4e0b\u5185\u5bb9\uff1a /etc/ /bin /etc/issue \u8fd0\u884c\u547d\u4ee4 file -f list.txt \uff0c\u7ed3\u679c\u5982\u4e0b\uff1a /etc/: directory /bin: directory /etc/issue: symbolic link to ../run/issue","title":"2.6.\u786e\u5b9a\u6587\u4ef6\u7c7b\u578b"},{"location":"linux/SRE/02-filesystem/#27","text":"iconv \u547d\u4ee4\u7528\u4e8e\u5c06\u4e00\u79cd\u7f16\u7801\u4e2d\u7684\u67d0\u4e9b\u6587\u672c\u8f6c\u6362\u4e3a\u53e6\u4e00\u79cd\u7f16\u7801\u3002 \u5982\u679c\u6ca1\u6709\u63d0\u4f9b\u8f93\u5165\u6587\u4ef6\uff0c\u5219\u5b83\u4ece\u6807\u51c6\u8f93\u5165\u4e2d\u8bfb\u53d6\u3002 \u540c\u6837\uff0c\u5982\u679c\u6ca1\u6709\u7ed9\u51fa\u8f93\u51fa\u6587\u4ef6\uff0c\u90a3\u4e48\u5b83\u4f1a\u5199\u5165\u6807\u51c6\u8f93\u51fa\u3002 \u5982\u679c\u6ca1\u6709\u63d0\u4f9b from-encoding \u6216 to-encoding \uff0c\u5219\u5b83\u4f7f\u7528\u5f53\u524d\u672c\u5730\u7684\u5b57\u7b26\u7f16\u7801\u3002 \u5c06\u6587\u672c\u4ece ISO 8859-15 \u5b57\u7b26\u7f16\u7801\u8f6c\u6362\u4e3a UTF-8\uff0c\u8bfb\u5165 input.txt \uff0c\u8f93\u51fa output.txt \u3002 iconv -f ISO-8859-15 -t UTF-8 < input.txt > output.txt \u4ece UTF-8 \u8f6c\u6362\u4e3a ASCII\uff0c\u5c3d\u53ef\u80fd\u8fdb\u884c\u97f3\u8bd1\uff08transliterating\uff09\uff1a echo abc \u00df \u03b1 \u20ac \u00e0\u1e03\u00e7 | iconv -f UTF-8 -t ASCII//TRANSLIT \u8fd0\u884c\u7ed3\u679c\uff1a abc ss ? EUR abc","title":"2.7.\u6587\u4ef6\u7f16\u7801\u8f6c\u6362"},{"location":"linux/SRE/02-filesystem/#28","text":"\u901a\u914d\u7b26\uff0c\u6307\u5305\u542b\u8fd9\u4e9b\u5b57\u7b26\u7684\u5b57\u7b26\u4e32 ? \uff1a\u8868\u793a\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26 * \uff1a\u8868\u793a\u4efb\u610f\u957f\u5ea6\u7684\u4efb\u610f\u5b57\u7b26 [] \uff1a\u5339\u914d\u6307\u5b9a\u8303\u56f4\u5185\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26 [abcd] \uff1a\u5339\u914dabcd\u4e2d\u7684\u4efb\u4f55\u4e00\u4e2a\u5b57\u7b26 [a-z] \uff1a\u5339\u914d\u8303\u56f4a\u5230z\u5185\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26 [!abcd] \uff1a\u4e0d\u5339\u914d\u62ec\u53f7\u91cc\u9762\u4efb\u4f55\u4e00\u4e2a\u5b57\u7b26 {} \uff1a\u8868\u793a\u751f\u6210\u5e8f\u5217\uff0c\u4ee5\u9017\u53f7\u5206\u5272\uff0c\u4e0d\u80fd\u6709\u7a7a\u683c \u793a\u4f8b\uff1a $ touch file_ { a..z } .txt $ touch file_ { A..Z } .txt $ ls file_a.txt file_C.txt file_f.txt file_H.txt file_k.txt file_M.txt file_p.txt file_R.txt file_u.txt file_W.txt file_z.txt file_A.txt file_d.txt file_F.txt file_i.txt file_K.txt file_n.txt file_P.txt file_s.txt file_U.txt file_x.txt file_Z.txt file_b.txt file_D.txt file_g.txt file_I.txt file_l.txt file_N.txt file_q.txt file_S.txt file_v.txt file_X.txt file_B.txt file_e.txt file_G.txt file_j.txt file_L.txt file_o.txt file_Q.txt file_t.txt file_V.txt file_y.txt file_c.txt file_E.txt file_h.txt file_J.txt file_m.txt file_O.txt file_r.txt file_T.txt file_w.txt file_Y.txt $ ls file_ [ a..d ] .* file_a.txt file_d.txt $ ls file_ [ a...d ] .* file_a.txt file_d.txt $ ls file_ [ ad ] .* file_a.txt file_d.txt $ ls file_ [ a-c ] .* file_a.txt file_A.txt file_b.txt file_B.txt file_c.txt $ ls file_ [ a-C ] .* file_a.txt file_A.txt file_b.txt file_B.txt file_c.txt file_C.txt $ ls file_ [ !d-W ] .* file_a.txt file_b.txt file_c.txt file_x.txt file_y.txt file_z.txt file_A.txt file_B.txt file_C.txt file_X.txt file_Y.txt file_Z.txt \u6bd4\u8f83\u6709\u65e0 * \u7684\u533a\u522b\uff1a $ ls -a * file_a.txt file_D.txt file_h.txt file_K.txt file_o.txt file_R.txt file_v.txt file_Y.txt file_A.txt file_e.txt file_H.txt file_l.txt file_O.txt file_s.txt file_V.txt file_z.txt file_b.txt file_E.txt file_i.txt file_L.txt file_p.txt file_S.txt file_w.txt file_Z.txt file_B.txt file_f.txt file_I.txt file_m.txt file_P.txt file_t.txt file_W.txt file_c.txt file_F.txt file_j.txt file_M.txt file_q.txt file_T.txt file_x.txt file_C.txt file_g.txt file_J.txt file_n.txt file_Q.txt file_u.txt file_X.txt file_d.txt file_G.txt file_k.txt file_N.txt file_r.txt file_U.txt file_y.txt $ ls -a . file_C.txt file_g.txt file_J.txt file_n.txt file_Q.txt file_u.txt file_X.txt .. file_d.txt file_G.txt file_k.txt file_N.txt file_r.txt file_U.txt file_y.txt file_a.txt file_D.txt file_h.txt file_K.txt file_o.txt file_R.txt file_v.txt file_Y.txt file_A.txt file_e.txt file_H.txt file_l.txt file_O.txt file_s.txt file_V.txt file_z.txt file_b.txt file_E.txt file_i.txt file_L.txt file_p.txt file_S.txt file_w.txt file_Z.txt file_B.txt file_f.txt file_I.txt file_m.txt file_P.txt file_t.txt file_W.txt file_c.txt file_F.txt file_j.txt file_M.txt file_q.txt file_T.txt file_x.txt","title":"2.8.\u901a\u914d\u7b26"},{"location":"linux/SRE/02-filesystem/#29","text":"[:alpha:] \uff1a\u8868\u793a\u6240\u6709\u7684\u5b57\u6bcd\uff08\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff09\uff0c\u6548\u679c\u540c [a-z] [:digit:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u6570\u5b57\uff0c\u6548\u679c\u540c [0-9] [:xdigit:] \uff1a\u8868\u793a\u5341\u516d\u8fdb\u5236\u6570\u5b57 [:lower:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5c0f\u5199\u5b57\u6bcd [:upper:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5927\u5199\u5b57\u6bcd [:alnum:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5b57\u6bcd\u6216\u6570\u5b57 [:blank:] \uff1a\u8868\u793a\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u548c\u5236\u8868\u7b26\uff09 [:space:] \uff1a\u8868\u793a\u5305\u62ec\u7a7a\u683c\u3001\u5236\u8868\u7b26\uff08\u6c34\u5e73\u548c\u5782\u76f4\uff09\u3001\u6362\u884c\u7b26\u3001\u56de\u8f66\u7b26\u7b49\u5404\u79cd\u7c7b\u578b\u7684\u7a7a\u767d\uff0c\u6bd4 [:blank:] \u8303\u56f4\u66f4\u5e7f [:cntrl:] \uff1a\u8868\u793a\u4e0d\u53ef\u6253\u5370\u7684\u63a7\u5236\u5b57\u7b26\uff08\u9000\u683c\u3001\u5220\u9664\u3001\u8b66\u94c3\u7b49\uff09 [:graph:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u7684\u975e\u7a7a\u767d\u5b57\u7b26 [:print:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u5b57\u7b26 [:punct:] \uff1a\u8868\u793a\u6807\u70b9\u7b26\u53f7 \u4e3e\u4f8b\uff1a ls -d [[:alpha:]] \u5373 ls -d [a-Z] \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u5355\u4e2a\u5b57\u6bcd\u7684\u76ee\u5f55\u548c\u6587\u4ef6 ls -d *[[:digit:]] \u5373 ls -d *[0-9] \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u4ee5\u6570\u5b57\u7ed3\u5c3e\u7684\u76ee\u5f55\u548c\u6587\u4ef6 ls [[:lower:]].txt \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u4ee5\u5355\u4e2a\u5c0f\u5199\u5b57\u6bcd\u4e3a\u540d\u7684.txt\u683c\u5f0f\u7684\u6587\u4ef6 ls -d [[:alnum:]] \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u5355\u4e2a\u5b57\u6bcd\uff08\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff09\u6216\u6570\u5b57\u4e3a\u540d\u7684\u76ee\u5f55\u6216\u6587\u4ef6","title":"2.9.\u5b57\u7b26\u96c6"},{"location":"linux/SRE/02-filesystem/#210","text":"| \uff1a\u7ba1\u9053\u7b26\uff0c\u6216\u8005\uff08\u6b63\u5219\uff09 > \uff1a\u8f93\u51fa\u91cd\u5b9a\u5411 >> \uff1a\u8f93\u51fa\u8ffd\u52a0\u91cd\u5b9a\u5411 < \uff1a\u8f93\u5165\u91cd\u5b9a\u5411 << \uff1a\u8ffd\u52a0\u8f93\u5165\u91cd\u5b9a\u5411 ~ \uff1a\u5f53\u524d\u7528\u6237\u5bb6\u76ee\u5f55 $() \uff1a\u5f15\u7528\u547d\u4ee4\u88ab\u6267\u884c\u540e\u7684\u7ed3\u679c $ \uff1a\u4ee5...\u7ed3\u5c3e\uff08\u6b63\u5219\uff09 ^ \uff1a\u4ee5...\u5f00\u5934\uff08\u6b63\u5219\uff09 * \uff1a\u5339\u914d\u5168\u90e8\u5b57\u7b26\uff0c\u901a\u914d\u7b26 ? \uff1a\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26\uff0c\u901a\u914d\u7b26 # \uff1a\u6ce8\u91ca & \uff1a\u8ba9\u7a0b\u5e8f\u6216\u811a\u672c\u5207\u6362\u5230\u540e\u53f0\u6267\u884c && \uff1a\u5e76\u4e14\uff0c\u540c\u65f6\u6210\u7acb [] \uff1a\u8868\u793a\u4e00\u4e2a\u8303\u56f4\uff08\u6b63\u5219\uff0c\u901a\u914d\u7b26\uff09 {} \uff1a\u4ea7\u751f\u4e00\u4e2a\u5e8f\u5217\uff08\u901a\u914d\u7b26\uff09 . \uff1a\u5f53\u524d\u76ee\u5f55\u7684\u786c\u94fe\u63a5 .. \uff1a\u4e0a\u7ea7\u76ee\u5f55\u7684\u786c\u94fe\u63a5","title":"2.10.\u7279\u6b8a\u7b26\u53f7"},{"location":"linux/SRE/02-filesystem/#211touch","text":"touch \u547d\u4ee4\u53ef\u4ee5\u521b\u5efa\u7a7a\u6587\u4ef6\uff0c\u4e5f\u53ef\u4ee5\u5237\u65b0\u6587\u4ef6\u65f6\u95f4\u3002\u53c2\u6570\u5982\u4e0b\uff1a -a \uff1a\u4ec5\u6539\u53d8 atime \u548c ctime -m \uff1a\u4ec5\u6539\u53d8 mtime \u548c ctime -t [[CC]YY]MMDDhhmm[.ss] \uff1a\u6307\u5b9a atime \u548c mtime -c \uff1a\u5982\u679c\u6587\u4ef6\u4e0d\u5b58\u5728\uff0c\u5219\u4e0d\u521b\u5efa $ touch file1 $ touch file2 $ ll -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 -rw-r--r--. 1 vagrant wheel 0 Nov 8 20 :28 file2 \u521b\u5efa\u6587\u4ef6file-non.log\uff0c\u5982\u679c\u4e0d\u5b58\u5728\u5219\u4e0d\u521b\u5efa\u3002 touch -c file-non.log \u66f4\u65b0 file1 \u7684\u65f6\u95f4\u548c file2 \u4e00\u81f4\u3002 $ touch -r file1 file2 $ ll -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 -rw-r--r--. 1 vagrant wheel 0 Nov 8 20 :49 file2 \u6307\u5b9a file2 \u7684\u65f6\u95f4\u3002 202210012135.25 \u4ee3\u8868 YYYYMMDDHHMM.SS \u3002 $ touch -t 202210012135 .25 file2 $ ll -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 -rw-r--r--. 1 vagrant wheel 0 Oct 1 21 :35 file2 $ stat file2 File: file2 Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: fd02h/64770d Inode: 140 Links: 1 Access: ( 0644 /-rw-r--r-- ) Uid: ( 1000 / vagrant ) Gid: ( 10 / wheel ) Context: unconfined_u:object_r:user_home_t:s0 Access: 2022 -10-01 21 :35:25.000000000 +0800 Modify: 2022 -10-01 21 :35:25.000000000 +0800 Change: 2022 -11-08 20 :56:18.306315887 +0800 Birth: 2022 -11-08 20 :28:37.809551441 +0800","title":"2.11.\u5237\u65b0\u6587\u4ef6\u65f6\u95f4touch"},{"location":"linux/SRE/02-filesystem/#212cp","text":"cp \u547d\u4ee4\uff1aCopy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY. \u5e38\u7528\u53c2\u6570\uff1a -a \uff1a\u5f52\u6863\uff0c\u76f8\u5f53\u4e8e -dR --preserv=all \u53c2\u6570\u7ec4\u5408\uff0c\u5e38\u7528\u4e8e\u5907\u4efd\u3002 -d \uff1a\u4e0d\u590d\u5236\u539f\u6587\u4ef6\uff0c\u53ea\u590d\u5236\u94fe\u63a5\u540d\u3002\u76f8\u5f53\u4e8e --no-dereference --preserve=links \u53c2\u6570\u7ec4\u5408\u3002 -f \uff1a\u8986\u76d6\u5df2\u7ecf\u5b58\u5728\u7684\u76ee\u6807\u6587\u4ef6\u3002 -i \uff1a\u8986\u76d6\u76ee\u6807\u6587\u4ef6\u4e4b\u524d\u7ed9\u51fa\u63d0\u793a\u3002 -p \uff1a\u9664\u590d\u5236\u6587\u4ef6\u7684\u5185\u5bb9\u5916\uff0c\u4e5f\u590d\u5236\u6587\u4ef6\u6743\u9650\uff0c\u65f6\u95f4\u6233\uff0c\u5c5e\u4e3b\u5c5e\u7ec4\u3002\u76f8\u5f53\u4e8e --preserve=mode,ownership,timestamps \u3002 -r, -R, --recursive \uff1a\u9012\u5f52\u590d\u5236\u76ee\u5f55\u6240\u5305\u542b\u7684\u5168\u90e8\u5185\u5bb9\u3002 -l \uff1a\u4e0d\u590d\u5236\u6587\u4ef6\uff0c\u53ea\u662f\u751f\u6210\u786c\u94fe\u63a5\u6587\u4ef6\u3002 \u53c2\u6570 --preserv \u53ef\u9009\u9879\uff1a mode\uff1a\u6743\u9650 ownership\uff1a\u5c5e\u4e3b\u5c5e\u7ec4 timestamp links xattr context all \u521b\u5efa\u6d4b\u8bd5\u76ee\u5f55\u3002 cd ~ mkdir test \u5bf9\u6bd4\u53c2\u6570 -p \u7684\u5dee\u522b\u3002 $ cp /etc/issue ~/test/issue1 $ cp -p /etc/issue ~/test/issue1 $ sudo cp /etc/issue ~/test/issue3 $ sudo cp -p /etc/issue ~/test/issue4 $ ll ~/test -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 issue1 -rw-r--r--. 1 vagrant wheel 23 Jul 21 01 :10 issue2 -rw-r--r--. 1 root root 23 Nov 8 22 :43 issue3 -rw-r--r--. 1 root root 23 Jul 21 01 :10 issue4 $ ll /etc/issue -rw-r--r--. 1 root root 23 Jul 21 01 :10 /etc/issue \u5bf9\u6bd4\u53c2\u6570 -r \u3002 $ sudo cp /etc/sysconfig/ ~/test cp: -r not specified ; omitting directory '/etc/sysconfig/' $ sudo cp -r /etc/sysconfig/ ~/test $ tree -L 2 ~/test /home/vagrant/test \u251c\u2500\u2500 issue1 \u251c\u2500\u2500 issue2 \u251c\u2500\u2500 issue3 \u251c\u2500\u2500 issue4 \u2514\u2500\u2500 sysconfig \u251c\u2500\u2500 anaconda \u251c\u2500\u2500 atd \u251c\u2500\u2500 chronyd \u251c\u2500\u2500 cpupower \u251c\u2500\u2500 crond \u251c\u2500\u2500 firewalld \u251c\u2500\u2500 irqbalance \u251c\u2500\u2500 kdump \u251c\u2500\u2500 kernel \u251c\u2500\u2500 man-db \u251c\u2500\u2500 network \u251c\u2500\u2500 network-scripts \u251c\u2500\u2500 nftables.conf \u251c\u2500\u2500 raid-check \u251c\u2500\u2500 rsyslog \u251c\u2500\u2500 run-parts \u251c\u2500\u2500 samba \u251c\u2500\u2500 selinux -> ../selinux/config \u251c\u2500\u2500 smartmontools \u2514\u2500\u2500 sshd \u53c2\u6570 -b \uff0c\u5982\u679c\u76ee\u6807\u6587\u4ef6\u5b58\u5728\uff0c\u590d\u5236\u524d\u5148\u5c06\u539f\u6587\u4ef6\u590d\u5236\u5e76\u4ee5 ~ \u7ed3\u5c3e\u3002 $ ll /etc/motd -rw-r--r--. 1 root root 0 Jun 23 2020 /etc/motd $ ll ~/test/issue1 -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 /home/vagrant/test/issue1 $ cp -b /etc/motd ~/test/issue $ cp -b /etc/motd ~/test/issue1 $ ll ~/test -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :00 issue -rw-r--r--. 1 vagrant wheel 0 Nov 8 22 :57 issue1 -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 issue1~ -rw-r--r--. 1 vagrant wheel 23 Jul 21 01 :10 issue2 -rw-r--r--. 1 root root 23 Nov 8 22 :43 issue3 -rw-r--r--. 1 root root 23 Jul 21 01 :10 issue4 drwxr-xr-x. 3 root root 4096 Nov 8 22 :49 sysconfig \u53c2\u6570 --backup=numbered \u4f1a\u5728\u590d\u5236\u539f\u6587\u4ef6\u65f6\u52a0\u4e0a\u6570\u5b57\u5e8f\u53f7\uff0c\u5e8f\u53f71\u4ee3\u8868\u539f\u59cb\u7684\u6587\u4ef6\u3002 $ cp --backup = numbered /etc/motd ~/test/issue2 $ cp --backup = numbered /etc/motd ~/test/issue2 $ cp --backup = numbered /etc/motd ~/test/issue2 $ ll ~/test -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :00 issue -rw-r--r--. 1 vagrant wheel 0 Nov 8 22 :57 issue1 -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 issue1~ -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :09 issue2 -rw-r--r--. 1 vagrant wheel 23 Jul 21 01 :10 issue2.~1~ -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :09 issue2.~2~ -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :09 issue2.~3~ -rw-r--r--. 1 root root 23 Nov 8 22 :43 issue3 -rw-r--r--. 1 root root 23 Jul 21 01 :10 issue4 drwxr-xr-x. 3 root root 4096 Nov 8 22 :49 sysconfig","title":"2.12.\u590d\u5236\u6587\u4ef6\u548c\u76ee\u5f55cp"},{"location":"linux/SRE/02-filesystem/#213mv","text":"mv \u547d\u4ee4\u3002Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY. \u5e38\u7528\u53c2\u6570\uff1a -v \uff1a\u663e\u793a\u547d\u4ee4\u6267\u884c\u7684\u4fe1\u606f\u3002 -i \uff1a\u4ea4\u4e92\u5f0f\uff0c\u6bd4\u5982\uff0c\u91cd\u540d\u8986\u76d6\u65f6\u4f1a\u63d0\u5347\u662f\u5426\u786e\u8ba4\u3002 -b \uff1a\u8986\u76d6\u65f6\u521b\u5efa\u5907\u4efd\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u79fb\u52a8\u6587\u4ef6\u5c06\u4f1a\u8986\u76d6\u5df2\u5b58\u5728\u7684\u76ee\u6807\u6587\u4ef6\u3002 \u79fb\u52a8\u591a\u4e2a\u6587\u4ef6\u5230\u67d0\u4e2a\u76ee\u5f55\u3002 mv file1 file2 file3 ~/dest mv file* ~/dest \u79fb\u52a8\u76ee\u5f55\u3002 mv ~/test ~/dest/new/one/ \u91cd\u547d\u540d\u6587\u4ef6\u548c\u76ee\u5f55\u3002 mv file1 file2 mv ~/test ~/dest","title":"2.13.\u79fb\u52a8\u6587\u4ef6\u548c\u76ee\u5f55mv"},{"location":"linux/SRE/02-filesystem/#214rename","text":"rename \u547d\u4ee4\u3002\u5206\u4e3aperl\u7248\u672c\u548cC\u8bed\u8a00\u7248\u672c\u3002 \u533a\u5206\u65b9\u6cd5: rename --version \u3002\u5982\u679c\u8fd4\u56de\u7ed3\u679c\u4e2d\u5305\u542b util-linux \uff0c\u8bf4\u660e\u662fC\u8bed\u8a00\u7248\u672c, \u53cd\u4e4b\u662fPerl\u7248\u672c\u3002 openSUSE\u548cRocy\u662fC\u8bed\u8a00\u7248\u672c\uff0cUbuntu\u662fPerl\u7248\u672c\u3002 \u4e3e\u4f8b\uff1a\u4fee\u6539\u5f53\u524d\u76ee\u5f55\u6240\u6709\u6269\u5c55\u540d\u4e3a s \u7684\u6587\u4ef6\u6539\u4e3a\u6269\u5c55\u540d\u4e3a gz \u3002 $ touch file { 1 ..3 } .s $ rename -v '.s' '.gz' *.s $ rename -v \".s\" \".gz\" *.s ` file1.txt ' -> `file1.html' ` file2.txt ' -> `file2.html' ` file3.txt ' -> `file3.html' \u5728Ubuntu\u4e0a\u5b8c\u6210\u540c\u6837\u4efb\u52a1\uff0c\u5219\u9700\u8981\u4f7f\u7528\u6b63\u5219\u3002 rename -v \"s/s/gz/g\" *.s","title":"2.14.\u91cd\u547d\u540d\u6587\u4ef6\u548c\u76ee\u5f55rename"},{"location":"linux/SRE/02-filesystem/#215rm","text":"rm \u547d\u4ee4\u3002\u5efa\u8bae\u4f7f\u7528 mv \u547d\u4ee4\u4ee3\u66ff rm \u547d\u4ee4\u3002","title":"2.15.\u5220\u9664\u6587\u4ef6rm"},{"location":"linux/SRE/02-filesystem/#216","text":"\u521b\u5efa\u76ee\u5f55\uff1a mkdir \u5220\u9664\u7a7a\u76ee\u5f55\uff1a rmdir \u5220\u9664\u975e\u7a7a\u76ee\u5f55\uff1a rm -r \u663e\u793a\u76ee\u5f55\u6811\uff1a tree","title":"2.16.\u76ee\u5f55\u64cd\u4f5c\u547d\u4ee4"},{"location":"linux/SRE/02-filesystem/#217","text":"\u663e\u793a /etc \u76ee\u5f55\u4e0b\u6240\u6709\u4ee5 l \u5f00\u5934\uff0c\u4ee5\u4e00\u4e2a\u5c0f\u5199\u5b57\u6bcd\u7ed3\u5c3e\uff0c\u4e14\u4e2d\u95f4\u51fa\u73b0\u81f3\u5c11\u4e00\u4f4d\u6570\u5b57\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls -d /etc/l* [ 0 -9 ] * [ a-z ] ls -d /etc/l* [[ :digit: ]] * [[ :lower: ]] \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/lam4you sudo mkdir /etc/lam5you \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/lam4you sudo rm -rf /etc/lam5you \u663e\u793a /etc \u76ee\u5f55\u4e0b\u4ee5\u4efb\u610f\u4e00\u4f4d\u6570\u5b57\u5f00\u5934\uff0c\u4e14\u4ee5\u975e\u6570\u5b57\u7ed3\u5c3e\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ 0 -9 ] * [ !0-9 ] ls /etc/ [[ :digit: ]] * [ ^ [ :digit: ]] \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/5am4yo. sudo mkdir /etc/5am5yo. \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/5am4yo. sudo rm -rf /etc/5am5yo. \u663e\u793a /etc \u76ee\u5f55\u4e0b\u4ee5\u975e\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u9762\u8ddf\u4e86\u4e00\u4e2a\u5b57\u6bcd\u53ca\u5176\u5b83\u4efb\u610f\u957f\u5ea6\u4efb\u610f\u5b57\u7b26\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ !a-zA-Z ][ a-zA-Z ] * ls /etc/ [ ^ [ :alpha: ]][[ :alpha: ]] * \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/5Ato3 sudo mkdir /etc/6dog6 \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/5Ato3 sudo rm -rf /etc/6dog6 \u663e\u793a /etc \u76ee\u5f55\u4e0b\uff0c\u6240\u6709\u4ee5 rc \u5f00\u5934\uff0c\u5e76\u540e\u9762\u662f0-6\u4e4b\u95f4\u7684\u6570\u5b57\uff0c\u5176\u5b83\u4e3a\u4efb\u610f\u5b57\u7b26\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/rc [ 0 -6 ] * \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/rc5come sudo mkdir /etc/rc0123 \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/rc5come sudo rm -rf /etc/rc0123 \u663e\u793a /etc \u76ee\u5f55\u4e0b\uff0c\u6240\u6709\u4ee5 .conf \u7ed3\u5c3e\uff0c\u4e14\u4ee5 m \u3001 n \u3001 r \u3001 p \u5f00\u5934\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ mnrp ] *.conf \u53ea\u663e\u793a /root \u4e0b\u7684\u9690\u85cf\u6587\u4ef6\u548c\u76ee\u5f55\u5217\u8868\u3002 ls .* \u53ea\u663e\u793a/etc\u4e0b\u975e\u9690\u85cf\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ ^. ] */ \u5c06 /etc \u76ee\u5f55\u4e0b\u6240\u6709\u6587\u4ef6\uff0c\u5907\u4efd\u5230 ~/test/ \u76ee\u5f55\u4e0b\uff0c\u5e76\u8981\u6c42\u5b50\u76ee\u5f55\u683c\u5f0f\u4e3a backupYYYY-mm-dd \uff0c\u5907\u4efd\u8fc7\u7a0b\u53ef\u89c1\u3002 sudo cp -av /etc/ ~/test/backup ` date +%F ` sudo cp -av /etc/ ~/test/backup ` date +%F_%H-%M-%S ` \u521b\u5efa\u76ee\u5f55 ~/testdir/dir1/x \uff0c ~/testdir/dir1/y \uff0c ~/testdir/dir1/x/a \uff0c ~/testdir/dir1/x/b \uff0c ~/testdir/dir1/y/a \uff0c ~/testdir/dir1/y/b \u3002 $ mkdir -p ~/testdir/dir1/ { x,y } / { a,b } $ tree ~/testdir/dir1/ /home/vagrant/testdir/dir1/ \u251c\u2500\u2500 x \u2502 \u251c\u2500\u2500 a \u2502 \u2514\u2500\u2500 b \u2514\u2500\u2500 y \u251c\u2500\u2500 a \u2514\u2500\u2500 b \u521b\u5efa\u76ee\u5f55 ~/testdir/dir2/x \uff0c ~/testdir/dir2/y \uff0c ~/testdir/dir2/x/a \uff0c ~/testdir/dir2/x/b \u3002 $ mkdir -p ~/testdir/dir2/ { x/ { a,b } ,y } $ tree ~/testdir/dir2/ /home/vagrant/testdir/dir2/ \u251c\u2500\u2500 x \u2502 \u251c\u2500\u2500 a \u2502 \u2514\u2500\u2500 b \u2514\u2500\u2500 y \u521b\u5efa\u76ee\u5f55 ~/testdir/dir3 \u3001 ~/testdir/dir4 \u3001 ~/testdir/dir5 \u3001 ~/testdir/dir5/dir6 \u3001 ~/testdir/dir5/dir7 \u3002 $ mkdir -p ~/testdir/dir { 3 ,4,5/dir { 6 ,7 }} $ tree ~/testdir /home/vagrant/testdir \u251c\u2500\u2500 dir1 \u2502 \u251c\u2500\u2500 x \u2502 \u2502 \u251c\u2500\u2500 a \u2502 \u2502 \u2514\u2500\u2500 b \u2502 \u2514\u2500\u2500 y \u2502 \u251c\u2500\u2500 a \u2502 \u2514\u2500\u2500 b \u251c\u2500\u2500 dir2 \u2502 \u251c\u2500\u2500 x \u2502 \u2502 \u251c\u2500\u2500 a \u2502 \u2502 \u2514\u2500\u2500 b \u2502 \u2514\u2500\u2500 y \u251c\u2500\u2500 dir3 \u251c\u2500\u2500 dir4 \u2514\u2500\u2500 dir5 \u251c\u2500\u2500 dir6 \u2514\u2500\u2500 dir7","title":"2.17.\u7ec3\u4e60"},{"location":"linux/SRE/02-filesystem/#3","text":"\u666e\u901a\u6587\u4ef6\uff08Normal Files\uff09 ASCII \u6587\u672c\u6587\u4ef6 \u53ef\u6267\u884c\u6587\u4ef6 \u56fe\u5f62\u6587\u4ef6 \u76ee\u5f55\uff08Directories\uff09 \u7ec4\u7ec7\u89c4\u5212\u78c1\u76d8\u4e0a\u7684\u6587\u4ef6 \u5305\u542b\u6587\u4ef6\u548c\u5b50\u76ee\u5f55 \u5b9e\u73b0\u5206\u5c42\u6587\u4ef6\u7cfb\u7edf \u94fe\u63a5\uff08Links\uff09 \u786c\u94fe\u63a5\uff08Hard links\uff09 \u78c1\u76d8\u4e0a\u6587\u4ef6\u7684\u8f85\u52a9\u6587\u4ef6\u540d \u591a\u4e2a\u6587\u4ef6\u540d\u5f15\u7528\u5355\u4e2a inode \u5f15\u7528\u7684\u6587\u4ef6\u5fc5\u987b\u5b58\u5728\u4e8e\u540c\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u4e2d \u7b26\u53f7\u94fe\u63a5\uff08Symbolic links\uff09 \u5bf9\u78c1\u76d8\u4e0a\u5176\u4ed6\u6587\u4ef6\u7684\u5f15\u7528 inode \u5305\u542b\u5bf9\u53e6\u4e00\u4e2a\u6587\u4ef6\u540d\u7684\u5f15\u7528 \u88ab\u5f15\u7528\u7684\u6587\u4ef6\u53ef\u4ee5\u5b58\u5728\u4e8e\u540c\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u4e2d\uff0c\u4e5f\u53ef\u4ee5\u5b58\u5728\u4e8e\u5176\u4ed6\u6587\u4ef6\u7cfb\u7edf\u4e2d \u7b26\u53f7\u94fe\u63a5\u53ef\u4ee5\u5f15\u7528\u4e0d\u5b58\u5728\u7684\u6587\u4ef6\uff08\u65ad\u5f00\u7684\u94fe\u63a5\uff09 \u5957\u63a5\u5b57Sockets - \u7528\u4e8e\u8fdb\u7a0b\u4e4b\u95f4\u7684\u53cc\u5411\u901a\u4fe1\u3002 \u7ba1\u9053\uff08Pipes\uff09(FIFOs) - \u7528\u4e8e\u4ece\u4e00\u4e2a\u8fdb\u7a0b\u5230\u53e6\u4e00\u4e2a\u8fdb\u7a0b\u7684\u5355\u5411\u901a\u4fe1\u3002 \u5757\u8bbe\u5907\uff08Block Devices\uff09 \u5b57\u7b26\u8bbe\u5907\uff08Character Devices\uff09","title":"3.\u4e03\u79cd\u6587\u4ef6\u7c7b\u578b"},{"location":"linux/SRE/02-filesystem/#31inode","text":"\u6587\u4ef6\u50a8\u5b58\u5728\u786c\u76d8\u4e0a\uff0c\u786c\u76d8\u7684\u6700\u5c0f\u5b58\u50a8\u5355\u4f4d\u53eb\u505a\u201c\u6247\u533a\u201d\uff08Sector\uff09\u3002\u6bcf\u4e2a\u6247\u533a\u50a8\u5b58512\u5b57\u8282\uff08\u76f8\u5f53\u4e8e0.5KB\uff09\u3002 \u64cd\u4f5c\u7cfb\u7edf\u8bfb\u53d6\u786c\u76d8\u7684\u65f6\u5019\uff0c\u4e0d\u662f\u4e00\u4e2a\u4e00\u4e2a\u6247\u533a\u8bfb\u53d6\uff0c\u800c\u662f\u4e00\u6b21\u6027\u8fde\u7eed\u8bfb\u53d6\u591a\u4e2a\u6247\u533a\uff0c\u6211\u4eec\u79f0\u4e3a\u8bfb\u53d6\u4e00\u4e2a\u201c\u5757\u201d\uff08block\uff09\u3002 \u5e38\u89c1\u7684block\u7684\u5927\u5c0f\u662f4KB\uff08\u8fde\u7eed\u516b\u4e2asector\u7ec4\u6210\u4e00\u4e2ablock\uff09\u3002 \u591a\u4e2a\u6247\u533a\u7ec4\u6210\u7684block\u662f\u6587\u4ef6\u5b58\u53d6\u7684*\u6700\u5c0f\u5355\u4f4d*\u3002 \u6587\u4ef6\u6570\u636e\u50a8\u5b58\u5728block\u4e2d\uff0c\u6587\u4ef6\u7684\u5143\u4fe1\u606f\uff0c\u6bd4\u5982\u6587\u4ef6\u7684\u521b\u5efa\u8005\u3001\u521b\u5efa\u65e5\u671f\u3001\u6587\u5927\u5c0f\u7b49\uff0c\u5b58\u50a8\u5728inode\uff0c\u5373\u201c\u7d22\u5f15\u8282\u70b9\u201d\u3002 \u6bcf\u4e00\u4e2a\u6587\u4ef6\u90fd\u6709\u5bf9\u5e94\u7684inode\uff0c\u91cc\u9762\u5305\u542b\u4e86\u4e0e\u8be5\u6587\u4ef6\u6709\u5173\u7684\u4e00\u4e9b\u4fe1\u606f\u3002\u6ce8\u610f\uff0c\u9664\u4e86\u6587\u4ef6\u540d\u4ee5\u5916\u7684\u5176\u5b83\u6587\u4ef6\u4fe1\u606f\uff0c\u90fd\u5b58\u5728inode\u4e4b\u4e2d\u3002 inode\u5305\u542b\u6587\u4ef6\u7684\u5143\u4fe1\u606f\u4e3b\u8981\u6709\uff1a \u6587\u4ef6\u7684\u5b57\u8282\u6570 \u6587\u4ef6\u62e5\u6709\u8005\u7684 User ID \u6587\u4ef6\u7684 Group ID \u6587\u4ef6\u7684\u8bfb\u3001\u5199\u3001\u6267\u884c\u6743\u9650 \u6587\u4ef6\u7684\u65f6\u95f4\u6233\uff0c\u5171\u6709\u4e09\u4e2a\uff1actime\u6307inode\u4e0a\u4e00\u6b21\u53d8\u52a8\u7684\u65f6\u95f4\uff0cmtime\u6307\u6587\u4ef6\u5185\u5bb9\u4e0a\u4e00\u6b21\u53d8\u52a8\u7684\u65f6\u95f4\uff0catime\u6307\u6587\u4ef6\u4e0a\u4e00\u6b21\u6253\u5f00\u7684\u65f6\u95f4\u3002 \u94fe\u63a5\u6570\uff0c\u5373\u6709\u591a\u5c11\u6587\u4ef6\u540d\u6307\u5411\u8fd9\u4e2ainode \u6587\u4ef6\u6570\u636eblock\u7684\u4f4d\u7f6e \u67e5\u770binode\u4fe1\u606f\u7684\u547d\u4ee4 stat \uff1a $ stat file1 File: file1 Size: 5 Blocks: 8 IO Block: 4096 regular file Device: fd02h/64770d Inode: 143 Links: 1 Access: ( 0644 /-rw-r--r-- ) Uid: ( 1000 / vagrant ) Gid: ( 10 / wheel ) Context: unconfined_u:object_r:user_home_t:s0 Access: 2022 -11-08 20 :49:26.019678244 +0800 Modify: 2022 -11-08 20 :49:26.019678244 +0800 Change: 2022 -11-08 20 :49:26.028678455 +0800 Birth: 2022 -11-08 20 :49:26.019678244 +0800 \u683c\u5f0f\u5316\u786c\u76d8\u65f6\uff0c\u64cd\u4f5c\u7cfb\u7edf\u4f1a\u81ea\u52a8\u5c06\u786c\u76d8\u5206\u6210\u4e24\u4e2a\u533a\u57df\u3002\u4e00\u4e2a\u662f\u6570\u636e\u533a\uff0c\u5b58\u653e\u6587\u4ef6\u6570\u636e\u3002\u53e6\u4e00\u4e2a\u662finode\u533a\uff08inode table\uff09\uff0c\u5b58\u653einode\u6240\u5305\u542b\u7684\u6587\u4ef6\u7684\u5143\u4fe1\u606f\u3002 \u6bcf\u4e2ainode\u8282\u70b9\u7684\u5927\u5c0f\uff0c\u4e00\u822c\u662f128\u5b57\u8282\u6216256\u5b57\u8282\u3002inode\u8282\u70b9\u7684\u603b\u6570\uff0c\u5728\u683c\u5f0f\u5316\u65f6\u5c31\u786e\u5b9a\u4e86\uff0c\u4e00\u822c\u662f\u6bcf1KB\u6216\u6bcf2KB\u5c31\u8bbe\u7f6e\u4e00\u4e2ainode\u3002 \u5047\u5b9a\u4e00\u57571GB\u7684\u786c\u76d8\uff0c\u5982\u679c\u6bcf\u4e2ainode\u8282\u70b9\u7684\u5927\u5c0f\u4e3a128\u5b57\u8282\uff0c\u4e14\u6bcf1KB\u5c31\u8bbe\u7f6e\u4e00\u4e2ainode\uff0c\u5219inode table\u7684\u5927\u5c0f\u5c31\u4f1a\u8fbe\u5230128MB\uff0c\u5360\u6574\u5757\u786c\u76d8\u768412.8%\u3002 \u901a\u8fc7 df \u547d\u4ee4\u67e5\u770b\u6bcf\u4e2a\u786c\u76d8\u5206\u533a\u7684inode\u603b\u6570\u548c\u5df2\u7ecf\u4f7f\u7528\u7684\u6570\u91cf\u3002 \u7531\u4e8e\u6bcf\u4e2a\u6587\u4ef6\u90fd\u5fc5\u987b\u6709\u4e00\u4e2ainode\uff0c\u56e0\u6b64\u6709\u53ef\u80fd\u53d1\u751finode\u5df2\u7ecf\u7528\u5149\uff0c\u4f46\u662f\u786c\u76d8\u8fd8\u672a\u5b58\u6ee1\u7684\u60c5\u51b5\uff0c\u4e5f\u5c31\u65e0\u6cd5\u5728\u786c\u76d8\u4e0a\u521b\u5efa\u65b0\u6587\u4ef6\u3002 $ df -i Filesystem Inodes IUsed IFree IUse% Mounted on tmpfs 497897 872 497025 1 % /run /dev/mapper/ubuntu--vg-ubuntu--lv 3211264 81473 3129791 3 % / tmpfs 497897 1 497896 1 % /dev/shm tmpfs 497897 3 497894 1 % /run/lock /dev/sda2 131072 316 130756 1 % /boot tmpfs 99579 25 99554 1 % /run/user/1000 \u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u67e5\u770b\u6bcf\u4e2ainode\u8282\u70b9\u7684\u5927\u5c0f\uff1a $ sudo dumpe2fs -h /dev/sda2 | grep \"Inode size\" dumpe2fs 1 .46.5 ( 30 -Dec-2021 ) Inode size: 256 \u6bcf\u4e2ainode\u90fd\u6709\u4e00\u4e2a\u53f7\u7801\uff0c\u64cd\u4f5c\u7cfb\u7edf\u7528inode\u53f7\u7801\u6765\u8bc6\u522b\u4e0d\u540c\u7684\u6587\u4ef6\uff0c\u6ce8\u610f\uff0c\u4e0d\u662f\u901a\u8fc7\u6587\u4ef6\u540d\u6765\u8bc6\u522b\u4e0d\u540c\u6587\u4ef6\u3002\u4ece\u64cd\u4f5c\u7cfb\u7edf\u89d2\u5ea6\u770b\uff0c\u6587\u4ef6\u540d\u53ea\u662finode\u53f7\u7801\u5bf9\u4e00\u4e2a\u522b\u540d\u3002 \u7528\u6237\u901a\u8fc7\u6587\u4ef6\u540d\uff0c\u6253\u5f00\u67d0\u4e2a\u6587\u4ef6\u7684\u8fc7\u7a0b\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5206\u6210\u4e09\u6b65\u5b8c\u6210\uff1a \u9996\u5148\uff0c\u7cfb\u7edf\u627e\u5230\u8fd9\u4e2a\u6587\u4ef6\u540d\u5bf9\u5e94\u7684inode\u53f7\u7801\u3002 \u5176\u6b21\uff0c\u901a\u8fc7inode\u53f7\uff0c\u83b7\u53d6inode\u4fe1\u606f\u3002 \u7b2c\u4e09\uff0c\u901a\u8fc7inode\u4fe1\u606f\uff0c\u627e\u5230\u6587\u4ef6\u6570\u636e\u6240\u5728\u7684block\uff0c\u8bfb\u51fa\u6570\u636e\u3002 \u901a\u8fc7 ls -i \u547d\u4ee4\uff0c\u53ef\u4ee5\u5f97\u5230\u6587\u4ef6\u5bf9\u5e94\u7684inode\u53f7\uff1a $ ls -i file1 143 file1 \u76ee\u5f55\uff08directory\uff09\u4e5f\u662f\u4e00\u79cd\u6587\u4ef6\u3002\u6253\u5f00\u76ee\u5f55\uff0c\u5b9e\u9645\u4e0a\u5c31\u662f\u6253\u5f00\u76ee\u5f55\u6587\u4ef6\u3002 \u76ee\u5f55\u6587\u4ef6\u7684\u7ed3\u6784\u662f\u7531\u4e00\u4e2a\u5305\u542b\u4e00\u7cfb\u5217\u76ee\u5f55\u9879\uff08dirent\uff09\u7684\u5217\u8868\u7ec4\u6210\u3002 \u6bcf\u4e2a\u76ee\u5f55\u9879\u7531\u4e24\u90e8\u5206\u7ec4\u6210\uff1a\u6240\u5305\u542b\u6587\u4ef6\u7684\u6587\u4ef6\u540d\uff0c\u4ee5\u53ca\u8be5\u6587\u4ef6\u540d\u5bf9\u5e94\u7684inode\u53f7\u3002 \u547d\u4ee4 ls -i \u5217\u51fa\u6574\u4e2a\u76ee\u5f55\u6587\u4ef6\uff0c\u5373\u6587\u4ef6\u540d\u548cinode\u53f7\uff1a $ ls -i 143 file1 140 file2 139 test $ ls -il 143 -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 140 -rw-r--r--. 1 vagrant wheel 0 Oct 1 21 :35 file2 139 drwxr-xr-x. 5 vagrant wheel 4096 Nov 9 22 :00 test","title":"3.1.inode\u7ed3\u6784"},{"location":"linux/SRE/02-filesystem/#32","text":"\u786c\u94fe\u63a5 \uff08Hard links\uff09\u786c\u94fe\u63a5\u662f\u5b58\u50a8\u5377\u4e0a\u6587\u4ef6\u7684\u76ee\u5f55\u5f15\u7528\u6216\u6307\u9488\u3002 \u6587\u4ef6\u540d\u662f\u5b58\u50a8\u5728\u76ee\u5f55\u7ed3\u6784\u4e2d\u7684\u6807\u7b7e\uff0c\u76ee\u5f55\u7ed3\u6784\u6307\u5411\u6587\u4ef6\u6570\u636e\u3002 \u56e0\u6b64\uff0c\u53ef\u4ee5\u5c06\u591a\u4e2a\u6587\u4ef6\u540d\u4e0e\u540c\u4e00\u6587\u4ef6\u5173\u8054\u3002 \u901a\u8fc7\u4e0d\u540c\u7684\u6587\u4ef6\u540d\u8bbf\u95ee\u65f6\uff0c\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u662f\u9488\u5bf9\u6e90\u6587\u4ef6\u6570\u636e\u3002 \u7b26\u53f7\u94fe\u63a5 \uff08Symbolic links\uff09: \u7b26\u53f7\u94fe\u63a5\u5305\u542b\u4e00\u4e2a\u6587\u672c\u5b57\u7b26\u4e32\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5c06\u5176\u89e3\u91ca\u4e3a\u53e6\u4e00\u4e2a\u6587\u4ef6\u6216\u76ee\u5f55\u3002 \u5b83\u672c\u8eab\u5c31\u662f\u4e00\u4e2a\u6587\u4ef6\uff0c\u53ef\u4ee5\u72ec\u7acb\u4e8e\u76ee\u6807\u800c\u5b58\u5728\u3002 \u5982\u679c\u5220\u9664\u4e86\u7b26\u53f7\u94fe\u63a5\uff0c\u5219\u5176\u76ee\u6807\u6587\u4ef6\u6216\u76ee\u5f55\u4e0d\u53d7\u5f71\u54cd\u3002 \u5982\u679c\u79fb\u52a8\uff0c\u91cd\u547d\u540d\u6216\u5220\u9664\u76ee\u6807\u6587\u4ef6\u6216\u76ee\u5f55\uff0c\u5219\u7528\u4e8e\u6307\u5411\u5b83\u7684\u4efb\u4f55\u7b26\u53f7\u94fe\u63a5\u5c06\u7ee7\u7eed\u5b58\u5728\uff0c\u4f46\u6307\u5411\u7684\u662f\u4e00\u4e2a\u4e0d\u5b58\u5728\u7684\u6587\u4ef6\u3002 \u4ec5\u5f53\u6587\u4ef6\u548c\u94fe\u63a5\u6587\u4ef6\u4f4d\u4e8e\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\uff08\u5728\u540c\u4e00\u5206\u533a\u4e0a\uff09\u65f6\uff0c\u624d\u80fd\u4f7f\u7528\u786c\u94fe\u63a5\uff0c\u56e0\u4e3ainode\u7f16\u53f7\u5728\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\u4e2d\u4ec5\u662f\u552f\u4e00\u7684\u3002 \u53ef\u4ee5\u4f7f\u7528 ln \u547d\u4ee4\u521b\u5efa\u786c\u94fe\u63a5\uff0c\u6307\u5411\u5df2\u5b58\u5728\u6587\u4ef6\u7684inode\uff0c\u53ef\u4ee5\u901a\u8fc7\u6587\u4ef6\u540d\u6216\u8005\u786c\u94fe\u63a5\u540d\u8bbf\u95ee\u6587\u4ef6\u3002 \u53ef\u4ee5\u4f7f\u7528 ln -s \u9009\u9879\u521b\u5efa\u7b26\u53f7\u94fe\u63a5\u3002 \u4e00\u4e2a\u7b26\u53f7\u94fe\u63a5\u4f1a\u88ab\u5206\u914d\u4e00\u4e2a\u5355\u72ec\u7684inode\uff0c\u5e76\u6307\u5411\u4e00\u4e2a\u6587\u4ef6\uff0c\u6240\u4ee5\u53ef\u4ee5\u660e\u663e\u533a\u5206\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\u548c\u5b9e\u9645\u6587\u4ef6\u3002 \u6587\u4ef6\u7cfb\u7edf\u672c\u8d28\u4e0a\u662f\u4e00\u4e2a\u7528\u4e8e\u8ddf\u8e2a\u5206\u533a\u5377\u4e2d\u7684\u6587\u4ef6\u7684\u6570\u636e\u5e93\u3002 \u5bf9\u4e8e\u666e\u901a\u6587\u4ef6\uff0c\u5206\u914d\u6570\u636e\u5757\u4ee5\u5b58\u50a8\u6587\u4ef6\u7684\u6570\u636e\uff0c\u5206\u914dinode\u4ee5\u6307\u5411\u6570\u636e\u5757\u4ee5\u53ca\u5b58\u50a8\u5173\u4e8e\u6587\u4ef6\u7684\u5143\u6570\u636e\uff0c\u7136\u540e\u5c06\u6587\u4ef6\u540d\u5206\u914d\u7ed9inode\u3002 \u786c\u94fe\u63a5\u662f\u4e0e\u73b0\u6709inode\u5173\u8054\u7684\u8f85\u52a9\u6587\u4ef6\u540d\u3002 \u5bf9\u4e8e\u7b26\u53f7\u94fe\u63a5\uff0c\u5c06\u4e3a\u65b0\u7684inode\u5206\u914d\u4e00\u4e2a\u4e0e\u4e4b\u5173\u8054\u7684\u65b0\u6587\u4ef6\u540d\uff0c\u4f46inode\u5f15\u7528\u53e6\u4e00\u4e2a\u6587\u4ef6\u540d\u800c\u4e0d\u662f\u5f15\u7528\u6570\u636e\u5757\u3002 \u67e5\u770b\u6587\u4ef6\u540d\u548cinode\u4e4b\u95f4\u5173\u7cfb\u7684\u4e00\u4e2a\u65b9\u6cd5\u662f\u4f7f\u7528 ls -il \u547d\u4ee4\u3002inode\u7684\u5178\u578b\u5927\u5c0f\u4e3a128\u4f4d\uff0c\u6570\u636e\u5757\u7684\u5927\u5c0f\u8303\u56f4\u53ef\u4ee5\u662f1k\uff0c2k\uff0c4k\u6216\u66f4\u5927\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u3002 \u8f6f\u8fde\u63a5\u53ef\u4ee5\u9488\u5bf9\u76ee\u5f55\uff0c\u786c\u8fde\u63a5\u53ea\u80fd\u9488\u5bf9\u6587\u4ef6\u3002 \u786c\u94fe\u63a5\u76f8\u5f53\u4e8e\u589e\u52a0\u4e86\u4e00\u4e2a\u767b\u8bb0\u9879\uff0c\u4f7f\u5f97\u539f\u6765\u7684\u6587\u4ef6\u591a\u4e86\u4e00\u4e2a\u540d\u5b57\uff0c\u81f3\u4e8einode\u90fd\u6ca1\u53d8\u3002\u6240\u8c13\u7684\u767b\u8bb0\u9879\u5176\u5b9e\u662f\u76ee\u5f55\u6587\u4ef6\u4e2d\u7684\u4e00\u4e2a\u6761\u76ee(\u76ee\u5f55\u9879)\uff0c\u4f7f\u7528hard link \u662f\u8ba9\u591a\u4e2a\u4e0d\u540c\u7684\u76ee\u5f55\u9879\u6307\u5411\u540c\u4e00\u4e2a\u6587\u4ef6\u7684inode\uff0c\u6ca1\u6709\u591a\u4f59\u7684\u5185\u5bb9\u9700\u8981\u5b58\u50a8\u5728\u78c1\u76d8\u6247\u533a\u4e2d\uff0c\u6240\u4ee5hardlink\u4e0d\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 \u7b26\u53f7\u94fe\u63a5\u6709\u5355\u72ec\u7684inode\uff0c\u5728inode\u4e2d\u5b58\u653e\u53e6\u4e00\u4e2a\u6587\u4ef6\u7684\u8def\u5f84\u800c\u4e0d\u662f\u6587\u4ef6\u6570\u636e\uff0c\u6240\u4ee5\u7b26\u53f7\u94fe\u63a5\u4f1a\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 \u7279\u5f81 \u786c\u94fe\u63a5 \u7b26\u53f7\u94fe\u63a5 \u672c\u8d28 \u540c\u4e00\u4e2a\u6587\u4ef6 \u4e0d\u662f\u540c\u4e00\u4e2a\u6587\u4ef6 \u8de8\u8bbe\u5907 \u4e0d\u652f\u6301 \u652f\u6301 inode \u76f8\u540c \u4e0d\u540c \u94fe\u63a5\u6570 \u521b\u5efa\u786c\u94fe\u63a5\uff0c\u94fe\u63a5\u6570\u4f1a\u589e\u52a0\uff0c\u5220\u9664\u5219\u51cf\u5c11 \u521b\u5efa\u6216\u5220\u9664\uff0c\u94fe\u63a5\u6570\u90fd\u4e0d\u53d8 \u6587\u4ef6\u5939 \u4e0d\u652f\u6301 \u652f\u6301 \u76f8\u5bf9\u8def\u5f84 \u539f\u59cb\u6587\u4ef6\u7684\u76f8\u5bf9\u8def\u5f84\u662f\u76f8\u5bf9\u4e8e\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55 \u539f\u59cb\u6587\u4ef6\u7684\u76f8\u5bf9\u8def\u5f84\u662f\u76f8\u5bf9\u4e8e\u94fe\u63a5\u6587\u4ef6\u7684\u76f8\u5bf9\u8def\u5f84 \u5220\u9664\u6e90\u6587\u4ef6 \u53ea\u662f\u94fe\u63a5\u6570\u51cf\u5c11\uff0c\u94fe\u63a5\u6587\u4ef6\u8bbf\u95ee\u4e0d\u53d7\u5f71\u54cd \u94fe\u63a5\u6587\u4ef6\u5c06\u65e0\u6cd5\u8bbf\u95ee \u6587\u4ef6\u7c7b\u578b \u548c\u6e90\u6587\u4ef6\u76f8\u540c \u94fe\u63a5\u6587\u4ef6\uff0c\u548c\u6e90\u6587\u4ef6\u65e0\u5173 \u6587\u4ef6\u5927\u5c0f \u548c\u6e90\u6587\u4ef6\u76f8\u540c \u6e90\u6587\u4ef6\u7684\u8def\u5f84\u7684\u957f\u5ea6","title":"3.2.\u94fe\u63a5\u7c7b\u578b"},{"location":"linux/SRE/02-filesystem/#33","text":"\u8bbe\u5907\u6587\u4ef6 \uff08Device File\uff09\u8868\u793a\u786c\u4ef6\uff08\u7f51\u5361\u9664\u5916\uff09\u3002 \u6bcf\u4e2a\u786c\u4ef6\u90fd\u7531\u4e00\u4e2a\u8bbe\u5907\u6587\u4ef6\u8868\u793a\u3002 \u7f51\u5361\u662f\u63a5\u53e3\u3002 \u8bbe\u5907\u6587\u4ef6\u628a\u5185\u6838\u9a71\u52a8\u548c\u7269\u7406\u786c\u4ef6\u8bbe\u5907\u8fde\u63a5\u8d77\u6765\u3002 \u5185\u6838\u9a71\u52a8\u7a0b\u5e8f\u901a\u8fc7\u5bf9\u8bbe\u5907\u6587\u4ef6\u8fdb\u884c\u8bfb\u5199\uff08\u6b63\u786e\u7684\u683c\u5f0f\uff09\u6765\u5b9e\u73b0\u5bf9\u786c\u4ef6\u7684\u8bfb\u5199\u3002 \u7c7b\u578b\uff1a \u5757\u8bbe\u5907\uff08Block Devices\uff09\uff1a\u5757\u8bbe\u5907\uff08\u901a\u5e38\uff09\u5728512\u5b57\u8282\u7684\u5927\u5757\u4e2d\u8bfb\u53d6/\u5199\u5165\u4fe1\u606f\u3002 \u5b57\u7b26\u8bbe\u5907\uff08Character Devices\uff09\uff1a\u5b57\u7b26\u8bbe\u5907\u4ee5\u5b57\u7b26\u65b9\u5f0f\u8bfb\u53d6/\u5199\u5165\u4fe1\u606f\u3002 \u5b57\u7b26\u8bbe\u5907\u76f4\u63a5\u63d0\u4f9b\u5bf9\u786c\u4ef6\u8bbe\u5907\u7684\u65e0\u7f13\u51b2\u8bbf\u95ee\u3002 \u6709\u65f6\u79f0\u4e3a\u88f8\u8bbe\u5907\uff08raw devices\uff09\u3002\uff08\u6ce8\u610f\uff1a\u88f8\u8bbe\u5907\u88ab\u89c6\u4e3a\u5b57\u7b26\u8bbe\u5907\uff0c\u4e0d\u662f\u5757\u8bbe\u5907\uff09 \u901a\u8fc7\u8f85\u4ee5\u4e0d\u540c\u9009\u9879\uff0c\u53ef\u4ee5\u5e7f\u6cdb\u800c\u591a\u6837\u5730\u5e94\u7528\u548c\u4f7f\u7528\u5b57\u7b26\u8bbe\u5907\u3002 \u5f53\u5185\u6838\u53d1\u73b0\u8bbe\u5907\u65f6\u7531\u64cd\u4f5c\u7cfb\u7edf udev \u81ea\u52a8\u521b\u5efa\u3002","title":"3.3.\u8bbe\u5907\u6587\u4ef6"},{"location":"linux/SRE/02-filesystem/#34","text":"\u76ee\u6807\uff1a\u4ee5Rocky 9\u4e3a\u4f8b\u3002 \u67e5\u770b\u8f6f/\u786c\u94fe\u63a5\u6587\u4ef6\u7684\u7279\u5f81\u3002 \u67e5\u770b\u76ee\u5f55\u7ed3\u6784\u3002 \u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u5f97\u5230\u5f53\u524d\u7cfb\u7edf\u76842\u7ea7\u76ee\u5f55\u7684\u7ed3\u6784\u3002 tree -L 2 -d / \u521b\u5efa\u7ec3\u4e60\u76ee\u5f55\u3002 mkdir data mkdir -p data/typelink cd data \u521b\u5efa\u786c\u94fe\u63a5\u3002\u6ce8\u610f\uff1a file \u3001 hardlinkfile1 \u3001 hardlinkfile2 \u6587\u4ef6\u7684\u94fe\u63a5\u4f4d\u7f6e\u7684\u6570\u503c\u7684\u53d8\u5316) echo \"it's original file\" > file ln file hardlinkfile1 ln -s file symlinkfile1 ln -s file symlinkfile2 \u6267\u884c ls -l \u547d\u4ee4\u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u7ed3\u679c\uff1a -rw-r--r--. 2 vagrant wheel 19 Nov 1 10 :42 file -rw-r--r--. 2 vagrant wheel 19 Nov 1 10 :42 hardlinkfile1 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file \u521b\u5efa\u53e6\u5916\u4e00\u4e2a\u786c\u94fe\u63a5\u3002 ln file hardlinkfile2 \u6267\u884c ls -l \u547d\u4ee4\u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u7ed3\u679c\uff1a -rw-r--r--. 3 vagrant wheel 19 Nov 1 10 :42 file -rw-r--r--. 3 vagrant wheel 19 Nov 1 10 :42 hardlinkfile1 -rw-r--r--. 3 vagrant wheel 19 Nov 1 10 :42 hardlinkfile2 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file \u4fee\u6539 file \u6587\u4ef6\u7684\u5185\u5bb9\u3002 echo \"add oneline\" >> file \u901a\u8fc7\u547d\u4ee4 cat file \u67e5\u770b\u5f53\u524d file \u7684\u5185\u5bb9\u3002 it ' s original file add oneline \u901a\u8fc7\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u53ef\u4ee5\u770b\u5230\u6240\u4ee5\u8f6f/\u786c\u94fe\u63a5\u6587\u4ef6\u5185\u5bb9\u90fd\u66f4\u65b0\u4e86\uff0c\u548c file \u6587\u4ef6\u66f4\u65b0\u540e\u7684\u5185\u5bb9\u4fdd\u6301\u4e00\u81f4\u3002 cat hardlinkfile1 cat hardlinkfile2 cat symlinkfile1 cat symlinkfile2 \u5bf9\u6587\u4ef6 symlinkfile1 \u518d\u521b\u5efa\u65b0\u7684\u8f6f\u8fde\u63a5\u3002 ln -s symlinkfile1 symlinkfile1-1 \u901a\u8fc7\u547d\u4ee4 ls -il \u67e5\u770b\u73b0\u5728\u7684\u76ee\u5f55\u4fe1\u606f\u3002 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 file 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile1 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile2 67274681 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file 67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov 1 11 :20 symlinkfile1-1 -> symlinkfile1 67274682 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file \u8bfb\u53d6\u8f6f\u94fe\u63a5\u6587\u4ef6\u7684\u6e90\u6587\u4ef6\u4fe1\u606f readlink symlinkfile1 readlink symlinkfile2 \u6ce8\u610f\uff0c\u5bf9\u4e8e symlinkfile1-1 \u7684\u60c5\u51b5\u6709\u4e9b\u4e0d\u540c\u3002 readlink symlinkfile1-1 \u4e0a\u9762\u547d\u4ee4\u8fd4\u56de\u7ed3\u679c symlinkfile1 \u4ecd\u7136\u662f\u4e00\u4e2a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\u3002\u901a\u8fc7 readlink -f \u53ef\u4ee5\u76f4\u63a5\u5b9a\u4f4d\u771f\u6b63\u7684\u6e90\u6587\u4ef6\u3002 readlink -f symlinkfile1-1 \u4e0a\u9762\u7684\u8fd4\u56de\u7ed3\u679c /data/linktype/file \u662f symlinkfile1-1 \u771f\u6b63\u7684\u6e90\u6587\u4ef6\u3002 \u663e\u793a data \u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\uff1a cd ~ tree ./data \u8fd0\u884c\u7ed3\u679c\uff1a ./data \u251c\u2500\u2500 file \u251c\u2500\u2500 hardlinkfile1 \u251c\u2500\u2500 hardlinkfile2 \u251c\u2500\u2500 symlinkfile1 -> file \u251c\u2500\u2500 symlinkfile1-1 -> symlinkfile1 \u251c\u2500\u2500 symlinkfile2 -> file \u2514\u2500\u2500 typelink \u53ea\u663e\u793a data \u76ee\u5f55\u4e0b\u7684\u5b50\u76ee\u5f55\uff1a tree -d ./data \u8fd0\u884c\u7ed3\u679c\uff1a ./data \u2514\u2500\u2500 typelink \u663e\u793a data \u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\uff0c\u5305\u542b\u5168\u76ee\u5f55\uff1a tree -f ./data \u8fd0\u884c\u7ed3\u679c\uff1a ./data \u251c\u2500\u2500 ./data/file \u251c\u2500\u2500 ./data/hardlinkfile1 \u251c\u2500\u2500 ./data/hardlinkfile2 \u251c\u2500\u2500 ./data/symlinkfile1 -> file \u251c\u2500\u2500 ./data/symlinkfile1-1 -> symlinkfile1 \u251c\u2500\u2500 ./data/symlinkfile2 -> file \u2514\u2500\u2500 ./data/typelink","title":"3.4.\u7ec3\u4e60"},{"location":"linux/SRE/02-filesystem/#4","text":"\u6267\u884c\u547d\u4ee4 ls -ihl \uff0c\u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\uff08Rocky 9\uff09\u3002 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 file 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile1 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile2 67274681 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file 67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov 1 11 :20 symlinkfile1-1 -> symlinkfile1 67274682 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file 33555262 drwxr-xr-x. 2 vagrant wheel 6 Nov 1 11 :30 typelink \u4ee5 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11:14 file \u4e3a\u4f8b\uff1a 67274680 : inode \u7d22\u5f15\u8282\u70b9\u7f16\u53f7\u3002 -rw-r--r-- \uff1a\u6587\u4ef6\u7c7b\u578b\u53ca\u6743\u9650 - \uff1a\u6587\u4ef6\u7c7b\u578b\uff0c\u4f8b\u5b50\u4e2d\u51fa\u73b0\u4e86\u4e09\u79cd\uff0c - \uff0c l \u548c d \u3002 - \uff1a\u666e\u901a\u6587\u4ef6 d \uff1a\u76ee\u5f55 l \uff1a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\uff08link\uff09 b \uff1a\u5757\u8bbe\u5907\uff08block\uff09 c \uff1a\u5b57\u7b26\u8bbe\u5907\uff08character\uff09 p \uff1a\u7ba1\u9053\u6587\u4ef6\uff08pipe\uff09 s \uff1a\u5957\u63a5\u5b57\u6587\u4ef6\uff08socket\uff09 rw-r--r-- \uff1a\u6587\u4ef6\u6743\u9650\uff0c\u4ece\u5de6\u5230\u53f3\u4f9d\u6b21\u4e3a\uff1a rw- \uff1a\u6587\u4ef6\u5c5e\u4e3b\u6743\u9650\uff0c\u4f8b\u5b50\u4e2d\u662f vagrant \u3002 r-- \uff1a\u6587\u4ef6\u5c5e\u7ec4\u7684\u6743\u9650\uff0c\u4f8b\u5b50\u4e2d\u662f wheel \u3002 r-- \uff1a\u5176\u4ed6\u7ec4\u7684\u6743\u9650\u3002 . \uff1a\u8fd9\u4e2a\u70b9\u8868\u793a\u6587\u4ef6\u5e26\u6709SELinux\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\uff08SELinux Contexts\uff09\u3002\u5173\u95edSELinux\uff0c\u65b0\u521b\u5efa\u7684\u6587\u4ef6\u5c31\u4e0d\u4f1a\u518d\u6709\u8fd9\u4e2a\u70b9\u4e86\u3002\u4f46\u662f\uff0c\u4ee5\u524d\u521b\u5efa\u7684\u6587\u4ef6\u672c\u6765\u6709\u8fd9\u4e2a\u70b9\u7684\u8fd8\u4f1a\u663e\u793a\u8fd9\u4e2a\u70b9\uff08\u867d\u7136SELinux\u4e0d\u8d77\u4f5c\u7528\u4e86\uff09\u3002 3 \uff1a\u786c\u94fe\u63a5\u6570\uff0c\u4f8b\u5b50\u4e2d file \u548c hardlinkfile1 \u548c hardlinkfile2 \u4e4b\u95f4\u662f\u786c\u94fe\u63a5\uff0c\u6240\u4ee5\u8fd9\u4e09\u4e2a\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u90fd\u662f 3 \u3002 vagrant \uff1a\u6587\u4ef6\u5c5e\u4e3b wheel \uff1a\u6587\u4ef6\u5c5e\u7ec4 31 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u5927\u5c0f Nov 1 11:14 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u521b\u5efa\u65e5\u671f\u548c\u65f6\u95f4 file \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u540d\u79f0 \u4e0b\u9762\u662f\u547d\u4ee4 ls -ihl \u5728openSUSE\u548cUbuntu\u4e0a\u7684\u663e\u793a\u7ed3\u679c\u3002 $ ls -ihl 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 file 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile1 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile2 233648 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile1 -> file 233650 lrwxrwxrwx 1 vagrant wheel 12 Nov 1 15 :52 symlinkfile1-1 -> symlinkfile1 233649 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile2 -> file 233646 drwxr-xr-x 1 vagrant wheel 0 Nov 1 15 :51 typelink","title":"4.\u6587\u4ef6\u5c5e\u6027\u8bf4\u660e"},{"location":"linux/SRE/02-filesystem/#5","text":"\u6807\u51c6\u8f93\u5165\u8f93\u51fa\uff0c\u5373I/O\uff0cI/O\u7684I\u662fInput\uff0cO\u662foutput\u3002 I\uff1a\u4ece\u5916\u90e8\u8bbe\u5907\u8f93\u5165\u5230\u5185\u5b58 O\uff1a\u4ece\u5185\u5b58\u8f93\u51fa\u5230\u5916\u90e8\u8bbe\u5907 \u6807\u51c6\u8f93\u5165\u548c\u6807\u51c6\u8f93\u51fa\u662f\u7528\u4e8eIO\u7684\uff0c\u5b83\u4eec\u5c5e\u4e8e\u5916\u90e8\u8bbe\u5907\uff08\u903b\u8f91\u4e0a\u7684\u5916\u90e8\u8bbe\u5907\uff09\uff0c\u4e0d\u662f\u5185\u5b58\u3002 linux\u4e2d\u4e00\u5207\u8bbe\u5907\u7686\u662f\u6587\u4ef6\uff01\u56e0\u6b64\u6807\u51c6\u8f93\u5165\u548c\u8f93\u51fa\u672c\u8d28\u5c31\u662f\u6587\u4ef6\uff0c\u5916\u90e8\u8bbe\u5907\u4ee5\u6587\u4ef6\u5f62\u5f0f\u8868\u73b0\u3002 \u5728Linux\u7cfb\u7edf\u4e2d\uff0c\u6807\u51c6\u8f93\u5165\u548c\u6807\u51c6\u8f93\u51fa\u5bf9\u5e94\u7684\u6587\u4ef6\u662f /dev/stdin \u548c /dev/stdout \u8fd9\u4e24\u4e2a\u6587\u4ef6\u3002 \u4ece\u6807\u51c6\u8f93\u5165\u8bfb\uff0c\u4ece\u903b\u8f91\u4e0a\u8bb2\uff0c\u5c31\u662f\u6253\u5f00 /dev/stdin \u8fd9\u4e2a\u6587\u4ef6\uff0c\u5e76\u8bfb\u5165\u6587\u4ef6\u5185\u5bb9\u3002 \u8f93\u51fa\u5230\u6807\u51c6\u8f93\u51fa\uff0c\u4ece\u903b\u8f91\u4e0a\u8bb2\uff0c\u5c31\u662f\u6253\u5f00 /dev/stdout \u8fd9\u4e2a\u6587\u4ef6\uff0c\u5e76\u628a\u5185\u5bb9\u8f93\u51fa\u5230\u8fd9\u4e2a\u6587\u4ef6\u91cc\u53bb\u3002 \u8fd9\u91cc\u5f3a\u8c03\u7684\u662f\u201c\u903b\u8f91\u4e0a\u201d\uff0c\u56e0\u4e3a /dev/stdin \u548c /dev/stdout \u8fd92\u4e2a\u6587\u4ef6\u672c\u8eab\u4e0d\u662f\u8bbe\u5907\u6587\u4ef6\u3002Linux\u4e2d\u8bbe\u5907\u662f\u6587\u4ef6\uff0c\u4f46\u662f\u6587\u4ef6\u4e0d\u4e00\u5b9a\u662f\u8bbe\u5907\u3002 \u56e0\u6b64\uff0c\u64cd\u4f5c /dev/stdin \u548c/dev/stdout`\u8fd92\u4e2a\u6587\u4ef6\uff0c\u5b9e\u9645\u4e0a\u662f\u64cd\u4f5c\u4e24\u4e2a\u6587\u4ef6\u5b58\u653e\u5730\u5740\u5bf9\u5e94\u7684\u8bbe\u5907\u6587\u4ef6\u3002 \u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u770b\u5230\u6807\u51c6\u8f93\u5165\u8f93\u51fa\u6587\u4ef6\u7684\u7279\u70b9\uff0c\u4ed6\u4eec\u867d\u7136\u5728 /dev \u76ee\u5f55\u4e0b\uff0c\u90fd\u662f\u4ee5 l \u5f00\u5934\u7684\u94fe\u63a5\u6587\u4ef6\uff0c\u6307\u5411\u7684\u662f\u53e6\u4e00\u4e2a\u6587\u4ef6\u7684\u5730\u5740\u3002 $ ls -l /dev/std* lrwxrwxrwx 1 root root 15 Nov 13 10 :39 /dev/stderr -> /proc/self/fd/2 lrwxrwxrwx 1 root root 15 Nov 13 10 :39 /dev/stdin -> /proc/self/fd/0 lrwxrwxrwx 1 root root 15 Nov 13 10 :39 /dev/stdout -> /proc/self/fd/1 # Rocky $ ll /proc/self/fd/ lrwx------. 1 vagrant wheel 64 Nov 13 22 :38 0 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 22 :38 1 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 22 :38 2 -> /dev/pts/0 lr-x------. 1 vagrant wheel 64 Nov 13 22 :38 3 -> /proc/1702/fd # Ubuntu $ ll /proc/self/fd/ lrwx------ 1 vagrant sudo 64 Nov 13 14 :38 0 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 14 :38 1 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 14 :38 2 -> /dev/pts/0 lr-x------ 1 vagrant sudo 64 Nov 13 14 :38 3 -> /proc/2062/fd/ # openSUSE $ ll /proc/self/fd/* ls: cannot access '/proc/self/fd/255' : No such file or directory ls: cannot access '/proc/self/fd/3' : No such file or directory lrwx------ 1 vagrant wheel 64 Nov 13 22 :37 /proc/self/fd/0 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 22 :37 /proc/self/fd/1 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 22 :37 /proc/self/fd/2 -> /dev/pts/0 Linux\u8fdb\u7a0b\u9ed8\u8ba4\u4f1a\u6253\u5f00\u7684\u4e09\u4e2a\u6587\u4ef6\uff1a \u6807\u51c6\u8f93\u5165 /dev/stdin \uff0c\u63cf\u8ff0\u7b26\u4e3a 0\uff0c\u9ed8\u8ba4\u662f\u952e\u76d8\u8f93\u5165\u3002 \u6807\u51c6\u8f93\u51fa /dev/stdout \uff0c\u63cf\u8ff0\u7b26\u4e3a 1\uff0c\u9ed8\u8ba4\u662f\u8f93\u51fa\u5230\u5c4f\u5e55\u3002 \u6807\u51c6\u8f93\u51fa /dev/stderr \uff0c\u63cf\u8ff0\u7b26\u4e3a 2\uff0c\u9ed8\u8ba4\u662f\u8f93\u51fa\u5230\u5c4f\u5e55\u3002 \u4ee5Rocky\u4e3a\u4f8b\uff0c\u521b\u5efa file.py \u6587\u4ef6\u3002 $ cat > file.py < test.txt \u8fd0\u884c file.py \u7a0b\u5e8f\u3002 python3 file.py \u6253\u5f00\u65b0\u7684\u7ec8\u7aef\u7a97\u53e3\uff0c\u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u5f97\u5230python3\u8fd9\u4e2a\u7a0b\u5e8f\u8fd0\u884c\u7684process ID\u3002\u5176\u4e2d\u53ef\u4ee5\u770b\u5230\u6709\u4e00\u4e2a\u6765\u81ea\u6587\u4ef6test.txt\u88ab\u7a0b\u5e8ffile.py\u6253\u5f00\uff08\u8f93\u5165\uff09\u3002 $ pidof python3 1739 788 $ sudo ls -l /proc/788/fd/ lr-x------. 1 root root 64 Nov 13 23 :00 0 -> /dev/null l-wx------. 1 root root 64 Nov 13 23 :00 1 -> /dev/null lrwx------. 1 root root 64 Nov 13 23 :00 10 -> 'socket:[24677]' lrwx------. 1 root root 64 Nov 13 23 :00 11 -> 'socket:[24678]' l-wx------. 1 root root 64 Nov 13 23 :00 2 -> /dev/null l-wx------. 1 root root 64 Nov 13 10 :41 3 -> /var/log/firewalld lrwx------. 1 root root 64 Nov 13 23 :00 4 -> 'socket:[23421]' lrwx------. 1 root root 64 Nov 13 23 :00 5 -> 'anon_inode:[eventfd]' lrwx------. 1 root root 64 Nov 13 23 :00 6 -> 'socket:[24586]' lr-x------. 1 root root 64 Nov 13 23 :00 7 -> anon_inode:inotify lrwx------. 1 root root 64 Nov 13 23 :00 8 -> 'anon_inode:[eventfd]' lrwx------. 1 root root 64 Nov 13 23 :00 9 -> '/memfd:libffi (deleted)' $ sudo ls -l /proc/1739/fd/ lrwx------. 1 vagrant wheel 64 Nov 13 23 :00 0 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 23 :00 1 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 23 :00 2 -> /dev/pts/0 lr-x------. 1 vagrant wheel 64 Nov 13 23 :00 3 -> /home/vagrant/test.txt \u5728Ubuntu\u4e2d\u8fd0\u884c file.py \u7a0b\u5e8f\uff0cpidof\u4f1a\u53d6\u5f973\u4e2aprocess IDs\u3002 $ pidof python3 2128 924 873 $ sudo ls -l /proc/2128/fd/ lrwx------ 1 vagrant sudo 64 Nov 13 15 :10 0 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 15 :10 1 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 15 :10 2 -> /dev/pts/0 lr-x------ 1 vagrant sudo 64 Nov 13 15 :10 3 -> /home/vagrant/test.txt $ sudo ls -l /proc/924/fd/ lr-x------ 1 root root 64 Nov 13 15 :11 0 -> /dev/null lrwx------ 1 root root 64 Nov 13 15 :11 1 -> 'socket:[31593]' lrwx------ 1 root root 64 Nov 13 15 :11 2 -> 'socket:[31593]' l-wx------ 1 root root 64 Nov 13 02 :40 3 -> /var/log/unattended-upgrades/unattended-upgrades-shutdown.log lrwx------ 1 root root 64 Nov 13 15 :11 4 -> 'socket:[31652]' lrwx------ 1 root root 64 Nov 13 15 :11 5 -> 'anon_inode:[eventfd]' lrwx------ 1 root root 64 Nov 13 15 :11 6 -> 'anon_inode:[eventfd]' lrwx------ 1 root root 64 Nov 13 15 :11 7 -> 'socket:[31657]' l-wx------ 1 root root 64 Nov 13 15 :11 8 -> /run/systemd/inhibit/1.ref lrwx------ 1 root root 64 Nov 13 15 :11 9 -> 'socket:[31658]' $ sudo ls -l /proc/873/fd/ lr-x------ 1 root root 64 Nov 13 15 :11 0 -> /dev/null lrwx------ 1 root root 64 Nov 13 15 :11 1 -> 'socket:[31412]' lrwx------ 1 root root 64 Nov 13 15 :11 2 -> 'socket:[31412]' lrwx------ 1 root root 64 Nov 13 02 :40 3 -> 'socket:[31650]' lrwx------ 1 root root 64 Nov 13 15 :11 4 -> 'anon_inode:[eventfd]' lrwx------ 1 root root 64 Nov 13 15 :11 5 -> 'socket:[31663]' lrwx------ 1 root root 64 Nov 13 15 :11 6 -> 'socket:[31664]' openSUSE\u9700\u8981\u5b89\u88c5\u5305 sysvinit-tools \u624d\u80fd\u4f7f\u7528 pidof \u547d\u4ee4\u3002 sudo zypper in sysvinit-tools \u7531\u4e8eopenSUSE\u4e2dpidof python3\u53ea\u8fd4\u56de\u4e00\u4e2aprocess ID\uff0c\u6240\u4ee5\u53ef\u4ee5\u7b80\u5316\u547d\u4ee4\u884c\u5f97\u5230process ID\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 $ sudo ls -l /proc/ ` pidof python3 ` /fd/ lrwx------ 1 vagrant wheel 64 Nov 13 23 :21 0 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 23 :21 1 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 23 :21 2 -> /dev/pts/0 lr-x------ 1 vagrant wheel 64 Nov 13 23 :21 3 -> /home/vagrant/test.txt \u53c2\u8003\uff1a \u5f53\u952e\u76d8\u548c\u9f20\u6807\u7b49\u8bbe\u5907\u901a\u8fc7\u4e32\u53e3\u76f4\u63a5\u8fde\u63a5\u5230\u8ba1\u7b97\u673a\u65f6\uff0c\u8fd9\u79cd\u8fde\u63a5\u79f0\u4e3aTTY\u3002 \u4f2a\u7ec8\u7aefpseudoterminal\uff08\u7f29\u5199\u4e3a\u201cpty\u201d\uff09\u662f\u4e00\u5bf9\u63d0\u4f9b\u53cc\u5411\u901a\u4fe1\u901a\u9053\u7684\u865a\u62df\u5b57\u7b26\u8bbe\u5907\u3002 \u901a\u9053\u7684\u4e00\u7aef\u79f0\u4e3a\u4e3b\u7aefmaster\uff1b \u53e6\u4e00\u7aef\u79f0\u4e3a\u4ece\u7aefslave\u3002 /dev/pts \u8868\u793a\u4e0e\u4f2a\u7ec8\u7aefpseudoterminal\u7684\u4e3b\u7aefmaster\u6216\u4ece\u7aefslave\u76f8\u5173\u7684master\u6587\u4ef6\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5c06\u5176\u4fdd\u5b58\u4e3a /dev/ptmx \u6587\u4ef6\u3002 telnet \u548c ssh \u7b49\u7a0b\u5e8f\u80fd\u591f\u4eff \u7aef\u7528\u6237> \u4e0e\u5b83\u4eec\u7684\u4ea4\u4e92\uff0c\u867d\u7136\u672c\u8d28\u4e0a\u662f\u4e0e\u6587\u4ef6 /dev/ptmx \u8fdb\u884c\u4ea4\u4e92\uff0c\u4f46\u5448\u73b0\u7ed9\u7528\u6237\u7684\u5374\u662f\u597d\u50cf\u8fd0\u884c\u5728\u771f\u6b63\u7684\u7ec8\u7aef\u7a97\u53e3\u4e00\u6837\uff0c\u4ece\u7aef\u7684\u6587\u4ef6\u662f\u4e3b\u7aef\u7684\u8f93\u5165\u3002 \u4f2a\u7ec8\u7aef\u8fdb\u7a0b\u5728Linux\u4e2d\u88ab\u5b58\u50a8\u5728 /dev/pts/ \u76ee\u5f55\u4e0b\u3002 /dev/pts/ \u76ee\u5f55\u4e0b\u7684\u5185\u5bb9\u662f\u4e00\u4e9b\u7279\u6b8a\u7684\u76ee\u5f55\uff0c\u7531Linux\u5185\u6838\u6240\u521b\u5efa\u3002 \u6bcf\u4e2a\u552f\u4e00\u7684\u7ec8\u7aef\u7a97\u53e3\u90fd\u4e0e /dev/pts \u7cfb\u7edf\u4e2d\u7684\u4e00\u4e2aLinux pts \u6761\u76ee\u76f8\u5173\u3002 \u4e0b\u9762\u8fd4\u56de\u7684\u7ed3\u679c\u8bf4\u660e\u67092\u4e2a\u8fdc\u7a0b\u7ec8\u7aef\u8fde\u63a5\u5230\u5f53\u524d\u7684\u673a\u5668\u3002 $ ll /dev/pts/ crw--w----. 1 vagrant tty 136 , 0 Nov 13 23 :18 0 crw--w----. 1 vagrant tty 136 , 1 Nov 13 23 :48 1 c---------. 1 root root 5 , 2 Nov 13 10 :41 ptmx \u4e5f\u53ef\u4ee5\u901a\u8fc7 w \u547d\u4ee4\u770b\u52302\u4e2a\u7ec8\u7aef\u8fdb\u7a0b\u3002 $ w 23 :55:05 up 13 :14, 2 users, load average: 0 .00, 0 .00, 0 .00 USER TTY LOGIN@ IDLE JCPU PCPU WHAT vagrant pts/0 10 :51 37 :03 0 .05s 0 .05s -bash vagrant pts/1 23 :48 0 .00s 0 .03s 0 .00s w \u5355\u4e2a\u4f2a\u7ec8\u7aefpseudoterminal\u53ef\u4ee5\u540c\u65f6\u63a5\u6536\u6765\u81ea\u4e0d\u540c\u7684\u7a0b\u5e8f\u7684\u8f93\u51fa\u3002 \u591a\u4e2a\u7a0b\u5e8f\u540c\u65f6\u5bf9\u4e00\u4e2a\u4f2a\u7ec8\u7aefpseudoterminal\u8fdb\u884c\u8bfb\u53d6\u4f1a\u5f15\u8d77\u6df7\u6dc6\u3002 \u5b58\u50a8\u5728 /dev/pts \u76ee\u5f55\u4e2d\u7684\u6587\u4ef6\u662f\u62bd\u8c61\u6587\u4ef6\u800c\u4e0d\u662f\u771f\u5b9e\u6587\u4ef6\uff0c\u662f\u4f2a\u7ec8\u7aef\u4e2d\u6267\u884c\u7a0b\u5e8f\u65f6\u4e34\u65f6\u5b58\u50a8\u7684\u6570\u636e\u3002 \u6253\u5f00 /dev/pts \u4e0b\u7684\u6587\u4ef6\u901a\u5e38\u6ca1\u6709\u4ec0\u4e48\u5b9e\u9645\u610f\u4e49\u3002","title":"5.\u6807\u51c6\u8f93\u5165\u8f93\u51fa"},{"location":"linux/SRE/02-filesystem/#6","text":"","title":"6.\u91cd\u5b9a\u5411\u548c\u7ba1\u9053"},{"location":"linux/SRE/02-filesystem/#61","text":"\u5e38\u7528\u547d\u4ee4\u683c\u5f0f\uff1a command < file \uff1a\u5c06\u6307\u5b9a\u6587\u4ef6 file \u4f5c\u4e3a\u547d\u4ee4\u7684\u8f93\u5165\u8bbe\u5907\u3002 command << delimiter \uff1a\u8868\u793a\u4ece\u6807\u51c6\u8f93\u5165\u8bbe\u5907\uff08\u952e\u76d8\uff09\u4e2d\u8bfb\u5165\uff0c\u76f4\u5230\u9047\u5230\u5206\u754c\u7b26 delimiter \u505c\u6b62\uff08\u8bfb\u5165\u7684\u6570\u636e\u4e0d\u5305\u62ec\u5206\u754c\u7b26\uff09\uff0c\u8fd9\u91cc\u7684\u5206\u754c\u7b26\u53ef\u4ee5\u7406\u89e3\u4e3a\u81ea\u5b9a\u4e49\u7684\u5b57\u7b26\u4e32\u3002 command < file1 > file2 \uff1a\u5c06 file1 \u4f5c\u4e3a\u547d\u4ee4\u7684\u8f93\u5165\u8bbe\u5907\uff0c\u8be5\u547d\u4ee4\u7684\u6267\u884c\u7ed3\u679c\u8f93\u51fa\u5230 file2 \u4e2d\u3002 # \u8f93\u51fa\u6587\u4ef6file.py\u5185\u5bb9\uff08\u8f93\u5165\u8bbe\u5907\u662f\u952e\u76d8\uff09 $ cat file.py # \u8f93\u51fa\u6587\u4ef6file.py\u5185\u5bb9\uff08\u8f93\u5165\u8bbe\u5907\u662f\u6587\u4ef6file.py\uff09 $ cat < file.py # \u6307\u5b9a\u5206\u754c\u7b26\uff08\u8fd9\u91cc\u662fEOF\uff09\uff0c\u8bfb\u53d6\u952e\u76d8\u8f93\u5165\u5185\u5bb9\uff0c\u76f4\u5230\u9047\u5230\u6307\u5b9a\u5206\u754c\u7b26\u4e3a\u6b62\uff0c\u5c06\u6240\u8bfb\u53d6\u7684\u5185\u5bb9\u8f93\u51fa\u5230\u6587\u4ef6file.py\u3002 $ cat > file.py < new.py","title":"6.1.\u8f93\u5165\u91cd\u5b9a\u5411"},{"location":"linux/SRE/02-filesystem/#62","text":"\u8f93\u51fa\u91cd\u5b9a\u5411\u5206\u4e3a\u6807\u51c6\u8f93\u51fa\u91cd\u5b9a\u5411\u548c\u9519\u8bef\u8f93\u51fa\u91cd\u5b9a\u5411\u4e24\u79cd\u3002 \u5e38\u7528\u547d\u4ee4\u683c\u5f0f\uff1a command > file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u6807\u51c6\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u8f93\u51fa\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u5df2\u5305\u542b\u6570\u636e\uff0c\u4f1a\u6e05\u7a7a\u539f\u6709\u6570\u636e\uff0c\u518d\u5199\u5165\u65b0\u6570\u636e\u3002 command 2> file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u9519\u8bef\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u4e2d\u5df2\u5305\u542b\u6570\u636e\uff0c\u4f1a\u6e05\u7a7a\u539f\u6709\u6570\u636e\uff0c\u518d\u5199\u5165\u65b0\u6570\u636e\u3002 command >> file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u6807\u51c6\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u8f93\u51fa\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u5df2\u5305\u542b\u6570\u636e\uff0c\u65b0\u6570\u636e\u5c06\u8ffd\u52a0\u5199\u5165\u5230\u539f\u6709\u5185\u5bb9\u7684\u540e\u9762\u3002 command 2>> file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u9519\u8bef\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u4e2d\u5df2\u5305\u542b\u6570\u636e\uff0c\u65b0\u6570\u636e\u5c06\u8ffd\u52a0\u5199\u5165\u5230\u539f\u6709\u5185\u5bb9\u7684\u540e\u9762\u3002 command >> file 2>&1 \u6216\u8005 command &>> file \uff1a\u5c06\u6807\u51c6\u8f93\u51fa\u6216\u8005\u9519\u8bef\u8f93\u51fa\u5199\u5165\u5230\u6307\u5b9a\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u4e2d\u5df2\u5305\u542b\u6570\u636e\uff0c\u65b0\u6570\u636e\u5c06\u8ffd\u52a0\u5199\u5165\u5230\u539f\u6709\u5185\u5bb9\u7684\u540e\u9762\u3002 \u6ce8\u610f\uff1a\u4e0a\u9762\u7684 file \u53ef\u4ee5\u662f\u4e00\u4e2a\u666e\u901a\u6587\u4ef6\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u4e00\u4e2a\u7279\u6b8a\u7684\u6587\u4ef6 /dev/null \u3002 /dev/null \u5e76\u4e0d\u4fdd\u5b58\u6570\u636e\uff0c\u88ab\u5199\u5165 /dev/null \u7684\u6570\u636e\u6700\u7ec8\u90fd\u4f1a\u4e22\u5931\u3002 \u4e3e\u4f8b\uff1a2\u4e2apython\u6587\u4ef6\u5b58\u5728\uff0c\u5176\u4ed62\u4e2a\u65e0\u6269\u5c55\u540d\u7684\u6587\u4ef6\u4e0d\u5b58\u5728\u3002 ls file.py > out ls file 2 > out.err ls new.py >> out ls new 2 >> out.err \u53ef\u4ee5\u5f97\u5230\u9884\u671f\u7684\u7ed3\u679c\u3002\u4e24\u4e2a\u9519\u8bef\u8bb0\u5f55\u90fd\u88ab\u8ffd\u52a0\u5230 out.err \u6587\u4ef6\u4e2d\u3002\u4e24\u4e2a\u6210\u529f\u6267\u884c\u7684\u547d\u4ee4\u7684\u8fd4\u56de\u7ed3\u679c\u4e5f\u8f93\u51fa\u5230 out \u6587\u4ef6\u4e2d\u3002 $ccat out file.py new.py $ cat out.err ls: cannot access 'file' : No such file or directory ls: cannot access 'new' : No such file or directory \u4e0a\u4f8b\u547d\u4ee4\u4e5f\u53ef\u4ee5\u5408\u5e76\u3002 ls file.py > out 2 > out.err ls file >> out 2 >> out.err 2>&1 \u683c\u5f0f\u4e3e\u4f8b\uff1a $ ls file >> out.txt 2 > & 1 $ cat out.txt ls: cannot access 'file' : No such file or directory $ ls file.py & >> out.txt $ cat out.txt ls: cannot access 'file' : No such file or directory file.py","title":"6.2.\u8f93\u51fa\u91cd\u5b9a\u5411"},{"location":"linux/SRE/02-filesystem/#63","text":"\u683c\u5f0f\uff1a command1 < <(command2) tr 'a-z' 'A-Z' < < ( echo \"Hello World\" ) \u5e94\u7528\uff1a\u4fee\u6539\u5bc6\u7801 \u5bc6\u7801\u4fdd\u5b58\u5728 passwd.txt \u6587\u4ef6\u4e2d\uff0c\u5e76\u4e25\u683c\u9650\u5236\u6539\u6587\u4ef6\u7684\u6743\u9650\u3002 \u901a\u8fc7\u53c2\u6570 --stdin \u5b9e\u73b0\u6a21\u62df\u952e\u76d8\u8f93\u5165\u64cd\u4f5c\u8f93\u5165\u7528\u6237\u540d\u3002 \u5728Rocky\u4e2d\u53ef\u4ee5\u4f7f\u7528 --stdin \u53c2\u6570\u3002 passwd --stdin vagrant < passwd.txt \u5728openSUSE\u548cUbuntu\u4e2d\uff0c --stdin \u53c2\u6570\u65e0\u6cd5\u8bc6\u522b\u3002\u53ef\u4ee5\u6539\u7528\u4e0b\u9762\u7684\u65b9\u6cd5\u3002 echo passwd.txt | chpasswd \u5176\u4e2dpasswd.txt\u7684\u683c\u5f0f\u4e3a username:password \u3002 \u53c2\u8003\uff1a Here-document(Here-doc)\uff1a\u8f93\u5165\u7684\u6587\u672c\u5757\u91cd\u5b9a\u5411\u81f3\u6807\u51c6\u8f93\u5165\u6d41\uff0c\u76f4\u81f3\u9047\u5230\u7279\u6b8a\u7684\u6587\u4ef6\u7ed3\u675f\u6807\u8bb0\u7b26\u4e3a\u6b62\uff08\u6587\u4ef6\u7ed3\u675f\u6807\u8bb0\u7b26\u53ef\u4ee5\u662f\u4efb\u610f\u7684\u552f\u4e00\u7684\u5b57\u7b26\u4e32\uff0c\u4f46\u5927\u90e8\u5206\u4eba\u90fd\u9ed8\u8ba4\u4f7f\u7528 EOF \uff09\u3002 cat < \u5c06\u547d\u4ee4\u4e0e\u6587\u4ef6\u8fde\u63a5\u8d77\u6765\uff0c\u7528\u6587\u4ef6\u6765\u63a5\u6536\u547d\u4ee4\u7684\u8f93\u51fa\uff1b\u800c\u7ba1\u9053\u7b26 | \u5c06\u547d\u4ee4\u4e0e\u547d\u4ee4\u8fde\u63a5\u8d77\u6765\uff0c\u7528\u53f3\u8fb9\u547d\u4ee4\u6765\u63a5\u6536\u5de6\u8fb9\u547d\u4ee4\u7684\u8f93\u51fa\u3002 $ ls | tr 'a-z' 'A-Z' BIN F1.TXT F2.TXT FILE.PY NEW.PY OUT OUT.ERR TEST.TXT","title":"7.\u7ba1\u9053"},{"location":"linux/SRE/03-identity-security/","text":"\u7b2c\u4e09\u7ae0 \u8eab\u4efd\u4e0e\u5b89\u5168 \u00b6 1.\u7528\u6237\u3001\u7ec4\u3001\u6743\u9650 \u00b6 \u7528\u6237\u548c\u7ec4 \u7528\u6237user\u548c\u7ec4group\u5728Linux\u7cfb\u7edf\u4e2d\u4ee5\u6570\u5b57\u5f62\u5f0f\u8fdb\u884c\u7ba1\u7406\u3002 \u7528\u6237\u88ab\u5206\u914d\u7684\u53f7\u7801\u79f0\u4e3a\u7528\u6237ID\uff08UID\uff09\u3002 \u6bcf\u4e2aLinux\u7cfb\u7edf\u90fd\u6709\u4e00\u4e2a\u7279\u6743\u7528\u6237\uff0c\u5373 root \u7528\u6237\u3002 root \u662f\u7cfb\u7edf\u7ba1\u7406\u5458\u3002 \u6b64\u7528\u6237\u7684UID\u59cb\u7ec8\u4e3a0\u3002 \u666e\u901a\u7528\u6237\u7684UID\u7f16\u53f7\uff08\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff09\u4e3a1000\u3002 \u6bcf\u4e2a\u7ec4\u4e5f\u5206\u914d\u4e86\u4e00\u4e2a\u79f0\u4e3a\u7ec4ID\uff08GID\uff09\u7684\u7f16\u53f7\u3002 \u6bcf\u4e2a\u7528\u6237\u6709\u4e00\u4e2a\u4e3b\u8981\u7ec4\uff08primary group\uff09\uff0c\u6709\u96f6\u4e2a\u6216\u8005\u4efb\u610f\u4e2a\u9644\u52a0\u7ec4\uff08supplementary group\uff09\u3002 \u4ee5openSUSE\u4e3a\u4f8b\uff1a UID 0: root 1 \u2013 99: System 100 \u2013 499: System accounts \u2265 1000: Normal (unprivileged) accounts GID 0: root 1 \u2013 99: System Groups 100 \u2013 499: Dynamically Allocated System Groups \u2265 1000: Normal Groups \u4e3e\u4f8b\uff1a $ id postfix uid = 51 ( postfix ) gid = 51 ( postfix ) groups = 482 ( mail ) ,59 ( maildrop ) ,51 ( postfix ) $ id vagrant uid = 1000 ( vagrant ) gid = 478 ( wheel ) groups = 0 ( root ) ,478 ( wheel ) \u63d0\u793a\uff1a UID\u548cGID\u7b49\u7f16\u53f7\u89c4\u5219\uff0c\u662f\u5728\u6587\u4ef6 /etc/login.defs \u4e2d\u7ea6\u5b9a\u7684\u3002 2.SELinux \u00b6 Security-Enhanced Linux (SELinux) \u662f\u4e00\u79cdLinux\u7cfb\u7edf\u7684\u5b89\u5168\u67b6\u6784\uff0c\u5b83\u5141\u8bb8\u7ba1\u7406\u5458\u66f4\u597d\u5730\u63a7\u5236\u8c01\u53ef\u4ee5\u8bbf\u95ee\u7cfb\u7edf\u3002 SELinux\u4e8e2000\u5e74\u5411\u5f00\u6e90\u793e\u533a\u53d1\u5e03\uff0c\u5e76\u4e8e2003\u5e74\u96c6\u6210\u5230\u4e0a\u6e38 Linux \u5185\u6838\u4e2d\u3002 SELinux\u4e3a\u7cfb\u7edf\u4e0a\u7684\u5e94\u7528\u7a0b\u5e8f\u3001\u8fdb\u7a0b\u548c\u6587\u4ef6\u5b9a\u4e49\u4e86\u8bbf\u95ee\u63a7\u5236\u3002 \u5b83\u4f7f\u7528\u5b89\u5168\u7b56\u7565\uff08\u4e00\u7ec4\u89c4\u5219\u544a\u8bc9SELinux\u4ec0\u4e48\u53ef\u4ee5\u8bbf\u95ee\u6216\u4e0d\u53ef\u4ee5\u8bbf\u95ee\uff09\u6765\u5f3a\u5236\u6267\u884c\u7b56\u7565\u5141\u8bb8\u7684\u8bbf\u95ee\u3002 \u5f53\u79f0\u4e3a\u4e3b\u4f53\uff08subject\uff09\u7684\u5e94\u7528\u7a0b\u5e8f\u6216\u8fdb\u7a0b\u8bf7\u6c42\u8bbf\u95ee\u5bf9\u8c61\uff08\u5982\u6587\u4ef6\uff09\u65f6\uff0cSELinux\u4f1a\u68c0\u67e5\u8bbf\u95ee\u5411\u91cf\u7f13\u5b58(AVC, Access Vector Cache)\uff0c\u5176\u4e2d\u7f13\u5b58\u4e86\u4e3b\u4f53\u548c\u5bf9\u8c61\u7684\u6743\u9650\u3002 \u5982\u679cSELinux\u65e0\u6cd5\u6839\u636e\u7f13\u5b58\u7684\u6743\u9650\u505a\u51fa\u8bbf\u95ee\u51b3\u5b9a\uff0c\u5b83\u4f1a\u5c06\u8bf7\u6c42\u53d1\u9001\u5230\u5b89\u5168\u670d\u52a1\u5668\u3002 \u5b89\u5168\u670d\u52a1\u5668\u68c0\u67e5\u5e94\u7528\u7a0b\u5e8f\u6216\u8fdb\u7a0b\u548c\u6587\u4ef6\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\u3002 \u4eceSELinux\u7b56\u7565\u6570\u636e\u5e93\u5e94\u7528\u5b89\u5168\u4e0a\u4e0b\u6587\uff08Security context\uff09\uff0c\u7136\u540e\u6388\u4e88\u6216\u62d2\u7edd\u8bb8\u53ef\u3002 \u5982\u679c\u6743\u9650\u88ab\u62d2\u7edd\uff0c avc: denied \u6d88\u606f\u5c06\u5728 /var/log.messages \u4e2d\u4f53\u73b0\u3002 \u4f20\u7edf\u4e0a\uff0cLinux\u548cUNIX\u7cfb\u7edf\u90fd\u4f7f\u7528DAC\uff08Discretionary Access Control\uff09\u3002 SELinux\u662fLinux\u7684MAC\uff08Mandatory Access Control\uff09\u7cfb\u7edf\u7684\u4e00\u4e2a\u793a\u4f8b\u3002 \u5728DAC\u65b9\u5f0f\u4e0b\uff0c\u6587\u4ef6\u548c\u8fdb\u7a0b\u6709\u81ea\u5df1\u7684\u5c5e\u4e3b\uff08\u6240\u6709\u8005\uff09\u3002 \u7528\u6237\u53ef\u4ee5\u62e5\u6709\u4e00\u4e2a\u6587\u4ef6\uff0c\u4e00\u4e2a\u7ec4\u4e5f\u53ef\u4ee5\u62e5\u6709\u4e00\u4e2a\u6587\u4ef6\uff0c\u6216\u8005\u5176\u4ed6\u4eba\u3002 \u7528\u6237\u53ef\u4ee5\u66f4\u6539\u81ea\u5df1\u6587\u4ef6\u7684\u6743\u9650\u3002 root \u7528\u6237\u5bf9DAC\u7cfb\u7edf\u5177\u6709\u5b8c\u5168\u8bbf\u95ee\u63a7\u5236\u6743\u3002 \u4f46\u662f\u5728\u50cfSELinux\u8fd9\u6837\u7684MAC\u7cfb\u7edf\u4e0a\uff0c\u5bf9\u4e8e\u8bbf\u95ee\u7684\u7ba1\u7406\u662f\u901a\u8fc7\u8bbe\u7f6e\u7b56\u7565\u6765\u5b9e\u73b0\u7684\u3002\u5373\u4f7f\u7528\u6237\u4e3b\u76ee\u5f55\u4e0a\u7684DAC\u8bbe\u7f6e\u53d1\u751f\u66f4\u6539\uff0c\u7528\u4e8e\u9632\u6b62\u5176\u4ed6\u7528\u6237\u6216\u8fdb\u7a0b\u8bbf\u95ee\u8be5\u76ee\u5f55\u7684SELinux\u7b56\u7565\u4e5f\u5c06\u7ee7\u7eed\u786e\u4fdd\u7cfb\u7edf\u5b89\u5168\u3002 MAC\u65b9\u5f0f\u662f\u63a7\u5236\u4e00\u4e2a\u8fdb\u7a0b\u5bf9\u5177\u4f53\u6587\u4ef6\u7cfb\u7edf\u4e0a\u9762\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u662f\u5426\u62e5\u6709\u8bbf\u95ee\u6743\u9650\u3002\u5224\u65ad\u8fdb\u7a0b\u662f\u5426\u53ef\u4ee5\u8bbf\u95ee\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u4f9d\u636e\uff0c\u53d6\u51b3\u4e8eSELinux\u4e2d\u8bbe\u5b9a\u7684\u5f88\u591a\u7b56\u7565\u89c4\u5219\u3002 \u8bbf\u95ee\u63a7\u5236\u5217\u8868 (ACL\uff0cAccess Control List) \u4e3a\u6587\u4ef6\u7cfb\u7edf\u63d0\u4f9b\u4e86\u4e00\u79cd\u989d\u5916\u7684\u3001\u66f4\u7075\u6d3b\u7684\u6743\u9650\u673a\u5236\u3002 \u5b83\u65e8\u5728\u534f\u52a9 UNIX \u6587\u4ef6\u6743\u9650\u3002ACL\u5141\u8bb8\u6388\u4e88\u4efb\u4f55\u7528\u6237\u6216\u7ec4\u5bf9\u4efb\u4f55\u78c1\u76d8\u8d44\u6e90\u7684\u6743\u9650\u3002ACL\u9002\u7528\u4e8e\u5728\u4e0d\u4f7f\u67d0\u4e2a\u7528\u6237\u6210\u4e3a\u7ec4\u6210\u5458\u7684\u60c5\u51b5\u4e0b\uff0c\u4ecd\u65e7\u6388\u4e88\u4e00\u4e9b\u8bfb\u6216\u5199\u8bbf\u95ee\u6743\u9650\u3002 \u4e0b\u9762\u793a\u4f8b\u5bf9\u6bd4\u8bf4\u660e\u4e86SELinux\u548cACL\u5728\u6587\u4ef6\u5c5e\u6027\u5c55\u73b0\u4e0a\u7684\u7279\u70b9\u3002 -rwxr-xr-- vagrant wheel \uff1a\u6ca1\u6709selinux\u4e0a\u4e0b\u6587\uff0c\u6ca1\u6709ACL -rwx--xr-x+ vagrant wheel \uff1a\u53ea\u6709ACL\uff0c\u6ca1\u6709selinux\u4e0a\u4e0b\u6587 -rw-r--r--. vagrant wheel \uff1a\u53ea\u6709selinux\u4e0a\u4e0b\u6587\uff0c\u6ca1\u6709ACL -rwxrwxr--+ vagrant wheel \uff1a\u6709selinux\u4e0a\u4e0b\u6587\uff0c\u6709ACL 2.1.SELinux\u4e3b\u8981\u6982\u5ff5 \u00b6 \u7528\u6237(Users)\uff1a SELinux\u7684\u7528\u6237\u4e0d\u7b49\u540c\u4e0eLinux\u7528\u6237\u3002 SELinux\u7528\u6237\u4ee5\u540e\u7f00 _u \u7ed3\u5c3e\u3002 \u89d2\u8272(Roles)\uff1a \u89d2\u8272Roles\u662f\u7531\u7b56\u7565Policies\u5b9a\u4e49\u7684\uff0c\u89d2\u8272\u51b3\u5b9a\u4e86\u4f7f\u7528\u54ea\u4e2a\u7b56\u7565\u3002 SELinux\u89d2\u8272\u4ee5\u540e\u7f00 _r \u7ed3\u5c3e\u3002 \u7c7b\u578b(Types)\uff1a SELinux\u662f\u7c7b\u578b\u5f3a\u5236\u7684\uff0c\u7c7b\u578bTypes\u51b3\u5b9a\u8fdb\u7a0b\u80fd\u5426\u8bbf\u95ee\u67d0\u4e2a\u6587\u4ef6\u3002 SELinux\u7c7b\u578b\u662f\u4ee5\u540e\u7f00 _t \u7ed3\u5c3e\u3002 \u4e0a\u4e0b\u6587(Contexts)\uff1a \u7528\u6765\u6807\u8bb0\u8fdb\u7a0b\u548c\u6587\u4ef6\u3002\u5206\u522b\u662f\u7528\u6237Users\uff0c\u89d2\u8272Roles\uff0c\u7c7b\u578bTypes\uff0c\u8303\u56f4Ranges\u3002 \u683c\u5f0f\uff1a user:role:type:range \u6587\u4ef6\u7c7b\u578b(Object Classes)\uff1a \u6bcf\u4e2a\u6587\u4ef6\u7c7b\u578bTypes\u90fd\u5bf9\u5e94\u4e00\u5957\u7b56\u7565Policies\u3002\u7b56\u7565Policies\u51b3\u5b9a\u4e86\u8fdb\u7a0b\u5bf9\u8fd9\u7c7b\u6587\u4ef6\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u8bbf\u95ee\u6743\u9650\u67094\u79cd\uff1a \u521b\u5efacreate \u8bfb\u53d6read \u5199\u5165write \u5220\u9664unlink\uff08\u6ce8\u610f\uff0c\u8fd9\u91cc\u4e0d\u662f\u94fe\u63a5\u7684\u610f\u601d\uff09 \u89c4\u5219(Rules) \u683c\u5f0f\uff1a allow user_t user_home_t:file {create read write unlink}; \u542b\u4e49\uff1a user_t \u7c7b\u578b\u5bf9 user_home_t \u7c7b\u578b\u6709\u521b\u5efacreate\uff0c\u8bfb\u53d6read\uff0c\u5199\u5165write\uff0c\u5220\u9664unlink\u6743\u9650\u3002 2.2.SELinux in openSUSE \u00b6 \u4f5c\u4e3aSELinux\u7684\u66ff\u4ee3\u54c1\uff0c2005\u5e74\u88abNovell\u6536\u8d2d\u7684Immunix\u516c\u53f8\u5f00\u53d1\u4e86AppArmor\u3002SUSE\u5728openSUSE Leap\u4e2d\u63d0\u4f9b\u5bf9SELinux\u6846\u67b6\u7684\u652f\u6301\u3002\u8fd9\u5e76\u4e0d\u610f\u5473\u7740openSUSE Leap\u7684\u9ed8\u8ba4\u5b89\u88c5\u4f1a\u5728\u4e0d\u4e45\u7684\u5c06\u6765\u4eceAppArmor\u5207\u6362\u5230SELinux\u3002 \u6dfb\u52a0SELinux\u7684\u6e90\u3002\u53ef\u4ee5\u4ece https://download.opensuse.org/repositories/security:/SELinux/ \u4e0b\u8f7d\u5bf9\u5e94\u7684\u7b56\u7565policy\u3002 sudo zypper ar -f https://download.opensuse.org/repositories/security:/SELinux/openSUSE_Factory/ Security-SELinux \u5b89\u88c5C++\u7b49\u57fa\u7840\u5f00\u53d1\u5305\uff1a # \u5217\u51fa\u5f53\u524d\u53ef\u5b89\u88c5\u7684Pattern sudo zypper pt # \u5b89\u88c5\u4e0b\u9762\u51e0\u4e2a\u5f00\u53d1\u76f8\u5173\u7684Pattern sudo zypper in -t pattern devel_C_C++ devel_basis devel_kernel \u5b89\u88c5SELinux packages\uff1a zypper se --search-descriptions selinux sudo zypper in restorecond policycoreutils setools-console sudo zypper in selinux-tools libselinux-devel \u5b89\u88c5SELinux policy\uff1a sudo zypper in selinux-policy-targeted selinux-policy-devel selinux-autorelabel \u66f4\u65b0GRUB2 bootloader\uff08GRUB2\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\uff09\uff1a \u7f16\u8f91\u6587\u4ef6 /etc/default/grub \uff0c\u6dfb\u52a0\u4e0b\u9762\u5185\u5bb9\u5230 GRUB_CMDLINE_LINUX_DEFAULT= \u8fd9\u4e00\u884c\uff1a security = selinux selinux = 1 \u8bb0\u5f55\u8fd9\u4e00\u884c\u7684\u539f\u59cb\u4fe1\u606f\uff1a GRUB_CMDLINE_LINUX_DEFAULT = \"splash=silent resume=/dev/disk/by-uuid/47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 preempt=full mitigations=auto quiet security=apparmor\" \u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u751f\u6210\u65b0\u7684GRUB2\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\u914d\u7f6e\u6587\u4ef6\u3002 sudo grub2-mkconfig -o /boot/grub2/grub.cfg \u7f16\u8f91\u6587\u4ef6 /etc/selinux/config \u5e76\u8bbe\u7f6e SELINUX=permissive \u6765\u542f\u7528SElinux\u3002\u8fd9\u4e0e\u524d\u9762GRUB2\u7684\u542f\u52a8\u914d\u7f6e\u662f\u4e00\u81f4\u7684\u3002 \u5982\u6587\u4ef6\u4e0d\u5b58\u5728\uff0c\u5219\u521b\u5efa\u3002 $ sudo cat /etc/selinux/config SELINUX = permissive SELINUXTYPE = targeted \u91cd\u542f\u7cfb\u7edf\u3002\u7cfb\u7edf\u542f\u52a8\u53ef\u80fd\u9700\u8981\u4e00\u4e9b\u65f6\u95f4\uff0cSELinux\u9700\u8981\u7ed9\u6574\u4e2a\u6587\u4ef6\u7cfb\u7edf\u91cd\u65b0\u8fdb\u884c\u6807\u7b7e\u5316\u3002 \u91cd\u542f\u540e\uff0c\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u6765\u67e5\u770bSELinux\u662f\u5426\u8fd0\u884c\u6b63\u5e38\u3002 $ sudo getenforce Permissive $ sudo sestatus -v SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted Current mode: permissive Mode from config file: permissive Policy MLS status: enabled Policy deny_unknown status: allowed Memory protection checking: requested ( insecure ) Max kernel policy version: 33 Process contexts: Current context: unconfined_u:unconfined_r:unconfined_t:s0 Init context: system_u:system_r:kernel_t:s0 /sbin/agetty system_u:system_r:kernel_t:s0 /usr/sbin/sshd system_u:system_r:kernel_t:s0 File contexts: Controlling terminal: unconfined_u:object_r:devpts_t:s0 /etc/passwd system_u:object_r:unlabeled_t:s0 /etc/shadow system_u:object_r:unlabeled_t:s0 /bin/bash system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /bin/login system_u:object_r:unlabeled_t:s0 /bin/sh system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /sbin/agetty system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /sbin/init system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /usr/sbin/sshd system_u:object_r:unlabeled_t:s0 \u53c2\u8003\uff1a GRUB2\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\u4e2d\u6dfb\u52a0\u7684\u4e09\u4e2a\u53c2\u6570\u7684\u89e3\u91ca\uff1a security=selinux : This option tells the kernel to use SELinux and not AppArmor. selinux=1 : This option switches on SELinux. enforcing=0 : This option puts SELinux in permissive mode. In this mode, SELinux is fully functional, but does not enforce any of the security settings in the policy. Use this mode for testing and configuring your system. To switch on SELinux protection, when the system is fully operational, change the option to enforcing=1 and add SELINUX=enforcing in /etc/selinux/config . \u5c0f\u8d34\u58eb\uff1a \u5728\u9996\u6b21\u542f\u7528SELinux\u540e\uff0c\u5982\u679c\u53ea\u5728grub2\u91cc\u9762\u6dfb\u52a0selinux=1\uff0c\u901a\u8fc7 getenforce \u547d\u4ee4\u770b\u7684SELinux\u4e00\u76f4\u5c31\u662fdisabled\u7684\u72b6\u6001\uff0c\u9700\u8981\u624b\u5de5\u521b\u5efa/etc/selinux/config\u6587\u4ef6\u6dfb\u52a0\u914d\u7f6e\u624d\u884c\u3002\u611f\u89c9grub2\u91cc\u9762\u65e0\u9700\u8bbe\u7f6e\uff0c\u76f4\u63a5\u914d\u7f6e/etc/selinux/config\u6587\u4ef6\u3002\u4e0d\u786e\u5b9a\u8fd9\u4e2a\u60f3\u6cd5\u662f\u5426\u6b63\u786e\u3002 \u5728grub2\u4e2d\u8bbe\u5b9aselinux=1\uff0c\u5728/etc/selinux/config\u6587\u4ef6\u4e2d\uff1a \u8bbe\u5b9aSELINUX=permissive\uff0c\u91cd\u542f\u540e\u901a\u8fc7 getenforce \u547d\u4ee4\u770b\u5230\u7684\u662fpermissive\u3002 \u8bbe\u5b9aSELINUX=disabled\uff0c\u5219\u91cd\u542f\u540e getenforce \u547d\u4ee4\u770b\u5230\u7684\u662fdisabled\u3002 \u8fd9\u8bf4\u660e\u914d\u7f6e\u6587\u4ef6\u540e\u542f\u52a8\uff0c\u8986\u76d6\u4e86\u5185\u6838\u8bbe\u7f6e\u3002 \u6ce8\u610f\uff0c\u5982\u679c\u4ec5\u4ec5\u5b8c\u6210\u4e86\u4e0a\u9762\u7684enable SELinux\uff0c\u7acb\u523b\u8bbe\u5b9aSELINUX=enforcing\uff0c\u4f1a\u5f15\u8d77ssh\u65e0\u6cd5\u767b\u5f55\uff0c\u9519\u8bef\u4fe1\u606f\u662f /bin/bash: Permission denied \u3002 \u914d\u7f6eSELinux\u3002 $ sudo semanage boolean -l Failed to use semanage \u6dfb\u52a0\u4e0b\u9762\u5185\u5bb9\u5230.bashrc\u6587\u4ef6\u3002 export PATH = /usr/local/bin:/home/ $USER /.local/bin: $PATH \u66f4\u65b0pip3. pip3 install --upgrade pip \u5b89\u88c5\u4e0b\u9762\u51e0\u4e2a\u5305 sudo zypper in libselinux libselinux-devel sudo zypper in python3-semanage sudo zypper in libsemanage-devel libsemanage-devel-static sudo zypper in policycoreutils-python-utils sudo zypper in cross-x86_64-linux-glibc-devel glibc-utils glibc-profile sudo zypper in policycoreutils-devel 2.3.SELinux in Ubuntu \u00b6 2.4.SELinux in Rocky \u00b6 3.\u7528\u6237\u548c\u7ec4\u7684\u914d\u7f6e\u6587\u4ef6 \u00b6 /etc/passwd \uff1a\u7528\u6237\u53ca\u5176\u5c5e\u6027\u4fe1\u606f\uff08\u7528\u6237\u540d\uff0cUID\uff0c\u4e3b\u7ec4ID\u7b49\uff09 /etc/shadow \uff1a\u7528\u6237\u5bc6\u7801\u673a\u5668\u5c5e\u6027 /etc/group \uff1a\u7ec4\u53ca\u5176\u5c5e\u6027 /etc/gshadow \uff1a\u7ec4\u5bc6\u7801\u53ca\u5176\u5c5e\u6027 3.1./etc/passwd \u00b6 \u683c\u5f0f\u8bf4\u660e\uff1a vagrant:x:1001:474:vagrant:/home/vagrant:/bin/bash [ ----- ] - [ -- ] [ - ] [ ----- ] [ ----------- ] [ ------- ] | | | | | | +--------> 7 . Login shell | | | | | +--------------------> 6 . Home directory | | | | +-------------------------------> 5 . GECOS or the full name of the user | | | +-------------------------------------> 4 . GID | | +------------------------------------------> 3 . UID | +---------------------------------------------> 2 . Password +--------------------------------------------------> 1 . Username 3.2./etc/shadow \u00b6 \u683c\u5f0f\u8bf4\u660e\uff1a vagrant: $6 $.n.:17736:0:99999:7::: [ ----- ] [ ---- ] [ --- ] - [ --- ] ---- | | | | | || | +-----------> 9 . Unused | | | | | || +------------> 8 . Expiration date since Jan 1 , 1970 | | | | | | +-------------> 7 . Inactivity period \u5bc6\u7801\u8fc7\u671f\u540e\u7684\u5bbd\u9650\u671f | | | | | +--------------> 6 . Warning period, default 7 days | | | | +------------------> 5 . Maximum password age | | | +----------------------> 4 . Minimum password age | | +--------------------------> 3 . Last password change since Jan 1 , 1970 | +---------------------------------> 2 . Encrypted Password +-------------------------------------------> 1 . Username 3.3./etc/group \u00b6 \u683c\u5f0f\u8bf4\u660e\uff1a audio:x:492:pulse [ --- ] - [ - ] [ --- ] | | | +----> 4 . username-list, who have this group as their supplementary | | +---------> 3 . GID | +------------> 2 . group-password. Real password is in /etc/gshadow +----------------> 1 . groupname 3.4./etc/gshadow \u00b6 \u683c\u5f0f\u8bf4\u660e\uff1a general:!!:shelley:juan,bob [ ----- ] -- [ ----- ] [ ------ ] | | | +-------> 4 . group members ( in a comma delimited list ) | | +---------------> 3 . group adminstrators ( in a comma delimited list ) | +---------------------> 2 . encrypted password. ` ! ` , ` !! ` , and null +---------------------------> 1 . group name Encrypted password ! \uff1ano user is allowed to access the group using the newgrp command. !! \uff1athe same as a value of ! \u2014 however, it also indicates that a password has never been set before. null\uff1aonly group members can log into the group. 3.5.\u751f\u6210\u968f\u673a\u5bc6\u7801 \u00b6 # \u901a\u8fc7`/dev/urandom`\u751f\u6210\u968f\u673a\u6570\uff0c\u901a\u8fc7`tr -dc`\u8fc7\u6ee4\u968f\u673a\u6570\uff0c\u53ea\u4fdd\u7559\u5b57\u6bcd\u548c\u6570\u5b57\uff0c\u901a\u8fc7`head -c`\u4fdd\u7559\u6307\u5b9a\u4f4d\u6570 $ tr -dc '[:alnum:]' < /dev/urandom | head -c 12 xFw7vfma54D8 $ openssl rand -base64 9 I5TZXJfpd3Pg 3.6.vipw/vigr/pwck/grpck\u547d\u4ee4 \u00b6 vipw \u548c vigr \u547d\u4ee4\u5206\u522b\u7f16\u8f91\u6587\u4ef6 /etc/passwd \u548c /etc/group \u3002 \u5982\u679c\u6307\u5b9a\u4e86 -s \u6807\u5fd7\uff0c\u8fd9\u4e9b\u547d\u4ee4\u5c06\u5206\u522b\u7f16\u8f91\u5176\u6587\u4ef6\u7684\u5f71\u5b50\uff08\u5b89\u5168\uff09\u7248\u672c\uff1a /etc/shadow \u548c /etc/gshadow \u3002 vipw \u548c vigr \u547d\u4ee4\u5728\u7f16\u8f91\u6587\u4ef6\u65f6\u4f1a\u8bbe\u7f6e\u9501\u4ee5\u9632\u6b62\u6587\u4ef6\u635f\u574f\u3002 vipw \u548c vigr \u547d\u4ee4\u4f1a\u9996\u5148\u5c1d\u8bd5\u73af\u5883\u53d8\u91cf $VISUAL \uff0c\u7136\u540e\u662f\u73af\u5883\u53d8\u91cf $EDITOR \uff0c\u6700\u540e\u662f\u9ed8\u8ba4\u7f16\u8f91\u5668 vi \u3002 sudo vipw sudo vipw -s sudo vigr sudo vigr -s pwck \u547d\u4ee4\u5b9e\u73b0\u9a8c\u8bc1\u7cfb\u7edf\u8ba4\u8bc1\u4fe1\u606f\u7684\u5b8c\u6574\u6027\u3002 \u68c0\u67e5 /etc/passwd \u548c /etc/shadow \u4e2d\u7684\u6240\u6709\u6761\u76ee\u6bcf\u4e2a\u5b57\u6bb5\u662f\u5426\u5177\u6709\u6b63\u786e\u7684\u683c\u5f0f\u548c\u6709\u6548\u6570\u636e\u3002 \u7cfb\u7edf\u4f1a\u63d0\u793a\u7528\u6237\u5220\u9664\u683c\u5f0f\u4e0d\u6b63\u786e\u6216\u5b58\u5728\u5176\u4ed6\u9519\u8bef\u7684\u6761\u76ee\u3002 pwck \u8fd4\u56de\u503c\uff1a 0 : success 1 : invalid command syntax 2 : one or more bad password entries 3 : can\u2019t open password files 4 : can\u2019t lock password files 5 : can\u2019t update password files grpck \u547d\u4ee4\u5b9e\u73b0\u9a8c\u8bc1\u7cfb\u7edf\u8ba4\u8bc1\u4fe1\u606f\u7684\u5b8c\u6574\u6027\u3002 \u68c0\u67e5 /etc/group \u548c /etc/gshadow \u4e2d\u7684\u6240\u6709\u6761\u76ee\u6bcf\u4e2a\u5b57\u6bb5\u662f\u5426\u5177\u6709\u6b63\u786e\u7684\u683c\u5f0f\u548c\u6709\u6548\u6570\u636e\u3002 \u7cfb\u7edf\u4f1a\u63d0\u793a\u7528\u6237\u5220\u9664\u683c\u5f0f\u4e0d\u6b63\u786e\u6216\u5b58\u5728\u5176\u4ed6\u9519\u8bef\u7684\u6761\u76ee\u3002 grpck \u8fd4\u56de\u503c\uff1a 0 : success 1 : invalid command syntax 2 : one or more bad group entries 3 : can\u2019t open group files 4 : can\u2019t lock group files 5 : can\u2019t update group files 4.\u7528\u6237\u7ba1\u7406 \u00b6 \u7528\u6237\u7ba1\u7406\u547d\u4ee4\uff1a useradd usermod userdel 4.1.\u521b\u5efa\u7528\u6237 useradd \u00b6 \u4e3e\u4f8b\uff1a # \u666e\u901a\u7528\u6237 $ useradd -m -g wheel -G root -c \"vagrant\" vagrant # \u975e\u4ea4\u4e92\u7528\u6237 $ useradd -r -u 48 -g apache -d /var/www -s /sbin/nologin -g postfix -c \"Apache\" apache 2 >/dev/null useradd \u547d\u4ee4\u7684\u9ed8\u8ba4\u503c\u662f\u5728 /etc/default/useradd \u6587\u4ef6\u4e2d\u8bbe\u5b9a\u3002 openSUSE\u7684 /etc/default/useradd \u6587\u4ef6\u5185\u5bb9\uff1a GROUP = 100 HOME = /home INACTIVE = -1 # \u5bf9\u5e94/etc/shadow\u6587\u4ef6\u7b2c7\u5217\uff0cInactivity period\uff0c\u5bc6\u7801\u8fc7\u671f\u540e\u7684\u5bbd\u9650\u671f\uff0c-1\u8868\u793a\u4e0d\u9650\u5236 EXPIRE = # \u5bf9\u5e94/etc/shadow\u6587\u4ef6\u7b2c8\u5217\uff0cExpiration date since Jan 1, 1970\uff0c\u5373\u8d26\u53f7\u6709\u6548\u671f SHELL = /bin/bash SKEL = /etc/skel # \u7528\u4e8e\u751f\u6210\u7528\u6237\u4e3b\u76ee\u5f55\u7684\u6a21\u7248\u6587\u4ef6 USRSKEL = /usr/etc/skel CREATE_MAIL_SPOOL = yes Rocky\u7684 /etc/default/useradd \u6587\u4ef6\u5185\u5bb9\uff1a GROUP = 100 HOME = /home INACTIVE = -1 EXPIRE = SHELL = /bin/bash SKEL = /etc/skel CREATE_MAIL_SPOOL = yes \u5728Ubuntu\u4e2d /etc/default/useradd \u6587\u4ef6\u53ea\u6709\u4e0b\u9762\u8fd9\u4e00\u884c\u3002 SHELL = /bin/sh 4.1.1.\u6279\u91cf\u521b\u5efa\u7528\u6237 newusers \u00b6 \u683c\u5f0f\uff1a newusers \u3002\u5176\u4e2d\u6587\u4ef6 \u7684\u683c\u5f0f\u5982\u4e0b\uff1a :::::: \u4e3e\u4f8b\uff0c\u521b\u5efa\u6587\u4ef6 users.txt \uff1a $ cat ~/users.txt tester1:123:600:1530: \"Test User1,testuser1@abc.com\" :/home/tester1:/bin/bash tester2:123:601:1529:::/bin/bash tester3:123::::: tester4:123::::/home/tester4:/bin/tsh \u770b\u7ed3\u679c\uff1a $ cat /etc/passwd | grep tester tester1:x:600:1530: \"Test User1,testuser1@abc.com\" :/home/tester1:/bin/bash tester2:x:601:1529:::/bin/bash tester3:x:1001:1001::: tester4:x:1002:1002::/home/tester4:/bin/tsh $ cat /etc/group | grep tester tester1:*:1530: tester2:*:1529: tester3:*:1001: tester4:*:1002: $ sudo cat /etc/shadow | grep tester tester1:!:19321:0:99999:7::: tester2:!:19321:0:99999:7::: tester3:!:19321:0:99999:7::: tester4:!:19321:0:99999:7::: $ ls -ld /home/tester* drwxr-xr-x. 1 tester1 tester1 0 Nov 26 00 :32 /home/tester1 drwxr-xr-x. 1 tester4 tester4 0 Nov 26 00 :32 /home/tester4 4.1.2.\u6279\u91cf\u4fee\u6539\u5bc6\u7801 chpasswd \u00b6 \u4e0d\u540c\u65b9\u6cd5\uff1a echo username:password | chpasswd chpasswd < file.txt # file.txt\u6bcf\u884c\u7684\u683c\u5f0f\u662fusername:password paste -d \":\" user.txt passwd.txt | chpasswd \u53c2\u6570 -e \uff1a\u53e3\u4ee4\u4ee5\u52a0\u5bc6\u7684\u65b9\u5f0f\u4f20\u9012\u3002\u5426\u5219\u53e3\u4ee4\u4ee5\u660e\u6587\u7684\u5f62\u5f0f\u4f20\u9012\u3002 \u6ce8\u610f\uff1a \u7528\u6237\u540dusername\u5fc5\u987b\u662f\u5df2\u5b58\u5728\u7684\u7528\u6237 \u666e\u901a\u7528\u6237\u6ca1\u6709\u4f7f\u7528\u8fd9\u4e2a\u6307\u4ee4\u7684\u6743\u9650 \u5982\u679c\u8f93\u5165\u6587\u4ef6\u662f\u6309\u975e\u52a0\u5bc6\u65b9\u5f0f\u4f20\u9012\u7684\u8bdd\uff0c\u8bf7\u5bf9\u8be5\u6587\u4ef6\u8fdb\u884c\u9002\u5f53\u7684\u52a0\u5bc6\u3002 \u6307\u4ee4\u6587\u4ef6\u4e0d\u80fd\u6709\u7a7a\u884c \u4e3e\u4f8b\uff1a echo tester1:112233 | sudo chpasswd $ cat chpasswd.txt tester1:112233 tester2:33445566 $ sudo chpasswd < chpasswd.txt 4.1.3.\u751f\u6210\u52a0\u5bc6\u5bc6\u7801 openssl passwd \u00b6 \u547d\u4ee4 openssl passwd \u683c\u5f0f\u53ef\u4ee5\u5982\u4e0b\u65b9\u6cd5\u83b7\u5f97\u3002 $ man -f passwd passwd ( 1 ) - change user password passwd ( 1ssl ) - compute password hashes passwd ( 5 ) - password file $ man passwd Man: find all matching manual pages ( set MAN_POSIXLY_CORRECT to avoid this ) * passwd ( 1 ) passwd ( 5 ) passwd ( 1ssl ) Man: What manual page do you want? Man: 1ssl \u4e3e\u4f8b\uff08\u8fd9\u91cc\u7528 \u4ee3\u66ff\u5b9e\u9645\u5bc6\u7801\uff09\uff1a # \u57fa\u4e8e\u7ed9\u5b9a\u5b57\u4e32newpasswd\u751f\u6210sha256\u52a0\u5bc6\u7801\uff0c $ openssl passwd -6 newpasswd # \u521b\u5efa\u65b0\u7528\u6237tester5\uff0c\u8d4b\u4e88\u52a0\u5bc6\u5bc6\u7801 $ useradd -p '' tester1 # \u8bfb\u53d6\u7528\u6237tester5\u7684\u5bc6\u7801\uff0c\u53ef\u4ee5\u9a8c\u8bc1\u662f\u5426\u548c\u4e4b\u524d\u7684\u4e00\u81f4 $ sudo getent shadow tester5 tester5::19321:0:99999:7::: 4.2.\u4fee\u6539\u7528\u6237\u5c5e\u6027 usermod \u00b6 \u6dfb\u52a0\u7528\u6237\u5230\u9644\u52a0\u7ec4 usermod -a -G GROUP USER usermod -a -G GROUP1,GROUP2,GROUP3 USER \u4fee\u6539\u7528\u6237\u4e3b\u7ec4 usermod -a -g GROUP USER \u4fee\u6539\u7528\u6237\u4fe1\u606f usermod -c \"GECOS Comments\" USER \u4fee\u6539\u7528\u6237\u4e3b\u76ee\u5f55\uff0c\u4f7f\u7528\u7edd\u5bf9\u8def\u5f84\uff0c -m \u53c2\u6570\u4f1a\u628a\u539f\u4e3b\u76ee\u5f55\u7684\u5185\u5bb9\u79fb\u52a8\u5230\u65b0\u4e3b\u76ee\u5f55\u3002 usermod -d NEW_HOME_DIR USER usermod -d NEW_HOME_DIR -m USER \u4fee\u6539\u7528\u6237shell usermod -s SHELL USER \u4fee\u6539\u7528\u6237UID usermod -u UID USER \u4fee\u6539\u7528\u6237\u540d\uff08\u4e0d\u5e38\u7528\uff09\uff0c\u540c\u65f6\u4e5f\u9700\u8981\u4fee\u6539\u7528\u6237\u4e3b\u76ee\u5f55\u3002 usermod -l NEW_USER USER \u4fee\u6539\u7528\u6237\u8fc7\u671f\u5c5e\u6027\uff0c\u65e5\u671f\u683c\u5f0f\u662f YYYY-MM-DD usermod -e DATE USER \u5982\u679c\u8bbe\u5b9a\u6c38\u4e0d\u8fc7\u671f\uff0c\u5219\u7f6e\u7a7a\u65e5\u671f\uff1a usermod -e \"\" USER \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684\u8fc7\u671f\u65e5\u671f $ sudo chage -l vagrant Last password change : Oct 30 , 2022 Password expires : never Password inactive : never Account expires : never Minimum number of days between password change : 0 Maximum number of days between password change : 99999 Number of days of warning before password expires : 7 \u9501\u5b9a\u7528\u6237\u3002 \u6b64\u547d\u4ee4\u5c06\u5728\u52a0\u5bc6\u5bc6\u7801\u524d\u63d2\u5165\u4e00\u4e2a\u611f\u53f9\u53f7 (!) \u6807\u8bb0\u3002 \u5f53 /etc/shadow \u6587\u4ef6\u4e2d\u7684\u5bc6\u7801\u5b57\u6bb5\u5305\u542b\u611f\u53f9\u53f7\u65f6\uff0c\u7528\u6237\u5c06\u65e0\u6cd5\u4f7f\u7528\u5bc6\u7801\u9a8c\u8bc1\u767b\u5f55\u7cfb\u7edf\u3002 \u5176\u4ed6\u767b\u5f55\u65b9\u6cd5\u4ecd\u7136\u5141\u8bb8\uff0c\u4f8b\u5982\u57fa\u4e8e\u5bc6\u94a5\u7684\u8eab\u4efd\u9a8c\u8bc1\u6216\u5207\u6362\u5230\u7528\u6237\u3002 \u5982\u679c\u8981\u9501\u5b9a\u8d26\u6237\u5e76\u7981\u7528\u6240\u6709\u767b\u5f55\u65b9\u5f0f\uff0c\u8fd8\u9700\u8981\u5c06\u5230\u671f\u65e5\u671f\u8bbe\u7f6e\u4e3a1\u3002 usermod -L USER usermod -L -e 1 USER \u89e3\u9501\u7528\u6237 usermod -U USER 4.3.\u5220\u9664\u7528\u6237 userdel \u00b6 userdel \u547d\u4ee4\u6267\u884c\u65f6\uff0c\u4f1a\u8bfb\u53d6 /etc/login.defs \u6587\u4ef6\u7684\u5185\u5bb9\u3002 \u6b64\u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u5c5e\u6027\u4f1a\u8986\u76d6 userdel \u7684\u9ed8\u8ba4\u884c\u4e3a\u3002 \u5982\u679c\u5728\u6b64\u6587\u4ef6\u4e2d\u5c06 USERGROUPS_ENAB \u8bbe\u7f6e\u4e3a yes \uff0c userdel \u5c06\u5220\u9664\u4e0e\u7528\u6237\u540c\u540d\u7684\u7ec4\uff0c\u524d\u63d0\u662f\u6ca1\u6709\u5176\u4ed6\u7528\u6237\u662f\u8be5\u7ec4\u7684\u6210\u5458\u3002 userdel \u547d\u4ee4\u4ece /etc/passwd \u548c /etc/shadow \u6587\u4ef6\u4e2d\u5220\u9664\u7528\u6237\u6761\u76ee\u3002 userdel \u547d\u4ee4\u5220\u9664\u7528\u6237\u5e10\u6237\u65f6\uff0c\u4e00\u822c\u4e0d\u4f1a\u5220\u9664\u7528\u6237\u4e3b\u76ee\u5f55\u548c\u90ae\u4ef6\u5047\u8131\u673amail spool\u76ee\u5f55\u3002 \u4f7f\u7528 -r \u9009\u9879\u5f3a\u5236\u5220\u9664\u7528\u6237\u7684\u4e3b\u76ee\u5f55\u548c\u90ae\u4ef6\u5047\u8131\u673a\u76ee\u5f55\u3002 \u5982\u679c\u8981\u5220\u9664\u7684\u7528\u6237\u4ecd\u7136\u5904\u4e8e\u767b\u5f55\u72b6\u6001\uff0c\u6216\u8005\u6709\u5c5e\u4e8e\u8be5\u7528\u6237\u7684\u6b63\u5728\u8fd0\u884c\u7684\u8fdb\u7a0b\uff0c\u5219 userdel \u547d\u4ee4\u4e0d\u5141\u8bb8\u5220\u9664\u8be5\u7528\u6237\u3002 \u4f7f\u7528 -f \u9009\u9879\u5f3a\u5236\u5220\u9664\u7528\u6237\u5e10\u6237\uff0c\u5373\u4f7f\u7528\u6237\u4ecd\u7136\u767b\u5f55\u6216\u6709\u5c5e\u4e8e\u8be5\u7528\u6237\u7684\u6b63\u5728\u8fd0\u884c\u7684\u8fdb\u7a0b\u4e5f\u662f\u5982\u6b64\u3002 userdel USER userdel -r USER 4.4.\u67e5\u770b\u7528\u6237\u4fe1\u606f id \u00b6 \u7c7bUnix\u64cd\u4f5c\u7cfb\u7edf\u4e2d\u7684\u6bcf\u4e2a\u7528\u6237\u90fd\u7531\u4e00\u4e2a\u4e0d\u540c\u7684\u6574\u6570\u6807\u8bc6\uff0c\u8fd9\u4e2a\u552f\u4e00\u7684\u6570\u5b57\u79f0\u4e3aUserID\u3002 \u4e3a\u8fdb\u7a0bprocess\u5b9a\u4e49\u4e86\u4e09\u79cd\u7c7b\u578b\u7684UID\uff0c\u53ef\u4ee5\u6839\u636e\u4efb\u52a1\u7684\u6743\u9650\u52a8\u6001\u66f4\u6539\u3002 \u5b9a\u4e49\u7684\u4e09\u79cd\u4e0d\u540c\u7c7b\u578b\u7684UID\u662f\uff1a \u771f\u5b9e\u7528\u6237ID\uff08Real UserId\uff09\uff1a\u5bf9\u4e8e\u4e00\u4e2a\u8fdb\u7a0b\uff0cReal UserId\u5c31\u662f\u542f\u52a8\u5b83\u7684\u7528\u6237\u7684 UserID\u3002 \u5b83\u5b9a\u4e49\u4e86\u8fd9\u4e2a\u8fdb\u7a0b\u53ef\u4ee5\u8bbf\u95ee\u54ea\u4e9b\u6587\u4ef6\u3002 \u6709\u6548\u7528\u6237\u540d\uff08Effective UserID\uff09\uff1a\u5b83\u901a\u5e38\u4e0e Real UserID \u76f8\u540c\uff0c\u4f46\u6709\u65f6\u4f1a\u66f4\u6539\u4e3a\u4f7f\u975e\u7279\u6743\u7528\u6237\u80fd\u591f\u8bbf\u95ee\u90a3\u4e9b\u53ea\u80fd\u7531\u7279\u6743\u7528\u6237\uff08\u5982 root \uff09\u8bbf\u95ee\u7684\u6587\u4ef6\u3002 \u4fdd\u5b58\u7684\u7528\u6237ID\uff08Saved UserID\uff09 \uff1a\u5f53\u4e00\u4e2a\u4ee5\u63d0\u5347\u7684\u6743\u9650\uff08\u901a\u5e38\u662f root \uff09\u8fd0\u884c\u7684\u8fdb\u7a0b\u9700\u8981\u505a\u4e00\u4e9b\u4f4e\u6743\u9650\u7684\u4efb\u52a1\u65f6\u4f7f\u7528\uff0c\u53ef\u4ee5\u901a\u8fc7\u4e34\u65f6\u5207\u6362\u5230\u975e\u7279\u6743\u5e10\u6237\u6765\u5b9e\u73b0\u3002\u5728\u6267\u884c\u4f4e\u6743\u9650\u4efb\u52a1\u65f6\uff0c\u6709\u6548\u7684 UID \u88ab\u66f4\u6539\u4e3a\u67d0\u4e2a\u8f83\u4f4e\u6743\u9650\u7684\u503c\uff0c\u5e76\u4e14 euid \u88ab\u4fdd\u5b58\u5230\u5df2\u4fdd\u5b58\u7684 userID (suid)\u4e2d\uff0c\u4ee5\u4fbf\u5728\u4efb\u52a1\u5b8c\u6210\u65f6\u7528\u4e8e\u5207\u6362\u56de\u7279\u6743\u5e10\u6237\u3002 \u5728\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u6682\u505c\u5728\u65b0\u5bc6\u7801\u8f93\u5165\u8fd9\u4e00\u6b65\u3002 $ ls -ltr /usr/bin/passwd -rwsr-xr-x. 1 root shadow 65208 May 8 2022 /usr/bin/passwd $ passwd Changing password for vagrant. Current password: New password: \u65b0\u5f00\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\u3002 $ ps -a | grep passwd 3040 pts/0 00 :00:00 passwd $ ps -eo pid,euid,ruid | grep 3040 3040 0 1000 \u4e0a\u9762\u8f93\u51fa\u53ef\u4ee5\u770b\u51fa\uff0c passwd \u8fd9\u4e2a\u8fdb\u7a0b\u7684Effective UserID\u662f 0 \u3002Real UserId\u662f 1000 . id \u547d\u4ee4\u67e5\u770b\u7528\u6237\u6709\u6548\u7684UID\u548cGID\u3002 \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684\u4fe1\u606f\uff1a $ id uid = 1000 ( vagrant ) gid = 478 ( wheel ) groups = 478 ( wheel ) ,0 ( root ) context = unconfined_u:unconfined_r:unconfined_t:s0 \u67e5\u770b\u6307\u5b9a\u7528\u6237\u7684\u4fe1\u606f\uff1a $ id vagrant uid = 1000 ( vagrant ) gid = 478 ( wheel ) groups = 0 ( root ) ,478 ( wheel ) \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684GID\uff1a $ id -g 478 \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684UID\uff1a $ id -u 1000 \u67e5\u770b\u5f53\u524d\u7528\u6237\u6240\u6709\u7ec4\u7684GID\uff1a $ id -G 478 0 \u67e5\u770b\u5f53\u524d\u7528\u6237\u540d\uff1a $ id -un vagrant \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684GID $ id -ur 1000 \u53ea\u6709SELinux\u6fc0\u6d3b\u540e\u624d\u6709 $ id -Z unconfined_u:unconfined_r:unconfined_t:s0 \u7c7b\u4f3c\u4e8e whoami \u547d\u4ee4 $ id -znG wheelroot 4.5.\u5207\u6362\u7528\u6237 su \u00b6 \u547d\u4ee4 su - username \u662f\u767b\u5f55\u5f0f\u5207\u6362\u7528\u6237\u3002\u4f1a\u8bfb\u53d6\u76ee\u6807\u7528\u6237\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5207\u6362\u81f3\u76ee\u6807\u7528\u6237\u7684\u4e3b\u76ee\u5f55\u3002 \u547d\u4ee4 su username \u662f\u975e\u767b\u5f55\u5f0f\u5207\u6362\u7528\u6237\u3002\u4e0d\u8bfb\u53d6\u76ee\u6807\u7528\u6237\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u4e0d\u6539\u53d8\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 \u5207\u6362\u6210root\u7528\u6237\uff0c\u5e76\u4f7f\u7528zsh shell\u3002 su -s /usr/bin/zsh su -s /usr/bin/zsh root \u5207\u6362\u6210tester1\u7528\u6237\uff0c\u4f7f\u7528bash shell su - tester1 -s /bin/bash su - -s /bin/bash tester1 \u4fdd\u7559\u5f53\u524d\u7528\u6237\u73af\u5883\u4e0d\u53d8\u3002 su -p root \u4e0d\u4ea4\u4e92\u5f0f\u5207\u6362\u7528\u6237\uff0c\u53ea\u7528\u76ee\u6807\u7528\u6237\u6267\u884c\u67d0\u4e9b\u547d\u4ee4\u3002 su -c ps su - root -c \"getent passwd\" su - root -s /bin/bash -c \"getent passwd\" root \u7528\u6237\u5207\u6362\u81f3\u5176\u4ed6\u7528\u6237\u4e0d\u9700\u8981\u5bc6\u7801\uff0c\u975e root \u7528\u6237\u5207\u6362\u5176\u4ed6\u7528\u6237\u9700\u8981\u5bc6\u7801\u3002 4.6.\u8bbe\u7f6e\u5bc6\u7801 \u00b6 4.6.1. passwd \u00b6 \u4fee\u6539\u5f53\u524d\u7528\u6237\u81ea\u5df1\u7684\u5bc6\u7801\uff1a passwd \u4fee\u6539\u5176\u4ed6\u7528\u6237\u7684\u5bc6\u7801\uff1a sudo passwd root \u67e5\u770b\u67d0\u4e2a\u7528\u6237\u5bc6\u7801\u72b6\u6001\uff1a $ sudo passwd -S root root P 10 /30/2022 -1 -1 -1 -1 $ sudo passwd -S vagrant vagrant P 10 /30/2022 0 99999 7 -1 \u68c0\u67e5\u5168\u90e8\u7528\u6237\u7684\u5bc6\u7801\u72b6\u6001\uff1a sudo passwd -Sa \u5bc6\u7801\u72b6\u6001\u8bf4\u660e\uff1a Username Status Date Last Changed Minimum Age Maximum Age Warning Period Inactivity Period vagrant P 10 /30/2022 0 99999 7 -1 root P 10 /30/2022 -1 -1 -1 -1 Status\u7684\u63cf\u8ff0\uff1a P : Usable password NP : No password L : Locked password Age\u7684\u4e00\u4e9b\u7279\u6b8a\u503c\uff1a 9999 : Never expires 0 : Can be changed at anytime -1 : Not active \u5f3a\u5236\u8981\u6c42\u7528\u6237\u4e0b\u6b21\u767b\u5f55\u65f6\u4fee\u6539\u5bc6\u7801\uff1a $ sudo passwd -e tester1 $ sudo passwd -S tester1 tester1 P 01 /01/1970 0 99999 7 -1 \u7528\u6237tester1\u7684\u5bc6\u7801\u65e5\u671f\u5df2\u7ecf\u88ab\u6539\u6210 01/01/1970 \u4e86\u3002\u8fd9\u4e2a\u65e5\u671f\u7b97\u662fUnix\u7684\u201c\u7eaa\u5143\uff08epoch\uff09\u201d\u65e5\u671f\uff0c\u610f\u5473\u7740Unix\u7684\u65e5\u671f\u8d77\u70b9\uff0c0\u5929\u3002 \u9501\u5b9a\u67d0\u4e2a\u7528\u6237\uff1a $ sudo passwd -l tester1 $ sudo passwd -S tester1 tester1 L 01 /01/1970 0 99999 7 -1 \u6b64\u65f6\u7528\u6237 tester1 \u7684\u72b6\u6001\u680f\u5df2\u7ecf\u53d8\u6210\u4e86 L \uff0c\u9501\u5b9a\u72b6\u6001\u3002 \u89e3\u9501\u67d0\u4e2a\u7528\u6237\uff1a $ sudo passwd -u tester1 $ sudo passwd -S tester1 tester1 P 01 /01/1970 0 99999 7 -1 \u6b64\u65f6\u7528\u6237 tester1 \u7684\u72b6\u6001\u680f\u5df2\u7ecf\u4ece L \u53d8\u56de\u4e86 P \uff0c\u89e3\u9664\u4e86\u9501\u5b9a\u72b6\u6001\u3002 \u5220\u9664\u7528\u6237\u5bc6\u7801\u3002\u8fd9\u4e2a\u64cd\u4f5c\u614e\u91cd\uff0c\u5bc6\u7801\u5220\u9664\u540e\u8be5\u7528\u6237\u53ef\u4ee5\u4e0d\u9700\u8981\u5bc6\u7801\u5c31\u80fd\u8bbf\u95ee\u7cfb\u7edf\u3002 $ sudo passwd -d tester1 $ sudo passwd -S tester1 tester1 NP 01 /01/1970 0 99999 7 -1 \u6b64\u65f6\u7528\u6237 tester1 \u7684\u72b6\u6001\u680f\u662f NP \u3002 4.6.2. pwgen \u00b6 \u5b89\u88c5\u5305\u3002 mkpasswd\u547d\u4ee4\u6709\u6b67\u4e49\uff0c2\u4e2a\u540c\u540d\u547d\u4ee4\u5b9e\u73b0\u4e0d\u540c\u529f\u80fd\uff0c\u751f\u6210\u968f\u673a\u5bc6\u7801\u5efa\u8bae\u4f7f\u7528 pwgen \u547d\u4ee4\u3002Rocky9\u6ca1\u6709\u627e\u5230pwgen\u5305\u3002 sudo zypper in pwgen sudo apt install pwgen \u968f\u673a\u751f\u6210\u957f\u5ea68\u4f4d\u5b89\u5168\u5bc6\u7801\u3002 pwgen -s -1 \u968f\u673a\u751f\u6210\u957f\u5ea614\u4f4d\u5b89\u5168\u5bc6\u7801\u3002 pwgen -s -1 14 \u968f\u673a\u751f\u62102\u4e2a\u957f\u5ea615\u4f4d\u5b89\u5168\u5bc6\u7801\u3002 pwgen -s -1 15 2 \u968f\u673a\u751f\u62105\u4e2a\u5bc6\u7801\uff0c\u957f\u5ea610\u4f4d\uff0c\u6bcf\u4e2a\u5bc6\u7801\u81f3\u5c11\u542b\u4e00\u4e2a\u7279\u6b8a\u5b57\u7b26\uff0c\u7ed3\u679c\u4ee5\u5217\u5f62\u5f0f\u8f93\u51fa\u3002 pwgen -s -1 -y 10 5 \u751f\u6210\u957f\u5ea68\uff0c\u542b\u6709\u6570\u5b57\uff0c\u542b\u6709\u5927\u5c0f\u5199\u5b57\u6bcd\u7684\u5bc6\u78014\u4e2a\uff0c\u5217\u6253\u5370 pwgen -s -n -c -C -1 8 4 \u751f\u6210\u957f\u5ea68\uff0c\u4e0d\u542b\u6570\u5b57\uff0c\u53ea\u542b\u5c0f\u5199\u5b57\u6bcd\uff0c\u5217\u6253\u5370 pwgen -s -c -A -0 -1 8 4 \u751f\u6210\u957f\u5ea616\uff0c\u542b\u6709\u6570\u5b57\uff0c\u542b\u6709\u5927\u5c0f\u5199\u5b57\u6bcd\uff0c\u542b\u6709\u7279\u6b8a\u5b57\u7b26\u7684\u5bc6\u78013\u4e2a\uff0c\u884c\u6253\u5370 pwgen -s -n -c -y -1 16 3 \u751f\u6210\u957f\u5ea680\uff0c\u4e0d\u542b\u5143\u97f3\u548c\u6570\u5b57\uff0c\u81f3\u5c11\u542b\u6709\u4e00\u4e2a\u5927\u5199\u5b57\u6bcd\uff0c\u884c\u6253\u5370 pwgen -s -v -c -0 80 1 4.6.3.\u975e\u4ea4\u4e92\u5f0f\u8bbe\u7f6e\u5bc6\u7801 \u00b6 \u65b9\u6cd51\uff1a $ echo -e '123456\\n123456' | sudo passwd tester1 New password: BAD PASSWORD: it is too simplistic/systematic BAD PASSWORD: is too simple Retype new password: passwd: password updated successfully \u65b9\u6cd52\uff1a Rocky\u4e2d\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u65b9\u6cd5\u3002 pwgen -ncy1 16 1 | tee passwd.txt | sudo passwd --stdin tester1 openSUSE\u548cUbuntu\u53ef\u4ee5\u7528\u4e0b\u9762\u65b9\u6cd5\u3002 echo \"tester1:\" ` pwgen -ncy1 16 1 ` | tee passwd.txt | sudo chpasswd \u65b9\u6cd53\uff1a\u6839\u636e\u9884\u5148\u7ed9\u5b9a\u7684\u7528\u6237\u5217\u8868\uff0c\u6279\u91cf\u751f\u6210\u5bc6\u7801\u3002 $ cat > user-list.txt < user.txt < file 67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov 1 11 :20 symlinkfile1-1 -> symlinkfile1 67274682 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file 33555262 drwxr-xr-x. 2 vagrant wheel 6 Nov 1 11 :30 typelink \u4ee5 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11:14 file \u4e3a\u4f8b\uff1a 67274680 : inode \u7d22\u5f15\u8282\u70b9\u7f16\u53f7\u3002 -rw-r--r-- \uff1a\u6587\u4ef6\u7c7b\u578b\u53ca\u6743\u9650 - \uff1a\u6587\u4ef6\u7c7b\u578b\uff0c\u4f8b\u5b50\u4e2d\u51fa\u73b0\u4e86\u4e09\u79cd\uff0c - \uff0c l \u548c d \u3002 - \uff1a\u666e\u901a\u6587\u4ef6 d \uff1a\u76ee\u5f55 l \uff1a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\uff08link\uff09 b \uff1a\u5757\u8bbe\u5907\uff08block\uff09 c \uff1a\u5b57\u7b26\u8bbe\u5907\uff08character\uff09 p \uff1a\u7ba1\u9053\u6587\u4ef6\uff08pipe\uff09 s \uff1a\u5957\u63a5\u5b57\u6587\u4ef6\uff08socket\uff09 rw-r--r-- \uff1a\u6587\u4ef6\u6743\u9650\uff0c\u4ece\u5de6\u5230\u53f3\u4f9d\u6b21\u4e3a\uff1a\uff08\u7528\u6237\u7684\u6700\u7ec8\u6743\u9650\uff0c\u662f\u4ece\u5de6\u5411\u53f3\u5339\u914d\uff0c\u4e00\u65e6\u5339\u914d\u5219\u6743\u9650\u7acb\u5373\u751f\u6548\uff0c\u4e0d\u518d\u5411\u53f3\u7ee7\u7eed\u5339\u914d\uff09 rw- \uff1a\u6587\u4ef6\u5c5e\u4e3b\u6743\u9650\uff08u\uff09\uff0c\u4f8b\u5b50\u4e2d\u662f vagrant \u3002 r-- \uff1a\u6587\u4ef6\u5c5e\u7ec4\u7684\u6743\u9650\uff08g\uff09\uff0c\u4f8b\u5b50\u4e2d\u662f wheel \u3002 r-- \uff1a\u5176\u4ed6\u7ec4\u7684\u6743\u9650\uff08o\uff09\u3002 . \uff1a\u8fd9\u4e2a\u70b9\u8868\u793a\u6587\u4ef6\u5e26\u6709SELinux\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\uff08SELinux Contexts\uff09\u3002\u5173\u95edSELinux\uff0c\u65b0\u521b\u5efa\u7684\u6587\u4ef6\u5c31\u4e0d\u4f1a\u518d\u6709\u8fd9\u4e2a\u70b9\u4e86\u3002\u4f46\u662f\uff0c\u4ee5\u524d\u521b\u5efa\u7684\u6587\u4ef6\u672c\u6765\u6709\u8fd9\u4e2a\u70b9\u7684\u8fd8\u4f1a\u663e\u793a\u8fd9\u4e2a\u70b9\uff08\u867d\u7136SELinux\u4e0d\u8d77\u4f5c\u7528\u4e86\uff09\u3002 3 \uff1a\u786c\u94fe\u63a5\u6570\uff0c\u4f8b\u5b50\u4e2d file \u548c hardlinkfile1 \u548c hardlinkfile2 \u4e4b\u95f4\u662f\u786c\u94fe\u63a5\uff0c\u6240\u4ee5\u8fd9\u4e09\u4e2a\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u90fd\u662f 3 \u3002 vagrant \uff1a\u6587\u4ef6\u5c5e\u4e3bowner wheel \uff1a\u6587\u4ef6\u5c5e\u7ec4group 31 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u5927\u5c0f Nov 1 11:14 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u521b\u5efa\u65e5\u671f\u548c\u65f6\u95f4 file \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u540d\u79f0 \u4e0b\u9762\u662f\u547d\u4ee4 ls -ihl \u5728openSUSE\u548cUbuntu\u4e0a\u7684\u663e\u793a\u7ed3\u679c\u3002 $ ls -ihl 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 file 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile1 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile2 233648 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile1 -> file 233650 lrwxrwxrwx 1 vagrant wheel 12 Nov 1 15 :52 symlinkfile1-1 -> symlinkfile1 233649 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile2 -> file 233646 drwxr-xr-x 1 vagrant wheel 0 Nov 1 15 :51 typelink 7.1.\u4fee\u6539\u5c5e\u4e3b chown \u00b6 chown \u547d\u4ee4\u4fee\u6539\u6587\u4ef6\u5c5e\u4e3b\uff08\u6240\u6709\u8005\uff0cowner\uff09\u3002 \u4fee\u6539\u6587\u4ef6\u5c5e\u4e3b\u4e3aroot\u3002 $ ll f1.txt -rw-r--r--. 1 vagrant wheel 41 Nov 14 22 :23 f1.txt $ sudo chown root f1.txt $ ll f1.txt -rw-r--r--. 1 root wheel 41 Nov 14 22 :23 f1.txt \u4fee\u6539\u6587\u4ef6\u7684\u5c5e\u7ec4\u4e3abin\u3002 $ sudo chown :bin f1.txt $ ll f1.txt -rw-r--r--. 1 root bin 41 Nov 14 22 :23 f1.txt \u540c\u65f6\u4fee\u6539\u6587\u4ef6\u7684\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u3002 $ sudo chown vagrant.wheel f1.txt $ ll f1.txt -rw-r--r--. 1 vagrant wheel 41 Nov 14 22 :23 f1.txt \u53c2\u7167\u67d0\u6587\u4ef6\u4fee\u6539\u53e6\u4e00\u6587\u4ef6\u7684\u5c5e\u6027\u3002 $ ll file.py -rw-r--r--. 1 vagrant wheel 56 Nov 13 22 :50 file.py $ ll user.txt -rw-r--r--. 1 root bin 21 Nov 27 23 :59 user.txt $ sudo chown root.bin user.txt $ sudo chown --reference = user.txt file.py $ ll file.py -rw-r--r--. 1 root bin 56 Nov 13 22 :50 file.py \u9012\u5f52\u4fee\u6539\u6240\u6709\u5b50\u76ee\u5f55\u53ca\u6587\u4ef6\u7684\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u3002 sudo chown -R vagrant.wheel ~ 7.2.\u4fee\u6539\u5c5e\u7ec4 chgrp \u00b6 \u4fee\u6539\u76ee\u5f55\u7684\u5c5e\u7ec4\u3002 sudo chgrp bin ~~ \u4fee\u6539\u76ee\u5f55\u53ca\u5b50\u76ee\u5f55\u53ca\u6587\u4ef6\u7684\u5c5e\u7ec4\u3002 sudo chgrp -R bin ~~ 7.3.\u6587\u4ef6\u548c\u76ee\u5f55\u6743\u9650 \u00b6 \u6587\u4ef6\uff1a r \uff1a\u53ef\u4ee5\u8bfb\u53d6\u8be5\u6587\u4ef6\u5185\u5bb9\uff0c\u6bd4\u5982\u901a\u8fc7 cat \u547d\u4ee4\u3002 w \uff1a\u53ef\u4ee5\u4fee\u6539\u8be5\u6587\u4ef6\u5185\u5bb9\uff0c\u53ef\u4ee5\u53ea\u6709 w \u800c\u6ca1\u6709 r \u3002 x \uff1a\u53ef\u4ee5\u628a\u8be5\u6587\u4ef6\u63d0\u8bf7\u5185\u6838\u542f\u52a8\u4e3a\u4e00\u4e2a\u8fdb\u7a0b\uff0c\u5373\u53ef\u4ee5\u6267\u884c\u8be5\u6587\u4ef6\uff08\u8be5\u6587\u4ef6\u7684\u5185\u5bb9\u5fc5\u987b\u662f\u53ef\u4ee5\u6267\u884c\uff09\u3002 \u76ee\u5f55\uff1a\uff08\u5bf9\u76ee\u5f55\u800c\u8a00\uff0c\u901a\u5e38\u9700\u8981\u7ed9 r \u548c x \u6743\u9650\uff09\uff08\u4ece\u76ee\u5f55\u89d2\u5ea6\u770b\uff0c\u76ee\u5f55\u5185\u6587\u4ef6\u5217\u8868\u7b49\u4e8e\u76ee\u5f55\u8282\u70b9\u7684\u5185\u5bb9\uff09 r \uff1a\u80fd\u770b\u6587\u4ef6\u5217\u8868\uff0c\u4f46\u4e0d\u80fd\u8bbf\u95ee\u6240\u542b\u6587\u4ef6\u7684\u5185\u5bb9\u53ca\u5176\u5c5e\u6027\u4fe1\u606f\uff0c\u5305\u62ecinode\u53f7\u3002 w \uff1a\u80fd\u5728\u8be5\u76ee\u5f55\u5185\u521b\u5efa\u548c\u5220\u9664\u6587\u4ef6\uff0c\u4e0d\u7531\u76ee\u5f55\u5185\u6587\u4ef6\u672c\u8eab\u7684\u6743\u9650\u51b3\u5b9a\u3002 x \uff1a\u80fdcd\u8fdb\u76ee\u5f55\uff0c\u80fd\u901a\u8fc7 ls -l file \u548c stat file \u67e5\u770b\u8be5\u76ee\u5f55\u4e2d\u5236\u5b9a\u6587\u4ef6\u7684\u5143\u6570\u636e\u3002 X \uff1a\u8868\u793a\u53ea\u6709\u5f53\u8be5\u6587\u4ef6\u662f\u4e2a\u5b50\u76ee\u5f55\u6216\u8005\u8be5\u6587\u4ef6\u5df2\u7ecf\u88ab\u8bbe\u5b9a\u8fc7\u4e3a\u53ef\u6267\u884c\u3002 \u6709\u53ea\u8bfb\u6743\u9650\u7684\u7528\u6237\u4e0d\u80fd\u7528cd\u8fdb\u5165\u8be5\u76ee\u5f55\uff0c\u8fd8\u5fc5\u987b\u6709\u6267\u884c\u6743\u9650\u624d\u80fd\u8fdb\u5165\u3002 \u6709\u6267\u884c\u6743\u9650\u7684\u7528\u6237\u53ea\u6709\u5728\u77e5\u9053\u6587\u4ef6\u540d\uff0c\u5e76\u62e5\u6709\u8bfb\u6743\u5229\u7684\u60c5\u51b5\u4e0b\u624d\u53ef\u4ee5\u8bbf\u95ee\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u3002 \u5fc5\u987b\u6709\u8bfb\u548c\u6267\u884c\u6743\u9650\u624d\u53ef\u4ee5ls\u5217\u51fa\u76ee\u5f55\u6e05\u5355\uff0c\u6216\u4f7f\u7528cd\u547d\u4ee4\u8fdb\u5165\u76ee\u5f55\u3002 \u6709\u76ee\u5f55\u7684\u5199\u6743\u9650\uff0c\u53ef\u4ee5\u521b\u5efa\u3001\u5220\u9664\u6216\u4fee\u6539\u76ee\u5f55\u4e0b\u7684\u4efb\u4f55\u6587\u4ef6\u6216\u5b50\u76ee\u5f55\uff0c\u5373\u4f7f\u4f7f\u8be5\u6587\u4ef6\u6216\u5b50\u76ee\u5f55\u5c5e\u4e8e\u5176\u4ed6\u7528\u6237\u4e5f\u662f\u5982\u6b64\u3002 \u5e38\u7528\u6743\u9650\u4f8b\u5b50\uff1a -rw------- ( 600 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\u548c\u5199\u7684\u6743\u9650 -rw-r--r-- ( 644 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\u548c\u5199\u7684\u6743\u9650\uff0c\u7ec4\u548c\u5176\u4ed6\u4eba\u53ea\u6709\u8bfb\u7684\u6743\u9650 -rwx------ ( 700 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\uff0c\u5199\uff0c\u6267\u884c\u7684\u6743\u9650 -rwxr-xr-x ( 755 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\uff0c\u5199\uff0c\u6267\u884c\u7684\u6743\u9650\uff0c\u7ec4\u548c\u5176\u4ed6\u4eba\u53ea\u6709\u8bfb\u548c\u6267\u884c\u7684\u6743\u9650 -rwx--x--x ( 711 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\uff0c\u5199\uff0c\u6267\u884c\u7684\u6743\u9650\uff0c\u7ec4\u548c\u5176\u4ed6\u4eba\u53ea\u6709\u6267\u884c\u7684\u6743\u9650 -rw-rw-rw- ( 666 ) \u6bcf\u4e2a\u4eba\u90fd\u6709\u8bfb\u5199\u7684\u6743\u9650 -rwxrwxrwx ( 777 ) \u6bcf\u4e2a\u4eba\u90fd\u6709\u8bfb\u5199\u548c\u6267\u884c\u7684\u6743\u9650 7.4.\u6743\u9650\u4fee\u6539 chmod \u00b6 \u547d\u4ee4\u683c\u5f0f\uff1a chmod [ -cfvR ] [ --help ] [ --version ] mode file mode \u5b57\u4e32\u683c\u5f0f\u4e3a\uff1a [ ugoa ][ +- =][ rwxXst ] who: u \u6587\u4ef6\u6240\u6709\u8005 g \u6587\u4ef6\u6240\u6709\u8005\u6240\u5728\u7ec4 o \u5176\u4ed6\u7528\u6237 a \u6240\u6709\u7528\u6237\uff0c\u76f8\u5f53\u4e8e ugo operator: + \u4e3a\u6307\u5b9a\u7684\u7528\u6237\u7c7b\u578b\u589e\u52a0\u6743\u9650 - \u53bb\u9664\u6307\u5b9a\u7528\u6237\u7c7b\u578b\u7684\u6743\u9650 = \u8bbe\u7f6e\u6307\u5b9a\u7528\u6237\u6743\u9650\u7684\u8bbe\u7f6e\uff0c\u5373\u5c06\u7528\u6237\u7c7b\u578b\u7684\u6240\u6709\u6743\u9650\u91cd\u65b0\u8bbe\u7f6e permission: r \u8bbe\u7f6e\u4e3a\u53ef\u8bfb\u6743\u9650 w \u8bbe\u7f6e\u4e3a\u53ef\u5199\u6743\u9650 x \u8bbe\u7f6e\u4e3a\u53ef\u6267\u884c\u6743\u9650 X \u7279\u6b8a\u6267\u884c\u6743\u9650\uff0c\u53ea\u6709\u5f53\u6587\u4ef6\u4e3a\u76ee\u5f55\u6587\u4ef6\uff0c\u6216\u8005\u5176\u4ed6\u7c7b\u578b\u7684\u7528\u6237\u6709\u53ef\u6267\u884c\u6743\u9650\u65f6\uff0c\u624d\u5c06\u6587\u4ef6\u6743\u9650\u8bbe\u7f6e\u53ef\u6267\u884c s \u5f53\u6587\u4ef6\u88ab\u6267\u884c\u65f6\uff0c\u6839\u636ewho\u53c2\u6570\u6307\u5b9a\u7684\u7528\u6237\u7c7b\u578b\u8bbe\u7f6e\u6587\u4ef6\u7684 setuid \u6216\u8005 setgid \u6743\u9650 t \u8bbe\u7f6e\u7c98\u8d34\u4f4d\uff0c\u53ea\u6709\u8d85\u7ea7\u7528\u6237\u53ef\u4ee5\u8bbe\u7f6e\u8be5\u4f4d\uff0c\u53ea\u6709\u6587\u4ef6\u6240\u6709\u8005u\u53ef\u4ee5\u4f7f\u7528\u8be5\u4f4d\u3002 \u793a\u4f8b\uff1a \u5c06\u6587\u4ef6 file1.txt \u8bbe\u4e3a\u6240\u6709\u4eba\u7686\u53ef\u8bfb\u53d6\u3002 chmod ugo+r file1.txt \u5c06\u6587\u4ef6 file1.txt \u8bbe\u4e3a\u6240\u6709\u4eba\u7686\u53ef\u8bfb\u53d6\u3002 chmod a+r file1.txt \u5c06\u6587\u4ef6 file1.txt \u4e0e file2.txt \u8bbe\u4e3a\u8be5\u6587\u4ef6\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u90fd\u53ef\u5199\u5165\uff0c\u4f46\u5176\u4ed6\u7528\u6237\u4e0d\u53ef\u5199\u5165\u3002 chmod ug+w,o-w file1.txt file2.txt \u4e3a ex1.py \u6587\u4ef6\u5c5e\u4e3b\u589e\u52a0\u53ef\u6267\u884c\u6743\u9650\u3002 chmod u+x ex1.py \u5c06\u76ee\u524d\u76ee\u5f55\u4e0b\u7684\u6240\u6709\u6587\u4ef6\u4e0e\u5b50\u76ee\u5f55\u7686\u8bbe\u4e3a\u4efb\u4f55\u4eba\u53ef\u8bfb\u53d6\u3002 chmod -R a+r * \u7ed9 file \u7684\u6240\u6709\u7528\u6237\u589e\u52a0\u8bfb\u6743\u9650 chmod a+r file \u5220\u9664 file \u7684\u6240\u6709\u7528\u6237\u7684\u6267\u884c\u6743\u9650 chmod a-x file \u7ed9 file \u7684\u6240\u6709\u7528\u6237\u589e\u52a0\u8bfb\u5199\u6743\u9650 chmod a+rw file \u7ed9 file \u7684\u6240\u6709\u7528\u6237\u589e\u52a0\u8bfb\u5199\u6267\u884c\u6743\u9650 chmod +rwx file \u5bf9 file \u7684\u5c5e\u4e3b\u8bbe\u7f6e\u8bfb\u5199\u6743\u9650\uff0c\u6e05\u7a7a\u5c5e\u7ec4\u548c\u5176\u4ed6\u7528\u6237\u5bf9 file \u7684\u6240\u6709\u6743\u9650\uff08\u7a7a\u683c\u4ee3\u8868\u65e0\u6743\u9650\uff09 chmod u = rw,go = file \u5bf9\u76ee\u5f55 docs \u548c\u5176\u5b50\u76ee\u5f55\u4e2d\u7684\u6240\u6709\u6587\u4ef6\u7ed9\u5c5e\u4e3b\u589e\u52a0\u8bfb\u6743\u9650\uff0c\u800c\u5bf9\u5c5e\u7ec4\u548c\u5176\u4ed6\u7528\u6237\u5220\u9664\u8bfb\u6743\u9650 chmod -R u+r,go-r docs \u5bf9 file \u7684\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u8bbe\u7f6e\u8bfb\u5199\u6743\u9650, \u4e3a\u5176\u4ed6\u7528\u6237\u8bbe\u7f6e\u8bfb\u6743\u9650 chmod 664 file \u5bf9 file \u7684\u5c5e\u4e3b\u8bbe\u7f6e\u8bfb\u5199\u6267\u884c\u6743\u9650\uff0c\u76f8\u5f53\u4e8e u=rwx (4+2+1)\uff0c\u8bbe\u7f6e\u5c5e\u7ec4\u8bfb\u548c\u6267\u884c\u6743\u9650\uff0c\u76f8\u5f53\u4e8e go=rx (4+1 & 4+1)\u3002 0 \u6ca1\u6709\u7279\u6b8a\u6a21\u5f0f chmod 0755 file 4 \u8bbe\u7f6e\u4e86\u8bbe\u7f6e\u7528\u6237ID\u4f4d\uff0c\u5269\u4e0b\u7684\u76f8\u5f53\u4e8e u=rwx (4+2+1)\u548c go=rx (4+1 & 4+1)\u3002 chmod 4755 file \u5220\u9664\u53ef\u6267\u884c\u6743\u9650\u5bf9 path/ \u4ee5\u53ca\u5176\u6240\u6709\u7684\u76ee\u5f55\uff08\u4e0d\u5305\u62ec\u6587\u4ef6\uff09\u7684\u6240\u6709\u7528\u6237\uff0c\u4f7f\u7528 -type f \u5339\u914d\u6587\u4ef6 find path/ -type d -exec chmod a-x {} \\; \u5141\u8bb8\u6240\u6709\u7528\u6237\u6d4f\u89c8\u6216\u901a\u8fc7\u76ee\u5f55 path/ find path/ -type d -exec chmod a+x {} \\; 7.5.\u9ed8\u8ba4\u6743\u9650 umask \u00b6 umask \u7684\u503c\uff0c\u5b9a\u4e49\u4e86\u6240\u6709\u65b0\u5efa\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u7684\u521d\u59cb\u6743\u9650\u7684\u3002 \u67e5\u770b\u5f53\u524d\u6743\u9650\u63a9\u7801\uff1a $ umask 0022 \u5728\u4e0d\u8003\u8651 umask \u7684\u60c5\u51b5\u4e0b\uff0c\u6587\u4ef6\u7684\u9ed8\u8ba4\u6743\u9650\u662f 666 (rw-rw-rw-)\uff0c\u76ee\u5f55\u7684\u9ed8\u8ba4\u6743\u9650\u662f 777 (rwxrwxrwx)\u3002 \u5728 umask \u7684\u503c\u4e3a 0022 \u7684\u60c5\u51b5\u4e0b\uff0c\u6587\u4ef6\u7684\u9ed8\u8ba4\u6743\u9650\u662f 644 (rw-r--r--)\uff0c\u76ee\u5f55\u7684\u9ed8\u8ba4\u6743\u9650\u662f 755 (rwxr-xr-x)\u3002 \u8ba1\u7b97\u65b9\u6cd5\uff1a Files: ( Default ) 6 6 6 ( umask ) 0 2 2 ---------------- ( Result ) 6 4 4 Directories: ( Default ) 7 7 7 ( umask ) 0 2 2 ---------------- ( Result ) 7 5 5 \u5982\u679c umask \u7684\u503c\u4e3a 0077 \u7684\u60c5\u51b5\u4e0b\uff0c\u6587\u4ef6\u7684\u9ed8\u8ba4\u6743\u9650\u662f 600 (rw-------)\uff0c\u76ee\u5f55\u7684\u9ed8\u8ba4\u6743\u9650\u662f 700 (rwx------)\u3002 \u8ba1\u7b97\u65b9\u6cd5\uff1a Files: ( Default ) 6 6 6 ( umask ) 0 7 7 ---------------- ( Result ) 6 0 0 Directories: ( Default ) 7 7 7 ( umask ) 0 7 7 ---------------- ( Result ) 7 0 0 \u4e3e\u4f8b\uff1a $ umask 022 $ touch file2 $ ll file2 -rw-r--r--. 1 vagrant wheel 0 Nov 28 23 :13 file2 $ umask 077 $ touch file1 $ ll file1 -rw-------. 1 vagrant wheel 0 Nov 28 23 :12 file1 $ umask 022 $ mkdir ./tmp1 $ umask 077 $ mkdir ./tmp2 $ ls -dl tmp* drwxr-xr-x. 1 vagrant wheel 0 Nov 28 23 :14 tmp1 drwx------. 1 vagrant wheel 0 Nov 28 23 :14 tmp2 7.6.\u7279\u6b8a\u6743\u9650 \u00b6 \u9664\u4e86\u4e09\u79cd\u5e38\u89c1\u7684\u6743\u9650rwx\uff0c\u8fd8\u6709\u4e09\u79cd\u7279\u6b8a\u6743\u9650\uff1aSUID\uff0cSGID\uff0cSticky\u3002 SUID\uff1a\u5c5e\u4e3bs\u6743\u9650\uff0c\u79f0\u4e3aSet UID \u524d\u63d0\uff1a\u8fdb\u7a0b\u6709\u5c5e\u4e3b\u548c\u5c5e\u7ec4\uff0c\u6587\u4ef6\u6709\u5c5e\u4e3b\u548c\u5c5e\u7ec4 \u4efb\u4f55\u53ef\u6267\u884c\u7a0b\u5e8f\u6587\u4ef6\u80fd\u4e0d\u80fd\u542f\u52a8\u4e3a\u8fdb\u7a0b\uff0c\u53d6\u51b3\u4e8e\u53d1\u8d77\u8005\u5bf9\u7a0b\u5e8f\u6587\u4ef6\u662f\u5426\u62e5\u6709\u6267\u884c\u6743\u9650\u3002 \u542f\u52a8\u4e3a\u8fdb\u7a0b\u4e4b\u540e\uff0c\u5176\u8fdb\u7a0b\u7684\u5c5e\u4e3b\u4e3a\u53d1\u8d77\u8005\u3002 \u8fdb\u7a0b\u8bbf\u95ee\u6587\u4ef6\u662f\u7684\u6743\u9650\uff0c\u53d6\u51b3\u4e8e\u8fdb\u7a0b\u7684\u53d1\u8d77\u8005\u3002 \u53ea\u5bf9\u4e8c\u8fdb\u5236\u53ef\u6267\u884c\u7a0b\u5e8f\u6587\u4ef6\u6709\u6548\u3002\u5f53\u6267\u884c\u8be5\u6587\u4ef6\u65f6\uff0c\u53d1\u8d77\u8005\u5c06\u81ea\u52a8\u5177\u6709\u8be5\u6587\u4ef6\u6240\u6709\u8005\u7684\u6743\u9650\u3002 \u5bf9\u76ee\u5f55\u65e0\u6548\u3002 $ ll file1 -rw-------. 1 vagrant wheel 0 Nov 28 23 :12 file1 $ sudo chmod u+s file1 $ ll file1 -rwS------. 1 vagrant wheel 0 Nov 28 23 :12 file1 \u5982\u679c\u5c5e\u4e3b\u7684 x \u4f4d\u4e0a\u662f-\uff0c\u5219\u5728\u5c5e\u4e3b\u7684 x \u4f4d\u4e0a\u6807\u8bb0\u5927\u5199 S \uff0c\u5426\u5219\u6807\u8bb0\u5c0f\u5199 s \u3002\u5982\u4e0b\uff1a $ chmod 777 file1 $ ll file1 -rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23 :12 file1 $ sudo chmod u+s file1 $ ll file1 -rwsrwxrwx. 1 vagrant wheel 0 Nov 28 23 :12 file1 \u4e0b\u97622\u7ec4\u547d\u4ee4\u5b9e\u73b0\u540c\u6837\u6548\u679c\u3002 sudo chmod 4xxx file1 chmod 777 file1 sudo chmod u+s file1 \u53d6\u6d88SUID\u3002 sudo chmod u-s file1 SGID\uff1a\u5c5e\u7ec4s\u6743\u9650\uff0c\u79f0\u4e3aSet GID \u5982\u679c\u4f5c\u7528\u4e8e\u4e8c\u8fdb\u5236\u53ef\u6267\u884c\u6587\u4ef6\u4e0a\uff0c\u5f53\u6267\u884c\u8be5\u6587\u4ef6\u4e3a\u8fdb\u7a0b\u4e4b\u540e\uff0c\u53d1\u8d77\u8005\u5c06\u81ea\u52a8\u5177\u6709\u8be5\u6587\u4ef6\u6240\u5c5e\u7ec4\u7684\u6743\u9650\uff0c\u8fdb\u7a0b\u7684\u5c5e\u7ec4\u4e3a\u53d1\u8d77\u8005\u7684\u5c5e\u7ec4\u3002 \u5982\u679c\u4f5c\u7528\u4e8e\u76ee\u5f55\u4e0a\uff0c\u5219\u8be5\u76ee\u5f55\u4e0b\u65b0\u5efa\u7acb\u7684\u76ee\u5f55\u548c\u6587\u4ef6\u90fd\u81ea\u52a8\u4ece\u6b64\u76ee\u5f55\u7ee7\u627f\u3002 $ sudo chmod g+s file2 $ ll file2 -rw-r-Sr--. 1 vagrant wheel 0 Nov 28 23 :13 file2 \u5982\u679c\u5c5e\u7ec4\u7684 x \u4f4d\u4e0a\u662f-\uff0c\u5219\u5728\u5c5e\u7ec4\u7684 x \u4f4d\u4e0a\u6807\u8bb0\u5927\u5199 S \uff0c\u5426\u5219\u6807\u8bb0\u5c0f\u5199 s \u3002\u5982\u4e0b\uff1a $ chmod 777 file2 $ ll file2 -rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23 :13 file2 $ sudo chmod g+s file2 $ ll file2 -rwxrwsrwx. 1 vagrant wheel 0 Nov 28 23 :13 file2 \u4e0b\u97622\u7ec4\u547d\u4ee4\u5b9e\u73b0\u540c\u6837\u6548\u679c\u3002 sudo chmod 2xxx file2 chmod 777 file2 sudo chmod g+s file2 \u53d6\u6d88SGID\u3002 sudo chmod g-s file2 \u5bf9\u4e8e\u76ee\u5f55\uff0c\u4e0b\u9762\u6f14\u793a\u53ef\u4ee5\u770b\u5230\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\u7684\u7ee7\u627f\u6027\u3002 $ ll -d data drwxr-xr-x. 1 vagrant bin 0 Nov 28 20 :55 data $ sudo chmod g+s .~ $ ll -d data drwxr-sr-x. 1 vagrant bin 0 Nov 28 20 :55 data $ cd data $ touch file2 $ ll file2 -rw-r--r--. 1 vagrant bin 0 Nov 29 21 :10 file2 $ mkdir tmp3 $ ll -d tmp3 drwxr-sr-x. 1 vagrant bin 0 Nov 29 21 :10 tmp3 Sticky Bit\uff1a\u7b80\u79f0\u4e3aSBIT\u6743\u9650 \u53ea\u9488\u5bf9\u76ee\u5f55\u6709\u6548\u3002\u5b83\u8868\u793a\u53ea\u80fd\u8ba9\u5176\u5c5e\u4e3b\u4ee5\u53caroot\u53ef\u4ee5\u5220\u9664\u3001\u91cd\u547d\u540d\u3001\u79fb\u52a8\u8be5\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u3002 Sticky\u8bbe\u7f6e\u5728\u6587\u4ef6\u4e0a\u65e0\u610f\u4e49\u3002 \u5982\u679c\u5176\u4ed6\u7684 x \u4f4d\u4e0a\u662f-\uff0c\u5219\u5728\u5176\u4ed6\u7684 x \u4f4d\u4e0a\u6807\u8bb0\u5927\u5199 T \uff0c\u5426\u5219\u6807\u8bb0\u5c0f\u5199 t \u3002 $ ll -d .~ drwxr-sr-x. 1 vagrant bin 18 Nov 29 21 :10 .~ $ sudo chmod o+t .~ $ ll -d .~ drwxr-sr-t. 1 vagrant bin 18 Nov 29 21 :10 .~ $ cd data $ touch file1 $ mkdir tmp1 $ ll file1 -rw-r--r--. 1 vagrant bin 0 Nov 29 21 :37 file1 $ ll -d tmp1 drwxr-sr-x. 1 vagrant bin 0 Nov 29 21 :37 tmp1 \u7279\u6b8a\u6743\u9650\u8bbe\u7f6e\u6570\u5b57\u6cd5\uff1a \u8bbe\u7f6eSUID User Group Others r w s r w s r w x r w S BIN 100 1 1 1 1 1 1 1 1 1 1 1 0 OCT 4 7 7 7 6 \u8bbe\u7f6eSGID User Group Others r w x r w s r w x r w S BIN 010 1 1 1 1 1 1 1 1 1 1 1 0 OCT 2 7 7 7 6 \u8bbe\u7f6eSticky Bit - SBIT User Group Others r w x r w x r w t r w T BIN 001 1 1 1 1 1 1 1 1 1 1 1 0 OCT 1 7 7 7 6 7.7.\u8bbe\u5b9a\u6587\u4ef6\u7279\u6b8a\u5c5e\u6027 chattr \u00b6 \u547d\u4ee4\u683c\u5f0f\uff1a chattr [ -RVf ] [ -v version ] [ mode ] files... \u5176\u4e2dmode\u7684\u5b57\u4e32\u683c\u5f0f\uff1a {+|-|=}[aAcCdDeijsStTu] \u5c5e\u6027 i \uff1a \u5982\u679c\u5bf9\u6587\u4ef6\u8bbe\u7f6e i \u5c5e\u6027\uff0c\u90a3\u4e48\u4e0d\u5141\u8bb8\u5bf9\u6587\u4ef6\u8fdb\u884c\u5220\u9664\u3001\u6539\u540d\uff0c\u4e5f\u4e0d\u80fd\u6dfb\u52a0\u548c\u4fee\u6539\u6570\u636e\uff1b \u5982\u679c\u5bf9\u76ee\u5f55\u8bbe\u7f6e i \u5c5e\u6027\uff0c\u90a3\u4e48\u53ea\u80fd\u4fee\u6539\u76ee\u5f55\u4e0b\u6587\u4ef6\u4e2d\u7684\u6570\u636e\uff0c\u4f46\u4e0d\u5141\u8bb8\u5efa\u7acb\u548c\u5220\u9664\u6587\u4ef6\uff1b \u5728openSUSE\u4e0b\u6267\u884c\uff0c\u5206\u533a\u6587\u4ef6\u7c7b\u578b\u662fbtrfs\u683c\u5f0f\u3002 $ touch filetest $ lsattr filetest ---------------------- filetest $ chattr +i filetest chattr: Operation not permitted while setting flags on filetest $ sudo chattr +i filetest $ lsattr filetest ----i----------------- filetest $ rm filetest rm: cannot remove 'filetest' : Operation not permitted $ sudo rm filetest rm: cannot remove 'filetest' : Operation not permitted $ echo \"test\" >> filetest -bash: filetest: Operation not permitted $ sudo echo \"test\" >> filetest -bash: filetest: Operation not permitted $ sudo chattr -i filetest \u5c5e\u6027 a \uff1a \u5982\u679c\u5bf9\u6587\u4ef6\u8bbe\u7f6e a \u5c5e\u6027\uff0c\u90a3\u4e48\u53ea\u80fd\u5728\u6587\u4ef6\u4e2d\u5897\u52a0\u6570\u636e\uff0c\u4f46\u662f\u4e0d\u80fd\u5220\u9664\u548c\u4fee\u6539\u6570\u636e\uff1b \u5982\u679c\u5bf9\u76ee\u5f55\u8bbe\u7f6e a \u5c5e\u6027\uff0c\u90a3\u4e48\u53ea\u5141\u8bb8\u5728\u76ee\u5f55\u4e2d\u5efa\u7acb\u548c\u4fee\u6539\u6587\u4ef6\uff0c\u4f46\u662f\u4e0d\u5141\u8bb8\u5220\u9664\u6587\u4ef6\uff1b \u5728openSUSE\u4e0b\u6267\u884c\uff0c\u5206\u533a\u6587\u4ef6\u7c7b\u578b\u662fbtrfs\u683c\u5f0f\u3002 lsattr filetest ---------------------- filetest $ chattr +a filetest chattr: Operation not permitted while setting flags on filetest $ sudo chattr +a filetest $ echo \"test\" >> filetest $ rm filetest rm: cannot remove 'filetest' : Operation not permitted $ sudo rm filetest rm: cannot remove 'filetest' : Operation not permitted $ sudo chattr -a filetest \u5c5e\u6027 u \uff1a \u8bbe\u7f6e\u6b64\u5c5e\u6027\u7684\u6587\u4ef6\u6216\u76ee\u5f55\uff0c\u5728\u5220\u9664\u65f6\uff0c\u5176\u5185\u5bb9\u4f1a\u88ab\u4fdd\u5b58\uff0c\u4ee5\u4fdd\u8bc1\u540e\u671f\u80fd\u591f\u6062\u590d\uff0c\u5e38\u7528\u6765\u9632\u6b62\u610f\u5916\u5220\u9664\u6587\u4ef6\u6216\u76ee\u5f55\u3002 \u5728Ubuntu\u4e0b\u6267\u884c\uff0c\u5206\u533a\u6587\u4ef6\u7c7b\u578b\u662fext4\u683c\u5f0f\u3002 $ touch filetest $ sudo chattr +u filetest $ lsattr filetest -u------------e------- filetest $ rm filetest \u5c5e\u6027 s \uff1a \u548c u \u76f8\u53cd\uff0c\u5220\u9664\u6587\u4ef6\u6216\u76ee\u5f55\u65f6\uff0c\u4f1a\u88ab\u5f7b\u5e95\u5220\u9664\uff08\u76f4\u63a5\u4ece\u786c\u76d8\u4e0a\u5220\u9664\uff0c\u7136\u540e\u75280\u586b\u5145\u6240\u5360\u7528\u7684\u533a\u57df\uff09\uff0c\u4e0d\u53ef\u6062\u590d\u3002 \u63d0\u793a\uff1a \u547d\u4ee4 chattr \u548c lsattr \u7684\u53ef\u64cd\u4f5c\u5c5e\u6027\u4f9d\u8d56\u4e8e\u6587\u4ef6\u6240\u5904\u5206\u533a\u7684\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\uff0c\u4f8b\u5982\uff0cext4\u548cxfs\u7684\u7ed3\u679c\u4f1a\u6709\u4e0d\u540c\u3002 \u5386\u53f2\uff1a\u547d\u4ee4 chattr \uff08\u7528\u4e8e\u64cd\u4f5c\u5c5e\u6027\uff09\u548c lsattr \uff08\u7528\u4e8e\u5217\u51fa\u5c5e\u6027\uff09\u6700\u521d\u4e13\u7528\u4e8e\u7b2c\u4e8c\u4e2a\u6269\u5c55\u6587\u4ef6\u7cfb\u7edf\u7cfb\u5217\uff08ext2\u3001ext3\u3001ext4\uff09\uff0c\u5e76\u4e14\u4f5c\u4e3a e2fsprogs \u5305\u7684\u4e00\u90e8\u5206\u63d0\u4f9b\u3002\u7136\u800c\uff0c\u6b64\u529f\u80fd\u5df2\u5168\u90e8\u6216\u90e8\u5206\u6269\u5c55\u5230\u8bb8\u591a\u5176\u4ed6\u7cfb\u7edf\uff0c\u5305\u62ec XFS\u3001ReiserFS\u3001JFS \u548c OCFS2\u3002 btrfs \u6587\u4ef6\u7cfb\u7edf\u5305\u62ec\u5c5e\u6027\u529f\u80fd\uff0c\u5305\u62ec C \u6807\u5fd7\uff0c\u7531\u4e8e\u4e0e CoW \u76f8\u5173\u7684\u6027\u80fd\u8f83\u6162\uff0c\u5b83\u5173\u95ed\u4e86btrfs\u7684\u5185\u7f6e\u5199\u65f6\u590d\u5236 (CoW) \u529f\u80fd\u3002 8.\u8bbf\u95ee\u63a7\u5236\u5217\u8868ACL \u00b6 8.1.ACL \u00b6 ACL\u7684\u5168\u79f0\u662fAccess Control List\u3002 \u4f20\u7edf\u7684POSIX\u6743\u9650\u6982\u5ff5\u4f7f\u7528\u4e09\u79cd\u7528\u6237\u7c7b\u578b\u6765\u5206\u914d\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6743\u9650\uff1a\u6240\u6709\u8005Owning Owner\uff0c\u6240\u6709\u8005\u7ec4Owning Group\u548c\u5176\u4ed6\u7528\u6237Other Users\u3002\u53ef\u4ee5\u4e3a\u6bcf\u4e2a\u7528\u6237\u7c7b\u578b\u8bbe\u7f6e\u4e09\u4e2a\u6743\u9650\u4f4d\uff0c\u8d4b\u4e88\u8bfb\uff08r\uff09\uff0c\u5199\uff08w\uff09\u548c\u6267\u884c\uff08x\uff09\u7684\u6743\u9650\u3002 \u6240\u6709\u8005Owning Owner\u6743\u9650\uff08\u5c5e\u4e3b\u6743\u9650\uff09 \u5c5e\u7ec4Owning Group\u6743\u9650 \u5176\u4ed6\uff08\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\uff09\u7528\u6237Other Users\u7684\u6743\u9650 \u4f20\u7edf\u7684\u4e09\u79cd\u6743\u9650\u9002\u7528\u4e8e\u5927\u591a\u6570\u5b9e\u9645\u6848\u4f8b\u3002\u4f46\u662f\uff0c\u5bf9\u4e8e\u66f4\u590d\u6742\u7684\u573a\u666f\u6216\u66f4\u9ad8\u7ea7\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u7cfb\u7edf\u7ba1\u7406\u5458\u5fc5\u987b\u4f7f\u7528\u8bb8\u591a\u6280\u5de7\u6765\u89c4\u907f\u4f20\u7edf\u6743\u9650\u7684\u9650\u5236\u3002 \u8bbf\u95ee\u63a7\u5236\u5217\u8868ACL\u63d0\u4f9b\u4e86\u5bf9\u4f20\u7edf\u6587\u4ef6\u6743\u9650\u6982\u5ff5\u7684\u6269\u5c55\u3002\u5b83\u4eec\u5141\u8bb8\u6211\u4eec\u4e3a\u5355\u4e2a\u7528\u6237\u6216\u7ec4\u5206\u914d\u6743\u9650\uff0c\u5373\u4f7f\u8fd9\u4e9b\u7528\u6237\u6216\u7ec4\u4e0e\u539f\u59cb\u6240\u6709\u8005\u6216\u5c5e\u7ec4\u4e0d\u5bf9\u5e94\u3002 ACL\u662fLinux\u5185\u6838\u7684\u4e00\u9879\u529f\u80fd\uff0c\u652f\u6301Ext\u2154/4\uff0cXFS\u548cBtrFS\u6587\u4ef6\u7cfb\u7edf\u4ee5\u53ca\u5176\u4ed6\u6587\u4ef6\u7cfb\u7edf\u3002 \u4f7f\u7528ACL\uff0c\u6211\u4eec\u53ef\u4ee5\u521b\u5efa\u590d\u6742\u7684\u65b9\u6848\uff0c\u800c\u65e0\u9700\u5728\u5e94\u7528\u7a0b\u5e8f\u7ea7\u522b\u4e0a\u53bb\u5b9e\u73b0\u590d\u6742\u7684\u6743\u9650\u6a21\u578b\u3002\u5728\u4f7f\u7528\u63d0\u4f9bSamba\u6587\u4ef6\u548c\u6253\u5370\u670d\u52a1\u7684Linux\u670d\u52a1\u5668\u66ff\u6362Windows\u670d\u52a1\u5668\u7684\u60c5\u51b5\u4e0b\uff0cACL\u7684\u4f18\u52bf\u975e\u5e38\u660e\u663e\u3002\u7531\u4e8eSamba\u652f\u6301ACL\uff0c\u56e0\u6b64\u53ef\u4ee5\u5728Linux\u670d\u52a1\u5668\u548cWindows\u4e2d\u914d\u7f6e\u7528\u6237\u6743\u9650\u3002 \u901a\u8fc7ACL\u6765\u5141\u8bb8\u5bf9\u6240\u6709\u8005\u7528\u6237\u4e4b\u5916\u7684\u5355\u4e2a\u7528\u6237\u8fdb\u884c\u6587\u4ef6\u5199\u6743\u9650\u662f\u4e00\u79cd\u7b80\u5355\u7684\u65b9\u6848\u3002\u4f7f\u7528\u4f20\u7edf\u65b9\u6cd5\uff0c\u6211\u4eec\u5fc5\u987b\u521b\u5efa\u4e00\u4e2a\u65b0\u7ec4\uff0c\u4f7f\u4e24\u4e2a\u7528\u6237\u6210\u4e3a\u8be5\u7ec4\u7684\u6210\u5458\uff0c\u5c06\u8be5\u6587\u4ef6\u7684\u6240\u6709\u7ec4\u66f4\u6539\u4e3a\u65b0\u7ec4\uff0c\u7136\u540e\u6388\u4e88\u8be5\u7ec4\u6587\u4ef6\u7684\u5199\u6743\u9650\u3002\u521b\u5efa\u7ec4\u5e76\u4f7f\u4e24\u4e2a\u7528\u6237\u6210\u4e3a\u8be5\u7ec4\u7684\u6210\u5458\u5219\u9700\u8981\u5229\u7528root\u6743\u9650\u6765\u5b9e\u73b0\u3002 \u4f7f\u7528ACL\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u4f7f\u6240\u6709\u8005\u548c\u6307\u5b9a\u7528\u6237\u5bf9\u6587\u4ef6\u5177\u6709\u5199\u6743\u9650\u6765\u5b9e\u73b0\u76f8\u540c\u7684\u7ed3\u679c\u3002 \u6b64\u65b9\u6cd5\u7684\u53e6\u4e00\u4e2a\u4f18\u70b9\u662f\u7cfb\u7edf\u7ba1\u7406\u5458\u65e0\u9700\u53c2\u4e0e\u521b\u5efa\u7ec4\u3002\u7528\u6237\u53ef\u4ee5\u81ea\u5df1\u51b3\u5b9a\u6388\u4e88\u8c01\u8bbf\u95ee\u5176\u6587\u4ef6\u7684\u6743\u9650\u3002 \u63d0\u793a\uff1a \u4f7f\u7528ACL\u65f6 ls \u7684\u8f93\u51fa\u7ed3\u679c\u4f1a\u53d1\u751f\u53d8\u5316\u3002\u6dfb\u52a0\u4e00\u4e2a\u52a0\u53f7+ \u6765\u8bf4\u660e\u5df2\u4e3a\u6b64\u6587\u4ef6\u5b9a\u4e49ACL\uff0c\u4e14\u5b9a\u4e49ACL\u540e\uff0c\u6240\u663e\u793a\u7684\u5c5e\u7ec4\u6743\u9650\u662fACL\u63a9\u7801\u7684\u503c\uff0c\u800c\u4e0d\u518d\u662f\u539f\u6765\u5c5e\u7ec4\u7684\u6743\u9650\u3002 8.2.ACL\u7684\u57fa\u672c\u7c7b\u578b \u00b6 Minimal ACLs\uff08\u6700\u5c0fACL\uff09\uff08\u5b9e\u9645\u7528\u9014\uff1a\u4e0ePOSIX\u6743\u9650\u76f8\u540c\uff09 \u4e0e\u6587\u4ef6\u6a21\u5f0f\u6743\u9650\u4f4d\u7b49\u6548\u7684ACL\u79f0\u4e3a\u6700\u5c0fACL \u5206\u4e09\u79cd\u7c7b\u578b\u7684ACL\u6761\u76ee\uff0c\u8fd9\u4e9b\u5bf9\u5e94\u4e8e\u6587\u4ef6\u548c\u76ee\u5f55\u7684\u4f20\u7edf\u6743\u9650\u4f4d Owning User \u6240\u6709\u8005 Owning Group \u6240\u6709\u8005\u7ec4 Others \u5176\u4ed6\u7ec4 Extended ACLs\uff08\u6269\u5c55ACL\uff09 \u5177\u6709\u591a\u4e8e\u4e0a\u8ff0\u4e09\u4e2aACL\u6761\u76ee\u7684ACL\u79f0\u4e3a\u6269\u5c55ACL \u6269\u5c55ACL\u8fd8\u5305\u542b\u63a9\u7801\u6761\u76ee\uff0c\u53ef\u4ee5\u5305\u542b\u4efb\u610f\u6570\u91cf\u7684\u6307\u5b9a\u7528\u6237\u548c\u6307\u5b9a\u7ec4\u6761\u76ee 8.3.ACL\u672f\u8bed \u00b6 \u7528\u6237\u7c7b\uff08User classes\uff09\u3002 \u4f20\u7edf\u7684POSIX\u6743\u9650\u6982\u5ff5\u4f7f\u7528\u4e09\u79cd\u7528\u6237\u7c7b\u6765\u5206\u914d\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6743\u9650\uff1a\u6240\u6709\u8005Owning Owner\uff0c\u6240\u6709\u8005\u7ec4Owning Group\u548c\u5176\u4ed6\u7528\u6237Other Users\u3002\u53ef\u4ee5\u4e3a\u6bcf\u4e2a\u7528\u6237\u7c7b\u578b\u8bbe\u7f6e\u4e09\u4e2a\u6743\u9650\u4f4d\uff0c\u8d4b\u4e88\u8bfb\uff08r\uff09\uff0c\u5199\uff08w\uff09\u548c\u6267\u884c\uff08x\uff09\u7684\u6743\u9650\u3002 Owner class \u6240\u6709\u8005\u7c7b Group class \u7ec4\u7c7b Other class \u5176\u4ed6\u7c7b ACL\u8bbf\u95ee\u6743\u9650\uff08Access ACL\uff09\uff1a\u786e\u5b9a\u5404\u79cd\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\uff08\u6587\u4ef6\u548c\u76ee\u5f55\uff09\u7684\u7528\u6237\u548c\u7ec4\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u9ed8\u8ba4ACL\uff08Default ACL\uff09\uff1a\u53ea\u80fd\u5e94\u7528\u4e8e\u76ee\u5f55\u3002 \u5b83\u4eec\u786e\u5b9a\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u5728\u521b\u5efa\u65f6\u4ece\u5176\u7236\u76ee\u5f55\u7ee7\u627f\u7684\u6743\u9650\u3002 ACL\u6761\u76ee\uff08ACL entry\uff09\uff1a \u6bcf\u4e2aACL\u7531\u4e00\u7ec4ACL\u6761\u76ee\u7ec4\u6210\u3002 ACL\u6761\u76ee\u5305\u542b\u7c7b\u578b\uff08type\uff09\uff0c\u6761\u76ee\u5f15\u7528\u7684\u7528\u6237\u6216\u7ec4\u7684\u9650\u5b9a\u7b26\uff08qualifier\uff09\uff0c\u4ee5\u53ca\u4e00\u7ec4\u6743\u9650\uff08permissions\uff09\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u6761\u76ee\u7c7b\u578b\uff0c\u672a\u5b9a\u4e49\u7ec4\u6216\u7528\u6237\u7684\u9650\u5b9a\u7b26\u3002 8.4.ACL\u6743\u9650\u5206\u7c7b \u00b6 Named user \u6307\u5b9a\u7528\u6237: Lets you assign permissions to individual users. \u5141\u8bb8\u6211\u4eec\u4e3a\u6307\u5b9a\u7528\u6237\u5206\u914d\u6743\u9650\u3002 Named group \u6307\u5b9a\u7ec4: Lets you assign permissions to individual groups. \u5141\u8bb8\u6211\u4eec\u4e3a\u5236\u5b9a\u7ec4\u5206\u914d\u6743\u9650\u3002 Mask \u63a9\u7801: Lets you limit the permissions granted to named users or groups. \u5141\u8bb8\u6211\u4eec\u9650\u5236\u7ed9\u4e88\u6307\u5b9a\u7528\u6237\u6216\u6307\u5b9a\u7ec4\u7684\u6743\u9650\u3002 \u6240\u4ee5\u53ef\u80fd\u7684ACL\u7c7b\u578b Type Text Form owner user::rwx named user user:name:rwx owning group group::rwx named group group:name:rwx mask mask::rwx other other::rwx \u4e0ePOSIX.1\u6743\u9650\u6a21\u578b\u4e0d\u540c\uff0c\u7ec4\u7c7bgroup class\u53ef\u4ee5\u5305\u542b\u5177\u6709\u4e0d\u540c\u6743\u9650\u96c6\u7684ACL\u6761\u76ee\uff0c\u56e0\u6b64\u5355\u72ec\u7684\u7ec4\u7c7b\u6743\u9650\u4e0d\u518d\u8db3\u4ee5\u8868\u793a\u5b83\u5305\u542b\u7684\u6240\u6709ACL\u6761\u76ee\u7684\u6240\u6709\u8be6\u7ec6\u6743\u9650\u3002 \u56e0\u6b64\uff0c\u7ec4\u7c7b\u578b\u6743\u9650\u7684\u542b\u4e49\u88ab\u91cd\u65b0\u5b9a\u4e49\u3002\u5728\u65b0\u8bed\u4e49\u4e0b\uff0c\u7ec4\u7c7b\u578b\u6743\u9650\u8868\u793a\u7ec4\u7c7b\u4e2d\u7684\u4efb\u4f55\u6761\u76ee\u5c06\u6388\u4e88\u7684\u6743\u9650\u7684**\u4e0a\u9650**\uff08upper bound\uff09\u3002 \u6b64\u4e0a\u9650\u5c5e\u6027\u53ef\u786e\u4fdd\u5728\u4f7f\u7528ACL\u63a7\u5236\u540e\uff0c\u5e94\u7528\u7a0b\u5e8f\u4e0d\u4f1a\u7a81\u7136\u6216\u8005\u610f\u5916\u5730\u6388\u4e88\u989d\u5916\u7684\u6743\u9650\u3002 \u5728\u6700\u5c0fACL\u4e2d\uff0c\u7ec4\u7c7b\u6743\u9650\u4e0e\u6240\u6709\u8005\u7ec4\u6743\u9650\u76f8\u540c\u3002\u5728\u6269\u5c55ACL\u4e2d\uff0c\u7ec4\u7c7b\u53ef\u4ee5\u5305\u542b\u5176\u4ed6\u7528\u6237\u6216\u7ec4\u7684\u6761\u76ee\u3002\u8fd9\u4f1a\u5bfc\u81f4\u4e00\u4e2a\u95ee\u9898\uff1a\u8fd9\u4e9b\u9644\u52a0\u6761\u76ee\u4e2d\u7684\u4e00\u4e9b\u53ef\u80fd\u62e5\u6709\u672a\u5305\u542b\u5728\u6240\u6709\u8005\u7ec4\u6761\u76ee\uff08owning group entry\uff09\u4e2d\u7684\u6743\u9650\uff0c\u56e0\u6b64\u6240\u6709\u8005\u7ec4\u6761\u76ee\u6743\u9650\u53ef\u80fd\u4e0e\u7ec4\u7c7b\u6743\u9650\uff08group class\uff09\u4e0d\u540c\u3002 \u901a\u8fc7\u63a9\u7801\uff08mask entry\uff09\u89e3\u51b3\u4e86\u8fd9\u4e2a\u95ee\u9898\u3002 \u4f7f\u7528\u6700\u5c0fACL\uff0c\u7ec4\u7c7b\u6743\u9650\u6620\u5c04\u5230\u6240\u6709\u8005\u7ec4\u6761\u76ee\u6743\u9650\u3002With minimal ACLs, the group class permissions map to the owning group entry permissions. \u4f7f\u7528\u6269\u5c55ACL\u65f6\uff0c\u7ec4\u7c7b\u6743\u9650\u6620\u5c04\u5230\u63a9\u7801\u6761\u76ee\u6743\u9650\uff0c\u800c\u6240\u6709\u8005\u7ec4\u6761\u76ee\u4ecd\u5b9a\u4e49\u62e5\u6709\u7ec4\u6743\u9650\u3002With extended ACLs, the group class permissions map to the mask entry permissions, whereas the owning group entry still defines the owning group permissions. 8.5.ACL\u64cd\u4f5c\u547d\u4ee4 \u00b6 \u8bbe\u5b9aACL\u6743\u9650\uff1a setfacl Syntax: setfacl [OPTIONS] [ACL-ENTRIES] Option Description -m : Add or modify an ACL entry -x : Remove an ACL entry -d : Set a default ACL -b : Remove all extended ACL entries -M : restore ACLs that have been written to a file \u6ce8\u610f\uff1a--set\u9009\u9879\u4f1a\u628a\u539f\u6709\u7684ACL\u9879\u90fd\u5220\u9664\uff0c\u7528\u65b0\u7684\u66ff\u4ee3\uff0c\u6240\u4ee5\u4e00\u5b9a\u8981\u5305\u542bUGO\u7684\u8bbe\u7f6e\uff0c\u4e0d\u80fd\u50cf-m\u533b\u9662\u53ea\u6dfb\u52a0ACL\u3002 setfacl --set u::rw,u:vagrant:rw,g::r,o::- file1 \u8bfb\u53d6ACL\u6743\u9650\uff1a getfacl Syntax: getfacl [OPTIONS] Option Description -a : Display the file access control list -d : Display the default access control list -R : List the ACLs of all files and directories recursively 8.6.ACL\u5b9e\u4f8b\u89e3\u6790 \u00b6 8.6.1.\u5b9e\u4f8b\u63cf\u8ff0 \u00b6 \u9879\u76ee\u76ee\u5f55 ~/project1 \u9879\u76ee\u7ecf\u7406 pm1 \u5bf9\u8fd9\u4e2a\u76ee\u5f55\u62e5\u6709\u8bbf\u95ee\u548c\u4fee\u6539\u6743\u9650 \u9879\u76ee\u6210\u5458 tm1 \u53ef\u4ee5\u8bbf\u95ee\u548c\u4fee\u6539\u8fd9\u4e2a\u76ee\u5f55 \u975e\u9879\u76ee\u6210\u5458 tm2 \u4e0d\u80fd\u8bbf\u95ee ~/project1 \u76ee\u5f55\u3002 \u9879\u76ee\u76ee\u5f55 ~/project1 \u7684\u6743\u9650\u89c4\u5212 \u9879\u76ee\u7ecf\u7406 pm1 \u662f\u8fd9\u4e2a\u76ee\u5f55\u7684\u5c5e\u4e3b\uff0c\u6743\u9650\u4e3a rwx \u9879\u76ee\u7ecf\u7406 pm1 \u5c5e\u4e8e project1 \u7ec4 \u9879\u76ee\u6210\u5458 tm1 \u4e0e pm1 \u5728\u540c\u4e00\u4e2a project1 \u7ec4\uff0c\u6743\u9650\u662f rw \u5176\u4ed6\u4eba\u7684\u6743\u9650\u8bbe\u5b9a\u4e3a 0 \u9879\u76ee\u4e34\u65f6\u6210\u5458tm2\u7684\u6743\u9650\u9700\u6c42 \u80fd\u8bbf\u95ee project1 \u76ee\u5f55\uff0c\u4f46\u53ea\u80fd\u5177\u6709 r \u548c x \u6743\u9650 \u89e3\u51b3\u65b9\u6cd5 \u5f53\u51fa\u73b0\u8fd9\u79cd\u60c5\u51b5\u65f6\uff0c\u666e\u901a\u6743\u9650\u4e2d\u7684\u4e09\u79cd\u8eab\u4efd\uff08owner\uff0cgroup\uff0cothers\uff09\u5c31\u4e0d\u80fd\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0c\u800cACL\u6743\u9650\u53ef\u4ee5\u3002 \u5728\u4f7f\u7528ACL\u6743\u9650\u7ed9\u7528\u6237 tm2 \u965a\u4e88\u6743\u9650\u65f6\uff0c tm2 \u65e2\u4e0d\u662f ~/project1 \u76ee\u5f55\u7684\u5c5e\u4e3b\uff0c\u4e5f\u4e0d\u662f\u5c5e\u7ec4\uff0c\u4ec5\u4ec5\u8d4b\u4e88\u7528\u6237 tm2 \u9488\u5bf9 ~/project1 \u76ee\u5f55\u7684r-x\u6743\u9650\uff0c \u5c5e\u4e8e\u5355\u72ec\u6307\u5b9a\u7528\u6237\u5e76\u5355\u72ec\u5206\u914d\u6743\u9650\uff0c\u89e3\u51b3\u4e86\u7528\u6237\u8eab\u4efd\u4e0d\u8db3\u7684\u95ee\u9898\u3002 \u62d3\u5c55\u95ee\u9898 \u7ed9 ~/project1 \u76ee\u5f55\u6dfb\u52a0\u5176\u4ed6\u7ec4 project2 \u7684\u8bbf\u95ee\u6743\u9650 \u901a\u8fc7 mask \u6765\u8c03\u6574\u7528\u6237 tm2 \u5b9e\u9645\u6709\u6548\u6743\u9650 \u9ed8\u8ba4ACL\u6743\u9650 \u9012\u5f52ACL\u6743\u9650 \u5220\u9664ACL\u6743\u9650 8.6.2.\u521d\u59cb\u5316\u73af\u5883 \u00b6 \u521b\u5efa\u6d4b\u8bd5\u7528\u6237 $ whoami vagrant $ sudo groupadd project1 $ sudo groupadd project2 $ sudo useradd -m -g project1 pm1 $ sudo useradd -m -g project1 tm1 $ sudo useradd -m -g project2 tm2 $ sudo passwd pm1 $ sudo passwd tm1 $ sudo passwd tm2 $ cat /etc/group ...... project1:x:1535: project2:x:1536: ...... $ cat /etc/passwd ...... pm1:x:2003:1535::/home/pm1:/bin/bash tm1:x:2004:1535::/home/tm1:/bin/bash tm2:x:2005:1536::/home/tm2:/bin/bash ...... \u521b\u5efa\u6d4b\u8bd5\u76ee\u5f55 project1 , \u6307\u5b9a project1 \u76ee\u5f55\u7684\u6743\u9650\uff0c\u521b\u5efa\u6d4b\u8bd5\u6587\u4ef6 file1 \u3002 $ su - pm1 $ cd ~ $ mkdir project1 $ ls -dl project1 drwxr-xr-x. 1 pm1 project1 0 Dec 4 06 :25 project1 $ chmod 770 project1/ $ ls -dl project1 drwxrwx---. 1 pm1 project1 0 Dec 4 06 :25 project1 $ echo \"hello from $USER \" > ./project1/file1 $ cat ./project1/file1 hello from pm1 \u76ee\u5f55 project1 \u5f53\u524d\u6743\u9650\u5feb\u7167 \u5c5e\u4e3b\uff1a pm1 \uff0c\u5bf9 ~/project1 \u76ee\u5f55\u6709 rwx \u6743\u9650 \u5c5e\u7ec4\uff1a project1 \uff0c\u5305\u542b\u7528\u6237 pm1 \u548c tm1 \uff0c\u5bf9 ~/project1 \u76ee\u5f55\u6709 rwx \u6743\u9650 \u5176\u4ed6\u7ec4\uff1a\u6ca1\u6709\u8bbf\u95ee\u6743\u9650 \u76ee\u5f55 ~/project1 \u5f53\u524d\u7684ACL\u5feb\u7167 $ getfacl ./project1/ # file: home/pm1/project1/ # owner: pm1 # group: project1 user::rwx group::rwx other::--- 8.6.3.\u6dfb\u52a0ACL\u6743\u9650 \u00b6 \u7ed9 ~/project1 \u76ee\u5f55\u6dfb\u52a0\u65b0\u7528\u6237 tm2 \uff0c\u6743\u9650\u4e3a rwx \u3002\u76ee\u5f55 ~/project1 \u7684\u66f4\u65b0\u540e\u7684\u6743\u9650\u4f4d\u53d8\u6210\u4e86 drwxrwx---+ \u3002 $ su - pm1 $ setfacl -m u:tm2:rx ./project1/ $ ls -dl ./project1 drwxrwx---+ 1 pm1 project1 0 Dec 4 06 :25 project1 $ getfacl ~/project1/ # file: project1 \uff08\u6587\u4ef6\u540d\uff09 # owner: pm1 \uff08Owner \u6587\u4ef6\u5c5e\u4e3b\uff09 # group: project1 \uff08Owing Group \u6587\u4ef6\u5c5e\u7ec4\uff09 user::rwx \uff08Ower\u6587\u4ef6\u5c5e\u4e3b\u7684\u6743\u9650\uff0c\u7528\u6237\u540d\u680f\u662f\u7a7a\u7684\uff0c\u8bf4\u660e\u662f\u5c5e\u4e3bOwner\u7684\u6743\u9650\uff09 user:tm2:r-x \uff08Named User \u6307\u5b9a\u7528\u6237\u7684\u6743\u9650\uff0c\u7528\u6237tm2\u7684\u6743\u9650\uff09 group::rwx \uff08Owing Group \u6587\u4ef6\u5c5e\u7ec4\u7684\u6743\u9650\uff0c\u7ec4\u540d\u680f\u662f\u7a7a\u7684\uff0c\u8bf4\u660e\u662f\u5c5e\u7ec4\u7684\u6743\u9650\uff09 \uff08Named Group \u6307\u5b9a\u7528\u6237\u7ec4\u7684\u6743\u9650\uff0c\u6b64\u65f6\u672a\u6307\u5b9a\uff09 mask::rwx \uff08mask\u6743\u9650\uff09 other::--- \uff08\u5176\u4ed6\u4ebaother\u7684\u6743\u9650\uff09 \u7ed9 ~/project1 \u76ee\u5f55\u6dfb\u52a0\u65b0\u7ec4 project2 \u7684\u6743\u9650 rwx $ su - pm1 $ setfacl -m g:project2:rwx ./project1/ $ ls -dl ./project1 drwxrwx---+ 1 pm1 project1 0 Dec 4 06 :46 ./project1 $ getfacl ./project1 # file: project1 # owner: pm1 # group: project1 user::rwx user:tm2:r-x ( \u7528\u6237tm2\u62e5\u6709\u4e86r-x\u6743\u9650\uff09 group::rwx group:project2:rwx ( \u7528\u6237\u7ec4project2\u62e5\u6709\u4e86rwx\u6743\u9650\uff09 mask::rwx other::--- \u6709\u6548\u6743\u9650\u7684\u8ba1\u7b97\uff1a \u5f53\u524d ~/project1 \u76ee\u5f55\u7684 mask \u662f rwx \uff0c tm2 \u7684\u6743\u9650\u662f r-x \uff0c\u4e8c\u8005\u8fdb\u884cAND\u64cd\u4f5c\uff0c tm2 \u7684\u5b9e\u9645\u6743\u9650\u662f r-x tm2: r - x ( 1 0 1 ) mask: r w x ( 1 1 1 ) --------------------- result: r - x ( 1 0 1 ) \u5bf9\u7167\u4e0b\u9762\u7684\u89c4\u5219\uff0c\u9a8c\u8bc1\u7528\u6237 tm2 \u5bf9 ~/project1 \u76ee\u5f55\u7684\u5b9e\u9645\u6743\u9650\u3002 su - tm2 \u80fd\u8fdb\u5165\u76ee\u5f55 project1 \uff0c\u8bf4\u660e\u5f53\u524d\u7528\u6237\u5177\u6709\u76ee\u5f55 project1 \u7684 r-x \u6743\u9650\u3002 $ whoami tm2 $ cd /home/pm1/project1/ \u80fd\u5217\u51fa\u76ee\u5f55 project1 \u4e0b\u6587\u4ef6\u5217\u8868\uff0c\u53ef\u4ee5\u67e5\u770b\u6587\u4ef6 file \u7684\u5185\u5bb9\uff0c\u8bf4\u660e\u5f53\u524d\u7528\u6237\u5177\u6709\u76ee\u5f55 project1 \u7684 r-x \u6743\u9650\u3002 $ pwd /home/pm1/project1 $ whoami tm2 $ ls -l -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 $ cat file1 hello from pm1 \u5bf9\u76ee\u5f55 project1 \u4e0d\u5177\u6709 w \u6743\u9650\uff0c\u6240\u4ee5\u65e0\u6cd5\u521b\u5efa\u3001\u5220\u9664\u6216\u4fee\u6539\u76ee\u5f55\u4e0b\u7684\u4efb\u4f55\u6587\u4ef6\u6216\u5b50\u76ee\u5f55\u3002 $ pwd /home/pm1/project1 $ whoami tm2 $ touch file2 touch: cannot touch 'file2' : Permission denied $ echo \"hello from $USER \" >> file1 -bash: file1: Permission denied 8.6.4.\u4fee\u6539mask\u6743\u9650 \u00b6 \u8c03\u6574 ~/project1 \u76ee\u5f55\u7684 mask \u4e3a r-- \uff0c\u5219 tm2 \u7684\u5b9e\u9645\u6743\u9650\u662f r-- $ su - pm1 $ cd ~ $ setfacl -m m::r ./project1/ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- (\u7528\u6237tm2\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u53d8\u4e3ar--) group::rwx #effective:r-- (\u5c5e\u7ec4project1\u7ec4\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u53d8\u4e3ar--) group:project2:rwx #effective:r-- (\u5176\u4ed6\u7ec4project2\u7ec4\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u53d8\u4e3ar--) mask::r-- ( mask\u53d8\u5316\uff0c\u5bfc\u81f4\u4e0a\u8ff0\u4e24\u4e2agroup\u7684\u6709\u6548\u6743\u9650\u90fd\u53d1\u751f\u4e86\u53d8\u5316 ) other::--- \u6709\u6548\u6743\u9650\u7684\u8ba1\u7b97\uff1a \u5f53\u524d ~/project1 \u76ee\u5f55\u7684 mask \u662f r-- \uff0c\u7528\u6237 tm2 \u3001\u7ec4 project2 \u7684\u5b9e\u9645\u6743\u9650\u662f r-- \u3002 tm2: r - w ( 1 0 1 ) mask: r - - ( 1 0 0 ) --------------------- result: r - - ( 1 0 0 ) \u63d0\u793a\uff1a \u7528\u6237\u548c\u7528\u6237\u7ec4\u6240\u8bbe\u5b9a\u7684\u6743\u9650\u5fc5\u987b\u5728mask\u6743\u9650\u8bbe\u5b9a\u7684\u8303\u56f4\u4e4b\u5185\u624d\u80fd\u751f\u6548\uff0cmask\u6743\u9650\u5c31\u662f\u6700\u5927\u6709\u6548\u6743\u9650\u3002 8.6.5.\u6709\u6548\u6743\u9650\u5206\u6790 \u00b6 \u5728POSIX\u6743\u9650\u6a21\u578b\u548cACL\u6743\u9650\u53e0\u52a0\u4f5c\u7528\u4e0b\uff0c\u7528\u6237\u7684\u5b9e\u9645\u6743\u9650\u5206\u6790\u3002 $ getfacl ./project1/ # file: project1/ # owner: pm1 <----Owner # group: project1 <----owning group user::rwx <----owner 's permissions user:tm2:r-x #effective:r-- <----named user' s permissions group::rwx #effective:r-- <----owning group's permissions group:project2:rwx #effective:r-- <----named group's permissions mask::r-- <----masks for named user and named group other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- \u6240\u6709\u8005ower\u548c\u5176\u4ed6\u7528\u6237other\u6761\u76ee\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\u603b\u662f\u6709\u6548\u7684\u3002\u4e0a\u4f8b\u4e2d\u7684user\u6761\u76ee\u548cother\u6761\u76ee\u3002 \u9664\u4e86\u63a9\u7801\u6761\u76ee\uff0c\u6240\u6709\u5176\u4ed6\u6761\u76ee\uff08\u6bd4\u5982\u6307\u5b9a\u7528\u6237named user\uff09\u53ef\u4ee5\u662f\u6709\u6548\u7684\u6216\u88ab\u5c4f\u853d\u7684\u3002 \u6307\u5b9a\u7528\u6237\uff08named user\uff09\uff0c\u6240\u6709\u8005\u7ec4\uff08owning group\uff09\u6216\u6307\u5b9a\u7ec4\uff08named group\uff09\u4ee5\u53ca\u63a9\u7801mask\u6761\u76ee\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\uff0c\u6709\u6548\u6743\u9650\u662f\u4ed6\u4eec\u6743\u9650\u8fdb\u884c\u903b\u8f91AND\u540e\u7684\u7ed3\u679c\uff0c\u800c\u4e0d\u662f\u5355\u72ec\u7684\u63a9\u7801\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\u6216\u8005\u5404\u81ea\u6761\u76ee\u4e2d\u5b9a\u4e49\u7684\u6743\u3002 \u6709\u6548\u6743\u9650\u8ba1\u7b97\u65b9\u6cd5\u5982\u4e0b\uff0c\u6ce8\u610f\uff0c ls \u547d\u4ee4\u4e2d\u663e\u793a\u51fa\u6765\u7684\u6743\u9650\uff0c\u4e0e\u5b9e\u9645\u7684ACL\u6743\u9650\u662f\u6709\u5dee\u522b\u7684\u3002 tm2: r - w ( 1 0 1 ) group: r w x ( 1 1 1 ) named group: r w x ( 1 1 1 ) mask: r - - ( 1 0 0 ) --------------------------- result: r - - ( 1 0 0 ) \u5c0f\u8d34\u58eb\uff1a \u4e0e\u6587\u4ef6\u6a21\u5f0f\u6743\u9650\u4f4d\u7b49\u6548\u7684ACL\u79f0\u4e3a\u6700\u5c0fACL\uff0c\u5373POSIX\u4f20\u7edf\u6743\u9650\u3002 \u542b\u63a9\u7801mask\u7b49\u5176\u4ed6\u6743\u9650\u6761\u76ee\u7684ACL\u79f0\u4e3a\u6269\u5c55ACL\u3002 \u5728\u6700\u5c0f\u548c\u6269\u5c55ACL\u60c5\u5f62\u4e0b\uff0c\u6240\u6709\u8005\u7c7b\u6743\u9650\uff08owner\uff09\u90fd\u662f\u6620\u5c04\u5230ACL\u7684\u6240\u6709\u8005\u6761\u76ee\u3002 \u5176\u4ed6\u7c7b\u6743\u9650\u6620\u5c04\u5230\u5176\u5404\u81ea\u7684ACL\u6761\u76ee\u3002 \u5728\u6269\u5c55ACL\u60c5\u5f62\u4e0b\uff0c\u7ec4\u7c7b\u6743\u9650\u7684\u6620\u5c04\u662f\u4e0d\u540c\u7684\u3002 \u5bf9\u4e8e\u6ca1\u6709\u63a9\u7801\u7684\u6700\u5c0fACL\uff0c\u7ec4\u7c7b\u6743\u9650\u5c06\u6620\u5c04\u5230ACL\u6240\u6709\u8005\u7ec4\u6761\u76ee\u3002 \u5bf9\u4e8e\u5e26\u6709\u63a9\u7801\u7684\u6269\u5c55ACL\uff0c\u7ec4\u7c7b\u6743\u9650\u5c06\u6620\u5c04\u5230\u63a9\u7801\u6761\u76ee\u3002 \u901a\u8fc7\u6743\u9650\u4f4d\u8fdb\u884c\u5206\u914d\u7684\u6743\u9650\u4ee3\u8868\u4e86\u901a\u8fc7ACL\u8fdb\u884c\u5206\u914d\u7684\u6743\u9650\u7684\u4e0a\u9650\u3002 \u6ca1\u6709\u5728\u8fd9\u91cc\u4f53\u73b0\u7684\u4efb\u4f55\u6743\u9650\uff0c\u8981\u4e48\u4e0d\u5728ACL\u4e2d\uff0c\u8981\u4e48\u65e0\u6548\u3002 \u5bf9\u6743\u9650\u4f4d\u6240\u505a\u7684\u66f4\u6539\u5c06\u7531ACL\u53cd\u6620\uff0c\u53cd\u4e4b\u4ea6\u7136\u3002 8.6.6.\u9ed8\u8ba4ACL\u6743\u9650 \u00b6 $ su - pm1 $ touch ./project1/file2 $ mkdir ./project1/cloud $ ll ./project1/ drwxr-xr-x. 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 $ ll -d project1/ drwxr-----+ 1 pm1 project1 30 Dec 4 08 :52 project1/ \u6587\u4ef6 file1 \u548c\u76ee\u5f55 cloud \u6ca1\u6709\u7ee7\u627f project1 \u76ee\u5f55\u7684ACL\u6743\u9650\u3002 \u63d0\u793a\uff1a \u9ed8\u8ba4 ACL\u9650\u53ea\u5bf9\u76ee\u5f55\u751f\u6548\u3002 \u9ed8\u8ba4ACL\u6743\u9650\u7684\u4f5c\u7528\u662f\uff1a\u5982\u679c\u7ed9\u7236\u76ee\u5f55\u8bbe\u5b9a\u4e86\u9ed8\u8ba4 ACL \u6743\u9650\uff0c\u90a3\u4e48\u7236\u76ee\u5f55\u4e2d\u6240\u6709\u65b0\u5efa\u7684\u5b50\u6587\u4ef6\u90fd\u4f1a\u7ee7\u627f\u7236\u76ee\u5f55\u7684ACL\u6743\u9650\u3002 \u4e0b\u9762\u589e\u52a0 ~/project1 \u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u6743\u9650\u3002 $ su - pm1 $ cd ~ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- group::rwx #effective:r-- group:project2:rwx #effective:r-- mask::r-- other::--- $ setfacl -m d:u:tm2:rx ./project1/ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- group::rwx #effective:r-- group:project2:rwx #effective:r-- mask::r-- other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- \u521b\u5efa\u65b0\u5b50\u76ee\u5f55 leonardo \uff0c\u5c31\u7ee7\u627f\u4e86 ~/project1 \u76ee\u5f55\u7684default ACL\u6743\u9650\u8bbe\u5b9a\u3002 \u6ce8\u610f\uff0c\u9ed8\u8ba4ACL\u6743\u9650\u662f\u9488\u5bf9\u65b0\u5efa\u7acb\u7684\u6587\u4ef6\u751f\u6548\u7684\uff0c\u76ee\u5f55cloud\u548c\u6587\u4ef6file1\u5e76\u6ca1\u6709\u56e0\u4e3a\u589e\u52a0\u4e86\u7236\u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u8bbe\u5b9a\u800c\u7ee7\u627f\u9ed8\u8ba4ACL\u6743\u9650\u8bbe\u5b9a. $ su - pm1 $ cd ~ $ mkdir ./project1/leonardo $ ll ./project1/ drwxr-xr-x. 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---+ 1 pm1 project1 0 Dec 4 09 :07 leonardo 8.6.7.\u9012\u5f52ACL\u6743\u9650 \u00b6 \u9012\u5f52 ACL \u6743\u9650\uff0c\u662f\u6307\u7236\u76ee\u5f55\u5728\u8bbe\u5b9aACL\u6743\u9650\u65f6\uff0c\u6240\u6709\u7684\u5b50\u76ee\u5f55\u4e5f\u4f1a\u62e5\u6709\u76f8\u540c\u7684ACL\u6743\u9650\u3002 $ su - pm1 $ cd ~ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- group::rwx #effective:r-- group:project2:rwx #effective:r-- mask::r-- other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- $ setfacl -m d:u:tm2:rx -R ./project1/ $ ll ./project1 drwxr-xr-x+ 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---+ 1 pm1 project1 0 Dec 4 09 :07 leonardo 8.6.8.\u5220\u9664ACL\u6743\u9650 \u00b6 \u5220\u9664\u7528\u6237 tm2 \u7684ACL\u6743\u9650\u3002 $ su - pm1 $ cd ~ $ setfacl -x u:tm2 ./project1/ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx group::rwx group:project2:rwx mask::rwx other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- \u5220\u9664\u6240\u6709\u7684ACL\u6743\u9650\u3002 $ setfacl -b ./project1 $ getfacl ./project1 # file: project1/ # owner: pm1 # group: project1 user::rwx group::rwx other::--- $ ll ./project1 drwxr-xr-x+ 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---+ 1 pm1 project1 0 Dec 4 09 :07 leonardo \u9012\u5f52\u5220\u9664\u5168\u90e8ACL\u6743\u9650\u3002 $ setfacl -b -R ./project1 $ ll ./project1/ total 4 drwxr-xr-x. 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---. 1 pm1 project1 0 Dec 4 09 :07 leonardo 8.7.ACL\u76ee\u5f55\u5b9e\u4f8b\u89e3\u6790 \u00b6 8.7.1.\u76ee\u5f55ACL \u00b6 \u5207\u6362\u5230pm1\u7528\u6237\uff0c\u5728\u5176\u4e3b\u76ee\u5f55\u4e2d\uff0c\u57fa\u4e8e\u4e0d\u540c\u7684\u63a9\u7801\u521b\u5efa2\u4e2a\u5b50\u76ee\u5f55\u3002 $ su - pm1 $ umask 0022 $ mkdir mydir1 $ umask 0027 $ mkdir mydir2 $ ll -d mydir* drwxr-xr-x. 1 pm1 project1 0 Dec 4 12 :30 mydir1 drwxr-x---. 1 pm1 project1 0 Dec 4 12 :31 mydir2 \u8fd92\u4e2a\u76ee\u5f55\u5f53\u524d\u7684ACL\u72b6\u6001\u5982\u4e0b\uff1a $ getfacl mydir1 # file: mydir1 # owner: pm1 # group: project1 user::rwx group::r-x other::r-x $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx group::r-x other::--- \u4fee\u6539\u76ee\u5f55 mydir2 \u7684ACL\u3002 $ setfacl -m u:tm2:rwx,g:project2:rwx mydir2 $ getfacl mydir2 getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx group::r-x group:project2:rwx mask::rwx other::--- $ ll -d mydir2 drwxrwx---+ 1 pm1 project1 0 Dec 4 12 :31 mydir2 \u73b0\u5728\uff0c\u7528\u6237 tm2 \u548c\u7ec4 project2 \u5bf9\u76ee\u5f55 mydir2 \u90fd\u5177\u6709rwx\u6743\u9650\uff0c\u4f20\u7edfPOSIX\u6743\u9650\u548cACL\u6743\u9650\u4e00\u81f4\u3002 \u73b0\u5728\u5bf9mydir2\u76ee\u5f55\u7ec4\u6743\u9650\u64a4\u9500w\u6743\u9650\u3002 \u7528\u6237 tm2 \u548c\u7ec4 project2 \u5bf9\u76ee\u5f55 mydir2 \u7684\u6709\u6548\u6743\u9650\u53d8\u6210\u4e86 r-x \u3002 mask\u4e5f\u53d7\u7ec4\u6743\u9650\u53d8\u5316\u5f71\u54cd\uff0c\u53d8\u6210\u4e86 r-x \u3002 $ chmod g-w mydir2 $ ll -d mydir2 drwxr-x---+ 1 pm1 project1 0 Dec 4 12 :31 mydir2 $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx #effective:r-x group::r-x group:project2:rwx #effective:r-x mask::r-x other::--- \u901a\u8fc7 chmod \u548c setfacl \u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u6cd5\u5bf9\u76ee\u5f55 mydir2 \u7684\u7ec4\u6743\u9650\u8fdb\u884c\u4fee\u6539\uff0c\u5728ls\u547d\u4ee4\u4e2d\u4f53\u73b0\u662f\u4e00\u6837\u7684\uff0c\u5bf9\u7ec4\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u7684\u5f71\u54cd\u4e5f\u662f\u4e00\u6837\u7684\u3002 chmod \u4fee\u6539\u7684\u662f mask \uff0c mask \u53ea\u5f71\u54cd\u9664\u6240\u6709\u8005\u548cother\u7684\u4e4b\u5916\u7684\u4eba\u548c\u7ec4\u7684\u6700\u5927\u6743\u9650\uff0c mask \u9700\u8981\u4e0e\u7528\u6237\u7684\u6743\u9650\u8fdb\u884c\u903b\u8f91\u4e0e\u8fd0\u7b97\u540e\uff0c\u624d\u80fd\u53d8\u6210\u6709\u6548\u6743\u9650\uff0c\u7528\u6237\u6216\u7ec4\u7684\u8bbe\u7f6e\u5fc5\u987b\u5728mask\u6743\u9650\u8bbe\u5b9a\u8303\u56f4\u5185\u624d\u4f1a\u751f\u6548\u3002 setfacl \u53ef\u4ee5\u4e0d\u4fee\u6539mask\u7684\u60c5\u51b5\u4e0b\u53ea\u4fee\u6539 owning group \u7684\u6743\u9650\uff0c\u4e0b\u9762\u7684\u4f8b\u5b50\u8bf4\u660e\u4e86\u8fd9\u4e00\u60c5\u51b5\u3002POSIX\u7ec4\u6743\u9650\u4ecd\u7136\u662f rwx \uff0c\u4f46ACL\u4e2d\u6240\u6709\u8005\u7ec4\u7684\u6743\u9650\u53d8\u6210\u4e86 r-- \u3002 $ setfacl -m g::r mydir2 $ ll -d mydir2 drwxrwx---+ 1 pm1 project1 0 Dec 4 12 :31 mydir2 $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx group::r-- group:project2:rwx mask::rwx other::--- 8.7.2.\u76ee\u5f55\u7684\u9ed8\u8ba4ACL \u00b6 \u76ee\u5f55\u53ef\u4ee5\u5177\u6709\u9ed8\u8ba4ACL\uff0c\u8fd9\u662f\u4e00\u79cd\u7279\u6b8a\u7684ACL\uff0c\u7528\u4e8e\u5b9a\u4e49\u76ee\u5f55\u4e0b\u7684\u5bf9\u8c61\u5728\u521b\u5efa\u65f6\u7ee7\u627f\u7684\u8bbf\u95ee\u6743\u9650\u3002\u9ed8\u8ba4ACL\u4f1a\u5f71\u54cd\u5b50\u76ee\u5f55\u548c\u6587\u4ef6\u3002 \u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u7684\u6743\u9650\u6709\u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u4f20\u9012\u7ed9\u5176\u4e2d\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\uff1a \u5b50\u76ee\u5f55\u7ee7\u627f\u7236\u76ee\u5f55\u7684\u9ed8\u8ba4ACL\uff0c\u65e2\u4f5c\u4e3a\u81ea\u5df1\u7684\u9ed8\u8ba4ACL\uff0c\u53c8\u4f5c\u4e3a\u81ea\u5df1\u7684\u8bbf\u95eeACL\u3002 \u6587\u4ef6\u7ee7\u627f\u76ee\u5f55\u9ed8\u8ba4ACL\u4f5c\u4e3a\u5176\u81ea\u5df1\u7684\u8bbf\u95eeACL\u3002 \u521b\u5efa\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u7684\u6240\u6709\u7cfb\u7edf\u51fd\u6570\u90fd\u4f7f\u7528mode\u53c2\u6570\uff0c\u8be5\u53c2\u6570\u5b9a\u4e49\u4e86\u65b0\u521b\u5efa\u7684\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u5982\u679c\u7236\u76ee\u5f55\u6ca1\u6709\u9ed8\u8ba4ACL\uff0c\u5219\u6839\u636eumask\u7684\u8bbe\u7f6e\u8bbe\u7f6e\u6743\u9650\u4f4d\u3002 \u5982\u679c\u7236\u76ee\u5f55\u5b58\u5728\u9ed8\u8ba4ACL\uff0c\u5219\u5206\u914d\u7ed9\u65b0\u5bf9\u8c61\u7684\u6743\u9650\u4f4d\u5219\u662fmode\u53c2\u6570\u6743\u9650\u4e0e\u9ed8\u8ba4ACL\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\u7684\u903b\u8f91\u4e0e\u7684\u7ed3\u679c\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5ffd\u7565umask\u547d\u4ee4\u3002 \u9ed8\u8ba4ACL\u4e0d\u4f1a\u7acb\u5373\u5f71\u54cd\u8bbf\u95ee\u6743\u9650\u3002\u5b83\u4eec\u4ec5\u5728\u521b\u5efa\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u65f6\u624d\u8d77\u4f5c\u7528\u3002\u8fd9\u4e9b\u65b0\u5bf9\u8c61\u4ec5\u4ece\u5176\u7236\u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u7ee7\u627f\u6743\u9650\u3002 \u547d\u4ee4 mkdir \u5728\u521b\u5efa\u76ee\u5f55\u65f6\u4f1a\u7ee7\u627f\u9ed8\u8ba4ACL\u3002 $ su - pm1 $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx group::r-- group:project2:rwx mask::rwx other::--- $ mkdir ./mydir2/sub1 $ ll ./mydir2 drwxr-x---. 1 pm1 project1 0 Dec 4 13 :23 sub1 $ setfacl -d -m g:project2:-w- mydir2 $ mkdir ./mydir2/sub2 $ ll ./mydir2 drwxr-x---. 1 pm1 project1 0 Dec 4 13 :23 sub1 drwxrw----+ 1 pm1 project1 0 Dec 4 13 :27 sub2 $ getfacl ./mydir2/sub2 # file: mydir2/sub2 # owner: pm1 # group: project1 user::rwx group::r-- group:project2:-w- mask::rw- other::--- default:user::rwx default:group::r-- default:group:project2:-w- default:mask::rw- default:other::--- \u5728\u5bf9 mydir2 \u76ee\u5f55\u6dfb\u52a0\u9ed8\u8ba4ACL\u524d\uff0c\u521b\u5efa\u5b50\u76ee\u5f55 sub1 \uff0c\u6dfb\u52a0\u540e\u521b\u5efa\u5b50\u76ee\u5f55 sub2 \u3002\u53ef\u4ee5\u89c2\u5bdf\u5230 sub2 \u5230\u7ee7\u627f\u4e86 mydir2 \u7684\u9ed8\u8ba4ACL\u3002 $ su - tm2 $ cd /home/pm1/mydir2/sub2 -bash: cd: /home/pm1/mydir2/sub2: Permission denied \u4e0a\u4f8b\u4e2d\uff0c\u9ed8\u8ba4ACL\u4e2d\u6307\u5b9a\u7ec4 project2 \u53ea\u5177\u6709w\u6743\u9650\uff0c\u6240\u4ee5\u65e0\u6cd5\u6267\u884c cd \u547d\u4ee4\u8fdb\u5165\u8be5\u76ee\u5f55\u3002 \u8fd9\u8bf4\u660e\u6a21\u5f0f\u503cmode\u4e2d\u7ed9\u4e88\u7684\u6743\u9650 r \u88ab\u5c4f\u853d\u4e86\uff0c\u53ea\u4fdd\u7559\u4e86ACL\u4e2d\u6700\u5c0f\u7684\u6743\u9650 w \u3002 8.8.ACL\u68c0\u67e5\u903b\u8f91 \u00b6 ACL\u68c0\u67e5\u987a\u5e8f\uff1a Owner Named user Owning group Named group Other If \u8fdb\u7a0b\u7684\u7528\u6237\u6807\u8bc6\u662fOwner\uff0c\u5219owner\u7684ACL\u6761\u76ee\u51b3\u5b9a\u8bbf\u95ee\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7528\u6237\u6807\u8bc6\u662fnamed user\uff0c\u5219name user\u7684ACL\u6761\u76ee\u7684\u6743\u9650\u51b3\u5b9a\u7533\u8bf7\u7684\u8bbf\u95ee\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7ec4\u5c5e\u4e8eowning group\uff0c\u4e14owning group\u7684ACL\u6761\u76ee\u5305\u542b\u6240\u8bf7\u6c42\u7684\u8bbf\u95ee\u6743\u9650\uff0c\u5219\u6388\u4e88\u6240\u8bf7\u6c42\u7684\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7ec4\u5c5e\u4e8enamed group\uff0c\u4e14named group\u7684ACL\u6761\u76ee\u5305\u542b\u6240\u8bf7\u6c42\u7684\u8bbf\u95ee\u6743\u9650\uff0c\u5219\u6388\u4e88\u6240\u8bf7\u6c42\u7684\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7ec4\u5c5e\u4e8eowning group\u6216\u8005named group\uff0c\u4f46owning group\u6216\u8005named group\u7684ACL\u6761\u76ee\u4e0d\u5305\u542b\u6240\u8bf7\u6c42\u7684\u8bbf\u95ee\u6743\u9650\uff0c\u5219\u62d2\u7edd\u6240\u8bf7\u6c42\u7684\u6743\u9650 else ACL\u4e2d\u7684other\u6761\u76ee\u5904\u7406\u7533\u8bf7\u7684\u6743\u9650 If \u5982\u679c\u8fdb\u7a0b\u5339\u914d\u5230owner\u6216\u8005other\u6761\u76ee\u4e2d\u5305\u542b\u6240\u7533\u8bf7\u7684\u6743\u9650\uff0c\u5219\u6388\u4e88\u6743\u9650 else if \u5982\u679c\u8fdb\u7a0b\u5339\u914d\u5230named user\uff0cowning group\uff0c\u6216\u8005named group\u6761\u76ee\u4e2d\u5305\u542b\u6240\u7533\u8bf7\u7684\u6743\u9650\uff0c\u4e14maks\u6761\u76ee\u4e5f\u5305\u542b\u6240\u7533\u8bf7\u7684\u6743\u9650\uff0c\u5219\u6388\u4e88\u6743\u9650 else \u62d2\u7edd\u6743\u9650\u7533\u8bf7 \u5b9e\u9645\u5e94\u7528\u4e3e\u4f8b\uff1a udev\u4f7f\u7528ACL\u7ed9\u4e88\u767b\u5f55\u5230\u56fe\u5f62\u754c\u9762\u7684\u7528\u6237\u8bbf\u95ee\u8bbe\u5907\u7684\u6743\u9650\uff0c\u4f8b\u5982DVD\u9a71\u52a8\u5668 \u67d0\u4e9b\u5e94\u7528\u7a0b\u5e8f\u4e0d\u652f\u6301ACL Star Archiver\u662f\u4e00\u4e2a\u5b8c\u5168\u4fdd\u7559ACL\u7684\u5907\u4efd\u5e94\u7528\u7a0b\u5e8f\uff0c\u5176\u4ed6\u4eba\u53ef\u80fd\u4f1a\u4e5f\u53ef\u80fd\u4e0d\u4f1a\u4fdd\u7559\u5b83 \u8bb8\u591a\u7f16\u8f91\u5668\u548c\u6587\u4ef6\u7ba1\u7406\u5668\u4e0d\u5141\u8bb8\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u67e5\u770b\u6216\u8bbe\u7f6eACL","title":"\u7b2c\u4e09\u7ae0 \u8eab\u4efd\u4e0e\u5b89\u5168"},{"location":"linux/SRE/03-identity-security/#_1","text":"","title":"\u7b2c\u4e09\u7ae0 \u8eab\u4efd\u4e0e\u5b89\u5168"},{"location":"linux/SRE/03-identity-security/#1","text":"\u7528\u6237\u548c\u7ec4 \u7528\u6237user\u548c\u7ec4group\u5728Linux\u7cfb\u7edf\u4e2d\u4ee5\u6570\u5b57\u5f62\u5f0f\u8fdb\u884c\u7ba1\u7406\u3002 \u7528\u6237\u88ab\u5206\u914d\u7684\u53f7\u7801\u79f0\u4e3a\u7528\u6237ID\uff08UID\uff09\u3002 \u6bcf\u4e2aLinux\u7cfb\u7edf\u90fd\u6709\u4e00\u4e2a\u7279\u6743\u7528\u6237\uff0c\u5373 root \u7528\u6237\u3002 root \u662f\u7cfb\u7edf\u7ba1\u7406\u5458\u3002 \u6b64\u7528\u6237\u7684UID\u59cb\u7ec8\u4e3a0\u3002 \u666e\u901a\u7528\u6237\u7684UID\u7f16\u53f7\uff08\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff09\u4e3a1000\u3002 \u6bcf\u4e2a\u7ec4\u4e5f\u5206\u914d\u4e86\u4e00\u4e2a\u79f0\u4e3a\u7ec4ID\uff08GID\uff09\u7684\u7f16\u53f7\u3002 \u6bcf\u4e2a\u7528\u6237\u6709\u4e00\u4e2a\u4e3b\u8981\u7ec4\uff08primary group\uff09\uff0c\u6709\u96f6\u4e2a\u6216\u8005\u4efb\u610f\u4e2a\u9644\u52a0\u7ec4\uff08supplementary group\uff09\u3002 \u4ee5openSUSE\u4e3a\u4f8b\uff1a UID 0: root 1 \u2013 99: System 100 \u2013 499: System accounts \u2265 1000: Normal (unprivileged) accounts GID 0: root 1 \u2013 99: System Groups 100 \u2013 499: Dynamically Allocated System Groups \u2265 1000: Normal Groups \u4e3e\u4f8b\uff1a $ id postfix uid = 51 ( postfix ) gid = 51 ( postfix ) groups = 482 ( mail ) ,59 ( maildrop ) ,51 ( postfix ) $ id vagrant uid = 1000 ( vagrant ) gid = 478 ( wheel ) groups = 0 ( root ) ,478 ( wheel ) \u63d0\u793a\uff1a UID\u548cGID\u7b49\u7f16\u53f7\u89c4\u5219\uff0c\u662f\u5728\u6587\u4ef6 /etc/login.defs \u4e2d\u7ea6\u5b9a\u7684\u3002","title":"1.\u7528\u6237\u3001\u7ec4\u3001\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#2selinux","text":"Security-Enhanced Linux (SELinux) \u662f\u4e00\u79cdLinux\u7cfb\u7edf\u7684\u5b89\u5168\u67b6\u6784\uff0c\u5b83\u5141\u8bb8\u7ba1\u7406\u5458\u66f4\u597d\u5730\u63a7\u5236\u8c01\u53ef\u4ee5\u8bbf\u95ee\u7cfb\u7edf\u3002 SELinux\u4e8e2000\u5e74\u5411\u5f00\u6e90\u793e\u533a\u53d1\u5e03\uff0c\u5e76\u4e8e2003\u5e74\u96c6\u6210\u5230\u4e0a\u6e38 Linux \u5185\u6838\u4e2d\u3002 SELinux\u4e3a\u7cfb\u7edf\u4e0a\u7684\u5e94\u7528\u7a0b\u5e8f\u3001\u8fdb\u7a0b\u548c\u6587\u4ef6\u5b9a\u4e49\u4e86\u8bbf\u95ee\u63a7\u5236\u3002 \u5b83\u4f7f\u7528\u5b89\u5168\u7b56\u7565\uff08\u4e00\u7ec4\u89c4\u5219\u544a\u8bc9SELinux\u4ec0\u4e48\u53ef\u4ee5\u8bbf\u95ee\u6216\u4e0d\u53ef\u4ee5\u8bbf\u95ee\uff09\u6765\u5f3a\u5236\u6267\u884c\u7b56\u7565\u5141\u8bb8\u7684\u8bbf\u95ee\u3002 \u5f53\u79f0\u4e3a\u4e3b\u4f53\uff08subject\uff09\u7684\u5e94\u7528\u7a0b\u5e8f\u6216\u8fdb\u7a0b\u8bf7\u6c42\u8bbf\u95ee\u5bf9\u8c61\uff08\u5982\u6587\u4ef6\uff09\u65f6\uff0cSELinux\u4f1a\u68c0\u67e5\u8bbf\u95ee\u5411\u91cf\u7f13\u5b58(AVC, Access Vector Cache)\uff0c\u5176\u4e2d\u7f13\u5b58\u4e86\u4e3b\u4f53\u548c\u5bf9\u8c61\u7684\u6743\u9650\u3002 \u5982\u679cSELinux\u65e0\u6cd5\u6839\u636e\u7f13\u5b58\u7684\u6743\u9650\u505a\u51fa\u8bbf\u95ee\u51b3\u5b9a\uff0c\u5b83\u4f1a\u5c06\u8bf7\u6c42\u53d1\u9001\u5230\u5b89\u5168\u670d\u52a1\u5668\u3002 \u5b89\u5168\u670d\u52a1\u5668\u68c0\u67e5\u5e94\u7528\u7a0b\u5e8f\u6216\u8fdb\u7a0b\u548c\u6587\u4ef6\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\u3002 \u4eceSELinux\u7b56\u7565\u6570\u636e\u5e93\u5e94\u7528\u5b89\u5168\u4e0a\u4e0b\u6587\uff08Security context\uff09\uff0c\u7136\u540e\u6388\u4e88\u6216\u62d2\u7edd\u8bb8\u53ef\u3002 \u5982\u679c\u6743\u9650\u88ab\u62d2\u7edd\uff0c avc: denied \u6d88\u606f\u5c06\u5728 /var/log.messages \u4e2d\u4f53\u73b0\u3002 \u4f20\u7edf\u4e0a\uff0cLinux\u548cUNIX\u7cfb\u7edf\u90fd\u4f7f\u7528DAC\uff08Discretionary Access Control\uff09\u3002 SELinux\u662fLinux\u7684MAC\uff08Mandatory Access Control\uff09\u7cfb\u7edf\u7684\u4e00\u4e2a\u793a\u4f8b\u3002 \u5728DAC\u65b9\u5f0f\u4e0b\uff0c\u6587\u4ef6\u548c\u8fdb\u7a0b\u6709\u81ea\u5df1\u7684\u5c5e\u4e3b\uff08\u6240\u6709\u8005\uff09\u3002 \u7528\u6237\u53ef\u4ee5\u62e5\u6709\u4e00\u4e2a\u6587\u4ef6\uff0c\u4e00\u4e2a\u7ec4\u4e5f\u53ef\u4ee5\u62e5\u6709\u4e00\u4e2a\u6587\u4ef6\uff0c\u6216\u8005\u5176\u4ed6\u4eba\u3002 \u7528\u6237\u53ef\u4ee5\u66f4\u6539\u81ea\u5df1\u6587\u4ef6\u7684\u6743\u9650\u3002 root \u7528\u6237\u5bf9DAC\u7cfb\u7edf\u5177\u6709\u5b8c\u5168\u8bbf\u95ee\u63a7\u5236\u6743\u3002 \u4f46\u662f\u5728\u50cfSELinux\u8fd9\u6837\u7684MAC\u7cfb\u7edf\u4e0a\uff0c\u5bf9\u4e8e\u8bbf\u95ee\u7684\u7ba1\u7406\u662f\u901a\u8fc7\u8bbe\u7f6e\u7b56\u7565\u6765\u5b9e\u73b0\u7684\u3002\u5373\u4f7f\u7528\u6237\u4e3b\u76ee\u5f55\u4e0a\u7684DAC\u8bbe\u7f6e\u53d1\u751f\u66f4\u6539\uff0c\u7528\u4e8e\u9632\u6b62\u5176\u4ed6\u7528\u6237\u6216\u8fdb\u7a0b\u8bbf\u95ee\u8be5\u76ee\u5f55\u7684SELinux\u7b56\u7565\u4e5f\u5c06\u7ee7\u7eed\u786e\u4fdd\u7cfb\u7edf\u5b89\u5168\u3002 MAC\u65b9\u5f0f\u662f\u63a7\u5236\u4e00\u4e2a\u8fdb\u7a0b\u5bf9\u5177\u4f53\u6587\u4ef6\u7cfb\u7edf\u4e0a\u9762\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u662f\u5426\u62e5\u6709\u8bbf\u95ee\u6743\u9650\u3002\u5224\u65ad\u8fdb\u7a0b\u662f\u5426\u53ef\u4ee5\u8bbf\u95ee\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u4f9d\u636e\uff0c\u53d6\u51b3\u4e8eSELinux\u4e2d\u8bbe\u5b9a\u7684\u5f88\u591a\u7b56\u7565\u89c4\u5219\u3002 \u8bbf\u95ee\u63a7\u5236\u5217\u8868 (ACL\uff0cAccess Control List) \u4e3a\u6587\u4ef6\u7cfb\u7edf\u63d0\u4f9b\u4e86\u4e00\u79cd\u989d\u5916\u7684\u3001\u66f4\u7075\u6d3b\u7684\u6743\u9650\u673a\u5236\u3002 \u5b83\u65e8\u5728\u534f\u52a9 UNIX \u6587\u4ef6\u6743\u9650\u3002ACL\u5141\u8bb8\u6388\u4e88\u4efb\u4f55\u7528\u6237\u6216\u7ec4\u5bf9\u4efb\u4f55\u78c1\u76d8\u8d44\u6e90\u7684\u6743\u9650\u3002ACL\u9002\u7528\u4e8e\u5728\u4e0d\u4f7f\u67d0\u4e2a\u7528\u6237\u6210\u4e3a\u7ec4\u6210\u5458\u7684\u60c5\u51b5\u4e0b\uff0c\u4ecd\u65e7\u6388\u4e88\u4e00\u4e9b\u8bfb\u6216\u5199\u8bbf\u95ee\u6743\u9650\u3002 \u4e0b\u9762\u793a\u4f8b\u5bf9\u6bd4\u8bf4\u660e\u4e86SELinux\u548cACL\u5728\u6587\u4ef6\u5c5e\u6027\u5c55\u73b0\u4e0a\u7684\u7279\u70b9\u3002 -rwxr-xr-- vagrant wheel \uff1a\u6ca1\u6709selinux\u4e0a\u4e0b\u6587\uff0c\u6ca1\u6709ACL -rwx--xr-x+ vagrant wheel \uff1a\u53ea\u6709ACL\uff0c\u6ca1\u6709selinux\u4e0a\u4e0b\u6587 -rw-r--r--. vagrant wheel \uff1a\u53ea\u6709selinux\u4e0a\u4e0b\u6587\uff0c\u6ca1\u6709ACL -rwxrwxr--+ vagrant wheel \uff1a\u6709selinux\u4e0a\u4e0b\u6587\uff0c\u6709ACL","title":"2.SELinux"},{"location":"linux/SRE/03-identity-security/#21selinux","text":"\u7528\u6237(Users)\uff1a SELinux\u7684\u7528\u6237\u4e0d\u7b49\u540c\u4e0eLinux\u7528\u6237\u3002 SELinux\u7528\u6237\u4ee5\u540e\u7f00 _u \u7ed3\u5c3e\u3002 \u89d2\u8272(Roles)\uff1a \u89d2\u8272Roles\u662f\u7531\u7b56\u7565Policies\u5b9a\u4e49\u7684\uff0c\u89d2\u8272\u51b3\u5b9a\u4e86\u4f7f\u7528\u54ea\u4e2a\u7b56\u7565\u3002 SELinux\u89d2\u8272\u4ee5\u540e\u7f00 _r \u7ed3\u5c3e\u3002 \u7c7b\u578b(Types)\uff1a SELinux\u662f\u7c7b\u578b\u5f3a\u5236\u7684\uff0c\u7c7b\u578bTypes\u51b3\u5b9a\u8fdb\u7a0b\u80fd\u5426\u8bbf\u95ee\u67d0\u4e2a\u6587\u4ef6\u3002 SELinux\u7c7b\u578b\u662f\u4ee5\u540e\u7f00 _t \u7ed3\u5c3e\u3002 \u4e0a\u4e0b\u6587(Contexts)\uff1a \u7528\u6765\u6807\u8bb0\u8fdb\u7a0b\u548c\u6587\u4ef6\u3002\u5206\u522b\u662f\u7528\u6237Users\uff0c\u89d2\u8272Roles\uff0c\u7c7b\u578bTypes\uff0c\u8303\u56f4Ranges\u3002 \u683c\u5f0f\uff1a user:role:type:range \u6587\u4ef6\u7c7b\u578b(Object Classes)\uff1a \u6bcf\u4e2a\u6587\u4ef6\u7c7b\u578bTypes\u90fd\u5bf9\u5e94\u4e00\u5957\u7b56\u7565Policies\u3002\u7b56\u7565Policies\u51b3\u5b9a\u4e86\u8fdb\u7a0b\u5bf9\u8fd9\u7c7b\u6587\u4ef6\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u8bbf\u95ee\u6743\u9650\u67094\u79cd\uff1a \u521b\u5efacreate \u8bfb\u53d6read \u5199\u5165write \u5220\u9664unlink\uff08\u6ce8\u610f\uff0c\u8fd9\u91cc\u4e0d\u662f\u94fe\u63a5\u7684\u610f\u601d\uff09 \u89c4\u5219(Rules) \u683c\u5f0f\uff1a allow user_t user_home_t:file {create read write unlink}; \u542b\u4e49\uff1a user_t \u7c7b\u578b\u5bf9 user_home_t \u7c7b\u578b\u6709\u521b\u5efacreate\uff0c\u8bfb\u53d6read\uff0c\u5199\u5165write\uff0c\u5220\u9664unlink\u6743\u9650\u3002","title":"2.1.SELinux\u4e3b\u8981\u6982\u5ff5"},{"location":"linux/SRE/03-identity-security/#22selinux-in-opensuse","text":"\u4f5c\u4e3aSELinux\u7684\u66ff\u4ee3\u54c1\uff0c2005\u5e74\u88abNovell\u6536\u8d2d\u7684Immunix\u516c\u53f8\u5f00\u53d1\u4e86AppArmor\u3002SUSE\u5728openSUSE Leap\u4e2d\u63d0\u4f9b\u5bf9SELinux\u6846\u67b6\u7684\u652f\u6301\u3002\u8fd9\u5e76\u4e0d\u610f\u5473\u7740openSUSE Leap\u7684\u9ed8\u8ba4\u5b89\u88c5\u4f1a\u5728\u4e0d\u4e45\u7684\u5c06\u6765\u4eceAppArmor\u5207\u6362\u5230SELinux\u3002 \u6dfb\u52a0SELinux\u7684\u6e90\u3002\u53ef\u4ee5\u4ece https://download.opensuse.org/repositories/security:/SELinux/ \u4e0b\u8f7d\u5bf9\u5e94\u7684\u7b56\u7565policy\u3002 sudo zypper ar -f https://download.opensuse.org/repositories/security:/SELinux/openSUSE_Factory/ Security-SELinux \u5b89\u88c5C++\u7b49\u57fa\u7840\u5f00\u53d1\u5305\uff1a # \u5217\u51fa\u5f53\u524d\u53ef\u5b89\u88c5\u7684Pattern sudo zypper pt # \u5b89\u88c5\u4e0b\u9762\u51e0\u4e2a\u5f00\u53d1\u76f8\u5173\u7684Pattern sudo zypper in -t pattern devel_C_C++ devel_basis devel_kernel \u5b89\u88c5SELinux packages\uff1a zypper se --search-descriptions selinux sudo zypper in restorecond policycoreutils setools-console sudo zypper in selinux-tools libselinux-devel \u5b89\u88c5SELinux policy\uff1a sudo zypper in selinux-policy-targeted selinux-policy-devel selinux-autorelabel \u66f4\u65b0GRUB2 bootloader\uff08GRUB2\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\uff09\uff1a \u7f16\u8f91\u6587\u4ef6 /etc/default/grub \uff0c\u6dfb\u52a0\u4e0b\u9762\u5185\u5bb9\u5230 GRUB_CMDLINE_LINUX_DEFAULT= \u8fd9\u4e00\u884c\uff1a security = selinux selinux = 1 \u8bb0\u5f55\u8fd9\u4e00\u884c\u7684\u539f\u59cb\u4fe1\u606f\uff1a GRUB_CMDLINE_LINUX_DEFAULT = \"splash=silent resume=/dev/disk/by-uuid/47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 preempt=full mitigations=auto quiet security=apparmor\" \u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u751f\u6210\u65b0\u7684GRUB2\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\u914d\u7f6e\u6587\u4ef6\u3002 sudo grub2-mkconfig -o /boot/grub2/grub.cfg \u7f16\u8f91\u6587\u4ef6 /etc/selinux/config \u5e76\u8bbe\u7f6e SELINUX=permissive \u6765\u542f\u7528SElinux\u3002\u8fd9\u4e0e\u524d\u9762GRUB2\u7684\u542f\u52a8\u914d\u7f6e\u662f\u4e00\u81f4\u7684\u3002 \u5982\u6587\u4ef6\u4e0d\u5b58\u5728\uff0c\u5219\u521b\u5efa\u3002 $ sudo cat /etc/selinux/config SELINUX = permissive SELINUXTYPE = targeted \u91cd\u542f\u7cfb\u7edf\u3002\u7cfb\u7edf\u542f\u52a8\u53ef\u80fd\u9700\u8981\u4e00\u4e9b\u65f6\u95f4\uff0cSELinux\u9700\u8981\u7ed9\u6574\u4e2a\u6587\u4ef6\u7cfb\u7edf\u91cd\u65b0\u8fdb\u884c\u6807\u7b7e\u5316\u3002 \u91cd\u542f\u540e\uff0c\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u6765\u67e5\u770bSELinux\u662f\u5426\u8fd0\u884c\u6b63\u5e38\u3002 $ sudo getenforce Permissive $ sudo sestatus -v SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted Current mode: permissive Mode from config file: permissive Policy MLS status: enabled Policy deny_unknown status: allowed Memory protection checking: requested ( insecure ) Max kernel policy version: 33 Process contexts: Current context: unconfined_u:unconfined_r:unconfined_t:s0 Init context: system_u:system_r:kernel_t:s0 /sbin/agetty system_u:system_r:kernel_t:s0 /usr/sbin/sshd system_u:system_r:kernel_t:s0 File contexts: Controlling terminal: unconfined_u:object_r:devpts_t:s0 /etc/passwd system_u:object_r:unlabeled_t:s0 /etc/shadow system_u:object_r:unlabeled_t:s0 /bin/bash system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /bin/login system_u:object_r:unlabeled_t:s0 /bin/sh system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /sbin/agetty system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /sbin/init system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /usr/sbin/sshd system_u:object_r:unlabeled_t:s0 \u53c2\u8003\uff1a GRUB2\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\u4e2d\u6dfb\u52a0\u7684\u4e09\u4e2a\u53c2\u6570\u7684\u89e3\u91ca\uff1a security=selinux : This option tells the kernel to use SELinux and not AppArmor. selinux=1 : This option switches on SELinux. enforcing=0 : This option puts SELinux in permissive mode. In this mode, SELinux is fully functional, but does not enforce any of the security settings in the policy. Use this mode for testing and configuring your system. To switch on SELinux protection, when the system is fully operational, change the option to enforcing=1 and add SELINUX=enforcing in /etc/selinux/config . \u5c0f\u8d34\u58eb\uff1a \u5728\u9996\u6b21\u542f\u7528SELinux\u540e\uff0c\u5982\u679c\u53ea\u5728grub2\u91cc\u9762\u6dfb\u52a0selinux=1\uff0c\u901a\u8fc7 getenforce \u547d\u4ee4\u770b\u7684SELinux\u4e00\u76f4\u5c31\u662fdisabled\u7684\u72b6\u6001\uff0c\u9700\u8981\u624b\u5de5\u521b\u5efa/etc/selinux/config\u6587\u4ef6\u6dfb\u52a0\u914d\u7f6e\u624d\u884c\u3002\u611f\u89c9grub2\u91cc\u9762\u65e0\u9700\u8bbe\u7f6e\uff0c\u76f4\u63a5\u914d\u7f6e/etc/selinux/config\u6587\u4ef6\u3002\u4e0d\u786e\u5b9a\u8fd9\u4e2a\u60f3\u6cd5\u662f\u5426\u6b63\u786e\u3002 \u5728grub2\u4e2d\u8bbe\u5b9aselinux=1\uff0c\u5728/etc/selinux/config\u6587\u4ef6\u4e2d\uff1a \u8bbe\u5b9aSELINUX=permissive\uff0c\u91cd\u542f\u540e\u901a\u8fc7 getenforce \u547d\u4ee4\u770b\u5230\u7684\u662fpermissive\u3002 \u8bbe\u5b9aSELINUX=disabled\uff0c\u5219\u91cd\u542f\u540e getenforce \u547d\u4ee4\u770b\u5230\u7684\u662fdisabled\u3002 \u8fd9\u8bf4\u660e\u914d\u7f6e\u6587\u4ef6\u540e\u542f\u52a8\uff0c\u8986\u76d6\u4e86\u5185\u6838\u8bbe\u7f6e\u3002 \u6ce8\u610f\uff0c\u5982\u679c\u4ec5\u4ec5\u5b8c\u6210\u4e86\u4e0a\u9762\u7684enable SELinux\uff0c\u7acb\u523b\u8bbe\u5b9aSELINUX=enforcing\uff0c\u4f1a\u5f15\u8d77ssh\u65e0\u6cd5\u767b\u5f55\uff0c\u9519\u8bef\u4fe1\u606f\u662f /bin/bash: Permission denied \u3002 \u914d\u7f6eSELinux\u3002 $ sudo semanage boolean -l Failed to use semanage \u6dfb\u52a0\u4e0b\u9762\u5185\u5bb9\u5230.bashrc\u6587\u4ef6\u3002 export PATH = /usr/local/bin:/home/ $USER /.local/bin: $PATH \u66f4\u65b0pip3. pip3 install --upgrade pip \u5b89\u88c5\u4e0b\u9762\u51e0\u4e2a\u5305 sudo zypper in libselinux libselinux-devel sudo zypper in python3-semanage sudo zypper in libsemanage-devel libsemanage-devel-static sudo zypper in policycoreutils-python-utils sudo zypper in cross-x86_64-linux-glibc-devel glibc-utils glibc-profile sudo zypper in policycoreutils-devel","title":"2.2.SELinux in openSUSE"},{"location":"linux/SRE/03-identity-security/#23selinux-in-ubuntu","text":"","title":"2.3.SELinux in Ubuntu"},{"location":"linux/SRE/03-identity-security/#24selinux-in-rocky","text":"","title":"2.4.SELinux in Rocky"},{"location":"linux/SRE/03-identity-security/#3","text":"/etc/passwd \uff1a\u7528\u6237\u53ca\u5176\u5c5e\u6027\u4fe1\u606f\uff08\u7528\u6237\u540d\uff0cUID\uff0c\u4e3b\u7ec4ID\u7b49\uff09 /etc/shadow \uff1a\u7528\u6237\u5bc6\u7801\u673a\u5668\u5c5e\u6027 /etc/group \uff1a\u7ec4\u53ca\u5176\u5c5e\u6027 /etc/gshadow \uff1a\u7ec4\u5bc6\u7801\u53ca\u5176\u5c5e\u6027","title":"3.\u7528\u6237\u548c\u7ec4\u7684\u914d\u7f6e\u6587\u4ef6"},{"location":"linux/SRE/03-identity-security/#31etcpasswd","text":"\u683c\u5f0f\u8bf4\u660e\uff1a vagrant:x:1001:474:vagrant:/home/vagrant:/bin/bash [ ----- ] - [ -- ] [ - ] [ ----- ] [ ----------- ] [ ------- ] | | | | | | +--------> 7 . Login shell | | | | | +--------------------> 6 . Home directory | | | | +-------------------------------> 5 . GECOS or the full name of the user | | | +-------------------------------------> 4 . GID | | +------------------------------------------> 3 . UID | +---------------------------------------------> 2 . Password +--------------------------------------------------> 1 . Username","title":"3.1./etc/passwd"},{"location":"linux/SRE/03-identity-security/#32etcshadow","text":"\u683c\u5f0f\u8bf4\u660e\uff1a vagrant: $6 $.n.:17736:0:99999:7::: [ ----- ] [ ---- ] [ --- ] - [ --- ] ---- | | | | | || | +-----------> 9 . Unused | | | | | || +------------> 8 . Expiration date since Jan 1 , 1970 | | | | | | +-------------> 7 . Inactivity period \u5bc6\u7801\u8fc7\u671f\u540e\u7684\u5bbd\u9650\u671f | | | | | +--------------> 6 . Warning period, default 7 days | | | | +------------------> 5 . Maximum password age | | | +----------------------> 4 . Minimum password age | | +--------------------------> 3 . Last password change since Jan 1 , 1970 | +---------------------------------> 2 . Encrypted Password +-------------------------------------------> 1 . Username","title":"3.2./etc/shadow"},{"location":"linux/SRE/03-identity-security/#33etcgroup","text":"\u683c\u5f0f\u8bf4\u660e\uff1a audio:x:492:pulse [ --- ] - [ - ] [ --- ] | | | +----> 4 . username-list, who have this group as their supplementary | | +---------> 3 . GID | +------------> 2 . group-password. Real password is in /etc/gshadow +----------------> 1 . groupname","title":"3.3./etc/group"},{"location":"linux/SRE/03-identity-security/#34etcgshadow","text":"\u683c\u5f0f\u8bf4\u660e\uff1a general:!!:shelley:juan,bob [ ----- ] -- [ ----- ] [ ------ ] | | | +-------> 4 . group members ( in a comma delimited list ) | | +---------------> 3 . group adminstrators ( in a comma delimited list ) | +---------------------> 2 . encrypted password. ` ! ` , ` !! ` , and null +---------------------------> 1 . group name Encrypted password ! \uff1ano user is allowed to access the group using the newgrp command. !! \uff1athe same as a value of ! \u2014 however, it also indicates that a password has never been set before. null\uff1aonly group members can log into the group.","title":"3.4./etc/gshadow"},{"location":"linux/SRE/03-identity-security/#35","text":"# \u901a\u8fc7`/dev/urandom`\u751f\u6210\u968f\u673a\u6570\uff0c\u901a\u8fc7`tr -dc`\u8fc7\u6ee4\u968f\u673a\u6570\uff0c\u53ea\u4fdd\u7559\u5b57\u6bcd\u548c\u6570\u5b57\uff0c\u901a\u8fc7`head -c`\u4fdd\u7559\u6307\u5b9a\u4f4d\u6570 $ tr -dc '[:alnum:]' < /dev/urandom | head -c 12 xFw7vfma54D8 $ openssl rand -base64 9 I5TZXJfpd3Pg","title":"3.5.\u751f\u6210\u968f\u673a\u5bc6\u7801"},{"location":"linux/SRE/03-identity-security/#36vipwvigrpwckgrpck","text":"vipw \u548c vigr \u547d\u4ee4\u5206\u522b\u7f16\u8f91\u6587\u4ef6 /etc/passwd \u548c /etc/group \u3002 \u5982\u679c\u6307\u5b9a\u4e86 -s \u6807\u5fd7\uff0c\u8fd9\u4e9b\u547d\u4ee4\u5c06\u5206\u522b\u7f16\u8f91\u5176\u6587\u4ef6\u7684\u5f71\u5b50\uff08\u5b89\u5168\uff09\u7248\u672c\uff1a /etc/shadow \u548c /etc/gshadow \u3002 vipw \u548c vigr \u547d\u4ee4\u5728\u7f16\u8f91\u6587\u4ef6\u65f6\u4f1a\u8bbe\u7f6e\u9501\u4ee5\u9632\u6b62\u6587\u4ef6\u635f\u574f\u3002 vipw \u548c vigr \u547d\u4ee4\u4f1a\u9996\u5148\u5c1d\u8bd5\u73af\u5883\u53d8\u91cf $VISUAL \uff0c\u7136\u540e\u662f\u73af\u5883\u53d8\u91cf $EDITOR \uff0c\u6700\u540e\u662f\u9ed8\u8ba4\u7f16\u8f91\u5668 vi \u3002 sudo vipw sudo vipw -s sudo vigr sudo vigr -s pwck \u547d\u4ee4\u5b9e\u73b0\u9a8c\u8bc1\u7cfb\u7edf\u8ba4\u8bc1\u4fe1\u606f\u7684\u5b8c\u6574\u6027\u3002 \u68c0\u67e5 /etc/passwd \u548c /etc/shadow \u4e2d\u7684\u6240\u6709\u6761\u76ee\u6bcf\u4e2a\u5b57\u6bb5\u662f\u5426\u5177\u6709\u6b63\u786e\u7684\u683c\u5f0f\u548c\u6709\u6548\u6570\u636e\u3002 \u7cfb\u7edf\u4f1a\u63d0\u793a\u7528\u6237\u5220\u9664\u683c\u5f0f\u4e0d\u6b63\u786e\u6216\u5b58\u5728\u5176\u4ed6\u9519\u8bef\u7684\u6761\u76ee\u3002 pwck \u8fd4\u56de\u503c\uff1a 0 : success 1 : invalid command syntax 2 : one or more bad password entries 3 : can\u2019t open password files 4 : can\u2019t lock password files 5 : can\u2019t update password files grpck \u547d\u4ee4\u5b9e\u73b0\u9a8c\u8bc1\u7cfb\u7edf\u8ba4\u8bc1\u4fe1\u606f\u7684\u5b8c\u6574\u6027\u3002 \u68c0\u67e5 /etc/group \u548c /etc/gshadow \u4e2d\u7684\u6240\u6709\u6761\u76ee\u6bcf\u4e2a\u5b57\u6bb5\u662f\u5426\u5177\u6709\u6b63\u786e\u7684\u683c\u5f0f\u548c\u6709\u6548\u6570\u636e\u3002 \u7cfb\u7edf\u4f1a\u63d0\u793a\u7528\u6237\u5220\u9664\u683c\u5f0f\u4e0d\u6b63\u786e\u6216\u5b58\u5728\u5176\u4ed6\u9519\u8bef\u7684\u6761\u76ee\u3002 grpck \u8fd4\u56de\u503c\uff1a 0 : success 1 : invalid command syntax 2 : one or more bad group entries 3 : can\u2019t open group files 4 : can\u2019t lock group files 5 : can\u2019t update group files","title":"3.6.vipw/vigr/pwck/grpck\u547d\u4ee4"},{"location":"linux/SRE/03-identity-security/#4","text":"\u7528\u6237\u7ba1\u7406\u547d\u4ee4\uff1a useradd usermod userdel","title":"4.\u7528\u6237\u7ba1\u7406"},{"location":"linux/SRE/03-identity-security/#41useradd","text":"\u4e3e\u4f8b\uff1a # \u666e\u901a\u7528\u6237 $ useradd -m -g wheel -G root -c \"vagrant\" vagrant # \u975e\u4ea4\u4e92\u7528\u6237 $ useradd -r -u 48 -g apache -d /var/www -s /sbin/nologin -g postfix -c \"Apache\" apache 2 >/dev/null useradd \u547d\u4ee4\u7684\u9ed8\u8ba4\u503c\u662f\u5728 /etc/default/useradd \u6587\u4ef6\u4e2d\u8bbe\u5b9a\u3002 openSUSE\u7684 /etc/default/useradd \u6587\u4ef6\u5185\u5bb9\uff1a GROUP = 100 HOME = /home INACTIVE = -1 # \u5bf9\u5e94/etc/shadow\u6587\u4ef6\u7b2c7\u5217\uff0cInactivity period\uff0c\u5bc6\u7801\u8fc7\u671f\u540e\u7684\u5bbd\u9650\u671f\uff0c-1\u8868\u793a\u4e0d\u9650\u5236 EXPIRE = # \u5bf9\u5e94/etc/shadow\u6587\u4ef6\u7b2c8\u5217\uff0cExpiration date since Jan 1, 1970\uff0c\u5373\u8d26\u53f7\u6709\u6548\u671f SHELL = /bin/bash SKEL = /etc/skel # \u7528\u4e8e\u751f\u6210\u7528\u6237\u4e3b\u76ee\u5f55\u7684\u6a21\u7248\u6587\u4ef6 USRSKEL = /usr/etc/skel CREATE_MAIL_SPOOL = yes Rocky\u7684 /etc/default/useradd \u6587\u4ef6\u5185\u5bb9\uff1a GROUP = 100 HOME = /home INACTIVE = -1 EXPIRE = SHELL = /bin/bash SKEL = /etc/skel CREATE_MAIL_SPOOL = yes \u5728Ubuntu\u4e2d /etc/default/useradd \u6587\u4ef6\u53ea\u6709\u4e0b\u9762\u8fd9\u4e00\u884c\u3002 SHELL = /bin/sh","title":"4.1.\u521b\u5efa\u7528\u6237useradd"},{"location":"linux/SRE/03-identity-security/#411newusers","text":"\u683c\u5f0f\uff1a newusers \u3002\u5176\u4e2d\u6587\u4ef6 \u7684\u683c\u5f0f\u5982\u4e0b\uff1a :::::: \u4e3e\u4f8b\uff0c\u521b\u5efa\u6587\u4ef6 users.txt \uff1a $ cat ~/users.txt tester1:123:600:1530: \"Test User1,testuser1@abc.com\" :/home/tester1:/bin/bash tester2:123:601:1529:::/bin/bash tester3:123::::: tester4:123::::/home/tester4:/bin/tsh \u770b\u7ed3\u679c\uff1a $ cat /etc/passwd | grep tester tester1:x:600:1530: \"Test User1,testuser1@abc.com\" :/home/tester1:/bin/bash tester2:x:601:1529:::/bin/bash tester3:x:1001:1001::: tester4:x:1002:1002::/home/tester4:/bin/tsh $ cat /etc/group | grep tester tester1:*:1530: tester2:*:1529: tester3:*:1001: tester4:*:1002: $ sudo cat /etc/shadow | grep tester tester1:!:19321:0:99999:7::: tester2:!:19321:0:99999:7::: tester3:!:19321:0:99999:7::: tester4:!:19321:0:99999:7::: $ ls -ld /home/tester* drwxr-xr-x. 1 tester1 tester1 0 Nov 26 00 :32 /home/tester1 drwxr-xr-x. 1 tester4 tester4 0 Nov 26 00 :32 /home/tester4","title":"4.1.1.\u6279\u91cf\u521b\u5efa\u7528\u6237newusers"},{"location":"linux/SRE/03-identity-security/#412chpasswd","text":"\u4e0d\u540c\u65b9\u6cd5\uff1a echo username:password | chpasswd chpasswd < file.txt # file.txt\u6bcf\u884c\u7684\u683c\u5f0f\u662fusername:password paste -d \":\" user.txt passwd.txt | chpasswd \u53c2\u6570 -e \uff1a\u53e3\u4ee4\u4ee5\u52a0\u5bc6\u7684\u65b9\u5f0f\u4f20\u9012\u3002\u5426\u5219\u53e3\u4ee4\u4ee5\u660e\u6587\u7684\u5f62\u5f0f\u4f20\u9012\u3002 \u6ce8\u610f\uff1a \u7528\u6237\u540dusername\u5fc5\u987b\u662f\u5df2\u5b58\u5728\u7684\u7528\u6237 \u666e\u901a\u7528\u6237\u6ca1\u6709\u4f7f\u7528\u8fd9\u4e2a\u6307\u4ee4\u7684\u6743\u9650 \u5982\u679c\u8f93\u5165\u6587\u4ef6\u662f\u6309\u975e\u52a0\u5bc6\u65b9\u5f0f\u4f20\u9012\u7684\u8bdd\uff0c\u8bf7\u5bf9\u8be5\u6587\u4ef6\u8fdb\u884c\u9002\u5f53\u7684\u52a0\u5bc6\u3002 \u6307\u4ee4\u6587\u4ef6\u4e0d\u80fd\u6709\u7a7a\u884c \u4e3e\u4f8b\uff1a echo tester1:112233 | sudo chpasswd $ cat chpasswd.txt tester1:112233 tester2:33445566 $ sudo chpasswd < chpasswd.txt","title":"4.1.2.\u6279\u91cf\u4fee\u6539\u5bc6\u7801chpasswd"},{"location":"linux/SRE/03-identity-security/#413openssl-passwd","text":"\u547d\u4ee4 openssl passwd \u683c\u5f0f\u53ef\u4ee5\u5982\u4e0b\u65b9\u6cd5\u83b7\u5f97\u3002 $ man -f passwd passwd ( 1 ) - change user password passwd ( 1ssl ) - compute password hashes passwd ( 5 ) - password file $ man passwd Man: find all matching manual pages ( set MAN_POSIXLY_CORRECT to avoid this ) * passwd ( 1 ) passwd ( 5 ) passwd ( 1ssl ) Man: What manual page do you want? Man: 1ssl \u4e3e\u4f8b\uff08\u8fd9\u91cc\u7528 \u4ee3\u66ff\u5b9e\u9645\u5bc6\u7801\uff09\uff1a # \u57fa\u4e8e\u7ed9\u5b9a\u5b57\u4e32newpasswd\u751f\u6210sha256\u52a0\u5bc6\u7801\uff0c $ openssl passwd -6 newpasswd # \u521b\u5efa\u65b0\u7528\u6237tester5\uff0c\u8d4b\u4e88\u52a0\u5bc6\u5bc6\u7801 $ useradd -p '' tester1 # \u8bfb\u53d6\u7528\u6237tester5\u7684\u5bc6\u7801\uff0c\u53ef\u4ee5\u9a8c\u8bc1\u662f\u5426\u548c\u4e4b\u524d\u7684\u4e00\u81f4 $ sudo getent shadow tester5 tester5::19321:0:99999:7:::","title":"4.1.3.\u751f\u6210\u52a0\u5bc6\u5bc6\u7801openssl passwd"},{"location":"linux/SRE/03-identity-security/#42usermod","text":"\u6dfb\u52a0\u7528\u6237\u5230\u9644\u52a0\u7ec4 usermod -a -G GROUP USER usermod -a -G GROUP1,GROUP2,GROUP3 USER \u4fee\u6539\u7528\u6237\u4e3b\u7ec4 usermod -a -g GROUP USER \u4fee\u6539\u7528\u6237\u4fe1\u606f usermod -c \"GECOS Comments\" USER \u4fee\u6539\u7528\u6237\u4e3b\u76ee\u5f55\uff0c\u4f7f\u7528\u7edd\u5bf9\u8def\u5f84\uff0c -m \u53c2\u6570\u4f1a\u628a\u539f\u4e3b\u76ee\u5f55\u7684\u5185\u5bb9\u79fb\u52a8\u5230\u65b0\u4e3b\u76ee\u5f55\u3002 usermod -d NEW_HOME_DIR USER usermod -d NEW_HOME_DIR -m USER \u4fee\u6539\u7528\u6237shell usermod -s SHELL USER \u4fee\u6539\u7528\u6237UID usermod -u UID USER \u4fee\u6539\u7528\u6237\u540d\uff08\u4e0d\u5e38\u7528\uff09\uff0c\u540c\u65f6\u4e5f\u9700\u8981\u4fee\u6539\u7528\u6237\u4e3b\u76ee\u5f55\u3002 usermod -l NEW_USER USER \u4fee\u6539\u7528\u6237\u8fc7\u671f\u5c5e\u6027\uff0c\u65e5\u671f\u683c\u5f0f\u662f YYYY-MM-DD usermod -e DATE USER \u5982\u679c\u8bbe\u5b9a\u6c38\u4e0d\u8fc7\u671f\uff0c\u5219\u7f6e\u7a7a\u65e5\u671f\uff1a usermod -e \"\" USER \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684\u8fc7\u671f\u65e5\u671f $ sudo chage -l vagrant Last password change : Oct 30 , 2022 Password expires : never Password inactive : never Account expires : never Minimum number of days between password change : 0 Maximum number of days between password change : 99999 Number of days of warning before password expires : 7 \u9501\u5b9a\u7528\u6237\u3002 \u6b64\u547d\u4ee4\u5c06\u5728\u52a0\u5bc6\u5bc6\u7801\u524d\u63d2\u5165\u4e00\u4e2a\u611f\u53f9\u53f7 (!) \u6807\u8bb0\u3002 \u5f53 /etc/shadow \u6587\u4ef6\u4e2d\u7684\u5bc6\u7801\u5b57\u6bb5\u5305\u542b\u611f\u53f9\u53f7\u65f6\uff0c\u7528\u6237\u5c06\u65e0\u6cd5\u4f7f\u7528\u5bc6\u7801\u9a8c\u8bc1\u767b\u5f55\u7cfb\u7edf\u3002 \u5176\u4ed6\u767b\u5f55\u65b9\u6cd5\u4ecd\u7136\u5141\u8bb8\uff0c\u4f8b\u5982\u57fa\u4e8e\u5bc6\u94a5\u7684\u8eab\u4efd\u9a8c\u8bc1\u6216\u5207\u6362\u5230\u7528\u6237\u3002 \u5982\u679c\u8981\u9501\u5b9a\u8d26\u6237\u5e76\u7981\u7528\u6240\u6709\u767b\u5f55\u65b9\u5f0f\uff0c\u8fd8\u9700\u8981\u5c06\u5230\u671f\u65e5\u671f\u8bbe\u7f6e\u4e3a1\u3002 usermod -L USER usermod -L -e 1 USER \u89e3\u9501\u7528\u6237 usermod -U USER","title":"4.2.\u4fee\u6539\u7528\u6237\u5c5e\u6027usermod"},{"location":"linux/SRE/03-identity-security/#43userdel","text":"userdel \u547d\u4ee4\u6267\u884c\u65f6\uff0c\u4f1a\u8bfb\u53d6 /etc/login.defs \u6587\u4ef6\u7684\u5185\u5bb9\u3002 \u6b64\u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u5c5e\u6027\u4f1a\u8986\u76d6 userdel \u7684\u9ed8\u8ba4\u884c\u4e3a\u3002 \u5982\u679c\u5728\u6b64\u6587\u4ef6\u4e2d\u5c06 USERGROUPS_ENAB \u8bbe\u7f6e\u4e3a yes \uff0c userdel \u5c06\u5220\u9664\u4e0e\u7528\u6237\u540c\u540d\u7684\u7ec4\uff0c\u524d\u63d0\u662f\u6ca1\u6709\u5176\u4ed6\u7528\u6237\u662f\u8be5\u7ec4\u7684\u6210\u5458\u3002 userdel \u547d\u4ee4\u4ece /etc/passwd \u548c /etc/shadow \u6587\u4ef6\u4e2d\u5220\u9664\u7528\u6237\u6761\u76ee\u3002 userdel \u547d\u4ee4\u5220\u9664\u7528\u6237\u5e10\u6237\u65f6\uff0c\u4e00\u822c\u4e0d\u4f1a\u5220\u9664\u7528\u6237\u4e3b\u76ee\u5f55\u548c\u90ae\u4ef6\u5047\u8131\u673amail spool\u76ee\u5f55\u3002 \u4f7f\u7528 -r \u9009\u9879\u5f3a\u5236\u5220\u9664\u7528\u6237\u7684\u4e3b\u76ee\u5f55\u548c\u90ae\u4ef6\u5047\u8131\u673a\u76ee\u5f55\u3002 \u5982\u679c\u8981\u5220\u9664\u7684\u7528\u6237\u4ecd\u7136\u5904\u4e8e\u767b\u5f55\u72b6\u6001\uff0c\u6216\u8005\u6709\u5c5e\u4e8e\u8be5\u7528\u6237\u7684\u6b63\u5728\u8fd0\u884c\u7684\u8fdb\u7a0b\uff0c\u5219 userdel \u547d\u4ee4\u4e0d\u5141\u8bb8\u5220\u9664\u8be5\u7528\u6237\u3002 \u4f7f\u7528 -f \u9009\u9879\u5f3a\u5236\u5220\u9664\u7528\u6237\u5e10\u6237\uff0c\u5373\u4f7f\u7528\u6237\u4ecd\u7136\u767b\u5f55\u6216\u6709\u5c5e\u4e8e\u8be5\u7528\u6237\u7684\u6b63\u5728\u8fd0\u884c\u7684\u8fdb\u7a0b\u4e5f\u662f\u5982\u6b64\u3002 userdel USER userdel -r USER","title":"4.3.\u5220\u9664\u7528\u6237userdel"},{"location":"linux/SRE/03-identity-security/#44id","text":"\u7c7bUnix\u64cd\u4f5c\u7cfb\u7edf\u4e2d\u7684\u6bcf\u4e2a\u7528\u6237\u90fd\u7531\u4e00\u4e2a\u4e0d\u540c\u7684\u6574\u6570\u6807\u8bc6\uff0c\u8fd9\u4e2a\u552f\u4e00\u7684\u6570\u5b57\u79f0\u4e3aUserID\u3002 \u4e3a\u8fdb\u7a0bprocess\u5b9a\u4e49\u4e86\u4e09\u79cd\u7c7b\u578b\u7684UID\uff0c\u53ef\u4ee5\u6839\u636e\u4efb\u52a1\u7684\u6743\u9650\u52a8\u6001\u66f4\u6539\u3002 \u5b9a\u4e49\u7684\u4e09\u79cd\u4e0d\u540c\u7c7b\u578b\u7684UID\u662f\uff1a \u771f\u5b9e\u7528\u6237ID\uff08Real UserId\uff09\uff1a\u5bf9\u4e8e\u4e00\u4e2a\u8fdb\u7a0b\uff0cReal UserId\u5c31\u662f\u542f\u52a8\u5b83\u7684\u7528\u6237\u7684 UserID\u3002 \u5b83\u5b9a\u4e49\u4e86\u8fd9\u4e2a\u8fdb\u7a0b\u53ef\u4ee5\u8bbf\u95ee\u54ea\u4e9b\u6587\u4ef6\u3002 \u6709\u6548\u7528\u6237\u540d\uff08Effective UserID\uff09\uff1a\u5b83\u901a\u5e38\u4e0e Real UserID \u76f8\u540c\uff0c\u4f46\u6709\u65f6\u4f1a\u66f4\u6539\u4e3a\u4f7f\u975e\u7279\u6743\u7528\u6237\u80fd\u591f\u8bbf\u95ee\u90a3\u4e9b\u53ea\u80fd\u7531\u7279\u6743\u7528\u6237\uff08\u5982 root \uff09\u8bbf\u95ee\u7684\u6587\u4ef6\u3002 \u4fdd\u5b58\u7684\u7528\u6237ID\uff08Saved UserID\uff09 \uff1a\u5f53\u4e00\u4e2a\u4ee5\u63d0\u5347\u7684\u6743\u9650\uff08\u901a\u5e38\u662f root \uff09\u8fd0\u884c\u7684\u8fdb\u7a0b\u9700\u8981\u505a\u4e00\u4e9b\u4f4e\u6743\u9650\u7684\u4efb\u52a1\u65f6\u4f7f\u7528\uff0c\u53ef\u4ee5\u901a\u8fc7\u4e34\u65f6\u5207\u6362\u5230\u975e\u7279\u6743\u5e10\u6237\u6765\u5b9e\u73b0\u3002\u5728\u6267\u884c\u4f4e\u6743\u9650\u4efb\u52a1\u65f6\uff0c\u6709\u6548\u7684 UID \u88ab\u66f4\u6539\u4e3a\u67d0\u4e2a\u8f83\u4f4e\u6743\u9650\u7684\u503c\uff0c\u5e76\u4e14 euid \u88ab\u4fdd\u5b58\u5230\u5df2\u4fdd\u5b58\u7684 userID (suid)\u4e2d\uff0c\u4ee5\u4fbf\u5728\u4efb\u52a1\u5b8c\u6210\u65f6\u7528\u4e8e\u5207\u6362\u56de\u7279\u6743\u5e10\u6237\u3002 \u5728\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u6682\u505c\u5728\u65b0\u5bc6\u7801\u8f93\u5165\u8fd9\u4e00\u6b65\u3002 $ ls -ltr /usr/bin/passwd -rwsr-xr-x. 1 root shadow 65208 May 8 2022 /usr/bin/passwd $ passwd Changing password for vagrant. Current password: New password: \u65b0\u5f00\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\u3002 $ ps -a | grep passwd 3040 pts/0 00 :00:00 passwd $ ps -eo pid,euid,ruid | grep 3040 3040 0 1000 \u4e0a\u9762\u8f93\u51fa\u53ef\u4ee5\u770b\u51fa\uff0c passwd \u8fd9\u4e2a\u8fdb\u7a0b\u7684Effective UserID\u662f 0 \u3002Real UserId\u662f 1000 . id \u547d\u4ee4\u67e5\u770b\u7528\u6237\u6709\u6548\u7684UID\u548cGID\u3002 \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684\u4fe1\u606f\uff1a $ id uid = 1000 ( vagrant ) gid = 478 ( wheel ) groups = 478 ( wheel ) ,0 ( root ) context = unconfined_u:unconfined_r:unconfined_t:s0 \u67e5\u770b\u6307\u5b9a\u7528\u6237\u7684\u4fe1\u606f\uff1a $ id vagrant uid = 1000 ( vagrant ) gid = 478 ( wheel ) groups = 0 ( root ) ,478 ( wheel ) \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684GID\uff1a $ id -g 478 \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684UID\uff1a $ id -u 1000 \u67e5\u770b\u5f53\u524d\u7528\u6237\u6240\u6709\u7ec4\u7684GID\uff1a $ id -G 478 0 \u67e5\u770b\u5f53\u524d\u7528\u6237\u540d\uff1a $ id -un vagrant \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684GID $ id -ur 1000 \u53ea\u6709SELinux\u6fc0\u6d3b\u540e\u624d\u6709 $ id -Z unconfined_u:unconfined_r:unconfined_t:s0 \u7c7b\u4f3c\u4e8e whoami \u547d\u4ee4 $ id -znG wheelroot","title":"4.4.\u67e5\u770b\u7528\u6237\u4fe1\u606fid"},{"location":"linux/SRE/03-identity-security/#45su","text":"\u547d\u4ee4 su - username \u662f\u767b\u5f55\u5f0f\u5207\u6362\u7528\u6237\u3002\u4f1a\u8bfb\u53d6\u76ee\u6807\u7528\u6237\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5207\u6362\u81f3\u76ee\u6807\u7528\u6237\u7684\u4e3b\u76ee\u5f55\u3002 \u547d\u4ee4 su username \u662f\u975e\u767b\u5f55\u5f0f\u5207\u6362\u7528\u6237\u3002\u4e0d\u8bfb\u53d6\u76ee\u6807\u7528\u6237\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u4e0d\u6539\u53d8\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 \u5207\u6362\u6210root\u7528\u6237\uff0c\u5e76\u4f7f\u7528zsh shell\u3002 su -s /usr/bin/zsh su -s /usr/bin/zsh root \u5207\u6362\u6210tester1\u7528\u6237\uff0c\u4f7f\u7528bash shell su - tester1 -s /bin/bash su - -s /bin/bash tester1 \u4fdd\u7559\u5f53\u524d\u7528\u6237\u73af\u5883\u4e0d\u53d8\u3002 su -p root \u4e0d\u4ea4\u4e92\u5f0f\u5207\u6362\u7528\u6237\uff0c\u53ea\u7528\u76ee\u6807\u7528\u6237\u6267\u884c\u67d0\u4e9b\u547d\u4ee4\u3002 su -c ps su - root -c \"getent passwd\" su - root -s /bin/bash -c \"getent passwd\" root \u7528\u6237\u5207\u6362\u81f3\u5176\u4ed6\u7528\u6237\u4e0d\u9700\u8981\u5bc6\u7801\uff0c\u975e root \u7528\u6237\u5207\u6362\u5176\u4ed6\u7528\u6237\u9700\u8981\u5bc6\u7801\u3002","title":"4.5.\u5207\u6362\u7528\u6237su"},{"location":"linux/SRE/03-identity-security/#46","text":"","title":"4.6.\u8bbe\u7f6e\u5bc6\u7801"},{"location":"linux/SRE/03-identity-security/#461passwd","text":"\u4fee\u6539\u5f53\u524d\u7528\u6237\u81ea\u5df1\u7684\u5bc6\u7801\uff1a passwd \u4fee\u6539\u5176\u4ed6\u7528\u6237\u7684\u5bc6\u7801\uff1a sudo passwd root \u67e5\u770b\u67d0\u4e2a\u7528\u6237\u5bc6\u7801\u72b6\u6001\uff1a $ sudo passwd -S root root P 10 /30/2022 -1 -1 -1 -1 $ sudo passwd -S vagrant vagrant P 10 /30/2022 0 99999 7 -1 \u68c0\u67e5\u5168\u90e8\u7528\u6237\u7684\u5bc6\u7801\u72b6\u6001\uff1a sudo passwd -Sa \u5bc6\u7801\u72b6\u6001\u8bf4\u660e\uff1a Username Status Date Last Changed Minimum Age Maximum Age Warning Period Inactivity Period vagrant P 10 /30/2022 0 99999 7 -1 root P 10 /30/2022 -1 -1 -1 -1 Status\u7684\u63cf\u8ff0\uff1a P : Usable password NP : No password L : Locked password Age\u7684\u4e00\u4e9b\u7279\u6b8a\u503c\uff1a 9999 : Never expires 0 : Can be changed at anytime -1 : Not active \u5f3a\u5236\u8981\u6c42\u7528\u6237\u4e0b\u6b21\u767b\u5f55\u65f6\u4fee\u6539\u5bc6\u7801\uff1a $ sudo passwd -e tester1 $ sudo passwd -S tester1 tester1 P 01 /01/1970 0 99999 7 -1 \u7528\u6237tester1\u7684\u5bc6\u7801\u65e5\u671f\u5df2\u7ecf\u88ab\u6539\u6210 01/01/1970 \u4e86\u3002\u8fd9\u4e2a\u65e5\u671f\u7b97\u662fUnix\u7684\u201c\u7eaa\u5143\uff08epoch\uff09\u201d\u65e5\u671f\uff0c\u610f\u5473\u7740Unix\u7684\u65e5\u671f\u8d77\u70b9\uff0c0\u5929\u3002 \u9501\u5b9a\u67d0\u4e2a\u7528\u6237\uff1a $ sudo passwd -l tester1 $ sudo passwd -S tester1 tester1 L 01 /01/1970 0 99999 7 -1 \u6b64\u65f6\u7528\u6237 tester1 \u7684\u72b6\u6001\u680f\u5df2\u7ecf\u53d8\u6210\u4e86 L \uff0c\u9501\u5b9a\u72b6\u6001\u3002 \u89e3\u9501\u67d0\u4e2a\u7528\u6237\uff1a $ sudo passwd -u tester1 $ sudo passwd -S tester1 tester1 P 01 /01/1970 0 99999 7 -1 \u6b64\u65f6\u7528\u6237 tester1 \u7684\u72b6\u6001\u680f\u5df2\u7ecf\u4ece L \u53d8\u56de\u4e86 P \uff0c\u89e3\u9664\u4e86\u9501\u5b9a\u72b6\u6001\u3002 \u5220\u9664\u7528\u6237\u5bc6\u7801\u3002\u8fd9\u4e2a\u64cd\u4f5c\u614e\u91cd\uff0c\u5bc6\u7801\u5220\u9664\u540e\u8be5\u7528\u6237\u53ef\u4ee5\u4e0d\u9700\u8981\u5bc6\u7801\u5c31\u80fd\u8bbf\u95ee\u7cfb\u7edf\u3002 $ sudo passwd -d tester1 $ sudo passwd -S tester1 tester1 NP 01 /01/1970 0 99999 7 -1 \u6b64\u65f6\u7528\u6237 tester1 \u7684\u72b6\u6001\u680f\u662f NP \u3002","title":"4.6.1.passwd"},{"location":"linux/SRE/03-identity-security/#462pwgen","text":"\u5b89\u88c5\u5305\u3002 mkpasswd\u547d\u4ee4\u6709\u6b67\u4e49\uff0c2\u4e2a\u540c\u540d\u547d\u4ee4\u5b9e\u73b0\u4e0d\u540c\u529f\u80fd\uff0c\u751f\u6210\u968f\u673a\u5bc6\u7801\u5efa\u8bae\u4f7f\u7528 pwgen \u547d\u4ee4\u3002Rocky9\u6ca1\u6709\u627e\u5230pwgen\u5305\u3002 sudo zypper in pwgen sudo apt install pwgen \u968f\u673a\u751f\u6210\u957f\u5ea68\u4f4d\u5b89\u5168\u5bc6\u7801\u3002 pwgen -s -1 \u968f\u673a\u751f\u6210\u957f\u5ea614\u4f4d\u5b89\u5168\u5bc6\u7801\u3002 pwgen -s -1 14 \u968f\u673a\u751f\u62102\u4e2a\u957f\u5ea615\u4f4d\u5b89\u5168\u5bc6\u7801\u3002 pwgen -s -1 15 2 \u968f\u673a\u751f\u62105\u4e2a\u5bc6\u7801\uff0c\u957f\u5ea610\u4f4d\uff0c\u6bcf\u4e2a\u5bc6\u7801\u81f3\u5c11\u542b\u4e00\u4e2a\u7279\u6b8a\u5b57\u7b26\uff0c\u7ed3\u679c\u4ee5\u5217\u5f62\u5f0f\u8f93\u51fa\u3002 pwgen -s -1 -y 10 5 \u751f\u6210\u957f\u5ea68\uff0c\u542b\u6709\u6570\u5b57\uff0c\u542b\u6709\u5927\u5c0f\u5199\u5b57\u6bcd\u7684\u5bc6\u78014\u4e2a\uff0c\u5217\u6253\u5370 pwgen -s -n -c -C -1 8 4 \u751f\u6210\u957f\u5ea68\uff0c\u4e0d\u542b\u6570\u5b57\uff0c\u53ea\u542b\u5c0f\u5199\u5b57\u6bcd\uff0c\u5217\u6253\u5370 pwgen -s -c -A -0 -1 8 4 \u751f\u6210\u957f\u5ea616\uff0c\u542b\u6709\u6570\u5b57\uff0c\u542b\u6709\u5927\u5c0f\u5199\u5b57\u6bcd\uff0c\u542b\u6709\u7279\u6b8a\u5b57\u7b26\u7684\u5bc6\u78013\u4e2a\uff0c\u884c\u6253\u5370 pwgen -s -n -c -y -1 16 3 \u751f\u6210\u957f\u5ea680\uff0c\u4e0d\u542b\u5143\u97f3\u548c\u6570\u5b57\uff0c\u81f3\u5c11\u542b\u6709\u4e00\u4e2a\u5927\u5199\u5b57\u6bcd\uff0c\u884c\u6253\u5370 pwgen -s -v -c -0 80 1","title":"4.6.2.pwgen"},{"location":"linux/SRE/03-identity-security/#463","text":"\u65b9\u6cd51\uff1a $ echo -e '123456\\n123456' | sudo passwd tester1 New password: BAD PASSWORD: it is too simplistic/systematic BAD PASSWORD: is too simple Retype new password: passwd: password updated successfully \u65b9\u6cd52\uff1a Rocky\u4e2d\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u65b9\u6cd5\u3002 pwgen -ncy1 16 1 | tee passwd.txt | sudo passwd --stdin tester1 openSUSE\u548cUbuntu\u53ef\u4ee5\u7528\u4e0b\u9762\u65b9\u6cd5\u3002 echo \"tester1:\" ` pwgen -ncy1 16 1 ` | tee passwd.txt | sudo chpasswd \u65b9\u6cd53\uff1a\u6839\u636e\u9884\u5148\u7ed9\u5b9a\u7684\u7528\u6237\u5217\u8868\uff0c\u6279\u91cf\u751f\u6210\u5bc6\u7801\u3002 $ cat > user-list.txt < user.txt < file 67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov 1 11 :20 symlinkfile1-1 -> symlinkfile1 67274682 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file 33555262 drwxr-xr-x. 2 vagrant wheel 6 Nov 1 11 :30 typelink \u4ee5 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11:14 file \u4e3a\u4f8b\uff1a 67274680 : inode \u7d22\u5f15\u8282\u70b9\u7f16\u53f7\u3002 -rw-r--r-- \uff1a\u6587\u4ef6\u7c7b\u578b\u53ca\u6743\u9650 - \uff1a\u6587\u4ef6\u7c7b\u578b\uff0c\u4f8b\u5b50\u4e2d\u51fa\u73b0\u4e86\u4e09\u79cd\uff0c - \uff0c l \u548c d \u3002 - \uff1a\u666e\u901a\u6587\u4ef6 d \uff1a\u76ee\u5f55 l \uff1a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\uff08link\uff09 b \uff1a\u5757\u8bbe\u5907\uff08block\uff09 c \uff1a\u5b57\u7b26\u8bbe\u5907\uff08character\uff09 p \uff1a\u7ba1\u9053\u6587\u4ef6\uff08pipe\uff09 s \uff1a\u5957\u63a5\u5b57\u6587\u4ef6\uff08socket\uff09 rw-r--r-- \uff1a\u6587\u4ef6\u6743\u9650\uff0c\u4ece\u5de6\u5230\u53f3\u4f9d\u6b21\u4e3a\uff1a\uff08\u7528\u6237\u7684\u6700\u7ec8\u6743\u9650\uff0c\u662f\u4ece\u5de6\u5411\u53f3\u5339\u914d\uff0c\u4e00\u65e6\u5339\u914d\u5219\u6743\u9650\u7acb\u5373\u751f\u6548\uff0c\u4e0d\u518d\u5411\u53f3\u7ee7\u7eed\u5339\u914d\uff09 rw- \uff1a\u6587\u4ef6\u5c5e\u4e3b\u6743\u9650\uff08u\uff09\uff0c\u4f8b\u5b50\u4e2d\u662f vagrant \u3002 r-- \uff1a\u6587\u4ef6\u5c5e\u7ec4\u7684\u6743\u9650\uff08g\uff09\uff0c\u4f8b\u5b50\u4e2d\u662f wheel \u3002 r-- \uff1a\u5176\u4ed6\u7ec4\u7684\u6743\u9650\uff08o\uff09\u3002 . \uff1a\u8fd9\u4e2a\u70b9\u8868\u793a\u6587\u4ef6\u5e26\u6709SELinux\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\uff08SELinux Contexts\uff09\u3002\u5173\u95edSELinux\uff0c\u65b0\u521b\u5efa\u7684\u6587\u4ef6\u5c31\u4e0d\u4f1a\u518d\u6709\u8fd9\u4e2a\u70b9\u4e86\u3002\u4f46\u662f\uff0c\u4ee5\u524d\u521b\u5efa\u7684\u6587\u4ef6\u672c\u6765\u6709\u8fd9\u4e2a\u70b9\u7684\u8fd8\u4f1a\u663e\u793a\u8fd9\u4e2a\u70b9\uff08\u867d\u7136SELinux\u4e0d\u8d77\u4f5c\u7528\u4e86\uff09\u3002 3 \uff1a\u786c\u94fe\u63a5\u6570\uff0c\u4f8b\u5b50\u4e2d file \u548c hardlinkfile1 \u548c hardlinkfile2 \u4e4b\u95f4\u662f\u786c\u94fe\u63a5\uff0c\u6240\u4ee5\u8fd9\u4e09\u4e2a\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u90fd\u662f 3 \u3002 vagrant \uff1a\u6587\u4ef6\u5c5e\u4e3bowner wheel \uff1a\u6587\u4ef6\u5c5e\u7ec4group 31 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u5927\u5c0f Nov 1 11:14 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u521b\u5efa\u65e5\u671f\u548c\u65f6\u95f4 file \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u540d\u79f0 \u4e0b\u9762\u662f\u547d\u4ee4 ls -ihl \u5728openSUSE\u548cUbuntu\u4e0a\u7684\u663e\u793a\u7ed3\u679c\u3002 $ ls -ihl 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 file 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile1 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile2 233648 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile1 -> file 233650 lrwxrwxrwx 1 vagrant wheel 12 Nov 1 15 :52 symlinkfile1-1 -> symlinkfile1 233649 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile2 -> file 233646 drwxr-xr-x 1 vagrant wheel 0 Nov 1 15 :51 typelink","title":"7.\u6743\u9650\u7ba1\u7406"},{"location":"linux/SRE/03-identity-security/#71chown","text":"chown \u547d\u4ee4\u4fee\u6539\u6587\u4ef6\u5c5e\u4e3b\uff08\u6240\u6709\u8005\uff0cowner\uff09\u3002 \u4fee\u6539\u6587\u4ef6\u5c5e\u4e3b\u4e3aroot\u3002 $ ll f1.txt -rw-r--r--. 1 vagrant wheel 41 Nov 14 22 :23 f1.txt $ sudo chown root f1.txt $ ll f1.txt -rw-r--r--. 1 root wheel 41 Nov 14 22 :23 f1.txt \u4fee\u6539\u6587\u4ef6\u7684\u5c5e\u7ec4\u4e3abin\u3002 $ sudo chown :bin f1.txt $ ll f1.txt -rw-r--r--. 1 root bin 41 Nov 14 22 :23 f1.txt \u540c\u65f6\u4fee\u6539\u6587\u4ef6\u7684\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u3002 $ sudo chown vagrant.wheel f1.txt $ ll f1.txt -rw-r--r--. 1 vagrant wheel 41 Nov 14 22 :23 f1.txt \u53c2\u7167\u67d0\u6587\u4ef6\u4fee\u6539\u53e6\u4e00\u6587\u4ef6\u7684\u5c5e\u6027\u3002 $ ll file.py -rw-r--r--. 1 vagrant wheel 56 Nov 13 22 :50 file.py $ ll user.txt -rw-r--r--. 1 root bin 21 Nov 27 23 :59 user.txt $ sudo chown root.bin user.txt $ sudo chown --reference = user.txt file.py $ ll file.py -rw-r--r--. 1 root bin 56 Nov 13 22 :50 file.py \u9012\u5f52\u4fee\u6539\u6240\u6709\u5b50\u76ee\u5f55\u53ca\u6587\u4ef6\u7684\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u3002 sudo chown -R vagrant.wheel ~","title":"7.1.\u4fee\u6539\u5c5e\u4e3bchown"},{"location":"linux/SRE/03-identity-security/#72chgrp","text":"\u4fee\u6539\u76ee\u5f55\u7684\u5c5e\u7ec4\u3002 sudo chgrp bin ~~ \u4fee\u6539\u76ee\u5f55\u53ca\u5b50\u76ee\u5f55\u53ca\u6587\u4ef6\u7684\u5c5e\u7ec4\u3002 sudo chgrp -R bin ~~","title":"7.2.\u4fee\u6539\u5c5e\u7ec4chgrp"},{"location":"linux/SRE/03-identity-security/#73","text":"\u6587\u4ef6\uff1a r \uff1a\u53ef\u4ee5\u8bfb\u53d6\u8be5\u6587\u4ef6\u5185\u5bb9\uff0c\u6bd4\u5982\u901a\u8fc7 cat \u547d\u4ee4\u3002 w \uff1a\u53ef\u4ee5\u4fee\u6539\u8be5\u6587\u4ef6\u5185\u5bb9\uff0c\u53ef\u4ee5\u53ea\u6709 w \u800c\u6ca1\u6709 r \u3002 x \uff1a\u53ef\u4ee5\u628a\u8be5\u6587\u4ef6\u63d0\u8bf7\u5185\u6838\u542f\u52a8\u4e3a\u4e00\u4e2a\u8fdb\u7a0b\uff0c\u5373\u53ef\u4ee5\u6267\u884c\u8be5\u6587\u4ef6\uff08\u8be5\u6587\u4ef6\u7684\u5185\u5bb9\u5fc5\u987b\u662f\u53ef\u4ee5\u6267\u884c\uff09\u3002 \u76ee\u5f55\uff1a\uff08\u5bf9\u76ee\u5f55\u800c\u8a00\uff0c\u901a\u5e38\u9700\u8981\u7ed9 r \u548c x \u6743\u9650\uff09\uff08\u4ece\u76ee\u5f55\u89d2\u5ea6\u770b\uff0c\u76ee\u5f55\u5185\u6587\u4ef6\u5217\u8868\u7b49\u4e8e\u76ee\u5f55\u8282\u70b9\u7684\u5185\u5bb9\uff09 r \uff1a\u80fd\u770b\u6587\u4ef6\u5217\u8868\uff0c\u4f46\u4e0d\u80fd\u8bbf\u95ee\u6240\u542b\u6587\u4ef6\u7684\u5185\u5bb9\u53ca\u5176\u5c5e\u6027\u4fe1\u606f\uff0c\u5305\u62ecinode\u53f7\u3002 w \uff1a\u80fd\u5728\u8be5\u76ee\u5f55\u5185\u521b\u5efa\u548c\u5220\u9664\u6587\u4ef6\uff0c\u4e0d\u7531\u76ee\u5f55\u5185\u6587\u4ef6\u672c\u8eab\u7684\u6743\u9650\u51b3\u5b9a\u3002 x \uff1a\u80fdcd\u8fdb\u76ee\u5f55\uff0c\u80fd\u901a\u8fc7 ls -l file \u548c stat file \u67e5\u770b\u8be5\u76ee\u5f55\u4e2d\u5236\u5b9a\u6587\u4ef6\u7684\u5143\u6570\u636e\u3002 X \uff1a\u8868\u793a\u53ea\u6709\u5f53\u8be5\u6587\u4ef6\u662f\u4e2a\u5b50\u76ee\u5f55\u6216\u8005\u8be5\u6587\u4ef6\u5df2\u7ecf\u88ab\u8bbe\u5b9a\u8fc7\u4e3a\u53ef\u6267\u884c\u3002 \u6709\u53ea\u8bfb\u6743\u9650\u7684\u7528\u6237\u4e0d\u80fd\u7528cd\u8fdb\u5165\u8be5\u76ee\u5f55\uff0c\u8fd8\u5fc5\u987b\u6709\u6267\u884c\u6743\u9650\u624d\u80fd\u8fdb\u5165\u3002 \u6709\u6267\u884c\u6743\u9650\u7684\u7528\u6237\u53ea\u6709\u5728\u77e5\u9053\u6587\u4ef6\u540d\uff0c\u5e76\u62e5\u6709\u8bfb\u6743\u5229\u7684\u60c5\u51b5\u4e0b\u624d\u53ef\u4ee5\u8bbf\u95ee\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u3002 \u5fc5\u987b\u6709\u8bfb\u548c\u6267\u884c\u6743\u9650\u624d\u53ef\u4ee5ls\u5217\u51fa\u76ee\u5f55\u6e05\u5355\uff0c\u6216\u4f7f\u7528cd\u547d\u4ee4\u8fdb\u5165\u76ee\u5f55\u3002 \u6709\u76ee\u5f55\u7684\u5199\u6743\u9650\uff0c\u53ef\u4ee5\u521b\u5efa\u3001\u5220\u9664\u6216\u4fee\u6539\u76ee\u5f55\u4e0b\u7684\u4efb\u4f55\u6587\u4ef6\u6216\u5b50\u76ee\u5f55\uff0c\u5373\u4f7f\u4f7f\u8be5\u6587\u4ef6\u6216\u5b50\u76ee\u5f55\u5c5e\u4e8e\u5176\u4ed6\u7528\u6237\u4e5f\u662f\u5982\u6b64\u3002 \u5e38\u7528\u6743\u9650\u4f8b\u5b50\uff1a -rw------- ( 600 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\u548c\u5199\u7684\u6743\u9650 -rw-r--r-- ( 644 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\u548c\u5199\u7684\u6743\u9650\uff0c\u7ec4\u548c\u5176\u4ed6\u4eba\u53ea\u6709\u8bfb\u7684\u6743\u9650 -rwx------ ( 700 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\uff0c\u5199\uff0c\u6267\u884c\u7684\u6743\u9650 -rwxr-xr-x ( 755 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\uff0c\u5199\uff0c\u6267\u884c\u7684\u6743\u9650\uff0c\u7ec4\u548c\u5176\u4ed6\u4eba\u53ea\u6709\u8bfb\u548c\u6267\u884c\u7684\u6743\u9650 -rwx--x--x ( 711 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\uff0c\u5199\uff0c\u6267\u884c\u7684\u6743\u9650\uff0c\u7ec4\u548c\u5176\u4ed6\u4eba\u53ea\u6709\u6267\u884c\u7684\u6743\u9650 -rw-rw-rw- ( 666 ) \u6bcf\u4e2a\u4eba\u90fd\u6709\u8bfb\u5199\u7684\u6743\u9650 -rwxrwxrwx ( 777 ) \u6bcf\u4e2a\u4eba\u90fd\u6709\u8bfb\u5199\u548c\u6267\u884c\u7684\u6743\u9650","title":"7.3.\u6587\u4ef6\u548c\u76ee\u5f55\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#74chmod","text":"\u547d\u4ee4\u683c\u5f0f\uff1a chmod [ -cfvR ] [ --help ] [ --version ] mode file mode \u5b57\u4e32\u683c\u5f0f\u4e3a\uff1a [ ugoa ][ +- =][ rwxXst ] who: u \u6587\u4ef6\u6240\u6709\u8005 g \u6587\u4ef6\u6240\u6709\u8005\u6240\u5728\u7ec4 o \u5176\u4ed6\u7528\u6237 a \u6240\u6709\u7528\u6237\uff0c\u76f8\u5f53\u4e8e ugo operator: + \u4e3a\u6307\u5b9a\u7684\u7528\u6237\u7c7b\u578b\u589e\u52a0\u6743\u9650 - \u53bb\u9664\u6307\u5b9a\u7528\u6237\u7c7b\u578b\u7684\u6743\u9650 = \u8bbe\u7f6e\u6307\u5b9a\u7528\u6237\u6743\u9650\u7684\u8bbe\u7f6e\uff0c\u5373\u5c06\u7528\u6237\u7c7b\u578b\u7684\u6240\u6709\u6743\u9650\u91cd\u65b0\u8bbe\u7f6e permission: r \u8bbe\u7f6e\u4e3a\u53ef\u8bfb\u6743\u9650 w \u8bbe\u7f6e\u4e3a\u53ef\u5199\u6743\u9650 x \u8bbe\u7f6e\u4e3a\u53ef\u6267\u884c\u6743\u9650 X \u7279\u6b8a\u6267\u884c\u6743\u9650\uff0c\u53ea\u6709\u5f53\u6587\u4ef6\u4e3a\u76ee\u5f55\u6587\u4ef6\uff0c\u6216\u8005\u5176\u4ed6\u7c7b\u578b\u7684\u7528\u6237\u6709\u53ef\u6267\u884c\u6743\u9650\u65f6\uff0c\u624d\u5c06\u6587\u4ef6\u6743\u9650\u8bbe\u7f6e\u53ef\u6267\u884c s \u5f53\u6587\u4ef6\u88ab\u6267\u884c\u65f6\uff0c\u6839\u636ewho\u53c2\u6570\u6307\u5b9a\u7684\u7528\u6237\u7c7b\u578b\u8bbe\u7f6e\u6587\u4ef6\u7684 setuid \u6216\u8005 setgid \u6743\u9650 t \u8bbe\u7f6e\u7c98\u8d34\u4f4d\uff0c\u53ea\u6709\u8d85\u7ea7\u7528\u6237\u53ef\u4ee5\u8bbe\u7f6e\u8be5\u4f4d\uff0c\u53ea\u6709\u6587\u4ef6\u6240\u6709\u8005u\u53ef\u4ee5\u4f7f\u7528\u8be5\u4f4d\u3002 \u793a\u4f8b\uff1a \u5c06\u6587\u4ef6 file1.txt \u8bbe\u4e3a\u6240\u6709\u4eba\u7686\u53ef\u8bfb\u53d6\u3002 chmod ugo+r file1.txt \u5c06\u6587\u4ef6 file1.txt \u8bbe\u4e3a\u6240\u6709\u4eba\u7686\u53ef\u8bfb\u53d6\u3002 chmod a+r file1.txt \u5c06\u6587\u4ef6 file1.txt \u4e0e file2.txt \u8bbe\u4e3a\u8be5\u6587\u4ef6\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u90fd\u53ef\u5199\u5165\uff0c\u4f46\u5176\u4ed6\u7528\u6237\u4e0d\u53ef\u5199\u5165\u3002 chmod ug+w,o-w file1.txt file2.txt \u4e3a ex1.py \u6587\u4ef6\u5c5e\u4e3b\u589e\u52a0\u53ef\u6267\u884c\u6743\u9650\u3002 chmod u+x ex1.py \u5c06\u76ee\u524d\u76ee\u5f55\u4e0b\u7684\u6240\u6709\u6587\u4ef6\u4e0e\u5b50\u76ee\u5f55\u7686\u8bbe\u4e3a\u4efb\u4f55\u4eba\u53ef\u8bfb\u53d6\u3002 chmod -R a+r * \u7ed9 file \u7684\u6240\u6709\u7528\u6237\u589e\u52a0\u8bfb\u6743\u9650 chmod a+r file \u5220\u9664 file \u7684\u6240\u6709\u7528\u6237\u7684\u6267\u884c\u6743\u9650 chmod a-x file \u7ed9 file \u7684\u6240\u6709\u7528\u6237\u589e\u52a0\u8bfb\u5199\u6743\u9650 chmod a+rw file \u7ed9 file \u7684\u6240\u6709\u7528\u6237\u589e\u52a0\u8bfb\u5199\u6267\u884c\u6743\u9650 chmod +rwx file \u5bf9 file \u7684\u5c5e\u4e3b\u8bbe\u7f6e\u8bfb\u5199\u6743\u9650\uff0c\u6e05\u7a7a\u5c5e\u7ec4\u548c\u5176\u4ed6\u7528\u6237\u5bf9 file \u7684\u6240\u6709\u6743\u9650\uff08\u7a7a\u683c\u4ee3\u8868\u65e0\u6743\u9650\uff09 chmod u = rw,go = file \u5bf9\u76ee\u5f55 docs \u548c\u5176\u5b50\u76ee\u5f55\u4e2d\u7684\u6240\u6709\u6587\u4ef6\u7ed9\u5c5e\u4e3b\u589e\u52a0\u8bfb\u6743\u9650\uff0c\u800c\u5bf9\u5c5e\u7ec4\u548c\u5176\u4ed6\u7528\u6237\u5220\u9664\u8bfb\u6743\u9650 chmod -R u+r,go-r docs \u5bf9 file \u7684\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u8bbe\u7f6e\u8bfb\u5199\u6743\u9650, \u4e3a\u5176\u4ed6\u7528\u6237\u8bbe\u7f6e\u8bfb\u6743\u9650 chmod 664 file \u5bf9 file \u7684\u5c5e\u4e3b\u8bbe\u7f6e\u8bfb\u5199\u6267\u884c\u6743\u9650\uff0c\u76f8\u5f53\u4e8e u=rwx (4+2+1)\uff0c\u8bbe\u7f6e\u5c5e\u7ec4\u8bfb\u548c\u6267\u884c\u6743\u9650\uff0c\u76f8\u5f53\u4e8e go=rx (4+1 & 4+1)\u3002 0 \u6ca1\u6709\u7279\u6b8a\u6a21\u5f0f chmod 0755 file 4 \u8bbe\u7f6e\u4e86\u8bbe\u7f6e\u7528\u6237ID\u4f4d\uff0c\u5269\u4e0b\u7684\u76f8\u5f53\u4e8e u=rwx (4+2+1)\u548c go=rx (4+1 & 4+1)\u3002 chmod 4755 file \u5220\u9664\u53ef\u6267\u884c\u6743\u9650\u5bf9 path/ \u4ee5\u53ca\u5176\u6240\u6709\u7684\u76ee\u5f55\uff08\u4e0d\u5305\u62ec\u6587\u4ef6\uff09\u7684\u6240\u6709\u7528\u6237\uff0c\u4f7f\u7528 -type f \u5339\u914d\u6587\u4ef6 find path/ -type d -exec chmod a-x {} \\; \u5141\u8bb8\u6240\u6709\u7528\u6237\u6d4f\u89c8\u6216\u901a\u8fc7\u76ee\u5f55 path/ find path/ -type d -exec chmod a+x {} \\;","title":"7.4.\u6743\u9650\u4fee\u6539chmod"},{"location":"linux/SRE/03-identity-security/#75umask","text":"umask \u7684\u503c\uff0c\u5b9a\u4e49\u4e86\u6240\u6709\u65b0\u5efa\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u7684\u521d\u59cb\u6743\u9650\u7684\u3002 \u67e5\u770b\u5f53\u524d\u6743\u9650\u63a9\u7801\uff1a $ umask 0022 \u5728\u4e0d\u8003\u8651 umask \u7684\u60c5\u51b5\u4e0b\uff0c\u6587\u4ef6\u7684\u9ed8\u8ba4\u6743\u9650\u662f 666 (rw-rw-rw-)\uff0c\u76ee\u5f55\u7684\u9ed8\u8ba4\u6743\u9650\u662f 777 (rwxrwxrwx)\u3002 \u5728 umask \u7684\u503c\u4e3a 0022 \u7684\u60c5\u51b5\u4e0b\uff0c\u6587\u4ef6\u7684\u9ed8\u8ba4\u6743\u9650\u662f 644 (rw-r--r--)\uff0c\u76ee\u5f55\u7684\u9ed8\u8ba4\u6743\u9650\u662f 755 (rwxr-xr-x)\u3002 \u8ba1\u7b97\u65b9\u6cd5\uff1a Files: ( Default ) 6 6 6 ( umask ) 0 2 2 ---------------- ( Result ) 6 4 4 Directories: ( Default ) 7 7 7 ( umask ) 0 2 2 ---------------- ( Result ) 7 5 5 \u5982\u679c umask \u7684\u503c\u4e3a 0077 \u7684\u60c5\u51b5\u4e0b\uff0c\u6587\u4ef6\u7684\u9ed8\u8ba4\u6743\u9650\u662f 600 (rw-------)\uff0c\u76ee\u5f55\u7684\u9ed8\u8ba4\u6743\u9650\u662f 700 (rwx------)\u3002 \u8ba1\u7b97\u65b9\u6cd5\uff1a Files: ( Default ) 6 6 6 ( umask ) 0 7 7 ---------------- ( Result ) 6 0 0 Directories: ( Default ) 7 7 7 ( umask ) 0 7 7 ---------------- ( Result ) 7 0 0 \u4e3e\u4f8b\uff1a $ umask 022 $ touch file2 $ ll file2 -rw-r--r--. 1 vagrant wheel 0 Nov 28 23 :13 file2 $ umask 077 $ touch file1 $ ll file1 -rw-------. 1 vagrant wheel 0 Nov 28 23 :12 file1 $ umask 022 $ mkdir ./tmp1 $ umask 077 $ mkdir ./tmp2 $ ls -dl tmp* drwxr-xr-x. 1 vagrant wheel 0 Nov 28 23 :14 tmp1 drwx------. 1 vagrant wheel 0 Nov 28 23 :14 tmp2","title":"7.5.\u9ed8\u8ba4\u6743\u9650umask"},{"location":"linux/SRE/03-identity-security/#76","text":"\u9664\u4e86\u4e09\u79cd\u5e38\u89c1\u7684\u6743\u9650rwx\uff0c\u8fd8\u6709\u4e09\u79cd\u7279\u6b8a\u6743\u9650\uff1aSUID\uff0cSGID\uff0cSticky\u3002 SUID\uff1a\u5c5e\u4e3bs\u6743\u9650\uff0c\u79f0\u4e3aSet UID \u524d\u63d0\uff1a\u8fdb\u7a0b\u6709\u5c5e\u4e3b\u548c\u5c5e\u7ec4\uff0c\u6587\u4ef6\u6709\u5c5e\u4e3b\u548c\u5c5e\u7ec4 \u4efb\u4f55\u53ef\u6267\u884c\u7a0b\u5e8f\u6587\u4ef6\u80fd\u4e0d\u80fd\u542f\u52a8\u4e3a\u8fdb\u7a0b\uff0c\u53d6\u51b3\u4e8e\u53d1\u8d77\u8005\u5bf9\u7a0b\u5e8f\u6587\u4ef6\u662f\u5426\u62e5\u6709\u6267\u884c\u6743\u9650\u3002 \u542f\u52a8\u4e3a\u8fdb\u7a0b\u4e4b\u540e\uff0c\u5176\u8fdb\u7a0b\u7684\u5c5e\u4e3b\u4e3a\u53d1\u8d77\u8005\u3002 \u8fdb\u7a0b\u8bbf\u95ee\u6587\u4ef6\u662f\u7684\u6743\u9650\uff0c\u53d6\u51b3\u4e8e\u8fdb\u7a0b\u7684\u53d1\u8d77\u8005\u3002 \u53ea\u5bf9\u4e8c\u8fdb\u5236\u53ef\u6267\u884c\u7a0b\u5e8f\u6587\u4ef6\u6709\u6548\u3002\u5f53\u6267\u884c\u8be5\u6587\u4ef6\u65f6\uff0c\u53d1\u8d77\u8005\u5c06\u81ea\u52a8\u5177\u6709\u8be5\u6587\u4ef6\u6240\u6709\u8005\u7684\u6743\u9650\u3002 \u5bf9\u76ee\u5f55\u65e0\u6548\u3002 $ ll file1 -rw-------. 1 vagrant wheel 0 Nov 28 23 :12 file1 $ sudo chmod u+s file1 $ ll file1 -rwS------. 1 vagrant wheel 0 Nov 28 23 :12 file1 \u5982\u679c\u5c5e\u4e3b\u7684 x \u4f4d\u4e0a\u662f-\uff0c\u5219\u5728\u5c5e\u4e3b\u7684 x \u4f4d\u4e0a\u6807\u8bb0\u5927\u5199 S \uff0c\u5426\u5219\u6807\u8bb0\u5c0f\u5199 s \u3002\u5982\u4e0b\uff1a $ chmod 777 file1 $ ll file1 -rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23 :12 file1 $ sudo chmod u+s file1 $ ll file1 -rwsrwxrwx. 1 vagrant wheel 0 Nov 28 23 :12 file1 \u4e0b\u97622\u7ec4\u547d\u4ee4\u5b9e\u73b0\u540c\u6837\u6548\u679c\u3002 sudo chmod 4xxx file1 chmod 777 file1 sudo chmod u+s file1 \u53d6\u6d88SUID\u3002 sudo chmod u-s file1 SGID\uff1a\u5c5e\u7ec4s\u6743\u9650\uff0c\u79f0\u4e3aSet GID \u5982\u679c\u4f5c\u7528\u4e8e\u4e8c\u8fdb\u5236\u53ef\u6267\u884c\u6587\u4ef6\u4e0a\uff0c\u5f53\u6267\u884c\u8be5\u6587\u4ef6\u4e3a\u8fdb\u7a0b\u4e4b\u540e\uff0c\u53d1\u8d77\u8005\u5c06\u81ea\u52a8\u5177\u6709\u8be5\u6587\u4ef6\u6240\u5c5e\u7ec4\u7684\u6743\u9650\uff0c\u8fdb\u7a0b\u7684\u5c5e\u7ec4\u4e3a\u53d1\u8d77\u8005\u7684\u5c5e\u7ec4\u3002 \u5982\u679c\u4f5c\u7528\u4e8e\u76ee\u5f55\u4e0a\uff0c\u5219\u8be5\u76ee\u5f55\u4e0b\u65b0\u5efa\u7acb\u7684\u76ee\u5f55\u548c\u6587\u4ef6\u90fd\u81ea\u52a8\u4ece\u6b64\u76ee\u5f55\u7ee7\u627f\u3002 $ sudo chmod g+s file2 $ ll file2 -rw-r-Sr--. 1 vagrant wheel 0 Nov 28 23 :13 file2 \u5982\u679c\u5c5e\u7ec4\u7684 x \u4f4d\u4e0a\u662f-\uff0c\u5219\u5728\u5c5e\u7ec4\u7684 x \u4f4d\u4e0a\u6807\u8bb0\u5927\u5199 S \uff0c\u5426\u5219\u6807\u8bb0\u5c0f\u5199 s \u3002\u5982\u4e0b\uff1a $ chmod 777 file2 $ ll file2 -rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23 :13 file2 $ sudo chmod g+s file2 $ ll file2 -rwxrwsrwx. 1 vagrant wheel 0 Nov 28 23 :13 file2 \u4e0b\u97622\u7ec4\u547d\u4ee4\u5b9e\u73b0\u540c\u6837\u6548\u679c\u3002 sudo chmod 2xxx file2 chmod 777 file2 sudo chmod g+s file2 \u53d6\u6d88SGID\u3002 sudo chmod g-s file2 \u5bf9\u4e8e\u76ee\u5f55\uff0c\u4e0b\u9762\u6f14\u793a\u53ef\u4ee5\u770b\u5230\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\u7684\u7ee7\u627f\u6027\u3002 $ ll -d data drwxr-xr-x. 1 vagrant bin 0 Nov 28 20 :55 data $ sudo chmod g+s .~ $ ll -d data drwxr-sr-x. 1 vagrant bin 0 Nov 28 20 :55 data $ cd data $ touch file2 $ ll file2 -rw-r--r--. 1 vagrant bin 0 Nov 29 21 :10 file2 $ mkdir tmp3 $ ll -d tmp3 drwxr-sr-x. 1 vagrant bin 0 Nov 29 21 :10 tmp3 Sticky Bit\uff1a\u7b80\u79f0\u4e3aSBIT\u6743\u9650 \u53ea\u9488\u5bf9\u76ee\u5f55\u6709\u6548\u3002\u5b83\u8868\u793a\u53ea\u80fd\u8ba9\u5176\u5c5e\u4e3b\u4ee5\u53caroot\u53ef\u4ee5\u5220\u9664\u3001\u91cd\u547d\u540d\u3001\u79fb\u52a8\u8be5\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u3002 Sticky\u8bbe\u7f6e\u5728\u6587\u4ef6\u4e0a\u65e0\u610f\u4e49\u3002 \u5982\u679c\u5176\u4ed6\u7684 x \u4f4d\u4e0a\u662f-\uff0c\u5219\u5728\u5176\u4ed6\u7684 x \u4f4d\u4e0a\u6807\u8bb0\u5927\u5199 T \uff0c\u5426\u5219\u6807\u8bb0\u5c0f\u5199 t \u3002 $ ll -d .~ drwxr-sr-x. 1 vagrant bin 18 Nov 29 21 :10 .~ $ sudo chmod o+t .~ $ ll -d .~ drwxr-sr-t. 1 vagrant bin 18 Nov 29 21 :10 .~ $ cd data $ touch file1 $ mkdir tmp1 $ ll file1 -rw-r--r--. 1 vagrant bin 0 Nov 29 21 :37 file1 $ ll -d tmp1 drwxr-sr-x. 1 vagrant bin 0 Nov 29 21 :37 tmp1 \u7279\u6b8a\u6743\u9650\u8bbe\u7f6e\u6570\u5b57\u6cd5\uff1a \u8bbe\u7f6eSUID User Group Others r w s r w s r w x r w S BIN 100 1 1 1 1 1 1 1 1 1 1 1 0 OCT 4 7 7 7 6 \u8bbe\u7f6eSGID User Group Others r w x r w s r w x r w S BIN 010 1 1 1 1 1 1 1 1 1 1 1 0 OCT 2 7 7 7 6 \u8bbe\u7f6eSticky Bit - SBIT User Group Others r w x r w x r w t r w T BIN 001 1 1 1 1 1 1 1 1 1 1 1 0 OCT 1 7 7 7 6","title":"7.6.\u7279\u6b8a\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#77chattr","text":"\u547d\u4ee4\u683c\u5f0f\uff1a chattr [ -RVf ] [ -v version ] [ mode ] files... \u5176\u4e2dmode\u7684\u5b57\u4e32\u683c\u5f0f\uff1a {+|-|=}[aAcCdDeijsStTu] \u5c5e\u6027 i \uff1a \u5982\u679c\u5bf9\u6587\u4ef6\u8bbe\u7f6e i \u5c5e\u6027\uff0c\u90a3\u4e48\u4e0d\u5141\u8bb8\u5bf9\u6587\u4ef6\u8fdb\u884c\u5220\u9664\u3001\u6539\u540d\uff0c\u4e5f\u4e0d\u80fd\u6dfb\u52a0\u548c\u4fee\u6539\u6570\u636e\uff1b \u5982\u679c\u5bf9\u76ee\u5f55\u8bbe\u7f6e i \u5c5e\u6027\uff0c\u90a3\u4e48\u53ea\u80fd\u4fee\u6539\u76ee\u5f55\u4e0b\u6587\u4ef6\u4e2d\u7684\u6570\u636e\uff0c\u4f46\u4e0d\u5141\u8bb8\u5efa\u7acb\u548c\u5220\u9664\u6587\u4ef6\uff1b \u5728openSUSE\u4e0b\u6267\u884c\uff0c\u5206\u533a\u6587\u4ef6\u7c7b\u578b\u662fbtrfs\u683c\u5f0f\u3002 $ touch filetest $ lsattr filetest ---------------------- filetest $ chattr +i filetest chattr: Operation not permitted while setting flags on filetest $ sudo chattr +i filetest $ lsattr filetest ----i----------------- filetest $ rm filetest rm: cannot remove 'filetest' : Operation not permitted $ sudo rm filetest rm: cannot remove 'filetest' : Operation not permitted $ echo \"test\" >> filetest -bash: filetest: Operation not permitted $ sudo echo \"test\" >> filetest -bash: filetest: Operation not permitted $ sudo chattr -i filetest \u5c5e\u6027 a \uff1a \u5982\u679c\u5bf9\u6587\u4ef6\u8bbe\u7f6e a \u5c5e\u6027\uff0c\u90a3\u4e48\u53ea\u80fd\u5728\u6587\u4ef6\u4e2d\u5897\u52a0\u6570\u636e\uff0c\u4f46\u662f\u4e0d\u80fd\u5220\u9664\u548c\u4fee\u6539\u6570\u636e\uff1b \u5982\u679c\u5bf9\u76ee\u5f55\u8bbe\u7f6e a \u5c5e\u6027\uff0c\u90a3\u4e48\u53ea\u5141\u8bb8\u5728\u76ee\u5f55\u4e2d\u5efa\u7acb\u548c\u4fee\u6539\u6587\u4ef6\uff0c\u4f46\u662f\u4e0d\u5141\u8bb8\u5220\u9664\u6587\u4ef6\uff1b \u5728openSUSE\u4e0b\u6267\u884c\uff0c\u5206\u533a\u6587\u4ef6\u7c7b\u578b\u662fbtrfs\u683c\u5f0f\u3002 lsattr filetest ---------------------- filetest $ chattr +a filetest chattr: Operation not permitted while setting flags on filetest $ sudo chattr +a filetest $ echo \"test\" >> filetest $ rm filetest rm: cannot remove 'filetest' : Operation not permitted $ sudo rm filetest rm: cannot remove 'filetest' : Operation not permitted $ sudo chattr -a filetest \u5c5e\u6027 u \uff1a \u8bbe\u7f6e\u6b64\u5c5e\u6027\u7684\u6587\u4ef6\u6216\u76ee\u5f55\uff0c\u5728\u5220\u9664\u65f6\uff0c\u5176\u5185\u5bb9\u4f1a\u88ab\u4fdd\u5b58\uff0c\u4ee5\u4fdd\u8bc1\u540e\u671f\u80fd\u591f\u6062\u590d\uff0c\u5e38\u7528\u6765\u9632\u6b62\u610f\u5916\u5220\u9664\u6587\u4ef6\u6216\u76ee\u5f55\u3002 \u5728Ubuntu\u4e0b\u6267\u884c\uff0c\u5206\u533a\u6587\u4ef6\u7c7b\u578b\u662fext4\u683c\u5f0f\u3002 $ touch filetest $ sudo chattr +u filetest $ lsattr filetest -u------------e------- filetest $ rm filetest \u5c5e\u6027 s \uff1a \u548c u \u76f8\u53cd\uff0c\u5220\u9664\u6587\u4ef6\u6216\u76ee\u5f55\u65f6\uff0c\u4f1a\u88ab\u5f7b\u5e95\u5220\u9664\uff08\u76f4\u63a5\u4ece\u786c\u76d8\u4e0a\u5220\u9664\uff0c\u7136\u540e\u75280\u586b\u5145\u6240\u5360\u7528\u7684\u533a\u57df\uff09\uff0c\u4e0d\u53ef\u6062\u590d\u3002 \u63d0\u793a\uff1a \u547d\u4ee4 chattr \u548c lsattr \u7684\u53ef\u64cd\u4f5c\u5c5e\u6027\u4f9d\u8d56\u4e8e\u6587\u4ef6\u6240\u5904\u5206\u533a\u7684\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\uff0c\u4f8b\u5982\uff0cext4\u548cxfs\u7684\u7ed3\u679c\u4f1a\u6709\u4e0d\u540c\u3002 \u5386\u53f2\uff1a\u547d\u4ee4 chattr \uff08\u7528\u4e8e\u64cd\u4f5c\u5c5e\u6027\uff09\u548c lsattr \uff08\u7528\u4e8e\u5217\u51fa\u5c5e\u6027\uff09\u6700\u521d\u4e13\u7528\u4e8e\u7b2c\u4e8c\u4e2a\u6269\u5c55\u6587\u4ef6\u7cfb\u7edf\u7cfb\u5217\uff08ext2\u3001ext3\u3001ext4\uff09\uff0c\u5e76\u4e14\u4f5c\u4e3a e2fsprogs \u5305\u7684\u4e00\u90e8\u5206\u63d0\u4f9b\u3002\u7136\u800c\uff0c\u6b64\u529f\u80fd\u5df2\u5168\u90e8\u6216\u90e8\u5206\u6269\u5c55\u5230\u8bb8\u591a\u5176\u4ed6\u7cfb\u7edf\uff0c\u5305\u62ec XFS\u3001ReiserFS\u3001JFS \u548c OCFS2\u3002 btrfs \u6587\u4ef6\u7cfb\u7edf\u5305\u62ec\u5c5e\u6027\u529f\u80fd\uff0c\u5305\u62ec C \u6807\u5fd7\uff0c\u7531\u4e8e\u4e0e CoW \u76f8\u5173\u7684\u6027\u80fd\u8f83\u6162\uff0c\u5b83\u5173\u95ed\u4e86btrfs\u7684\u5185\u7f6e\u5199\u65f6\u590d\u5236 (CoW) \u529f\u80fd\u3002","title":"7.7.\u8bbe\u5b9a\u6587\u4ef6\u7279\u6b8a\u5c5e\u6027chattr"},{"location":"linux/SRE/03-identity-security/#8acl","text":"","title":"8.\u8bbf\u95ee\u63a7\u5236\u5217\u8868ACL"},{"location":"linux/SRE/03-identity-security/#81acl","text":"ACL\u7684\u5168\u79f0\u662fAccess Control List\u3002 \u4f20\u7edf\u7684POSIX\u6743\u9650\u6982\u5ff5\u4f7f\u7528\u4e09\u79cd\u7528\u6237\u7c7b\u578b\u6765\u5206\u914d\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6743\u9650\uff1a\u6240\u6709\u8005Owning Owner\uff0c\u6240\u6709\u8005\u7ec4Owning Group\u548c\u5176\u4ed6\u7528\u6237Other Users\u3002\u53ef\u4ee5\u4e3a\u6bcf\u4e2a\u7528\u6237\u7c7b\u578b\u8bbe\u7f6e\u4e09\u4e2a\u6743\u9650\u4f4d\uff0c\u8d4b\u4e88\u8bfb\uff08r\uff09\uff0c\u5199\uff08w\uff09\u548c\u6267\u884c\uff08x\uff09\u7684\u6743\u9650\u3002 \u6240\u6709\u8005Owning Owner\u6743\u9650\uff08\u5c5e\u4e3b\u6743\u9650\uff09 \u5c5e\u7ec4Owning Group\u6743\u9650 \u5176\u4ed6\uff08\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\uff09\u7528\u6237Other Users\u7684\u6743\u9650 \u4f20\u7edf\u7684\u4e09\u79cd\u6743\u9650\u9002\u7528\u4e8e\u5927\u591a\u6570\u5b9e\u9645\u6848\u4f8b\u3002\u4f46\u662f\uff0c\u5bf9\u4e8e\u66f4\u590d\u6742\u7684\u573a\u666f\u6216\u66f4\u9ad8\u7ea7\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u7cfb\u7edf\u7ba1\u7406\u5458\u5fc5\u987b\u4f7f\u7528\u8bb8\u591a\u6280\u5de7\u6765\u89c4\u907f\u4f20\u7edf\u6743\u9650\u7684\u9650\u5236\u3002 \u8bbf\u95ee\u63a7\u5236\u5217\u8868ACL\u63d0\u4f9b\u4e86\u5bf9\u4f20\u7edf\u6587\u4ef6\u6743\u9650\u6982\u5ff5\u7684\u6269\u5c55\u3002\u5b83\u4eec\u5141\u8bb8\u6211\u4eec\u4e3a\u5355\u4e2a\u7528\u6237\u6216\u7ec4\u5206\u914d\u6743\u9650\uff0c\u5373\u4f7f\u8fd9\u4e9b\u7528\u6237\u6216\u7ec4\u4e0e\u539f\u59cb\u6240\u6709\u8005\u6216\u5c5e\u7ec4\u4e0d\u5bf9\u5e94\u3002 ACL\u662fLinux\u5185\u6838\u7684\u4e00\u9879\u529f\u80fd\uff0c\u652f\u6301Ext\u2154/4\uff0cXFS\u548cBtrFS\u6587\u4ef6\u7cfb\u7edf\u4ee5\u53ca\u5176\u4ed6\u6587\u4ef6\u7cfb\u7edf\u3002 \u4f7f\u7528ACL\uff0c\u6211\u4eec\u53ef\u4ee5\u521b\u5efa\u590d\u6742\u7684\u65b9\u6848\uff0c\u800c\u65e0\u9700\u5728\u5e94\u7528\u7a0b\u5e8f\u7ea7\u522b\u4e0a\u53bb\u5b9e\u73b0\u590d\u6742\u7684\u6743\u9650\u6a21\u578b\u3002\u5728\u4f7f\u7528\u63d0\u4f9bSamba\u6587\u4ef6\u548c\u6253\u5370\u670d\u52a1\u7684Linux\u670d\u52a1\u5668\u66ff\u6362Windows\u670d\u52a1\u5668\u7684\u60c5\u51b5\u4e0b\uff0cACL\u7684\u4f18\u52bf\u975e\u5e38\u660e\u663e\u3002\u7531\u4e8eSamba\u652f\u6301ACL\uff0c\u56e0\u6b64\u53ef\u4ee5\u5728Linux\u670d\u52a1\u5668\u548cWindows\u4e2d\u914d\u7f6e\u7528\u6237\u6743\u9650\u3002 \u901a\u8fc7ACL\u6765\u5141\u8bb8\u5bf9\u6240\u6709\u8005\u7528\u6237\u4e4b\u5916\u7684\u5355\u4e2a\u7528\u6237\u8fdb\u884c\u6587\u4ef6\u5199\u6743\u9650\u662f\u4e00\u79cd\u7b80\u5355\u7684\u65b9\u6848\u3002\u4f7f\u7528\u4f20\u7edf\u65b9\u6cd5\uff0c\u6211\u4eec\u5fc5\u987b\u521b\u5efa\u4e00\u4e2a\u65b0\u7ec4\uff0c\u4f7f\u4e24\u4e2a\u7528\u6237\u6210\u4e3a\u8be5\u7ec4\u7684\u6210\u5458\uff0c\u5c06\u8be5\u6587\u4ef6\u7684\u6240\u6709\u7ec4\u66f4\u6539\u4e3a\u65b0\u7ec4\uff0c\u7136\u540e\u6388\u4e88\u8be5\u7ec4\u6587\u4ef6\u7684\u5199\u6743\u9650\u3002\u521b\u5efa\u7ec4\u5e76\u4f7f\u4e24\u4e2a\u7528\u6237\u6210\u4e3a\u8be5\u7ec4\u7684\u6210\u5458\u5219\u9700\u8981\u5229\u7528root\u6743\u9650\u6765\u5b9e\u73b0\u3002 \u4f7f\u7528ACL\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u4f7f\u6240\u6709\u8005\u548c\u6307\u5b9a\u7528\u6237\u5bf9\u6587\u4ef6\u5177\u6709\u5199\u6743\u9650\u6765\u5b9e\u73b0\u76f8\u540c\u7684\u7ed3\u679c\u3002 \u6b64\u65b9\u6cd5\u7684\u53e6\u4e00\u4e2a\u4f18\u70b9\u662f\u7cfb\u7edf\u7ba1\u7406\u5458\u65e0\u9700\u53c2\u4e0e\u521b\u5efa\u7ec4\u3002\u7528\u6237\u53ef\u4ee5\u81ea\u5df1\u51b3\u5b9a\u6388\u4e88\u8c01\u8bbf\u95ee\u5176\u6587\u4ef6\u7684\u6743\u9650\u3002 \u63d0\u793a\uff1a \u4f7f\u7528ACL\u65f6 ls \u7684\u8f93\u51fa\u7ed3\u679c\u4f1a\u53d1\u751f\u53d8\u5316\u3002\u6dfb\u52a0\u4e00\u4e2a\u52a0\u53f7+ \u6765\u8bf4\u660e\u5df2\u4e3a\u6b64\u6587\u4ef6\u5b9a\u4e49ACL\uff0c\u4e14\u5b9a\u4e49ACL\u540e\uff0c\u6240\u663e\u793a\u7684\u5c5e\u7ec4\u6743\u9650\u662fACL\u63a9\u7801\u7684\u503c\uff0c\u800c\u4e0d\u518d\u662f\u539f\u6765\u5c5e\u7ec4\u7684\u6743\u9650\u3002","title":"8.1.ACL"},{"location":"linux/SRE/03-identity-security/#82acl","text":"Minimal ACLs\uff08\u6700\u5c0fACL\uff09\uff08\u5b9e\u9645\u7528\u9014\uff1a\u4e0ePOSIX\u6743\u9650\u76f8\u540c\uff09 \u4e0e\u6587\u4ef6\u6a21\u5f0f\u6743\u9650\u4f4d\u7b49\u6548\u7684ACL\u79f0\u4e3a\u6700\u5c0fACL \u5206\u4e09\u79cd\u7c7b\u578b\u7684ACL\u6761\u76ee\uff0c\u8fd9\u4e9b\u5bf9\u5e94\u4e8e\u6587\u4ef6\u548c\u76ee\u5f55\u7684\u4f20\u7edf\u6743\u9650\u4f4d Owning User \u6240\u6709\u8005 Owning Group \u6240\u6709\u8005\u7ec4 Others \u5176\u4ed6\u7ec4 Extended ACLs\uff08\u6269\u5c55ACL\uff09 \u5177\u6709\u591a\u4e8e\u4e0a\u8ff0\u4e09\u4e2aACL\u6761\u76ee\u7684ACL\u79f0\u4e3a\u6269\u5c55ACL \u6269\u5c55ACL\u8fd8\u5305\u542b\u63a9\u7801\u6761\u76ee\uff0c\u53ef\u4ee5\u5305\u542b\u4efb\u610f\u6570\u91cf\u7684\u6307\u5b9a\u7528\u6237\u548c\u6307\u5b9a\u7ec4\u6761\u76ee","title":"8.2.ACL\u7684\u57fa\u672c\u7c7b\u578b"},{"location":"linux/SRE/03-identity-security/#83acl","text":"\u7528\u6237\u7c7b\uff08User classes\uff09\u3002 \u4f20\u7edf\u7684POSIX\u6743\u9650\u6982\u5ff5\u4f7f\u7528\u4e09\u79cd\u7528\u6237\u7c7b\u6765\u5206\u914d\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6743\u9650\uff1a\u6240\u6709\u8005Owning Owner\uff0c\u6240\u6709\u8005\u7ec4Owning Group\u548c\u5176\u4ed6\u7528\u6237Other Users\u3002\u53ef\u4ee5\u4e3a\u6bcf\u4e2a\u7528\u6237\u7c7b\u578b\u8bbe\u7f6e\u4e09\u4e2a\u6743\u9650\u4f4d\uff0c\u8d4b\u4e88\u8bfb\uff08r\uff09\uff0c\u5199\uff08w\uff09\u548c\u6267\u884c\uff08x\uff09\u7684\u6743\u9650\u3002 Owner class \u6240\u6709\u8005\u7c7b Group class \u7ec4\u7c7b Other class \u5176\u4ed6\u7c7b ACL\u8bbf\u95ee\u6743\u9650\uff08Access ACL\uff09\uff1a\u786e\u5b9a\u5404\u79cd\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\uff08\u6587\u4ef6\u548c\u76ee\u5f55\uff09\u7684\u7528\u6237\u548c\u7ec4\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u9ed8\u8ba4ACL\uff08Default ACL\uff09\uff1a\u53ea\u80fd\u5e94\u7528\u4e8e\u76ee\u5f55\u3002 \u5b83\u4eec\u786e\u5b9a\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u5728\u521b\u5efa\u65f6\u4ece\u5176\u7236\u76ee\u5f55\u7ee7\u627f\u7684\u6743\u9650\u3002 ACL\u6761\u76ee\uff08ACL entry\uff09\uff1a \u6bcf\u4e2aACL\u7531\u4e00\u7ec4ACL\u6761\u76ee\u7ec4\u6210\u3002 ACL\u6761\u76ee\u5305\u542b\u7c7b\u578b\uff08type\uff09\uff0c\u6761\u76ee\u5f15\u7528\u7684\u7528\u6237\u6216\u7ec4\u7684\u9650\u5b9a\u7b26\uff08qualifier\uff09\uff0c\u4ee5\u53ca\u4e00\u7ec4\u6743\u9650\uff08permissions\uff09\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u6761\u76ee\u7c7b\u578b\uff0c\u672a\u5b9a\u4e49\u7ec4\u6216\u7528\u6237\u7684\u9650\u5b9a\u7b26\u3002","title":"8.3.ACL\u672f\u8bed"},{"location":"linux/SRE/03-identity-security/#84acl","text":"Named user \u6307\u5b9a\u7528\u6237: Lets you assign permissions to individual users. \u5141\u8bb8\u6211\u4eec\u4e3a\u6307\u5b9a\u7528\u6237\u5206\u914d\u6743\u9650\u3002 Named group \u6307\u5b9a\u7ec4: Lets you assign permissions to individual groups. \u5141\u8bb8\u6211\u4eec\u4e3a\u5236\u5b9a\u7ec4\u5206\u914d\u6743\u9650\u3002 Mask \u63a9\u7801: Lets you limit the permissions granted to named users or groups. \u5141\u8bb8\u6211\u4eec\u9650\u5236\u7ed9\u4e88\u6307\u5b9a\u7528\u6237\u6216\u6307\u5b9a\u7ec4\u7684\u6743\u9650\u3002 \u6240\u4ee5\u53ef\u80fd\u7684ACL\u7c7b\u578b Type Text Form owner user::rwx named user user:name:rwx owning group group::rwx named group group:name:rwx mask mask::rwx other other::rwx \u4e0ePOSIX.1\u6743\u9650\u6a21\u578b\u4e0d\u540c\uff0c\u7ec4\u7c7bgroup class\u53ef\u4ee5\u5305\u542b\u5177\u6709\u4e0d\u540c\u6743\u9650\u96c6\u7684ACL\u6761\u76ee\uff0c\u56e0\u6b64\u5355\u72ec\u7684\u7ec4\u7c7b\u6743\u9650\u4e0d\u518d\u8db3\u4ee5\u8868\u793a\u5b83\u5305\u542b\u7684\u6240\u6709ACL\u6761\u76ee\u7684\u6240\u6709\u8be6\u7ec6\u6743\u9650\u3002 \u56e0\u6b64\uff0c\u7ec4\u7c7b\u578b\u6743\u9650\u7684\u542b\u4e49\u88ab\u91cd\u65b0\u5b9a\u4e49\u3002\u5728\u65b0\u8bed\u4e49\u4e0b\uff0c\u7ec4\u7c7b\u578b\u6743\u9650\u8868\u793a\u7ec4\u7c7b\u4e2d\u7684\u4efb\u4f55\u6761\u76ee\u5c06\u6388\u4e88\u7684\u6743\u9650\u7684**\u4e0a\u9650**\uff08upper bound\uff09\u3002 \u6b64\u4e0a\u9650\u5c5e\u6027\u53ef\u786e\u4fdd\u5728\u4f7f\u7528ACL\u63a7\u5236\u540e\uff0c\u5e94\u7528\u7a0b\u5e8f\u4e0d\u4f1a\u7a81\u7136\u6216\u8005\u610f\u5916\u5730\u6388\u4e88\u989d\u5916\u7684\u6743\u9650\u3002 \u5728\u6700\u5c0fACL\u4e2d\uff0c\u7ec4\u7c7b\u6743\u9650\u4e0e\u6240\u6709\u8005\u7ec4\u6743\u9650\u76f8\u540c\u3002\u5728\u6269\u5c55ACL\u4e2d\uff0c\u7ec4\u7c7b\u53ef\u4ee5\u5305\u542b\u5176\u4ed6\u7528\u6237\u6216\u7ec4\u7684\u6761\u76ee\u3002\u8fd9\u4f1a\u5bfc\u81f4\u4e00\u4e2a\u95ee\u9898\uff1a\u8fd9\u4e9b\u9644\u52a0\u6761\u76ee\u4e2d\u7684\u4e00\u4e9b\u53ef\u80fd\u62e5\u6709\u672a\u5305\u542b\u5728\u6240\u6709\u8005\u7ec4\u6761\u76ee\uff08owning group entry\uff09\u4e2d\u7684\u6743\u9650\uff0c\u56e0\u6b64\u6240\u6709\u8005\u7ec4\u6761\u76ee\u6743\u9650\u53ef\u80fd\u4e0e\u7ec4\u7c7b\u6743\u9650\uff08group class\uff09\u4e0d\u540c\u3002 \u901a\u8fc7\u63a9\u7801\uff08mask entry\uff09\u89e3\u51b3\u4e86\u8fd9\u4e2a\u95ee\u9898\u3002 \u4f7f\u7528\u6700\u5c0fACL\uff0c\u7ec4\u7c7b\u6743\u9650\u6620\u5c04\u5230\u6240\u6709\u8005\u7ec4\u6761\u76ee\u6743\u9650\u3002With minimal ACLs, the group class permissions map to the owning group entry permissions. \u4f7f\u7528\u6269\u5c55ACL\u65f6\uff0c\u7ec4\u7c7b\u6743\u9650\u6620\u5c04\u5230\u63a9\u7801\u6761\u76ee\u6743\u9650\uff0c\u800c\u6240\u6709\u8005\u7ec4\u6761\u76ee\u4ecd\u5b9a\u4e49\u62e5\u6709\u7ec4\u6743\u9650\u3002With extended ACLs, the group class permissions map to the mask entry permissions, whereas the owning group entry still defines the owning group permissions.","title":"8.4.ACL\u6743\u9650\u5206\u7c7b"},{"location":"linux/SRE/03-identity-security/#85acl","text":"\u8bbe\u5b9aACL\u6743\u9650\uff1a setfacl Syntax: setfacl [OPTIONS] [ACL-ENTRIES] Option Description -m : Add or modify an ACL entry -x : Remove an ACL entry -d : Set a default ACL -b : Remove all extended ACL entries -M : restore ACLs that have been written to a file \u6ce8\u610f\uff1a--set\u9009\u9879\u4f1a\u628a\u539f\u6709\u7684ACL\u9879\u90fd\u5220\u9664\uff0c\u7528\u65b0\u7684\u66ff\u4ee3\uff0c\u6240\u4ee5\u4e00\u5b9a\u8981\u5305\u542bUGO\u7684\u8bbe\u7f6e\uff0c\u4e0d\u80fd\u50cf-m\u533b\u9662\u53ea\u6dfb\u52a0ACL\u3002 setfacl --set u::rw,u:vagrant:rw,g::r,o::- file1 \u8bfb\u53d6ACL\u6743\u9650\uff1a getfacl Syntax: getfacl [OPTIONS] Option Description -a : Display the file access control list -d : Display the default access control list -R : List the ACLs of all files and directories recursively","title":"8.5.ACL\u64cd\u4f5c\u547d\u4ee4"},{"location":"linux/SRE/03-identity-security/#86acl","text":"","title":"8.6.ACL\u5b9e\u4f8b\u89e3\u6790"},{"location":"linux/SRE/03-identity-security/#861","text":"\u9879\u76ee\u76ee\u5f55 ~/project1 \u9879\u76ee\u7ecf\u7406 pm1 \u5bf9\u8fd9\u4e2a\u76ee\u5f55\u62e5\u6709\u8bbf\u95ee\u548c\u4fee\u6539\u6743\u9650 \u9879\u76ee\u6210\u5458 tm1 \u53ef\u4ee5\u8bbf\u95ee\u548c\u4fee\u6539\u8fd9\u4e2a\u76ee\u5f55 \u975e\u9879\u76ee\u6210\u5458 tm2 \u4e0d\u80fd\u8bbf\u95ee ~/project1 \u76ee\u5f55\u3002 \u9879\u76ee\u76ee\u5f55 ~/project1 \u7684\u6743\u9650\u89c4\u5212 \u9879\u76ee\u7ecf\u7406 pm1 \u662f\u8fd9\u4e2a\u76ee\u5f55\u7684\u5c5e\u4e3b\uff0c\u6743\u9650\u4e3a rwx \u9879\u76ee\u7ecf\u7406 pm1 \u5c5e\u4e8e project1 \u7ec4 \u9879\u76ee\u6210\u5458 tm1 \u4e0e pm1 \u5728\u540c\u4e00\u4e2a project1 \u7ec4\uff0c\u6743\u9650\u662f rw \u5176\u4ed6\u4eba\u7684\u6743\u9650\u8bbe\u5b9a\u4e3a 0 \u9879\u76ee\u4e34\u65f6\u6210\u5458tm2\u7684\u6743\u9650\u9700\u6c42 \u80fd\u8bbf\u95ee project1 \u76ee\u5f55\uff0c\u4f46\u53ea\u80fd\u5177\u6709 r \u548c x \u6743\u9650 \u89e3\u51b3\u65b9\u6cd5 \u5f53\u51fa\u73b0\u8fd9\u79cd\u60c5\u51b5\u65f6\uff0c\u666e\u901a\u6743\u9650\u4e2d\u7684\u4e09\u79cd\u8eab\u4efd\uff08owner\uff0cgroup\uff0cothers\uff09\u5c31\u4e0d\u80fd\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0c\u800cACL\u6743\u9650\u53ef\u4ee5\u3002 \u5728\u4f7f\u7528ACL\u6743\u9650\u7ed9\u7528\u6237 tm2 \u965a\u4e88\u6743\u9650\u65f6\uff0c tm2 \u65e2\u4e0d\u662f ~/project1 \u76ee\u5f55\u7684\u5c5e\u4e3b\uff0c\u4e5f\u4e0d\u662f\u5c5e\u7ec4\uff0c\u4ec5\u4ec5\u8d4b\u4e88\u7528\u6237 tm2 \u9488\u5bf9 ~/project1 \u76ee\u5f55\u7684r-x\u6743\u9650\uff0c \u5c5e\u4e8e\u5355\u72ec\u6307\u5b9a\u7528\u6237\u5e76\u5355\u72ec\u5206\u914d\u6743\u9650\uff0c\u89e3\u51b3\u4e86\u7528\u6237\u8eab\u4efd\u4e0d\u8db3\u7684\u95ee\u9898\u3002 \u62d3\u5c55\u95ee\u9898 \u7ed9 ~/project1 \u76ee\u5f55\u6dfb\u52a0\u5176\u4ed6\u7ec4 project2 \u7684\u8bbf\u95ee\u6743\u9650 \u901a\u8fc7 mask \u6765\u8c03\u6574\u7528\u6237 tm2 \u5b9e\u9645\u6709\u6548\u6743\u9650 \u9ed8\u8ba4ACL\u6743\u9650 \u9012\u5f52ACL\u6743\u9650 \u5220\u9664ACL\u6743\u9650","title":"8.6.1.\u5b9e\u4f8b\u63cf\u8ff0"},{"location":"linux/SRE/03-identity-security/#862","text":"\u521b\u5efa\u6d4b\u8bd5\u7528\u6237 $ whoami vagrant $ sudo groupadd project1 $ sudo groupadd project2 $ sudo useradd -m -g project1 pm1 $ sudo useradd -m -g project1 tm1 $ sudo useradd -m -g project2 tm2 $ sudo passwd pm1 $ sudo passwd tm1 $ sudo passwd tm2 $ cat /etc/group ...... project1:x:1535: project2:x:1536: ...... $ cat /etc/passwd ...... pm1:x:2003:1535::/home/pm1:/bin/bash tm1:x:2004:1535::/home/tm1:/bin/bash tm2:x:2005:1536::/home/tm2:/bin/bash ...... \u521b\u5efa\u6d4b\u8bd5\u76ee\u5f55 project1 , \u6307\u5b9a project1 \u76ee\u5f55\u7684\u6743\u9650\uff0c\u521b\u5efa\u6d4b\u8bd5\u6587\u4ef6 file1 \u3002 $ su - pm1 $ cd ~ $ mkdir project1 $ ls -dl project1 drwxr-xr-x. 1 pm1 project1 0 Dec 4 06 :25 project1 $ chmod 770 project1/ $ ls -dl project1 drwxrwx---. 1 pm1 project1 0 Dec 4 06 :25 project1 $ echo \"hello from $USER \" > ./project1/file1 $ cat ./project1/file1 hello from pm1 \u76ee\u5f55 project1 \u5f53\u524d\u6743\u9650\u5feb\u7167 \u5c5e\u4e3b\uff1a pm1 \uff0c\u5bf9 ~/project1 \u76ee\u5f55\u6709 rwx \u6743\u9650 \u5c5e\u7ec4\uff1a project1 \uff0c\u5305\u542b\u7528\u6237 pm1 \u548c tm1 \uff0c\u5bf9 ~/project1 \u76ee\u5f55\u6709 rwx \u6743\u9650 \u5176\u4ed6\u7ec4\uff1a\u6ca1\u6709\u8bbf\u95ee\u6743\u9650 \u76ee\u5f55 ~/project1 \u5f53\u524d\u7684ACL\u5feb\u7167 $ getfacl ./project1/ # file: home/pm1/project1/ # owner: pm1 # group: project1 user::rwx group::rwx other::---","title":"8.6.2.\u521d\u59cb\u5316\u73af\u5883"},{"location":"linux/SRE/03-identity-security/#863acl","text":"\u7ed9 ~/project1 \u76ee\u5f55\u6dfb\u52a0\u65b0\u7528\u6237 tm2 \uff0c\u6743\u9650\u4e3a rwx \u3002\u76ee\u5f55 ~/project1 \u7684\u66f4\u65b0\u540e\u7684\u6743\u9650\u4f4d\u53d8\u6210\u4e86 drwxrwx---+ \u3002 $ su - pm1 $ setfacl -m u:tm2:rx ./project1/ $ ls -dl ./project1 drwxrwx---+ 1 pm1 project1 0 Dec 4 06 :25 project1 $ getfacl ~/project1/ # file: project1 \uff08\u6587\u4ef6\u540d\uff09 # owner: pm1 \uff08Owner \u6587\u4ef6\u5c5e\u4e3b\uff09 # group: project1 \uff08Owing Group \u6587\u4ef6\u5c5e\u7ec4\uff09 user::rwx \uff08Ower\u6587\u4ef6\u5c5e\u4e3b\u7684\u6743\u9650\uff0c\u7528\u6237\u540d\u680f\u662f\u7a7a\u7684\uff0c\u8bf4\u660e\u662f\u5c5e\u4e3bOwner\u7684\u6743\u9650\uff09 user:tm2:r-x \uff08Named User \u6307\u5b9a\u7528\u6237\u7684\u6743\u9650\uff0c\u7528\u6237tm2\u7684\u6743\u9650\uff09 group::rwx \uff08Owing Group \u6587\u4ef6\u5c5e\u7ec4\u7684\u6743\u9650\uff0c\u7ec4\u540d\u680f\u662f\u7a7a\u7684\uff0c\u8bf4\u660e\u662f\u5c5e\u7ec4\u7684\u6743\u9650\uff09 \uff08Named Group \u6307\u5b9a\u7528\u6237\u7ec4\u7684\u6743\u9650\uff0c\u6b64\u65f6\u672a\u6307\u5b9a\uff09 mask::rwx \uff08mask\u6743\u9650\uff09 other::--- \uff08\u5176\u4ed6\u4ebaother\u7684\u6743\u9650\uff09 \u7ed9 ~/project1 \u76ee\u5f55\u6dfb\u52a0\u65b0\u7ec4 project2 \u7684\u6743\u9650 rwx $ su - pm1 $ setfacl -m g:project2:rwx ./project1/ $ ls -dl ./project1 drwxrwx---+ 1 pm1 project1 0 Dec 4 06 :46 ./project1 $ getfacl ./project1 # file: project1 # owner: pm1 # group: project1 user::rwx user:tm2:r-x ( \u7528\u6237tm2\u62e5\u6709\u4e86r-x\u6743\u9650\uff09 group::rwx group:project2:rwx ( \u7528\u6237\u7ec4project2\u62e5\u6709\u4e86rwx\u6743\u9650\uff09 mask::rwx other::--- \u6709\u6548\u6743\u9650\u7684\u8ba1\u7b97\uff1a \u5f53\u524d ~/project1 \u76ee\u5f55\u7684 mask \u662f rwx \uff0c tm2 \u7684\u6743\u9650\u662f r-x \uff0c\u4e8c\u8005\u8fdb\u884cAND\u64cd\u4f5c\uff0c tm2 \u7684\u5b9e\u9645\u6743\u9650\u662f r-x tm2: r - x ( 1 0 1 ) mask: r w x ( 1 1 1 ) --------------------- result: r - x ( 1 0 1 ) \u5bf9\u7167\u4e0b\u9762\u7684\u89c4\u5219\uff0c\u9a8c\u8bc1\u7528\u6237 tm2 \u5bf9 ~/project1 \u76ee\u5f55\u7684\u5b9e\u9645\u6743\u9650\u3002 su - tm2 \u80fd\u8fdb\u5165\u76ee\u5f55 project1 \uff0c\u8bf4\u660e\u5f53\u524d\u7528\u6237\u5177\u6709\u76ee\u5f55 project1 \u7684 r-x \u6743\u9650\u3002 $ whoami tm2 $ cd /home/pm1/project1/ \u80fd\u5217\u51fa\u76ee\u5f55 project1 \u4e0b\u6587\u4ef6\u5217\u8868\uff0c\u53ef\u4ee5\u67e5\u770b\u6587\u4ef6 file \u7684\u5185\u5bb9\uff0c\u8bf4\u660e\u5f53\u524d\u7528\u6237\u5177\u6709\u76ee\u5f55 project1 \u7684 r-x \u6743\u9650\u3002 $ pwd /home/pm1/project1 $ whoami tm2 $ ls -l -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 $ cat file1 hello from pm1 \u5bf9\u76ee\u5f55 project1 \u4e0d\u5177\u6709 w \u6743\u9650\uff0c\u6240\u4ee5\u65e0\u6cd5\u521b\u5efa\u3001\u5220\u9664\u6216\u4fee\u6539\u76ee\u5f55\u4e0b\u7684\u4efb\u4f55\u6587\u4ef6\u6216\u5b50\u76ee\u5f55\u3002 $ pwd /home/pm1/project1 $ whoami tm2 $ touch file2 touch: cannot touch 'file2' : Permission denied $ echo \"hello from $USER \" >> file1 -bash: file1: Permission denied","title":"8.6.3.\u6dfb\u52a0ACL\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#864mask","text":"\u8c03\u6574 ~/project1 \u76ee\u5f55\u7684 mask \u4e3a r-- \uff0c\u5219 tm2 \u7684\u5b9e\u9645\u6743\u9650\u662f r-- $ su - pm1 $ cd ~ $ setfacl -m m::r ./project1/ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- (\u7528\u6237tm2\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u53d8\u4e3ar--) group::rwx #effective:r-- (\u5c5e\u7ec4project1\u7ec4\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u53d8\u4e3ar--) group:project2:rwx #effective:r-- (\u5176\u4ed6\u7ec4project2\u7ec4\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u53d8\u4e3ar--) mask::r-- ( mask\u53d8\u5316\uff0c\u5bfc\u81f4\u4e0a\u8ff0\u4e24\u4e2agroup\u7684\u6709\u6548\u6743\u9650\u90fd\u53d1\u751f\u4e86\u53d8\u5316 ) other::--- \u6709\u6548\u6743\u9650\u7684\u8ba1\u7b97\uff1a \u5f53\u524d ~/project1 \u76ee\u5f55\u7684 mask \u662f r-- \uff0c\u7528\u6237 tm2 \u3001\u7ec4 project2 \u7684\u5b9e\u9645\u6743\u9650\u662f r-- \u3002 tm2: r - w ( 1 0 1 ) mask: r - - ( 1 0 0 ) --------------------- result: r - - ( 1 0 0 ) \u63d0\u793a\uff1a \u7528\u6237\u548c\u7528\u6237\u7ec4\u6240\u8bbe\u5b9a\u7684\u6743\u9650\u5fc5\u987b\u5728mask\u6743\u9650\u8bbe\u5b9a\u7684\u8303\u56f4\u4e4b\u5185\u624d\u80fd\u751f\u6548\uff0cmask\u6743\u9650\u5c31\u662f\u6700\u5927\u6709\u6548\u6743\u9650\u3002","title":"8.6.4.\u4fee\u6539mask\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#865","text":"\u5728POSIX\u6743\u9650\u6a21\u578b\u548cACL\u6743\u9650\u53e0\u52a0\u4f5c\u7528\u4e0b\uff0c\u7528\u6237\u7684\u5b9e\u9645\u6743\u9650\u5206\u6790\u3002 $ getfacl ./project1/ # file: project1/ # owner: pm1 <----Owner # group: project1 <----owning group user::rwx <----owner 's permissions user:tm2:r-x #effective:r-- <----named user' s permissions group::rwx #effective:r-- <----owning group's permissions group:project2:rwx #effective:r-- <----named group's permissions mask::r-- <----masks for named user and named group other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- \u6240\u6709\u8005ower\u548c\u5176\u4ed6\u7528\u6237other\u6761\u76ee\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\u603b\u662f\u6709\u6548\u7684\u3002\u4e0a\u4f8b\u4e2d\u7684user\u6761\u76ee\u548cother\u6761\u76ee\u3002 \u9664\u4e86\u63a9\u7801\u6761\u76ee\uff0c\u6240\u6709\u5176\u4ed6\u6761\u76ee\uff08\u6bd4\u5982\u6307\u5b9a\u7528\u6237named user\uff09\u53ef\u4ee5\u662f\u6709\u6548\u7684\u6216\u88ab\u5c4f\u853d\u7684\u3002 \u6307\u5b9a\u7528\u6237\uff08named user\uff09\uff0c\u6240\u6709\u8005\u7ec4\uff08owning group\uff09\u6216\u6307\u5b9a\u7ec4\uff08named group\uff09\u4ee5\u53ca\u63a9\u7801mask\u6761\u76ee\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\uff0c\u6709\u6548\u6743\u9650\u662f\u4ed6\u4eec\u6743\u9650\u8fdb\u884c\u903b\u8f91AND\u540e\u7684\u7ed3\u679c\uff0c\u800c\u4e0d\u662f\u5355\u72ec\u7684\u63a9\u7801\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\u6216\u8005\u5404\u81ea\u6761\u76ee\u4e2d\u5b9a\u4e49\u7684\u6743\u3002 \u6709\u6548\u6743\u9650\u8ba1\u7b97\u65b9\u6cd5\u5982\u4e0b\uff0c\u6ce8\u610f\uff0c ls \u547d\u4ee4\u4e2d\u663e\u793a\u51fa\u6765\u7684\u6743\u9650\uff0c\u4e0e\u5b9e\u9645\u7684ACL\u6743\u9650\u662f\u6709\u5dee\u522b\u7684\u3002 tm2: r - w ( 1 0 1 ) group: r w x ( 1 1 1 ) named group: r w x ( 1 1 1 ) mask: r - - ( 1 0 0 ) --------------------------- result: r - - ( 1 0 0 ) \u5c0f\u8d34\u58eb\uff1a \u4e0e\u6587\u4ef6\u6a21\u5f0f\u6743\u9650\u4f4d\u7b49\u6548\u7684ACL\u79f0\u4e3a\u6700\u5c0fACL\uff0c\u5373POSIX\u4f20\u7edf\u6743\u9650\u3002 \u542b\u63a9\u7801mask\u7b49\u5176\u4ed6\u6743\u9650\u6761\u76ee\u7684ACL\u79f0\u4e3a\u6269\u5c55ACL\u3002 \u5728\u6700\u5c0f\u548c\u6269\u5c55ACL\u60c5\u5f62\u4e0b\uff0c\u6240\u6709\u8005\u7c7b\u6743\u9650\uff08owner\uff09\u90fd\u662f\u6620\u5c04\u5230ACL\u7684\u6240\u6709\u8005\u6761\u76ee\u3002 \u5176\u4ed6\u7c7b\u6743\u9650\u6620\u5c04\u5230\u5176\u5404\u81ea\u7684ACL\u6761\u76ee\u3002 \u5728\u6269\u5c55ACL\u60c5\u5f62\u4e0b\uff0c\u7ec4\u7c7b\u6743\u9650\u7684\u6620\u5c04\u662f\u4e0d\u540c\u7684\u3002 \u5bf9\u4e8e\u6ca1\u6709\u63a9\u7801\u7684\u6700\u5c0fACL\uff0c\u7ec4\u7c7b\u6743\u9650\u5c06\u6620\u5c04\u5230ACL\u6240\u6709\u8005\u7ec4\u6761\u76ee\u3002 \u5bf9\u4e8e\u5e26\u6709\u63a9\u7801\u7684\u6269\u5c55ACL\uff0c\u7ec4\u7c7b\u6743\u9650\u5c06\u6620\u5c04\u5230\u63a9\u7801\u6761\u76ee\u3002 \u901a\u8fc7\u6743\u9650\u4f4d\u8fdb\u884c\u5206\u914d\u7684\u6743\u9650\u4ee3\u8868\u4e86\u901a\u8fc7ACL\u8fdb\u884c\u5206\u914d\u7684\u6743\u9650\u7684\u4e0a\u9650\u3002 \u6ca1\u6709\u5728\u8fd9\u91cc\u4f53\u73b0\u7684\u4efb\u4f55\u6743\u9650\uff0c\u8981\u4e48\u4e0d\u5728ACL\u4e2d\uff0c\u8981\u4e48\u65e0\u6548\u3002 \u5bf9\u6743\u9650\u4f4d\u6240\u505a\u7684\u66f4\u6539\u5c06\u7531ACL\u53cd\u6620\uff0c\u53cd\u4e4b\u4ea6\u7136\u3002","title":"8.6.5.\u6709\u6548\u6743\u9650\u5206\u6790"},{"location":"linux/SRE/03-identity-security/#866acl","text":"$ su - pm1 $ touch ./project1/file2 $ mkdir ./project1/cloud $ ll ./project1/ drwxr-xr-x. 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 $ ll -d project1/ drwxr-----+ 1 pm1 project1 30 Dec 4 08 :52 project1/ \u6587\u4ef6 file1 \u548c\u76ee\u5f55 cloud \u6ca1\u6709\u7ee7\u627f project1 \u76ee\u5f55\u7684ACL\u6743\u9650\u3002 \u63d0\u793a\uff1a \u9ed8\u8ba4 ACL\u9650\u53ea\u5bf9\u76ee\u5f55\u751f\u6548\u3002 \u9ed8\u8ba4ACL\u6743\u9650\u7684\u4f5c\u7528\u662f\uff1a\u5982\u679c\u7ed9\u7236\u76ee\u5f55\u8bbe\u5b9a\u4e86\u9ed8\u8ba4 ACL \u6743\u9650\uff0c\u90a3\u4e48\u7236\u76ee\u5f55\u4e2d\u6240\u6709\u65b0\u5efa\u7684\u5b50\u6587\u4ef6\u90fd\u4f1a\u7ee7\u627f\u7236\u76ee\u5f55\u7684ACL\u6743\u9650\u3002 \u4e0b\u9762\u589e\u52a0 ~/project1 \u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u6743\u9650\u3002 $ su - pm1 $ cd ~ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- group::rwx #effective:r-- group:project2:rwx #effective:r-- mask::r-- other::--- $ setfacl -m d:u:tm2:rx ./project1/ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- group::rwx #effective:r-- group:project2:rwx #effective:r-- mask::r-- other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- \u521b\u5efa\u65b0\u5b50\u76ee\u5f55 leonardo \uff0c\u5c31\u7ee7\u627f\u4e86 ~/project1 \u76ee\u5f55\u7684default ACL\u6743\u9650\u8bbe\u5b9a\u3002 \u6ce8\u610f\uff0c\u9ed8\u8ba4ACL\u6743\u9650\u662f\u9488\u5bf9\u65b0\u5efa\u7acb\u7684\u6587\u4ef6\u751f\u6548\u7684\uff0c\u76ee\u5f55cloud\u548c\u6587\u4ef6file1\u5e76\u6ca1\u6709\u56e0\u4e3a\u589e\u52a0\u4e86\u7236\u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u8bbe\u5b9a\u800c\u7ee7\u627f\u9ed8\u8ba4ACL\u6743\u9650\u8bbe\u5b9a. $ su - pm1 $ cd ~ $ mkdir ./project1/leonardo $ ll ./project1/ drwxr-xr-x. 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---+ 1 pm1 project1 0 Dec 4 09 :07 leonardo","title":"8.6.6.\u9ed8\u8ba4ACL\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#867acl","text":"\u9012\u5f52 ACL \u6743\u9650\uff0c\u662f\u6307\u7236\u76ee\u5f55\u5728\u8bbe\u5b9aACL\u6743\u9650\u65f6\uff0c\u6240\u6709\u7684\u5b50\u76ee\u5f55\u4e5f\u4f1a\u62e5\u6709\u76f8\u540c\u7684ACL\u6743\u9650\u3002 $ su - pm1 $ cd ~ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- group::rwx #effective:r-- group:project2:rwx #effective:r-- mask::r-- other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- $ setfacl -m d:u:tm2:rx -R ./project1/ $ ll ./project1 drwxr-xr-x+ 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---+ 1 pm1 project1 0 Dec 4 09 :07 leonardo","title":"8.6.7.\u9012\u5f52ACL\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#868acl","text":"\u5220\u9664\u7528\u6237 tm2 \u7684ACL\u6743\u9650\u3002 $ su - pm1 $ cd ~ $ setfacl -x u:tm2 ./project1/ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx group::rwx group:project2:rwx mask::rwx other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- \u5220\u9664\u6240\u6709\u7684ACL\u6743\u9650\u3002 $ setfacl -b ./project1 $ getfacl ./project1 # file: project1/ # owner: pm1 # group: project1 user::rwx group::rwx other::--- $ ll ./project1 drwxr-xr-x+ 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---+ 1 pm1 project1 0 Dec 4 09 :07 leonardo \u9012\u5f52\u5220\u9664\u5168\u90e8ACL\u6743\u9650\u3002 $ setfacl -b -R ./project1 $ ll ./project1/ total 4 drwxr-xr-x. 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---. 1 pm1 project1 0 Dec 4 09 :07 leonardo","title":"8.6.8.\u5220\u9664ACL\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#87acl","text":"","title":"8.7.ACL\u76ee\u5f55\u5b9e\u4f8b\u89e3\u6790"},{"location":"linux/SRE/03-identity-security/#871acl","text":"\u5207\u6362\u5230pm1\u7528\u6237\uff0c\u5728\u5176\u4e3b\u76ee\u5f55\u4e2d\uff0c\u57fa\u4e8e\u4e0d\u540c\u7684\u63a9\u7801\u521b\u5efa2\u4e2a\u5b50\u76ee\u5f55\u3002 $ su - pm1 $ umask 0022 $ mkdir mydir1 $ umask 0027 $ mkdir mydir2 $ ll -d mydir* drwxr-xr-x. 1 pm1 project1 0 Dec 4 12 :30 mydir1 drwxr-x---. 1 pm1 project1 0 Dec 4 12 :31 mydir2 \u8fd92\u4e2a\u76ee\u5f55\u5f53\u524d\u7684ACL\u72b6\u6001\u5982\u4e0b\uff1a $ getfacl mydir1 # file: mydir1 # owner: pm1 # group: project1 user::rwx group::r-x other::r-x $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx group::r-x other::--- \u4fee\u6539\u76ee\u5f55 mydir2 \u7684ACL\u3002 $ setfacl -m u:tm2:rwx,g:project2:rwx mydir2 $ getfacl mydir2 getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx group::r-x group:project2:rwx mask::rwx other::--- $ ll -d mydir2 drwxrwx---+ 1 pm1 project1 0 Dec 4 12 :31 mydir2 \u73b0\u5728\uff0c\u7528\u6237 tm2 \u548c\u7ec4 project2 \u5bf9\u76ee\u5f55 mydir2 \u90fd\u5177\u6709rwx\u6743\u9650\uff0c\u4f20\u7edfPOSIX\u6743\u9650\u548cACL\u6743\u9650\u4e00\u81f4\u3002 \u73b0\u5728\u5bf9mydir2\u76ee\u5f55\u7ec4\u6743\u9650\u64a4\u9500w\u6743\u9650\u3002 \u7528\u6237 tm2 \u548c\u7ec4 project2 \u5bf9\u76ee\u5f55 mydir2 \u7684\u6709\u6548\u6743\u9650\u53d8\u6210\u4e86 r-x \u3002 mask\u4e5f\u53d7\u7ec4\u6743\u9650\u53d8\u5316\u5f71\u54cd\uff0c\u53d8\u6210\u4e86 r-x \u3002 $ chmod g-w mydir2 $ ll -d mydir2 drwxr-x---+ 1 pm1 project1 0 Dec 4 12 :31 mydir2 $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx #effective:r-x group::r-x group:project2:rwx #effective:r-x mask::r-x other::--- \u901a\u8fc7 chmod \u548c setfacl \u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u6cd5\u5bf9\u76ee\u5f55 mydir2 \u7684\u7ec4\u6743\u9650\u8fdb\u884c\u4fee\u6539\uff0c\u5728ls\u547d\u4ee4\u4e2d\u4f53\u73b0\u662f\u4e00\u6837\u7684\uff0c\u5bf9\u7ec4\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u7684\u5f71\u54cd\u4e5f\u662f\u4e00\u6837\u7684\u3002 chmod \u4fee\u6539\u7684\u662f mask \uff0c mask \u53ea\u5f71\u54cd\u9664\u6240\u6709\u8005\u548cother\u7684\u4e4b\u5916\u7684\u4eba\u548c\u7ec4\u7684\u6700\u5927\u6743\u9650\uff0c mask \u9700\u8981\u4e0e\u7528\u6237\u7684\u6743\u9650\u8fdb\u884c\u903b\u8f91\u4e0e\u8fd0\u7b97\u540e\uff0c\u624d\u80fd\u53d8\u6210\u6709\u6548\u6743\u9650\uff0c\u7528\u6237\u6216\u7ec4\u7684\u8bbe\u7f6e\u5fc5\u987b\u5728mask\u6743\u9650\u8bbe\u5b9a\u8303\u56f4\u5185\u624d\u4f1a\u751f\u6548\u3002 setfacl \u53ef\u4ee5\u4e0d\u4fee\u6539mask\u7684\u60c5\u51b5\u4e0b\u53ea\u4fee\u6539 owning group \u7684\u6743\u9650\uff0c\u4e0b\u9762\u7684\u4f8b\u5b50\u8bf4\u660e\u4e86\u8fd9\u4e00\u60c5\u51b5\u3002POSIX\u7ec4\u6743\u9650\u4ecd\u7136\u662f rwx \uff0c\u4f46ACL\u4e2d\u6240\u6709\u8005\u7ec4\u7684\u6743\u9650\u53d8\u6210\u4e86 r-- \u3002 $ setfacl -m g::r mydir2 $ ll -d mydir2 drwxrwx---+ 1 pm1 project1 0 Dec 4 12 :31 mydir2 $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx group::r-- group:project2:rwx mask::rwx other::---","title":"8.7.1.\u76ee\u5f55ACL"},{"location":"linux/SRE/03-identity-security/#872acl","text":"\u76ee\u5f55\u53ef\u4ee5\u5177\u6709\u9ed8\u8ba4ACL\uff0c\u8fd9\u662f\u4e00\u79cd\u7279\u6b8a\u7684ACL\uff0c\u7528\u4e8e\u5b9a\u4e49\u76ee\u5f55\u4e0b\u7684\u5bf9\u8c61\u5728\u521b\u5efa\u65f6\u7ee7\u627f\u7684\u8bbf\u95ee\u6743\u9650\u3002\u9ed8\u8ba4ACL\u4f1a\u5f71\u54cd\u5b50\u76ee\u5f55\u548c\u6587\u4ef6\u3002 \u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u7684\u6743\u9650\u6709\u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u4f20\u9012\u7ed9\u5176\u4e2d\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\uff1a \u5b50\u76ee\u5f55\u7ee7\u627f\u7236\u76ee\u5f55\u7684\u9ed8\u8ba4ACL\uff0c\u65e2\u4f5c\u4e3a\u81ea\u5df1\u7684\u9ed8\u8ba4ACL\uff0c\u53c8\u4f5c\u4e3a\u81ea\u5df1\u7684\u8bbf\u95eeACL\u3002 \u6587\u4ef6\u7ee7\u627f\u76ee\u5f55\u9ed8\u8ba4ACL\u4f5c\u4e3a\u5176\u81ea\u5df1\u7684\u8bbf\u95eeACL\u3002 \u521b\u5efa\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u7684\u6240\u6709\u7cfb\u7edf\u51fd\u6570\u90fd\u4f7f\u7528mode\u53c2\u6570\uff0c\u8be5\u53c2\u6570\u5b9a\u4e49\u4e86\u65b0\u521b\u5efa\u7684\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u5982\u679c\u7236\u76ee\u5f55\u6ca1\u6709\u9ed8\u8ba4ACL\uff0c\u5219\u6839\u636eumask\u7684\u8bbe\u7f6e\u8bbe\u7f6e\u6743\u9650\u4f4d\u3002 \u5982\u679c\u7236\u76ee\u5f55\u5b58\u5728\u9ed8\u8ba4ACL\uff0c\u5219\u5206\u914d\u7ed9\u65b0\u5bf9\u8c61\u7684\u6743\u9650\u4f4d\u5219\u662fmode\u53c2\u6570\u6743\u9650\u4e0e\u9ed8\u8ba4ACL\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\u7684\u903b\u8f91\u4e0e\u7684\u7ed3\u679c\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5ffd\u7565umask\u547d\u4ee4\u3002 \u9ed8\u8ba4ACL\u4e0d\u4f1a\u7acb\u5373\u5f71\u54cd\u8bbf\u95ee\u6743\u9650\u3002\u5b83\u4eec\u4ec5\u5728\u521b\u5efa\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u65f6\u624d\u8d77\u4f5c\u7528\u3002\u8fd9\u4e9b\u65b0\u5bf9\u8c61\u4ec5\u4ece\u5176\u7236\u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u7ee7\u627f\u6743\u9650\u3002 \u547d\u4ee4 mkdir \u5728\u521b\u5efa\u76ee\u5f55\u65f6\u4f1a\u7ee7\u627f\u9ed8\u8ba4ACL\u3002 $ su - pm1 $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx group::r-- group:project2:rwx mask::rwx other::--- $ mkdir ./mydir2/sub1 $ ll ./mydir2 drwxr-x---. 1 pm1 project1 0 Dec 4 13 :23 sub1 $ setfacl -d -m g:project2:-w- mydir2 $ mkdir ./mydir2/sub2 $ ll ./mydir2 drwxr-x---. 1 pm1 project1 0 Dec 4 13 :23 sub1 drwxrw----+ 1 pm1 project1 0 Dec 4 13 :27 sub2 $ getfacl ./mydir2/sub2 # file: mydir2/sub2 # owner: pm1 # group: project1 user::rwx group::r-- group:project2:-w- mask::rw- other::--- default:user::rwx default:group::r-- default:group:project2:-w- default:mask::rw- default:other::--- \u5728\u5bf9 mydir2 \u76ee\u5f55\u6dfb\u52a0\u9ed8\u8ba4ACL\u524d\uff0c\u521b\u5efa\u5b50\u76ee\u5f55 sub1 \uff0c\u6dfb\u52a0\u540e\u521b\u5efa\u5b50\u76ee\u5f55 sub2 \u3002\u53ef\u4ee5\u89c2\u5bdf\u5230 sub2 \u5230\u7ee7\u627f\u4e86 mydir2 \u7684\u9ed8\u8ba4ACL\u3002 $ su - tm2 $ cd /home/pm1/mydir2/sub2 -bash: cd: /home/pm1/mydir2/sub2: Permission denied \u4e0a\u4f8b\u4e2d\uff0c\u9ed8\u8ba4ACL\u4e2d\u6307\u5b9a\u7ec4 project2 \u53ea\u5177\u6709w\u6743\u9650\uff0c\u6240\u4ee5\u65e0\u6cd5\u6267\u884c cd \u547d\u4ee4\u8fdb\u5165\u8be5\u76ee\u5f55\u3002 \u8fd9\u8bf4\u660e\u6a21\u5f0f\u503cmode\u4e2d\u7ed9\u4e88\u7684\u6743\u9650 r \u88ab\u5c4f\u853d\u4e86\uff0c\u53ea\u4fdd\u7559\u4e86ACL\u4e2d\u6700\u5c0f\u7684\u6743\u9650 w \u3002","title":"8.7.2.\u76ee\u5f55\u7684\u9ed8\u8ba4ACL"},{"location":"linux/SRE/03-identity-security/#88acl","text":"ACL\u68c0\u67e5\u987a\u5e8f\uff1a Owner Named user Owning group Named group Other If \u8fdb\u7a0b\u7684\u7528\u6237\u6807\u8bc6\u662fOwner\uff0c\u5219owner\u7684ACL\u6761\u76ee\u51b3\u5b9a\u8bbf\u95ee\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7528\u6237\u6807\u8bc6\u662fnamed user\uff0c\u5219name user\u7684ACL\u6761\u76ee\u7684\u6743\u9650\u51b3\u5b9a\u7533\u8bf7\u7684\u8bbf\u95ee\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7ec4\u5c5e\u4e8eowning group\uff0c\u4e14owning group\u7684ACL\u6761\u76ee\u5305\u542b\u6240\u8bf7\u6c42\u7684\u8bbf\u95ee\u6743\u9650\uff0c\u5219\u6388\u4e88\u6240\u8bf7\u6c42\u7684\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7ec4\u5c5e\u4e8enamed group\uff0c\u4e14named group\u7684ACL\u6761\u76ee\u5305\u542b\u6240\u8bf7\u6c42\u7684\u8bbf\u95ee\u6743\u9650\uff0c\u5219\u6388\u4e88\u6240\u8bf7\u6c42\u7684\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7ec4\u5c5e\u4e8eowning group\u6216\u8005named group\uff0c\u4f46owning group\u6216\u8005named group\u7684ACL\u6761\u76ee\u4e0d\u5305\u542b\u6240\u8bf7\u6c42\u7684\u8bbf\u95ee\u6743\u9650\uff0c\u5219\u62d2\u7edd\u6240\u8bf7\u6c42\u7684\u6743\u9650 else ACL\u4e2d\u7684other\u6761\u76ee\u5904\u7406\u7533\u8bf7\u7684\u6743\u9650 If \u5982\u679c\u8fdb\u7a0b\u5339\u914d\u5230owner\u6216\u8005other\u6761\u76ee\u4e2d\u5305\u542b\u6240\u7533\u8bf7\u7684\u6743\u9650\uff0c\u5219\u6388\u4e88\u6743\u9650 else if \u5982\u679c\u8fdb\u7a0b\u5339\u914d\u5230named user\uff0cowning group\uff0c\u6216\u8005named group\u6761\u76ee\u4e2d\u5305\u542b\u6240\u7533\u8bf7\u7684\u6743\u9650\uff0c\u4e14maks\u6761\u76ee\u4e5f\u5305\u542b\u6240\u7533\u8bf7\u7684\u6743\u9650\uff0c\u5219\u6388\u4e88\u6743\u9650 else \u62d2\u7edd\u6743\u9650\u7533\u8bf7 \u5b9e\u9645\u5e94\u7528\u4e3e\u4f8b\uff1a udev\u4f7f\u7528ACL\u7ed9\u4e88\u767b\u5f55\u5230\u56fe\u5f62\u754c\u9762\u7684\u7528\u6237\u8bbf\u95ee\u8bbe\u5907\u7684\u6743\u9650\uff0c\u4f8b\u5982DVD\u9a71\u52a8\u5668 \u67d0\u4e9b\u5e94\u7528\u7a0b\u5e8f\u4e0d\u652f\u6301ACL Star Archiver\u662f\u4e00\u4e2a\u5b8c\u5168\u4fdd\u7559ACL\u7684\u5907\u4efd\u5e94\u7528\u7a0b\u5e8f\uff0c\u5176\u4ed6\u4eba\u53ef\u80fd\u4f1a\u4e5f\u53ef\u80fd\u4e0d\u4f1a\u4fdd\u7559\u5b83 \u8bb8\u591a\u7f16\u8f91\u5668\u548c\u6587\u4ef6\u7ba1\u7406\u5668\u4e0d\u5141\u8bb8\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u67e5\u770b\u6216\u8bbe\u7f6eACL","title":"8.8.ACL\u68c0\u67e5\u903b\u8f91"},{"location":"linux/SRE/04-TextTools/","text":"\u7b2c\u56db\u7ae0 \u6587\u672c\u7f16\u8f91 \u00b6 1.\u6587\u672c\u7f16\u8f91\u5668 \u00b6 1.1.vim\u5de5\u5177 \u00b6 vim\u547d\u4ee4\u683c\u5f0f\uff1a +# file : \u6253\u5f00\u6587\u4ef6\u540e\uff0c\u8ba9\u5149\u6807\u5904\u4e8e\u7b2c#\u884c\u9996\uff0c+\u9ed8\u8ba4\u884c\u5c3e +/PATTERN file : \u6253\u5f00\u6587\u4ef6\u6709\uff0c\u8ba9\u5149\u6807\u5904\u4e8e\u7b2c\u4e00\u4e2a\u88abPATTERN\u5339\u914d\u5230\u7684\u884c\u9996 -b file : \u4e8c\u8fdb\u5236\u65b9\u5f0f\u6253\u5f00\u6587\u4ef6 -d file1 file2 ... : \u6bd4\u8f83\u591a\u4e2a\u6587\u4ef6\uff0c\u76f8\u5f53\u4e8e vimdiff -m file : \u53ea\u8bfb\u65b9\u5f0f\u6253\u5f00\u6587\u4ef6 -e file : \u8fdb\u5165ex\u6a21\u5f0f\uff0c\u76f8\u5f53\u4e8e ex file -y file : vim\u4e09\u79cd\u5e38\u89c1\u6a21\u5f0f\uff1a \u666e\u901a\u6a21\u5f0fNormal\u6216\u547d\u4ee4\u6a21\u5f0f \u63d2\u5165Insert\u6216\u7f16\u8f91\u6a21\u5f0f \u6269\u5c55\u547d\u4ee4\u6a21\u5f0fExtended Command \u4e09\u79cd\u6a21\u5f0f\u5207\u6362 \u547d\u4ee4\u6a21\u5f0f\u2192\u63d2\u5165\u6a21\u5f0f i\uff1ainsert\uff0c\u5728\u5149\u6807\u5904\u8f93\u5165 I\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u9996\u8f93\u5165 a\uff1aappend\uff0c\u5728\u5149\u6807\u5904\u540e\u9762\u8f93\u5165 A\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u5c3e\u8f93\u5165 o\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u7684\u4e0b\u65b9\u6253\u5f00\u4e00\u4e2a\u65b0\u884c O\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u7684\u4e0a\u65b9\u6253\u5f00\u4e00\u4e2a\u65b0\u884c \u63d2\u5165\u6a21\u5f0f\u2192 ESC \u2192 \u547d\u4ee4\u6a21\u5f0f \u547d\u4ee4\u6a21\u5f0f\u2192 : \u2192 \u6269\u5c55\u547d\u4ee4\u6a21\u5f0f \u6269\u5c55\u547d\u4ee4\u6a21\u5f0f\u2192 ESC, enter \u2192 \u547d\u4ee4\u6a21\u5f0f \u6269\u5c55\u547d\u4ee4\u6a21\u5f0f\u5e38\u7528\u547d\u4ee4\uff1a :wq : \u4fdd\u5b58\u6587\u4ef6\u5e76\u9000\u51fa :w : \u4fdd\u5b58\u6587\u4ef6 :w filename : \u5199\u5165\u6307\u5b9a\u6587\u4ef6\uff0c\u76f8\u5f53\u4e8e\u53e6\u5b58\u4e3a :q! : \u653e\u5f03\u4efb\u4f55\u4fee\u6539\u5e76\u9000\u51fa ZQ : \u65e0\u6761\u4ef6\u9000\u51fa :join : \u5408\u5e76\u591a\u884c J : \u5408\u5e76\u4e24\u884c \u8bbe\u7f6e\uff1a\uff08\u53ef\u4ee5\u5728 /etc/vimrc \u6587\u4ef6\u4e2d\u914d\u7f6e\uff09 :set textwidth : \u8bbe\u7f6e\u6587\u672c\u5bbd\u5ea6\uff08\u4ece\u5de6\u5411\u53f3\u8ba1\u6570\uff09 :set wrapmargin=# : \u8bbe\u7f6e\u884c\u8fb9\u8ddd\uff08\u4ece\u53f3\u5411\u5de6\u8ba1\u6570\uff09 :set endofline : \u8bbe\u7f6e\u6587\u4ef6\u7ed3\u675f\u7b26 :set noendofline : \u53d6\u6d88\u6587\u4ef6\u7ed3\u675f\u7b26 :set wrap : \u81ea\u52a8\u6362\u884c :set nowrap : \u53d6\u6d88\u81ea\u52a8\u6362\u884c :set number : \u663e\u793a\u884c\u53f7 :set nonumber : \u53d6\u6d88\u663e\u793a\u884c\u53f7 :set list : \u8fdb\u5165List Mode\uff0c\u663e\u793aTab ^I\uff0c\u6362\u884c\u7b26\uff0c\u548c$\u663e\u793a :set nolist : \u9000\u51faList Mode :set ignorecase : \u5ffd\u7565\u5b57\u7b26\u7684\u5927\u5c0f\u5199 :set noic : \u4e0d\u5ffd\u7565\u5b57\u7b26\u5927\u5c0f\u5199 :set autoindent : \u542f\u7528\u81ea\u52a8\u7f29\u8fdb :set noai : \u5173\u95ed\u81ea\u52a8\u7f29\u8fdb :set hlsearch : \u542f\u7528\u9ad8\u4eae\u641c\u7d22 :set nohlsearch : \u5173\u95ed\u9ad8\u4eae\u641c\u7d22 :set fileformat=dos : \u542f\u7528windows\u683c\u5f0f :set fileformat=unix : \u542f\u7528unix\u683c\u5f0f :set expandtab : \u542f\u7528\u7a7a\u683c\u4ee3\u66ffTAB\uff0c\u9ed8\u8ba48\u4e2a\u7a7a\u683c\u4ee3\u66ff\u4e00\u4e2aTAB :set noexpandtab : \u5173\u95ed\u7a7a\u683c\u4ee3\u66ffTAB :set tabstop=# : \u6307\u5b9a#\u4e2a\u7a7a\u683c\u4ee3\u66ff\u4e00\u4e2aTAB :set shiftwidth=# : \u8bbe\u7f6e#\u4e2a\u7f29\u8fdb\u5bbd\u5ea6 :set cursorline : \u8bbe\u7f6e\u5149\u6807\u6240\u5728\u884c\u7684\u8868\u793a\u7ebf :set cursorline : \u5173\u95ed\u5149\u6807\u6240\u5728\u884c\u7684\u8868\u793a\u7ebf :set key=PASSWORD : \u542f\u7528\u5bc6\u7801\u4fdd\u62a4 :set key= : \u5173\u95ed\u5bc6\u7801\u4fdd\u62a4 :help option-list : \u83b7\u53d6\u5e2e\u52a9 \u67e5\u627e /pattern : \u4ece\u5149\u6807\u5f00\u59cb\u5904\u5411\u6587\u4ef6\u5c3e\u641c\u7d22pattern ?pattern : \u4ece\u5149\u6807\u5f00\u59cb\u5904\u5411\u6587\u4ef6\u9996\u641c\u7d22pattern n : \u5728\u540c\u4e00\u65b9\u5411\u91cd\u590d\u4e0a\u4e00\u6b21\u641c\u7d22\u547d\u4ee4 N : \u5728\u53cd\u65b9\u5411\u4e0a\u91cd\u590d\u4e0a\u4e00\u6b21\u641c\u7d22\u547d\u4ee4 # : \u5411\u4e0a\u5b8c\u6574\u5339\u914d\u5149\u6807\u4e0b\u7684\u5355\u8bcd, \u76f8\u5f53\u4e8e\uff1fword * : \u5411\u4e0b\u5b8c\u6574\u5339\u914d\u5149\u6807\u4e0b\u7684\u5355\u8bcd, \u76f8\u5f53\u4e8e/word % : \u67e5\u627e\u5bf9\u5e94\u7684( [ {\u5339\u914d nfx : \u5728\u5f53\u524d\u884c\u67e5\u627e\u5149\u6807\u540e\u7b2cn\u4e2ax\uff08\u4e00\u822c\u76f4\u63a5fx\uff09 \u66ff\u6362 :%s/\\n//g : \u5220\u9664\u6362\u884c\u7b26 :s/p1/p2/g : \u5c06\u5f53\u524d\u884c\u4e2d\u6240\u6709p1\u5747\u7528p2\u66ff\u4ee3, \u65e0g\uff0c\u5219\u53ea\u66ff\u6362\u7b2c\u4e00\u4e2a :s/p1/p2/c : \u67e5\u627e\u66ff\u6362\u8981\u6c42\u786e\u8ba4 :n1,n2s/p1/p2/g : \u5c06\u7b2cn1\u81f3n2\u884c\u4e2d\u6240\u6709p1\u5747\u7528p2\u66ff\u4ee3 :%s/p1/p2/g : \u5168\u5c40\uff0c\u4f7f\u7528p2\u66ff\u6362p1 :%s/p1/p2/gc : \u66ff\u6362\u524d\u8be2\u95ee :n,$s/vivian/sky/ : \u66ff\u6362\u7b2cn\u884c\u5f00\u59cb\u5230\u6700\u540e\u4e00\u884c\u4e2d\u6bcf\u4e00\u884c\u7684\u7b2c\u4e00\u4e2avivian\u4e3asky\uff0cn\u4e3a\u6570\u5b57 :.,$s/vivian/sky/g : \u66ff\u6362\u5f53\u524d\u884c\u5f00\u59cb\u5230\u6700\u540e\u4e00\u884c\u4e2d\u6bcf\u4e00\u884c\u6240\u6709vivian\u4e3asky :s/vivian\\//sky\\// : \u66ff\u6362\u5f53\u524d\u884c\u7b2c\u4e00\u4e2avivian/\u4e3asky/\uff0c\u53ef\u4ee5\u4f7f\u7528\\\u4f5c\u4e3a\u8f6c\u4e49\u7b26 :1,$s/^/some string/ : \u5728\u6587\u4ef6\u7684\u7b2c\u4e00\u884c\u81f3\u6700\u540e\u4e00\u884c\u7684\u884c\u9996\u524d\u63d2\u5165some string :%s/$/some string/g : \u5728\u6574\u4e2a\u6587\u4ef6\u6bcf\u4e00\u884c\u7684\u884c\u5c3e\u6dfb\u52a0some string :%s/\\s\\+$// : \u53bb\u6389\u6240\u6709\u7684\u884c\u5c3e\u7a7a\u683c\uff0c\u201c\\s\u201d\u8868\u793a\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u548c\u5236\u8868\u7b26\uff09\uff0c\u201c+\u201d\u5bf9\u524d\u9762\u7684\u5b57\u7b26\u5339\u914d\u4e00\u6b21\u6216\u591a\u6b21\uff08\u8d8a\u591a\u8d8a\u597d\uff09\uff0c\u201c \\(\u201d\u5339\u914d\u884c\u5c3e\uff08\u4f7f\u7528\u201c\\$\u201d\u8868\u793a\u5355\u7eaf\u7684\u201c\\) \u201d\u5b57\u7b26\uff09 :%s/\\s\u2217\\n\\+/\\r/ : \u53bb\u6389\u6240\u6709\u7684\u7a7a\u767d\u884c\uff0c\u201c \\(\u201d\u548c\u201c\\) \u201d\u5bf9\u8868\u8fbe\u5f0f\u8fdb\u884c\u5206\u7ec4\uff0c\u4f7f\u5176\u88ab\u89c6\u4f5c\u4e00\u4e2a\u4e0d\u53ef\u5206\u5272\u7684\u6574\u4f53 :%s!\\s*//.*!! : \u53bb\u6389\u6240\u6709\u7684\u201c//\u201d\u6ce8\u91ca :%s!\\s*/\\*\\_.\\{-}\\*/\\s*!!g : \u53bb\u6389\u6240\u6709\u7684\u201c/**/\u201d\u6ce8\u91ca :%s= *$== : \u5c06\u6240\u6709\u884c\u5c3e\u591a\u4f59\u7684\u7a7a\u683c\u5220\u9664 :g/^\\s*$/d : \u5c06\u6240\u6709\u4e0d\u5305\u542b\u5b57\u7b26(\u7a7a\u683c\u4e5f\u4e0d\u5305\u542b)\u7684\u7a7a\u884c\u5220\u9664 r : \u66ff\u6362\u5f53\u524d\u5b57\u7b26 R : \u66ff\u6362\u5f53\u524d\u5b57\u7b26\u53ca\u5176\u540e\u7684\u5b57\u7b26\uff0c\u76f4\u81f3\u6309ESC\u952e \u7f16\u8f91 h : \u5149\u6807\u5de6\u79fb\u4e00\u4e2a\u5b57\u7b26[\u56de\u9000\u952eBackspace] l : \u5149\u6807\u53f3\u79fb\u4e00\u4e2a\u5b57\u7b26[\u7a7a\u683c\u952eSpace] K : \u5149\u6807\u4e0a\u79fb\u4e00\u884c j : \u5149\u6807\u4e0b\u79fb\u4e00\u884c w : \u5149\u6807\u8df3\u5230\u4e0b\u4e2aword\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd(\u5305\u62ec\u6807\u70b9\u7b26\u53f7) [\u5e38\u7528] W : \u79fb\u5230\u4e0b\u4e00\u4e2a\u5b57\u7684\u5f00\u5934\uff0c\u5ffd\u7565\u6807\u70b9\u7b26\u53f7 B : \u5149\u6807\u56de\u5230\u4e0a\u4e2aword\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd B : \u79fb\u5230\u524d\u4e00\u4e2a\u5b57\u7684\u5f00\u5934\uff0c\u5ffd\u7565\u6807\u70b9\u7b26\u53f7 BACK E : \u5149\u6807\u8df3\u5230\u4e0b\u4e2aword\u7684\u6700\u540e\u4e00\u4e2a\u5b57\u6bcd E : \u79fb\u5230\u4e0b\u4e00\u4e2a\u5b57\u7684\u7ed3\u5c3e\uff0c\u5ffd\u7565\u6807\u70b9\u7b26\u53f7 END 0 : \u79fb\u5230\u5f53\u524d\u4e00\u884c\u7684\u5f00\u59cb[Home] $ : \u79fb\u5230\u5f53\u524d\u4e00\u884c\u7684\u6700\u540e[End] ^ : \u547d\u4ee4\u5c06\u5149\u6807\u79fb\u52a8\u5230\u5f53\u524d\u884c\u7684\u7b2c\u4e00\u4e2a\u975e\u7a7a\u767d\u5b57\u7b26\u4e0a g_ : \u5230\u672c\u884c\u6700\u540e\u4e00\u4e2a\u4e0d\u662fblank\u5b57\u7b26\u7684\u4f4d\u7f6e Enter : \u5149\u6807\u4e0b\u79fb\u4e00\u884c n+ : \u5149\u6807\u4e0b\u79fbn\u884c\u3010\u6309\u4e0a\u6863\u952e \u6570\u5b57shift +\u3011 n- : \u5149\u6807\u4e0a\u79fbn\u884c G : \u79fb\u5230\u6587\u4ef6\u7684\u6700\u540e\u4e00\u884c nG \u6216\u8005 :n : \u79fb\u5230\u6587\u4ef6\u7684\u7b2cn\u884c\ue5e5\ue5e5\ue5e5 gg : \u79fb\u52a8\u5230\u6587\u6863\u7684\u5f00\u59cb [[ : \u6587\u4ef6\u5f00\u59cb\u4f4d\u7f6e\u2014\u2014\u5f00\u59cb\u884c ]] : \u6587\u4ef6\u7ed3\u675f\u4f4d\u7f6e\u2014\u2014\u672b\u5c3e\u884c H : \u5149\u6807\u79fb\u81f3\u5c4f\u5e55\u9876\u884cHEAD\u3002\u5149\u6807\u5b9a\u4f4d\u5728\u663e\u793a\u5c4f\u7684\u7b2c\u4e00\u884c M : \u79fb\u5230\u5c4f\u5e55\u7684\u4e2d\u95f4\u884c\u5f00\u5934 Middle\u3002\u5149\u6807\u5b9a\u4f4d\u5728\u663e\u793a\u5c4f\u7684\u4e2d\u95f4 L : \u79fb\u5230\u5c4f\u5e55\u7684\u6700\u540e\u4e00\u884cLAST\u3002\u5149\u6807\u5b9a\u4f4d\u5728\u663e\u793a\u5c4f\u7684\u6700\u540e\u4e00\u884c ( : \u5149\u6807\u79fb\u81f3\u53e5\u9996 ) : \u5149\u6807\u79fb\u81f3\u53e5\u5c3e { : \u79fb\u5230\u6bb5\u843d\u7684\u5f00\u5934 } : \u79fb\u5230\u4e0b\u4e00\u4e2a\u6bb5\u843d\u7684\u5f00\u5934 % : \u5339\u914d\u62ec\u53f7\u79fb\u52a8\uff0c\u5305\u62ec (, {, [.\uff08\u9700\u8981\u628a\u5149\u6807\u5148\u79fb\u5230\u62ec\u53f7\u4e0a\uff09\u8df3\u8f6c\u5230\u4e0e\u4e4b\u5339\u914d\u7684\u62ec\u53f7\u5904 * \u548c # : \u5339\u914d\u5149\u6807\u5f53\u524d\u6240\u5728\u7684\u5355\u8bcd\uff0c\u79fb\u52a8\u5149\u6807\u5230\u4e0b\u4e00\u4e2a\uff08\u6216\u4e0a\u4e00\u4e2a\uff09\u5339\u914d\u5355\u8bcd\uff08*\u662f\u4e0b\u4e00\u4e2a\uff0c#\u662f\u4e0a\u4e00\u4e2a\uff09 zf : \u6298\u53e0\uff08\u9700\u52a0\u65b9\u5411\u952e\uff09 zo : \u5c55\u5f00\uff08\u7a7a\u683c\u4e5f\u53ef\u4ee5\u5c55\u5f00\uff09 CTRL+u : \u5411\u6587\u4ef6\u9996\u7ffb\u534a\u5c4fup CTRL+d : \u5411\u6587\u4ef6\u5c3e\u7ffb\u534a\u5c4fdown CTRL+f : \u5411\u6587\u4ef6\u5c3e\u7ffb\u4e00\u5c4f forward (fact\u6574\u5c4f\u53bb\u4e24\u884c) CTRL+b : \u5411\u6587\u4ef6\u9996\u7ffb\u4e00\u5c4fback (fact\u6574\u5c4f\u53bb\u4e24\u884c) CTRL-] : \u8df3\u8f6c\u5230\u5f53\u524d\u5149\u6807\u6240\u5728\u5355\u8bcd\u5bf9\u5e94\u7684\u4e3b\u9898 CTRL-O : \u56de\u5230\u524d\u4e00\u4e2a\u4f4d\u7f6e SHIFT+V : \u9009\u62e9\u6574\u884c zz : \u547d\u4ee4\u4f1a\u628a\u5f53\u524d\u884c\u7f6e\u4e3a\u5c4f\u5e55\u6b63\u4e2d\u592e(z\u5b57\u53d6\u5176\u8c61\u5f62\u610f\u4e49\u6a21\u62df\u4e00\u5f20\u7eb8\u7684\u6298\u53e0\u53ca\u53d8\u5f62\u4f4d\u7f6e\u91cd\u7f6e) zt : \u547d\u4ee4\u4f1a\u628a\u5f53\u524d\u884c\u7f6e\u4e8e\u5c4f\u5e55\u9876\u7aef(top) zb : \u547d\u4ee4\u4f1a\u628a\u5f53\u524d\u884c\u7f6e\u4e8e\u5c4f\u5e55\u5e95\u7aef(bottom) 50% : \u5149\u6807\u5b9a\u4f4d\u5728\u6587\u4ef6\u7684\u4e2d\u95f4 ` : \u8df3\u8f6c\u5230\u6700\u8fd1\u5149\u6807\u5b9a\u4f4d\u7684\u4f4d\u7f6e\uff08\u53ea\u80fd\u8bb0\u5fc6\u6700\u8fd1\u4e24\u4e2a\u4f4d\u7f6e\uff09 \u53cd\u5f15\u53f7 I : \u5728\u5149\u6807\u524d\u5f00\u59cb\u63d2\u5165\u5b57\u7b26 insert I : \u5728\u5f53\u524d\u884c\u9996\u5f00\u59cb\u63d2\u5165\u5b57\u7b26 A : \u5728\u5149\u6807\u4f4d\u7f6e\u540e\u5f00\u59cb\u52a0\u5b57 append A : \u5728\u5149\u6807\u6240\u5728\u884c\u7684\u6700\u540e\u9762\u5f00\u59cb\u52a0\u5b57 O : \u5728\u5149\u6807\u4e0b\u52a0\u4e00\u7a7a\u767d\u884c\u5e76\u5f00\u59cb\u52a0\u5b57 open O : \u5728\u5149\u6807\u4e0a\u52a0\u4e00\u7a7a\u767d\u884c\u5e76\u5f00\u59cb\u52a0\u5b57 R : \u66ff\u6362\u5f53\u524d\u5b57\u7b26 R : \u66ff\u6362\u5f53\u524d\u5b57\u7b26\u53ca\u5176\u540e\u7684\u5b57\u7b26\u3010\u5f53\u524d\u53ca\u5176\u540e\u5b57\u7b26\u88ab\u8986\u76d6\u3011 S : \u9ed8\u8ba4\u5220\u9664\u5149\u6807\u6240\u5728\u5b57\u7b26\uff0c\u8f93\u5165\u5185\u5bb9\u63d2\u5165\u4e4b= xi S : \u9ed8\u8ba4\u5220\u9664\u5f53\u524d\u884c\u5185\u5bb9\uff0c\u8f93\u5165\u5185\u5bb9\u4f5c\u4e3a\u5f53\u524d\u884c\u65b0\u5185\u5bb9= dd+o nx : \u5220\u9664\u7531\u5149\u6807\u4f4d\u7f6e\u8d77\u59cb\u540e\u7684n\u4e2a\u5b57\u7b26\uff08\u542b\u5149\u6807\u4f4d\u7f6e\uff09x =dl(\u5220\u9664\u5f53\u524d\u5149\u6807\u4e0b\u7684\u5b57\u7b26) nX : \u5220\u9664\u7531\u5149\u6807\u4f4d\u7f6e\u8d77\u59cb\u524d\u7684n\u4e2a\u5b57\u7b26\uff08\u542b\u5149\u6807\u4f4d\u7f6e\uff09X =dh(\u5220\u9664\u5f53\u524d\u5149\u6807\u5de6\u8fb9\u7684\u5b57\u7b26) d0 : \u5220\u81f3\u884c\u9996 d$ : \u5220\u81f3\u884c\u5c3e dfa : \u8868\u793a\u5220\u9664\u4ece\u5f53\u524d\u5149\u6807\u5230\u5149\u6807\u540e\u9762\u7684\u7b2c\u4e00\u4e2aa\u5b57\u7b26\u4e4b\u95f4\u7684\u5185\u5bb9 D : \u4ee3\u8868d$(\u5220\u9664\u5230\u884c\u5c3e\u7684\u5185\u5bb9) C : \u4ee3\u8868c$(\u4fee\u6539\u5230\u884c\u5c3e\u7684\u5185\u5bb9) ndw : \u5220\u9664\u5149\u6807\u5904\u5f00\u59cb\u53ca\u5176\u540e\u7684n-1\u4e2a\u5b57 ndb : \u5220\u9664\u5149\u6807\u5904\u5f00\u59cb\u53ca\u5176\u524d\u7684n-1\u4e2a\u5b57 diw : \u5220\u9664\u5f53\u524d\u5149\u6807\u6240\u5728\u7684word(\u4e0d\u5305\u62ec\u7a7a\u767d\u5b57\u7b26)\uff0c\u610f\u4e3aDelete Inner Word \u4e24\u4e2a\u7b26\u53f7\u4e4b\u95f4\u7684\u5355\u8bcd daw : \u5220\u9664\u5f53\u524d\u5149\u6807\u6240\u5728\u7684word(\u5305\u62ec\u7a7a\u767d\u5b57\u7b26)\uff0c\u610f\u4e3aDelete A Word ndd : \u5220\u9664\u5f53\u524d\u884c\u53ca\u5176\u540en-1\u884c :n1,n2 d : \u5c06 n1\u884c\u5230n2\u884c\u4e4b\u95f4\u7684\u5185\u5bb9\u5220\u9664 dG : \u5220\u9664\u5f53\u524d\u884c\u81f3\u6587\u4ef6\u5c3e\u7684\u5185\u5bb9 Dgg : \u5220\u9664\u5f53\u524d\u884c\u81f3\u6587\u4ef6\u5934\u7684\u5185\u5bb9 d+enter : \u5220\u96642\u884c\u3010\u5305\u62ec\u5149\u6807\u4e00\u884c\u3011 cw : \u5220\u9664\u5f53\u524d\u5b57\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f\u3010\u5f88\u597d\u7528\uff0c\u5feb\u901f\u66f4\u6539\u4e00\u4e2a\u5355\u8bcd\u3011\u76f8\u5f53\u4e8edw+i ncw : \u5220\u9664\u5f53\u524d\u5b57\u53ca\u5176\u540e\u7684n-1\u4e2a\u5b57\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f\\\u4fee\u6539\u6307\u5b9a\u6570\u76ee\u7684\u5b57 cc : \u5220\u9664\u5f53\u524d\u884c\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f ncc : \u5220\u9664\u5f53\u524d\u884c\u53ca\u5176\u540e\u7684n-1\u884c\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f guw : \u5149\u6807\u4e0b\u7684\u5355\u8bcd\u53d8\u4e3a\u5c0f\u5199 gUw : \u5149\u6807\u4e0b\u7684\u5355\u8bcd\u53d8\u4e3a\u5927\u5199 xp : \u5de6\u53f3\u4ea4\u6362\u5149\u6807\u5904\u4e24\u5b57\u7b26\u7684\u4f4d\u7f6e ga : \u663e\u793a\u5149\u6807\u4e0b\u7684\u5b57\u7b26\u5728\u5f53\u524d\u4f7f\u7528\u7684encoding\u4e0b\u7684\u5185\u7801 nyl : \u590d\u5236n\u4e2a\u5b57\u7b26(\u4e5f\u53efnyh) yw : \u590d\u5236\u4e00\u4e2a\u5355\u8bcd y0 : \u8868\u793a\u62f7\u8d1d\u4ece\u5f53\u524d\u5149\u6807\u5230\u5149\u6807\u6240\u5728\u884c\u9996\u7684\u5185\u5bb9 y$ : \u590d\u5236\u4ece\u5f53\u524d\u4f4d\u7f6e\u5230\u884c\u5c3e yfa : \u8868\u793a\u62f7\u8d1d\u4ece\u5f53\u524d\u5149\u6807\u5230\u5149\u6807\u540e\u9762\u7684\u7b2c\u4e00\u4e2aa\u5b57\u7b26\u4e4b\u95f4\u7684\u5185\u5bb9 yG : \u590d\u5236\u4ece\u6240\u5728\u884c\u5230\u6700\u540e\u4e00\u884c nyy : \u5c06\u5149\u6807\u6240\u5728\u4f4d\u7f6e\u5f00\u59cb\u7684n\u884c\u6570\u636e\u590d\u5236\u6682\u5b58, \u590d\u5236\u4e00\u6574\u884c CTRL+v \u65b9\u5411y : \u5217\u9009\u62e9\u6a21\u5f0f\uff0c\u590d\u5236\u9009\u62e9\u7684\u5f88\u591a\u884c\uff1a\u5148\u4f7f\u7528V\u8fdb\u5165visual\u6a21\u5f0f\uff0c\u7136\u540ej\u5411\u4e0b\u79fb\u52a8\u5230\u4f60\u60f3\u590d\u5236\u7684\u884c\u4e3a\u6b62\uff0c\u7136\u540ey p : \u590d\u5236\u6682\u5b58\u6570\u636e\u5728\u5149\u6807\u7684\u4e0b\u4e00\u884c P : \u590d\u5236\u6682\u5b58\u6570\u636e\u5728\u5149\u6807\u7684\u4e0a\u4e00\u884c :n1,n2 co n3 : \u5c06n1\u884c\u5230n2\u884c\u4e4b\u95f4\u7684\u5185\u5bb9\u62f7\u8d1d\u5230\u7b2cn3+1\u884c\u3010n3\u884c\u7684\u4e0b\u4e00\u884c\u3011 :n1,n2 m n3 : \u5c06n1\u884c\u5230n2\u884c\u4e4b\u95f4\u7684\u5185\u5bb9\u79fb\u81f3\u5230\u7b2cn3\u884c\u4e0b J : \u628a\u4e0b\u4e00\u884c\u7684\u6570\u636e\u8fde\u63a5\u5230\u672c\u884c\u4e4b\u540e, \u591a\u4e00\u7a7a\u683c ~ : \u6539\u53d8\u5f53\u524d\u5149\u6807\u4e0b\u5b57\u7b26\u7684\u5927\u5c0f\u5199 \u5176\u4ed6 . : \u91cd\u590d\u524d\u4e00\u6307\u4ee4 u : \u53d6\u6d88\u524d\u4e00\u6307\u4ee4undo, :u\u4e5f\u884c\uff0c\u4e00\u822c\u4e0d\u7528\uff0c\u64cd\u4f5c\u592a\u591a Ctrl + r : \u6062\u590d\u3010\u53ea\u5bf9u\u6709\u6548\u3011redo Ctrl + l : \u5237\u65b0\u5c4f\u5e55\u663e\u793a Ctrl+v \u7136\u540e ctrl+A\u662f^A Ctrl+I\u662f\\t : \u8f93\u5165\u7279\u6b8a\u5b57\u7b26 Ctrl+v\u7136\u540e\u7528j\u3001k\u3001l\u3001h\u6216\u65b9\u5411\u952e\u4e0a\u4e0b\u9009\u4e2d\u591a\u5217\uff0c\u4e4b\u540e I I a A r x\u7b49\uff0c\u6700\u540e\u6309esc\uff0c\u751f\u6548 : Vim\u5217\u64cd\u4f5c 2.\u6587\u672c\u5904\u7406\u5de5\u5177 \u00b6 2.1.\u663e\u793a\u6587\u672c\u5185\u5bb9 cat \u00b6 \u547d\u4ee4 cat \u4e3b\u8981\u53c2\u6570\u8bf4\u660e\uff1a -E \uff1a\u663e\u793a\u884c\u7ed3\u675f\u7b26 $ -A \uff1a\u663e\u793a\u6240\u6709\u63a7\u5236\u7b26 -n \uff1a\u5bf9\u663e\u793a\u51fa\u7684\u6bcf\u4e00\u884c\u8fdb\u884c\u7f16\u53f7 -b \uff1a\u975e\u7a7a\u884c\u7f16\u53f7 -s \uff1a\u538b\u7f29\u8fde\u7eed\u7684\u7a7a\u884c\u6210\u4e00\u884c \u4e3e\u4f8b\uff1a cat -nA user-list.txt 1 user0$ 2 user1$ 3 user2$ 4 user3$ 5 user4$ 6 user5$ 7 user6$ 8 user7$ 9 user8$ 10 user9$ 2.2.\u663e\u793a\u6587\u672c\u884c\u53f7 nl \u00b6 \u76f8\u5f53\u4e8e\u547d\u4ee4 cat -b \u3002 \u547d\u4ee4 nl \u4e3b\u8981\u53c2\u6570\u8bf4\u660e\uff1a -b \uff1a\u6307\u5b9a\u884c\u53f7\u6307\u5b9a\u7684\u65b9\u5f0f\uff0c\u4e3b\u8981\u6709\u4e24\u79cd\uff1a -b a \uff1a\u8868\u793a\u4e0d\u8bba\u662f\u5426\u4e3a\u7a7a\u884c\uff0c\u4e5f\u540c\u6837\u5217\u51fa\u884c\u53f7\uff08\u7c7b\u4f3c cat -n\uff09\uff1b -b t \uff1a\u5982\u679c\u6709\u7a7a\u884c\uff0c\u7a7a\u7684\u90a3\u4e00\u884c\u4e0d\u8981\u5217\u51fa\u884c\u53f7\uff08\u9ed8\u8ba4\u503c\uff09\uff1b -n \uff1a\u5217\u51fa\u884c\u53f7\u8868\u793a\u7684\u65b9\u6cd5\uff0c\u4e3b\u8981\u6709\u4e09\u79cd\uff1a -n ln \uff1a\u884c\u53f7\u5728\u5c4f\u5e55\u7684\u6700\u5de6\u65b9\u663e\u793a\uff1b\u6ca1\u6709\u524d\u5bfc0\uff1b -n rn \uff1a\u884c\u53f7\u5728\u81ea\u5df1\u680f\u4f4d\u7684\u6700\u53f3\u65b9\u663e\u793a\uff0c\u6ca1\u6709\u524d\u5bfc0\uff1b -n rz \uff1a\u884c\u53f7\u5728\u81ea\u5df1\u680f\u4f4d\u7684\u6700\u53f3\u65b9\u663e\u793a\uff0c\u6709\u524d\u5bfc0\uff1b -w \uff1a\u884c\u53f7\u680f\u4f4d\u7684\u5360\u7528\u7684\u4f4d\u6570\u3002 -p \uff1a\u5728\u903b\u8f91\u5b9a\u754c\u7b26\u5904\u4e0d\u91cd\u65b0\u5f00\u59cb\u8ba1 \u4e3e\u4f8b\uff1a $ nl -b a -n rz user-list.txt 000001 user0 000002 user1 000003 user2 000004 user3 000005 user4 000006 user5 000007 user6 000008 user7 000009 user8 000010 user9 2.3.\u9006\u5411\u663e\u793a\u6587\u672c\u5185\u5bb9 tac \u00b6 \u547d\u4ee4 tac \u9006\u5411\u663e\u793a\u6587\u672c\u5185\u5bb9\u3002 \u4e3e\u4f8b\uff1a $ tac user-list.txt user9 user8 user7 user6 user5 user4 user3 user2 user1 user0 \u4e3e\u4f8b\uff1a $ seq 10 | tac 10 9 8 7 6 5 4 3 2 1 2.4.\u9006\u5411\u663e\u793a\u540c\u884c\u5185\u5bb9 rev \u00b6 \u547d\u4ee4 rev \u9006\u5411\u663e\u793a\u540c\u4e00\u884c\u7684\u5185\u5bb9\u3002 \u4e3e\u4f8b\uff1a $ rev user-list.txt 0resu 1resu 2resu 3resu 4resu 5resu 6resu 7resu 8resu 9resu \u4e3e\u4f8b\uff1a $ echo { 1 ..10 } | rev 01 9 8 7 6 5 4 3 2 1 2.5.\u663e\u793a\u975e\u6587\u672c\u6587\u4ef6\u5185\u5bb9 hexdump \u00b6 \u547d\u4ee4 hexdump \u547d\u4ee4\u4e00\u822c\u7528\u6765\u67e5\u770b\u201c\u4e8c\u8fdb\u5236\u201d\u6587\u4ef6\u7684\u5341\u516d\u8fdb\u5236\u7f16\u7801 \u4e3e\u4f8b\uff1a $ hexdump -C -n 32 cp 00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 | .ELF............ | 00000010 03 00 3e 00 01 00 00 00 e0 48 00 00 00 00 00 00 | ..>......H...... | 00000020 2.6.\u5206\u9875\u67e5\u770b\u6587\u4ef6\u5185\u5bb9 \u00b6 \u547d\u4ee4 more \u548c less \u53ef\u4ee5\u5b9e\u73b0\u5206\u9875\u67e5\u770b\u6587\u4ef6\u5185\u5bb9\u3002 \u547d\u4ee4 less \u914d\u5408\u7ba1\u9053\u7b26\u4f7f\u7528\u3002 tree -d /etc | less 2.7.\u663e\u793a\u6587\u4ef6\u5934\u90e8\u5185\u5bb9 head \u00b6 \u547d\u4ee4 head \u663e\u793a\u6587\u4ef6\u5934\u90e8\u5185\u5bb9\u3002 head -c 20 cp : \u663e\u793a\u6587\u4ef6\u524d20\u5b57\u8282\u5185\u5bb9 head -n 20 zdiff : \u663e\u793a\u6587\u4ef6\u524d20\u884c\u5185\u5bb9 head -20 zdiff : \u663e\u793a\u6587\u4ef6\u524d20\u884c\u5185\u5bb9 $ echo \"\u6211\u662f\u8c01\" | head -c3 \u6211 $ echo \"\u6211\u662f\u8c01\" | head -c6 \u6211\u662f cat /dev/urandom | tr -dc '[:alnum]' | head -c 10 | tee passwd.txt $ cat user-list.txt user0 user1 user2 user3 user4 user5 user6 user7 user8 user9 $ head -n -3 user-list.txt user0 user1 user2 user3 user4 user5 user6 2.8.\u663e\u793a\u6587\u4ef6\u5c3e\u90e8\u5185\u5bb9 tail \u00b6 \u547d\u4ee4 tail \u663e\u793a\u6587\u4ef6\u5934\u90e8\u5185\u5bb9\u3002 tail -c 200 cp : \u663e\u793a\u6587\u4ef6\u5c3e\u90e8200\u4e2a\u5b57\u8282\u7684\u5185\u5bb9 tail -n 3 user-list.txt : \u663e\u793a\u6587\u4ef6\u6700\u540e3\u884c tail -n -3 user-list.txt : \u663e\u793a\u4ece-3\u884c\u5230\u6587\u4ef6\u7ed3\u675f\uff08\u5373\u6700\u540e\u4e09\u884c\uff09 tail -3 user-list.txt : \u663e\u793a\u6587\u4ef6\u6700\u540e3\u884c tail -f /var/log/messages : \u8ddf\u8e2a\u663e\u793a\u6587\u4ef6redo.log\u6587\u4ef6\u5185\u5bb9\uff0c\u5f53\u6587\u4ef6\u5220\u9664\uff0c\u518d\u5efa\u540c\u540d\u6587\u4ef6\uff0c\u65e0\u6cd5\u7ee7\u7eed\u8ffd\u8e2a tail -F /var/log/messages : \u8ddf\u8e2a\u663e\u793a\u6587\u4ef6redo.log\u6587\u4ef6\u5185\u5bb9\uff0c\u5f53\u6587\u4ef6\u5220\u9664\uff0c\u518d\u5efa\u540c\u540d\u6587\u4ef6\uff0c\u7ee7\u7eed\u8ffd\u8e2a 2.9.\u6309\u5217\u62bd\u53d6\u6587\u672c cut \u00b6 \u547d\u4ee4 cut \u53ef\u4ee5\u63d0\u53d6\u6587\u672c\u6587\u4ef6\u6216\u8005stdin\u6570\u636e\u7684\u6307\u5b9a\u5217\u5185\u5bb9\u3002 \u9009\u9879\uff1a -f : \u901a\u8fc7\u6307\u5b9a\u54ea\u4e00\u4e2a\u5b57\u6bb5\u8fdb\u884c\u63d0\u53d6\u3002cut\u547d\u4ee4\u4f7f\u7528\u201cTAB\u201d\u4f5c\u4e3a\u9ed8\u8ba4\u7684\u5b57\u6bb5\u5206\u9694\u7b26 -d : \u201cTAB\u201d\u662f\u9ed8\u8ba4\u7684\u5206\u9694\u7b26\uff0c\u4f7f\u7528\u6b64\u9009\u9879\u53ef\u4ee5\u66f4\u6539\u4e3a\u5176\u4ed6\u7684\u5206\u9694\u7b26 --complement : \u6b64\u9009\u9879\u7528\u4e8e\u6392\u9664\u6240\u6307\u5b9a\u7684\u5b57\u6bb5 --output-delimiter=STRING : \u6307\u5b9a\u8f93\u51fa\u5185\u5bb9\u7684\u5206\u9694\u7b26 -c : \u6309\u5b57\u7b26\u5207\u5272 \u53d6/etc/passwd\u6587\u4ef6\u7b2c1\u5217\u5185\u5bb9\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff08\u53ea\u53d6\u524d\u4e09\u884c\uff09 $ cut -d ':' -f 1 /etc/passwd | head -3 root messagebus systemd-network \u53d6/etc/passwd\u6587\u4ef6\u7b2c1\u548c6\u5217\u5185\u5bb9\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff08\u53ea\u53d6\u524d\u4e09\u884c\uff09 cut -d ':' -f 1 ,6 /etc/passwd | head -3 root:/root messagebus:/run/dbus systemd-network:/ \u53d6/etc/passwd\u6587\u4ef6\u7b2c1\u52303\u5217\u4ee5\u53ca\u7b2c6\u5217\u5185\u5bb9\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff08\u53ea\u53d6\u524d\u4e09\u884c\uff09 $ cut -d ':' -f 1 -3,6 /etc/passwd | head -3 root:x:0:/root messagebus:x:499:/run/dbus systemd-network:x:497:/ \u4e0b\u9762\u4f7f\u7528 --output-delimiter \u9009\u9879\uff0c\u628a\u8f93\u51fa\u7ed3\u679c\u4e2d\u7684\u5206\u9694\u7b26 : \u5168\u90e8\u66ff\u6362\u6210 --- \u3002 $ cat /etc/passwd | sort | head -3 admin3:x:1020:100::/home/admin3:/bin/bash at:x:25:25:Batch jobs daemon:/var/spool/atjobs:/usr/sbin/nologin bin:x:1:1:bin:/bin:/usr/sbin/nologin $ cut -d \":\" -f 1 ,7 /etc/passwd | sort | head -3 admin3:/bin/bash at:/usr/sbin/nologin bin:/usr/sbin/nologin $ cut -d \":\" -f 1 ,7 --output-delimiter = \"---\" /etc/passwd | sort | head -3 admin3---/bin/bash at---/usr/sbin/nologin bin---/usr/sbin/nologin --output-delimiter \u9009\u9879\u4e5f\u53ef\u4ee5\u5229\u7528\u6765\u8fdb\u884c\u8ba1\u7b97\u3002 $ echo { 1 ..10 } | cut -d \" \" -f 1 -10 --output-delimiter = \"+\" | bc 55 \u4ece ifconfig \u547d\u4ee4\u4e2d\u622a\u53d6\u5f53\u524d\u4e3b\u673a\u7684ip\u5730\u5740\u3002\uff08openSUSE\u9700\u8981\u5b89\u88c5\u5305 net-tools-deprecated \uff09 $ ifconfig | head -2 | tail -1 inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig | head -2 | tail -1 | cut -d \" \" -f 10 192 .168.10.210 \u6216\u8005 $ ip addr list | grep eth0 | tail -1 | cut -d \" \" -f 6 192 .168.10.210/24 \u57fa\u4e8e\u4e0a\u9762\u7ed3\u679c\uff0c\u53ef\u4ee5\u5c1d\u8bd5\u901a\u8fc7 --complement \u53c2\u6570\uff0c\u4ee5 / \u4e3a\u5206\u9694\u7b26\uff0c\u6392\u9664\u7b2c\u4e8c\u5217 24 \uff0c\u53ea\u8f93\u51fa\u7b2c\u4e00\u5217IP\u5730\u5740\u3002 ip addr list | grep eth0 | tail -1 | cut -d \" \" -f 6 | cut -d \"/\" --complement -f 2 192 .168.10.210 \u663e\u793a df \u547d\u4ee4\u8f93\u51fa\u4e2d\u7684\u5206\u533a\u4f7f\u7528\u7387\u3002 $ df | tr -s ' ' | cut -d ' ' -f 5 | tr -d % Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0 \u65b9\u6cd52\uff1a\u5148\u628a\u7a7a\u683c\u5168\u90e8\u66ff\u6362\u6210%\uff0c\u518d\u53bb\u91cd\u3002 df | tr -s ' ' % | cut -d % -f 5 Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0 2.10.\u5408\u5e76\u591a\u4e2a\u6587\u4ef6 paste \u00b6 \u547d\u4ee4 paste \u5e38\u7528\u9009\u9879\uff1a -d \uff1a\u6307\u5b9a\u5206\u9694\u7b26\uff0c\u9ed8\u8ba4\u662fTAB -s \uff1a\u6240\u6709\u884c\u5408\u6210\u4e00\u884c\u663e\u793a \u751f\u6210 alpha.log \u548c seq.log \u3002 for i in { a..z } ; do echo $i >> alpha.log ; done seq 10 > seq.log \u7528 paste \u547d\u4ee4\u5408\u5e76\u8fd92\u4e2a\u6587\u4ef6\u3002 $ paste alpha.log seq.log a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k l m n o p q r s t u v w x y z $ paste -d \":\" alpha.log seq.log a:1 b:2 c:3 d:4 e:5 f:6 g:7 h:8 i:9 j:10 k: l: m: n: o: p: q: r: s: t: u: v: w: x: y: z: \u539f\u6587\u4ef6\u90fd\u662f\u5217\u8f93\u51fa\uff0c\u6539\u6210\u884c\u8f93\u51fa\u3002 $ paste -d \"-\" -s alpha.log a-b-c-d-e-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z $ paste -d \"-\" -s seq.log $ paste -d \":\" -s alpha.log seq.log a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z 1 :2:3:4:5:6:7:8:9:10 $ paste -d \":\" -s seq.log alpha.log 1 :2:3:4:5:6:7:8:9:10 a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z 2.11.\u6587\u672c\u7edf\u8ba1\u6570\u636e wc \u00b6 \u5e38\u7528\u9009\u9879\uff1a -l \uff1a\u53ea\u8ba1\u6570\u884c\u6570 -w \uff1a\u53ea\u8ba1\u6570\u5355\u8bcd\u603b\u6570 -c \uff1a\u53ea\u8ba1\u6570\u5b57\u8282\u603b\u6570 -m \uff1a\u53ea\u8ba1\u6570\u5b57\u7b26\u603b\u6570 -L \uff1a\u663e\u793a\u6587\u4ef6\u4e2d\u6700\u957f\u884c\u7684\u957f\u5ea6 $ cat text Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ wc text # \u884c\u6570 \u5355\u8bcd\u6570 \u5b57\u8282\u6570 3 9 57 text $ wc -l text 3 text $ wc -w text 9 text $ wc -c text 57 text $ wc -m text 57 text $ wc -L text 20 text \u5bf9\u6bd4\u4e24\u79cd\u4e0d\u540c\u5408\u5e76\u7684\u65b9\u6cd5\u3002 $ cat text1 text2 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou $ paste text1 text2 Tom, 20 , Shanghai Tom, 20 , Shanghai Jack, 30 , Beijing Jack, 30 , Beijing Smith, 40 , Guangzhou Leo, 40 , Guangzhou 2.12.\u6587\u672c\u6392\u5e8f sort \u00b6 \u547d\u4ee4 sort \u628a\u6574\u7406\u8fc7\u7684\u6587\u672c\u663e\u793a\u5728stdout\u4e0a\uff0c\u4e0d\u6539\u53d8\u539f\u6587\u4ef6\u3002 \u5e38\u7528\u9009\u9879\uff1a -r \uff1a\u6267\u884c\u53cd\u65b9\u5411\uff08\u4ece\u4e0a\u81f3\u4e0b\uff09\u6392\u5e8f -R \uff1a\u968f\u673a\u6392\u5e8f -n \uff1a\u6309\u6570\u5b57\u5927\u5c0f\u6392\u5e8f -h \uff1a\u4eba\u7c7b\u53ef\u8bfb\u6392\u5e8f\uff0c\u5982\uff1a2K\uff0c1G -f \uff1a\u6392\u5e8f\u65f6\u5c06\u5c0f\u5199\u5b57\u6bcd\u89c6\u4e3a\u5927\u5199\u5b57\u6bcd -u \uff1a\u6392\u5e8f\u65f6\u5408\u5e76\u91cd\u590d\u9879 -t c \uff1a\u4f7f\u7528c\u4f5c\u4e3a\u5b57\u6bb5\u5206\u9694\u7b26 -k # \uff1a\u6309\u7167\u4ee5c\u4e3a\u5206\u9694\u7b26\u7684\u7b2c#\u5217\u6765\u6392\u5e8f \u4e3e\u4f8b\uff1a\u4ee5 , \u4e3a\u5206\u9694\u7b26\uff0c\u8bfb\u53d6 text \u6587\u4ef6\u5185\u5bb9\u4e2d\u7b2c1\uff0c3\u5217\uff0c\u5bf9\u8f93\u51fa\u7ed3\u679c\u4ee5 , \u4e3a\u5206\u9694\u7b26\uff0c\u6309\u7b2c\u4e8c\u5217\u6392\u5e8f\uff08\u6b63\u5e8f\u548c\u53cd\u5e8f\uff09\u3002 $ cat text Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ cut -d \",\" -f 1 ,3 text | sort -t \",\" -k 1 Jack, Beijing Smith, Guangzhou Tom, Shanghai $ cut -d \",\" -f 1 ,3 text | sort -t \",\" -k 1 -r Tom, Shanghai Smith, Guangzhou Jack, Beijing \u628a\u6587\u4ef6text1\u548c\u6587\u4ef6text2\u5408\u5e76\u540e\u53bb\u91cd\u8f93\u51fa\u3002 $ cat text2 Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou $ cat text1 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ cat text1 text2 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou \u5e76\u96c6\uff0c\u91cd\u590d\u884c\u53ea\u4fdd\u7559\u4e00\u884c\u3002\u524d\u97622\u4e2a\u547d\u4ee4\u662f\u540c\u6837\u542b\u4e49\uff08\u76f8\u540c\u7684\u6392\u5e8f\u5217\uff09\uff0c\u7b2c\u4e09\u4e2a\u547d\u4ee4\u4e2d\u5bf9\u4e0d\u540c\u5217\u8fdb\u884c\u4e86\u6392\u5e8f\uff0c\u5bfc\u81f4\u53bb\u91cd\u7ed3\u679c\u4e0d\u540c\u3002 $ cat text1 text2 | sort -u Jack, 30 , Beijing Leo, 40 , Guangzhou Smith, 40 , Guangzhou Tom, 20 , Shanghai $ cat text1 text2 | sort -t \",\" -k 1 -u Jack, 30 , Beijing Leo, 40 , Guangzhou Smith, 40 , Guangzhou Tom, 20 , Shanghai $ cat text1 text2 | sort -t \",\" -k 2 -u Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou 2.13.\u53bb\u91cd uniq \u00b6 \u547d\u4ee4 uniq \u4ece\u8f93\u5165\u4e2d\u5220\u9664\u524d\u540e\u76f8\u90bb\u91cd\u590d\u7684\u884c\u3002\u7ecf\u5e38\u4e0e sort \u547d\u4ee4\u7ed3\u5408\u4f7f\u7528\u3002 \u4e3b\u8981\u53c2\u6570\uff1a -c \uff1a\u663e\u793a\u6bcf\u884c\u91cd\u590d\u51fa\u73b0\u7684\u6b21\u6570 -d \uff1a\u4ec5\u663e\u793a\u91cd\u590d\u7684\u884c -u \uff1a\u4ec5\u663e\u793a\u4e0d\u91cd\u590d\u7684\u884c \u4e3e\u4f8b\uff0c\u6ce8\u610f\u53ea\u6709\u5bf9\u76f8\u90bb\u884c\u8fdb\u884c\u53bb\u91cd\u3002 $ cat text3 test 30 Hello 95 Hello 95 Linux 85 Linux 85 Hello 95 test 30 $ uniq text3 test 30 Hello 95 Linux 85 Hello 95 test 30 \u628a\u6587\u4ef6text1\u548c\u6587\u4ef6text2\u5408\u5e76\u540e\uff0c\u8fdb\u884c\u4ea4\u96c6\u548c\u5e76\u96c6\uff0c\u5e76\u53bb\u91cd\u3002 $ cat text1 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ cat text2 Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou # \u5e76\u96c6\uff0c\u6309\u9996\u5217\u6392\u5e8f\u53bb\u91cd $ cat text1 text2 | sort | uniq Jack, 30 , Beijing Leo, 40 , Guangzhou Smith, 40 , Guangzhou Tom, 20 , Shanghai # \u4ea4\u96c6 $ cat text1 text2 | sort | uniq -d Jack, 30 , Beijing Tom, 20 , Shanghai # \u5dee\u96c6 $ cat text1 text2 | sort | uniq -u Leo, 40 , Guangzhou Smith, 40 , Guangzhou \u67e5\u770b\u5e76\u53d1\u8fde\u63a5\u6570\u6700\u591a\u7684\u8fdc\u7a0b\u4e3b\u673aIP\u3002 $ ss -nt State Recv-Q Send-Q Local Address:Port Peer Address:Port Process ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:41650 ESTAB 0 0 192 .168.10.210:22 192 .168.10.201:65330 ESTAB 0 64 192 .168.10.210:22 192 .168.10.201:63289 ESTAB 0 0 192 .168.10.210:41650 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:47992 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:60268 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.201:65327 ESTAB 0 0 192 .168.10.210:35758 192 .168.10.220:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:56818 ESTAB 0 0 192 .168.10.210:56818 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:48006 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:60268 ESTAB 0 0 192 .168.10.210:22 192 .168.10.220:33896 ESTAB 0 0 192 .168.10.210:22 192 .168.10.201:65324 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:47992 ESTAB 0 0 192 .168.10.210:59554 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:59554 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:48006 $ ss -nt | tr -s \" \" \":\" | cut -d \":\" -f 6 ,7 | sort | uniq -c | sort -nr | head -n 1 6 192 .168.10.210:22 2.14.\u6587\u672c\u6bd4\u8f83 \u00b6 2.14.1. diff \u00b6 \u547d\u4ee4 diff \u6bd4\u8f83\u4e24\u4e2a\u6587\u4ef6\u4e4b\u95f4\u7684\u533a\u522b\u3002 \u5e38\u7528\u9009\u9879\uff1a -u \uff1a\u4ee5\u7edf\u4e00\u7684\u65b9\u5f0f\u6765\u663e\u793a\u6587\u4ef6\u5185\u5bb9\u7684\u4e0d\u540c -y \uff1a\u4ee5\u5e76\u5217\u7684\u65b9\u5f0f\u663e\u793a\u6587\u4ef6\u7684\u5f02\u540c\u4e4b\u5904 -W \uff1a\u5728\u4f7f\u7528-y\u53c2\u6570\u65f6\uff0c\u6307\u5b9a\u680f\u5bbd -c \uff1a\u663e\u793a\u5168\u90e8\u5185\u6587\uff0c\u5e76\u6807\u51fa\u4e0d\u540c\u4e4b\u5904 -N \uff1a\u7f3a\u5931\u6587\u4ef6\u4ee5\u7a7a\u6587\u4ef6\u5904\u7406 \u4e3e\u4f8b\uff1a $ cat text5 # \u6587\u4ef6\u5c3e\u90e8\u6ca1\u6709\u7a7a\u884c 1001 1002 1003 $ cat text6 # \u6587\u4ef6\u5c3e\u90e8\u6ca1\u6709\u7a7a\u884c 1001 1002 1003a 1004 \u663e\u793a\u4e0d\u540c\u3002 3c3,4 \u4ee3\u8868\u4e24\u4e2a\u6587\u4ef6\u5728\u7b2c3\uff0c4\u884c\u6709\u4e0d\u540c\u3002 $ diff text5 text6 3c3,4 < 1003 --- > 1003a > 1004 \u4ee5\u7edf\u4e00\u683c\u5f0f\u8f93\u51fa\u6bd4\u8f83\u7ed3\u679c\u3002 \u524d2\u884c\u662f\u6587\u4ef6\u4fe1\u606f\u3002\u5176\u4e2d --- \u8868\u793a\u53d8\u52a8\u524d\u7684\u6587\u4ef6\uff0c +++ \u8868\u793a\u53d8\u52a8\u540e\u7684\u6587\u4ef6\u3002 \u53d8\u52a8\u7684\u4f4d\u7f6e\u7528\u4e24\u4e2a@\u4f5c\u4e3a\u8d77\u9996\u548c\u7ed3\u675f\uff0c @@ -1,3 +1,4 @@ \u3002 -1,3 \u4e2d\uff0c - \u8868\u793a\u7b2c\u4e00\u4e2a\u6587\u4ef6\uff0c\u5373 text5 \u3002\u7b2c\u4e00\u4e2a\u6587\u4ef6\u4ece\u7b2c1\u884c\u5f00\u59cb\u8fde\u7eed3\u884c\u3002 +1,4 \u4e2d\uff0c + \u8868\u793a\u7b2c\u4e8c\u4e2a\u6587\u4ef6\uff0c\u5373 text6 \u3002\u5373\uff0c\u7b2c\u4e8c\u4e2a\u6587\u4ef6\u4ece\u7b2c1\u884c\u5f00\u59cb\u8fde\u7eed4\u884c\u3002 $ diff -u text5 text6 --- text5 2022 -12-07 08 :07:05.927805722 +0800 +++ text6 2022 -12-07 08 :07:24.692234585 +0800 @@ -1,3 +1,4 @@ 1001 1002 -1003 +1003a +1004 \u4ee5\u4e0a\u4e0b\u6587\u65b9\u5f0f\u8f93\u51fa\u6bd4\u8f83\u7ed3\u679c\u3002\u6807\u6709 ! \u4ee3\u8868\u5dee\u5f02\u884c\u3002 $ diff -c text5 text6 *** text5 2022 -12-07 08 :24:08.867168414 +0800 --- text6 2022 -12-07 08 :24:13.939284243 +0800 *************** *** 1 ,3 **** 1001 1002 ! 1003 --- 1 ,4 ---- 1001 1002 ! 1003a ! 1004 \u5e76\u6392\u683c\u5f0f\u8f93\u51fa\u6bd4\u8f83\u7ed3\u679c\u3002 | \u8868\u793a\u524d\u540e2\u4e2a\u6587\u4ef6\u5185\u5bb9\u6709\u4e0d\u540c < \u8868\u793a\u540e\u9762\u6587\u4ef6\u6bd4\u524d\u9762\u6587\u4ef6\u5c11\u4e861\u884c\u5185\u5bb9 > \u8868\u793a\u540e\u9762\u6587\u4ef6\u6bd4\u524d\u9762\u6587\u4ef6\u591a\u4e861\u884c\u5185\u5bb9 $ diff -y -W 50 text5 text6 1001 1001 1002 1002 1003 | 1003a > 1004 \u6bd4\u8f83\u6587\u4ef6\u5939\u5185\u5bb9\u3002\u6ce8\u610f\uff0c\u53ea\u6bd4\u8f83\u5185\u5bb9\uff0c\u4e0d\u6bd4\u8f83\u65f6\u95f4\u6233\u3002 $ mkdir dir1 $ mkdir dir2 $ cd dir1 $ touch file1 $ touch file2 $ cp file1 file2 ../dir2/ $ echo \"hello\" > file3 $ cd ../dir2 $ touch file3 $ touch file4 $ diff dir1 dir2 1d0 < hello Only in dir2: file4 2.14.2. patch \u00b6 \u547d\u4ee4 patch \u590d\u5236\u5176\u4ed6\u6587\u4ef6\u4e2d\u7684\u5185\u5bb9\u3002\u547d\u4ee4\u683c\u5f0f\uff1a patch -p [ num ] < patchfile patch [ options ] originalfile patchfile \u5f53\u7279\u5b9a\u8f6f\u4ef6\u6709\u53ef\u7528\u7684\u5b89\u5168\u4fee\u590d\u7a0b\u5e8f\u65f6\uff0c\u6211\u4eec\u901a\u5e38\u4f1a\u4f7f\u7528 yum \u6216 apt-get \u6216 zypper \u7b49\u5305\u7ba1\u7406\u5de5\u5177\u8fdb\u884c\u4e8c\u8fdb\u5236\u5347\u7ea7\u3002 \u4f46\u5982\u679c\u6211\u4eec\u662f\u901a\u8fc7\u4ece\u6e90\u4ee3\u7801\u7f16\u8bd1\u5b89\u88c5\u8f6f\u4ef6\u7684\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u9700\u8981\u4e0b\u8f7d\u5b89\u5168\u8865\u4e01\u5e76\u5c06\u5176\u5e94\u7528\u4e8e\u539f\u59cb\u6e90\u4ee3\u7801\u5e76\u91cd\u65b0\u7f16\u8bd1\u8f6f\u4ef6\u3002 \u8fd9\u5c31\u662f\u6211\u4eec\u4f7f\u7528 diff \u521b\u5efa\u8865\u4e01\u6587\u4ef6\uff08patch file\uff09\uff0c\u5e76\u4f7f\u7528 patch \u547d\u4ee4\u5e94\u7528\u5b83\u3002 \u8865\u4e01\u6587\u4ef6\u662f\u4e00\u4e2a\u6587\u672c\u6587\u4ef6\uff0c\u5176\u4e2d\u5305\u542b\u540c\u4e00\u6587\u4ef6\uff08\u6216\u540c\u4e00\u6e90\u4ee3\u7801\u6811\uff09\u7684\u4e24\u4e2a\u7248\u672c\u4e4b\u95f4\u7684\u5dee\u5f02\u3002 \u8865\u4e01\u6587\u4ef6\u662f\u4f7f\u7528 diff \u547d\u4ee4\u521b\u5efa\u7684\u3002 \u7ee7\u7eed\u4e0a\u4f8b\u3002 \u5c06\u6587\u4ef6 text5 \u7684\u5185\u5bb9\u540c\u6b65\u5230\u6587\u4ef6 text6 \uff0c\u7136\u540e\u64a4\u9500\u8865\u4e01\u3002\u6ce8\u610f\u533a\u5206\u6e90\u6587\u4ef6\u548c\u76ee\u6807\u6587\u4ef6\u3002 $ cat text5 1001 1002 1003 $ cat text6 1001 1002 1003a 1004 # \u751f\u6210\u8865\u4e01\u6587\u4ef6 $ diff -ruN text5 text6 > patchfile $ cat patchfile --- text5 2022 -12-07 08 :24:08.867168414 +0800 +++ text6 2022 -12-07 08 :24:13.939284243 +0800 @@ -1,3 +1,4 @@ 1001 1002 -1003 +1003a +1004 # \u4e0d\u6307\u660e\u76ee\u6807\u6587\u4ef6\uff0c\u5219\u9ed8\u8ba4\u7ed9diff\u547d\u4ee4\u4e2d\u7684\u6e90\u6587\u4ef6\u8fdb\u884c\u6253\u8865\u4e01 $ patch < patchfile patching file text5 $ cat text5 1001 1002 1003a 1004 $ cat text6 1001 1002 1003a 1004 # \u64a4\u9500\u8865\u4e01 patch -R < patchfile patching file text5 # cat text5 1001 1002 1003 # \u7ed9text6\u6587\u4ef6\u6253\u8865\u4e01\uff08\u7528text5\u7684\u6587\u4ef6\u5185\u5bb9\u8986\u76d6text6\u7684\u5185\u5bb9\uff09 $ patch text6 patchfile patching file text6 Reversed ( or previously applied ) patch detected! Assume -R? [ n ] y $ cat text6 1001 1002 1003 # \u64a4\u9500\u7ed9text6\u6587\u4ef6\u6253\u7684\u8865\u4e01\uff08\u6062\u590dtext6\u6587\u4ef6\u8865\u4e01\u524d\u7684\u5185\u5bb9\uff09 $ patch -R text6 patchfile patching file text6 Unreversed patch detected! Ignore -R? [ n ] y $ cat text6 1001 1002 1003a 1004 \u4f7f\u7528 -b \u53c2\u6570\uff0c\u5728patch\u524d\u5148\u5907\u4efd\u6e90\u6587\u4ef6\u3002 $ patch -b < patchfile patching file text5 $ cat text5 1001 1002 1003a 1004 $ cat text5.orig 1001 1002 1003 $ cat text6.orig 1001 1002 1003 $ patch -R < patchfile patching file text5 \u5728-b\u53c2\u6570\u4e2d\u52a0\u5165-V\u53c2\u6570\uff0c\u6307\u5b9a\u5907\u4efd\u6587\u4ef6\u540d\u7684\u683c\u5f0f\uff0c\u5982\u4e0b\uff0c\u4f1a\u5f97\u5230\u6587\u4ef6 text5.~1~ \u3002 $patch -b -V numbered < patchfile patching file text5 $ cat text5 1001 1002 1003a 1004 $ cat text5.~1~ 1001 1002 1003 \u8bd5\u8fd0\u884c\uff0c\u4e0d\u505a\u5b9e\u9645\u66f4\u6539\u3002 patch --dry-run < patchfile \u5bf9\u76ee\u5f55\u6253\u8865\u4e01\u3002 \u6267\u884c diff \u548c patch \u547d\u4ee4\u662f\u5728\u5f53\u524d\u7528\u6237 vagrant \u7684\u4e3b\u76ee\u5f55\u4e0b\uff0c\u7edd\u5bf9\u8def\u5f84\u662f /home/vagrant \u3002 diff \u547d\u4ee4\u4e2d\uff0c\u6e90\u76ee\u5f55\u662f /home/vagrant/dir1 \u3002\u76ee\u6807\u76ee\u5f55\u662f /home/vagrant/dir2 \u3002 -p3 \u662f\u544a\u8bc9 patch \u547d\u4ee4\u5ffd\u7565\u4e0a\u9762\u7edd\u5bf9\u8def\u5f84\u4e2d\u524d\u4e09\u4e2a\u659c\u6760 / \u3002 patch \u547d\u4ee4\u4e2d\u7528 diff \u7684\u76ee\u6807\u76ee\u5f55\u53bb\u8986\u76d6\u6e90\u76ee\u5f55\u3002\u4e92\u6362\u4f1a\u62a5\u9519\u3002 -R \uff1a\u64a4\u9500\u8865\u4e01\u3002 # file3\u548cfile4\u6709\u5185\u5bb9 $ tree ./dir1 ./dir1 \u251c\u2500\u2500 file1 \u251c\u2500\u2500 file2 \u251c\u2500\u2500 file3 \u2514\u2500\u2500 subdir1 \u2514\u2500\u2500 file4 \u90fd\u662f\u7a7a\u6587\u4ef6 $ tree ./dir2 ./dir2 \u251c\u2500\u2500 file1 \u251c\u2500\u2500 file2 \u251c\u2500\u2500 file3 \u2514\u2500\u2500 subdir1 \u2514\u2500\u2500 file4 $ diff -ruN /home/vagrant/dir1 /home/vagrant/dir2 > patchdir $ cat patchdir diff -ruN /home/vagrant/dir1/file3 /home/vagrant/dir2/file3 --- /home/vagrant/dir1/file3 2022 -12-07 08 :42:33.108418336 +0800 +++ /home/vagrant/dir2/file3 2022 -12-07 21 :25:48.156056360 +0800 @@ -1 +0,0 @@ -hello diff -ruN /home/vagrant/dir1/subdir1/file4 /home/vagrant/dir2/subdir1/file4 --- /home/vagrant/dir1/subdir1/file4 2022 -12-07 21 :15:09.689912160 +0800 +++ /home/vagrant/dir2/subdir1/file4 2022 -12-07 21 :26:55.405546177 +0800 @@ -1 +0,0 @@ -/home/vagrant/dir1/subdir1 # \u7528dir2\u7684\u5185\u5bb9\u8986\u76d6dir1\u7684\u5185\u5bb9 $ patch -p3 < patchdir patching file dir1/file3 patching file dir1/subdir1/file4 # \u73b0\u5728dir1\u76ee\u5f55\u4e0b\u7684\u5185\u5bb9\u5df2\u7ecf\u88abdir2\u76ee\u5f55\u8986\u76d6\u4e86\u3002file3\u548cfile4\u90fd\u662f\u7a7a\u6587\u4ef6 $ ll ./dir1 total 0 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :34 file1 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :35 file2 -rw-r--r--. 1 vagrant wheel 0 Dec 7 21 :40 file3 drwxr-xr-x. 1 vagrant wheel 10 Dec 7 21 :40 subdir1 $ ll ./dir1/subdir1 total 0 -rw-r--r--. 1 vagrant wheel 0 Dec 7 21 :40 file4 # \u64a4\u9500\u8865\u4e01\uff0cfile3\u548cfile4\u5df2\u7ecf\u6062\u590d\u4e3a\u539f\u6587\u4ef6 $ patch -R -p3 < patchdir patching file dir1/file3 patching file dir1/subdir1/file4 $ ll ./dir1 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :34 file1 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :35 file2 -rw-r--r--. 1 vagrant wheel 6 Dec 7 21 :45 file3 drwxr-xr-x. 1 vagrant wheel 10 Dec 7 21 :45 subdir1 $ ll ./dir1/subdir1 -rw-r--r--. 1 vagrant wheel 27 Dec 7 21 :45 file4 # \u7528dir1\u7684\u5185\u5bb9\u8986\u76d6dir2\u7684\u5185\u5bb9\uff0c\u7cfb\u7edf\u62d2\u7edd\u3002 patch dir2 -p3 < patchdir File dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file dir2.rej File dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file dir2.rej $ patch /home/vagrant/dir2 -p3 < patchdir File /home/vagrant/dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file /home/vagrant/dir2.rej File /home/vagrant/dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file /home/vagrant/dir2.rej 2.14.3. vimdiff \u00b6 \u547d\u4ee4 vimdiff \u76f8\u5f53\u4e8e vim -d \u3002 \u4e3e\u4f8b\uff1a vimdiff text1 text2 2.14.4. cmp \u00b6 \u547d\u4ee4 cmp \u67e5\u770b\u4e8c\u8fdb\u5236\u6587\u4ef6\u7684\u4e0d\u540c\u3002 $ cmp cp grep cp grep differ: byte 25 , line 1 $ cmp /usr/bin/ls /usr/bin/dir /usr/bin/ls /usr/bin/dir differ: byte 613 , line 1 # \u8df3\u8fc7\u524d735\u4e2a\u5b57\u8282\uff0c\u8f93\u51fa\u540e\u976230\u4e2a\u5b57\u8282\u5185\u5bb9 $ hexdump -s 735 -Cn 30 /usr/bin/ls 000002df 00 00 00 00 00 5d 00 00 00 50 00 00 00 68 00 00 | ..... ] ...P...h.. | 000002ef 00 6a 00 00 00 4f 00 00 00 00 00 00 00 1d | .j...O........ | 000002fd $ hexdump -s 735 -Cn 30 /usr/bin/dir 000002df 00 00 00 00 00 5d 00 00 00 50 00 00 00 68 00 00 | ..... ] ...P...h.. | 000002ef 00 6a 00 00 00 4f 00 00 00 00 00 00 00 1d | .j...O........ | 000002fd","title":"\u7b2c\u56db\u7ae0 \u6587\u672c\u7f16\u8f91"},{"location":"linux/SRE/04-TextTools/#_1","text":"","title":"\u7b2c\u56db\u7ae0 \u6587\u672c\u7f16\u8f91"},{"location":"linux/SRE/04-TextTools/#1","text":"","title":"1.\u6587\u672c\u7f16\u8f91\u5668"},{"location":"linux/SRE/04-TextTools/#11vim","text":"vim\u547d\u4ee4\u683c\u5f0f\uff1a +# file : \u6253\u5f00\u6587\u4ef6\u540e\uff0c\u8ba9\u5149\u6807\u5904\u4e8e\u7b2c#\u884c\u9996\uff0c+\u9ed8\u8ba4\u884c\u5c3e +/PATTERN file : \u6253\u5f00\u6587\u4ef6\u6709\uff0c\u8ba9\u5149\u6807\u5904\u4e8e\u7b2c\u4e00\u4e2a\u88abPATTERN\u5339\u914d\u5230\u7684\u884c\u9996 -b file : \u4e8c\u8fdb\u5236\u65b9\u5f0f\u6253\u5f00\u6587\u4ef6 -d file1 file2 ... : \u6bd4\u8f83\u591a\u4e2a\u6587\u4ef6\uff0c\u76f8\u5f53\u4e8e vimdiff -m file : \u53ea\u8bfb\u65b9\u5f0f\u6253\u5f00\u6587\u4ef6 -e file : \u8fdb\u5165ex\u6a21\u5f0f\uff0c\u76f8\u5f53\u4e8e ex file -y file : vim\u4e09\u79cd\u5e38\u89c1\u6a21\u5f0f\uff1a \u666e\u901a\u6a21\u5f0fNormal\u6216\u547d\u4ee4\u6a21\u5f0f \u63d2\u5165Insert\u6216\u7f16\u8f91\u6a21\u5f0f \u6269\u5c55\u547d\u4ee4\u6a21\u5f0fExtended Command \u4e09\u79cd\u6a21\u5f0f\u5207\u6362 \u547d\u4ee4\u6a21\u5f0f\u2192\u63d2\u5165\u6a21\u5f0f i\uff1ainsert\uff0c\u5728\u5149\u6807\u5904\u8f93\u5165 I\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u9996\u8f93\u5165 a\uff1aappend\uff0c\u5728\u5149\u6807\u5904\u540e\u9762\u8f93\u5165 A\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u5c3e\u8f93\u5165 o\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u7684\u4e0b\u65b9\u6253\u5f00\u4e00\u4e2a\u65b0\u884c O\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u7684\u4e0a\u65b9\u6253\u5f00\u4e00\u4e2a\u65b0\u884c \u63d2\u5165\u6a21\u5f0f\u2192 ESC \u2192 \u547d\u4ee4\u6a21\u5f0f \u547d\u4ee4\u6a21\u5f0f\u2192 : \u2192 \u6269\u5c55\u547d\u4ee4\u6a21\u5f0f \u6269\u5c55\u547d\u4ee4\u6a21\u5f0f\u2192 ESC, enter \u2192 \u547d\u4ee4\u6a21\u5f0f \u6269\u5c55\u547d\u4ee4\u6a21\u5f0f\u5e38\u7528\u547d\u4ee4\uff1a :wq : \u4fdd\u5b58\u6587\u4ef6\u5e76\u9000\u51fa :w : \u4fdd\u5b58\u6587\u4ef6 :w filename : \u5199\u5165\u6307\u5b9a\u6587\u4ef6\uff0c\u76f8\u5f53\u4e8e\u53e6\u5b58\u4e3a :q! : \u653e\u5f03\u4efb\u4f55\u4fee\u6539\u5e76\u9000\u51fa ZQ : \u65e0\u6761\u4ef6\u9000\u51fa :join : \u5408\u5e76\u591a\u884c J : \u5408\u5e76\u4e24\u884c \u8bbe\u7f6e\uff1a\uff08\u53ef\u4ee5\u5728 /etc/vimrc \u6587\u4ef6\u4e2d\u914d\u7f6e\uff09 :set textwidth : \u8bbe\u7f6e\u6587\u672c\u5bbd\u5ea6\uff08\u4ece\u5de6\u5411\u53f3\u8ba1\u6570\uff09 :set wrapmargin=# : \u8bbe\u7f6e\u884c\u8fb9\u8ddd\uff08\u4ece\u53f3\u5411\u5de6\u8ba1\u6570\uff09 :set endofline : \u8bbe\u7f6e\u6587\u4ef6\u7ed3\u675f\u7b26 :set noendofline : \u53d6\u6d88\u6587\u4ef6\u7ed3\u675f\u7b26 :set wrap : \u81ea\u52a8\u6362\u884c :set nowrap : \u53d6\u6d88\u81ea\u52a8\u6362\u884c :set number : \u663e\u793a\u884c\u53f7 :set nonumber : \u53d6\u6d88\u663e\u793a\u884c\u53f7 :set list : \u8fdb\u5165List Mode\uff0c\u663e\u793aTab ^I\uff0c\u6362\u884c\u7b26\uff0c\u548c$\u663e\u793a :set nolist : \u9000\u51faList Mode :set ignorecase : \u5ffd\u7565\u5b57\u7b26\u7684\u5927\u5c0f\u5199 :set noic : \u4e0d\u5ffd\u7565\u5b57\u7b26\u5927\u5c0f\u5199 :set autoindent : \u542f\u7528\u81ea\u52a8\u7f29\u8fdb :set noai : \u5173\u95ed\u81ea\u52a8\u7f29\u8fdb :set hlsearch : \u542f\u7528\u9ad8\u4eae\u641c\u7d22 :set nohlsearch : \u5173\u95ed\u9ad8\u4eae\u641c\u7d22 :set fileformat=dos : \u542f\u7528windows\u683c\u5f0f :set fileformat=unix : \u542f\u7528unix\u683c\u5f0f :set expandtab : \u542f\u7528\u7a7a\u683c\u4ee3\u66ffTAB\uff0c\u9ed8\u8ba48\u4e2a\u7a7a\u683c\u4ee3\u66ff\u4e00\u4e2aTAB :set noexpandtab : \u5173\u95ed\u7a7a\u683c\u4ee3\u66ffTAB :set tabstop=# : \u6307\u5b9a#\u4e2a\u7a7a\u683c\u4ee3\u66ff\u4e00\u4e2aTAB :set shiftwidth=# : \u8bbe\u7f6e#\u4e2a\u7f29\u8fdb\u5bbd\u5ea6 :set cursorline : \u8bbe\u7f6e\u5149\u6807\u6240\u5728\u884c\u7684\u8868\u793a\u7ebf :set cursorline : \u5173\u95ed\u5149\u6807\u6240\u5728\u884c\u7684\u8868\u793a\u7ebf :set key=PASSWORD : \u542f\u7528\u5bc6\u7801\u4fdd\u62a4 :set key= : \u5173\u95ed\u5bc6\u7801\u4fdd\u62a4 :help option-list : \u83b7\u53d6\u5e2e\u52a9 \u67e5\u627e /pattern : \u4ece\u5149\u6807\u5f00\u59cb\u5904\u5411\u6587\u4ef6\u5c3e\u641c\u7d22pattern ?pattern : \u4ece\u5149\u6807\u5f00\u59cb\u5904\u5411\u6587\u4ef6\u9996\u641c\u7d22pattern n : \u5728\u540c\u4e00\u65b9\u5411\u91cd\u590d\u4e0a\u4e00\u6b21\u641c\u7d22\u547d\u4ee4 N : \u5728\u53cd\u65b9\u5411\u4e0a\u91cd\u590d\u4e0a\u4e00\u6b21\u641c\u7d22\u547d\u4ee4 # : \u5411\u4e0a\u5b8c\u6574\u5339\u914d\u5149\u6807\u4e0b\u7684\u5355\u8bcd, \u76f8\u5f53\u4e8e\uff1fword * : \u5411\u4e0b\u5b8c\u6574\u5339\u914d\u5149\u6807\u4e0b\u7684\u5355\u8bcd, \u76f8\u5f53\u4e8e/word % : \u67e5\u627e\u5bf9\u5e94\u7684( [ {\u5339\u914d nfx : \u5728\u5f53\u524d\u884c\u67e5\u627e\u5149\u6807\u540e\u7b2cn\u4e2ax\uff08\u4e00\u822c\u76f4\u63a5fx\uff09 \u66ff\u6362 :%s/\\n//g : \u5220\u9664\u6362\u884c\u7b26 :s/p1/p2/g : \u5c06\u5f53\u524d\u884c\u4e2d\u6240\u6709p1\u5747\u7528p2\u66ff\u4ee3, \u65e0g\uff0c\u5219\u53ea\u66ff\u6362\u7b2c\u4e00\u4e2a :s/p1/p2/c : \u67e5\u627e\u66ff\u6362\u8981\u6c42\u786e\u8ba4 :n1,n2s/p1/p2/g : \u5c06\u7b2cn1\u81f3n2\u884c\u4e2d\u6240\u6709p1\u5747\u7528p2\u66ff\u4ee3 :%s/p1/p2/g : \u5168\u5c40\uff0c\u4f7f\u7528p2\u66ff\u6362p1 :%s/p1/p2/gc : \u66ff\u6362\u524d\u8be2\u95ee :n,$s/vivian/sky/ : \u66ff\u6362\u7b2cn\u884c\u5f00\u59cb\u5230\u6700\u540e\u4e00\u884c\u4e2d\u6bcf\u4e00\u884c\u7684\u7b2c\u4e00\u4e2avivian\u4e3asky\uff0cn\u4e3a\u6570\u5b57 :.,$s/vivian/sky/g : \u66ff\u6362\u5f53\u524d\u884c\u5f00\u59cb\u5230\u6700\u540e\u4e00\u884c\u4e2d\u6bcf\u4e00\u884c\u6240\u6709vivian\u4e3asky :s/vivian\\//sky\\// : \u66ff\u6362\u5f53\u524d\u884c\u7b2c\u4e00\u4e2avivian/\u4e3asky/\uff0c\u53ef\u4ee5\u4f7f\u7528\\\u4f5c\u4e3a\u8f6c\u4e49\u7b26 :1,$s/^/some string/ : \u5728\u6587\u4ef6\u7684\u7b2c\u4e00\u884c\u81f3\u6700\u540e\u4e00\u884c\u7684\u884c\u9996\u524d\u63d2\u5165some string :%s/$/some string/g : \u5728\u6574\u4e2a\u6587\u4ef6\u6bcf\u4e00\u884c\u7684\u884c\u5c3e\u6dfb\u52a0some string :%s/\\s\\+$// : \u53bb\u6389\u6240\u6709\u7684\u884c\u5c3e\u7a7a\u683c\uff0c\u201c\\s\u201d\u8868\u793a\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u548c\u5236\u8868\u7b26\uff09\uff0c\u201c+\u201d\u5bf9\u524d\u9762\u7684\u5b57\u7b26\u5339\u914d\u4e00\u6b21\u6216\u591a\u6b21\uff08\u8d8a\u591a\u8d8a\u597d\uff09\uff0c\u201c \\(\u201d\u5339\u914d\u884c\u5c3e\uff08\u4f7f\u7528\u201c\\$\u201d\u8868\u793a\u5355\u7eaf\u7684\u201c\\) \u201d\u5b57\u7b26\uff09 :%s/\\s\u2217\\n\\+/\\r/ : \u53bb\u6389\u6240\u6709\u7684\u7a7a\u767d\u884c\uff0c\u201c \\(\u201d\u548c\u201c\\) \u201d\u5bf9\u8868\u8fbe\u5f0f\u8fdb\u884c\u5206\u7ec4\uff0c\u4f7f\u5176\u88ab\u89c6\u4f5c\u4e00\u4e2a\u4e0d\u53ef\u5206\u5272\u7684\u6574\u4f53 :%s!\\s*//.*!! : \u53bb\u6389\u6240\u6709\u7684\u201c//\u201d\u6ce8\u91ca :%s!\\s*/\\*\\_.\\{-}\\*/\\s*!!g : \u53bb\u6389\u6240\u6709\u7684\u201c/**/\u201d\u6ce8\u91ca :%s= *$== : \u5c06\u6240\u6709\u884c\u5c3e\u591a\u4f59\u7684\u7a7a\u683c\u5220\u9664 :g/^\\s*$/d : \u5c06\u6240\u6709\u4e0d\u5305\u542b\u5b57\u7b26(\u7a7a\u683c\u4e5f\u4e0d\u5305\u542b)\u7684\u7a7a\u884c\u5220\u9664 r : \u66ff\u6362\u5f53\u524d\u5b57\u7b26 R : \u66ff\u6362\u5f53\u524d\u5b57\u7b26\u53ca\u5176\u540e\u7684\u5b57\u7b26\uff0c\u76f4\u81f3\u6309ESC\u952e \u7f16\u8f91 h : \u5149\u6807\u5de6\u79fb\u4e00\u4e2a\u5b57\u7b26[\u56de\u9000\u952eBackspace] l : \u5149\u6807\u53f3\u79fb\u4e00\u4e2a\u5b57\u7b26[\u7a7a\u683c\u952eSpace] K : \u5149\u6807\u4e0a\u79fb\u4e00\u884c j : \u5149\u6807\u4e0b\u79fb\u4e00\u884c w : \u5149\u6807\u8df3\u5230\u4e0b\u4e2aword\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd(\u5305\u62ec\u6807\u70b9\u7b26\u53f7) [\u5e38\u7528] W : \u79fb\u5230\u4e0b\u4e00\u4e2a\u5b57\u7684\u5f00\u5934\uff0c\u5ffd\u7565\u6807\u70b9\u7b26\u53f7 B : \u5149\u6807\u56de\u5230\u4e0a\u4e2aword\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd B : \u79fb\u5230\u524d\u4e00\u4e2a\u5b57\u7684\u5f00\u5934\uff0c\u5ffd\u7565\u6807\u70b9\u7b26\u53f7 BACK E : \u5149\u6807\u8df3\u5230\u4e0b\u4e2aword\u7684\u6700\u540e\u4e00\u4e2a\u5b57\u6bcd E : \u79fb\u5230\u4e0b\u4e00\u4e2a\u5b57\u7684\u7ed3\u5c3e\uff0c\u5ffd\u7565\u6807\u70b9\u7b26\u53f7 END 0 : \u79fb\u5230\u5f53\u524d\u4e00\u884c\u7684\u5f00\u59cb[Home] $ : \u79fb\u5230\u5f53\u524d\u4e00\u884c\u7684\u6700\u540e[End] ^ : \u547d\u4ee4\u5c06\u5149\u6807\u79fb\u52a8\u5230\u5f53\u524d\u884c\u7684\u7b2c\u4e00\u4e2a\u975e\u7a7a\u767d\u5b57\u7b26\u4e0a g_ : \u5230\u672c\u884c\u6700\u540e\u4e00\u4e2a\u4e0d\u662fblank\u5b57\u7b26\u7684\u4f4d\u7f6e Enter : \u5149\u6807\u4e0b\u79fb\u4e00\u884c n+ : \u5149\u6807\u4e0b\u79fbn\u884c\u3010\u6309\u4e0a\u6863\u952e \u6570\u5b57shift +\u3011 n- : \u5149\u6807\u4e0a\u79fbn\u884c G : \u79fb\u5230\u6587\u4ef6\u7684\u6700\u540e\u4e00\u884c nG \u6216\u8005 :n : \u79fb\u5230\u6587\u4ef6\u7684\u7b2cn\u884c\ue5e5\ue5e5\ue5e5 gg : \u79fb\u52a8\u5230\u6587\u6863\u7684\u5f00\u59cb [[ : \u6587\u4ef6\u5f00\u59cb\u4f4d\u7f6e\u2014\u2014\u5f00\u59cb\u884c ]] : \u6587\u4ef6\u7ed3\u675f\u4f4d\u7f6e\u2014\u2014\u672b\u5c3e\u884c H : \u5149\u6807\u79fb\u81f3\u5c4f\u5e55\u9876\u884cHEAD\u3002\u5149\u6807\u5b9a\u4f4d\u5728\u663e\u793a\u5c4f\u7684\u7b2c\u4e00\u884c M : \u79fb\u5230\u5c4f\u5e55\u7684\u4e2d\u95f4\u884c\u5f00\u5934 Middle\u3002\u5149\u6807\u5b9a\u4f4d\u5728\u663e\u793a\u5c4f\u7684\u4e2d\u95f4 L : \u79fb\u5230\u5c4f\u5e55\u7684\u6700\u540e\u4e00\u884cLAST\u3002\u5149\u6807\u5b9a\u4f4d\u5728\u663e\u793a\u5c4f\u7684\u6700\u540e\u4e00\u884c ( : \u5149\u6807\u79fb\u81f3\u53e5\u9996 ) : \u5149\u6807\u79fb\u81f3\u53e5\u5c3e { : \u79fb\u5230\u6bb5\u843d\u7684\u5f00\u5934 } : \u79fb\u5230\u4e0b\u4e00\u4e2a\u6bb5\u843d\u7684\u5f00\u5934 % : \u5339\u914d\u62ec\u53f7\u79fb\u52a8\uff0c\u5305\u62ec (, {, [.\uff08\u9700\u8981\u628a\u5149\u6807\u5148\u79fb\u5230\u62ec\u53f7\u4e0a\uff09\u8df3\u8f6c\u5230\u4e0e\u4e4b\u5339\u914d\u7684\u62ec\u53f7\u5904 * \u548c # : \u5339\u914d\u5149\u6807\u5f53\u524d\u6240\u5728\u7684\u5355\u8bcd\uff0c\u79fb\u52a8\u5149\u6807\u5230\u4e0b\u4e00\u4e2a\uff08\u6216\u4e0a\u4e00\u4e2a\uff09\u5339\u914d\u5355\u8bcd\uff08*\u662f\u4e0b\u4e00\u4e2a\uff0c#\u662f\u4e0a\u4e00\u4e2a\uff09 zf : \u6298\u53e0\uff08\u9700\u52a0\u65b9\u5411\u952e\uff09 zo : \u5c55\u5f00\uff08\u7a7a\u683c\u4e5f\u53ef\u4ee5\u5c55\u5f00\uff09 CTRL+u : \u5411\u6587\u4ef6\u9996\u7ffb\u534a\u5c4fup CTRL+d : \u5411\u6587\u4ef6\u5c3e\u7ffb\u534a\u5c4fdown CTRL+f : \u5411\u6587\u4ef6\u5c3e\u7ffb\u4e00\u5c4f forward (fact\u6574\u5c4f\u53bb\u4e24\u884c) CTRL+b : \u5411\u6587\u4ef6\u9996\u7ffb\u4e00\u5c4fback (fact\u6574\u5c4f\u53bb\u4e24\u884c) CTRL-] : \u8df3\u8f6c\u5230\u5f53\u524d\u5149\u6807\u6240\u5728\u5355\u8bcd\u5bf9\u5e94\u7684\u4e3b\u9898 CTRL-O : \u56de\u5230\u524d\u4e00\u4e2a\u4f4d\u7f6e SHIFT+V : \u9009\u62e9\u6574\u884c zz : \u547d\u4ee4\u4f1a\u628a\u5f53\u524d\u884c\u7f6e\u4e3a\u5c4f\u5e55\u6b63\u4e2d\u592e(z\u5b57\u53d6\u5176\u8c61\u5f62\u610f\u4e49\u6a21\u62df\u4e00\u5f20\u7eb8\u7684\u6298\u53e0\u53ca\u53d8\u5f62\u4f4d\u7f6e\u91cd\u7f6e) zt : \u547d\u4ee4\u4f1a\u628a\u5f53\u524d\u884c\u7f6e\u4e8e\u5c4f\u5e55\u9876\u7aef(top) zb : \u547d\u4ee4\u4f1a\u628a\u5f53\u524d\u884c\u7f6e\u4e8e\u5c4f\u5e55\u5e95\u7aef(bottom) 50% : \u5149\u6807\u5b9a\u4f4d\u5728\u6587\u4ef6\u7684\u4e2d\u95f4 ` : \u8df3\u8f6c\u5230\u6700\u8fd1\u5149\u6807\u5b9a\u4f4d\u7684\u4f4d\u7f6e\uff08\u53ea\u80fd\u8bb0\u5fc6\u6700\u8fd1\u4e24\u4e2a\u4f4d\u7f6e\uff09 \u53cd\u5f15\u53f7 I : \u5728\u5149\u6807\u524d\u5f00\u59cb\u63d2\u5165\u5b57\u7b26 insert I : \u5728\u5f53\u524d\u884c\u9996\u5f00\u59cb\u63d2\u5165\u5b57\u7b26 A : \u5728\u5149\u6807\u4f4d\u7f6e\u540e\u5f00\u59cb\u52a0\u5b57 append A : \u5728\u5149\u6807\u6240\u5728\u884c\u7684\u6700\u540e\u9762\u5f00\u59cb\u52a0\u5b57 O : \u5728\u5149\u6807\u4e0b\u52a0\u4e00\u7a7a\u767d\u884c\u5e76\u5f00\u59cb\u52a0\u5b57 open O : \u5728\u5149\u6807\u4e0a\u52a0\u4e00\u7a7a\u767d\u884c\u5e76\u5f00\u59cb\u52a0\u5b57 R : \u66ff\u6362\u5f53\u524d\u5b57\u7b26 R : \u66ff\u6362\u5f53\u524d\u5b57\u7b26\u53ca\u5176\u540e\u7684\u5b57\u7b26\u3010\u5f53\u524d\u53ca\u5176\u540e\u5b57\u7b26\u88ab\u8986\u76d6\u3011 S : \u9ed8\u8ba4\u5220\u9664\u5149\u6807\u6240\u5728\u5b57\u7b26\uff0c\u8f93\u5165\u5185\u5bb9\u63d2\u5165\u4e4b= xi S : \u9ed8\u8ba4\u5220\u9664\u5f53\u524d\u884c\u5185\u5bb9\uff0c\u8f93\u5165\u5185\u5bb9\u4f5c\u4e3a\u5f53\u524d\u884c\u65b0\u5185\u5bb9= dd+o nx : \u5220\u9664\u7531\u5149\u6807\u4f4d\u7f6e\u8d77\u59cb\u540e\u7684n\u4e2a\u5b57\u7b26\uff08\u542b\u5149\u6807\u4f4d\u7f6e\uff09x =dl(\u5220\u9664\u5f53\u524d\u5149\u6807\u4e0b\u7684\u5b57\u7b26) nX : \u5220\u9664\u7531\u5149\u6807\u4f4d\u7f6e\u8d77\u59cb\u524d\u7684n\u4e2a\u5b57\u7b26\uff08\u542b\u5149\u6807\u4f4d\u7f6e\uff09X =dh(\u5220\u9664\u5f53\u524d\u5149\u6807\u5de6\u8fb9\u7684\u5b57\u7b26) d0 : \u5220\u81f3\u884c\u9996 d$ : \u5220\u81f3\u884c\u5c3e dfa : \u8868\u793a\u5220\u9664\u4ece\u5f53\u524d\u5149\u6807\u5230\u5149\u6807\u540e\u9762\u7684\u7b2c\u4e00\u4e2aa\u5b57\u7b26\u4e4b\u95f4\u7684\u5185\u5bb9 D : \u4ee3\u8868d$(\u5220\u9664\u5230\u884c\u5c3e\u7684\u5185\u5bb9) C : \u4ee3\u8868c$(\u4fee\u6539\u5230\u884c\u5c3e\u7684\u5185\u5bb9) ndw : \u5220\u9664\u5149\u6807\u5904\u5f00\u59cb\u53ca\u5176\u540e\u7684n-1\u4e2a\u5b57 ndb : \u5220\u9664\u5149\u6807\u5904\u5f00\u59cb\u53ca\u5176\u524d\u7684n-1\u4e2a\u5b57 diw : \u5220\u9664\u5f53\u524d\u5149\u6807\u6240\u5728\u7684word(\u4e0d\u5305\u62ec\u7a7a\u767d\u5b57\u7b26)\uff0c\u610f\u4e3aDelete Inner Word \u4e24\u4e2a\u7b26\u53f7\u4e4b\u95f4\u7684\u5355\u8bcd daw : \u5220\u9664\u5f53\u524d\u5149\u6807\u6240\u5728\u7684word(\u5305\u62ec\u7a7a\u767d\u5b57\u7b26)\uff0c\u610f\u4e3aDelete A Word ndd : \u5220\u9664\u5f53\u524d\u884c\u53ca\u5176\u540en-1\u884c :n1,n2 d : \u5c06 n1\u884c\u5230n2\u884c\u4e4b\u95f4\u7684\u5185\u5bb9\u5220\u9664 dG : \u5220\u9664\u5f53\u524d\u884c\u81f3\u6587\u4ef6\u5c3e\u7684\u5185\u5bb9 Dgg : \u5220\u9664\u5f53\u524d\u884c\u81f3\u6587\u4ef6\u5934\u7684\u5185\u5bb9 d+enter : \u5220\u96642\u884c\u3010\u5305\u62ec\u5149\u6807\u4e00\u884c\u3011 cw : \u5220\u9664\u5f53\u524d\u5b57\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f\u3010\u5f88\u597d\u7528\uff0c\u5feb\u901f\u66f4\u6539\u4e00\u4e2a\u5355\u8bcd\u3011\u76f8\u5f53\u4e8edw+i ncw : \u5220\u9664\u5f53\u524d\u5b57\u53ca\u5176\u540e\u7684n-1\u4e2a\u5b57\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f\\\u4fee\u6539\u6307\u5b9a\u6570\u76ee\u7684\u5b57 cc : \u5220\u9664\u5f53\u524d\u884c\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f ncc : \u5220\u9664\u5f53\u524d\u884c\u53ca\u5176\u540e\u7684n-1\u884c\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f guw : \u5149\u6807\u4e0b\u7684\u5355\u8bcd\u53d8\u4e3a\u5c0f\u5199 gUw : \u5149\u6807\u4e0b\u7684\u5355\u8bcd\u53d8\u4e3a\u5927\u5199 xp : \u5de6\u53f3\u4ea4\u6362\u5149\u6807\u5904\u4e24\u5b57\u7b26\u7684\u4f4d\u7f6e ga : \u663e\u793a\u5149\u6807\u4e0b\u7684\u5b57\u7b26\u5728\u5f53\u524d\u4f7f\u7528\u7684encoding\u4e0b\u7684\u5185\u7801 nyl : \u590d\u5236n\u4e2a\u5b57\u7b26(\u4e5f\u53efnyh) yw : \u590d\u5236\u4e00\u4e2a\u5355\u8bcd y0 : \u8868\u793a\u62f7\u8d1d\u4ece\u5f53\u524d\u5149\u6807\u5230\u5149\u6807\u6240\u5728\u884c\u9996\u7684\u5185\u5bb9 y$ : \u590d\u5236\u4ece\u5f53\u524d\u4f4d\u7f6e\u5230\u884c\u5c3e yfa : \u8868\u793a\u62f7\u8d1d\u4ece\u5f53\u524d\u5149\u6807\u5230\u5149\u6807\u540e\u9762\u7684\u7b2c\u4e00\u4e2aa\u5b57\u7b26\u4e4b\u95f4\u7684\u5185\u5bb9 yG : \u590d\u5236\u4ece\u6240\u5728\u884c\u5230\u6700\u540e\u4e00\u884c nyy : \u5c06\u5149\u6807\u6240\u5728\u4f4d\u7f6e\u5f00\u59cb\u7684n\u884c\u6570\u636e\u590d\u5236\u6682\u5b58, \u590d\u5236\u4e00\u6574\u884c CTRL+v \u65b9\u5411y : \u5217\u9009\u62e9\u6a21\u5f0f\uff0c\u590d\u5236\u9009\u62e9\u7684\u5f88\u591a\u884c\uff1a\u5148\u4f7f\u7528V\u8fdb\u5165visual\u6a21\u5f0f\uff0c\u7136\u540ej\u5411\u4e0b\u79fb\u52a8\u5230\u4f60\u60f3\u590d\u5236\u7684\u884c\u4e3a\u6b62\uff0c\u7136\u540ey p : \u590d\u5236\u6682\u5b58\u6570\u636e\u5728\u5149\u6807\u7684\u4e0b\u4e00\u884c P : \u590d\u5236\u6682\u5b58\u6570\u636e\u5728\u5149\u6807\u7684\u4e0a\u4e00\u884c :n1,n2 co n3 : \u5c06n1\u884c\u5230n2\u884c\u4e4b\u95f4\u7684\u5185\u5bb9\u62f7\u8d1d\u5230\u7b2cn3+1\u884c\u3010n3\u884c\u7684\u4e0b\u4e00\u884c\u3011 :n1,n2 m n3 : \u5c06n1\u884c\u5230n2\u884c\u4e4b\u95f4\u7684\u5185\u5bb9\u79fb\u81f3\u5230\u7b2cn3\u884c\u4e0b J : \u628a\u4e0b\u4e00\u884c\u7684\u6570\u636e\u8fde\u63a5\u5230\u672c\u884c\u4e4b\u540e, \u591a\u4e00\u7a7a\u683c ~ : \u6539\u53d8\u5f53\u524d\u5149\u6807\u4e0b\u5b57\u7b26\u7684\u5927\u5c0f\u5199 \u5176\u4ed6 . : \u91cd\u590d\u524d\u4e00\u6307\u4ee4 u : \u53d6\u6d88\u524d\u4e00\u6307\u4ee4undo, :u\u4e5f\u884c\uff0c\u4e00\u822c\u4e0d\u7528\uff0c\u64cd\u4f5c\u592a\u591a Ctrl + r : \u6062\u590d\u3010\u53ea\u5bf9u\u6709\u6548\u3011redo Ctrl + l : \u5237\u65b0\u5c4f\u5e55\u663e\u793a Ctrl+v \u7136\u540e ctrl+A\u662f^A Ctrl+I\u662f\\t : \u8f93\u5165\u7279\u6b8a\u5b57\u7b26 Ctrl+v\u7136\u540e\u7528j\u3001k\u3001l\u3001h\u6216\u65b9\u5411\u952e\u4e0a\u4e0b\u9009\u4e2d\u591a\u5217\uff0c\u4e4b\u540e I I a A r x\u7b49\uff0c\u6700\u540e\u6309esc\uff0c\u751f\u6548 : Vim\u5217\u64cd\u4f5c","title":"1.1.vim\u5de5\u5177"},{"location":"linux/SRE/04-TextTools/#2","text":"","title":"2.\u6587\u672c\u5904\u7406\u5de5\u5177"},{"location":"linux/SRE/04-TextTools/#21cat","text":"\u547d\u4ee4 cat \u4e3b\u8981\u53c2\u6570\u8bf4\u660e\uff1a -E \uff1a\u663e\u793a\u884c\u7ed3\u675f\u7b26 $ -A \uff1a\u663e\u793a\u6240\u6709\u63a7\u5236\u7b26 -n \uff1a\u5bf9\u663e\u793a\u51fa\u7684\u6bcf\u4e00\u884c\u8fdb\u884c\u7f16\u53f7 -b \uff1a\u975e\u7a7a\u884c\u7f16\u53f7 -s \uff1a\u538b\u7f29\u8fde\u7eed\u7684\u7a7a\u884c\u6210\u4e00\u884c \u4e3e\u4f8b\uff1a cat -nA user-list.txt 1 user0$ 2 user1$ 3 user2$ 4 user3$ 5 user4$ 6 user5$ 7 user6$ 8 user7$ 9 user8$ 10 user9$","title":"2.1.\u663e\u793a\u6587\u672c\u5185\u5bb9cat"},{"location":"linux/SRE/04-TextTools/#22nl","text":"\u76f8\u5f53\u4e8e\u547d\u4ee4 cat -b \u3002 \u547d\u4ee4 nl \u4e3b\u8981\u53c2\u6570\u8bf4\u660e\uff1a -b \uff1a\u6307\u5b9a\u884c\u53f7\u6307\u5b9a\u7684\u65b9\u5f0f\uff0c\u4e3b\u8981\u6709\u4e24\u79cd\uff1a -b a \uff1a\u8868\u793a\u4e0d\u8bba\u662f\u5426\u4e3a\u7a7a\u884c\uff0c\u4e5f\u540c\u6837\u5217\u51fa\u884c\u53f7\uff08\u7c7b\u4f3c cat -n\uff09\uff1b -b t \uff1a\u5982\u679c\u6709\u7a7a\u884c\uff0c\u7a7a\u7684\u90a3\u4e00\u884c\u4e0d\u8981\u5217\u51fa\u884c\u53f7\uff08\u9ed8\u8ba4\u503c\uff09\uff1b -n \uff1a\u5217\u51fa\u884c\u53f7\u8868\u793a\u7684\u65b9\u6cd5\uff0c\u4e3b\u8981\u6709\u4e09\u79cd\uff1a -n ln \uff1a\u884c\u53f7\u5728\u5c4f\u5e55\u7684\u6700\u5de6\u65b9\u663e\u793a\uff1b\u6ca1\u6709\u524d\u5bfc0\uff1b -n rn \uff1a\u884c\u53f7\u5728\u81ea\u5df1\u680f\u4f4d\u7684\u6700\u53f3\u65b9\u663e\u793a\uff0c\u6ca1\u6709\u524d\u5bfc0\uff1b -n rz \uff1a\u884c\u53f7\u5728\u81ea\u5df1\u680f\u4f4d\u7684\u6700\u53f3\u65b9\u663e\u793a\uff0c\u6709\u524d\u5bfc0\uff1b -w \uff1a\u884c\u53f7\u680f\u4f4d\u7684\u5360\u7528\u7684\u4f4d\u6570\u3002 -p \uff1a\u5728\u903b\u8f91\u5b9a\u754c\u7b26\u5904\u4e0d\u91cd\u65b0\u5f00\u59cb\u8ba1 \u4e3e\u4f8b\uff1a $ nl -b a -n rz user-list.txt 000001 user0 000002 user1 000003 user2 000004 user3 000005 user4 000006 user5 000007 user6 000008 user7 000009 user8 000010 user9","title":"2.2.\u663e\u793a\u6587\u672c\u884c\u53f7nl"},{"location":"linux/SRE/04-TextTools/#23tac","text":"\u547d\u4ee4 tac \u9006\u5411\u663e\u793a\u6587\u672c\u5185\u5bb9\u3002 \u4e3e\u4f8b\uff1a $ tac user-list.txt user9 user8 user7 user6 user5 user4 user3 user2 user1 user0 \u4e3e\u4f8b\uff1a $ seq 10 | tac 10 9 8 7 6 5 4 3 2 1","title":"2.3.\u9006\u5411\u663e\u793a\u6587\u672c\u5185\u5bb9tac"},{"location":"linux/SRE/04-TextTools/#24rev","text":"\u547d\u4ee4 rev \u9006\u5411\u663e\u793a\u540c\u4e00\u884c\u7684\u5185\u5bb9\u3002 \u4e3e\u4f8b\uff1a $ rev user-list.txt 0resu 1resu 2resu 3resu 4resu 5resu 6resu 7resu 8resu 9resu \u4e3e\u4f8b\uff1a $ echo { 1 ..10 } | rev 01 9 8 7 6 5 4 3 2 1","title":"2.4.\u9006\u5411\u663e\u793a\u540c\u884c\u5185\u5bb9rev"},{"location":"linux/SRE/04-TextTools/#25hexdump","text":"\u547d\u4ee4 hexdump \u547d\u4ee4\u4e00\u822c\u7528\u6765\u67e5\u770b\u201c\u4e8c\u8fdb\u5236\u201d\u6587\u4ef6\u7684\u5341\u516d\u8fdb\u5236\u7f16\u7801 \u4e3e\u4f8b\uff1a $ hexdump -C -n 32 cp 00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 | .ELF............ | 00000010 03 00 3e 00 01 00 00 00 e0 48 00 00 00 00 00 00 | ..>......H...... | 00000020","title":"2.5.\u663e\u793a\u975e\u6587\u672c\u6587\u4ef6\u5185\u5bb9hexdump"},{"location":"linux/SRE/04-TextTools/#26","text":"\u547d\u4ee4 more \u548c less \u53ef\u4ee5\u5b9e\u73b0\u5206\u9875\u67e5\u770b\u6587\u4ef6\u5185\u5bb9\u3002 \u547d\u4ee4 less \u914d\u5408\u7ba1\u9053\u7b26\u4f7f\u7528\u3002 tree -d /etc | less","title":"2.6.\u5206\u9875\u67e5\u770b\u6587\u4ef6\u5185\u5bb9"},{"location":"linux/SRE/04-TextTools/#27head","text":"\u547d\u4ee4 head \u663e\u793a\u6587\u4ef6\u5934\u90e8\u5185\u5bb9\u3002 head -c 20 cp : \u663e\u793a\u6587\u4ef6\u524d20\u5b57\u8282\u5185\u5bb9 head -n 20 zdiff : \u663e\u793a\u6587\u4ef6\u524d20\u884c\u5185\u5bb9 head -20 zdiff : \u663e\u793a\u6587\u4ef6\u524d20\u884c\u5185\u5bb9 $ echo \"\u6211\u662f\u8c01\" | head -c3 \u6211 $ echo \"\u6211\u662f\u8c01\" | head -c6 \u6211\u662f cat /dev/urandom | tr -dc '[:alnum]' | head -c 10 | tee passwd.txt $ cat user-list.txt user0 user1 user2 user3 user4 user5 user6 user7 user8 user9 $ head -n -3 user-list.txt user0 user1 user2 user3 user4 user5 user6","title":"2.7.\u663e\u793a\u6587\u4ef6\u5934\u90e8\u5185\u5bb9head"},{"location":"linux/SRE/04-TextTools/#28tail","text":"\u547d\u4ee4 tail \u663e\u793a\u6587\u4ef6\u5934\u90e8\u5185\u5bb9\u3002 tail -c 200 cp : \u663e\u793a\u6587\u4ef6\u5c3e\u90e8200\u4e2a\u5b57\u8282\u7684\u5185\u5bb9 tail -n 3 user-list.txt : \u663e\u793a\u6587\u4ef6\u6700\u540e3\u884c tail -n -3 user-list.txt : \u663e\u793a\u4ece-3\u884c\u5230\u6587\u4ef6\u7ed3\u675f\uff08\u5373\u6700\u540e\u4e09\u884c\uff09 tail -3 user-list.txt : \u663e\u793a\u6587\u4ef6\u6700\u540e3\u884c tail -f /var/log/messages : \u8ddf\u8e2a\u663e\u793a\u6587\u4ef6redo.log\u6587\u4ef6\u5185\u5bb9\uff0c\u5f53\u6587\u4ef6\u5220\u9664\uff0c\u518d\u5efa\u540c\u540d\u6587\u4ef6\uff0c\u65e0\u6cd5\u7ee7\u7eed\u8ffd\u8e2a tail -F /var/log/messages : \u8ddf\u8e2a\u663e\u793a\u6587\u4ef6redo.log\u6587\u4ef6\u5185\u5bb9\uff0c\u5f53\u6587\u4ef6\u5220\u9664\uff0c\u518d\u5efa\u540c\u540d\u6587\u4ef6\uff0c\u7ee7\u7eed\u8ffd\u8e2a","title":"2.8.\u663e\u793a\u6587\u4ef6\u5c3e\u90e8\u5185\u5bb9tail"},{"location":"linux/SRE/04-TextTools/#29cut","text":"\u547d\u4ee4 cut \u53ef\u4ee5\u63d0\u53d6\u6587\u672c\u6587\u4ef6\u6216\u8005stdin\u6570\u636e\u7684\u6307\u5b9a\u5217\u5185\u5bb9\u3002 \u9009\u9879\uff1a -f : \u901a\u8fc7\u6307\u5b9a\u54ea\u4e00\u4e2a\u5b57\u6bb5\u8fdb\u884c\u63d0\u53d6\u3002cut\u547d\u4ee4\u4f7f\u7528\u201cTAB\u201d\u4f5c\u4e3a\u9ed8\u8ba4\u7684\u5b57\u6bb5\u5206\u9694\u7b26 -d : \u201cTAB\u201d\u662f\u9ed8\u8ba4\u7684\u5206\u9694\u7b26\uff0c\u4f7f\u7528\u6b64\u9009\u9879\u53ef\u4ee5\u66f4\u6539\u4e3a\u5176\u4ed6\u7684\u5206\u9694\u7b26 --complement : \u6b64\u9009\u9879\u7528\u4e8e\u6392\u9664\u6240\u6307\u5b9a\u7684\u5b57\u6bb5 --output-delimiter=STRING : \u6307\u5b9a\u8f93\u51fa\u5185\u5bb9\u7684\u5206\u9694\u7b26 -c : \u6309\u5b57\u7b26\u5207\u5272 \u53d6/etc/passwd\u6587\u4ef6\u7b2c1\u5217\u5185\u5bb9\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff08\u53ea\u53d6\u524d\u4e09\u884c\uff09 $ cut -d ':' -f 1 /etc/passwd | head -3 root messagebus systemd-network \u53d6/etc/passwd\u6587\u4ef6\u7b2c1\u548c6\u5217\u5185\u5bb9\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff08\u53ea\u53d6\u524d\u4e09\u884c\uff09 cut -d ':' -f 1 ,6 /etc/passwd | head -3 root:/root messagebus:/run/dbus systemd-network:/ \u53d6/etc/passwd\u6587\u4ef6\u7b2c1\u52303\u5217\u4ee5\u53ca\u7b2c6\u5217\u5185\u5bb9\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff08\u53ea\u53d6\u524d\u4e09\u884c\uff09 $ cut -d ':' -f 1 -3,6 /etc/passwd | head -3 root:x:0:/root messagebus:x:499:/run/dbus systemd-network:x:497:/ \u4e0b\u9762\u4f7f\u7528 --output-delimiter \u9009\u9879\uff0c\u628a\u8f93\u51fa\u7ed3\u679c\u4e2d\u7684\u5206\u9694\u7b26 : \u5168\u90e8\u66ff\u6362\u6210 --- \u3002 $ cat /etc/passwd | sort | head -3 admin3:x:1020:100::/home/admin3:/bin/bash at:x:25:25:Batch jobs daemon:/var/spool/atjobs:/usr/sbin/nologin bin:x:1:1:bin:/bin:/usr/sbin/nologin $ cut -d \":\" -f 1 ,7 /etc/passwd | sort | head -3 admin3:/bin/bash at:/usr/sbin/nologin bin:/usr/sbin/nologin $ cut -d \":\" -f 1 ,7 --output-delimiter = \"---\" /etc/passwd | sort | head -3 admin3---/bin/bash at---/usr/sbin/nologin bin---/usr/sbin/nologin --output-delimiter \u9009\u9879\u4e5f\u53ef\u4ee5\u5229\u7528\u6765\u8fdb\u884c\u8ba1\u7b97\u3002 $ echo { 1 ..10 } | cut -d \" \" -f 1 -10 --output-delimiter = \"+\" | bc 55 \u4ece ifconfig \u547d\u4ee4\u4e2d\u622a\u53d6\u5f53\u524d\u4e3b\u673a\u7684ip\u5730\u5740\u3002\uff08openSUSE\u9700\u8981\u5b89\u88c5\u5305 net-tools-deprecated \uff09 $ ifconfig | head -2 | tail -1 inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig | head -2 | tail -1 | cut -d \" \" -f 10 192 .168.10.210 \u6216\u8005 $ ip addr list | grep eth0 | tail -1 | cut -d \" \" -f 6 192 .168.10.210/24 \u57fa\u4e8e\u4e0a\u9762\u7ed3\u679c\uff0c\u53ef\u4ee5\u5c1d\u8bd5\u901a\u8fc7 --complement \u53c2\u6570\uff0c\u4ee5 / \u4e3a\u5206\u9694\u7b26\uff0c\u6392\u9664\u7b2c\u4e8c\u5217 24 \uff0c\u53ea\u8f93\u51fa\u7b2c\u4e00\u5217IP\u5730\u5740\u3002 ip addr list | grep eth0 | tail -1 | cut -d \" \" -f 6 | cut -d \"/\" --complement -f 2 192 .168.10.210 \u663e\u793a df \u547d\u4ee4\u8f93\u51fa\u4e2d\u7684\u5206\u533a\u4f7f\u7528\u7387\u3002 $ df | tr -s ' ' | cut -d ' ' -f 5 | tr -d % Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0 \u65b9\u6cd52\uff1a\u5148\u628a\u7a7a\u683c\u5168\u90e8\u66ff\u6362\u6210%\uff0c\u518d\u53bb\u91cd\u3002 df | tr -s ' ' % | cut -d % -f 5 Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0","title":"2.9.\u6309\u5217\u62bd\u53d6\u6587\u672ccut"},{"location":"linux/SRE/04-TextTools/#210paste","text":"\u547d\u4ee4 paste \u5e38\u7528\u9009\u9879\uff1a -d \uff1a\u6307\u5b9a\u5206\u9694\u7b26\uff0c\u9ed8\u8ba4\u662fTAB -s \uff1a\u6240\u6709\u884c\u5408\u6210\u4e00\u884c\u663e\u793a \u751f\u6210 alpha.log \u548c seq.log \u3002 for i in { a..z } ; do echo $i >> alpha.log ; done seq 10 > seq.log \u7528 paste \u547d\u4ee4\u5408\u5e76\u8fd92\u4e2a\u6587\u4ef6\u3002 $ paste alpha.log seq.log a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k l m n o p q r s t u v w x y z $ paste -d \":\" alpha.log seq.log a:1 b:2 c:3 d:4 e:5 f:6 g:7 h:8 i:9 j:10 k: l: m: n: o: p: q: r: s: t: u: v: w: x: y: z: \u539f\u6587\u4ef6\u90fd\u662f\u5217\u8f93\u51fa\uff0c\u6539\u6210\u884c\u8f93\u51fa\u3002 $ paste -d \"-\" -s alpha.log a-b-c-d-e-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z $ paste -d \"-\" -s seq.log $ paste -d \":\" -s alpha.log seq.log a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z 1 :2:3:4:5:6:7:8:9:10 $ paste -d \":\" -s seq.log alpha.log 1 :2:3:4:5:6:7:8:9:10 a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z","title":"2.10.\u5408\u5e76\u591a\u4e2a\u6587\u4ef6paste"},{"location":"linux/SRE/04-TextTools/#211wc","text":"\u5e38\u7528\u9009\u9879\uff1a -l \uff1a\u53ea\u8ba1\u6570\u884c\u6570 -w \uff1a\u53ea\u8ba1\u6570\u5355\u8bcd\u603b\u6570 -c \uff1a\u53ea\u8ba1\u6570\u5b57\u8282\u603b\u6570 -m \uff1a\u53ea\u8ba1\u6570\u5b57\u7b26\u603b\u6570 -L \uff1a\u663e\u793a\u6587\u4ef6\u4e2d\u6700\u957f\u884c\u7684\u957f\u5ea6 $ cat text Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ wc text # \u884c\u6570 \u5355\u8bcd\u6570 \u5b57\u8282\u6570 3 9 57 text $ wc -l text 3 text $ wc -w text 9 text $ wc -c text 57 text $ wc -m text 57 text $ wc -L text 20 text \u5bf9\u6bd4\u4e24\u79cd\u4e0d\u540c\u5408\u5e76\u7684\u65b9\u6cd5\u3002 $ cat text1 text2 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou $ paste text1 text2 Tom, 20 , Shanghai Tom, 20 , Shanghai Jack, 30 , Beijing Jack, 30 , Beijing Smith, 40 , Guangzhou Leo, 40 , Guangzhou","title":"2.11.\u6587\u672c\u7edf\u8ba1\u6570\u636ewc"},{"location":"linux/SRE/04-TextTools/#212sort","text":"\u547d\u4ee4 sort \u628a\u6574\u7406\u8fc7\u7684\u6587\u672c\u663e\u793a\u5728stdout\u4e0a\uff0c\u4e0d\u6539\u53d8\u539f\u6587\u4ef6\u3002 \u5e38\u7528\u9009\u9879\uff1a -r \uff1a\u6267\u884c\u53cd\u65b9\u5411\uff08\u4ece\u4e0a\u81f3\u4e0b\uff09\u6392\u5e8f -R \uff1a\u968f\u673a\u6392\u5e8f -n \uff1a\u6309\u6570\u5b57\u5927\u5c0f\u6392\u5e8f -h \uff1a\u4eba\u7c7b\u53ef\u8bfb\u6392\u5e8f\uff0c\u5982\uff1a2K\uff0c1G -f \uff1a\u6392\u5e8f\u65f6\u5c06\u5c0f\u5199\u5b57\u6bcd\u89c6\u4e3a\u5927\u5199\u5b57\u6bcd -u \uff1a\u6392\u5e8f\u65f6\u5408\u5e76\u91cd\u590d\u9879 -t c \uff1a\u4f7f\u7528c\u4f5c\u4e3a\u5b57\u6bb5\u5206\u9694\u7b26 -k # \uff1a\u6309\u7167\u4ee5c\u4e3a\u5206\u9694\u7b26\u7684\u7b2c#\u5217\u6765\u6392\u5e8f \u4e3e\u4f8b\uff1a\u4ee5 , \u4e3a\u5206\u9694\u7b26\uff0c\u8bfb\u53d6 text \u6587\u4ef6\u5185\u5bb9\u4e2d\u7b2c1\uff0c3\u5217\uff0c\u5bf9\u8f93\u51fa\u7ed3\u679c\u4ee5 , \u4e3a\u5206\u9694\u7b26\uff0c\u6309\u7b2c\u4e8c\u5217\u6392\u5e8f\uff08\u6b63\u5e8f\u548c\u53cd\u5e8f\uff09\u3002 $ cat text Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ cut -d \",\" -f 1 ,3 text | sort -t \",\" -k 1 Jack, Beijing Smith, Guangzhou Tom, Shanghai $ cut -d \",\" -f 1 ,3 text | sort -t \",\" -k 1 -r Tom, Shanghai Smith, Guangzhou Jack, Beijing \u628a\u6587\u4ef6text1\u548c\u6587\u4ef6text2\u5408\u5e76\u540e\u53bb\u91cd\u8f93\u51fa\u3002 $ cat text2 Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou $ cat text1 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ cat text1 text2 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou \u5e76\u96c6\uff0c\u91cd\u590d\u884c\u53ea\u4fdd\u7559\u4e00\u884c\u3002\u524d\u97622\u4e2a\u547d\u4ee4\u662f\u540c\u6837\u542b\u4e49\uff08\u76f8\u540c\u7684\u6392\u5e8f\u5217\uff09\uff0c\u7b2c\u4e09\u4e2a\u547d\u4ee4\u4e2d\u5bf9\u4e0d\u540c\u5217\u8fdb\u884c\u4e86\u6392\u5e8f\uff0c\u5bfc\u81f4\u53bb\u91cd\u7ed3\u679c\u4e0d\u540c\u3002 $ cat text1 text2 | sort -u Jack, 30 , Beijing Leo, 40 , Guangzhou Smith, 40 , Guangzhou Tom, 20 , Shanghai $ cat text1 text2 | sort -t \",\" -k 1 -u Jack, 30 , Beijing Leo, 40 , Guangzhou Smith, 40 , Guangzhou Tom, 20 , Shanghai $ cat text1 text2 | sort -t \",\" -k 2 -u Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou","title":"2.12.\u6587\u672c\u6392\u5e8fsort"},{"location":"linux/SRE/04-TextTools/#213uniq","text":"\u547d\u4ee4 uniq \u4ece\u8f93\u5165\u4e2d\u5220\u9664\u524d\u540e\u76f8\u90bb\u91cd\u590d\u7684\u884c\u3002\u7ecf\u5e38\u4e0e sort \u547d\u4ee4\u7ed3\u5408\u4f7f\u7528\u3002 \u4e3b\u8981\u53c2\u6570\uff1a -c \uff1a\u663e\u793a\u6bcf\u884c\u91cd\u590d\u51fa\u73b0\u7684\u6b21\u6570 -d \uff1a\u4ec5\u663e\u793a\u91cd\u590d\u7684\u884c -u \uff1a\u4ec5\u663e\u793a\u4e0d\u91cd\u590d\u7684\u884c \u4e3e\u4f8b\uff0c\u6ce8\u610f\u53ea\u6709\u5bf9\u76f8\u90bb\u884c\u8fdb\u884c\u53bb\u91cd\u3002 $ cat text3 test 30 Hello 95 Hello 95 Linux 85 Linux 85 Hello 95 test 30 $ uniq text3 test 30 Hello 95 Linux 85 Hello 95 test 30 \u628a\u6587\u4ef6text1\u548c\u6587\u4ef6text2\u5408\u5e76\u540e\uff0c\u8fdb\u884c\u4ea4\u96c6\u548c\u5e76\u96c6\uff0c\u5e76\u53bb\u91cd\u3002 $ cat text1 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ cat text2 Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou # \u5e76\u96c6\uff0c\u6309\u9996\u5217\u6392\u5e8f\u53bb\u91cd $ cat text1 text2 | sort | uniq Jack, 30 , Beijing Leo, 40 , Guangzhou Smith, 40 , Guangzhou Tom, 20 , Shanghai # \u4ea4\u96c6 $ cat text1 text2 | sort | uniq -d Jack, 30 , Beijing Tom, 20 , Shanghai # \u5dee\u96c6 $ cat text1 text2 | sort | uniq -u Leo, 40 , Guangzhou Smith, 40 , Guangzhou \u67e5\u770b\u5e76\u53d1\u8fde\u63a5\u6570\u6700\u591a\u7684\u8fdc\u7a0b\u4e3b\u673aIP\u3002 $ ss -nt State Recv-Q Send-Q Local Address:Port Peer Address:Port Process ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:41650 ESTAB 0 0 192 .168.10.210:22 192 .168.10.201:65330 ESTAB 0 64 192 .168.10.210:22 192 .168.10.201:63289 ESTAB 0 0 192 .168.10.210:41650 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:47992 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:60268 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.201:65327 ESTAB 0 0 192 .168.10.210:35758 192 .168.10.220:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:56818 ESTAB 0 0 192 .168.10.210:56818 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:48006 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:60268 ESTAB 0 0 192 .168.10.210:22 192 .168.10.220:33896 ESTAB 0 0 192 .168.10.210:22 192 .168.10.201:65324 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:47992 ESTAB 0 0 192 .168.10.210:59554 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:59554 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:48006 $ ss -nt | tr -s \" \" \":\" | cut -d \":\" -f 6 ,7 | sort | uniq -c | sort -nr | head -n 1 6 192 .168.10.210:22","title":"2.13.\u53bb\u91cduniq"},{"location":"linux/SRE/04-TextTools/#214","text":"","title":"2.14.\u6587\u672c\u6bd4\u8f83"},{"location":"linux/SRE/04-TextTools/#2141diff","text":"\u547d\u4ee4 diff \u6bd4\u8f83\u4e24\u4e2a\u6587\u4ef6\u4e4b\u95f4\u7684\u533a\u522b\u3002 \u5e38\u7528\u9009\u9879\uff1a -u \uff1a\u4ee5\u7edf\u4e00\u7684\u65b9\u5f0f\u6765\u663e\u793a\u6587\u4ef6\u5185\u5bb9\u7684\u4e0d\u540c -y \uff1a\u4ee5\u5e76\u5217\u7684\u65b9\u5f0f\u663e\u793a\u6587\u4ef6\u7684\u5f02\u540c\u4e4b\u5904 -W \uff1a\u5728\u4f7f\u7528-y\u53c2\u6570\u65f6\uff0c\u6307\u5b9a\u680f\u5bbd -c \uff1a\u663e\u793a\u5168\u90e8\u5185\u6587\uff0c\u5e76\u6807\u51fa\u4e0d\u540c\u4e4b\u5904 -N \uff1a\u7f3a\u5931\u6587\u4ef6\u4ee5\u7a7a\u6587\u4ef6\u5904\u7406 \u4e3e\u4f8b\uff1a $ cat text5 # \u6587\u4ef6\u5c3e\u90e8\u6ca1\u6709\u7a7a\u884c 1001 1002 1003 $ cat text6 # \u6587\u4ef6\u5c3e\u90e8\u6ca1\u6709\u7a7a\u884c 1001 1002 1003a 1004 \u663e\u793a\u4e0d\u540c\u3002 3c3,4 \u4ee3\u8868\u4e24\u4e2a\u6587\u4ef6\u5728\u7b2c3\uff0c4\u884c\u6709\u4e0d\u540c\u3002 $ diff text5 text6 3c3,4 < 1003 --- > 1003a > 1004 \u4ee5\u7edf\u4e00\u683c\u5f0f\u8f93\u51fa\u6bd4\u8f83\u7ed3\u679c\u3002 \u524d2\u884c\u662f\u6587\u4ef6\u4fe1\u606f\u3002\u5176\u4e2d --- \u8868\u793a\u53d8\u52a8\u524d\u7684\u6587\u4ef6\uff0c +++ \u8868\u793a\u53d8\u52a8\u540e\u7684\u6587\u4ef6\u3002 \u53d8\u52a8\u7684\u4f4d\u7f6e\u7528\u4e24\u4e2a@\u4f5c\u4e3a\u8d77\u9996\u548c\u7ed3\u675f\uff0c @@ -1,3 +1,4 @@ \u3002 -1,3 \u4e2d\uff0c - \u8868\u793a\u7b2c\u4e00\u4e2a\u6587\u4ef6\uff0c\u5373 text5 \u3002\u7b2c\u4e00\u4e2a\u6587\u4ef6\u4ece\u7b2c1\u884c\u5f00\u59cb\u8fde\u7eed3\u884c\u3002 +1,4 \u4e2d\uff0c + \u8868\u793a\u7b2c\u4e8c\u4e2a\u6587\u4ef6\uff0c\u5373 text6 \u3002\u5373\uff0c\u7b2c\u4e8c\u4e2a\u6587\u4ef6\u4ece\u7b2c1\u884c\u5f00\u59cb\u8fde\u7eed4\u884c\u3002 $ diff -u text5 text6 --- text5 2022 -12-07 08 :07:05.927805722 +0800 +++ text6 2022 -12-07 08 :07:24.692234585 +0800 @@ -1,3 +1,4 @@ 1001 1002 -1003 +1003a +1004 \u4ee5\u4e0a\u4e0b\u6587\u65b9\u5f0f\u8f93\u51fa\u6bd4\u8f83\u7ed3\u679c\u3002\u6807\u6709 ! \u4ee3\u8868\u5dee\u5f02\u884c\u3002 $ diff -c text5 text6 *** text5 2022 -12-07 08 :24:08.867168414 +0800 --- text6 2022 -12-07 08 :24:13.939284243 +0800 *************** *** 1 ,3 **** 1001 1002 ! 1003 --- 1 ,4 ---- 1001 1002 ! 1003a ! 1004 \u5e76\u6392\u683c\u5f0f\u8f93\u51fa\u6bd4\u8f83\u7ed3\u679c\u3002 | \u8868\u793a\u524d\u540e2\u4e2a\u6587\u4ef6\u5185\u5bb9\u6709\u4e0d\u540c < \u8868\u793a\u540e\u9762\u6587\u4ef6\u6bd4\u524d\u9762\u6587\u4ef6\u5c11\u4e861\u884c\u5185\u5bb9 > \u8868\u793a\u540e\u9762\u6587\u4ef6\u6bd4\u524d\u9762\u6587\u4ef6\u591a\u4e861\u884c\u5185\u5bb9 $ diff -y -W 50 text5 text6 1001 1001 1002 1002 1003 | 1003a > 1004 \u6bd4\u8f83\u6587\u4ef6\u5939\u5185\u5bb9\u3002\u6ce8\u610f\uff0c\u53ea\u6bd4\u8f83\u5185\u5bb9\uff0c\u4e0d\u6bd4\u8f83\u65f6\u95f4\u6233\u3002 $ mkdir dir1 $ mkdir dir2 $ cd dir1 $ touch file1 $ touch file2 $ cp file1 file2 ../dir2/ $ echo \"hello\" > file3 $ cd ../dir2 $ touch file3 $ touch file4 $ diff dir1 dir2 1d0 < hello Only in dir2: file4","title":"2.14.1.diff"},{"location":"linux/SRE/04-TextTools/#2142patch","text":"\u547d\u4ee4 patch \u590d\u5236\u5176\u4ed6\u6587\u4ef6\u4e2d\u7684\u5185\u5bb9\u3002\u547d\u4ee4\u683c\u5f0f\uff1a patch -p [ num ] < patchfile patch [ options ] originalfile patchfile \u5f53\u7279\u5b9a\u8f6f\u4ef6\u6709\u53ef\u7528\u7684\u5b89\u5168\u4fee\u590d\u7a0b\u5e8f\u65f6\uff0c\u6211\u4eec\u901a\u5e38\u4f1a\u4f7f\u7528 yum \u6216 apt-get \u6216 zypper \u7b49\u5305\u7ba1\u7406\u5de5\u5177\u8fdb\u884c\u4e8c\u8fdb\u5236\u5347\u7ea7\u3002 \u4f46\u5982\u679c\u6211\u4eec\u662f\u901a\u8fc7\u4ece\u6e90\u4ee3\u7801\u7f16\u8bd1\u5b89\u88c5\u8f6f\u4ef6\u7684\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u9700\u8981\u4e0b\u8f7d\u5b89\u5168\u8865\u4e01\u5e76\u5c06\u5176\u5e94\u7528\u4e8e\u539f\u59cb\u6e90\u4ee3\u7801\u5e76\u91cd\u65b0\u7f16\u8bd1\u8f6f\u4ef6\u3002 \u8fd9\u5c31\u662f\u6211\u4eec\u4f7f\u7528 diff \u521b\u5efa\u8865\u4e01\u6587\u4ef6\uff08patch file\uff09\uff0c\u5e76\u4f7f\u7528 patch \u547d\u4ee4\u5e94\u7528\u5b83\u3002 \u8865\u4e01\u6587\u4ef6\u662f\u4e00\u4e2a\u6587\u672c\u6587\u4ef6\uff0c\u5176\u4e2d\u5305\u542b\u540c\u4e00\u6587\u4ef6\uff08\u6216\u540c\u4e00\u6e90\u4ee3\u7801\u6811\uff09\u7684\u4e24\u4e2a\u7248\u672c\u4e4b\u95f4\u7684\u5dee\u5f02\u3002 \u8865\u4e01\u6587\u4ef6\u662f\u4f7f\u7528 diff \u547d\u4ee4\u521b\u5efa\u7684\u3002 \u7ee7\u7eed\u4e0a\u4f8b\u3002 \u5c06\u6587\u4ef6 text5 \u7684\u5185\u5bb9\u540c\u6b65\u5230\u6587\u4ef6 text6 \uff0c\u7136\u540e\u64a4\u9500\u8865\u4e01\u3002\u6ce8\u610f\u533a\u5206\u6e90\u6587\u4ef6\u548c\u76ee\u6807\u6587\u4ef6\u3002 $ cat text5 1001 1002 1003 $ cat text6 1001 1002 1003a 1004 # \u751f\u6210\u8865\u4e01\u6587\u4ef6 $ diff -ruN text5 text6 > patchfile $ cat patchfile --- text5 2022 -12-07 08 :24:08.867168414 +0800 +++ text6 2022 -12-07 08 :24:13.939284243 +0800 @@ -1,3 +1,4 @@ 1001 1002 -1003 +1003a +1004 # \u4e0d\u6307\u660e\u76ee\u6807\u6587\u4ef6\uff0c\u5219\u9ed8\u8ba4\u7ed9diff\u547d\u4ee4\u4e2d\u7684\u6e90\u6587\u4ef6\u8fdb\u884c\u6253\u8865\u4e01 $ patch < patchfile patching file text5 $ cat text5 1001 1002 1003a 1004 $ cat text6 1001 1002 1003a 1004 # \u64a4\u9500\u8865\u4e01 patch -R < patchfile patching file text5 # cat text5 1001 1002 1003 # \u7ed9text6\u6587\u4ef6\u6253\u8865\u4e01\uff08\u7528text5\u7684\u6587\u4ef6\u5185\u5bb9\u8986\u76d6text6\u7684\u5185\u5bb9\uff09 $ patch text6 patchfile patching file text6 Reversed ( or previously applied ) patch detected! Assume -R? [ n ] y $ cat text6 1001 1002 1003 # \u64a4\u9500\u7ed9text6\u6587\u4ef6\u6253\u7684\u8865\u4e01\uff08\u6062\u590dtext6\u6587\u4ef6\u8865\u4e01\u524d\u7684\u5185\u5bb9\uff09 $ patch -R text6 patchfile patching file text6 Unreversed patch detected! Ignore -R? [ n ] y $ cat text6 1001 1002 1003a 1004 \u4f7f\u7528 -b \u53c2\u6570\uff0c\u5728patch\u524d\u5148\u5907\u4efd\u6e90\u6587\u4ef6\u3002 $ patch -b < patchfile patching file text5 $ cat text5 1001 1002 1003a 1004 $ cat text5.orig 1001 1002 1003 $ cat text6.orig 1001 1002 1003 $ patch -R < patchfile patching file text5 \u5728-b\u53c2\u6570\u4e2d\u52a0\u5165-V\u53c2\u6570\uff0c\u6307\u5b9a\u5907\u4efd\u6587\u4ef6\u540d\u7684\u683c\u5f0f\uff0c\u5982\u4e0b\uff0c\u4f1a\u5f97\u5230\u6587\u4ef6 text5.~1~ \u3002 $patch -b -V numbered < patchfile patching file text5 $ cat text5 1001 1002 1003a 1004 $ cat text5.~1~ 1001 1002 1003 \u8bd5\u8fd0\u884c\uff0c\u4e0d\u505a\u5b9e\u9645\u66f4\u6539\u3002 patch --dry-run < patchfile \u5bf9\u76ee\u5f55\u6253\u8865\u4e01\u3002 \u6267\u884c diff \u548c patch \u547d\u4ee4\u662f\u5728\u5f53\u524d\u7528\u6237 vagrant \u7684\u4e3b\u76ee\u5f55\u4e0b\uff0c\u7edd\u5bf9\u8def\u5f84\u662f /home/vagrant \u3002 diff \u547d\u4ee4\u4e2d\uff0c\u6e90\u76ee\u5f55\u662f /home/vagrant/dir1 \u3002\u76ee\u6807\u76ee\u5f55\u662f /home/vagrant/dir2 \u3002 -p3 \u662f\u544a\u8bc9 patch \u547d\u4ee4\u5ffd\u7565\u4e0a\u9762\u7edd\u5bf9\u8def\u5f84\u4e2d\u524d\u4e09\u4e2a\u659c\u6760 / \u3002 patch \u547d\u4ee4\u4e2d\u7528 diff \u7684\u76ee\u6807\u76ee\u5f55\u53bb\u8986\u76d6\u6e90\u76ee\u5f55\u3002\u4e92\u6362\u4f1a\u62a5\u9519\u3002 -R \uff1a\u64a4\u9500\u8865\u4e01\u3002 # file3\u548cfile4\u6709\u5185\u5bb9 $ tree ./dir1 ./dir1 \u251c\u2500\u2500 file1 \u251c\u2500\u2500 file2 \u251c\u2500\u2500 file3 \u2514\u2500\u2500 subdir1 \u2514\u2500\u2500 file4 \u90fd\u662f\u7a7a\u6587\u4ef6 $ tree ./dir2 ./dir2 \u251c\u2500\u2500 file1 \u251c\u2500\u2500 file2 \u251c\u2500\u2500 file3 \u2514\u2500\u2500 subdir1 \u2514\u2500\u2500 file4 $ diff -ruN /home/vagrant/dir1 /home/vagrant/dir2 > patchdir $ cat patchdir diff -ruN /home/vagrant/dir1/file3 /home/vagrant/dir2/file3 --- /home/vagrant/dir1/file3 2022 -12-07 08 :42:33.108418336 +0800 +++ /home/vagrant/dir2/file3 2022 -12-07 21 :25:48.156056360 +0800 @@ -1 +0,0 @@ -hello diff -ruN /home/vagrant/dir1/subdir1/file4 /home/vagrant/dir2/subdir1/file4 --- /home/vagrant/dir1/subdir1/file4 2022 -12-07 21 :15:09.689912160 +0800 +++ /home/vagrant/dir2/subdir1/file4 2022 -12-07 21 :26:55.405546177 +0800 @@ -1 +0,0 @@ -/home/vagrant/dir1/subdir1 # \u7528dir2\u7684\u5185\u5bb9\u8986\u76d6dir1\u7684\u5185\u5bb9 $ patch -p3 < patchdir patching file dir1/file3 patching file dir1/subdir1/file4 # \u73b0\u5728dir1\u76ee\u5f55\u4e0b\u7684\u5185\u5bb9\u5df2\u7ecf\u88abdir2\u76ee\u5f55\u8986\u76d6\u4e86\u3002file3\u548cfile4\u90fd\u662f\u7a7a\u6587\u4ef6 $ ll ./dir1 total 0 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :34 file1 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :35 file2 -rw-r--r--. 1 vagrant wheel 0 Dec 7 21 :40 file3 drwxr-xr-x. 1 vagrant wheel 10 Dec 7 21 :40 subdir1 $ ll ./dir1/subdir1 total 0 -rw-r--r--. 1 vagrant wheel 0 Dec 7 21 :40 file4 # \u64a4\u9500\u8865\u4e01\uff0cfile3\u548cfile4\u5df2\u7ecf\u6062\u590d\u4e3a\u539f\u6587\u4ef6 $ patch -R -p3 < patchdir patching file dir1/file3 patching file dir1/subdir1/file4 $ ll ./dir1 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :34 file1 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :35 file2 -rw-r--r--. 1 vagrant wheel 6 Dec 7 21 :45 file3 drwxr-xr-x. 1 vagrant wheel 10 Dec 7 21 :45 subdir1 $ ll ./dir1/subdir1 -rw-r--r--. 1 vagrant wheel 27 Dec 7 21 :45 file4 # \u7528dir1\u7684\u5185\u5bb9\u8986\u76d6dir2\u7684\u5185\u5bb9\uff0c\u7cfb\u7edf\u62d2\u7edd\u3002 patch dir2 -p3 < patchdir File dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file dir2.rej File dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file dir2.rej $ patch /home/vagrant/dir2 -p3 < patchdir File /home/vagrant/dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file /home/vagrant/dir2.rej File /home/vagrant/dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file /home/vagrant/dir2.rej","title":"2.14.2.patch"},{"location":"linux/SRE/04-TextTools/#2143vimdiff","text":"\u547d\u4ee4 vimdiff \u76f8\u5f53\u4e8e vim -d \u3002 \u4e3e\u4f8b\uff1a vimdiff text1 text2","title":"2.14.3.vimdiff"},{"location":"linux/SRE/04-TextTools/#2144cmp","text":"\u547d\u4ee4 cmp \u67e5\u770b\u4e8c\u8fdb\u5236\u6587\u4ef6\u7684\u4e0d\u540c\u3002 $ cmp cp grep cp grep differ: byte 25 , line 1 $ cmp /usr/bin/ls /usr/bin/dir /usr/bin/ls /usr/bin/dir differ: byte 613 , line 1 # \u8df3\u8fc7\u524d735\u4e2a\u5b57\u8282\uff0c\u8f93\u51fa\u540e\u976230\u4e2a\u5b57\u8282\u5185\u5bb9 $ hexdump -s 735 -Cn 30 /usr/bin/ls 000002df 00 00 00 00 00 5d 00 00 00 50 00 00 00 68 00 00 | ..... ] ...P...h.. | 000002ef 00 6a 00 00 00 4f 00 00 00 00 00 00 00 1d | .j...O........ | 000002fd $ hexdump -s 735 -Cn 30 /usr/bin/dir 000002df 00 00 00 00 00 5d 00 00 00 50 00 00 00 68 00 00 | ..... ] ...P...h.. | 000002ef 00 6a 00 00 00 4f 00 00 00 00 00 00 00 1d | .j...O........ | 000002fd","title":"2.14.4.cmp"},{"location":"linux/SRE/05-RegExpress/","text":"\u7b2c\u4e94\u7ae0 \u6b63\u5219\u8868\u8fbe\u5f0f \u00b6 \u6b63\u5219\u8868\u8fbe\u5f0f\u5206\u4e24\u7c7b\uff1a \u57fa\u672c\u6b63\u5219\u8868\u8fbe\u5f0f\uff08Basic Regular Expression\uff0c \u53c8\u53ebBasic RegEx\uff0c\u7b80\u79f0BREs\uff09 \u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\uff08Extended Regular Expression\uff0c \u53c8\u53ebExtended RegEx\uff0c\u7b80\u79f0EREs\uff09 Perl\u6b63\u5219\u8868\u8fbe\u5f0f\uff08Perl Regular Expression\uff0c \u53c8\u53ebPerl RegEx \u7b80\u79f0PREs \u57fa\u672c\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u548c\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u533a\u522b\u5c31\u662f\u5143\u5b57\u7b26\u7684\u4e0d\u540c\u3002 5.1.\u57fa\u672c\u6b63\u5219\u8868\u8fbe\u5f0f\u7b26\u53f7 \u00b6 ^ \uff1a\u8868\u793a\u4ee5\u67d0\u4e2a\u5b57\u7b26\u5f00\u59cb $ \uff1a\u8868\u793a\u4ee5\u67d0\u4e2a\u5b57\u7b26\u7ed3\u5c3e . \uff1a\u8868\u793a\u5339\u914d\u4e00\u4e2a\u4e14\u53ea\u5339\u914d\u4e00\u4e2a\u5b57\u7b26 * \uff1a\u8868\u793a\u5339\u914d\u524d\u8fb9\u4e00\u4e2a\u5b57\u7b26\u51fa\u73b00\u6b21\u6216\u8005\u591a\u6b21 [] \uff1a\u8868\u793a\u5339\u914d\u62ec\u53f7\u5185\u7684\u591a\u4e2a\u5b57\u7b26\u4fe1\u606f,\u4e00\u4e2a\u4e00\u4e2a\u5339\u914d .* \uff1a\u8868\u793a\u5339\u914d\u6240\u6709\uff0c\u7a7a\u884c\u4e5f\u4f1a\u8fdb\u884c\u5339\u914d [^] \uff1a\u8868\u793a\u4e0d\u5339\u914d\u62ec\u53f7\u5185\u7684\u6bcf\u4e00\u4e2a\u5b57\u7b26 ^$ \uff1a\u8868\u793a\u5339\u914d\u7a7a\u884c\u4fe1\u606f \\ \uff1a\u5c06\u6709\u7279\u6b8a\u542b\u4e49\u7684\u5b57\u7b26\u8f6c\u4e49\u4e3a\u901a\u914d\u7b26 5.2.\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\u7b26\u53f7 \u00b6 + \uff1a\u8868\u793a\u524d\u4e00\u4e2a\u5b57\u7b26\u51fa\u73b0\u4e00\u6b21\u6216\u4e00\u6b21\u4ee5\u4e0a ? \uff1a\u8868\u793a\u524d\u4e00\u4e2a\u5b57\u7b26\u51fa\u73b00\u6b21\u6216\u8005\u4e00\u6b21\u4ee5\u4e0a | \uff1a\u8868\u793a\u6216\u8005\u7684\u5173\u7cfb,\u5339\u914d\u591a\u4e2a\u4fe1\u606f () \uff1a\u5339\u914d\u4e00\u4e2a\u6574\u4f53\u4fe1\u606f\uff0c\u4e5f\u53ef\u4ee5\u63a5\u540e\u9879\u5f15\u7528 {} \uff1a\u5b9a\u4e49\u524d\u8fb9\u5b57\u7b26\u51fa\u73b0\u51e0\u6b21 \u63d0\u793a\uff1a grep -E \u6216\u8005 egrep \u53ea\u662f\u8868\u793a\u6269\u5c55\u6b63\u5219\uff0c\u4e0d\u4ee3\u8868\u52a0\u4e86e\u5c31\u8868\u793a\u8f6c\u4e49\u4e86\u3002 \u5f53 grep \u4f7f\u7528\u6269\u5c55\u6b63\u5219\u7684\u7b26\u53f7\u65f6\u5019\u9700\u8981\u7528 \\ \u8f6c\u4e49\u4e3a\u901a\u914d\u7b26\u624d\u80fd\u4f7f\u7528\u3002 5.3.\u5b57\u7b26\u5339\u914d \u00b6 [:alpha:] \uff1a\u8868\u793a\u6240\u6709\u7684\u5b57\u6bcd\uff08\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff09\uff0c\u6548\u679c\u540c [a-z] [:digit:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u6570\u5b57\uff0c\u6548\u679c\u540c [0-9] [:xdigit:] \uff1a\u8868\u793a\u5341\u516d\u8fdb\u5236\u6570\u5b57 [:lower:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5c0f\u5199\u5b57\u6bcd [:upper:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5927\u5199\u5b57\u6bcd [:alnum:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5b57\u6bcd\u6216\u6570\u5b57 [:blank:] \uff1a\u8868\u793a\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u548c\u5236\u8868\u7b26\uff09 [:space:] \uff1a\u8868\u793a\u5305\u62ec\u7a7a\u683c\u3001\u5236\u8868\u7b26\uff08\u6c34\u5e73\u548c\u5782\u76f4\uff09\u3001\u6362\u884c\u7b26\u3001\u56de\u8f66\u7b26\u7b49\u5404\u79cd\u7c7b\u578b\u7684\u7a7a\u767d\uff0c\u6bd4 [:blank:] \u8303\u56f4\u66f4\u5e7f [:cntrl:] \uff1a\u8868\u793a\u4e0d\u53ef\u6253\u5370\u7684\u63a7\u5236\u5b57\u7b26\uff08\u9000\u683c\u3001\u5220\u9664\u3001\u8b66\u94c3\u7b49\uff09 [:graph:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u7684\u975e\u7a7a\u767d\u5b57\u7b26 [:print:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u5b57\u7b26 [:punct:] \uff1a\u8868\u793a\u6807\u70b9\u7b26\u53f7 5.4.\u4f4d\u7f6e\u6807\u8bb0 \u00b6 \u4f4d\u7f6e\u6807\u8bb0\u951a\u70b9\uff08position marker anchor\uff09\u662f\u6807\u8bc6\u5b57\u7b26\u4e32\u4f4d\u7f6e\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6b63\u5219\u8868\u8fbe\u5f0f\u6240\u5339\u914d\u7684\u5b57\u7b26\u53ef\u4ee5\u51fa\u73b0\u5728\u5b57\u7b26\u4e32\u4e2d\u4efb\u4f55\u4f4d\u7f6e\u3002 ^ \uff1a\u884c\u9996\u951a\u5b9a\uff0c\u6307\u5b9a\u4e86\u5339\u914d\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u6587\u672c\u5fc5\u987b\u8d77\u59cb\u4e8e\u5b57\u7b26\u4e32\u7684\u9996\u90e8\u3002 \u4f8b\u5982\uff1a ^tux \u80fd\u591f\u5339\u914d\u4ee5 tux \u8d77\u59cb\u7684\u884c $ \uff1a\u884c\u5c3e\u951a\u5b9a\uff0c\u6307\u5b9a\u4e86\u5339\u914d\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u6587\u672c\u5fc5\u987b\u7ed3\u675f\u4e8e\u76ee\u6807\u5b57\u7b26\u4e32\u7684\u5c3e\u90e8\u3002 \\< \u6216 \\b \uff1a\u8bcd\u9996\u951a\u5b9a\uff0c\u7528\u4e8e\u5355\u8bcd\u6a21\u5f0f\u5339\u914d\u5de6\u4fa7\u3002\uff08\u5355\u8bcd\u662f\u6709\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u4e0b\u5212\u7ebf\u7ec4\u6210\uff09 \\> \u6216 \\b \uff1a\u8bcd\u5c3e\u951a\u5b9a\uff0c\u7528\u4e8e\u5355\u8bcd\u6a21\u5f0f\u5339\u914d\u53f3\u4fa7\u3002\uff08\u5355\u8bcd\u662f\u6709\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u4e0b\u5212\u7ebf\u7ec4\u6210\uff09 ^PATTERN$ \uff1a\u7528\u6a21\u5f0fPATTERN\u5339\u914d\u6574\u884c\u3002 ^$ \uff1a\u5339\u914d\u7a7a\u884c\u3002 ^[[:space:]]*$ \uff1a\u5339\u914d\u7a7a\u767d\u884c\uff08\u6574\u884c\uff09\u3002 \\ \uff1a\u5339\u914d\u6574\u4e2a\u5355\u8bcd\u3002\uff08\u5355\u8bcd\u662f\u6709\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u4e0b\u5212\u7ebf\u7ec4\u6210\uff09 \u5173\u4e8e\u884c\u9996\u951a\u5b9a\u548c\u8bcd\u9996\u951a\u5b9a\uff0c\u5bf9\u6bd4\u4e0b\u9762\u4f8b\u5b50\u3002\u8bcd\u5c3e\u951a\u5b9a\u4e5f\u662f\u7c7b\u4f3c\u60c5\u51b5\u3002 ; \u548c - \u90fd\u88ab\u8ba4\u5b9a\u4e3a\u5355\u8bcd\u5206\u9694\u7b26\u3002 # \u7b26\u5408\u8bcd\u9996\u5339\u914d $ echo \"tux_01-tux02\" | grep '\\ mtu 1500 inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 inet6 fe80::20c:29ff:fea4:e17a prefixlen 64 scopeid 0x20 ether 00 :0c:29:a4:e1:7a txqueuelen 1000 ( Ethernet ) RX packets 7654 bytes 635932 ( 621 .0 KiB ) RX errors 0 dropped 1 overruns 0 frame 0 TX packets 1934 bytes 279649 ( 273 .0 KiB ) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 $ ifconfig eth0 | grep netmask | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' 192 .168.10.210 255 .255.255.0 192 .168.10.255 $ ifconfig eth0 | grep netmask | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' | head -n 1 192 .168.10.210 $ ifconfig eth0 | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' 192 .168.10.210 255 .255.255.0 192 .168.10.255 ifconfig eth0 | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' | head -n 1 192 .168.10.210 \u5339\u914d\u7a7a\u884c\u548c\u975e\u7a7a\u884c\uff1a grep '^$' /etc/profile grep -v '^$' /etc/profile \u5339\u914d\u975e\u7a7a\u884c\u548c\u975e#\u5f00\u5934\u7684\u884c\uff1a\uff08\u4e09\u79cd\u65b9\u6cd5\uff09 grep -v '^$' /etc/profile | grep -v '^#' grep -v '^$\\|#' /etc/profile grep '^[^$#]' /etc/profile \u6ce8\u610f\uff0c\u5982\u679c\u5199\u6210\u4e0b\u9762\u8fd9\u6837\uff0c\u5219\u4e0d\u4f1a\u8fc7\u6ee4\u6389\u7a7a\u884c\uff0c [$] \u4f1a\u88ab\u89c6\u4e3a $ \u7b26\u53f7\u3002 \u6240\u4ee5\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u5143\u5b57\u7b26\u653e\u5728\u4e2d\u62ec\u53f7 [] \u5185\u5c31\u88ab\u89c6\u4e3a\u666e\u901a\u5b57\u7b26\u3002 grep -v '^[$#]' /etc/profile 5.8.\u4e09\u5251\u5ba2 grep \u547d\u4ee4 \u00b6 \u683c\u5f0f\uff1a grep [OPTIONS] PATTERN [FILE...] grep [OPTIONS] -e PATTERN ... [FILE...] grep [OPTIONS] -f FILE ... [FILE...] \u53c2\u6570\uff1a -n \uff1a\u663e\u793a\u8fc7\u6ee4\u51fa\u6765\u7684\u6587\u4ef6\u5728\u6587\u4ef6\u5f53\u4e2d\u7684\u884c\u53f7 -c \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u884c\u6570 -o \uff1a\u53ea\u663e\u793a\u5339\u914d\u5230\u7684\u5185\u5bb9 -q \uff1a\u9759\u9ed8\u8f93\u51fa\uff08\u4e00\u822c\u7528\u5728shell\u811a\u672c\u5f53\u4e2d\uff0c\u901a\u8fc7 echo $? \u67e5\u770b\u547d\u4ee4\u6267\u884c\u7ed3\u679c\uff0c0\u8868\u793a\u6210\u529f\uff0c\u975e0\u8868\u793a\u5931\u8d25\uff09\uff09 -i \uff1a\u5ffd\u7565\u5927\u5c0f\u5199 -v \uff1a\u53cd\u5411\u67e5\u627e -w \uff1a\u5339\u914d\u67d0\u4e2a\u8bcd\u8bcd\uff1a\u5728Linux\u4e2d\uff0c\u8bcd\u4e3a\u4e00\u8fde\u4e32\u5b57\u6bcd\u3001\u6570\u5b57\u548c\u4e0b\u5212\u7ebf\u7ec4\u6210\u7684\u5b57\u7b26\u4e32 -E \uff1a\u4f7f\u7528\u6269\u5c55\u6b63\u5219 -R \uff1a\u9012\u5f52\u67e5\u8be2 -l \uff1a\u53ea\u6253\u5370\u6587\u4ef6\u8def\u5f84 \u6269\u5c55\u53c2\u6570\uff1a -A \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u6570\u636e\u7684\u540e\u51e0n\u884c -B \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u6570\u636e\u7684\u524d\u51e0n\u884c -C \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u6570\u636e\u7684\u524d\u540e\u5404\u51e0n\u884c \u793a\u4f8b\uff1a \u5339\u914d\u7528\u6237\uff1a grep root /etc/passwd root:x:0:0:root:/root:/bin/bash $ grep \"USER\" /etc/passwd $ grep \" $USER \" /etc/passwd vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash $ grep '$USER' /etc/passwd \u5339\u914d\u5173\u952e\u5b57\uff1a $ grep processor /proc/cpuinfo processor : 0 processor : 1 $ grep -o processor /proc/cpuinfo processor processor $ grep \"cpu family\" /proc/cpuinfo cpu family : 6 cpu family : 6 $ grep -o \"cpu family\" /proc/cpuinfo cpu family cpu family \u901a\u8fc7grep\u8fdb\u884c\u6587\u4ef6\u6bd4\u8f83\u3002 # \u6700\u540e\u4e00\u884c\u662f\u7a7a\u884c $ cat f1 a b 1 c # \u6700\u540e\u4e00\u884c\u662f\u7a7a\u884c $ cat f2 b e f c 1 2 # \u9ad8\u4eae\u663e\u793a\u76f8\u540c\u5185\u5bb9\u7684\u884c\uff0c\u5305\u542b\u6700\u540e\u4e00\u884c\u7a7a\u884c $ grep -f f1 f2 b e f c 1 2 # \u53ea\u663e\u793a\u76f8\u540c\u5185\u5bb9\u7684\u884c\uff0c\u5305\u542b\u6700\u540e\u4e00\u884c\u7a7a\u884c $ grep -wf f1 f2 b c 1 # \u53ea\u663e\u793a\u4e0d\u540c\u5185\u5bb9\u7684\u884c $ grep -wvf f1 f2 e f 2 \u63d0\u793a\uff1a grep -wvf f1 f2 \u6216\u8005 grep -w -v -f f1 f2 \u4e2d\uff0c -f \u53ea\u80fd\u4f5c\u4e3a\u6700\u540e\u4e00\u4e2a\u53c2\u6570\uff0c\u5426\u5219\u4f1a\u62a5\u9519\u3002 \u4f53\u4f1a\u57fa\u672c\u6b63\u5219\u548c\u6269\u5c55\u6b63\u5219\u7684\u5dee\u5f02\u3002 \u4f8b1\uff1a\u8f6c\u4e49\u3002 # \u4e0b\u9762\u51e0\u4e2a\u547d\u4ee4\u8fd4\u56de\u7684\u7ed3\u679c\u662f\u4e00\u6837\u7684\u3002 $ grep \"root\\|bash\" /etc/passwd $ grep -E \"root|bash\" /etc/passwd $ grep -e \"root\" -e \"bash\" /etc/passwd # \u4e0b\u9762\u7684\u547d\u4ee4\u6ca1\u6709\u5339\u914d\u7ed3\u679c\u8fd4\u56de\u3002 $ grep \"root|bash\" /etc/passwd \u4f8b2\uff1a\u4e0b\u97624\u4e2a\u547d\u4ee4\u8fd4\u56de\u540c\u6837\u7684\u7ed3\u679c\u3002 grep \"root\" /etc/passwd grep -E \"root\" /etc/passwd grep \"\\\" /etc/passwd grep -E \"\\\" /etc/passwd \u4f8b3\uff1a\u884c\u9996\u884c\u5c3e\u951a\u5b9a\u3002 $ grep \"^\\(.*\\)\\>.*\\<\\1 $ \" /etc/passwd $ grep -E \"^(.*)\\>.*\\<\\1 $ \" /etc/passwd $ egrep \"^(.*)\\>.*\\<\\1 $ \" /etc/passwd sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt \u4f8b4\uff1a\u4e09\u79cd\u65b9\u6cd5\u6c42\u548c\u8ba1\u7b97\uff0c\u8fd0\u7528 grep \uff0c cut \uff0c bc \u548c paste \u547d\u4ee4\u3002 $cat age Jason = 20 Tom = 30 Jack = 40 # \u65b9\u6cd51 $ cat age | cut -d \"=\" -f 2 | tr \"\\n\" + | grep -Eo \".*[0-9]\" | bc 90 # \u65b9\u6cd52 $ grep -Eo \"[0-9]+\" age | tr \"\\n\" + | grep -Eo \".*[0-9]\" | bc 90 # \u65b9\u6cd53 $ grep -Eo \"[0-9]+\" age | paste -s -d \"+\" | bc 90 5.9.\u4e09\u5251\u5ba2 sed \u547d\u4ee4 \u00b6 sed \u662fstream editor\u7684\u7f29\u5199\uff0c\u4e2d\u6587\u79f0\u4e4b\u4e3a\u201c\u6d41\u7f16\u8f91\u5668\u201d\u3002 sed \u547d\u4ee4\u662f\u4e00\u4e2a\u9762\u5411\u884c\u5904\u7406\u7684\u5de5\u5177\uff0c\u5b83\u4ee5\u201c\u884c\u201d\u4e3a\u5904\u7406\u5355\u4f4d\uff0c\u9488\u5bf9\u6bcf\u4e00\u884c\u8fdb\u884c\u5904\u7406\uff0c\u5904\u7406\u540e\u7684\u7ed3\u679c\u4f1a\u8f93\u51fa\u5230\u6807\u51c6\u8f93\u51fa STDOUT \uff0c\u4e0d\u4f1a\u5bf9\u8bfb\u53d6\u7684\u6587\u4ef6\u505a\u4efb\u4f55\u4fee\u6539\u3002 sed \u7684\u5de5\u4f5c\u539f\u7406\uff1a sed \u547d\u4ee4\u662f\u9762\u5411\u201c\u884c\u201d\u8fdb\u884c\u5904\u7406\u7684\uff0c\u6bcf\u4e00\u6b21\u5904\u7406\u4e00\u884c\u5185\u5bb9\u3002 \u5904\u7406\u65f6\uff0c sed \u4f1a\u628a\u8981\u5904\u7406\u7684\u884c\u5b58\u50a8\u5728\u7f13\u51b2\u533a\u4e2d\uff0c\u63a5\u7740\u7528 sed \u547d\u4ee4\u5904\u7406\u7f13\u51b2\u533a\u4e2d\u7684\u5185\u5bb9\uff0c\u5904\u7406\u5b8c\u6210\u540e\uff0c\u628a\u7f13\u51b2\u533a\u7684\u5185\u5bb9\u9001\u5f80\u5c4f\u5e55\u3002\u63a5\u7740\u5904\u7406\u4e0b\u4e00\u884c\uff0c\u8fd9\u6837\u4e0d\u65ad\u91cd\u590d\uff0c\u76f4\u5230\u6587\u4ef6\u672b\u5c3e\u3002\u8fd9\u4e2a\u7f13\u51b2\u533a\u88ab\u79f0\u4e3a\u201c \u6a21\u5f0f\u7a7a\u95f4 \u201d\uff08pattern space\uff09\u3002 \u4fdd\u6301\u7a7a\u95f4(hold space) sed \u7684\u4fdd\u6301\u7a7a\u95f4\u50cf\u4e00\u4e2a\u957f\u671f\u50a8\u5b58\uff0c \u53ef\u4ee5\u628a\u83b7\u53d6\u7684\u4fe1\u606f\u50a8\u5b58\u5230\u5176\u4e2d\uff0c\u5f85\u540e\u7eed\u8c03\u7528\u3002\u4e0d\u80fd\u76f4\u63a5\u5bf9\u4fdd\u6301\u7a7a\u95f4\u8fdb\u884c\u64cd\u4f5c\uff0c \u800c\u662f\u5c06\u4fdd\u6301\u7a7a\u95f4\u7684\u5185\u5bb9\u590d\u5236\u6216\u8005\u6dfb\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u8fdb\u884c\u64cd\u4f5c\u3002 \u975e\u4ea4\u4e92\u5f0f\u6279\u91cf\u4fee\u6539\u6587\u4ef6\u3002 sed \u547d\u4ee4\u683c\u5f0f\uff1a sed [ option ] command file option \u5e38\u7528\u9009\u9879\uff1a -n \uff1a\u4e0d\u8f93\u51fa\u6a21\u5f0fpattern\u7684\u5185\u5bb9\u5230\u5c4f\u5e55\uff08\u5373\u4e0d\u81ea\u52a8\u6253\u5370\uff09 -e \uff1a\u591a\u70b9\u7f16\u8f91 -f filename \uff1a\u4ece\u6307\u5b9a\u6587\u4ef6\u8bfb\u53d6\u7f16\u8f91\u811a\u672c -r \uff0c -E \uff1a\u4f7f\u7528\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f -i .bak \uff1a\u5907\u4efd\u6587\u4ef6\u5e76\u539f\u5904\u7f16\u8f91 -s \uff1a\u5c06\u591a\u4e2a\u6587\u4ef6\u89c6\u4e3a\u72ec\u7acb\u6587\u4ef6\uff0c\u800c\u4e0d\u662f\u5355\u4e2a\u8fde\u7eed\u7684\u957f\u6587\u4ef6\u6d41 -ir \uff1a \u4e0d\u652f\u6301 -i -r \uff1a \u652f\u6301 -ri \uff1a \u652f\u6301 -ni \uff1a \u5371\u9669\u9009\u9879\uff0c\u4f1a\u6e05\u7a7a\u6587\u4ef6 command \u90e8\u5206\u53ef\u4ee5\u5206\u4e3a\u4e24\u90e8\u5206\uff1a \u8303\u56f4\u8bbe\u5b9a\uff0c\u53ef\u4ee5\u91c7\u7528\u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u6765\u8868\u8fbe\uff1a \u6307\u5b9a\u884c\u6570\uff1a\u5982\uff1a 3,5 \u8868\u793a\u7b2c3\u30014\u30015\u884c 5,$ \u8868\u793a\u7b2c5\u884c\u81f3\u6587\u4ef6\u6700\u540e\u4e00\u884c \u6a21\u5f0f\u5339\u914d\uff1a\u5982\uff1a /^[^dD]/ \u8868\u793a\u5339\u914d\u884c\u9996\u4e0d\u662f\u4ee5 d \u6216 D \u5f00\u5934\u7684\u884c \u52a8\u4f5c\u5904\u7406\uff0c\u4e0b\u9762\u662f\u5e38\u7528\u7684\u52a8\u4f5c\uff1a a \uff1a\u65b0\u589e\uff0c a \u540e\u9762\u7684\u5b57\u4e32\u4f1a\u5728\u65b0\u7684\u4e00\u884c\u51fa\u73b0\uff08\u5f53\u524d\u884c\u7684\u4e0b\u4e00\u884c\uff09 i \uff1a\u63d2\u5165\uff0c i \u540e\u9762\u7684\u5b57\u4e32\u4f1a\u5728\u65b0\u7684\u4e00\u884c\u51fa\u73b0\uff08\u5f53\u524d\u884c\u7684\u4e0a\u4e00\u884c\uff09 r filename \uff1a\u8bfb\u53d6\u6307\u5b9a\u6587\u4ef6 fllename \u7684\u5185\u5bb9\uff0c\u8ffd\u52a0\u5230\u5f53\u524d\u884c\u7684\u4e0b\u4e00\u884c R filename \uff1a\u8bfb\u53d6\u6307\u5b9a\u6587\u4ef6 fllename \u7684\u4e00\u884c\uff0c\u8ffd\u52a0\u5230\u5f53\u524d\u884c\u7684\u4e0b\u4e00\u884c d \uff1a\u5220\u9664\u8be5\u884c p \uff1a\u6253\u5370\u8be5\u884c Ip \uff1a\u5ffd\u7565\u5927\u5c0f\u5199\u8f93\u51fa w filename \uff1a\u5199\u5165\u5230\u6307\u5b9a\u6587\u4ef6filename\u4e2d\u3002 s/regexp/replacement/ \uff1a\u53d6\u4ee3\uff0c\u7528replacement\u53d6\u4ee3\u6b63\u5219regexp\u5339\u914d\u5230\u7684\u5185\u5bb9 = \uff1a\u4e3a\u6a21\u5f0fpattern\u4e2d\u7684\u5339\u914d\u884c\u6253\u5370\u884c\u53f7 ! \uff1a\u4e3a\u6a21\u5f0fpattern\u4e2d\u7684\u5339\u914d\u884c\u53d6\u53cd\u64cd\u4f5c q \uff1a\u7ed3\u675f\u6216\u9000\u51fased \u521b\u5efa\u4e00\u4e2a testfile \u6587\u4ef6\u3002 $ cat < testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob Tesetfile Wiki EOF \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u7b2c\u4e8c\u884c\uff0c\u5e76\u8f93\u51fa\uff08\u5305\u542b\u5339\u914d\u7b2c\u4e8c\u884c\u548c\u8f93\u51fa\u7b2c\u4e8c\u884c\uff09\u3002 # nl testfile | sed '2p' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u7b2c\u4e8c\u884c\uff0c\u4e0d\u8f93\u51fa\u3002 # nl testfile | sed -n '2p' 2 Linux is a free unix-type opterating system. \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u6700\u540e\u4e00\u884c\u3002 $ nl testfile | sed -n '$p' 9 Wiki \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u5012\u6570\u7b2c\u4e8c\u884c\u3002 # sed -n \"$(echo $[`cat testfile | wc -l`-1])p\" testfile Tesetfile \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u7b2c2\uff5e3\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\u3002 $ nl testfile | sed -n '2,3p' 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! \u5c06 testfile \u7684\u5185\u5bb9\u4ece\u7b2c2\u884c\u5f00\u59cb\uff0c\u5411\u540e\u8f93\u51fa\u989d\u5916\u76843\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\u3002 $ nl testfile | sed -n '2,+3p' 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test 5 Google \u5c06 testfile \u7684\u5185\u5bb9\u4ece\u7b2c2\u884c\u5f00\u59cb\uff0c\u5411\u540e\u4ee52\u4e3a\u6b65\u8fdb\u5355\u4f4d\u8f93\u51fa\u6240\u6709\u5339\u914d\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff08\u5373\uff0c\u4ece\u7b2c2\u884c\u5f00\u59cb\u8f93\u51fa\u5076\u6570\u884c\uff09\u3002 nl testfile | sed -n '2~2p' 2 Linux is a free unix-type opterating system. 4 Linux test 6 Taobao 8 Tesetfile \u5c06 testfile \u7684\u5185\u5bb9\u4ece\u7b2c2\u884c\u5f00\u59cb\uff0c\u5411\u540e\u4ee52\u4e3a\u6b65\u8fdb\u5355\u4f4d\u5220\u9664\u6240\u6709\u5339\u914d\u884c\uff0c\u8f93\u51fa\u5269\u4f59\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff08\u5373\uff0c\u4ece\u7b2c2\u884c\u5f00\u59cb\u5220\u9664\u5076\u6570\u884c\uff0c\u8f93\u51fa\u5947\u6570\u884c\uff09\u3002 $ nl testfile | sed '2~2d' 1 HELLO LINUX! 3 This is a linux testfile! 5 Google 7 Banbooob 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u8f93\u51fa\uff0c\u5220\u9664\u7b2c2\u884c\u548c\u7b2c5\u884c\uff0c\u5e76\u6253\u5370\u884c\u53f7\u3002 $ nl testfile | sed -e '2d' -e '5d' $ nl testfile | sed -e '2d;5d' $ nl testfile | sed '2d;5d' 1 HELLO LINUX! 3 This is a linux testfile! 4 Linux test 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u8f93\u51fa\uff0c\u8f93\u51fa\u533a\u95f4\u662f\u4ece\u884c\u9996 L \u7684\u884c\u5230\u884c\u9996 G \u7684\u884c\u7ed3\u675f\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 \u5982\u679c\u884c\u9996\u5339\u914d\u4e0d\u5230\uff0c\u5219\u65e0\u7ed3\u679c\u8f93\u51fa\uff1b\u5982\u679c\u884c\u5c3e\u5339\u914d\u4e0d\u5230\uff0c\u5219\u8f93\u51fa\u5230\u6587\u4ef6\u7ed3\u675f\u3002 $ sed -n '/^L/,/^G/p' testfile Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google \u5c06 testfile \u7684\u5185\u5bb9\u8f93\u51fa\uff0c\u4e14\u5728\u7b2c6\u884c\u540e\u52a0\u4e0a I love Linux \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -e '6a I love Linux' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao I love Linux Banbooob Tesetfile Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5728\u7b2c6\u884c\u540e\u6dfb\u52a0 I love Linux \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '6a I love Linux' $ nl testfile | sed '6a\\I love Linux' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao I love Linux 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5728\u7b2c3\u884c\u524d\u6dfb\u52a0 I am a journer learner \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '3i\\I am a journer learner' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. I am a journer learner 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5728\u7b2c3\u884c\u524d\u6dfb\u52a0\u4e09\u884c\u5185\u5bb9 Add line 1 \uff0c Add line 2 \uff0c Add line 3 \u3002\u7528\u7b26\u5408 \\ \u8fdb\u884c\u6362\u884c\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '3i\\Add line 1 \\ Add line 2 \\ Add line 3' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. Add line 1 Add line 2 Add line 3 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5c06\u7b2c2-5\u884c\u7684\u5185\u5bb9\u53d6\u4ee3\u6210\u4e3a replaced \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '2,5c\\replaced' $ nl testfile | sed '2,5c replaced' $ nl testfile | sed '2,5creplaced' 1 HELLO LINUX! replaced 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5220\u9664\u7b2c2~5\u884c\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '2,5d' 1 HELLO LINUX! 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5220\u9664\u7b2c5\u884c\u5230\u6700\u540e\u4e00\u884c\u3002 $ nl testfile | sed '5,$d' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u4e2d\u5305\u542b\u5173\u952e\u5b57 linux \u7684\u884c\u3002 $ sed -n '/linux/p' testfile This is a linux testfile! \u5339\u914d\u5b9a\u4f4d\u547d\u4ee4 df \u8f93\u51fa\u4e2d\u4ee5 /dev/sd \u5173\u952e\u5b57\u5f00\u5934\u7684\u884c\u3002\uff08\u9700\u8981\u8f6c\u4e49\u7b26 \\ \uff09 $ df | sed -n '/^\\/dev\\/sd/p' /dev/sda2 102750208 7077280 92055312 8 % / /dev/sda2 102750208 7077280 92055312 8 % /.snapshots /dev/sda2 102750208 7077280 92055312 8 % /home /dev/sda2 102750208 7077280 92055312 8 % /opt /dev/sda2 102750208 7077280 92055312 8 % /root /dev/sda2 102750208 7077280 92055312 8 % /boot/grub2/x86_64-efi /dev/sda2 102750208 7077280 92055312 8 % /boot/grub2/i386-pc /dev/sda2 102750208 7077280 92055312 8 % /srv /dev/sda2 102750208 7077280 92055312 8 % /tmp /dev/sda2 102750208 7077280 92055312 8 % /usr/local /dev/sda2 102750208 7077280 92055312 8 % /var \u5339\u914d\u5b9a\u4f4d\u547d\u4ee4 df \u8f93\u51fa\u4e2d\u4e0d\u4ee5 /dev/sd \u5173\u952e\u5b57\u5f00\u5934\u7684\u884c\u3002\u901a\u8fc7 !p \u8fdb\u884c\u6c42\u53cd\u8f93\u51fa\u3002 $ df | sed -n '/^\\/dev\\/sd/!p' Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 4096 0 4096 0 % /dev tmpfs 1971208 0 1971208 0 % /dev/shm tmpfs 788484 9612 778872 2 % /run tmpfs 4096 0 4096 0 % /sys/fs/cgroup tmpfs 394240 0 394240 0 % /run/user/1000 \u5339\u914d\u5b9a\u4f4d\u547d\u4ee4 df \u8f93\u51fa\u4e2d\u4e0d\u4ee5 /dev/sd \u548c tmp \u5173\u952e\u5b57\u5f00\u5934\u7684\u884c\u3002 $ df | sed '/^\\/dev\\/sd/d;/^tmp/d' Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 4096 0 4096 0 % /dev $ df | grep -Ev '^\\/dev\\/sd|^tmp' Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 4096 0 4096 0 % /dev \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b oo \u5173\u952e\u5b57\u7684\u884c\u5e76\u5339\u914d\u8f93\u51fa\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -n '/ooo/p' testfile Banbooob $ sed -n '/oo/p' testfile Google Banbooob \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b oo \u5173\u952e\u5b57\u7684\u884c\u5e76\u5220\u9664\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed '/oo/d' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Taobao Tesetfile Wiki \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b oo \u7684\u884c\uff0c\u628a oo \u66ff\u6362\u4e3a kk \uff0c\u518d\u8f93\u51fa\u8fd9\u884c\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -n '/oo/{s/oo/kk/;p;q}' testfile $ sed -ne '/oo/{s/oo/kk/;p;q}' testfile Gkkgle \u5c06 testfile \u7684\u6bcf\u884c\u4e2d\u7b2c\u4e00\u6b21\u51fa\u73b0 ao \u7684\u66ff\u6362\u6210 HH \u3002 $ sed 's/ao/HH/' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbao Banbooob Tesetfile Wiki \u4e0b\u9762\u662f\u628a testfile \u7684\u5339\u914d\u5230 ao \u7684\u884c\u66ff\u6362\u6210 HH \u3002 sed '/ao/cHH' testfile HELLO LINUX! SUSE This is a linux testfile! SUSE Google Taobao Banbooob Tesetfile Wiki \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b ao \u7684\u5168\u90e8\u66ff\u6362\u6210 HH \u3002 g \u8868\u793a\u5168\u5c40\u5339\u914d\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -e 's/ao/HH/g' testfile $ sed 's/ao/HH/g' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbHH Banbooob Tesetfile Wiki \u5728\u6587\u4ef6 /etc/passwd \u4e2d\u67e5\u627e\u5339\u914d\u6240\u6709\u7b26\u5408 r \u5f00\u5934 t \u7ed3\u5c3e\u4e14\u4e2d\u95f4\u542b\u4efb\u610f\u4e24\u4e2a\u5b57\u7b26\u7684\u884c\uff0c\u5e76\u5728 t \u5b57\u6bcd\u540e\u6dfb\u52a0 er \u3002 $ sed -nr 's/r..t/&er/gp' /etc/passwd rooter:x:0:0:rooter:/rooter:/bin/bash lp:x:493:487:Printering daemon:/var/spool/lpd:/usr/sbin/nologin tftp:x:487:474:TFTP account:/srv/terftpboot:/bin/false vagranter:x:1000:478:vagranter:/home/vagranter:/bin/bash tester1:x:600:1530: \"Test User1,terestuser1@abc.com\" :/home/tester1:/bin/bash \u5c06\u4e0a\u8ff0\u7ed3\u679c\u548c\u539f\u59cb\u5185\u5bb9\u8fdb\u884c\u5bf9\u6bd4\uff0c\u80fd\u66f4\u597d\u7684\u7406\u89e3 s/r..t/&er \u7684\u64cd\u4f5c\u3002 rooter:x:0:0:rooter:/rooter:/bin/bash root:x:0:0:root:/root:/bin/bash lp:x:493:487:Printering daemon:/var/spool/lpd:/usr/sbin/nologin lp:x:493:487:Printing daemon:/var/spool/lpd:/usr/sbin/nologin tftp:x:487:474:TFTP account:/srv/terftpboot:/bin/false tftp:x:487:474:TFTP account:/srv/tftpboot:/bin/false vagranter:x:1000:478:vagranter:/home/vagranter:/bin/bash vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash tester1:x:600:1530: \"Test User1,terestuser1@abc.com\" :/home/tester1:/bin/bash tester1:x:600:1530: \"Test User1,testuser1@abc.com\" :/home/tester1:/bin/bash \u4f53\u4f1a & \u7684\u4f4d\u7f6e\u4e0d\u540c\u7684\u4e0d\u540c\u542b\u4e49\u3002 # \u9644\u52a0\u5728root\u5355\u8bcd\u540e $ sed -n 's/root/&superman/p' /etc/passwd rootsuperman:x:0:0:root:/root:/bin/bash # \u9644\u52a0\u5728root\u5355\u8bcd\u524d $ sed -n 's/root/superman&/p' /etc/passwd supermanroot:x:0:0:root:/root:/bin/bash \u4f7f\u7528\u53c2\u6570 -i \u8fdb\u884c\u6e90\u6587\u4ef6\u4fee\u6539\u3002 $ sed -i 's/ao/HH/' testfile $ cat testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbao Banbooob Tesetfile Wiki \u6e90\u6587\u4ef6\u4fee\u6539\u524d\uff0c\u5907\u4efd\u5728\u65b0\u6587\u4ef6 testfile.new \u3002 $ sed -i.new 's/ao/HH/' testfile $ cat testfile.new HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob Tesetfile Wiki $ cat testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbao Banbooob Tesetfile Wiki \u8303\u4f8b\uff1a\u9664\u6307\u5b9a\u6587\u4ef6\u5916\uff0c\u5176\u4f59\u90fd\u5220\u9664\u3002 $ touch { 1 ..9 } file.txt $ ls 1file.txt 2file.txt 3file.txt 4file.txt 5file.txt 6file.txt 7file.txt 8file.txt 9file.txt $ ls | grep -E '(3|5|7)file\\.txt' 3file.txt 5file.txt 7file.txt $ ls | grep -Ev '(3|5|7)file\\.txt' 1file.txt 2file.txt 4file.txt 6file.txt 8file.txt 9file.txt \u4e0b\u9762\u56db\u79cd\u65b9\u6cd5\u5b9e\u73b0\u540c\u6837\u7684\u529f\u80fd $ rm ` ls | grep -Ev '(3|5|7)file\\.txt' ` $ ls | sed -n '/^[357]file.txt/!p' | xargs rm $ ls | grep -Ev '(3|5|7)file\\.txt' | sed -n 's/.*/rm &/p' | bash $ ls | grep -Ev '(3|5|7)file\\.txt' | sed -En 's/(.*)/rm &/p' | bash $ ls | grep -Ev '(3|5|7)file\\.txt' | sed -En 's/(.*)/rm \\1/p' | bash $ ls 3file.txt 5file.txt 7file.txt \u540e\u5411\u5f15\u7528 \\0 \\1 \\2 \u7b49\u3002 $ $echo 123456789 | sed -nE 's/(123)(456)(789)/\\1/p' 123 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\2/p' 456 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\3/p' 789 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\3\\1\\2/p' 789123456 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\1xyz\\2/p' 123xyz456 \u8303\u4f8b\uff1a\u83b7\u53d6\u5206\u533a\u5229\u7528\u7387 $ df | sed -En '/^\\/dev\\/sd/p' /dev/sda2 102750208 7079236 92053692 8 % / /dev/sda2 102750208 7079236 92053692 8 % /.snapshots /dev/sda2 102750208 7079236 92053692 8 % /boot/grub2/i386-pc /dev/sda2 102750208 7079236 92053692 8 % /boot/grub2/x86_64-efi /dev/sda2 102750208 7079236 92053692 8 % /home /dev/sda2 102750208 7079236 92053692 8 % /opt /dev/sda2 102750208 7079236 92053692 8 % /root /dev/sda2 102750208 7079236 92053692 8 % /srv /dev/sda2 102750208 7079236 92053692 8 % /usr/local /dev/sda2 102750208 7079236 92053692 8 % /tmp /dev/sda2 102750208 7079236 92053692 8 % /var $ df | sed -En '/^\\/dev\\/sd/s@.*([0-9]+)%.*@\\1@p' $ df | sed -En '/^\\/dev\\/sd/s#.*([0-9]+)%.*#\\1#p' # df | sed -En '/^\\/dev\\/sd/s/.*([0-9]+)%.*/\\1/p' 8 8 8 8 8 8 8 8 8 8 8 \u4f53\u4f1a\u4e0b\u9762\u7a7a\u683c\u548c\u62ec\u5f27\u5e26\u6765\u7684\u4e0d\u540c\u3002 $ df | sed -En '/^\\/dev\\/sd/s# .*([0-9]+)%.*# \\1#p' /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 $ df | sed -En '/^\\/dev\\/sd/s#( .*)([0-9]+)%.*# \\1#p' /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 $ df | sed -En '/^\\/dev\\/sd/s#( .*)([0-9]+)%.*# \\2#p' /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 \u8303\u4f8b\uff1a\u53d6\u5f97\u5f53\u524dIP\u5730\u5740\u3002 $ ifconfig eth0 eth0: flags = 4163 mtu 1500 inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 inet6 fe80::20c:29ff:fea4:e17a prefixlen 64 scopeid 0x20 ether 00 :0c:29:a4:e1:7a txqueuelen 1000 ( Ethernet ) RX packets 22923 bytes 1658298 ( 1 .5 MiB ) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3763 bytes 442641 ( 432 .2 KiB ) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 $ ip addr show eth0 2 : eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00 :0c:29:a4:e1:7a brd ff:ff:ff:ff:ff:ff altname enp2s1 altname ens33 inet 192 .168.10.210/24 brd 192 .168.10.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::20c:29ff:fea4:e17a/64 scope link valid_lft forever preferred_lft forever $ ifconfig eth0 | sed -En '2s/[^0-9]+([0-9.]+).*/\\1/p' $ ifconfig eth0 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*/\\1/p' $ ifconfig eth0 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*$/\\1/p' $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.*//p' $ ifconfig eth0 | sed -n '2s/^.*inet //;s/ netmask.*//p' $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\2/p' 192 .168.10.210 192 .168.10.210 192 .168.10.210 \u4f7f\u7528 \\0 \u8f93\u51fa\u5168\u90e8\u53d8\u91cf\u3002 $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\0/p' inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\1/p' inet $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\2/p' 192 .168.10.210 $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\3/p' netmask 255 .255.255.0 broadcast 192 .168.10.255 \u5bf9\u6bd4\u4e0b\u9762\u4e24\u4e2a\u6307\u4ee4\u7684\u5339\u914d\u5dee\u5f02\u3002 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/ netmask.*//p' 192 .168.10.210 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.* //p' 192 .168.10.210 192 .168.10.255 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask .*//p' 192 .168.10.210 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.*//p' 192 .168.10.210 \u8303\u4f8b\uff1a\u53d6\u57fa\u540d\u548c\u76ee\u5f55\u540d\u3002 \uff08 /etc/sysconfig/network-scripts/ \u76ee\u5f55\u5728Rocky9\u4e2d\u9ed8\u8ba4\u5df2\u521b\u5efa\uff0c\u5728openSUSE\u548cUbuntu\u4e2d\u6ca1\u6709\uff09 # \u53d6\u76ee\u5f55\u540d $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's#(^/.*/)([^/]+/?)#\\1#' $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\1/' /etc/sysconfig/ # \u53d6\u57fa\u540d $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's#(^/.*/)([^/]+/?)#\\2#' $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\2/' network-scripts/ # \u53d6\u76ee\u5f55\u540d $ echo \"/etc/sysconfig/network-scripts/dummyfile\" | sed -E 's#(^/.*/)([^/]+/?)#\\1#' $ echo \"/etc/sysconfig/network-scripts/dummyfille\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\1/' /etc/sysconfig/network-scripts/ # \u53d6\u57fa\u540d $ echo \"/etc/sysconfig/network-scripts/dummyfile\" | sed -E 's#(^/.*/)([^/]+/?)#\\2#' $ echo \"/etc/sysconfig/network-scripts/dummyfille\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\2/' dummyfille \u8303\u4f8b\uff1a\u53d6\u6587\u4ef6\u540d\u548c\u6587\u4ef6\u6269\u5c55\u540d $ echo 1_.file.tar.gz | sed -En 's/(.*)\\.([^.]+)$/\\1/p' $ echo 1_.file.tar.gz | sed -En 's@(.*)\\.([^.]+)$@\\1@p' 1_.file.tar $ echo 1_.file.tar.gz | sed -En 's/(.*)\\.([^.]+)$/\\2/p' $ echo 1_.file.tar.gz | sed -En 's@(.*)\\.([^.]+)$@\\2@p' gz $ echo 1_.file.tar.gz | grep -Eo '.*\\.' 1_.file.tar. $ echo 1_.file.tar.gz | grep -Eo '[^.]+$' gz \u8303\u4f8b\uff1a\u5c06\u975e # \u5f00\u5934\u7684\u884c\u6dfb\u52a0 # $ cat < testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob #Tesetfile #Wiki EOF $ sed -En 's/^[^#]/#&/p' testfile $ sed -En 's/^[^#](.*)/#\\1/p' testfile #HELLO LINUX! #Linux is a free unix-type opterating system. #This is a linux testfile! #Linux test #Google #Taobao #Banbooob \u8303\u4f8b\uff1a\u5c06 # \u5f00\u5934\u7684\u884c\u5220\u9664 # $ cat < testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob #Tesetfile #Wiki EOF $ sed -Ei.bak '/^#/s/^#//' testfile $ cat testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob Tesetfile Wiki sed \u4fdd\u6301\u7a7a\u95f4\uff08hold space\uff09\u7684\u4f8b\u5b50\uff1a d \uff1a\u5220\u9664pattern space\u7684\u5185\u5bb9\uff0c\u5f00\u59cb\u4e0b\u4e00\u4e2a\u5faa\u73af\u3002 D \uff1a\u5982\u679c\u6a21\u5f0f\u7a7a\u95f4\u4fdd\u62a4\u6362\u884c\u7b26\uff0c\u5219\u5220\u9664\u76f4\u5230\u7b2c\u4e00\u4e2a\u6362\u884c\u7b26\u5230\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u7684\u6587\u672c\uff0c\u5e76\u4e0d\u8bfb\u53d6\u65b0\u7684\u8f93\u5165\u884c\uff0c\u800c\u4f7f\u7528\u5408\u6210\u7684\u6a21\u5f0f\u7a7a\u95f4\u91cd\u65b0\u542f\u52a8\u5faa\u73af\u3002\u5982\u679c\u6a21\u5f0f\u7a7a\u95f4\u4e0d\u5305\u542b\u6362\u884c\u7b26\uff0c\u5219\u7c7b\u4f3c d \u547d\u4ee4\u542f\u52a8\u6b63\u5e38\u7684\u65b0\u5faa\u73af\u3002 h \u3001 H \uff1a\u590d\u5236/\u8ffd\u52a0\u6a21\u5f0f\u7a7a\u95f4\u7684\u5185\u5bb9\u5230\u4fdd\u6301\u7a7a\u95f4\u3002 g \u3001 G \uff1a\u590d\u5236/\u8ffd\u52a0\u4fdd\u6301\u7a7a\u95f4\u7684\u5185\u5bb9\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002 n \u3001 N \uff1a\u590d\u5236/\u8ffd\u52a0\u5339\u914d\u5230\u7684\u4e0b\u4e00\u884c\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002 p\uff1a\u6253\u5370\u5f53\u524d\u6a21\u5f0f\u7a7a\u95f4\u5185\u5bb9\u3002 P\uff1a\u6253\u5370\u6a21\u5f0f\u7a7a\u95f4\u5f00\u5934\u81f3 \\n \u7684\u5185\u5bb9\uff0c\u5e76\u8ffd\u52a0\u5230\u9ed8\u8ba4\u8f93\u51fa\u4e4b\u524d\u3002 x \uff1a\u4ea4\u6362\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u7684\u5185\u5bb9. \u4e3e\u4f8b\u89e3\u8bfb1\uff1a seq 10 \u547d\u4ee4\u8f93\u51fa1\uff5e10\u4e2a\u6570\u5b57\uff0c\u6bcf\u4e2a\u6570\u5b57\u4e00\u884c\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e00\u884c 1 \u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u56e0\u4e3a\u53c2\u6570 -n \uff0c\u6240\u4ee5\u8bfb\u53d6\u5230\u7684 1 \u4e0d\u6253\u5370\u5230\u5c4f\u5e55\u3002 \u6267\u884c n \u547d\u4ee4\uff0c\u5373\u8bfb\u53d6\u5339\u914d\u5230\u7684\u4e0b\u4e00\u884c\u5230\u6a21\u5f0f\u7a7a\u95f4\uff0c\u5373\u628a\u7b2c\u4e8c\u884c\u7684 2 \u8bfb\u53d6\u5e76\u8986\u76d6\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002 \u6267\u884c p \u547d\u4ee4\uff0c\u628a 2 \u8f93\u51fa\u5230\u5c4f\u5e55\u3002 \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8bfb\u53d6\u7b2c\u4e09\u884c\u7684 3 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff0c\u6267\u884c n \u547d\u4ee4\uff0c\u5c06\u7b2c\u56db\u884c\u7684 4 \u8bfb\u53d6\u5e76\u8986\u76d6\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u6267\u884c p \u547d\u4ee4\uff0c\u8f93\u51fa 4 \u5230\u5c4f\u5e55\u3002 \u4ee5\u6b64\u7c7b\u63a8\u3002 $ seq 10 | sed -n 'n;p' 2 4 6 8 10 seq 10 | sed 'n;p' 1 2 2 3 4 4 5 6 6 7 8 8 9 10 10 \u4e3e\u4f8b\u89e3\u8bfb2\uff1a seq 10 \u547d\u4ee4\u8f93\u51fa1\uff5e10\u4e2a\u6570\u5b57\uff0c\u6bcf\u4e2a\u6570\u5b57\u4e00\u884c\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e00\u884c\u5230 1 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c\u547d\u4ee4 N \uff0c\u5373\u8bfb\u53d6\u4e0b\u4e00\u884c\uff0c\u5373\u7b2c\u4e8c\u884c\u7684 2 \uff0c\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u6240\u4ee5\u5f53\u524d\u6a21\u5f0f\u7a7a\u95f4\u6709 1 \u548c 2 \u8fd92\u884c\u8bb0\u5f55\u3002 \u6267\u884c s/\\n// \uff0c\u628a\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u7684\u7b2c\u4e00\u884c\u7684 1 \u540e\u9762\u7684 \\n \u66ff\u6362\u4e3a\u7a7a\uff0c\u5373\uff0c\u539f\u6765\u6a21\u5f0f\u7a7a\u95f4\u7684\u4e24\u884c 1 \u548c 2 \u73b0\u5728\u5408\u5e76\u4e3a\u4e00\u884c\uff0c\u5373 12 \u3002 \u8bfb\u53d6\u7b2c\u4e09\u884c\u7684 3 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c\u547d\u4ee4 N \uff0c\u5373\u8bfb\u53d6\u4e0b\u4e00\u884c\uff0c\u5373\u7b2c\u56db\u884c\u7684 4 \uff0c\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u6240\u4ee5\u5f53\u524d\u6a21\u5f0f\u7a7a\u95f4\u6709 3 \u548c 4 \u8fd92\u884c\u8bb0\u5f55\u3002 \u6267\u884c s/\\n// \uff0c\u628a\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u7684\u7b2c\u4e00\u884c 3 \u540e\u9762\u7684 \\n \u66ff\u6362\u4e3a\u7a7a\uff0c\u5373\uff0c\u539f\u6765\u6a21\u5f0f\u7a7a\u95f4\u7684\u4e24\u884c 3 \u548c 4 \u73b0\u5728\u5408\u5e76\u4e3a\u4e00\u884c\uff0c\u5373 34 \u3002 \u4ee5\u6b64\u7c7b\u63a8\u3002 $ seq 10 | sed 'N;s/\\n//' 12 34 56 78 910 \u4e3e\u4f8b\u89e3\u8bfb3\uff1a seq 10 \u547d\u4ee4\u8f93\u51fa1\uff5e10\u4e2a\u6570\u5b57\uff0c\u6bcf\u4e2a\u6570\u5b57\u4e00\u884c\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e00\u884c\u5230 1 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c !G \uff0c\u5373\u5bf9\u7b2c\u4e00\u884c\u7684 1 \u4e0d\u6267\u884c G \u547d\u4ee4\u3002 \u6267\u884c h \u547d\u4ee4\uff0c\u5373\u628a 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u8986\u76d6\u81f3\u4fdd\u6301\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u90fd\u5b58\u6709 1 \u3002 \u6267\u884c $!d \uff0c\u5373\u4e0d\u662f\u6700\u540e\u4e00\u884c\u5c31\u4ece\u6a21\u5f0f\u7a7a\u95f4\u5220\u9664\uff0c\u6240\u4ee5\u628a 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u5220\u9664\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e8c\u884c\u5230 2 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c !G \uff0c\u5373\u5bf9\u7b2c\u4e8c\u884c\u7684 2 \u6267\u884c G \u547d\u4ee4\uff0c\u628a 1 \u4ece\u4fdd\u6301\u7a7a\u95f4\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u5b58\u6709 1 \uff0c\u6a21\u5f0f\u7a7a\u95f4\u5b58\u6709 2 \u548c 1 \u3002 \u6267\u884c h \u547d\u4ee4\uff0c\u5373\u628a 2 \u548c 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u8986\u76d6\u81f3\u4fdd\u6301\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u90fd\u5b58\u6709 2 \u548c 1 \u3002 \u6267\u884c $!d \uff0c\u5373\u4e0d\u662f\u6700\u540e\u4e00\u884c\u5c31\u4ece\u6a21\u5f0f\u7a7a\u95f4\u5220\u9664\uff0c\u6240\u4ee5\u628a 2 \u548c 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u5220\u9664\u3002 \u4ee5\u6b64\u7c7b\u63a8\uff0c\u76f4\u81f3\u8bfb\u53d6\u6700\u540e\u4e00\u884c10\u3002\u6b64\u65f6\uff0c\u6a21\u5f0f\u7a7a\u95f4\u662f 10 \uff0c\u4fdd\u6301\u7a7a\u95f4\u5b58\u6709 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002 \u6267\u884c !G \uff0c\u5373\u5bf9\u6700\u540e\u4e00\u884c\u7684 10 \u6267\u884c G \u547d\u4ee4\uff0c\u628a 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u4ece\u4fdd\u6301\u7a7a\u95f4\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u5b58\u6709 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002\uff0c\u6a21\u5f0f\u7a7a\u95f4\u5b58\u6709 10 \u3001 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002 \u6267\u884c h \u547d\u4ee4\uff0c\u5373\u628a 10 \u3001 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u8986\u76d6\u81f3\u4fdd\u6301\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u90fd\u5b58\u6709 10 \u3001 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002 \u6267\u884c $!d \uff0c\u5f53\u524d\u662f\u6700\u540e\u4e00\u884c\uff0c\u6240\u4ee5\u4e0d\u4ece\u6a21\u5f0f\u7a7a\u95f4\u5220\u9664\u5f53\u524d\u5185\u5bb9\u3002 \u8f93\u51fa\u6a21\u5f0f\u7a7a\u95f4\u5185\u5bb9\u81f3\u5c4f\u5e55\u3002\u537310\uff5e1\u3002 $ seq 10 | sed '1!G;h;$!d' 10 9 8 7 6 5 4 3 2 1 \u5176\u4ed6\u4e00\u4e9b\u4f8b\u5b50\uff1a $ seq 10 | sed -n '/3/{g;1!p;};h' 2 $ seq 10 | sed -nr '/3/{n;p}' 4 $ seq 10 | sed 'N;D' 10 $ seq 10 | sed '3h;9G;9!d' 9 3 $ seq 10 | sed '$!N;$!D' 9 10 $ seq 10 | sed '$!d' 10 $ seq 10 | sed 'G' 1 2 3 4 5 6 7 8 9 10 $ seq 10 | sed 'g' $ seq 10 | sed '/^$/d;G' 1 2 3 4 5 6 7 8 9 10 $ seq 10 | sed 'n;d' 1 3 5 7 9 $ seq 10 | sed -n '1!G;h;$p' 10 9 8 7 6 5 4 3 2 1 5.10.\u4e09\u5251\u5ba2 awk \u547d\u4ee4 \u00b6 awk \u662f\u4e00\u4e2a\u6587\u672c\u5206\u6790\u5de5\u5177\u3002 grep \u64c5\u957f\u67e5\u627e\uff0c sed \u64c5\u957f\u7f16\u8f91\uff0c awk \u64c5\u957f\u6570\u636e\u5206\u6790\u5e76\u751f\u6210\u62a5\u544a\u3002 awk \u7684\u540d\u79f0\u5f97\u81ea\u4e8e\u5b83\u7684\u521b\u59cb\u4ebaAlfred Aho \u3001Peter Weinberger \u548c Brian Kernighan \u59d3\u6c0f\u7684\u9996\u4e2a\u5b57\u6bcd\u3002 awk \u67093\u4e2a\u4e0d\u540c\u7248\u672c: awk \u3001 nawk \u548c gawk \u3002\u6211\u4eec\u8bf4\u7684 awk \u4e00\u822c\u6307 gawk \u3002 gawk \u662f awk \u7684GNU\u7248\u672c\u3002 awk \u628a\u6587\u4ef6\u9010\u884c\u8bfb\u5165\uff0c\u4ee5\u7a7a\u683c\u4e3a\u9ed8\u8ba4\u5206\u9694\u7b26\u5c06\u6bcf\u884c\u5207\u7247\uff0c\u518d\u5bf9\u5207\u7247\u8fdb\u884c\u5206\u6790\u5904\u7406\u3002 5.10.1.\u547d\u4ee4\u683c\u5f0f \u00b6 awk 'pattern{action statements;...}' {filenames} pattern \u8868\u793a awk \u5728\u6570\u636e\u4e2d\u67e5\u627e\u7684\u5185\u5bb9\u3002\u662f\u8981\u8868\u793a\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\uff0c\u7528\u659c\u6760\u62ec\u8d77\u6765\u3002 action \u662f\u5728\u627e\u5230\u5339\u914d\u5185\u5bb9\u65f6\u6240\u6267\u884c\u7684\u4e00\u7cfb\u5217\u547d\u4ee4\u3002 -F \uff1a\u6307\u5b9a\u5206\u9694\u7b26\uff0c\u540e\u9762\u7d27\u8ddf\u5355\u5f15\u53f7\uff0c\u5355\u5f15\u53f7\u5185\u662f\u5206\u9694\u7b26\u3002\u5982\u4e0d\u52a0 -F \u9009\u9879\uff0c\u5219\u4ee5\u7a7a\u683c\u6216\u8005tab\u4f5c\u4e3a\u5206\u9694\u7b26\u3002 -v \uff1avar=value\uff0c\u53d8\u91cf\u8d4b\u503c\u3002 \u63d0\u793a\uff1a -F \"\" \u6307\u5b9a\u7a7a\u5b57\u7b26\u4e32\u4f5c\u4e3a\u5b57\u6bb5\u5206\u9694\u7b26\uff0c\u4ece\u800c\u5c06\u8f93\u5165\u5b57\u7b26\u4e32\u4e2d\u7684\u6bcf\u4e2a\u5b57\u7b26\u4f5c\u4e3a\u4e00\u4e2a\u72ec\u7acb\u7684\u5b57\u6bb5\u8fdb\u884c\u5904\u7406\u3002\u7136\u540e\uff0c\u4f7f\u7528\u5faa\u73af\u904d\u5386\u6bcf\u4e2a\u5b57\u6bb5\uff0c\u5982\u679c\u5b57\u6bb5\u4e2d\u5305\u542b\u6570\u5b57\uff0c\u5219\u5c06\u5176\u6dfb\u52a0\u5230str1\u53d8\u91cf\u4e2d\u3002\u6700\u540e\uff0c\u6253\u5370str1\u7684\u503c\u3002 -F '' \u4e2d\u7684\u4e24\u4e2a\u5355\u5f15\u53f7\u4e4b\u95f4\u6ca1\u6709\u63d0\u4f9b\u6709\u6548\u7684\u5b57\u6bb5\u5206\u9694\u7b26\u3002\u5728awk\u4e2d\uff0c\u5b57\u6bb5\u5206\u9694\u7b26\u5fc5\u987b\u662f\u4e00\u4e2a\u975e\u7a7a\u5b57\u7b26\u4e32\u3002 \u793a\u4f8b\uff1a\u7b2c\u4e00\u4e2a\u548c\u7b2c\u4e09\u4e2a\u547d\u4ee4\u662f\u6b63\u786e\u7684\u3002 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F \"\" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F \"\" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 5.10.2.\u5de5\u4f5c\u8fc7\u7a0b \u00b6 \u6267\u884cBEGIN{action;...}\u8bed\u53e5\u5757\u4e2d\u7684\u8bed\u53e5\u3002 BEGIN\u8bed\u53e5\u5757\u518dawk\u8bfb\u5165\u8f93\u5165\u6d41\u4e4b\u524d\u88ab\u6267\u884c\u3002 \u662f\u53ef\u9009\u8bed\u53e5\u5757\u3002 \u5305\u542b\u521d\u59cb\u5316\u53d8\u91cf\uff0c\u6253\u5370\u8f93\u51fa\u8868\u683c\u7684\u8868\u5934\u7b49\u8bed\u53e5\u3002 \u4ece\u6587\u4ef6\u6216\u8005\u6807\u51c6\u8f93\u5165stdin\u8bfb\u53d6\u4e00\u884c\uff0c\u7136\u540e\u6267\u884cpattern{action;...}\u8bed\u53e5\u5757\u3002\u4ece\u7b2c\u4e00\u884c\u5f00\u59cb\u5230\u6700\u540e\u4e00\u884c\uff0c\u9010\u884c\u626b\u63cf\u6587\u4ef6\uff0c\u91cd\u590d\u8fd9\u4e2a\u52a8\u4f5c\uff0c\u76f4\u5230\u6587\u4ef6\u6216\u8005\u8f93\u5165\u6d41\u5168\u90e8\u88ab\u8bfb\u53d6\u5b8c\u6bd5\u3002 \u53ef\u9009\u8bed\u53e5\u5757\u3002 \u5982\u679c\u6ca1\u6709\u63d0\u4f9bpattern\u8bed\u53e5\u5757\uff0c\u5219\u9ed8\u8ba4\u6267\u884c{print}\u3002 \u5f53\u8bfb\u81f3\u6587\u4ef6\u6216\u8005\u8f93\u5165\u6d41\u672b\u5c3e\u65f6\uff0c\u6267\u884cEND{action;...}\u8bed\u53e5\u5757\uff0c\u6bd4\u5982\u6253\u5370\u6240\u6709\u884c\u7684\u5206\u6790\u7ed3\u679c\u8fd9\u7c7b\u6c47\u603b\u4fe1\u606f\u3002\u4e5f\u662f\u4e00\u4e2a\u53ef\u9009\u8bed\u53e5\u5757\u3002 5.10.3.\u5206\u9694\u7b26\u3001\u57df\u548c\u8bb0\u5f55 \u00b6 \u6709\u5206\u9694\u7b26\u5206\u9694\u7684\u5b57\u6bb5\uff08\u5217column\uff0c\u57dffield\uff09\uff0c\u6807\u8bb0 $1 \u3001 $2 \u3001 $3 \u3001...\u3001 $n \u79f0\u4e3a\u57df\u6807\u8bc6\uff0c $0 \u4e3a\u6240\u6709\u57df\u3002\u6ce8\u610f\uff0c\u548cshell\u53d8\u91cf\u4e2d\u7684 $ \u4e0d\u540c\u3002 \u6bcf\u4e00\u884c\u6210\u4e3a\u8bb0\u5f55\uff08record\uff09\u3002 \u5982\u679c\u7701\u7565action\uff0c\u5219\u9ed8\u8ba4\u6267\u884c print $0 \u64cd\u4f5c\u3002 5.10.4.\u5e38\u7528action\u5206\u7c7b \u00b6 Output statements: print , printf Expressions: \u7b97\u672f\u3001\u6bd4\u8f83\u8868\u8fbe\u5f0f Compund statements: \u7ec4\u5408\u8bed\u53e5 Control statements: if , while \u8bed\u53e5 Input statements: \u52a8\u4f5c print \u683c\u5f0f\uff1a print item1, item2, ... \u8bf4\u660e\uff1a \u9017\u53f7\u5206\u9694\u7b26 \u8f93\u51faitem\u53ef\u4ee5\u662f\u5b57\u7b26\u4e32\uff0c\u4e5f\u53ef\u4ee5\u662f\u6570\u503c\uff0c\u662f\u5f53\u524d\u8bb0\u5f55\u7684\u5b57\u6bb5\u3001\u53d8\u91cf\u6216 awk \u8868\u8fbe\u5f0f\u3002 \u5982\u679c\u7701\u7565item\uff0c\u76f8\u5f53\u4e8e print $0 \u56fa\u5b9a\u5b57\u7b26\u9700\u8981\u7528\u53cc\u5f15\u53f7\uff0c\u800c\u53d8\u91cf\u548c\u6570\u5b57\u4e0d\u9700\u8981\u3002 \u793a\u4f8b\uff1a $ seq 5 | awk '{print \"hello awk\"}' hello awk hello awk hello awk hello awk hello awk $ seq 5 | awk '{print 3*5}' 15 15 15 15 15 $ awk -F ':' '{print \"hello\"}' /etc/passwd | head -5 hello hello hello hello hello $ awk -F ':' '{print}' /etc/passwd | head -5 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin systemd-timesync:x:496:496:systemd Time Synchronization:/:/usr/sbin/nologin nobody:x:65534:65534:nobody:/var/lib/nobody:/bin/bash $ awk -F ':' '{print $0}' /etc/passwd | head -5 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin systemd-timesync:x:496:496:systemd Time Synchronization:/:/usr/sbin/nologin nobody:x:65534:65534:nobody:/var/lib/nobody:/bin/bash $ awk -F ':' '{print $1,$3}' /etc/passwd | head -5 root 0 messagebus 499 systemd-network 497 systemd-timesync 496 nobody 65534 $ awk -F ':' '{print $1\"\\t\"$3}' /etc/passwd | head -5 root 0 messagebus 499 systemd-network 497 systemd-timesync 496 nobody 65534 $ grep \"^UUID\" /etc/fstab | awk '{print $2,$3}' / btrfs /var btrfs /usr/local btrfs /tmp btrfs /srv btrfs /root btrfs /opt btrfs /home btrfs /boot/grub2/x86_64-efi btrfs /boot/grub2/i386-pc btrfs /.snapshots btrfs swap swap \u793a\u4f8b\uff1a\u8bfb\u53d6\u5206\u533a\u5229\u7528\u7387\u3002 \u5206\u9694\u7b26\u4e2d\u7684\u5b9a\u4e49 [[:space:]]+|% \u7684\u542b\u4e49\uff0c\u4e00\u4e2a\u6216\u591a\u4e2a\u7a7a\u683c\u6216\u8005 % \u4f5c\u4e3a\u5206\u9694\u7b26\u3002 $ df | awk '{print $1,$5}' Filesystem Use% devtmpfs 0 % tmpfs 0 % tmpfs 2 % tmpfs 0 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % tmpfs 0 % $ df | grep '^/dev/sd' | awk -F '[[:space:]]+|%' '{print $1,$5}' $ df | grep '^/dev/sd' | awk -F ' +|%' '{print $1,$5}' /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 \u793a\u4f8b\uff1a\u8bfb\u53d6ifconfig\u8f93\u51fa\u7ed3\u679c\u4e2d\u7684ip\u5730\u5740\u3002 $ ifconfig eth0 | sed -n '2p' | awk '/netmask/{print $2}' 192 .168.10.210 $ ifconfig eth0 | sed -n '2p' | awk '{print $2}' 192 .168.10.210 5.10.5.\u6a21\u5f0fPattern \u00b6 \u6839\u636epattern\u6761\u4ef6\uff0c\u8fc7\u6ee4\u5339\u914d\u7684\u884c\uff0c\u518d\u505a\u5904\u7406\u3002 \u5982\u679c\u672a\u6307\u5b9a\uff0c\u5373\u7a7a\u6a21\u5f0f\uff0c\u5219\u5339\u914d\u6bcf\u4e00\u884c\u3002 /regular expression/ \uff0c\u4ec5\u5904\u7406\u80fd\u591f\u6a21\u5f0f\u5339\u914d\u5230\u7684\u884c\uff08\u5373\u7ed3\u679c\u4e3a\u771f\uff09\uff0c\u9700\u8981\u7528 / \u8fdb\u884c\u62ec\u8d77\u6765\u3002 \u7ed3\u679c\u4e3a\u771f\uff0c\u5373\u975e0\u503c\u3001\u975e\u7a7a\u5b57\u7b26\u4e32 \u7ed3\u679c\u4e3a\u5047\uff0c\u53730\u503c\u3001\u7a7a\u5b57\u7b26\u4e32 \u793a\u4f8b\uff1a\u7a7a\u6a21\u5f0f awk -F \":\" '{print $1, $3}' /etc/passwd | head -n5 root 0 messagebus 499 systemd-network 497 systemd-timesync 496 nobody 65534 \u793a\u4f8b\uff1a\u975e\u7a7a\u6a21\u5f0f $ seq 5 | awk '0' $ seq 5 | awk '1' 1 2 3 4 5 $ seq 5 | awk '2' 1 2 3 4 5 $ seq 5 | awk '\"true\"' 1 2 3 4 5 $ seq 5 | awk '\"false\"' 1 2 3 4 5 $ seq 5 | awk 'true' $ seq 5 | awk 'false' $ seq 5 | awk '' $ seq 5 | awk '\"\"' $ seq 5 | awk '\"0\"' 1 2 3 4 5 \u4f53\u4f1a\u4e0b\u9762\u53d8\u91cf\u7684\u503c\u548c\u6b63\u786e\u4f7f\u7528\u53d8\u91cf\uff08\u5b57\u7b26\u4e32\u8fd8\u662f\u53d8\u91cf\uff1f\uff09 $ seq 5 | awk '\"test\"' 1 2 3 4 5 $ seq 5 | awk 'test' $ seq 5 | awk -v test = 0 '\"test\"' $ seq 5 | awk -v test = 0 'test' $ seq 5 | awk -v test = \"0\" 'test' $ seq 5 | awk -v test = \"0\" '\"test\"' 1 2 3 4 5 $ seq 5 | awk -v test = 1 'test' 1 2 3 4 5 \u4f53\u4f1a\u4e0b\u9762\u7684\u4e0e\u975e\u5224\u65ad\u3002 $ awk '1' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin $ awk '0' /etc/passwd | head -n3 $ awk '!1' /etc/passwd | head -n3 $ awk '!0' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin # i\u6ca1\u6709\u8d4b\u503c\uff0c\u4e3a\u5047\uff0c\u6ca1\u6709\u8f93\u51fa $ seq 5 | awk 'i' # i\u8d4b\u503c\u4e3a0\uff0c\u4e3a\u5047\uff0c\u6ca1\u6709\u8f93\u51fa $ seq 5 | awk 'i=0' # i\u8d4b\u503c\u4e3a1\uff0c\u4e3a\u771f\uff0c\u8f93\u51fa\u7b2c\u4e00\u884c\u7ed3\u679c\uff0c\u4ee5\u6b64\u7c7b\u63a8\uff0c\u6bcf\u884c\u90fd\u4e3a\u771f\uff0c\u8f93\u51fa\u5168\u90e8seq\u7684\u7ed3\u679c $ seq 5 | awk 'i=1' 1 2 3 4 5 # \u7b2c\u4e00\u6b21\u521d\u59cbi\u672a\u8d4b\u503c\uff0c\u4e3a\u5047\uff0c!i\u5219\u4e3a\u771f\uff0c\u8d4b\u503c\u7ed9i\uff0c\u6240\u4ee5i\u4e3a\u771f,\u8f93\u51faseq\u7b2c1\u884c\u7ed3\u679c # \u7b2c\u4e8c\u6b21\u521d\u59cbi\u4e3a\u771f\uff0c!i\u5219\u4e3a\u5047\uff0c\u8d4b\u503c\u7ed9i\uff0c\u6240\u4ee5i\u4e3a\u5047\uff0c\u4e0d\u8f93\u51faseq\u7b2c2\u884c\u7ed3\u679c # \u7b2c\u4e09\u6b21\u521d\u59cbi\u4e3a\u5047\uff0c!i\u5219\u4e3a\u771f\uff0c\u8d4b\u503c\u7ed9i\uff0c\u6240\u4ee5i\u4e3a\u771f\uff0c\u8f93\u51faseq\u7b2c3\u884c\u7ed3\u679c # \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8f93\u51faseq\u7ed3\u679c\u7684\u5947\u6570\u884c $ seq 5 | awk 'i=!i' 1 3 5 # \u4e0e\u4e0a\u4f8b\u7684\u533a\u522b\u5728\u4e8ei\u521d\u59cb\u503c\u672a\u771f\uff0c\u7b2c\u4e00\u6b21\u7684i\u503c\u4e3a\u5047\uff0c\u4e0d\u8f93\u51faseq\u7b2c1\u884c\u7ed3\u679c # \u7b2c\u4e8c\u6b21i\u7684\u521d\u59cb\u503c\u4e3a\u5047\uff0c\u901a\u8fc7i=!i\u53d8\u4e3a\u771f\uff0c\u6240\u4ee5\u8f93\u51faseq\u7684\u7b2c2\u884c\u7ed3\u679c # \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8f93\u51faseq\u7ed3\u679c\u7684\u5076\u6570\u884c $ seq 5 | awk -v i = 1 'i=!i' 2 4 # \u8f93\u51fa\u8ba1\u6570\u884c $ seq 5 | awk -v i = 0 'i=!i' 1 3 5 # \u53ea\u8f93\u51fai\u7684\u503c\uff0c\u4e0d\u8f93\u51faseq\u7684\u503c $ seq 5 | awk '{i=!i;print i}' 1 0 1 0 1 $ seq 5 | awk '{i=!i}' $ seq 5 | awk '(i=!i)' 1 3 5 $ seq 5 | awk '!(i=!i)' 2 4 5.10.6.\u622a\u53d6\u7247\u6bb5 \u00b6 \u793a\u4f8b\uff1a $ head -n2 /etc/passwd | awk -F ':' '{print $0}' root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false $ head -n2 /etc/passwd | awk -F ':' '{print $2}' x x $ head -n2 /etc/passwd | awk -F ':' '{print $1}' root messagebus $ head -n2 /etc/passwd | awk -F ':' '{print $1\"#\"$2\"#\"$3\"#\"$4}' root#x#0#0 messagebus#x#499#499 5.10.7.\u64cd\u4f5c\u7b26 \u00b6 5.10.7.1.\u7b97\u6570\u64cd\u4f5c\u7b26 \u00b6 x+y \uff0c x-y \uff0c x*y \uff0c x/y \uff0c x^y \uff0c x%y \u3002 -x \uff1a\u8f6c\u6362\u4e3a\u8d1f\u6570 +x \uff1a\u5c06\u5b57\u7b26\u4e32\u8f6c\u6362\u4e3a\u6570\u503c \u5217\u503c\u4e4b\u95f4\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97\u3002 $ awk -F ':' '{$7=$3+$4;print $1,$3,$4,$7}' /etc/passwd | head -n5 root 0 0 0 messagebus 499 499 998 systemd-network 497 497 994 systemd-timesync 496 496 992 nobody 65534 65534 131068 \u8ba1\u7b97\u67d0\u4e2a\u5217\u7684\u603b\u548c\u3002 END \u8868\u793a\u6240\u6709\u7684\u884c\u90fd\u5df2\u7ecf\u6267\u884c\u3002 $ awk -F ':' '{(total=total+$3)}; END {print total}' /etc/passwd 103011 5.10.7.2.\u5b57\u7b26\u4e32\u64cd\u4f5c\u7b26 \u00b6 \u6ca1\u6709\u64cd\u4f5c\u7b26\u53f7\uff0c\u5b57\u7b26\u4e32\u8fde\u63a5\u3002 5.10.7.3.\u8d4b\u503c\u64cd\u4f5c\u7b26 \u00b6 = \uff0c += \uff0c -= \uff0c *= \uff0c /= \uff0c %= \uff0c ^= \uff0c ++ \uff0c -- \u3002 \u793a\u4f8b\uff1a $ awk 'BEGIN{print i}' $ awk 'BEGIN{print i++}' #\u4ece0\u5f00\u59cb 0 $ awk 'BEGIN{print ++i}' 1 $ awk 'BEGIN{print i++, i}' 0 1 $ awk 'BEGIN{i=0;print i++, i}' 0 1 $ awk 'BEGIN{print ++i, i}' 1 1 $ awk 'BEGIN{i=0;print ++i, i}' 1 1 $ awk 'BEGIN{i=0;print i, i++}' 0 0 $ awk 'BEGIN{i=0;print i, ++i}' 0 1 $ seq 10 1 2 3 4 5 6 7 8 9 10 # n\u4ece0\u5f00\u59cb\u8ba1\u6570\uff0c\u8f93\u51fa\u7684\u662fn\u503c\uff0c\u4e0d\u662fseq\u7684\u8f93\u51fa\u7ed3\u679c $ seq 10 | awk '{print n++}' 0 1 2 3 4 5 6 7 8 9 # seq=1\u65f6\uff0c\u521d\u59cbn\u672a\u8d4b\u503c\uff0c\u4e3a\u5047\uff0c\u4e0d\u8f93\u51faseq\u7ed3\u679c\uff0cn++\u4e3a\u771f # seq=2\u65f6\uff0cn\u4e3a\u771f\uff0c\u8f93\u51faseq\u7ed3\u679c\uff0cn++\u4e3a\u771f # \u540e\u7eedn++\u90fd\u4e3a\u771f\uff0c\u6240\u4ee5seq\u7684\u7ed3\u679c\u51fa\u4e86\u7b2c\u4e00\u884c\u7531\u4e8en\u4e3a\u5047\u6ca1\u6709\u8f93\u51fa\uff0c\u5176\u4ed6\u884c\u90fd\u8f93\u51fa $ seq 10 | awk 'n++' 2 3 4 5 6 7 8 9 10 # \u53c2\u8003\u4e0a\u4f8b\uff0cn\u521d\u59cb\u672a\u8d4b\u503c\uff0c\u4f46\u6267\u884c++n\u540e\u4e3a\u771f\uff0c\u6240\u4ee5\u8f93\u51fa\u7b2c\u4e00\u884c\uff0c\u540e\u7eed\u884c\u90fd\u8f93\u51fa\u56e0\u4e3an\u4e00\u76f4\u4e3a\u771f $ seq 10 | awk '++n' 1 2 3 4 5 6 7 8 9 10 # n=0\u65f6++n=1\uff0c!++n=0\uff0c\u8f93\u51fa\u7b2c0\u884c $ awk -v n = 0 '!++n' /etc/passwd # n=0\u65f6n++=1\uff0c!n++=1\uff0c\u8f93\u51fa\u7b2c1\u884c $ awk -v n = 0 '!n++' /etc/passwd root:x:0:0:root:/root:/bin/bash $ awk -v n = 0 '!n++{print n}' /etc/passwd 1 # \u65e0\u7ed3\u679c\u8f93\u51fa $ awk -v n = 0 '!++n{print n}' /etc/passwd $ awk -v n = 1 '!n++{print n}' /etc/passwd $ awk -v n = 0 '!n++' /etc/passwd root:x:0:0:root:/root:/bin/bash # \u65e0\u7ed3\u679c\u8f93\u51fa $ awk -v n = 1 '!n++' /etc/passwd $ awk -v n = 2 '!n++' /etc/passwd 5.10.7.4.\u6bd4\u8f83\u64cd\u4f5c\u7b26 \u00b6 \u4f7f\u7528 == \u4ee3\u8868\u7b49\u4e8e\uff0c\u5373\u7cbe\u786e\u5339\u914d\u3002\u7c7b\u4f3c\u8fd8\u6709 > \u3001 >= \u3001 < \u3001 <= \u3001 != \u7b26\u53f7\u3002 \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e09\u5217\u7684\u503c\u4e3a 1000 \u7684\u884c\u3002 $ awk -F ':' '$3==\"100\"' /etc/passwd vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash \u5728\u548c\u6570\u5b57\u6bd4\u8f83\u65f6\uff0c\u82e5\u628a\u8981\u6bd4\u8f83\u7684\u6570\u5b57\u7528\u53cc\u5f15\u53f7\u5f15\u8d77\u6765\uff0c awk \u4f1a\u6309\u5b57\u7b26\u5904\u7406\uff0c\u4e0d\u52a0\u53cc\u5f15\u53f7\uff0c\u5219\u4f1a\u6309\u6570\u5b57\u5904\u7406\u3002 $ awk -F ':' '$3<=\"100\"' /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/usr/sbin/nologin $ awk -F ':' '$3<=100' /etc/passwd root:x:0:0:root:/root:/bin/bash postfix:x:51:51:Postfix Daemon:/var/spool/postfix:/usr/sbin/nologin man:x:13:62:Manual pages viewer:/var/lib/empty:/usr/sbin/nologin daemon:x:2:2:Daemon:/sbin:/usr/sbin/nologin at:x:25:25:Batch jobs daemon:/var/spool/atjobs:/usr/sbin/nologin bin:x:1:1:bin:/bin:/usr/sbin/nologin awk -F ':' '{if ($1==\"root\") {print $0}}' /etc/passwd awk -F ':' '$7!=\"/bin/false\"' /etc/passwd awk -F ':' '$3<$2' /etc/passwd 5.10.7.5.\u903b\u8f91\u64cd\u4f5c\u7b26 \u00b6 && \u8868\u793a\u201c\u5e76\u4e14\u201d || \u8868\u793a\u201c\u6216\u8005\u201d ! \u8868\u793a\u201c\u975e\u201d\uff08\u53d6\u53cd\uff09 awk -F ':' '$3>10 && $3<100' /etc/passwd awk -F ':' '$3>10 || $3<100' /etc/passwd awk -F ':' '($3==0)' /etc/passwd awk -F ':' '!($3==0)' /etc/passwd \u6ce8\u610f\u4e0b\u9762\u5bf9\u5b57\u7b26\u548c\u6570\u503c\u8fdb\u884c\u53d6\u53cd\u64cd\u4f5c\u7684\u7ed3\u679c\u3002 $ awk 'BEGIN{print i}' $ awk 'BEGIN{print !i}' 1 $ awk -v i = 10 'BEGIN{print i}' 10 $ awk -v i = 10 'BEGIN{print !i}' 0 $ awk -v i = -5 'BEGIN{print i}' -5 $ awk -v i = -5 'BEGIN{print !i}' 0 $ awk -v i = \"abc\" 'BEGIN{print i}' abc $ awk -v i = \"abc\" 'BEGIN{print !i}' 0 $ awk -v i = abc 'BEGIN{print i}' abc $ awk -v i = abc 'BEGIN{print !i}' 0 $ awk -v i = \"\" 'BEGIN{print i}' $ awk -v i = \"\" 'BEGIN{print !i}' 1 \u5728\u5206\u9694\u7b26\u5b9a\u4e49\u4e2d\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u3002 $ df | awk -F \" +|%\" '{print $5}' Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0 $ df | awk -F \"[[:space:]]+|%\" '{print $5}' Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0 5.10.7.6.\u4e09\u76ee\u6761\u4ef6\u8868\u8fbe\u5f0f \u00b6 \u683c\u5f0f\uff1a selector?if-true-expression:if-false-expression $ awk -F ':' '{$3>1000?usertype=\"Common User\":usertype=\"Superuser\";printf\"%-20s:%12s\\n\", $1, usertype}' /etc/passwd | head -n5 root : Superuser messagebus : Superuser systemd-network : Superuser systemd-timesync : Superuser nobody : Common User 5.10.7.8.\u6a21\u5f0f\u5339\u914d\u7b26 \u00b6 ~ \uff1a\u5de6\u53f3\u662f\u5426\u5339\u914d !~ \uff1a\u5de6\u53f3\u662f\u5426\u4e0d\u5339\u914d \u793a\u4f8b\uff1a \u5339\u914d\u6587\u4ef6\u4e2d\u6307\u5b9a\u5b57\u7b26\u4e32 root \u7684\u6240\u6709\u884c\uff0c\u7c7b\u4f3cgrep\u547d\u4ee4\uff0c\u4f46\u6ca1\u6709\u9ad8\u4eae\u663e\u793a\u3002 $ awk '/root/' /etc/passwd root:x:0:0:root:/root:/bin/bash \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e00\u5217 $1 \u4e2d\u5305\u542b\u6307\u5b9a\u5b57\u7b26\u4e32 oo \u7684\u884c\u3002 ~ \u662f\u4ee3\u8868\u5de6\u53f3\u5339\u914d\u3002 $ awk -F ':' '$1 ~/oo/' /etc/passwd root:x:0:0:root:/root:/bin/bash gentoo:x:1014:100:Gentoo Distribution:/home/gentoo:/bin/csh \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u5217 $0 \uff08\u6574\u884c\uff09\u4e2d\u5305\u542b root \u884c\u7684\u7b2c\u4e00\u5217 $1 \u3002 $ awk -F: '$0 ~/root/{print $1}' /etc/passwd $ awk -F: '$0 ~\"root\"{print $1}' /etc/passwd root daemon _cvmsroot \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u5217 $0 \uff08\u6574\u884c\uff09\u4e2d\u4ee5 root \u5f00\u5934\u884c\u7684\u7b2c\u4e00\u5217 $1 \u3002 $ awk -F: '$0 ~\"^root\"{print $1}' /etc/passwd $ awk -F: '$0 ~/^root/{print $1}' /etc/passwd root \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u5217 $0 \uff08\u6574\u884c\uff09\u4e2d\u4e0d\u4ee5 root \u5f00\u5934\u884c\u7684\u7b2c\u4e00\u5217 $1 \u3002 awk -F: '$0 !~/^root/{print $1}' /etc/passwd awk -F: '$0 ~/^[^root]/{print $1}' /etc/passwd \u591a\u6761\u4ef6\u5339\u914d\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u542b\u6709 root \u6216 ftp \u7684\u884c\uff0c\u5e76\u6253\u5370\u7b2c1\u30013\u5217\u3002 awk -F ':' '/root/ {print $1,$3} /bin/ {print $1,$3}' /etc/passwd \u591a\u6761\u4ef6\u5339\u914d\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e00\u5217\u4e2d\u542b\u6709 root \u6216 bin \u7684\u884c\uff0c\u5e76\u6253\u5370\u7b2c1\u30013\u5217\u3002 $ awk -F ':' '$1 ~/root/ {print $1,$3} $1 ~/bin/ {print $1,$3}' /etc/passwd root 0 bin 1 \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e09\u5217 $3 \u4e2d\u503c\u4e3a 0 \u7684\u884c\u3002 $ awk -F \":\" '$3==0' /etc/passwd root:x:0:0:root:/root:/bin/bash \u4ee5\u81f3\u5c11\u4e00\u4e2a\u7a7a\u683c\u6216%\u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u4ee5 /dev/sd \u5f00\u5934\u7684\u884c\uff0c\u6253\u5370\u7b2c\u4e94\u5217\u3002 $ df | awk -F \"[[:space:]]+|%\" '$0 ~ /^\\/dev\\/sd/{print $5}' 8 8 8 8 8 8 8 8 8 8 8 \u8bfb\u53d6 ifconfig eth0 \u8f93\u51fa\u7ed3\u679c\u7684\u7b2c\u4e8c\u884c NR==2 \u7684\u7b2c\u4e8c\u5217 $2 \u3002 $ ifconfig eth0 | awk 'NR==2{print $2}' 192 .168.10.210 5.10.8.\u53d8\u91cf \u00b6 5.10.8.1.\u5185\u7f6e\u53d8\u91cf \u00b6 awk \u5e38\u7528\u7684\u53d8\u91cf\u6709 FS \u3001 OFS \u3001 NF \u548c NR \u3002 FS \u7528\u6765\u5b9a\u4e49\u8f93\u5165\u5b57\u6bb5\u5206\u9694\u7b26\uff0c\u9ed8\u8ba4\u4e3a\u7a7a\u767d\u5b57\u7b26\u3002\u4e0e -F \u9009\u9879\u529f\u80fd\u7c7b\u4f3c\uff0c\u540c\u65f6\u4f7f\u7528\u4f1a\u62a5\u9519\u3002 OFS \u7528\u6765\u5b9a\u4e49\u8f93\u51fa\u5b57\u6bb5\u5206\u9694\u7b26\uff0c\u9ed8\u8ba4\u4e3a\u7a7a\u767d\u5b57\u7b26\u3002 RS \u6307\u5b9a\u8f93\u5165\u65f6\u7684\u6362\u884c\u7b26\u3002 ORS \u6307\u5b9a\u7b26\u53f7\u5728\u8f93\u51fa\u65f6\u66ff\u6362\u6362\u884c\u7b26\u3002 NF \u8868\u793a\u7528\u5206\u9694\u7b26\u5206\u9694\u540e\u4e00\u5171\u6709\u591a\u5c11\u5217\u3002 NR \u8868\u793a\u884c\u53f7\u3002 FNR \u8868\u793a\u4e2a\u6587\u4ef6\u5206\u522b\u8ba1\u6570\u5404\u81ea\u8bb0\u5f55\u7684\u7f16\u53f7\u3002 FILENAME \u8868\u793a\u5f53\u524d\u6587\u4ef6\u540d\u3002 ARGC \u8868\u793a\u547d\u4ee4\u884c\u53c2\u6570\u7684\u4e2a\u6570\u3002 ARVC \u4ee5\u6570\u7ec4\u5f62\u5f0f\u4fdd\u5b58\u547d\u4ee4\u884c\u6240\u7ed9\u5b9a\u7684\u5404\u53c2\u6570\uff0c\u6bcf\u4e2a\u53c2\u6570\uff1a ARGV[0] \uff0c......\u3002 FS \u7684\u7528\u6cd5\uff1a $ awk -v FS = ':' '{print $1, FS, $3}' /etc/passwd | head -n5 root : 0 messagebus : 499 systemd-network : 497 $ awk -F: '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 $ S = : ; awk -v FS = $S '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 systemd-timesync:496 nobody:65534 $ S = : ; awk -F $S '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 FS \u548c -F \u9009\u9879\u529f\u540c\u65f6\u4f7f\u7528\u4f1a\u51b2\u7a81\uff0c -F \u7684\u4f18\u5148\u7ea7\u66f4\u9ad8\u3002 $ awk -v FS = ':' -F ';' '{print $1FS$3}' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash ; messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false ; systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin ; $ awk -v FS = ';' -F ':' '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 OFS \u7684\u7528\u6cd5\uff1a \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u7b2c1\u30013\u30014\u5217\u7b2c\u5185\u5bb9\uff0c\u5e76\u4ee5 # \u4e3a\u5206\u9694\u7b26\u3002 $ awk -F ':' '{OFS=\"#\"} {print $1,$3,$4}' /etc/passwd | head -n5 root#0#0 messagebus#499#499 systemd-network#497#497 systemd-timesync#496#496 nobody#65534#65534 $ awk -v FS = ':' -v OFS = '#' '{print $1,$3,$4}' /etc/passwd | head -n5 root#0#0 messagebus#499#499 systemd-network#497#497 systemd-timesync#496#496 nobody#65534#65534 \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5f53\u7b2c\u4e09\u5217\u5927\u4e8e\u7b49\u4e8e5000\u65f6\uff0c\u6253\u5370\u7b2c1\u30012\u30013\u30014\u5217\u7b2c\u5185\u5bb9\uff0c\u5e76\u4ee5 # \u4e3a\u5206\u9694\u7b26\u3002 $ awk -F ':' '{OFS=\"#\"} {if ($3>=5000) {print $1,$2,$3,$4}}' /etc/passwd nobody#x#65534#65534 RS \u7684\u7528\u6cd5\uff1a # \u4ee5\u7a7a\u683c\u4e3a\u6362\u884c\u6807\u5fd7 $ awk -v RS = ' ' '{print $0}' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for # \u4ee5\u5192\u53f7\u4e3a\u6362\u884c\u6807\u5fd7 $ awk -v RS = ':' '{print $0}' /etc/passwd | head -n3 root x 0 ORS \u7684\u7528\u6cd5\uff1a # \u4ee5\u5192\u53f7\u4e3a\u6362\u884c\u6807\u5fd7\uff0c\u66ff\u6362\u6210### $ awk -v RS = ':' -v ORS = '###' '{print $0}' /etc/passwd | head -n3 root###x###0###0###root###/root###/bin/bash messagebus###x###499###499###User for D-Bus###/run/dbus###/usr/bin/false systemd-network###x###497###497###systemd Network Management###/###/usr/sbin/nologin NF \u7684\u7528\u6cd5\uff1a \u5176\u4e2d NF \u662f\u591a\u5c11\u5217\uff0c $NF \u662f\u6700\u540e\u4e00\u5217\u7684\u503c\u3002 \u4e0b\u4f8b\u4e2d\u4ee5 : \u4e3a\u5206\u9694\u7b26\u4e00\u5171\u5206\u4e3a7\u5217\uff0c\u6700\u540e\u4e00\u5217\u7684\u503c\u662f $NF \u3002 $ awk -F ':' '{print $NF}' /etc/passwd | head -n2 /bin/bash /usr/bin/false $ awk -F ':' '{print NF}' /etc/passwd | head -n2 7 7 $ ss -nt | grep \"^ESTAB\" | awk -F \"[[:space:]]+|:\" '{print $(NF-2)}' 192 .168.10.103 $ ss -nt | awk -F \"[[:space:]]+|:\" '/^ESTAB/{print $(NF-2)}' 192 .168.10.103 NR \u7684\u7528\u6cd5\uff1a \u901a\u8fc7 NR \u8f93\u51fa\u884c\u53f7\u3002\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u524d\u4e09\u884c\u7684\u884c\u53f7\u3002 $ awk -F ':' '{print NR}' /etc/passwd | head -n3 1 2 3 \u53d6\u5947\u3001\u5076\u6570\u884c\u3002 $ seq 10 | awk 'NR%2==0' 2 4 6 8 10 $ seq 10 | awk 'NR%2==1' 1 3 5 7 9 \u901a\u8fc7 NR \u8bbe\u5b9a\u884c\u53f7\u6761\u4ef6\u3002\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u7b2c40\u884c\u4ee5\u540e\u7684\u884c\u5185\u5bb9\u3002 $ awk 'NR>45' /etc/passwd admin3:x:1020:100::/home/admin3:/bin/bash smith:x:2002:0:,,,:/home/admin2:/bin/bash pm1:x:2003:1535::/home/pm1:/bin/bash tm1:x:2004:1535::/home/tm1:/bin/bash tm2:x:2005:1536::/home/tm2:/bin/bash $ awk -F ':' 'NR>45' /etc/passwd admin3:x:1020:100::/home/admin3:/bin/bash smith:x:2002:0:,,,:/home/admin2:/bin/bash pm1:x:2003:1535::/home/pm1:/bin/bash tm1:x:2004:1535::/home/tm1:/bin/bash tm2:x:2005:1536::/home/tm2:/bin/bash $ awk -F ':' 'NR>45 {print NR,$1,$3}' /etc/passwd 46 admin3 1020 47 smith 2002 48 pm1 2003 49 tm1 2004 50 tm2 2005 $ awk -F ':' 'BEGIN{print NR}' /etc/passwd 0 $ awk -F ':' 'END{print NR}' /etc/passwd 50 $ ifconfig eth0 | awk '/netmask/{print $0}' inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig eth0 | awk '/netmask/{print $1}' inet $ ifconfig eth0 | awk '/netmask/{print $2}' 192 .168.10.210 $ ifconfig eth0 | awk 'NR==2{print $0}' inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig eth0 | awk 'NR==2{print $1}' inet $ ifconfig eth0 | awk 'NR==2{print $2}' 192 .168.10.210 \u901a\u8fc7 NR \u4e0e\u5217\u5339\u914d\u4e00\u8d77\u4f7f\u7528\u3002 $ awk -F ':' 'NR<5 && $1 ~/roo/' /etc/passwd root:x:0:0:root:/root:/bin/bash FNR \u7684\u7528\u6cd5\uff1a $ awk '{print FNR}' /etc/fstab /etc/networks 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 $ awk '{print NR, $0}' /etc/fstab /etc/networks 1 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af / btrfs defaults 0 0 2 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /var btrfs subvol = /@/var 0 0 3 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /usr/local btrfs subvol = /@/usr/local 0 0 4 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /tmp btrfs subvol = /@/tmp 0 0 5 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /srv btrfs subvol = /@/srv 0 0 6 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /root btrfs subvol = /@/root 0 0 7 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /opt btrfs subvol = /@/opt 0 0 8 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /home btrfs subvol = /@/home 0 0 9 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/x86_64-efi btrfs subvol = /@/boot/grub2/x86_64-efi 0 0 10 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/i386-pc btrfs subvol = /@/boot/grub2/i386-pc 0 0 11 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /.snapshots btrfs subvol = /@/.snapshots 0 0 12 UUID = 47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 swap swap defaults 0 0 13 # 14 # networks This file describes a number of netname-to-address 15 # mappings for the TCP/IP subsystem. It is mostly 16 # used at boot time, when no name servers are running. 17 # 18 19 loopback 127 .0.0.0 20 link-local 169 .254.0.0 21 22 # End. $ awk '{print FNR, $0}' /etc/fstab /etc/networks 1 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af / btrfs defaults 0 0 2 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /var btrfs subvol = /@/var 0 0 3 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /usr/local btrfs subvol = /@/usr/local 0 0 4 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /tmp btrfs subvol = /@/tmp 0 0 5 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /srv btrfs subvol = /@/srv 0 0 6 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /root btrfs subvol = /@/root 0 0 7 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /opt btrfs subvol = /@/opt 0 0 8 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /home btrfs subvol = /@/home 0 0 9 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/x86_64-efi btrfs subvol = /@/boot/grub2/x86_64-efi 0 0 10 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/i386-pc btrfs subvol = /@/boot/grub2/i386-pc 0 0 11 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /.snapshots btrfs subvol = /@/.snapshots 0 0 12 UUID = 47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 swap swap defaults 0 0 1 # 2 # networks This file describes a number of netname-to-address 3 # mappings for the TCP/IP subsystem. It is mostly 4 # used at boot time, when no name servers are running. 5 # 6 7 loopback 127 .0.0.0 8 link-local 169 .254.0.0 9 10 # End. FILENAME \u7684\u7528\u6cd5\uff1a $ awk '{print FILENAME}' /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab $ awk '{print FNR, FILENAME, $0}' /etc/fstab /etc/networks 1 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af / btrfs defaults 0 0 2 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /var btrfs subvol = /@/var 0 0 3 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /usr/local btrfs subvol = /@/usr/local 0 0 4 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /tmp btrfs subvol = /@/tmp 0 0 5 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /srv btrfs subvol = /@/srv 0 0 6 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /root btrfs subvol = /@/root 0 0 7 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /opt btrfs subvol = /@/opt 0 0 8 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /home btrfs subvol = /@/home 0 0 9 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/x86_64-efi btrfs subvol = /@/boot/grub2/x86_64-efi 0 0 10 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/i386-pc btrfs subvol = /@/boot/grub2/i386-pc 0 0 11 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /.snapshots btrfs subvol = /@/.snapshots 0 0 12 /etc/fstab UUID = 47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 swap swap defaults 0 0 1 /etc/networks # 2 /etc/networks # networks This file describes a number of netname-to-address 3 /etc/networks # mappings for the TCP/IP subsystem. It is mostly 4 /etc/networks # used at boot time, when no name servers are running. 5 /etc/networks # 6 /etc/networks 7 /etc/networks loopback 127 .0.0.0 8 /etc/networks link-local 169 .254.0.0 9 /etc/networks 10 /etc/networks # End. ARGC \u7684\u7528\u6cd5\uff1a \u6bcf\u4e2a\u53d8\u91cf\u7684\u540d\u5b57\u901a\u8fc7 ARGV \u83b7\u53d6\u3002 $ awk '{print ARGC}' /etc/fstab /etc/issue 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 $ awk 'BEGIN{print ARGC}' /etc/fstab /etc/issue 3 ARGV \u7684\u7528\u6cd5\uff1a $ awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/issue awk $ awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/issue /etc/fstab $ awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/issue /etc/issue $ awk 'BEGIN{print ARGV[3]}' /etc/fstab /etc/issue 5.10.8.2.\u81ea\u5b9a\u4e49\u53d8\u91cf \u00b6 \u81ea\u5b9a\u4e49\u53d8\u91cf\u662f\u533a\u5206\u5b57\u7b26\u5927\u5c0f\u5199\u7684\uff0c\u4f7f\u7528\u4e0b\u9762\u7684\u65b9\u5f0f\u8fdb\u884c\u8d4b\u503c\u3002 -v var=value \u5728program\u4e2d\u76f4\u63a5\u5b9a\u4e49 \u4e3e\u4f8b\uff1a $ awk -v t1 = t2 = \"hello awk\" 'BEGIN{print t1, t2}' t2 = hello awk $ awk -v t1 = t2 = \"hello awk\" 'BEGIN{t1=t2=\"gawk\"; print t1, t2}' gawk gawk $ awk 'BEGIN{t1=t2=\"hello awk\"; print t1, t2}' hello awk hello awk $ awk -v t1 = \"hello awk\" '{print t1}' /etc/issue hello awk hello awk hello awk hello awk hello awk $ awk -v t1 = \"hello awk\" 'BEGIN{print t1}' /etc/issue hello awk $ awk -v t1 = \"hello awk\" 'BEGIN{print t1}' hello awk $ awk -F: '{sex=\"male\"; print $1, sex, age; age=28}' /etc/passwd | head -n3 root male messagebus male 28 systemd-network male 28 $ cat < awkscript {print script,$1,$2} EOF $ awk -F: -f awkscript script = \"awk\" /etc/passwd | head -n2 awk root x awk messagebus x \u52a8\u4f5c printf \u3002 \u52a8\u4f5cprintf\u53ef\u4ee5\u5b9e\u73b0\u683c\u5f0f\u5316\u8f93\u51fa\u3002 \u683c\u5f0f\uff1a printf \"FORMAT\", item1, item2, ...... \u8bf4\u660e\uff1a \u5fc5\u987b\u6307\u5b9aFORMAT \u4e0d\u4f1a\u81ea\u52a8\u6362\u884c\uff0c\u9700\u8981\u663e\u5f0f\u7ed9\u51fa\u6362\u884c\u63a7\u5236\u7b26 \\n \u3002 FORMAT\u4e2d\u9700\u8981\u5206\u522b\u4e3a\u540e\u9762\u6bcf\u4e2aitem\u6307\u5b9a\u683c\u5f0f\u7b26\u3002 \u683c\u5f0f\u7b26\uff1a\u4e0eitem\u662f\u4e00\u4e00\u5bf9\u5e94\u7684 %s \uff1a\u663e\u793a\u5b57\u7b26\u4e32 %d , %i \uff1a\u663e\u793a\u5341\u8fdb\u5236\u6574\u6570 %f \uff1a\u663e\u793a\u4e3a\u6d6e\u70b9\u6570 %e , %E \uff1a\u663e\u793a\u79d1\u5b66\u8ba1\u6570\u6cd5\u6570\u503c %c \uff1a\u663e\u793a\u5b57\u7b26\u7684ASCII\u7801 %g , %G \uff1a\u4ee5\u79d1\u5b66\u8ba1\u6570\u6cd5\u6216\u6d6e\u70b9\u5f62\u5f0f\u663e\u793a\u6570\u503c %u \uff1a\u65e0\u7b26\u53f7\u6574\u6570 %% \uff1a\u663e\u793a % \u81ea\u8eab \u4fee\u9970\u7b26\uff1a #[.#] \uff1a\u7b2c\u4e00\u4e2a\u6570\u5b57\u63a7\u5236\u663e\u793a\u7684\u5bbd\u5ea6\uff0c\u7b2c\u4e8c\u4e2a#\u8868\u793a\u5c0f\u6570\u70b9\u540e\u7cbe\u5ea6\uff0c\u5982 %3.1f - \uff1a\u5de6\u5bf9\u9f50\uff08\u9ed8\u8ba4\u53f3\u5bf9\u9f50\uff09\uff0c\u5982 %-15s + \uff1a\u663e\u793a\u6570\u503c\u7684\u6b63\u8d1f\u7b26\u53f7\uff0c\u5982 %+d \u793a\u4f8b\uff1a $ awk -F: '{printf \"%s\", $1}' /etc/passwd | head -n3 rootmessagebussystemd-networksystemd-timesyncnobodymailchronypostfixmanlpgamesftpdaemonrpcnscdpolkitdattftpftpsecurebinstatdsshdvagrantpesignsvntester1tester2tester3tester4tester5user0user1user2user3user4user5user6user7user8user9gentoonginxvarnishmysqlwebuseradmin3smithpm1tm1tm2 $ awk -F: '{printf \"%s\\n\", $1}' /etc/passwd | head -n3 root messagebus systemd-network $ awk -F: '{printf \"%20s\\n\", $1}' /etc/passwd | head -n3 root messagebus systemd-network $ awk -F: '{printf \"%-20s\\n\", $1}' /etc/passwd | head -n3 root messagebus systemd-network $ awk -F: '{printf \"%-20s %10d\\n\", $1, $3}' /etc/passwd | head -n3 root 0 messagebus 499 systemd-network 497 $ awk -F: '{printf \"Username: %s\\n\", $1}' /etc/passwd | head -n3 Username: root Username: messagebus Username: systemd-network $ awk -F: '{printf \"Username: %s UID:%d\\n\", $1, $3}' /etc/passwd | head -n3 Username: root UID:0 Username: messagebus UID:499 Username: systemd-network UID:497 $ awk -F: '{printf \"Username: %25s UID:%d\\n\", $1, $3}' /etc/passwd | head -n3 Username: root UID:0 Username: messagebus UID:499 Username: systemd-network UID:497 $ awk -F: '{printf \"Username: %-25s UID:%d\\n\", $1, $3}' /etc/passwd | head -n3 Username: root UID:0 Username: messagebus UID:499 Username: systemd-network UID:497 5.10.9.BEGIN/END \u00b6 \u793a\u4f8b\uff1a awk -F \":\" 'BEGIN{printf \"--------------------------------\\n%-20s|%10s|\\n--------------------------------\\n\", \"Username\", \"UID\"}{printf \"%-20s|%-10d|\\n--------------------------------\\n\", $1, $3}END{print \"end\"}' /etc/passwd -------------------------------- Username | UID | -------------------------------- root | 0 | -------------------------------- daemon | 1 | -------------------------------- bin | 2 | ------------------------------- ... ... -------------------------------- mfe | 997 | -------------------------------- end 5.10.10.\u5e38\u7528\u63a7\u5236\u8bed\u53e5 \u00b6 {statements;...} \u7ec4\u5408\u8bed\u53e5 if(condition){statements;...} if(condition){statements;...} else(statements;...) switch(expression){case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2;......;default: statementn} while(condition){statements;...} do(statements;...) while{condition} for(expr1;expr2;expr3) {statements;...} break continue exit if-else\u793a\u4f8b\uff1a $ cat < score.txt Name Score Tom 100 Jack 91 Bill 81 Jim 51 EOF $ awk 'NR!=1{score=$2;if($2>=80){print $1, \"Good\"}else if($2>=60){print $1, \"Pass\"}else{print $1, \"failed\"}}' score.txt Tom Good Jack Good Bill Good Jim failed switch\u793a\u4f8b\uff1a $ awk 'NR!=1{switch($2){case 100:print $1,\"good\"; case 60:print $1,\"Pass\"; default:print $1,\"others\"}}' score.txt Tom good Tom Pass Tom others Jack others Bill others Jim others while\u793a\u4f8b\uff1a $ awk 'BEGIN{i=0;sum=0;while(i<=100){sum+=i;i++};print sum}' 5050 do-while\u793a\u4f8b\uff1a $ awk 'BEGIN{i=0;sum=0;do{sum+=i;i++}while(i<101);print sum}' 5050 for\u793a\u4f8b\uff1a $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){sum+=i};print sum}' 5050 \u547d\u4ee4\u6548\u7387\u6bd4\u8f83\uff1a $ time ( awk 'BEGIN{i=0;sum=0;while(i<=100000){sum+=i;i++};print sum}' ) 5000050000 real 0m0.028s user 0m0.027s sys 0m0.001s $ time ( seq -s+ 1000000 | bc ) 500000500000 real 0m0.329s user 0m0.240s sys 0m0.094s $ time ( awk 'BEGIN{i=0;sum=0;for(i=1;i<=1000000;i++){sum+=i};print sum}' ) 500000500000 real 0m0.050s user 0m0.046s sys 0m0.004s contine\u793a\u4f8b\uff1a\u4e2d\u65ad\u5f53\u524d\u5faa\u73af\uff0c\u8fdb\u5165\u4e0b\u4e00\u6b21\u5faa\u73af\u3002 $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){if(i==50)continue;sum+=i};print sum}' 5000 contine\u793a\u4f8b\uff1a\u4e2d\u65ad\u6574\u4e2a\u5faa\u73af\u3002 $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){if(i==50)break;sum+=i};print sum}' 1225 next\u793a\u4f8b\uff1a\u63d0\u524d\u7ed3\u675f\u5bf9\u672c\u884c\u5904\u7406\uff0c\u76f4\u63a5\u8fdb\u5165\u4e0b\u4e00\u884c\u5904\u7406\uff08\u6ce8\uff0cawk\u81ea\u5faa\u73af\uff0c\u5e76\u975e\u524d\u9762\u7684for\u6216while\u5faa\u73af\uff09 $ awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd # \u5947\u6570\u884c\u6253\u5370 root 0 systemd-timesync 496 nobody 65534 chrony 494 games 492 daemon 2 rpc 490 polkitd 488 ftpsecure 486 sshd 484 vagrant 1000 svn 482 tester1 600 tester4 1002 user0 1004 user2 1006 user4 1008 user6 1010 user8 1012 gentoo 1014 varnish 1016 webuser 666 admin3 1020 smith 2002 tm1 2004 $ awk -F: '{if($3%2==0)next;print $1,$3}' /etc/passwd # \u5076\u6570\u884c\u6253\u5370 messagebus 499 systemd-network 497 mail 495 postfix 51 man 13 lp 493 ftp 491 nscd 489 at 25 tftp 487 bin 1 statd 485 pesign 483 tester2 601 tester3 1001 tester5 1003 user1 1005 user3 1007 user5 1009 user7 1011 user9 1013 nginx 1015 mysql 1017 pm1 2003 tm2 2005 5.10.11.\u6570\u7ec4 \u00b6 \u5173\u8054\u6570\u7ec4\u662f\u4e00\u79cd\u6570\u636e\u7ed3\u6784\uff0c\u4e5f\u79f0\u4e3a\u5b57\u5178\u6216\u6620\u5c04\u3002\u4e0e\u4f20\u7edf\u7684\u6570\u7ec4\u4e0d\u540c\uff0c\u5173\u8054\u6570\u7ec4\u7684\u7d22\u5f15\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\u7684\u6570\u636e\uff0c\u4f8b\u5982\u5b57\u7b26\u4e32\u6216\u5bf9\u8c61\uff0c\u800c\u4e0d\u4ec5\u4ec5\u662f\u6574\u6570\u3002 \u63d0\u793a\uff1a \u5728\u8ba1\u7b97\u673a\u7f16\u7a0b\u4e2d\uff0c\u9664\u4e86\u5173\u8054\u6570\u7ec4\uff0c\u8fd8\u6709\u5176\u4ed6\u51e0\u79cd\u5e38\u89c1\u7684\u6570\u7ec4\u7c7b\u578b\uff0c\u5305\u62ec\uff1a \u7ebf\u6027\u6570\u7ec4\uff08\u6216\u79f0\u4e3a\u7d22\u5f15\u6570\u7ec4\uff09\uff1a\u8fd9\u662f\u6700\u5e38\u89c1\u7684\u6570\u7ec4\u7c7b\u578b\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e00\u4e2a\u6570\u5b57\u7d22\u5f15\uff0c\u53ef\u4ee5\u7528\u6765\u5feb\u901f\u8bbf\u95ee\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u3002\u4f8b\u5982\uff0c\u5728C\u8bed\u8a00\u4e2d\uff0c\u6570\u7ec4\u7684\u6bcf\u4e2a\u5143\u7d20\u90fd\u53ef\u4ee5\u901a\u8fc7\u6570\u7ec4\u4e0b\u6807\u6765\u8bbf\u95ee\u3002 \u591a\u7ef4\u6570\u7ec4\uff1a\u591a\u7ef4\u6570\u7ec4\u662f\u4e00\u79cd\u6570\u7ec4\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u4e5f\u662f\u4e00\u4e2a\u6570\u7ec4\u3002\u5728\u4e8c\u7ef4\u6570\u7ec4\u4e2d\uff0c\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e24\u4e2a\u7d22\u5f15\uff08\u4f8b\u5982\uff0c\u884c\u548c\u5217\uff09\uff0c\u53ef\u4ee5\u7528\u4e8e\u8bbf\u95ee\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u3002\u5728\u9ad8\u7ef4\u6570\u7ec4\u4e2d\uff0c\u6bcf\u4e2a\u5143\u7d20\u90fd\u5177\u6709\u66f4\u591a\u7684\u7d22\u5f15\u3002 \u52a8\u6001\u6570\u7ec4\uff1a\u52a8\u6001\u6570\u7ec4\u662f\u4e00\u79cd\u53ef\u4ee5\u52a8\u6001\u8c03\u6574\u5927\u5c0f\u7684\u6570\u7ec4\u3002\u5728\u8bb8\u591a\u7f16\u7a0b\u8bed\u8a00\u4e2d\uff0c\u52a8\u6001\u6570\u7ec4\u53ef\u4ee5\u52a8\u6001\u5206\u914d\u5185\u5b58\uff0c\u4ee5\u4fbf\u5728\u7a0b\u5e8f\u8fd0\u884c\u65f6\u6839\u636e\u9700\u8981\u8c03\u6574\u6570\u7ec4\u7684\u5927\u5c0f\u3002 \u5411\u91cf\uff1a\u5411\u91cf\u662f\u4e00\u79cd\u6570\u7ec4\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u90fd\u662f\u76f8\u540c\u7684\u6570\u636e\u7c7b\u578b\u3002\u5411\u91cf\u901a\u5e38\u7528\u4e8e\u6267\u884c\u6570\u5b66\u8fd0\u7b97\u6216\u5904\u7406\u5927\u91cf\u6570\u5b57\u6570\u636e\u3002 \u5728 awk \u4e2d\u4f7f\u7528\u6570\u7ec4\u65f6\uff0c\u901a\u5e38\u4f1a\u5c06\u67d0\u4e9b\u503c\u4e0e\u4e00\u4e2a\u5b57\u7b26\u4e32\u76f8\u5173\u8054\uff0c\u4ee5\u4fbf\u5728\u9700\u8981\u65f6\u53ef\u4ee5\u901a\u8fc7\u8be5\u5b57\u7b26\u4e32\u5feb\u901f\u5730\u68c0\u7d22\u8be5\u503c\u3002 awk \u7684\u6570\u7ec4\u662f\u4e00\u4e2a\u5173\u8054\u6570\u7ec4\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u90fd\u7531\u4e00\u4e2a\u552f\u4e00\u7684\u952e\u503c\u548c\u4e00\u4e2a\u5bf9\u5e94\u7684\u503c\u7ec4\u6210\u3002\u952e\u503c\uff08\u6216\u79f0\u4e3a\u7d22\u5f15\uff09\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\u7684\u5b57\u7b26\u4e32\u3002 \u6570\u7ec4\u53ef\u4ee5\u901a\u8fc7\u4ee5\u4e0b\u8bed\u6cd5\u8fdb\u884c\u58f0\u660e\uff1a array_name [ index ] = value \u5176\u4e2d\uff0c array_name \u662f\u6570\u7ec4\u7684\u540d\u79f0\uff0c index \u662f\u5143\u7d20\u7684\u7d22\u5f15\u503c\uff0c value \u662f\u5143\u7d20\u7684\u503c\u3002 \u4f8b\u5982\uff0c\u4ee5\u4e0b\u662f\u4e00\u4e2a\u5305\u542b\u4e09\u4e2a\u5143\u7d20\u7684\u5173\u8054\u6570\u7ec4\u7684\u793a\u4f8b\uff1a array [ \"apple\" ] = 1 array [ \"banana\" ] = 2 array [ \"orange\" ] = 3 \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c array \u662f\u4e00\u4e2a\u5173\u8054\u6570\u7ec4\uff0c\u5176\u7d22\u5f15\u4e3a\u5b57\u7b26\u4e32\u7c7b\u578b\uff0c\u800c\u503c\u4e3a\u6574\u6570\u7c7b\u578b\u3002\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u7684\u65b9\u5f0f\u8bbf\u95ee\u8be5\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\uff1a value = array [ \"apple\" ] \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c value \u7684\u503c\u5c06\u4e3a 1 \uff0c\u56e0\u4e3a array[\"apple\"] \u7684\u503c\u4e3a 1 \u3002 \u4ee5\u4e0b\u662f\u7528 awk \u547d\u4ee4\u6765\u521b\u5efa\u4e0a\u9762\u90a3\u4e2a\u5305\u542b\u4e09\u4e2a\u5143\u7d20\u7684\u5173\u8054\u6570\u7ec4\uff0c\u904d\u5386\u5e76\u8f93\u51fa\u6570\u7ec4\u503c\uff1a awk 'BEGIN { array[\"apple\"]=1; array[\"banana\"]=2; array[\"orange\"]=3; for(i in array){print array[i]}}' 3 1 2 \u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u4e92\u6362\u4e86\u6570\u7ec4\u7684\u952e\u548c\u503c\u3002 $ awk 'BEGIN {arr[1]=\"apple\";arr[2]=\"banana\";arr[3]=\"orange\";for(i in arr){print arr[i]}}' apple banana orange \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c i \u662f\u6570\u7ec4 arr \u7684\u7d22\u5f15\u503c\uff0c arr[i] \u662f\u6570\u7ec4\u4e2d\u5bf9\u5e94\u7684\u5143\u7d20\u503c\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\u53ef\u4ee5\u5faa\u73af\u904d\u5386\u6574\u4e2a\u6570\u7ec4\uff0c\u5e76\u8f93\u51fa\u5176\u4e2d\u7684\u5143\u7d20\u3002 \u9664\u4e86\u4f7f\u7528\u5faa\u73af\u904d\u5386\u6570\u7ec4\u4e4b\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f7f\u7528 length \u51fd\u6570\u83b7\u53d6\u6570\u7ec4\u4e2d\u5143\u7d20\u7684\u6570\u91cf\u3002\u4f8b\u5982\uff1a $ awk 'BEGIN { arr[1]=\"apple\"; arr[2]=\"banana\"; arr[3]=\"orange\"; print length(arr) }' 3 \u4e0a\u9762\u7684\u793a\u4f8b\u5c06\u8f93\u51fa\u6570\u5b573\uff0c\u8868\u793a\u6570\u7ec4 arr \u4e2d\u5305\u542b\u4e09\u4e2a\u5143\u7d20\u3002 \u4e3e\u4f8b\uff1a\u53bb\u91cd\u590d\u8bb0\u5f55\u3002 line \u662f\u6570\u7ec4\u540d\uff0c $0 \u662f awk \u8bfb\u53d6\u7684\u5f53\u524d\u884c\u7684\u5185\u5bb9\u3002 line[$0] \u7b49\u4ef7\u4e8e line[\"a\"] \uff0c line[\"b\"] \uff0c......\u3002 \u6211\u4eec\u770b\u6267\u884c\u8fc7\u7a0b\uff1a awk\u8bfb\u5165\u7b2c1\u884c\uff1b \u6267\u884c line[\"a\"] \uff0c\u503c\u4e3a\u7a7a\uff1b \u6c42\u53cd\uff0c\u5219\u7b2c\u4e00\u884c\u7684\u503c\u53d8\u4e3a true \uff0c\u5373 !line[\"a\"]=true \uff1b \u5f53 !line[\"a\"] \u4e3a true \uff0c\u5219\u6253\u5370\u5f53\u524d\u884c\uff0c\u5373\u8f93\u51fa a \u5230\u5c4f\u5e55\uff1b \u6267\u884c line[\"a\"]++ \uff0c\u6ce8\u610f\u7b2c2\u6b65\u4e2d line[\"a\"] \u7684\u503c\u662f\u7a7a\uff0c\u6267\u884c ++ \u540e\u503c\u53d8\u4e3a 1 \u3002 \u540c\u7406\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u7b2c2\uff0c3\uff0c4\u884c\u90fd\u8f93\u51fa\u4e86\u3002 \u5f53\u8bfb\u5165\u7b2c5\u884c\u65f6\uff08\u7b2c\u4e8c\u4e2a a \uff09\uff0c\u6267\u884c line[\"a\"] \uff0c\u503c\u4e3a 1 \uff1b !line[\"a\"]=0 \uff0c\u5373false\uff1b\u5219\u4e0d\u6253\u5370\u5f53\u524d\u884c\uff0c\u5373\u4e0d\u8f93\u51fa a \u5230\u5c4f\u5e55\uff1b\u6267\u884c ++ \u540e\u503c\u53d8\u4e3a 2 \u5f53\u8bfb\u5165\u7b2c8\u884c\u65f6\uff08\u7b2c\u4e09\u4e2a a \uff09\uff0c\u6267\u884c line[\"a\"] \uff0c\u503c\u4e3a 2 \uff1b !line[\"a\"]=0 \uff0c\u5373false\uff1b\u5219\u4e0d\u6253\u5370\u5f53\u524d\u884c\uff0c\u5373\u4e0d\u8f93\u51fa a \u5230\u5c4f\u5e55\uff1b\u6267\u884c ++ \u540e\u503c\u53d8\u4e3a 3 \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8bfb\u5165\u7b2c\u4e8c\u4e2a b \uff0c c \uff0c d \uff0c e \uff0c\u90fd\u4e0d\u4f1a\u518d\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4ece\u800c\u5b9e\u73b0\u53bb\u91cd\u8f93\u51fa\u5230\u529f\u80fd\u3002 $ cat > test << EOF a b c d a c d a b b e EOF $ awk '!line[$0]++' test a b c d e \u4e3e\u4f8b\uff1a\u5224\u65ad\u6570\u7ec4\u7d22\u5f15\u662f\u5426\u5b58\u5728\u3002 \u65b9\u6cd5\uff1a in array \uff0c 0 \u8868\u793a\u4e0d\u5b58\u5728\uff0c 1 \u8868\u793a\u5b58\u5728\u3002 $ awk 'BEGIN{array[\"i\"]=\"x\";array[\"j\"]=\"j\";print \"i\" in array, \"y\" in array}' 1 0 $ awk 'BEGIN{array[\"i\"]=\"x\";array[\"j\"]=\"j\";if(\"i\" in array){print \"exits!\"}else{print \"not exists!\"}}' exits! $ awk 'BEGIN{array[\"i\"]=\"x\";array[\"j\"]=\"j\";if(\"abc\" in array){print \"exits!\"}else{print \"not exists!\"}}' not exists! \u4e3e\u4f8b\uff1a\u904d\u5386\u6570\u7ec4\u4e2d\u6bcf\u4e2a\u5143\u7d20\u3002 \u65b9\u6cd5\uff1a for(your_var in array){your_for_body} \uff0c\u6ce8\u610f\uff0cyour_var\u4f1a\u904d\u5386\u6bcf\u4e2a\u7d22\u5f15\u3002 $ awk 'BEGIN{weekday[\"mon\"]=\"Monday\";weekday[\"tue\"]=\"Tuesday\";for(i in weekday){print i,weekday[i]}}' tue Tuesday mon Monday $ awk 'BEGIN{weekday[\"mon\"]=\"Monday\";weekday[\"tue\"]=\"Tuesday\";for(i in weekday){print i\": \"weekday[i]}}' tue: Tuesday mon: Monday \u6ce8\u610f\u4e0b\u9762\u7684\u6362\u884c\u5199\u6cd5\uff0c\u4e0d\u9700\u8981\u53cd\u659c\u6760 \\ \u3002 $ awk 'BEGIN{ arr[\"x\"]=\"welcome\" arr[\"y\"]=\"to\" arr[\"z\"]=\"Shanghai\" for (i in arr) { print i, arr[i] } }' x welcome y to z Shanghai \u793a\u4f8b\uff1a\u683c\u5f0f\u5316\u8f93\u51fa\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002 $ awk -F: '{user[$1]=$3}END{for (i in user){print \"Username: \" i, \"UID: \" user[i]}}' /etc/passwd Username: sshd UID: 476 Username: rpc UID: 482 Username: tftp UID: 488 Username: usbmux UID: 480 Username: srvGeoClue UID: 487 ...... \u793a\u4f8b\uff1a\u663e\u793a\u4e3b\u673a\u8fde\u63a5\u72b6\u6001\u51fa\u73b0\u7684\u6b21\u6570\u3002 # \u4f20\u7edf\u65b9\u6cd5 $ ss -ant | awk 'NR>=2{print $1}' | sort | uniq -c $ ss -ant | awk 'NR!=1{print $1}' | sort | uniq -c 1 ESTAB 6 LISTEN # \u4f7f\u7528awk\u6570\u7ec4 $ ss -ant | awk 'NR>=2{state[$1]++}END{for(i in state){print state[i], i}}' $ ss -ant | awk 'NR!=1{state[$1]++}END{for(i in state){print state[i], i}}' 6 LISTEN 1 ESTAB 5.10.12.awk\u51fd\u6570 \u00b6 \u53c2\u8003\uff1a awk \u51fd\u6570\u5b98\u7f51 5.10.12.1.\u5185\u7f6e\u51fd\u6570 \u00b6 \u5728 awk \u4e2d\uff0c\u51fd\u6570\u662f\u4e00\u79cd\u7528\u4e8e\u6267\u884c\u7279\u5b9a\u4efb\u52a1\u6216\u8ba1\u7b97\u7279\u5b9a\u503c\u7684\u53ef\u91cd\u7528\u4ee3\u7801\u5757\u3002 awk \u63d0\u4f9b\u4e86\u8bb8\u591a\u5185\u7f6e\u51fd\u6570\uff0c\u53ef\u4ee5\u7528\u4e8e\u5904\u7406\u6587\u672c\u6570\u636e\u3001\u6267\u884c\u6570\u5b66\u8fd0\u7b97\u3001\u64cd\u4f5c\u5b57\u7b26\u4e32\u7b49\u3002 \u4ee5\u4e0b\u662f\u4e00\u4e9b\u5e38\u7528\u7684awk\u51fd\u6570\u793a\u4f8b\uff1a length(string) \uff1a\u8fd4\u56de\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u3002 $ awk 'BEGIN { str = \"Hello World\"; len = length(str); print len }' 11 $ cut -d: -f1 /etc/passwd | awk '{print length($1)}' | head -3 4 10 15 substr(string, start, length) \uff1a\u4ece\u6307\u5b9a\u4f4d\u7f6e\u5f00\u59cb\u63d0\u53d6\u5b57\u7b26\u4e32\u7684\u5b50\u4e32\u3002 $ awk 'BEGIN { str = \"Hello World\"; substring = substr(str, 7, 5); print substring }' World sub(regexp, replacement [, target]) \uff1a\u4ece\u5b57\u7b26\u4e32target\u4e2d\u641c\u7d22\u5339\u914dregexp\u7684\u5185\u5bb9\uff0c\u5e76\u628a\u7b2c\u4e00\u4e2a\u5339\u914d\u7684\u5185\u5bb9\u66ff\u6362\u4e3areplacement\u3002\u61d2\u60f0\u6a21\u5f0f\u3002 \u6ce8\u610f\uff1a sub() \u51fd\u6570\u5728\u539f\u59cb\u5b57\u7b26\u4e32\u4e0a\u8fdb\u884c\u66ff\u6362\u64cd\u4f5c\uff0c\u5e76\u8fd4\u56de\u66ff\u6362\u7684\u6b21\u6570\u3002 # \u5728\u539f\u59cb\u5b57\u7b26\u4e32\u4e2d\uff0c\u7b2c\u4e00\u4e2a\u5339\u914d\u5230\u7684\"at\"\u88ab\u66ff\u6362\u4e3a\"ith\"\uff0c\u56e0\u6b64\u8f93\u51fa\u7ed3\u679c\u4e2d\u7684\"at\"\u53d8\u4e3a\"ith\"\uff0c\u5176\u4ed6\u5730\u65b9\u7684\"at\"\u4fdd\u6301\u4e0d\u53d8 $ awk 'BEGIN { str = \"water, water, everywhere\"; sub(/at/, \"ith\", str); print str }' wither, water, everywhere # \u8fd4\u56de\u5339\u914d\u6b21\u6570 $ awk 'BEGIN { str = \"water, water, everywhere\"; str_new = sub(/at/, \"ith\", str); print str_new }' 1 $ echo \"2023:15:35 08:15:26\" | awk 'sub(/:/, \"-\", $0)' 2023 -15:35 08 :15:26 $ echo \"2023:15:35 08:15:26\" | awk 'sub(/:/, \"-\", $1)' 2023 -15:35 08 :15:26 $ echo \"2023:15:35 08:15:26\" | awk 'sub(/:/, \"-\", $2)' 2023 :15:35 08 -15:26 gsub(regexp, replacement [, target])\uff1a\u4ece\u5b57\u7b26\u4e32target\u4e2d\u641c\u7d22\u5339\u914dregexp\u7684\u5185\u5bb9\uff0c\u5e76\u628a\u5168\u90e8\u5339\u914d\u7684\u5185\u5bb9\u66ff\u6362\u4e3areplacement\u3002\u8d2a\u5a6a\u6a21\u5f0f\u3002 # \u5728\u539f\u59cb\u5b57\u7b26\u4e32\u4e2d\uff0c\u5c06\u6240\u6709\u5339\u914d\u5230\u7684\"at\"\u88ab\u66ff\u6362\u4e3a\"ith\" $ awk 'BEGIN { str = \"water, water, everywhere\"; gsub(/at/, \"ith\", str); print str }' wither, wither, everywhere # \u8fd4\u56de\u5339\u914d\u6b21\u6570 $ awk 'BEGIN { str = \"water, water, everywhere\"; str_new = gsub(/at/, \"ith\", str); print str_new }' 2 $ echo \"2023:15:35 08:15:26\" | awk 'gsub(/:/, \"-\", $0)' 2023 -15-35 08 -15-26 $ echo \"2023:15:35 08:15:26\" | awk 'gsub(/:/, \"-\", $1)' 2023 -15-35 08 :15:26 $ echo \"2023:15:35 08:15:26\" | awk 'gsub(/:/, \"-\", $2)' 2023 :15:35 08 -15-26 split(string, array, delimiter) \uff1a\u5c06\u5b57\u7b26\u4e32string\u6309\u6307\u5b9a\u5206\u9694\u7b26delimiter\u62c6\u5206\u6210\u6570\u7ec4array\u7684\u5143\u7d20\u3002 \u6ce8\u610f\uff1a\u7b2c\u4e00\u4e2a\u7d22\u5f15\u503c\u4e3a 1 \uff0c\u7b2c\u4e8c\u4e2a\u7d22\u5f15\u503c\u4e3a 2 . $ awk 'BEGIN { str = \"apple,banana,orange\"; split(str, fruits, \",\"); print fruits[2] }' banana $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[1]}' messagebus $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[2]}' x $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[3]}' 499 $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[7]}' /usr/bin/false index(string, search) \uff1a\u5728\u5b57\u7b26\u4e32\u4e2d\u67e5\u627e\u6307\u5b9a\u5b50\u4e32\u7684\u4f4d\u7f6e\u3002 $ awk 'BEGIN { str = \"Hello World\"; pos = index(str, \"World\"); print pos }' 7 sprintf(format, expression) \uff1a\u6839\u636e\u6307\u5b9a\u7684\u683c\u5f0f\u5c06\u8868\u8fbe\u5f0f\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\u3002 $ awk 'BEGIN { num = 3.14159; str = sprintf(\"%.2f\", num); print str }' 3 .14 rand() \uff1a\u8fd4\u56de\u4e00\u4e2a\u968f\u673a\u6570\uff0c\u503c\u5728 0 \u548c 1 \u4e4b\u95f4\u5747\u5300\u5206\u5e03\u3002\u8fd9\u4e2a\u503c\u53ef\u4ee5\u662f 0 \uff0c\u4f46\u4e0d\u4f1a\u662f 1 \u3002\u4ece\u4e0b\u9762\u7684\u4f8b\u5b50\u53ef\u4ee5\u770b\u51fa\uff0c\u8fd0\u884c\u7ed3\u679c\u90fd\u662f\u4e00\u6837\u7684\uff0c\u6240\u4ee5\u4ea7\u751f\u968f\u673a\u6570\u7684\u79cd\u5b50\u662f\u4e00\u6837\u7684\u3002 $ awk 'BEGIN{print rand()}' 0 .924046 $ awk 'BEGIN{print rand()}' 0 .924046 $ awk 'BEGIN{print rand()}' 0 .924046 srand() \uff1a\u914d\u5408 rand() \u51fd\u6570\uff0c\u751f\u6210\u968f\u673a\u6570\u79cd\u5b50\u3002 $ awk 'BEGIN{srand();print rand()}' 0 .112006 $ awk 'BEGIN{srand();print rand()}' 0 .663431 $ awk 'BEGIN{srand();print rand()}' 0 .541305 int() \uff1a\u8fd4\u56de\u6574\u6570\u3002 $ awk 'BEGIN{srand();print int(rand()*100)}' 84 $ awk 'BEGIN{srand();print int(rand()*100)}' 66 $ awk 'BEGIN{srand();print int(rand()*100)}' 8 system(command) \uff1a\u6267\u884ccommand\u547d\u4ee4\uff08\u53ef\u4ee5\u662f\u4efb\u4f55\u6709\u6548\u7684Shell\u547d\u4ee4\uff09\u5e76\u8fd4\u56de\u547d\u4ee4\u7684\u9000\u51fa\u72b6\u6001\u7801\u3002\u5141\u8bb8\u5728 awk \u811a\u672c\u4e2d\u6267\u884c\u5916\u90e8\u547d\u4ee4\uff0c\u5e76\u83b7\u53d6\u547d\u4ee4\u6267\u884c\u7684\u7ed3\u679c\u3002 # \u6267\u884cls -l\u547d\u4ee4\uff0c\u5e76\u5c06\u547d\u4ee4\u7684\u9000\u51fa\u72b6\u6001\u7801\u5b58\u50a8\u5728status\u53d8\u91cf\u4e2d\uff0c\u5e76\u6253\u5370status\u53d8\u91cf\u7684\u503c $ awk 'BEGIN { status = system(\"ls -l\"); print \"Exit status:\", status }' total 0 drwxr-xr-x 1 vagrant users 70 Jan 2 15 :54 Desktop drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Documents drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Downloads drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Music drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Pictures drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Public drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Templates drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Videos drwxr-xr-x 1 vagrant users 0 Mar 15 2022 bin Exit status: 0 $ awk 'BEGIN{score=100; system(\"echo your score is \" score)}' your score is 100 systime() \uff1a\u5f53\u524d\u65f6\u95f4\u52301970\u5e741\u67081\u65e5\u5230\u79d2\u6570 $ awk 'BEGIN{print systime()}' 1684158395 strftime(format, timestamp) \uff1a\u5c06\u65f6\u95f4\u6233timestamp\u8f6c\u6362\u4e3a\u6307\u5b9a\u683c\u5f0fformat\u7684\u65e5\u671f\u548c\u65f6\u95f4\u5b57\u7b26\u4e32\u3002timestamp\u901a\u5e38\u662f\u4e00\u4e2a\u4ee5\u79d2\u4e3a\u5355\u4f4d\u8868\u793a\u7684\u6574\u6570\u3002 \u5e38\u89c1\u7684\u683c\u5f0f\u5316\u5b57\u7b26\u4e32\u9009\u9879\uff1a %Y \uff1a\u56db\u4f4d\u6570\u7684\u5e74\u4efd\uff08\u4f8b\u5982\uff1a2023\uff09 %m \uff1a\u4e24\u4f4d\u6570\u7684\u6708\u4efd\uff0801-12\uff09 %d \uff1a\u4e24\u4f4d\u6570\u7684\u65e5\u671f\uff0801-31\uff09 %H \uff1a\u4e24\u4f4d\u6570\u7684\u5c0f\u65f6\uff0800-23\uff09 %M \uff1a\u4e24\u4f4d\u6570\u7684\u5206\u949f\uff0800-59\uff09 %S \uff1a\u4e24\u4f4d\u6570\u7684\u79d2\uff0800-60\uff09 %Z \uff1a\u65f6\u533a\u540d\u79f0\uff08\u4f8b\u5982\uff1aGMT\uff09 # \u5c06\u5f53\u524d\u65f6\u95f4\u6233\u8f6c\u6362\u4e3a\u683c\u5f0f\u4e3a\"YYYY-MM-DD HH:MM:SS\"\u7684\u65e5\u671f\u548c\u65f6\u95f4\u5b57\u7b26\u4e32 $ awk 'BEGIN { timestamp = systime(); str = strftime(\"%Y-%m-%d %H:%M:%S\", timestamp); print str }' 2023 -05-15 22 :01:35 # \u5c06\u5f53\u524d\u65f6\u95f4\u6233\u7684\u524d\u4e00\u5c0f\u65f6\uff083600\u79d2\uff09\u8f6c\u6362\u4e3a\u683c\u5f0f\u4e3a\"YYYY-MM-DD HH:MM:SS\"\u7684\u65e5\u671f\u548c\u65f6\u95f4\u5b57\u7b26\u4e32 $ awk 'BEGIN { timestamp = systime()-3600; str = strftime(\"%Y-%m-%d %H:%M:%S\", timestamp); print str }' 2023 -05-15 21 :01:43 5.10.12.2.\u81ea\u5b9a\u4e49\u51fd\u6570 \u00b6 \u4e3e\u4f8b\uff1a $ cat > func.awk << EOF function max(x,y){ x>y?var=x:var=y return var } BEGIN{print max(a,b)} EOF $ awk -v a = 30 -v b = 20 -f func.awk 30 \u4e3e\u4f8b\uff1a \u5728\u4e0b\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u5b9a\u4e49\u4e86\u4e00\u4e2a\u540d\u4e3a square() \u7684\u81ea\u5b9a\u4e49\u51fd\u6570\uff0c\u5b83\u63a5\u53d7\u4e00\u4e2a\u53c2\u6570 x \uff0c\u5e76\u8fd4\u56de x \u7684\u5e73\u65b9\u3002\u7136\u540e\uff0c\u5728\u4e3b\u4ee3\u7801\u5757\u4e2d\uff0c\u6211\u4eec\u58f0\u660e\u4e86\u4e00\u4e2a\u53d8\u91cf num \u5e76\u8d4b\u503c\u4e3a 5 \u3002\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u8c03\u7528\u4e86\u81ea\u5b9a\u4e49\u51fd\u6570 square() \uff0c\u4f20\u9012 num \u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u5c06\u8fd4\u56de\u503c\u5b58\u50a8\u5728\u53d8\u91cf result \u4e2d\u3002\u6700\u540e\uff0c\u6211\u4eec\u6253\u5370\u51fa result \u7684\u503c\u3002 $ cat > func.awk << EOF # \u81ea\u5b9a\u4e49\u51fd\u6570\uff1a\u8ba1\u7b97\u5e73\u65b9 function square(x) { return x * x; } # \u4f7f\u7528\u81ea\u5b9a\u4e49\u51fd\u6570 { num = 5; result = square(num); print \"\u5e73\u65b9\u7ed3\u679c\uff1a\" result; } EOF $ awk -f func.awk \u5e73\u65b9\u7ed3\u679c\uff1a25 \u4e3e\u4f8b\uff1a $ cat > func.awk << EOF # \u81ea\u5b9a\u4e49\u51fd\u6570\uff1a\u8ba1\u7b97\u6570\u7ec4\u5e73\u5747\u503c function calculateAverage(arr, size) { sum = 0; for (i = 1; i <= size; i++) { sum += arr[i]; } return sum / size; } # \u4f7f\u7528\u81ea\u5b9a\u4e49\u51fd\u6570 { # \u5b9a\u4e49\u6570\u7ec4 numbers[1] = 10; numbers[2] = 20; numbers[3] = 30; numbers[4] = 40; numbers[5] = 50; # \u8ba1\u7b97\u6570\u7ec4\u7684\u5e73\u5747\u503c size = 5; average = calculateAverage(numbers, size); print \"\u6570\u7ec4\u7684\u5e73\u5747\u503c\uff1a\" average; } EOF $ awk -f func.awk \u6570\u7ec4\u7684\u5e73\u5747\u503c\uff1a30 5.10.12.3.awk\u811a\u672c \u00b6 \u4e3e\u4f8b\uff1a # \u6ce8\u610f\u8f6c\u4e49 $ cat > passwd.awk << EOF {if(\\$3>=1000)print \\$1,\\$3} EOF $ awk -F: -f passwd.awk /etc/passwd nobody 65534 vagrant 1000 \u4e0a\u9762\u4f8b\u5b50\u4e5f\u53ef\u4ee5\u5199\u6210\u5982\u4e0b\u811a\u6b65\u683c\u5f0f\u3002 $ cat > test.awk << EOF #!/bin/awk -f # This is an awk script {if(\\$3>=1000)print \\$1,\\$3} EOF $ chmod +x test.awk $ ./test.awk -F: /etc/passwd nobody 65534 vagrant 1000 \u5411awk\u811a\u672c\u4f20\u9012\u53c2\u6570\uff1a \u683c\u5f0f\uff1a awkfile var=value var2=value2 ... inputfile \u8bf4\u660e\uff1a \u4e0a\u9762\u683c\u5f0f\u53d8\u91cf\u5728 BEGIN \u8fc7\u7a0b\u4e2d\u4e0d\u53ef\u7528\uff0c\u76f4\u5230\u9996\u884c\u8f93\u5165\u5b8c\u6210\u4ee5\u540e\uff0c\u53d8\u91cf\u624d\u53ef\u7528\u3002 \u53ef\u4ee5\u901a\u8fc7 -v \u53c2\u6570\uff0c\u8ba9 awk \u5728\u6267\u884c BEGIN \u4e4b\u524d\u5f97\u5230\u53d8\u91cf\u3002 \u547d\u4ee4\u884c\u4e2d\u6bcf\u4e00\u4e2a\u6307\u5b9a\u7684\u53d8\u91cf\u90fd\u9700\u8981\u4e00\u4e2a -v \u53c2\u6570\u3002 \u4e3e\u4f8b\uff1a # x=100\u5728BEGIN{print x}\u533a\u6bb5\u53ef\u7528 $ awk -v x = 100 'BEGIN{print x}{print x+100}' /etc/hosts 100 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 # \u4e0d\u52a0-v\u5219x=100\u5728BEGIN{print x}\u533a\u6bb5\u4e0d\u53ef\u7528 $ awk x = 100 'BEGIN{print x}{print x+100}' /etc/hosts awk: fatal: cannot open file ` BEGIN { print x }{ print x+100 } ' for reading (No such file or directory) # \u4fee\u6b63\u4e0a\u9762\u7684\u9519\u8bef\uff0c\u5c06x=100\u653e\u5728\u540e\u9762\uff0c\u56e0\u4e3a\u6ca1\u6709-v\uff0c\u6240\u4ee5x=100\u5728BEGIN{print x}\u533a\u6bb5\u4e0d\u53ef\u7528\uff0c\u7b2c\u4e00\u884c\u8f93\u51fa\u7a7a\u767d $ awk ' BEGIN { print x }{ print x+100 } ' x = 100 /etc/hosts 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 5.11.\u5c0f\u7ec3\u4e60 \u00b6 \u663e\u793a /proc/meminfo \u6587\u4ef6\u4e2d\u4ee5\u5927\u5c0fs\u5f00\u5934\u7684\u884c\uff0c\u8981\u6c42\u4f7f\u7528\u4e24\u79cd\u65b9\u6cd5\u3002 cat /proc/meminfo | grep -i \"^s\" cat /proc/meminfo | grep \"^[sS]\" \u663e\u793a /etc/passwd \u6587\u4ef6\u4e2d\u4e0d\u4ee5 /bin/bash \u7ed3\u5c3e\u7684\u884c\u3002 grep -v \"/bin/bash $ \" /etc/passwd \u663e\u793a\u7528\u6237 rpc \u9ed8\u8ba4\u7684shell\u7a0b\u5e8f\u3002 $ grep \"rpc\" /etc/passwd | cut -d \":\" -f 7 /sbin/nologin \u627e\u51fa /etc/passwd \u4e2d\u7684\u4e24\u4f4d\u6216\u4e09\u4f4d\u6570\u3002 grep -Eo \"[:digit:]{2,3}\" /etc/passwd grep -Eo \"[0-9]{2,3}\" /etc/passwd \u8fd9\u91cc\u7528\u5230\u4e86 {} \uff0c\u5c5e\u4e8e\u6269\u5c55\u6b63\u5219\u7b26\u53f7\uff0c\u6240\u4ee5\u8981\u7528 -E \u3002 \u663e\u793aRocky 9\u7684 /etc/grub2.cfg \u6587\u4ef6\u4e2d\uff0c\u81f3\u5c11\u4ee5\u4e00\u4e2a\u7a7a\u767d\u5b57\u7b26\u5f00\u5934\u7684\u4e14\u540e\u9762\u6709\u975e\u7a7a\u767d\u5b57\u7b26\u7684\u884c\u3002\uff08\u6ce8\uff1a /etc/grub2.cfg \u5728openSUSE\u548cUbuntu\u4e2d\u6ca1\u6709\uff09 # \u4e0d\u542b\u9996\u5b57\u7b26\u4e3atab $ sudo grep \"^ \" /etc/grub2.cfg # \u5305\u542b\u9996\u5b57\u7b26\u4e3atab $ sudo grep \"^[[:space:]]\" /etc/grub2.cfg \u627e\u51fa netstat -tan \u547d\u4ee4\u7ed3\u679c\u4e2d\u4ee5 LISTEN \u540e\u8ddf\u4efb\u610f\u591a\u4e2a\u7a7a\u767d\u5b57\u7b26\u7ed3\u5c3e\u7684\u884c\u3002 netstat -tan | grep -E \"LISTEN[[:space:]]+\" \u663e\u793aRocky 9\u4e0a\u6240\u6709UID\u5c0f\u4e8e1000\u4ee5\u5185\u7684\u7528\u6237\u540d\u548cUID\u3002 cat /etc/passwd | cut -d \":\" -f 1 ,3 | grep -E \"\\:[0-9]{1,3} $ \" grep -E \"\\:[0-9]{1,3}\\:[0-9]{1,}\" /etc/passwd | cut -d \":\" -f 1 ,3 \u5728Rocky 9\u4e0a\u663e\u793a\u6587\u4ef6 /etc/passwd \u7528\u6237\u540d\u548cshell\u540c\u540d\u7684\u884c\u3002 $ grep -E \"^([[:alnum:]]+\\b).*\\1 $ \" /etc/passwd sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt \u5229\u7528 df \u548c grep \uff0c\u53d6\u51fa\u78c1\u76d8\u5404\u5206\u533a\u5229\u7528\u7387,\u5e76\u4ece\u5927\u5230\u5c0f\u6392\u5e8f\u3002 $ df | tr -s \" \" | cut -d \" \" -f 1 ,5 | sort -n -t \" \" -k 2 devtmpfs 0 % Filesystem Use% tmpfs 0 % tmpfs 0 % /dev/mapper/rl-home 1 % tmpfs 2 % /dev/mapper/rl-root 5 % /dev/nvme0n1p1 23 % \u663e\u793a\u4e09\u4e2a\u7528\u6237 root \uff0c sync \uff0c bin \u7684UID\u548c\u9ed8\u8ba4shell\u3002 $ grep \"^root:\\|^sync:\\|^bin:\" /etc/passwd | cut -d \":\" -f 1 ,7 root:/bin/bash bin:/usr/sbin/nologin \u4f7f\u7528 egrep \u53d6\u51fa /etc/default-1/text_2/local.3/grub \u4e2d\u5176\u57fa\u540d\u548c\u76ee\u5f55\u540d\u3002 # \u57fa\u540d $ echo \"/etc/default-1/text_2/local.3/grub\" | egrep -io \"[[:alpha:]]+ $ \" grub # \u76ee\u5f55\u540d $ echo \"/etc/default-1/text_2/local.3/grub\" | egrep -io \"/([[:alpha:]]+.|_?[[:alpha:]]|[[:alnum:]]+/){7}\" /etc/default-1/text_2/local.3/ \u7edf\u8ba1 last \u547d\u4ee4\u4e2d\u4ee5 vagrant \u767b\u5f55\u7684\u6bcf\u4e2a\u4e3b\u673aIP\u5730\u5740\u767b\u5f55\u6b21\u6570\u3002 $ last | grep vagrant | tr -s \" \" | cut -d \" \" -f 3 | grep -E \"([0-9]{1,3}\\.){1,3}[0-9]{1,3}\" | sort -n | uniq -c 24 192 .168.10.107 38 192 .168.10.109 17 192 .168.10.201 6 192 .168.10.210 2 192 .168.10.220 \u5229\u7528\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\u5206\u522b\u8868\u793a0-9\u300110-99\u3001100-199\u3001200-249\u3001250-255\u3002 [ 0 -9 ] | [ 0 -9 ]{ 2 } | 1 [ 0 -9 ]{ 2 } | 2 [ 0 -4 ][ 0 -9 ] | 25 [ 0 -5 ] \u663e\u793a ifconfig \u547d\u4ee4\u7ed3\u679c\u4e2d\u6240\u6709IPv4\u5730\u5740\u3002 $ ifconfig | grep -Eo \"([0-9]{1,3}\\.){3}[0-9]{1,3}\" | grep -v \"^255\" 192 .168.10.210 192 .168.10.255 127 .0.0.1 \u663e\u793a ip addr \u547d\u4ee4\u7ed3\u679c\u4e2d\u6240\u6709IPv4\u5730\u5740\u3002 $ ip addr show eth0 | grep inet | grep eth0 | tr -s \" \" | cut -d \" \" -f 3 | cut -d \"/\" -f 1 192 .168.10.210 $ ip addr show | grep -Eo \"([0-9]{1,3}\\.){3}[0-9]{1,3}\" | grep -v \"^255\" 127 .0.0.1 192 .168.10.210 192 .168.10.255 \u5c06\u6b64\u5b57\u7b26\u4e32Welcome to the linux world\u4e2d\u7684\u6bcf\u4e2a\u5b57\u7b26\u53bb\u91cd\u5e76\u6392\u5e8f\uff0c\u91cd\u590d\u6b21\u6570\u591a\u7684\u6392\u5230\u524d\u9762\u3002 $ echo \"Welcome to the linux world\" | grep -o [[ :alpha: ]] | sort | uniq -c | sort -nr 3 o 3 l 3 e 2 t 1 x 1 W 1 w 1 u 1 r 1 n 1 m 1 i 1 h 1 d 1 c \u5220\u9664 /etc/default/grub \u6587\u4ef6\u4e2d\u6240\u6709\u4ee5\u7a7a\u767d\u5f00\u5934\u7684\u884c\u884c\u9996\u7684\u7a7a\u767d\u5b57\u7b26\u3002 sed '/^$/d' /etc/default/grub \u5220\u9664 /etc/default/grub \u6587\u4ef6\u4e2d\u6240\u6709\u4ee5 # \u5f00\u5934\uff0c\u540e\u9762\u81f3\u5c11\u8ddf\u4e00\u4e2a\u7a7a\u767d\u5b57\u7b26\u7684\u884c\u7684\u884c\u9996\u7684 # \u548c\u7a7a\u767d\u5b57\u7b26\u3002 sed -r '/#[[:space:]]+/d;/#/d' /etc/default/grub \u4e0a\u9762\u8f93\u51fa\u7ed3\u679c\u4e2d\u5305\u542b\u7a7a\u767d\u884c\u3002 \u82e5\u8f93\u51fa\u4e2d\u5220\u9664\u7a7a\u767d\u884c\uff0c\u5219\uff1a sed -r '/#[[:space:]]+/d;/#/d;/^$/d' /etc/default/grub \u5728 /etc/fstab \u6bcf\u4e00\u884c\u884c\u9996\u589e\u52a0 # \u53f7\u3002 sed -r 's/(.*)/#&/' /etc/fstab \u5728 /etc/fstab \u6587\u4ef6\u4e2d\u4e0d\u4ee5 # \u5f00\u5934\u7684\u884c\u7684\u884c\u9996\u589e\u52a0 # \u53f7\uff08\u5305\u62ec\u7a7a\u884c\uff09\u3002 sed -r 's/^[^#].*/#&/' -r 's/^$/#/' /etc/default/grub \u901a\u8fc7\u547d\u4ee4 rpm -qa --last |awk -F ' ' '{print $1}' \u5f97\u5230\u6700\u65b0\u5b89\u88c5\u7684\u5305\u5217\u8868\u3002\u7edf\u8ba1\u6240\u6709 x86_64 \u7ed3\u5c3e\u7684\u5b89\u88c5\u5305\u540d\u4ee5 . \u5206\u9694\u5012\u6570\u7b2c\u4e8c\u4e2a\u5b57\u6bb5\u7684\u91cd\u590d\u6b21\u6570\u3002 $ rpm -qa --last | awk -F ' ' '{print $1}' | sed -nr '/x86_64$/s@.*\\.(.*)\\.x86_64@\\1@p' | sort -r | uniq -c 75 el9_0 563 el9 3 7 1 5 2 4 2 3 10 2 29 1 \u5728openSUSE\u4e2d\u7edf\u8ba1 /etc/rc.status \u6587\u4ef6\u4e2d\u6bcf\u4e2a\u5355\u8bcd\u7684\u51fa\u73b0\u6b21\u6570\uff0c\u5e76\u6392\u5e8f\uff08\u7528grep\u548csed\u4e24\u79cd\u65b9\u6cd5\u5206\u522b\u5b9e\u73b0\uff09\u3002 grep -Eo \"[a-zA-Z]+\" /etc/rc.status | sort | uniq -c cat /etc/rc.status | sed -r 's/[^[:alpha:]]+/\\n/g' | sed '/^$/d' | sort | uniq -c | sort -nr \u5c06\u6587\u672c\u6587\u4ef6\u7684n\u548cn+1\u884c\u5408\u5e76\u4e3a\u4e00\u884c\uff0cn\u4e3a\u5947\u6570\u884c\u3002 $ cat < sed.txt 1aa 2bb 3cc 4dd 5ee 6ff 7gg EOF $ sed -n 'N;s/\\n//p' sed.txt 1aa2bb 3cc4dd 5ee6ff $ sed 'N;s/\\n//' sed.txt 1aa2bb 3cc4dd 5ee6ff 7gg \u5bf9\u4e00\u4e32\u6570\u5b57\u8fdb\u884c\u6c42\u548c\u3002 $ cat < number.txt 1 2 3 4 5 6 EOF $ tr ' ' + < number.txt | bc 21 $ sum = 0 ; for i in ` cat number.txt ` ; do let sum += i ; done ; echo $sum 21 $ awk '{sum=0;for(i=1;i<=NF;i++){sum+=i};print sum}' number.txt 21 \u53d6\u51fa\u5b57\u7b26\u4e32\u4e2d\u7684\u6570\u5b57\u3002 $ echo 'kdajl;3k8jd33la5kj23f90ld02sakjflakjdslf' | awk -F \"\" ' { for(i=1;i<=NF;i++) { if($i ~ /[0-9]/) { str=(str $i) } }; print str }' 38335239002 host.log \u6587\u4ef6\u5185\u5bb9\u5982\u4e0b\uff0c\u63d0\u53d6 .edu.cn \u524d\u9762\u7684\u4e3b\u673a\u540d\uff0c\u5e76\u56de\u5199\u5230\u8be5\u6587\u4ef6\u4e2d\u3002 $ cat > host.log << EOF 1 www.edu.cn 2 blog.edu.cn 3 learning.edu.cn 4 java.edu.cn 5 nodejs.edu.cn 6 k8s.eud.cn 7 linux.edu.cn 8 python.edu.cn 9 learning.edu.cn 10 java.edu.cn 11 nodejs.edu.cn 12 www.edu.cn EOF # \u5bf9\u6bd4 $ awk -F '[ .]' '{print $1}' host.log 1 2 3 4 5 6 7 8 9 10 11 12 $ awk -F '[ .]' '{print $2}' host.log www blog learning java nodejs k8s linux python learning java nodejs www # \u4ee5\u7a7a\u683c\u6216\u8005.\u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u7b2c\u4e8c\u5217\uff08\u4e3b\u673a\u540d\uff09\uff0c\u8ffd\u52a0\u5199\u5165\u539f\u6587\u4ef6 $ awk -F '[ .]' '{print $2}' host.log >> host.log $ cat host.log 1 www.edu.cn 2 blog.edu.cn 3 learning.edu.cn 4 java.edu.cn 5 nodejs.edu.cn 6 k8s.eud.cn 7 linux.edu.cn 8 python.edu.cn 9 learning.edu.cn 10 java.edu.cn 11 nodejs.edu.cn 12 www.edu.cn www blog learning java nodejs k8s linux python learning java nodejs www \u7edf\u8ba1\u6587\u4ef6 /etc/fstab \u4e2d\u6bcf\u4e2a\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u51fa\u73b0\u7684\u6b21\u6570\u3002 # \u4ee5UUID\u5f00\u5934\uff0c\u4e00\u4e2a\u6216\u591a\u4e2a\u7a7a\u683c\u4e3a\u5206\u9694\u7b26\uff0c\u8bfb\u53d6\u7b2c\u4e09\u5217\uff08\u5373\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\uff09\u5e76\u8ba1\u6570\u3002 $ awk -F ' +' '/^UUID/{fs[$3]++}END{for(i in fs){print i, fs[i]}}' /etc/fstab swap 1 btrfs 10 vfat 1 # \u65b9\u6cd52 $ awk -F ' +' '/^UUID/{print $3}' /etc/fstab | uniq -c 10 btrfs 1 swap 1 vfat \u7edf\u8ba1\u6587\u4ef6 /etc/fstab \u4e2d\u6bcf\u4e2a\u5355\u8bcd\u51fa\u73b0\u7684\u6b21\u6570\u3002 $ awk -F \"[^[:alpha:]]\" '{for(i=1;i<=NF;i++)word[$i]++}END{for(a in word)if(a!=\"\")print a,word[a]}' /etc/fstab swap 2 B 1 srv 2 btrfs 10 snapshots 2 vfat 1 opt 2 cbaef 10 UUID 12 E 1 ecf 1 CD 1 cf 1 arm 2 a 11 c 2 tmp 2 usr 2 var 2 afa 20 home 2 d 10 utf 1 e 2 efi 3 grub 2 boot 3 subvol 9 root 2 local 2 defaults 2 f 10 \u63d0\u53d6\u5b57\u7b26\u4e32 Yd$@C#M05MD9&8923+Vip3wZ!33*44&55 \u4e2d\u6240\u6709\u7684\u6570\u5b57\u3002 # \u5bf9\u6bd4\u5355\u5f15\u53f7\u548c\u53cc\u5f15\u53f7\u7684\u533a\u522b\u3002 $ echo \"Yd $@ C#M05MD9&8923+Vip3wZ!33*44&55\" echo \"Yd $@ C#M05MD9&8923+Vip3wZcgcreate -g cpu:mygroup44&55\" YdC#M05MD9 & 8923 +Vip3wZcgcreate -g cpu:mygroup44 & 55 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' Yd $@ C#M05MD9 & 8923 +Vip3wZ!33*44 & 55 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk '{gsub(/[^0-9]/,\"\");print $0}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '[^0-9]' '{for(i=1;i<=NF;i++){printf \"%s\", $i}}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F \"\" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' # \u6ce8\u610f\uff0c\u5982\u679c\u5199\u6210\u5982\u4e0b\u683c\u5f0f\uff0c\u5219\u62a5\u9519\u3002 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' # \u6ce8\u610f\uff0c\u5982\u679c\u5199\u6210\u5982\u4e0b\u683c\u5f0f\uff0c\u5219\u8f93\u51fa\u539f\u5b57\u7b26\u4e32\u3002 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F ' ' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' \u751f\u6210500\u4e2a\u968f\u673a\u6570\uff0c\u4fdd\u5b58\u5230\u6587\u4ef6random.txt\u4e2d\uff0c\u683c\u5f0f\u4e3a 100,20,61,98... \uff0c\u53d6\u51fa\u5176\u4e2d\u6700\u5927\u6574\u6570\u548c\u6700\u5c0f\u6574\u6570\u3002 $ str = \"\" ; for (( i = 1 ; i< = 500 ; i++ )) ; do if [ $i -ne 500 ] ; then str += \" $RANDOM ,\" ; else str += \" $RANDOM \" ; fi ; done ; echo \" $str \" > random.txt $ cat random.txt 11308 ,8764,2075,9411,...... $ awk -F, '{max=$1;min=$1;for(i=1;i<=NF;i++){if($i>max){max=$i}else{if($i200){system(\"iptables -A INPUT -s \" i \" -j REJECT;\")}}}' \u5c06\u4e0b\u9762\u5185\u5bb9\u4e2dFQDN\u53d6\u51fa\uff0c\u5e76\u6839\u636e\u5176\u8fdb\u884c\u8ba1\u6570\uff0c\u4ece\u9ad8\u5230\u4f4e\u6392\u5e8f\u3002 $ cat > fqdn.txt << EOF http://mail.edu.com/index.html http://www.edu.com/test.html http://study.edu.com/index.html http://blog.edu.com/index.html http://www.edu.com/images/logo.jpg http://blog.edu.com/20080102.html EOF $ awk -F \"/\" '{url[$3]++}END{for(i in url){print url[i], i}}' fqdn.txt | sort -nr 2 www.edu.com 2 blog.edu.com 1 study.edu.com 1 mail.edu.com \u5c06\u4ee5\u4e0b\u2f42\u672c\u4ee5inode\u4e3a\u6807\u8bb0\uff0c\u5bf9inode\u76f8\u540c\u7684counts\u8fdb\u2f8f\u7d2f\u52a0\uff0c\u5e76\u4e14\u7edf\u8ba1\u51fa\u540c\u4e00inode\u4e2d\uff0cbeginnumber\u7684\u6700\u5c0f\u503c\u548cendnumber\u7684\u6700\u5927\u503c\u3002 inode | beginnumber | endnumber | counts | 106 | 3363120000 | 3363129999 | 10000 | 106 | 3368560000 | 3368579999 | 20000 | 310 | 3337000000 | 3337000100 | 101 | 310 | 3342950000 | 3342959999 | 10000 | 310 | 3362120960 | 3362120961 | 2 | 311 | 3313460102 | 3313469999 | 9898 | 311 | 3313470000 | 3313499999 | 30000 | 311 | 3362120962 | 3362120963 | 2 | \u8f93\u51fa\u7684\u7ed3\u679c\u683c\u5f0f\u4e3a\uff1a 310 | 3337000000 | 3362120961 | 10103 | 311 | 3313460102 | 3362120963 | 39900 | 106 | 3363120000 | 3368579999 | 30000 | $ cat > inode.text << EOF inode|beginnumber|endnumber|counts| 106|3363120000|3363129999|10000| 106|3368560000|3368579999|20000| 310|3337000000|3337000100|101| 310|3342950000|3342959999|10000| 310|3362120960|3362120961|2| 311|3313460102|3313469999|9898| 311|3313470000|3313499999|30000| 311|3362120962|3362120963|2| EOF $ awk -F '|' -v OFS = '|' '/^[0-9]/{inode[$1]++; if(!bn[$1]){bn[$1]=$2}else if(bn[$1]>$2) {bn[$1]=$2}; if(en[$1]<$3)en[$1]=$3;cnt[$1]+=$(NF-1)} END{for(i in inode)print i,bn[i],en[i],cnt[i]}' inode.text 106 | 3363120000 | 3368579999 | 30000 310 | 3337000000 | 3362120961 | 10103 311 | 3313460102 | 3362120963 | 39900","title":"\u7b2c\u4e94\u7ae0 \u6b63\u5219\u8868\u8fbe\u5f0f"},{"location":"linux/SRE/05-RegExpress/#_1","text":"\u6b63\u5219\u8868\u8fbe\u5f0f\u5206\u4e24\u7c7b\uff1a \u57fa\u672c\u6b63\u5219\u8868\u8fbe\u5f0f\uff08Basic Regular Expression\uff0c \u53c8\u53ebBasic RegEx\uff0c\u7b80\u79f0BREs\uff09 \u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\uff08Extended Regular Expression\uff0c \u53c8\u53ebExtended RegEx\uff0c\u7b80\u79f0EREs\uff09 Perl\u6b63\u5219\u8868\u8fbe\u5f0f\uff08Perl Regular Expression\uff0c \u53c8\u53ebPerl RegEx \u7b80\u79f0PREs \u57fa\u672c\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u548c\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u533a\u522b\u5c31\u662f\u5143\u5b57\u7b26\u7684\u4e0d\u540c\u3002","title":"\u7b2c\u4e94\u7ae0 \u6b63\u5219\u8868\u8fbe\u5f0f"},{"location":"linux/SRE/05-RegExpress/#51","text":"^ \uff1a\u8868\u793a\u4ee5\u67d0\u4e2a\u5b57\u7b26\u5f00\u59cb $ \uff1a\u8868\u793a\u4ee5\u67d0\u4e2a\u5b57\u7b26\u7ed3\u5c3e . \uff1a\u8868\u793a\u5339\u914d\u4e00\u4e2a\u4e14\u53ea\u5339\u914d\u4e00\u4e2a\u5b57\u7b26 * \uff1a\u8868\u793a\u5339\u914d\u524d\u8fb9\u4e00\u4e2a\u5b57\u7b26\u51fa\u73b00\u6b21\u6216\u8005\u591a\u6b21 [] \uff1a\u8868\u793a\u5339\u914d\u62ec\u53f7\u5185\u7684\u591a\u4e2a\u5b57\u7b26\u4fe1\u606f,\u4e00\u4e2a\u4e00\u4e2a\u5339\u914d .* \uff1a\u8868\u793a\u5339\u914d\u6240\u6709\uff0c\u7a7a\u884c\u4e5f\u4f1a\u8fdb\u884c\u5339\u914d [^] \uff1a\u8868\u793a\u4e0d\u5339\u914d\u62ec\u53f7\u5185\u7684\u6bcf\u4e00\u4e2a\u5b57\u7b26 ^$ \uff1a\u8868\u793a\u5339\u914d\u7a7a\u884c\u4fe1\u606f \\ \uff1a\u5c06\u6709\u7279\u6b8a\u542b\u4e49\u7684\u5b57\u7b26\u8f6c\u4e49\u4e3a\u901a\u914d\u7b26","title":"5.1.\u57fa\u672c\u6b63\u5219\u8868\u8fbe\u5f0f\u7b26\u53f7"},{"location":"linux/SRE/05-RegExpress/#52","text":"+ \uff1a\u8868\u793a\u524d\u4e00\u4e2a\u5b57\u7b26\u51fa\u73b0\u4e00\u6b21\u6216\u4e00\u6b21\u4ee5\u4e0a ? \uff1a\u8868\u793a\u524d\u4e00\u4e2a\u5b57\u7b26\u51fa\u73b00\u6b21\u6216\u8005\u4e00\u6b21\u4ee5\u4e0a | \uff1a\u8868\u793a\u6216\u8005\u7684\u5173\u7cfb,\u5339\u914d\u591a\u4e2a\u4fe1\u606f () \uff1a\u5339\u914d\u4e00\u4e2a\u6574\u4f53\u4fe1\u606f\uff0c\u4e5f\u53ef\u4ee5\u63a5\u540e\u9879\u5f15\u7528 {} \uff1a\u5b9a\u4e49\u524d\u8fb9\u5b57\u7b26\u51fa\u73b0\u51e0\u6b21 \u63d0\u793a\uff1a grep -E \u6216\u8005 egrep \u53ea\u662f\u8868\u793a\u6269\u5c55\u6b63\u5219\uff0c\u4e0d\u4ee3\u8868\u52a0\u4e86e\u5c31\u8868\u793a\u8f6c\u4e49\u4e86\u3002 \u5f53 grep \u4f7f\u7528\u6269\u5c55\u6b63\u5219\u7684\u7b26\u53f7\u65f6\u5019\u9700\u8981\u7528 \\ \u8f6c\u4e49\u4e3a\u901a\u914d\u7b26\u624d\u80fd\u4f7f\u7528\u3002","title":"5.2.\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\u7b26\u53f7"},{"location":"linux/SRE/05-RegExpress/#53","text":"[:alpha:] \uff1a\u8868\u793a\u6240\u6709\u7684\u5b57\u6bcd\uff08\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff09\uff0c\u6548\u679c\u540c [a-z] [:digit:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u6570\u5b57\uff0c\u6548\u679c\u540c [0-9] [:xdigit:] \uff1a\u8868\u793a\u5341\u516d\u8fdb\u5236\u6570\u5b57 [:lower:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5c0f\u5199\u5b57\u6bcd [:upper:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5927\u5199\u5b57\u6bcd [:alnum:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5b57\u6bcd\u6216\u6570\u5b57 [:blank:] \uff1a\u8868\u793a\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u548c\u5236\u8868\u7b26\uff09 [:space:] \uff1a\u8868\u793a\u5305\u62ec\u7a7a\u683c\u3001\u5236\u8868\u7b26\uff08\u6c34\u5e73\u548c\u5782\u76f4\uff09\u3001\u6362\u884c\u7b26\u3001\u56de\u8f66\u7b26\u7b49\u5404\u79cd\u7c7b\u578b\u7684\u7a7a\u767d\uff0c\u6bd4 [:blank:] \u8303\u56f4\u66f4\u5e7f [:cntrl:] \uff1a\u8868\u793a\u4e0d\u53ef\u6253\u5370\u7684\u63a7\u5236\u5b57\u7b26\uff08\u9000\u683c\u3001\u5220\u9664\u3001\u8b66\u94c3\u7b49\uff09 [:graph:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u7684\u975e\u7a7a\u767d\u5b57\u7b26 [:print:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u5b57\u7b26 [:punct:] \uff1a\u8868\u793a\u6807\u70b9\u7b26\u53f7","title":"5.3.\u5b57\u7b26\u5339\u914d"},{"location":"linux/SRE/05-RegExpress/#54","text":"\u4f4d\u7f6e\u6807\u8bb0\u951a\u70b9\uff08position marker anchor\uff09\u662f\u6807\u8bc6\u5b57\u7b26\u4e32\u4f4d\u7f6e\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6b63\u5219\u8868\u8fbe\u5f0f\u6240\u5339\u914d\u7684\u5b57\u7b26\u53ef\u4ee5\u51fa\u73b0\u5728\u5b57\u7b26\u4e32\u4e2d\u4efb\u4f55\u4f4d\u7f6e\u3002 ^ \uff1a\u884c\u9996\u951a\u5b9a\uff0c\u6307\u5b9a\u4e86\u5339\u914d\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u6587\u672c\u5fc5\u987b\u8d77\u59cb\u4e8e\u5b57\u7b26\u4e32\u7684\u9996\u90e8\u3002 \u4f8b\u5982\uff1a ^tux \u80fd\u591f\u5339\u914d\u4ee5 tux \u8d77\u59cb\u7684\u884c $ \uff1a\u884c\u5c3e\u951a\u5b9a\uff0c\u6307\u5b9a\u4e86\u5339\u914d\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u6587\u672c\u5fc5\u987b\u7ed3\u675f\u4e8e\u76ee\u6807\u5b57\u7b26\u4e32\u7684\u5c3e\u90e8\u3002 \\< \u6216 \\b \uff1a\u8bcd\u9996\u951a\u5b9a\uff0c\u7528\u4e8e\u5355\u8bcd\u6a21\u5f0f\u5339\u914d\u5de6\u4fa7\u3002\uff08\u5355\u8bcd\u662f\u6709\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u4e0b\u5212\u7ebf\u7ec4\u6210\uff09 \\> \u6216 \\b \uff1a\u8bcd\u5c3e\u951a\u5b9a\uff0c\u7528\u4e8e\u5355\u8bcd\u6a21\u5f0f\u5339\u914d\u53f3\u4fa7\u3002\uff08\u5355\u8bcd\u662f\u6709\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u4e0b\u5212\u7ebf\u7ec4\u6210\uff09 ^PATTERN$ \uff1a\u7528\u6a21\u5f0fPATTERN\u5339\u914d\u6574\u884c\u3002 ^$ \uff1a\u5339\u914d\u7a7a\u884c\u3002 ^[[:space:]]*$ \uff1a\u5339\u914d\u7a7a\u767d\u884c\uff08\u6574\u884c\uff09\u3002 \\ \uff1a\u5339\u914d\u6574\u4e2a\u5355\u8bcd\u3002\uff08\u5355\u8bcd\u662f\u6709\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u4e0b\u5212\u7ebf\u7ec4\u6210\uff09 \u5173\u4e8e\u884c\u9996\u951a\u5b9a\u548c\u8bcd\u9996\u951a\u5b9a\uff0c\u5bf9\u6bd4\u4e0b\u9762\u4f8b\u5b50\u3002\u8bcd\u5c3e\u951a\u5b9a\u4e5f\u662f\u7c7b\u4f3c\u60c5\u51b5\u3002 ; \u548c - \u90fd\u88ab\u8ba4\u5b9a\u4e3a\u5355\u8bcd\u5206\u9694\u7b26\u3002 # \u7b26\u5408\u8bcd\u9996\u5339\u914d $ echo \"tux_01-tux02\" | grep '\\ mtu 1500 inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 inet6 fe80::20c:29ff:fea4:e17a prefixlen 64 scopeid 0x20 ether 00 :0c:29:a4:e1:7a txqueuelen 1000 ( Ethernet ) RX packets 7654 bytes 635932 ( 621 .0 KiB ) RX errors 0 dropped 1 overruns 0 frame 0 TX packets 1934 bytes 279649 ( 273 .0 KiB ) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 $ ifconfig eth0 | grep netmask | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' 192 .168.10.210 255 .255.255.0 192 .168.10.255 $ ifconfig eth0 | grep netmask | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' | head -n 1 192 .168.10.210 $ ifconfig eth0 | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' 192 .168.10.210 255 .255.255.0 192 .168.10.255 ifconfig eth0 | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' | head -n 1 192 .168.10.210 \u5339\u914d\u7a7a\u884c\u548c\u975e\u7a7a\u884c\uff1a grep '^$' /etc/profile grep -v '^$' /etc/profile \u5339\u914d\u975e\u7a7a\u884c\u548c\u975e#\u5f00\u5934\u7684\u884c\uff1a\uff08\u4e09\u79cd\u65b9\u6cd5\uff09 grep -v '^$' /etc/profile | grep -v '^#' grep -v '^$\\|#' /etc/profile grep '^[^$#]' /etc/profile \u6ce8\u610f\uff0c\u5982\u679c\u5199\u6210\u4e0b\u9762\u8fd9\u6837\uff0c\u5219\u4e0d\u4f1a\u8fc7\u6ee4\u6389\u7a7a\u884c\uff0c [$] \u4f1a\u88ab\u89c6\u4e3a $ \u7b26\u53f7\u3002 \u6240\u4ee5\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u5143\u5b57\u7b26\u653e\u5728\u4e2d\u62ec\u53f7 [] \u5185\u5c31\u88ab\u89c6\u4e3a\u666e\u901a\u5b57\u7b26\u3002 grep -v '^[$#]' /etc/profile","title":"5.7.\u5206\u7ec4"},{"location":"linux/SRE/05-RegExpress/#58grep","text":"\u683c\u5f0f\uff1a grep [OPTIONS] PATTERN [FILE...] grep [OPTIONS] -e PATTERN ... [FILE...] grep [OPTIONS] -f FILE ... [FILE...] \u53c2\u6570\uff1a -n \uff1a\u663e\u793a\u8fc7\u6ee4\u51fa\u6765\u7684\u6587\u4ef6\u5728\u6587\u4ef6\u5f53\u4e2d\u7684\u884c\u53f7 -c \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u884c\u6570 -o \uff1a\u53ea\u663e\u793a\u5339\u914d\u5230\u7684\u5185\u5bb9 -q \uff1a\u9759\u9ed8\u8f93\u51fa\uff08\u4e00\u822c\u7528\u5728shell\u811a\u672c\u5f53\u4e2d\uff0c\u901a\u8fc7 echo $? \u67e5\u770b\u547d\u4ee4\u6267\u884c\u7ed3\u679c\uff0c0\u8868\u793a\u6210\u529f\uff0c\u975e0\u8868\u793a\u5931\u8d25\uff09\uff09 -i \uff1a\u5ffd\u7565\u5927\u5c0f\u5199 -v \uff1a\u53cd\u5411\u67e5\u627e -w \uff1a\u5339\u914d\u67d0\u4e2a\u8bcd\u8bcd\uff1a\u5728Linux\u4e2d\uff0c\u8bcd\u4e3a\u4e00\u8fde\u4e32\u5b57\u6bcd\u3001\u6570\u5b57\u548c\u4e0b\u5212\u7ebf\u7ec4\u6210\u7684\u5b57\u7b26\u4e32 -E \uff1a\u4f7f\u7528\u6269\u5c55\u6b63\u5219 -R \uff1a\u9012\u5f52\u67e5\u8be2 -l \uff1a\u53ea\u6253\u5370\u6587\u4ef6\u8def\u5f84 \u6269\u5c55\u53c2\u6570\uff1a -A \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u6570\u636e\u7684\u540e\u51e0n\u884c -B \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u6570\u636e\u7684\u524d\u51e0n\u884c -C \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u6570\u636e\u7684\u524d\u540e\u5404\u51e0n\u884c \u793a\u4f8b\uff1a \u5339\u914d\u7528\u6237\uff1a grep root /etc/passwd root:x:0:0:root:/root:/bin/bash $ grep \"USER\" /etc/passwd $ grep \" $USER \" /etc/passwd vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash $ grep '$USER' /etc/passwd \u5339\u914d\u5173\u952e\u5b57\uff1a $ grep processor /proc/cpuinfo processor : 0 processor : 1 $ grep -o processor /proc/cpuinfo processor processor $ grep \"cpu family\" /proc/cpuinfo cpu family : 6 cpu family : 6 $ grep -o \"cpu family\" /proc/cpuinfo cpu family cpu family \u901a\u8fc7grep\u8fdb\u884c\u6587\u4ef6\u6bd4\u8f83\u3002 # \u6700\u540e\u4e00\u884c\u662f\u7a7a\u884c $ cat f1 a b 1 c # \u6700\u540e\u4e00\u884c\u662f\u7a7a\u884c $ cat f2 b e f c 1 2 # \u9ad8\u4eae\u663e\u793a\u76f8\u540c\u5185\u5bb9\u7684\u884c\uff0c\u5305\u542b\u6700\u540e\u4e00\u884c\u7a7a\u884c $ grep -f f1 f2 b e f c 1 2 # \u53ea\u663e\u793a\u76f8\u540c\u5185\u5bb9\u7684\u884c\uff0c\u5305\u542b\u6700\u540e\u4e00\u884c\u7a7a\u884c $ grep -wf f1 f2 b c 1 # \u53ea\u663e\u793a\u4e0d\u540c\u5185\u5bb9\u7684\u884c $ grep -wvf f1 f2 e f 2 \u63d0\u793a\uff1a grep -wvf f1 f2 \u6216\u8005 grep -w -v -f f1 f2 \u4e2d\uff0c -f \u53ea\u80fd\u4f5c\u4e3a\u6700\u540e\u4e00\u4e2a\u53c2\u6570\uff0c\u5426\u5219\u4f1a\u62a5\u9519\u3002 \u4f53\u4f1a\u57fa\u672c\u6b63\u5219\u548c\u6269\u5c55\u6b63\u5219\u7684\u5dee\u5f02\u3002 \u4f8b1\uff1a\u8f6c\u4e49\u3002 # \u4e0b\u9762\u51e0\u4e2a\u547d\u4ee4\u8fd4\u56de\u7684\u7ed3\u679c\u662f\u4e00\u6837\u7684\u3002 $ grep \"root\\|bash\" /etc/passwd $ grep -E \"root|bash\" /etc/passwd $ grep -e \"root\" -e \"bash\" /etc/passwd # \u4e0b\u9762\u7684\u547d\u4ee4\u6ca1\u6709\u5339\u914d\u7ed3\u679c\u8fd4\u56de\u3002 $ grep \"root|bash\" /etc/passwd \u4f8b2\uff1a\u4e0b\u97624\u4e2a\u547d\u4ee4\u8fd4\u56de\u540c\u6837\u7684\u7ed3\u679c\u3002 grep \"root\" /etc/passwd grep -E \"root\" /etc/passwd grep \"\\\" /etc/passwd grep -E \"\\\" /etc/passwd \u4f8b3\uff1a\u884c\u9996\u884c\u5c3e\u951a\u5b9a\u3002 $ grep \"^\\(.*\\)\\>.*\\<\\1 $ \" /etc/passwd $ grep -E \"^(.*)\\>.*\\<\\1 $ \" /etc/passwd $ egrep \"^(.*)\\>.*\\<\\1 $ \" /etc/passwd sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt \u4f8b4\uff1a\u4e09\u79cd\u65b9\u6cd5\u6c42\u548c\u8ba1\u7b97\uff0c\u8fd0\u7528 grep \uff0c cut \uff0c bc \u548c paste \u547d\u4ee4\u3002 $cat age Jason = 20 Tom = 30 Jack = 40 # \u65b9\u6cd51 $ cat age | cut -d \"=\" -f 2 | tr \"\\n\" + | grep -Eo \".*[0-9]\" | bc 90 # \u65b9\u6cd52 $ grep -Eo \"[0-9]+\" age | tr \"\\n\" + | grep -Eo \".*[0-9]\" | bc 90 # \u65b9\u6cd53 $ grep -Eo \"[0-9]+\" age | paste -s -d \"+\" | bc 90","title":"5.8.\u4e09\u5251\u5ba2grep\u547d\u4ee4"},{"location":"linux/SRE/05-RegExpress/#59sed","text":"sed \u662fstream editor\u7684\u7f29\u5199\uff0c\u4e2d\u6587\u79f0\u4e4b\u4e3a\u201c\u6d41\u7f16\u8f91\u5668\u201d\u3002 sed \u547d\u4ee4\u662f\u4e00\u4e2a\u9762\u5411\u884c\u5904\u7406\u7684\u5de5\u5177\uff0c\u5b83\u4ee5\u201c\u884c\u201d\u4e3a\u5904\u7406\u5355\u4f4d\uff0c\u9488\u5bf9\u6bcf\u4e00\u884c\u8fdb\u884c\u5904\u7406\uff0c\u5904\u7406\u540e\u7684\u7ed3\u679c\u4f1a\u8f93\u51fa\u5230\u6807\u51c6\u8f93\u51fa STDOUT \uff0c\u4e0d\u4f1a\u5bf9\u8bfb\u53d6\u7684\u6587\u4ef6\u505a\u4efb\u4f55\u4fee\u6539\u3002 sed \u7684\u5de5\u4f5c\u539f\u7406\uff1a sed \u547d\u4ee4\u662f\u9762\u5411\u201c\u884c\u201d\u8fdb\u884c\u5904\u7406\u7684\uff0c\u6bcf\u4e00\u6b21\u5904\u7406\u4e00\u884c\u5185\u5bb9\u3002 \u5904\u7406\u65f6\uff0c sed \u4f1a\u628a\u8981\u5904\u7406\u7684\u884c\u5b58\u50a8\u5728\u7f13\u51b2\u533a\u4e2d\uff0c\u63a5\u7740\u7528 sed \u547d\u4ee4\u5904\u7406\u7f13\u51b2\u533a\u4e2d\u7684\u5185\u5bb9\uff0c\u5904\u7406\u5b8c\u6210\u540e\uff0c\u628a\u7f13\u51b2\u533a\u7684\u5185\u5bb9\u9001\u5f80\u5c4f\u5e55\u3002\u63a5\u7740\u5904\u7406\u4e0b\u4e00\u884c\uff0c\u8fd9\u6837\u4e0d\u65ad\u91cd\u590d\uff0c\u76f4\u5230\u6587\u4ef6\u672b\u5c3e\u3002\u8fd9\u4e2a\u7f13\u51b2\u533a\u88ab\u79f0\u4e3a\u201c \u6a21\u5f0f\u7a7a\u95f4 \u201d\uff08pattern space\uff09\u3002 \u4fdd\u6301\u7a7a\u95f4(hold space) sed \u7684\u4fdd\u6301\u7a7a\u95f4\u50cf\u4e00\u4e2a\u957f\u671f\u50a8\u5b58\uff0c \u53ef\u4ee5\u628a\u83b7\u53d6\u7684\u4fe1\u606f\u50a8\u5b58\u5230\u5176\u4e2d\uff0c\u5f85\u540e\u7eed\u8c03\u7528\u3002\u4e0d\u80fd\u76f4\u63a5\u5bf9\u4fdd\u6301\u7a7a\u95f4\u8fdb\u884c\u64cd\u4f5c\uff0c \u800c\u662f\u5c06\u4fdd\u6301\u7a7a\u95f4\u7684\u5185\u5bb9\u590d\u5236\u6216\u8005\u6dfb\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u8fdb\u884c\u64cd\u4f5c\u3002 \u975e\u4ea4\u4e92\u5f0f\u6279\u91cf\u4fee\u6539\u6587\u4ef6\u3002 sed \u547d\u4ee4\u683c\u5f0f\uff1a sed [ option ] command file option \u5e38\u7528\u9009\u9879\uff1a -n \uff1a\u4e0d\u8f93\u51fa\u6a21\u5f0fpattern\u7684\u5185\u5bb9\u5230\u5c4f\u5e55\uff08\u5373\u4e0d\u81ea\u52a8\u6253\u5370\uff09 -e \uff1a\u591a\u70b9\u7f16\u8f91 -f filename \uff1a\u4ece\u6307\u5b9a\u6587\u4ef6\u8bfb\u53d6\u7f16\u8f91\u811a\u672c -r \uff0c -E \uff1a\u4f7f\u7528\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f -i .bak \uff1a\u5907\u4efd\u6587\u4ef6\u5e76\u539f\u5904\u7f16\u8f91 -s \uff1a\u5c06\u591a\u4e2a\u6587\u4ef6\u89c6\u4e3a\u72ec\u7acb\u6587\u4ef6\uff0c\u800c\u4e0d\u662f\u5355\u4e2a\u8fde\u7eed\u7684\u957f\u6587\u4ef6\u6d41 -ir \uff1a \u4e0d\u652f\u6301 -i -r \uff1a \u652f\u6301 -ri \uff1a \u652f\u6301 -ni \uff1a \u5371\u9669\u9009\u9879\uff0c\u4f1a\u6e05\u7a7a\u6587\u4ef6 command \u90e8\u5206\u53ef\u4ee5\u5206\u4e3a\u4e24\u90e8\u5206\uff1a \u8303\u56f4\u8bbe\u5b9a\uff0c\u53ef\u4ee5\u91c7\u7528\u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u6765\u8868\u8fbe\uff1a \u6307\u5b9a\u884c\u6570\uff1a\u5982\uff1a 3,5 \u8868\u793a\u7b2c3\u30014\u30015\u884c 5,$ \u8868\u793a\u7b2c5\u884c\u81f3\u6587\u4ef6\u6700\u540e\u4e00\u884c \u6a21\u5f0f\u5339\u914d\uff1a\u5982\uff1a /^[^dD]/ \u8868\u793a\u5339\u914d\u884c\u9996\u4e0d\u662f\u4ee5 d \u6216 D \u5f00\u5934\u7684\u884c \u52a8\u4f5c\u5904\u7406\uff0c\u4e0b\u9762\u662f\u5e38\u7528\u7684\u52a8\u4f5c\uff1a a \uff1a\u65b0\u589e\uff0c a \u540e\u9762\u7684\u5b57\u4e32\u4f1a\u5728\u65b0\u7684\u4e00\u884c\u51fa\u73b0\uff08\u5f53\u524d\u884c\u7684\u4e0b\u4e00\u884c\uff09 i \uff1a\u63d2\u5165\uff0c i \u540e\u9762\u7684\u5b57\u4e32\u4f1a\u5728\u65b0\u7684\u4e00\u884c\u51fa\u73b0\uff08\u5f53\u524d\u884c\u7684\u4e0a\u4e00\u884c\uff09 r filename \uff1a\u8bfb\u53d6\u6307\u5b9a\u6587\u4ef6 fllename \u7684\u5185\u5bb9\uff0c\u8ffd\u52a0\u5230\u5f53\u524d\u884c\u7684\u4e0b\u4e00\u884c R filename \uff1a\u8bfb\u53d6\u6307\u5b9a\u6587\u4ef6 fllename \u7684\u4e00\u884c\uff0c\u8ffd\u52a0\u5230\u5f53\u524d\u884c\u7684\u4e0b\u4e00\u884c d \uff1a\u5220\u9664\u8be5\u884c p \uff1a\u6253\u5370\u8be5\u884c Ip \uff1a\u5ffd\u7565\u5927\u5c0f\u5199\u8f93\u51fa w filename \uff1a\u5199\u5165\u5230\u6307\u5b9a\u6587\u4ef6filename\u4e2d\u3002 s/regexp/replacement/ \uff1a\u53d6\u4ee3\uff0c\u7528replacement\u53d6\u4ee3\u6b63\u5219regexp\u5339\u914d\u5230\u7684\u5185\u5bb9 = \uff1a\u4e3a\u6a21\u5f0fpattern\u4e2d\u7684\u5339\u914d\u884c\u6253\u5370\u884c\u53f7 ! \uff1a\u4e3a\u6a21\u5f0fpattern\u4e2d\u7684\u5339\u914d\u884c\u53d6\u53cd\u64cd\u4f5c q \uff1a\u7ed3\u675f\u6216\u9000\u51fased \u521b\u5efa\u4e00\u4e2a testfile \u6587\u4ef6\u3002 $ cat < testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob Tesetfile Wiki EOF \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u7b2c\u4e8c\u884c\uff0c\u5e76\u8f93\u51fa\uff08\u5305\u542b\u5339\u914d\u7b2c\u4e8c\u884c\u548c\u8f93\u51fa\u7b2c\u4e8c\u884c\uff09\u3002 # nl testfile | sed '2p' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u7b2c\u4e8c\u884c\uff0c\u4e0d\u8f93\u51fa\u3002 # nl testfile | sed -n '2p' 2 Linux is a free unix-type opterating system. \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u6700\u540e\u4e00\u884c\u3002 $ nl testfile | sed -n '$p' 9 Wiki \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u5012\u6570\u7b2c\u4e8c\u884c\u3002 # sed -n \"$(echo $[`cat testfile | wc -l`-1])p\" testfile Tesetfile \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u7b2c2\uff5e3\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\u3002 $ nl testfile | sed -n '2,3p' 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! \u5c06 testfile \u7684\u5185\u5bb9\u4ece\u7b2c2\u884c\u5f00\u59cb\uff0c\u5411\u540e\u8f93\u51fa\u989d\u5916\u76843\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\u3002 $ nl testfile | sed -n '2,+3p' 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test 5 Google \u5c06 testfile \u7684\u5185\u5bb9\u4ece\u7b2c2\u884c\u5f00\u59cb\uff0c\u5411\u540e\u4ee52\u4e3a\u6b65\u8fdb\u5355\u4f4d\u8f93\u51fa\u6240\u6709\u5339\u914d\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff08\u5373\uff0c\u4ece\u7b2c2\u884c\u5f00\u59cb\u8f93\u51fa\u5076\u6570\u884c\uff09\u3002 nl testfile | sed -n '2~2p' 2 Linux is a free unix-type opterating system. 4 Linux test 6 Taobao 8 Tesetfile \u5c06 testfile \u7684\u5185\u5bb9\u4ece\u7b2c2\u884c\u5f00\u59cb\uff0c\u5411\u540e\u4ee52\u4e3a\u6b65\u8fdb\u5355\u4f4d\u5220\u9664\u6240\u6709\u5339\u914d\u884c\uff0c\u8f93\u51fa\u5269\u4f59\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff08\u5373\uff0c\u4ece\u7b2c2\u884c\u5f00\u59cb\u5220\u9664\u5076\u6570\u884c\uff0c\u8f93\u51fa\u5947\u6570\u884c\uff09\u3002 $ nl testfile | sed '2~2d' 1 HELLO LINUX! 3 This is a linux testfile! 5 Google 7 Banbooob 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u8f93\u51fa\uff0c\u5220\u9664\u7b2c2\u884c\u548c\u7b2c5\u884c\uff0c\u5e76\u6253\u5370\u884c\u53f7\u3002 $ nl testfile | sed -e '2d' -e '5d' $ nl testfile | sed -e '2d;5d' $ nl testfile | sed '2d;5d' 1 HELLO LINUX! 3 This is a linux testfile! 4 Linux test 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u8f93\u51fa\uff0c\u8f93\u51fa\u533a\u95f4\u662f\u4ece\u884c\u9996 L \u7684\u884c\u5230\u884c\u9996 G \u7684\u884c\u7ed3\u675f\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 \u5982\u679c\u884c\u9996\u5339\u914d\u4e0d\u5230\uff0c\u5219\u65e0\u7ed3\u679c\u8f93\u51fa\uff1b\u5982\u679c\u884c\u5c3e\u5339\u914d\u4e0d\u5230\uff0c\u5219\u8f93\u51fa\u5230\u6587\u4ef6\u7ed3\u675f\u3002 $ sed -n '/^L/,/^G/p' testfile Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google \u5c06 testfile \u7684\u5185\u5bb9\u8f93\u51fa\uff0c\u4e14\u5728\u7b2c6\u884c\u540e\u52a0\u4e0a I love Linux \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -e '6a I love Linux' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao I love Linux Banbooob Tesetfile Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5728\u7b2c6\u884c\u540e\u6dfb\u52a0 I love Linux \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '6a I love Linux' $ nl testfile | sed '6a\\I love Linux' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao I love Linux 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5728\u7b2c3\u884c\u524d\u6dfb\u52a0 I am a journer learner \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '3i\\I am a journer learner' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. I am a journer learner 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5728\u7b2c3\u884c\u524d\u6dfb\u52a0\u4e09\u884c\u5185\u5bb9 Add line 1 \uff0c Add line 2 \uff0c Add line 3 \u3002\u7528\u7b26\u5408 \\ \u8fdb\u884c\u6362\u884c\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '3i\\Add line 1 \\ Add line 2 \\ Add line 3' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. Add line 1 Add line 2 Add line 3 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5c06\u7b2c2-5\u884c\u7684\u5185\u5bb9\u53d6\u4ee3\u6210\u4e3a replaced \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '2,5c\\replaced' $ nl testfile | sed '2,5c replaced' $ nl testfile | sed '2,5creplaced' 1 HELLO LINUX! replaced 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5220\u9664\u7b2c2~5\u884c\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '2,5d' 1 HELLO LINUX! 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5220\u9664\u7b2c5\u884c\u5230\u6700\u540e\u4e00\u884c\u3002 $ nl testfile | sed '5,$d' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u4e2d\u5305\u542b\u5173\u952e\u5b57 linux \u7684\u884c\u3002 $ sed -n '/linux/p' testfile This is a linux testfile! \u5339\u914d\u5b9a\u4f4d\u547d\u4ee4 df \u8f93\u51fa\u4e2d\u4ee5 /dev/sd \u5173\u952e\u5b57\u5f00\u5934\u7684\u884c\u3002\uff08\u9700\u8981\u8f6c\u4e49\u7b26 \\ \uff09 $ df | sed -n '/^\\/dev\\/sd/p' /dev/sda2 102750208 7077280 92055312 8 % / /dev/sda2 102750208 7077280 92055312 8 % /.snapshots /dev/sda2 102750208 7077280 92055312 8 % /home /dev/sda2 102750208 7077280 92055312 8 % /opt /dev/sda2 102750208 7077280 92055312 8 % /root /dev/sda2 102750208 7077280 92055312 8 % /boot/grub2/x86_64-efi /dev/sda2 102750208 7077280 92055312 8 % /boot/grub2/i386-pc /dev/sda2 102750208 7077280 92055312 8 % /srv /dev/sda2 102750208 7077280 92055312 8 % /tmp /dev/sda2 102750208 7077280 92055312 8 % /usr/local /dev/sda2 102750208 7077280 92055312 8 % /var \u5339\u914d\u5b9a\u4f4d\u547d\u4ee4 df \u8f93\u51fa\u4e2d\u4e0d\u4ee5 /dev/sd \u5173\u952e\u5b57\u5f00\u5934\u7684\u884c\u3002\u901a\u8fc7 !p \u8fdb\u884c\u6c42\u53cd\u8f93\u51fa\u3002 $ df | sed -n '/^\\/dev\\/sd/!p' Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 4096 0 4096 0 % /dev tmpfs 1971208 0 1971208 0 % /dev/shm tmpfs 788484 9612 778872 2 % /run tmpfs 4096 0 4096 0 % /sys/fs/cgroup tmpfs 394240 0 394240 0 % /run/user/1000 \u5339\u914d\u5b9a\u4f4d\u547d\u4ee4 df \u8f93\u51fa\u4e2d\u4e0d\u4ee5 /dev/sd \u548c tmp \u5173\u952e\u5b57\u5f00\u5934\u7684\u884c\u3002 $ df | sed '/^\\/dev\\/sd/d;/^tmp/d' Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 4096 0 4096 0 % /dev $ df | grep -Ev '^\\/dev\\/sd|^tmp' Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 4096 0 4096 0 % /dev \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b oo \u5173\u952e\u5b57\u7684\u884c\u5e76\u5339\u914d\u8f93\u51fa\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -n '/ooo/p' testfile Banbooob $ sed -n '/oo/p' testfile Google Banbooob \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b oo \u5173\u952e\u5b57\u7684\u884c\u5e76\u5220\u9664\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed '/oo/d' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Taobao Tesetfile Wiki \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b oo \u7684\u884c\uff0c\u628a oo \u66ff\u6362\u4e3a kk \uff0c\u518d\u8f93\u51fa\u8fd9\u884c\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -n '/oo/{s/oo/kk/;p;q}' testfile $ sed -ne '/oo/{s/oo/kk/;p;q}' testfile Gkkgle \u5c06 testfile \u7684\u6bcf\u884c\u4e2d\u7b2c\u4e00\u6b21\u51fa\u73b0 ao \u7684\u66ff\u6362\u6210 HH \u3002 $ sed 's/ao/HH/' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbao Banbooob Tesetfile Wiki \u4e0b\u9762\u662f\u628a testfile \u7684\u5339\u914d\u5230 ao \u7684\u884c\u66ff\u6362\u6210 HH \u3002 sed '/ao/cHH' testfile HELLO LINUX! SUSE This is a linux testfile! SUSE Google Taobao Banbooob Tesetfile Wiki \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b ao \u7684\u5168\u90e8\u66ff\u6362\u6210 HH \u3002 g \u8868\u793a\u5168\u5c40\u5339\u914d\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -e 's/ao/HH/g' testfile $ sed 's/ao/HH/g' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbHH Banbooob Tesetfile Wiki \u5728\u6587\u4ef6 /etc/passwd \u4e2d\u67e5\u627e\u5339\u914d\u6240\u6709\u7b26\u5408 r \u5f00\u5934 t \u7ed3\u5c3e\u4e14\u4e2d\u95f4\u542b\u4efb\u610f\u4e24\u4e2a\u5b57\u7b26\u7684\u884c\uff0c\u5e76\u5728 t \u5b57\u6bcd\u540e\u6dfb\u52a0 er \u3002 $ sed -nr 's/r..t/&er/gp' /etc/passwd rooter:x:0:0:rooter:/rooter:/bin/bash lp:x:493:487:Printering daemon:/var/spool/lpd:/usr/sbin/nologin tftp:x:487:474:TFTP account:/srv/terftpboot:/bin/false vagranter:x:1000:478:vagranter:/home/vagranter:/bin/bash tester1:x:600:1530: \"Test User1,terestuser1@abc.com\" :/home/tester1:/bin/bash \u5c06\u4e0a\u8ff0\u7ed3\u679c\u548c\u539f\u59cb\u5185\u5bb9\u8fdb\u884c\u5bf9\u6bd4\uff0c\u80fd\u66f4\u597d\u7684\u7406\u89e3 s/r..t/&er \u7684\u64cd\u4f5c\u3002 rooter:x:0:0:rooter:/rooter:/bin/bash root:x:0:0:root:/root:/bin/bash lp:x:493:487:Printering daemon:/var/spool/lpd:/usr/sbin/nologin lp:x:493:487:Printing daemon:/var/spool/lpd:/usr/sbin/nologin tftp:x:487:474:TFTP account:/srv/terftpboot:/bin/false tftp:x:487:474:TFTP account:/srv/tftpboot:/bin/false vagranter:x:1000:478:vagranter:/home/vagranter:/bin/bash vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash tester1:x:600:1530: \"Test User1,terestuser1@abc.com\" :/home/tester1:/bin/bash tester1:x:600:1530: \"Test User1,testuser1@abc.com\" :/home/tester1:/bin/bash \u4f53\u4f1a & \u7684\u4f4d\u7f6e\u4e0d\u540c\u7684\u4e0d\u540c\u542b\u4e49\u3002 # \u9644\u52a0\u5728root\u5355\u8bcd\u540e $ sed -n 's/root/&superman/p' /etc/passwd rootsuperman:x:0:0:root:/root:/bin/bash # \u9644\u52a0\u5728root\u5355\u8bcd\u524d $ sed -n 's/root/superman&/p' /etc/passwd supermanroot:x:0:0:root:/root:/bin/bash \u4f7f\u7528\u53c2\u6570 -i \u8fdb\u884c\u6e90\u6587\u4ef6\u4fee\u6539\u3002 $ sed -i 's/ao/HH/' testfile $ cat testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbao Banbooob Tesetfile Wiki \u6e90\u6587\u4ef6\u4fee\u6539\u524d\uff0c\u5907\u4efd\u5728\u65b0\u6587\u4ef6 testfile.new \u3002 $ sed -i.new 's/ao/HH/' testfile $ cat testfile.new HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob Tesetfile Wiki $ cat testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbao Banbooob Tesetfile Wiki \u8303\u4f8b\uff1a\u9664\u6307\u5b9a\u6587\u4ef6\u5916\uff0c\u5176\u4f59\u90fd\u5220\u9664\u3002 $ touch { 1 ..9 } file.txt $ ls 1file.txt 2file.txt 3file.txt 4file.txt 5file.txt 6file.txt 7file.txt 8file.txt 9file.txt $ ls | grep -E '(3|5|7)file\\.txt' 3file.txt 5file.txt 7file.txt $ ls | grep -Ev '(3|5|7)file\\.txt' 1file.txt 2file.txt 4file.txt 6file.txt 8file.txt 9file.txt \u4e0b\u9762\u56db\u79cd\u65b9\u6cd5\u5b9e\u73b0\u540c\u6837\u7684\u529f\u80fd $ rm ` ls | grep -Ev '(3|5|7)file\\.txt' ` $ ls | sed -n '/^[357]file.txt/!p' | xargs rm $ ls | grep -Ev '(3|5|7)file\\.txt' | sed -n 's/.*/rm &/p' | bash $ ls | grep -Ev '(3|5|7)file\\.txt' | sed -En 's/(.*)/rm &/p' | bash $ ls | grep -Ev '(3|5|7)file\\.txt' | sed -En 's/(.*)/rm \\1/p' | bash $ ls 3file.txt 5file.txt 7file.txt \u540e\u5411\u5f15\u7528 \\0 \\1 \\2 \u7b49\u3002 $ $echo 123456789 | sed -nE 's/(123)(456)(789)/\\1/p' 123 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\2/p' 456 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\3/p' 789 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\3\\1\\2/p' 789123456 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\1xyz\\2/p' 123xyz456 \u8303\u4f8b\uff1a\u83b7\u53d6\u5206\u533a\u5229\u7528\u7387 $ df | sed -En '/^\\/dev\\/sd/p' /dev/sda2 102750208 7079236 92053692 8 % / /dev/sda2 102750208 7079236 92053692 8 % /.snapshots /dev/sda2 102750208 7079236 92053692 8 % /boot/grub2/i386-pc /dev/sda2 102750208 7079236 92053692 8 % /boot/grub2/x86_64-efi /dev/sda2 102750208 7079236 92053692 8 % /home /dev/sda2 102750208 7079236 92053692 8 % /opt /dev/sda2 102750208 7079236 92053692 8 % /root /dev/sda2 102750208 7079236 92053692 8 % /srv /dev/sda2 102750208 7079236 92053692 8 % /usr/local /dev/sda2 102750208 7079236 92053692 8 % /tmp /dev/sda2 102750208 7079236 92053692 8 % /var $ df | sed -En '/^\\/dev\\/sd/s@.*([0-9]+)%.*@\\1@p' $ df | sed -En '/^\\/dev\\/sd/s#.*([0-9]+)%.*#\\1#p' # df | sed -En '/^\\/dev\\/sd/s/.*([0-9]+)%.*/\\1/p' 8 8 8 8 8 8 8 8 8 8 8 \u4f53\u4f1a\u4e0b\u9762\u7a7a\u683c\u548c\u62ec\u5f27\u5e26\u6765\u7684\u4e0d\u540c\u3002 $ df | sed -En '/^\\/dev\\/sd/s# .*([0-9]+)%.*# \\1#p' /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 $ df | sed -En '/^\\/dev\\/sd/s#( .*)([0-9]+)%.*# \\1#p' /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 $ df | sed -En '/^\\/dev\\/sd/s#( .*)([0-9]+)%.*# \\2#p' /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 \u8303\u4f8b\uff1a\u53d6\u5f97\u5f53\u524dIP\u5730\u5740\u3002 $ ifconfig eth0 eth0: flags = 4163 mtu 1500 inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 inet6 fe80::20c:29ff:fea4:e17a prefixlen 64 scopeid 0x20 ether 00 :0c:29:a4:e1:7a txqueuelen 1000 ( Ethernet ) RX packets 22923 bytes 1658298 ( 1 .5 MiB ) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3763 bytes 442641 ( 432 .2 KiB ) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 $ ip addr show eth0 2 : eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00 :0c:29:a4:e1:7a brd ff:ff:ff:ff:ff:ff altname enp2s1 altname ens33 inet 192 .168.10.210/24 brd 192 .168.10.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::20c:29ff:fea4:e17a/64 scope link valid_lft forever preferred_lft forever $ ifconfig eth0 | sed -En '2s/[^0-9]+([0-9.]+).*/\\1/p' $ ifconfig eth0 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*/\\1/p' $ ifconfig eth0 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*$/\\1/p' $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.*//p' $ ifconfig eth0 | sed -n '2s/^.*inet //;s/ netmask.*//p' $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\2/p' 192 .168.10.210 192 .168.10.210 192 .168.10.210 \u4f7f\u7528 \\0 \u8f93\u51fa\u5168\u90e8\u53d8\u91cf\u3002 $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\0/p' inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\1/p' inet $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\2/p' 192 .168.10.210 $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\3/p' netmask 255 .255.255.0 broadcast 192 .168.10.255 \u5bf9\u6bd4\u4e0b\u9762\u4e24\u4e2a\u6307\u4ee4\u7684\u5339\u914d\u5dee\u5f02\u3002 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/ netmask.*//p' 192 .168.10.210 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.* //p' 192 .168.10.210 192 .168.10.255 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask .*//p' 192 .168.10.210 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.*//p' 192 .168.10.210 \u8303\u4f8b\uff1a\u53d6\u57fa\u540d\u548c\u76ee\u5f55\u540d\u3002 \uff08 /etc/sysconfig/network-scripts/ \u76ee\u5f55\u5728Rocky9\u4e2d\u9ed8\u8ba4\u5df2\u521b\u5efa\uff0c\u5728openSUSE\u548cUbuntu\u4e2d\u6ca1\u6709\uff09 # \u53d6\u76ee\u5f55\u540d $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's#(^/.*/)([^/]+/?)#\\1#' $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\1/' /etc/sysconfig/ # \u53d6\u57fa\u540d $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's#(^/.*/)([^/]+/?)#\\2#' $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\2/' network-scripts/ # \u53d6\u76ee\u5f55\u540d $ echo \"/etc/sysconfig/network-scripts/dummyfile\" | sed -E 's#(^/.*/)([^/]+/?)#\\1#' $ echo \"/etc/sysconfig/network-scripts/dummyfille\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\1/' /etc/sysconfig/network-scripts/ # \u53d6\u57fa\u540d $ echo \"/etc/sysconfig/network-scripts/dummyfile\" | sed -E 's#(^/.*/)([^/]+/?)#\\2#' $ echo \"/etc/sysconfig/network-scripts/dummyfille\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\2/' dummyfille \u8303\u4f8b\uff1a\u53d6\u6587\u4ef6\u540d\u548c\u6587\u4ef6\u6269\u5c55\u540d $ echo 1_.file.tar.gz | sed -En 's/(.*)\\.([^.]+)$/\\1/p' $ echo 1_.file.tar.gz | sed -En 's@(.*)\\.([^.]+)$@\\1@p' 1_.file.tar $ echo 1_.file.tar.gz | sed -En 's/(.*)\\.([^.]+)$/\\2/p' $ echo 1_.file.tar.gz | sed -En 's@(.*)\\.([^.]+)$@\\2@p' gz $ echo 1_.file.tar.gz | grep -Eo '.*\\.' 1_.file.tar. $ echo 1_.file.tar.gz | grep -Eo '[^.]+$' gz \u8303\u4f8b\uff1a\u5c06\u975e # \u5f00\u5934\u7684\u884c\u6dfb\u52a0 # $ cat < testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob #Tesetfile #Wiki EOF $ sed -En 's/^[^#]/#&/p' testfile $ sed -En 's/^[^#](.*)/#\\1/p' testfile #HELLO LINUX! #Linux is a free unix-type opterating system. #This is a linux testfile! #Linux test #Google #Taobao #Banbooob \u8303\u4f8b\uff1a\u5c06 # \u5f00\u5934\u7684\u884c\u5220\u9664 # $ cat < testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob #Tesetfile #Wiki EOF $ sed -Ei.bak '/^#/s/^#//' testfile $ cat testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob Tesetfile Wiki sed \u4fdd\u6301\u7a7a\u95f4\uff08hold space\uff09\u7684\u4f8b\u5b50\uff1a d \uff1a\u5220\u9664pattern space\u7684\u5185\u5bb9\uff0c\u5f00\u59cb\u4e0b\u4e00\u4e2a\u5faa\u73af\u3002 D \uff1a\u5982\u679c\u6a21\u5f0f\u7a7a\u95f4\u4fdd\u62a4\u6362\u884c\u7b26\uff0c\u5219\u5220\u9664\u76f4\u5230\u7b2c\u4e00\u4e2a\u6362\u884c\u7b26\u5230\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u7684\u6587\u672c\uff0c\u5e76\u4e0d\u8bfb\u53d6\u65b0\u7684\u8f93\u5165\u884c\uff0c\u800c\u4f7f\u7528\u5408\u6210\u7684\u6a21\u5f0f\u7a7a\u95f4\u91cd\u65b0\u542f\u52a8\u5faa\u73af\u3002\u5982\u679c\u6a21\u5f0f\u7a7a\u95f4\u4e0d\u5305\u542b\u6362\u884c\u7b26\uff0c\u5219\u7c7b\u4f3c d \u547d\u4ee4\u542f\u52a8\u6b63\u5e38\u7684\u65b0\u5faa\u73af\u3002 h \u3001 H \uff1a\u590d\u5236/\u8ffd\u52a0\u6a21\u5f0f\u7a7a\u95f4\u7684\u5185\u5bb9\u5230\u4fdd\u6301\u7a7a\u95f4\u3002 g \u3001 G \uff1a\u590d\u5236/\u8ffd\u52a0\u4fdd\u6301\u7a7a\u95f4\u7684\u5185\u5bb9\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002 n \u3001 N \uff1a\u590d\u5236/\u8ffd\u52a0\u5339\u914d\u5230\u7684\u4e0b\u4e00\u884c\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002 p\uff1a\u6253\u5370\u5f53\u524d\u6a21\u5f0f\u7a7a\u95f4\u5185\u5bb9\u3002 P\uff1a\u6253\u5370\u6a21\u5f0f\u7a7a\u95f4\u5f00\u5934\u81f3 \\n \u7684\u5185\u5bb9\uff0c\u5e76\u8ffd\u52a0\u5230\u9ed8\u8ba4\u8f93\u51fa\u4e4b\u524d\u3002 x \uff1a\u4ea4\u6362\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u7684\u5185\u5bb9. \u4e3e\u4f8b\u89e3\u8bfb1\uff1a seq 10 \u547d\u4ee4\u8f93\u51fa1\uff5e10\u4e2a\u6570\u5b57\uff0c\u6bcf\u4e2a\u6570\u5b57\u4e00\u884c\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e00\u884c 1 \u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u56e0\u4e3a\u53c2\u6570 -n \uff0c\u6240\u4ee5\u8bfb\u53d6\u5230\u7684 1 \u4e0d\u6253\u5370\u5230\u5c4f\u5e55\u3002 \u6267\u884c n \u547d\u4ee4\uff0c\u5373\u8bfb\u53d6\u5339\u914d\u5230\u7684\u4e0b\u4e00\u884c\u5230\u6a21\u5f0f\u7a7a\u95f4\uff0c\u5373\u628a\u7b2c\u4e8c\u884c\u7684 2 \u8bfb\u53d6\u5e76\u8986\u76d6\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002 \u6267\u884c p \u547d\u4ee4\uff0c\u628a 2 \u8f93\u51fa\u5230\u5c4f\u5e55\u3002 \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8bfb\u53d6\u7b2c\u4e09\u884c\u7684 3 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff0c\u6267\u884c n \u547d\u4ee4\uff0c\u5c06\u7b2c\u56db\u884c\u7684 4 \u8bfb\u53d6\u5e76\u8986\u76d6\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u6267\u884c p \u547d\u4ee4\uff0c\u8f93\u51fa 4 \u5230\u5c4f\u5e55\u3002 \u4ee5\u6b64\u7c7b\u63a8\u3002 $ seq 10 | sed -n 'n;p' 2 4 6 8 10 seq 10 | sed 'n;p' 1 2 2 3 4 4 5 6 6 7 8 8 9 10 10 \u4e3e\u4f8b\u89e3\u8bfb2\uff1a seq 10 \u547d\u4ee4\u8f93\u51fa1\uff5e10\u4e2a\u6570\u5b57\uff0c\u6bcf\u4e2a\u6570\u5b57\u4e00\u884c\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e00\u884c\u5230 1 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c\u547d\u4ee4 N \uff0c\u5373\u8bfb\u53d6\u4e0b\u4e00\u884c\uff0c\u5373\u7b2c\u4e8c\u884c\u7684 2 \uff0c\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u6240\u4ee5\u5f53\u524d\u6a21\u5f0f\u7a7a\u95f4\u6709 1 \u548c 2 \u8fd92\u884c\u8bb0\u5f55\u3002 \u6267\u884c s/\\n// \uff0c\u628a\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u7684\u7b2c\u4e00\u884c\u7684 1 \u540e\u9762\u7684 \\n \u66ff\u6362\u4e3a\u7a7a\uff0c\u5373\uff0c\u539f\u6765\u6a21\u5f0f\u7a7a\u95f4\u7684\u4e24\u884c 1 \u548c 2 \u73b0\u5728\u5408\u5e76\u4e3a\u4e00\u884c\uff0c\u5373 12 \u3002 \u8bfb\u53d6\u7b2c\u4e09\u884c\u7684 3 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c\u547d\u4ee4 N \uff0c\u5373\u8bfb\u53d6\u4e0b\u4e00\u884c\uff0c\u5373\u7b2c\u56db\u884c\u7684 4 \uff0c\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u6240\u4ee5\u5f53\u524d\u6a21\u5f0f\u7a7a\u95f4\u6709 3 \u548c 4 \u8fd92\u884c\u8bb0\u5f55\u3002 \u6267\u884c s/\\n// \uff0c\u628a\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u7684\u7b2c\u4e00\u884c 3 \u540e\u9762\u7684 \\n \u66ff\u6362\u4e3a\u7a7a\uff0c\u5373\uff0c\u539f\u6765\u6a21\u5f0f\u7a7a\u95f4\u7684\u4e24\u884c 3 \u548c 4 \u73b0\u5728\u5408\u5e76\u4e3a\u4e00\u884c\uff0c\u5373 34 \u3002 \u4ee5\u6b64\u7c7b\u63a8\u3002 $ seq 10 | sed 'N;s/\\n//' 12 34 56 78 910 \u4e3e\u4f8b\u89e3\u8bfb3\uff1a seq 10 \u547d\u4ee4\u8f93\u51fa1\uff5e10\u4e2a\u6570\u5b57\uff0c\u6bcf\u4e2a\u6570\u5b57\u4e00\u884c\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e00\u884c\u5230 1 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c !G \uff0c\u5373\u5bf9\u7b2c\u4e00\u884c\u7684 1 \u4e0d\u6267\u884c G \u547d\u4ee4\u3002 \u6267\u884c h \u547d\u4ee4\uff0c\u5373\u628a 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u8986\u76d6\u81f3\u4fdd\u6301\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u90fd\u5b58\u6709 1 \u3002 \u6267\u884c $!d \uff0c\u5373\u4e0d\u662f\u6700\u540e\u4e00\u884c\u5c31\u4ece\u6a21\u5f0f\u7a7a\u95f4\u5220\u9664\uff0c\u6240\u4ee5\u628a 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u5220\u9664\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e8c\u884c\u5230 2 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c !G \uff0c\u5373\u5bf9\u7b2c\u4e8c\u884c\u7684 2 \u6267\u884c G \u547d\u4ee4\uff0c\u628a 1 \u4ece\u4fdd\u6301\u7a7a\u95f4\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u5b58\u6709 1 \uff0c\u6a21\u5f0f\u7a7a\u95f4\u5b58\u6709 2 \u548c 1 \u3002 \u6267\u884c h \u547d\u4ee4\uff0c\u5373\u628a 2 \u548c 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u8986\u76d6\u81f3\u4fdd\u6301\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u90fd\u5b58\u6709 2 \u548c 1 \u3002 \u6267\u884c $!d \uff0c\u5373\u4e0d\u662f\u6700\u540e\u4e00\u884c\u5c31\u4ece\u6a21\u5f0f\u7a7a\u95f4\u5220\u9664\uff0c\u6240\u4ee5\u628a 2 \u548c 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u5220\u9664\u3002 \u4ee5\u6b64\u7c7b\u63a8\uff0c\u76f4\u81f3\u8bfb\u53d6\u6700\u540e\u4e00\u884c10\u3002\u6b64\u65f6\uff0c\u6a21\u5f0f\u7a7a\u95f4\u662f 10 \uff0c\u4fdd\u6301\u7a7a\u95f4\u5b58\u6709 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002 \u6267\u884c !G \uff0c\u5373\u5bf9\u6700\u540e\u4e00\u884c\u7684 10 \u6267\u884c G \u547d\u4ee4\uff0c\u628a 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u4ece\u4fdd\u6301\u7a7a\u95f4\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u5b58\u6709 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002\uff0c\u6a21\u5f0f\u7a7a\u95f4\u5b58\u6709 10 \u3001 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002 \u6267\u884c h \u547d\u4ee4\uff0c\u5373\u628a 10 \u3001 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u8986\u76d6\u81f3\u4fdd\u6301\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u90fd\u5b58\u6709 10 \u3001 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002 \u6267\u884c $!d \uff0c\u5f53\u524d\u662f\u6700\u540e\u4e00\u884c\uff0c\u6240\u4ee5\u4e0d\u4ece\u6a21\u5f0f\u7a7a\u95f4\u5220\u9664\u5f53\u524d\u5185\u5bb9\u3002 \u8f93\u51fa\u6a21\u5f0f\u7a7a\u95f4\u5185\u5bb9\u81f3\u5c4f\u5e55\u3002\u537310\uff5e1\u3002 $ seq 10 | sed '1!G;h;$!d' 10 9 8 7 6 5 4 3 2 1 \u5176\u4ed6\u4e00\u4e9b\u4f8b\u5b50\uff1a $ seq 10 | sed -n '/3/{g;1!p;};h' 2 $ seq 10 | sed -nr '/3/{n;p}' 4 $ seq 10 | sed 'N;D' 10 $ seq 10 | sed '3h;9G;9!d' 9 3 $ seq 10 | sed '$!N;$!D' 9 10 $ seq 10 | sed '$!d' 10 $ seq 10 | sed 'G' 1 2 3 4 5 6 7 8 9 10 $ seq 10 | sed 'g' $ seq 10 | sed '/^$/d;G' 1 2 3 4 5 6 7 8 9 10 $ seq 10 | sed 'n;d' 1 3 5 7 9 $ seq 10 | sed -n '1!G;h;$p' 10 9 8 7 6 5 4 3 2 1","title":"5.9.\u4e09\u5251\u5ba2sed\u547d\u4ee4"},{"location":"linux/SRE/05-RegExpress/#510awk","text":"awk \u662f\u4e00\u4e2a\u6587\u672c\u5206\u6790\u5de5\u5177\u3002 grep \u64c5\u957f\u67e5\u627e\uff0c sed \u64c5\u957f\u7f16\u8f91\uff0c awk \u64c5\u957f\u6570\u636e\u5206\u6790\u5e76\u751f\u6210\u62a5\u544a\u3002 awk \u7684\u540d\u79f0\u5f97\u81ea\u4e8e\u5b83\u7684\u521b\u59cb\u4ebaAlfred Aho \u3001Peter Weinberger \u548c Brian Kernighan \u59d3\u6c0f\u7684\u9996\u4e2a\u5b57\u6bcd\u3002 awk \u67093\u4e2a\u4e0d\u540c\u7248\u672c: awk \u3001 nawk \u548c gawk \u3002\u6211\u4eec\u8bf4\u7684 awk \u4e00\u822c\u6307 gawk \u3002 gawk \u662f awk \u7684GNU\u7248\u672c\u3002 awk \u628a\u6587\u4ef6\u9010\u884c\u8bfb\u5165\uff0c\u4ee5\u7a7a\u683c\u4e3a\u9ed8\u8ba4\u5206\u9694\u7b26\u5c06\u6bcf\u884c\u5207\u7247\uff0c\u518d\u5bf9\u5207\u7247\u8fdb\u884c\u5206\u6790\u5904\u7406\u3002","title":"5.10.\u4e09\u5251\u5ba2awk\u547d\u4ee4"},{"location":"linux/SRE/05-RegExpress/#5101","text":"awk 'pattern{action statements;...}' {filenames} pattern \u8868\u793a awk \u5728\u6570\u636e\u4e2d\u67e5\u627e\u7684\u5185\u5bb9\u3002\u662f\u8981\u8868\u793a\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\uff0c\u7528\u659c\u6760\u62ec\u8d77\u6765\u3002 action \u662f\u5728\u627e\u5230\u5339\u914d\u5185\u5bb9\u65f6\u6240\u6267\u884c\u7684\u4e00\u7cfb\u5217\u547d\u4ee4\u3002 -F \uff1a\u6307\u5b9a\u5206\u9694\u7b26\uff0c\u540e\u9762\u7d27\u8ddf\u5355\u5f15\u53f7\uff0c\u5355\u5f15\u53f7\u5185\u662f\u5206\u9694\u7b26\u3002\u5982\u4e0d\u52a0 -F \u9009\u9879\uff0c\u5219\u4ee5\u7a7a\u683c\u6216\u8005tab\u4f5c\u4e3a\u5206\u9694\u7b26\u3002 -v \uff1avar=value\uff0c\u53d8\u91cf\u8d4b\u503c\u3002 \u63d0\u793a\uff1a -F \"\" \u6307\u5b9a\u7a7a\u5b57\u7b26\u4e32\u4f5c\u4e3a\u5b57\u6bb5\u5206\u9694\u7b26\uff0c\u4ece\u800c\u5c06\u8f93\u5165\u5b57\u7b26\u4e32\u4e2d\u7684\u6bcf\u4e2a\u5b57\u7b26\u4f5c\u4e3a\u4e00\u4e2a\u72ec\u7acb\u7684\u5b57\u6bb5\u8fdb\u884c\u5904\u7406\u3002\u7136\u540e\uff0c\u4f7f\u7528\u5faa\u73af\u904d\u5386\u6bcf\u4e2a\u5b57\u6bb5\uff0c\u5982\u679c\u5b57\u6bb5\u4e2d\u5305\u542b\u6570\u5b57\uff0c\u5219\u5c06\u5176\u6dfb\u52a0\u5230str1\u53d8\u91cf\u4e2d\u3002\u6700\u540e\uff0c\u6253\u5370str1\u7684\u503c\u3002 -F '' \u4e2d\u7684\u4e24\u4e2a\u5355\u5f15\u53f7\u4e4b\u95f4\u6ca1\u6709\u63d0\u4f9b\u6709\u6548\u7684\u5b57\u6bb5\u5206\u9694\u7b26\u3002\u5728awk\u4e2d\uff0c\u5b57\u6bb5\u5206\u9694\u7b26\u5fc5\u987b\u662f\u4e00\u4e2a\u975e\u7a7a\u5b57\u7b26\u4e32\u3002 \u793a\u4f8b\uff1a\u7b2c\u4e00\u4e2a\u548c\u7b2c\u4e09\u4e2a\u547d\u4ee4\u662f\u6b63\u786e\u7684\u3002 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F \"\" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F \"\" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'","title":"5.10.1.\u547d\u4ee4\u683c\u5f0f"},{"location":"linux/SRE/05-RegExpress/#5102","text":"\u6267\u884cBEGIN{action;...}\u8bed\u53e5\u5757\u4e2d\u7684\u8bed\u53e5\u3002 BEGIN\u8bed\u53e5\u5757\u518dawk\u8bfb\u5165\u8f93\u5165\u6d41\u4e4b\u524d\u88ab\u6267\u884c\u3002 \u662f\u53ef\u9009\u8bed\u53e5\u5757\u3002 \u5305\u542b\u521d\u59cb\u5316\u53d8\u91cf\uff0c\u6253\u5370\u8f93\u51fa\u8868\u683c\u7684\u8868\u5934\u7b49\u8bed\u53e5\u3002 \u4ece\u6587\u4ef6\u6216\u8005\u6807\u51c6\u8f93\u5165stdin\u8bfb\u53d6\u4e00\u884c\uff0c\u7136\u540e\u6267\u884cpattern{action;...}\u8bed\u53e5\u5757\u3002\u4ece\u7b2c\u4e00\u884c\u5f00\u59cb\u5230\u6700\u540e\u4e00\u884c\uff0c\u9010\u884c\u626b\u63cf\u6587\u4ef6\uff0c\u91cd\u590d\u8fd9\u4e2a\u52a8\u4f5c\uff0c\u76f4\u5230\u6587\u4ef6\u6216\u8005\u8f93\u5165\u6d41\u5168\u90e8\u88ab\u8bfb\u53d6\u5b8c\u6bd5\u3002 \u53ef\u9009\u8bed\u53e5\u5757\u3002 \u5982\u679c\u6ca1\u6709\u63d0\u4f9bpattern\u8bed\u53e5\u5757\uff0c\u5219\u9ed8\u8ba4\u6267\u884c{print}\u3002 \u5f53\u8bfb\u81f3\u6587\u4ef6\u6216\u8005\u8f93\u5165\u6d41\u672b\u5c3e\u65f6\uff0c\u6267\u884cEND{action;...}\u8bed\u53e5\u5757\uff0c\u6bd4\u5982\u6253\u5370\u6240\u6709\u884c\u7684\u5206\u6790\u7ed3\u679c\u8fd9\u7c7b\u6c47\u603b\u4fe1\u606f\u3002\u4e5f\u662f\u4e00\u4e2a\u53ef\u9009\u8bed\u53e5\u5757\u3002","title":"5.10.2.\u5de5\u4f5c\u8fc7\u7a0b"},{"location":"linux/SRE/05-RegExpress/#5103","text":"\u6709\u5206\u9694\u7b26\u5206\u9694\u7684\u5b57\u6bb5\uff08\u5217column\uff0c\u57dffield\uff09\uff0c\u6807\u8bb0 $1 \u3001 $2 \u3001 $3 \u3001...\u3001 $n \u79f0\u4e3a\u57df\u6807\u8bc6\uff0c $0 \u4e3a\u6240\u6709\u57df\u3002\u6ce8\u610f\uff0c\u548cshell\u53d8\u91cf\u4e2d\u7684 $ \u4e0d\u540c\u3002 \u6bcf\u4e00\u884c\u6210\u4e3a\u8bb0\u5f55\uff08record\uff09\u3002 \u5982\u679c\u7701\u7565action\uff0c\u5219\u9ed8\u8ba4\u6267\u884c print $0 \u64cd\u4f5c\u3002","title":"5.10.3.\u5206\u9694\u7b26\u3001\u57df\u548c\u8bb0\u5f55"},{"location":"linux/SRE/05-RegExpress/#5104action","text":"Output statements: print , printf Expressions: \u7b97\u672f\u3001\u6bd4\u8f83\u8868\u8fbe\u5f0f Compund statements: \u7ec4\u5408\u8bed\u53e5 Control statements: if , while \u8bed\u53e5 Input statements: \u52a8\u4f5c print \u683c\u5f0f\uff1a print item1, item2, ... \u8bf4\u660e\uff1a \u9017\u53f7\u5206\u9694\u7b26 \u8f93\u51faitem\u53ef\u4ee5\u662f\u5b57\u7b26\u4e32\uff0c\u4e5f\u53ef\u4ee5\u662f\u6570\u503c\uff0c\u662f\u5f53\u524d\u8bb0\u5f55\u7684\u5b57\u6bb5\u3001\u53d8\u91cf\u6216 awk \u8868\u8fbe\u5f0f\u3002 \u5982\u679c\u7701\u7565item\uff0c\u76f8\u5f53\u4e8e print $0 \u56fa\u5b9a\u5b57\u7b26\u9700\u8981\u7528\u53cc\u5f15\u53f7\uff0c\u800c\u53d8\u91cf\u548c\u6570\u5b57\u4e0d\u9700\u8981\u3002 \u793a\u4f8b\uff1a $ seq 5 | awk '{print \"hello awk\"}' hello awk hello awk hello awk hello awk hello awk $ seq 5 | awk '{print 3*5}' 15 15 15 15 15 $ awk -F ':' '{print \"hello\"}' /etc/passwd | head -5 hello hello hello hello hello $ awk -F ':' '{print}' /etc/passwd | head -5 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin systemd-timesync:x:496:496:systemd Time Synchronization:/:/usr/sbin/nologin nobody:x:65534:65534:nobody:/var/lib/nobody:/bin/bash $ awk -F ':' '{print $0}' /etc/passwd | head -5 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin systemd-timesync:x:496:496:systemd Time Synchronization:/:/usr/sbin/nologin nobody:x:65534:65534:nobody:/var/lib/nobody:/bin/bash $ awk -F ':' '{print $1,$3}' /etc/passwd | head -5 root 0 messagebus 499 systemd-network 497 systemd-timesync 496 nobody 65534 $ awk -F ':' '{print $1\"\\t\"$3}' /etc/passwd | head -5 root 0 messagebus 499 systemd-network 497 systemd-timesync 496 nobody 65534 $ grep \"^UUID\" /etc/fstab | awk '{print $2,$3}' / btrfs /var btrfs /usr/local btrfs /tmp btrfs /srv btrfs /root btrfs /opt btrfs /home btrfs /boot/grub2/x86_64-efi btrfs /boot/grub2/i386-pc btrfs /.snapshots btrfs swap swap \u793a\u4f8b\uff1a\u8bfb\u53d6\u5206\u533a\u5229\u7528\u7387\u3002 \u5206\u9694\u7b26\u4e2d\u7684\u5b9a\u4e49 [[:space:]]+|% \u7684\u542b\u4e49\uff0c\u4e00\u4e2a\u6216\u591a\u4e2a\u7a7a\u683c\u6216\u8005 % \u4f5c\u4e3a\u5206\u9694\u7b26\u3002 $ df | awk '{print $1,$5}' Filesystem Use% devtmpfs 0 % tmpfs 0 % tmpfs 2 % tmpfs 0 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % tmpfs 0 % $ df | grep '^/dev/sd' | awk -F '[[:space:]]+|%' '{print $1,$5}' $ df | grep '^/dev/sd' | awk -F ' +|%' '{print $1,$5}' /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 \u793a\u4f8b\uff1a\u8bfb\u53d6ifconfig\u8f93\u51fa\u7ed3\u679c\u4e2d\u7684ip\u5730\u5740\u3002 $ ifconfig eth0 | sed -n '2p' | awk '/netmask/{print $2}' 192 .168.10.210 $ ifconfig eth0 | sed -n '2p' | awk '{print $2}' 192 .168.10.210","title":"5.10.4.\u5e38\u7528action\u5206\u7c7b"},{"location":"linux/SRE/05-RegExpress/#5105pattern","text":"\u6839\u636epattern\u6761\u4ef6\uff0c\u8fc7\u6ee4\u5339\u914d\u7684\u884c\uff0c\u518d\u505a\u5904\u7406\u3002 \u5982\u679c\u672a\u6307\u5b9a\uff0c\u5373\u7a7a\u6a21\u5f0f\uff0c\u5219\u5339\u914d\u6bcf\u4e00\u884c\u3002 /regular expression/ \uff0c\u4ec5\u5904\u7406\u80fd\u591f\u6a21\u5f0f\u5339\u914d\u5230\u7684\u884c\uff08\u5373\u7ed3\u679c\u4e3a\u771f\uff09\uff0c\u9700\u8981\u7528 / \u8fdb\u884c\u62ec\u8d77\u6765\u3002 \u7ed3\u679c\u4e3a\u771f\uff0c\u5373\u975e0\u503c\u3001\u975e\u7a7a\u5b57\u7b26\u4e32 \u7ed3\u679c\u4e3a\u5047\uff0c\u53730\u503c\u3001\u7a7a\u5b57\u7b26\u4e32 \u793a\u4f8b\uff1a\u7a7a\u6a21\u5f0f awk -F \":\" '{print $1, $3}' /etc/passwd | head -n5 root 0 messagebus 499 systemd-network 497 systemd-timesync 496 nobody 65534 \u793a\u4f8b\uff1a\u975e\u7a7a\u6a21\u5f0f $ seq 5 | awk '0' $ seq 5 | awk '1' 1 2 3 4 5 $ seq 5 | awk '2' 1 2 3 4 5 $ seq 5 | awk '\"true\"' 1 2 3 4 5 $ seq 5 | awk '\"false\"' 1 2 3 4 5 $ seq 5 | awk 'true' $ seq 5 | awk 'false' $ seq 5 | awk '' $ seq 5 | awk '\"\"' $ seq 5 | awk '\"0\"' 1 2 3 4 5 \u4f53\u4f1a\u4e0b\u9762\u53d8\u91cf\u7684\u503c\u548c\u6b63\u786e\u4f7f\u7528\u53d8\u91cf\uff08\u5b57\u7b26\u4e32\u8fd8\u662f\u53d8\u91cf\uff1f\uff09 $ seq 5 | awk '\"test\"' 1 2 3 4 5 $ seq 5 | awk 'test' $ seq 5 | awk -v test = 0 '\"test\"' $ seq 5 | awk -v test = 0 'test' $ seq 5 | awk -v test = \"0\" 'test' $ seq 5 | awk -v test = \"0\" '\"test\"' 1 2 3 4 5 $ seq 5 | awk -v test = 1 'test' 1 2 3 4 5 \u4f53\u4f1a\u4e0b\u9762\u7684\u4e0e\u975e\u5224\u65ad\u3002 $ awk '1' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin $ awk '0' /etc/passwd | head -n3 $ awk '!1' /etc/passwd | head -n3 $ awk '!0' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin # i\u6ca1\u6709\u8d4b\u503c\uff0c\u4e3a\u5047\uff0c\u6ca1\u6709\u8f93\u51fa $ seq 5 | awk 'i' # i\u8d4b\u503c\u4e3a0\uff0c\u4e3a\u5047\uff0c\u6ca1\u6709\u8f93\u51fa $ seq 5 | awk 'i=0' # i\u8d4b\u503c\u4e3a1\uff0c\u4e3a\u771f\uff0c\u8f93\u51fa\u7b2c\u4e00\u884c\u7ed3\u679c\uff0c\u4ee5\u6b64\u7c7b\u63a8\uff0c\u6bcf\u884c\u90fd\u4e3a\u771f\uff0c\u8f93\u51fa\u5168\u90e8seq\u7684\u7ed3\u679c $ seq 5 | awk 'i=1' 1 2 3 4 5 # \u7b2c\u4e00\u6b21\u521d\u59cbi\u672a\u8d4b\u503c\uff0c\u4e3a\u5047\uff0c!i\u5219\u4e3a\u771f\uff0c\u8d4b\u503c\u7ed9i\uff0c\u6240\u4ee5i\u4e3a\u771f,\u8f93\u51faseq\u7b2c1\u884c\u7ed3\u679c # \u7b2c\u4e8c\u6b21\u521d\u59cbi\u4e3a\u771f\uff0c!i\u5219\u4e3a\u5047\uff0c\u8d4b\u503c\u7ed9i\uff0c\u6240\u4ee5i\u4e3a\u5047\uff0c\u4e0d\u8f93\u51faseq\u7b2c2\u884c\u7ed3\u679c # \u7b2c\u4e09\u6b21\u521d\u59cbi\u4e3a\u5047\uff0c!i\u5219\u4e3a\u771f\uff0c\u8d4b\u503c\u7ed9i\uff0c\u6240\u4ee5i\u4e3a\u771f\uff0c\u8f93\u51faseq\u7b2c3\u884c\u7ed3\u679c # \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8f93\u51faseq\u7ed3\u679c\u7684\u5947\u6570\u884c $ seq 5 | awk 'i=!i' 1 3 5 # \u4e0e\u4e0a\u4f8b\u7684\u533a\u522b\u5728\u4e8ei\u521d\u59cb\u503c\u672a\u771f\uff0c\u7b2c\u4e00\u6b21\u7684i\u503c\u4e3a\u5047\uff0c\u4e0d\u8f93\u51faseq\u7b2c1\u884c\u7ed3\u679c # \u7b2c\u4e8c\u6b21i\u7684\u521d\u59cb\u503c\u4e3a\u5047\uff0c\u901a\u8fc7i=!i\u53d8\u4e3a\u771f\uff0c\u6240\u4ee5\u8f93\u51faseq\u7684\u7b2c2\u884c\u7ed3\u679c # \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8f93\u51faseq\u7ed3\u679c\u7684\u5076\u6570\u884c $ seq 5 | awk -v i = 1 'i=!i' 2 4 # \u8f93\u51fa\u8ba1\u6570\u884c $ seq 5 | awk -v i = 0 'i=!i' 1 3 5 # \u53ea\u8f93\u51fai\u7684\u503c\uff0c\u4e0d\u8f93\u51faseq\u7684\u503c $ seq 5 | awk '{i=!i;print i}' 1 0 1 0 1 $ seq 5 | awk '{i=!i}' $ seq 5 | awk '(i=!i)' 1 3 5 $ seq 5 | awk '!(i=!i)' 2 4","title":"5.10.5.\u6a21\u5f0fPattern"},{"location":"linux/SRE/05-RegExpress/#5106","text":"\u793a\u4f8b\uff1a $ head -n2 /etc/passwd | awk -F ':' '{print $0}' root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false $ head -n2 /etc/passwd | awk -F ':' '{print $2}' x x $ head -n2 /etc/passwd | awk -F ':' '{print $1}' root messagebus $ head -n2 /etc/passwd | awk -F ':' '{print $1\"#\"$2\"#\"$3\"#\"$4}' root#x#0#0 messagebus#x#499#499","title":"5.10.6.\u622a\u53d6\u7247\u6bb5"},{"location":"linux/SRE/05-RegExpress/#5107","text":"","title":"5.10.7.\u64cd\u4f5c\u7b26"},{"location":"linux/SRE/05-RegExpress/#51071","text":"x+y \uff0c x-y \uff0c x*y \uff0c x/y \uff0c x^y \uff0c x%y \u3002 -x \uff1a\u8f6c\u6362\u4e3a\u8d1f\u6570 +x \uff1a\u5c06\u5b57\u7b26\u4e32\u8f6c\u6362\u4e3a\u6570\u503c \u5217\u503c\u4e4b\u95f4\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97\u3002 $ awk -F ':' '{$7=$3+$4;print $1,$3,$4,$7}' /etc/passwd | head -n5 root 0 0 0 messagebus 499 499 998 systemd-network 497 497 994 systemd-timesync 496 496 992 nobody 65534 65534 131068 \u8ba1\u7b97\u67d0\u4e2a\u5217\u7684\u603b\u548c\u3002 END \u8868\u793a\u6240\u6709\u7684\u884c\u90fd\u5df2\u7ecf\u6267\u884c\u3002 $ awk -F ':' '{(total=total+$3)}; END {print total}' /etc/passwd 103011","title":"5.10.7.1.\u7b97\u6570\u64cd\u4f5c\u7b26"},{"location":"linux/SRE/05-RegExpress/#51072","text":"\u6ca1\u6709\u64cd\u4f5c\u7b26\u53f7\uff0c\u5b57\u7b26\u4e32\u8fde\u63a5\u3002","title":"5.10.7.2.\u5b57\u7b26\u4e32\u64cd\u4f5c\u7b26"},{"location":"linux/SRE/05-RegExpress/#51073","text":"= \uff0c += \uff0c -= \uff0c *= \uff0c /= \uff0c %= \uff0c ^= \uff0c ++ \uff0c -- \u3002 \u793a\u4f8b\uff1a $ awk 'BEGIN{print i}' $ awk 'BEGIN{print i++}' #\u4ece0\u5f00\u59cb 0 $ awk 'BEGIN{print ++i}' 1 $ awk 'BEGIN{print i++, i}' 0 1 $ awk 'BEGIN{i=0;print i++, i}' 0 1 $ awk 'BEGIN{print ++i, i}' 1 1 $ awk 'BEGIN{i=0;print ++i, i}' 1 1 $ awk 'BEGIN{i=0;print i, i++}' 0 0 $ awk 'BEGIN{i=0;print i, ++i}' 0 1 $ seq 10 1 2 3 4 5 6 7 8 9 10 # n\u4ece0\u5f00\u59cb\u8ba1\u6570\uff0c\u8f93\u51fa\u7684\u662fn\u503c\uff0c\u4e0d\u662fseq\u7684\u8f93\u51fa\u7ed3\u679c $ seq 10 | awk '{print n++}' 0 1 2 3 4 5 6 7 8 9 # seq=1\u65f6\uff0c\u521d\u59cbn\u672a\u8d4b\u503c\uff0c\u4e3a\u5047\uff0c\u4e0d\u8f93\u51faseq\u7ed3\u679c\uff0cn++\u4e3a\u771f # seq=2\u65f6\uff0cn\u4e3a\u771f\uff0c\u8f93\u51faseq\u7ed3\u679c\uff0cn++\u4e3a\u771f # \u540e\u7eedn++\u90fd\u4e3a\u771f\uff0c\u6240\u4ee5seq\u7684\u7ed3\u679c\u51fa\u4e86\u7b2c\u4e00\u884c\u7531\u4e8en\u4e3a\u5047\u6ca1\u6709\u8f93\u51fa\uff0c\u5176\u4ed6\u884c\u90fd\u8f93\u51fa $ seq 10 | awk 'n++' 2 3 4 5 6 7 8 9 10 # \u53c2\u8003\u4e0a\u4f8b\uff0cn\u521d\u59cb\u672a\u8d4b\u503c\uff0c\u4f46\u6267\u884c++n\u540e\u4e3a\u771f\uff0c\u6240\u4ee5\u8f93\u51fa\u7b2c\u4e00\u884c\uff0c\u540e\u7eed\u884c\u90fd\u8f93\u51fa\u56e0\u4e3an\u4e00\u76f4\u4e3a\u771f $ seq 10 | awk '++n' 1 2 3 4 5 6 7 8 9 10 # n=0\u65f6++n=1\uff0c!++n=0\uff0c\u8f93\u51fa\u7b2c0\u884c $ awk -v n = 0 '!++n' /etc/passwd # n=0\u65f6n++=1\uff0c!n++=1\uff0c\u8f93\u51fa\u7b2c1\u884c $ awk -v n = 0 '!n++' /etc/passwd root:x:0:0:root:/root:/bin/bash $ awk -v n = 0 '!n++{print n}' /etc/passwd 1 # \u65e0\u7ed3\u679c\u8f93\u51fa $ awk -v n = 0 '!++n{print n}' /etc/passwd $ awk -v n = 1 '!n++{print n}' /etc/passwd $ awk -v n = 0 '!n++' /etc/passwd root:x:0:0:root:/root:/bin/bash # \u65e0\u7ed3\u679c\u8f93\u51fa $ awk -v n = 1 '!n++' /etc/passwd $ awk -v n = 2 '!n++' /etc/passwd","title":"5.10.7.3.\u8d4b\u503c\u64cd\u4f5c\u7b26"},{"location":"linux/SRE/05-RegExpress/#51074","text":"\u4f7f\u7528 == \u4ee3\u8868\u7b49\u4e8e\uff0c\u5373\u7cbe\u786e\u5339\u914d\u3002\u7c7b\u4f3c\u8fd8\u6709 > \u3001 >= \u3001 < \u3001 <= \u3001 != \u7b26\u53f7\u3002 \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e09\u5217\u7684\u503c\u4e3a 1000 \u7684\u884c\u3002 $ awk -F ':' '$3==\"100\"' /etc/passwd vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash \u5728\u548c\u6570\u5b57\u6bd4\u8f83\u65f6\uff0c\u82e5\u628a\u8981\u6bd4\u8f83\u7684\u6570\u5b57\u7528\u53cc\u5f15\u53f7\u5f15\u8d77\u6765\uff0c awk \u4f1a\u6309\u5b57\u7b26\u5904\u7406\uff0c\u4e0d\u52a0\u53cc\u5f15\u53f7\uff0c\u5219\u4f1a\u6309\u6570\u5b57\u5904\u7406\u3002 $ awk -F ':' '$3<=\"100\"' /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/usr/sbin/nologin $ awk -F ':' '$3<=100' /etc/passwd root:x:0:0:root:/root:/bin/bash postfix:x:51:51:Postfix Daemon:/var/spool/postfix:/usr/sbin/nologin man:x:13:62:Manual pages viewer:/var/lib/empty:/usr/sbin/nologin daemon:x:2:2:Daemon:/sbin:/usr/sbin/nologin at:x:25:25:Batch jobs daemon:/var/spool/atjobs:/usr/sbin/nologin bin:x:1:1:bin:/bin:/usr/sbin/nologin awk -F ':' '{if ($1==\"root\") {print $0}}' /etc/passwd awk -F ':' '$7!=\"/bin/false\"' /etc/passwd awk -F ':' '$3<$2' /etc/passwd","title":"5.10.7.4.\u6bd4\u8f83\u64cd\u4f5c\u7b26"},{"location":"linux/SRE/05-RegExpress/#51075","text":"&& \u8868\u793a\u201c\u5e76\u4e14\u201d || \u8868\u793a\u201c\u6216\u8005\u201d ! \u8868\u793a\u201c\u975e\u201d\uff08\u53d6\u53cd\uff09 awk -F ':' '$3>10 && $3<100' /etc/passwd awk -F ':' '$3>10 || $3<100' /etc/passwd awk -F ':' '($3==0)' /etc/passwd awk -F ':' '!($3==0)' /etc/passwd \u6ce8\u610f\u4e0b\u9762\u5bf9\u5b57\u7b26\u548c\u6570\u503c\u8fdb\u884c\u53d6\u53cd\u64cd\u4f5c\u7684\u7ed3\u679c\u3002 $ awk 'BEGIN{print i}' $ awk 'BEGIN{print !i}' 1 $ awk -v i = 10 'BEGIN{print i}' 10 $ awk -v i = 10 'BEGIN{print !i}' 0 $ awk -v i = -5 'BEGIN{print i}' -5 $ awk -v i = -5 'BEGIN{print !i}' 0 $ awk -v i = \"abc\" 'BEGIN{print i}' abc $ awk -v i = \"abc\" 'BEGIN{print !i}' 0 $ awk -v i = abc 'BEGIN{print i}' abc $ awk -v i = abc 'BEGIN{print !i}' 0 $ awk -v i = \"\" 'BEGIN{print i}' $ awk -v i = \"\" 'BEGIN{print !i}' 1 \u5728\u5206\u9694\u7b26\u5b9a\u4e49\u4e2d\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u3002 $ df | awk -F \" +|%\" '{print $5}' Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0 $ df | awk -F \"[[:space:]]+|%\" '{print $5}' Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0","title":"5.10.7.5.\u903b\u8f91\u64cd\u4f5c\u7b26"},{"location":"linux/SRE/05-RegExpress/#51076","text":"\u683c\u5f0f\uff1a selector?if-true-expression:if-false-expression $ awk -F ':' '{$3>1000?usertype=\"Common User\":usertype=\"Superuser\";printf\"%-20s:%12s\\n\", $1, usertype}' /etc/passwd | head -n5 root : Superuser messagebus : Superuser systemd-network : Superuser systemd-timesync : Superuser nobody : Common User","title":"5.10.7.6.\u4e09\u76ee\u6761\u4ef6\u8868\u8fbe\u5f0f"},{"location":"linux/SRE/05-RegExpress/#51078","text":"~ \uff1a\u5de6\u53f3\u662f\u5426\u5339\u914d !~ \uff1a\u5de6\u53f3\u662f\u5426\u4e0d\u5339\u914d \u793a\u4f8b\uff1a \u5339\u914d\u6587\u4ef6\u4e2d\u6307\u5b9a\u5b57\u7b26\u4e32 root \u7684\u6240\u6709\u884c\uff0c\u7c7b\u4f3cgrep\u547d\u4ee4\uff0c\u4f46\u6ca1\u6709\u9ad8\u4eae\u663e\u793a\u3002 $ awk '/root/' /etc/passwd root:x:0:0:root:/root:/bin/bash \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e00\u5217 $1 \u4e2d\u5305\u542b\u6307\u5b9a\u5b57\u7b26\u4e32 oo \u7684\u884c\u3002 ~ \u662f\u4ee3\u8868\u5de6\u53f3\u5339\u914d\u3002 $ awk -F ':' '$1 ~/oo/' /etc/passwd root:x:0:0:root:/root:/bin/bash gentoo:x:1014:100:Gentoo Distribution:/home/gentoo:/bin/csh \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u5217 $0 \uff08\u6574\u884c\uff09\u4e2d\u5305\u542b root \u884c\u7684\u7b2c\u4e00\u5217 $1 \u3002 $ awk -F: '$0 ~/root/{print $1}' /etc/passwd $ awk -F: '$0 ~\"root\"{print $1}' /etc/passwd root daemon _cvmsroot \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u5217 $0 \uff08\u6574\u884c\uff09\u4e2d\u4ee5 root \u5f00\u5934\u884c\u7684\u7b2c\u4e00\u5217 $1 \u3002 $ awk -F: '$0 ~\"^root\"{print $1}' /etc/passwd $ awk -F: '$0 ~/^root/{print $1}' /etc/passwd root \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u5217 $0 \uff08\u6574\u884c\uff09\u4e2d\u4e0d\u4ee5 root \u5f00\u5934\u884c\u7684\u7b2c\u4e00\u5217 $1 \u3002 awk -F: '$0 !~/^root/{print $1}' /etc/passwd awk -F: '$0 ~/^[^root]/{print $1}' /etc/passwd \u591a\u6761\u4ef6\u5339\u914d\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u542b\u6709 root \u6216 ftp \u7684\u884c\uff0c\u5e76\u6253\u5370\u7b2c1\u30013\u5217\u3002 awk -F ':' '/root/ {print $1,$3} /bin/ {print $1,$3}' /etc/passwd \u591a\u6761\u4ef6\u5339\u914d\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e00\u5217\u4e2d\u542b\u6709 root \u6216 bin \u7684\u884c\uff0c\u5e76\u6253\u5370\u7b2c1\u30013\u5217\u3002 $ awk -F ':' '$1 ~/root/ {print $1,$3} $1 ~/bin/ {print $1,$3}' /etc/passwd root 0 bin 1 \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e09\u5217 $3 \u4e2d\u503c\u4e3a 0 \u7684\u884c\u3002 $ awk -F \":\" '$3==0' /etc/passwd root:x:0:0:root:/root:/bin/bash \u4ee5\u81f3\u5c11\u4e00\u4e2a\u7a7a\u683c\u6216%\u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u4ee5 /dev/sd \u5f00\u5934\u7684\u884c\uff0c\u6253\u5370\u7b2c\u4e94\u5217\u3002 $ df | awk -F \"[[:space:]]+|%\" '$0 ~ /^\\/dev\\/sd/{print $5}' 8 8 8 8 8 8 8 8 8 8 8 \u8bfb\u53d6 ifconfig eth0 \u8f93\u51fa\u7ed3\u679c\u7684\u7b2c\u4e8c\u884c NR==2 \u7684\u7b2c\u4e8c\u5217 $2 \u3002 $ ifconfig eth0 | awk 'NR==2{print $2}' 192 .168.10.210","title":"5.10.7.8.\u6a21\u5f0f\u5339\u914d\u7b26"},{"location":"linux/SRE/05-RegExpress/#5108","text":"","title":"5.10.8.\u53d8\u91cf"},{"location":"linux/SRE/05-RegExpress/#51081","text":"awk \u5e38\u7528\u7684\u53d8\u91cf\u6709 FS \u3001 OFS \u3001 NF \u548c NR \u3002 FS \u7528\u6765\u5b9a\u4e49\u8f93\u5165\u5b57\u6bb5\u5206\u9694\u7b26\uff0c\u9ed8\u8ba4\u4e3a\u7a7a\u767d\u5b57\u7b26\u3002\u4e0e -F \u9009\u9879\u529f\u80fd\u7c7b\u4f3c\uff0c\u540c\u65f6\u4f7f\u7528\u4f1a\u62a5\u9519\u3002 OFS \u7528\u6765\u5b9a\u4e49\u8f93\u51fa\u5b57\u6bb5\u5206\u9694\u7b26\uff0c\u9ed8\u8ba4\u4e3a\u7a7a\u767d\u5b57\u7b26\u3002 RS \u6307\u5b9a\u8f93\u5165\u65f6\u7684\u6362\u884c\u7b26\u3002 ORS \u6307\u5b9a\u7b26\u53f7\u5728\u8f93\u51fa\u65f6\u66ff\u6362\u6362\u884c\u7b26\u3002 NF \u8868\u793a\u7528\u5206\u9694\u7b26\u5206\u9694\u540e\u4e00\u5171\u6709\u591a\u5c11\u5217\u3002 NR \u8868\u793a\u884c\u53f7\u3002 FNR \u8868\u793a\u4e2a\u6587\u4ef6\u5206\u522b\u8ba1\u6570\u5404\u81ea\u8bb0\u5f55\u7684\u7f16\u53f7\u3002 FILENAME \u8868\u793a\u5f53\u524d\u6587\u4ef6\u540d\u3002 ARGC \u8868\u793a\u547d\u4ee4\u884c\u53c2\u6570\u7684\u4e2a\u6570\u3002 ARVC \u4ee5\u6570\u7ec4\u5f62\u5f0f\u4fdd\u5b58\u547d\u4ee4\u884c\u6240\u7ed9\u5b9a\u7684\u5404\u53c2\u6570\uff0c\u6bcf\u4e2a\u53c2\u6570\uff1a ARGV[0] \uff0c......\u3002 FS \u7684\u7528\u6cd5\uff1a $ awk -v FS = ':' '{print $1, FS, $3}' /etc/passwd | head -n5 root : 0 messagebus : 499 systemd-network : 497 $ awk -F: '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 $ S = : ; awk -v FS = $S '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 systemd-timesync:496 nobody:65534 $ S = : ; awk -F $S '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 FS \u548c -F \u9009\u9879\u529f\u540c\u65f6\u4f7f\u7528\u4f1a\u51b2\u7a81\uff0c -F \u7684\u4f18\u5148\u7ea7\u66f4\u9ad8\u3002 $ awk -v FS = ':' -F ';' '{print $1FS$3}' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash ; messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false ; systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin ; $ awk -v FS = ';' -F ':' '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 OFS \u7684\u7528\u6cd5\uff1a \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u7b2c1\u30013\u30014\u5217\u7b2c\u5185\u5bb9\uff0c\u5e76\u4ee5 # \u4e3a\u5206\u9694\u7b26\u3002 $ awk -F ':' '{OFS=\"#\"} {print $1,$3,$4}' /etc/passwd | head -n5 root#0#0 messagebus#499#499 systemd-network#497#497 systemd-timesync#496#496 nobody#65534#65534 $ awk -v FS = ':' -v OFS = '#' '{print $1,$3,$4}' /etc/passwd | head -n5 root#0#0 messagebus#499#499 systemd-network#497#497 systemd-timesync#496#496 nobody#65534#65534 \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5f53\u7b2c\u4e09\u5217\u5927\u4e8e\u7b49\u4e8e5000\u65f6\uff0c\u6253\u5370\u7b2c1\u30012\u30013\u30014\u5217\u7b2c\u5185\u5bb9\uff0c\u5e76\u4ee5 # \u4e3a\u5206\u9694\u7b26\u3002 $ awk -F ':' '{OFS=\"#\"} {if ($3>=5000) {print $1,$2,$3,$4}}' /etc/passwd nobody#x#65534#65534 RS \u7684\u7528\u6cd5\uff1a # \u4ee5\u7a7a\u683c\u4e3a\u6362\u884c\u6807\u5fd7 $ awk -v RS = ' ' '{print $0}' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for # \u4ee5\u5192\u53f7\u4e3a\u6362\u884c\u6807\u5fd7 $ awk -v RS = ':' '{print $0}' /etc/passwd | head -n3 root x 0 ORS \u7684\u7528\u6cd5\uff1a # \u4ee5\u5192\u53f7\u4e3a\u6362\u884c\u6807\u5fd7\uff0c\u66ff\u6362\u6210### $ awk -v RS = ':' -v ORS = '###' '{print $0}' /etc/passwd | head -n3 root###x###0###0###root###/root###/bin/bash messagebus###x###499###499###User for D-Bus###/run/dbus###/usr/bin/false systemd-network###x###497###497###systemd Network Management###/###/usr/sbin/nologin NF \u7684\u7528\u6cd5\uff1a \u5176\u4e2d NF \u662f\u591a\u5c11\u5217\uff0c $NF \u662f\u6700\u540e\u4e00\u5217\u7684\u503c\u3002 \u4e0b\u4f8b\u4e2d\u4ee5 : \u4e3a\u5206\u9694\u7b26\u4e00\u5171\u5206\u4e3a7\u5217\uff0c\u6700\u540e\u4e00\u5217\u7684\u503c\u662f $NF \u3002 $ awk -F ':' '{print $NF}' /etc/passwd | head -n2 /bin/bash /usr/bin/false $ awk -F ':' '{print NF}' /etc/passwd | head -n2 7 7 $ ss -nt | grep \"^ESTAB\" | awk -F \"[[:space:]]+|:\" '{print $(NF-2)}' 192 .168.10.103 $ ss -nt | awk -F \"[[:space:]]+|:\" '/^ESTAB/{print $(NF-2)}' 192 .168.10.103 NR \u7684\u7528\u6cd5\uff1a \u901a\u8fc7 NR \u8f93\u51fa\u884c\u53f7\u3002\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u524d\u4e09\u884c\u7684\u884c\u53f7\u3002 $ awk -F ':' '{print NR}' /etc/passwd | head -n3 1 2 3 \u53d6\u5947\u3001\u5076\u6570\u884c\u3002 $ seq 10 | awk 'NR%2==0' 2 4 6 8 10 $ seq 10 | awk 'NR%2==1' 1 3 5 7 9 \u901a\u8fc7 NR \u8bbe\u5b9a\u884c\u53f7\u6761\u4ef6\u3002\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u7b2c40\u884c\u4ee5\u540e\u7684\u884c\u5185\u5bb9\u3002 $ awk 'NR>45' /etc/passwd admin3:x:1020:100::/home/admin3:/bin/bash smith:x:2002:0:,,,:/home/admin2:/bin/bash pm1:x:2003:1535::/home/pm1:/bin/bash tm1:x:2004:1535::/home/tm1:/bin/bash tm2:x:2005:1536::/home/tm2:/bin/bash $ awk -F ':' 'NR>45' /etc/passwd admin3:x:1020:100::/home/admin3:/bin/bash smith:x:2002:0:,,,:/home/admin2:/bin/bash pm1:x:2003:1535::/home/pm1:/bin/bash tm1:x:2004:1535::/home/tm1:/bin/bash tm2:x:2005:1536::/home/tm2:/bin/bash $ awk -F ':' 'NR>45 {print NR,$1,$3}' /etc/passwd 46 admin3 1020 47 smith 2002 48 pm1 2003 49 tm1 2004 50 tm2 2005 $ awk -F ':' 'BEGIN{print NR}' /etc/passwd 0 $ awk -F ':' 'END{print NR}' /etc/passwd 50 $ ifconfig eth0 | awk '/netmask/{print $0}' inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig eth0 | awk '/netmask/{print $1}' inet $ ifconfig eth0 | awk '/netmask/{print $2}' 192 .168.10.210 $ ifconfig eth0 | awk 'NR==2{print $0}' inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig eth0 | awk 'NR==2{print $1}' inet $ ifconfig eth0 | awk 'NR==2{print $2}' 192 .168.10.210 \u901a\u8fc7 NR \u4e0e\u5217\u5339\u914d\u4e00\u8d77\u4f7f\u7528\u3002 $ awk -F ':' 'NR<5 && $1 ~/roo/' /etc/passwd root:x:0:0:root:/root:/bin/bash FNR \u7684\u7528\u6cd5\uff1a $ awk '{print FNR}' /etc/fstab /etc/networks 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 $ awk '{print NR, $0}' /etc/fstab /etc/networks 1 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af / btrfs defaults 0 0 2 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /var btrfs subvol = /@/var 0 0 3 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /usr/local btrfs subvol = /@/usr/local 0 0 4 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /tmp btrfs subvol = /@/tmp 0 0 5 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /srv btrfs subvol = /@/srv 0 0 6 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /root btrfs subvol = /@/root 0 0 7 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /opt btrfs subvol = /@/opt 0 0 8 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /home btrfs subvol = /@/home 0 0 9 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/x86_64-efi btrfs subvol = /@/boot/grub2/x86_64-efi 0 0 10 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/i386-pc btrfs subvol = /@/boot/grub2/i386-pc 0 0 11 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /.snapshots btrfs subvol = /@/.snapshots 0 0 12 UUID = 47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 swap swap defaults 0 0 13 # 14 # networks This file describes a number of netname-to-address 15 # mappings for the TCP/IP subsystem. It is mostly 16 # used at boot time, when no name servers are running. 17 # 18 19 loopback 127 .0.0.0 20 link-local 169 .254.0.0 21 22 # End. $ awk '{print FNR, $0}' /etc/fstab /etc/networks 1 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af / btrfs defaults 0 0 2 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /var btrfs subvol = /@/var 0 0 3 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /usr/local btrfs subvol = /@/usr/local 0 0 4 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /tmp btrfs subvol = /@/tmp 0 0 5 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /srv btrfs subvol = /@/srv 0 0 6 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /root btrfs subvol = /@/root 0 0 7 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /opt btrfs subvol = /@/opt 0 0 8 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /home btrfs subvol = /@/home 0 0 9 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/x86_64-efi btrfs subvol = /@/boot/grub2/x86_64-efi 0 0 10 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/i386-pc btrfs subvol = /@/boot/grub2/i386-pc 0 0 11 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /.snapshots btrfs subvol = /@/.snapshots 0 0 12 UUID = 47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 swap swap defaults 0 0 1 # 2 # networks This file describes a number of netname-to-address 3 # mappings for the TCP/IP subsystem. It is mostly 4 # used at boot time, when no name servers are running. 5 # 6 7 loopback 127 .0.0.0 8 link-local 169 .254.0.0 9 10 # End. FILENAME \u7684\u7528\u6cd5\uff1a $ awk '{print FILENAME}' /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab $ awk '{print FNR, FILENAME, $0}' /etc/fstab /etc/networks 1 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af / btrfs defaults 0 0 2 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /var btrfs subvol = /@/var 0 0 3 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /usr/local btrfs subvol = /@/usr/local 0 0 4 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /tmp btrfs subvol = /@/tmp 0 0 5 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /srv btrfs subvol = /@/srv 0 0 6 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /root btrfs subvol = /@/root 0 0 7 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /opt btrfs subvol = /@/opt 0 0 8 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /home btrfs subvol = /@/home 0 0 9 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/x86_64-efi btrfs subvol = /@/boot/grub2/x86_64-efi 0 0 10 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/i386-pc btrfs subvol = /@/boot/grub2/i386-pc 0 0 11 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /.snapshots btrfs subvol = /@/.snapshots 0 0 12 /etc/fstab UUID = 47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 swap swap defaults 0 0 1 /etc/networks # 2 /etc/networks # networks This file describes a number of netname-to-address 3 /etc/networks # mappings for the TCP/IP subsystem. It is mostly 4 /etc/networks # used at boot time, when no name servers are running. 5 /etc/networks # 6 /etc/networks 7 /etc/networks loopback 127 .0.0.0 8 /etc/networks link-local 169 .254.0.0 9 /etc/networks 10 /etc/networks # End. ARGC \u7684\u7528\u6cd5\uff1a \u6bcf\u4e2a\u53d8\u91cf\u7684\u540d\u5b57\u901a\u8fc7 ARGV \u83b7\u53d6\u3002 $ awk '{print ARGC}' /etc/fstab /etc/issue 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 $ awk 'BEGIN{print ARGC}' /etc/fstab /etc/issue 3 ARGV \u7684\u7528\u6cd5\uff1a $ awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/issue awk $ awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/issue /etc/fstab $ awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/issue /etc/issue $ awk 'BEGIN{print ARGV[3]}' /etc/fstab /etc/issue","title":"5.10.8.1.\u5185\u7f6e\u53d8\u91cf"},{"location":"linux/SRE/05-RegExpress/#51082","text":"\u81ea\u5b9a\u4e49\u53d8\u91cf\u662f\u533a\u5206\u5b57\u7b26\u5927\u5c0f\u5199\u7684\uff0c\u4f7f\u7528\u4e0b\u9762\u7684\u65b9\u5f0f\u8fdb\u884c\u8d4b\u503c\u3002 -v var=value \u5728program\u4e2d\u76f4\u63a5\u5b9a\u4e49 \u4e3e\u4f8b\uff1a $ awk -v t1 = t2 = \"hello awk\" 'BEGIN{print t1, t2}' t2 = hello awk $ awk -v t1 = t2 = \"hello awk\" 'BEGIN{t1=t2=\"gawk\"; print t1, t2}' gawk gawk $ awk 'BEGIN{t1=t2=\"hello awk\"; print t1, t2}' hello awk hello awk $ awk -v t1 = \"hello awk\" '{print t1}' /etc/issue hello awk hello awk hello awk hello awk hello awk $ awk -v t1 = \"hello awk\" 'BEGIN{print t1}' /etc/issue hello awk $ awk -v t1 = \"hello awk\" 'BEGIN{print t1}' hello awk $ awk -F: '{sex=\"male\"; print $1, sex, age; age=28}' /etc/passwd | head -n3 root male messagebus male 28 systemd-network male 28 $ cat < awkscript {print script,$1,$2} EOF $ awk -F: -f awkscript script = \"awk\" /etc/passwd | head -n2 awk root x awk messagebus x \u52a8\u4f5c printf \u3002 \u52a8\u4f5cprintf\u53ef\u4ee5\u5b9e\u73b0\u683c\u5f0f\u5316\u8f93\u51fa\u3002 \u683c\u5f0f\uff1a printf \"FORMAT\", item1, item2, ...... \u8bf4\u660e\uff1a \u5fc5\u987b\u6307\u5b9aFORMAT \u4e0d\u4f1a\u81ea\u52a8\u6362\u884c\uff0c\u9700\u8981\u663e\u5f0f\u7ed9\u51fa\u6362\u884c\u63a7\u5236\u7b26 \\n \u3002 FORMAT\u4e2d\u9700\u8981\u5206\u522b\u4e3a\u540e\u9762\u6bcf\u4e2aitem\u6307\u5b9a\u683c\u5f0f\u7b26\u3002 \u683c\u5f0f\u7b26\uff1a\u4e0eitem\u662f\u4e00\u4e00\u5bf9\u5e94\u7684 %s \uff1a\u663e\u793a\u5b57\u7b26\u4e32 %d , %i \uff1a\u663e\u793a\u5341\u8fdb\u5236\u6574\u6570 %f \uff1a\u663e\u793a\u4e3a\u6d6e\u70b9\u6570 %e , %E \uff1a\u663e\u793a\u79d1\u5b66\u8ba1\u6570\u6cd5\u6570\u503c %c \uff1a\u663e\u793a\u5b57\u7b26\u7684ASCII\u7801 %g , %G \uff1a\u4ee5\u79d1\u5b66\u8ba1\u6570\u6cd5\u6216\u6d6e\u70b9\u5f62\u5f0f\u663e\u793a\u6570\u503c %u \uff1a\u65e0\u7b26\u53f7\u6574\u6570 %% \uff1a\u663e\u793a % \u81ea\u8eab \u4fee\u9970\u7b26\uff1a #[.#] \uff1a\u7b2c\u4e00\u4e2a\u6570\u5b57\u63a7\u5236\u663e\u793a\u7684\u5bbd\u5ea6\uff0c\u7b2c\u4e8c\u4e2a#\u8868\u793a\u5c0f\u6570\u70b9\u540e\u7cbe\u5ea6\uff0c\u5982 %3.1f - \uff1a\u5de6\u5bf9\u9f50\uff08\u9ed8\u8ba4\u53f3\u5bf9\u9f50\uff09\uff0c\u5982 %-15s + \uff1a\u663e\u793a\u6570\u503c\u7684\u6b63\u8d1f\u7b26\u53f7\uff0c\u5982 %+d \u793a\u4f8b\uff1a $ awk -F: '{printf \"%s\", $1}' /etc/passwd | head -n3 rootmessagebussystemd-networksystemd-timesyncnobodymailchronypostfixmanlpgamesftpdaemonrpcnscdpolkitdattftpftpsecurebinstatdsshdvagrantpesignsvntester1tester2tester3tester4tester5user0user1user2user3user4user5user6user7user8user9gentoonginxvarnishmysqlwebuseradmin3smithpm1tm1tm2 $ awk -F: '{printf \"%s\\n\", $1}' /etc/passwd | head -n3 root messagebus systemd-network $ awk -F: '{printf \"%20s\\n\", $1}' /etc/passwd | head -n3 root messagebus systemd-network $ awk -F: '{printf \"%-20s\\n\", $1}' /etc/passwd | head -n3 root messagebus systemd-network $ awk -F: '{printf \"%-20s %10d\\n\", $1, $3}' /etc/passwd | head -n3 root 0 messagebus 499 systemd-network 497 $ awk -F: '{printf \"Username: %s\\n\", $1}' /etc/passwd | head -n3 Username: root Username: messagebus Username: systemd-network $ awk -F: '{printf \"Username: %s UID:%d\\n\", $1, $3}' /etc/passwd | head -n3 Username: root UID:0 Username: messagebus UID:499 Username: systemd-network UID:497 $ awk -F: '{printf \"Username: %25s UID:%d\\n\", $1, $3}' /etc/passwd | head -n3 Username: root UID:0 Username: messagebus UID:499 Username: systemd-network UID:497 $ awk -F: '{printf \"Username: %-25s UID:%d\\n\", $1, $3}' /etc/passwd | head -n3 Username: root UID:0 Username: messagebus UID:499 Username: systemd-network UID:497","title":"5.10.8.2.\u81ea\u5b9a\u4e49\u53d8\u91cf"},{"location":"linux/SRE/05-RegExpress/#5109beginend","text":"\u793a\u4f8b\uff1a awk -F \":\" 'BEGIN{printf \"--------------------------------\\n%-20s|%10s|\\n--------------------------------\\n\", \"Username\", \"UID\"}{printf \"%-20s|%-10d|\\n--------------------------------\\n\", $1, $3}END{print \"end\"}' /etc/passwd -------------------------------- Username | UID | -------------------------------- root | 0 | -------------------------------- daemon | 1 | -------------------------------- bin | 2 | ------------------------------- ... ... -------------------------------- mfe | 997 | -------------------------------- end","title":"5.10.9.BEGIN/END"},{"location":"linux/SRE/05-RegExpress/#51010","text":"{statements;...} \u7ec4\u5408\u8bed\u53e5 if(condition){statements;...} if(condition){statements;...} else(statements;...) switch(expression){case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2;......;default: statementn} while(condition){statements;...} do(statements;...) while{condition} for(expr1;expr2;expr3) {statements;...} break continue exit if-else\u793a\u4f8b\uff1a $ cat < score.txt Name Score Tom 100 Jack 91 Bill 81 Jim 51 EOF $ awk 'NR!=1{score=$2;if($2>=80){print $1, \"Good\"}else if($2>=60){print $1, \"Pass\"}else{print $1, \"failed\"}}' score.txt Tom Good Jack Good Bill Good Jim failed switch\u793a\u4f8b\uff1a $ awk 'NR!=1{switch($2){case 100:print $1,\"good\"; case 60:print $1,\"Pass\"; default:print $1,\"others\"}}' score.txt Tom good Tom Pass Tom others Jack others Bill others Jim others while\u793a\u4f8b\uff1a $ awk 'BEGIN{i=0;sum=0;while(i<=100){sum+=i;i++};print sum}' 5050 do-while\u793a\u4f8b\uff1a $ awk 'BEGIN{i=0;sum=0;do{sum+=i;i++}while(i<101);print sum}' 5050 for\u793a\u4f8b\uff1a $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){sum+=i};print sum}' 5050 \u547d\u4ee4\u6548\u7387\u6bd4\u8f83\uff1a $ time ( awk 'BEGIN{i=0;sum=0;while(i<=100000){sum+=i;i++};print sum}' ) 5000050000 real 0m0.028s user 0m0.027s sys 0m0.001s $ time ( seq -s+ 1000000 | bc ) 500000500000 real 0m0.329s user 0m0.240s sys 0m0.094s $ time ( awk 'BEGIN{i=0;sum=0;for(i=1;i<=1000000;i++){sum+=i};print sum}' ) 500000500000 real 0m0.050s user 0m0.046s sys 0m0.004s contine\u793a\u4f8b\uff1a\u4e2d\u65ad\u5f53\u524d\u5faa\u73af\uff0c\u8fdb\u5165\u4e0b\u4e00\u6b21\u5faa\u73af\u3002 $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){if(i==50)continue;sum+=i};print sum}' 5000 contine\u793a\u4f8b\uff1a\u4e2d\u65ad\u6574\u4e2a\u5faa\u73af\u3002 $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){if(i==50)break;sum+=i};print sum}' 1225 next\u793a\u4f8b\uff1a\u63d0\u524d\u7ed3\u675f\u5bf9\u672c\u884c\u5904\u7406\uff0c\u76f4\u63a5\u8fdb\u5165\u4e0b\u4e00\u884c\u5904\u7406\uff08\u6ce8\uff0cawk\u81ea\u5faa\u73af\uff0c\u5e76\u975e\u524d\u9762\u7684for\u6216while\u5faa\u73af\uff09 $ awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd # \u5947\u6570\u884c\u6253\u5370 root 0 systemd-timesync 496 nobody 65534 chrony 494 games 492 daemon 2 rpc 490 polkitd 488 ftpsecure 486 sshd 484 vagrant 1000 svn 482 tester1 600 tester4 1002 user0 1004 user2 1006 user4 1008 user6 1010 user8 1012 gentoo 1014 varnish 1016 webuser 666 admin3 1020 smith 2002 tm1 2004 $ awk -F: '{if($3%2==0)next;print $1,$3}' /etc/passwd # \u5076\u6570\u884c\u6253\u5370 messagebus 499 systemd-network 497 mail 495 postfix 51 man 13 lp 493 ftp 491 nscd 489 at 25 tftp 487 bin 1 statd 485 pesign 483 tester2 601 tester3 1001 tester5 1003 user1 1005 user3 1007 user5 1009 user7 1011 user9 1013 nginx 1015 mysql 1017 pm1 2003 tm2 2005","title":"5.10.10.\u5e38\u7528\u63a7\u5236\u8bed\u53e5"},{"location":"linux/SRE/05-RegExpress/#51011","text":"\u5173\u8054\u6570\u7ec4\u662f\u4e00\u79cd\u6570\u636e\u7ed3\u6784\uff0c\u4e5f\u79f0\u4e3a\u5b57\u5178\u6216\u6620\u5c04\u3002\u4e0e\u4f20\u7edf\u7684\u6570\u7ec4\u4e0d\u540c\uff0c\u5173\u8054\u6570\u7ec4\u7684\u7d22\u5f15\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\u7684\u6570\u636e\uff0c\u4f8b\u5982\u5b57\u7b26\u4e32\u6216\u5bf9\u8c61\uff0c\u800c\u4e0d\u4ec5\u4ec5\u662f\u6574\u6570\u3002 \u63d0\u793a\uff1a \u5728\u8ba1\u7b97\u673a\u7f16\u7a0b\u4e2d\uff0c\u9664\u4e86\u5173\u8054\u6570\u7ec4\uff0c\u8fd8\u6709\u5176\u4ed6\u51e0\u79cd\u5e38\u89c1\u7684\u6570\u7ec4\u7c7b\u578b\uff0c\u5305\u62ec\uff1a \u7ebf\u6027\u6570\u7ec4\uff08\u6216\u79f0\u4e3a\u7d22\u5f15\u6570\u7ec4\uff09\uff1a\u8fd9\u662f\u6700\u5e38\u89c1\u7684\u6570\u7ec4\u7c7b\u578b\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e00\u4e2a\u6570\u5b57\u7d22\u5f15\uff0c\u53ef\u4ee5\u7528\u6765\u5feb\u901f\u8bbf\u95ee\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u3002\u4f8b\u5982\uff0c\u5728C\u8bed\u8a00\u4e2d\uff0c\u6570\u7ec4\u7684\u6bcf\u4e2a\u5143\u7d20\u90fd\u53ef\u4ee5\u901a\u8fc7\u6570\u7ec4\u4e0b\u6807\u6765\u8bbf\u95ee\u3002 \u591a\u7ef4\u6570\u7ec4\uff1a\u591a\u7ef4\u6570\u7ec4\u662f\u4e00\u79cd\u6570\u7ec4\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u4e5f\u662f\u4e00\u4e2a\u6570\u7ec4\u3002\u5728\u4e8c\u7ef4\u6570\u7ec4\u4e2d\uff0c\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e24\u4e2a\u7d22\u5f15\uff08\u4f8b\u5982\uff0c\u884c\u548c\u5217\uff09\uff0c\u53ef\u4ee5\u7528\u4e8e\u8bbf\u95ee\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u3002\u5728\u9ad8\u7ef4\u6570\u7ec4\u4e2d\uff0c\u6bcf\u4e2a\u5143\u7d20\u90fd\u5177\u6709\u66f4\u591a\u7684\u7d22\u5f15\u3002 \u52a8\u6001\u6570\u7ec4\uff1a\u52a8\u6001\u6570\u7ec4\u662f\u4e00\u79cd\u53ef\u4ee5\u52a8\u6001\u8c03\u6574\u5927\u5c0f\u7684\u6570\u7ec4\u3002\u5728\u8bb8\u591a\u7f16\u7a0b\u8bed\u8a00\u4e2d\uff0c\u52a8\u6001\u6570\u7ec4\u53ef\u4ee5\u52a8\u6001\u5206\u914d\u5185\u5b58\uff0c\u4ee5\u4fbf\u5728\u7a0b\u5e8f\u8fd0\u884c\u65f6\u6839\u636e\u9700\u8981\u8c03\u6574\u6570\u7ec4\u7684\u5927\u5c0f\u3002 \u5411\u91cf\uff1a\u5411\u91cf\u662f\u4e00\u79cd\u6570\u7ec4\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u90fd\u662f\u76f8\u540c\u7684\u6570\u636e\u7c7b\u578b\u3002\u5411\u91cf\u901a\u5e38\u7528\u4e8e\u6267\u884c\u6570\u5b66\u8fd0\u7b97\u6216\u5904\u7406\u5927\u91cf\u6570\u5b57\u6570\u636e\u3002 \u5728 awk \u4e2d\u4f7f\u7528\u6570\u7ec4\u65f6\uff0c\u901a\u5e38\u4f1a\u5c06\u67d0\u4e9b\u503c\u4e0e\u4e00\u4e2a\u5b57\u7b26\u4e32\u76f8\u5173\u8054\uff0c\u4ee5\u4fbf\u5728\u9700\u8981\u65f6\u53ef\u4ee5\u901a\u8fc7\u8be5\u5b57\u7b26\u4e32\u5feb\u901f\u5730\u68c0\u7d22\u8be5\u503c\u3002 awk \u7684\u6570\u7ec4\u662f\u4e00\u4e2a\u5173\u8054\u6570\u7ec4\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u90fd\u7531\u4e00\u4e2a\u552f\u4e00\u7684\u952e\u503c\u548c\u4e00\u4e2a\u5bf9\u5e94\u7684\u503c\u7ec4\u6210\u3002\u952e\u503c\uff08\u6216\u79f0\u4e3a\u7d22\u5f15\uff09\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\u7684\u5b57\u7b26\u4e32\u3002 \u6570\u7ec4\u53ef\u4ee5\u901a\u8fc7\u4ee5\u4e0b\u8bed\u6cd5\u8fdb\u884c\u58f0\u660e\uff1a array_name [ index ] = value \u5176\u4e2d\uff0c array_name \u662f\u6570\u7ec4\u7684\u540d\u79f0\uff0c index \u662f\u5143\u7d20\u7684\u7d22\u5f15\u503c\uff0c value \u662f\u5143\u7d20\u7684\u503c\u3002 \u4f8b\u5982\uff0c\u4ee5\u4e0b\u662f\u4e00\u4e2a\u5305\u542b\u4e09\u4e2a\u5143\u7d20\u7684\u5173\u8054\u6570\u7ec4\u7684\u793a\u4f8b\uff1a array [ \"apple\" ] = 1 array [ \"banana\" ] = 2 array [ \"orange\" ] = 3 \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c array \u662f\u4e00\u4e2a\u5173\u8054\u6570\u7ec4\uff0c\u5176\u7d22\u5f15\u4e3a\u5b57\u7b26\u4e32\u7c7b\u578b\uff0c\u800c\u503c\u4e3a\u6574\u6570\u7c7b\u578b\u3002\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u7684\u65b9\u5f0f\u8bbf\u95ee\u8be5\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\uff1a value = array [ \"apple\" ] \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c value \u7684\u503c\u5c06\u4e3a 1 \uff0c\u56e0\u4e3a array[\"apple\"] \u7684\u503c\u4e3a 1 \u3002 \u4ee5\u4e0b\u662f\u7528 awk \u547d\u4ee4\u6765\u521b\u5efa\u4e0a\u9762\u90a3\u4e2a\u5305\u542b\u4e09\u4e2a\u5143\u7d20\u7684\u5173\u8054\u6570\u7ec4\uff0c\u904d\u5386\u5e76\u8f93\u51fa\u6570\u7ec4\u503c\uff1a awk 'BEGIN { array[\"apple\"]=1; array[\"banana\"]=2; array[\"orange\"]=3; for(i in array){print array[i]}}' 3 1 2 \u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u4e92\u6362\u4e86\u6570\u7ec4\u7684\u952e\u548c\u503c\u3002 $ awk 'BEGIN {arr[1]=\"apple\";arr[2]=\"banana\";arr[3]=\"orange\";for(i in arr){print arr[i]}}' apple banana orange \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c i \u662f\u6570\u7ec4 arr \u7684\u7d22\u5f15\u503c\uff0c arr[i] \u662f\u6570\u7ec4\u4e2d\u5bf9\u5e94\u7684\u5143\u7d20\u503c\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\u53ef\u4ee5\u5faa\u73af\u904d\u5386\u6574\u4e2a\u6570\u7ec4\uff0c\u5e76\u8f93\u51fa\u5176\u4e2d\u7684\u5143\u7d20\u3002 \u9664\u4e86\u4f7f\u7528\u5faa\u73af\u904d\u5386\u6570\u7ec4\u4e4b\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f7f\u7528 length \u51fd\u6570\u83b7\u53d6\u6570\u7ec4\u4e2d\u5143\u7d20\u7684\u6570\u91cf\u3002\u4f8b\u5982\uff1a $ awk 'BEGIN { arr[1]=\"apple\"; arr[2]=\"banana\"; arr[3]=\"orange\"; print length(arr) }' 3 \u4e0a\u9762\u7684\u793a\u4f8b\u5c06\u8f93\u51fa\u6570\u5b573\uff0c\u8868\u793a\u6570\u7ec4 arr \u4e2d\u5305\u542b\u4e09\u4e2a\u5143\u7d20\u3002 \u4e3e\u4f8b\uff1a\u53bb\u91cd\u590d\u8bb0\u5f55\u3002 line \u662f\u6570\u7ec4\u540d\uff0c $0 \u662f awk \u8bfb\u53d6\u7684\u5f53\u524d\u884c\u7684\u5185\u5bb9\u3002 line[$0] \u7b49\u4ef7\u4e8e line[\"a\"] \uff0c line[\"b\"] \uff0c......\u3002 \u6211\u4eec\u770b\u6267\u884c\u8fc7\u7a0b\uff1a awk\u8bfb\u5165\u7b2c1\u884c\uff1b \u6267\u884c line[\"a\"] \uff0c\u503c\u4e3a\u7a7a\uff1b \u6c42\u53cd\uff0c\u5219\u7b2c\u4e00\u884c\u7684\u503c\u53d8\u4e3a true \uff0c\u5373 !line[\"a\"]=true \uff1b \u5f53 !line[\"a\"] \u4e3a true \uff0c\u5219\u6253\u5370\u5f53\u524d\u884c\uff0c\u5373\u8f93\u51fa a \u5230\u5c4f\u5e55\uff1b \u6267\u884c line[\"a\"]++ \uff0c\u6ce8\u610f\u7b2c2\u6b65\u4e2d line[\"a\"] \u7684\u503c\u662f\u7a7a\uff0c\u6267\u884c ++ \u540e\u503c\u53d8\u4e3a 1 \u3002 \u540c\u7406\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u7b2c2\uff0c3\uff0c4\u884c\u90fd\u8f93\u51fa\u4e86\u3002 \u5f53\u8bfb\u5165\u7b2c5\u884c\u65f6\uff08\u7b2c\u4e8c\u4e2a a \uff09\uff0c\u6267\u884c line[\"a\"] \uff0c\u503c\u4e3a 1 \uff1b !line[\"a\"]=0 \uff0c\u5373false\uff1b\u5219\u4e0d\u6253\u5370\u5f53\u524d\u884c\uff0c\u5373\u4e0d\u8f93\u51fa a \u5230\u5c4f\u5e55\uff1b\u6267\u884c ++ \u540e\u503c\u53d8\u4e3a 2 \u5f53\u8bfb\u5165\u7b2c8\u884c\u65f6\uff08\u7b2c\u4e09\u4e2a a \uff09\uff0c\u6267\u884c line[\"a\"] \uff0c\u503c\u4e3a 2 \uff1b !line[\"a\"]=0 \uff0c\u5373false\uff1b\u5219\u4e0d\u6253\u5370\u5f53\u524d\u884c\uff0c\u5373\u4e0d\u8f93\u51fa a \u5230\u5c4f\u5e55\uff1b\u6267\u884c ++ \u540e\u503c\u53d8\u4e3a 3 \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8bfb\u5165\u7b2c\u4e8c\u4e2a b \uff0c c \uff0c d \uff0c e \uff0c\u90fd\u4e0d\u4f1a\u518d\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4ece\u800c\u5b9e\u73b0\u53bb\u91cd\u8f93\u51fa\u5230\u529f\u80fd\u3002 $ cat > test << EOF a b c d a c d a b b e EOF $ awk '!line[$0]++' test a b c d e \u4e3e\u4f8b\uff1a\u5224\u65ad\u6570\u7ec4\u7d22\u5f15\u662f\u5426\u5b58\u5728\u3002 \u65b9\u6cd5\uff1a in array \uff0c 0 \u8868\u793a\u4e0d\u5b58\u5728\uff0c 1 \u8868\u793a\u5b58\u5728\u3002 $ awk 'BEGIN{array[\"i\"]=\"x\";array[\"j\"]=\"j\";print \"i\" in array, \"y\" in array}' 1 0 $ awk 'BEGIN{array[\"i\"]=\"x\";array[\"j\"]=\"j\";if(\"i\" in array){print \"exits!\"}else{print \"not exists!\"}}' exits! $ awk 'BEGIN{array[\"i\"]=\"x\";array[\"j\"]=\"j\";if(\"abc\" in array){print \"exits!\"}else{print \"not exists!\"}}' not exists! \u4e3e\u4f8b\uff1a\u904d\u5386\u6570\u7ec4\u4e2d\u6bcf\u4e2a\u5143\u7d20\u3002 \u65b9\u6cd5\uff1a for(your_var in array){your_for_body} \uff0c\u6ce8\u610f\uff0cyour_var\u4f1a\u904d\u5386\u6bcf\u4e2a\u7d22\u5f15\u3002 $ awk 'BEGIN{weekday[\"mon\"]=\"Monday\";weekday[\"tue\"]=\"Tuesday\";for(i in weekday){print i,weekday[i]}}' tue Tuesday mon Monday $ awk 'BEGIN{weekday[\"mon\"]=\"Monday\";weekday[\"tue\"]=\"Tuesday\";for(i in weekday){print i\": \"weekday[i]}}' tue: Tuesday mon: Monday \u6ce8\u610f\u4e0b\u9762\u7684\u6362\u884c\u5199\u6cd5\uff0c\u4e0d\u9700\u8981\u53cd\u659c\u6760 \\ \u3002 $ awk 'BEGIN{ arr[\"x\"]=\"welcome\" arr[\"y\"]=\"to\" arr[\"z\"]=\"Shanghai\" for (i in arr) { print i, arr[i] } }' x welcome y to z Shanghai \u793a\u4f8b\uff1a\u683c\u5f0f\u5316\u8f93\u51fa\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002 $ awk -F: '{user[$1]=$3}END{for (i in user){print \"Username: \" i, \"UID: \" user[i]}}' /etc/passwd Username: sshd UID: 476 Username: rpc UID: 482 Username: tftp UID: 488 Username: usbmux UID: 480 Username: srvGeoClue UID: 487 ...... \u793a\u4f8b\uff1a\u663e\u793a\u4e3b\u673a\u8fde\u63a5\u72b6\u6001\u51fa\u73b0\u7684\u6b21\u6570\u3002 # \u4f20\u7edf\u65b9\u6cd5 $ ss -ant | awk 'NR>=2{print $1}' | sort | uniq -c $ ss -ant | awk 'NR!=1{print $1}' | sort | uniq -c 1 ESTAB 6 LISTEN # \u4f7f\u7528awk\u6570\u7ec4 $ ss -ant | awk 'NR>=2{state[$1]++}END{for(i in state){print state[i], i}}' $ ss -ant | awk 'NR!=1{state[$1]++}END{for(i in state){print state[i], i}}' 6 LISTEN 1 ESTAB","title":"5.10.11.\u6570\u7ec4"},{"location":"linux/SRE/05-RegExpress/#51012awk","text":"\u53c2\u8003\uff1a awk \u51fd\u6570\u5b98\u7f51","title":"5.10.12.awk\u51fd\u6570"},{"location":"linux/SRE/05-RegExpress/#510121","text":"\u5728 awk \u4e2d\uff0c\u51fd\u6570\u662f\u4e00\u79cd\u7528\u4e8e\u6267\u884c\u7279\u5b9a\u4efb\u52a1\u6216\u8ba1\u7b97\u7279\u5b9a\u503c\u7684\u53ef\u91cd\u7528\u4ee3\u7801\u5757\u3002 awk \u63d0\u4f9b\u4e86\u8bb8\u591a\u5185\u7f6e\u51fd\u6570\uff0c\u53ef\u4ee5\u7528\u4e8e\u5904\u7406\u6587\u672c\u6570\u636e\u3001\u6267\u884c\u6570\u5b66\u8fd0\u7b97\u3001\u64cd\u4f5c\u5b57\u7b26\u4e32\u7b49\u3002 \u4ee5\u4e0b\u662f\u4e00\u4e9b\u5e38\u7528\u7684awk\u51fd\u6570\u793a\u4f8b\uff1a length(string) \uff1a\u8fd4\u56de\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u3002 $ awk 'BEGIN { str = \"Hello World\"; len = length(str); print len }' 11 $ cut -d: -f1 /etc/passwd | awk '{print length($1)}' | head -3 4 10 15 substr(string, start, length) \uff1a\u4ece\u6307\u5b9a\u4f4d\u7f6e\u5f00\u59cb\u63d0\u53d6\u5b57\u7b26\u4e32\u7684\u5b50\u4e32\u3002 $ awk 'BEGIN { str = \"Hello World\"; substring = substr(str, 7, 5); print substring }' World sub(regexp, replacement [, target]) \uff1a\u4ece\u5b57\u7b26\u4e32target\u4e2d\u641c\u7d22\u5339\u914dregexp\u7684\u5185\u5bb9\uff0c\u5e76\u628a\u7b2c\u4e00\u4e2a\u5339\u914d\u7684\u5185\u5bb9\u66ff\u6362\u4e3areplacement\u3002\u61d2\u60f0\u6a21\u5f0f\u3002 \u6ce8\u610f\uff1a sub() \u51fd\u6570\u5728\u539f\u59cb\u5b57\u7b26\u4e32\u4e0a\u8fdb\u884c\u66ff\u6362\u64cd\u4f5c\uff0c\u5e76\u8fd4\u56de\u66ff\u6362\u7684\u6b21\u6570\u3002 # \u5728\u539f\u59cb\u5b57\u7b26\u4e32\u4e2d\uff0c\u7b2c\u4e00\u4e2a\u5339\u914d\u5230\u7684\"at\"\u88ab\u66ff\u6362\u4e3a\"ith\"\uff0c\u56e0\u6b64\u8f93\u51fa\u7ed3\u679c\u4e2d\u7684\"at\"\u53d8\u4e3a\"ith\"\uff0c\u5176\u4ed6\u5730\u65b9\u7684\"at\"\u4fdd\u6301\u4e0d\u53d8 $ awk 'BEGIN { str = \"water, water, everywhere\"; sub(/at/, \"ith\", str); print str }' wither, water, everywhere # \u8fd4\u56de\u5339\u914d\u6b21\u6570 $ awk 'BEGIN { str = \"water, water, everywhere\"; str_new = sub(/at/, \"ith\", str); print str_new }' 1 $ echo \"2023:15:35 08:15:26\" | awk 'sub(/:/, \"-\", $0)' 2023 -15:35 08 :15:26 $ echo \"2023:15:35 08:15:26\" | awk 'sub(/:/, \"-\", $1)' 2023 -15:35 08 :15:26 $ echo \"2023:15:35 08:15:26\" | awk 'sub(/:/, \"-\", $2)' 2023 :15:35 08 -15:26 gsub(regexp, replacement [, target])\uff1a\u4ece\u5b57\u7b26\u4e32target\u4e2d\u641c\u7d22\u5339\u914dregexp\u7684\u5185\u5bb9\uff0c\u5e76\u628a\u5168\u90e8\u5339\u914d\u7684\u5185\u5bb9\u66ff\u6362\u4e3areplacement\u3002\u8d2a\u5a6a\u6a21\u5f0f\u3002 # \u5728\u539f\u59cb\u5b57\u7b26\u4e32\u4e2d\uff0c\u5c06\u6240\u6709\u5339\u914d\u5230\u7684\"at\"\u88ab\u66ff\u6362\u4e3a\"ith\" $ awk 'BEGIN { str = \"water, water, everywhere\"; gsub(/at/, \"ith\", str); print str }' wither, wither, everywhere # \u8fd4\u56de\u5339\u914d\u6b21\u6570 $ awk 'BEGIN { str = \"water, water, everywhere\"; str_new = gsub(/at/, \"ith\", str); print str_new }' 2 $ echo \"2023:15:35 08:15:26\" | awk 'gsub(/:/, \"-\", $0)' 2023 -15-35 08 -15-26 $ echo \"2023:15:35 08:15:26\" | awk 'gsub(/:/, \"-\", $1)' 2023 -15-35 08 :15:26 $ echo \"2023:15:35 08:15:26\" | awk 'gsub(/:/, \"-\", $2)' 2023 :15:35 08 -15-26 split(string, array, delimiter) \uff1a\u5c06\u5b57\u7b26\u4e32string\u6309\u6307\u5b9a\u5206\u9694\u7b26delimiter\u62c6\u5206\u6210\u6570\u7ec4array\u7684\u5143\u7d20\u3002 \u6ce8\u610f\uff1a\u7b2c\u4e00\u4e2a\u7d22\u5f15\u503c\u4e3a 1 \uff0c\u7b2c\u4e8c\u4e2a\u7d22\u5f15\u503c\u4e3a 2 . $ awk 'BEGIN { str = \"apple,banana,orange\"; split(str, fruits, \",\"); print fruits[2] }' banana $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[1]}' messagebus $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[2]}' x $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[3]}' 499 $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[7]}' /usr/bin/false index(string, search) \uff1a\u5728\u5b57\u7b26\u4e32\u4e2d\u67e5\u627e\u6307\u5b9a\u5b50\u4e32\u7684\u4f4d\u7f6e\u3002 $ awk 'BEGIN { str = \"Hello World\"; pos = index(str, \"World\"); print pos }' 7 sprintf(format, expression) \uff1a\u6839\u636e\u6307\u5b9a\u7684\u683c\u5f0f\u5c06\u8868\u8fbe\u5f0f\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\u3002 $ awk 'BEGIN { num = 3.14159; str = sprintf(\"%.2f\", num); print str }' 3 .14 rand() \uff1a\u8fd4\u56de\u4e00\u4e2a\u968f\u673a\u6570\uff0c\u503c\u5728 0 \u548c 1 \u4e4b\u95f4\u5747\u5300\u5206\u5e03\u3002\u8fd9\u4e2a\u503c\u53ef\u4ee5\u662f 0 \uff0c\u4f46\u4e0d\u4f1a\u662f 1 \u3002\u4ece\u4e0b\u9762\u7684\u4f8b\u5b50\u53ef\u4ee5\u770b\u51fa\uff0c\u8fd0\u884c\u7ed3\u679c\u90fd\u662f\u4e00\u6837\u7684\uff0c\u6240\u4ee5\u4ea7\u751f\u968f\u673a\u6570\u7684\u79cd\u5b50\u662f\u4e00\u6837\u7684\u3002 $ awk 'BEGIN{print rand()}' 0 .924046 $ awk 'BEGIN{print rand()}' 0 .924046 $ awk 'BEGIN{print rand()}' 0 .924046 srand() \uff1a\u914d\u5408 rand() \u51fd\u6570\uff0c\u751f\u6210\u968f\u673a\u6570\u79cd\u5b50\u3002 $ awk 'BEGIN{srand();print rand()}' 0 .112006 $ awk 'BEGIN{srand();print rand()}' 0 .663431 $ awk 'BEGIN{srand();print rand()}' 0 .541305 int() \uff1a\u8fd4\u56de\u6574\u6570\u3002 $ awk 'BEGIN{srand();print int(rand()*100)}' 84 $ awk 'BEGIN{srand();print int(rand()*100)}' 66 $ awk 'BEGIN{srand();print int(rand()*100)}' 8 system(command) \uff1a\u6267\u884ccommand\u547d\u4ee4\uff08\u53ef\u4ee5\u662f\u4efb\u4f55\u6709\u6548\u7684Shell\u547d\u4ee4\uff09\u5e76\u8fd4\u56de\u547d\u4ee4\u7684\u9000\u51fa\u72b6\u6001\u7801\u3002\u5141\u8bb8\u5728 awk \u811a\u672c\u4e2d\u6267\u884c\u5916\u90e8\u547d\u4ee4\uff0c\u5e76\u83b7\u53d6\u547d\u4ee4\u6267\u884c\u7684\u7ed3\u679c\u3002 # \u6267\u884cls -l\u547d\u4ee4\uff0c\u5e76\u5c06\u547d\u4ee4\u7684\u9000\u51fa\u72b6\u6001\u7801\u5b58\u50a8\u5728status\u53d8\u91cf\u4e2d\uff0c\u5e76\u6253\u5370status\u53d8\u91cf\u7684\u503c $ awk 'BEGIN { status = system(\"ls -l\"); print \"Exit status:\", status }' total 0 drwxr-xr-x 1 vagrant users 70 Jan 2 15 :54 Desktop drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Documents drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Downloads drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Music drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Pictures drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Public drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Templates drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Videos drwxr-xr-x 1 vagrant users 0 Mar 15 2022 bin Exit status: 0 $ awk 'BEGIN{score=100; system(\"echo your score is \" score)}' your score is 100 systime() \uff1a\u5f53\u524d\u65f6\u95f4\u52301970\u5e741\u67081\u65e5\u5230\u79d2\u6570 $ awk 'BEGIN{print systime()}' 1684158395 strftime(format, timestamp) \uff1a\u5c06\u65f6\u95f4\u6233timestamp\u8f6c\u6362\u4e3a\u6307\u5b9a\u683c\u5f0fformat\u7684\u65e5\u671f\u548c\u65f6\u95f4\u5b57\u7b26\u4e32\u3002timestamp\u901a\u5e38\u662f\u4e00\u4e2a\u4ee5\u79d2\u4e3a\u5355\u4f4d\u8868\u793a\u7684\u6574\u6570\u3002 \u5e38\u89c1\u7684\u683c\u5f0f\u5316\u5b57\u7b26\u4e32\u9009\u9879\uff1a %Y \uff1a\u56db\u4f4d\u6570\u7684\u5e74\u4efd\uff08\u4f8b\u5982\uff1a2023\uff09 %m \uff1a\u4e24\u4f4d\u6570\u7684\u6708\u4efd\uff0801-12\uff09 %d \uff1a\u4e24\u4f4d\u6570\u7684\u65e5\u671f\uff0801-31\uff09 %H \uff1a\u4e24\u4f4d\u6570\u7684\u5c0f\u65f6\uff0800-23\uff09 %M \uff1a\u4e24\u4f4d\u6570\u7684\u5206\u949f\uff0800-59\uff09 %S \uff1a\u4e24\u4f4d\u6570\u7684\u79d2\uff0800-60\uff09 %Z \uff1a\u65f6\u533a\u540d\u79f0\uff08\u4f8b\u5982\uff1aGMT\uff09 # \u5c06\u5f53\u524d\u65f6\u95f4\u6233\u8f6c\u6362\u4e3a\u683c\u5f0f\u4e3a\"YYYY-MM-DD HH:MM:SS\"\u7684\u65e5\u671f\u548c\u65f6\u95f4\u5b57\u7b26\u4e32 $ awk 'BEGIN { timestamp = systime(); str = strftime(\"%Y-%m-%d %H:%M:%S\", timestamp); print str }' 2023 -05-15 22 :01:35 # \u5c06\u5f53\u524d\u65f6\u95f4\u6233\u7684\u524d\u4e00\u5c0f\u65f6\uff083600\u79d2\uff09\u8f6c\u6362\u4e3a\u683c\u5f0f\u4e3a\"YYYY-MM-DD HH:MM:SS\"\u7684\u65e5\u671f\u548c\u65f6\u95f4\u5b57\u7b26\u4e32 $ awk 'BEGIN { timestamp = systime()-3600; str = strftime(\"%Y-%m-%d %H:%M:%S\", timestamp); print str }' 2023 -05-15 21 :01:43","title":"5.10.12.1.\u5185\u7f6e\u51fd\u6570"},{"location":"linux/SRE/05-RegExpress/#510122","text":"\u4e3e\u4f8b\uff1a $ cat > func.awk << EOF function max(x,y){ x>y?var=x:var=y return var } BEGIN{print max(a,b)} EOF $ awk -v a = 30 -v b = 20 -f func.awk 30 \u4e3e\u4f8b\uff1a \u5728\u4e0b\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u5b9a\u4e49\u4e86\u4e00\u4e2a\u540d\u4e3a square() \u7684\u81ea\u5b9a\u4e49\u51fd\u6570\uff0c\u5b83\u63a5\u53d7\u4e00\u4e2a\u53c2\u6570 x \uff0c\u5e76\u8fd4\u56de x \u7684\u5e73\u65b9\u3002\u7136\u540e\uff0c\u5728\u4e3b\u4ee3\u7801\u5757\u4e2d\uff0c\u6211\u4eec\u58f0\u660e\u4e86\u4e00\u4e2a\u53d8\u91cf num \u5e76\u8d4b\u503c\u4e3a 5 \u3002\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u8c03\u7528\u4e86\u81ea\u5b9a\u4e49\u51fd\u6570 square() \uff0c\u4f20\u9012 num \u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u5c06\u8fd4\u56de\u503c\u5b58\u50a8\u5728\u53d8\u91cf result \u4e2d\u3002\u6700\u540e\uff0c\u6211\u4eec\u6253\u5370\u51fa result \u7684\u503c\u3002 $ cat > func.awk << EOF # \u81ea\u5b9a\u4e49\u51fd\u6570\uff1a\u8ba1\u7b97\u5e73\u65b9 function square(x) { return x * x; } # \u4f7f\u7528\u81ea\u5b9a\u4e49\u51fd\u6570 { num = 5; result = square(num); print \"\u5e73\u65b9\u7ed3\u679c\uff1a\" result; } EOF $ awk -f func.awk \u5e73\u65b9\u7ed3\u679c\uff1a25 \u4e3e\u4f8b\uff1a $ cat > func.awk << EOF # \u81ea\u5b9a\u4e49\u51fd\u6570\uff1a\u8ba1\u7b97\u6570\u7ec4\u5e73\u5747\u503c function calculateAverage(arr, size) { sum = 0; for (i = 1; i <= size; i++) { sum += arr[i]; } return sum / size; } # \u4f7f\u7528\u81ea\u5b9a\u4e49\u51fd\u6570 { # \u5b9a\u4e49\u6570\u7ec4 numbers[1] = 10; numbers[2] = 20; numbers[3] = 30; numbers[4] = 40; numbers[5] = 50; # \u8ba1\u7b97\u6570\u7ec4\u7684\u5e73\u5747\u503c size = 5; average = calculateAverage(numbers, size); print \"\u6570\u7ec4\u7684\u5e73\u5747\u503c\uff1a\" average; } EOF $ awk -f func.awk \u6570\u7ec4\u7684\u5e73\u5747\u503c\uff1a30","title":"5.10.12.2.\u81ea\u5b9a\u4e49\u51fd\u6570"},{"location":"linux/SRE/05-RegExpress/#510123awk","text":"\u4e3e\u4f8b\uff1a # \u6ce8\u610f\u8f6c\u4e49 $ cat > passwd.awk << EOF {if(\\$3>=1000)print \\$1,\\$3} EOF $ awk -F: -f passwd.awk /etc/passwd nobody 65534 vagrant 1000 \u4e0a\u9762\u4f8b\u5b50\u4e5f\u53ef\u4ee5\u5199\u6210\u5982\u4e0b\u811a\u6b65\u683c\u5f0f\u3002 $ cat > test.awk << EOF #!/bin/awk -f # This is an awk script {if(\\$3>=1000)print \\$1,\\$3} EOF $ chmod +x test.awk $ ./test.awk -F: /etc/passwd nobody 65534 vagrant 1000 \u5411awk\u811a\u672c\u4f20\u9012\u53c2\u6570\uff1a \u683c\u5f0f\uff1a awkfile var=value var2=value2 ... inputfile \u8bf4\u660e\uff1a \u4e0a\u9762\u683c\u5f0f\u53d8\u91cf\u5728 BEGIN \u8fc7\u7a0b\u4e2d\u4e0d\u53ef\u7528\uff0c\u76f4\u5230\u9996\u884c\u8f93\u5165\u5b8c\u6210\u4ee5\u540e\uff0c\u53d8\u91cf\u624d\u53ef\u7528\u3002 \u53ef\u4ee5\u901a\u8fc7 -v \u53c2\u6570\uff0c\u8ba9 awk \u5728\u6267\u884c BEGIN \u4e4b\u524d\u5f97\u5230\u53d8\u91cf\u3002 \u547d\u4ee4\u884c\u4e2d\u6bcf\u4e00\u4e2a\u6307\u5b9a\u7684\u53d8\u91cf\u90fd\u9700\u8981\u4e00\u4e2a -v \u53c2\u6570\u3002 \u4e3e\u4f8b\uff1a # x=100\u5728BEGIN{print x}\u533a\u6bb5\u53ef\u7528 $ awk -v x = 100 'BEGIN{print x}{print x+100}' /etc/hosts 100 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 # \u4e0d\u52a0-v\u5219x=100\u5728BEGIN{print x}\u533a\u6bb5\u4e0d\u53ef\u7528 $ awk x = 100 'BEGIN{print x}{print x+100}' /etc/hosts awk: fatal: cannot open file ` BEGIN { print x }{ print x+100 } ' for reading (No such file or directory) # \u4fee\u6b63\u4e0a\u9762\u7684\u9519\u8bef\uff0c\u5c06x=100\u653e\u5728\u540e\u9762\uff0c\u56e0\u4e3a\u6ca1\u6709-v\uff0c\u6240\u4ee5x=100\u5728BEGIN{print x}\u533a\u6bb5\u4e0d\u53ef\u7528\uff0c\u7b2c\u4e00\u884c\u8f93\u51fa\u7a7a\u767d $ awk ' BEGIN { print x }{ print x+100 } ' x = 100 /etc/hosts 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200","title":"5.10.12.3.awk\u811a\u672c"},{"location":"linux/SRE/05-RegExpress/#511","text":"\u663e\u793a /proc/meminfo \u6587\u4ef6\u4e2d\u4ee5\u5927\u5c0fs\u5f00\u5934\u7684\u884c\uff0c\u8981\u6c42\u4f7f\u7528\u4e24\u79cd\u65b9\u6cd5\u3002 cat /proc/meminfo | grep -i \"^s\" cat /proc/meminfo | grep \"^[sS]\" \u663e\u793a /etc/passwd \u6587\u4ef6\u4e2d\u4e0d\u4ee5 /bin/bash \u7ed3\u5c3e\u7684\u884c\u3002 grep -v \"/bin/bash $ \" /etc/passwd \u663e\u793a\u7528\u6237 rpc \u9ed8\u8ba4\u7684shell\u7a0b\u5e8f\u3002 $ grep \"rpc\" /etc/passwd | cut -d \":\" -f 7 /sbin/nologin \u627e\u51fa /etc/passwd \u4e2d\u7684\u4e24\u4f4d\u6216\u4e09\u4f4d\u6570\u3002 grep -Eo \"[:digit:]{2,3}\" /etc/passwd grep -Eo \"[0-9]{2,3}\" /etc/passwd \u8fd9\u91cc\u7528\u5230\u4e86 {} \uff0c\u5c5e\u4e8e\u6269\u5c55\u6b63\u5219\u7b26\u53f7\uff0c\u6240\u4ee5\u8981\u7528 -E \u3002 \u663e\u793aRocky 9\u7684 /etc/grub2.cfg \u6587\u4ef6\u4e2d\uff0c\u81f3\u5c11\u4ee5\u4e00\u4e2a\u7a7a\u767d\u5b57\u7b26\u5f00\u5934\u7684\u4e14\u540e\u9762\u6709\u975e\u7a7a\u767d\u5b57\u7b26\u7684\u884c\u3002\uff08\u6ce8\uff1a /etc/grub2.cfg \u5728openSUSE\u548cUbuntu\u4e2d\u6ca1\u6709\uff09 # \u4e0d\u542b\u9996\u5b57\u7b26\u4e3atab $ sudo grep \"^ \" /etc/grub2.cfg # \u5305\u542b\u9996\u5b57\u7b26\u4e3atab $ sudo grep \"^[[:space:]]\" /etc/grub2.cfg \u627e\u51fa netstat -tan \u547d\u4ee4\u7ed3\u679c\u4e2d\u4ee5 LISTEN \u540e\u8ddf\u4efb\u610f\u591a\u4e2a\u7a7a\u767d\u5b57\u7b26\u7ed3\u5c3e\u7684\u884c\u3002 netstat -tan | grep -E \"LISTEN[[:space:]]+\" \u663e\u793aRocky 9\u4e0a\u6240\u6709UID\u5c0f\u4e8e1000\u4ee5\u5185\u7684\u7528\u6237\u540d\u548cUID\u3002 cat /etc/passwd | cut -d \":\" -f 1 ,3 | grep -E \"\\:[0-9]{1,3} $ \" grep -E \"\\:[0-9]{1,3}\\:[0-9]{1,}\" /etc/passwd | cut -d \":\" -f 1 ,3 \u5728Rocky 9\u4e0a\u663e\u793a\u6587\u4ef6 /etc/passwd \u7528\u6237\u540d\u548cshell\u540c\u540d\u7684\u884c\u3002 $ grep -E \"^([[:alnum:]]+\\b).*\\1 $ \" /etc/passwd sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt \u5229\u7528 df \u548c grep \uff0c\u53d6\u51fa\u78c1\u76d8\u5404\u5206\u533a\u5229\u7528\u7387,\u5e76\u4ece\u5927\u5230\u5c0f\u6392\u5e8f\u3002 $ df | tr -s \" \" | cut -d \" \" -f 1 ,5 | sort -n -t \" \" -k 2 devtmpfs 0 % Filesystem Use% tmpfs 0 % tmpfs 0 % /dev/mapper/rl-home 1 % tmpfs 2 % /dev/mapper/rl-root 5 % /dev/nvme0n1p1 23 % \u663e\u793a\u4e09\u4e2a\u7528\u6237 root \uff0c sync \uff0c bin \u7684UID\u548c\u9ed8\u8ba4shell\u3002 $ grep \"^root:\\|^sync:\\|^bin:\" /etc/passwd | cut -d \":\" -f 1 ,7 root:/bin/bash bin:/usr/sbin/nologin \u4f7f\u7528 egrep \u53d6\u51fa /etc/default-1/text_2/local.3/grub \u4e2d\u5176\u57fa\u540d\u548c\u76ee\u5f55\u540d\u3002 # \u57fa\u540d $ echo \"/etc/default-1/text_2/local.3/grub\" | egrep -io \"[[:alpha:]]+ $ \" grub # \u76ee\u5f55\u540d $ echo \"/etc/default-1/text_2/local.3/grub\" | egrep -io \"/([[:alpha:]]+.|_?[[:alpha:]]|[[:alnum:]]+/){7}\" /etc/default-1/text_2/local.3/ \u7edf\u8ba1 last \u547d\u4ee4\u4e2d\u4ee5 vagrant \u767b\u5f55\u7684\u6bcf\u4e2a\u4e3b\u673aIP\u5730\u5740\u767b\u5f55\u6b21\u6570\u3002 $ last | grep vagrant | tr -s \" \" | cut -d \" \" -f 3 | grep -E \"([0-9]{1,3}\\.){1,3}[0-9]{1,3}\" | sort -n | uniq -c 24 192 .168.10.107 38 192 .168.10.109 17 192 .168.10.201 6 192 .168.10.210 2 192 .168.10.220 \u5229\u7528\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\u5206\u522b\u8868\u793a0-9\u300110-99\u3001100-199\u3001200-249\u3001250-255\u3002 [ 0 -9 ] | [ 0 -9 ]{ 2 } | 1 [ 0 -9 ]{ 2 } | 2 [ 0 -4 ][ 0 -9 ] | 25 [ 0 -5 ] \u663e\u793a ifconfig \u547d\u4ee4\u7ed3\u679c\u4e2d\u6240\u6709IPv4\u5730\u5740\u3002 $ ifconfig | grep -Eo \"([0-9]{1,3}\\.){3}[0-9]{1,3}\" | grep -v \"^255\" 192 .168.10.210 192 .168.10.255 127 .0.0.1 \u663e\u793a ip addr \u547d\u4ee4\u7ed3\u679c\u4e2d\u6240\u6709IPv4\u5730\u5740\u3002 $ ip addr show eth0 | grep inet | grep eth0 | tr -s \" \" | cut -d \" \" -f 3 | cut -d \"/\" -f 1 192 .168.10.210 $ ip addr show | grep -Eo \"([0-9]{1,3}\\.){3}[0-9]{1,3}\" | grep -v \"^255\" 127 .0.0.1 192 .168.10.210 192 .168.10.255 \u5c06\u6b64\u5b57\u7b26\u4e32Welcome to the linux world\u4e2d\u7684\u6bcf\u4e2a\u5b57\u7b26\u53bb\u91cd\u5e76\u6392\u5e8f\uff0c\u91cd\u590d\u6b21\u6570\u591a\u7684\u6392\u5230\u524d\u9762\u3002 $ echo \"Welcome to the linux world\" | grep -o [[ :alpha: ]] | sort | uniq -c | sort -nr 3 o 3 l 3 e 2 t 1 x 1 W 1 w 1 u 1 r 1 n 1 m 1 i 1 h 1 d 1 c \u5220\u9664 /etc/default/grub \u6587\u4ef6\u4e2d\u6240\u6709\u4ee5\u7a7a\u767d\u5f00\u5934\u7684\u884c\u884c\u9996\u7684\u7a7a\u767d\u5b57\u7b26\u3002 sed '/^$/d' /etc/default/grub \u5220\u9664 /etc/default/grub \u6587\u4ef6\u4e2d\u6240\u6709\u4ee5 # \u5f00\u5934\uff0c\u540e\u9762\u81f3\u5c11\u8ddf\u4e00\u4e2a\u7a7a\u767d\u5b57\u7b26\u7684\u884c\u7684\u884c\u9996\u7684 # \u548c\u7a7a\u767d\u5b57\u7b26\u3002 sed -r '/#[[:space:]]+/d;/#/d' /etc/default/grub \u4e0a\u9762\u8f93\u51fa\u7ed3\u679c\u4e2d\u5305\u542b\u7a7a\u767d\u884c\u3002 \u82e5\u8f93\u51fa\u4e2d\u5220\u9664\u7a7a\u767d\u884c\uff0c\u5219\uff1a sed -r '/#[[:space:]]+/d;/#/d;/^$/d' /etc/default/grub \u5728 /etc/fstab \u6bcf\u4e00\u884c\u884c\u9996\u589e\u52a0 # \u53f7\u3002 sed -r 's/(.*)/#&/' /etc/fstab \u5728 /etc/fstab \u6587\u4ef6\u4e2d\u4e0d\u4ee5 # \u5f00\u5934\u7684\u884c\u7684\u884c\u9996\u589e\u52a0 # \u53f7\uff08\u5305\u62ec\u7a7a\u884c\uff09\u3002 sed -r 's/^[^#].*/#&/' -r 's/^$/#/' /etc/default/grub \u901a\u8fc7\u547d\u4ee4 rpm -qa --last |awk -F ' ' '{print $1}' \u5f97\u5230\u6700\u65b0\u5b89\u88c5\u7684\u5305\u5217\u8868\u3002\u7edf\u8ba1\u6240\u6709 x86_64 \u7ed3\u5c3e\u7684\u5b89\u88c5\u5305\u540d\u4ee5 . \u5206\u9694\u5012\u6570\u7b2c\u4e8c\u4e2a\u5b57\u6bb5\u7684\u91cd\u590d\u6b21\u6570\u3002 $ rpm -qa --last | awk -F ' ' '{print $1}' | sed -nr '/x86_64$/s@.*\\.(.*)\\.x86_64@\\1@p' | sort -r | uniq -c 75 el9_0 563 el9 3 7 1 5 2 4 2 3 10 2 29 1 \u5728openSUSE\u4e2d\u7edf\u8ba1 /etc/rc.status \u6587\u4ef6\u4e2d\u6bcf\u4e2a\u5355\u8bcd\u7684\u51fa\u73b0\u6b21\u6570\uff0c\u5e76\u6392\u5e8f\uff08\u7528grep\u548csed\u4e24\u79cd\u65b9\u6cd5\u5206\u522b\u5b9e\u73b0\uff09\u3002 grep -Eo \"[a-zA-Z]+\" /etc/rc.status | sort | uniq -c cat /etc/rc.status | sed -r 's/[^[:alpha:]]+/\\n/g' | sed '/^$/d' | sort | uniq -c | sort -nr \u5c06\u6587\u672c\u6587\u4ef6\u7684n\u548cn+1\u884c\u5408\u5e76\u4e3a\u4e00\u884c\uff0cn\u4e3a\u5947\u6570\u884c\u3002 $ cat < sed.txt 1aa 2bb 3cc 4dd 5ee 6ff 7gg EOF $ sed -n 'N;s/\\n//p' sed.txt 1aa2bb 3cc4dd 5ee6ff $ sed 'N;s/\\n//' sed.txt 1aa2bb 3cc4dd 5ee6ff 7gg \u5bf9\u4e00\u4e32\u6570\u5b57\u8fdb\u884c\u6c42\u548c\u3002 $ cat < number.txt 1 2 3 4 5 6 EOF $ tr ' ' + < number.txt | bc 21 $ sum = 0 ; for i in ` cat number.txt ` ; do let sum += i ; done ; echo $sum 21 $ awk '{sum=0;for(i=1;i<=NF;i++){sum+=i};print sum}' number.txt 21 \u53d6\u51fa\u5b57\u7b26\u4e32\u4e2d\u7684\u6570\u5b57\u3002 $ echo 'kdajl;3k8jd33la5kj23f90ld02sakjflakjdslf' | awk -F \"\" ' { for(i=1;i<=NF;i++) { if($i ~ /[0-9]/) { str=(str $i) } }; print str }' 38335239002 host.log \u6587\u4ef6\u5185\u5bb9\u5982\u4e0b\uff0c\u63d0\u53d6 .edu.cn \u524d\u9762\u7684\u4e3b\u673a\u540d\uff0c\u5e76\u56de\u5199\u5230\u8be5\u6587\u4ef6\u4e2d\u3002 $ cat > host.log << EOF 1 www.edu.cn 2 blog.edu.cn 3 learning.edu.cn 4 java.edu.cn 5 nodejs.edu.cn 6 k8s.eud.cn 7 linux.edu.cn 8 python.edu.cn 9 learning.edu.cn 10 java.edu.cn 11 nodejs.edu.cn 12 www.edu.cn EOF # \u5bf9\u6bd4 $ awk -F '[ .]' '{print $1}' host.log 1 2 3 4 5 6 7 8 9 10 11 12 $ awk -F '[ .]' '{print $2}' host.log www blog learning java nodejs k8s linux python learning java nodejs www # \u4ee5\u7a7a\u683c\u6216\u8005.\u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u7b2c\u4e8c\u5217\uff08\u4e3b\u673a\u540d\uff09\uff0c\u8ffd\u52a0\u5199\u5165\u539f\u6587\u4ef6 $ awk -F '[ .]' '{print $2}' host.log >> host.log $ cat host.log 1 www.edu.cn 2 blog.edu.cn 3 learning.edu.cn 4 java.edu.cn 5 nodejs.edu.cn 6 k8s.eud.cn 7 linux.edu.cn 8 python.edu.cn 9 learning.edu.cn 10 java.edu.cn 11 nodejs.edu.cn 12 www.edu.cn www blog learning java nodejs k8s linux python learning java nodejs www \u7edf\u8ba1\u6587\u4ef6 /etc/fstab \u4e2d\u6bcf\u4e2a\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u51fa\u73b0\u7684\u6b21\u6570\u3002 # \u4ee5UUID\u5f00\u5934\uff0c\u4e00\u4e2a\u6216\u591a\u4e2a\u7a7a\u683c\u4e3a\u5206\u9694\u7b26\uff0c\u8bfb\u53d6\u7b2c\u4e09\u5217\uff08\u5373\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\uff09\u5e76\u8ba1\u6570\u3002 $ awk -F ' +' '/^UUID/{fs[$3]++}END{for(i in fs){print i, fs[i]}}' /etc/fstab swap 1 btrfs 10 vfat 1 # \u65b9\u6cd52 $ awk -F ' +' '/^UUID/{print $3}' /etc/fstab | uniq -c 10 btrfs 1 swap 1 vfat \u7edf\u8ba1\u6587\u4ef6 /etc/fstab \u4e2d\u6bcf\u4e2a\u5355\u8bcd\u51fa\u73b0\u7684\u6b21\u6570\u3002 $ awk -F \"[^[:alpha:]]\" '{for(i=1;i<=NF;i++)word[$i]++}END{for(a in word)if(a!=\"\")print a,word[a]}' /etc/fstab swap 2 B 1 srv 2 btrfs 10 snapshots 2 vfat 1 opt 2 cbaef 10 UUID 12 E 1 ecf 1 CD 1 cf 1 arm 2 a 11 c 2 tmp 2 usr 2 var 2 afa 20 home 2 d 10 utf 1 e 2 efi 3 grub 2 boot 3 subvol 9 root 2 local 2 defaults 2 f 10 \u63d0\u53d6\u5b57\u7b26\u4e32 Yd$@C#M05MD9&8923+Vip3wZ!33*44&55 \u4e2d\u6240\u6709\u7684\u6570\u5b57\u3002 # \u5bf9\u6bd4\u5355\u5f15\u53f7\u548c\u53cc\u5f15\u53f7\u7684\u533a\u522b\u3002 $ echo \"Yd $@ C#M05MD9&8923+Vip3wZ!33*44&55\" echo \"Yd $@ C#M05MD9&8923+Vip3wZcgcreate -g cpu:mygroup44&55\" YdC#M05MD9 & 8923 +Vip3wZcgcreate -g cpu:mygroup44 & 55 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' Yd $@ C#M05MD9 & 8923 +Vip3wZ!33*44 & 55 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk '{gsub(/[^0-9]/,\"\");print $0}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '[^0-9]' '{for(i=1;i<=NF;i++){printf \"%s\", $i}}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F \"\" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' # \u6ce8\u610f\uff0c\u5982\u679c\u5199\u6210\u5982\u4e0b\u683c\u5f0f\uff0c\u5219\u62a5\u9519\u3002 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' # \u6ce8\u610f\uff0c\u5982\u679c\u5199\u6210\u5982\u4e0b\u683c\u5f0f\uff0c\u5219\u8f93\u51fa\u539f\u5b57\u7b26\u4e32\u3002 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F ' ' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' \u751f\u6210500\u4e2a\u968f\u673a\u6570\uff0c\u4fdd\u5b58\u5230\u6587\u4ef6random.txt\u4e2d\uff0c\u683c\u5f0f\u4e3a 100,20,61,98... \uff0c\u53d6\u51fa\u5176\u4e2d\u6700\u5927\u6574\u6570\u548c\u6700\u5c0f\u6574\u6570\u3002 $ str = \"\" ; for (( i = 1 ; i< = 500 ; i++ )) ; do if [ $i -ne 500 ] ; then str += \" $RANDOM ,\" ; else str += \" $RANDOM \" ; fi ; done ; echo \" $str \" > random.txt $ cat random.txt 11308 ,8764,2075,9411,...... $ awk -F, '{max=$1;min=$1;for(i=1;i<=NF;i++){if($i>max){max=$i}else{if($i200){system(\"iptables -A INPUT -s \" i \" -j REJECT;\")}}}' \u5c06\u4e0b\u9762\u5185\u5bb9\u4e2dFQDN\u53d6\u51fa\uff0c\u5e76\u6839\u636e\u5176\u8fdb\u884c\u8ba1\u6570\uff0c\u4ece\u9ad8\u5230\u4f4e\u6392\u5e8f\u3002 $ cat > fqdn.txt << EOF http://mail.edu.com/index.html http://www.edu.com/test.html http://study.edu.com/index.html http://blog.edu.com/index.html http://www.edu.com/images/logo.jpg http://blog.edu.com/20080102.html EOF $ awk -F \"/\" '{url[$3]++}END{for(i in url){print url[i], i}}' fqdn.txt | sort -nr 2 www.edu.com 2 blog.edu.com 1 study.edu.com 1 mail.edu.com \u5c06\u4ee5\u4e0b\u2f42\u672c\u4ee5inode\u4e3a\u6807\u8bb0\uff0c\u5bf9inode\u76f8\u540c\u7684counts\u8fdb\u2f8f\u7d2f\u52a0\uff0c\u5e76\u4e14\u7edf\u8ba1\u51fa\u540c\u4e00inode\u4e2d\uff0cbeginnumber\u7684\u6700\u5c0f\u503c\u548cendnumber\u7684\u6700\u5927\u503c\u3002 inode | beginnumber | endnumber | counts | 106 | 3363120000 | 3363129999 | 10000 | 106 | 3368560000 | 3368579999 | 20000 | 310 | 3337000000 | 3337000100 | 101 | 310 | 3342950000 | 3342959999 | 10000 | 310 | 3362120960 | 3362120961 | 2 | 311 | 3313460102 | 3313469999 | 9898 | 311 | 3313470000 | 3313499999 | 30000 | 311 | 3362120962 | 3362120963 | 2 | \u8f93\u51fa\u7684\u7ed3\u679c\u683c\u5f0f\u4e3a\uff1a 310 | 3337000000 | 3362120961 | 10103 | 311 | 3313460102 | 3362120963 | 39900 | 106 | 3363120000 | 3368579999 | 30000 | $ cat > inode.text << EOF inode|beginnumber|endnumber|counts| 106|3363120000|3363129999|10000| 106|3368560000|3368579999|20000| 310|3337000000|3337000100|101| 310|3342950000|3342959999|10000| 310|3362120960|3362120961|2| 311|3313460102|3313469999|9898| 311|3313470000|3313499999|30000| 311|3362120962|3362120963|2| EOF $ awk -F '|' -v OFS = '|' '/^[0-9]/{inode[$1]++; if(!bn[$1]){bn[$1]=$2}else if(bn[$1]>$2) {bn[$1]=$2}; if(en[$1]<$3)en[$1]=$3;cnt[$1]+=$(NF-1)} END{for(i in inode)print i,bn[i],en[i],cnt[i]}' inode.text 106 | 3363120000 | 3368579999 | 30000 310 | 3337000000 | 3362120961 | 10103 311 | 3313460102 | 3362120963 | 39900","title":"5.11.\u5c0f\u7ec3\u4e60"},{"location":"linux/SRE/06-FileLookup/","text":"\u7b2c\u516d\u7ae0 \u6587\u4ef6\u67e5\u627e \u00b6 \u5e38\u7528\u6587\u4ef6\u67e5\u627e\u547d\u4ee4\uff1a locate\u547d\u4ee4 \u00b6 locate \u662f\u4e00\u4e2a\u5728 Linux \u7cfb\u7edf\u4e0a\u7528\u4e8e\u5feb\u901f\u641c\u7d22\u6587\u4ef6\u548c\u76ee\u5f55\u7684\u547d\u4ee4\u3002\u5b83\u4f7f\u7528\u9884\u5148\u6784\u5efa\u7684\u6587\u4ef6\u6570\u636e\u5e93 /var/lib/mlocate/mlocate.db \u8fdb\u884c\u641c\u7d22\uff0c\u56e0\u6b64\u6bd4\u76f4\u63a5\u5728\u6587\u4ef6\u7cfb\u7edf\u4e0a\u641c\u7d22\u8981\u5feb\u5f97\u591a\u3002 \u4f7f\u7528 updatedb \u547d\u4ee4\u624b\u52a8\u66f4\u65b0\u6587\u4ef6\u6570\u636e\u5e93 /var/lib/mlocate/mlocate.db \uff0c\u7d22\u5f15\u6784\u5efa\u8fc7\u7a0b\u9700\u8981\u904d\u5386\u6574\u4e2a\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u5f88\u6d88\u8017\u8d44\u6e90\u3002 \u6ce8\u610f\uff0c\u7531\u4e8e locate \u4f7f\u7528\u9884\u5148\u6784\u5efa\u7684\u6587\u4ef6\u6570\u636e\u5e93\uff0c\u56e0\u6b64\u5728\u66f4\u65b0\u6587\u4ef6\u6570\u636e\u5e93\u4e4b\u524d\uff0c\u65b0\u521b\u5efa\u6216\u79fb\u52a8\u7684\u6587\u4ef6\u53ef\u80fd\u4e0d\u4f1a\u7acb\u5373\u51fa\u73b0\u5728\u641c\u7d22\u7ed3\u679c\u4e2d\u3002 \u5728openSUSE 15\u4e2d\u9ed8\u8ba4\u6ca1\u6709\u5b89\u88c5\uff0c\u9700\u8981\u624b\u52a8\u5b89\u88c5\u4e0b\u9762\u7684\u8f6f\u4ef6\u5305\u3002 sudo zypper ref sudo zypper in mlocate sudo updatedb locate \u547d\u4ee4\u7684\u7279\u70b9\uff1a \u67e5\u627e\u901f\u5ea6\u5feb \u6a21\u7cca\u67e5\u627e \u975e\u5b9e\u65f6\u67e5\u627e \u641c\u7d22\u7684\u662f\u6587\u4ef6\u7684\u5168\u8def\u5f84\uff0c\u4e0d\u4ec5\u4ec5\u662f\u6587\u4ef6\u540d \u53ef\u80fd\u53ea\u641c\u7d22\u5f53\u524d\u7528\u6237\u5177\u5907\u8bfb\u53d6 r \u548c\u6267\u884c x \u6743\u9650\u7684\u76ee\u5f55 locate \u547d\u4ee4\u7684\u683c\u5f0f\uff1a locate [OPTIONS] PATTERN \u5e38\u7528\u9009\u9879\uff1a -i \uff1a\u5ffd\u7565\u5927\u5c0f\u5199\u3002 -r \uff1a\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u8fdb\u884c\u6a21\u5f0f\u5339\u914d\u3002 -l \uff1a\u4ec5\u663e\u793a\u6587\u4ef6\u8def\u5f84\uff0c\u800c\u4e0d\u663e\u793a\u6587\u4ef6\u540d\u3002 -c \uff1a\u4ec5\u663e\u793a\u5339\u914d\u7ed3\u679c\u7684\u8ba1\u6570\u3002 -b \uff1a\u53ea\u5339\u914d\u57fa\u672c\u540d\u79f0\u800c\u4e0d\u662f\u5168\u8def\u5f84\u540d\u3002 -n N \uff1a\u53ea\u5217\u4e3e\u524dN\u4e2a\u5339\u914d\u9879\u76ee\u3002 -q \uff1a\u5b89\u9759\u6a21\u5f0f\uff0c\u4e0d\u663e\u793a\u4efb\u4f55\u9519\u8bef\u4fe1\u606f\u3002 man locate \u83b7\u53d6\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\u548c\u9009\u9879\u8bf4\u660e\u3002 \u4e3e\u4f8b\uff1a\u641c\u7d22\u540d\u4e3a bashrc \u7684\u6587\u4ef6\uff0c\u6ce8\u610f\uff0c\u8fd9\u91cc\u662f\u641c\u7d22\u6587\u4ef6\u540d\u6216\u8def\u5f84\u540d\u4e2d\u5305\u542b bashrc \u7684\u6587\u4ef6 $ locate bashrc /etc/bash.bashrc /etc/skel/.bashrc /home/vagrant/.bashrc \u8981\u641c\u7d22\u4ee5 \"image\" \u5f00\u5934\u7684\u6587\u4ef6\uff0c\u5ffd\u7565\u5927\u5c0f\u5199\uff1a locate -i '^image' \u4e3e\u4f8b\uff1a\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u641c\u7d22\u4ee5 .conf \u4e3a\u6269\u5c55\u540d\u7684\u6587\u4ef6\uff1a locate -r '\\.conf$' find\u547d\u4ee4 \u00b6 find \u547d\u4ee4\u662f\u5b9e\u65f6\u67e5\u627e\u5de5\u5177\uff0c\u901a\u8fc7\u904d\u5386\u6307\u5b9a\u8def\u5f84\u5b8c\u6210\u6587\u4ef6\u67e5\u627e\u3002 \u7279\u70b9\uff1a \u67e5\u627e\u901f\u5ea6\u7565\u6162 \u7cbe\u786e\u67e5\u627e \u5b9e\u65f6\u67e5\u627e \u67e5\u627e\u6761\u4ef6\u4e30\u5bcc \u53ef\u80fd\u53ea\u641c\u7d22\u5f53\u524d\u7528\u6237\u5177\u5907\u8bfb\u53d6 r \u548c\u6267\u884c x \u6743\u9650\u7684\u76ee\u5f55 find \u547d\u4ee4\u7684\u683c\u5f0f\uff1a find [OPTIONS] [PATH] [CONDITIONS] [ACTIONS] [PATH]\uff1a\u6307\u5b9a\u5177\u4f53\u76ee\u6807\u8def\u5f84\uff0c\u9ed8\u8ba4\u4e3a\u5f53\u524d\u76ee\u5f55\u3002 [CONDITIONS]\uff1a\u6307\u5b9a\u67e5\u627e\u6807\u51c6\uff0c\u53ef\u4ee5\u662f\u6587\u4ef6\u540d\u3001\u6587\u4ef6\u5927\u5c0f\u3001\u6587\u4ef6\u7c7b\u578b\u3001\u6743\u9650\u7b49\uff0c\u9ed8\u8ba4\u4e3a\u627e\u51fa\u6307\u5b9a\u8def\u5f84\u4e0b\u6240\u6709\u6587\u4ef6\u3002 [ACTIONS]\uff1a\u5bf9\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u6267\u884c\u7684\u64cd\u4f5c\uff0c\u9ed8\u8ba4\u8f93\u51fa\u5230\u5c4f\u5e55\u3002 -maxdepth level \uff1a\u6700\u5927\u641c\u7d22\u76ee\u5f55\u6df1\u5ea6\uff0c\u6307\u5b9a\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u4e3a\u7b2c\u4e00\u7ea7\u3002 -mindepth level \uff1a\u6700\u5c0f\u641c\u7d22\u76ee\u5f55\u6df1\u5ea6\u3002 \u4e3e\u4f8b\uff1a\u53ea\u641c\u7d22 /etc \u76ee\u5f55\u7b2c\u4e8c\u7ea7\u3002 find /etc -maxdepth 2 -mindepth 2 find \u547d\u4ee4\u9ed8\u8ba4\u662f\u5148\u5904\u7406\u76ee\u5f55\uff0c\u518d\u5904\u7406\u76ee\u5f55\u5185\u90e8\u7684\u6587\u4ef6\u3002\u9009\u9879 -depth \u4f1a\u4fee\u6539 find \u547d\u4ee4\u5904\u7406\u4f18\u5148\u987a\u5e8f\uff0c\u5148\u5904\u7406\u76ee\u5f55\u5185\u90e8\u7684\u6587\u4ef6\uff0c\u518d\u5904\u7406\u76ee\u5f55\u3002 \u6839\u636e\u6587\u4ef6\u540d\u548cinode\u67e5\u627e\uff1a -name \"FILENAME\" \uff1a\u652f\u6301\u4f7f\u7528\u901a\u914d\u7b26\uff0c\u5982 * \uff0c \uff1f \uff0c [] \uff0c [^] \uff0c\u6ce8\u610f\uff0c\u901a\u914d\u7b26\u8981\u7528\u53cc\u5f15\u53f7\u3002 -iname \"FILENAME\" \uff1a\u4e0d\u533a\u5206\u5b57\u6bcd\u5927\u5c0f\u5199\u3002 -inum N \uff1a\u6309inode\u53f7\u67e5\u627e\u3002 -samefile NAME \uff1a\u67e5\u627e\u76f8\u540cinode\u53f7\u7684\u6587\u4ef6\u3002 -links N \uff1a\u94fe\u63a5\u6570\u4e3a N \u7684\u6587\u4ef6\u3002 -regex \"PATTERN\" \uff1a\u4ee5PATTERN\u5339\u914d\u6574\u4e2a\u6587\u4ef6\u8def\u5f84\uff0c\u800c\u975e\u6587\u4ef6\u540d\u79f0\u3002 xargs\u547d\u4ee4 \u00b6","title":"\u7b2c\u516d\u7ae0 \u6587\u4ef6\u67e5\u627e"},{"location":"linux/SRE/06-FileLookup/#_1","text":"\u5e38\u7528\u6587\u4ef6\u67e5\u627e\u547d\u4ee4\uff1a","title":"\u7b2c\u516d\u7ae0 \u6587\u4ef6\u67e5\u627e"},{"location":"linux/SRE/06-FileLookup/#locate","text":"locate \u662f\u4e00\u4e2a\u5728 Linux \u7cfb\u7edf\u4e0a\u7528\u4e8e\u5feb\u901f\u641c\u7d22\u6587\u4ef6\u548c\u76ee\u5f55\u7684\u547d\u4ee4\u3002\u5b83\u4f7f\u7528\u9884\u5148\u6784\u5efa\u7684\u6587\u4ef6\u6570\u636e\u5e93 /var/lib/mlocate/mlocate.db \u8fdb\u884c\u641c\u7d22\uff0c\u56e0\u6b64\u6bd4\u76f4\u63a5\u5728\u6587\u4ef6\u7cfb\u7edf\u4e0a\u641c\u7d22\u8981\u5feb\u5f97\u591a\u3002 \u4f7f\u7528 updatedb \u547d\u4ee4\u624b\u52a8\u66f4\u65b0\u6587\u4ef6\u6570\u636e\u5e93 /var/lib/mlocate/mlocate.db \uff0c\u7d22\u5f15\u6784\u5efa\u8fc7\u7a0b\u9700\u8981\u904d\u5386\u6574\u4e2a\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u5f88\u6d88\u8017\u8d44\u6e90\u3002 \u6ce8\u610f\uff0c\u7531\u4e8e locate \u4f7f\u7528\u9884\u5148\u6784\u5efa\u7684\u6587\u4ef6\u6570\u636e\u5e93\uff0c\u56e0\u6b64\u5728\u66f4\u65b0\u6587\u4ef6\u6570\u636e\u5e93\u4e4b\u524d\uff0c\u65b0\u521b\u5efa\u6216\u79fb\u52a8\u7684\u6587\u4ef6\u53ef\u80fd\u4e0d\u4f1a\u7acb\u5373\u51fa\u73b0\u5728\u641c\u7d22\u7ed3\u679c\u4e2d\u3002 \u5728openSUSE 15\u4e2d\u9ed8\u8ba4\u6ca1\u6709\u5b89\u88c5\uff0c\u9700\u8981\u624b\u52a8\u5b89\u88c5\u4e0b\u9762\u7684\u8f6f\u4ef6\u5305\u3002 sudo zypper ref sudo zypper in mlocate sudo updatedb locate \u547d\u4ee4\u7684\u7279\u70b9\uff1a \u67e5\u627e\u901f\u5ea6\u5feb \u6a21\u7cca\u67e5\u627e \u975e\u5b9e\u65f6\u67e5\u627e \u641c\u7d22\u7684\u662f\u6587\u4ef6\u7684\u5168\u8def\u5f84\uff0c\u4e0d\u4ec5\u4ec5\u662f\u6587\u4ef6\u540d \u53ef\u80fd\u53ea\u641c\u7d22\u5f53\u524d\u7528\u6237\u5177\u5907\u8bfb\u53d6 r \u548c\u6267\u884c x \u6743\u9650\u7684\u76ee\u5f55 locate \u547d\u4ee4\u7684\u683c\u5f0f\uff1a locate [OPTIONS] PATTERN \u5e38\u7528\u9009\u9879\uff1a -i \uff1a\u5ffd\u7565\u5927\u5c0f\u5199\u3002 -r \uff1a\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u8fdb\u884c\u6a21\u5f0f\u5339\u914d\u3002 -l \uff1a\u4ec5\u663e\u793a\u6587\u4ef6\u8def\u5f84\uff0c\u800c\u4e0d\u663e\u793a\u6587\u4ef6\u540d\u3002 -c \uff1a\u4ec5\u663e\u793a\u5339\u914d\u7ed3\u679c\u7684\u8ba1\u6570\u3002 -b \uff1a\u53ea\u5339\u914d\u57fa\u672c\u540d\u79f0\u800c\u4e0d\u662f\u5168\u8def\u5f84\u540d\u3002 -n N \uff1a\u53ea\u5217\u4e3e\u524dN\u4e2a\u5339\u914d\u9879\u76ee\u3002 -q \uff1a\u5b89\u9759\u6a21\u5f0f\uff0c\u4e0d\u663e\u793a\u4efb\u4f55\u9519\u8bef\u4fe1\u606f\u3002 man locate \u83b7\u53d6\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\u548c\u9009\u9879\u8bf4\u660e\u3002 \u4e3e\u4f8b\uff1a\u641c\u7d22\u540d\u4e3a bashrc \u7684\u6587\u4ef6\uff0c\u6ce8\u610f\uff0c\u8fd9\u91cc\u662f\u641c\u7d22\u6587\u4ef6\u540d\u6216\u8def\u5f84\u540d\u4e2d\u5305\u542b bashrc \u7684\u6587\u4ef6 $ locate bashrc /etc/bash.bashrc /etc/skel/.bashrc /home/vagrant/.bashrc \u8981\u641c\u7d22\u4ee5 \"image\" \u5f00\u5934\u7684\u6587\u4ef6\uff0c\u5ffd\u7565\u5927\u5c0f\u5199\uff1a locate -i '^image' \u4e3e\u4f8b\uff1a\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u641c\u7d22\u4ee5 .conf \u4e3a\u6269\u5c55\u540d\u7684\u6587\u4ef6\uff1a locate -r '\\.conf$'","title":"locate\u547d\u4ee4"},{"location":"linux/SRE/06-FileLookup/#find","text":"find \u547d\u4ee4\u662f\u5b9e\u65f6\u67e5\u627e\u5de5\u5177\uff0c\u901a\u8fc7\u904d\u5386\u6307\u5b9a\u8def\u5f84\u5b8c\u6210\u6587\u4ef6\u67e5\u627e\u3002 \u7279\u70b9\uff1a \u67e5\u627e\u901f\u5ea6\u7565\u6162 \u7cbe\u786e\u67e5\u627e \u5b9e\u65f6\u67e5\u627e \u67e5\u627e\u6761\u4ef6\u4e30\u5bcc \u53ef\u80fd\u53ea\u641c\u7d22\u5f53\u524d\u7528\u6237\u5177\u5907\u8bfb\u53d6 r \u548c\u6267\u884c x \u6743\u9650\u7684\u76ee\u5f55 find \u547d\u4ee4\u7684\u683c\u5f0f\uff1a find [OPTIONS] [PATH] [CONDITIONS] [ACTIONS] [PATH]\uff1a\u6307\u5b9a\u5177\u4f53\u76ee\u6807\u8def\u5f84\uff0c\u9ed8\u8ba4\u4e3a\u5f53\u524d\u76ee\u5f55\u3002 [CONDITIONS]\uff1a\u6307\u5b9a\u67e5\u627e\u6807\u51c6\uff0c\u53ef\u4ee5\u662f\u6587\u4ef6\u540d\u3001\u6587\u4ef6\u5927\u5c0f\u3001\u6587\u4ef6\u7c7b\u578b\u3001\u6743\u9650\u7b49\uff0c\u9ed8\u8ba4\u4e3a\u627e\u51fa\u6307\u5b9a\u8def\u5f84\u4e0b\u6240\u6709\u6587\u4ef6\u3002 [ACTIONS]\uff1a\u5bf9\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u6267\u884c\u7684\u64cd\u4f5c\uff0c\u9ed8\u8ba4\u8f93\u51fa\u5230\u5c4f\u5e55\u3002 -maxdepth level \uff1a\u6700\u5927\u641c\u7d22\u76ee\u5f55\u6df1\u5ea6\uff0c\u6307\u5b9a\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u4e3a\u7b2c\u4e00\u7ea7\u3002 -mindepth level \uff1a\u6700\u5c0f\u641c\u7d22\u76ee\u5f55\u6df1\u5ea6\u3002 \u4e3e\u4f8b\uff1a\u53ea\u641c\u7d22 /etc \u76ee\u5f55\u7b2c\u4e8c\u7ea7\u3002 find /etc -maxdepth 2 -mindepth 2 find \u547d\u4ee4\u9ed8\u8ba4\u662f\u5148\u5904\u7406\u76ee\u5f55\uff0c\u518d\u5904\u7406\u76ee\u5f55\u5185\u90e8\u7684\u6587\u4ef6\u3002\u9009\u9879 -depth \u4f1a\u4fee\u6539 find \u547d\u4ee4\u5904\u7406\u4f18\u5148\u987a\u5e8f\uff0c\u5148\u5904\u7406\u76ee\u5f55\u5185\u90e8\u7684\u6587\u4ef6\uff0c\u518d\u5904\u7406\u76ee\u5f55\u3002 \u6839\u636e\u6587\u4ef6\u540d\u548cinode\u67e5\u627e\uff1a -name \"FILENAME\" \uff1a\u652f\u6301\u4f7f\u7528\u901a\u914d\u7b26\uff0c\u5982 * \uff0c \uff1f \uff0c [] \uff0c [^] \uff0c\u6ce8\u610f\uff0c\u901a\u914d\u7b26\u8981\u7528\u53cc\u5f15\u53f7\u3002 -iname \"FILENAME\" \uff1a\u4e0d\u533a\u5206\u5b57\u6bcd\u5927\u5c0f\u5199\u3002 -inum N \uff1a\u6309inode\u53f7\u67e5\u627e\u3002 -samefile NAME \uff1a\u67e5\u627e\u76f8\u540cinode\u53f7\u7684\u6587\u4ef6\u3002 -links N \uff1a\u94fe\u63a5\u6570\u4e3a N \u7684\u6587\u4ef6\u3002 -regex \"PATTERN\" \uff1a\u4ee5PATTERN\u5339\u914d\u6574\u4e2a\u6587\u4ef6\u8def\u5f84\uff0c\u800c\u975e\u6587\u4ef6\u540d\u79f0\u3002","title":"find\u547d\u4ee4"},{"location":"linux/SRE/06-FileLookup/#xargs","text":"","title":"xargs\u547d\u4ee4"},{"location":"linux/SRE/07-FilePacking/","text":"\u7b2c\u4e03\u7ae0 \u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305 \u00b6 \u5e38\u7528\u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305\u547d\u4ee4\uff1a compress\u548cuncompress gzip\u548cgunzip bzip2\u548cbunzip2 xz\u548cunxz zip\u548cunzip tar","title":"\u7b2c\u4e03\u7ae0 \u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305"},{"location":"linux/SRE/07-FilePacking/#_1","text":"\u5e38\u7528\u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305\u547d\u4ee4\uff1a compress\u548cuncompress gzip\u548cgunzip bzip2\u548cbunzip2 xz\u548cunxz zip\u548cunzip tar","title":"\u7b2c\u4e03\u7ae0 \u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305"},{"location":"python/","text":"Content \u00b6 Memo Python\u5b66\u4e60\u7684\u7b14\u8bb0\u3002 Python\u57fa\u7840\u77e5\u8bc6\uff0c\u6765\u6e90\u4e8e\u53c2\u52a0\u7684\u5404\u79cd\u5728\u7ebf\u57fa\u7840\u8bfe\u7a0b\u6c47\u96c6\u800c\u6210\u3002 \u300a\u5229\u7528Python\u8fdb\u884c\u6570\u636e\u5206\u6790\uff08\u539f\u4e66\u7b2c2\u7248\uff09\u300b\uff08Python for Data Analysis, 2rd Edition\uff09\u5b66\u4e60\u7b14\u8bb0\uff0c\u4f5c\u8005\u7684github\u94fe\u63a5 Python For Data Analysis \u300a\u6570\u636e\u7ed3\u6784\uff08Python\u8bed\u8a00\u63cf\u8ff0\uff09\uff08\u7b2c2\u7248\uff09\u300b\uff08Fundamentals of Python: Data Structures 2 nd Edition\uff09\u5b66\u4e60\u7b14\u8bb0\u3002 \u5c0f\u7a0b\u5e8f\u6f14\u793a\uff0c\u6765\u6e90\u4e8e\u53c2\u52a0\u7684\u5404\u79cd\u5728\u7ebf\u57fa\u7840\u8bfe\u7a0b\u3002","title":"Index"},{"location":"python/#content","text":"Memo Python\u5b66\u4e60\u7684\u7b14\u8bb0\u3002 Python\u57fa\u7840\u77e5\u8bc6\uff0c\u6765\u6e90\u4e8e\u53c2\u52a0\u7684\u5404\u79cd\u5728\u7ebf\u57fa\u7840\u8bfe\u7a0b\u6c47\u96c6\u800c\u6210\u3002 \u300a\u5229\u7528Python\u8fdb\u884c\u6570\u636e\u5206\u6790\uff08\u539f\u4e66\u7b2c2\u7248\uff09\u300b\uff08Python for Data Analysis, 2rd Edition\uff09\u5b66\u4e60\u7b14\u8bb0\uff0c\u4f5c\u8005\u7684github\u94fe\u63a5 Python For Data Analysis \u300a\u6570\u636e\u7ed3\u6784\uff08Python\u8bed\u8a00\u63cf\u8ff0\uff09\uff08\u7b2c2\u7248\uff09\u300b\uff08Fundamentals of Python: Data Structures 2 nd Edition\uff09\u5b66\u4e60\u7b14\u8bb0\u3002 \u5c0f\u7a0b\u5e8f\u6f14\u793a\uff0c\u6765\u6e90\u4e8e\u53c2\u52a0\u7684\u5404\u79cd\u5728\u7ebf\u57fa\u7840\u8bfe\u7a0b\u3002","title":"Content"},{"location":"python/DataAnalysis/ch01/","text":"NumPy\u57fa\u7840 \u00b6 \u5305\u542b\u4ee5\u4e0b\u5185\u5bb9\uff1a \u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61 \u901a\u7528\u51fd\u6570 \u9762\u5411\u6570\u7ec4\u7f16\u7a0b \u4f7f\u7528\u6570\u7ec4\u8fdb\u884c\u6587\u4ef6\u8f93\u5165\u548c\u8f93\u51fa \u7ebf\u6027\u4ee3\u6570 \u4f2a\u968f\u673a\u6570\u751f\u6210 \u793a\u4f8b\uff1a\u968f\u673a\u6f2b\u6b65 \u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61ndarry \u00b6 \u522b\u540d\u7ea6\u5b9a \u00b6 import numpy as np import pandas as pd import matplotlib.pyplot as plt \u5b89\u88c5matplotlib\u4e2d\u6587\u5b57\u4f53 \u00b6 \u67e5\u770b\u5b57\u4f53\u8def\u5f84 >>> import matplotlib >>> print(matplotlib.matplotlib_fname()) /home/james/.local/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc \u4e0b\u8f7d\u4e2d\u6587\u5b57\u4f53\u3002\u7f51\u5740 https://www.fontpalace.com/font-download/SimHei/,\u5e76\u62f7\u8d1d\u5230\u4e0b\u9762\u7684\u8def\u5f84\u4e0b james@lizard:~/Downloads> cp SimHei.ttf /home/james/.local/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf/ \u67e5\u770bmatplotlib\u7684\u5b57\u4f53\u7f13\u5b58\u76ee\u5f55\u3002 >>> import matplotlib >>> print(matplotlib.get_cachedir()) /home/james/.cache/matplotlib \u5220\u9664\u8fd9\u4e2a\u76ee\u5f55 james@lizard:~> rm -rf /home/james/.cache/matplotlib \u7f16\u8f91matplotlibrc\u6587\u4ef6 /home/james/.local/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc \uff0c\u505a\u5982\u4e0b\u4fee\u6539\u3002 \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # font.family: sans-serif \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # \uff0c\u5e76\u6dfb\u52a0 SimHei \uff0c\u4fee\u6539\u540e\u4e3a font.serif: SimHei, DejaVu Serif, Bitstream Vera Serif, Computer Modern Roman, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # \uff0c\u5e76\u6dfb\u52a0 SimHei \uff0c\u4fee\u6539\u540e\u4e3a font.sans-serif: SimHei, DejaVu Sans, Bitstream Vera Sans, Computer Modern Sans Serif, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # \uff0c\u5e76\u628a True \u6539\u4e3a False \uff0c\u4fee\u6539\u540e\u4e3a axes.unicode_minus: False \u8bbe\u7f6ematplotlib\u540e\u7aef\u6e32\u67d3\u5668 \u00b6 \u5728\u4f7f\u7528matplotlib\u8f93\u51fa\u56fe\u50cf\u65f6\uff0c\u5982\u679c\u9047\u5230\u65e0\u6cd5\u663e\u793a\u56fe\u50cf\u7684\u9519\u8bef UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure\u3002 \uff0c\u53ef\u4ee5\u5c1d\u8bd5\u4e0b\u9762\u7684\u6b65\u9aa4\u89e3\u51b3\u3002 \u5b89\u88c5 python3-tk \u5305 james@lizard:~> sudo zypper in python3-tk \u6216\u8005\u901a\u8fc7 pip \u5b89\u88c5 tk \u5305 james@lizard:~> pip3 install tk Defaulting to user installation because normal site-packages is not writeable Collecting tk Downloading tk-0.1.0-py3-none-any.whl (3.9 kB) Installing collected packages: tk Successfully installed tk-0.1.0 \u4e00\u822c\u5b8c\u6210\u4e0a\u9762\u5b89\u88c5\u540e\uff0c\u7a0b\u5e8f\u5c31\u80fd\u81ea\u52a8\u663e\u793a\u56fe\u4e86\uff0c\u5982\u679c\u8fd8\u662f\u4e0d\u80fd\u663e\u793a\uff0c\u518d\u5c1d\u8bd5\u91cd\u65b0\u5b89\u88c5 matplotlib \u3002 pip3 ininstall matplotlib pip3 install matplotlib ndarray: N-\u7ef4\u6570\u7ec4\u5bf9\u8c61 \u00b6 \u4e00\u4e2andarray\u662f\u4e00\u4e2a\u901a\u7528\u7684\u591a\u7ef4\u540c\u7c7b\u6570\u636e\u5bb9\u5668\uff0c\u4e5f\u5c31\u662f\u8bf4\uff0c\u5b83\u5305\u542b\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u5747\u4e3a**\u76f8\u540c\u7c7b\u578b**\uff1b \u6bcf\u4e00\u4e2a\u6570\u7ec4\u90fd\u6709\u4e00\u4e2ashape\u5c5e\u6027\uff0c\u7528\u6765\u8868\u5f81\u6570\u7ec4\u6bcf\u4e00\u7ef4\u5ea6\u7684\u6570\u91cf\uff1b \u6bcf\u4e00\u4e2a\u6570\u7ec4\u90fd\u6709\u4e00\u4e2adtype\u5c5e\u6027\uff0c\u7528\u6765\u63cf\u8ff0\u6570\u7ec4\u7684\u6570\u636e\u7c7b\u578b\uff1b \u4e0b\u9762\u662f\u6807\u51c6\u6570\u7ec4\u7684\u751f\u6210\u51fd\u6570 array: \u5c06\u8f93\u5165\u6570\u636e\uff08\u5217\u8868\u3001\u5143\u7ec4\u3001\u6570\u7ec4\uff0c\u5176\u4ed6\u5e8f\u5217\uff09\u8f6c\u6362\u4e3andarray\uff0c\u5982\u679c\u4e0d\u663e\u5f0f\u6307\u660e\u6570\u636e\u7c7b\u578b\uff0c\u5c06\u81ea\u52a8\u63a8\u65ad\uff1b\u9ed8\u8ba4\u590d\u5236\u6240\u6709\u7684\u8f93\u5165\u6570\u636e\u3002 asarray\uff1a\u5c06\u8f93\u5165\u8f6c\u6362\u4e3andarray\uff0c\u4f46\u5982\u679c\u8f93\u5165\u5df2\u7ecf\u662fndarray\u5219\u4e0d\u518d\u590d\u5236\u3002 arange\uff1aPython\u5185\u7f6e\u51fd\u6570range\u7684\u6570\u7ec4\u7248\uff0c\u8fd4\u56de\u4e00\u4e2a\u6570\u7ec4\u3002 \u4e0b\u9762\u662f\u7528 Numpy.random() \u4e00\u4e2a\u751f\u6210\u4e00\u4e2a\u968f\u673a\u6570\u7ec4\u7684\u4f8b\u5b50\uff0c\u6ce8\u610f data01 \u7684\u7c7b\u578b\u662f'numpy.ndarray'\u3002\u53ef\u4ee5\u5728ndarray\u7c7b\u578b\u6570\u7ec4\u4e0a\u53e0\u52a0\u4e00\u4e0b\u6570\u5b66\u64cd\u4f5c\u3002 data01 = np.random.randn(2, 3) print(type(data01)) # print(data01) # [[ 0.12047302 -1.13499045 -0.39311368] # [ 1.54046881 0.01254838 -3.65090952]] print(data01 * 10) # \u7ed9data\u52a0\u4e0a\u4e00\u4e2a\u6570\u5b66\u64cd\u4f5c, \u6240\u6709\u7684\u5143\u7d20\u90fd\u540c\u65f6\u4e58\u4ee5\u4e8610 # [[ 1.20473022 -11.3499045 -3.93113676] # [ 15.40468806 0.12548383 -36.50909515]] print(data01 + data01) # \u7ed9data\u52a0\u4e0a\u4e00\u4e2a\u6570\u5b66\u64cd\u4f5c, \u6570\u7ec4\u4e2d\u7684\u5bf9\u5e94\u5143\u7d20\u8fdb\u884c\u4e86\u76f8\u52a0 # [[ 0.24094604 -2.2699809 -0.78622735] # [ 3.08093761 0.02509677 -7.30181903]] print(data01.shape) # (2, 3) print(data01.dtype) # float64 \u5f53\u8868\u8fbe\u201c\u6570\u7ec4\u201d\u3001\u201cNumPy\u6570\u7ec4\u201d\u6216\u201cndarray\u201d\u65f6\uff0c\u90fd\u8868\u793a\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1andarray\u5bf9\u8c61\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a data01 \u662f\u4e00\u4e2a\u5217\u8868\uff08list\uff09\u7c7b\u578b\uff0c\u901a\u8fc7 Numpy.array \u8f6c\u6362\u6210Numpy\u7684 ndarray \u7c7b\u578b\u3002 \u5728 np.array \u4e2d\uff0c\u9664\u975e\u663e\u5f0f\u5730\u6307\u5b9a\uff0c\u5982 np.array(data01, dtype=np.int8) \uff0c\u5426\u5219np.array\u4f1a\u81ea\u52a8\u63a8\u65ad\u751f\u6210\u6570\u7ec4\u7684\u6570\u636e\u7c7b\u578b array01.dtype \u3002 \u4f7f\u7528 astype() \u65b9\u6cd5\u663e\u5f0f\u5730\u8f6c\u6362\u6570\u7ec4\u7684\u6570\u636e\u7c7b\u578b\u3002\u4f7f\u7528 astype() \u65f6\u603b\u662f\u751f\u6210\u4e00\u4e2a*\u65b0\u7684\u6570\u7ec4*\uff0c\u5373\u4f7f\u4f60\u4f20\u5165\u7684dtype\u4e0e\u4e4b\u524d\u4e00\u6837\u3002 data02 \u662f\u4e00\u4e2a\u5d4c\u5957\u5217\u8868 [[1, 2, 3, 4], [5, 6, 7, 8]] \uff0c\u901a\u8fc7np.array()\u65b9\u6cd5\u8f6c\u6362\u6210\u591a\u7ef4\u6570\u7ec4\uff0c\u524d\u63d0\u662f\u6bcf\u4e2a\u5b50\u5217\u8868\u7684\u957f\u5ea6\u8981\u4e00\u81f4\u3002 data01 = [6, 7.5, 8, 0, 1] print(data01) # [6, 7.5, 8, 0, 1] print(type(data01)) # array01 = np.array(data01) print(\"\u77e9\u9635\u7c7b\u578b\", type(array01)) # \u77e9\u9635\u7c7b\u578b print(\"\u6837\u672c\u77e9\u9635\", array01) # \u6837\u672c\u77e9\u9635 [6. 7.5 8. 0. 1. ] print(\"\u6570\u7ec4\u7ef4\u5ea6\", array01.ndim) # \u6570\u7ec4\u7ef4\u5ea6 1 print(\"\u77e9\u9635\u5f62\u72b6\", array01.shape) # \u77e9\u9635\u5f62\u72b6 (5,) \u4e00\u884c\u4e94\u5217 print(\"\u77e9\u9635\u6570\u636e\u7c7b\u578b\", array01.dtype) # float64 data02 = [[1, 2, 3, 4], [5, 6, 7, 8]] array02 = np.array(data02) print(\"\u6837\u672c\u77e9\u9635\\n\", array02) # \u6837\u672c\u77e9\u9635 # [[1 2 3 4] # [5 6 7 8]] print(\"\u6570\u7ec4\u7ef4\u5ea6\", array02.ndim) # \u6570\u7ec4\u7ef4\u5ea6 2 print(\"\u77e9\u9635\u5f62\u72b6\", array02.shape) # \u77e9\u9635\u5f62\u72b6 (2, 4) print(\"\u77e9\u9635\u6570\u636e\u7c7b\u578b\", array02.dtype) # \u77e9\u9635\u6570\u636e\u7c7b\u578b int64 print(\"\u77e9\u96350\u8f74\u5411\u6c42\u548c\", array02.sum(axis=0)) # \u77e9\u96350\u8f74\u5411\u6c42\u548c [ 6 8 10 12] print(\"\u77e9\u96351\u8f74\u5411\u6c42\u548c\", array02.sum(axis=1)) # \u77e9\u96351\u8f74\u5411\u6c42\u548c [10 26] array03 = array02.astype(np.float64) print(array03.dtype) # float64 print(array03) # [[1. 2. 3. 4.] # [5. 6. 7. 8.]] zeros() \u65b9\u6cd5\u53ef\u4ee5\u4e00\u6b21\u6027\u521b\u9020\u51680\u6570\u7ec4\u3002 print(np.zeros(10)) # [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] ones() \u65b9\u6cd5\u53ef\u4ee5\u4e00\u6b21\u6027\u521b\u9020\u51681\u6570\u7ec4\u3002\u6ce8\u610f\uff0c\u4f20\u53c2shape\u662f\u4e00\u4e2a\u5143\u7ec4 (3, 5) \u3002 print(np.ones((3, 5))) # [[1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.]] empty() \u65b9\u6cd5\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u6ca1\u6709\u521d\u59cb\u5316\u6570\u503c\u7684\u6570\u7ec4\u3002\u4f46\u662f\uff0c\u4f7f\u7528np.empty\u6765\u751f\u6210\u4e00\u4e2a\u51680\u6570\u7ec4\uff0c\u5e76\u4e0d\u53ef\u9760\uff0c\u6709\u4e9b\u65f6\u5019\u5b83\u53ef\u80fd\u4f1a\u8fd4\u56de\u672a\u521d\u59cb\u5316\u7684\u5783\u573e\u6570\u503c print(np.empty((2, 3, 2))) # [[[2.30116964e-316 0.00000000e+000] # [2.10077583e-312 6.79038654e-313] # [2.22809558e-312 2.14321575e-312]] # # [[2.35541533e-312 6.79038654e-313] # [2.22809558e-312 2.14321575e-312] # [2.46151512e-312 2.41907520e-312]]] NumPy\u8f74 \u00b6 \u4e00\u53e5\u8bdd\u603b\u7ed3\uff1a\u5c06NumPy\u8f74\u89c6\u4e3a\u6211\u4eec\u53ef\u4ee5\u6267\u884c\u64cd\u4f5c\u7684\u65b9\u5411\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a arr_1 = np.array([[1, 1, 1], [1, 1, 1]]) arr_2 = np.array([[9, 9, 9], [9, 9, 9]]) print(arr_1) # [[1 1 1] # [1 1 1]] print(arr_2) # [[9 9 9] # [9 9 9]] \u6cbf0\u8f74\u5408\u5e76\u7684\u601d\u8def\u662f\uff0c\u4e24\u4e2a\u6570\u7ec4\u6cbf0\u8f74\u65b9\u5411\uff0c\u54110\u8f74\u201c\u584c\u7f29\u201d\uff08collapse\uff09\u3002 result = np.concatenate([arr_1, arr_2], axis=0) print(result) # [[1 1 1] # [1 1 1] # [9 9 9] # [9 9 9]] \u6cbf1\u8f74\u5408\u5e76\u7684\u601d\u8def\u662f\uff0c\u4e24\u4e2a\u6570\u7ec4\u6cbf1\u8f74\u65b9\u5411\uff0c\u54111\u8f74\u201c\u584c\u7f29\u201d result = np.concatenate([arr_1, arr_2], axis=1) print(result) # [[1 1 1 9 9 9] # [1 1 1 9 9 9]] \u6211\u4eec\u6765\u770bNumPy\u7684\u4e09\u7ef4\u6570\u7ec4\u3002 array1 = np.arange(36).reshape((3, 3, 4)) print(array1) # [[[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] # # [[12 13 14 15] # [16 17 18 19] # [20 21 22 23]] # # [[24 25 26 27] # [28 29 30 31] # [32 33 34 35]]] \u8fd9\u6837\u770b\u4f1a\u5bb9\u6613\u7406\u89e3\u4e00\u4e9b\uff0c0\u8f74\u67093\u884c\uff0c1\u8f74\u67093\u5217\uff0c2\u8f74\u67094\u4e2a\u5143\u7d20\uff1a [[[ 0 1 2 3], [ 4 5 6 7], [ 8 9 10 11]] [[12 13 14 15], [16 17 18 19], [20 21 22 23]] [[24 25 26 27], [28 29 30 31], [32 33 34 35]]] \u8f93\u51fa\uff1a\u8f740\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f741\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f742\u7d22\u5f15\u53f7\uff1a\u5168\u90e8 print(array1[0, 0, :]) # [0 1 2 3] \u8f93\u51fa\uff1a\u8f740\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f741\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f742\u7d22\u5f15\u53f7\uff1a1 print(array1[0, 0, 1]) # 1 NumPy\u6570\u7ec4\u7b97\u672f \u00b6 \u4e00\u4e2a**\u6807\u91cf**\u5c31\u662f\u4e00\u4e2a\u5355\u72ec\u7684\u6570\u3002\u4e00\u4e2a\u5411\u91cf\u5c31\u662f\u4e00\u5217\u6570\uff0c\u8fd9\u4e9b\u6570\u662f\u6709\u5e8f\u6392\u5217\u7684\u3002 \u77e9\u9635\u662f\u4e8c\u7ef4\u6570\u7ec4\uff0c\u5176\u4e2d\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u88ab\u4e24\u4e2a\u7d22\u5f15\u800c\u975e\u4e00\u4e2a\u6240\u786e\u5b9a\u3002 \u51e0\u4f55\u4ee3\u6570\u4e2d\u5b9a\u4e49\u7684**\u5f20\u91cf**\u662f\u57fa\u4e8e\u5411\u91cf\u548c\u77e9\u9635\u7684\u63a8\u5e7f\uff0c\u6211\u4eec\u53ef\u4ee5**\u5c06\u6807\u91cf\u89c6\u4e3a\u96f6\u9636\u5f20\u91cf**\uff0c \u77e2\u91cf**\u89c6\u4e3a\u4e00\u9636\u5f20\u91cf\uff0c\u90a3\u4e48**\u77e9\u9635\u5c31\u662f\u4e8c\u9636\u5f20\u91cf \u3002 \u5e26\u6709\u6807\u91cf\u8ba1\u7b97\u7684\u7b97\u672f\u64cd\u4f5c\uff0c\u4f1a\u628a\u8ba1\u7b97\u53c2\u6570\u4f20\u9012\u7ed9\u6570\u7ec4\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u3002 \u540c\u5c3a\u5bf8\u6570\u7ec4\u4e4b\u95f4\u7684\u6bd4\u8f83 array04 == array04 \uff0c\u4f1a\u4ea7\u751f\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4 \u4e0d\u540c\u5c3a\u5bf8\u7684\u6570\u7ec4\u95f4\u7684\u64cd\u4f5c\uff0c\u5c06\u4f1a\u7528\u5230 \u5e7f\u64ad\u7279\u6027\uff08broadcasting\uff09 \u3002 array04 = np.array([ [1, 2, 3, 4, 5], [3, 4, 5, 6, 7], [5, 6, 7, 8, 9] ], dtype=int) print(array04 + array04) # [[ 2 4 6 8 10] # [ 6 8 10 12 14] # [10 12 14 16 18]] print(array04 - array04) # [[0 0 0 0 0] # [0 0 0 0 0] # [0 0 0 0 0]] print(array04 * array04) # [[ 1 4 9 16 25] # [ 9 16 25 36 49] # [25 36 49 64 81]] print(array04 / array04) # [[1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.]] print(1 / array04) # [[1. 0.5 0.33333333 0.25 0.2 ] # [0.33333333 0.25 0.2 0.16666667 0.14285714] # [0.2 0.16666667 0.14285714 0.125 0.11111111]] print(array04 == array04) # [[ True True True True True] # [ True True True True True] # [ True True True True True]] \u57fa\u7840\u7d22\u5f15\u4e0e\u5207\u7247 \u00b6 ndarray\u5bf9\u8c61\u7684\u5185\u5bb9\u53ef\u4ee5\u901a\u8fc7\u7d22\u5f15\uff08indexing\uff09\u6216\u5207\u7247\uff08slicing\uff09\u6765\u8bbf\u95ee\u548c\u4fee\u6539\uff0cndarray\u5bf9\u8c61\u4e2d\u7684\u5143\u7d20\u7d22\u5f15\u4ece\u96f6\u5f00\u59cb\u3002 \u6709\u4e09\u79cd\u53ef\u7528\u7684\u7d22\u5f15\u65b9\u6cd5\uff1a\u5b57\u6bb5\u8bbf\u95ee\uff0c\u57fa\u672c\u5207\u7247\u548c\u9ad8\u7ea7\u7d22\u5f15\u3002 \u7d22\u5f15\uff08indexing\uff09\uff1a\u83b7\u53d6\u6570\u7ec4\u4e2d\u7279\u5b9a\u4f4d\u7f6e\u5143\u7d20\u7684\u8fc7\u7a0b\u3002 \u5207\u7247\uff08slicing\uff09\uff1a\u83b7\u53d6\u6570\u7ec4\u5143\u7d20\u5b50\u96c6\u7684\u8fc7\u7a0b\u3002\u6570\u7ec4\u7684\u5207\u7247\u662f\u539f\u6570\u7ec4\u7684\u89c6\u56fe\u3002\u8fd9\u610f\u5473\u7740\u4efb\u4f55**\u5bf9\u4e8e\u89c6\u56fe\u7684\u4fee\u6539\u90fd\u4f1a\u53cd\u6620\u5230\u539f\u6570\u7ec4\u4e0a**\u3002\u6570\u7ec4\u7684\u5207\u7247, \u8fd4\u56de\u7684\u5bf9\u8c61\u662f\u964d\u4f4e\u4e00\u4e2a\u7ef4\u5ea6\u7684\u6570\u7ec4\u3002 \u4e00\u7ef4\u6570\u7ec4\u7684\u7d22\u5f15\u548c\u5207\u7247\uff1a\u4e0ePython\u7684\u5217\u8868\u7c7b\u4f3c\uff1a a[n] \uff1a\u8fd4\u56de\u7b2c n+1 \u4e2a\u5143\u7d20\u3002\u5982\u679c n \u4e3a\u8d1f\u6570\uff0c\u5219\u8fd4\u56de\u5012\u6570\u7b2c n \u4e2a\u5143\u7d20\u3002 a[n:m:k] \uff1a\u8d77\u59cb\u7f16\u53f7 n \uff0c\u7ec8\u6b62\u7f16\u53f7 m \uff0c\u6b65\u957f k \uff0c\u7528\u5192\u53f7\u5206\u5272\u3002 \u9075\u5faa\u5de6\u95ed\u53f3\u5f00\u7684\u539f\u5219 \uff0c\u5373 [n, m) \u3002\u5982\u679c n \u4e3a\u7a7a\uff0c\u5373 n = 0 \uff1b\u5982\u679c m \u4e3a\u7a7a\uff0c\u5373 m = len(a) \u3002 \u591a\u7ef4\u6570\u7ec4\u7684\u7d22\u5f15\u548c\u5207\u7247\uff1a a[n,m,k,...] \uff1a\u6bcf\u4e2a\u7ef4\u5ea6\u4e00\u4e2a\u7d22\u5f15\u503c\uff0c\u6700\u5916\u5c42\u5217\u8868\uff08list\uff09\u4e2d\u7b2c n \u4e2a\u5143\u7d20\uff0c\u6b21\u5916\u5c42\u5217\u8868\uff08list\uff09\u4e2d\u7b2c m \u4e2a\u5143\u7d20\uff0c\u4ee5\u6b64\u7c7b\u63a8\u3002\u5982\u679c n \u4e3a\u8d1f\u6570\uff0c\u5219\u8fd4\u56de\u5012\u6570\u7b2c n \u4e2a\u5143\u7d20\u3002 a[n1:m1:k1,n2:m2:k2,n3:m3:k3,...] \uff1a\u6bcf\u4e2a\u7ef4\u5ea6\u7684\u5207\u7247\u65b9\u6cd5\u4e0e\u4e00\u7ef4\u6570\u7ec4\u76f8\u540c\u3002\u987a\u5e8f\u4e3a\u4ece\u5916\u5230\u5185\u3002 array05 = np.arange(10) print(array05) # [0 1 2 3 4 5 6 7 8 9] # \u4ece\u7d22\u5f15\u503c5\u5f00\u59cb\u5230\u7d22\u5f15\u503c7\u7684\u4e00\u4e2a\u5207\u7247\u3002 print(array05[5:8]) # [5 6 7] array06 = array05[5:8] # \u4f20\u5165\u4e00\u4e2a\u6570\u503c\u7ed9\u6570\u7ec4\u7684\u5207\u7247\uff0c\u6570\u503c\u88ab\u4f20\u9012\u7ed9\u4e86\u6574\u4e2a\u5207\u7247\u3002\u4e0d\u5199\u5207\u7247\u503c\u7684[:]\u5c06\u4f1a\u5f15\u7528\u6570\u7ec4\u7684\u6240\u6709\u503c array06[:] = 12 print(array06) # [12 12 12] # \u5207\u7247\u7684\u4fee\u6539\u4f1a\u53cd\u6620\u5230\u539f\u6570\u7ec4\u4e0a print(array05) # [ 0 1 2 3 4 12 12 12 8 9] # \u8f93\u51fa3\u7ef4\u77e9\u9635\uff0c3\u884c3\u5217\uff0c\u51719\u4e2a\u5143\u7d20\uff0c\u6bcf\u4e2a\u5143\u7d20\u662f\u4e00\u4e2a\u542b3\u4e2a\u5143\u7d20\u7684\u5217\u8868 array07 = np.array([ [[0, 1, 2], [3, 4, 5], [6, 7, 8]], [[9, 0, 1], [2, 3, 4], [5, 6, 7]], [[8, 9, 0], [1, 2, 3], [4, 5, 6]], ]) # \u8f93\u51fa3\u7ef4\u77e9\u9635\uff0c\u663e\u793a\u539f\u77e9\u9635\u7684\u7b2c1\uff0c2\u884c\u76842\uff0c3\u5217\u5143\u7d20\uff0c\u4e0d\u8981\u628a\u7d22\u5f15\u53f7\u548c\u8fd9\u91cc\u7684\u8868\u8ff0\u884c\u53f7\u6df7\u6dc6\u3002 print(array07[:2, 1:]) # [[[3 4 5] [6 7 8]] # [[2 3 4] [5 6 7]]] print(array07[:2, 1:].shape) # (2, 2, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c3\u884c print(array07[2]) # [[8 9 0] [1 2 3] [4 5 6]] print(array07[2].shape) # (3, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c3\u884c print(array07[2, :]) # [[8 9 0] [1 2 3] [4 5 6]] print(array07[2, :].shape) # (3, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c3\u884c\uff08\u53ea\u6709\u4e09\u884c\uff0c\u6240\u4ee5[2:, :]\u7b49\u540c\u4e8e[2, :]\uff09 print(array07[2:, :]) # [[[8 9 0] [1 2 3] [4 5 6]]] print(array07[2:, :].shape) # (1, 3, 3) # \u8f93\u51fa\u539f\u77e9\u9635\u76841\uff0c2\u5217 print(array07[:, :2]) # [[[0 1 2] [3 4 5]] # [[9 0 1] [2 3 4]] # [[8 9 0] [1 2 3]]] print(array07[:, :2].shape) # (3, 2, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u524d2\u4e2a\u5143\u7d20 print(array07[1, :2]) # [[9 0 1] [2 3 4]] print(array07[1, :2].shape) # (2, 3) # \u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u524d2\u4e2a\u5143\u7d20 print(array07[1:2, :2]) # [[[9 0 1] [2 3 4]]] print(array07[1:2, :2].shape) # (1, 2, 3) # \u5c06\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u8d4b\u503c\u7ed9\u53d8\u91cf old_value = array07[2].copy() print(old_value) # [[8 9 0] [1 2 3] [4 5 6]] # \u4fee\u6539\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u7684\u503c\uff0c\u6807\u91cf\u548c\u6570\u7ec4\u90fd\u53ef\u4ee5\u4f20\u9012\u7ed9 array07[2] array07[2] = 25 print(array07) # [[[ 0 1 2] [ 3 4 5] [ 6 7 8]] # [[ 9 0 1] [ 2 3 4] [ 5 6 7]] # [[25 25 25] [25 25 25] [25 25 25]]] # \u5c06\u53d8\u91cf\u503c\u8d4b\u503c\u7ed9\u539f\u77e9\u9635\u7684\u7b2c2\u884c array07[2] = old_value print(array07) # [[[0 1 2] [3 4 5] [6 7 8]] # [[9 0 1] [2 3 4] [5 6 7]] # [[8 9 0] [1 2 3] [4 5 6]]] \u5e03\u5c14\u7d22\u5f15 \u00b6 \u5e03\u5c14\u503c\u7d22\u5f15\uff08Boolean indexing\uff09\u662f\u901a\u8fc7\u4e00\u4e2a\u5e03\u5c14\u6570\u7ec4\u6765\u7d22\u5f15\u76ee\u6807\u6570\u7ec4\uff0c\u4ee5\u6b64\u627e\u51fa\u4e0e\u5e03\u5c14\u6570\u7ec4\u4e2d\u503c\u4e3aTrue\u7684\u5bf9\u5e94\u7684\u76ee\u6807\u6570\u7ec4\u4e2d\u7684\u6570\u636e\u3002\u5e03\u5c14\u6570\u7ec4\u7684\u957f\u5ea6\u5fc5\u987b\u4e0e\u76ee\u6807\u6570\u7ec4\u5bf9\u5e94\u7684\u8f74\u7684\u957f\u5ea6\u4e00\u81f4\u3002 \u4f7f\u7528\u5e03\u5c14\u503c\u7d22\u5f15\uff08Boolean indexing\uff09\u9009\u62e9\u6570\u636e\u65f6\uff0c\u603b\u662f\u751f\u6210\u6570\u636e\u7684\u62f7\u8d1d\uff0c\u5373\u4f7f\u8fd4\u56de\u7684\u6570\u7ec4\u5e76\u6ca1\u6709\u4efb\u4f55\u53d8\u5316\u3002 \u5047\u8bbe\u6211\u4eec\u7684\u6570\u636e\u90fd\u5728\u6570\u7ec4\u4e2d\uff0c\u5e76\u4e14\u6570\u7ec4\u4e2d\u7684\u6570\u636e\u662f\u4e00\u4e9b\u5b58\u5728\u91cd\u590d\u7684\u4eba\u540d\u3002\u7528randn\u51fd\u6570\u751f\u6210\u4e00\u4e9b\u6807\u51c6\u6b63\u6001(standard normal)\u5206\u5e03\u7684\u6570\u636e\u3002\u5047\u8bbe\u6bcf\u4e2a\u4eba\u540d\u90fd\u548cdata\u6570\u7ec4\u4e2d\u7684\u4e00\u884c\u76f8\u5bf9\u5e94\uff0c\u5e76\u4e14\u6211\u4eec\u60f3\u8981\u9009\u4e2d\u6240\u6709\u2019Bob\u2019\u5bf9\u5e94\u7684\u884c\u3002 names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype=' # \u56fe\u50cf\u6807\u9898 plt.title(\"$\\sqrt{x^2 + y^2}$ \u8ba1\u7b97\u503c\u7684\u7f51\u683c\u56fe\") # \u8f93\u51fa\u56fe\u50cf plt.show() \u8f93\u51fa\u56fe\u50cf\u4e3a\uff1a \u901a\u8fc7\u6761\u4ef6\u903b\u8f91\u64cd\u4f5c\u6570\u7ec4 \u00b6 numpy.where \u51fd\u6570\u662f\u4e09\u5143\u8868\u8fbe\u5f0f x if condition else y \u7684\u5411\u91cf\u5316\u7248\u672c\u3002 np.where \u7684\u7b2c\u4e8c\u4e2a\u548c\u7b2c\u4e09\u4e2a\u53c2\u6570\u5e76\u4e0d\u9700\u8981\u662f\u6570\u7ec4\uff0c\u5b83\u4eec\u53ef\u4ee5\u662f\u6807\u91cf\u3002 np.where \u5728\u6570\u636e\u5206\u6790\u4e2d\u7684\u4e00\u4e2a\u5178\u578b\u7528\u6cd5\u662f\u6839\u636e\u4e00\u4e2a\u6570\u7ec4\u6765\u751f\u6210\u4e00\u4e2a\u65b0\u7684\u6570\u7ec4\u3002 \u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4\u548c\u4e24\u4e2a\u6570\u503c\u6570\u7ec4\u3002\u5047\u8bbe cond \u4e2d\u7684\u5143\u7d20\u4e3a True \u65f6\uff0c\u6211\u4eec\u53d6 xarr \u4e2d\u7684\u5bf9\u5e94\u5143\u7d20\u503c\uff0c\u5426\u5219\u53d6 yarr \u4e2d\u7684\u5143\u7d20\u3002 xarray = np.array([1.1, 1.2, 1.3, 1.4, 1.5]) yarray = np.array([2.1, 2.2, 2.3, 2.4, 2.5]) cond = np.array([True, False, True, True, False]) \u901a\u8fc7\u5217\u8868\u63a8\u5bfc\u5f0f\u6765\u5b9e\u73b0\u4e0a\u8ff0\u9700\u6c42\u3002 \u7f3a\u70b9: \u9996\u5148\uff0c\u5982\u679c\u6570\u7ec4\u5f88\u5927\u7684\u8bdd\uff0c\u901f\u5ea6\u4f1a\u5f88\u6162\uff08\u56e0\u4e3a\u6240\u6709\u7684\u5de5\u4f5c\u90fd\u662f\u901a\u8fc7\u89e3\u91ca\u5668\u6765\u89e3\u91caPython\u4ee3\u7801\u5b8c\u6210\uff09\u3002 \u5176\u6b21\uff0c\u5f53\u6570\u7ec4\u662f\u591a\u7ef4\u65f6\uff0c\u5c31\u65e0\u6cd5\u51d1\u6548\u4e86\u3002 # \u901a\u8fc7\u5217\u8868\u63a8\u5bfc\u5f0f\u6765\u5b9e\u73b0 result = [(x if c else y) for x, y, c in zip(xarray, yarray, cond)] print(result) # [1.1, 2.2, 1.3, 1.4, 2.5] \u901a\u8fc7 np.where \u6765\u5b9e\u73b0\u4e0a\u8ff0\u9700\u6c42\u3002 result = np.where(cond, xarray, yarray) print(result) # [1.1 2.2 1.3 1.4 2.5] \u5047\u8bbe\u6709\u4e00\u4e2a\u968f\u673a\u751f\u6210\u7684\u77e9\u9635\u6570\u636e\uff0c\u4e0b\u9762\u4f7f\u7528np.where\u5b9e\u73b0\u66ff\u6362\u3002 array = np.random.randn(4, 4) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) print(\"\u77e9\u9635\u5143\u7d20\u662f\u5426\u5927\u4e8e0 \\n\", array > 0) # \u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2\uff0c\u5c06\u6240\u6709\u7684\u8d1f\u503c\u66ff\u6362\u4e3a-2 result03 = np.where(array > 0, 2, -2) print(\"\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2\uff0c\u5c06\u6240\u6709\u7684\u8d1f\u503c\u66ff\u6362\u4e3a-2 \\n\", result03) # \u4ec5\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2 result04 = np.where(array > 0, 2, array) print(\"\u4ec5\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2 \\n\", result04) # \u6837\u672c\u77e9\u9635 # [[-0.57177422 -0.34917512 2.20268075 1.99959296] # [ 0.67966599 2.67915099 -0.40528454 -0.80339907] # [-0.74406888 2.33802717 -0.74582936 0.59347128] # [ 0.68624473 0.65953112 -0.40871415 -0.68698878]] # \u77e9\u9635\u5143\u7d20\u662f\u5426\u5927\u4e8e0 # [[False False True True] # [ True True False False] # [False True False True] # [ True True False False]] # \u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2\uff0c\u5c06\u6240\u6709\u7684\u8d1f\u503c\u66ff\u6362\u4e3a-2 # [[-2 -2 2 2] # [ 2 2 -2 -2] # [-2 2 -2 2] # [ 2 2 -2 -2]] # \u4ec5\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2 # [[-0.57177422 -0.34917512 2. 2. ] # [ 2. 2. -0.40528454 -0.80339907] # [-0.74406888 2. -0.74582936 2. ] # [ 2. 2. -0.40871415 -0.68698878]] \u6570\u5b66\u548c\u7edf\u8ba1\u65b9\u6cd5 \u00b6 NumPy\u6709\u4e00\u4e9b\u4e13\u95e8\u7684\u6570\u5b66\u51fd\u6570\uff0c\u7528\u6765\u8ba1\u7b97\u6574\u4e2a\u6570\u7ec4\u7edf\u8ba1\u503c\u6216\u8f74\u5411\u6570\u636e\u7684\u8ba1\u7b97\u3002\u4f8b\u5982\uff0c\u805a\u5408\u51fd\u6570\uff08\u901a\u5e38\u4e5f\u53eb\u7f29\u51cf\u51fd\u6570\uff09\uff0c\u5982sum\u3001mean\u548cstd\uff08\u6807\u51c6\u5dee\uff09\u3002 \u65e2\u53ef\u4ee5\u76f4\u63a5\u8c03\u7528\u6570\u7ec4\u5b9e\u4f8b\u7684\u65b9\u6cd5\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u9876\u5c42\u7684NumPy\u51fd\u6570\u3002 \u4e3e\u4f8b\uff1a\u751f\u6210\u4e00\u4e9b\u6b63\u6001\u5206\u5e03\u7684\u968f\u673a\u6570\uff0c\u8ba1\u7b97\u90e8\u5206\u805a\u5408\u7edf\u8ba1\u6570\u636e\u3002 \u8fd9\u91cc\u518d\u5bf9\u8f74\u5411\u505a\u4e2a\u89e3\u91ca\uff0c np.random.randn(5, 4) \u4ea7\u751f\u7684\u4e8c\u7ef4\u6570\u7ec4\u662f\uff1a0\u8f74\u54115\u4e2a\u5143\u7d20, 1\u8f74\u54114\u4e2a\u5143\u7d20\u3002 # \u751f\u62102\u8f74\u6570\u7ec4 array = np.random.randn(5, 4) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) print(\"\u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c\", array.mean()) print(\"\u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c\", np.mean(array)) print(\"\u77e9\u9635\u5143\u7d20\u548c\", array.sum()) print(\"\u77e9\u9635\u5143\u7d20\u548c\", np.sum(array)) print(\"0\u8f74\u5411\u7684\u7d2f\u548c\", array.sum(axis=0)) print(\"1\u8f74\u5411\u7684\u7d2f\u548c\", array.sum(axis=1)) print(\"1\u8f74\u5411\u7684\u5e73\u5747\u503c\", array.mean(axis=1)) # \u6837\u672c\u77e9\u9635 shape=(5, 4) 0\u8f74\u54115\u4e2a\u5143\u7d20, 1\u8f74\u54114\u4e2a\u5143\u7d20 # [[ 0.32532911 -0.00177984 -1.59432632 1.58375133] # [ 1.48921763 0.25202456 0.44076148 -1.02277289] # [-0.73490219 0.19197171 -0.22374362 0.52610852] # [-1.03531076 1.0595528 -0.11566501 0.34063544] # [-0.2122241 -0.81348187 1.70989712 -0.00732696]] # \u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c 0.10788580775057008 # \u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c 0.10788580775057008 # \u77e9\u9635\u5143\u7d20\u548c 2.1577161550114017 # \u77e9\u9635\u5143\u7d20\u548c 2.1577161550114017 # 0\u8f74\u5411\u7684\u7d2f\u548c [-0.16789031 0.68828737 0.21692365 1.42039545] # 1\u8f74\u5411\u7684\u7d2f\u548c [ 0.31297429 1.15923078 -0.24056558 0.24921247 0.67686419] # 1\u8f74\u5411\u7684\u5e73\u5747\u503c [ 0.07824357 0.28980769 -0.06014139 0.06230312 0.16921605] \u4e0b\u9762\u5217\u4e3e\u4e86\u5e38\u7528\u7684\u57fa\u7840\u6570\u7ec4\u7edf\u8ba1\u65b9\u6cd5\u3002 array = np.array([ [1, 2, 3, 4, 5], [3, 4, 5, 6, 7], [5, 6, 7, 8, 9] ], dtype=int) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) print(\"\u8f74\u5411\u6c42\u548c\", array.sum()) print(\"\u8f74\u5411\u6c42\u548c\", array.sum(axis=0)) print(\"\u6570\u5b66\u5e73\u5747\", array.mean()) print(\"\u8f74\u5411\u6570\u5b66\u5e73\u5747\", array.mean(axis=0)) print(\"\u6807\u51c6\u5dee\", array.std(), \"\u65b9\u5dee\", array.var()) print(\"\u8f74\u5411\u6807\u51c6\u5dee\", array.std(axis=0), \"\u8f74\u5411\u65b9\u5dee\", array.var(axis=0)) print(\"\u6700\u5c0f\u503c\", array.min(), \"\u6700\u5927\u503c\", array.max()) print(\"\u8f74\u5411\u6700\u5c0f\u503c\", array.min(axis=0), \"\u8f74\u5411\u6700\u5927\u503c\", array.max(axis=0)) print(\"\u6700\u5c0f\u503c\u4f4d\u7f6e\", array.argmin(), \"\u6700\u5927\u503c\u4f4d\u7f6e\", array.argmax()) print(\"\u8f74\u5411\u6700\u5c0f\u503c\u4f4d\u7f6e\", array.argmin(axis=0), \"\u8f74\u5411\u6700\u5927\u503c\u4f4d\u7f6e\", array.argmax(axis=0)) print(\"\u7d2f\u79ef\u548c \\n\", array.cumsum()) print(\"\u8f74\u5411\u7d2f\u79ef\u548c \\n\", array.cumsum(axis=1)) print(\"\u7d2f\u79ef\u4e58\u79ef \\n\", array.cumprod()) print(\"\u8f74\u5411\u7d2f\u79ef\u4e58\u79ef \\n\", array.cumprod(axis=1)) # \u6837\u672c\u77e9\u9635 # [[1 2 3 4 5] # [3 4 5 6 7] # [5 6 7 8 9]] # \u8f74\u5411\u6c42\u548c 75 # \u8f74\u5411\u6c42\u548c [ 9 12 15 18 21] # \u6570\u5b66\u5e73\u5747 5.0 # \u8f74\u5411\u6570\u5b66\u5e73\u5747 [3. 4. 5. 6. 7.] # \u6807\u51c6\u5dee 2.160246899469287 \u65b9\u5dee 4.666666666666667 # \u8f74\u5411\u6807\u51c6\u5dee [1.63299316 1.63299316 1.63299316 1.63299316 1.63299316] \u8f74\u5411\u65b9\u5dee [2.66666667 2.66666667 2.66666667 2.66666667 2.66666667] # \u6700\u5c0f\u503c 1 \u6700\u5927\u503c 9 # \u8f74\u5411\u6700\u5c0f\u503c [1 2 3 4 5] \u8f74\u5411\u6700\u5927\u503c [5 6 7 8 9] # \u6700\u5c0f\u503c\u4f4d\u7f6e 0 \u6700\u5927\u503c\u4f4d\u7f6e 14 # \u8f74\u5411\u6700\u5c0f\u503c\u4f4d\u7f6e [0 0 0 0 0] \u8f74\u5411\u6700\u5927\u503c\u4f4d\u7f6e [2 2 2 2 2] # \u7d2f\u79ef\u548c # [ 1 3 6 10 15 18 22 27 33 40 45 51 58 66 75] # \u8f74\u5411\u7d2f\u79ef\u548c # [[ 1 3 6 10 15] # [ 3 7 12 18 25] # [ 5 11 18 26 35]] # \u7d2f\u79ef\u4e58\u79ef # [ 1 2 6 24 120 360 # 1440 7200 43200 302400 1512000 9072000 # 63504000 508032000 4572288000] # \u8f74\u5411\u7d2f\u79ef\u4e58\u79ef # [[ 1 2 6 24 120] # [ 3 12 60 360 2520] # [ 5 30 210 1680 15120]] \u5e03\u5c14\u503c\u6570\u7ec4(Boolean Array)\u7684\u65b9\u6cd5 \u00b6 \u5e03\u5c14\u503c\u6570\u7ec4\uff0c\u6709\u4e24\u4e2a\u975e\u5e38\u6709\u7528\u7684\u65b9\u6cd5any\u548call\u3002 * any\u68c0\u67e5\u6570\u7ec4\u4e2d\u662f\u5426\u81f3\u5c11\u6709\u4e00\u4e2aTrue\uff0c * all\u68c0\u67e5\u662f\u5426\u6bcf\u4e2a\u503c\u90fd\u662fTrue bools = np.array([False, False, True, False]) print(bools.any()) # True print(bools.all()) # False \u4e0b\u9762\u662f\u4e00\u4e2a\u8fd0\u7528\u5e03\u5c14\u503c\u6570\u7ec4\uff08Boolean Array\uff09\u8fdb\u884c\u6c42\u548c\u7684\u4e00\u4e2a\u4f8b\u5b50\uff0c\u5176\u4e2d (array > 0) \u672c\u8eab\u662f\u4e00\u4e2a\u5e03\u5c14\u578b\u7684\u6570\u7ec4\u3002 array = np.random.randn(100) result = (array > 0).sum() # \u8ba1\u7b97\u6b63\u503c\u7684\u4e2a\u6570 print(result) # 59 \u4e0b\u9762\u662f\u8fd0\u7528\u5e03\u5c14\u503c\u6570\u7ec4\u7684\u751f\u6210\u65b0\u6570\u7ec4\u7684\u4f8b\u5b50\u3002 arr = [[8, 9, 10, 11], [0, 1, 2, 3], [4, 5, 6, 7]] arr = np.array(arr) print(arr.shape) # (3, 4) print(arr) # [[ 8 9 10 11] # [ 0 1 2 3] # [ 4 5 6 7]] idx = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]] idx = np.array(idx) print(idx.shape) # (3, 4) print(idx) # [[1 0 0 0] # [0 1 0 0] # [0 0 1 0]] result = arr[idx] # print(result.shape) # (3, 4, 4) print(result) # [[[ 0 1 2 3] # [ 8 9 10 11] # [ 8 9 10 11] # [ 8 9 10 11]] # [[ 8 9 10 11] # [ 0 1 2 3] # [ 8 9 10 11] # [ 8 9 10 11]] # [[ 8 9 10 11] # [ 8 9 10 11] # [ 0 1 2 3] # [ 8 9 10 11]]] result = arr[idx == 1] print(result.shape) print(result) # [8 1 6] \u6392\u5e8f \u00b6 \u548cPython\u7684\u5185\u5efa\u5217\u8868\u7c7b\u578b\u76f8\u4f3c\uff0cNumPy\u6570\u7ec4\u53ef\u4ee5\u4f7f\u7528sort\u65b9\u6cd5\u6309\u4f4d\u7f6e\u6392\u5e8f\u3002 \u9876\u5c42\u7684np.sort\u65b9\u6cd5\u8fd4\u56de\u7684\u662f\u5df2\u7ecf\u6392\u5e8f\u597d\u7684\u6570\u7ec4*\u62f7\u8d1d*\uff0c\u800c\u4e0d\u662f\u5bf9\u539f\u6570\u7ec4\u6309\u4f4d\u7f6e\u6392\u5e8f\u3002 array = np.random.randn(6) print(\"\u6837\u672c\u77e9\u9635\", array) array.sort() print(\"\u6392\u5e8f\u540e\u77e9\u9635\", array) # \u6837\u672c\u77e9\u9635 [-0.03119521 0.01839556 0.79238537 -2.46622775 0.62522211 0.22430846] # \u6392\u5e8f\u540e\u77e9\u9635 [-2.46622775 -0.03119521 0.01839556 0.22430846 0.62522211 0.79238537] \u591a\u7ef4\u6570\u7ec4\u4e2d\u6839\u636e\u4f20\u9012\u7684axis\u503c\uff0c\u6cbf\u7740\u8f74\u5411\u5bf9\u6bcf\u4e2a\u4e00\u7ef4\u6570\u636e\u6bb5\u8fdb\u884c\u6392\u5e8f\u3002 array = np.random.randn(5, 3) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) array.sort(1) print(\"\u5bf91\u8f74\u6392\u5e8f\u540e\u77e9\u9635 \\n\", array) # \u6837\u672c\u77e9\u9635 # [[-0.88057833 0.30160954 -2.08788148] # [ 0.27969618 0.62923028 -0.58157581] # [-1.87194465 -1.1102104 1.09589605] # [ 0.1467938 -1.01558304 -0.25905165] # [-0.17294279 0.62369511 0.17947059]] # \u5bf91\u8f74\u6392\u5e8f\u540e\u77e9\u9635 # [[-2.08788148 -0.88057833 0.30160954] # [-0.58157581 0.27969618 0.62923028] # [-1.87194465 -1.1102104 1.09589605] # [-1.01558304 -0.25905165 0.1467938 ] # [-0.17294279 0.17947059 0.62369511]] \u552f\u4e00\u503c\u4e0e\u5176\u4ed6\u96c6\u5408\u903b\u8f91 \u00b6 NumPy\u5305\u542b\u4e00\u4e9b\u9488\u5bf9\u4e00\u7ef4 ndarray \u6570\u7ec4\u7684\u57fa\u7840\u96c6\u5408\u64cd\u4f5c\u3002 np.unique(x, y) \u8ba1\u7b97x\u7684\u552f\u4e00\u503c\uff0c\u5e76\u6392\u5e8f\u3002 names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe']) result = np.unique(names) # NumPy\u5b9e\u73b0 print(result) # ['Bob' 'Joe' 'Will'] result = sorted(set(names)) # \u7eafPython\u5b9e\u73b0 print(result) # ['Bob' 'Joe' 'Will'] inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) result = np.unique(inits) print(result) # [1 2 3 5] np.in1d(x, y) \u8ba1\u7b97x\u4e2d\u7684\u5143\u7d20\u662f\u5426\u5305\u542b\u5728y\u4e2d\uff0c\u5e76\u8fd4\u56de\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.in1d(inits, [3, 4, 5])) # [ True True True False False False False True True] np.intersect1d(x, y) \uff0c\u8ba1\u7b97x\u548cy\u7684\u4ea4\u96c6\uff0c\u5e76\u6392\u5e8f\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.intersect1d(inits, [3, 4, 5])) # [3 5] np.union1d(x, y) \u8ba1\u7b97x\u548cy\u7684\u5e76\u96c6\uff0c\u5e76\u6392\u5e8f\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.union1d(inits, [3, 4, 5])) # [1 2 3 4 5] np.setdiff1d(x, y) \u5dee\u96c6\uff0c\u5728x\u4e2d\u4f46\u4e0d\u5728y\u4e2d\u7684\u5143\u7d20\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.setdiff1d(inits, [3, 4, 5])) # [1 2] np.setxor1d(x, y) \u5f02\u6216\u96c6\uff0c\u5728x\u6216\u8005y\u4e2d\uff0c\u4f46\u4e0d\u5c5e\u4e8ex\uff0cy\u4ea4\u96c6\u7684\u5143\u7d20\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.setxor1d(inits, [3, 4, 5])) # [1 2 4] \u4f7f\u7528\u6570\u7ec4\u8fdb\u884c\u6587\u4ef6\u8f93\u5165\u548c\u8f93\u51fa \u00b6 NumPy\u53ef\u4ee5\u5728\u786c\u76d8\u4e2d\u5c06\u6570\u636e\u4ee5\u6587\u672c\u6216\u4e8c\u8fdb\u5236\u6587\u4ef6\u7684\u5f62\u5f0f\u8fdb\u884c\u5b58\u5165\u786c\u76d8\u6216\u7531\u786c\u76d8\u8f7d\u5165\u3002 \u5f53\u524d\u53ea\u5173\u6ce8NumPy\u7684\u5185\u5efa\u4e8c\u8fdb\u5236\u683c\u5f0f\uff0c\u56e0\u4e3a\u5927\u90e8\u5206\u7528\u6237\u66f4\u503e\u5411\u4e8e\u4f7f\u7528pandas\u6216\u5176\u4ed6\u5de5\u5177\u6765\u8f7d\u5165\u6587\u672c\u6216\u8868\u683c\u578b\u6570\u636e\u3002 np.save \u548c np.load \u662f\u9ad8\u6548\u5b58\u53d6\u786c\u76d8\u6570\u636e\u7684\u4e24\u5927\u5de5\u5177\u51fd\u6570\u3002\u6570\u7ec4\u5728\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u662f\u4ee5*\u672a\u538b\u7f29*\u7684\u683c\u5f0f\u8fdb\u884c\u5b58\u50a8\u7684\uff0c\u540e\u7f00\u540d\u662f.npy\u3002 import numpy as np array1 = np.arange(10) array2 = np.arange(15).reshape(3, 5) array3 = np.arange(30).reshape(3, 2, 5) print(array1) # [0 1 2 3 4 5 6 7 8 9] print(array2) # [[ 0 1 2 3 4] # [ 5 6 7 8 9] # [10 11 12 13 14]] print(array3) # [[[ 0 1 2 3 4] # [ 5 6 7 8 9]] # [[10 11 12 13 14] # [15 16 17 18 19]] # [[20 21 22 23 24] # [25 26 27 28 29]]] # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os.getcwd() # '/opt/myProject/mySite' # \u66f4\u6539\u9ed8\u8ba4\u8def\u5f84 os.chdir('/opt/myProject/mySite/docs/python/datasets/examples') # \u4fdd\u5b58\u5230\u9ed8\u8ba4\u8def\u5f84\u3002npy\u540e\u7f00\u540d\u4f1a\u88ab\u81ea\u52a8\u52a0\u4e0a np.save('some_array', array1) # \u8bfb\u53d6\u6240\u4fdd\u5b58\u7684\u6587\u4ef6 result = np.load('some_array.npy') # \u5bf9\u6bd4\u7ed3\u679c\u4e00\u81f4\u3002 print(result) # [0 1 2 3 4 5 6 7 8 9] # \u5c06\u591a\u4e2a\u6570\u7ec4\u4fdd\u5b58\u5230\u672a\u538b\u7f29\u7684\u5355\u4e2a\u6587\u4ef6\u4e2d\uff0c.npz\u683c\u5f0f np.savez('some_array_archive.npz', a=array2, b=array3) result = np.load('some_array_archive.npz') # reslt\u662f\u4e00\u4e2a\u5b57\u5178\u578b\u7684\u5bf9\u8c61 print(result['b']) # \u8f7d\u5165\u5355\u4e2a\u6570\u7ec4b # [[[ 0 1 2 3 4] # [ 5 6 7 8 9]] # [[10 11 12 13 14] # [15 16 17 18 19]] # [[20 21 22 23 24] # [25 26 27 28 29]]] \u7ebf\u6027\u4ee3\u6570 \u00b6 \u53c2\u8003\u94fe\u63a5\uff1a https://www.numpy.org.cn/reference/routines/linalg.html https://github.com/teadocs/numpy-cn \u5e0c\u814a\u5b57\u6bcd: \u0391 \u03b1 /'\u00e6lf\u0259/ alpha \u0392 \u03b2 /'bi:t\u0259/ beta \u0393 \u03b3 /'g\u00e6m\u0259/ gamma \u0394 \u03b4 /'delt\u0259/ delta \u0395 \u03b5 /'eps\u026al\u0252n/ epsilon \u0396 \u03b6 /'zi:t\u0259/ zeta \u0397 \u03b7 /'i:t\u0259/ eta \u0398 \u03b8 /'\u03b8i:t\u0259/ theta \u0399 \u03b9 /'a\u026a\u0259\u028at\u0259/ iota \u039a \u03ba /'k\u00e6p\u0259/ kappa \u2227 \u03bb /'l\u00e6md\u0259/ lambda \u039c \u03bc /mju:/ mu \u039d \u03bd /nju:/ nu \u039e \u03be /ksi/ xi \u039f \u03bf /\u0259u\u02c8maikr\u0259n/ omicron \u220f \u03c0 /pa\u026a/ pi \u03a1 \u03c1 /r\u0259\u028a/ rho \u2211 \u03c3 /'s\u026a\u0261m\u0259/ sigma \u03a4 \u03c4 /t\u0254:/ tau \u03a5 \u03c5 /\u02c8ips\u026alon/ upsilon \u03a6 \u03c6 /fa\u026a/ phi \u03a7 \u03c7 /ka\u026a/ chi \u03a8 \u03c8 /psa\u026a/ psi \u03a9 \u03c9 /'\u0259\u028am\u026a\u0261\u0259/ omega numpy.linalg \u6a21\u5757\u5305\u542b\u7ebf\u6027\u4ee3\u6570\u7684\u51fd\u6570\u3002\u4f7f\u7528\u8fd9\u4e2a\u6a21\u5757\uff0c\u53ef\u4ee5\u8ba1\u7b97\u9006\u77e9\u9635\u3001\u6c42\u7279\u5f81\u503c\u3001\u89e3\u7ebf\u6027\u65b9\u7a0b\u7ec4\u4ee5\u53ca\u6c42\u89e3\u884c\u5217\u5f0f\u7b49\u3002 import numpy as np from numpy import linalg as LA from numpy import * from numpy.linalg import inv import matplotlib.pyplot as plt diag \u00b6 np.diag \u5c06\u4e00\u4e2a\u65b9\u9635\u7684\u5bf9\u89d2\uff08\u6216\u975e\u5bf9\u89d2\uff09\u5143\u7d20\u4f5c\u4e3a\u4e00\u7ef4\u6570\u7ec4\u8fd4\u56de\uff0c\u6216\u8005\u5c06\u4e00\u7ef4\u6570\u7ec4\u8f6c\u6362\u6210\u4e00\u4e2a\u65b9\u9635\uff0c\u5e76\u4e14\u5728\u975e\u5bf9\u89d2\u7ebf\u4e0a\u6709\u96f6\u70b9\u3002 a1 = np.arange(9, dtype=float).reshape((3, 3)) r1 = np.diag(a1) r2 = np.diag(a1, k=1) r3 = np.diag(a1, k=-1) r4 = np.diag(np.diag(a1)) # \u5bf9\u89d2\u77e9\u9635 print(\"\u6837\u672c\u77e9\u9635 \\n\", a1) print(\"\u77e9\u9635\u5bf9\u89d2\u7ebf\", r1) print(\"\u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0a\u504f\u79fb\", r2) print(\"\u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0b\u504f\u79fb\", r3) print(\"\u5bf9\u89d2\u77e9\u9635 \\n\", r4) # \u6837\u672c\u77e9\u9635 # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]] # \u77e9\u9635\u5bf9\u89d2\u7ebf [0. 4. 8.] # \u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0a\u504f\u79fb [1. 5.] # \u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0b\u504f\u79fb [3. 7.] # \u5bf9\u89d2\u77e9\u9635 # [[0. 0. 0.] # [0. 4. 0.] # [0. 0. 8.]] dot \u00b6 np.dot \u5c06\u5411\u91cf\u4e2d\u5bf9\u5e94\u5143\u7d20\u76f8\u4e58\uff0c\u518d\u76f8\u52a0\u6240\u5f97\u3002\u5373\u666e\u901a\u7684\u5411\u91cf\u4e58\u6cd5\u8fd0\u7b97\uff0c\u6216**\u77e9\u9635\u70b9\u4e58**\u3002 a1 = np.dot(3, 4) print(a1) # 12 a2 = np.arange(9, dtype=float).reshape((3, 3)) r2 = np.dot(a2, a2) print(a2) # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]] print(r2) # [[ 15. 18. 21.] # [ 42. 54. 66.] # [ 69. 90. 111.]] r3 = np.dot([2j, 3j], [2j, 3j]) print(r3) # (-13+0j) trace \u00b6 np.trace \u8ba1\u7b97\u5bf9\u89d2\u5143\u7d20\u548c\u3002 a1 = np.arange(9, dtype=float).reshape((3, 3)) print(\"\u6837\u672c\u77e9\u9635 \\n\", a1) r1 = np.trace(a1) print(\"\u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c\", r1) a2 = np.arange(24, dtype=float).reshape((2, 3, 4)) r2 = np.trace(a2) print(\"\u6837\u672c\u77e9\u9635 \\n\", a2) print(\"\u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c\", r2) # \u6837\u672c\u77e9\u9635 # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]] # \u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c 12.0 # \u6837\u672c\u77e9\u9635 # [[[ 0. 1. 2. 3.] # [ 4. 5. 6. 7.] # [ 8. 9. 10. 11.]] # # [[12. 13. 14. 15.] # [16. 17. 18. 19.] # [20. 21. 22. 23.]]] # \u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c [16. 18. 20. 22.] det \u00b6 np.det \u8ba1\u7b97\u77e9\u9635\u7684\u884c\u5217\u5f0f\uff08\u65b9\u9635\uff09\u3002 \u4e8c\u9636\u884c\u5217\u5f0f[[a, b], [c, d]]\u7684\u503c\u662fad - bc \u4e09\u9636\u884c\u5217\u5f0f [[a, b, c], [d, e, f], [g, h, i]]\u7684\u503c\u662f aei + bfd + cdh - ceg - bdi - afh \u4e09\u9636\u884c\u5217\u5f0f\u7684\u6027\u8d28 \u6027\u8d281\uff1a\u884c\u5217\u5f0f\u4e0e\u5b83\u7684\u8f6c\u7f6e\u884c\u5217\u5f0f\u76f8\u7b49\u3002 \u6027\u8d282\uff1a\u4e92\u6362\u884c\u5217\u5f0f\u7684\u4e24\u884c(\u5217)\uff0c\u884c\u5217\u5f0f\u53d8\u53f7\u3002 \u63a8\u8bba\uff1a\u5982\u679c\u884c\u5217\u5f0f\u6709\u4e24\u884c(\u5217)\u5b8c\u5168\u76f8\u540c\uff0c\u5219\u6b64\u884c\u5217\u5f0f\u4e3a\u96f6\u3002 \u6027\u8d283\uff1a\u884c\u5217\u5f0f\u7684\u67d0\u4e00\u884c(\u5217)\u4e2d\u6240\u6709\u7684\u5143\u7d20\u90fd\u4e58\u4ee5\u540c\u4e00\u6570k\uff0c\u7b49\u4e8e\u7528\u6570k\u4e58\u6b64\u884c\u5217\u5f0f\u3002 \u63a8\u8bba\uff1a\u884c\u5217\u5f0f\u4e2d\u67d0\u4e00\u884c(\u5217)\u7684\u6240\u6709\u5143\u7d20\u7684\u516c\u56e0\u5b50\u53ef\u4ee5\u63d0\u5230\u884c\u5217\u5f0f\u7b26\u53f7\u7684\u5916\u9762\u3002 \u6027\u8d284\uff1a\u884c\u5217\u5f0f\u4e2d\u5982\u679c\u6709\u4e24\u884c(\u5217)\u5143\u7d20\u6210\u6bd4\u4f8b\uff0c\u5219\u6b64\u884c\u5217\u5f0f\u7b49\u4e8e\u96f6\u3002 \u6027\u8d285\uff1a\u628a\u884c\u5217\u5f0f\u7684\u67d0\u4e00\u5217(\u884c)\u7684\u5404\u5143\u7d20\u4e58\u4ee5\u540c\u4e00\u6570\u7136\u540e\u52a0\u5230\u53e6\u4e00\u5217(\u884c)\u5bf9\u5e94\u7684\u5143\u7d20\u4e0a\u53bb\uff0c\u884c\u5217\u5f0f\u4e0d\u53d8\u3002 a1 = np.array([[1, 2], [3, 4]]) r1 = np.linalg.det(a1) print(\"\u4e8c\u9636\u65b9\u9635 \\n\", a1) print(\"\u4e8c\u9636\u884c\u5217\u5f0f\u7684\u503c\", r1) # \u4e8c\u9636\u65b9\u9635 # [[1 2] # [3 4]] # \u4e8c\u9636\u884c\u5217\u5f0f\u7684\u503c -2.0000000000000004 # \u5e0c\u814a\u5b57\u6bcd # \u03b1, \u03b2, \u03b3,\u03b4, \u03b5, \u03b6, \u03b7, \u03b8, \u03b9, \u03ba, \u03bb, \u03bc, \u03bd, # \u03be, \u03bf, \u03c0, \u03c1, \u03c2, \u03c3, \u03c4, \u03c5, \u03c6, \u03c7, \u03c8, \u03c9, a2 = np.arange(9).reshape(3, 3) r2 = np.linalg.det(a2) print(\"\u4e09\u9636\u65b9\u9635 \\n\", a2) print(\"\u4e09\u9636\u884c\u5217\u5f0f\u7684\u503c\", r2) # \u4e09\u9636\u65b9\u9635 # [[0 1 2] # [3 4 5] # [6 7 8]] # \u4e09\u9636\u884c\u5217\u5f0f\u7684\u503c 0.0 a3 = np.arange(16).reshape(4, 4) r3 = np.linalg.det(a3) print(\"\u56db\u9636\u65b9\u9635 \\n\", a3) print(\"\u56db\u9636\u884c\u5217\u5f0f\u7684\u503c\", r3) # \u56db\u9636\u65b9\u9635 # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]# \u5e0c\u814a\u5b57\u6bcd # \u03b1, \u03b2, \u03b3,\u03b4, \u03b5, \u03b6, \u03b7, \u03b8, \u03b9, \u03ba, \u03bb, \u03bc, \u03bd, # \u03be, \u03bf, \u03c0, \u03c1, \u03c2, \u03c3, \u03c4, \u03c5, \u03c6, \u03c7, \u03c8, \u03c9, # [12 13 14 15]] # \u56db\u9636\u884c\u5217\u5f0f\u7684\u503c 0.0 eig \u00b6 np.eig \u8ba1\u7b97\u65b9\u9635\u7684\u7279\u5f81\u503c\u548c\u7279\u5f81\u5411\u91cf\u3002 \u7279\u5f81\u503c\u4e0e\u7279\u5f81\u5411\u91cf\u7684\u5b9a\u4e49\uff1a\u8bbeA\u662fn\u9636\u65b9\u9635\uff0c\u82e5\u6570\u03bb\u548cn\u7ef4\u975e\u96f6\u5217\u5411\u91cfx\uff0c\u4f7f\u5f97Ax = \u03bbx\u6210\u7acb\uff0c\u5219\u79f0\u03bb\u662f\u65b9\u9635A\u7684\u4e00\u4e2a\u7279\u5f81\u503c\uff0cx\u4e3a\u65b9\u9635A\u7684\u5bf9\u5e94\u4e8e\u7279\u5f81\u503c\u03bb\u7684\u4e00\u4e2a\u7279\u5f81\u5411\u91cf\u3002 A\u662f\u65b9\u9635\u3002\uff08\u5bf9\u4e8e\u975e\u65b9\u9635\uff0c\u662f\u6ca1\u6709\u7279\u5f81\u503c\u7684\uff0c\u4f46\u4f1a\u6709\u6761\u4ef6\u6570\u3002\uff09\u7279\u5f81\u5411\u91cfx\u4e3a\u975e\u96f6\u5217\u5411\u91cf\u3002 v_eigenvectors, v_eigenvalues = LA.eig(np.diag((1, 2, 3))) print(\"\u7279\u5f81\u5411\u91cf\", v_eigenvectors) print(\"\u7279\u5f81\u503c \\n\", v_eigenvalues) # \u7279\u5f81\u5411\u91cf [1. 2. 3.] # \u7279\u5f81\u503c # [[1. 0. 0.] # [0. 1. 0.] # [0. 0. 1.]] v_eigenvectors, v_eigenvalues = LA.eig(np.array([[1, -1], [1, 1]])) print(\"\u7279\u5f81\u5411\u91cf\", v_eigenvectors) print(\"\u7279\u5f81\u503c \\n\", v_eigenvalues) # \u7279\u5f81\u5411\u91cf [1.+1.j 1.-1.j] # \u7279\u5f81\u503c # [[0.70710678+0.j 0.70710678-0.j ] # [0. -0.70710678j 0. +0.70710678j]] inv \u00b6 np.inv \u8ba1\u7b97\u65b9\u9635\u7684\u9006\u77e9\u9635\u3002 a1 = np.array([[1, 2], [3, 4]]) r1 = inv(a1) r2 = inv(np.matrix(a1)) print(\"\u539f\u77e9\u9635 \\n\", a1) print(\"\u9006\u77e9\u9635 \\n\", r1) print(\"\u9006\u77e9\u9635 \\n\", r2) # \u539f\u77e9\u9635 # [[1 2] # [3 4]] # \u9006\u77e9\u9635 # [[-2. 1. ] # [ 1.5 -0.5]] # \u9006\u77e9\u9635 # [[-2. 1. ] # [ 1.5 -0.5]] pinv \u00b6 np.pinv \u8ba1\u7b97\u77e9\u9635\u7684Moore-Penrose\u4f2a\u9006(\u6469\u5c14\uff0d\u5f6d\u82e5\u65af\u5e7f\u4e49\u9006)\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u68c0\u9a8c a * a+ * a == a \u548c a+ * a * a+ == a+ a = np.random.randn(9, 6) B = np.linalg.pinv(a) r1 = np.allclose(a, np.dot(a, np.dot(B, a))) r2 = np.allclose(B, np.dot(B, np.dot(a, B))) print(a) print(B) print(r1) # True print(r2) # True # a: # [[-2.30316101 -0.63217332 1.24134743 -0.72492307 0.12456801 -0.14192548] # [ 1.37573495 0.07626697 -0.71870843 1.26824984 -0.79485727 -0.24630455] # [ 0.29003175 -1.23931665 -0.50864107 -0.31140718 0.45467649 -2.44973999] # [-0.70748664 -1.2995059 0.85126149 -1.10918804 -2.10042342 0.75942293] # [ 1.91765238 1.23892103 1.58516486 -1.65520154 0.11894439 0.84536298] # [ 1.03220791 0.1715148 0.85595408 0.58569706 1.34066384 -1.5782386 ] # [-0.54432889 -0.0114189 1.55403934 0.89852512 1.15586365 -0.30733805] # [-0.80874673 0.14602121 1.04680044 1.98722514 0.39766383 0.75178788] # [ 0.01664663 0.06243353 -0.50725334 -0.37707204 -1.76701091 -0.33866559]] # B: # [[-0.25055838 0.13963115 0.08990923 0.16280282 0.12997291 0.05088469 -0.01541299 -0.01656133 -0.21731387] # [ 0.22862622 -0.05108109 -0.2639602 -0.47835978 0.11776862 0.09324694 0.00436756 -0.00609393 0.61995597] # [ 0.10422554 0.03985857 0.00198025 0.15139023 0.17165026 0.15697725 0.17360246 0.13150089 0.08378135] # [-0.07021378 0.17665487 -0.04109252 0.0015022 -0.11998477 0.0543575 0.08649033 0.21190785 0.04065729] # [-0.08110336 -0.15274536 0.05601496 -0.07967802 -0.02454705 -0.04152356 0.00071268 -0.05981012 -0.43996066] # [-0.17998537 -0.03160871 -0.12587707 0.16856246 0.00565094 -0.21038026 -0.06060039 0.04322126 -0.42038066]] qr \u00b6 np.qr \u8ba1\u7b97QR\u5206\u89e3\u3002QR\uff08\u6b63\u4ea4\u4e09\u89d2\uff09\u5206\u89e3\u6cd5\u662f\u6c42\u4e00\u822c\u77e9\u9635\u5168\u90e8\u7279\u5f81\u503c\u7684\u6700\u6709\u6548\u5e76\u5e7f\u6cdb\u5e94\u7528\u7684\u65b9\u6cd5\u3002 \u4e00\u822c\u77e9\u9635\u5148\u7ecf\u8fc7\u6b63\u4ea4\u76f8\u4f3c\u53d8\u5316\u6210\u4e3aHessenberg\u77e9\u9635\uff0c\u7136\u540e\u518d\u5e94\u7528QR\u65b9\u6cd5\u6c42\u7279\u5f81\u503c\u548c\u7279\u5f81\u5411\u91cf\u3002QR\u5206\u89e3\u6cd5\u662f\u5c06\u77e9\u9635\u5206\u89e3\u6210\u4e00\u4e2a\u6b63\u89c4\u6b63\u4ea4\u77e9\u9635Q\u4e0e\u4e0a\u4e09\u89d2\u5f62\u77e9\u9635R\uff0c\u6240\u4ee5\u79f0\u4e3aQR\u5206\u89e3\u6cd5\u3002 a = np.arange(9).reshape(3, 3) q, r = np.linalg.qr(a) print(\"\u539f\u77e9\u9635 \\n\", a) print(\"\u6b63\u4ea4\u77e9\u9635 \\n\", q) print(\"\u4e0a\u4e09\u89d2\u77e9\u9635 \\n\", r) # \u539f\u77e9\u9635 # [[0 1 2] # [3 4 5] # [6 7 8]] # \u6b63\u4ea4\u77e9\u9635 # [[ 0. 0.91287093 0.40824829] # [-0.4472136 0.36514837 -0.81649658] # [-0.89442719 -0.18257419 0.40824829]] # \u4e0a\u4e09\u89d2\u77e9\u9635 # [[-6.70820393e+00 -8.04984472e+00 -9.39148551e+00] # [ 0.00000000e+00 1.09544512e+00 2.19089023e+00] # [ 0.00000000e+00 0.00000000e+00 -8.88178420e-16]] svd \u00b6 np.svd \u8ba1\u7b97\u5947\u5f02\u503c\u5206\u89e3\uff08SVD\uff09\u3002 \u51e0\u4f55\u610f\u4e49\uff1aSVD\u5206\u89e3\u7684\u51e0\u4f55\u610f\u4e49\u662f\u4efb\u4f55\u4e00\u4e2a\u77e9\u9635A\u5728\u4e00\u7cfb\u5217\u65cb\u8f6c\u548c\u5e73\u79fb\u4e0b\u90fd\u80fd\u8f6c\u5316\u6210\u4e00\u4e2a\u5bf9\u89d2\u77e9\u9635\u2211 , \u5176\u4e2d\u9149\u9635U, V\u7684\u51e0\u4f55\u610f\u4e49\u5c31\u662f\u4e00\u7cfb\u5217\u65cb\u8f6c\u548c\u5e73\u79fb\u7684\u53e0\u52a0\u3002 a = mat([[1, 2, 3],[4, 5, 6]]) U, sigma, V = np.linalg.svd(a) print(\"\u539f\u77e9\u9635 \\n\", a) print(\"\u5de6\u5947\u5f02\u503cU \\n\", U) print(\"\u5947\u5f02\u503cSigma \\n\", sigma) print(\"\u53f3\u5947\u5f02\u503cV \\n\", V) # \u539f\u77e9\u9635 # [[1 2 3] # [4 5 6]] # \u5de6\u5947\u5f02\u503cU # [[-0.3863177 -0.92236578] # [-0.92236578 0.3863177 ]] # \u5947\u5f02\u503cSigma # [9.508032 0.77286964] # \u53f3\u5947\u5f02\u503cV # [[-0.42866713 -0.56630692 -0.7039467 ] # [ 0.80596391 0.11238241 -0.58119908] # [ 0.40824829 -0.81649658 0.40824829]] solve \u00b6 np.solve \u6c42\u89e3x\u7684\u7ebf\u6027\u7cfb\u7edfAx = b\uff0c\u5176\u4e2dA\u662f\u65b9\u9635\u3002 \u89e3\u65b9\u7a0b\u7ec4\uff1a x + 2y = 1 3x + 5y = 2 a = np.array([[1, 2], [3, 5]]) b = np.array([1, 2]) x = np.linalg.solve(a, b) print(x) # [-1. 1.] lstsq \u00b6 np.lstsq \u8ba1\u7b97Ax = b\u7684\u6700\u5c0f\u4e8c\u4e58\u89e3\u3002 \u7528\u6700\u5c0f\u4e8c\u4e58\u6cd5\u62df\u5408\u6570\u636e\u5f97\u5230\u4e00\u4e2a\u5f62\u5982y = mx + c\u7684\u7ebf\u6027\u65b9\u7a0b\uff08Return the least-squares solution to a linear matrix equation\uff09\u3002 x = np.array([0, 1, 2, 3]) # \u539f\u59cb\u6570\u636e\u70b9\u7684\u6a2a\u5750\u6807 y = np.array([-1, 0.2, 0.9, 2.1]) # \u539f\u59cb\u6570\u636e\u70b9\u7684\u7eb5\u5750\u6807 print(x) # [0 1 2 3] print(y) # [-1. 0.2 0.9 2.1] A = np.vstack([x, np.ones(len(x))]).T # \u6784\u9020\u7cfb\u6570\u77e9\u9635 print(A) # [[0. 1.] # [1. 1.] # [2. 1.] # [3. 1.]] m, c = np.linalg.lstsq(A, y, rcond=None)[0] # \u89e3\u51fa\u659c\u7387a\u548c\u7eb5\u622a\u8dddc plt.plot(x, y, 'o', label='Original data', markersize=10) # \u505a\u51fa\u539f\u59cb\u6570\u636e\u6563\u70b9\u56fe plt.plot(x, m*x + c, 'r', label='Fitted line') # \u7528\u4e0a\u9762\u89e3\u51fa\u7684\u53c2\u6570\u505a\u51fa\u62df\u5408\u66f2\u7ebfy=mx+c plt.legend() plt.show() \u4f2a\u968f\u673a\u6570\u751f\u6210 \u00b6 numpy.random \u6a21\u5757\u586b\u8865\u4e86Python\u5185\u5efa\u7684 random \u6a21\u5757\u7684\u4e0d\u8db3\uff0c\u53ef\u4ee5\u9ad8\u6548\u5730\u751f\u6210\u591a\u79cd\u6982\u7387\u5206\u5e03\u4e0b\u7684\u5b8c\u6574\u6837\u672c\u503c\u6570\u7ec4\u3002 numpy.random \u4e2d\u7684\u6570\u636e\u751f\u6210\u51fd\u6570\u516c\u7528\u4e86\u4e00\u4e2a\u5168\u5c40\u7684\u968f\u673a\u6570\u79cd\u5b50\u3002 \u4f7f\u7528 numpy.random.RandomState \u751f\u6210\u4e00\u4e2a\u968f\u673a\u6570\u751f\u6210\u5668\uff0c\u4f7f\u6570\u636e\u72ec\u7acb\u4e8e\u5176\u4ed6\u7684\u968f\u673a\u6570\u72b6\u6001\u3002 \u901a\u8fc7 np.random.seed \u66f4\u6539NumPy\u7684\u968f\u673a\u6570\u79cd\u5b50\u3002 numpy.random \u4e2d\u7684\u90e8\u5206\u51fd\u6570\u5217\u8868 seed: \u5411\u968f\u673a\u6570\u751f\u6210\u5668\u4f20\u9012\u968f\u673a\u72b6\u6001\u79cd\u5b50 permutation: \u8fd4\u56de\u4e00\u4e2a\u5e8f\u5217\u7684\u968f\u673a\u6392\u5217\uff0c\u6216\u8005\u8fd4\u56de\u4e00\u4e2a\u4e71\u5e8f\u7684\u6574\u6570\u8303\u56f4\u5e8f\u5217 shuffle: \u968f\u673a\u6392\u5217\u4e00\u4e2a\u5e8f\u5217 rand: \u4ece\u5747\u5300\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c randint: \u6839\u636e\u7ed9\u5b9a\u7684\u7531\u4f4e\u5230\u9ad8\u7684\u8303\u56f4\u62bd\u53d6\u968f\u673a\u6574\u6570 randn: \u4ece\u5747\u503c0\u65b9\u5dee1\u7684\u6b63\u6001\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c(MATLAB\u578b\u63a5\u53e3\uff09 binomial: \u4ece\u4e8c\u9879\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c normal: \u4ece\u6b63\u6001\uff08\u9ad8\u65af\uff09\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c beta\u4ecebeta: \u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c chisquare: \u4ece\u5361\u65b9\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c \u4f8b\u5982\uff0c\u4f7f\u7528normal\u6765\u83b7\u5f97\u4e00\u4e2a4\u00d74\u7684\u6b63\u6001\u5206\u5e03\u6837\u672c\u6570\u7ec4\uff0c\u79f0\u4e3a\u4f2a\u968f\u673a\u6570\u3002 import numpy as np samples = np.random.normal(size=(4, 4)) print(samples) # [[ 0.78583658 -0.27462104 -0.53027675 -0.62675004] # [ 0.39054781 1.20503691 -0.0057432 0.17243182] # [-0.41516669 -0.93335854 0.01996088 -0.12707275] # [ 0.42952379 2.56998319 0.14848737 -0.42871493]] \u793a\u4f8b\uff1a\u968f\u673a\u6f2b\u6b65 \u00b6 import matplotlib.pyplot as plt import numpy as np position = 0 walk = [position] nwalks = 5000 nsteps = 1000 draws = np.random.randint(0, 2, size=(nwalks, nsteps)) steps = np.where(draws > 0, 1, -1) walks = steps.cumsum() plt.plot(walks[:500000000000000000000000000]) plt.show() \u8f93\u51fa\u56fe\u50cf\uff1a","title":"NumPy\u57fa\u7840"},{"location":"python/DataAnalysis/ch01/#numpy","text":"\u5305\u542b\u4ee5\u4e0b\u5185\u5bb9\uff1a \u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61 \u901a\u7528\u51fd\u6570 \u9762\u5411\u6570\u7ec4\u7f16\u7a0b \u4f7f\u7528\u6570\u7ec4\u8fdb\u884c\u6587\u4ef6\u8f93\u5165\u548c\u8f93\u51fa \u7ebf\u6027\u4ee3\u6570 \u4f2a\u968f\u673a\u6570\u751f\u6210 \u793a\u4f8b\uff1a\u968f\u673a\u6f2b\u6b65","title":"NumPy\u57fa\u7840"},{"location":"python/DataAnalysis/ch01/#ndarry","text":"","title":"\u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61ndarry"},{"location":"python/DataAnalysis/ch01/#_1","text":"import numpy as np import pandas as pd import matplotlib.pyplot as plt","title":"\u522b\u540d\u7ea6\u5b9a"},{"location":"python/DataAnalysis/ch01/#matplotlib","text":"\u67e5\u770b\u5b57\u4f53\u8def\u5f84 >>> import matplotlib >>> print(matplotlib.matplotlib_fname()) /home/james/.local/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc \u4e0b\u8f7d\u4e2d\u6587\u5b57\u4f53\u3002\u7f51\u5740 https://www.fontpalace.com/font-download/SimHei/,\u5e76\u62f7\u8d1d\u5230\u4e0b\u9762\u7684\u8def\u5f84\u4e0b james@lizard:~/Downloads> cp SimHei.ttf /home/james/.local/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf/ \u67e5\u770bmatplotlib\u7684\u5b57\u4f53\u7f13\u5b58\u76ee\u5f55\u3002 >>> import matplotlib >>> print(matplotlib.get_cachedir()) /home/james/.cache/matplotlib \u5220\u9664\u8fd9\u4e2a\u76ee\u5f55 james@lizard:~> rm -rf /home/james/.cache/matplotlib \u7f16\u8f91matplotlibrc\u6587\u4ef6 /home/james/.local/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc \uff0c\u505a\u5982\u4e0b\u4fee\u6539\u3002 \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # font.family: sans-serif \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # \uff0c\u5e76\u6dfb\u52a0 SimHei \uff0c\u4fee\u6539\u540e\u4e3a font.serif: SimHei, DejaVu Serif, Bitstream Vera Serif, Computer Modern Roman, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # \uff0c\u5e76\u6dfb\u52a0 SimHei \uff0c\u4fee\u6539\u540e\u4e3a font.sans-serif: SimHei, DejaVu Sans, Bitstream Vera Sans, Computer Modern Sans Serif, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # \uff0c\u5e76\u628a True \u6539\u4e3a False \uff0c\u4fee\u6539\u540e\u4e3a axes.unicode_minus: False","title":"\u5b89\u88c5matplotlib\u4e2d\u6587\u5b57\u4f53"},{"location":"python/DataAnalysis/ch01/#matplotlib_1","text":"\u5728\u4f7f\u7528matplotlib\u8f93\u51fa\u56fe\u50cf\u65f6\uff0c\u5982\u679c\u9047\u5230\u65e0\u6cd5\u663e\u793a\u56fe\u50cf\u7684\u9519\u8bef UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure\u3002 \uff0c\u53ef\u4ee5\u5c1d\u8bd5\u4e0b\u9762\u7684\u6b65\u9aa4\u89e3\u51b3\u3002 \u5b89\u88c5 python3-tk \u5305 james@lizard:~> sudo zypper in python3-tk \u6216\u8005\u901a\u8fc7 pip \u5b89\u88c5 tk \u5305 james@lizard:~> pip3 install tk Defaulting to user installation because normal site-packages is not writeable Collecting tk Downloading tk-0.1.0-py3-none-any.whl (3.9 kB) Installing collected packages: tk Successfully installed tk-0.1.0 \u4e00\u822c\u5b8c\u6210\u4e0a\u9762\u5b89\u88c5\u540e\uff0c\u7a0b\u5e8f\u5c31\u80fd\u81ea\u52a8\u663e\u793a\u56fe\u4e86\uff0c\u5982\u679c\u8fd8\u662f\u4e0d\u80fd\u663e\u793a\uff0c\u518d\u5c1d\u8bd5\u91cd\u65b0\u5b89\u88c5 matplotlib \u3002 pip3 ininstall matplotlib pip3 install matplotlib","title":"\u8bbe\u7f6ematplotlib\u540e\u7aef\u6e32\u67d3\u5668"},{"location":"python/DataAnalysis/ch01/#ndarray-n-","text":"\u4e00\u4e2andarray\u662f\u4e00\u4e2a\u901a\u7528\u7684\u591a\u7ef4\u540c\u7c7b\u6570\u636e\u5bb9\u5668\uff0c\u4e5f\u5c31\u662f\u8bf4\uff0c\u5b83\u5305\u542b\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u5747\u4e3a**\u76f8\u540c\u7c7b\u578b**\uff1b \u6bcf\u4e00\u4e2a\u6570\u7ec4\u90fd\u6709\u4e00\u4e2ashape\u5c5e\u6027\uff0c\u7528\u6765\u8868\u5f81\u6570\u7ec4\u6bcf\u4e00\u7ef4\u5ea6\u7684\u6570\u91cf\uff1b \u6bcf\u4e00\u4e2a\u6570\u7ec4\u90fd\u6709\u4e00\u4e2adtype\u5c5e\u6027\uff0c\u7528\u6765\u63cf\u8ff0\u6570\u7ec4\u7684\u6570\u636e\u7c7b\u578b\uff1b \u4e0b\u9762\u662f\u6807\u51c6\u6570\u7ec4\u7684\u751f\u6210\u51fd\u6570 array: \u5c06\u8f93\u5165\u6570\u636e\uff08\u5217\u8868\u3001\u5143\u7ec4\u3001\u6570\u7ec4\uff0c\u5176\u4ed6\u5e8f\u5217\uff09\u8f6c\u6362\u4e3andarray\uff0c\u5982\u679c\u4e0d\u663e\u5f0f\u6307\u660e\u6570\u636e\u7c7b\u578b\uff0c\u5c06\u81ea\u52a8\u63a8\u65ad\uff1b\u9ed8\u8ba4\u590d\u5236\u6240\u6709\u7684\u8f93\u5165\u6570\u636e\u3002 asarray\uff1a\u5c06\u8f93\u5165\u8f6c\u6362\u4e3andarray\uff0c\u4f46\u5982\u679c\u8f93\u5165\u5df2\u7ecf\u662fndarray\u5219\u4e0d\u518d\u590d\u5236\u3002 arange\uff1aPython\u5185\u7f6e\u51fd\u6570range\u7684\u6570\u7ec4\u7248\uff0c\u8fd4\u56de\u4e00\u4e2a\u6570\u7ec4\u3002 \u4e0b\u9762\u662f\u7528 Numpy.random() \u4e00\u4e2a\u751f\u6210\u4e00\u4e2a\u968f\u673a\u6570\u7ec4\u7684\u4f8b\u5b50\uff0c\u6ce8\u610f data01 \u7684\u7c7b\u578b\u662f'numpy.ndarray'\u3002\u53ef\u4ee5\u5728ndarray\u7c7b\u578b\u6570\u7ec4\u4e0a\u53e0\u52a0\u4e00\u4e0b\u6570\u5b66\u64cd\u4f5c\u3002 data01 = np.random.randn(2, 3) print(type(data01)) # print(data01) # [[ 0.12047302 -1.13499045 -0.39311368] # [ 1.54046881 0.01254838 -3.65090952]] print(data01 * 10) # \u7ed9data\u52a0\u4e0a\u4e00\u4e2a\u6570\u5b66\u64cd\u4f5c, \u6240\u6709\u7684\u5143\u7d20\u90fd\u540c\u65f6\u4e58\u4ee5\u4e8610 # [[ 1.20473022 -11.3499045 -3.93113676] # [ 15.40468806 0.12548383 -36.50909515]] print(data01 + data01) # \u7ed9data\u52a0\u4e0a\u4e00\u4e2a\u6570\u5b66\u64cd\u4f5c, \u6570\u7ec4\u4e2d\u7684\u5bf9\u5e94\u5143\u7d20\u8fdb\u884c\u4e86\u76f8\u52a0 # [[ 0.24094604 -2.2699809 -0.78622735] # [ 3.08093761 0.02509677 -7.30181903]] print(data01.shape) # (2, 3) print(data01.dtype) # float64 \u5f53\u8868\u8fbe\u201c\u6570\u7ec4\u201d\u3001\u201cNumPy\u6570\u7ec4\u201d\u6216\u201cndarray\u201d\u65f6\uff0c\u90fd\u8868\u793a\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1andarray\u5bf9\u8c61\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a data01 \u662f\u4e00\u4e2a\u5217\u8868\uff08list\uff09\u7c7b\u578b\uff0c\u901a\u8fc7 Numpy.array \u8f6c\u6362\u6210Numpy\u7684 ndarray \u7c7b\u578b\u3002 \u5728 np.array \u4e2d\uff0c\u9664\u975e\u663e\u5f0f\u5730\u6307\u5b9a\uff0c\u5982 np.array(data01, dtype=np.int8) \uff0c\u5426\u5219np.array\u4f1a\u81ea\u52a8\u63a8\u65ad\u751f\u6210\u6570\u7ec4\u7684\u6570\u636e\u7c7b\u578b array01.dtype \u3002 \u4f7f\u7528 astype() \u65b9\u6cd5\u663e\u5f0f\u5730\u8f6c\u6362\u6570\u7ec4\u7684\u6570\u636e\u7c7b\u578b\u3002\u4f7f\u7528 astype() \u65f6\u603b\u662f\u751f\u6210\u4e00\u4e2a*\u65b0\u7684\u6570\u7ec4*\uff0c\u5373\u4f7f\u4f60\u4f20\u5165\u7684dtype\u4e0e\u4e4b\u524d\u4e00\u6837\u3002 data02 \u662f\u4e00\u4e2a\u5d4c\u5957\u5217\u8868 [[1, 2, 3, 4], [5, 6, 7, 8]] \uff0c\u901a\u8fc7np.array()\u65b9\u6cd5\u8f6c\u6362\u6210\u591a\u7ef4\u6570\u7ec4\uff0c\u524d\u63d0\u662f\u6bcf\u4e2a\u5b50\u5217\u8868\u7684\u957f\u5ea6\u8981\u4e00\u81f4\u3002 data01 = [6, 7.5, 8, 0, 1] print(data01) # [6, 7.5, 8, 0, 1] print(type(data01)) # array01 = np.array(data01) print(\"\u77e9\u9635\u7c7b\u578b\", type(array01)) # \u77e9\u9635\u7c7b\u578b print(\"\u6837\u672c\u77e9\u9635\", array01) # \u6837\u672c\u77e9\u9635 [6. 7.5 8. 0. 1. ] print(\"\u6570\u7ec4\u7ef4\u5ea6\", array01.ndim) # \u6570\u7ec4\u7ef4\u5ea6 1 print(\"\u77e9\u9635\u5f62\u72b6\", array01.shape) # \u77e9\u9635\u5f62\u72b6 (5,) \u4e00\u884c\u4e94\u5217 print(\"\u77e9\u9635\u6570\u636e\u7c7b\u578b\", array01.dtype) # float64 data02 = [[1, 2, 3, 4], [5, 6, 7, 8]] array02 = np.array(data02) print(\"\u6837\u672c\u77e9\u9635\\n\", array02) # \u6837\u672c\u77e9\u9635 # [[1 2 3 4] # [5 6 7 8]] print(\"\u6570\u7ec4\u7ef4\u5ea6\", array02.ndim) # \u6570\u7ec4\u7ef4\u5ea6 2 print(\"\u77e9\u9635\u5f62\u72b6\", array02.shape) # \u77e9\u9635\u5f62\u72b6 (2, 4) print(\"\u77e9\u9635\u6570\u636e\u7c7b\u578b\", array02.dtype) # \u77e9\u9635\u6570\u636e\u7c7b\u578b int64 print(\"\u77e9\u96350\u8f74\u5411\u6c42\u548c\", array02.sum(axis=0)) # \u77e9\u96350\u8f74\u5411\u6c42\u548c [ 6 8 10 12] print(\"\u77e9\u96351\u8f74\u5411\u6c42\u548c\", array02.sum(axis=1)) # \u77e9\u96351\u8f74\u5411\u6c42\u548c [10 26] array03 = array02.astype(np.float64) print(array03.dtype) # float64 print(array03) # [[1. 2. 3. 4.] # [5. 6. 7. 8.]] zeros() \u65b9\u6cd5\u53ef\u4ee5\u4e00\u6b21\u6027\u521b\u9020\u51680\u6570\u7ec4\u3002 print(np.zeros(10)) # [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] ones() \u65b9\u6cd5\u53ef\u4ee5\u4e00\u6b21\u6027\u521b\u9020\u51681\u6570\u7ec4\u3002\u6ce8\u610f\uff0c\u4f20\u53c2shape\u662f\u4e00\u4e2a\u5143\u7ec4 (3, 5) \u3002 print(np.ones((3, 5))) # [[1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.]] empty() \u65b9\u6cd5\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u6ca1\u6709\u521d\u59cb\u5316\u6570\u503c\u7684\u6570\u7ec4\u3002\u4f46\u662f\uff0c\u4f7f\u7528np.empty\u6765\u751f\u6210\u4e00\u4e2a\u51680\u6570\u7ec4\uff0c\u5e76\u4e0d\u53ef\u9760\uff0c\u6709\u4e9b\u65f6\u5019\u5b83\u53ef\u80fd\u4f1a\u8fd4\u56de\u672a\u521d\u59cb\u5316\u7684\u5783\u573e\u6570\u503c print(np.empty((2, 3, 2))) # [[[2.30116964e-316 0.00000000e+000] # [2.10077583e-312 6.79038654e-313] # [2.22809558e-312 2.14321575e-312]] # # [[2.35541533e-312 6.79038654e-313] # [2.22809558e-312 2.14321575e-312] # [2.46151512e-312 2.41907520e-312]]]","title":"ndarray: N-\u7ef4\u6570\u7ec4\u5bf9\u8c61"},{"location":"python/DataAnalysis/ch01/#numpy_1","text":"\u4e00\u53e5\u8bdd\u603b\u7ed3\uff1a\u5c06NumPy\u8f74\u89c6\u4e3a\u6211\u4eec\u53ef\u4ee5\u6267\u884c\u64cd\u4f5c\u7684\u65b9\u5411\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a arr_1 = np.array([[1, 1, 1], [1, 1, 1]]) arr_2 = np.array([[9, 9, 9], [9, 9, 9]]) print(arr_1) # [[1 1 1] # [1 1 1]] print(arr_2) # [[9 9 9] # [9 9 9]] \u6cbf0\u8f74\u5408\u5e76\u7684\u601d\u8def\u662f\uff0c\u4e24\u4e2a\u6570\u7ec4\u6cbf0\u8f74\u65b9\u5411\uff0c\u54110\u8f74\u201c\u584c\u7f29\u201d\uff08collapse\uff09\u3002 result = np.concatenate([arr_1, arr_2], axis=0) print(result) # [[1 1 1] # [1 1 1] # [9 9 9] # [9 9 9]] \u6cbf1\u8f74\u5408\u5e76\u7684\u601d\u8def\u662f\uff0c\u4e24\u4e2a\u6570\u7ec4\u6cbf1\u8f74\u65b9\u5411\uff0c\u54111\u8f74\u201c\u584c\u7f29\u201d result = np.concatenate([arr_1, arr_2], axis=1) print(result) # [[1 1 1 9 9 9] # [1 1 1 9 9 9]] \u6211\u4eec\u6765\u770bNumPy\u7684\u4e09\u7ef4\u6570\u7ec4\u3002 array1 = np.arange(36).reshape((3, 3, 4)) print(array1) # [[[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] # # [[12 13 14 15] # [16 17 18 19] # [20 21 22 23]] # # [[24 25 26 27] # [28 29 30 31] # [32 33 34 35]]] \u8fd9\u6837\u770b\u4f1a\u5bb9\u6613\u7406\u89e3\u4e00\u4e9b\uff0c0\u8f74\u67093\u884c\uff0c1\u8f74\u67093\u5217\uff0c2\u8f74\u67094\u4e2a\u5143\u7d20\uff1a [[[ 0 1 2 3], [ 4 5 6 7], [ 8 9 10 11]] [[12 13 14 15], [16 17 18 19], [20 21 22 23]] [[24 25 26 27], [28 29 30 31], [32 33 34 35]]] \u8f93\u51fa\uff1a\u8f740\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f741\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f742\u7d22\u5f15\u53f7\uff1a\u5168\u90e8 print(array1[0, 0, :]) # [0 1 2 3] \u8f93\u51fa\uff1a\u8f740\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f741\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f742\u7d22\u5f15\u53f7\uff1a1 print(array1[0, 0, 1]) # 1","title":"NumPy\u8f74"},{"location":"python/DataAnalysis/ch01/#numpy_2","text":"\u4e00\u4e2a**\u6807\u91cf**\u5c31\u662f\u4e00\u4e2a\u5355\u72ec\u7684\u6570\u3002\u4e00\u4e2a\u5411\u91cf\u5c31\u662f\u4e00\u5217\u6570\uff0c\u8fd9\u4e9b\u6570\u662f\u6709\u5e8f\u6392\u5217\u7684\u3002 \u77e9\u9635\u662f\u4e8c\u7ef4\u6570\u7ec4\uff0c\u5176\u4e2d\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u88ab\u4e24\u4e2a\u7d22\u5f15\u800c\u975e\u4e00\u4e2a\u6240\u786e\u5b9a\u3002 \u51e0\u4f55\u4ee3\u6570\u4e2d\u5b9a\u4e49\u7684**\u5f20\u91cf**\u662f\u57fa\u4e8e\u5411\u91cf\u548c\u77e9\u9635\u7684\u63a8\u5e7f\uff0c\u6211\u4eec\u53ef\u4ee5**\u5c06\u6807\u91cf\u89c6\u4e3a\u96f6\u9636\u5f20\u91cf**\uff0c \u77e2\u91cf**\u89c6\u4e3a\u4e00\u9636\u5f20\u91cf\uff0c\u90a3\u4e48**\u77e9\u9635\u5c31\u662f\u4e8c\u9636\u5f20\u91cf \u3002 \u5e26\u6709\u6807\u91cf\u8ba1\u7b97\u7684\u7b97\u672f\u64cd\u4f5c\uff0c\u4f1a\u628a\u8ba1\u7b97\u53c2\u6570\u4f20\u9012\u7ed9\u6570\u7ec4\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u3002 \u540c\u5c3a\u5bf8\u6570\u7ec4\u4e4b\u95f4\u7684\u6bd4\u8f83 array04 == array04 \uff0c\u4f1a\u4ea7\u751f\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4 \u4e0d\u540c\u5c3a\u5bf8\u7684\u6570\u7ec4\u95f4\u7684\u64cd\u4f5c\uff0c\u5c06\u4f1a\u7528\u5230 \u5e7f\u64ad\u7279\u6027\uff08broadcasting\uff09 \u3002 array04 = np.array([ [1, 2, 3, 4, 5], [3, 4, 5, 6, 7], [5, 6, 7, 8, 9] ], dtype=int) print(array04 + array04) # [[ 2 4 6 8 10] # [ 6 8 10 12 14] # [10 12 14 16 18]] print(array04 - array04) # [[0 0 0 0 0] # [0 0 0 0 0] # [0 0 0 0 0]] print(array04 * array04) # [[ 1 4 9 16 25] # [ 9 16 25 36 49] # [25 36 49 64 81]] print(array04 / array04) # [[1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.]] print(1 / array04) # [[1. 0.5 0.33333333 0.25 0.2 ] # [0.33333333 0.25 0.2 0.16666667 0.14285714] # [0.2 0.16666667 0.14285714 0.125 0.11111111]] print(array04 == array04) # [[ True True True True True] # [ True True True True True] # [ True True True True True]]","title":"NumPy\u6570\u7ec4\u7b97\u672f"},{"location":"python/DataAnalysis/ch01/#_2","text":"ndarray\u5bf9\u8c61\u7684\u5185\u5bb9\u53ef\u4ee5\u901a\u8fc7\u7d22\u5f15\uff08indexing\uff09\u6216\u5207\u7247\uff08slicing\uff09\u6765\u8bbf\u95ee\u548c\u4fee\u6539\uff0cndarray\u5bf9\u8c61\u4e2d\u7684\u5143\u7d20\u7d22\u5f15\u4ece\u96f6\u5f00\u59cb\u3002 \u6709\u4e09\u79cd\u53ef\u7528\u7684\u7d22\u5f15\u65b9\u6cd5\uff1a\u5b57\u6bb5\u8bbf\u95ee\uff0c\u57fa\u672c\u5207\u7247\u548c\u9ad8\u7ea7\u7d22\u5f15\u3002 \u7d22\u5f15\uff08indexing\uff09\uff1a\u83b7\u53d6\u6570\u7ec4\u4e2d\u7279\u5b9a\u4f4d\u7f6e\u5143\u7d20\u7684\u8fc7\u7a0b\u3002 \u5207\u7247\uff08slicing\uff09\uff1a\u83b7\u53d6\u6570\u7ec4\u5143\u7d20\u5b50\u96c6\u7684\u8fc7\u7a0b\u3002\u6570\u7ec4\u7684\u5207\u7247\u662f\u539f\u6570\u7ec4\u7684\u89c6\u56fe\u3002\u8fd9\u610f\u5473\u7740\u4efb\u4f55**\u5bf9\u4e8e\u89c6\u56fe\u7684\u4fee\u6539\u90fd\u4f1a\u53cd\u6620\u5230\u539f\u6570\u7ec4\u4e0a**\u3002\u6570\u7ec4\u7684\u5207\u7247, \u8fd4\u56de\u7684\u5bf9\u8c61\u662f\u964d\u4f4e\u4e00\u4e2a\u7ef4\u5ea6\u7684\u6570\u7ec4\u3002 \u4e00\u7ef4\u6570\u7ec4\u7684\u7d22\u5f15\u548c\u5207\u7247\uff1a\u4e0ePython\u7684\u5217\u8868\u7c7b\u4f3c\uff1a a[n] \uff1a\u8fd4\u56de\u7b2c n+1 \u4e2a\u5143\u7d20\u3002\u5982\u679c n \u4e3a\u8d1f\u6570\uff0c\u5219\u8fd4\u56de\u5012\u6570\u7b2c n \u4e2a\u5143\u7d20\u3002 a[n:m:k] \uff1a\u8d77\u59cb\u7f16\u53f7 n \uff0c\u7ec8\u6b62\u7f16\u53f7 m \uff0c\u6b65\u957f k \uff0c\u7528\u5192\u53f7\u5206\u5272\u3002 \u9075\u5faa\u5de6\u95ed\u53f3\u5f00\u7684\u539f\u5219 \uff0c\u5373 [n, m) \u3002\u5982\u679c n \u4e3a\u7a7a\uff0c\u5373 n = 0 \uff1b\u5982\u679c m \u4e3a\u7a7a\uff0c\u5373 m = len(a) \u3002 \u591a\u7ef4\u6570\u7ec4\u7684\u7d22\u5f15\u548c\u5207\u7247\uff1a a[n,m,k,...] \uff1a\u6bcf\u4e2a\u7ef4\u5ea6\u4e00\u4e2a\u7d22\u5f15\u503c\uff0c\u6700\u5916\u5c42\u5217\u8868\uff08list\uff09\u4e2d\u7b2c n \u4e2a\u5143\u7d20\uff0c\u6b21\u5916\u5c42\u5217\u8868\uff08list\uff09\u4e2d\u7b2c m \u4e2a\u5143\u7d20\uff0c\u4ee5\u6b64\u7c7b\u63a8\u3002\u5982\u679c n \u4e3a\u8d1f\u6570\uff0c\u5219\u8fd4\u56de\u5012\u6570\u7b2c n \u4e2a\u5143\u7d20\u3002 a[n1:m1:k1,n2:m2:k2,n3:m3:k3,...] \uff1a\u6bcf\u4e2a\u7ef4\u5ea6\u7684\u5207\u7247\u65b9\u6cd5\u4e0e\u4e00\u7ef4\u6570\u7ec4\u76f8\u540c\u3002\u987a\u5e8f\u4e3a\u4ece\u5916\u5230\u5185\u3002 array05 = np.arange(10) print(array05) # [0 1 2 3 4 5 6 7 8 9] # \u4ece\u7d22\u5f15\u503c5\u5f00\u59cb\u5230\u7d22\u5f15\u503c7\u7684\u4e00\u4e2a\u5207\u7247\u3002 print(array05[5:8]) # [5 6 7] array06 = array05[5:8] # \u4f20\u5165\u4e00\u4e2a\u6570\u503c\u7ed9\u6570\u7ec4\u7684\u5207\u7247\uff0c\u6570\u503c\u88ab\u4f20\u9012\u7ed9\u4e86\u6574\u4e2a\u5207\u7247\u3002\u4e0d\u5199\u5207\u7247\u503c\u7684[:]\u5c06\u4f1a\u5f15\u7528\u6570\u7ec4\u7684\u6240\u6709\u503c array06[:] = 12 print(array06) # [12 12 12] # \u5207\u7247\u7684\u4fee\u6539\u4f1a\u53cd\u6620\u5230\u539f\u6570\u7ec4\u4e0a print(array05) # [ 0 1 2 3 4 12 12 12 8 9] # \u8f93\u51fa3\u7ef4\u77e9\u9635\uff0c3\u884c3\u5217\uff0c\u51719\u4e2a\u5143\u7d20\uff0c\u6bcf\u4e2a\u5143\u7d20\u662f\u4e00\u4e2a\u542b3\u4e2a\u5143\u7d20\u7684\u5217\u8868 array07 = np.array([ [[0, 1, 2], [3, 4, 5], [6, 7, 8]], [[9, 0, 1], [2, 3, 4], [5, 6, 7]], [[8, 9, 0], [1, 2, 3], [4, 5, 6]], ]) # \u8f93\u51fa3\u7ef4\u77e9\u9635\uff0c\u663e\u793a\u539f\u77e9\u9635\u7684\u7b2c1\uff0c2\u884c\u76842\uff0c3\u5217\u5143\u7d20\uff0c\u4e0d\u8981\u628a\u7d22\u5f15\u53f7\u548c\u8fd9\u91cc\u7684\u8868\u8ff0\u884c\u53f7\u6df7\u6dc6\u3002 print(array07[:2, 1:]) # [[[3 4 5] [6 7 8]] # [[2 3 4] [5 6 7]]] print(array07[:2, 1:].shape) # (2, 2, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c3\u884c print(array07[2]) # [[8 9 0] [1 2 3] [4 5 6]] print(array07[2].shape) # (3, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c3\u884c print(array07[2, :]) # [[8 9 0] [1 2 3] [4 5 6]] print(array07[2, :].shape) # (3, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c3\u884c\uff08\u53ea\u6709\u4e09\u884c\uff0c\u6240\u4ee5[2:, :]\u7b49\u540c\u4e8e[2, :]\uff09 print(array07[2:, :]) # [[[8 9 0] [1 2 3] [4 5 6]]] print(array07[2:, :].shape) # (1, 3, 3) # \u8f93\u51fa\u539f\u77e9\u9635\u76841\uff0c2\u5217 print(array07[:, :2]) # [[[0 1 2] [3 4 5]] # [[9 0 1] [2 3 4]] # [[8 9 0] [1 2 3]]] print(array07[:, :2].shape) # (3, 2, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u524d2\u4e2a\u5143\u7d20 print(array07[1, :2]) # [[9 0 1] [2 3 4]] print(array07[1, :2].shape) # (2, 3) # \u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u524d2\u4e2a\u5143\u7d20 print(array07[1:2, :2]) # [[[9 0 1] [2 3 4]]] print(array07[1:2, :2].shape) # (1, 2, 3) # \u5c06\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u8d4b\u503c\u7ed9\u53d8\u91cf old_value = array07[2].copy() print(old_value) # [[8 9 0] [1 2 3] [4 5 6]] # \u4fee\u6539\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u7684\u503c\uff0c\u6807\u91cf\u548c\u6570\u7ec4\u90fd\u53ef\u4ee5\u4f20\u9012\u7ed9 array07[2] array07[2] = 25 print(array07) # [[[ 0 1 2] [ 3 4 5] [ 6 7 8]] # [[ 9 0 1] [ 2 3 4] [ 5 6 7]] # [[25 25 25] [25 25 25] [25 25 25]]] # \u5c06\u53d8\u91cf\u503c\u8d4b\u503c\u7ed9\u539f\u77e9\u9635\u7684\u7b2c2\u884c array07[2] = old_value print(array07) # [[[0 1 2] [3 4 5] [6 7 8]] # [[9 0 1] [2 3 4] [5 6 7]] # [[8 9 0] [1 2 3] [4 5 6]]]","title":"\u57fa\u7840\u7d22\u5f15\u4e0e\u5207\u7247"},{"location":"python/DataAnalysis/ch01/#_3","text":"\u5e03\u5c14\u503c\u7d22\u5f15\uff08Boolean indexing\uff09\u662f\u901a\u8fc7\u4e00\u4e2a\u5e03\u5c14\u6570\u7ec4\u6765\u7d22\u5f15\u76ee\u6807\u6570\u7ec4\uff0c\u4ee5\u6b64\u627e\u51fa\u4e0e\u5e03\u5c14\u6570\u7ec4\u4e2d\u503c\u4e3aTrue\u7684\u5bf9\u5e94\u7684\u76ee\u6807\u6570\u7ec4\u4e2d\u7684\u6570\u636e\u3002\u5e03\u5c14\u6570\u7ec4\u7684\u957f\u5ea6\u5fc5\u987b\u4e0e\u76ee\u6807\u6570\u7ec4\u5bf9\u5e94\u7684\u8f74\u7684\u957f\u5ea6\u4e00\u81f4\u3002 \u4f7f\u7528\u5e03\u5c14\u503c\u7d22\u5f15\uff08Boolean indexing\uff09\u9009\u62e9\u6570\u636e\u65f6\uff0c\u603b\u662f\u751f\u6210\u6570\u636e\u7684\u62f7\u8d1d\uff0c\u5373\u4f7f\u8fd4\u56de\u7684\u6570\u7ec4\u5e76\u6ca1\u6709\u4efb\u4f55\u53d8\u5316\u3002 \u5047\u8bbe\u6211\u4eec\u7684\u6570\u636e\u90fd\u5728\u6570\u7ec4\u4e2d\uff0c\u5e76\u4e14\u6570\u7ec4\u4e2d\u7684\u6570\u636e\u662f\u4e00\u4e9b\u5b58\u5728\u91cd\u590d\u7684\u4eba\u540d\u3002\u7528randn\u51fd\u6570\u751f\u6210\u4e00\u4e9b\u6807\u51c6\u6b63\u6001(standard normal)\u5206\u5e03\u7684\u6570\u636e\u3002\u5047\u8bbe\u6bcf\u4e2a\u4eba\u540d\u90fd\u548cdata\u6570\u7ec4\u4e2d\u7684\u4e00\u884c\u76f8\u5bf9\u5e94\uff0c\u5e76\u4e14\u6211\u4eec\u60f3\u8981\u9009\u4e2d\u6240\u6709\u2019Bob\u2019\u5bf9\u5e94\u7684\u884c\u3002 names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype=' # \u56fe\u50cf\u6807\u9898 plt.title(\"$\\sqrt{x^2 + y^2}$ \u8ba1\u7b97\u503c\u7684\u7f51\u683c\u56fe\") # \u8f93\u51fa\u56fe\u50cf plt.show() \u8f93\u51fa\u56fe\u50cf\u4e3a\uff1a","title":"\u9762\u5411\u6570\u7ec4\u7f16\u7a0b"},{"location":"python/DataAnalysis/ch01/#_8","text":"numpy.where \u51fd\u6570\u662f\u4e09\u5143\u8868\u8fbe\u5f0f x if condition else y \u7684\u5411\u91cf\u5316\u7248\u672c\u3002 np.where \u7684\u7b2c\u4e8c\u4e2a\u548c\u7b2c\u4e09\u4e2a\u53c2\u6570\u5e76\u4e0d\u9700\u8981\u662f\u6570\u7ec4\uff0c\u5b83\u4eec\u53ef\u4ee5\u662f\u6807\u91cf\u3002 np.where \u5728\u6570\u636e\u5206\u6790\u4e2d\u7684\u4e00\u4e2a\u5178\u578b\u7528\u6cd5\u662f\u6839\u636e\u4e00\u4e2a\u6570\u7ec4\u6765\u751f\u6210\u4e00\u4e2a\u65b0\u7684\u6570\u7ec4\u3002 \u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4\u548c\u4e24\u4e2a\u6570\u503c\u6570\u7ec4\u3002\u5047\u8bbe cond \u4e2d\u7684\u5143\u7d20\u4e3a True \u65f6\uff0c\u6211\u4eec\u53d6 xarr \u4e2d\u7684\u5bf9\u5e94\u5143\u7d20\u503c\uff0c\u5426\u5219\u53d6 yarr \u4e2d\u7684\u5143\u7d20\u3002 xarray = np.array([1.1, 1.2, 1.3, 1.4, 1.5]) yarray = np.array([2.1, 2.2, 2.3, 2.4, 2.5]) cond = np.array([True, False, True, True, False]) \u901a\u8fc7\u5217\u8868\u63a8\u5bfc\u5f0f\u6765\u5b9e\u73b0\u4e0a\u8ff0\u9700\u6c42\u3002 \u7f3a\u70b9: \u9996\u5148\uff0c\u5982\u679c\u6570\u7ec4\u5f88\u5927\u7684\u8bdd\uff0c\u901f\u5ea6\u4f1a\u5f88\u6162\uff08\u56e0\u4e3a\u6240\u6709\u7684\u5de5\u4f5c\u90fd\u662f\u901a\u8fc7\u89e3\u91ca\u5668\u6765\u89e3\u91caPython\u4ee3\u7801\u5b8c\u6210\uff09\u3002 \u5176\u6b21\uff0c\u5f53\u6570\u7ec4\u662f\u591a\u7ef4\u65f6\uff0c\u5c31\u65e0\u6cd5\u51d1\u6548\u4e86\u3002 # \u901a\u8fc7\u5217\u8868\u63a8\u5bfc\u5f0f\u6765\u5b9e\u73b0 result = [(x if c else y) for x, y, c in zip(xarray, yarray, cond)] print(result) # [1.1, 2.2, 1.3, 1.4, 2.5] \u901a\u8fc7 np.where \u6765\u5b9e\u73b0\u4e0a\u8ff0\u9700\u6c42\u3002 result = np.where(cond, xarray, yarray) print(result) # [1.1 2.2 1.3 1.4 2.5] \u5047\u8bbe\u6709\u4e00\u4e2a\u968f\u673a\u751f\u6210\u7684\u77e9\u9635\u6570\u636e\uff0c\u4e0b\u9762\u4f7f\u7528np.where\u5b9e\u73b0\u66ff\u6362\u3002 array = np.random.randn(4, 4) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) print(\"\u77e9\u9635\u5143\u7d20\u662f\u5426\u5927\u4e8e0 \\n\", array > 0) # \u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2\uff0c\u5c06\u6240\u6709\u7684\u8d1f\u503c\u66ff\u6362\u4e3a-2 result03 = np.where(array > 0, 2, -2) print(\"\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2\uff0c\u5c06\u6240\u6709\u7684\u8d1f\u503c\u66ff\u6362\u4e3a-2 \\n\", result03) # \u4ec5\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2 result04 = np.where(array > 0, 2, array) print(\"\u4ec5\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2 \\n\", result04) # \u6837\u672c\u77e9\u9635 # [[-0.57177422 -0.34917512 2.20268075 1.99959296] # [ 0.67966599 2.67915099 -0.40528454 -0.80339907] # [-0.74406888 2.33802717 -0.74582936 0.59347128] # [ 0.68624473 0.65953112 -0.40871415 -0.68698878]] # \u77e9\u9635\u5143\u7d20\u662f\u5426\u5927\u4e8e0 # [[False False True True] # [ True True False False] # [False True False True] # [ True True False False]] # \u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2\uff0c\u5c06\u6240\u6709\u7684\u8d1f\u503c\u66ff\u6362\u4e3a-2 # [[-2 -2 2 2] # [ 2 2 -2 -2] # [-2 2 -2 2] # [ 2 2 -2 -2]] # \u4ec5\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2 # [[-0.57177422 -0.34917512 2. 2. ] # [ 2. 2. -0.40528454 -0.80339907] # [-0.74406888 2. -0.74582936 2. ] # [ 2. 2. -0.40871415 -0.68698878]]","title":"\u901a\u8fc7\u6761\u4ef6\u903b\u8f91\u64cd\u4f5c\u6570\u7ec4"},{"location":"python/DataAnalysis/ch01/#_9","text":"NumPy\u6709\u4e00\u4e9b\u4e13\u95e8\u7684\u6570\u5b66\u51fd\u6570\uff0c\u7528\u6765\u8ba1\u7b97\u6574\u4e2a\u6570\u7ec4\u7edf\u8ba1\u503c\u6216\u8f74\u5411\u6570\u636e\u7684\u8ba1\u7b97\u3002\u4f8b\u5982\uff0c\u805a\u5408\u51fd\u6570\uff08\u901a\u5e38\u4e5f\u53eb\u7f29\u51cf\u51fd\u6570\uff09\uff0c\u5982sum\u3001mean\u548cstd\uff08\u6807\u51c6\u5dee\uff09\u3002 \u65e2\u53ef\u4ee5\u76f4\u63a5\u8c03\u7528\u6570\u7ec4\u5b9e\u4f8b\u7684\u65b9\u6cd5\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u9876\u5c42\u7684NumPy\u51fd\u6570\u3002 \u4e3e\u4f8b\uff1a\u751f\u6210\u4e00\u4e9b\u6b63\u6001\u5206\u5e03\u7684\u968f\u673a\u6570\uff0c\u8ba1\u7b97\u90e8\u5206\u805a\u5408\u7edf\u8ba1\u6570\u636e\u3002 \u8fd9\u91cc\u518d\u5bf9\u8f74\u5411\u505a\u4e2a\u89e3\u91ca\uff0c np.random.randn(5, 4) \u4ea7\u751f\u7684\u4e8c\u7ef4\u6570\u7ec4\u662f\uff1a0\u8f74\u54115\u4e2a\u5143\u7d20, 1\u8f74\u54114\u4e2a\u5143\u7d20\u3002 # \u751f\u62102\u8f74\u6570\u7ec4 array = np.random.randn(5, 4) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) print(\"\u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c\", array.mean()) print(\"\u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c\", np.mean(array)) print(\"\u77e9\u9635\u5143\u7d20\u548c\", array.sum()) print(\"\u77e9\u9635\u5143\u7d20\u548c\", np.sum(array)) print(\"0\u8f74\u5411\u7684\u7d2f\u548c\", array.sum(axis=0)) print(\"1\u8f74\u5411\u7684\u7d2f\u548c\", array.sum(axis=1)) print(\"1\u8f74\u5411\u7684\u5e73\u5747\u503c\", array.mean(axis=1)) # \u6837\u672c\u77e9\u9635 shape=(5, 4) 0\u8f74\u54115\u4e2a\u5143\u7d20, 1\u8f74\u54114\u4e2a\u5143\u7d20 # [[ 0.32532911 -0.00177984 -1.59432632 1.58375133] # [ 1.48921763 0.25202456 0.44076148 -1.02277289] # [-0.73490219 0.19197171 -0.22374362 0.52610852] # [-1.03531076 1.0595528 -0.11566501 0.34063544] # [-0.2122241 -0.81348187 1.70989712 -0.00732696]] # \u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c 0.10788580775057008 # \u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c 0.10788580775057008 # \u77e9\u9635\u5143\u7d20\u548c 2.1577161550114017 # \u77e9\u9635\u5143\u7d20\u548c 2.1577161550114017 # 0\u8f74\u5411\u7684\u7d2f\u548c [-0.16789031 0.68828737 0.21692365 1.42039545] # 1\u8f74\u5411\u7684\u7d2f\u548c [ 0.31297429 1.15923078 -0.24056558 0.24921247 0.67686419] # 1\u8f74\u5411\u7684\u5e73\u5747\u503c [ 0.07824357 0.28980769 -0.06014139 0.06230312 0.16921605] \u4e0b\u9762\u5217\u4e3e\u4e86\u5e38\u7528\u7684\u57fa\u7840\u6570\u7ec4\u7edf\u8ba1\u65b9\u6cd5\u3002 array = np.array([ [1, 2, 3, 4, 5], [3, 4, 5, 6, 7], [5, 6, 7, 8, 9] ], dtype=int) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) print(\"\u8f74\u5411\u6c42\u548c\", array.sum()) print(\"\u8f74\u5411\u6c42\u548c\", array.sum(axis=0)) print(\"\u6570\u5b66\u5e73\u5747\", array.mean()) print(\"\u8f74\u5411\u6570\u5b66\u5e73\u5747\", array.mean(axis=0)) print(\"\u6807\u51c6\u5dee\", array.std(), \"\u65b9\u5dee\", array.var()) print(\"\u8f74\u5411\u6807\u51c6\u5dee\", array.std(axis=0), \"\u8f74\u5411\u65b9\u5dee\", array.var(axis=0)) print(\"\u6700\u5c0f\u503c\", array.min(), \"\u6700\u5927\u503c\", array.max()) print(\"\u8f74\u5411\u6700\u5c0f\u503c\", array.min(axis=0), \"\u8f74\u5411\u6700\u5927\u503c\", array.max(axis=0)) print(\"\u6700\u5c0f\u503c\u4f4d\u7f6e\", array.argmin(), \"\u6700\u5927\u503c\u4f4d\u7f6e\", array.argmax()) print(\"\u8f74\u5411\u6700\u5c0f\u503c\u4f4d\u7f6e\", array.argmin(axis=0), \"\u8f74\u5411\u6700\u5927\u503c\u4f4d\u7f6e\", array.argmax(axis=0)) print(\"\u7d2f\u79ef\u548c \\n\", array.cumsum()) print(\"\u8f74\u5411\u7d2f\u79ef\u548c \\n\", array.cumsum(axis=1)) print(\"\u7d2f\u79ef\u4e58\u79ef \\n\", array.cumprod()) print(\"\u8f74\u5411\u7d2f\u79ef\u4e58\u79ef \\n\", array.cumprod(axis=1)) # \u6837\u672c\u77e9\u9635 # [[1 2 3 4 5] # [3 4 5 6 7] # [5 6 7 8 9]] # \u8f74\u5411\u6c42\u548c 75 # \u8f74\u5411\u6c42\u548c [ 9 12 15 18 21] # \u6570\u5b66\u5e73\u5747 5.0 # \u8f74\u5411\u6570\u5b66\u5e73\u5747 [3. 4. 5. 6. 7.] # \u6807\u51c6\u5dee 2.160246899469287 \u65b9\u5dee 4.666666666666667 # \u8f74\u5411\u6807\u51c6\u5dee [1.63299316 1.63299316 1.63299316 1.63299316 1.63299316] \u8f74\u5411\u65b9\u5dee [2.66666667 2.66666667 2.66666667 2.66666667 2.66666667] # \u6700\u5c0f\u503c 1 \u6700\u5927\u503c 9 # \u8f74\u5411\u6700\u5c0f\u503c [1 2 3 4 5] \u8f74\u5411\u6700\u5927\u503c [5 6 7 8 9] # \u6700\u5c0f\u503c\u4f4d\u7f6e 0 \u6700\u5927\u503c\u4f4d\u7f6e 14 # \u8f74\u5411\u6700\u5c0f\u503c\u4f4d\u7f6e [0 0 0 0 0] \u8f74\u5411\u6700\u5927\u503c\u4f4d\u7f6e [2 2 2 2 2] # \u7d2f\u79ef\u548c # [ 1 3 6 10 15 18 22 27 33 40 45 51 58 66 75] # \u8f74\u5411\u7d2f\u79ef\u548c # [[ 1 3 6 10 15] # [ 3 7 12 18 25] # [ 5 11 18 26 35]] # \u7d2f\u79ef\u4e58\u79ef # [ 1 2 6 24 120 360 # 1440 7200 43200 302400 1512000 9072000 # 63504000 508032000 4572288000] # \u8f74\u5411\u7d2f\u79ef\u4e58\u79ef # [[ 1 2 6 24 120] # [ 3 12 60 360 2520] # [ 5 30 210 1680 15120]]","title":"\u6570\u5b66\u548c\u7edf\u8ba1\u65b9\u6cd5"},{"location":"python/DataAnalysis/ch01/#boolean-array","text":"\u5e03\u5c14\u503c\u6570\u7ec4\uff0c\u6709\u4e24\u4e2a\u975e\u5e38\u6709\u7528\u7684\u65b9\u6cd5any\u548call\u3002 * any\u68c0\u67e5\u6570\u7ec4\u4e2d\u662f\u5426\u81f3\u5c11\u6709\u4e00\u4e2aTrue\uff0c * all\u68c0\u67e5\u662f\u5426\u6bcf\u4e2a\u503c\u90fd\u662fTrue bools = np.array([False, False, True, False]) print(bools.any()) # True print(bools.all()) # False \u4e0b\u9762\u662f\u4e00\u4e2a\u8fd0\u7528\u5e03\u5c14\u503c\u6570\u7ec4\uff08Boolean Array\uff09\u8fdb\u884c\u6c42\u548c\u7684\u4e00\u4e2a\u4f8b\u5b50\uff0c\u5176\u4e2d (array > 0) \u672c\u8eab\u662f\u4e00\u4e2a\u5e03\u5c14\u578b\u7684\u6570\u7ec4\u3002 array = np.random.randn(100) result = (array > 0).sum() # \u8ba1\u7b97\u6b63\u503c\u7684\u4e2a\u6570 print(result) # 59 \u4e0b\u9762\u662f\u8fd0\u7528\u5e03\u5c14\u503c\u6570\u7ec4\u7684\u751f\u6210\u65b0\u6570\u7ec4\u7684\u4f8b\u5b50\u3002 arr = [[8, 9, 10, 11], [0, 1, 2, 3], [4, 5, 6, 7]] arr = np.array(arr) print(arr.shape) # (3, 4) print(arr) # [[ 8 9 10 11] # [ 0 1 2 3] # [ 4 5 6 7]] idx = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]] idx = np.array(idx) print(idx.shape) # (3, 4) print(idx) # [[1 0 0 0] # [0 1 0 0] # [0 0 1 0]] result = arr[idx] # print(result.shape) # (3, 4, 4) print(result) # [[[ 0 1 2 3] # [ 8 9 10 11] # [ 8 9 10 11] # [ 8 9 10 11]] # [[ 8 9 10 11] # [ 0 1 2 3] # [ 8 9 10 11] # [ 8 9 10 11]] # [[ 8 9 10 11] # [ 8 9 10 11] # [ 0 1 2 3] # [ 8 9 10 11]]] result = arr[idx == 1] print(result.shape) print(result) # [8 1 6]","title":"\u5e03\u5c14\u503c\u6570\u7ec4(Boolean Array)\u7684\u65b9\u6cd5"},{"location":"python/DataAnalysis/ch01/#_10","text":"\u548cPython\u7684\u5185\u5efa\u5217\u8868\u7c7b\u578b\u76f8\u4f3c\uff0cNumPy\u6570\u7ec4\u53ef\u4ee5\u4f7f\u7528sort\u65b9\u6cd5\u6309\u4f4d\u7f6e\u6392\u5e8f\u3002 \u9876\u5c42\u7684np.sort\u65b9\u6cd5\u8fd4\u56de\u7684\u662f\u5df2\u7ecf\u6392\u5e8f\u597d\u7684\u6570\u7ec4*\u62f7\u8d1d*\uff0c\u800c\u4e0d\u662f\u5bf9\u539f\u6570\u7ec4\u6309\u4f4d\u7f6e\u6392\u5e8f\u3002 array = np.random.randn(6) print(\"\u6837\u672c\u77e9\u9635\", array) array.sort() print(\"\u6392\u5e8f\u540e\u77e9\u9635\", array) # \u6837\u672c\u77e9\u9635 [-0.03119521 0.01839556 0.79238537 -2.46622775 0.62522211 0.22430846] # \u6392\u5e8f\u540e\u77e9\u9635 [-2.46622775 -0.03119521 0.01839556 0.22430846 0.62522211 0.79238537] \u591a\u7ef4\u6570\u7ec4\u4e2d\u6839\u636e\u4f20\u9012\u7684axis\u503c\uff0c\u6cbf\u7740\u8f74\u5411\u5bf9\u6bcf\u4e2a\u4e00\u7ef4\u6570\u636e\u6bb5\u8fdb\u884c\u6392\u5e8f\u3002 array = np.random.randn(5, 3) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) array.sort(1) print(\"\u5bf91\u8f74\u6392\u5e8f\u540e\u77e9\u9635 \\n\", array) # \u6837\u672c\u77e9\u9635 # [[-0.88057833 0.30160954 -2.08788148] # [ 0.27969618 0.62923028 -0.58157581] # [-1.87194465 -1.1102104 1.09589605] # [ 0.1467938 -1.01558304 -0.25905165] # [-0.17294279 0.62369511 0.17947059]] # \u5bf91\u8f74\u6392\u5e8f\u540e\u77e9\u9635 # [[-2.08788148 -0.88057833 0.30160954] # [-0.58157581 0.27969618 0.62923028] # [-1.87194465 -1.1102104 1.09589605] # [-1.01558304 -0.25905165 0.1467938 ] # [-0.17294279 0.17947059 0.62369511]]","title":"\u6392\u5e8f"},{"location":"python/DataAnalysis/ch01/#_11","text":"NumPy\u5305\u542b\u4e00\u4e9b\u9488\u5bf9\u4e00\u7ef4 ndarray \u6570\u7ec4\u7684\u57fa\u7840\u96c6\u5408\u64cd\u4f5c\u3002 np.unique(x, y) \u8ba1\u7b97x\u7684\u552f\u4e00\u503c\uff0c\u5e76\u6392\u5e8f\u3002 names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe']) result = np.unique(names) # NumPy\u5b9e\u73b0 print(result) # ['Bob' 'Joe' 'Will'] result = sorted(set(names)) # \u7eafPython\u5b9e\u73b0 print(result) # ['Bob' 'Joe' 'Will'] inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) result = np.unique(inits) print(result) # [1 2 3 5] np.in1d(x, y) \u8ba1\u7b97x\u4e2d\u7684\u5143\u7d20\u662f\u5426\u5305\u542b\u5728y\u4e2d\uff0c\u5e76\u8fd4\u56de\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.in1d(inits, [3, 4, 5])) # [ True True True False False False False True True] np.intersect1d(x, y) \uff0c\u8ba1\u7b97x\u548cy\u7684\u4ea4\u96c6\uff0c\u5e76\u6392\u5e8f\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.intersect1d(inits, [3, 4, 5])) # [3 5] np.union1d(x, y) \u8ba1\u7b97x\u548cy\u7684\u5e76\u96c6\uff0c\u5e76\u6392\u5e8f\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.union1d(inits, [3, 4, 5])) # [1 2 3 4 5] np.setdiff1d(x, y) \u5dee\u96c6\uff0c\u5728x\u4e2d\u4f46\u4e0d\u5728y\u4e2d\u7684\u5143\u7d20\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.setdiff1d(inits, [3, 4, 5])) # [1 2] np.setxor1d(x, y) \u5f02\u6216\u96c6\uff0c\u5728x\u6216\u8005y\u4e2d\uff0c\u4f46\u4e0d\u5c5e\u4e8ex\uff0cy\u4ea4\u96c6\u7684\u5143\u7d20\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.setxor1d(inits, [3, 4, 5])) # [1 2 4]","title":"\u552f\u4e00\u503c\u4e0e\u5176\u4ed6\u96c6\u5408\u903b\u8f91"},{"location":"python/DataAnalysis/ch01/#_12","text":"NumPy\u53ef\u4ee5\u5728\u786c\u76d8\u4e2d\u5c06\u6570\u636e\u4ee5\u6587\u672c\u6216\u4e8c\u8fdb\u5236\u6587\u4ef6\u7684\u5f62\u5f0f\u8fdb\u884c\u5b58\u5165\u786c\u76d8\u6216\u7531\u786c\u76d8\u8f7d\u5165\u3002 \u5f53\u524d\u53ea\u5173\u6ce8NumPy\u7684\u5185\u5efa\u4e8c\u8fdb\u5236\u683c\u5f0f\uff0c\u56e0\u4e3a\u5927\u90e8\u5206\u7528\u6237\u66f4\u503e\u5411\u4e8e\u4f7f\u7528pandas\u6216\u5176\u4ed6\u5de5\u5177\u6765\u8f7d\u5165\u6587\u672c\u6216\u8868\u683c\u578b\u6570\u636e\u3002 np.save \u548c np.load \u662f\u9ad8\u6548\u5b58\u53d6\u786c\u76d8\u6570\u636e\u7684\u4e24\u5927\u5de5\u5177\u51fd\u6570\u3002\u6570\u7ec4\u5728\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u662f\u4ee5*\u672a\u538b\u7f29*\u7684\u683c\u5f0f\u8fdb\u884c\u5b58\u50a8\u7684\uff0c\u540e\u7f00\u540d\u662f.npy\u3002 import numpy as np array1 = np.arange(10) array2 = np.arange(15).reshape(3, 5) array3 = np.arange(30).reshape(3, 2, 5) print(array1) # [0 1 2 3 4 5 6 7 8 9] print(array2) # [[ 0 1 2 3 4] # [ 5 6 7 8 9] # [10 11 12 13 14]] print(array3) # [[[ 0 1 2 3 4] # [ 5 6 7 8 9]] # [[10 11 12 13 14] # [15 16 17 18 19]] # [[20 21 22 23 24] # [25 26 27 28 29]]] # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os.getcwd() # '/opt/myProject/mySite' # \u66f4\u6539\u9ed8\u8ba4\u8def\u5f84 os.chdir('/opt/myProject/mySite/docs/python/datasets/examples') # \u4fdd\u5b58\u5230\u9ed8\u8ba4\u8def\u5f84\u3002npy\u540e\u7f00\u540d\u4f1a\u88ab\u81ea\u52a8\u52a0\u4e0a np.save('some_array', array1) # \u8bfb\u53d6\u6240\u4fdd\u5b58\u7684\u6587\u4ef6 result = np.load('some_array.npy') # \u5bf9\u6bd4\u7ed3\u679c\u4e00\u81f4\u3002 print(result) # [0 1 2 3 4 5 6 7 8 9] # \u5c06\u591a\u4e2a\u6570\u7ec4\u4fdd\u5b58\u5230\u672a\u538b\u7f29\u7684\u5355\u4e2a\u6587\u4ef6\u4e2d\uff0c.npz\u683c\u5f0f np.savez('some_array_archive.npz', a=array2, b=array3) result = np.load('some_array_archive.npz') # reslt\u662f\u4e00\u4e2a\u5b57\u5178\u578b\u7684\u5bf9\u8c61 print(result['b']) # \u8f7d\u5165\u5355\u4e2a\u6570\u7ec4b # [[[ 0 1 2 3 4] # [ 5 6 7 8 9]] # [[10 11 12 13 14] # [15 16 17 18 19]] # [[20 21 22 23 24] # [25 26 27 28 29]]]","title":"\u4f7f\u7528\u6570\u7ec4\u8fdb\u884c\u6587\u4ef6\u8f93\u5165\u548c\u8f93\u51fa"},{"location":"python/DataAnalysis/ch01/#_13","text":"\u53c2\u8003\u94fe\u63a5\uff1a https://www.numpy.org.cn/reference/routines/linalg.html https://github.com/teadocs/numpy-cn \u5e0c\u814a\u5b57\u6bcd: \u0391 \u03b1 /'\u00e6lf\u0259/ alpha \u0392 \u03b2 /'bi:t\u0259/ beta \u0393 \u03b3 /'g\u00e6m\u0259/ gamma \u0394 \u03b4 /'delt\u0259/ delta \u0395 \u03b5 /'eps\u026al\u0252n/ epsilon \u0396 \u03b6 /'zi:t\u0259/ zeta \u0397 \u03b7 /'i:t\u0259/ eta \u0398 \u03b8 /'\u03b8i:t\u0259/ theta \u0399 \u03b9 /'a\u026a\u0259\u028at\u0259/ iota \u039a \u03ba /'k\u00e6p\u0259/ kappa \u2227 \u03bb /'l\u00e6md\u0259/ lambda \u039c \u03bc /mju:/ mu \u039d \u03bd /nju:/ nu \u039e \u03be /ksi/ xi \u039f \u03bf /\u0259u\u02c8maikr\u0259n/ omicron \u220f \u03c0 /pa\u026a/ pi \u03a1 \u03c1 /r\u0259\u028a/ rho \u2211 \u03c3 /'s\u026a\u0261m\u0259/ sigma \u03a4 \u03c4 /t\u0254:/ tau \u03a5 \u03c5 /\u02c8ips\u026alon/ upsilon \u03a6 \u03c6 /fa\u026a/ phi \u03a7 \u03c7 /ka\u026a/ chi \u03a8 \u03c8 /psa\u026a/ psi \u03a9 \u03c9 /'\u0259\u028am\u026a\u0261\u0259/ omega numpy.linalg \u6a21\u5757\u5305\u542b\u7ebf\u6027\u4ee3\u6570\u7684\u51fd\u6570\u3002\u4f7f\u7528\u8fd9\u4e2a\u6a21\u5757\uff0c\u53ef\u4ee5\u8ba1\u7b97\u9006\u77e9\u9635\u3001\u6c42\u7279\u5f81\u503c\u3001\u89e3\u7ebf\u6027\u65b9\u7a0b\u7ec4\u4ee5\u53ca\u6c42\u89e3\u884c\u5217\u5f0f\u7b49\u3002 import numpy as np from numpy import linalg as LA from numpy import * from numpy.linalg import inv import matplotlib.pyplot as plt","title":"\u7ebf\u6027\u4ee3\u6570"},{"location":"python/DataAnalysis/ch01/#diag","text":"np.diag \u5c06\u4e00\u4e2a\u65b9\u9635\u7684\u5bf9\u89d2\uff08\u6216\u975e\u5bf9\u89d2\uff09\u5143\u7d20\u4f5c\u4e3a\u4e00\u7ef4\u6570\u7ec4\u8fd4\u56de\uff0c\u6216\u8005\u5c06\u4e00\u7ef4\u6570\u7ec4\u8f6c\u6362\u6210\u4e00\u4e2a\u65b9\u9635\uff0c\u5e76\u4e14\u5728\u975e\u5bf9\u89d2\u7ebf\u4e0a\u6709\u96f6\u70b9\u3002 a1 = np.arange(9, dtype=float).reshape((3, 3)) r1 = np.diag(a1) r2 = np.diag(a1, k=1) r3 = np.diag(a1, k=-1) r4 = np.diag(np.diag(a1)) # \u5bf9\u89d2\u77e9\u9635 print(\"\u6837\u672c\u77e9\u9635 \\n\", a1) print(\"\u77e9\u9635\u5bf9\u89d2\u7ebf\", r1) print(\"\u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0a\u504f\u79fb\", r2) print(\"\u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0b\u504f\u79fb\", r3) print(\"\u5bf9\u89d2\u77e9\u9635 \\n\", r4) # \u6837\u672c\u77e9\u9635 # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]] # \u77e9\u9635\u5bf9\u89d2\u7ebf [0. 4. 8.] # \u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0a\u504f\u79fb [1. 5.] # \u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0b\u504f\u79fb [3. 7.] # \u5bf9\u89d2\u77e9\u9635 # [[0. 0. 0.] # [0. 4. 0.] # [0. 0. 8.]]","title":"diag"},{"location":"python/DataAnalysis/ch01/#dot","text":"np.dot \u5c06\u5411\u91cf\u4e2d\u5bf9\u5e94\u5143\u7d20\u76f8\u4e58\uff0c\u518d\u76f8\u52a0\u6240\u5f97\u3002\u5373\u666e\u901a\u7684\u5411\u91cf\u4e58\u6cd5\u8fd0\u7b97\uff0c\u6216**\u77e9\u9635\u70b9\u4e58**\u3002 a1 = np.dot(3, 4) print(a1) # 12 a2 = np.arange(9, dtype=float).reshape((3, 3)) r2 = np.dot(a2, a2) print(a2) # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]] print(r2) # [[ 15. 18. 21.] # [ 42. 54. 66.] # [ 69. 90. 111.]] r3 = np.dot([2j, 3j], [2j, 3j]) print(r3) # (-13+0j)","title":"dot"},{"location":"python/DataAnalysis/ch01/#trace","text":"np.trace \u8ba1\u7b97\u5bf9\u89d2\u5143\u7d20\u548c\u3002 a1 = np.arange(9, dtype=float).reshape((3, 3)) print(\"\u6837\u672c\u77e9\u9635 \\n\", a1) r1 = np.trace(a1) print(\"\u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c\", r1) a2 = np.arange(24, dtype=float).reshape((2, 3, 4)) r2 = np.trace(a2) print(\"\u6837\u672c\u77e9\u9635 \\n\", a2) print(\"\u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c\", r2) # \u6837\u672c\u77e9\u9635 # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]] # \u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c 12.0 # \u6837\u672c\u77e9\u9635 # [[[ 0. 1. 2. 3.] # [ 4. 5. 6. 7.] # [ 8. 9. 10. 11.]] # # [[12. 13. 14. 15.] # [16. 17. 18. 19.] # [20. 21. 22. 23.]]] # \u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c [16. 18. 20. 22.]","title":"trace"},{"location":"python/DataAnalysis/ch01/#det","text":"np.det \u8ba1\u7b97\u77e9\u9635\u7684\u884c\u5217\u5f0f\uff08\u65b9\u9635\uff09\u3002 \u4e8c\u9636\u884c\u5217\u5f0f[[a, b], [c, d]]\u7684\u503c\u662fad - bc \u4e09\u9636\u884c\u5217\u5f0f [[a, b, c], [d, e, f], [g, h, i]]\u7684\u503c\u662f aei + bfd + cdh - ceg - bdi - afh \u4e09\u9636\u884c\u5217\u5f0f\u7684\u6027\u8d28 \u6027\u8d281\uff1a\u884c\u5217\u5f0f\u4e0e\u5b83\u7684\u8f6c\u7f6e\u884c\u5217\u5f0f\u76f8\u7b49\u3002 \u6027\u8d282\uff1a\u4e92\u6362\u884c\u5217\u5f0f\u7684\u4e24\u884c(\u5217)\uff0c\u884c\u5217\u5f0f\u53d8\u53f7\u3002 \u63a8\u8bba\uff1a\u5982\u679c\u884c\u5217\u5f0f\u6709\u4e24\u884c(\u5217)\u5b8c\u5168\u76f8\u540c\uff0c\u5219\u6b64\u884c\u5217\u5f0f\u4e3a\u96f6\u3002 \u6027\u8d283\uff1a\u884c\u5217\u5f0f\u7684\u67d0\u4e00\u884c(\u5217)\u4e2d\u6240\u6709\u7684\u5143\u7d20\u90fd\u4e58\u4ee5\u540c\u4e00\u6570k\uff0c\u7b49\u4e8e\u7528\u6570k\u4e58\u6b64\u884c\u5217\u5f0f\u3002 \u63a8\u8bba\uff1a\u884c\u5217\u5f0f\u4e2d\u67d0\u4e00\u884c(\u5217)\u7684\u6240\u6709\u5143\u7d20\u7684\u516c\u56e0\u5b50\u53ef\u4ee5\u63d0\u5230\u884c\u5217\u5f0f\u7b26\u53f7\u7684\u5916\u9762\u3002 \u6027\u8d284\uff1a\u884c\u5217\u5f0f\u4e2d\u5982\u679c\u6709\u4e24\u884c(\u5217)\u5143\u7d20\u6210\u6bd4\u4f8b\uff0c\u5219\u6b64\u884c\u5217\u5f0f\u7b49\u4e8e\u96f6\u3002 \u6027\u8d285\uff1a\u628a\u884c\u5217\u5f0f\u7684\u67d0\u4e00\u5217(\u884c)\u7684\u5404\u5143\u7d20\u4e58\u4ee5\u540c\u4e00\u6570\u7136\u540e\u52a0\u5230\u53e6\u4e00\u5217(\u884c)\u5bf9\u5e94\u7684\u5143\u7d20\u4e0a\u53bb\uff0c\u884c\u5217\u5f0f\u4e0d\u53d8\u3002 a1 = np.array([[1, 2], [3, 4]]) r1 = np.linalg.det(a1) print(\"\u4e8c\u9636\u65b9\u9635 \\n\", a1) print(\"\u4e8c\u9636\u884c\u5217\u5f0f\u7684\u503c\", r1) # \u4e8c\u9636\u65b9\u9635 # [[1 2] # [3 4]] # \u4e8c\u9636\u884c\u5217\u5f0f\u7684\u503c -2.0000000000000004 # \u5e0c\u814a\u5b57\u6bcd # \u03b1, \u03b2, \u03b3,\u03b4, \u03b5, \u03b6, \u03b7, \u03b8, \u03b9, \u03ba, \u03bb, \u03bc, \u03bd, # \u03be, \u03bf, \u03c0, \u03c1, \u03c2, \u03c3, \u03c4, \u03c5, \u03c6, \u03c7, \u03c8, \u03c9, a2 = np.arange(9).reshape(3, 3) r2 = np.linalg.det(a2) print(\"\u4e09\u9636\u65b9\u9635 \\n\", a2) print(\"\u4e09\u9636\u884c\u5217\u5f0f\u7684\u503c\", r2) # \u4e09\u9636\u65b9\u9635 # [[0 1 2] # [3 4 5] # [6 7 8]] # \u4e09\u9636\u884c\u5217\u5f0f\u7684\u503c 0.0 a3 = np.arange(16).reshape(4, 4) r3 = np.linalg.det(a3) print(\"\u56db\u9636\u65b9\u9635 \\n\", a3) print(\"\u56db\u9636\u884c\u5217\u5f0f\u7684\u503c\", r3) # \u56db\u9636\u65b9\u9635 # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]# \u5e0c\u814a\u5b57\u6bcd # \u03b1, \u03b2, \u03b3,\u03b4, \u03b5, \u03b6, \u03b7, \u03b8, \u03b9, \u03ba, \u03bb, \u03bc, \u03bd, # \u03be, \u03bf, \u03c0, \u03c1, \u03c2, \u03c3, \u03c4, \u03c5, \u03c6, \u03c7, \u03c8, \u03c9, # [12 13 14 15]] # \u56db\u9636\u884c\u5217\u5f0f\u7684\u503c 0.0","title":"det"},{"location":"python/DataAnalysis/ch01/#eig","text":"np.eig \u8ba1\u7b97\u65b9\u9635\u7684\u7279\u5f81\u503c\u548c\u7279\u5f81\u5411\u91cf\u3002 \u7279\u5f81\u503c\u4e0e\u7279\u5f81\u5411\u91cf\u7684\u5b9a\u4e49\uff1a\u8bbeA\u662fn\u9636\u65b9\u9635\uff0c\u82e5\u6570\u03bb\u548cn\u7ef4\u975e\u96f6\u5217\u5411\u91cfx\uff0c\u4f7f\u5f97Ax = \u03bbx\u6210\u7acb\uff0c\u5219\u79f0\u03bb\u662f\u65b9\u9635A\u7684\u4e00\u4e2a\u7279\u5f81\u503c\uff0cx\u4e3a\u65b9\u9635A\u7684\u5bf9\u5e94\u4e8e\u7279\u5f81\u503c\u03bb\u7684\u4e00\u4e2a\u7279\u5f81\u5411\u91cf\u3002 A\u662f\u65b9\u9635\u3002\uff08\u5bf9\u4e8e\u975e\u65b9\u9635\uff0c\u662f\u6ca1\u6709\u7279\u5f81\u503c\u7684\uff0c\u4f46\u4f1a\u6709\u6761\u4ef6\u6570\u3002\uff09\u7279\u5f81\u5411\u91cfx\u4e3a\u975e\u96f6\u5217\u5411\u91cf\u3002 v_eigenvectors, v_eigenvalues = LA.eig(np.diag((1, 2, 3))) print(\"\u7279\u5f81\u5411\u91cf\", v_eigenvectors) print(\"\u7279\u5f81\u503c \\n\", v_eigenvalues) # \u7279\u5f81\u5411\u91cf [1. 2. 3.] # \u7279\u5f81\u503c # [[1. 0. 0.] # [0. 1. 0.] # [0. 0. 1.]] v_eigenvectors, v_eigenvalues = LA.eig(np.array([[1, -1], [1, 1]])) print(\"\u7279\u5f81\u5411\u91cf\", v_eigenvectors) print(\"\u7279\u5f81\u503c \\n\", v_eigenvalues) # \u7279\u5f81\u5411\u91cf [1.+1.j 1.-1.j] # \u7279\u5f81\u503c # [[0.70710678+0.j 0.70710678-0.j ] # [0. -0.70710678j 0. +0.70710678j]]","title":"eig"},{"location":"python/DataAnalysis/ch01/#inv","text":"np.inv \u8ba1\u7b97\u65b9\u9635\u7684\u9006\u77e9\u9635\u3002 a1 = np.array([[1, 2], [3, 4]]) r1 = inv(a1) r2 = inv(np.matrix(a1)) print(\"\u539f\u77e9\u9635 \\n\", a1) print(\"\u9006\u77e9\u9635 \\n\", r1) print(\"\u9006\u77e9\u9635 \\n\", r2) # \u539f\u77e9\u9635 # [[1 2] # [3 4]] # \u9006\u77e9\u9635 # [[-2. 1. ] # [ 1.5 -0.5]] # \u9006\u77e9\u9635 # [[-2. 1. ] # [ 1.5 -0.5]]","title":"inv"},{"location":"python/DataAnalysis/ch01/#pinv","text":"np.pinv \u8ba1\u7b97\u77e9\u9635\u7684Moore-Penrose\u4f2a\u9006(\u6469\u5c14\uff0d\u5f6d\u82e5\u65af\u5e7f\u4e49\u9006)\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u68c0\u9a8c a * a+ * a == a \u548c a+ * a * a+ == a+ a = np.random.randn(9, 6) B = np.linalg.pinv(a) r1 = np.allclose(a, np.dot(a, np.dot(B, a))) r2 = np.allclose(B, np.dot(B, np.dot(a, B))) print(a) print(B) print(r1) # True print(r2) # True # a: # [[-2.30316101 -0.63217332 1.24134743 -0.72492307 0.12456801 -0.14192548] # [ 1.37573495 0.07626697 -0.71870843 1.26824984 -0.79485727 -0.24630455] # [ 0.29003175 -1.23931665 -0.50864107 -0.31140718 0.45467649 -2.44973999] # [-0.70748664 -1.2995059 0.85126149 -1.10918804 -2.10042342 0.75942293] # [ 1.91765238 1.23892103 1.58516486 -1.65520154 0.11894439 0.84536298] # [ 1.03220791 0.1715148 0.85595408 0.58569706 1.34066384 -1.5782386 ] # [-0.54432889 -0.0114189 1.55403934 0.89852512 1.15586365 -0.30733805] # [-0.80874673 0.14602121 1.04680044 1.98722514 0.39766383 0.75178788] # [ 0.01664663 0.06243353 -0.50725334 -0.37707204 -1.76701091 -0.33866559]] # B: # [[-0.25055838 0.13963115 0.08990923 0.16280282 0.12997291 0.05088469 -0.01541299 -0.01656133 -0.21731387] # [ 0.22862622 -0.05108109 -0.2639602 -0.47835978 0.11776862 0.09324694 0.00436756 -0.00609393 0.61995597] # [ 0.10422554 0.03985857 0.00198025 0.15139023 0.17165026 0.15697725 0.17360246 0.13150089 0.08378135] # [-0.07021378 0.17665487 -0.04109252 0.0015022 -0.11998477 0.0543575 0.08649033 0.21190785 0.04065729] # [-0.08110336 -0.15274536 0.05601496 -0.07967802 -0.02454705 -0.04152356 0.00071268 -0.05981012 -0.43996066] # [-0.17998537 -0.03160871 -0.12587707 0.16856246 0.00565094 -0.21038026 -0.06060039 0.04322126 -0.42038066]]","title":"pinv"},{"location":"python/DataAnalysis/ch01/#qr","text":"np.qr \u8ba1\u7b97QR\u5206\u89e3\u3002QR\uff08\u6b63\u4ea4\u4e09\u89d2\uff09\u5206\u89e3\u6cd5\u662f\u6c42\u4e00\u822c\u77e9\u9635\u5168\u90e8\u7279\u5f81\u503c\u7684\u6700\u6709\u6548\u5e76\u5e7f\u6cdb\u5e94\u7528\u7684\u65b9\u6cd5\u3002 \u4e00\u822c\u77e9\u9635\u5148\u7ecf\u8fc7\u6b63\u4ea4\u76f8\u4f3c\u53d8\u5316\u6210\u4e3aHessenberg\u77e9\u9635\uff0c\u7136\u540e\u518d\u5e94\u7528QR\u65b9\u6cd5\u6c42\u7279\u5f81\u503c\u548c\u7279\u5f81\u5411\u91cf\u3002QR\u5206\u89e3\u6cd5\u662f\u5c06\u77e9\u9635\u5206\u89e3\u6210\u4e00\u4e2a\u6b63\u89c4\u6b63\u4ea4\u77e9\u9635Q\u4e0e\u4e0a\u4e09\u89d2\u5f62\u77e9\u9635R\uff0c\u6240\u4ee5\u79f0\u4e3aQR\u5206\u89e3\u6cd5\u3002 a = np.arange(9).reshape(3, 3) q, r = np.linalg.qr(a) print(\"\u539f\u77e9\u9635 \\n\", a) print(\"\u6b63\u4ea4\u77e9\u9635 \\n\", q) print(\"\u4e0a\u4e09\u89d2\u77e9\u9635 \\n\", r) # \u539f\u77e9\u9635 # [[0 1 2] # [3 4 5] # [6 7 8]] # \u6b63\u4ea4\u77e9\u9635 # [[ 0. 0.91287093 0.40824829] # [-0.4472136 0.36514837 -0.81649658] # [-0.89442719 -0.18257419 0.40824829]] # \u4e0a\u4e09\u89d2\u77e9\u9635 # [[-6.70820393e+00 -8.04984472e+00 -9.39148551e+00] # [ 0.00000000e+00 1.09544512e+00 2.19089023e+00] # [ 0.00000000e+00 0.00000000e+00 -8.88178420e-16]]","title":"qr"},{"location":"python/DataAnalysis/ch01/#svd","text":"np.svd \u8ba1\u7b97\u5947\u5f02\u503c\u5206\u89e3\uff08SVD\uff09\u3002 \u51e0\u4f55\u610f\u4e49\uff1aSVD\u5206\u89e3\u7684\u51e0\u4f55\u610f\u4e49\u662f\u4efb\u4f55\u4e00\u4e2a\u77e9\u9635A\u5728\u4e00\u7cfb\u5217\u65cb\u8f6c\u548c\u5e73\u79fb\u4e0b\u90fd\u80fd\u8f6c\u5316\u6210\u4e00\u4e2a\u5bf9\u89d2\u77e9\u9635\u2211 , \u5176\u4e2d\u9149\u9635U, V\u7684\u51e0\u4f55\u610f\u4e49\u5c31\u662f\u4e00\u7cfb\u5217\u65cb\u8f6c\u548c\u5e73\u79fb\u7684\u53e0\u52a0\u3002 a = mat([[1, 2, 3],[4, 5, 6]]) U, sigma, V = np.linalg.svd(a) print(\"\u539f\u77e9\u9635 \\n\", a) print(\"\u5de6\u5947\u5f02\u503cU \\n\", U) print(\"\u5947\u5f02\u503cSigma \\n\", sigma) print(\"\u53f3\u5947\u5f02\u503cV \\n\", V) # \u539f\u77e9\u9635 # [[1 2 3] # [4 5 6]] # \u5de6\u5947\u5f02\u503cU # [[-0.3863177 -0.92236578] # [-0.92236578 0.3863177 ]] # \u5947\u5f02\u503cSigma # [9.508032 0.77286964] # \u53f3\u5947\u5f02\u503cV # [[-0.42866713 -0.56630692 -0.7039467 ] # [ 0.80596391 0.11238241 -0.58119908] # [ 0.40824829 -0.81649658 0.40824829]]","title":"svd"},{"location":"python/DataAnalysis/ch01/#solve","text":"np.solve \u6c42\u89e3x\u7684\u7ebf\u6027\u7cfb\u7edfAx = b\uff0c\u5176\u4e2dA\u662f\u65b9\u9635\u3002 \u89e3\u65b9\u7a0b\u7ec4\uff1a x + 2y = 1 3x + 5y = 2 a = np.array([[1, 2], [3, 5]]) b = np.array([1, 2]) x = np.linalg.solve(a, b) print(x) # [-1. 1.]","title":"solve"},{"location":"python/DataAnalysis/ch01/#lstsq","text":"np.lstsq \u8ba1\u7b97Ax = b\u7684\u6700\u5c0f\u4e8c\u4e58\u89e3\u3002 \u7528\u6700\u5c0f\u4e8c\u4e58\u6cd5\u62df\u5408\u6570\u636e\u5f97\u5230\u4e00\u4e2a\u5f62\u5982y = mx + c\u7684\u7ebf\u6027\u65b9\u7a0b\uff08Return the least-squares solution to a linear matrix equation\uff09\u3002 x = np.array([0, 1, 2, 3]) # \u539f\u59cb\u6570\u636e\u70b9\u7684\u6a2a\u5750\u6807 y = np.array([-1, 0.2, 0.9, 2.1]) # \u539f\u59cb\u6570\u636e\u70b9\u7684\u7eb5\u5750\u6807 print(x) # [0 1 2 3] print(y) # [-1. 0.2 0.9 2.1] A = np.vstack([x, np.ones(len(x))]).T # \u6784\u9020\u7cfb\u6570\u77e9\u9635 print(A) # [[0. 1.] # [1. 1.] # [2. 1.] # [3. 1.]] m, c = np.linalg.lstsq(A, y, rcond=None)[0] # \u89e3\u51fa\u659c\u7387a\u548c\u7eb5\u622a\u8dddc plt.plot(x, y, 'o', label='Original data', markersize=10) # \u505a\u51fa\u539f\u59cb\u6570\u636e\u6563\u70b9\u56fe plt.plot(x, m*x + c, 'r', label='Fitted line') # \u7528\u4e0a\u9762\u89e3\u51fa\u7684\u53c2\u6570\u505a\u51fa\u62df\u5408\u66f2\u7ebfy=mx+c plt.legend() plt.show()","title":"lstsq"},{"location":"python/DataAnalysis/ch01/#_14","text":"numpy.random \u6a21\u5757\u586b\u8865\u4e86Python\u5185\u5efa\u7684 random \u6a21\u5757\u7684\u4e0d\u8db3\uff0c\u53ef\u4ee5\u9ad8\u6548\u5730\u751f\u6210\u591a\u79cd\u6982\u7387\u5206\u5e03\u4e0b\u7684\u5b8c\u6574\u6837\u672c\u503c\u6570\u7ec4\u3002 numpy.random \u4e2d\u7684\u6570\u636e\u751f\u6210\u51fd\u6570\u516c\u7528\u4e86\u4e00\u4e2a\u5168\u5c40\u7684\u968f\u673a\u6570\u79cd\u5b50\u3002 \u4f7f\u7528 numpy.random.RandomState \u751f\u6210\u4e00\u4e2a\u968f\u673a\u6570\u751f\u6210\u5668\uff0c\u4f7f\u6570\u636e\u72ec\u7acb\u4e8e\u5176\u4ed6\u7684\u968f\u673a\u6570\u72b6\u6001\u3002 \u901a\u8fc7 np.random.seed \u66f4\u6539NumPy\u7684\u968f\u673a\u6570\u79cd\u5b50\u3002 numpy.random \u4e2d\u7684\u90e8\u5206\u51fd\u6570\u5217\u8868 seed: \u5411\u968f\u673a\u6570\u751f\u6210\u5668\u4f20\u9012\u968f\u673a\u72b6\u6001\u79cd\u5b50 permutation: \u8fd4\u56de\u4e00\u4e2a\u5e8f\u5217\u7684\u968f\u673a\u6392\u5217\uff0c\u6216\u8005\u8fd4\u56de\u4e00\u4e2a\u4e71\u5e8f\u7684\u6574\u6570\u8303\u56f4\u5e8f\u5217 shuffle: \u968f\u673a\u6392\u5217\u4e00\u4e2a\u5e8f\u5217 rand: \u4ece\u5747\u5300\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c randint: \u6839\u636e\u7ed9\u5b9a\u7684\u7531\u4f4e\u5230\u9ad8\u7684\u8303\u56f4\u62bd\u53d6\u968f\u673a\u6574\u6570 randn: \u4ece\u5747\u503c0\u65b9\u5dee1\u7684\u6b63\u6001\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c(MATLAB\u578b\u63a5\u53e3\uff09 binomial: \u4ece\u4e8c\u9879\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c normal: \u4ece\u6b63\u6001\uff08\u9ad8\u65af\uff09\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c beta\u4ecebeta: \u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c chisquare: \u4ece\u5361\u65b9\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c \u4f8b\u5982\uff0c\u4f7f\u7528normal\u6765\u83b7\u5f97\u4e00\u4e2a4\u00d74\u7684\u6b63\u6001\u5206\u5e03\u6837\u672c\u6570\u7ec4\uff0c\u79f0\u4e3a\u4f2a\u968f\u673a\u6570\u3002 import numpy as np samples = np.random.normal(size=(4, 4)) print(samples) # [[ 0.78583658 -0.27462104 -0.53027675 -0.62675004] # [ 0.39054781 1.20503691 -0.0057432 0.17243182] # [-0.41516669 -0.93335854 0.01996088 -0.12707275] # [ 0.42952379 2.56998319 0.14848737 -0.42871493]]","title":"\u4f2a\u968f\u673a\u6570\u751f\u6210"},{"location":"python/DataAnalysis/ch01/#_15","text":"import matplotlib.pyplot as plt import numpy as np position = 0 walk = [position] nwalks = 5000 nsteps = 1000 draws = np.random.randint(0, 2, size=(nwalks, nsteps)) steps = np.where(draws > 0, 1, -1) walks = steps.cumsum() plt.plot(walks[:500000000000000000000000000]) plt.show() \u8f93\u51fa\u56fe\u50cf\uff1a","title":"\u793a\u4f8b\uff1a\u968f\u673a\u6f2b\u6b65"},{"location":"python/DataAnalysis/ch02/","text":"Pandas\u5165\u95e8 \u00b6 \u7ea6\u5b9a\uff1a import numpy as np import pandas as pd from pandas import Series, DataFrame import pandas_datareader as web pandas\u6570\u636e\u7ed3\u6784\u4ecb\u7ecd \u00b6 Series \u00b6 Series\u662f\u4e00\u79cd\u4e00\u7ef4\u7684\u6570\u7ec4\u578b\u5bf9\u8c61\uff0c\u5b83\u5305\u542b\u4e86\u4e00\u4e2a\u503c\u5e8f\u5217\uff08\u4e0eNumPy\u4e2d\u7684\u7c7b\u578b\u76f8\u4f3c\uff09\uff0c\u5e76\u4e14\u5305\u542b\u4e86\u6570\u636e\u6807\u7b7e\uff0c\u79f0\u4e3a**\u7d22\u5f15\uff08index\uff09 \u3002 \u4ece\u53e6\u4e00\u4e2a\u89d2\u5ea6\u8003\u8651Series\uff0c\u53ef\u4ee5\u8ba4\u4e3a\u5b83\u662f\u4e00\u4e2a**\u957f\u5ea6\u56fa\u5b9a\u4e14\u6709\u5e8f\u7684\u5b57\u5178 \uff0c\u56e0\u4e3a\u5b83\u5c06\u7d22\u5f15\u503c\u548c\u6570\u636e\u503c\u6309\u4f4d\u7f6e\u914d\u5bf9\u3002\u7d22\u5f15\u5728\u5de6\u8fb9\uff0c\u503c\u5728\u53f3\u8fb9\u3002 obj = pd.Series([4, 7, -5, 3]) print(obj) # 0 4 # 1 7 # 2 -5 # 3 3 # dtype: int64 print(obj.values) # [ 4 7 -5 3 print(obj.index) # RangeIndex(start=0, stop=4, step=1) \u81ea\u5b9a\u4e49index obj = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c']) print(obj) # d 4 # b 7 # a -5 # c 3 # dtype: int64 print(obj.values) # [ 4 7 -5 3] print(obj.index) # Index(['d', 'b', 'a', 'c'], dtype='object') # \u8f93\u51fa\u7d22\u5f15\u503c\u4e3a'a'\u7684Series\u503c print(obj['a']) # -5 # \u4f7f\u7528\u5e03\u5c14\u503c\u6570\u7ec4\u8fdb\u884c\u8fc7\u6ee4Series\u503c print(obj[obj > 3]) # d 4 # b 7 # dtype: int64 # \u5bf9Series\u503c\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97 print(obj * 2) # d 8 # b 14 # a -10 # c 6 # dtype: int64 # \u5bf9Series\u503c\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97 print(np.exp(obj)) # d 54.598150 # b 1096.633158 # a 0.006738 # c 20.085537 # dtype: float64 # \u66f4\u65b0Series\u6570\u7ec4\u503c obj['a'] = 9 # \u8f93\u51fa\u6307\u5b9a\u7d22\u5f15\u503c\u7684Series\u503c\uff0c\u6ce8\u610f\uff0c\u7d22\u5f15\u6761\u4ef6\u662f\u5217\u8868 print(obj[['a', 'b', 'c']]) # a 9 # b 7 # c 3 # dtype: int64 # \u6ce8\u610f\uff0c\u4e0b\u9762\u7684\u5224\u65ad\u662f\u7d22\u5f15\u503c\uff0c\u975eSeries\u503c print(obj) print(7 in obj) # False print('a' in obj) # True \u901a\u8fc7\u5b57\u5178\u751f\u6210\u4e00\u4e2aSeries\u3002 NaN \uff08not a number\uff09\uff0c\u8fd9\u662fpandas\u4e2d\u6807\u8bb0\u7f3a\u5931\u503c\u6216NA\u503c\u7684\u65b9\u5f0f\u3002 \u5f53\u628a\u5b57\u5178\u4f20\u9012\u7ed9Series\u6784\u9020\u51fd\u6570\u65f6\uff0c\u4ea7\u751f\u7684Series\u7684\u7d22\u5f15\u5c06\u662f\u6392\u5e8f\u597d\u7684\u5b57\u5178\u952e\u3002\u53ef\u4ee5\u5c06\u5b57\u5178\u952e\u6309\u7167\u4f60\u6240\u60f3\u8981\u7684\u987a\u5e8f\u4f20\u9012\u7ed9\u6784\u9020\u51fd\u6570\uff0c\u4ece\u800c\u4f7f\u751f\u6210\u7684Series\u7684\u7d22\u5f15\u987a\u5e8f\u7b26\u5408\u9884\u671f\u3002 \u770b\u4e0b\u4f8b\uff0c\u901a\u8fc7\u5b57\u5178sdata\u751f\u6210Series\u3002 sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000} obj3 = pd.Series(sdata) print(sdata) # {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000} print(obj3) # Ohio 35000 # Texas 71000 # Oregon 16000 # Utah 5000 # dtype: int64 \u901a\u8fc7\u6307\u5b9a\u7d22\u5f15states\u53bb\u5339\u914d\u5b57\u5178sdata\u751f\u6210\u57fa\u4e8e\u65b0\u7d22\u5f15states\u7684Series\u3002 states = ['California', 'Ohio', 'Oregon', 'Texas'] obj4 = pd.Series(sdata, index=states) print(obj4) # California NaN # Ohio 35000.0 # Oregon 16000.0 # Texas 71000.0 # dtype: float64 \u5bf9Series\u8fdb\u884c\u5e03\u5c14\u503c\u5224\u65ad\u3002 print(pd.isnull(obj4)) # California True # Ohio False # Oregon False # Texas False # dtype: bool print(pd.notnull(obj4)) # California False # Ohio True # Oregon True # Texas True # dtype: bool \u5bf9Series\u8fdb\u884c\u5e03\u5c14\u503c\u5224\u65ad\u3002 print(obj4.isnull) # print(obj4.notnull) # Series\u7684\u81ea\u52a8\u5bf9\u9f50\u7d22\u5f15\uff0c\u4e0e\u6570\u636e\u5e93\u7684join\u64cd\u4f5c\u662f\u975e\u5e38\u76f8\u4f3c\u3002 print(\"obj3 \\n\", obj3) # obj3 # Ohio 35000 # Texas 71000 # Oregon 16000 # Utah 5000 # dtype: int64 print(\"obj4 \\n\", obj4) # obj4 # California NaN # Ohio 35000.0 # Oregon 16000.0 # Texas 71000.0 # dtype: float64 print(\"obj3+obj4 \\n\", obj3 + obj4) # obj3+obj4 # California NaN # Ohio 70000.0 # Oregon 32000.0 # Texas 142000.0 # Utah NaN # dtype: float64 # \u4e0b\u9762\u662fobj3\u548cobj4\u7684\u503c\uff0c\u5e2e\u52a9\u7406\u89e3\u4e0a\u9762obj3 + obj4\u7684\u64cd\u4f5c\u3002 # obj3 obj4 # Ohio 35000 California NaN # Texas 71000 Ohio 35000.0 # Oregon 16000 Oregon 16000.0 # Utah 5000 Texas 71000.0 # dtype: int64 dtype: float64 Series\u5bf9\u8c61\u81ea\u8eab\u548c\u5176\u7d22\u5f15\u90fd\u6709name\u5c5e\u6027\u3002 obj4.name = 'population' obj4.index.name = 'state' print(obj4) # state # California NaN # Ohio 35000.0 # Oregon 16000.0 # Texas 71000.0 # Name: population, dtype: float64 \u66ff\u6362Series\u7684\u7d22\u5f15\u540d\u3002 obj = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c']) print(obj) obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan'] print(obj) # Bob 4 # Steve 7 # Jeff -5 # Ryan 3 # dtype: int64 DataFrame \u00b6 DataFrame\u8868\u793a\u7684\u662f\u77e9\u9635\u7684\u6570\u636e\u8868\uff0c\u5b83\u5305\u542b\u5df2\u6392\u5e8f\u7684\u5217\u96c6\u5408\uff0c\u6bcf\u4e00\u5217\u53ef\u4ee5\u662f\u4e0d\u540c\u7684\u503c\u7c7b\u578b\uff08\u6570\u503c\u3001\u5b57\u7b26\u4e32\u3001\u5e03\u5c14\u503c\u7b49\uff09\u3002 DataFrame\u65e2\u6709\u884c\u7d22\u5f15\u4e5f\u6709\u5217\u7d22\u5f15\uff0c\u5b83\u53ef\u4ee5\u88ab\u89c6\u4e3a\u4e00\u4e2a\u5171\u4eab\u76f8\u540c\u7d22\u5f15\u7684Series\u7684\u5b57\u5178\uff0c\u6bd4\u5982\u6240\u6709\u5217\u5171\u4eab\u540c\u4e00\u4e2a\u5217\u7d22\u5f15\u3002 \u5728DataFrame\u4e2d\uff0c\u6570\u636e\u88ab\u5b58\u50a8\u4e3a\u4e00\u4e2a\u4ee5\u4e0a\u7684\u4e8c\u7ef4\u5757\uff0c\u800c\u4e0d\u662f\u5217\u8868\u3001\u5b57\u5178\u6216\u5176\u4ed6\u4e00\u7ef4\u6570\u7ec4\u7684\u96c6\u5408\u3002 DataFrame\u662f\u4e8c\u7ef4\u7684\uff0c\u4f46\u53ef\u4ee5\u5229\u7528**\u5206\u5c42\u7d22\u5f15**\u5728DataFrame\u4e2d\u5c55\u73b0\u66f4\u9ad8\u7ef4\u5ea6\u7684\u6570\u636e\u3002 \u4eceDataFrame\u4e2d\u9009\u53d6\u7684\u5217\u662f\u6570\u636e\u7684\u89c6\u56fe\uff0c\u800c\u4e0d\u662f\u62f7\u8d1d \u3002\u56e0\u6b64\uff0c\u5bf9Series\u7684\u4fee\u6539\u4f1a\u6620\u5c04\u5230DataFrame\u4e2d\u3002\u5982\u679c\u9700\u8981\u590d\u5236\uff0c\u5219\u5e94\u5f53\u663e\u5f0f\u5730\u4f7f\u7528Series\u7684copy\u65b9\u6cd5\u3002 \u7531\u5b57\u5178\u6784\u6210DataFrame \u00b6 \u57fa\u4e8e\u5b57\u5178 data \u4ea7\u751f\u7684DataFrame\u4f1a\u81ea\u52a8\u4e3aSereies\u5206\u914d\u7d22\u5f15\uff0c\u5e76\u4e14\u5217\u4f1a\u6309\u7167\u6392\u5e8f\u7684\u987a\u5e8f\u6392\u5217\u3002 data = { 'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], 'year': [2000, 2001, 2002, 2001, 2002, 2003], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2] } frame = pd.DataFrame(data) print(frame) # state year pop # 0 Ohio 2000 1.5 # 1 Ohio 2001 1.7 # 2 Ohio 2002 3.6 # 3 Nevada 2001 2.4 # 4 Nevada 2002 2.9 # 5 Nevada 2003 3.2 # \u5bf9\u4e8e\u5927\u578bDataFrame, head\u65b9\u6cd5\u5c06\u4f1a\u53ea\u9009\u51fa\u5934\u90e8\u7684\u82e5\u5e72\u884c, \u9ed8\u8ba4\u662f\u524d\u4e94\u884c\u3002 print(frame.head(3)) # state year pop # 0 Ohio 2000 1.5 # 1 Ohio 2001 1.7 # 2 Ohio 2002 3.6 \u5982\u679c\u6307\u5b9a\u4e86\u5217\u7684\u987a\u5e8f\uff0cDataFrame\u7684\u5217\u5c06\u4f1a\u6309\u7167\u6307\u5b9a\u987a\u5e8f\u6392\u5217\u3002 frame = pd.DataFrame(data, columns=['year', 'state', 'pop']) print(frame) # year state pop # 0 2000 Ohio 1.5 # 1 2001 Ohio 1.7 # 2 2002 Ohio 3.6 # 3 2001 Nevada 2.4 # 4 2002 Nevada 2.9 # 5 2003 Nevada 3.2 \u5982\u679c\u4f20\u7684\u5217\uff08 debt \uff09\u4e0d\u5305\u542b\u5728\u5b57\u5178\uff08 data \uff09\u4e2d\uff0c\u5c06\u4f1a\u5728\u7ed3\u679c\u4e2d\u51fa\u73b0\u7f3a\u5931\u503c\u3002 frame2 = pd.DataFrame( data, columns=['year', 'state', 'pop', 'debt'], index=['one', 'two', 'three', 'four', 'five', 'six'] ) print(frame2) # year state pop debt # one 2000 Ohio 1.5 NaN # two 2001 Ohio 1.7 NaN # three 2002 Ohio 3.6 NaN # four 2001 Nevada 2.4 NaN # five 2002 Nevada 2.9 NaN # six 2003 Nevada 3.2 NaN \u9009\u53d6\u884c, \u53ef\u4ee5\u901a\u8fc7\u4f4d\u7f6e\u6216\u884c\u7d22\u5f15\u6807\u7b7e loc \u8fdb\u884c\u9009\u53d6\u3002 print(frame2.loc['three']) # year 2002 # state Ohio # pop 3.6 # debt NaN # Name: three, dtype: object DataFrame\u4e2d\u7684\u4e00\u5217\uff0c\u53ef\u4ee5\u6309\u5b57\u5178\u578b\u6807\u8bb0\u6216\u5c5e\u6027\u90a3\u6837\u68c0\u7d22\u4e3aSeries\u3002 frame2[colunm] \u5bf9\u4e8e\u4efb\u610f\u5217\u540d\u5747\u6709\u6548\uff0c\u4f46\u662f frame2.column \u53ea\u5728\u5217\u540d\u662f\u6709\u6548\u7684Python\u53d8\u91cf\u540d\u65f6\u6709\u6548\u3002 \u8fd4\u56de\u7684Series\u4e0e\u539fDataFrame\u6709\u76f8\u540c\u7684\u7d22\u5f15\uff0c\u4e14Series\u7684 name \u5c5e\u6027\u4e5f\u4f1a\u88ab\u5408\u7406\u5730\u8bbe\u7f6e\u3002 print(frame2['state']) # one Ohio # two Ohio # three Ohio # four Nevada # five Nevada # six Nevada # Name: state, dtype: object print(frame2.state) # \u5c5e\u6027\u578b\u8fde\u63a5 # one Ohio # two Ohio # three Ohio # four Nevada # five Nevada # six Nevada # Name: state, dtype: object \u5217\u7684\u5f15\u7528\u662f\u53ef\u4ee5\u4fee\u6539\u7684\u3002\u503c\u7684\u957f\u5ea6\u5fc5\u987b\u548cDataFrame\u7684\u957f\u5ea6\u76f8\u5339\u914d,\u6bd4\u5982\uff0c\u4e0b\u4f8b\u4e2d np.arange(6.) \u548c frame2['debt'] \u7684\u957f\u5ea6\u90fd\u662f6\u3002 frame2['debt'] = 16.5 print(frame2) # Name: state, dtype: object # year state pop debt # one 2000 Ohio 1.5 16.5 # two 2001 Ohio 1.7 16.5 # three 2002 Ohio 3.6 16.5 # four 2001 Nevada 2.4 16.5 # five 2002 Nevada 2.9 16.5 # six 2003 Nevada 3.2 16.5 frame2['debt'] = np.arange(6.) print(frame2) # year state pop debt # one 2000 Ohio 1.5 0.0 # two 2001 Ohio 1.7 1.0 # three 2002 Ohio 3.6 2.0 # four 2001 Nevada 2.4 3.0 # five 2002 Nevada 2.9 4.0 # six 2003 Nevada 3.2 5.0 \u5982\u679c\u5c06Series\u8d4b\u503c\u7ed9\u4e00\u5217\u65f6\uff0cSeries\u7684\u7d22\u5f15\u5c06\u4f1a\u6309\u7167DataFrame\u7684\u7d22\u5f15\u91cd\u65b0\u6392\u5217\uff0c\u5e76\u5728\u7a7a\u7f3a\u7684\u5730\u65b9\u586b\u5145\u7f3a\u5931\u503c val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five']) frame2['debt'] = val print(frame2) # year state pop debt # one 2000 Ohio 1.5 NaN # two 2001 Ohio 1.7 -1.2 # three 2002 Ohio 3.6 NaN # four 2001 Nevada 2.4 -1.5 # five 2002 Nevada 2.9 -1.7 # six 2003 Nevada 3.2 NaN \u5982\u679c\u88ab\u8d4b\u503c\u7684\u5217( eastern \u5217)\u5e76\u4e0d\u5b58\u5728\uff0c\u5219\u4f1a\u751f\u6210\u4e00\u4e2a\u65b0\u7684\u5217\u3002 frame2.state == 'Ohio' \u8fd4\u56de\u7684\u662f\u5e03\u5c14\u503c\uff0c\u8d4b\u503c\u7ed9 eastern \u3002 frame2['eastern'] = frame2.state == 'Ohio' print(frame2) # year state pop debt eastern # one 2000 Ohio 1.5 NaN True # two 2001 Ohio 1.7 -1.2 True # three 2002 Ohio 3.6 NaN True # four 2001 Nevada 2.4 -1.5 False # five 2002 Nevada 2.9 -1.7 False # six 2003 Nevada 3.2 NaN False print(frame2.eastern) # one True # two True # three True # four False # five False # six False # Name: eastern, dtype: bool del \u5173\u952e\u5b57\u53ef\u4ee5\u50cf\u5728\u5b57\u5178\u4e2d\u90a3\u6837\u5bf9DataFrame\u5220\u9664\u5217\u3002 del frame2['eastern'] print(frame2.columns) # Index(['year', 'state', 'pop', 'debt'], dtype='object') \u4f7f\u7528\u5d4c\u5957\u5b57\u5178\u6784\u5efaDataFrame \u00b6 pandas\u4f1a\u5c06\u5b57\u5178\u7684\u952e\u4f5c\u4e3a\u5217('Nevada', etc.)\uff0c\u5c06\u5185\u90e8\u5b57\u5178\u7684\u952e\u4f5c\u4e3a\u884c\u7d22\u5f15(2001, etc.) pop = { 'Nevada': { 2001: 2.4, 2002: 2.9 }, 'Ohio': { 2000: 1.5, 2001: 1.7, 2002: 3.6 } } # \u4e0d\u6307\u5b9a\u7d22\u5f15\uff0c\u9ed8\u8ba4\u4f7f\u7528\u5b57\u5178\u7d22\u5f15 frame3 = pd.DataFrame(pop) print(frame3) # Nevada Ohio # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 # \u6307\u5b9a\u5b57\u5178\u67d0\u5217\u4f5c\u4e3a\u7d22\u5f15 print(pd.DataFrame(pop, index=[2001, 2002, 2003])) # Nevada Ohio # 2001 2.4 1.7 # 2002 2.9 3.6 # 2003 NaN NaN # \u6307\u5b9a\u4e0d\u76f8\u5e72\u7d22\u5f15 print(pd.DataFrame(pop, index=['a', 'b', 'c'])) # Nevada Ohio # a NaN NaN # b NaN NaN # c NaN NaN \u8f6c\u7f6e\u64cd\u4f5c\uff08\u8c03\u6362\u884c\u548c\u5217\uff09 print(frame3.T) # 2001 2002 2000 # Nevada 2.4 2.9 NaN # Ohio 1.7 3.6 1.5 \u4f7f\u7528\u542bSeries\u7684\u5b57\u5178\u6784\u9020DataFrame \u00b6 frame3['Ohio'][:-1] \u662f\u503c\u4e3a Ohio \u7684Series\u76840~\u5012\u6570\u7b2c\u4e00\u4e2a\u5143\u7d20\uff08\u4e0d\u542b\uff09\uff0c\u4e00\u51713\u4e2a\u3002 frame3['Nevada'][:2] \u662f\u503c\u4e3a Nevada \u7684Series\u7684\u524d2\u4e2a\u5143\u7d20\u3002 pdata = { 'Ohio': frame3['Ohio'][:-1], 'Nevada': frame3['Nevada'][:2] } print(pd.DataFrame(pdata)) # Ohio Nevada # 2001 1.7 2.4 # 2002 3.6 2.9 \u6307\u5b9aDataframe frame3 \u7684\u5217\u540d\u3002 frame3.index.name = 'year' frame3.columns.name = 'state' print(frame3) # state Nevada Ohio # year # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 \u53ea\u8f93\u51faDataframe\u7684\u503c frame3.values \uff0c\u662f\u4e00\u4e2a\u4e8c\u7ef4\u6570\u7ec4\u3002 print(frame3.values) # [[2.4 1.7] # [2.9 3.6] # [nan 1.5]] \u53ea\u8f93\u51faDataframe\u7684\u503c frame2.values \uff0c\u662f\u4e00\u4e2a\u4e8c\u7ef4\u6570\u7ec4\u3002 print(frame2) # year state pop debt # one 2000 Ohio 1.5 NaN # two 2001 Ohio 1.7 -1.2 # three 2002 Ohio 3.6 NaN # four 2001 Nevada 2.4 -1.5 # five 2002 Nevada 2.9 -1.7 # six 2003 Nevada 3.2 NaN print(frame2.values) # [[2000 'Ohio' 1.5 nan] # [2001 'Ohio' 1.7 -1.2] # [2002 'Ohio' 3.6 nan] # [2001 'Nevada' 2.4 -1.5] # [2002 'Nevada' 2.9 -1.7] # [2003 'Nevada' 3.2 nan]] \u7d22\u5f15\u5bf9\u8c61 \u00b6 pandas\u4e2d\u7684**\u7d22\u5f15\u5bf9\u8c61**\u662f\u7528\u4e8e\u5b58\u50a8\u8f74\u6807\u7b7e\u548c\u5176\u4ed6\u5143\u6570\u636e\u7684\uff08\u4f8b\u5982\u8f74\u540d\u79f0\u6216\u6807\u7b7e\uff09\u3002 \u5728\u6784\u9020Series\u6216DataFrame\u65f6\uff0c\u4f60\u6240\u4f7f\u7528\u7684\u4efb\u610f\u6570\u7ec4\u6216\u6807\u7b7e\u5e8f\u5217\u90fd\u53ef\u4ee5\u5728\u5185\u90e8\u8f6c\u6362\u4e3a\u7d22\u5f15\u5bf9\u8c61\u3002 \u7d22\u5f15\u5bf9\u8c61\u662f\u4e0d\u53ef\u53d8\u7684\u3002 \u9664\u4e86\u7c7b\u4f3c\u6570\u7ec4\uff0c\u7d22\u5f15\u5bf9\u8c61\u4e5f\u50cf\u4e00\u4e2a\u56fa\u5b9a\u5927\u5c0f\u7684\u96c6\u5408\u3002\u4e0ePython\u96c6\u5408\u4e0d\u540c\uff0c pandas\u7d22\u5f15\u5bf9\u8c61\u53ef\u4ee5\u5305\u542b\u91cd\u590d\u6807\u7b7e \u3002 \u56e0\u4e3a\u4e00\u4e9b\u64cd\u4f5c\u4f1a\u4ea7\u751f\u5305\u542b\u7d22\u5f15\u5316\u6570\u636e\u7684\u7ed3\u679c\uff0c\u7406\u89e3\u7d22\u5f15\u5982\u4f55\u5de5\u4f5c\u8fd8\u662f\u5f88\u91cd\u8981\u7684\u3002 \u4e0b\u4f8b\u6f14\u793a\u4e86\u5982\u4f55\u8bfb\u53d6Dataframe\u7684\u7d22\u5f15\u503c\u3002 obj = pd.Series(range(3), index=['a', 'b', 'c']) index = obj.index print(obj) # a 0 # b 1 # c 2 # dtype: int64 print(index) # Index(['a', 'b', 'c'], dtype='object') print(index[1:]) # Index(['b', 'c'], dtype='object') \u4e0b\u4f8b\u6f14\u793a\u4e86\u901a\u8fc7\u4e00\u4e2a\u6307\u5b9a\u7684Dataframe\u7d22\u5f15 labels \u6765\u751f\u6210Dataframe obj2 \u3002 labels = pd.Index(np.arange(3)) print(labels) # Int64Index([0, 1, 2], dtype='int64') obj2 = pd.Series([1.5, -2.5, 0], index=labels) print(obj2) # 0 1.5 # 1 -2.5 # 2 0.0 # dtype: float64 print(obj2.index is labels) # True \u4e0b\u4f8b\u6f14\u793a\u4e86\u4e0d\u6307\u5b9a\u7d22\u5f15\uff0c\u9ed8\u8ba4\u4f7f\u7528\u5b57\u5178\u7d22\u5f15\u6765\u521b\u5efaDataframe\u3002 pop = { 'Nevada': { 2001: 2.4, 2002: 2.9 }, 'Ohio': { 2000: 1.5, 2001: 1.7, 2002: 3.6 } } frame3 = pd.DataFrame(pop) print(frame3) # Nevada Ohio # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 print(frame3) # state Nevada Ohio # year # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 print(frame3.columns) # Index(['Nevada', 'Ohio'], dtype='object', name='state') print(frame3.index) # Int64Index([2001, 2002, 2000], dtype='int64', name='year') print('Ohio' in frame3.columns) # True print(2003 in frame3.index) # False pandas\u7d22\u5f15\u5bf9\u8c61\u5141\u8bb8\u5305\u542b\u91cd\u590d\u6807\u7b7e\u3002\u6839\u636e\u91cd\u590d\u6807\u7b7e\u8fdb\u884c\u7b5b\u9009\uff0c\u4f1a\u9009\u53d6\u6240\u6709\u91cd\u590d\u6807\u7b7e\u5bf9\u5e94\u7684\u6570\u636e\u3002 dup_labels = pd.Index(['foo', 'foo', 'bar', 'bar']) print(dup_labels) # Index(['foo', 'foo', 'bar', 'bar'], dtype='object') \u4e00\u4e9b\u5e38\u7528\u7d22\u5f15\u5bf9\u8c61\u7684\u65b9\u6cd5\u548c\u5c5e\u6027\u3002 obj1 = pd.Series(range(3), index=['a', 'b', 'c']) index1 = obj1.index obj2 = pd.Series(range(3), index=['c', 'f', 'g']) index2 = obj2.index print(index1) # Index(['a', 'b', 'c'], dtype='object') print(index2) # Index(['c', 'f', 'g'], dtype='object') append \u65b9\u6cd5\uff1a\u5c06\u5916\u90e8\u7684\u7d22\u5f15\u5bf9\u8c61\u7c98\u8d34\u5230\u539f\u7d22\u5f15\u540e\uff0c\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684\u7d22\u5f15\u3002 \u63a5\u4e0a\u4f8b\uff0c\u628a index2 \u5bf9\u8c61\u8ffd\u52a0\u5230 index1 \u5bf9\u8c61\u3002 print(index1.append(index2)) # Index(['a', 'b', 'c', 'c', 'f', 'g'], dtype='object') difference \u65b9\u6cd5: \u8ba1\u7b972\u4e2a\u7d22\u5f15\u7684\u5dee\u96c6\u3002 print(index1.difference(index2)) # Index(['a', 'b'], dtype='object') intersection \u65b9\u6cd5: \u8ba1\u7b972\u4e2a\u7d22\u5f15\u7684\u4ea4\u96c6\u3002 print(index1.intersection(index2)) # Index(['c'], dtype='object') union \u65b9\u6cd5: \u8ba1\u7b972\u4e2a\u7d22\u5f15\u7684\u5e76\u96c6\uff08\u53bb\u91cd\uff09\u3002 print(index1.union(index2)) # Index(['a', 'b', 'c', 'f', 'g'], dtype='object') isin \u65b9\u6cd5: \u8ba1\u7b97\u8868\u793a\u6bcf\u4e00\u4e2a\u503c\u662f\u5426\u5728\u4f20\u503c\u5bb9\u5668\u4e2d\uff0c\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u5e03\u5c14\u6570\u7ec4\u3002 print(index1.isin(index2)) # [False False True] delete \u65b9\u6cd5: \u5c06\u4f4d\u7f6ei\uff08\u4ece0\u5f00\u59cb\u7f16\u53f7\uff09\u7684\u5143\u7d20\u5220\u9664\uff0c\u5e76\u4ea7\u751f\u65b0\u7684\u7d22\u5f15\u3002 print(index1.delete('b')) # IndexError: arrays used as indices must be of integer (or boolean) type print(index1.delete(1)) # Index(['a', 'c'], dtype='object') print(index1) # Index(['a', 'b', 'c'], dtype='object') drop \u65b9\u6cd5: \u6839\u636e\u4f20\u53c2\u5220\u9664\u6307\u5b9a\u7d22\u5f15\u503c\uff0c\u5e76\u4ea7\u751f\u65b0\u7684\u7d22\u5f15, \u5bf9\u6bd4\u548cdelete\u7684\u533a\u522b\uff0c delete \u65b9\u6cd5\u662f\u8f93\u5165\u4f4d\u7f6e\uff0c drop \u65b9\u6cd5\u662f\u8f93\u5165\u7d22\u5f15\u540d\u79f0\u3002 print(index2.drop(1)) # KeyError: '[1] not found in axis' print(index2.drop('f')) # Index(['c', 'g'], dtype='object') print(index2) # Index(['c', 'f', 'g'], dtype='object') insert \u65b9\u6cd5: \u5728\u4f4d\u7f6e i \u63d2\u5165\u5143\u7d20\uff0c\u5e76\u4ea7\u751f\u65b0\u7684\u7d22\u5f15\u3002 print(index1.insert(1, 'e')) # Index(['a', 'e', 'b', 'c'], dtype='object') print(index1) # Index(['a', 'b', 'c'], dtype='object') is_monotonic \u65b9\u6cd5: \u5982\u679c\u7d22\u5f15\u5e8f\u5217\u9012\u589e\uff0c\u5219\u8fd4\u56de True \u3002 print(index1.is_monotonic) # True print(index1.insert(1, 'e').is_monotonic) # False is_unique \u65b9\u6cd5: \u5982\u679c\u7d22\u5f15\u5e8f\u5217\u552f\u4e00\u5219\u8fd4\u56de True \u3002 print(index1.is_unique) # True print(index1.append(index2).is_unique) # False unique \u65b9\u6cd5: \u8ba1\u7b97\u7d22\u5f15\u7684\u552f\u4e00\u503c\u5e8f\u5217\uff08\u5bf9\u6bd4Union\uff09\u3002 print(index1.unique()) # Index(['a', 'b', 'c'], dtype='object') print(index1.append(index2).unique()) # Index(['a', 'b', 'c', 'f', 'g'], dtype='object') pandas\u57fa\u672c\u529f\u80fd \u00b6 \u91cd\u5efa\u7d22\u5f15 \u00b6 Series\u8c03\u7528 reindex \u65b9\u6cd5\u65f6\uff0c\u4f1a\u5c06\u6570\u636e\u6309\u7167\u65b0\u7684\u7d22\u5f15\u8fdb\u884c\u6392\u5217\uff0c\u5982\u679c\u67d0\u4e2a\u7d22\u5f15\u503c\u4e4b\u524d\u5e76\u4e0d\u5b58\u5728\uff0c\u5219\u4f1a\u5f15\u5165\u7f3a\u5931\u503c\u3002 \u4e0b\u4f8b\u4e2d\uff0c\u5bf9 obj1 \u505a reindex \uff0c reindex \u65b9\u6cd5\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7d22\u5f15\u5bf9\u8c61 obj2 \uff0c\u7d22\u5f15\u503c e \u4e4b\u524d\u5e76\u4e0d\u5b58\u5728\uff0c\u6240\u4ee5\u586b\u5165\u7f3a\u5931\u503c\u3002 \u5982\u679c\u5bf9obj1\u505a reindex \u65f6\u6307\u5b9a method='ffill' \uff0c\u4f1a\u62a5\u9519 index must be monotonic increasing or decreasing \u3002 obj1 = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c']) print(obj1) # d 4.5 # b 7.2 # a -5.3 # c 3.6 # dtype: float64 obj2 = obj1.reindex(['a', 'b', 'c', 'd', 'e']) print(obj2) # a -5.3 # b 7.2 # c 3.6 # d 4.5 # e NaN # dtype: float64 obj2 = obj1.reindex(['a', 'b', 'c', 'd', 'e'], method='ffill') # ValueError: index must be monotonic increasing or decreasing \u5bf9\u4e8e\u987a\u5e8f\u6570\u636e\uff0c\u6bd4\u5982\u65f6\u95f4\u5e8f\u5217\uff0c\u5728\u91cd\u5efa\u7d22\u5f15\u65f6\u53ef\u80fd\u4f1a\u9700\u8981\u8fdb\u884c\u63d2\u503c\u6216\u586b\u503c\u3002 ffill \u65b9\u6cd5\u5728\u91cd\u5efa\u7d22\u5f15\u65f6\u63d2\u503c\uff0c\u5c06\u503c\u524d\u5411\u586b\u5145\u3002 obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4]) print(obj3.reindex(range(6), method='ffill')) # 0 blue # 1 blue # 2 purple # 3 purple # 4 yellow # 5 yellow # dtype: object \u5728DataFrame\u4e2d\uff0c reindex \u53ef\u4ee5\u6539\u53d8\u884c\u7d22\u5f15\u3001\u5217\u7d22\u5f15\uff0c\u4e5f\u53ef\u4ee5\u540c\u65f6\u6539\u53d8\u4e8c\u8005\u3002\u5f53\u4ec5\u4f20\u5165\u4e00\u4e2a\u5e8f\u5217\u65f6\uff0c\u4f1a\u91cd\u5efa\u884c\u7d22\u5f15\u3002 \u4e0b\u4f8b\u4e2d\uff0c\u901a\u8fc7 indexes \u521b\u5efaDataframe frame \u3002 \u901a\u8fc7 frame.reindex(['a', 'b', 'c', 'd'])\u91cd\u5efa\u884c\u7d22\u5f15 \u3002 \u901a\u8fc7 frame2.reindex(columns=['Ohio', 'Uta', 'California']) \u91cd\u5efa\u5217\u7d22\u5f15\u3002 \u7f3a\u5931\u7684\u7d22\u5f15\u5217\u586b\u5165\u7f3a\u5931\u503c\u3002 indexes = index = ['a', 'b', 'c'] states = ['Ohio', 'Texas', 'California'] frame = pd.DataFrame( np.arange(9).reshape(3, 3), index=indexes, columns=states ) print(frame) # Ohio Texas California # a 0 1 2 # b 3 4 5 # c 6 7 8 frame2 = frame.reindex(['a', 'b', 'c', 'd']) # \u91cd\u5efa\u884c\u7d22\u5f15 print(frame2) # Ohio Texas California # a 0.0 1.0 2.0 # b 3.0 4.0 5.0 # c 6.0 7.0 8.0 # d NaN NaN NaN frame3 = frame2.reindex(columns=['Ohio', 'Uta', 'California']) # \u91cd\u5efa\u5217\u7d22\u5f15 print(frame3) # Ohio Uta California # a 0.0 NaN 2.0 # b 3.0 NaN 5.0 # c 6.0 NaN 8.0 # d NaN NaN NaN \u4f7f\u7528 loc \u8fdb\u884c\u66f4\u4e3a\u7b80\u6d01\u7684\u884c\u3001\u5217\u6807\u7b7e\u7d22\u5f15\u3002\u4e0b\u4f8b\u901a\u8fc7\u7b5b\u9009\u884c\u7d22\u5f15\u548c\u5217\u7d22\u5f15\u4ea7\u751f\u65b0\u7684Dataframe\u3002 frame4 = frame.loc[['a', 'b'], states] print(frame4) # Ohio Texas California # a 0 1 2 # b 3 4 5 \u8f74\u5411\u7d22\u5f15\u5220\u9664\u6761\u76ee \u00b6 set_index() , dropna() , fillna() , reset_index() , drop() , replace() \u8fd9\u4e9b\u65b9\u6cd5\u7684 inplace \u5c5e\u6027\u8bbe\u4e3a True \u65f6\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u4f1a\u4fee\u6539Series\u6216DataFrame\u7684\u5c3a\u5bf8\u6216\u5f62\u72b6\uff0c*\u76f4\u63a5*\u64cd\u4f5c\u539f\u5bf9\u8c61\u800c\u4e0d\u8fd4\u56de\u65b0\u5bf9\u8c61\u3002 obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e']) print(obj) # a 0 # b 1 # c 2 # d 3 # e 4 # dtype: int64 obj1 = obj.drop('c') print(obj1) # a 0 # b 1 # d 3 # e 4 # dtype: int64 print(obj1.drop(['d', 'e'])) # a 0 # b 1 # dtype: int64 \u5bf9\u6bd4 inplace=True \u548c False \u7684\u533a\u522b\u3002 inplace=False \u65f6\uff0c obj \u7684\u503c\u6ca1\u6709\u53d8\u5316\u3002 obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e']) print(obj.drop('c', inplace=False)) # \u8bf4\u660e\u751f\u6210\u4e86\u65b0\u5bf9\u8c61 # a 0 # b 1 # d 3 # e 4 # dtype: int64 print(obj) # a 0 # b 1 # c 2 # d 3 # e 4 # dtype: int64 obj.drop('c', inplace=True) \u8f93\u51fa\u662f None \uff0c\u8bf4\u660e\u6ca1\u6709\u751f\u6210\u65b0\u5bf9\u8c61\uff0c\u53d8\u5316\u76f4\u63a5\u4f5c\u7528\u5230 obj \u4e0a\u3002 obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e']) print(obj) print(obj.drop('c', inplace=True)) # \u8bf4\u660e\u6ca1\u6709\u751f\u6210\u65b0\u5bf9\u8c61 # None print(obj) # a 0 # b 1 # d 3 # e 4 # dtype: int64 \u4e0b\u4f8b\u6f14\u793a\u4e86\u8f74\u5411\u7684\u6548\u679c\u3002 \u5982\u679c\u4e0d\u6307\u5b9a\u8f74\u5411axis\uff0c drop() \u4f1a\u9ed8\u8ba4\u6cbf axis=0 \u8fdb\u884c\uff0c\u6240\u4ee5\uff0c\u57280\u8f74\u4e0a\u6267\u884c data.drop(['one', 'two']) \u4f1a\u62a5\u9519\u3002 axis='columns \u4e0e\u6307\u5b9a axis=1 \u540c\u6837\u6548\u679c\u3002 data = pd.DataFrame( np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['one', 'two', 'three', 'four'] ) print(data) # one two three four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 # \u6cbf0\u8f74\u64cd\u4f5c\uff0c\u5220\u9664\u7b26\u5408\u6761\u4ef6\u7684\u884c\u8bb0\u5f55 print(data.drop(['Ohio', 'Colorado'])) # one two three four # Utah 8 9 10 11 # New York 12 13 14 15 print(data.drop(['one', 'two'])) # KeyError: \"['one' 'two'] not found in axis\" # \u6cbf1\u8f74\u64cd\u4f5c\uff0c\u5220\u9664\u7b26\u5408\u6761\u4ef6\u7684\u5217\u8bb0\u5f55 print(data.drop(['one', 'two'], axis=1)) # three four # Ohio 2 3 # Colorado 6 7 # Utah 10 11 # New York 14 15 print(data.drop(['one', 'two'], axis='columns')) # three four # Ohio 2 3 # Colorado 6 7 # Utah 10 11 # New York 14 15 \u518d\u901a\u8fc7\u4e0b\u4f8b\u4f53\u4f1a\u4e00\u4e0b inplace \u53c2\u6570\u7684\u4e0d\u540c\u6548\u679c\u3002 data = pd.DataFrame( { 'Name': ['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], 'class': [11, 12, 10, 9], 'Age': [18, 20, 21, 17] } ) print(data) # Name class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 print(data.rename(columns={'Name': 'FirstName'}, inplace=False)) # FirstName class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 print(data) # Name class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 print(data.rename(columns={'Name': 'FirstName'}, inplace=True)) # \u6ca1\u6709\u751f\u6210\u65b0\u5bf9\u8c61 # None print(data) # FirstName class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 \u7d22\u5f15\u3001\u9009\u62e9\u4e0e\u8fc7\u6ee4 \u00b6 Series\u7684\u7d22\u5f15 obj[...] \u4e0eNumPy\u6570\u7ec4\u7d22\u5f15\u7684\u529f\u80fd\u7c7b\u4f3c\uff0c\u53ea\u4e0d\u8fc7Series\u7684\u7d22\u5f15\u503c\u53ef\u4ee5\u4e0d\u4ec5\u4ec5\u662f\u6574\u6570\u3002 \u4e0b\u4f8b\u4e2d\uff1a obj[1] \u901a\u8fc7\u7d22\u5f15\u4f4d 1 \u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c\u3002 obj[1] \u901a\u8fc7\u7d22\u5f15\u4f4d [1] \u68c0\u7d22\uff0c\u8f93\u51faSeries\u3002 obj['b'] \u901a\u8fc7\u7d22\u5f15\u503c 'b' \u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c\u3002 obj[['b']] \u901a\u8fc7\u7d22\u5f15\u503c ['b'] \u68c0\u7d22\uff0c\u8f93\u51faSeries\u3002 obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd']) print(obj) # a Shobhit # b vaibhav # c vimal # d Sourabh # dtype: object print(obj[1]) # \u901a\u8fc7\u7d22\u5f15\u4f4d\u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c # vaibhav print(obj[[1]]) # b vaibhav # dtype: object print(obj['b']) # \u901a\u8fc7\u7d22\u5f15\u503c\u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c # vaibhav print(obj[['b']]) # \u901a\u8fc7\u7d22\u5f15\u503c\u68c0\u7d22\uff0c\u8f93\u51faSeries # b vaibhav # dtype: object \u4e0b\u9762\u4e00\u7ec4\u7684\u8f93\u51fa\u4e2d\uff0c\u6ce8\u610f\u5bf9\u6bd4\u666e\u901aPython\u5207\u7247\u4e0eSeries\u7684\u5207\u7247\u7684\u5dee\u5f02\u3002 obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd']) print(obj[1]) # vaibhav print(obj[[1]]) # b vaibhav # dtype: object print(obj[1:3]) # b vaibhav # c vimal # dtype: object print(obj['b':'d']) # b vaibhav # c vimal # d Sourabh # dtype: object Series\u7684\u5207\u7247\u7684\u503c\u66f4\u65b0\u3002 obj['b': 'c'] = 5 \u662f\u901a\u8fc7\u7d22\u5f15\u503c\u8fdb\u884c\u66f4\u65b0\uff0c\u76f4\u63a5\u4f5c\u7528\u5728 obj \u3002 obj[1: 3] = 6 \u662f\u901a\u8fc7\u7d22\u5f15\u4f4d\u7f6e\u6765\u66f4\u65b0 obj \u3002 obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd']) obj['b': 'c'] = 5 print(obj) # a Shobhit # b 5 # c 5 # d Sourabh # dtype: object obj[1: 3] = 6 print(obj) # a Shobhit # b 6 # c 6 # d Sourabh # dtype: object DataFrame\u7684\u7d22\u5f15\u4e0e\u5207\u7247\u3002 data[['Three', 'Two']] \u9009\u53d6\u6307\u5b9a\u5217\uff0c\u6ce8\u610f\u8f93\u5165\u5217\u6761\u4ef6\u662f\u5217\u8868 ['Three', 'Two'] \u3002 data = pd.DataFrame( np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['One', 'Two', 'Three', 'Four'] ) print(data) # One Two Three Four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 print(data['Two']) # Ohio 1 # Colorado 5 # Utah 9 # New York 13 # Name: Two, dtype: int64 print(data[['Three', 'Two']]) # Three Two # Ohio 2 1 # Colorado 6 5 # Utah 10 9 # New York 14 13 print(data[:2]) # One Two Three Four # Ohio 0 1 2 3 # Colorado 4 5 6 7 \u5d4c\u5957\uff1a\u6839\u636e\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4\u5207\u7247\u6216\u9009\u62e9\u6570\u636e\u3002 data['Three'] > 5 \u662f\u4e00\u4e2a\u5e03\u5c14\u503c\u5e8f\u5217\u3002 data[data['Three'] > 5] \u8f93\u51fa\u6761\u4ef6\u4e3aTrue\u7684\u7ed3\u679c\u96c6\u3002 print(data['Three'] > 5) # Ohio False # Colorado True # Utah True # New York True # Name: Three, dtype: bool print(data[data['Three'] > 5]) # One Two Three Four # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 \u4f7f\u7528\u5e03\u5c14\u503cDataFrame\u8fdb\u884c\u7d22\u5f15\uff0c\u5df2\u7ecf\u66f4\u65b0\u3002 \u5728\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u8fd9\u79cd\u7d22\u5f15\u65b9\u5f0f\u4f7f\u5f97DataFrame\u5728\u8bed\u6cd5\u4e0a\u66f4\u50cf\u662fNumPy\u4e8c\u7ef4\u6570\u7ec4\u3002 print(data < 5) # One Two Three Four # Ohio True True True True # Colorado True False False False # Utah False False False False # New York False False False False data[data < 5] = 0 print(data) # One Two Three Four # Ohio 0 0 0 0 # Colorado 0 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 \u4f7f\u7528loc\u548ciloc\u9009\u62e9\u6570\u636e\u3002 \u4f7f\u7528\u6807\u7b7e\u540d loc \u6216\u6807\u7b7e\u4f4d\u7f6e iloc \u4ee5NumPy\u98ce\u683c\u7684\u8bed\u6cd5\u4eceDataFrame\u4e2d\u9009\u51faDataframe\u7684\u884c\u548c\u5217\u7684\u5b50\u96c6\u3002 data = pd.DataFrame( np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['One', 'Two', 'Three', 'Four'] ) print(data) # One Two Three Four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 \u4e0b\u4f8b\u901a\u8fc7loc\u5bf9\u6807\u7b7e\u540d\u7b5b\u9009\u884c\u6216\u5217\u6570\u636e\u3002\u4f8b\u5982\uff0c\u8f93\u51fa Colorado \u884c\u6807\u7b7e\u7684 Two \u548c Three \u8fd9\u4e24\u5217\u7684\u503c\uff0c\u4ee5\u884c\u8bb0\u5f55\u7684\u65b9\u5f0f\u5c55\u73b0\u3002 print(data.loc['Colorado', ['Two', 'Three']]) # \u5207\u7247: # Two 5 # Three 6 # Name: Colorado, dtype: int64 print(data.loc[:'Ohio', :'Two']) # \u5207\u7247: 0\u884c\uff0c0,1\u5217 # One Two # Ohio 0 1 \u4e0b\u4f8b\u901a\u8fc7\u6807\u7b7e\u4f4d\u7f6e iloc \u8fdb\u884c\u7c7b\u4f3c\u7684\u6570\u636e\u9009\u62e9\u3002 data.iloc[:3, :2][data > 4] \u6309\u6307\u5b9a\u6761\u4ef6\u8fdb\u884c\u884c\u3001\u5217\u7b5b\u9009\uff0c\u7b26\u5408\u6761\u4ef6 [data > 4] \u7684\u8f93\u51faDataframe\u503c\uff0c\u4e0d\u7b26\u5408\u6761\u4ef6\u7684\u8f93\u51faNaN\u3002 print(data.iloc[[0]]) # 0\u884c # One Two Three Four # Ohio 0 1 2 3 print(data.iloc[[0], [1]]) # \u5207\u7247: 0\u884c\uff0c1\u5217 # Two # Ohio 1 print(data.iloc[1:2, 1:2]) # \u5207\u7247: 1\u884c\uff0c2\u5217 # Two # Ohio 1 print(data.iloc[2, [3, 0, 1]]) # \u5207\u7247: 2\u884c\uff0c\u4f9d\u6b21\u53d63\uff0c0\uff0c1\u5217 # Four 11 # One 8 # Two 9 # Name: Utah, dtype: int64 print(data.iloc[:3, :2][data > 4]) # One Two # Ohio NaN NaN # Colorado NaN 5.0 # Utah 8.0 9.0 \u6574\u6570\u7d22\u5f15 \u00b6 Pandas\u7684Series\u7684\u7d22\u5f15\u503c\u662f\u6574\u6570\u7d22\u5f15\u3002 data = np.arange(3.) ser = pd.Series(data) print(ser) # 0 0.0 # 1 1.0 # 2 2.0 # dtype: float64 print(ser[:1]) # 0 0.0 # dtype: float64 print(ser.loc[:1]) # loc\u7528\u4e8e\u6807\u7b7e\u540d # 0 0.0 # 1 1.0 # dtype: float64 print(ser.iloc[:1]) # iloc\u7528\u4e8e\u6807\u7b7e\u4f4d\u7f6e # 0 0.0 # dtype: float64 data = ['1', 'b', 'e', 3] ser = pd.Series(data) print(ser) # 0 1 # 1 b # 2 e # 3 3 # dtype: object print(ser[:1]) # 0 1 # dtype: object print(ser.loc[:1]) # 0 1 # 1 b # dtype: object print(ser.iloc[:1]) # 0 1 # dtype: object \u5bf9DataFrame\u7684\u66f4\u65b0\u3002 df1 = pd.DataFrame(np.arange(4).reshape((2, 2)), columns=list('ab')) print(df1) # a b # 0 0 1 # 1 2 3 # \u6309\u6807\u7b7e\u540d\u66f4\u65b0 df1.loc[1, :'b'] = np.nan print(df1) # a b # 0 0.0 1.0 # 1 NaN NaN \u7b97\u672f\u548c\u6570\u636e\u5bf9\u9f50 \u00b6 Pandas\u652f\u6301\u5728Series\u6216\u8005DataFrame\u5bf9\u8c61\u4e4b\u95f4\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97\u3002 \u4f8b\uff1a\u4e24\u4e2aSeries\u505a\u7b97\u672f\u52a0\u6cd5\u3002 \u8fd4\u56de\u7684\u7ed3\u679c\u4e5f\u662f\u4e00\u4e2aSeries\u3002 \u8fd4\u56de\u7ed3\u679c\u7684\u7d22\u5f15\u662f\u6bcf\u4e2aSeries\u7684\u7d22\u5f15\u7684\u5e76\u96c6\u3002 \u51e1\u662f\u6ca1\u6709\u5728\u4e24\u4e2aSeries\u90fd\u51fa\u73b0\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0c\u5185\u90e8\u6570\u636e\u5bf9\u9f50\u4f1a\u586b\u5145\u7f3a\u5931\u503cNaN\u3002\u7f3a\u5931\u503c\u4f1a\u5728\u540e\u7eed\u7684\u5176\u5b83\u7b97\u672f\u64cd\u4f5c\u4e0a\u4ea7\u751f\u5f71\u54cd\u3002 \u540c\u65f6\u51fa\u73b0\u5728\u4e24\u4e2aSeries\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0cSeries\u7684\u503c\u505a\u7b97\u672f\u76f8\u52a0\u3002 s1 = pd.Series( [7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'] ) s2 = pd.Series( [-2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'] ) print(s1) # a 7.3 # c -2.5 # d 3.4 # e 1.5 # dtype: float64 print(s2) # a -2.1 # c 3.6 # e -1.5 # f 4.0 # g 3.1 # dtype: float64 print(s1 + s2) # a 5.2 # c 1.1 # d NaN # e 0.0 # f NaN # g NaN # dtype: float64 \u4f8b\uff1a\u4e24\u4e2aDataframe\u505a\u7b97\u672f\u52a0\u6cd5 \u8fd4\u56de\u7ed3\u679c\u4e5f\u662f\u4e00\u4e2aDataframe\u3002 \u8fd4\u56de\u7ed3\u679c\u7684\u884c\u5217\u7d22\u5f15\u662f\u6bcf\u4e2aDataFrame\u7684\u884c\u5217\u7d22\u5f15\u7684\u5e76\u96c6\u3002 \u51e1\u662f\u6ca1\u6709\u5728\u4e24\u4e2aDataFrame\u90fd\u51fa\u73b0\u7684\u4f4d\u7f6e\u5c31\u4f1a\u88ab\u7f6e\u4e3aNaN\u3002 \u4e24\u4e2aDataFrame\u90fd\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5bf9Dataframe\u7684\u503c\u505a\u7b97\u672f\u52a0\u6cd5\u3002 df1 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'] ) df2 = pd.DataFrame( np.arange(12).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'] ) print(df1) # b c d # Ohio 0 1 2 # Texas 3 4 5 # Colorado 6 7 8 print(df2) # b d e # Utah 0 1 2 # Ohio 3 4 5 # Texas 6 7 8 # Oregon 9 10 11 print(df1 + df2) # b c d e # Colorado NaN NaN NaN NaN # Ohio 3.0 NaN 6.0 NaN # Oregon NaN NaN NaN NaN # Texas 9.0 NaN 12.0 NaN # Utah NaN NaN NaN NaN \u5728Series\u6216\u8005DataFrame\u5bf9\u8c61\u4e4b\u95f4\u8fdb\u884c\u7b97\u672f\u64cd\u4f5c\u65f6\uff0c\u6709\u65f6\u9700\u8981\u5bf9\u7f3a\u5931\u503c\u6307\u5b9a\u586b\u5145\u503c\uff0c\u6bd4\u5982\u5f53\u8f74\u6807\u7b7e\u5728\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u5b58\u5728\uff0c\u5728\u53e6\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u4e0d\u5b58\u5728\u65f6\uff0c\u5c06\u7f3a\u5931\u503c\u586b\u5145\u4e3a0\u3002\u4e5f\u5c31\u662f\u8bf4\uff0c\u5982\u679c\u5728\u4e24\u4e2aDataFrame\u90fd\u7f3a\u5931\uff0c\u90a3\u4e48\u4f9d\u7136\u8fd8\u4f1a\u662fNaN\u3002 \u4e0b\u4f8b\u4e2da2\u662f\u5728 df1 \u548c df2 \u90fd\u7f3a\u5931\u7684\u4f4d\u7f6e\uff0c\u6240\u4ee5\u5373\u4f7f fill_value=0 \uff0ca2\u4ecd\u7136\u662fNaN\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('bcd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # b c d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 # \u5bf9df1\u548cdf2\u5c31\u7b97\u672f\u548c\uff0c\u5bf9\u5e94\u6ca1\u6709\u884c\u5217\u5171\u540c\u7684\u4ea4\u96c6\u7684\u5730\u65b9\u586b\u5145\u7a7a\u503cNaN\uff0c\u6709\u4ea4\u96c6\u7684\u5730\u65b9\u6c42\u7b97\u672f\u548c\u3002 print(df1.add(df2)) # a b c d # 0 NaN 1.0 NaN NaN # 1 NaN 6.0 NaN NaN # 2 NaN NaN NaN NaN # \u5bf9df1\u548cdf2\u5c31\u7b97\u672f\u548c\uff0c\u5bf9\u5e94\u6ca1\u6709\u884c\u5217\u5171\u540c\u7684\u4ea4\u96c6\u7684\u5730\u65b9\u586b\u5145\u7a7a\u503c0\uff0c\u6709\u4ea4\u96c6\u7684\u5730\u65b9\u6c42\u7b97\u672f\u548c\u3002 print(df1.add(df2, fill_value=0)) # df2.add(df1, fill_value=0) \u8fd4\u56de\u540c\u6837\u7684\u7ed3\u679c # a b c d # 0 0.0 1.0 1.0 2.0 # 1 2.0 6.0 4.0 5.0 # 2 NaN 6.0 7.0 8.0 \u4e0b\u4f8b\u4e2db2\u662f\u5728 df1 \u548c df2 \u90fd\u7f3a\u5931\u7684\u4f4d\u7f6e\uff0c\u6240\u4ee5\u5373\u4f7f fill_value=0 \uff0cb2\u4ecd\u7136\u662fNaN\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('acd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # a c d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 print(df1.add(df2, fill_value=0)) # a b c d # 0 0.0 1.0 1.0 2.0 # 1 5.0 3.0 4.0 5.0 # 2 6.0 NaN 7.0 8.0 \u4e0b\u4f8b\u4e2d\u6ca1\u6709\u4e24\u4e2aDataFrame\u5171\u540c\u7f3a\u5931\u7684\u60c5\u51b5\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('abd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # a b d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 print(df1.add(df2, fill_value=0)) # a b d # 0 0.0 2.0 2.0 # 1 5.0 7.0 5.0 # 2 6.0 7.0 8.0 \u4e0b\u9762\u662fSeries\u548cDataFrame\u7684\u7b97\u672f\u65b9\u6cd5\u3002 add\uff0cradd\uff1a\u52a0\u6cd5(+) sub\uff0crsub\uff1a\u51cf\u6cd5(-) div\uff0crdiv\uff1a\u9664\u6cd5(/) floordiv\uff0crfloordiv\uff1a\u6574\u9664(//) mul\uff0crmul\uff1a\u4e58\u6cd5(*) pow\uff0crpow\uff1a\u5e42\u6b21\u65b9(**) \u4e0a\u8ff0\u6bcf\u4e2a\u65b9\u6cd5\u90fd\u6709\u4e00\u4e2a\u4ee5r\u5f00\u5934\u7684\u526f\u672c\uff0c\u8fd9\u4e9b\u526f\u672c\u65b9\u6cd5\u7684\u53c2\u6570\u662f\u7ffb\u8f6c\u7684\u3002\u6bd4\u5982\uff0c\u6c42DataFrame\u5f53\u4e2d\u6240\u6709\u5143\u7d20\u7684\u5012\u6570 1/df \uff0c\u53ef\u4ee5\u5199\u6210df.rdiv(1)\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('abd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # a b d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 print(df1.radd(df2, fill_value=0)) # a b d # 0 0.0 2.0 2.0 # 1 5.0 7.0 5.0 # 2 6.0 7.0 8.0 print(df1.sub(df2, fill_value=0)) # a b d # 0 0.0 0.0 -2.0 # 1 -1.0 -1.0 -5.0 # 2 -6.0 -7.0 -8.0 print(df1.div(df2, fill_value=0)) # a b d # 0 NaN 1.00 0.0 # 1 0.666667 0.75 0.0 # 2 0.000000 0.00 0.0 print(df1.floordiv(df2, fill_value=0)) # a b d # 0 NaN 1.0 0.0 # 1 0.0 0.0 0.0 # 2 0.0 0.0 0.0 print(df1.mul(df2, fill_value=0)) # a b d # 0 0.0 1.0 0.0 # 1 6.0 12.0 0.0 # 2 0.0 0.0 0.0 print(df1.pow(df2, fill_value=0)) # a b d # 0 1.0 1.0 0.0 # 1 8.0 81.0 0.0 # 2 0.0 0.0 0.0 DataFrame\u548cSeries\u95f4\u7684\u7b97\u672f\u64cd\u4f5c \u00b6 DataFrame\u548cSeries\u95f4\u7684\u7b97\u672f\u64cd\u4f5c\u4e0eNumPy\u4e2d\u4e0d\u540c\u7ef4\u5ea6\u6570\u7ec4\u95f4\u7684\u64cd\u4f5c\u7c7b\u4f3c\u3002 \u4e0d\u540c\u7ef4\u5ea6NumPy\u6570\u7ec4\u95f4\u7684\u7b97\u672f\u64cd\u4f5c \u00b6 \u4ecearr\u4e2d\u51cf\u53bbarr[0]\u65f6\uff0c\u51cf\u6cd5\u6cbf0\u8f74\u5728\u6bcf\u4e00\u884c\u90fd\u8fdb\u884c\u4e86\u64cd\u4f5c\u3002\u8fd9\u5c31\u662f\u6240\u8c13\u7684\u5e7f\u64ad\u673a\u5236\u3002 arr = np.arange(12).reshape((3, 4)) print(arr) # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] print(arr[0]) # [0 1 2 3] print(arr - arr[0]) # [[0 0 0 0] # [4 4 4 4] # [8 8 8 8]] DataFrame\u548cSeries\u95f4\u7684\u7b97\u672f\u64cd\u4f5c \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cDataFrame\u548cSeries\u7684\u6570\u5b66\u64cd\u4f5c\u4e2d\u4f1a\u5c06Series\u7684\u7d22\u5f15\u548cDataFrame\u7684*\u5217*\u8fdb\u884c\u5339\u914d\uff0c\u5e76*\u5e7f\u64ad\u5230\u5404\u884c*. \u5982\u679c\u4e00\u4e2a\u7d22\u5f15\u503c\u4e0d\u5728DataFrame\u7684\u5217\u4e2d\uff0c\u4e5f\u4e0d\u5728Series\u7684\u7d22\u5f15\u4e2d\uff0c\u5219\u65b0\u5bf9\u8c61\u4f1a\u6784\u5efa\u5e76\u96c6\u7d22\u5f15\u3002 frame = pd.DataFrame( np.arange(12).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'] ) print(frame) # b d e # Utah 0 1 2 # Ohio 3 4 5 # Texas 6 7 8 # Oregon 9 10 11 # \u622a\u53d6frame\u7684\u7b2c0\u884c\uff0c\u5217\u6807\u7b7e\u53d8\u6210\u65b0Serise\u7684\u7d22\u5f15\u3002 series = frame.iloc[0] print(series) # b 0 # d 1 # e 2 # Name: Utah, dtype: int64 series2 = pd.Series( range(3), index=list('bef') ) print(series2) # b 0 # e 1 # f 2 # dtype: int64 # \u622a\u53d6frame\u7684d\u5217\uff0c\u884c\u6807\u7b7e\u53d8\u6210\u65b0Serise\u7684\u7d22\u5f15\u3002 series3 = frame['d'] print(series3) # Utah 1 # Ohio 4 # Texas 7 # Oregon 10 # Name: d, dtype: int64 # \u5c06Series\u7684\u7d22\u5f15\u548cDataFrame\u7684\u5217\u6807\u7b7e\u8fdb\u884c\u5339\u914d\uff0cSeries\u7684\u503c\u6cbfDataFrame\u76840\u8f74\u5e7f\u64ad\u5230\u5404\u4e2a\u884c\u3002 print(frame - series) # frame: series Result: # b d e # b 0 # b d e # Utah 0 1 2 # d 1 # Utah 0 0 0 # Ohio 3 4 5 # e 2 # Ohio 3 3 3 # Texas 6 7 8 # Name: Utah, dtype: int64 # Texas 6 6 6 # Oregon 9 10 11 # Oregon 9 9 9 # \u5c06Series\u7684\u7d22\u5f15\u548cDataFrame\u7684\u5217\u6807\u7b7e\u8fdb\u884c\u5339\u914d\uff0cSeries\u7684\u503c\u6cbfDataFrame\u76840\u8f74\u5e7f\u64ad\u5230\u5404\u4e2a\u884c\uff0c\u7f3a\u5931\u4f4d\u7f6e\u586b\u5145\u7a7a\u503cNaN\u3002 print(frame - series2) # frame: series2 Result: # b d e # b 0 # b d e f # Utah 0 1 2 # e 1 # Utah 0.0 NaN 1.0 NaN # Ohio 3 4 5 # f 2 # Ohio 3.0 NaN 4.0 NaN # Texas 6 7 8 # dtype: int64 # Texas 6.0 NaN 7.0 NaN # Oregon 9 10 11 # Oregon 9.0 NaN 10.0 NaN # \u6539\u4e3a\u5728\u5217\u4e0a\u8fdb\u884c\u5e7f\u64ad\uff0c\u5728\u884c\u4e0a\u5339\u914d\uff0c\u5fc5\u987b\u4f5c\u7528\u5728\u67d0\u79cd\u7b97\u672f\u65b9\u6cd5\u4e0a\u3002\u4e0b\u4f8b\u4e2dSeries\u7684\u503c\u6cbfDataFrame\u76840\u8f74\u5e7f\u64ad\u5230\u5404\u4e2a\u884c\uff08\u6309index\u5339\u914d\u8fdb\u884c\u884c\u64cd\u4f5c\uff09\u3002 print(frame.sub(series3, axis='index')) # \u6216axis=0 # frame: series3 Result: # b d e # Utah 1 # b d e # Utah 0 1 2 # Ohio 4 # Utah -1 0 1 # Ohio 3 4 5 # Texas 7 # Ohio -1 0 1 # Texas 6 7 8 # Oregon 10 # Texas -1 0 1 # Oregon 9 10 11 # Name: d, dtype: int64 # Oregon -1 0 1 \u51fd\u6570\u5e94\u7528\u548c\u6620\u5c04 \u00b6 NumPy\u7684\u901a\u7528\u51fd\u6570\uff08\u9010\u5143\u7d20\u6570\u7ec4\u65b9\u6cd5\uff09\u5bf9pandas\u5bf9\u8c61\uff08DataFrame\u548cSeries\uff09\u4e5f\u6709\u6548\u3002 frame = pd.DataFrame( np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'] ) print(frame) # b d e # Utah 2.737734 -0.379977 0.758933 # Ohio 0.847497 0.839583 -2.192021 # Texas -0.907544 -0.457436 -1.907396 # Oregon 0.389362 0.250170 1.065889 # \u5bf9DataFrame\u5bf9\u8c61\u8ba1\u7b97\u7edd\u5bf9\u503c\u3002 print(np.abs(frame)) # b d e # Utah 2.737734 0.379977 0.758933 # Ohio 0.847497 0.839583 2.192021 # Texas 0.907544 0.457436 1.907396 # Oregon 0.389362 0.250170 1.065889 # f\u8fd4\u56de\u4e00\u4e2a\u6807\u91cf\u503c f = lambda x: x.max() - x.min() # \u6cbf0\u8f74\u5e94\u7528f\uff08\u5bf9\u6bcf\u5217\u7684\u6240\u6709\u884c\u5143\u7d20\u8fdb\u884cf\u8ba1\u7b97\uff09, \u9ed8\u8ba4axis=0 print(frame.apply(f)) # b 3.645278 # d 1.297019 # e 3.257911 # dtype: float64 # \u6cbf1\u8f74\u5e94\u7528f\uff08\u5bf9\u6bcf\u884c\u7684\u6240\u6709\u5217\u5143\u7d20\u8fdb\u884cf\u8ba1\u7b97\uff09 print(frame.apply(f, axis=1)) # Utah 3.117711 # Ohio 3.039518 # Texas 1.449961 # Oregon 0.815720 # dtype: float64 # \u5b9a\u4e49\u51fd\u6570f\uff0c\u8fd4\u56de\u5e26\u6709\u591a\u4e2a\u503c\u7684Series\u3002 def f(x): return pd.Series( [x.min(), x.max()], index=['min', 'max'] ) print(frame.apply(f)) # b d e # min -0.907544 -0.457436 -2.192021 # max 2.737734 0.839583 1.065889 # \u5b9a\u4e49\u51fd\u6570f\uff0c\u4f7f\u7528applymap\u65b9\u6cd5\u683c\u5f0f\u5316\u5b57\u7b26\uff0c\u5c06\u4e00\u4e2a\u9010\u5143\u7d20\u7684\u51fd\u6570\u5e94\u7528\u5230Series\u4e0a\u3002 f = lambda x: '%.2f' % x print(frame.applymap(f)) # # b d e # Utah 2.74 -0.38 0.76 # Ohio 0.85 0.84 -2.19 # Texas -0.91 -0.46 -1.91 # Oregon 0.39 0.25 1.07 print(frame['e'].map(f)) # Utah 0.76 # Ohio -2.19 # Texas -1.91 # Oregon 1.07 # Name: e, dtype: object \u6392\u5e8f\u548c\u6392\u540d \u00b6 \u4f7f\u7528sort_index\u65b9\u6cd5\uff0c\u6309\u884c\u6216\u5217\u7d22\u5f15\u8fdb\u884c\u5b57\u5178\u578b\u6392\u5e8f\uff0c\u8fd4\u56de\u4e00\u4e2a\u65b0\u7684\u6392\u5e8f\u597d\u7684Pandas\u5bf9\u8c61\u3002 Series\u6392\u5e8f \u00b6 \u5bf9Series\u8fdb\u884c\u7d22\u5f15\u6392\u5e8f\u548c\u503c\u6392\u5e8f\u3002 obj = pd.Series( range(4), index=list('dabc') ) print(obj) # d 0 # a 1 # b 2 # c 3 # dtype: int64 print(obj.sort_index()) # a 1 # b 2 # c 3 # d 0 # dtype: int64 # print(obj.sort_values()) # d 0 # a 1 # b 2 # c 3 # dtype: int64 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6240\u6709\u7684\u7f3a\u5931\u503c\u90fd\u4f1a\u88ab\u6392\u5e8f\u81f3Series\u7684\u5c3e\u90e8\u3002 obj = pd.Series([4, np.nan, 7, np.nan, -3, 2]) print(obj) # 0 4.0 # 1 NaN # 2 7.0 # 3 NaN # 4 -3.0 # 5 2.0 # dtype: float64 print(obj.sort_values()) # 4 -3.0 # 5 2.0 # 0 4.0 # 2 7.0 # 1 NaN # 3 NaN # dtype: float64 DataFrame\u6392\u5e8f \u00b6 frame = pd.DataFrame( [[0, 1, 10, 3], [4, 5, 6, 21], [8, 9, 2, 21]], index=['three', 'one', 'five'], columns=list('dabc') ) print(frame) # d a b c # three 0 1 10 3 # one 4 5 6 21 # five 8 9 2 21 print(frame.index) # Index(['three', 'one', 'five'], dtype='object') # \u9ed8\u8ba40\u8f74\uff0c\u6240\u6709\u884c\u8fdb\u884c\u7d22\u5f15\u9996\u5b57\u6bcd\u5347\u5e8f print(frame.sort_index()) # d a b c # five 8 9 2 21 # one 4 5 6 21 # three 0 1 10 3 # \u6307\u5b9a0\u8f74\uff0c\u6240\u6709\u884c\u8fdb\u884c\u7d22\u5f15\u9996\u5b57\u6bcd\u5347\u5e8f print(frame.sort_index(axis=0)) # d a b c # five 8 9 2 21 # one 4 5 6 21 # three 0 1 10 3 # \u6307\u5b9a0\u8f74\uff0c\u6240\u6709\u884c\u8fdb\u884c\u7d22\u5f15\u9996\u5b57\u6bcd\u964d\u5e8f print(frame.sort_index(axis=0, ascending=False)) # d a b c # three 0 1 10 3 # one 4 5 6 21 # five 8 9 2 21 # \u6307\u5b9a1\u8f74\uff0c\u6240\u6709\u5217\u8fdb\u5217\u7d22\u5f15\u9996\u5b57\u6bcd\u5347\u5e8f print(frame.sort_index(axis=1)) # a b c d # three 1 10 3 0 # one 5 6 21 4 # five 9 2 21 8 # \u6307\u5b9a1\u8f74\uff0c\u6240\u6709\u5217\u8fdb\u5217\u7d22\u5f15\u9996\u5b57\u6bcd\u964d\u5e8f print(frame.sort_index(axis=1, ascending=False)) # d c b a # three 0 3 10 1 # one 4 21 6 5 # five 8 21 2 9 # \u6309\u6307\u5b9a\u5355\u5217\u8fdb\u884c\u503c\u6392\u5e8f\uff08\u964d\u5e8f\uff09 print(frame.sort_values(by=['c'], ascending=False)) # d a b c # one 4 5 6 21 # five 8 9 2 21 # three 0 1 10 3 # \u6309\u6307\u5b9a\u591a\u5217\u8fdb\u884c\u503c\u6392\u5e8f\uff08\u964d\u5e8f\uff09\uff0c\u5148\u5bf9b\u964d\u5e8f\uff0c\u518d\u5bf9d\u964d\u5e8f print(frame.sort_values(by=['c', 'd'], ascending=False)) # d a b c # five 8 9 2 21 # one 4 5 6 21 # three 0 1 10 3 \u6392\u540d \u00b6 **\u6392\u540d**\u662f\u6307\u5bf9\u6570\u7ec4\u4ece1\u5230\u6709\u6548\u6570\u636e\u70b9\u603b\u6570\u5206\u914d\u540d\u6b21\u7684\u64cd\u4f5c\u3002 Series\u548cDataFrame\u7684 rank \u65b9\u6cd5\u662f\u5b9e\u73b0\u6392\u540d\u7684\u65b9\u6cd5\uff0c df.rank(ascending=False, method='max') \u3002 ascending \uff1a\u6392\u540d\u65b9\u5f0f\uff0c\u9ed8\u8ba4\u4ece\u4f4e\u5230\u9ad8\uff0c ascending=False \u8868\u793a\u4ece\u9ad8\u5230\u4f4e\uff1b method \uff1a\u6392\u540d\u65b9\u5f0f\uff0c\u5305\u62ec\uff1a average:\u9ed8\u8ba4\uff0c\u5728\u76f8\u7b49\u5206\u7ec4\u4e2d\uff0c\u4e3a\u5404\u4e2a\u503c\u5206\u914d\u5e73\u5747\u6392\u540d\uff0c\u5373\u76f8\u540c\u503c\u7684\u548c\u9664\u4ee5\u8be5\u503c\u7684\u4e2a\u6570\uff0c\u5373\u4e3a\u8be5\u503c\u7684\u540d\u6b21\u3002 min:\u4f7f\u7528\u6574\u4e2a\u5206\u7ec4\u7684\u6700\u5c0f\u6392\u540d\uff0c\u5373\uff0c\u5bf9\u5e94\u76f8\u540c\u503c\uff0c\u53d6\u5728\u987a\u5e8f\u6392\u540d\u4e2d\u6700\u5c0f\u7684\u90a3\u4e2a\u6392\u540d\u4f5c\u4e3a\u6240\u6709\u8be5\u503c\u7684\u6392\u540d\u3002 max:\u4f7f\u7528\u6574\u4e2a\u5206\u7ec4\u7684\u6700\u5927\u6392\u540d\uff0c\u5373\uff0c\u5bf9\u5e94\u76f8\u540c\u503c\uff0c\u53d6\u5728\u987a\u5e8f\u6392\u540d\u4e2d\u6700\u5927\u7684\u90a3\u4e2a\u6392\u540d\u4f5c\u4e3a\u6240\u6709\u8be5\u503c\u7684\u6392\u540d\u3002 first:\u6309\u503c\u518d\u539f\u59cb\u6570\u636e\u4e2d\u51fa\u73b0\u987a\u5e8f\u5206\u914d\u6392\u540d\uff0c\u8c01\u51fa\u73b0\u7684\u4f4d\u7f6e\u9760\u524d\uff0c\u8c01\u7684\u6392\u540d\u9760\u524d\u3002 dense:\u7c7b\u4f3cmin\u65b9\u6cd5\uff0c\u4f46\u6392\u540d\u603b\u662f\u5728\u7ec4\u95f4\u589e\u52a01\uff0c\u800c\u4e0d\u662f\u7ec4\u4e2d\u76f8\u540c\u7684\u5143\u7d20\u6570\uff0c\u5373\u76f8\u540c\u503c\u7684\u6392\u540d\u76f8\u540c\uff0c\u5176\u4ed6\u4f9d\u6b21\u52a01\u5373\u53ef\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0crank\u662f\u901a\u8fc7\u201c\u4e3a\u5404\u7ec4\u5206\u914d\u4e00\u4e2a\u5e73\u5747\u6392\u540d\u201d\u7684\u65b9\u5f0f\u7834\u574f\u5e73\u7ea7\u5173\u7cfb # \u6309\u7167\u6bcf\u4e2a\u5143\u7d20\u7684\u5927\u5c0f\u987a\u5e8f\u7ed9\u51fa\u4e00\u4e2a\u5e73\u5747\u6392\u540d obj = pd.Series([7, -5, 7, 4, 2, 0, 4]) print(obj) # 0 7 # 1 -5 # 2 7 # 3 4 # 4 2 # 5 0 # 6 4 # dtype: int64 print(obj.rank()) # 0 6.5 # 1 1.0 # 2 6.5 # 3 4.5 # 4 3.0 # 5 2.0 # 6 4.5 # dtype: float64 # index value rank # 2 -5 1 # 6 0 2 # 5 2 3 # 4 4 4.5 # 7 4 4.5 # 1 7 6.5 # 3 7 6.5 # \u6839\u636e\u5143\u7d20\u7684\u89c2\u5bdf\u987a\u5e8f\u8fdb\u884c\u5206\u914d\u3002\u5143\u7d200\u548c2\u6ca1\u6709\u4f7f\u7528\u5e73\u5747\u6392\u540d6.5\uff0c\u5b83\u4eec\u88ab\u8bbe\u6210\u4e866\u548c7\uff0c\u56e0\u4e3a\u6570\u636e\u4e2d\u6807\u7b7e0\u4f4d\u4e8e\u6807\u7b7e2\u7684\u524d\u9762\u3002 print(obj.rank(method='first')) # 0 6.0 # 1 1.0 # 2 7.0 # 3 4.0 # 4 3.0 # 5 2.0 # 6 5.0 # dtype: float64 # \u6309\u7167max\u8fdb\u884c\u5347\u5e8f\u548c\u964d\u5e8f print(obj.rank(ascending=False, method='max')) print(obj.rank(ascending=True, method='max')) # Original Series Max with inc Max with dec # 0 7 # 0 2.0 (\u6700\u5c0f) # 0 7.0 (\u6700\u5927) # 1 -5 # 1 7.0 (\u6700\u5927) # 1 1.0 (\u6700\u5c0f) # 2 7 # 2 2.0 (\u6700\u5c0f) # 2 7.0 (\u6700\u5927) # 3 4 # 3 4.0 # 3 5.0 # 4 2 # 4 5.0 # 4 3.0 # 5 0 # 5 6.0 # 5 2.0 # 6 4 # 6 4.0 # 6 5.0 # dtype: float64 # dtype: float64 # dtype: float64 frame = pd.DataFrame( {'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1], 'c': [-2, 5, 8, -2]} ) print(frame) # b a c # 0 4.3 0 -2 # 1 7.0 1 5 # 2 -3.0 0 8 # 3 2.0 1 -2 # \u6cbf1\u8f74\u5bf9DataFrame\u8fdb\u884crank\u64cd\u4f5c\uff0c\u5373\uff0c\u6bcf\u4e00\u884c\u5404\u5143\u7d20\u8fdb\u884crank\u3002 print(frame.rank(axis='columns')) # axis=1 # b a c # 0 3.0 2.0 1.0 # 1 3.0 1.0 2.0 # 2 1.0 2.0 3.0 # 3 3.0 2.0 1.0 \u542b\u6709\u91cd\u590d\u6807\u7b7e\u7684\u8f74\u7d22\u5f15 \u00b6 \u5c3d\u7ba1\u5f88\u591apandas\u51fd\u6570\uff08\u6bd4\u5982reindex\uff09\u9700\u8981\u6807\u7b7e\u662f\u552f\u4e00\u7684\uff0c\u4f46\u8fd9\u4e2a\u5e76\u4e0d\u662f\u5f3a\u5236\u6027\u7684\u3002 \u7d22\u5f15\u7684is_unique\u5c5e\u6027\u53ef\u4ee5\u68c0\u67e5\u6807\u7b7e\u662f\u5426\u552f\u4e00\u3002 \u5e26\u6709\u91cd\u590d\u7d22\u5f15\u7684\u60c5\u51b5\u4e0b\uff0c\u4e00\u4e2a\u7d22\u5f15\u6807\u7b7e\u4f1a\u4ee5\u5e8f\u5217\u65b9\u5f0f\u8fd4\u56de\u591a\u4e2a\u6761\u76ee\u3002\u4e0d\u91cd\u590d\u7684\u7d22\u5f15\u5219\u4f1a\u4ee5\u6807\u91cf\u503c\u7684\u5f62\u5f0f\u8fd4\u56de\u5355\u4e2a\u6761\u76ee\uff0c\u8fd9\u53ef\u80fd\u4f1a\u4f7f\u4ee3\u7801\u66f4\u590d\u6742\u3002 obj = pd.Series(range(5), index=['a', 'b', 'a', 'c', 'b']) print(obj) # a 0 # b 1 # a 2 # c 3 # b 4 # dtype: int64 print(obj.is_unique) # True print(obj.index.is_unique) # False # \u8fd4\u56de\u91cd\u590d\u7d22\u5f15\u5bf9\u5e94\u503c\u7684\u5e8f\u5217\u3002 print(obj['a']) # a 0 # a 2 # dtype: int64 df = pd.DataFrame(np.random.randn(4, 3), index=['a', 'a', 'b', 'b']) print(df) # 0 1 2 # a -0.726164 0.531540 -0.521611 # a -1.539807 -0.710880 -0.992789 # b -0.975970 -0.470725 0.121958 # b -0.301495 1.072322 -1.542296 print(df.index.is_unique) # False print(df.loc['b']) # 0 1 2 # b -0.520008 0.052574 0.638529 # b -1.928705 -1.099534 -1.605296 \u63cf\u8ff0\u6027\u7edf\u8ba1\u6982\u8ff0\u4e0e\u8ba1\u7b97 \u00b6 pandas\u5305\u542b\u4e86\u4e00\u4e9b\u5e38\u7528\u6570\u5b66\u3001\u7edf\u8ba1\u5b66\u65b9\u6cd5\u3002\u5176\u4e2d\u5927\u90e8\u5206\u5c5e\u4e8e\u5f52\u7ea6\u6216\u6c47\u603b\u7edf\u8ba1\u7684\u7c7b\u522b\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u4eceDataFrame\u7684\u884c\u6216\u5217\u4e2d\u62bd\u53d6\u4e00\u4e2aSeries\u6216\u4e00\u7cfb\u5217\u503c\uff08\u5982\u603b\u548c\u6216\u5e73\u5747\u503c\uff09\u3002 \u4e0eNumPy\u6570\u7ec4\u4e2d\u7684\u7c7b\u4f3c\u65b9\u6cd5\u76f8\u6bd4\uff0cpandas\u5185\u5efa\u4e86\u5904\u7406\u7f3a\u5931\u503c\u7684\u529f\u80fd\u3002 \u5f52\u7ea6\u65b9\u6cd5: sum() \u79ef\u7d2f\u578b\u65b9\u6cd5: cumsun() \u65e2\u4e0d\u662f\u5f52\u7ea6\u578b\u65b9\u6cd5\u4e5f\u4e0d\u662f\u79ef\u7d2f\u578b\u65b9\u6cd5: describe() df = pd.DataFrame( [[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=list('abcd'), columns=['one', 'two'] ) print(df) # one two # a 1.40 NaN # b 7.10 -4.5 # c NaN NaN # d 0.75 -1.3 # axis=0, \u8fd4\u56de\u4e00\u4e2a\u6bcf\u5217\u7b97\u672f\u548c\u7684Series print(df.sum()) # one 9.25 # two -5.80 # dtype: float64 # axis=1\u4e14skipna=True, \u8fd4\u56de\u4e00\u4e2a\u6bcf\u884c\u548c\u7684Series, \u5ffd\u7565NA\u503c, \u586b0\u3002 print(df.sum(axis=1)) # a 1.40 # b 2.60 # c 0.00 # d -0.55 # dtype: float64 # \u4e0d\u5ffd\u7565NA\u503c\uff0c\u586bNaN\u3002 print(df.sum(axis=1, skipna=False)) # a NaN # b 2.60 # c NaN # d -0.55 # dtype: float64 # \u53ea\u67091\u7ea7\u7d22\u5f15\uff0c\u6240\u4ee5level=0\u548c\u539f\u7d22\u5f15\u6ca1\u6709\u533a\u522b\uff0cNaN\u586b\u51450\u3002 print(df.groupby(level=0).sum()) # one two # a 1.40 0.0 # b 7.10 -4.5 # c 0.00 0.0 # d 0.75 -1.3 # \u5217one\u7684\u6700\u5927\u503c\u662f\u5728\u7d22\u5f15b, \u5217two\u7684\u6700\u5927\u503c\u662f\u5728\u7d22\u5f15d print(df.idxmax()) # one b # two d # dtype: object print(df.idxmin()) # one d # two b # dtype: object # cumsun\u7684\u610f\u601d\u662f\u7b2cn\u6b21\u7684\u548c\u662fn-1\u6b21\u7684\u548c\u4e0en\u7684\u548c\uff0cone\u5217d\u884c\u7684\u548c\u5c31\u662fone\u5217a\u3001b\u3001c\u3001d\u503c\u7684\u603b\u548c\u3002 print(df.cumsum()) # one two # a 1.40 NaN # b 8.50 -4.5 # c NaN NaN # d 9.25 -5.8 \u901a\u8fc7describe\u4ea7\u751f\u7edf\u8ba1\u4fe1\u606f\uff0c\u6ce8\u610f\uff0c\u6570\u503c\u578b\u548c\u975e\u6570\u503c\u578b\u7684describe\u7684\u4fe1\u606f\u662f\u4e0d\u540c\u7684\u3002 # \u4e00\u6b21\u6027\u4ea7\u751f\u591a\u4e2a\u6c47\u603b\u7edf\u8ba1 print(df.describe()) # one two # count 3.000000 2.000000 # mean 3.083333 -2.900000 # std 3.493685 2.262742 # min 0.750000 -4.500000 # 25% 1.075000 -3.700000 # 50% 1.400000 -2.900000 # 75% 4.250000 -2.100000 # max 7.100000 -1.300000 obj = pd.Series(['a', 'a', 'b', 'c'] * 4) print(obj) # 0 a # 1 a # 2 b # 3 c # 4 a # 5 a # 6 b # 7 c # 8 a # 9 a # 10 b # 11 c # 12 a # 13 a # 14 b # 15 c # dtype: object # \u9488\u5bf9\u975e\u6570\u503c\u578b\u6570\u636e\uff0cdescribe\u4ea7\u751f\u53e6\u4e00\u79cd\u6c47\u603b\u7edf\u8ba1 print(obj.describe()) # count 16 # unique 3 # top a # freq 8 # dtype: object \u76f8\u5173\u6027\u548c\u534f\u65b9\u5dee \u00b6 \u534f\u65b9\u5dee\u4e0e\u76f8\u5173\u7cfb\u6570\u4e5f\u662f\u5728\u65f6\u57df\u5206\u6790\u65f6\u5e38\u89c1\u7684\u4e24\u4e2a\u6982\u5ff5\uff0c\u4ed6\u4eec\u90fd\u662f\u7528\u6765\u63cf\u8ff0\u6570\u636e\u201c\u50cf\u4e0d\u50cf\u201d\u7684\u3002 \u534f\u65b9\u5dee\u7684\u901a\u4fd7\u7406\u89e3\uff1a \u4e24\u4e2a\u53d8\u91cf\u5728\u53d8\u5316\u8fc7\u7a0b\u4e2d\u662f\u540c\u65b9\u5411\u53d8\u5316\u8fd8\u662f\u53cd\u65b9\u5411\u53d8\u5316\uff1f\u76f8\u540c\u6216\u8005\u76f8\u53cd\u7a0b\u5ea6\u5982\u4f55\uff1f \u4f60\u53d8\u5927\uff0c\u540c\u65f6\u6211\u53d8\u5927\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u662f\u540c\u5411\u53d8\u5316\uff0c\u8fd9\u65f6\u534f\u65b9\u5dee\u5c31\u662f\u6b63\u7684\u3002 \u4f60\u53d8\u5927\uff0c\u540c\u65f6\u6211\u53d8\u5c0f\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u662f\u53cd\u5411\u53d8\u5316\uff0c\u8fd9\u65f6\u534f\u65b9\u5dee\u5c31\u662f\u8d1f\u7684\u3002 \u4ece\u6570\u503c\u770b\uff0c\u534f\u65b9\u5dee\u7684\u6570\u503c\u8d8a\u5927\uff0c\u4e24\u4e2a\u53d8\u91cf\u540c\u5411\u7a0b\u5ea6\u4e5f\u5c31\u8d8a\u5927\u3002\u53cd\u4e4b\u4ea6\u7136\u3002 \u76f8\u5173\u7cfb\u6570\u7684\u901a\u4fd7\u7406\u89e3\uff1a \u7528X\uff0cY\u7684\u534f\u65b9\u5dee\u9664\u4ee5X\u7684\u6807\u51c6\u5dee\u548cY\u7684\u6807\u51c6\u5dee\u3002\u76f8\u5173\u7cfb\u6570\u4e5f\u53ef\u4ee5\u770b\u6210\u534f\u65b9\u5dee\uff0c\u4e00\u79cd\u63d0\u51fa\u4e86\u4e24\u4e2a\u53d8\u91cf\u91cf\u7eb2\u5f71\u54cd\u3001\u6807\u51c6\u5316\u540e\u7684\u7279\u6b8a\u534f\u65b9\u5dee\u3002\u6240\u4ee5\uff1a\u4e5f\u53ef\u4ee5\u53cd\u6620\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u65f6\u662f\u540c\u5411\u8fd8\u662f\u53cd\u5411\uff0c\u5982\u679c\u540c\u5411\u53d8\u5316\u5c31\u4e3a\u6b63\uff0c\u53cd\u5411\u53d8\u5316\u5c31\u4e3a\u8d1f\u3002 \u7531\u4e8e\u662f\u6807\u51c6\u7248\u540e\u7684\u534f\u65b9\u5dee\uff0c\u76f8\u5173\u7cfb\u6570\u6d88\u9664\u4e86\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u5e45\u5ea6\u7684\u5f71\u54cd\uff0c\u800c\u53ea\u662f\u5355\u7eaf\u53cd\u5e94\u4e24\u4e2a\u53d8\u91cf\u6bcf\u5355\u4f4d\u53d8\u5316\u65f6\u7684\u76f8\u4f3c\u7a0b\u5ea6\u3002 \u603b\u7ed3\uff1a \u5bf9\u4e8e\u4e24\u4e2a\u53d8\u91cfX\u3001Y\uff0c \u5f53\u4ed6\u4eec\u7684\u76f8\u5173\u7cfb\u6570\u4e3a1\u65f6\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u65f6\u7684\u6b63\u5411\u76f8\u4f3c\u5ea6\u6700\u5927\u3002 \u5f53\u4ed6\u4eec\u7684\u76f8\u5173\u7cfb\u6570\u4e3a\uff0d1\u65f6\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u7684\u53cd\u5411\u76f8\u4f3c\u5ea6\u6700\u5927\u3002 \u968f\u7740\u4ed6\u4eec\u76f8\u5173\u7cfb\u6570\u51cf\u5c0f\uff0c\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u65f6\u7684\u76f8\u4f3c\u5ea6\u4e5f\u53d8\u5c0f\uff0c\u5f53\u76f8\u5173\u7cfb\u6570\u4e3a0\u65f6\uff0c\u4e24\u4e2a\u53d8\u91cf\u7684\u53d8\u5316\u8fc7\u7a0b\u6ca1\u6709\u4efb\u4f55\u76f8\u4f3c\u5ea6\uff0c\u4e5f\u5373\u4e24\u4e2a\u53d8\u91cf\u65e0\u5173\u3002 \u5f53\u76f8\u5173\u7cfb\u6570\u7ee7\u7eed\u53d8\u5c0f\uff0c\u5c0f\u4e8e0\u65f6\uff0c\u4e24\u4e2a\u53d8\u91cf\u5f00\u59cb\u51fa\u73b0\u53cd\u5411\u7684\u76f8\u4f3c\u5ea6\uff0c\u968f\u7740\u76f8\u5173\u7cfb\u6570\u7ee7\u7eed\u53d8\u5c0f\uff0c\u53cd\u5411\u76f8\u4f3c\u5ea6\u4f1a\u9010\u6e10\u53d8\u5927\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u4f7f\u7528 pandas-datareader\uff1a https://pypi.org/project/pandas-datareader/ https://pydata.github.io/pandas-datareader/) \u5728\u6240\u6709\u4f8b\u5b50\u4e2d\uff0c\u5728\u8ba1\u7b97\u76f8\u5173\u6027\u4e4b\u524d\uff0c\u6570\u636e\u70b9\u5df2\u7ecf\u6309\u6807\u7b7e\u8fdb\u884c\u4e86\u5bf9\u9f50\u3002 \u4e0b\u4f8b\u9700\u8981\u901a\u8fc7pandas-datareader\u5e93\u4eceYahoo! Finance\u4e0a\u83b7\u53d6\u7684\u5305\u542b\u80a1\u4ef7\u548c\u4ea4\u6613\u91cf\u7684DataFrame\u3002 import pandas_datareader.data as web all_data = { ticker: web.get_data_yahoo(ticker) for ticker in ['AAPL', 'IBM', 'MSFT', 'GOOG'] } price = pd.DataFrame( { ticker: data['Adj Close'] for ticker, data in all_data.items() } ) volume = pd.DataFrame( { ticker: data['Volume'] for ticker, data in all_data.items() } ) returns = price.pct_change() print(returns.tail()) # AAPL IBM MSFT GOOG # Date # 2021-08-09 -0.000342 -0.008424 -0.003904 0.007049 # 2021-08-10 -0.003354 0.000920 -0.006555 0.000685 # 2021-08-11 0.001786 0.005305 0.001781 -0.002947 # 2021-08-12 0.020773 0.006614 0.009967 0.005084 # 2021-08-13 0.001410 0.000769 0.010490 0.000119 Series\u7684corr\u65b9\u6cd5\u8ba1\u7b97\u7684\u662f\u4e24\u4e2aSeries\u4e2d\u91cd\u53e0\u7684\u3001\u975eNA\u7684\u3001\u6309\u7d22\u5f15\u5bf9\u9f50\u7684\u503c\u7684\u76f8\u5173\u6027\u3002\u76f8\u5e94\u5730\uff0ccov\u8ba1\u7b97\u7684\u662f\u534f\u65b9\u5dee print(returns['MSFT']) # Date # 2016-08-15 NaN # 2016-08-16 -0.005540 # 2016-08-17 0.002089 # 2016-08-18 0.000695 # 2016-08-19 0.000347 # ... # 2021-08-09 -0.003904 # 2021-08-10 -0.006555 # 2021-08-11 0.001781 # 2021-08-12 0.009967 # 2021-08-13 0.010490 # Name: MSFT, Length: 1259, dtype: float64 # Series\u7684corr\u65b9\u6cd5\u8ba1\u7b97\u7684\u662f\u4e24\u4e2aSeries\u4e2d\u91cd\u53e0\u7684\u3001\u975eNA\u7684\u3001\u6309\u7d22\u5f15\u5bf9\u9f50\u7684\u503c\u7684\u76f8\u5173\u6027\u3002 print(returns['MSFT'].corr(returns['IBM'])) # 0.5175237180581937 # \u7b49\u540c\u5199\u6cd5\uff0cMSFT\u662f\u4e00\u4e2a\u6709\u6548\u7684Python\u5c5e\u6027 print(returns.MSFT.corr(returns.IBM)) # 0.5175237180581937 # Series\u7684cov\u65b9\u6cd5\u8ba1\u7b97\u7684\u662f\u4e24\u4e2aSeries\u4e2d\u503c\u7684\u534f\u65b9\u5dee\u3002 print(returns['MSFT'].cov(returns['IBM'])) # 0.0001452224236764915 DataFrame\u7684corr\u548ccov\u65b9\u6cd5\u4f1a\u5206\u522b\u4ee5DataFrame\u7684\u5f62\u5f0f\u8fd4\u56de\u76f8\u5173\u6027\u548c\u534f\u65b9\u5dee\u77e9\u9635\u3002 print(returns.corr()) # AAPL IBM MSFT GOOG # AAPL 1.000000 0.441111 0.735539 0.661961 # IBM 0.441111 1.000000 0.517524 0.484230 # MSFT 0.735539 0.517524 1.000000 0.775756 # GOOG 0.661961 0.484230 0.775756 1.000000 # \u7ed9corrwith\u65b9\u6cd5\uff0c\u4f20\u5165\u4e00\u4e2aSeries\u65f6\uff0c\u4f1a\u8fd4\u56de\u4e00\u4e2a\u542b\u6709\u4e3a\u6bcf\u5217\u8ba1\u7b97\u76f8\u5173\u6027\u503c\u7684Series print(returns.corrwith(returns['IBM'])) # AAPL 0.441111 # IBM 1.000000 # MSFT 0.517524 # GOOG 0.484230 # dtype: float64 # \u7ed9corrwith\u65b9\u6cd5\uff0c\u4f20\u5165\u4e00\u4e2aDataFrame\u65f6\uff0c\u4f1a\u8ba1\u7b97\u5339\u914d\u5230\u5217\u540d\u7684\u76f8\u5173\u6027\u6570\u503c\u3002\u4e0b\u9762\u662f\u8ba1\u7b97\u4ea4\u6613\u91cf\u767e\u5206\u6bd4\u53d8\u5316\u7684\u76f8\u5173\u6027 print(returns.corrwith(volume)) # AAPL -0.063111 # IBM -0.103721 # MSFT -0.056842 # GOOG -0.119026 # dtype: float64 print(returns.cov()) # AAPL IBM MSFT GOOG # AAPL 0.000361 0.000137 0.000240 0.000211 # IBM 0.000137 0.000268 0.000145 0.000133 # MSFT 0.000240 0.000145 0.000294 0.000224 # GOOG 0.000211 0.000133 0.000224 0.000282 \u552f\u4e00\u503c\u3001\u8ba1\u6570\u548c\u6210\u5458\u5c5e\u6027 \u00b6 obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c']) print(obj) # 0 c # 1 a # 2 d # 3 a # 4 a # 5 a # 6 b # 7 b # 8 c # 9 c # dtype: object \u51fd\u6570 unique \u7ed9\u51faSeries\u4e2d\u7684\u552f\u4e00\u503c\u3002 print(obj.unique()) # ['c' 'a' 'd' 'b'] print(obj.sort_values().unique()) # ['a' 'b' 'c' 'd'] # value_counts\u8ba1\u7b97Series\u5305\u542b\u7684\u503c\u7684\u4e2a\u6570 print(obj.value_counts()) # a 4 # c 3 # b 2 # d 1 # dtype: int64 # \u8fd9\u91ccvalue_counts\u4e0d\u662fSeries\u7684\u65b9\u6cd5\uff0c\u662fpandas\u9876\u5c42\u65b9\u6cd5 print(pd.value_counts(obj.values, sort=True)) # a 4 # c 3 # b 2 # d 1 # dtype: int64 print(obj.isin(['b', 'c'])) # 0 True # 1 False # 2 False # 3 False # 4 False # 5 False # 6 True # 7 True # 8 True # 9 True # dtype: bool # \u5c06\u4e0a\u9762\u7684\u7ed3\u679c\u4f5c\u4e3a\u5217\u8868\u8f93\u5165\u7684\u6761\u4ef6\uff0c\u8f93\u51fa\u4e3aTrue\u7684\u7ed3\u679c print(obj[obj.isin(['b', 'c'])]) # 0 c # 6 b # 7 b # 8 c # 9 c # dtype: object \u53c2\u8003: pandas.Index.get_indexer obj1 = pd.Series(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c']) obj2 = pd.Series(['c', 'a', 'b']) print(pd.Index(obj1)) # Index(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c'], dtype='object') print(pd.Index(obj2)) # Index(['c', 'a', 'b'], dtype='object') # \u8fd9\u91cc0\u5bf9\u5e94obj2\u91cc\u9762\u7684c\u5728job1\u7684\u4f4d\u7f6e\uff0c\u4ee5\u6b64\u7c7b\u63a8\uff0c\u751f\u6210\u65b0\u7684\u7d22\u5f15\u5217\u8868 print(pd.Index(obj2).get_indexer(obj1)) # [ 0 1 -1 1 1 1 2 2 0 0] \u8ba1\u7b97DataFrame\u591a\u4e2a\u76f8\u5173\u5217\u7684\u76f4\u65b9\u56fe\u3002 data = pd.DataFrame( { 'Que1': [1, 3, 4, 3, 4], 'Que2': [2, 3, 1, 2, 3], 'Que3': [1, 5, 2, 4, 4], } ) print(data) # Que1 Que2 Que3 # 0 1 2 1 # 1 3 3 5 # 2 4 1 2 # 3 3 2 4 # 4 4 3 4 result = data.apply(pd.value_counts).fillna(0) # \u4e0b\u9762\u7ed3\u679c\u4e2d\u7684\u884c\u6807\u7b7e\u662f\u6240\u6709\u5217\u4e2d\u51fa\u73b0\u7684\u4e0d\u540c\u503c\uff0c\u6570\u503c\u5219\u662f\u8fd9\u4e9b\u4e0d\u540c\u503c\u5728\u6bcf\u4e2a\u5217\u4e2d\u51fa\u73b0\u7684\u6b21\u6570\uff0c\u4f8b\u5982\uff1a\u6570\u5b575\u53ea\u5728Que3\u91cc\u9762\u51fa\u73b0\u4e86\u4e00\u6b21 print(result) # Que1 Que2 Que3 # 1 1.0 1.0 1.0 # 2 0.0 2.0 1.0 # 3 2.0 2.0 0.0 # 4 2.0 0.0 2.0 # 5 0.0 0.0 1.0","title":"Pandas\u5165\u95e8"},{"location":"python/DataAnalysis/ch02/#pandas","text":"\u7ea6\u5b9a\uff1a import numpy as np import pandas as pd from pandas import Series, DataFrame import pandas_datareader as web","title":"Pandas\u5165\u95e8"},{"location":"python/DataAnalysis/ch02/#pandas_1","text":"","title":"pandas\u6570\u636e\u7ed3\u6784\u4ecb\u7ecd"},{"location":"python/DataAnalysis/ch02/#series","text":"Series\u662f\u4e00\u79cd\u4e00\u7ef4\u7684\u6570\u7ec4\u578b\u5bf9\u8c61\uff0c\u5b83\u5305\u542b\u4e86\u4e00\u4e2a\u503c\u5e8f\u5217\uff08\u4e0eNumPy\u4e2d\u7684\u7c7b\u578b\u76f8\u4f3c\uff09\uff0c\u5e76\u4e14\u5305\u542b\u4e86\u6570\u636e\u6807\u7b7e\uff0c\u79f0\u4e3a**\u7d22\u5f15\uff08index\uff09 \u3002 \u4ece\u53e6\u4e00\u4e2a\u89d2\u5ea6\u8003\u8651Series\uff0c\u53ef\u4ee5\u8ba4\u4e3a\u5b83\u662f\u4e00\u4e2a**\u957f\u5ea6\u56fa\u5b9a\u4e14\u6709\u5e8f\u7684\u5b57\u5178 \uff0c\u56e0\u4e3a\u5b83\u5c06\u7d22\u5f15\u503c\u548c\u6570\u636e\u503c\u6309\u4f4d\u7f6e\u914d\u5bf9\u3002\u7d22\u5f15\u5728\u5de6\u8fb9\uff0c\u503c\u5728\u53f3\u8fb9\u3002 obj = pd.Series([4, 7, -5, 3]) print(obj) # 0 4 # 1 7 # 2 -5 # 3 3 # dtype: int64 print(obj.values) # [ 4 7 -5 3 print(obj.index) # RangeIndex(start=0, stop=4, step=1) \u81ea\u5b9a\u4e49index obj = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c']) print(obj) # d 4 # b 7 # a -5 # c 3 # dtype: int64 print(obj.values) # [ 4 7 -5 3] print(obj.index) # Index(['d', 'b', 'a', 'c'], dtype='object') # \u8f93\u51fa\u7d22\u5f15\u503c\u4e3a'a'\u7684Series\u503c print(obj['a']) # -5 # \u4f7f\u7528\u5e03\u5c14\u503c\u6570\u7ec4\u8fdb\u884c\u8fc7\u6ee4Series\u503c print(obj[obj > 3]) # d 4 # b 7 # dtype: int64 # \u5bf9Series\u503c\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97 print(obj * 2) # d 8 # b 14 # a -10 # c 6 # dtype: int64 # \u5bf9Series\u503c\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97 print(np.exp(obj)) # d 54.598150 # b 1096.633158 # a 0.006738 # c 20.085537 # dtype: float64 # \u66f4\u65b0Series\u6570\u7ec4\u503c obj['a'] = 9 # \u8f93\u51fa\u6307\u5b9a\u7d22\u5f15\u503c\u7684Series\u503c\uff0c\u6ce8\u610f\uff0c\u7d22\u5f15\u6761\u4ef6\u662f\u5217\u8868 print(obj[['a', 'b', 'c']]) # a 9 # b 7 # c 3 # dtype: int64 # \u6ce8\u610f\uff0c\u4e0b\u9762\u7684\u5224\u65ad\u662f\u7d22\u5f15\u503c\uff0c\u975eSeries\u503c print(obj) print(7 in obj) # False print('a' in obj) # True \u901a\u8fc7\u5b57\u5178\u751f\u6210\u4e00\u4e2aSeries\u3002 NaN \uff08not a number\uff09\uff0c\u8fd9\u662fpandas\u4e2d\u6807\u8bb0\u7f3a\u5931\u503c\u6216NA\u503c\u7684\u65b9\u5f0f\u3002 \u5f53\u628a\u5b57\u5178\u4f20\u9012\u7ed9Series\u6784\u9020\u51fd\u6570\u65f6\uff0c\u4ea7\u751f\u7684Series\u7684\u7d22\u5f15\u5c06\u662f\u6392\u5e8f\u597d\u7684\u5b57\u5178\u952e\u3002\u53ef\u4ee5\u5c06\u5b57\u5178\u952e\u6309\u7167\u4f60\u6240\u60f3\u8981\u7684\u987a\u5e8f\u4f20\u9012\u7ed9\u6784\u9020\u51fd\u6570\uff0c\u4ece\u800c\u4f7f\u751f\u6210\u7684Series\u7684\u7d22\u5f15\u987a\u5e8f\u7b26\u5408\u9884\u671f\u3002 \u770b\u4e0b\u4f8b\uff0c\u901a\u8fc7\u5b57\u5178sdata\u751f\u6210Series\u3002 sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000} obj3 = pd.Series(sdata) print(sdata) # {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000} print(obj3) # Ohio 35000 # Texas 71000 # Oregon 16000 # Utah 5000 # dtype: int64 \u901a\u8fc7\u6307\u5b9a\u7d22\u5f15states\u53bb\u5339\u914d\u5b57\u5178sdata\u751f\u6210\u57fa\u4e8e\u65b0\u7d22\u5f15states\u7684Series\u3002 states = ['California', 'Ohio', 'Oregon', 'Texas'] obj4 = pd.Series(sdata, index=states) print(obj4) # California NaN # Ohio 35000.0 # Oregon 16000.0 # Texas 71000.0 # dtype: float64 \u5bf9Series\u8fdb\u884c\u5e03\u5c14\u503c\u5224\u65ad\u3002 print(pd.isnull(obj4)) # California True # Ohio False # Oregon False # Texas False # dtype: bool print(pd.notnull(obj4)) # California False # Ohio True # Oregon True # Texas True # dtype: bool \u5bf9Series\u8fdb\u884c\u5e03\u5c14\u503c\u5224\u65ad\u3002 print(obj4.isnull) # print(obj4.notnull) # Series\u7684\u81ea\u52a8\u5bf9\u9f50\u7d22\u5f15\uff0c\u4e0e\u6570\u636e\u5e93\u7684join\u64cd\u4f5c\u662f\u975e\u5e38\u76f8\u4f3c\u3002 print(\"obj3 \\n\", obj3) # obj3 # Ohio 35000 # Texas 71000 # Oregon 16000 # Utah 5000 # dtype: int64 print(\"obj4 \\n\", obj4) # obj4 # California NaN # Ohio 35000.0 # Oregon 16000.0 # Texas 71000.0 # dtype: float64 print(\"obj3+obj4 \\n\", obj3 + obj4) # obj3+obj4 # California NaN # Ohio 70000.0 # Oregon 32000.0 # Texas 142000.0 # Utah NaN # dtype: float64 # \u4e0b\u9762\u662fobj3\u548cobj4\u7684\u503c\uff0c\u5e2e\u52a9\u7406\u89e3\u4e0a\u9762obj3 + obj4\u7684\u64cd\u4f5c\u3002 # obj3 obj4 # Ohio 35000 California NaN # Texas 71000 Ohio 35000.0 # Oregon 16000 Oregon 16000.0 # Utah 5000 Texas 71000.0 # dtype: int64 dtype: float64 Series\u5bf9\u8c61\u81ea\u8eab\u548c\u5176\u7d22\u5f15\u90fd\u6709name\u5c5e\u6027\u3002 obj4.name = 'population' obj4.index.name = 'state' print(obj4) # state # California NaN # Ohio 35000.0 # Oregon 16000.0 # Texas 71000.0 # Name: population, dtype: float64 \u66ff\u6362Series\u7684\u7d22\u5f15\u540d\u3002 obj = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c']) print(obj) obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan'] print(obj) # Bob 4 # Steve 7 # Jeff -5 # Ryan 3 # dtype: int64","title":"Series"},{"location":"python/DataAnalysis/ch02/#dataframe","text":"DataFrame\u8868\u793a\u7684\u662f\u77e9\u9635\u7684\u6570\u636e\u8868\uff0c\u5b83\u5305\u542b\u5df2\u6392\u5e8f\u7684\u5217\u96c6\u5408\uff0c\u6bcf\u4e00\u5217\u53ef\u4ee5\u662f\u4e0d\u540c\u7684\u503c\u7c7b\u578b\uff08\u6570\u503c\u3001\u5b57\u7b26\u4e32\u3001\u5e03\u5c14\u503c\u7b49\uff09\u3002 DataFrame\u65e2\u6709\u884c\u7d22\u5f15\u4e5f\u6709\u5217\u7d22\u5f15\uff0c\u5b83\u53ef\u4ee5\u88ab\u89c6\u4e3a\u4e00\u4e2a\u5171\u4eab\u76f8\u540c\u7d22\u5f15\u7684Series\u7684\u5b57\u5178\uff0c\u6bd4\u5982\u6240\u6709\u5217\u5171\u4eab\u540c\u4e00\u4e2a\u5217\u7d22\u5f15\u3002 \u5728DataFrame\u4e2d\uff0c\u6570\u636e\u88ab\u5b58\u50a8\u4e3a\u4e00\u4e2a\u4ee5\u4e0a\u7684\u4e8c\u7ef4\u5757\uff0c\u800c\u4e0d\u662f\u5217\u8868\u3001\u5b57\u5178\u6216\u5176\u4ed6\u4e00\u7ef4\u6570\u7ec4\u7684\u96c6\u5408\u3002 DataFrame\u662f\u4e8c\u7ef4\u7684\uff0c\u4f46\u53ef\u4ee5\u5229\u7528**\u5206\u5c42\u7d22\u5f15**\u5728DataFrame\u4e2d\u5c55\u73b0\u66f4\u9ad8\u7ef4\u5ea6\u7684\u6570\u636e\u3002 \u4eceDataFrame\u4e2d\u9009\u53d6\u7684\u5217\u662f\u6570\u636e\u7684\u89c6\u56fe\uff0c\u800c\u4e0d\u662f\u62f7\u8d1d \u3002\u56e0\u6b64\uff0c\u5bf9Series\u7684\u4fee\u6539\u4f1a\u6620\u5c04\u5230DataFrame\u4e2d\u3002\u5982\u679c\u9700\u8981\u590d\u5236\uff0c\u5219\u5e94\u5f53\u663e\u5f0f\u5730\u4f7f\u7528Series\u7684copy\u65b9\u6cd5\u3002","title":"DataFrame"},{"location":"python/DataAnalysis/ch02/#dataframe_1","text":"\u57fa\u4e8e\u5b57\u5178 data \u4ea7\u751f\u7684DataFrame\u4f1a\u81ea\u52a8\u4e3aSereies\u5206\u914d\u7d22\u5f15\uff0c\u5e76\u4e14\u5217\u4f1a\u6309\u7167\u6392\u5e8f\u7684\u987a\u5e8f\u6392\u5217\u3002 data = { 'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], 'year': [2000, 2001, 2002, 2001, 2002, 2003], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2] } frame = pd.DataFrame(data) print(frame) # state year pop # 0 Ohio 2000 1.5 # 1 Ohio 2001 1.7 # 2 Ohio 2002 3.6 # 3 Nevada 2001 2.4 # 4 Nevada 2002 2.9 # 5 Nevada 2003 3.2 # \u5bf9\u4e8e\u5927\u578bDataFrame, head\u65b9\u6cd5\u5c06\u4f1a\u53ea\u9009\u51fa\u5934\u90e8\u7684\u82e5\u5e72\u884c, \u9ed8\u8ba4\u662f\u524d\u4e94\u884c\u3002 print(frame.head(3)) # state year pop # 0 Ohio 2000 1.5 # 1 Ohio 2001 1.7 # 2 Ohio 2002 3.6 \u5982\u679c\u6307\u5b9a\u4e86\u5217\u7684\u987a\u5e8f\uff0cDataFrame\u7684\u5217\u5c06\u4f1a\u6309\u7167\u6307\u5b9a\u987a\u5e8f\u6392\u5217\u3002 frame = pd.DataFrame(data, columns=['year', 'state', 'pop']) print(frame) # year state pop # 0 2000 Ohio 1.5 # 1 2001 Ohio 1.7 # 2 2002 Ohio 3.6 # 3 2001 Nevada 2.4 # 4 2002 Nevada 2.9 # 5 2003 Nevada 3.2 \u5982\u679c\u4f20\u7684\u5217\uff08 debt \uff09\u4e0d\u5305\u542b\u5728\u5b57\u5178\uff08 data \uff09\u4e2d\uff0c\u5c06\u4f1a\u5728\u7ed3\u679c\u4e2d\u51fa\u73b0\u7f3a\u5931\u503c\u3002 frame2 = pd.DataFrame( data, columns=['year', 'state', 'pop', 'debt'], index=['one', 'two', 'three', 'four', 'five', 'six'] ) print(frame2) # year state pop debt # one 2000 Ohio 1.5 NaN # two 2001 Ohio 1.7 NaN # three 2002 Ohio 3.6 NaN # four 2001 Nevada 2.4 NaN # five 2002 Nevada 2.9 NaN # six 2003 Nevada 3.2 NaN \u9009\u53d6\u884c, \u53ef\u4ee5\u901a\u8fc7\u4f4d\u7f6e\u6216\u884c\u7d22\u5f15\u6807\u7b7e loc \u8fdb\u884c\u9009\u53d6\u3002 print(frame2.loc['three']) # year 2002 # state Ohio # pop 3.6 # debt NaN # Name: three, dtype: object DataFrame\u4e2d\u7684\u4e00\u5217\uff0c\u53ef\u4ee5\u6309\u5b57\u5178\u578b\u6807\u8bb0\u6216\u5c5e\u6027\u90a3\u6837\u68c0\u7d22\u4e3aSeries\u3002 frame2[colunm] \u5bf9\u4e8e\u4efb\u610f\u5217\u540d\u5747\u6709\u6548\uff0c\u4f46\u662f frame2.column \u53ea\u5728\u5217\u540d\u662f\u6709\u6548\u7684Python\u53d8\u91cf\u540d\u65f6\u6709\u6548\u3002 \u8fd4\u56de\u7684Series\u4e0e\u539fDataFrame\u6709\u76f8\u540c\u7684\u7d22\u5f15\uff0c\u4e14Series\u7684 name \u5c5e\u6027\u4e5f\u4f1a\u88ab\u5408\u7406\u5730\u8bbe\u7f6e\u3002 print(frame2['state']) # one Ohio # two Ohio # three Ohio # four Nevada # five Nevada # six Nevada # Name: state, dtype: object print(frame2.state) # \u5c5e\u6027\u578b\u8fde\u63a5 # one Ohio # two Ohio # three Ohio # four Nevada # five Nevada # six Nevada # Name: state, dtype: object \u5217\u7684\u5f15\u7528\u662f\u53ef\u4ee5\u4fee\u6539\u7684\u3002\u503c\u7684\u957f\u5ea6\u5fc5\u987b\u548cDataFrame\u7684\u957f\u5ea6\u76f8\u5339\u914d,\u6bd4\u5982\uff0c\u4e0b\u4f8b\u4e2d np.arange(6.) \u548c frame2['debt'] \u7684\u957f\u5ea6\u90fd\u662f6\u3002 frame2['debt'] = 16.5 print(frame2) # Name: state, dtype: object # year state pop debt # one 2000 Ohio 1.5 16.5 # two 2001 Ohio 1.7 16.5 # three 2002 Ohio 3.6 16.5 # four 2001 Nevada 2.4 16.5 # five 2002 Nevada 2.9 16.5 # six 2003 Nevada 3.2 16.5 frame2['debt'] = np.arange(6.) print(frame2) # year state pop debt # one 2000 Ohio 1.5 0.0 # two 2001 Ohio 1.7 1.0 # three 2002 Ohio 3.6 2.0 # four 2001 Nevada 2.4 3.0 # five 2002 Nevada 2.9 4.0 # six 2003 Nevada 3.2 5.0 \u5982\u679c\u5c06Series\u8d4b\u503c\u7ed9\u4e00\u5217\u65f6\uff0cSeries\u7684\u7d22\u5f15\u5c06\u4f1a\u6309\u7167DataFrame\u7684\u7d22\u5f15\u91cd\u65b0\u6392\u5217\uff0c\u5e76\u5728\u7a7a\u7f3a\u7684\u5730\u65b9\u586b\u5145\u7f3a\u5931\u503c val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five']) frame2['debt'] = val print(frame2) # year state pop debt # one 2000 Ohio 1.5 NaN # two 2001 Ohio 1.7 -1.2 # three 2002 Ohio 3.6 NaN # four 2001 Nevada 2.4 -1.5 # five 2002 Nevada 2.9 -1.7 # six 2003 Nevada 3.2 NaN \u5982\u679c\u88ab\u8d4b\u503c\u7684\u5217( eastern \u5217)\u5e76\u4e0d\u5b58\u5728\uff0c\u5219\u4f1a\u751f\u6210\u4e00\u4e2a\u65b0\u7684\u5217\u3002 frame2.state == 'Ohio' \u8fd4\u56de\u7684\u662f\u5e03\u5c14\u503c\uff0c\u8d4b\u503c\u7ed9 eastern \u3002 frame2['eastern'] = frame2.state == 'Ohio' print(frame2) # year state pop debt eastern # one 2000 Ohio 1.5 NaN True # two 2001 Ohio 1.7 -1.2 True # three 2002 Ohio 3.6 NaN True # four 2001 Nevada 2.4 -1.5 False # five 2002 Nevada 2.9 -1.7 False # six 2003 Nevada 3.2 NaN False print(frame2.eastern) # one True # two True # three True # four False # five False # six False # Name: eastern, dtype: bool del \u5173\u952e\u5b57\u53ef\u4ee5\u50cf\u5728\u5b57\u5178\u4e2d\u90a3\u6837\u5bf9DataFrame\u5220\u9664\u5217\u3002 del frame2['eastern'] print(frame2.columns) # Index(['year', 'state', 'pop', 'debt'], dtype='object')","title":"\u7531\u5b57\u5178\u6784\u6210DataFrame"},{"location":"python/DataAnalysis/ch02/#dataframe_2","text":"pandas\u4f1a\u5c06\u5b57\u5178\u7684\u952e\u4f5c\u4e3a\u5217('Nevada', etc.)\uff0c\u5c06\u5185\u90e8\u5b57\u5178\u7684\u952e\u4f5c\u4e3a\u884c\u7d22\u5f15(2001, etc.) pop = { 'Nevada': { 2001: 2.4, 2002: 2.9 }, 'Ohio': { 2000: 1.5, 2001: 1.7, 2002: 3.6 } } # \u4e0d\u6307\u5b9a\u7d22\u5f15\uff0c\u9ed8\u8ba4\u4f7f\u7528\u5b57\u5178\u7d22\u5f15 frame3 = pd.DataFrame(pop) print(frame3) # Nevada Ohio # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 # \u6307\u5b9a\u5b57\u5178\u67d0\u5217\u4f5c\u4e3a\u7d22\u5f15 print(pd.DataFrame(pop, index=[2001, 2002, 2003])) # Nevada Ohio # 2001 2.4 1.7 # 2002 2.9 3.6 # 2003 NaN NaN # \u6307\u5b9a\u4e0d\u76f8\u5e72\u7d22\u5f15 print(pd.DataFrame(pop, index=['a', 'b', 'c'])) # Nevada Ohio # a NaN NaN # b NaN NaN # c NaN NaN \u8f6c\u7f6e\u64cd\u4f5c\uff08\u8c03\u6362\u884c\u548c\u5217\uff09 print(frame3.T) # 2001 2002 2000 # Nevada 2.4 2.9 NaN # Ohio 1.7 3.6 1.5","title":"\u4f7f\u7528\u5d4c\u5957\u5b57\u5178\u6784\u5efaDataFrame"},{"location":"python/DataAnalysis/ch02/#seriesdataframe","text":"frame3['Ohio'][:-1] \u662f\u503c\u4e3a Ohio \u7684Series\u76840~\u5012\u6570\u7b2c\u4e00\u4e2a\u5143\u7d20\uff08\u4e0d\u542b\uff09\uff0c\u4e00\u51713\u4e2a\u3002 frame3['Nevada'][:2] \u662f\u503c\u4e3a Nevada \u7684Series\u7684\u524d2\u4e2a\u5143\u7d20\u3002 pdata = { 'Ohio': frame3['Ohio'][:-1], 'Nevada': frame3['Nevada'][:2] } print(pd.DataFrame(pdata)) # Ohio Nevada # 2001 1.7 2.4 # 2002 3.6 2.9 \u6307\u5b9aDataframe frame3 \u7684\u5217\u540d\u3002 frame3.index.name = 'year' frame3.columns.name = 'state' print(frame3) # state Nevada Ohio # year # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 \u53ea\u8f93\u51faDataframe\u7684\u503c frame3.values \uff0c\u662f\u4e00\u4e2a\u4e8c\u7ef4\u6570\u7ec4\u3002 print(frame3.values) # [[2.4 1.7] # [2.9 3.6] # [nan 1.5]] \u53ea\u8f93\u51faDataframe\u7684\u503c frame2.values \uff0c\u662f\u4e00\u4e2a\u4e8c\u7ef4\u6570\u7ec4\u3002 print(frame2) # year state pop debt # one 2000 Ohio 1.5 NaN # two 2001 Ohio 1.7 -1.2 # three 2002 Ohio 3.6 NaN # four 2001 Nevada 2.4 -1.5 # five 2002 Nevada 2.9 -1.7 # six 2003 Nevada 3.2 NaN print(frame2.values) # [[2000 'Ohio' 1.5 nan] # [2001 'Ohio' 1.7 -1.2] # [2002 'Ohio' 3.6 nan] # [2001 'Nevada' 2.4 -1.5] # [2002 'Nevada' 2.9 -1.7] # [2003 'Nevada' 3.2 nan]]","title":"\u4f7f\u7528\u542bSeries\u7684\u5b57\u5178\u6784\u9020DataFrame"},{"location":"python/DataAnalysis/ch02/#_1","text":"pandas\u4e2d\u7684**\u7d22\u5f15\u5bf9\u8c61**\u662f\u7528\u4e8e\u5b58\u50a8\u8f74\u6807\u7b7e\u548c\u5176\u4ed6\u5143\u6570\u636e\u7684\uff08\u4f8b\u5982\u8f74\u540d\u79f0\u6216\u6807\u7b7e\uff09\u3002 \u5728\u6784\u9020Series\u6216DataFrame\u65f6\uff0c\u4f60\u6240\u4f7f\u7528\u7684\u4efb\u610f\u6570\u7ec4\u6216\u6807\u7b7e\u5e8f\u5217\u90fd\u53ef\u4ee5\u5728\u5185\u90e8\u8f6c\u6362\u4e3a\u7d22\u5f15\u5bf9\u8c61\u3002 \u7d22\u5f15\u5bf9\u8c61\u662f\u4e0d\u53ef\u53d8\u7684\u3002 \u9664\u4e86\u7c7b\u4f3c\u6570\u7ec4\uff0c\u7d22\u5f15\u5bf9\u8c61\u4e5f\u50cf\u4e00\u4e2a\u56fa\u5b9a\u5927\u5c0f\u7684\u96c6\u5408\u3002\u4e0ePython\u96c6\u5408\u4e0d\u540c\uff0c pandas\u7d22\u5f15\u5bf9\u8c61\u53ef\u4ee5\u5305\u542b\u91cd\u590d\u6807\u7b7e \u3002 \u56e0\u4e3a\u4e00\u4e9b\u64cd\u4f5c\u4f1a\u4ea7\u751f\u5305\u542b\u7d22\u5f15\u5316\u6570\u636e\u7684\u7ed3\u679c\uff0c\u7406\u89e3\u7d22\u5f15\u5982\u4f55\u5de5\u4f5c\u8fd8\u662f\u5f88\u91cd\u8981\u7684\u3002 \u4e0b\u4f8b\u6f14\u793a\u4e86\u5982\u4f55\u8bfb\u53d6Dataframe\u7684\u7d22\u5f15\u503c\u3002 obj = pd.Series(range(3), index=['a', 'b', 'c']) index = obj.index print(obj) # a 0 # b 1 # c 2 # dtype: int64 print(index) # Index(['a', 'b', 'c'], dtype='object') print(index[1:]) # Index(['b', 'c'], dtype='object') \u4e0b\u4f8b\u6f14\u793a\u4e86\u901a\u8fc7\u4e00\u4e2a\u6307\u5b9a\u7684Dataframe\u7d22\u5f15 labels \u6765\u751f\u6210Dataframe obj2 \u3002 labels = pd.Index(np.arange(3)) print(labels) # Int64Index([0, 1, 2], dtype='int64') obj2 = pd.Series([1.5, -2.5, 0], index=labels) print(obj2) # 0 1.5 # 1 -2.5 # 2 0.0 # dtype: float64 print(obj2.index is labels) # True \u4e0b\u4f8b\u6f14\u793a\u4e86\u4e0d\u6307\u5b9a\u7d22\u5f15\uff0c\u9ed8\u8ba4\u4f7f\u7528\u5b57\u5178\u7d22\u5f15\u6765\u521b\u5efaDataframe\u3002 pop = { 'Nevada': { 2001: 2.4, 2002: 2.9 }, 'Ohio': { 2000: 1.5, 2001: 1.7, 2002: 3.6 } } frame3 = pd.DataFrame(pop) print(frame3) # Nevada Ohio # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 print(frame3) # state Nevada Ohio # year # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 print(frame3.columns) # Index(['Nevada', 'Ohio'], dtype='object', name='state') print(frame3.index) # Int64Index([2001, 2002, 2000], dtype='int64', name='year') print('Ohio' in frame3.columns) # True print(2003 in frame3.index) # False pandas\u7d22\u5f15\u5bf9\u8c61\u5141\u8bb8\u5305\u542b\u91cd\u590d\u6807\u7b7e\u3002\u6839\u636e\u91cd\u590d\u6807\u7b7e\u8fdb\u884c\u7b5b\u9009\uff0c\u4f1a\u9009\u53d6\u6240\u6709\u91cd\u590d\u6807\u7b7e\u5bf9\u5e94\u7684\u6570\u636e\u3002 dup_labels = pd.Index(['foo', 'foo', 'bar', 'bar']) print(dup_labels) # Index(['foo', 'foo', 'bar', 'bar'], dtype='object') \u4e00\u4e9b\u5e38\u7528\u7d22\u5f15\u5bf9\u8c61\u7684\u65b9\u6cd5\u548c\u5c5e\u6027\u3002 obj1 = pd.Series(range(3), index=['a', 'b', 'c']) index1 = obj1.index obj2 = pd.Series(range(3), index=['c', 'f', 'g']) index2 = obj2.index print(index1) # Index(['a', 'b', 'c'], dtype='object') print(index2) # Index(['c', 'f', 'g'], dtype='object') append \u65b9\u6cd5\uff1a\u5c06\u5916\u90e8\u7684\u7d22\u5f15\u5bf9\u8c61\u7c98\u8d34\u5230\u539f\u7d22\u5f15\u540e\uff0c\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684\u7d22\u5f15\u3002 \u63a5\u4e0a\u4f8b\uff0c\u628a index2 \u5bf9\u8c61\u8ffd\u52a0\u5230 index1 \u5bf9\u8c61\u3002 print(index1.append(index2)) # Index(['a', 'b', 'c', 'c', 'f', 'g'], dtype='object') difference \u65b9\u6cd5: \u8ba1\u7b972\u4e2a\u7d22\u5f15\u7684\u5dee\u96c6\u3002 print(index1.difference(index2)) # Index(['a', 'b'], dtype='object') intersection \u65b9\u6cd5: \u8ba1\u7b972\u4e2a\u7d22\u5f15\u7684\u4ea4\u96c6\u3002 print(index1.intersection(index2)) # Index(['c'], dtype='object') union \u65b9\u6cd5: \u8ba1\u7b972\u4e2a\u7d22\u5f15\u7684\u5e76\u96c6\uff08\u53bb\u91cd\uff09\u3002 print(index1.union(index2)) # Index(['a', 'b', 'c', 'f', 'g'], dtype='object') isin \u65b9\u6cd5: \u8ba1\u7b97\u8868\u793a\u6bcf\u4e00\u4e2a\u503c\u662f\u5426\u5728\u4f20\u503c\u5bb9\u5668\u4e2d\uff0c\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u5e03\u5c14\u6570\u7ec4\u3002 print(index1.isin(index2)) # [False False True] delete \u65b9\u6cd5: \u5c06\u4f4d\u7f6ei\uff08\u4ece0\u5f00\u59cb\u7f16\u53f7\uff09\u7684\u5143\u7d20\u5220\u9664\uff0c\u5e76\u4ea7\u751f\u65b0\u7684\u7d22\u5f15\u3002 print(index1.delete('b')) # IndexError: arrays used as indices must be of integer (or boolean) type print(index1.delete(1)) # Index(['a', 'c'], dtype='object') print(index1) # Index(['a', 'b', 'c'], dtype='object') drop \u65b9\u6cd5: \u6839\u636e\u4f20\u53c2\u5220\u9664\u6307\u5b9a\u7d22\u5f15\u503c\uff0c\u5e76\u4ea7\u751f\u65b0\u7684\u7d22\u5f15, \u5bf9\u6bd4\u548cdelete\u7684\u533a\u522b\uff0c delete \u65b9\u6cd5\u662f\u8f93\u5165\u4f4d\u7f6e\uff0c drop \u65b9\u6cd5\u662f\u8f93\u5165\u7d22\u5f15\u540d\u79f0\u3002 print(index2.drop(1)) # KeyError: '[1] not found in axis' print(index2.drop('f')) # Index(['c', 'g'], dtype='object') print(index2) # Index(['c', 'f', 'g'], dtype='object') insert \u65b9\u6cd5: \u5728\u4f4d\u7f6e i \u63d2\u5165\u5143\u7d20\uff0c\u5e76\u4ea7\u751f\u65b0\u7684\u7d22\u5f15\u3002 print(index1.insert(1, 'e')) # Index(['a', 'e', 'b', 'c'], dtype='object') print(index1) # Index(['a', 'b', 'c'], dtype='object') is_monotonic \u65b9\u6cd5: \u5982\u679c\u7d22\u5f15\u5e8f\u5217\u9012\u589e\uff0c\u5219\u8fd4\u56de True \u3002 print(index1.is_monotonic) # True print(index1.insert(1, 'e').is_monotonic) # False is_unique \u65b9\u6cd5: \u5982\u679c\u7d22\u5f15\u5e8f\u5217\u552f\u4e00\u5219\u8fd4\u56de True \u3002 print(index1.is_unique) # True print(index1.append(index2).is_unique) # False unique \u65b9\u6cd5: \u8ba1\u7b97\u7d22\u5f15\u7684\u552f\u4e00\u503c\u5e8f\u5217\uff08\u5bf9\u6bd4Union\uff09\u3002 print(index1.unique()) # Index(['a', 'b', 'c'], dtype='object') print(index1.append(index2).unique()) # Index(['a', 'b', 'c', 'f', 'g'], dtype='object')","title":"\u7d22\u5f15\u5bf9\u8c61"},{"location":"python/DataAnalysis/ch02/#pandas_2","text":"","title":"pandas\u57fa\u672c\u529f\u80fd"},{"location":"python/DataAnalysis/ch02/#_2","text":"Series\u8c03\u7528 reindex \u65b9\u6cd5\u65f6\uff0c\u4f1a\u5c06\u6570\u636e\u6309\u7167\u65b0\u7684\u7d22\u5f15\u8fdb\u884c\u6392\u5217\uff0c\u5982\u679c\u67d0\u4e2a\u7d22\u5f15\u503c\u4e4b\u524d\u5e76\u4e0d\u5b58\u5728\uff0c\u5219\u4f1a\u5f15\u5165\u7f3a\u5931\u503c\u3002 \u4e0b\u4f8b\u4e2d\uff0c\u5bf9 obj1 \u505a reindex \uff0c reindex \u65b9\u6cd5\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7d22\u5f15\u5bf9\u8c61 obj2 \uff0c\u7d22\u5f15\u503c e \u4e4b\u524d\u5e76\u4e0d\u5b58\u5728\uff0c\u6240\u4ee5\u586b\u5165\u7f3a\u5931\u503c\u3002 \u5982\u679c\u5bf9obj1\u505a reindex \u65f6\u6307\u5b9a method='ffill' \uff0c\u4f1a\u62a5\u9519 index must be monotonic increasing or decreasing \u3002 obj1 = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c']) print(obj1) # d 4.5 # b 7.2 # a -5.3 # c 3.6 # dtype: float64 obj2 = obj1.reindex(['a', 'b', 'c', 'd', 'e']) print(obj2) # a -5.3 # b 7.2 # c 3.6 # d 4.5 # e NaN # dtype: float64 obj2 = obj1.reindex(['a', 'b', 'c', 'd', 'e'], method='ffill') # ValueError: index must be monotonic increasing or decreasing \u5bf9\u4e8e\u987a\u5e8f\u6570\u636e\uff0c\u6bd4\u5982\u65f6\u95f4\u5e8f\u5217\uff0c\u5728\u91cd\u5efa\u7d22\u5f15\u65f6\u53ef\u80fd\u4f1a\u9700\u8981\u8fdb\u884c\u63d2\u503c\u6216\u586b\u503c\u3002 ffill \u65b9\u6cd5\u5728\u91cd\u5efa\u7d22\u5f15\u65f6\u63d2\u503c\uff0c\u5c06\u503c\u524d\u5411\u586b\u5145\u3002 obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4]) print(obj3.reindex(range(6), method='ffill')) # 0 blue # 1 blue # 2 purple # 3 purple # 4 yellow # 5 yellow # dtype: object \u5728DataFrame\u4e2d\uff0c reindex \u53ef\u4ee5\u6539\u53d8\u884c\u7d22\u5f15\u3001\u5217\u7d22\u5f15\uff0c\u4e5f\u53ef\u4ee5\u540c\u65f6\u6539\u53d8\u4e8c\u8005\u3002\u5f53\u4ec5\u4f20\u5165\u4e00\u4e2a\u5e8f\u5217\u65f6\uff0c\u4f1a\u91cd\u5efa\u884c\u7d22\u5f15\u3002 \u4e0b\u4f8b\u4e2d\uff0c\u901a\u8fc7 indexes \u521b\u5efaDataframe frame \u3002 \u901a\u8fc7 frame.reindex(['a', 'b', 'c', 'd'])\u91cd\u5efa\u884c\u7d22\u5f15 \u3002 \u901a\u8fc7 frame2.reindex(columns=['Ohio', 'Uta', 'California']) \u91cd\u5efa\u5217\u7d22\u5f15\u3002 \u7f3a\u5931\u7684\u7d22\u5f15\u5217\u586b\u5165\u7f3a\u5931\u503c\u3002 indexes = index = ['a', 'b', 'c'] states = ['Ohio', 'Texas', 'California'] frame = pd.DataFrame( np.arange(9).reshape(3, 3), index=indexes, columns=states ) print(frame) # Ohio Texas California # a 0 1 2 # b 3 4 5 # c 6 7 8 frame2 = frame.reindex(['a', 'b', 'c', 'd']) # \u91cd\u5efa\u884c\u7d22\u5f15 print(frame2) # Ohio Texas California # a 0.0 1.0 2.0 # b 3.0 4.0 5.0 # c 6.0 7.0 8.0 # d NaN NaN NaN frame3 = frame2.reindex(columns=['Ohio', 'Uta', 'California']) # \u91cd\u5efa\u5217\u7d22\u5f15 print(frame3) # Ohio Uta California # a 0.0 NaN 2.0 # b 3.0 NaN 5.0 # c 6.0 NaN 8.0 # d NaN NaN NaN \u4f7f\u7528 loc \u8fdb\u884c\u66f4\u4e3a\u7b80\u6d01\u7684\u884c\u3001\u5217\u6807\u7b7e\u7d22\u5f15\u3002\u4e0b\u4f8b\u901a\u8fc7\u7b5b\u9009\u884c\u7d22\u5f15\u548c\u5217\u7d22\u5f15\u4ea7\u751f\u65b0\u7684Dataframe\u3002 frame4 = frame.loc[['a', 'b'], states] print(frame4) # Ohio Texas California # a 0 1 2 # b 3 4 5","title":"\u91cd\u5efa\u7d22\u5f15"},{"location":"python/DataAnalysis/ch02/#_3","text":"set_index() , dropna() , fillna() , reset_index() , drop() , replace() \u8fd9\u4e9b\u65b9\u6cd5\u7684 inplace \u5c5e\u6027\u8bbe\u4e3a True \u65f6\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u4f1a\u4fee\u6539Series\u6216DataFrame\u7684\u5c3a\u5bf8\u6216\u5f62\u72b6\uff0c*\u76f4\u63a5*\u64cd\u4f5c\u539f\u5bf9\u8c61\u800c\u4e0d\u8fd4\u56de\u65b0\u5bf9\u8c61\u3002 obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e']) print(obj) # a 0 # b 1 # c 2 # d 3 # e 4 # dtype: int64 obj1 = obj.drop('c') print(obj1) # a 0 # b 1 # d 3 # e 4 # dtype: int64 print(obj1.drop(['d', 'e'])) # a 0 # b 1 # dtype: int64 \u5bf9\u6bd4 inplace=True \u548c False \u7684\u533a\u522b\u3002 inplace=False \u65f6\uff0c obj \u7684\u503c\u6ca1\u6709\u53d8\u5316\u3002 obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e']) print(obj.drop('c', inplace=False)) # \u8bf4\u660e\u751f\u6210\u4e86\u65b0\u5bf9\u8c61 # a 0 # b 1 # d 3 # e 4 # dtype: int64 print(obj) # a 0 # b 1 # c 2 # d 3 # e 4 # dtype: int64 obj.drop('c', inplace=True) \u8f93\u51fa\u662f None \uff0c\u8bf4\u660e\u6ca1\u6709\u751f\u6210\u65b0\u5bf9\u8c61\uff0c\u53d8\u5316\u76f4\u63a5\u4f5c\u7528\u5230 obj \u4e0a\u3002 obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e']) print(obj) print(obj.drop('c', inplace=True)) # \u8bf4\u660e\u6ca1\u6709\u751f\u6210\u65b0\u5bf9\u8c61 # None print(obj) # a 0 # b 1 # d 3 # e 4 # dtype: int64 \u4e0b\u4f8b\u6f14\u793a\u4e86\u8f74\u5411\u7684\u6548\u679c\u3002 \u5982\u679c\u4e0d\u6307\u5b9a\u8f74\u5411axis\uff0c drop() \u4f1a\u9ed8\u8ba4\u6cbf axis=0 \u8fdb\u884c\uff0c\u6240\u4ee5\uff0c\u57280\u8f74\u4e0a\u6267\u884c data.drop(['one', 'two']) \u4f1a\u62a5\u9519\u3002 axis='columns \u4e0e\u6307\u5b9a axis=1 \u540c\u6837\u6548\u679c\u3002 data = pd.DataFrame( np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['one', 'two', 'three', 'four'] ) print(data) # one two three four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 # \u6cbf0\u8f74\u64cd\u4f5c\uff0c\u5220\u9664\u7b26\u5408\u6761\u4ef6\u7684\u884c\u8bb0\u5f55 print(data.drop(['Ohio', 'Colorado'])) # one two three four # Utah 8 9 10 11 # New York 12 13 14 15 print(data.drop(['one', 'two'])) # KeyError: \"['one' 'two'] not found in axis\" # \u6cbf1\u8f74\u64cd\u4f5c\uff0c\u5220\u9664\u7b26\u5408\u6761\u4ef6\u7684\u5217\u8bb0\u5f55 print(data.drop(['one', 'two'], axis=1)) # three four # Ohio 2 3 # Colorado 6 7 # Utah 10 11 # New York 14 15 print(data.drop(['one', 'two'], axis='columns')) # three four # Ohio 2 3 # Colorado 6 7 # Utah 10 11 # New York 14 15 \u518d\u901a\u8fc7\u4e0b\u4f8b\u4f53\u4f1a\u4e00\u4e0b inplace \u53c2\u6570\u7684\u4e0d\u540c\u6548\u679c\u3002 data = pd.DataFrame( { 'Name': ['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], 'class': [11, 12, 10, 9], 'Age': [18, 20, 21, 17] } ) print(data) # Name class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 print(data.rename(columns={'Name': 'FirstName'}, inplace=False)) # FirstName class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 print(data) # Name class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 print(data.rename(columns={'Name': 'FirstName'}, inplace=True)) # \u6ca1\u6709\u751f\u6210\u65b0\u5bf9\u8c61 # None print(data) # FirstName class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17","title":"\u8f74\u5411\u7d22\u5f15\u5220\u9664\u6761\u76ee"},{"location":"python/DataAnalysis/ch02/#_4","text":"Series\u7684\u7d22\u5f15 obj[...] \u4e0eNumPy\u6570\u7ec4\u7d22\u5f15\u7684\u529f\u80fd\u7c7b\u4f3c\uff0c\u53ea\u4e0d\u8fc7Series\u7684\u7d22\u5f15\u503c\u53ef\u4ee5\u4e0d\u4ec5\u4ec5\u662f\u6574\u6570\u3002 \u4e0b\u4f8b\u4e2d\uff1a obj[1] \u901a\u8fc7\u7d22\u5f15\u4f4d 1 \u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c\u3002 obj[1] \u901a\u8fc7\u7d22\u5f15\u4f4d [1] \u68c0\u7d22\uff0c\u8f93\u51faSeries\u3002 obj['b'] \u901a\u8fc7\u7d22\u5f15\u503c 'b' \u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c\u3002 obj[['b']] \u901a\u8fc7\u7d22\u5f15\u503c ['b'] \u68c0\u7d22\uff0c\u8f93\u51faSeries\u3002 obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd']) print(obj) # a Shobhit # b vaibhav # c vimal # d Sourabh # dtype: object print(obj[1]) # \u901a\u8fc7\u7d22\u5f15\u4f4d\u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c # vaibhav print(obj[[1]]) # b vaibhav # dtype: object print(obj['b']) # \u901a\u8fc7\u7d22\u5f15\u503c\u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c # vaibhav print(obj[['b']]) # \u901a\u8fc7\u7d22\u5f15\u503c\u68c0\u7d22\uff0c\u8f93\u51faSeries # b vaibhav # dtype: object \u4e0b\u9762\u4e00\u7ec4\u7684\u8f93\u51fa\u4e2d\uff0c\u6ce8\u610f\u5bf9\u6bd4\u666e\u901aPython\u5207\u7247\u4e0eSeries\u7684\u5207\u7247\u7684\u5dee\u5f02\u3002 obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd']) print(obj[1]) # vaibhav print(obj[[1]]) # b vaibhav # dtype: object print(obj[1:3]) # b vaibhav # c vimal # dtype: object print(obj['b':'d']) # b vaibhav # c vimal # d Sourabh # dtype: object Series\u7684\u5207\u7247\u7684\u503c\u66f4\u65b0\u3002 obj['b': 'c'] = 5 \u662f\u901a\u8fc7\u7d22\u5f15\u503c\u8fdb\u884c\u66f4\u65b0\uff0c\u76f4\u63a5\u4f5c\u7528\u5728 obj \u3002 obj[1: 3] = 6 \u662f\u901a\u8fc7\u7d22\u5f15\u4f4d\u7f6e\u6765\u66f4\u65b0 obj \u3002 obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd']) obj['b': 'c'] = 5 print(obj) # a Shobhit # b 5 # c 5 # d Sourabh # dtype: object obj[1: 3] = 6 print(obj) # a Shobhit # b 6 # c 6 # d Sourabh # dtype: object DataFrame\u7684\u7d22\u5f15\u4e0e\u5207\u7247\u3002 data[['Three', 'Two']] \u9009\u53d6\u6307\u5b9a\u5217\uff0c\u6ce8\u610f\u8f93\u5165\u5217\u6761\u4ef6\u662f\u5217\u8868 ['Three', 'Two'] \u3002 data = pd.DataFrame( np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['One', 'Two', 'Three', 'Four'] ) print(data) # One Two Three Four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 print(data['Two']) # Ohio 1 # Colorado 5 # Utah 9 # New York 13 # Name: Two, dtype: int64 print(data[['Three', 'Two']]) # Three Two # Ohio 2 1 # Colorado 6 5 # Utah 10 9 # New York 14 13 print(data[:2]) # One Two Three Four # Ohio 0 1 2 3 # Colorado 4 5 6 7 \u5d4c\u5957\uff1a\u6839\u636e\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4\u5207\u7247\u6216\u9009\u62e9\u6570\u636e\u3002 data['Three'] > 5 \u662f\u4e00\u4e2a\u5e03\u5c14\u503c\u5e8f\u5217\u3002 data[data['Three'] > 5] \u8f93\u51fa\u6761\u4ef6\u4e3aTrue\u7684\u7ed3\u679c\u96c6\u3002 print(data['Three'] > 5) # Ohio False # Colorado True # Utah True # New York True # Name: Three, dtype: bool print(data[data['Three'] > 5]) # One Two Three Four # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 \u4f7f\u7528\u5e03\u5c14\u503cDataFrame\u8fdb\u884c\u7d22\u5f15\uff0c\u5df2\u7ecf\u66f4\u65b0\u3002 \u5728\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u8fd9\u79cd\u7d22\u5f15\u65b9\u5f0f\u4f7f\u5f97DataFrame\u5728\u8bed\u6cd5\u4e0a\u66f4\u50cf\u662fNumPy\u4e8c\u7ef4\u6570\u7ec4\u3002 print(data < 5) # One Two Three Four # Ohio True True True True # Colorado True False False False # Utah False False False False # New York False False False False data[data < 5] = 0 print(data) # One Two Three Four # Ohio 0 0 0 0 # Colorado 0 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 \u4f7f\u7528loc\u548ciloc\u9009\u62e9\u6570\u636e\u3002 \u4f7f\u7528\u6807\u7b7e\u540d loc \u6216\u6807\u7b7e\u4f4d\u7f6e iloc \u4ee5NumPy\u98ce\u683c\u7684\u8bed\u6cd5\u4eceDataFrame\u4e2d\u9009\u51faDataframe\u7684\u884c\u548c\u5217\u7684\u5b50\u96c6\u3002 data = pd.DataFrame( np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['One', 'Two', 'Three', 'Four'] ) print(data) # One Two Three Four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 \u4e0b\u4f8b\u901a\u8fc7loc\u5bf9\u6807\u7b7e\u540d\u7b5b\u9009\u884c\u6216\u5217\u6570\u636e\u3002\u4f8b\u5982\uff0c\u8f93\u51fa Colorado \u884c\u6807\u7b7e\u7684 Two \u548c Three \u8fd9\u4e24\u5217\u7684\u503c\uff0c\u4ee5\u884c\u8bb0\u5f55\u7684\u65b9\u5f0f\u5c55\u73b0\u3002 print(data.loc['Colorado', ['Two', 'Three']]) # \u5207\u7247: # Two 5 # Three 6 # Name: Colorado, dtype: int64 print(data.loc[:'Ohio', :'Two']) # \u5207\u7247: 0\u884c\uff0c0,1\u5217 # One Two # Ohio 0 1 \u4e0b\u4f8b\u901a\u8fc7\u6807\u7b7e\u4f4d\u7f6e iloc \u8fdb\u884c\u7c7b\u4f3c\u7684\u6570\u636e\u9009\u62e9\u3002 data.iloc[:3, :2][data > 4] \u6309\u6307\u5b9a\u6761\u4ef6\u8fdb\u884c\u884c\u3001\u5217\u7b5b\u9009\uff0c\u7b26\u5408\u6761\u4ef6 [data > 4] \u7684\u8f93\u51faDataframe\u503c\uff0c\u4e0d\u7b26\u5408\u6761\u4ef6\u7684\u8f93\u51faNaN\u3002 print(data.iloc[[0]]) # 0\u884c # One Two Three Four # Ohio 0 1 2 3 print(data.iloc[[0], [1]]) # \u5207\u7247: 0\u884c\uff0c1\u5217 # Two # Ohio 1 print(data.iloc[1:2, 1:2]) # \u5207\u7247: 1\u884c\uff0c2\u5217 # Two # Ohio 1 print(data.iloc[2, [3, 0, 1]]) # \u5207\u7247: 2\u884c\uff0c\u4f9d\u6b21\u53d63\uff0c0\uff0c1\u5217 # Four 11 # One 8 # Two 9 # Name: Utah, dtype: int64 print(data.iloc[:3, :2][data > 4]) # One Two # Ohio NaN NaN # Colorado NaN 5.0 # Utah 8.0 9.0","title":"\u7d22\u5f15\u3001\u9009\u62e9\u4e0e\u8fc7\u6ee4"},{"location":"python/DataAnalysis/ch02/#_5","text":"Pandas\u7684Series\u7684\u7d22\u5f15\u503c\u662f\u6574\u6570\u7d22\u5f15\u3002 data = np.arange(3.) ser = pd.Series(data) print(ser) # 0 0.0 # 1 1.0 # 2 2.0 # dtype: float64 print(ser[:1]) # 0 0.0 # dtype: float64 print(ser.loc[:1]) # loc\u7528\u4e8e\u6807\u7b7e\u540d # 0 0.0 # 1 1.0 # dtype: float64 print(ser.iloc[:1]) # iloc\u7528\u4e8e\u6807\u7b7e\u4f4d\u7f6e # 0 0.0 # dtype: float64 data = ['1', 'b', 'e', 3] ser = pd.Series(data) print(ser) # 0 1 # 1 b # 2 e # 3 3 # dtype: object print(ser[:1]) # 0 1 # dtype: object print(ser.loc[:1]) # 0 1 # 1 b # dtype: object print(ser.iloc[:1]) # 0 1 # dtype: object \u5bf9DataFrame\u7684\u66f4\u65b0\u3002 df1 = pd.DataFrame(np.arange(4).reshape((2, 2)), columns=list('ab')) print(df1) # a b # 0 0 1 # 1 2 3 # \u6309\u6807\u7b7e\u540d\u66f4\u65b0 df1.loc[1, :'b'] = np.nan print(df1) # a b # 0 0.0 1.0 # 1 NaN NaN","title":"\u6574\u6570\u7d22\u5f15"},{"location":"python/DataAnalysis/ch02/#_6","text":"Pandas\u652f\u6301\u5728Series\u6216\u8005DataFrame\u5bf9\u8c61\u4e4b\u95f4\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97\u3002 \u4f8b\uff1a\u4e24\u4e2aSeries\u505a\u7b97\u672f\u52a0\u6cd5\u3002 \u8fd4\u56de\u7684\u7ed3\u679c\u4e5f\u662f\u4e00\u4e2aSeries\u3002 \u8fd4\u56de\u7ed3\u679c\u7684\u7d22\u5f15\u662f\u6bcf\u4e2aSeries\u7684\u7d22\u5f15\u7684\u5e76\u96c6\u3002 \u51e1\u662f\u6ca1\u6709\u5728\u4e24\u4e2aSeries\u90fd\u51fa\u73b0\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0c\u5185\u90e8\u6570\u636e\u5bf9\u9f50\u4f1a\u586b\u5145\u7f3a\u5931\u503cNaN\u3002\u7f3a\u5931\u503c\u4f1a\u5728\u540e\u7eed\u7684\u5176\u5b83\u7b97\u672f\u64cd\u4f5c\u4e0a\u4ea7\u751f\u5f71\u54cd\u3002 \u540c\u65f6\u51fa\u73b0\u5728\u4e24\u4e2aSeries\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0cSeries\u7684\u503c\u505a\u7b97\u672f\u76f8\u52a0\u3002 s1 = pd.Series( [7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'] ) s2 = pd.Series( [-2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'] ) print(s1) # a 7.3 # c -2.5 # d 3.4 # e 1.5 # dtype: float64 print(s2) # a -2.1 # c 3.6 # e -1.5 # f 4.0 # g 3.1 # dtype: float64 print(s1 + s2) # a 5.2 # c 1.1 # d NaN # e 0.0 # f NaN # g NaN # dtype: float64 \u4f8b\uff1a\u4e24\u4e2aDataframe\u505a\u7b97\u672f\u52a0\u6cd5 \u8fd4\u56de\u7ed3\u679c\u4e5f\u662f\u4e00\u4e2aDataframe\u3002 \u8fd4\u56de\u7ed3\u679c\u7684\u884c\u5217\u7d22\u5f15\u662f\u6bcf\u4e2aDataFrame\u7684\u884c\u5217\u7d22\u5f15\u7684\u5e76\u96c6\u3002 \u51e1\u662f\u6ca1\u6709\u5728\u4e24\u4e2aDataFrame\u90fd\u51fa\u73b0\u7684\u4f4d\u7f6e\u5c31\u4f1a\u88ab\u7f6e\u4e3aNaN\u3002 \u4e24\u4e2aDataFrame\u90fd\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5bf9Dataframe\u7684\u503c\u505a\u7b97\u672f\u52a0\u6cd5\u3002 df1 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'] ) df2 = pd.DataFrame( np.arange(12).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'] ) print(df1) # b c d # Ohio 0 1 2 # Texas 3 4 5 # Colorado 6 7 8 print(df2) # b d e # Utah 0 1 2 # Ohio 3 4 5 # Texas 6 7 8 # Oregon 9 10 11 print(df1 + df2) # b c d e # Colorado NaN NaN NaN NaN # Ohio 3.0 NaN 6.0 NaN # Oregon NaN NaN NaN NaN # Texas 9.0 NaN 12.0 NaN # Utah NaN NaN NaN NaN \u5728Series\u6216\u8005DataFrame\u5bf9\u8c61\u4e4b\u95f4\u8fdb\u884c\u7b97\u672f\u64cd\u4f5c\u65f6\uff0c\u6709\u65f6\u9700\u8981\u5bf9\u7f3a\u5931\u503c\u6307\u5b9a\u586b\u5145\u503c\uff0c\u6bd4\u5982\u5f53\u8f74\u6807\u7b7e\u5728\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u5b58\u5728\uff0c\u5728\u53e6\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u4e0d\u5b58\u5728\u65f6\uff0c\u5c06\u7f3a\u5931\u503c\u586b\u5145\u4e3a0\u3002\u4e5f\u5c31\u662f\u8bf4\uff0c\u5982\u679c\u5728\u4e24\u4e2aDataFrame\u90fd\u7f3a\u5931\uff0c\u90a3\u4e48\u4f9d\u7136\u8fd8\u4f1a\u662fNaN\u3002 \u4e0b\u4f8b\u4e2da2\u662f\u5728 df1 \u548c df2 \u90fd\u7f3a\u5931\u7684\u4f4d\u7f6e\uff0c\u6240\u4ee5\u5373\u4f7f fill_value=0 \uff0ca2\u4ecd\u7136\u662fNaN\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('bcd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # b c d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 # \u5bf9df1\u548cdf2\u5c31\u7b97\u672f\u548c\uff0c\u5bf9\u5e94\u6ca1\u6709\u884c\u5217\u5171\u540c\u7684\u4ea4\u96c6\u7684\u5730\u65b9\u586b\u5145\u7a7a\u503cNaN\uff0c\u6709\u4ea4\u96c6\u7684\u5730\u65b9\u6c42\u7b97\u672f\u548c\u3002 print(df1.add(df2)) # a b c d # 0 NaN 1.0 NaN NaN # 1 NaN 6.0 NaN NaN # 2 NaN NaN NaN NaN # \u5bf9df1\u548cdf2\u5c31\u7b97\u672f\u548c\uff0c\u5bf9\u5e94\u6ca1\u6709\u884c\u5217\u5171\u540c\u7684\u4ea4\u96c6\u7684\u5730\u65b9\u586b\u5145\u7a7a\u503c0\uff0c\u6709\u4ea4\u96c6\u7684\u5730\u65b9\u6c42\u7b97\u672f\u548c\u3002 print(df1.add(df2, fill_value=0)) # df2.add(df1, fill_value=0) \u8fd4\u56de\u540c\u6837\u7684\u7ed3\u679c # a b c d # 0 0.0 1.0 1.0 2.0 # 1 2.0 6.0 4.0 5.0 # 2 NaN 6.0 7.0 8.0 \u4e0b\u4f8b\u4e2db2\u662f\u5728 df1 \u548c df2 \u90fd\u7f3a\u5931\u7684\u4f4d\u7f6e\uff0c\u6240\u4ee5\u5373\u4f7f fill_value=0 \uff0cb2\u4ecd\u7136\u662fNaN\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('acd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # a c d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 print(df1.add(df2, fill_value=0)) # a b c d # 0 0.0 1.0 1.0 2.0 # 1 5.0 3.0 4.0 5.0 # 2 6.0 NaN 7.0 8.0 \u4e0b\u4f8b\u4e2d\u6ca1\u6709\u4e24\u4e2aDataFrame\u5171\u540c\u7f3a\u5931\u7684\u60c5\u51b5\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('abd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # a b d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 print(df1.add(df2, fill_value=0)) # a b d # 0 0.0 2.0 2.0 # 1 5.0 7.0 5.0 # 2 6.0 7.0 8.0 \u4e0b\u9762\u662fSeries\u548cDataFrame\u7684\u7b97\u672f\u65b9\u6cd5\u3002 add\uff0cradd\uff1a\u52a0\u6cd5(+) sub\uff0crsub\uff1a\u51cf\u6cd5(-) div\uff0crdiv\uff1a\u9664\u6cd5(/) floordiv\uff0crfloordiv\uff1a\u6574\u9664(//) mul\uff0crmul\uff1a\u4e58\u6cd5(*) pow\uff0crpow\uff1a\u5e42\u6b21\u65b9(**) \u4e0a\u8ff0\u6bcf\u4e2a\u65b9\u6cd5\u90fd\u6709\u4e00\u4e2a\u4ee5r\u5f00\u5934\u7684\u526f\u672c\uff0c\u8fd9\u4e9b\u526f\u672c\u65b9\u6cd5\u7684\u53c2\u6570\u662f\u7ffb\u8f6c\u7684\u3002\u6bd4\u5982\uff0c\u6c42DataFrame\u5f53\u4e2d\u6240\u6709\u5143\u7d20\u7684\u5012\u6570 1/df \uff0c\u53ef\u4ee5\u5199\u6210df.rdiv(1)\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('abd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # a b d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 print(df1.radd(df2, fill_value=0)) # a b d # 0 0.0 2.0 2.0 # 1 5.0 7.0 5.0 # 2 6.0 7.0 8.0 print(df1.sub(df2, fill_value=0)) # a b d # 0 0.0 0.0 -2.0 # 1 -1.0 -1.0 -5.0 # 2 -6.0 -7.0 -8.0 print(df1.div(df2, fill_value=0)) # a b d # 0 NaN 1.00 0.0 # 1 0.666667 0.75 0.0 # 2 0.000000 0.00 0.0 print(df1.floordiv(df2, fill_value=0)) # a b d # 0 NaN 1.0 0.0 # 1 0.0 0.0 0.0 # 2 0.0 0.0 0.0 print(df1.mul(df2, fill_value=0)) # a b d # 0 0.0 1.0 0.0 # 1 6.0 12.0 0.0 # 2 0.0 0.0 0.0 print(df1.pow(df2, fill_value=0)) # a b d # 0 1.0 1.0 0.0 # 1 8.0 81.0 0.0 # 2 0.0 0.0 0.0","title":"\u7b97\u672f\u548c\u6570\u636e\u5bf9\u9f50"},{"location":"python/DataAnalysis/ch02/#dataframeseries","text":"DataFrame\u548cSeries\u95f4\u7684\u7b97\u672f\u64cd\u4f5c\u4e0eNumPy\u4e2d\u4e0d\u540c\u7ef4\u5ea6\u6570\u7ec4\u95f4\u7684\u64cd\u4f5c\u7c7b\u4f3c\u3002","title":"DataFrame\u548cSeries\u95f4\u7684\u7b97\u672f\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch02/#numpy","text":"\u4ecearr\u4e2d\u51cf\u53bbarr[0]\u65f6\uff0c\u51cf\u6cd5\u6cbf0\u8f74\u5728\u6bcf\u4e00\u884c\u90fd\u8fdb\u884c\u4e86\u64cd\u4f5c\u3002\u8fd9\u5c31\u662f\u6240\u8c13\u7684\u5e7f\u64ad\u673a\u5236\u3002 arr = np.arange(12).reshape((3, 4)) print(arr) # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] print(arr[0]) # [0 1 2 3] print(arr - arr[0]) # [[0 0 0 0] # [4 4 4 4] # [8 8 8 8]]","title":"\u4e0d\u540c\u7ef4\u5ea6NumPy\u6570\u7ec4\u95f4\u7684\u7b97\u672f\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch02/#dataframeseries_1","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cDataFrame\u548cSeries\u7684\u6570\u5b66\u64cd\u4f5c\u4e2d\u4f1a\u5c06Series\u7684\u7d22\u5f15\u548cDataFrame\u7684*\u5217*\u8fdb\u884c\u5339\u914d\uff0c\u5e76*\u5e7f\u64ad\u5230\u5404\u884c*. \u5982\u679c\u4e00\u4e2a\u7d22\u5f15\u503c\u4e0d\u5728DataFrame\u7684\u5217\u4e2d\uff0c\u4e5f\u4e0d\u5728Series\u7684\u7d22\u5f15\u4e2d\uff0c\u5219\u65b0\u5bf9\u8c61\u4f1a\u6784\u5efa\u5e76\u96c6\u7d22\u5f15\u3002 frame = pd.DataFrame( np.arange(12).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'] ) print(frame) # b d e # Utah 0 1 2 # Ohio 3 4 5 # Texas 6 7 8 # Oregon 9 10 11 # \u622a\u53d6frame\u7684\u7b2c0\u884c\uff0c\u5217\u6807\u7b7e\u53d8\u6210\u65b0Serise\u7684\u7d22\u5f15\u3002 series = frame.iloc[0] print(series) # b 0 # d 1 # e 2 # Name: Utah, dtype: int64 series2 = pd.Series( range(3), index=list('bef') ) print(series2) # b 0 # e 1 # f 2 # dtype: int64 # \u622a\u53d6frame\u7684d\u5217\uff0c\u884c\u6807\u7b7e\u53d8\u6210\u65b0Serise\u7684\u7d22\u5f15\u3002 series3 = frame['d'] print(series3) # Utah 1 # Ohio 4 # Texas 7 # Oregon 10 # Name: d, dtype: int64 # \u5c06Series\u7684\u7d22\u5f15\u548cDataFrame\u7684\u5217\u6807\u7b7e\u8fdb\u884c\u5339\u914d\uff0cSeries\u7684\u503c\u6cbfDataFrame\u76840\u8f74\u5e7f\u64ad\u5230\u5404\u4e2a\u884c\u3002 print(frame - series) # frame: series Result: # b d e # b 0 # b d e # Utah 0 1 2 # d 1 # Utah 0 0 0 # Ohio 3 4 5 # e 2 # Ohio 3 3 3 # Texas 6 7 8 # Name: Utah, dtype: int64 # Texas 6 6 6 # Oregon 9 10 11 # Oregon 9 9 9 # \u5c06Series\u7684\u7d22\u5f15\u548cDataFrame\u7684\u5217\u6807\u7b7e\u8fdb\u884c\u5339\u914d\uff0cSeries\u7684\u503c\u6cbfDataFrame\u76840\u8f74\u5e7f\u64ad\u5230\u5404\u4e2a\u884c\uff0c\u7f3a\u5931\u4f4d\u7f6e\u586b\u5145\u7a7a\u503cNaN\u3002 print(frame - series2) # frame: series2 Result: # b d e # b 0 # b d e f # Utah 0 1 2 # e 1 # Utah 0.0 NaN 1.0 NaN # Ohio 3 4 5 # f 2 # Ohio 3.0 NaN 4.0 NaN # Texas 6 7 8 # dtype: int64 # Texas 6.0 NaN 7.0 NaN # Oregon 9 10 11 # Oregon 9.0 NaN 10.0 NaN # \u6539\u4e3a\u5728\u5217\u4e0a\u8fdb\u884c\u5e7f\u64ad\uff0c\u5728\u884c\u4e0a\u5339\u914d\uff0c\u5fc5\u987b\u4f5c\u7528\u5728\u67d0\u79cd\u7b97\u672f\u65b9\u6cd5\u4e0a\u3002\u4e0b\u4f8b\u4e2dSeries\u7684\u503c\u6cbfDataFrame\u76840\u8f74\u5e7f\u64ad\u5230\u5404\u4e2a\u884c\uff08\u6309index\u5339\u914d\u8fdb\u884c\u884c\u64cd\u4f5c\uff09\u3002 print(frame.sub(series3, axis='index')) # \u6216axis=0 # frame: series3 Result: # b d e # Utah 1 # b d e # Utah 0 1 2 # Ohio 4 # Utah -1 0 1 # Ohio 3 4 5 # Texas 7 # Ohio -1 0 1 # Texas 6 7 8 # Oregon 10 # Texas -1 0 1 # Oregon 9 10 11 # Name: d, dtype: int64 # Oregon -1 0 1","title":"DataFrame\u548cSeries\u95f4\u7684\u7b97\u672f\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch02/#_7","text":"NumPy\u7684\u901a\u7528\u51fd\u6570\uff08\u9010\u5143\u7d20\u6570\u7ec4\u65b9\u6cd5\uff09\u5bf9pandas\u5bf9\u8c61\uff08DataFrame\u548cSeries\uff09\u4e5f\u6709\u6548\u3002 frame = pd.DataFrame( np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'] ) print(frame) # b d e # Utah 2.737734 -0.379977 0.758933 # Ohio 0.847497 0.839583 -2.192021 # Texas -0.907544 -0.457436 -1.907396 # Oregon 0.389362 0.250170 1.065889 # \u5bf9DataFrame\u5bf9\u8c61\u8ba1\u7b97\u7edd\u5bf9\u503c\u3002 print(np.abs(frame)) # b d e # Utah 2.737734 0.379977 0.758933 # Ohio 0.847497 0.839583 2.192021 # Texas 0.907544 0.457436 1.907396 # Oregon 0.389362 0.250170 1.065889 # f\u8fd4\u56de\u4e00\u4e2a\u6807\u91cf\u503c f = lambda x: x.max() - x.min() # \u6cbf0\u8f74\u5e94\u7528f\uff08\u5bf9\u6bcf\u5217\u7684\u6240\u6709\u884c\u5143\u7d20\u8fdb\u884cf\u8ba1\u7b97\uff09, \u9ed8\u8ba4axis=0 print(frame.apply(f)) # b 3.645278 # d 1.297019 # e 3.257911 # dtype: float64 # \u6cbf1\u8f74\u5e94\u7528f\uff08\u5bf9\u6bcf\u884c\u7684\u6240\u6709\u5217\u5143\u7d20\u8fdb\u884cf\u8ba1\u7b97\uff09 print(frame.apply(f, axis=1)) # Utah 3.117711 # Ohio 3.039518 # Texas 1.449961 # Oregon 0.815720 # dtype: float64 # \u5b9a\u4e49\u51fd\u6570f\uff0c\u8fd4\u56de\u5e26\u6709\u591a\u4e2a\u503c\u7684Series\u3002 def f(x): return pd.Series( [x.min(), x.max()], index=['min', 'max'] ) print(frame.apply(f)) # b d e # min -0.907544 -0.457436 -2.192021 # max 2.737734 0.839583 1.065889 # \u5b9a\u4e49\u51fd\u6570f\uff0c\u4f7f\u7528applymap\u65b9\u6cd5\u683c\u5f0f\u5316\u5b57\u7b26\uff0c\u5c06\u4e00\u4e2a\u9010\u5143\u7d20\u7684\u51fd\u6570\u5e94\u7528\u5230Series\u4e0a\u3002 f = lambda x: '%.2f' % x print(frame.applymap(f)) # # b d e # Utah 2.74 -0.38 0.76 # Ohio 0.85 0.84 -2.19 # Texas -0.91 -0.46 -1.91 # Oregon 0.39 0.25 1.07 print(frame['e'].map(f)) # Utah 0.76 # Ohio -2.19 # Texas -1.91 # Oregon 1.07 # Name: e, dtype: object","title":"\u51fd\u6570\u5e94\u7528\u548c\u6620\u5c04"},{"location":"python/DataAnalysis/ch02/#_8","text":"\u4f7f\u7528sort_index\u65b9\u6cd5\uff0c\u6309\u884c\u6216\u5217\u7d22\u5f15\u8fdb\u884c\u5b57\u5178\u578b\u6392\u5e8f\uff0c\u8fd4\u56de\u4e00\u4e2a\u65b0\u7684\u6392\u5e8f\u597d\u7684Pandas\u5bf9\u8c61\u3002","title":"\u6392\u5e8f\u548c\u6392\u540d"},{"location":"python/DataAnalysis/ch02/#series_1","text":"\u5bf9Series\u8fdb\u884c\u7d22\u5f15\u6392\u5e8f\u548c\u503c\u6392\u5e8f\u3002 obj = pd.Series( range(4), index=list('dabc') ) print(obj) # d 0 # a 1 # b 2 # c 3 # dtype: int64 print(obj.sort_index()) # a 1 # b 2 # c 3 # d 0 # dtype: int64 # print(obj.sort_values()) # d 0 # a 1 # b 2 # c 3 # dtype: int64 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6240\u6709\u7684\u7f3a\u5931\u503c\u90fd\u4f1a\u88ab\u6392\u5e8f\u81f3Series\u7684\u5c3e\u90e8\u3002 obj = pd.Series([4, np.nan, 7, np.nan, -3, 2]) print(obj) # 0 4.0 # 1 NaN # 2 7.0 # 3 NaN # 4 -3.0 # 5 2.0 # dtype: float64 print(obj.sort_values()) # 4 -3.0 # 5 2.0 # 0 4.0 # 2 7.0 # 1 NaN # 3 NaN # dtype: float64","title":"Series\u6392\u5e8f"},{"location":"python/DataAnalysis/ch02/#dataframe_3","text":"frame = pd.DataFrame( [[0, 1, 10, 3], [4, 5, 6, 21], [8, 9, 2, 21]], index=['three', 'one', 'five'], columns=list('dabc') ) print(frame) # d a b c # three 0 1 10 3 # one 4 5 6 21 # five 8 9 2 21 print(frame.index) # Index(['three', 'one', 'five'], dtype='object') # \u9ed8\u8ba40\u8f74\uff0c\u6240\u6709\u884c\u8fdb\u884c\u7d22\u5f15\u9996\u5b57\u6bcd\u5347\u5e8f print(frame.sort_index()) # d a b c # five 8 9 2 21 # one 4 5 6 21 # three 0 1 10 3 # \u6307\u5b9a0\u8f74\uff0c\u6240\u6709\u884c\u8fdb\u884c\u7d22\u5f15\u9996\u5b57\u6bcd\u5347\u5e8f print(frame.sort_index(axis=0)) # d a b c # five 8 9 2 21 # one 4 5 6 21 # three 0 1 10 3 # \u6307\u5b9a0\u8f74\uff0c\u6240\u6709\u884c\u8fdb\u884c\u7d22\u5f15\u9996\u5b57\u6bcd\u964d\u5e8f print(frame.sort_index(axis=0, ascending=False)) # d a b c # three 0 1 10 3 # one 4 5 6 21 # five 8 9 2 21 # \u6307\u5b9a1\u8f74\uff0c\u6240\u6709\u5217\u8fdb\u5217\u7d22\u5f15\u9996\u5b57\u6bcd\u5347\u5e8f print(frame.sort_index(axis=1)) # a b c d # three 1 10 3 0 # one 5 6 21 4 # five 9 2 21 8 # \u6307\u5b9a1\u8f74\uff0c\u6240\u6709\u5217\u8fdb\u5217\u7d22\u5f15\u9996\u5b57\u6bcd\u964d\u5e8f print(frame.sort_index(axis=1, ascending=False)) # d c b a # three 0 3 10 1 # one 4 21 6 5 # five 8 21 2 9 # \u6309\u6307\u5b9a\u5355\u5217\u8fdb\u884c\u503c\u6392\u5e8f\uff08\u964d\u5e8f\uff09 print(frame.sort_values(by=['c'], ascending=False)) # d a b c # one 4 5 6 21 # five 8 9 2 21 # three 0 1 10 3 # \u6309\u6307\u5b9a\u591a\u5217\u8fdb\u884c\u503c\u6392\u5e8f\uff08\u964d\u5e8f\uff09\uff0c\u5148\u5bf9b\u964d\u5e8f\uff0c\u518d\u5bf9d\u964d\u5e8f print(frame.sort_values(by=['c', 'd'], ascending=False)) # d a b c # five 8 9 2 21 # one 4 5 6 21 # three 0 1 10 3","title":"DataFrame\u6392\u5e8f"},{"location":"python/DataAnalysis/ch02/#_9","text":"**\u6392\u540d**\u662f\u6307\u5bf9\u6570\u7ec4\u4ece1\u5230\u6709\u6548\u6570\u636e\u70b9\u603b\u6570\u5206\u914d\u540d\u6b21\u7684\u64cd\u4f5c\u3002 Series\u548cDataFrame\u7684 rank \u65b9\u6cd5\u662f\u5b9e\u73b0\u6392\u540d\u7684\u65b9\u6cd5\uff0c df.rank(ascending=False, method='max') \u3002 ascending \uff1a\u6392\u540d\u65b9\u5f0f\uff0c\u9ed8\u8ba4\u4ece\u4f4e\u5230\u9ad8\uff0c ascending=False \u8868\u793a\u4ece\u9ad8\u5230\u4f4e\uff1b method \uff1a\u6392\u540d\u65b9\u5f0f\uff0c\u5305\u62ec\uff1a average:\u9ed8\u8ba4\uff0c\u5728\u76f8\u7b49\u5206\u7ec4\u4e2d\uff0c\u4e3a\u5404\u4e2a\u503c\u5206\u914d\u5e73\u5747\u6392\u540d\uff0c\u5373\u76f8\u540c\u503c\u7684\u548c\u9664\u4ee5\u8be5\u503c\u7684\u4e2a\u6570\uff0c\u5373\u4e3a\u8be5\u503c\u7684\u540d\u6b21\u3002 min:\u4f7f\u7528\u6574\u4e2a\u5206\u7ec4\u7684\u6700\u5c0f\u6392\u540d\uff0c\u5373\uff0c\u5bf9\u5e94\u76f8\u540c\u503c\uff0c\u53d6\u5728\u987a\u5e8f\u6392\u540d\u4e2d\u6700\u5c0f\u7684\u90a3\u4e2a\u6392\u540d\u4f5c\u4e3a\u6240\u6709\u8be5\u503c\u7684\u6392\u540d\u3002 max:\u4f7f\u7528\u6574\u4e2a\u5206\u7ec4\u7684\u6700\u5927\u6392\u540d\uff0c\u5373\uff0c\u5bf9\u5e94\u76f8\u540c\u503c\uff0c\u53d6\u5728\u987a\u5e8f\u6392\u540d\u4e2d\u6700\u5927\u7684\u90a3\u4e2a\u6392\u540d\u4f5c\u4e3a\u6240\u6709\u8be5\u503c\u7684\u6392\u540d\u3002 first:\u6309\u503c\u518d\u539f\u59cb\u6570\u636e\u4e2d\u51fa\u73b0\u987a\u5e8f\u5206\u914d\u6392\u540d\uff0c\u8c01\u51fa\u73b0\u7684\u4f4d\u7f6e\u9760\u524d\uff0c\u8c01\u7684\u6392\u540d\u9760\u524d\u3002 dense:\u7c7b\u4f3cmin\u65b9\u6cd5\uff0c\u4f46\u6392\u540d\u603b\u662f\u5728\u7ec4\u95f4\u589e\u52a01\uff0c\u800c\u4e0d\u662f\u7ec4\u4e2d\u76f8\u540c\u7684\u5143\u7d20\u6570\uff0c\u5373\u76f8\u540c\u503c\u7684\u6392\u540d\u76f8\u540c\uff0c\u5176\u4ed6\u4f9d\u6b21\u52a01\u5373\u53ef\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0crank\u662f\u901a\u8fc7\u201c\u4e3a\u5404\u7ec4\u5206\u914d\u4e00\u4e2a\u5e73\u5747\u6392\u540d\u201d\u7684\u65b9\u5f0f\u7834\u574f\u5e73\u7ea7\u5173\u7cfb # \u6309\u7167\u6bcf\u4e2a\u5143\u7d20\u7684\u5927\u5c0f\u987a\u5e8f\u7ed9\u51fa\u4e00\u4e2a\u5e73\u5747\u6392\u540d obj = pd.Series([7, -5, 7, 4, 2, 0, 4]) print(obj) # 0 7 # 1 -5 # 2 7 # 3 4 # 4 2 # 5 0 # 6 4 # dtype: int64 print(obj.rank()) # 0 6.5 # 1 1.0 # 2 6.5 # 3 4.5 # 4 3.0 # 5 2.0 # 6 4.5 # dtype: float64 # index value rank # 2 -5 1 # 6 0 2 # 5 2 3 # 4 4 4.5 # 7 4 4.5 # 1 7 6.5 # 3 7 6.5 # \u6839\u636e\u5143\u7d20\u7684\u89c2\u5bdf\u987a\u5e8f\u8fdb\u884c\u5206\u914d\u3002\u5143\u7d200\u548c2\u6ca1\u6709\u4f7f\u7528\u5e73\u5747\u6392\u540d6.5\uff0c\u5b83\u4eec\u88ab\u8bbe\u6210\u4e866\u548c7\uff0c\u56e0\u4e3a\u6570\u636e\u4e2d\u6807\u7b7e0\u4f4d\u4e8e\u6807\u7b7e2\u7684\u524d\u9762\u3002 print(obj.rank(method='first')) # 0 6.0 # 1 1.0 # 2 7.0 # 3 4.0 # 4 3.0 # 5 2.0 # 6 5.0 # dtype: float64 # \u6309\u7167max\u8fdb\u884c\u5347\u5e8f\u548c\u964d\u5e8f print(obj.rank(ascending=False, method='max')) print(obj.rank(ascending=True, method='max')) # Original Series Max with inc Max with dec # 0 7 # 0 2.0 (\u6700\u5c0f) # 0 7.0 (\u6700\u5927) # 1 -5 # 1 7.0 (\u6700\u5927) # 1 1.0 (\u6700\u5c0f) # 2 7 # 2 2.0 (\u6700\u5c0f) # 2 7.0 (\u6700\u5927) # 3 4 # 3 4.0 # 3 5.0 # 4 2 # 4 5.0 # 4 3.0 # 5 0 # 5 6.0 # 5 2.0 # 6 4 # 6 4.0 # 6 5.0 # dtype: float64 # dtype: float64 # dtype: float64 frame = pd.DataFrame( {'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1], 'c': [-2, 5, 8, -2]} ) print(frame) # b a c # 0 4.3 0 -2 # 1 7.0 1 5 # 2 -3.0 0 8 # 3 2.0 1 -2 # \u6cbf1\u8f74\u5bf9DataFrame\u8fdb\u884crank\u64cd\u4f5c\uff0c\u5373\uff0c\u6bcf\u4e00\u884c\u5404\u5143\u7d20\u8fdb\u884crank\u3002 print(frame.rank(axis='columns')) # axis=1 # b a c # 0 3.0 2.0 1.0 # 1 3.0 1.0 2.0 # 2 1.0 2.0 3.0 # 3 3.0 2.0 1.0","title":"\u6392\u540d"},{"location":"python/DataAnalysis/ch02/#_10","text":"\u5c3d\u7ba1\u5f88\u591apandas\u51fd\u6570\uff08\u6bd4\u5982reindex\uff09\u9700\u8981\u6807\u7b7e\u662f\u552f\u4e00\u7684\uff0c\u4f46\u8fd9\u4e2a\u5e76\u4e0d\u662f\u5f3a\u5236\u6027\u7684\u3002 \u7d22\u5f15\u7684is_unique\u5c5e\u6027\u53ef\u4ee5\u68c0\u67e5\u6807\u7b7e\u662f\u5426\u552f\u4e00\u3002 \u5e26\u6709\u91cd\u590d\u7d22\u5f15\u7684\u60c5\u51b5\u4e0b\uff0c\u4e00\u4e2a\u7d22\u5f15\u6807\u7b7e\u4f1a\u4ee5\u5e8f\u5217\u65b9\u5f0f\u8fd4\u56de\u591a\u4e2a\u6761\u76ee\u3002\u4e0d\u91cd\u590d\u7684\u7d22\u5f15\u5219\u4f1a\u4ee5\u6807\u91cf\u503c\u7684\u5f62\u5f0f\u8fd4\u56de\u5355\u4e2a\u6761\u76ee\uff0c\u8fd9\u53ef\u80fd\u4f1a\u4f7f\u4ee3\u7801\u66f4\u590d\u6742\u3002 obj = pd.Series(range(5), index=['a', 'b', 'a', 'c', 'b']) print(obj) # a 0 # b 1 # a 2 # c 3 # b 4 # dtype: int64 print(obj.is_unique) # True print(obj.index.is_unique) # False # \u8fd4\u56de\u91cd\u590d\u7d22\u5f15\u5bf9\u5e94\u503c\u7684\u5e8f\u5217\u3002 print(obj['a']) # a 0 # a 2 # dtype: int64 df = pd.DataFrame(np.random.randn(4, 3), index=['a', 'a', 'b', 'b']) print(df) # 0 1 2 # a -0.726164 0.531540 -0.521611 # a -1.539807 -0.710880 -0.992789 # b -0.975970 -0.470725 0.121958 # b -0.301495 1.072322 -1.542296 print(df.index.is_unique) # False print(df.loc['b']) # 0 1 2 # b -0.520008 0.052574 0.638529 # b -1.928705 -1.099534 -1.605296","title":"\u542b\u6709\u91cd\u590d\u6807\u7b7e\u7684\u8f74\u7d22\u5f15"},{"location":"python/DataAnalysis/ch02/#_11","text":"pandas\u5305\u542b\u4e86\u4e00\u4e9b\u5e38\u7528\u6570\u5b66\u3001\u7edf\u8ba1\u5b66\u65b9\u6cd5\u3002\u5176\u4e2d\u5927\u90e8\u5206\u5c5e\u4e8e\u5f52\u7ea6\u6216\u6c47\u603b\u7edf\u8ba1\u7684\u7c7b\u522b\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u4eceDataFrame\u7684\u884c\u6216\u5217\u4e2d\u62bd\u53d6\u4e00\u4e2aSeries\u6216\u4e00\u7cfb\u5217\u503c\uff08\u5982\u603b\u548c\u6216\u5e73\u5747\u503c\uff09\u3002 \u4e0eNumPy\u6570\u7ec4\u4e2d\u7684\u7c7b\u4f3c\u65b9\u6cd5\u76f8\u6bd4\uff0cpandas\u5185\u5efa\u4e86\u5904\u7406\u7f3a\u5931\u503c\u7684\u529f\u80fd\u3002 \u5f52\u7ea6\u65b9\u6cd5: sum() \u79ef\u7d2f\u578b\u65b9\u6cd5: cumsun() \u65e2\u4e0d\u662f\u5f52\u7ea6\u578b\u65b9\u6cd5\u4e5f\u4e0d\u662f\u79ef\u7d2f\u578b\u65b9\u6cd5: describe() df = pd.DataFrame( [[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=list('abcd'), columns=['one', 'two'] ) print(df) # one two # a 1.40 NaN # b 7.10 -4.5 # c NaN NaN # d 0.75 -1.3 # axis=0, \u8fd4\u56de\u4e00\u4e2a\u6bcf\u5217\u7b97\u672f\u548c\u7684Series print(df.sum()) # one 9.25 # two -5.80 # dtype: float64 # axis=1\u4e14skipna=True, \u8fd4\u56de\u4e00\u4e2a\u6bcf\u884c\u548c\u7684Series, \u5ffd\u7565NA\u503c, \u586b0\u3002 print(df.sum(axis=1)) # a 1.40 # b 2.60 # c 0.00 # d -0.55 # dtype: float64 # \u4e0d\u5ffd\u7565NA\u503c\uff0c\u586bNaN\u3002 print(df.sum(axis=1, skipna=False)) # a NaN # b 2.60 # c NaN # d -0.55 # dtype: float64 # \u53ea\u67091\u7ea7\u7d22\u5f15\uff0c\u6240\u4ee5level=0\u548c\u539f\u7d22\u5f15\u6ca1\u6709\u533a\u522b\uff0cNaN\u586b\u51450\u3002 print(df.groupby(level=0).sum()) # one two # a 1.40 0.0 # b 7.10 -4.5 # c 0.00 0.0 # d 0.75 -1.3 # \u5217one\u7684\u6700\u5927\u503c\u662f\u5728\u7d22\u5f15b, \u5217two\u7684\u6700\u5927\u503c\u662f\u5728\u7d22\u5f15d print(df.idxmax()) # one b # two d # dtype: object print(df.idxmin()) # one d # two b # dtype: object # cumsun\u7684\u610f\u601d\u662f\u7b2cn\u6b21\u7684\u548c\u662fn-1\u6b21\u7684\u548c\u4e0en\u7684\u548c\uff0cone\u5217d\u884c\u7684\u548c\u5c31\u662fone\u5217a\u3001b\u3001c\u3001d\u503c\u7684\u603b\u548c\u3002 print(df.cumsum()) # one two # a 1.40 NaN # b 8.50 -4.5 # c NaN NaN # d 9.25 -5.8 \u901a\u8fc7describe\u4ea7\u751f\u7edf\u8ba1\u4fe1\u606f\uff0c\u6ce8\u610f\uff0c\u6570\u503c\u578b\u548c\u975e\u6570\u503c\u578b\u7684describe\u7684\u4fe1\u606f\u662f\u4e0d\u540c\u7684\u3002 # \u4e00\u6b21\u6027\u4ea7\u751f\u591a\u4e2a\u6c47\u603b\u7edf\u8ba1 print(df.describe()) # one two # count 3.000000 2.000000 # mean 3.083333 -2.900000 # std 3.493685 2.262742 # min 0.750000 -4.500000 # 25% 1.075000 -3.700000 # 50% 1.400000 -2.900000 # 75% 4.250000 -2.100000 # max 7.100000 -1.300000 obj = pd.Series(['a', 'a', 'b', 'c'] * 4) print(obj) # 0 a # 1 a # 2 b # 3 c # 4 a # 5 a # 6 b # 7 c # 8 a # 9 a # 10 b # 11 c # 12 a # 13 a # 14 b # 15 c # dtype: object # \u9488\u5bf9\u975e\u6570\u503c\u578b\u6570\u636e\uff0cdescribe\u4ea7\u751f\u53e6\u4e00\u79cd\u6c47\u603b\u7edf\u8ba1 print(obj.describe()) # count 16 # unique 3 # top a # freq 8 # dtype: object","title":"\u63cf\u8ff0\u6027\u7edf\u8ba1\u6982\u8ff0\u4e0e\u8ba1\u7b97"},{"location":"python/DataAnalysis/ch02/#_12","text":"\u534f\u65b9\u5dee\u4e0e\u76f8\u5173\u7cfb\u6570\u4e5f\u662f\u5728\u65f6\u57df\u5206\u6790\u65f6\u5e38\u89c1\u7684\u4e24\u4e2a\u6982\u5ff5\uff0c\u4ed6\u4eec\u90fd\u662f\u7528\u6765\u63cf\u8ff0\u6570\u636e\u201c\u50cf\u4e0d\u50cf\u201d\u7684\u3002 \u534f\u65b9\u5dee\u7684\u901a\u4fd7\u7406\u89e3\uff1a \u4e24\u4e2a\u53d8\u91cf\u5728\u53d8\u5316\u8fc7\u7a0b\u4e2d\u662f\u540c\u65b9\u5411\u53d8\u5316\u8fd8\u662f\u53cd\u65b9\u5411\u53d8\u5316\uff1f\u76f8\u540c\u6216\u8005\u76f8\u53cd\u7a0b\u5ea6\u5982\u4f55\uff1f \u4f60\u53d8\u5927\uff0c\u540c\u65f6\u6211\u53d8\u5927\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u662f\u540c\u5411\u53d8\u5316\uff0c\u8fd9\u65f6\u534f\u65b9\u5dee\u5c31\u662f\u6b63\u7684\u3002 \u4f60\u53d8\u5927\uff0c\u540c\u65f6\u6211\u53d8\u5c0f\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u662f\u53cd\u5411\u53d8\u5316\uff0c\u8fd9\u65f6\u534f\u65b9\u5dee\u5c31\u662f\u8d1f\u7684\u3002 \u4ece\u6570\u503c\u770b\uff0c\u534f\u65b9\u5dee\u7684\u6570\u503c\u8d8a\u5927\uff0c\u4e24\u4e2a\u53d8\u91cf\u540c\u5411\u7a0b\u5ea6\u4e5f\u5c31\u8d8a\u5927\u3002\u53cd\u4e4b\u4ea6\u7136\u3002 \u76f8\u5173\u7cfb\u6570\u7684\u901a\u4fd7\u7406\u89e3\uff1a \u7528X\uff0cY\u7684\u534f\u65b9\u5dee\u9664\u4ee5X\u7684\u6807\u51c6\u5dee\u548cY\u7684\u6807\u51c6\u5dee\u3002\u76f8\u5173\u7cfb\u6570\u4e5f\u53ef\u4ee5\u770b\u6210\u534f\u65b9\u5dee\uff0c\u4e00\u79cd\u63d0\u51fa\u4e86\u4e24\u4e2a\u53d8\u91cf\u91cf\u7eb2\u5f71\u54cd\u3001\u6807\u51c6\u5316\u540e\u7684\u7279\u6b8a\u534f\u65b9\u5dee\u3002\u6240\u4ee5\uff1a\u4e5f\u53ef\u4ee5\u53cd\u6620\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u65f6\u662f\u540c\u5411\u8fd8\u662f\u53cd\u5411\uff0c\u5982\u679c\u540c\u5411\u53d8\u5316\u5c31\u4e3a\u6b63\uff0c\u53cd\u5411\u53d8\u5316\u5c31\u4e3a\u8d1f\u3002 \u7531\u4e8e\u662f\u6807\u51c6\u7248\u540e\u7684\u534f\u65b9\u5dee\uff0c\u76f8\u5173\u7cfb\u6570\u6d88\u9664\u4e86\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u5e45\u5ea6\u7684\u5f71\u54cd\uff0c\u800c\u53ea\u662f\u5355\u7eaf\u53cd\u5e94\u4e24\u4e2a\u53d8\u91cf\u6bcf\u5355\u4f4d\u53d8\u5316\u65f6\u7684\u76f8\u4f3c\u7a0b\u5ea6\u3002 \u603b\u7ed3\uff1a \u5bf9\u4e8e\u4e24\u4e2a\u53d8\u91cfX\u3001Y\uff0c \u5f53\u4ed6\u4eec\u7684\u76f8\u5173\u7cfb\u6570\u4e3a1\u65f6\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u65f6\u7684\u6b63\u5411\u76f8\u4f3c\u5ea6\u6700\u5927\u3002 \u5f53\u4ed6\u4eec\u7684\u76f8\u5173\u7cfb\u6570\u4e3a\uff0d1\u65f6\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u7684\u53cd\u5411\u76f8\u4f3c\u5ea6\u6700\u5927\u3002 \u968f\u7740\u4ed6\u4eec\u76f8\u5173\u7cfb\u6570\u51cf\u5c0f\uff0c\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u65f6\u7684\u76f8\u4f3c\u5ea6\u4e5f\u53d8\u5c0f\uff0c\u5f53\u76f8\u5173\u7cfb\u6570\u4e3a0\u65f6\uff0c\u4e24\u4e2a\u53d8\u91cf\u7684\u53d8\u5316\u8fc7\u7a0b\u6ca1\u6709\u4efb\u4f55\u76f8\u4f3c\u5ea6\uff0c\u4e5f\u5373\u4e24\u4e2a\u53d8\u91cf\u65e0\u5173\u3002 \u5f53\u76f8\u5173\u7cfb\u6570\u7ee7\u7eed\u53d8\u5c0f\uff0c\u5c0f\u4e8e0\u65f6\uff0c\u4e24\u4e2a\u53d8\u91cf\u5f00\u59cb\u51fa\u73b0\u53cd\u5411\u7684\u76f8\u4f3c\u5ea6\uff0c\u968f\u7740\u76f8\u5173\u7cfb\u6570\u7ee7\u7eed\u53d8\u5c0f\uff0c\u53cd\u5411\u76f8\u4f3c\u5ea6\u4f1a\u9010\u6e10\u53d8\u5927\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u4f7f\u7528 pandas-datareader\uff1a https://pypi.org/project/pandas-datareader/ https://pydata.github.io/pandas-datareader/) \u5728\u6240\u6709\u4f8b\u5b50\u4e2d\uff0c\u5728\u8ba1\u7b97\u76f8\u5173\u6027\u4e4b\u524d\uff0c\u6570\u636e\u70b9\u5df2\u7ecf\u6309\u6807\u7b7e\u8fdb\u884c\u4e86\u5bf9\u9f50\u3002 \u4e0b\u4f8b\u9700\u8981\u901a\u8fc7pandas-datareader\u5e93\u4eceYahoo! Finance\u4e0a\u83b7\u53d6\u7684\u5305\u542b\u80a1\u4ef7\u548c\u4ea4\u6613\u91cf\u7684DataFrame\u3002 import pandas_datareader.data as web all_data = { ticker: web.get_data_yahoo(ticker) for ticker in ['AAPL', 'IBM', 'MSFT', 'GOOG'] } price = pd.DataFrame( { ticker: data['Adj Close'] for ticker, data in all_data.items() } ) volume = pd.DataFrame( { ticker: data['Volume'] for ticker, data in all_data.items() } ) returns = price.pct_change() print(returns.tail()) # AAPL IBM MSFT GOOG # Date # 2021-08-09 -0.000342 -0.008424 -0.003904 0.007049 # 2021-08-10 -0.003354 0.000920 -0.006555 0.000685 # 2021-08-11 0.001786 0.005305 0.001781 -0.002947 # 2021-08-12 0.020773 0.006614 0.009967 0.005084 # 2021-08-13 0.001410 0.000769 0.010490 0.000119 Series\u7684corr\u65b9\u6cd5\u8ba1\u7b97\u7684\u662f\u4e24\u4e2aSeries\u4e2d\u91cd\u53e0\u7684\u3001\u975eNA\u7684\u3001\u6309\u7d22\u5f15\u5bf9\u9f50\u7684\u503c\u7684\u76f8\u5173\u6027\u3002\u76f8\u5e94\u5730\uff0ccov\u8ba1\u7b97\u7684\u662f\u534f\u65b9\u5dee print(returns['MSFT']) # Date # 2016-08-15 NaN # 2016-08-16 -0.005540 # 2016-08-17 0.002089 # 2016-08-18 0.000695 # 2016-08-19 0.000347 # ... # 2021-08-09 -0.003904 # 2021-08-10 -0.006555 # 2021-08-11 0.001781 # 2021-08-12 0.009967 # 2021-08-13 0.010490 # Name: MSFT, Length: 1259, dtype: float64 # Series\u7684corr\u65b9\u6cd5\u8ba1\u7b97\u7684\u662f\u4e24\u4e2aSeries\u4e2d\u91cd\u53e0\u7684\u3001\u975eNA\u7684\u3001\u6309\u7d22\u5f15\u5bf9\u9f50\u7684\u503c\u7684\u76f8\u5173\u6027\u3002 print(returns['MSFT'].corr(returns['IBM'])) # 0.5175237180581937 # \u7b49\u540c\u5199\u6cd5\uff0cMSFT\u662f\u4e00\u4e2a\u6709\u6548\u7684Python\u5c5e\u6027 print(returns.MSFT.corr(returns.IBM)) # 0.5175237180581937 # Series\u7684cov\u65b9\u6cd5\u8ba1\u7b97\u7684\u662f\u4e24\u4e2aSeries\u4e2d\u503c\u7684\u534f\u65b9\u5dee\u3002 print(returns['MSFT'].cov(returns['IBM'])) # 0.0001452224236764915 DataFrame\u7684corr\u548ccov\u65b9\u6cd5\u4f1a\u5206\u522b\u4ee5DataFrame\u7684\u5f62\u5f0f\u8fd4\u56de\u76f8\u5173\u6027\u548c\u534f\u65b9\u5dee\u77e9\u9635\u3002 print(returns.corr()) # AAPL IBM MSFT GOOG # AAPL 1.000000 0.441111 0.735539 0.661961 # IBM 0.441111 1.000000 0.517524 0.484230 # MSFT 0.735539 0.517524 1.000000 0.775756 # GOOG 0.661961 0.484230 0.775756 1.000000 # \u7ed9corrwith\u65b9\u6cd5\uff0c\u4f20\u5165\u4e00\u4e2aSeries\u65f6\uff0c\u4f1a\u8fd4\u56de\u4e00\u4e2a\u542b\u6709\u4e3a\u6bcf\u5217\u8ba1\u7b97\u76f8\u5173\u6027\u503c\u7684Series print(returns.corrwith(returns['IBM'])) # AAPL 0.441111 # IBM 1.000000 # MSFT 0.517524 # GOOG 0.484230 # dtype: float64 # \u7ed9corrwith\u65b9\u6cd5\uff0c\u4f20\u5165\u4e00\u4e2aDataFrame\u65f6\uff0c\u4f1a\u8ba1\u7b97\u5339\u914d\u5230\u5217\u540d\u7684\u76f8\u5173\u6027\u6570\u503c\u3002\u4e0b\u9762\u662f\u8ba1\u7b97\u4ea4\u6613\u91cf\u767e\u5206\u6bd4\u53d8\u5316\u7684\u76f8\u5173\u6027 print(returns.corrwith(volume)) # AAPL -0.063111 # IBM -0.103721 # MSFT -0.056842 # GOOG -0.119026 # dtype: float64 print(returns.cov()) # AAPL IBM MSFT GOOG # AAPL 0.000361 0.000137 0.000240 0.000211 # IBM 0.000137 0.000268 0.000145 0.000133 # MSFT 0.000240 0.000145 0.000294 0.000224 # GOOG 0.000211 0.000133 0.000224 0.000282","title":"\u76f8\u5173\u6027\u548c\u534f\u65b9\u5dee"},{"location":"python/DataAnalysis/ch02/#_13","text":"obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c']) print(obj) # 0 c # 1 a # 2 d # 3 a # 4 a # 5 a # 6 b # 7 b # 8 c # 9 c # dtype: object \u51fd\u6570 unique \u7ed9\u51faSeries\u4e2d\u7684\u552f\u4e00\u503c\u3002 print(obj.unique()) # ['c' 'a' 'd' 'b'] print(obj.sort_values().unique()) # ['a' 'b' 'c' 'd'] # value_counts\u8ba1\u7b97Series\u5305\u542b\u7684\u503c\u7684\u4e2a\u6570 print(obj.value_counts()) # a 4 # c 3 # b 2 # d 1 # dtype: int64 # \u8fd9\u91ccvalue_counts\u4e0d\u662fSeries\u7684\u65b9\u6cd5\uff0c\u662fpandas\u9876\u5c42\u65b9\u6cd5 print(pd.value_counts(obj.values, sort=True)) # a 4 # c 3 # b 2 # d 1 # dtype: int64 print(obj.isin(['b', 'c'])) # 0 True # 1 False # 2 False # 3 False # 4 False # 5 False # 6 True # 7 True # 8 True # 9 True # dtype: bool # \u5c06\u4e0a\u9762\u7684\u7ed3\u679c\u4f5c\u4e3a\u5217\u8868\u8f93\u5165\u7684\u6761\u4ef6\uff0c\u8f93\u51fa\u4e3aTrue\u7684\u7ed3\u679c print(obj[obj.isin(['b', 'c'])]) # 0 c # 6 b # 7 b # 8 c # 9 c # dtype: object \u53c2\u8003: pandas.Index.get_indexer obj1 = pd.Series(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c']) obj2 = pd.Series(['c', 'a', 'b']) print(pd.Index(obj1)) # Index(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c'], dtype='object') print(pd.Index(obj2)) # Index(['c', 'a', 'b'], dtype='object') # \u8fd9\u91cc0\u5bf9\u5e94obj2\u91cc\u9762\u7684c\u5728job1\u7684\u4f4d\u7f6e\uff0c\u4ee5\u6b64\u7c7b\u63a8\uff0c\u751f\u6210\u65b0\u7684\u7d22\u5f15\u5217\u8868 print(pd.Index(obj2).get_indexer(obj1)) # [ 0 1 -1 1 1 1 2 2 0 0] \u8ba1\u7b97DataFrame\u591a\u4e2a\u76f8\u5173\u5217\u7684\u76f4\u65b9\u56fe\u3002 data = pd.DataFrame( { 'Que1': [1, 3, 4, 3, 4], 'Que2': [2, 3, 1, 2, 3], 'Que3': [1, 5, 2, 4, 4], } ) print(data) # Que1 Que2 Que3 # 0 1 2 1 # 1 3 3 5 # 2 4 1 2 # 3 3 2 4 # 4 4 3 4 result = data.apply(pd.value_counts).fillna(0) # \u4e0b\u9762\u7ed3\u679c\u4e2d\u7684\u884c\u6807\u7b7e\u662f\u6240\u6709\u5217\u4e2d\u51fa\u73b0\u7684\u4e0d\u540c\u503c\uff0c\u6570\u503c\u5219\u662f\u8fd9\u4e9b\u4e0d\u540c\u503c\u5728\u6bcf\u4e2a\u5217\u4e2d\u51fa\u73b0\u7684\u6b21\u6570\uff0c\u4f8b\u5982\uff1a\u6570\u5b575\u53ea\u5728Que3\u91cc\u9762\u51fa\u73b0\u4e86\u4e00\u6b21 print(result) # Que1 Que2 Que3 # 1 1.0 1.0 1.0 # 2 0.0 2.0 1.0 # 3 2.0 2.0 0.0 # 4 2.0 0.0 2.0 # 5 0.0 0.0 1.0","title":"\u552f\u4e00\u503c\u3001\u8ba1\u6570\u548c\u6210\u5458\u5c5e\u6027"},{"location":"python/DataAnalysis/ch03/","text":"\u6570\u636e\u8f7d\u5165\u3001\u5b58\u50a8\u53ca\u6587\u4ef6\u683c\u5f0f \u00b6 \u6587\u672c\u683c\u5f0f\u6570\u636e\u7684\u8bfb\u5199 \u00b6 import numpy as np import pandas as pd import sys import csv import json \u5c06\u8868\u683c\u578b\u6570\u636e\u8bfb\u53d6\u4e3aDataFrame\u5bf9\u8c61\u662fpandas\u7684\u91cd\u8981\u7279\u6027\u3002 \u4e0b\u9762\u662f\u90e8\u5206\u5b9e\u73b0\u6587\u4ef6\u8bfb\u53d6\u529f\u80fd\u7684\u51fd\u6570\uff0cread_csv\u548cread_table\u53ef\u80fd\u662f\u540e\u671f\u6211\u4eec\u4f7f\u7528\u6700\u591a\u7684\u51fd\u6570\u3002 \u8fd9\u4e9b\u51fd\u6570\u7684\u53ef\u9009\u53c2\u6570\u4e3b\u8981\u6709\u4ee5\u4e0b\u51e0\u79cd\u7c7b\u578b\uff1a \u7d22\u5f15\uff1a\u53ef\u4ee5\u5c06\u4e00\u5217\u6216\u591a\u4e2a\u5217\u4f5c\u4e3a\u8fd4\u56de\u7684DataFrame\uff0c\u4ece\u6587\u4ef6\u6216\u7528\u6237\u5904\u83b7\u5f97\u5217\u540d\uff0c\u6216\u8005\u6ca1\u6709\u5217\u540d\u3002 \u7c7b\u578b\u63a8\u65ad\u548c\u6570\u636e\u8f6c\u6362\uff1a\u5305\u62ec\u7528\u6237\u81ea\u5b9a\u4e49\u7684\u503c\u8f6c\u6362\u548c\u81ea\u5b9a\u4e49\u7684\u7f3a\u5931\u503c\u7b26\u53f7\u5217\u8868\u3002 \u65e5\u671f\u65f6\u95f4\u89e3\u6790\uff1a\u5305\u62ec\u7ec4\u5408\u529f\u80fd\uff0c\u4e5f\u5305\u62ec\u5c06\u5206\u6563\u5728\u591a\u4e2a\u5217\u4e0a\u7684\u65e5\u671f\u548c\u65f6\u95f4\u4fe1\u606f\u7ec4\u5408\u6210\u7ed3\u679c\u4e2d\u7684\u5355\u4e2a\u5217\u3002 \u8fed\u4ee3\uff1a\u652f\u6301\u5bf9\u5927\u578b\u6587\u4ef6\u7684\u5206\u5757\u8fed\u4ee3\u3002 \u672a\u6e05\u6d17\u6570\u636e\u95ee\u9898\uff1a\u8df3\u8fc7\u884c\u3001\u9875\u811a\u3001\u6ce8\u91ca\u4ee5\u53ca\u5176\u4ed6\u6b21\u8981\u6570\u636e\uff0c\u6bd4\u5982\u4f7f\u7528\u9017\u53f7\u5206\u9694\u5343\u4f4d\u7684\u6570\u5b57\u3002 file01 = '../examples/ex1.csv' # \u4f7f\u7528read_csv\u5c06\u6587\u4ef6\u8bfb\u5165\u4e00\u4e2aDataFrame df = pd.read_csv(file01) print(df) # 1 2 3 4 hello # 0 5 6 7 8 world # 1 9 10 11 12 foo df = pd.read_csv(file01, header=None) # \u4f7f\u7528pandas\u81ea\u52a8\u5206\u914d\u9ed8\u8ba4\u5217\u540d print(df) # 0 1 2 3 4 # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo df = pd.read_csv(file01, names=['aa', 'bb', 'cc', 'dd', 'message']) # \u81ea\u5df1\u6307\u5b9a\u5217\u540d print(df) # aa bb cc dd ee # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo # \u4f7f\u7528read_table\uff0c\u5e76\u6307\u5b9a\u5206\u9694\u7b26\uff0c\u5c06\u6587\u4ef6\u8bfb\u5165\u4e00\u4e2aDataFrame df = pd.read_table(file01, sep=',') print(df) # a b c d message # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo \u4ece\u591a\u4e2a\u5217\u4e2d\u5f62\u6210\u4e00\u4e2a\u5206\u5c42\u7d22\u5f15 parased = pd.read_csv('../examples/csv_mindex.csv', index_col=['key1', 'key2']) print(parased) # value1 value2 # key1 key2 # one a 1 2 # b 3 4 # c 5 6 # d 7 8 # two a 9 10 # b 11 12 # c 13 14 # d 15 16 \u4e0b\u4f8b\u4e2d\uff0c\u7531\u4e8e\u5217\u540d\u7684\u6570\u91cf\u6bd4\u6570\u636e\u7684\u5217\u6570\u5c11\u4e00\u4e2a\uff0c\u56e0\u6b64read_table\u63a8\u65ad\u7b2c\u4e00\u5217\u5e94\u5f53\u4f5c\u4e3aDataFrame\u7684\u7d22\u5f15\u3002 ex3.txt\u539f\u59cb\u6587\u4ef6\u5185\u5bb9 A B C aaa -0.264438 -1.026059 -0.619500 bbb 0.927272 0.302904 -0.032399 ccc -0.264273 -0.386314 -0.217601 ddd -0.871858 -0.348382 1.100491 result = pd.read_table('../examples/ex3.txt') # \u76f4\u63a5\u8bfb\u53d6 print(result) # A B C # aaa -0.264438 -1.026059 -0.619500 # bbb 0.927272 0.302904 -0.032399 NaN # ccc -0.264273 -0.386314 -0.217601 # ddd -0.871858 -0.348382 1.100491 result = pd.read_table('../examples/ex3.txt', sep='\\s+') # \u5411read_table\u6b63\u5219\u8868\u8fbe\u5f0f\u4e3a\\s+\u6765\u683c\u5f0f\u5316\u6587\u4ef6 print(result) # A B C # aaa -0.264438 -1.026059 -0.619500 # bbb 0.927272 0.302904 -0.032399 # ccc -0.264273 -0.386314 -0.217601 # ddd -0.871858 -0.348382 1.100491 \u4e0b\u4f8b\u4e2dex4.csv\u539f\u59cb\u6587\u4ef6\u5185\u5bb9 # hey! a,b,c,d,message # just wanted to make things more difficult for you # who reads CSV files with computers, anyway? 1,2,3,4,hello 5,6,7,8,world 9,10,11,12,foo result = pd.read_csv('../examples/ex4.csv', skiprows=[0, 2, 3]) # \u4f7f\u7528skiprows\u6765\u8df3\u8fc7\u7b2c\u4e00\u884c\u3001\u7b2c\u4e09\u884c\u548c\u7b2c\u56db\u884c print(result) # a b c d message # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo \u7f3a\u5931\u503c\u5904\u7406 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cpandas\u4f7f\u7528\u4e00\u4e9b\u5e38\u89c1\u7684\u6807\u8bc6\uff0c\u4f8b\u5982 NA \u548c NULL \u4e0b\u4f8b\u4e2dex5.csv\u539f\u59cb\u6587\u4ef6\u5185\u5bb9 something,a,b,c,d,message one,1,2,3,4,NA two,5,6,,8,world three,9,10,11,12,foo result = pd.read_csv('../examples/ex5.csv') print(result) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 two 5 6 NaN 8 world # 2 three 9 10 11.0 12 foo print(pd.isnull(result)) # something a b c d message # 0 False False False False False True # 1 False False False True False False # 2 False False False False False False result = pd.read_csv('../examples/ex5.csv', na_values=['NULL']) print(result) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 two 5 6 NaN 8 world # 2 three 9 10 11.0 12 foo \u5b9a\u4e49\u66ff\u6362\u89c4\u5219 sentinels = { 'message': ['foo', 'NA'], 'something': ['two'] } result = pd.read_csv('../examples/ex5.csv', na_values=sentinels) \u628amessage\u5217\u6240\u6709\u503c\u4e3afoo\u6216NA\u7684\u66ff\u6362\u4e3aNull \u628asomething\u5217\u6240\u6709\u503c\u4e3atwo\u7684\u66ff\u6362\u4e3aNull print(result) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 NaN 5 6 NaN 8 world # 2 three 9 10 11.0 12 NaN \u5206\u5757\u8bfb\u5165\u6587\u672c\u6587\u4ef6 \u00b6 pd.options.display.max_rows = 10 result = pd.read_csv('../examples/ex6.csv') # \u8bfb\u53d6\u5168\u90e8\u8bb0\u5f55 print(result) result = pd.read_csv('../examples/ex6.csv', nrows=5) # \u8bfb\u53d6\u524d5\u884c\u8bb0\u5f55 print(result) # [10000 rows x 5 columns] # one two three four key # 0 0.467976 -0.038649 -0.295344 -1.824726 L # 1 -0.358893 1.404453 0.704965 -0.200638 B # 2 -0.501840 0.659254 -0.421691 -0.057688 G # 3 0.204886 1.074134 1.388361 -0.982404 R # 4 0.354628 -0.133116 0.283763 -0.837063 Q result = pd.read_csv('../examples/ex6.csv', chunksize=1000) # \u5206\u5757\u8bfb\u5165\u6587\u4ef6\uff0c\u6bcf\u57571000\u884c print(result) # \u8fd4\u56de\u7684\u662f\u4e00\u4e2aTextParser\u5bf9\u8c61, \u5141\u8bb8\u4f60\u6839\u636echunksize\u904d\u5386\u6587\u4ef6\u3002 # \u53ef\u4ee5\u904d\u5386 ex6.csv \uff0c\u5e76\u5bf9 key \u5217\u805a\u5408\u83b7\u5f97\u8ba1\u6570\u503c tot = pd.Series([], dtype=float) # \u8fd9\u91cc\u9700\u8981\u663e\u5f0f\u6307\u5b9adtype\uff0c\u540e\u7eedPython\u4f1a\u5c06\u9ed8\u8ba4\u503c\u4ecefloat64\u53d8\u6210object\uff0c\u76ee\u524d\u9ed8\u8ba4\u662ffloat64 for piece in result: tot = tot.add(piece['key'].value_counts(), fill_value=0) tot = tot.sort_values(ascending=False) print(tot[:10]) # E 368.0 # X 364.0 # L 346.0 # O 343.0 # Q 340.0 # M 338.0 # J 337.0 # F 335.0 # K 334.0 # H 330.0 # dtype: float64 \u5c06\u6570\u636e\u5199\u5165\u6587\u672c\u683c\u5f0f \u00b6 data = pd.read_csv('../examples/ex5.csv') print(data) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 two 5 6 NaN 8 world # 2 three 9 10 11.0 12 foo \u4f7f\u7528DataFrame\u7684 to_csv \u65b9\u6cd5\uff0c\u5c06\u6570\u636e\u5bfc\u51fa\u4e3a\u9017\u53f7\u5206\u9694\u7684\u6587\u4ef6 data.to_csv('../examples/out.csv') # \u8f93\u51faout.csv\u7684\u5185\u5bb9 # ,something,a,b,c,d,message # 0,one,1,2,3.0,4, # 1,two,5,6,,8,world # 2,three,9,10,11.0,12,foo \u4f7f\u7528DataFrame\u7684 to_csv \u65b9\u6cd5\uff0c\u5c06\u6570\u636e\u5bfc\u51fa\u4e3a\u5176\u4ed6\u7684\u5206\u9694\u7b26\u7684\u6587\u4ef6 data.to_csv(sys.stdout, sep='|') # |something|a|b|c|d|message # 0|one|1|2|3.0|4| # 1|two|5|6||8|world # 2|three|9|10|11.0|12|foo data.to_csv(sys.stdout, sep=',') # ,something,a,b,c,d,message # 0,one,1,2,3.0,4, # 1,two,5,6,,8,world # 2,three,9,10,11.0,12,foo data.to_csv(sys.stdout, sep=',', na_rep='NULL') # \u8bbe\u5b9a\u7f3a\u5931\u503c\u5728\u8f93\u51fa\u65f6\u4ee5\u7a7a\u5b57\u7b26\u4e32\u51fa\u73b0 # ,something,a,b,c,d,message # 0,one,1,2,3.0,4,NULL # 1,two,5,6,NULL,8,world # 2,three,9,10,11.0,12,foo data.to_csv(sys.stdout, sep=',', na_rep='NULL', index=False, header=False) # \u4e0d\u8f93\u51fa\u884c\u548c\u5217\u7684\u6807\u7b7e\uff08index\uff0cheader\uff09 # one,1,2,3.0,4,NULL # two,5,6,NULL,8,world # three,9,10,11.0,12,foo data.to_csv(sys.stdout, sep=',', na_rep='NULL', index=False, header=False, columns=['a', 'b', 'c']) # \u6309\u7167\u81ea\u5b9a\u7684\u987a\u5e8f\u8f93\u51fa\u5b50\u96c6 # 1,2,3.0 # 5,6,NULL # 9,10,11.0 Series\u4e5f\u6709 to_csv \u65b9\u6cd5 dates = pd.date_range('1/1/2000', periods=7) ts = pd.Series(np.arange(7), index=dates) ts.to_csv('../examples/tseries.csv', header=False) # \u8f93\u51fatseries.csv\u6587\u4ef6\u5185\u5bb9 # 2000-01-01,0 # 2000-01-02,1 # 2000-01-03,2 # 2000-01-04,3 # 2000-01-05,4 # 2000-01-06,5 # 2000-01-07,6 \u4f7f\u7528\u5206\u9694\u683c\u5f0f \u00b6 \u7edd\u5927\u591a\u6570\u7684\u8868\u578b\u6570\u636e\u90fd\u53ef\u4ee5\u4f7f\u7528\u51fd\u6570 pandas.read_table \u4ece\u786c\u76d8\u4e2d\u8bfb\u53d6\u3002 \u7136\u800c\uff0c\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u63a5\u6536\u4e00\u4e2a\u5e26\u6709\u4e00\u884c\u6216\u591a\u884c\u9519\u8bef\u7684\u6587\u4ef6\u5e76\u4e0d\u5c11\u89c1\uff0c read_table \u4e5f\u65e0\u6cd5\u89e3\u51b3\u8fd9\u79cd\u60c5\u51b5\u3002 ex7.csv \u6587\u4ef6\u5185\u5bb9 \"a\",\"b\",\"c\" \"1\",\"2\",\"3\" \"1\",\"2\",\"3\" f = open('../examples/ex7.csv') # \u4f7f\u7528Python\u7684\u5185\u5efacsv\u6a21\u5757 reader = csv.reader(f) # \u5c06\u4efb\u4e00\u6253\u5f00\u7684\u6587\u4ef6\u6216\u6587\u4ef6\u578b\u5bf9\u8c61\u4f20\u7ed9csv.reader for line in reader: # # \u904d\u5386reader\uff0c\u4ea7\u751f\u5143\u7ec4\uff0c\u5143\u7ec4\u7684\u503c\u4e3a\u5220\u9664\u4e86\u5f15\u53f7\u7684\u5b57\u7b26 print(line) f.close() # ['a', 'b', 'c'] # ['1', '2', '3'] # ['1', '2', '3'] with open('../examples/ex7.csv') as f: lines = list(csv.reader(f)) # \u9996\u5148\uff0c\u5c06\u6587\u4ef6\u8bfb\u53d6\u4e3a\u884c\u7684\u5217\u8868 header, values = lines[0], lines[1:] # \u5176\u6b21\uff0c\u5c06\u6570\u636e\u62c6\u5206\u4e3a\u5217\u540d\u884c\u548c\u6570\u636e\u884c data_dict = { h: v for h, v in zip(header, zip(*values)) # \u518d\u7136\u540e\uff0c\u4f7f\u7528\u5b57\u5178\u63a8\u5bfc\u5f0f\u548c\u8868\u8fbe\u5f0fzip(*values)\u751f\u6210\u4e00\u4e2a\u5305\u542b\u6570\u636e\u5217\u7684\u5b57\u5178\uff0c\u5b57\u5178\u4e2d\u884c\u8f6c\u7f6e\u6210\u5217 } print(data_dict) # \u8f93\u51fa\u7ed3\u679c # {'a': ('1', '1'), 'b': ('2', '2'), 'c': ('3', '3')} \u5982\u679c\u9700\u6839\u636e\u4e0d\u540c\u7684\u5206\u9694\u7b26\u3001\u5b57\u7b26\u4e32\u5f15\u7528\u7ea6\u5b9a\u6216\u884c\u7ec8\u6b62\u7b26\u5b9a\u4e49\u4e00\u79cd\u65b0\u7684\u683c\u5f0f\u65f6\uff0c\u53ef\u4ee5: \u65b9\u6cd51\uff1a\u4f7f\u7528csv.Dialect\u5b9a\u4e49\u4e00\u4e2a\u7b80\u5355\u7684\u5b50\u7c7b class my_dialect(csv.Dialect): lineterminator = '\\n' delimiter = ';' # \u8fd9\u91cc\u53ea\u80fd\u662f\u4e00\u4e2a\u5b57\u7b26 quotechar = '\"' quoting = csv.QUOTE_MINIMAL f = open('../examples/ex7.csv') reader = csv.reader(f, dialect=my_dialect) for line in reader: # \u904d\u5386reader\uff0c\u4ea7\u751f\u5143\u7ec4\uff0c\u5143\u7ec4\u7684\u503c\u4e3a\u5220\u9664\u4e86\u5f15\u53f7\u7684\u5b57\u7b26 print(line) f.close() # ['a,\"b\",\"c\"'] # ['1,\"2\",\"3\"'] # ['1,\"2\",\"3\"'] \u65b9\u6cd52\uff1a\u76f4\u63a5\u5c06CSV\u65b9\u8a00\u53c2\u6570(dialect)\u4f20\u5165csv.reader\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 \u6bd4\u8f83\u8be6\u7ec6\u7684 \u4ecb\u7ecd\u65b9\u8a00\u548c\u5206\u9694\u7b26 f = open('../examples/ex7.csv') reader = csv.reader(f, delimiter='|') for line in reader: # \u904d\u5386reader\uff0c\u4ea7\u751f\u5143\u7ec4\uff0c\u5143\u7ec4\u7684\u503c\u4e3a\u5220\u9664\u4e86\u5f15\u53f7\u7684\u5b57\u7b26 print(line) f.close() # ['a,\"b\",\"c\"'] # ['1,\"2\",\"3\"'] # ['1,\"2\",\"3\"'] \u5bf9\u4e8e\u5177\u6709\u66f4\u590d\u6742\u6216\u56fa\u5b9a\u7684\u591a\u5b57\u7b26\u5206\u9694\u7b26\u7684\u6587\u4ef6\uff0c\u5c06\u65e0\u6cd5\u4f7f\u7528csv\u6a21\u5757\u3002 \u5728\u6b64\u7c7b\u60c5\u51b5\u4e0b\uff0c\u5c06\u4f7f\u7528\u5b57\u7b26\u4e32\u7684split\u65b9\u6cd5\u6216\u6b63\u5219\u8868\u8fbe\u5f0f\u65b9\u6cd5re.split\u8fdb\u884c\u884c\u62c6\u5206\u548c\u5176\u4ed6\u6e05\u7406\u5de5\u4f5c\u3002 \u9700\u8981\u624b\u52a8\u5199\u5165\u88ab\u5206\u9694\u7684\u6587\u4ef6\u65f6\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528csv.writer\u3002 \u8fd9\u4e2a\u51fd\u6570\u63a5\u6536\u4e00\u4e2a\u5df2\u7ecf\u6253\u5f00\u7684\u53ef\u5199\u5165\u6587\u4ef6\u5bf9\u8c61\u4ee5\u53ca\u548ccsv.reader\u76f8\u540c\u7684CSV\u65b9\u8a00\u3001\u683c\u5f0f\u9009\u9879. with open('../examples/mydata.csv', 'w') as f: writer = csv.writer(f, dialect=my_dialect) writer.writerow(('1', '2', '3')) writer.writerow(('4', '5', '6')) writer.writerow(('7', '8', '9')) writer.writerow(('10', '11', '12')) # mydata.csv \u6587\u4ef6\u5185\u5bb9 # 1;2;3 # 4;5;6 # 7;8;9 # 10;11;12 JSON\u6570\u636e \u00b6 obj = \"\"\" { \"name\": \"Wes\", \"places_lived\": [\"United States\", \"Spain\", \"Germany\"], \"pet\": null, \"siblings\": [ { \"name\": \"Scott\", \"age\": 30, \"pets\": [\"Zeus\", \"Zuko\"] }, { \"name\": \"Katie\", \"age\": 38, \"pets\": [\"Sixes\", \"Stache\", \"Cisco\"] } ] } \"\"\" \u5c06JSON\u5b57\u7b26\u4e32\u8f6c\u6362\u4e3aPython\u5f62\u5f0f\u65f6\uff0c\u4f7f\u7528json.loads\u65b9\u6cd5 result = json.loads(obj) print(result) # {'name': 'Wes', 'places_lived': ['United States', 'Spain', 'Germany'], 'pet': None, 'siblings': [{'name': 'Scott', 'age': 30, 'pets': ['Zeus', 'Zuko']}, {'name': 'Katie', 'age': 38, 'pets': ['Sixes', 'Stache', 'Cisco']}]} \u53e6\u4e00\u65b9\u9762\uff0cjson.dumps\u53ef\u4ee5\u5c06Python\u5bf9\u8c61\u8f6c\u6362\u56deJSON asjson = json.dumps(result) print(asjson) # {\"name\": \"Wes\", \"places_lived\": [\"United States\", \"Spain\", \"Germany\"], \"pet\": null, \"siblings\": [{\"name\": \"Scott\", \"age\": 30, \"pets\": [\"Zeus\", \"Zuko\"]}, {\"name\": \"Katie\", \"age\": 38, \"pets\": [\"Sixes\", \"Stache\", \"Cisco\"]}]} \u5c06JSON\u5bf9\u8c61\u6216\u5bf9\u8c61\u5217\u8868\u8f6c\u6362\u4e3aDataFrame\u6216\u5176\u4ed6\u6570\u636e\u7ed3\u6784\u3002 \u6bd4\u8f83\u65b9\u4fbf\u7684\u65b9\u5f0f\u662f\u5c06\u5b57\u5178\u6784\u6210\u7684\u5217\u8868\uff08\u4e4b\u524d\u662fJSON\u5bf9\u8c61\uff09\u4f20\u5165DataFrame\u6784\u9020\u51fd\u6570\uff0c\u5e76\u9009\u51fa\u6570\u636e\u5b57\u6bb5\u7684\u5b50\u96c6\u3002 siblings = pd.DataFrame(result['siblings'], columns=['name', 'age']) print(siblings) # name age # 0 Scott 30 # 1 Katie 38 pandas.read_json\u53ef\u4ee5\u81ea\u52a8\u5c06JSON\u6570\u636e\u96c6\u6309\u7167\u6307\u5b9a\u6b21\u5e8f\u8f6c\u6362\u4e3aSeries\u6216DataFrame\u3002 pandas.read_json\u7684\u9ed8\u8ba4\u9009\u9879\u662f\u5047\u8bbeJSON\u6570\u7ec4\u4e2d\u7684\u6bcf\u4e2a\u5bf9\u8c61\u662f\u8868\u91cc\u7684\u4e00\u884c\u3002 \u4f8b\u5982\u8bfb\u53d6 data = pd.read_json('../examples/example_new.json') data = pd.read_json('../examples/example.json') print(data) # a b c # 0 1 2 3 # 1 4 5 6 # 2 7 8 9 print(data.to_json()) # {\"a\":{\"0\":1,\"1\":4,\"2\":7},\"b\":{\"0\":2,\"1\":5,\"2\":8},\"c\":{\"0\":3,\"1\":6,\"2\":9}} print(data.to_json(orient='records')) # [{\"a\":1,\"b\":2,\"c\":3},{\"a\":4,\"b\":5,\"c\":6},{\"a\":7,\"b\":8,\"c\":9}] XML\u548cHTML\uff1a\u7f51\u7edc\u6293\u53d6 \u00b6 pandas\u7684\u5185\u5efa\u51fd\u6570read_html\u53ef\u4ee5\u4f7f\u7528lxml\u548cBeautiful Soup\u7b49\u5e93\u5c06HTML\u4e2d\u7684\u8868\u81ea\u52a8\u89e3\u6790\u4e3aDataFrame\u5bf9\u8c61\u3002 tables = pd.read_html('../examples/fdic_failed_bank_list.html') print(len(tables)) # 1 failures = tables[0] # //*[@id=\"table\"] print(failures.head()) # \u8bfb\u53d6\u524d5\u884c\u8bb0\u5f55 # Bank Name ... Updated Date # 0 Allied Bank ... November 17, 2016 # 1 The Woodbury Banking Company ... November 17, 2016 # 2 First CornerStone Bank ... September 6, 2016 # 3 Trust Company Bank ... September 6, 2016 # 4 North Milwaukee State Bank ... June 16, 2016 # # [5 rows x 7 columns] close_timestamps = pd.to_datetime(failures['Closing Date']) # \u8ba1\u7b97\u6bcf\u5e74\u94f6\u884c\u5012\u95ed\u7684\u6570\u91cf print(close_timestamps.dt.year.value_counts()) # 2010 157 # 2009 140 # 2011 92 # 2012 51 # 2008 25 # ... # 2004 4 # 2001 4 # 2007 3 # 2003 3 # 2000 2 # Name: Closing Date, Length: 15, dtype: int64 \u4e8c\u8fdb\u5236\u683c\u5f0f \u00b6 \u4e0eWeb API\u4ea4\u4e92 \u00b6 \u4e0e\u6570\u636e\u5e93\u4ea4\u4e92 \u00b6","title":"\u6570\u636e\u8f7d\u5165\u3001\u5b58\u50a8\u53ca\u6587\u4ef6\u683c\u5f0f"},{"location":"python/DataAnalysis/ch03/#_1","text":"","title":"\u6570\u636e\u8f7d\u5165\u3001\u5b58\u50a8\u53ca\u6587\u4ef6\u683c\u5f0f"},{"location":"python/DataAnalysis/ch03/#_2","text":"import numpy as np import pandas as pd import sys import csv import json \u5c06\u8868\u683c\u578b\u6570\u636e\u8bfb\u53d6\u4e3aDataFrame\u5bf9\u8c61\u662fpandas\u7684\u91cd\u8981\u7279\u6027\u3002 \u4e0b\u9762\u662f\u90e8\u5206\u5b9e\u73b0\u6587\u4ef6\u8bfb\u53d6\u529f\u80fd\u7684\u51fd\u6570\uff0cread_csv\u548cread_table\u53ef\u80fd\u662f\u540e\u671f\u6211\u4eec\u4f7f\u7528\u6700\u591a\u7684\u51fd\u6570\u3002 \u8fd9\u4e9b\u51fd\u6570\u7684\u53ef\u9009\u53c2\u6570\u4e3b\u8981\u6709\u4ee5\u4e0b\u51e0\u79cd\u7c7b\u578b\uff1a \u7d22\u5f15\uff1a\u53ef\u4ee5\u5c06\u4e00\u5217\u6216\u591a\u4e2a\u5217\u4f5c\u4e3a\u8fd4\u56de\u7684DataFrame\uff0c\u4ece\u6587\u4ef6\u6216\u7528\u6237\u5904\u83b7\u5f97\u5217\u540d\uff0c\u6216\u8005\u6ca1\u6709\u5217\u540d\u3002 \u7c7b\u578b\u63a8\u65ad\u548c\u6570\u636e\u8f6c\u6362\uff1a\u5305\u62ec\u7528\u6237\u81ea\u5b9a\u4e49\u7684\u503c\u8f6c\u6362\u548c\u81ea\u5b9a\u4e49\u7684\u7f3a\u5931\u503c\u7b26\u53f7\u5217\u8868\u3002 \u65e5\u671f\u65f6\u95f4\u89e3\u6790\uff1a\u5305\u62ec\u7ec4\u5408\u529f\u80fd\uff0c\u4e5f\u5305\u62ec\u5c06\u5206\u6563\u5728\u591a\u4e2a\u5217\u4e0a\u7684\u65e5\u671f\u548c\u65f6\u95f4\u4fe1\u606f\u7ec4\u5408\u6210\u7ed3\u679c\u4e2d\u7684\u5355\u4e2a\u5217\u3002 \u8fed\u4ee3\uff1a\u652f\u6301\u5bf9\u5927\u578b\u6587\u4ef6\u7684\u5206\u5757\u8fed\u4ee3\u3002 \u672a\u6e05\u6d17\u6570\u636e\u95ee\u9898\uff1a\u8df3\u8fc7\u884c\u3001\u9875\u811a\u3001\u6ce8\u91ca\u4ee5\u53ca\u5176\u4ed6\u6b21\u8981\u6570\u636e\uff0c\u6bd4\u5982\u4f7f\u7528\u9017\u53f7\u5206\u9694\u5343\u4f4d\u7684\u6570\u5b57\u3002 file01 = '../examples/ex1.csv' # \u4f7f\u7528read_csv\u5c06\u6587\u4ef6\u8bfb\u5165\u4e00\u4e2aDataFrame df = pd.read_csv(file01) print(df) # 1 2 3 4 hello # 0 5 6 7 8 world # 1 9 10 11 12 foo df = pd.read_csv(file01, header=None) # \u4f7f\u7528pandas\u81ea\u52a8\u5206\u914d\u9ed8\u8ba4\u5217\u540d print(df) # 0 1 2 3 4 # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo df = pd.read_csv(file01, names=['aa', 'bb', 'cc', 'dd', 'message']) # \u81ea\u5df1\u6307\u5b9a\u5217\u540d print(df) # aa bb cc dd ee # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo # \u4f7f\u7528read_table\uff0c\u5e76\u6307\u5b9a\u5206\u9694\u7b26\uff0c\u5c06\u6587\u4ef6\u8bfb\u5165\u4e00\u4e2aDataFrame df = pd.read_table(file01, sep=',') print(df) # a b c d message # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo \u4ece\u591a\u4e2a\u5217\u4e2d\u5f62\u6210\u4e00\u4e2a\u5206\u5c42\u7d22\u5f15 parased = pd.read_csv('../examples/csv_mindex.csv', index_col=['key1', 'key2']) print(parased) # value1 value2 # key1 key2 # one a 1 2 # b 3 4 # c 5 6 # d 7 8 # two a 9 10 # b 11 12 # c 13 14 # d 15 16 \u4e0b\u4f8b\u4e2d\uff0c\u7531\u4e8e\u5217\u540d\u7684\u6570\u91cf\u6bd4\u6570\u636e\u7684\u5217\u6570\u5c11\u4e00\u4e2a\uff0c\u56e0\u6b64read_table\u63a8\u65ad\u7b2c\u4e00\u5217\u5e94\u5f53\u4f5c\u4e3aDataFrame\u7684\u7d22\u5f15\u3002 ex3.txt\u539f\u59cb\u6587\u4ef6\u5185\u5bb9 A B C aaa -0.264438 -1.026059 -0.619500 bbb 0.927272 0.302904 -0.032399 ccc -0.264273 -0.386314 -0.217601 ddd -0.871858 -0.348382 1.100491 result = pd.read_table('../examples/ex3.txt') # \u76f4\u63a5\u8bfb\u53d6 print(result) # A B C # aaa -0.264438 -1.026059 -0.619500 # bbb 0.927272 0.302904 -0.032399 NaN # ccc -0.264273 -0.386314 -0.217601 # ddd -0.871858 -0.348382 1.100491 result = pd.read_table('../examples/ex3.txt', sep='\\s+') # \u5411read_table\u6b63\u5219\u8868\u8fbe\u5f0f\u4e3a\\s+\u6765\u683c\u5f0f\u5316\u6587\u4ef6 print(result) # A B C # aaa -0.264438 -1.026059 -0.619500 # bbb 0.927272 0.302904 -0.032399 # ccc -0.264273 -0.386314 -0.217601 # ddd -0.871858 -0.348382 1.100491 \u4e0b\u4f8b\u4e2dex4.csv\u539f\u59cb\u6587\u4ef6\u5185\u5bb9 # hey! a,b,c,d,message # just wanted to make things more difficult for you # who reads CSV files with computers, anyway? 1,2,3,4,hello 5,6,7,8,world 9,10,11,12,foo result = pd.read_csv('../examples/ex4.csv', skiprows=[0, 2, 3]) # \u4f7f\u7528skiprows\u6765\u8df3\u8fc7\u7b2c\u4e00\u884c\u3001\u7b2c\u4e09\u884c\u548c\u7b2c\u56db\u884c print(result) # a b c d message # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo \u7f3a\u5931\u503c\u5904\u7406 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cpandas\u4f7f\u7528\u4e00\u4e9b\u5e38\u89c1\u7684\u6807\u8bc6\uff0c\u4f8b\u5982 NA \u548c NULL \u4e0b\u4f8b\u4e2dex5.csv\u539f\u59cb\u6587\u4ef6\u5185\u5bb9 something,a,b,c,d,message one,1,2,3,4,NA two,5,6,,8,world three,9,10,11,12,foo result = pd.read_csv('../examples/ex5.csv') print(result) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 two 5 6 NaN 8 world # 2 three 9 10 11.0 12 foo print(pd.isnull(result)) # something a b c d message # 0 False False False False False True # 1 False False False True False False # 2 False False False False False False result = pd.read_csv('../examples/ex5.csv', na_values=['NULL']) print(result) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 two 5 6 NaN 8 world # 2 three 9 10 11.0 12 foo \u5b9a\u4e49\u66ff\u6362\u89c4\u5219 sentinels = { 'message': ['foo', 'NA'], 'something': ['two'] } result = pd.read_csv('../examples/ex5.csv', na_values=sentinels) \u628amessage\u5217\u6240\u6709\u503c\u4e3afoo\u6216NA\u7684\u66ff\u6362\u4e3aNull \u628asomething\u5217\u6240\u6709\u503c\u4e3atwo\u7684\u66ff\u6362\u4e3aNull print(result) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 NaN 5 6 NaN 8 world # 2 three 9 10 11.0 12 NaN","title":"\u6587\u672c\u683c\u5f0f\u6570\u636e\u7684\u8bfb\u5199"},{"location":"python/DataAnalysis/ch03/#_3","text":"pd.options.display.max_rows = 10 result = pd.read_csv('../examples/ex6.csv') # \u8bfb\u53d6\u5168\u90e8\u8bb0\u5f55 print(result) result = pd.read_csv('../examples/ex6.csv', nrows=5) # \u8bfb\u53d6\u524d5\u884c\u8bb0\u5f55 print(result) # [10000 rows x 5 columns] # one two three four key # 0 0.467976 -0.038649 -0.295344 -1.824726 L # 1 -0.358893 1.404453 0.704965 -0.200638 B # 2 -0.501840 0.659254 -0.421691 -0.057688 G # 3 0.204886 1.074134 1.388361 -0.982404 R # 4 0.354628 -0.133116 0.283763 -0.837063 Q result = pd.read_csv('../examples/ex6.csv', chunksize=1000) # \u5206\u5757\u8bfb\u5165\u6587\u4ef6\uff0c\u6bcf\u57571000\u884c print(result) # \u8fd4\u56de\u7684\u662f\u4e00\u4e2aTextParser\u5bf9\u8c61, \u5141\u8bb8\u4f60\u6839\u636echunksize\u904d\u5386\u6587\u4ef6\u3002 # \u53ef\u4ee5\u904d\u5386 ex6.csv \uff0c\u5e76\u5bf9 key \u5217\u805a\u5408\u83b7\u5f97\u8ba1\u6570\u503c tot = pd.Series([], dtype=float) # \u8fd9\u91cc\u9700\u8981\u663e\u5f0f\u6307\u5b9adtype\uff0c\u540e\u7eedPython\u4f1a\u5c06\u9ed8\u8ba4\u503c\u4ecefloat64\u53d8\u6210object\uff0c\u76ee\u524d\u9ed8\u8ba4\u662ffloat64 for piece in result: tot = tot.add(piece['key'].value_counts(), fill_value=0) tot = tot.sort_values(ascending=False) print(tot[:10]) # E 368.0 # X 364.0 # L 346.0 # O 343.0 # Q 340.0 # M 338.0 # J 337.0 # F 335.0 # K 334.0 # H 330.0 # dtype: float64","title":"\u5206\u5757\u8bfb\u5165\u6587\u672c\u6587\u4ef6"},{"location":"python/DataAnalysis/ch03/#_4","text":"data = pd.read_csv('../examples/ex5.csv') print(data) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 two 5 6 NaN 8 world # 2 three 9 10 11.0 12 foo \u4f7f\u7528DataFrame\u7684 to_csv \u65b9\u6cd5\uff0c\u5c06\u6570\u636e\u5bfc\u51fa\u4e3a\u9017\u53f7\u5206\u9694\u7684\u6587\u4ef6 data.to_csv('../examples/out.csv') # \u8f93\u51faout.csv\u7684\u5185\u5bb9 # ,something,a,b,c,d,message # 0,one,1,2,3.0,4, # 1,two,5,6,,8,world # 2,three,9,10,11.0,12,foo \u4f7f\u7528DataFrame\u7684 to_csv \u65b9\u6cd5\uff0c\u5c06\u6570\u636e\u5bfc\u51fa\u4e3a\u5176\u4ed6\u7684\u5206\u9694\u7b26\u7684\u6587\u4ef6 data.to_csv(sys.stdout, sep='|') # |something|a|b|c|d|message # 0|one|1|2|3.0|4| # 1|two|5|6||8|world # 2|three|9|10|11.0|12|foo data.to_csv(sys.stdout, sep=',') # ,something,a,b,c,d,message # 0,one,1,2,3.0,4, # 1,two,5,6,,8,world # 2,three,9,10,11.0,12,foo data.to_csv(sys.stdout, sep=',', na_rep='NULL') # \u8bbe\u5b9a\u7f3a\u5931\u503c\u5728\u8f93\u51fa\u65f6\u4ee5\u7a7a\u5b57\u7b26\u4e32\u51fa\u73b0 # ,something,a,b,c,d,message # 0,one,1,2,3.0,4,NULL # 1,two,5,6,NULL,8,world # 2,three,9,10,11.0,12,foo data.to_csv(sys.stdout, sep=',', na_rep='NULL', index=False, header=False) # \u4e0d\u8f93\u51fa\u884c\u548c\u5217\u7684\u6807\u7b7e\uff08index\uff0cheader\uff09 # one,1,2,3.0,4,NULL # two,5,6,NULL,8,world # three,9,10,11.0,12,foo data.to_csv(sys.stdout, sep=',', na_rep='NULL', index=False, header=False, columns=['a', 'b', 'c']) # \u6309\u7167\u81ea\u5b9a\u7684\u987a\u5e8f\u8f93\u51fa\u5b50\u96c6 # 1,2,3.0 # 5,6,NULL # 9,10,11.0 Series\u4e5f\u6709 to_csv \u65b9\u6cd5 dates = pd.date_range('1/1/2000', periods=7) ts = pd.Series(np.arange(7), index=dates) ts.to_csv('../examples/tseries.csv', header=False) # \u8f93\u51fatseries.csv\u6587\u4ef6\u5185\u5bb9 # 2000-01-01,0 # 2000-01-02,1 # 2000-01-03,2 # 2000-01-04,3 # 2000-01-05,4 # 2000-01-06,5 # 2000-01-07,6","title":"\u5c06\u6570\u636e\u5199\u5165\u6587\u672c\u683c\u5f0f"},{"location":"python/DataAnalysis/ch03/#_5","text":"\u7edd\u5927\u591a\u6570\u7684\u8868\u578b\u6570\u636e\u90fd\u53ef\u4ee5\u4f7f\u7528\u51fd\u6570 pandas.read_table \u4ece\u786c\u76d8\u4e2d\u8bfb\u53d6\u3002 \u7136\u800c\uff0c\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u63a5\u6536\u4e00\u4e2a\u5e26\u6709\u4e00\u884c\u6216\u591a\u884c\u9519\u8bef\u7684\u6587\u4ef6\u5e76\u4e0d\u5c11\u89c1\uff0c read_table \u4e5f\u65e0\u6cd5\u89e3\u51b3\u8fd9\u79cd\u60c5\u51b5\u3002 ex7.csv \u6587\u4ef6\u5185\u5bb9 \"a\",\"b\",\"c\" \"1\",\"2\",\"3\" \"1\",\"2\",\"3\" f = open('../examples/ex7.csv') # \u4f7f\u7528Python\u7684\u5185\u5efacsv\u6a21\u5757 reader = csv.reader(f) # \u5c06\u4efb\u4e00\u6253\u5f00\u7684\u6587\u4ef6\u6216\u6587\u4ef6\u578b\u5bf9\u8c61\u4f20\u7ed9csv.reader for line in reader: # # \u904d\u5386reader\uff0c\u4ea7\u751f\u5143\u7ec4\uff0c\u5143\u7ec4\u7684\u503c\u4e3a\u5220\u9664\u4e86\u5f15\u53f7\u7684\u5b57\u7b26 print(line) f.close() # ['a', 'b', 'c'] # ['1', '2', '3'] # ['1', '2', '3'] with open('../examples/ex7.csv') as f: lines = list(csv.reader(f)) # \u9996\u5148\uff0c\u5c06\u6587\u4ef6\u8bfb\u53d6\u4e3a\u884c\u7684\u5217\u8868 header, values = lines[0], lines[1:] # \u5176\u6b21\uff0c\u5c06\u6570\u636e\u62c6\u5206\u4e3a\u5217\u540d\u884c\u548c\u6570\u636e\u884c data_dict = { h: v for h, v in zip(header, zip(*values)) # \u518d\u7136\u540e\uff0c\u4f7f\u7528\u5b57\u5178\u63a8\u5bfc\u5f0f\u548c\u8868\u8fbe\u5f0fzip(*values)\u751f\u6210\u4e00\u4e2a\u5305\u542b\u6570\u636e\u5217\u7684\u5b57\u5178\uff0c\u5b57\u5178\u4e2d\u884c\u8f6c\u7f6e\u6210\u5217 } print(data_dict) # \u8f93\u51fa\u7ed3\u679c # {'a': ('1', '1'), 'b': ('2', '2'), 'c': ('3', '3')} \u5982\u679c\u9700\u6839\u636e\u4e0d\u540c\u7684\u5206\u9694\u7b26\u3001\u5b57\u7b26\u4e32\u5f15\u7528\u7ea6\u5b9a\u6216\u884c\u7ec8\u6b62\u7b26\u5b9a\u4e49\u4e00\u79cd\u65b0\u7684\u683c\u5f0f\u65f6\uff0c\u53ef\u4ee5: \u65b9\u6cd51\uff1a\u4f7f\u7528csv.Dialect\u5b9a\u4e49\u4e00\u4e2a\u7b80\u5355\u7684\u5b50\u7c7b class my_dialect(csv.Dialect): lineterminator = '\\n' delimiter = ';' # \u8fd9\u91cc\u53ea\u80fd\u662f\u4e00\u4e2a\u5b57\u7b26 quotechar = '\"' quoting = csv.QUOTE_MINIMAL f = open('../examples/ex7.csv') reader = csv.reader(f, dialect=my_dialect) for line in reader: # \u904d\u5386reader\uff0c\u4ea7\u751f\u5143\u7ec4\uff0c\u5143\u7ec4\u7684\u503c\u4e3a\u5220\u9664\u4e86\u5f15\u53f7\u7684\u5b57\u7b26 print(line) f.close() # ['a,\"b\",\"c\"'] # ['1,\"2\",\"3\"'] # ['1,\"2\",\"3\"'] \u65b9\u6cd52\uff1a\u76f4\u63a5\u5c06CSV\u65b9\u8a00\u53c2\u6570(dialect)\u4f20\u5165csv.reader\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 \u6bd4\u8f83\u8be6\u7ec6\u7684 \u4ecb\u7ecd\u65b9\u8a00\u548c\u5206\u9694\u7b26 f = open('../examples/ex7.csv') reader = csv.reader(f, delimiter='|') for line in reader: # \u904d\u5386reader\uff0c\u4ea7\u751f\u5143\u7ec4\uff0c\u5143\u7ec4\u7684\u503c\u4e3a\u5220\u9664\u4e86\u5f15\u53f7\u7684\u5b57\u7b26 print(line) f.close() # ['a,\"b\",\"c\"'] # ['1,\"2\",\"3\"'] # ['1,\"2\",\"3\"'] \u5bf9\u4e8e\u5177\u6709\u66f4\u590d\u6742\u6216\u56fa\u5b9a\u7684\u591a\u5b57\u7b26\u5206\u9694\u7b26\u7684\u6587\u4ef6\uff0c\u5c06\u65e0\u6cd5\u4f7f\u7528csv\u6a21\u5757\u3002 \u5728\u6b64\u7c7b\u60c5\u51b5\u4e0b\uff0c\u5c06\u4f7f\u7528\u5b57\u7b26\u4e32\u7684split\u65b9\u6cd5\u6216\u6b63\u5219\u8868\u8fbe\u5f0f\u65b9\u6cd5re.split\u8fdb\u884c\u884c\u62c6\u5206\u548c\u5176\u4ed6\u6e05\u7406\u5de5\u4f5c\u3002 \u9700\u8981\u624b\u52a8\u5199\u5165\u88ab\u5206\u9694\u7684\u6587\u4ef6\u65f6\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528csv.writer\u3002 \u8fd9\u4e2a\u51fd\u6570\u63a5\u6536\u4e00\u4e2a\u5df2\u7ecf\u6253\u5f00\u7684\u53ef\u5199\u5165\u6587\u4ef6\u5bf9\u8c61\u4ee5\u53ca\u548ccsv.reader\u76f8\u540c\u7684CSV\u65b9\u8a00\u3001\u683c\u5f0f\u9009\u9879. with open('../examples/mydata.csv', 'w') as f: writer = csv.writer(f, dialect=my_dialect) writer.writerow(('1', '2', '3')) writer.writerow(('4', '5', '6')) writer.writerow(('7', '8', '9')) writer.writerow(('10', '11', '12')) # mydata.csv \u6587\u4ef6\u5185\u5bb9 # 1;2;3 # 4;5;6 # 7;8;9 # 10;11;12","title":"\u4f7f\u7528\u5206\u9694\u683c\u5f0f"},{"location":"python/DataAnalysis/ch03/#json","text":"obj = \"\"\" { \"name\": \"Wes\", \"places_lived\": [\"United States\", \"Spain\", \"Germany\"], \"pet\": null, \"siblings\": [ { \"name\": \"Scott\", \"age\": 30, \"pets\": [\"Zeus\", \"Zuko\"] }, { \"name\": \"Katie\", \"age\": 38, \"pets\": [\"Sixes\", \"Stache\", \"Cisco\"] } ] } \"\"\" \u5c06JSON\u5b57\u7b26\u4e32\u8f6c\u6362\u4e3aPython\u5f62\u5f0f\u65f6\uff0c\u4f7f\u7528json.loads\u65b9\u6cd5 result = json.loads(obj) print(result) # {'name': 'Wes', 'places_lived': ['United States', 'Spain', 'Germany'], 'pet': None, 'siblings': [{'name': 'Scott', 'age': 30, 'pets': ['Zeus', 'Zuko']}, {'name': 'Katie', 'age': 38, 'pets': ['Sixes', 'Stache', 'Cisco']}]} \u53e6\u4e00\u65b9\u9762\uff0cjson.dumps\u53ef\u4ee5\u5c06Python\u5bf9\u8c61\u8f6c\u6362\u56deJSON asjson = json.dumps(result) print(asjson) # {\"name\": \"Wes\", \"places_lived\": [\"United States\", \"Spain\", \"Germany\"], \"pet\": null, \"siblings\": [{\"name\": \"Scott\", \"age\": 30, \"pets\": [\"Zeus\", \"Zuko\"]}, {\"name\": \"Katie\", \"age\": 38, \"pets\": [\"Sixes\", \"Stache\", \"Cisco\"]}]} \u5c06JSON\u5bf9\u8c61\u6216\u5bf9\u8c61\u5217\u8868\u8f6c\u6362\u4e3aDataFrame\u6216\u5176\u4ed6\u6570\u636e\u7ed3\u6784\u3002 \u6bd4\u8f83\u65b9\u4fbf\u7684\u65b9\u5f0f\u662f\u5c06\u5b57\u5178\u6784\u6210\u7684\u5217\u8868\uff08\u4e4b\u524d\u662fJSON\u5bf9\u8c61\uff09\u4f20\u5165DataFrame\u6784\u9020\u51fd\u6570\uff0c\u5e76\u9009\u51fa\u6570\u636e\u5b57\u6bb5\u7684\u5b50\u96c6\u3002 siblings = pd.DataFrame(result['siblings'], columns=['name', 'age']) print(siblings) # name age # 0 Scott 30 # 1 Katie 38 pandas.read_json\u53ef\u4ee5\u81ea\u52a8\u5c06JSON\u6570\u636e\u96c6\u6309\u7167\u6307\u5b9a\u6b21\u5e8f\u8f6c\u6362\u4e3aSeries\u6216DataFrame\u3002 pandas.read_json\u7684\u9ed8\u8ba4\u9009\u9879\u662f\u5047\u8bbeJSON\u6570\u7ec4\u4e2d\u7684\u6bcf\u4e2a\u5bf9\u8c61\u662f\u8868\u91cc\u7684\u4e00\u884c\u3002 \u4f8b\u5982\u8bfb\u53d6 data = pd.read_json('../examples/example_new.json') data = pd.read_json('../examples/example.json') print(data) # a b c # 0 1 2 3 # 1 4 5 6 # 2 7 8 9 print(data.to_json()) # {\"a\":{\"0\":1,\"1\":4,\"2\":7},\"b\":{\"0\":2,\"1\":5,\"2\":8},\"c\":{\"0\":3,\"1\":6,\"2\":9}} print(data.to_json(orient='records')) # [{\"a\":1,\"b\":2,\"c\":3},{\"a\":4,\"b\":5,\"c\":6},{\"a\":7,\"b\":8,\"c\":9}]","title":"JSON\u6570\u636e"},{"location":"python/DataAnalysis/ch03/#xmlhtml","text":"pandas\u7684\u5185\u5efa\u51fd\u6570read_html\u53ef\u4ee5\u4f7f\u7528lxml\u548cBeautiful Soup\u7b49\u5e93\u5c06HTML\u4e2d\u7684\u8868\u81ea\u52a8\u89e3\u6790\u4e3aDataFrame\u5bf9\u8c61\u3002 tables = pd.read_html('../examples/fdic_failed_bank_list.html') print(len(tables)) # 1 failures = tables[0] # //*[@id=\"table\"] print(failures.head()) # \u8bfb\u53d6\u524d5\u884c\u8bb0\u5f55 # Bank Name ... Updated Date # 0 Allied Bank ... November 17, 2016 # 1 The Woodbury Banking Company ... November 17, 2016 # 2 First CornerStone Bank ... September 6, 2016 # 3 Trust Company Bank ... September 6, 2016 # 4 North Milwaukee State Bank ... June 16, 2016 # # [5 rows x 7 columns] close_timestamps = pd.to_datetime(failures['Closing Date']) # \u8ba1\u7b97\u6bcf\u5e74\u94f6\u884c\u5012\u95ed\u7684\u6570\u91cf print(close_timestamps.dt.year.value_counts()) # 2010 157 # 2009 140 # 2011 92 # 2012 51 # 2008 25 # ... # 2004 4 # 2001 4 # 2007 3 # 2003 3 # 2000 2 # Name: Closing Date, Length: 15, dtype: int64","title":"XML\u548cHTML\uff1a\u7f51\u7edc\u6293\u53d6"},{"location":"python/DataAnalysis/ch03/#_6","text":"","title":"\u4e8c\u8fdb\u5236\u683c\u5f0f"},{"location":"python/DataAnalysis/ch03/#web-api","text":"","title":"\u4e0eWeb API\u4ea4\u4e92"},{"location":"python/DataAnalysis/ch03/#_7","text":"","title":"\u4e0e\u6570\u636e\u5e93\u4ea4\u4e92"},{"location":"python/DataAnalysis/ch04/","text":"\u6570\u636e\u6e05\u6d17\u4e0e\u51c6\u5907 \u00b6 \u5904\u7406\u7f3a\u5931\u503c \u00b6 import pandas as pd import numpy as np from numpy import nan as NA \u5bf9\u4e8e\u6570\u503c\u578b\u6570\u636e\uff0cpandas\u4f7f\u7528\u6d6e\u70b9\u503c NaN \uff08Not a Number\u6765\u8868\u793a\u7f3a\u5931\u503c\uff09\u3002 \u5728pandas\u4e2d\uff0c\u91c7\u7528\u4e86R\u8bed\u8a00\u4e2d\u7684\u7f16\u7a0b\u60ef\u4f8b\uff0c\u5c06\u7f3a\u5931\u503c\u6210\u4e3a NA \uff0c\u610f\u601d\u662fnotavailable\uff08\u4e0d\u53ef\u7528\uff09\u3002 Python\u5185\u5efa\u7684 None \u503c\u5728\u5bf9\u8c61\u6570\u7ec4\u4e2d\u4e5f\u88ab\u5f53\u4f5c NA \u5904\u7406\u3002 NA\u5904\u7406\u65b9\u6cd5\uff1a dropna :\u6839\u636e\u6bcf\u4e2a\u6807\u7b7e\u7684\u503c\u662f\u5426\u662f\u786e\u5b9e\u6570\u636e\u6765\u7b5b\u9009\u8f74\u6807\u7b7e\uff0c\u5e76\u6839\u636e\u5141\u8bb8\u4e22\u5931\u7684\u6570\u636e\u91cf\u6765\u786e\u5b9a\u9608\u503c fillna :\u7528\u67d0\u4e9b\u503c\u586b\u5145\u786e\u5b9e\u7684\u6570\u636e\u6216\u4f7f\u7528\u63d2\u503c\u65b9\u6cd5\uff0c\u5982 ffill \u6216 bfill isnull :\u8fd4\u56de\u8868\u660e\u54ea\u4e9b\u503c\u662f\u7f3a\u5931\u503c\u7684\u5e03\u5c14\u503c notnull :\u662f isnull \u7684\u53cd\u51fd\u6570 string_data = pd.Series(['aardvark', 'artichoke', np.nan, 'avocado']) print(string_data) # 0 aardvark # 1 artichoke # 2 NaN # 3 avocado # dtype: object print(string_data.isnull()) # 0 False # 1 False # 2 True # 3 False # dtype: bool string_data[0] = None print(string_data.isnull()) # 0 True # 1 False # 2 True # 3 False # dtype: bool \u8fc7\u6ee4\u7f3a\u5931\u503c \u00b6 \u5904\u7406Series \u00b6 \u5728Series\u4e0a\u4f7f\u7528 dropna \uff0c\u5b83\u4f1a\u8fd4\u56deSeries\u4e2d\u6240\u6709\u7684\u975e\u7a7a\u6570\u636e\u53ca\u5176\u7d22\u5f15\u503c\u3002 data = pd.Series([1, NA, 3.5, NA, 7]) print(data.dropna()) # 0 1.0 # 2 3.5 # 4 7.0 # dtype: float64 print(data[data.notnull()]) # \u4e0e\u4e0a\u9762\u7b49\u4ef7 # 0 1.0 # 2 3.5 # 4 7.0 # dtype: float64 \u5904\u7406DataFrame \u00b6 data = pd.DataFrame( [[1., 6.5, 3.], [1., NA, NA], [NA, NA, NA], [NA, 6.5, 3.]] ) print(data) # 0 1 2 # 0 1.0 6.5 3.0 # 1 1.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 6.5 3.0 cleaned = data.dropna() # dropna\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u4f1a\u5220\u9664\u5305\u542b\u7f3a\u5931\u503c\u7684\u884c print(cleaned) # 0 1 2 # 0 1.0 6.5 3.0 cleaned = data.dropna(how='all') # \u4f20\u5165how='all\u2019\u65f6\uff0c\u5c06\u5220\u9664\u6240\u6709\u503c\u5747\u4e3aNA\u7684\u884c print(cleaned) # 0 1 2 # 0 1.0 6.5 3.0 # 1 1.0 NaN NaN # 3 NaN 6.5 3.0 data[4] = NA print(data) # 0 1 2 4 # 0 1.0 6.5 3.0 NaN # 1 1.0 NaN NaN NaN # 2 NaN NaN NaN NaN # 3 NaN 6.5 3.0 NaN cleaned = data.dropna(axis=1, how='all') # \u5220\u9664\u5168NA\u7684\u5217 print(cleaned) # 0 1 2 # 0 1.0 6.5 3.0 # 1 1.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 6.5 3.0 df = pd.DataFrame(np.random.randn(7, 3)) print(df) # 0 1 2 # 0 -1.069771 -0.777921 0.181956 # 1 -0.399504 -0.641737 -0.946327 # 2 -1.013920 -0.247588 -0.760146 # 3 1.076946 -1.263203 0.494077 # 4 0.460985 -1.241870 0.283006 # 5 1.168149 1.033752 0.900095 # 6 -1.208514 -1.049546 -0.783680 df.iloc[:4, 1] = NA # \u6807\u7b7e1\uff0c\u524d4\u4e2a\u5143\u7d20 df.iloc[:2, 2] = NA # \u6807\u7b7e2\uff0c\u524d2\u4e2a\u5143\u7d20 print(df) # 0 1 2 # 0 -1.069771 NaN NaN # 1 -0.399504 NaN NaN # 2 -1.013920 NaN -0.760146 # 3 1.076946 NaN 0.494077 # 4 0.460985 -1.241870 0.283006 # 5 1.168149 1.033752 0.900095 # 6 -1.208514 -1.049546 -0.783680 cleaned = df.dropna() print(cleaned) # 0 1 2 # 4 0.033663 0.291886 0.736448 # 5 -0.433380 0.397104 1.252005 # 6 -1.999018 0.303866 1.430109 cleaned = df.dropna(thresh=2) # \u4fdd\u75592\u884c\u542bNA\u7684\u89c2\u5bdf\u503c print(cleaned) # 0 1 2 # 2 -1.413976 NaN 0.222274 # 3 -0.644266 NaN 0.324180 # 4 -0.122160 -2.244880 -0.406562 # 5 -0.140326 0.101133 -0.764048 # 6 -1.809141 0.139091 -0.819175 \u8865\u5168\u7f3a\u5931\u503c \u00b6 fillna \u51fd\u6570\u53c2\u6570\uff1a value\uff1a\u6807\u91cf\u503c\u6216\u5b57\u5178\u578b\u5bf9\u8c61\u7528\u4e8e\u586b\u5145\u7f3a\u5931\u503c method\uff1a\u63d2\u503c\u65b9\u6cd5\uff0c\u5982\u679c\u6ca1\u6709\u5176\u4ed6\u53c2\u6570\uff0c\u9ed8\u8ba4\u662f'ffill' axis\uff1a\u9700\u8981\u586b\u5145\u7684\u8f74\uff0c\u9ed8\u8ba4axis=0 inplace\uff1a\u4fee\u6539\u88ab\u8c03\u7528\u5bf9\u8c61\uff0c\u800c\u4e0d\u662f\u751f\u6210\u4e00\u4e2a\u5907\u4efd limit\uff1a\u7528\u4e8e\u524d\u5411\u6216\u540e\u5411\u586b\u5145\u65f6\u6700\u5927\u7684\u586b\u5145\u8303\u56f4 df = pd.DataFrame(np.random.randn(7, 3)) df.iloc[:4, 1] = NA # \u6807\u7b7e1\uff0c\u524d4\u4e2a\u5143\u7d20 df.iloc[:2, 2] = NA # \u6807\u7b7e2\uff0c\u524d2\u4e2a\u5143\u7d20 print(df) # 0 1 2 # 0 -0.181196 NaN NaN # 1 -1.657668 NaN NaN # 2 -0.053454 NaN 0.391461 # 3 -0.539307 NaN -0.668400 # 4 -0.433439 0.839713 -0.295273 # 5 0.749930 1.661641 -0.495165 # 6 0.591810 1.017372 0.932367 result = df.fillna(0) # \u8c03\u7528fillna\u65f6\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e00\u4e2a\u5e38\u6570\u6765\u66ff\u4ee3\u7f3a\u5931\u503c print(result) # 0 1 2 # 0 -0.430926 0.000000 0.000000 # 1 0.448061 0.000000 0.000000 # 2 -0.059910 0.000000 -1.532646 # 3 -0.315793 0.000000 -0.196546 # 4 -0.546106 0.135108 -0.332309 # 5 1.083075 0.346070 -0.773104 # 6 -0.186511 1.055337 -1.168303 result = df.fillna({1: 0.5, 2: 0}) # \u8c03\u7528fillna\u65f6\u4f7f\u7528\u5b57\u5178\uff0c\u53ef\u4ee5\u4e3a\u4e0d\u540c\u5217\u8bbe\u5b9a\u4e0d\u540c\u7684\u586b\u5145\u503c print(result) # 0 1 2 # 0 -0.794344 0.500000 0.000000 # 1 -0.960917 0.500000 0.000000 # 2 1.494351 0.500000 0.100878 # 3 -0.554765 0.500000 1.118801 # 4 -0.866117 0.523615 1.217478 # 5 -0.706966 -0.681776 0.797690 # 6 -1.456366 1.205518 -0.402432 fillna \u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u65b0\u7684\u5bf9\u8c61\uff0c\u4f46\u4e5f\u53ef\u4ee5\u4fee\u6539\u5df2\u7ecf\u5b58\u5728\u7684\u5bf9\u8c61 _ = df.fillna(0, inplace=True) # inplace=True\u6307\u5b9a\u5728\u5df2\u6709\u5bf9\u8c61\u4e0a\u76f4\u63a5\u4fee\u6539 print(df) # 0 1 2 # 0 -1.176124 0.000000 0.000000 # 1 0.120458 0.000000 0.000000 # 2 -1.206408 0.000000 0.551693 # 3 0.224563 0.000000 1.145156 # 4 -0.557836 0.081135 -0.075282 # 5 2.378837 -0.876145 1.430386 # 6 -0.152662 1.278364 0.479686 df = pd.DataFrame(np.random.randn(6, 3)) df.iloc[2:, 1] = NA # \u6807\u7b7e1\uff0c\u524d4\u4e2a\u5143\u7d20 df.iloc[4:, 2] = NA # \u6807\u7b7e2\uff0c\u524d2\u4e2a\u5143\u7d20 print(df) # 0 1 2 # 0 1.154788 0.033949 -0.122807 # 1 0.258684 -0.580244 1.636514 # 2 1.503756 NaN -1.224203 # 3 0.824049 NaN -0.364345 # 4 -1.247609 NaN NaN # 5 -1.019980 NaN NaN result = df.fillna(method='ffill') # \u5411\u540e\u586b\u5145 print(result) # 0 1 2 # 0 2.082449 0.398874 0.359772 # 1 0.233129 0.385347 1.953533 # 2 0.396555 0.385347 0.592784 # 3 -0.957249 0.385347 0.169815 # 4 0.854452 0.385347 0.169815 # 5 -0.105982 0.385347 0.169815 result = df.fillna(method='ffill', limit=3) # \u6bcf\u5217\u6700\u591a\u586b3\u4e2a print(result) result = df.fillna(df[0].max()) # \u75280\u5217\u7684\u6700\u5927\u503c\u586b\u5145\u6240\u6709\u7684NA print(result) # 0 1 2 # 0 -0.377697 -0.852891 -0.705489 # 1 -0.611759 -0.013237 -0.295764 # 2 -0.389974 1.057881 1.041957 # 3 -0.016845 1.057881 -1.149954 # 4 1.057881 1.057881 1.057881 # 5 -0.463471 1.057881 1.057881 \u6570\u636e\u8f6c\u6362 \u00b6 import pandas as pd import numpy as np from numpy import nan as NA \u5220\u9664\u91cd\u590d\u503c \u00b6 data = pd.DataFrame( { 'k1': ['one', 'two'] * 3 + ['two'], 'k2': [1, 1, 2, 3, 4, 4, 4] } ) print(data) # \u91cd\u590d\u51fa\u73b02\u6b21\u7684\u8bb0\u5f55\uff1atwo 4 # k1 k2 # 0 one 1 # 1 two 1 # 2 one 2 # 3 two 3 # 4 one 4 # 5 two 4 # 6 two 4 DataFrame\u7684 duplicated \u65b9\u6cd5\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u5e03\u5c14\u503cSeries\uff0c\u8fd9\u4e2aSeries\u53cd\u6620\u7684\u662f\u6bcf\u4e00\u884c\u662f\u5426\u5b58\u5728\u91cd\u590d\uff08\u4e0e\u4e4b\u524d\u51fa\u73b0\u8fc7\u7684\u884c\u76f8\u540c\uff09\u60c5\u51b5\uff0c\u9ed8\u8ba4\u662f\u5bf9\u5217\u8fdb\u884c\u64cd\u4f5c\u3002 print(data.duplicated()) # 0 False # 1 False # 2 False # 3 False # 4 False # 5 False # 6 True # dtype: bool drop_duplicates \u8fd4\u56de\u7684\u662fDataFrame\uff0c\u5185\u5bb9\u662f duplicated \u8fd4\u56de\u6570\u7ec4\u4e2d\u4e3a False \u7684\u90e8\u5206\u3002\u9ed8\u8ba4\u662f\u5bf9\u5217\u8fdb\u884c\u64cd\u4f5c\u3002 print(data.drop_duplicates()) # k1 k2 # 0 one 1 # 1 two 1 # 2 one 2 # 3 two 3 # 4 one 4 # 5 two 4 \u53ef\u4ee5\u6307\u5b9a\u6570\u636e\u7684\u4efb\u4f55\u5b50\u96c6\u6765\u68c0\u6d4b\u662f\u5426\u6709\u91cd\u590d\u3002\u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u989d\u5916\u7684\u5217\uff0c\u5e76\u60f3\u57fa\u4e8e\u2019k1\u2019\u5217\u53bb\u9664\u91cd\u590d\u503c\u3002 data['v1'] = range(7) print(data) # k1 k2 v1 # 0 one 1 0 # 1 two 1 1 # 2 one 2 2 # 3 two 3 3 # 4 one 4 4 # 5 two 4 5 # 6 two 4 6 print(data.drop_duplicates(['k1'])) # \u4fdd\u7559\u7b2c\u4e00\u4e2a\u89c2\u6d4b\u5230\u7684one\u548ctwo\uff0c\u5176\u4f59\u4e22\u5f03 # k1 k2 v1 # 0 one 1 0 # 1 two 1 1 duplicated \u548c drop_duplicates \u9ed8\u8ba4\u90fd\u662f\u4fdd\u7559\u7b2c\u4e00\u4e2a\u89c2\u6d4b\u5230\u7684\u503c\u3002\u4f20\u5165\u53c2\u6570keep='last\u2019\u5c06\u4f1a\u8fd4\u56de\u6700\u540e\u4e00\u4e2a\u3002 print(data.drop_duplicates(['k1'], keep='last')) # \u4fdd\u7559\u6700\u540e\u4e00\u4e2a\u89c2\u6d4b\u5230\u7684one\u548ctwo # k1 k2 v1 # 4 one 4 4 # 6 two 4 6 \u4f7f\u7528\u51fd\u6570\u6216\u6620\u5c04\u8fdb\u884c\u6570\u636e\u8f6c\u6362 \u00b6 \u4f7f\u7528 map \u662f\u4e00\u79cd\u53ef\u4ee5\u4fbf\u6377\u6267\u884c\u6309\u5143\u7d20\u8f6c\u6362\u53ca\u5176\u4ed6\u6e05\u6d17\u76f8\u5173\u64cd\u4f5c\u7684\u65b9\u6cd5\u3002 data = pd.DataFrame( { 'food': ['bacon', 'pulled pork', 'bacon', 'Pastrami', 'corned beef', 'Bacon', 'pastrami', 'honey ham', 'nova lox'], 'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6] } ) print(data) # food ounces # 0 bacon 4.0 # 1 pulled pork 3.0 # 2 bacon 12.0 # 3 Pastrami 6.0 # 4 corned beef 7.5 # 5 Bacon 8.0 # 6 pastrami 3.0 # 7 honey ham 5.0 # 8 nova lox 6.0 \u6dfb\u52a0\u4e00\u5217\u7528\u4e8e\u8868\u660e\u6bcf\u79cd\u98df\u7269\u7684\u52a8\u7269\u8089\u7c7b\u578b\u3002 \u5148\u521b\u5efa\u4e00\u4e2a\u98df\u7269\u548c\u8089\u7c7b\u7684\u6620\u5c04\u3002 meat_to_animal = { 'bacon': 'pig', 'pulled pork': 'pig', 'pastrami': 'cow', 'corned beef': 'cow', 'honey ham': 'pig', 'nova lox': 'salmon' } lowercased = data['food'].str.lower() # \u4f7f\u7528Series\u7684str.lower\u65b9\u6cd5\u5c06food\u7684\u6bcf\u4e2a\u503c\u90fd\u8f6c\u6362\u4e3a\u5c0f\u5199 print(lowercased) # 0 bacon # 1 pulled pork # 2 bacon # 3 pastrami # 4 corned beef # 5 bacon # 6 pastrami # 7 honey ham # 8 nova lox # Name: food, dtype: object data['animal'] = lowercased.map(meat_to_animal) print(data) # food ounces animal # 0 bacon 4.0 pig # 1 pulled pork 3.0 pig # 2 bacon 12.0 pig # 3 Pastrami 6.0 cow # 4 corned beef 7.5 cow # 5 Bacon 8.0 pig # 6 pastrami 3.0 cow # 7 honey ham 5.0 pig # 8 nova lox 6.0 salmon \u4e5f\u53ef\u4ee5\u4f20\u5165\u4e00\u4e2a\u51fd\u6570\uff0c\u5b8c\u6210\u4e0a\u9762\u6240\u6709\u529f\u80fd\u3002 data = pd.DataFrame( { 'food': ['bacon', 'pulled pork', 'bacon', 'Pastrami', 'corned beef', 'Bacon', 'pastrami', 'honey ham', 'nova lox'], 'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6] } ) result = data['food'].map(lambda x: meat_to_animal[x.lower()]) print(result) # 0 pig # 1 pig # 2 pig # 3 cow # 4 cow # 5 pig # 6 cow # 7 pig # 8 salmon # Name: food, dtype: object \u66ff\u4ee3\u503c \u00b6 \u4f7f\u7528 fillna \u586b\u5145\u7f3a\u5931\u503c\u662f\u901a\u7528\u503c\u66ff\u6362\u7684\u7279\u6b8a\u6848\u4f8b\u3002 map \u53ef\u4ee5\u7528\u6765\u4fee\u6539\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u7684\u5b50\u96c6\u7684\u503c\uff0c\u4f46\u662f replace \u63d0\u4f9b\u4e86\u66f4\u4e3a\u7b80\u5355\u7075\u6d3b\u7684\u5b9e\u73b0\u3002 data.replace \u65b9\u6cd5\u4e0e data.str.replace \u65b9\u6cd5\u662f\u4e0d\u540c\u7684\uff0c data.str.replace \u662f\u5bf9\u5b57\u7b26\u4e32\u8fdb\u884c\u6309\u5143\u7d20\u66ff\u4ee3\u7684\u3002 \u4e0b\u9762\u7684Series\uff0c -999 \u53ef\u80fd\u662f\u7f3a\u5931\u503c\u7684\u6807\u8bc6\u3002\u5982\u679c\u8981\u4f7f\u7528 NA \u6765\u66ff\u4ee3\u8fd9\u4e9b\u503c\uff0c\u53ef\u4ee5\u4f7f\u7528 replace \u65b9\u6cd5\u751f\u6210\u65b0\u7684Series\uff08\u9664\u975e\u4f20\u5165\u4e86 inplace=True \uff09 data = pd.Series([1., -999., 2., -999., -1000., 3.]) print(data) # 0 1.0 # 1 -999.0 # 2 2.0 # 3 -999.0 # 4 -1000.0 # 5 3.0 # dtype: float64 result = data.replace(-999, np.nan) print(result) # 0 1.0 # 1 NaN # 2 2.0 # 3 NaN # 4 -1000.0 # 5 3.0 # dtype: float64 \u8981\u5c06\u4e0d\u540c\u7684\u503c\u66ff\u6362\u4e3a\u4e0d\u540c\u7684\u503c\uff0c\u53ef\u4ee5\u4f20\u5165\u66ff\u4ee3\u503c\u7684\u5217\u8868 result = data.replace([-999, -1000], [np.nan, 0]) print(result) # 0 1.0 # 1 NaN # 2 2.0 # 3 NaN # 4 0.0 # 5 3.0 # dtype: float64 \u4e5f\u53ef\u4ee5\u4f20\u5165\u66ff\u4ee3\u503c\u7684\u5b57\u5178 result = data.replace({-999: np.nan, -1000: 0}) print(result) # 0 1.0 # 1 NaN # 2 2.0 # 3 NaN # 4 0.0 # 5 3.0 # dtype: float64 \u91cd\u547d\u540d\u8f74\u7d22\u5f15 \u00b6 \u548cSeries\u4e2d\u503c\u66ff\u6362\u7c7b\u4f3c\uff0c\u53ef\u4ee5\u901a\u8fc7\u51fd\u6570\u6216\u6620\u5c04\u5bf9\u8f74\u6807\u7b7e\u8fdb\u884c\u7c7b\u4f3c\u7684\u8f6c\u6362\uff0c\u751f\u6210\u65b0\u7684\u4e14\u5e26\u6709\u4e0d\u540c\u6807\u7b7e\u7684\u5bf9\u8c61\u3002 data = pd.DataFrame( np.arange(12).reshape((3, 4)), index=['Ohio', 'Colorado', 'New York'], columns=['one', 'two', 'three', 'four'] ) print(data) # one two three four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # New York 8 9 10 11 \u4e0eSeries\u7c7b\u4f3c\uff0c\u8f74\u7d22\u5f15\u4e5f\u6709\u4e00\u4e2a map \u65b9\u6cd5\u3002 transform = lambda x: x[:4].upper() # \u622a\u53d6index\u7684\u524d\u56db\u4f4d\u5e76\u8f6c\u5316\u4e3a\u5927\u5199\u683c\u5f0f result = data.index.map(transform) print(result) # Index(['OHIO', 'COLO', 'NEW '], dtype='object') \u8d4b\u503c\u7ed9 index \uff0c\u4fee\u6539DataFrame\u3002 data.index = data.index.map(transform) print(data) # one two three four # OHIO 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 \u521b\u5efa\u6570\u636e\u96c6\u8f6c\u6362\u540e\u7684\u7248\u672c\uff0c\u5e76\u4e14\u4e0d\u4fee\u6539\u539f\u6709\u7684\u6570\u636e\u96c6\uff0c\u4e00\u4e2a\u6709\u7528\u7684\u65b9\u6cd5\u662f rename \u3002 result = data.rename(index=str.title, columns=str.upper) print(result) # ONE TWO THREE FOUR # Ohio 0 1 2 3 # Colo 4 5 6 7 # New 8 9 10 11 print(data) # \u539f\u6709\u7684\u6570\u636e\u96c6\u672a\u88ab\u4fee\u6539 # one two three four # OHIO 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 rename \u53ef\u4ee5\u7ed3\u5408\u5b57\u5178\u578b\u5bf9\u8c61\u4f7f\u7528\uff0c\u4e3a\u8f74\u6807\u7b7e\u7684\u5b50\u96c6\u63d0\u4f9b\u65b0\u7684\u503c\u3002 result = data.rename(index={'OHIO': 'INDIANA'}, columns={'three': 'peekaboo'}) print(result) # one two peekaboo four # INDIANA 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 \u5982\u679c\u8981\u4fee\u6539\u539f\u6709\u7684\u6570\u636e\u96c6\uff0c\u4f20\u5165 inplace=True \u3002 data.rename(index={'OHIO': 'INDIANA'}, columns={'three': 'peekaboo'}, inplace=True) print(data) # one two peekaboo four # INDIANA 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 \u79bb\u6563\u5316\u548c\u5206\u7bb1 \u00b6 \u8fde\u7eed\u503c\u7ecf\u5e38\u9700\u8981\u79bb\u6563\u5316\uff0c\u6216\u8005\u5206\u79bb\u6210\u201d\u7bb1\u5b50\u201c\u8fdb\u884c\u5206\u6790\u3002 \u5047\u8bbe\u6709\u4e00\u7ec4\u4eba\u7fa4\u7684\u6570\u636e\uff0c\u60f3\u5c06\u4ed6\u4eec\u8fdb\u884c\u5206\u7ec4\uff0c\u653e\u5165\u79bb\u6563\u7684\u5e74\u9f84\u6846\u4e2d\u3002 ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32] \u5c06\u8fd9\u4e9b\u5e74\u9f84\u5206\u4e3a18\uff5e25\u300126\uff5e35\u300136\uff5e60\u4ee5\u53ca61\u53ca\u4ee5\u4e0a\u7b49\u82e5\u5e72\u7ec4\uff0c\u4f7f\u7528pandas\u4e2d\u7684 cut \u3002 bins = [18, 25, 35, 60, 100] cats = pd.cut(ages, bins) print(cats) # [(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]] # Length: 12 # Categories (4, interval[int64, right]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]] pandas\u8fd4\u56de\u7684\u5bf9\u8c61\u662f\u4e00\u4e2a\u7279\u6b8a\u7684 Categorical \u5bf9\u8c61\u3002 \u4f60\u770b\u5230\u7684\u8f93\u51fa\u63cf\u8ff0\u4e86\u7531 pandas.cut \u8ba1\u7b97\u51fa\u7684\u7bb1\u3002 \u4f60\u53ef\u4ee5\u5c06\u5b83\u5f53\u4f5c\u4e00\u4e2a\u8868\u793a\u7bb1\u540d\u7684\u5b57\u7b26\u4e32\u6570\u7ec4\uff1b\u5b83\u5728\u5185\u90e8\u5305\u542b\u4e00\u4e2a categories \uff08\u7c7b\u522b\uff09\u6570\u7ec4\uff0c\u5b83\u6307\u5b9a\u4e86\u4e0d\u540c\u7684\u7c7b\u522b\u540d\u79f0\u4ee5\u53ca codes \u5c5e\u6027\u4e2d\u7684 ages \uff08\u5e74\u9f84\uff09\u6570\u636e\u6807\u7b7e\u3002 print(cats.categories) # \u56db\u4e2a\u533a\u95f4\u7ec4 # IntervalIndex([(18, 25], (25, 35], (35, 60], (60, 100]], dtype='interval[int64, right]') print(cats.codes) # 61\u5c81\u843d\u5728\u7b2c3\u7ec4\uff08\u7ec4\u7f16\u53f7\u4ece0\u5f00\u59cb\uff09 # [0 0 0 1 0 0 2 1 3 2 2 1] \u6ce8\u610f\uff0c pd.value_counts(cats) \u662f\u5bf9 pandas.cut \u7684\u7ed3\u679c\u4e2d\u7684\u7bb1\u6570\u91cf\u7684\u8ba1\u6570\u3002 result = pd.value_counts(cats) print(result) # (18, 25] 5 # (25, 35] 3 # (35, 60] 3 # (60, 100] 1 # dtype: int64 \u4e0e\u533a\u95f4\u7684\u6570\u5b66\u7b26\u53f7\u4e00\u81f4\uff0c\u5c0f\u62ec\u53f7\u8868\u793a\u8fb9\u662f\u5f00\u653e\u7684\uff0c\u4e2d\u62ec\u53f7\u8868\u793a\u5b83\u662f\u5c01\u95ed\u7684\uff08\u5305\u62ec\u8fb9\uff09\u3002\u53ef\u4ee5\u901a\u8fc7\u4f20\u9012 right=False \u6765\u6539\u53d8\u54ea\u4e00\u8fb9\u662f\u5c01\u95ed\u7684\u3002\u9ed8\u8ba4 right=True \u3002 result = pd.cut(ages, [18, 26, 36, 61, 100], right=False) print(result) # [[18, 26), [18, 26), [18, 26), [26, 36), [18, 26), ..., [26, 36), [61, 100), [36, 61), [36, 61), [26, 36)] # Length: 12 # Categories (4, interval[int64, left]): [[18, 26) < [26, 36) < [36, 61) < [61, 100)] \u901a\u8fc7\u5411 labels \u9009\u9879\u4f20\u9012\u4e00\u4e2a\u5217\u8868\u6216\u6570\u7ec4\u6765\u4f20\u5165\u81ea\u5b9a\u4e49\u7684\u7bb1\u540d\u3002 group_name = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior'] result = pd.cut(ages, bins, labels=group_name) print(result) # ['Youth', 'Youth', 'Youth', 'YoungAdult', 'Youth', ..., 'YoungAdult', 'Senior', 'MiddleAged', 'MiddleAged', 'YoungAdult'] # Length: 12 # Categories (4, object): ['Youth' < 'YoungAdult' < 'MiddleAged' < 'Senior'] result = pd.value_counts(pd.cut(ages, bins, labels=group_name)) # \u6807\u7b7e\u8f93\u51fa print(result) # Youth 5 # YoungAdult 3 # MiddleAged 3 # Senior 1 # dtype: int64 result = pd.value_counts(pd.cut(ages, bins)) # \u533a\u95f4\u8f93\u51fa print(result) # (18, 25] 5 # (25, 35] 3 # (35, 60] 3 # (60, 100] 1 # dtype: int64 \u5982\u679c\u4f20\u7ed9 cut \u6574\u6570\u4e2a\u7684\u7bb1\u6765\u4ee3\u66ff\u663e\u5f0f\u7684\u7bb1\u8fb9\uff0cpandas\u5c06\u6839\u636e\u6570\u636e\u4e2d\u7684\u6700\u5c0f\u503c\u548c\u6700\u5927\u503c\u8ba1\u7b97\u51fa\u7b49\u957f\u7684\u7bb1\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u8003\u8651\u4e00\u4e9b\u5747\u5300\u5206\u5e03\u7684\u6570\u636e\u88ab\u5207\u6210\u56db\u4efd\u7684\u60c5\u51b5\u3002 data = np.random.rand(20) result = pd.cut(data, 4, precision=2) # precision=2\u7684\u9009\u9879\u5c06\u5341\u8fdb\u5236\u7cbe\u5ea6\u9650\u5236\u5728\u4e24\u4f4d\u3002 print(result) # [(0.44, 0.66], (0.0063, 0.23], (0.23, 0.44], (0.0063, 0.23], (0.23, 0.44], ..., (0.23, 0.44], (0.0063, 0.23], (0.23, 0.44], (0.66, 0.88], (0.23, 0.44]] # Length: 20 # Categories (4, interval[float64, right]): [(0.0063, 0.23] < (0.23, 0.44] < (0.44, 0.66] < (0.66, 0.88]] qcut \u662f\u4e00\u4e2a\u4e0e\u5206\u7bb1\u5bc6\u5207\u76f8\u5173\u7684\u51fd\u6570\uff0c\u5b83\u57fa\u4e8e\u6837\u672c\u5206\u4f4d\u6570\u8fdb\u884c\u5206\u7bb1\u3002 \u53d6\u51b3\u4e8e\u6570\u636e\u7684\u5206\u5e03\uff0c\u4f7f\u7528 cut \u901a\u5e38\u4e0d\u4f1a\u4f7f\u6bcf\u4e2a\u7bb1\u5177\u6709\u76f8\u540c\u6570\u636e\u91cf\u7684\u6570\u636e\u70b9\u3002 \u7531\u4e8eqcut\u4f7f\u7528\u6837\u672c\u7684\u5206\u4f4d\u6570\uff0c\u4f60\u53ef\u4ee5\u901a\u8fc7qcut\u83b7\u5f97\u7b49\u957f\u7684\u7bb1\u3002 data = np.random.randn(1000) # \u6b63\u6001\u5206\u5e03 cats = pd.qcut(data, 4) # \u5207\u62104\u4efd print(cats) # [(-0.00329, 0.644], (-0.00329, 0.644], (-0.659, -0.00329], (-0.659, -0.00329], (0.644, 3.468], ..., (0.644, 3.468], (-3.9619999999999997, -0.659], (-3.9619999999999997, -0.659], (-0.00329, 0.644], (-0.00329, 0.644]] # Length: 1000 # Categories (4, interval[float64, right]): [(-3.9619999999999997, -0.659] < (-0.659, -0.00329] < (-0.00329, 0.644] < (0.644, 3.468]] result = pd.value_counts(cats) print(result) # (-3.9619999999999997, -0.659] 250 # (-0.659, -0.00329] 250 # (-0.00329, 0.644] 250 # (0.644, 3.468] 250 # dtype: int64 \u4e0e cut \u7c7b\u4f3c\uff0c\u53ef\u4ee5\u4f20\u5165\u81ea\u5b9a\u4e49\u7684\u5206\u4f4d\u6570\uff080\u548c1\u4e4b\u95f4\u7684\u6570\u636e\uff0c\u5305\u62ec\u8fb9\uff09\u3002 result = pd.qcut(data, [0, 0.1, 0.5, 0.9, 1.]) print(result) # [(-0.00329, 1.234], (-0.00329, 1.234], (-1.321, -0.00329], (-1.321, -0.00329], (-0.00329, 1.234], ..., (-0.00329, 1.234], (-1.321, -0.00329], (-1.321, -0.00329], (-0.00329, 1.234], (-0.00329, 1.234]] # Length: 1000 # Categories (4, interval[float64, right]): [(-3.9619999999999997, -1.321] < (-1.321, -0.00329] < (-0.00329, 1.234] < (1.234, 3.468]] \u68c0\u6d4b\u548c\u8fc7\u6ee4\u5f02\u5e38\u503c \u00b6 \u8fc7\u6ee4\u6216\u8f6c\u6362\u5f02\u5e38\u503c\u5728\u5f88\u5927\u7a0b\u5ea6\u4e0a\u662f\u5e94\u7528\u6570\u7ec4\u64cd\u4f5c\u7684\u4e8b\u60c5\u3002 \u8003\u8651\u4e00\u4e2a\u5177\u6709\u6b63\u6001\u5206\u5e03\u6570\u636e\u7684DataFrame\u3002 data = pd.DataFrame(np.random.randn(1000, 4)) print(data.describe()) # 0 1 2 3 # count 1000.000000 1000.000000 1000.000000 1000.000000 # mean 0.008124 -0.008050 -0.013403 -0.008261 # std 0.979236 0.992982 0.998819 1.038760 # min -3.231914 -3.441270 -3.345210 -4.320565 # 25% -0.634801 -0.599852 -0.656481 -0.677611 # 50% -0.033252 0.000060 -0.040634 -0.015463 # 75% 0.649340 0.644312 0.678101 0.683849 # max 3.292099 2.758754 2.911447 3.371729 \u627e\u51fa\u4e00\u5217\u4e2d\u7edd\u5bf9\u503c\u5927\u4e8e\u4e09\u7684\u503c\u3002 col = data[2] result = col[np.abs(col) > 3] print(result) # 519 -3.035355 # 536 -3.345210 # Name: 2, dtype: float64 \u9009\u51fa\u6240\u6709\u503c\u5927\u4e8e3\u6216\u5c0f\u4e8e-3\u7684\u884c\uff0c\u53ef\u4ee5\u5bf9\u5e03\u5c14\u503cDataFrame\u4f7f\u7528 any \u65b9\u6cd5\u3002 result = data[(np.abs(data) > 3).any(1)] print(result) # 0 1 2 3 # 116 -0.080907 -3.441270 -0.163263 0.392800 # 139 -1.294440 1.828397 1.178897 -3.469466 # 241 -0.486292 0.150443 0.264172 -3.013440 # 295 3.292099 -0.339284 0.732829 -0.475202 # 355 0.307577 -3.053322 0.967497 0.896363 # 359 3.264981 -1.172096 0.207622 -0.281803 # 519 -0.448987 1.623843 -3.035355 -0.436833 # 533 -1.022616 -0.212597 1.030969 3.371729 # 536 1.067598 -1.306839 -3.345210 0.620834 # 541 -0.952760 -2.157970 -0.403199 -4.320565 # 690 0.006821 -3.104117 0.484881 -0.132613 # 750 -3.231914 1.017712 0.070430 0.631447 # 771 -3.007622 0.257960 -0.118179 -1.283365 # 976 1.684760 -0.003295 -0.249843 3.169371 \u6839\u636e\u8fd9\u4e9b\u6807\u51c6\u6765\u8bbe\u7f6e\u6765\u9650\u5b9a\u503c\uff0c\u4e0b\u9762\u4ee3\u7801\u9650\u5236\u4e86-3\u52303\u4e4b\u95f4\u7684\u6570\u503c\u3002 \u8bed\u53e5 np.sign(data) \u6839\u636e\u6570\u636e\u4e2d\u7684\u503c\u7684\u6b63\u8d1f\u5206\u522b\u751f\u62101\u548c-1\u7684\u6570\u503c\u3002 result = data[(np.abs(data) > 3)] = np.sign(data) * 3 print(result.describe()) # 0 1 2 3 # count 1000.000000 1000.000000 1000.000000 1000.000000 # mean -0.036000 0.000000 -0.084000 -0.048000 # std 3.001285 3.001501 3.000324 3.001117 # min -3.000000 -3.000000 -3.000000 -3.000000 # 25% -3.000000 -3.000000 -3.000000 -3.000000 # 50% -3.000000 0.000000 -3.000000 -3.000000 # 75% 3.000000 3.000000 3.000000 3.000000 # max 3.000000 3.000000 3.000000 3.000000 print(result.head()) # 0 1 2 3 # 0 -3.0 3.0 -3.0 -3.0 # 1 -3.0 -3.0 -3.0 -3.0 # 2 3.0 3.0 -3.0 3.0 # 3 3.0 -3.0 3.0 -3.0 # 4 3.0 -3.0 -3.0 -3.0 \u7f6e\u6362\u548c\u968f\u673a\u62bd\u6837 \u00b6 \u4f7f\u7528 numpy.random.permutation \u5bf9DataFrame\u4e2d\u7684Series\u6216\u884c\u8fdb\u884c\u7f6e\u6362\uff08\u968f\u673a\u91cd\u6392\u5e8f\uff09\u3002 \u5728\u8c03\u7528 permutation \u65f6\u6839\u636e\u4f60\u60f3\u8981\u7684\u8f74\u957f\u5ea6\u53ef\u4ee5\u4ea7\u751f\u4e00\u4e2a\u8868\u793a\u65b0\u987a\u5e8f\u7684\u6574\u6570\u6570\u7ec4\u3002 df = pd.DataFrame(np.arange(5 * 4).reshape((5, 4))) sampler = np.random.permutation(5) print(sampler) # \u8fd4\u56dearray # [1 4 3 0 2] print(df) # 0 1 2 3 # 0 0 1 2 3 # 1 4 5 6 7 # 2 8 9 10 11 # 3 12 13 14 15 # 4 16 17 18 19 \u4e0a\u9762\u8fd4\u56de\u7684 sampler \u6574\u6570\u6570\u7ec4 [1 4 3 0 2] \u7528\u5728\u57fa\u4e8e iloc \u7684\u7d22\u5f15\u6216\u7b49\u4ef7\u7684 take \u51fd\u6570\u4e2d\uff0c\u91cd\u65b0\u6392\u5217\u884c\u987a\u5e8f\u3002 print(df.take(sampler)) # 0 1 2 3 # 1 4 5 6 7 # 4 16 17 18 19 # 3 12 13 14 15 # 0 0 1 2 3 # 2 8 9 10 11 \u9009\u51fa\u4e00\u4e2a\u4e0d\u542b\u6709\u66ff\u4ee3\u503c\u7684\u968f\u673a\u5b50\u96c6\uff0c\u53ef\u4ee5\u4f7f\u7528Series\u548cDataFrame\u7684 sample \u65b9\u6cd5\u3002 result = df.sample(n=3) print(result) # 0 1 2 3 # 0 0 1 2 3 # 2 8 9 10 11 # 1 4 5 6 7 \u8981\u751f\u6210\u4e00\u4e2a\u5e26\u6709\u66ff\u4ee3\u503c\u7684\u6837\u672c\uff08\u5141\u8bb8\u6709\u91cd\u590d\u9009\u62e9\uff09\uff0c\u5c06 replace=True \u4f20\u5165 sample \u65b9\u6cd5\u3002 choice = pd.Series([5, 7, -1, 6, 4]) draws = choice.sample(n=10, replace=True) print(choice) # 0 5 # 1 7 # 2 -1 # 3 6 # 4 4 # dtype: int64 print(draws) # 4 4 # 0 5 # 0 5 # 3 6 # 4 4 # 0 5 # 1 7 # 3 6 # 2 -1 # 0 5 # dtype: int64 \u8ba1\u7b97\u6307\u6807/\u865a\u62df\u53d8\u91cf \u00b6 \u5c06\u5206\u7c7b\u53d8\u91cf\u8f6c\u6362\u4e3a\u201c\u865a\u62df\u201d\u6216\u201c\u6307\u6807\u201d\u77e9\u9635\u662f\u53e6\u4e00\u79cd\u7528\u4e8e\u7edf\u8ba1\u5efa\u6a21\u6216\u673a\u5668\u5b66\u4e60\u7684\u8f6c\u6362\u64cd\u4f5c\u3002 \u5982\u679cDataFrame\u4e2d\u7684\u4e00\u5217\u6709 k \u4e2a\u4e0d\u540c\u7684\u503c\uff0c\u5219\u53ef\u4ee5\u884d\u751f\u4e00\u4e2a k \u5217\u7684\u503c\u4e3a 1 \u548c 0 \u7684\u77e9\u9635\u6216DataFrame\u3002 pandas\u6709\u4e00\u4e2aget_dummies\u51fd\u6570\u7528\u4e8e\u5b9e\u73b0\u8be5\u529f\u80fd\u3002 df = pd.DataFrame( { 'key': ['b', 'b', 'a', 'c', 'a', 'b'], 'data1': range(6) } ) print(df) # key data1 # 0 b 0 # 1 b 1 # 2 a 2 # 3 c 3 # 4 a 4 # 5 b 5 \u5728\u6307\u6807DataFrame\u7684\u5217\u4e0a\u52a0\u5165\u524d\u7f00\uff0c\u7136\u540e\u4e0e\u5176\u4ed6\u6570\u636e\u5408\u5e76\u3002\u5728 get_dummies \u65b9\u6cd5\u4e2d\u6709\u4e00\u4e2a\u524d\u7f00\u53c2\u6570\u7528\u4e8e\u5b9e\u73b0\u8be5\u529f\u80fd\u3002 \u901a\u8fc7 get_dummies \u65b9\u6cd5\uff0c\u628a\u4e0a\u9762 df \u6570\u636e\u6309\u7167 key \u8fdb\u884c\u4e86\u5206\u7ec4\uff0c\u5e76\u901a\u8fc7\u4e0d\u540c\u5217\u6765\u5c55\u73b0\u5206\u7ec4\u540e\u7684\u5bf9\u5e94\u5173\u7cfb\u3002\u4f8b\u5982\uff0c key \u5217\u7684 a \uff0c\u5bf9\u5e94\u503c 2 \u548c 4 \u3002 dummies = pd.get_dummies(df['key'], prefix='key') print(dummies) # key_a key_b key_c # 0 0 1 0 # 1 0 1 0 # 2 1 0 0 # 3 0 0 1 # 4 1 0 0 # 5 0 1 0 df_with_dummy = df[['data1']].join(dummies) print(df_with_dummy) # data1 key_a key_b key_c # 0 0 0 1 0 # 1 1 0 1 0 # 2 2 1 0 0 # 3 3 0 0 1 # 4 4 1 0 0 # 5 5 0 1 0 \u66f4\u4e3a\u590d\u6742\u7684\u60c5\u51b5\uff0cDataFrame\u4e2d\u7684\u4e00\u884c\u5c5e\u4e8e\u591a\u4e2a\u7c7b\u522b\u3002 \u4ee5MovieLens\u76841M\u6570\u636e\u96c6\u4e3a\u4f8b\u3002\u589e\u52a0\u53c2\u6570 encoding='unicode_escape' \u907f\u514d\u51fa\u73b0\u4e0b\u9762\u7684\u9519\u8bef\uff1a UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 3114: invalid continuation byte \u589e\u52a0\u53c2\u6570 engine='python' \u907f\u514d\u51fa\u73b0\u4e0b\u9762\u7684\u9519\u8bef\uff1a ParserWarning: Falling back to the 'python' engine because the 'c' engine does not support regex separators (separators > 1 char and different from '\\s+' are interpreted as regex); you can avoid this warning by specifying engine='python'. mnames = ['movie_id', 'title', 'genres'] movies = pd.read_table( '../datasets/movielens/movies.dat', sep='::', header=None, names=mnames, encoding='unicode_escape', engine='python' ) print(movies[:10]) # movie_id title genres # 0 1 Toy Story (1995) Animation|Children's|Comedy # 1 2 Jumanji (1995) Adventure|Children's|Fantasy # 2 3 Grumpier Old Men (1995) Comedy|Romance # 3 4 Waiting to Exhale (1995) Comedy|Drama # 4 5 Father of the Bride Part II (1995) Comedy # 5 6 Heat (1995) Action|Crime|Thriller # 6 7 Sabrina (1995) Comedy|Romance # 7 8 Tom and Huck (1995) Adventure|Children's # 8 9 Sudden Death (1995) Action # 9 10 GoldenEye (1995) Action|Adventure|Thriller \u4e3a\u6bcf\u4e2a\u7535\u5f71\u6d41\u6d3e\u6dfb\u52a0\u6307\u6807\u53d8\u91cf\u9700\u8981\u8fdb\u884c\u4e00\u4e9b\u6570\u636e\u5904\u7406\u3002 \u9996\u5148\uff0c\u6211\u4eec\u4ece\u6570\u636e\u96c6\u4e2d\u63d0\u53d6\u51fa\u6240\u6709\u4e0d\u540c\u7684\u6d41\u6d3e\u7684\u5217\u8868\u3002 all_genres = [] for x in movies.genres: all_genres.extend(x.split('|')) genres = pd.unique(all_genres) print(genres) # ['Animation' \"Children's\" 'Comedy' 'Adventure' 'Fantasy' 'Romance' 'Drama' # 'Action' 'Crime' 'Thriller' 'Horror' 'Sci-Fi' 'Documentary' 'War' # 'Musical' 'Mystery' 'Film-Noir' 'Western'] \u4f7f\u7528\u51680\u7684DataFrame\u662f\u6784\u5efa\u6307\u6807DataFrame\u7684\u4e00\u79cd\u65b9\u5f0f\u3002 zero_matrix = np.zeros((len(movies), len(genres))) dummies = pd.DataFrame(zero_matrix, columns=genres) print(zero_matrix) # [[0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.] # ... # [0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.]] print(dummies.head(n=10)) # Animation Children's Comedy ... Mystery Film-Noir Western # 0 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 1 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 2 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 3 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 4 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 5 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 6 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 7 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 8 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 9 0.0 0.0 0.0 ... 0.0 0.0 0.0 # # [10 rows x 18 columns] \u904d\u5386\u6bcf\u4e00\u90e8\u7535\u5f71\uff0c\u5c06 dummies \u6bcf\u4e00\u884c\u7684\u6761\u76ee\u8bbe\u7f6e\u4e3a 1 \u3002\u4f7f\u7528 dummies.columns \u6765\u8ba1\u7b97\u6bcf\u4e00\u4e2a\u6d41\u6d3e\u7684\u5217\u6307\u6807\u3002 gen = movies.genres[0] print(gen.split('|')) # ['Animation', \"Children's\", 'Comedy'] result = dummies.columns.get_indexer(gen.split('|')) print(result) # [0 1 2] \u4f7f\u7528 .loc \u6839\u636e\u8fd9\u4e9b\u6307\u6807\u6765\u8bbe\u7f6e\u503c\u3002 for i, gen in enumerate(movies.genres): indices = dummies.columns.get_indexer(gen.split('|')) dummies.iloc[i, indices] = 1 \u5c06\u7ed3\u679c\u4e0e movies \u8fdb\u884c\u5408\u5e76\u3002 movies_windic = movies.join(dummies.add_prefix('Genre_')) print(movies_windic.iloc[0]) # movie_id 1 # title Toy Story (1995) # genres Animation|Children's|Comedy # Genre_Animation 1.0 # Genre_Children's 1.0 # Genre_Comedy 1.0 # Genre_Adventure 0.0 # Genre_Fantasy 0.0 # Genre_Romance 0.0 # Genre_Drama 0.0 # Genre_Action 0.0 # Genre_Crime 0.0 # Genre_Thriller 0.0 # Genre_Horror 0.0 # Genre_Sci-Fi 0.0 # Genre_Documentary 0.0 # Genre_War 0.0 # Genre_Musical 0.0 # Genre_Mystery 0.0 # Genre_Film-Noir 0.0 # Genre_Western 0.0 # Name: 0, dtype: object \u5bf9\u4e8e\u66f4\u5927\u7684\u6570\u636e\uff0c\u4e0a\u9762\u8fd9\u79cd\u4f7f\u7528\u591a\u6210\u5458\u6784\u5efa\u6307\u6807\u53d8\u91cf\u5e76\u4e0d\u662f\u7279\u522b\u5feb\u901f\u3002 \u66f4\u597d\u7684\u65b9\u6cd5\u662f\u5199\u4e00\u4e2a\u76f4\u63a5\u5c06\u6570\u636e\u5199\u4e3aNumPy\u6570\u7ec4\u7684\u5e95\u5c42\u51fd\u6570\uff0c\u7136\u540e\u5c06\u7ed3\u679c\u5c01\u88c5\u8fdbDataFrame\u3002 \u5c06 get_dummies \u4e0e cut \u7b49\u79bb\u6563\u5316\u51fd\u6570\u7ed3\u5408\u4f7f\u7528\u662f\u7edf\u8ba1\u5e94\u7528\u7684\u4e00\u4e2a\u6709\u7528\u65b9\u6cd5\u3002 np.random.seed(12345) # \u4f7f\u7528numpy.random.seed\u6765\u8bbe\u7f6e\u968f\u673a\u79cd\u5b50\u4ee5\u786e\u4fdd\u793a\u4f8b\u7684\u786e\u5b9a\u6027 values = np.random.rand(10) print(values) # [0.92961609 0.31637555 0.18391881 0.20456028 0.56772503 0.5955447 # 0.96451452 0.6531771 0.74890664 0.65356987] bins = [0, 0.2, 0.4, 0.6, 0.8, 1] result = pd.get_dummies(pd.cut(values, bins)) print(result) # (0.0, 0.2] (0.2, 0.4] (0.4, 0.6] (0.6, 0.8] (0.8, 1.0] # 0 0 0 0 0 1 # 1 0 1 0 0 0 # 2 1 0 0 0 0 # 3 0 1 0 0 0 # 4 0 0 1 0 0 # 5 0 0 1 0 0 # 6 0 0 0 0 1 # 7 0 0 0 1 0 # 8 0 0 0 1 0 # 9 0 0 0 1 0 \u5b57\u7b26\u4e32\u64cd\u4f5c \u00b6 import re pandas\u5141\u8bb8\u5c06\u5b57\u7b26\u4e32\u548c\u6b63\u5219\u8868\u8fbe\u5f0f\u7b80\u6d01\u5730\u5e94\u7528\u5230\u6574\u4e2a\u6570\u636e\u6570\u7ec4\u4e0a\uff0c\u6b64\u5916\u8fd8\u80fd\u5904\u7406\u6570\u636e\u7f3a\u5931\u3002 \u5b57\u7b26\u4e32\u5bf9\u8c61\u65b9\u6cd5 \u00b6 \u5b57\u4e32\u62c6\u5206\u5408\u5e76\u65b9\u6cd5\u3002\u5728\u5f88\u591a\u5b57\u7b26\u4e32\u5904\u7406\u548c\u811a\u672c\u5e94\u7528\u4e2d\uff0c\u5185\u5efa\u7684\u5b57\u7b26\u4e32\u65b9\u6cd5\u662f\u8db3\u591f\u7684\u3002 \u4f8b\u5982\uff0c\u4e00\u4e2a\u9017\u53f7\u5206\u9694\u7684\u5b57\u7b26\u4e32\u53ef\u4ee5\u4f7f\u7528split\u65b9\u6cd5\u62c6\u5206\u6210\u591a\u5757\u3002 import numpy as np import pandas as pd val = 'a, b, guido' result = val.split(',') print(result) # ['a', ' b', ' guido'] count \uff1a\u8fd4\u56de\u5b50\u5b57\u7b26\u4e32\u5728\u5b57\u7b26\u4e32\u4e2d\u7684\u975e\u91cd\u53e0\u51fa\u73b0\u6b21\u6570\u3002 result = val.count(',') print(result) # 2 endswith \uff1a\u5982\u679c\u5b57\u7b26\u4e32\u4ee5\u540e\u7f00\u7ed3\u5c3e\u5219\u8fd4\u56de True \u3002 startswith \uff1a\u5982\u679c\u5b57\u7b26\u4e32\u4ee5\u540e\u7f00\u7ed3\u5c3e\u5219\u8fd4\u56de True \u3002 result = val.endswith('b') print(result) # False result = val.endswith('o') print(result) # True result = val.startswith('a') print(result) # True split \u5e38\u548c strip \u4e00\u8d77\u4f7f\u7528\uff0c\u7528\u4e8e\u6e05\u9664\u7a7a\u683c\uff08\u5305\u62ec\u6362\u884c\uff09\u3002 split \uff1a\u4f7f\u7528\u5206\u9694\u7b26\u8bb2\u5b57\u7b26\u4e32\u62c6\u5206\u6210\u5b50\u5b57\u7b26\u4e32\u7684\u5217\u8868\u3002 strip \uff0c rstrip \uff0c lstrip \uff1a\u4fee\u526a\u7a7a\u767d\uff0c\u5305\u62ec\u6362\u884c\u7b26\uff1b\u76f8\u5f53\u4e8e\u5bf9\u6bcf\u4e2a\u5143\u7d20\u8fdb\u884c x.strip() (\u4ee5\u53ca rstrip \uff0c lstrip )\u3002 pieces = [x.strip() for x in val.split(',')] print(pieces) # ['a', 'b', 'guido'] \u8fd9\u4e9b\u5b50\u5b57\u7b26\u4e32\u53ef\u4ee5\u4f7f\u7528\u52a0\u6cd5\u4e0e\u4e24\u4e2a\u5192\u53f7\u5206\u9694\u7b26\u8fde\u63a5\u5728\u4e00\u8d77\u3002 first, second, third = pieces result = first + '::' + second + '::' + third print(result) # a::b::guido \u4f46\u662f\u8fd9\u5e76\u4e0d\u662f\u4e00\u4e2a\u5b9e\u7528\u7684\u901a\u7528\u65b9\u6cd5\u3002 \u5728\u5b57\u7b26\u4e32 ': :' \u7684 join \u65b9\u6cd5\u4e2d\u4f20\u5165\u4e00\u4e2a\u5217\u8868\u6216\u5143\u7ec4\u662f\u4e00\u79cd\u66f4\u5feb\u4e14\u66f4\u52a0Pythonic\uff08Python\u98ce\u683c\u5316\uff09\u7684\u65b9\u6cd5\u3002 join : \u4f7f\u7528\u5b57\u7b26\u4e32\u5ea7\u4f4d\u95f4\u9694\u7b26\uff0c\u7528\u4e8e\u7c98\u5408\u5176\u4ed6\u5b57\u7b26\u4e32\u7684\u5e8f\u5217\u3002 result = '::'.join(pieces) print(result) # a::b::guido \u5b9a\u4f4d\u5b50\u5b57\u7b26\u4e32\u7684\u65b9\u6cd5\u3002 \u4f7f\u7528Python\u7684 in \u5173\u952e\u5b57\u662f\u68c0\u6d4b\u5b50\u5b57\u7b26\u4e32\u7684\u6700\u4f73\u65b9\u6cd5\uff0c\u5c3d\u7ba1 index \u548c find \u4e5f\u80fd\u5b9e\u73b0\u540c\u6837\u7684\u529f\u80fd\u3002 result = 'guido' in val print(result) # True index \uff1a\u5982\u679c\u5728\u5b57\u7b26\u4e32\u4e2d\u627e\u5230\uff0c\u5219\u8fd4\u56de\u5b50\u5b57\u7b26\u4e32\u4e2d\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u627e\u4e0d\u5230\u5219\u89e6\u53d1\u4e00\u4e2a ValueError \u3002 find \uff1a\u8fd4\u56de\u5b57\u7b26\u4e32\u4e2d\u7b2c\u4e00\u4e2a\u51fa\u73b0\u5b50\u5b57\u7b26\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u4f4d\u7f6e\uff0c\u7c7b\u4f3c index \uff0c\u5982\u679c\u6ca1\u6709\u627e\u5230\uff0c\u5219\u8fd4\u56de -1 \u3002 rfind \uff1a\u8fd4\u56de\u5b57\u7b26\u4e32\u4e2d\u5b50\u5b57\u7b26\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u65f6\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u627e\u5230\uff0c\u5219\u8fd4\u56de -1 \u3002 result = val.index(',') print(result) # 1 result = val.find(',') print(result) # 1 # result = val.index(':') print(result) # ValueError: substring not found result = val.find(':') print(result) # -1 result = val.rfind(',') print(result) # 4 replace \u5c06\u7528\u4e00\u79cd\u6a21\u5f0f\u66ff\u4ee3\u53e6\u4e00\u79cd\u6a21\u5f0f\u3002\u5b83\u4e5f\u7528\u4e8e\u4f20\u5165\u7a7a\u5b57\u7b26\u4e32\u6765\u5220\u9664\u67d0\u4e2a\u6a21\u5f0f\u3002 result = val.replace(',', '::') print(result) # a:: b:: guido result = val.replace(', ', '') print(result) # abguido result = val.replace(',', '') print(result) # a b guido lower \uff1a\u5c06\u5927\u5199\u5b57\u6bcd\u8f6c\u6362\u4e3a\u5c0f\u5199\u5b57\u6bcd\u3002 upper \uff1a\u5c06\u5c0f\u5199\u5b57\u6bcd\u8f6c\u6362\u4e3a\u5927\u5199\u5b57\u6bcd\u3002 uppers = val.upper() print(uppers) # A, B, GUIDO casefold \uff1a\u548c lower \u7c7b\u4f3c\uff0c\u5c06\u5b57\u7b26\u4e32\u4e2d\u7684\u5143\u7d20\u53d8\u6210\u5c0f\u5199\uff0c lower \u51fd\u6570\u53ea\u652f\u6301 ascill \u8868\u4e2d\u7684\u5b57\u7b26\uff0c casefold \u652f\u6301\u5f88\u591a\u4e0d\u540c\u79cd\u7c7b\u7684\u8bed\u8a00\u3002 str1 = \"Jan Wei\u03b2@cN\u4e0a\u6d77\" result = str1.casefold() print(result) # jan wei\u03b2@cn\u4e0a\u6d77 result = str1.lower() print(result) # jan wei\u03b2@cn\u4e0a\u6d77 ljust \uff0c rjust \uff1a\u5de6\u5bf9\u9f50\u6216\u8005\u53f3\u5bf9\u9f50\uff1b\u7528\u7a7a\u683c\u6216\u8005\u5176\u5b83\u4e00\u4e9b\u5b57\u7b26\u586b\u5145\u5b57\u7b26\u4e32\u7684\u76f8\u53cd\u4fa7\uff0c\u4ee5\u8fd4\u56de\u5177\u6709\u6700\u5c0f\u5bbd\u5ea6\u7684\u5b57\u7b26\u4e32 str1 = 'https://docs.python.org/3/' str2 = 'https://packagehub.suse.com/package-categories/python/' print(str1.ljust(60, '*')) print(str2.ljust(60, '*')) # https://docs.python.org/3/********************************** # https://packagehub.suse.com/package-categories/python/****** print(str1.rjust(60, '*')) print(str2.rjust(60, '*')) # **********************************https://docs.python.org/3/ # ******https://packagehub.suse.com/package-categories/python/ print(str1.rjust(60)) print(str2.rjust(60)) \u6b63\u5219\u8868\u8fbe\u5f0f \u00b6 Python\u5185\u5efa\u7684 re \u6a21\u5757\u662f\u7528\u4e8e\u5c06\u6b63\u5219\u8868\u8fbe\u5f0f\u5e94\u7528\u5230\u5b57\u7b26\u4e32\u4e0a\u7684\u5e93\u3002 re \u6a21\u5757\u4e3b\u8981\u6709\u4e09\u4e2a\u4e3b\u9898\uff1a\u6a21\u5f0f\u5339\u914d\u3001\u66ff\u4ee3\u3001\u62c6\u5206\u3002 \u770b\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\uff1a\u5047\u8bbe\u6211\u4eec\u60f3\u5c06\u542b\u6709\u591a\u79cd\u7a7a\u767d\u5b57\u7b26\uff08\u5236\u8868\u7b26\u3001\u7a7a\u683c\u3001\u6362\u884c\u7b26\uff09\u7684\u5b57\u7b26\u4e32\u62c6\u5206\u5f00\u3002 \u63cf\u8ff0\u4e00\u4e2a\u6216\u591a\u4e2a\u7a7a\u767d\u5b57\u7b26\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u662f \\s+ \u3002 \u5f53\u8c03\u7528 re.split('\\s+', text) \uff0c\u6b63\u5219\u8868\u8fbe\u5f0f\u9996\u5148\u4f1a\u88ab\u7f16\u8bd1\uff0c\u7136\u540e\u6b63\u5219\u8868\u8fbe\u5f0f\u7684 split \u65b9\u6cd5\u5728\u4f20\u5165\u6587\u672c\u4e0a\u88ab\u8c03\u7528\u3002 text = \"foo bar\\t baz \\tqux\" result = re.split('\\s+', text) print(result) # ['foo', 'bar', 'baz', 'qux'] \u53ef\u4ee5\u4f7f\u7528 re.compile \u81ea\u884c\u7f16\u8bd1\uff0c\u5f62\u6210\u4e00\u4e2a\u53ef\u590d\u7528\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u5bf9\u8c61\u3002 regex = re.compile('\\s+') result = regex.split(text) print(result) # ['foo', 'bar', 'baz', 'qux'] \u5982\u679c\u60f3\u83b7\u5f97\u7684\u662f\u4e00\u4e2a\u6240\u6709\u5339\u914d\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u6a21\u5f0f\u7684\u5217\u8868\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 findall \u65b9\u6cd5\u3002 result = regex.findall(text) print(result) # [' ', '\\t ', ' \\t'] \u4e3a\u4e86\u5728\u6b63\u5219\u8868\u8fbe\u5f0f\u4e2d\u907f\u514d\u8f6c\u4e49\u7b26 \\ \u7684\u5f71\u54cd\uff0c\u53ef\u4ee5\u4f7f\u7528\u539f\u751f\u5b57\u7b26\u4e32\u8bed\u6cd5\uff0c\u6bd4\u5982 r'C:\\x' \u6216\u8005\u7528\u7b49\u4ef7\u7684 'C:\\\\x'\\ \u3002 \u5982\u679c\u9700\u8981\u5c06\u76f8\u540c\u7684\u8868\u8fbe\u5f0f\u5e94\u7528\u5230\u591a\u4e2a\u5b57\u7b26\u4e32\u4e0a\uff0c\u63a8\u8350\u4f7f\u7528 re.compile \u521b\u5efa\u4e00\u4e2a\u6b63\u5219\u8868\u8fbe\u5f0f\u5bf9\u8c61\uff0c\u8fd9\u6837\u505a\u6709\u5229\u4e8e\u8282\u7ea6CPU\u5468\u671f\u3002 match \u548c search \u4e0e findall \u76f8\u5173\u6027\u5f88\u5927\u3002 findall \u8fd4\u56de\u7684\u662f\u5b57\u7b26\u4e32\u4e2d\u6240\u6709\u7684\u5339\u914d\u9879\uff0c\u800c search \u8fd4\u56de\u7684\u4ec5\u4ec5\u662f\u7b2c\u4e00\u4e2a\u5339\u914d\u9879\u3002 match \u66f4\u4e3a\u4e25\u683c\uff0c\u5b83\u53ea\u5728\u5b57\u7b26\u4e32\u7684\u8d77\u59cb\u4f4d\u7f6e\u8fdb\u884c\u5339\u914d\u3002 text = \"\"\"Dave dave@google.com Steve steve@gmail.com Rob rob@gmail.com Ryan ryan@yahoo.com \"\"\" pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}' regex = re.compile(pattern, flags=re.IGNORECASE) # flags=re.IGNORECASE \u4f7f\u6b63\u5219\u8868\u8fbe\u5f0f\u4e0d\u533a\u5206\u5927\u5c0f\u5199 m = regex.findall(text) # findall\u4f1a\u751f\u6210\u4e00\u4e2a\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u7684\u5217\u8868 print(m) # ['dave@google.com', 'steve@gmail.com', 'rob@gmail.com', 'ryan@yahoo.com'] search \u8fd4\u56de\u7684\u662f\u6587\u672c\u4e2d\u7b2c\u4e00\u4e2a\u5339\u914d\u5230\u7684\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u3002 \u5bf9\u4e8e\u524d\u9762\u63d0\u5230\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\uff0c\u5339\u914d\u5bf9\u8c61\u53ea\u80fd\u544a\u8bc9\u6211\u4eec\u6a21\u5f0f\u5728\u5b57\u7b26\u4e32\u4e2d\u8d77\u59cb\u548c\u7ed3\u675f\u7684\u4f4d\u7f6e\u3002 m = regex.search(text) print(m) # print(text[m.start():m.end()]) # dave@google.com regex.match \u53ea\u5728\u6a21\u5f0f\u51fa\u73b0\u4e8e\u5b57\u7b26\u4e32\u8d77\u59cb\u4f4d\u7f6e\u65f6\u8fdb\u884c\u5339\u914d\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u5230\uff0c\u8fd4\u56de None \u3002 m = regex.match(text) print(m) # None m = regex.match('rob@gmail.com') print(m) # print(m.group()) # rob@gmail.com print(m.groups()) # () regex.sub \u4f1a\u8fd4\u56de\u4e00\u4e2a\u65b0\u7684\u5b57\u7b26\u4e32\uff0c\u539f\u5b57\u7b26\u4e32\u4e2d\u7684\u6a21\u5f0f\u4f1a\u88ab\u4e00\u4e2a\u65b0\u7684\u5b57\u7b26\u4e32\u66ff\u4ee3\u3002 m = regex.sub('REDACTED', text) print(m) # Dave REDACTED # Steve REDACTED # Rob REDACTED # Ryan REDACTED \u67e5\u627e\u7535\u5b50\u90ae\u4ef6\u5730\u5740\uff0c\u5e76\u5c06\u6bcf\u4e2a\u5730\u5740\u5206\u4e3a\u4e09\u4e2a\u90e8\u5206\uff1a\u7528\u6237\u540d\uff0c\u57df\u540d\u548c\u57df\u540d\u540e\u7f00\u3002\u8981\u5b9e\u73b0\u8fd9\u4e00\u70b9\uff0c\u53ef\u4ee5\u7528\u62ec\u53f7\u5c06 pattern \u5305\u8d77\u6765\u3002 \u4fee\u6539\u540e\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u4ea7\u751f\u7684\u5339\u914d\u5bf9\u8c61\u7684 groups \u65b9\u6cd5\uff0c\u8fd4\u56de\u7684\u662f\u6a21\u5f0f\u7ec4\u4ef6\u7684\u5143\u7ec4\u3002 text = \"\"\"Dave dave@google.com Steve steve@gmail.com Rob rob@gmail.com Ryan ryan@yahoo.com \"\"\" pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\\.([A-Z]{2,4})' regex = re.compile(pattern, flags=re.IGNORECASE) m = regex.findall(text) # \u5f53pattern\u53ef\u4ee5\u5206\u7ec4\u65f6\uff0cfindall\u8fd4\u56de\u7684\u662f\u5305\u542b\u5143\u7ec4\u7684\u5217\u8868 print(m) # [('dave', 'google', 'com'), ('steve', 'gmail', 'com'), ('rob', 'gmail', 'com'), ('ryan', 'yahoo', 'com')] m = regex.search(text) print(m) # print(text[m.start():m.end()]) # dave@google.com m = regex.match('rob@gmail.com') print(m) # print(m.group()) # rob@gmail.com print(m.groups()) # ('rob', 'gmail', 'com') m = regex.sub('REDACTED', text) print(m) # Dave REDACTED # Steve REDACTED # Rob REDACTED # Ryan REDACTED m = regex.sub(r'Username: \\1, Domain: \\2, Suffix: \\3', text) print(m) # Dave Username: dave, Domain: google, Suffix: com # Steve Username: steve, Domain: gmail, Suffix: com # Rob Username: rob, Domain: gmail, Suffix: com # Ryan Username: ryan, Domain: yahoo, Suffix: com pandas\u4e2d\u7684\u5411\u91cf\u5316\u5b57\u7b26\u4e32\u51fd\u6570 \u00b6 \u6e05\u7406\u6742\u4e71\u7684\u6570\u636e\u96c6\u7528\u4e8e\u5206\u6790\u901a\u5e38\u9700\u8981\u5927\u91cf\u7684\u5b57\u7b26\u4e32\u5904\u7406\u548c\u6b63\u5219\u5316\u3002 data = { 'Dave': 'dave@gmail.com', 'Steve': 'steve@gmail.com', 'Rob': 'rob@gmail.com', 'Wes': np.nan } data = pd.Series(data) print(data) # Dave dave@gmail.com # Steve steve@gmail.com # Rob rob@gmail.com # Wes NaN # dtype: object print(data.isnull()) # Dave False # Steve False # Rob False # Wes True # dtype: bool \u53ef\u4ee5\u4f7f\u7528 data.map \u5c06\u5b57\u7b26\u4e32\u548c\u6709\u6548\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u65b9\u6cd5\uff08\u4ee5 lambda \u6216\u5176\u4ed6\u51fd\u6570\u7684\u65b9\u5f0f\u4f20\u9012\uff09\u5e94\u7528\u5230\u6bcf\u4e2a\u503c\u4e0a\uff0c\u4f46\u662f\u5728 NA \uff08 null \uff09\u503c\u4e0a\u4f1a\u5931\u8d25\u3002 \u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0cSeries\u6709\u9762\u5411\u6570\u7ec4\u7684\u65b9\u6cd5\u7528\u4e8e\u8df3\u8fc7 NA \u503c\u7684\u5b57\u7b26\u4e32\u64cd\u4f5c\u3002\u8fd9\u4e9b\u65b9\u6cd5\u901a\u8fc7Series\u7684 str \u5c5e\u6027\u8fdb\u884c\u8c03\u7528\u3002 \u4f8b\u5982\uff0c\u53ef\u4ee5\u901a\u8fc7 str.contains \u6765\u68c0\u67e5\u6bcf\u4e2a\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u662f\u5426\u542b\u6709 'gmail' \u3002 m = data.str.contains('gmail') print(m) # Dave True # Steve True # Rob True # Wes NaN # dtype: object \u6b63\u5219\u8868\u8fbe\u5f0f\u4e5f\u53ef\u4ee5\u7ed3\u5408\u4efb\u610f\u7684 re \u6a21\u5757\u9009\u9879\u4f7f\u7528\uff0c\u4f8b\u5982 IGNORECASE \u3002 print(pattern) # ([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\\.([A-Z]{2,4}) m = data.str.findall(pattern, flags=re.IGNORECASE) print(m) # Dave [(dave, gmail, com)] # Steve [(steve, gmail, com)] # Rob [(rob, gmail, com)] # Wes NaN # dtype: object \u4f7f\u7528 str.get \u6216\u5728 str \u5c5e\u6027\u5185\u90e8\u7d22\u5f15\uff0c\u8fdb\u884c\u5411\u91cf\u5316\u7684\u5143\u7d20\u68c0\u7d22\u3002 m = data.str.match(pattern, flags=re.IGNORECASE) print(m) # Dave True # Steve True # Rob True # Wes NaN # dtype: object m = data.str.findall(pattern, flags=re.IGNORECASE) print(m.str.get(1)) # Dave NaN # Steve NaN # Rob NaN # Wes NaN # dtype: float64 print(m.str[0]) # Dave (dave, gmail, com) # Steve (steve, gmail, com) # Rob (rob, gmail, com) # Wes NaN # dtype: object \u4f7f\u7528\u5b57\u7b26\u4e32\u5207\u7247\u7684\u7c7b\u4f3c\u8bed\u6cd5\u8fdb\u884c\u5411\u91cf\u5316\u5207\u7247\u3002 print(data.str[:]) # Dave dave@gmail.com # Steve steve@gmail.com # Rob rob@gmail.com # Wes NaN # dtype: object print(data.str[:5]) # Dave dave@ # Steve steve # Rob rob@g # Wes NaN # dtype: object","title":"\u6570\u636e\u6e05\u6d17\u4e0e\u51c6\u5907"},{"location":"python/DataAnalysis/ch04/#_1","text":"","title":"\u6570\u636e\u6e05\u6d17\u4e0e\u51c6\u5907"},{"location":"python/DataAnalysis/ch04/#_2","text":"import pandas as pd import numpy as np from numpy import nan as NA \u5bf9\u4e8e\u6570\u503c\u578b\u6570\u636e\uff0cpandas\u4f7f\u7528\u6d6e\u70b9\u503c NaN \uff08Not a Number\u6765\u8868\u793a\u7f3a\u5931\u503c\uff09\u3002 \u5728pandas\u4e2d\uff0c\u91c7\u7528\u4e86R\u8bed\u8a00\u4e2d\u7684\u7f16\u7a0b\u60ef\u4f8b\uff0c\u5c06\u7f3a\u5931\u503c\u6210\u4e3a NA \uff0c\u610f\u601d\u662fnotavailable\uff08\u4e0d\u53ef\u7528\uff09\u3002 Python\u5185\u5efa\u7684 None \u503c\u5728\u5bf9\u8c61\u6570\u7ec4\u4e2d\u4e5f\u88ab\u5f53\u4f5c NA \u5904\u7406\u3002 NA\u5904\u7406\u65b9\u6cd5\uff1a dropna :\u6839\u636e\u6bcf\u4e2a\u6807\u7b7e\u7684\u503c\u662f\u5426\u662f\u786e\u5b9e\u6570\u636e\u6765\u7b5b\u9009\u8f74\u6807\u7b7e\uff0c\u5e76\u6839\u636e\u5141\u8bb8\u4e22\u5931\u7684\u6570\u636e\u91cf\u6765\u786e\u5b9a\u9608\u503c fillna :\u7528\u67d0\u4e9b\u503c\u586b\u5145\u786e\u5b9e\u7684\u6570\u636e\u6216\u4f7f\u7528\u63d2\u503c\u65b9\u6cd5\uff0c\u5982 ffill \u6216 bfill isnull :\u8fd4\u56de\u8868\u660e\u54ea\u4e9b\u503c\u662f\u7f3a\u5931\u503c\u7684\u5e03\u5c14\u503c notnull :\u662f isnull \u7684\u53cd\u51fd\u6570 string_data = pd.Series(['aardvark', 'artichoke', np.nan, 'avocado']) print(string_data) # 0 aardvark # 1 artichoke # 2 NaN # 3 avocado # dtype: object print(string_data.isnull()) # 0 False # 1 False # 2 True # 3 False # dtype: bool string_data[0] = None print(string_data.isnull()) # 0 True # 1 False # 2 True # 3 False # dtype: bool","title":"\u5904\u7406\u7f3a\u5931\u503c"},{"location":"python/DataAnalysis/ch04/#_3","text":"","title":"\u8fc7\u6ee4\u7f3a\u5931\u503c"},{"location":"python/DataAnalysis/ch04/#series","text":"\u5728Series\u4e0a\u4f7f\u7528 dropna \uff0c\u5b83\u4f1a\u8fd4\u56deSeries\u4e2d\u6240\u6709\u7684\u975e\u7a7a\u6570\u636e\u53ca\u5176\u7d22\u5f15\u503c\u3002 data = pd.Series([1, NA, 3.5, NA, 7]) print(data.dropna()) # 0 1.0 # 2 3.5 # 4 7.0 # dtype: float64 print(data[data.notnull()]) # \u4e0e\u4e0a\u9762\u7b49\u4ef7 # 0 1.0 # 2 3.5 # 4 7.0 # dtype: float64","title":"\u5904\u7406Series"},{"location":"python/DataAnalysis/ch04/#dataframe","text":"data = pd.DataFrame( [[1., 6.5, 3.], [1., NA, NA], [NA, NA, NA], [NA, 6.5, 3.]] ) print(data) # 0 1 2 # 0 1.0 6.5 3.0 # 1 1.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 6.5 3.0 cleaned = data.dropna() # dropna\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u4f1a\u5220\u9664\u5305\u542b\u7f3a\u5931\u503c\u7684\u884c print(cleaned) # 0 1 2 # 0 1.0 6.5 3.0 cleaned = data.dropna(how='all') # \u4f20\u5165how='all\u2019\u65f6\uff0c\u5c06\u5220\u9664\u6240\u6709\u503c\u5747\u4e3aNA\u7684\u884c print(cleaned) # 0 1 2 # 0 1.0 6.5 3.0 # 1 1.0 NaN NaN # 3 NaN 6.5 3.0 data[4] = NA print(data) # 0 1 2 4 # 0 1.0 6.5 3.0 NaN # 1 1.0 NaN NaN NaN # 2 NaN NaN NaN NaN # 3 NaN 6.5 3.0 NaN cleaned = data.dropna(axis=1, how='all') # \u5220\u9664\u5168NA\u7684\u5217 print(cleaned) # 0 1 2 # 0 1.0 6.5 3.0 # 1 1.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 6.5 3.0 df = pd.DataFrame(np.random.randn(7, 3)) print(df) # 0 1 2 # 0 -1.069771 -0.777921 0.181956 # 1 -0.399504 -0.641737 -0.946327 # 2 -1.013920 -0.247588 -0.760146 # 3 1.076946 -1.263203 0.494077 # 4 0.460985 -1.241870 0.283006 # 5 1.168149 1.033752 0.900095 # 6 -1.208514 -1.049546 -0.783680 df.iloc[:4, 1] = NA # \u6807\u7b7e1\uff0c\u524d4\u4e2a\u5143\u7d20 df.iloc[:2, 2] = NA # \u6807\u7b7e2\uff0c\u524d2\u4e2a\u5143\u7d20 print(df) # 0 1 2 # 0 -1.069771 NaN NaN # 1 -0.399504 NaN NaN # 2 -1.013920 NaN -0.760146 # 3 1.076946 NaN 0.494077 # 4 0.460985 -1.241870 0.283006 # 5 1.168149 1.033752 0.900095 # 6 -1.208514 -1.049546 -0.783680 cleaned = df.dropna() print(cleaned) # 0 1 2 # 4 0.033663 0.291886 0.736448 # 5 -0.433380 0.397104 1.252005 # 6 -1.999018 0.303866 1.430109 cleaned = df.dropna(thresh=2) # \u4fdd\u75592\u884c\u542bNA\u7684\u89c2\u5bdf\u503c print(cleaned) # 0 1 2 # 2 -1.413976 NaN 0.222274 # 3 -0.644266 NaN 0.324180 # 4 -0.122160 -2.244880 -0.406562 # 5 -0.140326 0.101133 -0.764048 # 6 -1.809141 0.139091 -0.819175","title":"\u5904\u7406DataFrame"},{"location":"python/DataAnalysis/ch04/#_4","text":"fillna \u51fd\u6570\u53c2\u6570\uff1a value\uff1a\u6807\u91cf\u503c\u6216\u5b57\u5178\u578b\u5bf9\u8c61\u7528\u4e8e\u586b\u5145\u7f3a\u5931\u503c method\uff1a\u63d2\u503c\u65b9\u6cd5\uff0c\u5982\u679c\u6ca1\u6709\u5176\u4ed6\u53c2\u6570\uff0c\u9ed8\u8ba4\u662f'ffill' axis\uff1a\u9700\u8981\u586b\u5145\u7684\u8f74\uff0c\u9ed8\u8ba4axis=0 inplace\uff1a\u4fee\u6539\u88ab\u8c03\u7528\u5bf9\u8c61\uff0c\u800c\u4e0d\u662f\u751f\u6210\u4e00\u4e2a\u5907\u4efd limit\uff1a\u7528\u4e8e\u524d\u5411\u6216\u540e\u5411\u586b\u5145\u65f6\u6700\u5927\u7684\u586b\u5145\u8303\u56f4 df = pd.DataFrame(np.random.randn(7, 3)) df.iloc[:4, 1] = NA # \u6807\u7b7e1\uff0c\u524d4\u4e2a\u5143\u7d20 df.iloc[:2, 2] = NA # \u6807\u7b7e2\uff0c\u524d2\u4e2a\u5143\u7d20 print(df) # 0 1 2 # 0 -0.181196 NaN NaN # 1 -1.657668 NaN NaN # 2 -0.053454 NaN 0.391461 # 3 -0.539307 NaN -0.668400 # 4 -0.433439 0.839713 -0.295273 # 5 0.749930 1.661641 -0.495165 # 6 0.591810 1.017372 0.932367 result = df.fillna(0) # \u8c03\u7528fillna\u65f6\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e00\u4e2a\u5e38\u6570\u6765\u66ff\u4ee3\u7f3a\u5931\u503c print(result) # 0 1 2 # 0 -0.430926 0.000000 0.000000 # 1 0.448061 0.000000 0.000000 # 2 -0.059910 0.000000 -1.532646 # 3 -0.315793 0.000000 -0.196546 # 4 -0.546106 0.135108 -0.332309 # 5 1.083075 0.346070 -0.773104 # 6 -0.186511 1.055337 -1.168303 result = df.fillna({1: 0.5, 2: 0}) # \u8c03\u7528fillna\u65f6\u4f7f\u7528\u5b57\u5178\uff0c\u53ef\u4ee5\u4e3a\u4e0d\u540c\u5217\u8bbe\u5b9a\u4e0d\u540c\u7684\u586b\u5145\u503c print(result) # 0 1 2 # 0 -0.794344 0.500000 0.000000 # 1 -0.960917 0.500000 0.000000 # 2 1.494351 0.500000 0.100878 # 3 -0.554765 0.500000 1.118801 # 4 -0.866117 0.523615 1.217478 # 5 -0.706966 -0.681776 0.797690 # 6 -1.456366 1.205518 -0.402432 fillna \u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u65b0\u7684\u5bf9\u8c61\uff0c\u4f46\u4e5f\u53ef\u4ee5\u4fee\u6539\u5df2\u7ecf\u5b58\u5728\u7684\u5bf9\u8c61 _ = df.fillna(0, inplace=True) # inplace=True\u6307\u5b9a\u5728\u5df2\u6709\u5bf9\u8c61\u4e0a\u76f4\u63a5\u4fee\u6539 print(df) # 0 1 2 # 0 -1.176124 0.000000 0.000000 # 1 0.120458 0.000000 0.000000 # 2 -1.206408 0.000000 0.551693 # 3 0.224563 0.000000 1.145156 # 4 -0.557836 0.081135 -0.075282 # 5 2.378837 -0.876145 1.430386 # 6 -0.152662 1.278364 0.479686 df = pd.DataFrame(np.random.randn(6, 3)) df.iloc[2:, 1] = NA # \u6807\u7b7e1\uff0c\u524d4\u4e2a\u5143\u7d20 df.iloc[4:, 2] = NA # \u6807\u7b7e2\uff0c\u524d2\u4e2a\u5143\u7d20 print(df) # 0 1 2 # 0 1.154788 0.033949 -0.122807 # 1 0.258684 -0.580244 1.636514 # 2 1.503756 NaN -1.224203 # 3 0.824049 NaN -0.364345 # 4 -1.247609 NaN NaN # 5 -1.019980 NaN NaN result = df.fillna(method='ffill') # \u5411\u540e\u586b\u5145 print(result) # 0 1 2 # 0 2.082449 0.398874 0.359772 # 1 0.233129 0.385347 1.953533 # 2 0.396555 0.385347 0.592784 # 3 -0.957249 0.385347 0.169815 # 4 0.854452 0.385347 0.169815 # 5 -0.105982 0.385347 0.169815 result = df.fillna(method='ffill', limit=3) # \u6bcf\u5217\u6700\u591a\u586b3\u4e2a print(result) result = df.fillna(df[0].max()) # \u75280\u5217\u7684\u6700\u5927\u503c\u586b\u5145\u6240\u6709\u7684NA print(result) # 0 1 2 # 0 -0.377697 -0.852891 -0.705489 # 1 -0.611759 -0.013237 -0.295764 # 2 -0.389974 1.057881 1.041957 # 3 -0.016845 1.057881 -1.149954 # 4 1.057881 1.057881 1.057881 # 5 -0.463471 1.057881 1.057881","title":"\u8865\u5168\u7f3a\u5931\u503c"},{"location":"python/DataAnalysis/ch04/#_5","text":"import pandas as pd import numpy as np from numpy import nan as NA","title":"\u6570\u636e\u8f6c\u6362"},{"location":"python/DataAnalysis/ch04/#_6","text":"data = pd.DataFrame( { 'k1': ['one', 'two'] * 3 + ['two'], 'k2': [1, 1, 2, 3, 4, 4, 4] } ) print(data) # \u91cd\u590d\u51fa\u73b02\u6b21\u7684\u8bb0\u5f55\uff1atwo 4 # k1 k2 # 0 one 1 # 1 two 1 # 2 one 2 # 3 two 3 # 4 one 4 # 5 two 4 # 6 two 4 DataFrame\u7684 duplicated \u65b9\u6cd5\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u5e03\u5c14\u503cSeries\uff0c\u8fd9\u4e2aSeries\u53cd\u6620\u7684\u662f\u6bcf\u4e00\u884c\u662f\u5426\u5b58\u5728\u91cd\u590d\uff08\u4e0e\u4e4b\u524d\u51fa\u73b0\u8fc7\u7684\u884c\u76f8\u540c\uff09\u60c5\u51b5\uff0c\u9ed8\u8ba4\u662f\u5bf9\u5217\u8fdb\u884c\u64cd\u4f5c\u3002 print(data.duplicated()) # 0 False # 1 False # 2 False # 3 False # 4 False # 5 False # 6 True # dtype: bool drop_duplicates \u8fd4\u56de\u7684\u662fDataFrame\uff0c\u5185\u5bb9\u662f duplicated \u8fd4\u56de\u6570\u7ec4\u4e2d\u4e3a False \u7684\u90e8\u5206\u3002\u9ed8\u8ba4\u662f\u5bf9\u5217\u8fdb\u884c\u64cd\u4f5c\u3002 print(data.drop_duplicates()) # k1 k2 # 0 one 1 # 1 two 1 # 2 one 2 # 3 two 3 # 4 one 4 # 5 two 4 \u53ef\u4ee5\u6307\u5b9a\u6570\u636e\u7684\u4efb\u4f55\u5b50\u96c6\u6765\u68c0\u6d4b\u662f\u5426\u6709\u91cd\u590d\u3002\u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u989d\u5916\u7684\u5217\uff0c\u5e76\u60f3\u57fa\u4e8e\u2019k1\u2019\u5217\u53bb\u9664\u91cd\u590d\u503c\u3002 data['v1'] = range(7) print(data) # k1 k2 v1 # 0 one 1 0 # 1 two 1 1 # 2 one 2 2 # 3 two 3 3 # 4 one 4 4 # 5 two 4 5 # 6 two 4 6 print(data.drop_duplicates(['k1'])) # \u4fdd\u7559\u7b2c\u4e00\u4e2a\u89c2\u6d4b\u5230\u7684one\u548ctwo\uff0c\u5176\u4f59\u4e22\u5f03 # k1 k2 v1 # 0 one 1 0 # 1 two 1 1 duplicated \u548c drop_duplicates \u9ed8\u8ba4\u90fd\u662f\u4fdd\u7559\u7b2c\u4e00\u4e2a\u89c2\u6d4b\u5230\u7684\u503c\u3002\u4f20\u5165\u53c2\u6570keep='last\u2019\u5c06\u4f1a\u8fd4\u56de\u6700\u540e\u4e00\u4e2a\u3002 print(data.drop_duplicates(['k1'], keep='last')) # \u4fdd\u7559\u6700\u540e\u4e00\u4e2a\u89c2\u6d4b\u5230\u7684one\u548ctwo # k1 k2 v1 # 4 one 4 4 # 6 two 4 6","title":"\u5220\u9664\u91cd\u590d\u503c"},{"location":"python/DataAnalysis/ch04/#_7","text":"\u4f7f\u7528 map \u662f\u4e00\u79cd\u53ef\u4ee5\u4fbf\u6377\u6267\u884c\u6309\u5143\u7d20\u8f6c\u6362\u53ca\u5176\u4ed6\u6e05\u6d17\u76f8\u5173\u64cd\u4f5c\u7684\u65b9\u6cd5\u3002 data = pd.DataFrame( { 'food': ['bacon', 'pulled pork', 'bacon', 'Pastrami', 'corned beef', 'Bacon', 'pastrami', 'honey ham', 'nova lox'], 'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6] } ) print(data) # food ounces # 0 bacon 4.0 # 1 pulled pork 3.0 # 2 bacon 12.0 # 3 Pastrami 6.0 # 4 corned beef 7.5 # 5 Bacon 8.0 # 6 pastrami 3.0 # 7 honey ham 5.0 # 8 nova lox 6.0 \u6dfb\u52a0\u4e00\u5217\u7528\u4e8e\u8868\u660e\u6bcf\u79cd\u98df\u7269\u7684\u52a8\u7269\u8089\u7c7b\u578b\u3002 \u5148\u521b\u5efa\u4e00\u4e2a\u98df\u7269\u548c\u8089\u7c7b\u7684\u6620\u5c04\u3002 meat_to_animal = { 'bacon': 'pig', 'pulled pork': 'pig', 'pastrami': 'cow', 'corned beef': 'cow', 'honey ham': 'pig', 'nova lox': 'salmon' } lowercased = data['food'].str.lower() # \u4f7f\u7528Series\u7684str.lower\u65b9\u6cd5\u5c06food\u7684\u6bcf\u4e2a\u503c\u90fd\u8f6c\u6362\u4e3a\u5c0f\u5199 print(lowercased) # 0 bacon # 1 pulled pork # 2 bacon # 3 pastrami # 4 corned beef # 5 bacon # 6 pastrami # 7 honey ham # 8 nova lox # Name: food, dtype: object data['animal'] = lowercased.map(meat_to_animal) print(data) # food ounces animal # 0 bacon 4.0 pig # 1 pulled pork 3.0 pig # 2 bacon 12.0 pig # 3 Pastrami 6.0 cow # 4 corned beef 7.5 cow # 5 Bacon 8.0 pig # 6 pastrami 3.0 cow # 7 honey ham 5.0 pig # 8 nova lox 6.0 salmon \u4e5f\u53ef\u4ee5\u4f20\u5165\u4e00\u4e2a\u51fd\u6570\uff0c\u5b8c\u6210\u4e0a\u9762\u6240\u6709\u529f\u80fd\u3002 data = pd.DataFrame( { 'food': ['bacon', 'pulled pork', 'bacon', 'Pastrami', 'corned beef', 'Bacon', 'pastrami', 'honey ham', 'nova lox'], 'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6] } ) result = data['food'].map(lambda x: meat_to_animal[x.lower()]) print(result) # 0 pig # 1 pig # 2 pig # 3 cow # 4 cow # 5 pig # 6 cow # 7 pig # 8 salmon # Name: food, dtype: object","title":"\u4f7f\u7528\u51fd\u6570\u6216\u6620\u5c04\u8fdb\u884c\u6570\u636e\u8f6c\u6362"},{"location":"python/DataAnalysis/ch04/#_8","text":"\u4f7f\u7528 fillna \u586b\u5145\u7f3a\u5931\u503c\u662f\u901a\u7528\u503c\u66ff\u6362\u7684\u7279\u6b8a\u6848\u4f8b\u3002 map \u53ef\u4ee5\u7528\u6765\u4fee\u6539\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u7684\u5b50\u96c6\u7684\u503c\uff0c\u4f46\u662f replace \u63d0\u4f9b\u4e86\u66f4\u4e3a\u7b80\u5355\u7075\u6d3b\u7684\u5b9e\u73b0\u3002 data.replace \u65b9\u6cd5\u4e0e data.str.replace \u65b9\u6cd5\u662f\u4e0d\u540c\u7684\uff0c data.str.replace \u662f\u5bf9\u5b57\u7b26\u4e32\u8fdb\u884c\u6309\u5143\u7d20\u66ff\u4ee3\u7684\u3002 \u4e0b\u9762\u7684Series\uff0c -999 \u53ef\u80fd\u662f\u7f3a\u5931\u503c\u7684\u6807\u8bc6\u3002\u5982\u679c\u8981\u4f7f\u7528 NA \u6765\u66ff\u4ee3\u8fd9\u4e9b\u503c\uff0c\u53ef\u4ee5\u4f7f\u7528 replace \u65b9\u6cd5\u751f\u6210\u65b0\u7684Series\uff08\u9664\u975e\u4f20\u5165\u4e86 inplace=True \uff09 data = pd.Series([1., -999., 2., -999., -1000., 3.]) print(data) # 0 1.0 # 1 -999.0 # 2 2.0 # 3 -999.0 # 4 -1000.0 # 5 3.0 # dtype: float64 result = data.replace(-999, np.nan) print(result) # 0 1.0 # 1 NaN # 2 2.0 # 3 NaN # 4 -1000.0 # 5 3.0 # dtype: float64 \u8981\u5c06\u4e0d\u540c\u7684\u503c\u66ff\u6362\u4e3a\u4e0d\u540c\u7684\u503c\uff0c\u53ef\u4ee5\u4f20\u5165\u66ff\u4ee3\u503c\u7684\u5217\u8868 result = data.replace([-999, -1000], [np.nan, 0]) print(result) # 0 1.0 # 1 NaN # 2 2.0 # 3 NaN # 4 0.0 # 5 3.0 # dtype: float64 \u4e5f\u53ef\u4ee5\u4f20\u5165\u66ff\u4ee3\u503c\u7684\u5b57\u5178 result = data.replace({-999: np.nan, -1000: 0}) print(result) # 0 1.0 # 1 NaN # 2 2.0 # 3 NaN # 4 0.0 # 5 3.0 # dtype: float64","title":"\u66ff\u4ee3\u503c"},{"location":"python/DataAnalysis/ch04/#_9","text":"\u548cSeries\u4e2d\u503c\u66ff\u6362\u7c7b\u4f3c\uff0c\u53ef\u4ee5\u901a\u8fc7\u51fd\u6570\u6216\u6620\u5c04\u5bf9\u8f74\u6807\u7b7e\u8fdb\u884c\u7c7b\u4f3c\u7684\u8f6c\u6362\uff0c\u751f\u6210\u65b0\u7684\u4e14\u5e26\u6709\u4e0d\u540c\u6807\u7b7e\u7684\u5bf9\u8c61\u3002 data = pd.DataFrame( np.arange(12).reshape((3, 4)), index=['Ohio', 'Colorado', 'New York'], columns=['one', 'two', 'three', 'four'] ) print(data) # one two three four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # New York 8 9 10 11 \u4e0eSeries\u7c7b\u4f3c\uff0c\u8f74\u7d22\u5f15\u4e5f\u6709\u4e00\u4e2a map \u65b9\u6cd5\u3002 transform = lambda x: x[:4].upper() # \u622a\u53d6index\u7684\u524d\u56db\u4f4d\u5e76\u8f6c\u5316\u4e3a\u5927\u5199\u683c\u5f0f result = data.index.map(transform) print(result) # Index(['OHIO', 'COLO', 'NEW '], dtype='object') \u8d4b\u503c\u7ed9 index \uff0c\u4fee\u6539DataFrame\u3002 data.index = data.index.map(transform) print(data) # one two three four # OHIO 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 \u521b\u5efa\u6570\u636e\u96c6\u8f6c\u6362\u540e\u7684\u7248\u672c\uff0c\u5e76\u4e14\u4e0d\u4fee\u6539\u539f\u6709\u7684\u6570\u636e\u96c6\uff0c\u4e00\u4e2a\u6709\u7528\u7684\u65b9\u6cd5\u662f rename \u3002 result = data.rename(index=str.title, columns=str.upper) print(result) # ONE TWO THREE FOUR # Ohio 0 1 2 3 # Colo 4 5 6 7 # New 8 9 10 11 print(data) # \u539f\u6709\u7684\u6570\u636e\u96c6\u672a\u88ab\u4fee\u6539 # one two three four # OHIO 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 rename \u53ef\u4ee5\u7ed3\u5408\u5b57\u5178\u578b\u5bf9\u8c61\u4f7f\u7528\uff0c\u4e3a\u8f74\u6807\u7b7e\u7684\u5b50\u96c6\u63d0\u4f9b\u65b0\u7684\u503c\u3002 result = data.rename(index={'OHIO': 'INDIANA'}, columns={'three': 'peekaboo'}) print(result) # one two peekaboo four # INDIANA 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 \u5982\u679c\u8981\u4fee\u6539\u539f\u6709\u7684\u6570\u636e\u96c6\uff0c\u4f20\u5165 inplace=True \u3002 data.rename(index={'OHIO': 'INDIANA'}, columns={'three': 'peekaboo'}, inplace=True) print(data) # one two peekaboo four # INDIANA 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11","title":"\u91cd\u547d\u540d\u8f74\u7d22\u5f15"},{"location":"python/DataAnalysis/ch04/#_10","text":"\u8fde\u7eed\u503c\u7ecf\u5e38\u9700\u8981\u79bb\u6563\u5316\uff0c\u6216\u8005\u5206\u79bb\u6210\u201d\u7bb1\u5b50\u201c\u8fdb\u884c\u5206\u6790\u3002 \u5047\u8bbe\u6709\u4e00\u7ec4\u4eba\u7fa4\u7684\u6570\u636e\uff0c\u60f3\u5c06\u4ed6\u4eec\u8fdb\u884c\u5206\u7ec4\uff0c\u653e\u5165\u79bb\u6563\u7684\u5e74\u9f84\u6846\u4e2d\u3002 ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32] \u5c06\u8fd9\u4e9b\u5e74\u9f84\u5206\u4e3a18\uff5e25\u300126\uff5e35\u300136\uff5e60\u4ee5\u53ca61\u53ca\u4ee5\u4e0a\u7b49\u82e5\u5e72\u7ec4\uff0c\u4f7f\u7528pandas\u4e2d\u7684 cut \u3002 bins = [18, 25, 35, 60, 100] cats = pd.cut(ages, bins) print(cats) # [(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]] # Length: 12 # Categories (4, interval[int64, right]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]] pandas\u8fd4\u56de\u7684\u5bf9\u8c61\u662f\u4e00\u4e2a\u7279\u6b8a\u7684 Categorical \u5bf9\u8c61\u3002 \u4f60\u770b\u5230\u7684\u8f93\u51fa\u63cf\u8ff0\u4e86\u7531 pandas.cut \u8ba1\u7b97\u51fa\u7684\u7bb1\u3002 \u4f60\u53ef\u4ee5\u5c06\u5b83\u5f53\u4f5c\u4e00\u4e2a\u8868\u793a\u7bb1\u540d\u7684\u5b57\u7b26\u4e32\u6570\u7ec4\uff1b\u5b83\u5728\u5185\u90e8\u5305\u542b\u4e00\u4e2a categories \uff08\u7c7b\u522b\uff09\u6570\u7ec4\uff0c\u5b83\u6307\u5b9a\u4e86\u4e0d\u540c\u7684\u7c7b\u522b\u540d\u79f0\u4ee5\u53ca codes \u5c5e\u6027\u4e2d\u7684 ages \uff08\u5e74\u9f84\uff09\u6570\u636e\u6807\u7b7e\u3002 print(cats.categories) # \u56db\u4e2a\u533a\u95f4\u7ec4 # IntervalIndex([(18, 25], (25, 35], (35, 60], (60, 100]], dtype='interval[int64, right]') print(cats.codes) # 61\u5c81\u843d\u5728\u7b2c3\u7ec4\uff08\u7ec4\u7f16\u53f7\u4ece0\u5f00\u59cb\uff09 # [0 0 0 1 0 0 2 1 3 2 2 1] \u6ce8\u610f\uff0c pd.value_counts(cats) \u662f\u5bf9 pandas.cut \u7684\u7ed3\u679c\u4e2d\u7684\u7bb1\u6570\u91cf\u7684\u8ba1\u6570\u3002 result = pd.value_counts(cats) print(result) # (18, 25] 5 # (25, 35] 3 # (35, 60] 3 # (60, 100] 1 # dtype: int64 \u4e0e\u533a\u95f4\u7684\u6570\u5b66\u7b26\u53f7\u4e00\u81f4\uff0c\u5c0f\u62ec\u53f7\u8868\u793a\u8fb9\u662f\u5f00\u653e\u7684\uff0c\u4e2d\u62ec\u53f7\u8868\u793a\u5b83\u662f\u5c01\u95ed\u7684\uff08\u5305\u62ec\u8fb9\uff09\u3002\u53ef\u4ee5\u901a\u8fc7\u4f20\u9012 right=False \u6765\u6539\u53d8\u54ea\u4e00\u8fb9\u662f\u5c01\u95ed\u7684\u3002\u9ed8\u8ba4 right=True \u3002 result = pd.cut(ages, [18, 26, 36, 61, 100], right=False) print(result) # [[18, 26), [18, 26), [18, 26), [26, 36), [18, 26), ..., [26, 36), [61, 100), [36, 61), [36, 61), [26, 36)] # Length: 12 # Categories (4, interval[int64, left]): [[18, 26) < [26, 36) < [36, 61) < [61, 100)] \u901a\u8fc7\u5411 labels \u9009\u9879\u4f20\u9012\u4e00\u4e2a\u5217\u8868\u6216\u6570\u7ec4\u6765\u4f20\u5165\u81ea\u5b9a\u4e49\u7684\u7bb1\u540d\u3002 group_name = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior'] result = pd.cut(ages, bins, labels=group_name) print(result) # ['Youth', 'Youth', 'Youth', 'YoungAdult', 'Youth', ..., 'YoungAdult', 'Senior', 'MiddleAged', 'MiddleAged', 'YoungAdult'] # Length: 12 # Categories (4, object): ['Youth' < 'YoungAdult' < 'MiddleAged' < 'Senior'] result = pd.value_counts(pd.cut(ages, bins, labels=group_name)) # \u6807\u7b7e\u8f93\u51fa print(result) # Youth 5 # YoungAdult 3 # MiddleAged 3 # Senior 1 # dtype: int64 result = pd.value_counts(pd.cut(ages, bins)) # \u533a\u95f4\u8f93\u51fa print(result) # (18, 25] 5 # (25, 35] 3 # (35, 60] 3 # (60, 100] 1 # dtype: int64 \u5982\u679c\u4f20\u7ed9 cut \u6574\u6570\u4e2a\u7684\u7bb1\u6765\u4ee3\u66ff\u663e\u5f0f\u7684\u7bb1\u8fb9\uff0cpandas\u5c06\u6839\u636e\u6570\u636e\u4e2d\u7684\u6700\u5c0f\u503c\u548c\u6700\u5927\u503c\u8ba1\u7b97\u51fa\u7b49\u957f\u7684\u7bb1\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u8003\u8651\u4e00\u4e9b\u5747\u5300\u5206\u5e03\u7684\u6570\u636e\u88ab\u5207\u6210\u56db\u4efd\u7684\u60c5\u51b5\u3002 data = np.random.rand(20) result = pd.cut(data, 4, precision=2) # precision=2\u7684\u9009\u9879\u5c06\u5341\u8fdb\u5236\u7cbe\u5ea6\u9650\u5236\u5728\u4e24\u4f4d\u3002 print(result) # [(0.44, 0.66], (0.0063, 0.23], (0.23, 0.44], (0.0063, 0.23], (0.23, 0.44], ..., (0.23, 0.44], (0.0063, 0.23], (0.23, 0.44], (0.66, 0.88], (0.23, 0.44]] # Length: 20 # Categories (4, interval[float64, right]): [(0.0063, 0.23] < (0.23, 0.44] < (0.44, 0.66] < (0.66, 0.88]] qcut \u662f\u4e00\u4e2a\u4e0e\u5206\u7bb1\u5bc6\u5207\u76f8\u5173\u7684\u51fd\u6570\uff0c\u5b83\u57fa\u4e8e\u6837\u672c\u5206\u4f4d\u6570\u8fdb\u884c\u5206\u7bb1\u3002 \u53d6\u51b3\u4e8e\u6570\u636e\u7684\u5206\u5e03\uff0c\u4f7f\u7528 cut \u901a\u5e38\u4e0d\u4f1a\u4f7f\u6bcf\u4e2a\u7bb1\u5177\u6709\u76f8\u540c\u6570\u636e\u91cf\u7684\u6570\u636e\u70b9\u3002 \u7531\u4e8eqcut\u4f7f\u7528\u6837\u672c\u7684\u5206\u4f4d\u6570\uff0c\u4f60\u53ef\u4ee5\u901a\u8fc7qcut\u83b7\u5f97\u7b49\u957f\u7684\u7bb1\u3002 data = np.random.randn(1000) # \u6b63\u6001\u5206\u5e03 cats = pd.qcut(data, 4) # \u5207\u62104\u4efd print(cats) # [(-0.00329, 0.644], (-0.00329, 0.644], (-0.659, -0.00329], (-0.659, -0.00329], (0.644, 3.468], ..., (0.644, 3.468], (-3.9619999999999997, -0.659], (-3.9619999999999997, -0.659], (-0.00329, 0.644], (-0.00329, 0.644]] # Length: 1000 # Categories (4, interval[float64, right]): [(-3.9619999999999997, -0.659] < (-0.659, -0.00329] < (-0.00329, 0.644] < (0.644, 3.468]] result = pd.value_counts(cats) print(result) # (-3.9619999999999997, -0.659] 250 # (-0.659, -0.00329] 250 # (-0.00329, 0.644] 250 # (0.644, 3.468] 250 # dtype: int64 \u4e0e cut \u7c7b\u4f3c\uff0c\u53ef\u4ee5\u4f20\u5165\u81ea\u5b9a\u4e49\u7684\u5206\u4f4d\u6570\uff080\u548c1\u4e4b\u95f4\u7684\u6570\u636e\uff0c\u5305\u62ec\u8fb9\uff09\u3002 result = pd.qcut(data, [0, 0.1, 0.5, 0.9, 1.]) print(result) # [(-0.00329, 1.234], (-0.00329, 1.234], (-1.321, -0.00329], (-1.321, -0.00329], (-0.00329, 1.234], ..., (-0.00329, 1.234], (-1.321, -0.00329], (-1.321, -0.00329], (-0.00329, 1.234], (-0.00329, 1.234]] # Length: 1000 # Categories (4, interval[float64, right]): [(-3.9619999999999997, -1.321] < (-1.321, -0.00329] < (-0.00329, 1.234] < (1.234, 3.468]]","title":"\u79bb\u6563\u5316\u548c\u5206\u7bb1"},{"location":"python/DataAnalysis/ch04/#_11","text":"\u8fc7\u6ee4\u6216\u8f6c\u6362\u5f02\u5e38\u503c\u5728\u5f88\u5927\u7a0b\u5ea6\u4e0a\u662f\u5e94\u7528\u6570\u7ec4\u64cd\u4f5c\u7684\u4e8b\u60c5\u3002 \u8003\u8651\u4e00\u4e2a\u5177\u6709\u6b63\u6001\u5206\u5e03\u6570\u636e\u7684DataFrame\u3002 data = pd.DataFrame(np.random.randn(1000, 4)) print(data.describe()) # 0 1 2 3 # count 1000.000000 1000.000000 1000.000000 1000.000000 # mean 0.008124 -0.008050 -0.013403 -0.008261 # std 0.979236 0.992982 0.998819 1.038760 # min -3.231914 -3.441270 -3.345210 -4.320565 # 25% -0.634801 -0.599852 -0.656481 -0.677611 # 50% -0.033252 0.000060 -0.040634 -0.015463 # 75% 0.649340 0.644312 0.678101 0.683849 # max 3.292099 2.758754 2.911447 3.371729 \u627e\u51fa\u4e00\u5217\u4e2d\u7edd\u5bf9\u503c\u5927\u4e8e\u4e09\u7684\u503c\u3002 col = data[2] result = col[np.abs(col) > 3] print(result) # 519 -3.035355 # 536 -3.345210 # Name: 2, dtype: float64 \u9009\u51fa\u6240\u6709\u503c\u5927\u4e8e3\u6216\u5c0f\u4e8e-3\u7684\u884c\uff0c\u53ef\u4ee5\u5bf9\u5e03\u5c14\u503cDataFrame\u4f7f\u7528 any \u65b9\u6cd5\u3002 result = data[(np.abs(data) > 3).any(1)] print(result) # 0 1 2 3 # 116 -0.080907 -3.441270 -0.163263 0.392800 # 139 -1.294440 1.828397 1.178897 -3.469466 # 241 -0.486292 0.150443 0.264172 -3.013440 # 295 3.292099 -0.339284 0.732829 -0.475202 # 355 0.307577 -3.053322 0.967497 0.896363 # 359 3.264981 -1.172096 0.207622 -0.281803 # 519 -0.448987 1.623843 -3.035355 -0.436833 # 533 -1.022616 -0.212597 1.030969 3.371729 # 536 1.067598 -1.306839 -3.345210 0.620834 # 541 -0.952760 -2.157970 -0.403199 -4.320565 # 690 0.006821 -3.104117 0.484881 -0.132613 # 750 -3.231914 1.017712 0.070430 0.631447 # 771 -3.007622 0.257960 -0.118179 -1.283365 # 976 1.684760 -0.003295 -0.249843 3.169371 \u6839\u636e\u8fd9\u4e9b\u6807\u51c6\u6765\u8bbe\u7f6e\u6765\u9650\u5b9a\u503c\uff0c\u4e0b\u9762\u4ee3\u7801\u9650\u5236\u4e86-3\u52303\u4e4b\u95f4\u7684\u6570\u503c\u3002 \u8bed\u53e5 np.sign(data) \u6839\u636e\u6570\u636e\u4e2d\u7684\u503c\u7684\u6b63\u8d1f\u5206\u522b\u751f\u62101\u548c-1\u7684\u6570\u503c\u3002 result = data[(np.abs(data) > 3)] = np.sign(data) * 3 print(result.describe()) # 0 1 2 3 # count 1000.000000 1000.000000 1000.000000 1000.000000 # mean -0.036000 0.000000 -0.084000 -0.048000 # std 3.001285 3.001501 3.000324 3.001117 # min -3.000000 -3.000000 -3.000000 -3.000000 # 25% -3.000000 -3.000000 -3.000000 -3.000000 # 50% -3.000000 0.000000 -3.000000 -3.000000 # 75% 3.000000 3.000000 3.000000 3.000000 # max 3.000000 3.000000 3.000000 3.000000 print(result.head()) # 0 1 2 3 # 0 -3.0 3.0 -3.0 -3.0 # 1 -3.0 -3.0 -3.0 -3.0 # 2 3.0 3.0 -3.0 3.0 # 3 3.0 -3.0 3.0 -3.0 # 4 3.0 -3.0 -3.0 -3.0","title":"\u68c0\u6d4b\u548c\u8fc7\u6ee4\u5f02\u5e38\u503c"},{"location":"python/DataAnalysis/ch04/#_12","text":"\u4f7f\u7528 numpy.random.permutation \u5bf9DataFrame\u4e2d\u7684Series\u6216\u884c\u8fdb\u884c\u7f6e\u6362\uff08\u968f\u673a\u91cd\u6392\u5e8f\uff09\u3002 \u5728\u8c03\u7528 permutation \u65f6\u6839\u636e\u4f60\u60f3\u8981\u7684\u8f74\u957f\u5ea6\u53ef\u4ee5\u4ea7\u751f\u4e00\u4e2a\u8868\u793a\u65b0\u987a\u5e8f\u7684\u6574\u6570\u6570\u7ec4\u3002 df = pd.DataFrame(np.arange(5 * 4).reshape((5, 4))) sampler = np.random.permutation(5) print(sampler) # \u8fd4\u56dearray # [1 4 3 0 2] print(df) # 0 1 2 3 # 0 0 1 2 3 # 1 4 5 6 7 # 2 8 9 10 11 # 3 12 13 14 15 # 4 16 17 18 19 \u4e0a\u9762\u8fd4\u56de\u7684 sampler \u6574\u6570\u6570\u7ec4 [1 4 3 0 2] \u7528\u5728\u57fa\u4e8e iloc \u7684\u7d22\u5f15\u6216\u7b49\u4ef7\u7684 take \u51fd\u6570\u4e2d\uff0c\u91cd\u65b0\u6392\u5217\u884c\u987a\u5e8f\u3002 print(df.take(sampler)) # 0 1 2 3 # 1 4 5 6 7 # 4 16 17 18 19 # 3 12 13 14 15 # 0 0 1 2 3 # 2 8 9 10 11 \u9009\u51fa\u4e00\u4e2a\u4e0d\u542b\u6709\u66ff\u4ee3\u503c\u7684\u968f\u673a\u5b50\u96c6\uff0c\u53ef\u4ee5\u4f7f\u7528Series\u548cDataFrame\u7684 sample \u65b9\u6cd5\u3002 result = df.sample(n=3) print(result) # 0 1 2 3 # 0 0 1 2 3 # 2 8 9 10 11 # 1 4 5 6 7 \u8981\u751f\u6210\u4e00\u4e2a\u5e26\u6709\u66ff\u4ee3\u503c\u7684\u6837\u672c\uff08\u5141\u8bb8\u6709\u91cd\u590d\u9009\u62e9\uff09\uff0c\u5c06 replace=True \u4f20\u5165 sample \u65b9\u6cd5\u3002 choice = pd.Series([5, 7, -1, 6, 4]) draws = choice.sample(n=10, replace=True) print(choice) # 0 5 # 1 7 # 2 -1 # 3 6 # 4 4 # dtype: int64 print(draws) # 4 4 # 0 5 # 0 5 # 3 6 # 4 4 # 0 5 # 1 7 # 3 6 # 2 -1 # 0 5 # dtype: int64","title":"\u7f6e\u6362\u548c\u968f\u673a\u62bd\u6837"},{"location":"python/DataAnalysis/ch04/#_13","text":"\u5c06\u5206\u7c7b\u53d8\u91cf\u8f6c\u6362\u4e3a\u201c\u865a\u62df\u201d\u6216\u201c\u6307\u6807\u201d\u77e9\u9635\u662f\u53e6\u4e00\u79cd\u7528\u4e8e\u7edf\u8ba1\u5efa\u6a21\u6216\u673a\u5668\u5b66\u4e60\u7684\u8f6c\u6362\u64cd\u4f5c\u3002 \u5982\u679cDataFrame\u4e2d\u7684\u4e00\u5217\u6709 k \u4e2a\u4e0d\u540c\u7684\u503c\uff0c\u5219\u53ef\u4ee5\u884d\u751f\u4e00\u4e2a k \u5217\u7684\u503c\u4e3a 1 \u548c 0 \u7684\u77e9\u9635\u6216DataFrame\u3002 pandas\u6709\u4e00\u4e2aget_dummies\u51fd\u6570\u7528\u4e8e\u5b9e\u73b0\u8be5\u529f\u80fd\u3002 df = pd.DataFrame( { 'key': ['b', 'b', 'a', 'c', 'a', 'b'], 'data1': range(6) } ) print(df) # key data1 # 0 b 0 # 1 b 1 # 2 a 2 # 3 c 3 # 4 a 4 # 5 b 5 \u5728\u6307\u6807DataFrame\u7684\u5217\u4e0a\u52a0\u5165\u524d\u7f00\uff0c\u7136\u540e\u4e0e\u5176\u4ed6\u6570\u636e\u5408\u5e76\u3002\u5728 get_dummies \u65b9\u6cd5\u4e2d\u6709\u4e00\u4e2a\u524d\u7f00\u53c2\u6570\u7528\u4e8e\u5b9e\u73b0\u8be5\u529f\u80fd\u3002 \u901a\u8fc7 get_dummies \u65b9\u6cd5\uff0c\u628a\u4e0a\u9762 df \u6570\u636e\u6309\u7167 key \u8fdb\u884c\u4e86\u5206\u7ec4\uff0c\u5e76\u901a\u8fc7\u4e0d\u540c\u5217\u6765\u5c55\u73b0\u5206\u7ec4\u540e\u7684\u5bf9\u5e94\u5173\u7cfb\u3002\u4f8b\u5982\uff0c key \u5217\u7684 a \uff0c\u5bf9\u5e94\u503c 2 \u548c 4 \u3002 dummies = pd.get_dummies(df['key'], prefix='key') print(dummies) # key_a key_b key_c # 0 0 1 0 # 1 0 1 0 # 2 1 0 0 # 3 0 0 1 # 4 1 0 0 # 5 0 1 0 df_with_dummy = df[['data1']].join(dummies) print(df_with_dummy) # data1 key_a key_b key_c # 0 0 0 1 0 # 1 1 0 1 0 # 2 2 1 0 0 # 3 3 0 0 1 # 4 4 1 0 0 # 5 5 0 1 0 \u66f4\u4e3a\u590d\u6742\u7684\u60c5\u51b5\uff0cDataFrame\u4e2d\u7684\u4e00\u884c\u5c5e\u4e8e\u591a\u4e2a\u7c7b\u522b\u3002 \u4ee5MovieLens\u76841M\u6570\u636e\u96c6\u4e3a\u4f8b\u3002\u589e\u52a0\u53c2\u6570 encoding='unicode_escape' \u907f\u514d\u51fa\u73b0\u4e0b\u9762\u7684\u9519\u8bef\uff1a UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 3114: invalid continuation byte \u589e\u52a0\u53c2\u6570 engine='python' \u907f\u514d\u51fa\u73b0\u4e0b\u9762\u7684\u9519\u8bef\uff1a ParserWarning: Falling back to the 'python' engine because the 'c' engine does not support regex separators (separators > 1 char and different from '\\s+' are interpreted as regex); you can avoid this warning by specifying engine='python'. mnames = ['movie_id', 'title', 'genres'] movies = pd.read_table( '../datasets/movielens/movies.dat', sep='::', header=None, names=mnames, encoding='unicode_escape', engine='python' ) print(movies[:10]) # movie_id title genres # 0 1 Toy Story (1995) Animation|Children's|Comedy # 1 2 Jumanji (1995) Adventure|Children's|Fantasy # 2 3 Grumpier Old Men (1995) Comedy|Romance # 3 4 Waiting to Exhale (1995) Comedy|Drama # 4 5 Father of the Bride Part II (1995) Comedy # 5 6 Heat (1995) Action|Crime|Thriller # 6 7 Sabrina (1995) Comedy|Romance # 7 8 Tom and Huck (1995) Adventure|Children's # 8 9 Sudden Death (1995) Action # 9 10 GoldenEye (1995) Action|Adventure|Thriller \u4e3a\u6bcf\u4e2a\u7535\u5f71\u6d41\u6d3e\u6dfb\u52a0\u6307\u6807\u53d8\u91cf\u9700\u8981\u8fdb\u884c\u4e00\u4e9b\u6570\u636e\u5904\u7406\u3002 \u9996\u5148\uff0c\u6211\u4eec\u4ece\u6570\u636e\u96c6\u4e2d\u63d0\u53d6\u51fa\u6240\u6709\u4e0d\u540c\u7684\u6d41\u6d3e\u7684\u5217\u8868\u3002 all_genres = [] for x in movies.genres: all_genres.extend(x.split('|')) genres = pd.unique(all_genres) print(genres) # ['Animation' \"Children's\" 'Comedy' 'Adventure' 'Fantasy' 'Romance' 'Drama' # 'Action' 'Crime' 'Thriller' 'Horror' 'Sci-Fi' 'Documentary' 'War' # 'Musical' 'Mystery' 'Film-Noir' 'Western'] \u4f7f\u7528\u51680\u7684DataFrame\u662f\u6784\u5efa\u6307\u6807DataFrame\u7684\u4e00\u79cd\u65b9\u5f0f\u3002 zero_matrix = np.zeros((len(movies), len(genres))) dummies = pd.DataFrame(zero_matrix, columns=genres) print(zero_matrix) # [[0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.] # ... # [0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.]] print(dummies.head(n=10)) # Animation Children's Comedy ... Mystery Film-Noir Western # 0 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 1 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 2 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 3 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 4 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 5 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 6 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 7 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 8 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 9 0.0 0.0 0.0 ... 0.0 0.0 0.0 # # [10 rows x 18 columns] \u904d\u5386\u6bcf\u4e00\u90e8\u7535\u5f71\uff0c\u5c06 dummies \u6bcf\u4e00\u884c\u7684\u6761\u76ee\u8bbe\u7f6e\u4e3a 1 \u3002\u4f7f\u7528 dummies.columns \u6765\u8ba1\u7b97\u6bcf\u4e00\u4e2a\u6d41\u6d3e\u7684\u5217\u6307\u6807\u3002 gen = movies.genres[0] print(gen.split('|')) # ['Animation', \"Children's\", 'Comedy'] result = dummies.columns.get_indexer(gen.split('|')) print(result) # [0 1 2] \u4f7f\u7528 .loc \u6839\u636e\u8fd9\u4e9b\u6307\u6807\u6765\u8bbe\u7f6e\u503c\u3002 for i, gen in enumerate(movies.genres): indices = dummies.columns.get_indexer(gen.split('|')) dummies.iloc[i, indices] = 1 \u5c06\u7ed3\u679c\u4e0e movies \u8fdb\u884c\u5408\u5e76\u3002 movies_windic = movies.join(dummies.add_prefix('Genre_')) print(movies_windic.iloc[0]) # movie_id 1 # title Toy Story (1995) # genres Animation|Children's|Comedy # Genre_Animation 1.0 # Genre_Children's 1.0 # Genre_Comedy 1.0 # Genre_Adventure 0.0 # Genre_Fantasy 0.0 # Genre_Romance 0.0 # Genre_Drama 0.0 # Genre_Action 0.0 # Genre_Crime 0.0 # Genre_Thriller 0.0 # Genre_Horror 0.0 # Genre_Sci-Fi 0.0 # Genre_Documentary 0.0 # Genre_War 0.0 # Genre_Musical 0.0 # Genre_Mystery 0.0 # Genre_Film-Noir 0.0 # Genre_Western 0.0 # Name: 0, dtype: object \u5bf9\u4e8e\u66f4\u5927\u7684\u6570\u636e\uff0c\u4e0a\u9762\u8fd9\u79cd\u4f7f\u7528\u591a\u6210\u5458\u6784\u5efa\u6307\u6807\u53d8\u91cf\u5e76\u4e0d\u662f\u7279\u522b\u5feb\u901f\u3002 \u66f4\u597d\u7684\u65b9\u6cd5\u662f\u5199\u4e00\u4e2a\u76f4\u63a5\u5c06\u6570\u636e\u5199\u4e3aNumPy\u6570\u7ec4\u7684\u5e95\u5c42\u51fd\u6570\uff0c\u7136\u540e\u5c06\u7ed3\u679c\u5c01\u88c5\u8fdbDataFrame\u3002 \u5c06 get_dummies \u4e0e cut \u7b49\u79bb\u6563\u5316\u51fd\u6570\u7ed3\u5408\u4f7f\u7528\u662f\u7edf\u8ba1\u5e94\u7528\u7684\u4e00\u4e2a\u6709\u7528\u65b9\u6cd5\u3002 np.random.seed(12345) # \u4f7f\u7528numpy.random.seed\u6765\u8bbe\u7f6e\u968f\u673a\u79cd\u5b50\u4ee5\u786e\u4fdd\u793a\u4f8b\u7684\u786e\u5b9a\u6027 values = np.random.rand(10) print(values) # [0.92961609 0.31637555 0.18391881 0.20456028 0.56772503 0.5955447 # 0.96451452 0.6531771 0.74890664 0.65356987] bins = [0, 0.2, 0.4, 0.6, 0.8, 1] result = pd.get_dummies(pd.cut(values, bins)) print(result) # (0.0, 0.2] (0.2, 0.4] (0.4, 0.6] (0.6, 0.8] (0.8, 1.0] # 0 0 0 0 0 1 # 1 0 1 0 0 0 # 2 1 0 0 0 0 # 3 0 1 0 0 0 # 4 0 0 1 0 0 # 5 0 0 1 0 0 # 6 0 0 0 0 1 # 7 0 0 0 1 0 # 8 0 0 0 1 0 # 9 0 0 0 1 0","title":"\u8ba1\u7b97\u6307\u6807/\u865a\u62df\u53d8\u91cf"},{"location":"python/DataAnalysis/ch04/#_14","text":"import re pandas\u5141\u8bb8\u5c06\u5b57\u7b26\u4e32\u548c\u6b63\u5219\u8868\u8fbe\u5f0f\u7b80\u6d01\u5730\u5e94\u7528\u5230\u6574\u4e2a\u6570\u636e\u6570\u7ec4\u4e0a\uff0c\u6b64\u5916\u8fd8\u80fd\u5904\u7406\u6570\u636e\u7f3a\u5931\u3002","title":"\u5b57\u7b26\u4e32\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch04/#_15","text":"\u5b57\u4e32\u62c6\u5206\u5408\u5e76\u65b9\u6cd5\u3002\u5728\u5f88\u591a\u5b57\u7b26\u4e32\u5904\u7406\u548c\u811a\u672c\u5e94\u7528\u4e2d\uff0c\u5185\u5efa\u7684\u5b57\u7b26\u4e32\u65b9\u6cd5\u662f\u8db3\u591f\u7684\u3002 \u4f8b\u5982\uff0c\u4e00\u4e2a\u9017\u53f7\u5206\u9694\u7684\u5b57\u7b26\u4e32\u53ef\u4ee5\u4f7f\u7528split\u65b9\u6cd5\u62c6\u5206\u6210\u591a\u5757\u3002 import numpy as np import pandas as pd val = 'a, b, guido' result = val.split(',') print(result) # ['a', ' b', ' guido'] count \uff1a\u8fd4\u56de\u5b50\u5b57\u7b26\u4e32\u5728\u5b57\u7b26\u4e32\u4e2d\u7684\u975e\u91cd\u53e0\u51fa\u73b0\u6b21\u6570\u3002 result = val.count(',') print(result) # 2 endswith \uff1a\u5982\u679c\u5b57\u7b26\u4e32\u4ee5\u540e\u7f00\u7ed3\u5c3e\u5219\u8fd4\u56de True \u3002 startswith \uff1a\u5982\u679c\u5b57\u7b26\u4e32\u4ee5\u540e\u7f00\u7ed3\u5c3e\u5219\u8fd4\u56de True \u3002 result = val.endswith('b') print(result) # False result = val.endswith('o') print(result) # True result = val.startswith('a') print(result) # True split \u5e38\u548c strip \u4e00\u8d77\u4f7f\u7528\uff0c\u7528\u4e8e\u6e05\u9664\u7a7a\u683c\uff08\u5305\u62ec\u6362\u884c\uff09\u3002 split \uff1a\u4f7f\u7528\u5206\u9694\u7b26\u8bb2\u5b57\u7b26\u4e32\u62c6\u5206\u6210\u5b50\u5b57\u7b26\u4e32\u7684\u5217\u8868\u3002 strip \uff0c rstrip \uff0c lstrip \uff1a\u4fee\u526a\u7a7a\u767d\uff0c\u5305\u62ec\u6362\u884c\u7b26\uff1b\u76f8\u5f53\u4e8e\u5bf9\u6bcf\u4e2a\u5143\u7d20\u8fdb\u884c x.strip() (\u4ee5\u53ca rstrip \uff0c lstrip )\u3002 pieces = [x.strip() for x in val.split(',')] print(pieces) # ['a', 'b', 'guido'] \u8fd9\u4e9b\u5b50\u5b57\u7b26\u4e32\u53ef\u4ee5\u4f7f\u7528\u52a0\u6cd5\u4e0e\u4e24\u4e2a\u5192\u53f7\u5206\u9694\u7b26\u8fde\u63a5\u5728\u4e00\u8d77\u3002 first, second, third = pieces result = first + '::' + second + '::' + third print(result) # a::b::guido \u4f46\u662f\u8fd9\u5e76\u4e0d\u662f\u4e00\u4e2a\u5b9e\u7528\u7684\u901a\u7528\u65b9\u6cd5\u3002 \u5728\u5b57\u7b26\u4e32 ': :' \u7684 join \u65b9\u6cd5\u4e2d\u4f20\u5165\u4e00\u4e2a\u5217\u8868\u6216\u5143\u7ec4\u662f\u4e00\u79cd\u66f4\u5feb\u4e14\u66f4\u52a0Pythonic\uff08Python\u98ce\u683c\u5316\uff09\u7684\u65b9\u6cd5\u3002 join : \u4f7f\u7528\u5b57\u7b26\u4e32\u5ea7\u4f4d\u95f4\u9694\u7b26\uff0c\u7528\u4e8e\u7c98\u5408\u5176\u4ed6\u5b57\u7b26\u4e32\u7684\u5e8f\u5217\u3002 result = '::'.join(pieces) print(result) # a::b::guido \u5b9a\u4f4d\u5b50\u5b57\u7b26\u4e32\u7684\u65b9\u6cd5\u3002 \u4f7f\u7528Python\u7684 in \u5173\u952e\u5b57\u662f\u68c0\u6d4b\u5b50\u5b57\u7b26\u4e32\u7684\u6700\u4f73\u65b9\u6cd5\uff0c\u5c3d\u7ba1 index \u548c find \u4e5f\u80fd\u5b9e\u73b0\u540c\u6837\u7684\u529f\u80fd\u3002 result = 'guido' in val print(result) # True index \uff1a\u5982\u679c\u5728\u5b57\u7b26\u4e32\u4e2d\u627e\u5230\uff0c\u5219\u8fd4\u56de\u5b50\u5b57\u7b26\u4e32\u4e2d\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u627e\u4e0d\u5230\u5219\u89e6\u53d1\u4e00\u4e2a ValueError \u3002 find \uff1a\u8fd4\u56de\u5b57\u7b26\u4e32\u4e2d\u7b2c\u4e00\u4e2a\u51fa\u73b0\u5b50\u5b57\u7b26\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u4f4d\u7f6e\uff0c\u7c7b\u4f3c index \uff0c\u5982\u679c\u6ca1\u6709\u627e\u5230\uff0c\u5219\u8fd4\u56de -1 \u3002 rfind \uff1a\u8fd4\u56de\u5b57\u7b26\u4e32\u4e2d\u5b50\u5b57\u7b26\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u65f6\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u627e\u5230\uff0c\u5219\u8fd4\u56de -1 \u3002 result = val.index(',') print(result) # 1 result = val.find(',') print(result) # 1 # result = val.index(':') print(result) # ValueError: substring not found result = val.find(':') print(result) # -1 result = val.rfind(',') print(result) # 4 replace \u5c06\u7528\u4e00\u79cd\u6a21\u5f0f\u66ff\u4ee3\u53e6\u4e00\u79cd\u6a21\u5f0f\u3002\u5b83\u4e5f\u7528\u4e8e\u4f20\u5165\u7a7a\u5b57\u7b26\u4e32\u6765\u5220\u9664\u67d0\u4e2a\u6a21\u5f0f\u3002 result = val.replace(',', '::') print(result) # a:: b:: guido result = val.replace(', ', '') print(result) # abguido result = val.replace(',', '') print(result) # a b guido lower \uff1a\u5c06\u5927\u5199\u5b57\u6bcd\u8f6c\u6362\u4e3a\u5c0f\u5199\u5b57\u6bcd\u3002 upper \uff1a\u5c06\u5c0f\u5199\u5b57\u6bcd\u8f6c\u6362\u4e3a\u5927\u5199\u5b57\u6bcd\u3002 uppers = val.upper() print(uppers) # A, B, GUIDO casefold \uff1a\u548c lower \u7c7b\u4f3c\uff0c\u5c06\u5b57\u7b26\u4e32\u4e2d\u7684\u5143\u7d20\u53d8\u6210\u5c0f\u5199\uff0c lower \u51fd\u6570\u53ea\u652f\u6301 ascill \u8868\u4e2d\u7684\u5b57\u7b26\uff0c casefold \u652f\u6301\u5f88\u591a\u4e0d\u540c\u79cd\u7c7b\u7684\u8bed\u8a00\u3002 str1 = \"Jan Wei\u03b2@cN\u4e0a\u6d77\" result = str1.casefold() print(result) # jan wei\u03b2@cn\u4e0a\u6d77 result = str1.lower() print(result) # jan wei\u03b2@cn\u4e0a\u6d77 ljust \uff0c rjust \uff1a\u5de6\u5bf9\u9f50\u6216\u8005\u53f3\u5bf9\u9f50\uff1b\u7528\u7a7a\u683c\u6216\u8005\u5176\u5b83\u4e00\u4e9b\u5b57\u7b26\u586b\u5145\u5b57\u7b26\u4e32\u7684\u76f8\u53cd\u4fa7\uff0c\u4ee5\u8fd4\u56de\u5177\u6709\u6700\u5c0f\u5bbd\u5ea6\u7684\u5b57\u7b26\u4e32 str1 = 'https://docs.python.org/3/' str2 = 'https://packagehub.suse.com/package-categories/python/' print(str1.ljust(60, '*')) print(str2.ljust(60, '*')) # https://docs.python.org/3/********************************** # https://packagehub.suse.com/package-categories/python/****** print(str1.rjust(60, '*')) print(str2.rjust(60, '*')) # **********************************https://docs.python.org/3/ # ******https://packagehub.suse.com/package-categories/python/ print(str1.rjust(60)) print(str2.rjust(60))","title":"\u5b57\u7b26\u4e32\u5bf9\u8c61\u65b9\u6cd5"},{"location":"python/DataAnalysis/ch04/#_16","text":"Python\u5185\u5efa\u7684 re \u6a21\u5757\u662f\u7528\u4e8e\u5c06\u6b63\u5219\u8868\u8fbe\u5f0f\u5e94\u7528\u5230\u5b57\u7b26\u4e32\u4e0a\u7684\u5e93\u3002 re \u6a21\u5757\u4e3b\u8981\u6709\u4e09\u4e2a\u4e3b\u9898\uff1a\u6a21\u5f0f\u5339\u914d\u3001\u66ff\u4ee3\u3001\u62c6\u5206\u3002 \u770b\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\uff1a\u5047\u8bbe\u6211\u4eec\u60f3\u5c06\u542b\u6709\u591a\u79cd\u7a7a\u767d\u5b57\u7b26\uff08\u5236\u8868\u7b26\u3001\u7a7a\u683c\u3001\u6362\u884c\u7b26\uff09\u7684\u5b57\u7b26\u4e32\u62c6\u5206\u5f00\u3002 \u63cf\u8ff0\u4e00\u4e2a\u6216\u591a\u4e2a\u7a7a\u767d\u5b57\u7b26\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u662f \\s+ \u3002 \u5f53\u8c03\u7528 re.split('\\s+', text) \uff0c\u6b63\u5219\u8868\u8fbe\u5f0f\u9996\u5148\u4f1a\u88ab\u7f16\u8bd1\uff0c\u7136\u540e\u6b63\u5219\u8868\u8fbe\u5f0f\u7684 split \u65b9\u6cd5\u5728\u4f20\u5165\u6587\u672c\u4e0a\u88ab\u8c03\u7528\u3002 text = \"foo bar\\t baz \\tqux\" result = re.split('\\s+', text) print(result) # ['foo', 'bar', 'baz', 'qux'] \u53ef\u4ee5\u4f7f\u7528 re.compile \u81ea\u884c\u7f16\u8bd1\uff0c\u5f62\u6210\u4e00\u4e2a\u53ef\u590d\u7528\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u5bf9\u8c61\u3002 regex = re.compile('\\s+') result = regex.split(text) print(result) # ['foo', 'bar', 'baz', 'qux'] \u5982\u679c\u60f3\u83b7\u5f97\u7684\u662f\u4e00\u4e2a\u6240\u6709\u5339\u914d\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u6a21\u5f0f\u7684\u5217\u8868\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 findall \u65b9\u6cd5\u3002 result = regex.findall(text) print(result) # [' ', '\\t ', ' \\t'] \u4e3a\u4e86\u5728\u6b63\u5219\u8868\u8fbe\u5f0f\u4e2d\u907f\u514d\u8f6c\u4e49\u7b26 \\ \u7684\u5f71\u54cd\uff0c\u53ef\u4ee5\u4f7f\u7528\u539f\u751f\u5b57\u7b26\u4e32\u8bed\u6cd5\uff0c\u6bd4\u5982 r'C:\\x' \u6216\u8005\u7528\u7b49\u4ef7\u7684 'C:\\\\x'\\ \u3002 \u5982\u679c\u9700\u8981\u5c06\u76f8\u540c\u7684\u8868\u8fbe\u5f0f\u5e94\u7528\u5230\u591a\u4e2a\u5b57\u7b26\u4e32\u4e0a\uff0c\u63a8\u8350\u4f7f\u7528 re.compile \u521b\u5efa\u4e00\u4e2a\u6b63\u5219\u8868\u8fbe\u5f0f\u5bf9\u8c61\uff0c\u8fd9\u6837\u505a\u6709\u5229\u4e8e\u8282\u7ea6CPU\u5468\u671f\u3002 match \u548c search \u4e0e findall \u76f8\u5173\u6027\u5f88\u5927\u3002 findall \u8fd4\u56de\u7684\u662f\u5b57\u7b26\u4e32\u4e2d\u6240\u6709\u7684\u5339\u914d\u9879\uff0c\u800c search \u8fd4\u56de\u7684\u4ec5\u4ec5\u662f\u7b2c\u4e00\u4e2a\u5339\u914d\u9879\u3002 match \u66f4\u4e3a\u4e25\u683c\uff0c\u5b83\u53ea\u5728\u5b57\u7b26\u4e32\u7684\u8d77\u59cb\u4f4d\u7f6e\u8fdb\u884c\u5339\u914d\u3002 text = \"\"\"Dave dave@google.com Steve steve@gmail.com Rob rob@gmail.com Ryan ryan@yahoo.com \"\"\" pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}' regex = re.compile(pattern, flags=re.IGNORECASE) # flags=re.IGNORECASE \u4f7f\u6b63\u5219\u8868\u8fbe\u5f0f\u4e0d\u533a\u5206\u5927\u5c0f\u5199 m = regex.findall(text) # findall\u4f1a\u751f\u6210\u4e00\u4e2a\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u7684\u5217\u8868 print(m) # ['dave@google.com', 'steve@gmail.com', 'rob@gmail.com', 'ryan@yahoo.com'] search \u8fd4\u56de\u7684\u662f\u6587\u672c\u4e2d\u7b2c\u4e00\u4e2a\u5339\u914d\u5230\u7684\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u3002 \u5bf9\u4e8e\u524d\u9762\u63d0\u5230\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\uff0c\u5339\u914d\u5bf9\u8c61\u53ea\u80fd\u544a\u8bc9\u6211\u4eec\u6a21\u5f0f\u5728\u5b57\u7b26\u4e32\u4e2d\u8d77\u59cb\u548c\u7ed3\u675f\u7684\u4f4d\u7f6e\u3002 m = regex.search(text) print(m) # print(text[m.start():m.end()]) # dave@google.com regex.match \u53ea\u5728\u6a21\u5f0f\u51fa\u73b0\u4e8e\u5b57\u7b26\u4e32\u8d77\u59cb\u4f4d\u7f6e\u65f6\u8fdb\u884c\u5339\u914d\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u5230\uff0c\u8fd4\u56de None \u3002 m = regex.match(text) print(m) # None m = regex.match('rob@gmail.com') print(m) # print(m.group()) # rob@gmail.com print(m.groups()) # () regex.sub \u4f1a\u8fd4\u56de\u4e00\u4e2a\u65b0\u7684\u5b57\u7b26\u4e32\uff0c\u539f\u5b57\u7b26\u4e32\u4e2d\u7684\u6a21\u5f0f\u4f1a\u88ab\u4e00\u4e2a\u65b0\u7684\u5b57\u7b26\u4e32\u66ff\u4ee3\u3002 m = regex.sub('REDACTED', text) print(m) # Dave REDACTED # Steve REDACTED # Rob REDACTED # Ryan REDACTED \u67e5\u627e\u7535\u5b50\u90ae\u4ef6\u5730\u5740\uff0c\u5e76\u5c06\u6bcf\u4e2a\u5730\u5740\u5206\u4e3a\u4e09\u4e2a\u90e8\u5206\uff1a\u7528\u6237\u540d\uff0c\u57df\u540d\u548c\u57df\u540d\u540e\u7f00\u3002\u8981\u5b9e\u73b0\u8fd9\u4e00\u70b9\uff0c\u53ef\u4ee5\u7528\u62ec\u53f7\u5c06 pattern \u5305\u8d77\u6765\u3002 \u4fee\u6539\u540e\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u4ea7\u751f\u7684\u5339\u914d\u5bf9\u8c61\u7684 groups \u65b9\u6cd5\uff0c\u8fd4\u56de\u7684\u662f\u6a21\u5f0f\u7ec4\u4ef6\u7684\u5143\u7ec4\u3002 text = \"\"\"Dave dave@google.com Steve steve@gmail.com Rob rob@gmail.com Ryan ryan@yahoo.com \"\"\" pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\\.([A-Z]{2,4})' regex = re.compile(pattern, flags=re.IGNORECASE) m = regex.findall(text) # \u5f53pattern\u53ef\u4ee5\u5206\u7ec4\u65f6\uff0cfindall\u8fd4\u56de\u7684\u662f\u5305\u542b\u5143\u7ec4\u7684\u5217\u8868 print(m) # [('dave', 'google', 'com'), ('steve', 'gmail', 'com'), ('rob', 'gmail', 'com'), ('ryan', 'yahoo', 'com')] m = regex.search(text) print(m) # print(text[m.start():m.end()]) # dave@google.com m = regex.match('rob@gmail.com') print(m) # print(m.group()) # rob@gmail.com print(m.groups()) # ('rob', 'gmail', 'com') m = regex.sub('REDACTED', text) print(m) # Dave REDACTED # Steve REDACTED # Rob REDACTED # Ryan REDACTED m = regex.sub(r'Username: \\1, Domain: \\2, Suffix: \\3', text) print(m) # Dave Username: dave, Domain: google, Suffix: com # Steve Username: steve, Domain: gmail, Suffix: com # Rob Username: rob, Domain: gmail, Suffix: com # Ryan Username: ryan, Domain: yahoo, Suffix: com","title":"\u6b63\u5219\u8868\u8fbe\u5f0f"},{"location":"python/DataAnalysis/ch04/#pandas","text":"\u6e05\u7406\u6742\u4e71\u7684\u6570\u636e\u96c6\u7528\u4e8e\u5206\u6790\u901a\u5e38\u9700\u8981\u5927\u91cf\u7684\u5b57\u7b26\u4e32\u5904\u7406\u548c\u6b63\u5219\u5316\u3002 data = { 'Dave': 'dave@gmail.com', 'Steve': 'steve@gmail.com', 'Rob': 'rob@gmail.com', 'Wes': np.nan } data = pd.Series(data) print(data) # Dave dave@gmail.com # Steve steve@gmail.com # Rob rob@gmail.com # Wes NaN # dtype: object print(data.isnull()) # Dave False # Steve False # Rob False # Wes True # dtype: bool \u53ef\u4ee5\u4f7f\u7528 data.map \u5c06\u5b57\u7b26\u4e32\u548c\u6709\u6548\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u65b9\u6cd5\uff08\u4ee5 lambda \u6216\u5176\u4ed6\u51fd\u6570\u7684\u65b9\u5f0f\u4f20\u9012\uff09\u5e94\u7528\u5230\u6bcf\u4e2a\u503c\u4e0a\uff0c\u4f46\u662f\u5728 NA \uff08 null \uff09\u503c\u4e0a\u4f1a\u5931\u8d25\u3002 \u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0cSeries\u6709\u9762\u5411\u6570\u7ec4\u7684\u65b9\u6cd5\u7528\u4e8e\u8df3\u8fc7 NA \u503c\u7684\u5b57\u7b26\u4e32\u64cd\u4f5c\u3002\u8fd9\u4e9b\u65b9\u6cd5\u901a\u8fc7Series\u7684 str \u5c5e\u6027\u8fdb\u884c\u8c03\u7528\u3002 \u4f8b\u5982\uff0c\u53ef\u4ee5\u901a\u8fc7 str.contains \u6765\u68c0\u67e5\u6bcf\u4e2a\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u662f\u5426\u542b\u6709 'gmail' \u3002 m = data.str.contains('gmail') print(m) # Dave True # Steve True # Rob True # Wes NaN # dtype: object \u6b63\u5219\u8868\u8fbe\u5f0f\u4e5f\u53ef\u4ee5\u7ed3\u5408\u4efb\u610f\u7684 re \u6a21\u5757\u9009\u9879\u4f7f\u7528\uff0c\u4f8b\u5982 IGNORECASE \u3002 print(pattern) # ([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\\.([A-Z]{2,4}) m = data.str.findall(pattern, flags=re.IGNORECASE) print(m) # Dave [(dave, gmail, com)] # Steve [(steve, gmail, com)] # Rob [(rob, gmail, com)] # Wes NaN # dtype: object \u4f7f\u7528 str.get \u6216\u5728 str \u5c5e\u6027\u5185\u90e8\u7d22\u5f15\uff0c\u8fdb\u884c\u5411\u91cf\u5316\u7684\u5143\u7d20\u68c0\u7d22\u3002 m = data.str.match(pattern, flags=re.IGNORECASE) print(m) # Dave True # Steve True # Rob True # Wes NaN # dtype: object m = data.str.findall(pattern, flags=re.IGNORECASE) print(m.str.get(1)) # Dave NaN # Steve NaN # Rob NaN # Wes NaN # dtype: float64 print(m.str[0]) # Dave (dave, gmail, com) # Steve (steve, gmail, com) # Rob (rob, gmail, com) # Wes NaN # dtype: object \u4f7f\u7528\u5b57\u7b26\u4e32\u5207\u7247\u7684\u7c7b\u4f3c\u8bed\u6cd5\u8fdb\u884c\u5411\u91cf\u5316\u5207\u7247\u3002 print(data.str[:]) # Dave dave@gmail.com # Steve steve@gmail.com # Rob rob@gmail.com # Wes NaN # dtype: object print(data.str[:5]) # Dave dave@ # Steve steve # Rob rob@g # Wes NaN # dtype: object","title":"pandas\u4e2d\u7684\u5411\u91cf\u5316\u5b57\u7b26\u4e32\u51fd\u6570"},{"location":"python/DataAnalysis/ch05/","text":"\u6570\u636e\u89c4\u6574\uff1a\u8fde\u63a5\u3001\u8054\u5408\u4e0e\u91cd\u5851 \u00b6 \u5206\u5c42\u7d22\u5f15 \u00b6 import pandas as pd import numpy as np import re \u5206\u5c42\u7d22\u5f15\u662fpandas\u7684\u91cd\u8981\u7279\u6027\uff0c\u5141\u8bb8\u4f60\u5728\u4e00\u4e2a\u8f74\u5411\u4e0a\u62e5\u6709\u591a\u4e2a\uff08\u4e24\u4e2a\u6216\u4e24\u4e2a\u4ee5\u4e0a\uff09\u7d22\u5f15\u5c42\u7ea7\u3002 \u5206\u5c42\u7d22 import re \u5f15\u63d0\u4f9b\u4e86\u4e00\u79cd\u5728\u66f4\u4f4e\u7ef4\u5ea6\u7684\u5f62\u5f0f\u4e2d\u5904\u7406\u66f4\u9ad8\u7ef4\u5ea6\u6570\u636e\u7684\u65b9\u5f0f\u3002 Series\u7d22\u5f15\u5206\u5c42 \u00b6 data = pd.Series( np.random.randn(9), index=[['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'], [1, 2, 3, 1, 3, 1, 2, 2, 3]] ) \u8f93\u51fa\u662f\u4e00\u4e2a\u4ee5 MultiIndex \u4f5c\u4e3a\u7d22\u5f15\u7684Series\u7684\u7f8e\u5316\u89c6\u56fe\u3002 \u7d22\u5f15\u4e2d\u7684\"\u95f4\u9699\"\u8868\u793a\"\u76f4\u63a5\u4f7f\u7528\u4e0a\u9762\u7684\u6807\u7b7e\"\u3002 print(data) # a 1 0.163468 # 2 -1.525926 # 3 -0.210247 # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # d 2 0.034305 # 3 -0.896078 # dtype: float64 print(data.index) # MultiIndex([('a', 1), # ('a', 2), # ('a', 3), # ('b', 1), # ('b', 3), # ('c', 1), # ('c', 2), # ('d', 2), # ('d', 3)], # ) \u901a\u8fc7\u5206\u5c42\u7d22\u5f15\u5bf9\u8c61\uff0c\u4e5f\u53ef\u4ee5\u79f0\u4e3a\u90e8\u5206\u7d22\u5f15\uff0c\u53ef\u4ee5\u7b80\u6d01\u5730\u9009\u62e9\u51fa\u6570\u636e\u7684\u5b50\u96c6\u3002 m = data['b'] print(m) # 1 -0.956063 # 3 -1.839111 # dtype: float64 m = data['b': 'c'] print(m) # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # dtype: float64 m = data.loc[['b', 'c']] print(m) # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # dtype: float64 m = data.loc[:, 2] print(m) # a -1.525926 # c 0.595279 # d 0.034305 # dtype: float64 \u5206\u5c42\u7d22\u5f15\u5728\u91cd\u5851\u6570\u636e\u548c\u6570\u7ec4\u900f\u89c6\u8868\u7b49\u5206\u7ec4\u64cd\u4f5c\u4e2d\u626e\u6f14\u4e86\u91cd\u8981\u89d2\u8272\u3002 \u4f8b\u5982\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 unstack \u65b9\u6cd5\u5c06\u6570\u636e\u5728DataFrame\u4e2d\u91cd\u65b0\u6392\u5217\u3002 m = data.unstack() print(m) # 1 2 3 # a 0.163468 -1.525926 -0.210247 # b -0.956063 NaN -1.839111 # c -0.398905 0.595279 NaN # d NaN 0.034305 -0.896078 n = m.stack() print(n) # \u6216\u8005 print(data.unstack().stack()) # a 1 0.163468 # 2 -1.525926 # 3 -0.210247 # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # d 2 0.034305 # 3 -0.896078 # dtype: float64 DataFrame\u7d22\u5f15\u5206\u5c42 \u00b6 \u5728DataFrame\u4e2d\uff0c\u6bcf\u4e2a\u8f74\u90fd\u53ef\u4ee5\u62e5\u6709\u5206\u5c42\u7d22\u5f15\u3002 \u53c2\u8003 \u65b9\u6cd51\uff1a\u76f4\u63a5\u521b\u5efa \u00b6 \u76f4\u63a5\u901a\u8fc7\u7ed9 index \uff08columns\uff09\u53c2\u6570\u4f20\u9012\u591a\u7ef4\u6570\u7ec4\uff0c\u8fdb\u800c\u6784\u5efa\u591a\u7ef4\u7d22\u5f15\u3002 \u6570\u7ec4\u4e2d\u6bcf\u4e2a\u7ef4\u5ea6\u5bf9\u5e94\u4f4d\u7f6e\u7684\u5143\u7d20\uff0c\u7ec4\u6210\u6bcf\u4e2a\u7d22\u5f15\u503c\u3002 frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]], columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) print(frame) # Ohio Colorado # Green Red Green # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 \u4e0a\u9762\u8f93\u51fa\u4e2d\u76842\u4e2a\u5c42\u7ea7\u662f\u6ca1\u6709\u540d\u5b57\u3002 \u5206\u5c42\u7684\u5c42\u7ea7\u53ef\u4ee5\u6709\u540d\u79f0\uff08\u53ef\u4ee5\u662f\u5b57\u7b26\u4e32\u6216Python\u5bf9\u8c61\uff09\u3002 \u5982\u679c\u5c42\u7ea7\u6709\u540d\u79f0\uff0c\u8fd9\u4e9b\u540d\u79f0\u4f1a\u5728\u63a7\u5236\u53f0\u8f93\u51fa\u4e2d\u663e\u793a\u3002 print(frame.index.names) # [None, None] print(frame.columns.names) # [None, None] \u7ed9\u5c42\u7ea7\u8d4b\u4e88\u540d\u79f0\u3002\u6ce8\u610f\u533a\u5206\u884c\u6807\u7b7e\u4e2d\u7684\u7d22\u5f15\u540d\u79f0 state \u548c color \u3002 frame.index.names = ['key1', 'key2'] frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 print(frame['Ohio']) # color Green Red # key1 key2 # a 1 0 1 # 2 3 4 # b 1 6 7 # 2 9 10 print(frame.index) # MultiIndex([('a', 1), # ('a', 2), # ('b', 1), # ('b', 2)], # names=['key1', 'key2']) \u901a\u8fc7 MultiIndex \u7c7b\u7684\u76f8\u5173\u65b9\u6cd5\uff0c\u9884\u5148\u521b\u5efa\u4e00\u4e2a MultiIndex \u5bf9\u8c61\uff0c\u7136\u540e\u4f5c\u4e3aSeries\u4e0eDataFrame\u4e2d\u7684 index \uff08\u6216columns\uff09\u53c2\u6570\u503c\u3002\u540c\u65f6\uff0c\u53ef\u4ee5\u901a\u8fc7 names \u53c2\u6570\u6307\u5b9a\u591a\u5c42\u7d22\u5f15\u7684\u540d\u79f0\u3002 \u65b9\u6cd52\uff1afrom_arrays \u00b6 from_arrays \uff1a\u63a5\u6536\u4e00\u4e2a\u591a\u7ef4\u6570\u7ec4\u53c2\u6570\uff0c\u9ad8\u7ef4\u6307\u5b9a\u9ad8\u5c42\u7d22\u5f15\uff0c\u4f4e\u7ef4\u6307\u5b9a\u5e95\u5c42\u7d22\u5f15\u3002 mindex = pd.MultiIndex.from_arrays( [['a', 'a', 'b', 'b'], [1, 2, 1, 2]], names=['key1', 'key2'] ) frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=mindex, columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 \u65b9\u6cd53\uff1afrom_tuples \u00b6 from_tuples \uff1a\u63a5\u6536\u4e00\u4e2a\u5143\u7ec4\u7684\u5217\u8868\uff0c\u6bcf\u4e2a\u5143\u7ec4\u6307\u5b9a\u6bcf\u4e2a\u7d22\u5f15\uff08\u9ad8\u7ef4\u7d22\u5f15\uff0c\u4f4e\u7ef4\u7d22\u5f15\uff09\u3002 mindex = pd.MultiIndex.from_tuples( [('a', 1), ('a', 2), ('b', 1), ('b', 2)] ) frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=mindex, columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) frame.index.names = ['key1', 'key2'] frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 \u65b9\u6cd54\uff1afrom_product \u00b6 from_product \uff1a\u63a5\u6536\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u7684\u5217\u8868\uff0c\u6839\u636e\u591a\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u5143\u7d20\u7684\u7b1b\u5361\u5c14\u79ef\u8fdb\u884c\u521b\u5efa\u7d22\u5f15\u3002 \u4f7f\u7528\u7b1b\u5361\u5c14\u79ef\u7684\u65b9\u5f0f\u6765\u521b\u5efa\u591a\u5c42\u7d22\u5f15\u3002\u53c2\u6570\u4e3a\u5d4c\u5957\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002\u7ed3\u679c\u4e3a\u4f7f\u7528\u6bcf\u4e2a\u4e00\u7ef4\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u4e0e\u5176\u4ed6\u4e00\u7ef4\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u6765\u751f\u6210\u3002 \u7b1b\u5361\u5c14\u79ef\u7684\u65b9\u5f0f\u7684\u5c40\u9650\uff1a\u4e24\u4e24\u7ec4\u5408\u5fc5\u987b\u90fd\u5b58\u5728\uff0c\u5426\u5219\uff0c\u5c31\u4e0d\u80fd\u4f7f\u7528\u8fd9\u79cd\u65b9\u5f0f\u3002 mindex = pd.MultiIndex.from_product( [['a', 'b'], ['1', '2']], names=['key1', 'key2'] ) frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=mindex, columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 \u91cd\u6392\u5e8f\u548c\u5c42\u7ea7\u6392\u5e8f \u00b6 \u5982\u679c\u9700\u8981\u91cd\u65b0\u6392\u5217\u8f74\u4e0a\u7684\u5c42\u7ea7\u987a\u5e8f\uff0c\u6216\u8005\u6309\u7167\u7279\u5b9a\u5c42\u7ea7\u7684\u503c\u5bf9\u6570\u636e\u8fdb\u884c\u6392\u5e8f\uff0c \u53ef\u4ee5\u901a\u8fc7swaplevel\u63a5\u6536\u4e24\u4e2a\u5c42\u7ea7\u5e8f\u53f7\u6216\u5c42\u7ea7\u540d\u79f0\uff0c\u8fd4\u56de\u4e00\u4e2a\u8fdb\u884c\u4e86\u5c42\u7ea7\u53d8\u66f4\u7684\u65b0\u5bf9\u8c61\uff08\u4f46\u662f\u6570\u636e\u662f\u4e0d\u53d8\u7684\uff09\u3002 print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 m = frame.swaplevel('key1', 'key2') print(m) # state Ohio Colorado # color Green Red Green # key2 key1 # 1 a 0 1 2 # 2 a 3 4 5 # 1 b 6 7 8 # 2 b 9 10 11 sort_index \u53ea\u80fd\u5728\u5355\u4e00\u5c42\u7ea7\u4e0a\u5bf9\u6570\u636e\u8fdb\u884c\u6392\u5e8f\u3002 \u5728\u8fdb\u884c\u5c42\u7ea7\u53d8\u6362\u65f6\uff0c\u4f7f\u7528 sort_index \u4ee5\u4f7f\u5f97\u7ed3\u679c\u6309\u7167\u5c42\u7ea7\u8fdb\u884c\u5b57\u5178\u6392\u5e8f\u3002 m = frame.sort_index(level=1) # \u5bf9key2\u6392\u5e8f\uff0c\u5e95\u5c42\u7d22\u5f15 print(m) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # b 1 6 7 8 # a 2 3 4 5 # b 2 9 10 11 m = frame.sort_index(level=0) # \u5bf9key1\u6392\u5e8f\uff0c\u9ad8\u5c42\u7d22\u5f15 print(m) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 m = frame.swaplevel(0, 1).sort_index(level=1) # swaplevel(0, 1)\u7b49\u540c\u4e8eswaplevel(key1, key2)\uff0c\u4ea4\u6362\u540ekey1\u53d8\u6210\u4e86\u5e95\u5c42\u7d22\u5f15 print(m) # state Ohio Colorado # color Green Red Green # key2 key1 # 1 a 0 1 2 # 2 a 3 4 5 # 1 b 6 7 8 # 2 b 9 10 11 \u6309\u5c42\u7ea7\u8fdb\u884c\u6c47\u603b\u7edf\u8ba1 \u00b6 DataFrame\u548cSeries\u4e2d\u5f88\u591a\u63cf\u8ff0\u6027\u548c\u6c47\u603b\u6027\u7edf\u8ba1\u6709\u4e00\u4e2a level \u9009\u9879\uff0c\u901a\u8fc7 level \u9009\u9879\u4f60\u53ef\u4ee5\u6307\u5b9a\u4f60\u60f3\u8981\u5728\u67d0\u4e2a\u7279\u5b9a\u7684\u8f74\u4e0a\u8fdb\u884c\u805a\u5408\u3002 print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 m = frame.groupby(level='key2').sum() print(m) # state Ohio Colorado # color Green Red Green # key2 # 1 6 8 10 # 2 12 14 16 m = frame.groupby(level='color', axis=1).sum() print(m) # color Green Red # key1 key2 # a 1 2 1 # 2 8 4 # b 1 14 7 # 2 20 10 \u4f7f\u7528DataFrame\u7684\u5217\u8fdb\u884c\u7d22\u5f15 \u00b6 \u901a\u5e38\u6211\u4eec\u4e0d\u4f1a\u4f7f\u7528DataFrame\u4e2d\u4e00\u4e2a\u6216\u591a\u4e2a\u5217\u4f5c\u4e3a\u884c\u7d22\u5f15\uff1b\u53cd\u800c\u4f60\u53ef\u80fd\u60f3\u8981\u5c06\u884c\u7d22\u5f15\u79fb\u52a8\u5230DataFrame\u7684\u5217\u4e2d\u3002 frame = pd.DataFrame( {'a': range(7), 'b': range(7, 0, -1), 'c': ['one', 'one', 'one', 'two', 'two', 'two', 'two'], 'd': [0, 1, 2, 0, 1, 2, 3] } ) print(frame) # a b c d # 0 0 7 one 0 # 1 1 6 one 1 # 2 2 5 one 2 # 3 3 4 two 0 # 4 4 3 two 1 # 5 5 2 two 2 # 6 6 1 two 3 DataFrame\u7684 set_index \u51fd\u6570\u4f1a\u751f\u6210\u4e00\u4e2a\u65b0\u7684DataFrame\uff0c\u65b0\u7684DataFrame\u4f7f\u7528\u4e00\u4e2a\u6216\u591a\u4e2a\u5217\u4f5c\u4e3a\u7d22\u5f15\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\u8fd9\u4e9b\u7d22\u5f15\u5217\u4f1a\u4eceDataFrame\u4e2d\u79fb\u9664\uff0c\u4e5f\u53ef\u4ee5\u5c06\u5b83\u4eec\u7559\u5728DataFrame\u4e2d\u3002 frame2 = frame.set_index(['c', 'd'], drop=False) print(frame2) # a b c d # c d # one 0 0 7 one 0 # 1 1 6 one 1 # 2 2 5 one 2 # two 0 3 4 two 0 # 1 4 3 two 1 # 2 5 2 two 2 # 3 6 1 two 3 frame2 = frame.set_index(['c', 'd']) print(frame2) # a b # c d # one 0 0 7 # 1 1 6 # 2 2 5 # two 0 3 4 # 1 4 3 # 2 5 2 # 3 6 1 reset_index \u662f set_index \u7684\u53cd\u64cd\u4f5c\uff0c\u5206\u5c42\u7d22\u5f15\u7684\u7d22\u5f15\u5c42\u7ea7\u4f1a\u88ab\u79fb\u52a8\u5230\u5217\u4e2d\u3002 \u6ce8\u610f\uff1a\u5982\u679c\u5728 set_index \u65f6\u4f7f\u7528\u4e86 drop=False \uff0c\u5728\u4f7f\u7528 reset_index \u4f1a\u62a5\u9519\u3002 m = frame2.reset_index() print(m) # c d a b # 0 one 0 0 7 # 1 one 1 1 6 # 2 one 2 2 5 # 3 two 0 3 4 # 4 two 1 4 3 # 5 two 2 5 2 # 6 two 3 6 1 \u8054\u5408\u4e0e\u5408\u5e76\u6570\u636e\u96c6 \u00b6 \u5305\u542b\u5728pandas\u5bf9\u8c61\u7684\u6570\u636e\u53ef\u4ee5\u901a\u8fc7\u591a\u79cd\u65b9\u5f0f\u8054\u5408\u5728\u4e00\u8d77\uff1a pandas.merge \u6839\u636e\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u5c06\u884c\u8fdb\u884c\u8fde\u63a5\u3002\u5bf9\u4e8eSQL\u6216\u5176\u4ed6\u5173\u7cfb\u578b\u6570\u636e\u5e93\u7684\u7528\u6237\u6765\u8bf4\uff0c\u8fd9\u79cd\u65b9\u5f0f\u6bd4\u8f83\u719f\u6089\uff0c\u5b83\u5b9e\u73b0\u7684\u662f\u6570\u636e\u5e93\u7684\u8fde\u63a5\u64cd\u4f5c\u3002 pandas.concat \u4f7f\u5bf9\u8c61\u5728\u8f74\u5411\u4e0a\u8fdb\u884c\u9ecf\u5408\u6216\u201c\u5806\u53e0\u201d\u3002 combine_first \u5b9e\u4f8b\u65b9\u6cd5\u5141\u8bb8\u5c06\u91cd\u53e0\u7684\u6570\u636e\u62fc\u63a5\u5728\u4e00\u8d77\uff0c\u4ee5\u4f7f\u7528\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u7684\u503c\u586b\u5145\u53e6\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u7684\u7f3a\u5931\u503c\u3002 \u6570\u636e\u5e93\u98ce\u683c\u7684DataFrame\u8fde\u63a5 \u00b6 \u5408\u5e76\u6216\u8fde\u63a5\u64cd\u4f5c\u901a\u8fc7\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u8fde\u63a5\u884c\u6765\u8054\u5408\u6570\u636e\u96c6\u3002 \u8fd9\u4e9b\u64cd\u4f5c\u662f\u5173\u7cfb\u578b\u6570\u636e\u5e93\u7684\u6838\u5fc3\u5185\u5bb9\uff08\u4f8b\u5982\u57fa\u4e8eSQL\u7684\u6570\u636e\u5e93\uff09\u3002 pandas\u4e2d\u7684 merge \u51fd\u6570\u4e3b\u8981\u7528\u4e8e\u5c06\u5404\u79cd join \u64cd\u4f5c\u7b97\u6cd5\u8fd0\u7528\u5728\u6570\u636e\u4e0a\u3002 \u5728\u8fdb\u884c\u5217-\u5217\u8fde\u63a5\u65f6\uff0c\u4f20\u9012\u7684DataFrame\u7d22\u5f15\u5bf9\u8c61\u4f1a\u88ab\u4e22\u5f03\u3002 \u5408\u5e76\u64cd\u4f5c\u4e5f\u8981\u8003\u8651\u5982\u4f55\u5904\u7406\u91cd\u53e0\u7684\u5217\u540d( suffixes \u540e\u7f00\u9009\u9879)\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u591a\u5bf9\u4e00\u8fde\u63a5\u7684\u4f8b\u5b50\u3002 df1 \u7684\u6570\u636e\u6709\u591a\u4e2a\u884c\u7684\u6807\u7b7e\u4e3a a \u548c b \uff0c\u800c df2 \u5728 key \u5217\u4e2d\u6bcf\u4e2a\u503c\u4ec5\u6709\u4e00\u884c\u3002 df1 = pd.DataFrame( { 'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7) } ) df2 = pd.DataFrame( { 'key': ['a', 'b', 'd'], 'data1': range(3) } ) print(df1) # key data1 # 0 b 0 # 1 b 1 # 2 a 2 # 3 c 3 # 4 a 4 # 5 a 5 # 6 b 6 print(df2) # key data1 # 0 a 0 # 1 b 1 # 2 d 2 \u8c03\u7528 merge \u5904\u7406\uff0c\u63a8\u8350\u663e\u5f0f\u5730\u6307\u5b9a\u8fde\u63a5\u952e\u3002 result = pd.merge(df1, df2) print(result) # key data1 # 0 b 1 result = pd.merge(df1, df2, on=['key', 'data1']) print(result) # key data1 # 0 b 1 result = pd.merge(df1, df2, on='key') print(result) # key data1_x data1_y # 0 b 0 1 # 1 b 1 1 # 2 b 6 1 # 3 a 2 0 # 4 a 4 0 # 5 a 5 0 \u5982\u679c\u6bcf\u4e2a\u5bf9\u8c61\u7684\u5217\u540d\u662f\u4e0d\u540c\u7684\uff0c\u53ef\u4ee5\u5206\u522b\u4e3a\u5b83\u4eec\u6307\u5b9a\u5217\u540d\u3002 df3 = pd.DataFrame( { 'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7) } ) df4 = pd.DataFrame( { 'rkey': ['a', 'b', 'd'], 'data2': range(3) } ) print(df3) # lkey data1 # 0 b 0 # 1 b 1 # 2 a 2 # 3 c 3 # 4 a 4 # 5 a 5 # 6 b 6 print(df4) # rkey data2 # 0 a 0 # 1 b 1 # 2 d 2 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c merge \u505a\u7684\u662f\u5185\u8fde\u63a5\uff08'inner' join\uff09\uff0c\u7ed3\u679c\u4e2d\u7684\u952e\u662f\u4e24\u5f20\u8868\u7684\u4ea4\u96c6\u3002 result = pd.merge(df3, df4, left_on='lkey', right_on='rkey') # df4\u7684[a,0]\u5bf9\u5e94df3\u7684\u6240\u6709[a,?]\u8bb0\u5f55\uff08\u901a\u8fc7\u91cd\u590d\u6765\u586b\u5145\u4e0d\u8db3\uff09 print(result) # lkey data1 rkey data2 # 0 b 0 b 1 # 1 b 1 b 1 # 2 b 6 b 1 # 3 a 2 a 0 # 4 a 4 a 0 # 5 a 5 a 0 \u5916\u8fde\u63a5\uff08outer join\uff09\u662f\u952e\u7684\u5e76\u96c6\uff0c\u8054\u5408\u4e86\u5de6\u8fde\u63a5\u548c\u53f3\u8fde\u63a5\u7684\u6548\u679c\u3002 \u591a\u5bf9\u591a\u8fde\u63a5\u662f\u884c\u7684\u7b1b\u5361\u5c14\u79ef\u3002 df1 = pd.DataFrame( { 'key': ['b', 'b', 'a', 'c', 'a', 'b'], 'data1': range(6) } ) df2 = pd.DataFrame( { 'key': ['a', 'b', 'a', 'b', 'd'], 'data2': range(5) } ) print(df1.sort_values(by='key')) # key data1 # 2 a 2 # 4 a 4 # 0 b 0 # 1 b 1 # 5 b 5 # 3 c 3 print(df2.sort_values(by='key')) # key data2 # 0 a 0 # 2 a 2 # 1 b 1 # 3 b 3 # 4 d 4 result = pd.merge(df1, df2, on='key', how='left') print(result.sort_values(by='key')) # key data1 data2 # 4 a 2 0.0 # 5 a 2 2.0 # 7 a 4 0.0 # 8 a 4 2.0 # 0 b 0 1.0 # 1 b 0 3.0 # 2 b 1 1.0 # 3 b 1 3.0 # 9 b 5 1.0 # 10 b 5 3.0 # 6 c 3 NaN result = pd.merge(df1, df2, on='key', how='outer') # \u591a\u5bf9\u591a\u8fde\u63a5 print(result.sort_values(by='key')) # key data1 data2 # 6 a 2.0 0.0 # 7 a 2.0 2.0 # 8 a 4.0 0.0 # 9 a 4.0 2.0 # 0 b 0.0 1.0 # 1 b 0.0 3.0 # 2 b 1.0 1.0 # 3 b 1.0 3.0 # 4 b 5.0 1.0 # 5 b 5.0 3.0 # 10 c 3.0 NaN # 11 d NaN 4.0 \u591a\u952e\u5408\u5e76\u3002 df1 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar'], 'key2': ['one', 'two', 'one'], 'lval': [1, 2, 3] } ) df2 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar', 'bar'], 'key2': ['one', 'one', 'one', 'two'], 'rval': [4, 5, 6, 7] } ) print(df1.sort_values(by=['key1', 'key2'])) # key1 key2 lval # 2 bar one 3 # 0 foo one 1 # 1 foo two 2 print(df2.sort_values(by=['key1', 'key2'])) # key1 key2 rval # 2 bar one 6 # 3 bar two 7 # 0 foo one 4 # 1 foo one 5 result = pd.merge(df1, df2, on=['key1', 'key2'], how='outer') print(result.sort_values(by=['key1', 'key2'])) # key1 key2 lval rval # 3 bar one 3.0 6.0 # 4 bar two NaN 7.0 # 0 foo one 1.0 4.0 # \u91cd\u590d\u586b\u5145 # 1 foo one 1.0 5.0 # \u91cd\u590d\u586b\u5145 # 2 foo two 2.0 NaN \u5904\u7406\u91cd\u53e0\u5217\u540d\u3002 result = pd.merge(df1, df2, on='key1') print(result.sort_values(by='key1')) # key1 key2_x lval key2_y rval # 4 bar one 3 one 6 # 5 bar one 3 two 7 # 0 foo one 1 one 4 # 1 foo one 1 one 5 # 2 foo two 2 one 4 # 3 foo two 2 one 5 result = pd.merge(df1, df2, on='key1', suffixes=('_left', '_right')) print(result.sort_values(by='key1')) # key1 key2_left lval key2_right rval # 4 bar one 3 one 6 # 5 bar one 3 two 7 # 0 foo one 1 one 4 # 1 foo one 1 one 5 # 2 foo two 2 one 4 # 3 foo two 2 one 5 \u6839\u636e\u7d22\u5f15\u5408\u5e76 \u00b6 \u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0cDataFrame\u4e2d\u7528\u4e8e\u5408\u5e76\u7684\u952e\u662f\u5b83\u7684\u7d22\u5f15\u3002\u53ef\u4ee5\u4f20\u9012 left_index=True \u6216 right_index=True \uff08\u6216\u8005\u90fd\u4f20\uff09\u6765\u8868\u793a\u7d22\u5f15\u9700\u8981\u7528\u6765\u4f5c\u4e3a\u5408\u5e76\u7684\u952e\u3002 df1 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar'], 'key2': ['one', 'two', 'one'], 'lval': [1, 2, 3] } ) df2 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar', 'bar'], 'key2': ['one', 'one', 'one', 'two'], 'rval': [4, 5, 6, 7] }, index=['foo', 'foo', 'bar', 'bar'] ) print(df1) # key1 key2 lval # 0 foo one 1 # 1 foo two 2 # 2 bar one 3 print(df2) # key1 key2 rval # foo foo one 4 # foo foo one 5 # bar bar one 6 # bar bar two 7 result = pd.merge(df1, df2, left_on='key1', right_index=True, suffixes=('_left', '_right')) print(result.sort_index()) # key1 key1_left key2_left lval key1_right key2_right rval # 0 foo foo one 1 foo one 4 # 0 foo foo one 1 foo one 5 # 1 foo foo two 2 foo one 4 # 1 foo foo two 2 foo one 5 # 2 bar bar one 3 bar one 6 # 2 bar bar one 3 bar two 7 result = pd.merge(df1, df2, left_on='key1', right_index=True, how='outer', suffixes=('_left', '_right')) # \u548c\u4e0a\u8ff0\u7ed3\u679c\u4e00\u6837 print(result.sort_index()) # key1 key1_left key2_left lval key1_right key2_right rval # 0 foo foo one 1 foo one 4 # 0 foo foo one 1 foo one 5 # 1 foo foo two 2 foo one 4 # 1 foo foo two 2 foo one 5 # 2 bar bar one 3 bar one 6 # 2 bar bar one 3 bar two 7 \u5728\u66f4\u590d\u6742\u591a\u5c42\u7d22\u5f15\u6570\u636e\u7684\u591a\u952e\u5408\u5e76\uff0c\u5728\u7d22\u5f15\u4e0a\u8fde\u63a5\u662f\u4e00\u4e2a\u9690\u5f0f\u7684\u591a\u952e\u5408\u5e76\u3002 \u5fc5\u987b\u4ee5\u5217\u8868\u7684\u65b9\u5f0f\u6307\u660e\u5408\u5e76\u6240\u9700\u591a\u4e2a\u5217\uff08\u6ce8\u610f\u4f7f\u7528 how='outer' \u5904\u7406\u91cd\u590d\u7684\u7d22\u5f15\u503c\uff09\u3002 df1 = pd.DataFrame( { 'key1': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'], 'key2': [2000, 2001, 2002, 2001, 2002], 'data': np.arange(5.) } ) df2 = pd.DataFrame( np.arange(12).reshape((6, 2)), index=[ ['Nevada', 'Nevada', 'Ohio', 'Ohio', 'Ohio', 'Ohio'], [2001, 2000, 2000, 2000, 2001, 2002] ], columns=['event1', 'event2'] ) print(df1) # key1 key2 data # 0 Ohio 2000 0.0 # 1 Ohio 2001 1.0 # 2 Ohio 2002 2.0 # 3 Nevada 2001 3.0 # 4 Nevada 2002 4.0 print(df2) # event1 event2 # Nevada 2001 0 1 # 2000 2 3 # Ohio 2000 4 5 # 2000 6 7 # 2001 8 9 # 2002 10 11 result = pd.merge(df1, df2, left_on=['key1', 'key2'], right_index=True) print(result) # key1 key2 data event1 event2 # 0 Ohio 2000 0.0 4 5 # 0 Ohio 2000 0.0 6 7 # 1 Ohio 2001 1.0 8 9 # 2 Ohio 2002 2.0 10 11 # 3 Nevada 2001 3.0 0 1 result = pd.merge(df1, df2, left_on=['key1', 'key2'], right_index=True, how='outer') print(result) # key1 key2 data event1 event2 # 0 Ohio 2000 0.0 4.0 5.0 # 0 Ohio 2000 0.0 6.0 7.0 # 1 Ohio 2001 1.0 8.0 9.0 # 2 Ohio 2002 2.0 10.0 11.0 # 3 Nevada 2001 3.0 0.0 1.0 # 4 Nevada 2002 4.0 NaN NaN # 4 Nevada 2000 NaN 2.0 3.0 \u4f7f\u7528\u4e24\u8fb9\u7684\u7d22\u5f15\u8fdb\u884c\u5408\u5e76\u4e5f\u662f\u53ef\u4ee5\u7684\uff0c\u524d\u63d0\u662f\u7528\u4e24\u8fb9\u7528\u6765\u5408\u5e76\u7684\u7d22\u5f15\u6709\u4ea4\u96c6\uff08\u516c\u5171\u90e8\u5206\uff09\u3002 \u5728\u4f7f\u7528 merge \u65f6\uff0c\u53c2\u6570 on=['key1', 'key2'] \u4e0d\u80fd\u548c left_index=True , right_index=True \u540c\u65f6\u5b58\u5728\u3002 \u5bf9\u4e8e\u91cd\u590d\u7d22\u5f15\uff0c\u5982\u679c\u503c\u4e0d\u540c\uff0c\u5219\u591a\u884c\u663e\u793a\uff0c\u548c\u6570\u636e\u5e93SQL\u7684 full join \u7c7b\u4f3c\u6982\u5ff5\u3002 \u5982\u679c\u51fa\u73b0\u76f8\u540c\u5217\u540d\uff0c\u5219\u4f1a\u81ea\u52a8\u6dfb\u52a0\u540e\u7f00\u5b57\u7b26\u4ee5\u793a\u533a\u522b\u3002 df1 = pd.DataFrame( [[1, 2], [3, 4], [5, 6]], index=['a', 'c', 'e'], columns=['Ohio', 'Nevada'] ) print(df1) # Ohio Nevada # a 1 2 # c 3 4 # e 5 6 df2 = pd.DataFrame( [[7, 8], [9, 10], [11, 12], [13, 14]], index=['b', 'c', 'c', 'e'], columns=['Missouri', 'Alabama'] ) print(df2) # Missouri Alabama # b 7 8 # c 9 10 # c 11 12 # e 13 14 df3 = pd.DataFrame( [[7, 8], [9, 10], [11, 12], [13, 14]], index=['a', 'c', 'e', 'f'], columns=['Nevada', 'Alabama'] ) print(df3) # Nevada Alabama # a 7 8 # c 9 10 # e 11 12 # f 13 14 result = pd.merge(df1, df2, left_index=True, right_index=True, how='outer') print(result) # Ohio Nevada Missouri Alabama # a 1.0 2.0 NaN NaN # b NaN NaN 7.0 8.0 # c 3.0 4.0 9.0 10.0 # c 3.0 4.0 11.0 12.0 # e 5.0 6.0 13.0 14.0 result = pd.merge(df1, df3, left_index=True, right_index=True, how='outer') print(result) # Ohio Nevada_x Nevada_y Alabama # a 1.0 2.0 7 8 # c 3.0 4.0 9 10 # e 5.0 6.0 11 12 # f NaN NaN 13 14 \u53e6\u4e00\u79cd\u5199\u6cd5\uff1a result = df1.join(df2, how='outer') print(result) # Ohio Nevada Missouri Alabama # a 1.0 2.0 NaN NaN # b NaN NaN 7.0 8.0 # c 3.0 4.0 9.0 10.0 # c 3.0 4.0 11.0 12.0 # e 5.0 6.0 13.0 14.0 \u4e5f\u53ef\u4ee5\u5411 join \u65b9\u6cd5\u4f20\u5165\u4e00\u4e2aDataFrame\u5217\u8868\uff0c\u7c7b\u4f3c\u4e8e\u5bf9\u4e09\u4e2a\u6570\u636e\u96c6\u8fdb\u884c join \u64cd\u4f5c\u3002 result = df1.join([df2, df3]) print(result) # Ohio Nevada_x Missouri Alabama_x Nevada_y Alabama_y # a 1 2 NaN NaN 7 8 # c 3 4 9.0 10.0 9 10 # c 3 4 11.0 12.0 9 10 # e 5 6 13.0 14.0 11 12 \u6cbf\u8f74\u5411\u8fde\u63a5 \u00b6 \u53e6\u4e00\u79cd\u6570\u636e\u7ec4\u5408\u64cd\u4f5c\u53ef\u79f0\u4e3a\u62fc\u63a5\u3001\u7ed1\u5b9a\u6216\u5806\u53e0\u3002NumPy\u7684 concatenate \u51fd\u6570\u53ef\u4ee5\u5728NumPy\u6570\u7ec4\u4e0a\u5b9e\u73b0\u8be5\u529f\u80fd\u3002 \u57fa\u4e8eSeries\u7684pandas\u7684 concat \u51fd\u6570\u7684\u5de5\u4f5c\u673a\u5236\u5206\u6790\u3002 \u4e0b\u9762\u4e09\u4e2a\u7d22\u5f15\u4e0d\u91cd\u53e0\u7684Series\u3002 s1 = pd.Series([0, 1], index=['a', 'b']) s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e']) s3 = pd.Series([5, 6], index=['f', 'g']) \u7528\u5217\u8868\u4e2d\u7684\u8fd9\u4e9b\u5bf9\u8c61\u8c03\u7528 concat \u65b9\u6cd5\u4f1a\u5c06\u503c\u548c\u7d22\u5f15\u7c98\u5728\u4e00\u8d77\uff1a \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c concat \u65b9\u6cd5\u662f\u6cbf\u7740 axis=0 \u7684\u8f74\u5411\u751f\u6548\u7684\uff0c\u751f\u6210\u53e6\u4e00\u4e2aSeries\u3002 \u5982\u679c\u4f20\u9012 axis=1 \uff0c\u8fd4\u56de\u7684\u7ed3\u679c\u5219\u662f\u4e00\u4e2aDataFrame\uff08 axis=1 \u65f6\u662f\u5217\uff09\u3002 result = pd.concat([s1, s2, s3]) print(result) # a 0 # b 1 # c 2 # d 3 # e 4 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s2, s3], keys=['one', 'two', 'three']) # \u901a\u8fc7keys\u53c2\u6570\uff0c\u5728\u8fde\u63a5\u8f74\u5411\u4e0a\u521b\u5efa\u4e00\u4e2a\u591a\u5c42\u7d22\u5f15\uff0c\u4ee5\u4fbf\u5728\u7ed3\u679c\u4e2d\u533a\u5206\u5404\u90e8\u5206 print(result) # one a 0 # b 1 # two c 2 # d 3 # e 4 # three f 5 # g 6 # dtype: int64 print(result.unstack()) # \u628a\u539f\u7d22\u5f15\u4f5c\u4e3a\u5217\u6807\u7b7e\u5c55\u5f00 # a b c d e f g # one 0.0 1.0 NaN NaN NaN NaN NaN # two NaN NaN 2.0 3.0 4.0 NaN NaN # three NaN NaN NaN NaN NaN 5.0 6.0 result = pd.concat([s1, s2, s3], axis=1) # \u5728\u8fd9\u4e2a\u6848\u4f8b\u4e2daxis=1\u8f74\u5411\u4e0a\u5e76\u6ca1\u6709\u91cd\u53e0 print(result) # 0 1 2 # a 0.0 NaN NaN # b 1.0 NaN NaN # c NaN 2.0 NaN # d NaN 3.0 NaN # e NaN 4.0 NaN # f NaN NaN 5.0 # g NaN NaN 6.0 result = pd.concat([s1, s2, s3], axis=1, keys=['one', 'two', 'three']) # \u5728\u8fd9\u4e2a\u6848\u4f8b\u4e2daxis=1\u8f74\u5411\u4e0a\u5e76\u6ca1\u6709\u91cd\u53e0 print(result) # one two three # a 0.0 NaN NaN # b 1.0 NaN NaN # c NaN 2.0 NaN # d NaN 3.0 NaN # e NaN 4.0 NaN # f NaN NaN 5.0 # g NaN NaN 6.0 print(result.unstack()) # \u5bf9\u6bd4axis=0\u7684\u591a\u5c42\u7d22\u5f15\uff0c\u5f53axis=1\u65f6\u5bf9\u8f93\u51fa\u5404index\u7684\u5e76\u96c6\u505a\u4e86\u5206\u7ec4\u3002 # one a 0.0 # b 1.0 # c NaN # d NaN # e NaN # f NaN # g NaN # two a NaN # b NaN # c 2.0 # d 3.0 # e 4.0 # f NaN # g NaN # three a NaN # b NaN # c NaN # d NaN # e NaN # f 5.0 # g 6.0 # dtype: float64 s4 = pd.concat([s1, s3]) print(s4) # a 0 # b 1 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s4]) print(result) # a 0 # b 1 # a 0 # b 1 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s4], axis=1) # \u73b0\u5728\u5728\u4e2daxis=1\u8f74\u5411\u4e0a\u6709\u91cd\u53e0 print(result) # 0 1 # a 0.0 0 # b 1.0 1 # f NaN 5 # g NaN 6 result = pd.concat([s1, s4], axis=1, keys=['one', 'two', 'three']) print(result) # one two # a 0.0 0 # b 1.0 1 # f NaN 5 # g NaN 6 result = pd.concat([s1, s4], axis=0, keys=['one', 'two', 'three']) # \u901a\u8fc7keys\u53c2\u6570\uff0c\u5728\u8fde\u63a5\u8f74\u5411\u4e0a\u521b\u5efa\u4e00\u4e2a\u591a\u5c42\u7d22\u5f15 print(result) # one a 0 # b 1 # two a 0 # b 1 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s4], axis=1, join='inner') # \u5185\u8fde\u63a5\u65b9\u5f0f\u5408\u5e76\u7d22\u5f15\uff08\u7d22\u5f15\u4ea4\u96c6\uff09 print(result) # 0 1 # a 0 0 # b 1 1 result = pd.concat([s1, s4], axis=1).reindex(['a', 'c', 'b', 'e']) # \u4f7f\u7528join_axes(\u5df2\u88ab\u66ff\u6362\u6210reindex)\u6765\u6307\u5b9a\u7528\u4e8e\u8fde\u63a5\u5176\u4ed6\u8f74\u5411\u7684\u8f74 print(result) # 0 1 # a 0.0 0.0 # c NaN NaN # b 1.0 1.0 # e NaN NaN \u57fa\u4e8eDataFrame\u7684pandas\u7684 concat \u51fd\u6570\u7684\u5de5\u4f5c\u673a\u5236\u5206\u6790\u3002 df1 = pd.DataFrame( np.arange(12).reshape((6, 2)), index=[ ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], [2000, 2001, 2002, 2000, 2001, 2002] ], columns=['event1', 'event2'] ) df2 = pd.DataFrame( np.arange(12).reshape((6, 2)), index=[ ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], [2000, 2001, 2002, 2000, 2001, 2002] ], columns=['event3', 'event4'] ) print(df1) # event1 event2 # Ohio 2000 0 1 # 2001 2 3 # 2002 4 5 # Nevada 2000 6 7 # 2001 8 9 # 2002 10 11 print(df2) # event3 event4 # Ohio 2000 0 1 # 2001 2 3 # 2002 4 5 # Nevada 2000 6 7 # 2001 8 9 # 2002 10 11 result = np.concatenate([df1, df2], axis=0) # \u6cbf0\u8f74\u62fc\u63a5 print(result) # [[ 0 1] # [ 2 3] # [ 4 5] # [ 6 7] # [ 8 9] # [10 11] # [ 0 1] # [ 2 3] # [ 4 5] # [ 6 7] # [ 8 9] # [10 11]] result = np.concatenate([df1, df2], axis=1) # \u6cbf1\u8f74\u62fc\u63a5 print(result) # [[ 0 1 0 1] # [ 2 3 2 3] # [ 4 5 4 5] # [ 6 7 6 7] # [ 8 9 8 9] # [10 11 10 11]] result = np.concatenate([df1, df2], axis=None) # \u5c06\u6570\u7ec4\u5c55\u5e73 print(result) # [ 0 1 2 3 4 5 6 7 8 9 10 11 0 1 2 3 4 5 6 7 8 9 10 11] \u8054\u5408\u91cd\u53e0\u6570\u636e \u00b6 \u53e6\u4e00\u4e2a\u6570\u636e\u8054\u5408\u573a\u666f\uff0c\u65e2\u4e0d\u662f\u5408\u5e76\u64cd\u4f5c\uff0c\u4e5f\u4e0d\u662f\u8fde\u63a5\u64cd\u4f5c\u3002 \u5047\u5982\u6709\u4e24\u4e2a\u6570\u636e\u96c6\uff0c\u8fd9\u4e24\u4e2a\u6570\u636e\u96c6\u7684\u7d22\u5f15\u5168\u90e8\u6216\u90e8\u5206\u91cd\u53e0\uff0c\u901a\u8fc7NumPy\u7684 where \u51fd\u6570\u53ef\u4ee5\u8fdb\u884c\u9762\u5411\u6570\u7ec4\u7684if-else\u7b49\u4ef7\u64cd\u4f5c\u3002 s1 = pd.Series( [np.nan, 2.5, 0.0, 3.5, 4.5, np.nan], index=['f', 'e', 'd', 'c', 'b', 'a'] ) s2 = pd.Series( [0.0, np.nan, 2.0, np.nan, np.nan, 5.0], index=['a', 'b', 'c', 'd', 'e', 'f'] ) print(s1) # f NaN # e 2.5 # d 0.0 # c 3.5 # b 4.5 # a NaN # dtype: float64 print(s2) # a 0.0 # b NaN # c 2.0 # d NaN # e NaN # f 5.0 # dtype: float64 \u65b9\u6cd51\uff0c\u901a\u8fc7Numpy\u7684 where \u51fd\u6570\u3002 result = np.where(pd.isnull(s1), s2, s1) # An array with elements from 'x'(s2) where 'condition'(isnull(s1)) is True, and elements from 'y'(s1) elsewhere. print(result) # [0. 2.5 0. 3.5 4.5 5. ] # s1 # s2 # result # f NaN # a 0.0 0. \u6761\u4ef6\u4e2ds1\u8be5\u5143\u7d20\u4e3anull\uff0c\u6240\u4ee5where\u51fd\u6570\u53d6\u5bf9\u5e94x(s2)\u7684\u5143\u7d20\uff08\u6ce8\u610f\uff0c\u4e0e\u7d22\u5f15\u987a\u5e8f\u65e0\u5173\uff09 # e 2.5 # b NaN 2.5 \u6761\u4ef6\u4e2ds1\u8be5\u5143\u7d20\u4e0d\u4e3anull\uff0c\u6240\u4ee5where\u51fd\u6570\u53d6\u5bf9\u5e94y(s1)\u7684\u5143\u7d20 # d 0.0 # c 2.0 0. # c 3.5 # d NaN 3.5 # b 4.5 # e NaN 4.5 # a NaN # f 5.0 5.0 \u6761\u4ef6\u4e2ds1\u8be5\u5143\u7d20\u4e3anull\uff0c\u6240\u4ee5where\u51fd\u6570\u53d6\u5bf9\u5e94x(s2)\u7684\u5143\u7d20 result = np.where(pd.isnull(s2), s1, s2) print(result) # [0. 2.5 2. 3.5 4.5 5. ] \u65b9\u6cd52\uff0c\u901a\u8fc7Series\u7684 combine_first \u65b9\u6cd5\u3002 result = s2.combine_first(s1) # \u6ce8\u610f\uff0ccombine_first\u662f\u6309\u7167s2\u7684\u7d22\u5f15\u987a\u5e8f\u68c0\u7d22\u7684\uff0c\u76f8\u540c\u7d22\u5f15\u7684s1\u7684\u503c\u4f1a\u586b\u5145\u5bf9\u5e94s2\u7684null print(result) # a 0.0 # b 4.5 # c 2.0 # d 0.0 # e 2.5 # f 5.0 # dtype: float64 \u65b9\u6cd53\uff1aPandas\u7684 combine_first \u65b9\u6cd5\u3002 df1 = pd.DataFrame( { 'a': [1.0, np.nan, 5.0, np.nan], 'b': [np.nan, 2.0, np.nan, 6.0], 'c': [2.0, 6.0, 10.0, 15.0] } ) df2 = pd.DataFrame( { 'a': [5.0, 4.0, np.nan, 3.0, 7.0], 'b': [np.nan, 3.0, 4.0, 6.0, 8.0] } ) print(df1) # a b c # 0 1.0 NaN 2.0 # 1 NaN 2.0 6.0 # 2 5.0 NaN 10.0 # 3 NaN 6.0 15.0 print(df2) # a b # 0 5.0 NaN # 1 4.0 3.0 # 2 NaN 4.0 # 3 3.0 6.0 # 4 7.0 8.0 result = df2.combine_first(df1) # \u7528df1\u7684\u503c\u53bb\u586b\u5145df2\u5bf9\u5e94\u7d22\u5f15\u4f4d\u7f6e\u7684null\u503c print(result) # a b c # 0 5.0 NaN 2.0 # 1 4.0 3.0 6.0 # 2 5.0 4.0 10.0 # 3 3.0 6.0 15.0 # 4 7.0 8.0 NaN \u91cd\u5851\u548c\u900f\u89c6 \u00b6 \u91cd\u65b0\u6392\u5217\u8868\u683c\u578b\u6570\u636e\u6709\u591a\u79cd\u57fa\u7840\u64cd\u4f5c\u3002\u8fd9\u4e9b\u64cd\u4f5c\u88ab\u79f0\u4e3a\u91cd\u5851\u6216\u900f\u89c6\u3002 import numpy as np import pandas as pd \u4f7f\u7528\u591a\u5c42\u7d22\u5f15\u8fdb\u884c\u91cd\u5851 \u00b6 \u591a\u5c42\u7d22\u5f15\u5728DataFrame\u4e2d\u63d0\u4f9b\u4e86\u4e00\u79cd\u4e00\u81f4\u6027\u65b9\u5f0f\u7528\u4e8e\u91cd\u6392\u5217\u6570\u636e\u3002\u4ee5\u4e0b\u662f\u4e24\u4e2a\u57fa\u7840\u64cd\u4f5c\uff1a statck\uff08\u5806\u53e0\uff09\u8be5\u64cd\u4f5c\u4f1a\u201c\u65cb\u8f6c\u201d\u6216\u5c06\u5217\u4e2d\u7684\u6570\u636e\u900f\u89c6\u5230\u884c\u3002 unstack\uff08\u62c6\u5806\uff09\u8be5\u64cd\u4f5c\u4f1a\u5c06\u884c\u4e2d\u7684\u6570\u636e\u900f\u89c6\u5230\u5217\u3002 df = pd.DataFrame( np.arange(6).reshape((2, 3)), index=pd.Index(['Ohio', 'Colorado'], name='state'), columns=pd.Index(['one', 'two', 'three'], name='number') ) print(df) # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 \u5728\u8fd9\u4efd\u6570\u636e\u4e0a\u4f7f\u7528stack\u65b9\u6cd5\u4f1a\u5c06\u5217\u900f\u89c6\u5230\u884c\uff0c\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684Series\uff1a result = df.stack() print(result) # state number # Ohio one 0 # two 1 # three 2 # Colorado one 3 # two 4 # three 5 # dtype: int64 \u4ece\u4e00\u4e2a\u591a\u5c42\u7d22\u5f15\u5e8f\u5217\u4e2d\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 unstack \u65b9\u6cd5\u5c06\u6570\u636e\u91cd\u6392\u5217\u540e\u653e\u5165\u4e00\u4e2aDataFrame\u4e2d\uff1a print(result.unstack()) # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 print(result.unstack(0)) # \u53ef\u4ee5\u4f20\u5165\u4e00\u4e2a\u5c42\u7ea7\u5e8f\u53f7\u6216\u540d\u79f0\u6765\u62c6\u5206\u4e00\u4e2a\u4e0d\u540c\u7684\u5c42\u7ea7 # state Ohio Colorado # number # one 0 3 # two 1 4 # three 2 5 print(result.unstack(1)) # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 print(result.unstack('state')) # \u8f93\u51fa\u7ed3\u679c\u548c\u4f20\u5165\u5c42\u7ea70\u4e00\u6837 # state Ohio Colorado # number # one 0 3 # two 1 4 # three 2 5 print(result.unstack('number')) # \u8f93\u51fa\u7ed3\u679c\u548c\u4f20\u5165\u5c42\u7ea71\u4e00\u6837 # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 \u5982\u679c\u5c42\u7ea7\u4e2d\u7684\u6240\u6709\u503c\u5e76\u672a\u5305\u542b\u4e8e\u6bcf\u4e2a\u5b50\u5206\u7ec4\u4e2d\u65f6\uff0c\u62c6\u5206\u53ef\u80fd\u4f1a\u5f15\u5165\u7f3a\u5931\u503c\uff1a s1 = pd.Series([0, 1, 2, 3], index=['a', 'b', 'c', 'd']) s2 = pd.Series([4, 5, 6], index=['c', 'd', 'e']) s3 = pd.concat([s1, s2], keys=['one', 'two']) print(s3) # one a 0 # b 1 # c 2 # d 3 # two c 4 # d 5 # e 6 # dtype: int64 print(s3.unstack(0)) # one two # a 0.0 NaN # b 1.0 NaN # c 2.0 4.0 # d 3.0 5.0 # e NaN 6.0 print(s3.unstack(1)) print(s3.unstack()) # a b c d e # one 0.0 1.0 2.0 3.0 NaN # two NaN NaN 4.0 5.0 6.0 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5806\u53e0\u4f1a\u8fc7\u6ee4\u51fa\u7f3a\u5931\u503c\uff0c\u56e0\u6b64\u5806\u53e0\u62c6\u5806\u7684\u64cd\u4f5c\u662f\u53ef\u9006\u7684\u3002 print(s3.unstack().stack()) # one a 0.0 # b 1.0 # c 2.0 # d 3.0 # two c 4.0 # d 5.0 # e 6.0 # dtype: float64 print(s3.unstack().stack(dropna=False)) # one a 0.0 # b 1.0 # c 2.0 # d 3.0 # e NaN # two a NaN # b NaN # c 4.0 # d 5.0 # e 6.0 # dtype: float64 \u5728DataFrame\u4e2d\u62c6\u5806\u65f6\uff0c\u88ab\u62c6\u5806\u7684\u5c42\u7ea7\u4f1a\u53d8\u4e3a\u7ed3\u679c\u4e2d\u6700\u4f4e\u7684\u5c42\u7ea7\u3002 \u5728\u8c03\u7528 stack \u65b9\u6cd5\u65f6\uff0c\u6211\u4eec\u53ef\u4ee5\u6307\u660e\u9700\u8981\u5806\u53e0\u7684\u8f74\u5411\u540d\u79f0\u3002 df = pd.DataFrame( {'left': result, 'right': result + 5}, columns=pd.Index(['left', 'right'], name='side') ) print(df) # side left right # state number # Ohio one 0 5 # two 1 6 # three 2 7 # Colorado one 3 8 # two 4 9 # three 5 10 print(df.unstack()) # side left right # number one two three one two three # state # Ohio 0 1 2 5 6 7 # Colorado 3 4 5 8 9 10 print(df.unstack('state')) # \u88ab\u62c6\u5806\u7684\u5c42\u7ea7(state)\u4f1a\u53d8\u4e3a\u7ed3\u679c\u4e2d\u6700\u4f4e\u7684\u5c42\u7ea7 # side left right # state Ohio Colorado Ohio Colorado # number # one 0 3 5 8 # two 1 4 6 9 # three 2 5 7 10 \u5728\u8c03\u7528 stack \u65b9\u6cd5\u65f6\uff0c\u53ef\u4ee5\u6307\u660e\u9700\u8981\u5806\u53e0\u7684\u8f74\u5411\u540d\u79f0\uff1a print(df.unstack('state').stack('side')) # state Colorado Ohio # number side # one left 3 0 # right 8 5 # two left 4 1 # right 9 6 # three left 5 2 # right 10 7 \u5c06\u201c\u957f\u201d\u900f\u89c6\u4e3a\u201c\u5bbd\u201d \u00b6 \u5728\u6570\u636e\u5e93\u548cCSV\u4e2d\u5b58\u50a8\u591a\u65f6\u95f4\u5e8f\u5217\u7684\u65b9\u5f0f\u5c31\u662f\u6240\u8c13\u7684\u957f\u683c\u5f0f\u6216\u5806\u53e0\u683c\u5f0f\u3002 data = pd.read_csv('../examples/macrodata.csv') print(data.head(3)) # year quarter realgdp realcons ... unemp pop infl realint # 0 1959.0 1.0 2710.349 1707.4 ... 5.8 177.146 0.00 0.00 # 1 1959.0 2.0 2778.801 1733.7 ... 5.1 177.830 2.34 0.74 # 2 1959.0 3.0 2775.488 1751.8 ... 5.3 178.657 2.74 1.09 # ...... # [3 rows x 14 columns] # PeriodIndex\u5c06year\u548cquarter\u7b49\u5217\u8fdb\u884c\u8054\u5408\u5e76\u751f\u6210\u4e86\u4e00\u79cd\u65f6\u95f4\u95f4\u9694\u7c7b\u578b periods = pd.PeriodIndex( year=data.year, quarter=data.quarter, name='date' ) columns = pd.Index( ['realgdp', 'infl', 'unemp'], name='item' ) data = data.reindex(columns=columns) print(data) # item realgdp infl unemp # 0 2710.349 0.00 5.8 # 1 2778.801 2.34 5.1 # 2 2775.488 2.74 5.3 # ...... # [203 rows x 3 columns] data.index = periods.to_timestamp('D', 'end') print(data.index) # DatetimeIndex(['1959-03-31 23:59:59.999999999', # '1959-06-30 23:59:59.999999999', # ... # '2009-06-30 23:59:59.999999999', # '2009-09-30 23:59:59.999999999'], # dtype='datetime64[ns]', name='date', length=203, freq=None) \u4e0b\u9762\u662fldata\u7684\u6570\u636e\u6837\u672c\u3002 \u8fd9\u79cd\u6570\u636e\u5373\u6240\u8c13\u7684\u591a\u65f6\u95f4\u5e8f\u5217\u7684\u957f\u683c\u5f0f\uff0c\u6216\u79f0\u4e3a\u5177\u6709\u4e24\u4e2a\u6216\u66f4\u591a\u4e2a\u952e\u7684\u5176\u4ed6\u89c2\u6d4b\u6570\u636e\uff08\u8fd9\u91cc\uff0c\u6211\u4eec\u7684\u952e\u662fdate\u548citem\uff09\u3002 \u8868\u4e2d\u7684\u6bcf\u4e00\u884c\u8868\u793a\u4e00\u4e2a\u65f6\u95f4\u70b9\u4e0a\u7684\u5355\u4e2a\u89c2\u6d4b\u503c\u3002 ldata = data.stack().reset_index().rename(columns={0: 'value'}) print(ldata) # date item value # 0 1959-03-31 23:59:59.999999999 realgdp 2710.349 # 1 1959-03-31 23:59:59.999999999 infl 0.000 # 2 1959-03-31 23:59:59.999999999 unemp 5.800 # 3 1959-06-30 23:59:59.999999999 realgdp 2778.801 # 4 1959-06-30 23:59:59.999999999 infl 2.340 # .. ... ... ... # 604 2009-06-30 23:59:59.999999999 infl 3.370 # 605 2009-06-30 23:59:59.999999999 unemp 9.200 # 606 2009-09-30 23:59:59.999999999 realgdp 12990.341 # 607 2009-09-30 23:59:59.999999999 infl 3.560 # 608 2009-09-30 23:59:59.999999999 unemp 9.600 # [609 rows x 3 columns] \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff1a \u6570\u636e\u901a\u5e38\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u5b58\u50a8\u5728\u5173\u7cfb\u578b\u6570\u636e\u5e93\u4e2d\uff0c\u6bd4\u5982MySQL\uff0c\u56e0\u4e3a\u56fa\u5b9a\u6a21\u5f0f\uff08\u5217\u540d\u79f0\u548c\u6570\u636e\u7c7b\u578b\uff09\u5141\u8bb8 item \u5217\u4e2d\u4e0d\u540c\u503c\u7684\u6570\u91cf\u968f\u7740\u6570\u636e\u88ab\u6dfb\u52a0\u5230\u8868\u4e2d\u800c\u6539\u53d8\u3002 date \u548c item \u901a\u5e38\u662f\u4e3b\u952e\uff08\u4f7f\u7528\u5173\u7cfb\u578b\u6570\u636e\u5e93\u7684\u8bf4\u6cd5\uff09\uff0c\u63d0\u4f9b\u4e86\u5173\u7cfb\u5b8c\u6574\u6027\u548c\u66f4\u7b80\u5355\u7684\u8fde\u63a5\u3002 \u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u5904\u7406\u8fd9\u79cd\u683c\u5f0f\u7684\u6570\u636e\u66f4\u4e3a\u56f0\u96be\u3002\u53ef\u80fd\u66f4\u503e\u5411\u4e8e\u83b7\u53d6\u4e00\u4e2a\u6309 date \u5217\u65f6\u95f4\u6233\u7d22\u5f15\u7684\u4e14\u6bcf\u4e2a\u4e0d\u540c\u7684 item \u72ec\u7acb\u4e00\u5217\u7684DataFrame\u3002 DataFrame\u7684pivot\u65b9\u6cd5\u5c31\u662f\u8fdb\u884c\u8fd9\u79cd\u8f6c\u6362\u7684\uff1a \u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c\u4f20\u9012\u7684\u524d\u4e24\u4e2a\u503c\u662f\u5206\u522b\u7528\u4f5c\u884c\u548c\u5217\u7d22\u5f15\u7684\u5217\uff0c\u7136\u540e\u662f\u53ef\u9009\u7684\u6570\u503c\u5217\u4ee5\u586b\u5145DataFrame\u3002 \u6ce8\u610f\uff0c pivot \u65b9\u6cd5\u7b49\u4ef7\u4e8e\u4f7f\u7528 set_index \u521b\u5efa\u5206\u5c42\u7d22\u5f15\uff0c\u7136\u540e\u8c03\u7528unstack\u3002 pivoted = ldata.pivot('date', 'item', 'value') print(pivoted) # item infl realgdp unemp # date # 1959-03-31 23:59:59.999999999 0.00 2710.349 5.8 # 1959-06-30 23:59:59.999999999 2.34 2778.801 5.1 # ... ... ... ... # 2009-06-30 23:59:59.999999999 3.37 12901.504 9.2 # 2009-09-30 23:59:59.999999999 3.56 12990.341 9.6 # [203 rows x 3 columns] ldata['value2'] = np.random.randn(len(ldata)) print(ldata[:5]) # date item value value2 # 0 1959-03-31 23:59:59.999999999 realgdp 2710.349 -1.268405 # 1 1959-03-31 23:59:59.999999999 infl 0.000 0.377691 # 2 1959-03-31 23:59:59.999999999 unemp 5.800 -0.342492 # 3 1959-06-30 23:59:59.999999999 realgdp 2778.801 0.132797 # 4 1959-06-30 23:59:59.999999999 infl 2.340 0.180290 \u6b64\u65f6 ldata \u5df2\u7ecf\u6dfb\u52a0\u4e86\u4e00\u5217\u3002\u5982\u679c\u9057\u6f0f\u6700\u540e\u4e00\u4e2a\u53c2\u6570\uff0c\u4f1a\u5f97\u5230\u4e00\u4e2a\u542b\u6709\u591a\u5c42\u5217\u7684DataFrame\uff0c\u5982\u4e0b\uff1a pivoted = ldata.pivot('date', 'item') print(pivoted) # value ... value2 # item infl realgdp ... realgdp unemp # date ... # 1959-03-31 23:59:59.999999999 0.00 2710.349 ... 0.157467 -0.222464 # 1959-06-30 23:59:59.999999999 2.34 2778.801 ... 0.861501 0.368855 # ... ... ... ... ... ... # 2009-06-30 23:59:59.999999999 3.37 12901.504 ... 0.279988 0.934972 # 2009-09-30 23:59:59.999999999 3.56 12990.341 ... 0.547914 1.842967 # [203 rows x 6 columns] \u6ce8\u610f\uff0c pivot \u65b9\u6cd5\u7b49\u4ef7\u4e8e\u4f7f\u7528 set_index \u521b\u5efa\u5206\u5c42\u7d22\u5f15\uff0c\u7136\u540e\u8c03\u7528 unstack \u3002 unstacked = ldata.set_index(['date', 'item']).unstack('item') print(unstacked[:5]) # value ... value2 # item infl realgdp ... realgdp unemp # date ... # 1959-03-31 23:59:59.999999999 0.00 2710.349 ... 0.213120 -0.248004 # 1959-06-30 23:59:59.999999999 2.34 2778.801 ... 0.697763 0.112388 # 1959-09-30 23:59:59.999999999 2.74 2775.488 ... 1.291884 -1.046142 # 1959-12-31 23:59:59.999999999 0.27 2785.204 ... 0.363339 -0.307364 # 1960-03-31 23:59:59.999999999 2.31 2847.699 ... 0.377330 2.272980 # [5 rows x 6 columns] \u5c06\u201c\u5bbd\u201d\u900f\u89c6\u4e3a\u201c\u957f\u201d \u00b6 \u5728DataFrame\u4e2d\uff0cpivot\u65b9\u6cd5\u7684\u53cd\u64cd\u4f5c\u662f pandas.melt \u3002 \u4e0e\u5c06\u4e00\u5217\u53d8\u6362\u4e3a\u65b0\u7684DataFrame\u4e2d\u7684\u591a\u5217\u4e0d\u540c\uff0c\u5b83\u5c06\u591a\u5217\u5408\u5e76\u6210\u4e00\u5217\uff0c\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684DataFrame\uff0c\u5176\u957f\u5ea6\u6bd4\u8f93\u5165\u66f4\u957f\u3002 df = pd.DataFrame( { 'key': ['foo', 'bar', 'baz'], 'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9] } ) print(df) # key A B C # 0 foo 1 4 7 # 1 bar 2 5 8 # 2 baz 3 6 9 key \u5217\u53ef\u4ee5\u4f5c\u4e3a\u5206\u7ec4\u6307\u6807\uff0c\u5176\u4ed6\u5217\u5747\u4e3a\u6570\u636e\u503c\u3002 \u5f53\u4f7f\u7528 pandas.melt \u65f6\uff0c\u6211\u4eec\u5fc5\u987b\u6307\u660e\u54ea\u4e9b\u5217\u662f\u5206\u7ec4\u6307\u6807\uff08\u5982\u679c\u6709\u7684\u8bdd\uff09\u3002 \u6b64\u5904\uff0c\u8ba9\u6211\u4eec\u4f7f\u7528 key \u4f5c\u4e3a\u552f\u4e00\u7684\u5206\u7ec4\u6307\u6807\uff1a melted = pd.melt(df, ['key']) print(melted) # key variable value # 0 foo A 1 # 1 bar A 2 # 2 baz A 3 # 3 foo B 4 # 4 bar B 5 # 5 baz B 6 # 6 foo C 7 # 7 bar C 8 # 8 baz C 9 \u4f7f\u7528 pivot \u65b9\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u6570\u636e\u91cd\u5851\u56de\u539f\u5148\u7684\u5e03\u5c40\u3002 reshaped = melted.pivot('key', 'variable', 'value') print(reshaped) # variable A B C # key # bar 2 5 8 # baz 3 6 9 # foo 1 4 7 \u7531\u4e8e pivot \u7684\u7ed3\u679c\u6839\u636e\u4f5c\u4e3a\u884c\u6807\u7b7e\u7684\u5217\u751f\u6210\u4e86\u7d22\u5f15\uff0c\u53ef\u4f7f\u7528 reset_index \u6765\u5c06\u6570\u636e\u56de\u79fb\u4e00\u5217\uff1a print(reshaped.reset_index()) # variable key A B C # 0 bar 2 5 8 # 1 baz 3 6 9 # 2 foo 1 4 7 pandas.melt \u7684\u4f7f\u7528\u4e5f\u53ef\u4ee5\u65e0\u987b\u4efb\u4f55\u5206\u7ec4\u6307\u6807\u3002 result = pd.melt(df, value_vars=['A', 'B', 'C']) print(result) # variable value # 0 A 1 # 1 A 2 # 2 A 3 # 3 B 4 # 4 B 5 # 5 B 6 # 6 C 7 # 7 C 8 # 8 C 9 result = pd.melt(df, value_vars=['key', 'B', 'C']) print(result) # variable value # 0 key foo # 1 key bar # 2 key baz # 3 B 4 # 4 B 5 # 5 B 6 # 6 C 7 # 7 C 8 # 8 C 9","title":"\u6570\u636e\u89c4\u6574\uff1a\u8fde\u63a5\u3001\u8054\u5408\u4e0e\u91cd\u5851"},{"location":"python/DataAnalysis/ch05/#_1","text":"","title":"\u6570\u636e\u89c4\u6574\uff1a\u8fde\u63a5\u3001\u8054\u5408\u4e0e\u91cd\u5851"},{"location":"python/DataAnalysis/ch05/#_2","text":"import pandas as pd import numpy as np import re \u5206\u5c42\u7d22\u5f15\u662fpandas\u7684\u91cd\u8981\u7279\u6027\uff0c\u5141\u8bb8\u4f60\u5728\u4e00\u4e2a\u8f74\u5411\u4e0a\u62e5\u6709\u591a\u4e2a\uff08\u4e24\u4e2a\u6216\u4e24\u4e2a\u4ee5\u4e0a\uff09\u7d22\u5f15\u5c42\u7ea7\u3002 \u5206\u5c42\u7d22 import re \u5f15\u63d0\u4f9b\u4e86\u4e00\u79cd\u5728\u66f4\u4f4e\u7ef4\u5ea6\u7684\u5f62\u5f0f\u4e2d\u5904\u7406\u66f4\u9ad8\u7ef4\u5ea6\u6570\u636e\u7684\u65b9\u5f0f\u3002","title":"\u5206\u5c42\u7d22\u5f15"},{"location":"python/DataAnalysis/ch05/#series","text":"data = pd.Series( np.random.randn(9), index=[['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'], [1, 2, 3, 1, 3, 1, 2, 2, 3]] ) \u8f93\u51fa\u662f\u4e00\u4e2a\u4ee5 MultiIndex \u4f5c\u4e3a\u7d22\u5f15\u7684Series\u7684\u7f8e\u5316\u89c6\u56fe\u3002 \u7d22\u5f15\u4e2d\u7684\"\u95f4\u9699\"\u8868\u793a\"\u76f4\u63a5\u4f7f\u7528\u4e0a\u9762\u7684\u6807\u7b7e\"\u3002 print(data) # a 1 0.163468 # 2 -1.525926 # 3 -0.210247 # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # d 2 0.034305 # 3 -0.896078 # dtype: float64 print(data.index) # MultiIndex([('a', 1), # ('a', 2), # ('a', 3), # ('b', 1), # ('b', 3), # ('c', 1), # ('c', 2), # ('d', 2), # ('d', 3)], # ) \u901a\u8fc7\u5206\u5c42\u7d22\u5f15\u5bf9\u8c61\uff0c\u4e5f\u53ef\u4ee5\u79f0\u4e3a\u90e8\u5206\u7d22\u5f15\uff0c\u53ef\u4ee5\u7b80\u6d01\u5730\u9009\u62e9\u51fa\u6570\u636e\u7684\u5b50\u96c6\u3002 m = data['b'] print(m) # 1 -0.956063 # 3 -1.839111 # dtype: float64 m = data['b': 'c'] print(m) # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # dtype: float64 m = data.loc[['b', 'c']] print(m) # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # dtype: float64 m = data.loc[:, 2] print(m) # a -1.525926 # c 0.595279 # d 0.034305 # dtype: float64 \u5206\u5c42\u7d22\u5f15\u5728\u91cd\u5851\u6570\u636e\u548c\u6570\u7ec4\u900f\u89c6\u8868\u7b49\u5206\u7ec4\u64cd\u4f5c\u4e2d\u626e\u6f14\u4e86\u91cd\u8981\u89d2\u8272\u3002 \u4f8b\u5982\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 unstack \u65b9\u6cd5\u5c06\u6570\u636e\u5728DataFrame\u4e2d\u91cd\u65b0\u6392\u5217\u3002 m = data.unstack() print(m) # 1 2 3 # a 0.163468 -1.525926 -0.210247 # b -0.956063 NaN -1.839111 # c -0.398905 0.595279 NaN # d NaN 0.034305 -0.896078 n = m.stack() print(n) # \u6216\u8005 print(data.unstack().stack()) # a 1 0.163468 # 2 -1.525926 # 3 -0.210247 # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # d 2 0.034305 # 3 -0.896078 # dtype: float64","title":"Series\u7d22\u5f15\u5206\u5c42"},{"location":"python/DataAnalysis/ch05/#dataframe","text":"\u5728DataFrame\u4e2d\uff0c\u6bcf\u4e2a\u8f74\u90fd\u53ef\u4ee5\u62e5\u6709\u5206\u5c42\u7d22\u5f15\u3002 \u53c2\u8003","title":"DataFrame\u7d22\u5f15\u5206\u5c42"},{"location":"python/DataAnalysis/ch05/#1","text":"\u76f4\u63a5\u901a\u8fc7\u7ed9 index \uff08columns\uff09\u53c2\u6570\u4f20\u9012\u591a\u7ef4\u6570\u7ec4\uff0c\u8fdb\u800c\u6784\u5efa\u591a\u7ef4\u7d22\u5f15\u3002 \u6570\u7ec4\u4e2d\u6bcf\u4e2a\u7ef4\u5ea6\u5bf9\u5e94\u4f4d\u7f6e\u7684\u5143\u7d20\uff0c\u7ec4\u6210\u6bcf\u4e2a\u7d22\u5f15\u503c\u3002 frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]], columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) print(frame) # Ohio Colorado # Green Red Green # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 \u4e0a\u9762\u8f93\u51fa\u4e2d\u76842\u4e2a\u5c42\u7ea7\u662f\u6ca1\u6709\u540d\u5b57\u3002 \u5206\u5c42\u7684\u5c42\u7ea7\u53ef\u4ee5\u6709\u540d\u79f0\uff08\u53ef\u4ee5\u662f\u5b57\u7b26\u4e32\u6216Python\u5bf9\u8c61\uff09\u3002 \u5982\u679c\u5c42\u7ea7\u6709\u540d\u79f0\uff0c\u8fd9\u4e9b\u540d\u79f0\u4f1a\u5728\u63a7\u5236\u53f0\u8f93\u51fa\u4e2d\u663e\u793a\u3002 print(frame.index.names) # [None, None] print(frame.columns.names) # [None, None] \u7ed9\u5c42\u7ea7\u8d4b\u4e88\u540d\u79f0\u3002\u6ce8\u610f\u533a\u5206\u884c\u6807\u7b7e\u4e2d\u7684\u7d22\u5f15\u540d\u79f0 state \u548c color \u3002 frame.index.names = ['key1', 'key2'] frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 print(frame['Ohio']) # color Green Red # key1 key2 # a 1 0 1 # 2 3 4 # b 1 6 7 # 2 9 10 print(frame.index) # MultiIndex([('a', 1), # ('a', 2), # ('b', 1), # ('b', 2)], # names=['key1', 'key2']) \u901a\u8fc7 MultiIndex \u7c7b\u7684\u76f8\u5173\u65b9\u6cd5\uff0c\u9884\u5148\u521b\u5efa\u4e00\u4e2a MultiIndex \u5bf9\u8c61\uff0c\u7136\u540e\u4f5c\u4e3aSeries\u4e0eDataFrame\u4e2d\u7684 index \uff08\u6216columns\uff09\u53c2\u6570\u503c\u3002\u540c\u65f6\uff0c\u53ef\u4ee5\u901a\u8fc7 names \u53c2\u6570\u6307\u5b9a\u591a\u5c42\u7d22\u5f15\u7684\u540d\u79f0\u3002","title":"\u65b9\u6cd51\uff1a\u76f4\u63a5\u521b\u5efa"},{"location":"python/DataAnalysis/ch05/#2from_arrays","text":"from_arrays \uff1a\u63a5\u6536\u4e00\u4e2a\u591a\u7ef4\u6570\u7ec4\u53c2\u6570\uff0c\u9ad8\u7ef4\u6307\u5b9a\u9ad8\u5c42\u7d22\u5f15\uff0c\u4f4e\u7ef4\u6307\u5b9a\u5e95\u5c42\u7d22\u5f15\u3002 mindex = pd.MultiIndex.from_arrays( [['a', 'a', 'b', 'b'], [1, 2, 1, 2]], names=['key1', 'key2'] ) frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=mindex, columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11","title":"\u65b9\u6cd52\uff1afrom_arrays"},{"location":"python/DataAnalysis/ch05/#3from_tuples","text":"from_tuples \uff1a\u63a5\u6536\u4e00\u4e2a\u5143\u7ec4\u7684\u5217\u8868\uff0c\u6bcf\u4e2a\u5143\u7ec4\u6307\u5b9a\u6bcf\u4e2a\u7d22\u5f15\uff08\u9ad8\u7ef4\u7d22\u5f15\uff0c\u4f4e\u7ef4\u7d22\u5f15\uff09\u3002 mindex = pd.MultiIndex.from_tuples( [('a', 1), ('a', 2), ('b', 1), ('b', 2)] ) frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=mindex, columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) frame.index.names = ['key1', 'key2'] frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11","title":"\u65b9\u6cd53\uff1afrom_tuples"},{"location":"python/DataAnalysis/ch05/#4from_product","text":"from_product \uff1a\u63a5\u6536\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u7684\u5217\u8868\uff0c\u6839\u636e\u591a\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u5143\u7d20\u7684\u7b1b\u5361\u5c14\u79ef\u8fdb\u884c\u521b\u5efa\u7d22\u5f15\u3002 \u4f7f\u7528\u7b1b\u5361\u5c14\u79ef\u7684\u65b9\u5f0f\u6765\u521b\u5efa\u591a\u5c42\u7d22\u5f15\u3002\u53c2\u6570\u4e3a\u5d4c\u5957\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002\u7ed3\u679c\u4e3a\u4f7f\u7528\u6bcf\u4e2a\u4e00\u7ef4\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u4e0e\u5176\u4ed6\u4e00\u7ef4\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u6765\u751f\u6210\u3002 \u7b1b\u5361\u5c14\u79ef\u7684\u65b9\u5f0f\u7684\u5c40\u9650\uff1a\u4e24\u4e24\u7ec4\u5408\u5fc5\u987b\u90fd\u5b58\u5728\uff0c\u5426\u5219\uff0c\u5c31\u4e0d\u80fd\u4f7f\u7528\u8fd9\u79cd\u65b9\u5f0f\u3002 mindex = pd.MultiIndex.from_product( [['a', 'b'], ['1', '2']], names=['key1', 'key2'] ) frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=mindex, columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11","title":"\u65b9\u6cd54\uff1afrom_product"},{"location":"python/DataAnalysis/ch05/#_3","text":"\u5982\u679c\u9700\u8981\u91cd\u65b0\u6392\u5217\u8f74\u4e0a\u7684\u5c42\u7ea7\u987a\u5e8f\uff0c\u6216\u8005\u6309\u7167\u7279\u5b9a\u5c42\u7ea7\u7684\u503c\u5bf9\u6570\u636e\u8fdb\u884c\u6392\u5e8f\uff0c \u53ef\u4ee5\u901a\u8fc7swaplevel\u63a5\u6536\u4e24\u4e2a\u5c42\u7ea7\u5e8f\u53f7\u6216\u5c42\u7ea7\u540d\u79f0\uff0c\u8fd4\u56de\u4e00\u4e2a\u8fdb\u884c\u4e86\u5c42\u7ea7\u53d8\u66f4\u7684\u65b0\u5bf9\u8c61\uff08\u4f46\u662f\u6570\u636e\u662f\u4e0d\u53d8\u7684\uff09\u3002 print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 m = frame.swaplevel('key1', 'key2') print(m) # state Ohio Colorado # color Green Red Green # key2 key1 # 1 a 0 1 2 # 2 a 3 4 5 # 1 b 6 7 8 # 2 b 9 10 11 sort_index \u53ea\u80fd\u5728\u5355\u4e00\u5c42\u7ea7\u4e0a\u5bf9\u6570\u636e\u8fdb\u884c\u6392\u5e8f\u3002 \u5728\u8fdb\u884c\u5c42\u7ea7\u53d8\u6362\u65f6\uff0c\u4f7f\u7528 sort_index \u4ee5\u4f7f\u5f97\u7ed3\u679c\u6309\u7167\u5c42\u7ea7\u8fdb\u884c\u5b57\u5178\u6392\u5e8f\u3002 m = frame.sort_index(level=1) # \u5bf9key2\u6392\u5e8f\uff0c\u5e95\u5c42\u7d22\u5f15 print(m) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # b 1 6 7 8 # a 2 3 4 5 # b 2 9 10 11 m = frame.sort_index(level=0) # \u5bf9key1\u6392\u5e8f\uff0c\u9ad8\u5c42\u7d22\u5f15 print(m) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 m = frame.swaplevel(0, 1).sort_index(level=1) # swaplevel(0, 1)\u7b49\u540c\u4e8eswaplevel(key1, key2)\uff0c\u4ea4\u6362\u540ekey1\u53d8\u6210\u4e86\u5e95\u5c42\u7d22\u5f15 print(m) # state Ohio Colorado # color Green Red Green # key2 key1 # 1 a 0 1 2 # 2 a 3 4 5 # 1 b 6 7 8 # 2 b 9 10 11","title":"\u91cd\u6392\u5e8f\u548c\u5c42\u7ea7\u6392\u5e8f"},{"location":"python/DataAnalysis/ch05/#_4","text":"DataFrame\u548cSeries\u4e2d\u5f88\u591a\u63cf\u8ff0\u6027\u548c\u6c47\u603b\u6027\u7edf\u8ba1\u6709\u4e00\u4e2a level \u9009\u9879\uff0c\u901a\u8fc7 level \u9009\u9879\u4f60\u53ef\u4ee5\u6307\u5b9a\u4f60\u60f3\u8981\u5728\u67d0\u4e2a\u7279\u5b9a\u7684\u8f74\u4e0a\u8fdb\u884c\u805a\u5408\u3002 print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 m = frame.groupby(level='key2').sum() print(m) # state Ohio Colorado # color Green Red Green # key2 # 1 6 8 10 # 2 12 14 16 m = frame.groupby(level='color', axis=1).sum() print(m) # color Green Red # key1 key2 # a 1 2 1 # 2 8 4 # b 1 14 7 # 2 20 10","title":"\u6309\u5c42\u7ea7\u8fdb\u884c\u6c47\u603b\u7edf\u8ba1"},{"location":"python/DataAnalysis/ch05/#dataframe_1","text":"\u901a\u5e38\u6211\u4eec\u4e0d\u4f1a\u4f7f\u7528DataFrame\u4e2d\u4e00\u4e2a\u6216\u591a\u4e2a\u5217\u4f5c\u4e3a\u884c\u7d22\u5f15\uff1b\u53cd\u800c\u4f60\u53ef\u80fd\u60f3\u8981\u5c06\u884c\u7d22\u5f15\u79fb\u52a8\u5230DataFrame\u7684\u5217\u4e2d\u3002 frame = pd.DataFrame( {'a': range(7), 'b': range(7, 0, -1), 'c': ['one', 'one', 'one', 'two', 'two', 'two', 'two'], 'd': [0, 1, 2, 0, 1, 2, 3] } ) print(frame) # a b c d # 0 0 7 one 0 # 1 1 6 one 1 # 2 2 5 one 2 # 3 3 4 two 0 # 4 4 3 two 1 # 5 5 2 two 2 # 6 6 1 two 3 DataFrame\u7684 set_index \u51fd\u6570\u4f1a\u751f\u6210\u4e00\u4e2a\u65b0\u7684DataFrame\uff0c\u65b0\u7684DataFrame\u4f7f\u7528\u4e00\u4e2a\u6216\u591a\u4e2a\u5217\u4f5c\u4e3a\u7d22\u5f15\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\u8fd9\u4e9b\u7d22\u5f15\u5217\u4f1a\u4eceDataFrame\u4e2d\u79fb\u9664\uff0c\u4e5f\u53ef\u4ee5\u5c06\u5b83\u4eec\u7559\u5728DataFrame\u4e2d\u3002 frame2 = frame.set_index(['c', 'd'], drop=False) print(frame2) # a b c d # c d # one 0 0 7 one 0 # 1 1 6 one 1 # 2 2 5 one 2 # two 0 3 4 two 0 # 1 4 3 two 1 # 2 5 2 two 2 # 3 6 1 two 3 frame2 = frame.set_index(['c', 'd']) print(frame2) # a b # c d # one 0 0 7 # 1 1 6 # 2 2 5 # two 0 3 4 # 1 4 3 # 2 5 2 # 3 6 1 reset_index \u662f set_index \u7684\u53cd\u64cd\u4f5c\uff0c\u5206\u5c42\u7d22\u5f15\u7684\u7d22\u5f15\u5c42\u7ea7\u4f1a\u88ab\u79fb\u52a8\u5230\u5217\u4e2d\u3002 \u6ce8\u610f\uff1a\u5982\u679c\u5728 set_index \u65f6\u4f7f\u7528\u4e86 drop=False \uff0c\u5728\u4f7f\u7528 reset_index \u4f1a\u62a5\u9519\u3002 m = frame2.reset_index() print(m) # c d a b # 0 one 0 0 7 # 1 one 1 1 6 # 2 one 2 2 5 # 3 two 0 3 4 # 4 two 1 4 3 # 5 two 2 5 2 # 6 two 3 6 1","title":"\u4f7f\u7528DataFrame\u7684\u5217\u8fdb\u884c\u7d22\u5f15"},{"location":"python/DataAnalysis/ch05/#_5","text":"\u5305\u542b\u5728pandas\u5bf9\u8c61\u7684\u6570\u636e\u53ef\u4ee5\u901a\u8fc7\u591a\u79cd\u65b9\u5f0f\u8054\u5408\u5728\u4e00\u8d77\uff1a pandas.merge \u6839\u636e\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u5c06\u884c\u8fdb\u884c\u8fde\u63a5\u3002\u5bf9\u4e8eSQL\u6216\u5176\u4ed6\u5173\u7cfb\u578b\u6570\u636e\u5e93\u7684\u7528\u6237\u6765\u8bf4\uff0c\u8fd9\u79cd\u65b9\u5f0f\u6bd4\u8f83\u719f\u6089\uff0c\u5b83\u5b9e\u73b0\u7684\u662f\u6570\u636e\u5e93\u7684\u8fde\u63a5\u64cd\u4f5c\u3002 pandas.concat \u4f7f\u5bf9\u8c61\u5728\u8f74\u5411\u4e0a\u8fdb\u884c\u9ecf\u5408\u6216\u201c\u5806\u53e0\u201d\u3002 combine_first \u5b9e\u4f8b\u65b9\u6cd5\u5141\u8bb8\u5c06\u91cd\u53e0\u7684\u6570\u636e\u62fc\u63a5\u5728\u4e00\u8d77\uff0c\u4ee5\u4f7f\u7528\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u7684\u503c\u586b\u5145\u53e6\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u7684\u7f3a\u5931\u503c\u3002","title":"\u8054\u5408\u4e0e\u5408\u5e76\u6570\u636e\u96c6"},{"location":"python/DataAnalysis/ch05/#dataframe_2","text":"\u5408\u5e76\u6216\u8fde\u63a5\u64cd\u4f5c\u901a\u8fc7\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u8fde\u63a5\u884c\u6765\u8054\u5408\u6570\u636e\u96c6\u3002 \u8fd9\u4e9b\u64cd\u4f5c\u662f\u5173\u7cfb\u578b\u6570\u636e\u5e93\u7684\u6838\u5fc3\u5185\u5bb9\uff08\u4f8b\u5982\u57fa\u4e8eSQL\u7684\u6570\u636e\u5e93\uff09\u3002 pandas\u4e2d\u7684 merge \u51fd\u6570\u4e3b\u8981\u7528\u4e8e\u5c06\u5404\u79cd join \u64cd\u4f5c\u7b97\u6cd5\u8fd0\u7528\u5728\u6570\u636e\u4e0a\u3002 \u5728\u8fdb\u884c\u5217-\u5217\u8fde\u63a5\u65f6\uff0c\u4f20\u9012\u7684DataFrame\u7d22\u5f15\u5bf9\u8c61\u4f1a\u88ab\u4e22\u5f03\u3002 \u5408\u5e76\u64cd\u4f5c\u4e5f\u8981\u8003\u8651\u5982\u4f55\u5904\u7406\u91cd\u53e0\u7684\u5217\u540d( suffixes \u540e\u7f00\u9009\u9879)\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u591a\u5bf9\u4e00\u8fde\u63a5\u7684\u4f8b\u5b50\u3002 df1 \u7684\u6570\u636e\u6709\u591a\u4e2a\u884c\u7684\u6807\u7b7e\u4e3a a \u548c b \uff0c\u800c df2 \u5728 key \u5217\u4e2d\u6bcf\u4e2a\u503c\u4ec5\u6709\u4e00\u884c\u3002 df1 = pd.DataFrame( { 'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7) } ) df2 = pd.DataFrame( { 'key': ['a', 'b', 'd'], 'data1': range(3) } ) print(df1) # key data1 # 0 b 0 # 1 b 1 # 2 a 2 # 3 c 3 # 4 a 4 # 5 a 5 # 6 b 6 print(df2) # key data1 # 0 a 0 # 1 b 1 # 2 d 2 \u8c03\u7528 merge \u5904\u7406\uff0c\u63a8\u8350\u663e\u5f0f\u5730\u6307\u5b9a\u8fde\u63a5\u952e\u3002 result = pd.merge(df1, df2) print(result) # key data1 # 0 b 1 result = pd.merge(df1, df2, on=['key', 'data1']) print(result) # key data1 # 0 b 1 result = pd.merge(df1, df2, on='key') print(result) # key data1_x data1_y # 0 b 0 1 # 1 b 1 1 # 2 b 6 1 # 3 a 2 0 # 4 a 4 0 # 5 a 5 0 \u5982\u679c\u6bcf\u4e2a\u5bf9\u8c61\u7684\u5217\u540d\u662f\u4e0d\u540c\u7684\uff0c\u53ef\u4ee5\u5206\u522b\u4e3a\u5b83\u4eec\u6307\u5b9a\u5217\u540d\u3002 df3 = pd.DataFrame( { 'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7) } ) df4 = pd.DataFrame( { 'rkey': ['a', 'b', 'd'], 'data2': range(3) } ) print(df3) # lkey data1 # 0 b 0 # 1 b 1 # 2 a 2 # 3 c 3 # 4 a 4 # 5 a 5 # 6 b 6 print(df4) # rkey data2 # 0 a 0 # 1 b 1 # 2 d 2 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c merge \u505a\u7684\u662f\u5185\u8fde\u63a5\uff08'inner' join\uff09\uff0c\u7ed3\u679c\u4e2d\u7684\u952e\u662f\u4e24\u5f20\u8868\u7684\u4ea4\u96c6\u3002 result = pd.merge(df3, df4, left_on='lkey', right_on='rkey') # df4\u7684[a,0]\u5bf9\u5e94df3\u7684\u6240\u6709[a,?]\u8bb0\u5f55\uff08\u901a\u8fc7\u91cd\u590d\u6765\u586b\u5145\u4e0d\u8db3\uff09 print(result) # lkey data1 rkey data2 # 0 b 0 b 1 # 1 b 1 b 1 # 2 b 6 b 1 # 3 a 2 a 0 # 4 a 4 a 0 # 5 a 5 a 0 \u5916\u8fde\u63a5\uff08outer join\uff09\u662f\u952e\u7684\u5e76\u96c6\uff0c\u8054\u5408\u4e86\u5de6\u8fde\u63a5\u548c\u53f3\u8fde\u63a5\u7684\u6548\u679c\u3002 \u591a\u5bf9\u591a\u8fde\u63a5\u662f\u884c\u7684\u7b1b\u5361\u5c14\u79ef\u3002 df1 = pd.DataFrame( { 'key': ['b', 'b', 'a', 'c', 'a', 'b'], 'data1': range(6) } ) df2 = pd.DataFrame( { 'key': ['a', 'b', 'a', 'b', 'd'], 'data2': range(5) } ) print(df1.sort_values(by='key')) # key data1 # 2 a 2 # 4 a 4 # 0 b 0 # 1 b 1 # 5 b 5 # 3 c 3 print(df2.sort_values(by='key')) # key data2 # 0 a 0 # 2 a 2 # 1 b 1 # 3 b 3 # 4 d 4 result = pd.merge(df1, df2, on='key', how='left') print(result.sort_values(by='key')) # key data1 data2 # 4 a 2 0.0 # 5 a 2 2.0 # 7 a 4 0.0 # 8 a 4 2.0 # 0 b 0 1.0 # 1 b 0 3.0 # 2 b 1 1.0 # 3 b 1 3.0 # 9 b 5 1.0 # 10 b 5 3.0 # 6 c 3 NaN result = pd.merge(df1, df2, on='key', how='outer') # \u591a\u5bf9\u591a\u8fde\u63a5 print(result.sort_values(by='key')) # key data1 data2 # 6 a 2.0 0.0 # 7 a 2.0 2.0 # 8 a 4.0 0.0 # 9 a 4.0 2.0 # 0 b 0.0 1.0 # 1 b 0.0 3.0 # 2 b 1.0 1.0 # 3 b 1.0 3.0 # 4 b 5.0 1.0 # 5 b 5.0 3.0 # 10 c 3.0 NaN # 11 d NaN 4.0 \u591a\u952e\u5408\u5e76\u3002 df1 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar'], 'key2': ['one', 'two', 'one'], 'lval': [1, 2, 3] } ) df2 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar', 'bar'], 'key2': ['one', 'one', 'one', 'two'], 'rval': [4, 5, 6, 7] } ) print(df1.sort_values(by=['key1', 'key2'])) # key1 key2 lval # 2 bar one 3 # 0 foo one 1 # 1 foo two 2 print(df2.sort_values(by=['key1', 'key2'])) # key1 key2 rval # 2 bar one 6 # 3 bar two 7 # 0 foo one 4 # 1 foo one 5 result = pd.merge(df1, df2, on=['key1', 'key2'], how='outer') print(result.sort_values(by=['key1', 'key2'])) # key1 key2 lval rval # 3 bar one 3.0 6.0 # 4 bar two NaN 7.0 # 0 foo one 1.0 4.0 # \u91cd\u590d\u586b\u5145 # 1 foo one 1.0 5.0 # \u91cd\u590d\u586b\u5145 # 2 foo two 2.0 NaN \u5904\u7406\u91cd\u53e0\u5217\u540d\u3002 result = pd.merge(df1, df2, on='key1') print(result.sort_values(by='key1')) # key1 key2_x lval key2_y rval # 4 bar one 3 one 6 # 5 bar one 3 two 7 # 0 foo one 1 one 4 # 1 foo one 1 one 5 # 2 foo two 2 one 4 # 3 foo two 2 one 5 result = pd.merge(df1, df2, on='key1', suffixes=('_left', '_right')) print(result.sort_values(by='key1')) # key1 key2_left lval key2_right rval # 4 bar one 3 one 6 # 5 bar one 3 two 7 # 0 foo one 1 one 4 # 1 foo one 1 one 5 # 2 foo two 2 one 4 # 3 foo two 2 one 5","title":"\u6570\u636e\u5e93\u98ce\u683c\u7684DataFrame\u8fde\u63a5"},{"location":"python/DataAnalysis/ch05/#_6","text":"\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0cDataFrame\u4e2d\u7528\u4e8e\u5408\u5e76\u7684\u952e\u662f\u5b83\u7684\u7d22\u5f15\u3002\u53ef\u4ee5\u4f20\u9012 left_index=True \u6216 right_index=True \uff08\u6216\u8005\u90fd\u4f20\uff09\u6765\u8868\u793a\u7d22\u5f15\u9700\u8981\u7528\u6765\u4f5c\u4e3a\u5408\u5e76\u7684\u952e\u3002 df1 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar'], 'key2': ['one', 'two', 'one'], 'lval': [1, 2, 3] } ) df2 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar', 'bar'], 'key2': ['one', 'one', 'one', 'two'], 'rval': [4, 5, 6, 7] }, index=['foo', 'foo', 'bar', 'bar'] ) print(df1) # key1 key2 lval # 0 foo one 1 # 1 foo two 2 # 2 bar one 3 print(df2) # key1 key2 rval # foo foo one 4 # foo foo one 5 # bar bar one 6 # bar bar two 7 result = pd.merge(df1, df2, left_on='key1', right_index=True, suffixes=('_left', '_right')) print(result.sort_index()) # key1 key1_left key2_left lval key1_right key2_right rval # 0 foo foo one 1 foo one 4 # 0 foo foo one 1 foo one 5 # 1 foo foo two 2 foo one 4 # 1 foo foo two 2 foo one 5 # 2 bar bar one 3 bar one 6 # 2 bar bar one 3 bar two 7 result = pd.merge(df1, df2, left_on='key1', right_index=True, how='outer', suffixes=('_left', '_right')) # \u548c\u4e0a\u8ff0\u7ed3\u679c\u4e00\u6837 print(result.sort_index()) # key1 key1_left key2_left lval key1_right key2_right rval # 0 foo foo one 1 foo one 4 # 0 foo foo one 1 foo one 5 # 1 foo foo two 2 foo one 4 # 1 foo foo two 2 foo one 5 # 2 bar bar one 3 bar one 6 # 2 bar bar one 3 bar two 7 \u5728\u66f4\u590d\u6742\u591a\u5c42\u7d22\u5f15\u6570\u636e\u7684\u591a\u952e\u5408\u5e76\uff0c\u5728\u7d22\u5f15\u4e0a\u8fde\u63a5\u662f\u4e00\u4e2a\u9690\u5f0f\u7684\u591a\u952e\u5408\u5e76\u3002 \u5fc5\u987b\u4ee5\u5217\u8868\u7684\u65b9\u5f0f\u6307\u660e\u5408\u5e76\u6240\u9700\u591a\u4e2a\u5217\uff08\u6ce8\u610f\u4f7f\u7528 how='outer' \u5904\u7406\u91cd\u590d\u7684\u7d22\u5f15\u503c\uff09\u3002 df1 = pd.DataFrame( { 'key1': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'], 'key2': [2000, 2001, 2002, 2001, 2002], 'data': np.arange(5.) } ) df2 = pd.DataFrame( np.arange(12).reshape((6, 2)), index=[ ['Nevada', 'Nevada', 'Ohio', 'Ohio', 'Ohio', 'Ohio'], [2001, 2000, 2000, 2000, 2001, 2002] ], columns=['event1', 'event2'] ) print(df1) # key1 key2 data # 0 Ohio 2000 0.0 # 1 Ohio 2001 1.0 # 2 Ohio 2002 2.0 # 3 Nevada 2001 3.0 # 4 Nevada 2002 4.0 print(df2) # event1 event2 # Nevada 2001 0 1 # 2000 2 3 # Ohio 2000 4 5 # 2000 6 7 # 2001 8 9 # 2002 10 11 result = pd.merge(df1, df2, left_on=['key1', 'key2'], right_index=True) print(result) # key1 key2 data event1 event2 # 0 Ohio 2000 0.0 4 5 # 0 Ohio 2000 0.0 6 7 # 1 Ohio 2001 1.0 8 9 # 2 Ohio 2002 2.0 10 11 # 3 Nevada 2001 3.0 0 1 result = pd.merge(df1, df2, left_on=['key1', 'key2'], right_index=True, how='outer') print(result) # key1 key2 data event1 event2 # 0 Ohio 2000 0.0 4.0 5.0 # 0 Ohio 2000 0.0 6.0 7.0 # 1 Ohio 2001 1.0 8.0 9.0 # 2 Ohio 2002 2.0 10.0 11.0 # 3 Nevada 2001 3.0 0.0 1.0 # 4 Nevada 2002 4.0 NaN NaN # 4 Nevada 2000 NaN 2.0 3.0 \u4f7f\u7528\u4e24\u8fb9\u7684\u7d22\u5f15\u8fdb\u884c\u5408\u5e76\u4e5f\u662f\u53ef\u4ee5\u7684\uff0c\u524d\u63d0\u662f\u7528\u4e24\u8fb9\u7528\u6765\u5408\u5e76\u7684\u7d22\u5f15\u6709\u4ea4\u96c6\uff08\u516c\u5171\u90e8\u5206\uff09\u3002 \u5728\u4f7f\u7528 merge \u65f6\uff0c\u53c2\u6570 on=['key1', 'key2'] \u4e0d\u80fd\u548c left_index=True , right_index=True \u540c\u65f6\u5b58\u5728\u3002 \u5bf9\u4e8e\u91cd\u590d\u7d22\u5f15\uff0c\u5982\u679c\u503c\u4e0d\u540c\uff0c\u5219\u591a\u884c\u663e\u793a\uff0c\u548c\u6570\u636e\u5e93SQL\u7684 full join \u7c7b\u4f3c\u6982\u5ff5\u3002 \u5982\u679c\u51fa\u73b0\u76f8\u540c\u5217\u540d\uff0c\u5219\u4f1a\u81ea\u52a8\u6dfb\u52a0\u540e\u7f00\u5b57\u7b26\u4ee5\u793a\u533a\u522b\u3002 df1 = pd.DataFrame( [[1, 2], [3, 4], [5, 6]], index=['a', 'c', 'e'], columns=['Ohio', 'Nevada'] ) print(df1) # Ohio Nevada # a 1 2 # c 3 4 # e 5 6 df2 = pd.DataFrame( [[7, 8], [9, 10], [11, 12], [13, 14]], index=['b', 'c', 'c', 'e'], columns=['Missouri', 'Alabama'] ) print(df2) # Missouri Alabama # b 7 8 # c 9 10 # c 11 12 # e 13 14 df3 = pd.DataFrame( [[7, 8], [9, 10], [11, 12], [13, 14]], index=['a', 'c', 'e', 'f'], columns=['Nevada', 'Alabama'] ) print(df3) # Nevada Alabama # a 7 8 # c 9 10 # e 11 12 # f 13 14 result = pd.merge(df1, df2, left_index=True, right_index=True, how='outer') print(result) # Ohio Nevada Missouri Alabama # a 1.0 2.0 NaN NaN # b NaN NaN 7.0 8.0 # c 3.0 4.0 9.0 10.0 # c 3.0 4.0 11.0 12.0 # e 5.0 6.0 13.0 14.0 result = pd.merge(df1, df3, left_index=True, right_index=True, how='outer') print(result) # Ohio Nevada_x Nevada_y Alabama # a 1.0 2.0 7 8 # c 3.0 4.0 9 10 # e 5.0 6.0 11 12 # f NaN NaN 13 14 \u53e6\u4e00\u79cd\u5199\u6cd5\uff1a result = df1.join(df2, how='outer') print(result) # Ohio Nevada Missouri Alabama # a 1.0 2.0 NaN NaN # b NaN NaN 7.0 8.0 # c 3.0 4.0 9.0 10.0 # c 3.0 4.0 11.0 12.0 # e 5.0 6.0 13.0 14.0 \u4e5f\u53ef\u4ee5\u5411 join \u65b9\u6cd5\u4f20\u5165\u4e00\u4e2aDataFrame\u5217\u8868\uff0c\u7c7b\u4f3c\u4e8e\u5bf9\u4e09\u4e2a\u6570\u636e\u96c6\u8fdb\u884c join \u64cd\u4f5c\u3002 result = df1.join([df2, df3]) print(result) # Ohio Nevada_x Missouri Alabama_x Nevada_y Alabama_y # a 1 2 NaN NaN 7 8 # c 3 4 9.0 10.0 9 10 # c 3 4 11.0 12.0 9 10 # e 5 6 13.0 14.0 11 12","title":"\u6839\u636e\u7d22\u5f15\u5408\u5e76"},{"location":"python/DataAnalysis/ch05/#_7","text":"\u53e6\u4e00\u79cd\u6570\u636e\u7ec4\u5408\u64cd\u4f5c\u53ef\u79f0\u4e3a\u62fc\u63a5\u3001\u7ed1\u5b9a\u6216\u5806\u53e0\u3002NumPy\u7684 concatenate \u51fd\u6570\u53ef\u4ee5\u5728NumPy\u6570\u7ec4\u4e0a\u5b9e\u73b0\u8be5\u529f\u80fd\u3002 \u57fa\u4e8eSeries\u7684pandas\u7684 concat \u51fd\u6570\u7684\u5de5\u4f5c\u673a\u5236\u5206\u6790\u3002 \u4e0b\u9762\u4e09\u4e2a\u7d22\u5f15\u4e0d\u91cd\u53e0\u7684Series\u3002 s1 = pd.Series([0, 1], index=['a', 'b']) s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e']) s3 = pd.Series([5, 6], index=['f', 'g']) \u7528\u5217\u8868\u4e2d\u7684\u8fd9\u4e9b\u5bf9\u8c61\u8c03\u7528 concat \u65b9\u6cd5\u4f1a\u5c06\u503c\u548c\u7d22\u5f15\u7c98\u5728\u4e00\u8d77\uff1a \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c concat \u65b9\u6cd5\u662f\u6cbf\u7740 axis=0 \u7684\u8f74\u5411\u751f\u6548\u7684\uff0c\u751f\u6210\u53e6\u4e00\u4e2aSeries\u3002 \u5982\u679c\u4f20\u9012 axis=1 \uff0c\u8fd4\u56de\u7684\u7ed3\u679c\u5219\u662f\u4e00\u4e2aDataFrame\uff08 axis=1 \u65f6\u662f\u5217\uff09\u3002 result = pd.concat([s1, s2, s3]) print(result) # a 0 # b 1 # c 2 # d 3 # e 4 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s2, s3], keys=['one', 'two', 'three']) # \u901a\u8fc7keys\u53c2\u6570\uff0c\u5728\u8fde\u63a5\u8f74\u5411\u4e0a\u521b\u5efa\u4e00\u4e2a\u591a\u5c42\u7d22\u5f15\uff0c\u4ee5\u4fbf\u5728\u7ed3\u679c\u4e2d\u533a\u5206\u5404\u90e8\u5206 print(result) # one a 0 # b 1 # two c 2 # d 3 # e 4 # three f 5 # g 6 # dtype: int64 print(result.unstack()) # \u628a\u539f\u7d22\u5f15\u4f5c\u4e3a\u5217\u6807\u7b7e\u5c55\u5f00 # a b c d e f g # one 0.0 1.0 NaN NaN NaN NaN NaN # two NaN NaN 2.0 3.0 4.0 NaN NaN # three NaN NaN NaN NaN NaN 5.0 6.0 result = pd.concat([s1, s2, s3], axis=1) # \u5728\u8fd9\u4e2a\u6848\u4f8b\u4e2daxis=1\u8f74\u5411\u4e0a\u5e76\u6ca1\u6709\u91cd\u53e0 print(result) # 0 1 2 # a 0.0 NaN NaN # b 1.0 NaN NaN # c NaN 2.0 NaN # d NaN 3.0 NaN # e NaN 4.0 NaN # f NaN NaN 5.0 # g NaN NaN 6.0 result = pd.concat([s1, s2, s3], axis=1, keys=['one', 'two', 'three']) # \u5728\u8fd9\u4e2a\u6848\u4f8b\u4e2daxis=1\u8f74\u5411\u4e0a\u5e76\u6ca1\u6709\u91cd\u53e0 print(result) # one two three # a 0.0 NaN NaN # b 1.0 NaN NaN # c NaN 2.0 NaN # d NaN 3.0 NaN # e NaN 4.0 NaN # f NaN NaN 5.0 # g NaN NaN 6.0 print(result.unstack()) # \u5bf9\u6bd4axis=0\u7684\u591a\u5c42\u7d22\u5f15\uff0c\u5f53axis=1\u65f6\u5bf9\u8f93\u51fa\u5404index\u7684\u5e76\u96c6\u505a\u4e86\u5206\u7ec4\u3002 # one a 0.0 # b 1.0 # c NaN # d NaN # e NaN # f NaN # g NaN # two a NaN # b NaN # c 2.0 # d 3.0 # e 4.0 # f NaN # g NaN # three a NaN # b NaN # c NaN # d NaN # e NaN # f 5.0 # g 6.0 # dtype: float64 s4 = pd.concat([s1, s3]) print(s4) # a 0 # b 1 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s4]) print(result) # a 0 # b 1 # a 0 # b 1 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s4], axis=1) # \u73b0\u5728\u5728\u4e2daxis=1\u8f74\u5411\u4e0a\u6709\u91cd\u53e0 print(result) # 0 1 # a 0.0 0 # b 1.0 1 # f NaN 5 # g NaN 6 result = pd.concat([s1, s4], axis=1, keys=['one', 'two', 'three']) print(result) # one two # a 0.0 0 # b 1.0 1 # f NaN 5 # g NaN 6 result = pd.concat([s1, s4], axis=0, keys=['one', 'two', 'three']) # \u901a\u8fc7keys\u53c2\u6570\uff0c\u5728\u8fde\u63a5\u8f74\u5411\u4e0a\u521b\u5efa\u4e00\u4e2a\u591a\u5c42\u7d22\u5f15 print(result) # one a 0 # b 1 # two a 0 # b 1 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s4], axis=1, join='inner') # \u5185\u8fde\u63a5\u65b9\u5f0f\u5408\u5e76\u7d22\u5f15\uff08\u7d22\u5f15\u4ea4\u96c6\uff09 print(result) # 0 1 # a 0 0 # b 1 1 result = pd.concat([s1, s4], axis=1).reindex(['a', 'c', 'b', 'e']) # \u4f7f\u7528join_axes(\u5df2\u88ab\u66ff\u6362\u6210reindex)\u6765\u6307\u5b9a\u7528\u4e8e\u8fde\u63a5\u5176\u4ed6\u8f74\u5411\u7684\u8f74 print(result) # 0 1 # a 0.0 0.0 # c NaN NaN # b 1.0 1.0 # e NaN NaN \u57fa\u4e8eDataFrame\u7684pandas\u7684 concat \u51fd\u6570\u7684\u5de5\u4f5c\u673a\u5236\u5206\u6790\u3002 df1 = pd.DataFrame( np.arange(12).reshape((6, 2)), index=[ ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], [2000, 2001, 2002, 2000, 2001, 2002] ], columns=['event1', 'event2'] ) df2 = pd.DataFrame( np.arange(12).reshape((6, 2)), index=[ ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], [2000, 2001, 2002, 2000, 2001, 2002] ], columns=['event3', 'event4'] ) print(df1) # event1 event2 # Ohio 2000 0 1 # 2001 2 3 # 2002 4 5 # Nevada 2000 6 7 # 2001 8 9 # 2002 10 11 print(df2) # event3 event4 # Ohio 2000 0 1 # 2001 2 3 # 2002 4 5 # Nevada 2000 6 7 # 2001 8 9 # 2002 10 11 result = np.concatenate([df1, df2], axis=0) # \u6cbf0\u8f74\u62fc\u63a5 print(result) # [[ 0 1] # [ 2 3] # [ 4 5] # [ 6 7] # [ 8 9] # [10 11] # [ 0 1] # [ 2 3] # [ 4 5] # [ 6 7] # [ 8 9] # [10 11]] result = np.concatenate([df1, df2], axis=1) # \u6cbf1\u8f74\u62fc\u63a5 print(result) # [[ 0 1 0 1] # [ 2 3 2 3] # [ 4 5 4 5] # [ 6 7 6 7] # [ 8 9 8 9] # [10 11 10 11]] result = np.concatenate([df1, df2], axis=None) # \u5c06\u6570\u7ec4\u5c55\u5e73 print(result) # [ 0 1 2 3 4 5 6 7 8 9 10 11 0 1 2 3 4 5 6 7 8 9 10 11]","title":"\u6cbf\u8f74\u5411\u8fde\u63a5"},{"location":"python/DataAnalysis/ch05/#_8","text":"\u53e6\u4e00\u4e2a\u6570\u636e\u8054\u5408\u573a\u666f\uff0c\u65e2\u4e0d\u662f\u5408\u5e76\u64cd\u4f5c\uff0c\u4e5f\u4e0d\u662f\u8fde\u63a5\u64cd\u4f5c\u3002 \u5047\u5982\u6709\u4e24\u4e2a\u6570\u636e\u96c6\uff0c\u8fd9\u4e24\u4e2a\u6570\u636e\u96c6\u7684\u7d22\u5f15\u5168\u90e8\u6216\u90e8\u5206\u91cd\u53e0\uff0c\u901a\u8fc7NumPy\u7684 where \u51fd\u6570\u53ef\u4ee5\u8fdb\u884c\u9762\u5411\u6570\u7ec4\u7684if-else\u7b49\u4ef7\u64cd\u4f5c\u3002 s1 = pd.Series( [np.nan, 2.5, 0.0, 3.5, 4.5, np.nan], index=['f', 'e', 'd', 'c', 'b', 'a'] ) s2 = pd.Series( [0.0, np.nan, 2.0, np.nan, np.nan, 5.0], index=['a', 'b', 'c', 'd', 'e', 'f'] ) print(s1) # f NaN # e 2.5 # d 0.0 # c 3.5 # b 4.5 # a NaN # dtype: float64 print(s2) # a 0.0 # b NaN # c 2.0 # d NaN # e NaN # f 5.0 # dtype: float64 \u65b9\u6cd51\uff0c\u901a\u8fc7Numpy\u7684 where \u51fd\u6570\u3002 result = np.where(pd.isnull(s1), s2, s1) # An array with elements from 'x'(s2) where 'condition'(isnull(s1)) is True, and elements from 'y'(s1) elsewhere. print(result) # [0. 2.5 0. 3.5 4.5 5. ] # s1 # s2 # result # f NaN # a 0.0 0. \u6761\u4ef6\u4e2ds1\u8be5\u5143\u7d20\u4e3anull\uff0c\u6240\u4ee5where\u51fd\u6570\u53d6\u5bf9\u5e94x(s2)\u7684\u5143\u7d20\uff08\u6ce8\u610f\uff0c\u4e0e\u7d22\u5f15\u987a\u5e8f\u65e0\u5173\uff09 # e 2.5 # b NaN 2.5 \u6761\u4ef6\u4e2ds1\u8be5\u5143\u7d20\u4e0d\u4e3anull\uff0c\u6240\u4ee5where\u51fd\u6570\u53d6\u5bf9\u5e94y(s1)\u7684\u5143\u7d20 # d 0.0 # c 2.0 0. # c 3.5 # d NaN 3.5 # b 4.5 # e NaN 4.5 # a NaN # f 5.0 5.0 \u6761\u4ef6\u4e2ds1\u8be5\u5143\u7d20\u4e3anull\uff0c\u6240\u4ee5where\u51fd\u6570\u53d6\u5bf9\u5e94x(s2)\u7684\u5143\u7d20 result = np.where(pd.isnull(s2), s1, s2) print(result) # [0. 2.5 2. 3.5 4.5 5. ] \u65b9\u6cd52\uff0c\u901a\u8fc7Series\u7684 combine_first \u65b9\u6cd5\u3002 result = s2.combine_first(s1) # \u6ce8\u610f\uff0ccombine_first\u662f\u6309\u7167s2\u7684\u7d22\u5f15\u987a\u5e8f\u68c0\u7d22\u7684\uff0c\u76f8\u540c\u7d22\u5f15\u7684s1\u7684\u503c\u4f1a\u586b\u5145\u5bf9\u5e94s2\u7684null print(result) # a 0.0 # b 4.5 # c 2.0 # d 0.0 # e 2.5 # f 5.0 # dtype: float64 \u65b9\u6cd53\uff1aPandas\u7684 combine_first \u65b9\u6cd5\u3002 df1 = pd.DataFrame( { 'a': [1.0, np.nan, 5.0, np.nan], 'b': [np.nan, 2.0, np.nan, 6.0], 'c': [2.0, 6.0, 10.0, 15.0] } ) df2 = pd.DataFrame( { 'a': [5.0, 4.0, np.nan, 3.0, 7.0], 'b': [np.nan, 3.0, 4.0, 6.0, 8.0] } ) print(df1) # a b c # 0 1.0 NaN 2.0 # 1 NaN 2.0 6.0 # 2 5.0 NaN 10.0 # 3 NaN 6.0 15.0 print(df2) # a b # 0 5.0 NaN # 1 4.0 3.0 # 2 NaN 4.0 # 3 3.0 6.0 # 4 7.0 8.0 result = df2.combine_first(df1) # \u7528df1\u7684\u503c\u53bb\u586b\u5145df2\u5bf9\u5e94\u7d22\u5f15\u4f4d\u7f6e\u7684null\u503c print(result) # a b c # 0 5.0 NaN 2.0 # 1 4.0 3.0 6.0 # 2 5.0 4.0 10.0 # 3 3.0 6.0 15.0 # 4 7.0 8.0 NaN","title":"\u8054\u5408\u91cd\u53e0\u6570\u636e"},{"location":"python/DataAnalysis/ch05/#_9","text":"\u91cd\u65b0\u6392\u5217\u8868\u683c\u578b\u6570\u636e\u6709\u591a\u79cd\u57fa\u7840\u64cd\u4f5c\u3002\u8fd9\u4e9b\u64cd\u4f5c\u88ab\u79f0\u4e3a\u91cd\u5851\u6216\u900f\u89c6\u3002 import numpy as np import pandas as pd","title":"\u91cd\u5851\u548c\u900f\u89c6"},{"location":"python/DataAnalysis/ch05/#_10","text":"\u591a\u5c42\u7d22\u5f15\u5728DataFrame\u4e2d\u63d0\u4f9b\u4e86\u4e00\u79cd\u4e00\u81f4\u6027\u65b9\u5f0f\u7528\u4e8e\u91cd\u6392\u5217\u6570\u636e\u3002\u4ee5\u4e0b\u662f\u4e24\u4e2a\u57fa\u7840\u64cd\u4f5c\uff1a statck\uff08\u5806\u53e0\uff09\u8be5\u64cd\u4f5c\u4f1a\u201c\u65cb\u8f6c\u201d\u6216\u5c06\u5217\u4e2d\u7684\u6570\u636e\u900f\u89c6\u5230\u884c\u3002 unstack\uff08\u62c6\u5806\uff09\u8be5\u64cd\u4f5c\u4f1a\u5c06\u884c\u4e2d\u7684\u6570\u636e\u900f\u89c6\u5230\u5217\u3002 df = pd.DataFrame( np.arange(6).reshape((2, 3)), index=pd.Index(['Ohio', 'Colorado'], name='state'), columns=pd.Index(['one', 'two', 'three'], name='number') ) print(df) # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 \u5728\u8fd9\u4efd\u6570\u636e\u4e0a\u4f7f\u7528stack\u65b9\u6cd5\u4f1a\u5c06\u5217\u900f\u89c6\u5230\u884c\uff0c\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684Series\uff1a result = df.stack() print(result) # state number # Ohio one 0 # two 1 # three 2 # Colorado one 3 # two 4 # three 5 # dtype: int64 \u4ece\u4e00\u4e2a\u591a\u5c42\u7d22\u5f15\u5e8f\u5217\u4e2d\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 unstack \u65b9\u6cd5\u5c06\u6570\u636e\u91cd\u6392\u5217\u540e\u653e\u5165\u4e00\u4e2aDataFrame\u4e2d\uff1a print(result.unstack()) # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 print(result.unstack(0)) # \u53ef\u4ee5\u4f20\u5165\u4e00\u4e2a\u5c42\u7ea7\u5e8f\u53f7\u6216\u540d\u79f0\u6765\u62c6\u5206\u4e00\u4e2a\u4e0d\u540c\u7684\u5c42\u7ea7 # state Ohio Colorado # number # one 0 3 # two 1 4 # three 2 5 print(result.unstack(1)) # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 print(result.unstack('state')) # \u8f93\u51fa\u7ed3\u679c\u548c\u4f20\u5165\u5c42\u7ea70\u4e00\u6837 # state Ohio Colorado # number # one 0 3 # two 1 4 # three 2 5 print(result.unstack('number')) # \u8f93\u51fa\u7ed3\u679c\u548c\u4f20\u5165\u5c42\u7ea71\u4e00\u6837 # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 \u5982\u679c\u5c42\u7ea7\u4e2d\u7684\u6240\u6709\u503c\u5e76\u672a\u5305\u542b\u4e8e\u6bcf\u4e2a\u5b50\u5206\u7ec4\u4e2d\u65f6\uff0c\u62c6\u5206\u53ef\u80fd\u4f1a\u5f15\u5165\u7f3a\u5931\u503c\uff1a s1 = pd.Series([0, 1, 2, 3], index=['a', 'b', 'c', 'd']) s2 = pd.Series([4, 5, 6], index=['c', 'd', 'e']) s3 = pd.concat([s1, s2], keys=['one', 'two']) print(s3) # one a 0 # b 1 # c 2 # d 3 # two c 4 # d 5 # e 6 # dtype: int64 print(s3.unstack(0)) # one two # a 0.0 NaN # b 1.0 NaN # c 2.0 4.0 # d 3.0 5.0 # e NaN 6.0 print(s3.unstack(1)) print(s3.unstack()) # a b c d e # one 0.0 1.0 2.0 3.0 NaN # two NaN NaN 4.0 5.0 6.0 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5806\u53e0\u4f1a\u8fc7\u6ee4\u51fa\u7f3a\u5931\u503c\uff0c\u56e0\u6b64\u5806\u53e0\u62c6\u5806\u7684\u64cd\u4f5c\u662f\u53ef\u9006\u7684\u3002 print(s3.unstack().stack()) # one a 0.0 # b 1.0 # c 2.0 # d 3.0 # two c 4.0 # d 5.0 # e 6.0 # dtype: float64 print(s3.unstack().stack(dropna=False)) # one a 0.0 # b 1.0 # c 2.0 # d 3.0 # e NaN # two a NaN # b NaN # c 4.0 # d 5.0 # e 6.0 # dtype: float64 \u5728DataFrame\u4e2d\u62c6\u5806\u65f6\uff0c\u88ab\u62c6\u5806\u7684\u5c42\u7ea7\u4f1a\u53d8\u4e3a\u7ed3\u679c\u4e2d\u6700\u4f4e\u7684\u5c42\u7ea7\u3002 \u5728\u8c03\u7528 stack \u65b9\u6cd5\u65f6\uff0c\u6211\u4eec\u53ef\u4ee5\u6307\u660e\u9700\u8981\u5806\u53e0\u7684\u8f74\u5411\u540d\u79f0\u3002 df = pd.DataFrame( {'left': result, 'right': result + 5}, columns=pd.Index(['left', 'right'], name='side') ) print(df) # side left right # state number # Ohio one 0 5 # two 1 6 # three 2 7 # Colorado one 3 8 # two 4 9 # three 5 10 print(df.unstack()) # side left right # number one two three one two three # state # Ohio 0 1 2 5 6 7 # Colorado 3 4 5 8 9 10 print(df.unstack('state')) # \u88ab\u62c6\u5806\u7684\u5c42\u7ea7(state)\u4f1a\u53d8\u4e3a\u7ed3\u679c\u4e2d\u6700\u4f4e\u7684\u5c42\u7ea7 # side left right # state Ohio Colorado Ohio Colorado # number # one 0 3 5 8 # two 1 4 6 9 # three 2 5 7 10 \u5728\u8c03\u7528 stack \u65b9\u6cd5\u65f6\uff0c\u53ef\u4ee5\u6307\u660e\u9700\u8981\u5806\u53e0\u7684\u8f74\u5411\u540d\u79f0\uff1a print(df.unstack('state').stack('side')) # state Colorado Ohio # number side # one left 3 0 # right 8 5 # two left 4 1 # right 9 6 # three left 5 2 # right 10 7","title":"\u4f7f\u7528\u591a\u5c42\u7d22\u5f15\u8fdb\u884c\u91cd\u5851"},{"location":"python/DataAnalysis/ch05/#_11","text":"\u5728\u6570\u636e\u5e93\u548cCSV\u4e2d\u5b58\u50a8\u591a\u65f6\u95f4\u5e8f\u5217\u7684\u65b9\u5f0f\u5c31\u662f\u6240\u8c13\u7684\u957f\u683c\u5f0f\u6216\u5806\u53e0\u683c\u5f0f\u3002 data = pd.read_csv('../examples/macrodata.csv') print(data.head(3)) # year quarter realgdp realcons ... unemp pop infl realint # 0 1959.0 1.0 2710.349 1707.4 ... 5.8 177.146 0.00 0.00 # 1 1959.0 2.0 2778.801 1733.7 ... 5.1 177.830 2.34 0.74 # 2 1959.0 3.0 2775.488 1751.8 ... 5.3 178.657 2.74 1.09 # ...... # [3 rows x 14 columns] # PeriodIndex\u5c06year\u548cquarter\u7b49\u5217\u8fdb\u884c\u8054\u5408\u5e76\u751f\u6210\u4e86\u4e00\u79cd\u65f6\u95f4\u95f4\u9694\u7c7b\u578b periods = pd.PeriodIndex( year=data.year, quarter=data.quarter, name='date' ) columns = pd.Index( ['realgdp', 'infl', 'unemp'], name='item' ) data = data.reindex(columns=columns) print(data) # item realgdp infl unemp # 0 2710.349 0.00 5.8 # 1 2778.801 2.34 5.1 # 2 2775.488 2.74 5.3 # ...... # [203 rows x 3 columns] data.index = periods.to_timestamp('D', 'end') print(data.index) # DatetimeIndex(['1959-03-31 23:59:59.999999999', # '1959-06-30 23:59:59.999999999', # ... # '2009-06-30 23:59:59.999999999', # '2009-09-30 23:59:59.999999999'], # dtype='datetime64[ns]', name='date', length=203, freq=None) \u4e0b\u9762\u662fldata\u7684\u6570\u636e\u6837\u672c\u3002 \u8fd9\u79cd\u6570\u636e\u5373\u6240\u8c13\u7684\u591a\u65f6\u95f4\u5e8f\u5217\u7684\u957f\u683c\u5f0f\uff0c\u6216\u79f0\u4e3a\u5177\u6709\u4e24\u4e2a\u6216\u66f4\u591a\u4e2a\u952e\u7684\u5176\u4ed6\u89c2\u6d4b\u6570\u636e\uff08\u8fd9\u91cc\uff0c\u6211\u4eec\u7684\u952e\u662fdate\u548citem\uff09\u3002 \u8868\u4e2d\u7684\u6bcf\u4e00\u884c\u8868\u793a\u4e00\u4e2a\u65f6\u95f4\u70b9\u4e0a\u7684\u5355\u4e2a\u89c2\u6d4b\u503c\u3002 ldata = data.stack().reset_index().rename(columns={0: 'value'}) print(ldata) # date item value # 0 1959-03-31 23:59:59.999999999 realgdp 2710.349 # 1 1959-03-31 23:59:59.999999999 infl 0.000 # 2 1959-03-31 23:59:59.999999999 unemp 5.800 # 3 1959-06-30 23:59:59.999999999 realgdp 2778.801 # 4 1959-06-30 23:59:59.999999999 infl 2.340 # .. ... ... ... # 604 2009-06-30 23:59:59.999999999 infl 3.370 # 605 2009-06-30 23:59:59.999999999 unemp 9.200 # 606 2009-09-30 23:59:59.999999999 realgdp 12990.341 # 607 2009-09-30 23:59:59.999999999 infl 3.560 # 608 2009-09-30 23:59:59.999999999 unemp 9.600 # [609 rows x 3 columns] \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff1a \u6570\u636e\u901a\u5e38\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u5b58\u50a8\u5728\u5173\u7cfb\u578b\u6570\u636e\u5e93\u4e2d\uff0c\u6bd4\u5982MySQL\uff0c\u56e0\u4e3a\u56fa\u5b9a\u6a21\u5f0f\uff08\u5217\u540d\u79f0\u548c\u6570\u636e\u7c7b\u578b\uff09\u5141\u8bb8 item \u5217\u4e2d\u4e0d\u540c\u503c\u7684\u6570\u91cf\u968f\u7740\u6570\u636e\u88ab\u6dfb\u52a0\u5230\u8868\u4e2d\u800c\u6539\u53d8\u3002 date \u548c item \u901a\u5e38\u662f\u4e3b\u952e\uff08\u4f7f\u7528\u5173\u7cfb\u578b\u6570\u636e\u5e93\u7684\u8bf4\u6cd5\uff09\uff0c\u63d0\u4f9b\u4e86\u5173\u7cfb\u5b8c\u6574\u6027\u548c\u66f4\u7b80\u5355\u7684\u8fde\u63a5\u3002 \u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u5904\u7406\u8fd9\u79cd\u683c\u5f0f\u7684\u6570\u636e\u66f4\u4e3a\u56f0\u96be\u3002\u53ef\u80fd\u66f4\u503e\u5411\u4e8e\u83b7\u53d6\u4e00\u4e2a\u6309 date \u5217\u65f6\u95f4\u6233\u7d22\u5f15\u7684\u4e14\u6bcf\u4e2a\u4e0d\u540c\u7684 item \u72ec\u7acb\u4e00\u5217\u7684DataFrame\u3002 DataFrame\u7684pivot\u65b9\u6cd5\u5c31\u662f\u8fdb\u884c\u8fd9\u79cd\u8f6c\u6362\u7684\uff1a \u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c\u4f20\u9012\u7684\u524d\u4e24\u4e2a\u503c\u662f\u5206\u522b\u7528\u4f5c\u884c\u548c\u5217\u7d22\u5f15\u7684\u5217\uff0c\u7136\u540e\u662f\u53ef\u9009\u7684\u6570\u503c\u5217\u4ee5\u586b\u5145DataFrame\u3002 \u6ce8\u610f\uff0c pivot \u65b9\u6cd5\u7b49\u4ef7\u4e8e\u4f7f\u7528 set_index \u521b\u5efa\u5206\u5c42\u7d22\u5f15\uff0c\u7136\u540e\u8c03\u7528unstack\u3002 pivoted = ldata.pivot('date', 'item', 'value') print(pivoted) # item infl realgdp unemp # date # 1959-03-31 23:59:59.999999999 0.00 2710.349 5.8 # 1959-06-30 23:59:59.999999999 2.34 2778.801 5.1 # ... ... ... ... # 2009-06-30 23:59:59.999999999 3.37 12901.504 9.2 # 2009-09-30 23:59:59.999999999 3.56 12990.341 9.6 # [203 rows x 3 columns] ldata['value2'] = np.random.randn(len(ldata)) print(ldata[:5]) # date item value value2 # 0 1959-03-31 23:59:59.999999999 realgdp 2710.349 -1.268405 # 1 1959-03-31 23:59:59.999999999 infl 0.000 0.377691 # 2 1959-03-31 23:59:59.999999999 unemp 5.800 -0.342492 # 3 1959-06-30 23:59:59.999999999 realgdp 2778.801 0.132797 # 4 1959-06-30 23:59:59.999999999 infl 2.340 0.180290 \u6b64\u65f6 ldata \u5df2\u7ecf\u6dfb\u52a0\u4e86\u4e00\u5217\u3002\u5982\u679c\u9057\u6f0f\u6700\u540e\u4e00\u4e2a\u53c2\u6570\uff0c\u4f1a\u5f97\u5230\u4e00\u4e2a\u542b\u6709\u591a\u5c42\u5217\u7684DataFrame\uff0c\u5982\u4e0b\uff1a pivoted = ldata.pivot('date', 'item') print(pivoted) # value ... value2 # item infl realgdp ... realgdp unemp # date ... # 1959-03-31 23:59:59.999999999 0.00 2710.349 ... 0.157467 -0.222464 # 1959-06-30 23:59:59.999999999 2.34 2778.801 ... 0.861501 0.368855 # ... ... ... ... ... ... # 2009-06-30 23:59:59.999999999 3.37 12901.504 ... 0.279988 0.934972 # 2009-09-30 23:59:59.999999999 3.56 12990.341 ... 0.547914 1.842967 # [203 rows x 6 columns] \u6ce8\u610f\uff0c pivot \u65b9\u6cd5\u7b49\u4ef7\u4e8e\u4f7f\u7528 set_index \u521b\u5efa\u5206\u5c42\u7d22\u5f15\uff0c\u7136\u540e\u8c03\u7528 unstack \u3002 unstacked = ldata.set_index(['date', 'item']).unstack('item') print(unstacked[:5]) # value ... value2 # item infl realgdp ... realgdp unemp # date ... # 1959-03-31 23:59:59.999999999 0.00 2710.349 ... 0.213120 -0.248004 # 1959-06-30 23:59:59.999999999 2.34 2778.801 ... 0.697763 0.112388 # 1959-09-30 23:59:59.999999999 2.74 2775.488 ... 1.291884 -1.046142 # 1959-12-31 23:59:59.999999999 0.27 2785.204 ... 0.363339 -0.307364 # 1960-03-31 23:59:59.999999999 2.31 2847.699 ... 0.377330 2.272980 # [5 rows x 6 columns]","title":"\u5c06\u201c\u957f\u201d\u900f\u89c6\u4e3a\u201c\u5bbd\u201d"},{"location":"python/DataAnalysis/ch05/#_12","text":"\u5728DataFrame\u4e2d\uff0cpivot\u65b9\u6cd5\u7684\u53cd\u64cd\u4f5c\u662f pandas.melt \u3002 \u4e0e\u5c06\u4e00\u5217\u53d8\u6362\u4e3a\u65b0\u7684DataFrame\u4e2d\u7684\u591a\u5217\u4e0d\u540c\uff0c\u5b83\u5c06\u591a\u5217\u5408\u5e76\u6210\u4e00\u5217\uff0c\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684DataFrame\uff0c\u5176\u957f\u5ea6\u6bd4\u8f93\u5165\u66f4\u957f\u3002 df = pd.DataFrame( { 'key': ['foo', 'bar', 'baz'], 'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9] } ) print(df) # key A B C # 0 foo 1 4 7 # 1 bar 2 5 8 # 2 baz 3 6 9 key \u5217\u53ef\u4ee5\u4f5c\u4e3a\u5206\u7ec4\u6307\u6807\uff0c\u5176\u4ed6\u5217\u5747\u4e3a\u6570\u636e\u503c\u3002 \u5f53\u4f7f\u7528 pandas.melt \u65f6\uff0c\u6211\u4eec\u5fc5\u987b\u6307\u660e\u54ea\u4e9b\u5217\u662f\u5206\u7ec4\u6307\u6807\uff08\u5982\u679c\u6709\u7684\u8bdd\uff09\u3002 \u6b64\u5904\uff0c\u8ba9\u6211\u4eec\u4f7f\u7528 key \u4f5c\u4e3a\u552f\u4e00\u7684\u5206\u7ec4\u6307\u6807\uff1a melted = pd.melt(df, ['key']) print(melted) # key variable value # 0 foo A 1 # 1 bar A 2 # 2 baz A 3 # 3 foo B 4 # 4 bar B 5 # 5 baz B 6 # 6 foo C 7 # 7 bar C 8 # 8 baz C 9 \u4f7f\u7528 pivot \u65b9\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u6570\u636e\u91cd\u5851\u56de\u539f\u5148\u7684\u5e03\u5c40\u3002 reshaped = melted.pivot('key', 'variable', 'value') print(reshaped) # variable A B C # key # bar 2 5 8 # baz 3 6 9 # foo 1 4 7 \u7531\u4e8e pivot \u7684\u7ed3\u679c\u6839\u636e\u4f5c\u4e3a\u884c\u6807\u7b7e\u7684\u5217\u751f\u6210\u4e86\u7d22\u5f15\uff0c\u53ef\u4f7f\u7528 reset_index \u6765\u5c06\u6570\u636e\u56de\u79fb\u4e00\u5217\uff1a print(reshaped.reset_index()) # variable key A B C # 0 bar 2 5 8 # 1 baz 3 6 9 # 2 foo 1 4 7 pandas.melt \u7684\u4f7f\u7528\u4e5f\u53ef\u4ee5\u65e0\u987b\u4efb\u4f55\u5206\u7ec4\u6307\u6807\u3002 result = pd.melt(df, value_vars=['A', 'B', 'C']) print(result) # variable value # 0 A 1 # 1 A 2 # 2 A 3 # 3 B 4 # 4 B 5 # 5 B 6 # 6 C 7 # 7 C 8 # 8 C 9 result = pd.melt(df, value_vars=['key', 'B', 'C']) print(result) # variable value # 0 key foo # 1 key bar # 2 key baz # 3 B 4 # 4 B 5 # 5 B 6 # 6 C 7 # 7 C 8 # 8 C 9","title":"\u5c06\u201c\u5bbd\u201d\u900f\u89c6\u4e3a\u201c\u957f\u201d"},{"location":"python/DataAnalysis/ch06/","text":"\u7ed8\u56fe\u4e0e\u53ef\u89c6\u5316 \u00b6 \u7b80\u660ematplotlib API\u5165\u95e8 \u00b6 import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np import pandas as pd from io import BytesIO \u6267\u884c plt.show() \u65f6\u62a5\u9519\uff1a UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure. \u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u5f97\u5230 plt \u7684 backend \u662f\u7528 agg \u3002 plt.get_backend() \u4f8b\u5982\uff1a\u4e0b\u9762\u4e24\u79cd\u8868\u8fbe\u65b9\u5f0f\u6548\u679c\u4e00\u6837\u3002 ax.plot(x, y, 'g--') ax.plot(x, y, linestyle='--', color='g') Out[6]: 'agg' \u5b89\u88c5\u4e0b\u9762\u51e0\u4e2a\u5305\uff1a sudo zypper in python-tk python3-tk sudo zypper in plplot-tcltk-devel plplot-tcltk-libs pip install tk \u6dfb\u52a0\u4e0b\u9762\u5230python\u4ee3\u7801\u4e2d\u3002 import matplotlib.pyplot as plt mpl.use('TkAgg') \u6267\u884c\u540e\u62a5\u4e0b\u9762\u9519\u8bef\uff1a your Python may not be configured for Tk \u8fdb\u5165python\u6e90\u7801\u76ee\u5f55\uff0c\u91cd\u65b0\u7f16\u8bd1\u4f8b\u5982\uff1a\u4e0b\u9762\u4e24\u79cd\u8868\u8fbe\u65b9\u5f0f\u6548\u679c\u4e00\u6837\u3002 ax.plot(x, y, 'g--') ax.plot(x, y, linestyle='--', color='g') james@lizard:/opt/Python-3.9.6> sudo make james@lizard:/opt/Python-3.9.6> sudo make install \u95ee\u9898\u89e3\u51b3\uff0c\u5373\u4f7f\u4e0d\u52a0\u5165 mpl.use('TkAgg') \uff0c\u6267\u884c plt.show() \u4e5f\u662f\u53ef\u4ee5\u8f93\u51fa\u56fe\u50cf\u3002 \u56fe\u7247\u4e0e\u5b50\u56fe \u00b6 matplotlib \u6240\u7ed8\u5236\u7684\u56fe\u4f4d\u4e8e\u56fe\u7247\uff08Figure\uff09\u5bf9\u8c61\u4e2d\u3002\u53ef\u4ee5\u4f7f\u7528 plt.figure \u751f\u6210\u4e00\u4e2a\u65b0\u7684\u56fe\u7247\u3002 \u4f7f\u7528 add_subplot \u521b\u5efa\u4e00\u4e2a\u6216\u591a\u4e2a\u5b50\u56fe\uff08subplot\uff09\u3002 plt \u4e0e ax \u7ed8\u56fe\u3002 fig = plt.figure() # plt: \u5148\u751f\u6210\u4e86\u4e00\u4e2a\u753b\u5e03\uff0c\u7136\u540e\u5728\u8fd9\u4e2a\u753b\u5e03\u4e0a\u9690\u5f0f\u7684\u751f\u6210\u4e00\u4e2a\u753b\u56fe\u533a\u57df\u6765\u8fdb\u884c\u753b\u56fe # plt.plot([1, 2, 3, 4]) # plt.show() # ax: \u5148\u751f\u6210\u4e00\u4e2a\u753b\u5e03\uff082\u00d72\u7684\u533a\u57df\uff0c\u6700\u591a\u653e\u56db\u4e2a\u56fe\u5f62\uff09\uff0c\u7136\u540e\u5728\u6b64\u753b\u5e03\u4e0a\uff0c\u9009\u5b9a\u4e00\u4e2a\u5b50\u533a\u57df\u753b\u4e86\u4e00\u4e2a\u5b50\u56fe\uff08\u5e8f\u53f71\u4ee3\u8868\u7b2c\u4e00\u4e2a\u533a\u57df\uff09 ax1 = fig.add_subplot(2, 2, 1) # \u4e5f\u53ef\u4ee5\u5199\u6210fig.add_subplot(221) ax1.plot([1, 2, 3, 4], [1, 4, 3, 2]) # \u8f93\u51fa\u56fe\u7247\u5230\u7b2c\u4e00\u4e2a\u533a\u57df\u3002 # \u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u6570\u636e\u96c6\u91cc\u5404\u4e2a\u6570\u636e\u70b9\u7684X\u503c\u7684\u96c6\u5408 # \u7b2c\u4e8c\u4e2a\u53c2\u6570\u6570\u636e\u96c6\u91cc\u5404\u4e2a\u6570\u636e\u70b9\u7684Y\u503c\u7684\u96c6\u5408\u3002 # \u4e0d\u662f\u6570\u5b66\u4e0a\u5e38\u89c1\u7684\u6210\u5bf9\u5750\u6807\u70b9\u5982(x1,y1)\u3001(x2,y2)\u3001...\u3001(xn,yn)\u7684\u683c\u5f0f\uff0c\u800c\u662f (x1,x2,...,xn)\u548c(y1,y2,...,yn) \u3002 plt.show() \u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u589e\u52a0\u5b50\u56fe\u540e\u7684\u6570\u636e\u53ef\u89c6\u5316\u6548\u679c\u3002 fig = plt.figure() ax1 = fig.add_subplot(2, 2, 1) ax2 = fig.add_subplot(2, 2, 2) ax3 = fig.add_subplot(2, 2, 3) ax1.plot(np.random.randn(50).cumsum(), 'k--') # \u5728\u7b2c\u4e09\u4e2a\u533a\u57df\u8f93\u51fa\u56fe\u50cf\u3002'k--\u2019\u662f\u7528\u4e8e\u7ed8\u5236\u9ed1\u8272\u5206\u6bb5\u7ebf\u7684style\u9009\u9879\u3002 ax2.hist(np.random.randn(100), bins=20, color='k', alpha=0.3) ax3.scatter(np.arange(30), np.arange(30) + 3 * np.random.randn(30)) plt.show() plt.subplots \u901a\u8fc7 matplotlib \u7684 subplots \u65b9\u6cd5\uff0c\u4f7f\u7528\u5b50\u56fe\u7f51\u683c\u521b\u5efa\u56fe\u7247\uff0c\u7136\u540e\u8fd4\u56de\u5305\u542b\u4e86\u5df2\u751f\u6210\u5b50\u56fe\u5bf9\u8c61\u7684NumPy\u6570\u7ec4\u3002 \u6570\u7ec4 axes \u53ef\u4ee5\u50cf\u4e8c\u7ef4\u6570\u7ec4\u90a3\u6837\u65b9\u4fbf\u5730\u8fdb\u884c\u7d22\u5f15\uff0c\u4f8b\u5982\uff0c axes[0, 1] \u3002 plt.subplots \u53c2\u6570\u9009\u9879\uff1a nrows\uff1a\u53ef\u9009\u7684\uff0c\u6574\u578b\uff0c\u9ed8\u8ba4\u4e3a1\u3002\u5b50\u56fe\u7f51\u683c\u7684\u884c\u6570\u3002 ncols\uff1a\u53ef\u9009\u7684\uff0c\u6574\u578b\uff0c\u9ed8\u8ba4\u4e3a1\u3002\u5b50\u56fe\u7f51\u683c\u7684\u5217\u6570\u3002 sharex\uff1a\u53ef\u9009\u7684\uff0c\u9ed8\u8ba4\u4e3aFalse\u3002\u53ef\u9009\u503c\u5982\u4e0b\uff1a True\u6216all\uff0c\u6240\u6709\u5b50\u56fe\u5171\u4eabx\u8f74 False\u6216none\uff0c\u6bcf\u4e2a\u5b50\u56fe\u7684x\u8f74\u90fd\u662f\u72ec\u7acb\u7684 row\uff0c\u6bcf\u884c\u5b50\u56fe\u5171\u4eab\u4e00\u4e2ax\u8f74 col\uff0c\u6bcf\u5217\u5b50\u56fe\u5171\u4eab\u4e00\u4e2ax\u8f74 sharey\uff1a\u7c7b\u4f3c\u4e8esharex\uff0c\u8bbe\u7f6ey\u8f74\u7684\u5171\u4eab\u65b9\u5f0f\u3002\u5f53\u67d0\u5217\u5171\u4eab\u4e00\u4e2ax\u8f74\u65f6\uff0c\u53ea\u6709\u5e95\u90e8\u7684\u5b50\u56fe\u4f1a\u521b\u5efax\u8f74\u6807\u8bb0\u3002\u540c\u6837\u7684\uff0c\u5982\u679c\u67d0\u884c\u5171\u4eab\u4e00\u4e2ay\u8f74\u65f6\uff0c\u53ea\u6709\u884c\u7684\u7b2c\u4e00\u5217\u5b50\u56fe\u4f1a\u521b\u5efay\u8f74\u6807\u8bb0\u3002 squeeze \uff1a\u53ef\u9009\u7684\uff0c\u5e03\u5c14\u578b\uff0c\u9ed8\u8ba4\u4e3aTrue\u3002\u662f\u5426\u538b\u7f29\u8fd4\u56de\u7684Axes\u6570\u7ec4\u3002\u5982\u679c\u4e3aTrue\uff0c\u5f53\u53ea\u6709\u4e00\u4e2a\u5b50\u56fe\uff0c\u5373nrows\u548cncols\u5747\u4e3a1\u65f6\uff0c\u8fd4\u56de\u4e00\u4e2a\u5355\u72ec\u7684Axes\u5bf9\u8c61\uff0c\u5f53\u6709N*1\u548c1*M\u4e2a\u5b50\u56fe\u65f6\uff0c\u8fd4\u56de\u4e00\u4e2a\u4e00\u7ef4Axes\u5bf9\u8c61\u6570\u7ec4\u3002\u5f53\u6709N*M\u4e2a\u5b50\u56fe\uff08N>1\uff0cM>1\uff09\u65f6\uff0c\u8fd4\u56de\u4e8c\u7ef4\u6570\u7ec4\u3002\u5982\u679c\u4e3aFalse\uff0c\u5219\u603b\u662f\u8fd4\u56de\u4e8c\u7ef4\u6570\u7ec4\u3002 num\uff1a\u53ef\u9009\u7684\uff0c\u6574\u578b\u6216\u5b57\u7b26\u4e32\uff0c\u9ed8\u8ba4\u4e3aNone\u3002\u662fmatplotlib.pyplot.figure\u7684\u5173\u952e\u5b57\uff0c\u7528\u4e8e\u8bbe\u7f6e\u56fe\u50cf\u6570\u5b57\u6216\u6807\u7b7e\u3002\u5982\u679c\u672a\u8bbe\u7f6e\u6b64\u53c2\u6570\uff0c\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u56fe\u50cf\uff0c\u5e76\u9012\u589e\u56fe\u50cf\u7f16\u53f7\uff0cfigure\u5bf9\u8c61\u4f1a\u5c06\u7f16\u53f7\u4fdd\u5b58\u5728number\u5c5e\u6027\u4e2d\u3002\u5982\u679c\u8bbe\u7f6e\u4e86\u6b64\u53c2\u6570\uff0c\u5e76\u4e14\u5b58\u5728\u53c2\u6570\u6307\u5b9a\u7684\u56fe\u50cf\uff0c\u5219\u4f1a\u8fd4\u56de\u6b64\u56fe\u50cf\u7684\u5f15\u7528\uff0c\u5982\u679c\u4e0d\u5b58\u5728\u5219\u4f1a\u521b\u5efa\u65b0\u7684\u56fe\u50cf\u5e76\u8fd4\u56de\u5b83\u7684\u5f15\u7528\u3002\u5982\u679c\u662f\u5b57\u7b26\u4e32\uff0c\u5219\u7a97\u53e3\u6807\u9898\u4f1a\u88ab\u8bbe\u7f6e\u4e3a\u6b64\u5b57\u7b26\u4e32\u7684\u503c\u3002 subplot_kw\uff1a\u53ef\u9009\u7684\uff0c\u5b57\u5178\u7c7b\u578b\u3002\u5305\u542b\u4f20\u9012\u7ed9\u7528\u4e8e\u521b\u5efa\u5b50\u56fe\u7684\u8c03\u7528add_subplot\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 gridspec_kw\uff1a\u53ef\u9009\u7684\uff0c\u5b57\u5178\u7c7b\u578b\u3002\u5305\u542b\u4f20\u9012\u7ed9\u7528\u4e8e\u521b\u5efa\u5b50\u56fe\u7f51\u683c\u7684GridSpec\u6784\u9020\u51fd\u6570\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 fig, axes = plt.subplots(2, 3) print(axes) # \u5c06\u751f\u6210\u7684axes\u5bf9\u8c61\u653e\u5165NumPy\u6570\u7ec4\u3002 # [[ ] # [ ]] \u8c03\u6574\u5b50\u56fe\u5468\u56f4\u7684\u95f4\u8ddd\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c matplotlib \u4f1a\u5728\u5b50\u56fe\u7684\u5916\u90e8\u548c\u5b50\u56fe\u4e4b\u95f4\u7559\u51fa\u4e00\u5b9a\u7684\u95f4\u8ddd\u3002 \u8fd9\u4e2a\u95f4\u8ddd\u90fd\u662f\u76f8\u5bf9\u4e8e\u56fe\u7684\u9ad8\u5ea6\u548c\u5bbd\u5ea6\u6765\u6307\u5b9a\u7684\uff0c\u624b\u52a8\u8c03\u6574\u56fe\u7684\u5927\u5c0f\uff0c\u90a3\u4e48\u95f4\u8ddd\u4f1a\u81ea\u52a8\u8c03\u6574\u3002 \u4e5f\u53ef\u4ee5\u4f7f\u7528\u56fe\u5bf9\u8c61\u4e0a\u7684 subplots_adjust \u65b9\u6cd5\u66f4\u6539\u95f4\u8ddd\uff0c\u4e5f\u53ef\u4ee5\u7528\u4f5c\u9876\u5c42\u51fd\u6570\u3002 fig, axes = plt.subplots(2, 2, sharex=True, sharey=True) for i in range(2): for j in range(2): axes[i, j].hist(np.random.randn(500), bins=50, color='k', alpha=0.5) plt.subplots_adjust(wspace=0, hspace=0) plt.show() \u4e0a\u9762\u8f93\u51fa\u56fe\u50cf\u7684\u8f74\u6807\u7b7e\u662f\u5b58\u5728\u91cd\u53e0\u7684\u3002 matplotlib \u5e76\u4e0d\u68c0\u67e5\u6807\u7b7e\u662f\u5426\u91cd\u53e0\uff0c\u56e0\u6b64\u5728\u7c7b\u4f3c\u60c5\u51b5\u4e0b\u4f60\u9700\u8981\u901a\u8fc7\u663e\u5f0f\u6307\u5b9a\u523b\u5ea6\u4f4d\u7f6e\u548c\u523b\u5ea6\u6807\u7b7e\u7684\u65b9\u6cd5\u6765\u4fee\u590d\u8f74\u6807\u7b7e\u3002 \u989c\u8272\u3001\u6807\u8bb0\u548c\u7ebf\u7c7b\u578b \u00b6 matplotlib \u7684\u4e3b\u51fd\u6570 plot \u63a5\u6536\u5e26\u6709 x \u548c y \u8f74\u7684\u6570\u7ec4\u4ee5\u53ca\u4e00\u4e9b\u53ef\u9009\u7684\u5b57\u7b26\u4e32\u7f29\u5199\u53c2\u6570\u6765\u6307\u660e\u989c\u8272\u548c\u7ebf\u7c7b\u578b\u3002 \u4f8b\u5982\uff1a\u4e0b\u9762\u4e24\u79cd\u8868\u8fbe\u65b9\u5f0f\u6548\u679c\u4e00\u6837\u3002 ax.plot(x, y, 'g--') ax.plot(x, y, linestyle='--', color='g') data = np.random.randn(30).cumsum() plt.plot(data, 'ko--') plt.show() # \u4e0a\u9762\u7684\u4ee3\u7801\u53ef\u4ee5\u5199\u5f97\u66f4\u4e3a\u663e\u5f0f\uff1a plt.plot(data, color='k', linestyle='dashed', marker='o') plt.show() plt.plot(data, color='k', linestyle='dashed', marker='o', label='Default') plt.show() plt.plot(data, color='k', linestyle='dashed', marker='o', label='steps-post', drawstyle='steps-post') plt.show() \u523b\u5ea6\u3001\u6807\u7b7e\u548c\u56fe\u4f8b \u00b6 \u5bf9\u4e8e\u5927\u591a\u6570\u56fe\u8868\u4fee\u9970\u5de5\u4f5c\uff0c\u6709\u4e24\u79cd\u4e3b\u8981\u7684\u65b9\u5f0f\uff1a\u4f7f\u7528\u7a0b\u5e8f\u6027\u7684pyplot\u63a5\u53e3\uff08\u5373matplotlib.pyplot\uff09\u548c\u66f4\u591a\u9762\u5411\u5bf9\u8c61\u7684\u539f\u751fmatplotlib API\u3002 pyplot \u63a5\u53e3\u8bbe\u8ba1\u4e3a\u4ea4\u4e92\u5f0f\u4f7f\u7528\uff0c\u5305\u542b\u4e86\u50cf xlim \u3001 xticks \u548c xticklabels \u7b49\u65b9\u6cd5\u3002\u8fd9\u4e9b\u65b9\u6cd5\u5206\u522b\u63a7\u5236\u4e86\u7ed8\u56fe\u8303\u56f4\u3001\u523b\u5ea6\u4f4d\u7f6e\u4ee5\u53ca\u523b\u5ea6\u6807\u7b7e\u3002 \u5728\u6ca1\u6709\u51fd\u6570\u53c2\u6570\u7684\u60c5\u51b5\u4e0b\u8c03\u7528\uff0c\u8fd4\u56de\u5f53\u524d\u7684\u53c2\u6570\u503c\uff08\u4f8b\u5982 plt.xlim() \u8fd4\u56de\u5f53\u524d\u7684x\u8f74\u7ed8\u56fe\u8303\u56f4\uff09\u3002 \u4f20\u5165\u53c2\u6570\u7684\u60c5\u51b5\u4e0b\u8c03\u7528\uff0c\u5e76\u8bbe\u7f6e\u53c2\u6570\u503c\uff08\u4f8b\u5982 plt.xlim\uff08[0, 10]\uff09 \u4f1a\u5c06 x \u8f74\u7684\u8303\u56f4\u8bbe\u7f6e\u4e3a0\u523010\uff09\u3002 \u6240\u6709\u7684\u8fd9\u4e9b\u65b9\u6cd5\u90fd\u4f1a\u5728\u5f53\u524d\u6d3b\u52a8\u7684\u6216\u6700\u8fd1\u521b\u5efa\u7684 AxesSubplot \u4e0a\u751f\u6548\u3002 \u8fd9\u4e9b\u65b9\u6cd5\u4e2d\u7684\u6bcf\u4e00\u4e2a\u5bf9\u5e94\u4e8e\u5b50\u56fe\u81ea\u8eab\u7684\u4e24\u4e2a\u65b9\u6cd5\u3002\u6bd4\u5982 xlim \u5bf9\u5e94\u4e8e ax.get_lim \u548c ax.set_lim \u3002 \u63a8\u8350\u4f7f\u7528 subplot \u7684\u5b9e\u4f8b\u65b9\u6cd5\uff0c\u56e0\u4e3a\u8fd9\u6837\u66f4\u4e3a\u663e\u5f0f\uff08\u5c24\u5176\u662f\u5728\u5904\u7406\u591a\u4e2a\u5b50\u56fe\u65f6\uff09\u3002 data = np.random.randn(1000).cumsum() fig = plt.figure() # \u8bbe\u5b9a\u5b50\u56fe ax = fig.add_subplot(1, 1, 1) # \u8bbe\u5b9ax\u8f74\u5bf9\u5e94\u53c2\u6570\uff1a # \u8bbe\u5b9ax\u8f74\u523b\u5ea6 ax.set_xticks([0, 250, 500, 750, 1000]) # \u8bbe\u5b9ax\u8f74\u6807\u7b7e ax.set_xticklabels(['one(0)', 'two(250)', 'three(500)', 'four(750)', 'five(1000)'], rotation=30, fontsize='small') # \u7ed9x\u8f74\u4e00\u4e2a\u540d\u79f0 ax.set_xlabel('Stages') # \u8bbe\u5b9ay\u8f74\u5bf9\u5e94\u53c2\u6570\uff1a # \u672a\u6307\u5b9a\u7684\u53c2\u6570\u7531\u7cfb\u7edf\u9ed8\u8ba4\u4ea7\u751f\u3002 ax.set_ylabel('Steps') # \u7ed9\u5b50\u56fe\u6dfb\u52a0\u4e00\u4e2a\u6807\u9898 ax.set_title('My first matplotlib plot') # \u7ed9\u5b50\u56fe\u6dfb\u52a0\u4e00\u4e2a\u56fe\u4f8b\uff08\u5982\uff1a\u7ed9\u5b50\u56fe\u5185\u4e00\u4e2a\u56fe\u5f62\u66f2\u7ebf\u6dfb\u52a0\u4e00\u4e2alabel\uff09 ax.plot(data, 'k--', label='Label One') # loc\u53c2\u6570\u544a\u8bc9matplotlib\u5728\u54ea\u91cc\u653e\u7f6e\u56fe\u8868\u3002legend\u65b9\u6cd5\u6709\u591a\u4e2a\u5176\u4ed6\u7684\u4f4d\u7f6e\u53c2\u6570loc\u3002 ax.legend(loc='best') # \u6216\u8005plt.legend(loc='best') \u3002 # \u5728\u56fe\u5f62\u5750\u6807\u4e3a(0, 0)\u7684\u4f4d\u7f6e\u6dfb\u52a0\u4e00\u4e2alable ax.text(0, 0, 'Hello World1', family='monospace', fontsize=10) # \u7ed9\u5b50\u56fe\u6dfb\u52a0annotate\u3002\u7528\u4e00\u4e2a\u7bad\u5934\u6307\u5411\u8981\u6ce8\u91ca\u7684\u5730\u65b9\uff0c\u518d\u5199\u4e0a\u4e00\u6bb5\u8bdd\u7684\u884c\u4e3a\uff0c\u53eb\u505aannotate\u3002 # * s: \u6ce8\u91ca\u7684\u5185\u5bb9\uff0c\u4e00\u6bb5\u6587\u5b57\uff1b # * xytext: \u8fd9\u6bb5\u6587\u5b57\u6240\u5904\u7684\u4f4d\u7f6e; # * xy: \u7bad\u5934\u6307\u5411\u7684\u4f4d\u7f6e\uff1b # * arrowprops: \u901a\u8fc7arrowstyle\u8868\u660e\u7bad\u5934\u7684\u98ce\u683c\u6216\u79cd\u7c7b\u3002 ax.annotate('Zero is here!', xytext=(20, 20), xy=(1, 1), arrowprops=dict(arrowstyle='->')) # \u7ed9\u5b50\u56fe\u6dfb\u52a0\u4e00\u4e9b\u56fe\u5f62 # matplotlib\u542b\u6709\u8868\u793a\u591a\u79cd\u5e38\u89c1\u56fe\u5f62\u7684\u5bf9\u8c61\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u7684\u5f15\u7528\u662fpatches\u3002 # \u4e00\u4e9b\u56fe\u5f62\uff0c\u6bd4\u5982Rectangle\uff08\u77e9\u5f62\uff09\u548cCircle\uff08\u5706\u5f62\uff09\uff0c\u53ef\u4ee5\u5728matplotlib.pyplot\u4e2d\u627e\u5230\uff0c\u4f46\u56fe\u5f62\u7684\u5168\u96c6\u4f4d\u4e8ematplotlib.patches\u3002 rect = plt.Rectangle((10, 5), 100, 15, color='k', alpha=0.3) circ = plt.Circle((200, 9), 95, color='b', alpha=0.3) pgon = plt.Polygon([[500, 5], [600, -5], [700, 30]], color='g', alpha=0.5) ax.add_patch(rect) ax.add_patch(circ) ax.add_patch(pgon) # \u5c06\u56fe\u7247\u4fdd\u5b58\u5230\u6587\u4ef6 # \u6587\u4ef6\u7c7b\u578b\u662f\u4ece\u6587\u4ef6\u6269\u5c55\u540d\u4e2d\u63a8\u65ad\u51fa\u6765\u7684\u3002\u6240\u4ee5\u5982\u679c\u4f60\u4f7f\u7528\uff0epdf\uff0c\u5219\u4f1a\u5f97\u5230\u4e00\u4e2aPDF\u3002 # \u51e0\u4e2a\u91cd\u8981\u7684\u9009\u9879\uff1adpi\uff0c\u5b83\u63a7\u5236\u6bcf\u82f1\u5bf8\u70b9\u6570\u7684\u5206\u8fa8\u7387\uff1bbbox_inches\uff0c\u53ef\u4ee5\u4fee\u526a\u5b9e\u9645\u56fe\u5f62\u7684\u7a7a\u767d\u3002 plt.savefig('../examples/figpath.png', dpi=400, bbox_inches='tight') # saveifg\u5e76\u975e\u4e00\u5b9a\u662f\u5199\u5230\u786c\u76d8\u7684\uff0c\u5b83\u53ef\u4ee5\u5c06\u56fe\u7247\u5199\u5165\u5230\u6240\u6709\u7684\u6587\u4ef6\u578b\u5bf9\u8c61\u4e2d\uff0c\u4f8b\u5982BytesIO buffer = BytesIO() plt.savefig(buffer) plot_data = buffer.getvalue() plt.show() matplotlib\u8bbe\u7f6e \u00b6 matplotlib \u914d\u7f6e\u4e86\u914d\u8272\u65b9\u6848\u548c\u9ed8\u8ba4\u8bbe\u7f6e\uff0c\u901a\u8fc7\u5168\u5c40\u53c2\u6570\u6765\u5b9a\u5236\uff0c\u5305\u62ec\u56fe\u5f62\u5927\u5c0f\u3001\u5b50\u56fe\u95f4\u8ddd\u3001\u989c\u8272\u3001\u5b57\u4f53\u5927\u5c0f\u548c\u7f51\u683c\u6837\u5f0f\u7b49\u7b49\u3002 \u4f7f\u7528 rc \u65b9\u6cd5\u662f\u4f7f\u7528Python\u7f16\u7a0b\u4fee\u6539\u914d\u7f6e\u7684\u4e00\u79cd\u65b9\u5f0f\u3002 rc \u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u4f60\u60f3\u8981\u81ea\u5b9a\u4e49\u7684\u7ec4\u4ef6\uff0c\u6bd4\u5982 'figure'\u3001'axes'\u3001'xtick'\u3001'ytick'\u3001'grid'\u3001'legend' \u7b49\u7b49\u3002 \u4e4b\u540e\uff0c\u53ef\u4ee5\u6309\u7167\u5173\u952e\u5b57\u53c2\u6570\u7684\u5e8f\u5217\u6307\u5b9a\u65b0\u53c2\u6570\u3002 \u5b57\u5178\u662f\u4e00\u79cd\u5728\u7a0b\u5e8f\u4e2d\u8bbe\u7f6e\u9009\u9879\u7684\u7b80\u5355\u65b9\u5f0f\u3002\u6bd4\u5982\uff1a plt.rc('figure', figsize=(10, 10)) font_options = { 'family': 'monospace', 'weight': 'bold', 'size': 'small' } plt.rc('font', **font_options) \u4f7f\u7528pandas\u548cseaborn\u7ed8\u56fe \u00b6 pandas\u81ea\u8eab\u6709\u5f88\u591a\u5185\u5efa\u65b9\u6cd5\u53ef\u4ee5\u7b80\u5316\u4eceDataFrame\u548cSeries\u5bf9\u8c61\u751f\u6210\u53ef\u89c6\u5316\u7684\u8fc7\u7a0b\u3002 \u53e6\u4e00\u4e2a\u5e93\u662f seaborn \u3002 seaborn \u7b80\u5316\u4e86\u5f88\u591a\u5e38\u7528\u53ef\u89c6\u5316\u7c7b\u578b\u7684\u751f\u6210\u3002 \u5bfc\u5165 seaborn \u4f1a\u4fee\u6539\u9ed8\u8ba4\u7684matplotlib\u914d\u8272\u65b9\u6848\u548c\u7ed8\u56fe\u6837\u5f0f\uff0c\u8fd9\u4f1a\u63d0\u9ad8\u56fe\u8868\u7684\u53ef\u8bfb\u6027\u548c\u7f8e\u89c2\u6027\u3002 \u5373\u4f7f\u4e0d\u4f7f\u7528seaborn\u7684API\uff0c\u4e5f\u53ef\u4ee5\u5bfc\u5165seaborn\u6765\u4e3a\u901a\u7528matplotlib\u56fe\u8868\u63d0\u4f9b\u66f4\u597d\u7684\u89c6\u89c9\u7f8e\u89c2\u5ea6\u3002 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns \u6298\u7ebf\u56fe \u00b6 Series\u548cDataFrame\u90fd\u6709\u4e00\u4e2a plot \u5c5e\u6027\uff0c\u7528\u4e8e\u7ed8\u5236\u57fa\u672c\u7684\u56fe\u5f62\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c plot() \u7ed8\u5236\u7684\u662f\u6298\u7ebf\u56fe\u3002 Series\u7684 plot \u53c2\u6570\uff1a ax: matplotlib\u5b50\u56fe\u5bf9\u8c61axes\uff0c\u5982\u679c\u6ca1\u6709\u4f20\u503c\uff0c\u5219\u4f7f\u7528\u5f53\u524d\u6d3b\u52a8\u7684\u5b50\u56fe\u9ed8\u8ba4\u4f7f\u7528gca() alpha: \u56fe\u7247\u4e0d\u900f\u660e\u5ea6\uff080\u52301\uff09 data: \u6570\u636e\u5e8f\u5217Series figsize: \u56fe\u50cf\u5c3a\u5bf8\uff0ctuple(\u5bbd\u5ea6\uff0c\u9ad8\u5ea6)\uff0c\u6ce8\u610f\u8fd9\u91cc\u7684\u5355\u4f4d\u662f\u82f1\u5bf8 fontsize: \u8bbe\u7f6e\u523b\u5ea6\u6807\u7b7e\uff08xticks, yticks\uff09\u7684\u5927\u5c0f grid: \u7f51\u683c\u7ebf\uff08\u9ed8\u8ba4\u662f\u6253\u5f00\u7684\uff09 kind: \u56fe\u7c7b\u578b\uff1a\u6298\u7ebf\u56fe\uff0c\u67f1\u5f62\u56fe\uff0c\u6a2a\u5411\u67f1\u5f62\u56fe\uff0c\u76f4\u65b9\u56fe\uff0c\u7bb1\u7ebf\u56fe\uff0c\u5bc6\u5ea6\u56fe\uff0c\u9762\u79ef\u56fe\uff0c\u997c\u56fe label: \u5217\u7684\u522b\u540d\uff0c\u4f5c\u7528\u5728\u56fe\u4f8b\u4e0a legend: \u56fe\u4f8b loglog: x,y\u8f74\u90fd\u4f7f\u7528\u5bf9\u6570\u523b\u5ea6 logx: x\u8f74\u4f7f\u7528\u5bf9\u6570\u523b\u5ea6 logy: y\u8f74\u4f7f\u7528\u5bf9\u6570\u523b\u5ea6 mark_right: \u53cc y \u8f74\u65f6\uff0c\u5728\u56fe\u4f8b\u4e2d\u7684\u5217\u6807\u7b7e\u65c1\u589e\u52a0\u663e\u793a (right) \u6807\u8bc6 position: \u67f1\u5f62\u56fe\u7684\u67f1\u5b50\u7684\u4f4d\u7f6e\u8bbe\u7f6e rot: \u6539\u53d8\u523b\u5ea6\u6807\u7b7e\uff08xticks, yticks\uff09\u7684\u65cb\u8f6c\u5ea6\uff080\u5230360\uff09 secondary_y: \u53cc y \u8f74\uff0c\u5728\u53f3\u8fb9\u7684\u7b2c\u4e8c\u4e2a y \u8f74 style: \u7ebf\u7684\u6837\u5f0f\uff0c\u6bd4\u5982'ko--' table: \u5c06\u6570\u636e\u4ee5\u8868\u683c\u7684\u5f62\u5f0f\u5c55\u793a\u51fa\u6765 title: \u6807\u9898 use_index: \u662f\u5426\u4f7f\u7528\u7d22\u5f15\u4f5c\u4e3ax\u523b\u5ea6\u6807\u7b7e xerr: \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe xlim: \u6a2a\u8f74\u5750\u6807\u523b\u5ea6\u7684\u53d6\u503c\u8303\u56f4 xticks: x\u8f74\u523b\u5ea6\u6807\u7b7e yerr: \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe ylim: \u7eb5\u8f74\u5750\u6807\u523b\u5ea6\u7684\u53d6\u503c\u8303\u56f4 yticks: y\u8f74\u523b\u5ea6\u6807\u7b7e **kwds: matplotlib plot\u65b9\u6cd5\u7684\u5176\u4ed6\u53c2\u6570 DataFrame\u7684 plot \u53c2\u6570\uff1a x : \u6307\u6570\u636e\u6846\u5217\u7684\u6807\u7b7e\u6216\u4f4d\u7f6e\u53c2\u6570 y : \u6307\u6570\u636e\u6846\u5217\u7684\u6807\u7b7e\u6216\u4f4d\u7f6e\u53c2\u6570 kind : 'line' : \u6298\u7ebf\u56fe 'bar' : \u6761\u5f62\u56fe 'barh' : \u6a2a\u5411\u6761\u5f62\u56fe 'hist' : \u67f1\u72b6\u56fe 'box' : \u7bb1\u7ebf\u56fe 'kde' : Kernel\u7684\u5bc6\u5ea6\u4f30\u8ba1\u56fe\uff0c\u4e3b\u8981\u5bf9\u67f1\u72b6\u56fe\u6dfb\u52a0Kernel \u6982\u7387\u5bc6\u5ea6\u7ebf 'density' : 'kde' 'area' : area plot 'pie' : \u997c\u56fe 'scatter' : \u6563\u70b9\u56fe \u9700\u8981\u4f20\u5165columns\u65b9\u5411\u7684\u7d22\u5f15 'hexbin' : hexbin plot ax : \u5b50\u56fe(axes, \u4e5f\u53ef\u4ee5\u7406\u89e3\u6210\u5750\u6807\u8f74) \u8981\u5728\u5176\u4e0a\u8fdb\u884c\u7ed8\u5236\u7684matplotlib subplot\u5bf9\u8c61\u3002\u5982\u679c\u6ca1\u6709\u8bbe\u7f6e\uff0c\u5219\u4f7f\u7528\u5f53\u524dmatplotlib subplot\u3002\u5176\u4e2d\uff0c\u53d8\u91cf\u548c\u51fd\u6570\u901a\u8fc7\u6539\u53d8figure\u548caxes\u4e2d\u7684\u5143\u7d20\uff08\u4f8b\u5982\uff1atitle,label,\u70b9\u548c\u7ebf\u7b49\u7b49\uff09\u4e00\u8d77\u63cf\u8ff0figure\u548caxes\uff0c\u4e5f\u5c31\u662f\u5728\u753b\u5e03\u4e0a\u7ed8\u56fe\u3002 subplots : \u5224\u65ad\u56fe\u7247\u4e2d\u662f\u5426\u6709\u5b50\u56fe sharex : \u5982\u679c\u6709\u5b50\u56fe\uff0c\u5b50\u56fe\u5171x\u8f74\u523b\u5ea6\uff0c\u6807\u7b7e sharey : \u5982\u679c\u6709\u5b50\u56fe\uff0c\u5b50\u56fe\u5171y\u8f74\u523b\u5ea6\uff0c\u6807\u7b7e layout : \u5b50\u56fe\u7684\u884c\u5217\u5e03\u5c40 figsize : \u56fe\u7247\u5c3a\u5bf8\u5927\u5c0f use_index : \u9ed8\u8ba4\u7528\u7d22\u5f15\u505ax\u8f74 title : \u56fe\u7247\u7684\u6807\u9898\u7528\u5b57\u7b26\u4e32 grid : \u56fe\u7247\u662f\u5426\u6709\u7f51\u683c legend : \u5b50\u56fe\u7684\u56fe\u4f8b\uff0c\u6dfb\u52a0\u4e00\u4e2asubplot\u56fe\u4f8b(\u9ed8\u8ba4\u4e3aTrue) style : \u5bf9\u6bcf\u5217\u6298\u7ebf\u56fe\u8bbe\u7f6e\u7ebf\u7684\u7c7b\u578b logx : \u8bbe\u7f6ex\u8f74\u523b\u5ea6\u662f\u5426\u53d6\u5bf9\u6570 logy : \u8bbe\u7f6ey\u8f74\u523b\u5ea6\u662f\u5426\u53d6\u5bf9\u6570 loglog : \u540c\u65f6\u8bbe\u7f6ex\uff0cy\u8f74\u523b\u5ea6\u662f\u5426\u53d6\u5bf9\u6570 xticks : \u8bbe\u7f6ex\u8f74\u523b\u5ea6\u503c\uff0c\u5e8f\u5217\u5f62\u5f0f\uff08\u6bd4\u5982\u5217\u8868\uff09 yticks : \u8bbe\u7f6ey\u8f74\u523b\u5ea6\uff0c\u5e8f\u5217\u5f62\u5f0f\uff08\u6bd4\u5982\u5217\u8868\uff09 xlim : \u8bbe\u7f6e\u5750\u6807\u8f74x\u7684\u8303\u56f4\uff0c\u5217\u8868\u6216\u5143\u7ec4\u5f62\u5f0f ylim : \u8bbe\u7f6e\u5750\u6807\u8f74y\u7684\u8303\u56f4\uff0c\u5217\u8868\u6216\u5143\u7ec4\u5f62\u5f0f rot : \u8bbe\u7f6e\u8f74\u6807\u7b7e\uff08\u8f74\u523b\u5ea6\uff09\u7684\u663e\u793a\u65cb\u8f6c\u5ea6\u6570 fontsize : \u8bbe\u7f6e\u8f74\u523b\u5ea6\u7684\u5b57\u4f53\u5927\u5c0f colormap : \u8bbe\u7f6e\u56fe\u7684\u533a\u57df\u989c\u8272 colorbar : \u56fe\u7247\u67f1\u5b50 position : Specify relative alignments for bar plot layout. From 0 (left/bottom-end) to 1 (right/top-end). Default is 0.5 (center) layout : \u5e03\u5c40(rows, columns) for the layout of the plot table : \u5982\u679c\u4e3a\u6b63\uff0c\u5219\u9009\u62e9DataFrame\u7c7b\u578b\u7684\u6570\u636e\u5e76\u4e14\u8f6c\u6362\u5339\u914dmatplotlib\u7684\u5e03\u5c40 yerr : \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe xerr : \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe stacked : \u751f\u6210\u5806\u79ef\u67f1\u72b6\u56fe sort_columns : \u4ee5\u5b57\u6bcd\u8868\u987a\u5e8f\u7ed8\u5236\u5404\u5217\uff0c\u9ed8\u8ba4\u4f7f\u7528\u524d\u5217\u987a\u5e8f secondary_y : \u8bbe\u7f6e\u7b2c\u4e8c\u4e2ay\u8f74\uff08\u53f3y\u8f74\uff09 mark_right : When using a secondary_y axis, automatically mark the column labels with \u201c(right)\u201d in the legend kwds : Options to pass to matplotlib plotting method Series data1 = np.random.randn(10).cumsum(0) s1 = pd.Series( data1, index=np.arange(0, 100, 10), ) print(s1) fig, axes = plt.subplots(3, 1) # 3\u4e2a\u5b50\u56fe s1.plot.bar(ax=axes[0], color='k', alpha=0.7) # \u6761\u5f62\u56fe(\u5b50\u56fe0)\uff0ccolor='k\u2019(\u67f1\u5b50\u7684\u989c\u8272\u8bbe\u7f6e\u4e3a\u9ed1\u8272)\uff0calpha=0.7(\u56fe\u50cf\u7684\u586b\u5145\u8272\u8bbe\u7f6e\u4e3a\u90e8\u5206\u900f\u660e) s1.plot.barh(ax=axes[1], color='k', alpha=0.7) # \u6a2a\u5411\u6761\u5f62\u56fe(\u5b50\u56fe1) s1.value_counts().plot.pie(ax=axes[2]) # \u901a\u8fc7value_counts()\u5bf9Series\u503c\u9891\u7387\u8fdb\u884c\u53ef\u89c6\u5316 plt.show() DataFrame data2 = np.random.randn(10, 4).cumsum(0) df1 = pd.DataFrame( data2, columns=pd.Index(['A', 'B', 'C', 'D'], name='Genus'), index=np.arange(0, 100, 10) ) print(df1) fig, axes = plt.subplots(2, 1) # 2\u4e2a\u5b50\u56fe df1.plot.kde(ax=axes[0], alpha=0.7, grid='True', title='KDE Figure', sharex=True) df1.plot.bar(ax=axes[1], grid='True', title='Line Figure', sharex=True, use_index=False, stacked=True) # \u56e0\u4e3a\u5171\u4eabx\u8f74\uff0c\u6240\u4ee5\u5728KDE\u5b50\u56fe\u4e2d\u6307\u5b9ause_index=False\u770b\u4e0d\u51fa\u6548\u679c\u3002 # DataFrame\u7684\u5217\u540d\u79f0\"Genus\"\u88ab\u7528\u4f5c\u4e86\u56fe\u4f8b\u6807\u9898 # stacked=True\u6765\u751f\u6210\u5806\u79ef\u67f1\u72b6\u56fe plt.show() \u5b9e\u4f8b\uff1a\u7ed8\u5236\u4e00\u4e2a\u5806\u79ef\u67f1\u72b6\u56fe\uff0c\u7528\u4e8e\u5c55\u793a\u6bcf\u4e2a\u6d3e\u5bf9\u5728\u6bcf\u5929\u7684\u6570\u636e\u70b9\u5360\u6bd4\u3002 \u4ea4\u53c9\u8868 \u662f\u4e00\u79cd\u5e38\u7528\u7684\u5206\u7c7b\u6c47\u603b\u8868\u683c\uff0c\u7528\u4e8e\u9891\u6570\u5206\u5e03\u7edf\u8ba1\uff0c\u4e3b\u8981\u4ef7\u503c\u5728\u4e8e\u63cf\u8ff0\u4e86\u53d8\u91cf\u95f4\u5173\u7cfb\u7684\u6df1\u523b\u542b\u4e49\u3002 \u867d\u7136\u4e24\u4e2a\uff08\u6216\u4ee5\u4e0a\uff09\u53d8\u91cf\u53ef\u4ee5\u662f\u5206\u7c7b\u7684\u6216\u6570\u91cf\u7684\uff0c\u4f46\u662f\u4ee5\u90fd\u662f\u5206\u7c7b\u7684\u60c5\u5f62\u6700\u4e3a\u5e38\u89c1\u3002 Pandas\u7684 crosstab() \u65b9\u6cd5\u80fd\u591f\u5feb\u901f\u6784\u5efa\u4ea4\u53c9\u8868\uff0c\u5e76\u53ef\u4ee5\u901a\u8fc7\u53c2\u6570\u52a0\u4ee5\u4e2a\u6027\u5316\u7684\u8bbe\u7f6e\u3002\u5176\u4e2d\uff0c\u7b2c\u4e00\u4e2a\u53c2\u6570\u5c06\u6784\u6210\u4ea4\u53c9\u8868\u7684\u884c\uff0c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u5c06\u6784\u6210\u4ea4\u53c9\u8868\u7684\u5217\u3002 tips = pd.read_csv('../examples/tips.csv') print(tips) # total_bill tip smoker day time size # 0 16.99 1.01 No Sun Dinner 2 # 1 10.34 1.66 No Sun Dinner 3 # 2 21.01 3.50 No Sun Dinner 3 # 3 23.68 3.31 No Sun Dinner 2 # 4 24.59 3.61 No Sun Dinner 4 # .. ... ... ... ... ... ... # 239 29.03 5.92 No Sat Dinner 3 # 240 27.18 2.00 Yes Sat Dinner 2 # 241 22.67 2.00 Yes Sat Dinner 2 # 242 17.82 1.75 No Sat Dinner 2 # 243 18.78 3.00 No Thur Dinner 2 # [244 rows x 6 columns] party_counts = pd.crosstab(tips['day'], tips['size']) # \u5bf9\u539f\u59cb\u6570\u636e\u7684day\u548csize\u8fdb\u884c\u805a\u5408\uff0c\u5e76\u6784\u5efa\u4ea4\u53c9\u8868\uff0cday\u4f5c\u4e3a\u884c\uff0csize\u4f5c\u4e3a\u5217\u3002 print(party_counts) # size 1 2 3 4 5 6 # day # Fri 1 16 1 1 0 0 # Sat 2 53 18 13 1 0 # Sun 0 39 15 18 3 1 # Thur 1 48 4 5 1 3 # \u6ca1\u6709\u592a\u591a\u76841\u4eba\u548c6\u4eba\u6d3e\u5bf9\uff0c\u820d\u5f03\u8fd9\u4e9b\u6570\u636e party_counts = party_counts.loc[:, 2:5] print(party_counts) # size 2 3 4 5 # day # Fri 16 1 1 0 # Sat 53 18 13 1 # Sun 39 15 18 3 # Thur 48 4 5 1 # \u6807\u51c6\u5316\u81f3\u548c\u4e3a1\uff1a\u6cbf0\u8f74\uff08\u884c\uff09\u5bf9\u6bcf\u5217\u6c42\u548c\uff0c\u6bcf\u884c\u5404\u503c\u9664\u4ee5\u548c\uff0c\u4ee5\u786e\u4fdd\u6bcf\u4e00\u884c\u7684\u503c\u548c\u4e3a1\uff0c\u7136\u540e\u8fdb\u884c\u7ed8\u56fe party_pcts = party_counts.div(party_counts.sum(1), axis=0) print(party_pcts) # size 2 3 4 5 # day # Fri 0.888889 0.055556 0.055556 0.000000 # Sat 0.623529 0.211765 0.152941 0.011765 # Sun 0.520000 0.200000 0.240000 0.040000 # Thur 0.827586 0.068966 0.086207 0.017241 party_counts.plot.bar() plt.show() \u53ef\u4ee5\u770b\u5230\u672c\u6570\u636e\u96c6\u4e2d\u7684\u6d3e\u5bf9\u6570\u91cf\u5728\u5468\u672b\u4f1a\u589e\u52a0\u3002 \u5b9e\u4f8b\uff1a\u4f7f\u7528seaborn\u8fdb\u884c\u6309\u661f\u671f\u65e5\u671f\u8ba1\u7b97\u5c0f\u8d39\u767e\u5206\u6bd4\u3002 Seaborn\u8981\u6c42\u6570\u636e\u7684\u8f93\u5165\u7c7b\u578b\u4e3apandas\u7684Dataframe\u6216Numpy\u6570\u7ec4\u3002 tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) print(tips) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 # .. ... ... ... ... ... ... ... # 239 29.03 5.92 No Sat Dinner 3 0.256166 # 240 27.18 2.00 Yes Sat Dinner 2 0.079428 # 241 22.67 2.00 Yes Sat Dinner 2 0.096759 # 242 17.82 1.75 No Sat Dinner 2 0.108899 # 243 18.78 3.00 No Thur Dinner 2 0.190114 # [244 rows x 7 columns] # barplot: \u5c06\u70b9\u4f30\u8ba1\u548c\u7f6e\u4fe1\u533a\u95f4\u663e\u793a\u4e3a\u77e9\u5f62\u6761\u3002\u6761\u5f62\u56fe\u8868\u793a\u5177\u6709\u6bcf\u4e2a\u77e9\u5f62\u7684\u9ad8\u5ea6\u7684\u6570\u503c\u53d8\u91cf\u7684\u96c6\u4e2d\u8d8b\u52bf\u7684\u4f30\u8ba1\uff0c\u5e76\u4e14\u4f7f\u7528\u8bef\u5dee\u6761\u63d0\u4f9b\u56f4\u7ed5\u8be5\u4f30\u8ba1\u7684\u4e0d\u786e\u5b9a\u6027\u7684\u4e00\u4e9b\u6307\u793a # \u67f1\u5b50\u7684\u503c\u662ftip_pct\u7684\u5e73\u5747\u503c # \u67f1\u5b50\u4e0a\u753b\u51fa\u7684\u9ed1\u7ebf\u4ee3\u8868\u7684\u662f95%\u7684\u7f6e\u4fe1\u533a\u95f4\uff08\u7f6e\u4fe1\u533a\u95f4\u53ef\u4ee5\u901a\u8fc7\u53ef\u9009\u53c2\u6570\u8fdb\u884c\u8bbe\u7f6e\uff09 # hue\u9009\u9879\uff0c\u5141\u8bb8\u6211\u4eec\u901a\u8fc7\u4e00\u4e2a\u989d\u5916\u7684\u5206\u7c7b\u503c\u5c06\u6570\u636e\u5206\u79bb # \u5e26\u53c2\u6570hue='time'\u65f6\uff0c\u56db\u4e2a\u4e0d\u540c\u989c\u8272\u7684\u67f1\u5b50\uff0c\u6bcf\u4e2a\u67f1\u5b50\u4e0a\u6709\u7f6e\u4fe1\u533a\u95f4\u7684\u9ed1\u7ebf\uff0c\u523b\u5ea60.00~0.30\uff0c\u6b65\u957f0.05 # \u4e0d\u5e26\u53c2\u6570hue='time'\u65f6\uff0c\u4e24\u4e2a\u4e0d\u540c\u989c\u8272\u7684\u67f1\u5b50\uff0c\u5206\u522b\u4ee3\u8868Dinner\u548cLunch\uff0c\u4e0d\u662f\u6bcf\u4e2a\u67f1\u5b50\u4e0a\u90fd\u6709\u7f6e\u4fe1\u533a\u95f4\u7684\u9ed1\u7ebf\uff0c\u523b\u5ea60.00~0.30\uff0c\u6b65\u957f0.05 sns.barplot(x='tip_pct', y='day', data=tips, hue='time', orient='h') # \u6839\u636e\u661f\u671f\u65e5\u671f\u548c\u65f6\u95f4\u8ba1\u7b97\u7684\u5c0f\u8d39\u767e\u5206\u6bd4 # sns.barplot(x='tip_pct', y='day', data=tips, orient='h') sns.set(style=\"darkgrid\", palette=\"deep\") # style=\"whitegrid\" plt.show() \u76f4\u65b9\u56fe\u548c\u5bc6\u5ea6\u56fe \u00b6 \u76f4\u65b9\u56fe\u662f\u4e00\u79cd\u6761\u5f62\u56fe\uff0c\u7528\u4e8e\u7ed9\u51fa\u503c\u9891\u7387\u7684\u79bb\u6563\u663e\u793a\u3002\u6570\u636e\u70b9\u88ab\u5206\u6210\u79bb\u6563\u7684\uff0c\u5747\u5300\u95f4\u9694\u7684\u7bb1\uff0c\u5e76\u4e14\u7ed8\u5236\u6bcf\u4e2a\u7bb1\u4e2d\u6570\u636e\u70b9\u7684\u6570\u91cf\u3002 tips['tip_pct'].plot.hist(bins=50) # \u5c0f\u8d39\u767e\u5206\u6bd4\u7684\u76f4\u65b9\u56fe plt.show() \u5bc6\u5ea6\u56fe\u662f\u4e00\u79cd\u4e0e\u76f4\u65b9\u56fe\u76f8\u5173\u7684\u56fe\u8868\u7c7b\u578b\uff0c\u5b83\u901a\u8fc7\u8ba1\u7b97\u53ef\u80fd\u4ea7\u751f\u89c2\u6d4b\u6570\u636e\u7684\u8fde\u7eed\u6982\u7387\u5206\u5e03\u4f30\u8ba1\u800c\u4ea7\u751f\u3002 \u901a\u5e38\u7684\u505a\u6cd5\u662f\u5c06\u8fd9\u79cd\u5206\u5e03\u8fd1\u4f3c\u4e3a\u201c\u5185\u6838\u201d\u7684\u6df7\u5408\uff0c\u4e5f\u5c31\u662f\u50cf\u6b63\u6001\u5206\u5e03\u90a3\u6837\u7b80\u5355\u7684\u5206\u5e03\u3002 \u56e0\u6b64\uff0c\u5bc6\u5ea6\u56fe\u4e5f\u88ab\u79f0\u4e3a\u5185\u6838\u5bc6\u5ea6\u4f30\u8ba1\u56fe\uff08KDE\uff09\u3002 tips['tip_pct'].plot.density() # \u5c0f\u8d39\u767e\u5206\u6bd4\u5bc6\u5ea6\u56fe plt.show() \u7ed8\u5236\u76f4\u65b9\u56fe\u548c\u8fde\u7eed\u5bc6\u5ea6\u4f30\u8ba1 sns.displot() \u3002 sns.distplot(tips['tip_pct'], bins=100, color='k') plt.show() # FutureWarning: `distplot` is a deprecated function and will be removed in a future version. # Please adapt your code to use either `displot` (a figure-level function with similar flexibility) # or `histplot` (an axes-level function for histograms). \u6563\u70b9\u56fe\u6216\u70b9\u56fe \u00b6 \u70b9\u56fe\u6216\u6563\u70b9\u56fe\u53ef\u4ee5\u7528\u4e8e\u68c0\u9a8c\u4e24\u4e2a\u4e00\u7ef4\u6570\u636e\u5e8f\u5217\u4e4b\u95f4\u7684\u5173\u7cfb\u3002 \u5b9e\u4f8b\uff1a\u4ece statsmodels \u9879\u76ee\u4e2d\u8f7d\u5165\u4e86macrodata\u6570\u636e\u96c6\uff0c\u5e76\u9009\u62e9\u4e86\u4e00\u4e9b\u53d8\u91cf\uff0c\u4e4b\u540e\u8ba1\u7b97\u5bf9\u6570\u5dee\u3002 macro = pd.read_csv('../examples/macrodata.csv') print(macro.head(5)) # year quarter realgdp realcons ... unemp pop infl realint # 0 1959.0 1.0 2710.349 1707.4 ... 5.8 177.146 0.00 0.00 # 1 1959.0 2.0 2778.801 1733.7 ... 5.1 177.830 2.34 0.74 # 2 1959.0 3.0 2775.488 1751.8 ... 5.3 178.657 2.74 1.09 # 3 1959.0 4.0 2785.204 1753.7 ... 5.6 179.386 0.27 4.06 # 4 1960.0 1.0 2847.699 1770.5 ... 5.2 180.007 2.31 1.19 # [5 rows x 14 columns] data = macro[['cpi', 'm1', 'tbilrate', 'unemp']] print(data.head(5)) # cpi m1 tbilrate unemp # 0 28.98 139.7 2.82 5.8 # 1 29.15 141.7 3.08 5.1 # 2 29.35 140.5 3.82 5.3 # 3 29.37 140.0 4.33 5.6 # 4 29.54 139.6 3.50 5.2 trans_data = np.log(data).diff().dropna() print(trans_data[-5:]) # cpi m1 tbilrate unemp # 198 -0.007904 0.045361 -0.396881 0.105361 # 199 -0.021979 0.066753 -2.277267 0.139762 # 200 0.002340 0.010286 0.606136 0.160343 # 201 0.008419 0.037461 -0.200671 0.127339 # 202 0.008894 0.012202 -0.405465 0.042560 \u7528 seaborn \u7684 regplot \u65b9\u6cd5\u7ed8\u5236\u6563\u70b9\u56fe\uff0c\u5e76\u62df\u5408\u51fa\u4e00\u4e2a\u6761\u7ebf\u6027\u56de\u5f52\u7ebf\u3002( seaborn\u6587\u6863 ) sns.regplot('m1', 'unemp', data=trans_data) plt.title('Changes in log %s versus log %s ' % ('m1', 'unemp')) plt.show() \u5728\u63a2\u7d22\u6027\u6570\u636e\u5206\u6790\u4e2d\uff0c\u80fd\u591f\u67e5\u770b\u4e00\u7ec4\u53d8\u91cf\u4e2d\u7684\u6240\u6709\u6563\u70b9\u56fe\u662f\u6709\u5e2e\u52a9\u7684\uff0c\u8fd9\u88ab\u79f0\u4e3a\u6210\u5bf9\u56fe\u6216\u6563\u70b9\u56fe\u77e9\u9635\u3002 Seaborn\u6709\u4e00\u4e2a\u65b9\u4fbf\u7684 pairplot \u51fd\u6570\uff0c\u5b83\u652f\u6301\u5728\u5bf9\u89d2\u7ebf\u4e0a\u653e\u7f6e\u6bcf\u4e2a\u53d8\u91cf\u7684\u76f4\u65b9\u56fe\u6216\u5bc6\u5ea6\u4f30\u8ba1\u503c\u3002 plot_ksw \u53c2\u6570\u80fd\u591f\u5c06\u914d\u7f6e\u9009\u9879\u4f20\u9012\u7ed9\u975e\u5bf9\u89d2\u5143\u7d20\u4e0a\u7684\u5404\u4e2a\u7ed8\u56fe\u8c03\u7528\u3002 sns.pairplot(trans_data, diag_kind='kde', plot_kws={'alpha': 0.2}) plt.show() \u5206\u9762\u7f51\u683c\u548c\u5206\u7c7b\u6570\u636e \u00b6 \u5982\u679c\u6570\u636e\u96c6\u6709\u989d\u5916\u7684\u5206\u7ec4\u7ef4\u5ea6\u600e\u4e48\u529e\uff1f\u4f7f\u7528\u5206\u9762\u7f51\u683c\u662f\u5229\u7528\u591a\u79cd\u5206\u7ec4\u53d8\u91cf\u5bf9\u6570\u636e\u8fdb\u884c\u53ef\u89c6\u5316\u7684\u65b9\u5f0f\u3002 seaborn\u62e5\u6709\u4e00\u4e2a\u6709\u6548\u7684\u5185\u5efa\u51fd\u6570 factorplot \uff0c\u5b83\u53ef\u4ee5\u7b80\u5316\u591a\u79cd\u5206\u9762\u7ed8\u56fe\u3002 sns.factorplot(x='day', y='tip_pct', hue='time', col='smoker', kind='bar', data=tips[tips.tip_pct < 1]) plt.show() # UserWarning: The `factorplot` function has been renamed to `catplot`. # The original name will be removed in a future release. Please update your code. # Note that the default `kind` in `factorplot` (`'point'`) has changed `'strip'` in `catplot`. sns.catplot(x='day', y='tip_pct', hue='time', col='smoker', kind='box', data=tips[tips.tip_pct < 0.5]) plt.show() \u5176\u4ed6Python\u53ef\u89c6\u5316\u5de5\u5177 \u00b6 \u81ea2010\u5e74\u4ee5\u6765\uff0c\u5f88\u591a\u5f00\u53d1\u5de5\u4f5c\u90fd\u96c6\u4e2d\u5728\u521b\u5efaweb\u4ea4\u4e92\u5f0f\u56fe\u5f62\u4e0a\u3002 \u501f\u52a9\u50cf Bokeh \u548c Plotly \u8fd9\u6837\u7684\u5de5\u5177\uff0c\u5728web\u6d4f\u89c8\u5668\u4e2d\u521b\u5efa\u52a8\u6001\u7684\u3001\u4ea4\u4e92\u5f0f\u56fe\u50cf\u7684\u5de5\u4f5c\u73b0\u5728\u5df2\u7ecf\u53ef\u4ee5\u5b9e\u73b0\u3002 \u53ef\u89c6\u5316\u662f\u4e00\u4e2a\u6d3b\u8dc3\u7684\u7814\u7a76\u9886\u57df\u3002","title":"\u7ed8\u56fe\u4e0e\u53ef\u89c6\u5316"},{"location":"python/DataAnalysis/ch06/#_1","text":"","title":"\u7ed8\u56fe\u4e0e\u53ef\u89c6\u5316"},{"location":"python/DataAnalysis/ch06/#matplotlib-api","text":"import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np import pandas as pd from io import BytesIO \u6267\u884c plt.show() \u65f6\u62a5\u9519\uff1a UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure. \u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u5f97\u5230 plt \u7684 backend \u662f\u7528 agg \u3002 plt.get_backend() \u4f8b\u5982\uff1a\u4e0b\u9762\u4e24\u79cd\u8868\u8fbe\u65b9\u5f0f\u6548\u679c\u4e00\u6837\u3002 ax.plot(x, y, 'g--') ax.plot(x, y, linestyle='--', color='g') Out[6]: 'agg' \u5b89\u88c5\u4e0b\u9762\u51e0\u4e2a\u5305\uff1a sudo zypper in python-tk python3-tk sudo zypper in plplot-tcltk-devel plplot-tcltk-libs pip install tk \u6dfb\u52a0\u4e0b\u9762\u5230python\u4ee3\u7801\u4e2d\u3002 import matplotlib.pyplot as plt mpl.use('TkAgg') \u6267\u884c\u540e\u62a5\u4e0b\u9762\u9519\u8bef\uff1a your Python may not be configured for Tk \u8fdb\u5165python\u6e90\u7801\u76ee\u5f55\uff0c\u91cd\u65b0\u7f16\u8bd1\u4f8b\u5982\uff1a\u4e0b\u9762\u4e24\u79cd\u8868\u8fbe\u65b9\u5f0f\u6548\u679c\u4e00\u6837\u3002 ax.plot(x, y, 'g--') ax.plot(x, y, linestyle='--', color='g') james@lizard:/opt/Python-3.9.6> sudo make james@lizard:/opt/Python-3.9.6> sudo make install \u95ee\u9898\u89e3\u51b3\uff0c\u5373\u4f7f\u4e0d\u52a0\u5165 mpl.use('TkAgg') \uff0c\u6267\u884c plt.show() \u4e5f\u662f\u53ef\u4ee5\u8f93\u51fa\u56fe\u50cf\u3002","title":"\u7b80\u660ematplotlib API\u5165\u95e8"},{"location":"python/DataAnalysis/ch06/#_2","text":"matplotlib \u6240\u7ed8\u5236\u7684\u56fe\u4f4d\u4e8e\u56fe\u7247\uff08Figure\uff09\u5bf9\u8c61\u4e2d\u3002\u53ef\u4ee5\u4f7f\u7528 plt.figure \u751f\u6210\u4e00\u4e2a\u65b0\u7684\u56fe\u7247\u3002 \u4f7f\u7528 add_subplot \u521b\u5efa\u4e00\u4e2a\u6216\u591a\u4e2a\u5b50\u56fe\uff08subplot\uff09\u3002 plt \u4e0e ax \u7ed8\u56fe\u3002 fig = plt.figure() # plt: \u5148\u751f\u6210\u4e86\u4e00\u4e2a\u753b\u5e03\uff0c\u7136\u540e\u5728\u8fd9\u4e2a\u753b\u5e03\u4e0a\u9690\u5f0f\u7684\u751f\u6210\u4e00\u4e2a\u753b\u56fe\u533a\u57df\u6765\u8fdb\u884c\u753b\u56fe # plt.plot([1, 2, 3, 4]) # plt.show() # ax: \u5148\u751f\u6210\u4e00\u4e2a\u753b\u5e03\uff082\u00d72\u7684\u533a\u57df\uff0c\u6700\u591a\u653e\u56db\u4e2a\u56fe\u5f62\uff09\uff0c\u7136\u540e\u5728\u6b64\u753b\u5e03\u4e0a\uff0c\u9009\u5b9a\u4e00\u4e2a\u5b50\u533a\u57df\u753b\u4e86\u4e00\u4e2a\u5b50\u56fe\uff08\u5e8f\u53f71\u4ee3\u8868\u7b2c\u4e00\u4e2a\u533a\u57df\uff09 ax1 = fig.add_subplot(2, 2, 1) # \u4e5f\u53ef\u4ee5\u5199\u6210fig.add_subplot(221) ax1.plot([1, 2, 3, 4], [1, 4, 3, 2]) # \u8f93\u51fa\u56fe\u7247\u5230\u7b2c\u4e00\u4e2a\u533a\u57df\u3002 # \u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u6570\u636e\u96c6\u91cc\u5404\u4e2a\u6570\u636e\u70b9\u7684X\u503c\u7684\u96c6\u5408 # \u7b2c\u4e8c\u4e2a\u53c2\u6570\u6570\u636e\u96c6\u91cc\u5404\u4e2a\u6570\u636e\u70b9\u7684Y\u503c\u7684\u96c6\u5408\u3002 # \u4e0d\u662f\u6570\u5b66\u4e0a\u5e38\u89c1\u7684\u6210\u5bf9\u5750\u6807\u70b9\u5982(x1,y1)\u3001(x2,y2)\u3001...\u3001(xn,yn)\u7684\u683c\u5f0f\uff0c\u800c\u662f (x1,x2,...,xn)\u548c(y1,y2,...,yn) \u3002 plt.show() \u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u589e\u52a0\u5b50\u56fe\u540e\u7684\u6570\u636e\u53ef\u89c6\u5316\u6548\u679c\u3002 fig = plt.figure() ax1 = fig.add_subplot(2, 2, 1) ax2 = fig.add_subplot(2, 2, 2) ax3 = fig.add_subplot(2, 2, 3) ax1.plot(np.random.randn(50).cumsum(), 'k--') # \u5728\u7b2c\u4e09\u4e2a\u533a\u57df\u8f93\u51fa\u56fe\u50cf\u3002'k--\u2019\u662f\u7528\u4e8e\u7ed8\u5236\u9ed1\u8272\u5206\u6bb5\u7ebf\u7684style\u9009\u9879\u3002 ax2.hist(np.random.randn(100), bins=20, color='k', alpha=0.3) ax3.scatter(np.arange(30), np.arange(30) + 3 * np.random.randn(30)) plt.show() plt.subplots \u901a\u8fc7 matplotlib \u7684 subplots \u65b9\u6cd5\uff0c\u4f7f\u7528\u5b50\u56fe\u7f51\u683c\u521b\u5efa\u56fe\u7247\uff0c\u7136\u540e\u8fd4\u56de\u5305\u542b\u4e86\u5df2\u751f\u6210\u5b50\u56fe\u5bf9\u8c61\u7684NumPy\u6570\u7ec4\u3002 \u6570\u7ec4 axes \u53ef\u4ee5\u50cf\u4e8c\u7ef4\u6570\u7ec4\u90a3\u6837\u65b9\u4fbf\u5730\u8fdb\u884c\u7d22\u5f15\uff0c\u4f8b\u5982\uff0c axes[0, 1] \u3002 plt.subplots \u53c2\u6570\u9009\u9879\uff1a nrows\uff1a\u53ef\u9009\u7684\uff0c\u6574\u578b\uff0c\u9ed8\u8ba4\u4e3a1\u3002\u5b50\u56fe\u7f51\u683c\u7684\u884c\u6570\u3002 ncols\uff1a\u53ef\u9009\u7684\uff0c\u6574\u578b\uff0c\u9ed8\u8ba4\u4e3a1\u3002\u5b50\u56fe\u7f51\u683c\u7684\u5217\u6570\u3002 sharex\uff1a\u53ef\u9009\u7684\uff0c\u9ed8\u8ba4\u4e3aFalse\u3002\u53ef\u9009\u503c\u5982\u4e0b\uff1a True\u6216all\uff0c\u6240\u6709\u5b50\u56fe\u5171\u4eabx\u8f74 False\u6216none\uff0c\u6bcf\u4e2a\u5b50\u56fe\u7684x\u8f74\u90fd\u662f\u72ec\u7acb\u7684 row\uff0c\u6bcf\u884c\u5b50\u56fe\u5171\u4eab\u4e00\u4e2ax\u8f74 col\uff0c\u6bcf\u5217\u5b50\u56fe\u5171\u4eab\u4e00\u4e2ax\u8f74 sharey\uff1a\u7c7b\u4f3c\u4e8esharex\uff0c\u8bbe\u7f6ey\u8f74\u7684\u5171\u4eab\u65b9\u5f0f\u3002\u5f53\u67d0\u5217\u5171\u4eab\u4e00\u4e2ax\u8f74\u65f6\uff0c\u53ea\u6709\u5e95\u90e8\u7684\u5b50\u56fe\u4f1a\u521b\u5efax\u8f74\u6807\u8bb0\u3002\u540c\u6837\u7684\uff0c\u5982\u679c\u67d0\u884c\u5171\u4eab\u4e00\u4e2ay\u8f74\u65f6\uff0c\u53ea\u6709\u884c\u7684\u7b2c\u4e00\u5217\u5b50\u56fe\u4f1a\u521b\u5efay\u8f74\u6807\u8bb0\u3002 squeeze \uff1a\u53ef\u9009\u7684\uff0c\u5e03\u5c14\u578b\uff0c\u9ed8\u8ba4\u4e3aTrue\u3002\u662f\u5426\u538b\u7f29\u8fd4\u56de\u7684Axes\u6570\u7ec4\u3002\u5982\u679c\u4e3aTrue\uff0c\u5f53\u53ea\u6709\u4e00\u4e2a\u5b50\u56fe\uff0c\u5373nrows\u548cncols\u5747\u4e3a1\u65f6\uff0c\u8fd4\u56de\u4e00\u4e2a\u5355\u72ec\u7684Axes\u5bf9\u8c61\uff0c\u5f53\u6709N*1\u548c1*M\u4e2a\u5b50\u56fe\u65f6\uff0c\u8fd4\u56de\u4e00\u4e2a\u4e00\u7ef4Axes\u5bf9\u8c61\u6570\u7ec4\u3002\u5f53\u6709N*M\u4e2a\u5b50\u56fe\uff08N>1\uff0cM>1\uff09\u65f6\uff0c\u8fd4\u56de\u4e8c\u7ef4\u6570\u7ec4\u3002\u5982\u679c\u4e3aFalse\uff0c\u5219\u603b\u662f\u8fd4\u56de\u4e8c\u7ef4\u6570\u7ec4\u3002 num\uff1a\u53ef\u9009\u7684\uff0c\u6574\u578b\u6216\u5b57\u7b26\u4e32\uff0c\u9ed8\u8ba4\u4e3aNone\u3002\u662fmatplotlib.pyplot.figure\u7684\u5173\u952e\u5b57\uff0c\u7528\u4e8e\u8bbe\u7f6e\u56fe\u50cf\u6570\u5b57\u6216\u6807\u7b7e\u3002\u5982\u679c\u672a\u8bbe\u7f6e\u6b64\u53c2\u6570\uff0c\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u56fe\u50cf\uff0c\u5e76\u9012\u589e\u56fe\u50cf\u7f16\u53f7\uff0cfigure\u5bf9\u8c61\u4f1a\u5c06\u7f16\u53f7\u4fdd\u5b58\u5728number\u5c5e\u6027\u4e2d\u3002\u5982\u679c\u8bbe\u7f6e\u4e86\u6b64\u53c2\u6570\uff0c\u5e76\u4e14\u5b58\u5728\u53c2\u6570\u6307\u5b9a\u7684\u56fe\u50cf\uff0c\u5219\u4f1a\u8fd4\u56de\u6b64\u56fe\u50cf\u7684\u5f15\u7528\uff0c\u5982\u679c\u4e0d\u5b58\u5728\u5219\u4f1a\u521b\u5efa\u65b0\u7684\u56fe\u50cf\u5e76\u8fd4\u56de\u5b83\u7684\u5f15\u7528\u3002\u5982\u679c\u662f\u5b57\u7b26\u4e32\uff0c\u5219\u7a97\u53e3\u6807\u9898\u4f1a\u88ab\u8bbe\u7f6e\u4e3a\u6b64\u5b57\u7b26\u4e32\u7684\u503c\u3002 subplot_kw\uff1a\u53ef\u9009\u7684\uff0c\u5b57\u5178\u7c7b\u578b\u3002\u5305\u542b\u4f20\u9012\u7ed9\u7528\u4e8e\u521b\u5efa\u5b50\u56fe\u7684\u8c03\u7528add_subplot\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 gridspec_kw\uff1a\u53ef\u9009\u7684\uff0c\u5b57\u5178\u7c7b\u578b\u3002\u5305\u542b\u4f20\u9012\u7ed9\u7528\u4e8e\u521b\u5efa\u5b50\u56fe\u7f51\u683c\u7684GridSpec\u6784\u9020\u51fd\u6570\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 fig, axes = plt.subplots(2, 3) print(axes) # \u5c06\u751f\u6210\u7684axes\u5bf9\u8c61\u653e\u5165NumPy\u6570\u7ec4\u3002 # [[ ] # [ ]] \u8c03\u6574\u5b50\u56fe\u5468\u56f4\u7684\u95f4\u8ddd\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c matplotlib \u4f1a\u5728\u5b50\u56fe\u7684\u5916\u90e8\u548c\u5b50\u56fe\u4e4b\u95f4\u7559\u51fa\u4e00\u5b9a\u7684\u95f4\u8ddd\u3002 \u8fd9\u4e2a\u95f4\u8ddd\u90fd\u662f\u76f8\u5bf9\u4e8e\u56fe\u7684\u9ad8\u5ea6\u548c\u5bbd\u5ea6\u6765\u6307\u5b9a\u7684\uff0c\u624b\u52a8\u8c03\u6574\u56fe\u7684\u5927\u5c0f\uff0c\u90a3\u4e48\u95f4\u8ddd\u4f1a\u81ea\u52a8\u8c03\u6574\u3002 \u4e5f\u53ef\u4ee5\u4f7f\u7528\u56fe\u5bf9\u8c61\u4e0a\u7684 subplots_adjust \u65b9\u6cd5\u66f4\u6539\u95f4\u8ddd\uff0c\u4e5f\u53ef\u4ee5\u7528\u4f5c\u9876\u5c42\u51fd\u6570\u3002 fig, axes = plt.subplots(2, 2, sharex=True, sharey=True) for i in range(2): for j in range(2): axes[i, j].hist(np.random.randn(500), bins=50, color='k', alpha=0.5) plt.subplots_adjust(wspace=0, hspace=0) plt.show() \u4e0a\u9762\u8f93\u51fa\u56fe\u50cf\u7684\u8f74\u6807\u7b7e\u662f\u5b58\u5728\u91cd\u53e0\u7684\u3002 matplotlib \u5e76\u4e0d\u68c0\u67e5\u6807\u7b7e\u662f\u5426\u91cd\u53e0\uff0c\u56e0\u6b64\u5728\u7c7b\u4f3c\u60c5\u51b5\u4e0b\u4f60\u9700\u8981\u901a\u8fc7\u663e\u5f0f\u6307\u5b9a\u523b\u5ea6\u4f4d\u7f6e\u548c\u523b\u5ea6\u6807\u7b7e\u7684\u65b9\u6cd5\u6765\u4fee\u590d\u8f74\u6807\u7b7e\u3002","title":"\u56fe\u7247\u4e0e\u5b50\u56fe"},{"location":"python/DataAnalysis/ch06/#_3","text":"matplotlib \u7684\u4e3b\u51fd\u6570 plot \u63a5\u6536\u5e26\u6709 x \u548c y \u8f74\u7684\u6570\u7ec4\u4ee5\u53ca\u4e00\u4e9b\u53ef\u9009\u7684\u5b57\u7b26\u4e32\u7f29\u5199\u53c2\u6570\u6765\u6307\u660e\u989c\u8272\u548c\u7ebf\u7c7b\u578b\u3002 \u4f8b\u5982\uff1a\u4e0b\u9762\u4e24\u79cd\u8868\u8fbe\u65b9\u5f0f\u6548\u679c\u4e00\u6837\u3002 ax.plot(x, y, 'g--') ax.plot(x, y, linestyle='--', color='g') data = np.random.randn(30).cumsum() plt.plot(data, 'ko--') plt.show() # \u4e0a\u9762\u7684\u4ee3\u7801\u53ef\u4ee5\u5199\u5f97\u66f4\u4e3a\u663e\u5f0f\uff1a plt.plot(data, color='k', linestyle='dashed', marker='o') plt.show() plt.plot(data, color='k', linestyle='dashed', marker='o', label='Default') plt.show() plt.plot(data, color='k', linestyle='dashed', marker='o', label='steps-post', drawstyle='steps-post') plt.show()","title":"\u989c\u8272\u3001\u6807\u8bb0\u548c\u7ebf\u7c7b\u578b"},{"location":"python/DataAnalysis/ch06/#_4","text":"\u5bf9\u4e8e\u5927\u591a\u6570\u56fe\u8868\u4fee\u9970\u5de5\u4f5c\uff0c\u6709\u4e24\u79cd\u4e3b\u8981\u7684\u65b9\u5f0f\uff1a\u4f7f\u7528\u7a0b\u5e8f\u6027\u7684pyplot\u63a5\u53e3\uff08\u5373matplotlib.pyplot\uff09\u548c\u66f4\u591a\u9762\u5411\u5bf9\u8c61\u7684\u539f\u751fmatplotlib API\u3002 pyplot \u63a5\u53e3\u8bbe\u8ba1\u4e3a\u4ea4\u4e92\u5f0f\u4f7f\u7528\uff0c\u5305\u542b\u4e86\u50cf xlim \u3001 xticks \u548c xticklabels \u7b49\u65b9\u6cd5\u3002\u8fd9\u4e9b\u65b9\u6cd5\u5206\u522b\u63a7\u5236\u4e86\u7ed8\u56fe\u8303\u56f4\u3001\u523b\u5ea6\u4f4d\u7f6e\u4ee5\u53ca\u523b\u5ea6\u6807\u7b7e\u3002 \u5728\u6ca1\u6709\u51fd\u6570\u53c2\u6570\u7684\u60c5\u51b5\u4e0b\u8c03\u7528\uff0c\u8fd4\u56de\u5f53\u524d\u7684\u53c2\u6570\u503c\uff08\u4f8b\u5982 plt.xlim() \u8fd4\u56de\u5f53\u524d\u7684x\u8f74\u7ed8\u56fe\u8303\u56f4\uff09\u3002 \u4f20\u5165\u53c2\u6570\u7684\u60c5\u51b5\u4e0b\u8c03\u7528\uff0c\u5e76\u8bbe\u7f6e\u53c2\u6570\u503c\uff08\u4f8b\u5982 plt.xlim\uff08[0, 10]\uff09 \u4f1a\u5c06 x \u8f74\u7684\u8303\u56f4\u8bbe\u7f6e\u4e3a0\u523010\uff09\u3002 \u6240\u6709\u7684\u8fd9\u4e9b\u65b9\u6cd5\u90fd\u4f1a\u5728\u5f53\u524d\u6d3b\u52a8\u7684\u6216\u6700\u8fd1\u521b\u5efa\u7684 AxesSubplot \u4e0a\u751f\u6548\u3002 \u8fd9\u4e9b\u65b9\u6cd5\u4e2d\u7684\u6bcf\u4e00\u4e2a\u5bf9\u5e94\u4e8e\u5b50\u56fe\u81ea\u8eab\u7684\u4e24\u4e2a\u65b9\u6cd5\u3002\u6bd4\u5982 xlim \u5bf9\u5e94\u4e8e ax.get_lim \u548c ax.set_lim \u3002 \u63a8\u8350\u4f7f\u7528 subplot \u7684\u5b9e\u4f8b\u65b9\u6cd5\uff0c\u56e0\u4e3a\u8fd9\u6837\u66f4\u4e3a\u663e\u5f0f\uff08\u5c24\u5176\u662f\u5728\u5904\u7406\u591a\u4e2a\u5b50\u56fe\u65f6\uff09\u3002 data = np.random.randn(1000).cumsum() fig = plt.figure() # \u8bbe\u5b9a\u5b50\u56fe ax = fig.add_subplot(1, 1, 1) # \u8bbe\u5b9ax\u8f74\u5bf9\u5e94\u53c2\u6570\uff1a # \u8bbe\u5b9ax\u8f74\u523b\u5ea6 ax.set_xticks([0, 250, 500, 750, 1000]) # \u8bbe\u5b9ax\u8f74\u6807\u7b7e ax.set_xticklabels(['one(0)', 'two(250)', 'three(500)', 'four(750)', 'five(1000)'], rotation=30, fontsize='small') # \u7ed9x\u8f74\u4e00\u4e2a\u540d\u79f0 ax.set_xlabel('Stages') # \u8bbe\u5b9ay\u8f74\u5bf9\u5e94\u53c2\u6570\uff1a # \u672a\u6307\u5b9a\u7684\u53c2\u6570\u7531\u7cfb\u7edf\u9ed8\u8ba4\u4ea7\u751f\u3002 ax.set_ylabel('Steps') # \u7ed9\u5b50\u56fe\u6dfb\u52a0\u4e00\u4e2a\u6807\u9898 ax.set_title('My first matplotlib plot') # \u7ed9\u5b50\u56fe\u6dfb\u52a0\u4e00\u4e2a\u56fe\u4f8b\uff08\u5982\uff1a\u7ed9\u5b50\u56fe\u5185\u4e00\u4e2a\u56fe\u5f62\u66f2\u7ebf\u6dfb\u52a0\u4e00\u4e2alabel\uff09 ax.plot(data, 'k--', label='Label One') # loc\u53c2\u6570\u544a\u8bc9matplotlib\u5728\u54ea\u91cc\u653e\u7f6e\u56fe\u8868\u3002legend\u65b9\u6cd5\u6709\u591a\u4e2a\u5176\u4ed6\u7684\u4f4d\u7f6e\u53c2\u6570loc\u3002 ax.legend(loc='best') # \u6216\u8005plt.legend(loc='best') \u3002 # \u5728\u56fe\u5f62\u5750\u6807\u4e3a(0, 0)\u7684\u4f4d\u7f6e\u6dfb\u52a0\u4e00\u4e2alable ax.text(0, 0, 'Hello World1', family='monospace', fontsize=10) # \u7ed9\u5b50\u56fe\u6dfb\u52a0annotate\u3002\u7528\u4e00\u4e2a\u7bad\u5934\u6307\u5411\u8981\u6ce8\u91ca\u7684\u5730\u65b9\uff0c\u518d\u5199\u4e0a\u4e00\u6bb5\u8bdd\u7684\u884c\u4e3a\uff0c\u53eb\u505aannotate\u3002 # * s: \u6ce8\u91ca\u7684\u5185\u5bb9\uff0c\u4e00\u6bb5\u6587\u5b57\uff1b # * xytext: \u8fd9\u6bb5\u6587\u5b57\u6240\u5904\u7684\u4f4d\u7f6e; # * xy: \u7bad\u5934\u6307\u5411\u7684\u4f4d\u7f6e\uff1b # * arrowprops: \u901a\u8fc7arrowstyle\u8868\u660e\u7bad\u5934\u7684\u98ce\u683c\u6216\u79cd\u7c7b\u3002 ax.annotate('Zero is here!', xytext=(20, 20), xy=(1, 1), arrowprops=dict(arrowstyle='->')) # \u7ed9\u5b50\u56fe\u6dfb\u52a0\u4e00\u4e9b\u56fe\u5f62 # matplotlib\u542b\u6709\u8868\u793a\u591a\u79cd\u5e38\u89c1\u56fe\u5f62\u7684\u5bf9\u8c61\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u7684\u5f15\u7528\u662fpatches\u3002 # \u4e00\u4e9b\u56fe\u5f62\uff0c\u6bd4\u5982Rectangle\uff08\u77e9\u5f62\uff09\u548cCircle\uff08\u5706\u5f62\uff09\uff0c\u53ef\u4ee5\u5728matplotlib.pyplot\u4e2d\u627e\u5230\uff0c\u4f46\u56fe\u5f62\u7684\u5168\u96c6\u4f4d\u4e8ematplotlib.patches\u3002 rect = plt.Rectangle((10, 5), 100, 15, color='k', alpha=0.3) circ = plt.Circle((200, 9), 95, color='b', alpha=0.3) pgon = plt.Polygon([[500, 5], [600, -5], [700, 30]], color='g', alpha=0.5) ax.add_patch(rect) ax.add_patch(circ) ax.add_patch(pgon) # \u5c06\u56fe\u7247\u4fdd\u5b58\u5230\u6587\u4ef6 # \u6587\u4ef6\u7c7b\u578b\u662f\u4ece\u6587\u4ef6\u6269\u5c55\u540d\u4e2d\u63a8\u65ad\u51fa\u6765\u7684\u3002\u6240\u4ee5\u5982\u679c\u4f60\u4f7f\u7528\uff0epdf\uff0c\u5219\u4f1a\u5f97\u5230\u4e00\u4e2aPDF\u3002 # \u51e0\u4e2a\u91cd\u8981\u7684\u9009\u9879\uff1adpi\uff0c\u5b83\u63a7\u5236\u6bcf\u82f1\u5bf8\u70b9\u6570\u7684\u5206\u8fa8\u7387\uff1bbbox_inches\uff0c\u53ef\u4ee5\u4fee\u526a\u5b9e\u9645\u56fe\u5f62\u7684\u7a7a\u767d\u3002 plt.savefig('../examples/figpath.png', dpi=400, bbox_inches='tight') # saveifg\u5e76\u975e\u4e00\u5b9a\u662f\u5199\u5230\u786c\u76d8\u7684\uff0c\u5b83\u53ef\u4ee5\u5c06\u56fe\u7247\u5199\u5165\u5230\u6240\u6709\u7684\u6587\u4ef6\u578b\u5bf9\u8c61\u4e2d\uff0c\u4f8b\u5982BytesIO buffer = BytesIO() plt.savefig(buffer) plot_data = buffer.getvalue() plt.show()","title":"\u523b\u5ea6\u3001\u6807\u7b7e\u548c\u56fe\u4f8b"},{"location":"python/DataAnalysis/ch06/#matplotlib","text":"matplotlib \u914d\u7f6e\u4e86\u914d\u8272\u65b9\u6848\u548c\u9ed8\u8ba4\u8bbe\u7f6e\uff0c\u901a\u8fc7\u5168\u5c40\u53c2\u6570\u6765\u5b9a\u5236\uff0c\u5305\u62ec\u56fe\u5f62\u5927\u5c0f\u3001\u5b50\u56fe\u95f4\u8ddd\u3001\u989c\u8272\u3001\u5b57\u4f53\u5927\u5c0f\u548c\u7f51\u683c\u6837\u5f0f\u7b49\u7b49\u3002 \u4f7f\u7528 rc \u65b9\u6cd5\u662f\u4f7f\u7528Python\u7f16\u7a0b\u4fee\u6539\u914d\u7f6e\u7684\u4e00\u79cd\u65b9\u5f0f\u3002 rc \u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u4f60\u60f3\u8981\u81ea\u5b9a\u4e49\u7684\u7ec4\u4ef6\uff0c\u6bd4\u5982 'figure'\u3001'axes'\u3001'xtick'\u3001'ytick'\u3001'grid'\u3001'legend' \u7b49\u7b49\u3002 \u4e4b\u540e\uff0c\u53ef\u4ee5\u6309\u7167\u5173\u952e\u5b57\u53c2\u6570\u7684\u5e8f\u5217\u6307\u5b9a\u65b0\u53c2\u6570\u3002 \u5b57\u5178\u662f\u4e00\u79cd\u5728\u7a0b\u5e8f\u4e2d\u8bbe\u7f6e\u9009\u9879\u7684\u7b80\u5355\u65b9\u5f0f\u3002\u6bd4\u5982\uff1a plt.rc('figure', figsize=(10, 10)) font_options = { 'family': 'monospace', 'weight': 'bold', 'size': 'small' } plt.rc('font', **font_options)","title":"matplotlib\u8bbe\u7f6e"},{"location":"python/DataAnalysis/ch06/#pandasseaborn","text":"pandas\u81ea\u8eab\u6709\u5f88\u591a\u5185\u5efa\u65b9\u6cd5\u53ef\u4ee5\u7b80\u5316\u4eceDataFrame\u548cSeries\u5bf9\u8c61\u751f\u6210\u53ef\u89c6\u5316\u7684\u8fc7\u7a0b\u3002 \u53e6\u4e00\u4e2a\u5e93\u662f seaborn \u3002 seaborn \u7b80\u5316\u4e86\u5f88\u591a\u5e38\u7528\u53ef\u89c6\u5316\u7c7b\u578b\u7684\u751f\u6210\u3002 \u5bfc\u5165 seaborn \u4f1a\u4fee\u6539\u9ed8\u8ba4\u7684matplotlib\u914d\u8272\u65b9\u6848\u548c\u7ed8\u56fe\u6837\u5f0f\uff0c\u8fd9\u4f1a\u63d0\u9ad8\u56fe\u8868\u7684\u53ef\u8bfb\u6027\u548c\u7f8e\u89c2\u6027\u3002 \u5373\u4f7f\u4e0d\u4f7f\u7528seaborn\u7684API\uff0c\u4e5f\u53ef\u4ee5\u5bfc\u5165seaborn\u6765\u4e3a\u901a\u7528matplotlib\u56fe\u8868\u63d0\u4f9b\u66f4\u597d\u7684\u89c6\u89c9\u7f8e\u89c2\u5ea6\u3002 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns","title":"\u4f7f\u7528pandas\u548cseaborn\u7ed8\u56fe"},{"location":"python/DataAnalysis/ch06/#_5","text":"Series\u548cDataFrame\u90fd\u6709\u4e00\u4e2a plot \u5c5e\u6027\uff0c\u7528\u4e8e\u7ed8\u5236\u57fa\u672c\u7684\u56fe\u5f62\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c plot() \u7ed8\u5236\u7684\u662f\u6298\u7ebf\u56fe\u3002 Series\u7684 plot \u53c2\u6570\uff1a ax: matplotlib\u5b50\u56fe\u5bf9\u8c61axes\uff0c\u5982\u679c\u6ca1\u6709\u4f20\u503c\uff0c\u5219\u4f7f\u7528\u5f53\u524d\u6d3b\u52a8\u7684\u5b50\u56fe\u9ed8\u8ba4\u4f7f\u7528gca() alpha: \u56fe\u7247\u4e0d\u900f\u660e\u5ea6\uff080\u52301\uff09 data: \u6570\u636e\u5e8f\u5217Series figsize: \u56fe\u50cf\u5c3a\u5bf8\uff0ctuple(\u5bbd\u5ea6\uff0c\u9ad8\u5ea6)\uff0c\u6ce8\u610f\u8fd9\u91cc\u7684\u5355\u4f4d\u662f\u82f1\u5bf8 fontsize: \u8bbe\u7f6e\u523b\u5ea6\u6807\u7b7e\uff08xticks, yticks\uff09\u7684\u5927\u5c0f grid: \u7f51\u683c\u7ebf\uff08\u9ed8\u8ba4\u662f\u6253\u5f00\u7684\uff09 kind: \u56fe\u7c7b\u578b\uff1a\u6298\u7ebf\u56fe\uff0c\u67f1\u5f62\u56fe\uff0c\u6a2a\u5411\u67f1\u5f62\u56fe\uff0c\u76f4\u65b9\u56fe\uff0c\u7bb1\u7ebf\u56fe\uff0c\u5bc6\u5ea6\u56fe\uff0c\u9762\u79ef\u56fe\uff0c\u997c\u56fe label: \u5217\u7684\u522b\u540d\uff0c\u4f5c\u7528\u5728\u56fe\u4f8b\u4e0a legend: \u56fe\u4f8b loglog: x,y\u8f74\u90fd\u4f7f\u7528\u5bf9\u6570\u523b\u5ea6 logx: x\u8f74\u4f7f\u7528\u5bf9\u6570\u523b\u5ea6 logy: y\u8f74\u4f7f\u7528\u5bf9\u6570\u523b\u5ea6 mark_right: \u53cc y \u8f74\u65f6\uff0c\u5728\u56fe\u4f8b\u4e2d\u7684\u5217\u6807\u7b7e\u65c1\u589e\u52a0\u663e\u793a (right) \u6807\u8bc6 position: \u67f1\u5f62\u56fe\u7684\u67f1\u5b50\u7684\u4f4d\u7f6e\u8bbe\u7f6e rot: \u6539\u53d8\u523b\u5ea6\u6807\u7b7e\uff08xticks, yticks\uff09\u7684\u65cb\u8f6c\u5ea6\uff080\u5230360\uff09 secondary_y: \u53cc y \u8f74\uff0c\u5728\u53f3\u8fb9\u7684\u7b2c\u4e8c\u4e2a y \u8f74 style: \u7ebf\u7684\u6837\u5f0f\uff0c\u6bd4\u5982'ko--' table: \u5c06\u6570\u636e\u4ee5\u8868\u683c\u7684\u5f62\u5f0f\u5c55\u793a\u51fa\u6765 title: \u6807\u9898 use_index: \u662f\u5426\u4f7f\u7528\u7d22\u5f15\u4f5c\u4e3ax\u523b\u5ea6\u6807\u7b7e xerr: \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe xlim: \u6a2a\u8f74\u5750\u6807\u523b\u5ea6\u7684\u53d6\u503c\u8303\u56f4 xticks: x\u8f74\u523b\u5ea6\u6807\u7b7e yerr: \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe ylim: \u7eb5\u8f74\u5750\u6807\u523b\u5ea6\u7684\u53d6\u503c\u8303\u56f4 yticks: y\u8f74\u523b\u5ea6\u6807\u7b7e **kwds: matplotlib plot\u65b9\u6cd5\u7684\u5176\u4ed6\u53c2\u6570 DataFrame\u7684 plot \u53c2\u6570\uff1a x : \u6307\u6570\u636e\u6846\u5217\u7684\u6807\u7b7e\u6216\u4f4d\u7f6e\u53c2\u6570 y : \u6307\u6570\u636e\u6846\u5217\u7684\u6807\u7b7e\u6216\u4f4d\u7f6e\u53c2\u6570 kind : 'line' : \u6298\u7ebf\u56fe 'bar' : \u6761\u5f62\u56fe 'barh' : \u6a2a\u5411\u6761\u5f62\u56fe 'hist' : \u67f1\u72b6\u56fe 'box' : \u7bb1\u7ebf\u56fe 'kde' : Kernel\u7684\u5bc6\u5ea6\u4f30\u8ba1\u56fe\uff0c\u4e3b\u8981\u5bf9\u67f1\u72b6\u56fe\u6dfb\u52a0Kernel \u6982\u7387\u5bc6\u5ea6\u7ebf 'density' : 'kde' 'area' : area plot 'pie' : \u997c\u56fe 'scatter' : \u6563\u70b9\u56fe \u9700\u8981\u4f20\u5165columns\u65b9\u5411\u7684\u7d22\u5f15 'hexbin' : hexbin plot ax : \u5b50\u56fe(axes, \u4e5f\u53ef\u4ee5\u7406\u89e3\u6210\u5750\u6807\u8f74) \u8981\u5728\u5176\u4e0a\u8fdb\u884c\u7ed8\u5236\u7684matplotlib subplot\u5bf9\u8c61\u3002\u5982\u679c\u6ca1\u6709\u8bbe\u7f6e\uff0c\u5219\u4f7f\u7528\u5f53\u524dmatplotlib subplot\u3002\u5176\u4e2d\uff0c\u53d8\u91cf\u548c\u51fd\u6570\u901a\u8fc7\u6539\u53d8figure\u548caxes\u4e2d\u7684\u5143\u7d20\uff08\u4f8b\u5982\uff1atitle,label,\u70b9\u548c\u7ebf\u7b49\u7b49\uff09\u4e00\u8d77\u63cf\u8ff0figure\u548caxes\uff0c\u4e5f\u5c31\u662f\u5728\u753b\u5e03\u4e0a\u7ed8\u56fe\u3002 subplots : \u5224\u65ad\u56fe\u7247\u4e2d\u662f\u5426\u6709\u5b50\u56fe sharex : \u5982\u679c\u6709\u5b50\u56fe\uff0c\u5b50\u56fe\u5171x\u8f74\u523b\u5ea6\uff0c\u6807\u7b7e sharey : \u5982\u679c\u6709\u5b50\u56fe\uff0c\u5b50\u56fe\u5171y\u8f74\u523b\u5ea6\uff0c\u6807\u7b7e layout : \u5b50\u56fe\u7684\u884c\u5217\u5e03\u5c40 figsize : \u56fe\u7247\u5c3a\u5bf8\u5927\u5c0f use_index : \u9ed8\u8ba4\u7528\u7d22\u5f15\u505ax\u8f74 title : \u56fe\u7247\u7684\u6807\u9898\u7528\u5b57\u7b26\u4e32 grid : \u56fe\u7247\u662f\u5426\u6709\u7f51\u683c legend : \u5b50\u56fe\u7684\u56fe\u4f8b\uff0c\u6dfb\u52a0\u4e00\u4e2asubplot\u56fe\u4f8b(\u9ed8\u8ba4\u4e3aTrue) style : \u5bf9\u6bcf\u5217\u6298\u7ebf\u56fe\u8bbe\u7f6e\u7ebf\u7684\u7c7b\u578b logx : \u8bbe\u7f6ex\u8f74\u523b\u5ea6\u662f\u5426\u53d6\u5bf9\u6570 logy : \u8bbe\u7f6ey\u8f74\u523b\u5ea6\u662f\u5426\u53d6\u5bf9\u6570 loglog : \u540c\u65f6\u8bbe\u7f6ex\uff0cy\u8f74\u523b\u5ea6\u662f\u5426\u53d6\u5bf9\u6570 xticks : \u8bbe\u7f6ex\u8f74\u523b\u5ea6\u503c\uff0c\u5e8f\u5217\u5f62\u5f0f\uff08\u6bd4\u5982\u5217\u8868\uff09 yticks : \u8bbe\u7f6ey\u8f74\u523b\u5ea6\uff0c\u5e8f\u5217\u5f62\u5f0f\uff08\u6bd4\u5982\u5217\u8868\uff09 xlim : \u8bbe\u7f6e\u5750\u6807\u8f74x\u7684\u8303\u56f4\uff0c\u5217\u8868\u6216\u5143\u7ec4\u5f62\u5f0f ylim : \u8bbe\u7f6e\u5750\u6807\u8f74y\u7684\u8303\u56f4\uff0c\u5217\u8868\u6216\u5143\u7ec4\u5f62\u5f0f rot : \u8bbe\u7f6e\u8f74\u6807\u7b7e\uff08\u8f74\u523b\u5ea6\uff09\u7684\u663e\u793a\u65cb\u8f6c\u5ea6\u6570 fontsize : \u8bbe\u7f6e\u8f74\u523b\u5ea6\u7684\u5b57\u4f53\u5927\u5c0f colormap : \u8bbe\u7f6e\u56fe\u7684\u533a\u57df\u989c\u8272 colorbar : \u56fe\u7247\u67f1\u5b50 position : Specify relative alignments for bar plot layout. From 0 (left/bottom-end) to 1 (right/top-end). Default is 0.5 (center) layout : \u5e03\u5c40(rows, columns) for the layout of the plot table : \u5982\u679c\u4e3a\u6b63\uff0c\u5219\u9009\u62e9DataFrame\u7c7b\u578b\u7684\u6570\u636e\u5e76\u4e14\u8f6c\u6362\u5339\u914dmatplotlib\u7684\u5e03\u5c40 yerr : \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe xerr : \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe stacked : \u751f\u6210\u5806\u79ef\u67f1\u72b6\u56fe sort_columns : \u4ee5\u5b57\u6bcd\u8868\u987a\u5e8f\u7ed8\u5236\u5404\u5217\uff0c\u9ed8\u8ba4\u4f7f\u7528\u524d\u5217\u987a\u5e8f secondary_y : \u8bbe\u7f6e\u7b2c\u4e8c\u4e2ay\u8f74\uff08\u53f3y\u8f74\uff09 mark_right : When using a secondary_y axis, automatically mark the column labels with \u201c(right)\u201d in the legend kwds : Options to pass to matplotlib plotting method Series data1 = np.random.randn(10).cumsum(0) s1 = pd.Series( data1, index=np.arange(0, 100, 10), ) print(s1) fig, axes = plt.subplots(3, 1) # 3\u4e2a\u5b50\u56fe s1.plot.bar(ax=axes[0], color='k', alpha=0.7) # \u6761\u5f62\u56fe(\u5b50\u56fe0)\uff0ccolor='k\u2019(\u67f1\u5b50\u7684\u989c\u8272\u8bbe\u7f6e\u4e3a\u9ed1\u8272)\uff0calpha=0.7(\u56fe\u50cf\u7684\u586b\u5145\u8272\u8bbe\u7f6e\u4e3a\u90e8\u5206\u900f\u660e) s1.plot.barh(ax=axes[1], color='k', alpha=0.7) # \u6a2a\u5411\u6761\u5f62\u56fe(\u5b50\u56fe1) s1.value_counts().plot.pie(ax=axes[2]) # \u901a\u8fc7value_counts()\u5bf9Series\u503c\u9891\u7387\u8fdb\u884c\u53ef\u89c6\u5316 plt.show() DataFrame data2 = np.random.randn(10, 4).cumsum(0) df1 = pd.DataFrame( data2, columns=pd.Index(['A', 'B', 'C', 'D'], name='Genus'), index=np.arange(0, 100, 10) ) print(df1) fig, axes = plt.subplots(2, 1) # 2\u4e2a\u5b50\u56fe df1.plot.kde(ax=axes[0], alpha=0.7, grid='True', title='KDE Figure', sharex=True) df1.plot.bar(ax=axes[1], grid='True', title='Line Figure', sharex=True, use_index=False, stacked=True) # \u56e0\u4e3a\u5171\u4eabx\u8f74\uff0c\u6240\u4ee5\u5728KDE\u5b50\u56fe\u4e2d\u6307\u5b9ause_index=False\u770b\u4e0d\u51fa\u6548\u679c\u3002 # DataFrame\u7684\u5217\u540d\u79f0\"Genus\"\u88ab\u7528\u4f5c\u4e86\u56fe\u4f8b\u6807\u9898 # stacked=True\u6765\u751f\u6210\u5806\u79ef\u67f1\u72b6\u56fe plt.show() \u5b9e\u4f8b\uff1a\u7ed8\u5236\u4e00\u4e2a\u5806\u79ef\u67f1\u72b6\u56fe\uff0c\u7528\u4e8e\u5c55\u793a\u6bcf\u4e2a\u6d3e\u5bf9\u5728\u6bcf\u5929\u7684\u6570\u636e\u70b9\u5360\u6bd4\u3002 \u4ea4\u53c9\u8868 \u662f\u4e00\u79cd\u5e38\u7528\u7684\u5206\u7c7b\u6c47\u603b\u8868\u683c\uff0c\u7528\u4e8e\u9891\u6570\u5206\u5e03\u7edf\u8ba1\uff0c\u4e3b\u8981\u4ef7\u503c\u5728\u4e8e\u63cf\u8ff0\u4e86\u53d8\u91cf\u95f4\u5173\u7cfb\u7684\u6df1\u523b\u542b\u4e49\u3002 \u867d\u7136\u4e24\u4e2a\uff08\u6216\u4ee5\u4e0a\uff09\u53d8\u91cf\u53ef\u4ee5\u662f\u5206\u7c7b\u7684\u6216\u6570\u91cf\u7684\uff0c\u4f46\u662f\u4ee5\u90fd\u662f\u5206\u7c7b\u7684\u60c5\u5f62\u6700\u4e3a\u5e38\u89c1\u3002 Pandas\u7684 crosstab() \u65b9\u6cd5\u80fd\u591f\u5feb\u901f\u6784\u5efa\u4ea4\u53c9\u8868\uff0c\u5e76\u53ef\u4ee5\u901a\u8fc7\u53c2\u6570\u52a0\u4ee5\u4e2a\u6027\u5316\u7684\u8bbe\u7f6e\u3002\u5176\u4e2d\uff0c\u7b2c\u4e00\u4e2a\u53c2\u6570\u5c06\u6784\u6210\u4ea4\u53c9\u8868\u7684\u884c\uff0c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u5c06\u6784\u6210\u4ea4\u53c9\u8868\u7684\u5217\u3002 tips = pd.read_csv('../examples/tips.csv') print(tips) # total_bill tip smoker day time size # 0 16.99 1.01 No Sun Dinner 2 # 1 10.34 1.66 No Sun Dinner 3 # 2 21.01 3.50 No Sun Dinner 3 # 3 23.68 3.31 No Sun Dinner 2 # 4 24.59 3.61 No Sun Dinner 4 # .. ... ... ... ... ... ... # 239 29.03 5.92 No Sat Dinner 3 # 240 27.18 2.00 Yes Sat Dinner 2 # 241 22.67 2.00 Yes Sat Dinner 2 # 242 17.82 1.75 No Sat Dinner 2 # 243 18.78 3.00 No Thur Dinner 2 # [244 rows x 6 columns] party_counts = pd.crosstab(tips['day'], tips['size']) # \u5bf9\u539f\u59cb\u6570\u636e\u7684day\u548csize\u8fdb\u884c\u805a\u5408\uff0c\u5e76\u6784\u5efa\u4ea4\u53c9\u8868\uff0cday\u4f5c\u4e3a\u884c\uff0csize\u4f5c\u4e3a\u5217\u3002 print(party_counts) # size 1 2 3 4 5 6 # day # Fri 1 16 1 1 0 0 # Sat 2 53 18 13 1 0 # Sun 0 39 15 18 3 1 # Thur 1 48 4 5 1 3 # \u6ca1\u6709\u592a\u591a\u76841\u4eba\u548c6\u4eba\u6d3e\u5bf9\uff0c\u820d\u5f03\u8fd9\u4e9b\u6570\u636e party_counts = party_counts.loc[:, 2:5] print(party_counts) # size 2 3 4 5 # day # Fri 16 1 1 0 # Sat 53 18 13 1 # Sun 39 15 18 3 # Thur 48 4 5 1 # \u6807\u51c6\u5316\u81f3\u548c\u4e3a1\uff1a\u6cbf0\u8f74\uff08\u884c\uff09\u5bf9\u6bcf\u5217\u6c42\u548c\uff0c\u6bcf\u884c\u5404\u503c\u9664\u4ee5\u548c\uff0c\u4ee5\u786e\u4fdd\u6bcf\u4e00\u884c\u7684\u503c\u548c\u4e3a1\uff0c\u7136\u540e\u8fdb\u884c\u7ed8\u56fe party_pcts = party_counts.div(party_counts.sum(1), axis=0) print(party_pcts) # size 2 3 4 5 # day # Fri 0.888889 0.055556 0.055556 0.000000 # Sat 0.623529 0.211765 0.152941 0.011765 # Sun 0.520000 0.200000 0.240000 0.040000 # Thur 0.827586 0.068966 0.086207 0.017241 party_counts.plot.bar() plt.show() \u53ef\u4ee5\u770b\u5230\u672c\u6570\u636e\u96c6\u4e2d\u7684\u6d3e\u5bf9\u6570\u91cf\u5728\u5468\u672b\u4f1a\u589e\u52a0\u3002 \u5b9e\u4f8b\uff1a\u4f7f\u7528seaborn\u8fdb\u884c\u6309\u661f\u671f\u65e5\u671f\u8ba1\u7b97\u5c0f\u8d39\u767e\u5206\u6bd4\u3002 Seaborn\u8981\u6c42\u6570\u636e\u7684\u8f93\u5165\u7c7b\u578b\u4e3apandas\u7684Dataframe\u6216Numpy\u6570\u7ec4\u3002 tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) print(tips) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 # .. ... ... ... ... ... ... ... # 239 29.03 5.92 No Sat Dinner 3 0.256166 # 240 27.18 2.00 Yes Sat Dinner 2 0.079428 # 241 22.67 2.00 Yes Sat Dinner 2 0.096759 # 242 17.82 1.75 No Sat Dinner 2 0.108899 # 243 18.78 3.00 No Thur Dinner 2 0.190114 # [244 rows x 7 columns] # barplot: \u5c06\u70b9\u4f30\u8ba1\u548c\u7f6e\u4fe1\u533a\u95f4\u663e\u793a\u4e3a\u77e9\u5f62\u6761\u3002\u6761\u5f62\u56fe\u8868\u793a\u5177\u6709\u6bcf\u4e2a\u77e9\u5f62\u7684\u9ad8\u5ea6\u7684\u6570\u503c\u53d8\u91cf\u7684\u96c6\u4e2d\u8d8b\u52bf\u7684\u4f30\u8ba1\uff0c\u5e76\u4e14\u4f7f\u7528\u8bef\u5dee\u6761\u63d0\u4f9b\u56f4\u7ed5\u8be5\u4f30\u8ba1\u7684\u4e0d\u786e\u5b9a\u6027\u7684\u4e00\u4e9b\u6307\u793a # \u67f1\u5b50\u7684\u503c\u662ftip_pct\u7684\u5e73\u5747\u503c # \u67f1\u5b50\u4e0a\u753b\u51fa\u7684\u9ed1\u7ebf\u4ee3\u8868\u7684\u662f95%\u7684\u7f6e\u4fe1\u533a\u95f4\uff08\u7f6e\u4fe1\u533a\u95f4\u53ef\u4ee5\u901a\u8fc7\u53ef\u9009\u53c2\u6570\u8fdb\u884c\u8bbe\u7f6e\uff09 # hue\u9009\u9879\uff0c\u5141\u8bb8\u6211\u4eec\u901a\u8fc7\u4e00\u4e2a\u989d\u5916\u7684\u5206\u7c7b\u503c\u5c06\u6570\u636e\u5206\u79bb # \u5e26\u53c2\u6570hue='time'\u65f6\uff0c\u56db\u4e2a\u4e0d\u540c\u989c\u8272\u7684\u67f1\u5b50\uff0c\u6bcf\u4e2a\u67f1\u5b50\u4e0a\u6709\u7f6e\u4fe1\u533a\u95f4\u7684\u9ed1\u7ebf\uff0c\u523b\u5ea60.00~0.30\uff0c\u6b65\u957f0.05 # \u4e0d\u5e26\u53c2\u6570hue='time'\u65f6\uff0c\u4e24\u4e2a\u4e0d\u540c\u989c\u8272\u7684\u67f1\u5b50\uff0c\u5206\u522b\u4ee3\u8868Dinner\u548cLunch\uff0c\u4e0d\u662f\u6bcf\u4e2a\u67f1\u5b50\u4e0a\u90fd\u6709\u7f6e\u4fe1\u533a\u95f4\u7684\u9ed1\u7ebf\uff0c\u523b\u5ea60.00~0.30\uff0c\u6b65\u957f0.05 sns.barplot(x='tip_pct', y='day', data=tips, hue='time', orient='h') # \u6839\u636e\u661f\u671f\u65e5\u671f\u548c\u65f6\u95f4\u8ba1\u7b97\u7684\u5c0f\u8d39\u767e\u5206\u6bd4 # sns.barplot(x='tip_pct', y='day', data=tips, orient='h') sns.set(style=\"darkgrid\", palette=\"deep\") # style=\"whitegrid\" plt.show()","title":"\u6298\u7ebf\u56fe"},{"location":"python/DataAnalysis/ch06/#_6","text":"\u76f4\u65b9\u56fe\u662f\u4e00\u79cd\u6761\u5f62\u56fe\uff0c\u7528\u4e8e\u7ed9\u51fa\u503c\u9891\u7387\u7684\u79bb\u6563\u663e\u793a\u3002\u6570\u636e\u70b9\u88ab\u5206\u6210\u79bb\u6563\u7684\uff0c\u5747\u5300\u95f4\u9694\u7684\u7bb1\uff0c\u5e76\u4e14\u7ed8\u5236\u6bcf\u4e2a\u7bb1\u4e2d\u6570\u636e\u70b9\u7684\u6570\u91cf\u3002 tips['tip_pct'].plot.hist(bins=50) # \u5c0f\u8d39\u767e\u5206\u6bd4\u7684\u76f4\u65b9\u56fe plt.show() \u5bc6\u5ea6\u56fe\u662f\u4e00\u79cd\u4e0e\u76f4\u65b9\u56fe\u76f8\u5173\u7684\u56fe\u8868\u7c7b\u578b\uff0c\u5b83\u901a\u8fc7\u8ba1\u7b97\u53ef\u80fd\u4ea7\u751f\u89c2\u6d4b\u6570\u636e\u7684\u8fde\u7eed\u6982\u7387\u5206\u5e03\u4f30\u8ba1\u800c\u4ea7\u751f\u3002 \u901a\u5e38\u7684\u505a\u6cd5\u662f\u5c06\u8fd9\u79cd\u5206\u5e03\u8fd1\u4f3c\u4e3a\u201c\u5185\u6838\u201d\u7684\u6df7\u5408\uff0c\u4e5f\u5c31\u662f\u50cf\u6b63\u6001\u5206\u5e03\u90a3\u6837\u7b80\u5355\u7684\u5206\u5e03\u3002 \u56e0\u6b64\uff0c\u5bc6\u5ea6\u56fe\u4e5f\u88ab\u79f0\u4e3a\u5185\u6838\u5bc6\u5ea6\u4f30\u8ba1\u56fe\uff08KDE\uff09\u3002 tips['tip_pct'].plot.density() # \u5c0f\u8d39\u767e\u5206\u6bd4\u5bc6\u5ea6\u56fe plt.show() \u7ed8\u5236\u76f4\u65b9\u56fe\u548c\u8fde\u7eed\u5bc6\u5ea6\u4f30\u8ba1 sns.displot() \u3002 sns.distplot(tips['tip_pct'], bins=100, color='k') plt.show() # FutureWarning: `distplot` is a deprecated function and will be removed in a future version. # Please adapt your code to use either `displot` (a figure-level function with similar flexibility) # or `histplot` (an axes-level function for histograms).","title":"\u76f4\u65b9\u56fe\u548c\u5bc6\u5ea6\u56fe"},{"location":"python/DataAnalysis/ch06/#_7","text":"\u70b9\u56fe\u6216\u6563\u70b9\u56fe\u53ef\u4ee5\u7528\u4e8e\u68c0\u9a8c\u4e24\u4e2a\u4e00\u7ef4\u6570\u636e\u5e8f\u5217\u4e4b\u95f4\u7684\u5173\u7cfb\u3002 \u5b9e\u4f8b\uff1a\u4ece statsmodels \u9879\u76ee\u4e2d\u8f7d\u5165\u4e86macrodata\u6570\u636e\u96c6\uff0c\u5e76\u9009\u62e9\u4e86\u4e00\u4e9b\u53d8\u91cf\uff0c\u4e4b\u540e\u8ba1\u7b97\u5bf9\u6570\u5dee\u3002 macro = pd.read_csv('../examples/macrodata.csv') print(macro.head(5)) # year quarter realgdp realcons ... unemp pop infl realint # 0 1959.0 1.0 2710.349 1707.4 ... 5.8 177.146 0.00 0.00 # 1 1959.0 2.0 2778.801 1733.7 ... 5.1 177.830 2.34 0.74 # 2 1959.0 3.0 2775.488 1751.8 ... 5.3 178.657 2.74 1.09 # 3 1959.0 4.0 2785.204 1753.7 ... 5.6 179.386 0.27 4.06 # 4 1960.0 1.0 2847.699 1770.5 ... 5.2 180.007 2.31 1.19 # [5 rows x 14 columns] data = macro[['cpi', 'm1', 'tbilrate', 'unemp']] print(data.head(5)) # cpi m1 tbilrate unemp # 0 28.98 139.7 2.82 5.8 # 1 29.15 141.7 3.08 5.1 # 2 29.35 140.5 3.82 5.3 # 3 29.37 140.0 4.33 5.6 # 4 29.54 139.6 3.50 5.2 trans_data = np.log(data).diff().dropna() print(trans_data[-5:]) # cpi m1 tbilrate unemp # 198 -0.007904 0.045361 -0.396881 0.105361 # 199 -0.021979 0.066753 -2.277267 0.139762 # 200 0.002340 0.010286 0.606136 0.160343 # 201 0.008419 0.037461 -0.200671 0.127339 # 202 0.008894 0.012202 -0.405465 0.042560 \u7528 seaborn \u7684 regplot \u65b9\u6cd5\u7ed8\u5236\u6563\u70b9\u56fe\uff0c\u5e76\u62df\u5408\u51fa\u4e00\u4e2a\u6761\u7ebf\u6027\u56de\u5f52\u7ebf\u3002( seaborn\u6587\u6863 ) sns.regplot('m1', 'unemp', data=trans_data) plt.title('Changes in log %s versus log %s ' % ('m1', 'unemp')) plt.show() \u5728\u63a2\u7d22\u6027\u6570\u636e\u5206\u6790\u4e2d\uff0c\u80fd\u591f\u67e5\u770b\u4e00\u7ec4\u53d8\u91cf\u4e2d\u7684\u6240\u6709\u6563\u70b9\u56fe\u662f\u6709\u5e2e\u52a9\u7684\uff0c\u8fd9\u88ab\u79f0\u4e3a\u6210\u5bf9\u56fe\u6216\u6563\u70b9\u56fe\u77e9\u9635\u3002 Seaborn\u6709\u4e00\u4e2a\u65b9\u4fbf\u7684 pairplot \u51fd\u6570\uff0c\u5b83\u652f\u6301\u5728\u5bf9\u89d2\u7ebf\u4e0a\u653e\u7f6e\u6bcf\u4e2a\u53d8\u91cf\u7684\u76f4\u65b9\u56fe\u6216\u5bc6\u5ea6\u4f30\u8ba1\u503c\u3002 plot_ksw \u53c2\u6570\u80fd\u591f\u5c06\u914d\u7f6e\u9009\u9879\u4f20\u9012\u7ed9\u975e\u5bf9\u89d2\u5143\u7d20\u4e0a\u7684\u5404\u4e2a\u7ed8\u56fe\u8c03\u7528\u3002 sns.pairplot(trans_data, diag_kind='kde', plot_kws={'alpha': 0.2}) plt.show()","title":"\u6563\u70b9\u56fe\u6216\u70b9\u56fe"},{"location":"python/DataAnalysis/ch06/#_8","text":"\u5982\u679c\u6570\u636e\u96c6\u6709\u989d\u5916\u7684\u5206\u7ec4\u7ef4\u5ea6\u600e\u4e48\u529e\uff1f\u4f7f\u7528\u5206\u9762\u7f51\u683c\u662f\u5229\u7528\u591a\u79cd\u5206\u7ec4\u53d8\u91cf\u5bf9\u6570\u636e\u8fdb\u884c\u53ef\u89c6\u5316\u7684\u65b9\u5f0f\u3002 seaborn\u62e5\u6709\u4e00\u4e2a\u6709\u6548\u7684\u5185\u5efa\u51fd\u6570 factorplot \uff0c\u5b83\u53ef\u4ee5\u7b80\u5316\u591a\u79cd\u5206\u9762\u7ed8\u56fe\u3002 sns.factorplot(x='day', y='tip_pct', hue='time', col='smoker', kind='bar', data=tips[tips.tip_pct < 1]) plt.show() # UserWarning: The `factorplot` function has been renamed to `catplot`. # The original name will be removed in a future release. Please update your code. # Note that the default `kind` in `factorplot` (`'point'`) has changed `'strip'` in `catplot`. sns.catplot(x='day', y='tip_pct', hue='time', col='smoker', kind='box', data=tips[tips.tip_pct < 0.5]) plt.show()","title":"\u5206\u9762\u7f51\u683c\u548c\u5206\u7c7b\u6570\u636e"},{"location":"python/DataAnalysis/ch06/#python","text":"\u81ea2010\u5e74\u4ee5\u6765\uff0c\u5f88\u591a\u5f00\u53d1\u5de5\u4f5c\u90fd\u96c6\u4e2d\u5728\u521b\u5efaweb\u4ea4\u4e92\u5f0f\u56fe\u5f62\u4e0a\u3002 \u501f\u52a9\u50cf Bokeh \u548c Plotly \u8fd9\u6837\u7684\u5de5\u5177\uff0c\u5728web\u6d4f\u89c8\u5668\u4e2d\u521b\u5efa\u52a8\u6001\u7684\u3001\u4ea4\u4e92\u5f0f\u56fe\u50cf\u7684\u5de5\u4f5c\u73b0\u5728\u5df2\u7ecf\u53ef\u4ee5\u5b9e\u73b0\u3002 \u53ef\u89c6\u5316\u662f\u4e00\u4e2a\u6d3b\u8dc3\u7684\u7814\u7a76\u9886\u57df\u3002","title":"\u5176\u4ed6Python\u53ef\u89c6\u5316\u5de5\u5177"},{"location":"python/DataAnalysis/ch07/","text":"\u6570\u636e\u805a\u5408\u4e0e\u5206\u7ec4\u64cd\u4f5c \u00b6 GroupBy\u673a\u5236 \u00b6 import pandas as pd import numpy as np \u5206\u7ec4\u673a\u5236 \u00b6 \u5206\u7ec4\u64cd\u4f5c\u7b2c\u4e00\u6b65\uff0c\u6570\u636e\u5305\u542b\u5728pandas\u5bf9\u8c61\u4e2d\uff0c\u53ef\u4ee5\u662fSeries\u3001DataFrame\u6216\u5176\u4ed6\u6570\u636e\u7ed3\u6784\u3002\u4e4b\u540e\u6839\u636e\u63d0\u4f9b\u7684\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u5206\u79bb\u5230\u5404\u4e2a\u7ec4\u4e2d\u3002 \u5206\u7ec4\u952e\u53ef\u662f\u591a\u79cd\u5f62\u5f0f\u7684\uff0c\u5e76\u4e14\u952e\u4e0d\u4e00\u5b9a\u662f\u5b8c\u5168\u76f8\u540c\u7684\u7c7b\u578b(\u6ce8\u610f\u540e\u9762\u4ecb\u7ecd\u7684\u4e09\u4e2a\u65b9\u6cd5\u662f\u53ef\u4ee5\u4ea7\u751f\u7528\u4e8e\u5206\u9694\u5bf9\u8c61\u7684\u503c\u6570\u7ec4\u7684\u5feb\u6377\u65b9\u5f0f)\uff1a \u4e0e\u9700\u8981\u5206\u7ec4\u7684\u8f74\u5411\u957f\u5ea6\u4e00\u81f4\u7684\u503c\u5217\u8868\u6216\u503c\u6570\u7ec4\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cgroupby\u5728axis=0\u7684\u8f74\u5411\u4e0a\u5206\u7ec4\u3002 DataFrame\u7684\u5217\u540d\u7684\u503c\u3002 \u53ef\u4ee5\u5c06\u5206\u7ec4\u8f74\u5411\u4e0a\u7684\u503c\u548c\u5206\u7ec4\u540d\u79f0\u76f8\u5339\u914d\u7684\u5b57\u5178\u6216Series\u3002 \u53ef\u4ee5\u5728\u8f74\u7d22\u5f15\u6216\u7d22\u5f15\u4e2d\u7684\u5355\u4e2a\u6807\u7b7e\u4e0a\u8c03\u7528\u7684\u51fd\u6570\u3002 \u8bf7\u6ce8\u610f\uff0c\u5206\u7ec4\u952e\u4e2d\u7684\u4efb\u4f55\u7f3a\u5931\u503c\u5c06\u88ab\u6392\u9664\u5728\u7ed3\u679c\u4e4b\u5916\u3002 \u5206\u79bb\u64cd\u4f5c\u662f\u5728\u6570\u636e\u5bf9\u8c61\u7684\u7279\u5b9a\u8f74\u5411\u4e0a\u8fdb\u884c\u7684\u3002\u4f8b\u5982\uff0cDataFrame\u53ef\u4ee5\u5728\u5b83\u7684\u884c\u65b9\u5411\uff08axis=0\uff09\u6216\u5217\u65b9\u5411\uff08axis=1\uff09\u8fdb\u884c\u5206\u7ec4\u3002 \u5206\u7ec4\u64cd\u4f5c\u540e\uff0c\u4e00\u4e2a\u51fd\u6570\u5c31\u53ef\u4ee5\u5e94\u7528\u5230\u5404\u4e2a\u7ec4\u4e2d\uff0c\u4ea7\u751f\u65b0\u7684\u503c\u3002\u6700\u7ec8\uff0c\u6240\u6709\u51fd\u6570\u7684\u5e94\u7528\u7ed3\u679c\u4f1a\u8054\u5408\u4e3a\u4e00\u4e2a\u7ed3\u679c\u5bf9\u8c61\u3002 df = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a'], 'key2': ['one', 'two', 'one', 'two', 'one'], 'data1': [1, 3, 5, 7, 9], 'data2': [2, 4, 6, 8, 10] } ) \u6839\u636ekey1\u6807\u7b7e\u8ba1\u7b97data1\u5217\u7684\u5747\u503c\uff0c\u65b9\u6cd5\u4e00\uff0c\u8bbf\u95ee data1 \u5e76\u4f7f\u7528 key1 \u5217\uff08\u5b83\u662f\u4e00\u4e2aSeries\uff09\u8c03\u7528 groupby \u65b9\u6cd5\uff1a grouped = df['data1'].groupby(df['key1']) print(grouped) # grouped \u53d8\u91cf\u73b0\u5728\u662f\u4e00\u4e2a GroupBy \u5bf9\u8c61\uff0c\u5b83\u5b9e\u9645\u4e0a\u8fd8\u6ca1\u6709\u8fdb\u884c\u4efb\u4f55\u8ba1\u7b97\uff0c\u62e5\u6709\u4e00\u4e9b\u5173\u4e8e\u5206\u7ec4\u952edf['key1']\u7684\u4e00\u4e9b\u4e2d\u95f4\u6570\u636e\u7684\u4fe1\u606f\u3002 \u4e0b\u9762\u5bf9 grouped \u5bf9\u8c61\u505a\u4e00\u4e9b\u64cd\u4f5c\uff1a result = grouped.mean() # \u8ba1\u7b97\u5e73\u5747\u503c print(result) # key1 # a 4.333333 # b 6.000000 # Name: data1, dtype: float64 grouped_means = df['data1'].groupby([df['key1'], df['key2']]).mean() print(grouped_means) # key1 key2 # a one 5.0 # two 3.0 # b one 5.0 # two 7.0 # Name: data1, dtype: float64 \u4e0a\u9762\u4f8b\u5b50\u4f7f\u7528\u4e86\u4e24\u4e2a\u952e\u5bf9\u6570\u636e\u8fdb\u884c\u5206\u7ec4\uff0c\u5e76\u4e14\u7ed3\u679cSeries\u73b0\u5728\u62e5\u6709\u4e00\u4e2a\u5305\u542b\u552f\u4e00\u952e\u5bf9\u7684\u591a\u5c42\u7d22\u5f15\u3002 \u4e0b\u9762\u5bf9\u8ba1\u7b97\u7684\u5e73\u5747\u503c\uff08mean\uff09\u8fdb\u884c\u91cd\u5851\uff08unstack\uff09\u3002 print(grouped_means.unstack()) # key2 one two # key1 # a 5.0 3.0 # b 5.0 7.0 \u5206\u7ec4\u4fe1\u606f\u901a\u5e38\u5305\u542b\u5728\u540c\u4e00\u4e2aDataFrame\u4e2d\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u53ef\u4ee5\u4f20\u9012\u5217\u540d\uff08\u65e0\u8bba\u90a3\u4e9b\u5217\u540d\u662f\u5b57\u7b26\u4e32\u3001\u6570\u5b57\u6216\u5176\u4ed6Python\u5bf9\u8c61\uff09\u4f5c\u4e3a\u5206\u7ec4\u952e\uff1a \u4e0b\u9762\u4f8b\u5b50\u4e2d df.groupby('key1').mean() \u7684\u7ed3\u679c\u91cc\u5e76\u6ca1\u6709 key2 \u5217\u3002\u8fd9\u662f\u56e0\u4e3a df['key2'] \u5e76\u4e0d\u662f\u6570\u503c\u6570\u636e\uff0c\u5373 df['key2'] \u662f\u4e00\u4e2a\u5197\u4f59\u5217\uff0c\u56e0\u6b64\u88ab\u6392\u9664\u5728\u7ed3\u679c\u4e4b\u5916\u3002 result = df.groupby('key1').mean() print(result) # data1 data2 # key1 # a 4.333333 5.333333 # b 6.000000 7.000000 result = df.groupby(['key1', 'key2']).mean() print(result) # data1 data2 # key1 key2 # a one 5.0 6.0 # two 3.0 4.0 # b one 5.0 6.0 # two 7.0 8.0 result = df.groupby(['key1', 'key2']).size() print(result) # key1 key # a one 2 # two 1 # b one 1 # two 1 # dtype: int64 \u904d\u5386\u5404\u5206\u7ec4 \u00b6 GroupBy \u5bf9\u8c61\u652f\u6301\u8fed\u4ee3\uff0c\u4f1a\u751f\u6210\u4e00\u4e2a\u5305\u542b\u7ec4\u540d\u548c\u6570\u636e\u5757\u76842\u7ef4\u5143\u7ec4\u5e8f\u5217\u3002 df = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a'], 'key2': ['one', 'two', 'one', 'two', 'one'], 'data1': [1, 3, 5, 7, 9], 'data2': [2, 4, 6, 8, 10] } ) \u5355\u4e2a\u5206\u7ec4\u952e\u7684\u60c5\u51b5: for name, group in df.groupby('key1'): print(name) print(group) # a # key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10 # b # key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 \u591a\u4e2a\u5206\u7ec4\u952e\u7684\u60c5\u51b5: \u5143\u7ec4\u4e2d\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u662f\u952e\u503c\u7684\u5143\u7ec4\u3002 for (k1, k2), group in df.groupby(['key1', 'key2']): print((k1, k2)) print(group) # ('a', 'one') # key1 key2 data1 data2 # 0 a one 1 2 # 4 a one 9 10 # ('a', 'two') # key1 key2 data1 data2 # 1 a two 3 4 # ('b', 'one') # key1 key2 data1 data2 # 2 b one 5 6 # ('b', 'two') # key1 key2 data1 data2 # 3 b two 7 8 result = dict(list(df.groupby('key1'))) print(result) # df.groupby('key1')\u7684\u7ed3\u679c\u662f\u4e00\u4e2a\u5bf9\u8c61 # # list(df.groupby('key1'))\u7684\u7ed3\u679c\u662f\u5305\u542bFrameData\u7684\u7ed3\u6784\u7684\u5217\u8868list: # [ # ('a', key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10), # ('b', key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8) # ] # dict(list(df.groupby('key1')))\u7684\u7ed3\u679c\u662f\u5305\u542bFrameData\u7684\u7ed3\u6784\u7684\u5b57\u5178dict # { # 'a': key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10, # 'b': key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 # } print(result['b']) # key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c groupby \u5728 axis=0 \u7684\u8f74\u5411\u4e0a\u5206\u7ec4\uff0c\u4e5f\u53ef\u4ee5\u5728\u5176\u4ed6\u4efb\u610f\u8f74\u5411\u4e0a\u8fdb\u884c\u5206\u7ec4\u3002 print(df.dtypes) # key1 object # key2 object # data1 int64 # data2 int64 # dtype: object grouped = df.groupby(df.dtypes, axis=1) print(grouped) # print(list(grouped)) # [ # (dtype('int64'), data1 data2 # 0 1 2 # 1 3 4 # 2 5 6 # 3 7 8 # 4 9 10), # (dtype('O'), key1 key2 # 0 a one # 1 a two # 2 b one # 3 b two # 4 a one) # ] \u6253\u5370\u5404\u5206\u7ec4\u5982\u4e0b\uff1a for dtype, group in grouped: print(dtype) print(group) # int64 # data1 data2 # 0 1 2 # 1 3 4 # 2 5 6 # 3 7 8 # 4 9 10 # object # key1 key2 # 0 a one # 1 a two # 2 b one # 3 b two # 4 a one \u9009\u62e9\u4e00\u5217\u6216\u6240\u6709\u5217\u7684\u5b50\u96c6 \u00b6 \u5bf9\u4e8e\u4eceDataFrame\u521b\u5efa\u7684 GroupBy \u5bf9\u8c61\uff0c\u7528\u5217\u540d\u79f0\u6216\u5217\u540d\u79f0\u6570\u7ec4\u8fdb\u884c\u7d22\u5f15\u65f6\uff0c\u4f1a\u4ea7\u751f\u7528\u4e8e\u805a\u5408\u7684\u5217\u5b50\u96c6\u7684\u6548\u679c\u3002 \u5982\u679c\u4f20\u9012\u7684\u662f\u5217\u8868\u6216\u6570\u7ec4\uff0c\u5219\u6b64\u7d22\u5f15\u64cd\u4f5c\u8fd4\u56de\u7684\u5bf9\u8c61\u662f\u5206\u7ec4\u7684DataFrame\uff1b\u5982\u679c\u53ea\u6709\u5355\u4e2a\u5217\u540d\u4f5c\u4e3a\u6807\u91cf\u4f20\u9012\uff0c\u5219\u4e3a\u5206\u7ec4\u7684Series\uff1b \u5bf9\u6bd4\u4e0b\u97624\u53e5\uff1a result = df.groupby('key1')['data1'] # \u5355\u4e2a\u5217\u540d print(result) # for key, data in result: print(key) print(data) result = df['data1'].groupby(df['key1']) # \u5355\u4e2a\u5217\u540d print(result) # for key, data in result: print(key) print(data) # a # 0 1 # 1 3 # 4 9 # Name: data1, dtype: int64 # b # 2 5 # 3 7 # Name: data1, dtype: int64 result = df.groupby('key1')[['data1']] # \u5217\u8868\u6216\u6570\u7ec4 print(result) # for key, data in result: print(key) print(data) # a # key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10 # b # key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 result = df[['data1']].groupby(df['key1']) # \u5217\u8868\u6216\u6570\u7ec4 print(result) # for key, data in result: print(key) print(data) # a # data1 # 0 1 # 1 3 # 4 9 # b # data1 # 2 5 # 3 7 \u4f7f\u7528\u5b57\u5178\u548cSeries\u5206\u7ec4 \u00b6 \u5206\u7ec4\u4fe1\u606f\u53ef\u80fd\u4f1a\u4ee5\u975e\u6570\u7ec4\u5f62\u5f0f\u5b58\u5728\u3002 \u751f\u6210\u4e00\u4e2a\u793a\u4f8bDataFrame\u3002 people = pd.DataFrame( [[1, 3, 5, 7, 9], [0, 2, 4, 6, 8], [0, 2, 4, 6, 8], [1, 3, 5, 7, 9], [1, 2, 3, 4, 5]], columns=['a', 'b', 'c', 'd', 'e'], index=['Joe', 'Steve', 'Wes', 'Jim', 'Travis'] ) \u6dfb\u52a0\u4e00\u4e9bNA\u503c\u3002 people.iloc[2:3, [1, 2]] = np.nan print(people) # a b c d e # Joe 1 3.0 5.0 7 9 # Steve 0 2.0 4.0 6 8 # Wes 0 NaN NaN 6 8 # Jim 1 3.0 5.0 7 9 # Travis 1 2.0 3.0 4 5 \u5047\u8bbe\u6709\u5982\u4e0b\u5404\u5217\u7684\u5206\u7ec4\u5bf9\u5e94\u5173\u7cfb\uff0c\u5e76\u4e14\u60f3\u628a\u5404\u5217\u6309\u7ec4\u7d2f\u52a0\u3002 mapping = { 'a': 'red', 'b': 'red', 'c': 'blue', 'd': 'blue', 'e': 'red', 'f': 'orange' # \u6ce8\u610f\uff1a\u5065f\u867d\u7136\u6ca1\u6709\u88ab\u7528\u5230\uff0c\u4f46\u4e0d\u5f71\u54cd\u5728\u8fd9\u91cc\u5b9a\u4e49\u3002 } \u628a mapping \u8fd9\u4e2a\u5b57\u5178\u4f20\u7ed9 groupby() \u3002 by_column = people.groupby(mapping, axis=1) print(by_column.sum()) # blue red # Joe 12.0 13.0 # Steve 10.0 10.0 # Wes 6.0 8.0 # Jim 12.0 13.0 # Travis 7.0 8.0 Series\u4e5f\u6709\u76f8\u540c\u7684\u529f\u80fd\uff0c\u53ef\u4ee5\u89c6\u4e3a\u56fa\u5b9a\u5927\u5c0f\u7684\u6620\u5c04\u3002 map_services = pd.Series(mapping) print(map_services) # a red # b red # c blue # d blue # e red # f orange # dtype: object result = people.groupby(map_services, axis=1).count() print(result) # blue red # Joe 2 3 # Steve 2 3 # Wes 1 2 # Jim 2 3 # Travis 2 3 \u4f7f\u7528\u51fd\u6570\u5206\u7ec4 \u00b6 \u4e0e\u4f7f\u7528\u5b57\u5178\u6216Series\u5206\u7ec4\u76f8\u6bd4\uff0c\u4f7f\u7528Python\u51fd\u6570\u662f\u5b9a\u4e49\u5206\u7ec4\u5173\u7cfb\u7684\u4e00\u79cd\u66f4\u4e3a\u901a\u7528\u7684\u65b9\u5f0f\u3002 \u4f5c\u4e3a\u5206\u7ec4\u952e\u4f20\u9012\u7684\u51fd\u6570\u5c06\u4f1a\u6309\u7167\u6bcf\u4e2a\u7d22\u5f15\u503c\u8c03\u7528\u4e00\u6b21\uff0c\u540c\u65f6\u8fd4\u56de\u503c\u4f1a\u88ab\u7528\u4f5c\u5206\u7ec4\u540d\u79f0\u3002\u6ce8\u610f\uff1a\u51fd\u6570\u662f\u4f5c\u7528\u5728\u7d22\u5f15\u4e0a\u3002 result = people.groupby(len).sum() # \u4eba\u7684\u540d\u5b57\u662f\u7d22\u5f15\u503c\uff0c\u6839\u636e\u540d\u5b57\u7684\u957f\u5ea6\u6765\u8fdb\u884c\u5206\u7ec4 print(result) # a b c d e # 3 2 6.0 10.0 20 26 # 5 0 2.0 4.0 6 8 # 6 1 2.0 3.0 4 5 \u53ef\u4ee5\u5c06\u51fd\u6570\u4e0e\u6570\u7ec4\u3001\u5b57\u5178\u6216Series\u8fdb\u884c\u6df7\u5408\uff0c\u6240\u6709\u7684\u5bf9\u8c61\u90fd\u4f1a\u5728\u5185\u90e8\u8f6c\u6362\u4e3a\u6570\u7ec4\u3002 key_list = ['one', 'one', 'one', 'two', 'two'] result = people.groupby([len, key_list]).min() print(result) # a b c d e # 3 one 0 3.0 5.0 6 8 # two 1 3.0 5.0 7 9 # 5 one 0 2.0 4.0 6 8 # 6 two 1 2.0 3.0 4 5 \u6839\u636e\u7d22\u5f15\u5c42\u7ea7\u5206\u7ec4 \u00b6 \u6839\u636e\u5c42\u7ea7\u5206\u7ec4\u65f6\uff0c\u5c06\u5c42\u7ea7\u6570\u503c\u6216\u5c42\u7ea7\u540d\u79f0\u4f20\u9012\u7ed9 level \u5173\u952e\u5b57\u3002 columns = pd.MultiIndex.from_arrays( [['US', 'US', 'US', 'JP', 'JP'], [1, 3, 5, 1, 3]], names=['cty', 'tenor'] ) hier_df = pd.DataFrame( [[1, 3, 5, 7, 9], [0, 2, 4, 6, 8], [1, 3, 5, 7, 9], [1, 2, 3, 4, 5]], columns=columns ) print(hier_df) # cty US JP # tenor 1 3 5 1 3 # 0 1 3 5 7 9 # 1 0 2 4 6 8 # 2 1 3 5 7 9 # 3 1 2 3 4 5 result = hier_df.groupby(level='cty', axis=1).count() print(result) # cty JP US # 0 2 3 # 1 2 3 # 2 2 3 # 3 2 3 \u6570\u636e\u805a\u5408 \u00b6 \u805a\u5408\u662f\u6307\u6240\u6709\u6839\u636e\u6570\u7ec4\u4ea7\u751f\u6807\u91cf\u503c\u7684\u6570\u636e\u8f6c\u6362\u8fc7\u7a0b\uff0c\u6bd4\u5982\uff1a mean \u3001 count \u3001 min \u548c sum \u7b49\u4e00\u4e9b\u805a\u5408\u64cd\u4f5c\u3002 import pandas as pd import numpy as np \u9884\u5907\u77e5\u8bc6\uff1a \u5206\u4f4d\u6570\uff08Quantile\uff09\uff0c\u4e5f\u79f0\u5206\u4f4d\u70b9\uff0c\u662f\u6307\u5c06\u4e00\u4e2a\u968f\u673a\u53d8\u91cf\u7684\u6982\u7387\u5206\u5e03\u8303\u56f4\u5206\u4e3a\u51e0\u4e2a\u7b49\u4efd\u7684\u6570\u503c\u70b9\uff0c\u5206\u6790\u5176\u6570\u636e\u53d8\u91cf\u7684\u8d8b\u52bf\u3002 \u5e38\u7528\u7684\u5206\u4f4d\u6570\u6709 \u4e2d\u4f4d\u6570\u3001\u56db\u5206\u4f4d\u6570\u3001\u767e\u5206\u4f4d\u6570\u7b49\u3002 \u4e2d\u4f4d\u6570\uff08Medians\uff09\u662f\u4e00\u4e2a\u7edf\u8ba1\u5b66\u7684\u4e13\u6709\u540d\u8bcd\uff0c\u4ee3\u8868\u4e00\u4e2a\u6837\u672c\u3001\u79cd\u7fa4\u6216\u6982\u7387\u5206\u5e03\u4e2d\u7684\u4e00\u4e2a\u6570\u503c\uff0c\u53ef\u4ee5\u5c06\u6570\u503c\u96c6\u5408\u5212\u5206\u4e3a\u76f8\u7b49\u7684\u4e24\u90e8\u5206\u3002 \u5229\u7528pandas\u5e93\u8ba1\u7b97 data = [6, 47, 49, 15, 42, 41, 7, 39, 43, 40, 36] \u7684\u5206\u4f4d\u6570\u3002 \u786e\u5b9a p \u5206\u4f4d\u6570\u4f4d\u7f6e\u7684\u4e24\u79cd\u65b9\u6cd5( n \u4e3a\u6570\u636e\u7684\u603b\u4e2a\u6570\uff0c p \u4e3a 0-1 \u4e4b\u95f4\u7684\u503c)\u3002\u5728python\u4e2d\u8ba1\u7b97\u5206\u4f4d\u6570\u4f4d\u7f6e\u7684\u65b9\u6848\u91c7\u7528 position=1+(n-1)*p \uff1a position = (n+1)*p position = 1 + (n-1)*p \u6848\u4f8b1 data = pd.Series(np.array([6, 47, 49, 15, 42, 41, 7, 39, 43, 40, 36])) print(\"\u6570\u636e\u683c\u5f0f\uff1a\") print(np.sort(data)) # \u5fc5\u987b\u8981\u6392\u5e8f print('Q1:', data.quantile(.25)) print('Q2:', data.quantile(.5)) print('Q3:', data.quantile(.75)) # \u6570\u636e\u683c\u5f0f\uff1a # [ 6 7 15 36 39 40 41 42 43 47 49] # Q1: 25.5 # Q2: 40.0 # Q3: 42.5 # \u624b\u7b97\u8ba1\u7b97\u7ed3\u679c\uff1a # Q1\u7684p\u5206\u4f4d\u6570(0.25)\u4f4d\u7f6eposition = 1+(11-1)*0.25 = 3.5(\u53d6\u7b2c3\u4f4d) (p=0.25) Q1=15+(36-15)*0.5=25.5 (\u7b2c3\u30014\u4f4d\u7684\u5dee\u4e58\u4ee5\u4f59\u65700.5) # Q2\u7684p\u5206\u4f4d\u6570(0.5)\u4f4d\u7f6eposition = 1+(11-1)*0.5 = 6 (p=0.5) Q2=40 # Q3\u7684p\u5206\u4f4d\u6570(0.75)\u4f4d\u7f6eposition = 1+(11-1)*0.75 = 9 (p=0.75) Q3=42+(43-42)*0.5=42.5 # IQR = Q3 - Q1 = 17 \u6848\u4f8b2 df = pd.DataFrame(np.array([[1, 1], [2, 10], [3, 100], [4, 100]]), columns=['a', 'b']) print(\"\u6570\u636e\u539f\u59cb\u683c\u5f0f\uff1a\") print(df) print(\"\u8ba1\u7b97p=0.1\u65f6\uff0ca\u5217\u548cb\u5217\u7684\u5206\u4f4d\u6570\") print(df.quantile(.1)) # \u6570\u636e\u539f\u59cb\u683c\u5f0f\uff1a # a b # 0 1 1 # 1 2 10 # 2 3 100 # 3 4 100 # \u8ba1\u7b97p=0.1\u65f6\uff0ca\u5217\u548cb\u5217\u7684\u5206\u4f4d\u6570 # a 1.3 # b 3.7 # Name: 0.1, dtype: float64 # \u624b\u7b97\u8ba1\u7b97\u7ed3\u679c\uff1a # \u8ba1\u7b97a\u5217 # position=1+(4-1)*0.1=1.3 (\u53d6\u7b2c1\u4f4d) # Q1=1+(2-1)*0.3=1.3 (\u7b2c1\u30012\u4f4d\u7684\u5dee\u4e58\u4ee5\u4f59\u65700.3) # \u8ba1\u7b97b\u5217 # position=1+(4-1)*0.1=1.3 (\u53d6\u7b2c1\u4f4d) # Q1=1+(10-1)*0.3=3.7 (\u7b2c1\u30012\u4f4d\u7684\u5dee\u4e58\u4ee5\u4f59\u65700.3) \u4f18\u5316\u7684 groupby \u65b9\u6cd5\uff1a count: \u5206\u7ec4\u4e2d\u975eNA\u503c\u7684\u6570\u91cf sum: \u975eNA\u503c\u7684\u7d2f\u52a0\u548c mean: \u975eNA\u503c\u7684\u5e73\u5747\u503c median: \u975eNA\u503c\u7684\u7b97\u672f\u4e2d\u4f4d\u6570 std, var: \u65e0\u504f\u7684(n-1\u5206\u6bcd)\u6807\u51c6\u5dee\u548c\u65b9\u5dee min, max: \u975eNA\u503c\u7684\u6700\u5c0f\u503c\u3001\u6700\u5927\u503c prod: \u975eNA\u503c\u7684\u4e58\u79ef first, last: \u975eNA\u503c\u7684\u7b2c\u4e00\u4e2a\u3001\u6700\u540e\u4e00\u4e2a\u503c df = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a'], 'key2': ['one', 'two', 'one', 'two', 'one'], 'data1': [1, 3, 5, 7, 9], 'data2': [2, 4, 6, 8, 10] } ) print(df) # key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 2 b one 5 6 # 3 b two 7 8 # 4 a one 9 10 grouped = df.groupby('key1') result = grouped['data1'] for i in result: print(i) # ('a', 0 1 # 1 3 # 4 9 # Name: data1, dtype: int64) # ('b', 2 5 # 3 7 # Name: data1, dtype: int64) result = grouped['data1'].quantile(0.9) # quantile\u5206\u4f4d\u6570 print(result) # key1 # a 7.8 # b 6.8 # Name: data1, dtype: float64 # \u624b\u7b97\u8ba1\u7b97\u7ed3\u679c\uff1a # \u8ba1\u7b97a\u5217 # position=1+(3-1)*0.9=2.8 # Q1=3+(9-3)*0.8=7.8 # \u8ba1\u7b97b\u5217 # position=1+(2-1)*0.9=1.9 # Q1=5+(7-5)*0.9=6.8 \u4f7f\u7528\u81ea\u884c\u5236\u5b9a\u7684\u805a\u5408\uff0c\u5e76\u518d\u8c03\u7528\u5df2\u7ecf\u5728\u5206\u7ec4\u5bf9\u8c61\u4e0a\u5b9a\u4e49\u597d\u7684\u65b9\u6cd5\u3002 def peak_to_peak(arr): return arr.max() - arr.min() result = grouped.agg(peak_to_peak) print(result) # data1 data2 # key1 # a 8 8 # b 2 2 result = grouped.describe() print(result) # data1 ... data2 # count mean std min 25% ... min 25% 50% 75% max # key1 ... # a 3.0 4.333333 4.163332 1.0 2.0 ... 2.0 3.0 4.0 7.0 10.0 # b 2.0 6.000000 1.414214 5.0 5.5 ... 6.0 6.5 7.0 7.5 8.0 \u9010\u5217\u53ca\u591a\u51fd\u6570\u5e94\u7528 \u00b6 tips = pd.read_csv('../examples/tips.csv') tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) print(tips.head(5)) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 \u6839\u636e\u5404\u5217\u540c\u65f6\u4f7f\u7528\u591a\u4e2a\u51fd\u6570\u8fdb\u884c\u805a\u5408 grouped = tips.groupby(['day', 'smoker']) # for i in grouped: # print(i) # (('Fri', 'No'), total_bill tip smoker day time size tip_pct # 91 22.49 3.50 No Fri Dinner 2 0.184308 # ...... # 223 15.98 3.00 No Fri Lunch 3 0.231125) # (('Fri', 'Yes'), total_bill tip smoker day time size tip_pct # 90 28.97 3.00 Yes Fri Dinner 2 0.115518 # ...... # 226 10.09 2.00 Yes Fri Lunch 2 0.247219) # ...... grouped_pct = grouped['tip_pct'] for i in grouped_pct: print(i) # (('Fri', 'No'), 91 0.184308 # 94 0.166667 # ...... # Name: tip_pct, dtype: float64) # (('Fri', 'Yes'), 90 0.115518 # 92 0.210526 # ...... # Name: tip_pct, dtype: float64) # ...... \u5c06\u51fd\u6570\u540d\u4ee5\u5b57\u7b26\u4e32\u5f62\u5f0f\u4f20\u9012\u3002 result = grouped_pct.agg('mean') print(result) # day smoker # Fri No 0.179740 # Yes 0.216293 # Sat No 0.190412 # Yes 0.179833 # Sun No 0.193617 # Yes 0.322021 # Thur No 0.193424 # Yes 0.198508 # Name: tip_pct, dtype: float64 \u5982\u679c\u4f20\u9012\u7684\u662f\u51fd\u6570\u6216\u8005\u51fd\u6570\u540d\u7684\u5217\u8868\uff0c\u4f1a\u5f97\u5230\u4e00\u4e2a\u5217\u540d\u662f\u8fd9\u4e9b\u51fd\u6570\u540d\u7684DataFrame\u3002 \u4e0b\u9762\u4f20\u9012\u4e86\u805a\u5408\u51fd\u6570\u7684\u5217\u8868\u7ed9agg\u65b9\u6cd5\uff0c\u8fd9\u4e9b\u51fd\u6570\u4f1a\u5404\u81ea\u8fd0\u7528\u4e8e\u6570\u636e\u5206\u7ec4\u3002 result = grouped_pct.agg(['mean', 'std', peak_to_peak]) print(result) # mean std peak_to_peak # day smoker # Fri No 0.179740 0.039458 0.094263 # Yes 0.216293 0.077530 0.242219 # Sat No 0.190412 0.058626 0.352192 # Yes 0.179833 0.089496 0.446137 # Sun No 0.193617 0.060302 0.274897 # Yes 0.322021 0.538061 2.382107 # Thur No 0.193424 0.056065 0.284273 # Yes 0.198508 0.057170 0.219047 \u5982\u679c\u4f20\u9012\u7684\u662f (name, function) \u5143\u7ec4\u7684\u5217\u8868\uff0c\u6bcf\u4e2a\u5143\u7ec4\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5c06\u4f5c\u4e3aDataFrame\u7684\u5217\u540d\uff08\u53ef\u4ee5\u8ba4\u4e3a\u4e8c\u5143\u5143\u7ec4\u7684\u5217\u8868\u662f\u4e00\u79cd\u6709\u5e8f\u7684\u5bf9\u5e94\u5173\u7cfb\uff09\uff1a result = grouped_pct.agg([('foo', 'mean'), ('bar', np.std)]) # foo\u662fmean\u503c\u7684\u5217\u540d print(result) # foo bar # day smoker # Fri No 0.179740 0.039458 # Yes 0.216293 0.077530 # Sat No 0.190412 0.058626 # Yes 0.179833 0.089496 # Sun No 0.193617 0.060302 # Yes 0.322021 0.538061 # Thur No 0.193424 0.056065 # Yes 0.198508 0.057170 \u53ef\u4ee5\u6307\u5b9a\u5e94\u7528\u5230\u6240\u6709\u5217\u4e0a\u7684\u51fd\u6570\u5217\u8868\u6216\u6bcf\u4e00\u5217\u4e0a\u8981\u5e94\u7528\u7684\u4e0d\u540c\u51fd\u6570\u3002 \u4e0b\u9762\u4ea7\u751f\u7684DataFrame\u62e5\u6709\u5206\u5c42\u5217\uff0c\u4e0e\u5206\u522b\u805a\u5408\u6bcf\u4e00\u5217\uff0c\u518d\u4ee5\u5217\u540d\u4f5c\u4e3a keys \u53c2\u6570\u4f7f\u7528 concat \u5c06\u7ed3\u679c\u62fc\u63a5\u5728\u4e00\u8d77\u7684\u7ed3\u679c\u76f8\u540c\u3002 functions = ['count', 'mean', 'max'] result = grouped[['tip_pct', 'total_bill']].agg(functions) print(result) # tip_pct total_bill # count mean max count mean max # day smoker # Fri No 4 0.179740 0.231125 4 18.420000 22.75 # Yes 15 0.216293 0.357737 15 16.813333 40.17 # Sat No 45 0.190412 0.412409 45 19.661778 48.33 # Yes 42 0.179833 0.483092 42 21.276667 50.81 # Sun No 57 0.193617 0.338101 57 20.506667 48.17 # Yes 19 0.322021 2.452381 19 24.120000 45.35 # Thur No 45 0.193424 0.362976 45 17.113111 41.19 # Yes 17 0.198508 0.317965 17 19.190588 43.11 # \u628a['tip_pct', 'total_bill']\u6539\u6210[['tip_pct', 'total_bill']]\uff0c\u5c31\u53ef\u4ee5\u907f\u514d\u62a5\u9519 # FutureWarning: Indexing with multiple keys (implicitly converted to a tuple of keys) will be deprecated, use a list instead. # result = grouped['tip_pct', 'total_bill'].agg(functions) print(result['tip_pct']) # count mean max # day smoker # Fri No 4 0.179740 0.231125 # Yes 15 0.216293 0.357737 # Sat No 45 0.190412 0.412409 # Yes 42 0.179833 0.483092 # Sun No 57 0.193617 0.338101 # Yes 19 0.322021 2.452381 # Thur No 45 0.193424 0.362976 # Yes 17 0.198508 0.317965 \u4e5f\u540c\u6837\u53ef\u4ee5\u4f20\u9012\u5177\u6709\u81ea\u5b9a\u4e49\u540d\u79f0\u7684\u5143\u7ec4\u5217\u8868\uff1a ftuples = [('Durchschnitt', 'mean'), ('Abweichung', np.var)] result = grouped[['tip_pct', 'total_bill']].agg(ftuples) print(result) # tip_pct total_bill # Durchschnitt Abweichung Durchschnitt Abweichung # day smoker # Fri No 0.179740 0.001557 18.420000 25.596333 # Yes 0.216293 0.006011 16.813333 82.562438 # Sat No 0.190412 0.003437 19.661778 79.908965 # Yes 0.179833 0.008010 21.276667 101.387535 # Sun No 0.193617 0.003636 20.506667 66.099980 # Yes 0.322021 0.289509 24.120000 109.046044 # Thur No 0.193424 0.003143 17.113111 59.625081 # Yes 0.198508 0.003268 19.190588 69.808518 \u8981\u5c06\u4e0d\u540c\u7684\u51fd\u6570\u5e94\u7528\u5230\u4e00\u4e2a\u6216\u591a\u4e2a\u5217\u4e0a\uff0c\u9700\u8981\u5c06\u542b\u6709\u5217\u540d\u4e0e\u51fd\u6570\u5bf9\u5e94\u5173\u7cfb\u7684\u5b57\u5178\u4f20\u9012\u7ed9 agg \uff1a result = grouped.agg({'tip': np.max, 'size': 'sum'}) print(result) # tip size # day smoker # Fri No 3.50 9 # Yes 4.73 31 # Sat No 9.00 115 # Yes 10.00 104 # Sun No 6.00 167 # Yes 6.50 49 # Thur No 6.70 112 # Yes 5.00 40 result = grouped.agg({'tip_pct': ['min', 'max', 'mean', 'std']}) print(result) # tip_pct # min max mean std # day smoker # Fri No 0.136861 0.231125 0.179740 0.039458 # Yes 0.115518 0.357737 0.216293 0.077530 # Sat No 0.060217 0.412409 0.190412 0.058626 # Yes 0.036955 0.483092 0.179833 0.089496 # Sun No 0.063204 0.338101 0.193617 0.060302 # Yes 0.070274 2.452381 0.322021 0.538061 # Thur No 0.078704 0.362976 0.193424 0.056065 # Yes 0.098918 0.317965 0.198508 0.057170 \u53ea\u6709\u591a\u4e2a\u51fd\u6570\u5e94\u7528\u4e8e\u81f3\u5c11\u4e00\u4e2a\u5217\u65f6\uff0cDataFrame\u624d\u5177\u6709\u5206\u5c42\u5217\u3002 \u8fd4\u56de\u4e0d\u542b\u884c\u7d22\u5f15\u7684\u805a\u5408\u6570\u636e \u00b6 \u5728\u524d\u9762\u6240\u6709\u7684\u4f8b\u5b50\u4e2d\uff0c\u805a\u5408\u6570\u636e\u8fd4\u56de\u65f6\u90fd\u662f\u5e26\u6709\u7d22\u5f15\u7684\uff0c\u6709\u65f6\u7d22\u5f15\u662f\u5206\u5c42\u7684\uff0c\u7531\u552f\u4e00\u7684\u5206\u7ec4\u952e\u8054\u5408\u5f62\u6210\u3002 \u56e0\u4e3a\u4e0d\u662f\u6240\u6709\u7684\u60c5\u51b5\u4e0b\u90fd\u9700\u8981\u7d22\u5f15\uff0c\u6240\u4ee5\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\u53ef\u4ee5\u901a\u8fc7\u5411groupby\u4f20\u9012as_index=False\u6765\u7981\u7528\u5206\u7ec4\u952e\u4f5c\u4e3a\u7d22\u5f15\u7684\u884c\u4e3a\uff1a result = tips.groupby(['day', 'smoker'], as_index=False).mean() print(result) # day smoker total_bill tip size tip_pct # 0 Fri No 18.420000 2.812500 2.250000 0.179740 # 1 Fri Yes 16.813333 2.714000 2.066667 0.216293 # 2 Sat No 19.661778 3.102889 2.555556 0.190412 # 3 Sat Yes 21.276667 2.875476 2.476190 0.179833 # 4 Sun No 20.506667 3.167895 2.929825 0.193617 # 5 Sun Yes 24.120000 3.516842 2.578947 0.322021 # 6 Thur No 17.113111 2.673778 2.488889 0.193424 # 7 Thur Yes 19.190588 3.030000 2.352941 0.198508 \u901a\u8fc7\u5728\u7ed3\u679c\u4e0a\u8c03\u7528reset_index\u4e5f\u53ef\u4ee5\u83b7\u5f97\u540c\u6837\u7684\u7ed3\u679c\u3002\u4f7f\u7528as_index=False\u53ef\u4ee5\u907f\u514d\u4e00\u4e9b\u4e0d\u5fc5\u8981\u7684\u8ba1\u7b97\u3002 result = tips.groupby(['day', 'smoker']).mean() print(result.reset_index()) # day smoker total_bill tip size tip_pct # 0 Fri No 18.420000 2.812500 2.250000 0.179740 # 1 Fri Yes 16.813333 2.714000 2.066667 0.216293 # 2 Sat No 19.661778 3.102889 2.555556 0.190412 # 3 Sat Yes 21.276667 2.875476 2.476190 0.179833 # 4 Sun No 20.506667 3.167895 2.929825 0.193617 # 5 Sun Yes 24.120000 3.516842 2.578947 0.322021 # 6 Thur No 17.113111 2.673778 2.488889 0.193424 # 7 Thur Yes 19.190588 3.030000 2.352941 0.198508 print(result) # total_bill tip size tip_pct # day smoker # Fri No 18.420000 2.812500 2.250000 0.179740 # Yes 16.813333 2.714000 2.066667 0.216293 # Sat No 19.661778 3.102889 2.555556 0.190412 # Yes 21.276667 2.875476 2.476190 0.179833 # Sun No 20.506667 3.167895 2.929825 0.193617 # Yes 24.120000 3.516842 2.578947 0.322021 # Thur No 17.113111 2.673778 2.488889 0.193424 # Yes 19.190588 3.030000 2.352941 0.198508 \u5e94\u7528\uff1a\u901a\u7528\u62c6\u5206-\u5e94\u7528-\u8054\u5408 \u00b6 import pandas as pd import numpy as np import statsmodels.api as sm GroupBy \u65b9\u6cd5\u6700\u5e38\u89c1\u7684\u76ee\u7684\u662f apply \uff08\u5e94\u7528\uff09\u3002 apply \u5c06\u5bf9\u8c61\u62c6\u5206\u6210\u591a\u5757\uff0c\u7136\u540e\u5728\u6bcf\u4e00\u5757\u4e0a\u8c03\u7528\u4f20\u9012\u7684\u51fd\u6570\uff0c\u4e4b\u540e\u5c1d\u8bd5\u5c06\u6bcf\u4e00\u5757\u62fc\u63a5\u5230\u4e00\u8d77\u3002 \u6839\u636e\u4e0b\u9762\u7684\u5c0f\u8d39\u6570\u636e\u96c6\uff0c\u6309\u7ec4\u9009\u51fa\u5c0f\u8d39\u767e\u5206\u6bd4\uff08tip-pct\uff09\u6700\u9ad8\u7684\u4e94\u7ec4\u3002 tips = pd.read_csv('../examples/tips.csv') tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) \u6837\u672c\u6570\u636e print(tips.head(5)) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 \u9996\u5148\uff0c\u5199\u4e00\u4e2a\u53ef\u4ee5\u5728\u7279\u5b9a\u5217\u4e2d\u9009\u51fa\u6700\u5927\u503c\u6240\u5728\u884c\u7684\u51fd\u6570\uff1a \u6dfb\u52a0\u4e86\u5347\u5e8f\uff0c\u7ed3\u679c\u8f93\u51fa\u6700\u540e5\u884c\uff08\u6700\u540e\u76845\u884c\u4e5f\u662f\u6700\u5927\u76845\u4e2a tip_tcp \u8bb0\u5f55\uff09\u3002 def top(df, n=5, column='tip_pct'): return df.sort_values(by=column, ascending=True)[-n:] result = top(tips, n=6) print(result) # \u7b49\u4ef7\u65b9\u5f0f\uff1a # result = tips.sort_values('tip_pct')[-6:] # print(result) # total_bill tip smoker day time size tip_pct # 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 \u5982\u679c\u6309\u7167 smoker \u8fdb\u884c\u5206\u7ec4\uff0c\u4e4b\u540e\u8c03\u7528 apply \uff0c\u4f1a\u5f97\u5230\u4ee5\u4e0b\u7ed3\u679c\uff1a top \u51fd\u6570\u5728DataFrame\u7684\u6bcf\u4e00\u884c\u5206\u7ec4\u4e0a\u88ab\u8c03\u7528\uff0c\u4e4b\u540e\u4f7f\u7528 pandas.concat \u5c06\u51fd\u6570\u7ed3\u679c\u7c98\u8d34\u5728\u4e00\u8d77\uff0c\u5e76\u4f7f\u7528\u5206\u7ec4\u540d\u4f5c\u4e3a\u5404\u7ec4\u7684\u6807\u7b7e\u3002 \u56e0\u6b64\u7ed3\u679c\u5305\u542b\u4e00\u4e2a\u5206\u5c42\u7d22\u5f15\uff0c\u8be5\u5206\u5c42\u7d22\u5f15\u7684\u5185\u90e8\u5c42\u7ea7\u5305\u542b\u539fDataFrame\u7684\u7d22\u5f15\u503c\u3002 result = tips.groupby('smoker').apply(top) print(result) # total_bill tip smoker day time size tip_pct # smoker # No 88 24.71 5.85 No Thur Lunch 2 0.310180 # 185 20.69 5.00 No Sun Dinner 5 0.318674 # 51 10.29 2.60 No Sun Dinner 2 0.338101 # 149 7.51 2.00 No Thur Lunch 2 0.362976 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # Yes 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 \u5982\u679c\u9664\u4e86\u5411 apply \u4f20\u9012\u51fd\u6570\uff0c\u8fd8\u4f20\u9012\u5176\u4ed6\u53c2\u6570\u6216\u5173\u952e\u5b57\u7684\u8bdd\uff0c\u4f60\u53ef\u4ee5\u628a\u8fd9\u4e9b\u653e\u5728\u51fd\u6570\u540e\u8fdb\u884c\u4f20\u9012\u3002 result = tips.groupby('smoker').apply(top, n=1, column='total_bill') print(result) # \u8fd92\u884c\u90fd\u662fsmoker\u662fyes\u548cno\u65f6\u6700\u5927total_bill\u503c\u6240\u5728\u884c\u3002 # total_bill tip smoker day time size tip_pct # smoker # No 212 48.33 9.0 No Sat Dinner 4 0.228833 # Yes 170 50.81 10.0 Yes Sat Dinner 3 0.245038 \u5728 GroupBy \u5bf9\u8c61\u4e0a\u8c03\u7528 describe \u65b9\u6cd5\u3002 result = tips.groupby('smoker')['tip_pct'].describe() print(result) # count mean std ... 50% 75% max # smoker ... # No 151.0 0.192237 0.057665 ... 0.184308 0.227015 0.412409 # Yes 93.0 0.218176 0.254295 ... 0.181818 0.242326 2.452381 # [2 rows x 8 columns] print(result.unstack('smoker')) # \u7c7b\u4f3c\u4e8e\u8f6c\u7f6e # smoker # count No 151.000000 # Yes 93.000000 # mean No 0.192237 # Yes 0.218176 # std No 0.057665 # Yes 0.254295 # min No 0.060217 # Yes 0.036955 # 25% No 0.158622 # Yes 0.119534 # 50% No 0.184308 # Yes 0.181818 # 75% No 0.227015 # Yes 0.242326 # max No 0.412409 # Yes 2.452381 # dtype: float64 \u5728 GroupBy \u5bf9\u8c61\u7684\u5185\u90e8\uff0c\u5f53\u8c03\u7528\u50cf describe \u8fd9\u6837\u7684\u65b9\u6cd5\u65f6\uff0c\u5b9e\u9645\u4e0a\u662f\u4ee5\u4e0b\u4ee3\u7801\u7684\u7b80\u5199\uff1a grouped = tips.groupby(['smoker']) f = lambda x: x.describe() result = grouped.apply(f) print(result) # total_bill tip size tip_pct # smoker # No count 151.000000 151.000000 151.000000 151.000000 # mean 19.188278 2.991854 2.668874 0.192237 # std 8.255582 1.377190 1.017984 0.057665 # min 7.250000 1.000000 1.000000 0.060217 # 25% 13.325000 2.000000 2.000000 0.158622 # 50% 17.590000 2.740000 2.000000 0.184308 # 75% 22.755000 3.505000 3.000000 0.227015 # max 48.330000 9.000000 6.000000 0.412409 # Yes count 93.000000 93.000000 93.000000 93.000000 # mean 20.756344 3.008710 2.408602 0.218176 # std 9.832154 1.401468 0.810751 0.254295 # min 3.070000 1.000000 1.000000 0.036955 # 25% 13.420000 2.000000 2.000000 0.119534 # 50% 17.920000 3.000000 2.000000 0.181818 # 75% 26.860000 3.680000 3.000000 0.242326 # max 50.810000 10.000000 5.000000 2.452381 \u538b\u7f29\u5206\u7ec4\u952e \u00b6 \u5728\u524d\u9762\u7684\u4f8b\u5b50\u4e2d\u6240\u5f97\u5230\u7684\u5bf9\u8c61\uff0c\u90fd\u5177\u6709\u5206\u7ec4\u952e\u6240\u5f62\u6210\u7684\u5206\u5c42\u7d22\u5f15\u4ee5\u53ca\u6bcf\u4e2a\u539f\u59cb\u5bf9\u8c61\u7684\u7d22\u5f15\u3002 \u4e5f\u53ef\u4ee5\u901a\u8fc7\u5411 groupby \u4f20\u9012 group_keys=False \u6765\u7981\u7528\u8fd9\u4e2a\u529f\u80fd\u3002 result = tips.groupby('smoker', group_keys=True).apply(top) print(result) # total_bill tip smoker day time size tip_pct # smoker # No 88 24.71 5.85 No Thur Lunch 2 0.310180 # 185 20.69 5.00 No Sun Dinner 5 0.318674 # 51 10.29 2.60 No Sun Dinner 2 0.338101 # 149 7.51 2.00 No Thur Lunch 2 0.362976 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # Yes 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 result = tips.groupby('smoker', group_keys=False).apply(top) print(result) # total_bill tip smoker day time size tip_pct # 88 24.71 5.85 No Thur Lunch 2 0.310180 # 185 20.69 5.00 No Sun Dinner 5 0.318674 # 51 10.29 2.60 No Sun Dinner 2 0.338101 # 149 7.51 2.00 No Thur Lunch 2 0.362976 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 \u5206\u4f4d\u6570\u4e0e\u6876\u5206\u6790 \u00b6 \u7b2c8\u7ae0\u4e2d\uff0cpandas\u6709\u4e00\u4e9b\u5de5\u5177\uff0c\u5c24\u5176\u662f cut \u548c qcut \uff0c\u7528\u4e8e\u5c06\u6570\u636e\u6309\u7167\u4f60\u9009\u62e9\u7684\u7bb1\u4f4d\u6216\u6837\u672c\u5206\u4f4d\u6570\u8fdb\u884c\u5206\u6876\u3002 \u4e0e groupby \u65b9\u6cd5\u4e00\u8d77\u4f7f\u7528\u8fd9\u4e9b\u51fd\u6570\u53ef\u4ee5\u5bf9\u6570\u636e\u96c6\u66f4\u65b9\u4fbf\u5730\u8fdb\u884c\u5206\u6876\u6216\u5206\u4f4d\u5206\u6790\u3002 \u590d\u4e60\uff1a\u673a\u68b0\u5b66\u4e60\u4e2d\u7684\u5206\u7bb1\u5904\u7406\u3002 \u5728\u673a\u68b0\u5b66\u4e60\u4e2d\u7ecf\u5e38\u4f1a\u5bf9\u6570\u636e\u8fdb\u884c\u5206\u7bb1\u5904\u7406\u7684\u64cd\u4f5c\uff0c \u4e5f\u5c31\u662f\u628a\u4e00\u6bb5\u8fde\u7eed\u7684\u503c\u5207\u5206\u6210\u82e5\u5e72\u6bb5\uff0c\u6bcf\u4e00\u6bb5\u7684\u503c\u770b\u6210\u4e00\u4e2a\u5206\u7c7b\u3002\u8fd9\u4e2a\u628a\u8fde\u7eed\u503c\u8f6c\u6362\u6210\u79bb\u6563\u503c\u7684\u8fc7\u7a0b\uff0c\u6211\u4eec\u53eb\u505a\u5206\u7bb1\u5904\u7406\u3002 \u6bd4\u5982\uff0c\u628a\u5e74\u9f84\u630915\u5c81\u5212\u5206\u6210\u4e00\u7ec4\uff0c0-15\u5c81\u53eb\u505a\u5c11\u5e74\uff0c16-30\u5c81\u53eb\u505a\u9752\u5e74\uff0c31-45\u5c81\u53eb\u505a\u58ee\u5e74\u3002\u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e2d\uff0c\u6211\u4eec\u628a\u8fde\u7eed\u7684\u5e74\u9f84\u5206\u6210\u4e86\u4e09\u4e2a\u7c7b\u522b\uff0c\u201c\u5c11\u5e74\u201d\uff0c\u201c\u9752\u5e74\u201d\u548c\u201c\u58ee\u5e74\u201d\u5c31\u662f\u5404\u4e2a\u7c7b\u522b\u7684\u540d\u79f0\uff0c\u6216\u8005\u53eb\u505a\u6807\u7b7e\u3002 \u5728pandas\u4e2d\uff0c cut \u548c qcut \u51fd\u6570\u90fd\u53ef\u4ee5\u8fdb\u884c\u5206\u7bb1\u5904\u7406\u64cd\u4f5c\u3002 cut() \u6309\u7167\u53d8\u91cf\u7684\u503c\u5bf9\u53d8\u91cf\u8fdb\u884c\u5206\u5272\uff0c\u6bcf\u4e2a\u5206\u7ec4\u91cc\u6570\u636e\u7684\u4e2a\u6570\u5e76\u4e0d\u4e00\u6837\u3002 qcut() \u662f\u6309\u53d8\u91cf\u7684\u6570\u91cf\u6765\u5bf9\u53d8\u91cf\u8fdb\u884c\u5206\u5272\uff0c\u5e76\u4e14\u5c3d\u91cf\u4fdd\u8bc1\u6bcf\u4e2a\u5206\u7ec4\u91cc\u53d8\u91cf\u7684\u4e2a\u6570\u76f8\u540c\u3002 \u8003\u8651\u4e0b\u9762\u4e00\u4e2a\u7b80\u5355\u7684\u968f\u673a\u6570\u636e\u96c6\u548c\u4e00\u4e2a\u4f7f\u7528 cut \u7684\u7b49\u957f\u6876\u5206\u7c7b\uff1a df = pd.DataFrame( { 'data1': np.random.randn(1000), 'data2': np.random.randn(1000) } ) quartiles = pd.cut(df.data1, 4) # \u6309\u7167data1\u503c\u7531\u5c0f\u5230\u5927\u7684\u987a\u5e8f\u5c06\u6570\u636e\u5206\u62104\u4efd\uff0c\u5e76\u4e14\u4f7f\u6bcf\u7ec4\u503c\u7684\u8303\u56f4\u5927\u81f4\u76f8\u7b49\u3002 print(quartiles[:10]) # 0 (-0.0743, 1.729] # 1 (-0.0743, 1.729] # 2 (-0.0743, 1.729] # 3 (-0.0743, 1.729] # 4 (-1.877, -0.0743] # 5 (-0.0743, 1.729] # 6 (-0.0743, 1.729] # 7 (-0.0743, 1.729] # 8 (-1.877, -0.0743] # 9 (-0.0743, 1.729] # Name: data1, dtype: category # Categories ( # 4, # interval[float64, right]): [ # (-3.687, -1.877] < (-1.877, -0.0743] < (-0.0743, 1.729] < (1.729, 3.531] # ] \u4e0a\u9762 cut \u8fd4\u56de\u7684 Categorical \u5bf9\u8c61\u53ef\u4ee5\u76f4\u63a5\u4f20\u9012\u7ed9 groupby \u3002\u5229\u7528\u5b83\u8ba1\u7b97\u51fa data2 \u5217\u7684\u4e00\u4e2a\u7edf\u8ba1\u503c\u96c6\u5408\uff0c\u5982\u4e0b\uff1a def get_stats(group): return { 'min': group.min(), 'max': group.max(), 'count': group.count(), 'mean': group.mean() } grouped = df.data2.groupby(quartiles) for i in grouped: print(i) result = grouped.apply(get_stats).unstack() print(result) # min max count mean # data1 # (-3.145, -1.424] -1.759377 2.484321 77.0 -0.127900 # (-1.424, 0.29] -3.142344 2.830654 524.0 -0.081931 # (0.29, 2.005] -3.557136 3.261635 376.0 0.015715 # (2.005, 3.719] -2.829458 1.766352 23.0 -0.198780 \u4f7f\u7528 qcut \uff0c\u6839\u636e\u6837\u672c\u5206\u4f4d\u6570\u8ba1\u7b97\u51fa\u7b49\u5927\u5c0f\u7684\u6876\uff0c\u5c31\u662f\u7b49\u957f\u6876\u3002\u901a\u8fc7\u4f20\u9012 labels=False \u6765\u83b7\u5f97\u5206\u4f4d\u6570\u6570\u503c\u3002 grouping = pd.qcut(df.data1, 10, labels=False) grouped = df.data2.groupby(grouping) result = grouped.apply(get_stats).unstack() print(result) # min max count mean # data1 # 0 -3.678934 3.022862 100.0 0.029658 # 1 -2.319813 2.646502 100.0 0.094035 # 2 -2.873727 2.470840 100.0 0.023866 # 3 -2.196701 2.042251 100.0 0.021232 # 4 -2.154161 2.020809 100.0 0.110834 # 5 -2.723061 2.415626 100.0 0.057365 # 6 -2.291470 2.536159 100.0 0.020866 # 7 -2.064083 1.799356 100.0 -0.081025 # 8 -3.405679 1.792581 100.0 -0.009705 # 9 -2.469285 2.600849 100.0 -0.061721 \u793a\u4f8b\uff1a\u4f7f\u7528\u6307\u5b9a\u5206\u7ec4\u503c\u586b\u5145\u7f3a\u5931\u503c \u00b6 \u5728\u6e05\u9664\u7f3a\u5931\u503c\u65f6\uff0c\u6709\u65f6\u4f1a\u4f7f\u7528 dropna \u6765\u53bb\u9664\u7f3a\u5931\u503c\uff0c\u6709\u65f6\u4f7f\u7528\u4fee\u6b63\u503c\u6216\u6765\u81ea\u4e8e\u5176\u4ed6\u6570\u636e\u7684\u503c\u6765\u8f93\u5165\uff08\u586b\u5145\uff09\u5230 null \u503c\uff08 NA \uff09\u3002 fillna \u662f\u4e00\u4e2a\u53ef\u4ee5\u4f7f\u7528\u7684\u6b63\u786e\u5de5\u5177\u3002 \u4f8b\u5982\u4e0b\u9762\u4f8b\u5b50\u4e2d\u4f7f\u7528\u4f7f\u7528\u5e73\u5747\u503c\u6765\u586b\u5145NA\u503c\uff1a data = (100, 110, 120, 130, 140, 150) s = pd.Series(data) print(s) # 0 100 # 1 110 # 2 120 # 3 130 # 4 140 # 5 150 # dtype: float64 \u5c06\u6570\u636e\u4e2d\u7684\u4e00\u4e9b\u503c\u8bbe\u7f6e\u4e3a\u7f3a\u5931\u503c\uff1a s[::2] = np.nan print(s) # 0 NaN # 1 110.0 # 2 NaN # 3 130.0 # 4 NaN # 5 150.0 # dtype: float64 result = s.fillna(s.mean()) # 110, 130, 150\u7684\u5e73\u5747\u503c\u662f130 print(result) # 0 130.0 # 1 110.0 # 2 130.0 # 3 130.0 # 4 130.0 # 5 150.0 # dtype: float64 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u6309\u7ec4\u586b\u5145NA\u503c\uff1a \u65b9\u6cd51,\u5bf9\u6570\u636e\u5206\u7ec4\u540e\u4f7f\u7528 apply \u3002 \u65b9\u6cd52,\u5728\u6bcf\u4e2a\u6570\u636e\u5757\u4e0a\u90fd\u8c03\u7528 fillna \u7684\u51fd\u6570\u3002 data = (100, 110, 120, 130, 140, 150, 160, 170) states = ['Ohio', 'New York', 'Vermont', 'Florida', 'Oregon', 'Nevada', 'California', 'Idaho'] group_key = ['East'] * 4 + ['West'] * 4 # 4\u4e2aEast\u548c4\u4e2aWest\u62fc\u63a5\u7684\u5217\u8868list s = pd.Series(data, index=states) print(s) # Ohio 100 # New York 110 # Vermont 120 # Florida 130 # Oregon 140 # Nevada 150 # California 160 # Idaho 170 # dtype: int64 \u5c06\u6570\u636e\u4e2d\u7684\u4e00\u4e9b\u503c\u8bbe\u7f6e\u4e3a\u7f3a\u5931\u503c\uff1a s[['Vermont', 'Nevada', 'Idaho']] = np.nan print(s) # Ohio 100.0 # New York 110.0 # Vermont NaN # Florida 130.0 # Oregon 140.0 # Nevada NaN # California 160.0 # Idaho NaN # dtype: float64 result = s.groupby(group_key).mean() print(result) # East 113.333333 # West 150.000000 # dtype: float64 \u7528\u4e0a\u9762\u5f97\u51fa\u7684\u5206\u7ec4\u5e73\u5747\u503c\u6765\u586b\u5145NA\u3002 fill_mean = lambda g: g.fillna(g.mean()) result = s.groupby(group_key).apply(fill_mean) print(result) # Ohio 100.000000 # New York 110.000000 # Vermont 113.333333 # Florida 130.000000 # Oregon 140.000000 # Nevada 150.000000 # California 160.000000 # Idaho 150.000000 # dtype: float64 \u5982\u679c\u5df2\u7ecf\u5728\u4ee3\u7801\u4e2d\u4e3a\u6bcf\u4e2a\u5206\u7ec4\u9884\u5b9a\u4e49\u4e86\u586b\u5145\u503c\uff0c\u53ef\u4ee5\u5229\u7528\u6bcf\u4e2a\u5206\u7ec4\u90fd\u6709\u7684\u5185\u7f6e\u7684 name \u5c5e\u6027\uff0c\u5b9e\u73b0\u586b\u5145 NA \u3002 fill_value = {'East': 0.5, 'West': -1} fill_func = lambda g: g.fillna(fill_value[g.name]) result = s.groupby(group_key).apply(fill_func) print(result) # Ohio 100.0 # New York 110.0 # Vermont 0.5 # Florida 130.0 # Oregon 140.0 # Nevada -1.0 # California 160.0 # Idaho -1.0 # dtype: float64 \u793a\u4f8b\uff1a\u968f\u673a\u91c7\u6837\u4e0e\u6392\u5217 \u00b6 \u5047\u8bbe\u60f3\u4ece\u5927\u6570\u636e\u96c6\u4e2d\u62bd\u53d6\u968f\u673a\u6837\u672c\uff08\u6709\u6216\u6ca1\u6709\u66ff\u6362\uff09\u4ee5\u7528\u4e8e\u8499\u7279\u5361\u7f57\u6a21\u62df\u76ee\u7684\u6216\u67d0\u4e9b\u5176\u4ed6\u5e94\u7528\u7a0b\u5e8f\u3002 \u6709\u5f88\u591a\u65b9\u6cd5\u6765\u6267\u884c\u201c\u62bd\u53d6\u201d\uff0c\u8fd9\u91cc\u4f7f\u7528Series\u7684sample\u65b9\u6cd5\u3002 \u4e3a\u4e86\u6f14\u793a\uff0c\u8fd9\u91cc\u4ecb\u7ecd\u4e00\u79cd\u6784\u9020\u4e00\u526f\u82f1\u5f0f\u6251\u514b\u724c\u7684\u65b9\u6cd5\uff1a # \u6885\u82b1clubs\u3001\u65b9\u5757diamonds\u3001\u7ea2\u6843hearts\u3001\u9ed1\u6843spades\u3002 suits = ['H', 'S', 'C', 'D'] card_val = (list(range(1, 11)) + [10] * 3) * 4 # card_val [ # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10 # ] base_names = ['A'] + list(range(2, 11)) + ['J', 'K', 'Q'] # base_names\uff1a ['A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'K', 'Q'] \u751f\u6210\u4e86\u4e00\u4e2a\u957f\u5ea6\u4e3a 52 \u7684Series, Series\u7684\u7d22\u5f15\u5305\u542b\u4e86\u724c\u540d\uff0cSeries\u7684\u503c\u53ef\u4ee5\u7528\u6e38\u620f\uff08\u4e3a\u4e86\u4fdd\u6301\u7b80\u5355\uff0c\u8ba9\u2019A\u2019\u4e3a1 \uff09\uff1a cards = [] for suit in ['H', 'S', 'C', 'D']: cards.extend(str(num) + suit for num in base_names) deck = pd.Series(card_val, index=cards) print(deck) # AH 1 # 2H 2 # 3H 3 # 4H 4 # 5H 5 # 6H 6 # 7H 7 # 8H 8 # 9H 9 # 10H 10 # JH 10 # KH 10 # QH 10 # AS 1 # 2S 2 # 3S 3 # 4S 4 # 5S 5 # 6S 6 # 7S 7 # 8S 8 # 9S 9 # 10S 10 # JS 10 # KS 10 # QS 10 # AC 1 # 2C 2 # 3C 3 # 4C 4 # 5C 5 # 6C 6 # 7C 7 # 8C 8 # 9C 9 # 10C 10 # JC 10 # KC 10 # QC 10 # AD 1 # 2D 2 # 3D 3 # 4D 4 # 5D 5 # 6D 6 # 7D 7 # 8D 8 # 9D 9 # 10D 10 # JD 10 # KD 10 # QD 10 # dtype: int64 \u4ece\u8fd9\u526f\u724c\u4e2d\u62ff\u51fa\u4e94\u5f20\u724c\u53ef\u4ee5\u5199\u6210\uff1a def draw(_deck, n=5): return _deck.sample(n) print(draw(deck)) # KD 10 # 2S 2 # 5C 5 # 6C 6 # QD 10 # dtype: int64 \u5047\u8bbe\u8981\u4ece\u6bcf\u4e2a\u82b1\u8272\u4e2d\u968f\u673a\u62bd\u53d6\u4e24\u5f20\u724c\u3002\u7531\u4e8e\u82b1\u8272\u662f\u724c\u540d\u7684\u6700\u540e\u4e24\u4e2a\u5b57\u7b26\uff0c\u53ef\u4ee5\u57fa\u4e8e\u8fd9\u70b9\u8fdb\u884c\u5206\u7ec4\uff0c\u5e76\u4f7f\u7528 apply \uff1a get_suit = lambda card: card[-1] # \u6700\u540e\u4e00\u4e2a\u5b57\u6bcd\u662f\u82b1\u8272 result = deck.groupby(get_suit).apply(draw, n=2) print(result) # C 10C 10 # 3C 3 # D KD 10 # AD 1 # H 5H 5 # 7H 7 # S 3S 3 # 5S 5 # dtype: int64 \u6216\u8005\u4e5f\u53ef\u4ee5\u5199\u6210\uff1a result = deck.groupby(get_suit, group_keys=False).apply(draw, n=2) print(result) # JC 10 # 8C 8 # QD 10 # 4D 4 # 10H 10 # 6H 6 # 7S 7 # KS 10 # dtype: int64 \u793a\u4f8b\uff1a\u5206\u7ec4\u52a0\u6743\u5e73\u5747\u548c\u76f8\u5173\u6027 \u00b6 \u5728 groupby \u7684\u62c6\u5206-\u5e94\u7528-\u8054\u5408\u7684\u8303\u5f0f\u4e0b\uff0cDataFrame\u7684\u5217\u95f4\u64cd\u4f5c\u6216\u4e24\u4e2aSeriese\u4e4b\u95f4\u7684\u64cd\u4f5c\uff0c\u4f8b\u5982\u5b9e\u73b0\u5206\u7ec4\u52a0\u6743\u5e73\u5747\u3002 \u4e0b\u9762\u4f8b\u5b50\uff0c\u4f7f\u7528\u4e00\u4e2a\u5305\u542b\u5206\u7ec4\u952e\u548c\u6743\u91cd\u503c\u7684\u6570\u636e\u96c6\uff1a dt = np.random.randn(8) wt = np.random.randn(8) df = pd.DataFrame( { 'category': ['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b'], 'data': dt, 'weight': wt } ) print(df) # category data weight # 0 a -0.250764 -0.085285 # 1 a 0.167155 -1.361254 # 2 a 0.399306 1.755542 # 3 a -0.514477 0.270124 # 4 b -0.005558 0.886514 # 5 b 0.607596 -1.384315 # 6 b -1.029627 -0.845340 # 7 b -0.294204 1.253965 \u901a\u8fc7 category \u8fdb\u884c\u5206\u7ec4\u52a0\u6743\u5e73\u5747\u5982\u4e0b\uff1a grouped = df.groupby('category') get_wavg = lambda g: np.average(g['data'], weights=g['weight']) result = grouped.apply(get_wavg) print(result) # category # a 0.614499 # b 3.863947 # dtype: float64 \u53e6\u4e00\u4e2a\u4f8b\u5b50\uff0c\u4e00\u4e2a\u4ece\u96c5\u864e\u8d22\u7ecf\u4e0a\u83b7\u5f97\u7684\u6570\u636e\u96c6\uff0c\u8be5\u6570\u636e\u96c6\u5305\u542b\u4e00\u4e9b\u6807\u666e500 \uff08SPX\u7b26\u53f7\uff09\u548c\u80a1\u7968\u7684\u6536\u76d8\u4ef7\uff1a close_px = pd.read_csv('../examples/stock_px_2.csv', parse_dates=True, index_col=0) print(close_px.info()) # # DatetimeIndex: 2214 entries, 2003-01-02 to 2011-10-14 # Data columns (total 4 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 AAPL 2214 non-null float64 # 1 MSFT 2214 non-null float64 # 2 XOM 2214 non-null float64 # 3 SPX 2214 non-null float64 # dtypes: float64(4) # memory usage: 86.5 KB # None print(close_px[-4:]) # AAPL MSFT XOM SPX # 2011-10-11 400.29 27.00 76.27 1195.54 # 2011-10-12 402.19 26.96 77.16 1207.25 # 2011-10-13 408.43 27.18 76.37 1203.66 # 2011-10-14 422.00 27.27 78.11 1224.58 \u76ee\u6807\u4efb\u52a1\uff1a\u8ba1\u7b97\u4e00\u4e2aDataFrame\uff0c\u5b83\u5305\u542b\u6807\u666e\u6307\u6570\uff08SPX\uff09\u6bcf\u65e5\u6536\u76ca\u7684\u5e74\u5ea6\u76f8\u5173\u6027\uff08\u901a\u8fc7\u767e\u5206\u6bd4\u53d8\u5316\u8ba1\u7b97\uff09\u3002 \u9996\u5148\u521b\u5efa\u4e00\u4e2a\u8ba1\u7b97\u6bcf\u5217\u4e0e\u2019SPX\u2019\u5217\u6210\u5bf9\u5173\u8054\u7684\u51fd\u6570\uff1a spx_corr = lambda x: x.corrwith(x['SPX']) \u4e4b\u540e\uff0c\u4f7f\u7528 pct_change \u8ba1\u7b97 close-px \u767e\u5206\u6bd4\u7684\u53d8\u5316\uff1a rets = close_px.pct_change().dropna() # Percentage change between the current and a prior element. print(rets) # AAPL MSFT XOM SPX # 2003-01-03 0.006757 0.001421 0.000684 -0.000484 # 2003-01-06 0.000000 0.017975 0.024624 0.022474 # ... ... ... ... ... # 2011-10-14 0.033225 0.003311 0.022784 0.017380 # [2213 rows x 4 columns] \u6700\u540e\uff0c\u6309\u5e74\u5bf9\u767e\u5206\u6bd4\u53d8\u5316\u8fdb\u884c\u5206\u7ec4\uff0c\u53ef\u4ee5\u4f7f\u7528\u5355\u884c\u51fd\u6570\u4ece\u6bcf\u4e2a\u884c\u6807\u7b7e\u4e2d\u63d0\u53d6\u6bcf\u4e2a datetime \u6807\u7b7e\u7684 year \u5c5e\u6027\uff1a get_year = lambda x: x.year by_year = rets.groupby(get_year) result = by_year.apply(spx_corr) print(result) # AAPL MSFT XOM SPX # 2003 0.541124 0.745174 0.661265 1.0 # 2004 0.374283 0.588531 0.557742 1.0 # 2005 0.467540 0.562374 0.631010 1.0 # 2006 0.428267 0.406126 0.518514 1.0 # 2007 0.508118 0.658770 0.786264 1.0 # 2008 0.681434 0.804626 0.828303 1.0 # 2009 0.707103 0.654902 0.797921 1.0 # 2010 0.710105 0.730118 0.839057 1.0 # 2011 0.691931 0.800996 0.859975 1.0 \u53ef\u4ee5\u8ba1\u7b97\u5185\u90e8\u5217\u76f8\u5173\u6027\u3002\u8fd9\u91cc\u8ba1\u7b97\u4e86\u82f9\u679c\u548c\u5fae\u8f6f\u7684\u5e74\u5ea6\u76f8\u5173\u6027\uff1a result = by_year.apply(lambda g: g['AAPL'].corr(g['MSFT'])) print(result) # 2003 0.480868 # 2004 0.259024 # 2005 0.300093 # 2006 0.161735 # 2007 0.417738 # 2008 0.611901 # 2009 0.432738 # 2010 0.571946 # 2011 0.581987 # dtype: float64 \u793a\u4f8b\uff1a\u9010\u7ec4\u7ebf\u6027\u56de\u5f52 \u00b6 \u5b9a\u4e49\u4ee5\u4e0b regress \uff08\u56de\u5f52\uff09\u51fd\u6570\uff08\u4f7f\u7528 statsmodels \u8ba1\u91cf\u7ecf\u6d4e\u5b66\u5e93\uff09\uff0c\u8be5\u51fd\u6570\u5bf9\u6bcf\u4e2a\u6570\u636e\u5757\u6267\u884c\u666e\u901a\u6700\u5c0f\u4e8c\u4e58\uff08OLS\uff09\u56de\u5f52\uff1a def regress(data, yvar, xvars): Y = data[yvar] X = data[xvars] X['intercept'] = 1. result = sm.OLS(Y, X).fit() return result.params \u73b0\u5728\u8981\u8ba1\u7b97AAPL\u5728SPX\u56de\u62a5\u4e0a\u7684\u5e74\u5ea6\u7ebf\u6027\u56de\u5f52\uff1a result = by_year.apply(regress, 'AAPL', ['SPX']) print(result) # SPX intercept # 2003 1.195406 0.000710 # 2004 1.363463 0.004201 # 2005 1.766415 0.003246 # 2006 1.645496 0.000080 # 2007 1.198761 0.003438 # 2008 0.968016 -0.001110 # 2009 0.879103 0.002954 # 2010 1.052608 0.001261 # 2011 0.806605 0.001514 \u6570\u636e\u900f\u89c6\u8868\u4e0e\u4ea4\u53c9\u8868 \u00b6 \u6570\u636e\u900f\u89c6\u8868 \u00b6 \u6570\u636e\u900f\u89c6\u8868\u662f\u7535\u5b50\u8868\u683c\u7a0b\u5e8f\u548c\u5176\u4ed6\u6570\u636e\u5206\u6790\u8f6f\u4ef6\u4e2d\u5e38\u89c1\u7684\u6570\u636e\u6c47\u603b\u5de5\u5177\u3002 \u5b83\u6839\u636e\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u805a\u5408\u4e00\u5f20\u8868\u7684\u6570\u636e\uff0c\u5c06\u6570\u636e\u5728\u77e9\u5f62\u683c\u5f0f\u4e2d\u6392\u5217\uff0c\u5176\u4e2d\u4e00\u4e9b\u5206\u7ec4\u952e\u662f\u6cbf\u7740\u884c\u7684\uff0c\u53e6\u4e00\u4e9b\u662f\u6cbf\u7740\u5217\u7684\u3002 Python\u4e2d\u7684pandas\u900f\u89c6\u8868\u662f\u901a\u8fc7\u8fd9\u91cc\u6240\u4ecb\u7ecd\u7684groupby\u5de5\u5177\u4ee5\u53ca\u4f7f\u7528\u5206\u5c42\u7d22\u5f15\u7684\u91cd\u5851\u64cd\u4f5c\u5b9e\u73b0\u7684\u3002 DataFrame\u62e5\u6709\u4e00\u4e2a pivot_table \u65b9\u6cd5\uff0c\u5e76\u4e14\u8fd8\u6709\u8fd8\u4e00\u4e2a\u9876\u5c42\u7684 pandas.pivot_table \u51fd\u6570\u3002 \u9664\u4e86\u4e3a groupby \u63d0\u4f9b\u4e00\u4e2a\u65b9\u4fbf\u63a5\u53e3\uff0c pivot_table \u8fd8\u53ef\u4ee5\u6dfb\u52a0\u90e8\u5206\u603b\u8ba1\uff0c\u4e5f\u79f0\u4f5c\u8fb9\u8ddd\u3002 import pandas as pd import numpy as np \u6839\u636e\u4e0b\u9762\u7684\u5c0f\u8d39\u6570\u636e\u96c6\uff0c\u8ba1\u7b97\u4e00\u5f20\u5728\u884c\u65b9\u5411\u4e0a\u6309 day \u548c smoker \u6392\u5217\u7684\u5206\u7ec4\u5e73\u5747\u503c\uff08\u9ed8\u8ba4\u7684 pivot_table \u805a\u5408\u7c7b\u578b\uff09\u7684\u8868\u3002 pivot_table \u9009\u9879\uff1a values: \u9700\u8981\u805a\u5408\u7684\u5217\u540d\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u805a\u5408\u6240\u6709\u6570\u503c\u578b\u7684\u5217\u3002 index: \u5728\u7ed3\u679c\u900f\u89c6\u8868\u7684\u884c\u4e0a\u8fdb\u884c\u5206\u7ec4\u7684\u5217\u540d\u6216\u8005\u5176\u4ed6\u5206\u7ec4\u952e\u3002 tips = pd.read_csv('../examples/tips.csv') tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) \u6837\u672c\u6570\u636e\u3002 print(tips.head(5)) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 \u8ba1\u7b97\u5728\u884c\u65b9\u5411\u4e0a\u6309 day \u548c smoker \u6392\u5217\u7684\u5206\u7ec4\u5e73\u5747\u503c\u3002\u4e5f\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528 groupby \u5b9e\u73b0\u3002 result = tips.pivot_table(index=['day', 'smoker']) print(result) # size tip tip_pct total_bill # day smoker # Fri No 2.250000 2.812500 0.179740 18.420000 # Yes 2.066667 2.714000 0.216293 16.813333 # Sat No 2.555556 3.102889 0.190412 19.661778 # Yes 2.476190 2.875476 0.179833 21.276667 # Sun No 2.929825 3.167895 0.193617 20.506667 # Yes 2.578947 3.516842 0.322021 24.120000 # Thur No 2.488889 2.673778 0.193424 17.113111 # Yes 2.352941 3.030000 0.198508 19.190588 \u5728 tip_pct \u548c size \u4e0a\u8fdb\u884c\u805a\u5408\uff0c\u5e76\u6839\u636e time \u5206\u7ec4\u3002\u5c06\u628a smoker \u653e\u5165\u8868\u7684\u5217\uff0c\u800c\u5c06 day \u653e\u5165\u8868\u7684\u884c\uff1a result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker' ) print(result) # size tip_pct # smoker No Yes No Yes # time day # Dinner Fri 2.000000 2.222222 0.162612 0.202545 # Sat 2.555556 2.476190 0.190412 0.179833 # Sun 2.929825 2.578947 0.193617 0.322021 # Thur 2.000000 NaN 0.190114 NaN # Lunch Fri 3.000000 1.833333 0.231125 0.236915 # Thur 2.500000 2.352941 0.193499 0.198508 \u901a\u8fc7\u4f20\u9012 margins=True \u6765\u6269\u5145\u8fd9\u4e2a\u8868\u6765\u5305\u542b\u90e8\u5206\u603b\u8ba1\u3002\u8fd9\u4f1a\u6dfb\u52a0 All \u884c\u548c\u5217\u6807\u7b7e\uff0c\u5176\u4e2d\u76f8\u5e94\u7684\u503c\u662f\u5355\u5c42\u4e2d\u6240\u6709\u6570\u636e\u7684\u5206\u7ec4\u7edf\u8ba1\u503c\u3002 \u8fd9\u91cc All \u7684\u503c\u662f\u5747\u503c\uff0c\u4e14\u8be5\u5747\u503c\u662f\u4e0d\u8003\u8651\u5438\u70df\u8005\u4e0e\u975e\u5438\u70df\u8005\uff08 All \u5217\uff09\u6216\u884c\u5206\u7ec4\u4e2d\u4efb\u4f55\u4e24\u7ea7\u7684\uff08 All \u884c\uff09\u3002 result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker', margins=True ) print(result) # size tip_pct # smoker No Yes All No Yes All # time day # Dinner Fri 2.000000 2.222222 2.166667 0.162612 0.202545 0.192562 # Sat 2.555556 2.476190 2.517241 0.190412 0.179833 0.185305 # Sun 2.929825 2.578947 2.842105 0.193617 0.322021 0.225718 # Thur 2.000000 NaN 2.000000 0.190114 NaN 0.190114 # Lunch Fri 3.000000 1.833333 2.000000 0.231125 0.236915 0.236088 # Thur 2.500000 2.352941 2.459016 0.193499 0.198508 0.194895 # All 2.668874 2.408602 2.569672 0.192237 0.218176 0.202123 \u8981\u4f7f\u7528\u4e0d\u540c\u7684\u805a\u5408\u51fd\u6570\u65f6\uff0c\u5c06\u51fd\u6570\u4f20\u9012\u7ed9 aggfunc \u3002\u4f8b\u5982\uff0c count \u6216\u8005 len \u5c06\u7ed9\u51fa\u4e00\u5f20\u5206\u7ec4\u5927\u5c0f\u7684\u4ea4\u53c9\u8868\uff08\u8ba1\u6570\u6216\u51fa\u73b0\u9891\u7387\uff09\uff1a result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker', aggfunc=len, margins=True ) print(result) # size tip_pct # smoker No Yes All No Yes All # time day # Dinner Fri 3.0 9.0 12 3.0 9.0 12 # Sat 45.0 42.0 87 45.0 42.0 87 # Sun 57.0 19.0 76 57.0 19.0 76 # Thur 1.0 NaN 1 1.0 NaN 1 # Lunch Fri 1.0 6.0 7 1.0 6.0 7 # Thur 44.0 17.0 61 44.0 17.0 61 # All 151.0 93.0 244 151.0 93.0 244 \u5bf9\u4e8e\u7a7a\u503c NA \uff0c\u4f20\u9012\u4e00\u4e2a fill_value \u3002 result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker', aggfunc='mean', fill_value=0, margins=True ) print(result) # size tip_pct # smoker No Yes All No Yes All # time day # Dinner Fri 2.000000 2.222222 2.166667 0.162612 0.202545 0.192562 # Sat 2.555556 2.476190 2.517241 0.190412 0.179833 0.185305 # Sun 2.929825 2.578947 2.842105 0.193617 0.322021 0.225718 # Thur 2.000000 0.000000 2.000000 0.190114 0.000000 0.190114 # Lunch Fri 3.000000 1.833333 2.000000 0.231125 0.236915 0.236088 # Thur 2.500000 2.352941 2.459016 0.193499 0.198508 0.194895 # All 2.668874 2.408602 2.569672 0.192237 0.218176 0.202123 \u4ea4\u53c9\u8868\uff1acrosstab \u00b6 \u4ea4\u53c9\u8868\uff08\u7b80\u5199\u4e3acrosstab\uff09\u662f\u6570\u636e\u900f\u89c6\u8868\u7684\u4e00\u4e2a\u7279\u6b8a\u60c5\u51b5\uff0c\u8ba1\u7b97\u7684\u662f\u5206\u7ec4\u4e2d\u7684\u9891\u7387\u3002 crosstab \u7684\u524d\u4e24\u4e2a\u53c2\u6570\u53ef\u662f\u6570\u7ec4\u3001Series\u6216\u6570\u7ec4\u7684\u5217\u8868\u3002 sample = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] nationality = ['USA', 'Japan', 'USA', 'Japan', 'Japan', 'Japan', 'USA', 'USA', 'Japan', 'USA'] handedness = ['Right-handed', 'Left-handed', 'Right-handed', 'Right-handed', 'Left-handed', 'Right-handed', 'Right-handed', 'Left-handed', 'Right-handed', 'Right-handed'] df = pd.DataFrame( { 'sample': sample, 'nationality': nationality, 'handedness': handedness } ) print(df) # sample nationality handedness # 0 1 USA Right-handed # 1 2 Japan Left-handed # 2 3 USA Right-handed # 3 4 Japan Right-handed # 4 5 Japan Left-handed # 5 6 Japan Right-handed # 6 7 USA Right-handed # 7 8 USA Left-handed # 8 9 Japan Right-handed # 9 10 USA Right-handed \u6309\u7167\u56fd\u7c4d\u548c\u60ef\u7528\u6027\u6765\u603b\u7ed3\u8fd9\u4e9b\u6570\u636e\uff0c\u53ef\u4ee5\u4f7f\u7528 pivot_table \u6765\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\uff0c\u4f46\u662f pandas.crosstable \u51fd\u6570\u66f4\u4e3a\u65b9\u4fbf\uff1a result = pd.crosstab(df.nationality, df.handedness, margins=True) print(result) # handedness Left-handed Right-handed All # nationality # Japan 2 3 5 # USA 1 4 5 # All 3 7 10 \u5728\u5c0f\u8d39\u6570\u636e\u4e2d\u53ef\u4ee5\u8fd9\u4e48\u505a\uff1a result = pd.crosstab(['tips.time', tips.day], tips.smoker, margins=True) print(result) # smoker No Yes All # row_0 day # tips.time Fri 4 15 19 # Sat 45 42 87 # Sun 57 19 76 # Thur 45 17 62 # All 151 93 244","title":"\u6570\u636e\u805a\u5408\u4e0e\u5206\u7ec4\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch07/#_1","text":"","title":"\u6570\u636e\u805a\u5408\u4e0e\u5206\u7ec4\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch07/#groupby","text":"import pandas as pd import numpy as np","title":"GroupBy\u673a\u5236"},{"location":"python/DataAnalysis/ch07/#_2","text":"\u5206\u7ec4\u64cd\u4f5c\u7b2c\u4e00\u6b65\uff0c\u6570\u636e\u5305\u542b\u5728pandas\u5bf9\u8c61\u4e2d\uff0c\u53ef\u4ee5\u662fSeries\u3001DataFrame\u6216\u5176\u4ed6\u6570\u636e\u7ed3\u6784\u3002\u4e4b\u540e\u6839\u636e\u63d0\u4f9b\u7684\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u5206\u79bb\u5230\u5404\u4e2a\u7ec4\u4e2d\u3002 \u5206\u7ec4\u952e\u53ef\u662f\u591a\u79cd\u5f62\u5f0f\u7684\uff0c\u5e76\u4e14\u952e\u4e0d\u4e00\u5b9a\u662f\u5b8c\u5168\u76f8\u540c\u7684\u7c7b\u578b(\u6ce8\u610f\u540e\u9762\u4ecb\u7ecd\u7684\u4e09\u4e2a\u65b9\u6cd5\u662f\u53ef\u4ee5\u4ea7\u751f\u7528\u4e8e\u5206\u9694\u5bf9\u8c61\u7684\u503c\u6570\u7ec4\u7684\u5feb\u6377\u65b9\u5f0f)\uff1a \u4e0e\u9700\u8981\u5206\u7ec4\u7684\u8f74\u5411\u957f\u5ea6\u4e00\u81f4\u7684\u503c\u5217\u8868\u6216\u503c\u6570\u7ec4\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cgroupby\u5728axis=0\u7684\u8f74\u5411\u4e0a\u5206\u7ec4\u3002 DataFrame\u7684\u5217\u540d\u7684\u503c\u3002 \u53ef\u4ee5\u5c06\u5206\u7ec4\u8f74\u5411\u4e0a\u7684\u503c\u548c\u5206\u7ec4\u540d\u79f0\u76f8\u5339\u914d\u7684\u5b57\u5178\u6216Series\u3002 \u53ef\u4ee5\u5728\u8f74\u7d22\u5f15\u6216\u7d22\u5f15\u4e2d\u7684\u5355\u4e2a\u6807\u7b7e\u4e0a\u8c03\u7528\u7684\u51fd\u6570\u3002 \u8bf7\u6ce8\u610f\uff0c\u5206\u7ec4\u952e\u4e2d\u7684\u4efb\u4f55\u7f3a\u5931\u503c\u5c06\u88ab\u6392\u9664\u5728\u7ed3\u679c\u4e4b\u5916\u3002 \u5206\u79bb\u64cd\u4f5c\u662f\u5728\u6570\u636e\u5bf9\u8c61\u7684\u7279\u5b9a\u8f74\u5411\u4e0a\u8fdb\u884c\u7684\u3002\u4f8b\u5982\uff0cDataFrame\u53ef\u4ee5\u5728\u5b83\u7684\u884c\u65b9\u5411\uff08axis=0\uff09\u6216\u5217\u65b9\u5411\uff08axis=1\uff09\u8fdb\u884c\u5206\u7ec4\u3002 \u5206\u7ec4\u64cd\u4f5c\u540e\uff0c\u4e00\u4e2a\u51fd\u6570\u5c31\u53ef\u4ee5\u5e94\u7528\u5230\u5404\u4e2a\u7ec4\u4e2d\uff0c\u4ea7\u751f\u65b0\u7684\u503c\u3002\u6700\u7ec8\uff0c\u6240\u6709\u51fd\u6570\u7684\u5e94\u7528\u7ed3\u679c\u4f1a\u8054\u5408\u4e3a\u4e00\u4e2a\u7ed3\u679c\u5bf9\u8c61\u3002 df = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a'], 'key2': ['one', 'two', 'one', 'two', 'one'], 'data1': [1, 3, 5, 7, 9], 'data2': [2, 4, 6, 8, 10] } ) \u6839\u636ekey1\u6807\u7b7e\u8ba1\u7b97data1\u5217\u7684\u5747\u503c\uff0c\u65b9\u6cd5\u4e00\uff0c\u8bbf\u95ee data1 \u5e76\u4f7f\u7528 key1 \u5217\uff08\u5b83\u662f\u4e00\u4e2aSeries\uff09\u8c03\u7528 groupby \u65b9\u6cd5\uff1a grouped = df['data1'].groupby(df['key1']) print(grouped) # grouped \u53d8\u91cf\u73b0\u5728\u662f\u4e00\u4e2a GroupBy \u5bf9\u8c61\uff0c\u5b83\u5b9e\u9645\u4e0a\u8fd8\u6ca1\u6709\u8fdb\u884c\u4efb\u4f55\u8ba1\u7b97\uff0c\u62e5\u6709\u4e00\u4e9b\u5173\u4e8e\u5206\u7ec4\u952edf['key1']\u7684\u4e00\u4e9b\u4e2d\u95f4\u6570\u636e\u7684\u4fe1\u606f\u3002 \u4e0b\u9762\u5bf9 grouped \u5bf9\u8c61\u505a\u4e00\u4e9b\u64cd\u4f5c\uff1a result = grouped.mean() # \u8ba1\u7b97\u5e73\u5747\u503c print(result) # key1 # a 4.333333 # b 6.000000 # Name: data1, dtype: float64 grouped_means = df['data1'].groupby([df['key1'], df['key2']]).mean() print(grouped_means) # key1 key2 # a one 5.0 # two 3.0 # b one 5.0 # two 7.0 # Name: data1, dtype: float64 \u4e0a\u9762\u4f8b\u5b50\u4f7f\u7528\u4e86\u4e24\u4e2a\u952e\u5bf9\u6570\u636e\u8fdb\u884c\u5206\u7ec4\uff0c\u5e76\u4e14\u7ed3\u679cSeries\u73b0\u5728\u62e5\u6709\u4e00\u4e2a\u5305\u542b\u552f\u4e00\u952e\u5bf9\u7684\u591a\u5c42\u7d22\u5f15\u3002 \u4e0b\u9762\u5bf9\u8ba1\u7b97\u7684\u5e73\u5747\u503c\uff08mean\uff09\u8fdb\u884c\u91cd\u5851\uff08unstack\uff09\u3002 print(grouped_means.unstack()) # key2 one two # key1 # a 5.0 3.0 # b 5.0 7.0 \u5206\u7ec4\u4fe1\u606f\u901a\u5e38\u5305\u542b\u5728\u540c\u4e00\u4e2aDataFrame\u4e2d\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u53ef\u4ee5\u4f20\u9012\u5217\u540d\uff08\u65e0\u8bba\u90a3\u4e9b\u5217\u540d\u662f\u5b57\u7b26\u4e32\u3001\u6570\u5b57\u6216\u5176\u4ed6Python\u5bf9\u8c61\uff09\u4f5c\u4e3a\u5206\u7ec4\u952e\uff1a \u4e0b\u9762\u4f8b\u5b50\u4e2d df.groupby('key1').mean() \u7684\u7ed3\u679c\u91cc\u5e76\u6ca1\u6709 key2 \u5217\u3002\u8fd9\u662f\u56e0\u4e3a df['key2'] \u5e76\u4e0d\u662f\u6570\u503c\u6570\u636e\uff0c\u5373 df['key2'] \u662f\u4e00\u4e2a\u5197\u4f59\u5217\uff0c\u56e0\u6b64\u88ab\u6392\u9664\u5728\u7ed3\u679c\u4e4b\u5916\u3002 result = df.groupby('key1').mean() print(result) # data1 data2 # key1 # a 4.333333 5.333333 # b 6.000000 7.000000 result = df.groupby(['key1', 'key2']).mean() print(result) # data1 data2 # key1 key2 # a one 5.0 6.0 # two 3.0 4.0 # b one 5.0 6.0 # two 7.0 8.0 result = df.groupby(['key1', 'key2']).size() print(result) # key1 key # a one 2 # two 1 # b one 1 # two 1 # dtype: int64","title":"\u5206\u7ec4\u673a\u5236"},{"location":"python/DataAnalysis/ch07/#_3","text":"GroupBy \u5bf9\u8c61\u652f\u6301\u8fed\u4ee3\uff0c\u4f1a\u751f\u6210\u4e00\u4e2a\u5305\u542b\u7ec4\u540d\u548c\u6570\u636e\u5757\u76842\u7ef4\u5143\u7ec4\u5e8f\u5217\u3002 df = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a'], 'key2': ['one', 'two', 'one', 'two', 'one'], 'data1': [1, 3, 5, 7, 9], 'data2': [2, 4, 6, 8, 10] } ) \u5355\u4e2a\u5206\u7ec4\u952e\u7684\u60c5\u51b5: for name, group in df.groupby('key1'): print(name) print(group) # a # key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10 # b # key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 \u591a\u4e2a\u5206\u7ec4\u952e\u7684\u60c5\u51b5: \u5143\u7ec4\u4e2d\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u662f\u952e\u503c\u7684\u5143\u7ec4\u3002 for (k1, k2), group in df.groupby(['key1', 'key2']): print((k1, k2)) print(group) # ('a', 'one') # key1 key2 data1 data2 # 0 a one 1 2 # 4 a one 9 10 # ('a', 'two') # key1 key2 data1 data2 # 1 a two 3 4 # ('b', 'one') # key1 key2 data1 data2 # 2 b one 5 6 # ('b', 'two') # key1 key2 data1 data2 # 3 b two 7 8 result = dict(list(df.groupby('key1'))) print(result) # df.groupby('key1')\u7684\u7ed3\u679c\u662f\u4e00\u4e2a\u5bf9\u8c61 # # list(df.groupby('key1'))\u7684\u7ed3\u679c\u662f\u5305\u542bFrameData\u7684\u7ed3\u6784\u7684\u5217\u8868list: # [ # ('a', key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10), # ('b', key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8) # ] # dict(list(df.groupby('key1')))\u7684\u7ed3\u679c\u662f\u5305\u542bFrameData\u7684\u7ed3\u6784\u7684\u5b57\u5178dict # { # 'a': key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10, # 'b': key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 # } print(result['b']) # key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c groupby \u5728 axis=0 \u7684\u8f74\u5411\u4e0a\u5206\u7ec4\uff0c\u4e5f\u53ef\u4ee5\u5728\u5176\u4ed6\u4efb\u610f\u8f74\u5411\u4e0a\u8fdb\u884c\u5206\u7ec4\u3002 print(df.dtypes) # key1 object # key2 object # data1 int64 # data2 int64 # dtype: object grouped = df.groupby(df.dtypes, axis=1) print(grouped) # print(list(grouped)) # [ # (dtype('int64'), data1 data2 # 0 1 2 # 1 3 4 # 2 5 6 # 3 7 8 # 4 9 10), # (dtype('O'), key1 key2 # 0 a one # 1 a two # 2 b one # 3 b two # 4 a one) # ] \u6253\u5370\u5404\u5206\u7ec4\u5982\u4e0b\uff1a for dtype, group in grouped: print(dtype) print(group) # int64 # data1 data2 # 0 1 2 # 1 3 4 # 2 5 6 # 3 7 8 # 4 9 10 # object # key1 key2 # 0 a one # 1 a two # 2 b one # 3 b two # 4 a one","title":"\u904d\u5386\u5404\u5206\u7ec4"},{"location":"python/DataAnalysis/ch07/#_4","text":"\u5bf9\u4e8e\u4eceDataFrame\u521b\u5efa\u7684 GroupBy \u5bf9\u8c61\uff0c\u7528\u5217\u540d\u79f0\u6216\u5217\u540d\u79f0\u6570\u7ec4\u8fdb\u884c\u7d22\u5f15\u65f6\uff0c\u4f1a\u4ea7\u751f\u7528\u4e8e\u805a\u5408\u7684\u5217\u5b50\u96c6\u7684\u6548\u679c\u3002 \u5982\u679c\u4f20\u9012\u7684\u662f\u5217\u8868\u6216\u6570\u7ec4\uff0c\u5219\u6b64\u7d22\u5f15\u64cd\u4f5c\u8fd4\u56de\u7684\u5bf9\u8c61\u662f\u5206\u7ec4\u7684DataFrame\uff1b\u5982\u679c\u53ea\u6709\u5355\u4e2a\u5217\u540d\u4f5c\u4e3a\u6807\u91cf\u4f20\u9012\uff0c\u5219\u4e3a\u5206\u7ec4\u7684Series\uff1b \u5bf9\u6bd4\u4e0b\u97624\u53e5\uff1a result = df.groupby('key1')['data1'] # \u5355\u4e2a\u5217\u540d print(result) # for key, data in result: print(key) print(data) result = df['data1'].groupby(df['key1']) # \u5355\u4e2a\u5217\u540d print(result) # for key, data in result: print(key) print(data) # a # 0 1 # 1 3 # 4 9 # Name: data1, dtype: int64 # b # 2 5 # 3 7 # Name: data1, dtype: int64 result = df.groupby('key1')[['data1']] # \u5217\u8868\u6216\u6570\u7ec4 print(result) # for key, data in result: print(key) print(data) # a # key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10 # b # key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 result = df[['data1']].groupby(df['key1']) # \u5217\u8868\u6216\u6570\u7ec4 print(result) # for key, data in result: print(key) print(data) # a # data1 # 0 1 # 1 3 # 4 9 # b # data1 # 2 5 # 3 7","title":"\u9009\u62e9\u4e00\u5217\u6216\u6240\u6709\u5217\u7684\u5b50\u96c6"},{"location":"python/DataAnalysis/ch07/#series","text":"\u5206\u7ec4\u4fe1\u606f\u53ef\u80fd\u4f1a\u4ee5\u975e\u6570\u7ec4\u5f62\u5f0f\u5b58\u5728\u3002 \u751f\u6210\u4e00\u4e2a\u793a\u4f8bDataFrame\u3002 people = pd.DataFrame( [[1, 3, 5, 7, 9], [0, 2, 4, 6, 8], [0, 2, 4, 6, 8], [1, 3, 5, 7, 9], [1, 2, 3, 4, 5]], columns=['a', 'b', 'c', 'd', 'e'], index=['Joe', 'Steve', 'Wes', 'Jim', 'Travis'] ) \u6dfb\u52a0\u4e00\u4e9bNA\u503c\u3002 people.iloc[2:3, [1, 2]] = np.nan print(people) # a b c d e # Joe 1 3.0 5.0 7 9 # Steve 0 2.0 4.0 6 8 # Wes 0 NaN NaN 6 8 # Jim 1 3.0 5.0 7 9 # Travis 1 2.0 3.0 4 5 \u5047\u8bbe\u6709\u5982\u4e0b\u5404\u5217\u7684\u5206\u7ec4\u5bf9\u5e94\u5173\u7cfb\uff0c\u5e76\u4e14\u60f3\u628a\u5404\u5217\u6309\u7ec4\u7d2f\u52a0\u3002 mapping = { 'a': 'red', 'b': 'red', 'c': 'blue', 'd': 'blue', 'e': 'red', 'f': 'orange' # \u6ce8\u610f\uff1a\u5065f\u867d\u7136\u6ca1\u6709\u88ab\u7528\u5230\uff0c\u4f46\u4e0d\u5f71\u54cd\u5728\u8fd9\u91cc\u5b9a\u4e49\u3002 } \u628a mapping \u8fd9\u4e2a\u5b57\u5178\u4f20\u7ed9 groupby() \u3002 by_column = people.groupby(mapping, axis=1) print(by_column.sum()) # blue red # Joe 12.0 13.0 # Steve 10.0 10.0 # Wes 6.0 8.0 # Jim 12.0 13.0 # Travis 7.0 8.0 Series\u4e5f\u6709\u76f8\u540c\u7684\u529f\u80fd\uff0c\u53ef\u4ee5\u89c6\u4e3a\u56fa\u5b9a\u5927\u5c0f\u7684\u6620\u5c04\u3002 map_services = pd.Series(mapping) print(map_services) # a red # b red # c blue # d blue # e red # f orange # dtype: object result = people.groupby(map_services, axis=1).count() print(result) # blue red # Joe 2 3 # Steve 2 3 # Wes 1 2 # Jim 2 3 # Travis 2 3","title":"\u4f7f\u7528\u5b57\u5178\u548cSeries\u5206\u7ec4"},{"location":"python/DataAnalysis/ch07/#_5","text":"\u4e0e\u4f7f\u7528\u5b57\u5178\u6216Series\u5206\u7ec4\u76f8\u6bd4\uff0c\u4f7f\u7528Python\u51fd\u6570\u662f\u5b9a\u4e49\u5206\u7ec4\u5173\u7cfb\u7684\u4e00\u79cd\u66f4\u4e3a\u901a\u7528\u7684\u65b9\u5f0f\u3002 \u4f5c\u4e3a\u5206\u7ec4\u952e\u4f20\u9012\u7684\u51fd\u6570\u5c06\u4f1a\u6309\u7167\u6bcf\u4e2a\u7d22\u5f15\u503c\u8c03\u7528\u4e00\u6b21\uff0c\u540c\u65f6\u8fd4\u56de\u503c\u4f1a\u88ab\u7528\u4f5c\u5206\u7ec4\u540d\u79f0\u3002\u6ce8\u610f\uff1a\u51fd\u6570\u662f\u4f5c\u7528\u5728\u7d22\u5f15\u4e0a\u3002 result = people.groupby(len).sum() # \u4eba\u7684\u540d\u5b57\u662f\u7d22\u5f15\u503c\uff0c\u6839\u636e\u540d\u5b57\u7684\u957f\u5ea6\u6765\u8fdb\u884c\u5206\u7ec4 print(result) # a b c d e # 3 2 6.0 10.0 20 26 # 5 0 2.0 4.0 6 8 # 6 1 2.0 3.0 4 5 \u53ef\u4ee5\u5c06\u51fd\u6570\u4e0e\u6570\u7ec4\u3001\u5b57\u5178\u6216Series\u8fdb\u884c\u6df7\u5408\uff0c\u6240\u6709\u7684\u5bf9\u8c61\u90fd\u4f1a\u5728\u5185\u90e8\u8f6c\u6362\u4e3a\u6570\u7ec4\u3002 key_list = ['one', 'one', 'one', 'two', 'two'] result = people.groupby([len, key_list]).min() print(result) # a b c d e # 3 one 0 3.0 5.0 6 8 # two 1 3.0 5.0 7 9 # 5 one 0 2.0 4.0 6 8 # 6 two 1 2.0 3.0 4 5","title":"\u4f7f\u7528\u51fd\u6570\u5206\u7ec4"},{"location":"python/DataAnalysis/ch07/#_6","text":"\u6839\u636e\u5c42\u7ea7\u5206\u7ec4\u65f6\uff0c\u5c06\u5c42\u7ea7\u6570\u503c\u6216\u5c42\u7ea7\u540d\u79f0\u4f20\u9012\u7ed9 level \u5173\u952e\u5b57\u3002 columns = pd.MultiIndex.from_arrays( [['US', 'US', 'US', 'JP', 'JP'], [1, 3, 5, 1, 3]], names=['cty', 'tenor'] ) hier_df = pd.DataFrame( [[1, 3, 5, 7, 9], [0, 2, 4, 6, 8], [1, 3, 5, 7, 9], [1, 2, 3, 4, 5]], columns=columns ) print(hier_df) # cty US JP # tenor 1 3 5 1 3 # 0 1 3 5 7 9 # 1 0 2 4 6 8 # 2 1 3 5 7 9 # 3 1 2 3 4 5 result = hier_df.groupby(level='cty', axis=1).count() print(result) # cty JP US # 0 2 3 # 1 2 3 # 2 2 3 # 3 2 3","title":"\u6839\u636e\u7d22\u5f15\u5c42\u7ea7\u5206\u7ec4"},{"location":"python/DataAnalysis/ch07/#_7","text":"\u805a\u5408\u662f\u6307\u6240\u6709\u6839\u636e\u6570\u7ec4\u4ea7\u751f\u6807\u91cf\u503c\u7684\u6570\u636e\u8f6c\u6362\u8fc7\u7a0b\uff0c\u6bd4\u5982\uff1a mean \u3001 count \u3001 min \u548c sum \u7b49\u4e00\u4e9b\u805a\u5408\u64cd\u4f5c\u3002 import pandas as pd import numpy as np \u9884\u5907\u77e5\u8bc6\uff1a \u5206\u4f4d\u6570\uff08Quantile\uff09\uff0c\u4e5f\u79f0\u5206\u4f4d\u70b9\uff0c\u662f\u6307\u5c06\u4e00\u4e2a\u968f\u673a\u53d8\u91cf\u7684\u6982\u7387\u5206\u5e03\u8303\u56f4\u5206\u4e3a\u51e0\u4e2a\u7b49\u4efd\u7684\u6570\u503c\u70b9\uff0c\u5206\u6790\u5176\u6570\u636e\u53d8\u91cf\u7684\u8d8b\u52bf\u3002 \u5e38\u7528\u7684\u5206\u4f4d\u6570\u6709 \u4e2d\u4f4d\u6570\u3001\u56db\u5206\u4f4d\u6570\u3001\u767e\u5206\u4f4d\u6570\u7b49\u3002 \u4e2d\u4f4d\u6570\uff08Medians\uff09\u662f\u4e00\u4e2a\u7edf\u8ba1\u5b66\u7684\u4e13\u6709\u540d\u8bcd\uff0c\u4ee3\u8868\u4e00\u4e2a\u6837\u672c\u3001\u79cd\u7fa4\u6216\u6982\u7387\u5206\u5e03\u4e2d\u7684\u4e00\u4e2a\u6570\u503c\uff0c\u53ef\u4ee5\u5c06\u6570\u503c\u96c6\u5408\u5212\u5206\u4e3a\u76f8\u7b49\u7684\u4e24\u90e8\u5206\u3002 \u5229\u7528pandas\u5e93\u8ba1\u7b97 data = [6, 47, 49, 15, 42, 41, 7, 39, 43, 40, 36] \u7684\u5206\u4f4d\u6570\u3002 \u786e\u5b9a p \u5206\u4f4d\u6570\u4f4d\u7f6e\u7684\u4e24\u79cd\u65b9\u6cd5( n \u4e3a\u6570\u636e\u7684\u603b\u4e2a\u6570\uff0c p \u4e3a 0-1 \u4e4b\u95f4\u7684\u503c)\u3002\u5728python\u4e2d\u8ba1\u7b97\u5206\u4f4d\u6570\u4f4d\u7f6e\u7684\u65b9\u6848\u91c7\u7528 position=1+(n-1)*p \uff1a position = (n+1)*p position = 1 + (n-1)*p \u6848\u4f8b1 data = pd.Series(np.array([6, 47, 49, 15, 42, 41, 7, 39, 43, 40, 36])) print(\"\u6570\u636e\u683c\u5f0f\uff1a\") print(np.sort(data)) # \u5fc5\u987b\u8981\u6392\u5e8f print('Q1:', data.quantile(.25)) print('Q2:', data.quantile(.5)) print('Q3:', data.quantile(.75)) # \u6570\u636e\u683c\u5f0f\uff1a # [ 6 7 15 36 39 40 41 42 43 47 49] # Q1: 25.5 # Q2: 40.0 # Q3: 42.5 # \u624b\u7b97\u8ba1\u7b97\u7ed3\u679c\uff1a # Q1\u7684p\u5206\u4f4d\u6570(0.25)\u4f4d\u7f6eposition = 1+(11-1)*0.25 = 3.5(\u53d6\u7b2c3\u4f4d) (p=0.25) Q1=15+(36-15)*0.5=25.5 (\u7b2c3\u30014\u4f4d\u7684\u5dee\u4e58\u4ee5\u4f59\u65700.5) # Q2\u7684p\u5206\u4f4d\u6570(0.5)\u4f4d\u7f6eposition = 1+(11-1)*0.5 = 6 (p=0.5) Q2=40 # Q3\u7684p\u5206\u4f4d\u6570(0.75)\u4f4d\u7f6eposition = 1+(11-1)*0.75 = 9 (p=0.75) Q3=42+(43-42)*0.5=42.5 # IQR = Q3 - Q1 = 17 \u6848\u4f8b2 df = pd.DataFrame(np.array([[1, 1], [2, 10], [3, 100], [4, 100]]), columns=['a', 'b']) print(\"\u6570\u636e\u539f\u59cb\u683c\u5f0f\uff1a\") print(df) print(\"\u8ba1\u7b97p=0.1\u65f6\uff0ca\u5217\u548cb\u5217\u7684\u5206\u4f4d\u6570\") print(df.quantile(.1)) # \u6570\u636e\u539f\u59cb\u683c\u5f0f\uff1a # a b # 0 1 1 # 1 2 10 # 2 3 100 # 3 4 100 # \u8ba1\u7b97p=0.1\u65f6\uff0ca\u5217\u548cb\u5217\u7684\u5206\u4f4d\u6570 # a 1.3 # b 3.7 # Name: 0.1, dtype: float64 # \u624b\u7b97\u8ba1\u7b97\u7ed3\u679c\uff1a # \u8ba1\u7b97a\u5217 # position=1+(4-1)*0.1=1.3 (\u53d6\u7b2c1\u4f4d) # Q1=1+(2-1)*0.3=1.3 (\u7b2c1\u30012\u4f4d\u7684\u5dee\u4e58\u4ee5\u4f59\u65700.3) # \u8ba1\u7b97b\u5217 # position=1+(4-1)*0.1=1.3 (\u53d6\u7b2c1\u4f4d) # Q1=1+(10-1)*0.3=3.7 (\u7b2c1\u30012\u4f4d\u7684\u5dee\u4e58\u4ee5\u4f59\u65700.3) \u4f18\u5316\u7684 groupby \u65b9\u6cd5\uff1a count: \u5206\u7ec4\u4e2d\u975eNA\u503c\u7684\u6570\u91cf sum: \u975eNA\u503c\u7684\u7d2f\u52a0\u548c mean: \u975eNA\u503c\u7684\u5e73\u5747\u503c median: \u975eNA\u503c\u7684\u7b97\u672f\u4e2d\u4f4d\u6570 std, var: \u65e0\u504f\u7684(n-1\u5206\u6bcd)\u6807\u51c6\u5dee\u548c\u65b9\u5dee min, max: \u975eNA\u503c\u7684\u6700\u5c0f\u503c\u3001\u6700\u5927\u503c prod: \u975eNA\u503c\u7684\u4e58\u79ef first, last: \u975eNA\u503c\u7684\u7b2c\u4e00\u4e2a\u3001\u6700\u540e\u4e00\u4e2a\u503c df = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a'], 'key2': ['one', 'two', 'one', 'two', 'one'], 'data1': [1, 3, 5, 7, 9], 'data2': [2, 4, 6, 8, 10] } ) print(df) # key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 2 b one 5 6 # 3 b two 7 8 # 4 a one 9 10 grouped = df.groupby('key1') result = grouped['data1'] for i in result: print(i) # ('a', 0 1 # 1 3 # 4 9 # Name: data1, dtype: int64) # ('b', 2 5 # 3 7 # Name: data1, dtype: int64) result = grouped['data1'].quantile(0.9) # quantile\u5206\u4f4d\u6570 print(result) # key1 # a 7.8 # b 6.8 # Name: data1, dtype: float64 # \u624b\u7b97\u8ba1\u7b97\u7ed3\u679c\uff1a # \u8ba1\u7b97a\u5217 # position=1+(3-1)*0.9=2.8 # Q1=3+(9-3)*0.8=7.8 # \u8ba1\u7b97b\u5217 # position=1+(2-1)*0.9=1.9 # Q1=5+(7-5)*0.9=6.8 \u4f7f\u7528\u81ea\u884c\u5236\u5b9a\u7684\u805a\u5408\uff0c\u5e76\u518d\u8c03\u7528\u5df2\u7ecf\u5728\u5206\u7ec4\u5bf9\u8c61\u4e0a\u5b9a\u4e49\u597d\u7684\u65b9\u6cd5\u3002 def peak_to_peak(arr): return arr.max() - arr.min() result = grouped.agg(peak_to_peak) print(result) # data1 data2 # key1 # a 8 8 # b 2 2 result = grouped.describe() print(result) # data1 ... data2 # count mean std min 25% ... min 25% 50% 75% max # key1 ... # a 3.0 4.333333 4.163332 1.0 2.0 ... 2.0 3.0 4.0 7.0 10.0 # b 2.0 6.000000 1.414214 5.0 5.5 ... 6.0 6.5 7.0 7.5 8.0","title":"\u6570\u636e\u805a\u5408"},{"location":"python/DataAnalysis/ch07/#_8","text":"tips = pd.read_csv('../examples/tips.csv') tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) print(tips.head(5)) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 \u6839\u636e\u5404\u5217\u540c\u65f6\u4f7f\u7528\u591a\u4e2a\u51fd\u6570\u8fdb\u884c\u805a\u5408 grouped = tips.groupby(['day', 'smoker']) # for i in grouped: # print(i) # (('Fri', 'No'), total_bill tip smoker day time size tip_pct # 91 22.49 3.50 No Fri Dinner 2 0.184308 # ...... # 223 15.98 3.00 No Fri Lunch 3 0.231125) # (('Fri', 'Yes'), total_bill tip smoker day time size tip_pct # 90 28.97 3.00 Yes Fri Dinner 2 0.115518 # ...... # 226 10.09 2.00 Yes Fri Lunch 2 0.247219) # ...... grouped_pct = grouped['tip_pct'] for i in grouped_pct: print(i) # (('Fri', 'No'), 91 0.184308 # 94 0.166667 # ...... # Name: tip_pct, dtype: float64) # (('Fri', 'Yes'), 90 0.115518 # 92 0.210526 # ...... # Name: tip_pct, dtype: float64) # ...... \u5c06\u51fd\u6570\u540d\u4ee5\u5b57\u7b26\u4e32\u5f62\u5f0f\u4f20\u9012\u3002 result = grouped_pct.agg('mean') print(result) # day smoker # Fri No 0.179740 # Yes 0.216293 # Sat No 0.190412 # Yes 0.179833 # Sun No 0.193617 # Yes 0.322021 # Thur No 0.193424 # Yes 0.198508 # Name: tip_pct, dtype: float64 \u5982\u679c\u4f20\u9012\u7684\u662f\u51fd\u6570\u6216\u8005\u51fd\u6570\u540d\u7684\u5217\u8868\uff0c\u4f1a\u5f97\u5230\u4e00\u4e2a\u5217\u540d\u662f\u8fd9\u4e9b\u51fd\u6570\u540d\u7684DataFrame\u3002 \u4e0b\u9762\u4f20\u9012\u4e86\u805a\u5408\u51fd\u6570\u7684\u5217\u8868\u7ed9agg\u65b9\u6cd5\uff0c\u8fd9\u4e9b\u51fd\u6570\u4f1a\u5404\u81ea\u8fd0\u7528\u4e8e\u6570\u636e\u5206\u7ec4\u3002 result = grouped_pct.agg(['mean', 'std', peak_to_peak]) print(result) # mean std peak_to_peak # day smoker # Fri No 0.179740 0.039458 0.094263 # Yes 0.216293 0.077530 0.242219 # Sat No 0.190412 0.058626 0.352192 # Yes 0.179833 0.089496 0.446137 # Sun No 0.193617 0.060302 0.274897 # Yes 0.322021 0.538061 2.382107 # Thur No 0.193424 0.056065 0.284273 # Yes 0.198508 0.057170 0.219047 \u5982\u679c\u4f20\u9012\u7684\u662f (name, function) \u5143\u7ec4\u7684\u5217\u8868\uff0c\u6bcf\u4e2a\u5143\u7ec4\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5c06\u4f5c\u4e3aDataFrame\u7684\u5217\u540d\uff08\u53ef\u4ee5\u8ba4\u4e3a\u4e8c\u5143\u5143\u7ec4\u7684\u5217\u8868\u662f\u4e00\u79cd\u6709\u5e8f\u7684\u5bf9\u5e94\u5173\u7cfb\uff09\uff1a result = grouped_pct.agg([('foo', 'mean'), ('bar', np.std)]) # foo\u662fmean\u503c\u7684\u5217\u540d print(result) # foo bar # day smoker # Fri No 0.179740 0.039458 # Yes 0.216293 0.077530 # Sat No 0.190412 0.058626 # Yes 0.179833 0.089496 # Sun No 0.193617 0.060302 # Yes 0.322021 0.538061 # Thur No 0.193424 0.056065 # Yes 0.198508 0.057170 \u53ef\u4ee5\u6307\u5b9a\u5e94\u7528\u5230\u6240\u6709\u5217\u4e0a\u7684\u51fd\u6570\u5217\u8868\u6216\u6bcf\u4e00\u5217\u4e0a\u8981\u5e94\u7528\u7684\u4e0d\u540c\u51fd\u6570\u3002 \u4e0b\u9762\u4ea7\u751f\u7684DataFrame\u62e5\u6709\u5206\u5c42\u5217\uff0c\u4e0e\u5206\u522b\u805a\u5408\u6bcf\u4e00\u5217\uff0c\u518d\u4ee5\u5217\u540d\u4f5c\u4e3a keys \u53c2\u6570\u4f7f\u7528 concat \u5c06\u7ed3\u679c\u62fc\u63a5\u5728\u4e00\u8d77\u7684\u7ed3\u679c\u76f8\u540c\u3002 functions = ['count', 'mean', 'max'] result = grouped[['tip_pct', 'total_bill']].agg(functions) print(result) # tip_pct total_bill # count mean max count mean max # day smoker # Fri No 4 0.179740 0.231125 4 18.420000 22.75 # Yes 15 0.216293 0.357737 15 16.813333 40.17 # Sat No 45 0.190412 0.412409 45 19.661778 48.33 # Yes 42 0.179833 0.483092 42 21.276667 50.81 # Sun No 57 0.193617 0.338101 57 20.506667 48.17 # Yes 19 0.322021 2.452381 19 24.120000 45.35 # Thur No 45 0.193424 0.362976 45 17.113111 41.19 # Yes 17 0.198508 0.317965 17 19.190588 43.11 # \u628a['tip_pct', 'total_bill']\u6539\u6210[['tip_pct', 'total_bill']]\uff0c\u5c31\u53ef\u4ee5\u907f\u514d\u62a5\u9519 # FutureWarning: Indexing with multiple keys (implicitly converted to a tuple of keys) will be deprecated, use a list instead. # result = grouped['tip_pct', 'total_bill'].agg(functions) print(result['tip_pct']) # count mean max # day smoker # Fri No 4 0.179740 0.231125 # Yes 15 0.216293 0.357737 # Sat No 45 0.190412 0.412409 # Yes 42 0.179833 0.483092 # Sun No 57 0.193617 0.338101 # Yes 19 0.322021 2.452381 # Thur No 45 0.193424 0.362976 # Yes 17 0.198508 0.317965 \u4e5f\u540c\u6837\u53ef\u4ee5\u4f20\u9012\u5177\u6709\u81ea\u5b9a\u4e49\u540d\u79f0\u7684\u5143\u7ec4\u5217\u8868\uff1a ftuples = [('Durchschnitt', 'mean'), ('Abweichung', np.var)] result = grouped[['tip_pct', 'total_bill']].agg(ftuples) print(result) # tip_pct total_bill # Durchschnitt Abweichung Durchschnitt Abweichung # day smoker # Fri No 0.179740 0.001557 18.420000 25.596333 # Yes 0.216293 0.006011 16.813333 82.562438 # Sat No 0.190412 0.003437 19.661778 79.908965 # Yes 0.179833 0.008010 21.276667 101.387535 # Sun No 0.193617 0.003636 20.506667 66.099980 # Yes 0.322021 0.289509 24.120000 109.046044 # Thur No 0.193424 0.003143 17.113111 59.625081 # Yes 0.198508 0.003268 19.190588 69.808518 \u8981\u5c06\u4e0d\u540c\u7684\u51fd\u6570\u5e94\u7528\u5230\u4e00\u4e2a\u6216\u591a\u4e2a\u5217\u4e0a\uff0c\u9700\u8981\u5c06\u542b\u6709\u5217\u540d\u4e0e\u51fd\u6570\u5bf9\u5e94\u5173\u7cfb\u7684\u5b57\u5178\u4f20\u9012\u7ed9 agg \uff1a result = grouped.agg({'tip': np.max, 'size': 'sum'}) print(result) # tip size # day smoker # Fri No 3.50 9 # Yes 4.73 31 # Sat No 9.00 115 # Yes 10.00 104 # Sun No 6.00 167 # Yes 6.50 49 # Thur No 6.70 112 # Yes 5.00 40 result = grouped.agg({'tip_pct': ['min', 'max', 'mean', 'std']}) print(result) # tip_pct # min max mean std # day smoker # Fri No 0.136861 0.231125 0.179740 0.039458 # Yes 0.115518 0.357737 0.216293 0.077530 # Sat No 0.060217 0.412409 0.190412 0.058626 # Yes 0.036955 0.483092 0.179833 0.089496 # Sun No 0.063204 0.338101 0.193617 0.060302 # Yes 0.070274 2.452381 0.322021 0.538061 # Thur No 0.078704 0.362976 0.193424 0.056065 # Yes 0.098918 0.317965 0.198508 0.057170 \u53ea\u6709\u591a\u4e2a\u51fd\u6570\u5e94\u7528\u4e8e\u81f3\u5c11\u4e00\u4e2a\u5217\u65f6\uff0cDataFrame\u624d\u5177\u6709\u5206\u5c42\u5217\u3002","title":"\u9010\u5217\u53ca\u591a\u51fd\u6570\u5e94\u7528"},{"location":"python/DataAnalysis/ch07/#_9","text":"\u5728\u524d\u9762\u6240\u6709\u7684\u4f8b\u5b50\u4e2d\uff0c\u805a\u5408\u6570\u636e\u8fd4\u56de\u65f6\u90fd\u662f\u5e26\u6709\u7d22\u5f15\u7684\uff0c\u6709\u65f6\u7d22\u5f15\u662f\u5206\u5c42\u7684\uff0c\u7531\u552f\u4e00\u7684\u5206\u7ec4\u952e\u8054\u5408\u5f62\u6210\u3002 \u56e0\u4e3a\u4e0d\u662f\u6240\u6709\u7684\u60c5\u51b5\u4e0b\u90fd\u9700\u8981\u7d22\u5f15\uff0c\u6240\u4ee5\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\u53ef\u4ee5\u901a\u8fc7\u5411groupby\u4f20\u9012as_index=False\u6765\u7981\u7528\u5206\u7ec4\u952e\u4f5c\u4e3a\u7d22\u5f15\u7684\u884c\u4e3a\uff1a result = tips.groupby(['day', 'smoker'], as_index=False).mean() print(result) # day smoker total_bill tip size tip_pct # 0 Fri No 18.420000 2.812500 2.250000 0.179740 # 1 Fri Yes 16.813333 2.714000 2.066667 0.216293 # 2 Sat No 19.661778 3.102889 2.555556 0.190412 # 3 Sat Yes 21.276667 2.875476 2.476190 0.179833 # 4 Sun No 20.506667 3.167895 2.929825 0.193617 # 5 Sun Yes 24.120000 3.516842 2.578947 0.322021 # 6 Thur No 17.113111 2.673778 2.488889 0.193424 # 7 Thur Yes 19.190588 3.030000 2.352941 0.198508 \u901a\u8fc7\u5728\u7ed3\u679c\u4e0a\u8c03\u7528reset_index\u4e5f\u53ef\u4ee5\u83b7\u5f97\u540c\u6837\u7684\u7ed3\u679c\u3002\u4f7f\u7528as_index=False\u53ef\u4ee5\u907f\u514d\u4e00\u4e9b\u4e0d\u5fc5\u8981\u7684\u8ba1\u7b97\u3002 result = tips.groupby(['day', 'smoker']).mean() print(result.reset_index()) # day smoker total_bill tip size tip_pct # 0 Fri No 18.420000 2.812500 2.250000 0.179740 # 1 Fri Yes 16.813333 2.714000 2.066667 0.216293 # 2 Sat No 19.661778 3.102889 2.555556 0.190412 # 3 Sat Yes 21.276667 2.875476 2.476190 0.179833 # 4 Sun No 20.506667 3.167895 2.929825 0.193617 # 5 Sun Yes 24.120000 3.516842 2.578947 0.322021 # 6 Thur No 17.113111 2.673778 2.488889 0.193424 # 7 Thur Yes 19.190588 3.030000 2.352941 0.198508 print(result) # total_bill tip size tip_pct # day smoker # Fri No 18.420000 2.812500 2.250000 0.179740 # Yes 16.813333 2.714000 2.066667 0.216293 # Sat No 19.661778 3.102889 2.555556 0.190412 # Yes 21.276667 2.875476 2.476190 0.179833 # Sun No 20.506667 3.167895 2.929825 0.193617 # Yes 24.120000 3.516842 2.578947 0.322021 # Thur No 17.113111 2.673778 2.488889 0.193424 # Yes 19.190588 3.030000 2.352941 0.198508","title":"\u8fd4\u56de\u4e0d\u542b\u884c\u7d22\u5f15\u7684\u805a\u5408\u6570\u636e"},{"location":"python/DataAnalysis/ch07/#-","text":"import pandas as pd import numpy as np import statsmodels.api as sm GroupBy \u65b9\u6cd5\u6700\u5e38\u89c1\u7684\u76ee\u7684\u662f apply \uff08\u5e94\u7528\uff09\u3002 apply \u5c06\u5bf9\u8c61\u62c6\u5206\u6210\u591a\u5757\uff0c\u7136\u540e\u5728\u6bcf\u4e00\u5757\u4e0a\u8c03\u7528\u4f20\u9012\u7684\u51fd\u6570\uff0c\u4e4b\u540e\u5c1d\u8bd5\u5c06\u6bcf\u4e00\u5757\u62fc\u63a5\u5230\u4e00\u8d77\u3002 \u6839\u636e\u4e0b\u9762\u7684\u5c0f\u8d39\u6570\u636e\u96c6\uff0c\u6309\u7ec4\u9009\u51fa\u5c0f\u8d39\u767e\u5206\u6bd4\uff08tip-pct\uff09\u6700\u9ad8\u7684\u4e94\u7ec4\u3002 tips = pd.read_csv('../examples/tips.csv') tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) \u6837\u672c\u6570\u636e print(tips.head(5)) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 \u9996\u5148\uff0c\u5199\u4e00\u4e2a\u53ef\u4ee5\u5728\u7279\u5b9a\u5217\u4e2d\u9009\u51fa\u6700\u5927\u503c\u6240\u5728\u884c\u7684\u51fd\u6570\uff1a \u6dfb\u52a0\u4e86\u5347\u5e8f\uff0c\u7ed3\u679c\u8f93\u51fa\u6700\u540e5\u884c\uff08\u6700\u540e\u76845\u884c\u4e5f\u662f\u6700\u5927\u76845\u4e2a tip_tcp \u8bb0\u5f55\uff09\u3002 def top(df, n=5, column='tip_pct'): return df.sort_values(by=column, ascending=True)[-n:] result = top(tips, n=6) print(result) # \u7b49\u4ef7\u65b9\u5f0f\uff1a # result = tips.sort_values('tip_pct')[-6:] # print(result) # total_bill tip smoker day time size tip_pct # 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 \u5982\u679c\u6309\u7167 smoker \u8fdb\u884c\u5206\u7ec4\uff0c\u4e4b\u540e\u8c03\u7528 apply \uff0c\u4f1a\u5f97\u5230\u4ee5\u4e0b\u7ed3\u679c\uff1a top \u51fd\u6570\u5728DataFrame\u7684\u6bcf\u4e00\u884c\u5206\u7ec4\u4e0a\u88ab\u8c03\u7528\uff0c\u4e4b\u540e\u4f7f\u7528 pandas.concat \u5c06\u51fd\u6570\u7ed3\u679c\u7c98\u8d34\u5728\u4e00\u8d77\uff0c\u5e76\u4f7f\u7528\u5206\u7ec4\u540d\u4f5c\u4e3a\u5404\u7ec4\u7684\u6807\u7b7e\u3002 \u56e0\u6b64\u7ed3\u679c\u5305\u542b\u4e00\u4e2a\u5206\u5c42\u7d22\u5f15\uff0c\u8be5\u5206\u5c42\u7d22\u5f15\u7684\u5185\u90e8\u5c42\u7ea7\u5305\u542b\u539fDataFrame\u7684\u7d22\u5f15\u503c\u3002 result = tips.groupby('smoker').apply(top) print(result) # total_bill tip smoker day time size tip_pct # smoker # No 88 24.71 5.85 No Thur Lunch 2 0.310180 # 185 20.69 5.00 No Sun Dinner 5 0.318674 # 51 10.29 2.60 No Sun Dinner 2 0.338101 # 149 7.51 2.00 No Thur Lunch 2 0.362976 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # Yes 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 \u5982\u679c\u9664\u4e86\u5411 apply \u4f20\u9012\u51fd\u6570\uff0c\u8fd8\u4f20\u9012\u5176\u4ed6\u53c2\u6570\u6216\u5173\u952e\u5b57\u7684\u8bdd\uff0c\u4f60\u53ef\u4ee5\u628a\u8fd9\u4e9b\u653e\u5728\u51fd\u6570\u540e\u8fdb\u884c\u4f20\u9012\u3002 result = tips.groupby('smoker').apply(top, n=1, column='total_bill') print(result) # \u8fd92\u884c\u90fd\u662fsmoker\u662fyes\u548cno\u65f6\u6700\u5927total_bill\u503c\u6240\u5728\u884c\u3002 # total_bill tip smoker day time size tip_pct # smoker # No 212 48.33 9.0 No Sat Dinner 4 0.228833 # Yes 170 50.81 10.0 Yes Sat Dinner 3 0.245038 \u5728 GroupBy \u5bf9\u8c61\u4e0a\u8c03\u7528 describe \u65b9\u6cd5\u3002 result = tips.groupby('smoker')['tip_pct'].describe() print(result) # count mean std ... 50% 75% max # smoker ... # No 151.0 0.192237 0.057665 ... 0.184308 0.227015 0.412409 # Yes 93.0 0.218176 0.254295 ... 0.181818 0.242326 2.452381 # [2 rows x 8 columns] print(result.unstack('smoker')) # \u7c7b\u4f3c\u4e8e\u8f6c\u7f6e # smoker # count No 151.000000 # Yes 93.000000 # mean No 0.192237 # Yes 0.218176 # std No 0.057665 # Yes 0.254295 # min No 0.060217 # Yes 0.036955 # 25% No 0.158622 # Yes 0.119534 # 50% No 0.184308 # Yes 0.181818 # 75% No 0.227015 # Yes 0.242326 # max No 0.412409 # Yes 2.452381 # dtype: float64 \u5728 GroupBy \u5bf9\u8c61\u7684\u5185\u90e8\uff0c\u5f53\u8c03\u7528\u50cf describe \u8fd9\u6837\u7684\u65b9\u6cd5\u65f6\uff0c\u5b9e\u9645\u4e0a\u662f\u4ee5\u4e0b\u4ee3\u7801\u7684\u7b80\u5199\uff1a grouped = tips.groupby(['smoker']) f = lambda x: x.describe() result = grouped.apply(f) print(result) # total_bill tip size tip_pct # smoker # No count 151.000000 151.000000 151.000000 151.000000 # mean 19.188278 2.991854 2.668874 0.192237 # std 8.255582 1.377190 1.017984 0.057665 # min 7.250000 1.000000 1.000000 0.060217 # 25% 13.325000 2.000000 2.000000 0.158622 # 50% 17.590000 2.740000 2.000000 0.184308 # 75% 22.755000 3.505000 3.000000 0.227015 # max 48.330000 9.000000 6.000000 0.412409 # Yes count 93.000000 93.000000 93.000000 93.000000 # mean 20.756344 3.008710 2.408602 0.218176 # std 9.832154 1.401468 0.810751 0.254295 # min 3.070000 1.000000 1.000000 0.036955 # 25% 13.420000 2.000000 2.000000 0.119534 # 50% 17.920000 3.000000 2.000000 0.181818 # 75% 26.860000 3.680000 3.000000 0.242326 # max 50.810000 10.000000 5.000000 2.452381","title":"\u5e94\u7528\uff1a\u901a\u7528\u62c6\u5206-\u5e94\u7528-\u8054\u5408"},{"location":"python/DataAnalysis/ch07/#_10","text":"\u5728\u524d\u9762\u7684\u4f8b\u5b50\u4e2d\u6240\u5f97\u5230\u7684\u5bf9\u8c61\uff0c\u90fd\u5177\u6709\u5206\u7ec4\u952e\u6240\u5f62\u6210\u7684\u5206\u5c42\u7d22\u5f15\u4ee5\u53ca\u6bcf\u4e2a\u539f\u59cb\u5bf9\u8c61\u7684\u7d22\u5f15\u3002 \u4e5f\u53ef\u4ee5\u901a\u8fc7\u5411 groupby \u4f20\u9012 group_keys=False \u6765\u7981\u7528\u8fd9\u4e2a\u529f\u80fd\u3002 result = tips.groupby('smoker', group_keys=True).apply(top) print(result) # total_bill tip smoker day time size tip_pct # smoker # No 88 24.71 5.85 No Thur Lunch 2 0.310180 # 185 20.69 5.00 No Sun Dinner 5 0.318674 # 51 10.29 2.60 No Sun Dinner 2 0.338101 # 149 7.51 2.00 No Thur Lunch 2 0.362976 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # Yes 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 result = tips.groupby('smoker', group_keys=False).apply(top) print(result) # total_bill tip smoker day time size tip_pct # 88 24.71 5.85 No Thur Lunch 2 0.310180 # 185 20.69 5.00 No Sun Dinner 5 0.318674 # 51 10.29 2.60 No Sun Dinner 2 0.338101 # 149 7.51 2.00 No Thur Lunch 2 0.362976 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381","title":"\u538b\u7f29\u5206\u7ec4\u952e"},{"location":"python/DataAnalysis/ch07/#_11","text":"\u7b2c8\u7ae0\u4e2d\uff0cpandas\u6709\u4e00\u4e9b\u5de5\u5177\uff0c\u5c24\u5176\u662f cut \u548c qcut \uff0c\u7528\u4e8e\u5c06\u6570\u636e\u6309\u7167\u4f60\u9009\u62e9\u7684\u7bb1\u4f4d\u6216\u6837\u672c\u5206\u4f4d\u6570\u8fdb\u884c\u5206\u6876\u3002 \u4e0e groupby \u65b9\u6cd5\u4e00\u8d77\u4f7f\u7528\u8fd9\u4e9b\u51fd\u6570\u53ef\u4ee5\u5bf9\u6570\u636e\u96c6\u66f4\u65b9\u4fbf\u5730\u8fdb\u884c\u5206\u6876\u6216\u5206\u4f4d\u5206\u6790\u3002 \u590d\u4e60\uff1a\u673a\u68b0\u5b66\u4e60\u4e2d\u7684\u5206\u7bb1\u5904\u7406\u3002 \u5728\u673a\u68b0\u5b66\u4e60\u4e2d\u7ecf\u5e38\u4f1a\u5bf9\u6570\u636e\u8fdb\u884c\u5206\u7bb1\u5904\u7406\u7684\u64cd\u4f5c\uff0c \u4e5f\u5c31\u662f\u628a\u4e00\u6bb5\u8fde\u7eed\u7684\u503c\u5207\u5206\u6210\u82e5\u5e72\u6bb5\uff0c\u6bcf\u4e00\u6bb5\u7684\u503c\u770b\u6210\u4e00\u4e2a\u5206\u7c7b\u3002\u8fd9\u4e2a\u628a\u8fde\u7eed\u503c\u8f6c\u6362\u6210\u79bb\u6563\u503c\u7684\u8fc7\u7a0b\uff0c\u6211\u4eec\u53eb\u505a\u5206\u7bb1\u5904\u7406\u3002 \u6bd4\u5982\uff0c\u628a\u5e74\u9f84\u630915\u5c81\u5212\u5206\u6210\u4e00\u7ec4\uff0c0-15\u5c81\u53eb\u505a\u5c11\u5e74\uff0c16-30\u5c81\u53eb\u505a\u9752\u5e74\uff0c31-45\u5c81\u53eb\u505a\u58ee\u5e74\u3002\u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e2d\uff0c\u6211\u4eec\u628a\u8fde\u7eed\u7684\u5e74\u9f84\u5206\u6210\u4e86\u4e09\u4e2a\u7c7b\u522b\uff0c\u201c\u5c11\u5e74\u201d\uff0c\u201c\u9752\u5e74\u201d\u548c\u201c\u58ee\u5e74\u201d\u5c31\u662f\u5404\u4e2a\u7c7b\u522b\u7684\u540d\u79f0\uff0c\u6216\u8005\u53eb\u505a\u6807\u7b7e\u3002 \u5728pandas\u4e2d\uff0c cut \u548c qcut \u51fd\u6570\u90fd\u53ef\u4ee5\u8fdb\u884c\u5206\u7bb1\u5904\u7406\u64cd\u4f5c\u3002 cut() \u6309\u7167\u53d8\u91cf\u7684\u503c\u5bf9\u53d8\u91cf\u8fdb\u884c\u5206\u5272\uff0c\u6bcf\u4e2a\u5206\u7ec4\u91cc\u6570\u636e\u7684\u4e2a\u6570\u5e76\u4e0d\u4e00\u6837\u3002 qcut() \u662f\u6309\u53d8\u91cf\u7684\u6570\u91cf\u6765\u5bf9\u53d8\u91cf\u8fdb\u884c\u5206\u5272\uff0c\u5e76\u4e14\u5c3d\u91cf\u4fdd\u8bc1\u6bcf\u4e2a\u5206\u7ec4\u91cc\u53d8\u91cf\u7684\u4e2a\u6570\u76f8\u540c\u3002 \u8003\u8651\u4e0b\u9762\u4e00\u4e2a\u7b80\u5355\u7684\u968f\u673a\u6570\u636e\u96c6\u548c\u4e00\u4e2a\u4f7f\u7528 cut \u7684\u7b49\u957f\u6876\u5206\u7c7b\uff1a df = pd.DataFrame( { 'data1': np.random.randn(1000), 'data2': np.random.randn(1000) } ) quartiles = pd.cut(df.data1, 4) # \u6309\u7167data1\u503c\u7531\u5c0f\u5230\u5927\u7684\u987a\u5e8f\u5c06\u6570\u636e\u5206\u62104\u4efd\uff0c\u5e76\u4e14\u4f7f\u6bcf\u7ec4\u503c\u7684\u8303\u56f4\u5927\u81f4\u76f8\u7b49\u3002 print(quartiles[:10]) # 0 (-0.0743, 1.729] # 1 (-0.0743, 1.729] # 2 (-0.0743, 1.729] # 3 (-0.0743, 1.729] # 4 (-1.877, -0.0743] # 5 (-0.0743, 1.729] # 6 (-0.0743, 1.729] # 7 (-0.0743, 1.729] # 8 (-1.877, -0.0743] # 9 (-0.0743, 1.729] # Name: data1, dtype: category # Categories ( # 4, # interval[float64, right]): [ # (-3.687, -1.877] < (-1.877, -0.0743] < (-0.0743, 1.729] < (1.729, 3.531] # ] \u4e0a\u9762 cut \u8fd4\u56de\u7684 Categorical \u5bf9\u8c61\u53ef\u4ee5\u76f4\u63a5\u4f20\u9012\u7ed9 groupby \u3002\u5229\u7528\u5b83\u8ba1\u7b97\u51fa data2 \u5217\u7684\u4e00\u4e2a\u7edf\u8ba1\u503c\u96c6\u5408\uff0c\u5982\u4e0b\uff1a def get_stats(group): return { 'min': group.min(), 'max': group.max(), 'count': group.count(), 'mean': group.mean() } grouped = df.data2.groupby(quartiles) for i in grouped: print(i) result = grouped.apply(get_stats).unstack() print(result) # min max count mean # data1 # (-3.145, -1.424] -1.759377 2.484321 77.0 -0.127900 # (-1.424, 0.29] -3.142344 2.830654 524.0 -0.081931 # (0.29, 2.005] -3.557136 3.261635 376.0 0.015715 # (2.005, 3.719] -2.829458 1.766352 23.0 -0.198780 \u4f7f\u7528 qcut \uff0c\u6839\u636e\u6837\u672c\u5206\u4f4d\u6570\u8ba1\u7b97\u51fa\u7b49\u5927\u5c0f\u7684\u6876\uff0c\u5c31\u662f\u7b49\u957f\u6876\u3002\u901a\u8fc7\u4f20\u9012 labels=False \u6765\u83b7\u5f97\u5206\u4f4d\u6570\u6570\u503c\u3002 grouping = pd.qcut(df.data1, 10, labels=False) grouped = df.data2.groupby(grouping) result = grouped.apply(get_stats).unstack() print(result) # min max count mean # data1 # 0 -3.678934 3.022862 100.0 0.029658 # 1 -2.319813 2.646502 100.0 0.094035 # 2 -2.873727 2.470840 100.0 0.023866 # 3 -2.196701 2.042251 100.0 0.021232 # 4 -2.154161 2.020809 100.0 0.110834 # 5 -2.723061 2.415626 100.0 0.057365 # 6 -2.291470 2.536159 100.0 0.020866 # 7 -2.064083 1.799356 100.0 -0.081025 # 8 -3.405679 1.792581 100.0 -0.009705 # 9 -2.469285 2.600849 100.0 -0.061721","title":"\u5206\u4f4d\u6570\u4e0e\u6876\u5206\u6790"},{"location":"python/DataAnalysis/ch07/#_12","text":"\u5728\u6e05\u9664\u7f3a\u5931\u503c\u65f6\uff0c\u6709\u65f6\u4f1a\u4f7f\u7528 dropna \u6765\u53bb\u9664\u7f3a\u5931\u503c\uff0c\u6709\u65f6\u4f7f\u7528\u4fee\u6b63\u503c\u6216\u6765\u81ea\u4e8e\u5176\u4ed6\u6570\u636e\u7684\u503c\u6765\u8f93\u5165\uff08\u586b\u5145\uff09\u5230 null \u503c\uff08 NA \uff09\u3002 fillna \u662f\u4e00\u4e2a\u53ef\u4ee5\u4f7f\u7528\u7684\u6b63\u786e\u5de5\u5177\u3002 \u4f8b\u5982\u4e0b\u9762\u4f8b\u5b50\u4e2d\u4f7f\u7528\u4f7f\u7528\u5e73\u5747\u503c\u6765\u586b\u5145NA\u503c\uff1a data = (100, 110, 120, 130, 140, 150) s = pd.Series(data) print(s) # 0 100 # 1 110 # 2 120 # 3 130 # 4 140 # 5 150 # dtype: float64 \u5c06\u6570\u636e\u4e2d\u7684\u4e00\u4e9b\u503c\u8bbe\u7f6e\u4e3a\u7f3a\u5931\u503c\uff1a s[::2] = np.nan print(s) # 0 NaN # 1 110.0 # 2 NaN # 3 130.0 # 4 NaN # 5 150.0 # dtype: float64 result = s.fillna(s.mean()) # 110, 130, 150\u7684\u5e73\u5747\u503c\u662f130 print(result) # 0 130.0 # 1 110.0 # 2 130.0 # 3 130.0 # 4 130.0 # 5 150.0 # dtype: float64 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u6309\u7ec4\u586b\u5145NA\u503c\uff1a \u65b9\u6cd51,\u5bf9\u6570\u636e\u5206\u7ec4\u540e\u4f7f\u7528 apply \u3002 \u65b9\u6cd52,\u5728\u6bcf\u4e2a\u6570\u636e\u5757\u4e0a\u90fd\u8c03\u7528 fillna \u7684\u51fd\u6570\u3002 data = (100, 110, 120, 130, 140, 150, 160, 170) states = ['Ohio', 'New York', 'Vermont', 'Florida', 'Oregon', 'Nevada', 'California', 'Idaho'] group_key = ['East'] * 4 + ['West'] * 4 # 4\u4e2aEast\u548c4\u4e2aWest\u62fc\u63a5\u7684\u5217\u8868list s = pd.Series(data, index=states) print(s) # Ohio 100 # New York 110 # Vermont 120 # Florida 130 # Oregon 140 # Nevada 150 # California 160 # Idaho 170 # dtype: int64 \u5c06\u6570\u636e\u4e2d\u7684\u4e00\u4e9b\u503c\u8bbe\u7f6e\u4e3a\u7f3a\u5931\u503c\uff1a s[['Vermont', 'Nevada', 'Idaho']] = np.nan print(s) # Ohio 100.0 # New York 110.0 # Vermont NaN # Florida 130.0 # Oregon 140.0 # Nevada NaN # California 160.0 # Idaho NaN # dtype: float64 result = s.groupby(group_key).mean() print(result) # East 113.333333 # West 150.000000 # dtype: float64 \u7528\u4e0a\u9762\u5f97\u51fa\u7684\u5206\u7ec4\u5e73\u5747\u503c\u6765\u586b\u5145NA\u3002 fill_mean = lambda g: g.fillna(g.mean()) result = s.groupby(group_key).apply(fill_mean) print(result) # Ohio 100.000000 # New York 110.000000 # Vermont 113.333333 # Florida 130.000000 # Oregon 140.000000 # Nevada 150.000000 # California 160.000000 # Idaho 150.000000 # dtype: float64 \u5982\u679c\u5df2\u7ecf\u5728\u4ee3\u7801\u4e2d\u4e3a\u6bcf\u4e2a\u5206\u7ec4\u9884\u5b9a\u4e49\u4e86\u586b\u5145\u503c\uff0c\u53ef\u4ee5\u5229\u7528\u6bcf\u4e2a\u5206\u7ec4\u90fd\u6709\u7684\u5185\u7f6e\u7684 name \u5c5e\u6027\uff0c\u5b9e\u73b0\u586b\u5145 NA \u3002 fill_value = {'East': 0.5, 'West': -1} fill_func = lambda g: g.fillna(fill_value[g.name]) result = s.groupby(group_key).apply(fill_func) print(result) # Ohio 100.0 # New York 110.0 # Vermont 0.5 # Florida 130.0 # Oregon 140.0 # Nevada -1.0 # California 160.0 # Idaho -1.0 # dtype: float64","title":"\u793a\u4f8b\uff1a\u4f7f\u7528\u6307\u5b9a\u5206\u7ec4\u503c\u586b\u5145\u7f3a\u5931\u503c"},{"location":"python/DataAnalysis/ch07/#_13","text":"\u5047\u8bbe\u60f3\u4ece\u5927\u6570\u636e\u96c6\u4e2d\u62bd\u53d6\u968f\u673a\u6837\u672c\uff08\u6709\u6216\u6ca1\u6709\u66ff\u6362\uff09\u4ee5\u7528\u4e8e\u8499\u7279\u5361\u7f57\u6a21\u62df\u76ee\u7684\u6216\u67d0\u4e9b\u5176\u4ed6\u5e94\u7528\u7a0b\u5e8f\u3002 \u6709\u5f88\u591a\u65b9\u6cd5\u6765\u6267\u884c\u201c\u62bd\u53d6\u201d\uff0c\u8fd9\u91cc\u4f7f\u7528Series\u7684sample\u65b9\u6cd5\u3002 \u4e3a\u4e86\u6f14\u793a\uff0c\u8fd9\u91cc\u4ecb\u7ecd\u4e00\u79cd\u6784\u9020\u4e00\u526f\u82f1\u5f0f\u6251\u514b\u724c\u7684\u65b9\u6cd5\uff1a # \u6885\u82b1clubs\u3001\u65b9\u5757diamonds\u3001\u7ea2\u6843hearts\u3001\u9ed1\u6843spades\u3002 suits = ['H', 'S', 'C', 'D'] card_val = (list(range(1, 11)) + [10] * 3) * 4 # card_val [ # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10 # ] base_names = ['A'] + list(range(2, 11)) + ['J', 'K', 'Q'] # base_names\uff1a ['A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'K', 'Q'] \u751f\u6210\u4e86\u4e00\u4e2a\u957f\u5ea6\u4e3a 52 \u7684Series, Series\u7684\u7d22\u5f15\u5305\u542b\u4e86\u724c\u540d\uff0cSeries\u7684\u503c\u53ef\u4ee5\u7528\u6e38\u620f\uff08\u4e3a\u4e86\u4fdd\u6301\u7b80\u5355\uff0c\u8ba9\u2019A\u2019\u4e3a1 \uff09\uff1a cards = [] for suit in ['H', 'S', 'C', 'D']: cards.extend(str(num) + suit for num in base_names) deck = pd.Series(card_val, index=cards) print(deck) # AH 1 # 2H 2 # 3H 3 # 4H 4 # 5H 5 # 6H 6 # 7H 7 # 8H 8 # 9H 9 # 10H 10 # JH 10 # KH 10 # QH 10 # AS 1 # 2S 2 # 3S 3 # 4S 4 # 5S 5 # 6S 6 # 7S 7 # 8S 8 # 9S 9 # 10S 10 # JS 10 # KS 10 # QS 10 # AC 1 # 2C 2 # 3C 3 # 4C 4 # 5C 5 # 6C 6 # 7C 7 # 8C 8 # 9C 9 # 10C 10 # JC 10 # KC 10 # QC 10 # AD 1 # 2D 2 # 3D 3 # 4D 4 # 5D 5 # 6D 6 # 7D 7 # 8D 8 # 9D 9 # 10D 10 # JD 10 # KD 10 # QD 10 # dtype: int64 \u4ece\u8fd9\u526f\u724c\u4e2d\u62ff\u51fa\u4e94\u5f20\u724c\u53ef\u4ee5\u5199\u6210\uff1a def draw(_deck, n=5): return _deck.sample(n) print(draw(deck)) # KD 10 # 2S 2 # 5C 5 # 6C 6 # QD 10 # dtype: int64 \u5047\u8bbe\u8981\u4ece\u6bcf\u4e2a\u82b1\u8272\u4e2d\u968f\u673a\u62bd\u53d6\u4e24\u5f20\u724c\u3002\u7531\u4e8e\u82b1\u8272\u662f\u724c\u540d\u7684\u6700\u540e\u4e24\u4e2a\u5b57\u7b26\uff0c\u53ef\u4ee5\u57fa\u4e8e\u8fd9\u70b9\u8fdb\u884c\u5206\u7ec4\uff0c\u5e76\u4f7f\u7528 apply \uff1a get_suit = lambda card: card[-1] # \u6700\u540e\u4e00\u4e2a\u5b57\u6bcd\u662f\u82b1\u8272 result = deck.groupby(get_suit).apply(draw, n=2) print(result) # C 10C 10 # 3C 3 # D KD 10 # AD 1 # H 5H 5 # 7H 7 # S 3S 3 # 5S 5 # dtype: int64 \u6216\u8005\u4e5f\u53ef\u4ee5\u5199\u6210\uff1a result = deck.groupby(get_suit, group_keys=False).apply(draw, n=2) print(result) # JC 10 # 8C 8 # QD 10 # 4D 4 # 10H 10 # 6H 6 # 7S 7 # KS 10 # dtype: int64","title":"\u793a\u4f8b\uff1a\u968f\u673a\u91c7\u6837\u4e0e\u6392\u5217"},{"location":"python/DataAnalysis/ch07/#_14","text":"\u5728 groupby \u7684\u62c6\u5206-\u5e94\u7528-\u8054\u5408\u7684\u8303\u5f0f\u4e0b\uff0cDataFrame\u7684\u5217\u95f4\u64cd\u4f5c\u6216\u4e24\u4e2aSeriese\u4e4b\u95f4\u7684\u64cd\u4f5c\uff0c\u4f8b\u5982\u5b9e\u73b0\u5206\u7ec4\u52a0\u6743\u5e73\u5747\u3002 \u4e0b\u9762\u4f8b\u5b50\uff0c\u4f7f\u7528\u4e00\u4e2a\u5305\u542b\u5206\u7ec4\u952e\u548c\u6743\u91cd\u503c\u7684\u6570\u636e\u96c6\uff1a dt = np.random.randn(8) wt = np.random.randn(8) df = pd.DataFrame( { 'category': ['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b'], 'data': dt, 'weight': wt } ) print(df) # category data weight # 0 a -0.250764 -0.085285 # 1 a 0.167155 -1.361254 # 2 a 0.399306 1.755542 # 3 a -0.514477 0.270124 # 4 b -0.005558 0.886514 # 5 b 0.607596 -1.384315 # 6 b -1.029627 -0.845340 # 7 b -0.294204 1.253965 \u901a\u8fc7 category \u8fdb\u884c\u5206\u7ec4\u52a0\u6743\u5e73\u5747\u5982\u4e0b\uff1a grouped = df.groupby('category') get_wavg = lambda g: np.average(g['data'], weights=g['weight']) result = grouped.apply(get_wavg) print(result) # category # a 0.614499 # b 3.863947 # dtype: float64 \u53e6\u4e00\u4e2a\u4f8b\u5b50\uff0c\u4e00\u4e2a\u4ece\u96c5\u864e\u8d22\u7ecf\u4e0a\u83b7\u5f97\u7684\u6570\u636e\u96c6\uff0c\u8be5\u6570\u636e\u96c6\u5305\u542b\u4e00\u4e9b\u6807\u666e500 \uff08SPX\u7b26\u53f7\uff09\u548c\u80a1\u7968\u7684\u6536\u76d8\u4ef7\uff1a close_px = pd.read_csv('../examples/stock_px_2.csv', parse_dates=True, index_col=0) print(close_px.info()) # # DatetimeIndex: 2214 entries, 2003-01-02 to 2011-10-14 # Data columns (total 4 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 AAPL 2214 non-null float64 # 1 MSFT 2214 non-null float64 # 2 XOM 2214 non-null float64 # 3 SPX 2214 non-null float64 # dtypes: float64(4) # memory usage: 86.5 KB # None print(close_px[-4:]) # AAPL MSFT XOM SPX # 2011-10-11 400.29 27.00 76.27 1195.54 # 2011-10-12 402.19 26.96 77.16 1207.25 # 2011-10-13 408.43 27.18 76.37 1203.66 # 2011-10-14 422.00 27.27 78.11 1224.58 \u76ee\u6807\u4efb\u52a1\uff1a\u8ba1\u7b97\u4e00\u4e2aDataFrame\uff0c\u5b83\u5305\u542b\u6807\u666e\u6307\u6570\uff08SPX\uff09\u6bcf\u65e5\u6536\u76ca\u7684\u5e74\u5ea6\u76f8\u5173\u6027\uff08\u901a\u8fc7\u767e\u5206\u6bd4\u53d8\u5316\u8ba1\u7b97\uff09\u3002 \u9996\u5148\u521b\u5efa\u4e00\u4e2a\u8ba1\u7b97\u6bcf\u5217\u4e0e\u2019SPX\u2019\u5217\u6210\u5bf9\u5173\u8054\u7684\u51fd\u6570\uff1a spx_corr = lambda x: x.corrwith(x['SPX']) \u4e4b\u540e\uff0c\u4f7f\u7528 pct_change \u8ba1\u7b97 close-px \u767e\u5206\u6bd4\u7684\u53d8\u5316\uff1a rets = close_px.pct_change().dropna() # Percentage change between the current and a prior element. print(rets) # AAPL MSFT XOM SPX # 2003-01-03 0.006757 0.001421 0.000684 -0.000484 # 2003-01-06 0.000000 0.017975 0.024624 0.022474 # ... ... ... ... ... # 2011-10-14 0.033225 0.003311 0.022784 0.017380 # [2213 rows x 4 columns] \u6700\u540e\uff0c\u6309\u5e74\u5bf9\u767e\u5206\u6bd4\u53d8\u5316\u8fdb\u884c\u5206\u7ec4\uff0c\u53ef\u4ee5\u4f7f\u7528\u5355\u884c\u51fd\u6570\u4ece\u6bcf\u4e2a\u884c\u6807\u7b7e\u4e2d\u63d0\u53d6\u6bcf\u4e2a datetime \u6807\u7b7e\u7684 year \u5c5e\u6027\uff1a get_year = lambda x: x.year by_year = rets.groupby(get_year) result = by_year.apply(spx_corr) print(result) # AAPL MSFT XOM SPX # 2003 0.541124 0.745174 0.661265 1.0 # 2004 0.374283 0.588531 0.557742 1.0 # 2005 0.467540 0.562374 0.631010 1.0 # 2006 0.428267 0.406126 0.518514 1.0 # 2007 0.508118 0.658770 0.786264 1.0 # 2008 0.681434 0.804626 0.828303 1.0 # 2009 0.707103 0.654902 0.797921 1.0 # 2010 0.710105 0.730118 0.839057 1.0 # 2011 0.691931 0.800996 0.859975 1.0 \u53ef\u4ee5\u8ba1\u7b97\u5185\u90e8\u5217\u76f8\u5173\u6027\u3002\u8fd9\u91cc\u8ba1\u7b97\u4e86\u82f9\u679c\u548c\u5fae\u8f6f\u7684\u5e74\u5ea6\u76f8\u5173\u6027\uff1a result = by_year.apply(lambda g: g['AAPL'].corr(g['MSFT'])) print(result) # 2003 0.480868 # 2004 0.259024 # 2005 0.300093 # 2006 0.161735 # 2007 0.417738 # 2008 0.611901 # 2009 0.432738 # 2010 0.571946 # 2011 0.581987 # dtype: float64","title":"\u793a\u4f8b\uff1a\u5206\u7ec4\u52a0\u6743\u5e73\u5747\u548c\u76f8\u5173\u6027"},{"location":"python/DataAnalysis/ch07/#_15","text":"\u5b9a\u4e49\u4ee5\u4e0b regress \uff08\u56de\u5f52\uff09\u51fd\u6570\uff08\u4f7f\u7528 statsmodels \u8ba1\u91cf\u7ecf\u6d4e\u5b66\u5e93\uff09\uff0c\u8be5\u51fd\u6570\u5bf9\u6bcf\u4e2a\u6570\u636e\u5757\u6267\u884c\u666e\u901a\u6700\u5c0f\u4e8c\u4e58\uff08OLS\uff09\u56de\u5f52\uff1a def regress(data, yvar, xvars): Y = data[yvar] X = data[xvars] X['intercept'] = 1. result = sm.OLS(Y, X).fit() return result.params \u73b0\u5728\u8981\u8ba1\u7b97AAPL\u5728SPX\u56de\u62a5\u4e0a\u7684\u5e74\u5ea6\u7ebf\u6027\u56de\u5f52\uff1a result = by_year.apply(regress, 'AAPL', ['SPX']) print(result) # SPX intercept # 2003 1.195406 0.000710 # 2004 1.363463 0.004201 # 2005 1.766415 0.003246 # 2006 1.645496 0.000080 # 2007 1.198761 0.003438 # 2008 0.968016 -0.001110 # 2009 0.879103 0.002954 # 2010 1.052608 0.001261 # 2011 0.806605 0.001514","title":"\u793a\u4f8b\uff1a\u9010\u7ec4\u7ebf\u6027\u56de\u5f52"},{"location":"python/DataAnalysis/ch07/#_16","text":"","title":"\u6570\u636e\u900f\u89c6\u8868\u4e0e\u4ea4\u53c9\u8868"},{"location":"python/DataAnalysis/ch07/#_17","text":"\u6570\u636e\u900f\u89c6\u8868\u662f\u7535\u5b50\u8868\u683c\u7a0b\u5e8f\u548c\u5176\u4ed6\u6570\u636e\u5206\u6790\u8f6f\u4ef6\u4e2d\u5e38\u89c1\u7684\u6570\u636e\u6c47\u603b\u5de5\u5177\u3002 \u5b83\u6839\u636e\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u805a\u5408\u4e00\u5f20\u8868\u7684\u6570\u636e\uff0c\u5c06\u6570\u636e\u5728\u77e9\u5f62\u683c\u5f0f\u4e2d\u6392\u5217\uff0c\u5176\u4e2d\u4e00\u4e9b\u5206\u7ec4\u952e\u662f\u6cbf\u7740\u884c\u7684\uff0c\u53e6\u4e00\u4e9b\u662f\u6cbf\u7740\u5217\u7684\u3002 Python\u4e2d\u7684pandas\u900f\u89c6\u8868\u662f\u901a\u8fc7\u8fd9\u91cc\u6240\u4ecb\u7ecd\u7684groupby\u5de5\u5177\u4ee5\u53ca\u4f7f\u7528\u5206\u5c42\u7d22\u5f15\u7684\u91cd\u5851\u64cd\u4f5c\u5b9e\u73b0\u7684\u3002 DataFrame\u62e5\u6709\u4e00\u4e2a pivot_table \u65b9\u6cd5\uff0c\u5e76\u4e14\u8fd8\u6709\u8fd8\u4e00\u4e2a\u9876\u5c42\u7684 pandas.pivot_table \u51fd\u6570\u3002 \u9664\u4e86\u4e3a groupby \u63d0\u4f9b\u4e00\u4e2a\u65b9\u4fbf\u63a5\u53e3\uff0c pivot_table \u8fd8\u53ef\u4ee5\u6dfb\u52a0\u90e8\u5206\u603b\u8ba1\uff0c\u4e5f\u79f0\u4f5c\u8fb9\u8ddd\u3002 import pandas as pd import numpy as np \u6839\u636e\u4e0b\u9762\u7684\u5c0f\u8d39\u6570\u636e\u96c6\uff0c\u8ba1\u7b97\u4e00\u5f20\u5728\u884c\u65b9\u5411\u4e0a\u6309 day \u548c smoker \u6392\u5217\u7684\u5206\u7ec4\u5e73\u5747\u503c\uff08\u9ed8\u8ba4\u7684 pivot_table \u805a\u5408\u7c7b\u578b\uff09\u7684\u8868\u3002 pivot_table \u9009\u9879\uff1a values: \u9700\u8981\u805a\u5408\u7684\u5217\u540d\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u805a\u5408\u6240\u6709\u6570\u503c\u578b\u7684\u5217\u3002 index: \u5728\u7ed3\u679c\u900f\u89c6\u8868\u7684\u884c\u4e0a\u8fdb\u884c\u5206\u7ec4\u7684\u5217\u540d\u6216\u8005\u5176\u4ed6\u5206\u7ec4\u952e\u3002 tips = pd.read_csv('../examples/tips.csv') tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) \u6837\u672c\u6570\u636e\u3002 print(tips.head(5)) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 \u8ba1\u7b97\u5728\u884c\u65b9\u5411\u4e0a\u6309 day \u548c smoker \u6392\u5217\u7684\u5206\u7ec4\u5e73\u5747\u503c\u3002\u4e5f\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528 groupby \u5b9e\u73b0\u3002 result = tips.pivot_table(index=['day', 'smoker']) print(result) # size tip tip_pct total_bill # day smoker # Fri No 2.250000 2.812500 0.179740 18.420000 # Yes 2.066667 2.714000 0.216293 16.813333 # Sat No 2.555556 3.102889 0.190412 19.661778 # Yes 2.476190 2.875476 0.179833 21.276667 # Sun No 2.929825 3.167895 0.193617 20.506667 # Yes 2.578947 3.516842 0.322021 24.120000 # Thur No 2.488889 2.673778 0.193424 17.113111 # Yes 2.352941 3.030000 0.198508 19.190588 \u5728 tip_pct \u548c size \u4e0a\u8fdb\u884c\u805a\u5408\uff0c\u5e76\u6839\u636e time \u5206\u7ec4\u3002\u5c06\u628a smoker \u653e\u5165\u8868\u7684\u5217\uff0c\u800c\u5c06 day \u653e\u5165\u8868\u7684\u884c\uff1a result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker' ) print(result) # size tip_pct # smoker No Yes No Yes # time day # Dinner Fri 2.000000 2.222222 0.162612 0.202545 # Sat 2.555556 2.476190 0.190412 0.179833 # Sun 2.929825 2.578947 0.193617 0.322021 # Thur 2.000000 NaN 0.190114 NaN # Lunch Fri 3.000000 1.833333 0.231125 0.236915 # Thur 2.500000 2.352941 0.193499 0.198508 \u901a\u8fc7\u4f20\u9012 margins=True \u6765\u6269\u5145\u8fd9\u4e2a\u8868\u6765\u5305\u542b\u90e8\u5206\u603b\u8ba1\u3002\u8fd9\u4f1a\u6dfb\u52a0 All \u884c\u548c\u5217\u6807\u7b7e\uff0c\u5176\u4e2d\u76f8\u5e94\u7684\u503c\u662f\u5355\u5c42\u4e2d\u6240\u6709\u6570\u636e\u7684\u5206\u7ec4\u7edf\u8ba1\u503c\u3002 \u8fd9\u91cc All \u7684\u503c\u662f\u5747\u503c\uff0c\u4e14\u8be5\u5747\u503c\u662f\u4e0d\u8003\u8651\u5438\u70df\u8005\u4e0e\u975e\u5438\u70df\u8005\uff08 All \u5217\uff09\u6216\u884c\u5206\u7ec4\u4e2d\u4efb\u4f55\u4e24\u7ea7\u7684\uff08 All \u884c\uff09\u3002 result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker', margins=True ) print(result) # size tip_pct # smoker No Yes All No Yes All # time day # Dinner Fri 2.000000 2.222222 2.166667 0.162612 0.202545 0.192562 # Sat 2.555556 2.476190 2.517241 0.190412 0.179833 0.185305 # Sun 2.929825 2.578947 2.842105 0.193617 0.322021 0.225718 # Thur 2.000000 NaN 2.000000 0.190114 NaN 0.190114 # Lunch Fri 3.000000 1.833333 2.000000 0.231125 0.236915 0.236088 # Thur 2.500000 2.352941 2.459016 0.193499 0.198508 0.194895 # All 2.668874 2.408602 2.569672 0.192237 0.218176 0.202123 \u8981\u4f7f\u7528\u4e0d\u540c\u7684\u805a\u5408\u51fd\u6570\u65f6\uff0c\u5c06\u51fd\u6570\u4f20\u9012\u7ed9 aggfunc \u3002\u4f8b\u5982\uff0c count \u6216\u8005 len \u5c06\u7ed9\u51fa\u4e00\u5f20\u5206\u7ec4\u5927\u5c0f\u7684\u4ea4\u53c9\u8868\uff08\u8ba1\u6570\u6216\u51fa\u73b0\u9891\u7387\uff09\uff1a result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker', aggfunc=len, margins=True ) print(result) # size tip_pct # smoker No Yes All No Yes All # time day # Dinner Fri 3.0 9.0 12 3.0 9.0 12 # Sat 45.0 42.0 87 45.0 42.0 87 # Sun 57.0 19.0 76 57.0 19.0 76 # Thur 1.0 NaN 1 1.0 NaN 1 # Lunch Fri 1.0 6.0 7 1.0 6.0 7 # Thur 44.0 17.0 61 44.0 17.0 61 # All 151.0 93.0 244 151.0 93.0 244 \u5bf9\u4e8e\u7a7a\u503c NA \uff0c\u4f20\u9012\u4e00\u4e2a fill_value \u3002 result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker', aggfunc='mean', fill_value=0, margins=True ) print(result) # size tip_pct # smoker No Yes All No Yes All # time day # Dinner Fri 2.000000 2.222222 2.166667 0.162612 0.202545 0.192562 # Sat 2.555556 2.476190 2.517241 0.190412 0.179833 0.185305 # Sun 2.929825 2.578947 2.842105 0.193617 0.322021 0.225718 # Thur 2.000000 0.000000 2.000000 0.190114 0.000000 0.190114 # Lunch Fri 3.000000 1.833333 2.000000 0.231125 0.236915 0.236088 # Thur 2.500000 2.352941 2.459016 0.193499 0.198508 0.194895 # All 2.668874 2.408602 2.569672 0.192237 0.218176 0.202123","title":"\u6570\u636e\u900f\u89c6\u8868"},{"location":"python/DataAnalysis/ch07/#crosstab","text":"\u4ea4\u53c9\u8868\uff08\u7b80\u5199\u4e3acrosstab\uff09\u662f\u6570\u636e\u900f\u89c6\u8868\u7684\u4e00\u4e2a\u7279\u6b8a\u60c5\u51b5\uff0c\u8ba1\u7b97\u7684\u662f\u5206\u7ec4\u4e2d\u7684\u9891\u7387\u3002 crosstab \u7684\u524d\u4e24\u4e2a\u53c2\u6570\u53ef\u662f\u6570\u7ec4\u3001Series\u6216\u6570\u7ec4\u7684\u5217\u8868\u3002 sample = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] nationality = ['USA', 'Japan', 'USA', 'Japan', 'Japan', 'Japan', 'USA', 'USA', 'Japan', 'USA'] handedness = ['Right-handed', 'Left-handed', 'Right-handed', 'Right-handed', 'Left-handed', 'Right-handed', 'Right-handed', 'Left-handed', 'Right-handed', 'Right-handed'] df = pd.DataFrame( { 'sample': sample, 'nationality': nationality, 'handedness': handedness } ) print(df) # sample nationality handedness # 0 1 USA Right-handed # 1 2 Japan Left-handed # 2 3 USA Right-handed # 3 4 Japan Right-handed # 4 5 Japan Left-handed # 5 6 Japan Right-handed # 6 7 USA Right-handed # 7 8 USA Left-handed # 8 9 Japan Right-handed # 9 10 USA Right-handed \u6309\u7167\u56fd\u7c4d\u548c\u60ef\u7528\u6027\u6765\u603b\u7ed3\u8fd9\u4e9b\u6570\u636e\uff0c\u53ef\u4ee5\u4f7f\u7528 pivot_table \u6765\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\uff0c\u4f46\u662f pandas.crosstable \u51fd\u6570\u66f4\u4e3a\u65b9\u4fbf\uff1a result = pd.crosstab(df.nationality, df.handedness, margins=True) print(result) # handedness Left-handed Right-handed All # nationality # Japan 2 3 5 # USA 1 4 5 # All 3 7 10 \u5728\u5c0f\u8d39\u6570\u636e\u4e2d\u53ef\u4ee5\u8fd9\u4e48\u505a\uff1a result = pd.crosstab(['tips.time', tips.day], tips.smoker, margins=True) print(result) # smoker No Yes All # row_0 day # tips.time Fri 4 15 19 # Sat 45 42 87 # Sun 57 19 76 # Thur 45 17 62 # All 151 93 244","title":"\u4ea4\u53c9\u8868\uff1acrosstab"},{"location":"python/DataAnalysis/ch08/","text":"\u65f6\u95f4\u5e8f\u5217 \u00b6 \u65e5\u671f\u548c\u65f6\u95f4\u6570\u636e\u7684\u7c7b\u578b\u53ca\u5de5\u5177 \u00b6 \u65f6\u95f4\u5e8f\u5217\u6570\u636e\u5728\u5f88\u591a\u9886\u57df\u90fd\u662f\u91cd\u8981\u7684\u7ed3\u6784\u5316\u6570\u636e\u5f62\u5f0f\u3002\u5728\u591a\u4e2a\u65f6\u95f4\u70b9\u89c2\u6d4b\u6216\u6d4b\u91cf\u7684\u6570\u636e\u5f62\u6210\u4e86\u65f6\u95f4\u5e8f\u5217\u3002 \u8bb8\u591a\u65f6\u95f4\u5e8f\u5217\u662f\u56fa\u5b9a\u9891\u7387\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\u6570\u636e\u662f\u6839\u636e\u76f8\u540c\u7684\u89c4\u5219\u5b9a\u671f\u51fa\u73b0\u7684\uff0c\u4f8b\u5982\u6bcf15\u79d2\u3001\u6bcf5\u5206\u949f\u6216\u6bcf\u67081\u6b21\u3002 \u65f6\u95f4\u5e8f\u5217\u4e5f\u53ef\u4ee5\u662f\u4e0d\u89c4\u5219\u7684\uff0c\u6ca1\u6709\u56fa\u5b9a\u7684\u65f6\u95f4\u5355\u4f4d\u6216\u5355\u4f4d\u95f4\u7684\u504f\u79fb\u91cf\u3002 \u5982\u4f55\u6807\u8bb0\u548c\u5f15\u7528\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u53d6\u51b3\u4e8e\u5e94\u7528\u7a0b\u5e8f\uff0c\u65f6\u95f4\u5e8f\u5217\u5305\u62ec\uff1a \u65f6\u95f4\u6233\uff0c\u5177\u4f53\u7684\u65f6\u523b\u3002 \u56fa\u5b9a\u7684\u65f6\u95f4\u533a\u95f4\uff0c\u4f8b\u59822007\u76841\u6708\u6216\u6574\u4e2a2010\u5e74\u3002 \u65f6\u95f4\u95f4\u9694\uff0c\u7531\u5f00\u59cb\u548c\u7ed3\u675f\u65f6\u95f4\u6233\u8868\u793a\u3002\u65f6\u95f4\u533a\u95f4\u53ef\u4ee5\u88ab\u8ba4\u4e3a\u662f\u95f4\u9694\u7684\u7279\u6b8a\u60c5\u51b5\u3002 \u5b9e\u9a8c\u65f6\u95f4\u6216\u6d88\u8017\u65f6\u95f4\u3002\u6bcf\u4e2a\u65f6\u95f4\u6233\u662f\u76f8\u5bf9\u4e8e\u7279\u5b9a\u5f00\u59cb\u65f6\u95f4\u7684\u65f6\u95f4\u7684\u91cf\u5ea6\uff08\u4f8b\u5982\uff0c\u81ea\u4ece\u88ab\u653e\u7f6e\u5728\u70e4\u7bb1\u4e2d\u6bcf\u79d2\u70d8\u70e4\u7684\u997c\u5e72\u7684\u76f4\u5f84\uff09\u3002 \u76ee\u524d\u4e3b\u8981\u5173\u6ce8\u524d\u4e09\u7c7b\u4e2d\u7684\u65f6\u95f4\u5e8f\u5217\u3002 from datetime import datetime, timedelta import datetime as dt from dateutil.parser import parse import pandas as pd datetime \u00b6 datetime\u683c\u5f0f\u7b26\uff1a %a \u661f\u671f\u7684\u82f1\u6587\u5355\u8bcd\u7684\u7f29\u5199\uff1a\u5982\u661f\u671f\u4e00\uff0c \u5219\u8fd4\u56de Mon %A \u661f\u671f\u7684\u82f1\u6587\u5355\u8bcd\u7684\u5168\u62fc\uff1a\u5982\u661f\u671f\u4e00\uff0c\u8fd4\u56de Monday %b \u6708\u4efd\u7684\u82f1\u6587\u5355\u8bcd\u7684\u7f29\u5199\uff1a\u5982\u4e00\u6708\uff0c \u5219\u8fd4\u56de Jan %B \u6708\u4efd\u7684\u5f15\u6587\u5355\u8bcd\u7684\u7f29\u5199\uff1a\u5982\u4e00\u6708\uff0c \u5219\u8fd4\u56de January %c \u8fd4\u56dedatetime\u7684\u5b57\u7b26\u4e32\u8868\u793a\uff0c\u598203/08/15 23:01:26 %d \u8fd4\u56de\u7684\u662f\u5f53\u524d\u65f6\u95f4\u662f\u5f53\u524d\u6708\u7684\u7b2c\u51e0\u5929 %f \u5fae\u79d2\u7684\u8868\u793a\uff1a \u8303\u56f4: [0,999999] %H \u4ee524\u5c0f\u65f6\u5236\u8868\u793a\u5f53\u524d\u5c0f\u65f6 %I \u4ee512\u5c0f\u65f6\u5236\u8868\u793a\u5f53\u524d\u5c0f\u65f6 %m \u8fd4\u56de\u6708\u4efd \u8303\u56f4[0,12] %M \u8fd4\u56de\u5206\u949f\u6570 \u8303\u56f4 [0,59] %P \u8fd4\u56de\u662f\u4e0a\u5348\u8fd8\u662f\u4e0b\u5348\u2013AM or PM %S \u8fd4\u56de\u79d2\u6570 \u8303\u56f4 [0,61]\u3002\u3002\u3002\u624b\u518c\u8bf4\u660e\u7684 %U \u8fd4\u56de\u5f53\u5468\u662f\u5f53\u5e74\u7684\u7b2c\u51e0\u5468 \u4ee5\u5468\u65e5\u4e3a\u7b2c\u4e00\u5929 %W \u8fd4\u56de\u5f53\u5468\u662f\u5f53\u5e74\u7684\u7b2c\u51e0\u5468 \u4ee5\u5468\u4e00\u4e3a\u7b2c\u4e00\u5929 %w \u5f53\u5929\u5728\u5f53\u5468\u7684\u5929\u6570\uff0c\u8303\u56f4\u4e3a[0, 6]\uff0c6\u8868\u793a\u661f\u671f\u5929 %x \u65e5\u671f\u7684\u5b57\u7b26\u4e32\u8868\u793a \uff1a03/08/15 %X \u65f6\u95f4\u7684\u5b57\u7b26\u4e32\u8868\u793a \uff1a23:22:08 %y \u4e24\u4e2a\u6570\u5b57\u8868\u793a\u7684\u5e74\u4efd 15 %Y \u56db\u4e2a\u6570\u5b57\u8868\u793a\u7684\u5e74\u4efd 2015 %z \u4e0eutc\u65f6\u95f4\u7684\u95f4\u9694 \uff08\u5982\u679c\u662f\u672c\u5730\u65f6\u95f4\uff0c\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\uff09 %Z \u65f6\u533a\u540d\u79f0\uff08\u5982\u679c\u662f\u672c\u5730\u65f6\u95f4\uff0c\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\uff09 datestrs = ['2020/5/6', '2021/10/1'] # \u6ce8\u610f\u533a\u5206datetime\u6a21\u5757\u548cdatetime\u7c7b\uff0c\u540d\u5b57\u76f8\u540c\uff0c\u5bb9\u6613\u5f15\u8d77\u9519\u8bef\u3002 # \u6bd4\u5982datetime.datetime\u5c31\u62a5\u9519type object 'datetime.datetime' has no attribute 'datetime' print(datetime) # print(dt) # Python\u6807\u51c6\u5e93\u5305\u542b\u4e86\u65e5\u671f\u548c\u65f6\u95f4\u6570\u636e\u7684\u7c7b\u578b\u3002 datetime \u3001 time \u548c calendar \u6a21\u5757\u662f\u5f00\u59cb\u5904\u7406\u65f6\u95f4\u6570\u636e\u7684\u4e3b\u8981\u5185\u5bb9\u3002 datetime.datetime \u7c7b\u578b\uff0c\u6216\u7b80\u5199\u4e3a datetime \uff0c\u662f\u5e7f\u6cdb\u4f7f\u7528\u7684\u3002 now = datetime.now() print(now) # 2021-10-07 20:24:43.834293 result = dt.datetime(2021, 10, 7, 20, 26, 00, 72973) print(result) # 2021-10-07 20:26:00.072973 datetime \u65e2\u5b58\u50a8\u4e86\u65e5\u671f\uff0c\u4e5f\u5b58\u50a8\u4e86\u7ec6\u5316\u5230\u5fae\u79d2\u7684\u65f6\u95f4\u3002 timedelta \u8868\u793a\u4e24\u4e2a datetime \u5bf9\u8c61\u7684\u65f6\u95f4\u5dee\u3002 delta = datetime(2021, 10, 7) - datetime(2021, 9, 7) print(delta) # 30 days, 0:00:00 print(delta.days) # 30 print(delta.seconds) # 0 result = dt.timedelta(926, 56700) print(result) # 926 days, 15:45:00 \u53ef\u4ee5\u4e3a\u4e00\u4e2a datetime \u5bf9\u8c61\u52a0\u4e0a\uff08\u6216\u51cf\u53bb\uff09\u4e00\u4e2a timedelta \u6216\u5176\u6574\u6570\u500d\u6765\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684 datetime \u5bf9\u8c61\u3002 start = datetime(2021, 10, 7) result = start + timedelta(12) print(result) # 2021-10-19 00:00:00 result = start - 2 * timedelta(5) print(result) # 2021-09-27 00:00:00 \u5b57\u7b26\u4e32\u4e0edatetime\u4e92\u76f8\u8f6c\u6362 \u00b6 \u4f7f\u7528 str \u65b9\u6cd5\u6216\u4f20\u9012\u4e00\u4e2a\u6307\u5b9a\u7684\u683c\u5f0f\u7ed9 strftime \u65b9\u6cd5\u6765\u5bf9 datetime \u5bf9\u8c61\u548cpandas\u7684 Timestamp \u5bf9\u8c61\u8fdb\u884c\u683c\u5f0f\u5316\u3002 stamp = datetime(2021, 10, 7) result = str(stamp) print(result) # 2021-10-07 00:00:00 \u4f7f\u7528 datetime.srtptime \u548c datetime \u683c\u5f0f\u7b26\uff0c\u628a\u5b57\u7b26\u4e32\u8f6c\u6362\u65e5\u671f\u3002 datetime.strptime \u662f\u5728\u5df2\u77e5\u683c\u5f0f\u7684\u60c5\u51b5\u4e0b\u8f6c\u6362\u65e5\u671f\u7684\u597d\u65b9\u5f0f\u3002 value = '2021-10-7' result = datetime.strptime(value, '%Y-%m-%d') print(result) # 2021-10-07 00:00:00 datestrs = ['2020/5/6', '2021/10/1'] result = [datetime.strptime(x, '%Y/%m/%d') for x in datestrs] print(result) # [datetime.datetime(2020, 5, 6, 0, 0), datetime.datetime(2021, 10, 1, 0, 0)] dateutil \u89e3\u6790\u901a\u7528\u65e5\u671f\u683c\u5f0f\uff1a print(parse('2020/5/6')) # 2020-05-06 00:00:00 print(parse('Jan 31, 2021 10:25 AM')) # 2021-01-31 10:25:00 print(parse('5/6/2021', dayfirst=True)) # \u65e5\u671f\u51fa\u73b0\u5728\u6708\u4efd\u4e4b\u524d # 2021-06-05 00:00:00 pandas\u4e3b\u8981\u662f\u9762\u5411\u5904\u7406\u65e5\u671f\u6570\u7ec4\u7684\uff0c\u65e0\u8bba\u662f\u7528\u4f5c\u8f74\u7d22\u5f15\u8fd8\u662f\u7528\u4f5cDataFrame\u4e2d\u7684\u5217\u3002 to_datetime \u65b9\u6cd5\u53ef\u4ee5\u8f6c\u6362\u5f88\u591a\u4e0d\u540c\u7684\u65e5\u671f\u8868\u793a\u683c\u5f0f\u3002 to_datetime \u65b9\u6cd5\u8fd8\u53ef\u4ee5\u5904\u7406\u90a3\u4e9b\u88ab\u8ba4\u4e3a\u662f\u7f3a\u5931\u503c\u7684\u503c\uff08None\u3001\u7a7a\u5b57\u7b26\u4e32\u7b49\uff09\u3002 NaT \uff08Not a time\uff09\u662fpandas\u4e2d\u65f6\u95f4\u6233\u6570\u636e\u7684\u662fnull\u503c\u3002 datestrs = ['2020/5/6 12:00:00', '2021/10/1 09:00:00'] result = pd.to_datetime(datestrs) print(result) # DatetimeIndex(['2020-05-06 12:00:00', '2021-10-01 09:00:00'], dtype='datetime64[ns]', freq=None) idx = pd.to_datetime(datestrs + [None]) print(idx) # DatetimeIndex(['2020-05-06 12:00:00', '2021-10-01 09:00:00', 'NaT'], dtype='datetime64[ns]', freq=None) print(idx[2]) # NaT print(pd.isnull(idx)) # [False False True] \u65f6\u95f4\u5e8f\u5217\u57fa\u7840 \u00b6 from datetime import datetime import pandas as pd import numpy as np DatetimeIndex \u00b6 pandas\u4e2d\u7684\u57fa\u7840\u65f6\u95f4\u5e8f\u5217\u79cd\u7c7b\u662f\u7531\u65f6\u95f4\u6233\u7d22\u5f15\u7684Series\uff0c\u5728pandas\u5916\u90e8\u5219\u901a\u5e38\u8868\u793a\u4e3aPython\u5b57\u7b26\u4e32\u6216 datetime \u5bf9\u8c61\u3002 \u6240\u6709\u4f7f\u7528 datetime \u5bf9\u8c61\u7684\u5730\u65b9\u90fd\u53ef\u4ee5\u7528 Timestamp \u3002 dates = [ datetime(2021, 10, 1), datetime(2021, 10, 3), datetime(2021, 10, 5), datetime(2021, 10, 7), datetime(2021, 10, 9), datetime(2021, 10, 11) ] data = np.random.rand(6) ts = pd.Series(data, index=dates) print(ts) # 2021-10-01 0.678297 # 2021-10-03 0.538631 # 2021-10-05 0.934413 # 2021-10-07 0.018534 # 2021-10-09 0.938441 # 2021-10-11 0.173329 # dtype: float64 \u8fd9\u4e9b datetime \u5bf9\u8c61\u88ab\u653e\u5165 DatetimeIndex \u4e2d\u3002 print(ts.index) # DatetimeIndex(['2021-10-01', '2021-10-03', '2021-10-05', '2021-10-07', # '2021-10-09', '2021-10-11'], # dtype='datetime64[ns]', freq=None) DatetimeIndex \u4e2d\u7684\u6807\u91cf\u503c\u662f pandas \u7684 Timestamp \u5bf9\u8c61\uff1a stamp = ts.index[0] print(stamp) # 2021-10-01 00:00:00 \u548c\u5176\u4ed6Series\u7c7b\u4f3c\uff0c\u4e0d\u540c\u7d22\u5f15\u7684\u65f6\u95f4\u5e8f\u5217\u4e4b\u95f4\u7684\u7b97\u672f\u8fd0\u7b97\u5728\u65e5\u671f\u4e0a\u81ea\u52a8\u5bf9\u9f50\uff1a print(ts + ts[::2]) # ts[::2]\u4f1a\u5c06ts\u4e2d\u6bcf\u9694\u4e00\u4e2a\u7684\u5143\u7d20\u9009\u62e9\u51fa # 2021-10-01 1.356595 # 2021-10-03 NaN # 2021-10-05 1.868825 # 2021-10-07 NaN # 2021-10-09 1.876883 # 2021-10-11 NaN # dtype: float64 pandas\u4f7f\u7528NumPy\u7684 datetime64 \u6570\u636e\u7c7b\u578b\u5728\u7eb3\u79d2\u7ea7\u7684\u5206\u8fa8\u7387\u4e0b\u5b58\u50a8\u65f6\u95f4\u6233 print(ts.index.dtype) # datetime64[ns] \u7d22\u5f15\u3001\u9009\u62e9\u3001\u5b50\u96c6 \u00b6 \u5f53\u57fa\u4e8e\u6807\u7b7e\u8fdb\u884c\u7d22\u5f15\u548c\u9009\u62e9\u65f6\uff0c\u65f6\u95f4\u5e8f\u5217\u7684\u884c\u4e3a\u548c\u5176\u4ed6\u7684pandas.Series\u7c7b\u4f3c\uff1a stamp = ts.index[2] print(ts[stamp]) # 0.9344125159374457 \u5bf9\u5e942021-10-05 \u4e5f\u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u80fd\u89e3\u91ca\u4e3a\u65e5\u671f\u7684\u5b57\u7b26\u4e32\uff1a print(ts['10/9/2021']) print(ts['20211003']) \u5bf9\u4e00\u4e2a\u957f\u7684\u65f6\u95f4\u5e8f\u5217\uff0c\u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u5e74\u4efd\u6216\u4e00\u4e2a\u5e74\u4efd\u548c\u6708\u4efd\u6765\u9009\u62e9\u6570\u636e\u5207\u7247\uff1a data = np.random.randn(1000) longer_ts = pd.Series( data, index=pd.date_range('1/1/2021', periods=1000) ) print(longer_ts) # 2021-01-01 -0.009192 # 2021-01-02 -1.079068 # 2021-01-03 -1.851176 # 2021-01-04 1.347109 # 2021-01-05 -0.236394 # ... # 2023-09-23 -1.317943 # 2023-09-24 0.201741 # 2023-09-25 0.442282 # 2023-09-26 0.176137 # 2023-09-27 1.146437 # Freq: D, Length: 1000, dtype: float64 \u5b57\u7b26\u4e32\u20192001\u2019\u88ab\u89e3\u91ca\u4e3a\u4e00\u4e2a\u5e74\u4efd\uff0c\u5e76\u9009\u62e9\u4e86\u76f8\u5e94\u7684\u65f6\u95f4\u533a\u95f4\u3002 print(longer_ts['2021']) # 2021-01-01 2.170411 # 2021-01-02 1.186933 # 2021-01-03 0.399262 # 2021-01-04 -1.042606 # 2021-01-05 2.082112 # ... # 2021-12-27 -0.988282 # 2021-12-28 0.598683 # 2021-12-29 2.770580 # 2021-12-30 -1.463262 # 2021-12-31 -1.642846 # Freq: D, Length: 365, dtype: float64 \u6307\u5b9a\u4e86\u5e74\u4efd\u548c\u6708\u4efd\u4e5f\u662f\u6709\u6548\u7684\u3002 print(longer_ts['2021-10']) # 2021-10-01 0.712265 # 2021-10-02 1.195221 # 2021-10-03 -1.930220 # 2021-10-04 -0.720816 # 2021-10-05 0.081777 # 2021-10-06 -0.037466 # 2021-10-07 3.737303 # 2021-10-08 1.620383 # 2021-10-09 0.990797 # 2021-10-10 0.507850 # 2021-10-11 0.846935 # 2021-10-12 0.996947 # 2021-10-13 -1.078558 # 2021-10-14 0.871832 # 2021-10-15 -0.591698 # 2021-10-16 -0.805463 # 2021-10-17 0.160528 # 2021-10-18 -0.028474 # 2021-10-19 2.305579 # 2021-10-20 -1.132288 # 2021-10-21 0.649980 # 2021-10-22 0.615327 # 2021-10-23 0.185108 # 2021-10-24 0.857199 # 2021-10-25 -1.473752 # 2021-10-26 -0.895161 # 2021-10-27 -0.432717 # 2021-10-28 0.734504 # 2021-10-29 1.892493 # 2021-10-30 0.456619 # 2021-10-31 -0.255288 # Freq: D, dtype: float64 \u4f7f\u7528 datetime \u5bf9\u8c61\u8fdb\u884c\u5207\u7247\u4e5f\u662f\u53ef\u4ee5\u7684\uff1a print(longer_ts[datetime(2023, 1, 6):]) # 2023-01-06 0.952591 # 2023-01-07 -0.900259 # 2023-01-08 0.925332 # 2023-01-09 0.173215 # 2023-01-10 -0.507791 # ... # 2023-09-23 -0.319989 # 2023-09-24 -1.105417 # 2023-09-25 -2.118769 # 2023-09-26 0.009420 # 2023-09-27 -0.310281 # Freq: D, Length: 265, dtype: float64 \u56e0\u4e3a\u5927\u90e8\u5206\u7684\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u662f\u6309\u65f6\u95f4\u987a\u5e8f\u6392\u5e8f\u7684\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e0d\u5305\u542b\u5728\u65f6\u95f4\u5e8f\u5217\u4e2d\u7684\u65f6\u95f4\u6233\u8fdb\u884c\u5207\u7247\uff0c\u4ee5\u6267\u884c\u8303\u56f4\u67e5\u8be2\uff1a print(longer_ts['2021/10/1':'2021/10/5']) # 2021-10-01 -0.591853 # 2021-10-02 -1.554564 # 2021-10-03 -0.712585 # 2021-10-04 -0.326657 # 2021-10-05 1.044887 # Freq: D, dtype: float64 \u4f7f\u7528 truncate \u5728\u4e24\u4e2a\u65e5\u671f\u95f4\u5bf9Series\u8fdb\u884c\u5207\u7247\uff1a print(longer_ts.truncate(after='2021/10/1')) # 2021-01-01 -0.906685 # 2021-01-02 -0.470732 # 2021-01-03 -0.041316 # 2021-01-04 -0.287356 # 2021-01-05 0.104268 # ... # 2021-09-27 -0.669198 # 2021-09-28 -2.222169 # 2021-09-29 -0.653814 # 2021-09-30 -0.625868 # 2021-10-01 0.872684 # Freq: D, Length: 274, dtype: float64 \u4e0a\u9762\u8fd9\u4e9b\u64cd\u4f5c\u4e5f\u90fd\u9002\u7528\u4e8eDataFrame\uff0c\u5e76\u5728\u5176\u884c\u4e0a\u8fdb\u884c\u7d22\u5f15\uff1a dates = pd.date_range('10/1/2020', periods=100, freq='W-WED') data = np.random.randn(100, 4) long_df = pd.DataFrame( data, index=dates, columns=['Colorado', 'Texas', 'New York', 'Ohio'] ) print(long_df) # Colorado Texas New York Ohio # 2020-10-07 -1.186789 2.020634 0.300076 -0.955234 # 2020-10-14 1.502838 0.965368 -0.797539 -0.292833 # ... ... ... ... ... # 2022-08-24 -0.253116 -0.263307 0.602425 0.370599 # 2022-08-31 0.907918 0.091939 0.789694 2.781535 # [100 rows x 4 columns] print(long_df.loc['10-2020']) # Colorado Texas New York Ohio # 2020-10-07 1.031616 -1.812038 -0.446577 0.395656 # 2020-10-14 -0.673167 0.198804 -0.439141 0.086004 # 2020-10-21 -1.139786 0.716820 0.006516 -0.284335 # 2020-10-28 -0.637939 1.647810 -0.750786 0.140637 \u542b\u6709\u91cd\u590d\u7d22\u5f15\u7684\u65f6\u95f4\u5e8f\u5217 \u00b6 \u5728\u67d0\u4e9b\u5e94\u7528\u4e2d\uff0c\u53ef\u80fd\u4f1a\u6709\u591a\u4e2a\u6570\u636e\u89c2\u5bdf\u503c\u843d\u5728\u7279\u5b9a\u7684\u65f6\u95f4\u6233\u4e0a\u3002\u4e0b\u9762\u662f\u4e2a\u4f8b\u5b50\uff1a dates = pd.DatetimeIndex( ['2021/1/1', '2021/1/2', '2021/1/2', '2021/1/2', '2021/1/3'] ) dup_ts = pd.Series( np.arange(5), index=dates ) print(dup_ts) # 2021-01-01 0 # 2021-01-02 1 # 2021-01-02 2 # 2021-01-02 3 # 2021-01-03 4 # dtype: int64 \u901a\u8fc7\u68c0\u67e5\u7d22\u5f15\u7684 is_unique \u5c5e\u6027\uff0c\u53ef\u4ee5\u770b\u51fa\u7d22\u5f15\u5e76\u4e0d\u662f\u552f\u4e00\u7684\uff1a print(dup_ts.index.is_unique) # False \u5bf9\u4e0a\u9762\u7684Series\u8fdb\u884c\u7d22\u5f15\uff0c\u7ed3\u679c\u662f\u6807\u91cf\u503c\u8fd8\u662fSeries\u5207\u7247\u53d6\u51b3\u4e8e\u662f\u5426\u6709\u65f6\u95f4\u6233\u662f\u91cd\u590d\u7684\uff1a result = dup_ts['2021/1/3'] print(result) # 4 result = dup_ts['2021/1/2'] print(result) # 2021-01-02 1 # 2021-01-02 2 # 2021-01-02 3 # dtype: int64 \u5047\u8bbe\u60f3\u8981\u805a\u5408\u542b\u6709\u975e\u552f\u4e00\u65f6\u95f4\u6233\u7684\u6570\u636e\u3002\u4e00\u79cd\u65b9\u5f0f\u5c31\u662f\u4f7f\u7528 groupby \u5e76\u4f20\u9012 level=0 \uff1a grouped = dup_ts.groupby(level=0) result = grouped.mean() print(result) # 2021-01-01 0.0 # 2021-01-02 2.0 # 2021-01-03 4.0 # dtype: float64 result = grouped.count() print(result) # 2021-01-01 1 # 2021-01-02 3 # 2021-01-03 1 # dtype: int64 \u65e5\u671f\u8303\u56f4\u3001\u9891\u7387\u548c\u79fb\u4f4d \u00b6 from datetime import datetime, timedelta import pandas as pd import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd pandas\u7684\u901a\u7528\u65f6\u95f4\u5e8f\u5217\u662f\u4e0d\u89c4\u5219\u7684\uff0c\u5373\u65f6\u95f4\u5e8f\u5217\u7684\u9891\u7387\u4e0d\u662f\u56fa\u5b9a\u7684\u3002 \u4f46\u6709\u65f6\u9700\u8981\u5904\u7406\u56fa\u5b9a\u9891\u7387\u7684\u573a\u666f\uff0c\u4f8b\u5982\u6bcf\u65e5\u7684\u3001\u6bcf\u6708\u7684\u6216\u6bcf15\u5206\u949f\u7684\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u3002 \u53ef\u4ee5\u901a\u8fc7\u8c03\u7528resample\u65b9\u6cd5\u5c06\u6837\u672c\u65f6\u95f4\u5e8f\u5217\u8f6c\u6362\u4e3a\u56fa\u5b9a\u7684\u6bcf\u65e5\u9891\u7387\u6570\u636e\u3002 \u5728\u9891\u7387\u95f4\u8f6c\u6362\uff0c\u53c8\u79f0\u4e3a\u91cd\u65b0\u91c7\u6837\u3002 dates = [ datetime(2021, 10, 1), datetime(2021, 10, 3), datetime(2021, 10, 5), datetime(2021, 10, 7), datetime(2021, 10, 9), datetime(2021, 10, 11) ] data = np.random.rand(6) ts = pd.Series(data, index=dates) print(ts) # 2021-10-01 0.956685 # 2021-10-03 0.817168 # 2021-10-05 0.275543 # 2021-10-07 0.614226 # 2021-10-09 0.061377 # 2021-10-11 0.357080 # dtype: float64 resampler = ts.resample('D') # \u5b57\u7b26\u4e32\u2019D\u2019\u88ab\u89e3\u91ca\u4e3a\u6bcf\u65e5\u9891\u7387 print(resampler) # DatetimeIndexResampler [freq=, axis=0, closed=left, label=left, convention=start, origin=start_day] \u751f\u6210\u65e5\u671f\u8303\u56f4 \u00b6 pandas.date_range \u662f\u7528\u4e8e\u6839\u636e\u7279\u5b9a\u9891\u7387\u751f\u6210\u6307\u5b9a\u957f\u5ea6\u7684 DatetimeIndex \u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c date_range \u751f\u6210\u7684\u662f\u6bcf\u65e5\u7684\u65f6\u95f4\u6233\u3002\u5982\u679c\u53ea\u4f20\u9012\u4e00\u4e2a\u8d77\u59cb\u6216\u7ed3\u5c3e\u65e5\u671f\uff0c\u4f60\u5fc5\u987b\u4f20\u9012\u4e00\u4e2a\u7528\u4e8e\u751f\u6210\u8303\u56f4\u7684\u6570\u5b57\u3002 \u5f00\u59cb\u65e5\u671f\u548c\u7ed3\u675f\u65e5\u671f\u4e25\u683c\u5b9a\u4e49\u4e86\u751f\u6210\u65e5\u671f\u7d22\u5f15\u7684\u8fb9\u754c\u3002 index = pd.date_range('2021/1/1', '2021/1/30') print(index) index = pd.date_range(start='2021/1/1', periods=30) print(index) index = pd.date_range(end='2021/1/30', periods=30) print(index) # DatetimeIndex(['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', # '2021-01-05', '2021-01-06', '2021-01-07', '2021-01-08', # '2021-01-09', '2021-01-10', '2021-01-11', '2021-01-12', # '2021-01-13', '2021-01-14', '2021-01-15', '2021-01-16', # '2021-01-17', '2021-01-18', '2021-01-19', '2021-01-20', # '2021-01-21', '2021-01-22', '2021-01-23', '2021-01-24', # '2021-01-25', '2021-01-26', '2021-01-27', '2021-01-28', # '2021-01-29', '2021-01-30'], # dtype='datetime64[ns]', freq='D') \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c date_range \u4fdd\u7559\u5f00\u59cb\u6216\u7ed3\u675f\u65f6\u95f4\u6233\u7684\u65f6\u95f4\uff08\u5982\u679c\u6709\u7684\u8bdd\uff09\u3002 normalize \u9009\u9879\u53ef\u4ee5\u5b9e\u73b0\u751f\u6210\u7684\u662f\u6807\u51c6\u5316\u4e3a\u96f6\u70b9\u7684\u65f6\u95f4\u6233\u3002 index = pd.date_range('2021/1/1 12:56:30', periods=5) print(index) # DatetimeIndex(['2021-01-01 12:56:30', '2021-01-02 12:56:30', # '2021-01-03 12:56:30', '2021-01-04 12:56:30', # '2021-01-05 12:56:30'], # dtype='datetime64[ns]', freq='D') index = pd.date_range('2021/1/1 12:56:30', periods=5, normalize=True) print(index) # DatetimeIndex(['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', # '2021-01-05'], # dtype='datetime64[ns]', freq='D') Pandas\u65f6\u95f4\u5e8f\u5217\uff1a\u9891\u7387\u548c\u65e5\u671f\u504f\u79fb\u91cf\u3002 pandas\u4e2d\u7684\u9891\u7387\u662f\u7531\u4e00\u4e2a\u57fa\u7840\u9891\u7387(\u4f8b\u5982\u201c\u65e5\u201d\u3001\u201c\u6708\u201d)\u548c\u4e00\u4e2a\u4e58\u6570\u7ec4\u6210\u3002 \u57fa\u7840\u9891\u7387\u901a\u5e38\u4ee5\u4e00\u4e2a\u5b57\u7b26\u4e32\u522b\u540d\u8868\u793a\uff0c\u6bd4\u5982\u201cD\u201d\u8868\u793a\u65e5\uff0c\u201cM\u201d\u8868\u793a\u6708\u3002 \u5bf9\u4e8e\u6bcf\u4e2a\u57fa\u7840\u9891\u7387\uff0c\u90fd\u6709\u4e00\u4e2a\u88ab\u79f0\u4e3a\u65e5\u671f\u504f\u79fb\u91cf(dateoffset)\u7684\u5bf9\u8c61\u4e0e\u4e4b\u5bf9\u5e94\uff0c\u6bd4\u5982\u65e5\u671f\u504f\u79fb\u91cf Hour \u5bf9\u5e94\u7684\u9891\u7387\u662f H \u3002 \u5e38\u7528\u9891\u7387\u4e0e\u65e5\u671f\u504f\u79fb\u91cf\u3002 \u9891\u7387 \u65e5\u671f\u504f\u79fb\u91cf \u8bf4\u660e D Day \u65e5\u5386\u65e5 B BusinessDay \u5de5\u4f5c\u65e5 H Hour \u5c0f\u65f6 T/min Minute \u5206 S Second \u79d2 L/ms Milli \u6beb\u79d2 U Micro \u5fae\u79d2 M MonthEnd \u6bcf\u6708\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5 BM BusinessMonthEnd \u6bcf\u6708\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5 MS MonthBegin \u6bcf\u6708\u7b2c\u4e00\u4e2a\u65e5\u5386\u65e5 BMS BussinessMonthBegin \u6bcf\u6708\u7b2c\u4e00\u4e2a\u5de5\u4f5c\u65e5 W-MON, W-TUE, ... Week \u6307\u5b9a\u661f\u671f\u51e0(MON,TUE,WED,THU,FRI,SAT,SUN) WOM-1MON,WOM-2MON, ... WeekOfMonth \u4ea7\u751f\u6bcf\u6708\u7b2c\u4e00,\u7b2c\u4e8c,\u7b2c\u4e09\u6216\u7b2c\u56db\u5468\u7684\u661f\u671f\u51e0\u3002\u4f8b\u5982WOM-3FRI\u8868\u793a\u6bcf\u6708\u7b2c3\u4e2a\u661f\u671f\u4e94 Q-JAN,Q-FEB, ... QuarterEnd \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5 BQ-JAN,BQ-FEB, ... BusinessQuarterEnd \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5 QS-JAN,QS-FEB, ... QuarterBegin \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u7b2c\u4e00\u4e2a\u65e5\u5386\u65e5 BQS-JAN,BQS-FEB, ... BusinessQuarterBegin \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u7b2c\u4e00\u4e2a\u5de5\u4f5c\u65e5 A-JAN,A-FEB, ... YearEnd \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5 BA-JAN,BA-FEB, ... BusinessYearEnd \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5 AS-JAN,AS-FEB, ... YearBegin \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u7b2c\u4e00\u4e2a\u65e5\u5386\u65e5 BAS-JAN,BAS-FEB, ... BusinessYearBegin \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u7b2c\u4e00\u4e2a\u5de5\u4f5c\u65e5 \u9891\u7387\u548c\u65e5\u671f\u504f\u7f6e \u00b6 pandas\u4e2d\u7684\u9891\u7387\u662f\u7531\u57fa\u7840\u9891\u7387\u548c\u500d\u6570\u7ec4\u6210\u7684\u3002 \u57fa\u7840\u9891\u7387\u901a\u5e38\u4f1a\u6709\u5b57\u7b26\u4e32\u522b\u540d\uff0c\u4f8b\u5982 M \u4ee3\u8868\u6bcf\u6708\uff0c H \u4ee3\u8868\u6bcf\u5c0f\u65f6\u3002 \u5bf9\u4e8e\u6bcf\u4e2a\u57fa\u7840\u9891\u7387\uff0c\u90fd\u6709\u4e00\u4e2a\u5bf9\u8c61\u53ef\u4ee5\u88ab\u7528\u4e8e\u5b9a\u4e49\u65e5\u671f\u504f\u7f6e\u3002 \u4f8b\u5982\uff0c\u6bcf\u5c0f\u65f6\u7684\u9891\u7387\u53ef\u4ee5\u4f7f\u7528 Hour \u7c7b\u6765\u8868\u793a\uff1a ```hour = Hour() print(hour) \u00b6 \u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u6574\u6570\u6765\u5b9a\u4e49\u504f\u7f6e\u91cf\u7684\u500d\u6570\uff1a four_hours = Hour(4) print(four_hours) <4 * Hours> \u00b6 \u5728\u5927\u591a\u6570\u5e94\u7528\u4e2d\uff0c\u4e0d\u9700\u8981\u663e\u5f0f\u5730\u521b\u5efa\u8fd9\u4e9b\u5bf9\u8c61\uff0c\u800c\u662f\u4f7f\u7528\u5b57\u7b26\u4e32\u522b\u540d\uff0c\u5982`H`\u6216`4H`\u3002\u5728\u57fa\u7840\u9891\u7387\u524d\u653e\u4e00\u4e2a\u6574\u6570\u5c31\u53ef\u4ee5\u751f\u6210\u500d\u6570\uff1a ts = pd.date_range('2021/1/1', '2021/\u00bd 23:59', freq='4h') print(ts) DatetimeIndex(['2021-01-01 00:00:00', '2021-01-01 04:00:00', \u00b6 '2021-01-01 08:00:00', '2021-01-01 12:00:00', \u00b6 '2021-01-01 16:00:00', '2021-01-01 20:00:00', \u00b6 '2021-01-02 00:00:00', '2021-01-02 04:00:00', \u00b6 '2021-01-02 08:00:00', '2021-01-02 12:00:00', \u00b6 '2021-01-02 16:00:00', '2021-01-02 20:00:00'], \u00b6 dtype='datetime64[ns]', freq='4H') \u00b6 \u591a\u4e2a\u504f\u7f6e\u53ef\u4ee5\u901a\u8fc7\u52a0\u6cd5\u8fdb\u884c\u8054\u5408\uff1a print(Hour(2) + Minute(30)) <150 * Minutes> \u00b6 \u7c7b\u4f3c\u5730\uff0c\u53ef\u4ee5\u4f20\u9012\u9891\u7387\u5b57\u7b26\u4e32\uff1a ts = pd.date_range('2021/1/1', '2021/1/1 23:59', freq='4h30min') print(ts) DatetimeIndex(['2021-01-01 00:00:00', '2021-01-01 04:30:00', \u00b6 '2021-01-01 09:00:00', '2021-01-01 13:30:00', \u00b6 '2021-01-01 18:00:00', '2021-01-01 22:30:00'], \u00b6 dtype='datetime64[ns]', freq='270T') \u00b6 \u6709\u4e9b\u9891\u7387\u63cf\u8ff0\u70b9\u7684\u65f6\u95f4\u5e76\u4e0d\u662f\u5747\u5300\u5206\u9694\u7684\u3002\u4f8b\u5982\uff0c`M`\uff08\u65e5\u5386\u6708\u672b\uff09\u548c`BM`\uff08\u6708\u5185\u6700\u540e\u5de5\u4f5c\u65e5\uff09\u53d6\u51b3\u4e8e\u5f53\u6708\u5929\u6570\uff0c\u6708\u672b\u662f\u5426\u662f\u5468\u672b\u3002\u6211\u4eec\u5c06\u8fd9\u4e9b\u65e5\u671f\u79f0\u4e3a\u951a\u5b9a\u504f\u7f6e\u91cf\u3002 #### \u6708\u4e2d\u67d0\u661f\u671f\u7684\u65e5\u671f \"\u6708\u4e2d\u67d0\u661f\u671f\"\uff08week of month \uff09\u7684\u65e5\u671f\u662f\u4e00\u4e2a\u6709\u7528\u7684\u9891\u7387\u7c7b\uff0c\u4ee5`WOM`\u5f00\u59cb\u3002 rng = pd.date_range('2021-1-1', '2021-9-1', freq='WOM-3FRI') # \u6bcf\u6708\u7b2c\u4e09\u4e2a\u661f\u671f\u4e94 print(rng) DatetimeIndex(['2021-01-15', '2021-02-19', '2021-03-19', '2021-04-16', \u00b6 '2021-05-21', '2021-06-18', '2021-07-16', '2021-08-20'], \u00b6 dtype='datetime64[ns]', freq='WOM-3FRI') \u00b6 ### \u79fb\u4f4d\uff08\u524d\u5411\u548c\u540e\u5411\uff09\u65e5\u671f \"\u79fb\u4f4d\"\u662f\u6307\u5c06\u65e5\u671f\u6309\u65f6\u95f4\u5411\u524d\u79fb\u52a8\u6216\u5411\u540e\u79fb\u52a8\u3002 Series\u548cDataFrame\u90fd\u6709\u4e00\u4e2a`shift`\u65b9\u6cd5\u7528\u4e8e\u8fdb\u884c\u7b80\u5355\u7684\u524d\u5411\u6216\u540e\u5411\u79fb\u4f4d\uff0c\u800c\u4e0d\u6539\u53d8\u7d22\u5f15\u3002 \u8fdb\u884c\u79fb\u4f4d\u65f6\uff0c\u4f1a\u5728\u65f6\u95f4\u5e8f\u5217\u7684\u8d77\u59cb\u4f4d\u6216\u7ed3\u675f\u4f4d\u5f15\u5165\u7f3a\u5931\u503c\u3002 data = [0.882972, 1.363282, -0.687750, -0.048117] ts = pd.Series(data, index=pd.date_range('2021-1-1', periods=4, freq='M')) print(ts) 2021-01-31 0.882972 \u00b6 2021-02-28 1.363282 \u00b6 2021-03-31 -0.687750 \u00b6 2021-04-30 -0.048117 \u00b6 Freq: M, dtype: float64 \u00b6 print(ts.shift(2)) 2021-01-31 NaN \u00b6 2021-02-28 NaN \u00b6 2021-03-31 0.882972 \u00b6 2021-04-30 1.363282 \u00b6 Freq: M, dtype: float64 \u00b6 print(ts.shift(-2)) 2021-01-31 -0.687750 \u00b6 2021-02-28 -0.048117 \u00b6 2021-03-31 NaN \u00b6 2021-04-30 NaN \u00b6 Freq: M, dtype: float64 \u00b6 `shift`\u5e38\u7528\u4e8e\u8ba1\u7b97\u65f6\u95f4\u5e8f\u5217\u6216DataFrame\u591a\u5217\u65f6\u95f4\u5e8f\u5217\u7684\u767e\u5206\u6bd4\u53d8\u5316\uff1a print(ts/ts.shift(1)) 2021-01-31 NaN \u00b6 2021-02-28 1.543970 \u00b6 2021-03-31 -0.504481 \u00b6 2021-04-30 0.069963 \u00b6 Freq: M, dtype: float64 \u00b6 print(ts/ts.shift(1) - 1) 2021-01-31 NaN \u00b6 2021-02-28 0.543970 \u00b6 2021-03-31 -1.504481 \u00b6 2021-04-30 -0.930037 \u00b6 Freq: M, dtype: float64 \u00b6 \u5982\u679c\u9891\u7387\u662f\u5df2\u77e5\u7684\uff0c\u5219\u53ef\u4ee5\u5c06\u9891\u7387\u4f20\u9012\u7ed9`shift`\u6765\u63a8\u79fb\u65f6\u95f4\u6233\uff1a print(ts.shift(2, freq='M')) # \u539f\u59cb\u6570\u636e\u7684\u201c\u6708\u201c\u589e\u52a0\u4e86\u504f\u79fb\u503c 2021-03-31 0.882972 \u00b6 2022021-10-31 00:00:001-04-30 1.363282 \u00b6 2021-05-31 -0.687750 \u00b6 2021-06-30 -0.048117 \u00b6 Freq: M, dtype: float64 \u00b6 print(ts.shift(2, freq='D')) # \u539f\u59cb\u6570\u636e\u7684\u201c\u65e5\u201c\u589e\u52a0\u4e86\u504f\u79fb\u503c 2021-02-02 0.882972 \u00b6 2021-03-02 1.363282 \u00b6 2021-04-02 -0.687750 \u00b6 2021-05-02 -0.048117 \u00b6 dtype: float64 \u00b6 print(ts.shift(2, freq='90T')) # \u539f\u59cb\u6570\u636e\u7684\u201c\u5c0f\u65f6\u201c\u589e\u52a0\u4e86\u504f\u79fb\u503c 2021-01-31 03:00:00 0.882972 \u00b6 2021-02-28 03:00:00 1.363282 \u00b6 2021-03-31 03:00:00 -0.687750 \u00b6 2021-04-30 03:00:00 -0.048117 \u00b6 dtype: float64 \u00b6 #### \u4f7f\u7528\u504f\u7f6e\u8fdb\u884c\u79fb\u4f4d\u65e5\u671f pandas\u65e5\u671f\u504f\u7f6e\u4e5f\u53ef\u4ee5\u4f7f\u7528`datetime`\u6216`Timestamp`\u5bf9\u8c61\u5b8c\u6210\uff1a now = datetime(2021, 10, 9) print(now) 2021-10-09 00:00:00 \u00b6 print(now + 3 * Day()) 2021-10-12 00:00:00 \u00b6 \u951a\u5b9a\u504f\u7f6e\u53ef\u4ee5\u4f7f\u7528`rollforward`\u548c`rollback`\u5206\u522b\u663e\u5f0f\u5730\u5c06\u65e5\u671f\u5411\u524d\u6216\u5411\u540e\"\u6eda\u52a8\"\u3002 \u5982\u679c\u6dfb\u52a0\u4e86\u4e00\u4e2a\u951a\u5b9a\u504f\u7f6e\u91cf\uff0c\u6bd4\u5982`MonthEnd`\uff0c\u6839\u636e\u9891\u7387\u89c4\u5219\uff0c\u7b2c\u4e00\u4e2a\u589e\u91cf\u4f1a\u5c06\u65e5\u671f\u201c\u524d\u6eda\u201d\u5230\u4e0b\u4e00\u4e2a\u65e5\u671f\uff1a print(now + MonthEnd()) # \u201c\u524d\u6eda\u201d\u5230\u5f53\u524d\u6708\u7684\u6708\u5e95 2021-10-31 00:00:00 \u00b6 print(now + MonthEnd(2)) # \u6ce8\u610f\u8fd9\u91cc\u7684\u5e8f\u5217\u53f7\uff0c\u5f53\u524d\u6708\u662f1,\u4e0b\u4e2a\u6708\u662f2 2021-11-30 00:00:00 \u00b6 offset = MonthEnd() print(offset.rollback(now)) 2021-09-30 00:00:00 \u00b6 print(offset.rollforward(now)) 2021-10-31 00:00:00 \u00b6 \u5c06\u79fb\u4f4d\u65b9\u6cd5\u4e0e`groupby`\u4e00\u8d77\u4f7f\u7528\u662f\u65e5\u671f\u504f\u7f6e\u7684\u4e00\u79cd\u521b\u9020\u6027\u7528\u6cd5\uff1a ts = pd.Series( np.random.randn(20), index=pd.date_range('2021/1/1', periods=20, freq='4d') ) print(ts) 2021-01-01 0.674348 \u00b6 2021-01-05 -1.437803 \u00b6 2021-01-09 -0.079218 \u00b6 2021-01-13 -1.444890 \u00b6 2021-01-17 0.643279 \u00b6 2021-01-21 1.089965 \u00b6 2021-01-25 0.021876 \u00b6 2021-01-29 0.692138 \u00b6 2021-02-02 0.833496 \u00b6 2021-02-06 1.082616 \u00b6 2021-02-10 -0.729415 \u00b6 2021-02-14 0.271186 \u00b6 2021-02-18 -1.416218 \u00b6 2021-02-22 -0.780402 \u00b6 2021-02-26 -0.113773 \u00b6 2021-03-02 2.095338 \u00b6 2021-03-06 -0.302612 \u00b6 2021-03-10 1.113632 \u00b6 2021-03-14 -1.314581 \u00b6 2021-03-18 0.947746 \u00b6 Freq: 4D, dtype: float64 \u00b6 print(ts.groupby(offset.rollforward).mean()) # \u524d\u6eda\u81f3\u5f53\u6708\u6708\u5e95\uff0c\u8ba1\u7b97\u5f53\u6708\u5e73\u5747\u503c 2021-01-31 0.019962 \u00b6 2021-02-28 -0.121787 \u00b6 2021-03-31 0.507905 \u00b6 dtype: float64 \u00b6 \u4f7f\u7528resample\u662f\u66f4\u7b80\u5355\u66f4\u5feb\u6377\u7684\u65b9\u6cd5 \u00b6 print(ts.resample('M').mean()) 2021-01-31 0.019962 \u00b6 2021-02-28 -0.121787 \u00b6 2021-03-31 0.507905 \u00b6 Freq: M, dtype: float64 \u00b6 ## \u65f6\u533a\u5904\u7406 \u65f6\u533a\u901a\u5e38\u88ab\u8868\u793a\u4e3aUTC\u7684\u504f\u7f6e\u3002 \u5728Python\u8bed\u8a00\u4e2d\uff0c\u65f6\u533a\u4fe1\u606f\u6765\u6e90\u4e8e\u7b2c\u4e09\u65b9\u5e93pytz\uff08\u53ef\u4ee5\u4f7f\u7528pip\u6216conda\u5b89\u88c5\uff09\uff0c\u5176\u4e2d\u516c\u5f00\u4e86Olson\u6570\u636e\u5e93\uff0c\u8fd9\u662f\u4e16\u754c\u65f6\u533a\u4fe1\u606f\u7684\u6c47\u7f16\u3002 pandas\u5c01\u88c5\u4e86pytz\u7684\u529f\u80fd\u3002 from datetime import datetime, timedelta import pandas as pd import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd import pytz #### common_timezones tz = pytz.common_timezones[-5:] # \u8bfb\u53d6common_timezones\u8fd9\u4e2a\u5217\u8868\u7684\u6700\u540e5\u4e2a\u5143\u7d20 print(tz) ['US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC'] \u00b6 \u8981\u83b7\u5f97pytz\u7684\u65f6\u533a\u5bf9\u8c61\uff0c\u53ef\u4f7f\u7528pytz.timezone\uff1a tz = pytz.timezone('Asia/Shanghai') print(tz) #### \u65f6\u533a\u7684\u672c\u5730\u5316\u548c\u8f6c\u6362 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cpandas\u4e2d\u7684\u65f6\u95f4\u5e8f\u5217\u662f\u65f6\u533a\u7b80\u5355\u578b\u7684\u3002 rng = pd.date_range('2021/1/1 9:30', periods=6, freq='D') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(rng) DatetimeIndex(['2021-01-01 09:30:00', '2021-01-02 09:30:00', \u00b6 '2021-01-03 09:30:00', '2021-01-04 09:30:00', \u00b6 '2021-01-05 09:30:00', '2021-01-06 09:30:00'], \u00b6 dtype='datetime64[ns]', freq='D') \u00b6 print(ts) 2021-01-01 09:30:00 0.339822 \u00b6 2021-01-02 09:30:00 1.356382 \u00b6 2021-01-03 09:30:00 0.475429 \u00b6 2021-01-04 09:30:00 1.826654 \u00b6 2021-01-05 09:30:00 -0.245510 \u00b6 2021-01-06 09:30:00 0.705274 \u00b6 Freq: D, dtype: float64 \u00b6 print(ts.index.tz) # \u7d22\u5f15\u7684tz\u5c5e\u6027\u662fNone None \u00b6 \u65e5\u671f\u8303\u56f4\u53ef\u4ee5\u901a\u8fc7\u65f6\u533a\u96c6\u5408\u6765\u751f\u6210\uff1a rng = pd.date_range('2021/3/1', periods=10, freq='D', tz='UTC') print(rng) DatetimeIndex(['2021-03-01 00:00:00+00:00', '2021-03-02 00:00:00+00:00', \u00b6 '2021-03-03 00:00:00+00:00', '2021-03-04 00:00:00+00:00', \u00b6 '2021-03-05 00:00:00+00:00', '2021-03-06 00:00:00+00:00', \u00b6 '2021-03-07 00:00:00+00:00', '2021-03-08 00:00:00+00:00', \u00b6 '2021-03-09 00:00:00+00:00', '2021-03-10 00:00:00+00:00'], \u00b6 dtype='datetime64[ns, UTC]', freq='D') \u00b6 \u4f7f\u7528`tz_localize`\u65b9\u6cd5\u53ef\u4ee5\u4ece\u7b80\u5355\u65f6\u533a\u8f6c\u6362\u5230\u672c\u5730\u5316\u65f6\u533a\uff1a print(ts) 2021-01-01 09:30:00 0.294647 \u00b6 2021-01-02 09:30:00 0.958414 \u00b6 2021-01-03 09:30:00 0.424235 \u00b6 2021-01-04 09:30:00 -1.714333 \u00b6 2021-01-05 09:30:00 -0.030319 \u00b6 2021-01-06 09:30:00 -0.744940 \u00b6 Freq: D, dtype: float64 \u00b6 print(ts.tz_localize('UTC')) 2021-01-01 09:30:00+00:00 0.294647 \u00b6 2021-01-02 09:30:00+00:00 0.958414 \u00b6 2021-01-03 09:30:00+00:00 0.424235 \u00b6 2021-01-04 09:30:00+00:00 -1.714333 \u00b6 2021-01-05 09:30:00+00:00 -0.030319 \u00b6 2021-01-06 09:30:00+00:00 -0.744940 \u00b6 Freq: D, dtype: float64 \u00b6 print(ts.tz_localize('Asia/Shanghai')) 2021-01-01 09:30:00+08:00 0.052521 \u00b6 2021-01-02 09:30:00+08:00 -0.305417 \u00b6 2021-01-03 09:30:00+08:00 0.150215 \u00b6 2021-01-04 09:30:00+08:00 -0.953715 \u00b6 2021-01-05 09:30:00+08:00 0.543622 \u00b6 2021-01-06 09:30:00+08:00 0.222422 \u00b6 dtype: float64 \u00b6 print(ts.tz_localize('Asia/Shanghai').index) DatetimeIndex(['2021-01-01 09:30:00+08:00', '2021-01-02 09:30:00+08:00', \u00b6 '2021-01-03 09:30:00+08:00', '2021-01-04 09:30:00+08:00', \u00b6 '2021-01-05 09:30:00+08:00', '2021-01-06 09:30:00+08:00'], \u00b6 dtype='datetime64[ns, Asia/Shanghai]', freq=None) \u00b6 \u4e00\u65e6\u65f6\u95f4\u5e8f\u5217\u88ab\u672c\u5730\u5316\u4e3a\u67d0\u4e2a\u7279\u5b9a\u7684\u65f6\u533a\uff0c\u5219\u53ef\u4ee5\u901a\u8fc7`tz_convert`\u5c06\u5176\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u65f6\u533a\uff1a tz_sha = ts.tz_localize('Asia/Shanghai') tz_utc = tz_sha.tz_convert('UTC') print(tz_sha) 2021-01-01 09:30:00+08:00 0.095689 \u00b6 2021-01-02 09:30:00+08:00 -0.392730 \u00b6 2021-01-03 09:30:00+08:00 0.151468 \u00b6 2021-01-04 09:30:00+08:00 0.027467 \u00b6 2021-01-05 09:30:00+08:00 0.393709 \u00b6 2021-01-06 09:30:00+08:00 0.872914 \u00b6 dtype: float64 \u00b6 print(tz_utc) 2021-01-01 01:30:00+00:00 0.095689 \u00b6 2021-01-02 01:30:00+00:00 -0.392730 \u00b6 2021-01-03 01:30:00+00:00 0.151468 \u00b6 2021-01-04 01:30:00+00:00 0.027467 \u00b6 2021-01-05 01:30:00+00:00 0.393709 \u00b6 2021-01-06 01:30:00+00:00 0.872914 \u00b6 dtype: float64 \u00b6 tz_localize\u548ctz_convert\u4e5f\u662fDatetimeIndex\u7684\u5b9e\u4f8b\u65b9\u6cd5\uff1a \u00b6 print(ts.index.tz_localize('Asia/Shanghai')) DatetimeIndex(['2021-01-01 09:30:00+08:00', '2021-01-02 09:30:00+08:00', \u00b6 '2021-01-03 09:30:00+08:00', '2021-01-04 09:30:00+08:00', \u00b6 '2021-01-05 09:30:00+08:00', '2021-01-06 09:30:00+08:00'], \u00b6 dtype='datetime64[ns, Asia/Shanghai]', freq=None) \u00b6 ### \u65f6\u533a\u611f\u77e5\u65f6\u95f4\u6233\u5bf9\u8c61\u7684\u64cd\u4f5c \u4e0e\u65f6\u95f4\u5e8f\u5217\u548c\u65e5\u671f\u8303\u56f4\u7c7b\u4f3c\uff0c\u5355\u72ec\u7684`Timestamp`\u5bf9\u8c61\u4e5f\u53ef\u4ee5\u4ece\u7b80\u5355\u65f6\u95f4\u6233\u672c\u5730\u5316\u4e3a\u65f6\u533a\u611f\u77e5\u65f6\u95f4\u6233\uff0c\u5e76\u4ece\u4e00\u4e2a\u65f6\u533a\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u65f6\u533a\uff1a stamp = pd.Timestamp('2021-5-1 05:30') print(stamp) 2021-05-01 05:30:00 \u00b6 stamp_utc = stamp.tz_localize('utc') print(stamp_utc) 2021-05-01 05:30:00+00:00 \u00b6 stamp_sha = stamp_utc.tz_convert('Asia/Shanghai') print(stamp_sha) 2021-05-01 13:30:00+08:00 \u00b6 \u4e5f\u53ef\u4ee5\u5728\u521b\u5efa`Timestamp`\u7684\u65f6\u5019\u4f20\u9012\u4e00\u4e2a\u65f6\u533a\uff1a stamp_sha = pd.Timestamp('2021-5-1 05:30', tz='Asia/Shanghai') print(stamp_sha) 2021-05-01 05:30:00+08:00 \u00b6 `Timestamp`\u5bf9\u8c61\u5185\u90e8\u5b58\u50a8\u4e86\u4e00\u4e2aUnix\u7eaa\u5143(1970\u5e741\u67081\u65e5)\u81f3\u4eca\u7684\u7eb3\u79d2\u6570\u91cfUTC\u65f6\u95f4\u6233\u6570\u503c\uff0c\u8be5\u6570\u503c\u5728\u65f6\u533a\u8f6c\u6362\u4e2d\u662f\u4e0d\u53d8\u7684\uff1a print(stamp_utc.value) 1619847000000000000 \u00b6 print(stamp_utc.tz_convert('Asia/Shanghai').value) 1619847000000000000 \u00b6 \u5728\u4f7f\u7528pandas\u7684`DateOffset`\u8fdb\u884c\u65f6\u95f4\u7b97\u672f\u65f6\uff0cpandas\u5c3d\u53ef\u80fd\u9075\u4ece\u590f\u65f6\u5236\u3002 \u9996\u5148\uff0c\u6784\u9020\u8f6c\u6362\u5230DST\u4e4b\u524d\u768430\u5206\u949f\u7684\u65f6\u95f4\uff1a stamp = pd.Timestamp('2012-3-12 1:30', tz='US/Eastern') print(stamp) 2012-03-12 01:30:00-04:00 \u00b6 print(stamp + Hour()) 2012-03-12 02:30:00-04:00 \u00b6 \u4e4b\u540e\uff0c\u6784\u5efa\u4eceDST\u8fdb\u884c\u8f6c\u6362\u524d\u768490\u5206\u949f\uff1a stamp = pd.Timestamp('2012-11-04 0:30-04:00', tz='US/Eastern') print(stamp) 2012-11-04 00:30:00-04:00 \u00b6 print(stamp + 2 * Hour()) # \u53ea\u589e\u52a0\u4e86\u4e00\u5c0f\u65f6 2012-11-04 01:30:00-05:00 \u00b6 ### \u4e0d\u540c\u65f6\u533a\u95f4\u7684\u64cd\u4f5c \u5982\u679c\u4e24\u4e2a\u65f6\u533a\u4e0d\u540c\u7684\u65f6\u95f4\u5e8f\u5217\u9700\u8981\u8054\u5408\uff0c\u90a3\u4e48\u7ed3\u679c\u5c06\u662fUTC\u65f6\u95f4\u7684\uff0c\u56e0\u4e3a\u65f6\u95f4\u6233\u4ee5UTC\u683c\u5f0f\u5b58\u50a8\u3002 rng = pd.date_range('2021/1/1 9:30', periods=9, freq='B') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(ts) 2021-01-01 09:30:00 0.715681 \u00b6 2021-01-04 09:30:00 0.524563 \u00b6 2021-01-05 09:30:00 -0.482199 \u00b6 2021-01-06 09:30:00 -0.661303 \u00b6 2021-01-07 09:30:00 1.750010 \u00b6 2021-01-08 09:30:00 0.251478 \u00b6 2021-01-11 09:30:00 -1.487268 \u00b6 2021-01-12 09:30:00 -0.224024 \u00b6 2021-01-13 09:30:00 -1.621853 \u00b6 Freq: B, dtype: float64 \u00b6 ts1 = ts[:7].tz_localize('Europe/London') ts2 = ts1[2:].tz_convert('Europe/Moscow') result = ts1 + ts2 print(ts1) 2021-01-01 09:30:00+00:00 -1.393445 \u00b6 2021-01-04 09:30:00+00:00 -1.179614 \u00b6 2021-01-05 09:30:00+00:00 0.716669 \u00b6 2021-01-06 09:30:00+00:00 -0.485656 \u00b6 2021-01-07 09:30:00+00:00 0.433000 \u00b6 2021-01-08 09:30:00+00:00 1.540745 \u00b6 2021-01-11 09:30:00+00:00 0.343751 \u00b6 dtype: float64 \u00b6 print(ts2) 2021-01-05 12:30:00+03:00 0.716669 \u00b6 2021-01-06 12:30:00+03:00 -0.485656 \u00b6 2021-01-07 12:30:00+03:00 0.433000 \u00b6 2021-01-08 12:30:00+03:00 1.540745 \u00b6 2021-01-11 12:30:00+03:00 0.343751 \u00b6 dtype: float64 \u00b6 print(result) 2021-01-01 09:30:00+00:00 NaN \u00b6 2021-01-04 09:30:00+00:00 NaN \u00b6 2021-01-05 09:30:00+00:00 1.433337 \u00b6 2021-01-06 09:30:00+00:00 -0.971312 \u00b6 2021-01-07 09:30:00+00:00 0.866000 \u00b6 2021-01-08 09:30:00+00:00 3.081489 \u00b6 2021-01-11 09:30:00+00:00 0.687502 \u00b6 dtype: float64 \u00b6 ## \u65f6\u95f4\u533a\u95f4\u548c\u533a\u95f4\u7b97\u672f from datetime import datetime, timedelta import pandas as pd import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd import pytz \u65f6\u95f4\u533a\u95f4\u8868\u793a\u7684\u662f\u65f6\u95f4\u8303\u56f4\u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628a`year`\u548c`quarter`\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f15\uff0c\u6bd4\u5982\u4e00\u4e9b\u5929\u3001\u4e00\u4e9b\u6708\u3001\u4e00\u4e9b\u5b63\u5ea6\u6216\u8005\u662f\u4e00\u4e9b\u5e74\u3002 `Period`\u7c7b\u8868\u793a\u7684\u6b63\u662f\u8fd9\u79cd\u6570\u636e\u7c7b\u578b\uff0c\u9700\u8981\u4e00\u4e2a\u5b57\u7b26\u4e32\u6216\u6570\u5b57\u4ee5\u53ca\u9891\u7387\u3002 \u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c`Period`\u5bf9\u8c61\u8868\u793a\u7684\u662f\u4ece2007\u5e741\u67081\u65e5\u52302007\u5e7412\u670831\u65e5\uff08\u5305\u542b\u5728\u5185\uff09\u7684\u65f6\u95f4\u6bb5\u3002 \u5728\u65f6\u95f4\u6bb5\u4e0a\u589e\u52a0\u6216\u51cf\u53bb\u6574\u6570\u53ef\u4ee5\u65b9\u4fbf\u5730\u6839\u636e\u5b83\u4eec\u7684\u9891\u7387\u8fdb\u884c\u79fb\u4f4d\u3002 p = pd.Period(2020, freq='A-DEC') print(p) 2020 \u00b6 print(p + 5) 2025 \u00b6 print(p - 5) 2015 \u00b6 \u5982\u679c\u4e24\u4e2a\u533a\u95f4\u62e5\u6709\u76f8\u540c\u7684\u9891\u7387\uff0c\u5219\u5b83\u4eec\u7684\u5dee\u662f\u5b83\u4eec\u4e4b\u95f4\u7684\u5355\u4f4d\u6570\u3002 p1 = pd.Period(2020, freq='A-DEC') p2 = pd.Period(2010, freq='A-DEC') print(p1 - p2) <10 * YearEnds: month=12> \u00b6 p1 = pd.Period(2020, freq='Q-DEC') p2 = pd.Period(2010, freq='Q-DEC') print(p1 - p2) <40 * QuarterEnds: startingMonth=12> \u00b6 \u4f7f\u7528`period_range`\u51fd\u6570\u53ef\u4ee5\u6784\u9020\u89c4\u5219\u533a\u95f4\u5e8f\u5217\u3002`PeriodIndex`\u7c7b\u5b58\u50a8\u7684\u662f\u533a\u95f4\u7684\u5e8f\u5217\uff0c\u53ef\u4ee5\u4f5c\u4e3a\u4efb\u610fpandas\u6570\u636e\u7ed3\u6784\u7684\u8f74\u7d22\u5f15\u3002 data = np.random.randn(6) strings = ['2021Q1', '2021Q2', '2021Q3', '2021Q4', '2022Q1', '2022Q2'] rng = pd.period_range('2001-1-1', '2001-6-30', freq='M') ts = pd.Series(data, index=rng) print(ts) 2001-01 -0.481408 \u00b6 2001-02 -0.297590 \u00b6 2001-03 -0.860354 \u00b6 2001-04 1.281540 \u00b6 2001-05 1.036551 \u00b6 2001-06 -0.522592 \u00b6 Freq: M, dtype: float64 \u00b6 rng = pd.PeriodIndex(strings, freq='Q-DEC') # \u5b57\u7b26\u4e32\u6570\u7ec4\u4e5f\u53ef\u4ee5\u4f7f\u7528PeriodIndex\u7c7b ts = pd.Series(data, index=rng) print(ts) 2021Q1 -2.077200 \u00b6 2021Q2 -0.948796 \u00b6 2021Q3 -1.104737 \u00b6 2021Q4 0.090281 \u00b6 2022Q1 0.431517 \u00b6 2022Q2 1.537045 \u00b6 Freq: Q-DEC, dtype: float64 \u00b6 ### \u533a\u95f4\u9891\u7387\u8f6c\u6362 \u4f7f\u7528`asfreq`\u53ef\u4ee5\u5c06\u533a\u95f4\u548c`PeriodIndex`\u5bf9\u8c61\u8f6c\u6362\u4e3a\u5176\u4ed6\u7684\u9891\u7387\u3002 \u4f8b\u5982\uff0c\u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u5e74\u5ea6\u533a\u95f4\uff0c\u5e76\u4e14\u60f3\u8981\u5728\u4e00\u5e74\u7684\u5f00\u59cb\u6216\u7ed3\u675f\u65f6\u5c06\u5176\u8f6c\u6362\u4e3a\u6708\u5ea6\u533a\u95f4\u3002 \u53ef\u4ee5\u5c06`Period('2020', 'A-DEC')`\u770b\u4f5c\u4e00\u6bb5\u65f6\u95f4\u4e2d\u7684\u4e00\u79cd\u6e38\u6807\uff0c\u5c06\u65f6\u95f4\u6309\u6708\u4efd\u5212\u5206\u3002 p = pd.Period(2020, freq='A-DEC') print(p.asfreq('M', how='start')) 2020-01 \u00b6 print(p.asfreq('M', how='end')) 2020-12 \u00b6 \u5982\u679c\u8d22\u5e74\u7ed3\u675f\u4e0d\u572812\u6708\uff0c\u5219\u6bcf\u6708\u5206\u671f\u4f1a\u81ea\u52a8\u8c03\u6574\u3002 \u6309\u5f53\u5e74\u8d22\u5e74\u7ed3\u675f\u8ba1\u7b97\uff0c\u8d77\u59cb\u5e74\u4efd\u5c31\u662f\u4e0a\u4e00\u5e74\u4e86\u3002 p = pd.Period(2020, freq='A-JUN') print(p.asfreq('M', how='start')) 2019-07 \u00b6 print(p.asfreq('M', how='end')) 2020-06 \u00b6 \u5f53\u4ece\u9ad8\u9891\u7387\u5411\u4f4e\u9891\u7387\u8f6c\u6362\u65f6\uff0cpandas\u6839\u636e\u5b50\u533a\u95f4\u7684\"\u6240\u5c5e\"\u6765\u51b3\u5b9a\u7236\u533a\u95f4\u3002 \u4f8b\u5982\uff0c\u5728A-JUN\u9891\u7387\u4e2d\uff0cAug-2020\u662f2020\u533a\u95f4\u7684\u4e00\u90e8\u5206\uff1a print(p.asfreq('A-JUN')) 2020\u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628a`year`\u548c`quarter`\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f15\u3002 \u5b8c\u6574\u7684`PeriodIndex`\u5bf9\u8c61\u6216\u65f6\u95f4\u5e8f\u5217\u53ef\u4ee5\u6309\u7167\u76f8\u540c\u7684\u8bed\u4e49\u8fdb\u884c\u8f6c\u6362\uff1a rng = pd.period_range('2018', '2021', freq='A-DEC') data = np.random.randn(len(rng)) ts = pd.Series(data, index=rng) print(ts) 2018 0.221634 \u00b6 2019 -0.392724 \u00b6 2020 -0.355022 \u00b6 2021 0.114000 \u00b6 Freq: A-DEC, dtype: float64 \u00b6 \u4e0b\u9762\u5e74\u5ea6\u533a\u95f4\u5c06\u901a\u8fc7`asfreq`\u88ab\u66ff\u6362\u4e3a\u5bf9\u5e94\u4e8e\u6bcf\u4e2a\u5e74\u5ea6\u533a\u95f4\u5185\u7684\u7b2c\u4e00\u4e2a\u6708\u7684\u6708\u5ea6\u533a\u95f4\u3002 print(ts.asfreq('M', how='start')) 2018-01 0.681874 \u00b6 2019-01 -1.006585 \u00b6 2020-01 -0.619142 \u00b6 2021-01 1.445820 \u00b6 Freq: M, dtype: float64 \u00b6 \u5982\u679c\u6211\u4eec\u60f3\u8981\u6bcf\u5e74\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528`B`\u9891\u7387\u6765\u8868\u793a\u6211\u4eec\u60f3\u8981\u7684\u662f\u533a\u95f4\u7684\u672b\u7aef\u3002 print(ts.asfreq('B', how='end')) 2018-12-31 -1.520316 \u00b6 2019-12-31 -0.425544 \u00b6 2020-12-31 -0.658073 \u00b6 2021-12-31 1.206881 \u00b6 Freq: B, dtype: float64 \u00b6 ### \u5b63\u5ea6\u533a\u95f4\u9891\u7387 \u5b63\u5ea6\u6570\u636e\u662f\u4f1a\u8ba1\u3001\u91d1\u878d\u548c\u5176\u4ed6\u9886\u57df\u7684\u6807\u51c6\u3002 \u5f88\u591a\u5b63\u5ea6\u6570\u636e\u662f\u5728\u8d22\u5e74\u7ed3\u5c3e\u62a5\u544a\u7684\uff0c\u901a\u5e38\u662f\u4e00\u5e7412\u4e2a\u6708\u4e2d\u7684\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5\u6216\u5de5\u4f5c\u65e5\u3002 pandas\u652f\u6301\u6240\u6709\u7684\u53ef\u80fd\u768412\u4e2a\u5b63\u5ea6\u9891\u7387\u4eceQ-JAN\u5230Q-DEC\uff1a \u4e0b\u4f8b\u4e2d\uff0c\u8d22\u5e74\u7ed3\u675f\u4e8e1\u6708\uff0c2020Q4\u884c\u65f6\u95f4\u4e3a\u4e0a\u4e00\u5e7411\u6708\u81f3\u5f53\u5e741\u6708\u3002\u53ef\u4ee5\u901a\u8fc7\u8f6c\u6362\u4e3a\u6bcf\u65e5\u9891\u7387\uff08asfreq\uff09\u8fdb\u884c\u68c0\u67e5\u3002 p = pd.Period('2020Q4', freq='Q-JAN') print(p) 2020Q4 \u00b6 print(p.asfreq('D', 'start')) 2019-11-01 \u00b6 print(p.asfreq('D', 'end')) 2020-01-31 \u00b6 \u5047\u5982\u8d22\u5e74\u7ed3\u675f\u4e8e2\u6708\uff0c2020Q4\u884c\u65f6\u95f4\u4e3a\u4e0a\u4e00\u5e7412\u6708\u81f3\u5f53\u5e742\u6708\u3002 p = pd.Period('2020Q4', freq='Q-FEB') print(p) 2020Q4 \u00b6 print(p.asfreq('D', 'start')) 2019-11-01 \u00b6 print(p.asfreq('D', 'end')) 2020-01-31 \u00b6 \u5047\u5982\u8d22\u5e74\u7ed3\u675f\u4e8e4\u6708\uff0c2020Q4\u884c\u65f6\u95f4\u4e3a\u4e0a\u4e00\u5e7412\u6708\u81f3\u5f53\u5e742\u6708\u3002 p = pd.Period('2020Q4', freq='Q-APR') print(p) 2020Q4 \u00b6 print(p.asfreq('D', 'start')) 2020-02-01 \u00b6 print(p.asfreq('D', 'end')) 2020-04-30 \u00b6 \u53ef\u4ee5\u5bf9\u533a\u95f4\u6570\u636e\u505a\u7b97\u672f\u64cd\u4f5c\u3002\u4f8b\u5982\uff0c\u8981\u83b7\u53d6\u5728\u5b63\u5ea6\u5012\u6570\u7b2c\u4e8c\u4e2a\u5de5\u4f5c\u65e5\u4e0b\u53484\u70b9\u7684\u65f6\u95f4\u6233\uff0c\u53ef\u4ee5\u8fd9\u4e48\u505a\uff1a(\u7591\u95ee\uff1a\u8fd9\u91cc\u7684\u53c2\u6570e\u4ee3\u8868\u4ec0\u4e48 ???) p4pm = (p.asfreq('B', 'e') - 1).asfreq('T', 's') + 16 * 60 print(p4pm) 2020-04-29 16:00 \u00b6 print(p4pm.to_timestamp()) 2020-04-29 16:00:00 \u00b6 \u53ef\u4ee5\u4f7f\u7528`peroid_range`\u751f\u6210\u5b63\u5ea6\u5e8f\u5217\u3002\u5b83\u7684\u7b97\u672f\u4e5f\u662f\u4e00\u6837\u7684\uff1a rng = pd.period_range('2000Q3', '2001Q4', freq='Q-JAN') ts = pd.Series(np.arange(len(rng)), index=rng) print(ts) 2000Q3 0 \u00b6 2000Q4 1 \u00b6 2001Q1 2 \u00b6 2001Q2 3 \u00b6 2001Q3 4 \u00b6 2001Q4 5 \u00b6 Freq: Q-JAN, dtype: int64 \u00b6 new_rng = (rng.asfreq('B', 'e') - 1).asfreq('T', 's') + 16 * 60 ts.index = new_rng.to_timestamp() print(ts) 1999-10-28 16:00:00 0 \u00b6 2000-01-28 16:00:00 1 \u00b6 2000-04-27 16:00:00 2 \u00b6 2000-07-28 16:00:00 3 \u00b6 2000-10-30 16:00:00 4 \u00b6 2001-01-30 16:00:00 5 \u00b6 dtype: int64 \u00b6 ### \u5c06\u65f6\u95f4\u6233\u8f6c\u6362\u4e3a\u533a\u95f4\uff08\u4ee5\u53ca\u9006\u8f6c\u6362\uff09 \u901a\u8fc7\u65f6\u95f4\u6233\u7d22\u5f15\u7684Series\u548cDataFrame\u53ef\u4ee5\u88ab`to_period`\u65b9\u6cd5\u8f6c\u6362\u4e3a\u533a\u95f4\uff1a rng = pd.date_range('2020-01-01', periods=3, freq='M') ts = pd.Series(np.random.randn(3), index=rng) print(ts) 2020-01-31 -0.567097 \u00b6 2020-02-29 0.63452\u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628ayear\u548cquarter\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f152 \u00b6 2020-03-31 0.297777 \u00b6 Freq: M, dtype: float64 \u00b6 pts = ts.to_period() print(pts) 2020-01 -0.567097 \u00b6 2020-02 0.634522 \u00b6 2020-03 0.297777 \u00b6 Freq: M, dtype: float64 \u00b6 \u7531\u4e8e\u533a\u95f4\u662f\u975e\u91cd\u53e0\u65f6\u95f4\u8303\u56f4\uff0c\u4e00\u4e2a\u65f6\u95f4\u6233\u53ea\u80fd\u5c5e\u4e8e\u7ed9\u5b9a\u9891\u7387\u7684\u5355\u4e2a\u533a\u95f4\u3002 \u5c3d\u7ba1\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u6839\u636e\u65f6\u95f4\u6233\u63a8\u65ad\u51fa\u65b0`PeriodIndex`\u7684\u9891\u7387\uff0c\u4f46\u53ef\u4ee5\u6307\u5b9a\u4efb\u4f55\u60f3\u8981\u7684\u9891\u7387\u3002 \u5728\u7ed3\u679c\u4e2d\u5305\u542b\u91cd\u590d\u7684\u533a\u95f4\u4e5f\u662f\u6ca1\u6709\u95ee\u9898\u7684\u3002 rng = pd.date_range('2020-01-01', periods=6, freq='D') ts = pd.Series(np.random.randn(6), index=rng) print(ts) 2020-01-01 -0.111287 \u00b6 2020-01-02 1.442234 \u00b6 2020-01-03 -0.767553 \u00b6 2020-01-04 -0.265064 \u00b6 2020-01-05 1.200312 \u00b6 2020-01-06 -1.782557 \u00b6 Freq: D, dtype: float64 \u00b6 ts_m = ts.to_period('M') # \u6307\u5b9aperiod\u7684\u9891\u7387\uff08M\uff09,\u8f93\u51fa\u7ed3\u679c\u5305\u542b\u91cd\u590dperiod print(ts_m) 2020-01 -0.111287 \u00b6 2020-01 1.442234 \u00b6 2020-01 -0.767553 \u00b6 2020-01 -0.265064 \u00b6 2020-01 1.200312 \u00b6 2020-01 -1.782557 \u00b6 Freq: M, dtype: float64 \u00b6 \u4f7f\u7528`to_timestamp`\u53ef\u4ee5\u5c06\u533a\u95f4\u518d\u8f6c\u6362\u4e3a\u65f6\u95f4\u6233\uff1a print(ts_m.to_timestamp(how='end')) 2020-01-31 23:59:59.999999999 -0.111287 \u00b6 2020-01-31 23:59:59.999999999 1.442234 \u00b6 2020-01-31 23:59:59.999999999 -0.767553 \u00b6 2020-01-31 23:59:59.999999999 -0.265064 \u00b6 2020-01-31 23:59:59.999999999 1.200312 \u00b6 2020-01-31 23:59:59.999999999 -1.782557 \u00b6 dtype: float64 \u00b6 print(ts_m.to_timestamp(how='start')) 2020-01-01 -0.111287 \u00b6 2020-01-01 1.442234 \u00b6 2020-01-01 -0.767553 \u00b6 2020-01-01 -0.265064 \u00b6 2020-01-01 1.200312 \u00b6 2020-01-01 -1.782557 \u00b6 dtype: float64 \u00b6 ### \u4ece\u6570\u7ec4\u751f\u6210PeriodIndex \u56fa\u5b9a\u9891\u7387\u6570\u636e\u96c6\u6709\u65f6\u5b58\u50a8\u5728\u8de8\u8d8a\u591a\u5217\u7684\u65f6\u95f4\u8303\u56f4\u4fe1\u606f\u4e2d\u3002\u4f8b\u5982\uff0c\u5728\u8fd9\u4e2a\u5b8f\u89c2\u7ecf\u6d4e\u6570\u636e\u96c6\u4e2d\uff0c\u5e74\u4efd\u548c\u5b63\u5ea6\u5728\u4e0d\u540c\u5217\u4e2d\uff1a data = pd.read_csv('../examples/macrodata.csv') print(data.head(5)) year quarter realgdp realcons ... unemp pop infl realint \u00b6 0 1959.0 1.0 2710.349 1707.4 ... 5.8 177.146 0.00 0.00 \u00b6 1 1959.0 2.0 2778.801 1733.7 ... 5.1 177.830 2.34 0.74 \u00b6 2 1959.0 3.0 2775.488 1751.8 ... 5.3 178.657 2.74 1.09 \u00b6 3 1959.0 4.0 2785.204 1753.7 ... 5.6 179.386 0.27 4.06 \u00b6 4 1960.0 1.0 2847.699 1770.5 ... 5.2 180.007 2.31 1.19 \u00b6 print(data.year) 0 1959.0 \u00b6 1 1959.0 \u00b6 2 1959.0 \u00b6 3 1959.0 \u00b6 4 1960.0 \u00b6 ... \u00b6 198 2008.0 \u00b6 199 2008.0 \u00b6 200 2009.0 \u00b6 201 2009.0 \u00b6 202 2009.0 \u00b6 Name: year, Length: 203, dtype: float64 \u00b6 print(data.quarter) 0 1.0 \u00b6 1 2.0 \u00b6 2 3.0 \u00b6 3 4.0 \u00b6 4 1.0 \u00b6 ... \u00b6 198 3.0 \u00b6 199 4.0 \u00b6 200 1.0 \u00b6 201 2.0 \u00b6 202 3.0 \u00b6 Name: quarter, Length: 203, dtype: float64 \u00b6 \u901a\u8fc7\u5c06\u8fd9\u4e9b\u6570\u7ec4\u548c\u9891\u7387\u4f20\u9012\u7ed9`PeriodIndex`\uff0c\u53ef\u4ee5\u8054\u5408\u5f62\u6210DataFrame\u7684\u7d22\u5f15 index = pd.PeriodIndex(year=data.year, quarter=data.quarter, freq='Q-DEC') print(index) PeriodIndex(['1959Q1', '1959Q2', '1959Q3', '1959Q4', '1960Q1', '1960Q2', \u00b6 '1960Q3', '1960Q4', '1961Q1', '1961Q2', \u00b6 ... \u00b6 '2007Q2', '2007Q3', '2007Q4', '2008Q1', '2008Q2', '2008Q3', \u00b6 '2008Q4', '2009Q1', '2009Q2', '2009Q3'], \u00b6 dtype='period[Q-DEC]', length=203) \u00b6 data.index = index # \u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628ayear\u548cquarter\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f15 print(data.infl) 1959Q1 0.00 \u00b6 1959Q2 2.34 \u00b6 1959Q3 2.74 \u00b6 1959Q4 0.27 \u00b6 1960Q1 2.31 \u00b6 ... \u00b6 2008Q3 -3.16 \u00b6 2008Q4 -8.79 \u00b6 2009Q1 0.94 \u00b6 2009Q2 3.37 \u00b6 2009Q3 3.56 \u00b6 Freq: Q-DEC, Name: infl, Length: 203, dtype: float64 \u00b6 ## \u91cd\u65b0\u91c7\u6837\u9891\u7387\u8f6c\u6362 import pandas as pd import numpy as np from pandas.tseries.frequencies import to_offset \u91cd\u65b0\u91c7\u6837\u662f\u6307\u5c06\u65f6\u95f4\u5e8f\u5217\u4ece\u4e00\u4e2a\u9891\u7387\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u9891\u7387\u7684\u8fc7\u7a0b\u3002 \u5c06\u66f4\u9ad8\u9891\u7387\u7684\u6570\u636e\u805a\u5408\u5230\u4f4e\u9891\u7387\u88ab\u79f0\u4e3a\u5411\u4e0b\u91c7\u6837\uff0c\u800c\u4ece\u4f4e\u9891\u7387\u8f6c\u6362\u5230\u9ad8\u9891\u7387\u79f0\u4e3a\u5411\u4e0a\u91c7\u6837\u3002 \u5e76\u4e0d\u662f\u6240\u6709\u7684\u91cd\u65b0\u91c7\u6837\u90fd\u5c5e\u4e8e\u4e0a\u9762\u8bf4\u7684\u4e24\u7c7b\u3002\u4f8b\u5982\uff0c\u5c06W-WED\uff08weekly on Wednesday\uff0c\u6bcf\u5468\u4e09\uff09\u8f6c\u6362\u5230W-FRI\uff08\u6bcf\u5468\u4e94\uff09\u65e2\u4e0d\u662f\u5411\u4e0a\u91c7\u6837\u4e5f\u4e0d\u662f\u5411\u4e0b\u91c7\u6837\u3002 pandas\u5bf9\u8c61\u90fd\u914d\u6709`resample`\u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u662f\u6240\u6709\u9891\u7387\u8f6c\u6362\u7684\u5de5\u5177\u51fd\u6570\u3002`resample`\u62e5\u6709\u7c7b\u4f3c\u4e8e`groupby`\u7684API\uff1b\u8c03\u7528`resample`\u5bf9\u6570\u636e\u5206\u7ec4\uff0c\u4e4b\u540e\u518d\u8c03\u7528\u805a\u5408\u51fd\u6570\uff1a ### resample\u65b9\u6cd5\u53c2\u6570 \u53c2\u6570 * freq: \u8868\u793a\u91cd\u91c7\u6837\u9891\u7387\uff0c\u4f8b\u5982\u2018M'\u3001\u20185min'\uff0cSecond(15) * how='mean': \u7528\u4e8e\u4ea7\u751f\u805a\u5408\u503c\u7684\u51fd\u6570\u540d\u6216\u6570\u7ec4\u51fd\u6570\uff0c\u4f8b\u5982\u2018mean'\u3001\u2018ohlc'\u3001np.max\u7b49\uff0c\u9ed8\u8ba4\u662f\u2018mean'\uff0c\u5176\u4ed6\u5e38\u7528\u7684\u503c\u7531\uff1a\u2018first'\u3001\u2018last'\u3001\u2018median'\u3001\u2018max'\u3001\u2018min' * axis=0: \u9ed8\u8ba4\u662f\u7eb5\u8f74\uff0c\u6a2a\u8f74\u8bbe\u7f6eaxis=1 * fill_method = None: \u5347\u91c7\u6837\u65f6\u5982\u4f55\u63d2\u503c\uff0c\u6bd4\u5982\u2018ffill'\u3001\u2018bfill'\u7b49 * closed = \u2018right': \u5728\u964d\u91c7\u6837\u65f6\uff0c\u5404\u65f6\u95f4\u6bb5\u7684\u54ea\u4e00\u6bb5\u662f\u95ed\u5408\u7684\uff0c\u2018right'\u6216\u2018left'\uff0c\u9ed8\u8ba4\u2018right' * label= \u2018right': \u5728\u964d\u91c7\u6837\u65f6\uff0c\u5982\u4f55\u8bbe\u7f6e\u805a\u5408\u503c\u7684\u6807\u7b7e\uff0c\u4f8b\u5982\uff0c9\uff1a30-9\uff1a35\u4f1a\u88ab\u6807\u8bb0\u62109\uff1a30\u8fd8\u662f9\uff1a35,\u9ed8\u8ba49\uff1a35 * loffset = None: \u9762\u5143\u6807\u7b7e\u7684\u65f6\u95f4\u6821\u6b63\u503c\uff0c\u6bd4\u5982\u2018-1s'\u6216Second(-1)\u7528\u4e8e\u5c06\u805a\u5408\u6807\u7b7e\u8c03\u65e91\u79d2 * limit=None: \u5728\u5411\u524d\u6216\u5411\u540e\u586b\u5145\u65f6\uff0c\u5141\u8bb8\u586b\u5145\u7684\u6700\u5927\u65f6\u671f\u6570 * kind = None: \u805a\u5408\u5230\u65f6\u671f\uff08\u2018period'\uff09\u6216\u65f6\u95f4\u6233\uff08\u2018timestamp'\uff09\uff0c\u9ed8\u8ba4\u805a\u5408\u5230\u65f6\u95f4\u5e8f\u5217\u7684\u7d22\u5f15\u7c7b\u578b * convention = None: \u5f53\u91cd\u91c7\u6837\u65f6\u671f\u65f6\uff0c\u5c06\u4f4e\u9891\u7387\u8f6c\u6362\u5230\u9ad8\u9891\u7387\u6240\u91c7\u7528\u7684\u7ea6\u5b9a\uff08start\u6216end\uff09\u3002\u9ed8\u8ba4\u2018end' rng = pd.date_range('2020-1-1', periods=100, freq='D') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(ts) 2020-01-01 0.802409 \u00b6 2020-01-02 -1.147130 \u00b6 2020-01-03 -1.076115 \u00b6 2020-01-04 -2.097443 \u00b6 2020-01-05 0.577671 \u00b6 ... \u00b6 2020-04-05 -0.110747 \u00b6 2020-04-06 0.132867 \u00b6 2020-04-07 -0.294061 \u00b6 2020-04-08 -0.246155 \u00b6 2020-04-09 0.927194 \u00b6 Freq: D, Length: 100, dtype: float64 \u00b6 print(ts.resample('M')) DatetimeIndexResampler [freq= , axis=0, closed=right, label=right, convention=start, origin=start_day] \u00b6 print(ts.resample('M').mean()) # \u628a100\u5929\u7684\u6570\u636e\u6309\u6708groupby\uff0c\u5e76\u8f93\u51fa\u6708\u672b\u6700\u540e\u4e00\u5929\uff0c\u8ba1\u7b97\u5e73\u5747\u503c 2020-01-31 -0.311714 \u00b6 2020-02-29 0.121526 \u00b6 2020-03-31 -0.051131 \u00b6 2020-04-30 -0.273113 \u00b6 Freq: M, dtype: float64 \u00b6 print(ts.resample('M', kind='period').mean()) # # \u628a100\u5929\u7684\u6570\u636e\u6309\u6708groupby\uff0c\u5e76\u8f93\u51fa\u6708\u4efd\uff08\u53c2\u6570period\uff09\uff0c\u8ba1\u7b97\u5e73\u5747\u503c 2020-01 -0.311714 \u00b6 2020-02 0.121526 \u00b6 2020-03 -0.051131 \u00b6 2020-04 -0.273113 \u00b6 Freq: M, dtype: float64 \u00b6 ### \u5411\u4e0b\u91c7\u6837 \u5c06\u6570\u636e\u805a\u5408\u5230\u4e00\u4e2a\u89c4\u5219\u7684\u4f4e\u9891\u7387\u4e0a\u662f\u4e00\u4e2a\u5e38\u89c1\u7684\u65f6\u95f4\u5e8f\u5217\u4efb\u52a1\u3002 \u8981\u805a\u5408\u7684\u6570\u636e\u4e0d\u5fc5\u662f\u56fa\u5b9a\u9891\u7387\u7684\u3002 \u671f\u671b\u7684\u9891\u7387\u5b9a\u4e49\u4e86\u7528\u4e8e\u5bf9\u65f6\u95f4\u5e8f\u5217\u5207\u7247\u4ee5\u805a\u5408\u7684\u7bb1\u4f53\u8fb9\u754c\u3002\u4f8b\u5982\uff0c\u8981\u5c06\u65f6\u95f4\u8f6c\u6362\u4e3a\u6bcf\u6708\uff0c`M`\u6216`BM`\uff0c\u5219\u9700\u8981\u5c06\u6570\u636e\u5206\u6210\u4e00\u4e2a\u6708\u7684\u65f6\u95f4\u95f4\u9694\u3002 \u6bcf\u4e2a\u95f4\u9694\u662f\u534a\u95ed\u5408\u7684\uff0c\u4e00\u4e2a\u6570\u636e\u70b9\u53ea\u80fd\u5c5e\u4e8e\u4e00\u4e2a\u65f6\u95f4\u95f4\u9694\uff0c\u65f6\u95f4\u95f4\u9694\u7684\u5e76\u96c6\u5fc5\u987b\u662f\u6574\u4e2a\u65f6\u95f4\u5e27\u3002 \u5728\u4f7f\u7528resample\u8fdb\u884c\u5411\u4e0b\u91c7\u6837\u6570\u636e\u65f6\u6709\u4e9b\u4e8b\u60c5\u9700\u8981\u8003\u8651\uff1a * \u6bcf\u6bb5\u95f4\u9694\u7684\u54ea\u4e00\u8fb9\u662f\u95ed\u5408\u7684\u3002 * \u5982\u4f55\u5728\u95f4\u9694\u7684\u8d77\u59cb\u6216\u7ed3\u675f\u4f4d\u7f6e\u6807\u8bb0\u6bcf\u4e2a\u5df2\u805a\u5408\u7684\u7bb1\u4f53\u3002 rng = pd.date_range('2020-1-1', periods=12, freq='T') ts = pd.Series(np.arange(12), index=rng) print(ts) 2020-01-01 00:00:00 0 \u00b6 2020-01-01 00:01:00 1 \u00b6 2020-01-01 00:02:00 2 \u00b6 2020-01-01 00:03:00 3 \u00b6 2020-01-01 00:04:00 4 \u00b6 2020-01-01 00:05:00 5 \u00b6 2020-01-01 00:06:00 6 \u00b6 2020-01-01 00:07:00 7 \u00b6 2020-01-01 00:08:00 8 \u00b6 2020-01-01 00:09:00 9 \u00b6 2020-01-01 00:10:00 10 \u00b6 2020-01-01 00:11:00 11 \u00b6 Freq: T, dtype: int64 \u00b6 \u6309\u4e94\u5206\u949f\u9891\u7387\u805a\u5408\u5206\u7ec4\uff0c\u8ba1\u7b97\u6bcf\u4e00\u7ec4\u7684\u52a0\u548c\u3002\u9891\u7387\u6309\u4e94\u5206\u949f\u7684\u589e\u91cf\u5b9a\u4e49\u4e86\u7bb1\u4f53\u8fb9\u754c\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5de6\u7bb1\u4f53\u8fb9\u754c\u662f\u5305\u542b\u7684\uff0c\u56e0\u6b6400:00\u7684\u503c\u662f\u5305\u542b\u572800:00\u523000:05\u95f4\u9694\u5185\u7684\u3002 \u4f20\u9012`closed='right'`\u5c06\u95f4\u9694\u7684\u95ed\u5408\u7aef\u6539\u4e3a\u4e86\u53f3\u8fb9\u3002 \u5206\u7ec4\uff1a * left: [00:00,00:01,00:02,00:03,00:04],[00:05,00:06,00:07,00:08,00:09],[00:10,00:11] * right:[00:00],[00:01,00:02,00:03,00:04,00:05],[00:06,00:07,00:08,00:09,00:10],[00:11] result = ts.resample('5min', closed='right').sum() print(result) 2019-12-31 23:55:00 0 \u00b6 2020-01-01 00:00:00 15 \u00b6 2020-01-01 00:05:00 40 \u00b6 2020-01-01 00:10:00 11 \u00b6 Freq: 5T, dtype: int64 \u00b6 result = ts.resample('5min', closed='left').sum() print(result) 2020-01-01 00:00:00 10 \u00b6 2020-01-01 00:05:00 35 \u00b6 2020-01-01 00:10:00 21 \u00b6 Freq: 5T, dtype: int64 \u00b6 \u6700\u540e\uff0c\u5c06\u7ed3\u679c\u7d22\u5f15\u79fb\u52a8\u4e00\u5b9a\u7684\u6570\u91cf\uff0c\u4f8b\u5982\u4ece\u53f3\u8fb9\u7f18\u51cf\u53bb\u4e00\u79d2\uff0c\u4ee5\u4f7f\u5176\u66f4\u6e05\u695a\u5730\u8868\u660e\u65f6\u95f4\u6233\u6240\u6307\u7684\u95f4\u9694\u3002 \u8981\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\uff0c\u5411`loffset`\u4f20\u9012\u5b57\u7b26\u4e32\u6216\u65e5\u671f\u504f\u7f6e\uff1a result = ts.resample('5min', closed='right', label='right', loffset='-1s').sum() print(result) 2019-12-31 23:59:59 0 \u00b6 2020-01-01 00:04:59 15 \u00b6 2020-01-01 00:09:59 40 \u00b6 2020-01-01 00:14:59 11 \u00b6 Freq: 5T, dtype: int64 \u00b6 FutureWarning: 'loffset' in .resample() and in Grouper() is deprecated. \u00b6 >>> df.resample(freq=\"3s\", loffset=\"8H\") \u00b6 becomes: \u00b6 >>> from pandas.tseries.frequencies import to_offset \u00b6 >>> df = df.resample(freq=\"3s\").mean() \u00b6 >>> df.index = df.index.to_timestamp() + to_offset(\"8H\") \u00b6 #### \u5f00\u7aef-\u5cf0\u503c-\u8c37\u503c-\u7ed3\u675f\uff08OHLC\uff09\u91cd\u65b0\u91c7\u6837 \u5728\u91d1\u878d\u4e2d\uff0c\u4e3a\u6bcf\u4e2a\u6570\u636e\u6876\u8ba1\u7b97\u56db\u4e2a\u503c\u662f\u4e00\u79cd\u6d41\u884c\u7684\u65f6\u95f4\u5e8f\u5217\u805a\u5408\u65b9\u6cd5\uff1a\u7b2c\u4e00\u4e2a\u503c\uff08\u5f00\u7aef\uff09\u3001\u6700\u540e\u4e00\u4e2a\u503c\uff08\u7ed3\u675f\uff09\u3001\u6700\u5927\u503c\uff08\u5cf0\u503c\uff09\u548c\u6700\u5c0f\u503c\uff08\u8c37\u503c\uff09\u3002 \u901a\u8fc7\u4f7f\u7528`ohlc`\u805a\u5408\u51fd\u6570\u53d6\u5f97\u5305\u542b\u56db\u79cd\u805a\u5408\u503c\u5217\u7684DataFrame\uff0c\u8fd9\u4e9b\u503c\u5728\u6570\u636e\u7684\u5355\u6b21\u626b\u63cf\u4e2d\u88ab\u9ad8\u6548\u8ba1\u7b97\uff1a result = ts.resample('5min').ohlc() print(result) open high low close \u00b6 2020-01-01 00:00:00 0 4 0 4 \u00b6 2020-01-01 00:05:00 5 9 5 9 \u00b6 2020-01-01 00:10:00 10 11 10 11 \u00b6 ### \u5411\u4e0a\u91c7\u6837\u4e0e\u63d2\u503c \u5f53\u4ece\u4f4e\u9891\u7387\u8f6c\u6362\u4e3a\u9ad8\u9891\u7387\u65f6\uff0c\u5e76\u4e0d\u9700\u8981\u4efb\u4f55\u805a\u5408\u3002 df = pd.DataFrame( np.random.randn(2, 4), index=pd.date_range('2020/1/1', periods=2, freq='W-WED'), columns=['Colorado', 'Texas', 'New York', 'Ohio'] ) print(df) Colorado Texas New York Ohio \u00b6 2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-08 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 df_daily = df.resample('W-WED').sum() print(df_daily) Colorado Texas New York Ohio \u00b6 2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-08 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 df_daily = df.resample('D').sum() print(df_daily) Colorado Texas New York Ohio \u00b6 2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-02 0.000000 0.000000 0.000000 0.000000 \u00b6 2020-01-03 0.000000 0.000000 0.000000 0.000000 \u00b6 2020-01-04 0.000000 0.000000 0.000000 0.000000 \u00b6 2020-01-05 0.000000 0.000000 0.000000 0.000000 \u00b6 2020-01-06 0.000000 0.000000 0.000000 0.000000 \u00b6 2020-01-07 0.000000 0.000000 0.000000 0.000000 \u00b6 2020-01-08 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 \u5f53\u5bf9\u8fd9\u4e9b\u6570\u636e\u4f7f\u7528\u805a\u5408\u51fd\u6570\u65f6\uff0c\u6bcf\u4e00\u7ec4\u53ea\u6709\u4e00\u4e2a\u503c\uff0c\u5e76\u4e14\u4f1a\u5728\u95f4\u9699\u4e2d\u4ea7\u751f\u7f3a\u5931\u503c\u3002 \u4f7f\u7528`asfreq`\u65b9\u6cd5\u5728\u4e0d\u805a\u5408\u7684\u60c5\u51b5\u4e0b\u8f6c\u6362\u5230\u9ad8\u9891\u7387\uff1a df_daily = df.resample('D').asfreq() print(df_daily) Colorado Texas New York Ohio \u00b6 2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-02 NaN NaN NaN NaN \u00b6 2020-01-03 NaN NaN NaN NaN \u00b6 2020-01-04 NaN NaN NaN NaN \u00b6 2020-01-05 NaN NaN NaN NaN \u00b6 2020-01-06 NaN NaN NaN NaN \u00b6 2020-01-07 NaN NaN NaN NaN \u00b6 2020-01-08 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 \u5728\u975e\u661f\u671f\u4e09\u7684\u65e5\u671f\u4e0a\u5411\u524d\u586b\u5145\u6bcf\u5468\u6570\u503c\u3002`fillna`\u548c`reindex`\u65b9\u6cd5\u4e2d\u53ef\u7528\u7684\u586b\u5145\u6216\u63d2\u503c\u65b9\u6cd5\u53ef\u7528\u4e8e\u91cd\u91c7\u6837\uff1a df_daily = df.resample('D').ffill() print(df_daily) Colorado Texas New York Ohio \u00b6 2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-02 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-03 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-04 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-05 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-06 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-07 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-08 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 \u53ef\u4ee5\u540c\u6837\u9009\u62e9\u4ec5\u5411\u524d\u586b\u5145\u4e00\u5b9a\u6570\u91cf\u7684\u533a\u95f4\uff0c\u4ee5\u9650\u5236\u7ee7\u7eed\u4f7f\u7528\u89c2\u6d4b\u503c\u7684\u65f6\u8ddd\uff1a df_daily = df.resample('D').ffill(limit=2) print(df_daily) Colorado Texas New York Ohio \u00b6 2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-02 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-03 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-04 NaN NaN NaN NaN \u00b6 2020-01-05 NaN NaN NaN NaN \u00b6 2020-01-06 NaN NaN NaN NaN \u00b6 2020-01-07 NaN NaN NaN NaN \u00b6 2020-01-08 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 \u6ce8\u610f\uff0c\u65b0\u7684\u65e5\u671f\u7d22\u5f15\u4e0d\u9700\u8981\u4e0e\u65e7\u7684\u7d22\u5f15\u91cd\u53e0\uff0c\u548c\u539f\u6765`df`\u7684\u503c\u4e00\u6837\uff0c\u53ea\u662f\u65e5\u671f\u7d22\u5f15\u53d8\u4e86\u3002 df_new = df.resample('W-THU').ffill() print(df_new) Colorado Texas New York Ohio \u00b6 2020-01-02 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-09 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 ### \u4f7f\u7528\u533a\u95f4\u8fdb\u884c\u91cd\u65b0\u91c7\u6837 \u5bf9\u4ee5\u533a\u95f4\u4e3a\u7d22\u5f15\u7684\u6570\u636e\u8fdb\u884c\u91c7\u6837\u4e0e\u65f6\u95f4\u6233\u7684\u60c5\u51b5\u7c7b\u4f3c\uff1a df = pd.DataFrame( np.random.randn(24, 4), index=pd.period_range('2020-1', periods=24, freq='M'), columns=['Colorado', 'Texas', 'New York', 'Ohio'] ) print(df) 2020-01 0.721395 -1.492674 0.707410 1.641890 \u00b6 2020-02 -0.894880 0.032823 -0.676158 0.029203 \u00b6 2020-03 2.147365 -0.176796 0.562695 -0.747656 \u00b6 2020-04 1.496037 -0.797119 -0.495601 0.774147 \u00b6 2020-05 -0.309839 0.502563 0.237244 0.910624 \u00b6 2020-06 1.231869 -0.105227 1.315759 0.217701 \u00b6 2020-07 1.447419 0.263876 -0.342045 -0.768907 \u00b6 2020-08 -2.567162 -1.008827 0.391085 1.259560 \u00b6 2020-09 -0.772501 1.183532 0.450374 0.450714 \u00b6 2020-10 0.228974 0.461224 1.393178 0.175243 \u00b6 2020-11 -0.725193 -1.544131 1.372029 -0.659224 \u00b6 2020-12 0.718195 0.862024 -0.166460 -0.940191 \u00b6 2021-01 -0.617054 -0.887312 0.338451 -1.392838 \u00b6 2021-02 -0.081140 0.634730 -0.868051 -1.277167 \u00b6 2021-03 -0.999642 -1.959715 -0.930662 0.748687 \u00b6 2021-04 1.851453 1.561669 -0.688822 -0.371255 \u00b6 2021-05 -0.540777 -0.890403 -1.204188 0.243480 \u00b6 2021-06 1.318905 1.247457 0.518969 0.799793 \u00b6 2021-07 0.223238 0.747177 -0.410889 0.904593 \u00b6 2021-08 -0.652551 -0.254351 -0.464604 -0.676923 \u00b6 2021-09 0.562312 0.182099 0.018617 0.573331 \u00b6 2021-10 0.429490 -0.045959 -0.356292 -0.295776 \u00b6 2021-11 2.552155 0.801299 1.378421 1.232792 \u00b6 2021-12 1.102288 0.850280 -0.767015 -0.519840 \u00b6 df_annual = df.resample('A-DEC').mean() print(df_annual) Colorado Texas New York Ohio \u00b6 2020 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021 0.429056 0.165581 -0.286339 -0.002594 \u00b6 \u5411\u4e0a\u91c7\u6837\u66f4\u4e3a\u7ec6\u81f4\uff0c\u56e0\u4e3a\u5fc5\u987b\u5728\u91cd\u65b0\u91c7\u6837\u524d\u51b3\u5b9a\u65b0\u9891\u7387\u4e2d\u5728\u65f6\u95f4\u6bb5\u7684\u54ea\u4e00\u7aef\u653e\u7f6e\u6570\u503c\uff0c\u5c31\u50cfasfreq\u65b9\u6cd5\u4e00\u6837\u3002 `convention`\u53c2\u6570\u9ed8\u8ba4\u503c\u662f`start`\uff0c\u4f46\u4e5f\u53ef\u4ee5\u662f`end`\uff1a result = df_annual.resample('Q-DEC').ffill() print(result) Colorado Texas New York Ohio \u00b6 2020Q1 0.226807 -0.151561 0.395793 0.195259 \u00b6 2020Q2 0.226807 -0.151561 0.395793 0.195259 \u00b6 2020Q3 0.226807 -0.151561 0.395793 0.195259 \u00b6 2020Q4 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q1 0.429056 0.165581 -0.286339 -0.002594 \u00b6 2021Q2 0.429056 0.165581 -0.286339 -0.002594 \u00b6 2021Q3 0.429056 0.165581 -0.286339 -0.002594 \u00b6 2021Q4 0.429056 0.165581 -0.286339 -0.002594 \u00b6 result = df_annual.resample('Q-DEC', convention='end').ffill() print(result) Colorado Texas New York Ohio \u00b6 2020Q4 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q1 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q2 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q3 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q4 0.429056 0.165581 -0.286339 -0.002594 \u00b6 \u7531\u4e8e\u533a\u95f4\u6d89\u53ca\u65f6\u95f4\u8303\u56f4\uff0c\u5411\u4e0a\u91c7\u6837\u548c\u5411\u4e0b\u91c7\u6837\u5c31\u66f4\u4e3a\u4e25\u683c\uff1a * \u5728\u5411\u4e0b\u91c7\u6837\u4e2d\uff0c\u76ee\u6807\u9891\u7387\u5fc5\u987b\u662f\u539f\u9891\u7387\u7684\u5b50\u533a\u95f4\u3002 * \u5728\u5411\u4e0a\u91c7\u6837\u4e2d\uff0c\u76ee\u6807\u9891\u7387\u5fc5\u987b\u662f\u539f\u9891\u7387\u7684\u7236\u533a\u95f4\u3002 \u5982\u679c\u4e0d\u6ee1\u8db3\u8fd9\u4e9b\u89c4\u5219\uff0c\u5c06\u4f1a\u5f15\u8d77\u5f02\u5e38\u3002\u8fd9\u4e3b\u8981\u4f1a\u5f71\u54cd\u6bcf\u5b63\u5ea6\u3001\u6bcf\u5e74\u548c\u6bcf\u5468\u7684\u9891\u7387\u3002 \u4f8b\u5982\uff0c\u6839\u636eQ-MAR\u5b9a\u4e49\u7684\u65f6\u95f4\u8303\u56f4\u5c06\u53ea\u548cA-MAR\u3001A-JUN\u3001A-SEP\u548cA-DEC\u4fdd\u6301\u4e00\u81f4\uff1a result = df_annual.resample('Q-MAR').ffill() print(result) Colorado Texas New York Ohio \u00b6 2020Q4 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q1 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q2 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q3 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q4 0.429056 0.165581 -0.286339 -0.002594 \u00b6 2022Q1 0.429056 0.165581 -0.286339 -0.002594 \u00b6 2022Q2 0.429056 0.165581 -0.286339 -0.002594 \u00b6 2022Q3 0.429056 0.165581 -0.286339 -0.002594 \u00b6 ## \u79fb\u52a8\u7a97\u53e3\u51fd\u6570 \u7edf\u8ba1\u90a3\u4e9b\u901a\u8fc7\u79fb\u52a8\u7a97\u53e3\u6216\u6307\u6570\u8870\u51cf\u800c\u8fd0\u884c\u7684\u51fd\u6570\uff0c\u662f\u7528\u4e8e\u65f6\u95f4\u5e8f\u5217\u64cd\u4f5c\u7684\u6570\u7ec4\u53d8\u6362\u7684\u4e00\u4e2a\u91cd\u8981\u7c7b\u522b\u3002 \u8fd9\u5bf9\u5e73\u6ed1\u566a\u58f0\u6216\u7c97\u7cd9\u7684\u6570\u636e\u975e\u5e38\u6709\u7528\u3002\u79f0\u8fd9\u4e9b\u51fd\u6570\u4e3a\u79fb\u52a8\u7a97\u53e3\u51fd\u6570\uff0c\u5c3d\u7ba1\u5b83\u4e5f\u5305\u542b\u4e86\u4e00\u4e9b\u6ca1\u6709\u56fa\u5b9a\u957f\u5ea6\u7a97\u53e3\u7684\u51fd\u6570\uff0c\u6bd4\u5982\u6307\u6570\u52a0\u6743\u79fb\u52a8\u5e73\u5747\u3002 \u4e0e\u5176\u4ed6\u7684\u7edf\u8ba1\u51fd\u6570\u7c7b\u4f3c\uff0c\u8fd9\u4e9b\u51fd\u6570\u4f1a\u81ea\u52a8\u6392\u9664\u7f3a\u5931\u6570\u636e\u3002 import matplotlib.pyplot as plt import pandas as pd from scipy.stats import percentileofscore import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd import pytz \u5728\u6df1\u5165\u4e86\u89e3\u4e4b\u524d\uff0c\u6211\u4eec\u53ef\u4ee5\u5148\u8f7d\u5165\u4e00\u4e9b\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u5e76\u6309\u7167\u5de5\u4f5c\u65e5\u9891\u7387\u8fdb\u884c\u91cd\u65b0\u91c7\u6837\uff1a close_px_all = pd.read_csv( '../examples/stock_px_2.csv', parse_dates = True, index_col=0 ) print(close_px_all.head(5)) AAPL MSFT XOM SPX \u00b6 2003-01-02 7.40 21.11 29.22 909.03 \u00b6 2003-01-03 7.45 21.14 29.24 908.59 \u00b6 2003-01-06 7.45 21.52 29.96 929.01 \u00b6 2003-01-07 7.43 21.93 28.95 922.93 \u00b6 2003-01-08 7.28 21.31 28.83 909.93 \u00b6 close_px = close_px_all[ ['AAPL', 'MSFT', 'XOM'] ] close_px = close_px.resample('B').ffill() print(close_px) AAPL MSFT XOM \u00b6 2003-01-02 7.40 21.11 29.22 \u00b6 2003-01-03 7.45 21.14 29.24 \u00b6 ... ... ... ... \u00b6 2011-10-13 408.43 27.18 76.37 \u00b6 2011-10-14 422.00 27.27 78.11 \u00b6 [2292 rows x 3 columns] \u00b6 `rolling`\u7b97\u5b50\uff0c\u5b83\u7684\u884c\u4e3a\u4e0e`resample`\u548c`groupby`\u7c7b\u4f3c\u3002 `rolling`\u53ef\u4ee5\u5728Series\u6216DataFrame\u4e0a\u901a\u8fc7\u4e00\u4e2awindow\uff08\u4ee5\u4e00\u4e2a\u533a\u95f4\u7684\u6570\u5b57\u6765\u8868\u793a\uff09\u8fdb\u884c\u8c03\u7528\u3002 close_px.AAPL.plot() \u8868\u8fbe\u5f0f`rolling(250)`\u4e0e`groupby`\u7684\u884c\u4e3a\u7c7b\u4f3c\uff0c\u4f46\u662f\u5b83\u521b\u5efa\u7684\u5bf9\u8c61\u662f\u6839\u636e250\u65e5\u6ed1\u52a8\u7a97\u53e3\u5206\u7ec4\u7684\u800c\u4e0d\u662f\u76f4\u63a5\u5206\u7ec4\u3002 \u56e0\u6b64\u8fd9\u91cc\u6211\u4eec\u83b7\u5f97\u4e86\u82f9\u679c\u516c\u53f8\u80a1\u7968\u4ef7\u683c\u7684250\u65e5\u79fb\u52a8\u7a97\u53e3\u5e73\u5747\u503c\u3002 close_px.AAPL.rolling(250).mean().plot() plt.show() \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6eda\u52a8\u51fd\u6570\u9700\u8981\u7a97\u53e3\u4e2d\u6240\u6709\u7684\u503c\u5fc5\u987b\u662f\u975e`NA`\u503c\u3002 \u7531\u4e8e\u5b58\u5728\u7f3a\u5931\u503c\u8fd9\u79cd\u884c\u4e3a\u4f1a\u53d1\u751f\u6539\u53d8\uff0c\u5c24\u5176\u662f\u5728\u65f6\u95f4\u5e8f\u5217\u7684\u8d77\u59cb\u4f4d\u7f6e\u4f60\u62e5\u6709\u7684\u6570\u636e\u662f\u5c11\u4e8e\u7a97\u53e3\u533a\u95f4\u7684 apple_std250 = close_px.AAPL.rolling(250, min_periods=10).std() # \u82f9\u679c\u516c\u53f8250\u65e5\u6bcf\u65e5\u8fd4\u56de\u6807\u51c6\u5dee print(apple_std250[5:12]) 2003-01-09 NaN \u00b6 2003-01-10 NaN \u00b6 2003-01-13 NaN \u00b6 2003-01-14 NaN \u00b6 2003-01-15 0.077496 \u00b6 2003-01-16 0.074760 \u00b6 2003-01-17 0.112368 \u00b6 Freq: B, Name: AAPL, dtype: float64 \u00b6 apple_std250.plot() plt.show() expanding_mean = apple_std250.expanding().mean() print(expanding_mean[5:12]) 2003-01-09 NaN \u00b6 2003-01-10 NaN \u00b6 2003-01-13 NaN \u00b6 2003-01-14 NaN \u00b6 2003-01-15 0.077496 \u00b6 2003-01-16 0.076128 \u00b6 2003-01-17 0.088208 \u00b6 Freq: B, Name: AAPL, dtype: float64 \u00b6 expanding_mean.plot() plt.show() \u5728DataFrame\u4e0a\u8c03\u7528\u4e00\u4e2a\u79fb\u52a8\u7a97\u53e3\u51fd\u6570\u4f1a\u5c06\u53d8\u6362\u5e94\u7528\u5230\u6bcf\u4e00\u5217\u4e0a: close_px.rolling(60).mean().plot(logy=True) # \u80a1\u7968\u4ef7\u683c60\u65e5MA\uff08Y\u8f74\u53d6\u5bf9\u6570\uff09 plt.show() `rolling`\u51fd\u6570\u4e5f\u63a5\u6536\u8868\u793a\u56fa\u5b9a\u5927\u5c0f\u7684\u65f6\u95f4\u504f\u7f6e\u5b57\u7b26\u4e32\uff0c\u800c\u4e0d\u53ea\u662f\u4e00\u4e2a\u533a\u95f4\u7684\u96c6\u5408\u6570\u5b57\u3002 \u5bf9\u4e0d\u89c4\u5219\u65f6\u95f4\u5e8f\u5217\u4f7f\u7528\u6ce8\u91ca\u975e\u5e38\u6709\u7528\u3002\u8fd9\u4e9b\u5b57\u7b26\u4e32\u53ef\u4ee5\u4f20\u9012\u7ed9`resample`\u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u50cf\u8fd9\u6837\u8ba1\u7b9720\u5929\u7684\u6eda\u52a8\u5e73\u5747\u503c\uff1a result = close_px.rolling('20D').mean() print(result) AAPL MSFT XOM \u00b6 2003-01-02 7.400000 21.110000 29.220000 \u00b6 ... ... ... ... \u00b6 2011-10-14 391.038000 26.048667 74.185333 \u00b6 [2292 rows x 3 columns] \u00b6 result.plot() plt.show() ### \u6307\u6570\u52a0\u6743\u51fd\u6570 \u6307\u5b9a\u4e00\u4e2a\u5e38\u6570\u8870\u51cf\u56e0\u5b50\u4ee5\u5411\u66f4\u591a\u8fd1\u671f\u89c2\u6d4b\u503c\u63d0\u4f9b\u66f4\u591a\u6743\u91cd\uff0c\u53ef\u4ee5\u66ff\u4ee3\u4f7f\u7528\u5177\u6709\u76f8\u7b49\u52a0\u6743\u89c2\u5bdf\u503c\u7684\u9759\u6001\u7a97\u53e3\u5c3a\u5bf8\u7684\u65b9\u6cd5\u3002 \u6709\u591a\u79cd\u65b9\u5f0f\u53ef\u4ee5\u6307\u5b9a\u8870\u51cf\u56e0\u5b50\u3002\u5176\u4e2d\u4e00\u79cd\u6d41\u884c\u7684\u65b9\u5f0f\u662f\u4f7f\u7528\u4e00\u4e2aspan\uff08\u8de8\u5ea6\uff09\uff0c\u8fd9\u4f7f\u5f97\u7ed3\u679c\u4e0e\u7a97\u53e3\u5927\u5c0f\u7b49\u4e8e\u8de8\u5ea6\u7684\u7b80\u5355\u79fb\u52a8\u7a97\u53e3\u51fd\u6570\u3002 \u7531\u4e8e\u6307\u6570\u52a0\u6743\u7edf\u8ba1\u503c\u7ed9\u66f4\u8fd1\u671f\u7684\u89c2\u6d4b\u503c\u4ee5\u66f4\u591a\u7684\u6743\u91cd\uff0c\u4e0e\u7b49\u6743\u91cd\u7684\u7248\u672c\u76f8\u6bd4\uff0c\u5b83\u5bf9\u53d8\u5316\u201c\u9002\u5e94\u201d\u5f97\u66f4\u5feb\u3002 pandas\u62e5\u6709`ewm`\u7b97\u5b50\uff0c\u540c`rolling`\u3001`expanding`\u7b97\u5b50\u4e00\u8d77\u4f7f\u7528\u3002 \u4ee5\u4e0b\u662f\u5c06\u82f9\u679c\u516c\u53f8\u80a1\u7968\u4ef7\u683c\u768460\u65e5\u5747\u7ebf\u4e0e`span=60`\u7684EW\u79fb\u52a8\u5e73\u5747\u7ebf\u8fdb\u884c\u6bd4\u8f83\u7684\u4f8b\u5b50\uff1a aapl_ex = close_px.AAPL['2006':'2007'] ma60 = aapl_ex.rolling(30, min_periods=20).mean() ewma60 = aapl_ex.ewm(span=30).mean() ma60.plot(style='k--', label='Simple MA') ewma60.plot(style='k-', label='EWMA') plt.legend() plt.show() ### \u4e8c\u5143\u79fb\u52a8\u7a97\u53e3\u51fd\u6570 \u4e00\u4e9b\u7edf\u8ba1\u7b97\u5b50\uff0c\u4f8b\u5982\u76f8\u5173\u5ea6\u548c\u534f\u65b9\u5dee\uff0c\u9700\u8981\u64cd\u4f5c\u4e24\u4e2a\u65f6\u95f4\u5e8f\u5217\u3002 \u4f8b\u5982\uff0c\u91d1\u878d\u5206\u6790\u5e08\u7ecf\u5e38\u5bf9\u80a1\u7968\u4e0e\u57fa\u51c6\u6307\u6570\uff08\u5982\u6807\u666e500\uff09\u7684\u5173\u8054\u6027\u611f\u5174\u8da3\u3002 \u6211\u4eec\u9996\u5148\u8ba1\u7b97\u6240\u6709\u6211\u4eec\u611f\u5174\u8da3\u7684\u65f6\u95f4\u5e8f\u5217\u7684\u767e\u5206\u6bd4\u53d8\u5316\uff1a spx_px = close_px_all['SPX'] spx_rets = spx_px.pct_change() returns = close_px.pct_change() \u5728\u8c03\u7528rolling\u540e\uff0ccorr\u805a\u5408\u51fd\u6570\u53ef\u4ee5\u6839\u636espx_rets\u8ba1\u7b97\u6eda\u52a8\u76f8\u5173\u6027\uff1a \u00b6 corr = returns.AAPL.rolling(125, min_periods=100).corr(spx_rets) # \u82f9\u679c\u516c\u53f8\u4e0e\u6807\u666e500\u7684\u516d\u4e2a\u6708\u7684\u6536\u76ca\u76f8\u5173\u6027 corr.plot() plt.show() corr = returns.rolling(125, min_periods=100).corr(spx_rets) # \u591a\u53ea\u80a1\u7968\u4e0e\u6807\u666e500\u7684\u516d\u4e2a\u6708\u6536\u76ca\u76f8\u5173\u6027 corr.plot() plt.show() ### \u7528\u6237\u81ea\u5b9a\u4e49\u7684\u79fb\u52a8\u7a97\u53e3\u51fd\u6570 \u5728`rolling`\u53ca\u5176\u76f8\u5173\u65b9\u6cd5\u4e0a\u4f7f\u7528apply\u65b9\u6cd5\u63d0\u4f9b\u4e86\u4e00\u79cd\u5728\u79fb\u52a8\u7a97\u53e3\u4e2d\u5e94\u7528\u4f60\u81ea\u5df1\u8bbe\u8ba1\u7684\u6570\u7ec4\u51fd\u6570\u7684\u65b9\u6cd5\u3002 \u552f\u4e00\u7684\u8981\u6c42\u662f\u8be5\u51fd\u6570\u4ece\u6bcf\u4e2a\u6570\u7ec4\u4e2d\u4ea7\u751f\u4e00\u4e2a\u5355\u503c\uff08\u7f29\u805a\uff09\u3002 \u4f8b\u5982\uff0c\u5c3d\u7ba1\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528`rolling(...).quantile(q)`\u8ba1\u7b97\u6837\u672c\u7684\u5206\u4f4d\u6570\uff0c\u4f46\u6211\u4eec\u53ef\u80fd\u4f1a\u5bf9\u6837\u672c\u4e2d\u7279\u5b9a\u503c\u7684\u767e\u5206\u4f4d\u6570\u611f\u5174\u8da3\u3002 `scipy.stats.percentileofscore`\u51fd\u6570\u5c31\u662f\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\u7684\uff1a score_at_2percent = lambda x: percentileofscore(x, 0.02) result = returns.AAPL.rolling(250).apply(score_at_2percent) # \u4e00\u5e74\u7a97\u53e3\u4e0b\u82f9\u679c\u516c\u53f8\u80a1\u4ef72%\u6536\u76ca\u7684\u767e\u5206\u4f4d\u7b49\u7ea7 result.plot() plt.show() result = returns.rolling(250).apply(score_at_2percent) # \u4e00\u5e74\u7a97\u53e3\u4e0b\u6240\u6709\u516c\u53f8\u80a1\u4ef72%\u6536\u76ca\u7684\u767e\u5206\u4f4d\u7b49\u7ea7 result.plot() plt.show() ```","title":"\u65f6\u95f4\u5e8f\u5217"},{"location":"python/DataAnalysis/ch08/#_1","text":"","title":"\u65f6\u95f4\u5e8f\u5217"},{"location":"python/DataAnalysis/ch08/#_2","text":"\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u5728\u5f88\u591a\u9886\u57df\u90fd\u662f\u91cd\u8981\u7684\u7ed3\u6784\u5316\u6570\u636e\u5f62\u5f0f\u3002\u5728\u591a\u4e2a\u65f6\u95f4\u70b9\u89c2\u6d4b\u6216\u6d4b\u91cf\u7684\u6570\u636e\u5f62\u6210\u4e86\u65f6\u95f4\u5e8f\u5217\u3002 \u8bb8\u591a\u65f6\u95f4\u5e8f\u5217\u662f\u56fa\u5b9a\u9891\u7387\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\u6570\u636e\u662f\u6839\u636e\u76f8\u540c\u7684\u89c4\u5219\u5b9a\u671f\u51fa\u73b0\u7684\uff0c\u4f8b\u5982\u6bcf15\u79d2\u3001\u6bcf5\u5206\u949f\u6216\u6bcf\u67081\u6b21\u3002 \u65f6\u95f4\u5e8f\u5217\u4e5f\u53ef\u4ee5\u662f\u4e0d\u89c4\u5219\u7684\uff0c\u6ca1\u6709\u56fa\u5b9a\u7684\u65f6\u95f4\u5355\u4f4d\u6216\u5355\u4f4d\u95f4\u7684\u504f\u79fb\u91cf\u3002 \u5982\u4f55\u6807\u8bb0\u548c\u5f15\u7528\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u53d6\u51b3\u4e8e\u5e94\u7528\u7a0b\u5e8f\uff0c\u65f6\u95f4\u5e8f\u5217\u5305\u62ec\uff1a \u65f6\u95f4\u6233\uff0c\u5177\u4f53\u7684\u65f6\u523b\u3002 \u56fa\u5b9a\u7684\u65f6\u95f4\u533a\u95f4\uff0c\u4f8b\u59822007\u76841\u6708\u6216\u6574\u4e2a2010\u5e74\u3002 \u65f6\u95f4\u95f4\u9694\uff0c\u7531\u5f00\u59cb\u548c\u7ed3\u675f\u65f6\u95f4\u6233\u8868\u793a\u3002\u65f6\u95f4\u533a\u95f4\u53ef\u4ee5\u88ab\u8ba4\u4e3a\u662f\u95f4\u9694\u7684\u7279\u6b8a\u60c5\u51b5\u3002 \u5b9e\u9a8c\u65f6\u95f4\u6216\u6d88\u8017\u65f6\u95f4\u3002\u6bcf\u4e2a\u65f6\u95f4\u6233\u662f\u76f8\u5bf9\u4e8e\u7279\u5b9a\u5f00\u59cb\u65f6\u95f4\u7684\u65f6\u95f4\u7684\u91cf\u5ea6\uff08\u4f8b\u5982\uff0c\u81ea\u4ece\u88ab\u653e\u7f6e\u5728\u70e4\u7bb1\u4e2d\u6bcf\u79d2\u70d8\u70e4\u7684\u997c\u5e72\u7684\u76f4\u5f84\uff09\u3002 \u76ee\u524d\u4e3b\u8981\u5173\u6ce8\u524d\u4e09\u7c7b\u4e2d\u7684\u65f6\u95f4\u5e8f\u5217\u3002 from datetime import datetime, timedelta import datetime as dt from dateutil.parser import parse import pandas as pd","title":"\u65e5\u671f\u548c\u65f6\u95f4\u6570\u636e\u7684\u7c7b\u578b\u53ca\u5de5\u5177"},{"location":"python/DataAnalysis/ch08/#datetime","text":"datetime\u683c\u5f0f\u7b26\uff1a %a \u661f\u671f\u7684\u82f1\u6587\u5355\u8bcd\u7684\u7f29\u5199\uff1a\u5982\u661f\u671f\u4e00\uff0c \u5219\u8fd4\u56de Mon %A \u661f\u671f\u7684\u82f1\u6587\u5355\u8bcd\u7684\u5168\u62fc\uff1a\u5982\u661f\u671f\u4e00\uff0c\u8fd4\u56de Monday %b \u6708\u4efd\u7684\u82f1\u6587\u5355\u8bcd\u7684\u7f29\u5199\uff1a\u5982\u4e00\u6708\uff0c \u5219\u8fd4\u56de Jan %B \u6708\u4efd\u7684\u5f15\u6587\u5355\u8bcd\u7684\u7f29\u5199\uff1a\u5982\u4e00\u6708\uff0c \u5219\u8fd4\u56de January %c \u8fd4\u56dedatetime\u7684\u5b57\u7b26\u4e32\u8868\u793a\uff0c\u598203/08/15 23:01:26 %d \u8fd4\u56de\u7684\u662f\u5f53\u524d\u65f6\u95f4\u662f\u5f53\u524d\u6708\u7684\u7b2c\u51e0\u5929 %f \u5fae\u79d2\u7684\u8868\u793a\uff1a \u8303\u56f4: [0,999999] %H \u4ee524\u5c0f\u65f6\u5236\u8868\u793a\u5f53\u524d\u5c0f\u65f6 %I \u4ee512\u5c0f\u65f6\u5236\u8868\u793a\u5f53\u524d\u5c0f\u65f6 %m \u8fd4\u56de\u6708\u4efd \u8303\u56f4[0,12] %M \u8fd4\u56de\u5206\u949f\u6570 \u8303\u56f4 [0,59] %P \u8fd4\u56de\u662f\u4e0a\u5348\u8fd8\u662f\u4e0b\u5348\u2013AM or PM %S \u8fd4\u56de\u79d2\u6570 \u8303\u56f4 [0,61]\u3002\u3002\u3002\u624b\u518c\u8bf4\u660e\u7684 %U \u8fd4\u56de\u5f53\u5468\u662f\u5f53\u5e74\u7684\u7b2c\u51e0\u5468 \u4ee5\u5468\u65e5\u4e3a\u7b2c\u4e00\u5929 %W \u8fd4\u56de\u5f53\u5468\u662f\u5f53\u5e74\u7684\u7b2c\u51e0\u5468 \u4ee5\u5468\u4e00\u4e3a\u7b2c\u4e00\u5929 %w \u5f53\u5929\u5728\u5f53\u5468\u7684\u5929\u6570\uff0c\u8303\u56f4\u4e3a[0, 6]\uff0c6\u8868\u793a\u661f\u671f\u5929 %x \u65e5\u671f\u7684\u5b57\u7b26\u4e32\u8868\u793a \uff1a03/08/15 %X \u65f6\u95f4\u7684\u5b57\u7b26\u4e32\u8868\u793a \uff1a23:22:08 %y \u4e24\u4e2a\u6570\u5b57\u8868\u793a\u7684\u5e74\u4efd 15 %Y \u56db\u4e2a\u6570\u5b57\u8868\u793a\u7684\u5e74\u4efd 2015 %z \u4e0eutc\u65f6\u95f4\u7684\u95f4\u9694 \uff08\u5982\u679c\u662f\u672c\u5730\u65f6\u95f4\uff0c\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\uff09 %Z \u65f6\u533a\u540d\u79f0\uff08\u5982\u679c\u662f\u672c\u5730\u65f6\u95f4\uff0c\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\uff09 datestrs = ['2020/5/6', '2021/10/1'] # \u6ce8\u610f\u533a\u5206datetime\u6a21\u5757\u548cdatetime\u7c7b\uff0c\u540d\u5b57\u76f8\u540c\uff0c\u5bb9\u6613\u5f15\u8d77\u9519\u8bef\u3002 # \u6bd4\u5982datetime.datetime\u5c31\u62a5\u9519type object 'datetime.datetime' has no attribute 'datetime' print(datetime) # print(dt) # Python\u6807\u51c6\u5e93\u5305\u542b\u4e86\u65e5\u671f\u548c\u65f6\u95f4\u6570\u636e\u7684\u7c7b\u578b\u3002 datetime \u3001 time \u548c calendar \u6a21\u5757\u662f\u5f00\u59cb\u5904\u7406\u65f6\u95f4\u6570\u636e\u7684\u4e3b\u8981\u5185\u5bb9\u3002 datetime.datetime \u7c7b\u578b\uff0c\u6216\u7b80\u5199\u4e3a datetime \uff0c\u662f\u5e7f\u6cdb\u4f7f\u7528\u7684\u3002 now = datetime.now() print(now) # 2021-10-07 20:24:43.834293 result = dt.datetime(2021, 10, 7, 20, 26, 00, 72973) print(result) # 2021-10-07 20:26:00.072973 datetime \u65e2\u5b58\u50a8\u4e86\u65e5\u671f\uff0c\u4e5f\u5b58\u50a8\u4e86\u7ec6\u5316\u5230\u5fae\u79d2\u7684\u65f6\u95f4\u3002 timedelta \u8868\u793a\u4e24\u4e2a datetime \u5bf9\u8c61\u7684\u65f6\u95f4\u5dee\u3002 delta = datetime(2021, 10, 7) - datetime(2021, 9, 7) print(delta) # 30 days, 0:00:00 print(delta.days) # 30 print(delta.seconds) # 0 result = dt.timedelta(926, 56700) print(result) # 926 days, 15:45:00 \u53ef\u4ee5\u4e3a\u4e00\u4e2a datetime \u5bf9\u8c61\u52a0\u4e0a\uff08\u6216\u51cf\u53bb\uff09\u4e00\u4e2a timedelta \u6216\u5176\u6574\u6570\u500d\u6765\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684 datetime \u5bf9\u8c61\u3002 start = datetime(2021, 10, 7) result = start + timedelta(12) print(result) # 2021-10-19 00:00:00 result = start - 2 * timedelta(5) print(result) # 2021-09-27 00:00:00","title":"datetime"},{"location":"python/DataAnalysis/ch08/#datetime_1","text":"\u4f7f\u7528 str \u65b9\u6cd5\u6216\u4f20\u9012\u4e00\u4e2a\u6307\u5b9a\u7684\u683c\u5f0f\u7ed9 strftime \u65b9\u6cd5\u6765\u5bf9 datetime \u5bf9\u8c61\u548cpandas\u7684 Timestamp \u5bf9\u8c61\u8fdb\u884c\u683c\u5f0f\u5316\u3002 stamp = datetime(2021, 10, 7) result = str(stamp) print(result) # 2021-10-07 00:00:00 \u4f7f\u7528 datetime.srtptime \u548c datetime \u683c\u5f0f\u7b26\uff0c\u628a\u5b57\u7b26\u4e32\u8f6c\u6362\u65e5\u671f\u3002 datetime.strptime \u662f\u5728\u5df2\u77e5\u683c\u5f0f\u7684\u60c5\u51b5\u4e0b\u8f6c\u6362\u65e5\u671f\u7684\u597d\u65b9\u5f0f\u3002 value = '2021-10-7' result = datetime.strptime(value, '%Y-%m-%d') print(result) # 2021-10-07 00:00:00 datestrs = ['2020/5/6', '2021/10/1'] result = [datetime.strptime(x, '%Y/%m/%d') for x in datestrs] print(result) # [datetime.datetime(2020, 5, 6, 0, 0), datetime.datetime(2021, 10, 1, 0, 0)] dateutil \u89e3\u6790\u901a\u7528\u65e5\u671f\u683c\u5f0f\uff1a print(parse('2020/5/6')) # 2020-05-06 00:00:00 print(parse('Jan 31, 2021 10:25 AM')) # 2021-01-31 10:25:00 print(parse('5/6/2021', dayfirst=True)) # \u65e5\u671f\u51fa\u73b0\u5728\u6708\u4efd\u4e4b\u524d # 2021-06-05 00:00:00 pandas\u4e3b\u8981\u662f\u9762\u5411\u5904\u7406\u65e5\u671f\u6570\u7ec4\u7684\uff0c\u65e0\u8bba\u662f\u7528\u4f5c\u8f74\u7d22\u5f15\u8fd8\u662f\u7528\u4f5cDataFrame\u4e2d\u7684\u5217\u3002 to_datetime \u65b9\u6cd5\u53ef\u4ee5\u8f6c\u6362\u5f88\u591a\u4e0d\u540c\u7684\u65e5\u671f\u8868\u793a\u683c\u5f0f\u3002 to_datetime \u65b9\u6cd5\u8fd8\u53ef\u4ee5\u5904\u7406\u90a3\u4e9b\u88ab\u8ba4\u4e3a\u662f\u7f3a\u5931\u503c\u7684\u503c\uff08None\u3001\u7a7a\u5b57\u7b26\u4e32\u7b49\uff09\u3002 NaT \uff08Not a time\uff09\u662fpandas\u4e2d\u65f6\u95f4\u6233\u6570\u636e\u7684\u662fnull\u503c\u3002 datestrs = ['2020/5/6 12:00:00', '2021/10/1 09:00:00'] result = pd.to_datetime(datestrs) print(result) # DatetimeIndex(['2020-05-06 12:00:00', '2021-10-01 09:00:00'], dtype='datetime64[ns]', freq=None) idx = pd.to_datetime(datestrs + [None]) print(idx) # DatetimeIndex(['2020-05-06 12:00:00', '2021-10-01 09:00:00', 'NaT'], dtype='datetime64[ns]', freq=None) print(idx[2]) # NaT print(pd.isnull(idx)) # [False False True]","title":"\u5b57\u7b26\u4e32\u4e0edatetime\u4e92\u76f8\u8f6c\u6362"},{"location":"python/DataAnalysis/ch08/#_3","text":"from datetime import datetime import pandas as pd import numpy as np","title":"\u65f6\u95f4\u5e8f\u5217\u57fa\u7840"},{"location":"python/DataAnalysis/ch08/#datetimeindex","text":"pandas\u4e2d\u7684\u57fa\u7840\u65f6\u95f4\u5e8f\u5217\u79cd\u7c7b\u662f\u7531\u65f6\u95f4\u6233\u7d22\u5f15\u7684Series\uff0c\u5728pandas\u5916\u90e8\u5219\u901a\u5e38\u8868\u793a\u4e3aPython\u5b57\u7b26\u4e32\u6216 datetime \u5bf9\u8c61\u3002 \u6240\u6709\u4f7f\u7528 datetime \u5bf9\u8c61\u7684\u5730\u65b9\u90fd\u53ef\u4ee5\u7528 Timestamp \u3002 dates = [ datetime(2021, 10, 1), datetime(2021, 10, 3), datetime(2021, 10, 5), datetime(2021, 10, 7), datetime(2021, 10, 9), datetime(2021, 10, 11) ] data = np.random.rand(6) ts = pd.Series(data, index=dates) print(ts) # 2021-10-01 0.678297 # 2021-10-03 0.538631 # 2021-10-05 0.934413 # 2021-10-07 0.018534 # 2021-10-09 0.938441 # 2021-10-11 0.173329 # dtype: float64 \u8fd9\u4e9b datetime \u5bf9\u8c61\u88ab\u653e\u5165 DatetimeIndex \u4e2d\u3002 print(ts.index) # DatetimeIndex(['2021-10-01', '2021-10-03', '2021-10-05', '2021-10-07', # '2021-10-09', '2021-10-11'], # dtype='datetime64[ns]', freq=None) DatetimeIndex \u4e2d\u7684\u6807\u91cf\u503c\u662f pandas \u7684 Timestamp \u5bf9\u8c61\uff1a stamp = ts.index[0] print(stamp) # 2021-10-01 00:00:00 \u548c\u5176\u4ed6Series\u7c7b\u4f3c\uff0c\u4e0d\u540c\u7d22\u5f15\u7684\u65f6\u95f4\u5e8f\u5217\u4e4b\u95f4\u7684\u7b97\u672f\u8fd0\u7b97\u5728\u65e5\u671f\u4e0a\u81ea\u52a8\u5bf9\u9f50\uff1a print(ts + ts[::2]) # ts[::2]\u4f1a\u5c06ts\u4e2d\u6bcf\u9694\u4e00\u4e2a\u7684\u5143\u7d20\u9009\u62e9\u51fa # 2021-10-01 1.356595 # 2021-10-03 NaN # 2021-10-05 1.868825 # 2021-10-07 NaN # 2021-10-09 1.876883 # 2021-10-11 NaN # dtype: float64 pandas\u4f7f\u7528NumPy\u7684 datetime64 \u6570\u636e\u7c7b\u578b\u5728\u7eb3\u79d2\u7ea7\u7684\u5206\u8fa8\u7387\u4e0b\u5b58\u50a8\u65f6\u95f4\u6233 print(ts.index.dtype) # datetime64[ns]","title":"DatetimeIndex"},{"location":"python/DataAnalysis/ch08/#_4","text":"\u5f53\u57fa\u4e8e\u6807\u7b7e\u8fdb\u884c\u7d22\u5f15\u548c\u9009\u62e9\u65f6\uff0c\u65f6\u95f4\u5e8f\u5217\u7684\u884c\u4e3a\u548c\u5176\u4ed6\u7684pandas.Series\u7c7b\u4f3c\uff1a stamp = ts.index[2] print(ts[stamp]) # 0.9344125159374457 \u5bf9\u5e942021-10-05 \u4e5f\u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u80fd\u89e3\u91ca\u4e3a\u65e5\u671f\u7684\u5b57\u7b26\u4e32\uff1a print(ts['10/9/2021']) print(ts['20211003']) \u5bf9\u4e00\u4e2a\u957f\u7684\u65f6\u95f4\u5e8f\u5217\uff0c\u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u5e74\u4efd\u6216\u4e00\u4e2a\u5e74\u4efd\u548c\u6708\u4efd\u6765\u9009\u62e9\u6570\u636e\u5207\u7247\uff1a data = np.random.randn(1000) longer_ts = pd.Series( data, index=pd.date_range('1/1/2021', periods=1000) ) print(longer_ts) # 2021-01-01 -0.009192 # 2021-01-02 -1.079068 # 2021-01-03 -1.851176 # 2021-01-04 1.347109 # 2021-01-05 -0.236394 # ... # 2023-09-23 -1.317943 # 2023-09-24 0.201741 # 2023-09-25 0.442282 # 2023-09-26 0.176137 # 2023-09-27 1.146437 # Freq: D, Length: 1000, dtype: float64 \u5b57\u7b26\u4e32\u20192001\u2019\u88ab\u89e3\u91ca\u4e3a\u4e00\u4e2a\u5e74\u4efd\uff0c\u5e76\u9009\u62e9\u4e86\u76f8\u5e94\u7684\u65f6\u95f4\u533a\u95f4\u3002 print(longer_ts['2021']) # 2021-01-01 2.170411 # 2021-01-02 1.186933 # 2021-01-03 0.399262 # 2021-01-04 -1.042606 # 2021-01-05 2.082112 # ... # 2021-12-27 -0.988282 # 2021-12-28 0.598683 # 2021-12-29 2.770580 # 2021-12-30 -1.463262 # 2021-12-31 -1.642846 # Freq: D, Length: 365, dtype: float64 \u6307\u5b9a\u4e86\u5e74\u4efd\u548c\u6708\u4efd\u4e5f\u662f\u6709\u6548\u7684\u3002 print(longer_ts['2021-10']) # 2021-10-01 0.712265 # 2021-10-02 1.195221 # 2021-10-03 -1.930220 # 2021-10-04 -0.720816 # 2021-10-05 0.081777 # 2021-10-06 -0.037466 # 2021-10-07 3.737303 # 2021-10-08 1.620383 # 2021-10-09 0.990797 # 2021-10-10 0.507850 # 2021-10-11 0.846935 # 2021-10-12 0.996947 # 2021-10-13 -1.078558 # 2021-10-14 0.871832 # 2021-10-15 -0.591698 # 2021-10-16 -0.805463 # 2021-10-17 0.160528 # 2021-10-18 -0.028474 # 2021-10-19 2.305579 # 2021-10-20 -1.132288 # 2021-10-21 0.649980 # 2021-10-22 0.615327 # 2021-10-23 0.185108 # 2021-10-24 0.857199 # 2021-10-25 -1.473752 # 2021-10-26 -0.895161 # 2021-10-27 -0.432717 # 2021-10-28 0.734504 # 2021-10-29 1.892493 # 2021-10-30 0.456619 # 2021-10-31 -0.255288 # Freq: D, dtype: float64 \u4f7f\u7528 datetime \u5bf9\u8c61\u8fdb\u884c\u5207\u7247\u4e5f\u662f\u53ef\u4ee5\u7684\uff1a print(longer_ts[datetime(2023, 1, 6):]) # 2023-01-06 0.952591 # 2023-01-07 -0.900259 # 2023-01-08 0.925332 # 2023-01-09 0.173215 # 2023-01-10 -0.507791 # ... # 2023-09-23 -0.319989 # 2023-09-24 -1.105417 # 2023-09-25 -2.118769 # 2023-09-26 0.009420 # 2023-09-27 -0.310281 # Freq: D, Length: 265, dtype: float64 \u56e0\u4e3a\u5927\u90e8\u5206\u7684\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u662f\u6309\u65f6\u95f4\u987a\u5e8f\u6392\u5e8f\u7684\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e0d\u5305\u542b\u5728\u65f6\u95f4\u5e8f\u5217\u4e2d\u7684\u65f6\u95f4\u6233\u8fdb\u884c\u5207\u7247\uff0c\u4ee5\u6267\u884c\u8303\u56f4\u67e5\u8be2\uff1a print(longer_ts['2021/10/1':'2021/10/5']) # 2021-10-01 -0.591853 # 2021-10-02 -1.554564 # 2021-10-03 -0.712585 # 2021-10-04 -0.326657 # 2021-10-05 1.044887 # Freq: D, dtype: float64 \u4f7f\u7528 truncate \u5728\u4e24\u4e2a\u65e5\u671f\u95f4\u5bf9Series\u8fdb\u884c\u5207\u7247\uff1a print(longer_ts.truncate(after='2021/10/1')) # 2021-01-01 -0.906685 # 2021-01-02 -0.470732 # 2021-01-03 -0.041316 # 2021-01-04 -0.287356 # 2021-01-05 0.104268 # ... # 2021-09-27 -0.669198 # 2021-09-28 -2.222169 # 2021-09-29 -0.653814 # 2021-09-30 -0.625868 # 2021-10-01 0.872684 # Freq: D, Length: 274, dtype: float64 \u4e0a\u9762\u8fd9\u4e9b\u64cd\u4f5c\u4e5f\u90fd\u9002\u7528\u4e8eDataFrame\uff0c\u5e76\u5728\u5176\u884c\u4e0a\u8fdb\u884c\u7d22\u5f15\uff1a dates = pd.date_range('10/1/2020', periods=100, freq='W-WED') data = np.random.randn(100, 4) long_df = pd.DataFrame( data, index=dates, columns=['Colorado', 'Texas', 'New York', 'Ohio'] ) print(long_df) # Colorado Texas New York Ohio # 2020-10-07 -1.186789 2.020634 0.300076 -0.955234 # 2020-10-14 1.502838 0.965368 -0.797539 -0.292833 # ... ... ... ... ... # 2022-08-24 -0.253116 -0.263307 0.602425 0.370599 # 2022-08-31 0.907918 0.091939 0.789694 2.781535 # [100 rows x 4 columns] print(long_df.loc['10-2020']) # Colorado Texas New York Ohio # 2020-10-07 1.031616 -1.812038 -0.446577 0.395656 # 2020-10-14 -0.673167 0.198804 -0.439141 0.086004 # 2020-10-21 -1.139786 0.716820 0.006516 -0.284335 # 2020-10-28 -0.637939 1.647810 -0.750786 0.140637","title":"\u7d22\u5f15\u3001\u9009\u62e9\u3001\u5b50\u96c6"},{"location":"python/DataAnalysis/ch08/#_5","text":"\u5728\u67d0\u4e9b\u5e94\u7528\u4e2d\uff0c\u53ef\u80fd\u4f1a\u6709\u591a\u4e2a\u6570\u636e\u89c2\u5bdf\u503c\u843d\u5728\u7279\u5b9a\u7684\u65f6\u95f4\u6233\u4e0a\u3002\u4e0b\u9762\u662f\u4e2a\u4f8b\u5b50\uff1a dates = pd.DatetimeIndex( ['2021/1/1', '2021/1/2', '2021/1/2', '2021/1/2', '2021/1/3'] ) dup_ts = pd.Series( np.arange(5), index=dates ) print(dup_ts) # 2021-01-01 0 # 2021-01-02 1 # 2021-01-02 2 # 2021-01-02 3 # 2021-01-03 4 # dtype: int64 \u901a\u8fc7\u68c0\u67e5\u7d22\u5f15\u7684 is_unique \u5c5e\u6027\uff0c\u53ef\u4ee5\u770b\u51fa\u7d22\u5f15\u5e76\u4e0d\u662f\u552f\u4e00\u7684\uff1a print(dup_ts.index.is_unique) # False \u5bf9\u4e0a\u9762\u7684Series\u8fdb\u884c\u7d22\u5f15\uff0c\u7ed3\u679c\u662f\u6807\u91cf\u503c\u8fd8\u662fSeries\u5207\u7247\u53d6\u51b3\u4e8e\u662f\u5426\u6709\u65f6\u95f4\u6233\u662f\u91cd\u590d\u7684\uff1a result = dup_ts['2021/1/3'] print(result) # 4 result = dup_ts['2021/1/2'] print(result) # 2021-01-02 1 # 2021-01-02 2 # 2021-01-02 3 # dtype: int64 \u5047\u8bbe\u60f3\u8981\u805a\u5408\u542b\u6709\u975e\u552f\u4e00\u65f6\u95f4\u6233\u7684\u6570\u636e\u3002\u4e00\u79cd\u65b9\u5f0f\u5c31\u662f\u4f7f\u7528 groupby \u5e76\u4f20\u9012 level=0 \uff1a grouped = dup_ts.groupby(level=0) result = grouped.mean() print(result) # 2021-01-01 0.0 # 2021-01-02 2.0 # 2021-01-03 4.0 # dtype: float64 result = grouped.count() print(result) # 2021-01-01 1 # 2021-01-02 3 # 2021-01-03 1 # dtype: int64","title":"\u542b\u6709\u91cd\u590d\u7d22\u5f15\u7684\u65f6\u95f4\u5e8f\u5217"},{"location":"python/DataAnalysis/ch08/#_6","text":"from datetime import datetime, timedelta import pandas as pd import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd pandas\u7684\u901a\u7528\u65f6\u95f4\u5e8f\u5217\u662f\u4e0d\u89c4\u5219\u7684\uff0c\u5373\u65f6\u95f4\u5e8f\u5217\u7684\u9891\u7387\u4e0d\u662f\u56fa\u5b9a\u7684\u3002 \u4f46\u6709\u65f6\u9700\u8981\u5904\u7406\u56fa\u5b9a\u9891\u7387\u7684\u573a\u666f\uff0c\u4f8b\u5982\u6bcf\u65e5\u7684\u3001\u6bcf\u6708\u7684\u6216\u6bcf15\u5206\u949f\u7684\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u3002 \u53ef\u4ee5\u901a\u8fc7\u8c03\u7528resample\u65b9\u6cd5\u5c06\u6837\u672c\u65f6\u95f4\u5e8f\u5217\u8f6c\u6362\u4e3a\u56fa\u5b9a\u7684\u6bcf\u65e5\u9891\u7387\u6570\u636e\u3002 \u5728\u9891\u7387\u95f4\u8f6c\u6362\uff0c\u53c8\u79f0\u4e3a\u91cd\u65b0\u91c7\u6837\u3002 dates = [ datetime(2021, 10, 1), datetime(2021, 10, 3), datetime(2021, 10, 5), datetime(2021, 10, 7), datetime(2021, 10, 9), datetime(2021, 10, 11) ] data = np.random.rand(6) ts = pd.Series(data, index=dates) print(ts) # 2021-10-01 0.956685 # 2021-10-03 0.817168 # 2021-10-05 0.275543 # 2021-10-07 0.614226 # 2021-10-09 0.061377 # 2021-10-11 0.357080 # dtype: float64 resampler = ts.resample('D') # \u5b57\u7b26\u4e32\u2019D\u2019\u88ab\u89e3\u91ca\u4e3a\u6bcf\u65e5\u9891\u7387 print(resampler) # DatetimeIndexResampler [freq=, axis=0, closed=left, label=left, convention=start, origin=start_day]","title":"\u65e5\u671f\u8303\u56f4\u3001\u9891\u7387\u548c\u79fb\u4f4d"},{"location":"python/DataAnalysis/ch08/#_7","text":"pandas.date_range \u662f\u7528\u4e8e\u6839\u636e\u7279\u5b9a\u9891\u7387\u751f\u6210\u6307\u5b9a\u957f\u5ea6\u7684 DatetimeIndex \u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c date_range \u751f\u6210\u7684\u662f\u6bcf\u65e5\u7684\u65f6\u95f4\u6233\u3002\u5982\u679c\u53ea\u4f20\u9012\u4e00\u4e2a\u8d77\u59cb\u6216\u7ed3\u5c3e\u65e5\u671f\uff0c\u4f60\u5fc5\u987b\u4f20\u9012\u4e00\u4e2a\u7528\u4e8e\u751f\u6210\u8303\u56f4\u7684\u6570\u5b57\u3002 \u5f00\u59cb\u65e5\u671f\u548c\u7ed3\u675f\u65e5\u671f\u4e25\u683c\u5b9a\u4e49\u4e86\u751f\u6210\u65e5\u671f\u7d22\u5f15\u7684\u8fb9\u754c\u3002 index = pd.date_range('2021/1/1', '2021/1/30') print(index) index = pd.date_range(start='2021/1/1', periods=30) print(index) index = pd.date_range(end='2021/1/30', periods=30) print(index) # DatetimeIndex(['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', # '2021-01-05', '2021-01-06', '2021-01-07', '2021-01-08', # '2021-01-09', '2021-01-10', '2021-01-11', '2021-01-12', # '2021-01-13', '2021-01-14', '2021-01-15', '2021-01-16', # '2021-01-17', '2021-01-18', '2021-01-19', '2021-01-20', # '2021-01-21', '2021-01-22', '2021-01-23', '2021-01-24', # '2021-01-25', '2021-01-26', '2021-01-27', '2021-01-28', # '2021-01-29', '2021-01-30'], # dtype='datetime64[ns]', freq='D') \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c date_range \u4fdd\u7559\u5f00\u59cb\u6216\u7ed3\u675f\u65f6\u95f4\u6233\u7684\u65f6\u95f4\uff08\u5982\u679c\u6709\u7684\u8bdd\uff09\u3002 normalize \u9009\u9879\u53ef\u4ee5\u5b9e\u73b0\u751f\u6210\u7684\u662f\u6807\u51c6\u5316\u4e3a\u96f6\u70b9\u7684\u65f6\u95f4\u6233\u3002 index = pd.date_range('2021/1/1 12:56:30', periods=5) print(index) # DatetimeIndex(['2021-01-01 12:56:30', '2021-01-02 12:56:30', # '2021-01-03 12:56:30', '2021-01-04 12:56:30', # '2021-01-05 12:56:30'], # dtype='datetime64[ns]', freq='D') index = pd.date_range('2021/1/1 12:56:30', periods=5, normalize=True) print(index) # DatetimeIndex(['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', # '2021-01-05'], # dtype='datetime64[ns]', freq='D') Pandas\u65f6\u95f4\u5e8f\u5217\uff1a\u9891\u7387\u548c\u65e5\u671f\u504f\u79fb\u91cf\u3002 pandas\u4e2d\u7684\u9891\u7387\u662f\u7531\u4e00\u4e2a\u57fa\u7840\u9891\u7387(\u4f8b\u5982\u201c\u65e5\u201d\u3001\u201c\u6708\u201d)\u548c\u4e00\u4e2a\u4e58\u6570\u7ec4\u6210\u3002 \u57fa\u7840\u9891\u7387\u901a\u5e38\u4ee5\u4e00\u4e2a\u5b57\u7b26\u4e32\u522b\u540d\u8868\u793a\uff0c\u6bd4\u5982\u201cD\u201d\u8868\u793a\u65e5\uff0c\u201cM\u201d\u8868\u793a\u6708\u3002 \u5bf9\u4e8e\u6bcf\u4e2a\u57fa\u7840\u9891\u7387\uff0c\u90fd\u6709\u4e00\u4e2a\u88ab\u79f0\u4e3a\u65e5\u671f\u504f\u79fb\u91cf(dateoffset)\u7684\u5bf9\u8c61\u4e0e\u4e4b\u5bf9\u5e94\uff0c\u6bd4\u5982\u65e5\u671f\u504f\u79fb\u91cf Hour \u5bf9\u5e94\u7684\u9891\u7387\u662f H \u3002 \u5e38\u7528\u9891\u7387\u4e0e\u65e5\u671f\u504f\u79fb\u91cf\u3002 \u9891\u7387 \u65e5\u671f\u504f\u79fb\u91cf \u8bf4\u660e D Day \u65e5\u5386\u65e5 B BusinessDay \u5de5\u4f5c\u65e5 H Hour \u5c0f\u65f6 T/min Minute \u5206 S Second \u79d2 L/ms Milli \u6beb\u79d2 U Micro \u5fae\u79d2 M MonthEnd \u6bcf\u6708\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5 BM BusinessMonthEnd \u6bcf\u6708\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5 MS MonthBegin \u6bcf\u6708\u7b2c\u4e00\u4e2a\u65e5\u5386\u65e5 BMS BussinessMonthBegin \u6bcf\u6708\u7b2c\u4e00\u4e2a\u5de5\u4f5c\u65e5 W-MON, W-TUE, ... Week \u6307\u5b9a\u661f\u671f\u51e0(MON,TUE,WED,THU,FRI,SAT,SUN) WOM-1MON,WOM-2MON, ... WeekOfMonth \u4ea7\u751f\u6bcf\u6708\u7b2c\u4e00,\u7b2c\u4e8c,\u7b2c\u4e09\u6216\u7b2c\u56db\u5468\u7684\u661f\u671f\u51e0\u3002\u4f8b\u5982WOM-3FRI\u8868\u793a\u6bcf\u6708\u7b2c3\u4e2a\u661f\u671f\u4e94 Q-JAN,Q-FEB, ... QuarterEnd \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5 BQ-JAN,BQ-FEB, ... BusinessQuarterEnd \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5 QS-JAN,QS-FEB, ... QuarterBegin \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u7b2c\u4e00\u4e2a\u65e5\u5386\u65e5 BQS-JAN,BQS-FEB, ... BusinessQuarterBegin \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u7b2c\u4e00\u4e2a\u5de5\u4f5c\u65e5 A-JAN,A-FEB, ... YearEnd \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5 BA-JAN,BA-FEB, ... BusinessYearEnd \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5 AS-JAN,AS-FEB, ... YearBegin \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u7b2c\u4e00\u4e2a\u65e5\u5386\u65e5 BAS-JAN,BAS-FEB, ... BusinessYearBegin \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u7b2c\u4e00\u4e2a\u5de5\u4f5c\u65e5","title":"\u751f\u6210\u65e5\u671f\u8303\u56f4"},{"location":"python/DataAnalysis/ch08/#_8","text":"pandas\u4e2d\u7684\u9891\u7387\u662f\u7531\u57fa\u7840\u9891\u7387\u548c\u500d\u6570\u7ec4\u6210\u7684\u3002 \u57fa\u7840\u9891\u7387\u901a\u5e38\u4f1a\u6709\u5b57\u7b26\u4e32\u522b\u540d\uff0c\u4f8b\u5982 M \u4ee3\u8868\u6bcf\u6708\uff0c H \u4ee3\u8868\u6bcf\u5c0f\u65f6\u3002 \u5bf9\u4e8e\u6bcf\u4e2a\u57fa\u7840\u9891\u7387\uff0c\u90fd\u6709\u4e00\u4e2a\u5bf9\u8c61\u53ef\u4ee5\u88ab\u7528\u4e8e\u5b9a\u4e49\u65e5\u671f\u504f\u7f6e\u3002 \u4f8b\u5982\uff0c\u6bcf\u5c0f\u65f6\u7684\u9891\u7387\u53ef\u4ee5\u4f7f\u7528 Hour \u7c7b\u6765\u8868\u793a\uff1a ```hour = Hour() print(hour)","title":"\u9891\u7387\u548c\u65e5\u671f\u504f\u7f6e"},{"location":"python/DataAnalysis/ch08/#_9","text":"\u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u6574\u6570\u6765\u5b9a\u4e49\u504f\u7f6e\u91cf\u7684\u500d\u6570\uff1a four_hours = Hour(4) print(four_hours)","title":""},{"location":"python/DataAnalysis/ch08/#4-hours","text":"\u5728\u5927\u591a\u6570\u5e94\u7528\u4e2d\uff0c\u4e0d\u9700\u8981\u663e\u5f0f\u5730\u521b\u5efa\u8fd9\u4e9b\u5bf9\u8c61\uff0c\u800c\u662f\u4f7f\u7528\u5b57\u7b26\u4e32\u522b\u540d\uff0c\u5982`H`\u6216`4H`\u3002\u5728\u57fa\u7840\u9891\u7387\u524d\u653e\u4e00\u4e2a\u6574\u6570\u5c31\u53ef\u4ee5\u751f\u6210\u500d\u6570\uff1a ts = pd.date_range('2021/1/1', '2021/\u00bd 23:59', freq='4h') print(ts)","title":"<4 * Hours>"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-01-01-000000-2021-01-01-040000","text":"","title":"DatetimeIndex(['2021-01-01 00:00:00', '2021-01-01 04:00:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-01-080000-2021-01-01-120000","text":"","title":"'2021-01-01 08:00:00', '2021-01-01 12:00:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-01-160000-2021-01-01-200000","text":"","title":"'2021-01-01 16:00:00', '2021-01-01 20:00:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-02-000000-2021-01-02-040000","text":"","title":"'2021-01-02 00:00:00', '2021-01-02 04:00:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-02-080000-2021-01-02-120000","text":"","title":"'2021-01-02 08:00:00', '2021-01-02 12:00:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-02-160000-2021-01-02-200000","text":"","title":"'2021-01-02 16:00:00', '2021-01-02 20:00:00'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-freq4h","text":"\u591a\u4e2a\u504f\u7f6e\u53ef\u4ee5\u901a\u8fc7\u52a0\u6cd5\u8fdb\u884c\u8054\u5408\uff1a print(Hour(2) + Minute(30))","title":"dtype='datetime64[ns]', freq='4H')"},{"location":"python/DataAnalysis/ch08/#150-minutes","text":"\u7c7b\u4f3c\u5730\uff0c\u53ef\u4ee5\u4f20\u9012\u9891\u7387\u5b57\u7b26\u4e32\uff1a ts = pd.date_range('2021/1/1', '2021/1/1 23:59', freq='4h30min') print(ts)","title":"<150 * Minutes>"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-01-01-000000-2021-01-01-043000","text":"","title":"DatetimeIndex(['2021-01-01 00:00:00', '2021-01-01 04:30:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-01-090000-2021-01-01-133000","text":"","title":"'2021-01-01 09:00:00', '2021-01-01 13:30:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-01-180000-2021-01-01-223000","text":"","title":"'2021-01-01 18:00:00', '2021-01-01 22:30:00'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-freq270t","text":"\u6709\u4e9b\u9891\u7387\u63cf\u8ff0\u70b9\u7684\u65f6\u95f4\u5e76\u4e0d\u662f\u5747\u5300\u5206\u9694\u7684\u3002\u4f8b\u5982\uff0c`M`\uff08\u65e5\u5386\u6708\u672b\uff09\u548c`BM`\uff08\u6708\u5185\u6700\u540e\u5de5\u4f5c\u65e5\uff09\u53d6\u51b3\u4e8e\u5f53\u6708\u5929\u6570\uff0c\u6708\u672b\u662f\u5426\u662f\u5468\u672b\u3002\u6211\u4eec\u5c06\u8fd9\u4e9b\u65e5\u671f\u79f0\u4e3a\u951a\u5b9a\u504f\u7f6e\u91cf\u3002 #### \u6708\u4e2d\u67d0\u661f\u671f\u7684\u65e5\u671f \"\u6708\u4e2d\u67d0\u661f\u671f\"\uff08week of month \uff09\u7684\u65e5\u671f\u662f\u4e00\u4e2a\u6709\u7528\u7684\u9891\u7387\u7c7b\uff0c\u4ee5`WOM`\u5f00\u59cb\u3002 rng = pd.date_range('2021-1-1', '2021-9-1', freq='WOM-3FRI') # \u6bcf\u6708\u7b2c\u4e09\u4e2a\u661f\u671f\u4e94 print(rng)","title":"dtype='datetime64[ns]', freq='270T')"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-01-15-2021-02-19-2021-03-19-2021-04-16","text":"","title":"DatetimeIndex(['2021-01-15', '2021-02-19', '2021-03-19', '2021-04-16',"},{"location":"python/DataAnalysis/ch08/#2021-05-21-2021-06-18-2021-07-16-2021-08-20","text":"","title":"'2021-05-21', '2021-06-18', '2021-07-16', '2021-08-20'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-freqwom-3fri","text":"### \u79fb\u4f4d\uff08\u524d\u5411\u548c\u540e\u5411\uff09\u65e5\u671f \"\u79fb\u4f4d\"\u662f\u6307\u5c06\u65e5\u671f\u6309\u65f6\u95f4\u5411\u524d\u79fb\u52a8\u6216\u5411\u540e\u79fb\u52a8\u3002 Series\u548cDataFrame\u90fd\u6709\u4e00\u4e2a`shift`\u65b9\u6cd5\u7528\u4e8e\u8fdb\u884c\u7b80\u5355\u7684\u524d\u5411\u6216\u540e\u5411\u79fb\u4f4d\uff0c\u800c\u4e0d\u6539\u53d8\u7d22\u5f15\u3002 \u8fdb\u884c\u79fb\u4f4d\u65f6\uff0c\u4f1a\u5728\u65f6\u95f4\u5e8f\u5217\u7684\u8d77\u59cb\u4f4d\u6216\u7ed3\u675f\u4f4d\u5f15\u5165\u7f3a\u5931\u503c\u3002 data = [0.882972, 1.363282, -0.687750, -0.048117] ts = pd.Series(data, index=pd.date_range('2021-1-1', periods=4, freq='M')) print(ts)","title":"dtype='datetime64[ns]', freq='WOM-3FRI')"},{"location":"python/DataAnalysis/ch08/#2021-01-31-0882972","text":"","title":"2021-01-31 0.882972"},{"location":"python/DataAnalysis/ch08/#2021-02-28-1363282","text":"","title":"2021-02-28 1.363282"},{"location":"python/DataAnalysis/ch08/#2021-03-31-0687750","text":"","title":"2021-03-31 -0.687750"},{"location":"python/DataAnalysis/ch08/#2021-04-30-0048117","text":"","title":"2021-04-30 -0.048117"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64","text":"print(ts.shift(2))","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-31-nan","text":"","title":"2021-01-31 NaN"},{"location":"python/DataAnalysis/ch08/#2021-02-28-nan","text":"","title":"2021-02-28 NaN"},{"location":"python/DataAnalysis/ch08/#2021-03-31-0882972","text":"","title":"2021-03-31 0.882972"},{"location":"python/DataAnalysis/ch08/#2021-04-30-1363282","text":"","title":"2021-04-30 1.363282"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_1","text":"print(ts.shift(-2))","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-31-0687750","text":"","title":"2021-01-31 -0.687750"},{"location":"python/DataAnalysis/ch08/#2021-02-28-0048117","text":"","title":"2021-02-28 -0.048117"},{"location":"python/DataAnalysis/ch08/#2021-03-31-nan","text":"","title":"2021-03-31 NaN"},{"location":"python/DataAnalysis/ch08/#2021-04-30-nan","text":"","title":"2021-04-30 NaN"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_2","text":"`shift`\u5e38\u7528\u4e8e\u8ba1\u7b97\u65f6\u95f4\u5e8f\u5217\u6216DataFrame\u591a\u5217\u65f6\u95f4\u5e8f\u5217\u7684\u767e\u5206\u6bd4\u53d8\u5316\uff1a print(ts/ts.shift(1))","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-31-nan_1","text":"","title":"2021-01-31 NaN"},{"location":"python/DataAnalysis/ch08/#2021-02-28-1543970","text":"","title":"2021-02-28 1.543970"},{"location":"python/DataAnalysis/ch08/#2021-03-31-0504481","text":"","title":"2021-03-31 -0.504481"},{"location":"python/DataAnalysis/ch08/#2021-04-30-0069963","text":"","title":"2021-04-30 0.069963"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_3","text":"print(ts/ts.shift(1) - 1)","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-31-nan_2","text":"","title":"2021-01-31 NaN"},{"location":"python/DataAnalysis/ch08/#2021-02-28-0543970","text":"","title":"2021-02-28 0.543970"},{"location":"python/DataAnalysis/ch08/#2021-03-31-1504481","text":"","title":"2021-03-31 -1.504481"},{"location":"python/DataAnalysis/ch08/#2021-04-30-0930037","text":"","title":"2021-04-30 -0.930037"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_4","text":"\u5982\u679c\u9891\u7387\u662f\u5df2\u77e5\u7684\uff0c\u5219\u53ef\u4ee5\u5c06\u9891\u7387\u4f20\u9012\u7ed9`shift`\u6765\u63a8\u79fb\u65f6\u95f4\u6233\uff1a print(ts.shift(2, freq='M')) # \u539f\u59cb\u6570\u636e\u7684\u201c\u6708\u201c\u589e\u52a0\u4e86\u504f\u79fb\u503c","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-03-31-0882972_1","text":"","title":"2021-03-31 0.882972"},{"location":"python/DataAnalysis/ch08/#2022021-10-31-0000001-04-30-1363282","text":"","title":"2022021-10-31 00:00:001-04-30 1.363282"},{"location":"python/DataAnalysis/ch08/#2021-05-31-0687750","text":"","title":"2021-05-31 -0.687750"},{"location":"python/DataAnalysis/ch08/#2021-06-30-0048117","text":"","title":"2021-06-30 -0.048117"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_5","text":"print(ts.shift(2, freq='D')) # \u539f\u59cb\u6570\u636e\u7684\u201c\u65e5\u201c\u589e\u52a0\u4e86\u504f\u79fb\u503c","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-02-02-0882972","text":"","title":"2021-02-02 0.882972"},{"location":"python/DataAnalysis/ch08/#2021-03-02-1363282","text":"","title":"2021-03-02 1.363282"},{"location":"python/DataAnalysis/ch08/#2021-04-02-0687750","text":"","title":"2021-04-02 -0.687750"},{"location":"python/DataAnalysis/ch08/#2021-05-02-0048117","text":"","title":"2021-05-02 -0.048117"},{"location":"python/DataAnalysis/ch08/#dtype-float64","text":"print(ts.shift(2, freq='90T')) # \u539f\u59cb\u6570\u636e\u7684\u201c\u5c0f\u65f6\u201c\u589e\u52a0\u4e86\u504f\u79fb\u503c","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-31-030000-0882972","text":"","title":"2021-01-31 03:00:00 0.882972"},{"location":"python/DataAnalysis/ch08/#2021-02-28-030000-1363282","text":"","title":"2021-02-28 03:00:00 1.363282"},{"location":"python/DataAnalysis/ch08/#2021-03-31-030000-0687750","text":"","title":"2021-03-31 03:00:00 -0.687750"},{"location":"python/DataAnalysis/ch08/#2021-04-30-030000-0048117","text":"","title":"2021-04-30 03:00:00 -0.048117"},{"location":"python/DataAnalysis/ch08/#dtype-float64_1","text":"#### \u4f7f\u7528\u504f\u7f6e\u8fdb\u884c\u79fb\u4f4d\u65e5\u671f pandas\u65e5\u671f\u504f\u7f6e\u4e5f\u53ef\u4ee5\u4f7f\u7528`datetime`\u6216`Timestamp`\u5bf9\u8c61\u5b8c\u6210\uff1a now = datetime(2021, 10, 9) print(now)","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-10-09-000000","text":"print(now + 3 * Day())","title":"2021-10-09 00:00:00"},{"location":"python/DataAnalysis/ch08/#2021-10-12-000000","text":"\u951a\u5b9a\u504f\u7f6e\u53ef\u4ee5\u4f7f\u7528`rollforward`\u548c`rollback`\u5206\u522b\u663e\u5f0f\u5730\u5c06\u65e5\u671f\u5411\u524d\u6216\u5411\u540e\"\u6eda\u52a8\"\u3002 \u5982\u679c\u6dfb\u52a0\u4e86\u4e00\u4e2a\u951a\u5b9a\u504f\u7f6e\u91cf\uff0c\u6bd4\u5982`MonthEnd`\uff0c\u6839\u636e\u9891\u7387\u89c4\u5219\uff0c\u7b2c\u4e00\u4e2a\u589e\u91cf\u4f1a\u5c06\u65e5\u671f\u201c\u524d\u6eda\u201d\u5230\u4e0b\u4e00\u4e2a\u65e5\u671f\uff1a print(now + MonthEnd()) # \u201c\u524d\u6eda\u201d\u5230\u5f53\u524d\u6708\u7684\u6708\u5e95","title":"2021-10-12 00:00:00"},{"location":"python/DataAnalysis/ch08/#2021-10-31-000000","text":"print(now + MonthEnd(2)) # \u6ce8\u610f\u8fd9\u91cc\u7684\u5e8f\u5217\u53f7\uff0c\u5f53\u524d\u6708\u662f1,\u4e0b\u4e2a\u6708\u662f2","title":"2021-10-31 00:00:00"},{"location":"python/DataAnalysis/ch08/#2021-11-30-000000","text":"offset = MonthEnd() print(offset.rollback(now))","title":"2021-11-30 00:00:00"},{"location":"python/DataAnalysis/ch08/#2021-09-30-000000","text":"print(offset.rollforward(now))","title":"2021-09-30 00:00:00"},{"location":"python/DataAnalysis/ch08/#2021-10-31-000000_1","text":"\u5c06\u79fb\u4f4d\u65b9\u6cd5\u4e0e`groupby`\u4e00\u8d77\u4f7f\u7528\u662f\u65e5\u671f\u504f\u7f6e\u7684\u4e00\u79cd\u521b\u9020\u6027\u7528\u6cd5\uff1a ts = pd.Series( np.random.randn(20), index=pd.date_range('2021/1/1', periods=20, freq='4d') ) print(ts)","title":"2021-10-31 00:00:00"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0674348","text":"","title":"2021-01-01 0.674348"},{"location":"python/DataAnalysis/ch08/#2021-01-05-1437803","text":"","title":"2021-01-05 -1.437803"},{"location":"python/DataAnalysis/ch08/#2021-01-09-0079218","text":"","title":"2021-01-09 -0.079218"},{"location":"python/DataAnalysis/ch08/#2021-01-13-1444890","text":"","title":"2021-01-13 -1.444890"},{"location":"python/DataAnalysis/ch08/#2021-01-17-0643279","text":"","title":"2021-01-17 0.643279"},{"location":"python/DataAnalysis/ch08/#2021-01-21-1089965","text":"","title":"2021-01-21 1.089965"},{"location":"python/DataAnalysis/ch08/#2021-01-25-0021876","text":"","title":"2021-01-25 0.021876"},{"location":"python/DataAnalysis/ch08/#2021-01-29-0692138","text":"","title":"2021-01-29 0.692138"},{"location":"python/DataAnalysis/ch08/#2021-02-02-0833496","text":"","title":"2021-02-02 0.833496"},{"location":"python/DataAnalysis/ch08/#2021-02-06-1082616","text":"","title":"2021-02-06 1.082616"},{"location":"python/DataAnalysis/ch08/#2021-02-10-0729415","text":"","title":"2021-02-10 -0.729415"},{"location":"python/DataAnalysis/ch08/#2021-02-14-0271186","text":"","title":"2021-02-14 0.271186"},{"location":"python/DataAnalysis/ch08/#2021-02-18-1416218","text":"","title":"2021-02-18 -1.416218"},{"location":"python/DataAnalysis/ch08/#2021-02-22-0780402","text":"","title":"2021-02-22 -0.780402"},{"location":"python/DataAnalysis/ch08/#2021-02-26-0113773","text":"","title":"2021-02-26 -0.113773"},{"location":"python/DataAnalysis/ch08/#2021-03-02-2095338","text":"","title":"2021-03-02 2.095338"},{"location":"python/DataAnalysis/ch08/#2021-03-06-0302612","text":"","title":"2021-03-06 -0.302612"},{"location":"python/DataAnalysis/ch08/#2021-03-10-1113632","text":"","title":"2021-03-10 1.113632"},{"location":"python/DataAnalysis/ch08/#2021-03-14-1314581","text":"","title":"2021-03-14 -1.314581"},{"location":"python/DataAnalysis/ch08/#2021-03-18-0947746","text":"","title":"2021-03-18 0.947746"},{"location":"python/DataAnalysis/ch08/#freq-4d-dtype-float64","text":"print(ts.groupby(offset.rollforward).mean()) # \u524d\u6eda\u81f3\u5f53\u6708\u6708\u5e95\uff0c\u8ba1\u7b97\u5f53\u6708\u5e73\u5747\u503c","title":"Freq: 4D, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-31-0019962","text":"","title":"2021-01-31 0.019962"},{"location":"python/DataAnalysis/ch08/#2021-02-28-0121787","text":"","title":"2021-02-28 -0.121787"},{"location":"python/DataAnalysis/ch08/#2021-03-31-0507905","text":"","title":"2021-03-31 0.507905"},{"location":"python/DataAnalysis/ch08/#dtype-float64_2","text":"","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#resample","text":"print(ts.resample('M').mean())","title":"\u4f7f\u7528resample\u662f\u66f4\u7b80\u5355\u66f4\u5feb\u6377\u7684\u65b9\u6cd5"},{"location":"python/DataAnalysis/ch08/#2021-01-31-0019962_1","text":"","title":"2021-01-31 0.019962"},{"location":"python/DataAnalysis/ch08/#2021-02-28-0121787_1","text":"","title":"2021-02-28 -0.121787"},{"location":"python/DataAnalysis/ch08/#2021-03-31-0507905_1","text":"","title":"2021-03-31 0.507905"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_6","text":"## \u65f6\u533a\u5904\u7406 \u65f6\u533a\u901a\u5e38\u88ab\u8868\u793a\u4e3aUTC\u7684\u504f\u7f6e\u3002 \u5728Python\u8bed\u8a00\u4e2d\uff0c\u65f6\u533a\u4fe1\u606f\u6765\u6e90\u4e8e\u7b2c\u4e09\u65b9\u5e93pytz\uff08\u53ef\u4ee5\u4f7f\u7528pip\u6216conda\u5b89\u88c5\uff09\uff0c\u5176\u4e2d\u516c\u5f00\u4e86Olson\u6570\u636e\u5e93\uff0c\u8fd9\u662f\u4e16\u754c\u65f6\u533a\u4fe1\u606f\u7684\u6c47\u7f16\u3002 pandas\u5c01\u88c5\u4e86pytz\u7684\u529f\u80fd\u3002 from datetime import datetime, timedelta import pandas as pd import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd import pytz #### common_timezones tz = pytz.common_timezones[-5:] # \u8bfb\u53d6common_timezones\u8fd9\u4e2a\u5217\u8868\u7684\u6700\u540e5\u4e2a\u5143\u7d20 print(tz)","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#useastern-ushawaii-usmountain-uspacific-utc","text":"\u8981\u83b7\u5f97pytz\u7684\u65f6\u533a\u5bf9\u8c61\uff0c\u53ef\u4f7f\u7528pytz.timezone\uff1a tz = pytz.timezone('Asia/Shanghai') print(tz) #### \u65f6\u533a\u7684\u672c\u5730\u5316\u548c\u8f6c\u6362 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cpandas\u4e2d\u7684\u65f6\u95f4\u5e8f\u5217\u662f\u65f6\u533a\u7b80\u5355\u578b\u7684\u3002 rng = pd.date_range('2021/1/1 9:30', periods=6, freq='D') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(rng)","title":"['US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC']"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-01-01-093000-2021-01-02-093000","text":"","title":"DatetimeIndex(['2021-01-01 09:30:00', '2021-01-02 09:30:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-03-093000-2021-01-04-093000","text":"","title":"'2021-01-03 09:30:00', '2021-01-04 09:30:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-05-093000-2021-01-06-093000","text":"","title":"'2021-01-05 09:30:00', '2021-01-06 09:30:00'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-freqd","text":"print(ts)","title":"dtype='datetime64[ns]', freq='D')"},{"location":"python/DataAnalysis/ch08/#2021-01-01-093000-0339822","text":"","title":"2021-01-01 09:30:00 0.339822"},{"location":"python/DataAnalysis/ch08/#2021-01-02-093000-1356382","text":"","title":"2021-01-02 09:30:00 1.356382"},{"location":"python/DataAnalysis/ch08/#2021-01-03-093000-0475429","text":"","title":"2021-01-03 09:30:00 0.475429"},{"location":"python/DataAnalysis/ch08/#2021-01-04-093000-1826654","text":"","title":"2021-01-04 09:30:00 1.826654"},{"location":"python/DataAnalysis/ch08/#2021-01-05-093000-0245510","text":"","title":"2021-01-05 09:30:00 -0.245510"},{"location":"python/DataAnalysis/ch08/#2021-01-06-093000-0705274","text":"","title":"2021-01-06 09:30:00 0.705274"},{"location":"python/DataAnalysis/ch08/#freq-d-dtype-float64","text":"print(ts.index.tz) # \u7d22\u5f15\u7684tz\u5c5e\u6027\u662fNone","title":"Freq: D, dtype: float64"},{"location":"python/DataAnalysis/ch08/#none","text":"\u65e5\u671f\u8303\u56f4\u53ef\u4ee5\u901a\u8fc7\u65f6\u533a\u96c6\u5408\u6765\u751f\u6210\uff1a rng = pd.date_range('2021/3/1', periods=10, freq='D', tz='UTC') print(rng)","title":"None"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-03-01-0000000000-2021-03-02-0000000000","text":"","title":"DatetimeIndex(['2021-03-01 00:00:00+00:00', '2021-03-02 00:00:00+00:00',"},{"location":"python/DataAnalysis/ch08/#2021-03-03-0000000000-2021-03-04-0000000000","text":"","title":"'2021-03-03 00:00:00+00:00', '2021-03-04 00:00:00+00:00',"},{"location":"python/DataAnalysis/ch08/#2021-03-05-0000000000-2021-03-06-0000000000","text":"","title":"'2021-03-05 00:00:00+00:00', '2021-03-06 00:00:00+00:00',"},{"location":"python/DataAnalysis/ch08/#2021-03-07-0000000000-2021-03-08-0000000000","text":"","title":"'2021-03-07 00:00:00+00:00', '2021-03-08 00:00:00+00:00',"},{"location":"python/DataAnalysis/ch08/#2021-03-09-0000000000-2021-03-10-0000000000","text":"","title":"'2021-03-09 00:00:00+00:00', '2021-03-10 00:00:00+00:00'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-utc-freqd","text":"\u4f7f\u7528`tz_localize`\u65b9\u6cd5\u53ef\u4ee5\u4ece\u7b80\u5355\u65f6\u533a\u8f6c\u6362\u5230\u672c\u5730\u5316\u65f6\u533a\uff1a print(ts)","title":"dtype='datetime64[ns, UTC]', freq='D')"},{"location":"python/DataAnalysis/ch08/#2021-01-01-093000-0294647","text":"","title":"2021-01-01 09:30:00 0.294647"},{"location":"python/DataAnalysis/ch08/#2021-01-02-093000-0958414","text":"","title":"2021-01-02 09:30:00 0.958414"},{"location":"python/DataAnalysis/ch08/#2021-01-03-093000-0424235","text":"","title":"2021-01-03 09:30:00 0.424235"},{"location":"python/DataAnalysis/ch08/#2021-01-04-093000-1714333","text":"","title":"2021-01-04 09:30:00 -1.714333"},{"location":"python/DataAnalysis/ch08/#2021-01-05-093000-0030319","text":"","title":"2021-01-05 09:30:00 -0.030319"},{"location":"python/DataAnalysis/ch08/#2021-01-06-093000-0744940","text":"","title":"2021-01-06 09:30:00 -0.744940"},{"location":"python/DataAnalysis/ch08/#freq-d-dtype-float64_1","text":"print(ts.tz_localize('UTC'))","title":"Freq: D, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0930000000-0294647","text":"","title":"2021-01-01 09:30:00+00:00 0.294647"},{"location":"python/DataAnalysis/ch08/#2021-01-02-0930000000-0958414","text":"","title":"2021-01-02 09:30:00+00:00 0.958414"},{"location":"python/DataAnalysis/ch08/#2021-01-03-0930000000-0424235","text":"","title":"2021-01-03 09:30:00+00:00 0.424235"},{"location":"python/DataAnalysis/ch08/#2021-01-04-0930000000-1714333","text":"","title":"2021-01-04 09:30:00+00:00 -1.714333"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000000-0030319","text":"","title":"2021-01-05 09:30:00+00:00 -0.030319"},{"location":"python/DataAnalysis/ch08/#2021-01-06-0930000000-0744940","text":"","title":"2021-01-06 09:30:00+00:00 -0.744940"},{"location":"python/DataAnalysis/ch08/#freq-d-dtype-float64_2","text":"print(ts.tz_localize('Asia/Shanghai'))","title":"Freq: D, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0930000800-0052521","text":"","title":"2021-01-01 09:30:00+08:00 0.052521"},{"location":"python/DataAnalysis/ch08/#2021-01-02-0930000800-0305417","text":"","title":"2021-01-02 09:30:00+08:00 -0.305417"},{"location":"python/DataAnalysis/ch08/#2021-01-03-0930000800-0150215","text":"","title":"2021-01-03 09:30:00+08:00 0.150215"},{"location":"python/DataAnalysis/ch08/#2021-01-04-0930000800-0953715","text":"","title":"2021-01-04 09:30:00+08:00 -0.953715"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000800-0543622","text":"","title":"2021-01-05 09:30:00+08:00 0.543622"},{"location":"python/DataAnalysis/ch08/#2021-01-06-0930000800-0222422","text":"","title":"2021-01-06 09:30:00+08:00 0.222422"},{"location":"python/DataAnalysis/ch08/#dtype-float64_3","text":"print(ts.tz_localize('Asia/Shanghai').index)","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-01-01-0930000800-2021-01-02-0930000800","text":"","title":"DatetimeIndex(['2021-01-01 09:30:00+08:00', '2021-01-02 09:30:00+08:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-03-0930000800-2021-01-04-0930000800","text":"","title":"'2021-01-03 09:30:00+08:00', '2021-01-04 09:30:00+08:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000800-2021-01-06-0930000800","text":"","title":"'2021-01-05 09:30:00+08:00', '2021-01-06 09:30:00+08:00'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-asiashanghai-freqnone","text":"\u4e00\u65e6\u65f6\u95f4\u5e8f\u5217\u88ab\u672c\u5730\u5316\u4e3a\u67d0\u4e2a\u7279\u5b9a\u7684\u65f6\u533a\uff0c\u5219\u53ef\u4ee5\u901a\u8fc7`tz_convert`\u5c06\u5176\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u65f6\u533a\uff1a tz_sha = ts.tz_localize('Asia/Shanghai') tz_utc = tz_sha.tz_convert('UTC') print(tz_sha)","title":"dtype='datetime64[ns, Asia/Shanghai]', freq=None)"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0930000800-0095689","text":"","title":"2021-01-01 09:30:00+08:00 0.095689"},{"location":"python/DataAnalysis/ch08/#2021-01-02-0930000800-0392730","text":"","title":"2021-01-02 09:30:00+08:00 -0.392730"},{"location":"python/DataAnalysis/ch08/#2021-01-03-0930000800-0151468","text":"","title":"2021-01-03 09:30:00+08:00 0.151468"},{"location":"python/DataAnalysis/ch08/#2021-01-04-0930000800-0027467","text":"","title":"2021-01-04 09:30:00+08:00 0.027467"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000800-0393709","text":"","title":"2021-01-05 09:30:00+08:00 0.393709"},{"location":"python/DataAnalysis/ch08/#2021-01-06-0930000800-0872914","text":"","title":"2021-01-06 09:30:00+08:00 0.872914"},{"location":"python/DataAnalysis/ch08/#dtype-float64_4","text":"print(tz_utc)","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0130000000-0095689","text":"","title":"2021-01-01 01:30:00+00:00 0.095689"},{"location":"python/DataAnalysis/ch08/#2021-01-02-0130000000-0392730","text":"","title":"2021-01-02 01:30:00+00:00 -0.392730"},{"location":"python/DataAnalysis/ch08/#2021-01-03-0130000000-0151468","text":"","title":"2021-01-03 01:30:00+00:00 0.151468"},{"location":"python/DataAnalysis/ch08/#2021-01-04-0130000000-0027467","text":"","title":"2021-01-04 01:30:00+00:00 0.027467"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0130000000-0393709","text":"","title":"2021-01-05 01:30:00+00:00 0.393709"},{"location":"python/DataAnalysis/ch08/#2021-01-06-0130000000-0872914","text":"","title":"2021-01-06 01:30:00+00:00 0.872914"},{"location":"python/DataAnalysis/ch08/#dtype-float64_5","text":"","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#tz_localizetz_convertdatetimeindex","text":"print(ts.index.tz_localize('Asia/Shanghai'))","title":"tz_localize\u548ctz_convert\u4e5f\u662fDatetimeIndex\u7684\u5b9e\u4f8b\u65b9\u6cd5\uff1a"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-01-01-0930000800-2021-01-02-0930000800_1","text":"","title":"DatetimeIndex(['2021-01-01 09:30:00+08:00', '2021-01-02 09:30:00+08:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-03-0930000800-2021-01-04-0930000800_1","text":"","title":"'2021-01-03 09:30:00+08:00', '2021-01-04 09:30:00+08:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000800-2021-01-06-0930000800_1","text":"","title":"'2021-01-05 09:30:00+08:00', '2021-01-06 09:30:00+08:00'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-asiashanghai-freqnone_1","text":"### \u65f6\u533a\u611f\u77e5\u65f6\u95f4\u6233\u5bf9\u8c61\u7684\u64cd\u4f5c \u4e0e\u65f6\u95f4\u5e8f\u5217\u548c\u65e5\u671f\u8303\u56f4\u7c7b\u4f3c\uff0c\u5355\u72ec\u7684`Timestamp`\u5bf9\u8c61\u4e5f\u53ef\u4ee5\u4ece\u7b80\u5355\u65f6\u95f4\u6233\u672c\u5730\u5316\u4e3a\u65f6\u533a\u611f\u77e5\u65f6\u95f4\u6233\uff0c\u5e76\u4ece\u4e00\u4e2a\u65f6\u533a\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u65f6\u533a\uff1a stamp = pd.Timestamp('2021-5-1 05:30') print(stamp)","title":"dtype='datetime64[ns, Asia/Shanghai]', freq=None)"},{"location":"python/DataAnalysis/ch08/#2021-05-01-053000","text":"stamp_utc = stamp.tz_localize('utc') print(stamp_utc)","title":"2021-05-01 05:30:00"},{"location":"python/DataAnalysis/ch08/#2021-05-01-0530000000","text":"stamp_sha = stamp_utc.tz_convert('Asia/Shanghai') print(stamp_sha)","title":"2021-05-01 05:30:00+00:00"},{"location":"python/DataAnalysis/ch08/#2021-05-01-1330000800","text":"\u4e5f\u53ef\u4ee5\u5728\u521b\u5efa`Timestamp`\u7684\u65f6\u5019\u4f20\u9012\u4e00\u4e2a\u65f6\u533a\uff1a stamp_sha = pd.Timestamp('2021-5-1 05:30', tz='Asia/Shanghai') print(stamp_sha)","title":"2021-05-01 13:30:00+08:00"},{"location":"python/DataAnalysis/ch08/#2021-05-01-0530000800","text":"`Timestamp`\u5bf9\u8c61\u5185\u90e8\u5b58\u50a8\u4e86\u4e00\u4e2aUnix\u7eaa\u5143(1970\u5e741\u67081\u65e5)\u81f3\u4eca\u7684\u7eb3\u79d2\u6570\u91cfUTC\u65f6\u95f4\u6233\u6570\u503c\uff0c\u8be5\u6570\u503c\u5728\u65f6\u533a\u8f6c\u6362\u4e2d\u662f\u4e0d\u53d8\u7684\uff1a print(stamp_utc.value)","title":"2021-05-01 05:30:00+08:00"},{"location":"python/DataAnalysis/ch08/#1619847000000000000","text":"print(stamp_utc.tz_convert('Asia/Shanghai').value)","title":"1619847000000000000"},{"location":"python/DataAnalysis/ch08/#1619847000000000000_1","text":"\u5728\u4f7f\u7528pandas\u7684`DateOffset`\u8fdb\u884c\u65f6\u95f4\u7b97\u672f\u65f6\uff0cpandas\u5c3d\u53ef\u80fd\u9075\u4ece\u590f\u65f6\u5236\u3002 \u9996\u5148\uff0c\u6784\u9020\u8f6c\u6362\u5230DST\u4e4b\u524d\u768430\u5206\u949f\u7684\u65f6\u95f4\uff1a stamp = pd.Timestamp('2012-3-12 1:30', tz='US/Eastern') print(stamp)","title":"1619847000000000000"},{"location":"python/DataAnalysis/ch08/#2012-03-12-013000-0400","text":"print(stamp + Hour())","title":"2012-03-12 01:30:00-04:00"},{"location":"python/DataAnalysis/ch08/#2012-03-12-023000-0400","text":"\u4e4b\u540e\uff0c\u6784\u5efa\u4eceDST\u8fdb\u884c\u8f6c\u6362\u524d\u768490\u5206\u949f\uff1a stamp = pd.Timestamp('2012-11-04 0:30-04:00', tz='US/Eastern') print(stamp)","title":"2012-03-12 02:30:00-04:00"},{"location":"python/DataAnalysis/ch08/#2012-11-04-003000-0400","text":"print(stamp + 2 * Hour()) # \u53ea\u589e\u52a0\u4e86\u4e00\u5c0f\u65f6","title":"2012-11-04 00:30:00-04:00"},{"location":"python/DataAnalysis/ch08/#2012-11-04-013000-0500","text":"### \u4e0d\u540c\u65f6\u533a\u95f4\u7684\u64cd\u4f5c \u5982\u679c\u4e24\u4e2a\u65f6\u533a\u4e0d\u540c\u7684\u65f6\u95f4\u5e8f\u5217\u9700\u8981\u8054\u5408\uff0c\u90a3\u4e48\u7ed3\u679c\u5c06\u662fUTC\u65f6\u95f4\u7684\uff0c\u56e0\u4e3a\u65f6\u95f4\u6233\u4ee5UTC\u683c\u5f0f\u5b58\u50a8\u3002 rng = pd.date_range('2021/1/1 9:30', periods=9, freq='B') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(ts)","title":"2012-11-04 01:30:00-05:00"},{"location":"python/DataAnalysis/ch08/#2021-01-01-093000-0715681","text":"","title":"2021-01-01 09:30:00 0.715681"},{"location":"python/DataAnalysis/ch08/#2021-01-04-093000-0524563","text":"","title":"2021-01-04 09:30:00 0.524563"},{"location":"python/DataAnalysis/ch08/#2021-01-05-093000-0482199","text":"","title":"2021-01-05 09:30:00 -0.482199"},{"location":"python/DataAnalysis/ch08/#2021-01-06-093000-0661303","text":"","title":"2021-01-06 09:30:00 -0.661303"},{"location":"python/DataAnalysis/ch08/#2021-01-07-093000-1750010","text":"","title":"2021-01-07 09:30:00 1.750010"},{"location":"python/DataAnalysis/ch08/#2021-01-08-093000-0251478","text":"","title":"2021-01-08 09:30:00 0.251478"},{"location":"python/DataAnalysis/ch08/#2021-01-11-093000-1487268","text":"","title":"2021-01-11 09:30:00 -1.487268"},{"location":"python/DataAnalysis/ch08/#2021-01-12-093000-0224024","text":"","title":"2021-01-12 09:30:00 -0.224024"},{"location":"python/DataAnalysis/ch08/#2021-01-13-093000-1621853","text":"","title":"2021-01-13 09:30:00 -1.621853"},{"location":"python/DataAnalysis/ch08/#freq-b-dtype-float64","text":"ts1 = ts[:7].tz_localize('Europe/London') ts2 = ts1[2:].tz_convert('Europe/Moscow') result = ts1 + ts2 print(ts1)","title":"Freq: B, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0930000000-1393445","text":"","title":"2021-01-01 09:30:00+00:00 -1.393445"},{"location":"python/DataAnalysis/ch08/#2021-01-04-0930000000-1179614","text":"","title":"2021-01-04 09:30:00+00:00 -1.179614"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000000-0716669","text":"","title":"2021-01-05 09:30:00+00:00 0.716669"},{"location":"python/DataAnalysis/ch08/#2021-01-06-0930000000-0485656","text":"","title":"2021-01-06 09:30:00+00:00 -0.485656"},{"location":"python/DataAnalysis/ch08/#2021-01-07-0930000000-0433000","text":"","title":"2021-01-07 09:30:00+00:00 0.433000"},{"location":"python/DataAnalysis/ch08/#2021-01-08-0930000000-1540745","text":"","title":"2021-01-08 09:30:00+00:00 1.540745"},{"location":"python/DataAnalysis/ch08/#2021-01-11-0930000000-0343751","text":"","title":"2021-01-11 09:30:00+00:00 0.343751"},{"location":"python/DataAnalysis/ch08/#dtype-float64_6","text":"print(ts2)","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-05-1230000300-0716669","text":"","title":"2021-01-05 12:30:00+03:00 0.716669"},{"location":"python/DataAnalysis/ch08/#2021-01-06-1230000300-0485656","text":"","title":"2021-01-06 12:30:00+03:00 -0.485656"},{"location":"python/DataAnalysis/ch08/#2021-01-07-1230000300-0433000","text":"","title":"2021-01-07 12:30:00+03:00 0.433000"},{"location":"python/DataAnalysis/ch08/#2021-01-08-1230000300-1540745","text":"","title":"2021-01-08 12:30:00+03:00 1.540745"},{"location":"python/DataAnalysis/ch08/#2021-01-11-1230000300-0343751","text":"","title":"2021-01-11 12:30:00+03:00 0.343751"},{"location":"python/DataAnalysis/ch08/#dtype-float64_7","text":"print(result)","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0930000000-nan","text":"","title":"2021-01-01 09:30:00+00:00 NaN"},{"location":"python/DataAnalysis/ch08/#2021-01-04-0930000000-nan","text":"","title":"2021-01-04 09:30:00+00:00 NaN"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000000-1433337","text":"","title":"2021-01-05 09:30:00+00:00 1.433337"},{"location":"python/DataAnalysis/ch08/#2021-01-06-0930000000-0971312","text":"","title":"2021-01-06 09:30:00+00:00 -0.971312"},{"location":"python/DataAnalysis/ch08/#2021-01-07-0930000000-0866000","text":"","title":"2021-01-07 09:30:00+00:00 0.866000"},{"location":"python/DataAnalysis/ch08/#2021-01-08-0930000000-3081489","text":"","title":"2021-01-08 09:30:00+00:00 3.081489"},{"location":"python/DataAnalysis/ch08/#2021-01-11-0930000000-0687502","text":"","title":"2021-01-11 09:30:00+00:00 0.687502"},{"location":"python/DataAnalysis/ch08/#dtype-float64_8","text":"## \u65f6\u95f4\u533a\u95f4\u548c\u533a\u95f4\u7b97\u672f from datetime import datetime, timedelta import pandas as pd import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd import pytz \u65f6\u95f4\u533a\u95f4\u8868\u793a\u7684\u662f\u65f6\u95f4\u8303\u56f4\u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628a`year`\u548c`quarter`\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f15\uff0c\u6bd4\u5982\u4e00\u4e9b\u5929\u3001\u4e00\u4e9b\u6708\u3001\u4e00\u4e9b\u5b63\u5ea6\u6216\u8005\u662f\u4e00\u4e9b\u5e74\u3002 `Period`\u7c7b\u8868\u793a\u7684\u6b63\u662f\u8fd9\u79cd\u6570\u636e\u7c7b\u578b\uff0c\u9700\u8981\u4e00\u4e2a\u5b57\u7b26\u4e32\u6216\u6570\u5b57\u4ee5\u53ca\u9891\u7387\u3002 \u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c`Period`\u5bf9\u8c61\u8868\u793a\u7684\u662f\u4ece2007\u5e741\u67081\u65e5\u52302007\u5e7412\u670831\u65e5\uff08\u5305\u542b\u5728\u5185\uff09\u7684\u65f6\u95f4\u6bb5\u3002 \u5728\u65f6\u95f4\u6bb5\u4e0a\u589e\u52a0\u6216\u51cf\u53bb\u6574\u6570\u53ef\u4ee5\u65b9\u4fbf\u5730\u6839\u636e\u5b83\u4eec\u7684\u9891\u7387\u8fdb\u884c\u79fb\u4f4d\u3002 p = pd.Period(2020, freq='A-DEC') print(p)","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020","text":"print(p + 5)","title":"2020"},{"location":"python/DataAnalysis/ch08/#2025","text":"print(p - 5)","title":"2025"},{"location":"python/DataAnalysis/ch08/#2015","text":"\u5982\u679c\u4e24\u4e2a\u533a\u95f4\u62e5\u6709\u76f8\u540c\u7684\u9891\u7387\uff0c\u5219\u5b83\u4eec\u7684\u5dee\u662f\u5b83\u4eec\u4e4b\u95f4\u7684\u5355\u4f4d\u6570\u3002 p1 = pd.Period(2020, freq='A-DEC') p2 = pd.Period(2010, freq='A-DEC') print(p1 - p2)","title":"2015"},{"location":"python/DataAnalysis/ch08/#10-yearends-month12","text":"p1 = pd.Period(2020, freq='Q-DEC') p2 = pd.Period(2010, freq='Q-DEC') print(p1 - p2)","title":"<10 * YearEnds: month=12>"},{"location":"python/DataAnalysis/ch08/#40-quarterends-startingmonth12","text":"\u4f7f\u7528`period_range`\u51fd\u6570\u53ef\u4ee5\u6784\u9020\u89c4\u5219\u533a\u95f4\u5e8f\u5217\u3002`PeriodIndex`\u7c7b\u5b58\u50a8\u7684\u662f\u533a\u95f4\u7684\u5e8f\u5217\uff0c\u53ef\u4ee5\u4f5c\u4e3a\u4efb\u610fpandas\u6570\u636e\u7ed3\u6784\u7684\u8f74\u7d22\u5f15\u3002 data = np.random.randn(6) strings = ['2021Q1', '2021Q2', '2021Q3', '2021Q4', '2022Q1', '2022Q2'] rng = pd.period_range('2001-1-1', '2001-6-30', freq='M') ts = pd.Series(data, index=rng) print(ts)","title":"<40 * QuarterEnds: startingMonth=12>"},{"location":"python/DataAnalysis/ch08/#2001-01-0481408","text":"","title":"2001-01 -0.481408"},{"location":"python/DataAnalysis/ch08/#2001-02-0297590","text":"","title":"2001-02 -0.297590"},{"location":"python/DataAnalysis/ch08/#2001-03-0860354","text":"","title":"2001-03 -0.860354"},{"location":"python/DataAnalysis/ch08/#2001-04-1281540","text":"","title":"2001-04 1.281540"},{"location":"python/DataAnalysis/ch08/#2001-05-1036551","text":"","title":"2001-05 1.036551"},{"location":"python/DataAnalysis/ch08/#2001-06-0522592","text":"","title":"2001-06 -0.522592"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_7","text":"rng = pd.PeriodIndex(strings, freq='Q-DEC') # \u5b57\u7b26\u4e32\u6570\u7ec4\u4e5f\u53ef\u4ee5\u4f7f\u7528PeriodIndex\u7c7b ts = pd.Series(data, index=rng) print(ts)","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021q1-2077200","text":"","title":"2021Q1 -2.077200"},{"location":"python/DataAnalysis/ch08/#2021q2-0948796","text":"","title":"2021Q2 -0.948796"},{"location":"python/DataAnalysis/ch08/#2021q3-1104737","text":"","title":"2021Q3 -1.104737"},{"location":"python/DataAnalysis/ch08/#2021q4-0090281","text":"","title":"2021Q4 0.090281"},{"location":"python/DataAnalysis/ch08/#2022q1-0431517","text":"","title":"2022Q1 0.431517"},{"location":"python/DataAnalysis/ch08/#2022q2-1537045","text":"","title":"2022Q2 1.537045"},{"location":"python/DataAnalysis/ch08/#freq-q-dec-dtype-float64","text":"### \u533a\u95f4\u9891\u7387\u8f6c\u6362 \u4f7f\u7528`asfreq`\u53ef\u4ee5\u5c06\u533a\u95f4\u548c`PeriodIndex`\u5bf9\u8c61\u8f6c\u6362\u4e3a\u5176\u4ed6\u7684\u9891\u7387\u3002 \u4f8b\u5982\uff0c\u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u5e74\u5ea6\u533a\u95f4\uff0c\u5e76\u4e14\u60f3\u8981\u5728\u4e00\u5e74\u7684\u5f00\u59cb\u6216\u7ed3\u675f\u65f6\u5c06\u5176\u8f6c\u6362\u4e3a\u6708\u5ea6\u533a\u95f4\u3002 \u53ef\u4ee5\u5c06`Period('2020', 'A-DEC')`\u770b\u4f5c\u4e00\u6bb5\u65f6\u95f4\u4e2d\u7684\u4e00\u79cd\u6e38\u6807\uff0c\u5c06\u65f6\u95f4\u6309\u6708\u4efd\u5212\u5206\u3002 p = pd.Period(2020, freq='A-DEC') print(p.asfreq('M', how='start'))","title":"Freq: Q-DEC, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01","text":"print(p.asfreq('M', how='end'))","title":"2020-01"},{"location":"python/DataAnalysis/ch08/#2020-12","text":"\u5982\u679c\u8d22\u5e74\u7ed3\u675f\u4e0d\u572812\u6708\uff0c\u5219\u6bcf\u6708\u5206\u671f\u4f1a\u81ea\u52a8\u8c03\u6574\u3002 \u6309\u5f53\u5e74\u8d22\u5e74\u7ed3\u675f\u8ba1\u7b97\uff0c\u8d77\u59cb\u5e74\u4efd\u5c31\u662f\u4e0a\u4e00\u5e74\u4e86\u3002 p = pd.Period(2020, freq='A-JUN') print(p.asfreq('M', how='start'))","title":"2020-12"},{"location":"python/DataAnalysis/ch08/#2019-07","text":"print(p.asfreq('M', how='end'))","title":"2019-07"},{"location":"python/DataAnalysis/ch08/#2020-06","text":"\u5f53\u4ece\u9ad8\u9891\u7387\u5411\u4f4e\u9891\u7387\u8f6c\u6362\u65f6\uff0cpandas\u6839\u636e\u5b50\u533a\u95f4\u7684\"\u6240\u5c5e\"\u6765\u51b3\u5b9a\u7236\u533a\u95f4\u3002 \u4f8b\u5982\uff0c\u5728A-JUN\u9891\u7387\u4e2d\uff0cAug-2020\u662f2020\u533a\u95f4\u7684\u4e00\u90e8\u5206\uff1a print(p.asfreq('A-JUN')) 2020\u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628a`year`\u548c`quarter`\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f15\u3002 \u5b8c\u6574\u7684`PeriodIndex`\u5bf9\u8c61\u6216\u65f6\u95f4\u5e8f\u5217\u53ef\u4ee5\u6309\u7167\u76f8\u540c\u7684\u8bed\u4e49\u8fdb\u884c\u8f6c\u6362\uff1a rng = pd.period_range('2018', '2021', freq='A-DEC') data = np.random.randn(len(rng)) ts = pd.Series(data, index=rng) print(ts)","title":"2020-06"},{"location":"python/DataAnalysis/ch08/#2018-0221634","text":"","title":"2018 0.221634"},{"location":"python/DataAnalysis/ch08/#2019-0392724","text":"","title":"2019 -0.392724"},{"location":"python/DataAnalysis/ch08/#2020-0355022","text":"","title":"2020 -0.355022"},{"location":"python/DataAnalysis/ch08/#2021-0114000","text":"","title":"2021 0.114000"},{"location":"python/DataAnalysis/ch08/#freq-a-dec-dtype-float64","text":"\u4e0b\u9762\u5e74\u5ea6\u533a\u95f4\u5c06\u901a\u8fc7`asfreq`\u88ab\u66ff\u6362\u4e3a\u5bf9\u5e94\u4e8e\u6bcf\u4e2a\u5e74\u5ea6\u533a\u95f4\u5185\u7684\u7b2c\u4e00\u4e2a\u6708\u7684\u6708\u5ea6\u533a\u95f4\u3002 print(ts.asfreq('M', how='start'))","title":"Freq: A-DEC, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2018-01-0681874","text":"","title":"2018-01 0.681874"},{"location":"python/DataAnalysis/ch08/#2019-01-1006585","text":"","title":"2019-01 -1.006585"},{"location":"python/DataAnalysis/ch08/#2020-01-0619142","text":"","title":"2020-01 -0.619142"},{"location":"python/DataAnalysis/ch08/#2021-01-1445820","text":"","title":"2021-01 1.445820"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_8","text":"\u5982\u679c\u6211\u4eec\u60f3\u8981\u6bcf\u5e74\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528`B`\u9891\u7387\u6765\u8868\u793a\u6211\u4eec\u60f3\u8981\u7684\u662f\u533a\u95f4\u7684\u672b\u7aef\u3002 print(ts.asfreq('B', how='end'))","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2018-12-31-1520316","text":"","title":"2018-12-31 -1.520316"},{"location":"python/DataAnalysis/ch08/#2019-12-31-0425544","text":"","title":"2019-12-31 -0.425544"},{"location":"python/DataAnalysis/ch08/#2020-12-31-0658073","text":"","title":"2020-12-31 -0.658073"},{"location":"python/DataAnalysis/ch08/#2021-12-31-1206881","text":"","title":"2021-12-31 1.206881"},{"location":"python/DataAnalysis/ch08/#freq-b-dtype-float64_1","text":"### \u5b63\u5ea6\u533a\u95f4\u9891\u7387 \u5b63\u5ea6\u6570\u636e\u662f\u4f1a\u8ba1\u3001\u91d1\u878d\u548c\u5176\u4ed6\u9886\u57df\u7684\u6807\u51c6\u3002 \u5f88\u591a\u5b63\u5ea6\u6570\u636e\u662f\u5728\u8d22\u5e74\u7ed3\u5c3e\u62a5\u544a\u7684\uff0c\u901a\u5e38\u662f\u4e00\u5e7412\u4e2a\u6708\u4e2d\u7684\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5\u6216\u5de5\u4f5c\u65e5\u3002 pandas\u652f\u6301\u6240\u6709\u7684\u53ef\u80fd\u768412\u4e2a\u5b63\u5ea6\u9891\u7387\u4eceQ-JAN\u5230Q-DEC\uff1a \u4e0b\u4f8b\u4e2d\uff0c\u8d22\u5e74\u7ed3\u675f\u4e8e1\u6708\uff0c2020Q4\u884c\u65f6\u95f4\u4e3a\u4e0a\u4e00\u5e7411\u6708\u81f3\u5f53\u5e741\u6708\u3002\u53ef\u4ee5\u901a\u8fc7\u8f6c\u6362\u4e3a\u6bcf\u65e5\u9891\u7387\uff08asfreq\uff09\u8fdb\u884c\u68c0\u67e5\u3002 p = pd.Period('2020Q4', freq='Q-JAN') print(p)","title":"Freq: B, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020q4","text":"print(p.asfreq('D', 'start'))","title":"2020Q4"},{"location":"python/DataAnalysis/ch08/#2019-11-01","text":"print(p.asfreq('D', 'end'))","title":"2019-11-01"},{"location":"python/DataAnalysis/ch08/#2020-01-31","text":"\u5047\u5982\u8d22\u5e74\u7ed3\u675f\u4e8e2\u6708\uff0c2020Q4\u884c\u65f6\u95f4\u4e3a\u4e0a\u4e00\u5e7412\u6708\u81f3\u5f53\u5e742\u6708\u3002 p = pd.Period('2020Q4', freq='Q-FEB') print(p)","title":"2020-01-31"},{"location":"python/DataAnalysis/ch08/#2020q4_1","text":"print(p.asfreq('D', 'start'))","title":"2020Q4"},{"location":"python/DataAnalysis/ch08/#2019-11-01_1","text":"print(p.asfreq('D', 'end'))","title":"2019-11-01"},{"location":"python/DataAnalysis/ch08/#2020-01-31_1","text":"\u5047\u5982\u8d22\u5e74\u7ed3\u675f\u4e8e4\u6708\uff0c2020Q4\u884c\u65f6\u95f4\u4e3a\u4e0a\u4e00\u5e7412\u6708\u81f3\u5f53\u5e742\u6708\u3002 p = pd.Period('2020Q4', freq='Q-APR') print(p)","title":"2020-01-31"},{"location":"python/DataAnalysis/ch08/#2020q4_2","text":"print(p.asfreq('D', 'start'))","title":"2020Q4"},{"location":"python/DataAnalysis/ch08/#2020-02-01","text":"print(p.asfreq('D', 'end'))","title":"2020-02-01"},{"location":"python/DataAnalysis/ch08/#2020-04-30","text":"\u53ef\u4ee5\u5bf9\u533a\u95f4\u6570\u636e\u505a\u7b97\u672f\u64cd\u4f5c\u3002\u4f8b\u5982\uff0c\u8981\u83b7\u53d6\u5728\u5b63\u5ea6\u5012\u6570\u7b2c\u4e8c\u4e2a\u5de5\u4f5c\u65e5\u4e0b\u53484\u70b9\u7684\u65f6\u95f4\u6233\uff0c\u53ef\u4ee5\u8fd9\u4e48\u505a\uff1a(\u7591\u95ee\uff1a\u8fd9\u91cc\u7684\u53c2\u6570e\u4ee3\u8868\u4ec0\u4e48 ???) p4pm = (p.asfreq('B', 'e') - 1).asfreq('T', 's') + 16 * 60 print(p4pm)","title":"2020-04-30"},{"location":"python/DataAnalysis/ch08/#2020-04-29-1600","text":"print(p4pm.to_timestamp())","title":"2020-04-29 16:00"},{"location":"python/DataAnalysis/ch08/#2020-04-29-160000","text":"\u53ef\u4ee5\u4f7f\u7528`peroid_range`\u751f\u6210\u5b63\u5ea6\u5e8f\u5217\u3002\u5b83\u7684\u7b97\u672f\u4e5f\u662f\u4e00\u6837\u7684\uff1a rng = pd.period_range('2000Q3', '2001Q4', freq='Q-JAN') ts = pd.Series(np.arange(len(rng)), index=rng) print(ts)","title":"2020-04-29 16:00:00"},{"location":"python/DataAnalysis/ch08/#2000q3-0","text":"","title":"2000Q3 0"},{"location":"python/DataAnalysis/ch08/#2000q4-1","text":"","title":"2000Q4 1"},{"location":"python/DataAnalysis/ch08/#2001q1-2","text":"","title":"2001Q1 2"},{"location":"python/DataAnalysis/ch08/#2001q2-3","text":"","title":"2001Q2 3"},{"location":"python/DataAnalysis/ch08/#2001q3-4","text":"","title":"2001Q3 4"},{"location":"python/DataAnalysis/ch08/#2001q4-5","text":"","title":"2001Q4 5"},{"location":"python/DataAnalysis/ch08/#freq-q-jan-dtype-int64","text":"new_rng = (rng.asfreq('B', 'e') - 1).asfreq('T', 's') + 16 * 60 ts.index = new_rng.to_timestamp() print(ts)","title":"Freq: Q-JAN, dtype: int64"},{"location":"python/DataAnalysis/ch08/#1999-10-28-160000-0","text":"","title":"1999-10-28 16:00:00 0"},{"location":"python/DataAnalysis/ch08/#2000-01-28-160000-1","text":"","title":"2000-01-28 16:00:00 1"},{"location":"python/DataAnalysis/ch08/#2000-04-27-160000-2","text":"","title":"2000-04-27 16:00:00 2"},{"location":"python/DataAnalysis/ch08/#2000-07-28-160000-3","text":"","title":"2000-07-28 16:00:00 3"},{"location":"python/DataAnalysis/ch08/#2000-10-30-160000-4","text":"","title":"2000-10-30 16:00:00 4"},{"location":"python/DataAnalysis/ch08/#2001-01-30-160000-5","text":"","title":"2001-01-30 16:00:00 5"},{"location":"python/DataAnalysis/ch08/#dtype-int64","text":"### \u5c06\u65f6\u95f4\u6233\u8f6c\u6362\u4e3a\u533a\u95f4\uff08\u4ee5\u53ca\u9006\u8f6c\u6362\uff09 \u901a\u8fc7\u65f6\u95f4\u6233\u7d22\u5f15\u7684Series\u548cDataFrame\u53ef\u4ee5\u88ab`to_period`\u65b9\u6cd5\u8f6c\u6362\u4e3a\u533a\u95f4\uff1a rng = pd.date_range('2020-01-01', periods=3, freq='M') ts = pd.Series(np.random.randn(3), index=rng) print(ts)","title":"dtype: int64"},{"location":"python/DataAnalysis/ch08/#2020-01-31-0567097","text":"","title":"2020-01-31 -0.567097"},{"location":"python/DataAnalysis/ch08/#2020-02-29-0634521202yearquarter2","text":"","title":"2020-02-29 0.63452\u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628ayear\u548cquarter\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f152"},{"location":"python/DataAnalysis/ch08/#2020-03-31-0297777","text":"","title":"2020-03-31 0.297777"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_9","text":"pts = ts.to_period() print(pts)","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-0567097","text":"","title":"2020-01 -0.567097"},{"location":"python/DataAnalysis/ch08/#2020-02-0634522","text":"","title":"2020-02 0.634522"},{"location":"python/DataAnalysis/ch08/#2020-03-0297777","text":"","title":"2020-03 0.297777"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_10","text":"\u7531\u4e8e\u533a\u95f4\u662f\u975e\u91cd\u53e0\u65f6\u95f4\u8303\u56f4\uff0c\u4e00\u4e2a\u65f6\u95f4\u6233\u53ea\u80fd\u5c5e\u4e8e\u7ed9\u5b9a\u9891\u7387\u7684\u5355\u4e2a\u533a\u95f4\u3002 \u5c3d\u7ba1\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u6839\u636e\u65f6\u95f4\u6233\u63a8\u65ad\u51fa\u65b0`PeriodIndex`\u7684\u9891\u7387\uff0c\u4f46\u53ef\u4ee5\u6307\u5b9a\u4efb\u4f55\u60f3\u8981\u7684\u9891\u7387\u3002 \u5728\u7ed3\u679c\u4e2d\u5305\u542b\u91cd\u590d\u7684\u533a\u95f4\u4e5f\u662f\u6ca1\u6709\u95ee\u9898\u7684\u3002 rng = pd.date_range('2020-01-01', periods=6, freq='D') ts = pd.Series(np.random.randn(6), index=rng) print(ts)","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0111287","text":"","title":"2020-01-01 -0.111287"},{"location":"python/DataAnalysis/ch08/#2020-01-02-1442234","text":"","title":"2020-01-02 1.442234"},{"location":"python/DataAnalysis/ch08/#2020-01-03-0767553","text":"","title":"2020-01-03 -0.767553"},{"location":"python/DataAnalysis/ch08/#2020-01-04-0265064","text":"","title":"2020-01-04 -0.265064"},{"location":"python/DataAnalysis/ch08/#2020-01-05-1200312","text":"","title":"2020-01-05 1.200312"},{"location":"python/DataAnalysis/ch08/#2020-01-06-1782557","text":"","title":"2020-01-06 -1.782557"},{"location":"python/DataAnalysis/ch08/#freq-d-dtype-float64_3","text":"ts_m = ts.to_period('M') # \u6307\u5b9aperiod\u7684\u9891\u7387\uff08M\uff09,\u8f93\u51fa\u7ed3\u679c\u5305\u542b\u91cd\u590dperiod print(ts_m)","title":"Freq: D, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-0111287","text":"","title":"2020-01 -0.111287"},{"location":"python/DataAnalysis/ch08/#2020-01-1442234","text":"","title":"2020-01 1.442234"},{"location":"python/DataAnalysis/ch08/#2020-01-0767553","text":"","title":"2020-01 -0.767553"},{"location":"python/DataAnalysis/ch08/#2020-01-0265064","text":"","title":"2020-01 -0.265064"},{"location":"python/DataAnalysis/ch08/#2020-01-1200312","text":"","title":"2020-01 1.200312"},{"location":"python/DataAnalysis/ch08/#2020-01-1782557","text":"","title":"2020-01 -1.782557"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_11","text":"\u4f7f\u7528`to_timestamp`\u53ef\u4ee5\u5c06\u533a\u95f4\u518d\u8f6c\u6362\u4e3a\u65f6\u95f4\u6233\uff1a print(ts_m.to_timestamp(how='end'))","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-31-235959999999999-0111287","text":"","title":"2020-01-31 23:59:59.999999999 -0.111287"},{"location":"python/DataAnalysis/ch08/#2020-01-31-235959999999999-1442234","text":"","title":"2020-01-31 23:59:59.999999999 1.442234"},{"location":"python/DataAnalysis/ch08/#2020-01-31-235959999999999-0767553","text":"","title":"2020-01-31 23:59:59.999999999 -0.767553"},{"location":"python/DataAnalysis/ch08/#2020-01-31-235959999999999-0265064","text":"","title":"2020-01-31 23:59:59.999999999 -0.265064"},{"location":"python/DataAnalysis/ch08/#2020-01-31-235959999999999-1200312","text":"","title":"2020-01-31 23:59:59.999999999 1.200312"},{"location":"python/DataAnalysis/ch08/#2020-01-31-235959999999999-1782557","text":"","title":"2020-01-31 23:59:59.999999999 -1.782557"},{"location":"python/DataAnalysis/ch08/#dtype-float64_9","text":"print(ts_m.to_timestamp(how='start'))","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0111287_1","text":"","title":"2020-01-01 -0.111287"},{"location":"python/DataAnalysis/ch08/#2020-01-01-1442234","text":"","title":"2020-01-01 1.442234"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0767553","text":"","title":"2020-01-01 -0.767553"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0265064","text":"","title":"2020-01-01 -0.265064"},{"location":"python/DataAnalysis/ch08/#2020-01-01-1200312","text":"","title":"2020-01-01 1.200312"},{"location":"python/DataAnalysis/ch08/#2020-01-01-1782557","text":"","title":"2020-01-01 -1.782557"},{"location":"python/DataAnalysis/ch08/#dtype-float64_10","text":"### \u4ece\u6570\u7ec4\u751f\u6210PeriodIndex \u56fa\u5b9a\u9891\u7387\u6570\u636e\u96c6\u6709\u65f6\u5b58\u50a8\u5728\u8de8\u8d8a\u591a\u5217\u7684\u65f6\u95f4\u8303\u56f4\u4fe1\u606f\u4e2d\u3002\u4f8b\u5982\uff0c\u5728\u8fd9\u4e2a\u5b8f\u89c2\u7ecf\u6d4e\u6570\u636e\u96c6\u4e2d\uff0c\u5e74\u4efd\u548c\u5b63\u5ea6\u5728\u4e0d\u540c\u5217\u4e2d\uff1a data = pd.read_csv('../examples/macrodata.csv') print(data.head(5))","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#year-quarter-realgdp-realcons-unemp-pop-infl-realint","text":"","title":"year quarter realgdp realcons ... unemp pop infl realint"},{"location":"python/DataAnalysis/ch08/#0-19590-10-2710349-17074-58-177146-000-000","text":"","title":"0 1959.0 1.0 2710.349 1707.4 ... 5.8 177.146 0.00 0.00"},{"location":"python/DataAnalysis/ch08/#1-19590-20-2778801-17337-51-177830-234-074","text":"","title":"1 1959.0 2.0 2778.801 1733.7 ... 5.1 177.830 2.34 0.74"},{"location":"python/DataAnalysis/ch08/#2-19590-30-2775488-17518-53-178657-274-109","text":"","title":"2 1959.0 3.0 2775.488 1751.8 ... 5.3 178.657 2.74 1.09"},{"location":"python/DataAnalysis/ch08/#3-19590-40-2785204-17537-56-179386-027-406","text":"","title":"3 1959.0 4.0 2785.204 1753.7 ... 5.6 179.386 0.27 4.06"},{"location":"python/DataAnalysis/ch08/#4-19600-10-2847699-17705-52-180007-231-119","text":"print(data.year)","title":"4 1960.0 1.0 2847.699 1770.5 ... 5.2 180.007 2.31 1.19"},{"location":"python/DataAnalysis/ch08/#0-19590","text":"","title":"0 1959.0"},{"location":"python/DataAnalysis/ch08/#1-19590","text":"","title":"1 1959.0"},{"location":"python/DataAnalysis/ch08/#2-19590","text":"","title":"2 1959.0"},{"location":"python/DataAnalysis/ch08/#3-19590","text":"","title":"3 1959.0"},{"location":"python/DataAnalysis/ch08/#4-19600","text":"","title":"4 1960.0"},{"location":"python/DataAnalysis/ch08/#_10","text":"","title":"..."},{"location":"python/DataAnalysis/ch08/#198-20080","text":"","title":"198 2008.0"},{"location":"python/DataAnalysis/ch08/#199-20080","text":"","title":"199 2008.0"},{"location":"python/DataAnalysis/ch08/#200-20090","text":"","title":"200 2009.0"},{"location":"python/DataAnalysis/ch08/#201-20090","text":"","title":"201 2009.0"},{"location":"python/DataAnalysis/ch08/#202-20090","text":"","title":"202 2009.0"},{"location":"python/DataAnalysis/ch08/#name-year-length-203-dtype-float64","text":"print(data.quarter)","title":"Name: year, Length: 203, dtype: float64"},{"location":"python/DataAnalysis/ch08/#0-10","text":"","title":"0 1.0"},{"location":"python/DataAnalysis/ch08/#1-20","text":"","title":"1 2.0"},{"location":"python/DataAnalysis/ch08/#2-30","text":"","title":"2 3.0"},{"location":"python/DataAnalysis/ch08/#3-40","text":"","title":"3 4.0"},{"location":"python/DataAnalysis/ch08/#4-10","text":"","title":"4 1.0"},{"location":"python/DataAnalysis/ch08/#_11","text":"","title":"..."},{"location":"python/DataAnalysis/ch08/#198-30","text":"","title":"198 3.0"},{"location":"python/DataAnalysis/ch08/#199-40","text":"","title":"199 4.0"},{"location":"python/DataAnalysis/ch08/#200-10","text":"","title":"200 1.0"},{"location":"python/DataAnalysis/ch08/#201-20","text":"","title":"201 2.0"},{"location":"python/DataAnalysis/ch08/#202-30","text":"","title":"202 3.0"},{"location":"python/DataAnalysis/ch08/#name-quarter-length-203-dtype-float64","text":"\u901a\u8fc7\u5c06\u8fd9\u4e9b\u6570\u7ec4\u548c\u9891\u7387\u4f20\u9012\u7ed9`PeriodIndex`\uff0c\u53ef\u4ee5\u8054\u5408\u5f62\u6210DataFrame\u7684\u7d22\u5f15 index = pd.PeriodIndex(year=data.year, quarter=data.quarter, freq='Q-DEC') print(index)","title":"Name: quarter, Length: 203, dtype: float64"},{"location":"python/DataAnalysis/ch08/#periodindex1959q1-1959q2-1959q3-1959q4-1960q1-1960q2","text":"","title":"PeriodIndex(['1959Q1', '1959Q2', '1959Q3', '1959Q4', '1960Q1', '1960Q2',"},{"location":"python/DataAnalysis/ch08/#1960q3-1960q4-1961q1-1961q2","text":"","title":"'1960Q3', '1960Q4', '1961Q1', '1961Q2',"},{"location":"python/DataAnalysis/ch08/#_12","text":"","title":"..."},{"location":"python/DataAnalysis/ch08/#2007q2-2007q3-2007q4-2008q1-2008q2-2008q3","text":"","title":"'2007Q2', '2007Q3', '2007Q4', '2008Q1', '2008Q2', '2008Q3',"},{"location":"python/DataAnalysis/ch08/#2008q4-2009q1-2009q2-2009q3","text":"","title":"'2008Q4', '2009Q1', '2009Q2', '2009Q3'],"},{"location":"python/DataAnalysis/ch08/#dtypeperiodq-dec-length203","text":"data.index = index # \u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628ayear\u548cquarter\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f15 print(data.infl)","title":"dtype='period[Q-DEC]', length=203)"},{"location":"python/DataAnalysis/ch08/#1959q1-000","text":"","title":"1959Q1 0.00"},{"location":"python/DataAnalysis/ch08/#1959q2-234","text":"","title":"1959Q2 2.34"},{"location":"python/DataAnalysis/ch08/#1959q3-274","text":"","title":"1959Q3 2.74"},{"location":"python/DataAnalysis/ch08/#1959q4-027","text":"","title":"1959Q4 0.27"},{"location":"python/DataAnalysis/ch08/#1960q1-231","text":"","title":"1960Q1 2.31"},{"location":"python/DataAnalysis/ch08/#_13","text":"","title":"..."},{"location":"python/DataAnalysis/ch08/#2008q3-316","text":"","title":"2008Q3 -3.16"},{"location":"python/DataAnalysis/ch08/#2008q4-879","text":"","title":"2008Q4 -8.79"},{"location":"python/DataAnalysis/ch08/#2009q1-094","text":"","title":"2009Q1 0.94"},{"location":"python/DataAnalysis/ch08/#2009q2-337","text":"","title":"2009Q2 3.37"},{"location":"python/DataAnalysis/ch08/#2009q3-356","text":"","title":"2009Q3 3.56"},{"location":"python/DataAnalysis/ch08/#freq-q-dec-name-infl-length-203-dtype-float64","text":"## \u91cd\u65b0\u91c7\u6837\u9891\u7387\u8f6c\u6362 import pandas as pd import numpy as np from pandas.tseries.frequencies import to_offset \u91cd\u65b0\u91c7\u6837\u662f\u6307\u5c06\u65f6\u95f4\u5e8f\u5217\u4ece\u4e00\u4e2a\u9891\u7387\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u9891\u7387\u7684\u8fc7\u7a0b\u3002 \u5c06\u66f4\u9ad8\u9891\u7387\u7684\u6570\u636e\u805a\u5408\u5230\u4f4e\u9891\u7387\u88ab\u79f0\u4e3a\u5411\u4e0b\u91c7\u6837\uff0c\u800c\u4ece\u4f4e\u9891\u7387\u8f6c\u6362\u5230\u9ad8\u9891\u7387\u79f0\u4e3a\u5411\u4e0a\u91c7\u6837\u3002 \u5e76\u4e0d\u662f\u6240\u6709\u7684\u91cd\u65b0\u91c7\u6837\u90fd\u5c5e\u4e8e\u4e0a\u9762\u8bf4\u7684\u4e24\u7c7b\u3002\u4f8b\u5982\uff0c\u5c06W-WED\uff08weekly on Wednesday\uff0c\u6bcf\u5468\u4e09\uff09\u8f6c\u6362\u5230W-FRI\uff08\u6bcf\u5468\u4e94\uff09\u65e2\u4e0d\u662f\u5411\u4e0a\u91c7\u6837\u4e5f\u4e0d\u662f\u5411\u4e0b\u91c7\u6837\u3002 pandas\u5bf9\u8c61\u90fd\u914d\u6709`resample`\u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u662f\u6240\u6709\u9891\u7387\u8f6c\u6362\u7684\u5de5\u5177\u51fd\u6570\u3002`resample`\u62e5\u6709\u7c7b\u4f3c\u4e8e`groupby`\u7684API\uff1b\u8c03\u7528`resample`\u5bf9\u6570\u636e\u5206\u7ec4\uff0c\u4e4b\u540e\u518d\u8c03\u7528\u805a\u5408\u51fd\u6570\uff1a ### resample\u65b9\u6cd5\u53c2\u6570 \u53c2\u6570 * freq: \u8868\u793a\u91cd\u91c7\u6837\u9891\u7387\uff0c\u4f8b\u5982\u2018M'\u3001\u20185min'\uff0cSecond(15) * how='mean': \u7528\u4e8e\u4ea7\u751f\u805a\u5408\u503c\u7684\u51fd\u6570\u540d\u6216\u6570\u7ec4\u51fd\u6570\uff0c\u4f8b\u5982\u2018mean'\u3001\u2018ohlc'\u3001np.max\u7b49\uff0c\u9ed8\u8ba4\u662f\u2018mean'\uff0c\u5176\u4ed6\u5e38\u7528\u7684\u503c\u7531\uff1a\u2018first'\u3001\u2018last'\u3001\u2018median'\u3001\u2018max'\u3001\u2018min' * axis=0: \u9ed8\u8ba4\u662f\u7eb5\u8f74\uff0c\u6a2a\u8f74\u8bbe\u7f6eaxis=1 * fill_method = None: \u5347\u91c7\u6837\u65f6\u5982\u4f55\u63d2\u503c\uff0c\u6bd4\u5982\u2018ffill'\u3001\u2018bfill'\u7b49 * closed = \u2018right': \u5728\u964d\u91c7\u6837\u65f6\uff0c\u5404\u65f6\u95f4\u6bb5\u7684\u54ea\u4e00\u6bb5\u662f\u95ed\u5408\u7684\uff0c\u2018right'\u6216\u2018left'\uff0c\u9ed8\u8ba4\u2018right' * label= \u2018right': \u5728\u964d\u91c7\u6837\u65f6\uff0c\u5982\u4f55\u8bbe\u7f6e\u805a\u5408\u503c\u7684\u6807\u7b7e\uff0c\u4f8b\u5982\uff0c9\uff1a30-9\uff1a35\u4f1a\u88ab\u6807\u8bb0\u62109\uff1a30\u8fd8\u662f9\uff1a35,\u9ed8\u8ba49\uff1a35 * loffset = None: \u9762\u5143\u6807\u7b7e\u7684\u65f6\u95f4\u6821\u6b63\u503c\uff0c\u6bd4\u5982\u2018-1s'\u6216Second(-1)\u7528\u4e8e\u5c06\u805a\u5408\u6807\u7b7e\u8c03\u65e91\u79d2 * limit=None: \u5728\u5411\u524d\u6216\u5411\u540e\u586b\u5145\u65f6\uff0c\u5141\u8bb8\u586b\u5145\u7684\u6700\u5927\u65f6\u671f\u6570 * kind = None: \u805a\u5408\u5230\u65f6\u671f\uff08\u2018period'\uff09\u6216\u65f6\u95f4\u6233\uff08\u2018timestamp'\uff09\uff0c\u9ed8\u8ba4\u805a\u5408\u5230\u65f6\u95f4\u5e8f\u5217\u7684\u7d22\u5f15\u7c7b\u578b * convention = None: \u5f53\u91cd\u91c7\u6837\u65f6\u671f\u65f6\uff0c\u5c06\u4f4e\u9891\u7387\u8f6c\u6362\u5230\u9ad8\u9891\u7387\u6240\u91c7\u7528\u7684\u7ea6\u5b9a\uff08start\u6216end\uff09\u3002\u9ed8\u8ba4\u2018end' rng = pd.date_range('2020-1-1', periods=100, freq='D') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(ts)","title":"Freq: Q-DEC, Name: infl, Length: 203, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0802409","text":"","title":"2020-01-01 0.802409"},{"location":"python/DataAnalysis/ch08/#2020-01-02-1147130","text":"","title":"2020-01-02 -1.147130"},{"location":"python/DataAnalysis/ch08/#2020-01-03-1076115","text":"","title":"2020-01-03 -1.076115"},{"location":"python/DataAnalysis/ch08/#2020-01-04-2097443","text":"","title":"2020-01-04 -2.097443"},{"location":"python/DataAnalysis/ch08/#2020-01-05-0577671","text":"","title":"2020-01-05 0.577671"},{"location":"python/DataAnalysis/ch08/#_14","text":"","title":"..."},{"location":"python/DataAnalysis/ch08/#2020-04-05-0110747","text":"","title":"2020-04-05 -0.110747"},{"location":"python/DataAnalysis/ch08/#2020-04-06-0132867","text":"","title":"2020-04-06 0.132867"},{"location":"python/DataAnalysis/ch08/#2020-04-07-0294061","text":"","title":"2020-04-07 -0.294061"},{"location":"python/DataAnalysis/ch08/#2020-04-08-0246155","text":"","title":"2020-04-08 -0.246155"},{"location":"python/DataAnalysis/ch08/#2020-04-09-0927194","text":"","title":"2020-04-09 0.927194"},{"location":"python/DataAnalysis/ch08/#freq-d-length-100-dtype-float64","text":"print(ts.resample('M'))","title":"Freq: D, Length: 100, dtype: float64"},{"location":"python/DataAnalysis/ch08/#datetimeindexresampler-freq-axis0-closedright-labelright-conventionstart-originstart_day","text":"print(ts.resample('M').mean()) # \u628a100\u5929\u7684\u6570\u636e\u6309\u6708groupby\uff0c\u5e76\u8f93\u51fa\u6708\u672b\u6700\u540e\u4e00\u5929\uff0c\u8ba1\u7b97\u5e73\u5747\u503c","title":"DatetimeIndexResampler [freq=, axis=0, closed=right, label=right, convention=start, origin=start_day]"},{"location":"python/DataAnalysis/ch08/#2020-01-31-0311714","text":"","title":"2020-01-31 -0.311714"},{"location":"python/DataAnalysis/ch08/#2020-02-29-0121526","text":"","title":"2020-02-29 0.121526"},{"location":"python/DataAnalysis/ch08/#2020-03-31-0051131","text":"","title":"2020-03-31 -0.051131"},{"location":"python/DataAnalysis/ch08/#2020-04-30-0273113","text":"","title":"2020-04-30 -0.273113"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_12","text":"print(ts.resample('M', kind='period').mean()) # # \u628a100\u5929\u7684\u6570\u636e\u6309\u6708groupby\uff0c\u5e76\u8f93\u51fa\u6708\u4efd\uff08\u53c2\u6570period\uff09\uff0c\u8ba1\u7b97\u5e73\u5747\u503c","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-0311714","text":"","title":"2020-01 -0.311714"},{"location":"python/DataAnalysis/ch08/#2020-02-0121526","text":"","title":"2020-02 0.121526"},{"location":"python/DataAnalysis/ch08/#2020-03-0051131","text":"","title":"2020-03 -0.051131"},{"location":"python/DataAnalysis/ch08/#2020-04-0273113","text":"","title":"2020-04 -0.273113"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_13","text":"### \u5411\u4e0b\u91c7\u6837 \u5c06\u6570\u636e\u805a\u5408\u5230\u4e00\u4e2a\u89c4\u5219\u7684\u4f4e\u9891\u7387\u4e0a\u662f\u4e00\u4e2a\u5e38\u89c1\u7684\u65f6\u95f4\u5e8f\u5217\u4efb\u52a1\u3002 \u8981\u805a\u5408\u7684\u6570\u636e\u4e0d\u5fc5\u662f\u56fa\u5b9a\u9891\u7387\u7684\u3002 \u671f\u671b\u7684\u9891\u7387\u5b9a\u4e49\u4e86\u7528\u4e8e\u5bf9\u65f6\u95f4\u5e8f\u5217\u5207\u7247\u4ee5\u805a\u5408\u7684\u7bb1\u4f53\u8fb9\u754c\u3002\u4f8b\u5982\uff0c\u8981\u5c06\u65f6\u95f4\u8f6c\u6362\u4e3a\u6bcf\u6708\uff0c`M`\u6216`BM`\uff0c\u5219\u9700\u8981\u5c06\u6570\u636e\u5206\u6210\u4e00\u4e2a\u6708\u7684\u65f6\u95f4\u95f4\u9694\u3002 \u6bcf\u4e2a\u95f4\u9694\u662f\u534a\u95ed\u5408\u7684\uff0c\u4e00\u4e2a\u6570\u636e\u70b9\u53ea\u80fd\u5c5e\u4e8e\u4e00\u4e2a\u65f6\u95f4\u95f4\u9694\uff0c\u65f6\u95f4\u95f4\u9694\u7684\u5e76\u96c6\u5fc5\u987b\u662f\u6574\u4e2a\u65f6\u95f4\u5e27\u3002 \u5728\u4f7f\u7528resample\u8fdb\u884c\u5411\u4e0b\u91c7\u6837\u6570\u636e\u65f6\u6709\u4e9b\u4e8b\u60c5\u9700\u8981\u8003\u8651\uff1a * \u6bcf\u6bb5\u95f4\u9694\u7684\u54ea\u4e00\u8fb9\u662f\u95ed\u5408\u7684\u3002 * \u5982\u4f55\u5728\u95f4\u9694\u7684\u8d77\u59cb\u6216\u7ed3\u675f\u4f4d\u7f6e\u6807\u8bb0\u6bcf\u4e2a\u5df2\u805a\u5408\u7684\u7bb1\u4f53\u3002 rng = pd.date_range('2020-1-1', periods=12, freq='T') ts = pd.Series(np.arange(12), index=rng) print(ts)","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000000-0","text":"","title":"2020-01-01 00:00:00 0"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000100-1","text":"","title":"2020-01-01 00:01:00 1"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000200-2","text":"","title":"2020-01-01 00:02:00 2"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000300-3","text":"","title":"2020-01-01 00:03:00 3"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000400-4","text":"","title":"2020-01-01 00:04:00 4"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000500-5","text":"","title":"2020-01-01 00:05:00 5"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000600-6","text":"","title":"2020-01-01 00:06:00 6"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000700-7","text":"","title":"2020-01-01 00:07:00 7"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000800-8","text":"","title":"2020-01-01 00:08:00 8"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000900-9","text":"","title":"2020-01-01 00:09:00 9"},{"location":"python/DataAnalysis/ch08/#2020-01-01-001000-10","text":"","title":"2020-01-01 00:10:00 10"},{"location":"python/DataAnalysis/ch08/#2020-01-01-001100-11","text":"","title":"2020-01-01 00:11:00 11"},{"location":"python/DataAnalysis/ch08/#freq-t-dtype-int64","text":"\u6309\u4e94\u5206\u949f\u9891\u7387\u805a\u5408\u5206\u7ec4\uff0c\u8ba1\u7b97\u6bcf\u4e00\u7ec4\u7684\u52a0\u548c\u3002\u9891\u7387\u6309\u4e94\u5206\u949f\u7684\u589e\u91cf\u5b9a\u4e49\u4e86\u7bb1\u4f53\u8fb9\u754c\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5de6\u7bb1\u4f53\u8fb9\u754c\u662f\u5305\u542b\u7684\uff0c\u56e0\u6b6400:00\u7684\u503c\u662f\u5305\u542b\u572800:00\u523000:05\u95f4\u9694\u5185\u7684\u3002 \u4f20\u9012`closed='right'`\u5c06\u95f4\u9694\u7684\u95ed\u5408\u7aef\u6539\u4e3a\u4e86\u53f3\u8fb9\u3002 \u5206\u7ec4\uff1a * left: [00:00,00:01,00:02,00:03,00:04],[00:05,00:06,00:07,00:08,00:09],[00:10,00:11] * right:[00:00],[00:01,00:02,00:03,00:04,00:05],[00:06,00:07,00:08,00:09,00:10],[00:11] result = ts.resample('5min', closed='right').sum() print(result)","title":"Freq: T, dtype: int64"},{"location":"python/DataAnalysis/ch08/#2019-12-31-235500-0","text":"","title":"2019-12-31 23:55:00 0"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000000-15","text":"","title":"2020-01-01 00:00:00 15"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000500-40","text":"","title":"2020-01-01 00:05:00 40"},{"location":"python/DataAnalysis/ch08/#2020-01-01-001000-11","text":"","title":"2020-01-01 00:10:00 11"},{"location":"python/DataAnalysis/ch08/#freq-5t-dtype-int64","text":"result = ts.resample('5min', closed='left').sum() print(result)","title":"Freq: 5T, dtype: int64"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000000-10","text":"","title":"2020-01-01 00:00:00 10"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000500-35","text":"","title":"2020-01-01 00:05:00 35"},{"location":"python/DataAnalysis/ch08/#2020-01-01-001000-21","text":"","title":"2020-01-01 00:10:00 21"},{"location":"python/DataAnalysis/ch08/#freq-5t-dtype-int64_1","text":"\u6700\u540e\uff0c\u5c06\u7ed3\u679c\u7d22\u5f15\u79fb\u52a8\u4e00\u5b9a\u7684\u6570\u91cf\uff0c\u4f8b\u5982\u4ece\u53f3\u8fb9\u7f18\u51cf\u53bb\u4e00\u79d2\uff0c\u4ee5\u4f7f\u5176\u66f4\u6e05\u695a\u5730\u8868\u660e\u65f6\u95f4\u6233\u6240\u6307\u7684\u95f4\u9694\u3002 \u8981\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\uff0c\u5411`loffset`\u4f20\u9012\u5b57\u7b26\u4e32\u6216\u65e5\u671f\u504f\u7f6e\uff1a result = ts.resample('5min', closed='right', label='right', loffset='-1s').sum() print(result)","title":"Freq: 5T, dtype: int64"},{"location":"python/DataAnalysis/ch08/#2019-12-31-235959-0","text":"","title":"2019-12-31 23:59:59 0"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000459-15","text":"","title":"2020-01-01 00:04:59 15"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000959-40","text":"","title":"2020-01-01 00:09:59 40"},{"location":"python/DataAnalysis/ch08/#2020-01-01-001459-11","text":"","title":"2020-01-01 00:14:59 11"},{"location":"python/DataAnalysis/ch08/#freq-5t-dtype-int64_2","text":"","title":"Freq: 5T, dtype: int64"},{"location":"python/DataAnalysis/ch08/#futurewarning-loffset-in-resample-and-in-grouper-is-deprecated","text":"","title":"FutureWarning: 'loffset' in .resample() and in Grouper() is deprecated."},{"location":"python/DataAnalysis/ch08/#dfresamplefreq3s-loffset8h","text":"","title":">>> df.resample(freq=\"3s\", loffset=\"8H\")"},{"location":"python/DataAnalysis/ch08/#becomes","text":"","title":"becomes:"},{"location":"python/DataAnalysis/ch08/#from-pandastseriesfrequencies-import-to_offset","text":"","title":">>> from pandas.tseries.frequencies import to_offset"},{"location":"python/DataAnalysis/ch08/#df-dfresamplefreq3smean","text":"","title":">>> df = df.resample(freq=\"3s\").mean()"},{"location":"python/DataAnalysis/ch08/#dfindex-dfindexto_timestamp-to_offset8h","text":"#### \u5f00\u7aef-\u5cf0\u503c-\u8c37\u503c-\u7ed3\u675f\uff08OHLC\uff09\u91cd\u65b0\u91c7\u6837 \u5728\u91d1\u878d\u4e2d\uff0c\u4e3a\u6bcf\u4e2a\u6570\u636e\u6876\u8ba1\u7b97\u56db\u4e2a\u503c\u662f\u4e00\u79cd\u6d41\u884c\u7684\u65f6\u95f4\u5e8f\u5217\u805a\u5408\u65b9\u6cd5\uff1a\u7b2c\u4e00\u4e2a\u503c\uff08\u5f00\u7aef\uff09\u3001\u6700\u540e\u4e00\u4e2a\u503c\uff08\u7ed3\u675f\uff09\u3001\u6700\u5927\u503c\uff08\u5cf0\u503c\uff09\u548c\u6700\u5c0f\u503c\uff08\u8c37\u503c\uff09\u3002 \u901a\u8fc7\u4f7f\u7528`ohlc`\u805a\u5408\u51fd\u6570\u53d6\u5f97\u5305\u542b\u56db\u79cd\u805a\u5408\u503c\u5217\u7684DataFrame\uff0c\u8fd9\u4e9b\u503c\u5728\u6570\u636e\u7684\u5355\u6b21\u626b\u63cf\u4e2d\u88ab\u9ad8\u6548\u8ba1\u7b97\uff1a result = ts.resample('5min').ohlc() print(result)","title":">>> df.index = df.index.to_timestamp() + to_offset(\"8H\")"},{"location":"python/DataAnalysis/ch08/#open-high-low-close","text":"","title":"open high low close"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000000-0-4-0-4","text":"","title":"2020-01-01 00:00:00 0 4 0 4"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000500-5-9-5-9","text":"","title":"2020-01-01 00:05:00 5 9 5 9"},{"location":"python/DataAnalysis/ch08/#2020-01-01-001000-10-11-10-11","text":"### \u5411\u4e0a\u91c7\u6837\u4e0e\u63d2\u503c \u5f53\u4ece\u4f4e\u9891\u7387\u8f6c\u6362\u4e3a\u9ad8\u9891\u7387\u65f6\uff0c\u5e76\u4e0d\u9700\u8981\u4efb\u4f55\u805a\u5408\u3002 df = pd.DataFrame( np.random.randn(2, 4), index=pd.date_range('2020/1/1', periods=2, freq='W-WED'), columns=['Colorado', 'Texas', 'New York', 'Ohio'] ) print(df)","title":"2020-01-01 00:10:00 10 11 10 11"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0228758-0758718-0025410-1001819","text":"","title":"2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-08-0704541-0261414-0863335-0267101","text":"df_daily = df.resample('W-WED').sum() print(df_daily)","title":"2020-01-08 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_1","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0228758-0758718-0025410-1001819_1","text":"","title":"2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-08-0704541-0261414-0863335-0267101_1","text":"df_daily = df.resample('D').sum() print(df_daily)","title":"2020-01-08 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_2","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0228758-0758718-0025410-1001819_2","text":"","title":"2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-02-0000000-0000000-0000000-0000000","text":"","title":"2020-01-02 0.000000 0.000000 0.000000 0.000000"},{"location":"python/DataAnalysis/ch08/#2020-01-03-0000000-0000000-0000000-0000000","text":"","title":"2020-01-03 0.000000 0.000000 0.000000 0.000000"},{"location":"python/DataAnalysis/ch08/#2020-01-04-0000000-0000000-0000000-0000000","text":"","title":"2020-01-04 0.000000 0.000000 0.000000 0.000000"},{"location":"python/DataAnalysis/ch08/#2020-01-05-0000000-0000000-0000000-0000000","text":"","title":"2020-01-05 0.000000 0.000000 0.000000 0.000000"},{"location":"python/DataAnalysis/ch08/#2020-01-06-0000000-0000000-0000000-0000000","text":"","title":"2020-01-06 0.000000 0.000000 0.000000 0.000000"},{"location":"python/DataAnalysis/ch08/#2020-01-07-0000000-0000000-0000000-0000000","text":"","title":"2020-01-07 0.000000 0.000000 0.000000 0.000000"},{"location":"python/DataAnalysis/ch08/#2020-01-08-0704541-0261414-0863335-0267101_2","text":"\u5f53\u5bf9\u8fd9\u4e9b\u6570\u636e\u4f7f\u7528\u805a\u5408\u51fd\u6570\u65f6\uff0c\u6bcf\u4e00\u7ec4\u53ea\u6709\u4e00\u4e2a\u503c\uff0c\u5e76\u4e14\u4f1a\u5728\u95f4\u9699\u4e2d\u4ea7\u751f\u7f3a\u5931\u503c\u3002 \u4f7f\u7528`asfreq`\u65b9\u6cd5\u5728\u4e0d\u805a\u5408\u7684\u60c5\u51b5\u4e0b\u8f6c\u6362\u5230\u9ad8\u9891\u7387\uff1a df_daily = df.resample('D').asfreq() print(df_daily)","title":"2020-01-08 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_3","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0228758-0758718-0025410-1001819_3","text":"","title":"2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-02-nan-nan-nan-nan","text":"","title":"2020-01-02 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-03-nan-nan-nan-nan","text":"","title":"2020-01-03 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-04-nan-nan-nan-nan","text":"","title":"2020-01-04 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-05-nan-nan-nan-nan","text":"","title":"2020-01-05 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-06-nan-nan-nan-nan","text":"","title":"2020-01-06 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-07-nan-nan-nan-nan","text":"","title":"2020-01-07 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-08-0704541-0261414-0863335-0267101_3","text":"\u5728\u975e\u661f\u671f\u4e09\u7684\u65e5\u671f\u4e0a\u5411\u524d\u586b\u5145\u6bcf\u5468\u6570\u503c\u3002`fillna`\u548c`reindex`\u65b9\u6cd5\u4e2d\u53ef\u7528\u7684\u586b\u5145\u6216\u63d2\u503c\u65b9\u6cd5\u53ef\u7528\u4e8e\u91cd\u91c7\u6837\uff1a df_daily = df.resample('D').ffill() print(df_daily)","title":"2020-01-08 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_4","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0228758-0758718-0025410-1001819_4","text":"","title":"2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-02-0228758-0758718-0025410-1001819","text":"","title":"2020-01-02 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-03-0228758-0758718-0025410-1001819","text":"","title":"2020-01-03 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-04-0228758-0758718-0025410-1001819","text":"","title":"2020-01-04 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-05-0228758-0758718-0025410-1001819","text":"","title":"2020-01-05 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-06-0228758-0758718-0025410-1001819","text":"","title":"2020-01-06 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-07-0228758-0758718-0025410-1001819","text":"","title":"2020-01-07 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-08-0704541-0261414-0863335-0267101_4","text":"\u53ef\u4ee5\u540c\u6837\u9009\u62e9\u4ec5\u5411\u524d\u586b\u5145\u4e00\u5b9a\u6570\u91cf\u7684\u533a\u95f4\uff0c\u4ee5\u9650\u5236\u7ee7\u7eed\u4f7f\u7528\u89c2\u6d4b\u503c\u7684\u65f6\u8ddd\uff1a df_daily = df.resample('D').ffill(limit=2) print(df_daily)","title":"2020-01-08 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_5","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0228758-0758718-0025410-1001819_5","text":"","title":"2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-02-0228758-0758718-0025410-1001819_1","text":"","title":"2020-01-02 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-03-0228758-0758718-0025410-1001819_1","text":"","title":"2020-01-03 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-04-nan-nan-nan-nan_1","text":"","title":"2020-01-04 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-05-nan-nan-nan-nan_1","text":"","title":"2020-01-05 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-06-nan-nan-nan-nan_1","text":"","title":"2020-01-06 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-07-nan-nan-nan-nan_1","text":"","title":"2020-01-07 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-08-0704541-0261414-0863335-0267101_5","text":"\u6ce8\u610f\uff0c\u65b0\u7684\u65e5\u671f\u7d22\u5f15\u4e0d\u9700\u8981\u4e0e\u65e7\u7684\u7d22\u5f15\u91cd\u53e0\uff0c\u548c\u539f\u6765`df`\u7684\u503c\u4e00\u6837\uff0c\u53ea\u662f\u65e5\u671f\u7d22\u5f15\u53d8\u4e86\u3002 df_new = df.resample('W-THU').ffill() print(df_new)","title":"2020-01-08 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_6","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-02-0228758-0758718-0025410-1001819_2","text":"","title":"2020-01-02 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-09-0704541-0261414-0863335-0267101","text":"### \u4f7f\u7528\u533a\u95f4\u8fdb\u884c\u91cd\u65b0\u91c7\u6837 \u5bf9\u4ee5\u533a\u95f4\u4e3a\u7d22\u5f15\u7684\u6570\u636e\u8fdb\u884c\u91c7\u6837\u4e0e\u65f6\u95f4\u6233\u7684\u60c5\u51b5\u7c7b\u4f3c\uff1a df = pd.DataFrame( np.random.randn(24, 4), index=pd.period_range('2020-1', periods=24, freq='M'), columns=['Colorado', 'Texas', 'New York', 'Ohio'] ) print(df)","title":"2020-01-09 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#2020-01-0721395-1492674-0707410-1641890","text":"","title":"2020-01 0.721395 -1.492674 0.707410 1.641890"},{"location":"python/DataAnalysis/ch08/#2020-02-0894880-0032823-0676158-0029203","text":"","title":"2020-02 -0.894880 0.032823 -0.676158 0.029203"},{"location":"python/DataAnalysis/ch08/#2020-03-2147365-0176796-0562695-0747656","text":"","title":"2020-03 2.147365 -0.176796 0.562695 -0.747656"},{"location":"python/DataAnalysis/ch08/#2020-04-1496037-0797119-0495601-0774147","text":"","title":"2020-04 1.496037 -0.797119 -0.495601 0.774147"},{"location":"python/DataAnalysis/ch08/#2020-05-0309839-0502563-0237244-0910624","text":"","title":"2020-05 -0.309839 0.502563 0.237244 0.910624"},{"location":"python/DataAnalysis/ch08/#2020-06-1231869-0105227-1315759-0217701","text":"","title":"2020-06 1.231869 -0.105227 1.315759 0.217701"},{"location":"python/DataAnalysis/ch08/#2020-07-1447419-0263876-0342045-0768907","text":"","title":"2020-07 1.447419 0.263876 -0.342045 -0.768907"},{"location":"python/DataAnalysis/ch08/#2020-08-2567162-1008827-0391085-1259560","text":"","title":"2020-08 -2.567162 -1.008827 0.391085 1.259560"},{"location":"python/DataAnalysis/ch08/#2020-09-0772501-1183532-0450374-0450714","text":"","title":"2020-09 -0.772501 1.183532 0.450374 0.450714"},{"location":"python/DataAnalysis/ch08/#2020-10-0228974-0461224-1393178-0175243","text":"","title":"2020-10 0.228974 0.461224 1.393178 0.175243"},{"location":"python/DataAnalysis/ch08/#2020-11-0725193-1544131-1372029-0659224","text":"","title":"2020-11 -0.725193 -1.544131 1.372029 -0.659224"},{"location":"python/DataAnalysis/ch08/#2020-12-0718195-0862024-0166460-0940191","text":"","title":"2020-12 0.718195 0.862024 -0.166460 -0.940191"},{"location":"python/DataAnalysis/ch08/#2021-01-0617054-0887312-0338451-1392838","text":"","title":"2021-01 -0.617054 -0.887312 0.338451 -1.392838"},{"location":"python/DataAnalysis/ch08/#2021-02-0081140-0634730-0868051-1277167","text":"","title":"2021-02 -0.081140 0.634730 -0.868051 -1.277167"},{"location":"python/DataAnalysis/ch08/#2021-03-0999642-1959715-0930662-0748687","text":"","title":"2021-03 -0.999642 -1.959715 -0.930662 0.748687"},{"location":"python/DataAnalysis/ch08/#2021-04-1851453-1561669-0688822-0371255","text":"","title":"2021-04 1.851453 1.561669 -0.688822 -0.371255"},{"location":"python/DataAnalysis/ch08/#2021-05-0540777-0890403-1204188-0243480","text":"","title":"2021-05 -0.540777 -0.890403 -1.204188 0.243480"},{"location":"python/DataAnalysis/ch08/#2021-06-1318905-1247457-0518969-0799793","text":"","title":"2021-06 1.318905 1.247457 0.518969 0.799793"},{"location":"python/DataAnalysis/ch08/#2021-07-0223238-0747177-0410889-0904593","text":"","title":"2021-07 0.223238 0.747177 -0.410889 0.904593"},{"location":"python/DataAnalysis/ch08/#2021-08-0652551-0254351-0464604-0676923","text":"","title":"2021-08 -0.652551 -0.254351 -0.464604 -0.676923"},{"location":"python/DataAnalysis/ch08/#2021-09-0562312-0182099-0018617-0573331","text":"","title":"2021-09 0.562312 0.182099 0.018617 0.573331"},{"location":"python/DataAnalysis/ch08/#2021-10-0429490-0045959-0356292-0295776","text":"","title":"2021-10 0.429490 -0.045959 -0.356292 -0.295776"},{"location":"python/DataAnalysis/ch08/#2021-11-2552155-0801299-1378421-1232792","text":"","title":"2021-11 2.552155 0.801299 1.378421 1.232792"},{"location":"python/DataAnalysis/ch08/#2021-12-1102288-0850280-0767015-0519840","text":"df_annual = df.resample('A-DEC').mean() print(df_annual)","title":"2021-12 1.102288 0.850280 -0.767015 -0.519840"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_7","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-0226807-0151561-0395793-0195259","text":"","title":"2020 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021-0429056-0165581-0286339-0002594","text":"\u5411\u4e0a\u91c7\u6837\u66f4\u4e3a\u7ec6\u81f4\uff0c\u56e0\u4e3a\u5fc5\u987b\u5728\u91cd\u65b0\u91c7\u6837\u524d\u51b3\u5b9a\u65b0\u9891\u7387\u4e2d\u5728\u65f6\u95f4\u6bb5\u7684\u54ea\u4e00\u7aef\u653e\u7f6e\u6570\u503c\uff0c\u5c31\u50cfasfreq\u65b9\u6cd5\u4e00\u6837\u3002 `convention`\u53c2\u6570\u9ed8\u8ba4\u503c\u662f`start`\uff0c\u4f46\u4e5f\u53ef\u4ee5\u662f`end`\uff1a result = df_annual.resample('Q-DEC').ffill() print(result)","title":"2021 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_8","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020q1-0226807-0151561-0395793-0195259","text":"","title":"2020Q1 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2020q2-0226807-0151561-0395793-0195259","text":"","title":"2020Q2 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2020q3-0226807-0151561-0395793-0195259","text":"","title":"2020Q3 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2020q4-0226807-0151561-0395793-0195259","text":"","title":"2020Q4 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q1-0429056-0165581-0286339-0002594","text":"","title":"2021Q1 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#2021q2-0429056-0165581-0286339-0002594","text":"","title":"2021Q2 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#2021q3-0429056-0165581-0286339-0002594","text":"","title":"2021Q3 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#2021q4-0429056-0165581-0286339-0002594","text":"result = df_annual.resample('Q-DEC', convention='end').ffill() print(result)","title":"2021Q4 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_9","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020q4-0226807-0151561-0395793-0195259_1","text":"","title":"2020Q4 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q1-0226807-0151561-0395793-0195259","text":"","title":"2021Q1 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q2-0226807-0151561-0395793-0195259","text":"","title":"2021Q2 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q3-0226807-0151561-0395793-0195259","text":"","title":"2021Q3 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q4-0429056-0165581-0286339-0002594_1","text":"\u7531\u4e8e\u533a\u95f4\u6d89\u53ca\u65f6\u95f4\u8303\u56f4\uff0c\u5411\u4e0a\u91c7\u6837\u548c\u5411\u4e0b\u91c7\u6837\u5c31\u66f4\u4e3a\u4e25\u683c\uff1a * \u5728\u5411\u4e0b\u91c7\u6837\u4e2d\uff0c\u76ee\u6807\u9891\u7387\u5fc5\u987b\u662f\u539f\u9891\u7387\u7684\u5b50\u533a\u95f4\u3002 * \u5728\u5411\u4e0a\u91c7\u6837\u4e2d\uff0c\u76ee\u6807\u9891\u7387\u5fc5\u987b\u662f\u539f\u9891\u7387\u7684\u7236\u533a\u95f4\u3002 \u5982\u679c\u4e0d\u6ee1\u8db3\u8fd9\u4e9b\u89c4\u5219\uff0c\u5c06\u4f1a\u5f15\u8d77\u5f02\u5e38\u3002\u8fd9\u4e3b\u8981\u4f1a\u5f71\u54cd\u6bcf\u5b63\u5ea6\u3001\u6bcf\u5e74\u548c\u6bcf\u5468\u7684\u9891\u7387\u3002 \u4f8b\u5982\uff0c\u6839\u636eQ-MAR\u5b9a\u4e49\u7684\u65f6\u95f4\u8303\u56f4\u5c06\u53ea\u548cA-MAR\u3001A-JUN\u3001A-SEP\u548cA-DEC\u4fdd\u6301\u4e00\u81f4\uff1a result = df_annual.resample('Q-MAR').ffill() print(result)","title":"2021Q4 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_10","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020q4-0226807-0151561-0395793-0195259_2","text":"","title":"2020Q4 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q1-0226807-0151561-0395793-0195259_1","text":"","title":"2021Q1 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q2-0226807-0151561-0395793-0195259_1","text":"","title":"2021Q2 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q3-0226807-0151561-0395793-0195259_1","text":"","title":"2021Q3 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q4-0429056-0165581-0286339-0002594_2","text":"","title":"2021Q4 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#2022q1-0429056-0165581-0286339-0002594","text":"","title":"2022Q1 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#2022q2-0429056-0165581-0286339-0002594","text":"","title":"2022Q2 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#2022q3-0429056-0165581-0286339-0002594","text":"## \u79fb\u52a8\u7a97\u53e3\u51fd\u6570 \u7edf\u8ba1\u90a3\u4e9b\u901a\u8fc7\u79fb\u52a8\u7a97\u53e3\u6216\u6307\u6570\u8870\u51cf\u800c\u8fd0\u884c\u7684\u51fd\u6570\uff0c\u662f\u7528\u4e8e\u65f6\u95f4\u5e8f\u5217\u64cd\u4f5c\u7684\u6570\u7ec4\u53d8\u6362\u7684\u4e00\u4e2a\u91cd\u8981\u7c7b\u522b\u3002 \u8fd9\u5bf9\u5e73\u6ed1\u566a\u58f0\u6216\u7c97\u7cd9\u7684\u6570\u636e\u975e\u5e38\u6709\u7528\u3002\u79f0\u8fd9\u4e9b\u51fd\u6570\u4e3a\u79fb\u52a8\u7a97\u53e3\u51fd\u6570\uff0c\u5c3d\u7ba1\u5b83\u4e5f\u5305\u542b\u4e86\u4e00\u4e9b\u6ca1\u6709\u56fa\u5b9a\u957f\u5ea6\u7a97\u53e3\u7684\u51fd\u6570\uff0c\u6bd4\u5982\u6307\u6570\u52a0\u6743\u79fb\u52a8\u5e73\u5747\u3002 \u4e0e\u5176\u4ed6\u7684\u7edf\u8ba1\u51fd\u6570\u7c7b\u4f3c\uff0c\u8fd9\u4e9b\u51fd\u6570\u4f1a\u81ea\u52a8\u6392\u9664\u7f3a\u5931\u6570\u636e\u3002 import matplotlib.pyplot as plt import pandas as pd from scipy.stats import percentileofscore import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd import pytz \u5728\u6df1\u5165\u4e86\u89e3\u4e4b\u524d\uff0c\u6211\u4eec\u53ef\u4ee5\u5148\u8f7d\u5165\u4e00\u4e9b\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u5e76\u6309\u7167\u5de5\u4f5c\u65e5\u9891\u7387\u8fdb\u884c\u91cd\u65b0\u91c7\u6837\uff1a close_px_all = pd.read_csv( '../examples/stock_px_2.csv', parse_dates = True, index_col=0 ) print(close_px_all.head(5))","title":"2022Q3 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#aapl-msft-xom-spx","text":"","title":"AAPL MSFT XOM SPX"},{"location":"python/DataAnalysis/ch08/#2003-01-02-740-2111-2922-90903","text":"","title":"2003-01-02 7.40 21.11 29.22 909.03"},{"location":"python/DataAnalysis/ch08/#2003-01-03-745-2114-2924-90859","text":"","title":"2003-01-03 7.45 21.14 29.24 908.59"},{"location":"python/DataAnalysis/ch08/#2003-01-06-745-2152-2996-92901","text":"","title":"2003-01-06 7.45 21.52 29.96 929.01"},{"location":"python/DataAnalysis/ch08/#2003-01-07-743-2193-2895-92293","text":"","title":"2003-01-07 7.43 21.93 28.95 922.93"},{"location":"python/DataAnalysis/ch08/#2003-01-08-728-2131-2883-90993","text":"close_px = close_px_all[ ['AAPL', 'MSFT', 'XOM'] ] close_px = close_px.resample('B').ffill() print(close_px)","title":"2003-01-08 7.28 21.31 28.83 909.93"},{"location":"python/DataAnalysis/ch08/#aapl-msft-xom","text":"","title":"AAPL MSFT XOM"},{"location":"python/DataAnalysis/ch08/#2003-01-02-740-2111-2922","text":"","title":"2003-01-02 7.40 21.11 29.22"},{"location":"python/DataAnalysis/ch08/#2003-01-03-745-2114-2924","text":"","title":"2003-01-03 7.45 21.14 29.24"},{"location":"python/DataAnalysis/ch08/#_15","text":"","title":"... ... ... ..."},{"location":"python/DataAnalysis/ch08/#2011-10-13-40843-2718-7637","text":"","title":"2011-10-13 408.43 27.18 76.37"},{"location":"python/DataAnalysis/ch08/#2011-10-14-42200-2727-7811","text":"","title":"2011-10-14 422.00 27.27 78.11"},{"location":"python/DataAnalysis/ch08/#2292-rows-x-3-columns","text":"`rolling`\u7b97\u5b50\uff0c\u5b83\u7684\u884c\u4e3a\u4e0e`resample`\u548c`groupby`\u7c7b\u4f3c\u3002 `rolling`\u53ef\u4ee5\u5728Series\u6216DataFrame\u4e0a\u901a\u8fc7\u4e00\u4e2awindow\uff08\u4ee5\u4e00\u4e2a\u533a\u95f4\u7684\u6570\u5b57\u6765\u8868\u793a\uff09\u8fdb\u884c\u8c03\u7528\u3002 close_px.AAPL.plot() \u8868\u8fbe\u5f0f`rolling(250)`\u4e0e`groupby`\u7684\u884c\u4e3a\u7c7b\u4f3c\uff0c\u4f46\u662f\u5b83\u521b\u5efa\u7684\u5bf9\u8c61\u662f\u6839\u636e250\u65e5\u6ed1\u52a8\u7a97\u53e3\u5206\u7ec4\u7684\u800c\u4e0d\u662f\u76f4\u63a5\u5206\u7ec4\u3002 \u56e0\u6b64\u8fd9\u91cc\u6211\u4eec\u83b7\u5f97\u4e86\u82f9\u679c\u516c\u53f8\u80a1\u7968\u4ef7\u683c\u7684250\u65e5\u79fb\u52a8\u7a97\u53e3\u5e73\u5747\u503c\u3002 close_px.AAPL.rolling(250).mean().plot() plt.show() \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6eda\u52a8\u51fd\u6570\u9700\u8981\u7a97\u53e3\u4e2d\u6240\u6709\u7684\u503c\u5fc5\u987b\u662f\u975e`NA`\u503c\u3002 \u7531\u4e8e\u5b58\u5728\u7f3a\u5931\u503c\u8fd9\u79cd\u884c\u4e3a\u4f1a\u53d1\u751f\u6539\u53d8\uff0c\u5c24\u5176\u662f\u5728\u65f6\u95f4\u5e8f\u5217\u7684\u8d77\u59cb\u4f4d\u7f6e\u4f60\u62e5\u6709\u7684\u6570\u636e\u662f\u5c11\u4e8e\u7a97\u53e3\u533a\u95f4\u7684 apple_std250 = close_px.AAPL.rolling(250, min_periods=10).std() # \u82f9\u679c\u516c\u53f8250\u65e5\u6bcf\u65e5\u8fd4\u56de\u6807\u51c6\u5dee print(apple_std250[5:12])","title":"[2292 rows x 3 columns]"},{"location":"python/DataAnalysis/ch08/#2003-01-09-nan","text":"","title":"2003-01-09 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-10-nan","text":"","title":"2003-01-10 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-13-nan","text":"","title":"2003-01-13 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-14-nan","text":"","title":"2003-01-14 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-15-0077496","text":"","title":"2003-01-15 0.077496"},{"location":"python/DataAnalysis/ch08/#2003-01-16-0074760","text":"","title":"2003-01-16 0.074760"},{"location":"python/DataAnalysis/ch08/#2003-01-17-0112368","text":"","title":"2003-01-17 0.112368"},{"location":"python/DataAnalysis/ch08/#freq-b-name-aapl-dtype-float64","text":"apple_std250.plot() plt.show() expanding_mean = apple_std250.expanding().mean() print(expanding_mean[5:12])","title":"Freq: B, Name: AAPL, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2003-01-09-nan_1","text":"","title":"2003-01-09 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-10-nan_1","text":"","title":"2003-01-10 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-13-nan_1","text":"","title":"2003-01-13 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-14-nan_1","text":"","title":"2003-01-14 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-15-0077496_1","text":"","title":"2003-01-15 0.077496"},{"location":"python/DataAnalysis/ch08/#2003-01-16-0076128","text":"","title":"2003-01-16 0.076128"},{"location":"python/DataAnalysis/ch08/#2003-01-17-0088208","text":"","title":"2003-01-17 0.088208"},{"location":"python/DataAnalysis/ch08/#freq-b-name-aapl-dtype-float64_1","text":"expanding_mean.plot() plt.show() \u5728DataFrame\u4e0a\u8c03\u7528\u4e00\u4e2a\u79fb\u52a8\u7a97\u53e3\u51fd\u6570\u4f1a\u5c06\u53d8\u6362\u5e94\u7528\u5230\u6bcf\u4e00\u5217\u4e0a: close_px.rolling(60).mean().plot(logy=True) # \u80a1\u7968\u4ef7\u683c60\u65e5MA\uff08Y\u8f74\u53d6\u5bf9\u6570\uff09 plt.show() `rolling`\u51fd\u6570\u4e5f\u63a5\u6536\u8868\u793a\u56fa\u5b9a\u5927\u5c0f\u7684\u65f6\u95f4\u504f\u7f6e\u5b57\u7b26\u4e32\uff0c\u800c\u4e0d\u53ea\u662f\u4e00\u4e2a\u533a\u95f4\u7684\u96c6\u5408\u6570\u5b57\u3002 \u5bf9\u4e0d\u89c4\u5219\u65f6\u95f4\u5e8f\u5217\u4f7f\u7528\u6ce8\u91ca\u975e\u5e38\u6709\u7528\u3002\u8fd9\u4e9b\u5b57\u7b26\u4e32\u53ef\u4ee5\u4f20\u9012\u7ed9`resample`\u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u50cf\u8fd9\u6837\u8ba1\u7b9720\u5929\u7684\u6eda\u52a8\u5e73\u5747\u503c\uff1a result = close_px.rolling('20D').mean() print(result)","title":"Freq: B, Name: AAPL, dtype: float64"},{"location":"python/DataAnalysis/ch08/#aapl-msft-xom_1","text":"","title":"AAPL MSFT XOM"},{"location":"python/DataAnalysis/ch08/#2003-01-02-7400000-21110000-29220000","text":"","title":"2003-01-02 7.400000 21.110000 29.220000"},{"location":"python/DataAnalysis/ch08/#_16","text":"","title":"... ... ... ..."},{"location":"python/DataAnalysis/ch08/#2011-10-14-391038000-26048667-74185333","text":"","title":"2011-10-14 391.038000 26.048667 74.185333"},{"location":"python/DataAnalysis/ch08/#2292-rows-x-3-columns_1","text":"result.plot() plt.show() ### \u6307\u6570\u52a0\u6743\u51fd\u6570 \u6307\u5b9a\u4e00\u4e2a\u5e38\u6570\u8870\u51cf\u56e0\u5b50\u4ee5\u5411\u66f4\u591a\u8fd1\u671f\u89c2\u6d4b\u503c\u63d0\u4f9b\u66f4\u591a\u6743\u91cd\uff0c\u53ef\u4ee5\u66ff\u4ee3\u4f7f\u7528\u5177\u6709\u76f8\u7b49\u52a0\u6743\u89c2\u5bdf\u503c\u7684\u9759\u6001\u7a97\u53e3\u5c3a\u5bf8\u7684\u65b9\u6cd5\u3002 \u6709\u591a\u79cd\u65b9\u5f0f\u53ef\u4ee5\u6307\u5b9a\u8870\u51cf\u56e0\u5b50\u3002\u5176\u4e2d\u4e00\u79cd\u6d41\u884c\u7684\u65b9\u5f0f\u662f\u4f7f\u7528\u4e00\u4e2aspan\uff08\u8de8\u5ea6\uff09\uff0c\u8fd9\u4f7f\u5f97\u7ed3\u679c\u4e0e\u7a97\u53e3\u5927\u5c0f\u7b49\u4e8e\u8de8\u5ea6\u7684\u7b80\u5355\u79fb\u52a8\u7a97\u53e3\u51fd\u6570\u3002 \u7531\u4e8e\u6307\u6570\u52a0\u6743\u7edf\u8ba1\u503c\u7ed9\u66f4\u8fd1\u671f\u7684\u89c2\u6d4b\u503c\u4ee5\u66f4\u591a\u7684\u6743\u91cd\uff0c\u4e0e\u7b49\u6743\u91cd\u7684\u7248\u672c\u76f8\u6bd4\uff0c\u5b83\u5bf9\u53d8\u5316\u201c\u9002\u5e94\u201d\u5f97\u66f4\u5feb\u3002 pandas\u62e5\u6709`ewm`\u7b97\u5b50\uff0c\u540c`rolling`\u3001`expanding`\u7b97\u5b50\u4e00\u8d77\u4f7f\u7528\u3002 \u4ee5\u4e0b\u662f\u5c06\u82f9\u679c\u516c\u53f8\u80a1\u7968\u4ef7\u683c\u768460\u65e5\u5747\u7ebf\u4e0e`span=60`\u7684EW\u79fb\u52a8\u5e73\u5747\u7ebf\u8fdb\u884c\u6bd4\u8f83\u7684\u4f8b\u5b50\uff1a aapl_ex = close_px.AAPL['2006':'2007'] ma60 = aapl_ex.rolling(30, min_periods=20).mean() ewma60 = aapl_ex.ewm(span=30).mean() ma60.plot(style='k--', label='Simple MA') ewma60.plot(style='k-', label='EWMA') plt.legend() plt.show() ### \u4e8c\u5143\u79fb\u52a8\u7a97\u53e3\u51fd\u6570 \u4e00\u4e9b\u7edf\u8ba1\u7b97\u5b50\uff0c\u4f8b\u5982\u76f8\u5173\u5ea6\u548c\u534f\u65b9\u5dee\uff0c\u9700\u8981\u64cd\u4f5c\u4e24\u4e2a\u65f6\u95f4\u5e8f\u5217\u3002 \u4f8b\u5982\uff0c\u91d1\u878d\u5206\u6790\u5e08\u7ecf\u5e38\u5bf9\u80a1\u7968\u4e0e\u57fa\u51c6\u6307\u6570\uff08\u5982\u6807\u666e500\uff09\u7684\u5173\u8054\u6027\u611f\u5174\u8da3\u3002 \u6211\u4eec\u9996\u5148\u8ba1\u7b97\u6240\u6709\u6211\u4eec\u611f\u5174\u8da3\u7684\u65f6\u95f4\u5e8f\u5217\u7684\u767e\u5206\u6bd4\u53d8\u5316\uff1a spx_px = close_px_all['SPX'] spx_rets = spx_px.pct_change() returns = close_px.pct_change()","title":"[2292 rows x 3 columns]"},{"location":"python/DataAnalysis/ch08/#rollingcorrspx_rets","text":"corr = returns.AAPL.rolling(125, min_periods=100).corr(spx_rets) # \u82f9\u679c\u516c\u53f8\u4e0e\u6807\u666e500\u7684\u516d\u4e2a\u6708\u7684\u6536\u76ca\u76f8\u5173\u6027 corr.plot() plt.show() corr = returns.rolling(125, min_periods=100).corr(spx_rets) # \u591a\u53ea\u80a1\u7968\u4e0e\u6807\u666e500\u7684\u516d\u4e2a\u6708\u6536\u76ca\u76f8\u5173\u6027 corr.plot() plt.show() ### \u7528\u6237\u81ea\u5b9a\u4e49\u7684\u79fb\u52a8\u7a97\u53e3\u51fd\u6570 \u5728`rolling`\u53ca\u5176\u76f8\u5173\u65b9\u6cd5\u4e0a\u4f7f\u7528apply\u65b9\u6cd5\u63d0\u4f9b\u4e86\u4e00\u79cd\u5728\u79fb\u52a8\u7a97\u53e3\u4e2d\u5e94\u7528\u4f60\u81ea\u5df1\u8bbe\u8ba1\u7684\u6570\u7ec4\u51fd\u6570\u7684\u65b9\u6cd5\u3002 \u552f\u4e00\u7684\u8981\u6c42\u662f\u8be5\u51fd\u6570\u4ece\u6bcf\u4e2a\u6570\u7ec4\u4e2d\u4ea7\u751f\u4e00\u4e2a\u5355\u503c\uff08\u7f29\u805a\uff09\u3002 \u4f8b\u5982\uff0c\u5c3d\u7ba1\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528`rolling(...).quantile(q)`\u8ba1\u7b97\u6837\u672c\u7684\u5206\u4f4d\u6570\uff0c\u4f46\u6211\u4eec\u53ef\u80fd\u4f1a\u5bf9\u6837\u672c\u4e2d\u7279\u5b9a\u503c\u7684\u767e\u5206\u4f4d\u6570\u611f\u5174\u8da3\u3002 `scipy.stats.percentileofscore`\u51fd\u6570\u5c31\u662f\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\u7684\uff1a score_at_2percent = lambda x: percentileofscore(x, 0.02) result = returns.AAPL.rolling(250).apply(score_at_2percent) # \u4e00\u5e74\u7a97\u53e3\u4e0b\u82f9\u679c\u516c\u53f8\u80a1\u4ef72%\u6536\u76ca\u7684\u767e\u5206\u4f4d\u7b49\u7ea7 result.plot() plt.show() result = returns.rolling(250).apply(score_at_2percent) # \u4e00\u5e74\u7a97\u53e3\u4e0b\u6240\u6709\u516c\u53f8\u80a1\u4ef72%\u6536\u76ca\u7684\u767e\u5206\u4f4d\u7b49\u7ea7 result.plot() plt.show() ```","title":"\u5728\u8c03\u7528rolling\u540e\uff0ccorr\u805a\u5408\u51fd\u6570\u53ef\u4ee5\u6839\u636espx_rets\u8ba1\u7b97\u6eda\u52a8\u76f8\u5173\u6027\uff1a"},{"location":"python/DataAnalysis/ch09/","text":"\u9ad8\u9636pandas \u00b6 \u5206\u7c7b\u6570\u636e \u00b6 import numpy as np import pandas as pd \u80cc\u666f\u548c\u76ee\u6807 \u00b6 \u4e00\u4e2a\u5217\u7ecf\u5e38\u4f1a\u5305\u542b\u91cd\u590d\u503c\uff0c\u8fd9\u4e9b\u91cd\u590d\u503c\u662f\u4e00\u4e2a\u5c0f\u578b\u7684\u4e0d\u540c\u503c\u7684\u96c6\u5408\u3002 unique \u548c value_counts \u8fd9\u6837\u7684\u51fd\u6570\u5141\u8bb8\u6211\u4eec\u4ece\u4e00\u4e2a\u6570\u7ec4\u4e2d\u63d0\u53d6\u4e0d\u540c\u503c\u5e76\u5206\u522b\u8ba1\u7b97\u8fd9\u4e9b\u4e0d\u540c\u503c\u7684\u9891\u7387\uff1a values = pd.Series(['apple', 'orange', 'apple', 'apple'] * 2) print(values) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # dtype: object print(pd.unique(values)) # ['apple' 'orange'] print(pd.value_counts(values)) # apple 6 # orange 2 # dtype: int64 \u5728\u6570\u636e\u5165\u5e93\u7684\u64cd\u4f5c\u4e2d\uff0c\u4f7f\u7528\u7ef4\u5ea6\u8868\u662f\u4e00\u79cd\u6700\u4f73\u5b9e\u8df5\uff0c\u7ef4\u5ea6\u8868\u5305\u542b\u4e86\u4e0d\u540c\u503c\uff0c\u5e76\u5c06\u4e3b\u8981\u89c2\u6d4b\u503c\u5b58\u50a8\u4e3a\u5f15\u7528\u7ef4\u5ea6\u8868\u7684\u6574\u6570\u952e\uff1a values = pd.Series([0, 1, 0, 0] * 2) dim = pd.Series(['apple', 'oragne']) \u4f7f\u7528 take \u65b9\u6cd5\u6765\u6062\u590d\u539f\u6765\u7684\u5b57\u7b26\u4e32Series\u3002\uff080\u5bf9\u5e94\u5230apple)\u3002 \u8fd9\u79cd\u6309\u7167\u6574\u6570\u5c55\u73b0\u7684\u65b9\u5f0f\u88ab\u79f0\u4e3a\u5206\u7c7b\u6216\u5b57\u5178\u7f16\u7801\u5c55\u73b0\u3002\u4e0d\u540c\u503c\u7684\u6570\u7ec4\u53ef\u4ee5\u88ab\u79f0\u4e3a\u6570\u636e\u7684\u7c7b\u522b\u3001\u5b57\u5178\u6216\u5c42\u7ea7\u3002 print(dim.take(values)) # 0 apple # 1 oragne # 0 apple # 0 apple # 0 apple # 1 oragne # 0 apple # 0 apple # dtype: object \u5728\u505a\u6570\u636e\u5206\u6790\u65f6\uff0c\u5206\u7c7b\u5c55\u793a\u4f1a\u4ea7\u751f\u663e\u8457\u7684\u6027\u80fd\u63d0\u5347\u3002\u53ef\u4ee5\u5728\u7c7b\u522b\u4e0a\u8fdb\u884c\u8f6c\u6362\u540c\u65f6\u4e0d\u6539\u53d8\u4ee3\u7801\u3002 \u4ee5\u4e0b\u662f\u4e00\u4e9b\u76f8\u5bf9\u4f4e\u5f00\u9500\u7684\u8f6c\u6362\u793a\u4f8b\uff1a \u91cd\u547d\u540d\u7c7b\u522b \u5728\u4e0d\u6539\u53d8\u5df2\u6709\u7684\u7c7b\u522b\u987a\u5e8f\u7684\u60c5\u51b5\u4e0b\u6dfb\u52a0\u4e00\u4e2a\u65b0\u7684\u7c7b\u522b pandas\u4e2d\u7684Categorical\u7c7b\u578b \u00b6 pandas\u62e5\u6709\u7279\u6b8a\u7684 Categorical \u7c7b\u578b\uff0c\u7528\u4e8e\u627f\u8f7d\u57fa\u4e8e\u6574\u6570\u7684\u7c7b\u522b\u5c55\u793a\u6216\u7f16\u7801\u7684\u6570\u636e\u3002 fruits = ['apple', 'orange', 'apple', 'apple'] * 2 N = len(fruits) df = pd.DataFrame( { 'fruit': fruits, 'basket_id': np.arange(N), 'count': np.random.randint(3, 15, size=N), 'weight': np.random.uniform(0, 4, size=N) }, columns=['basket_id', 'fruit', 'count', 'weight'] ) print(df) # basket_id fruit count weight # 0 0 apple 8 1.288867 # 1 1 orange 4 3.414430 # 2 2 apple 7 3.222160 # 3 3 apple 14 2.724804 # 4 4 apple 8 3.548828 # 5 5 orange 10 0.918739 # 6 6 apple 4 0.784816 # 7 7 apple 10 3.140607 df['fruit'] \u662f\u4e00\u4e2aPython\u5b57\u7b26\u4e32\u5bf9\u8c61\u7ec4\u6210\u7684\u6570\u7ec4\u3002\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528\u51fd\u6570\u5c06\u5b83\u8f6c\u6362\u4e3a Categorical \u5bf9\u8c61\uff1a fruit_cat = df['fruit'].astype('category') print(fruit_cat) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # Name: fruit, dtype: category # Categories (2, object): ['apple', 'orange'] fruit_cat \u7684\u503c\u5e76\u4e0d\u662fNumPy\u6570\u7ec4\uff0c\u800c\u662f pandas.Categorical \u7684\u5b9e\u4f8b\uff1a c = fruit_cat.values print(type(c)) # print(c) # ['apple', 'orange', 'apple', 'apple', 'apple', 'orange', 'apple', 'apple'] # Categories (2, object): ['apple', 'orange'] Categorical \u5bf9\u8c61\u62e5\u6709 categories \u548c codes \u5c5e\u6027\uff1a print(c.categories) # Index(['apple', 'orange'], dtype='object') print(c.codes) # [0 1 0 0 0 1 0 0] \u901a\u8fc7\u5206\u914d\u5df2\u8f6c\u6362\u7684\u7ed3\u679c\u5c06DataFrame\u7684\u4e00\u5217\u8f6c\u6362\u4e3a Categorical \u5bf9\u8c61\uff1a print(df['fruit']) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # Name: fruit, dtype: object df['fruit'] = df['fruit'].astype('category') print(df['fruit']) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # Name: fruit, dtype: category # Categories (2, object): ['apple', 'orange'] \u4e5f\u53ef\u4ee5\u4ece\u5176\u4ed6Python\u5e8f\u5217\u7c7b\u578b\u76f4\u63a5\u751f\u6210 pandas.Categorical \uff1a my_categories = pd.Categorical(['foo', 'bar', 'baz', 'foo', 'bar']) print(my_categories) # ['foo', 'bar', 'baz', 'foo', 'bar'] # Categories (3, object): ['bar', 'baz', 'foo'] \u4e5f\u53ef\u4ee5\u4f7f\u7528 from_codes \u6784\u9020\u51fd\u6570\u6765\u8f6c\u6362\u5176\u4ed6\u6570\u636e\u6e90\u7684\u5206\u7c7b\u7f16\u7801\u6570\u636e\uff1a categories = ['foo', 'bar', 'baz'] codes = [0, 1, 2, 0, 0, 1] my_cats_2 = pd.Categorical.from_codes(codes, categories) print(my_cats_2) # ['foo', 'bar', 'baz', 'foo', 'foo', 'bar'] # Categories (3, object): ['foo', 'bar', 'baz'] \u8fd9\u4e2a\u672a\u6392\u5e8f\u7684\u5206\u7c7b\u5b9e\u4f8b\u53ef\u4ee5\u4f7f\u7528 as_ordered \u8fdb\u884c\u6392\u5e8f\uff1a print(my_cats_2.as_ordered()) # ['foo', 'bar', 'baz', 'foo', 'foo', 'bar'] # Categories (3, object): ['foo' < 'bar' < 'baz'] \u9664\u975e\u663e\u5f0f\u5730\u6307\u5b9a\uff0c\u5206\u7c7b\u8f6c\u6362\u662f\u4e0d\u4f1a\u6307\u5b9a\u7c7b\u522b\u7684\u987a\u5e8f\u7684\u3002\u56e0\u6b64 categories \u6570\u7ec4\u53ef\u80fd\u4f1a\u4e0e\u8f93\u5165\u6570\u636e\u7684\u987a\u5e8f\u4e0d\u540c\u3002 \u5f53\u4f7f\u7528 from_codes \u6216\u5176\u4ed6\u4efb\u610f\u6784\u9020\u51fd\u6570\u65f6\uff0c\u53ef\u4ee5\u4e3a\u7c7b\u522b\u6307\u5b9a\u4e00\u4e2a\u6709\u610f\u4e49\u7684\u987a\u5e8f\uff1a\u8f93\u51fa\u7684 [foo df.pipe(len) # \u4f20\u9012\u7684\u662flen\u5b9e\u4f8b # 4 def fun(df): return df * 2 fun(df) # 0 1 2 # 0 2.0 4.0 6.0 # 1 2.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 4.0 6.0 df.pipe(fun) # \u4f20\u9012\u7684\u662ffun\u51fd\u6570 # 0 1 2 # 0 2.0 4.0 6.0 # 1 2.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 4.0 6.0 def fun2(x, df): # \u6570\u636e\u662f\u7b2c\u4e8c\u4e2a\u53c2\u6570 return df * 3 df.pipe((fun2, 'df'), 2) # \u6ce8\u610f\u4f20\u503c # 0 1 2 # 0 3.0 6.0 9.0 # 1 3.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 6.0 9.0 Series \u793a\u4f8b\uff1a \u00b6 s = pd.Series([1, 2, 3, 4, 5]) s.pipe(type) # s.pipe(len) # 5 def fun3(x, ss): return ss * 3 s.pipe((fun3, 'ss'), 2) # 0 3 # 1 6 # 2 9 # 3 12 # 4 15 # dtype: int64 GroupBy \u793a\u4f8b\uff1a \u00b6 df = pd.DataFrame({'A': 'a b a b'.split(), 'B': [1, 2, 3, 4]}) print(df) # A B # 0 a 1 # 1 b 2 # 2 a 3 # 3 b 4 \u6c42\u6bcf\u7ec4\u6700\u5927\u503c\u548c\u6700\u5c0f\u503c\u4e4b\u95f4\u7684\u5dee\u5f02\u3002 df.groupby('A').pipe(lambda x: x.max() - x.min()) # B # A # a 2 # b 2 def mean1(groupby): return groupby.mean() df.groupby(['A']).pipe(mean1) # B # A # a 2.0 # b 3.0","title":"\u9ad8\u9636pandas"},{"location":"python/DataAnalysis/ch09/#pandas","text":"","title":"\u9ad8\u9636pandas"},{"location":"python/DataAnalysis/ch09/#_1","text":"import numpy as np import pandas as pd","title":"\u5206\u7c7b\u6570\u636e"},{"location":"python/DataAnalysis/ch09/#_2","text":"\u4e00\u4e2a\u5217\u7ecf\u5e38\u4f1a\u5305\u542b\u91cd\u590d\u503c\uff0c\u8fd9\u4e9b\u91cd\u590d\u503c\u662f\u4e00\u4e2a\u5c0f\u578b\u7684\u4e0d\u540c\u503c\u7684\u96c6\u5408\u3002 unique \u548c value_counts \u8fd9\u6837\u7684\u51fd\u6570\u5141\u8bb8\u6211\u4eec\u4ece\u4e00\u4e2a\u6570\u7ec4\u4e2d\u63d0\u53d6\u4e0d\u540c\u503c\u5e76\u5206\u522b\u8ba1\u7b97\u8fd9\u4e9b\u4e0d\u540c\u503c\u7684\u9891\u7387\uff1a values = pd.Series(['apple', 'orange', 'apple', 'apple'] * 2) print(values) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # dtype: object print(pd.unique(values)) # ['apple' 'orange'] print(pd.value_counts(values)) # apple 6 # orange 2 # dtype: int64 \u5728\u6570\u636e\u5165\u5e93\u7684\u64cd\u4f5c\u4e2d\uff0c\u4f7f\u7528\u7ef4\u5ea6\u8868\u662f\u4e00\u79cd\u6700\u4f73\u5b9e\u8df5\uff0c\u7ef4\u5ea6\u8868\u5305\u542b\u4e86\u4e0d\u540c\u503c\uff0c\u5e76\u5c06\u4e3b\u8981\u89c2\u6d4b\u503c\u5b58\u50a8\u4e3a\u5f15\u7528\u7ef4\u5ea6\u8868\u7684\u6574\u6570\u952e\uff1a values = pd.Series([0, 1, 0, 0] * 2) dim = pd.Series(['apple', 'oragne']) \u4f7f\u7528 take \u65b9\u6cd5\u6765\u6062\u590d\u539f\u6765\u7684\u5b57\u7b26\u4e32Series\u3002\uff080\u5bf9\u5e94\u5230apple)\u3002 \u8fd9\u79cd\u6309\u7167\u6574\u6570\u5c55\u73b0\u7684\u65b9\u5f0f\u88ab\u79f0\u4e3a\u5206\u7c7b\u6216\u5b57\u5178\u7f16\u7801\u5c55\u73b0\u3002\u4e0d\u540c\u503c\u7684\u6570\u7ec4\u53ef\u4ee5\u88ab\u79f0\u4e3a\u6570\u636e\u7684\u7c7b\u522b\u3001\u5b57\u5178\u6216\u5c42\u7ea7\u3002 print(dim.take(values)) # 0 apple # 1 oragne # 0 apple # 0 apple # 0 apple # 1 oragne # 0 apple # 0 apple # dtype: object \u5728\u505a\u6570\u636e\u5206\u6790\u65f6\uff0c\u5206\u7c7b\u5c55\u793a\u4f1a\u4ea7\u751f\u663e\u8457\u7684\u6027\u80fd\u63d0\u5347\u3002\u53ef\u4ee5\u5728\u7c7b\u522b\u4e0a\u8fdb\u884c\u8f6c\u6362\u540c\u65f6\u4e0d\u6539\u53d8\u4ee3\u7801\u3002 \u4ee5\u4e0b\u662f\u4e00\u4e9b\u76f8\u5bf9\u4f4e\u5f00\u9500\u7684\u8f6c\u6362\u793a\u4f8b\uff1a \u91cd\u547d\u540d\u7c7b\u522b \u5728\u4e0d\u6539\u53d8\u5df2\u6709\u7684\u7c7b\u522b\u987a\u5e8f\u7684\u60c5\u51b5\u4e0b\u6dfb\u52a0\u4e00\u4e2a\u65b0\u7684\u7c7b\u522b","title":"\u80cc\u666f\u548c\u76ee\u6807"},{"location":"python/DataAnalysis/ch09/#pandascategorical","text":"pandas\u62e5\u6709\u7279\u6b8a\u7684 Categorical \u7c7b\u578b\uff0c\u7528\u4e8e\u627f\u8f7d\u57fa\u4e8e\u6574\u6570\u7684\u7c7b\u522b\u5c55\u793a\u6216\u7f16\u7801\u7684\u6570\u636e\u3002 fruits = ['apple', 'orange', 'apple', 'apple'] * 2 N = len(fruits) df = pd.DataFrame( { 'fruit': fruits, 'basket_id': np.arange(N), 'count': np.random.randint(3, 15, size=N), 'weight': np.random.uniform(0, 4, size=N) }, columns=['basket_id', 'fruit', 'count', 'weight'] ) print(df) # basket_id fruit count weight # 0 0 apple 8 1.288867 # 1 1 orange 4 3.414430 # 2 2 apple 7 3.222160 # 3 3 apple 14 2.724804 # 4 4 apple 8 3.548828 # 5 5 orange 10 0.918739 # 6 6 apple 4 0.784816 # 7 7 apple 10 3.140607 df['fruit'] \u662f\u4e00\u4e2aPython\u5b57\u7b26\u4e32\u5bf9\u8c61\u7ec4\u6210\u7684\u6570\u7ec4\u3002\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528\u51fd\u6570\u5c06\u5b83\u8f6c\u6362\u4e3a Categorical \u5bf9\u8c61\uff1a fruit_cat = df['fruit'].astype('category') print(fruit_cat) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # Name: fruit, dtype: category # Categories (2, object): ['apple', 'orange'] fruit_cat \u7684\u503c\u5e76\u4e0d\u662fNumPy\u6570\u7ec4\uff0c\u800c\u662f pandas.Categorical \u7684\u5b9e\u4f8b\uff1a c = fruit_cat.values print(type(c)) # print(c) # ['apple', 'orange', 'apple', 'apple', 'apple', 'orange', 'apple', 'apple'] # Categories (2, object): ['apple', 'orange'] Categorical \u5bf9\u8c61\u62e5\u6709 categories \u548c codes \u5c5e\u6027\uff1a print(c.categories) # Index(['apple', 'orange'], dtype='object') print(c.codes) # [0 1 0 0 0 1 0 0] \u901a\u8fc7\u5206\u914d\u5df2\u8f6c\u6362\u7684\u7ed3\u679c\u5c06DataFrame\u7684\u4e00\u5217\u8f6c\u6362\u4e3a Categorical \u5bf9\u8c61\uff1a print(df['fruit']) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # Name: fruit, dtype: object df['fruit'] = df['fruit'].astype('category') print(df['fruit']) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # Name: fruit, dtype: category # Categories (2, object): ['apple', 'orange'] \u4e5f\u53ef\u4ee5\u4ece\u5176\u4ed6Python\u5e8f\u5217\u7c7b\u578b\u76f4\u63a5\u751f\u6210 pandas.Categorical \uff1a my_categories = pd.Categorical(['foo', 'bar', 'baz', 'foo', 'bar']) print(my_categories) # ['foo', 'bar', 'baz', 'foo', 'bar'] # Categories (3, object): ['bar', 'baz', 'foo'] \u4e5f\u53ef\u4ee5\u4f7f\u7528 from_codes \u6784\u9020\u51fd\u6570\u6765\u8f6c\u6362\u5176\u4ed6\u6570\u636e\u6e90\u7684\u5206\u7c7b\u7f16\u7801\u6570\u636e\uff1a categories = ['foo', 'bar', 'baz'] codes = [0, 1, 2, 0, 0, 1] my_cats_2 = pd.Categorical.from_codes(codes, categories) print(my_cats_2) # ['foo', 'bar', 'baz', 'foo', 'foo', 'bar'] # Categories (3, object): ['foo', 'bar', 'baz'] \u8fd9\u4e2a\u672a\u6392\u5e8f\u7684\u5206\u7c7b\u5b9e\u4f8b\u53ef\u4ee5\u4f7f\u7528 as_ordered \u8fdb\u884c\u6392\u5e8f\uff1a print(my_cats_2.as_ordered()) # ['foo', 'bar', 'baz', 'foo', 'foo', 'bar'] # Categories (3, object): ['foo' < 'bar' < 'baz'] \u9664\u975e\u663e\u5f0f\u5730\u6307\u5b9a\uff0c\u5206\u7c7b\u8f6c\u6362\u662f\u4e0d\u4f1a\u6307\u5b9a\u7c7b\u522b\u7684\u987a\u5e8f\u7684\u3002\u56e0\u6b64 categories \u6570\u7ec4\u53ef\u80fd\u4f1a\u4e0e\u8f93\u5165\u6570\u636e\u7684\u987a\u5e8f\u4e0d\u540c\u3002 \u5f53\u4f7f\u7528 from_codes \u6216\u5176\u4ed6\u4efb\u610f\u6784\u9020\u51fd\u6570\u65f6\uff0c\u53ef\u4ee5\u4e3a\u7c7b\u522b\u6307\u5b9a\u4e00\u4e2a\u6709\u610f\u4e49\u7684\u987a\u5e8f\uff1a\u8f93\u51fa\u7684 [foo df.pipe(len) # \u4f20\u9012\u7684\u662flen\u5b9e\u4f8b # 4 def fun(df): return df * 2 fun(df) # 0 1 2 # 0 2.0 4.0 6.0 # 1 2.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 4.0 6.0 df.pipe(fun) # \u4f20\u9012\u7684\u662ffun\u51fd\u6570 # 0 1 2 # 0 2.0 4.0 6.0 # 1 2.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 4.0 6.0 def fun2(x, df): # \u6570\u636e\u662f\u7b2c\u4e8c\u4e2a\u53c2\u6570 return df * 3 df.pipe((fun2, 'df'), 2) # \u6ce8\u610f\u4f20\u503c # 0 1 2 # 0 3.0 6.0 9.0 # 1 3.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 6.0 9.0","title":"DataFrame\u793a\u4f8b\uff1a"},{"location":"python/DataAnalysis/ch09/#series","text":"s = pd.Series([1, 2, 3, 4, 5]) s.pipe(type) # s.pipe(len) # 5 def fun3(x, ss): return ss * 3 s.pipe((fun3, 'ss'), 2) # 0 3 # 1 6 # 2 9 # 3 12 # 4 15 # dtype: int64","title":"Series \u793a\u4f8b\uff1a"},{"location":"python/DataAnalysis/ch09/#groupby_2","text":"df = pd.DataFrame({'A': 'a b a b'.split(), 'B': [1, 2, 3, 4]}) print(df) # A B # 0 a 1 # 1 b 2 # 2 a 3 # 3 b 4 \u6c42\u6bcf\u7ec4\u6700\u5927\u503c\u548c\u6700\u5c0f\u503c\u4e4b\u95f4\u7684\u5dee\u5f02\u3002 df.groupby('A').pipe(lambda x: x.max() - x.min()) # B # A # a 2 # b 2 def mean1(groupby): return groupby.mean() df.groupby(['A']).pipe(mean1) # B # A # a 2.0 # b 3.0","title":"GroupBy \u793a\u4f8b\uff1a"},{"location":"python/DataAnalysis/ch10/","text":"NumPy\u8fdb\u9636 \u00b6 \u5305\u542b\u4ee5\u4e0b\u5185\u5bb9\uff1a ndarray\u5bf9\u8c61\u7684\u5185\u90e8\u673a\u7406 \u9ad8\u7ea7\u6570\u7ec4\u64cd\u4f5c \u91cd\u5851\u6570\u7ec4 C\u987a\u5e8f\u548cF\u987a\u5e8f \u8fde\u63a5\u548c\u5206\u9694\u6570\u7ec4 \u5806\u53e0\u52a9\u624b\uff1ar \u548cc \u91cd\u590d\u5143\u7d20\uff1atile\u548crepeat \u795e\u5947\u7d22\u5f15\u7684\u7b49\u4ef7\u65b9\u6cd5\uff1atake\u548cput \u5e7f\u64ad ufunc\u9ad8\u7ea7\u5e94\u7528 \u7ed3\u6784\u5316\u548c\u8bb0\u5f55\u5f0f\u6570\u7ec4 ndarray\u5bf9\u8c61\u7684\u5185\u90e8\u673a\u7406 \u00b6 NumPy\u7684 ndarray \u63d0\u4f9b\u4e86\u4e00\u79cd\u5c06\u540c\u8d28\u6570\u636e\u5757\uff08\u53ef\u4ee5\u662f\u8fde\u7eed\u6216\u8de8\u8d8a\uff09\u89e3\u91ca\u4e3a\u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61\u7684\u65b9\u5f0f\u3002 ndarray \u7684\u6570\u636e\u7c7b\u578b dtype \u51b3\u5b9a\u4e86\u6570\u636e\u7684\u89e3\u91ca\u65b9\u5f0f\uff0c\u6bd4\u5982\u6d6e\u70b9\u6570\u3001\u6574\u6570\u3001\u5e03\u5c14\u503c\u7b49\u3002 ndarray \u7684\u6240\u6709\u6570\u7ec4\u5bf9\u8c61\u90fd\u662f\u6570\u636e\u5757\u7684\u4e00\u4e2a\u8de8\u5ea6\u89c6\u56fe\uff08strided view\uff09\u3002 \u6570\u7ec4\u89c6\u56fe arr[::2,::-1] \u4e0d\u590d\u5236\u4efb\u4f55\u6570\u636e\u7684\u539f\u56e0\u662f\u4ec0\u4e48\uff1f \u7b80\u5355\u5730\u8bf4\uff0c ndarray \u4e0d\u53ea\u662f\u4e00\u5757\u5185\u5b58\u548c\u4e00\u4e2a dtype \uff0c\u5b83\u8fd8\u6709\u8de8\u5ea6\u4fe1\u606f\uff0c\u8fd9\u4f7f\u5f97\u6570\u7ec4\u80fd\u4ee5\u5404\u79cd\u6b65\u5e45\uff08step size\uff09\u5728\u5185\u5b58\u4e2d\u79fb\u52a8\u3002 \u66f4\u51c6\u786e\u5730\u8bb2\uff0c ndarray \u5185\u90e8\u7531\u4ee5\u4e0b\u5185\u5bb9\u7ec4\u6210\uff1a \u4e00\u4e2a\u6307\u5411\u6570\u636e\uff08\u5185\u5b58\u6216\u5185\u5b58\u6620\u5c04\u6587\u4ef6\u4e2d\u7684\u4e00\u5757\u6570\u636e\uff09\u7684\u6307\u9488\u3002 \u6570\u636e\u7c7b\u578b\u6216 dtype \uff0c\u63cf\u8ff0\u5728\u6570\u7ec4\u4e2d\u7684\u56fa\u5b9a\u5927\u5c0f\u503c\u7684\u683c\u5b50\u3002 \u4e00\u4e2a\u8868\u793a\u6570\u7ec4\u5f62\u72b6\uff08shape\uff09\u7684\u5143\u7ec4\u3002 \u4e00\u4e2a\u8de8\u5ea6\u5143\u7ec4\uff08stride\uff09\uff0c\u5176\u4e2d\u7684\u6574\u6570\u6307\u7684\u662f\u4e3a\u4e86\u524d\u8fdb\u5230\u5f53\u524d\u7ef4\u5ea6\u4e0b\u4e00\u4e2a\u5143\u7d20\u9700\u8981\u201c\u8de8\u8fc7\u201d\u7684\u5b57\u8282\u6570\u3002 \u4f8b\u5982\uff0c\u4e00\u4e2a10\u00d75\u7684\u6570\u7ec4\uff0c\u5176shape\u4e3a(10, 5)\uff1a s = np.ones((10, 5)).shape print(s) # (10, 5) \u4e00\u4e2a\u5178\u578b\u7684\uff08C\u9636\uff093\u00d74\u00d75 float64\u503c\uff088\u5b57\u8282\uff09\u7684\u6570\u7ec4\u5177\u6709\u8de8\u5ea6\uff08160,40,8\uff09\uff08\u901a\u5e38\u7279\u5b9a\u8f74\u4e0a\u7684\u8de8\u5ea6\u8d8a\u5927\uff0c\u6cbf\u7740\u8be5\u8f74\u6267\u884c\u8ba1\u7b97\u7684\u4ee3\u4ef7\u8d8a\u9ad8\uff09\uff1a s = np.ones((3, 4, 5), dtype=np.float64).strides print(s) # (160, 40, 8) \u6570\u7ec4\u8de8\u5ea6\uff08strides\uff09\u662f\u6784\u5efa\u201c\u96f6\u590d\u5236\u201d\u6570\u7ec4\u89c6\u56fe\u7684\u5173\u952e\u56e0\u7d20\u3002 \u6570\u7ec4\u8de8\u5ea6\u751a\u81f3\u53ef\u4ee5\u662f\u8d1f\u7684\uff0c\u8fd9\u4f7f\u5f97\u6570\u7ec4\u80fd\u591f\u7a7f\u8fc7\u5185\u5b58\u201c\u5411\u540e\u201d\u79fb\u52a8\uff08\u4f8b\u5982\uff0c\u5728\u8bf8\u5982obj[::-1]\u6216obj[:, ::-1]\u7684\u5207\u7247\u4e2d\u5c31\u662f\u8fd9\u79cd\u60c5\u51b5\uff09\u3002 NumPy dtype\u5c42\u6b21\u7ed3\u6784 \u00b6 \u6709\u65f6\u5019\u9700\u8981\u901a\u8fc7\u4e00\u4e9b\u4ee3\u7801\u6765\u68c0\u67e5\u6570\u7ec4\u662f\u5426\u5305\u542b\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u5b57\u7b26\u4e32\u6216Python\u5bf9\u8c61\u3002 \u7531\u4e8e\u6d6e\u70b9\u6570\u6709\u591a\u79cd\u7c7b\u578b\uff08float16\u5230float128\uff09\uff0c\u56e0\u6b64\u68c0\u67e5dtype\u662f\u5426\u5728\u7c7b\u578b\u5217\u8868\u4e2d\u4f1a\u975e\u5e38\u9ebb\u70e6\u3002 dtype\u6709\u8d85\u7c7b\uff0c\u5982np.integer\u548cnp.floating\uff0c\u5b83\u4eec\u53ef\u4ee5\u548cnp.issubdtype\u51fd\u6570\u4e00\u8d77\u4f7f\u7528\uff1a ints = np.ones(10, dtype=np.uint16) floats = np.ones(10, dtype=np.float32) \u53ef\u4ee5\u901a\u8fc7\u8c03\u7528\u7c7b\u578b\u7684mro\u65b9\u6cd5\u6765\u67e5\u770b\u7279\u5b9adtype\u7684\u6240\u6709\u7236\u7c7b\uff1a print(np.float64.mro()) # [, # , # , # , # , # , # ] print(np.issubdtype(ints.dtype, np.integer)) # True print(np.issubdtype(floats.dtype, np.floating)) # True print(np.issubdtype(floats.dtype, np.number)) # True print(np.issubdtype(floats.dtype, np.generic)) # True \u9ad8\u7ea7\u6570\u7ec4\u64cd\u4f5c \u00b6 \u91cd\u5851\u6570\u7ec4 \u00b6 \u901a\u5e38\uff0c\u901a\u8fc7 reshape \u5c06\u6570\u7ec4\u4ece\u4e00\u4e2a\u5f62\u72b6\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u5f62\u72b6\uff0c\u5e76\u4e14\u4e0d\u590d\u5236\u4efb\u4f55\u6570\u636e\u3002 reshape \u91cc\u9762\u6709\u4e24\u79cd\u91cd\u5851\u987a\u5e8f\uff0c\u6309C\u987a\u5e8f\uff08\u884c\u65b9\u5411\uff09\u7684\u91cd\u5851\u548c\u6309Fortran\u987a\u5e8f\uff08\u5217\u65b9\u5411\uff09\u7684\u91cd\u5851\u3002 \u9996\u5148\u662f\u53d6\u6570\uff0c\u7136\u540e\u662f\u653e\u6570\uff0c\u53d6\u6570\u6309\u4ec0\u4e48\u987a\u5e8f\uff0c\u653e\u6570\u5c31\u6309\u4ec0\u4e48\u987a\u5e8f\u3002 \u4e0b\u9762\u662f\u5b98\u7f51\u7684\u89e3\u91ca\uff1a \u2018C\u2019 means to read / write the elements using C-like index order, with the last axis index changing fastest, back to the first axis index changing slowest. \u2018F\u2019 means to read / write the elements using Fortran-like index order, with the first index changing fastest, and the last index changing slowest. Note that the \u2018C\u2019 and \u2018F\u2019 options take no account of the memory layout of the underlying array, and only refer to the order of indexing. \u2018A\u2019 means to read / write the elements in Fortran-like index order if a is Fortran contiguous in memory, C-like order otherwise. \u4e00\u7ef4\u6570\u7ec4\u91cd\u5851\uff1a arr = np.arange(8) print(arr) # [0 1 2 3 4 5 6 7] a = arr.reshape((4, 2), order='C') print(a) # [[0 1] # [2 3] # [4 5] # [6 7]] a = arr.reshape((4, 2), order='F') print(a) # [[0 4] # [1 5] # [2 6] # [3 7]] \u591a\u7ef4\u6570\u7ec4\u91cd\u5851\uff1a\u4f20\u9012\u7684\u5f62\u72b6\u7ef4\u5ea6\u53ef\u4ee5\u6709\u4e00\u4e2a\u503c\u662f-1\uff0c\u8868\u793a\u7ef4\u5ea6\u901a\u8fc7\u6570\u636e\u8fdb\u884c\u63a8\u65ad\uff1a a = arr.reshape((4, 2)).reshape((2, 4)) print(a) # [[0 1 2 3] # [4 5 6 7]] arr = np.arange(15) a = arr.reshape((5, -1)) # 15 / 5 = 3\u5217 print(a) # [[ 0 1 2] # [ 3 4 5] # [ 6 7 8] # [ 9 10 11] # [12 13 14]] print(a.shape) # (5, 3) \u6570\u7ec4\u7684 shape \u5c5e\u6027\u662f\u4e00\u4e2a**\u5143\u7ec4**\uff0c\u5b83\u4e5f\u53ef\u4ee5\u88ab\u4f20\u9012\u7ed9 reshape \uff0c\u63a5\u4e0a\u4f8b\uff1a other_arr = np.ones((3, 5)) print(other_arr.shape) # (3, 5) a = arr.reshape(other_arr.shape) print(a.shape) # (3, 5) reshape \u7684\u53cd\u64cd\u4f5c\u53ef\u4ee5\u5c06\u66f4\u9ad8\u7ef4\u5ea6\u7684\u6570\u7ec4\u8f6c\u6362\u4e3a\u4e00\u7ef4\u6570\u7ec4\uff0c\u8fd9\u79cd\u64cd\u4f5c\u901a\u5e38\u88ab\u6210\u4e3a\u6241\u5e73\u5316\uff08flattening\uff09\u6216\u5206\u6563\u5316\uff08raveling\uff09\u3002 \u5982\u679c\u7ed3\u679c\u4e2d\u7684\u503c\u5728\u539f\u59cb\u6570\u7ec4\u4e2d\u662f\u8fde\u7eed\u7684\uff0c\u5219 ravel \u4e0d\u4f1a\u751f\u6210\u5e95\u5c42\u6570\u503c\u7684\u526f\u672c\u3002 flatten \u65b9\u6cd5\u7684\u884c\u4e3a\u7c7b\u4f3c\u4e8e ravel \uff0c\u4f46\u5b83\u603b\u662f\u751f\u6210\u6570\u636e\u7684\u526f\u672c\u3002 arr = np.arange(15).reshape((5, 3)) print(arr) # [[ 0 1 2] # [ 3 4 5] # [ 6 7 8] # [ 9 10 11] # [12 13 14]] a = arr.ravel() print(a) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] a = arr.flatten() print(a) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] C\u987a\u5e8f\u548cF\u987a\u5e8f \u00b6 \u6570\u636e\u53ef\u4ee5\u6309\u7167\u4e0d\u540c\u7684\u987a\u5e8f\u8fdb\u884c\u91cd\u5851\u6216\u6241\u5e73\u5316\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cNumPy\u6570\u7ec4\u662f\u6309\u884c\u65b9\u5411\u987a\u5e8f\u521b\u5efa\u7684\u3002 \u5bf9\u4e8e\u4e00\u4e2a\u4e8c\u7ef4\u7684\u6570\u636e\u6570\u7ec4\uff0c**C\u987a\u5e8f**\u8bf4\u660e\u6570\u7ec4\u6bcf\u884c\u4e2d\u7684\u5143\u7d20\u5b58\u50a8\u5728\u76f8\u90bb\u7684\u5b58\u50a8\u5355\u5143\u4e2d\u3002**F\u987a\u5e8f**\u610f\u5473\u7740\u6bcf\u5217\u6570\u636e\u4e2d\u7684\u503c\u90fd\u5b58\u50a8\u5728\u76f8\u90bb\u7684\u5185\u5b58\u4f4d\u7f6e\u4e2d\u3002 \u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e reshape \u548c ravel \u51fd\u6570\u7684 order \u53c2\u6570\u6765\u8868\u793a\u6570\u636e\u5728\u6570\u7ec4\u4e2d\u4f7f\u7528\u54ea\u79cd\u987a\u5e8f\u3002 arr = np.arange(15).reshape((5, 3)) print(arr) # [[ 0 1 2] # [ 3 4 5] # [ 6 7 8] # [ 9 10 11] # [12 13 14]] print(arr.ravel()) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] print(arr.ravel('F')) # [ 0 3 6 9 12 1 4 7 10 13 2 5 8 11 14] C\u987a\u5e8f\u548cFortran\u987a\u5e8f\u7684\u6838\u5fc3\u533a\u522b\u5c31\u662f\u5728\u7ef4\u5ea6\u65b9\u5411\u4e0a\u904d\u5386\u7684\u65b9\u5f0f\u3002 C\u987a\u5e8f/\u884c\u65b9\u5411\u987a\u5e8f\u9996\u5148\u904d\u5386\u66f4\u9ad8\u7684\u7ef4\u5ea6\uff08\u4f8b\u5982\uff0c\u5728\u8f740\u4e0a\u884c\u8fdb\u4e4b\u524d\u5148\u5728\u8f741\u4e0a\u884c\u8fdb\uff09\u3002 Fortran\u987a\u5e8f/\u5217\u65b9\u5411\u987a\u5e8f\u6700\u540e\u904d\u5386\u66f4\u9ad8\u7684\u7ef4\u5ea6\uff08\u4f8b\u5982\uff0c\u5728\u8f741\u4e0a\u884c\u8fdb\u4e4b\u524d\u5148\u5728\u8f740\u4e0a\u884c\u8fdb\uff09\u3002 \u6570\u7ec4\u8fde\u63a5\u548c\u5206\u9694 \u00b6 numpy.concatenate \u53ef\u4ee5\u83b7\u53d6\u6570\u7ec4\u7684\u5e8f\u5217\uff08\u5143\u7ec4\u3001\u5217\u8868\u7b49\uff09\uff0c\u5e76\u6cbf\u7740\u8f93\u5165\u8f74\u5c06\u5b83\u4eec\u6309\u987a\u5e8f\u8fde\u63a5\u5728\u4e00\u8d77\uff1a arr1 = np.array( [ [1, 2, 3], [4, 5, 6] ] ) arr2 = np.array( [ [7, 8, 9], [10, 11, 12] ] ) a = np.concatenate([arr1, arr2], axis=0) print(a) # [[ 1 2 3] # [ 4 5 6] # [ 7 8 9] # [10 11 12]] a = np.concatenate([arr1, arr2], axis=1) print(a) # [[ 1 2 3 7 8 9] # [ 4 5 6 10 11 12]] \u5176\u4ed6\u7c7b\u4f3c concatenate \u7684\u51fd\u6570\u3002 vstack \u7c7b\u4f3c concatenate \u6cbf axis=0 \u64cd\u4f5c\uff0c hstack \u7c7b\u4f3c concatenate \u6cbf axis=1 \u64cd\u4f5c\u3002 a = np.vstack((arr1, arr2)) print(a) # [[ 1 2 3] # [ 4 5 6] # [ 7 8 9] # [10 11 12]] a = np.hstack((arr1, arr2)) print(a) # [[ 1 2 3 7 8 9] # [ 4 5 6 10 11 12]] split \u53ef\u4ee5\u5c06\u4e00\u4e2a\u6570\u7ec4\u6cbf\u8f74\u5411\u5207\u7247\u6210\u591a\u4e2a\u6570\u7ec4\u3002\u5148\u770b\u4e00\u7ef4\u6570\u7ec4\u3002 np.split(arr, 3) \u8868\u793a\u5c06\u6570\u7ec4\u62c6\u5206\u65f6\u7684**\u7d22\u5f15\u4f4d\u7f6e** arr = np.array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']) print(arr) # ['a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k'] print(np.split(arr, 3)) print(np.split(arr, [3])) # \u4ece\u7d22\u5f15\u4f4d\u7f6e\u4e3a3\u8fdb\u884c\u62c6\u5206 # [array(['a', 'b', 'c'], dtype=', # , # , # , # , # , # ] print(np.issubdtype(ints.dtype, np.integer)) # True print(np.issubdtype(floats.dtype, np.floating)) # True print(np.issubdtype(floats.dtype, np.number)) # True print(np.issubdtype(floats.dtype, np.generic)) # True","title":"NumPy dtype\u5c42\u6b21\u7ed3\u6784"},{"location":"python/DataAnalysis/ch10/#_1","text":"","title":"\u9ad8\u7ea7\u6570\u7ec4\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch10/#_2","text":"\u901a\u5e38\uff0c\u901a\u8fc7 reshape \u5c06\u6570\u7ec4\u4ece\u4e00\u4e2a\u5f62\u72b6\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u5f62\u72b6\uff0c\u5e76\u4e14\u4e0d\u590d\u5236\u4efb\u4f55\u6570\u636e\u3002 reshape \u91cc\u9762\u6709\u4e24\u79cd\u91cd\u5851\u987a\u5e8f\uff0c\u6309C\u987a\u5e8f\uff08\u884c\u65b9\u5411\uff09\u7684\u91cd\u5851\u548c\u6309Fortran\u987a\u5e8f\uff08\u5217\u65b9\u5411\uff09\u7684\u91cd\u5851\u3002 \u9996\u5148\u662f\u53d6\u6570\uff0c\u7136\u540e\u662f\u653e\u6570\uff0c\u53d6\u6570\u6309\u4ec0\u4e48\u987a\u5e8f\uff0c\u653e\u6570\u5c31\u6309\u4ec0\u4e48\u987a\u5e8f\u3002 \u4e0b\u9762\u662f\u5b98\u7f51\u7684\u89e3\u91ca\uff1a \u2018C\u2019 means to read / write the elements using C-like index order, with the last axis index changing fastest, back to the first axis index changing slowest. \u2018F\u2019 means to read / write the elements using Fortran-like index order, with the first index changing fastest, and the last index changing slowest. Note that the \u2018C\u2019 and \u2018F\u2019 options take no account of the memory layout of the underlying array, and only refer to the order of indexing. \u2018A\u2019 means to read / write the elements in Fortran-like index order if a is Fortran contiguous in memory, C-like order otherwise. \u4e00\u7ef4\u6570\u7ec4\u91cd\u5851\uff1a arr = np.arange(8) print(arr) # [0 1 2 3 4 5 6 7] a = arr.reshape((4, 2), order='C') print(a) # [[0 1] # [2 3] # [4 5] # [6 7]] a = arr.reshape((4, 2), order='F') print(a) # [[0 4] # [1 5] # [2 6] # [3 7]] \u591a\u7ef4\u6570\u7ec4\u91cd\u5851\uff1a\u4f20\u9012\u7684\u5f62\u72b6\u7ef4\u5ea6\u53ef\u4ee5\u6709\u4e00\u4e2a\u503c\u662f-1\uff0c\u8868\u793a\u7ef4\u5ea6\u901a\u8fc7\u6570\u636e\u8fdb\u884c\u63a8\u65ad\uff1a a = arr.reshape((4, 2)).reshape((2, 4)) print(a) # [[0 1 2 3] # [4 5 6 7]] arr = np.arange(15) a = arr.reshape((5, -1)) # 15 / 5 = 3\u5217 print(a) # [[ 0 1 2] # [ 3 4 5] # [ 6 7 8] # [ 9 10 11] # [12 13 14]] print(a.shape) # (5, 3) \u6570\u7ec4\u7684 shape \u5c5e\u6027\u662f\u4e00\u4e2a**\u5143\u7ec4**\uff0c\u5b83\u4e5f\u53ef\u4ee5\u88ab\u4f20\u9012\u7ed9 reshape \uff0c\u63a5\u4e0a\u4f8b\uff1a other_arr = np.ones((3, 5)) print(other_arr.shape) # (3, 5) a = arr.reshape(other_arr.shape) print(a.shape) # (3, 5) reshape \u7684\u53cd\u64cd\u4f5c\u53ef\u4ee5\u5c06\u66f4\u9ad8\u7ef4\u5ea6\u7684\u6570\u7ec4\u8f6c\u6362\u4e3a\u4e00\u7ef4\u6570\u7ec4\uff0c\u8fd9\u79cd\u64cd\u4f5c\u901a\u5e38\u88ab\u6210\u4e3a\u6241\u5e73\u5316\uff08flattening\uff09\u6216\u5206\u6563\u5316\uff08raveling\uff09\u3002 \u5982\u679c\u7ed3\u679c\u4e2d\u7684\u503c\u5728\u539f\u59cb\u6570\u7ec4\u4e2d\u662f\u8fde\u7eed\u7684\uff0c\u5219 ravel \u4e0d\u4f1a\u751f\u6210\u5e95\u5c42\u6570\u503c\u7684\u526f\u672c\u3002 flatten \u65b9\u6cd5\u7684\u884c\u4e3a\u7c7b\u4f3c\u4e8e ravel \uff0c\u4f46\u5b83\u603b\u662f\u751f\u6210\u6570\u636e\u7684\u526f\u672c\u3002 arr = np.arange(15).reshape((5, 3)) print(arr) # [[ 0 1 2] # [ 3 4 5] # [ 6 7 8] # [ 9 10 11] # [12 13 14]] a = arr.ravel() print(a) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] a = arr.flatten() print(a) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]","title":"\u91cd\u5851\u6570\u7ec4"},{"location":"python/DataAnalysis/ch10/#cf","text":"\u6570\u636e\u53ef\u4ee5\u6309\u7167\u4e0d\u540c\u7684\u987a\u5e8f\u8fdb\u884c\u91cd\u5851\u6216\u6241\u5e73\u5316\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cNumPy\u6570\u7ec4\u662f\u6309\u884c\u65b9\u5411\u987a\u5e8f\u521b\u5efa\u7684\u3002 \u5bf9\u4e8e\u4e00\u4e2a\u4e8c\u7ef4\u7684\u6570\u636e\u6570\u7ec4\uff0c**C\u987a\u5e8f**\u8bf4\u660e\u6570\u7ec4\u6bcf\u884c\u4e2d\u7684\u5143\u7d20\u5b58\u50a8\u5728\u76f8\u90bb\u7684\u5b58\u50a8\u5355\u5143\u4e2d\u3002**F\u987a\u5e8f**\u610f\u5473\u7740\u6bcf\u5217\u6570\u636e\u4e2d\u7684\u503c\u90fd\u5b58\u50a8\u5728\u76f8\u90bb\u7684\u5185\u5b58\u4f4d\u7f6e\u4e2d\u3002 \u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e reshape \u548c ravel \u51fd\u6570\u7684 order \u53c2\u6570\u6765\u8868\u793a\u6570\u636e\u5728\u6570\u7ec4\u4e2d\u4f7f\u7528\u54ea\u79cd\u987a\u5e8f\u3002 arr = np.arange(15).reshape((5, 3)) print(arr) # [[ 0 1 2] # [ 3 4 5] # [ 6 7 8] # [ 9 10 11] # [12 13 14]] print(arr.ravel()) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] print(arr.ravel('F')) # [ 0 3 6 9 12 1 4 7 10 13 2 5 8 11 14] C\u987a\u5e8f\u548cFortran\u987a\u5e8f\u7684\u6838\u5fc3\u533a\u522b\u5c31\u662f\u5728\u7ef4\u5ea6\u65b9\u5411\u4e0a\u904d\u5386\u7684\u65b9\u5f0f\u3002 C\u987a\u5e8f/\u884c\u65b9\u5411\u987a\u5e8f\u9996\u5148\u904d\u5386\u66f4\u9ad8\u7684\u7ef4\u5ea6\uff08\u4f8b\u5982\uff0c\u5728\u8f740\u4e0a\u884c\u8fdb\u4e4b\u524d\u5148\u5728\u8f741\u4e0a\u884c\u8fdb\uff09\u3002 Fortran\u987a\u5e8f/\u5217\u65b9\u5411\u987a\u5e8f\u6700\u540e\u904d\u5386\u66f4\u9ad8\u7684\u7ef4\u5ea6\uff08\u4f8b\u5982\uff0c\u5728\u8f741\u4e0a\u884c\u8fdb\u4e4b\u524d\u5148\u5728\u8f740\u4e0a\u884c\u8fdb\uff09\u3002","title":"C\u987a\u5e8f\u548cF\u987a\u5e8f"},{"location":"python/DataAnalysis/ch10/#_3","text":"numpy.concatenate \u53ef\u4ee5\u83b7\u53d6\u6570\u7ec4\u7684\u5e8f\u5217\uff08\u5143\u7ec4\u3001\u5217\u8868\u7b49\uff09\uff0c\u5e76\u6cbf\u7740\u8f93\u5165\u8f74\u5c06\u5b83\u4eec\u6309\u987a\u5e8f\u8fde\u63a5\u5728\u4e00\u8d77\uff1a arr1 = np.array( [ [1, 2, 3], [4, 5, 6] ] ) arr2 = np.array( [ [7, 8, 9], [10, 11, 12] ] ) a = np.concatenate([arr1, arr2], axis=0) print(a) # [[ 1 2 3] # [ 4 5 6] # [ 7 8 9] # [10 11 12]] a = np.concatenate([arr1, arr2], axis=1) print(a) # [[ 1 2 3 7 8 9] # [ 4 5 6 10 11 12]] \u5176\u4ed6\u7c7b\u4f3c concatenate \u7684\u51fd\u6570\u3002 vstack \u7c7b\u4f3c concatenate \u6cbf axis=0 \u64cd\u4f5c\uff0c hstack \u7c7b\u4f3c concatenate \u6cbf axis=1 \u64cd\u4f5c\u3002 a = np.vstack((arr1, arr2)) print(a) # [[ 1 2 3] # [ 4 5 6] # [ 7 8 9] # [10 11 12]] a = np.hstack((arr1, arr2)) print(a) # [[ 1 2 3 7 8 9] # [ 4 5 6 10 11 12]] split \u53ef\u4ee5\u5c06\u4e00\u4e2a\u6570\u7ec4\u6cbf\u8f74\u5411\u5207\u7247\u6210\u591a\u4e2a\u6570\u7ec4\u3002\u5148\u770b\u4e00\u7ef4\u6570\u7ec4\u3002 np.split(arr, 3) \u8868\u793a\u5c06\u6570\u7ec4\u62c6\u5206\u65f6\u7684**\u7d22\u5f15\u4f4d\u7f6e** arr = np.array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']) print(arr) # ['a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k'] print(np.split(arr, 3)) print(np.split(arr, [3])) # \u4ece\u7d22\u5f15\u4f4d\u7f6e\u4e3a3\u8fdb\u884c\u62c6\u5206 # [array(['a', 'b', 'c'], dtype='|t| [0.025 0.975] # ------------------------------------------------------------------------------ # x1 0.1783 0.053 3.364 0.001 0.073 0.283 # x2 0.2230 0.046 4.818 0.000 0.131 0.315 # x3 0.5010 0.080 6.237 0.000 0.342 0.660 # ============================================================================== # Omnibus: 4.662 Durbin-Watson: 0 -0.002327 # Prob(Omnibus): 0.097 Jarque-Bera (JB): 4.098 # Skew: 0.481 Prob(JB): 0.129 # Kurtosis: 3.243 Cond. No. 1.74 # ============================================================================== # # Notes: # [1] R\u00b2 is computed without centering (uncentered) since the model does not contain a constant. # [2] Standard Errors assume that the covariance matrix of the errors is correctly specified. \u5047\u8bbe\u6240\u6709\u6a21\u578b\u53c2\u6570\u90fd\u5728DataFrame\u4e2d\uff1a data = pd.DataFrame(X, columns=['col0', 'col1', 'col2']) data['y'] = y print(data[:5]) # col0 col1 col2 y # 0 -0.129468 -1.212753 0.504225 0.427863 # 1 0.302910 -0.435742 -0.254180 -0.673480 # 2 -0.328522 -0.025302 0.138351 -0.090878 # 3 -0.351475 -0.719605 -0.258215 -0.489494 # 4 1.243269 -0.373799 -0.522629 -0.128941 \u73b0\u5728\u53ef\u4ee5\u4f7f\u7528 statsmodels \u516c\u5f0fAPI\u548cPatsy\u516c\u5f0f\u5b57\u7b26\u4e32\u3002\u89c2\u5bdf statsmodels \u5982\u4f55\u5c06\u7ed3\u679c\u4f5c\u4e3a\u5e26\u6709DataFrame\u5217\u540d\u79f0\u7684Series\u8fd4\u56de\u3002 results = smf.ols('y ~ col0 + col1 + col2', data=data).fit() print(results.params) # Intercept 0.033559 # col0 0.176149 # col1 0.224826 # col2 0.514808 # dtype: float64 \u7ed9\u5b9a\u65b0\u7684\u6837\u672c\u5916\u6570\u636e\u540e\uff0c\u53ef\u4ee5\u6839\u636e\u4f30\u8ba1\u7684\u6a21\u578b\u53c2\u6570\u8ba1\u7b97\u9884\u6d4b\u503c\uff1a print(results.predict(data[:5])) # 0 -0.002327 # 1 -0.141904 # 2 0.041226 # 3 -0.323070 # 4 -0.100535 # dtype: float64 \u8bc4\u4f30\u65f6\u95f4\u5e8f\u5217\u5904\u7406 \u00b6 statsmodels\u4e2d\u7684\u53e6\u4e00\u7c7b\u6a21\u578b\u7528\u4e8e\u65f6\u95f4\u5e8f\u5217\u5206\u6790\u3002\u5176\u4e2d\u5305\u62ec\u81ea\u56de\u5f52\u8fc7\u7a0b\uff0c\u5361\u5c14\u66fc\u6ee4\u6ce2\u548c\u5176\u4ed6\u72b6\u6001\u7a7a\u95f4\u6a21\u578b\uff0c\u4ee5\u53ca\u591a\u53d8\u91cf\u81ea\u56de\u5f52\u6a21\u578b\u3002 \u4e0b\u4f8b\u6a21\u62df\u4e00\u4e9b\u5177\u6709\u81ea\u56de\u5f52\u7ed3\u6784\u548c\u566a\u58f0\u7684\u65f6\u95f4\u5e8f\u5217\u6570\u636e\uff0c\u8be5\u6570\u636e\u5177\u6709\u53c2\u6570\u4e3a0.8\u548c-0.4\u7684AR\uff082\uff09\u7ed3\u6784\uff08\u4e24\u4e2a\u6ede\u540e\uff09\u3002 init_x = 4 values = [init_x, init_x] N = 1000 b0 = 0.8 b1 = -0.4 noise = dnorm(0, 0.1, N) for i in range(N): new_x = values[-1] * b0 + values[-2] * b1 + noise[i] values.append(new_x) \u5f53\u62df\u5408\u4e00\u4e2aAR\u6a21\u578b\u65f6\uff0c\u4f60\u53ef\u80fd\u4e0d\u77e5\u9053\u5305\u542b\u7684\u6ede\u540e\u9879\u7684\u6570\u91cf\uff0c\u6240\u4ee5\u53ef\u4ee5\u7528\u66f4\u5927\u7684\u6ede\u540e\u6570\u6765\u62df\u5408\u8be5\u6a21\u578b\uff1a MAXLAGS = 5 model = sm.tsa.AR(values) results = model.fit(MAXLAGS) print(results.params) # NotImplementedError: AR has been removed from statsmodels and replaced with statsmodels.tsa.ar_model.AutoReg. sikit-learn\u4ecb\u7ecd \u00b6 scikit-learn\uff08http://scikit-learn.org\uff09\u662f\u4f7f\u7528\u6700\u5e7f\u6cdb\u4e14\u6700\u53d7\u4fe1\u4efb\u7684\u901a\u7528Python\u673a\u5668\u5b66\u4e60\u5e93\u3002\\ \u5b83\u5305\u542b\u5e7f\u6cdb\u7684\u6807\u51c6\u76d1\u7763\u7684\u548c\u65e0\u76d1\u7763\u7684\u673a\u5668\u5b66\u4e60\u65b9\u6cd5\uff0c\u5305\u62ec\u7528\u4e8e\u6a21\u578b\u9009\u62e9\u548c\u8bc4\u4f30\u3001\u6570\u636e\u8f6c\u6362\u3001\u6570\u636e\u52a0\u8f7d\u548c\u6a21\u578b\u6301\u4e45\u5316\u7684\u5de5\u5177\u3002\\ \u8fd9\u4e9b\u6a21\u578b\u53ef\u7528\u4e8e\u5206\u7c7b\u3001\u805a\u7c7b\u3001\u9884\u6d4b\u548c\u5176\u4ed6\u5e38\u89c1\u4efb\u52a1\u3002\\ pandas\u975e\u5e38\u9002\u5408\u5728\u6a21\u578b\u62df\u5408\u524d\u5904\u7406\u6570\u636e\u96c6\u3002 \u4e3e\u4e2a\u4f8b\u5b50\uff0c\u7528\u4e00\u4e2aKaggle\u7ade\u8d5b\u7684\u7ecf\u5178\u6570\u636e\u96c6\uff0c\u5173\u4e8e\u6cf0\u5766\u5c3c\u514b\u53f7\u4e58\u5ba2\u7684\u751f\u8fd8\u7387\u3002\u6211\u4eec\u7528pandas\u52a0\u8f7d\u6d4b\u8bd5\u548c\u8bad\u7ec3\u6570\u636e\u96c6\uff1a import pandas as pd from sklearn.linear_model import LogisticRegression from sklearn.linear_model import LogisticRegressionCV from sklearn.model_selection import cross_val_score train = pd.read_csv('../datasets/titanic/train.csv') test = pd.read_csv('../datasets/titanic/test.csv') print(train[:4]) # PassengerId Survived Pclass ... Fare Cabin Embarked # 0 1 0 3 ... 7.2500 NaN S # 1 2 1 1 ... 71.2833 C85 C # 2 3 1 3 ... 7.9250 NaN S # 3 4 1 1 ... 53.1000 C123 S \u50cfstatsmodels\u548cscikit-learn\u901a\u5e38\u4e0d\u80fd\u63d0\u4f9b\u7f3a\u5931\u6570\u636e\uff0c\u56e0\u6b64\u6211\u4eec\u8981\u68c0\u67e5\u5404\u5217\uff0c\u770b\u770b\u662f\u5426\u6709\u5305\u542b\u7f3a\u5931\u6570\u636e\uff1a print(train.isnull().sum()) # PassengerId 0 # Survived 0 # Pclass 0 # Name 0 # Sex 0 # Age 177 # SibSp 0 # Parch 0 # Ticket 0 # Fare 0 # Cabin 687 # Embarked 2 # dtype: int64 print(test.isnull().sum()) # PassengerId 0 # Pclass 0 # Name 0 # Sex 0 # Age 86 # SibSp 0 # Parch 0 # Ticket 0 # Fare 1 # Cabin 327 # Embarked 0 # dtype: int64 \u5728\u50cf\u8fd9\u6837\u7684\u7edf\u8ba1\u548c\u673a\u5668\u5b66\u4e60\u7684\u4f8b\u5b50\u4e2d\uff0c\u4e00\u4e2a\u5178\u578b\u7684\u4efb\u52a1\u662f\u6839\u636e\u6570\u636e\u4e2d\u7684\u7279\u5f81\u6765\u9884\u6d4b\u4e58\u5ba2\u662f\u5426\u80fd\u5e78\u5b58\u4e0b\u6765\u3002\\ \u5c06\u6a21\u578b\u62df\u5408\u5230\u8bad\u7ec3\u6570\u636e\u96c6\u4e0a\uff0c\u7136\u540e\u5728\u6837\u672c\u5916\u6d4b\u8bd5\u6570\u636e\u96c6\u4e0a\u8fdb\u884c\u8bc4\u4f30\u3002\\ \u5982\u679c\u7528Age\u4f5c\u4e3a\u9884\u6d4b\uff0c\u4f46\u5b83\u7f3a\u5c11\u6570\u636e\u3002\u9700\u8981\u8fdb\u884c\u7f3a\u5931\u6570\u636e\u63d2\u8865\uff08imputation\uff09\uff0c\u5e76\u4f7f\u7528\u8bad\u7ec3\u6570\u636e\u96c6\u7684\u4e2d\u95f4\u503c\u586b\u5145\u4e24\u4e2a\u8868\u4e2d\u7684\u7a7a\u503c\uff1a impute_value = train['Age'].median() train['Age'] = train['Age'].fillna(impute_value) test['Age'] = test['Age'].fillna(impute_value) \u73b0\u5728\u5efa\u7acb\u6a21\u578b\u3002\\ \u6dfb\u52a0\u4e00\u5217IsFemale\u4f5c\u4e3a\u2019Sex\u2019\u5217\u7684\u7f16\u7801\u7248\u672c\uff1a train['IsFemale'] = (train['Sex'] == 'female').astype(int) test['IsFemale'] = (test['Sex'] == 'female').astype(int) \u786e\u5b9a\u4e00\u4e9b\u6a21\u578b\u53d8\u91cf\u5e76\u521b\u5efaNumPy\u6570\u7ec4\uff1a predictors = ['Pclass', 'IsFemale', 'Age'] X_train = train[predictors].values X_test = test[predictors].values y_train = train['Survived'].values print(X_train[:5]) # [[ 3. 0. 22.] # [ 1. 1. 38.] # [ 3. 1. 26.] # [ 1. 1. 35.] # [ 3. 0. 35.]] print(y_train[:5]) # [0 1 1 1 0] \u4f7f\u7528scikit-learn\u7684LogisticRegression\u6a21\u578b\u521b\u5efa\u4e00\u4e2a\u6a21\u578b\u5b9e\u4f8b\uff1a model = LogisticRegression() \u4e0estatsmodels\u7c7b\u4f3c\uff0c\u4f7f\u7528\u6a21\u578b\u7684fit\u65b9\u6cd5\u5728\u8bad\u7ec3\u6570\u636e\u4e0a\u62df\u5408\u6a21\u578b\uff1a result = model.fit(X_train, y_train) print(result) # LogisticRegression() \u4f7f\u7528model.predict\u4e3a\u6d4b\u8bd5\u6570\u636e\u96c6\u5f62\u6210\u9884\u6d4b\uff1a y_predict = model.predict(X_test) print(y_predict[:10]) # [0 0 0 0 1 0 1 0 1 0] \u5b9e\u9645\u4e0a\uff0c\u6a21\u578b\u8bad\u7ec3\u4e2d\u7ecf\u5e38\u5b58\u5728\u8bb8\u591a\u9644\u52a0\u7684\u590d\u6742\u5c42\u6b21\u3002\\ \u8bb8\u591a\u6a21\u578b\u5177\u6709\u53ef\u4ee5\u8c03\u6574\u7684\u53c2\u6570\uff0c\u5e76\u4e14\u5b58\u5728\u53ef\u7528\u4e8e\u53c2\u6570\u8c03\u6574\u7684\u4ea4\u53c9\u9a8c\u8bc1\u7b49\u6280\u672f\u4ee5\u907f\u514d\u8fc7\u5ea6\u62df\u5408\u8bad\u7ec3\u6570\u636e\u3002\\ \u8fd9\u901a\u5e38\u53ef\u4ee5\u5728\u65b0\u6570\u636e\u4e0a\u4ea7\u751f\u66f4\u597d\u7684\u9884\u6d4b\u6027\u80fd\u6216\u7a33\u5065\u6027\u3002\u4ea4\u53c9\u9a8c\u8bc1\u901a\u8fc7\u5206\u5272\u8bad\u7ec3\u6570\u636e\u6765\u6a21\u62df\u6837\u672c\u5916\u9884\u6d4b\u3002\\ \u57fa\u4e8e\u50cf\u5747\u65b9\u8bef\u5dee\u4e4b\u7c7b\u7684\u6a21\u578b\u51c6\u786e\u5ea6\u5206\u6570\uff0c\u53ef\u4ee5\u5bf9\u6a21\u578b\u53c2\u6570\u6267\u884c\u7f51\u683c\u641c\u7d22\u3002\\ \u4e00\u4e9b\u6a21\u578b\uff0c\u5982\u903b\u8f91\u56de\u5f52\uff0c\u5177\u6709\u5185\u7f6e\u4ea4\u53c9\u9a8c\u8bc1\u7684\u4f30\u8ba1\u7c7b\u3002\\ \u4f8b\u5982\uff0cLogisticRegressionCV\u7c7b\u53ef\u4ee5\u4e0e\u4e00\u4e2a\u53c2\u6570\u4e00\u8d77\u4f7f\u7528\uff0c\u8be5\u53c2\u6570\u8868\u793a\u7f51\u683c\u641c\u7d22\u5728\u6a21\u578b\u6b63\u5219\u5316\u53c2\u6570C\u4e0a\u7684\u7ec6\u81f4\u5ea6\uff1a model_cv = LogisticRegressionCV() result = model_cv.fit(X_train, y_train) print(result) # LogisticRegressionCV() \u8981\u624b\u52a8\u8fdb\u884c\u4ea4\u53c9\u9a8c\u8bc1\uff0c\u53ef\u4ee5\u4f7f\u7528cross_val_score\u51fd\u6570\uff0c\u8be5\u51fd\u6570\u5904\u7406\u6570\u636e\u62c6\u5206\u8fc7\u7a0b\u3002\\ \u4f8b\u5982\uff0c\u4e3a\u4e86\u7528\u6211\u4eec\u7684\u6a21\u578b\u4e0e\u8bad\u7ec3\u6570\u636e\u7684\u56db\u4e2a\u975e\u91cd\u53e0\u5206\u5272\u8fdb\u884c\u4ea4\u53c9\u9a8c\u8bc1\uff0c\u53ef\u4ee5\u8fd9\u6837\u505a\uff1a model = LogisticRegression(C=10) scores = cross_val_score(model, X_train, y_train, cv=4) print(scores) # [0.77578475 0.79820628 0.77578475 0.78828829] \u9ed8\u8ba4\u8bc4\u5206\u6307\u6807\u662f\u4f9d\u8d56\u4e8e\u6a21\u578b\u7684\uff0c\u4f46\u53ef\u4ee5\u9009\u62e9\u660e\u786e\u7684\u8bc4\u5206\u51fd\u6570\u3002\u7ecf\u8fc7\u4ea4\u53c9\u9a8c\u8bc1\u7684\u6a21\u578b\u9700\u8981\u66f4\u957f\u65f6\u95f4\u7684\u8bad\u7ec3\uff0c\u4f46\u901a\u5e38\u53ef\u4ee5\u4ea7\u751f\u66f4\u597d\u7684\u6a21\u578b\u6027\u80fd\u3002","title":"Python\u5efa\u6a21\u5e93\u4ecb\u7ecd"},{"location":"python/DataAnalysis/ch11/#python","text":"","title":"Python\u5efa\u6a21\u5e93\u4ecb\u7ecd"},{"location":"python/DataAnalysis/ch11/#pandas","text":"\u4ecb\u7ecd\u4e24\u4e2a\u6d41\u884c\u7684\u5efa\u6a21\u5de5\u5177\u5305\uff1a [statsmodels]http://statsmodels.org\uff09 [scikit-learn]http://scikit-learn.org\uff09 import pandas as pd import numpy as np \u4f7f\u7528pandas\u7528\u4e8e\u6570\u636e\u8f7d\u5165\u548c\u6570\u636e\u6e05\u6d17\uff0c\u4e4b\u540e\u5207\u6362\u5230\u6a21\u578b\u5e93\u53bb\u5efa\u7acb\u6a21\u578b\u662f\u4e00\u4e2a\u5e38\u89c1\u7684\u6a21\u578b\u5f00\u53d1\u5de5\u4f5c\u6d41\u3002 \u5728\u673a\u5668\u5b66\u4e60\u4e2d\uff0c\u7279\u5f81\u5de5\u7a0b\u662f\u6a21\u578b\u5f00\u53d1\u7684\u91cd\u8981\u90e8\u5206\u4e4b\u4e00\u3002 \u7279\u5f81\u5de5\u7a0b\u662f\u6307\u4ece\u539f\u751f\u6570\u636e\u96c6\u4e2d\u63d0\u53d6\u53ef\u7528\u4e8e\u6a21\u578b\u4e0a\u4e0b\u6587\u7684\u6709\u6548\u4fe1\u606f\u7684\u6570\u636e\u8f6c\u6362\u8fc7\u7a0b\u6216\u5206\u6790\u3002 pandas\u548c\u5176\u4ed6\u5206\u6790\u5e93\u7684\u7ed3\u5408\u70b9\u901a\u5e38\u662fNumPy\u6570\u7ec4\u3002 \u8981\u5c06DataFrame\u8f6c\u6362\u4e3aNumPy\u6570\u7ec4\uff0c\u4f7f\u7528 .values \u5c5e\u6027\uff1a df = pd.DataFrame( { 'x0': [1, 2, 3, 4, 5], 'x1': [0.01, -0.01, 0.25, -4.1, 0.], 'y': [-1.5, 0., 3.6, 1.3, -2.] } ) print(df) # x0 x1 y # 0 1 0.01 -1.5 # 1 2 -0.01 0.0 # 2 3 0.25 3.6 # 3 4 -4.10 1.3 # 4 5 0.00 -2.0 print(df.columns) # Index(['x0', 'x1', 'y'], dtype='object') print(df.values) # [[ 1. 0.01 -1.5 ] # [ 2. -0.01 0. ] # [ 3. 0.25 3.6 ] # [ 4. -4.1 1.3 ] # [ 5. 0. -2. ]] \u5c06\u6570\u7ec4\u518d\u8f6c\u6362\u4e3aDataFrame\uff1a df2 = pd.DataFrame(df.values, columns=['one', 'two', 'three']) # \u9012\u4e00\u4e2a\u542b\u6709\u5217\u540d\u7684\u4e8c\u7ef4ndarray print(df2) # one two three # 0 1.0 0.01 -1.5 # 1 2.0 -0.01 0.0 # 2 3.0 0.25 3.6 # 3 4.0 -4.10 1.3 # 4 5.0 0.00 -2.0 .values \u5c5e\u6027\u4e00\u822c\u5728\u6570\u636e\u662f\u540c\u6784\u5316\u7684\u65f6\u5019\u4f7f\u7528\u2014\u2014\u4f8b\u5982\uff0c\u90fd\u662f\u6570\u5b57\u7c7b\u578b\u7684\u65f6\u5019\u3002\u5982\u679c\u6570\u636e\u662f\u5f02\u6784\u5316\u7684\uff0c\u7ed3\u679c\u5c06\u662fPython\u5bf9\u8c61\u7684 ndarray \uff1a \u6dfb\u52a0\u4e00\u4e2a\u975e\u6570\u5b57\u7c7b\u578b\u7684\u5217\u3002 df3 = df.copy() df3['category'] = pd.Categorical(['a', 'b', 'a', 'a', 'b'], categories=['a', 'b']) print(df3) # x0 x1 y category # 0 1 0.01 -1.5 a # 1 2 -0.01 0.0 b # 2 3 0.25 3.6 a # 3 4 -4.10 1.3 a # 4 5 0.00 -2.0 b print(df3.values) # [[1 0.01 -1.5 'a'] # [2 -0.01 0.0 'b'] # [3 0.25 3.6 'a'] # [4 -4.1 1.3 'a'] # [5 0.0 -2.0 'b']] \u901a\u8fc7 loc \u7d22\u5f15\u548c values \u4f7f\u7528\u4e00\u90e8\u5206\u5217\u6570\u636e\u3002 model_cols = ['x0', 'x1'] result = df.loc[:, model_cols].values print(result) # [[ 1. 0.01] # [ 2. -0.01] # [ 3. 0.25] # [ 4. -4.1 ] # [ 5. 0. ]] \u5982\u679c\u6211\u4f7f\u7528\u865a\u62df\u53d8\u91cf\u66ff\u4ee3 df3 \u7684 category \u5217\uff0c\u5148\u521b\u5efa\u865a\u62df\u53d8\u91cf\uff0c\u4e4b\u540e\u5220\u9664 categroy \u5217\uff0c\u7136\u540e\u8fde\u63a5\u7ed3\u679c\uff1a dummies = pd.get_dummies(df3.category, prefix='category') print(dummies) # category_a category_b # 0 1 0 # 1 0 1 # 2 1 0 # 3 1 0 # 4 0 1 data_with_dummies = df3.drop('category', axis=1).join(dummies) print(data_with_dummies) # x0 x1 y category_a category_b # 0 1 0.01 -1.5 1 0 # 1 2 -0.01 0.0 0 1 # 2 3 0.25 3.6 1 0 # 3 4 -4.10 1.3 1 0 # 4 5 0.00 -2.0 0 1","title":"pandas\u4e0e\u5efa\u6a21\u4ee3\u7801\u7684\u7ed3\u5408"},{"location":"python/DataAnalysis/ch11/#patsy","text":"\u6837\u672c\u7684\u8868\u793a\u5f62\u5f0f\uff1a \u5728\u6570\u636e\u6316\u6398\u8fc7\u7a0b\u4e2d\uff0c\u6837\u672c\u4ee5\u7279\u5f81\u503c\u77e9\u9635X\u548c\u76ee\u6807\u503c\u5411\u91cfY\u7684\u5f62\u5f0f\u8868\u793a\u3002 \u5bb9\u91cf\u4e3a n \uff0c\u6709 m \u4e2a\u7279\u5f81\u7684\u6837\u672c\uff0c\u5176\u7279\u5f81\u503c\u77e9\u9635X\u7531 n \u4e2a\u7ef4\u5ea6\u4e3a m \u7684\u5217\u5411\u91cf\u7ec4\u6210\uff0c\u7b2c j \u4e2a\u5217\u5411\u91cf\u4e3a\u6837\u672c\u4e2d\u7b2c j \u4e2a\u4e2a\u4f53\u7684\u7279\u5f81\u503c\u5411\u91cf\uff1b \u76ee\u6807\u503c\u5411\u91cfY\u7684\u7b2c j \u4e2a\u5206\u91cf\u4e3a\u6837\u672c\u4e2d\u7b2c j \u4e2a\u4e2a\u4f53\u7684\u76ee\u6807\u503c\u3002 \u53c2\u8003\uff1a How formulas work [Patsy](https://patsy.readthedocs.io/\uff09\u662f\u4e00\u4e2a\u7528\u4e8e\u63cf\u8ff0\u7edf\u8ba1\u6a21\u578b\uff08\u5c24\u5176\u662f\u7ebf\u6027\u6a21\u578b\uff09\u7684Python\u5e93\u3002 \u5b83\u4f7f\u7528\u4e00\u79cd\u5c0f\u578b\u57fa\u4e8e\u5b57\u7b26\u4e32\u7684\"\u516c\u5f0f\u8bed\u6cd5\"\u3002 Patsy\u80fd\u591f\u5f88\u597d\u5730\u652f\u6301 statsmodels \u4e2d\u7279\u5b9a\u7684\u7ebf\u6027\u6a21\u578b\u3002 \u50cf y ~ x0 + x1 \u8fd9\u79cd a + b \u7684\u8bed\u6cd5\u5e76\u4e0d\u4ee3\u8868\u5c06 a \u548c b \u76f8\u52a0\uff0c\u800c\u662f\u4ee3\u8868\u4e3a\u6a21\u578b\u521b\u5efa\u7684\u8bbe\u8ba1\u77e9\u9635\u7684\u672f\u8bed\uff08terms in the design matrix\uff09\u3002 patsy.dmatrices \u51fd\u6570\uff0c\u53d6\u4e00\u4e2a\u516c\u5f0f\u5b57\u7b26\u4e32\u548c\u4e00\u4e2a\u6570\u636e\u96c6\uff08\u53ef\u4ee5\u4f7fDataFrame\u6216dict\uff09\uff0c\u7136\u540e\u4e3a\u7ebf\u6027\u6a21\u578b\u4ea7\u751f\u8bbe\u8ba1\u77e9\u9635\uff1a import pandas as pd import numpy as np import patsy from patsy import dmatrices, dmatrix, demo_data df = pd.DataFrame( { 'x0': [1, 2, 3, 4, 5], 'x1': [0.01, -0.01, 0.25, -4.1, 0.], 'y': [-1.5, 0., 3.6, 1.3, -2.] } ) print(df) # x0 x1 y # 0 1 0.01 -1.5 # 1 2 -0.01 0.0 # 2 3 0.25 3.6 # 3 4 -4.10 1.3 # 4 5 0.00 -2.0 y, X = patsy.dmatrices('y ~ x0 + x1', df) print(y) # [[-1.5] # [ 0. ] # [ 3.6] # [ 1.3] # [-2. ]] print(X) # [[ 1. 1. 0.01] # [ 1. 2. -0.01] # [ 1. 3. 0.25] # [ 1. 4. -4.1 ] # [ 1. 5. 0. ]] print(np.asarray(y)) # Patsy\u7684DesignMatrix\u5b9e\u4f8b\uff0c\u542b\u6709\u9644\u52a0\u5143\u6570\u636e\u7684NumPy.ndarray # [[-1.5] # [ 0. ] # [ 3.6] # [ 1.3] # [-2. ]] print(np.asarray(X)) # Patsy\u7684DesignMatrix\u5b9e\u4f8b\uff0c\u542b\u6709\u9644\u52a0\u5143\u6570\u636e\u7684NumPy.ndarray # [[ 1. 1. 0.01] # [ 1. 2. -0.01] # [ 1. 3. 0.25] # [ 1. 4. -4.1 ] # [ 1. 5. 0. ]] \u4e0a\u9762X\u8f93\u51fa\u4e2d\u7684Intercept(\u6700\u5de6\u8fb9\u4e00\u5217)\u662f\u4ece\u54ea\u91cc\u6765\u7684\u3002 \u8fd9\u5176\u5b9e\u662f\u7ebf\u6027\u6a21\u578b\u7684\u4e00\u4e2a\u60ef\u4f8b\uff0c\u6bd4\u5982\u666e\u901a\u6700\u5c0f\u4e8c\u4e58\u56de\u5f52\u6cd5\uff08ordinary least squares regression\uff09\u3002 \u53ef\u4ee5\u53bb\u6389\u8fd9\u4e2a\u622a\u8ddd\uff08intercept\uff09\uff0c\u901a\u8fc7 y ~ x0 + x1 + 0 \u7ed9\u6a21\u578b\u3002 y, X = patsy.dmatrices('y ~ x0 + x1 + 0', df) print(X) # [[ 1. 0.01] # [ 2. -0.01] # [ 3. 0.25] # [ 4. -4.1 ] # [ 5. 0. ]] \u8fd9\u79cdPatsy\u5bf9\u8c61\u53ef\u4ee5\u76f4\u63a5\u4f20\u5165\u4e00\u4e2a\u7b97\u6cd5\uff0c\u6bd4\u5982 numpy.linalg.lstsq \uff0c\u6765\u8fdb\u884c\u666e\u901a\u6700\u5c0f\u4e8c\u4e58\u56de\u5f52\u7684\u8ba1\u7b97 coef, resid, _, _ =np.linalg.lstsq(X, y, rcond=1) # \u6700\u5c0f\u4e8c\u4e58\u6cd5 print(coef) # [[ 0.00925424] # [-0.25485421]] print(resid) # [19.72552896] coef = pd.Series(coef.squeeze(), index=X.design_info.column_names) print(coef) # x0 0.009254 # x1 -0.254854 # dtype: float64","title":"\u4f7f\u7528Patsy\u521b\u5efa\u6a21\u578b\u63cf\u8ff0"},{"location":"python/DataAnalysis/ch11/#patsy_1","text":"\u53ef\u4ee5\u5c06Python\u4ee3\u7801\u6df7\u5408\u5230\u4f60\u7684Patsy\u516c\u5f0f\u4e2d\uff0c\u5728\u6267\u884c\u516c\u5f0f\u65f6\uff0cPatsy\u5e93\u5c06\u5c1d\u8bd5\u5728\u5c01\u95ed\u4f5c\u7528\u57df\u4e2d\u5bfb\u627e\u4f60\u4f7f\u7528\u7684\u51fd\u6570\uff1a y, X = patsy.dmatrices('y ~ x0 + np.log(np.abs(x1) +1)', df) print(X) # [[1. 1. 0.00995033] # [1. 2. 0.00995033] # [1. 3. 0.22314355] # [1. 4. 1.62924054] # [1. 5. 0. ]] \u4e00\u4e9b\u5e38\u7528\u7684\u53d8\u91cf\u53d8\u6362\uff0c\u5305\u62ec\u6807\u51c6\u5316\uff08standardizing (\u5e73\u5747\u503c0\uff0c\u65b9\u5dee1\uff09\u548c\u4e2d\u5fc3\u5316\uff08\u51cf\u53bb\u5e73\u5747\u503c\uff09\u3002Patsy\u6709\u5185\u5efa\u7684\u51fd\u6570\u53ef\u4ee5\u505a\u5230\u8fd9\u4e9b\u3002 y, X = patsy.dmatrices('y ~ standardize(x0) + center(x1)', df) print(X) # [[ 1. -1.41421356 0.78 ] # [ 1. -0.70710678 0.76 ] # [ 1. 0. 1.02 ] # [ 1. 0.70710678 -3.33 ] # [ 1. 1.41421356 0.77 ]] \u4f5c\u4e3a\u5efa\u6a21\u7684\u4e00\u90e8\u5206\uff0c\u6211\u4eec\u53ef\u80fd\u4f1a\u5728\u4e00\u4e2a\u6570\u636e\u53ca\u4e0a\u8bad\u7ec3\u6a21\u578b\uff0c\u7136\u540e\u5728\u53e6\u4e00\u4e2a\u6570\u636e\u53ca\u4e0a\u8bc4\u4ef7\u6a21\u578b\u3002 \u5f53\u4f7f\u7528\u4e2d\u5fc3\u5316\u6216\u6807\u51c6\u5316\u8fd9\u6837\u7684\u8f6c\u6362\u65f6\uff0c\u6211\u4eec\u5fc5\u987b\u6ce8\u610f\uff0c\u5fc5\u987b\u7528\u6a21\u578b\u5728\u65b0\u6570\u636e\u96c6\u4e0a\u505a\u9884\u6d4b\u3002 \u8fd9\u53eb\u505a\u72b6\u6001\u53d8\u6362\uff08stateful transformations\uff09\u3002 \u56e0\u4e3a\u6211\u4eec\u5fc5\u987b\u7528\u539f\u672c\u5728\u8bad\u7ec3\u96c6\u4e0a\u5f97\u5230\u7684\u5e73\u5747\u503c\u548c\u6807\u51c6\u5dee\uff0c\u7528\u5728\u65b0\u7684\u6570\u636e\u96c6\u4e0a\u3002 new_df = pd.DataFrame( { 'x0': [6, 7, 8, 9], 'x1': [3.1, -0.5, 0, 2.3], 'y': [1, 2, 3, 4] } ) new_X = patsy.build_design_matrices([X.design_info], new_df) print(new_X) # [DesignMatrix with shape (4, 3) # Intercept standardize(x0) center(x1) # 1 2.12132 3.87 # 1 2.82843 0.27 # 1 3.53553 0.77 # 1 4.24264 3.07 # Terms: # 'Intercept' (column 0), 'standardize(x0)' (column 1), 'center(x1)' (column 2)] \u56e0\u4e3a\u52a0\u53f7\uff08+\uff09\u5728Patsy\u516c\u5f0f\u7684\u4e0a\u4e0b\u6587\u4e2d\u5e76\u4e0d\u662f\u52a0\u6cd5\u7684\u610f\u601d\uff0c\u5f53\u60f3\u8981\u5bf9\u6570\u636e\u96c6\u4e2d\u4e24\u5217\u6309\u5217\u540d\u76f8\u52a0\u65f6\uff0c\u5fc5\u987b\u5c06\u5217\u540d\u5c01\u88c5\u5230\u7279\u6b8a\u7684I\u51fd\u6570\u4e2d\uff1a y, X = patsy.dmatrices('y ~ I(x0 + x1)', df) print(X) # [[ 1. 1.01] # [ 1. 1.99] # [ 1. 3.25] # [ 1. -0.1 ] # [ 1. 5. ]]","title":"Patsy\u516c\u5f0f\u4e2d\u7684\u6570\u636e\u8f6c\u6362"},{"location":"python/DataAnalysis/ch11/#categoricalpatsy","text":"\u975e\u6570\u503c\u578b\u6570\u636e\u53ef\u4ee5\u901a\u8fc7\u5f88\u591a\u79cd\u65b9\u5f0f\u53d8\u4e3a\u4e00\u4e2a\u6a21\u578b\u8bbe\u8ba1\u77e9\u9635\u3002 \u5f53\u6211\u4eec\u5728Patsy\u516c\u5f0f\u4e2d\u4f7f\u7528\u975e\u6570\u503c\u672f\u8bed\u65f6\uff0c\u8fd9\u4e9b\u7c7b\u578b\u6570\u636e\u9ed8\u8ba4\u4f1a\u88ab\u8f6c\u6362\u4e3a\u54d1\u53d8\u91cf\u3002\u5982\u679c\u6709\u622a\u8ddd\uff0c\u4e00\u4e2a\u5c42\u7ea7\u4e0a\u7684\u622a\u8ddd\u4f1a\u88ab\u820d\u5f03\uff0c\u9632\u6b62\u51fa\u73b0\u5171\u7ebf\u6027\u3002 data = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a', 'b', 'a', 'b'], 'key2': [0, 1, 0, 1, 0, 1, 0, 0], 'v1': [1, 2, 3, 4, 5, 6, 7, 8], 'v2': [-1, 0, 2.5, -0.5, 4., -1.2, 0.2, -1.7] } ) y, X = patsy.dmatrices('v2 ~ key1', data) print(y) # [[-1. ] # [ 0. ] # [ 2.5] # [-0.5] # [ 4. ] # [-1.2] # [ 0.2] # [-1.7]] print(X) # [[1. 0.] # [1. 0.] # [1. 1.] # [1. 1.] # [1. 0.] # [1. 1.] # [1. 0.] # [1. 1.]] \u5982\u679c\u4ece\u6a21\u578b\u4e2d\u820d\u5f03\u622a\u8ddd\uff0c\u6bcf\u4e2a\u7c7b\u578b\u7684\u5217\u4f1a\u88ab\u5305\u542b\u5728\u6a21\u578b\u8bbe\u8ba1\u77e9\u9635\u4e2d\u3002 y, X = patsy.dmatrices('v2 ~ key1 + 0', data) print(X) # [[1. 0.] # [1. 0.] # [0. 1.] # [0. 1.] # [1. 0.] # [0. 1.] # [1. 0.] # [0. 1.]] \u6570\u503c\u578b\u5217\u53ef\u4ee5\u901a\u8fc7C\u51fd\u6570\uff0c\u53d8\u4e3a\u7c7b\u578b\u5217\uff1a y, X = patsy.dmatrices('v2 ~ C(key2)', data) print(X) # [[1. 0.] # [1. 1.] # [1. 0.] # [1. 1.] # [1. 0.] # [1. 1.] # [1. 0.] # [1. 0.]] \u5f53\u6211\u4eec\u5728\u4e00\u4e2a\u6a21\u578b\u4e2d\u4f7f\u7528\u591a\u4e2a\u7c7b\u578b\u672f\u8bed\u65f6\uff0c\u4f1a\u53d8\u5f97\u66f4\u590d\u6742\u4e00\u4e9b\uff0c\u4e4b\u524d\u7528key1:key2\u7684\u5f62\u5f0f\u6765\u5305\u542b\u6709\u4ea4\u96c6\u7684\u672f\u8bed\uff0c \u8fd9\u79cd\u65b9\u6cd5\u53ef\u4ee5\u7528\u4e8e\u4f7f\u7528\u591a\u4e2a\u672f\u8bed\uff0c\u4f8b\u5982\uff0c\u4e00\u4e2a\u65b9\u6cd5\u5206\u6790\u6a21\u578b\uff08analysis of variance (ANOVA) models\uff09\uff1a data['key2'] = data['key2'].map({0: 'zero', 1: 'one'}) print(data) # key1 key2 v1 v2 # 0 a zero 1 -1.0 # 1 a one 2 0.0 # 2 b zero 3 2.5 # 3 b one 4 -0.5 # 4 a zero 5 4.0 # 5 b one 6 -1.2 # 6 a zero 7 0.2 # 7 b zero 8 -1.7 y, X = patsy.dmatrices('v2 ~ key1 + key2', data) print(X) # [[1. 0. 1.] # [1. 0. 0.] # [1. 1. 1.] # [1. 1. 0.] # [1. 0. 1.] # [1. 1. 0.] # [1. 0. 1.] # [1. 1. 1.]] y, X = patsy.dmatrices('v2 ~ key1 + key2 + key1:key2', data) print(X) # [[1. 0. 1. 0.] # [1. 0. 0. 0.] # [1. 1. 1. 1.] # [1. 1. 0. 0.] # [1. 0. 1. 0.] # [1. 1. 0. 0.] # [1. 0. 1. 0.] # [1. 1. 1. 1.]]","title":"\u5206\u7c7b\u6570\u636eCategorical\u548cPatsy"},{"location":"python/DataAnalysis/ch11/#statsmodels","text":"statsmodels \u662f\u4e00\u4e2aPython\u5e93\uff0c\u7528\u4e8e\u62df\u5408\u591a\u79cd\u7edf\u8ba1\u6a21\u578b\uff0c\u6267\u884c\u7edf\u8ba1\u6d4b\u8bd5\u4ee5\u53ca\u6570\u636e\u63a2\u7d22\u548c\u53ef\u89c6\u5316\u3002 statsmodels \u5305\u542b\u66f4\u591a\u7684\u201c\u7ecf\u5178\u201d\u9891\u7387\u5b66\u6d3e\u7edf\u8ba1\u65b9\u6cd5\uff0c\u800c\u8d1d\u53f6\u65af\u65b9\u6cd5\u548c\u673a\u5668\u5b66\u4e60\u6a21\u578b\u53ef\u5728\u5176\u4ed6\u5e93\u4e2d\u627e\u5230\u3002 \u5305\u542b\u5728statsmodels\u4e2d\u7684\u4e00\u4e9b\u6a21\u578b\uff1a \u7ebf\u6027\u6a21\u578b\uff0c\u5e7f\u4e49\u7ebf\u6027\u6a21\u578b\u548c\u9c81\u68d2\u7ebf\u6027\u6a21\u578b \u7ebf\u6027\u6df7\u5408\u6548\u5e94\u6a21\u578b \u65b9\u5dee\u5206\u6790\uff08ANOVA\uff09\u65b9\u6cd5 \u65f6\u95f4\u5e8f\u5217\u8fc7\u7a0b\u548c\u72b6\u6001\u7a7a\u95f4\u6a21\u578b \u5e7f\u4e49\u7684\u77e9\u91cf\u6cd5 import pandas as pd import statsmodels.api as sm import statsmodels.formula.api as smf import numpy as np import random","title":"statsmodels\u4ecb\u7ecd"},{"location":"python/DataAnalysis/ch11/#_1","text":"\u7edf\u8ba1\u6a21\u578b\u4e2d\u6709\u51e0\u79cd\u7ebf\u6027\u56de\u5f52\u6a21\u578b\uff0c\u4ece\u8f83\u57fa\u672c\u7684\uff08\u4f8b\u5982\uff0c\u666e\u901a\u6700\u5c0f\u4e8c\u4e58\uff09\u5230\u66f4\u590d\u6742\u7684\uff08\u4f8b\u5982\uff0c\u8fed\u4ee3\u91cd\u65b0\u52a0\u6743\u7684\u6700\u5c0f\u4e8c\u4e58\uff09\u3002 tatsmodels \u4e2d\u7684\u7ebf\u6027\u6a21\u578b\u6709\u4e24\u4e2a\u4e0d\u540c\u7684\u4e3b\u8981\u63a5\u53e3\uff0c\u8fd9\u4e9b\u63a5\u53e3\u901a\u8fc7\u8fd9\u4e9bAPI\u6a21\u5757\u5bfc\u5165\u6765\u8bbf\u95ee\uff1a \u57fa\u4e8e\u6570\u7ec4 \u57fa\u4e8e\u516c\u5f0f \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u8c03\u7528\u5df2\u77e5\u53c2\u6570beta\u7684\u6a21\u578b\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c dnorm \u662f\u7528\u4e8e\u751f\u6210\u5177\u6709\u7279\u5b9a\u5747\u503c\u548c\u65b9\u5dee\u7684\u6b63\u6001\u5206\u5e03\u6570\u636e\u7684\u8f85\u52a9\u51fd\u6570\u3002 def dnorm (mean, variance, size=1): if isinstance(size, int): size = size, return mean + np.sqrt(variance) * np.random.randn(*size) np.random.seed(12345) N = 100 X = np.c_[ dnorm(0, 0.4, size=N), dnorm(0, 0.6, size=N), dnorm(0, 0.2, size=N) ] eps = dnorm(0, 0.1, size=N) beta = [0.1, 0.3, 0.5] y = np.dot(X, beta) + eps print(X[:5]) # [[-0.12946849 -1.21275292 0.50422488] # [ 0.30291036 -0.43574176 -0.25417986] # [-0.32852189 -0.02530153 0.13835097] # [-0.35147471 -0.71960511 -0.25821463] # [ 1.2432688 -0.37379916 -0.52262905]] print(y[:5]) # [ 0.42786349 -0.67348041 -0.09087764 -0.48949442 -0.12894109] \u7ebf\u6027\u6a21\u578b\u901a\u5e38\u4e0e\u6211\u4eec\u5728Patsy\u4e2d\u770b\u5230\u7684\u622a\u8ddd\u9879\u76f8\u5339\u914d\u3002 sm.add_constant \u51fd\u6570\u53ef\u4ee5\u5c06\u622a\u8ddd\u5217\u6dfb\u52a0\u5230\u73b0\u6709\u77e9\u9635\uff1a X_model = sm.add_constant(X) print(X_model[:5]) # [[ 1. -0.12946849 -1.21275292 0.50422488] # [ 1. 0.30291036 -0.43574176 -0.25417986] # [ 1. -0.32852189 -0.02530153 0.13835097] # [ 1. -0.35147471 -0.71960511 -0.25821463] # [ 1. 1.2432688 -0.37379916 -0.52262905]] sm.OLS \u7c7b\u53ef\u4ee5\u62df\u5408\u4e00\u4e2a\u6700\u5c0f\u4e8c\u4e58\u7ebf\u6027\u56de\u5f52\uff1a model = sm.OLS(y, X) \u6a21\u578b\u7684 fit \u65b9\u6cd5\u8fd4\u56de\u4e00\u4e2a\u56de\u5f52\u7ed3\u679c\u5bf9\u8c61\uff0c\u8be5\u5bf9\u8c61\u5305\u542b\u4e86\u4f30\u8ba1\u7684\u6a21\u578b\u53c2\u6570\u548c\u5176\u4ed6\u7684\u8bca\u65ad\uff1a results = model.fit() print(results.params) # [0.17826108 0.22303962 0.50095093] \u8c03\u7528 summary \u65b9\u6cd5\u53ef\u4ee5\u6253\u5370\u51fa\u4e00\u4e2a\u6a21\u578b\u7684\u8bca\u65ad\u7ec6\u8282\uff0c\u6b64\u5904\u7684\u53c2\u6570\u540d\u79f0\u5df2\u88ab\u8d4b\u4e88\u901a\u7528\u540d\u79f0 x1 \u3001 x2 \u7b49\uff1a print(results.summary()) # OLS Regression Results # ======================================================================================= # Dep. Variable: y R-squared (uncentered): 0.430 # Model: OLS Adj. R-squared (uncentered): 0.413 # Method: Least Squares F-statistic: 24.42 # Date: Sat, 16 Oct 2021 Prob (F-statistic): 7.44e-12 # Time: 14:21:45 Log-Likelihood: -34.305 # No. Observations: 100 AIC: 74.61 # Df Residuals: 97 BIC: 82.42 # Df Model: 3 # Covariance Type: nonrobust # ============================================================================== # coef std err t P>|t| [0.025 0.975] # ------------------------------------------------------------------------------ # x1 0.1783 0.053 3.364 0.001 0.073 0.283 # x2 0.2230 0.046 4.818 0.000 0.131 0.315 # x3 0.5010 0.080 6.237 0.000 0.342 0.660 # ============================================================================== # Omnibus: 4.662 Durbin-Watson: 0 -0.002327 # Prob(Omnibus): 0.097 Jarque-Bera (JB): 4.098 # Skew: 0.481 Prob(JB): 0.129 # Kurtosis: 3.243 Cond. No. 1.74 # ============================================================================== # # Notes: # [1] R\u00b2 is computed without centering (uncentered) since the model does not contain a constant. # [2] Standard Errors assume that the covariance matrix of the errors is correctly specified. \u5047\u8bbe\u6240\u6709\u6a21\u578b\u53c2\u6570\u90fd\u5728DataFrame\u4e2d\uff1a data = pd.DataFrame(X, columns=['col0', 'col1', 'col2']) data['y'] = y print(data[:5]) # col0 col1 col2 y # 0 -0.129468 -1.212753 0.504225 0.427863 # 1 0.302910 -0.435742 -0.254180 -0.673480 # 2 -0.328522 -0.025302 0.138351 -0.090878 # 3 -0.351475 -0.719605 -0.258215 -0.489494 # 4 1.243269 -0.373799 -0.522629 -0.128941 \u73b0\u5728\u53ef\u4ee5\u4f7f\u7528 statsmodels \u516c\u5f0fAPI\u548cPatsy\u516c\u5f0f\u5b57\u7b26\u4e32\u3002\u89c2\u5bdf statsmodels \u5982\u4f55\u5c06\u7ed3\u679c\u4f5c\u4e3a\u5e26\u6709DataFrame\u5217\u540d\u79f0\u7684Series\u8fd4\u56de\u3002 results = smf.ols('y ~ col0 + col1 + col2', data=data).fit() print(results.params) # Intercept 0.033559 # col0 0.176149 # col1 0.224826 # col2 0.514808 # dtype: float64 \u7ed9\u5b9a\u65b0\u7684\u6837\u672c\u5916\u6570\u636e\u540e\uff0c\u53ef\u4ee5\u6839\u636e\u4f30\u8ba1\u7684\u6a21\u578b\u53c2\u6570\u8ba1\u7b97\u9884\u6d4b\u503c\uff1a print(results.predict(data[:5])) # 0 -0.002327 # 1 -0.141904 # 2 0.041226 # 3 -0.323070 # 4 -0.100535 # dtype: float64","title":"\u8bc4\u4f30\u7ebf\u6027\u6a21\u578b"},{"location":"python/DataAnalysis/ch11/#_2","text":"statsmodels\u4e2d\u7684\u53e6\u4e00\u7c7b\u6a21\u578b\u7528\u4e8e\u65f6\u95f4\u5e8f\u5217\u5206\u6790\u3002\u5176\u4e2d\u5305\u62ec\u81ea\u56de\u5f52\u8fc7\u7a0b\uff0c\u5361\u5c14\u66fc\u6ee4\u6ce2\u548c\u5176\u4ed6\u72b6\u6001\u7a7a\u95f4\u6a21\u578b\uff0c\u4ee5\u53ca\u591a\u53d8\u91cf\u81ea\u56de\u5f52\u6a21\u578b\u3002 \u4e0b\u4f8b\u6a21\u62df\u4e00\u4e9b\u5177\u6709\u81ea\u56de\u5f52\u7ed3\u6784\u548c\u566a\u58f0\u7684\u65f6\u95f4\u5e8f\u5217\u6570\u636e\uff0c\u8be5\u6570\u636e\u5177\u6709\u53c2\u6570\u4e3a0.8\u548c-0.4\u7684AR\uff082\uff09\u7ed3\u6784\uff08\u4e24\u4e2a\u6ede\u540e\uff09\u3002 init_x = 4 values = [init_x, init_x] N = 1000 b0 = 0.8 b1 = -0.4 noise = dnorm(0, 0.1, N) for i in range(N): new_x = values[-1] * b0 + values[-2] * b1 + noise[i] values.append(new_x) \u5f53\u62df\u5408\u4e00\u4e2aAR\u6a21\u578b\u65f6\uff0c\u4f60\u53ef\u80fd\u4e0d\u77e5\u9053\u5305\u542b\u7684\u6ede\u540e\u9879\u7684\u6570\u91cf\uff0c\u6240\u4ee5\u53ef\u4ee5\u7528\u66f4\u5927\u7684\u6ede\u540e\u6570\u6765\u62df\u5408\u8be5\u6a21\u578b\uff1a MAXLAGS = 5 model = sm.tsa.AR(values) results = model.fit(MAXLAGS) print(results.params) # NotImplementedError: AR has been removed from statsmodels and replaced with statsmodels.tsa.ar_model.AutoReg.","title":"\u8bc4\u4f30\u65f6\u95f4\u5e8f\u5217\u5904\u7406"},{"location":"python/DataAnalysis/ch11/#sikit-learn","text":"scikit-learn\uff08http://scikit-learn.org\uff09\u662f\u4f7f\u7528\u6700\u5e7f\u6cdb\u4e14\u6700\u53d7\u4fe1\u4efb\u7684\u901a\u7528Python\u673a\u5668\u5b66\u4e60\u5e93\u3002\\ \u5b83\u5305\u542b\u5e7f\u6cdb\u7684\u6807\u51c6\u76d1\u7763\u7684\u548c\u65e0\u76d1\u7763\u7684\u673a\u5668\u5b66\u4e60\u65b9\u6cd5\uff0c\u5305\u62ec\u7528\u4e8e\u6a21\u578b\u9009\u62e9\u548c\u8bc4\u4f30\u3001\u6570\u636e\u8f6c\u6362\u3001\u6570\u636e\u52a0\u8f7d\u548c\u6a21\u578b\u6301\u4e45\u5316\u7684\u5de5\u5177\u3002\\ \u8fd9\u4e9b\u6a21\u578b\u53ef\u7528\u4e8e\u5206\u7c7b\u3001\u805a\u7c7b\u3001\u9884\u6d4b\u548c\u5176\u4ed6\u5e38\u89c1\u4efb\u52a1\u3002\\ pandas\u975e\u5e38\u9002\u5408\u5728\u6a21\u578b\u62df\u5408\u524d\u5904\u7406\u6570\u636e\u96c6\u3002 \u4e3e\u4e2a\u4f8b\u5b50\uff0c\u7528\u4e00\u4e2aKaggle\u7ade\u8d5b\u7684\u7ecf\u5178\u6570\u636e\u96c6\uff0c\u5173\u4e8e\u6cf0\u5766\u5c3c\u514b\u53f7\u4e58\u5ba2\u7684\u751f\u8fd8\u7387\u3002\u6211\u4eec\u7528pandas\u52a0\u8f7d\u6d4b\u8bd5\u548c\u8bad\u7ec3\u6570\u636e\u96c6\uff1a import pandas as pd from sklearn.linear_model import LogisticRegression from sklearn.linear_model import LogisticRegressionCV from sklearn.model_selection import cross_val_score train = pd.read_csv('../datasets/titanic/train.csv') test = pd.read_csv('../datasets/titanic/test.csv') print(train[:4]) # PassengerId Survived Pclass ... Fare Cabin Embarked # 0 1 0 3 ... 7.2500 NaN S # 1 2 1 1 ... 71.2833 C85 C # 2 3 1 3 ... 7.9250 NaN S # 3 4 1 1 ... 53.1000 C123 S \u50cfstatsmodels\u548cscikit-learn\u901a\u5e38\u4e0d\u80fd\u63d0\u4f9b\u7f3a\u5931\u6570\u636e\uff0c\u56e0\u6b64\u6211\u4eec\u8981\u68c0\u67e5\u5404\u5217\uff0c\u770b\u770b\u662f\u5426\u6709\u5305\u542b\u7f3a\u5931\u6570\u636e\uff1a print(train.isnull().sum()) # PassengerId 0 # Survived 0 # Pclass 0 # Name 0 # Sex 0 # Age 177 # SibSp 0 # Parch 0 # Ticket 0 # Fare 0 # Cabin 687 # Embarked 2 # dtype: int64 print(test.isnull().sum()) # PassengerId 0 # Pclass 0 # Name 0 # Sex 0 # Age 86 # SibSp 0 # Parch 0 # Ticket 0 # Fare 1 # Cabin 327 # Embarked 0 # dtype: int64 \u5728\u50cf\u8fd9\u6837\u7684\u7edf\u8ba1\u548c\u673a\u5668\u5b66\u4e60\u7684\u4f8b\u5b50\u4e2d\uff0c\u4e00\u4e2a\u5178\u578b\u7684\u4efb\u52a1\u662f\u6839\u636e\u6570\u636e\u4e2d\u7684\u7279\u5f81\u6765\u9884\u6d4b\u4e58\u5ba2\u662f\u5426\u80fd\u5e78\u5b58\u4e0b\u6765\u3002\\ \u5c06\u6a21\u578b\u62df\u5408\u5230\u8bad\u7ec3\u6570\u636e\u96c6\u4e0a\uff0c\u7136\u540e\u5728\u6837\u672c\u5916\u6d4b\u8bd5\u6570\u636e\u96c6\u4e0a\u8fdb\u884c\u8bc4\u4f30\u3002\\ \u5982\u679c\u7528Age\u4f5c\u4e3a\u9884\u6d4b\uff0c\u4f46\u5b83\u7f3a\u5c11\u6570\u636e\u3002\u9700\u8981\u8fdb\u884c\u7f3a\u5931\u6570\u636e\u63d2\u8865\uff08imputation\uff09\uff0c\u5e76\u4f7f\u7528\u8bad\u7ec3\u6570\u636e\u96c6\u7684\u4e2d\u95f4\u503c\u586b\u5145\u4e24\u4e2a\u8868\u4e2d\u7684\u7a7a\u503c\uff1a impute_value = train['Age'].median() train['Age'] = train['Age'].fillna(impute_value) test['Age'] = test['Age'].fillna(impute_value) \u73b0\u5728\u5efa\u7acb\u6a21\u578b\u3002\\ \u6dfb\u52a0\u4e00\u5217IsFemale\u4f5c\u4e3a\u2019Sex\u2019\u5217\u7684\u7f16\u7801\u7248\u672c\uff1a train['IsFemale'] = (train['Sex'] == 'female').astype(int) test['IsFemale'] = (test['Sex'] == 'female').astype(int) \u786e\u5b9a\u4e00\u4e9b\u6a21\u578b\u53d8\u91cf\u5e76\u521b\u5efaNumPy\u6570\u7ec4\uff1a predictors = ['Pclass', 'IsFemale', 'Age'] X_train = train[predictors].values X_test = test[predictors].values y_train = train['Survived'].values print(X_train[:5]) # [[ 3. 0. 22.] # [ 1. 1. 38.] # [ 3. 1. 26.] # [ 1. 1. 35.] # [ 3. 0. 35.]] print(y_train[:5]) # [0 1 1 1 0] \u4f7f\u7528scikit-learn\u7684LogisticRegression\u6a21\u578b\u521b\u5efa\u4e00\u4e2a\u6a21\u578b\u5b9e\u4f8b\uff1a model = LogisticRegression() \u4e0estatsmodels\u7c7b\u4f3c\uff0c\u4f7f\u7528\u6a21\u578b\u7684fit\u65b9\u6cd5\u5728\u8bad\u7ec3\u6570\u636e\u4e0a\u62df\u5408\u6a21\u578b\uff1a result = model.fit(X_train, y_train) print(result) # LogisticRegression() \u4f7f\u7528model.predict\u4e3a\u6d4b\u8bd5\u6570\u636e\u96c6\u5f62\u6210\u9884\u6d4b\uff1a y_predict = model.predict(X_test) print(y_predict[:10]) # [0 0 0 0 1 0 1 0 1 0] \u5b9e\u9645\u4e0a\uff0c\u6a21\u578b\u8bad\u7ec3\u4e2d\u7ecf\u5e38\u5b58\u5728\u8bb8\u591a\u9644\u52a0\u7684\u590d\u6742\u5c42\u6b21\u3002\\ \u8bb8\u591a\u6a21\u578b\u5177\u6709\u53ef\u4ee5\u8c03\u6574\u7684\u53c2\u6570\uff0c\u5e76\u4e14\u5b58\u5728\u53ef\u7528\u4e8e\u53c2\u6570\u8c03\u6574\u7684\u4ea4\u53c9\u9a8c\u8bc1\u7b49\u6280\u672f\u4ee5\u907f\u514d\u8fc7\u5ea6\u62df\u5408\u8bad\u7ec3\u6570\u636e\u3002\\ \u8fd9\u901a\u5e38\u53ef\u4ee5\u5728\u65b0\u6570\u636e\u4e0a\u4ea7\u751f\u66f4\u597d\u7684\u9884\u6d4b\u6027\u80fd\u6216\u7a33\u5065\u6027\u3002\u4ea4\u53c9\u9a8c\u8bc1\u901a\u8fc7\u5206\u5272\u8bad\u7ec3\u6570\u636e\u6765\u6a21\u62df\u6837\u672c\u5916\u9884\u6d4b\u3002\\ \u57fa\u4e8e\u50cf\u5747\u65b9\u8bef\u5dee\u4e4b\u7c7b\u7684\u6a21\u578b\u51c6\u786e\u5ea6\u5206\u6570\uff0c\u53ef\u4ee5\u5bf9\u6a21\u578b\u53c2\u6570\u6267\u884c\u7f51\u683c\u641c\u7d22\u3002\\ \u4e00\u4e9b\u6a21\u578b\uff0c\u5982\u903b\u8f91\u56de\u5f52\uff0c\u5177\u6709\u5185\u7f6e\u4ea4\u53c9\u9a8c\u8bc1\u7684\u4f30\u8ba1\u7c7b\u3002\\ \u4f8b\u5982\uff0cLogisticRegressionCV\u7c7b\u53ef\u4ee5\u4e0e\u4e00\u4e2a\u53c2\u6570\u4e00\u8d77\u4f7f\u7528\uff0c\u8be5\u53c2\u6570\u8868\u793a\u7f51\u683c\u641c\u7d22\u5728\u6a21\u578b\u6b63\u5219\u5316\u53c2\u6570C\u4e0a\u7684\u7ec6\u81f4\u5ea6\uff1a model_cv = LogisticRegressionCV() result = model_cv.fit(X_train, y_train) print(result) # LogisticRegressionCV() \u8981\u624b\u52a8\u8fdb\u884c\u4ea4\u53c9\u9a8c\u8bc1\uff0c\u53ef\u4ee5\u4f7f\u7528cross_val_score\u51fd\u6570\uff0c\u8be5\u51fd\u6570\u5904\u7406\u6570\u636e\u62c6\u5206\u8fc7\u7a0b\u3002\\ \u4f8b\u5982\uff0c\u4e3a\u4e86\u7528\u6211\u4eec\u7684\u6a21\u578b\u4e0e\u8bad\u7ec3\u6570\u636e\u7684\u56db\u4e2a\u975e\u91cd\u53e0\u5206\u5272\u8fdb\u884c\u4ea4\u53c9\u9a8c\u8bc1\uff0c\u53ef\u4ee5\u8fd9\u6837\u505a\uff1a model = LogisticRegression(C=10) scores = cross_val_score(model, X_train, y_train, cv=4) print(scores) # [0.77578475 0.79820628 0.77578475 0.78828829] \u9ed8\u8ba4\u8bc4\u5206\u6307\u6807\u662f\u4f9d\u8d56\u4e8e\u6a21\u578b\u7684\uff0c\u4f46\u53ef\u4ee5\u9009\u62e9\u660e\u786e\u7684\u8bc4\u5206\u51fd\u6570\u3002\u7ecf\u8fc7\u4ea4\u53c9\u9a8c\u8bc1\u7684\u6a21\u578b\u9700\u8981\u66f4\u957f\u65f6\u95f4\u7684\u8bad\u7ec3\uff0c\u4f46\u901a\u5e38\u53ef\u4ee5\u4ea7\u751f\u66f4\u597d\u7684\u6a21\u578b\u6027\u80fd\u3002","title":"sikit-learn\u4ecb\u7ecd"},{"location":"python/DataStructure/01_PythonFundmantal/","text":"1.\u57fa\u7840\u77e5\u8bc6\u56de\u987e \u00b6 1.1.\u57fa\u672c\u7a0b\u5e8f\u8981\u7d20 \u00b6 \u793a\u4f8b\u4ee3\u7801 numberguess.py \u3002 import random def main (): smaller = int ( input ( \"\u8f93\u5165\u6700\u5c0f\u503c: \" )) larger = int ( input ( \"\u8f93\u5165\u6700\u5927\u503c: \" )) myNumber = random . randint ( smaller , larger ) count = 0 while True : count += 1 userNumber = int ( input ( \"\u8f93\u5165\u4f60\u731c\u7684\u503c: \" )) if userNumber < myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5c0f\uff01\" ) elif userNumber > myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5927\uff01\" ) else : print ( \"\u606d\u559c\uff0c\u4f60\u5728\u7b2c\" , count , \"\u6b21\u731c\u5bf9\u4e86!\" ) break if __name__ == \"__main__\" : main () \u8fd0\u884c\u4ee3\u7801\uff1a $ python3 numberguess.py Enter the smaller number: 10 Enter the larger number: 60 Enter your guess: 50 Too large Enter your guess: 40 Too large Enter your guess: 30 Too large Enter your guess: 20 Too large Enter your guess: 10 Too small Enter your guess: 15 You\u2019ve got it in 6 tries! 1.1.1.\u62fc\u5199\u548c\u547d\u540d\u60ef\u4f8b \u00b6 \u53d8\u91cf\uff1asalary\uff0choursWorked\uff0cisAbsent \u5e38\u6570\uff1aABSOLUTE_ZERO\uff0cINTEREST_RATE \u51fd\u6570\u6216\u65b9\u6cd5\uff1aprintResults\uff0ccubeRoot\uff0cinput \u7c7b\uff1aBankAccount\uff0cSortedSet \u901a\u5e38\u7ea6\u5b9a\uff1a\u53d8\u91cf\u540d\u662f\u540d\u8bcd\u3001\u5f62\u5bb9\u8bcd\uff08\u5e03\u5c14\u503c\uff09\uff0c\u51fd\u6570\u548c\u65b9\u6cd5\u662f\u52a8\u8bcd\uff08\u8868\u793a\u52a8\u4f5c\uff09\u3001\u540d\u8bcd\u3001\u6216\u5f62\u5bb9\u8bcd\uff08\u8868\u793a\u8fd4\u56de\u7684\u503c\uff09\u3002 \u8bed\u6cd5\u5143\u7d20\uff1a Python\u4f7f\u7528\u7a7a\u767d\u7b26\uff08\u7a7a\u683c\u3001\u5236\u8868\u7b26\u3001\u6216\u6362\u884c\u7b26\uff09\u6765\u8868\u793a\u4e0d\u540c\u7c7b\u578b\u7684\u8bed\u53e5\u7684\u8bed\u6cd5\u3002 \u901a\u5e38\u7ea6\u5b9a\u4f7f\u75284\u4e2a\u7a7a\u683c\u4f5c\u4e3a\u9501\u8fdb\u5bbd\u5ea6\u3002 1.1.2.\u5b57\u7b26\u4e32 \u00b6 \u5355\u5f15\u53f7 \u53cc\u5f15\u53f7 \u6210\u5bf9\u7684\u4e09\u4e2a\u53cc\u5f15\u53f7\uff08\u591a\u884c\u6587\u672c\uff09 \u6210\u5bf9\u7684\u4e09\u4e2a\u5355\u5f15\u53f7\uff08\u591a\u884c\u6587\u672c\uff09 \u8f6c\u4e49\u5b57\u7b26 \\ \uff08\u53cd\u659c\u6760\uff09 1.1.3.\u8fd0\u7b97\u7b26\u548c\u8868\u8fbe\u5f0f \u00b6 \u6807\u51c6\u8fd0\u7b97\u7b26\uff1a + \u3001 - \u3001 * \u3001 / \u3001 % \u7b97\u672f\u8868\u8fbe\u5f0f\u662f\u7528\u6807\u51c6\u8fd0\u7b97\u7b26\u548c\u4e2d\u7f00\u8868\u793a\u6cd5 \u6bd4\u8f83\u8fd0\u7b97\u7b26\uff1a < \u3001 <= \u3001 > \u3001 >= \u3001 == \u3001 != \uff0c\u7528\u4e8e\u6bd4\u8f83\u6570\u5b57\u6216\u5b57\u7b26\u4e32\uff0c\u8fd4\u56deTrue\u6216False \u8fd0\u7b97\u7b26 == \u7528\u4e8e\u6bd4\u8f83\u6570\u636e\u7ed3\u6784\u91cc\u7684\u5185\u5bb9\uff0c\u8fd0\u7b97\u7b26 is \u7528\u4e8e\u6bd4\u8f83\u4e24\u4e2a\u5bf9\u8c61\u7684\u6807\u8bc6\u662f\u5426\u4e00\u81f4 \u903b\u8f91\u8fd0\u7b97\u7b26\uff1a and \u3001 or \u3001 not \u3002\u628a0\u3001None\u3001\u7a7a\u5b57\u7b26\u4e32\u3001\u7a7a\u5217\u8868\u7b49\u89c6\u4e3aFalse\uff0c\u5927\u591a\u6570\u5176\u4ed6\u503c\u662f\u4e3aTrue \u4e0b\u6807\u8fd0\u7b97\u7b26\uff1a [] \uff0c\u4e0e\u591a\u9879\u96c6collection\u5bf9\u8c61\u4e00\u8d77\u4f7f\u7528 \u9009\u62e9\u5668\u8fd0\u7b97\u7b26\uff1a . \uff0c\u7528\u4e8e\u5f15\u7528\u4e00\u4e2a\u6a21\u5757\u3001\u7c7b\u6216\u5bf9\u8c61\u4e2d\u7684\u4e00\u4e2a\u5177\u540d\u7684\u9879 \u8fd0\u7b97\u7b26\u4f18\u5148\u7ea7\uff0c\u4f9d\u6b21\u662f\u9009\u62e9\u8fd0\u7b97\u7b26\u3001\u51fd\u6570\u8c03\u7528\u8fd0\u7b97\u7b26\u3001\u4e0b\u6807\u8fd0\u7b97\u7b26\u3001\u7b97\u672f\u8fd0\u7b97\u7b26\u3001\u6bd4\u8f83\u8fd0\u7b97\u7b26\u3001\u903b\u8f91\u8fd0\u7b97\u7b26\u3001\u8d4b\u503c\u8fd0\u7b97\u7b26\u3002\u62ec\u53f7\u7528\u4e8e\u8ba9\u5b50\u8868\u8fbe\u5f0f\u4f18\u5148\u8fd0\u884c\u3002 1.1.4.\u51fd\u6570\u8c03\u7528 \u00b6 \u51fd\u6570\u540d\u79f0\u540e\u9762\u8ddf\u7740\u7528\u62ec\u53f7\u62ec\u8d77\u6765\u7684\u53c2\u6570\u5217\u8868\uff0c\u4f8b\u5982\uff1a min(5,2) \u6807\u51c6\u51fd\u6570 \u5176\u4ed6\u6a21\u5757\u5bfc\u5165\u51fd\u6570 1.1.5.print\u51fd\u6570 \u00b6 \u81ea\u52a8\u4e3a\u6bcf\u4e2a\u53c2\u6570\u8fd0\u884c str \u51fd\u6570\uff0c\u4ee5\u5f97\u5230\u5176\u5b57\u7b26\u4e32\u8868\u793a \u5728\u8f93\u51fa\u4e4b\u524d\u4f1a\u7528\u7a7a\u683c\u5427\u6bcf\u4e2a\u5b57\u7b26\u4e32\u9694\u5f00 \u9ed8\u8ba4\u4ee5\u6362\u884c\u7b26\u4f5c\u4e3a\u7ed3\u675f 1.1.6.input\u51fd\u6570 \u00b6 \u6807\u51c6\u8f93\u5165\u51fd\u6570input\u4f1a\u4e00\u76f4\u7b49\u5f85\u7528\u6237\u901a\u8fc7\u952e\u76d8\u8f93\u5165\u6587\u672c \u63a5\u53d7\u4e00\u4e2a\u53ef\u9009\u7684\u5b57\u7b26\u4e32\u4f5c\u4e3a\u5176\u53c2\u6570 1.1.7.\u7c7b\u578b\u8f6c\u6362\u51fd\u6570\u548c\u6df7\u5408\u6a21\u5f0f\u64cd\u4f5c \u00b6 Python\u5141\u8bb8\u7b97\u672f\u8868\u8fbe\u5f0f\u4e2d\u7684\u64cd\u4f5c\u6570\u5177\u6709\u4e0d\u540c\u7684\u6570\u503c\u7c7b\u578b\u3002\u4f8b\u5982\uff0c\u628aint\u7c7b\u578b\u7684\u64cd\u4f5c\u6570\u548cfloat\u7c7b\u578b\u7684\u64cd\u4f5c\u6570\u76f8\u52a0\uff0c\u4f1a\u5f97\u5230float\u7c7b\u578b\u7684\u6570\u3002 # \u8f93\u5165\u534a\u5f84\u6c42\u5706\u9762\u79ef radius = float ( input ( \"Radius: \" )) print ( \"The area is\" , 3.14 * radius ** 2 ) 1.1.8.\u53ef\u9009\u548c\u5173\u952e\u5b57\u51fd\u6570\u53c2\u6570 \u00b6 \u5fc5\u9009\u53c2\u6570\u662f\u6ca1\u6709\u9ed8\u8ba4\u503c\u7684\uff1b\u53ef\u9009\u53c2\u6570\u6709\u9ed8\u8ba4\u503c\uff1b \u5728\u8c03\u7528\u51fd\u6570\u65f6\uff0c\u4f20\u9012\u7ed9\u5b83\u7684\u53c2\u6570\u6570\u91cf\u5fc5\u987b\u81f3\u5c11\u548c\u5fc5\u9009\u53c2\u6570\u7684\u6570\u91cf\u76f8\u540c\u3002 \u6807\u51c6\u51fd\u6570\u548cPython\u7684\u5e93\u51fd\u6570\u5728\u8c03\u7528\u65f6\u90fd\u4f1a\u5bf9\u4f20\u5165\u7684\u53c2\u6570\u8fdb\u884c\u7c7b\u578b\u68c0\u67e5 1.1.9.\u53d8\u91cf\u548c\u8d4b\u503c\u8bed\u53e5 \u00b6 \u7b80\u5355\u7684\u8d4b\u503c\u8bed\u53e5 PI = 3.1416 \u591a\u53d8\u91cf\u8d4b\u503c minValue, maxValue = 1, 100 \u53d8\u91cf\u4ea4\u6362 a, b = b, a \u8d4b\u503c\u8bed\u53e5\u5fc5\u987b\u5199\u5728\u4e00\u884c\u4ee3\u7801\u91cc\uff0c\u4f46\u662f\u53ef\u4ee5\u5728\u9017\u53f7\u3001\u5706\u62ec\u53f7\u3001\u82b1\u62ec\u53f7\u6216\u65b9\u62ec\u53f7\u4e4b\u540e\u6362\u884c\uff0c\u6216\u8005\u7528\u8f6c\u4e49\u7b26 \\ \u8fdb\u884c\u6362\u884c\u3002 \u6362\u884c\u793a\u4f8b\uff1a minValue = min ( 100 , 200 ) product = max ( 100 , 200 ) \\ * 30 1.1.10.\u6570\u636e\u7c7b\u578b \u00b6 \u53d8\u91cf\u90fd\u53ef\u4ee5\u88ab\u6307\u5b9a\u4e3a\u4efb\u4f55\u7c7b\u578b\u7684\u503c\u3002\u8fd9\u4e9b\u53d8\u91cf\u5e76\u4e0d\u50cf\u5176\u4ed6\u8bed\u8a00\u90a3\u6837\u88ab\u58f0\u660e\u4e3a\u7279\u5b9a\u7684\u7c7b\u578b\uff0c\u800c\u53ea\u662f\u88ab\u8d4b\u4e86\u4e00\u4e2a\u503c \u503c\u548c\u5bf9\u8c61\u90fd\u662f\u6709\u7c7b\u578b\u7684\uff0c\u4f1a\u5728\u8fd0\u884c\u65f6\u8fdb\u884c\u6570\u636e\u7c7b\u578b\u68c0\u67e5 1.1.11. import \u8bed\u53e5 \u00b6 import \u8bed\u53e5\u4f7f\u5f97\u4e00\u4e2a\u6a21\u5757\u4e2d\u7684\u6807\u8bc6\u7b26\u53ef\u4ee5\u88ab\u53e6\u4e00\u4e2a\u7a0b\u5e8f\u6240\u89c1\u5230\u3002\u6807\u8bc6\u7b26\u53ef\u4ee5\u662f\u5bf9\u8c61\u540d\u3001\u51fd\u6570\u540d\u6216\u7c7b\u540d \u5bfc\u5165\u6a21\u5757\u540d\u79f0\uff0c\u4f8b\u5982 import math \u5bfc\u5165\u6a21\u5757\u4e2d\u7684\u6807\u8bc6\u7b26\uff0c\u4f8b\u5982\uff1a from math import sqrt \uff0c\u6216\u8005 from math import pi, sqrt \u4e5f\u53ef\u4ee5\u4f7f\u7528\u7b26\u53f7 * \u5bfc\u5165\u4e00\u4e2a\u6a21\u5757\u4e2d\u7684\u6240\u6709\u540d\u79f0\uff0c\u4f46\u4e0d\u63a8\u8350 1.2.\u63a7\u5236\u8bed\u53e5 \u00b6 1.2.1.\u6761\u4ef6\u8bed\u53e5 \u00b6 \u5355\u5411if\u8bed\u53e5\u7684\u8bed\u6cd5 if < Boolean expression > : < sequence of statements > \u53cc\u5411if\u8bed\u53e5\u7684\u8bed\u6cd5 if < Boolean expression > : < sequence of statements > else : < sequence of statements > \u591a\u5411if\u8bed\u53e5\u7684\u8bed\u6cd5 if < Boolean expression > : < sequence of statements > elif < Boolean expression > : < sequence of statements > ... else : < sequence of statements > 1.2.2.\u4f7f\u7528if name == \" main \" \u00b6 \u793a\u4f8b\u4ee3\u7801 numberguess.py \u3002 import random def main (): smaller = int ( input ( \"\u8f93\u5165\u6700\u5c0f\u503c: \" )) larger = int ( input ( \"\u8f93\u5165\u6700\u5927\u503c: \" )) myNumber = random . randint ( smaller , larger ) count = 0 while True : count += 1 userNumber = int ( input ( \"\u8f93\u5165\u4f60\u731c\u7684\u503c: \" )) if userNumber < myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5c0f\uff01\" ) elif userNumber > myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5927\uff01\" ) else : print ( \"\u606d\u559c\uff0c\u4f60\u5728\u7b2c\" , count , \"\u6b21\u731c\u5bf9\u4e86!\" ) break if __name__ == \"__main__\" : main () \u4e0a\u9762\u7684if\u8bed\u53e5\u7684\u4f5c\u7528\u662f\uff0c \u8981\u4e48\u5c06\u6a21\u5757\u5f53\u4f5c\u4e00\u4e2a\u72ec\u7acb\u7684\u7a0b\u5e8f\u8fd0\u884c\uff0c\u8be5\u6a21\u5757\u7684 _name_ \u53d8\u91cf\u4f1a\u8bbe\u7f6e\u4e3a\u5b57\u7b26\u4e32 _main_ \uff0c\u624d\u4f1a\u6267\u884c main() \u51fd\u6570 \u8981\u4e48\u4ece\u53e6\u4e00\u4e2a\u6a21\u5757\u4e2d\u5bfc\u5165\uff0c\u8be5\u6a21\u5757\u7684 _name_ \u53d8\u91cf\u4f1a\u8bbe\u7f6e\u8be5\u6a21\u5757\u7684\u540d\u79f0\uff0c\u4e0a\u4f8b\u4e2d\u5373 numberguess 1.2.3.\u5faa\u73af\u8bed\u53e5 \u00b6 \u901a\u5e38\uff1a \u4e00\u822c\u4f1a\u4f7f\u7528for\u5faa\u73af\u6765\u8fed\u4ee3\u786e\u5b9a\u8303\u56f4\u7684\u503c\u6216\u503c\u7684\u5e8f\u5217 \u5982\u679c\u7ee7\u7eed\u5faa\u73af\u7684\u6761\u4ef6\u662f\u67d0\u4e2a\u5e03\u5c14\u8868\u8fbe\u5f0f\uff0c\u4e00\u822c\u4f1a\u4f7f\u7528while\u5faa\u73af while \u8bed\u6cd5\u683c\u5f0f\uff1a while < Boolean expression > : < sequence of statements > \u793a\u4f8b\uff1a # \u8ba1\u7b97\u4ece1\u523010\u7684\u4e58\u79ef\u5e76\u8f93\u51fa\u7ed3\u679c result = 1 value = 1 while value <= 10 : result *= value value += 1 print ( result , value ) # \u8fd0\u884c\u7ed3\u679c # 3628800 11 for \u8bed\u6cd5\u683c\u5f0f\uff1a for < variable > in < iterable object > : < sequence of statements > \u793a\u4f8b\uff1a # \u8ba1\u7b97\u4ece1\u523010\u7684\u4e58\u79ef\u5e76\u8f93\u51fa\u7ed3\u679c result = 1 value = 1 for value in range ( 1 , 11 ): result *= value value += 1 print ( result , value ) # \u8fd0\u884c\u7ed3\u679c # 3628800 11 1.3.\u5b57\u7b26\u4e32\u53ca\u5176\u8fd0\u7b97 \u00b6 Python\u4e2d\u7684\u5b57\u7b26\u4e32\u4e5f\u662f\u4e00\u4e2a\u590d\u5408\u5bf9\u8c61 Python\u7684\u5b57\u7b26\u4e32\u7c7b\u578b\u540d\u4e3a str \u7ea6\u5b9a\uff1a \u628a\u5355\u5b57\u7b26\u7684\u5b57\u7b26\u4e32\u7528\u5355\u5f15\u53f7\u62ec\u8d77\u6765 \u628a\u591a\u5b57\u7b26\u7684\u5b57\u7b26\u4e32\u7528\u53cc\u5f15\u53f7\u62ec\u8d77\u6765 1.3.1.\u8fd0\u7b97\u7b26 \u00b6 \u6bd4\u8f83\u8fd0\u7b97\u7b26\uff0c\u662f\u6309\u7167ASCII\u7801\u7684\u987a\u5e8f\u6bd4\u8f83\u4e24\u4e2a\u5b57\u7b26\u4e32\u4e2d\u6bcf\u4e2a\u4f4d\u7f6e\u7684\u5b57\u7b26\u5bf9 \u793a\u4f8b\uff1a print ( 'A' > 'a' ) # \u8fd0\u884c\u7ed3\u679c False print ( 'A' < 'a' ) # \u8fd0\u884c\u7ed3\u679c True + \u8fd0\u7b97\u7b26\u751f\u6210\u5e76\u8fd4\u56de\u4e00\u4e2a\u5305\u542b\u4e24\u4e2a\u64cd\u4f5c\u6570\u7684\u65b0\u5b57\u7b26\u4e32 \u793a\u4f8b\uff1a print ( \"Hello\" + \"Python\" ) # \u8fd0\u884c\u7ed3\u679c HelloPython \u4e0b\u6807\u8fd0\u7b97\u7b26\uff0c\u8303\u56f4\u662f\u4ece0\u5230\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u51cf\u53bb1\u7684\u4e00\u4e2a\u6574\u6570\u3002 \u8fd0\u7b97\u7b26\u8fd4\u56de\u5728\u5b57\u7b26\u4e32\u4e2d\u8be5\u4f4d\u7f6e\u7684\u5b57\u7b26\u3002 \u793a\u4f8b\uff1a print ( \"Greater\" [ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1ar \u5f53\u7d22\u5f15\u4e3a\u8d1f\u503c\u65f6\uff0cPython\u4f1a\u628a\u8fd9\u4e2a\u503c\u548c\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u76f8\u52a0\uff0c\u4ee5\u786e\u5b9a\u8981\u8fd4\u56de\u7684\u5b57\u7b26\u7684\u4f4d\u7f6e\u3002\u8d1f\u7d22\u5f15\u503c\u4e0d\u5f97\u5c0f\u4e8e\u5b57\u7b26\u4e32\u957f\u5ea6\u7684\u8d1f\u503c\u3002 print ( \"Greater\" [ - 3 ]) # \u8fd0\u884c\u7ed3\u679c\uff1at print ( \"Greater\" [ - 9 ]) # \u8fd0\u884c\u7ed3\u679c\uff1aIndexError: string index out of range \u5207\u7247\u8fd0\u7b97\u7b26\uff08slice operator\uff09\uff0c\u4e0b\u6807\u8fd0\u7b97\u7b26\u7684\u4e00\u79cd\u53d8\u4f53\u3002 \u8bed\u6cd5\u683c\u5f0f\uff1a [:] \uff1a\u8303\u56f4\u662f\u4ece0\u5230\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u51cf\u53bb1\u7684\u6574\u6570 \uff1a\u8303\u56f4\u662f\u4ece0\u5230\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u7684\u6574\u6570 \u5207\u7247\u68c0\u7d22\u89c4\u5219\uff1a \u8fd4\u56de\u8fd9\u6837\u4e00\u4e2a\u5b50\u5b57\u7b26\u4e32\uff1a\u8fd9\u4e2a\u5b50\u5b57\u7b26\u4e32\u4f1a\u4ece \u7d22\u5f15\u5904\u7684\u5b57\u7b26\u5f00\u59cb\uff0c\u5230 \u7d22\u5f15\u51cf1\u7684\u4f4d\u7f6e\u4f5c\u4e3a\u7ed3\u675f\u3002 \u5982\u679c\u7701\u7565 \u7d22\u5f15\uff0c\u90a3\u4e48\u5207\u7247\u8fd0\u7b97\u7b26\u5c06\u8fd4\u56de\u4e00\u4e2a\u4ee5\u5f53\u524d\u5b57\u7b26\u4e32\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\u4f5c\u4e3a\u5f00\u5934\u7684\u5b50\u5b57\u7b26\u4e32\u3002 \u5982\u679c\u7701\u7565 \u7d22\u5f15\uff0c\u90a3\u4e48\u5207\u7247\u8fd0\u7b97\u7b26\u5c06\u8fd4\u56de\u4e00\u4e2a\u4ee5\u5f53\u524d\u5b57\u7b26\u4e32\u7684\u6700\u540e\u4e00\u4e2a\u5b57\u7b26\u4f5c\u4e3a\u7ed3\u5c3e\u7684\u5b50\u5b57\u7b26\u4e32\u3002 \u5982\u679c\u7701\u7565\u8fd9\u4e24\u4e2a\u503c\uff0c\u90a3\u4e48\u5207\u7247\u8fd0\u7b97\u7b26\u4f1a\u8fd4\u56de\u6574\u4e2a\u5b57\u7b26\u4e32\u3002 \u793a\u4f8b\uff1a print ( \"Greater\" [:]) # \u8fd4\u56de\u5b57\u4e32 Greater print ( \"Greater\" [ 2 :]) # \u8fd4\u56de\u5b57\u4e32 eater print ( \"Greater\" [: 2 ]) # \u8fd4\u56de\u5b57\u4e32 Gr print ( \"Greater\" [ 2 : 5 ]) # \u8fd4\u56de\u5b57\u4e32 eat 1.3.2.\u5b57\u7b26\u4e32\u683c\u5f0f\u5316 \u00b6 \u683c\u5f0f\u5316\u5b57\u7b26\u4e32\u91cc\u7684\u6570\u636e\u5b57\u7b26\u4ee5\u53ca\u6ee1\u8db3\u7ed9\u5b9a\u57fa\u51c6\u7ebf\u7684\u9644\u52a0\u7a7a\u683c\u7684\u603b\u6570\u79f0\u4e3a\u5b83\u7684\u5b57\u6bb5\u5bbd\u5ea6\uff08field width\uff09\u3002 print \u51fd\u6570\u4f1a\u5728\u9047\u5230\u7b2c\u4e00\u5217\u65f6\u81ea\u52a8\u5f00\u59cb\u6253\u5370\u8f93\u51fa\u57fa\u51c6\u7ebf\u3002 \u793a\u4f8b\uff0c\u901a\u8fc7print\u8bed\u53e5\u8f93\u51fa2\u5217\u3002 for i in range ( 7 , 11 ): print ( i , 10 * i ) # \u8fd0\u884c\u7ed3\u679c # 7 70 # 8 80 # 9 90 # 10 100 Python\u7684\u901a\u7528\u683c\u5f0f\u5316\u673a\u5236 \u8bed\u6cd5\u683c\u5f0f % \u548c % (, \u2026, ) \u3002 \u683c\u5f0f\u5316\u5b57\u7b26\u4e32\u65f6\uff0c \u4f7f\u7528 %s \u8868\u793a\u6cd5\u3002\u5f53\u5b57\u6bb5\u5bbd\u5ea6\u4e3a\u6b63\u65f6\uff0c\u6570\u636e\u662f\u53f3\u5bf9\u9f50\u7684\uff1b\u5f53\u5b57\u6bb5\u5bbd\u5ea6\u4e3a\u8d1f\u65f6\uff0c\u6570\u636e\u662f\u5de6\u5bf9\u9f50\u7684\u3002 \u683c\u5f0f\u6574\u6570\u65f6\uff0c \u4f7f\u7528 %d \u8868\u793a\u6cd5\u3002 \u683c\u5f0f\u6d6e\u70b9\u6570\u65f6\uff0c \u4f7f\u7528 %.f \u8868\u793a\u6cd5\uff0c\u5176\u4e2d . \u8fd9\u4e00\u90e8\u5206\u662f\u53ef\u9009\u7684\u3002 \u793a\u4f8b\uff1a print ( \" %6s \" % \"four\" ) print ( \" %-6s \" % \"four\" ) # four # four for i in range ( 7 , 11 ): print ( \" %-3d%5d \" % ( i , 10 * i )) # 7 70 # 8 80 # 9 90 # 10 100 for i in range ( 7 , 11 ): print ( \" %-3d%5.3f \" % ( i , i / 3 )) # 7 2.333 # 8 2.667 # 9 3.000 # 10 3.333 \u4e0b\u4f8b\u5bf9\u6bd4\u4e86\u6d6e\u70b9\u6570\u5728\u4f7f\u7528\u4e86\u683c\u5f0f\u5b57\u7b26\u4e32\u548c\u6ca1\u6709\u4f7f\u7528\u683c\u5f0f\u5b57\u7b26\u4e32\u8fd9\u4e24\u79cd\u60c5\u51b5\u4e0b\u7684\u8f93\u51fa\u5dee\u5f02\u3002 salary = 100.00 print ( \"Salary: $\" + str ( salary )) # Salary: $100.0 print ( \"Salary: $ %0.2f \" % salary ) # Salary: $100.00 \u6ce8\u610f\uff0c\u4e0b\u4f8b\u4e2dPython\u7ed9\u6570\u5b57\u6dfb\u52a0\u4e86\u4e00\u4e2a\u7cbe\u5ea6\u4f4d\u6570\uff0c\u5e76\u4e14\u5176\u5de6\u4fa7\u586b\u5145\u7a7a\u683c\uff0c\u4ece\u800c\u5b9e\u73b0\u4e86\u5b57\u6bb5\u5bbd\u5ea6\u4e3a6\u3001\u7cbe\u5ea6\u4e3a3\u7684\u8bbe\u7f6e\u3002\u8fd9\u4e2a\u5bbd\u5ea6\u5305\u542b\u5c0f\u6570\u70b9\u540e\u6240\u5360\u636e\u7684\u4f4d\u7f6e\u3002 print ( \" %6.3f \" % 3.14 ) # \u5de6\u4fa7\u586b\u5145\u4e86\u7a7a\u683c # 3.140 print ( \" %-6.3f \" % 3.14 ) # 3.140 1.3.3.\u5bf9\u8c61\u548c\u65b9\u6cd5\u8c03\u7528 \u00b6 \u8bed\u6cd5\u683c\u5f0f\uff1a .() \u793a\u4f8b\uff1a print ( \"greater\" . isupper ()) # \u8fd0\u884c\u7ed3\u679c # False print ( \"greater\" . upper ()) # \u8fd0\u884c\u7ed3\u679c # GREATER print ( \"greater\" . startswith ( \"great\" )) # \u8fd0\u884c\u7ed3\u679c # True print ( len ( \"greater\" )) print ( \"greater\" . __len__ ()) # \u8fd0\u884c\u7ed3\u679c # 7 print ( \"great\" + \"er\" ) print ( \"great\" . __add__ ( \"er\" )) # \u8fd0\u884c\u7ed3\u679c # greater print ( \"e\" in \"great\" ) print ( \"great\" . __contains__ ( \"e\" )) # \u8fd0\u884c\u7ed3\u679c # True \u63d0\u793a\uff1a dir() \u65b9\u6cd5\u4f1a\u8fd4\u56de\u6240\u4f20\u9012\u7684\u5bf9\u8c61\u7684\u6709\u6548\u5c5e\u6027\uff0c\u8bed\u6cd5\u683c\u5f0f\uff1a dir(object) help() \u51fd\u6570\u67e5\u770b\u51fd\u6570\u6216\u6a21\u5757\u7528\u9014\u7684\u8be6\u7ec6\u8bf4\u660e\uff0c\u8bed\u6cd5\u683c\u5f0f\uff1a help(object) dir ( str ) help ( str . __contains__ ) 1.4.\u5185\u7f6e\u591a\u9879\u96c6\u53ca\u5176\u64cd\u4f5c \u00b6 Python\u4e2d\u7684\u591a\u9879\u96c6\uff08collections\uff09\u6307\u80fd\u591f\u5305\u542b\u5143\u7d20\u7684\u6570\u636e\u7ed3\u6784\u3002\u591a\u9879\u96c6\u6a21\u5757\u63d0\u4f9b\u4e86\u4e0d\u540c\u7c7b\u578b\u7684\u5bb9\u5668\u3002\u5bb9\u5668\u662f\u7528\u4e8e\u5b58\u50a8\u4e0d\u540c\u5bf9\u8c61\u5e76\u63d0\u4f9b\u8bbf\u95ee\u6240\u5305\u542b\u5bf9\u8c61\u4ee5\u53ca\u5bf9\u5b83\u4eec\u8fdb\u884c\u8fed\u4ee3\u7684\u65b9\u5f0f\u7684\u5bf9\u8c61\u3002\u4e00\u4e9b\u5185\u7f6e\u7684\u5bb9\u5668\u6709\u5143\u7ec4\uff08Tuple\uff09\u3001\u5217\u8868\uff08List\uff09\u3001\u5b57\u5178\uff08Dictionary\uff09\u7b49\u3002 \u4ee5\u4e0b\u662f\u7531collections\u6a21\u5757\u63d0\u4f9b\u7684\u4e0d\u540c\u5bb9\u5668\u7684\u5217\u8868\uff1a \u8ba1\u6570\u5668\uff08Counters\uff09 \u6709\u5e8f\u5b57\u5178\uff08OrderedDict\uff09 \u9ed8\u8ba4\u5b57\u5178\uff08DefaultDict\uff09 \u94fe\u6620\u5c04\uff08ChainMap\uff09 \u547d\u540d\u5143\u7ec4\uff08NamedTuple\uff09 \u53cc\u5411\u961f\u5217\uff08DeQue\uff09 \u7528\u6237\u5b57\u5178\uff08UserDict\uff09 \u7528\u6237\u5217\u8868\uff08UserList\uff09 \u7528\u6237\u5b57\u7b26\u4e32\uff08UserString\uff09 1.4.1.\u5217\u8868 \u00b6 \u5217\u8868\uff08list\uff09\u662f\u96f6\u4e2a\u6216\u591a\u4e2aPython\u5bf9\u8c61\u7684\u4e00\u4e2a\u5e8f\u5217\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u901a\u5e38\u79f0\u4e3a\u9879\uff08item\uff09\u3002 \u5217\u8868\u7684\u8868\u73b0\u5f62\u5f0f\u662f\uff1a\u7528\u65b9\u62ec\u53f7\u62ec\u8d77\u6574\u4e2a\u5217\u8868\uff0c\u5e76\u7528\u9017\u53f7\u5206\u9694\u5143\u7d20\u3002 \u793a\u4f8b\uff1a [] # \u7a7a\u5217\u8868 [ \"greater\" , \"less\" , 10 ] # \u542b\u4e0d\u540c\u7c7b\u578b\u7684\u5217\u8868 [ \"greater\" , [ \"less\" , 10 ]] # \u542b\u5185\u5d4c\u5217\u8868\u7684\u5217\u8868 \u5217\u8868\u7684\u5207\u7247\u64cd\u4f5c\uff1a \u548c\u5b57\u7b26\u4e32\u7c7b\u4f3c\uff0c\u53ef\u4ee5\u901a\u8fc7\u6807\u51c6\u8fd0\u7b97\u7b26\u6267\u884c\u5207\u7247\u6216\u8fde\u63a5\u64cd\u4f5c\uff0c\u8fd4\u56de\u7ed3\u679c\u4e5f\u662f\u5217\u8868\u3002 \u548c\u5b57\u7b26\u4e32\u4e0d\u540c\uff0c\u5217\u8868\u662f\u53ef\u53d8\u7684\uff0c\u5373\uff0c\u53ef\u4ee5\u66ff\u6362\u3001\u63d2\u5165\u6216\u5220\u9664\u5217\u8868\u4e2d\u6240\u5305\u542b\u7684\u9879\u3002 \u5207\u7247\u548c\u8fde\u63a5\u8fd0\u7b97\u7b26\u6240\u8fd4\u56de\u7684\u5217\u8868\u662f\u65b0\u7684\u5217\u8868\uff0c\u800c\u4e0d\u662f\u6700\u521d\u5217\u8868\u7684\u4e00\u90e8\u5206\uff1b \u5217\u8868\u7c7b\u578b\u5305\u542b\u4e86\u51e0\u4e2a\u53eb\u4f5c\u53d8\u5f02\u5668\uff08mutator\uff09\u7684\u65b9\u6cd5\uff0c\u7528\u4e8e\u4fee\u6539\u5217\u8868\u7684\u7ed3\u6784\u3002 \u53ef\u4ee5\u901a\u8fc7 dir(list) \u6765\u67e5\u770b\u65b9\u6cd5\uff0c\u5305\u62ec\u53d8\u5f02\u5668\uff08mutator\uff09\u7684\u65b9\u6cd5\u3002 dir ( list ) # \u8fd0\u884c\u7ed3\u679c # ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] \u6700\u5e38\u7528\u7684\u5217\u8868\u53d8\u5f02\u5668\u65b9\u6cd5\u662f append \u3001 insert \u3001 pop \u3001 remove \u548c sort \u3002 \u793a\u4f8b\uff1a myList = [] # myList\u5f53\u524d\u4e3a[] myList . append ( 34 ) # myList\u5f53\u524d\u4e3a[34]\uff0c\u9ed8\u8ba4\u5c3e\u90e8\u63d2\u5165 myList . append ( 22 ) # myList\u5f53\u524d\u4e3a[34, 22]\uff0c\u9ed8\u8ba4\u5c3e\u90e8\u63d2\u5165 myList . sort () # myList\u5f53\u524d\u4e3a[22, 34] myList . pop () # \u9ed8\u8ba4\u4ece\u7d22\u5f15\u4f4d[0]\u5220\u9664\uff0c\u8fd4\u56de\u7ed3\u679c22\uff1bmyList\u5f53\u524d\u4e3a[34] myList . insert ( 0 , 22 ) # \u5728\u6307\u5b9a\u7d22\u5f15\u4f4d[0]\u63d2\u5165\uff1bmyList\u5f53\u524d\u4e3a[22, 34] myList . insert ( 1 , 55 ) # \u5728\u6307\u5b9a\u7d22\u5f15\u4f4d[1]\u63d2\u5165\uff1bmyList\u5f53\u524d\u4e3a[22, 55, 34] myList . pop ( 1 ) # \u6307\u5b9a\u7d22\u5f15\u4f4d[1]\u5220\u9664\uff0c\u8fd4\u56de\u7ed3\u679c55\uff1bmyList\u5f53\u524d\u4e3a[22, 34] myList . remove ( 22 ) # \u5220\u9664\u9996\u4e2a\u5339\u914d\u9879\u7684\u5143\u7d20[22]\uff1bmyList\u5f53\u524d\u4e3a[34] myList . remove ( 55 ) # \u62a5ValueError\u9519\uff0clist.remove(x): x not in list \u5bf9\u4e8e\u5b57\u7b26\u4e32\uff0csplit\u65b9\u6cd5\u4f1a\u4ece\u5b57\u7b26\u4e32\u91cc\u5206\u79bb\u51fa\u4e00\u4e2a\u5355\u8bcd\u5217\u8868\uff0c\u800cjoin\u65b9\u6cd5\u4f1a\u628a\u5355\u8bcd\u5217\u8868\u8fde\u5728\u4e00\u8d77\u4ece\u800c\u5f62\u6210\u5b57\u7b26\u4e32\u3002\u4f8b\u5982\uff1a print ( \"Python is cool\" . split ()) # \u8fd0\u884c\u7ed3\u679c\uff1a # ['Python', 'is', 'cool'] print ( \" \" . join ([ \"Python\" , \"is\" , \"cool\" ])) # \u8fd0\u884c\u7ed3\u679c\uff1a # Python is cool \u5bf9\u4e8e\u5217\u8868\u7279\u6027\u548c\u64cd\u4f5c\u7684\u8be6\u7ec6\u7ec3\u4e60\uff0c\u53c2\u8003 Python\u8bed\u8a00\u57fa\u7840@github \u6216\u8005 Python\u8bed\u8a00\u57fa\u7840@web \u4e2d\u201c1.3 \u5217\u8868\uff08list\uff09\u201d\u7684\u5185\u5bb9\u3002 1.4.2.\u5143\u7ec4 \u00b6 \u5143\u7ec4\uff08tuple\uff09\u662f\u4e00\u4e2a\u4e0d\u53ef\u53d8\u7684\u5143\u7d20\u5e8f\u5217\u3002 \u5143\u7ec4\uff08tuple\uff09\u5f62\u5f0f\u662f\u7528\u5706\u62ec\u53f7\u5c06\u5404\u9879\u62ec\u8d77\u6765\uff0c\u5e76\u4e14\u5fc5\u987b\u81f3\u5c11\u5305\u542b\u4e24\u4e2a\u9879\u3002 \u5143\u7ec4\u5b9e\u9645\u4e0a\u5c31\u50cf\u5217\u8868\u4e00\u6837\uff0c\u53ea\u4e0d\u8fc7\u5b83\u6ca1\u6709\u53d8\u5f02\u5668\u65b9\u6cd5\u3002 \u5982\u679c\u8981\u4f7f\u5143\u7ec4\u53ea\u5305\u542b\u4e00\u4e2a\u5143\u7d20\uff0c\u5219\u5fc5\u987b\u5728\u5143\u7ec4\u91cc\u5305\u542b\u9017\u53f7\u3002 \u5bf9\u6bd4\u4e0b\u9762\u7684\u533a\u522b\uff1a print (( 21 )) # (21)\u88ab\u89c6\u4e3a\u6574\u6570 # \u8fd0\u884c\u7ed3\u679c\uff1a # 21 print (( 21 ,)) # (21,)\u88ab\u89c6\u4e3a\u5143\u7ec4 # \u8fd0\u884c\u7ed3\u679c\uff1a # (21,) \u5bf9\u4e8e\u5217\u8868\u7279\u6027\u548c\u64cd\u4f5c\u7684\u8be6\u7ec6\u7ec3\u4e60\uff0c\u53c2\u8003 Python\u8bed\u8a00\u57fa\u7840@github \u6216\u8005 Python\u8bed\u8a00\u57fa\u7840@web \u4e2d\u201c1.6 \u5143\u7ec4\uff08tuple\uff09\u201d\u7684\u5185\u5bb9\u3002 1.4.3.\u5e8f\u5217\u904d\u5386 \u00b6 for \u5faa\u73af\u53ef\u4ee5\u7528\u6765\u904d\u5386\u5e8f\u5217\uff08\u5982\u5b57\u7b26\u4e32\u3001\u5217\u8868\u6216\u5143\u7ec4\uff09\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002 \u904d\u5386\u5217\u8868\uff1a myList = [ 67 , 100 , 'Monday' , \"It's good\" ] for item in myList : print ( item ) myList = [ 67 , 100 , 'Monday' , \"It's good\" ] for idx in range ( len ( myList )): print ( myList [ idx ]) \u904d\u5386\u5143\u7ec4\uff1a myString = \"I love Python\" myList = myString . split () myTuple = tuple ( myList ) for i in myTuple : print ( i ) \u904d\u5386\u5b57\u7b26\u4e32\uff1a(\u6ce8\u610f\uff0c\u662f\u904d\u5386\u5b57\u7b26\uff0c\u4e0d\u662f\u5355\u8bcd) myString = \"I love Python\" for i in myString : print ( i ) myString = \"I love Python\" for i in range ( len ( myString )): print ( myString [ i ]) myString = \"I love Python\" for i in enumerate ( myString ): print ( i ) myString = \"I love Python\" for i , j in enumerate ( myString ): print ( i , j ) myString = \"I love Python\" for i in iter ( myString ): print ( i ) \u5982\u679c\u6309\u7167\u5355\u8bcd\u904d\u5386\u5b57\u7b26\u4e32\uff0c\u5219\u9700\u8981\u5148\u628a\u5b57\u4e32\u6309\u5355\u8bcd\u62c6\u89e3\u4e3a\u5217\u8868\u3002 myString = \"I love Python\" myList = \"I love Python\" . split () for i in myList : print ( i ) \u5bf9\u4e8e\u5217\u8868\u548c\u5143\u7ec4\u904d\u5386\u7684\u66f4\u591a\u4f8b\u5b50\uff0c\u5305\u62ec\u62c6\u5305\u904d\u5386\uff0c\u53c2\u8003 Python\u8bed\u8a00\u57fa\u7840@github \u6216\u8005 Python\u8bed\u8a00\u57fa\u7840@web \u7684\u5185\u5bb9\u3002 1.4.4.\u5b57\u5178 \u00b6 \u5b57\u5178\uff08dictionary\uff09\u5305\u542b\u96f6\u4e2a\u6216\u591a\u4e2a\u6761\u76ee\u3002 \u6bcf\u4e2a\u6761\u76ee\uff08entry\uff09\u90fd\u6709\u552f\u4e00\u7684\u952e\u548c\u5b83\u6240\u5bf9\u5e94\u7684\u503c\u76f8\u5173\u8054\u3002 \u952e\u901a\u5e38\u662f\u5b57\u7b26\u4e32\u6216\u6574\u6570\uff0c\u800c\u503c\u662f\u4efb\u610f\u7684Python\u5bf9\u8c61\u3002 \u4e0b\u6807\u8fd0\u7b97\u7b26\u53ef\u4ee5\u7528\u4e8e\u8bbf\u95ee\u4e00\u4e2a\u7ed9\u5b9a\u952e\u7684\u503c\uff0c\u7ed9\u4e00\u4e2a\u65b0\u952e\u6dfb\u52a0\u4e00\u4e2a\u503c\uff0c\u4ee5\u53ca\u66ff\u6362\u7ed9\u5b9a\u952e\u7684\u503c\u3002 pop \u65b9\u6cd5\u4f1a\u5220\u9664\u4e00\u4e2a\u6761\u76ee\u5e76\u8fd4\u56de\u7ed9\u5b9a\u952e\u6240\u5bf9\u5e94\u7684\u503c\u3002 keys \u65b9\u6cd5\u4f1a\u628a\u6240\u6709\u952e\u8fd4\u56de\u6210\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 values \u65b9\u6cd5\u4f1a\u628a\u6240\u6709\u503c\u8fd4\u56de\u6210\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 \u793a\u4f8b\uff1a {} # \u7a7a\u5b57\u5178 { \"name\" : \"Ken\" } # \u542b\u4e00\u4e2a\u6761\u76ee { \"name\" : \"Ken\" , \"age\" : 67 } # \u542b\u4e8c\u4e2a\u6761\u76ee { \"hobbies\" :[ \"reading\" , \"running\" ]} # \u542b\u4e00\u4e2a\u6761\u76ee\uff0c\u5176\u4e2d\u503c\u662f\u4e00\u4e2a\u5217\u8868 \u5b57\u5178\u672c\u8eab\u4e5f\u662f\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002\u53ef\u4ee5\u901a\u8fc7for\u8bed\u53e5\u8fdb\u884c\u904d\u5386\u952e\u6216/\u548c\u503c\u3002 myDict = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } for keys in myDict : print ( keys , myDict [ keys ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # name Ming # id 1001 # age 35 1.4.5.\u503c\u68c0\u7d22 \u00b6 \u53ef\u4ee5\u5728\u5b57\u7b26\u4e32\u5217\u8868\u3001\u5143\u7ec4\u6216\u5b57\u5178\u91cc\u901a\u8fc7 in \u8fd0\u7b97\u7b26\u6765\u5bf9\u503c\u6216\u591a\u9879\u96c6\u8fdb\u884c\u641c\u7d22\uff0c\u8fd4\u56de True \u6216 False \u3002\u5bf9\u4e8e\u5b57\u5178\u6765\u8bf4\uff0c\u641c\u7d22\u7684\u76ee\u6807\u503c\u5e94\u8be5\u662f\u4e00\u4e2a\u952e\u3002 \u5982\u679c\u5df2\u77e5\u7ed9\u5b9a\u503c\u5b58\u5728\u4e8e\u5e8f\u5217\uff08\u5b57\u7b26\u4e32\u3001\u5217\u8868\u6216\u5143\u7ec4\uff09\u91cc\uff0c\u90a3\u4e48 index \u65b9\u6cd5\u5c06\u8fd4\u56de\u8fd9\u4e2a\u503c\u6240\u51fa\u73b0\u7684\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3002 \u5217\u8868\u68c0\u7d22\uff1a myString = \"I love Python\" myList = myString . split () print ( myList ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ['I', 'love', 'Python'] print ( myList . index ( 'love' )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 1 \u5143\u7ec4\u68c0\u7d22\uff1a myString = \"I love Python\" myList = myString . split () myTuple = tuple ( myList ) print ( myTuple ) print ( myTuple . index ( 'love' )) \u5b57\u5178\u68c0\u7d22\uff1a myDict = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } print ( myDict ) for keys in myDict : print ( keys , myDict [ keys ]) myDict . pop ( 'city' ) # \u62a5\u9519\uff0cKeyError: 'city' myDict . pop ( 'id' ) print ( myDict ) # \u8fd0\u884c\u7ed3\u679c\uff1a{'name': 'Ming', 'age': 35} 1.4.6.\u6a21\u5f0f\u5339\u914d\u8bbf\u95ee\u591a\u9879\u96c6 \u00b6 \u4e0b\u6807\u8fd0\u7b97\u7b26\u53ef\u4ee5\u7528\u6765\u8bbf\u95ee\u5217\u8868\u3001\u5143\u7ec4\u548c\u5b57\u5178\u91cc\u7684\u5143\u7d20\u3002 \u901a\u8fc7\u6a21\u5f0f\u5339\u914d\u53ef\u4ee5\u4e00\u6b21\u8bbf\u95ee\u591a\u4e2a\u5143\u7d20\u3002 \u793a\u4f8b\uff1a myTuple \u662f\u4e00\u4e2a\u542b\u5185\u5d4c\u5143\u7ec4\u7684\u5143\u7ec4\u3002 myTuple = (( 'r' , 'g' , 'b' ), 'hexString' ) print ( myTuple ) # \u8fd0\u884c\u7ed3\u679c\uff1a # (('r', 'g', 'b'), 'hexString') print ( myTuple [ 0 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # ('r', 'g', 'b') print ( myTuple [ 0 ][ 0 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # r print ( myTuple [ 0 ][ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # g print ( myTuple [ 0 ][ 2 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # b print ( myTuple [ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # hexString \u901a\u8fc7\u4e0a\u9762\u7684\u62c6\u89e3\uff0c\u6211\u4eec\u6e05\u695a\u4e86\u5185\u5d4c\u5143\u7ec4\u7684\u7ed3\u6784\u8be6\u7ec6\u60c5\u51b5\u3002 \u4e0b\u9762\uff0c\u6211\u4eec\u901a\u8fc7\u6a21\u5f0f\u5339\u914d\uff0c\u628a\u4e00\u4e2a\u7ed3\u6784\u5206\u914d\u7ed9\u5f62\u5f0f\u5b8c\u5168\u76f8\u540c\u7684\u53e6\u4e00\u4e2a\u7ed3\u6784\u3002\u8fd9\u91cc\u76ee\u6807\u7ed3\u6784 newTuple \u6240\u5305\u542b\u7684\u53d8\u91cf\u4ece\u6e90\u7ed3\u6784 (('r', 'g', 'b'), 'hexString') \u91cc\u7684\u76f8\u5e94\u4f4d\u7f6e\u5904\u83b7\u5f97\u5bf9\u5e94\u7684\u503c\u3002 newTuple = (( 'r' , 'g' , 'b' ), 'hexString' ) print ( newTuple [ 0 ]) # ('r', 'g', 'b') print ( newTuple [ 0 ][ 0 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # r print ( newTuple [ 0 ][ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # g print ( newTuple [ 0 ][ 2 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # b print ( newTuple [ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # hexString 1.5.\u521b\u5efa\u51fd\u6570 \u00b6 Python\u652f\u6301\u5b8c\u5168\u51fd\u6570\u5f0f\u7f16\u7a0b\u8bbe\u8ba1\u3002 Python\u5305\u542b\u5f88\u591a\u5185\u7f6e\u51fd\u6570\u3002 Python\u4e5f\u8fd0\u884c\u521b\u5efa\u65b0\u51fd\u6570\uff0c\u53ef\u4ee5\u4f7f\u7528\u9012\u5f52\uff0c\u628a\u51fd\u6570\u4f5c\u4e3a\u6570\u636e\u8fdb\u884c\u4f20\u9012\u548c\u8fd4\u56de\u3002 1.5.1.\u51fd\u6570\u5b9a\u4e49 \u00b6 \u51fd\u6570\u5b9a\u4e49\u8bed\u6cd5\uff1a \u547d\u540d\u51fd\u6570\u540d\u79f0\u548c\u53c2\u6570\u540d\u79f0\u7684\u89c4\u5219\u4e0e\u60ef\u4f8b\u4e0e\u547d\u540d\u53d8\u91cf\u7684\u662f\u76f8\u540c\u7684\u3002 \u5fc5\u9009\u53c2\u6570\u7684\u5217\u8868\u53ef\u4ee5\u4e3a\u7a7a\uff0c\u4e5f\u53ef\u4ee5\u5305\u542b\u7528\u9017\u53f7\u9694\u5f00\u7684\u540d\u79f0\u3002 \u4e0e\u5176\u4ed6\u7f16\u7a0b\u8bed\u8a00\u4e0d\u540c\u7684\u662f\uff0c\u53c2\u6570\u540d\u79f0\u6216\u51fd\u6570\u540d\u79f0\u672c\u8eab\u5e76\u4e0d\u4f1a\u548c\u6570\u636e\u7c7b\u578b\u8fdb\u884c\u5173\u8054\u3002 def < function name > ( < list of parameters > ): < sequence of statements > \u793a\u4f8b\uff1a \u5728\u51fd\u6570\u7684\u6807\u9898\u4e0b\u6709\u4e00\u884c\u7528\u4e09\u5f15\u53f7\u62ec\u8d77\u6765\u7684\u5b57\u7b26\u4e32 \u8fd4\u56den\u7684\u5e73\u65b9\u6570 \uff0c\u8fd9\u662f\u4e00\u4e2a\u6587\u6863\u5b57\u7b26\u4e32\uff08docstring\uff09\u3002 \u5728shell\u91cc\u9762\u8f93\u5165help(square)\u65f6\uff0c\u4f1a\u663e\u793a\u8fd9\u4e2a\u5b57\u7b26\u4e32\u3002 \u5b9a\u4e49\u7684\u6bcf\u4e00\u4e2a\u51fd\u6570\u90fd\u5e94\u8be5\u6709\u6587\u6863\u5b57\u7b26\u4e32\uff0c\u6765\u8bf4\u660e\u8be5\u51fd\u6570\u7684\u529f\u80fd\uff0c\u5e76\u63d0\u4f9b\u76f8\u5173\u7684\u6240\u6709\u53c2\u6570\u4ee5\u53ca\u8fd4\u56de\u503c\u7684\u4fe1\u606f\u3002 \u51fd\u6570\u7684\u53c2\u6570\u548c\u4e34\u65f6\u53d8\u91cf\u53ea\u4f1a\u5728\u51fd\u6570\u8c03\u7528\u7684\u751f\u5b58\u5468\u671f\u5185\u5b58\u5728\uff0c\u5e76\u4e14\u5bf9\u5176\u4ed6\u51fd\u6570\u53ca\u5176\u5916\u56f4\u7a0b\u5e8f\u90fd\u662f\u4e0d\u53ef\u89c1\u7684\u3002 n \u662f\u53c2\u6570\u3002 result \u662f\u4e34\u65f6\u53d8\u91cf\u3002 \u5982\u679c\u51fd\u6570\u4e0d\u5305\u542b return \u8bed\u53e5\u65f6\uff0c\u5b83\u5c06\u5728\u6700\u540e\u4e00\u6761\u8bed\u53e5\u6267\u884c\u4e4b\u540e\u81ea\u52a8\u8fd4\u56de None \u503c\u3002 \u7528 = \u628a\u53c2\u6570\u6307\u5b9a\u4e3a\u6709\u9ed8\u8ba4\u503c\u7684\u53ef\u9009\u53c2\u6570\u3002 \u5728\u53c2\u6570\u5217\u8868\u4e2d\uff0c\u5fc5\u9009\u53c2\u6570\uff08\u6ca1\u6709\u9ed8\u8ba4\u503c\u7684\u53c2\u6570\uff09\u5fc5\u987b\u4f4d\u4e8e\u53ef\u9009\u53c2\u6570\u4e4b\u524d\u3002 def square ( n ): \"\"\"\u8fd4\u56den\u7684\u5e73\u65b9\u6570\"\"\" result = n ** 2 return result print ( square ( 5 )) 1.5.2.\u51fd\u6570\u9012\u5f52 \u00b6 \u9012\u5f52\u51fd\u6570\uff08recursive function\uff09\u662f\u6307\u4f1a\u8c03\u7528\u81ea\u8eab\u7684\u51fd\u6570\u3002 \u4e3a\u4e86\u9632\u6b62\u51fd\u6570\u65e0\u9650\u5730\u91cd\u590d\u8c03\u7528\u81ea\u8eab\uff0c\u4ee3\u7801\u4e2d\u5fc5\u987b\u81f3\u5c11\u6709\u4e00\u6761\u7528\u6765\u67e5\u9a8c\u6761\u4ef6\u7684\u9009\u62e9\u8bed\u53e5\uff0c\u7528\u4e8e\u786e\u5b9a\u63a5\u4e0b\u6765\u8981\u7ee7\u7eed\u9012\u5f52\u8fd8\u662f\u505c\u6b62\u9012\u5f52\u3002\u8fd9\u4e2a\u68c0\u67e5\u6761\u4ef6\u8bed\u53e5\u79f0\u4e3a\u57fa\u672c\u60c5\u51b5\uff08base case\uff09\u3002 \u793a\u4f8b\uff1a\u4e0b\u9762\u662f\u901a\u8fc7\u5faa\u73af\u5b9e\u73b0\u8f93\u51fa\u4ece\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u548c\u3002 def mySum ( lower , upper ): \"\"\"\u5bf9\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u6c42\u548c; lower:\u6700\u5c0f\u503c; upper:\u6700\u5927\u503c;\"\"\" result = 0 while ( lower <= upper ): result = result + lower lower += 1 return result print ( mySum ( 1 , 10 )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 55 \u7528\u9012\u5f52\u51fd\u6570\u6539\u5199\u4e0a\u8ff0\u51fd\u6570\u3002 def mySum ( lower , upper ): \"\"\"\u5bf9\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u6c42\u548c; lower:\u6700\u5c0f\u503c; upper:\u6700\u5927\u503c;\"\"\" if lower <= upper : return lower + mySum ( lower + 1 , upper ) else : return 0 print ( mySum ( 1 , 10 )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 55 \u901a\u5e38\u6765\u8bf4\uff0c\u9012\u5f52\u51fd\u6570\u81f3\u5c11\u6709\u4e00\u4e2a\u53c2\u6570\u3002 \u8fd9\u4e2a\u53c2\u6570\u7684\u503c\u4f1a\u88ab\u7528\u6765\u5bf9\u9012\u5f52\u8fc7\u7a0b\u7684\u57fa\u672c\u60c5\u51b5\u8fdb\u884c\u5224\u5b9a\uff0c\u4ece\u800c\u51b3\u5b9a\u662f\u5426\u8981\u7ed3\u675f\u6574\u4e2a\u8c03\u7528\u3002 \u5728\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u4e4b\u524d\uff0c\u8fd9\u4e2a\u503c\u4e5f\u4f1a\u88ab\u8fdb\u884c\u67d0\u79cd\u65b9\u5f0f\u7684\u4fee\u6539\u3002 \u6bcf\u6b21\u5bf9\u8fd9\u4e2a\u503c\u7684\u4fee\u6539\uff0c\u90fd\u5e94\u8be5\u4ea7\u751f\u4e00\u4e2a\u65b0\u6570\u636e\u503c\uff0c\u53ef\u4ee5\u8ba9\u51fd\u6570\u6700\u7ec8\u8fbe\u5230\u57fa\u672c\u60c5\u51b5\u3002 \u4e3a\u4e86\u5bf9 mySum \u51fd\u6570\u7684\u9012\u5f52\u8fdb\u884c\u8ddf\u8e2a\uff0c\u53ef\u4ee5\u5c1d\u8bd5\u6dfb\u52a0\u4e00\u4e2a\u4ee3\u8868\u7f29\u8fdb\u8fb9\u8ddd\u7684\u53c2\u6570\u5e76\u4e14\u6dfb\u52a0\u4e00\u4e9bprint\u8bed\u53e5\u3002\u8fd9\u6837\u5728\u6bcf\u6b21\u8c03\u7528\u65f6\uff0c\u51fd\u6570\u7684\u7b2c\u4e00\u6761\u8bed\u53e5\u4f1a\u8ba1\u7b97\u7f29\u8fdb\u6570\u91cf\uff0c\u7136\u540e\u518d\u6253\u5370\u4e24\u4e2a\u53c2\u6570\u7684\u503c\uff0c\u6bcf\u6b21\u8fd4\u56de\u8c03\u7528\u4e4b\u524d\u7684\u8fd4\u56de\u503c\u65f6\u90fd\u4f7f\u7528\u76f8\u540c\u7684\u7f29\u8fdb\uff0c\u5c31\u53ef\u4ee5\u5b9e\u73b0\u5bf9\u4e24\u4e2a\u53c2\u6570\u7684\u503c\u4ee5\u53ca\u6bcf\u6b21\u8c03\u7528\u7684\u8fd4\u56de\u503c\u8fdb\u884c\u8ddf\u8e2a\u3002 def mySum ( lower , upper , margin = 0 ): \"\"\"\u5bf9\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u6c42\u548c\uff0c\u901a\u8fc7\u9636\u68af\u65b9\u5f0f\u8f93\u51fa; lower:\u6700\u5c0f\u503c; upper:\u6700\u5927\u503c;\"\"\" blanks = \" \" * margin print ( blanks , lower , upper ) if lower <= upper : result = lower + mySum ( lower + 1 , upper , margin + 4 ) print ( blanks , result ) return result else : print ( blanks , 0 ) return 0 print ( mySum ( 1 , 5 )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 1 5 # 2 5 # 3 5 # 4 5 # 5 5 # 6 5 # 0 # 5 # 9 # 12 # 14 # 15 # 15 1.5.3.\u51fd\u6570\u5d4c\u5957 \u00b6 \u5d4c\u5957\u51fd\u6570\u7c7b\u4f3c\u4e8e\u5d4c\u5957\u5faa\u73af\uff0c\u5c31\u662f\u51fd\u6570\u5185\u53c8\u5d4c\u5957\u7740\u51fd\u6570\u3002\u5373\uff0c\u51fd\u6570\u7684\u5b9a\u4e49\u5d4c\u5957\u5728\u4e00\u4e2a\u51fd\u6570\u7684\u8bed\u53e5\u5e8f\u5217\u91cc\u3002 \u5148\u770b\u4e00\u4e2a\u666e\u901a\u4f8b\u5b50\uff1a # \u5b9a\u4e49inner\u51fd\u6570 def inner (): print ( '\u6211\u662finner' ) # \u5b9a\u4e49outer\u51fd\u6570\uff0couter\u51fd\u6570\u8c03\u7528inner\u51fd\u6570 def outer (): print ( '\u6211\u662fouter' ) inner () outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter # \u6211\u662finner \u6539\u5199\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u628a inner \u51fd\u6570\u5199\u5728 outer \u51fd\u6570\u91cc\u9762\u3002 # \u5b9a\u4e49outer\u51fd\u6570\uff0couter\u51fd\u6570\u5185\u5d4cinner\u51fd\u6570\uff0c\u5e76\u8c03\u7528inner\u51fd\u6570 def outer (): print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): print ( '\u6211\u662finner' ) inner () outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter # \u6211\u662finner \u4e0a\u9762\u7684\u5916\u5c42 outer \u51fd\u6570\u548c\u5185\u5c42 inner \u51fd\u6570\u90fd\u6ca1\u6709\u53d8\u91cf\u548c\u53c2\u6570\u3002 \u73b0\u5728\u4fee\u6539\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u6211\u4eec\u4f20\u5165\u53c2\u6570\u548c\u53d8\u91cf\uff0c\u7136\u540e\u628a\u5916\u5c42\u51fd\u6570\u8fd4\u56de\u503c\u6307\u5411\u5185\u5c42\u51fd\u6570\u540d\u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) # \u8fd4\u56de\u5185\u5c42inner\u51fd\u6570\u540d return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662finner # inner\u6253\u5370: 1 \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff1a f = outer() \u8c03\u7528\u5916\u5c42 outer \u51fd\u6570\uff0c\u5e76\u628a\u7ed3\u679c\u8d4b\u503c\u7ed9 f \u3002\u6ce8\u610f\uff0cinner\u51fd\u6570\u5e76\u6ca1\u6709\u88ab\u6267\u884c\u3002 f \u5176\u5b9e\u5c31\u662f inner \uff0c\u6307\u5411 inner \u7684\u5185\u5b58\u7a7a\u95f4\u3002\u901a\u8fc7 f() \u9a8c\u8bc1\u4e86\u8fd9\u4e00\u70b9\uff0c outer \u51fd\u6570\u4e2d\u7684\u53d8\u91cf a \u88ab\u6253\u5370\u51fa\u6765\u4e86\u3002 \u4e0a\u9762\u4f8b\u5b50\u4e2d outer \u5c31\u662f\u95ed\u5305\u51fd\u6570\uff0c\u5916\u5c42\u51fd\u6570\u7684\u53d8\u91cf\u53ef\u4ee5\u88ab\u5185\u5c42\u51fd\u6570\u8c03\u7528\uff0c\u7c7b\u4f3c\u4e8e\u5c01\u88c5\u7684\u6548\u679c\u3002\u5185\u5c42\u51fd\u6570\u4e0d\u4f1a\u7acb\u523b\u88ab\u6267\u884c\uff0c\u5f53\u518d\u6b21\u8c03\u7528\u65f6\uff0c\u5185\u5c42\u51fd\u6570\u624d\u4f1a\u6267\u884c\u3002 \u95ed\u5305\u51fd\u6570\u9700\u8981\u6709\u4e09\u4e2a\u6761\u4ef6\uff1a \u5fc5\u987b\u6709\u4e00\u4e2a\u5185\u5d4c\u51fd\u6570\uff0c\u4f8b\u5982\u51fd\u6570 inner \uff1b \u5185\u90e8\u51fd\u6570\u5f15\u7528\u5916\u90e8\u51fd\u6570\u53d8\u91cf\uff0c\u4f8b\u5982\u53d8\u91cf a \uff1b \u5916\u90e8\u51fd\u6570\u5fc5\u987b\u8fd4\u56de\u5185\u5d4c\u51fd\u6570\uff0c\u4f8b\u5982 outer \u51fd\u6570\u4e2d\u7684 return inner \uff1b \u5bf9\u4e0a\u9762\u7684\u4ee3\u7801\u518d\u8fdb\u884c\u4fee\u6539\uff0c\u5728 inner \u51fd\u6570\u4e2d\u518d\u6dfb\u52a0\u4e00\u4e2a\u540c\u540d\u7684\u53d8\u91cfa\u3002\u4ece\u7ed3\u679c\u53ef\u4ee5\u5f97\u51fa\u7ed3\u8bba\uff0c inner \u51fd\u6570\u4f18\u5148\u5728\u5185\u90e8\u67e5\u627e\u53d8\u91cf a=5 \u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): a = 5 print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662finner # inner\u6253\u5370: 5 \u7ed3\u8bba\uff1a\u5185\u5c42\u51fd\u6570\u4e2d\u8c03\u7528\u7684\u53d8\u91cf\uff1a \u9996\u5148\u4f1a\u4ece\u5185\u5c42\u51fd\u6570\u4e2d\u627e\uff0c \u627e\u4e0d\u5230\u5c31\u53bb\u5916\u5c42\u51fd\u6570\u4e2d\u627e\uff0c \u518d\u627e\u4e0d\u5230\u5c31\u5230\u51fd\u6570\u5916\u4e2d\u627e\uff0c \u518d\u627e\u4e0d\u5230\u5c31\u5230\u5185\u7f6e\u7684\u6a21\u5757\u4e2d\u627e\uff0c \u518d\u627e\u4e0d\u5230\uff0c\u5c31\u62a5\u9519\u3002 \u8fd9\u5c31\u662f\u4f5c\u7528\u57df\u7684\u6982\u5ff5\u3002 \u7ee7\u7eed\u4fee\u6539\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u5728 inner \u51fd\u6570\u4e2d\u4fee\u6539 outer \u51fd\u6570\u4e2d\u53d8\u91cf a \u7684\u503c\uff0c\u8fd0\u884c\u7ed3\u679c\u62a5\u9519\u3002\u7ed3\u8bba\uff1a\u5185\u5c42\u51fd\u6570\u4e0d\u80fd\u4fee\u6539\u5916\u5c42\u51fd\u6570\u7684\u53d8\u91cf\u503c\u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): a += 5 print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # UnboundLocalError: local variable 'a' referenced before assignment \u4fee\u6b63\u4e0a\u9762\u7684\u4ee3\u7801\u3002\u5728 inner \u51fd\u6570\u4e2d\u5bf9\u53d8\u91cfa\u6dfb\u52a0\u4e00\u4e2a nonlocal \u7684\u58f0\u660e\uff0c\u5c31\u53ef\u4ee5\u5728 inner \u51fd\u6570\u4e2d\u4fee\u6539\u5916\u5c42outer\u51fd\u6570\u7684\u53d8\u91cf a \u7684\u503c\u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): nonlocal a a += 5 print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662finner # inner\u6253\u5370: 6 \u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u662f\u9636\u4e58\uff08factorial\uff09\u9012\u5f52\u51fd\u6570\u7684\u4e24\u4e2a\u4e0d\u540c\u7684\u5b9a\u4e49\u3002 \u7b2c\u4e00\u4e2a\u5b9a\u4e49\u4f7f\u7528\u4e86\u5d4c\u5957\u7684\u8f85\u52a9\u51fd\u6570 recurse \u6765\u5bf9\u6240\u9700\u8981\u7684\u53c2\u6570\u8fdb\u884c\u9012\u5f52\uff1b\u8fd9\u91cc\u7684 factorial \u51fd\u6570\u5c31\u662f\u95ed\u5305\u51fd\u6570\u3002 \u7b2c\u4e00\u6b65\uff1a\u7b2c\u4e00\u6b21\u8c03\u7528 factorial() \u51fd\u6570\uff0c\u5373 n=5 \uff1b \u7b2c\u4e8c\u6b65\uff1a\u7b2c\u4e00\u6b21\u8c03\u7528\u5185\u5c42\u51fd\u6570 recurse() \uff0c\u4f46\u4e0d\u4f1a\u7acb\u523b\u88ab\u6267\u884c\uff1b \u7b2c\u4e09\u6b65\uff0c\u6267\u884c return recurse(5, 1) \uff0c\u5bf9\u53c2\u6570 product \u521d\u59cb\u5316\u8d4b\u503c 1 \u7b2c\u56db\u6b65\uff1a\u6267\u884c return recurse(5, 5 * 1) \uff0c\u6b64\u65f6 n=5 \uff0c product=1 \u3002 \u7b2c\u4e94\u6b65\uff1a\u6267\u884c return recurse(4, 4 * 5) \uff0c\u6b64\u65f6 n=4 \uff0c product=5 \u3002 \u7b2c\u516d\u6b65\uff1a\u6267\u884c return recurse(3, 3 * 20) \uff0c\u6b64\u65f6 n=3 \uff0c product=20 \u3002 \u7b2c\u4e03\u6b65\uff1a\u6267\u884c return recurse(2, 2 * 60) \uff0c\u6b64\u65f6 n=2 \uff0c product=60 \u3002 \u7b2c\u516b\u6b65\uff1a\u6267\u884c return recurse(1, 1 * 120) \uff0c\u6b64\u65f6 n=1 \uff0c product=120 \u3002 \u7b2c\u4e5d\u6b65\uff1a\u6b64\u65f6 n=1 \uff0c\u6267\u884c return product \uff0c\u5373 return 120 \uff0c\u7ed3\u675f\u3002 \u7b2c\u4e8c\u4e2a\u5b9a\u4e49\u5219\u662f\u4e3a\u7b2c\u4e8c\u4e2a\u53c2\u6570\u63d0\u4f9b\u4e86\u9ed8\u8ba4\u503c\uff0c\u4ece\u800c\u7b80\u5316\u4e86\u8bbe\u8ba1\u3002 # \u7b2c\u4e00\u4e2a\u5b9a\u4e49 def factorial ( n ): \"\"\"\u8fd4\u56de n \u7684\u9636\u4e58\"\"\" def recurse ( n , product ): \"\"\"\u8ba1\u7b97\u9636\u4e58\u7684\u5e2e\u52a9\u5668\"\"\" print ( n , product ) # \u63d2\u5165\u8fd9\u4e00\u53e5\u662f\u4e3a\u4e86\u80fd\u770b\u6e05\u695a\u6bcf\u4e00\u6b21\u9012\u5f52\u8c03\u7528\u7684n\u548cproduct\u53d8\u5316 if n == 1 : return product else : return recurse ( n - 1 , n * product ) return recurse ( n , 1 ) f = factorial ( 5 ) # \u8fd0\u884c\u7ed3\u679c 5 1 4 5 3 20 2 60 1 120 # \u7b2c\u4e8c\u4e2a\u5b9a\u4e49 def factorial ( n , product = 1 ): \"\"\"\u8fd4\u56de n \u7684\u9636\u4e58\"\"\" if n == 1 : return product else : return factorial ( n - 1 , n * product ) print ( factorial ( 5 )) # \u8fd0\u884c\u7ed3\u679c # 120 1.5.4.\u9ad8\u9636\u51fd\u6570 \u00b6 \u51fd\u6570\u672c\u8eab\u4e5f\u662f\u4e00\u79cd\u72ec\u7279\u7684\u6570\u636e\u5bf9\u8c61\u3002\u53ef\u4ee5\u628a\u5b83\u4eec\u8d4b\u7ed9\u53d8\u91cf\u3001\u5b58\u50a8\u5728\u6570\u636e\u7ed3\u6784\u91cc\u3001\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7ed9\u5176\u4ed6\u51fd\u6570\u4ee5\u53ca\u4f5c\u4e3a\u5176\u4ed6\u51fd\u6570\u7684\u503c\u8fd4\u56de\u3002 \u9ad8\u9636\u51fd\u6570\uff08higher-order function\uff09\uff1a\u5b83\u63a5\u6536\u53e6\u4e00\u4e2a\u51fd\u6570\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u4e14\u4ee5\u67d0\u79cd\u65b9\u5f0f\u5e94\u7528\u8be5\u51fd\u6570\u3002 Python\u6709\u4e24\u4e2a\u5185\u7f6e\u7684\u9ad8\u9636\u51fd\u6570\uff0c\u5206\u522b\u662f map \u548c filter \uff0c\u5b83\u4eec\u53ef\u4ee5\u7528\u4e8e\u5904\u7406\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 map \u51fd\u6570\u4f1a\u63a5\u6536\u53e6\u4e00\u4e2a\u51fd\u6570\u548c\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\uff0c\u8fd4\u56de\u53e6\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002\u8fd9\u4e2a\u51fd\u6570\u4f1a\u628a\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7684\u51fd\u6570\u5e94\u7528\u5728\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\u7684\u6bcf\u4e2a\u5143\u7d20\u4e0a\u3002\u7b80\u5355\u6765\u8bf4\uff0c map \u51fd\u6570\u4f1a\u5bf9\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\u7684\u6bcf\u4e2a\u5143\u7d20\u8fdb\u884c\u8f6c\u6362\u3002 filter \u4f1a\u63a5\u53d7\u4e00\u4e2a\u5e03\u5c14\u51fd\u6570\u548c\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\uff0c\u8fd4\u56de\u8fd9\u6837\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff0c\u5b83\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u90fd\u4f1a\u88ab\u4f20\u9012\u7ed9\u5e03\u5c14\u51fd\u6570\uff0c\u5982\u679c\u8fd9\u4e2a\u51fd\u6570\u8fd4\u56deTrue\uff0c\u90a3\u4e48\u8fd9\u4e2a\u5143\u7d20\u5c06\u88ab\u4fdd\u7559\u5728\u8fd4\u56de\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\uff1b\u5426\u5219\uff0c\u8fd9\u4e2a\u5143\u7d20\u5c06\u88ab\u5220\u9664\u3002\u7b80\u5355\u8bf4\uff0c filter \u51fd\u6570\u4f1a\u628a\u6240\u6709\u80fd\u591f\u901a\u8fc7\u68c0\u9a8c\u7684\u5143\u7d20\u4fdd\u7559\u5728\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\u3002 functools.reduce \u901a\u8fc7\u628a\u63a5\u6536\u4e24\u4e2a\u53c2\u6570\u7684\u51fd\u6570\u7684\u7ed3\u679c\u4ee5\u53ca\u8fed\u4ee3\u5bf9\u8c61\u7684\u4e0b\u4e00\u4e2a\u5143\u7d20\u518d\u6b21\u5e94\u7528\u4e8e\u8fd9\u4e2a\u63a5\u6536\u4e24\u4e2a\u53c2\u6570\u7684\u51fd\u6570\uff0c\u6765\u628a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u8ba1\u7b97\u6210\u5355\u4e00\u7684\u503c\u3002 \u793a\u4f8b\uff1a\u628a\u4e00\u4e2a\u6574\u6570\u5217\u8868\u8f6c\u6362\u6210\u53e6\u4e00\u4e2a\u5305\u542b\u8fd9\u4e9b\u6574\u6570\u7684\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\u5217\u8868\u3002 \u4f20\u7edf\u65b9\u6cd5\u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] for i in oldList : newList . append ( str ( i )) print ( newList ) # ['0', '1', '3', '5', '7', '9'] \u7528 map \u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] newList = list ( map ( str , oldList )) print ( newList ) # ['0', '1', '3', '5', '7', '9'] \u62d3\u5c55\uff1a\u628a\u4e00\u4e2a\u6574\u6570\u5217\u8868\u4e2d\u7684\u6b63\u6574\u6570\u8f6c\u6362\u6210\u53e6\u4e00\u4e2a\u5305\u542b\u8fd9\u4e9b\u6574\u6570\u7684\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\u5217\u8868\u3002 \u4f20\u7edf\u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] for i in oldList : if i > 0 : newList . append (( str ( i ))) print ( newList ) # ['1', '3', '5', '7', '9'] \u4f7f\u7528 filter \u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] def isPositive ( n ): if n > 0 : return True # \u521b\u5efa\u4e00\u4e2a\u4e0d\u5305\u542b\u4efb\u4f55\u96f6\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61 newList = list ( filter ( isPositive , oldList )) print ( newList ) # [1, 3, 5, 7, 9] \u793a\u4f8b\uff1a\u8ba1\u7b97\u4ece1\u523010\u7684\u4e58\u79ef\u5e76\u8f93\u51fa\u7ed3\u679c\u3002 \u901a\u8fc7 for \u5faa\u73af\u5b9e\u73b0\uff1a result = 1 value = 1 for value in range ( 1 , 11 ): result *= value value += 1 print ( result ) # \u8fd0\u884c\u7ed3\u679c # 3628800 \u901a\u8fc7 functools.reduce \u5faa\u73af\u5b9e\u73b0\uff1a import functools result = functools . reduce ( lambda x , y : x * y , range ( 1 , 11 )) print ( result ) # 3628800 1.5.5.lambda\u4e0e\u533f\u540d\u51fd\u6570 \u00b6 \u8bed\u6cd5\u683c\u5f0f\uff1a lambda < argument list > : < expression > lambda\u8868\u8fbe\u5f0f\u4e0d\u80fd\u50cf\u5176\u4ed6Python\u51fd\u6570\u90a3\u6837\u5305\u542b\u4e00\u6574\u4e2a\u8bed\u53e5\u5e8f\u5217\u3002 \u62d3\u5c55\uff1a\u7528lambda\u5b9e\u73b0\u628a\u4e00\u4e2a\u6574\u6570\u5217\u8868\u4e2d\u7684\u6b63\u6574\u6570\u8f6c\u6362\u6210\u53e6\u4e00\u4e2a\u5305\u542b\u8fd9\u4e9b\u6574\u6570\u7684\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\u5217\u8868\uff0c\u5b9e\u9645\u5c31\u662f\u901a\u8fc7\u4f7f\u7528\u533f\u540d\u7684\u5e03\u5c14\u51fd\u6570\u6765\u4ece\u6574\u6570\u5217\u8868\u91cc\u5254\u9664\u6240\u6709\u4e3a\u96f6\u7684\u5143\u7d20\u3002 oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] newList = list ( filter ( lambda i : i > 0 , oldList )) print ( newList ) # [1, 3, 5, 7, 9] 1.6.\u6355\u83b7\u5f02\u5e38 \u00b6 \u8003\u8651\u4e24\u79cd\u5f02\u5e38\u60c5\u51b5\uff1a Python\u865a\u62df\u673a\u5728\u7a0b\u5e8f\u6267\u884c\u671f\u95f4\u9047\u5230\u4e86\u8bed\u4e49\u9519\u8bef\uff0c\u5219\u4f1a\u5f97\u5230\u76f8\u5e94\u7684\u9519\u8bef\u6d88\u606f\uff0c\u4ece\u800c\u5f15\u53d1\u4e00\u4e2a\u5f02\u5e38\u5e76\u4e14\u6682\u505c\u7a0b\u5e8f\u3002\u8bed\u4e49\u9519\u8bef\u5305\u62ec\u4f8b\u5982\u672a\u5b9a\u4e49\u7684\u53d8\u91cf\u540d\u3001\u9664\u4ee50\u4ee5\u53ca\u8d85\u51fa\u5217\u8868\u8303\u56f4\u7684\u7d22\u5f15\u7b49\u3002 \u7528\u6237\u5f15\u8d77\u7684\u67d0\u4e9b\u9519\u8bef\uff0c\u4f8b\u5982\uff0c\u671f\u671b\u8f93\u5165\u6570\u5b57\u7684\u65f6\u5019\u8f93\u5165\u4e86\u5176\u4ed6\u5b57\u7b26\u3002\u5bf9\u4e8e\u5728\u8fd9\u4e9b\u60c5\u51b5\u4e0b\u4ea7\u751f\u7684\u5f02\u5e38\uff0c\u7a0b\u5e8f\u4e0d\u5e94\u8be5\u505c\u6b62\u6267\u884c\uff0c\u800c\u5e94\u8be5\u5bf9\u8fd9\u4e9b\u5f02\u5e38\u8fdb\u884c\u6355\u83b7\uff0c\u5e76\u4e14\u5141\u8bb8\u7528\u6237\u4fee\u6b63\u9519\u8bef\u3002 Python\u63d0\u4f9b\u4e86try-except\u8bed\u53e5\uff0c\u53ef\u4ee5\u8ba9\u7a0b\u5e8f\u6355\u83b7\u5f02\u5e38\u5e76\u6267\u884c\u76f8\u5e94\u7684\u6062\u590d\u64cd\u4f5c\u3002 try \u5b50\u53e5\u4e2d\u7684\u8bed\u53e5\u5c06\u5148\u88ab\u6267\u884c\u3002\u5982\u679c\u8fd9\u4e9b\u8bed\u53e5\u4e2d\u7684\u4e00\u6761\u5f15\u53d1\u4e86\u5f02\u5e38\uff0c\u90a3\u4e48\u63a7\u5236\u6743\u4f1a\u7acb\u5373\u8f6c\u79fb\u5230 except \u5b50\u53e5\u53bb\u3002 \u5982\u679c\u5f15\u53d1\u7684\u5f02\u5e38\u7c7b\u578b\u548c\u8fd9\u4e2a\u5b50\u53e5\u91cc\u7684\u7c7b\u578b\u4e00\u81f4\uff0c\u90a3\u4e48\u4f1a\u6267\u884c\u5b83\u91cc\u9762\u7684\u8bed\u53e5\uff1b \u5426\u5219\uff0c\u5c06\u8f6c\u79fb\u5230try-except\u8bed\u53e5\u7684\u8c03\u7528\u8005\uff0c\u5e76\u57fa\u4e8e\u8c03\u7528\u94fe\u5411\u4e0a\u4f20\u9012\uff0c\u76f4\u5230\u8fd9\u4e2a\u5f02\u5e38\u88ab\u6210\u529f\u6355\u83b7\uff0c\u6216\u8005\u662f\u7a0b\u5e8f\u56e0\u9519\u8bef\u6d88\u606f\u800c\u505c\u6b62\u6267\u884c\u3002 \u5982\u679c try \u5b50\u53e5\u91cc\u7684\u8bed\u53e5\u6ca1\u6709\u5f15\u53d1\u4efb\u4f55\u5f02\u5e38\uff0c\u90a3\u4e48\u4f1a\u8df3\u8fc7 except \u5b50\u53e5\u5e76\u7ee7\u7eed\u6267\u884c\uff0c\u76f4\u5230try-except\u8bed\u53e5\u7684\u672b\u5c3e\u3002 try : < statements > except < exception type > : < statements > \u901a\u5e38\u6765\u8bf4\uff0c \u5bf9\u4e8e\u5df2\u77e5\u53ef\u80fd\u4f1a\u53d1\u751f\u7684\u5f02\u5e38\u7c7b\u578b\uff0c\u5e94\u8be5\u5c3d\u53ef\u80fd\u5730\u5305\u62ec\u5728\u5728 except \u8bed\u53e5\u91cc\u3002 \u5982\u679c\u4e0d\u77e5\u9053\u5f02\u5e38\u7684\u7c7b\u578b\uff0c\u53ef\u4ee5\u5728 except \u4e2d\u7528\u66f4\u901a\u7528\u7684Exception\u7c7b\u578b\u5339\u914d\u53ef\u80fd\u4f1a\u5f15\u53d1\u7684\u4efb\u4f55\u5f02\u5e38\u3002 \u793a\u4f8b\uff1a def getYourAge ( prompt ): \"\"\"\u63d0\u793a\u7528\u6237\u8f93\u5165\u4e00\u4e2a\u6574\u6570\uff0c\u5426\u5219\u7ed9\u51fa\u9519\u8bef\u63d0\u793a\uff0c\u5e76\u7ee7\u7eed\u63d0\u793a\u7528\u6237\u8f93\u5165\u3002\"\"\" inputStr = input ( prompt ) try : number = int ( inputStr ) return number except ValueError : print ( \"Error in number format:\" , inputStr ) return getYourAge ( prompt ) if __name__ == \"__main__\" : age = getYourAge ( \"Enter your age: \" ) print ( \"Your age is\" , age ) # \u8fd0\u884c\u7ed3\u679c # Enter your age: 3a # Error in number format: 3a # Enter your age: 3.5 # Error in number format: 3.5 # Enter your age: 20 # Your age is 20 1.7.\u6587\u4ef6\u53ca\u5176\u64cd\u4f5c \u00b6 1.7.1.\u6587\u672c\u6587\u4ef6\u8bfb\u53d6 \u00b6 \u53ef\u4ee5\u628a\u6587\u672c\u6587\u4ef6\u91cc\u7684\u6570\u636e\u770b\u4f5c\u5b57\u7b26\u3001\u5355\u8bcd\u3001\u6570\u5b57\u6216\u8005\u82e5\u5e72\u884c\u6587\u672c\u3002 \u5982\u679c\u628a\u6587\u672c\u6587\u4ef6\u91cc\u7684\u6570\u636e\u5f53\u4f5c\u6574\u6570\u6216\u6d6e\u70b9\u6570\uff0c\u5c31\u5fc5\u987b\u7528\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u3001\u5236\u8868\u7b26\u548c\u6362\u884c\u7b26\uff09\u5c06\u5176\u5206\u9694\u5f00\u3002\u8f93\u51fa\u6216\u8f93\u5165\u5230\u6587\u672c\u6587\u4ef6\u7684\u6240\u6709\u6570\u636e\u5fc5\u987b\u662f\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\uff0c\u6240\u4ee5\u5728\u8f93\u5165/\u8f93\u51fa\u65f6\u9700\u8981\u505a\u76f8\u5e94\u7684\u7c7b\u578b\u8f6c\u6362\u3002 \u5982\u4e0b\u4f8b\uff1a 34.6 22.33 66.75 77.12 21.44 99.01 Python\u7684open\u51fd\u6570\u63a5\u6536\u4e0b\u9762\u4e24\u4e2a\u4e3b\u8981\u53c2\u6570\uff0c\u6253\u5f00\u4e00\u4e2a\u4e0e\u78c1\u76d8\u6587\u4ef6\u7684\u8fde\u63a5\u5e76\u4e14\u8fd4\u56de\u76f8\u5e94\u7684\u6587\u4ef6\u5bf9\u8c61\u3002 \u6587\u4ef6\u8def\u5f84\uff1b \u6253\u5f00\u6a21\u5f0f\uff1a \u6253\u5f00\u6a21\u5f0f\uff1a r \u8868\u793a\u6587\u4ef6\u53ea\u80fd\u8bfb\u53d6\uff1b w \u8868\u793a\u6587\u4ef6\u53ea\u80fd\u5199\u5165\uff1b a \u8868\u793a\u6253\u5f00\u6587\u4ef6\uff0c\u5728\u539f\u6709\u5185\u5bb9\u7684\u57fa\u7840\u4e0a\u8ffd\u52a0\u5185\u5bb9\uff0c\u5728\u672b\u5c3e\u5199\u5165\uff1b w+ \u8868\u793a\u53ef\u4ee5\u5bf9\u6587\u4ef6\u8fdb\u884c\u8bfb\u5199\u53cc\u91cd\u64cd\u4f5c\uff1b rb \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u53ea\u8bfb\uff1b wb \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u53ea\u5199\uff1b ab \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u8ffd\u52a0\uff1b wb+ \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u8bfb\u5199\uff1b \u793a\u4f8b\uff1a \u4e3a myfile.txt \u6587\u4ef6\u6253\u5f00\u4e00\u4e2a\u7528\u6765\u8f93\u51fa\u7684\u6587\u4ef6\u5bf9\u8c61\u3002 \u5b57\u7b26\u4e32\u6570\u636e\u901a\u8fc7 write \u65b9\u6cd5\u548c\u6587\u4ef6\u5bf9\u8c61\u5199\u5165\uff08\u6216\u8f93\u51fa\uff09\u5230\u6587\u4ef6\u91cc\u3002 \u8f6c\u4e49\u7b26 \\n \u5b9e\u73b0\u6362\u884c\u3002 \u4f7f\u7528 close \u65b9\u6cd5\u5173\u95ed\u6587\u4ef6\u3002\u5982\u679c\u6ca1\u6709\u5173\u95ed\u8f93\u51fa\u6587\u4ef6\uff0c\u5219\u53ef\u80fd\u5bfc\u81f4\u6570\u636e\u4e22\u5931\u3002 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) f . write ( \"First line. \\n Second line. \\n \" ) f . close () \u6587\u4ef6myfile.txt\u7684\u5185\u5bb9\uff1a First line. Second line. 1.7.2.\u6587\u672c\u6587\u4ef6\u5199\u5165 \u00b6 \u6587\u4ef6\u7684 write \u65b9\u6cd5\u63a5\u6536\u4e00\u4e2a\u5b57\u7b26\u4e32\u4f5c\u4e3a\u53c2\u6570\u3002\u56e0\u6b64\uff0c\u5176\u4ed6\u7c7b\u578b\u7684\u6570\u636e\uff08\u5982\u6574\u6570\u6216\u6d6e\u70b9\u6570\uff09\u5728\u5199\u5165\u8f93\u51fa\u6587\u4ef6\u4e4b\u524d\uff0c\u90fd\u5fc5\u987b\u5148\u88ab\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\u3002 \u5728Python\u91cc\uff0c\u53ef\u4ee5\u4f7f\u7528 str \u51fd\u6570\u628a\u7edd\u5927\u591a\u6570\u7684\u6570\u636e\u7c7b\u578b\u7684\u503c\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\uff0c\u4ee5\u7a7a\u683c\u6216\u6362\u884c\u7b26\u4f5c\u4e3a\u5206\u9694\u7b26\uff0c\u5c06\u5176\u5199\u5165\u6587\u4ef6\u91cc\u3002 \u793a\u4f8b\uff1a\u751f\u6210500\u4e2a\u4ecb\u4e8e1\u548c500\u4e4b\u95f4\u7684\u968f\u673a\u6570\uff0c\u5e76\u8f93\u51fa\u5230\u6587\u672c\u6587\u4ef6\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) for count in range ( 500 ): number = random . randint ( 1 , 500 ) f . write ( str ( number ) + \" \\n \" ) f . close () 1.7.3.\u4ece\u6587\u672c\u6587\u4ef6\u8bfb\u53d6\u6570\u636e \u00b6 \u793a\u4f8b\uff1a\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) f . write ( \"First line. \\n Second line. \\n \" ) # \u521d\u59cb\u5316\u6587\u4ef6\u5185\u5bb9 f . close () # \u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) text1 = f . read () # \u628a\u6587\u4ef6\u7684\u5168\u90e8\u5185\u5bb9\u8f93\u5165\u5355\u4e2a\u5b57\u7b26\u4e32\u4e2d print ( text1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # First line. # Second line text2 = f . read () # \u518d\u6b21read\uff0c\u5f97\u5230\u4e00\u4e2a\u7a7a\u5b57\u4e32\uff0c\u8868\u8ff0\u5df2\u7ecf\u5230\u8fbe\u6587\u4ef6\u672b\u5c3e\u3002\u8981\u518d\u6b21\u8bfb\u53d6\u9700\u8981\u91cd\u65b0\u6253\u5f00\u6587\u4ef6 print ( \"======\" ) print ( text2 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ====== # f . close () # \u91cd\u65b0\u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) for line in f : # \u9010\u884c\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9 print ( \"======\" ) print ( line ) # \u6bcf\u884c\u90fd\u6709\u4e00\u4e2a\u6362\u884c\u7b26\uff0c\u8fd9\u662fprint\u51fd\u6570\u9ed8\u8ba4\u884c\u4e3a # \u8fd0\u884c\u7ed3\u679c\uff1a # ====== # First line. # ====== # Second line. # f . close () # \u91cd\u65b0\u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) while True : line = f . readline () # readline\u65b9\u6cd5\u4f1a\u4ece\u8f93\u5165\u7684\u6587\u672c\u91cc\u53ea\u83b7\u53d6\u4e00\u884c\u6570\u636e\uff0c\u5e76\u4e14\u8fd4\u56de\u8fd9\u4e2a\u5305\u542b\u6362\u884c\u7b26\u7684\u5b57\u7b26\u4e32\u3002\u5982\u679creadline\u9047\u5230\u4e86\u6587\u4ef6\u672b\u5c3e\uff0c\u90a3\u4e48\u4f1a\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\u3002 if line == \"\" : break print ( \"******\" ) print ( line ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ****** # First line. # ****** # Second line. # f . close () # \u91cd\u65b0\u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) line = f . readlines () # readlines\u65b9\u6cd5\u5219\u662f\u8bfb\u53d6\u6240\u6709\u884c\uff0c\u8fd4\u56de\u7684\u662f\u6240\u6709\u884c\u7ec4\u6210\u7684\u5217\u8868\u3002 print ( line ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ['First line.\\n', 'Second line.\\n'] f . close () 1.7.4.\u4ece\u5176\u5b83\u6587\u4ef6\u8bfb\u53d6\u6570\u636e \u00b6 \u793a\u4f8b\uff1a\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6574\u6570\uff0c\u6bcf\u884c\u53ea\u6709\u4e00\u4e2a\u6574\u6570\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) # \u751f\u62100~9\u6574\u6570\uff0c\u5e76\u5199\u5165\u6587\u4ef6 for count in range ( 10 ): f . write ( str ( count ) + \" \\n \" ) f . close () # \u6253\u5f00\u6587\u4ef6 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) # \u4f9d\u6b21\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6570\u5b57\uff0c\u5e76\u6c42\u548c theSum = 0 for line in f : line = line . strip () number = int ( line ) theSum += number print ( \"The sum is : \" , theSum ) # \u8fd0\u884c\u7ed3\u679c\uff1a # The sum is : 45 f . close () \u793a\u4f8b\uff1a\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6574\u6570\uff0c\u6bcf\u884c\u6709\u591a\u4e2a\u6574\u6570\u3002\u9700\u8981\u4e8b\u5148\u628a\u4e0b\u9762\u7684\u5185\u5bb9\u5199\u5165 myfile.txt \u6587\u4ef6\u4e2d\u3002 \u6587\u4ef6 myfile.txt \u7684\u5185\u5bb9\u3002 1 3 5 7 9 2 4 6 8 10 31 200 3000 50000 import random # \u6253\u5f00\u6587\u4ef6 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) # \u4f9d\u6b21\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6570\u5b57\uff0c\u5e76\u6c42\u548c theSum = 0 for line in f : lines = line . split () # split\u65b9\u6cd5\u4f1a\u81ea\u52a8\u5904\u7406\u6362\u884c\u7b26 for word in lines : number = int ( word ) theSum += number print ( \"The sum is : \" , theSum ) # \u8fd0\u884c\u7ed3\u679c\uff1a # The sum is : 53286 f . close () \u7b80\u5199\u4e0a\u9762\u7684\u4ee3\u7801\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) print ( \"The sum is: \" , sum ( map ( int , f . read () . split ()))) # \u8fd0\u884c\u7ed3\u679c\uff1a # The sum is : 53286 f . close () 1.7.5.\u4f7f\u7528pickle\u8bfb\u5199\u5bf9\u8c61 \u00b6 \u5728\u628a\u4efb\u4f55\u5bf9\u8c61\u4fdd\u5b58\u5230\u6587\u4ef6\u4e4b\u524d\uff0c\u6211\u4eec\u53ef\u4ee5\u5bf9\u5b83\u8fdb\u884c\u201c\u814c\u5236\u201d\uff1b\u5728\u628a\u5bf9\u8c61\u4ece\u6587\u4ef6\u52a0\u8f7d\u5230\u7a0b\u5e8f\u4e2d\u65f6\uff0c\u4e5f\u53ef\u4ee5\u5bf9\u5b83\u8fdb\u884c\u201c\u53cd\u814c\u5236\u201d\u3002 \u793a\u4f8b\uff1a \u4f7f\u7528pickle\u6a21\u5757\u7684 pickle.dump \u628a\u540d\u4e3alyst\u7684\u5217\u8868\u91cc\u7684\u6240\u6709\u5bf9\u8c61\u4fdd\u5b58\u5230\u540d\u4e3aitems.dat\u7684\u6587\u4ef6\u91cc\uff08\u201c\u814c\u5236\u201d\uff09\u3002\u6211\u4eec\u4e0d\u9700\u8981\u77e5\u9053\u5217\u8868\u91cc\u6709\u54ea\u4e9b\u7c7b\u578b\u7684\u5bf9\u8c61\uff0c\u4e5f\u4e0d\u9700\u8981\u77e5\u9053\u6709\u591a\u5c11\u4e2a\u5bf9\u8c61\u3002 import pickle myList = [ 60 , \"A string object\" , 1977 ] fObj = open ( \"./docs/python/DataStructure/code/items.dat\" , \"wb\" ) for item in myList : pickle . dump ( item , fObj ) fObj . close () \u4f7f\u7528pickle\u6a21\u5757\u7684 pickle.load \u628aitems.dat\u7684\u6587\u4ef6\u5185\u5bb9\u52a0\u8f7d\u56de\u7a0b\u5e8f\uff08\u201c\u53cd\u814c\u5236\u201d\uff09\u3002 import pickle lyst = list () fileObj = open ( \"./docs/python/DataStructure/code/items.dat\" , \"rb\" ) while True : try : item = pickle . load ( fileObj ) lyst . append ( item ) except EOFError : # \u68c0\u6d4b\u5df2\u7ecf\u5230\u8fbe\u6587\u4ef6\u672b\u5c3e fileObj . close () break print ( lyst ) # \u8fd0\u884c\u7ed3\u679c\uff1a # [60, 'A string object', 1977] 1.8.\u521b\u5efa\u7c7b \u00b6 \u7c7b\uff08class\uff09\u7528\u6765\u63cf\u8ff0\u4e0e\u4e00\u7ec4\u5bf9\u8c61\u6709\u5173\u7684\u6570\u636e\u548c\u65b9\u6cd5\u3002\u5b83\u63d0\u4f9b\u4e86\u7528\u6765\u521b\u5efa\u5bf9\u8c61\u7684\u84dd\u56fe\uff0c\u4ee5\u53ca\u5728\u5bf9\u8c61\u4e0a\u8c03\u7528\u65b9\u6cd5\u65f6\u6240\u9700\u8981\u6267\u884c\u7684\u4ee3\u7801\u3002 Python\u91cc\u7684\u6570\u636e\u7c7b\u578b\u90fd\u662f\u7c7b\uff1b \u7c7b\u540d\u6309\u7167\u60ef\u4f8b\u9996\u5b57\u6bcd\u5e94\u4e3a\u5927\u5199\u6837\u5f0f\uff1b \u5b9a\u4e49\u7c7b\u7684\u4ee3\u7801\u901a\u5e38\u4f1a\u88ab\u5b58\u653e\u5728\u9996\u5b57\u6bcd\u5c0f\u5199\u7684\u7c7b\u540d\u7684\u6a21\u5757\u6587\u4ef6\u91cc\u3002 \u76f8\u5173\u7684\u7c7b\u4e5f\u53ef\u80fd\u4f1a\u51fa\u73b0\u5728\u540c\u4e00\u4e2a\u6a21\u5757\u91cc\u3002 \u7c7b\u7684\u8bed\u6cd5\uff1a def < class name > ( < parent class name > )[ 2 ]: < class variable assignments > < instance method definitions > \u7236\u7c7b\uff08parent class\uff09\u7684\u540d\u79f0\u662f\u53ef\u9009\u7684\uff0c\u5728\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b83\u4f1a\u662fobject\u3002 \u6240\u6709Python\u7c7b\u5c5e\u4e8e\u4e00\u4e2a\u4ee5 object \u4f5c\u4e3a\u6839\u8282\u70b9\u7684\u5c42\u6b21\u7ed3\u6784\u3002 \u5728 object \u91cc\uff0cPython\u5b9a\u4e49\u4e86\u51e0\u79cd\u65b9\u6cd5\uff1a __str__ \u548c __eq__ \uff0c\u56e0\u6b64\u6240\u6709\u5b50\u7c7b\u4f1a\u81ea\u52a8\u7ee7\u627f\u8fd9\u4e9b\u65b9\u6cd5\u3002 \u5b9e\u4f8b\u65b9\u6cd5\uff08instance method\uff09\u662f\u5728\u7c7b\u7684\u5bf9\u8c61\u4e0a\u8fd0\u884c\u7684\u3002\u5b83\u4eec\u5305\u542b\u7528\u6765\u8bbf\u95ee\u6216\u4fee\u6539\u5b9e\u4f8b\u53d8\u91cf\u7684\u4ee3\u7801\u3002 \u5b9e\u4f8b\u53d8\u91cf\uff08instance variable\uff09\u662f\u6307\u7531\u5355\u4e2a\u5bf9\u8c61\u6240\u62e5\u6709\u7684\u5b58\u50a8\u4fe1\u606f\u3002 \u7c7b\u53d8\u91cf\uff08class variable\uff09\u662f\u6307\u7531\u7c7b\u7684\u6240\u6709\u5bf9\u8c61\u5b58\u50a8\u6240\u6709\u7684\u4fe1\u606f\u3002 \u793a\u4f8b\uff1a\u89e3\u8bfbCounter\u7c7b\u3002 Counter \u7c7b\u662f object \u7684\u5b50\u7c7b\uff1b instances \u662f\u7c7b\u53d8\u91cf\uff0c\u8ddf\u8e2a\u5df2\u521b\u5efa\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u7684\u6570\u91cf\uff1b \u5b9e\u4f8b\u65b9\u6cd5 __init__ \u4e5f\u79f0\u4e3a\u6784\u9020\u51fd\u6570\uff1b\u8fd9\u4e2a\u65b9\u6cd5\u7528\u6765\u521d\u59cb\u5316\u5b9e\u4f8b\u53d8\u91cf\uff0c\u5e76\u4e14\u5bf9\u7c7b\u53d8\u91cf\u8fdb\u884c\u66f4\u65b0\uff1b self \u662f\u6307\u5728\u8fd0\u884c\u65f6\u8fd9\u4e2a\u65b9\u6cd5\u7684\u5bf9\u8c61\u672c\u8eab\uff1b \u4f7f\u7528\u5b9e\u4f8b\u53d8\u91cf\u90fd\u4f1a\u52a0\u4e0a\u524d\u7f00 self \uff1b\u548c\u53c2\u6570\u6216\u4e34\u65f6\u53d8\u91cf\u4e0d\u540c\u7684\u5730\u65b9\u662f\uff0c\u5b9e\u4f8b\u53d8\u91cf\u5728\u7c7b\u7684\u4efb\u4f55\u65b9\u6cd5\u91cc\u662f\u53ef\u89c1\u7684\uff1b \u5176\u4ed6\u5b9e\u4f8b\u65b9\u6cd5\u53ef\u4ee5\u5206\u4e3a\u4e24\u79cd\uff1a\u53d8\u5f02\u5668\uff08mutator\uff09\u548c\u8bbf\u95ee\u5668\uff08accessor\uff09\u3002\u53d8\u5f02\u5668\u4f1a\u901a\u8fc7\u4fee\u6539\u5bf9\u8c61\u7684\u5b9e\u4f8b\u53d8\u91cf\u5bf9\u5176\u5185\u90e8\u72b6\u6001\u8fdb\u884c\u4fee\u6539\u6216\u66f4\u6539\u3002\u8bbf\u95ee\u5668\u5219\u53ea\u4f1a\u67e5\u770b\u6216\u4f7f\u7528\u5bf9\u8c61\u7684\u5b9e\u4f8b\u53d8\u91cf\u7684\u503c\uff0c\u800c\u4e0d\u4f1a\u53bb\u4fee\u6539\u5b83\u4eec\uff1b __str__ \u65b9\u6cd5\u5c06\u8986\u76d6object\u7c7b\u91cc\u7684\u8fd9\u4e2a\u65b9\u6cd5\uff1b \u5f53Python\u7684 print \u51fd\u6570\u63a5\u6536\u5230\u4e00\u4e2a\u53c2\u6570\u65f6\uff0c\u8fd9\u4e2a\u53c2\u6570\u7684 __str__ \u65b9\u6cd5\u5c06\u81ea\u52a8\u8fd0\u884c\uff0c\u4ece\u800c\u5f97\u5230\u5b83\u7684\u5b57\u7b26\u4e32\u8868\u8fbe\u5f0f\uff0c\u4ee5\u4fbf\u7528\u6765\u8f93\u51fa\uff1b \u5f53\u770b\u5230 == \u8fd0\u7b97\u7b26\u65f6\uff0cPython\u5c06\u8fd0\u884c __eq__ \u65b9\u6cd5\uff1b\u5728 object \u7c7b\u91cc\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u7684\u9ed8\u8ba4\u5b9a\u4e49\u662f\u8fd0\u884c is \u8fd0\u7b97\u7b26\u3002 class Counter ( object ): # Counter\u7c7b\u662fobject\u7684\u5b50\u7c7b \"\"\"Models a counter.\"\"\" # Class variable \u7c7b\u53d8\u91cf instances = 0 # \u8ddf\u8e2a\u5df2\u521b\u5efa\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u7684\u6570\u91cf # Constructor \u6784\u9020\u5668 # \u5b9e\u4f8b\u65b9\u6cd5__init__\u4e5f\u79f0\u4e3a\u6784\u9020\u51fd\u6570\uff1b\u8fd9\u4e2a\u65b9\u6cd5\u7528\u6765\u521d\u59cb\u5316\u5b9e\u4f8b\u53d8\u91cf\uff0c\u5e76\u4e14\u5bf9\u7c7b\u53d8\u91cf\u8fdb\u884c\u66f4\u65b0\uff1b def __init__ ( self ): # self\u662f\u6307\u5728\u8fd0\u884c\u65f6\u8fd9\u4e2a\u65b9\u6cd5\u7684\u5bf9\u8c61\u672c\u8eab \"\"\"Sets up the counter.\"\"\" Counter . instances += 1 self . reset () # Mutator methods def reset ( self ): \"\"\"Sets the counter to 0.\"\"\" self . value = 0 def increment ( self , amount = 1 ): \"\"\"Adds amount to the counter.\"\"\" self . value += amount def decrement ( self , amount = 1 ): \"\"\"Subtracts amount from the counter.\"\"\" self . value -= amount # Accessor methods def getValue ( self ): \"\"\"Returns the counter's value.\"\"\" return self . value def __str__ ( self ): \"\"\"Returns the string representation of the counter.\"\"\" return str ( self . value ) def __eq__ ( self , other ): \"\"\"Returns True if self equals other or False otherwise.\"\"\" if self is other : return True if type ( self ) != type ( other ): return False return self . value == other . value c1 = Counter () print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 0 c1 . getValue () str ( c1 ) c1 . increment () print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 1 c1 . increment ( 5 ) print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 6 c1 . reset () print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 0 c2 = Counter () print ( Counter . instances ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 2 print ( c1 == c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # True print ( c1 == 0 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # False print ( c1 == c2 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # True c2 . increment () print ( c1 == c2 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # False 1.9.\u7f16\u7a0b\u7ec3\u4e60 \u00b6 1\uff0e\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u4f7f\u4e4b\u80fd\u591f\u63a5\u6536\u7403\u4f53\u7684\u534a\u5f84\uff08\u6d6e\u70b9\u6570\uff09\uff0c\u5e76\u4e14\u53ef\u4ee5\u8f93\u51fa\u7403\u4f53\u7684\u76f4\u5f84\u3001\u5468\u957f\u3001\u8868\u9762\u79ef\u4ee5\u53ca\u4f53\u79ef\u3002 \u89e3\u7b54\uff1a PAI = 3.14 radius = float ( input ( \"\u8f93\u5165\u7403\u534a\u5f84\uff1a\" )) diameter = radius * 2 circumference = 2 * PAI * radius surfaceArea = 4 * PAI * radius ** 2 sphereVolume = 4 * ( PAI * radius ** 3 ) / 3 print ( \"\u7403\u534a\u5f84\uff1a\" , radius , \"\u7403\u76f4\u5f84\uff1a\" , diameter , \"\u7403\u8868\u9762\u79ef\uff1a\" , surfaceArea , \"\u7403\u4f53\u79ef\uff1a\" , sphereVolume ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u7403\u534a\u5f84\uff1a3.5 # \u7403\u534a\u5f84\uff1a 3.5 \u7403\u76f4\u5f84\uff1a 7.0 \u7403\u8868\u9762\u79ef\uff1a 153.86 \u7403\u4f53\u79ef\uff1a 179.50333333333333 import math def main (): try : radius = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u534a\u5f84\uff1a\" )) if radius <= 0 : print ( \"\u534a\u5f84\u5fc5\u987b\u4e3a\u6b63\u6570\uff01\" ) return diameter = 2 * radius circumference = 2 * math . pi * radius surfaceArea = 4 * math . pi * radius ** 2 volume = ( 4 / 3 ) * math . pi * radius ** 3 print ( f \"\u7403\u4f53\u7684\u76f4\u5f84\uff1a { diameter : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u5468\u957f\uff1a { circumference : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a { surfaceArea : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u4f53\u79ef\uff1a { volume : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u7403\u534a\u5f84\uff1a3.5 # \u7403\u4f53\u7684\u76f4\u5f84\uff1a7.00 # \u7403\u4f53\u7684\u5468\u957f\uff1a21.99 # \u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a153.94 # \u7403\u4f53\u7684\u4f53\u79ef\uff1a179.59 import math class Sphere : def __init__ ( self , radius ): self . radius = radius def diameter ( self ): return 2 * self . radius def circumference ( self ): return 2 * math . pi * self . radius def surfaceArea ( self ): return 4 * math . pi * self . radius ** 2 def volume ( self ): return ( 4 / 3 ) * math . pi * self . radius ** 3 def main (): try : radius = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u4f53\u7684\u534a\u5f84\uff1a\" )) if radius <= 0 : print ( \"\u534a\u5f84\u5fc5\u987b\u4e3a\u6b63\u6570\uff01\" ) return sphere = Sphere ( radius ) print ( f \"\u7403\u4f53\u7684\u76f4\u5f84\uff1a { sphere . diameter () : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u5468\u957f\uff1a { sphere . circumference () : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a { sphere . surfaceArea () : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u4f53\u79ef\uff1a { sphere . volume () : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u7403\u4f53\u7684\u534a\u5f84\uff1a3.5 # \u7403\u4f53\u7684\u76f4\u5f84\uff1a7.00 # \u7403\u4f53\u7684\u5468\u957f\uff1a21.99 # \u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a153.94 # \u7403\u4f53\u7684\u4f53\u79ef\uff1a179.59 2\uff0e\u5458\u5de5\u7684\u5468\u5de5\u8d44\u7b49\u4e8e\u5c0f\u65f6\u5de5\u8d44\u4e58\u4ee5\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\u518d\u52a0\u4e0a\u52a0\u73ed\u5de5\u8d44\u3002\u52a0\u73ed\u5de5\u8d44\u7b49\u4e8e\u603b\u52a0\u73ed\u65f6\u95f4\u4e58\u4ee5\u5c0f\u65f6\u5de5\u8d44\u76841.5\u500d\u3002\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\u3001\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\u4ee5\u53ca\u52a0\u73ed\u603b\u65f6\u95f4\uff0c\u7136\u540e\u663e\u793a\u51fa\u5458\u5de5\u7684\u5468\u5de5\u8d44\u3002 \u89e3\u7b54\uff1a hourSalary = float ( input ( \"\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff08\u5143\uff09\uff1a\" )) totalWorkingHours = float ( input ( \"\u8f93\u5165\u672c\u5468\u6b63\u5e38\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) totalOvertimeHours = float ( input ( \"\u8f93\u5165\u672c\u5468\u603b\u52a0\u73ed\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) weeklySalary = hourSalary * totalWorkingHours + hourSalary * totalOvertimeHours * 1.5 print ( \"\u5458\u5de5\u7684\u5468\u5de5\u8d44\uff08\u5143\uff09\u662f\uff1a\" , weeklySalary ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff08\u5143\uff09\uff1a20 # \u8f93\u5165\u672c\u5468\u6b63\u5e38\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a40 # \u8f93\u5165\u672c\u5468\u603b\u52a0\u73ed\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a10 # \u5458\u5de5\u7684\u5468\u5de5\u8d44\uff08\u5143\uff09\u662f\uff1a 1100.0 def calculate_weekly_salary ( hourly_wage , normal_hours , overtime_hours ): overtime_pay = overtime_hours * hourly_wage * 1.5 normal_pay = normal_hours * hourly_wage weekly_salary = normal_pay + overtime_pay return weekly_salary def main (): try : hourly_wage = float ( input ( \"\u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a\" )) normal_hours = float ( input ( \"\u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) overtime_hours = float ( input ( \"\u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) weekly_salary = calculate_weekly_salary ( hourly_wage , normal_hours , overtime_hours ) print ( f \"\u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a { weekly_salary : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a20 # \u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a40 # \u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a10 # \u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a1100.00 class Employee : def __init__ ( self , hourly_wage , normal_hours , overtime_hours ): self . hourly_wage = hourly_wage self . normal_hours = normal_hours self . overtime_hours = overtime_hours def calculate_weekly_salary ( self ): overtime_pay = self . overtime_hours * self . hourly_wage * 1.5 normal_pay = self . normal_hours * self . hourly_wage weekly_salary = normal_pay + overtime_pay return weekly_salary def main (): try : hourly_wage = float ( input ( \"\u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a\" )) normal_hours = float ( input ( \"\u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) overtime_hours = float ( input ( \"\u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) employee = Employee ( hourly_wage , normal_hours , overtime_hours ) weekly_salary = employee . calculate_weekly_salary () print ( f \"\u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a { weekly_salary : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a20 # \u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a40 # \u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a10 # \u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a1100.00 3\uff0e\u6709\u4e00\u4e2a\u6807\u51c6\u7684\u79d1\u5b66\u5b9e\u9a8c\uff1a\u6254\u4e00\u4e2a\u7403\uff0c\u770b\u770b\u5b83\u80fd\u53cd\u5f39\u591a\u9ad8\u3002\u4e00\u65e6\u786e\u5b9a\u4e86\u7403\u7684\u201c\u53cd\u5f39\u9ad8\u5ea6\u201d\uff0c\u8fd9\u4e2a\u6bd4\u503c\u5c31\u7ed9\u51fa\u4e86\u76f8\u5e94\u7684\u53cd\u5f39\u5ea6\u6307\u6570\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4ece10ft\uff081ft=0.3048m\uff09\u9ad8\u5904\u6389\u843d\u7684\u7403\u53ef\u4ee5\u53cd\u5f39\u52306 ft\u9ad8\uff0c\u90a3\u4e48\u76f8\u5e94\u7684\u53cd\u5f39\u5ea6\u6307\u6570\u5c31\u662f0.6\uff1b\u5728\u4e00\u6b21\u53cd\u5f39\u4e4b\u540e\uff0c\u7403\u7684\u603b\u884c\u8fdb\u8ddd\u79bb\u662f16 ft\u3002\u63a5\u4e0b\u6765\uff0c\u7403\u7ee7\u7eed\u5f39\u8df3\uff0c\u90a3\u4e48\u4e24\u6b21\u5f39\u8df3\u540e\u7684\u603b\u8ddd\u79bb\u5e94\u8be5\u662f\uff1a10 ft + 6 ft + 6 ft + 3.6 ft = 25.6 ft\u3002\u53ef\u4ee5\u770b\u5230\uff0c\u6bcf\u6b21\u8fde\u7eed\u5f39\u8df3\u6240\u7ecf\u8fc7\u7684\u8ddd\u79bb\u662f\uff1a\u7403\u5230\u5730\u9762\u7684\u8ddd\u79bb\uff0c\u52a0\u4e0a\u8fd9\u4e2a\u8ddd\u79bb\u4e58\u4ee5 0.6\uff0c\u8fd9\u65f6\u7403\u53c8\u5f39\u56de\u6765\u4e86\u3002\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u53ef\u4ee5\u8ba9\u7528\u6237\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\u548c\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff0c\u5e76\u8f93\u51fa\u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u3002 \u89e3\u7b54\uff1a height = float ( input ( \"\u8f93\u5165\u5c0f\u7403\u521d\u59cb\u9ad8\u5ea6\uff08ft\uff09\uff1a\" )) times = float ( input ( \"\u8f93\u5165\u5141\u8bb8\u5c0f\u7403\u5f39\u8df3\u6b21\u6570\uff1a\" )) distance = 0 traceDistance = 0 while times : distance = height + 0.6 * height traceDistance += distance height = 0.6 * height times -= 1 print ( \"\u5c0f\u7403\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\uff08ft\uff09\uff1a\" , traceDistance ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u5c0f\u7403\u521d\u59cb\u9ad8\u5ea6\uff08ft\uff09\uff1a50 # \u8f93\u5165\u5141\u8bb8\u5c0f\u7403\u5f39\u8df3\u6b21\u6570\uff1a5 # \u5c0f\u7403\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\uff08ft\uff09\uff1a 184.448 # \u8f93\u5165\u5c0f\u7403\u521d\u59cb\u9ad8\u5ea6\uff08ft\uff09\uff1a100 # \u8f93\u5165\u5141\u8bb8\u5c0f\u7403\u5f39\u8df3\u6b21\u6570\uff1a10 # \u5c0f\u7403\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\uff08ft\uff09\uff1a 397.58135296000006 def calculate_total_distance ( initial_height , num_bounces ): rebound_factor = 0.6 total_distance = 0 height = initial_height for _ in range ( num_bounces + 1 ): total_distance += height height *= rebound_factor return total_distance def main (): try : initial_height = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a\" )) num_bounces = int ( input ( \"\u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a\" )) total_distance = calculate_total_distance ( initial_height , num_bounces ) print ( f \"\u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a { total_distance : .2f } ft\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a50 # \u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a5 # \u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a119.17 ft # \u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a100 # \u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a10 # \u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a249.09 ft class BouncingBall : def __init__ ( self , initial_height , num_bounces ): self . initial_height = initial_height self . num_bounces = num_bounces self . rebound_factor = 0.6 def calculate_total_distance ( self ): total_distance = 0 height = self . initial_height for _ in range ( self . num_bounces + 1 ): total_distance += height height *= self . rebound_factor return total_distance def main (): try : initial_height = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a\" )) num_bounces = int ( input ( \"\u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a\" )) bouncing_ball = BouncingBall ( initial_height , num_bounces ) total_distance = bouncing_ball . calculate_total_distance () print ( f \"\u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a { total_distance : .2f } ft\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () 4\uff0e\u5fb7\u56fd\u6570\u5b66\u5bb6Gottfried Leibniz\u53d1\u660e\u4e86\u4e0b\u9762\u8fd9\u4e2a\u7528\u6765\u6c42\u03c0\u7684\u8fd1\u4f3c\u503c\u7684\u65b9\u6cd5\uff1a \u03c0/4 = 1 - 1/3 + 1/5 - 1/7 + ...... \uff0c\u8bf7\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u6307\u5b9a\u8fd9\u4e2a\u8fd1\u4f3c\u503c\u6240\u4f7f\u7528\u7684\u8fed\u4ee3\u6b21\u6570\uff0c\u5e76\u4e14\u663e\u793a\u51fa\u7ed3\u679c\u3002 \u89e3\u7b54\uff1a n = int ( input ( \"\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a\" )) mySum = 0 while n : mySum += 1 / ( 2 * n - 1 ) * (( - 1 ) ** ( n + 1 )) n -= 1 print ( \"\u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a\" , mySum * 4 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a5 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.33968253968254 # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.0418396189294024 # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a20 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.0916238066678385 # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10000000 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.1415925535897933 def calculate_pi_approximation ( iterations ): approximation = 0 sign = 1 for i in range ( 1 , iterations * 2 , 2 ): approximation += sign * ( 1 / i ) sign *= - 1 return approximation * 4 def main (): try : iterations = int ( input ( \"\u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a\" )) if iterations <= 0 : print ( \"\u8fed\u4ee3\u6b21\u6570\u5fc5\u987b\u4e3a\u6b63\u6574\u6570\uff01\" ) return pi_approximation = calculate_pi_approximation ( iterations ) print ( f \"\u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a { pi_approximation : .10f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6574\u6570\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a5 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.3396825397 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0418396189 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a20 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0916238067 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10000000 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.1415925536 class PiApproximation : @classmethod def calculate_pi_approximation ( cls , iterations ): approximation = 0 sign = 1 for i in range ( 1 , iterations * 2 , 2 ): approximation += sign * ( 1 / i ) sign *= - 1 return approximation * 4 def main (): try : iterations = int ( input ( \"\u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a\" )) if iterations <= 0 : print ( \"\u8fed\u4ee3\u6b21\u6570\u5fc5\u987b\u4e3a\u6b63\u6574\u6570\uff01\" ) return pi_approximation = PiApproximation . calculate_pi_approximation ( iterations ) print ( f \"\u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a { pi_approximation : .10f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6574\u6570\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a5 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.3396825397 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0418396189 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a20 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0916238067 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10000000 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.1415925536 5\uff0e\u67d0\u8ba1\u7b97\u673a\u5546\u5e97\u6709\u8d2d\u4e70\u8ba1\u7b97\u673a\u7684\u4fe1\u8d37\u8ba1\u5212\uff1a\u9996\u4ed810%\uff0c\u5e74\u5229\u7387\u4e3a12%\uff0c\u6bcf\u6708\u6240\u4ed8\u6b3e\u4e3a\u8d2d\u4e70\u4ef7\u683c\u51cf\u53bb\u9996\u4ed8\u4e4b\u540e\u76845%\u3002\u7f16\u5199\u4e00\u4e2a\u4ee5\u8d2d\u4e70\u4ef7\u683c\u4e3a\u8f93\u5165\u7684\u7a0b\u5e8f\uff0c\u53ef\u4ee5\u8f93\u51fa\u4e00\u4e2a\u6709\u9002\u5f53\u6807\u9898\u7684\u8868\u683c\uff0c\u663e\u793a\u8d37\u6b3e\u671f\u9650\u5185\u7684\u4ed8\u6b3e\u8ba1\u5212\u3002\u8868\u7684\u6bcf\u4e00\u884c\u90fd\u5e94\u5305\u542b\u4e0b\u9762\u5404\u9879\uff1a \u6708\u6570\uff08\u4ee51\u5f00\u5934\uff09\uff1b \u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d\uff1b \u5f53\u6708\u6240\u6b20\u7684\u5229\u606f\uff1b \u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1\uff1b \u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d\uff1b \u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d\u3002 \u4e00\u4e2a\u6708\u7684\u5229\u606f\u7b49\u4e8e\u4f59\u989d \u00d7 \u5229\u7387/12\uff1b\u4e00\u4e2a\u6708\u6240\u6b20\u7684\u672c\u91d1\u7b49\u4e8e\u5f53\u6708\u8fd8\u6b3e\u989d\u51cf\u53bb\u6240\u6b20\u7684\u5229\u606f\u3002 \u89e3\u7b54\uff1a def calculate_payment_schedule ( purchase_price ): down_payment = purchase_price * 0.1 loan_balance = purchase_price - down_payment annual_interest_rate = 0.12 monthly_interest_rate = annual_interest_rate / 12 monthly_payment = ( purchase_price - down_payment ) * 0.05 payment_schedule = [] for month in range ( 1 , 13 ): interest = loan_balance * monthly_interest_rate principal = monthly_payment - interest loan_balance -= principal payment_schedule . append (( month , loan_balance , interest , principal , monthly_payment , loan_balance + monthly_payment )) return payment_schedule def main (): try : purchase_price = float ( input ( \"\u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a\" )) payment_schedule = calculate_payment_schedule ( purchase_price ) print ( \" {:<10} {:<15} {:<15} {:<15} {:<15} {:<15} \" . format ( \"\u6708\u6570\" , \"\u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d\" , \"\u5f53\u6708\u6240\u6b20\u7684\u5229\u606f\" , \"\u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1\" , \"\u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d\" , \"\u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d\" )) for payment in payment_schedule : month , balance , interest , principal , monthly_payment , new_balance = payment print ( \" {:<10} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} \" . format ( month , balance , interest , principal , monthly_payment , new_balance )) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a5000 # \u6708\u6570 \u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d \u5f53\u6708\u6240\u6b20\u7684\u5229\u606f \u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1 \u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d \u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d # 1 4320.00 45.00 180.00 225.00 4545.00 # 2 4138.20 43.20 181.80 225.00 4363.20 # 3 3954.58 41.38 183.62 225.00 4179.58 # 4 3769.13 39.55 185.45 225.00 3994.13 # 5 3581.82 37.69 187.31 225.00 3806.82 # 6 3392.64 35.82 189.18 225.00 3617.64 # 7 3201.56 33.93 191.07 225.00 3426.56 # 8 3008.58 32.02 192.98 225.00 3233.58 # 9 2813.67 30.09 194.91 225.00 3038.67 # 10 2616.80 28.14 196.86 225.00 2841.80 # 11 2417.97 26.17 198.83 225.00 2642.97 # 12 2217.15 24.18 200.82 225.00 2442.15 class PaymentSchedule : def __init__ ( self , purchase_price ): self . purchase_price = purchase_price self . down_payment = purchase_price * 0.1 self . loan_balance = purchase_price - self . down_payment self . annual_interest_rate = 0.12 self . monthly_interest_rate = self . annual_interest_rate / 12 self . monthly_payment = ( purchase_price - self . down_payment ) * 0.05 def calculate_schedule ( self ): payment_schedule = [] for month in range ( 1 , 13 ): interest = self . loan_balance * self . monthly_interest_rate principal = self . monthly_payment - interest self . loan_balance -= principal payment_schedule . append (( month , self . loan_balance , interest , principal , self . monthly_payment , self . loan_balance + self . monthly_payment )) return payment_schedule def print_schedule_table ( self ): payment_schedule = self . calculate_schedule () print ( \" {:<10} {:<15} {:<15} {:<15} {:<15} {:<15} \" . format ( \"\u6708\u6570\" , \"\u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d\" , \"\u5f53\u6708\u6240\u6b20\u7684\u5229\u606f\" , \"\u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1\" , \"\u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d\" , \"\u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d\" )) for payment in payment_schedule : month , balance , interest , principal , monthly_payment , new_balance = payment print ( \" {:<10} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} \" . format ( month , balance , interest , principal , monthly_payment , new_balance )) def main (): try : purchase_price = float ( input ( \"\u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a\" )) payment_schedule = PaymentSchedule ( purchase_price ) payment_schedule . print_schedule_table () except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # \u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a5000 # \u6708\u6570 \u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d \u5f53\u6708\u6240\u6b20\u7684\u5229\u606f \u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1 \u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d \u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d # 1 4320.00 45.00 180.00 225.00 4545.00 # 2 4138.20 43.20 181.80 225.00 4363.20 # 3 3954.58 41.38 183.62 225.00 4179.58 # 4 3769.13 39.55 185.45 225.00 3994.13 # 5 3581.82 37.69 187.31 225.00 3806.82 # 6 3392.64 35.82 189.18 225.00 3617.64 # 7 3201.56 33.93 191.07 225.00 3426.56 # 8 3008.58 32.02 192.98 225.00 3233.58 # 9 2813.67 30.09 194.91 225.00 3038.67 # 10 2616.80 28.14 196.86 225.00 2841.80 # 11 2417.97 26.17 198.83 225.00 2642.97 # 12 2217.15 24.18 200.82 225.00 2442.15 6\uff0e\u8d22\u52a1\u90e8\u95e8\u5728\u6587\u672c\u6587\u4ef6\u91cc\u4fdd\u5b58\u4e86\u6240\u6709\u5458\u5de5\u5728\u6bcf\u4e2a\u5de5\u8d44\u5468\u671f\u91cc\u7684\u4fe1\u606f\u5217\u8868\u3002\u6587\u4ef6\u4e2d\u6bcf\u4e00\u884c\u7684\u683c\u5f0f\u4e3a \u3002\u8bf7\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u8f93\u5165\u6587\u4ef6\u7684\u540d\u79f0\uff0c\u5e76\u5728\u7ec8\u7aef\u4e0a\u6253\u5370\u51fa\u7ed9\u5b9a\u65f6\u95f4\u5185\u652f\u4ed8\u7ed9\u6bcf\u4e2a\u5458\u5de5\u7684\u5de5\u8d44\u62a5\u544a\u3002\u8fd9\u4e2a\u62a5\u544a\u662f\u4e00\u4e2a\u6709\u5408\u9002\u6807\u9898\u7684\u8868\uff0c\u5176\u4e2d\u6bcf\u884c\u90fd\u5e94\u8be5\u5305\u542b\u5458\u5de5\u7684\u59d3\u540d\u3001\u5de5\u4f5c\u65f6\u957f\u4ee5\u53ca\u7ed9\u5b9a\u65f6\u95f4\u5185\u6240\u652f\u4ed8\u7684\u5de5\u8d44\u3002 \u89e3\u7b54\uff1a # \u7a0b\u5e8f\u4f1a\u63d0\u793a\u7528\u6237\u8f93\u5165\u6587\u4ef6\u540d\uff0c\u7136\u540e\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u5458\u5de5\u4fe1\u606f\uff0c\u8ba1\u7b97\u5de5\u8d44\u62a5\u544a\uff0c\u5e76\u6253\u5370\u51fa\u5458\u5de5\u7684\u59d3\u540d\u3001\u5de5\u4f5c\u65f6\u957f\u548c\u652f\u4ed8\u5de5\u8d44\u3002\u6ce8\u610f\uff0c\u7a0b\u5e8f\u4f1a\u68c0\u67e5\u6587\u4ef6\u662f\u5426\u5b58\u5728\uff0c\u5e76\u4f1a\u5bf9\u6587\u4ef6\u4e2d\u7684\u6bcf\u884c\u6570\u636e\u8fdb\u884c\u5904\u7406\u4ee5\u786e\u4fdd\u6b63\u786e\u89e3\u6790\u3002 class Employee : def __init__ ( self , last_name , hourly_wage , hours_worked ): self . last_name = last_name self . hourly_wage = float ( hourly_wage ) self . hours_worked = float ( hours_worked ) def calculate_salary ( self ): return self . hourly_wage * self . hours_worked def main (): try : filename = input ( \"\u8bf7\u8f93\u5165\u6587\u4ef6\u540d\uff1a\" ) with open ( filename , 'r' ) as file : employees = [] for line in file : parts = line . strip () . split () if len ( parts ) == 3 : last_name , hourly_wage , hours_worked = parts employee = Employee ( last_name , hourly_wage , hours_worked ) employees . append ( employee ) print ( \" {:<20} {:<15} {:<15} \" . format ( \"\u5458\u5de5\u59d3\u540d\" , \"\u5de5\u4f5c\u65f6\u957f\" , \"\u652f\u4ed8\u5de5\u8d44\" )) print ( \"=\" * 50 ) total_salary = 0 for employee in employees : salary = employee . calculate_salary () total_salary += salary print ( \" {:<20} {:<15.2f} {:<15.2f} \" . format ( employee . last_name , employee . hours_worked , salary )) print ( \"=\" * 50 ) print ( f \"\u603b\u652f\u4ed8\u5de5\u8d44\uff1a { total_salary : .2f } \" ) except FileNotFoundError : print ( \"\u6587\u4ef6\u4e0d\u5b58\u5728\uff01\" ) if __name__ == \"__main__\" : main () 7\uff0e\u7edf\u8ba1\u5b66\u5bb6\u5e0c\u671b\u4f7f\u7528\u4e00\u7ec4\u51fd\u6570\u8ba1\u7b97\u6570\u5b57\u5217\u8868\u7684\u4e2d\u4f4d\u6570\uff08median\uff09\u548c\u4f17\u6570\uff08mode\uff09\u3002\u4e2d\u4f4d\u6570\u662f\u6307\u5982\u679c\u5bf9\u5217\u8868\u8fdb\u884c\u6392\u5e8f\u5c06\u4f1a\u51fa\u73b0\u5728\u5217\u8868\u4e2d\u70b9\u7684\u6570\u5b57\uff0c\u4f17\u6570\u662f\u6307\u5217\u8868\u4e2d\u6700\u5e38\u51fa\u73b0\u7684\u6570\u5b57\u3002\u628a\u8fd9\u4e9b\u529f\u80fd\u5b9a\u4e49\u5728\u540d\u53ebstats.py\u7684\u6a21\u5757\u4e2d\u3002\u9664\u6b64\u4e4b\u5916\uff0c\u6a21\u5757\u8fd8\u5e94\u8be5\u5305\u542b\u4e00\u4e2a\u540d\u53ebmean\u7684\u51fd\u6570\uff0c\u7528\u6765\u8ba1\u7b97\u4e00\u7ec4\u6570\u5b57\u7684\u5e73\u5747\u503c\u3002\u6bcf\u4e2a\u51fd\u6570\u90fd\u4f1a\u63a5\u6536\u4e00\u4e2a\u6570\u5b57\u5217\u8868\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u8fd4\u56de\u4e00\u4e2a\u6570\u5b57\u3002 \u89e3\u7b54\uff1a def median ( numbers ): sorted_numbers = sorted ( numbers ) length = len ( sorted_numbers ) if length % 2 == 1 : return sorted_numbers [ length // 2 ] else : mid1 = sorted_numbers [ length // 2 - 1 ] mid2 = sorted_numbers [ length // 2 ] return ( mid1 + mid2 ) / 2 def mode ( numbers ): from collections import Counter counter = Counter ( numbers ) mode_list = counter . most_common () max_count = mode_list [ 0 ][ 1 ] modes = [ num for num , count in mode_list if count == max_count ] return modes def mean ( numbers ): total = sum ( numbers ) count = len ( numbers ) return total / count if __name__ == \"__main__\" : test_numbers = [ 4 , 2 , 7 , 2 , 1 , 9 , 4 , 7 ] print ( \"\u4e2d\u4f4d\u6570:\" , median ( test_numbers )) print ( \"\u4f17\u6570:\" , mode ( test_numbers )) print ( \"\u5e73\u5747\u503c:\" , mean ( test_numbers )) class Stats : @staticmethod def median ( numbers ): sorted_numbers = sorted ( numbers ) length = len ( sorted_numbers ) if length % 2 == 1 : return sorted_numbers [ length // 2 ] else : mid1 = sorted_numbers [ length // 2 - 1 ] mid2 = sorted_numbers [ length // 2 ] return ( mid1 + mid2 ) / 2 @staticmethod def mode ( numbers ): from collections import Counter counter = Counter ( numbers ) mode_list = counter . most_common () max_count = mode_list [ 0 ][ 1 ] modes = [ num for num , count in mode_list if count == max_count ] return modes @staticmethod def mean ( numbers ): total = sum ( numbers ) count = len ( numbers ) return total / count if __name__ == \"__main__\" : test_numbers = [ 4 , 2 , 7 , 2 , 1 , 9 , 4 , 7 ] print ( \"\u4e2d\u4f4d\u6570:\" , Stats . median ( test_numbers )) print ( \"\u4f17\u6570:\" , Stats . mode ( test_numbers )) print ( \"\u5e73\u5747\u503c:\" , Stats . mean ( test_numbers )) 8\uff0e\u7f16\u5199\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u6d4f\u89c8\u6587\u4ef6\u91cc\u7684\u6587\u672c\u884c\u3002\u8fd9\u4e2a\u7a0b\u5e8f\u4f1a\u63d0\u793a\u7528\u6237\u8f93\u5165\u6587\u4ef6\u540d\uff0c\u7136\u540e\u628a\u6587\u672c\u884c\u90fd\u8f93\u5165\u5217\u8868\u3002\u63a5\u4e0b\u6765\uff0c\u8fd9\u4e2a\u7a0b\u5e8f\u4f1a\u8fdb\u5165\u4e00\u4e2a\u5faa\u73af\uff0c\u5728\u8fd9\u4e2a\u5faa\u73af\u91cc\u6253\u5370\u51fa\u6587\u4ef6\u7684\u603b\u884c\u6570\uff0c\u5e76\u63d0\u793a\u7528\u6237\u8f93\u5165\u884c\u53f7\u3002\u8fd9\u4e2a\u884c\u53f7\u7684\u8303\u56f4\u5e94\u5f53\u662f1\u5230\u6587\u4ef6\u7684\u603b\u884c\u6570\u3002\u5982\u679c\u8f93\u5165\u662f0\uff0c\u90a3\u4e48\u7a0b\u5e8f\u9000\u51fa\uff1b\u5426\u5219\uff0c\u7a0b\u5e8f\u5c06\u6253\u5370\u51fa\u884c\u53f7\u6240\u5bf9\u5e94\u7684\u6587\u672c\u884c\u3002 def read_file_lines ( filename ): try : with open ( filename , 'r' ) as file : lines = file . readlines () return lines except FileNotFoundError : print ( \"\u6587\u4ef6\u4e0d\u5b58\u5728\uff01\" ) return [] def main (): filename = input ( \"\u8bf7\u8f93\u5165\u6587\u4ef6\u540d\uff1a\" ) lines = read_file_lines ( filename ) if not lines : return total_lines = len ( lines ) while True : print ( f \"\u6587\u4ef6\u603b\u884c\u6570\uff1a { total_lines } \" ) try : line_number = int ( input ( \"\u8bf7\u8f93\u5165\u884c\u53f7\uff08\u8f93\u51650\u9000\u51fa\uff09\uff1a\" )) if line_number == 0 : break elif 1 <= line_number <= total_lines : print ( f \"\u884c\u53f7 { line_number } : { lines [ line_number - 1 ] . strip () } \" ) else : print ( \"\u65e0\u6548\u7684\u884c\u53f7\uff0c\u8bf7\u8f93\u5165\u6b63\u786e\u8303\u56f4\u5185\u7684\u884c\u53f7\uff01\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () class TextFileBrowser : @classmethod def read_file_lines ( cls , filename ): try : with open ( filename , 'r' ) as file : lines = file . readlines () return lines except FileNotFoundError : print ( \"\u6587\u4ef6\u4e0d\u5b58\u5728\uff01\" ) return [] @classmethod def browse_file ( cls , filename ): lines = cls . read_file_lines ( filename ) if not lines : return total_lines = len ( lines ) while True : print ( f \"\u6587\u4ef6\u603b\u884c\u6570\uff1a { total_lines } \" ) try : line_number = int ( input ( \"\u8bf7\u8f93\u5165\u884c\u53f7\uff08\u8f93\u51650\u9000\u51fa\uff09\uff1a\" )) if line_number == 0 : break elif 1 <= line_number <= total_lines : print ( f \"\u884c\u53f7 { line_number } : { lines [ line_number - 1 ] . strip () } \" ) else : print ( \"\u65e0\u6548\u7684\u884c\u53f7\uff0c\u8bf7\u8f93\u5165\u6b63\u786e\u8303\u56f4\u5185\u7684\u884c\u53f7\uff01\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) def main (): filename = input ( \"\u8bf7\u8f93\u5165\u6587\u4ef6\u540d\uff1a\" ) TextFileBrowser . browse_file ( filename ) if __name__ == \"__main__\" : main () 9\uff0e\u5728\u672c\u7ae0\u8ba8\u8bba\u7684numberguess\u7a0b\u5e8f\u91cc\uff0c\u8ba1\u7b97\u673a\u4f1a\u201c\u6784\u601d\u201d\u4e00\u4e2a\u6570\u5b57\uff0c\u800c\u7528\u6237\u5219\u8f93\u5165\u731c\u6d4b\u7684\u503c\uff0c\u76f4\u5230\u731c\u5bf9\u4e3a\u6b62\u3002\u7f16\u5199\u8fd9\u6837\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u4f7f\u5176\u53ef\u4ee5\u8c03\u6362\u8fd9\u4e24\u4e2a\u89d2\u8272\uff0c\u4e5f\u5c31\u662f\uff1a\u7528\u6237\u53bb\u201c\u6784\u601d\u201d\u4e00\u4e2a\u6570\u5b57\uff0c\u7136\u540e\u8ba1\u7b97\u673a\u53bb\u8ba1\u7b97\u5e76\u8f93\u51fa\u731c\u6d4b\u7684\u503c\u3002\u548c\u524d\u9762\u90a3\u4e2a\u6e38\u620f\u7248\u672c\u4e00\u6837\uff0c\u5f53\u8ba1\u7b97\u673a\u731c\u9519\u65f6\uff0c\u7528\u6237\u5fc5\u987b\u7ed9\u51fa\u76f8\u5e94\u7684\u63d0\u793a\uff0c\u4f8b\u5982\u201c<\u201d\u548c\u201c>\u201d\uff08\u5206\u522b\u4ee3\u8868\u201c\u6211\u7684\u6570\u5b57\u66f4\u5c0f\u201d\u548c\u201c\u6211\u7684\u6570\u5b57\u66f4\u5927\u201d\uff09\u3002\u5f53\u8ba1\u7b97\u673a\u731c\u5bf9\u65f6\uff0c\u7528\u6237\u5e94\u8be5\u8f93\u5165\u201c=\u201d\u3002\u7528\u6237\u9700\u8981\u5728\u7a0b\u5e8f\u542f\u52a8\u7684\u65f6\u5019\u8f93\u5165\u6570\u5b57\u7684\u4e0b\u9650\u548c\u4e0a\u9650\u3002\u8ba1\u7b97\u673a\u5e94\u8be5\u5728\u6700\u591a [log2(high\u2212low)+1] \u6b21\u731c\u6d4b\u91cc\u627e\u5230\u6b63\u786e\u7684\u6570\u5b57\u3002\u7a0b\u5e8f\u5e94\u8be5\u80fd\u591f\u8ddf\u8e2a\u731c\u6d4b\u6b21\u6570\uff0c\u5982\u679c\u731c\u6d4b\u9519\u8bef\u7684\u6b21\u6570\u5230\u4e86\u5141\u8bb8\u731c\u6d4b\u7684\u6700\u5927\u503c\u4f46\u8fd8\u6ca1\u6709\u731c\u5bf9\uff0c\u5c31\u8f93\u51fa\u6d88\u606f\u201cYou're cheating\uff01\u201d\u3002\u4e0b\u9762\u662f\u548c\u8fd9\u4e2a\u7a0b\u5e8f\u8fdb\u884c\u4ea4\u4e92\u7684\u793a\u4f8b\uff1a Enter the smaller number : 1 Enter the larger number : 100 Your number is 50 Enter = , < , or > : > Your number is 75 Enter = , < , or > : < Your number is 62 Enter = , < , or > : < Your number is 56 Enter = , < , or > : = Hooray , I 've got it in 4 tries! import math class ComputerGuesser : def __init__ ( self , lower_limit , upper_limit ): self . lower_limit = lower_limit self . upper_limit = upper_limit self . max_attempts = math . floor ( math . log2 ( upper_limit - lower_limit + 1 )) + 1 self . attempts = 0 def guess ( self ): return ( self . lower_limit + self . upper_limit ) // 2 def play ( self ): print ( f \"\u8bf7\u4f60\u9009\u62e9\u4e00\u4e2a\u5728 { self . lower_limit } \u5230 { self . upper_limit } \u4e4b\u95f4\u7684\u6570\u5b57\u3002\" ) while self . attempts < self . max_attempts : guess = self . guess () print ( f \"\u6211\u7684\u731c\u6d4b\u662f\uff1a { guess } \" ) response = input ( \"\u8bf7\u8f93\u5165 =, <, \u6216 > \u6765\u6307\u793a\u662f\u5426\u731c\u5bf9\uff1a\" ) self . attempts += 1 if response == '=' : print ( f \"\u6211\u5728\u7b2c { self . attempts } \u6b21\u731c\u5bf9\u4e86\uff01\" ) break elif response == '<' : self . upper_limit = guess - 1 elif response == '>' : self . lower_limit = guess + 1 else : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u64cd\u4f5c\u7b26\uff1a=, <, \u6216 >\" ) if self . attempts >= self . max_attempts : print ( \"\u4f60\u5728\u6b3a\u9a97\u6211\uff01\" ) def main (): lower_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5c0f\u7684\u6570\u5b57\uff1a\" )) upper_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5927\u7684\u6570\u5b57\uff1a\" )) guesser = ComputerGuesser ( lower_limit , upper_limit ) guesser . play () if __name__ == \"__main__\" : main () import math class ComputerGuesser : def __init__ ( self , lower_limit , upper_limit ): self . lower_limit = lower_limit self . upper_limit = upper_limit self . max_attempts = math . floor ( math . log2 ( upper_limit - lower_limit + 1 )) + 1 self . attempts = 0 @classmethod def guess ( cls , lower_limit , upper_limit ): return ( lower_limit + upper_limit ) // 2 @classmethod def play ( cls , lower_limit , upper_limit ): print ( f \"\u8bf7\u4f60\u9009\u62e9\u4e00\u4e2a\u5728 { lower_limit } \u5230 { upper_limit } \u4e4b\u95f4\u7684\u6570\u5b57\u3002\" ) attempts = 0 while attempts < cls . max_attempts : guess = cls . guess ( lower_limit , upper_limit ) print ( f \"\u6211\u7684\u731c\u6d4b\u662f\uff1a { guess } \" ) response = input ( \"\u8bf7\u8f93\u5165 =, <, \u6216 > \u6765\u6307\u793a\u662f\u5426\u731c\u5bf9\uff1a\" ) attempts += 1 if response == '=' : print ( f \"\u6211\u5728\u7b2c { attempts } \u6b21\u731c\u5bf9\u4e86\uff01\" ) break elif response == '<' : upper_limit = guess - 1 elif response == '>' : lower_limit = guess + 1 else : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u64cd\u4f5c\u7b26\uff1a=, <, \u6216 >\" ) if attempts >= cls . max_attempts : print ( \"\u4f60\u5728\u6b3a\u9a97\u6211\uff01\" ) def main (): lower_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5c0f\u7684\u6570\u5b57\uff1a\" )) upper_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5927\u7684\u6570\u5b57\uff1a\" )) ComputerGuesser . play ( lower_limit , upper_limit ) if __name__ == \"__main__\" : main () 10\uff0e\u6709\u4e00\u4e2a\u7b80\u5355\u7684\u8bfe\u7a0b\u7ba1\u7406\u7cfb\u7edf\uff0c\u5b83\u901a\u8fc7\u4f7f\u7528\u540d\u5b57\u548c\u4e00\u7ec4\u8003\u8bd5\u5206\u6570\u6765\u6a21\u62df\u5b66\u751f\u7684\u4fe1\u606f\u3002\u8fd9\u4e2a\u7cfb\u7edf\u5e94\u8be5\u80fd\u591f\u521b\u5efa\u4e00\u4e2a\u5177\u6709\u7ed9\u5b9a\u540d\u5b57\u548c\u5206\u6570\uff08\u8d77\u521d\u5747\u4e3a0\uff09\u7684\u5b66\u751f\u5bf9\u8c61\u3002\u7cfb\u7edf\u5e94\u8be5\u80fd\u591f\u8bbf\u95ee\u548c\u66ff\u6362\u6307\u5b9a\u4f4d\u7f6e\u5904\u7684\u5206\u6570\uff08\u4ece0\u5f00\u59cb\u8ba1\u6570\uff09\u3001\u5f97\u5230\u5b66\u751f\u6709\u591a\u5c11\u6b21\u8003\u8bd5\u3001\u5f97\u5230\u7684\u6700\u9ad8\u5206\u3001\u5f97\u5230\u7684\u5e73\u5747\u5206\u4ee5\u53ca\u5b66\u751f\u7684\u59d3\u540d\u3002\u9664\u6b64\u4e4b\u5916\uff0c\u5728\u6253\u5370\u5b66\u751f\u5bf9\u8c61\u7684\u65f6\u5019\uff0c\u5e94\u8be5\u50cf\u4e0b\u9762\u8fd9\u6837\u663e\u793a\u5b66\u751f\u7684\u59d3\u540d\u548c\u5206\u6570\uff1a Name : Ken Lambert Score 1 : 88 Score 2 : 77 Score 3 : 100 \u8bf7\u5b9a\u4e49\u4e00\u4e2a\u652f\u6301\u8fd9\u4e9b\u529f\u80fd\u548c\u884c\u4e3a\u7684Student\u7c7b\uff0c\u5e76\u4e14\u7f16\u5199\u4e00\u4e2a\u521b\u5efaStudent\u5bf9\u8c61\u5e76\u8fd0\u884c\u5176\u65b9\u6cd5\u7684\u7b80\u77ed\u7684\u6d4b\u8bd5\u51fd\u6570\u3002 class Student : def __init__ ( self , name ): self . name = name self . scores = [] def add_score ( self , score ): self . scores . append ( score ) def replace_score ( self , index , score ): if 0 <= index < len ( self . scores ): self . scores [ index ] = score else : print ( \"\u65e0\u6548\u7684\u5206\u6570\u7d22\u5f15\" ) def num_scores ( self ): return len ( self . scores ) def highest_score ( self ): if self . scores : return max ( self . scores ) else : return None def average_score ( self ): if self . scores : return sum ( self . scores ) / len ( self . scores ) else : return None def display ( self ): print ( f \"Name: { self . name } \" ) for i , score in enumerate ( self . scores , start = 1 ): print ( f \"Score { i } : { score } \" ) def test_student_class (): student = Student ( \"Ken Lambert\" ) student . add_score ( 88 ) student . add_score ( 77 ) student . add_score ( 100 ) student . display () print ( f \"Total Scores: { student . num_scores () } \" ) print ( f \"Highest Score: { student . highest_score () } \" ) print ( f \"Average Score: { student . average_score () } \" ) if __name__ == \"__main__\" : test_student_class ()","title":"\u57fa\u7840\u77e5\u8bc6\u56de\u987e"},{"location":"python/DataStructure/01_PythonFundmantal/#1","text":"","title":"1.\u57fa\u7840\u77e5\u8bc6\u56de\u987e"},{"location":"python/DataStructure/01_PythonFundmantal/#11","text":"\u793a\u4f8b\u4ee3\u7801 numberguess.py \u3002 import random def main (): smaller = int ( input ( \"\u8f93\u5165\u6700\u5c0f\u503c: \" )) larger = int ( input ( \"\u8f93\u5165\u6700\u5927\u503c: \" )) myNumber = random . randint ( smaller , larger ) count = 0 while True : count += 1 userNumber = int ( input ( \"\u8f93\u5165\u4f60\u731c\u7684\u503c: \" )) if userNumber < myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5c0f\uff01\" ) elif userNumber > myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5927\uff01\" ) else : print ( \"\u606d\u559c\uff0c\u4f60\u5728\u7b2c\" , count , \"\u6b21\u731c\u5bf9\u4e86!\" ) break if __name__ == \"__main__\" : main () \u8fd0\u884c\u4ee3\u7801\uff1a $ python3 numberguess.py Enter the smaller number: 10 Enter the larger number: 60 Enter your guess: 50 Too large Enter your guess: 40 Too large Enter your guess: 30 Too large Enter your guess: 20 Too large Enter your guess: 10 Too small Enter your guess: 15 You\u2019ve got it in 6 tries!","title":"1.1.\u57fa\u672c\u7a0b\u5e8f\u8981\u7d20"},{"location":"python/DataStructure/01_PythonFundmantal/#111","text":"\u53d8\u91cf\uff1asalary\uff0choursWorked\uff0cisAbsent \u5e38\u6570\uff1aABSOLUTE_ZERO\uff0cINTEREST_RATE \u51fd\u6570\u6216\u65b9\u6cd5\uff1aprintResults\uff0ccubeRoot\uff0cinput \u7c7b\uff1aBankAccount\uff0cSortedSet \u901a\u5e38\u7ea6\u5b9a\uff1a\u53d8\u91cf\u540d\u662f\u540d\u8bcd\u3001\u5f62\u5bb9\u8bcd\uff08\u5e03\u5c14\u503c\uff09\uff0c\u51fd\u6570\u548c\u65b9\u6cd5\u662f\u52a8\u8bcd\uff08\u8868\u793a\u52a8\u4f5c\uff09\u3001\u540d\u8bcd\u3001\u6216\u5f62\u5bb9\u8bcd\uff08\u8868\u793a\u8fd4\u56de\u7684\u503c\uff09\u3002 \u8bed\u6cd5\u5143\u7d20\uff1a Python\u4f7f\u7528\u7a7a\u767d\u7b26\uff08\u7a7a\u683c\u3001\u5236\u8868\u7b26\u3001\u6216\u6362\u884c\u7b26\uff09\u6765\u8868\u793a\u4e0d\u540c\u7c7b\u578b\u7684\u8bed\u53e5\u7684\u8bed\u6cd5\u3002 \u901a\u5e38\u7ea6\u5b9a\u4f7f\u75284\u4e2a\u7a7a\u683c\u4f5c\u4e3a\u9501\u8fdb\u5bbd\u5ea6\u3002","title":"1.1.1.\u62fc\u5199\u548c\u547d\u540d\u60ef\u4f8b"},{"location":"python/DataStructure/01_PythonFundmantal/#112","text":"\u5355\u5f15\u53f7 \u53cc\u5f15\u53f7 \u6210\u5bf9\u7684\u4e09\u4e2a\u53cc\u5f15\u53f7\uff08\u591a\u884c\u6587\u672c\uff09 \u6210\u5bf9\u7684\u4e09\u4e2a\u5355\u5f15\u53f7\uff08\u591a\u884c\u6587\u672c\uff09 \u8f6c\u4e49\u5b57\u7b26 \\ \uff08\u53cd\u659c\u6760\uff09","title":"1.1.2.\u5b57\u7b26\u4e32"},{"location":"python/DataStructure/01_PythonFundmantal/#113","text":"\u6807\u51c6\u8fd0\u7b97\u7b26\uff1a + \u3001 - \u3001 * \u3001 / \u3001 % \u7b97\u672f\u8868\u8fbe\u5f0f\u662f\u7528\u6807\u51c6\u8fd0\u7b97\u7b26\u548c\u4e2d\u7f00\u8868\u793a\u6cd5 \u6bd4\u8f83\u8fd0\u7b97\u7b26\uff1a < \u3001 <= \u3001 > \u3001 >= \u3001 == \u3001 != \uff0c\u7528\u4e8e\u6bd4\u8f83\u6570\u5b57\u6216\u5b57\u7b26\u4e32\uff0c\u8fd4\u56deTrue\u6216False \u8fd0\u7b97\u7b26 == \u7528\u4e8e\u6bd4\u8f83\u6570\u636e\u7ed3\u6784\u91cc\u7684\u5185\u5bb9\uff0c\u8fd0\u7b97\u7b26 is \u7528\u4e8e\u6bd4\u8f83\u4e24\u4e2a\u5bf9\u8c61\u7684\u6807\u8bc6\u662f\u5426\u4e00\u81f4 \u903b\u8f91\u8fd0\u7b97\u7b26\uff1a and \u3001 or \u3001 not \u3002\u628a0\u3001None\u3001\u7a7a\u5b57\u7b26\u4e32\u3001\u7a7a\u5217\u8868\u7b49\u89c6\u4e3aFalse\uff0c\u5927\u591a\u6570\u5176\u4ed6\u503c\u662f\u4e3aTrue \u4e0b\u6807\u8fd0\u7b97\u7b26\uff1a [] \uff0c\u4e0e\u591a\u9879\u96c6collection\u5bf9\u8c61\u4e00\u8d77\u4f7f\u7528 \u9009\u62e9\u5668\u8fd0\u7b97\u7b26\uff1a . \uff0c\u7528\u4e8e\u5f15\u7528\u4e00\u4e2a\u6a21\u5757\u3001\u7c7b\u6216\u5bf9\u8c61\u4e2d\u7684\u4e00\u4e2a\u5177\u540d\u7684\u9879 \u8fd0\u7b97\u7b26\u4f18\u5148\u7ea7\uff0c\u4f9d\u6b21\u662f\u9009\u62e9\u8fd0\u7b97\u7b26\u3001\u51fd\u6570\u8c03\u7528\u8fd0\u7b97\u7b26\u3001\u4e0b\u6807\u8fd0\u7b97\u7b26\u3001\u7b97\u672f\u8fd0\u7b97\u7b26\u3001\u6bd4\u8f83\u8fd0\u7b97\u7b26\u3001\u903b\u8f91\u8fd0\u7b97\u7b26\u3001\u8d4b\u503c\u8fd0\u7b97\u7b26\u3002\u62ec\u53f7\u7528\u4e8e\u8ba9\u5b50\u8868\u8fbe\u5f0f\u4f18\u5148\u8fd0\u884c\u3002","title":"1.1.3.\u8fd0\u7b97\u7b26\u548c\u8868\u8fbe\u5f0f"},{"location":"python/DataStructure/01_PythonFundmantal/#114","text":"\u51fd\u6570\u540d\u79f0\u540e\u9762\u8ddf\u7740\u7528\u62ec\u53f7\u62ec\u8d77\u6765\u7684\u53c2\u6570\u5217\u8868\uff0c\u4f8b\u5982\uff1a min(5,2) \u6807\u51c6\u51fd\u6570 \u5176\u4ed6\u6a21\u5757\u5bfc\u5165\u51fd\u6570","title":"1.1.4.\u51fd\u6570\u8c03\u7528"},{"location":"python/DataStructure/01_PythonFundmantal/#115print","text":"\u81ea\u52a8\u4e3a\u6bcf\u4e2a\u53c2\u6570\u8fd0\u884c str \u51fd\u6570\uff0c\u4ee5\u5f97\u5230\u5176\u5b57\u7b26\u4e32\u8868\u793a \u5728\u8f93\u51fa\u4e4b\u524d\u4f1a\u7528\u7a7a\u683c\u5427\u6bcf\u4e2a\u5b57\u7b26\u4e32\u9694\u5f00 \u9ed8\u8ba4\u4ee5\u6362\u884c\u7b26\u4f5c\u4e3a\u7ed3\u675f","title":"1.1.5.print\u51fd\u6570"},{"location":"python/DataStructure/01_PythonFundmantal/#116input","text":"\u6807\u51c6\u8f93\u5165\u51fd\u6570input\u4f1a\u4e00\u76f4\u7b49\u5f85\u7528\u6237\u901a\u8fc7\u952e\u76d8\u8f93\u5165\u6587\u672c \u63a5\u53d7\u4e00\u4e2a\u53ef\u9009\u7684\u5b57\u7b26\u4e32\u4f5c\u4e3a\u5176\u53c2\u6570","title":"1.1.6.input\u51fd\u6570"},{"location":"python/DataStructure/01_PythonFundmantal/#117","text":"Python\u5141\u8bb8\u7b97\u672f\u8868\u8fbe\u5f0f\u4e2d\u7684\u64cd\u4f5c\u6570\u5177\u6709\u4e0d\u540c\u7684\u6570\u503c\u7c7b\u578b\u3002\u4f8b\u5982\uff0c\u628aint\u7c7b\u578b\u7684\u64cd\u4f5c\u6570\u548cfloat\u7c7b\u578b\u7684\u64cd\u4f5c\u6570\u76f8\u52a0\uff0c\u4f1a\u5f97\u5230float\u7c7b\u578b\u7684\u6570\u3002 # \u8f93\u5165\u534a\u5f84\u6c42\u5706\u9762\u79ef radius = float ( input ( \"Radius: \" )) print ( \"The area is\" , 3.14 * radius ** 2 )","title":"1.1.7.\u7c7b\u578b\u8f6c\u6362\u51fd\u6570\u548c\u6df7\u5408\u6a21\u5f0f\u64cd\u4f5c"},{"location":"python/DataStructure/01_PythonFundmantal/#118","text":"\u5fc5\u9009\u53c2\u6570\u662f\u6ca1\u6709\u9ed8\u8ba4\u503c\u7684\uff1b\u53ef\u9009\u53c2\u6570\u6709\u9ed8\u8ba4\u503c\uff1b \u5728\u8c03\u7528\u51fd\u6570\u65f6\uff0c\u4f20\u9012\u7ed9\u5b83\u7684\u53c2\u6570\u6570\u91cf\u5fc5\u987b\u81f3\u5c11\u548c\u5fc5\u9009\u53c2\u6570\u7684\u6570\u91cf\u76f8\u540c\u3002 \u6807\u51c6\u51fd\u6570\u548cPython\u7684\u5e93\u51fd\u6570\u5728\u8c03\u7528\u65f6\u90fd\u4f1a\u5bf9\u4f20\u5165\u7684\u53c2\u6570\u8fdb\u884c\u7c7b\u578b\u68c0\u67e5","title":"1.1.8.\u53ef\u9009\u548c\u5173\u952e\u5b57\u51fd\u6570\u53c2\u6570"},{"location":"python/DataStructure/01_PythonFundmantal/#119","text":"\u7b80\u5355\u7684\u8d4b\u503c\u8bed\u53e5 PI = 3.1416 \u591a\u53d8\u91cf\u8d4b\u503c minValue, maxValue = 1, 100 \u53d8\u91cf\u4ea4\u6362 a, b = b, a \u8d4b\u503c\u8bed\u53e5\u5fc5\u987b\u5199\u5728\u4e00\u884c\u4ee3\u7801\u91cc\uff0c\u4f46\u662f\u53ef\u4ee5\u5728\u9017\u53f7\u3001\u5706\u62ec\u53f7\u3001\u82b1\u62ec\u53f7\u6216\u65b9\u62ec\u53f7\u4e4b\u540e\u6362\u884c\uff0c\u6216\u8005\u7528\u8f6c\u4e49\u7b26 \\ \u8fdb\u884c\u6362\u884c\u3002 \u6362\u884c\u793a\u4f8b\uff1a minValue = min ( 100 , 200 ) product = max ( 100 , 200 ) \\ * 30","title":"1.1.9.\u53d8\u91cf\u548c\u8d4b\u503c\u8bed\u53e5"},{"location":"python/DataStructure/01_PythonFundmantal/#1110","text":"\u53d8\u91cf\u90fd\u53ef\u4ee5\u88ab\u6307\u5b9a\u4e3a\u4efb\u4f55\u7c7b\u578b\u7684\u503c\u3002\u8fd9\u4e9b\u53d8\u91cf\u5e76\u4e0d\u50cf\u5176\u4ed6\u8bed\u8a00\u90a3\u6837\u88ab\u58f0\u660e\u4e3a\u7279\u5b9a\u7684\u7c7b\u578b\uff0c\u800c\u53ea\u662f\u88ab\u8d4b\u4e86\u4e00\u4e2a\u503c \u503c\u548c\u5bf9\u8c61\u90fd\u662f\u6709\u7c7b\u578b\u7684\uff0c\u4f1a\u5728\u8fd0\u884c\u65f6\u8fdb\u884c\u6570\u636e\u7c7b\u578b\u68c0\u67e5","title":"1.1.10.\u6570\u636e\u7c7b\u578b"},{"location":"python/DataStructure/01_PythonFundmantal/#1111import","text":"import \u8bed\u53e5\u4f7f\u5f97\u4e00\u4e2a\u6a21\u5757\u4e2d\u7684\u6807\u8bc6\u7b26\u53ef\u4ee5\u88ab\u53e6\u4e00\u4e2a\u7a0b\u5e8f\u6240\u89c1\u5230\u3002\u6807\u8bc6\u7b26\u53ef\u4ee5\u662f\u5bf9\u8c61\u540d\u3001\u51fd\u6570\u540d\u6216\u7c7b\u540d \u5bfc\u5165\u6a21\u5757\u540d\u79f0\uff0c\u4f8b\u5982 import math \u5bfc\u5165\u6a21\u5757\u4e2d\u7684\u6807\u8bc6\u7b26\uff0c\u4f8b\u5982\uff1a from math import sqrt \uff0c\u6216\u8005 from math import pi, sqrt \u4e5f\u53ef\u4ee5\u4f7f\u7528\u7b26\u53f7 * \u5bfc\u5165\u4e00\u4e2a\u6a21\u5757\u4e2d\u7684\u6240\u6709\u540d\u79f0\uff0c\u4f46\u4e0d\u63a8\u8350","title":"1.1.11.import\u8bed\u53e5"},{"location":"python/DataStructure/01_PythonFundmantal/#12","text":"","title":"1.2.\u63a7\u5236\u8bed\u53e5"},{"location":"python/DataStructure/01_PythonFundmantal/#121","text":"\u5355\u5411if\u8bed\u53e5\u7684\u8bed\u6cd5 if < Boolean expression > : < sequence of statements > \u53cc\u5411if\u8bed\u53e5\u7684\u8bed\u6cd5 if < Boolean expression > : < sequence of statements > else : < sequence of statements > \u591a\u5411if\u8bed\u53e5\u7684\u8bed\u6cd5 if < Boolean expression > : < sequence of statements > elif < Boolean expression > : < sequence of statements > ... else : < sequence of statements >","title":"1.2.1.\u6761\u4ef6\u8bed\u53e5"},{"location":"python/DataStructure/01_PythonFundmantal/#122if-name-main","text":"\u793a\u4f8b\u4ee3\u7801 numberguess.py \u3002 import random def main (): smaller = int ( input ( \"\u8f93\u5165\u6700\u5c0f\u503c: \" )) larger = int ( input ( \"\u8f93\u5165\u6700\u5927\u503c: \" )) myNumber = random . randint ( smaller , larger ) count = 0 while True : count += 1 userNumber = int ( input ( \"\u8f93\u5165\u4f60\u731c\u7684\u503c: \" )) if userNumber < myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5c0f\uff01\" ) elif userNumber > myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5927\uff01\" ) else : print ( \"\u606d\u559c\uff0c\u4f60\u5728\u7b2c\" , count , \"\u6b21\u731c\u5bf9\u4e86!\" ) break if __name__ == \"__main__\" : main () \u4e0a\u9762\u7684if\u8bed\u53e5\u7684\u4f5c\u7528\u662f\uff0c \u8981\u4e48\u5c06\u6a21\u5757\u5f53\u4f5c\u4e00\u4e2a\u72ec\u7acb\u7684\u7a0b\u5e8f\u8fd0\u884c\uff0c\u8be5\u6a21\u5757\u7684 _name_ \u53d8\u91cf\u4f1a\u8bbe\u7f6e\u4e3a\u5b57\u7b26\u4e32 _main_ \uff0c\u624d\u4f1a\u6267\u884c main() \u51fd\u6570 \u8981\u4e48\u4ece\u53e6\u4e00\u4e2a\u6a21\u5757\u4e2d\u5bfc\u5165\uff0c\u8be5\u6a21\u5757\u7684 _name_ \u53d8\u91cf\u4f1a\u8bbe\u7f6e\u8be5\u6a21\u5757\u7684\u540d\u79f0\uff0c\u4e0a\u4f8b\u4e2d\u5373 numberguess","title":"1.2.2.\u4f7f\u7528if name == \"main\""},{"location":"python/DataStructure/01_PythonFundmantal/#123","text":"\u901a\u5e38\uff1a \u4e00\u822c\u4f1a\u4f7f\u7528for\u5faa\u73af\u6765\u8fed\u4ee3\u786e\u5b9a\u8303\u56f4\u7684\u503c\u6216\u503c\u7684\u5e8f\u5217 \u5982\u679c\u7ee7\u7eed\u5faa\u73af\u7684\u6761\u4ef6\u662f\u67d0\u4e2a\u5e03\u5c14\u8868\u8fbe\u5f0f\uff0c\u4e00\u822c\u4f1a\u4f7f\u7528while\u5faa\u73af while \u8bed\u6cd5\u683c\u5f0f\uff1a while < Boolean expression > : < sequence of statements > \u793a\u4f8b\uff1a # \u8ba1\u7b97\u4ece1\u523010\u7684\u4e58\u79ef\u5e76\u8f93\u51fa\u7ed3\u679c result = 1 value = 1 while value <= 10 : result *= value value += 1 print ( result , value ) # \u8fd0\u884c\u7ed3\u679c # 3628800 11 for \u8bed\u6cd5\u683c\u5f0f\uff1a for < variable > in < iterable object > : < sequence of statements > \u793a\u4f8b\uff1a # \u8ba1\u7b97\u4ece1\u523010\u7684\u4e58\u79ef\u5e76\u8f93\u51fa\u7ed3\u679c result = 1 value = 1 for value in range ( 1 , 11 ): result *= value value += 1 print ( result , value ) # \u8fd0\u884c\u7ed3\u679c # 3628800 11","title":"1.2.3.\u5faa\u73af\u8bed\u53e5"},{"location":"python/DataStructure/01_PythonFundmantal/#13","text":"Python\u4e2d\u7684\u5b57\u7b26\u4e32\u4e5f\u662f\u4e00\u4e2a\u590d\u5408\u5bf9\u8c61 Python\u7684\u5b57\u7b26\u4e32\u7c7b\u578b\u540d\u4e3a str \u7ea6\u5b9a\uff1a \u628a\u5355\u5b57\u7b26\u7684\u5b57\u7b26\u4e32\u7528\u5355\u5f15\u53f7\u62ec\u8d77\u6765 \u628a\u591a\u5b57\u7b26\u7684\u5b57\u7b26\u4e32\u7528\u53cc\u5f15\u53f7\u62ec\u8d77\u6765","title":"1.3.\u5b57\u7b26\u4e32\u53ca\u5176\u8fd0\u7b97"},{"location":"python/DataStructure/01_PythonFundmantal/#131","text":"\u6bd4\u8f83\u8fd0\u7b97\u7b26\uff0c\u662f\u6309\u7167ASCII\u7801\u7684\u987a\u5e8f\u6bd4\u8f83\u4e24\u4e2a\u5b57\u7b26\u4e32\u4e2d\u6bcf\u4e2a\u4f4d\u7f6e\u7684\u5b57\u7b26\u5bf9 \u793a\u4f8b\uff1a print ( 'A' > 'a' ) # \u8fd0\u884c\u7ed3\u679c False print ( 'A' < 'a' ) # \u8fd0\u884c\u7ed3\u679c True + \u8fd0\u7b97\u7b26\u751f\u6210\u5e76\u8fd4\u56de\u4e00\u4e2a\u5305\u542b\u4e24\u4e2a\u64cd\u4f5c\u6570\u7684\u65b0\u5b57\u7b26\u4e32 \u793a\u4f8b\uff1a print ( \"Hello\" + \"Python\" ) # \u8fd0\u884c\u7ed3\u679c HelloPython \u4e0b\u6807\u8fd0\u7b97\u7b26\uff0c\u8303\u56f4\u662f\u4ece0\u5230\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u51cf\u53bb1\u7684\u4e00\u4e2a\u6574\u6570\u3002 \u8fd0\u7b97\u7b26\u8fd4\u56de\u5728\u5b57\u7b26\u4e32\u4e2d\u8be5\u4f4d\u7f6e\u7684\u5b57\u7b26\u3002 \u793a\u4f8b\uff1a print ( \"Greater\" [ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1ar \u5f53\u7d22\u5f15\u4e3a\u8d1f\u503c\u65f6\uff0cPython\u4f1a\u628a\u8fd9\u4e2a\u503c\u548c\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u76f8\u52a0\uff0c\u4ee5\u786e\u5b9a\u8981\u8fd4\u56de\u7684\u5b57\u7b26\u7684\u4f4d\u7f6e\u3002\u8d1f\u7d22\u5f15\u503c\u4e0d\u5f97\u5c0f\u4e8e\u5b57\u7b26\u4e32\u957f\u5ea6\u7684\u8d1f\u503c\u3002 print ( \"Greater\" [ - 3 ]) # \u8fd0\u884c\u7ed3\u679c\uff1at print ( \"Greater\" [ - 9 ]) # \u8fd0\u884c\u7ed3\u679c\uff1aIndexError: string index out of range \u5207\u7247\u8fd0\u7b97\u7b26\uff08slice operator\uff09\uff0c\u4e0b\u6807\u8fd0\u7b97\u7b26\u7684\u4e00\u79cd\u53d8\u4f53\u3002 \u8bed\u6cd5\u683c\u5f0f\uff1a [:] \uff1a\u8303\u56f4\u662f\u4ece0\u5230\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u51cf\u53bb1\u7684\u6574\u6570 \uff1a\u8303\u56f4\u662f\u4ece0\u5230\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u7684\u6574\u6570 \u5207\u7247\u68c0\u7d22\u89c4\u5219\uff1a \u8fd4\u56de\u8fd9\u6837\u4e00\u4e2a\u5b50\u5b57\u7b26\u4e32\uff1a\u8fd9\u4e2a\u5b50\u5b57\u7b26\u4e32\u4f1a\u4ece \u7d22\u5f15\u5904\u7684\u5b57\u7b26\u5f00\u59cb\uff0c\u5230 \u7d22\u5f15\u51cf1\u7684\u4f4d\u7f6e\u4f5c\u4e3a\u7ed3\u675f\u3002 \u5982\u679c\u7701\u7565 \u7d22\u5f15\uff0c\u90a3\u4e48\u5207\u7247\u8fd0\u7b97\u7b26\u5c06\u8fd4\u56de\u4e00\u4e2a\u4ee5\u5f53\u524d\u5b57\u7b26\u4e32\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\u4f5c\u4e3a\u5f00\u5934\u7684\u5b50\u5b57\u7b26\u4e32\u3002 \u5982\u679c\u7701\u7565 \u7d22\u5f15\uff0c\u90a3\u4e48\u5207\u7247\u8fd0\u7b97\u7b26\u5c06\u8fd4\u56de\u4e00\u4e2a\u4ee5\u5f53\u524d\u5b57\u7b26\u4e32\u7684\u6700\u540e\u4e00\u4e2a\u5b57\u7b26\u4f5c\u4e3a\u7ed3\u5c3e\u7684\u5b50\u5b57\u7b26\u4e32\u3002 \u5982\u679c\u7701\u7565\u8fd9\u4e24\u4e2a\u503c\uff0c\u90a3\u4e48\u5207\u7247\u8fd0\u7b97\u7b26\u4f1a\u8fd4\u56de\u6574\u4e2a\u5b57\u7b26\u4e32\u3002 \u793a\u4f8b\uff1a print ( \"Greater\" [:]) # \u8fd4\u56de\u5b57\u4e32 Greater print ( \"Greater\" [ 2 :]) # \u8fd4\u56de\u5b57\u4e32 eater print ( \"Greater\" [: 2 ]) # \u8fd4\u56de\u5b57\u4e32 Gr print ( \"Greater\" [ 2 : 5 ]) # \u8fd4\u56de\u5b57\u4e32 eat","title":"1.3.1.\u8fd0\u7b97\u7b26"},{"location":"python/DataStructure/01_PythonFundmantal/#132","text":"\u683c\u5f0f\u5316\u5b57\u7b26\u4e32\u91cc\u7684\u6570\u636e\u5b57\u7b26\u4ee5\u53ca\u6ee1\u8db3\u7ed9\u5b9a\u57fa\u51c6\u7ebf\u7684\u9644\u52a0\u7a7a\u683c\u7684\u603b\u6570\u79f0\u4e3a\u5b83\u7684\u5b57\u6bb5\u5bbd\u5ea6\uff08field width\uff09\u3002 print \u51fd\u6570\u4f1a\u5728\u9047\u5230\u7b2c\u4e00\u5217\u65f6\u81ea\u52a8\u5f00\u59cb\u6253\u5370\u8f93\u51fa\u57fa\u51c6\u7ebf\u3002 \u793a\u4f8b\uff0c\u901a\u8fc7print\u8bed\u53e5\u8f93\u51fa2\u5217\u3002 for i in range ( 7 , 11 ): print ( i , 10 * i ) # \u8fd0\u884c\u7ed3\u679c # 7 70 # 8 80 # 9 90 # 10 100 Python\u7684\u901a\u7528\u683c\u5f0f\u5316\u673a\u5236 \u8bed\u6cd5\u683c\u5f0f % \u548c % (, \u2026, ) \u3002 \u683c\u5f0f\u5316\u5b57\u7b26\u4e32\u65f6\uff0c \u4f7f\u7528 %s \u8868\u793a\u6cd5\u3002\u5f53\u5b57\u6bb5\u5bbd\u5ea6\u4e3a\u6b63\u65f6\uff0c\u6570\u636e\u662f\u53f3\u5bf9\u9f50\u7684\uff1b\u5f53\u5b57\u6bb5\u5bbd\u5ea6\u4e3a\u8d1f\u65f6\uff0c\u6570\u636e\u662f\u5de6\u5bf9\u9f50\u7684\u3002 \u683c\u5f0f\u6574\u6570\u65f6\uff0c \u4f7f\u7528 %d \u8868\u793a\u6cd5\u3002 \u683c\u5f0f\u6d6e\u70b9\u6570\u65f6\uff0c \u4f7f\u7528 %.f \u8868\u793a\u6cd5\uff0c\u5176\u4e2d . \u8fd9\u4e00\u90e8\u5206\u662f\u53ef\u9009\u7684\u3002 \u793a\u4f8b\uff1a print ( \" %6s \" % \"four\" ) print ( \" %-6s \" % \"four\" ) # four # four for i in range ( 7 , 11 ): print ( \" %-3d%5d \" % ( i , 10 * i )) # 7 70 # 8 80 # 9 90 # 10 100 for i in range ( 7 , 11 ): print ( \" %-3d%5.3f \" % ( i , i / 3 )) # 7 2.333 # 8 2.667 # 9 3.000 # 10 3.333 \u4e0b\u4f8b\u5bf9\u6bd4\u4e86\u6d6e\u70b9\u6570\u5728\u4f7f\u7528\u4e86\u683c\u5f0f\u5b57\u7b26\u4e32\u548c\u6ca1\u6709\u4f7f\u7528\u683c\u5f0f\u5b57\u7b26\u4e32\u8fd9\u4e24\u79cd\u60c5\u51b5\u4e0b\u7684\u8f93\u51fa\u5dee\u5f02\u3002 salary = 100.00 print ( \"Salary: $\" + str ( salary )) # Salary: $100.0 print ( \"Salary: $ %0.2f \" % salary ) # Salary: $100.00 \u6ce8\u610f\uff0c\u4e0b\u4f8b\u4e2dPython\u7ed9\u6570\u5b57\u6dfb\u52a0\u4e86\u4e00\u4e2a\u7cbe\u5ea6\u4f4d\u6570\uff0c\u5e76\u4e14\u5176\u5de6\u4fa7\u586b\u5145\u7a7a\u683c\uff0c\u4ece\u800c\u5b9e\u73b0\u4e86\u5b57\u6bb5\u5bbd\u5ea6\u4e3a6\u3001\u7cbe\u5ea6\u4e3a3\u7684\u8bbe\u7f6e\u3002\u8fd9\u4e2a\u5bbd\u5ea6\u5305\u542b\u5c0f\u6570\u70b9\u540e\u6240\u5360\u636e\u7684\u4f4d\u7f6e\u3002 print ( \" %6.3f \" % 3.14 ) # \u5de6\u4fa7\u586b\u5145\u4e86\u7a7a\u683c # 3.140 print ( \" %-6.3f \" % 3.14 ) # 3.140","title":"1.3.2.\u5b57\u7b26\u4e32\u683c\u5f0f\u5316"},{"location":"python/DataStructure/01_PythonFundmantal/#133","text":"\u8bed\u6cd5\u683c\u5f0f\uff1a .() \u793a\u4f8b\uff1a print ( \"greater\" . isupper ()) # \u8fd0\u884c\u7ed3\u679c # False print ( \"greater\" . upper ()) # \u8fd0\u884c\u7ed3\u679c # GREATER print ( \"greater\" . startswith ( \"great\" )) # \u8fd0\u884c\u7ed3\u679c # True print ( len ( \"greater\" )) print ( \"greater\" . __len__ ()) # \u8fd0\u884c\u7ed3\u679c # 7 print ( \"great\" + \"er\" ) print ( \"great\" . __add__ ( \"er\" )) # \u8fd0\u884c\u7ed3\u679c # greater print ( \"e\" in \"great\" ) print ( \"great\" . __contains__ ( \"e\" )) # \u8fd0\u884c\u7ed3\u679c # True \u63d0\u793a\uff1a dir() \u65b9\u6cd5\u4f1a\u8fd4\u56de\u6240\u4f20\u9012\u7684\u5bf9\u8c61\u7684\u6709\u6548\u5c5e\u6027\uff0c\u8bed\u6cd5\u683c\u5f0f\uff1a dir(object) help() \u51fd\u6570\u67e5\u770b\u51fd\u6570\u6216\u6a21\u5757\u7528\u9014\u7684\u8be6\u7ec6\u8bf4\u660e\uff0c\u8bed\u6cd5\u683c\u5f0f\uff1a help(object) dir ( str ) help ( str . __contains__ )","title":"1.3.3.\u5bf9\u8c61\u548c\u65b9\u6cd5\u8c03\u7528"},{"location":"python/DataStructure/01_PythonFundmantal/#14","text":"Python\u4e2d\u7684\u591a\u9879\u96c6\uff08collections\uff09\u6307\u80fd\u591f\u5305\u542b\u5143\u7d20\u7684\u6570\u636e\u7ed3\u6784\u3002\u591a\u9879\u96c6\u6a21\u5757\u63d0\u4f9b\u4e86\u4e0d\u540c\u7c7b\u578b\u7684\u5bb9\u5668\u3002\u5bb9\u5668\u662f\u7528\u4e8e\u5b58\u50a8\u4e0d\u540c\u5bf9\u8c61\u5e76\u63d0\u4f9b\u8bbf\u95ee\u6240\u5305\u542b\u5bf9\u8c61\u4ee5\u53ca\u5bf9\u5b83\u4eec\u8fdb\u884c\u8fed\u4ee3\u7684\u65b9\u5f0f\u7684\u5bf9\u8c61\u3002\u4e00\u4e9b\u5185\u7f6e\u7684\u5bb9\u5668\u6709\u5143\u7ec4\uff08Tuple\uff09\u3001\u5217\u8868\uff08List\uff09\u3001\u5b57\u5178\uff08Dictionary\uff09\u7b49\u3002 \u4ee5\u4e0b\u662f\u7531collections\u6a21\u5757\u63d0\u4f9b\u7684\u4e0d\u540c\u5bb9\u5668\u7684\u5217\u8868\uff1a \u8ba1\u6570\u5668\uff08Counters\uff09 \u6709\u5e8f\u5b57\u5178\uff08OrderedDict\uff09 \u9ed8\u8ba4\u5b57\u5178\uff08DefaultDict\uff09 \u94fe\u6620\u5c04\uff08ChainMap\uff09 \u547d\u540d\u5143\u7ec4\uff08NamedTuple\uff09 \u53cc\u5411\u961f\u5217\uff08DeQue\uff09 \u7528\u6237\u5b57\u5178\uff08UserDict\uff09 \u7528\u6237\u5217\u8868\uff08UserList\uff09 \u7528\u6237\u5b57\u7b26\u4e32\uff08UserString\uff09","title":"1.4.\u5185\u7f6e\u591a\u9879\u96c6\u53ca\u5176\u64cd\u4f5c"},{"location":"python/DataStructure/01_PythonFundmantal/#141","text":"\u5217\u8868\uff08list\uff09\u662f\u96f6\u4e2a\u6216\u591a\u4e2aPython\u5bf9\u8c61\u7684\u4e00\u4e2a\u5e8f\u5217\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u901a\u5e38\u79f0\u4e3a\u9879\uff08item\uff09\u3002 \u5217\u8868\u7684\u8868\u73b0\u5f62\u5f0f\u662f\uff1a\u7528\u65b9\u62ec\u53f7\u62ec\u8d77\u6574\u4e2a\u5217\u8868\uff0c\u5e76\u7528\u9017\u53f7\u5206\u9694\u5143\u7d20\u3002 \u793a\u4f8b\uff1a [] # \u7a7a\u5217\u8868 [ \"greater\" , \"less\" , 10 ] # \u542b\u4e0d\u540c\u7c7b\u578b\u7684\u5217\u8868 [ \"greater\" , [ \"less\" , 10 ]] # \u542b\u5185\u5d4c\u5217\u8868\u7684\u5217\u8868 \u5217\u8868\u7684\u5207\u7247\u64cd\u4f5c\uff1a \u548c\u5b57\u7b26\u4e32\u7c7b\u4f3c\uff0c\u53ef\u4ee5\u901a\u8fc7\u6807\u51c6\u8fd0\u7b97\u7b26\u6267\u884c\u5207\u7247\u6216\u8fde\u63a5\u64cd\u4f5c\uff0c\u8fd4\u56de\u7ed3\u679c\u4e5f\u662f\u5217\u8868\u3002 \u548c\u5b57\u7b26\u4e32\u4e0d\u540c\uff0c\u5217\u8868\u662f\u53ef\u53d8\u7684\uff0c\u5373\uff0c\u53ef\u4ee5\u66ff\u6362\u3001\u63d2\u5165\u6216\u5220\u9664\u5217\u8868\u4e2d\u6240\u5305\u542b\u7684\u9879\u3002 \u5207\u7247\u548c\u8fde\u63a5\u8fd0\u7b97\u7b26\u6240\u8fd4\u56de\u7684\u5217\u8868\u662f\u65b0\u7684\u5217\u8868\uff0c\u800c\u4e0d\u662f\u6700\u521d\u5217\u8868\u7684\u4e00\u90e8\u5206\uff1b \u5217\u8868\u7c7b\u578b\u5305\u542b\u4e86\u51e0\u4e2a\u53eb\u4f5c\u53d8\u5f02\u5668\uff08mutator\uff09\u7684\u65b9\u6cd5\uff0c\u7528\u4e8e\u4fee\u6539\u5217\u8868\u7684\u7ed3\u6784\u3002 \u53ef\u4ee5\u901a\u8fc7 dir(list) \u6765\u67e5\u770b\u65b9\u6cd5\uff0c\u5305\u62ec\u53d8\u5f02\u5668\uff08mutator\uff09\u7684\u65b9\u6cd5\u3002 dir ( list ) # \u8fd0\u884c\u7ed3\u679c # ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] \u6700\u5e38\u7528\u7684\u5217\u8868\u53d8\u5f02\u5668\u65b9\u6cd5\u662f append \u3001 insert \u3001 pop \u3001 remove \u548c sort \u3002 \u793a\u4f8b\uff1a myList = [] # myList\u5f53\u524d\u4e3a[] myList . append ( 34 ) # myList\u5f53\u524d\u4e3a[34]\uff0c\u9ed8\u8ba4\u5c3e\u90e8\u63d2\u5165 myList . append ( 22 ) # myList\u5f53\u524d\u4e3a[34, 22]\uff0c\u9ed8\u8ba4\u5c3e\u90e8\u63d2\u5165 myList . sort () # myList\u5f53\u524d\u4e3a[22, 34] myList . pop () # \u9ed8\u8ba4\u4ece\u7d22\u5f15\u4f4d[0]\u5220\u9664\uff0c\u8fd4\u56de\u7ed3\u679c22\uff1bmyList\u5f53\u524d\u4e3a[34] myList . insert ( 0 , 22 ) # \u5728\u6307\u5b9a\u7d22\u5f15\u4f4d[0]\u63d2\u5165\uff1bmyList\u5f53\u524d\u4e3a[22, 34] myList . insert ( 1 , 55 ) # \u5728\u6307\u5b9a\u7d22\u5f15\u4f4d[1]\u63d2\u5165\uff1bmyList\u5f53\u524d\u4e3a[22, 55, 34] myList . pop ( 1 ) # \u6307\u5b9a\u7d22\u5f15\u4f4d[1]\u5220\u9664\uff0c\u8fd4\u56de\u7ed3\u679c55\uff1bmyList\u5f53\u524d\u4e3a[22, 34] myList . remove ( 22 ) # \u5220\u9664\u9996\u4e2a\u5339\u914d\u9879\u7684\u5143\u7d20[22]\uff1bmyList\u5f53\u524d\u4e3a[34] myList . remove ( 55 ) # \u62a5ValueError\u9519\uff0clist.remove(x): x not in list \u5bf9\u4e8e\u5b57\u7b26\u4e32\uff0csplit\u65b9\u6cd5\u4f1a\u4ece\u5b57\u7b26\u4e32\u91cc\u5206\u79bb\u51fa\u4e00\u4e2a\u5355\u8bcd\u5217\u8868\uff0c\u800cjoin\u65b9\u6cd5\u4f1a\u628a\u5355\u8bcd\u5217\u8868\u8fde\u5728\u4e00\u8d77\u4ece\u800c\u5f62\u6210\u5b57\u7b26\u4e32\u3002\u4f8b\u5982\uff1a print ( \"Python is cool\" . split ()) # \u8fd0\u884c\u7ed3\u679c\uff1a # ['Python', 'is', 'cool'] print ( \" \" . join ([ \"Python\" , \"is\" , \"cool\" ])) # \u8fd0\u884c\u7ed3\u679c\uff1a # Python is cool \u5bf9\u4e8e\u5217\u8868\u7279\u6027\u548c\u64cd\u4f5c\u7684\u8be6\u7ec6\u7ec3\u4e60\uff0c\u53c2\u8003 Python\u8bed\u8a00\u57fa\u7840@github \u6216\u8005 Python\u8bed\u8a00\u57fa\u7840@web \u4e2d\u201c1.3 \u5217\u8868\uff08list\uff09\u201d\u7684\u5185\u5bb9\u3002","title":"1.4.1.\u5217\u8868"},{"location":"python/DataStructure/01_PythonFundmantal/#142","text":"\u5143\u7ec4\uff08tuple\uff09\u662f\u4e00\u4e2a\u4e0d\u53ef\u53d8\u7684\u5143\u7d20\u5e8f\u5217\u3002 \u5143\u7ec4\uff08tuple\uff09\u5f62\u5f0f\u662f\u7528\u5706\u62ec\u53f7\u5c06\u5404\u9879\u62ec\u8d77\u6765\uff0c\u5e76\u4e14\u5fc5\u987b\u81f3\u5c11\u5305\u542b\u4e24\u4e2a\u9879\u3002 \u5143\u7ec4\u5b9e\u9645\u4e0a\u5c31\u50cf\u5217\u8868\u4e00\u6837\uff0c\u53ea\u4e0d\u8fc7\u5b83\u6ca1\u6709\u53d8\u5f02\u5668\u65b9\u6cd5\u3002 \u5982\u679c\u8981\u4f7f\u5143\u7ec4\u53ea\u5305\u542b\u4e00\u4e2a\u5143\u7d20\uff0c\u5219\u5fc5\u987b\u5728\u5143\u7ec4\u91cc\u5305\u542b\u9017\u53f7\u3002 \u5bf9\u6bd4\u4e0b\u9762\u7684\u533a\u522b\uff1a print (( 21 )) # (21)\u88ab\u89c6\u4e3a\u6574\u6570 # \u8fd0\u884c\u7ed3\u679c\uff1a # 21 print (( 21 ,)) # (21,)\u88ab\u89c6\u4e3a\u5143\u7ec4 # \u8fd0\u884c\u7ed3\u679c\uff1a # (21,) \u5bf9\u4e8e\u5217\u8868\u7279\u6027\u548c\u64cd\u4f5c\u7684\u8be6\u7ec6\u7ec3\u4e60\uff0c\u53c2\u8003 Python\u8bed\u8a00\u57fa\u7840@github \u6216\u8005 Python\u8bed\u8a00\u57fa\u7840@web \u4e2d\u201c1.6 \u5143\u7ec4\uff08tuple\uff09\u201d\u7684\u5185\u5bb9\u3002","title":"1.4.2.\u5143\u7ec4"},{"location":"python/DataStructure/01_PythonFundmantal/#143","text":"for \u5faa\u73af\u53ef\u4ee5\u7528\u6765\u904d\u5386\u5e8f\u5217\uff08\u5982\u5b57\u7b26\u4e32\u3001\u5217\u8868\u6216\u5143\u7ec4\uff09\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002 \u904d\u5386\u5217\u8868\uff1a myList = [ 67 , 100 , 'Monday' , \"It's good\" ] for item in myList : print ( item ) myList = [ 67 , 100 , 'Monday' , \"It's good\" ] for idx in range ( len ( myList )): print ( myList [ idx ]) \u904d\u5386\u5143\u7ec4\uff1a myString = \"I love Python\" myList = myString . split () myTuple = tuple ( myList ) for i in myTuple : print ( i ) \u904d\u5386\u5b57\u7b26\u4e32\uff1a(\u6ce8\u610f\uff0c\u662f\u904d\u5386\u5b57\u7b26\uff0c\u4e0d\u662f\u5355\u8bcd) myString = \"I love Python\" for i in myString : print ( i ) myString = \"I love Python\" for i in range ( len ( myString )): print ( myString [ i ]) myString = \"I love Python\" for i in enumerate ( myString ): print ( i ) myString = \"I love Python\" for i , j in enumerate ( myString ): print ( i , j ) myString = \"I love Python\" for i in iter ( myString ): print ( i ) \u5982\u679c\u6309\u7167\u5355\u8bcd\u904d\u5386\u5b57\u7b26\u4e32\uff0c\u5219\u9700\u8981\u5148\u628a\u5b57\u4e32\u6309\u5355\u8bcd\u62c6\u89e3\u4e3a\u5217\u8868\u3002 myString = \"I love Python\" myList = \"I love Python\" . split () for i in myList : print ( i ) \u5bf9\u4e8e\u5217\u8868\u548c\u5143\u7ec4\u904d\u5386\u7684\u66f4\u591a\u4f8b\u5b50\uff0c\u5305\u62ec\u62c6\u5305\u904d\u5386\uff0c\u53c2\u8003 Python\u8bed\u8a00\u57fa\u7840@github \u6216\u8005 Python\u8bed\u8a00\u57fa\u7840@web \u7684\u5185\u5bb9\u3002","title":"1.4.3.\u5e8f\u5217\u904d\u5386"},{"location":"python/DataStructure/01_PythonFundmantal/#144","text":"\u5b57\u5178\uff08dictionary\uff09\u5305\u542b\u96f6\u4e2a\u6216\u591a\u4e2a\u6761\u76ee\u3002 \u6bcf\u4e2a\u6761\u76ee\uff08entry\uff09\u90fd\u6709\u552f\u4e00\u7684\u952e\u548c\u5b83\u6240\u5bf9\u5e94\u7684\u503c\u76f8\u5173\u8054\u3002 \u952e\u901a\u5e38\u662f\u5b57\u7b26\u4e32\u6216\u6574\u6570\uff0c\u800c\u503c\u662f\u4efb\u610f\u7684Python\u5bf9\u8c61\u3002 \u4e0b\u6807\u8fd0\u7b97\u7b26\u53ef\u4ee5\u7528\u4e8e\u8bbf\u95ee\u4e00\u4e2a\u7ed9\u5b9a\u952e\u7684\u503c\uff0c\u7ed9\u4e00\u4e2a\u65b0\u952e\u6dfb\u52a0\u4e00\u4e2a\u503c\uff0c\u4ee5\u53ca\u66ff\u6362\u7ed9\u5b9a\u952e\u7684\u503c\u3002 pop \u65b9\u6cd5\u4f1a\u5220\u9664\u4e00\u4e2a\u6761\u76ee\u5e76\u8fd4\u56de\u7ed9\u5b9a\u952e\u6240\u5bf9\u5e94\u7684\u503c\u3002 keys \u65b9\u6cd5\u4f1a\u628a\u6240\u6709\u952e\u8fd4\u56de\u6210\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 values \u65b9\u6cd5\u4f1a\u628a\u6240\u6709\u503c\u8fd4\u56de\u6210\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 \u793a\u4f8b\uff1a {} # \u7a7a\u5b57\u5178 { \"name\" : \"Ken\" } # \u542b\u4e00\u4e2a\u6761\u76ee { \"name\" : \"Ken\" , \"age\" : 67 } # \u542b\u4e8c\u4e2a\u6761\u76ee { \"hobbies\" :[ \"reading\" , \"running\" ]} # \u542b\u4e00\u4e2a\u6761\u76ee\uff0c\u5176\u4e2d\u503c\u662f\u4e00\u4e2a\u5217\u8868 \u5b57\u5178\u672c\u8eab\u4e5f\u662f\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002\u53ef\u4ee5\u901a\u8fc7for\u8bed\u53e5\u8fdb\u884c\u904d\u5386\u952e\u6216/\u548c\u503c\u3002 myDict = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } for keys in myDict : print ( keys , myDict [ keys ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # name Ming # id 1001 # age 35","title":"1.4.4.\u5b57\u5178"},{"location":"python/DataStructure/01_PythonFundmantal/#145","text":"\u53ef\u4ee5\u5728\u5b57\u7b26\u4e32\u5217\u8868\u3001\u5143\u7ec4\u6216\u5b57\u5178\u91cc\u901a\u8fc7 in \u8fd0\u7b97\u7b26\u6765\u5bf9\u503c\u6216\u591a\u9879\u96c6\u8fdb\u884c\u641c\u7d22\uff0c\u8fd4\u56de True \u6216 False \u3002\u5bf9\u4e8e\u5b57\u5178\u6765\u8bf4\uff0c\u641c\u7d22\u7684\u76ee\u6807\u503c\u5e94\u8be5\u662f\u4e00\u4e2a\u952e\u3002 \u5982\u679c\u5df2\u77e5\u7ed9\u5b9a\u503c\u5b58\u5728\u4e8e\u5e8f\u5217\uff08\u5b57\u7b26\u4e32\u3001\u5217\u8868\u6216\u5143\u7ec4\uff09\u91cc\uff0c\u90a3\u4e48 index \u65b9\u6cd5\u5c06\u8fd4\u56de\u8fd9\u4e2a\u503c\u6240\u51fa\u73b0\u7684\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3002 \u5217\u8868\u68c0\u7d22\uff1a myString = \"I love Python\" myList = myString . split () print ( myList ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ['I', 'love', 'Python'] print ( myList . index ( 'love' )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 1 \u5143\u7ec4\u68c0\u7d22\uff1a myString = \"I love Python\" myList = myString . split () myTuple = tuple ( myList ) print ( myTuple ) print ( myTuple . index ( 'love' )) \u5b57\u5178\u68c0\u7d22\uff1a myDict = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } print ( myDict ) for keys in myDict : print ( keys , myDict [ keys ]) myDict . pop ( 'city' ) # \u62a5\u9519\uff0cKeyError: 'city' myDict . pop ( 'id' ) print ( myDict ) # \u8fd0\u884c\u7ed3\u679c\uff1a{'name': 'Ming', 'age': 35}","title":"1.4.5.\u503c\u68c0\u7d22"},{"location":"python/DataStructure/01_PythonFundmantal/#146","text":"\u4e0b\u6807\u8fd0\u7b97\u7b26\u53ef\u4ee5\u7528\u6765\u8bbf\u95ee\u5217\u8868\u3001\u5143\u7ec4\u548c\u5b57\u5178\u91cc\u7684\u5143\u7d20\u3002 \u901a\u8fc7\u6a21\u5f0f\u5339\u914d\u53ef\u4ee5\u4e00\u6b21\u8bbf\u95ee\u591a\u4e2a\u5143\u7d20\u3002 \u793a\u4f8b\uff1a myTuple \u662f\u4e00\u4e2a\u542b\u5185\u5d4c\u5143\u7ec4\u7684\u5143\u7ec4\u3002 myTuple = (( 'r' , 'g' , 'b' ), 'hexString' ) print ( myTuple ) # \u8fd0\u884c\u7ed3\u679c\uff1a # (('r', 'g', 'b'), 'hexString') print ( myTuple [ 0 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # ('r', 'g', 'b') print ( myTuple [ 0 ][ 0 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # r print ( myTuple [ 0 ][ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # g print ( myTuple [ 0 ][ 2 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # b print ( myTuple [ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # hexString \u901a\u8fc7\u4e0a\u9762\u7684\u62c6\u89e3\uff0c\u6211\u4eec\u6e05\u695a\u4e86\u5185\u5d4c\u5143\u7ec4\u7684\u7ed3\u6784\u8be6\u7ec6\u60c5\u51b5\u3002 \u4e0b\u9762\uff0c\u6211\u4eec\u901a\u8fc7\u6a21\u5f0f\u5339\u914d\uff0c\u628a\u4e00\u4e2a\u7ed3\u6784\u5206\u914d\u7ed9\u5f62\u5f0f\u5b8c\u5168\u76f8\u540c\u7684\u53e6\u4e00\u4e2a\u7ed3\u6784\u3002\u8fd9\u91cc\u76ee\u6807\u7ed3\u6784 newTuple \u6240\u5305\u542b\u7684\u53d8\u91cf\u4ece\u6e90\u7ed3\u6784 (('r', 'g', 'b'), 'hexString') \u91cc\u7684\u76f8\u5e94\u4f4d\u7f6e\u5904\u83b7\u5f97\u5bf9\u5e94\u7684\u503c\u3002 newTuple = (( 'r' , 'g' , 'b' ), 'hexString' ) print ( newTuple [ 0 ]) # ('r', 'g', 'b') print ( newTuple [ 0 ][ 0 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # r print ( newTuple [ 0 ][ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # g print ( newTuple [ 0 ][ 2 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # b print ( newTuple [ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # hexString","title":"1.4.6.\u6a21\u5f0f\u5339\u914d\u8bbf\u95ee\u591a\u9879\u96c6"},{"location":"python/DataStructure/01_PythonFundmantal/#15","text":"Python\u652f\u6301\u5b8c\u5168\u51fd\u6570\u5f0f\u7f16\u7a0b\u8bbe\u8ba1\u3002 Python\u5305\u542b\u5f88\u591a\u5185\u7f6e\u51fd\u6570\u3002 Python\u4e5f\u8fd0\u884c\u521b\u5efa\u65b0\u51fd\u6570\uff0c\u53ef\u4ee5\u4f7f\u7528\u9012\u5f52\uff0c\u628a\u51fd\u6570\u4f5c\u4e3a\u6570\u636e\u8fdb\u884c\u4f20\u9012\u548c\u8fd4\u56de\u3002","title":"1.5.\u521b\u5efa\u51fd\u6570"},{"location":"python/DataStructure/01_PythonFundmantal/#151","text":"\u51fd\u6570\u5b9a\u4e49\u8bed\u6cd5\uff1a \u547d\u540d\u51fd\u6570\u540d\u79f0\u548c\u53c2\u6570\u540d\u79f0\u7684\u89c4\u5219\u4e0e\u60ef\u4f8b\u4e0e\u547d\u540d\u53d8\u91cf\u7684\u662f\u76f8\u540c\u7684\u3002 \u5fc5\u9009\u53c2\u6570\u7684\u5217\u8868\u53ef\u4ee5\u4e3a\u7a7a\uff0c\u4e5f\u53ef\u4ee5\u5305\u542b\u7528\u9017\u53f7\u9694\u5f00\u7684\u540d\u79f0\u3002 \u4e0e\u5176\u4ed6\u7f16\u7a0b\u8bed\u8a00\u4e0d\u540c\u7684\u662f\uff0c\u53c2\u6570\u540d\u79f0\u6216\u51fd\u6570\u540d\u79f0\u672c\u8eab\u5e76\u4e0d\u4f1a\u548c\u6570\u636e\u7c7b\u578b\u8fdb\u884c\u5173\u8054\u3002 def < function name > ( < list of parameters > ): < sequence of statements > \u793a\u4f8b\uff1a \u5728\u51fd\u6570\u7684\u6807\u9898\u4e0b\u6709\u4e00\u884c\u7528\u4e09\u5f15\u53f7\u62ec\u8d77\u6765\u7684\u5b57\u7b26\u4e32 \u8fd4\u56den\u7684\u5e73\u65b9\u6570 \uff0c\u8fd9\u662f\u4e00\u4e2a\u6587\u6863\u5b57\u7b26\u4e32\uff08docstring\uff09\u3002 \u5728shell\u91cc\u9762\u8f93\u5165help(square)\u65f6\uff0c\u4f1a\u663e\u793a\u8fd9\u4e2a\u5b57\u7b26\u4e32\u3002 \u5b9a\u4e49\u7684\u6bcf\u4e00\u4e2a\u51fd\u6570\u90fd\u5e94\u8be5\u6709\u6587\u6863\u5b57\u7b26\u4e32\uff0c\u6765\u8bf4\u660e\u8be5\u51fd\u6570\u7684\u529f\u80fd\uff0c\u5e76\u63d0\u4f9b\u76f8\u5173\u7684\u6240\u6709\u53c2\u6570\u4ee5\u53ca\u8fd4\u56de\u503c\u7684\u4fe1\u606f\u3002 \u51fd\u6570\u7684\u53c2\u6570\u548c\u4e34\u65f6\u53d8\u91cf\u53ea\u4f1a\u5728\u51fd\u6570\u8c03\u7528\u7684\u751f\u5b58\u5468\u671f\u5185\u5b58\u5728\uff0c\u5e76\u4e14\u5bf9\u5176\u4ed6\u51fd\u6570\u53ca\u5176\u5916\u56f4\u7a0b\u5e8f\u90fd\u662f\u4e0d\u53ef\u89c1\u7684\u3002 n \u662f\u53c2\u6570\u3002 result \u662f\u4e34\u65f6\u53d8\u91cf\u3002 \u5982\u679c\u51fd\u6570\u4e0d\u5305\u542b return \u8bed\u53e5\u65f6\uff0c\u5b83\u5c06\u5728\u6700\u540e\u4e00\u6761\u8bed\u53e5\u6267\u884c\u4e4b\u540e\u81ea\u52a8\u8fd4\u56de None \u503c\u3002 \u7528 = \u628a\u53c2\u6570\u6307\u5b9a\u4e3a\u6709\u9ed8\u8ba4\u503c\u7684\u53ef\u9009\u53c2\u6570\u3002 \u5728\u53c2\u6570\u5217\u8868\u4e2d\uff0c\u5fc5\u9009\u53c2\u6570\uff08\u6ca1\u6709\u9ed8\u8ba4\u503c\u7684\u53c2\u6570\uff09\u5fc5\u987b\u4f4d\u4e8e\u53ef\u9009\u53c2\u6570\u4e4b\u524d\u3002 def square ( n ): \"\"\"\u8fd4\u56den\u7684\u5e73\u65b9\u6570\"\"\" result = n ** 2 return result print ( square ( 5 ))","title":"1.5.1.\u51fd\u6570\u5b9a\u4e49"},{"location":"python/DataStructure/01_PythonFundmantal/#152","text":"\u9012\u5f52\u51fd\u6570\uff08recursive function\uff09\u662f\u6307\u4f1a\u8c03\u7528\u81ea\u8eab\u7684\u51fd\u6570\u3002 \u4e3a\u4e86\u9632\u6b62\u51fd\u6570\u65e0\u9650\u5730\u91cd\u590d\u8c03\u7528\u81ea\u8eab\uff0c\u4ee3\u7801\u4e2d\u5fc5\u987b\u81f3\u5c11\u6709\u4e00\u6761\u7528\u6765\u67e5\u9a8c\u6761\u4ef6\u7684\u9009\u62e9\u8bed\u53e5\uff0c\u7528\u4e8e\u786e\u5b9a\u63a5\u4e0b\u6765\u8981\u7ee7\u7eed\u9012\u5f52\u8fd8\u662f\u505c\u6b62\u9012\u5f52\u3002\u8fd9\u4e2a\u68c0\u67e5\u6761\u4ef6\u8bed\u53e5\u79f0\u4e3a\u57fa\u672c\u60c5\u51b5\uff08base case\uff09\u3002 \u793a\u4f8b\uff1a\u4e0b\u9762\u662f\u901a\u8fc7\u5faa\u73af\u5b9e\u73b0\u8f93\u51fa\u4ece\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u548c\u3002 def mySum ( lower , upper ): \"\"\"\u5bf9\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u6c42\u548c; lower:\u6700\u5c0f\u503c; upper:\u6700\u5927\u503c;\"\"\" result = 0 while ( lower <= upper ): result = result + lower lower += 1 return result print ( mySum ( 1 , 10 )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 55 \u7528\u9012\u5f52\u51fd\u6570\u6539\u5199\u4e0a\u8ff0\u51fd\u6570\u3002 def mySum ( lower , upper ): \"\"\"\u5bf9\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u6c42\u548c; lower:\u6700\u5c0f\u503c; upper:\u6700\u5927\u503c;\"\"\" if lower <= upper : return lower + mySum ( lower + 1 , upper ) else : return 0 print ( mySum ( 1 , 10 )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 55 \u901a\u5e38\u6765\u8bf4\uff0c\u9012\u5f52\u51fd\u6570\u81f3\u5c11\u6709\u4e00\u4e2a\u53c2\u6570\u3002 \u8fd9\u4e2a\u53c2\u6570\u7684\u503c\u4f1a\u88ab\u7528\u6765\u5bf9\u9012\u5f52\u8fc7\u7a0b\u7684\u57fa\u672c\u60c5\u51b5\u8fdb\u884c\u5224\u5b9a\uff0c\u4ece\u800c\u51b3\u5b9a\u662f\u5426\u8981\u7ed3\u675f\u6574\u4e2a\u8c03\u7528\u3002 \u5728\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u4e4b\u524d\uff0c\u8fd9\u4e2a\u503c\u4e5f\u4f1a\u88ab\u8fdb\u884c\u67d0\u79cd\u65b9\u5f0f\u7684\u4fee\u6539\u3002 \u6bcf\u6b21\u5bf9\u8fd9\u4e2a\u503c\u7684\u4fee\u6539\uff0c\u90fd\u5e94\u8be5\u4ea7\u751f\u4e00\u4e2a\u65b0\u6570\u636e\u503c\uff0c\u53ef\u4ee5\u8ba9\u51fd\u6570\u6700\u7ec8\u8fbe\u5230\u57fa\u672c\u60c5\u51b5\u3002 \u4e3a\u4e86\u5bf9 mySum \u51fd\u6570\u7684\u9012\u5f52\u8fdb\u884c\u8ddf\u8e2a\uff0c\u53ef\u4ee5\u5c1d\u8bd5\u6dfb\u52a0\u4e00\u4e2a\u4ee3\u8868\u7f29\u8fdb\u8fb9\u8ddd\u7684\u53c2\u6570\u5e76\u4e14\u6dfb\u52a0\u4e00\u4e9bprint\u8bed\u53e5\u3002\u8fd9\u6837\u5728\u6bcf\u6b21\u8c03\u7528\u65f6\uff0c\u51fd\u6570\u7684\u7b2c\u4e00\u6761\u8bed\u53e5\u4f1a\u8ba1\u7b97\u7f29\u8fdb\u6570\u91cf\uff0c\u7136\u540e\u518d\u6253\u5370\u4e24\u4e2a\u53c2\u6570\u7684\u503c\uff0c\u6bcf\u6b21\u8fd4\u56de\u8c03\u7528\u4e4b\u524d\u7684\u8fd4\u56de\u503c\u65f6\u90fd\u4f7f\u7528\u76f8\u540c\u7684\u7f29\u8fdb\uff0c\u5c31\u53ef\u4ee5\u5b9e\u73b0\u5bf9\u4e24\u4e2a\u53c2\u6570\u7684\u503c\u4ee5\u53ca\u6bcf\u6b21\u8c03\u7528\u7684\u8fd4\u56de\u503c\u8fdb\u884c\u8ddf\u8e2a\u3002 def mySum ( lower , upper , margin = 0 ): \"\"\"\u5bf9\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u6c42\u548c\uff0c\u901a\u8fc7\u9636\u68af\u65b9\u5f0f\u8f93\u51fa; lower:\u6700\u5c0f\u503c; upper:\u6700\u5927\u503c;\"\"\" blanks = \" \" * margin print ( blanks , lower , upper ) if lower <= upper : result = lower + mySum ( lower + 1 , upper , margin + 4 ) print ( blanks , result ) return result else : print ( blanks , 0 ) return 0 print ( mySum ( 1 , 5 )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 1 5 # 2 5 # 3 5 # 4 5 # 5 5 # 6 5 # 0 # 5 # 9 # 12 # 14 # 15 # 15","title":"1.5.2.\u51fd\u6570\u9012\u5f52"},{"location":"python/DataStructure/01_PythonFundmantal/#153","text":"\u5d4c\u5957\u51fd\u6570\u7c7b\u4f3c\u4e8e\u5d4c\u5957\u5faa\u73af\uff0c\u5c31\u662f\u51fd\u6570\u5185\u53c8\u5d4c\u5957\u7740\u51fd\u6570\u3002\u5373\uff0c\u51fd\u6570\u7684\u5b9a\u4e49\u5d4c\u5957\u5728\u4e00\u4e2a\u51fd\u6570\u7684\u8bed\u53e5\u5e8f\u5217\u91cc\u3002 \u5148\u770b\u4e00\u4e2a\u666e\u901a\u4f8b\u5b50\uff1a # \u5b9a\u4e49inner\u51fd\u6570 def inner (): print ( '\u6211\u662finner' ) # \u5b9a\u4e49outer\u51fd\u6570\uff0couter\u51fd\u6570\u8c03\u7528inner\u51fd\u6570 def outer (): print ( '\u6211\u662fouter' ) inner () outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter # \u6211\u662finner \u6539\u5199\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u628a inner \u51fd\u6570\u5199\u5728 outer \u51fd\u6570\u91cc\u9762\u3002 # \u5b9a\u4e49outer\u51fd\u6570\uff0couter\u51fd\u6570\u5185\u5d4cinner\u51fd\u6570\uff0c\u5e76\u8c03\u7528inner\u51fd\u6570 def outer (): print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): print ( '\u6211\u662finner' ) inner () outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter # \u6211\u662finner \u4e0a\u9762\u7684\u5916\u5c42 outer \u51fd\u6570\u548c\u5185\u5c42 inner \u51fd\u6570\u90fd\u6ca1\u6709\u53d8\u91cf\u548c\u53c2\u6570\u3002 \u73b0\u5728\u4fee\u6539\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u6211\u4eec\u4f20\u5165\u53c2\u6570\u548c\u53d8\u91cf\uff0c\u7136\u540e\u628a\u5916\u5c42\u51fd\u6570\u8fd4\u56de\u503c\u6307\u5411\u5185\u5c42\u51fd\u6570\u540d\u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) # \u8fd4\u56de\u5185\u5c42inner\u51fd\u6570\u540d return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662finner # inner\u6253\u5370: 1 \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff1a f = outer() \u8c03\u7528\u5916\u5c42 outer \u51fd\u6570\uff0c\u5e76\u628a\u7ed3\u679c\u8d4b\u503c\u7ed9 f \u3002\u6ce8\u610f\uff0cinner\u51fd\u6570\u5e76\u6ca1\u6709\u88ab\u6267\u884c\u3002 f \u5176\u5b9e\u5c31\u662f inner \uff0c\u6307\u5411 inner \u7684\u5185\u5b58\u7a7a\u95f4\u3002\u901a\u8fc7 f() \u9a8c\u8bc1\u4e86\u8fd9\u4e00\u70b9\uff0c outer \u51fd\u6570\u4e2d\u7684\u53d8\u91cf a \u88ab\u6253\u5370\u51fa\u6765\u4e86\u3002 \u4e0a\u9762\u4f8b\u5b50\u4e2d outer \u5c31\u662f\u95ed\u5305\u51fd\u6570\uff0c\u5916\u5c42\u51fd\u6570\u7684\u53d8\u91cf\u53ef\u4ee5\u88ab\u5185\u5c42\u51fd\u6570\u8c03\u7528\uff0c\u7c7b\u4f3c\u4e8e\u5c01\u88c5\u7684\u6548\u679c\u3002\u5185\u5c42\u51fd\u6570\u4e0d\u4f1a\u7acb\u523b\u88ab\u6267\u884c\uff0c\u5f53\u518d\u6b21\u8c03\u7528\u65f6\uff0c\u5185\u5c42\u51fd\u6570\u624d\u4f1a\u6267\u884c\u3002 \u95ed\u5305\u51fd\u6570\u9700\u8981\u6709\u4e09\u4e2a\u6761\u4ef6\uff1a \u5fc5\u987b\u6709\u4e00\u4e2a\u5185\u5d4c\u51fd\u6570\uff0c\u4f8b\u5982\u51fd\u6570 inner \uff1b \u5185\u90e8\u51fd\u6570\u5f15\u7528\u5916\u90e8\u51fd\u6570\u53d8\u91cf\uff0c\u4f8b\u5982\u53d8\u91cf a \uff1b \u5916\u90e8\u51fd\u6570\u5fc5\u987b\u8fd4\u56de\u5185\u5d4c\u51fd\u6570\uff0c\u4f8b\u5982 outer \u51fd\u6570\u4e2d\u7684 return inner \uff1b \u5bf9\u4e0a\u9762\u7684\u4ee3\u7801\u518d\u8fdb\u884c\u4fee\u6539\uff0c\u5728 inner \u51fd\u6570\u4e2d\u518d\u6dfb\u52a0\u4e00\u4e2a\u540c\u540d\u7684\u53d8\u91cfa\u3002\u4ece\u7ed3\u679c\u53ef\u4ee5\u5f97\u51fa\u7ed3\u8bba\uff0c inner \u51fd\u6570\u4f18\u5148\u5728\u5185\u90e8\u67e5\u627e\u53d8\u91cf a=5 \u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): a = 5 print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662finner # inner\u6253\u5370: 5 \u7ed3\u8bba\uff1a\u5185\u5c42\u51fd\u6570\u4e2d\u8c03\u7528\u7684\u53d8\u91cf\uff1a \u9996\u5148\u4f1a\u4ece\u5185\u5c42\u51fd\u6570\u4e2d\u627e\uff0c \u627e\u4e0d\u5230\u5c31\u53bb\u5916\u5c42\u51fd\u6570\u4e2d\u627e\uff0c \u518d\u627e\u4e0d\u5230\u5c31\u5230\u51fd\u6570\u5916\u4e2d\u627e\uff0c \u518d\u627e\u4e0d\u5230\u5c31\u5230\u5185\u7f6e\u7684\u6a21\u5757\u4e2d\u627e\uff0c \u518d\u627e\u4e0d\u5230\uff0c\u5c31\u62a5\u9519\u3002 \u8fd9\u5c31\u662f\u4f5c\u7528\u57df\u7684\u6982\u5ff5\u3002 \u7ee7\u7eed\u4fee\u6539\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u5728 inner \u51fd\u6570\u4e2d\u4fee\u6539 outer \u51fd\u6570\u4e2d\u53d8\u91cf a \u7684\u503c\uff0c\u8fd0\u884c\u7ed3\u679c\u62a5\u9519\u3002\u7ed3\u8bba\uff1a\u5185\u5c42\u51fd\u6570\u4e0d\u80fd\u4fee\u6539\u5916\u5c42\u51fd\u6570\u7684\u53d8\u91cf\u503c\u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): a += 5 print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # UnboundLocalError: local variable 'a' referenced before assignment \u4fee\u6b63\u4e0a\u9762\u7684\u4ee3\u7801\u3002\u5728 inner \u51fd\u6570\u4e2d\u5bf9\u53d8\u91cfa\u6dfb\u52a0\u4e00\u4e2a nonlocal \u7684\u58f0\u660e\uff0c\u5c31\u53ef\u4ee5\u5728 inner \u51fd\u6570\u4e2d\u4fee\u6539\u5916\u5c42outer\u51fd\u6570\u7684\u53d8\u91cf a \u7684\u503c\u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): nonlocal a a += 5 print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662finner # inner\u6253\u5370: 6 \u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u662f\u9636\u4e58\uff08factorial\uff09\u9012\u5f52\u51fd\u6570\u7684\u4e24\u4e2a\u4e0d\u540c\u7684\u5b9a\u4e49\u3002 \u7b2c\u4e00\u4e2a\u5b9a\u4e49\u4f7f\u7528\u4e86\u5d4c\u5957\u7684\u8f85\u52a9\u51fd\u6570 recurse \u6765\u5bf9\u6240\u9700\u8981\u7684\u53c2\u6570\u8fdb\u884c\u9012\u5f52\uff1b\u8fd9\u91cc\u7684 factorial \u51fd\u6570\u5c31\u662f\u95ed\u5305\u51fd\u6570\u3002 \u7b2c\u4e00\u6b65\uff1a\u7b2c\u4e00\u6b21\u8c03\u7528 factorial() \u51fd\u6570\uff0c\u5373 n=5 \uff1b \u7b2c\u4e8c\u6b65\uff1a\u7b2c\u4e00\u6b21\u8c03\u7528\u5185\u5c42\u51fd\u6570 recurse() \uff0c\u4f46\u4e0d\u4f1a\u7acb\u523b\u88ab\u6267\u884c\uff1b \u7b2c\u4e09\u6b65\uff0c\u6267\u884c return recurse(5, 1) \uff0c\u5bf9\u53c2\u6570 product \u521d\u59cb\u5316\u8d4b\u503c 1 \u7b2c\u56db\u6b65\uff1a\u6267\u884c return recurse(5, 5 * 1) \uff0c\u6b64\u65f6 n=5 \uff0c product=1 \u3002 \u7b2c\u4e94\u6b65\uff1a\u6267\u884c return recurse(4, 4 * 5) \uff0c\u6b64\u65f6 n=4 \uff0c product=5 \u3002 \u7b2c\u516d\u6b65\uff1a\u6267\u884c return recurse(3, 3 * 20) \uff0c\u6b64\u65f6 n=3 \uff0c product=20 \u3002 \u7b2c\u4e03\u6b65\uff1a\u6267\u884c return recurse(2, 2 * 60) \uff0c\u6b64\u65f6 n=2 \uff0c product=60 \u3002 \u7b2c\u516b\u6b65\uff1a\u6267\u884c return recurse(1, 1 * 120) \uff0c\u6b64\u65f6 n=1 \uff0c product=120 \u3002 \u7b2c\u4e5d\u6b65\uff1a\u6b64\u65f6 n=1 \uff0c\u6267\u884c return product \uff0c\u5373 return 120 \uff0c\u7ed3\u675f\u3002 \u7b2c\u4e8c\u4e2a\u5b9a\u4e49\u5219\u662f\u4e3a\u7b2c\u4e8c\u4e2a\u53c2\u6570\u63d0\u4f9b\u4e86\u9ed8\u8ba4\u503c\uff0c\u4ece\u800c\u7b80\u5316\u4e86\u8bbe\u8ba1\u3002 # \u7b2c\u4e00\u4e2a\u5b9a\u4e49 def factorial ( n ): \"\"\"\u8fd4\u56de n \u7684\u9636\u4e58\"\"\" def recurse ( n , product ): \"\"\"\u8ba1\u7b97\u9636\u4e58\u7684\u5e2e\u52a9\u5668\"\"\" print ( n , product ) # \u63d2\u5165\u8fd9\u4e00\u53e5\u662f\u4e3a\u4e86\u80fd\u770b\u6e05\u695a\u6bcf\u4e00\u6b21\u9012\u5f52\u8c03\u7528\u7684n\u548cproduct\u53d8\u5316 if n == 1 : return product else : return recurse ( n - 1 , n * product ) return recurse ( n , 1 ) f = factorial ( 5 ) # \u8fd0\u884c\u7ed3\u679c 5 1 4 5 3 20 2 60 1 120 # \u7b2c\u4e8c\u4e2a\u5b9a\u4e49 def factorial ( n , product = 1 ): \"\"\"\u8fd4\u56de n \u7684\u9636\u4e58\"\"\" if n == 1 : return product else : return factorial ( n - 1 , n * product ) print ( factorial ( 5 )) # \u8fd0\u884c\u7ed3\u679c # 120","title":"1.5.3.\u51fd\u6570\u5d4c\u5957"},{"location":"python/DataStructure/01_PythonFundmantal/#154","text":"\u51fd\u6570\u672c\u8eab\u4e5f\u662f\u4e00\u79cd\u72ec\u7279\u7684\u6570\u636e\u5bf9\u8c61\u3002\u53ef\u4ee5\u628a\u5b83\u4eec\u8d4b\u7ed9\u53d8\u91cf\u3001\u5b58\u50a8\u5728\u6570\u636e\u7ed3\u6784\u91cc\u3001\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7ed9\u5176\u4ed6\u51fd\u6570\u4ee5\u53ca\u4f5c\u4e3a\u5176\u4ed6\u51fd\u6570\u7684\u503c\u8fd4\u56de\u3002 \u9ad8\u9636\u51fd\u6570\uff08higher-order function\uff09\uff1a\u5b83\u63a5\u6536\u53e6\u4e00\u4e2a\u51fd\u6570\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u4e14\u4ee5\u67d0\u79cd\u65b9\u5f0f\u5e94\u7528\u8be5\u51fd\u6570\u3002 Python\u6709\u4e24\u4e2a\u5185\u7f6e\u7684\u9ad8\u9636\u51fd\u6570\uff0c\u5206\u522b\u662f map \u548c filter \uff0c\u5b83\u4eec\u53ef\u4ee5\u7528\u4e8e\u5904\u7406\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 map \u51fd\u6570\u4f1a\u63a5\u6536\u53e6\u4e00\u4e2a\u51fd\u6570\u548c\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\uff0c\u8fd4\u56de\u53e6\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002\u8fd9\u4e2a\u51fd\u6570\u4f1a\u628a\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7684\u51fd\u6570\u5e94\u7528\u5728\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\u7684\u6bcf\u4e2a\u5143\u7d20\u4e0a\u3002\u7b80\u5355\u6765\u8bf4\uff0c map \u51fd\u6570\u4f1a\u5bf9\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\u7684\u6bcf\u4e2a\u5143\u7d20\u8fdb\u884c\u8f6c\u6362\u3002 filter \u4f1a\u63a5\u53d7\u4e00\u4e2a\u5e03\u5c14\u51fd\u6570\u548c\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\uff0c\u8fd4\u56de\u8fd9\u6837\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff0c\u5b83\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u90fd\u4f1a\u88ab\u4f20\u9012\u7ed9\u5e03\u5c14\u51fd\u6570\uff0c\u5982\u679c\u8fd9\u4e2a\u51fd\u6570\u8fd4\u56deTrue\uff0c\u90a3\u4e48\u8fd9\u4e2a\u5143\u7d20\u5c06\u88ab\u4fdd\u7559\u5728\u8fd4\u56de\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\uff1b\u5426\u5219\uff0c\u8fd9\u4e2a\u5143\u7d20\u5c06\u88ab\u5220\u9664\u3002\u7b80\u5355\u8bf4\uff0c filter \u51fd\u6570\u4f1a\u628a\u6240\u6709\u80fd\u591f\u901a\u8fc7\u68c0\u9a8c\u7684\u5143\u7d20\u4fdd\u7559\u5728\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\u3002 functools.reduce \u901a\u8fc7\u628a\u63a5\u6536\u4e24\u4e2a\u53c2\u6570\u7684\u51fd\u6570\u7684\u7ed3\u679c\u4ee5\u53ca\u8fed\u4ee3\u5bf9\u8c61\u7684\u4e0b\u4e00\u4e2a\u5143\u7d20\u518d\u6b21\u5e94\u7528\u4e8e\u8fd9\u4e2a\u63a5\u6536\u4e24\u4e2a\u53c2\u6570\u7684\u51fd\u6570\uff0c\u6765\u628a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u8ba1\u7b97\u6210\u5355\u4e00\u7684\u503c\u3002 \u793a\u4f8b\uff1a\u628a\u4e00\u4e2a\u6574\u6570\u5217\u8868\u8f6c\u6362\u6210\u53e6\u4e00\u4e2a\u5305\u542b\u8fd9\u4e9b\u6574\u6570\u7684\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\u5217\u8868\u3002 \u4f20\u7edf\u65b9\u6cd5\u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] for i in oldList : newList . append ( str ( i )) print ( newList ) # ['0', '1', '3', '5', '7', '9'] \u7528 map \u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] newList = list ( map ( str , oldList )) print ( newList ) # ['0', '1', '3', '5', '7', '9'] \u62d3\u5c55\uff1a\u628a\u4e00\u4e2a\u6574\u6570\u5217\u8868\u4e2d\u7684\u6b63\u6574\u6570\u8f6c\u6362\u6210\u53e6\u4e00\u4e2a\u5305\u542b\u8fd9\u4e9b\u6574\u6570\u7684\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\u5217\u8868\u3002 \u4f20\u7edf\u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] for i in oldList : if i > 0 : newList . append (( str ( i ))) print ( newList ) # ['1', '3', '5', '7', '9'] \u4f7f\u7528 filter \u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] def isPositive ( n ): if n > 0 : return True # \u521b\u5efa\u4e00\u4e2a\u4e0d\u5305\u542b\u4efb\u4f55\u96f6\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61 newList = list ( filter ( isPositive , oldList )) print ( newList ) # [1, 3, 5, 7, 9] \u793a\u4f8b\uff1a\u8ba1\u7b97\u4ece1\u523010\u7684\u4e58\u79ef\u5e76\u8f93\u51fa\u7ed3\u679c\u3002 \u901a\u8fc7 for \u5faa\u73af\u5b9e\u73b0\uff1a result = 1 value = 1 for value in range ( 1 , 11 ): result *= value value += 1 print ( result ) # \u8fd0\u884c\u7ed3\u679c # 3628800 \u901a\u8fc7 functools.reduce \u5faa\u73af\u5b9e\u73b0\uff1a import functools result = functools . reduce ( lambda x , y : x * y , range ( 1 , 11 )) print ( result ) # 3628800","title":"1.5.4.\u9ad8\u9636\u51fd\u6570"},{"location":"python/DataStructure/01_PythonFundmantal/#155lambda","text":"\u8bed\u6cd5\u683c\u5f0f\uff1a lambda < argument list > : < expression > lambda\u8868\u8fbe\u5f0f\u4e0d\u80fd\u50cf\u5176\u4ed6Python\u51fd\u6570\u90a3\u6837\u5305\u542b\u4e00\u6574\u4e2a\u8bed\u53e5\u5e8f\u5217\u3002 \u62d3\u5c55\uff1a\u7528lambda\u5b9e\u73b0\u628a\u4e00\u4e2a\u6574\u6570\u5217\u8868\u4e2d\u7684\u6b63\u6574\u6570\u8f6c\u6362\u6210\u53e6\u4e00\u4e2a\u5305\u542b\u8fd9\u4e9b\u6574\u6570\u7684\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\u5217\u8868\uff0c\u5b9e\u9645\u5c31\u662f\u901a\u8fc7\u4f7f\u7528\u533f\u540d\u7684\u5e03\u5c14\u51fd\u6570\u6765\u4ece\u6574\u6570\u5217\u8868\u91cc\u5254\u9664\u6240\u6709\u4e3a\u96f6\u7684\u5143\u7d20\u3002 oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] newList = list ( filter ( lambda i : i > 0 , oldList )) print ( newList ) # [1, 3, 5, 7, 9]","title":"1.5.5.lambda\u4e0e\u533f\u540d\u51fd\u6570"},{"location":"python/DataStructure/01_PythonFundmantal/#16","text":"\u8003\u8651\u4e24\u79cd\u5f02\u5e38\u60c5\u51b5\uff1a Python\u865a\u62df\u673a\u5728\u7a0b\u5e8f\u6267\u884c\u671f\u95f4\u9047\u5230\u4e86\u8bed\u4e49\u9519\u8bef\uff0c\u5219\u4f1a\u5f97\u5230\u76f8\u5e94\u7684\u9519\u8bef\u6d88\u606f\uff0c\u4ece\u800c\u5f15\u53d1\u4e00\u4e2a\u5f02\u5e38\u5e76\u4e14\u6682\u505c\u7a0b\u5e8f\u3002\u8bed\u4e49\u9519\u8bef\u5305\u62ec\u4f8b\u5982\u672a\u5b9a\u4e49\u7684\u53d8\u91cf\u540d\u3001\u9664\u4ee50\u4ee5\u53ca\u8d85\u51fa\u5217\u8868\u8303\u56f4\u7684\u7d22\u5f15\u7b49\u3002 \u7528\u6237\u5f15\u8d77\u7684\u67d0\u4e9b\u9519\u8bef\uff0c\u4f8b\u5982\uff0c\u671f\u671b\u8f93\u5165\u6570\u5b57\u7684\u65f6\u5019\u8f93\u5165\u4e86\u5176\u4ed6\u5b57\u7b26\u3002\u5bf9\u4e8e\u5728\u8fd9\u4e9b\u60c5\u51b5\u4e0b\u4ea7\u751f\u7684\u5f02\u5e38\uff0c\u7a0b\u5e8f\u4e0d\u5e94\u8be5\u505c\u6b62\u6267\u884c\uff0c\u800c\u5e94\u8be5\u5bf9\u8fd9\u4e9b\u5f02\u5e38\u8fdb\u884c\u6355\u83b7\uff0c\u5e76\u4e14\u5141\u8bb8\u7528\u6237\u4fee\u6b63\u9519\u8bef\u3002 Python\u63d0\u4f9b\u4e86try-except\u8bed\u53e5\uff0c\u53ef\u4ee5\u8ba9\u7a0b\u5e8f\u6355\u83b7\u5f02\u5e38\u5e76\u6267\u884c\u76f8\u5e94\u7684\u6062\u590d\u64cd\u4f5c\u3002 try \u5b50\u53e5\u4e2d\u7684\u8bed\u53e5\u5c06\u5148\u88ab\u6267\u884c\u3002\u5982\u679c\u8fd9\u4e9b\u8bed\u53e5\u4e2d\u7684\u4e00\u6761\u5f15\u53d1\u4e86\u5f02\u5e38\uff0c\u90a3\u4e48\u63a7\u5236\u6743\u4f1a\u7acb\u5373\u8f6c\u79fb\u5230 except \u5b50\u53e5\u53bb\u3002 \u5982\u679c\u5f15\u53d1\u7684\u5f02\u5e38\u7c7b\u578b\u548c\u8fd9\u4e2a\u5b50\u53e5\u91cc\u7684\u7c7b\u578b\u4e00\u81f4\uff0c\u90a3\u4e48\u4f1a\u6267\u884c\u5b83\u91cc\u9762\u7684\u8bed\u53e5\uff1b \u5426\u5219\uff0c\u5c06\u8f6c\u79fb\u5230try-except\u8bed\u53e5\u7684\u8c03\u7528\u8005\uff0c\u5e76\u57fa\u4e8e\u8c03\u7528\u94fe\u5411\u4e0a\u4f20\u9012\uff0c\u76f4\u5230\u8fd9\u4e2a\u5f02\u5e38\u88ab\u6210\u529f\u6355\u83b7\uff0c\u6216\u8005\u662f\u7a0b\u5e8f\u56e0\u9519\u8bef\u6d88\u606f\u800c\u505c\u6b62\u6267\u884c\u3002 \u5982\u679c try \u5b50\u53e5\u91cc\u7684\u8bed\u53e5\u6ca1\u6709\u5f15\u53d1\u4efb\u4f55\u5f02\u5e38\uff0c\u90a3\u4e48\u4f1a\u8df3\u8fc7 except \u5b50\u53e5\u5e76\u7ee7\u7eed\u6267\u884c\uff0c\u76f4\u5230try-except\u8bed\u53e5\u7684\u672b\u5c3e\u3002 try : < statements > except < exception type > : < statements > \u901a\u5e38\u6765\u8bf4\uff0c \u5bf9\u4e8e\u5df2\u77e5\u53ef\u80fd\u4f1a\u53d1\u751f\u7684\u5f02\u5e38\u7c7b\u578b\uff0c\u5e94\u8be5\u5c3d\u53ef\u80fd\u5730\u5305\u62ec\u5728\u5728 except \u8bed\u53e5\u91cc\u3002 \u5982\u679c\u4e0d\u77e5\u9053\u5f02\u5e38\u7684\u7c7b\u578b\uff0c\u53ef\u4ee5\u5728 except \u4e2d\u7528\u66f4\u901a\u7528\u7684Exception\u7c7b\u578b\u5339\u914d\u53ef\u80fd\u4f1a\u5f15\u53d1\u7684\u4efb\u4f55\u5f02\u5e38\u3002 \u793a\u4f8b\uff1a def getYourAge ( prompt ): \"\"\"\u63d0\u793a\u7528\u6237\u8f93\u5165\u4e00\u4e2a\u6574\u6570\uff0c\u5426\u5219\u7ed9\u51fa\u9519\u8bef\u63d0\u793a\uff0c\u5e76\u7ee7\u7eed\u63d0\u793a\u7528\u6237\u8f93\u5165\u3002\"\"\" inputStr = input ( prompt ) try : number = int ( inputStr ) return number except ValueError : print ( \"Error in number format:\" , inputStr ) return getYourAge ( prompt ) if __name__ == \"__main__\" : age = getYourAge ( \"Enter your age: \" ) print ( \"Your age is\" , age ) # \u8fd0\u884c\u7ed3\u679c # Enter your age: 3a # Error in number format: 3a # Enter your age: 3.5 # Error in number format: 3.5 # Enter your age: 20 # Your age is 20","title":"1.6.\u6355\u83b7\u5f02\u5e38"},{"location":"python/DataStructure/01_PythonFundmantal/#17","text":"","title":"1.7.\u6587\u4ef6\u53ca\u5176\u64cd\u4f5c"},{"location":"python/DataStructure/01_PythonFundmantal/#171","text":"\u53ef\u4ee5\u628a\u6587\u672c\u6587\u4ef6\u91cc\u7684\u6570\u636e\u770b\u4f5c\u5b57\u7b26\u3001\u5355\u8bcd\u3001\u6570\u5b57\u6216\u8005\u82e5\u5e72\u884c\u6587\u672c\u3002 \u5982\u679c\u628a\u6587\u672c\u6587\u4ef6\u91cc\u7684\u6570\u636e\u5f53\u4f5c\u6574\u6570\u6216\u6d6e\u70b9\u6570\uff0c\u5c31\u5fc5\u987b\u7528\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u3001\u5236\u8868\u7b26\u548c\u6362\u884c\u7b26\uff09\u5c06\u5176\u5206\u9694\u5f00\u3002\u8f93\u51fa\u6216\u8f93\u5165\u5230\u6587\u672c\u6587\u4ef6\u7684\u6240\u6709\u6570\u636e\u5fc5\u987b\u662f\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\uff0c\u6240\u4ee5\u5728\u8f93\u5165/\u8f93\u51fa\u65f6\u9700\u8981\u505a\u76f8\u5e94\u7684\u7c7b\u578b\u8f6c\u6362\u3002 \u5982\u4e0b\u4f8b\uff1a 34.6 22.33 66.75 77.12 21.44 99.01 Python\u7684open\u51fd\u6570\u63a5\u6536\u4e0b\u9762\u4e24\u4e2a\u4e3b\u8981\u53c2\u6570\uff0c\u6253\u5f00\u4e00\u4e2a\u4e0e\u78c1\u76d8\u6587\u4ef6\u7684\u8fde\u63a5\u5e76\u4e14\u8fd4\u56de\u76f8\u5e94\u7684\u6587\u4ef6\u5bf9\u8c61\u3002 \u6587\u4ef6\u8def\u5f84\uff1b \u6253\u5f00\u6a21\u5f0f\uff1a \u6253\u5f00\u6a21\u5f0f\uff1a r \u8868\u793a\u6587\u4ef6\u53ea\u80fd\u8bfb\u53d6\uff1b w \u8868\u793a\u6587\u4ef6\u53ea\u80fd\u5199\u5165\uff1b a \u8868\u793a\u6253\u5f00\u6587\u4ef6\uff0c\u5728\u539f\u6709\u5185\u5bb9\u7684\u57fa\u7840\u4e0a\u8ffd\u52a0\u5185\u5bb9\uff0c\u5728\u672b\u5c3e\u5199\u5165\uff1b w+ \u8868\u793a\u53ef\u4ee5\u5bf9\u6587\u4ef6\u8fdb\u884c\u8bfb\u5199\u53cc\u91cd\u64cd\u4f5c\uff1b rb \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u53ea\u8bfb\uff1b wb \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u53ea\u5199\uff1b ab \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u8ffd\u52a0\uff1b wb+ \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u8bfb\u5199\uff1b \u793a\u4f8b\uff1a \u4e3a myfile.txt \u6587\u4ef6\u6253\u5f00\u4e00\u4e2a\u7528\u6765\u8f93\u51fa\u7684\u6587\u4ef6\u5bf9\u8c61\u3002 \u5b57\u7b26\u4e32\u6570\u636e\u901a\u8fc7 write \u65b9\u6cd5\u548c\u6587\u4ef6\u5bf9\u8c61\u5199\u5165\uff08\u6216\u8f93\u51fa\uff09\u5230\u6587\u4ef6\u91cc\u3002 \u8f6c\u4e49\u7b26 \\n \u5b9e\u73b0\u6362\u884c\u3002 \u4f7f\u7528 close \u65b9\u6cd5\u5173\u95ed\u6587\u4ef6\u3002\u5982\u679c\u6ca1\u6709\u5173\u95ed\u8f93\u51fa\u6587\u4ef6\uff0c\u5219\u53ef\u80fd\u5bfc\u81f4\u6570\u636e\u4e22\u5931\u3002 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) f . write ( \"First line. \\n Second line. \\n \" ) f . close () \u6587\u4ef6myfile.txt\u7684\u5185\u5bb9\uff1a First line. Second line.","title":"1.7.1.\u6587\u672c\u6587\u4ef6\u8bfb\u53d6"},{"location":"python/DataStructure/01_PythonFundmantal/#172","text":"\u6587\u4ef6\u7684 write \u65b9\u6cd5\u63a5\u6536\u4e00\u4e2a\u5b57\u7b26\u4e32\u4f5c\u4e3a\u53c2\u6570\u3002\u56e0\u6b64\uff0c\u5176\u4ed6\u7c7b\u578b\u7684\u6570\u636e\uff08\u5982\u6574\u6570\u6216\u6d6e\u70b9\u6570\uff09\u5728\u5199\u5165\u8f93\u51fa\u6587\u4ef6\u4e4b\u524d\uff0c\u90fd\u5fc5\u987b\u5148\u88ab\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\u3002 \u5728Python\u91cc\uff0c\u53ef\u4ee5\u4f7f\u7528 str \u51fd\u6570\u628a\u7edd\u5927\u591a\u6570\u7684\u6570\u636e\u7c7b\u578b\u7684\u503c\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\uff0c\u4ee5\u7a7a\u683c\u6216\u6362\u884c\u7b26\u4f5c\u4e3a\u5206\u9694\u7b26\uff0c\u5c06\u5176\u5199\u5165\u6587\u4ef6\u91cc\u3002 \u793a\u4f8b\uff1a\u751f\u6210500\u4e2a\u4ecb\u4e8e1\u548c500\u4e4b\u95f4\u7684\u968f\u673a\u6570\uff0c\u5e76\u8f93\u51fa\u5230\u6587\u672c\u6587\u4ef6\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) for count in range ( 500 ): number = random . randint ( 1 , 500 ) f . write ( str ( number ) + \" \\n \" ) f . close ()","title":"1.7.2.\u6587\u672c\u6587\u4ef6\u5199\u5165"},{"location":"python/DataStructure/01_PythonFundmantal/#173","text":"\u793a\u4f8b\uff1a\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) f . write ( \"First line. \\n Second line. \\n \" ) # \u521d\u59cb\u5316\u6587\u4ef6\u5185\u5bb9 f . close () # \u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) text1 = f . read () # \u628a\u6587\u4ef6\u7684\u5168\u90e8\u5185\u5bb9\u8f93\u5165\u5355\u4e2a\u5b57\u7b26\u4e32\u4e2d print ( text1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # First line. # Second line text2 = f . read () # \u518d\u6b21read\uff0c\u5f97\u5230\u4e00\u4e2a\u7a7a\u5b57\u4e32\uff0c\u8868\u8ff0\u5df2\u7ecf\u5230\u8fbe\u6587\u4ef6\u672b\u5c3e\u3002\u8981\u518d\u6b21\u8bfb\u53d6\u9700\u8981\u91cd\u65b0\u6253\u5f00\u6587\u4ef6 print ( \"======\" ) print ( text2 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ====== # f . close () # \u91cd\u65b0\u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) for line in f : # \u9010\u884c\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9 print ( \"======\" ) print ( line ) # \u6bcf\u884c\u90fd\u6709\u4e00\u4e2a\u6362\u884c\u7b26\uff0c\u8fd9\u662fprint\u51fd\u6570\u9ed8\u8ba4\u884c\u4e3a # \u8fd0\u884c\u7ed3\u679c\uff1a # ====== # First line. # ====== # Second line. # f . close () # \u91cd\u65b0\u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) while True : line = f . readline () # readline\u65b9\u6cd5\u4f1a\u4ece\u8f93\u5165\u7684\u6587\u672c\u91cc\u53ea\u83b7\u53d6\u4e00\u884c\u6570\u636e\uff0c\u5e76\u4e14\u8fd4\u56de\u8fd9\u4e2a\u5305\u542b\u6362\u884c\u7b26\u7684\u5b57\u7b26\u4e32\u3002\u5982\u679creadline\u9047\u5230\u4e86\u6587\u4ef6\u672b\u5c3e\uff0c\u90a3\u4e48\u4f1a\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\u3002 if line == \"\" : break print ( \"******\" ) print ( line ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ****** # First line. # ****** # Second line. # f . close () # \u91cd\u65b0\u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) line = f . readlines () # readlines\u65b9\u6cd5\u5219\u662f\u8bfb\u53d6\u6240\u6709\u884c\uff0c\u8fd4\u56de\u7684\u662f\u6240\u6709\u884c\u7ec4\u6210\u7684\u5217\u8868\u3002 print ( line ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ['First line.\\n', 'Second line.\\n'] f . close ()","title":"1.7.3.\u4ece\u6587\u672c\u6587\u4ef6\u8bfb\u53d6\u6570\u636e"},{"location":"python/DataStructure/01_PythonFundmantal/#174","text":"\u793a\u4f8b\uff1a\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6574\u6570\uff0c\u6bcf\u884c\u53ea\u6709\u4e00\u4e2a\u6574\u6570\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) # \u751f\u62100~9\u6574\u6570\uff0c\u5e76\u5199\u5165\u6587\u4ef6 for count in range ( 10 ): f . write ( str ( count ) + \" \\n \" ) f . close () # \u6253\u5f00\u6587\u4ef6 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) # \u4f9d\u6b21\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6570\u5b57\uff0c\u5e76\u6c42\u548c theSum = 0 for line in f : line = line . strip () number = int ( line ) theSum += number print ( \"The sum is : \" , theSum ) # \u8fd0\u884c\u7ed3\u679c\uff1a # The sum is : 45 f . close () \u793a\u4f8b\uff1a\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6574\u6570\uff0c\u6bcf\u884c\u6709\u591a\u4e2a\u6574\u6570\u3002\u9700\u8981\u4e8b\u5148\u628a\u4e0b\u9762\u7684\u5185\u5bb9\u5199\u5165 myfile.txt \u6587\u4ef6\u4e2d\u3002 \u6587\u4ef6 myfile.txt \u7684\u5185\u5bb9\u3002 1 3 5 7 9 2 4 6 8 10 31 200 3000 50000 import random # \u6253\u5f00\u6587\u4ef6 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) # \u4f9d\u6b21\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6570\u5b57\uff0c\u5e76\u6c42\u548c theSum = 0 for line in f : lines = line . split () # split\u65b9\u6cd5\u4f1a\u81ea\u52a8\u5904\u7406\u6362\u884c\u7b26 for word in lines : number = int ( word ) theSum += number print ( \"The sum is : \" , theSum ) # \u8fd0\u884c\u7ed3\u679c\uff1a # The sum is : 53286 f . close () \u7b80\u5199\u4e0a\u9762\u7684\u4ee3\u7801\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) print ( \"The sum is: \" , sum ( map ( int , f . read () . split ()))) # \u8fd0\u884c\u7ed3\u679c\uff1a # The sum is : 53286 f . close ()","title":"1.7.4.\u4ece\u5176\u5b83\u6587\u4ef6\u8bfb\u53d6\u6570\u636e"},{"location":"python/DataStructure/01_PythonFundmantal/#175pickle","text":"\u5728\u628a\u4efb\u4f55\u5bf9\u8c61\u4fdd\u5b58\u5230\u6587\u4ef6\u4e4b\u524d\uff0c\u6211\u4eec\u53ef\u4ee5\u5bf9\u5b83\u8fdb\u884c\u201c\u814c\u5236\u201d\uff1b\u5728\u628a\u5bf9\u8c61\u4ece\u6587\u4ef6\u52a0\u8f7d\u5230\u7a0b\u5e8f\u4e2d\u65f6\uff0c\u4e5f\u53ef\u4ee5\u5bf9\u5b83\u8fdb\u884c\u201c\u53cd\u814c\u5236\u201d\u3002 \u793a\u4f8b\uff1a \u4f7f\u7528pickle\u6a21\u5757\u7684 pickle.dump \u628a\u540d\u4e3alyst\u7684\u5217\u8868\u91cc\u7684\u6240\u6709\u5bf9\u8c61\u4fdd\u5b58\u5230\u540d\u4e3aitems.dat\u7684\u6587\u4ef6\u91cc\uff08\u201c\u814c\u5236\u201d\uff09\u3002\u6211\u4eec\u4e0d\u9700\u8981\u77e5\u9053\u5217\u8868\u91cc\u6709\u54ea\u4e9b\u7c7b\u578b\u7684\u5bf9\u8c61\uff0c\u4e5f\u4e0d\u9700\u8981\u77e5\u9053\u6709\u591a\u5c11\u4e2a\u5bf9\u8c61\u3002 import pickle myList = [ 60 , \"A string object\" , 1977 ] fObj = open ( \"./docs/python/DataStructure/code/items.dat\" , \"wb\" ) for item in myList : pickle . dump ( item , fObj ) fObj . close () \u4f7f\u7528pickle\u6a21\u5757\u7684 pickle.load \u628aitems.dat\u7684\u6587\u4ef6\u5185\u5bb9\u52a0\u8f7d\u56de\u7a0b\u5e8f\uff08\u201c\u53cd\u814c\u5236\u201d\uff09\u3002 import pickle lyst = list () fileObj = open ( \"./docs/python/DataStructure/code/items.dat\" , \"rb\" ) while True : try : item = pickle . load ( fileObj ) lyst . append ( item ) except EOFError : # \u68c0\u6d4b\u5df2\u7ecf\u5230\u8fbe\u6587\u4ef6\u672b\u5c3e fileObj . close () break print ( lyst ) # \u8fd0\u884c\u7ed3\u679c\uff1a # [60, 'A string object', 1977]","title":"1.7.5.\u4f7f\u7528pickle\u8bfb\u5199\u5bf9\u8c61"},{"location":"python/DataStructure/01_PythonFundmantal/#18","text":"\u7c7b\uff08class\uff09\u7528\u6765\u63cf\u8ff0\u4e0e\u4e00\u7ec4\u5bf9\u8c61\u6709\u5173\u7684\u6570\u636e\u548c\u65b9\u6cd5\u3002\u5b83\u63d0\u4f9b\u4e86\u7528\u6765\u521b\u5efa\u5bf9\u8c61\u7684\u84dd\u56fe\uff0c\u4ee5\u53ca\u5728\u5bf9\u8c61\u4e0a\u8c03\u7528\u65b9\u6cd5\u65f6\u6240\u9700\u8981\u6267\u884c\u7684\u4ee3\u7801\u3002 Python\u91cc\u7684\u6570\u636e\u7c7b\u578b\u90fd\u662f\u7c7b\uff1b \u7c7b\u540d\u6309\u7167\u60ef\u4f8b\u9996\u5b57\u6bcd\u5e94\u4e3a\u5927\u5199\u6837\u5f0f\uff1b \u5b9a\u4e49\u7c7b\u7684\u4ee3\u7801\u901a\u5e38\u4f1a\u88ab\u5b58\u653e\u5728\u9996\u5b57\u6bcd\u5c0f\u5199\u7684\u7c7b\u540d\u7684\u6a21\u5757\u6587\u4ef6\u91cc\u3002 \u76f8\u5173\u7684\u7c7b\u4e5f\u53ef\u80fd\u4f1a\u51fa\u73b0\u5728\u540c\u4e00\u4e2a\u6a21\u5757\u91cc\u3002 \u7c7b\u7684\u8bed\u6cd5\uff1a def < class name > ( < parent class name > )[ 2 ]: < class variable assignments > < instance method definitions > \u7236\u7c7b\uff08parent class\uff09\u7684\u540d\u79f0\u662f\u53ef\u9009\u7684\uff0c\u5728\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b83\u4f1a\u662fobject\u3002 \u6240\u6709Python\u7c7b\u5c5e\u4e8e\u4e00\u4e2a\u4ee5 object \u4f5c\u4e3a\u6839\u8282\u70b9\u7684\u5c42\u6b21\u7ed3\u6784\u3002 \u5728 object \u91cc\uff0cPython\u5b9a\u4e49\u4e86\u51e0\u79cd\u65b9\u6cd5\uff1a __str__ \u548c __eq__ \uff0c\u56e0\u6b64\u6240\u6709\u5b50\u7c7b\u4f1a\u81ea\u52a8\u7ee7\u627f\u8fd9\u4e9b\u65b9\u6cd5\u3002 \u5b9e\u4f8b\u65b9\u6cd5\uff08instance method\uff09\u662f\u5728\u7c7b\u7684\u5bf9\u8c61\u4e0a\u8fd0\u884c\u7684\u3002\u5b83\u4eec\u5305\u542b\u7528\u6765\u8bbf\u95ee\u6216\u4fee\u6539\u5b9e\u4f8b\u53d8\u91cf\u7684\u4ee3\u7801\u3002 \u5b9e\u4f8b\u53d8\u91cf\uff08instance variable\uff09\u662f\u6307\u7531\u5355\u4e2a\u5bf9\u8c61\u6240\u62e5\u6709\u7684\u5b58\u50a8\u4fe1\u606f\u3002 \u7c7b\u53d8\u91cf\uff08class variable\uff09\u662f\u6307\u7531\u7c7b\u7684\u6240\u6709\u5bf9\u8c61\u5b58\u50a8\u6240\u6709\u7684\u4fe1\u606f\u3002 \u793a\u4f8b\uff1a\u89e3\u8bfbCounter\u7c7b\u3002 Counter \u7c7b\u662f object \u7684\u5b50\u7c7b\uff1b instances \u662f\u7c7b\u53d8\u91cf\uff0c\u8ddf\u8e2a\u5df2\u521b\u5efa\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u7684\u6570\u91cf\uff1b \u5b9e\u4f8b\u65b9\u6cd5 __init__ \u4e5f\u79f0\u4e3a\u6784\u9020\u51fd\u6570\uff1b\u8fd9\u4e2a\u65b9\u6cd5\u7528\u6765\u521d\u59cb\u5316\u5b9e\u4f8b\u53d8\u91cf\uff0c\u5e76\u4e14\u5bf9\u7c7b\u53d8\u91cf\u8fdb\u884c\u66f4\u65b0\uff1b self \u662f\u6307\u5728\u8fd0\u884c\u65f6\u8fd9\u4e2a\u65b9\u6cd5\u7684\u5bf9\u8c61\u672c\u8eab\uff1b \u4f7f\u7528\u5b9e\u4f8b\u53d8\u91cf\u90fd\u4f1a\u52a0\u4e0a\u524d\u7f00 self \uff1b\u548c\u53c2\u6570\u6216\u4e34\u65f6\u53d8\u91cf\u4e0d\u540c\u7684\u5730\u65b9\u662f\uff0c\u5b9e\u4f8b\u53d8\u91cf\u5728\u7c7b\u7684\u4efb\u4f55\u65b9\u6cd5\u91cc\u662f\u53ef\u89c1\u7684\uff1b \u5176\u4ed6\u5b9e\u4f8b\u65b9\u6cd5\u53ef\u4ee5\u5206\u4e3a\u4e24\u79cd\uff1a\u53d8\u5f02\u5668\uff08mutator\uff09\u548c\u8bbf\u95ee\u5668\uff08accessor\uff09\u3002\u53d8\u5f02\u5668\u4f1a\u901a\u8fc7\u4fee\u6539\u5bf9\u8c61\u7684\u5b9e\u4f8b\u53d8\u91cf\u5bf9\u5176\u5185\u90e8\u72b6\u6001\u8fdb\u884c\u4fee\u6539\u6216\u66f4\u6539\u3002\u8bbf\u95ee\u5668\u5219\u53ea\u4f1a\u67e5\u770b\u6216\u4f7f\u7528\u5bf9\u8c61\u7684\u5b9e\u4f8b\u53d8\u91cf\u7684\u503c\uff0c\u800c\u4e0d\u4f1a\u53bb\u4fee\u6539\u5b83\u4eec\uff1b __str__ \u65b9\u6cd5\u5c06\u8986\u76d6object\u7c7b\u91cc\u7684\u8fd9\u4e2a\u65b9\u6cd5\uff1b \u5f53Python\u7684 print \u51fd\u6570\u63a5\u6536\u5230\u4e00\u4e2a\u53c2\u6570\u65f6\uff0c\u8fd9\u4e2a\u53c2\u6570\u7684 __str__ \u65b9\u6cd5\u5c06\u81ea\u52a8\u8fd0\u884c\uff0c\u4ece\u800c\u5f97\u5230\u5b83\u7684\u5b57\u7b26\u4e32\u8868\u8fbe\u5f0f\uff0c\u4ee5\u4fbf\u7528\u6765\u8f93\u51fa\uff1b \u5f53\u770b\u5230 == \u8fd0\u7b97\u7b26\u65f6\uff0cPython\u5c06\u8fd0\u884c __eq__ \u65b9\u6cd5\uff1b\u5728 object \u7c7b\u91cc\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u7684\u9ed8\u8ba4\u5b9a\u4e49\u662f\u8fd0\u884c is \u8fd0\u7b97\u7b26\u3002 class Counter ( object ): # Counter\u7c7b\u662fobject\u7684\u5b50\u7c7b \"\"\"Models a counter.\"\"\" # Class variable \u7c7b\u53d8\u91cf instances = 0 # \u8ddf\u8e2a\u5df2\u521b\u5efa\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u7684\u6570\u91cf # Constructor \u6784\u9020\u5668 # \u5b9e\u4f8b\u65b9\u6cd5__init__\u4e5f\u79f0\u4e3a\u6784\u9020\u51fd\u6570\uff1b\u8fd9\u4e2a\u65b9\u6cd5\u7528\u6765\u521d\u59cb\u5316\u5b9e\u4f8b\u53d8\u91cf\uff0c\u5e76\u4e14\u5bf9\u7c7b\u53d8\u91cf\u8fdb\u884c\u66f4\u65b0\uff1b def __init__ ( self ): # self\u662f\u6307\u5728\u8fd0\u884c\u65f6\u8fd9\u4e2a\u65b9\u6cd5\u7684\u5bf9\u8c61\u672c\u8eab \"\"\"Sets up the counter.\"\"\" Counter . instances += 1 self . reset () # Mutator methods def reset ( self ): \"\"\"Sets the counter to 0.\"\"\" self . value = 0 def increment ( self , amount = 1 ): \"\"\"Adds amount to the counter.\"\"\" self . value += amount def decrement ( self , amount = 1 ): \"\"\"Subtracts amount from the counter.\"\"\" self . value -= amount # Accessor methods def getValue ( self ): \"\"\"Returns the counter's value.\"\"\" return self . value def __str__ ( self ): \"\"\"Returns the string representation of the counter.\"\"\" return str ( self . value ) def __eq__ ( self , other ): \"\"\"Returns True if self equals other or False otherwise.\"\"\" if self is other : return True if type ( self ) != type ( other ): return False return self . value == other . value c1 = Counter () print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 0 c1 . getValue () str ( c1 ) c1 . increment () print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 1 c1 . increment ( 5 ) print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 6 c1 . reset () print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 0 c2 = Counter () print ( Counter . instances ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 2 print ( c1 == c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # True print ( c1 == 0 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # False print ( c1 == c2 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # True c2 . increment () print ( c1 == c2 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # False","title":"1.8.\u521b\u5efa\u7c7b"},{"location":"python/DataStructure/01_PythonFundmantal/#19","text":"1\uff0e\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u4f7f\u4e4b\u80fd\u591f\u63a5\u6536\u7403\u4f53\u7684\u534a\u5f84\uff08\u6d6e\u70b9\u6570\uff09\uff0c\u5e76\u4e14\u53ef\u4ee5\u8f93\u51fa\u7403\u4f53\u7684\u76f4\u5f84\u3001\u5468\u957f\u3001\u8868\u9762\u79ef\u4ee5\u53ca\u4f53\u79ef\u3002 \u89e3\u7b54\uff1a PAI = 3.14 radius = float ( input ( \"\u8f93\u5165\u7403\u534a\u5f84\uff1a\" )) diameter = radius * 2 circumference = 2 * PAI * radius surfaceArea = 4 * PAI * radius ** 2 sphereVolume = 4 * ( PAI * radius ** 3 ) / 3 print ( \"\u7403\u534a\u5f84\uff1a\" , radius , \"\u7403\u76f4\u5f84\uff1a\" , diameter , \"\u7403\u8868\u9762\u79ef\uff1a\" , surfaceArea , \"\u7403\u4f53\u79ef\uff1a\" , sphereVolume ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u7403\u534a\u5f84\uff1a3.5 # \u7403\u534a\u5f84\uff1a 3.5 \u7403\u76f4\u5f84\uff1a 7.0 \u7403\u8868\u9762\u79ef\uff1a 153.86 \u7403\u4f53\u79ef\uff1a 179.50333333333333 import math def main (): try : radius = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u534a\u5f84\uff1a\" )) if radius <= 0 : print ( \"\u534a\u5f84\u5fc5\u987b\u4e3a\u6b63\u6570\uff01\" ) return diameter = 2 * radius circumference = 2 * math . pi * radius surfaceArea = 4 * math . pi * radius ** 2 volume = ( 4 / 3 ) * math . pi * radius ** 3 print ( f \"\u7403\u4f53\u7684\u76f4\u5f84\uff1a { diameter : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u5468\u957f\uff1a { circumference : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a { surfaceArea : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u4f53\u79ef\uff1a { volume : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u7403\u534a\u5f84\uff1a3.5 # \u7403\u4f53\u7684\u76f4\u5f84\uff1a7.00 # \u7403\u4f53\u7684\u5468\u957f\uff1a21.99 # \u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a153.94 # \u7403\u4f53\u7684\u4f53\u79ef\uff1a179.59 import math class Sphere : def __init__ ( self , radius ): self . radius = radius def diameter ( self ): return 2 * self . radius def circumference ( self ): return 2 * math . pi * self . radius def surfaceArea ( self ): return 4 * math . pi * self . radius ** 2 def volume ( self ): return ( 4 / 3 ) * math . pi * self . radius ** 3 def main (): try : radius = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u4f53\u7684\u534a\u5f84\uff1a\" )) if radius <= 0 : print ( \"\u534a\u5f84\u5fc5\u987b\u4e3a\u6b63\u6570\uff01\" ) return sphere = Sphere ( radius ) print ( f \"\u7403\u4f53\u7684\u76f4\u5f84\uff1a { sphere . diameter () : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u5468\u957f\uff1a { sphere . circumference () : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a { sphere . surfaceArea () : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u4f53\u79ef\uff1a { sphere . volume () : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u7403\u4f53\u7684\u534a\u5f84\uff1a3.5 # \u7403\u4f53\u7684\u76f4\u5f84\uff1a7.00 # \u7403\u4f53\u7684\u5468\u957f\uff1a21.99 # \u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a153.94 # \u7403\u4f53\u7684\u4f53\u79ef\uff1a179.59 2\uff0e\u5458\u5de5\u7684\u5468\u5de5\u8d44\u7b49\u4e8e\u5c0f\u65f6\u5de5\u8d44\u4e58\u4ee5\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\u518d\u52a0\u4e0a\u52a0\u73ed\u5de5\u8d44\u3002\u52a0\u73ed\u5de5\u8d44\u7b49\u4e8e\u603b\u52a0\u73ed\u65f6\u95f4\u4e58\u4ee5\u5c0f\u65f6\u5de5\u8d44\u76841.5\u500d\u3002\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\u3001\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\u4ee5\u53ca\u52a0\u73ed\u603b\u65f6\u95f4\uff0c\u7136\u540e\u663e\u793a\u51fa\u5458\u5de5\u7684\u5468\u5de5\u8d44\u3002 \u89e3\u7b54\uff1a hourSalary = float ( input ( \"\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff08\u5143\uff09\uff1a\" )) totalWorkingHours = float ( input ( \"\u8f93\u5165\u672c\u5468\u6b63\u5e38\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) totalOvertimeHours = float ( input ( \"\u8f93\u5165\u672c\u5468\u603b\u52a0\u73ed\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) weeklySalary = hourSalary * totalWorkingHours + hourSalary * totalOvertimeHours * 1.5 print ( \"\u5458\u5de5\u7684\u5468\u5de5\u8d44\uff08\u5143\uff09\u662f\uff1a\" , weeklySalary ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff08\u5143\uff09\uff1a20 # \u8f93\u5165\u672c\u5468\u6b63\u5e38\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a40 # \u8f93\u5165\u672c\u5468\u603b\u52a0\u73ed\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a10 # \u5458\u5de5\u7684\u5468\u5de5\u8d44\uff08\u5143\uff09\u662f\uff1a 1100.0 def calculate_weekly_salary ( hourly_wage , normal_hours , overtime_hours ): overtime_pay = overtime_hours * hourly_wage * 1.5 normal_pay = normal_hours * hourly_wage weekly_salary = normal_pay + overtime_pay return weekly_salary def main (): try : hourly_wage = float ( input ( \"\u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a\" )) normal_hours = float ( input ( \"\u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) overtime_hours = float ( input ( \"\u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) weekly_salary = calculate_weekly_salary ( hourly_wage , normal_hours , overtime_hours ) print ( f \"\u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a { weekly_salary : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a20 # \u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a40 # \u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a10 # \u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a1100.00 class Employee : def __init__ ( self , hourly_wage , normal_hours , overtime_hours ): self . hourly_wage = hourly_wage self . normal_hours = normal_hours self . overtime_hours = overtime_hours def calculate_weekly_salary ( self ): overtime_pay = self . overtime_hours * self . hourly_wage * 1.5 normal_pay = self . normal_hours * self . hourly_wage weekly_salary = normal_pay + overtime_pay return weekly_salary def main (): try : hourly_wage = float ( input ( \"\u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a\" )) normal_hours = float ( input ( \"\u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) overtime_hours = float ( input ( \"\u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) employee = Employee ( hourly_wage , normal_hours , overtime_hours ) weekly_salary = employee . calculate_weekly_salary () print ( f \"\u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a { weekly_salary : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a20 # \u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a40 # \u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a10 # \u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a1100.00 3\uff0e\u6709\u4e00\u4e2a\u6807\u51c6\u7684\u79d1\u5b66\u5b9e\u9a8c\uff1a\u6254\u4e00\u4e2a\u7403\uff0c\u770b\u770b\u5b83\u80fd\u53cd\u5f39\u591a\u9ad8\u3002\u4e00\u65e6\u786e\u5b9a\u4e86\u7403\u7684\u201c\u53cd\u5f39\u9ad8\u5ea6\u201d\uff0c\u8fd9\u4e2a\u6bd4\u503c\u5c31\u7ed9\u51fa\u4e86\u76f8\u5e94\u7684\u53cd\u5f39\u5ea6\u6307\u6570\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4ece10ft\uff081ft=0.3048m\uff09\u9ad8\u5904\u6389\u843d\u7684\u7403\u53ef\u4ee5\u53cd\u5f39\u52306 ft\u9ad8\uff0c\u90a3\u4e48\u76f8\u5e94\u7684\u53cd\u5f39\u5ea6\u6307\u6570\u5c31\u662f0.6\uff1b\u5728\u4e00\u6b21\u53cd\u5f39\u4e4b\u540e\uff0c\u7403\u7684\u603b\u884c\u8fdb\u8ddd\u79bb\u662f16 ft\u3002\u63a5\u4e0b\u6765\uff0c\u7403\u7ee7\u7eed\u5f39\u8df3\uff0c\u90a3\u4e48\u4e24\u6b21\u5f39\u8df3\u540e\u7684\u603b\u8ddd\u79bb\u5e94\u8be5\u662f\uff1a10 ft + 6 ft + 6 ft + 3.6 ft = 25.6 ft\u3002\u53ef\u4ee5\u770b\u5230\uff0c\u6bcf\u6b21\u8fde\u7eed\u5f39\u8df3\u6240\u7ecf\u8fc7\u7684\u8ddd\u79bb\u662f\uff1a\u7403\u5230\u5730\u9762\u7684\u8ddd\u79bb\uff0c\u52a0\u4e0a\u8fd9\u4e2a\u8ddd\u79bb\u4e58\u4ee5 0.6\uff0c\u8fd9\u65f6\u7403\u53c8\u5f39\u56de\u6765\u4e86\u3002\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u53ef\u4ee5\u8ba9\u7528\u6237\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\u548c\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff0c\u5e76\u8f93\u51fa\u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u3002 \u89e3\u7b54\uff1a height = float ( input ( \"\u8f93\u5165\u5c0f\u7403\u521d\u59cb\u9ad8\u5ea6\uff08ft\uff09\uff1a\" )) times = float ( input ( \"\u8f93\u5165\u5141\u8bb8\u5c0f\u7403\u5f39\u8df3\u6b21\u6570\uff1a\" )) distance = 0 traceDistance = 0 while times : distance = height + 0.6 * height traceDistance += distance height = 0.6 * height times -= 1 print ( \"\u5c0f\u7403\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\uff08ft\uff09\uff1a\" , traceDistance ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u5c0f\u7403\u521d\u59cb\u9ad8\u5ea6\uff08ft\uff09\uff1a50 # \u8f93\u5165\u5141\u8bb8\u5c0f\u7403\u5f39\u8df3\u6b21\u6570\uff1a5 # \u5c0f\u7403\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\uff08ft\uff09\uff1a 184.448 # \u8f93\u5165\u5c0f\u7403\u521d\u59cb\u9ad8\u5ea6\uff08ft\uff09\uff1a100 # \u8f93\u5165\u5141\u8bb8\u5c0f\u7403\u5f39\u8df3\u6b21\u6570\uff1a10 # \u5c0f\u7403\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\uff08ft\uff09\uff1a 397.58135296000006 def calculate_total_distance ( initial_height , num_bounces ): rebound_factor = 0.6 total_distance = 0 height = initial_height for _ in range ( num_bounces + 1 ): total_distance += height height *= rebound_factor return total_distance def main (): try : initial_height = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a\" )) num_bounces = int ( input ( \"\u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a\" )) total_distance = calculate_total_distance ( initial_height , num_bounces ) print ( f \"\u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a { total_distance : .2f } ft\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a50 # \u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a5 # \u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a119.17 ft # \u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a100 # \u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a10 # \u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a249.09 ft class BouncingBall : def __init__ ( self , initial_height , num_bounces ): self . initial_height = initial_height self . num_bounces = num_bounces self . rebound_factor = 0.6 def calculate_total_distance ( self ): total_distance = 0 height = self . initial_height for _ in range ( self . num_bounces + 1 ): total_distance += height height *= self . rebound_factor return total_distance def main (): try : initial_height = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a\" )) num_bounces = int ( input ( \"\u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a\" )) bouncing_ball = BouncingBall ( initial_height , num_bounces ) total_distance = bouncing_ball . calculate_total_distance () print ( f \"\u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a { total_distance : .2f } ft\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () 4\uff0e\u5fb7\u56fd\u6570\u5b66\u5bb6Gottfried Leibniz\u53d1\u660e\u4e86\u4e0b\u9762\u8fd9\u4e2a\u7528\u6765\u6c42\u03c0\u7684\u8fd1\u4f3c\u503c\u7684\u65b9\u6cd5\uff1a \u03c0/4 = 1 - 1/3 + 1/5 - 1/7 + ...... \uff0c\u8bf7\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u6307\u5b9a\u8fd9\u4e2a\u8fd1\u4f3c\u503c\u6240\u4f7f\u7528\u7684\u8fed\u4ee3\u6b21\u6570\uff0c\u5e76\u4e14\u663e\u793a\u51fa\u7ed3\u679c\u3002 \u89e3\u7b54\uff1a n = int ( input ( \"\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a\" )) mySum = 0 while n : mySum += 1 / ( 2 * n - 1 ) * (( - 1 ) ** ( n + 1 )) n -= 1 print ( \"\u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a\" , mySum * 4 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a5 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.33968253968254 # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.0418396189294024 # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a20 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.0916238066678385 # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10000000 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.1415925535897933 def calculate_pi_approximation ( iterations ): approximation = 0 sign = 1 for i in range ( 1 , iterations * 2 , 2 ): approximation += sign * ( 1 / i ) sign *= - 1 return approximation * 4 def main (): try : iterations = int ( input ( \"\u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a\" )) if iterations <= 0 : print ( \"\u8fed\u4ee3\u6b21\u6570\u5fc5\u987b\u4e3a\u6b63\u6574\u6570\uff01\" ) return pi_approximation = calculate_pi_approximation ( iterations ) print ( f \"\u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a { pi_approximation : .10f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6574\u6570\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a5 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.3396825397 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0418396189 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a20 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0916238067 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10000000 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.1415925536 class PiApproximation : @classmethod def calculate_pi_approximation ( cls , iterations ): approximation = 0 sign = 1 for i in range ( 1 , iterations * 2 , 2 ): approximation += sign * ( 1 / i ) sign *= - 1 return approximation * 4 def main (): try : iterations = int ( input ( \"\u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a\" )) if iterations <= 0 : print ( \"\u8fed\u4ee3\u6b21\u6570\u5fc5\u987b\u4e3a\u6b63\u6574\u6570\uff01\" ) return pi_approximation = PiApproximation . calculate_pi_approximation ( iterations ) print ( f \"\u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a { pi_approximation : .10f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6574\u6570\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a5 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.3396825397 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0418396189 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a20 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0916238067 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10000000 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.1415925536 5\uff0e\u67d0\u8ba1\u7b97\u673a\u5546\u5e97\u6709\u8d2d\u4e70\u8ba1\u7b97\u673a\u7684\u4fe1\u8d37\u8ba1\u5212\uff1a\u9996\u4ed810%\uff0c\u5e74\u5229\u7387\u4e3a12%\uff0c\u6bcf\u6708\u6240\u4ed8\u6b3e\u4e3a\u8d2d\u4e70\u4ef7\u683c\u51cf\u53bb\u9996\u4ed8\u4e4b\u540e\u76845%\u3002\u7f16\u5199\u4e00\u4e2a\u4ee5\u8d2d\u4e70\u4ef7\u683c\u4e3a\u8f93\u5165\u7684\u7a0b\u5e8f\uff0c\u53ef\u4ee5\u8f93\u51fa\u4e00\u4e2a\u6709\u9002\u5f53\u6807\u9898\u7684\u8868\u683c\uff0c\u663e\u793a\u8d37\u6b3e\u671f\u9650\u5185\u7684\u4ed8\u6b3e\u8ba1\u5212\u3002\u8868\u7684\u6bcf\u4e00\u884c\u90fd\u5e94\u5305\u542b\u4e0b\u9762\u5404\u9879\uff1a \u6708\u6570\uff08\u4ee51\u5f00\u5934\uff09\uff1b \u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d\uff1b \u5f53\u6708\u6240\u6b20\u7684\u5229\u606f\uff1b \u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1\uff1b \u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d\uff1b \u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d\u3002 \u4e00\u4e2a\u6708\u7684\u5229\u606f\u7b49\u4e8e\u4f59\u989d \u00d7 \u5229\u7387/12\uff1b\u4e00\u4e2a\u6708\u6240\u6b20\u7684\u672c\u91d1\u7b49\u4e8e\u5f53\u6708\u8fd8\u6b3e\u989d\u51cf\u53bb\u6240\u6b20\u7684\u5229\u606f\u3002 \u89e3\u7b54\uff1a def calculate_payment_schedule ( purchase_price ): down_payment = purchase_price * 0.1 loan_balance = purchase_price - down_payment annual_interest_rate = 0.12 monthly_interest_rate = annual_interest_rate / 12 monthly_payment = ( purchase_price - down_payment ) * 0.05 payment_schedule = [] for month in range ( 1 , 13 ): interest = loan_balance * monthly_interest_rate principal = monthly_payment - interest loan_balance -= principal payment_schedule . append (( month , loan_balance , interest , principal , monthly_payment , loan_balance + monthly_payment )) return payment_schedule def main (): try : purchase_price = float ( input ( \"\u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a\" )) payment_schedule = calculate_payment_schedule ( purchase_price ) print ( \" {:<10} {:<15} {:<15} {:<15} {:<15} {:<15} \" . format ( \"\u6708\u6570\" , \"\u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d\" , \"\u5f53\u6708\u6240\u6b20\u7684\u5229\u606f\" , \"\u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1\" , \"\u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d\" , \"\u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d\" )) for payment in payment_schedule : month , balance , interest , principal , monthly_payment , new_balance = payment print ( \" {:<10} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} \" . format ( month , balance , interest , principal , monthly_payment , new_balance )) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a5000 # \u6708\u6570 \u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d \u5f53\u6708\u6240\u6b20\u7684\u5229\u606f \u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1 \u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d \u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d # 1 4320.00 45.00 180.00 225.00 4545.00 # 2 4138.20 43.20 181.80 225.00 4363.20 # 3 3954.58 41.38 183.62 225.00 4179.58 # 4 3769.13 39.55 185.45 225.00 3994.13 # 5 3581.82 37.69 187.31 225.00 3806.82 # 6 3392.64 35.82 189.18 225.00 3617.64 # 7 3201.56 33.93 191.07 225.00 3426.56 # 8 3008.58 32.02 192.98 225.00 3233.58 # 9 2813.67 30.09 194.91 225.00 3038.67 # 10 2616.80 28.14 196.86 225.00 2841.80 # 11 2417.97 26.17 198.83 225.00 2642.97 # 12 2217.15 24.18 200.82 225.00 2442.15 class PaymentSchedule : def __init__ ( self , purchase_price ): self . purchase_price = purchase_price self . down_payment = purchase_price * 0.1 self . loan_balance = purchase_price - self . down_payment self . annual_interest_rate = 0.12 self . monthly_interest_rate = self . annual_interest_rate / 12 self . monthly_payment = ( purchase_price - self . down_payment ) * 0.05 def calculate_schedule ( self ): payment_schedule = [] for month in range ( 1 , 13 ): interest = self . loan_balance * self . monthly_interest_rate principal = self . monthly_payment - interest self . loan_balance -= principal payment_schedule . append (( month , self . loan_balance , interest , principal , self . monthly_payment , self . loan_balance + self . monthly_payment )) return payment_schedule def print_schedule_table ( self ): payment_schedule = self . calculate_schedule () print ( \" {:<10} {:<15} {:<15} {:<15} {:<15} {:<15} \" . format ( \"\u6708\u6570\" , \"\u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d\" , \"\u5f53\u6708\u6240\u6b20\u7684\u5229\u606f\" , \"\u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1\" , \"\u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d\" , \"\u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d\" )) for payment in payment_schedule : month , balance , interest , principal , monthly_payment , new_balance = payment print ( \" {:<10} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} \" . format ( month , balance , interest , principal , monthly_payment , new_balance )) def main (): try : purchase_price = float ( input ( \"\u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a\" )) payment_schedule = PaymentSchedule ( purchase_price ) payment_schedule . print_schedule_table () except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # \u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a5000 # \u6708\u6570 \u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d \u5f53\u6708\u6240\u6b20\u7684\u5229\u606f \u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1 \u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d \u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d # 1 4320.00 45.00 180.00 225.00 4545.00 # 2 4138.20 43.20 181.80 225.00 4363.20 # 3 3954.58 41.38 183.62 225.00 4179.58 # 4 3769.13 39.55 185.45 225.00 3994.13 # 5 3581.82 37.69 187.31 225.00 3806.82 # 6 3392.64 35.82 189.18 225.00 3617.64 # 7 3201.56 33.93 191.07 225.00 3426.56 # 8 3008.58 32.02 192.98 225.00 3233.58 # 9 2813.67 30.09 194.91 225.00 3038.67 # 10 2616.80 28.14 196.86 225.00 2841.80 # 11 2417.97 26.17 198.83 225.00 2642.97 # 12 2217.15 24.18 200.82 225.00 2442.15 6\uff0e\u8d22\u52a1\u90e8\u95e8\u5728\u6587\u672c\u6587\u4ef6\u91cc\u4fdd\u5b58\u4e86\u6240\u6709\u5458\u5de5\u5728\u6bcf\u4e2a\u5de5\u8d44\u5468\u671f\u91cc\u7684\u4fe1\u606f\u5217\u8868\u3002\u6587\u4ef6\u4e2d\u6bcf\u4e00\u884c\u7684\u683c\u5f0f\u4e3a \u3002\u8bf7\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u8f93\u5165\u6587\u4ef6\u7684\u540d\u79f0\uff0c\u5e76\u5728\u7ec8\u7aef\u4e0a\u6253\u5370\u51fa\u7ed9\u5b9a\u65f6\u95f4\u5185\u652f\u4ed8\u7ed9\u6bcf\u4e2a\u5458\u5de5\u7684\u5de5\u8d44\u62a5\u544a\u3002\u8fd9\u4e2a\u62a5\u544a\u662f\u4e00\u4e2a\u6709\u5408\u9002\u6807\u9898\u7684\u8868\uff0c\u5176\u4e2d\u6bcf\u884c\u90fd\u5e94\u8be5\u5305\u542b\u5458\u5de5\u7684\u59d3\u540d\u3001\u5de5\u4f5c\u65f6\u957f\u4ee5\u53ca\u7ed9\u5b9a\u65f6\u95f4\u5185\u6240\u652f\u4ed8\u7684\u5de5\u8d44\u3002 \u89e3\u7b54\uff1a # \u7a0b\u5e8f\u4f1a\u63d0\u793a\u7528\u6237\u8f93\u5165\u6587\u4ef6\u540d\uff0c\u7136\u540e\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u5458\u5de5\u4fe1\u606f\uff0c\u8ba1\u7b97\u5de5\u8d44\u62a5\u544a\uff0c\u5e76\u6253\u5370\u51fa\u5458\u5de5\u7684\u59d3\u540d\u3001\u5de5\u4f5c\u65f6\u957f\u548c\u652f\u4ed8\u5de5\u8d44\u3002\u6ce8\u610f\uff0c\u7a0b\u5e8f\u4f1a\u68c0\u67e5\u6587\u4ef6\u662f\u5426\u5b58\u5728\uff0c\u5e76\u4f1a\u5bf9\u6587\u4ef6\u4e2d\u7684\u6bcf\u884c\u6570\u636e\u8fdb\u884c\u5904\u7406\u4ee5\u786e\u4fdd\u6b63\u786e\u89e3\u6790\u3002 class Employee : def __init__ ( self , last_name , hourly_wage , hours_worked ): self . last_name = last_name self . hourly_wage = float ( hourly_wage ) self . hours_worked = float ( hours_worked ) def calculate_salary ( self ): return self . hourly_wage * self . hours_worked def main (): try : filename = input ( \"\u8bf7\u8f93\u5165\u6587\u4ef6\u540d\uff1a\" ) with open ( filename , 'r' ) as file : employees = [] for line in file : parts = line . strip () . split () if len ( parts ) == 3 : last_name , hourly_wage , hours_worked = parts employee = Employee ( last_name , hourly_wage , hours_worked ) employees . append ( employee ) print ( \" {:<20} {:<15} {:<15} \" . format ( \"\u5458\u5de5\u59d3\u540d\" , \"\u5de5\u4f5c\u65f6\u957f\" , \"\u652f\u4ed8\u5de5\u8d44\" )) print ( \"=\" * 50 ) total_salary = 0 for employee in employees : salary = employee . calculate_salary () total_salary += salary print ( \" {:<20} {:<15.2f} {:<15.2f} \" . format ( employee . last_name , employee . hours_worked , salary )) print ( \"=\" * 50 ) print ( f \"\u603b\u652f\u4ed8\u5de5\u8d44\uff1a { total_salary : .2f } \" ) except FileNotFoundError : print ( \"\u6587\u4ef6\u4e0d\u5b58\u5728\uff01\" ) if __name__ == \"__main__\" : main () 7\uff0e\u7edf\u8ba1\u5b66\u5bb6\u5e0c\u671b\u4f7f\u7528\u4e00\u7ec4\u51fd\u6570\u8ba1\u7b97\u6570\u5b57\u5217\u8868\u7684\u4e2d\u4f4d\u6570\uff08median\uff09\u548c\u4f17\u6570\uff08mode\uff09\u3002\u4e2d\u4f4d\u6570\u662f\u6307\u5982\u679c\u5bf9\u5217\u8868\u8fdb\u884c\u6392\u5e8f\u5c06\u4f1a\u51fa\u73b0\u5728\u5217\u8868\u4e2d\u70b9\u7684\u6570\u5b57\uff0c\u4f17\u6570\u662f\u6307\u5217\u8868\u4e2d\u6700\u5e38\u51fa\u73b0\u7684\u6570\u5b57\u3002\u628a\u8fd9\u4e9b\u529f\u80fd\u5b9a\u4e49\u5728\u540d\u53ebstats.py\u7684\u6a21\u5757\u4e2d\u3002\u9664\u6b64\u4e4b\u5916\uff0c\u6a21\u5757\u8fd8\u5e94\u8be5\u5305\u542b\u4e00\u4e2a\u540d\u53ebmean\u7684\u51fd\u6570\uff0c\u7528\u6765\u8ba1\u7b97\u4e00\u7ec4\u6570\u5b57\u7684\u5e73\u5747\u503c\u3002\u6bcf\u4e2a\u51fd\u6570\u90fd\u4f1a\u63a5\u6536\u4e00\u4e2a\u6570\u5b57\u5217\u8868\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u8fd4\u56de\u4e00\u4e2a\u6570\u5b57\u3002 \u89e3\u7b54\uff1a def median ( numbers ): sorted_numbers = sorted ( numbers ) length = len ( sorted_numbers ) if length % 2 == 1 : return sorted_numbers [ length // 2 ] else : mid1 = sorted_numbers [ length // 2 - 1 ] mid2 = sorted_numbers [ length // 2 ] return ( mid1 + mid2 ) / 2 def mode ( numbers ): from collections import Counter counter = Counter ( numbers ) mode_list = counter . most_common () max_count = mode_list [ 0 ][ 1 ] modes = [ num for num , count in mode_list if count == max_count ] return modes def mean ( numbers ): total = sum ( numbers ) count = len ( numbers ) return total / count if __name__ == \"__main__\" : test_numbers = [ 4 , 2 , 7 , 2 , 1 , 9 , 4 , 7 ] print ( \"\u4e2d\u4f4d\u6570:\" , median ( test_numbers )) print ( \"\u4f17\u6570:\" , mode ( test_numbers )) print ( \"\u5e73\u5747\u503c:\" , mean ( test_numbers )) class Stats : @staticmethod def median ( numbers ): sorted_numbers = sorted ( numbers ) length = len ( sorted_numbers ) if length % 2 == 1 : return sorted_numbers [ length // 2 ] else : mid1 = sorted_numbers [ length // 2 - 1 ] mid2 = sorted_numbers [ length // 2 ] return ( mid1 + mid2 ) / 2 @staticmethod def mode ( numbers ): from collections import Counter counter = Counter ( numbers ) mode_list = counter . most_common () max_count = mode_list [ 0 ][ 1 ] modes = [ num for num , count in mode_list if count == max_count ] return modes @staticmethod def mean ( numbers ): total = sum ( numbers ) count = len ( numbers ) return total / count if __name__ == \"__main__\" : test_numbers = [ 4 , 2 , 7 , 2 , 1 , 9 , 4 , 7 ] print ( \"\u4e2d\u4f4d\u6570:\" , Stats . median ( test_numbers )) print ( \"\u4f17\u6570:\" , Stats . mode ( test_numbers )) print ( \"\u5e73\u5747\u503c:\" , Stats . mean ( test_numbers )) 8\uff0e\u7f16\u5199\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u6d4f\u89c8\u6587\u4ef6\u91cc\u7684\u6587\u672c\u884c\u3002\u8fd9\u4e2a\u7a0b\u5e8f\u4f1a\u63d0\u793a\u7528\u6237\u8f93\u5165\u6587\u4ef6\u540d\uff0c\u7136\u540e\u628a\u6587\u672c\u884c\u90fd\u8f93\u5165\u5217\u8868\u3002\u63a5\u4e0b\u6765\uff0c\u8fd9\u4e2a\u7a0b\u5e8f\u4f1a\u8fdb\u5165\u4e00\u4e2a\u5faa\u73af\uff0c\u5728\u8fd9\u4e2a\u5faa\u73af\u91cc\u6253\u5370\u51fa\u6587\u4ef6\u7684\u603b\u884c\u6570\uff0c\u5e76\u63d0\u793a\u7528\u6237\u8f93\u5165\u884c\u53f7\u3002\u8fd9\u4e2a\u884c\u53f7\u7684\u8303\u56f4\u5e94\u5f53\u662f1\u5230\u6587\u4ef6\u7684\u603b\u884c\u6570\u3002\u5982\u679c\u8f93\u5165\u662f0\uff0c\u90a3\u4e48\u7a0b\u5e8f\u9000\u51fa\uff1b\u5426\u5219\uff0c\u7a0b\u5e8f\u5c06\u6253\u5370\u51fa\u884c\u53f7\u6240\u5bf9\u5e94\u7684\u6587\u672c\u884c\u3002 def read_file_lines ( filename ): try : with open ( filename , 'r' ) as file : lines = file . readlines () return lines except FileNotFoundError : print ( \"\u6587\u4ef6\u4e0d\u5b58\u5728\uff01\" ) return [] def main (): filename = input ( \"\u8bf7\u8f93\u5165\u6587\u4ef6\u540d\uff1a\" ) lines = read_file_lines ( filename ) if not lines : return total_lines = len ( lines ) while True : print ( f \"\u6587\u4ef6\u603b\u884c\u6570\uff1a { total_lines } \" ) try : line_number = int ( input ( \"\u8bf7\u8f93\u5165\u884c\u53f7\uff08\u8f93\u51650\u9000\u51fa\uff09\uff1a\" )) if line_number == 0 : break elif 1 <= line_number <= total_lines : print ( f \"\u884c\u53f7 { line_number } : { lines [ line_number - 1 ] . strip () } \" ) else : print ( \"\u65e0\u6548\u7684\u884c\u53f7\uff0c\u8bf7\u8f93\u5165\u6b63\u786e\u8303\u56f4\u5185\u7684\u884c\u53f7\uff01\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () class TextFileBrowser : @classmethod def read_file_lines ( cls , filename ): try : with open ( filename , 'r' ) as file : lines = file . readlines () return lines except FileNotFoundError : print ( \"\u6587\u4ef6\u4e0d\u5b58\u5728\uff01\" ) return [] @classmethod def browse_file ( cls , filename ): lines = cls . read_file_lines ( filename ) if not lines : return total_lines = len ( lines ) while True : print ( f \"\u6587\u4ef6\u603b\u884c\u6570\uff1a { total_lines } \" ) try : line_number = int ( input ( \"\u8bf7\u8f93\u5165\u884c\u53f7\uff08\u8f93\u51650\u9000\u51fa\uff09\uff1a\" )) if line_number == 0 : break elif 1 <= line_number <= total_lines : print ( f \"\u884c\u53f7 { line_number } : { lines [ line_number - 1 ] . strip () } \" ) else : print ( \"\u65e0\u6548\u7684\u884c\u53f7\uff0c\u8bf7\u8f93\u5165\u6b63\u786e\u8303\u56f4\u5185\u7684\u884c\u53f7\uff01\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) def main (): filename = input ( \"\u8bf7\u8f93\u5165\u6587\u4ef6\u540d\uff1a\" ) TextFileBrowser . browse_file ( filename ) if __name__ == \"__main__\" : main () 9\uff0e\u5728\u672c\u7ae0\u8ba8\u8bba\u7684numberguess\u7a0b\u5e8f\u91cc\uff0c\u8ba1\u7b97\u673a\u4f1a\u201c\u6784\u601d\u201d\u4e00\u4e2a\u6570\u5b57\uff0c\u800c\u7528\u6237\u5219\u8f93\u5165\u731c\u6d4b\u7684\u503c\uff0c\u76f4\u5230\u731c\u5bf9\u4e3a\u6b62\u3002\u7f16\u5199\u8fd9\u6837\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u4f7f\u5176\u53ef\u4ee5\u8c03\u6362\u8fd9\u4e24\u4e2a\u89d2\u8272\uff0c\u4e5f\u5c31\u662f\uff1a\u7528\u6237\u53bb\u201c\u6784\u601d\u201d\u4e00\u4e2a\u6570\u5b57\uff0c\u7136\u540e\u8ba1\u7b97\u673a\u53bb\u8ba1\u7b97\u5e76\u8f93\u51fa\u731c\u6d4b\u7684\u503c\u3002\u548c\u524d\u9762\u90a3\u4e2a\u6e38\u620f\u7248\u672c\u4e00\u6837\uff0c\u5f53\u8ba1\u7b97\u673a\u731c\u9519\u65f6\uff0c\u7528\u6237\u5fc5\u987b\u7ed9\u51fa\u76f8\u5e94\u7684\u63d0\u793a\uff0c\u4f8b\u5982\u201c<\u201d\u548c\u201c>\u201d\uff08\u5206\u522b\u4ee3\u8868\u201c\u6211\u7684\u6570\u5b57\u66f4\u5c0f\u201d\u548c\u201c\u6211\u7684\u6570\u5b57\u66f4\u5927\u201d\uff09\u3002\u5f53\u8ba1\u7b97\u673a\u731c\u5bf9\u65f6\uff0c\u7528\u6237\u5e94\u8be5\u8f93\u5165\u201c=\u201d\u3002\u7528\u6237\u9700\u8981\u5728\u7a0b\u5e8f\u542f\u52a8\u7684\u65f6\u5019\u8f93\u5165\u6570\u5b57\u7684\u4e0b\u9650\u548c\u4e0a\u9650\u3002\u8ba1\u7b97\u673a\u5e94\u8be5\u5728\u6700\u591a [log2(high\u2212low)+1] \u6b21\u731c\u6d4b\u91cc\u627e\u5230\u6b63\u786e\u7684\u6570\u5b57\u3002\u7a0b\u5e8f\u5e94\u8be5\u80fd\u591f\u8ddf\u8e2a\u731c\u6d4b\u6b21\u6570\uff0c\u5982\u679c\u731c\u6d4b\u9519\u8bef\u7684\u6b21\u6570\u5230\u4e86\u5141\u8bb8\u731c\u6d4b\u7684\u6700\u5927\u503c\u4f46\u8fd8\u6ca1\u6709\u731c\u5bf9\uff0c\u5c31\u8f93\u51fa\u6d88\u606f\u201cYou're cheating\uff01\u201d\u3002\u4e0b\u9762\u662f\u548c\u8fd9\u4e2a\u7a0b\u5e8f\u8fdb\u884c\u4ea4\u4e92\u7684\u793a\u4f8b\uff1a Enter the smaller number : 1 Enter the larger number : 100 Your number is 50 Enter = , < , or > : > Your number is 75 Enter = , < , or > : < Your number is 62 Enter = , < , or > : < Your number is 56 Enter = , < , or > : = Hooray , I 've got it in 4 tries! import math class ComputerGuesser : def __init__ ( self , lower_limit , upper_limit ): self . lower_limit = lower_limit self . upper_limit = upper_limit self . max_attempts = math . floor ( math . log2 ( upper_limit - lower_limit + 1 )) + 1 self . attempts = 0 def guess ( self ): return ( self . lower_limit + self . upper_limit ) // 2 def play ( self ): print ( f \"\u8bf7\u4f60\u9009\u62e9\u4e00\u4e2a\u5728 { self . lower_limit } \u5230 { self . upper_limit } \u4e4b\u95f4\u7684\u6570\u5b57\u3002\" ) while self . attempts < self . max_attempts : guess = self . guess () print ( f \"\u6211\u7684\u731c\u6d4b\u662f\uff1a { guess } \" ) response = input ( \"\u8bf7\u8f93\u5165 =, <, \u6216 > \u6765\u6307\u793a\u662f\u5426\u731c\u5bf9\uff1a\" ) self . attempts += 1 if response == '=' : print ( f \"\u6211\u5728\u7b2c { self . attempts } \u6b21\u731c\u5bf9\u4e86\uff01\" ) break elif response == '<' : self . upper_limit = guess - 1 elif response == '>' : self . lower_limit = guess + 1 else : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u64cd\u4f5c\u7b26\uff1a=, <, \u6216 >\" ) if self . attempts >= self . max_attempts : print ( \"\u4f60\u5728\u6b3a\u9a97\u6211\uff01\" ) def main (): lower_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5c0f\u7684\u6570\u5b57\uff1a\" )) upper_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5927\u7684\u6570\u5b57\uff1a\" )) guesser = ComputerGuesser ( lower_limit , upper_limit ) guesser . play () if __name__ == \"__main__\" : main () import math class ComputerGuesser : def __init__ ( self , lower_limit , upper_limit ): self . lower_limit = lower_limit self . upper_limit = upper_limit self . max_attempts = math . floor ( math . log2 ( upper_limit - lower_limit + 1 )) + 1 self . attempts = 0 @classmethod def guess ( cls , lower_limit , upper_limit ): return ( lower_limit + upper_limit ) // 2 @classmethod def play ( cls , lower_limit , upper_limit ): print ( f \"\u8bf7\u4f60\u9009\u62e9\u4e00\u4e2a\u5728 { lower_limit } \u5230 { upper_limit } \u4e4b\u95f4\u7684\u6570\u5b57\u3002\" ) attempts = 0 while attempts < cls . max_attempts : guess = cls . guess ( lower_limit , upper_limit ) print ( f \"\u6211\u7684\u731c\u6d4b\u662f\uff1a { guess } \" ) response = input ( \"\u8bf7\u8f93\u5165 =, <, \u6216 > \u6765\u6307\u793a\u662f\u5426\u731c\u5bf9\uff1a\" ) attempts += 1 if response == '=' : print ( f \"\u6211\u5728\u7b2c { attempts } \u6b21\u731c\u5bf9\u4e86\uff01\" ) break elif response == '<' : upper_limit = guess - 1 elif response == '>' : lower_limit = guess + 1 else : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u64cd\u4f5c\u7b26\uff1a=, <, \u6216 >\" ) if attempts >= cls . max_attempts : print ( \"\u4f60\u5728\u6b3a\u9a97\u6211\uff01\" ) def main (): lower_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5c0f\u7684\u6570\u5b57\uff1a\" )) upper_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5927\u7684\u6570\u5b57\uff1a\" )) ComputerGuesser . play ( lower_limit , upper_limit ) if __name__ == \"__main__\" : main () 10\uff0e\u6709\u4e00\u4e2a\u7b80\u5355\u7684\u8bfe\u7a0b\u7ba1\u7406\u7cfb\u7edf\uff0c\u5b83\u901a\u8fc7\u4f7f\u7528\u540d\u5b57\u548c\u4e00\u7ec4\u8003\u8bd5\u5206\u6570\u6765\u6a21\u62df\u5b66\u751f\u7684\u4fe1\u606f\u3002\u8fd9\u4e2a\u7cfb\u7edf\u5e94\u8be5\u80fd\u591f\u521b\u5efa\u4e00\u4e2a\u5177\u6709\u7ed9\u5b9a\u540d\u5b57\u548c\u5206\u6570\uff08\u8d77\u521d\u5747\u4e3a0\uff09\u7684\u5b66\u751f\u5bf9\u8c61\u3002\u7cfb\u7edf\u5e94\u8be5\u80fd\u591f\u8bbf\u95ee\u548c\u66ff\u6362\u6307\u5b9a\u4f4d\u7f6e\u5904\u7684\u5206\u6570\uff08\u4ece0\u5f00\u59cb\u8ba1\u6570\uff09\u3001\u5f97\u5230\u5b66\u751f\u6709\u591a\u5c11\u6b21\u8003\u8bd5\u3001\u5f97\u5230\u7684\u6700\u9ad8\u5206\u3001\u5f97\u5230\u7684\u5e73\u5747\u5206\u4ee5\u53ca\u5b66\u751f\u7684\u59d3\u540d\u3002\u9664\u6b64\u4e4b\u5916\uff0c\u5728\u6253\u5370\u5b66\u751f\u5bf9\u8c61\u7684\u65f6\u5019\uff0c\u5e94\u8be5\u50cf\u4e0b\u9762\u8fd9\u6837\u663e\u793a\u5b66\u751f\u7684\u59d3\u540d\u548c\u5206\u6570\uff1a Name : Ken Lambert Score 1 : 88 Score 2 : 77 Score 3 : 100 \u8bf7\u5b9a\u4e49\u4e00\u4e2a\u652f\u6301\u8fd9\u4e9b\u529f\u80fd\u548c\u884c\u4e3a\u7684Student\u7c7b\uff0c\u5e76\u4e14\u7f16\u5199\u4e00\u4e2a\u521b\u5efaStudent\u5bf9\u8c61\u5e76\u8fd0\u884c\u5176\u65b9\u6cd5\u7684\u7b80\u77ed\u7684\u6d4b\u8bd5\u51fd\u6570\u3002 class Student : def __init__ ( self , name ): self . name = name self . scores = [] def add_score ( self , score ): self . scores . append ( score ) def replace_score ( self , index , score ): if 0 <= index < len ( self . scores ): self . scores [ index ] = score else : print ( \"\u65e0\u6548\u7684\u5206\u6570\u7d22\u5f15\" ) def num_scores ( self ): return len ( self . scores ) def highest_score ( self ): if self . scores : return max ( self . scores ) else : return None def average_score ( self ): if self . scores : return sum ( self . scores ) / len ( self . scores ) else : return None def display ( self ): print ( f \"Name: { self . name } \" ) for i , score in enumerate ( self . scores , start = 1 ): print ( f \"Score { i } : { score } \" ) def test_student_class (): student = Student ( \"Ken Lambert\" ) student . add_score ( 88 ) student . add_score ( 77 ) student . add_score ( 100 ) student . display () print ( f \"Total Scores: { student . num_scores () } \" ) print ( f \"Highest Score: { student . highest_score () } \" ) print ( f \"Average Score: { student . average_score () } \" ) if __name__ == \"__main__\" : test_student_class ()","title":"1.9.\u7f16\u7a0b\u7ec3\u4e60"},{"location":"python/DataStructure/02_CollectionsOverview/","text":"2.\u591a\u9879\u96c6\u7684\u6982\u8ff0 \u00b6 \u591a\u9879\u96c6\uff08collection\uff09\u662f\u6307\u7531 0 \u4e2a\u6216\u8005\u591a\u4e2a\u5143\u7d20\u7ec4\u6210\u7684\u6982\u5ff5\u5355\u5143\u3002 \u4ece\u4e24\u4e2a\u89d2\u5ea6\u770b\u5f85\u591a\u9879\u96c6\uff1a \u591a\u9879\u96c6\u7684\u7528\u6237\u6216\u8005\u5ba2\u6237\u4f1a\u5173\u5fc3\u5b83\u4eec\u5728\u4e0d\u540c\u7684\u5e94\u7528\u7a0b\u5e8f\u91cc\u80fd\u505a\u4e9b\u4ec0\u4e48\u3002 \u591a\u9879\u96c6\u7684\u5f00\u53d1\u8005\u6216\u8005\u5b9e\u73b0\u8005\u5219\u4f1a\u5173\u5fc3\u5982\u4f55\u624d\u80fd\u8ba9\u5b83\u4eec\u6210\u4e3a\u6700\u597d\u7684\u901a\u7528\u8d44\u6e90\u4ee5\u88ab\u4f7f\u7528\u3002 \u76ee\u6807\uff1a \u5b9a\u4e49\u591a\u9879\u96c6\u76844\u4e2a\u901a\u7528\u7c7b\u578b\uff1a \u7ebf\u6027\u591a\u9879\u96c6 \u5206\u5c42\u591a\u9879\u96c6 \u56fe\u591a\u9879\u96c6 \u65e0\u5e8f\u591a\u9879\u96c6 \u4e86\u89e34\u4e2a\u591a\u9879\u96c6\u7c7b\u578b\u4e2d\u7684\u7279\u5b9a\u7c7b\u578b\uff1b \u4e86\u89e3\u8fd9\u4e9b\u591a\u9879\u96c6\u9002\u5408\u7528\u5728\u4ec0\u4e48\u7c7b\u578b\u7684\u5e94\u7528\u7a0b\u5e8f\u91cc\uff1b \u63cf\u8ff0\u6bcf\u79cd\u591a\u9879\u96c6\u7c7b\u578b\u7684\u5e38\u7528\u64cd\u4f5c\uff1b \u63cf\u8ff0\u591a\u9879\u96c6\u7684\u62bd\u8c61\u7c7b\u578b\u548c\u5b9e\u73b0\u4e4b\u95f4\u7684\u533a\u522b\uff1b 2.1.\u591a\u9879\u96c6\u7c7b\u578b \u00b6 \u5185\u7f6e\u591a\u9879\u96c6\u7c7b\u578b\uff1a \u5b57\u7b26\u4e32 str \u5217\u8868 list \u5143\u7ec4 tuple \u96c6\u5408 set \u5b57\u5178 dict \u5176\u4ed6\u591a\u9879\u96c6\u7c7b\u578b\uff1a \u6808 \u961f\u5217 \u4f18\u5148\u961f\u5217 \u4e8c\u53c9\u67e5\u627e\u6811 \u5806 \u56fe \u5305 \u6709\u5e8f\u591a\u9879\u96c6 \u591a\u9879\u96c6\u901a\u5e38\u4e0d\u662f\u9759\u6001\uff08static\uff09\u7684\uff0c\u800c\u662f\u52a8\u6001\uff08dynamic\uff09\u7684\uff0c\u53ef\u4ee5\u6839\u636e\u9700\u8981\u6765\u6269\u5927\u6216\u8005\u7f29\u5c0f\u591a\u9879\u96c6\u3002 \u4e0d\u53ef\u53d8\u591a\u9879\u96c6\uff08immutable collection\uff09\u7684\u5185\u5bb9\u5728\u7a0b\u5e8f\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u662f\u4e0d\u53ef\u6539\u53d8\u7684\uff08\u5143\u7d20\u4e0d\u53ef\u4ee5\u6dfb\u52a0\u3001\u5220\u9664\u6216\u8005\u66ff\u6362\uff09\uff0c\u6bd4\u5982\u5143\u7ec4tuple\u3002 \u53ef\u53d8\u591a\u9879\u96c6\uff08mutable collection\uff09\u91cc\u7684\u5185\u5bb9\u53ef\u4ee5\u5728\u7a0b\u5e8f\u7684\u6574\u4e2a\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u88ab\u6539\u53d8\uff0c\u6bd4\u5982\u5b57\u7b26\u4e32\u3001\u5217\u8868list\u3002 \u591a\u9879\u96c6\u6309\u6784\u6210\u65b9\u5f0f\u5212\u5206\u7684\u7c7b\u578b\uff1a \u7ebf\u6027\u591a\u9879\u96c6 \u5206\u5c42\u591a\u9879\u96c6 \u56fe\u591a\u9879\u96c6 \u65e0\u5e8f\u591a\u9879\u96c6 \u6709\u5e8f\u591a\u9879\u96c6 2.1.1.\u7ebf\u6027\u591a\u9879\u96c6 \u00b6 \u7ebf\u6027\u591a\u9879\u96c6\uff08linear collection\uff09\u91cc\u7684\u5143\u7d20\u6309\u7167\u4f4d\u7f6e\u8fdb\u884c\u6392\u5217\u3002 \u9664\u4e86\u7b2c\u4e00\u4e2a\u5143\u7d20\uff0c\u5176\u4ed6\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\uff1b \u9664\u4e86\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff0c\u5176\u4ed6\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u540e\u5e8f\uff1b \u5b9e\u4f8b\uff1a\u6392\u961f\u7684\u4eba\uff0c\u8d2d\u7269\u6e05\u5355\uff0c\u5806\u53e0\u5728\u4e00\u8d77\u7684\u9910\u76d8\u7b49\u3002 2.1.2.\u5206\u5c42\u591a\u9879\u96c6 \u00b6 \u5206\u5c42\u591a\u9879\u96c6\uff08hierarchical collection\uff09\u91cc\u7684\u6570\u636e\u5143\u7d20\u4f1a\u4ee5\u7c7b\u4f3c\u4e8e\u5012\u7f6e\u7684\u6811\u7ed3\u6784\u8fdb\u884c\u6392\u5217\u3002\u9664\u4e86\u9876\u90e8\u7684\u6570\u636e\u5143\u7d20\uff0c\u5176\u4ed6\u6bcf\u4e2a\u6570\u636e\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\uff0c\u88ab\u79f0\u4e3a\u7236\u5143\u7d20\uff08parent\uff09\uff0c\u4f46\u5b83\u4eec\u53ef\u4ee5\u6709\u8bb8\u591a\u7684\u540e\u5e8f\uff0c\u88ab\u79f0\u4e3a\u5b50\u5143\u7d20\uff08children\uff09\u3002 \u56fe\u4f8b\u4e2d\uff0c D3 \u7684\u524d\u5e8f\u7236\u5143\u7d20\u662f D1 \uff0c D3 \u7684\u540e\u7eed\u5b50\u5143\u7d20\u662f D4 \u3001 D5 \u3001 D6 \u3002 \u5b9e\u4f8b\uff1a\u6587\u4ef6\u76ee\u5f55\u7cfb\u7edf\u3001\u516c\u53f8\u7684\u7ec4\u7ec7\u67b6\u6784\u3001\u4e66\u7684\u76ee\u5f55\u7b49\u3002 2.1.3.\u56fe\u591a\u9879\u96c6 \u00b6 \u56fe\u591a\u9879\u96c6\uff08graph collection\uff09\u4e5f\u88ab\u79f0\u4e3a\u56fe\uff08graph\uff09\uff0c\u5b83\u662f\u8fd9\u6837\u4e00\u4e2a\u591a\u9879\u96c6\uff1a\u5b83\u7684\u6bcf\u4e00\u4e2a\u6570\u636e\u5143\u7d20\u90fd\u53ef\u4ee5\u6709\u591a\u4e2a\u524d\u5e8f\u548c\u591a\u4e2a\u540e\u5e8f\u3002 \u56fe\u4f8b\u4e2d\uff0c\u8fde\u63a5\u5230 D3 \u7684\u6240\u6709\u5143\u7d20\u4f1a\u88ab\u5f53\u4f5c\u5b83\u7684\u524d\u5e8f\u548c\u540e\u5e8f\uff0c\u5b83\u4eec\u4e5f\u56e0\u6b64\u88ab\u79f0\u4e3a D3 \u7684\u90bb\u5c45\u3002 \u5b9e\u4f8b\uff1a\u57ce\u5e02\u4e4b\u95f4\u7684\u822a\u7ebf\u56fe\u3001\u4e07\u7ef4\u7f51\u7b49\u3002 2.1.4.\u65e0\u5e8f\u591a\u9879\u96c6 \u00b6 \u65e0\u5e8f\u591a\u9879\u96c6\uff08unordered collection\uff09\u91cc\u7684\u5143\u7d20\u6ca1\u6709\u7279\u5b9a\u7684\u987a\u5e8f\uff0c\u5e76\u4e14\u4e0d\u4f1a\u7528\u4efb\u4f55\u660e\u786e\u7684\u65b9\u5f0f\u6765\u6307\u51fa\u5143\u7d20\u7684\u524d\u5e8f\u6216\u8005\u540e\u5e8f\u3002 \u5b9e\u4f8b\uff1a\u4e00\u888b\u5f39\u73e0\u7b49\u3002 2.1.5.\u6709\u5e8f\u591a\u9879\u96c6 \u00b6 \u6709\u5e8f\u591a\u9879\u96c6\uff08sorted collection\uff09\u4f1a\u5bf9\u5b83\u91cc\u9762\u7684\u5143\u7d20\u8fdb\u884c\u81ea\u7136\u6392\u5e8f\uff08natural ordering\uff09\u3002 \u8981\u8fdb\u884c\u81ea\u7136\u6392\u5e8f\uff0c\u5c31\u5fc5\u987b\u8981\u6709\u89c4\u5219\u6765\u5bf9\u6709\u5e8f\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u52a0\u4ee5\u6bd4\u8f83\uff0c\u4f8b\u5982 item(i) <= item(i+1) \u8fd9\u6837\u7684\u2014\u2014\u89c4\u5219\u3002 \u6709\u5e8f\u5217\u8868\u662f\u6700\u5e38\u89c1\u7684\u6709\u5e8f\u591a\u9879\u96c6\u3002\u6709\u5e8f\u591a\u9879\u96c6\u4e0d\u4e00\u5b9a\u662f\u7ebf\u6027\u7684\u6216\u8005\u6309\u7167\u4f4d\u7f6e\u8fdb\u884c\u6392\u5e8f\u7684\u3002 \u5bf9\u4e8e\u96c6\u5408\u3001\u5305\u3001\u5b57\u5178\uff0c\u867d\u7136\u4e0d\u80fd\u6309\u7167\u4f4d\u7f6e\u6765\u8bbf\u95ee\u5b83\u4eec\u7684\u5143\u7d20\uff0c\u4f46\u5b83\u4eec\u90fd\u53ef\u4ee5\u662f\u6709\u5e8f\u7684\u3002 \u7279\u6b8a\u7684\u5206\u5c42\u591a\u9879\u96c6\u7c7b\u578b\uff08\u5982\u4e8c\u53c9\u67e5\u627e\u6811\uff09\u4e5f\u4f1a\u5bf9\u5176\u4e2d\u7684\u5143\u7d20\u8fdb\u884c\u81ea\u7136\u6392\u5e8f\u3002 2.1.6.\u591a\u9879\u96c6\u7c7b\u578b\u7684\u5206\u7c7b \u00b6 \u4e0b\u9762\u5206\u7c7b\u91cc\u7684\u7c7b\u578b\u540d\u79f0\u6307\u7684\u5e76\u4e0d\u662f\u591a\u9879\u96c6\u7684\u7279\u5b9a\u5b9e\u73b0\u3002\u4e00\u79cd\u7279\u5b9a\u7c7b\u578b\u7684\u591a\u9879\u96c6\u53ef\u4ee5\u6709\u591a\u4e2a\u5b9e\u73b0\u3002 \u591a\u9879\u96c6 | ---\u56fe\u591a\u9879\u96c6 | ---\u5206\u5c42\u591a\u9879\u96c6 | | ---\u4e8c\u53c9\u67e5\u627e\u6811 | | ---\u5806 | ---\u7ebf\u6027\u591a\u9879\u96c6 | | ---\u5217\u8868 | | | ---\u6709\u5e8f\u5217\u8868 | | ---\u961f\u5217 | | | ---\u4f18\u5148\u5bf9\u5217 | | ---\u6808 | | ---\u5b57\u7b26\u4e32 | ---\u65e0\u5e8f\u591a\u9879\u96c6 | ---\u5305 | | ---\u6709\u5e8f\u5305 | ---\u5b57\u5178 | | ---\u6709\u5e8f\u5305 | ---\u96c6\u5408 | ---\u6709\u5e8f\u96c6\u5408 2.2.\u591a\u9879\u96c6\u64cd\u4f5c \u00b6 \u591a\u9879\u96c6\u64cd\u4f5c\u7c7b\u522b\uff1a \u786e\u5b9a\u5927\u5c0f\uff1a\u4f7f\u7528 len \u51fd\u6570\u83b7\u53d6\u5f53\u524d\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u6570\u91cf\u3002 \u68c0\u6d4b\u5143\u7d20\u6210\u5458\uff1a\u4f7f\u7528 in \u8fd0\u7b97\u7b26\u5728\u591a\u9879\u96c6\u91cc\u641c\u7d22\u6307\u5b9a\u7684\u76ee\u6807\u5143\u7d20\u3002\u5982\u679c\u627e\u5230\u4e86\u8fd9\u4e2a\u5143\u7d20\uff0c\u5219\u8fd4\u56deTrue\uff0c\u5426\u5219\u8fd4\u56deFalse\u3002 \u904d\u5386\u591a\u9879\u96c6\uff1a\u4f7f\u7528 for \u5faa\u73af\u8bbf\u95ee\u591a\u9879\u96c6\u91cc\u7684\u6b38\u4e00\u4e2a\u5143\u7d20\u3002\u5143\u7d20\u7684\u8bbf\u95ee\u987a\u5e8f\u53d6\u51b3\u4e8e\u591a\u9879\u96c6\u7684\u7c7b\u578b\u3002 \u83b7\u53d6\u591a\u9879\u96c6\u7684\u5b57\u7b26\u4e32\u8868\u793a\uff1a\u4f7f\u7528 str \u51fd\u6570\u83b7\u53d6\u591a\u9879\u96c6\u7684\u5b57\u7b26\u4e32\u8868\u793a\u3002 \u76f8\u7b49\u68c0\u6d4b\uff1a\u4f7f\u7528 == \u8fd0\u7b97\u7b26\u6765\u786e\u5b9a\u4e24\u4e2a\u591a\u9879\u96c6\u662f\u5426\u76f8\u7b49\u3002\u5982\u679c\u4e24\u4e2a\u591a\u9879\u96c6\u80b2\u6709\u76f8\u540c\u7684\u7c7b\u578b\uff0c\u5e76\u4e14\u5305\u542b\u76f8\u540c\u7684\u5143\u7d20\uff0c\u90a3\u4e48\u5b83\u4eec\u5c31\u662f\u76f8\u7b49\u7684\u3002\u6bd4\u8f83\u8fd9\u4e9b\u5143\u7d20\u5bf9\u7684\u987a\u5e8f\u53d6\u51b3\u4e8e\u591a\u9879\u96c6\u7684\u7c7b\u578b\u3002 \u8fde\u63a5\u4e24\u4e2a\u591a\u9879\u96c6\uff1a\u4f7f\u7528 + \u8fd0\u7b97\u7b26\u6765\u5f97\u5230\u4e00\u4e2a\u548c\u64cd\u4f5c\u6570\u76f8\u540c\u7c7b\u578b\u7684\u65b0\u591a\u9879\u96c6\uff0c\u5e76\u4e14\u5305\u542b\u4e24\u4e2a\u64cd\u4f5c\u6570\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002 \u8f6c\u6362\u4e3a\u5176\u4ed6\u7c7b\u578b\u7684\u591a\u9879\u96c6\uff1a\u521b\u5efa\u4e00\u4e2a\u4e0e\u6e90\u591a\u9879\u96c6\u5177\u6709\u76f8\u540c\u5143\u7d20\u7684\u65b0\u591a\u9879\u96c6\u3002\u514b\u9686\u64cd\u4f5c\u65f6\u7c7b\u578b\u8f6c\u6362\u7684\u4e00\u79cd\u7279\u6b8a\u60c5\u51b5\uff0c\u56e0\u4e3a\u8f93\u5165\u8f93\u51fa\u7684\u4e24\u4e2a\u591a\u9879\u96c6\u5177\u6709\u76f8\u540c\u7c7b\u578b\u3002 \u63d2\u5165\u4e00\u4e2a\u5143\u7d20\uff1a\u5982\u679c\u53ef\u4ee5\uff0c\u5219\u5728\u7ed9\u5b9a\u7684\u4f4d\u7f6e\u5c06\u5bf9\u5e94\u7684\u5143\u7d20\u6dfb\u52a0\u5230\u591a\u9879\u96c6\u91cc\u3002 \u5220\u9664\u4e00\u4e2a\u5143\u7d20\uff1a\u5982\u679c\u53ef\u4ee5\uff0c\u5219\u5728\u7ed9\u5b9a\u7684\u4f4d\u7f6e\u5c06\u5bf9\u5e94\u7684\u5143\u7d20\u4ece\u591a\u9879\u96c6\u4e2d\u5220\u9664\u3002 \u66ff\u6362\u4e00\u4e2a\u5143\u7d20\uff1a\u5c06\u5220\u9664\u548c\u63d2\u5165\u5408\u5e76\u4e3a\u4e00\u9879\u64cd\u4f5c\u3002 \u8bbf\u95ee\u6216\u8005\u83b7\u53d6\u5143\u7d20\uff1a\u5982\u679c\u800c\u5df2\uff0c\u5219\u5728\u7ed9\u5b9a\u7684\u4f4d\u7f6e\u83b7\u53d6\u5143\u7d20\u3002 2.2.1.\u6240\u6709\u591a\u9879\u96c6\u7c7b\u578b\u4e2d\u7684\u57fa\u672c\u64cd\u4f5c \u00b6 \u5728Python\u91cc\uff0c\u4e0d\u540c\u591a\u9879\u96c6\u7c7b\u578b\u7684\u63d2\u5165\u3001\u5220\u9664\u3001\u66ff\u6362\u6216\u8005\u8bbf\u95ee\u64cd\u4f5c\u5e76\u6ca1\u6709\u7edf\u4e00\u7684\u540d\u79f0\uff0c\u4f46\u662f\u4f1a\u6709\u4e00\u4e9b\u6807\u51c6\u53d8\u4f53\u3002\u6bd4\u5982\uff0c \u65b9\u6cd5pop\u4f1a\u88ab\u7528\u6765\u4ece\u5217\u8868\u91cc\u79fb\u9664\u6307\u5b9a\u4f4d\u7f6e\u7684\u5143\u7d20\uff1b \u65b9\u6cd5pop\u4f1a\u88ab\u7528\u6765\u4ece\u5b57\u5178\u91cc\u79fb\u9664\u7ed9\u5b9a\u952e\u6240\u5bf9\u5e94\u7684\u503c\uff1b \u65b9\u6cd5remove\u4f1a\u88ab\u7528\u6765\u4ece\u5217\u8868\u6216\u8005\u67d0\u4e9b\u591a\u9879\u96c6\u91cc\u5220\u9664\u6307\u5b9a\u7684\u5143\u7d20\uff1b \u5bf9\u4e8e\u65b0\u5f00\u53d1\u51fa\u7684\u3001Python\u5c1a\u4e0d\u652f\u6301\u7684\u591a\u9879\u96c6\u7c7b\u578b\uff0c\u5c3d\u53ef\u80fd\u5730\u4f7f\u7528\u6807\u51c6\u7684\u8fd0\u7b97\u7b26\u3001\u51fd\u6570\u4ee5\u53ca\u65b9\u6cd5\u540d\u79f0\u5bf9\u5b83\u4eec\u8fdb\u884c\u64cd\u4f5c\u3002 2.2.2.\u7c7b\u578b\u8f6c\u6362 \u00b6 \u7c7b\u578b\u8f6c\u6362\uff0c\u5c06\u4e00\u79cd\u7c7b\u578b\u7684\u591a\u9879\u96c6\u8f6c\u6362\u4e3a\u53e6\u4e00\u79cd\u7c7b\u578b\u7684\u591a\u9879\u96c6\u3002\u4f8b\u5982\uff0c\u901a\u8fc7 list \u6216 tuple \u51fd\u6570\u5c06\u5b57\u7b26\u4e32\u8f6c\u6362\u4e3a\u5217\u8868\u6216\u8005\u5143\u7ec4\u3002 list \u6216 tuple \u51fd\u6570\u7684\u53c2\u6570\u4e0d\u4e00\u5b9a\u662f\u53e6\u4e00\u4e2a\u591a\u9879\u96c6\uff0c\u4e5f\u53ef\u4ee5\u662f\u4efb\u4f55\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08iterable object\uff09\u3002 \u53ef\u8fed\u4ee3\u5bf9\u8c61\u662f\u6307\uff0c\u80fd\u591f\u4f7f\u7528for\u5faa\u73af\u6765\u8bbf\u95ee\u7684\u4e00\u7cfb\u5217\u5143\u7d20\u3002\uff08\u591a\u9879\u96c6\u672c\u8eab\u4e5f\u662f\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff09 2.2.3.\u514b\u9686\u548c\u76f8\u7b49\u6027 \u00b6 \u7c7b\u578b\u8f6c\u6362\u7684\u4e00\u79cd\u7279\u6b8a\u60c5\u51b5\u662f\u514b\u9686\uff0c\u5b83\u7684\u529f\u80fd\u662f\u8fd4\u56de\u8f6c\u6362\u51fd\u6570\u4e2d\u53c2\u6570\u7684\u5b8c\u6574\u526f\u672c\u3002 \u4f8b\u5982\uff1a myList1 = [ 2 , 4 , 8 ] myList2 = list ( myList1 ) myList1 is myList2 # False myList1 == myList2 # True \u6ce8\u610f\uff1a \u4e0a\u9762\u4e24\u4e2a\u5217\u8868\u4e0d\u4ec5\u6709\u76f8\u540c\u7684\u7ed3\u6784\uff0c\u5b83\u4eec\u8fd8\u6709\u76f8\u540c\u7684\u5143\u7d20\uff0c\u6bcf\u5bf9\u5143\u7d20\u5728\u4e24\u4e2a\u5217\u8868\u91cc\u7684\u4f4d\u7f6e\u90fd\u76f8\u540c\u3002\u4f46\u662f\uff0c\u4ed6\u4eec\u662f\u4e24\u4e2a\u4e0d\u540c\u7684\u5bf9\u8c61\u3002 \u4e0a\u4f8b\u4e2d list \u51fd\u6570\u5bf9\u5b83\u7684\u53c2\u6570\u5217\u8868\u8fdb\u884c\u6d45\u62f7\u8d1d\uff08shallow copy\uff09\u3002\u8fd9\u4e9b\u5143\u7d20\u7684\u672c\u8eab\u5728\u6dfb\u52a0\u5230\u65b0\u5217\u8868\u4e4b\u524d\u662f\u4e0d\u4f1a\u88ab\u514b\u9686\u7684\uff0c\u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e2d\u53ea\u4f1a\u590d\u5236\u5bf9\u8fd9\u4e9b\u5bf9\u8c61\u7684\u5f15\u7528\u3002\u5f53\u5143\u7d20\uff08\u6570\u5b57\u3001\u5b57\u7b26\u4e32\u6216\u8005Python\u7684\u5143\u7ec4\uff09\u4e0d\u53ef\u53d8\u65f6\uff0c\u8fd9\u4e2a\u7b56\u7565\u4e0d\u4f1a\u5f15\u8d77\u95ee\u9898\u3002\u4f46\u662f\uff0c\u5982\u679c\u591a\u9879\u96c6\u5305\u542b\u7684\u662f\u53ef\u53d8\u5143\u7d20\uff0c\u5c31\u53ef\u80fd\u4f1a\u4ea7\u751f\u526f\u4f5c\u7528\u3002\u4e3a\u4e86\u907f\u514d\u8fd9\u79cd\u60c5\u51b5\u7684\u53d1\u751f\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u5bf9\u6e90\u591a\u9879\u96c6\u7f16\u5199 for \u5faa\u73af\u6765\u521b\u5efa\u6df1\u62f7\u8d1d\uff08deep copy\uff09\uff0c\u8fd9\u4f1a\u628a\u5143\u7d20\u663e\u5f0f\u5730\u514b\u9686\u4e4b\u540e\u518d\u6dfb\u52a0\u5230\u65b0\u7684\u591a\u9879\u96c6\u91cc\u3002 2.3.\u8fed\u4ee3\u5668\u548c\u9ad8\u9636\u51fd\u6570 \u00b6 \u6bcf\u79cd\u7c7b\u578b\u7684\u591a\u9879\u96c6\u90fd\u652f\u6301\u4e00\u4e2a\u8fed\u4ee3\u5668\u6216 for \u5faa\u73af\uff0c\u8fd9\u4e2a\u64cd\u4f5c\u80fd\u591f\u8fed\u4ee3\u8fd9\u4e2a\u591a\u9879\u96c6\u7684\u6240\u6709\u5143\u7d20\u3002\u8fed\u4ee3\u5668\u662f\u591a\u9879\u96c6\u63d0\u4f9b\u7684\u6700\u5173\u952e\u7684\u64cd\u4f5c\u3002 for \u5faa\u73af\u670d\u52a1\u7684\u591a\u9879\u96c6\u4e2d\u5143\u7d20\u7684\u987a\u5e8f\u53d6\u51b3\u4e8e\u591a\u9879\u96c6\u7684\u7ec4\u7ec7\u65b9\u5f0f\u3002\u4f8b\u5982\uff1a \u5217\u8868\u91cc\u7684\u5143\u7d20\u4f1a\u4ece\u5934\u5230\u5c3e\u6309\u7167\u4f4d\u7f6e\u8fdb\u884c\u8bbf\u95ee\uff1b \u6709\u5e8f\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u4f1a\u6309\u4ece\u5c0f\u5230\u5927\u7684\u5347\u5e8f\u8fdb\u884c\u8bbf\u95ee\uff1b \u5bf9\u4e8e\u96c6\u5408\u6216\u8005\u5b57\u5178\u91cc\u7684\u5143\u7d20\u6765\u8bf4\uff0c\u4e0d\u4f1a\u6309\u7167\u7279\u5b9a\u7684\u987a\u5e8f\u8fdb\u884c\u8bbf\u95ee\u3002 \u8fed\u4ee3\u5668\uff08\u4f8b\u5982 for \u5faa\u73af\uff09\u8fd8\u652f\u6301\u4f7f\u7528\u9ad8\u9636\u51fd\u6570 map \u3001 filter \u548c reduce \u3002 \u8fd9\u4e9b\u9ad8\u9636\u51fd\u6570\u90fd\u4f7f\u7528\u53e6\u4e00\u4e2a\u51fd\u6570\u548c\u4e00\u4e2a\u591a\u9879\u96c6\u4f5c\u4e3a\u53c2\u6570\u3002 \u591a\u9879\u96c6\u90fd\u652f\u6301 for \u5faa\u73af\uff0c\u6240\u4ee5 map \u3001 filter \u548c reduce \u51fd\u6570\u53ef\u4ee5\u4e0e\u4efb\u4f55\u7c7b\u578b\u7684\u591a\u9879\u96c6\u4e00\u8d77\u4f7f\u7528\u3002 2.4.\u591a\u9879\u96c6\u7684\u5b9e\u73b0 \u00b6 \u4ece\u7528\u6237\uff08\u6bd4\u5982\uff0c\u7a0b\u5e8f\u5458\uff09\u7684\u89d2\u5ea6\u6765\u770b\uff0c\u591a\u9879\u96c6\u662f\u4e00\u79cd\u62bd\u8c61\uff0c\u662f\u4e00\u79cd\u4ee5\u67d0\u79cd\u9884\u5b9a\u884c\u4e3a\u6765\u5b58\u50a8\u548c\u8bbf\u95ee\u6570\u636e\u5143\u7d20\u7684\u65b9\u5f0f\uff0c\u5e76\u4e0d\u9700\u8981\u5173\u5fc3\u591a\u9879\u96c6\u5b9e\u73b0\u7684\u7ec6\u8282\u3002 \u591a\u9879\u96c6\u4e5f\u88ab\u79f0\u4e3a\u62bd\u8c61\u6570\u636e\u7c7b\u578b\uff08Abstract Data Type\uff0cADT\uff09\u3002\u62bd\u8c61\u6570\u636e\u7c7b\u578b\u7684\u7528\u6237\u53ea\u5173\u6ce8\u5b83\u7684\u63a5\u53e3\u4ee5\u53ca\u8fd9\u4e2a\u7c7b\u578b\u5bf9\u8c61\u6240\u63d0\u4f9b\u7684\u4e00\u7ec4\u64cd\u4f5c\u3002 \u5728Python\u91cc\uff0c\u51fd\u6570\u548c\u65b9\u6cd5\u662f\u6700\u5c0f\u7684\u62bd\u8c61\u5355\u5143\uff0c\u7c7b\u7684\u5927\u5c0f\u6b21\u4e4b\uff0c\u6a21\u5757\u662f\u6700\u5927\u7684\u62bd\u8c61\u5355\u5143\u3002 \u8fd9\u91cc\u4f1a\u628a\u62bd\u8c61\u591a\u9879\u96c6\u7c7b\u578b\u7684\u5b9e\u73b0\u5f53\u4f5c\u6a21\u5757\u91cc\u7684\u7c7b\u6216\u8005\u4e00\u7ec4\u76f8\u5173\u7684\u7c7b\u52a0\u4ee5\u63cf\u8ff0\u3002\u6784\u5efa\u8fd9\u4e9b\u7c7b\u5c31\u662f\u9762\u5411\u5bf9\u8c61\u7f16\u7a0b\u3002 2.5.\u5c0f\u7ed3 \u00b6 \u591a\u9879\u96c6\u662f\u5305\u542b0\u4e2a\u6216\u591a\u4e2a\u5176\u4ed6\u5bf9\u8c61\u7684\u5bf9\u8c61\u3002\u591a\u9879\u96c6\u53ef\u4ee5\u8fdb\u884c\u7684\u64cd\u4f5c\u6709\u8bbf\u95ee\u5bf9\u8c61\u3001\u63d2\u5165\u5bf9\u8c61\u3001\u5220\u9664\u5bf9\u8c61\u3001\u786e\u5b9a\u591a\u9879\u96c6\u7684\u5927\u5c0f\uff0c\u4ee5\u53ca\u904d\u5386\u6216\u8bbf\u95ee\u8fd9\u4e2a\u591a\u9879\u96c6\u7684\u5bf9\u8c61\u3002 \u591a\u9879\u96c6\u76845\u4e2a\u4e3b\u8981\u7c7b\u578b\u662f\uff1a\u7ebf\u6027\u591a\u9879\u96c6\u3001\u5206\u5c42\u591a\u9879\u96c6\u3001\u56fe\u591a\u9879\u96c6\u3001\u65e0\u5e8f\u591a\u9879\u96c6\u548c\u6709\u5e8f\u591a\u9879\u96c6\u3002 \u7ebf\u6027\u591a\u9879\u96c6\u4f1a\u6309\u7167\u4f4d\u7f6e\u5bf9\u5143\u7d20\u8fdb\u884c\u6392\u5e8f\uff0c\u5176\u4e2d\u9664\u4e86\u7b2c\u4e00\u4e2a\u5143\u7d20\uff0c\u6bcf\u4e2a\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\uff1b\u9664\u4e86\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff0c\u6bcf\u4e2a\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u540e\u5e8f\u3002 \u5728\u5206\u5c42\u591a\u9879\u96c6\u91cc\uff0c\u9664\u4e86\u4e00\u4e2a\u5143\u7d20\uff0c\u5176\u4ed6\u6240\u6709\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\u4ee5\u53ca0\u4e2a\u6216\u591a\u4e2a\u540e\u5e8f\u3002\u88ab\u79f0\u4e3a\u6839\u7684\u90a3\u4e2a\u989d\u5916\u5143\u7d20\u6ca1\u6709\u524d\u5e8f\u3002 \u56fe\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u53ef\u4ee5\u67090\u4e2a\u6216\u591a\u4e2a\u524d\u5e8f\u4ee5\u53ca0\u4e2a\u6216\u591a\u4e2a\u540e\u5e8f\u3002 \u65e0\u5e8f\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u6ca1\u6709\u7279\u5b9a\u7684\u987a\u5e8f\u3002 \u591a\u9879\u96c6\u662f\u53ef\u8fed\u4ee3\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\uff0c\u53ef\u4ee5\u4f7f\u7528for\u5faa\u73af\u8bbf\u95ee\u591a\u9879\u96c6\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u7a0b\u5e8f\u5458\u4e5f\u53ef\u4ee5\u4f7f\u7528\u9ad8\u9636\u51fd\u6570map\u3001filter\u548creduce\u7b80\u5316\u591a\u9879\u96c6\u7684\u6570\u636e\u5904\u7406\u3002 \u62bd\u8c61\u6570\u636e\u7c7b\u578b\u662f\u4e00\u7ec4\u5bf9\u8c61\u548c\u5bf9\u8fd9\u4e9b\u5bf9\u8c61\u7684\u64cd\u4f5c\u3002\u56e0\u6b64\uff0c\u591a\u9879\u96c6\u662f\u62bd\u8c61\u6570\u636e\u7c7b\u578b\u3002 \u6570\u636e\u7ed3\u6784\u662f\u4e00\u4e2a\u8868\u793a\u591a\u9879\u96c6\u91cc\u5305\u542b\u7684\u6570\u636e\u7684\u5bf9\u8c61\u3002 2.6.\u590d\u4e60\u9898 \u00b6 \u7ebf\u6027\u591a\u9879\u96c6\u7684\u4e00\u4e2a\u4f8b\u5b50\u662f\uff1a \u96c6\u5408\u548c\u6811 \u5217\u8868\u548c\u6808 \u65e0\u5e8f\u591a\u9879\u96c6\u7684\u4e00\u4e2a\u4f8b\u5b50\u662f\uff1a \u961f\u5217\u548c\u5217\u8868 \u96c6\u5408\u548c\u5b57\u5178 \u5206\u5c42\u591a\u9879\u96c6\u53ef\u4ee5\u7528\u6765\u8868\u793a\uff1a \u94f6\u884c\u6392\u961f\u7684\u5ba2\u6237 \u6587\u4ef6\u76ee\u5f55\u7cfb\u7edf \u56fe\u591a\u9879\u96c6\u6700\u80fd\u4ee3\u8868\uff1a \u4e00\u7ec4\u6570\u5b57 \u57ce\u5e02\u4e4b\u95f4\u7684\u822a\u7ebf\u56fe \u5728Python\u91cc\uff0c\u4e24\u4e2a\u591a\u9879\u96c6\u95f4\u7684\u7c7b\u578b\u8f6c\u6362\u64cd\u4f5c\uff1a \u5728\u6e90\u591a\u9879\u96c6\u91cc\u521b\u5efa\u5bf9\u8c61\u7684\u526f\u672c\uff0c\u5e76\u4e14\u628a\u8fd9\u4e9b\u65b0\u5bf9\u8c61\u6dfb\u52a0\u5230\u76ee\u6807\u591a\u9879\u96c6\u7684\u65b0\u5b9e\u4f8b\u91cc \u628a\u5bf9\u6e90\u591a\u9879\u96c6\u5bf9\u8c61\u7684\u5f15\u7528\u6dfb\u52a0\u5230\u76ee\u6807\u591a\u9879\u96c6\u7684\u65b0\u5b9e\u4f8b\u91cc \u4e24\u4e2a\u5217\u8868\u7684 == \u64cd\u4f5c\u5fc5\u987b\uff1a \u6bd4\u8f83\u6bcf\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u5bf9\u662f\u5426\u76f8\u7b49 \u53ea\u4f1a\u9a8c\u8bc1\u4e00\u4e2a\u5217\u8868\u91cc\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u662f\u5426\u4e5f\u5728\u53e6\u4e00\u4e2a\u5217\u8868\u91cc \u4e24\u4e2a\u96c6\u5408\u7684 == \u64cd\u4f5c\u5fc5\u987b\uff1a \u6bd4\u8f83\u6bcf\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u5bf9\u662f\u5426\u76f8\u7b49 \u9a8c\u8bc1\u96c6\u5408\u7684\u5927\u5c0f\u662f\u5426\u76f8\u7b49\uff0c\u5e76\u4e14\u4e00\u4e2a\u96c6\u5408\u91cc\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u662f\u5426\u4e5f\u5728\u53e6\u4e00\u4e2a\u96c6\u5408\u91cc \u5bf9\u5217\u8868\u8fdb\u884c for \u5faa\u73af\u65f6\uff0c\u8bbf\u95ee\u5143\u7d20\u7684\u987a\u5e8f\uff1a \u4ece\u5934\u5230\u5c3e\u7684\u6240\u6709\u4f4d\u7f6e \u4e0d\u4f1a\u6309\u7167\u7279\u5b9a\u7684\u987a\u5e8f map \u51fd\u6570\u4f1a\u521b\u5efa\u4e00\u4e2a\u4ec0\u4e48\u6837\u7684\u5e8f\u5217\uff1a \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u901a\u8fc7\u5e03\u5c14\u6d4b\u8bd5\u7684\u5143\u7d20 \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u5bf9\u5143\u7d20\u6267\u884c\u51fd\u6570\u7684\u7ed3\u679c filter \u51fd\u6570\u4f1a\u521b\u5efa\u4e00\u4e2a\u4ec0\u4e48\u6837\u7684\u5e8f\u5217\uff1a \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u901a\u8fc7\u5e03\u5c14\u6d4b\u8bd5\u7684\u5143\u7d20 \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u5bf9\u5143\u7d20\u6267\u884c\u51fd\u6570\u7684\u7ed3\u679c 2.7.\u7f16\u7a0b\u7ec3\u4e60 \u00b6 1\uff0e\u5728Shell\u7a97\u53e3\u7684\u63d0\u793a\u7b26\u4e0b\u4f7f\u7528 dir \u548c help \u51fd\u6570\u6765\u63a2\u7d22Python\u7684\u5185\u7f6e\u591a\u9879\u96c6\u7c7b\u578b str \u3001 list \u3001 tuple \u3001 set \u4ee5\u53ca dict \u7684\u63a5\u53e3\u3002\u5b83\u4eec\u7684\u8bed\u6cd5\u662f dir() \u548c help() \u3002 \u89e3\u7b54\uff1a \u53ef\u4ee5\u901a\u8fc7\u4ee5\u4e0b\u65b9\u5f0f\u6765\u4e86\u89e3\u5b83\u4eec\u7684\u63a5\u53e3\uff1a \u5b57\u7b26\u4e32 ( str ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5b57\u7b26\u4e32\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( str ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5b57\u7b26\u4e32\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( str ) \u5217\u8868 ( list ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5217\u8868\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( list ) x # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5217\u8868\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( list ) \u5143\u7ec4 ( tuple ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5143\u7ec4\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( tuple ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5143\u7ec4\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( tuple ) \u96c6\u5408 ( set ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u96c6\u5408\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( set ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u96c6\u5408\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( set ) \u5b57\u5178 ( dict ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5b57\u5178\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( dict ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5b57\u5178\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( dict ) dir() \u51fd\u6570\u5c06\u8fd4\u56de\u4e00\u4e2a\u5305\u542b\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027\u540d\u79f0\u7684\u5217\u8868\uff0c\u800c help() \u51fd\u6570\u5c06\u663e\u793a\u5173\u4e8e\u8be5\u7c7b\u578b\u7684\u8be6\u7ec6\u5e2e\u52a9\u4fe1\u606f\uff0c\u5305\u62ec\u6bcf\u4e2a\u65b9\u6cd5\u7684\u8bf4\u660e\u548c\u7528\u6cd5\u793a\u4f8b\u3002 2\uff0e\u67e5\u770b java.util \u5305\u91cc\u6240\u63d0\u4f9b\u7684Java\u591a\u9879\u96c6\u7c7b\u578b\uff0c\u5e76\u548cPython\u7684\u591a\u9879\u96c6\u7c7b\u578b\u52a0\u4ee5\u6bd4\u8f83\u3002 java.util \u5305\u4e2d\u63d0\u4f9b\u4e86\u8bb8\u591aJava\u7684\u96c6\u5408\u7c7b\u578b\uff0c\u5305\u62ec\u5217\u8868\u3001\u96c6\u5408\u3001\u6620\u5c04\u7b49\u3002\u4e0b\u9762\u5c06\u5217\u51fa\u5176\u4e2d\u4e00\u4e9b\u5e38\u7528\u7684\u591a\u9879\u96c6\u7c7b\u578b\uff0c\u5e76\u5c06\u5b83\u4eec\u4e0ePython\u4e2d\u7684\u591a\u9879\u96c6\u7c7b\u578b\u8fdb\u884c\u6bd4\u8f83\u3002 Java ArrayList vs Python List: Java ArrayList \u662f\u4e00\u4e2a\u53ef\u53d8\u5927\u5c0f\u7684\u52a8\u6001\u6570\u7ec4\u3002 Python List \u4e5f\u662f\u53ef\u53d8\u5927\u5c0f\u7684\u52a8\u6001\u6570\u7ec4\uff0c\u53ef\u4ee5\u5bb9\u7eb3\u4efb\u610f\u7c7b\u578b\u7684\u6570\u636e\u3002 Java HashSet vs Python Set: Java HashSet \u662f\u4e00\u4e2a\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\u7684\u96c6\u5408\u3002 Python Set \u4e5f\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\uff0c\u540c\u65f6\u8fd8\u6709\u4e00\u4e2a\u7279\u6b8a\u7c7b\u578b\u7684\u96c6\u5408\u53eb\u505a frozenset \uff0c\u5b83\u662f\u4e0d\u53ef\u53d8\u7684\u3002 Java LinkedHashSet vs Python OrderedDict: Java LinkedHashSet \u662f\u4e00\u4e2a\u4fdd\u6301\u5143\u7d20\u63d2\u5165\u987a\u5e8f\u7684\u96c6\u5408\uff0c\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\u3002 Python OrderedDict \u662f\u4e00\u4e2a\u6709\u5e8f\u5b57\u5178\uff0c\u4fdd\u6301\u5143\u7d20\u63d2\u5165\u987a\u5e8f\uff0c\u53ef\u4ee5\u7528\u4e8e\u521b\u5efa\u6709\u5e8f\u7684\u952e-\u503c\u5bf9\u96c6\u5408\u3002 Java TreeSet vs Python SortedSet: Java TreeSet \u662f\u4e00\u4e2a\u81ea\u7136\u6392\u5e8f\u6216\u8005\u901a\u8fc7\u63d0\u4f9b\u7684\u6bd4\u8f83\u5668\u8fdb\u884c\u6392\u5e8f\u7684\u96c6\u5408\uff0c\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\u3002 Python \u6ca1\u6709\u4e13\u95e8\u7684 SortedSet \u7c7b\uff0c\u4f46\u4f60\u53ef\u4ee5\u4f7f\u7528 sorted() \u51fd\u6570\u5bf9\u96c6\u5408\u8fdb\u884c\u6392\u5e8f\u3002 Java HashMap vs Python Dictionary: Java HashMap \u662f\u4e00\u4e2a\u65e0\u5e8f\u7684\u952e-\u503c\u5bf9\u6620\u5c04\uff0c\u4e0d\u5141\u8bb8\u91cd\u590d\u952e\u3002 Python Dictionary \u662f\u4e00\u4e2a\u65e0\u5e8f\u7684\u952e-\u503c\u5bf9\u6620\u5c04\uff0c\u952e\u662f\u552f\u4e00\u7684\u3002 Java TreeMap vs Python OrderedDict: Java TreeMap \u662f\u4e00\u4e2a\u57fa\u4e8e\u7ea2\u9ed1\u6811\u7684\u6709\u5e8f\u6620\u5c04\u3002 Python OrderedDict \u5728\u952e\u7684\u63d2\u5165\u987a\u5e8f\u4e0a\u4fdd\u6301\u6709\u5e8f\u3002 Java \u7684\u591a\u9879\u96c6\u7c7b\u578b\u548c Python \u7684\u591a\u9879\u96c6\u7c7b\u578b\u5728\u529f\u80fd\u4e0a\u975e\u5e38\u7c7b\u4f3c\uff0c\u90fd\u63d0\u4f9b\u4e86\u5404\u79cd\u4e0d\u540c\u7684\u96c6\u5408\u7c7b\u578b\u6765\u9002\u5e94\u4e0d\u540c\u7684\u9700\u6c42\u3002\u9700\u8981\u6839\u636e\u5177\u4f53\u7684\u4f7f\u7528\u60c5\u51b5\u6765\u9009\u62e9\u54ea\u79cd\u96c6\u5408\u7c7b\u578b\u66f4\u9002\u5408\u3002\u540c\u65f6\uff0cPython \u8fd8\u63d0\u4f9b\u4e86\u65b9\u4fbf\u7684\u5217\u8868\u63a8\u5bfc\u3001\u96c6\u5408\u63a8\u5bfc\u548c\u5b57\u5178\u63a8\u5bfc\u7b49\u7279\u6027\uff0c\u53ef\u4ee5\u66f4\u52a0\u4fbf\u6377\u5730\u521b\u5efa\u548c\u5904\u7406\u591a\u9879\u96c6\u3002","title":"\u591a\u9879\u96c6\u7684\u6982\u8ff0"},{"location":"python/DataStructure/02_CollectionsOverview/#2","text":"\u591a\u9879\u96c6\uff08collection\uff09\u662f\u6307\u7531 0 \u4e2a\u6216\u8005\u591a\u4e2a\u5143\u7d20\u7ec4\u6210\u7684\u6982\u5ff5\u5355\u5143\u3002 \u4ece\u4e24\u4e2a\u89d2\u5ea6\u770b\u5f85\u591a\u9879\u96c6\uff1a \u591a\u9879\u96c6\u7684\u7528\u6237\u6216\u8005\u5ba2\u6237\u4f1a\u5173\u5fc3\u5b83\u4eec\u5728\u4e0d\u540c\u7684\u5e94\u7528\u7a0b\u5e8f\u91cc\u80fd\u505a\u4e9b\u4ec0\u4e48\u3002 \u591a\u9879\u96c6\u7684\u5f00\u53d1\u8005\u6216\u8005\u5b9e\u73b0\u8005\u5219\u4f1a\u5173\u5fc3\u5982\u4f55\u624d\u80fd\u8ba9\u5b83\u4eec\u6210\u4e3a\u6700\u597d\u7684\u901a\u7528\u8d44\u6e90\u4ee5\u88ab\u4f7f\u7528\u3002 \u76ee\u6807\uff1a \u5b9a\u4e49\u591a\u9879\u96c6\u76844\u4e2a\u901a\u7528\u7c7b\u578b\uff1a \u7ebf\u6027\u591a\u9879\u96c6 \u5206\u5c42\u591a\u9879\u96c6 \u56fe\u591a\u9879\u96c6 \u65e0\u5e8f\u591a\u9879\u96c6 \u4e86\u89e34\u4e2a\u591a\u9879\u96c6\u7c7b\u578b\u4e2d\u7684\u7279\u5b9a\u7c7b\u578b\uff1b \u4e86\u89e3\u8fd9\u4e9b\u591a\u9879\u96c6\u9002\u5408\u7528\u5728\u4ec0\u4e48\u7c7b\u578b\u7684\u5e94\u7528\u7a0b\u5e8f\u91cc\uff1b \u63cf\u8ff0\u6bcf\u79cd\u591a\u9879\u96c6\u7c7b\u578b\u7684\u5e38\u7528\u64cd\u4f5c\uff1b \u63cf\u8ff0\u591a\u9879\u96c6\u7684\u62bd\u8c61\u7c7b\u578b\u548c\u5b9e\u73b0\u4e4b\u95f4\u7684\u533a\u522b\uff1b","title":"2.\u591a\u9879\u96c6\u7684\u6982\u8ff0"},{"location":"python/DataStructure/02_CollectionsOverview/#21","text":"\u5185\u7f6e\u591a\u9879\u96c6\u7c7b\u578b\uff1a \u5b57\u7b26\u4e32 str \u5217\u8868 list \u5143\u7ec4 tuple \u96c6\u5408 set \u5b57\u5178 dict \u5176\u4ed6\u591a\u9879\u96c6\u7c7b\u578b\uff1a \u6808 \u961f\u5217 \u4f18\u5148\u961f\u5217 \u4e8c\u53c9\u67e5\u627e\u6811 \u5806 \u56fe \u5305 \u6709\u5e8f\u591a\u9879\u96c6 \u591a\u9879\u96c6\u901a\u5e38\u4e0d\u662f\u9759\u6001\uff08static\uff09\u7684\uff0c\u800c\u662f\u52a8\u6001\uff08dynamic\uff09\u7684\uff0c\u53ef\u4ee5\u6839\u636e\u9700\u8981\u6765\u6269\u5927\u6216\u8005\u7f29\u5c0f\u591a\u9879\u96c6\u3002 \u4e0d\u53ef\u53d8\u591a\u9879\u96c6\uff08immutable collection\uff09\u7684\u5185\u5bb9\u5728\u7a0b\u5e8f\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u662f\u4e0d\u53ef\u6539\u53d8\u7684\uff08\u5143\u7d20\u4e0d\u53ef\u4ee5\u6dfb\u52a0\u3001\u5220\u9664\u6216\u8005\u66ff\u6362\uff09\uff0c\u6bd4\u5982\u5143\u7ec4tuple\u3002 \u53ef\u53d8\u591a\u9879\u96c6\uff08mutable collection\uff09\u91cc\u7684\u5185\u5bb9\u53ef\u4ee5\u5728\u7a0b\u5e8f\u7684\u6574\u4e2a\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u88ab\u6539\u53d8\uff0c\u6bd4\u5982\u5b57\u7b26\u4e32\u3001\u5217\u8868list\u3002 \u591a\u9879\u96c6\u6309\u6784\u6210\u65b9\u5f0f\u5212\u5206\u7684\u7c7b\u578b\uff1a \u7ebf\u6027\u591a\u9879\u96c6 \u5206\u5c42\u591a\u9879\u96c6 \u56fe\u591a\u9879\u96c6 \u65e0\u5e8f\u591a\u9879\u96c6 \u6709\u5e8f\u591a\u9879\u96c6","title":"2.1.\u591a\u9879\u96c6\u7c7b\u578b"},{"location":"python/DataStructure/02_CollectionsOverview/#211","text":"\u7ebf\u6027\u591a\u9879\u96c6\uff08linear collection\uff09\u91cc\u7684\u5143\u7d20\u6309\u7167\u4f4d\u7f6e\u8fdb\u884c\u6392\u5217\u3002 \u9664\u4e86\u7b2c\u4e00\u4e2a\u5143\u7d20\uff0c\u5176\u4ed6\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\uff1b \u9664\u4e86\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff0c\u5176\u4ed6\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u540e\u5e8f\uff1b \u5b9e\u4f8b\uff1a\u6392\u961f\u7684\u4eba\uff0c\u8d2d\u7269\u6e05\u5355\uff0c\u5806\u53e0\u5728\u4e00\u8d77\u7684\u9910\u76d8\u7b49\u3002","title":"2.1.1.\u7ebf\u6027\u591a\u9879\u96c6"},{"location":"python/DataStructure/02_CollectionsOverview/#212","text":"\u5206\u5c42\u591a\u9879\u96c6\uff08hierarchical collection\uff09\u91cc\u7684\u6570\u636e\u5143\u7d20\u4f1a\u4ee5\u7c7b\u4f3c\u4e8e\u5012\u7f6e\u7684\u6811\u7ed3\u6784\u8fdb\u884c\u6392\u5217\u3002\u9664\u4e86\u9876\u90e8\u7684\u6570\u636e\u5143\u7d20\uff0c\u5176\u4ed6\u6bcf\u4e2a\u6570\u636e\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\uff0c\u88ab\u79f0\u4e3a\u7236\u5143\u7d20\uff08parent\uff09\uff0c\u4f46\u5b83\u4eec\u53ef\u4ee5\u6709\u8bb8\u591a\u7684\u540e\u5e8f\uff0c\u88ab\u79f0\u4e3a\u5b50\u5143\u7d20\uff08children\uff09\u3002 \u56fe\u4f8b\u4e2d\uff0c D3 \u7684\u524d\u5e8f\u7236\u5143\u7d20\u662f D1 \uff0c D3 \u7684\u540e\u7eed\u5b50\u5143\u7d20\u662f D4 \u3001 D5 \u3001 D6 \u3002 \u5b9e\u4f8b\uff1a\u6587\u4ef6\u76ee\u5f55\u7cfb\u7edf\u3001\u516c\u53f8\u7684\u7ec4\u7ec7\u67b6\u6784\u3001\u4e66\u7684\u76ee\u5f55\u7b49\u3002","title":"2.1.2.\u5206\u5c42\u591a\u9879\u96c6"},{"location":"python/DataStructure/02_CollectionsOverview/#213","text":"\u56fe\u591a\u9879\u96c6\uff08graph collection\uff09\u4e5f\u88ab\u79f0\u4e3a\u56fe\uff08graph\uff09\uff0c\u5b83\u662f\u8fd9\u6837\u4e00\u4e2a\u591a\u9879\u96c6\uff1a\u5b83\u7684\u6bcf\u4e00\u4e2a\u6570\u636e\u5143\u7d20\u90fd\u53ef\u4ee5\u6709\u591a\u4e2a\u524d\u5e8f\u548c\u591a\u4e2a\u540e\u5e8f\u3002 \u56fe\u4f8b\u4e2d\uff0c\u8fde\u63a5\u5230 D3 \u7684\u6240\u6709\u5143\u7d20\u4f1a\u88ab\u5f53\u4f5c\u5b83\u7684\u524d\u5e8f\u548c\u540e\u5e8f\uff0c\u5b83\u4eec\u4e5f\u56e0\u6b64\u88ab\u79f0\u4e3a D3 \u7684\u90bb\u5c45\u3002 \u5b9e\u4f8b\uff1a\u57ce\u5e02\u4e4b\u95f4\u7684\u822a\u7ebf\u56fe\u3001\u4e07\u7ef4\u7f51\u7b49\u3002","title":"2.1.3.\u56fe\u591a\u9879\u96c6"},{"location":"python/DataStructure/02_CollectionsOverview/#214","text":"\u65e0\u5e8f\u591a\u9879\u96c6\uff08unordered collection\uff09\u91cc\u7684\u5143\u7d20\u6ca1\u6709\u7279\u5b9a\u7684\u987a\u5e8f\uff0c\u5e76\u4e14\u4e0d\u4f1a\u7528\u4efb\u4f55\u660e\u786e\u7684\u65b9\u5f0f\u6765\u6307\u51fa\u5143\u7d20\u7684\u524d\u5e8f\u6216\u8005\u540e\u5e8f\u3002 \u5b9e\u4f8b\uff1a\u4e00\u888b\u5f39\u73e0\u7b49\u3002","title":"2.1.4.\u65e0\u5e8f\u591a\u9879\u96c6"},{"location":"python/DataStructure/02_CollectionsOverview/#215","text":"\u6709\u5e8f\u591a\u9879\u96c6\uff08sorted collection\uff09\u4f1a\u5bf9\u5b83\u91cc\u9762\u7684\u5143\u7d20\u8fdb\u884c\u81ea\u7136\u6392\u5e8f\uff08natural ordering\uff09\u3002 \u8981\u8fdb\u884c\u81ea\u7136\u6392\u5e8f\uff0c\u5c31\u5fc5\u987b\u8981\u6709\u89c4\u5219\u6765\u5bf9\u6709\u5e8f\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u52a0\u4ee5\u6bd4\u8f83\uff0c\u4f8b\u5982 item(i) <= item(i+1) \u8fd9\u6837\u7684\u2014\u2014\u89c4\u5219\u3002 \u6709\u5e8f\u5217\u8868\u662f\u6700\u5e38\u89c1\u7684\u6709\u5e8f\u591a\u9879\u96c6\u3002\u6709\u5e8f\u591a\u9879\u96c6\u4e0d\u4e00\u5b9a\u662f\u7ebf\u6027\u7684\u6216\u8005\u6309\u7167\u4f4d\u7f6e\u8fdb\u884c\u6392\u5e8f\u7684\u3002 \u5bf9\u4e8e\u96c6\u5408\u3001\u5305\u3001\u5b57\u5178\uff0c\u867d\u7136\u4e0d\u80fd\u6309\u7167\u4f4d\u7f6e\u6765\u8bbf\u95ee\u5b83\u4eec\u7684\u5143\u7d20\uff0c\u4f46\u5b83\u4eec\u90fd\u53ef\u4ee5\u662f\u6709\u5e8f\u7684\u3002 \u7279\u6b8a\u7684\u5206\u5c42\u591a\u9879\u96c6\u7c7b\u578b\uff08\u5982\u4e8c\u53c9\u67e5\u627e\u6811\uff09\u4e5f\u4f1a\u5bf9\u5176\u4e2d\u7684\u5143\u7d20\u8fdb\u884c\u81ea\u7136\u6392\u5e8f\u3002","title":"2.1.5.\u6709\u5e8f\u591a\u9879\u96c6"},{"location":"python/DataStructure/02_CollectionsOverview/#216","text":"\u4e0b\u9762\u5206\u7c7b\u91cc\u7684\u7c7b\u578b\u540d\u79f0\u6307\u7684\u5e76\u4e0d\u662f\u591a\u9879\u96c6\u7684\u7279\u5b9a\u5b9e\u73b0\u3002\u4e00\u79cd\u7279\u5b9a\u7c7b\u578b\u7684\u591a\u9879\u96c6\u53ef\u4ee5\u6709\u591a\u4e2a\u5b9e\u73b0\u3002 \u591a\u9879\u96c6 | ---\u56fe\u591a\u9879\u96c6 | ---\u5206\u5c42\u591a\u9879\u96c6 | | ---\u4e8c\u53c9\u67e5\u627e\u6811 | | ---\u5806 | ---\u7ebf\u6027\u591a\u9879\u96c6 | | ---\u5217\u8868 | | | ---\u6709\u5e8f\u5217\u8868 | | ---\u961f\u5217 | | | ---\u4f18\u5148\u5bf9\u5217 | | ---\u6808 | | ---\u5b57\u7b26\u4e32 | ---\u65e0\u5e8f\u591a\u9879\u96c6 | ---\u5305 | | ---\u6709\u5e8f\u5305 | ---\u5b57\u5178 | | ---\u6709\u5e8f\u5305 | ---\u96c6\u5408 | ---\u6709\u5e8f\u96c6\u5408","title":"2.1.6.\u591a\u9879\u96c6\u7c7b\u578b\u7684\u5206\u7c7b"},{"location":"python/DataStructure/02_CollectionsOverview/#22","text":"\u591a\u9879\u96c6\u64cd\u4f5c\u7c7b\u522b\uff1a \u786e\u5b9a\u5927\u5c0f\uff1a\u4f7f\u7528 len \u51fd\u6570\u83b7\u53d6\u5f53\u524d\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u6570\u91cf\u3002 \u68c0\u6d4b\u5143\u7d20\u6210\u5458\uff1a\u4f7f\u7528 in \u8fd0\u7b97\u7b26\u5728\u591a\u9879\u96c6\u91cc\u641c\u7d22\u6307\u5b9a\u7684\u76ee\u6807\u5143\u7d20\u3002\u5982\u679c\u627e\u5230\u4e86\u8fd9\u4e2a\u5143\u7d20\uff0c\u5219\u8fd4\u56deTrue\uff0c\u5426\u5219\u8fd4\u56deFalse\u3002 \u904d\u5386\u591a\u9879\u96c6\uff1a\u4f7f\u7528 for \u5faa\u73af\u8bbf\u95ee\u591a\u9879\u96c6\u91cc\u7684\u6b38\u4e00\u4e2a\u5143\u7d20\u3002\u5143\u7d20\u7684\u8bbf\u95ee\u987a\u5e8f\u53d6\u51b3\u4e8e\u591a\u9879\u96c6\u7684\u7c7b\u578b\u3002 \u83b7\u53d6\u591a\u9879\u96c6\u7684\u5b57\u7b26\u4e32\u8868\u793a\uff1a\u4f7f\u7528 str \u51fd\u6570\u83b7\u53d6\u591a\u9879\u96c6\u7684\u5b57\u7b26\u4e32\u8868\u793a\u3002 \u76f8\u7b49\u68c0\u6d4b\uff1a\u4f7f\u7528 == \u8fd0\u7b97\u7b26\u6765\u786e\u5b9a\u4e24\u4e2a\u591a\u9879\u96c6\u662f\u5426\u76f8\u7b49\u3002\u5982\u679c\u4e24\u4e2a\u591a\u9879\u96c6\u80b2\u6709\u76f8\u540c\u7684\u7c7b\u578b\uff0c\u5e76\u4e14\u5305\u542b\u76f8\u540c\u7684\u5143\u7d20\uff0c\u90a3\u4e48\u5b83\u4eec\u5c31\u662f\u76f8\u7b49\u7684\u3002\u6bd4\u8f83\u8fd9\u4e9b\u5143\u7d20\u5bf9\u7684\u987a\u5e8f\u53d6\u51b3\u4e8e\u591a\u9879\u96c6\u7684\u7c7b\u578b\u3002 \u8fde\u63a5\u4e24\u4e2a\u591a\u9879\u96c6\uff1a\u4f7f\u7528 + \u8fd0\u7b97\u7b26\u6765\u5f97\u5230\u4e00\u4e2a\u548c\u64cd\u4f5c\u6570\u76f8\u540c\u7c7b\u578b\u7684\u65b0\u591a\u9879\u96c6\uff0c\u5e76\u4e14\u5305\u542b\u4e24\u4e2a\u64cd\u4f5c\u6570\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002 \u8f6c\u6362\u4e3a\u5176\u4ed6\u7c7b\u578b\u7684\u591a\u9879\u96c6\uff1a\u521b\u5efa\u4e00\u4e2a\u4e0e\u6e90\u591a\u9879\u96c6\u5177\u6709\u76f8\u540c\u5143\u7d20\u7684\u65b0\u591a\u9879\u96c6\u3002\u514b\u9686\u64cd\u4f5c\u65f6\u7c7b\u578b\u8f6c\u6362\u7684\u4e00\u79cd\u7279\u6b8a\u60c5\u51b5\uff0c\u56e0\u4e3a\u8f93\u5165\u8f93\u51fa\u7684\u4e24\u4e2a\u591a\u9879\u96c6\u5177\u6709\u76f8\u540c\u7c7b\u578b\u3002 \u63d2\u5165\u4e00\u4e2a\u5143\u7d20\uff1a\u5982\u679c\u53ef\u4ee5\uff0c\u5219\u5728\u7ed9\u5b9a\u7684\u4f4d\u7f6e\u5c06\u5bf9\u5e94\u7684\u5143\u7d20\u6dfb\u52a0\u5230\u591a\u9879\u96c6\u91cc\u3002 \u5220\u9664\u4e00\u4e2a\u5143\u7d20\uff1a\u5982\u679c\u53ef\u4ee5\uff0c\u5219\u5728\u7ed9\u5b9a\u7684\u4f4d\u7f6e\u5c06\u5bf9\u5e94\u7684\u5143\u7d20\u4ece\u591a\u9879\u96c6\u4e2d\u5220\u9664\u3002 \u66ff\u6362\u4e00\u4e2a\u5143\u7d20\uff1a\u5c06\u5220\u9664\u548c\u63d2\u5165\u5408\u5e76\u4e3a\u4e00\u9879\u64cd\u4f5c\u3002 \u8bbf\u95ee\u6216\u8005\u83b7\u53d6\u5143\u7d20\uff1a\u5982\u679c\u800c\u5df2\uff0c\u5219\u5728\u7ed9\u5b9a\u7684\u4f4d\u7f6e\u83b7\u53d6\u5143\u7d20\u3002","title":"2.2.\u591a\u9879\u96c6\u64cd\u4f5c"},{"location":"python/DataStructure/02_CollectionsOverview/#221","text":"\u5728Python\u91cc\uff0c\u4e0d\u540c\u591a\u9879\u96c6\u7c7b\u578b\u7684\u63d2\u5165\u3001\u5220\u9664\u3001\u66ff\u6362\u6216\u8005\u8bbf\u95ee\u64cd\u4f5c\u5e76\u6ca1\u6709\u7edf\u4e00\u7684\u540d\u79f0\uff0c\u4f46\u662f\u4f1a\u6709\u4e00\u4e9b\u6807\u51c6\u53d8\u4f53\u3002\u6bd4\u5982\uff0c \u65b9\u6cd5pop\u4f1a\u88ab\u7528\u6765\u4ece\u5217\u8868\u91cc\u79fb\u9664\u6307\u5b9a\u4f4d\u7f6e\u7684\u5143\u7d20\uff1b \u65b9\u6cd5pop\u4f1a\u88ab\u7528\u6765\u4ece\u5b57\u5178\u91cc\u79fb\u9664\u7ed9\u5b9a\u952e\u6240\u5bf9\u5e94\u7684\u503c\uff1b \u65b9\u6cd5remove\u4f1a\u88ab\u7528\u6765\u4ece\u5217\u8868\u6216\u8005\u67d0\u4e9b\u591a\u9879\u96c6\u91cc\u5220\u9664\u6307\u5b9a\u7684\u5143\u7d20\uff1b \u5bf9\u4e8e\u65b0\u5f00\u53d1\u51fa\u7684\u3001Python\u5c1a\u4e0d\u652f\u6301\u7684\u591a\u9879\u96c6\u7c7b\u578b\uff0c\u5c3d\u53ef\u80fd\u5730\u4f7f\u7528\u6807\u51c6\u7684\u8fd0\u7b97\u7b26\u3001\u51fd\u6570\u4ee5\u53ca\u65b9\u6cd5\u540d\u79f0\u5bf9\u5b83\u4eec\u8fdb\u884c\u64cd\u4f5c\u3002","title":"2.2.1.\u6240\u6709\u591a\u9879\u96c6\u7c7b\u578b\u4e2d\u7684\u57fa\u672c\u64cd\u4f5c"},{"location":"python/DataStructure/02_CollectionsOverview/#222","text":"\u7c7b\u578b\u8f6c\u6362\uff0c\u5c06\u4e00\u79cd\u7c7b\u578b\u7684\u591a\u9879\u96c6\u8f6c\u6362\u4e3a\u53e6\u4e00\u79cd\u7c7b\u578b\u7684\u591a\u9879\u96c6\u3002\u4f8b\u5982\uff0c\u901a\u8fc7 list \u6216 tuple \u51fd\u6570\u5c06\u5b57\u7b26\u4e32\u8f6c\u6362\u4e3a\u5217\u8868\u6216\u8005\u5143\u7ec4\u3002 list \u6216 tuple \u51fd\u6570\u7684\u53c2\u6570\u4e0d\u4e00\u5b9a\u662f\u53e6\u4e00\u4e2a\u591a\u9879\u96c6\uff0c\u4e5f\u53ef\u4ee5\u662f\u4efb\u4f55\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08iterable object\uff09\u3002 \u53ef\u8fed\u4ee3\u5bf9\u8c61\u662f\u6307\uff0c\u80fd\u591f\u4f7f\u7528for\u5faa\u73af\u6765\u8bbf\u95ee\u7684\u4e00\u7cfb\u5217\u5143\u7d20\u3002\uff08\u591a\u9879\u96c6\u672c\u8eab\u4e5f\u662f\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff09","title":"2.2.2.\u7c7b\u578b\u8f6c\u6362"},{"location":"python/DataStructure/02_CollectionsOverview/#223","text":"\u7c7b\u578b\u8f6c\u6362\u7684\u4e00\u79cd\u7279\u6b8a\u60c5\u51b5\u662f\u514b\u9686\uff0c\u5b83\u7684\u529f\u80fd\u662f\u8fd4\u56de\u8f6c\u6362\u51fd\u6570\u4e2d\u53c2\u6570\u7684\u5b8c\u6574\u526f\u672c\u3002 \u4f8b\u5982\uff1a myList1 = [ 2 , 4 , 8 ] myList2 = list ( myList1 ) myList1 is myList2 # False myList1 == myList2 # True \u6ce8\u610f\uff1a \u4e0a\u9762\u4e24\u4e2a\u5217\u8868\u4e0d\u4ec5\u6709\u76f8\u540c\u7684\u7ed3\u6784\uff0c\u5b83\u4eec\u8fd8\u6709\u76f8\u540c\u7684\u5143\u7d20\uff0c\u6bcf\u5bf9\u5143\u7d20\u5728\u4e24\u4e2a\u5217\u8868\u91cc\u7684\u4f4d\u7f6e\u90fd\u76f8\u540c\u3002\u4f46\u662f\uff0c\u4ed6\u4eec\u662f\u4e24\u4e2a\u4e0d\u540c\u7684\u5bf9\u8c61\u3002 \u4e0a\u4f8b\u4e2d list \u51fd\u6570\u5bf9\u5b83\u7684\u53c2\u6570\u5217\u8868\u8fdb\u884c\u6d45\u62f7\u8d1d\uff08shallow copy\uff09\u3002\u8fd9\u4e9b\u5143\u7d20\u7684\u672c\u8eab\u5728\u6dfb\u52a0\u5230\u65b0\u5217\u8868\u4e4b\u524d\u662f\u4e0d\u4f1a\u88ab\u514b\u9686\u7684\uff0c\u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e2d\u53ea\u4f1a\u590d\u5236\u5bf9\u8fd9\u4e9b\u5bf9\u8c61\u7684\u5f15\u7528\u3002\u5f53\u5143\u7d20\uff08\u6570\u5b57\u3001\u5b57\u7b26\u4e32\u6216\u8005Python\u7684\u5143\u7ec4\uff09\u4e0d\u53ef\u53d8\u65f6\uff0c\u8fd9\u4e2a\u7b56\u7565\u4e0d\u4f1a\u5f15\u8d77\u95ee\u9898\u3002\u4f46\u662f\uff0c\u5982\u679c\u591a\u9879\u96c6\u5305\u542b\u7684\u662f\u53ef\u53d8\u5143\u7d20\uff0c\u5c31\u53ef\u80fd\u4f1a\u4ea7\u751f\u526f\u4f5c\u7528\u3002\u4e3a\u4e86\u907f\u514d\u8fd9\u79cd\u60c5\u51b5\u7684\u53d1\u751f\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u5bf9\u6e90\u591a\u9879\u96c6\u7f16\u5199 for \u5faa\u73af\u6765\u521b\u5efa\u6df1\u62f7\u8d1d\uff08deep copy\uff09\uff0c\u8fd9\u4f1a\u628a\u5143\u7d20\u663e\u5f0f\u5730\u514b\u9686\u4e4b\u540e\u518d\u6dfb\u52a0\u5230\u65b0\u7684\u591a\u9879\u96c6\u91cc\u3002","title":"2.2.3.\u514b\u9686\u548c\u76f8\u7b49\u6027"},{"location":"python/DataStructure/02_CollectionsOverview/#23","text":"\u6bcf\u79cd\u7c7b\u578b\u7684\u591a\u9879\u96c6\u90fd\u652f\u6301\u4e00\u4e2a\u8fed\u4ee3\u5668\u6216 for \u5faa\u73af\uff0c\u8fd9\u4e2a\u64cd\u4f5c\u80fd\u591f\u8fed\u4ee3\u8fd9\u4e2a\u591a\u9879\u96c6\u7684\u6240\u6709\u5143\u7d20\u3002\u8fed\u4ee3\u5668\u662f\u591a\u9879\u96c6\u63d0\u4f9b\u7684\u6700\u5173\u952e\u7684\u64cd\u4f5c\u3002 for \u5faa\u73af\u670d\u52a1\u7684\u591a\u9879\u96c6\u4e2d\u5143\u7d20\u7684\u987a\u5e8f\u53d6\u51b3\u4e8e\u591a\u9879\u96c6\u7684\u7ec4\u7ec7\u65b9\u5f0f\u3002\u4f8b\u5982\uff1a \u5217\u8868\u91cc\u7684\u5143\u7d20\u4f1a\u4ece\u5934\u5230\u5c3e\u6309\u7167\u4f4d\u7f6e\u8fdb\u884c\u8bbf\u95ee\uff1b \u6709\u5e8f\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u4f1a\u6309\u4ece\u5c0f\u5230\u5927\u7684\u5347\u5e8f\u8fdb\u884c\u8bbf\u95ee\uff1b \u5bf9\u4e8e\u96c6\u5408\u6216\u8005\u5b57\u5178\u91cc\u7684\u5143\u7d20\u6765\u8bf4\uff0c\u4e0d\u4f1a\u6309\u7167\u7279\u5b9a\u7684\u987a\u5e8f\u8fdb\u884c\u8bbf\u95ee\u3002 \u8fed\u4ee3\u5668\uff08\u4f8b\u5982 for \u5faa\u73af\uff09\u8fd8\u652f\u6301\u4f7f\u7528\u9ad8\u9636\u51fd\u6570 map \u3001 filter \u548c reduce \u3002 \u8fd9\u4e9b\u9ad8\u9636\u51fd\u6570\u90fd\u4f7f\u7528\u53e6\u4e00\u4e2a\u51fd\u6570\u548c\u4e00\u4e2a\u591a\u9879\u96c6\u4f5c\u4e3a\u53c2\u6570\u3002 \u591a\u9879\u96c6\u90fd\u652f\u6301 for \u5faa\u73af\uff0c\u6240\u4ee5 map \u3001 filter \u548c reduce \u51fd\u6570\u53ef\u4ee5\u4e0e\u4efb\u4f55\u7c7b\u578b\u7684\u591a\u9879\u96c6\u4e00\u8d77\u4f7f\u7528\u3002","title":"2.3.\u8fed\u4ee3\u5668\u548c\u9ad8\u9636\u51fd\u6570"},{"location":"python/DataStructure/02_CollectionsOverview/#24","text":"\u4ece\u7528\u6237\uff08\u6bd4\u5982\uff0c\u7a0b\u5e8f\u5458\uff09\u7684\u89d2\u5ea6\u6765\u770b\uff0c\u591a\u9879\u96c6\u662f\u4e00\u79cd\u62bd\u8c61\uff0c\u662f\u4e00\u79cd\u4ee5\u67d0\u79cd\u9884\u5b9a\u884c\u4e3a\u6765\u5b58\u50a8\u548c\u8bbf\u95ee\u6570\u636e\u5143\u7d20\u7684\u65b9\u5f0f\uff0c\u5e76\u4e0d\u9700\u8981\u5173\u5fc3\u591a\u9879\u96c6\u5b9e\u73b0\u7684\u7ec6\u8282\u3002 \u591a\u9879\u96c6\u4e5f\u88ab\u79f0\u4e3a\u62bd\u8c61\u6570\u636e\u7c7b\u578b\uff08Abstract Data Type\uff0cADT\uff09\u3002\u62bd\u8c61\u6570\u636e\u7c7b\u578b\u7684\u7528\u6237\u53ea\u5173\u6ce8\u5b83\u7684\u63a5\u53e3\u4ee5\u53ca\u8fd9\u4e2a\u7c7b\u578b\u5bf9\u8c61\u6240\u63d0\u4f9b\u7684\u4e00\u7ec4\u64cd\u4f5c\u3002 \u5728Python\u91cc\uff0c\u51fd\u6570\u548c\u65b9\u6cd5\u662f\u6700\u5c0f\u7684\u62bd\u8c61\u5355\u5143\uff0c\u7c7b\u7684\u5927\u5c0f\u6b21\u4e4b\uff0c\u6a21\u5757\u662f\u6700\u5927\u7684\u62bd\u8c61\u5355\u5143\u3002 \u8fd9\u91cc\u4f1a\u628a\u62bd\u8c61\u591a\u9879\u96c6\u7c7b\u578b\u7684\u5b9e\u73b0\u5f53\u4f5c\u6a21\u5757\u91cc\u7684\u7c7b\u6216\u8005\u4e00\u7ec4\u76f8\u5173\u7684\u7c7b\u52a0\u4ee5\u63cf\u8ff0\u3002\u6784\u5efa\u8fd9\u4e9b\u7c7b\u5c31\u662f\u9762\u5411\u5bf9\u8c61\u7f16\u7a0b\u3002","title":"2.4.\u591a\u9879\u96c6\u7684\u5b9e\u73b0"},{"location":"python/DataStructure/02_CollectionsOverview/#25","text":"\u591a\u9879\u96c6\u662f\u5305\u542b0\u4e2a\u6216\u591a\u4e2a\u5176\u4ed6\u5bf9\u8c61\u7684\u5bf9\u8c61\u3002\u591a\u9879\u96c6\u53ef\u4ee5\u8fdb\u884c\u7684\u64cd\u4f5c\u6709\u8bbf\u95ee\u5bf9\u8c61\u3001\u63d2\u5165\u5bf9\u8c61\u3001\u5220\u9664\u5bf9\u8c61\u3001\u786e\u5b9a\u591a\u9879\u96c6\u7684\u5927\u5c0f\uff0c\u4ee5\u53ca\u904d\u5386\u6216\u8bbf\u95ee\u8fd9\u4e2a\u591a\u9879\u96c6\u7684\u5bf9\u8c61\u3002 \u591a\u9879\u96c6\u76845\u4e2a\u4e3b\u8981\u7c7b\u578b\u662f\uff1a\u7ebf\u6027\u591a\u9879\u96c6\u3001\u5206\u5c42\u591a\u9879\u96c6\u3001\u56fe\u591a\u9879\u96c6\u3001\u65e0\u5e8f\u591a\u9879\u96c6\u548c\u6709\u5e8f\u591a\u9879\u96c6\u3002 \u7ebf\u6027\u591a\u9879\u96c6\u4f1a\u6309\u7167\u4f4d\u7f6e\u5bf9\u5143\u7d20\u8fdb\u884c\u6392\u5e8f\uff0c\u5176\u4e2d\u9664\u4e86\u7b2c\u4e00\u4e2a\u5143\u7d20\uff0c\u6bcf\u4e2a\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\uff1b\u9664\u4e86\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff0c\u6bcf\u4e2a\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u540e\u5e8f\u3002 \u5728\u5206\u5c42\u591a\u9879\u96c6\u91cc\uff0c\u9664\u4e86\u4e00\u4e2a\u5143\u7d20\uff0c\u5176\u4ed6\u6240\u6709\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\u4ee5\u53ca0\u4e2a\u6216\u591a\u4e2a\u540e\u5e8f\u3002\u88ab\u79f0\u4e3a\u6839\u7684\u90a3\u4e2a\u989d\u5916\u5143\u7d20\u6ca1\u6709\u524d\u5e8f\u3002 \u56fe\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u53ef\u4ee5\u67090\u4e2a\u6216\u591a\u4e2a\u524d\u5e8f\u4ee5\u53ca0\u4e2a\u6216\u591a\u4e2a\u540e\u5e8f\u3002 \u65e0\u5e8f\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u6ca1\u6709\u7279\u5b9a\u7684\u987a\u5e8f\u3002 \u591a\u9879\u96c6\u662f\u53ef\u8fed\u4ee3\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\uff0c\u53ef\u4ee5\u4f7f\u7528for\u5faa\u73af\u8bbf\u95ee\u591a\u9879\u96c6\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u7a0b\u5e8f\u5458\u4e5f\u53ef\u4ee5\u4f7f\u7528\u9ad8\u9636\u51fd\u6570map\u3001filter\u548creduce\u7b80\u5316\u591a\u9879\u96c6\u7684\u6570\u636e\u5904\u7406\u3002 \u62bd\u8c61\u6570\u636e\u7c7b\u578b\u662f\u4e00\u7ec4\u5bf9\u8c61\u548c\u5bf9\u8fd9\u4e9b\u5bf9\u8c61\u7684\u64cd\u4f5c\u3002\u56e0\u6b64\uff0c\u591a\u9879\u96c6\u662f\u62bd\u8c61\u6570\u636e\u7c7b\u578b\u3002 \u6570\u636e\u7ed3\u6784\u662f\u4e00\u4e2a\u8868\u793a\u591a\u9879\u96c6\u91cc\u5305\u542b\u7684\u6570\u636e\u7684\u5bf9\u8c61\u3002","title":"2.5.\u5c0f\u7ed3"},{"location":"python/DataStructure/02_CollectionsOverview/#26","text":"\u7ebf\u6027\u591a\u9879\u96c6\u7684\u4e00\u4e2a\u4f8b\u5b50\u662f\uff1a \u96c6\u5408\u548c\u6811 \u5217\u8868\u548c\u6808 \u65e0\u5e8f\u591a\u9879\u96c6\u7684\u4e00\u4e2a\u4f8b\u5b50\u662f\uff1a \u961f\u5217\u548c\u5217\u8868 \u96c6\u5408\u548c\u5b57\u5178 \u5206\u5c42\u591a\u9879\u96c6\u53ef\u4ee5\u7528\u6765\u8868\u793a\uff1a \u94f6\u884c\u6392\u961f\u7684\u5ba2\u6237 \u6587\u4ef6\u76ee\u5f55\u7cfb\u7edf \u56fe\u591a\u9879\u96c6\u6700\u80fd\u4ee3\u8868\uff1a \u4e00\u7ec4\u6570\u5b57 \u57ce\u5e02\u4e4b\u95f4\u7684\u822a\u7ebf\u56fe \u5728Python\u91cc\uff0c\u4e24\u4e2a\u591a\u9879\u96c6\u95f4\u7684\u7c7b\u578b\u8f6c\u6362\u64cd\u4f5c\uff1a \u5728\u6e90\u591a\u9879\u96c6\u91cc\u521b\u5efa\u5bf9\u8c61\u7684\u526f\u672c\uff0c\u5e76\u4e14\u628a\u8fd9\u4e9b\u65b0\u5bf9\u8c61\u6dfb\u52a0\u5230\u76ee\u6807\u591a\u9879\u96c6\u7684\u65b0\u5b9e\u4f8b\u91cc \u628a\u5bf9\u6e90\u591a\u9879\u96c6\u5bf9\u8c61\u7684\u5f15\u7528\u6dfb\u52a0\u5230\u76ee\u6807\u591a\u9879\u96c6\u7684\u65b0\u5b9e\u4f8b\u91cc \u4e24\u4e2a\u5217\u8868\u7684 == \u64cd\u4f5c\u5fc5\u987b\uff1a \u6bd4\u8f83\u6bcf\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u5bf9\u662f\u5426\u76f8\u7b49 \u53ea\u4f1a\u9a8c\u8bc1\u4e00\u4e2a\u5217\u8868\u91cc\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u662f\u5426\u4e5f\u5728\u53e6\u4e00\u4e2a\u5217\u8868\u91cc \u4e24\u4e2a\u96c6\u5408\u7684 == \u64cd\u4f5c\u5fc5\u987b\uff1a \u6bd4\u8f83\u6bcf\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u5bf9\u662f\u5426\u76f8\u7b49 \u9a8c\u8bc1\u96c6\u5408\u7684\u5927\u5c0f\u662f\u5426\u76f8\u7b49\uff0c\u5e76\u4e14\u4e00\u4e2a\u96c6\u5408\u91cc\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u662f\u5426\u4e5f\u5728\u53e6\u4e00\u4e2a\u96c6\u5408\u91cc \u5bf9\u5217\u8868\u8fdb\u884c for \u5faa\u73af\u65f6\uff0c\u8bbf\u95ee\u5143\u7d20\u7684\u987a\u5e8f\uff1a \u4ece\u5934\u5230\u5c3e\u7684\u6240\u6709\u4f4d\u7f6e \u4e0d\u4f1a\u6309\u7167\u7279\u5b9a\u7684\u987a\u5e8f map \u51fd\u6570\u4f1a\u521b\u5efa\u4e00\u4e2a\u4ec0\u4e48\u6837\u7684\u5e8f\u5217\uff1a \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u901a\u8fc7\u5e03\u5c14\u6d4b\u8bd5\u7684\u5143\u7d20 \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u5bf9\u5143\u7d20\u6267\u884c\u51fd\u6570\u7684\u7ed3\u679c filter \u51fd\u6570\u4f1a\u521b\u5efa\u4e00\u4e2a\u4ec0\u4e48\u6837\u7684\u5e8f\u5217\uff1a \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u901a\u8fc7\u5e03\u5c14\u6d4b\u8bd5\u7684\u5143\u7d20 \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u5bf9\u5143\u7d20\u6267\u884c\u51fd\u6570\u7684\u7ed3\u679c","title":"2.6.\u590d\u4e60\u9898"},{"location":"python/DataStructure/02_CollectionsOverview/#27","text":"1\uff0e\u5728Shell\u7a97\u53e3\u7684\u63d0\u793a\u7b26\u4e0b\u4f7f\u7528 dir \u548c help \u51fd\u6570\u6765\u63a2\u7d22Python\u7684\u5185\u7f6e\u591a\u9879\u96c6\u7c7b\u578b str \u3001 list \u3001 tuple \u3001 set \u4ee5\u53ca dict \u7684\u63a5\u53e3\u3002\u5b83\u4eec\u7684\u8bed\u6cd5\u662f dir() \u548c help() \u3002 \u89e3\u7b54\uff1a \u53ef\u4ee5\u901a\u8fc7\u4ee5\u4e0b\u65b9\u5f0f\u6765\u4e86\u89e3\u5b83\u4eec\u7684\u63a5\u53e3\uff1a \u5b57\u7b26\u4e32 ( str ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5b57\u7b26\u4e32\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( str ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5b57\u7b26\u4e32\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( str ) \u5217\u8868 ( list ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5217\u8868\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( list ) x # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5217\u8868\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( list ) \u5143\u7ec4 ( tuple ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5143\u7ec4\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( tuple ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5143\u7ec4\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( tuple ) \u96c6\u5408 ( set ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u96c6\u5408\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( set ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u96c6\u5408\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( set ) \u5b57\u5178 ( dict ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5b57\u5178\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( dict ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5b57\u5178\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( dict ) dir() \u51fd\u6570\u5c06\u8fd4\u56de\u4e00\u4e2a\u5305\u542b\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027\u540d\u79f0\u7684\u5217\u8868\uff0c\u800c help() \u51fd\u6570\u5c06\u663e\u793a\u5173\u4e8e\u8be5\u7c7b\u578b\u7684\u8be6\u7ec6\u5e2e\u52a9\u4fe1\u606f\uff0c\u5305\u62ec\u6bcf\u4e2a\u65b9\u6cd5\u7684\u8bf4\u660e\u548c\u7528\u6cd5\u793a\u4f8b\u3002 2\uff0e\u67e5\u770b java.util \u5305\u91cc\u6240\u63d0\u4f9b\u7684Java\u591a\u9879\u96c6\u7c7b\u578b\uff0c\u5e76\u548cPython\u7684\u591a\u9879\u96c6\u7c7b\u578b\u52a0\u4ee5\u6bd4\u8f83\u3002 java.util \u5305\u4e2d\u63d0\u4f9b\u4e86\u8bb8\u591aJava\u7684\u96c6\u5408\u7c7b\u578b\uff0c\u5305\u62ec\u5217\u8868\u3001\u96c6\u5408\u3001\u6620\u5c04\u7b49\u3002\u4e0b\u9762\u5c06\u5217\u51fa\u5176\u4e2d\u4e00\u4e9b\u5e38\u7528\u7684\u591a\u9879\u96c6\u7c7b\u578b\uff0c\u5e76\u5c06\u5b83\u4eec\u4e0ePython\u4e2d\u7684\u591a\u9879\u96c6\u7c7b\u578b\u8fdb\u884c\u6bd4\u8f83\u3002 Java ArrayList vs Python List: Java ArrayList \u662f\u4e00\u4e2a\u53ef\u53d8\u5927\u5c0f\u7684\u52a8\u6001\u6570\u7ec4\u3002 Python List \u4e5f\u662f\u53ef\u53d8\u5927\u5c0f\u7684\u52a8\u6001\u6570\u7ec4\uff0c\u53ef\u4ee5\u5bb9\u7eb3\u4efb\u610f\u7c7b\u578b\u7684\u6570\u636e\u3002 Java HashSet vs Python Set: Java HashSet \u662f\u4e00\u4e2a\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\u7684\u96c6\u5408\u3002 Python Set \u4e5f\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\uff0c\u540c\u65f6\u8fd8\u6709\u4e00\u4e2a\u7279\u6b8a\u7c7b\u578b\u7684\u96c6\u5408\u53eb\u505a frozenset \uff0c\u5b83\u662f\u4e0d\u53ef\u53d8\u7684\u3002 Java LinkedHashSet vs Python OrderedDict: Java LinkedHashSet \u662f\u4e00\u4e2a\u4fdd\u6301\u5143\u7d20\u63d2\u5165\u987a\u5e8f\u7684\u96c6\u5408\uff0c\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\u3002 Python OrderedDict \u662f\u4e00\u4e2a\u6709\u5e8f\u5b57\u5178\uff0c\u4fdd\u6301\u5143\u7d20\u63d2\u5165\u987a\u5e8f\uff0c\u53ef\u4ee5\u7528\u4e8e\u521b\u5efa\u6709\u5e8f\u7684\u952e-\u503c\u5bf9\u96c6\u5408\u3002 Java TreeSet vs Python SortedSet: Java TreeSet \u662f\u4e00\u4e2a\u81ea\u7136\u6392\u5e8f\u6216\u8005\u901a\u8fc7\u63d0\u4f9b\u7684\u6bd4\u8f83\u5668\u8fdb\u884c\u6392\u5e8f\u7684\u96c6\u5408\uff0c\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\u3002 Python \u6ca1\u6709\u4e13\u95e8\u7684 SortedSet \u7c7b\uff0c\u4f46\u4f60\u53ef\u4ee5\u4f7f\u7528 sorted() \u51fd\u6570\u5bf9\u96c6\u5408\u8fdb\u884c\u6392\u5e8f\u3002 Java HashMap vs Python Dictionary: Java HashMap \u662f\u4e00\u4e2a\u65e0\u5e8f\u7684\u952e-\u503c\u5bf9\u6620\u5c04\uff0c\u4e0d\u5141\u8bb8\u91cd\u590d\u952e\u3002 Python Dictionary \u662f\u4e00\u4e2a\u65e0\u5e8f\u7684\u952e-\u503c\u5bf9\u6620\u5c04\uff0c\u952e\u662f\u552f\u4e00\u7684\u3002 Java TreeMap vs Python OrderedDict: Java TreeMap \u662f\u4e00\u4e2a\u57fa\u4e8e\u7ea2\u9ed1\u6811\u7684\u6709\u5e8f\u6620\u5c04\u3002 Python OrderedDict \u5728\u952e\u7684\u63d2\u5165\u987a\u5e8f\u4e0a\u4fdd\u6301\u6709\u5e8f\u3002 Java \u7684\u591a\u9879\u96c6\u7c7b\u578b\u548c Python \u7684\u591a\u9879\u96c6\u7c7b\u578b\u5728\u529f\u80fd\u4e0a\u975e\u5e38\u7c7b\u4f3c\uff0c\u90fd\u63d0\u4f9b\u4e86\u5404\u79cd\u4e0d\u540c\u7684\u96c6\u5408\u7c7b\u578b\u6765\u9002\u5e94\u4e0d\u540c\u7684\u9700\u6c42\u3002\u9700\u8981\u6839\u636e\u5177\u4f53\u7684\u4f7f\u7528\u60c5\u51b5\u6765\u9009\u62e9\u54ea\u79cd\u96c6\u5408\u7c7b\u578b\u66f4\u9002\u5408\u3002\u540c\u65f6\uff0cPython \u8fd8\u63d0\u4f9b\u4e86\u65b9\u4fbf\u7684\u5217\u8868\u63a8\u5bfc\u3001\u96c6\u5408\u63a8\u5bfc\u548c\u5b57\u5178\u63a8\u5bfc\u7b49\u7279\u6027\uff0c\u53ef\u4ee5\u66f4\u52a0\u4fbf\u6377\u5730\u521b\u5efa\u548c\u5904\u7406\u591a\u9879\u96c6\u3002","title":"2.7.\u7f16\u7a0b\u7ec3\u4e60"},{"location":"python/DataStructure/03_TimeComplexity/","text":"3.\u641c\u7d22\u3001\u6392\u5e8f\u4ee5\u53ca\u590d\u6742\u5ea6\u5206\u6790 \u00b6 \u7b97\u6cd5\u63cf\u8ff0\u4e86\u4e00\u4e2a\u968f\u7740\u95ee\u9898\u88ab\u89e3\u51b3\u800c\u505c\u6b62\u7684\u8ba1\u7b97\u8fc7\u7a0b\u3002 \u7b97\u6cd5\u662f\u8ba1\u7b97\u673a\u7a0b\u5e8f\u7684\u57fa\u672c\u7ec4\u6210\u90e8\u5206\u4e4b\u4e00\uff0c\u53e6\u4e00\u4e2a\u57fa\u672c\u7ec4\u6210\u90e8\u5206\u662f\u6570\u636e\u7ed3\u6784\u3002 \u5728\u7b97\u6cd5\u6267\u884c\u8fc7\u7a0b\u4e2d\u4f1a\u6d88\u8017\u4e24\u4e2a\u8d44\u6e90\uff1a\u5904\u7406\u5bf9\u8c61\u6240\u9700\u7684\u65f6\u95f4\u548c\u7a7a\u95f4\uff08\u4e5f\u5c31\u662f\u5185\u5b58\uff09\u3002\u5bf9\u4e8e\u7b97\u6cd5\u6765\u8bf4\uff0c\u603b\u4f1a\u8ffd\u6c42\u6d88\u8017\u66f4\u77ed\u7684\u65f6\u95f4\u548c\u5360\u7528\u66f4\u5c11\u7684\u7a7a\u95f4\u3002\u5728\u9009\u62e9\u7b97\u6cd5\u65f6\uff0c\u901a\u5e38\u5728\u7a7a\u95f4/\u65f6\u95f4\u4e4b\u95f4\u8fdb\u884c\u6743\u8861\u3002 \u7b97\u6cd5\u8d28\u91cf\u7684\u4e3b\u8981\u8bc4\u4f30\u6807\u51c6\uff1a \u6b63\u786e\u6027\uff0c\u5373\u7b97\u6cd5\u80fd\u591f\u771f\u6b63\u89e3\u51b3\u6240\u9488\u5bf9\u7684\u95ee\u9898\uff1b \u53ef\u8bfb\u6027\u548c\u6613\u4e8e\u7ef4\u62a4\u6027\uff1b \u8fd0\u884c\u65f6\u6027\u80fd\uff1b \u76ee\u6807\uff1a \u6839\u636e\u95ee\u9898\u7684\u89c4\u6a21\u786e\u5b9a\u7b97\u6cd5\u5de5\u4f5c\u91cf\u7684\u589e\u957f\u7387\uff1b \u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u6765\u63cf\u8ff0\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\uff1b \u8ba4\u8bc6\u5e38\u89c1\u7684\u5de5\u4f5c\u91cf\u589e\u957f\u7387\u6216\u590d\u6742\u5ea6\u7684\u7c7b\u522b\uff08\u5e38\u6570\u3001\u5bf9\u6570\u3001\u7ebf\u6027\u3001\u5e73\u65b9\u548c\u6307\u6570\uff09\uff1b \u5c06\u7b97\u6cd5\u8f6c\u6362\u4e3a\u590d\u6742\u5ea6\u4f4e\u4e00\u4e2a\u6570\u91cf\u7ea7\u7684\u66f4\u5feb\u7684\u7248\u672c\uff1b \u63cf\u8ff0\u987a\u5e8f\u641c\u7d22\u7b97\u6cd5\u548c\u4e8c\u5206\u641c\u7d22\u7b97\u6cd5\u7684\u5de5\u4f5c\u65b9\u5f0f\uff1b \u63cf\u8ff0\u9009\u62e9\u6392\u5e8f\u7b97\u6cd5\u548c\u5feb\u901f\u6392\u5e8f\u7b97\u6cd5\u7684\u5de5\u4f5c\u65b9\u5f0f\u3002 3.1.\u8861\u91cf\u7b97\u6cd5\u7684\u6548\u7387 \u00b6 \u8861\u91cf\u7b97\u6cd5\u65f6\u95f4\u6210\u672c\u7684\u4e24\u79cd\u65b9\u6cd5\uff1a \u7528\u8ba1\u7b97\u673a\u65f6\u949f\u5f97\u5230\u7b97\u6cd5\u5b9e\u9645\u7684\u8fd0\u884c\u65f6\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u88ab\u79f0\u4e3a\u57fa\u51c6\u6d4b\u8bd5\uff08benchmarking\uff09\u6216\u6027\u80fd\u5206\u6790\uff08profiling\uff09\u3002\u9884\u6d4b\u7b97\u6cd5\u6267\u884c\u7684\u62bd\u8c61\u5de5\u4f5c\u91cf\u4f9d\u8d56\u4e8e\u7279\u5b9a\u7684\u786c\u4ef6\u6216\u8f6f\u4ef6\u5e73\u53f0\u3002 \u5728\u4e0d\u540c\u95ee\u9898\u89c4\u6a21\u4e0b\uff0c\u7edf\u8ba1\u9700\u8981\u6267\u884c\u7684\u6307\u4ee4\u6570\u3002\u9884\u6d4b\u7b97\u6cd5\u6267\u884c\u7684\u62bd\u8c61\u5de5\u4f5c\u91cf\u9002\u7528\u4e8e\u4e0d\u540c\u7684\u786c\u4ef6\u6216\u8f6f\u4ef6\u5e73\u53f0\u3002 3.1.1.\u8861\u91cf\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6 \u00b6 import time problemSize = 10000000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): \"\"\" \u5728\u4e00\u4e2a\u5faa\u73af\u4e2d\uff0c\u5c06\u95ee\u9898\u89c4\u6a21\u7ffb\u500d5\u6b21\uff0c\u8bb0\u5f55\u7b97\u6cd5\u6bcf\u6b21\u8fd0\u884c\u65f6\u95f4\u3002 \"\"\" start = time . time () # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f elapsed = time . time () - start print ( \" %12d%16.3f \" % ( problemSize , elapsed )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Seconds # 10000000 0.689 # 20000000 1.367 # 40000000 2.644 # 80000000 5.296 # 160000000 10.622 \u4e0a\u8ff0\u6d4b\u8bd5\u7a0b\u5e8f\u4f7f\u7528\u4e86 time \u6a21\u5757\u91cc\u7684 time() \u51fd\u6570\u6765\u8bb0\u5f55\u8fd0\u884c\u65f6\uff0c\u5373 time.time() \u3002\u8fd9\u4e2a\u51fd\u6570\u4f1a\u8fd4\u56de\u8ba1\u7b97\u673a\u7684\u5f53\u524d\u65f6\u95f4\u548c1970\u5e741\u67081\u65e5\uff3b\u4e5f\u79f0\u4e3a\u7eaa\u5143\uff08epoch\uff09\uff3d\u76f8\u5dee\u7684\u79d2\u6570\u3002\u4e24\u6b21\u8c03\u7528 time.time() \u7684\u7ed3\u679c\u4e4b\u95f4\u7684\u5dee\u503c\u5c31\u4ee3\u8868\u4e86\u4e2d\u95f4\u7ecf\u5386\u4e86\u591a\u5c11\u79d2\u3002 \u4e0a\u8ff0\u6d4b\u8bd5\u7a0b\u5e8f\u5728\u6bcf\u6b21\u5faa\u73af\u7684\u65f6\u5019\u90fd\u4f1a\u6267\u884c\u4e24\u4e2a\u6269\u5c55\u7684\u8d4b\u503c\u8bed\u53e5\uff0c\u4e5f\u5c31\u662f\u6bcf\u6b21\u90fd\u6267\u884c\u7684\u5de5\u4f5c\u91cf\u662f\u56fa\u5b9a\u7684\uff0c\u4f1a\u6d88\u8017\u4e86\u4e00\u5b9a\u7684\u65f6\u95f4\u3002 \u4fee\u6539\u4e0a\u8ff0\u7b97\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u4ece\u4e0b\u9762\u7684\u8fd0\u884c\u7ed3\u679c\u770b\u51fa\uff0c\u5f53 problemSize \u4e3a 1,000 \u65f6\uff0c\u7b97\u6cd5\u7684\u6d88\u8017\u65f6\u95f4\u5c31\u5df2\u7ecf\u8d85\u8fc7\u4e86\u539f\u5148\u7b97\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u63a8\u65ad\u51fa\u7ee7\u7eed\u6d4b\u8bd5 problemSize \u4e3a 10,000,000 \u7684\u8017\u65f6\u5df2\u7ecf\u53d8\u5f97\u4e0d\u5b9e\u9645\u4e86\u3002 import time problemSize = 1000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): start = time . time () # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): for y in range ( problemSize ): work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f elapsed = time . time () - start print ( \" %12d%16.3f \" % ( problemSize , elapsed )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Seconds # 1000 0.093 # 2000 0.350 # 4000 1.280 # 8000 5.004 # 16000 20.020 \u4e0d\u540c\u7684\u786c\u4ef6\u5e73\u53f0\u4f1a\u6709\u4e0d\u540c\u7684\u5904\u7406\u901f\u5ea6\uff0c\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u4f1a\u56e0\u673a\u5668\u7684\u4e0d\u540c\u800c\u5b58\u5728\u5dee\u5f02\u3002 \u7a0b\u5e8f\u7684\u8fd0\u884c\u65f6\u4e5f\u4f1a\u968f\u7740\u5b83\u548c\u786c\u4ef6\u4e4b\u95f4\u7684\u64cd\u4f5c\u7cfb\u7edf\u7c7b\u578b\u7684\u4e0d\u540c\u800c\u53d8\u5316\u3002 \u4e0d\u540c\u7684\u7f16\u7a0b\u8bed\u8a00\u548c\u7f16\u8bd1\u5668\u751f\u6210\u7684\u4ee3\u7801\u7684\u6027\u80fd\u4e5f\u4f1a\u6709\u6240\u4e0d\u540c\uff0c\u56e0\u6b64\uff0c\u5728\u67d0\u4e00\u4e2a\u786c\u4ef6\u6216\u8f6f\u4ef6\u5e73\u53f0\u4e0a\u6d4b\u5f97\u7684\u8fd0\u884c\u65f6\u7ed3\u679c\u901a\u5e38\u4e0d\u80fd\u7528\u6765\u9884\u6d4b\u5728\u5176\u4ed6\u5e73\u53f0\u4e0a\u7684\u6027\u80fd\u3002 \u7528\u975e\u5e38\u5927\u7684\u6570\u636e\u96c6\u786e\u5b9a\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u662f\u975e\u5e38\u4e0d\u5207\u5b9e\u9645\u7684\u3002\u5bf9\u4e8e\u67d0\u4e9b\u7b97\u6cd5\u6765\u8bf4\uff0c\u4e0d\u8bba\u662f\u7f16\u8bd1\u7684\u4ee3\u7801\u8fd8\u662f\u786c\u4ef6\u5904\u7406\u5668\u7684\u901f\u5ea6\u6709\u591a\u5feb\uff0c\u90fd\u6ca1\u6709\u4efb\u4f55\u7684\u533a\u522b\uff0c\u56e0\u4e3a\u5b83\u4eec\u5728\u4efb\u4f55\u8ba1\u7b97\u673a\u4e0a\u90fd\u6ca1\u529e\u6cd5\u5904\u7406\u975e\u5e38\u5927\u7684\u6570\u636e\u96c6\u3002 3.1.2.\u7edf\u8ba1\u6307\u4ee4\u6570 \u00b6 \u7edf\u8ba1\u6307\u4ee4\u6570\u65f6\uff0c\u7edf\u8ba1\u7684\u662f\u7f16\u5199\u7b97\u6cd5\u7684\u9ad8\u7ea7\u8bed\u8a00\u91cc\u7684\u6307\u4ee4\u6570\uff0c\u800c\u4e0d\u662f\u53ef\u6267\u884c\u673a\u5668\u8bed\u8a00\u7a0b\u5e8f\u91cc\u7684\u6307\u4ee4\u6570\u3002 \u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\u5bf9\u7b97\u6cd5\u8fdb\u884c\u5206\u6790\u65f6\uff0c\u628a\u5b83\u5206\u6210\u4e24\u4e2a\u90e8\u5206\uff1a \u65e0\u8bba\u95ee\u9898\u7684\u89c4\u6a21\u5982\u4f55\u53d8\u5316\uff0c\u6307\u4ee4\u6267\u884c\u7684\u6b21\u6570\u603b\u662f\u76f8\u540c\u7684\uff1b\u6211\u4eec\u5ffd\u7565\u8fd9\u79cd\u7c7b\u578b\uff0c\u56e0\u4e3a\u5206\u6790\u6548\u7387\u65f6\u5b83\u4eec\u7684\u4f5c\u7528\u5e76\u4e0d\u660e\u663e\u3002 \u6267\u884c\u7684\u6307\u4ee4\u6570\u968f\u7740\u95ee\u9898\u89c4\u6a21\u7684\u53d8\u5316\u800c\u53d8\u5316\uff1b\u6211\u4eec\u91cd\u70b9\u5173\u6ce8\u8fd9\u79cd\u7c7b\u578b\uff0c\u8fd9\u79cd\u7c7b\u578b\u7684\u6307\u4ee4\u901a\u5e38\u53ef\u4ee5\u5728\u5faa\u73af\u6216\u8005\u9012\u5f52\u51fd\u6570\u91cc\u627e\u5230\u3002 \u6211\u4eec\u6765\u6539\u5199\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u4ece\u7edf\u8ba1\u8fd0\u884c\u65f6\u95f4\u53d8\u4e3a\u7edf\u8ba1\u8fed\u4ee3\u6b21\u6570\u3002 \u4e0b\u9762\u7684\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u662f\u76f8\u7b49\u7684\u3002 import time problemSize = 10000000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): number = 0 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%16.3f \" % ( problemSize , Iterations )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Iterations # 10000000 10000000.000 # 20000000 20000000.000 # 40000000 40000000.000 # 80000000 80000000.000 # 160000000 160000000.000 \u4e0b\u9762\u7684\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u7684\u5e73\u65b9\u3002\u8fd9\u5c31\u89e3\u91ca\u4e86\u4e3a\u4ec0\u4e48\u8fd9\u4e2a\u7b97\u6cd5\u7684\u8017\u65f6\u975e\u5e38\u5927\u3002 import time problemSize = 1000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): number = 0 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): for y in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%16.3f \" % ( problemSize , number )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Iterations # 1000 1000000.000 # 2000 4000000.000 # 4000 16000000.000 # 8000 64000000.000 # 16000 256000000.000 \u5728\u4e0b\u9762\u7684\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7684\u4f8b\u5b50\u4e2d\uff0c\u51fd\u6570 fib(problemSize, counter) \u4e2d counter \u53c2\u6570\u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u7684\u65f6\u5019\uff0c\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u3002 \u4ece\u4e0b\u9762\u7684\u8fd0\u884c\u7ed3\u679c\u53ef\u4ee5\u770b\u51fa\uff0c\u968f\u7740\u95ee\u9898\u89c4\u6a21\uff08Problem Size\uff09\u7684\u7ffb\u500d\uff0c\u6307\u4ee4\u6570\uff08\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\uff09\u5728\u4e00\u5f00\u59cb\u7684\u65f6\u5019\u7f13\u6162\u589e\u957f\uff0c\u968f\u540e\u8fc5\u901f\u52a0\u5feb\u3002 \u7edf\u8ba1\u6307\u4ee4\u6570\u662f\u6b63\u786e\u7684\u601d\u8def\uff0c\u4f46\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u8fdb\u884c\u8ddf\u8e2a\u8ba1\u6570\u7684\u95ee\u9898\u5728\u4e8e\uff0c\u5bf9\u4e8e\u67d0\u4e9b\u7b97\u6cd5\u6765\u8bf4\uff0c\u5982\u679c\u95ee\u9898\u89c4\u6a21\u975e\u5e38\u5927\uff0c\u8ba1\u7b97\u673a\u65e0\u6cd5\u4ee5\u8db3\u591f\u5feb\u7684\u901f\u5ea6\u8fd0\u884c\uff0c\u5e76\u5728\u4e00\u5b9a\u65f6\u95f4\u5185\u5f97\u5230\u7ed3\u679c\u3002 class Counter ( object ): \"\"\"Models a counter.\"\"\" # Class variable instances = 0 #Constructor def __init__ ( self ): \"\"\"Sets up the counter.\"\"\" Counter . instances += 1 self . reset () # Mutator methods def reset ( self ): \"\"\"Sets the counter to 0.\"\"\" self . _value = 0 def increment ( self , amount = 1 ): \"\"\"Adds amount to the counter.\"\"\" self . _value += amount def decrement ( self , amount = 1 ): \"\"\"Subtracts amount from the counter.\"\"\" self . _value -= amount # Accessor methods def getValue ( self ): \"\"\"Returns the counter's value.\"\"\" return self . _value def __str__ ( self ): \"\"\"Returns the string representation of the counter.\"\"\" return str ( self . _value ) def __eq__ ( self , other ): \"\"\"Returns True if self equals other or False otherwise.\"\"\" if self is other : return True if type ( self ) != type ( other ): return False return self . _value == other . _value def fib ( n , counter ): \"\"\"\u7edf\u8ba1\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u88ab\u5916\u90e8\u8c03\u7528\u7684\u6b21\u6570\"\"\" counter . increment () if n < 3 : return 1 else : return fib ( n - 1 , counter ) + fib ( n - 2 , counter ) problemSize = 2 print ( \" %12s%15s \" % ( \"Problem Size\" , \"Calls\" )) for count in range ( 5 ): \"\"\"\u968f\u7740\u95ee\u9898\u89c4\u6a21\u589e\u52a0\uff0c\u8f93\u51fa\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u51fd\u6570\u88ab\u5916\u90e8\u8c03\u7528\u7684\u6b21\u6570\"\"\" counter = Counter () # \u7b97\u6cd5\u5f00\u59cb fib ( problemSize , counter ) # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%15s \" % ( problemSize , counter )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Calls # 2 1 # 4 5 # 8 41 # 16 1973 # 32 4356617 3.1.3.\u8861\u91cf\u7b97\u6cd5\u4f7f\u7528\u7684\u5185\u5b58 \u00b6 \u5bf9\u4e8e\u7b97\u6cd5\u6240\u7528\u8d44\u6e90\u7684\u5206\u6790\u4e5f\u9700\u8981\u5305\u542b\u5b83\u6240\u9700\u7684\u5185\u5b58\u91cf\u7684\u5206\u6790\u3002\u548c\u524d\u9762\u7c7b\u4f3c\u7684\u95ee\u9898\u4e5f\u4f1a\u5b58\u5728\uff0c\u4e00\u4e9b\u7b97\u6cd5\u4f1a\u968f\u7740\u95ee\u9898\u89c4\u6a21\u53d8\u5927\u800c\u9700\u8981\u989d\u5916\u66f4\u591a\u7684\u5185\u5b58\u3002 3.1.4.\u7ec3\u4e60\u9898 \u00b6 \u7f16\u5199\u4e00\u4e2a\u6d4b\u8bd5\u7a0b\u5e8f\uff0c\u8fd9\u4e2a\u7a0b\u5e8f\u7edf\u8ba1\u5e76\u663e\u793a\u51fa\u4e0b\u9762\u8fd9\u4e2a\u5faa\u73af\u7684\u8fed\u4ee3\u6b21\u6570\u3002 while problemSize > 0 : problemSize = problemSize // 2 \u89e3\u7b54\uff1a def count_iterations ( problemSize ): iterations = 0 # \u521d\u59cb\u5316\u8ba1\u6570\u5668 while problemSize > 0 : problemSize = problemSize // 2 iterations += 1 # \u6bcf\u6b21\u5faa\u73af\u8fed\u4ee3\uff0c\u8ba1\u6570\u5668\u52a0\u4e00 return iterations problemSize = 1000 # \u8bbe\u7f6e\u95ee\u9898\u89c4\u6a21 iterations = count_iterations ( problemSize ) print ( f \"Problem Size: { problemSize } \" ) print ( f \"Iterations: { iterations } \" ) # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size: 1000 # Iterations: 10 \u5728\u95ee\u9898\u89c4\u6a21\u5206\u522b\u4e3a1000\u30012000\u30014000\u300110000\u548c100000\u65f6\uff0c\u8fd0\u884c\u5728\u7ec3\u4e601\u91cc\u6240\u521b\u5efa\u7684\u7a0b\u5e8f\u3002\u5f53\u95ee\u9898\u89c4\u6a21\u7ffb\u500d\u6216\u662f\u4e58\u4ee510\u65f6\uff0c\u8fed\u4ee3\u6b21\u6570\u4f1a\u5982\u4f55\u53d8\u5316\uff1f \u89e3\u7b54\uff1a\u5206\u522b\u4ee5\u4e0d\u540c\u7684\u95ee\u9898\u89c4\u6a21\u8fd0\u884c\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u7ed3\u679c\u5982\u4e0b\uff1a Problem Size : 1000 Iterations : 10 Problem Size : 4000 Iterations : 12 Problem Size : 8000 Iterations : 13 Problem Size : 10000 Iterations : 14 Problem Size : 100000 Iterations : 17 \u4e24\u6b21\u8c03\u7528\u51fd\u6570 time.time() \u7684\u7ed3\u679c\u4e4b\u5dee\u5c31\u662f\u8fd0\u884c\u65f6\u3002\u7531\u4e8e\u64cd\u4f5c\u7cfb\u7edf\u4e5f\u53ef\u80fd\u4f1a\u5728\u8fd9\u6bb5\u65f6\u95f4\u5185\u4f7f\u7528CPU\uff0c\u56e0\u6b64\u8fd9\u4e2a\u8fd0\u884c\u65f6\u53ef\u80fd\u5e76\u4e0d\u80fd\u53cd\u6620\u51faPython\u4ee3\u7801\u4f7f\u7528CPU\u7684\u5b9e\u9645\u65f6\u95f4\u3002\u6d4f\u89c8Python\u6587\u6863\uff0c\u627e\u51fa\u53e6\u4e00\u79cd\u53ef\u4ee5\u5b8c\u6574\u8bb0\u5f55\u5904\u7406\u65f6\u95f4\u7684\u65b9\u6cd5\uff0c\u5e76\u63cf\u8ff0\u5982\u4f55\u5b9e\u73b0\u5b83\u3002 \u89e3\u7b54\uff1a \u5728Python\u4e2d\uff0c time \u6a21\u5757\u63d0\u4f9b\u4e86\u66f4\u7cbe\u786e\u7684\u8ba1\u65f6\u529f\u80fd\uff0c\u5176\u4e2d\u7684 time.perf_counter() \u51fd\u6570\u53ef\u4ee5\u7528\u6765\u6d4b\u91cf\u65f6\u95f4\u7684\u7cbe\u786e\u95f4\u9694\u3002\u4e0e time.time() \u4e0d\u540c\uff0c time. perf_counter() \u4f1a\u5728\u5927\u591a\u6570\u5e73\u53f0\u4e0a\u63d0\u4f9b\u4e00\u4e2a\u66f4\u9ad8\u5206\u8fa8\u7387\u7684\u8ba1\u65f6\u5668\uff0c\u53ef\u4ee5\u7528\u6765\u6d4b\u91cf\u4ee3\u7801\u5757\u7684\u6267\u884c\u65f6\u95f4\u3002 time.perf_counter() \u8fd4\u56de\u4e00\u4e2a\u6d6e\u70b9\u6570\uff0c\u8868\u793a\u4ece\u67d0\u4e2a\u7279\u5b9a\u65f6\u95f4\u70b9\u5230\u73b0\u5728\u7ecf\u8fc7\u7684\u79d2\u6570\u3002\u4ee5\u4e0b\u662f\u5982\u4f55\u4f7f\u7528 time.perf_counter() \u6765\u8ba1\u7b97\u4ee3\u7801\u5757\u7684\u6267\u884c\u65f6\u95f4\uff1a import time # \u83b7\u53d6\u8d77\u59cb\u65f6\u95f4\uff08\u5305\u62ecCPU\u65f6\u95f4\u548c\u7cfb\u7edf\u65f6\u95f4\uff09 start_cpu_time = time . process_time () start_real_time = time . perf_counter () start_system_time = time . time () # \u6267\u884c\u4ee3\u7801 for i in range ( 100000000 ): _ = i * i # \u83b7\u53d6\u7ed3\u675f\u65f6\u95f4\uff08\u5305\u62ecCPU\u65f6\u95f4\u548c\u7cfb\u7edf\u65f6\u95f4\uff09 end_cpu_time = time . process_time () end_real_time = time . perf_counter () end_system_time = time . time () # \u8ba1\u7b97CPU\u65f6\u95f4\u5dee cpu_execution_time = end_cpu_time - start_cpu_time real_execution_time = end_real_time - start_real_time system_execution_time = end_system_time - start_system_time print ( f \"CPU Execution Time: { cpu_execution_time : .6f } seconds\" ) print ( f \"Real Execution Time: { real_execution_time : .6f } seconds\" ) print ( f \"System Execution Time: { system_execution_time : .6f } seconds\" ) # \u8fd0\u884c\u7ed3\u679c\uff1a # CPU Execution Time: 7.157305 seconds # Real Execution Time: 7.156638 seconds # System Execution Time: 7.156638 seconds \u5728\u4e0a\u9762\u4ee3\u7801\u4e2d\uff0c start_system_time \u548c end_system_time \u5206\u522b\u8bb0\u5f55\u4e86\u4ee3\u7801\u5757\u5f00\u59cb\u548c\u7ed3\u675f\u65f6\u7684\u7cfb\u7edf\u65f6\u95f4\u3002\u7136\u540e\uff0c\u53ef\u4ee5\u901a\u8fc7\u8ba1\u7b97 end_system_time - start_system_time \u6765\u83b7\u53d6\u7cfb\u7edf\u65f6\u95f4\u7684\u6d88\u8017\u3002 \u7cfb\u7edf\u65f6\u95f4\u7684\u8ba1\u7b97\u53ef\u80fd\u53d7\u5230\u7cfb\u7edf\u7684\u5f71\u54cd\uff0c\u53ef\u80fd\u4f1a\u56e0\u4e3a\u7cfb\u7edf\u65f6\u95f4\u7684\u53d8\u5316\u800c\u4ea7\u751f\u4e0d\u51c6\u786e\u7684\u7ed3\u679c\u3002\u5728\u8fdb\u884c\u6027\u80fd\u6d4b\u8bd5\u65f6\uff0c\u5c3d\u91cf\u4ee5CPU\u65f6\u95f4\u548c\u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u4e3a\u4e3b\u8981\u53c2\u8003\u6307\u6807\u3002 \u8865\u5145\uff1a CPU \u65f6\u95f4\u3001\u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u548c\u7cfb\u7edf\u65f6\u95f4\u4ee3\u8868\u4e86\u4e0d\u540c\u7684\u65f6\u95f4\u6307\u6807\uff0c\u5b83\u4eec\u4e4b\u95f4\u6709\u4ee5\u4e0b\u533a\u522b\uff1a CPU \u65f6\u95f4\uff1a - CPU \u65f6\u95f4\u662f\u7a0b\u5e8f\u5728 CPU \u4e0a\u6267\u884c\u7684\u65f6\u95f4\uff0c\u5305\u62ec\u4e86\u5728\u7528\u6237\u6001\uff08\u6267\u884c\u5e94\u7528\u7a0b\u5e8f\u4ee3\u7801\uff09\u548c\u5185\u6838\u6001\uff08\u6267\u884c\u64cd\u4f5c\u7cfb\u7edf\u4ee3\u7801\uff09\u7684\u65f6\u95f4\u3002\u56e0\u6b64\uff0c\u5b83\u8003\u8651\u4e86\u5e94\u7528\u7a0b\u5e8f\u548c\u64cd\u4f5c\u7cfb\u7edf\u7684\u6267\u884c\u65f6\u95f4\u3002 - CPU \u65f6\u95f4\u901a\u5e38\u7528\u4e8e\u6d4b\u91cf\u7a0b\u5e8f\u7684\u8ba1\u7b97\u5bc6\u96c6\u578b\u5de5\u4f5c\u91cf\uff0c\u5373\u5927\u91cf\u8ba1\u7b97\u64cd\u4f5c\uff0c\u6bd4\u5982\u5faa\u73af\u548c\u6570\u5b66\u8ba1\u7b97\u3002 - \u901a\u8fc7 time.process_time() \u51fd\u6570\u53ef\u4ee5\u83b7\u53d6\u5f53\u524d\u8fdb\u7a0b\u7684 CPU \u65f6\u95f4\u3002 \u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\uff1a - \u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u662f\u4ece\u67d0\u4e2a\u65f6\u95f4\u70b9\u5230\u73b0\u5728\u7684\u5b9e\u9645\u7ecf\u8fc7\u7684\u65f6\u95f4\uff0c\u8003\u8651\u4e86\u6240\u6709\u56e0\u7d20\uff0c\u5305\u62ec\u4e86 CPU \u65f6\u95f4\u3001\u7b49\u5f85\u65f6\u95f4\u3001\u7cfb\u7edf\u8c03\u5ea6\u7b49\u3002 - \u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u7528\u4e8e\u6d4b\u91cf\u4ee3\u7801\u7684\u603b\u6267\u884c\u65f6\u95f4\uff0c\u5305\u62ec\u4e86\u8ba1\u7b97\u548c\u7b49\u5f85\u7684\u65f6\u95f4\u3002 - \u901a\u8fc7 time.perf_counter() \u51fd\u6570\u53ef\u4ee5\u83b7\u53d6\u5f53\u524d\u65f6\u95f4\u3002 \u7cfb\u7edf\u65f6\u95f4\uff1a - \u7cfb\u7edf\u65f6\u95f4\u662f\u64cd\u4f5c\u7cfb\u7edf\u5185\u90e8\u7ef4\u62a4\u7684\u4e00\u4e2a\u65f6\u95f4\u503c\uff0c\u5b83\u4ee3\u8868\u4e86\u4ece\u67d0\u4e2a\u56fa\u5b9a\u65f6\u95f4\u70b9\u5f00\u59cb\u7684\u79d2\u6570\u3002 - \u7cfb\u7edf\u65f6\u95f4\u901a\u5e38\u7528\u4e8e\u8bb0\u5f55\u4e8b\u4ef6\u548c\u8ba1\u7b97\u65f6\u95f4\u95f4\u9694\uff0c\u4e0d\u53d7\u7a0b\u5e8f\u7684\u6267\u884c\u5f71\u54cd\u3002 - \u901a\u8fc7 time.time() \u51fd\u6570\u53ef\u4ee5\u83b7\u53d6\u5f53\u524d\u7684\u7cfb\u7edf\u65f6\u95f4\u3002 \u603b\u7ed3\uff1aCPU \u65f6\u95f4\u5173\u6ce8\u7684\u662f\u7a0b\u5e8f\u5728 CPU \u4e0a\u7684\u6267\u884c\u65f6\u95f4\uff0c\u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u5173\u6ce8\u7684\u662f\u4ece\u4ee3\u7801\u5f00\u59cb\u5230\u7ed3\u675f\u6240\u7ecf\u8fc7\u7684\u771f\u5b9e\u65f6\u95f4\uff0c\u7cfb\u7edf\u65f6\u95f4\u662f\u7cfb\u7edf\u7ef4\u62a4\u7684\u5168\u5c40\u65f6\u95f4\u3002\u5728\u4e0d\u540c\u7684\u573a\u666f\u4e2d\uff0c\u4f60\u53ef\u4ee5\u6839\u636e\u9700\u8981\u9009\u62e9\u5408\u9002\u7684\u65f6\u95f4\u6307\u6807\u6765\u8fdb\u884c\u6027\u80fd\u6d4b\u91cf\u548c\u5206\u6790\u3002 3.2.\u590d\u6742\u5ea6\u5206\u6790 \u00b6 \u590d\u6742\u5ea6\u5206\u6790\uff08complexity analysis\uff09\u65b9\u6cd5\uff0c\u4e00\u79cd\u8bc4\u4f30\u7b97\u6cd5\u6548\u7387\u7684\u65b9\u6cd5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u53ef\u4ee5\u4e0d\u7528\u5173\u5fc3\u4e0e\u5e73\u53f0\u76f8\u5173\u7684\u65f6\u95f4\uff0c\u4e5f\u4e0d\u9700\u8981\u4f7f\u7528\u7edf\u8ba1\u6307\u4ee4\u6570\u91cf\u8fd9\u79cd\u65b9\u6cd5\u6765\u5bf9\u7b97\u6cd5\u8fdb\u884c\u8bc4\u4f30\u3002 3.2.1.\u590d\u6742\u5ea6\u7684\u9636 \u00b6 \u5728 3.1.2.\u7edf\u8ba1\u6307\u4ee4\u6570 \u4e2d\u5173\u4e8e\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u7684\u4e24\u4e2a\u7b97\u6cd5\uff0c\u5b83\u4eec\u590d\u6742\u5ea6\u7684\u9636\uff08order of complexity\uff09\u4e0a\u662f\u4e0d\u4e00\u6837\u7684\u3002 \u7b2c\u4e00\u4e2a\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u4e4b\u95f4\u662f\u7ebf\u6027\u5173\u7cfb\uff0c\u79f0\u5176\u590d\u6742\u5ea6\u4e3a\u7ebf\u6027\uff08linear\uff09\u9636\uff1b \u7b2c\u4e8c\u4e2a\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u4e4b\u95f4\u662f\u5e73\u65b9\u5173\u7cfb\uff0c\u79f0\u5176\u590d\u6742\u5ea6\u4e3a\u5e73\u65b9\uff08quadratic\uff09\u9636\uff1b \u5982\u679c\u7b97\u6cd5\u9700\u8981\u76f8\u540c\u6570\u91cf\u7684\u8fd0\u7b97\uff0c\u90a3\u4e48\u5b83\u7684\u6027\u80fd\u5c31\u662f\u5e38\u6570\uff08constant\uff09\u9636\u3002\u5217\u8868\u7d22\u5f15\u5c31\u662f\u4e00\u4e2a\u5e38\u6570\u65f6\u95f4\u7b97\u6cd5\u7684\u4f8b\u5b50\u3002 \u6bd4\u7ebf\u6027\u6027\u80fd\u597d\uff0c\u4f46\u6bd4\u5e38\u6570\u6027\u80fd\u5dee\u7684\u53e6\u4e00\u4e2a\u590d\u6742\u5ea6\u7684\u9636\u88ab\u79f0\u4e3a\u5bf9\u6570\uff08logarithmic\uff09\u9636\u3002\u5bf9\u6570\u7b97\u6cd5\u7684\u5de5\u4f5c\u91cf\u4e0e\u95ee\u9898\u89c4\u6a21\u7684\u4ee52\u4e3a\u5e95\u7684\u5bf9\u6570\u6210\u6b63\u6bd4\u3002\u5f53\u95ee\u9898\u89c4\u6a21\u6269\u5927\u4e00\u500d\u65f6\uff0c\u5de5\u4f5c\u91cf\u53ea\u4f1a\u52a01\u3002 \u591a\u9879\u5f0f\u65f6\u95f4\u7b97\u6cd5\uff08polynomial time algorithm\uff09\u7684\u5de5\u4f5c\u91cf\u4f1a\u4ee5 n^k \u7684\u901f\u7387\u589e\u957f\uff0c\u5176\u4e2d k \u662f\u5927\u4e8e 1 \u7684\u5e38\u6570\uff0c\u6bd4\u5982 n^2 \u3001 n^3 \u4ee5\u53ca n^10 \u3002\u4ece\u67d0\u79cd\u610f\u4e49\u4e0a\u8bb2\uff0c n^3 \u7684\u6027\u80fd\u8981\u6bd4 n^2 \u5dee\uff0c\u4f46\u90fd\u5c5e\u4e8e\u591a\u9879\u5f0f\uff08polynomial\uff09\u9636\u3002 \u6bd4\u591a\u9879\u5f0f\u8fd8\u8981\u5dee\u7684\u590d\u6742\u5ea6\u7684\u9636\u88ab\u79f0\u4e3a\u6307\u6570\uff08exponential\uff09\u9636\uff0c\u6bd4\u5982 2^n \u3002\u5bf9\u4e8e\u5927\u7684\u95ee\u9898\u89c4\u6a21\u6765\u8bf4\uff0c\u6307\u6570\u7b97\u6cd5\u662f\u4e0d\u53ef\u884c\u7684\u3002 \u4e0d\u540c\u590d\u6742\u5ea6\u9636\u7684\u7b97\u6cd5\u7684\u5de5\u4f5c\u91cf\u6bd4\u8f83\uff08\u4ece\u5c0f\u5230\u5927\uff09\uff1a\u5bf9\u6570\u9636 < \u7ebf\u6027\u9636 < \u5e73\u65b9\u9636 < \u6307\u6570\u9636\u3002\u968f\u7740\u95ee\u9898\u89c4\u6a21\u7684\u589e\u5927\uff0c\u5177\u6709\u8f83\u9ad8\u590d\u6742\u5ea6\u7684\u9636\u7684\u7b97\u6cd5\u7684\u6027\u80fd\u4f1a\u66f4\u5feb\u5730\u53d8\u5dee\u3002 3.2.2.\u5927O\u8868\u793a\u6cd5 \u00b6 \u5f88\u591a\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u4e2d\u7684\u5de5\u4f5c\u91cf\u901a\u5e38\u662f\u591a\u9879\u5f0f\u91cc\u591a\u9879\u7684\u603b\u548c\uff0c\u800c\u5f53\u5de5\u4f5c\u91cf\u8868\u793a\u4e3a\u591a\u9879\u5f0f\u65f6\uff0c\u5176\u4e2d\u4e00\u9879\u662f\u4e3b\u5bfc\u9879\uff08dominant\uff09\u3002\u968f\u7740 n \u8d8a\u6765\u8d8a\u5927\uff0c\u4e3b\u5bfc\u9879\u5c06\u53d8\u5f97\u975e\u5e38\u5927\uff0c\u4ee5\u81f3\u4e8e\u53ef\u4ee5\u5ffd\u7565\u5176\u4ed6\u9879\u6240\u4ee3\u8868\u7684\u5de5\u4f5c\u91cf\u3002\u56e0\u6b64\uff0c\u5bf9\u4e8e\u591a\u9879\u5f0f n^2+n \uff0c\u53ea\u9700\u8981\u7740\u91cd\u8003\u8651\u5e73\u65b9\u9879 n^2 \uff0c\u4e5f\u5c31\u662f\u5728\u8003\u8651\u7684\u65f6\u5019\u53ef\u4ee5\u5ffd\u7565\u7ebf\u6027\u9879 n \u3002\u968f\u7740 n^2 \u53d8\u5f97\u975e\u5e38\u5927\uff0c\u591a\u9879\u5f0f\u7684\u503c\u6e10\u8fd1\u5730\u63a5\u8fd1\u6216\u8fd1\u4f3c\u4e8e\u5b83\u7684\u6700\u5927\u9879\u503c\uff0c\u8fd9\u79cd\u5f62\u5f0f\u7684\u5206\u6790\u6709\u65f6\u88ab\u79f0\u4e3a\u6e10\u8fd1\u5206\u6790\uff08asymptotic analysis\uff09\u3002 \u8ba1\u7b97\u4e2d\u7528\u6765\u8868\u793a\u7b97\u6cd5\u7684\u6548\u7387\u6216\u8ba1\u7b97\u590d\u6742\u5ea6\u7684\u4e00\u79cd\u65b9\u6cd5\u88ab\u79f0\u4e3a\u5927O\u8868\u793a\u6cd5\uff08big-O notation\uff09\u3002\u201cO\u201d\u4ee3\u8868\u201c\u5728\u2026\u2026\u9636\u201d\uff0c\u6307\u7684\u662f\u7b97\u6cd5\u5de5\u4f5c\u7684\u590d\u6742\u5ea6\u7684\u9636\u3002\u4f8b\u5982\uff1a \u5e38\u6570\u65f6\u95f4\uff1aO(1) \u7ebf\u6027\u65f6\u95f4\uff1aO(n) \u5e73\u65b9\u65f6\u95f4\uff1aO(n^2) \u7acb\u65b9\u65f6\u95f4\uff1aO(n^3) \u591a\u9879\u5f0f\u65f6\u95f4\uff1aO(n^k) 3.2.3.\u6bd4\u4f8b\u5e38\u6570\u7684\u4f5c\u7528 \u00b6 \u6bd4\u4f8b\u5e38\u6570\uff08constant of proportionality\uff09\u5305\u542b\u5728\u5927O\u5206\u6790\u4e2d\u88ab\u5ffd\u7565\u7684\u9879\u548c\u7cfb\u6570\u3002\u6bd4\u5982\uff0c\u7ebf\u6027\u65f6\u95f4\u7b97\u6cd5\u6240\u6267\u884c\u7684\u5de5\u4f5c\u91cf\u53ef\u4ee5\u8868\u793a\u4e3a\uff1a work = 2 * size \uff0c\u5176\u4e2d\u6bd4\u4f8b\u5e38\u6570\u5c31\u662f work/size \uff0c\u4e5f\u5c31\u662f 2 \u3002\u5728\u5904\u7406\u4e2d\u5c0f\u578b\u6570\u636e\u96c6\u7684\u65f6\u5019\uff0c\u5982\u679c\u8fd9\u4e9b\u5e38\u6570\u5f88\u5927\uff0c\u90a3\u4e48\u5b83\u4eec\u4e5f\u4f1a\u5f71\u54cd\u5230\u7b97\u6cd5\u6548\u7387\u3002 \u56de\u987e\u4e0b\u9762\u7684\u4f8b\u5b50\u3002 import time problemSize = 10000000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): number = 0 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%16.3f \" % ( problemSize , Iterations )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Iterations # 10000000 10000000.000 # 20000000 20000000.000 # 40000000 40000000.000 # 80000000 80000000.000 # 160000000 160000000.000 \u5176\u4e2d\u7684\u7b97\u6cd5\u90e8\u5206\uff0c\u9664\u4e86\u5faa\u73af\u8bed\u53e5\u672c\u8eab\uff0c\u8fd8\u6709\u5176\u4ed63\u884c\u4ee3\u7801\uff0c\u5b83\u4eec\u90fd\u662f\u590d\u5236\u8bed\u53e5\uff0c\u90fd\u4f1a\u4ee5\u5e38\u6570\u65f6\u95f4\u8fd0\u884c\u3002\u5047\u8bbe\u5faa\u73af\u8bed\u53e5\u672c\u8eab\u4f1a\u6d88\u8017\u4e00\u4e2a\u65f6\u95f4\u5e38\u6570\uff0c\u90a3\u4e48\u8fd9\u4e2a\u7b97\u6cd5\u7684\u62bd\u8c61\u5de5\u4f5c\u65f6\u95f4\u5c31\u662f 3n+1 \u3002\u867d\u7136 3n+1 \u7684\u5de5\u4f5c\u91cf\u5927\u4e8e n \uff0c\u4f46\u4e8c\u8005\u5728\u8fd0\u884c\u65f6\u90fd\u662f\u7ebf\u6027\u589e\u52a0\uff0c\u6240\u4ee5\u4ed6\u4eec\u8fd0\u884c\u65f6\u90fd\u662f O(n) \u3002 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f 3.2.4.\u7ec3\u4e60\u9898 \u00b6 \u5047\u8bbe\u4e0b\u9762\u7684\u8868\u8fbe\u5f0f\u90fd\u5206\u522b\u8868\u793a\u5bf9\u95ee\u9898\u89c4\u6a21\u4e3a n \u7684\u7b97\u6cd5\u6240\u9700\u8981\u6267\u884c\u7684\u64cd\u4f5c\u6570\uff0c\u8bf7\u6307\u51fa\u6bcf\u79cd\u7b97\u6cd5\u4e2d\u7684\u4e3b\u5bfc\u9879\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u5bf9\u5b83\u8fdb\u884c\u5206\u7c7b\u3002 a. 2^n - 4n + 5n b. 2n^2 + 8 c. n^3 n^2 + n \u89e3\u7b54\uff1a a. 2^n\uff0cO(n) b. n 2\uff0cO(n 2) c. n 3\uff0cO(n 3) \u5bf9\u4e8e\u89c4\u6a21\u4e3a n \u7684\u95ee\u9898\uff0c\u7b97\u6cd5A\u548cB\u5206\u522b\u4f1a\u6267\u884c n^2 \u548c (1/2)*n^2+(1/2)*n \u6761\u6307\u4ee4\u3002\u54ea\u79cd\u7b97\u6cd5\u66f4\u9ad8\u6548\uff1f\u6709\u6ca1\u6709\u4e00\u79cd\u7b97\u6cd5\u6bd4\u53e6\u4e00\u79cd\u7b97\u6cd5\u6027\u80fd\u660e\u663e\u66f4\u597d\u7684\u7279\u5b9a\u7684\u95ee\u9898\u89c4\u6a21\uff1f\u662f\u5426\u6709\u8ba9\u4e24\u79cd\u7b97\u6cd5\u90fd\u6267\u884c\u5927\u81f4\u76f8\u540c\u5de5\u4f5c\u91cf\u7684\u7279\u5b9a\u7684\u95ee\u9898\u89c4\u6a21\uff1f \u89e3\u7b54\uff1a \u5728\u6bd4\u8f83\u4e24\u79cd\u7b97\u6cd5\u7684\u6548\u7387\u65f6\uff0c\u901a\u5e38\u5173\u6ce8\u7b97\u6cd5\u6267\u884c\u65f6\u95f4\u968f\u95ee\u9898\u89c4\u6a21\u589e\u957f\u7684\u8d8b\u52bf\u3002\u9898\u76ee\u4e2d\u7684\u4e24\u79cd\u7b97\u6cd5\u7684\u6267\u884c\u6307\u4ee4\u6570\u5206\u522b\u5982\u4e0b\uff1a \u7b97\u6cd5A\uff1a\u6267\u884c n^2 \u6761\u6307\u4ee4\u3002 \u7b97\u6cd5B\uff1a\u6267\u884c (1/2)*n^2+(1/2)*n \u6761\u6307\u4ee4\u3002 \u7528\u5982\u4e0b\u4ee3\u7801\u6a21\u62df\u7b97\u6cd5A\u548c\u7b97\u6cd5B\uff0c\u53ef\u4ee5\u770b\u51fa\uff0c\u968f\u7740 n \u7684\u589e\u52a0\uff0c\u7b97\u6cd5A\u7684\u589e\u957f\u901f\u7387\u8fdc\u5927\u4e8e\u7b97\u6cd5B\u3002\u6240\u4ee5\u53ef\u4ee5\u8ba4\u4e3a\u5728 n >= 2 \u7684\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5A\u4f18\u4e8e\u7b97\u6cd5B\u3002 n = 1 print ( \" %-15s%25s \" % ( \"ProblemSize: n\" , \"A/B\" )) while n < 1000000 : n *= 10 print ( \" %-15d%25d \" % ( n , int (( n ** 2 ) / ( 1 / 2 ) * n ** 2 + ( 1 / 2 ) * n ))) # ProblemSize: n A/B # 10 20005 # 100 200000050 # 1000 2000000000500 # 10000 20000000000005000 # 100000 200000000000000065536 # 1000000 1999999999999999966445568 \u7531\u6b64\u53ef\u5f97\uff0c\u5728\u5927\u95ee\u9898\u89c4\u6a21\u4e0b\uff0c\u7b97\u6cd5B\u7684\u589e\u957f\u901f\u7387\u4f1a\u66f4\u6162\uff0c\u56e0\u4e3a (1/2)*n^2+(1/2)*n \u4e2d\u7684 (1/2)*n \u90e8\u5206\u5bf9\u4e8e\u6574\u4f53\u589e\u957f\u6765\u8bf4\u76f8\u5bf9\u8f83\u5c0f\u3002 \u4e3a\u4e86\u8ba9\u4e24\u79cd\u7b97\u6cd5\u6267\u884c\u76f8\u8fd1\u7684\u5de5\u4f5c\u91cf\uff0c\u6211\u4eec\u53ef\u4ee5\u89e3\u4e0b\u9762\u7684\u65b9\u7a0b\uff1a ( 1 / 2 ) * n ^ 2 + ( 1 / 2 ) * n = k * n ^ 2 \u5176\u4e2d k \u662f\u4e00\u4e2a\u5e38\u6570\uff0c\u8868\u793a\u4e24\u79cd\u7b97\u6cd5\u6267\u884c\u7684\u5de5\u4f5c\u91cf\u76f8\u7b49\u65f6\u7684\u95ee\u9898\u89c4\u6a21\u3002\u901a\u8fc7\u89e3\u8fd9\u4e2a\u65b9\u7a0b\uff0c\u6211\u4eec\u53ef\u4ee5\u627e\u5230\u4e00\u4e2a\u95ee\u9898\u89c4\u6a21 k \uff0c\u5728\u8fd9\u4e2a\u95ee\u9898\u89c4\u6a21\u4e0b\uff0c\u4e24\u79cd\u7b97\u6cd5\u7684\u6267\u884c\u6307\u4ee4\u6570\u76f8\u8fd1\u3002 \u7b97\u6cd5\u7684\u6548\u7387\u5206\u6790\u5e76\u4e0d\u4ec5\u4ec5\u53d6\u51b3\u4e8e\u6307\u4ee4\u6570\uff0c\u8fd8\u53ef\u80fd\u53d7\u5230\u7b97\u6cd5\u4e2d\u5e38\u6570\u56e0\u5b50\u3001\u6570\u636e\u8bbf\u95ee\u6a21\u5f0f\u3001\u5185\u5b58\u5360\u7528\u7b49\u56e0\u7d20\u7684\u5f71\u54cd\u3002\u56e0\u6b64\uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u901a\u5e38\u9700\u8981\u7efc\u5408\u8003\u8651\u591a\u4e2a\u56e0\u7d20\u6765\u786e\u5b9a\u6700\u4f18\u7684\u7b97\u6cd5\u9009\u62e9\u3002 \u5728\u4ec0\u4e48\u65f6\u5019\u5f00\u59cb n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u8868\u73b0\u66f4\u597d\uff1f \u89e3\u7b54\uff1a\u7528\u4e0b\u9762\u7684\u7b97\u6cd5\u6a21\u62df n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u6267\u884c\u5de5\u4f5c\u91cf\u3002\u4ece\u8fd0\u884c\u7ed3\u679c\u53ef\u4ee5\u770b\u51fa\uff1a n=16 \u662f\u5206\u754c\u70b9\uff0c n^4 \u7b97\u6cd5\u4e0e 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u76f8\u7b49\uff1b \u5f53 n<16 \u65f6\uff0c n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u8981\u9ad8\uff1b \u5f53 n>16 \u65f6\uff0c n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u8981\u4f4e\uff1b\u800c\u4e14 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u589e\u957f\u901f\u5ea6\u8fdc\u5927\u4e8e n^4 \u7b97\u6cd5\uff1b n = 1 print ( \" %-8s%10s%15s%10s \" % ( \"Size:n\" , \"A:n^4\" , \"B:2^n\" , \"B/A\" )) while n < 30 : n += 1 print ( \" %-8d%10d%15d%10.3f \" % ( n , int ( n ** 4 ), int ( 2 ** n ), ( 2 ** n ) / ( n ** 4 ))) # \u8fd0\u884c\u7ed3\u679c\uff1a # Size:n A:n^4 B:2^n B/A # 2 16 4 0.250 # 3 81 8 0.099 # 4 256 16 0.062 # 5 625 32 0.051 # 6 1296 64 0.049 # 7 2401 128 0.053 # 8 4096 256 0.062 # 9 6561 512 0.078 # 10 10000 1024 0.102 # 11 14641 2048 0.140 # 12 20736 4096 0.198 # 13 28561 8192 0.287 # 14 38416 16384 0.426 # 15 50625 32768 0.647 # 16 65536 65536 1.000 # 17 83521 131072 1.569 # 18 104976 262144 2.497 # 19 130321 524288 4.023 # 20 160000 1048576 6.554 # 21 194481 2097152 10.783 # 22 234256 4194304 17.905 # 23 279841 8388608 29.976 # 24 331776 16777216 50.568 # 25 390625 33554432 85.899 # 26 456976 67108864 146.854 # 27 531441 134217728 252.554 # 28 614656 268435456 436.725 # 29 707281 536870912 759.063 # 30 810000 1073741824 1325.607 3.3.\u641c\u7d22\u7b97\u6cd5 \u00b6 \u7ea6\u5b9a\uff1a \u4ee5\u5217\u8868\u4e3a\u4f8b\uff0c\u4ecb\u7ecd\u641c\u7d22\u548c\u6392\u5e8f\u7684\u7b97\u6cd5\uff1b \u9610\u91ca\u8fd9\u4e9b\u7b97\u6cd5\u7684\u8bbe\u8ba1\uff0c\u5e76\u628a\u5b83\u5b9e\u73b0\u4e3aPython\u51fd\u6570\uff1b \u51fd\u6570\u53ea\u5904\u7406\u5168\u90e8\u662f\u6574\u6570\u7684\u5217\u8868\uff0c\u4e0d\u540c\u5927\u5c0f\u7684\u5217\u8868\u5c06\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7ed9\u51fd\u6570\uff1b \u5bf9\u8fd9\u4e9b\u7b97\u6cd5\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u8fdb\u884c\u5206\u6790\uff1b 3.3.1.\u6700\u5c0f\u503c\u641c\u7d22 \u00b6 Python\u4e2d\u6709 min \u51fd\u6570\uff0c\u4f1a\u8fd4\u56de\u5217\u8868\u91cc\u7684\u6700\u5c0f\u503c\u6216\u6700\u5c0f\u5143\u7d20\uff0c\u4e0b\u9762\u5199\u4e00\u4e2a\u65b0\u7b97\u6cd5\uff0c\u6765\u5206\u6790 min \u51fd\u6570\u7684\u7b97\u6cd5\u590d\u6742\u5ea6\u3002 \u7b97\u6cd5\u76ee\u6807\uff1a\u5047\u5b9a\u5217\u8868\u4e0d\u4e3a\u7a7a\uff0c\u5e76\u4e14\u5143\u7d20\u662f\u6309\u7167\u4efb\u610f\u987a\u5e8f\u5b58\u653e\u5728\u5217\u8868\u91cc\u7684\uff0c\u7b97\u6cd5\u8fd4\u56de\u6700\u5c0f\u5143\u7d20\u7684\u7d22\u5f15\uff08index\uff09\u3002 \u7b97\u6cd5\u89e3\u6790\uff1a \u9996\u5148\u628a\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u4f5c\u4e3a\u5b58\u653e\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\uff1b \u7136\u540e\u5411\u53f3\u4fa7\u641c\u7d22\u66f4\u5c0f\u7684\u5143\u7d20\uff1b \u5982\u679c\u627e\u5230\uff0c\u90a3\u4e48\u628a\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\u91cd\u7f6e\u4e3a\u5f53\u524d\u4f4d\u7f6e\uff1b \u5f53\u7b97\u6cd5\u5230\u8fbe\u5217\u8868\u672b\u5c3e\u65f6\uff0c\u5b83\u5c06\u8fd4\u56de\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\u3002 \u7b97\u6cd5\u5b9e\u73b0\uff1a def indexOfMin ( lyst ): \"\"\"\u8fd4\u56de\u6700\u5c0f\u5143\u7d20\u7684\u7d22\u5f15\uff0c\u76f8\u540c\u6700\u5c0f\u5143\u7d20\u8fd4\u56de\u7b2c\u4e00\u4e2a\u7d22\u5f15\"\"\" # \u7b97\u6cd5\u5f00\u59cb minIndex = 0 currentIndex = 1 while currentIndex < len ( lyst ): if lyst [ currentIndex ] < lyst [ minIndex ]: # \u6539\u6210<=\uff0c\u76f8\u540c\u6700\u5c0f\u5143\u7d20\u5219\u8fd4\u56de\u6700\u540e\u4e00\u4e2a\u7d22\u5f15 minIndex = currentIndex currentIndex += 1 return minIndex # \u7b97\u6cd5\u7ed3\u675f def main (): myList = [ 2 , 20 , 5 , 0 , 1 , 0 , 9 ] minIndex = indexOfMin ( myList ) print ( minIndex , myList [ minIndex ]) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # 3 0 # \u5982\u679c\u6539\u6210\u6539\u6210yst[currentIndex] <= lyst[minIndex]\uff0c\u5219\u76f8\u540c\u6700\u5c0f\u5143\u7d20\u5219\u8fd4\u56de\u6700\u540e\u4e00\u4e2a\u7d22\u5f15 # 5 0 \u65e0\u8bba\u5217\u8868\u7684\u5927\u5c0f\u5982\u4f55\uff0c\u5faa\u73af\u5916\u76843\u6761\u6307\u4ee4\uff082\u6761\u8d4b\u503c\u8bed\u53e5\uff0c\u4e00\u6761while\u8bed\u53e5\u672c\u8eab\uff09\u90fd\u4f1a\u6267\u884c\u76f8\u540c\u7684\u6b21\u6570\uff0c\u53ef\u4ee5\u5ffd\u7565\u5b83\u4eec\u90fd\u5f71\u54cd\u3002 \u5faa\u73af\u91cc\u8fd8\u67093\u6761\u6307\u4ee4\uff0c\u5176\u4e2d if \u8bed\u53e5\u5185\u7684\u6bd4\u8f83 lyst[currentIndex] < lyst[minIndex] \u548c currentIndex += 1 \u7684\u81ea\u589e\uff0c\u4f1a\u5728\u6bcf\u6b21\u5faa\u73af\u65f6\u90fd\u6267\u884c\uff0c\u4e14\u6ca1\u6709\u5176\u5b83\u5d4c\u5957\u6216\u9690\u85cf\u7684\u5faa\u73af\u3002 if \u8bed\u53e5\u4e2d\u7684\u6bd4\u8f83\u64cd\u4f5c\u5b9e\u73b0\u4e86\u8bbf\u95ee\u5217\u8868\u91cc\u7684\u6bcf\u4e2a\u5143\u7d20\uff0c\u4ece\u800c\u80fd\u591f\u627e\u5230\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\u3002 \u56e0\u6b64\uff0c\u8fd9\u4e2a\u7b97\u6cd5\u5fc5\u987b\u5bf9\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\u8fdb\u884c n-1 \u6b21\u6bd4\u8f83\uff0c\u5373\uff0c\u5b83\u7684\u590d\u6742\u5ea6\u4e3aO(n)\u3002 3.3.2.\u987a\u5e8f\u641c\u7d22\u5217\u8868 \u00b6 Python\u7684 in \u8fd0\u7b97\u7b26\u5728list\u7c7b\u91cc\u88ab\u5b9e\u73b0\u4e3a\u53eb\u4f5c __contains__ \u7684\u65b9\u6cd5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u5728\u4efb\u610f\u7684\u5143\u7d20\u5217\u8868\u91cc\u641c\u7d22\u7279\u5b9a\u7684\u5143\u7d20\uff0c\u5373\u76ee\u6807\u5143\u7d20\uff08target item\uff09\u3002 \u5728\u5217\u8868\u91cc\uff0c\u627e\u5230\u76ee\u6807\u5143\u7d20\u7684\u552f\u4e00\u65b9\u6cd5\u662f\u4ece\u4f4d\u4e8e\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u5f00\u59cb\uff0c\u5e76\u628a\u5b83\u548c\u76ee\u6807\u5143\u7d20\u8fdb\u884c\u6bd4\u8f83\u3002\u5982\u679c\u4e24\u4e2a\u5143\u7d20\u76f8\u7b49\uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u8fd4\u56de True \uff1b\u5426\u5219\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u5c06\u79fb\u52a8\u5230\u4e0b\u4e00\u4e2a\u4f4d\u7f6e\uff0c\u5e76\u628a\u5b83\u548c\u76ee\u6807\u5143\u7d20\u8fdb\u884c\u6bd4\u8f83\u3002\u5982\u679c\u8fd9\u4e2a\u65b9\u6cd5\u5230\u4e86\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u4ecd\u7136\u627e\u4e0d\u5230\u76ee\u6807\uff0c\u90a3\u4e48\u8fd4\u56de False \u3002\u8fd9\u79cd\u641c\u7d22\u79f0\u4e3a\u987a\u5e8f\u641c\u7d22\uff08sequential search\uff09\u6216\u7ebf\u6027\u641c\u7d22\uff08linear search\uff09\u3002 \u4e0b\u9762\u662f\u987a\u5e8f\u641c\u7d22\u51fd\u6570\u7684\u5b9e\u73b0\u3002\u82e5\u987a\u5e8f\u641c\u7d22\u7b97\u6cd5\u5728\u5217\u8868\u5f00\u5934\u5c31\u627e\u5230\u76ee\u6807\u5143\u7d20\uff0c\u90a3\u4e48\u8fd9\u65f6\u7684\u5de5\u4f5c\u91cf\u660e\u663e\u4f1a\u6bd4\u5728\u5217\u8868\u672b\u5c3e\u627e\u5230\u7684\u5de5\u4f5c\u91cf\u8981\u5c11\u3002 def sequentialSearch ( target , lyst ): \"\"\"\u627e\u5230\u76ee\u6807\u5143\u7d20\u65f6\u8fd4\u56de\u5143\u7d20\u7684\u7d22\u5f15, \u5426\u5219\u8fd4\u56de-1\"\"\" position = 0 while position < len ( lyst ): if target == lyst [ position ]: return position position += 1 return - 1 def main (): myList = [ 2 , 20 , 5 , 0 , 1 , 0 , 9 ] locatedIndex = sequentialSearch ( 9 , myList ) print ( locatedIndex , myList [ locatedIndex ]) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # 6 9 3.3.3.\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd \u00b6 \u4e00\u822c\u6765\u8bf4\uff0c\u91cd\u70b9\u5173\u6ce8\u5728\u5e73\u5747\u60c5\u51b5\u548c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\uff0c\u4e0d\u4f1a\u7279\u522b\u5173\u6ce8\u6700\u597d\u60c5\u51b5\u3002 \u5bf9\u987a\u5e8f\u641c\u7d22\u7684\u5206\u6790\u9700\u8981\u8003\u8651\u4e0b\u97623\u79cd\u60c5\u51b5\u3002 \u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u76ee\u6807\u5143\u7d20\u4f4d\u4e8e\u5217\u8868\u7684\u672b\u5c3e\u6216\u8005\u6839\u672c\u5c31\u4e0d\u5728\u5217\u8868\u91cc\u3002\u8fd9\u65f6\uff0c\u8fd9\u4e2a\u7b97\u6cd5\u5c31\u5fc5\u987b\u8bbf\u95ee\u6bcf\u4e00\u4e2a\u5143\u7d20\uff0c\u5bf9\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\u9700\u8981\u6267\u884c n \u6b21\u8fed\u4ee3\u3002\u56e0\u6b64\uff0c\u987a\u5e8f\u641c\u7d22\u7684\u6700\u574f\u60c5\u51b5\u7684\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u53ea\u9700\u8981O(1)\u7684\u590d\u6742\u5ea6\uff0c\u56e0\u4e3a\u8fd9\u4e2a\u7b97\u6cd5\u5728\u4e00\u6b21\u8fed\u4ee3\u4e4b\u540e\u5c31\u4f1a\u5728\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u627e\u5230\u76ee\u6807\u5143\u7d20\u3002 \u8981\u786e\u5b9a\u5e73\u5747\u60c5\u51b5\uff0c\u5c31\u9700\u8981\u628a\u6bcf\u4e2a\u53ef\u80fd\u4f4d\u7f6e\u627e\u5230\u76ee\u6807\u6240\u9700\u8981\u7684\u8fed\u4ee3\u6b21\u6570\u76f8\u52a0\uff0c\u7136\u540e\u518d\u5c06\u5b83\u4eec\u7684\u603b\u548c\u9664\u4ee5 n \u3002\u56e0\u6b64\uff0c\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u4f1a\u6267\u884c (n + n\u22121 + n\u22122+ ... +1)/n \u6216 (n+1)/2 \u6b21\u8fed\u4ee3\u3002\u5bf9\u4e8e\u975e\u5e38\u5927\u7684 n \u6765\u8bf4\uff0c\u5e38\u6570\u7cfb\u65702\u662f\u53ef\u4ee5\u5ffd\u7565\u7684\uff0c\u56e0\u6b64\uff0c\u5e73\u5747\u60c5\u51b5\u7684\u590d\u6742\u5ea6\u4ecd\u7136\u662fO(2)\u3002 \u7ed3\u8bba\uff1a\u6700\u597d\u60c5\u51b5\u4e0b\u987a\u5e8f\u641c\u7d22\u7684\u6027\u80fd\u548c\u5176\u4ed6\u4e24\u79cd\u60c5\u51b5\u6bd4\u8d77\u6765\u5c0f\u5f88\u591a\uff0c\u800c\u5176\u4ed6\u4e24\u79cd\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u662f\u5dee\u4e0d\u591a\u7684\u3002 3.3.4.\u57fa\u4e8e\u6709\u5e8f\u5217\u8868\u7684\u4e8c\u5206\u641c\u7d22 \u00b6 \u5728\u6570\u636e\u65e0\u5e8f\u7684\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528\u987a\u5e8f\u641c\u7d22\u6765\u627e\u5230\u76ee\u6807\u5143\u7d20\u3002 \u5728\u6570\u636e\u6709\u5e8f\u7684\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528\u4e8c\u5206\u641c\u7d22\u6765\u627e\u5230\u76ee\u6807\u5143\u7d20\u3002 Python\u4e2d\u5b9e\u73b0\u4e8c\u5206\u641c\u7d22\u7684\u601d\u8def\uff1a \u5047\u8bbe\u5217\u8868\u91cc\u7684\u5143\u7d20\u90fd\u4ee5\u5347\u5e8f\u6392\u5e8f\u3002 \u641c\u7d22\u7b97\u6cd5\u9996\u5148\u5230\u5217\u8868\u7684\u4e2d\u95f4\u4f4d\u7f6e\uff0c\u5e76\u628a\u8fd9\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u4e0e\u76ee\u6807\u5143\u7d20\u8fdb\u884c\u6bd4\u8f83\uff1b \u5982\u679c\u5339\u914d\uff0c\u90a3\u4e48\u7b97\u6cd5\u5c31\u8fd4\u56de\u5f53\u524d\u4f4d\u7f6e\u3002\u5982\u679c\u76ee\u6807\u5143\u7d20\u5c0f\u4e8e\u5f53\u524d\u5143\u7d20\uff0c\u90a3\u4e48\u7b97\u6cd5\u5c06\u4f1a\u641c\u7d22\u4e2d\u95f4\u4f4d\u7f6e\u4e4b\u524d\u7684\u90e8\u5206\uff1b \u5982\u679c\u76ee\u6807\u5143\u7d20\u5927\u4e8e\u5f53\u524d\u5143\u7d20\uff0c\u5219\u641c\u7d22\u4e2d\u95f4\u4f4d\u7f6e\u4e4b\u540e\u7684\u90e8\u5206\u3002 \u5728\u627e\u5230\u4e86\u76ee\u6807\u5143\u7d20\u6216\u8005\u5f53\u524d\u5f00\u59cb\u4f4d\u7f6e\u5927\u4e8e\u5f53\u524d\u7ed3\u675f\u4f4d\u7f6e\u65f6\uff0c\u505c\u6b62\u641c\u7d22\u8fc7\u7a0b\u3002 \u4e0b\u9762\u662f\u4e8c\u5206\u641c\u7d22\u51fd\u6570\u7684\u4ee3\u7801\u3002\u4ee5\u5217\u8868 [2, 20, 5, 0, 1, 0, 9] \u4e3a\u4f8b\uff1a \u6392\u5e8f\u540e\u7684\u5217\u8868\u4e3a [0, 0, 1, 2, 5, 9, 20] \uff1b \u6392\u5e8f\u540e\u5217\u8868\u957f\u5ea6\u662f7\uff0c\u6240\u4ee5\u521d\u59cbmidpoint=3\uff0c\u5bf9\u5e94\u5217\u8868\u503c\u662f2\uff1b def binarySearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 while left <= right : midpoint = ( left + right ) // 2 if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 return - 1 def main (): myList = [ 2 , 20 , 5 , 0 , 1 , 0 , 9 ] sortedList = sorted ( myList ) # \u5982\u679c\u4f7f\u7528myList.sort()\uff0c\u5219\u4f1a\u4fee\u6539myList\u672c\u8eab locatedIndex = binarySearch ( 5 , sortedList ) print ( sortedList ) print ( locatedIndex , sortedList [ locatedIndex ]) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # [0, 0, 1, 2, 5, 9, 20] # 4 5 # \u5982\u679c\u6267\u884cbinarySearch(0, sortedList)\uff0c\u5219\u4f1a\u8fd4\u56de\u7b2c\u4e8c\u4e2a0\u7684\u7d22\u5f15 # [0, 0, 1, 2, 5, 9, 20] # 1 0 \u4e0a\u9762\u4e8c\u5206\u6cd5\u7b97\u6cd5\u590d\u6742\u5ea6\u5206\u6790\uff1a \u7b97\u6cd5\u91cc\u53ea\u6709\u4e00\u4e2a\u5faa\u73af\uff0c\u5e76\u4e14\u6ca1\u6709\u5d4c\u5957\u6216\u9690\u85cf\u7684\u5faa\u73af\u3002\u5982\u679c\u76ee\u6807\u4e0d\u5728\u5217\u8868\u91cc\uff0c\u5c31\u4f1a\u5f97\u5230\u6700\u574f\u60c5\u51b5\uff0c\u5373\u904d\u5386\u5217\u8868\u7684\u4e00\u534a\uff0c\u5373\u5faa\u73af\u5217\u8868\u5927\u5c0f\u4e0d\u65ad\u9664\u4ee52\u76f4\u81f3\u5546\u4e3a1\u7684\u6b21\u6570\u3002 \u5bf9\u4e8e\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\u6765\u8bf4\uff0c\u4e5f\u5c31\u662f\u4f60\u9700\u8981\u6267\u884c n/2/2/.../2 \u6b21\uff0c\u76f4\u5230\u7ed3\u679c\u4e3a1\u3002\u5047\u8bbe k \u662f n \u53ef\u4ee5\u9664\u4ee52\u7684\u6b21\u6570\uff0c\u90a3\u4e48\u6c42\u89e3 k \u4f1a\u6709 n/(2^k)=1 \uff0c\u5373 n=2^k \uff0c\u5373 k=log(n,2) \u3002\u56e0\u6b64\uff0c\u4e8c\u5206\u641c\u7d22\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u590d\u6742\u5ea6\u4e3aO(log(n,2))\u3002 3.3.5.\u6bd4\u8f83\u6570\u636e\u5143\u7d20 \u00b6 \u4e8c\u5206\u641c\u7d22\u548c\u6700\u5c0f\u503c\u641c\u7d22\u90fd\u6709\u4e00\u4e2a\u5047\u8bbe\uff0c\u90a3\u5c31\u662f\u201c\u5217\u8868\u91cc\u7684\u5143\u7d20\u5f7c\u6b64\u4e4b\u95f4\u662f\u53ef\u4ee5\u6bd4\u8f83\u7684\u201d\u3002\u5373\uff0c\u8fd9\u4e9b\u5143\u7d20\u5c5e\u4e8e\u540c\u4e00\u4e2a\u7c7b\u578b\uff0c\u5373\uff0c\u53ef\u4ee5\u4f7f\u7528\u6bd4\u8f83\u8fd0\u7b97\u7b26 == \u3001 < \u548c > \u3002 Python\u5185\u7f6e\u7684\u7c7b\u578b\u5bf9\u8c61\uff0c\u5982\u6570\u5b57\u3001\u5b57\u7b26\u4e32\u548c\u5217\u8868\uff0c\u90fd\u652f\u6301\u6bd4\u8f83\u8fd0\u7b97\u7b26\u3002 \u4e3a\u4e86\u80fd\u591f\u8ba9\u7b97\u6cd5\u5bf9\u65b0\u7684\u7c7b\u5bf9\u8c61\u4f7f\u7528\u6bd4\u8f83\u8fd0\u7b97\u7b26 == \u3001 < \u548c > \uff0c\u5e94\u8be5\u5728\u8fd9\u4e2a\u7c7b\u91cc\u5b9a\u4e49 __eq__ \u3001 __lt__ \u548c __gt__ \u65b9\u6cd5\u3002\u5728\u5b9a\u4e49\u4e86\u8fd9\u4e9b\u65b9\u6cd5\u4e4b\u540e\uff0c\u5176\u4ed6\u6bd4\u8f83\u8fd0\u7b97\u7b26\u7684\u65b9\u6cd5\u5c06\u81ea\u52a8\u751f\u6210\u3002 \u4f8b\u5982\uff0c __lt__ \u7684\u5b9a\u4e49\u5982\u4e0b\uff0c\u5982\u679c self \u5c0f\u4e8e other \uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u5c06\u8fd4\u56de True \uff1b\u5426\u5219\uff0c\u8fd4\u56de False \u3002 __lt__ \u65b9\u6cd5\u4f1a\u4e3a\u4e24\u4e2a\u8d26\u6237\u5bf9\u8c61\u7684 name \u5b57\u6bb5\u8c03\u7528\u8fd0\u7b97\u7b26 < \u3002 \u540d\u79f0\u5b57\u6bb5\u662f\u5b57\u7b26\u4e32\uff0c\u5b57\u7b26\u4e32\u7c7b\u578b\u5df2\u7ecf\u5305\u542b\u5728 __lt__ \u65b9\u6cd5\u91cc\u3002 \u5728\u4f7f\u7528\u8fd0\u7b97\u7b26 < \u65f6\uff0cPython\u4f1a\u81ea\u52a8\u8fd0\u884c\u5b57\u7b26\u4e32\u7684 __lt__ \u65b9\u6cd5\uff0c\u8fd9\u4e0e\u8c03\u7528 str \u51fd\u6570\u65f6\u81ea\u52a8\u8fd0\u884c __str__ \u65b9\u6cd5\u662f\u7c7b\u4f3c\u7684\u3002 def __lt__ ( self , other ): \u793a\u4f8b\uff1a\u8fd4\u56de\u50a8\u84c4\u8d26\u6237\u7684\u6240\u6709\u4eba\u540d\u5b57\u3001PIN\u7801\u3001\u4f59\u989d\u3002 class SavingsAccount ( object ): \"\"\"\u8fd4\u56de\u50a8\u84c4\u8d26\u6237\u7684\u6240\u6709\u4eba\u540d\u5b57\u3001PIN\u7801\u3001\u4f59\u989d\"\"\" def __init__ ( self , name , pin , balance = 0.0 ): self . name = name self . pin = pin self . balance = balance def __lt__ ( self , other ): return self . name < other . name # Other methods, including __eq__ def main (): s1 = SavingsAccount ( \"Ken\" , \"1001\" , 0 ) s2 = SavingsAccount ( \"Bill\" , \"1001\" , 30 ) s3 = SavingsAccount ( \"Ken\" , \"1000\" , 0 ) s4 = s1 print ( \"s1 < s2: \" , s1 < s2 ) print ( \"s2 < s1: \" , s2 < s1 ) print ( \"s2 > s1: \" , s2 > s1 ) print ( \"s2 == s1: \" , s2 == s1 ) print ( \"s1 == s3: \" , s1 == s3 ) print ( \"s1 == s4: \" , s1 == s4 ) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # s1 < s2: False # s2 < s1: True # s2 > s1: False # s2 == s1: False # s1 == s3: False # s1 == s4: True \u63d0\u793a\uff1a\u5728Python\u4e2d\uff0c\u9ed8\u8ba4\u662f\u6309\u7167ASCII\u7684\u5927\u5c0f\u6bd4\u8f83\u5b57\u7b26\u4e32\u7684\uff0c\u5373\u4ece\u5b57\u7b26\u4e32\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\u8fdb\u884c\u6bd4\u8f83\uff0c\u5982\u679c\u76f8\u7b49\uff0c\u5219\u7ee7\u7eed\u6bd4\u8f83\u4e0b\u4e00\u4e2a\u5b57\u7b26\uff0c\u76f4\u5230\u5206\u51fa\u5927\u5c0f\uff0c\u6216\u8005\u8fd8\u6ca1\u5206\u51fa\u5927\u5c0f\uff0c\u6709\u4e00\u4e2a\u5b57\u7b26\u4e32\u5df2\u7ecf\u5230\u5934\u4e86\uff0c\u90a3\u4e48\u8f83\u957f\u7684\u90a3\u4e00\u4e2a\u5b57\u7b26\u4e32\u5927\u3002 3.3.6.\u7ec3\u4e60\u9898 \u00b6 \u5047\u8bbe\u4e00\u4e2a\u5217\u8868\u5728\u7d22\u5f150\uff5e9\u7684\u4f4d\u7f6e\u5904\u5305\u542b\u503c20\u300144\u300148\u300155\u300162\u300166\u300174\u300188\u300193\u300199\uff0c\u8bf7\u5728\u7528\u4e8c\u5206\u641c\u7d22\u67e5\u627e\u76ee\u6807\u5143\u7d2090\u7684\u65f6\u5019\uff0c\u5bf9\u53d8\u91cfleft\u3001right\u548cmidpoint\u7684\u503c\u8fdb\u884c\u8ddf\u8e2a\u3002\u6539\u53d8\u76ee\u6807\u5143\u7d20\u4e3a44\uff0c\u5e76\u91cd\u590d\u8fd9\u4e2a\u6b65\u9aa4\u3002 \u89e3\u7b54\uff1a \u4e0b\u9762\u662f\u4ee3\u7801\u548c\u8ddf\u8e2a\u7ed3\u679c\u3002 def binarySearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 print ( \" %5s%10s%10s \" % ( \"left\" , \"midpoint\" , \"right\" )) while left <= right : midpoint = ( left + right ) // 2 print ( \" %5s%10s%10s \" % ( left , midpoint , right )) if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 return - 1 def main (): myList = [ 20 , 44 , 48 , 55 , 62 , 66 , 74 , 88 , 93 , 99 ] sortedList = sorted ( myList ) locatedIndex = binarySearch ( 44 , sortedList ) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # Target = 90 # left midpoint right # 0 4 9 # 5 7 9 # 8 8 9 # # Target = 44 # left midpoint right # 0 4 9 # 0 1 3 \u901a\u5e38\u6765\u8bf4\uff0c\u67e5\u627e\u7535\u8bdd\u7c3f\u4e2d\u6761\u76ee\u7684\u65b9\u6cd5\u4e0e\u4e8c\u5206\u641c\u7d22\u5e76\u4e0d\u5b8c\u5168\u76f8\u540c\uff0c\u56e0\u4e3a\u4f7f\u7528\u7535\u8bdd\u7c3f\u7684\u65f6\u5019\uff0c\u5e76\u4e0d\u4f1a\u6bcf\u6b21\u90fd\u7ffb\u5230\u88ab\u641c\u7d22\u7684\u5b50\u5217\u8868\u7684\u4e2d\u70b9\u3002\u4e00\u822c\u6765\u8bf4\uff0c\u53ef\u4ee5\u6839\u636e\u8fd9\u4e2a\u4eba\u7684\u59d3\u6c0f\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd\u987a\u5e8f\u6765\u4f30\u7b97\u76ee\u6807\u53ef\u80fd\u4f1a\u5728\u7684\u4f4d\u7f6e\u3002\u4f8b\u5982\uff0c\u5f53\u67e5\u627e\u201cSmith\u201d\u7684\u7535\u8bdd\u65f6\uff0c\u4f60\u4f1a\u9996\u5148\u67e5\u770b\u7535\u8bdd\u7c3f\u4e0b\u534a\u90e8\u5206\u7684\u4e2d\u95f4\uff0c\u800c\u4e0d\u662f\u6574\u4e2a\u7535\u8bdd\u7c3f\u7684\u4e2d\u95f4\u3002\u8bf7\u5bf9\u4e8c\u5206\u641c\u7d22\u7b97\u6cd5\u5c1d\u8bd5\u8fdb\u884c\u4fee\u6539\uff0c\u4ece\u800c\u53ef\u4ee5\u5728\u5904\u7406\u540d\u79f0\u5217\u8868\u7684\u65f6\u5019\u6a21\u62df\u8fd9\u4e2a\u7b56\u7565\u3002\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u4e0e\u6807\u51c6\u7684\u4e8c\u5206\u641c\u7d22\u76f8\u6bd4\u8f83\u4f1a\u66f4\u597d\u5417\uff1f \u89e3\u7b54\uff1a\u4e0b\u9762\u662f\u4ee3\u7801\u548c\u8ffd\u8e2a\u7ed3\u679c\u3002\u901a\u8fc7\u5bf9\u6bd4\u4e0d\u540c\u6743\u91cd\u5355\u8bcd\u5230\u7684\u641c\u7d22\uff0c\u53ef\u4ee5\u53d1\u73b0\u6743\u91cd\u4e8c\u5206\u6cd5\u7684\u6548\u7387\u82e5\u8981\u4f18\u4e8e\u4f20\u7edf\u4e8c\u5206\u6cd5\uff0c\u662f\u9700\u8981\u6ee1\u8db3\u4e00\u5b9a\u7684\u6761\u4ef6\u7684\u3002 \u5728\u641c\u7d22\u7684\u7b2c\u4e00\u8f6e\u4e2d\uff0c\u4e2d\u95f4\u4f4d\u7f6e\u5c06\u53d6\u51b3\u4e8e\u5217\u8868\u7684\u5927\u5c0f\u548c\u76ee\u6807\u540d\u5b57\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd\u7684\u987a\u5e8f\u503c\u3002\u56e0\u6b64\uff0c\u7b2c\u4e00\u8f6e\u641c\u7d22\u5c06\u6d88\u9664\u6bd4\u4ee5\u524d\u66f4\u591a\u7684\u5143\u7d20\uff0c\u5e76\u4e14\u5982\u679c\u9700\u8981\u5176\u4ed6\u8f6e\u641c\u7d22\uff0c\u5b83\u4eec\u7684\u641c\u7d22\u7a7a\u95f4\u4e5f\u4f1a\u66f4\u5c0f\u3002\u7136\u800c\uff0c\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u4fee\u6539\u540e\u7684\u7b97\u6cd5\u4ecd\u7136\u6bd4O(1)\u66f4\u63a5\u8fd1O(log n)\u3002 def binarySearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 print ( \" %5s%10s%10s \" % ( \"left\" , \"midpoint\" , \"right\" )) while left <= right : midpoint = ( left + right ) // 2 print ( \" %5s%10s%10s \" % ( left , midpoint , right )) if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 return - 1 def letter_position ( myLetter ): letter = myLetter . lower () # \u8f6c\u6210\u5c0f\u5199\u5b57\u6bcd alphabet = \"abcdefghijklmnopqrstuvwxyz\" if letter in alphabet : return alphabet . index ( letter ) + 1 # \u4f4d\u7f6e\u63091\uff5e26\u8ba1\u7b97 else : return None # \u975e\u5b57\u6bcd def dictSearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 # \u9996\u5b57\u6bcd\u5728\u5b57\u6bcd\u8868\u4e2d\u7684\u767e\u5206\u4f4d letter_position_range = letter_position ( target [ 0 ]) * 100 // 26 # \u6309\u7167\u6240\u5f97\u7684\u9996\u5b57\u6bcd\u5728\u5b57\u6bcd\u8868\u4e2d\u7684\u767e\u5206\u4f4d\uff0c\u4f5c\u4e3a\u7ed9\u5b9a\u5b57\u4e32\u4e2d\u8bbe\u5b9a\u641c\u7d22\u8d77\u59cb\u767e\u5206\u4f4d midpoint = letter_position_range * ( len ( sortedLyst ) - 1 ) // 100 print ( \" %5s%10s%10s \" % ( \"left\" , \"midpoint\" , \"right\" )) while left <= right : print ( \" %5s%10s%10s \" % ( left , midpoint , right )) if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 midpoint = ( left + right ) // 2 return - 1 def main (): myList = [ \"Bob\" , \"Charlie\" , \"Eva\" , \"Alice\" , \"Grace\" , \"David\" , \"Smith\" , \"Frank\" , \"Zoe\" , \"Jack\" ] sortedList = sorted ( myList ) print ( sortedList ) print ( \"=====call binarySearch=====\" ) locatedIndex = binarySearch ( \"Alice\" , sortedList ) print ( \"Found\" , sortedList [ locatedIndex ], \"in position\" , locatedIndex ) print ( \"=====call dictSearch=====\" ) locatedIndex = dictSearch ( \"Alice\" , sortedList ) print ( \"Found\" , sortedList [ locatedIndex ], \"in position\" , locatedIndex ) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # \u641c\u7d22Alice # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 0 1 3 # 0 0 0 # Found Alice in position 0 # =====call dictSearch===== # left midpoint right # 0 0 9 # Found Alice in position 0 # \u641c\u7d22Bob # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 0 1 3 # Found Bob in position 1 # =====call dictSearch===== # left midpoint right # 0 0 9 # 1 5 9 # 1 2 4 # 1 1 1 # Found Bob in position 1 # \u641c\u7d22Smith # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 5 7 9 # 8 8 9 # Found Smith in position 8 # =====call dictSearch===== # left midpoint right # 0 6 9 # 7 8 9 # Found Smith in position 8 # \u641c\u7d22Zoe # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 5 7 9 # 8 8 9 # 9 9 9 # Found Zoe in position 9 # =====call dictSearch===== # left midpoint right # 0 9 9 # Found Zoe in position 9 3.4.\u57fa\u672c\u7684\u6392\u5e8f\u7b97\u6cd5 \u00b6 \u4e0b\u9762\u662fswap\u51fd\u6570\u7684\u4f8b\u5b50\uff0c\u5b9e\u73b0\u4e86\uff1a \u5047\u8bbe\u90fd\u5728\u6574\u6570\u5217\u8868\u4e0a\u8fd0\u884c\uff1b \u4ea4\u6362\u5217\u8868\u4e2d\u4e24\u4e2a\u5143\u7d20\u7684\u4f4d\u7f6e\uff1b def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( myList ) swap ( myList , 3 , 5 ) print ( myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # [9, 4, 2, 7, 6, 8, 1] # [9, 4, 2, 8, 6, 7, 1] 3.4.1.\u9009\u62e9\u6392\u5e8f \u00b6 \u9009\u62e9\u6392\u5e8f\uff08selection sort\uff09\uff1a\uff08\u4ee5\u5217\u8868\u4e3a\u4f8b\uff09 \u5728\u4e00\u4e2a\u957f\u5ea6\u4e3a N \u7684\u65e0\u5e8f\u5217\u8868\u4e2d\uff0c\u7b2c\u4e00\u6b21\u904d\u5386 n-1 \u4e2a\u6570\u627e\u5230\u6700\u5c0f\u7684\u548c\u7b2c\u4e00\u4e2a\u6570\u4ea4\u6362\u3002 \u7b2c\u4e8c\u6b21\u4ece\u4e0b\u4e00\u4e2a\u6570\u5f00\u59cb\u904d\u5386 n-2 \u4e2a\u6570\uff0c\u627e\u5230\u6700\u5c0f\u7684\u6570\u548c\u7b2c\u4e8c\u4e2a\u6570\u4ea4\u6362\u3002 \u91cd\u590d\u4ee5\u4e0a\u64cd\u4f5c\u76f4\u5230\u7b2c n-1 \u6b21\u904d\u5386\u6700\u5c0f\u7684\u6570\u548c\u7b2c n-1 \u4e2a\u6570\u4ea4\u6362\uff0c\u6392\u5e8f\u5b8c\u6210\u3002 \u8fd9\u4e2a\u7b97\u6cd5\u5728\u6bcf\u6b21\u901a\u8fc7\u4e3b\u5faa\u73af\u65f6\uff0c\u90fd\u4f1a\u9009\u62e9\u8981\u79fb\u52a8\u7684\u90a3\u4e00\u4e2a\u5143\u7d20\u3002 \u7b97\u6cd5\u590d\u6742\u5ea6\uff1a \u7b2c1\u6b21\u6267\u884c\u5916\u90e8\u5faa\u73af\u65f6\uff0c\u5185\u90e8\u5faa\u73af\u4f1a\u6267\u884cn-1\u6b21\uff1b \u7b2c2\u6b21\u6267\u884c\u5916\u90e8\u5faa\u73af\u65f6\uff0c\u5185\u90e8\u5faa\u73af\u4f1a\u6267\u884cn-2\u6b21\uff1b \u6700\u540e\u4e00\u6b21\u6267\u884c\u5916\u90e8\u5faa\u73af\u65f6\uff0c\u5185\u90e8\u5faa\u73af\u4f1a\u6267\u884c1\u6b21\uff1b \u6240\u4ee5\uff0c\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\uff0c\u4e00\u5171\u9700\u8981\u7684\u6bd4\u8f83\u6b21\u6570\u662f (n-1)+(n-2)+...+1 \uff0c\u5316\u7b80\u4e3a n*(n-1)/2 \uff0c\u5373 (1/2)*n^2+(1/2)*n \u3002\u5f53 n \u6bd4\u8f83\u5927\u65f6\uff0c\u53ef\u4ee5\u9009\u62e9\u6700\u9ad8\u6b21\u7684\u9879\u5e76\u5ffd\u7565\u7cfb\u6570\uff0c\u56e0\u6b64\u5728\u6240\u6709\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u7684\u590d\u6742\u5ea6\u90fd\u662fO(n^2)\u3002 \u5bf9\u4e8e\u5927\u578b\u6570\u636e\u96c6\u6765\u8bf4\uff0c\u4ea4\u6362\u5143\u7d20\u7684\u6210\u672c\u53ef\u80fd\u4f1a\u5f88\u9ad8\u3002\u56e0\u4e3a\u8fd9\u4e2a\u7b97\u6cd5\u53ea\u4f1a\u5728\u5916\u90e8\u5faa\u73af\u91cc\u5bf9\u6570\u636e\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\uff0c\u6240\u4ee5\u5728\u6700\u574f\u60c5\u51b5\u548c\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u7684\u989d\u5916\u6210\u672c\u662f\u7ebf\u6027\u7684\u3002 \u7b97\u6cd5\u4ee3\u7801\uff1a def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 minIndex = i # \u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , minIndex , i ) i += 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] 3.4.2.\u5192\u6ce1\u6392\u5e8f \u00b6 \u5192\u6ce1\u6392\u5e8f\uff08Bubble Sort\uff09\uff1a \u6bd4\u8f83\u76f8\u90bb\u4e24\u4e2a\u6570\u636e\u5982\u679c\u3002\u7b2c\u4e00\u4e2a\u6bd4\u7b2c\u4e8c\u4e2a\u5927\uff0c\u5c31\u4ea4\u6362\u4e24\u4e2a\u6570\uff1b \u5bf9\u6bcf\u4e00\u4e2a\u76f8\u90bb\u7684\u6570\u505a\u540c\u68371\u7684\u5de5\u4f5c\uff0c\u8fd9\u6837\u4ece\u5f00\u59cb\u4e00\u961f\u5230\u7ed3\u5c3e\u4e00\u961f\u5728\u6700\u540e\u7684\u6570\u5c31\u662f\u6700\u5927\u7684\u6570\u3002 \u9488\u5bf9\u6240\u6709\u5143\u7d20\u4e0a\u9762\u7684\u64cd\u4f5c\uff0c\u9664\u4e86\u6700\u540e\u4e00\u4e2a\u3002 \u91cd\u590d1~3\u6b65\u9aa4\uff0c\u76f4\u81f3\u5b8c\u6210\u3002 \u7b97\u6cd5\u590d\u6742\u5ea6\uff1a \u5192\u6ce1\u6392\u5e8f\u53ea\u4f1a\u6539\u5584\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u590d\u6742\u5ea6\u3002\u5bf9\u4e8e\u5e73\u5747\u60c5\u51b5\u800c\u8a00\uff0c\u7531\u4e8e\u4f9d\u7136\u662f\u53cc\u91cd\u5faa\u73af\u65f6\u95f4\uff0c\u6240\u4ee5\u590d\u6742\u5ea6\u662fO(n^2)\uff1b \u5bf9\u4e8e\u6709\u5e8f\u7684\u5217\u8868\u6765\u8bf4\uff0c\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u4f1a\u6bd4\u9009\u62e9\u6392\u5e8f\u7684\u6267\u884c\u6548\u7387\u66f4\u9ad8\u3002 \u7b97\u6cd5\u4ee3\u7801\uff1a def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 minIndex = i # \u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , minIndex , i ) i += 1 def bubbleSortWithTweak ( lyst ): \"\"\"\u5b9e\u73b0\u5192\u6ce1\u6392\u5e8f\u7b97\u6cd5\"\"\" n = len ( lyst ) while n > 1 : swapped = False # \u7528\u5e03\u5c14\u6807\u5fd7\u6765\u8ffd\u8e2a\u6709\u6ca1\u6709\u53d1\u751f\u4ea4\u6362 i = 1 while i < n : if lyst [ i ] < lyst [ i - 1 ]: # \u5982\u679c\u540e\u9762\u5143\u7d20\u7684\u503c\u6bd4\u524d\u9762\u5143\u7d20\u7684\u5927\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\uff0c\u76f4\u81f3\u628a\u5faa\u73af\u4e2d\u7684\u6700\u5927\u5143\u7d20\u79fb\u5230\u6700\u540e swap ( lyst , i , i - 1 ) swapped = True i += 1 if not swapped : # \u5982\u679c\u4e0d\u9700\u8981\u4ea4\u6362\uff0c\u76f4\u63a5return return n -= 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] # \u6bd4\u8f83\u6392\u5e8f print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) # \u5192\u6ce1\u6392\u5e8f myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before bubble sort \" , myList ) bubbleSortWithTweak ( myList ) print ( \"After bubble sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] # Before bubble sort [9, 4, 2, 7, 6, 8, 1] # After bubble sort [1, 2, 4, 6, 7, 8, 9] 3.4.3.\u63d2\u5165\u6392\u5e8f \u00b6 \u63d2\u5165\u6392\u5e8f\uff08Insertion-Sort\uff09\u662f\u901a\u8fc7\u6784\u5efa\u6709\u5e8f\u5e8f\u5217\uff0c\u5bf9\u4e8e\u672a\u6392\u5e8f\u6570\u636e\uff0c\u5728\u5df2\u6392\u5e8f\u5e8f\u5217\u4e2d\u4ece\u540e\u5411\u524d\u626b\u63cf\uff0c\u627e\u5230\u76f8\u5e94\u4f4d\u7f6e\u5e76\u63d2\u5165\u3002\u63d2\u5165\u6392\u5e8f\u90fd\u91c7\u7528 in-place \u5728\u6570\u7ec4\u4e0a\u5b9e\u73b0\uff1a \u4ece\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\uff0c\u8be5\u5143\u7d20\u53ef\u4ee5\u8ba4\u4e3a\u5df2\u7ecf\u88ab\u6392\u5e8f\uff1b \u53d6\u51fa\u4e0b\u4e00\u4e2a\u5143\u7d20\uff0c\u5728\u5df2\u7ecf\u6392\u5e8f\u7684\u5143\u7d20\u5e8f\u5217\u4ece\u540e\u5411\u524d\u626b\u63cf\uff1b \u5982\u679c\u65b0\u5143\u7d20\u5c0f\u4e8e\u5df2\u6392\u5e8f\u7684\u5143\u7d20\uff0c\u5c06\u65b0\u5143\u7d20\u79fb\u5230\u4e0b\u4e00\u4f4d\u7f6e\uff1b \u91cd\u590d\u6b65\u9aa43\uff0c\u76f4\u5230\u627e\u5230\u5df2\u6392\u5e8f\u7684\u5143\u7d20\u5c0f\u4e8e\u6216\u8005\u7b49\u4e8e\u65b0\u5143\u7d20\u7684\u4f4d\u7f6e\uff1b \u5c06\u65b0\u5143\u7d20\u63d2\u5165\u5230\u8be5\u4f4d\u7f6e\u540e\uff1b \u91cd\u590d\u6b65\u9aa42~5\u3002 \u590d\u6742\u5ea6\uff1a \u548c\u9009\u62e9\u6392\u5e8f\u7c7b\u4f3c\uff0c\u904d\u5386\u6b21\u6570\u4e5f\u662f (1/2)*n^2+(1/2)*n \uff0c\u6240\u4ee5\u590d\u6742\u5ea6\u4e5f\u662fO(n^2)\u3002 \u5217\u8868\u91cc\u6709\u5e8f\u5143\u7d20\u8d8a\u591a\uff0c\u63d2\u5165\u6392\u5e8f\u7684\u6027\u80fd\u5c31\u4f1a\u8d8a\u597d\uff1b \u5728\u6709\u5e8f\u5217\u8868\u7684\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u6392\u5e8f\u590d\u6742\u5ea6\u662f\u7ebf\u6027\u7684\uff1b def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 minIndex = i # \u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , minIndex , i ) i += 1 def bubbleSortWithTweak ( lyst ): \"\"\"\u5b9e\u73b0\u5192\u6ce1\u6392\u5e8f\u7b97\u6cd5\"\"\" n = len ( lyst ) while n > 1 : swapped = False # \u7528\u5e03\u5c14\u6807\u5fd7\u6765\u8ffd\u8e2a\u6709\u6ca1\u6709\u53d1\u751f\u4ea4\u6362 i = 1 while i < n : if lyst [ i ] < lyst [ i - 1 ]: # \u5982\u679c\u540e\u9762\u5143\u7d20\u7684\u503c\u6bd4\u524d\u9762\u5143\u7d20\u7684\u5927\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\uff0c\u76f4\u81f3\u628a\u5faa\u73af\u4e2d\u7684\u6700\u5927\u5143\u7d20\u79fb\u5230\u6700\u540e swap ( lyst , i , i - 1 ) swapped = True i += 1 if not swapped : # \u5982\u679c\u4e0d\u9700\u8981\u4ea4\u6362\uff0c\u76f4\u63a5return return n -= 1 def insertionSort ( lyst ): i = 1 # \u65b0\u5143\u7d20\u7684\u4f4d\u7f6e while i < len ( lyst ): itemToInsert = lyst [ i ] # \u65b0\u5143\u7d20 j = i - 1 # \u5df2\u6392\u5e8f\u7684\u5143\u7d20\u5e8f\u5217\u7684\u6700\u53f3\u4f4d\u7f6e while j >= 0 : if itemToInsert < lyst [ j ]: lyst [ j + 1 ] = lyst [ j ] # \u5982\u679c\u65b0\u5143\u7d20\u5c0f\u4e8e\u5df2\u6392\u5e8f\u5143\u7d20\uff0c\u5219\u5df2\u6392\u5e8f\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4e2a\u4f4d\u7f6e j -= 1 else : break # \u65b0\u5143\u7d20\u7b49\u4e8e\u6216\u8005\u5927\u4e8e\u5df2\u6392\u5e8f\u5143\u7d20\uff0c\u8df3\u51fa\u5faa\u73af\uff0c\u6b64\u65f6lyst[j + 1]\u662f\u548clyst[j]\u662f\u540c\u4e00\u4e2a\u5143\u7d20\u503c\uff0clyst[j + 1]\u4f4d\u7f6e\u662f\u7559\u7ed9\u65b0\u5143\u7d20\u7684 lyst [ j + 1 ] = itemToInsert # i += 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] # \u6bd4\u8f83\u6392\u5e8f print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) # \u5192\u6ce1\u6392\u5e8f myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before bubble sort \" , myList ) bubbleSortWithTweak ( myList ) print ( \"After bubble sort \" , myList ) # \u63d2\u5165\u6392\u5e8f myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before insertion sort \" , myList ) insertionSort ( myList ) print ( \"After insertion sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] # Before bubble sort [9, 4, 2, 7, 6, 8, 1] # After bubble sort [1, 2, 4, 6, 7, 8, 9] # Before insertion sort [9, 4, 2, 7, 6, 8, 1] # After insertion sort [1, 2, 4, 6, 7, 8, 9] 3.4.4.\u518d\u8bba\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd \u00b6 \u5bf9\u4e8e\u8bb8\u591a\u7b97\u6cd5\u6765\u8bf4\uff0c\u4e0d\u80fd\u5bf9\u6240\u6709\u60c5\u51b5\u91c7\u7528\u5355\u4e00\u7684\u590d\u6742\u5ea6\u6765\u8861\u91cf\u3002\u5f53\u9047\u5230\u7279\u5b9a\u987a\u5e8f\u7684\u6570\u636e\u65f6\uff0c\u7b97\u6cd5\u7684\u884c\u4e3a\u53ef\u80fd\u4f1a\u53d8\u5f97\u66f4\u597d\u6216\u66f4\u7cdf\u3002 \u5bf9\u7b97\u6cd5\u590d\u6742\u5ea6\u884c\u4e3a\u5206\u4e3a3\u79cd\u60c5\u51b5\uff1a \u6700\u597d\u60c5\u51b5\uff08best case\uff09\u2014\u2014\u7b97\u6cd5\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\u53ef\u4ee5\u4ee5\u6700\u5c11\u7684\u5de5\u4f5c\u91cf\u5b8c\u6210\u5de5\u4f5c\uff1f\u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u7684\u590d\u6742\u5ea6\u662f\u591a\u5c11\uff1f \u6700\u574f\u60c5\u51b5\uff08worst case\uff09\u2014\u2014\u7b97\u6cd5\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\u9700\u8981\u5b8c\u6210\u6700\u591a\u7684\u5de5\u4f5c\u91cf\uff1f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u7684\u590d\u6742\u5ea6\u662f\u591a\u5c11\uff1f \u5e73\u5747\u60c5\u51b5\uff08average case\uff09\u2014\u2014\u7b97\u6cd5\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\u7528\u9002\u91cf\u7684\u5de5\u4f5c\u91cf\u5c31\u80fd\u5b8c\u6210\u5de5\u4f5c\uff1f\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u7684\u590d\u6742\u5ea6\u662f\u591a\u5c11\uff1f \u4e0b\u9762\u5206\u522b\u5bf9\u6700\u5c0f\u503c\u641c\u7d22\u3001\u987a\u5e8f\u641c\u7d22\u548c\u5192\u6ce1\u6392\u5e8f\u8fdb\u884c\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u548c\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u5206\u6790\uff0c\u4e0d\u8003\u8651\u5b9e\u9645\u786c\u4ef6\u548c\u7f16\u7a0b\u8bed\u8a00\u7b49\u7684\u5f71\u54cd\u3002 \u6700\u5c0f\u503c\u641c\u7d22\uff08Minimum Value Search\uff09 \u6700\u597d\u60c5\u51b5\uff1a\u6700\u5c0f\u503c\u521a\u597d\u5728\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3002\u8fd9\u65f6\uff0c\u53ea\u9700\u8981\u4e00\u6b21\u6bd4\u8f83\u5c31\u53ef\u4ee5\u627e\u5230\u6700\u5c0f\u503c\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(1)\u3002 \u6700\u574f\u60c5\u51b5\uff1a\u6700\u5c0f\u503c\u5728\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u6216\u4e0d\u5b58\u5728\u3002\u8fd9\u65f6\uff0c\u9700\u8981\u8fdb\u884cn-1\u6b21\u6bd4\u8f83\u624d\u80fd\u786e\u5b9a\u6700\u5c0f\u503c\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5e73\u5747\u60c5\u51b5\uff1a\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u6bcf\u4e2a\u5143\u7d20\u6709\u76f8\u7b49\u7684\u6982\u7387\u6210\u4e3a\u6700\u5c0f\u503c\u3002\u56e0\u6b64\uff0c\u5e73\u5747\u6bd4\u8f83\u6b21\u6570\u4e3a(n-1)/2\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u987a\u5e8f\u641c\u7d22\uff08Sequential Search\uff09 \u6700\u597d\u60c5\u51b5\uff1a\u641c\u7d22\u7684\u5143\u7d20\u521a\u597d\u662f\u5217\u8868\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u3002\u8fd9\u65f6\uff0c\u53ea\u9700\u8981\u4e00\u6b21\u6bd4\u8f83\u5c31\u53ef\u4ee5\u627e\u5230\u76ee\u6807\u5143\u7d20\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(1)\u3002 \u6700\u574f\u60c5\u51b5\uff1a\u641c\u7d22\u7684\u5143\u7d20\u5728\u5217\u8868\u7684\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u6216\u4e0d\u5b58\u5728\u3002\u8fd9\u65f6\uff0c\u9700\u8981\u8fdb\u884cn\u6b21\u6bd4\u8f83\u624d\u80fd\u786e\u5b9a\u76ee\u6807\u5143\u7d20\u4e0d\u5b58\u5728\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5e73\u5747\u60c5\u51b5\uff1a\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u6bcf\u4e2a\u5143\u7d20\u6709\u76f8\u7b49\u7684\u6982\u7387\u6210\u4e3a\u76ee\u6807\u5143\u7d20\u3002\u56e0\u6b64\uff0c\u5e73\u5747\u6bd4\u8f83\u6b21\u6570\u4e3a (n+1)/2 \uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5192\u6ce1\u6392\u5e8f\uff08Bubble Sort\uff09 \u6700\u597d\u60c5\u51b5\uff1a\u5982\u679c\u8f93\u5165\u5217\u8868\u5df2\u7ecf\u662f\u6709\u5e8f\u7684\uff0c\u5192\u6ce1\u6392\u5e8f\u53ea\u9700\u8981\u8fdb\u884c\u4e00\u6b21\u904d\u5386\u6765\u68c0\u6d4b\u5217\u8868\u5df2\u7ecf\u6709\u5e8f\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002\u4f46\u5b9e\u9645\u4e0a\uff0c\u901a\u5e38\u9700\u8981\u8fdb\u884c\u591a\u6b21\u904d\u5386\u6765\u5b8c\u6210\u6392\u5e8f\uff0c\u56e0\u6b64\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662fO(n^2)\u3002 \u6700\u574f\u60c5\u51b5\uff1a\u5982\u679c\u8f93\u5165\u5217\u8868\u662f\u9006\u5e8f\u7684\uff0c\u6bcf\u6b21\u904d\u5386\u90fd\u9700\u8981\u8fdb\u884cn-1\u6b21\u4ea4\u6362\uff0c\u603b\u5171\u9700\u8981\u8fdb\u884cn-1\u8f6e\u904d\u5386\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n^2)\u3002 \u5e73\u5747\u60c5\u51b5\uff1a\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u5192\u6ce1\u6392\u5e8f\u9700\u8981\u8fdb\u884c n(n-1)/2 \u6b21\u6bd4\u8f83\u548c\u4ea4\u6362\u64cd\u4f5c\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n^2)\u3002 3.4.5.\u7ec3\u4e60\u9898 \u00b6 \u5217\u8868\u91cc\u5982\u4f55\u6392\u5217\u6570\u636e\u624d\u80fd\u8ba9\u9009\u62e9\u6392\u5e8f\u4e2d\u5143\u7d20\u4ea4\u6362\u7684\u6b21\u6570\u6700\u5c11\uff1f\u5982\u4f55\u6392\u5217\u6570\u636e\u624d\u80fd\u8ba9\u5b83\u6267\u884c\u6700\u591a\u7684\u4ea4\u6362\u6b21\u6570\uff1f \u89e3\u7b54\uff1a \u5728\u9009\u62e9\u6392\u5e8f\u4e2d\uff0c\u5143\u7d20\u7684\u4ea4\u6362\u6b21\u6570\u4e3b\u8981\u53d6\u51b3\u4e8e\u5f85\u6392\u5e8f\u5217\u8868\u7684\u521d\u59cb\u6392\u5217\uff1a \u6700\u5c0f\u5316\u4ea4\u6362\u6b21\u6570\uff1a \u8981\u6700\u5c0f\u5316\u9009\u62e9\u6392\u5e8f\u7684\u5143\u7d20\u4ea4\u6362\u6b21\u6570\uff0c\u53ef\u4ee5\u8ba9\u8f93\u5165\u5217\u8868\u5df2\u7ecf\u6309\u5347\u5e8f\u6392\u5217\u3002\u8fd9\u662f\u56e0\u4e3a\u5728\u5347\u5e8f\u6392\u5217\u7684\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u6bcf\u6b21\u9009\u62e9\u6700\u5c0f\u7684\u5143\u7d20\u5e76\u5c06\u5176\u653e\u7f6e\u5728\u6b63\u786e\u7684\u4f4d\u7f6e\uff0c\u65e0\u9700\u4ea4\u6362\u3002\u56e0\u6b64\uff0c\u5143\u7d20\u4ea4\u6362\u7684\u6b21\u6570\u4e3a 0 \u3002 \u6700\u5927\u5316\u4ea4\u6362\u6b21\u6570\uff1a \u8981\u6700\u5927\u5316\u9009\u62e9\u6392\u5e8f\u7684\u5143\u7d20\u4ea4\u6362\u6b21\u6570\uff0c\u53ef\u4ee5\u8ba9\u8f93\u5165\u5217\u8868\u6309\u964d\u5e8f\u6392\u5217\u3002\u5728\u964d\u5e8f\u6392\u5217\u7684\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u6bcf\u6b21\u9009\u62e9\u6700\u5927\u7684\u5143\u7d20\u5e76\u5c06\u5176\u653e\u7f6e\u5728\u6b63\u786e\u7684\u4f4d\u7f6e\uff0c\u8fd9\u5c06\u5bfc\u81f4\u5927\u91cf\u7684\u4ea4\u6362\u64cd\u4f5c\u3002\u5177\u4f53\u6765\u8bf4\uff0c\u5bf9\u4e8e\u957f\u5ea6\u4e3an\u7684\u5217\u8868\uff0c\u6700\u5927\u5316\u4ea4\u6362\u6b21\u6570\u7684\u60c5\u51b5\u4e0b\uff0c\u5c06\u6267\u884c n-1 \u6b21\u4ea4\u6362\u64cd\u4f5c\u3002 \u603b\u4e4b\uff0c\u8981\u6700\u5c0f\u5316\u9009\u62e9\u6392\u5e8f\u7684\u5143\u7d20\u4ea4\u6362\u6b21\u6570\uff0c\u8f93\u5165\u5217\u8868\u5e94\u8be5\u5df2\u7ecf\u6309\u5347\u5e8f\u6392\u5217\u3002\u8981\u6700\u5927\u5316\u4ea4\u6362\u6b21\u6570\uff0c\u8f93\u5165\u5217\u8868\u5e94\u8be5\u6309\u964d\u5e8f\u6392\u5217\u3002\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u9009\u62e9\u6392\u5e8f\u901a\u5e38\u4e0d\u662f\u9996\u9009\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u56e0\u4e3a\u5176\u4ea4\u6362\u6b21\u6570\u8f83\u591a\uff0c\u800c\u5176\u4ed6\u7b97\u6cd5\u5982\u5feb\u901f\u6392\u5e8f\u3001\u5f52\u5e76\u6392\u5e8f\u7b49\u5177\u6709\u66f4\u597d\u7684\u6027\u80fd\u3002 \u8bf7\u8bf4\u660e\u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\u5728\u5206\u6790\u9009\u62e9\u6392\u5e8f\u548c\u5192\u6ce1\u6392\u5e8f\u65f6\u6240\u8d77\u5230\u7684\u4f5c\u7528\u3002\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u5728\u5b83\u4eec\u4e4b\u95f4\u53d1\u6325\u7740\u4ec0\u4e48\u4f5c\u7528\uff08\u5982\u679c\u6709\u4f5c\u7528\uff09\uff1f \u89e3\u7b54\uff1a \u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\u5728\u5206\u6790\u9009\u62e9\u6392\u5e8f\u548c\u5192\u6ce1\u6392\u5e8f\u65f6\u8d77\u5230\u91cd\u8981\u4f5c\u7528\uff0c\u56e0\u4e3a\u5b83\u4eec\u76f4\u63a5\u5f71\u54cd\u5230\u6392\u5e8f\u7b97\u6cd5\u7684\u6027\u80fd\u548c\u6548\u7387\u3002 \u9009\u62e9\u6392\u5e8f\uff08Selection Sort\uff09\uff1a \u9009\u62e9\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e0e\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u76f4\u63a5\u76f8\u5173\u3002\u5728\u9009\u62e9\u6392\u5e8f\u4e2d\uff0c\u6bcf\u4e00\u8f6e\u90fd\u4f1a\u9009\u62e9\u672a\u6392\u5e8f\u90e8\u5206\u7684\u6700\u5c0f\u5143\u7d20\uff0c\u5e76\u5c06\u5176\u653e\u7f6e\u5728\u6b63\u786e\u7684\u4f4d\u7f6e\uff0c\u8fd9\u610f\u5473\u7740\u6bcf\u8f6e\u90fd\u9700\u8981\u4e00\u6b21\u4ea4\u6362\u64cd\u4f5c\u3002 \u9009\u62e9\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u662f\u4e0e\u8f93\u5165\u6570\u636e\u7684\u521d\u59cb\u6392\u5217\u65e0\u5173\u7684\uff0c\u56e0\u4e3a\u5b83\u603b\u662f\u4f1a\u6267\u884c\u76f8\u540c\u6570\u91cf\u7684\u4ea4\u6362\u64cd\u4f5c\uff0c\u65e0\u8bba\u6570\u636e\u662f\u5426\u6709\u5e8f\u3002 \u5bf9\u4e8e\u9009\u62e9\u6392\u5e8f\uff0c\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e3b\u8981\u53d7\u5230\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u5f71\u54cd\uff0c\u800c\u4e0d\u53d7\u6570\u636e\u7684\u5177\u4f53\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u65e0\u8bba\u6570\u636e\u7684\u6392\u5217\u5982\u4f55\uff0c\u9009\u62e9\u6392\u5e8f\u7684\u5e73\u5747\u548c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u90fd\u662f\u76f8\u540c\u7684\uff0c\u5373 n-1 \u6b21\u3002 \u5192\u6ce1\u6392\u5e8f\uff08Bubble Sort\uff09\uff1a \u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e5f\u4e0e\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u76f8\u5173\u3002\u5728\u5192\u6ce1\u6392\u5e8f\u4e2d\uff0c\u76f8\u90bb\u5143\u7d20\u9010\u4e00\u6bd4\u8f83\uff0c\u5982\u679c\u9006\u5e8f\u5c31\u4ea4\u6362\u4f4d\u7f6e\uff0c\u56e0\u6b64\u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e0e\u9006\u5e8f\u5bf9\u7684\u6570\u91cf\u76f8\u5173\u3002 \u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u5728\u4e0d\u540c\u7684\u6570\u636e\u6392\u5217\u60c5\u51b5\u4e0b\u53ef\u4ee5\u6709\u5f88\u5927\u5dee\u5f02\u3002\u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff08\u8f93\u5165\u6570\u636e\u5df2\u7ecf\u6709\u5e8f\uff09\uff0c\u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e3a 0 \u3002\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff08\u8f93\u5165\u6570\u636e\u5b8c\u5168\u9006\u5e8f\uff09\uff0c\u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u662f\u6700\u5927\u7684\u3002 \u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u65e2\u53d7\u5230\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u5f71\u54cd\uff0c\u53c8\u53d7\u5230\u6570\u636e\u7684\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u4ea4\u6362\u6b21\u6570\u4e3a 0 \uff0c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u4ea4\u6362\u6b21\u6570\u4e3a n*(n-1)/2 \uff0c\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u4ea4\u6362\u6b21\u6570\u53d6\u51b3\u4e8e\u6570\u636e\u6392\u5217\u7684\u968f\u673a\u6027\u3002 \u7efc\u4e0a\u6240\u8ff0\uff0c\u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\u5728\u9009\u62e9\u6392\u5e8f\u548c\u5192\u6ce1\u6392\u5e8f\u7684\u5206\u6790\u4e2d\u662f\u91cd\u8981\u7684\u6027\u80fd\u6307\u6807\u3002\u9009\u62e9\u6392\u5e8f\u7684\u4ea4\u6362\u6b21\u6570\u4e0e\u6570\u636e\u89c4\u6a21\u76f8\u5173\uff0c\u800c\u5192\u6ce1\u6392\u5e8f\u7684\u4ea4\u6362\u6b21\u6570\u65e2\u4e0e\u6570\u636e\u89c4\u6a21\u76f8\u5173\uff0c\u53c8\u53d7\u5230\u6570\u636e\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u5728\u5927\u89c4\u6a21\u6570\u636e\u96c6\u4e0a\uff0c\u5192\u6ce1\u6392\u5e8f\u901a\u5e38\u6bd4\u9009\u62e9\u6392\u5e8f\u66f4\u6162\uff0c\u56e0\u4e3a\u5b83\u7684\u4ea4\u6362\u64cd\u4f5c\u66f4\u591a\u3002\u56e0\u6b64\uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u901a\u5e38\u9009\u62e9\u6392\u5e8f\u6bd4\u5192\u6ce1\u6392\u5e8f\u66f4\u6709\u6548\u3002\u4f46\u4e24\u8005\u90fd\u4e0d\u662f\u9996\u9009\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u66f4\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\u5982\u5feb\u901f\u6392\u5e8f\u3001\u5f52\u5e76\u6392\u5e8f\u7b49\u901a\u5e38\u88ab\u4f18\u5148\u8003\u8651\u3002 \u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u6027\u80fd\u4ecd\u7136\u4e3aO(n^2)\u3002 \u89e3\u7b54\uff1a \u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u6027\u80fd\u4ecd\u7136\u4e3aO(n^2)\uff0c\u539f\u56e0\u5982\u4e0b\uff1a \u5192\u6ce1\u6392\u5e8f\u7684\u57fa\u672c\u64cd\u4f5c\u662f\u6bd4\u8f83\u76f8\u90bb\u5143\u7d20\u5e76\u4ea4\u6362\u5b83\u4eec\uff0c\u76f4\u5230\u6574\u4e2a\u5217\u8868\u6309\u7167\u5347\u5e8f\u6392\u5217\u3002\u5728\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u4e2d\uff0c\u5f53\u4e24\u4e2a\u76f8\u90bb\u5143\u7d20\u9006\u5e8f\u65f6\uff0c\u4f1a\u53d1\u751f\u4ea4\u6362\u3002\u8fd9\u4e2a\u57fa\u672c\u64cd\u4f5c\u7684\u590d\u6742\u5ea6\u662fO(1)\uff0c\u56e0\u4e3a\u5b83\u53ea\u6d89\u53ca\u4e24\u4e2a\u5143\u7d20\u7684\u6bd4\u8f83\u548c\u53ef\u80fd\u7684\u4ea4\u6362\u3002 \u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u6bcf\u4e00\u8f6e\u904d\u5386\u4e2d\uff0c\u4ecd\u7136\u9700\u8981\u68c0\u67e5\u76f8\u90bb\u5143\u7d20\u7684\u6bd4\u8f83\uff0c\u5373\u4f7f\u5728\u6709\u5e8f\u90e8\u5206\uff0c\u5b83\u4ecd\u7136\u9700\u8981\u8fdb\u884c\u6bd4\u8f83\u3002\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5b83\u4f1a\u6267\u884cn-1\u6b21\u904d\u5386\uff0c\u6bcf\u6b21\u90fd\u8981\u6bd4\u8f83\u76f8\u90bb\u5143\u7d20\u3002 \u5192\u6ce1\u6392\u5e8f\u7684\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n^2)\uff0c\u8fd9\u662f\u56e0\u4e3a\u5b83\u4e0d\u4f1a\u5229\u7528\u8f93\u5165\u6570\u636e\u7684\u4efb\u4f55\u6709\u5e8f\u6027\u3002\u65e0\u8bba\u8f93\u5165\u6570\u636e\u662f\u6709\u5e8f\u7684\u3001\u9006\u5e8f\u7684\uff0c\u8fd8\u662f\u968f\u673a\u6392\u5217\u7684\uff0c\u90fd\u9700\u8981\u6267\u884c\u76f8\u540c\u6570\u91cf\u7684\u6bd4\u8f83\u548c\u4ea4\u6362\u64cd\u4f5c\u3002 \u603b\u4e4b\uff0c\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u867d\u7136\u51cf\u5c11\u4e86\u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\uff0c\u4f46\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u4ecd\u7136\u9700\u8981\u6267\u884c\u5927\u7ea6 n(n-1)/2 \u6b21\u6bd4\u8f83\u64cd\u4f5c\uff0c\u56e0\u6b64\u5b83\u7684\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662fO(n^2)\u3002\u5192\u6ce1\u6392\u5e8f\u7684\u6027\u80fd\u4e3b\u8981\u53d7\u5230\u6570\u636e\u89c4\u6a21\u7684\u5f71\u54cd\uff0c\u800c\u4e0d\u592a\u53d7\u5230\u5177\u4f53\u6570\u636e\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u56e0\u6b64\uff0c\u5b83\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u4ecd\u7136\u5177\u6709\u4e8c\u6b21\u65f6\u95f4\u590d\u6742\u5ea6\u3002 \u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u63d2\u5165\u6392\u5e8f\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e0a\u80fd\u591f\u5f88\u597d\u5730\u5de5\u4f5c\u3002 \u89e3\u7b54\uff1a \u63d2\u5165\u6392\u5e8f\u4e4b\u6240\u4ee5\u80fd\u591f\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e0a\u5f88\u597d\u5730\u5de5\u4f5c\uff0c\u662f\u56e0\u4e3a\u5b83\u7684\u6838\u5fc3\u601d\u60f3\u662f\u9010\u6b65\u6784\u5efa\u6709\u5e8f\u7684\u5b50\u5217\u8868\uff0c\u800c\u4e0d\u662f\u50cf\u9009\u62e9\u6392\u5e8f\u6216\u5192\u6ce1\u6392\u5e8f\u4e00\u6837\u603b\u662f\u8003\u8651\u6574\u4e2a\u5217\u8868\u3002\u8fd9\u4f7f\u5f97\u63d2\u5165\u6392\u5e8f\u5728\u5904\u7406\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u65f6\u5177\u6709\u4e00\u4e9b\u4f18\u52bf\uff1a \u5c40\u90e8\u6027\u539f\u7406\uff1a\u63d2\u5165\u6392\u5e8f\u5229\u7528\u4e86\u5c40\u90e8\u6027\u539f\u7406\uff0c\u5373\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u6570\u636e\u9879\u7684\u6b63\u786e\u4f4d\u7f6e\u79bb\u5b83\u4eec\u5f53\u524d\u7684\u4f4d\u7f6e\u5f88\u8fd1\u3002\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e2d\uff0c\u5927\u591a\u6570\u6570\u636e\u9879\u5df2\u7ecf\u63a5\u8fd1\u4e8e\u5b83\u4eec\u7684\u6700\u7ec8\u4f4d\u7f6e\uff0c\u56e0\u6b64\u53ea\u9700\u8981\u8fdb\u884c\u5c11\u91cf\u7684\u79fb\u52a8\u64cd\u4f5c\u3002 \u9002\u5e94\u6027\uff1a\u63d2\u5165\u6392\u5e8f\u662f\u4e00\u79cd\u81ea\u9002\u5e94\u6392\u5e8f\u7b97\u6cd5\uff0c\u5b83\u53ef\u4ee5\u6839\u636e\u8f93\u5165\u6570\u636e\u7684\u6709\u5e8f\u6027\u8fdb\u884c\u81ea\u52a8\u8c03\u6574\u3002\u5728\u5904\u7406\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u65f6\uff0c\u63d2\u5165\u6392\u5e8f\u7684\u6027\u80fd\u4f1a\u66f4\u597d\uff0c\u56e0\u4e3a\u4e0d\u9700\u8981\u6267\u884c\u592a\u591a\u7684\u6bd4\u8f83\u548c\u4ea4\u6362\u64cd\u4f5c\u3002 \u7b80\u5355\u6027\uff1a\u63d2\u5165\u6392\u5e8f\u7684\u5b9e\u73b0\u975e\u5e38\u7b80\u5355\u76f4\u89c2\uff0c\u5b83\u53ea\u6d89\u53ca\u5230\u9010\u4e2a\u63d2\u5165\u5143\u7d20\u5230\u6b63\u786e\u7684\u4f4d\u7f6e\u3002\u8fd9\u79cd\u7b80\u5355\u6027\u4f7f\u5f97\u63d2\u5165\u6392\u5e8f\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\u6bd4\u66f4\u590d\u6742\u7684\u6392\u5e8f\u7b97\u6cd5\u66f4\u5177\u7ade\u4e89\u529b\u3002 \u867d\u7136\u63d2\u5165\u6392\u5e8f\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e0a\u8868\u73b0\u826f\u597d\uff0c\u4f46\u5728\u5904\u7406\u5927\u89c4\u6a21\u4e71\u5e8f\u6570\u636e\u96c6\u65f6\uff0c\u5b83\u7684\u6027\u80fd\u4e0d\u5982\u5feb\u901f\u6392\u5e8f\u3001\u5f52\u5e76\u6392\u5e8f\u7b49\u66f4\u9ad8\u7ea7\u7684\u6392\u5e8f\u7b97\u6cd5\u3002\u56e0\u6b64\uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u6839\u636e\u6570\u636e\u7684\u6027\u8d28\u9009\u62e9\u9002\u5f53\u7684\u6392\u5e8f\u7b97\u6cd5\u662f\u91cd\u8981\u7684\u3002\u63d2\u5165\u6392\u5e8f\u901a\u5e38\u9002\u7528\u4e8e\u5c0f\u89c4\u6a21\u6570\u636e\u6216\u8005\u5df2\u7ecf\u90e8\u5206\u6709\u5e8f\u7684\u6570\u636e\uff0c\u800c\u4e0d\u662f\u5927\u89c4\u6a21\u4e71\u5e8f\u6570\u636e\u7684\u6392\u5e8f\u3002 3.5.\u66f4\u5feb\u7684\u6392\u5e8f \u00b6 \u5206\u6cbb\u6cd5\uff08divide-and-conquer\uff09\u7b56\u7565\uff1a\u628a\u5217\u8868\u5206\u6210\u66f4\u5c0f\u7684\u5b50\u5217\u8868\uff0c\u7136\u540e\u518d\u901a\u8fc7\u9012\u5f52\u628a\u8fd9\u4e9b\u5b50\u5217\u8868\u6392\u5e8f\u3002 \u7406\u60f3\u60c5\u51b5\u4e0b\uff0c\u5982\u679c\u8fd9\u4e9b\u88ab\u62c6\u5206\u7684\u5b50\u5217\u8868\u7684\u6570\u91cf\u662f logn \uff0c\u800c\u628a\u6bcf\u4e2a\u5b50\u5217\u8868\u8fdb\u884c\u5408\u5e76\u6240\u9700\u7684\u5de5\u4f5c\u91cf\u4e3a n \uff0c\u90a3\u4e48\u8fd9\u79cd\u6392\u5e8f\u7b97\u6cd5\u7684\u603b\u590d\u6742\u5ea6\u5c31\u662f O(nlogn) \uff0c\u76f8\u6bd4 O(n^2) \u7684\u5de5\u4f5c\u91cf\u589e\u957f\u8981\u4f4e\u5f88\u591a\u3002 3.5.1.\u5feb\u901f\u6392\u5e8f \u00b6 \u5feb\u901f\u6392\u5e8f\uff08QuickSort\uff09\u662f\u6392\u9664\u7a33\u5b9a\u6027\u56e0\u7d20\u540e\u6700\u5e38\u7528\u7684\u6392\u5e8f\u3002 \u9996\u5148\u4ece\u5217\u8868\u7684\u4e2d\u95f4\u4f4d\u7f6e\u9009\u62e9\u4e00\u4e2a\u5143\u7d20\uff0c\u8fd9\u4e2a\u5143\u7d20\u88ab\u79f0\u4e3a\u57fa\u51c6\uff08pivot\uff09\uff1b \u5bf9\u5217\u8868\u91cc\u7684\u5143\u7d20\u8fdb\u884c\u5206\u5272\uff0c\u628a\u5c0f\u4e8e\u57fa\u51c6\u7684\u6240\u6709\u5143\u7d20\u79fb\u52a8\u5230\u57fa\u51c6\u7684\u5de6\u4fa7\uff0c\u800c\u628a\u5176\u4f59\u5143\u7d20\u90fd\u79fb\u5230\u57fa\u51c6\u7684\u53f3\u4fa7\u3002 \u5982\u679c\u57fa\u51c6\u6b63\u597d\u662f\u6700\u5927\u7684\u5143\u7d20\uff0c\u90a3\u4e48\u5b83\u6700\u7ec8\u4f1a\u5904\u4e8e\u5217\u8868\u7684\u6700\u53f3\u4fa7\uff1b \u5982\u679c\u57fa\u51c6\u6b63\u597d\u662f\u6700\u5c0f\u7684\u5143\u7d20\uff0c\u90a3\u4e48\u5b83\u5c31\u4f1a\u5728\u6700\u5de6\u4fa7\uff1b \u5206\u6cbb\u6cd5\u3002\u5c06\u8fd9\u4e2a\u8fc7\u7a0b\u9012\u5f52\u5730\u5e94\u7528\u5230\u901a\u8fc7\u57fa\u51c6\u800c\u628a\u539f\u5217\u8868\u5206\u5272\u7684\u5b50\u5217\u8868\u4e0a\uff0c\u5176\u4e2d\uff1a \u4e00\u4e2a\u65b0\u7684\u5b50\u5217\u8868\u7531\u57fa\u51c6\u5de6\u4fa7\u7684\u6240\u6709\u5143\u7d20\uff08\u8f83\u5c0f\u7684\u5143\u7d20\uff09\u7ec4\u6210\uff0c \u53e6\u4e00\u4e2a\u65b0\u7684\u5b50\u5217\u8868\u7531\u57fa\u51c6\u53f3\u4fa7\u7684\u6240\u6709\u5143\u7d20\uff08\u8f83\u5927\u7684\u5143\u7d20\uff09\u7ec4\u6210\uff1b \u5f53\u5206\u51fa\u7684\u5b50\u5217\u8868\u5185\u5c11\u4e8e\u4e24\u4e2a\u5143\u7d20\u65f6\uff0c\u8fd9\u4e2a\u8fc7\u7a0b\u7ec8\u6b62\uff1b 3.5.1.1.\u5206\u5272 \u00b6 \u8fd9\u4e2a\u7b97\u6cd5\u91cc\u6700\u590d\u6742\u7684\u90e8\u5206\u662f\u5bf9\u5143\u7d20\u8fdb\u884c\u5206\u5272\u4ece\u800c\u5f97\u5230\u5b50\u5217\u8868\u7684\u64cd\u4f5c\u3002 \u5c06\u57fa\u51c6\u4e0e\u5b50\u5217\u8868\u91cc\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\u3002 \u5728\u5df2\u77e5\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u548c\u5176\u4ed6\u5143\u7d20\u4e4b\u95f4\u6784\u5efa\u4e00\u4e2a\u8fb9\u754c\u3002\u4e00\u5f00\u59cb\uff0c\u8fd9\u4e2a\u8fb9\u754c\u4f1a\u5904\u4e8e\u7b2c\u4e00\u4e2a\u5143\u7d20\u4e4b\u524d\u3002 \u4ece\u5b50\u5217\u8868\u8fb9\u754c\u4e4b\u540e\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\u5411\u53f3\u626b\u63cf\u3002\u5f53\u6bcf\u6b21\u9047\u5230\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u65f6\uff0c\u5c06\u5b83\u548c\u8fb9\u754c\u4e4b\u540e\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\uff0c\u5e76\u4e14\u5c06\u8fb9\u754c\u5411\u53f3\u79fb\u52a8\u3002 \u5728\u7ed3\u675f\u7684\u65f6\u5019\uff0c\u5c06\u57fa\u51c6\u548c\u8fb9\u754c\u4e4b\u540e\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\u3002 \u793a\u4f8b\u5217\u8868\uff1a[12,19,17,18,14,11,15,13,16]\uff0c\u4e0b\u56fe\u5c55\u793a\u4e86\u5206\u5272\u7684\u6bcf\u4e00\u6b65\u8fc7\u7a0b\u3002 3.5.1.2.\u5feb\u901f\u6392\u5e8f\u590d\u6742\u5ea6\u5206\u6790 \u00b6 \u5feb\u901f\u6392\u5e8f\uff08Quick Sort\uff09\u662f\u4e00\u79cd\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u5176\u5e73\u5747\u548c\u6700\u574f\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662f O(n log n) \u3002\u4e0b\u9762\u662f\u5feb\u901f\u6392\u5e8f\u7684\u590d\u6742\u5ea6\u5206\u6790\uff1a \u5728\u7b2c\u4e00\u6b21\u8fdb\u884c\u5206\u5272\u64cd\u4f5c\u65f6\uff0c\u6211\u4eec\u5c06\u626b\u63cf\u5217\u8868\u91cc\u4ece\u5f00\u5934\u5230\u7ed3\u5c3e\u7684\u6240\u6709\u5143\u7d20\u3002\u56e0\u6b64\uff0c\u5728\u8fd9\u4e2a\u64cd\u4f5c\u671f\u95f4\u5de5\u4f5c\u91cf\u662f\u548c\u5217\u8868\u7684\u957f\u5ea6 n \u6210\u6b63\u6bd4\u7684\u3002\u8fd9\u6b21\u5206\u5272\u4e4b\u540e\u7684\u5de5\u4f5c\u91cf\u4f1a\u548c\u5de6\u5b50\u5217\u8868\u52a0\u4e0a\u53f3\u5b50\u5217\u8868\u7684\u603b\u957f\u5ea6\u6210\u6b63\u6bd4\uff0c\u4e5f\u5c31\u662f n-1 \u3002 \u518d\u6b21\u5bf9\u8fd9\u4e24\u4e2a\u5b50\u5217\u8868\u8fdb\u884c\u5206\u5272\u4e4b\u540e\uff0c\u5c31\u4f1a\u4ea7\u751f4\u4e2a\u52a0\u8d77\u6765\u603b\u957f\u5ea6\u5927\u7ea6\u4e3a n \u7684\u5217\u8868\u6bb5\u3002\u56e0\u6b64\uff0c\u5bf9\u5b83\u4eec\u8fdb\u884c\u5206\u5272\u7684\u603b\u5de5\u4f5c\u91cf\u8fd8\u662f\u548c n \u6210\u6b63\u6bd4\u7684\u3002\u968f\u7740\u5217\u8868\u88ab\u5206\u5272\u6210\u66f4\u591a\u6bb5\uff0c\u603b\u5de5\u4f5c\u91cf\u4f1a\u4e00\u76f4\u548c n \u6210\u6b63\u6bd4\u3002 \u8981\u5b8c\u6210\u6574\u4e2a\u5206\u6790\uff0c\u8fd8\u9700\u8981\u786e\u5b9a\u5217\u8868\u88ab\u5206\u5272\u4e86\u591a\u5c11\u6b21\u3002\u6309\u7167\u6700\u4e50\u89c2\u7684\u60c5\u51b5\u6765\u8bf4\uff08\u867d\u7136\u5728\u5b9e\u9645\u64cd\u4f5c\u7684\u65f6\u5019\uff0c\u901a\u5e38\u5e76\u4e0d\u4f1a\u51fa\u73b0\u8fd9\u4e48\u597d\u7684\u60c5\u51b5\uff09\uff0c\u5047\u8bbe\u6bcf\u6b21\u65b0\u5b50\u5217\u8868\u4e4b\u95f4\u7684\u5206\u754c\u7ebf\u90fd\u5c3d\u53ef\u80fd\u5730\u9760\u8fd1\u5f53\u524d\u5217\u8868\u7684\u4e2d\u5fc3\uff0c\u901a\u5e38\u8fd9\u79cd\u60c5\u51b5\u5e76\u4e0d\u5e38\u89c1\u3002\u4ece\u4e8c\u5206\u641c\u7d22\u7b97\u6cd5\u7684\u8ba8\u8bba\u91cc\u53ef\u77e5\uff0c\u8981\u628a\u5217\u8868\u4e0d\u65ad\u5730\u5206\u6210\u4e24\u534a\uff0c\u5927\u7ea6\u5728 log n \u6b65\u7684\u65f6\u5019\u5c31\u53ea\u5269\u4e0b\u4e00\u4e2a\u5143\u7d20\u4e86\u3002 \u56e0\u6b64\uff0c\u8fd9\u4e2a\u7b97\u6cd5\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u4e3a O(n log n) \u3002\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u6765\u8003\u8651\u6709\u5e8f\u5217\u8868\u7684\u60c5\u51b5\u3002\u5982\u679c\u9009\u62e9\u7684\u57fa\u51c6\u5143\u7d20\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20\uff0c\u90a3\u4e48\u5728\u7b2c\u4e00\u6b21\u5206\u5272\u4e4b\u540e\u5b83\u7684\u53f3\u8fb9\u4f1a\u6709 n-1 \u4e2a\u5143\u7d20\uff0c\u5728\u7b2c\u4e8c\u6b21\u5206\u5272\u4e4b\u540e\u5b83\u7684\u53f3\u8fb9\u6709 n-2 \u4e2a\u5143\u7d20\uff0c\u4ee5\u6b64\u7c7b\u63a8\uff0c \u5c3d\u7ba1\u6574\u4e2a\u64cd\u4f5c\u91cc\u6ca1\u6709\u4ea4\u6362\u4efb\u4f55\u5143\u7d20\uff0c\u4f46\u5206\u5272\u603b\u5171\u4e5f\u6267\u884c\u4e86 n-1 \u6b21\uff0c\u4e8e\u662f\u6267\u884c\u7684\u6bd4\u8f83\u603b\u6570\u5c31\u662f n^2/2-n/2 \u3002\u8fd9\u4e0e\u9009\u62e9\u6392\u5e8f\u4ee5\u53ca\u5192\u6ce1\u6392\u5e8f\u7684\u60c5\u51b5\u662f\u4e00\u6837\u7684\u3002\u56e0\u6b64\uff0c\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7b97\u6cd5\u7684\u6027\u80fd\u4e3a O(n^2) \u3002\u5982\u679c\u628a\u5feb\u901f\u6392\u5e8f\u5b9e\u73b0\u6210\u9012\u5f52\u7b97\u6cd5\uff0c\u90a3\u4e48\u5728\u5bf9\u5b83\u8fdb\u884c\u5206\u6790\u65f6\u8fd8\u5fc5\u987b\u8981\u8003\u8651\u8c03\u7528\u6808\u7684\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\u3002\u7531\u4e8e\u5bf9\u4e8e\u6808\u7684\u4e00\u5e27\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u90fd\u9700\u8981\u56fa\u5b9a\u7684\u5185\u5b58\uff0c\u5e76\u4e14\u6bcf\u6b21\u5206\u5272\u4e4b\u540e\u90fd\u4f1a\u6709\u4e24\u6b21\u9012\u5f52\u8c03\u7528\u3002\u56e0\u6b64\uff0c\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u5185\u5b58\u7684\u4f7f\u7528\u91cf\u4f1a\u662f O(log n) \uff0c\u800c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u5185\u5b58\u4f7f\u7528\u91cf\u662f O(n) \u3002 \u5c3d\u7ba1\u5feb\u901f\u6392\u5e8f\u5904\u4e8e\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u53ef\u80fd\u6027\u5f88\u5c0f\uff0c\u6211\u4eec\u8fd8\u662f\u4f1a\u52aa\u529b\u5730\u53bb\u907f\u514d\u8fd9\u79cd\u60c5\u51b5\uff0c\u56e0\u6b64\uff0c\u5b83\u4eec\u5e76\u4e0d\u4f1a\u5728\u7b2c\u4e00\u4e2a\u6216\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u9009\u62e9\u57fa\u51c6\u5143\u7d20\u3002\u6709\u5176\u4ed6\u4e00\u4e9b\u9009\u62e9\u57fa\u51c6\u7684\u65b9\u6cd5\u53ef\u4ee5\u8ba9\u8fd9\u4e2a\u7b97\u6cd5\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u6709\u5927\u7ea6 O(n log n) \u7684\u6027\u80fd\uff0c\u6bd4\u5982\uff0c\u53ef\u4ee5\u9009\u62e9\u968f\u673a\u4f4d\u7f6e\u4e0a\u7684\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\uff0c\u6216\u8005\u9009\u62e9\u6574\u4e2a\u5217\u8868\u91cc\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3001\u4e2d\u95f4\u4f4d\u7f6e\u4ee5\u53ca\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u8fd93\u4e2a\u5143\u7d20\u7684\u4e2d\u4f4d\u6570\u3002 \u603b\u7ed3\uff1a \u6700\u597d\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u4e5f\u5c31\u662f\u6bcf\u6b21\u9009\u62e9\u7684\u57fa\u51c6\u5143\u7d20\u90fd\u521a\u597d\u5c06\u8f93\u5165\u6570\u636e\u5206\u6210\u4e24\u4e2a\u7b49\u957f\u7684\u5b50\u6570\u7ec4\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n log n) \u3002\u8fd9\u79cd\u60c5\u51b5\u901a\u5e38\u53d1\u751f\u5728\u57fa\u51c6\u5143\u7d20\u7684\u9009\u62e9\u975e\u5e38\u5408\u7406\u7684\u60c5\u51b5\u4e0b\uff0c\u4f8b\u5982\u5728\u6bcf\u6b21\u9009\u62e9\u4e2d\u90fd\u9009\u62e9\u4e2d\u95f4\u5143\u7d20\u3002 \u5e73\u5747\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e5f\u662f O(n log n) \u3002\u8fd9\u662f\u56e0\u4e3a\u5feb\u901f\u6392\u5e8f\u662f\u4e00\u79cd\u5206\u6cbb\u7b97\u6cd5\uff0c\u6bcf\u6b21\u5c06\u95ee\u9898\u5206\u6210\u4e24\u4e2a\u5b50\u95ee\u9898\uff0c\u7136\u540e\u9012\u5f52\u5730\u89e3\u51b3\u8fd9\u4e9b\u5b50\u95ee\u9898\u3002\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u6bcf\u6b21\u5206\u5272\u64cd\u4f5c\u90fd\u80fd\u5c06\u95ee\u9898\u89c4\u6a21\u51cf\u534a\uff0c\u56e0\u6b64\u9700\u8981\u6267\u884c O(n log n) \u6b21\u5206\u5272\u64cd\u4f5c\uff0c\u6bcf\u6b21\u5206\u5272\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002\u56e0\u6b64\uff0c\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n log n) \u3002 \u6700\u574f\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n^2) \u3002\u6700\u574f\u60c5\u51b5\u53d1\u751f\u5728\u6bcf\u6b21\u9009\u62e9\u7684\u57fa\u51c6\u5143\u7d20\u90fd\u662f\u8f93\u5165\u6570\u636e\u4e2d\u7684\u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\uff0c\u5bfc\u81f4\u5206\u5272\u64cd\u4f5c\u4e0d\u5747\u8861\uff0c\u6bcf\u6b21\u5206\u5272\u53ea\u80fd\u5c06\u95ee\u9898\u89c4\u6a21\u51cf\u5c111\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u9000\u5316\u4e3a\u5192\u6ce1\u6392\u5e8f\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \u3002 \u5feb\u901f\u6392\u5e8f\u7684\u5e73\u5747\u548c\u6700\u597d\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n log n) \uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\u901a\u5e38\u6027\u80fd\u4f18\u8d8a\u3002\u7136\u800c\uff0c\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \uff0c\u56e0\u6b64\u5728\u5b9e\u73b0\u5feb\u901f\u6392\u5e8f\u65f6\u9700\u8981\u7279\u522b\u6ce8\u610f\u57fa\u51c6\u5143\u7d20\u7684\u9009\u62e9\u4ee5\u907f\u514d\u6700\u574f\u60c5\u51b5\u7684\u53d1\u751f\u3002 3.5.1.3.\u5b9e\u73b0\u5feb\u901f\u6392\u5e8f \u00b6 \u4ee5\u4e0a\u9762\u56fe\u793a\u7684\u5217\u8868 [12,19,17,18,14,11,15,13,16] \u4e3a\u4f8b\uff0c\u4e0b\u9762\u662f\u5b9e\u73b0\u4ee3\u7801\uff1a import random def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def quicksort ( lyst ): # left\u7684\u521d\u59cb\u503c\u662f0 # right\u7684\u521d\u59cb\u503c\u662f\u5217\u8868\u957f\u5ea6\u51cf1 quicksortHelper ( lyst , 0 , len ( lyst ) - 1 ) def quicksortHelper ( lyst , left , right ): print ( lyst ) if left < right : pivotLocation = partition ( lyst , left , right ) quicksortHelper ( lyst , left , pivotLocation - 1 ) quicksortHelper ( lyst , pivotLocation + 1 , right ) def partition ( lyst , left , right ): \"\"\"\u5bf9\u5217\u8868\u8fdb\u884c\u5206\u533a\"\"\" # \u627e\u5230\u57fa\u51c6\u5143\u7d20\uff08pivot\uff09\uff0c\u5e76\u548c\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u4e92\u6362 middle = ( left + right ) // 2 pivot = lyst [ middle ] lyst [ middle ] = lyst [ right ] lyst [ right ] = pivot # \u8bbe\u5b9a\u8fb9\u754c\u5143\u7d20\uff08boundary point\uff09\uff0c\u521d\u59cb\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20 boundary = left print ( \"pivot: \" , pivot , \"boundary: \" , lyst [ boundary ]) # \u628a\u6240\u6709\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u90fd\u79fb\u52a8\u5230\u8fb9\u754c\u7684\u5de6\u8fb9 for index in range ( left , right ): if lyst [ index ] < pivot : swap ( lyst , index , boundary ) boundary += 1 # \u4ea4\u6362\u57fa\u51c6\u5143\u7d20\u548c\u8fb9\u754c\u5143\u7d20 swap ( lyst , right , boundary ) print ( lyst ) return boundary def main ( size = 20 , sort = quicksort ): lyst = [ 12 , 19 , 17 , 18 , 14 , 11 , 15 , 13 , 16 ] sort ( lyst ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # [12, 19, 17, 18, 14, 11, 15, 13, 16] # pivot: 14 boundary: 12 # [12, 11, 13, 14, 16, 19, 15, 17, 18] # [12, 11, 13, 14, 16, 19, 15, 17, 18] # pivot: 11 boundary: 12 # [11, 13, 12, 14, 16, 19, 15, 17, 18] # [11, 13, 12, 14, 16, 19, 15, 17, 18] # [11, 13, 12, 14, 16, 19, 15, 17, 18] # pivot: 13 boundary: 12 # [11, 12, 13, 14, 16, 19, 15, 17, 18] # [11, 12, 13, 14, 16, 19, 15, 17, 18] # [11, 12, 13, 14, 16, 19, 15, 17, 18] # [11, 12, 13, 14, 16, 19, 15, 17, 18] # pivot: 15 boundary: 16 # [11, 12, 13, 14, 15, 19, 18, 17, 16] # [11, 12, 13, 14, 15, 19, 18, 17, 16] # [11, 12, 13, 14, 15, 19, 18, 17, 16] # pivot: 18 boundary: 19 # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] # pivot: 16 boundary: 17 # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] \u628amain()\u6539\u6210\u5982\u4e0b\uff0c\u5219\u53ef\u4ee5\u751f\u6210\u753120\u4e2a\u968f\u673a\u6574\u6570\u7ec4\u6210\u7684\u5217\u8868\uff1a def main ( size = 20 , sort = quicksort ): lyst = [] for count in range ( size ): lyst . append ( random . randint ( 1 , size + 1 )) print ( lyst ) sort ( lyst ) print ( lyst ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u7b2c\u4e00\u6b21\u8fd0\u884c # [3, 19, 18, 11, 2, 16, 2, 13, 14, 1, 20, 1, 1, 19, 19, 9, 16, 1, 7, 4] # [1, 1, 1, 1, 2, 2, 3, 4, 7, 9, 11, 13, 14, 16, 16, 18, 19, 19, 19, 20] # \u7b2c\u4e8c\u6b21\u8fd0\u884c # [20, 4, 1, 15, 6, 4, 3, 16, 21, 4, 12, 9, 16, 10, 3, 6, 2, 15, 21, 4] # [1, 2, 3, 3, 4, 4, 4, 4, 6, 6, 9, 10, 12, 15, 15, 16, 16, 20, 21, 21] 3.5.2.\u5f52\u5e76\u6392\u5e8f \u00b6 \u5f52\u5e76\u6392\u5e8f\u7684\u7b97\u6cd5\u4e5f\u662f\u91c7\u7528\u5206\u6cbb\u6cd5\uff08Divide and Conquer\uff09\u7684\u4e00\u4e2a\u975e\u5e38\u5178\u578b\u7684\u5e94\u7528\uff0c\u901a\u8fc7\u9012\u5f52\u548c\u5206\u6cbb\u7b56\u7565\u6765\u7a81\u7834 O(n^2) \u6027\u80fd\u74f6\u9888\u7684\u3002 \u4e0b\u9762\u662f\u5bf9\u8fd9\u4e2a\u7b97\u6cd5\u7684\u7b80\u5355\u63cf\u8ff0\u3002 \u5206\u89e3\uff08Divide\uff09\uff1a\u5c06n\u4e2a\u5143\u7d20\u5206\u6210\u4e2a\u542bn/2\u4e2a\u5143\u7d20\u7684\u5b50\u5e8f\u5217\u3002 \u89e3\u51b3\uff08Conquer\uff09\uff1a\u7528\u5408\u5e76\u6392\u5e8f\u6cd5\u5bf9\u4e24\u4e2a\u5b50\u5e8f\u5217\u9012\u5f52\u7684\u6392\u5e8f\u3002 \u5408\u5e76\uff08Combine\uff09\uff1a\u5408\u5e76\u4e24\u4e2a\u5df2\u6392\u5e8f\u7684\u5b50\u5e8f\u5217\u5df2\u5f97\u5230\u6392\u5e8f\u7ed3\u679c\u3002 \u7b97\u6cd5\u601d\u8def\uff1a \u8fed\u4ee3\u6cd5 \u7533\u8bf7\u7a7a\u95f4\uff0c\u4f7f\u5176\u5927\u5c0f\u4e3a\u4e24\u4e2a\u5df2\u7ecf\u6392\u5e8f\u5e8f\u5217\u4e4b\u548c\uff0c\u8be5\u7a7a\u95f4\u7528\u6765\u5b58\u653e\u5408\u5e76\u540e\u7684\u5e8f\u5217\uff1b \u8bbe\u5b9a\u4e24\u4e2a\u6307\u9488\uff0c\u6700\u521d\u4f4d\u7f6e\u5206\u522b\u4e3a\u4e24\u4e2a\u5df2\u7ecf\u6392\u5e8f\u5e8f\u5217\u7684\u8d77\u59cb\u4f4d\u7f6e\uff1b \u6bd4\u8f83\u4e24\u4e2a\u6307\u9488\u6240\u6307\u5411\u7684\u5143\u7d20\uff0c\u9009\u62e9\u76f8\u5bf9\u5c0f\u7684\u5143\u7d20\u653e\u5165\u5230\u5408\u5e76\u7a7a\u95f4\uff0c\u5e76\u79fb\u52a8\u6307\u9488\u5230\u4e0b\u4e00\u4f4d\u7f6e\uff1b \u91cd\u590d\u6b65\u9aa43\u76f4\u5230\u67d0\u4e00\u6307\u9488\u5230\u8fbe\u5e8f\u5217\u5c3e\uff1b \u5c06\u53e6\u4e00\u5e8f\u5217\u5269\u4e0b\u7684\u6240\u6709\u5143\u7d20\u76f4\u63a5\u590d\u5236\u5230\u5408\u5e76\u5e8f\u5217\u5c3e\uff1b \u9012\u5f52\u6cd5 \u5c06\u5e8f\u5217\u6bcf\u76f8\u90bb\u4e24\u4e2a\u6570\u5b57\u8fdb\u884c\u5f52\u5e76\u64cd\u4f5c\uff0c\u5f62\u6210 floor(n/2) \u4e2a\u5e8f\u5217\uff0c\u6392\u5e8f\u540e\u6bcf\u4e2a\u5e8f\u5217\u5305\u542b\u4e24\u4e2a\u5143\u7d20\uff1b \u5c06\u4e0a\u8ff0\u5e8f\u5217\u518d\u6b21\u5f52\u5e76\uff0c\u5f62\u6210 floor(n/4) \u4e2a\u5e8f\u5217\uff0c\u6bcf\u4e2a\u5e8f\u5217\u5305\u542b\u56db\u4e2a\u5143\u7d20\uff1b \u91cd\u590d\u6b65\u9aa42\uff0c\u76f4\u5230\u6240\u6709\u5143\u7d20\u6392\u5e8f\u5b8c\u6bd5\uff1b \u5728\u9876\u5c42\u5b9a\u4e49\u4e863\u4e2aPython\u51fd\u6570\u8fdb\u884c\u534f\u4f5c\u3002 mergeSort \uff1a\u7528\u6237\u8c03\u7528\u7684\u51fd\u6570\uff1b mergeSortHelper \uff1a\u8f85\u52a9\u51fd\u6570\uff0c\u7528\u6765\u9690\u85cf\u9012\u5f52\u8c03\u7528\u6240\u9700\u8981\u7684\u989d\u5916\u53c2\u6570\uff1b merge \uff1a\u5b9e\u73b0\u5408\u5e76\u8fc7\u7a0b\u7684\u51fd\u6570\uff1b 3.5.2.1.\u5408\u5e76\u8fc7\u7a0b\u7684\u5b9e\u73b0 \u00b6 \u5408\u5e76\u8fc7\u7a0b\u7528\u5230\u4e00\u4e2a\u4e0e\u5217\u8868\u5927\u5c0f\u76f8\u540c\u7684\u6570\u7ec4\uff0c\u8fd9\u4e2a\u6570\u7ec4\u53ef\u4ee5\u628a\u5b83\u79f0\u4e3a copyBuffer \u3002\u4e3a\u4e86\u907f\u514d\u6bcf\u6b21\u8c03\u7528 merge \u65f6\u90fd\u8981\u4e3a copyBuffer \u7684\u5206\u914d\u548c\u91ca\u653e\u4ea7\u751f\u5f00\u9500\uff0c\u8fd9\u4e2a\u7f13\u51b2\u533a\u4f1a\u5728 mergeSort \u51fd\u6570\u91cc\u5c31\u5206\u914d\u597d\uff0c\u7136\u540e\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7ed9 mergeSortHelper \u548c merge \u51fd\u6570\u3002\u6bcf\u6b21\u8c03\u7528 mergeSortHelper \u51fd\u6570\u65f6\uff0c\u5b83\u8fd8\u9700\u8981\u77e5\u9053\u5e94\u8be5\u4f7f\u7528\u7684\u5b50\u5217\u8868\u7684\u8303\u56f4\u3002\u8fd9\u4e2a\u8303\u56f4\u53ef\u4ee5\u7531\u53e6\u5916\u4e24\u4e2a\u53c2\u6570 low \u548c high \u6765\u63d0\u4f9b\u3002\u5177\u4f53\u5b9e\u73b0\u53c2\u8003 mergeSort \u51fd\u6570\u7684\u4ee3\u7801\u3002 \u5728\u68c0\u67e5\u4f20\u9012\u7684\u5b50\u5217\u8868\u662f\u4e0d\u662f\u81f3\u5c11\u6709\u4e24\u4e2a\u5143\u7d20\u4e4b\u540e\uff0c mergeSortHelper \u51fd\u6570\u5c06\u4f1a\u8ba1\u7b97\u8fd9\u4e2a\u5b50\u5217\u8868\u7684\u4e2d\u70b9\uff0c\u5e76\u4e14\u5bf9\u4e2d\u70b9\u5de6\u53f3\u4e24\u90e8\u5206\u8fdb\u884c\u9012\u5f52\u6392\u5e8f\uff0c\u6700\u540e\u518d\u8c03\u7528 merge \u51fd\u6570\u6765\u5408\u5e76\u7ed3\u679c\u3002\u5177\u4f53\u5b9e\u73b0\u53c2\u8003 mergeSortHelper \u51fd\u6570\u7684\u4ee3\u7801\u3002 merge \u51fd\u6570\u4f1a\u628a\u4e24\u4e2a\u5df2\u7ecf\u6392\u597d\u5e8f\u7684\u5b50\u5217\u8868\u5408\u5e76\u6210\u4e00\u4e2a\u66f4\u5927\u7684\u6709\u5e8f\u5217\u8868\u3002\u5728\u539f\u5217\u8868\u91cc\uff0c\u7b2c\u4e00\u4e2a\u5b50\u5217\u8868\u4f1a\u5728 low \u5230 middle \u4e4b\u95f4\uff1b\u7b2c\u4e8c\u4e2a\u5b50\u5217\u8868\u5219\u4f4d\u4e8e middle + 1 \u548c high \u4e4b\u95f4\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u5305\u542b\u5982\u4e0b3\u4e2a\u6b65\u9aa4\u3002 \u8bbe\u7f6e\u6307\u5411\u4e24\u4e2a\u5b50\u5217\u8868\u4e2d\u7b2c\u4e00\u4e2a\u5143\u7d20\u7684\u7d22\u5f15\u6307\u9488\u3002\u5b83\u4eec\u5206\u522b\u4f4d\u4e8e low \u548c middle +1 \uff1b \u4ece\u5b50\u5217\u8868\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\u91cd\u590d\u6bd4\u8f83\u8fd9\u4e9b\u5143\u7d20\u3002\u628a\u66f4\u5c0f\u7684\u90a3\u4e2a\u5143\u7d20\u4ece\u5b83\u6240\u5728\u7684\u5b50\u5217\u8868\u91cc\u590d\u5236\u5230\u62f7\u8d1d\u7f13\u51b2\u533a\u53bb\uff0c\u7136\u540e\u628a\u8fd9\u4e2a\u5b50\u5217\u8868\u7684\u7d22\u5f15\u79fb\u52a8\u5230\u4e0b\u4e00\u4e2a\u5143\u7d20\uff1b \u4e0d\u65ad\u5730\u6267\u884c\u8fd9\u4e2a\u64cd\u4f5c\uff0c\u76f4\u5230\u5df2\u7ecf\u5b8c\u5168\u590d\u5236\u4e86\u4e24\u4e2a\u5b50\u5217\u8868\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u5982\u679c\u5176\u4e2d\u4e00\u4e2a\u5b50\u5217\u8868\u5df2\u7ecf\u5230\u8fbe\u4e86\u672b\u5c3e\uff0c\u90a3\u4e48\u53ef\u4ee5\u628a\u53e6\u4e00\u4e2a\u5b50\u5217\u8868\u91cc\u7684\u5176\u4f59\u5143\u7d20\u76f4\u63a5\u590d\u5236\u8fc7\u53bb\uff1b \u628a copyBuffer \u4e2d low \u5230 high \u4e4b\u95f4\u7684\u90e8\u5206\u590d\u5236\u56de lyst \u4e2d\u7684\u76f8\u5e94\u4f4d\u7f6e\uff1b \u5b9e\u73b0\u4ee3\u7801\uff1a class Array ( object ): \"\"\" \u63cf\u8ff0\u4e00\u4e2a\u6570\u7ec4\u3002 \u6570\u7ec4\u7c7b\u4f3c\u5217\u8868\uff0c\u4f46\u6570\u7ec4\u53ea\u80fd\u4f7f\u7528[], len, iter, \u548c str\u8fd9\u4e9b\u5c5e\u6027\u3002 \u5b9e\u4f8b\u5316\u4e00\u4e2a\u6570\u7ec4\uff0c\u4f7f\u7528 = Array(, ) \u5176\u4e2dfill value\u9ed8\u8ba4\u503c\u662fNone\u3002 \"\"\" def __init__ ( self , capacity , fillValue = None ): \"\"\"Capacity\u662f\u6570\u7ec4\u7684\u5927\u5c0f. fillValue\u4f1a\u586b\u5145\u5728\u6bcf\u4e2a\u5143\u7d20\u4f4d\u7f6e, \u9ed8\u8ba4\u503c\u662fNone\"\"\" self . items = list () for count in range ( capacity ): self . items . append ( fillValue ) def __len__ ( self ): \"\"\"-> \u6570\u7ec4\u7684\u5927\u5c0f\"\"\" return len ( self . items ) def __str__ ( self ): \"\"\"-> \u5c06\u6570\u7ec4\u5b57\u7b26\u4e32\u5316\"\"\" return str ( self . items ) def __iter__ ( self ): \"\"\"\u652f\u6301for\u5faa\u73af\u5bf9\u6570\u7ec4\u8fdb\u884c\u904d\u5386.\"\"\" return iter ( self . items ) def __getitem__ ( self , index ): \"\"\"\u7528\u4e8e\u8bbf\u95ee\u7d22\u5f15\u5904\u7684\u4e0b\u6807\u8fd0\u7b97\u7b26.\"\"\" return self . items [ index ] def __setitem__ ( self , index , newItem ): \"\"\"\u4e0b\u6807\u8fd0\u7b97\u7b26\u7528\u4e8e\u5728\u7d22\u5f15\u5904\u8fdb\u884c\u66ff\u6362.\"\"\" self . items [ index ] = newItem def mergeSort ( lyst ): # lyst : \u7528\u4e8e\u6392\u5e8f\u7684\u5217\u8868 # copyBuffer : \u7528\u4e8e\u5408\u5e76\u7684\u4e34\u65f6\u7a7a\u95f4 copyBuffer = Array ( len ( lyst )) mergeSortHelper ( lyst , copyBuffer , 0 , len ( lyst ) - 1 ) def mergeSortHelper ( lyst , copyBuffer , low , high ): # lyst : \u7528\u4e8e\u6392\u5e8f\u7684\u5217\u8868 # copyBuffer : \u7528\u4e8e\u5408\u5e76\u7684\u4e34\u65f6\u7a7a\u95f4 # low, high : \u5b50\u5217\u8868\u7684\u8fb9\u754c # middle : \u5b50\u5217\u8868\u7684\u4e2d\u70b9 if low < high : middle = ( low + high ) // 2 print ( f 'low: { lyst [ low ] } , middle: { lyst [ middle ] } , high: { lyst [ high ] } , copyBuffer: { copyBuffer } ' ) # \u9012\u5f52\u5904\u7406\u7b2c\u4e00\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\uff0c\u5373\u4e2d\u503c\u7684\u5de6\u6bb5\uff0c\u76f4\u81f3\u4e0d\u6ee1\u8db3low < high\u65f6\u9000\u51fa mergeSortHelper ( lyst , copyBuffer , low , middle ) # \u9012\u5f52\u5904\u7406\u7b2c\u4e8c\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\uff0c\u5373\u4e2d\u503c\u7684\u53f3\u6bb5\uff0c\u76f4\u81f3\u4e0d\u6ee1\u8db3low < high\u65f6\u9000\u51fa mergeSortHelper ( lyst , copyBuffer , middle + 1 , high ) # \u5f53\u524d\u5904\u7406\u7684\u5b50\u8868\u6570\u636e\u9001\u5165copyBuffer\uff0c\u5408\u5e76\u4e14\u6392\u5e8f merge ( lyst , copyBuffer , low , middle , high ) def merge ( lyst , copyBuffer , low , middle , high ): # lyst : \u7528\u4e8e\u6392\u5e8f\u7684\u5217\u8868 # copyBuffer : \u7528\u4e8e\u5408\u5e76\u7684\u4e34\u65f6\u7a7a\u95f4 # low : \u7b2c\u4e00\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u5f00\u5934 # middle : \u7b2c\u4e00\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u7ed3\u5c3e # middle + 1 : \u7b2c\u4e8c\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u5f00\u5934 # high : \u7b2c\u4e8c\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u7ed3\u5c3e # \u5c06 i1 \u548c i2 \u521d\u59cb\u5316\u4e3a\u6bcf\u4e2a\u5b50\u5217\u8868\u4e2d\u7684\u7b2c\u4e00\u9879 i1 = low i2 = middle + 1 # \u5c06\u5b50\u5217\u8868\u4e2d\u7684\u5143\u7d20\u4ea4\u9519\u653e\u5165copyBuffer\u4e2d\uff0c\u5e76\u4fdd\u6301\u987a\u5e8f\u3002 for i in range ( low , high + 1 ): if i1 > middle : copyBuffer [ i ] = lyst [ i2 ] # \u7b2c\u4e00\u4e2a\u5b50\u5217\u8868\u5df2\u7528\u5b8c i2 += 1 elif i2 > high : copyBuffer [ i ] = lyst [ i1 ] # \u7b2c\u4e8c\u4e2a\u5b50\u5217\u8868\u5df2\u7528\u5b8c i1 += 1 elif lyst [ i1 ] < lyst [ i2 ]: copyBuffer [ i ] = lyst [ i1 ] # \u7b2c\u4e00\u4e2a\u5b50\u8868\u4e2d\u7684\u5143\u7d20 < i1 += 1 else : copyBuffer [ i ] = lyst [ i2 ] # \u7b2c\u4e8c\u4e2a\u5b50\u8868\u4e2d\u7684\u5143\u7d20 < i2 += 1 print ( \"i=\" , i , \"\" , \"i1=\" , i1 , \"i2=\" , i2 , \"copyBuffer:\" , copyBuffer ) for i in range ( low , high + 1 ): # \u5c06\u5df2\u6392\u5e8f\u7684\u5143\u7d20\u590d\u5236\u56delyst\u4e2d\u7684\u6b63\u786e\u4f4d\u7f6e lyst [ i ] = copyBuffer [ i ] def main (): lyst = [ 12 , 19 , 17 , 18 , 14 , 11 , 15 , 13 , 16 ] print ( \"Original List\" , lyst ) mergeSort ( lyst ) print ( \"Sorted List\" , lyst ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Original List [12, 19, 17, 18, 14, 11, 15, 13, 16] # low: 12, middle: 14, high: 16, copyBuffer: [None, None, None, None, None, None, None, None, None] # low: 12, middle: 17, high: 14, copyBuffer: [None, None, None, None, None, None, None, None, None] # low: 12, middle: 19, high: 17, copyBuffer: [None, None, None, None, None, None, None, None, None] # low: 12, middle: 12, high: 19, copyBuffer: [None, None, None, None, None, None, None, None, None] # i= 1 i1= 1 i2= 2 copyBuffer: [12, 19, None, None, None, None, None, None, None] # i= 2 i1= 2 i2= 3 copyBuffer: [12, 17, 19, None, None, None, None, None, None] # low: 18, middle: 18, high: 14, copyBuffer: [12, 17, 19, None, None, None, None, None, None] # i= 4 i1= 4 i2= 5 copyBuffer: [12, 17, 19, 14, 18, None, None, None, None] # i= 4 i1= 3 i2= 5 copyBuffer: [12, 14, 17, 18, 19, None, None, None, None] # low: 11, middle: 15, high: 16, copyBuffer: [12, 14, 17, 18, 19, None, None, None, None] # low: 11, middle: 11, high: 15, copyBuffer: [12, 14, 17, 18, 19, None, None, None, None] # i= 6 i1= 6 i2= 7 copyBuffer: [12, 14, 17, 18, 19, 11, 15, None, None] # low: 13, middle: 13, high: 16, copyBuffer: [12, 14, 17, 18, 19, 11, 15, None, None] # i= 8 i1= 8 i2= 9 copyBuffer: [12, 14, 17, 18, 19, 11, 15, 13, 16] # i= 8 i1= 7 i2= 9 copyBuffer: [12, 14, 17, 18, 19, 11, 13, 15, 16] # i= 8 i1= 5 i2= 9 copyBuffer: [11, 12, 13, 14, 15, 16, 17, 18, 19] # Sorted List [11, 12, 13, 14, 15, 16, 17, 18, 19] \u8fd0\u884c\u7ed3\u679c\u56fe\u793a\u5206\u6790\uff1a 3.5.2.2.\u5f52\u5e76\u6392\u5e8f\u7684\u590d\u6742\u5ea6\u5206\u6790 \u00b6 merge \u51fd\u6570\u7684\u8fd0\u884c\u65f6\u7531\u4e24\u4e2a for \u8bed\u53e5\u6765\u51b3\u5b9a\uff0c\u800c\u8fd9\u4e24\u4e2a\u5faa\u73af\u90fd\u4f1a\u88ab\u8fed\u4ee3 (high \u2013 low + 1) \u6b21\uff0c\u56e0\u6b64\uff0c\u8fd9\u4e2a\u51fd\u6570\u7684\u8fd0\u884c\u65f6\u662f O(high\u2212low) \uff0c\u4e8e\u662f\u6bcf\u4e00\u5c42\u4e0a\u7684\u6240\u6709\u5408\u5e76\u603b\u5171\u9700\u8981 O(n) \u7684\u65f6\u95f4\u3002\u56e0\u4e3a mergeSortHelper \u5728\u6bcf\u4e00\u5c42\u90fd\u5c3d\u53ef\u80fd\u5747\u5300\u5730\u62c6\u5206\u5b50\u5217\u8868\uff0c\u6240\u4ee5\u5c42\u6570\u5e94\u8be5\u662f O(log n) \uff0c\u5728\u6240\u6709\u7684\u60c5\u51b5\u4e0b\u8fd9\u4e2a\u51fd\u6570\u7684\u6700\u5927\u8fd0\u884c\u65f6\u90fd\u662f O(n log n) \u3002 \u5f52\u5e76\u6392\u5e8f\u4f1a\u6709\u4e24\u4e2a\u57fa\u4e8e\u5217\u8868\u5927\u5c0f\u7684\u7a7a\u95f4\u9700\u6c42\u3002\u9996\u5148\uff0c\u5728\u8c03\u7528\u6808\u4e0a\u9700\u8981 O(log n) \u7684\u7a7a\u95f4\u6765\u652f\u6301\u9012\u5f52\u8c03\u7528\uff1b\u5176\u6b21\uff0c\u62f7\u8d1d\u7f13\u51b2\u533a\u4f1a\u7528\u5230 O(n) \u7684\u7a7a\u95f4\u3002 3.5.3.\u7ec3\u4e60\u9898 \u00b6 \u63cf\u8ff0\u5feb\u901f\u6392\u5e8f\u7684\u7b56\u7565\uff0c\u5e76\u8bf4\u660e\u4e3a\u4ec0\u4e48\u5b83\u53ef\u4ee5\u628a\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ece O(n^2) \u964d\u4f4e\u5230 O(n log n) \u3002 \u89e3\u7b54\uff1a\u5feb\u901f\u6392\u5e8f\uff08Quick Sort\uff09\u662f\u4e00\u79cd\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u5b83\u91c7\u7528\u5206\u6cbb\u7b56\u7565\u6765\u5c06\u4e00\u4e2a\u5927\u95ee\u9898\u5206\u89e3\u6210\u82e5\u5e72\u4e2a\u5b50\u95ee\u9898\uff0c\u7136\u540e\u9012\u5f52\u5730\u89e3\u51b3\u8fd9\u4e9b\u5b50\u95ee\u9898\u3002\u4ee5\u4e0b\u662f\u5feb\u901f\u6392\u5e8f\u7684\u7b56\u7565\u548c\u539f\u7406\uff0c\u4ee5\u53ca\u4e3a\u4ec0\u4e48\u5b83\u80fd\u591f\u5c06\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ece O(n^2) \u964d\u4f4e\u5230 O(n log n) \uff1a \u5feb\u901f\u6392\u5e8f\u7684\u7b56\u7565\uff1a \u9009\u62e9\u4e3b\u5143\uff08Pivot\uff09\uff1a\u5728\u5feb\u901f\u6392\u5e8f\u4e2d\uff0c\u9996\u5148\u4ece\u5f85\u6392\u5e8f\u7684\u5143\u7d20\u4e2d\u9009\u62e9\u4e00\u4e2a\u4e3b\u5143\uff08\u901a\u5e38\u662f\u7b2c\u4e00\u4e2a\u6216\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff09\uff0c\u4e5f\u53eb\u57fa\u51c6\u5143\u7d20\u3002 \u5206\u5272\u64cd\u4f5c\uff1a\u5c06\u5143\u7d20\u5206\u4e3a\u4e24\u4e2a\u5b50\u6570\u7ec4\uff0c\u4e00\u4e2a\u5c0f\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\uff0c\u4e00\u4e2a\u5927\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u79f0\u4e3a\u5206\u5272\u3002 \u9012\u5f52\u6392\u5e8f\uff1a\u9012\u5f52\u5730\u5bf9\u4e24\u4e2a\u5b50\u6570\u7ec4\u8fdb\u884c\u6392\u5e8f\u3002\u5373\uff0c\u5bf9\u5c0f\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\u548c\u5927\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\u5206\u522b\u8fdb\u884c\u5feb\u901f\u6392\u5e8f\u3002 \u5408\u5e76\uff1a\u5c06\u5df2\u6392\u5e8f\u7684\u5b50\u6570\u7ec4\u5408\u5e76\u6210\u6700\u7ec8\u7684\u6709\u5e8f\u6570\u7ec4\u3002 \u4e3a\u4ec0\u4e48\u5feb\u901f\u6392\u5e8f\u80fd\u591f\u964d\u4f4e\u65f6\u95f4\u590d\u6742\u5ea6\uff1a \u5feb\u901f\u6392\u5e8f\u4e4b\u6240\u4ee5\u80fd\u591f\u5c06\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ece O(n^2) \u964d\u4f4e\u5230 O(n log n) \uff0c\u4e3b\u8981\u6709\u4ee5\u4e0b\u539f\u56e0\uff1a \u5206\u6cbb\u7b56\u7565\uff1a\u5feb\u901f\u6392\u5e8f\u91c7\u7528\u4e86\u5206\u6cbb\u7b56\u7565\uff0c\u5c06\u4e00\u4e2a\u5927\u95ee\u9898\u5206\u89e3\u6210\u4e24\u4e2a\u6216\u591a\u4e2a\u89c4\u6a21\u8f83\u5c0f\u7684\u5b50\u95ee\u9898\u3002\u8fd9\u79cd\u5206\u6cbb\u7b56\u7565\u80fd\u591f\u51cf\u5c0f\u95ee\u9898\u7684\u89c4\u6a21\uff0c\u4ece\u800c\u964d\u4f4e\u4e86\u89e3\u51b3\u95ee\u9898\u7684\u590d\u6742\u5ea6\u3002 \u597d\u7684\u5e73\u5747\u60c5\u51b5\uff1a\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u5bf9\u5f85\u6392\u5e8f\u7684\u6570\u636e\u8fdb\u884c\u4e86\u826f\u597d\u7684\u5e73\u5747\u5206\u5272\uff0c\u6bcf\u6b21\u5206\u5272\u90fd\u5c06\u95ee\u9898\u89c4\u6a21\u51cf\u534a\u3002\u8fd9\u4f7f\u5f97\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n log n) \u3002 **\u4e0d\u7a33\u5b9a\u6027\uff1a\u5feb\u901f\u6392\u5e8f\u662f\u4e0d\u7a33\u5b9a\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u8fd9\u610f\u5473\u7740\u76f8\u540c\u5143\u7d20\u7684\u76f8\u5bf9\u987a\u5e8f\u5728\u6392\u5e8f\u540e\u53ef\u80fd\u4f1a\u6539\u53d8\u3002\u8fd9\u79cd\u4e0d\u7a33\u5b9a\u6027\u4f7f\u5f97\u5feb\u901f\u6392\u5e8f\u53ef\u4ee5\u66f4\u5feb\u5730\u6392\u5e8f\u76f8\u540c\u5143\u7d20\u7684\u5927\u6570\u636e\u96c6\u3002 \u539f\u5730\u6392\u5e8f\uff1a\u5feb\u901f\u6392\u5e8f\u901a\u5e38\u662f\u539f\u5730\u6392\u5e8f\u7684\uff0c\u5b83\u4e0d\u9700\u8981\u989d\u5916\u7684\u5185\u5b58\u6765\u5b58\u50a8\u4e34\u65f6\u6570\u636e\u3002\u8fd9\u5bf9\u4e8e\u5185\u5b58\u5360\u7528\u6709\u9650\u7684\u60c5\u51b5\u5f88\u6709\u5229\u3002 \u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662f O(n^2) \uff0c\u8fd9\u79cd\u60c5\u51b5\u901a\u5e38\u53d1\u751f\u5728\u4e3b\u5143\u9009\u62e9\u4e0d\u5f53\u6216\u8f93\u5165\u6570\u636e\u5df2\u7ecf\u6709\u5e8f\u7684\u60c5\u51b5\u4e0b\u3002\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u901a\u5e38\u9700\u8981\u9009\u62e9\u4e00\u4e2a\u5408\u9002\u7684\u4e3b\u5143\u9009\u62e9\u7b56\u7565\uff0c\u4ee5\u5c3d\u91cf\u907f\u514d\u6700\u574f\u60c5\u51b5\u7684\u53d1\u751f\u3002 \u4e3a\u4ec0\u4e48\u5feb\u901f\u6392\u5e8f\u5e76\u4e0d\u5728\u6240\u6709\u60c5\u51b5\u4e0b\u90fd\u6709 O(n log n) \u7684\u590d\u6742\u5ea6\uff1f\u5bf9\u5feb\u901f\u6392\u5e8f\u7684\u6700\u574f\u60c5\u51b5\u8fdb\u884c\u63cf\u8ff0\uff0c\u5e76\u7ed9\u51fa\u4e00\u4e2a\u4f1a\u4ea7\u751f\u8fd9\u4e2a\u60c5\u51b5\u7684\u5305\u542b10\u4e2a\u6574\u6570\uff081\uff5e10\uff09\u7684\u5217\u8868\u3002 \u89e3\u7b54\uff1a\u5feb\u901f\u6392\u5e8f\u5e76\u4e0d\u5728\u6240\u6709\u60c5\u51b5\u4e0b\u90fd\u5177\u6709 O(n log n) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\uff0c\u5b83\u7684\u6027\u80fd\u53d6\u51b3\u4e8e\u4e3b\u5143\uff08pivot\uff09\u7684\u9009\u62e9\u548c\u8f93\u5165\u6570\u636e\u7684\u5206\u5e03\u60c5\u51b5\u3002\u6700\u574f\u60c5\u51b5\u53d1\u751f\u5728\u4ee5\u4e0b\u60c5\u51b5\u4e0b\uff1a \u4e3b\u5143\u9009\u62e9\u4e0d\u5f53\uff1a\u5982\u679c\u6bcf\u6b21\u9009\u62e9\u7684\u4e3b\u5143\u90fd\u662f\u8f93\u5165\u6570\u636e\u4e2d\u7684\u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\uff0c\u5feb\u901f\u6392\u5e8f\u5c06\u4f1a\u4ea7\u751f\u6700\u574f\u60c5\u51b5\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5206\u5272\u64cd\u4f5c\u5c06\u5bfc\u81f4\u4e00\u4e2a\u5b50\u6570\u7ec4\u4e3a\u7a7a\uff0c\u53e6\u4e00\u4e2a\u5b50\u6570\u7ec4\u7684\u5927\u5c0f\u4e3a\u539f\u59cb\u6570\u7ec4\u5927\u5c0f\u51cf\u4e00\u3002\u8fd9\u4f7f\u5f97\u6bcf\u6b21\u5206\u5272\u64cd\u4f5c\u53ea\u51cf\u5c11\u4e00\u4e2a\u5143\u7d20\uff0c\u5bfc\u81f4\u9012\u5f52\u6df1\u5ea6\u8fbe\u5230\u6700\u5927\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \u3002 \u8f93\u5165\u6570\u636e\u5df2\u7ecf\u6709\u5e8f\uff1a\u5982\u679c\u8f93\u5165\u6570\u636e\u5df2\u7ecf\u662f\u6709\u5e8f\u7684\uff0c\u4e0d\u7ba1\u662f\u5347\u5e8f\u8fd8\u662f\u964d\u5e8f\uff0c\u5feb\u901f\u6392\u5e8f\u4e5f\u4f1a\u4ea7\u751f\u6700\u574f\u60c5\u51b5\u3002\u56e0\u4e3a\u65e0\u8bba\u5982\u4f55\u9009\u62e9\u4e3b\u5143\uff0c\u5206\u5272\u64cd\u4f5c\u90fd\u5c06\u5bfc\u81f4\u4e00\u4e2a\u5b50\u6570\u7ec4\u4e3a\u7a7a\uff0c\u53e6\u4e00\u4e2a\u5b50\u6570\u7ec4\u7684\u5927\u5c0f\u4e3a\u539f\u59cb\u6570\u7ec4\u5927\u5c0f\u51cf\u4e00\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u5305\u542b10\u4e2a\u6574\u6570\uff081\uff5e10\uff09\u7684\u5217\u8868\uff0c\u6f14\u793a\u4e86\u5bfc\u81f4\u5feb\u901f\u6392\u5e8f\u6700\u574f\u60c5\u51b5\u7684\u8f93\u5165\u6570\u636e\uff1a [ 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 ] \u5728\u8fd9\u4e2a\u793a\u4f8b\u4e2d\uff0c\u6bcf\u6b21\u9009\u62e9\u7684\u4e3b\u5143\u90fd\u662f\u6700\u5927\u7684\u5143\u7d20\uff0810\uff09\uff0c\u5bfc\u81f4\u5206\u5272\u64cd\u4f5c\u4e0d\u65ad\u51cf\u5c11\u6570\u7ec4\u7684\u5927\u5c0f\uff0c\u9012\u5f52\u6df1\u5ea6\u8fbe\u5230\u6700\u5927\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \u3002 \u8981\u907f\u514d\u6700\u574f\u60c5\u51b5\uff0c\u901a\u5e38\u91c7\u7528\u4ee5\u4e0b\u7b56\u7565\uff1a \u9009\u62e9\u5408\u9002\u7684\u4e3b\u5143\uff0c\u4f8b\u5982\u9009\u62e9\u4e2d\u95f4\u5143\u7d20\uff0c\u4ee5\u786e\u4fdd\u5e73\u5747\u5206\u5272\u3002 \u968f\u673a\u9009\u62e9\u4e3b\u5143\uff0c\u4ee5\u51cf\u5c11\u51fa\u73b0\u6700\u574f\u60c5\u51b5\u7684\u6982\u7387\u3002 \u8fd9\u4e9b\u7b56\u7565\u6709\u52a9\u4e8e\u7ef4\u6301\u5feb\u901f\u6392\u5e8f\u7684\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n log n) \u3002 \u5feb\u901f\u6392\u5e8f\u91cc\u7684\u5206\u5272\u64cd\u4f5c\u4f1a\u9009\u62e9\u4e2d\u70b9\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\u3002\u8bf7\u63cf\u8ff0\u53e6\u5916\u4e24\u79cd\u9009\u62e9\u57fa\u51c6\u7684\u7b56\u7565\u3002 \u89e3\u7b54\uff1a\u5feb\u901f\u6392\u5e8f\u4e2d\u7684\u5206\u5272\u64cd\u4f5c\u53ef\u4ee5\u9009\u62e9\u4e2d\u70b9\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\uff0c\u4f46\u8fd8\u6709\u5176\u4ed6\u4e24\u79cd\u5e38\u89c1\u7684\u9009\u62e9\u57fa\u51c6\u7684\u7b56\u7565\uff0c\u5b83\u4eec\u5206\u522b\u662f\uff1a \u968f\u673a\u9009\u62e9\u57fa\u51c6\uff08Random Pivot\uff09\uff1a\u8fd9\u79cd\u7b56\u7565\u662f\u5728\u5f85\u6392\u5e8f\u6570\u7ec4\u4e2d\u968f\u673a\u9009\u62e9\u4e00\u4e2a\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\u3002\u968f\u673a\u9009\u62e9\u57fa\u51c6\u7684\u597d\u5904\u662f\u53ef\u4ee5\u964d\u4f4e\u51fa\u73b0\u6700\u574f\u60c5\u51b5\u7684\u6982\u7387\uff0c\u56e0\u4e3a\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u968f\u673a\u9009\u62e9\u7684\u57fa\u51c6\u4f1a\u6bd4\u56fa\u5b9a\u4f4d\u7f6e\u7684\u57fa\u51c6\u66f4\u5e73\u5747\u5730\u5212\u5206\u6570\u636e\u3002\u8fd9\u53ef\u4ee5\u63d0\u9ad8\u7b97\u6cd5\u7684\u6027\u80fd\u3002 \u4e09\u6570\u53d6\u4e2d\u6cd5\uff08Median-of-Three Pivot\uff09\uff1a\u8fd9\u79cd\u7b56\u7565\u662f\u5728\u5f85\u6392\u5e8f\u6570\u7ec4\u4e2d\u9009\u62e9\u4e09\u4e2a\u5143\u7d20\uff08\u901a\u5e38\u662f\u7b2c\u4e00\u4e2a\u3001\u4e2d\u95f4\u4e00\u4e2a\u548c\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff09\uff0c\u7136\u540e\u4ece\u8fd9\u4e09\u4e2a\u5143\u7d20\u4e2d\u9009\u62e9\u4e2d\u95f4\u503c\u4f5c\u4e3a\u57fa\u51c6\u3002\u8fd9\u4e2a\u7b56\u7565\u7684\u76ee\u7684\u662f\u5728\u5c3d\u91cf\u907f\u514d\u6700\u574f\u60c5\u51b5\u7684\u540c\u65f6\uff0c\u4fdd\u6301\u57fa\u51c6\u7684\u76f8\u5bf9\u4e2d\u95f4\u4f4d\u7f6e\u3002\u8fd9\u53ef\u4ee5\u63d0\u9ad8\u7b97\u6cd5\u7684\u5e73\u5747\u6027\u80fd\u3002 \u8fd9\u4e09\u79cd\u9009\u62e9\u57fa\u51c6\u7684\u7b56\u7565\u5404\u6709\u4f18\u52a3\uff0c\u4f46\u5b83\u4eec\u7684\u5171\u540c\u76ee\u6807\u662f\u964d\u4f4e\u6700\u574f\u60c5\u51b5\u7684\u6982\u7387\uff0c\u4ece\u800c\u63d0\u9ad8\u5feb\u901f\u6392\u5e8f\u7684\u6027\u80fd\u3002\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u9009\u62e9\u54ea\u79cd\u7b56\u7565\u53d6\u51b3\u4e8e\u5177\u4f53\u7684\u60c5\u51b5\u548c\u5b9e\u73b0\u3002 \u5f53\u5feb\u901f\u6392\u5e8f\u91cc\u7684\u5b50\u5217\u8868\u7684\u957f\u5ea6\u5c0f\u4e8e\u67d0\u4e2a\u6570\u5b57\uff08\u598230\uff09\u65f6\uff0c\u6267\u884c\u63d2\u5165\u6392\u5e8f\u6765\u5904\u7406\u8fd9\u4e2a\u5b50\u5217\u8868\u3002\u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u8fd9\u662f\u4e00\u4e2a\u597d\u65b9\u6cd5\u3002 \u89e3\u7b54\uff1a\u5728\u5feb\u901f\u6392\u5e8f\u4e2d\uff0c\u5f53\u5b50\u5217\u8868\u7684\u957f\u5ea6\u53d8\u5f97\u5f88\u5c0f\u65f6\uff08\u901a\u5e38\u5c0f\u4e8e\u67d0\u4e2a\u9884\u5b9a\u7684\u9608\u503c\uff0c\u598230\u6216\u5176\u4ed6\u7ecf\u9a8c\u503c\uff09\uff0c\u6267\u884c\u63d2\u5165\u6392\u5e8f\u6765\u5904\u7406\u8fd9\u4e2a\u5b50\u5217\u8868\u662f\u4e00\u4e2a\u597d\u65b9\u6cd5\uff0c\u4e3b\u8981\u57fa\u4e8e\u4ee5\u4e0b\u8003\u8651\uff1a \u63d2\u5165\u6392\u5e8f\u5bf9\u5c0f\u89c4\u6a21\u6570\u636e\u8868\u73b0\u826f\u597d\uff1a\u63d2\u5165\u6392\u5e8f\u662f\u4e00\u79cd\u7b80\u5355\u4f46\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u7279\u522b\u9002\u7528\u4e8e\u5c0f\u89c4\u6a21\u6570\u636e\u96c6\u3002\u5b83\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \uff0c\u4f46\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u5bf9\u4e8e\u5c0f\u89c4\u6a21\u7684\u6570\u636e\uff0c\u5b83\u7684\u6027\u80fd\u901a\u5e38\u5f88\u597d\u3002 \u51cf\u5c11\u9012\u5f52\u6df1\u5ea6\uff1a\u5728\u5feb\u901f\u6392\u5e8f\u4e2d\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u90fd\u4f1a\u589e\u52a0\u9012\u5f52\u6df1\u5ea6\uff0c\u800c\u9012\u5f52\u6df1\u5ea6\u8fc7\u5927\u53ef\u80fd\u4f1a\u5bfc\u81f4\u6808\u6ea2\u51fa\u6216\u6027\u80fd\u4e0b\u964d\u3002\u5f53\u5b50\u5217\u8868\u957f\u5ea6\u5c0f\u4e8e\u67d0\u4e2a\u9608\u503c\u65f6\uff0c\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u53ef\u4ee5\u907f\u514d\u4e0d\u5fc5\u8981\u7684\u9012\u5f52\u6df1\u5ea6\uff0c\u4ece\u800c\u51cf\u5c11\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u3002 \u9002\u7528\u4e8e\u90e8\u5206\u6709\u5e8f\u7684\u5b50\u5217\u8868\uff1a\u5f53\u5b50\u5217\u8868\u5df2\u7ecf\u90e8\u5206\u6709\u5e8f\u65f6\uff0c\u63d2\u5165\u6392\u5e8f\u7684\u6027\u80fd\u901a\u5e38\u6bd4\u5feb\u901f\u6392\u5e8f\u66f4\u597d\u3002\u56e0\u6b64\uff0c\u5bf9\u4e8e\u53ef\u80fd\u5305\u542b\u5df2\u6392\u5e8f\u90e8\u5206\u7684\u5c0f\u5b50\u5217\u8868\uff0c\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u53ef\u4ee5\u63d0\u9ad8\u7b97\u6cd5\u7684\u6548\u7387\u3002 \u51cf\u5c11\u9012\u5f52\u5f00\u9500\uff1a\u9012\u5f52\u5f00\u9500\u662f\u5feb\u901f\u6392\u5e8f\u7684\u4e00\u4e2a\u4e0d\u53ef\u5ffd\u89c6\u7684\u56e0\u7d20\uff0c\u7279\u522b\u662f\u5728\u5904\u7406\u5c0f\u89c4\u6a21\u5b50\u5217\u8868\u65f6\u3002\u901a\u8fc7\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u6765\u5904\u7406\u8fd9\u4e9b\u5c0f\u89c4\u6a21\u5b50\u5217\u8868\uff0c\u53ef\u4ee5\u51cf\u5c11\u9012\u5f52\u5f00\u9500\uff0c\u63d0\u9ad8\u7b97\u6cd5\u7684\u6574\u4f53\u6027\u80fd\u3002 \u5c06\u63d2\u5165\u6392\u5e8f\u4e0e\u5feb\u901f\u6392\u5e8f\u7ed3\u5408\u4f7f\u7528\u662f\u4e00\u79cd\u5e38\u89c1\u7684\u4f18\u5316\u7b56\u7565\uff0c\u5b83\u53ef\u4ee5\u5728\u5904\u7406\u5c0f\u89c4\u6a21\u5b50\u5217\u8868\u65f6\u63d0\u9ad8\u7b97\u6cd5\u7684\u6548\u7387\uff0c\u540c\u65f6\u4fdd\u6301\u5feb\u901f\u6392\u5e8f\u7684\u6574\u4f53\u6027\u80fd\u3002\u8fd9\u79cd\u65b9\u6cd5\u88ab\u79f0\u4e3a\u201c\u5feb\u901f\u6392\u5e8f\u7684\u6539\u8fdb\u201d\u6216\u201c\u5feb\u901f\u6392\u5e8f\u7684\u6df7\u5408\u6392\u5e8f\u201d\u7b56\u7565\uff0c\u7528\u4e8e\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\u63d0\u9ad8\u7b97\u6cd5\u7684\u6548\u7387\u3002 \u4e3a\u4ec0\u4e48\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4e5f\u662f\u4e00\u4e2a O(n log n) \u7b97\u6cd5\uff1f \u89e3\u7b54\uff1a\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4ecd\u7136\u5177\u6709 O(n log n) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\uff0c\u8fd9\u662f\u56e0\u4e3a\u5f52\u5e76\u6392\u5e8f\u7684\u7b97\u6cd5\u8bbe\u8ba1\u4f7f\u5176\u80fd\u591f\u7a33\u5b9a\u5730\u4fdd\u6301\u8fd9\u79cd\u6027\u80fd\uff0c\u4e0d\u53d7\u8f93\u5165\u6570\u636e\u5206\u5e03\u7684\u5f71\u54cd\u3002 \u4ee5\u4e0b\u662f\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4ecd\u7136\u5177\u6709 O(n log n) \u65f6\u95f4\u590d\u6742\u5ea6\u7684\u539f\u56e0\uff1a \u5206\u800c\u6cbb\u4e4b\u7b56\u7565\uff1a\u5f52\u5e76\u6392\u5e8f\u91c7\u7528\u4e86\u5206\u800c\u6cbb\u4e4b\u7684\u7b56\u7565\uff0c\u5c06\u95ee\u9898\u5206\u89e3\u4e3a\u8f83\u5c0f\u7684\u5b50\u95ee\u9898\uff0c\u7136\u540e\u5408\u5e76\u8fd9\u4e9b\u5b50\u95ee\u9898\u7684\u89e3\u3002\u8fd9\u4e2a\u7b56\u7565\u786e\u4fdd\u4e86\u7b97\u6cd5\u7684\u9012\u5f52\u6df1\u5ea6\u5728 log n \u7ea7\u522b\uff0c\u56e0\u4e3a\u6bcf\u6b21\u9012\u5f52\u90fd\u5c06\u6570\u636e\u5212\u5206\u6210\u4e24\u534a\uff0c\u76f4\u5230\u6700\u5c0f\u5b50\u95ee\u9898\u7684\u5927\u5c0f\u4e3a1\u3002 \u5408\u5e76\u64cd\u4f5c\u7684\u7ebf\u6027\u65f6\u95f4\uff1a\u5f52\u5e76\u6392\u5e8f\u7684\u5173\u952e\u64cd\u4f5c\u662f\u5408\u5e76\u5df2\u6392\u5e8f\u7684\u5b50\u6570\u7ec4\u3002\u5408\u5e76\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f\u7ebf\u6027\u7684\uff0c\u4e0e\u8f93\u5165\u6570\u636e\u7684\u89c4\u6a21 n \u6210\u6b63\u6bd4\u3002\u56e0\u6b64\uff0c\u5373\u4f7f\u5728\u5408\u5e76\u9636\u6bb5\uff0c\u7b97\u6cd5\u7684\u603b\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u53d7\u9650\u4e8e O(n log n) \u3002 \u7a33\u5b9a\u6027\uff1a\u5f52\u5e76\u6392\u5e8f\u662f\u4e00\u79cd\u7a33\u5b9a\u6392\u5e8f\u7b97\u6cd5\uff0c\u610f\u5473\u7740\u5b83\u5728\u6392\u5e8f\u76f8\u7b49\u5143\u7d20\u65f6\u4f1a\u4fdd\u6301\u5b83\u4eec\u7684\u76f8\u5bf9\u987a\u5e8f\u3002\u8fd9\u4e00\u6027\u8d28\u4f7f\u5f97\u7b97\u6cd5\u5728\u5904\u7406\u76f8\u7b49\u5143\u7d20\u6216\u8005\u5177\u6709\u7279\u5b9a\u6570\u636e\u5206\u5e03\u7684\u60c5\u51b5\u4e0b\u4ecd\u7136\u4fdd\u6301 O(n log n) \u7684\u6027\u80fd\uff0c\u800c\u4e0d\u4f1a\u51fa\u73b0\u6700\u574f\u60c5\u51b5\u3002 \u65e0\u8bba\u8f93\u5165\u6570\u636e\u5982\u4f55\u5206\u5e03\uff0c\u5f52\u5e76\u6392\u5e8f\u7684\u5206\u5272\u548c\u5408\u5e76\u64cd\u4f5c\u90fd\u662f\u786e\u5b9a\u6027\u7684\uff1a\u5f52\u5e76\u6392\u5e8f\u7684\u6bcf\u4e00\u6b65\u90fd\u662f\u786e\u5b9a\u6027\u7684\uff0c\u4e0d\u53d7\u8f93\u5165\u6570\u636e\u5206\u5e03\u7684\u5f71\u54cd\u3002\u4e0d\u50cf\u5feb\u901f\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u53ef\u80fd\u51fa\u73b0\u5206\u5272\u6781\u4e0d\u5e73\u8861\u7684\u60c5\u51b5\uff0c\u5bfc\u81f4\u6027\u80fd\u4e0b\u964d\u3002 \u56e0\u6b64\uff0c\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4ecd\u7136\u80fd\u591f\u4fdd\u6301 O(n log n) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\uff0c\u4f7f\u5176\u6210\u4e3a\u4e00\u79cd\u53ef\u9760\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u7279\u522b\u9002\u7528\u4e8e\u5bf9\u7a33\u5b9a\u6027\u548c\u6027\u80fd\u6709\u8981\u6c42\u7684\u60c5\u51b5\u3002 3.6.\u6307\u6570\u590d\u6742\u5ea6\u7684\u7b97\u6cd5 \u00b6 \u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7b97\u6cd5 \u00b6 \u4e0b\u9762\u662f\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7b97\u6cd5\u7684\u4f8b\u5b50\u3002 def fib ( n , depth = 0 ): \"\"\"\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u6570\u5217\"\"\" if n <= 1 : return 1 else : print ( f 'Depth: { depth } ,fib( { n } ) calls fib( { n - 1 } ) and fib( { n - 2 } )' ) return fib ( n - 1 , depth + 1 ) + fib ( n - 2 , depth + 1 ) def main (): fib ( 6 ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Depth:0,fib(6) calls fib(5) and fib(4) # Depth:1,fib(5) calls fib(4) and fib(3) # Depth:2,fib(4) calls fib(3) and fib(2) # Depth:3,fib(3) calls fib(2) and fib(1) # Depth:4,fib(2) calls fib(1) and fib(0) # Depth:3,fib(2) calls fib(1) and fib(0) # Depth:2,fib(3) calls fib(2) and fib(1) # Depth:3,fib(2) calls fib(1) and fib(0) # Depth:1,fib(4) calls fib(3) and fib(2) # Depth:2,fib(3) calls fib(2) and fib(1) # Depth:3,fib(2) calls fib(1) and fib(0) # Depth:2,fib(2) calls fib(1) and fib(0) \u4e0a\u4f8b\u53ef\u4ee5\u770b\u51fa\uff0c\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7b97\u6cd5\u7684\u8c03\u7528\u6b21\u6570\u6bd4\u95ee\u9898\u89c4\u6a21\u7684\u5e73\u65b9\u6570\u589e\u957f\u7684\u8fd8\u8981\u5feb\u5f88\u591a\u3002\u4f8b\u5982\uff0c fib(4) \u53ea\u9700\u89814\u6b21\u9012\u5f52\u8c03\u7528\uff0c\u770b\u8d77\u6765\u5b83\u597d\u50cf\u662f\u7ebf\u6027\u589e\u957f\u7684\uff0c\u4f46\u5728\u603b\u5171\u768414\u6b21\u9012\u5f52\u8c03\u7528\u91cc\uff0c fib(6) \u9700\u8981\u8c03\u75282\u6b21 fib(4) \u3002\u968f\u7740\u95ee\u9898\u89c4\u6a21\u7684\u6269\u5927\uff0c\u5de5\u4f5c\u91cf\u4f1a\u663e\u8457\u589e\u52a0\uff0c\u8fd9\u662f\u56e0\u4e3a\u5728\u8c03\u7528\u6811\uff08call tree\uff09\u91cc\u53ef\u80fd\u6709\u5f88\u591a\u91cd\u590d\u7684\u76f8\u540c\u5b50\u6811\u3002 \u5982\u679c\u8fd9\u68f5\u8c03\u7528\u6811\u662f\u5b8c\u5168\u5e73\u8861\u7684\uff0c\u5e76\u4e14\u5b8c\u5168\u586b\u5145\u4e86\u6700\u4e0b\u9762\u7684\u4e24\u5c42\u8c03\u7528\uff0c\u90a3\u4e48\u5f53\u53c2\u6570\u4e3a6\u65f6\uff0c\u4f1a\u67092 + 4 + 8 + 16 = 30\u6b21\u9012\u5f52\u8c03\u7528\u3002\u6bcf\u4e00\u5c42\u91cc\u7684\u6ee1\u8c03\u7528\u6570\u91cf\u90fd\u662f\u5b83\u4e0a\u4e00\u5c42\u76842\u500d\u3002\u56e0\u6b64\uff0c\u5728\u5b8c\u5168\u5e73\u8861\u7684\u8c03\u7528\u6811\u91cc\uff0c\u9012\u5f52\u8c03\u7528\u7684\u603b\u6570\u91cf\u901a\u5e38\u662f 2^(n+1)-2 \uff0c\u5176\u4e2d n \u662f\u8c03\u7528\u6811\u9876\u90e8\uff08\u6839\uff09\u7684\u53c2\u6570\u3002\u8fd9\u662f\u4e00\u4e2a\u6307\u6570\u7ea7\u7684\u589e\u957f\uff0c\u4e5f\u5c31\u662f O(k^n) \u7b97\u6cd5\u3002 \u5c3d\u7ba1\u5728\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u8c03\u7528\u6811\u7684\u5e95\u90e8\u4e24\u5c42\u5e76\u6ca1\u6709\u88ab\u5b8c\u5168\u586b\u5145\u6ee1\uff0c\u4f46\u5b83\u7684\u8c03\u7528\u6811\u5f62\u72b6\u548c\u5b8c\u5168\u5e73\u8861\u7684\u6811\u5df2\u7ecf\u8db3\u591f\u76f8\u8fd1\u4e86\uff0c\u56e0\u6b64\uff0c\u53ef\u4ee5\u628a\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u5f52\u4e3a\u6307\u6570\u7b97\u6cd5\u3002\u7ecf\u8fc7\u8ba1\u7b97\uff0c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u7684\u5e38\u6570 k \u5927\u7ea6\u662f1.63\u3002 \u6307\u6570\u7b97\u6cd5\u901a\u5e38\u53ea\u9002\u5408\u7528\u4e8e\u975e\u5e38\u5c0f\u7684\u95ee\u9898\u89c4\u6a21\u3002 \u5c06\u6590\u6ce2\u90a3\u5951\u8f6c\u6362\u4e3a\u7ebf\u6027\u7b97\u6cd5 \u00b6 \u4e0b\u9762\u7684\u4ee3\u7801\u7528\u7ebf\u6027\u7b97\u6cd5\u6539\u5199\u4e86\u4e0a\u9762\u7684\u9012\u5f52\u7b97\u6cd5\u3002\u5b83\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\u3002 def fibonacci_linear ( n ): if n <= 1 : return 1 prev , current = 0 , 1 for _ in range ( 2 , n + 1 ): next_value = prev + current prev , current = current , next_value return current def main (): n = 6 result = fibonacci_linear ( n ) print ( f \"Fibonacci( { n } ) = { result } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Fibonacci(6) = 8 3.7.\u6848\u4f8b\u7814\u7a76:\u7b97\u6cd5\u5206\u6790\u5668 \u00b6 \u76ee\u6807\uff1a\u7f16\u5199\u4e00\u4e2a\u53ef\u4ee5\u7528\u6765\u5206\u6790\u4e0d\u540c\u6392\u5e8f\u7b97\u6cd5\u7684\u7a0b\u5e8f\u3002 \u9700\u6c42\uff1a \u5206\u6790\u5668\u53ef\u4ee5\u8fd0\u884c\u6392\u5e8f\u7b97\u6cd5\u4ee5\u5bf9\u6570\u5b57\u5217\u8868\u8fdb\u884c\u6392\u5e8f\uff1b \u5206\u6790\u5668\u53ef\u4ee5\u8ffd\u8e2a\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u3001\u6bd4\u8f83\u6b21\u6570\u4ee5\u53ca\u6267\u884c\u4ea4\u6362\u7684\u6b21\u6570\uff1b \u5f53\u7b97\u6cd5\u4ea4\u6362\u4e24\u4e2a\u503c\u7684\u65f6\u5019\uff0c\u5206\u6790\u5668\u53ef\u4ee5\u6253\u5370\u51fa\u5217\u8868\u7684\u53d8\u5316\u8f68\u8ff9\uff1b \u5141\u8bb8\u7ed9\u5206\u6790\u5668\u63d0\u4f9b\u81ea\u5b9a\u4e49\u7684\u6570\u5b57\u5217\u8868\uff0c\u6216\u8005\u751f\u6210\u4e00\u4e2a\u5927\u5c0f\u7ed9\u5b9a\u7684\u968f\u673a\u6570\u5b57\u5217\u8868\uff1b\u5141\u8bb8\u5217\u8868\u53ea\u5305\u542b\u4e00\u4e2a\u6570\u5b57\uff0c\u6216\u8005\u5305\u542b\u91cd\u590d\u6570\u503c\uff1b \u5728\u8fd0\u884c\u7b97\u6cd5\u4e4b\u524d\uff0c\u5141\u8bb8\u7528\u6237\u9009\u62e9\u4e0a\u8ff0\u8fd9\u4e9b\u529f\u80fd\uff1b \u5206\u6790\u5668\u7684\u9ed8\u8ba4\u884c\u4e3a\u662f\u5728\u4e00\u4e2a\u5305\u542b10\u4e2a\u4e0d\u91cd\u590d\u6570\u5b57\u7684\u968f\u673a\u5217\u8868\u4e0a\u8fd0\u884c\u7b97\u6cd5\uff0c\u5e76\u8bb0\u5f55\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u3001\u6bd4\u8f83\u6b21\u6570\u4ee5\u53ca\u4ea4\u6362\u6b21\u6570\uff1b \u5b9e\u73b0\uff1a \u5206\u6790\u5668\u662f Profiler \u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\u3002\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u8fd0\u884c\u5206\u6790\u5668\u91cc\u7684 test \u65b9\u6cd5\u6765\u5206\u6790\u6392\u5e8f\u51fd\u6570\uff0c\u8fd9\u4e2a\u6392\u5e8f\u51fd\u6570\u4f1a\u4f5c\u4e3a\u65b9\u6cd5\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\uff0c\u4e0a\u9762\u9700\u6c42\u4e2d\u63d0\u5230\u7684\u90a3\u4e9b\u9009\u9879\u4e5f\u4f1a\u4f5c\u4e3a\u53c2\u6570\u540c\u65f6\u4f20\u9012\u7ed9\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u4e24\u4e2a\u6a21\u5757\uff1a profiler \uff1a\u8fd9\u4e2a\u6a21\u5757\u4f1a\u5b9a\u4e49 Profiler \u7c7b\u3002 algorithms \uff1a\u8fd9\u4e2a\u6a21\u5757\u5b9a\u4e49\u9488\u5bf9\u5206\u6790\u5668\u4fee\u6539\u8fc7\u7684\u6392\u5e8f\u51fd\u6570\u3002 import time import random class Profiler ( object ): \"\"\" \u5b9a\u4e49\u4e00\u4e2aProfiler\u7c7b, \u7528\u6765\u5206\u6790\u6392\u5e8f\u7b97\u6cd5\u3002 Profiler\u5bf9\u8c61\u8ddf\u8e2a\u4e00\u4e2a\u5217\u8868\u7684\u6bd4\u8f83\u6b21\u6570\u3001\u4ea4\u6362\u6b21\u6570\u3001\u548c\u8fd0\u884c\u65f6\u95f4\u3002 Profiler\u5bf9\u8c61\u4e5f\u80fd\u8f93\u51fa\u4e0a\u8ff0\u8ffd\u8e2a\u4fe1\u606f, \u5e76\u521b\u5efa\u4e00\u4e2a\u542b\u6709\u91cd\u590d\u6216\u4e0d\u91cd\u590d\u6570\u5b57\u7684\u5217\u8868\u3002 \u793a\u4f8b\uff1a from profiler import Profiler from algorithms import selectionSort p = Profiler() p.test(selectionSort, size = 15, comp = True, exch = True, trace = True) \"\"\" def test ( self , function , lyst = None , size = 10 , unique = True , comp = True , exch = True , trace = False ): \"\"\" function: \u914d\u7f6e\u7684\u7b97\u6cd5 target: \u914d\u7f6e\u7684\u641c\u7d22\u76ee\u6807 lyst: \u5141\u8bb8\u8c03\u7528\u8005\u4f7f\u7528\u7684\u5217\u8868 size: \u5217\u8868\u7684\u5927\u5c0f, \u9ed8\u8ba4\u503c\u662f10 unique: \u5982\u679c\u662fTrue, \u5219\u5217\u8868\u5305\u542b\u4e0d\u91cd\u590d\u7684\u6574\u6570 comp: \u5982\u679c\u662fTrue, \u5219\u7edf\u8ba1\u6bd4\u8f83\u6b21\u6570 exch: \u5982\u679c\u662fTrue, \u5219\u7edf\u8ba1\u4ea4\u6362\u6b21\u6570 trace: \u5982\u679c\u662fTrue, \u5219\u5728\u6bcf\u6b21\u4ea4\u6362\u540e\u90fd\u8f93\u51fa\u5217\u8868\u5185\u5bb9 \u6b64\u51fd\u6570\u4f9d\u636e\u7ed9\u5b9a\u7684\u4e0a\u8ff0\u5c5e\u6027, \u6253\u5370\u8f93\u51fa\u76f8\u5e94\u7684\u7ed3\u679c \"\"\" self . comp = comp self . exch = exch self . trace = trace if lyst != None : self . lyst = lyst elif unique : self . lyst = list ( range ( 1 , size + 1 )) random . shuffle ( self . lyst ) else : self . lyst = [] for count in range ( size ): self . lyst . append ( random . randint ( 1 , size )) self . exchCount = 0 self . cmpCount = 0 self . startClock () function ( self . lyst , self ) self . stopClock () print ( self ) def exchange ( self ): \"\"\"\u7edf\u8ba1\u4ea4\u6362\u6b21\u6570\"\"\" if self . exch : self . exchCount += 1 if self . trace : print ( self . lyst ) def comparison ( self ): \"\"\"\u7edf\u8ba1\u4ea4\u6362\u6b21\u6570\"\"\" if self . comp : self . cmpCount += 1 def startClock ( self ): \"\"\"\u8bb0\u5f55\u5f00\u59cb\u65f6\u95f4\"\"\" self . start = time . time () def stopClock ( self ): \"\"\"\u505c\u6b62\u8ba1\u65f6\u5e76\u4ee5\u79d2\u4e3a\u5355\u4f4d\u8ba1\u7b97\u6d88\u8017\u65f6\u95f4\"\"\" self . elapsedTime = round ( time . time () - self . start , 3 ) def __str__ ( self ): \"\"\"\u4ee5\u5b57\u7b26\u4e32\u65b9\u5f0f\u8fd4\u56de\u7ed3\u679c\"\"\" result = \"Problem size: \" result += str ( len ( self . lyst )) + \" \\n \" result += \"Elapsed time: \" result += str ( self . elapsedTime ) + \" \\n \" if self . comp : result += \"Comparisons: \" result += str ( self . cmpCount ) + \" \\n \" if self . exch : result += \"Exchanges: \" result += str ( self . exchCount ) + \" \\n \" return result def selectionSort ( lyst , profiler ): i = 0 while i < len ( lyst ) - 1 : minIndex = i j = i + 1 while j < len ( lyst ): profiler . comparison () # Count if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : swap ( lyst , minIndex , i , profiler ) i += 1 def swap ( lyst , i , j , profiler ): \"\"\"\u4ea4\u6362\u5904\u4e8e\u4f4d\u7f6ei\u548cj\u7684\u5143\u7d20\"\"\" profiler . exchange () # Count temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def main (): p = Profiler () # \u9ed8\u8ba4\u884c\u4e3a print ( \"The result of p.test(selectionSort)\" ) p . test ( selectionSort ) print ( \"The result of p.test(selectionSort, size=5, trace=True)\" ) p . test ( selectionSort , size = 5 , trace = True ) print ( \"The result of p.test(selectionSort, size=100)\" ) p . test ( selectionSort , size = 100 ) print ( \"The result of p.test(selectionSort, size=1000)\" ) p . test ( selectionSort , size = 1000 ) print ( \"The result of p.test(selectionSort, size=10000, exch=False, comp=False)\" ) p . test ( selectionSort , size = 10000 , exch = False , comp = False ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # The result of p.test(selectionSort) # Problem size: 20 # Elapsed time: 0.0 # Comparisons: 190 # Exchanges: 12 # The result of p.test(selectionSort, size=5, trace=True) # [5, 1, 4, 3, 2, 1, 1, 2, 4, 4] # [1, 5, 4, 3, 2, 1, 1, 2, 4, 4] # [1, 1, 4, 3, 2, 5, 1, 2, 4, 4] # [1, 1, 1, 3, 2, 5, 4, 2, 4, 4] # [1, 1, 1, 2, 3, 5, 4, 2, 4, 4] # [1, 1, 1, 2, 2, 5, 4, 3, 4, 4] # [1, 1, 1, 2, 2, 3, 4, 5, 4, 4] # [1, 1, 1, 2, 2, 3, 4, 4, 5, 4] # Problem size: 10 # Elapsed time: 0.0 # Comparisons: 45 # Exchanges: 8 # The result of p.test(selectionSort, size=100) # Problem size: 200 # Elapsed time: 0.003 # Comparisons: 19900 # Exchanges: 195 # The result of p.test(selectionSort, size=1000) # Problem size: 2000 # Elapsed time: 0.36 # Comparisons: 1999000 # Exchanges: 1992 # The result of p.test(selectionSort, size=10000, exch=False, comp=False) # Problem size: 20000 # Elapsed time: 26.535 3.8.\u5c0f\u7ed3 \u00b6 \u6839\u636e\u6240\u9700\u8981\u7684\u65f6\u95f4\u548c\u5185\u5b58\u8d44\u6e90\uff0c\u6211\u4eec\u53ef\u4ee5\u5bf9\u89e3\u51b3\u540c\u4e00\u4e2a\u95ee\u9898\u7684\u4e0d\u540c\u7b97\u6cd5\u8fdb\u884c\u6392\u540d\u3002\u4e0e\u9700\u8981\u66f4\u591a\u8d44\u6e90\u7684\u7b97\u6cd5\u76f8\u6bd4\uff0c\u6211\u4eec\u901a\u5e38\u8ba4\u4e3a\u8017\u8d39\u66f4\u5c11\u8fd0\u884c\u65f6\u548c\u5360\u7528\u66f4\u5c11\u5185\u5b58\u7684\u7b97\u6cd5\u66f4\u597d\u3002\u4f46\u662f\uff0c\u8fd9\u4e24\u79cd\u8d44\u6e90\u4e5f\u901a\u5e38\u9700\u8981\u8fdb\u884c\u6743\u8861\u53d6\u820d\uff1a\u6709\u65f6\u4ee5\u66f4\u591a\u5185\u5b58\u4e3a\u4ee3\u4ef7\u6765\u6539\u5584\u8fd0\u884c\u65f6\uff1b\u6709\u65f6\u4ee5\u8f83\u6162\u7684\u8fd0\u884c\u65f6\u4f5c\u4e3a\u4ee3\u4ef7\u6765\u63d0\u9ad8\u5185\u5b58\u7684\u4f7f\u7528\u7387\u3002 \u53ef\u4ee5\u6839\u636e\u8ba1\u7b97\u673a\u7684\u65f6\u949f\u6309\u7167\u8fc7\u5f80\u7ecf\u9a8c\u6d4b\u7b97\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u3002\u4f46\u662f\uff0c\u8fd9\u4e2a\u65f6\u95f4\u4f1a\u968f\u7740\u786c\u4ef6\u548c\u6240\u7528\u7f16\u7a0b\u8bed\u8a00\u7684\u4e0d\u540c\u800c\u53d8\u5316\u3002 \u7edf\u8ba1\u6307\u4ee4\u7684\u6570\u91cf\u63d0\u4f9b\u4e86\u53e6\u4e00\u79cd\u5bf9\u7b97\u6cd5\u6240\u9700\u5de5\u4f5c\u91cf\u8fdb\u884c\u7ecf\u9a8c\u6027\u5ea6\u91cf\u7684\u65b9\u5f0f\u3002\u6307\u4ee4\u7684\u8ba1\u6570\u53ef\u4ee5\u663e\u793a\u51fa\u7b97\u6cd5\u5de5\u4f5c\u91cf\u7684\u589e\u957f\u7387\u7684\u53d8\u5316\uff0c\u800c\u4e14\u8fd9\u4e2a\u6570\u636e\u548c\u786c\u4ef6\u4ee5\u53ca\u8f6f\u4ef6\u5e73\u53f0\u90fd\u6ca1\u6709\u5173\u7cfb\u3002 \u7b97\u6cd5\u5de5\u4f5c\u91cf\u7684\u589e\u957f\u7387\u53ef\u4ee5\u7528\u57fa\u4e8e\u95ee\u9898\u89c4\u6a21\u7684\u51fd\u6570\u6765\u8868\u793a\u3002\u590d\u6742\u5ea6\u5206\u6790\u67e5\u770b\u7b97\u6cd5\u91cc\u7684\u4ee3\u7801\u4ee5\u5f97\u5230\u8fd9\u4e9b\u6570\u5b66\u8868\u8fbe\u5f0f\uff0c\u4ece\u800c\u8ba9\u7a0b\u5e8f\u5458\u9884\u6d4b\u5728\u4efb\u4f55\u8ba1\u7b97\u673a\u4e0a\u6267\u884c\u8fd9\u4e2a\u7b97\u6cd5\u7684\u6548\u679c\u3002 \u5927O\u8868\u793a\u6cd5\u662f\u7528\u6765\u8868\u793a\u7b97\u6cd5\u8fd0\u884c\u65f6\u884c\u4e3a\u7684\u5e38\u7528\u65b9\u6cd5\u3002\u5b83\u7528 O(f(n)) \u7684\u5f62\u5f0f\u6765\u8868\u793a\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u6240\u9700\u8981\u7684\u5de5\u4f5c\u91cf\uff0c\u5176\u4e2d n \u662f\u7b97\u6cd5\u95ee\u9898\u7684\u89c4\u6a21\u3001 f(n) \u662f\u6570\u5b66\u51fd\u6570\u3002 \u8fd0\u884c\u65f6\u884c\u4e3a\u7684\u5e38\u89c1\u8868\u8fbe\u5f0f\u6709 O(log(n, 2)) \uff08\u5bf9\u6570\uff09\u3001 O(n) \uff08\u7ebf\u6027\uff09\u3001 O(n^2) \uff08\u5e73\u65b9\uff09\u4ee5\u53ca O(k^n) \uff08\u6307\u6570\uff09\u3002 \u7b97\u6cd5\u5728\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u53ef\u4ee5\u662f\u4e0d\u540c\u7684\u3002\u6bd4\u5982\uff0c\u5192\u6ce1\u6392\u5e8f\u548c\u63d2\u5165\u6392\u5e8f\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u90fd\u662f\u7ebf\u6027\u590d\u6742\u5ea6\uff0c\u4f46\u662f\u5b83\u4eec\u5728\u5e73\u5747\u60c5\u51b5\u548c\u6700\u574f\u60c5\u51b5\u4e0b\u662f\u5e73\u65b9\u9636\u590d\u6742\u5ea6\u3002 \u901a\u5e38\u6765\u8bf4\uff0c\u8981\u63d0\u9ad8\u7b97\u6cd5\u7684\u6027\u80fd\u6700\u597d\u662f\u5c1d\u8bd5\u964d\u4f4e\u5b83\u7684\u8fd0\u884c\u65f6\u590d\u6742\u5ea6\u7684\u9636\u6570\uff0c\u800c\u4e0d\u662f\u5bf9\u4ee3\u7801\u8fdb\u884c\u5fae\u8c03\u3002 \u4e8c\u5206\u641c\u7d22\u4f1a\u6bd4\u987a\u5e8f\u641c\u7d22\u8981\u5feb\u5f97\u591a\u3002\u4f46\u662f\uff0c\u5728\u7528\u4e8c\u5206\u641c\u7d22\u8fdb\u884c\u641c\u7d22\u65f6\uff0c\u6570\u636e\u5fc5\u987b\u662f\u6709\u5e8f\u7684\u3002 nlogn \u6392\u5e8f\u7b97\u6cd5\u901a\u8fc7\u9012\u5f52\u3001\u5206\u6cbb\u6cd5\u7b56\u7565\u6765\u7a81\u7834 n^2 \u7684\u6027\u80fd\u969c\u788d\u3002\u5feb\u901f\u6392\u5e8f\u4f1a\u5728\u57fa\u51c6\u5143\u7d20\u5de6\u53f3\u5bf9\u5176\u4ed6\u5143\u7d20\u91cd\u65b0\u6392\u5217\uff0c\u7136\u540e\u5bf9\u57fa\u51c6\u4e24\u4fa7\u7684\u5b50\u5217\u8868\u9012\u5f52\u5730\u6392\u5e8f\u3002\u5f52\u5e76\u6392\u5e8f\u5219\u4f1a\u628a\u4e00\u4e2a\u5217\u8868\u8fdb\u884c\u62c6\u5206\uff0c\u9012\u5f52\u5730\u5bf9\u6bcf\u4e2a\u90e8\u5206\u8fdb\u884c\u6392\u5e8f\uff0c\u7136\u540e\u5408\u5e76\u51fa\u6700\u7ec8\u7ed3\u679c\u3002 \u6307\u6570\u590d\u6742\u5ea6\u7684\u7b97\u6cd5\u901a\u5e38\u53ea\u5728\u7406\u8bba\u4e0a\u88ab\u5173\u6ce8\uff0c\u5728\u5904\u7406\u5927\u578b\u95ee\u9898\u7684\u65f6\u5019\uff0c\u5b83\u4eec\u662f\u6ca1\u6709\u4f7f\u7528\u4ef7\u503c\u7684\u3002 3.9.\u590d\u4e60\u9898 \u00b6 \u5728\u4e0d\u540c\u95ee\u9898\u89c4\u6a21\u7684\u60c5\u51b5\u4e0b\u8bb0\u5f55\u7b97\u6cd5\u8fd0\u884c\u65f6\uff1a \u53ef\u4ee5\u8ba9\u4f60\u5927\u81f4\u4e86\u89e3\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u884c\u4e3a \u53ef\u4ee5\u8ba9\u4f60\u4e86\u89e3\u7b97\u6cd5\u5728\u7279\u5b9a\u786c\u4ef6\u5e73\u53f0\u548c\u7279\u5b9a\u8f6f\u4ef6\u5e73\u53f0\u4e0a\u7684\u8fd0\u884c\u65f6\u884c\u4e3a \u7edf\u8ba1\u6307\u4ee4\u7684\u6570\u91cf\u4f1a\uff1a \u5728\u4e0d\u540c\u7684\u786c\u4ef6\u548c\u8f6f\u4ef6\u5e73\u53f0\u4e0a\u5f97\u5230\u76f8\u540c\u7684\u6570\u636e \u53ef\u4ee5\u8bc1\u660e\u5728\u95ee\u9898\u89c4\u6a21\u5f88\u5927\u7684\u60c5\u51b5\u4e0b\uff0c\u6307\u6570\u7b97\u6cd5\u662f\u6ca1\u6cd5\u4f7f\u7528\u7684 \u8868\u8fbe\u5f0f O(n) \u3001 O(n^2) \u548c O(k^n) \u5206\u522b\u4ee3\u8868\u7684\u590d\u6742\u5ea6\u662f\uff1a \u6307\u6570\u3001\u7ebf\u6027\u548c\u5e73\u65b9 \u7ebf\u6027\u3001\u5e73\u65b9\u548c\u6307\u6570 \u5bf9\u6570\u3001\u7ebf\u6027\u548c\u5e73\u65b9 \u4e8c\u5206\u641c\u7d22\u9700\u8981\u5047\u5b9a\u6570\u636e\uff1a \u6ca1\u6709\u4efb\u4f55\u7279\u522b\u7684\u987a\u5e8f\u5173\u7cfb \u6709\u5e8f\u7684 \u9009\u62e9\u6392\u5e8f\u6700\u591a\u53ef\u4ee5\u6709\uff1a n^2 \u6b21\u6570\u636e\u5143\u7d20\u7684\u4ea4\u6362 n \u6b21\u6570\u636e\u5143\u7d20\u7684\u4ea4\u6362 \u63d2\u5165\u6392\u5e8f\u548c\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u662f\uff1a \u7ebf\u6027\u7684 \u5e73\u65b9\u7684 \u6307\u6570\u7684 \u6700\u597d\u60c5\u51b5\u3001\u5e73\u5747\u60c5\u51b5\u4ee5\u53ca\u6700\u574f\u60c5\u51b5\u4e0b\u590d\u6742\u5ea6\u90fd\u76f8\u540c\u7684\u7b97\u6cd5\u662f\uff1a \u987a\u5e8f\u641c\u7d22 \u9009\u62e9\u6392\u5e8f \u5feb\u901f\u6392\u5e8f \u4e00\u822c\u6765\u8bf4\uff0c\u4e0b\u9762\u54ea\u4e2a\u9009\u62e9\u66f4\u597d\uff1a \u8c03\u6574\u7b97\u6cd5\u4ece\u800c\u8282\u7701\u82e5\u5e72\u79d2\u7684\u8fd0\u884c\u65f6 \u9009\u62e9\u8ba1\u7b97\u590d\u6742\u5ea6\u66f4\u4f4e\u7684\u7b97\u6cd5 \u5bf9\u4e8e\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\uff1a \u95ee\u9898\u89c4\u6a21\u4e3a n \u7684\u65f6\u5019\uff0c\u6709 n^2 \u6b21\u9012\u5f52\u8c03\u7528 \u95ee\u9898\u89c4\u6a21\u4e3a n \u7684\u65f6\u5019\uff0c\u6709 2n \u6b21\u9012\u5f52\u8c03\u7528 \u5b8c\u5168\u586b\u5145\u7684\u4e8c\u53c9\u8c03\u7528\u6811\u91cc\u6bcf\u4e00\u5c42\uff1a \u8c03\u7528\u6b21\u6570\u662f\u4e0a\u4e00\u5c42\u8c03\u7528\u6b21\u6570\u76842\u500d \u4e0e\u4e0a\u4e00\u5c42\u76f8\u540c\u7684\u8c03\u7528\u6b21\u6570 3.10.\u7f16\u7a0b\u7ec3\u4e60 \u00b6 1\uff0e\u5bf9\u4e00\u4e2a\u6709\u5e8f\u5217\u8868\u8fdb\u884c\u987a\u5e8f\u641c\u7d22\uff0c\u5f53\u76ee\u6807\u5c0f\u4e8e\u6709\u5e8f\u5217\u8868\u91cc\u7684\u67d0\u4e2a\u5143\u7d20\u65f6\uff0c\u987a\u5e8f\u641c\u7d22\u53ef\u4ee5\u63d0\u524d\u505c\u6b62\u3002\u5b9a\u4e49\u8fd9\u4e2a\u7b97\u6cd5\u7684\u4fee\u6539\u7248\u672c\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u6765\u63cf\u8ff0\u5b83\u5728\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 \u89e3\u7b54\uff1a \u5728\u6700\u597d\u7684\u60c5\u51b5\u4e0b\uff0c\u76ee\u6807\u5143\u7d20\u5728\u6709\u5e8f\u5217\u8868\u7684\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u51fd\u6570\u53ea\u9700\u8981\u8fdb\u884c\u4e00\u6b21\u6bd4\u8f83\u3002\u6240\u4ee5\uff0c\u6700\u4f73\u60c5\u51b5\u590d\u6742\u5ea6\u4e3a O(1) \u3002 \u5728\u6700\u574f\u7684\u60c5\u51b5\u4e0b\uff0c\u76ee\u6807\u5143\u7d20\u4e0d\u5728\u5217\u8868\u4e2d\uff0c\u5e76\u4e14\u6240\u6709\u5217\u8868\u5143\u7d20\u90fd\u5c0f\u4e8e\u76ee\u6807\u5143\u7d20\u3002\u8fd9\u5c06\u5bfc\u81f4\u51fd\u6570\u904d\u5386\u6574\u4e2a\u5217\u8868\uff0c\u6240\u4ee5\u6700\u574f\u60c5\u51b5\u590d\u6742\u5ea6\u4e3a O(n) \u3002 \u5bf9\u4e8e\u5e73\u5747\u60c5\u51b5\uff0c\u5047\u8bbe\u6709 n \u4e2a\u9879\u5728\u5217\u8868\u4e2d\uff0c\u641c\u7d22\u76ee\u6807\u4f1a\u5728\u5217\u8868\u524d n/2 \u4e2a\u9879\u6216\u8005\u4e0d\u5728\u6240\u6709\u3002\u5728\u8fd9\u4e2a\u7ea6\u5b9a\u4e0b\uff0c\u5e73\u5747\u6211\u4eec\u9700\u8981\u5bfb\u627e n/2 \u4e2a\u9879\uff0c\u56e0\u6b64\u590d\u6742\u5ea6\u4e3a O(n) \u3002\u4e4b\u6240\u4ee5\u662f n/2 \uff0c\u662f\u56e0\u4e3a\u8fd9\u4e2a\u4efb\u52a1\u53ef\u80fd\u4f1a\u5728\u4efb\u4f55\u5730\u65b9\u88ab\u505c\u6b62\uff0c\u6211\u4eec\u5bf9\u6b64\u505a\u5e73\u5747\u5904\u7406\u3002\u7136\u800c\u5728\u5927O\u6807\u8bb0\u6cd5\u4e2d\uff0c\u5e38\u6570\u5c06\u88ab\u9057\u5fd8\uff0c\u6240\u4ee5\u5b83\u4ecd\u7136\u662f O(n) \u3002 \u4ee3\u7801\u5982\u4e0b\uff1a def ordered_sequential_search ( arr , target ): comparisons = 0 # \u7528\u4e8e\u7edf\u8ba1\u6bd4\u8f83\u6b21\u6570 index = 0 while index < len ( arr ): comparisons += 1 if arr [ index ] == target : return comparisons , index # \u627e\u5230\u76ee\u6807\u5e76\u8fd4\u56de\u6bd4\u8f83\u6b21\u6570\u548c\u7d22\u5f15 elif arr [ index ] > target : break # \u5982\u679c\u76ee\u6807\u5c0f\u4e8e\u5f53\u524d\u5143\u7d20\uff0c\u63d0\u524d\u505c\u6b62\u641c\u7d22 index += 1 return comparisons , - 1 # \u6ca1\u627e\u5230\u76ee\u6807\u8fd4\u56de\u6bd4\u8f83\u6b21\u6570\u548c-1 def main (): # \u6d4b\u8bd5 arr = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] for target in [ 5 , 11 ]: comparisons , index = ordered_sequential_search ( arr , target ) if index != - 1 : print ( f \"\u76ee\u6807 { target } \u5728\u7d22\u5f15 { index } \u5904\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a { comparisons } \" ) else : print ( f \"\u76ee\u6807 { target } \u672a\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a { comparisons } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # \u76ee\u6807 5 \u5728\u7d22\u5f15 4 \u5904\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a 5 # \u76ee\u6807 11 \u672a\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a 10 2\uff0e\u5217\u8868\u7684 reverse \u65b9\u6cd5\u7528\u6765\u53cd\u8f6c\u5217\u8868\u91cc\u7684\u5143\u7d20\u3002\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c reverse \u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u53ef\u4ee5\u5728\u4e0d\u4f7f\u7528 reverse \u65b9\u6cd5\u7684\u60c5\u51b5\u4e0b\uff0c\u53cd\u8f6c\u5217\u8868\u53c2\u6570\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u5c1d\u8bd5\u8ba9\u8fd9\u4e2a\u51fd\u6570\u5c3d\u53ef\u80fd\u5730\u9ad8\u6548\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 \u89e3\u7b54\uff1a \u53ea\u9700\u8981\u904d\u5386\u5217\u8868\u7684\u4e00\u534a\uff0c\u6211\u4eec\u5c31\u80fd\u5230\u8fbe\u5217\u8868\u7684\u4e2d\u95f4\u4f4d\u7f6e\u628a\u5217\u8868\u4e24\u8fb9\u7684\u5143\u7d20\u4e92\u6362\uff0c\u8fd9\u6837\u5c31\u5b8c\u6210\u4e86\u5217\u8868\u7684\u53cd\u8f6c\u3002 \u8fd9\u4e2a\u7b97\u6cd5\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n/2) \uff0c\u5176\u4e2d n \u662f\u5217\u8868\u7684\u957f\u5ea6\u3002\u4f46\u5728\u5927O\u8868\u793a\u6cd5\u4e2d\uff0c\u5e38\u6570\u88ab\u5ffd\u7565\uff0c\u56e0\u6b64\u8be5\u7b97\u6cd5\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002\u5728\u8fd9\u4e2a\u7b97\u6cd5\u4e2d\uff0c n \u5c31\u4ee3\u8868\u7740\u5217\u8868\u7684\u957f\u5ea6\u3002\u610f\u5473\u7740\u65f6\u95f4\u590d\u6742\u5ea6\u53d7\u5217\u8868\u957f\u5ea6\u7684\u5f71\u54cd\u3002\u5217\u8868\u957f\u5ea6\u6bcf\u589e\u52a0\u4e00\u6b21\uff0c\u6267\u884c\u53cd\u8f6c\u7684\u65f6\u95f4\u5c31\u589e\u52a0\u4e00\u6b21\u3002\u8fd9\u5c31\u662f O(n) \u7684\u6982\u5ff5\u3002 \u8fd9\u4e2a\u51fd\u6570\u7684\u7a7a\u95f4\u590d\u6742\u5ea6\u662f O(1) \uff0c\u56e0\u4e3a\u5b83\u53ea\u662f\u5728\u539f\u5730\u4fee\u6539\u5217\u8868\uff0c\u4e0d\u9700\u8981\u989d\u5916\u7684\u5b58\u50a8\u7a7a\u95f4\u3002 \u4ee3\u7801\u5982\u4e0b\uff1a def custom_reverse ( arr ): left , right = 0 , len ( arr ) - 1 while left < right : arr [ left ], arr [ right ] = arr [ right ], arr [ left ] left += 1 right -= 1 def main (): # \u6d4b\u8bd5\u5217\u8868reverse\u65b9\u6cd5 my_list = [ 1 , 2 , 3 , 4 , 5 ] my_list . reverse () print ( my_list ) # \u6d4b\u8bd5\u81ea\u5b9a\u4e49\u7684reverse\u65b9\u6cd5 my_list = [ 1 , 2 , 3 , 4 , 5 ] custom_reverse ( my_list ) print ( my_list ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # [5, 4, 3, 2, 1] # [5, 4, 3, 2, 1] 3\uff0ePython\u7684pow\u51fd\u6570\u4f1a\u8fd4\u56de\u6570\u5b57\u7279\u5b9a\u5e42\u6b21\u7684\u7ed3\u679c\u3002\u5b9a\u4e49\u6267\u884c\u8fd9\u4e2a\u4efb\u52a1\u7684expo\u51fd\u6570\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002\u8fd9\u4e2a\u51fd\u6570\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u6570\u5b57\uff0c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u6307\u6570\uff08\u975e\u8d1f\u6570\uff09\u3002\u4f60\u53ef\u4ee5\u901a\u8fc7\u5faa\u73af\u6216\u9012\u5f52\u51fd\u6570\u6765\u5b9e\u73b0\uff0c\u4f46\u4e0d\u8981\u4f7f\u7528Python\u5185\u7f6e\u7684**\u8fd0\u7b97\u7b26\u6216\u662fpow\u51fd\u6570\u3002 \u89e3\u7b54\uff1a \u4e0b\u9762\u5b9e\u73b0\u7684 expo \u51fd\u6570\u4f7f\u7528\u5faa\u73af\u6765\u8fde\u7eed\u4e58\u4ee5 base \uff0c\u5faa\u73af\u7684\u6b21\u6570\u7b49\u4e8e exponent \u7684\u503c\u3002 \u65f6\u95f4\u590d\u6742\u5ea6\u662f O(exponent) \uff0c\u5176\u4e2d exponent \u662f\u6307\u6570\u7684\u503c\u3002 \u6700\u597d\u60c5\u51b5\uff1aO(exponent) \u6700\u574f\u60c5\u51b5\uff1aO(exponent) \u5e73\u5747\u60c5\u51b5\uff1aO(exponent) def expo ( base , exponent ): result = 1 for _ in range ( exponent ): result *= base return result def main (): # \u6d4b\u8bd5 base = 2 for exponent in [ 3 , - 3 ]: result = expo ( base , exponent ) print ( f \" { base } \u7684 { exponent } \u6b21\u65b9\u7b49\u4e8e { result } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # 2 \u7684 3 \u6b21\u65b9\u7b49\u4e8e 8 # 2 \u7684 -3 \u6b21\u65b9\u7b49\u4e8e 1 4\uff0e\u53e6\u4e00\u4e2a\u5b9e\u73b0 expo \u51fd\u6570\u7684\u7b56\u7565\u4f7f\u7528\u4e0b\u9762\u8fd9\u4e2a\u9012\u5f52\u3002\u8bf7\u5b9a\u4e49\u4f7f\u7528\u8fd9\u4e2a\u7b56\u7565\u7684\u9012\u5f52\u51fd\u6570 expo \uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 expo ( number \uff0c exponent ) = 1 \uff0c \u5f53 exponent = 0 \u7684\u65f6\u5019 = number * expo ( number , exponent \u2212 1 ) \uff0c \u5f53exponent\u4e3a\u5947\u6570\u7684\u65f6\u5019 = ( expo ( number , exponent / 2 )) 2 \uff0c \u5f53exponent\u4e3a\u5076\u6570\u7684\u65f6\u5019 \u89e3\u7b54\uff1a \u4e0b\u9762\u5b9e\u73b0expo\u51fd\u6570\u662f\u901a\u8fc7\u9012\u5f52\u5b9e\u73b0\uff0c\u5e76\u91c7\u7528\u4e86\u5206\u800c\u6cbb\u4e4b\u7684\u7b56\u7565\u3002 \u5982\u679c\u6307\u6570\u662f\u5947\u6570\uff0c\u5c31\u628a\u95ee\u9898\u5206\u89e3\u4e3a\u4e00\u4e2a\u66f4\u5c0f\u7684\u7248\u672c\uff08\u5373 num * num^(exp - 1) \uff09\uff1b \u5982\u679c\u6307\u6570\u662f\u5076\u6570\uff0c\u5219\u53ef\u4ee5\u5c06\u6307\u6570\u5206\u6210\u4e24\u534a\uff0c\u5e76\u53ea\u8ba1\u7b97\u5176\u4e2d\u7684\u4e00\u534a\uff08\u5373 num^(exp / 2) * num^(exp / 2) \uff09\u3002 \u8fd9\u5c31\u5229\u7528\u4e86\u5e42\u7684\u6027\u8d28 a^(m * n) = (a^m)^n \u3002 \u8be5\u9012\u5f52\u5b9e\u73b0\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(log n) \uff0c\u5176\u4e2dn\u4e3a\u6307\u6570\u3002\u8fd9\u662f\u56e0\u4e3a\u5728\u6307\u6570\u4e3a\u5076\u6570\u7684\u60c5\u51b5\u4e0b\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u90fd\u4f1a\u628a\u95ee\u9898\u89c4\u6a21\u7f29\u5c0f\u4e00\u534a\uff0c\u7c7b\u4f3c\u4e8e\u4e8c\u5206\u67e5\u627e\u7b49\u8bfe\u5206\u5272\u95ee\u9898\u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\u4e5f\u662f O(log n) \uff0c\u8fd9\u4e3b\u8981\u662f\u7531\u4e8e\u51fd\u6570\u8c03\u7528\u6808\u7684\u6df1\u5ea6\u5728\u6307\u6570\u4e3a\u5076\u6570\u7684\u60c5\u51b5\u4e0b\uff0c\u4f1a\u53d8\u4e3a\u539f\u6765\u7684\u4e00\u534a\u3002 def expo ( number , exponent ): if exponent <= 0 : return 1 elif exponent % 2 == 1 : # \u5f53 exponent \u4e3a\u5947\u6570 return number * expo ( number , exponent - 1 ) else : # \u5f53 exponent \u4e3a\u5076\u6570 half_expo = expo ( number , exponent // 2 ) return half_expo * half_expo def main (): # \u6d4b\u8bd5 base = 2 for exponent in [ 3 , - 3 ]: result = expo ( base , exponent ) print ( f \" { base } \u7684 { exponent } \u6b21\u65b9\u7b49\u4e8e { result } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # 2 \u7684 3 \u6b21\u65b9\u7b49\u4e8e 8 # 2 \u7684 -3 \u6b21\u65b9\u7b49\u4e8e 1 5\uff0ePython\u4e2dlist\u91cc\u7684sort\u65b9\u6cd5\u5305\u542b\u4e00\u4e2a\u7528\u5173\u952e\u5b57\u547d\u540d\u7684\u53c2\u6570reverse\uff0c\u5b83\u7684\u9ed8\u8ba4\u503c\u4e3aFalse\u3002\u7a0b\u5e8f\u5458\u53ef\u4ee5\u901a\u8fc7\u8986\u76d6\u8fd9\u4e2a\u503c\u4ee5\u5bf9\u5217\u8868\u8fdb\u884c\u964d\u5e8f\u6392\u5e8f\u3002\u4fee\u6539\u672c\u7ae0\u8ba8\u8bba\u7684selectionSort\u51fd\u6570\uff0c\u4f7f\u5b83\u53ef\u4ee5\u63d0\u4f9b\u8fd9\u4e2a\u9644\u52a0\u53c2\u6570\u6765\u8ba9\u7a0b\u5e8f\u5458\u51b3\u5b9a\u6392\u5e8f\u7684\u65b9\u5411\u3002 \u89e3\u7b54\uff1a \u901a\u8fc7\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a reverse \u7684\u53c2\u6570\u6765\u4fee\u6539 selectionSort \u51fd\u6570\uff0c\u4ee5\u4fbf\u8ba9\u7a0b\u5e8f\u5458\u51b3\u5b9a\u6392\u5e8f\u7684\u65b9\u5411\u3002\u5982\u679c reverse \u4e3a True \uff0c\u6392\u5e8f\u5c06\u662f\u964d\u5e8f\u7684\uff0c\u5982\u679c\u4e3a False \uff08\u9ed8\u8ba4\u503c\uff09\uff0c\u6392\u5e8f\u5c06\u662f\u5347\u5e8f\u7684\u3002 \u4e0b\u9762\u662f\u4fee\u6539\u540e\u7684 selectionSort \u51fd\u6570\uff1a def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst , reverse = False ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\uff0c\u53ef\u4ee5\u9009\u62e9\u5347\u5e8f\u6216\u964d\u5e8f\u6392\u5e8f\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 index = i # \u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\u4f4d\u7f6e if not reverse : if ( lyst [ j ] < lyst [ index ]): index = j else : if ( lyst [ j ] > lyst [ index ]): index = j j += 1 if index != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , index , i ) i += 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] 6\uff0e\u4fee\u6539\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\uff0c\u8ba9\u5b83\u652f\u6301\u672c\u7ae0\u91cc\u8ba8\u8bba\u8fc7\u7684\u8bb0\u5fc6\u5316\u6280\u672f\u3002\u8fd9\u4e2a\u51fd\u6570\u5e94\u6dfb\u52a0\u4e00\u4e2a\u5b57\u5178\u7c7b\u578b\u7684\u53c2\u6570\u3002\u5b83\u7684\u9876\u5c42\u8c03\u7528\u4f1a\u63a5\u6536\u4e00\u4e2a\u7a7a\u5b57\u5178\u4f5c\u4e3a\u53c2\u6570\uff0c\u8fd9\u4e2a\u5b57\u5178\u7684\u952e\u548c\u503c\u5e94\u8be5\u662f\u9012\u5f52\u8c03\u7528\u6240\u4f20\u9012\u7684\u53c2\u6570\u548c\u8ba1\u7b97\u51fa\u7684\u503c\u3002\u4e4b\u540e\uff0c\u7528\u672c\u7ae0\u8ba8\u8bba\u8fc7\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u5bf9\u9012\u5f52\u8c03\u7528\u7684\u6570\u91cf\u8fdb\u884c\u7edf\u8ba1\u3002 \u89e3\u7b54\uff1a \u4e0b\u9762\u662f\u4e00\u4e2a\u4fee\u6539\u540e\u7684\u7248\u672c\uff0c\u5b83\u4f7f\u7528\u4e00\u4e2a\u5b57\u5178\uff08\u7f13\u5b58\uff09\u6765\u5b58\u50a8\u5df2\u8ba1\u7b97\u7684\u7ed3\u679c\uff0c\u5e76\u4e14\u6dfb\u52a0\u4e86\u4e00\u4e2a\u8ba1\u6570\u5668\u5bf9\u8c61\u6765\u7edf\u8ba1\u9012\u5f52\u8c03\u7528\u6b21\u6570\u3002\u8fd9\u4e2a\u4ee3\u7801\u4f1a\u8f93\u51fa\u6307\u5b9a\u9879\u6570\u7684\u6590\u6ce2\u90a3\u5951\u6570\u4ee5\u53ca\u9012\u5f52\u8c03\u7528\u7684\u603b\u6b21\u6570\u3002\u8bb0\u5fc6\u5316\u6280\u672f\u53ef\u4ee5\u663e\u8457\u63d0\u9ad8\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u6027\u80fd\uff0c\u907f\u514d\u4e86\u91cd\u590d\u8ba1\u7b97\u3002 class Counter : def __init__ ( self ): self . count = 0 def increment ( self ): self . count += 1 def fib ( n , cache , counter ): \"\"\"\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u6570\u5217\uff0c\u5e26\u6709\u8bb0\u5fc6\u5316\u548c\u8c03\u7528\u8ba1\u6570\u5668\"\"\" if n in cache : return cache [ n ] counter . increment () if n <= 1 : result = 1 else : result = fib ( n - 1 , cache , counter ) + fib ( n - 2 , cache , counter ) cache [ n ] = result return result def main (): n = 10 # \u4f60\u53ef\u4ee5\u8bbe\u7f6e\u4e0d\u540c\u7684\u6590\u6ce2\u90a3\u5951\u6570\u5217\u9879\u6570 cache = {} # \u7528\u4e8e\u7f13\u5b58\u5df2\u8ba1\u7b97\u7ed3\u679c\u7684\u5b57\u5178 counter = Counter () # \u7528\u4e8e\u8ba1\u6570\u9012\u5f52\u8c03\u7528\u6b21\u6570\u7684\u8ba1\u6570\u5668\u5bf9\u8c61 result = fib ( n , cache , counter ) print ( f \"Fibonacci( { n } ) = { result } \" ) print ( f \"Total recursive calls: { counter . count } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Fibonacci(10) = 89 # Total recursive calls: 11 7\uff0e\u5206\u6790\u4e0a\u9762\u6590\u6ce2\u90a3\u5951\u6570\u5217\u91cc\u5b9a\u4e49\u7684\u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u6027\u80fd\uff0c\u7edf\u8ba1\u8fd9\u4e2a\u51fd\u6570\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u3002\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\uff0c\u5e76\u8bc1\u660e\u4f60\u7684\u7b54\u6848\u662f\u5408\u7406\u7684\u3002 \u89e3\u7b54\uff1a \u5728\u4e0a\u9762\u7684\u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u4e2d\uff0c\u6211\u4eec\u4f7f\u7528\u4e86\u8bb0\u5fc6\u5316\u6280\u672f\u6765\u907f\u514d\u91cd\u590d\u8ba1\u7b97\u3002\u8fd9\u79cd\u4f18\u5316\u4f1a\u663e\u8457\u51cf\u5c11\u8ba1\u7b97\u65f6\u95f4\uff0c\u56e0\u4e3a\u6bcf\u4e2a\u6590\u6ce2\u90a3\u5951\u6570\u53ea\u4f1a\u88ab\u8ba1\u7b97\u4e00\u6b21\u3002 \u8ba1\u7b97\u590d\u6742\u5ea6\u5206\u6790\uff1a \u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u662f O(n) \u3002\u8fd9\u662f\u56e0\u4e3a\u5b83\u9700\u8981\u8ba1\u7b97\u6590\u6ce2\u90a3\u5951\u6570\u5217\u7684\u524d n \u9879\uff0c\u6bcf\u4e00\u9879\u53ea\u9700\u8ba1\u7b97\u4e00\u6b21\uff0c\u7136\u540e\u5b58\u50a8\u5728\u7f13\u5b58\u4e2d\u3002\u56e0\u6b64\uff0c\u603b\u5171\u6267\u884c\u7684\u8ba1\u7b97\u91cf\u4e0e n \u6210\u6b63\u6bd4\uff0c\u5373 O(n) \u3002 \u9012\u5f52\u8c03\u7528\u6b21\u6570\uff1a \u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u53d6\u51b3\u4e8e\u8f93\u5165\u53c2\u6570 n \u3002\u5bf9\u4e8e\u6590\u6ce2\u90a3\u5951\u6570\u5217\uff0c\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u5927\u81f4\u7b49\u4e8e n \u3002\u56e0\u4e3a\u6bcf\u4e2a\u9879\u9700\u8981\u8ba1\u7b97\u4e00\u6b21\uff0c\u6240\u4ee5\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u4e0e\u8ba1\u7b97\u7684\u9879\u6570\u662f\u4e00\u81f4\u7684\u3002 \u6240\u4ee5\uff0c\u8fd9\u4e2a\u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u662f O(n) \uff0c\u800c\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u4e5f\u5927\u81f4\u7b49\u4e8e n \u3002\u8fd9\u4e2a\u6027\u80fd\u662f\u76f8\u5bf9\u8f83\u597d\u7684\uff0c\u56e0\u4e3a\u5b83\u907f\u514d\u4e86\u6307\u6570\u7ea7\u522b\u7684\u91cd\u590d\u8ba1\u7b97\uff0c\u800c\u662f\u7ebf\u6027\u5730\u8ba1\u7b97\u6590\u6ce2\u90a3\u5951\u6570\u5217\u7684\u5404\u9879\u3002 8\uff0e\u51fd\u6570makeRandomList\u4f1a\u521b\u5efa\u5e76\u8fd4\u56de\u4e00\u4e2a\u7ed9\u5b9a\u5927\u5c0f\uff08\u5b83\u7684\u53c2\u6570\uff09\u7684\u6570\u5b57\u5217\u8868\u3002\u5217\u8868\u91cc\u7684\u6570\u5b57\u6ca1\u6709\u91cd\u590d\uff0c\u5b83\u4eec\u7684\u8303\u56f4\u4e3a1\uff5esize\uff0c\u4f4d\u7f6e\u662f\u968f\u673a\u7684\u3002\u4e0b\u9762\u662f\u8fd9\u4e2a\u51fd\u6570\u7684\u4ee3\u7801\u3002\u53ef\u4ee5\u5047\u5b9arange\u3001randint\u548cappend\u51fd\u6570\u90fd\u662f\u5e38\u6570\u65f6\u95f4\u7684\u590d\u6742\u5ea6\u3002\u8fd8\u53ef\u4ee5\u5047\u8bberandom.randint\u968f\u7740\u53c2\u6570\u4e4b\u95f4\u5dee\u503c\u7684\u589e\u52a0\u800c\u66f4\u5c11\u5730\u8fd4\u56de\u91cd\u590d\u7684\u6570\u5b57\u3002\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u8fd9\u4e2a\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\uff0c\u5e76\u8bc1\u660e\u4f60\u7684\u7b54\u6848\u662f\u5408\u7406\u7684\u3002 def makeRandomList ( size ): lyst = [] for count in range ( size ): while True : number = random . randint ( 1 , size ) if not number in lyst : lyst . append ( number ) break return lyst \u89e3\u7b54\uff1a \u8fd9\u4e2a\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u5b83\u7684\u5185\u90e8\u5faa\u73af\uff0c\u8be5\u5faa\u73af\u4f1a\u4e0d\u65ad\u751f\u6210\u968f\u673a\u6570\uff0c\u5e76\u68c0\u67e5\u5b83\u662f\u5426\u5df2\u7ecf\u5728\u5217\u8868 lyst \u4e2d\u3002\u5177\u4f53\u5206\u6790\u5982\u4e0b\uff1a \u521b\u5efa\u4e00\u4e2a\u7a7a\u5217\u8868 lyst \uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(1)\u3002 \u8fdb\u5165 for \u5faa\u73af\uff0c\u5faa\u73af\u6b21\u6570\u4e3a size \uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(size)\u3002 \u5728\u5185\u90e8 while \u5faa\u73af\u4e2d\uff0c\u751f\u6210\u4e00\u4e2a\u968f\u673a\u6570 number \uff0c\u6700\u574f\u60c5\u51b5\u4e0b\u9700\u8981\u751f\u6210 size \u6b21\u968f\u673a\u6570\u624d\u80fd\u627e\u5230\u4e00\u4e2a\u4e0d\u5728 lyst \u4e2d\u7684\u6570\u5b57\u3002\u8fd9\u90e8\u5206\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(size)\u3002 \u7efc\u4e0a\u6240\u8ff0\uff0c\u8fd9\u4e2a\u51fd\u6570\u7684\u603b\u4f53\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(size^2)\u3002\u8fd9\u662f\u56e0\u4e3a\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u6bcf\u6b21\u751f\u6210\u7684\u968f\u673a\u6570\u90fd\u9700\u8981\u68c0\u67e5\u662f\u5426\u5728 lyst \u4e2d\uff0c\u800c\u968f\u673a\u6570\u7684\u751f\u6210\u53ef\u80fd\u9700\u8981\u591a\u6b21\u624d\u80fd\u751f\u6210\u4e00\u4e2a\u4e0d\u5728\u5217\u8868\u4e2d\u7684\u6570\u5b57\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u968f\u7740 size \u7684\u589e\u52a0\uff0c\u5185\u90e8\u5faa\u73af\u7684\u8fed\u4ee3\u6b21\u6570\u4e5f\u4f1a\u589e\u52a0\uff0c\u5bfc\u81f4\u65f6\u95f4\u590d\u6742\u5ea6\u5448\u4e8c\u6b21\u589e\u957f\u3002\u56e0\u6b64\uff0c\u8fd9\u4e2a\u51fd\u6570\u7684\u6027\u80fd\u5728\u5927\u89c4\u6a21\u6570\u636e\u4e0a\u53ef\u80fd\u4f1a\u53d7\u5230\u9650\u5236\u3002\u5982\u679c\u9700\u8981\u66f4\u597d\u7684\u6027\u80fd\uff0c\u53ef\u4ee5\u8003\u8651\u5176\u4ed6\u7b97\u6cd5\uff0c\u4ee5\u907f\u514d\u91cd\u590d\u68c0\u67e5\u548c\u751f\u6210\u968f\u673a\u6570\u3002 import random def makeRandomList ( size ): lyst = [] for count in range ( size ): while True : number = random . randint ( 1 , size ) if not number in lyst : lyst . append ( number ) break print ( \"count=\" , count , \"list=\" , lyst ) return lyst def main (): print ( \"final list=\" , makeRandomList ( 10 )) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # count= 0 list= [2] # count= 1 list= [2, 10] # count= 2 list= [2, 10, 9] # count= 3 list= [2, 10, 9, 5] # count= 4 list= [2, 10, 9, 5, 3] # count= 5 list= [2, 10, 9, 5, 3, 4] # count= 6 list= [2, 10, 9, 5, 3, 4, 8] # count= 7 list= [2, 10, 9, 5, 3, 4, 8, 7] # count= 8 list= [2, 10, 9, 5, 3, 4, 8, 7, 6] # count= 9 list= [2, 10, 9, 5, 3, 4, 8, 7, 6, 1] # final list= [2, 10, 9, 5, 3, 4, 8, 7, 6, 1] 9\uff0e\u4fee\u6539quicksort\u51fd\u6570\uff0c\u8ba9\u5b83\u53ef\u4ee5\u5bf9\u4efb\u4f55\u5c3a\u5bf8\u5c0f\u4e8e50\u7684\u5b50\u5217\u8868\u8c03\u7528\u63d2\u5165\u6392\u5e8f\u3002\u4f7f\u7528\u670950\u3001500\u548c5000\u4e2a\u5143\u7d20\u7684\u6570\u636e\u96c6\u6bd4\u8f83\u8fd9\u4e2a\u7248\u672c\u4e0e\u539f\u59cb\u7248\u672c\u7684\u6027\u80fd\u3002\u7136\u540e\u8c03\u6574\u8fd9\u4e2a\u9608\u503c\uff0c\u4ece\u800c\u786e\u5b9a\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u7684\u6700\u4f73\u8bbe\u7f6e\u3002 \u89e3\u7b54\uff1a \u53ef\u4ee5\u5728 quicksortHelper \u51fd\u6570\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u6761\u4ef6\uff0c\u68c0\u67e5\u5b50\u5217\u8868\u7684\u5927\u5c0f\u3002\u7136\u540e\u518d\u4fee\u6539 quicksort \u51fd\u6570\uff0c\u5b9e\u73b0\u5728\u5c0f\u4e8e50\u7684\u5b50\u5217\u8868\u4e0a\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u3002 \u5982\u679c\u5b50\u5217\u8868\u7684\u5927\u5c0f\u5c0f\u4e8e50\uff0c\u5c31\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u7b97\u6cd5\uff0c\u5426\u5219\u4f7f\u7528\u5feb\u901f\u6392\u5e8f\u7b97\u6cd5\u3002\u4e0b\u9762\u662f\u4fee\u6539\u540e\u7684\u4ee3\u7801\uff1a import random def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def quicksort ( lyst ): quicksortHelper ( lyst , 0 , len ( lyst ) - 1 ) def quicksortHelper ( lyst , left , right ): if left < right : # \u68c0\u67e5\u5b50\u5217\u8868\u7684\u5927\u5c0f\u662f\u5426\u5c0f\u4e8e50 if right - left < 50 : # \u5982\u679c\u5c0f\u4e8e50\uff0c\u4f7f\u7528\u63d2\u5165\u6392\u5e8f insertionSort ( lyst , left , right ) else : pivotLocation = partition ( lyst , left , right ) quicksortHelper ( lyst , left , pivotLocation - 1 ) quicksortHelper ( lyst , pivotLocation + 1 , right ) def partition ( lyst , left , right ): \"\"\"\u5bf9\u5217\u8868\u8fdb\u884c\u5206\u533a\"\"\" # \u627e\u5230\u57fa\u51c6\u5143\u7d20\uff08pivot\uff09\uff0c\u5e76\u548c\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u4e92\u6362 middle = ( left + right ) // 2 pivot = lyst [ middle ] lyst [ middle ] = lyst [ right ] lyst [ right ] = pivot # \u8bbe\u5b9a\u8fb9\u754c\u5143\u7d20\uff08boundary point\uff09\uff0c\u521d\u59cb\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20 boundary = left print ( \"pivot: \" , pivot , \"boundary: \" , lyst [ boundary ]) # \u628a\u6240\u6709\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u90fd\u79fb\u52a8\u5230\u8fb9\u754c\u7684\u5de6\u8fb9 for index in range ( left , right ): if lyst [ index ] < pivot : swap ( lyst , index , boundary ) boundary += 1 # \u4ea4\u6362\u57fa\u51c6\u5143\u7d20\u548c\u8fb9\u754c\u5143\u7d20 swap ( lyst , right , boundary ) print ( lyst ) return boundary def insertionSort ( lyst , left , right ): \"\"\"\u63d2\u5165\u6392\u5e8f\u7b97\u6cd5\"\"\" for i in range ( left + 1 , right + 1 ): currentElement = lyst [ i ] j = i while j > left and currentElement < lyst [ j - 1 ]: lyst [ j ] = lyst [ j - 1 ] j -= 1 lyst [ j ] = currentElement def main ( size = 20 , sort = quicksort ): lyst = [ random . randint ( 1 , size ) for _ in range ( size )] print ( \"Before sorted\" , lyst ) sort ( lyst ) print ( \"After sorted\" , lyst ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before sorted [1, 3, 6, 14, 9, 6, 14, 15, 17, 13, 4, 3, 1, 13, 11, 16, 2, 4, 6, 2] # After sorted [1, 1, 2, 2, 3, 3, 4, 4, 6, 6, 6, 9, 11, 13, 13, 14, 14, 15, 16, 17] 10\uff0e\u8ba1\u7b97\u673a\u4f7f\u7528\u540d\u4e3a\u8c03\u7528\u6808\u7684\u7ed3\u6784\u6765\u4e3a\u9012\u5f52\u51fd\u6570\u7684\u8c03\u7528\u63d0\u4f9b\u652f\u6301\u3002\u4e00\u822c\u800c\u8a00\uff0c\u8ba1\u7b97\u673a\u4f1a\u4e3a\u51fd\u6570\u7684\u6bcf\u6b21\u8c03\u7528\u90fd\u4fdd\u7559\u4e00\u5b9a\u6570\u91cf\u7684\u5185\u5b58\u3002\u56e0\u6b64\uff0c\u53ef\u4ee5\u5bf9\u9012\u5f52\u51fd\u6570\u4f7f\u7528\u7684\u5185\u5b58\u6570\u91cf\u8fdb\u884c\u590d\u6742\u5ea6\u5206\u6790\u3002\u8bf7\u8bf4\u660e\u9012\u5f52\u9636\u4e58\u51fd\u6570\u548c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u4f7f\u7528\u7684\u5185\u5b58\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 \u89e3\u7b54\uff1a \u9012\u5f52\u9636\u4e58\u51fd\u6570\u548c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u4f7f\u7528\u7684\u5185\u5b58\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u90fd\u4e0e\u9012\u5f52\u7684\u6df1\u5ea6\uff08\u9012\u5f52\u8c03\u7528\u7684\u5c42\u6570\uff09\u76f8\u5173\u3002\u9012\u5f52\u51fd\u6570\u6bcf\u6b21\u8c03\u7528\u90fd\u4f1a\u5728\u8c03\u7528\u6808\u4e2d\u5206\u914d\u4e00\u5b9a\u6570\u91cf\u7684\u5185\u5b58\uff0c\u5305\u62ec\u51fd\u6570\u7684\u53c2\u6570\u3001\u5c40\u90e8\u53d8\u91cf\u4ee5\u53ca\u8fd4\u56de\u5730\u5740\u7b49\u4fe1\u606f\u3002 \u9012\u5f52\u9636\u4e58\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\uff1a \u9012\u5f52\u9636\u4e58\u51fd\u6570\u662f\u4e00\u4e2a\u975e\u5e38\u7b80\u5355\u7684\u9012\u5f52\u51fd\u6570\uff0c\u5b83\u53ea\u9700\u8981\u4fdd\u5b58\u4e00\u4e2a\u6574\u6570\u53c2\u6570 n \u548c\u8fd4\u56de\u5730\u5740\u3002\u56e0\u6b64\uff0c\u5b83\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(1)\uff0c\u4e0e\u8f93\u5165\u53c2\u6570 n \u7684\u5927\u5c0f\u65e0\u5173\u3002\u6bcf\u4e2a\u9012\u5f52\u8c03\u7528\u90fd\u53ea\u9700\u8981\u5e38\u6570\u7ea7\u522b\u7684\u5185\u5b58\u7a7a\u95f4\u3002 \u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\uff1a \u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u9012\u5f52\u7684\u6df1\u5ea6\u3002\u6bcf\u4e2a\u9012\u5f52\u8c03\u7528\u90fd\u9700\u8981\u4fdd\u5b58\u4e24\u4e2a\u6574\u6570\u53c2\u6570 n \u548c depth \uff0c\u4ee5\u53ca\u8fd4\u56de\u5730\u5740\u3002\u56e0\u6b64\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u9700\u8981\u7684\u5185\u5b58\u7a7a\u95f4\u662f\u5e38\u6570\u7ea7\u522b\u7684\u3002 \u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u9012\u5f52\u6df1\u5ea6\u53d6\u51b3\u4e8e\u8f93\u5165\u53c2\u6570 n \u3002\u5177\u4f53\u6765\u8bf4\uff0c\u9012\u5f52\u6df1\u5ea6\u7b49\u4e8e n \u3002\u56e0\u6b64\uff0c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(n)\uff0c\u4e0e\u8f93\u5165\u53c2\u6570 n \u6210\u6b63\u6bd4\u3002 \u603b\u7ed3\u6765\u8bf4\uff0c\u9012\u5f52\u9636\u4e58\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(1)\uff0c\u800c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(n)\u3002\u5728\u9012\u5f52\u7b97\u6cd5\u4e2d\uff0c\u5185\u5b58\u590d\u6742\u5ea6\u901a\u5e38\u4e0e\u9012\u5f52\u6df1\u5ea6\u6210\u6b63\u6bd4\uff0c\u56e0\u6b64\u9700\u8981\u8c28\u614e\u5904\u7406\u9012\u5f52\u8c03\u7528\uff0c\u4ee5\u907f\u514d\u51fa\u73b0\u6808\u6ea2\u51fa\u7b49\u95ee\u9898\u3002\u53ef\u4ee5\u4f7f\u7528\u8fed\u4ee3\u6216\u52a8\u6001\u89c4\u5212\u7b49\u65b9\u6cd5\u6765\u964d\u4f4e\u5185\u5b58\u6d88\u8017\u3002","title":"\u641c\u7d22\u3001\u6392\u5e8f\u4ee5\u53ca\u590d\u6742\u5ea6\u5206\u6790"},{"location":"python/DataStructure/03_TimeComplexity/#3","text":"\u7b97\u6cd5\u63cf\u8ff0\u4e86\u4e00\u4e2a\u968f\u7740\u95ee\u9898\u88ab\u89e3\u51b3\u800c\u505c\u6b62\u7684\u8ba1\u7b97\u8fc7\u7a0b\u3002 \u7b97\u6cd5\u662f\u8ba1\u7b97\u673a\u7a0b\u5e8f\u7684\u57fa\u672c\u7ec4\u6210\u90e8\u5206\u4e4b\u4e00\uff0c\u53e6\u4e00\u4e2a\u57fa\u672c\u7ec4\u6210\u90e8\u5206\u662f\u6570\u636e\u7ed3\u6784\u3002 \u5728\u7b97\u6cd5\u6267\u884c\u8fc7\u7a0b\u4e2d\u4f1a\u6d88\u8017\u4e24\u4e2a\u8d44\u6e90\uff1a\u5904\u7406\u5bf9\u8c61\u6240\u9700\u7684\u65f6\u95f4\u548c\u7a7a\u95f4\uff08\u4e5f\u5c31\u662f\u5185\u5b58\uff09\u3002\u5bf9\u4e8e\u7b97\u6cd5\u6765\u8bf4\uff0c\u603b\u4f1a\u8ffd\u6c42\u6d88\u8017\u66f4\u77ed\u7684\u65f6\u95f4\u548c\u5360\u7528\u66f4\u5c11\u7684\u7a7a\u95f4\u3002\u5728\u9009\u62e9\u7b97\u6cd5\u65f6\uff0c\u901a\u5e38\u5728\u7a7a\u95f4/\u65f6\u95f4\u4e4b\u95f4\u8fdb\u884c\u6743\u8861\u3002 \u7b97\u6cd5\u8d28\u91cf\u7684\u4e3b\u8981\u8bc4\u4f30\u6807\u51c6\uff1a \u6b63\u786e\u6027\uff0c\u5373\u7b97\u6cd5\u80fd\u591f\u771f\u6b63\u89e3\u51b3\u6240\u9488\u5bf9\u7684\u95ee\u9898\uff1b \u53ef\u8bfb\u6027\u548c\u6613\u4e8e\u7ef4\u62a4\u6027\uff1b \u8fd0\u884c\u65f6\u6027\u80fd\uff1b \u76ee\u6807\uff1a \u6839\u636e\u95ee\u9898\u7684\u89c4\u6a21\u786e\u5b9a\u7b97\u6cd5\u5de5\u4f5c\u91cf\u7684\u589e\u957f\u7387\uff1b \u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u6765\u63cf\u8ff0\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\uff1b \u8ba4\u8bc6\u5e38\u89c1\u7684\u5de5\u4f5c\u91cf\u589e\u957f\u7387\u6216\u590d\u6742\u5ea6\u7684\u7c7b\u522b\uff08\u5e38\u6570\u3001\u5bf9\u6570\u3001\u7ebf\u6027\u3001\u5e73\u65b9\u548c\u6307\u6570\uff09\uff1b \u5c06\u7b97\u6cd5\u8f6c\u6362\u4e3a\u590d\u6742\u5ea6\u4f4e\u4e00\u4e2a\u6570\u91cf\u7ea7\u7684\u66f4\u5feb\u7684\u7248\u672c\uff1b \u63cf\u8ff0\u987a\u5e8f\u641c\u7d22\u7b97\u6cd5\u548c\u4e8c\u5206\u641c\u7d22\u7b97\u6cd5\u7684\u5de5\u4f5c\u65b9\u5f0f\uff1b \u63cf\u8ff0\u9009\u62e9\u6392\u5e8f\u7b97\u6cd5\u548c\u5feb\u901f\u6392\u5e8f\u7b97\u6cd5\u7684\u5de5\u4f5c\u65b9\u5f0f\u3002","title":"3.\u641c\u7d22\u3001\u6392\u5e8f\u4ee5\u53ca\u590d\u6742\u5ea6\u5206\u6790"},{"location":"python/DataStructure/03_TimeComplexity/#31","text":"\u8861\u91cf\u7b97\u6cd5\u65f6\u95f4\u6210\u672c\u7684\u4e24\u79cd\u65b9\u6cd5\uff1a \u7528\u8ba1\u7b97\u673a\u65f6\u949f\u5f97\u5230\u7b97\u6cd5\u5b9e\u9645\u7684\u8fd0\u884c\u65f6\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u88ab\u79f0\u4e3a\u57fa\u51c6\u6d4b\u8bd5\uff08benchmarking\uff09\u6216\u6027\u80fd\u5206\u6790\uff08profiling\uff09\u3002\u9884\u6d4b\u7b97\u6cd5\u6267\u884c\u7684\u62bd\u8c61\u5de5\u4f5c\u91cf\u4f9d\u8d56\u4e8e\u7279\u5b9a\u7684\u786c\u4ef6\u6216\u8f6f\u4ef6\u5e73\u53f0\u3002 \u5728\u4e0d\u540c\u95ee\u9898\u89c4\u6a21\u4e0b\uff0c\u7edf\u8ba1\u9700\u8981\u6267\u884c\u7684\u6307\u4ee4\u6570\u3002\u9884\u6d4b\u7b97\u6cd5\u6267\u884c\u7684\u62bd\u8c61\u5de5\u4f5c\u91cf\u9002\u7528\u4e8e\u4e0d\u540c\u7684\u786c\u4ef6\u6216\u8f6f\u4ef6\u5e73\u53f0\u3002","title":"3.1.\u8861\u91cf\u7b97\u6cd5\u7684\u6548\u7387"},{"location":"python/DataStructure/03_TimeComplexity/#311","text":"import time problemSize = 10000000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): \"\"\" \u5728\u4e00\u4e2a\u5faa\u73af\u4e2d\uff0c\u5c06\u95ee\u9898\u89c4\u6a21\u7ffb\u500d5\u6b21\uff0c\u8bb0\u5f55\u7b97\u6cd5\u6bcf\u6b21\u8fd0\u884c\u65f6\u95f4\u3002 \"\"\" start = time . time () # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f elapsed = time . time () - start print ( \" %12d%16.3f \" % ( problemSize , elapsed )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Seconds # 10000000 0.689 # 20000000 1.367 # 40000000 2.644 # 80000000 5.296 # 160000000 10.622 \u4e0a\u8ff0\u6d4b\u8bd5\u7a0b\u5e8f\u4f7f\u7528\u4e86 time \u6a21\u5757\u91cc\u7684 time() \u51fd\u6570\u6765\u8bb0\u5f55\u8fd0\u884c\u65f6\uff0c\u5373 time.time() \u3002\u8fd9\u4e2a\u51fd\u6570\u4f1a\u8fd4\u56de\u8ba1\u7b97\u673a\u7684\u5f53\u524d\u65f6\u95f4\u548c1970\u5e741\u67081\u65e5\uff3b\u4e5f\u79f0\u4e3a\u7eaa\u5143\uff08epoch\uff09\uff3d\u76f8\u5dee\u7684\u79d2\u6570\u3002\u4e24\u6b21\u8c03\u7528 time.time() \u7684\u7ed3\u679c\u4e4b\u95f4\u7684\u5dee\u503c\u5c31\u4ee3\u8868\u4e86\u4e2d\u95f4\u7ecf\u5386\u4e86\u591a\u5c11\u79d2\u3002 \u4e0a\u8ff0\u6d4b\u8bd5\u7a0b\u5e8f\u5728\u6bcf\u6b21\u5faa\u73af\u7684\u65f6\u5019\u90fd\u4f1a\u6267\u884c\u4e24\u4e2a\u6269\u5c55\u7684\u8d4b\u503c\u8bed\u53e5\uff0c\u4e5f\u5c31\u662f\u6bcf\u6b21\u90fd\u6267\u884c\u7684\u5de5\u4f5c\u91cf\u662f\u56fa\u5b9a\u7684\uff0c\u4f1a\u6d88\u8017\u4e86\u4e00\u5b9a\u7684\u65f6\u95f4\u3002 \u4fee\u6539\u4e0a\u8ff0\u7b97\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u4ece\u4e0b\u9762\u7684\u8fd0\u884c\u7ed3\u679c\u770b\u51fa\uff0c\u5f53 problemSize \u4e3a 1,000 \u65f6\uff0c\u7b97\u6cd5\u7684\u6d88\u8017\u65f6\u95f4\u5c31\u5df2\u7ecf\u8d85\u8fc7\u4e86\u539f\u5148\u7b97\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u63a8\u65ad\u51fa\u7ee7\u7eed\u6d4b\u8bd5 problemSize \u4e3a 10,000,000 \u7684\u8017\u65f6\u5df2\u7ecf\u53d8\u5f97\u4e0d\u5b9e\u9645\u4e86\u3002 import time problemSize = 1000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): start = time . time () # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): for y in range ( problemSize ): work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f elapsed = time . time () - start print ( \" %12d%16.3f \" % ( problemSize , elapsed )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Seconds # 1000 0.093 # 2000 0.350 # 4000 1.280 # 8000 5.004 # 16000 20.020 \u4e0d\u540c\u7684\u786c\u4ef6\u5e73\u53f0\u4f1a\u6709\u4e0d\u540c\u7684\u5904\u7406\u901f\u5ea6\uff0c\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u4f1a\u56e0\u673a\u5668\u7684\u4e0d\u540c\u800c\u5b58\u5728\u5dee\u5f02\u3002 \u7a0b\u5e8f\u7684\u8fd0\u884c\u65f6\u4e5f\u4f1a\u968f\u7740\u5b83\u548c\u786c\u4ef6\u4e4b\u95f4\u7684\u64cd\u4f5c\u7cfb\u7edf\u7c7b\u578b\u7684\u4e0d\u540c\u800c\u53d8\u5316\u3002 \u4e0d\u540c\u7684\u7f16\u7a0b\u8bed\u8a00\u548c\u7f16\u8bd1\u5668\u751f\u6210\u7684\u4ee3\u7801\u7684\u6027\u80fd\u4e5f\u4f1a\u6709\u6240\u4e0d\u540c\uff0c\u56e0\u6b64\uff0c\u5728\u67d0\u4e00\u4e2a\u786c\u4ef6\u6216\u8f6f\u4ef6\u5e73\u53f0\u4e0a\u6d4b\u5f97\u7684\u8fd0\u884c\u65f6\u7ed3\u679c\u901a\u5e38\u4e0d\u80fd\u7528\u6765\u9884\u6d4b\u5728\u5176\u4ed6\u5e73\u53f0\u4e0a\u7684\u6027\u80fd\u3002 \u7528\u975e\u5e38\u5927\u7684\u6570\u636e\u96c6\u786e\u5b9a\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u662f\u975e\u5e38\u4e0d\u5207\u5b9e\u9645\u7684\u3002\u5bf9\u4e8e\u67d0\u4e9b\u7b97\u6cd5\u6765\u8bf4\uff0c\u4e0d\u8bba\u662f\u7f16\u8bd1\u7684\u4ee3\u7801\u8fd8\u662f\u786c\u4ef6\u5904\u7406\u5668\u7684\u901f\u5ea6\u6709\u591a\u5feb\uff0c\u90fd\u6ca1\u6709\u4efb\u4f55\u7684\u533a\u522b\uff0c\u56e0\u4e3a\u5b83\u4eec\u5728\u4efb\u4f55\u8ba1\u7b97\u673a\u4e0a\u90fd\u6ca1\u529e\u6cd5\u5904\u7406\u975e\u5e38\u5927\u7684\u6570\u636e\u96c6\u3002","title":"3.1.1.\u8861\u91cf\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6"},{"location":"python/DataStructure/03_TimeComplexity/#312","text":"\u7edf\u8ba1\u6307\u4ee4\u6570\u65f6\uff0c\u7edf\u8ba1\u7684\u662f\u7f16\u5199\u7b97\u6cd5\u7684\u9ad8\u7ea7\u8bed\u8a00\u91cc\u7684\u6307\u4ee4\u6570\uff0c\u800c\u4e0d\u662f\u53ef\u6267\u884c\u673a\u5668\u8bed\u8a00\u7a0b\u5e8f\u91cc\u7684\u6307\u4ee4\u6570\u3002 \u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\u5bf9\u7b97\u6cd5\u8fdb\u884c\u5206\u6790\u65f6\uff0c\u628a\u5b83\u5206\u6210\u4e24\u4e2a\u90e8\u5206\uff1a \u65e0\u8bba\u95ee\u9898\u7684\u89c4\u6a21\u5982\u4f55\u53d8\u5316\uff0c\u6307\u4ee4\u6267\u884c\u7684\u6b21\u6570\u603b\u662f\u76f8\u540c\u7684\uff1b\u6211\u4eec\u5ffd\u7565\u8fd9\u79cd\u7c7b\u578b\uff0c\u56e0\u4e3a\u5206\u6790\u6548\u7387\u65f6\u5b83\u4eec\u7684\u4f5c\u7528\u5e76\u4e0d\u660e\u663e\u3002 \u6267\u884c\u7684\u6307\u4ee4\u6570\u968f\u7740\u95ee\u9898\u89c4\u6a21\u7684\u53d8\u5316\u800c\u53d8\u5316\uff1b\u6211\u4eec\u91cd\u70b9\u5173\u6ce8\u8fd9\u79cd\u7c7b\u578b\uff0c\u8fd9\u79cd\u7c7b\u578b\u7684\u6307\u4ee4\u901a\u5e38\u53ef\u4ee5\u5728\u5faa\u73af\u6216\u8005\u9012\u5f52\u51fd\u6570\u91cc\u627e\u5230\u3002 \u6211\u4eec\u6765\u6539\u5199\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u4ece\u7edf\u8ba1\u8fd0\u884c\u65f6\u95f4\u53d8\u4e3a\u7edf\u8ba1\u8fed\u4ee3\u6b21\u6570\u3002 \u4e0b\u9762\u7684\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u662f\u76f8\u7b49\u7684\u3002 import time problemSize = 10000000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): number = 0 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%16.3f \" % ( problemSize , Iterations )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Iterations # 10000000 10000000.000 # 20000000 20000000.000 # 40000000 40000000.000 # 80000000 80000000.000 # 160000000 160000000.000 \u4e0b\u9762\u7684\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u7684\u5e73\u65b9\u3002\u8fd9\u5c31\u89e3\u91ca\u4e86\u4e3a\u4ec0\u4e48\u8fd9\u4e2a\u7b97\u6cd5\u7684\u8017\u65f6\u975e\u5e38\u5927\u3002 import time problemSize = 1000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): number = 0 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): for y in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%16.3f \" % ( problemSize , number )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Iterations # 1000 1000000.000 # 2000 4000000.000 # 4000 16000000.000 # 8000 64000000.000 # 16000 256000000.000 \u5728\u4e0b\u9762\u7684\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7684\u4f8b\u5b50\u4e2d\uff0c\u51fd\u6570 fib(problemSize, counter) \u4e2d counter \u53c2\u6570\u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u7684\u65f6\u5019\uff0c\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u3002 \u4ece\u4e0b\u9762\u7684\u8fd0\u884c\u7ed3\u679c\u53ef\u4ee5\u770b\u51fa\uff0c\u968f\u7740\u95ee\u9898\u89c4\u6a21\uff08Problem Size\uff09\u7684\u7ffb\u500d\uff0c\u6307\u4ee4\u6570\uff08\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\uff09\u5728\u4e00\u5f00\u59cb\u7684\u65f6\u5019\u7f13\u6162\u589e\u957f\uff0c\u968f\u540e\u8fc5\u901f\u52a0\u5feb\u3002 \u7edf\u8ba1\u6307\u4ee4\u6570\u662f\u6b63\u786e\u7684\u601d\u8def\uff0c\u4f46\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u8fdb\u884c\u8ddf\u8e2a\u8ba1\u6570\u7684\u95ee\u9898\u5728\u4e8e\uff0c\u5bf9\u4e8e\u67d0\u4e9b\u7b97\u6cd5\u6765\u8bf4\uff0c\u5982\u679c\u95ee\u9898\u89c4\u6a21\u975e\u5e38\u5927\uff0c\u8ba1\u7b97\u673a\u65e0\u6cd5\u4ee5\u8db3\u591f\u5feb\u7684\u901f\u5ea6\u8fd0\u884c\uff0c\u5e76\u5728\u4e00\u5b9a\u65f6\u95f4\u5185\u5f97\u5230\u7ed3\u679c\u3002 class Counter ( object ): \"\"\"Models a counter.\"\"\" # Class variable instances = 0 #Constructor def __init__ ( self ): \"\"\"Sets up the counter.\"\"\" Counter . instances += 1 self . reset () # Mutator methods def reset ( self ): \"\"\"Sets the counter to 0.\"\"\" self . _value = 0 def increment ( self , amount = 1 ): \"\"\"Adds amount to the counter.\"\"\" self . _value += amount def decrement ( self , amount = 1 ): \"\"\"Subtracts amount from the counter.\"\"\" self . _value -= amount # Accessor methods def getValue ( self ): \"\"\"Returns the counter's value.\"\"\" return self . _value def __str__ ( self ): \"\"\"Returns the string representation of the counter.\"\"\" return str ( self . _value ) def __eq__ ( self , other ): \"\"\"Returns True if self equals other or False otherwise.\"\"\" if self is other : return True if type ( self ) != type ( other ): return False return self . _value == other . _value def fib ( n , counter ): \"\"\"\u7edf\u8ba1\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u88ab\u5916\u90e8\u8c03\u7528\u7684\u6b21\u6570\"\"\" counter . increment () if n < 3 : return 1 else : return fib ( n - 1 , counter ) + fib ( n - 2 , counter ) problemSize = 2 print ( \" %12s%15s \" % ( \"Problem Size\" , \"Calls\" )) for count in range ( 5 ): \"\"\"\u968f\u7740\u95ee\u9898\u89c4\u6a21\u589e\u52a0\uff0c\u8f93\u51fa\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u51fd\u6570\u88ab\u5916\u90e8\u8c03\u7528\u7684\u6b21\u6570\"\"\" counter = Counter () # \u7b97\u6cd5\u5f00\u59cb fib ( problemSize , counter ) # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%15s \" % ( problemSize , counter )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Calls # 2 1 # 4 5 # 8 41 # 16 1973 # 32 4356617","title":"3.1.2.\u7edf\u8ba1\u6307\u4ee4\u6570"},{"location":"python/DataStructure/03_TimeComplexity/#313","text":"\u5bf9\u4e8e\u7b97\u6cd5\u6240\u7528\u8d44\u6e90\u7684\u5206\u6790\u4e5f\u9700\u8981\u5305\u542b\u5b83\u6240\u9700\u7684\u5185\u5b58\u91cf\u7684\u5206\u6790\u3002\u548c\u524d\u9762\u7c7b\u4f3c\u7684\u95ee\u9898\u4e5f\u4f1a\u5b58\u5728\uff0c\u4e00\u4e9b\u7b97\u6cd5\u4f1a\u968f\u7740\u95ee\u9898\u89c4\u6a21\u53d8\u5927\u800c\u9700\u8981\u989d\u5916\u66f4\u591a\u7684\u5185\u5b58\u3002","title":"3.1.3.\u8861\u91cf\u7b97\u6cd5\u4f7f\u7528\u7684\u5185\u5b58"},{"location":"python/DataStructure/03_TimeComplexity/#314","text":"\u7f16\u5199\u4e00\u4e2a\u6d4b\u8bd5\u7a0b\u5e8f\uff0c\u8fd9\u4e2a\u7a0b\u5e8f\u7edf\u8ba1\u5e76\u663e\u793a\u51fa\u4e0b\u9762\u8fd9\u4e2a\u5faa\u73af\u7684\u8fed\u4ee3\u6b21\u6570\u3002 while problemSize > 0 : problemSize = problemSize // 2 \u89e3\u7b54\uff1a def count_iterations ( problemSize ): iterations = 0 # \u521d\u59cb\u5316\u8ba1\u6570\u5668 while problemSize > 0 : problemSize = problemSize // 2 iterations += 1 # \u6bcf\u6b21\u5faa\u73af\u8fed\u4ee3\uff0c\u8ba1\u6570\u5668\u52a0\u4e00 return iterations problemSize = 1000 # \u8bbe\u7f6e\u95ee\u9898\u89c4\u6a21 iterations = count_iterations ( problemSize ) print ( f \"Problem Size: { problemSize } \" ) print ( f \"Iterations: { iterations } \" ) # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size: 1000 # Iterations: 10 \u5728\u95ee\u9898\u89c4\u6a21\u5206\u522b\u4e3a1000\u30012000\u30014000\u300110000\u548c100000\u65f6\uff0c\u8fd0\u884c\u5728\u7ec3\u4e601\u91cc\u6240\u521b\u5efa\u7684\u7a0b\u5e8f\u3002\u5f53\u95ee\u9898\u89c4\u6a21\u7ffb\u500d\u6216\u662f\u4e58\u4ee510\u65f6\uff0c\u8fed\u4ee3\u6b21\u6570\u4f1a\u5982\u4f55\u53d8\u5316\uff1f \u89e3\u7b54\uff1a\u5206\u522b\u4ee5\u4e0d\u540c\u7684\u95ee\u9898\u89c4\u6a21\u8fd0\u884c\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u7ed3\u679c\u5982\u4e0b\uff1a Problem Size : 1000 Iterations : 10 Problem Size : 4000 Iterations : 12 Problem Size : 8000 Iterations : 13 Problem Size : 10000 Iterations : 14 Problem Size : 100000 Iterations : 17 \u4e24\u6b21\u8c03\u7528\u51fd\u6570 time.time() \u7684\u7ed3\u679c\u4e4b\u5dee\u5c31\u662f\u8fd0\u884c\u65f6\u3002\u7531\u4e8e\u64cd\u4f5c\u7cfb\u7edf\u4e5f\u53ef\u80fd\u4f1a\u5728\u8fd9\u6bb5\u65f6\u95f4\u5185\u4f7f\u7528CPU\uff0c\u56e0\u6b64\u8fd9\u4e2a\u8fd0\u884c\u65f6\u53ef\u80fd\u5e76\u4e0d\u80fd\u53cd\u6620\u51faPython\u4ee3\u7801\u4f7f\u7528CPU\u7684\u5b9e\u9645\u65f6\u95f4\u3002\u6d4f\u89c8Python\u6587\u6863\uff0c\u627e\u51fa\u53e6\u4e00\u79cd\u53ef\u4ee5\u5b8c\u6574\u8bb0\u5f55\u5904\u7406\u65f6\u95f4\u7684\u65b9\u6cd5\uff0c\u5e76\u63cf\u8ff0\u5982\u4f55\u5b9e\u73b0\u5b83\u3002 \u89e3\u7b54\uff1a \u5728Python\u4e2d\uff0c time \u6a21\u5757\u63d0\u4f9b\u4e86\u66f4\u7cbe\u786e\u7684\u8ba1\u65f6\u529f\u80fd\uff0c\u5176\u4e2d\u7684 time.perf_counter() \u51fd\u6570\u53ef\u4ee5\u7528\u6765\u6d4b\u91cf\u65f6\u95f4\u7684\u7cbe\u786e\u95f4\u9694\u3002\u4e0e time.time() \u4e0d\u540c\uff0c time. perf_counter() \u4f1a\u5728\u5927\u591a\u6570\u5e73\u53f0\u4e0a\u63d0\u4f9b\u4e00\u4e2a\u66f4\u9ad8\u5206\u8fa8\u7387\u7684\u8ba1\u65f6\u5668\uff0c\u53ef\u4ee5\u7528\u6765\u6d4b\u91cf\u4ee3\u7801\u5757\u7684\u6267\u884c\u65f6\u95f4\u3002 time.perf_counter() \u8fd4\u56de\u4e00\u4e2a\u6d6e\u70b9\u6570\uff0c\u8868\u793a\u4ece\u67d0\u4e2a\u7279\u5b9a\u65f6\u95f4\u70b9\u5230\u73b0\u5728\u7ecf\u8fc7\u7684\u79d2\u6570\u3002\u4ee5\u4e0b\u662f\u5982\u4f55\u4f7f\u7528 time.perf_counter() \u6765\u8ba1\u7b97\u4ee3\u7801\u5757\u7684\u6267\u884c\u65f6\u95f4\uff1a import time # \u83b7\u53d6\u8d77\u59cb\u65f6\u95f4\uff08\u5305\u62ecCPU\u65f6\u95f4\u548c\u7cfb\u7edf\u65f6\u95f4\uff09 start_cpu_time = time . process_time () start_real_time = time . perf_counter () start_system_time = time . time () # \u6267\u884c\u4ee3\u7801 for i in range ( 100000000 ): _ = i * i # \u83b7\u53d6\u7ed3\u675f\u65f6\u95f4\uff08\u5305\u62ecCPU\u65f6\u95f4\u548c\u7cfb\u7edf\u65f6\u95f4\uff09 end_cpu_time = time . process_time () end_real_time = time . perf_counter () end_system_time = time . time () # \u8ba1\u7b97CPU\u65f6\u95f4\u5dee cpu_execution_time = end_cpu_time - start_cpu_time real_execution_time = end_real_time - start_real_time system_execution_time = end_system_time - start_system_time print ( f \"CPU Execution Time: { cpu_execution_time : .6f } seconds\" ) print ( f \"Real Execution Time: { real_execution_time : .6f } seconds\" ) print ( f \"System Execution Time: { system_execution_time : .6f } seconds\" ) # \u8fd0\u884c\u7ed3\u679c\uff1a # CPU Execution Time: 7.157305 seconds # Real Execution Time: 7.156638 seconds # System Execution Time: 7.156638 seconds \u5728\u4e0a\u9762\u4ee3\u7801\u4e2d\uff0c start_system_time \u548c end_system_time \u5206\u522b\u8bb0\u5f55\u4e86\u4ee3\u7801\u5757\u5f00\u59cb\u548c\u7ed3\u675f\u65f6\u7684\u7cfb\u7edf\u65f6\u95f4\u3002\u7136\u540e\uff0c\u53ef\u4ee5\u901a\u8fc7\u8ba1\u7b97 end_system_time - start_system_time \u6765\u83b7\u53d6\u7cfb\u7edf\u65f6\u95f4\u7684\u6d88\u8017\u3002 \u7cfb\u7edf\u65f6\u95f4\u7684\u8ba1\u7b97\u53ef\u80fd\u53d7\u5230\u7cfb\u7edf\u7684\u5f71\u54cd\uff0c\u53ef\u80fd\u4f1a\u56e0\u4e3a\u7cfb\u7edf\u65f6\u95f4\u7684\u53d8\u5316\u800c\u4ea7\u751f\u4e0d\u51c6\u786e\u7684\u7ed3\u679c\u3002\u5728\u8fdb\u884c\u6027\u80fd\u6d4b\u8bd5\u65f6\uff0c\u5c3d\u91cf\u4ee5CPU\u65f6\u95f4\u548c\u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u4e3a\u4e3b\u8981\u53c2\u8003\u6307\u6807\u3002 \u8865\u5145\uff1a CPU \u65f6\u95f4\u3001\u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u548c\u7cfb\u7edf\u65f6\u95f4\u4ee3\u8868\u4e86\u4e0d\u540c\u7684\u65f6\u95f4\u6307\u6807\uff0c\u5b83\u4eec\u4e4b\u95f4\u6709\u4ee5\u4e0b\u533a\u522b\uff1a CPU \u65f6\u95f4\uff1a - CPU \u65f6\u95f4\u662f\u7a0b\u5e8f\u5728 CPU \u4e0a\u6267\u884c\u7684\u65f6\u95f4\uff0c\u5305\u62ec\u4e86\u5728\u7528\u6237\u6001\uff08\u6267\u884c\u5e94\u7528\u7a0b\u5e8f\u4ee3\u7801\uff09\u548c\u5185\u6838\u6001\uff08\u6267\u884c\u64cd\u4f5c\u7cfb\u7edf\u4ee3\u7801\uff09\u7684\u65f6\u95f4\u3002\u56e0\u6b64\uff0c\u5b83\u8003\u8651\u4e86\u5e94\u7528\u7a0b\u5e8f\u548c\u64cd\u4f5c\u7cfb\u7edf\u7684\u6267\u884c\u65f6\u95f4\u3002 - CPU \u65f6\u95f4\u901a\u5e38\u7528\u4e8e\u6d4b\u91cf\u7a0b\u5e8f\u7684\u8ba1\u7b97\u5bc6\u96c6\u578b\u5de5\u4f5c\u91cf\uff0c\u5373\u5927\u91cf\u8ba1\u7b97\u64cd\u4f5c\uff0c\u6bd4\u5982\u5faa\u73af\u548c\u6570\u5b66\u8ba1\u7b97\u3002 - \u901a\u8fc7 time.process_time() \u51fd\u6570\u53ef\u4ee5\u83b7\u53d6\u5f53\u524d\u8fdb\u7a0b\u7684 CPU \u65f6\u95f4\u3002 \u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\uff1a - \u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u662f\u4ece\u67d0\u4e2a\u65f6\u95f4\u70b9\u5230\u73b0\u5728\u7684\u5b9e\u9645\u7ecf\u8fc7\u7684\u65f6\u95f4\uff0c\u8003\u8651\u4e86\u6240\u6709\u56e0\u7d20\uff0c\u5305\u62ec\u4e86 CPU \u65f6\u95f4\u3001\u7b49\u5f85\u65f6\u95f4\u3001\u7cfb\u7edf\u8c03\u5ea6\u7b49\u3002 - \u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u7528\u4e8e\u6d4b\u91cf\u4ee3\u7801\u7684\u603b\u6267\u884c\u65f6\u95f4\uff0c\u5305\u62ec\u4e86\u8ba1\u7b97\u548c\u7b49\u5f85\u7684\u65f6\u95f4\u3002 - \u901a\u8fc7 time.perf_counter() \u51fd\u6570\u53ef\u4ee5\u83b7\u53d6\u5f53\u524d\u65f6\u95f4\u3002 \u7cfb\u7edf\u65f6\u95f4\uff1a - \u7cfb\u7edf\u65f6\u95f4\u662f\u64cd\u4f5c\u7cfb\u7edf\u5185\u90e8\u7ef4\u62a4\u7684\u4e00\u4e2a\u65f6\u95f4\u503c\uff0c\u5b83\u4ee3\u8868\u4e86\u4ece\u67d0\u4e2a\u56fa\u5b9a\u65f6\u95f4\u70b9\u5f00\u59cb\u7684\u79d2\u6570\u3002 - \u7cfb\u7edf\u65f6\u95f4\u901a\u5e38\u7528\u4e8e\u8bb0\u5f55\u4e8b\u4ef6\u548c\u8ba1\u7b97\u65f6\u95f4\u95f4\u9694\uff0c\u4e0d\u53d7\u7a0b\u5e8f\u7684\u6267\u884c\u5f71\u54cd\u3002 - \u901a\u8fc7 time.time() \u51fd\u6570\u53ef\u4ee5\u83b7\u53d6\u5f53\u524d\u7684\u7cfb\u7edf\u65f6\u95f4\u3002 \u603b\u7ed3\uff1aCPU \u65f6\u95f4\u5173\u6ce8\u7684\u662f\u7a0b\u5e8f\u5728 CPU \u4e0a\u7684\u6267\u884c\u65f6\u95f4\uff0c\u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u5173\u6ce8\u7684\u662f\u4ece\u4ee3\u7801\u5f00\u59cb\u5230\u7ed3\u675f\u6240\u7ecf\u8fc7\u7684\u771f\u5b9e\u65f6\u95f4\uff0c\u7cfb\u7edf\u65f6\u95f4\u662f\u7cfb\u7edf\u7ef4\u62a4\u7684\u5168\u5c40\u65f6\u95f4\u3002\u5728\u4e0d\u540c\u7684\u573a\u666f\u4e2d\uff0c\u4f60\u53ef\u4ee5\u6839\u636e\u9700\u8981\u9009\u62e9\u5408\u9002\u7684\u65f6\u95f4\u6307\u6807\u6765\u8fdb\u884c\u6027\u80fd\u6d4b\u91cf\u548c\u5206\u6790\u3002","title":"3.1.4.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/03_TimeComplexity/#32","text":"\u590d\u6742\u5ea6\u5206\u6790\uff08complexity analysis\uff09\u65b9\u6cd5\uff0c\u4e00\u79cd\u8bc4\u4f30\u7b97\u6cd5\u6548\u7387\u7684\u65b9\u6cd5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u53ef\u4ee5\u4e0d\u7528\u5173\u5fc3\u4e0e\u5e73\u53f0\u76f8\u5173\u7684\u65f6\u95f4\uff0c\u4e5f\u4e0d\u9700\u8981\u4f7f\u7528\u7edf\u8ba1\u6307\u4ee4\u6570\u91cf\u8fd9\u79cd\u65b9\u6cd5\u6765\u5bf9\u7b97\u6cd5\u8fdb\u884c\u8bc4\u4f30\u3002","title":"3.2.\u590d\u6742\u5ea6\u5206\u6790"},{"location":"python/DataStructure/03_TimeComplexity/#321","text":"\u5728 3.1.2.\u7edf\u8ba1\u6307\u4ee4\u6570 \u4e2d\u5173\u4e8e\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u7684\u4e24\u4e2a\u7b97\u6cd5\uff0c\u5b83\u4eec\u590d\u6742\u5ea6\u7684\u9636\uff08order of complexity\uff09\u4e0a\u662f\u4e0d\u4e00\u6837\u7684\u3002 \u7b2c\u4e00\u4e2a\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u4e4b\u95f4\u662f\u7ebf\u6027\u5173\u7cfb\uff0c\u79f0\u5176\u590d\u6742\u5ea6\u4e3a\u7ebf\u6027\uff08linear\uff09\u9636\uff1b \u7b2c\u4e8c\u4e2a\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u4e4b\u95f4\u662f\u5e73\u65b9\u5173\u7cfb\uff0c\u79f0\u5176\u590d\u6742\u5ea6\u4e3a\u5e73\u65b9\uff08quadratic\uff09\u9636\uff1b \u5982\u679c\u7b97\u6cd5\u9700\u8981\u76f8\u540c\u6570\u91cf\u7684\u8fd0\u7b97\uff0c\u90a3\u4e48\u5b83\u7684\u6027\u80fd\u5c31\u662f\u5e38\u6570\uff08constant\uff09\u9636\u3002\u5217\u8868\u7d22\u5f15\u5c31\u662f\u4e00\u4e2a\u5e38\u6570\u65f6\u95f4\u7b97\u6cd5\u7684\u4f8b\u5b50\u3002 \u6bd4\u7ebf\u6027\u6027\u80fd\u597d\uff0c\u4f46\u6bd4\u5e38\u6570\u6027\u80fd\u5dee\u7684\u53e6\u4e00\u4e2a\u590d\u6742\u5ea6\u7684\u9636\u88ab\u79f0\u4e3a\u5bf9\u6570\uff08logarithmic\uff09\u9636\u3002\u5bf9\u6570\u7b97\u6cd5\u7684\u5de5\u4f5c\u91cf\u4e0e\u95ee\u9898\u89c4\u6a21\u7684\u4ee52\u4e3a\u5e95\u7684\u5bf9\u6570\u6210\u6b63\u6bd4\u3002\u5f53\u95ee\u9898\u89c4\u6a21\u6269\u5927\u4e00\u500d\u65f6\uff0c\u5de5\u4f5c\u91cf\u53ea\u4f1a\u52a01\u3002 \u591a\u9879\u5f0f\u65f6\u95f4\u7b97\u6cd5\uff08polynomial time algorithm\uff09\u7684\u5de5\u4f5c\u91cf\u4f1a\u4ee5 n^k \u7684\u901f\u7387\u589e\u957f\uff0c\u5176\u4e2d k \u662f\u5927\u4e8e 1 \u7684\u5e38\u6570\uff0c\u6bd4\u5982 n^2 \u3001 n^3 \u4ee5\u53ca n^10 \u3002\u4ece\u67d0\u79cd\u610f\u4e49\u4e0a\u8bb2\uff0c n^3 \u7684\u6027\u80fd\u8981\u6bd4 n^2 \u5dee\uff0c\u4f46\u90fd\u5c5e\u4e8e\u591a\u9879\u5f0f\uff08polynomial\uff09\u9636\u3002 \u6bd4\u591a\u9879\u5f0f\u8fd8\u8981\u5dee\u7684\u590d\u6742\u5ea6\u7684\u9636\u88ab\u79f0\u4e3a\u6307\u6570\uff08exponential\uff09\u9636\uff0c\u6bd4\u5982 2^n \u3002\u5bf9\u4e8e\u5927\u7684\u95ee\u9898\u89c4\u6a21\u6765\u8bf4\uff0c\u6307\u6570\u7b97\u6cd5\u662f\u4e0d\u53ef\u884c\u7684\u3002 \u4e0d\u540c\u590d\u6742\u5ea6\u9636\u7684\u7b97\u6cd5\u7684\u5de5\u4f5c\u91cf\u6bd4\u8f83\uff08\u4ece\u5c0f\u5230\u5927\uff09\uff1a\u5bf9\u6570\u9636 < \u7ebf\u6027\u9636 < \u5e73\u65b9\u9636 < \u6307\u6570\u9636\u3002\u968f\u7740\u95ee\u9898\u89c4\u6a21\u7684\u589e\u5927\uff0c\u5177\u6709\u8f83\u9ad8\u590d\u6742\u5ea6\u7684\u9636\u7684\u7b97\u6cd5\u7684\u6027\u80fd\u4f1a\u66f4\u5feb\u5730\u53d8\u5dee\u3002","title":"3.2.1.\u590d\u6742\u5ea6\u7684\u9636"},{"location":"python/DataStructure/03_TimeComplexity/#322o","text":"\u5f88\u591a\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u4e2d\u7684\u5de5\u4f5c\u91cf\u901a\u5e38\u662f\u591a\u9879\u5f0f\u91cc\u591a\u9879\u7684\u603b\u548c\uff0c\u800c\u5f53\u5de5\u4f5c\u91cf\u8868\u793a\u4e3a\u591a\u9879\u5f0f\u65f6\uff0c\u5176\u4e2d\u4e00\u9879\u662f\u4e3b\u5bfc\u9879\uff08dominant\uff09\u3002\u968f\u7740 n \u8d8a\u6765\u8d8a\u5927\uff0c\u4e3b\u5bfc\u9879\u5c06\u53d8\u5f97\u975e\u5e38\u5927\uff0c\u4ee5\u81f3\u4e8e\u53ef\u4ee5\u5ffd\u7565\u5176\u4ed6\u9879\u6240\u4ee3\u8868\u7684\u5de5\u4f5c\u91cf\u3002\u56e0\u6b64\uff0c\u5bf9\u4e8e\u591a\u9879\u5f0f n^2+n \uff0c\u53ea\u9700\u8981\u7740\u91cd\u8003\u8651\u5e73\u65b9\u9879 n^2 \uff0c\u4e5f\u5c31\u662f\u5728\u8003\u8651\u7684\u65f6\u5019\u53ef\u4ee5\u5ffd\u7565\u7ebf\u6027\u9879 n \u3002\u968f\u7740 n^2 \u53d8\u5f97\u975e\u5e38\u5927\uff0c\u591a\u9879\u5f0f\u7684\u503c\u6e10\u8fd1\u5730\u63a5\u8fd1\u6216\u8fd1\u4f3c\u4e8e\u5b83\u7684\u6700\u5927\u9879\u503c\uff0c\u8fd9\u79cd\u5f62\u5f0f\u7684\u5206\u6790\u6709\u65f6\u88ab\u79f0\u4e3a\u6e10\u8fd1\u5206\u6790\uff08asymptotic analysis\uff09\u3002 \u8ba1\u7b97\u4e2d\u7528\u6765\u8868\u793a\u7b97\u6cd5\u7684\u6548\u7387\u6216\u8ba1\u7b97\u590d\u6742\u5ea6\u7684\u4e00\u79cd\u65b9\u6cd5\u88ab\u79f0\u4e3a\u5927O\u8868\u793a\u6cd5\uff08big-O notation\uff09\u3002\u201cO\u201d\u4ee3\u8868\u201c\u5728\u2026\u2026\u9636\u201d\uff0c\u6307\u7684\u662f\u7b97\u6cd5\u5de5\u4f5c\u7684\u590d\u6742\u5ea6\u7684\u9636\u3002\u4f8b\u5982\uff1a \u5e38\u6570\u65f6\u95f4\uff1aO(1) \u7ebf\u6027\u65f6\u95f4\uff1aO(n) \u5e73\u65b9\u65f6\u95f4\uff1aO(n^2) \u7acb\u65b9\u65f6\u95f4\uff1aO(n^3) \u591a\u9879\u5f0f\u65f6\u95f4\uff1aO(n^k)","title":"3.2.2.\u5927O\u8868\u793a\u6cd5"},{"location":"python/DataStructure/03_TimeComplexity/#323","text":"\u6bd4\u4f8b\u5e38\u6570\uff08constant of proportionality\uff09\u5305\u542b\u5728\u5927O\u5206\u6790\u4e2d\u88ab\u5ffd\u7565\u7684\u9879\u548c\u7cfb\u6570\u3002\u6bd4\u5982\uff0c\u7ebf\u6027\u65f6\u95f4\u7b97\u6cd5\u6240\u6267\u884c\u7684\u5de5\u4f5c\u91cf\u53ef\u4ee5\u8868\u793a\u4e3a\uff1a work = 2 * size \uff0c\u5176\u4e2d\u6bd4\u4f8b\u5e38\u6570\u5c31\u662f work/size \uff0c\u4e5f\u5c31\u662f 2 \u3002\u5728\u5904\u7406\u4e2d\u5c0f\u578b\u6570\u636e\u96c6\u7684\u65f6\u5019\uff0c\u5982\u679c\u8fd9\u4e9b\u5e38\u6570\u5f88\u5927\uff0c\u90a3\u4e48\u5b83\u4eec\u4e5f\u4f1a\u5f71\u54cd\u5230\u7b97\u6cd5\u6548\u7387\u3002 \u56de\u987e\u4e0b\u9762\u7684\u4f8b\u5b50\u3002 import time problemSize = 10000000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): number = 0 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%16.3f \" % ( problemSize , Iterations )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Iterations # 10000000 10000000.000 # 20000000 20000000.000 # 40000000 40000000.000 # 80000000 80000000.000 # 160000000 160000000.000 \u5176\u4e2d\u7684\u7b97\u6cd5\u90e8\u5206\uff0c\u9664\u4e86\u5faa\u73af\u8bed\u53e5\u672c\u8eab\uff0c\u8fd8\u6709\u5176\u4ed63\u884c\u4ee3\u7801\uff0c\u5b83\u4eec\u90fd\u662f\u590d\u5236\u8bed\u53e5\uff0c\u90fd\u4f1a\u4ee5\u5e38\u6570\u65f6\u95f4\u8fd0\u884c\u3002\u5047\u8bbe\u5faa\u73af\u8bed\u53e5\u672c\u8eab\u4f1a\u6d88\u8017\u4e00\u4e2a\u65f6\u95f4\u5e38\u6570\uff0c\u90a3\u4e48\u8fd9\u4e2a\u7b97\u6cd5\u7684\u62bd\u8c61\u5de5\u4f5c\u65f6\u95f4\u5c31\u662f 3n+1 \u3002\u867d\u7136 3n+1 \u7684\u5de5\u4f5c\u91cf\u5927\u4e8e n \uff0c\u4f46\u4e8c\u8005\u5728\u8fd0\u884c\u65f6\u90fd\u662f\u7ebf\u6027\u589e\u52a0\uff0c\u6240\u4ee5\u4ed6\u4eec\u8fd0\u884c\u65f6\u90fd\u662f O(n) \u3002 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f","title":"3.2.3.\u6bd4\u4f8b\u5e38\u6570\u7684\u4f5c\u7528"},{"location":"python/DataStructure/03_TimeComplexity/#324","text":"\u5047\u8bbe\u4e0b\u9762\u7684\u8868\u8fbe\u5f0f\u90fd\u5206\u522b\u8868\u793a\u5bf9\u95ee\u9898\u89c4\u6a21\u4e3a n \u7684\u7b97\u6cd5\u6240\u9700\u8981\u6267\u884c\u7684\u64cd\u4f5c\u6570\uff0c\u8bf7\u6307\u51fa\u6bcf\u79cd\u7b97\u6cd5\u4e2d\u7684\u4e3b\u5bfc\u9879\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u5bf9\u5b83\u8fdb\u884c\u5206\u7c7b\u3002 a. 2^n - 4n + 5n b. 2n^2 + 8 c. n^3 n^2 + n \u89e3\u7b54\uff1a a. 2^n\uff0cO(n) b. n 2\uff0cO(n 2) c. n 3\uff0cO(n 3) \u5bf9\u4e8e\u89c4\u6a21\u4e3a n \u7684\u95ee\u9898\uff0c\u7b97\u6cd5A\u548cB\u5206\u522b\u4f1a\u6267\u884c n^2 \u548c (1/2)*n^2+(1/2)*n \u6761\u6307\u4ee4\u3002\u54ea\u79cd\u7b97\u6cd5\u66f4\u9ad8\u6548\uff1f\u6709\u6ca1\u6709\u4e00\u79cd\u7b97\u6cd5\u6bd4\u53e6\u4e00\u79cd\u7b97\u6cd5\u6027\u80fd\u660e\u663e\u66f4\u597d\u7684\u7279\u5b9a\u7684\u95ee\u9898\u89c4\u6a21\uff1f\u662f\u5426\u6709\u8ba9\u4e24\u79cd\u7b97\u6cd5\u90fd\u6267\u884c\u5927\u81f4\u76f8\u540c\u5de5\u4f5c\u91cf\u7684\u7279\u5b9a\u7684\u95ee\u9898\u89c4\u6a21\uff1f \u89e3\u7b54\uff1a \u5728\u6bd4\u8f83\u4e24\u79cd\u7b97\u6cd5\u7684\u6548\u7387\u65f6\uff0c\u901a\u5e38\u5173\u6ce8\u7b97\u6cd5\u6267\u884c\u65f6\u95f4\u968f\u95ee\u9898\u89c4\u6a21\u589e\u957f\u7684\u8d8b\u52bf\u3002\u9898\u76ee\u4e2d\u7684\u4e24\u79cd\u7b97\u6cd5\u7684\u6267\u884c\u6307\u4ee4\u6570\u5206\u522b\u5982\u4e0b\uff1a \u7b97\u6cd5A\uff1a\u6267\u884c n^2 \u6761\u6307\u4ee4\u3002 \u7b97\u6cd5B\uff1a\u6267\u884c (1/2)*n^2+(1/2)*n \u6761\u6307\u4ee4\u3002 \u7528\u5982\u4e0b\u4ee3\u7801\u6a21\u62df\u7b97\u6cd5A\u548c\u7b97\u6cd5B\uff0c\u53ef\u4ee5\u770b\u51fa\uff0c\u968f\u7740 n \u7684\u589e\u52a0\uff0c\u7b97\u6cd5A\u7684\u589e\u957f\u901f\u7387\u8fdc\u5927\u4e8e\u7b97\u6cd5B\u3002\u6240\u4ee5\u53ef\u4ee5\u8ba4\u4e3a\u5728 n >= 2 \u7684\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5A\u4f18\u4e8e\u7b97\u6cd5B\u3002 n = 1 print ( \" %-15s%25s \" % ( \"ProblemSize: n\" , \"A/B\" )) while n < 1000000 : n *= 10 print ( \" %-15d%25d \" % ( n , int (( n ** 2 ) / ( 1 / 2 ) * n ** 2 + ( 1 / 2 ) * n ))) # ProblemSize: n A/B # 10 20005 # 100 200000050 # 1000 2000000000500 # 10000 20000000000005000 # 100000 200000000000000065536 # 1000000 1999999999999999966445568 \u7531\u6b64\u53ef\u5f97\uff0c\u5728\u5927\u95ee\u9898\u89c4\u6a21\u4e0b\uff0c\u7b97\u6cd5B\u7684\u589e\u957f\u901f\u7387\u4f1a\u66f4\u6162\uff0c\u56e0\u4e3a (1/2)*n^2+(1/2)*n \u4e2d\u7684 (1/2)*n \u90e8\u5206\u5bf9\u4e8e\u6574\u4f53\u589e\u957f\u6765\u8bf4\u76f8\u5bf9\u8f83\u5c0f\u3002 \u4e3a\u4e86\u8ba9\u4e24\u79cd\u7b97\u6cd5\u6267\u884c\u76f8\u8fd1\u7684\u5de5\u4f5c\u91cf\uff0c\u6211\u4eec\u53ef\u4ee5\u89e3\u4e0b\u9762\u7684\u65b9\u7a0b\uff1a ( 1 / 2 ) * n ^ 2 + ( 1 / 2 ) * n = k * n ^ 2 \u5176\u4e2d k \u662f\u4e00\u4e2a\u5e38\u6570\uff0c\u8868\u793a\u4e24\u79cd\u7b97\u6cd5\u6267\u884c\u7684\u5de5\u4f5c\u91cf\u76f8\u7b49\u65f6\u7684\u95ee\u9898\u89c4\u6a21\u3002\u901a\u8fc7\u89e3\u8fd9\u4e2a\u65b9\u7a0b\uff0c\u6211\u4eec\u53ef\u4ee5\u627e\u5230\u4e00\u4e2a\u95ee\u9898\u89c4\u6a21 k \uff0c\u5728\u8fd9\u4e2a\u95ee\u9898\u89c4\u6a21\u4e0b\uff0c\u4e24\u79cd\u7b97\u6cd5\u7684\u6267\u884c\u6307\u4ee4\u6570\u76f8\u8fd1\u3002 \u7b97\u6cd5\u7684\u6548\u7387\u5206\u6790\u5e76\u4e0d\u4ec5\u4ec5\u53d6\u51b3\u4e8e\u6307\u4ee4\u6570\uff0c\u8fd8\u53ef\u80fd\u53d7\u5230\u7b97\u6cd5\u4e2d\u5e38\u6570\u56e0\u5b50\u3001\u6570\u636e\u8bbf\u95ee\u6a21\u5f0f\u3001\u5185\u5b58\u5360\u7528\u7b49\u56e0\u7d20\u7684\u5f71\u54cd\u3002\u56e0\u6b64\uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u901a\u5e38\u9700\u8981\u7efc\u5408\u8003\u8651\u591a\u4e2a\u56e0\u7d20\u6765\u786e\u5b9a\u6700\u4f18\u7684\u7b97\u6cd5\u9009\u62e9\u3002 \u5728\u4ec0\u4e48\u65f6\u5019\u5f00\u59cb n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u8868\u73b0\u66f4\u597d\uff1f \u89e3\u7b54\uff1a\u7528\u4e0b\u9762\u7684\u7b97\u6cd5\u6a21\u62df n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u6267\u884c\u5de5\u4f5c\u91cf\u3002\u4ece\u8fd0\u884c\u7ed3\u679c\u53ef\u4ee5\u770b\u51fa\uff1a n=16 \u662f\u5206\u754c\u70b9\uff0c n^4 \u7b97\u6cd5\u4e0e 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u76f8\u7b49\uff1b \u5f53 n<16 \u65f6\uff0c n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u8981\u9ad8\uff1b \u5f53 n>16 \u65f6\uff0c n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u8981\u4f4e\uff1b\u800c\u4e14 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u589e\u957f\u901f\u5ea6\u8fdc\u5927\u4e8e n^4 \u7b97\u6cd5\uff1b n = 1 print ( \" %-8s%10s%15s%10s \" % ( \"Size:n\" , \"A:n^4\" , \"B:2^n\" , \"B/A\" )) while n < 30 : n += 1 print ( \" %-8d%10d%15d%10.3f \" % ( n , int ( n ** 4 ), int ( 2 ** n ), ( 2 ** n ) / ( n ** 4 ))) # \u8fd0\u884c\u7ed3\u679c\uff1a # Size:n A:n^4 B:2^n B/A # 2 16 4 0.250 # 3 81 8 0.099 # 4 256 16 0.062 # 5 625 32 0.051 # 6 1296 64 0.049 # 7 2401 128 0.053 # 8 4096 256 0.062 # 9 6561 512 0.078 # 10 10000 1024 0.102 # 11 14641 2048 0.140 # 12 20736 4096 0.198 # 13 28561 8192 0.287 # 14 38416 16384 0.426 # 15 50625 32768 0.647 # 16 65536 65536 1.000 # 17 83521 131072 1.569 # 18 104976 262144 2.497 # 19 130321 524288 4.023 # 20 160000 1048576 6.554 # 21 194481 2097152 10.783 # 22 234256 4194304 17.905 # 23 279841 8388608 29.976 # 24 331776 16777216 50.568 # 25 390625 33554432 85.899 # 26 456976 67108864 146.854 # 27 531441 134217728 252.554 # 28 614656 268435456 436.725 # 29 707281 536870912 759.063 # 30 810000 1073741824 1325.607","title":"3.2.4.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/03_TimeComplexity/#33","text":"\u7ea6\u5b9a\uff1a \u4ee5\u5217\u8868\u4e3a\u4f8b\uff0c\u4ecb\u7ecd\u641c\u7d22\u548c\u6392\u5e8f\u7684\u7b97\u6cd5\uff1b \u9610\u91ca\u8fd9\u4e9b\u7b97\u6cd5\u7684\u8bbe\u8ba1\uff0c\u5e76\u628a\u5b83\u5b9e\u73b0\u4e3aPython\u51fd\u6570\uff1b \u51fd\u6570\u53ea\u5904\u7406\u5168\u90e8\u662f\u6574\u6570\u7684\u5217\u8868\uff0c\u4e0d\u540c\u5927\u5c0f\u7684\u5217\u8868\u5c06\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7ed9\u51fd\u6570\uff1b \u5bf9\u8fd9\u4e9b\u7b97\u6cd5\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u8fdb\u884c\u5206\u6790\uff1b","title":"3.3.\u641c\u7d22\u7b97\u6cd5"},{"location":"python/DataStructure/03_TimeComplexity/#331","text":"Python\u4e2d\u6709 min \u51fd\u6570\uff0c\u4f1a\u8fd4\u56de\u5217\u8868\u91cc\u7684\u6700\u5c0f\u503c\u6216\u6700\u5c0f\u5143\u7d20\uff0c\u4e0b\u9762\u5199\u4e00\u4e2a\u65b0\u7b97\u6cd5\uff0c\u6765\u5206\u6790 min \u51fd\u6570\u7684\u7b97\u6cd5\u590d\u6742\u5ea6\u3002 \u7b97\u6cd5\u76ee\u6807\uff1a\u5047\u5b9a\u5217\u8868\u4e0d\u4e3a\u7a7a\uff0c\u5e76\u4e14\u5143\u7d20\u662f\u6309\u7167\u4efb\u610f\u987a\u5e8f\u5b58\u653e\u5728\u5217\u8868\u91cc\u7684\uff0c\u7b97\u6cd5\u8fd4\u56de\u6700\u5c0f\u5143\u7d20\u7684\u7d22\u5f15\uff08index\uff09\u3002 \u7b97\u6cd5\u89e3\u6790\uff1a \u9996\u5148\u628a\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u4f5c\u4e3a\u5b58\u653e\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\uff1b \u7136\u540e\u5411\u53f3\u4fa7\u641c\u7d22\u66f4\u5c0f\u7684\u5143\u7d20\uff1b \u5982\u679c\u627e\u5230\uff0c\u90a3\u4e48\u628a\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\u91cd\u7f6e\u4e3a\u5f53\u524d\u4f4d\u7f6e\uff1b \u5f53\u7b97\u6cd5\u5230\u8fbe\u5217\u8868\u672b\u5c3e\u65f6\uff0c\u5b83\u5c06\u8fd4\u56de\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\u3002 \u7b97\u6cd5\u5b9e\u73b0\uff1a def indexOfMin ( lyst ): \"\"\"\u8fd4\u56de\u6700\u5c0f\u5143\u7d20\u7684\u7d22\u5f15\uff0c\u76f8\u540c\u6700\u5c0f\u5143\u7d20\u8fd4\u56de\u7b2c\u4e00\u4e2a\u7d22\u5f15\"\"\" # \u7b97\u6cd5\u5f00\u59cb minIndex = 0 currentIndex = 1 while currentIndex < len ( lyst ): if lyst [ currentIndex ] < lyst [ minIndex ]: # \u6539\u6210<=\uff0c\u76f8\u540c\u6700\u5c0f\u5143\u7d20\u5219\u8fd4\u56de\u6700\u540e\u4e00\u4e2a\u7d22\u5f15 minIndex = currentIndex currentIndex += 1 return minIndex # \u7b97\u6cd5\u7ed3\u675f def main (): myList = [ 2 , 20 , 5 , 0 , 1 , 0 , 9 ] minIndex = indexOfMin ( myList ) print ( minIndex , myList [ minIndex ]) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # 3 0 # \u5982\u679c\u6539\u6210\u6539\u6210yst[currentIndex] <= lyst[minIndex]\uff0c\u5219\u76f8\u540c\u6700\u5c0f\u5143\u7d20\u5219\u8fd4\u56de\u6700\u540e\u4e00\u4e2a\u7d22\u5f15 # 5 0 \u65e0\u8bba\u5217\u8868\u7684\u5927\u5c0f\u5982\u4f55\uff0c\u5faa\u73af\u5916\u76843\u6761\u6307\u4ee4\uff082\u6761\u8d4b\u503c\u8bed\u53e5\uff0c\u4e00\u6761while\u8bed\u53e5\u672c\u8eab\uff09\u90fd\u4f1a\u6267\u884c\u76f8\u540c\u7684\u6b21\u6570\uff0c\u53ef\u4ee5\u5ffd\u7565\u5b83\u4eec\u90fd\u5f71\u54cd\u3002 \u5faa\u73af\u91cc\u8fd8\u67093\u6761\u6307\u4ee4\uff0c\u5176\u4e2d if \u8bed\u53e5\u5185\u7684\u6bd4\u8f83 lyst[currentIndex] < lyst[minIndex] \u548c currentIndex += 1 \u7684\u81ea\u589e\uff0c\u4f1a\u5728\u6bcf\u6b21\u5faa\u73af\u65f6\u90fd\u6267\u884c\uff0c\u4e14\u6ca1\u6709\u5176\u5b83\u5d4c\u5957\u6216\u9690\u85cf\u7684\u5faa\u73af\u3002 if \u8bed\u53e5\u4e2d\u7684\u6bd4\u8f83\u64cd\u4f5c\u5b9e\u73b0\u4e86\u8bbf\u95ee\u5217\u8868\u91cc\u7684\u6bcf\u4e2a\u5143\u7d20\uff0c\u4ece\u800c\u80fd\u591f\u627e\u5230\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\u3002 \u56e0\u6b64\uff0c\u8fd9\u4e2a\u7b97\u6cd5\u5fc5\u987b\u5bf9\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\u8fdb\u884c n-1 \u6b21\u6bd4\u8f83\uff0c\u5373\uff0c\u5b83\u7684\u590d\u6742\u5ea6\u4e3aO(n)\u3002","title":"3.3.1.\u6700\u5c0f\u503c\u641c\u7d22"},{"location":"python/DataStructure/03_TimeComplexity/#332","text":"Python\u7684 in \u8fd0\u7b97\u7b26\u5728list\u7c7b\u91cc\u88ab\u5b9e\u73b0\u4e3a\u53eb\u4f5c __contains__ \u7684\u65b9\u6cd5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u5728\u4efb\u610f\u7684\u5143\u7d20\u5217\u8868\u91cc\u641c\u7d22\u7279\u5b9a\u7684\u5143\u7d20\uff0c\u5373\u76ee\u6807\u5143\u7d20\uff08target item\uff09\u3002 \u5728\u5217\u8868\u91cc\uff0c\u627e\u5230\u76ee\u6807\u5143\u7d20\u7684\u552f\u4e00\u65b9\u6cd5\u662f\u4ece\u4f4d\u4e8e\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u5f00\u59cb\uff0c\u5e76\u628a\u5b83\u548c\u76ee\u6807\u5143\u7d20\u8fdb\u884c\u6bd4\u8f83\u3002\u5982\u679c\u4e24\u4e2a\u5143\u7d20\u76f8\u7b49\uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u8fd4\u56de True \uff1b\u5426\u5219\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u5c06\u79fb\u52a8\u5230\u4e0b\u4e00\u4e2a\u4f4d\u7f6e\uff0c\u5e76\u628a\u5b83\u548c\u76ee\u6807\u5143\u7d20\u8fdb\u884c\u6bd4\u8f83\u3002\u5982\u679c\u8fd9\u4e2a\u65b9\u6cd5\u5230\u4e86\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u4ecd\u7136\u627e\u4e0d\u5230\u76ee\u6807\uff0c\u90a3\u4e48\u8fd4\u56de False \u3002\u8fd9\u79cd\u641c\u7d22\u79f0\u4e3a\u987a\u5e8f\u641c\u7d22\uff08sequential search\uff09\u6216\u7ebf\u6027\u641c\u7d22\uff08linear search\uff09\u3002 \u4e0b\u9762\u662f\u987a\u5e8f\u641c\u7d22\u51fd\u6570\u7684\u5b9e\u73b0\u3002\u82e5\u987a\u5e8f\u641c\u7d22\u7b97\u6cd5\u5728\u5217\u8868\u5f00\u5934\u5c31\u627e\u5230\u76ee\u6807\u5143\u7d20\uff0c\u90a3\u4e48\u8fd9\u65f6\u7684\u5de5\u4f5c\u91cf\u660e\u663e\u4f1a\u6bd4\u5728\u5217\u8868\u672b\u5c3e\u627e\u5230\u7684\u5de5\u4f5c\u91cf\u8981\u5c11\u3002 def sequentialSearch ( target , lyst ): \"\"\"\u627e\u5230\u76ee\u6807\u5143\u7d20\u65f6\u8fd4\u56de\u5143\u7d20\u7684\u7d22\u5f15, \u5426\u5219\u8fd4\u56de-1\"\"\" position = 0 while position < len ( lyst ): if target == lyst [ position ]: return position position += 1 return - 1 def main (): myList = [ 2 , 20 , 5 , 0 , 1 , 0 , 9 ] locatedIndex = sequentialSearch ( 9 , myList ) print ( locatedIndex , myList [ locatedIndex ]) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # 6 9","title":"3.3.2.\u987a\u5e8f\u641c\u7d22\u5217\u8868"},{"location":"python/DataStructure/03_TimeComplexity/#333","text":"\u4e00\u822c\u6765\u8bf4\uff0c\u91cd\u70b9\u5173\u6ce8\u5728\u5e73\u5747\u60c5\u51b5\u548c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\uff0c\u4e0d\u4f1a\u7279\u522b\u5173\u6ce8\u6700\u597d\u60c5\u51b5\u3002 \u5bf9\u987a\u5e8f\u641c\u7d22\u7684\u5206\u6790\u9700\u8981\u8003\u8651\u4e0b\u97623\u79cd\u60c5\u51b5\u3002 \u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u76ee\u6807\u5143\u7d20\u4f4d\u4e8e\u5217\u8868\u7684\u672b\u5c3e\u6216\u8005\u6839\u672c\u5c31\u4e0d\u5728\u5217\u8868\u91cc\u3002\u8fd9\u65f6\uff0c\u8fd9\u4e2a\u7b97\u6cd5\u5c31\u5fc5\u987b\u8bbf\u95ee\u6bcf\u4e00\u4e2a\u5143\u7d20\uff0c\u5bf9\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\u9700\u8981\u6267\u884c n \u6b21\u8fed\u4ee3\u3002\u56e0\u6b64\uff0c\u987a\u5e8f\u641c\u7d22\u7684\u6700\u574f\u60c5\u51b5\u7684\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u53ea\u9700\u8981O(1)\u7684\u590d\u6742\u5ea6\uff0c\u56e0\u4e3a\u8fd9\u4e2a\u7b97\u6cd5\u5728\u4e00\u6b21\u8fed\u4ee3\u4e4b\u540e\u5c31\u4f1a\u5728\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u627e\u5230\u76ee\u6807\u5143\u7d20\u3002 \u8981\u786e\u5b9a\u5e73\u5747\u60c5\u51b5\uff0c\u5c31\u9700\u8981\u628a\u6bcf\u4e2a\u53ef\u80fd\u4f4d\u7f6e\u627e\u5230\u76ee\u6807\u6240\u9700\u8981\u7684\u8fed\u4ee3\u6b21\u6570\u76f8\u52a0\uff0c\u7136\u540e\u518d\u5c06\u5b83\u4eec\u7684\u603b\u548c\u9664\u4ee5 n \u3002\u56e0\u6b64\uff0c\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u4f1a\u6267\u884c (n + n\u22121 + n\u22122+ ... +1)/n \u6216 (n+1)/2 \u6b21\u8fed\u4ee3\u3002\u5bf9\u4e8e\u975e\u5e38\u5927\u7684 n \u6765\u8bf4\uff0c\u5e38\u6570\u7cfb\u65702\u662f\u53ef\u4ee5\u5ffd\u7565\u7684\uff0c\u56e0\u6b64\uff0c\u5e73\u5747\u60c5\u51b5\u7684\u590d\u6742\u5ea6\u4ecd\u7136\u662fO(2)\u3002 \u7ed3\u8bba\uff1a\u6700\u597d\u60c5\u51b5\u4e0b\u987a\u5e8f\u641c\u7d22\u7684\u6027\u80fd\u548c\u5176\u4ed6\u4e24\u79cd\u60c5\u51b5\u6bd4\u8d77\u6765\u5c0f\u5f88\u591a\uff0c\u800c\u5176\u4ed6\u4e24\u79cd\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u662f\u5dee\u4e0d\u591a\u7684\u3002","title":"3.3.3.\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd"},{"location":"python/DataStructure/03_TimeComplexity/#334","text":"\u5728\u6570\u636e\u65e0\u5e8f\u7684\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528\u987a\u5e8f\u641c\u7d22\u6765\u627e\u5230\u76ee\u6807\u5143\u7d20\u3002 \u5728\u6570\u636e\u6709\u5e8f\u7684\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528\u4e8c\u5206\u641c\u7d22\u6765\u627e\u5230\u76ee\u6807\u5143\u7d20\u3002 Python\u4e2d\u5b9e\u73b0\u4e8c\u5206\u641c\u7d22\u7684\u601d\u8def\uff1a \u5047\u8bbe\u5217\u8868\u91cc\u7684\u5143\u7d20\u90fd\u4ee5\u5347\u5e8f\u6392\u5e8f\u3002 \u641c\u7d22\u7b97\u6cd5\u9996\u5148\u5230\u5217\u8868\u7684\u4e2d\u95f4\u4f4d\u7f6e\uff0c\u5e76\u628a\u8fd9\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u4e0e\u76ee\u6807\u5143\u7d20\u8fdb\u884c\u6bd4\u8f83\uff1b \u5982\u679c\u5339\u914d\uff0c\u90a3\u4e48\u7b97\u6cd5\u5c31\u8fd4\u56de\u5f53\u524d\u4f4d\u7f6e\u3002\u5982\u679c\u76ee\u6807\u5143\u7d20\u5c0f\u4e8e\u5f53\u524d\u5143\u7d20\uff0c\u90a3\u4e48\u7b97\u6cd5\u5c06\u4f1a\u641c\u7d22\u4e2d\u95f4\u4f4d\u7f6e\u4e4b\u524d\u7684\u90e8\u5206\uff1b \u5982\u679c\u76ee\u6807\u5143\u7d20\u5927\u4e8e\u5f53\u524d\u5143\u7d20\uff0c\u5219\u641c\u7d22\u4e2d\u95f4\u4f4d\u7f6e\u4e4b\u540e\u7684\u90e8\u5206\u3002 \u5728\u627e\u5230\u4e86\u76ee\u6807\u5143\u7d20\u6216\u8005\u5f53\u524d\u5f00\u59cb\u4f4d\u7f6e\u5927\u4e8e\u5f53\u524d\u7ed3\u675f\u4f4d\u7f6e\u65f6\uff0c\u505c\u6b62\u641c\u7d22\u8fc7\u7a0b\u3002 \u4e0b\u9762\u662f\u4e8c\u5206\u641c\u7d22\u51fd\u6570\u7684\u4ee3\u7801\u3002\u4ee5\u5217\u8868 [2, 20, 5, 0, 1, 0, 9] \u4e3a\u4f8b\uff1a \u6392\u5e8f\u540e\u7684\u5217\u8868\u4e3a [0, 0, 1, 2, 5, 9, 20] \uff1b \u6392\u5e8f\u540e\u5217\u8868\u957f\u5ea6\u662f7\uff0c\u6240\u4ee5\u521d\u59cbmidpoint=3\uff0c\u5bf9\u5e94\u5217\u8868\u503c\u662f2\uff1b def binarySearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 while left <= right : midpoint = ( left + right ) // 2 if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 return - 1 def main (): myList = [ 2 , 20 , 5 , 0 , 1 , 0 , 9 ] sortedList = sorted ( myList ) # \u5982\u679c\u4f7f\u7528myList.sort()\uff0c\u5219\u4f1a\u4fee\u6539myList\u672c\u8eab locatedIndex = binarySearch ( 5 , sortedList ) print ( sortedList ) print ( locatedIndex , sortedList [ locatedIndex ]) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # [0, 0, 1, 2, 5, 9, 20] # 4 5 # \u5982\u679c\u6267\u884cbinarySearch(0, sortedList)\uff0c\u5219\u4f1a\u8fd4\u56de\u7b2c\u4e8c\u4e2a0\u7684\u7d22\u5f15 # [0, 0, 1, 2, 5, 9, 20] # 1 0 \u4e0a\u9762\u4e8c\u5206\u6cd5\u7b97\u6cd5\u590d\u6742\u5ea6\u5206\u6790\uff1a \u7b97\u6cd5\u91cc\u53ea\u6709\u4e00\u4e2a\u5faa\u73af\uff0c\u5e76\u4e14\u6ca1\u6709\u5d4c\u5957\u6216\u9690\u85cf\u7684\u5faa\u73af\u3002\u5982\u679c\u76ee\u6807\u4e0d\u5728\u5217\u8868\u91cc\uff0c\u5c31\u4f1a\u5f97\u5230\u6700\u574f\u60c5\u51b5\uff0c\u5373\u904d\u5386\u5217\u8868\u7684\u4e00\u534a\uff0c\u5373\u5faa\u73af\u5217\u8868\u5927\u5c0f\u4e0d\u65ad\u9664\u4ee52\u76f4\u81f3\u5546\u4e3a1\u7684\u6b21\u6570\u3002 \u5bf9\u4e8e\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\u6765\u8bf4\uff0c\u4e5f\u5c31\u662f\u4f60\u9700\u8981\u6267\u884c n/2/2/.../2 \u6b21\uff0c\u76f4\u5230\u7ed3\u679c\u4e3a1\u3002\u5047\u8bbe k \u662f n \u53ef\u4ee5\u9664\u4ee52\u7684\u6b21\u6570\uff0c\u90a3\u4e48\u6c42\u89e3 k \u4f1a\u6709 n/(2^k)=1 \uff0c\u5373 n=2^k \uff0c\u5373 k=log(n,2) \u3002\u56e0\u6b64\uff0c\u4e8c\u5206\u641c\u7d22\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u590d\u6742\u5ea6\u4e3aO(log(n,2))\u3002","title":"3.3.4.\u57fa\u4e8e\u6709\u5e8f\u5217\u8868\u7684\u4e8c\u5206\u641c\u7d22"},{"location":"python/DataStructure/03_TimeComplexity/#335","text":"\u4e8c\u5206\u641c\u7d22\u548c\u6700\u5c0f\u503c\u641c\u7d22\u90fd\u6709\u4e00\u4e2a\u5047\u8bbe\uff0c\u90a3\u5c31\u662f\u201c\u5217\u8868\u91cc\u7684\u5143\u7d20\u5f7c\u6b64\u4e4b\u95f4\u662f\u53ef\u4ee5\u6bd4\u8f83\u7684\u201d\u3002\u5373\uff0c\u8fd9\u4e9b\u5143\u7d20\u5c5e\u4e8e\u540c\u4e00\u4e2a\u7c7b\u578b\uff0c\u5373\uff0c\u53ef\u4ee5\u4f7f\u7528\u6bd4\u8f83\u8fd0\u7b97\u7b26 == \u3001 < \u548c > \u3002 Python\u5185\u7f6e\u7684\u7c7b\u578b\u5bf9\u8c61\uff0c\u5982\u6570\u5b57\u3001\u5b57\u7b26\u4e32\u548c\u5217\u8868\uff0c\u90fd\u652f\u6301\u6bd4\u8f83\u8fd0\u7b97\u7b26\u3002 \u4e3a\u4e86\u80fd\u591f\u8ba9\u7b97\u6cd5\u5bf9\u65b0\u7684\u7c7b\u5bf9\u8c61\u4f7f\u7528\u6bd4\u8f83\u8fd0\u7b97\u7b26 == \u3001 < \u548c > \uff0c\u5e94\u8be5\u5728\u8fd9\u4e2a\u7c7b\u91cc\u5b9a\u4e49 __eq__ \u3001 __lt__ \u548c __gt__ \u65b9\u6cd5\u3002\u5728\u5b9a\u4e49\u4e86\u8fd9\u4e9b\u65b9\u6cd5\u4e4b\u540e\uff0c\u5176\u4ed6\u6bd4\u8f83\u8fd0\u7b97\u7b26\u7684\u65b9\u6cd5\u5c06\u81ea\u52a8\u751f\u6210\u3002 \u4f8b\u5982\uff0c __lt__ \u7684\u5b9a\u4e49\u5982\u4e0b\uff0c\u5982\u679c self \u5c0f\u4e8e other \uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u5c06\u8fd4\u56de True \uff1b\u5426\u5219\uff0c\u8fd4\u56de False \u3002 __lt__ \u65b9\u6cd5\u4f1a\u4e3a\u4e24\u4e2a\u8d26\u6237\u5bf9\u8c61\u7684 name \u5b57\u6bb5\u8c03\u7528\u8fd0\u7b97\u7b26 < \u3002 \u540d\u79f0\u5b57\u6bb5\u662f\u5b57\u7b26\u4e32\uff0c\u5b57\u7b26\u4e32\u7c7b\u578b\u5df2\u7ecf\u5305\u542b\u5728 __lt__ \u65b9\u6cd5\u91cc\u3002 \u5728\u4f7f\u7528\u8fd0\u7b97\u7b26 < \u65f6\uff0cPython\u4f1a\u81ea\u52a8\u8fd0\u884c\u5b57\u7b26\u4e32\u7684 __lt__ \u65b9\u6cd5\uff0c\u8fd9\u4e0e\u8c03\u7528 str \u51fd\u6570\u65f6\u81ea\u52a8\u8fd0\u884c __str__ \u65b9\u6cd5\u662f\u7c7b\u4f3c\u7684\u3002 def __lt__ ( self , other ): \u793a\u4f8b\uff1a\u8fd4\u56de\u50a8\u84c4\u8d26\u6237\u7684\u6240\u6709\u4eba\u540d\u5b57\u3001PIN\u7801\u3001\u4f59\u989d\u3002 class SavingsAccount ( object ): \"\"\"\u8fd4\u56de\u50a8\u84c4\u8d26\u6237\u7684\u6240\u6709\u4eba\u540d\u5b57\u3001PIN\u7801\u3001\u4f59\u989d\"\"\" def __init__ ( self , name , pin , balance = 0.0 ): self . name = name self . pin = pin self . balance = balance def __lt__ ( self , other ): return self . name < other . name # Other methods, including __eq__ def main (): s1 = SavingsAccount ( \"Ken\" , \"1001\" , 0 ) s2 = SavingsAccount ( \"Bill\" , \"1001\" , 30 ) s3 = SavingsAccount ( \"Ken\" , \"1000\" , 0 ) s4 = s1 print ( \"s1 < s2: \" , s1 < s2 ) print ( \"s2 < s1: \" , s2 < s1 ) print ( \"s2 > s1: \" , s2 > s1 ) print ( \"s2 == s1: \" , s2 == s1 ) print ( \"s1 == s3: \" , s1 == s3 ) print ( \"s1 == s4: \" , s1 == s4 ) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # s1 < s2: False # s2 < s1: True # s2 > s1: False # s2 == s1: False # s1 == s3: False # s1 == s4: True \u63d0\u793a\uff1a\u5728Python\u4e2d\uff0c\u9ed8\u8ba4\u662f\u6309\u7167ASCII\u7684\u5927\u5c0f\u6bd4\u8f83\u5b57\u7b26\u4e32\u7684\uff0c\u5373\u4ece\u5b57\u7b26\u4e32\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\u8fdb\u884c\u6bd4\u8f83\uff0c\u5982\u679c\u76f8\u7b49\uff0c\u5219\u7ee7\u7eed\u6bd4\u8f83\u4e0b\u4e00\u4e2a\u5b57\u7b26\uff0c\u76f4\u5230\u5206\u51fa\u5927\u5c0f\uff0c\u6216\u8005\u8fd8\u6ca1\u5206\u51fa\u5927\u5c0f\uff0c\u6709\u4e00\u4e2a\u5b57\u7b26\u4e32\u5df2\u7ecf\u5230\u5934\u4e86\uff0c\u90a3\u4e48\u8f83\u957f\u7684\u90a3\u4e00\u4e2a\u5b57\u7b26\u4e32\u5927\u3002","title":"3.3.5.\u6bd4\u8f83\u6570\u636e\u5143\u7d20"},{"location":"python/DataStructure/03_TimeComplexity/#336","text":"\u5047\u8bbe\u4e00\u4e2a\u5217\u8868\u5728\u7d22\u5f150\uff5e9\u7684\u4f4d\u7f6e\u5904\u5305\u542b\u503c20\u300144\u300148\u300155\u300162\u300166\u300174\u300188\u300193\u300199\uff0c\u8bf7\u5728\u7528\u4e8c\u5206\u641c\u7d22\u67e5\u627e\u76ee\u6807\u5143\u7d2090\u7684\u65f6\u5019\uff0c\u5bf9\u53d8\u91cfleft\u3001right\u548cmidpoint\u7684\u503c\u8fdb\u884c\u8ddf\u8e2a\u3002\u6539\u53d8\u76ee\u6807\u5143\u7d20\u4e3a44\uff0c\u5e76\u91cd\u590d\u8fd9\u4e2a\u6b65\u9aa4\u3002 \u89e3\u7b54\uff1a \u4e0b\u9762\u662f\u4ee3\u7801\u548c\u8ddf\u8e2a\u7ed3\u679c\u3002 def binarySearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 print ( \" %5s%10s%10s \" % ( \"left\" , \"midpoint\" , \"right\" )) while left <= right : midpoint = ( left + right ) // 2 print ( \" %5s%10s%10s \" % ( left , midpoint , right )) if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 return - 1 def main (): myList = [ 20 , 44 , 48 , 55 , 62 , 66 , 74 , 88 , 93 , 99 ] sortedList = sorted ( myList ) locatedIndex = binarySearch ( 44 , sortedList ) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # Target = 90 # left midpoint right # 0 4 9 # 5 7 9 # 8 8 9 # # Target = 44 # left midpoint right # 0 4 9 # 0 1 3 \u901a\u5e38\u6765\u8bf4\uff0c\u67e5\u627e\u7535\u8bdd\u7c3f\u4e2d\u6761\u76ee\u7684\u65b9\u6cd5\u4e0e\u4e8c\u5206\u641c\u7d22\u5e76\u4e0d\u5b8c\u5168\u76f8\u540c\uff0c\u56e0\u4e3a\u4f7f\u7528\u7535\u8bdd\u7c3f\u7684\u65f6\u5019\uff0c\u5e76\u4e0d\u4f1a\u6bcf\u6b21\u90fd\u7ffb\u5230\u88ab\u641c\u7d22\u7684\u5b50\u5217\u8868\u7684\u4e2d\u70b9\u3002\u4e00\u822c\u6765\u8bf4\uff0c\u53ef\u4ee5\u6839\u636e\u8fd9\u4e2a\u4eba\u7684\u59d3\u6c0f\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd\u987a\u5e8f\u6765\u4f30\u7b97\u76ee\u6807\u53ef\u80fd\u4f1a\u5728\u7684\u4f4d\u7f6e\u3002\u4f8b\u5982\uff0c\u5f53\u67e5\u627e\u201cSmith\u201d\u7684\u7535\u8bdd\u65f6\uff0c\u4f60\u4f1a\u9996\u5148\u67e5\u770b\u7535\u8bdd\u7c3f\u4e0b\u534a\u90e8\u5206\u7684\u4e2d\u95f4\uff0c\u800c\u4e0d\u662f\u6574\u4e2a\u7535\u8bdd\u7c3f\u7684\u4e2d\u95f4\u3002\u8bf7\u5bf9\u4e8c\u5206\u641c\u7d22\u7b97\u6cd5\u5c1d\u8bd5\u8fdb\u884c\u4fee\u6539\uff0c\u4ece\u800c\u53ef\u4ee5\u5728\u5904\u7406\u540d\u79f0\u5217\u8868\u7684\u65f6\u5019\u6a21\u62df\u8fd9\u4e2a\u7b56\u7565\u3002\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u4e0e\u6807\u51c6\u7684\u4e8c\u5206\u641c\u7d22\u76f8\u6bd4\u8f83\u4f1a\u66f4\u597d\u5417\uff1f \u89e3\u7b54\uff1a\u4e0b\u9762\u662f\u4ee3\u7801\u548c\u8ffd\u8e2a\u7ed3\u679c\u3002\u901a\u8fc7\u5bf9\u6bd4\u4e0d\u540c\u6743\u91cd\u5355\u8bcd\u5230\u7684\u641c\u7d22\uff0c\u53ef\u4ee5\u53d1\u73b0\u6743\u91cd\u4e8c\u5206\u6cd5\u7684\u6548\u7387\u82e5\u8981\u4f18\u4e8e\u4f20\u7edf\u4e8c\u5206\u6cd5\uff0c\u662f\u9700\u8981\u6ee1\u8db3\u4e00\u5b9a\u7684\u6761\u4ef6\u7684\u3002 \u5728\u641c\u7d22\u7684\u7b2c\u4e00\u8f6e\u4e2d\uff0c\u4e2d\u95f4\u4f4d\u7f6e\u5c06\u53d6\u51b3\u4e8e\u5217\u8868\u7684\u5927\u5c0f\u548c\u76ee\u6807\u540d\u5b57\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd\u7684\u987a\u5e8f\u503c\u3002\u56e0\u6b64\uff0c\u7b2c\u4e00\u8f6e\u641c\u7d22\u5c06\u6d88\u9664\u6bd4\u4ee5\u524d\u66f4\u591a\u7684\u5143\u7d20\uff0c\u5e76\u4e14\u5982\u679c\u9700\u8981\u5176\u4ed6\u8f6e\u641c\u7d22\uff0c\u5b83\u4eec\u7684\u641c\u7d22\u7a7a\u95f4\u4e5f\u4f1a\u66f4\u5c0f\u3002\u7136\u800c\uff0c\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u4fee\u6539\u540e\u7684\u7b97\u6cd5\u4ecd\u7136\u6bd4O(1)\u66f4\u63a5\u8fd1O(log n)\u3002 def binarySearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 print ( \" %5s%10s%10s \" % ( \"left\" , \"midpoint\" , \"right\" )) while left <= right : midpoint = ( left + right ) // 2 print ( \" %5s%10s%10s \" % ( left , midpoint , right )) if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 return - 1 def letter_position ( myLetter ): letter = myLetter . lower () # \u8f6c\u6210\u5c0f\u5199\u5b57\u6bcd alphabet = \"abcdefghijklmnopqrstuvwxyz\" if letter in alphabet : return alphabet . index ( letter ) + 1 # \u4f4d\u7f6e\u63091\uff5e26\u8ba1\u7b97 else : return None # \u975e\u5b57\u6bcd def dictSearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 # \u9996\u5b57\u6bcd\u5728\u5b57\u6bcd\u8868\u4e2d\u7684\u767e\u5206\u4f4d letter_position_range = letter_position ( target [ 0 ]) * 100 // 26 # \u6309\u7167\u6240\u5f97\u7684\u9996\u5b57\u6bcd\u5728\u5b57\u6bcd\u8868\u4e2d\u7684\u767e\u5206\u4f4d\uff0c\u4f5c\u4e3a\u7ed9\u5b9a\u5b57\u4e32\u4e2d\u8bbe\u5b9a\u641c\u7d22\u8d77\u59cb\u767e\u5206\u4f4d midpoint = letter_position_range * ( len ( sortedLyst ) - 1 ) // 100 print ( \" %5s%10s%10s \" % ( \"left\" , \"midpoint\" , \"right\" )) while left <= right : print ( \" %5s%10s%10s \" % ( left , midpoint , right )) if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 midpoint = ( left + right ) // 2 return - 1 def main (): myList = [ \"Bob\" , \"Charlie\" , \"Eva\" , \"Alice\" , \"Grace\" , \"David\" , \"Smith\" , \"Frank\" , \"Zoe\" , \"Jack\" ] sortedList = sorted ( myList ) print ( sortedList ) print ( \"=====call binarySearch=====\" ) locatedIndex = binarySearch ( \"Alice\" , sortedList ) print ( \"Found\" , sortedList [ locatedIndex ], \"in position\" , locatedIndex ) print ( \"=====call dictSearch=====\" ) locatedIndex = dictSearch ( \"Alice\" , sortedList ) print ( \"Found\" , sortedList [ locatedIndex ], \"in position\" , locatedIndex ) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # \u641c\u7d22Alice # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 0 1 3 # 0 0 0 # Found Alice in position 0 # =====call dictSearch===== # left midpoint right # 0 0 9 # Found Alice in position 0 # \u641c\u7d22Bob # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 0 1 3 # Found Bob in position 1 # =====call dictSearch===== # left midpoint right # 0 0 9 # 1 5 9 # 1 2 4 # 1 1 1 # Found Bob in position 1 # \u641c\u7d22Smith # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 5 7 9 # 8 8 9 # Found Smith in position 8 # =====call dictSearch===== # left midpoint right # 0 6 9 # 7 8 9 # Found Smith in position 8 # \u641c\u7d22Zoe # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 5 7 9 # 8 8 9 # 9 9 9 # Found Zoe in position 9 # =====call dictSearch===== # left midpoint right # 0 9 9 # Found Zoe in position 9","title":"3.3.6.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/03_TimeComplexity/#34","text":"\u4e0b\u9762\u662fswap\u51fd\u6570\u7684\u4f8b\u5b50\uff0c\u5b9e\u73b0\u4e86\uff1a \u5047\u8bbe\u90fd\u5728\u6574\u6570\u5217\u8868\u4e0a\u8fd0\u884c\uff1b \u4ea4\u6362\u5217\u8868\u4e2d\u4e24\u4e2a\u5143\u7d20\u7684\u4f4d\u7f6e\uff1b def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( myList ) swap ( myList , 3 , 5 ) print ( myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # [9, 4, 2, 7, 6, 8, 1] # [9, 4, 2, 8, 6, 7, 1]","title":"3.4.\u57fa\u672c\u7684\u6392\u5e8f\u7b97\u6cd5"},{"location":"python/DataStructure/03_TimeComplexity/#341","text":"\u9009\u62e9\u6392\u5e8f\uff08selection sort\uff09\uff1a\uff08\u4ee5\u5217\u8868\u4e3a\u4f8b\uff09 \u5728\u4e00\u4e2a\u957f\u5ea6\u4e3a N \u7684\u65e0\u5e8f\u5217\u8868\u4e2d\uff0c\u7b2c\u4e00\u6b21\u904d\u5386 n-1 \u4e2a\u6570\u627e\u5230\u6700\u5c0f\u7684\u548c\u7b2c\u4e00\u4e2a\u6570\u4ea4\u6362\u3002 \u7b2c\u4e8c\u6b21\u4ece\u4e0b\u4e00\u4e2a\u6570\u5f00\u59cb\u904d\u5386 n-2 \u4e2a\u6570\uff0c\u627e\u5230\u6700\u5c0f\u7684\u6570\u548c\u7b2c\u4e8c\u4e2a\u6570\u4ea4\u6362\u3002 \u91cd\u590d\u4ee5\u4e0a\u64cd\u4f5c\u76f4\u5230\u7b2c n-1 \u6b21\u904d\u5386\u6700\u5c0f\u7684\u6570\u548c\u7b2c n-1 \u4e2a\u6570\u4ea4\u6362\uff0c\u6392\u5e8f\u5b8c\u6210\u3002 \u8fd9\u4e2a\u7b97\u6cd5\u5728\u6bcf\u6b21\u901a\u8fc7\u4e3b\u5faa\u73af\u65f6\uff0c\u90fd\u4f1a\u9009\u62e9\u8981\u79fb\u52a8\u7684\u90a3\u4e00\u4e2a\u5143\u7d20\u3002 \u7b97\u6cd5\u590d\u6742\u5ea6\uff1a \u7b2c1\u6b21\u6267\u884c\u5916\u90e8\u5faa\u73af\u65f6\uff0c\u5185\u90e8\u5faa\u73af\u4f1a\u6267\u884cn-1\u6b21\uff1b \u7b2c2\u6b21\u6267\u884c\u5916\u90e8\u5faa\u73af\u65f6\uff0c\u5185\u90e8\u5faa\u73af\u4f1a\u6267\u884cn-2\u6b21\uff1b \u6700\u540e\u4e00\u6b21\u6267\u884c\u5916\u90e8\u5faa\u73af\u65f6\uff0c\u5185\u90e8\u5faa\u73af\u4f1a\u6267\u884c1\u6b21\uff1b \u6240\u4ee5\uff0c\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\uff0c\u4e00\u5171\u9700\u8981\u7684\u6bd4\u8f83\u6b21\u6570\u662f (n-1)+(n-2)+...+1 \uff0c\u5316\u7b80\u4e3a n*(n-1)/2 \uff0c\u5373 (1/2)*n^2+(1/2)*n \u3002\u5f53 n \u6bd4\u8f83\u5927\u65f6\uff0c\u53ef\u4ee5\u9009\u62e9\u6700\u9ad8\u6b21\u7684\u9879\u5e76\u5ffd\u7565\u7cfb\u6570\uff0c\u56e0\u6b64\u5728\u6240\u6709\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u7684\u590d\u6742\u5ea6\u90fd\u662fO(n^2)\u3002 \u5bf9\u4e8e\u5927\u578b\u6570\u636e\u96c6\u6765\u8bf4\uff0c\u4ea4\u6362\u5143\u7d20\u7684\u6210\u672c\u53ef\u80fd\u4f1a\u5f88\u9ad8\u3002\u56e0\u4e3a\u8fd9\u4e2a\u7b97\u6cd5\u53ea\u4f1a\u5728\u5916\u90e8\u5faa\u73af\u91cc\u5bf9\u6570\u636e\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\uff0c\u6240\u4ee5\u5728\u6700\u574f\u60c5\u51b5\u548c\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u7684\u989d\u5916\u6210\u672c\u662f\u7ebf\u6027\u7684\u3002 \u7b97\u6cd5\u4ee3\u7801\uff1a def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 minIndex = i # \u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , minIndex , i ) i += 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9]","title":"3.4.1.\u9009\u62e9\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#342","text":"\u5192\u6ce1\u6392\u5e8f\uff08Bubble Sort\uff09\uff1a \u6bd4\u8f83\u76f8\u90bb\u4e24\u4e2a\u6570\u636e\u5982\u679c\u3002\u7b2c\u4e00\u4e2a\u6bd4\u7b2c\u4e8c\u4e2a\u5927\uff0c\u5c31\u4ea4\u6362\u4e24\u4e2a\u6570\uff1b \u5bf9\u6bcf\u4e00\u4e2a\u76f8\u90bb\u7684\u6570\u505a\u540c\u68371\u7684\u5de5\u4f5c\uff0c\u8fd9\u6837\u4ece\u5f00\u59cb\u4e00\u961f\u5230\u7ed3\u5c3e\u4e00\u961f\u5728\u6700\u540e\u7684\u6570\u5c31\u662f\u6700\u5927\u7684\u6570\u3002 \u9488\u5bf9\u6240\u6709\u5143\u7d20\u4e0a\u9762\u7684\u64cd\u4f5c\uff0c\u9664\u4e86\u6700\u540e\u4e00\u4e2a\u3002 \u91cd\u590d1~3\u6b65\u9aa4\uff0c\u76f4\u81f3\u5b8c\u6210\u3002 \u7b97\u6cd5\u590d\u6742\u5ea6\uff1a \u5192\u6ce1\u6392\u5e8f\u53ea\u4f1a\u6539\u5584\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u590d\u6742\u5ea6\u3002\u5bf9\u4e8e\u5e73\u5747\u60c5\u51b5\u800c\u8a00\uff0c\u7531\u4e8e\u4f9d\u7136\u662f\u53cc\u91cd\u5faa\u73af\u65f6\u95f4\uff0c\u6240\u4ee5\u590d\u6742\u5ea6\u662fO(n^2)\uff1b \u5bf9\u4e8e\u6709\u5e8f\u7684\u5217\u8868\u6765\u8bf4\uff0c\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u4f1a\u6bd4\u9009\u62e9\u6392\u5e8f\u7684\u6267\u884c\u6548\u7387\u66f4\u9ad8\u3002 \u7b97\u6cd5\u4ee3\u7801\uff1a def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 minIndex = i # \u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , minIndex , i ) i += 1 def bubbleSortWithTweak ( lyst ): \"\"\"\u5b9e\u73b0\u5192\u6ce1\u6392\u5e8f\u7b97\u6cd5\"\"\" n = len ( lyst ) while n > 1 : swapped = False # \u7528\u5e03\u5c14\u6807\u5fd7\u6765\u8ffd\u8e2a\u6709\u6ca1\u6709\u53d1\u751f\u4ea4\u6362 i = 1 while i < n : if lyst [ i ] < lyst [ i - 1 ]: # \u5982\u679c\u540e\u9762\u5143\u7d20\u7684\u503c\u6bd4\u524d\u9762\u5143\u7d20\u7684\u5927\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\uff0c\u76f4\u81f3\u628a\u5faa\u73af\u4e2d\u7684\u6700\u5927\u5143\u7d20\u79fb\u5230\u6700\u540e swap ( lyst , i , i - 1 ) swapped = True i += 1 if not swapped : # \u5982\u679c\u4e0d\u9700\u8981\u4ea4\u6362\uff0c\u76f4\u63a5return return n -= 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] # \u6bd4\u8f83\u6392\u5e8f print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) # \u5192\u6ce1\u6392\u5e8f myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before bubble sort \" , myList ) bubbleSortWithTweak ( myList ) print ( \"After bubble sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] # Before bubble sort [9, 4, 2, 7, 6, 8, 1] # After bubble sort [1, 2, 4, 6, 7, 8, 9]","title":"3.4.2.\u5192\u6ce1\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#343","text":"\u63d2\u5165\u6392\u5e8f\uff08Insertion-Sort\uff09\u662f\u901a\u8fc7\u6784\u5efa\u6709\u5e8f\u5e8f\u5217\uff0c\u5bf9\u4e8e\u672a\u6392\u5e8f\u6570\u636e\uff0c\u5728\u5df2\u6392\u5e8f\u5e8f\u5217\u4e2d\u4ece\u540e\u5411\u524d\u626b\u63cf\uff0c\u627e\u5230\u76f8\u5e94\u4f4d\u7f6e\u5e76\u63d2\u5165\u3002\u63d2\u5165\u6392\u5e8f\u90fd\u91c7\u7528 in-place \u5728\u6570\u7ec4\u4e0a\u5b9e\u73b0\uff1a \u4ece\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\uff0c\u8be5\u5143\u7d20\u53ef\u4ee5\u8ba4\u4e3a\u5df2\u7ecf\u88ab\u6392\u5e8f\uff1b \u53d6\u51fa\u4e0b\u4e00\u4e2a\u5143\u7d20\uff0c\u5728\u5df2\u7ecf\u6392\u5e8f\u7684\u5143\u7d20\u5e8f\u5217\u4ece\u540e\u5411\u524d\u626b\u63cf\uff1b \u5982\u679c\u65b0\u5143\u7d20\u5c0f\u4e8e\u5df2\u6392\u5e8f\u7684\u5143\u7d20\uff0c\u5c06\u65b0\u5143\u7d20\u79fb\u5230\u4e0b\u4e00\u4f4d\u7f6e\uff1b \u91cd\u590d\u6b65\u9aa43\uff0c\u76f4\u5230\u627e\u5230\u5df2\u6392\u5e8f\u7684\u5143\u7d20\u5c0f\u4e8e\u6216\u8005\u7b49\u4e8e\u65b0\u5143\u7d20\u7684\u4f4d\u7f6e\uff1b \u5c06\u65b0\u5143\u7d20\u63d2\u5165\u5230\u8be5\u4f4d\u7f6e\u540e\uff1b \u91cd\u590d\u6b65\u9aa42~5\u3002 \u590d\u6742\u5ea6\uff1a \u548c\u9009\u62e9\u6392\u5e8f\u7c7b\u4f3c\uff0c\u904d\u5386\u6b21\u6570\u4e5f\u662f (1/2)*n^2+(1/2)*n \uff0c\u6240\u4ee5\u590d\u6742\u5ea6\u4e5f\u662fO(n^2)\u3002 \u5217\u8868\u91cc\u6709\u5e8f\u5143\u7d20\u8d8a\u591a\uff0c\u63d2\u5165\u6392\u5e8f\u7684\u6027\u80fd\u5c31\u4f1a\u8d8a\u597d\uff1b \u5728\u6709\u5e8f\u5217\u8868\u7684\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u6392\u5e8f\u590d\u6742\u5ea6\u662f\u7ebf\u6027\u7684\uff1b def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 minIndex = i # \u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , minIndex , i ) i += 1 def bubbleSortWithTweak ( lyst ): \"\"\"\u5b9e\u73b0\u5192\u6ce1\u6392\u5e8f\u7b97\u6cd5\"\"\" n = len ( lyst ) while n > 1 : swapped = False # \u7528\u5e03\u5c14\u6807\u5fd7\u6765\u8ffd\u8e2a\u6709\u6ca1\u6709\u53d1\u751f\u4ea4\u6362 i = 1 while i < n : if lyst [ i ] < lyst [ i - 1 ]: # \u5982\u679c\u540e\u9762\u5143\u7d20\u7684\u503c\u6bd4\u524d\u9762\u5143\u7d20\u7684\u5927\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\uff0c\u76f4\u81f3\u628a\u5faa\u73af\u4e2d\u7684\u6700\u5927\u5143\u7d20\u79fb\u5230\u6700\u540e swap ( lyst , i , i - 1 ) swapped = True i += 1 if not swapped : # \u5982\u679c\u4e0d\u9700\u8981\u4ea4\u6362\uff0c\u76f4\u63a5return return n -= 1 def insertionSort ( lyst ): i = 1 # \u65b0\u5143\u7d20\u7684\u4f4d\u7f6e while i < len ( lyst ): itemToInsert = lyst [ i ] # \u65b0\u5143\u7d20 j = i - 1 # \u5df2\u6392\u5e8f\u7684\u5143\u7d20\u5e8f\u5217\u7684\u6700\u53f3\u4f4d\u7f6e while j >= 0 : if itemToInsert < lyst [ j ]: lyst [ j + 1 ] = lyst [ j ] # \u5982\u679c\u65b0\u5143\u7d20\u5c0f\u4e8e\u5df2\u6392\u5e8f\u5143\u7d20\uff0c\u5219\u5df2\u6392\u5e8f\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4e2a\u4f4d\u7f6e j -= 1 else : break # \u65b0\u5143\u7d20\u7b49\u4e8e\u6216\u8005\u5927\u4e8e\u5df2\u6392\u5e8f\u5143\u7d20\uff0c\u8df3\u51fa\u5faa\u73af\uff0c\u6b64\u65f6lyst[j + 1]\u662f\u548clyst[j]\u662f\u540c\u4e00\u4e2a\u5143\u7d20\u503c\uff0clyst[j + 1]\u4f4d\u7f6e\u662f\u7559\u7ed9\u65b0\u5143\u7d20\u7684 lyst [ j + 1 ] = itemToInsert # i += 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] # \u6bd4\u8f83\u6392\u5e8f print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) # \u5192\u6ce1\u6392\u5e8f myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before bubble sort \" , myList ) bubbleSortWithTweak ( myList ) print ( \"After bubble sort \" , myList ) # \u63d2\u5165\u6392\u5e8f myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before insertion sort \" , myList ) insertionSort ( myList ) print ( \"After insertion sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] # Before bubble sort [9, 4, 2, 7, 6, 8, 1] # After bubble sort [1, 2, 4, 6, 7, 8, 9] # Before insertion sort [9, 4, 2, 7, 6, 8, 1] # After insertion sort [1, 2, 4, 6, 7, 8, 9]","title":"3.4.3.\u63d2\u5165\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#344","text":"\u5bf9\u4e8e\u8bb8\u591a\u7b97\u6cd5\u6765\u8bf4\uff0c\u4e0d\u80fd\u5bf9\u6240\u6709\u60c5\u51b5\u91c7\u7528\u5355\u4e00\u7684\u590d\u6742\u5ea6\u6765\u8861\u91cf\u3002\u5f53\u9047\u5230\u7279\u5b9a\u987a\u5e8f\u7684\u6570\u636e\u65f6\uff0c\u7b97\u6cd5\u7684\u884c\u4e3a\u53ef\u80fd\u4f1a\u53d8\u5f97\u66f4\u597d\u6216\u66f4\u7cdf\u3002 \u5bf9\u7b97\u6cd5\u590d\u6742\u5ea6\u884c\u4e3a\u5206\u4e3a3\u79cd\u60c5\u51b5\uff1a \u6700\u597d\u60c5\u51b5\uff08best case\uff09\u2014\u2014\u7b97\u6cd5\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\u53ef\u4ee5\u4ee5\u6700\u5c11\u7684\u5de5\u4f5c\u91cf\u5b8c\u6210\u5de5\u4f5c\uff1f\u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u7684\u590d\u6742\u5ea6\u662f\u591a\u5c11\uff1f \u6700\u574f\u60c5\u51b5\uff08worst case\uff09\u2014\u2014\u7b97\u6cd5\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\u9700\u8981\u5b8c\u6210\u6700\u591a\u7684\u5de5\u4f5c\u91cf\uff1f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u7684\u590d\u6742\u5ea6\u662f\u591a\u5c11\uff1f \u5e73\u5747\u60c5\u51b5\uff08average case\uff09\u2014\u2014\u7b97\u6cd5\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\u7528\u9002\u91cf\u7684\u5de5\u4f5c\u91cf\u5c31\u80fd\u5b8c\u6210\u5de5\u4f5c\uff1f\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u7684\u590d\u6742\u5ea6\u662f\u591a\u5c11\uff1f \u4e0b\u9762\u5206\u522b\u5bf9\u6700\u5c0f\u503c\u641c\u7d22\u3001\u987a\u5e8f\u641c\u7d22\u548c\u5192\u6ce1\u6392\u5e8f\u8fdb\u884c\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u548c\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u5206\u6790\uff0c\u4e0d\u8003\u8651\u5b9e\u9645\u786c\u4ef6\u548c\u7f16\u7a0b\u8bed\u8a00\u7b49\u7684\u5f71\u54cd\u3002 \u6700\u5c0f\u503c\u641c\u7d22\uff08Minimum Value Search\uff09 \u6700\u597d\u60c5\u51b5\uff1a\u6700\u5c0f\u503c\u521a\u597d\u5728\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3002\u8fd9\u65f6\uff0c\u53ea\u9700\u8981\u4e00\u6b21\u6bd4\u8f83\u5c31\u53ef\u4ee5\u627e\u5230\u6700\u5c0f\u503c\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(1)\u3002 \u6700\u574f\u60c5\u51b5\uff1a\u6700\u5c0f\u503c\u5728\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u6216\u4e0d\u5b58\u5728\u3002\u8fd9\u65f6\uff0c\u9700\u8981\u8fdb\u884cn-1\u6b21\u6bd4\u8f83\u624d\u80fd\u786e\u5b9a\u6700\u5c0f\u503c\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5e73\u5747\u60c5\u51b5\uff1a\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u6bcf\u4e2a\u5143\u7d20\u6709\u76f8\u7b49\u7684\u6982\u7387\u6210\u4e3a\u6700\u5c0f\u503c\u3002\u56e0\u6b64\uff0c\u5e73\u5747\u6bd4\u8f83\u6b21\u6570\u4e3a(n-1)/2\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u987a\u5e8f\u641c\u7d22\uff08Sequential Search\uff09 \u6700\u597d\u60c5\u51b5\uff1a\u641c\u7d22\u7684\u5143\u7d20\u521a\u597d\u662f\u5217\u8868\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u3002\u8fd9\u65f6\uff0c\u53ea\u9700\u8981\u4e00\u6b21\u6bd4\u8f83\u5c31\u53ef\u4ee5\u627e\u5230\u76ee\u6807\u5143\u7d20\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(1)\u3002 \u6700\u574f\u60c5\u51b5\uff1a\u641c\u7d22\u7684\u5143\u7d20\u5728\u5217\u8868\u7684\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u6216\u4e0d\u5b58\u5728\u3002\u8fd9\u65f6\uff0c\u9700\u8981\u8fdb\u884cn\u6b21\u6bd4\u8f83\u624d\u80fd\u786e\u5b9a\u76ee\u6807\u5143\u7d20\u4e0d\u5b58\u5728\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5e73\u5747\u60c5\u51b5\uff1a\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u6bcf\u4e2a\u5143\u7d20\u6709\u76f8\u7b49\u7684\u6982\u7387\u6210\u4e3a\u76ee\u6807\u5143\u7d20\u3002\u56e0\u6b64\uff0c\u5e73\u5747\u6bd4\u8f83\u6b21\u6570\u4e3a (n+1)/2 \uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5192\u6ce1\u6392\u5e8f\uff08Bubble Sort\uff09 \u6700\u597d\u60c5\u51b5\uff1a\u5982\u679c\u8f93\u5165\u5217\u8868\u5df2\u7ecf\u662f\u6709\u5e8f\u7684\uff0c\u5192\u6ce1\u6392\u5e8f\u53ea\u9700\u8981\u8fdb\u884c\u4e00\u6b21\u904d\u5386\u6765\u68c0\u6d4b\u5217\u8868\u5df2\u7ecf\u6709\u5e8f\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002\u4f46\u5b9e\u9645\u4e0a\uff0c\u901a\u5e38\u9700\u8981\u8fdb\u884c\u591a\u6b21\u904d\u5386\u6765\u5b8c\u6210\u6392\u5e8f\uff0c\u56e0\u6b64\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662fO(n^2)\u3002 \u6700\u574f\u60c5\u51b5\uff1a\u5982\u679c\u8f93\u5165\u5217\u8868\u662f\u9006\u5e8f\u7684\uff0c\u6bcf\u6b21\u904d\u5386\u90fd\u9700\u8981\u8fdb\u884cn-1\u6b21\u4ea4\u6362\uff0c\u603b\u5171\u9700\u8981\u8fdb\u884cn-1\u8f6e\u904d\u5386\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n^2)\u3002 \u5e73\u5747\u60c5\u51b5\uff1a\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u5192\u6ce1\u6392\u5e8f\u9700\u8981\u8fdb\u884c n(n-1)/2 \u6b21\u6bd4\u8f83\u548c\u4ea4\u6362\u64cd\u4f5c\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n^2)\u3002","title":"3.4.4.\u518d\u8bba\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd"},{"location":"python/DataStructure/03_TimeComplexity/#345","text":"\u5217\u8868\u91cc\u5982\u4f55\u6392\u5217\u6570\u636e\u624d\u80fd\u8ba9\u9009\u62e9\u6392\u5e8f\u4e2d\u5143\u7d20\u4ea4\u6362\u7684\u6b21\u6570\u6700\u5c11\uff1f\u5982\u4f55\u6392\u5217\u6570\u636e\u624d\u80fd\u8ba9\u5b83\u6267\u884c\u6700\u591a\u7684\u4ea4\u6362\u6b21\u6570\uff1f \u89e3\u7b54\uff1a \u5728\u9009\u62e9\u6392\u5e8f\u4e2d\uff0c\u5143\u7d20\u7684\u4ea4\u6362\u6b21\u6570\u4e3b\u8981\u53d6\u51b3\u4e8e\u5f85\u6392\u5e8f\u5217\u8868\u7684\u521d\u59cb\u6392\u5217\uff1a \u6700\u5c0f\u5316\u4ea4\u6362\u6b21\u6570\uff1a \u8981\u6700\u5c0f\u5316\u9009\u62e9\u6392\u5e8f\u7684\u5143\u7d20\u4ea4\u6362\u6b21\u6570\uff0c\u53ef\u4ee5\u8ba9\u8f93\u5165\u5217\u8868\u5df2\u7ecf\u6309\u5347\u5e8f\u6392\u5217\u3002\u8fd9\u662f\u56e0\u4e3a\u5728\u5347\u5e8f\u6392\u5217\u7684\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u6bcf\u6b21\u9009\u62e9\u6700\u5c0f\u7684\u5143\u7d20\u5e76\u5c06\u5176\u653e\u7f6e\u5728\u6b63\u786e\u7684\u4f4d\u7f6e\uff0c\u65e0\u9700\u4ea4\u6362\u3002\u56e0\u6b64\uff0c\u5143\u7d20\u4ea4\u6362\u7684\u6b21\u6570\u4e3a 0 \u3002 \u6700\u5927\u5316\u4ea4\u6362\u6b21\u6570\uff1a \u8981\u6700\u5927\u5316\u9009\u62e9\u6392\u5e8f\u7684\u5143\u7d20\u4ea4\u6362\u6b21\u6570\uff0c\u53ef\u4ee5\u8ba9\u8f93\u5165\u5217\u8868\u6309\u964d\u5e8f\u6392\u5217\u3002\u5728\u964d\u5e8f\u6392\u5217\u7684\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u6bcf\u6b21\u9009\u62e9\u6700\u5927\u7684\u5143\u7d20\u5e76\u5c06\u5176\u653e\u7f6e\u5728\u6b63\u786e\u7684\u4f4d\u7f6e\uff0c\u8fd9\u5c06\u5bfc\u81f4\u5927\u91cf\u7684\u4ea4\u6362\u64cd\u4f5c\u3002\u5177\u4f53\u6765\u8bf4\uff0c\u5bf9\u4e8e\u957f\u5ea6\u4e3an\u7684\u5217\u8868\uff0c\u6700\u5927\u5316\u4ea4\u6362\u6b21\u6570\u7684\u60c5\u51b5\u4e0b\uff0c\u5c06\u6267\u884c n-1 \u6b21\u4ea4\u6362\u64cd\u4f5c\u3002 \u603b\u4e4b\uff0c\u8981\u6700\u5c0f\u5316\u9009\u62e9\u6392\u5e8f\u7684\u5143\u7d20\u4ea4\u6362\u6b21\u6570\uff0c\u8f93\u5165\u5217\u8868\u5e94\u8be5\u5df2\u7ecf\u6309\u5347\u5e8f\u6392\u5217\u3002\u8981\u6700\u5927\u5316\u4ea4\u6362\u6b21\u6570\uff0c\u8f93\u5165\u5217\u8868\u5e94\u8be5\u6309\u964d\u5e8f\u6392\u5217\u3002\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u9009\u62e9\u6392\u5e8f\u901a\u5e38\u4e0d\u662f\u9996\u9009\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u56e0\u4e3a\u5176\u4ea4\u6362\u6b21\u6570\u8f83\u591a\uff0c\u800c\u5176\u4ed6\u7b97\u6cd5\u5982\u5feb\u901f\u6392\u5e8f\u3001\u5f52\u5e76\u6392\u5e8f\u7b49\u5177\u6709\u66f4\u597d\u7684\u6027\u80fd\u3002 \u8bf7\u8bf4\u660e\u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\u5728\u5206\u6790\u9009\u62e9\u6392\u5e8f\u548c\u5192\u6ce1\u6392\u5e8f\u65f6\u6240\u8d77\u5230\u7684\u4f5c\u7528\u3002\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u5728\u5b83\u4eec\u4e4b\u95f4\u53d1\u6325\u7740\u4ec0\u4e48\u4f5c\u7528\uff08\u5982\u679c\u6709\u4f5c\u7528\uff09\uff1f \u89e3\u7b54\uff1a \u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\u5728\u5206\u6790\u9009\u62e9\u6392\u5e8f\u548c\u5192\u6ce1\u6392\u5e8f\u65f6\u8d77\u5230\u91cd\u8981\u4f5c\u7528\uff0c\u56e0\u4e3a\u5b83\u4eec\u76f4\u63a5\u5f71\u54cd\u5230\u6392\u5e8f\u7b97\u6cd5\u7684\u6027\u80fd\u548c\u6548\u7387\u3002 \u9009\u62e9\u6392\u5e8f\uff08Selection Sort\uff09\uff1a \u9009\u62e9\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e0e\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u76f4\u63a5\u76f8\u5173\u3002\u5728\u9009\u62e9\u6392\u5e8f\u4e2d\uff0c\u6bcf\u4e00\u8f6e\u90fd\u4f1a\u9009\u62e9\u672a\u6392\u5e8f\u90e8\u5206\u7684\u6700\u5c0f\u5143\u7d20\uff0c\u5e76\u5c06\u5176\u653e\u7f6e\u5728\u6b63\u786e\u7684\u4f4d\u7f6e\uff0c\u8fd9\u610f\u5473\u7740\u6bcf\u8f6e\u90fd\u9700\u8981\u4e00\u6b21\u4ea4\u6362\u64cd\u4f5c\u3002 \u9009\u62e9\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u662f\u4e0e\u8f93\u5165\u6570\u636e\u7684\u521d\u59cb\u6392\u5217\u65e0\u5173\u7684\uff0c\u56e0\u4e3a\u5b83\u603b\u662f\u4f1a\u6267\u884c\u76f8\u540c\u6570\u91cf\u7684\u4ea4\u6362\u64cd\u4f5c\uff0c\u65e0\u8bba\u6570\u636e\u662f\u5426\u6709\u5e8f\u3002 \u5bf9\u4e8e\u9009\u62e9\u6392\u5e8f\uff0c\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e3b\u8981\u53d7\u5230\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u5f71\u54cd\uff0c\u800c\u4e0d\u53d7\u6570\u636e\u7684\u5177\u4f53\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u65e0\u8bba\u6570\u636e\u7684\u6392\u5217\u5982\u4f55\uff0c\u9009\u62e9\u6392\u5e8f\u7684\u5e73\u5747\u548c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u90fd\u662f\u76f8\u540c\u7684\uff0c\u5373 n-1 \u6b21\u3002 \u5192\u6ce1\u6392\u5e8f\uff08Bubble Sort\uff09\uff1a \u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e5f\u4e0e\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u76f8\u5173\u3002\u5728\u5192\u6ce1\u6392\u5e8f\u4e2d\uff0c\u76f8\u90bb\u5143\u7d20\u9010\u4e00\u6bd4\u8f83\uff0c\u5982\u679c\u9006\u5e8f\u5c31\u4ea4\u6362\u4f4d\u7f6e\uff0c\u56e0\u6b64\u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e0e\u9006\u5e8f\u5bf9\u7684\u6570\u91cf\u76f8\u5173\u3002 \u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u5728\u4e0d\u540c\u7684\u6570\u636e\u6392\u5217\u60c5\u51b5\u4e0b\u53ef\u4ee5\u6709\u5f88\u5927\u5dee\u5f02\u3002\u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff08\u8f93\u5165\u6570\u636e\u5df2\u7ecf\u6709\u5e8f\uff09\uff0c\u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e3a 0 \u3002\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff08\u8f93\u5165\u6570\u636e\u5b8c\u5168\u9006\u5e8f\uff09\uff0c\u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u662f\u6700\u5927\u7684\u3002 \u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u65e2\u53d7\u5230\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u5f71\u54cd\uff0c\u53c8\u53d7\u5230\u6570\u636e\u7684\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u4ea4\u6362\u6b21\u6570\u4e3a 0 \uff0c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u4ea4\u6362\u6b21\u6570\u4e3a n*(n-1)/2 \uff0c\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u4ea4\u6362\u6b21\u6570\u53d6\u51b3\u4e8e\u6570\u636e\u6392\u5217\u7684\u968f\u673a\u6027\u3002 \u7efc\u4e0a\u6240\u8ff0\uff0c\u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\u5728\u9009\u62e9\u6392\u5e8f\u548c\u5192\u6ce1\u6392\u5e8f\u7684\u5206\u6790\u4e2d\u662f\u91cd\u8981\u7684\u6027\u80fd\u6307\u6807\u3002\u9009\u62e9\u6392\u5e8f\u7684\u4ea4\u6362\u6b21\u6570\u4e0e\u6570\u636e\u89c4\u6a21\u76f8\u5173\uff0c\u800c\u5192\u6ce1\u6392\u5e8f\u7684\u4ea4\u6362\u6b21\u6570\u65e2\u4e0e\u6570\u636e\u89c4\u6a21\u76f8\u5173\uff0c\u53c8\u53d7\u5230\u6570\u636e\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u5728\u5927\u89c4\u6a21\u6570\u636e\u96c6\u4e0a\uff0c\u5192\u6ce1\u6392\u5e8f\u901a\u5e38\u6bd4\u9009\u62e9\u6392\u5e8f\u66f4\u6162\uff0c\u56e0\u4e3a\u5b83\u7684\u4ea4\u6362\u64cd\u4f5c\u66f4\u591a\u3002\u56e0\u6b64\uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u901a\u5e38\u9009\u62e9\u6392\u5e8f\u6bd4\u5192\u6ce1\u6392\u5e8f\u66f4\u6709\u6548\u3002\u4f46\u4e24\u8005\u90fd\u4e0d\u662f\u9996\u9009\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u66f4\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\u5982\u5feb\u901f\u6392\u5e8f\u3001\u5f52\u5e76\u6392\u5e8f\u7b49\u901a\u5e38\u88ab\u4f18\u5148\u8003\u8651\u3002 \u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u6027\u80fd\u4ecd\u7136\u4e3aO(n^2)\u3002 \u89e3\u7b54\uff1a \u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u6027\u80fd\u4ecd\u7136\u4e3aO(n^2)\uff0c\u539f\u56e0\u5982\u4e0b\uff1a \u5192\u6ce1\u6392\u5e8f\u7684\u57fa\u672c\u64cd\u4f5c\u662f\u6bd4\u8f83\u76f8\u90bb\u5143\u7d20\u5e76\u4ea4\u6362\u5b83\u4eec\uff0c\u76f4\u5230\u6574\u4e2a\u5217\u8868\u6309\u7167\u5347\u5e8f\u6392\u5217\u3002\u5728\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u4e2d\uff0c\u5f53\u4e24\u4e2a\u76f8\u90bb\u5143\u7d20\u9006\u5e8f\u65f6\uff0c\u4f1a\u53d1\u751f\u4ea4\u6362\u3002\u8fd9\u4e2a\u57fa\u672c\u64cd\u4f5c\u7684\u590d\u6742\u5ea6\u662fO(1)\uff0c\u56e0\u4e3a\u5b83\u53ea\u6d89\u53ca\u4e24\u4e2a\u5143\u7d20\u7684\u6bd4\u8f83\u548c\u53ef\u80fd\u7684\u4ea4\u6362\u3002 \u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u6bcf\u4e00\u8f6e\u904d\u5386\u4e2d\uff0c\u4ecd\u7136\u9700\u8981\u68c0\u67e5\u76f8\u90bb\u5143\u7d20\u7684\u6bd4\u8f83\uff0c\u5373\u4f7f\u5728\u6709\u5e8f\u90e8\u5206\uff0c\u5b83\u4ecd\u7136\u9700\u8981\u8fdb\u884c\u6bd4\u8f83\u3002\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5b83\u4f1a\u6267\u884cn-1\u6b21\u904d\u5386\uff0c\u6bcf\u6b21\u90fd\u8981\u6bd4\u8f83\u76f8\u90bb\u5143\u7d20\u3002 \u5192\u6ce1\u6392\u5e8f\u7684\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n^2)\uff0c\u8fd9\u662f\u56e0\u4e3a\u5b83\u4e0d\u4f1a\u5229\u7528\u8f93\u5165\u6570\u636e\u7684\u4efb\u4f55\u6709\u5e8f\u6027\u3002\u65e0\u8bba\u8f93\u5165\u6570\u636e\u662f\u6709\u5e8f\u7684\u3001\u9006\u5e8f\u7684\uff0c\u8fd8\u662f\u968f\u673a\u6392\u5217\u7684\uff0c\u90fd\u9700\u8981\u6267\u884c\u76f8\u540c\u6570\u91cf\u7684\u6bd4\u8f83\u548c\u4ea4\u6362\u64cd\u4f5c\u3002 \u603b\u4e4b\uff0c\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u867d\u7136\u51cf\u5c11\u4e86\u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\uff0c\u4f46\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u4ecd\u7136\u9700\u8981\u6267\u884c\u5927\u7ea6 n(n-1)/2 \u6b21\u6bd4\u8f83\u64cd\u4f5c\uff0c\u56e0\u6b64\u5b83\u7684\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662fO(n^2)\u3002\u5192\u6ce1\u6392\u5e8f\u7684\u6027\u80fd\u4e3b\u8981\u53d7\u5230\u6570\u636e\u89c4\u6a21\u7684\u5f71\u54cd\uff0c\u800c\u4e0d\u592a\u53d7\u5230\u5177\u4f53\u6570\u636e\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u56e0\u6b64\uff0c\u5b83\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u4ecd\u7136\u5177\u6709\u4e8c\u6b21\u65f6\u95f4\u590d\u6742\u5ea6\u3002 \u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u63d2\u5165\u6392\u5e8f\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e0a\u80fd\u591f\u5f88\u597d\u5730\u5de5\u4f5c\u3002 \u89e3\u7b54\uff1a \u63d2\u5165\u6392\u5e8f\u4e4b\u6240\u4ee5\u80fd\u591f\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e0a\u5f88\u597d\u5730\u5de5\u4f5c\uff0c\u662f\u56e0\u4e3a\u5b83\u7684\u6838\u5fc3\u601d\u60f3\u662f\u9010\u6b65\u6784\u5efa\u6709\u5e8f\u7684\u5b50\u5217\u8868\uff0c\u800c\u4e0d\u662f\u50cf\u9009\u62e9\u6392\u5e8f\u6216\u5192\u6ce1\u6392\u5e8f\u4e00\u6837\u603b\u662f\u8003\u8651\u6574\u4e2a\u5217\u8868\u3002\u8fd9\u4f7f\u5f97\u63d2\u5165\u6392\u5e8f\u5728\u5904\u7406\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u65f6\u5177\u6709\u4e00\u4e9b\u4f18\u52bf\uff1a \u5c40\u90e8\u6027\u539f\u7406\uff1a\u63d2\u5165\u6392\u5e8f\u5229\u7528\u4e86\u5c40\u90e8\u6027\u539f\u7406\uff0c\u5373\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u6570\u636e\u9879\u7684\u6b63\u786e\u4f4d\u7f6e\u79bb\u5b83\u4eec\u5f53\u524d\u7684\u4f4d\u7f6e\u5f88\u8fd1\u3002\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e2d\uff0c\u5927\u591a\u6570\u6570\u636e\u9879\u5df2\u7ecf\u63a5\u8fd1\u4e8e\u5b83\u4eec\u7684\u6700\u7ec8\u4f4d\u7f6e\uff0c\u56e0\u6b64\u53ea\u9700\u8981\u8fdb\u884c\u5c11\u91cf\u7684\u79fb\u52a8\u64cd\u4f5c\u3002 \u9002\u5e94\u6027\uff1a\u63d2\u5165\u6392\u5e8f\u662f\u4e00\u79cd\u81ea\u9002\u5e94\u6392\u5e8f\u7b97\u6cd5\uff0c\u5b83\u53ef\u4ee5\u6839\u636e\u8f93\u5165\u6570\u636e\u7684\u6709\u5e8f\u6027\u8fdb\u884c\u81ea\u52a8\u8c03\u6574\u3002\u5728\u5904\u7406\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u65f6\uff0c\u63d2\u5165\u6392\u5e8f\u7684\u6027\u80fd\u4f1a\u66f4\u597d\uff0c\u56e0\u4e3a\u4e0d\u9700\u8981\u6267\u884c\u592a\u591a\u7684\u6bd4\u8f83\u548c\u4ea4\u6362\u64cd\u4f5c\u3002 \u7b80\u5355\u6027\uff1a\u63d2\u5165\u6392\u5e8f\u7684\u5b9e\u73b0\u975e\u5e38\u7b80\u5355\u76f4\u89c2\uff0c\u5b83\u53ea\u6d89\u53ca\u5230\u9010\u4e2a\u63d2\u5165\u5143\u7d20\u5230\u6b63\u786e\u7684\u4f4d\u7f6e\u3002\u8fd9\u79cd\u7b80\u5355\u6027\u4f7f\u5f97\u63d2\u5165\u6392\u5e8f\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\u6bd4\u66f4\u590d\u6742\u7684\u6392\u5e8f\u7b97\u6cd5\u66f4\u5177\u7ade\u4e89\u529b\u3002 \u867d\u7136\u63d2\u5165\u6392\u5e8f\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e0a\u8868\u73b0\u826f\u597d\uff0c\u4f46\u5728\u5904\u7406\u5927\u89c4\u6a21\u4e71\u5e8f\u6570\u636e\u96c6\u65f6\uff0c\u5b83\u7684\u6027\u80fd\u4e0d\u5982\u5feb\u901f\u6392\u5e8f\u3001\u5f52\u5e76\u6392\u5e8f\u7b49\u66f4\u9ad8\u7ea7\u7684\u6392\u5e8f\u7b97\u6cd5\u3002\u56e0\u6b64\uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u6839\u636e\u6570\u636e\u7684\u6027\u8d28\u9009\u62e9\u9002\u5f53\u7684\u6392\u5e8f\u7b97\u6cd5\u662f\u91cd\u8981\u7684\u3002\u63d2\u5165\u6392\u5e8f\u901a\u5e38\u9002\u7528\u4e8e\u5c0f\u89c4\u6a21\u6570\u636e\u6216\u8005\u5df2\u7ecf\u90e8\u5206\u6709\u5e8f\u7684\u6570\u636e\uff0c\u800c\u4e0d\u662f\u5927\u89c4\u6a21\u4e71\u5e8f\u6570\u636e\u7684\u6392\u5e8f\u3002","title":"3.4.5.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/03_TimeComplexity/#35","text":"\u5206\u6cbb\u6cd5\uff08divide-and-conquer\uff09\u7b56\u7565\uff1a\u628a\u5217\u8868\u5206\u6210\u66f4\u5c0f\u7684\u5b50\u5217\u8868\uff0c\u7136\u540e\u518d\u901a\u8fc7\u9012\u5f52\u628a\u8fd9\u4e9b\u5b50\u5217\u8868\u6392\u5e8f\u3002 \u7406\u60f3\u60c5\u51b5\u4e0b\uff0c\u5982\u679c\u8fd9\u4e9b\u88ab\u62c6\u5206\u7684\u5b50\u5217\u8868\u7684\u6570\u91cf\u662f logn \uff0c\u800c\u628a\u6bcf\u4e2a\u5b50\u5217\u8868\u8fdb\u884c\u5408\u5e76\u6240\u9700\u7684\u5de5\u4f5c\u91cf\u4e3a n \uff0c\u90a3\u4e48\u8fd9\u79cd\u6392\u5e8f\u7b97\u6cd5\u7684\u603b\u590d\u6742\u5ea6\u5c31\u662f O(nlogn) \uff0c\u76f8\u6bd4 O(n^2) \u7684\u5de5\u4f5c\u91cf\u589e\u957f\u8981\u4f4e\u5f88\u591a\u3002","title":"3.5.\u66f4\u5feb\u7684\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#351","text":"\u5feb\u901f\u6392\u5e8f\uff08QuickSort\uff09\u662f\u6392\u9664\u7a33\u5b9a\u6027\u56e0\u7d20\u540e\u6700\u5e38\u7528\u7684\u6392\u5e8f\u3002 \u9996\u5148\u4ece\u5217\u8868\u7684\u4e2d\u95f4\u4f4d\u7f6e\u9009\u62e9\u4e00\u4e2a\u5143\u7d20\uff0c\u8fd9\u4e2a\u5143\u7d20\u88ab\u79f0\u4e3a\u57fa\u51c6\uff08pivot\uff09\uff1b \u5bf9\u5217\u8868\u91cc\u7684\u5143\u7d20\u8fdb\u884c\u5206\u5272\uff0c\u628a\u5c0f\u4e8e\u57fa\u51c6\u7684\u6240\u6709\u5143\u7d20\u79fb\u52a8\u5230\u57fa\u51c6\u7684\u5de6\u4fa7\uff0c\u800c\u628a\u5176\u4f59\u5143\u7d20\u90fd\u79fb\u5230\u57fa\u51c6\u7684\u53f3\u4fa7\u3002 \u5982\u679c\u57fa\u51c6\u6b63\u597d\u662f\u6700\u5927\u7684\u5143\u7d20\uff0c\u90a3\u4e48\u5b83\u6700\u7ec8\u4f1a\u5904\u4e8e\u5217\u8868\u7684\u6700\u53f3\u4fa7\uff1b \u5982\u679c\u57fa\u51c6\u6b63\u597d\u662f\u6700\u5c0f\u7684\u5143\u7d20\uff0c\u90a3\u4e48\u5b83\u5c31\u4f1a\u5728\u6700\u5de6\u4fa7\uff1b \u5206\u6cbb\u6cd5\u3002\u5c06\u8fd9\u4e2a\u8fc7\u7a0b\u9012\u5f52\u5730\u5e94\u7528\u5230\u901a\u8fc7\u57fa\u51c6\u800c\u628a\u539f\u5217\u8868\u5206\u5272\u7684\u5b50\u5217\u8868\u4e0a\uff0c\u5176\u4e2d\uff1a \u4e00\u4e2a\u65b0\u7684\u5b50\u5217\u8868\u7531\u57fa\u51c6\u5de6\u4fa7\u7684\u6240\u6709\u5143\u7d20\uff08\u8f83\u5c0f\u7684\u5143\u7d20\uff09\u7ec4\u6210\uff0c \u53e6\u4e00\u4e2a\u65b0\u7684\u5b50\u5217\u8868\u7531\u57fa\u51c6\u53f3\u4fa7\u7684\u6240\u6709\u5143\u7d20\uff08\u8f83\u5927\u7684\u5143\u7d20\uff09\u7ec4\u6210\uff1b \u5f53\u5206\u51fa\u7684\u5b50\u5217\u8868\u5185\u5c11\u4e8e\u4e24\u4e2a\u5143\u7d20\u65f6\uff0c\u8fd9\u4e2a\u8fc7\u7a0b\u7ec8\u6b62\uff1b","title":"3.5.1.\u5feb\u901f\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#3511","text":"\u8fd9\u4e2a\u7b97\u6cd5\u91cc\u6700\u590d\u6742\u7684\u90e8\u5206\u662f\u5bf9\u5143\u7d20\u8fdb\u884c\u5206\u5272\u4ece\u800c\u5f97\u5230\u5b50\u5217\u8868\u7684\u64cd\u4f5c\u3002 \u5c06\u57fa\u51c6\u4e0e\u5b50\u5217\u8868\u91cc\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\u3002 \u5728\u5df2\u77e5\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u548c\u5176\u4ed6\u5143\u7d20\u4e4b\u95f4\u6784\u5efa\u4e00\u4e2a\u8fb9\u754c\u3002\u4e00\u5f00\u59cb\uff0c\u8fd9\u4e2a\u8fb9\u754c\u4f1a\u5904\u4e8e\u7b2c\u4e00\u4e2a\u5143\u7d20\u4e4b\u524d\u3002 \u4ece\u5b50\u5217\u8868\u8fb9\u754c\u4e4b\u540e\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\u5411\u53f3\u626b\u63cf\u3002\u5f53\u6bcf\u6b21\u9047\u5230\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u65f6\uff0c\u5c06\u5b83\u548c\u8fb9\u754c\u4e4b\u540e\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\uff0c\u5e76\u4e14\u5c06\u8fb9\u754c\u5411\u53f3\u79fb\u52a8\u3002 \u5728\u7ed3\u675f\u7684\u65f6\u5019\uff0c\u5c06\u57fa\u51c6\u548c\u8fb9\u754c\u4e4b\u540e\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\u3002 \u793a\u4f8b\u5217\u8868\uff1a[12,19,17,18,14,11,15,13,16]\uff0c\u4e0b\u56fe\u5c55\u793a\u4e86\u5206\u5272\u7684\u6bcf\u4e00\u6b65\u8fc7\u7a0b\u3002","title":"3.5.1.1.\u5206\u5272"},{"location":"python/DataStructure/03_TimeComplexity/#3512","text":"\u5feb\u901f\u6392\u5e8f\uff08Quick Sort\uff09\u662f\u4e00\u79cd\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u5176\u5e73\u5747\u548c\u6700\u574f\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662f O(n log n) \u3002\u4e0b\u9762\u662f\u5feb\u901f\u6392\u5e8f\u7684\u590d\u6742\u5ea6\u5206\u6790\uff1a \u5728\u7b2c\u4e00\u6b21\u8fdb\u884c\u5206\u5272\u64cd\u4f5c\u65f6\uff0c\u6211\u4eec\u5c06\u626b\u63cf\u5217\u8868\u91cc\u4ece\u5f00\u5934\u5230\u7ed3\u5c3e\u7684\u6240\u6709\u5143\u7d20\u3002\u56e0\u6b64\uff0c\u5728\u8fd9\u4e2a\u64cd\u4f5c\u671f\u95f4\u5de5\u4f5c\u91cf\u662f\u548c\u5217\u8868\u7684\u957f\u5ea6 n \u6210\u6b63\u6bd4\u7684\u3002\u8fd9\u6b21\u5206\u5272\u4e4b\u540e\u7684\u5de5\u4f5c\u91cf\u4f1a\u548c\u5de6\u5b50\u5217\u8868\u52a0\u4e0a\u53f3\u5b50\u5217\u8868\u7684\u603b\u957f\u5ea6\u6210\u6b63\u6bd4\uff0c\u4e5f\u5c31\u662f n-1 \u3002 \u518d\u6b21\u5bf9\u8fd9\u4e24\u4e2a\u5b50\u5217\u8868\u8fdb\u884c\u5206\u5272\u4e4b\u540e\uff0c\u5c31\u4f1a\u4ea7\u751f4\u4e2a\u52a0\u8d77\u6765\u603b\u957f\u5ea6\u5927\u7ea6\u4e3a n \u7684\u5217\u8868\u6bb5\u3002\u56e0\u6b64\uff0c\u5bf9\u5b83\u4eec\u8fdb\u884c\u5206\u5272\u7684\u603b\u5de5\u4f5c\u91cf\u8fd8\u662f\u548c n \u6210\u6b63\u6bd4\u7684\u3002\u968f\u7740\u5217\u8868\u88ab\u5206\u5272\u6210\u66f4\u591a\u6bb5\uff0c\u603b\u5de5\u4f5c\u91cf\u4f1a\u4e00\u76f4\u548c n \u6210\u6b63\u6bd4\u3002 \u8981\u5b8c\u6210\u6574\u4e2a\u5206\u6790\uff0c\u8fd8\u9700\u8981\u786e\u5b9a\u5217\u8868\u88ab\u5206\u5272\u4e86\u591a\u5c11\u6b21\u3002\u6309\u7167\u6700\u4e50\u89c2\u7684\u60c5\u51b5\u6765\u8bf4\uff08\u867d\u7136\u5728\u5b9e\u9645\u64cd\u4f5c\u7684\u65f6\u5019\uff0c\u901a\u5e38\u5e76\u4e0d\u4f1a\u51fa\u73b0\u8fd9\u4e48\u597d\u7684\u60c5\u51b5\uff09\uff0c\u5047\u8bbe\u6bcf\u6b21\u65b0\u5b50\u5217\u8868\u4e4b\u95f4\u7684\u5206\u754c\u7ebf\u90fd\u5c3d\u53ef\u80fd\u5730\u9760\u8fd1\u5f53\u524d\u5217\u8868\u7684\u4e2d\u5fc3\uff0c\u901a\u5e38\u8fd9\u79cd\u60c5\u51b5\u5e76\u4e0d\u5e38\u89c1\u3002\u4ece\u4e8c\u5206\u641c\u7d22\u7b97\u6cd5\u7684\u8ba8\u8bba\u91cc\u53ef\u77e5\uff0c\u8981\u628a\u5217\u8868\u4e0d\u65ad\u5730\u5206\u6210\u4e24\u534a\uff0c\u5927\u7ea6\u5728 log n \u6b65\u7684\u65f6\u5019\u5c31\u53ea\u5269\u4e0b\u4e00\u4e2a\u5143\u7d20\u4e86\u3002 \u56e0\u6b64\uff0c\u8fd9\u4e2a\u7b97\u6cd5\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u4e3a O(n log n) \u3002\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u6765\u8003\u8651\u6709\u5e8f\u5217\u8868\u7684\u60c5\u51b5\u3002\u5982\u679c\u9009\u62e9\u7684\u57fa\u51c6\u5143\u7d20\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20\uff0c\u90a3\u4e48\u5728\u7b2c\u4e00\u6b21\u5206\u5272\u4e4b\u540e\u5b83\u7684\u53f3\u8fb9\u4f1a\u6709 n-1 \u4e2a\u5143\u7d20\uff0c\u5728\u7b2c\u4e8c\u6b21\u5206\u5272\u4e4b\u540e\u5b83\u7684\u53f3\u8fb9\u6709 n-2 \u4e2a\u5143\u7d20\uff0c\u4ee5\u6b64\u7c7b\u63a8\uff0c \u5c3d\u7ba1\u6574\u4e2a\u64cd\u4f5c\u91cc\u6ca1\u6709\u4ea4\u6362\u4efb\u4f55\u5143\u7d20\uff0c\u4f46\u5206\u5272\u603b\u5171\u4e5f\u6267\u884c\u4e86 n-1 \u6b21\uff0c\u4e8e\u662f\u6267\u884c\u7684\u6bd4\u8f83\u603b\u6570\u5c31\u662f n^2/2-n/2 \u3002\u8fd9\u4e0e\u9009\u62e9\u6392\u5e8f\u4ee5\u53ca\u5192\u6ce1\u6392\u5e8f\u7684\u60c5\u51b5\u662f\u4e00\u6837\u7684\u3002\u56e0\u6b64\uff0c\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7b97\u6cd5\u7684\u6027\u80fd\u4e3a O(n^2) \u3002\u5982\u679c\u628a\u5feb\u901f\u6392\u5e8f\u5b9e\u73b0\u6210\u9012\u5f52\u7b97\u6cd5\uff0c\u90a3\u4e48\u5728\u5bf9\u5b83\u8fdb\u884c\u5206\u6790\u65f6\u8fd8\u5fc5\u987b\u8981\u8003\u8651\u8c03\u7528\u6808\u7684\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\u3002\u7531\u4e8e\u5bf9\u4e8e\u6808\u7684\u4e00\u5e27\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u90fd\u9700\u8981\u56fa\u5b9a\u7684\u5185\u5b58\uff0c\u5e76\u4e14\u6bcf\u6b21\u5206\u5272\u4e4b\u540e\u90fd\u4f1a\u6709\u4e24\u6b21\u9012\u5f52\u8c03\u7528\u3002\u56e0\u6b64\uff0c\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u5185\u5b58\u7684\u4f7f\u7528\u91cf\u4f1a\u662f O(log n) \uff0c\u800c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u5185\u5b58\u4f7f\u7528\u91cf\u662f O(n) \u3002 \u5c3d\u7ba1\u5feb\u901f\u6392\u5e8f\u5904\u4e8e\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u53ef\u80fd\u6027\u5f88\u5c0f\uff0c\u6211\u4eec\u8fd8\u662f\u4f1a\u52aa\u529b\u5730\u53bb\u907f\u514d\u8fd9\u79cd\u60c5\u51b5\uff0c\u56e0\u6b64\uff0c\u5b83\u4eec\u5e76\u4e0d\u4f1a\u5728\u7b2c\u4e00\u4e2a\u6216\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u9009\u62e9\u57fa\u51c6\u5143\u7d20\u3002\u6709\u5176\u4ed6\u4e00\u4e9b\u9009\u62e9\u57fa\u51c6\u7684\u65b9\u6cd5\u53ef\u4ee5\u8ba9\u8fd9\u4e2a\u7b97\u6cd5\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u6709\u5927\u7ea6 O(n log n) \u7684\u6027\u80fd\uff0c\u6bd4\u5982\uff0c\u53ef\u4ee5\u9009\u62e9\u968f\u673a\u4f4d\u7f6e\u4e0a\u7684\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\uff0c\u6216\u8005\u9009\u62e9\u6574\u4e2a\u5217\u8868\u91cc\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3001\u4e2d\u95f4\u4f4d\u7f6e\u4ee5\u53ca\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u8fd93\u4e2a\u5143\u7d20\u7684\u4e2d\u4f4d\u6570\u3002 \u603b\u7ed3\uff1a \u6700\u597d\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u4e5f\u5c31\u662f\u6bcf\u6b21\u9009\u62e9\u7684\u57fa\u51c6\u5143\u7d20\u90fd\u521a\u597d\u5c06\u8f93\u5165\u6570\u636e\u5206\u6210\u4e24\u4e2a\u7b49\u957f\u7684\u5b50\u6570\u7ec4\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n log n) \u3002\u8fd9\u79cd\u60c5\u51b5\u901a\u5e38\u53d1\u751f\u5728\u57fa\u51c6\u5143\u7d20\u7684\u9009\u62e9\u975e\u5e38\u5408\u7406\u7684\u60c5\u51b5\u4e0b\uff0c\u4f8b\u5982\u5728\u6bcf\u6b21\u9009\u62e9\u4e2d\u90fd\u9009\u62e9\u4e2d\u95f4\u5143\u7d20\u3002 \u5e73\u5747\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e5f\u662f O(n log n) \u3002\u8fd9\u662f\u56e0\u4e3a\u5feb\u901f\u6392\u5e8f\u662f\u4e00\u79cd\u5206\u6cbb\u7b97\u6cd5\uff0c\u6bcf\u6b21\u5c06\u95ee\u9898\u5206\u6210\u4e24\u4e2a\u5b50\u95ee\u9898\uff0c\u7136\u540e\u9012\u5f52\u5730\u89e3\u51b3\u8fd9\u4e9b\u5b50\u95ee\u9898\u3002\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u6bcf\u6b21\u5206\u5272\u64cd\u4f5c\u90fd\u80fd\u5c06\u95ee\u9898\u89c4\u6a21\u51cf\u534a\uff0c\u56e0\u6b64\u9700\u8981\u6267\u884c O(n log n) \u6b21\u5206\u5272\u64cd\u4f5c\uff0c\u6bcf\u6b21\u5206\u5272\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002\u56e0\u6b64\uff0c\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n log n) \u3002 \u6700\u574f\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n^2) \u3002\u6700\u574f\u60c5\u51b5\u53d1\u751f\u5728\u6bcf\u6b21\u9009\u62e9\u7684\u57fa\u51c6\u5143\u7d20\u90fd\u662f\u8f93\u5165\u6570\u636e\u4e2d\u7684\u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\uff0c\u5bfc\u81f4\u5206\u5272\u64cd\u4f5c\u4e0d\u5747\u8861\uff0c\u6bcf\u6b21\u5206\u5272\u53ea\u80fd\u5c06\u95ee\u9898\u89c4\u6a21\u51cf\u5c111\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u9000\u5316\u4e3a\u5192\u6ce1\u6392\u5e8f\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \u3002 \u5feb\u901f\u6392\u5e8f\u7684\u5e73\u5747\u548c\u6700\u597d\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n log n) \uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\u901a\u5e38\u6027\u80fd\u4f18\u8d8a\u3002\u7136\u800c\uff0c\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \uff0c\u56e0\u6b64\u5728\u5b9e\u73b0\u5feb\u901f\u6392\u5e8f\u65f6\u9700\u8981\u7279\u522b\u6ce8\u610f\u57fa\u51c6\u5143\u7d20\u7684\u9009\u62e9\u4ee5\u907f\u514d\u6700\u574f\u60c5\u51b5\u7684\u53d1\u751f\u3002","title":"3.5.1.2.\u5feb\u901f\u6392\u5e8f\u590d\u6742\u5ea6\u5206\u6790"},{"location":"python/DataStructure/03_TimeComplexity/#3513","text":"\u4ee5\u4e0a\u9762\u56fe\u793a\u7684\u5217\u8868 [12,19,17,18,14,11,15,13,16] \u4e3a\u4f8b\uff0c\u4e0b\u9762\u662f\u5b9e\u73b0\u4ee3\u7801\uff1a import random def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def quicksort ( lyst ): # left\u7684\u521d\u59cb\u503c\u662f0 # right\u7684\u521d\u59cb\u503c\u662f\u5217\u8868\u957f\u5ea6\u51cf1 quicksortHelper ( lyst , 0 , len ( lyst ) - 1 ) def quicksortHelper ( lyst , left , right ): print ( lyst ) if left < right : pivotLocation = partition ( lyst , left , right ) quicksortHelper ( lyst , left , pivotLocation - 1 ) quicksortHelper ( lyst , pivotLocation + 1 , right ) def partition ( lyst , left , right ): \"\"\"\u5bf9\u5217\u8868\u8fdb\u884c\u5206\u533a\"\"\" # \u627e\u5230\u57fa\u51c6\u5143\u7d20\uff08pivot\uff09\uff0c\u5e76\u548c\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u4e92\u6362 middle = ( left + right ) // 2 pivot = lyst [ middle ] lyst [ middle ] = lyst [ right ] lyst [ right ] = pivot # \u8bbe\u5b9a\u8fb9\u754c\u5143\u7d20\uff08boundary point\uff09\uff0c\u521d\u59cb\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20 boundary = left print ( \"pivot: \" , pivot , \"boundary: \" , lyst [ boundary ]) # \u628a\u6240\u6709\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u90fd\u79fb\u52a8\u5230\u8fb9\u754c\u7684\u5de6\u8fb9 for index in range ( left , right ): if lyst [ index ] < pivot : swap ( lyst , index , boundary ) boundary += 1 # \u4ea4\u6362\u57fa\u51c6\u5143\u7d20\u548c\u8fb9\u754c\u5143\u7d20 swap ( lyst , right , boundary ) print ( lyst ) return boundary def main ( size = 20 , sort = quicksort ): lyst = [ 12 , 19 , 17 , 18 , 14 , 11 , 15 , 13 , 16 ] sort ( lyst ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # [12, 19, 17, 18, 14, 11, 15, 13, 16] # pivot: 14 boundary: 12 # [12, 11, 13, 14, 16, 19, 15, 17, 18] # [12, 11, 13, 14, 16, 19, 15, 17, 18] # pivot: 11 boundary: 12 # [11, 13, 12, 14, 16, 19, 15, 17, 18] # [11, 13, 12, 14, 16, 19, 15, 17, 18] # [11, 13, 12, 14, 16, 19, 15, 17, 18] # pivot: 13 boundary: 12 # [11, 12, 13, 14, 16, 19, 15, 17, 18] # [11, 12, 13, 14, 16, 19, 15, 17, 18] # [11, 12, 13, 14, 16, 19, 15, 17, 18] # [11, 12, 13, 14, 16, 19, 15, 17, 18] # pivot: 15 boundary: 16 # [11, 12, 13, 14, 15, 19, 18, 17, 16] # [11, 12, 13, 14, 15, 19, 18, 17, 16] # [11, 12, 13, 14, 15, 19, 18, 17, 16] # pivot: 18 boundary: 19 # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] # pivot: 16 boundary: 17 # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] \u628amain()\u6539\u6210\u5982\u4e0b\uff0c\u5219\u53ef\u4ee5\u751f\u6210\u753120\u4e2a\u968f\u673a\u6574\u6570\u7ec4\u6210\u7684\u5217\u8868\uff1a def main ( size = 20 , sort = quicksort ): lyst = [] for count in range ( size ): lyst . append ( random . randint ( 1 , size + 1 )) print ( lyst ) sort ( lyst ) print ( lyst ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u7b2c\u4e00\u6b21\u8fd0\u884c # [3, 19, 18, 11, 2, 16, 2, 13, 14, 1, 20, 1, 1, 19, 19, 9, 16, 1, 7, 4] # [1, 1, 1, 1, 2, 2, 3, 4, 7, 9, 11, 13, 14, 16, 16, 18, 19, 19, 19, 20] # \u7b2c\u4e8c\u6b21\u8fd0\u884c # [20, 4, 1, 15, 6, 4, 3, 16, 21, 4, 12, 9, 16, 10, 3, 6, 2, 15, 21, 4] # [1, 2, 3, 3, 4, 4, 4, 4, 6, 6, 9, 10, 12, 15, 15, 16, 16, 20, 21, 21]","title":"3.5.1.3.\u5b9e\u73b0\u5feb\u901f\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#352","text":"\u5f52\u5e76\u6392\u5e8f\u7684\u7b97\u6cd5\u4e5f\u662f\u91c7\u7528\u5206\u6cbb\u6cd5\uff08Divide and Conquer\uff09\u7684\u4e00\u4e2a\u975e\u5e38\u5178\u578b\u7684\u5e94\u7528\uff0c\u901a\u8fc7\u9012\u5f52\u548c\u5206\u6cbb\u7b56\u7565\u6765\u7a81\u7834 O(n^2) \u6027\u80fd\u74f6\u9888\u7684\u3002 \u4e0b\u9762\u662f\u5bf9\u8fd9\u4e2a\u7b97\u6cd5\u7684\u7b80\u5355\u63cf\u8ff0\u3002 \u5206\u89e3\uff08Divide\uff09\uff1a\u5c06n\u4e2a\u5143\u7d20\u5206\u6210\u4e2a\u542bn/2\u4e2a\u5143\u7d20\u7684\u5b50\u5e8f\u5217\u3002 \u89e3\u51b3\uff08Conquer\uff09\uff1a\u7528\u5408\u5e76\u6392\u5e8f\u6cd5\u5bf9\u4e24\u4e2a\u5b50\u5e8f\u5217\u9012\u5f52\u7684\u6392\u5e8f\u3002 \u5408\u5e76\uff08Combine\uff09\uff1a\u5408\u5e76\u4e24\u4e2a\u5df2\u6392\u5e8f\u7684\u5b50\u5e8f\u5217\u5df2\u5f97\u5230\u6392\u5e8f\u7ed3\u679c\u3002 \u7b97\u6cd5\u601d\u8def\uff1a \u8fed\u4ee3\u6cd5 \u7533\u8bf7\u7a7a\u95f4\uff0c\u4f7f\u5176\u5927\u5c0f\u4e3a\u4e24\u4e2a\u5df2\u7ecf\u6392\u5e8f\u5e8f\u5217\u4e4b\u548c\uff0c\u8be5\u7a7a\u95f4\u7528\u6765\u5b58\u653e\u5408\u5e76\u540e\u7684\u5e8f\u5217\uff1b \u8bbe\u5b9a\u4e24\u4e2a\u6307\u9488\uff0c\u6700\u521d\u4f4d\u7f6e\u5206\u522b\u4e3a\u4e24\u4e2a\u5df2\u7ecf\u6392\u5e8f\u5e8f\u5217\u7684\u8d77\u59cb\u4f4d\u7f6e\uff1b \u6bd4\u8f83\u4e24\u4e2a\u6307\u9488\u6240\u6307\u5411\u7684\u5143\u7d20\uff0c\u9009\u62e9\u76f8\u5bf9\u5c0f\u7684\u5143\u7d20\u653e\u5165\u5230\u5408\u5e76\u7a7a\u95f4\uff0c\u5e76\u79fb\u52a8\u6307\u9488\u5230\u4e0b\u4e00\u4f4d\u7f6e\uff1b \u91cd\u590d\u6b65\u9aa43\u76f4\u5230\u67d0\u4e00\u6307\u9488\u5230\u8fbe\u5e8f\u5217\u5c3e\uff1b \u5c06\u53e6\u4e00\u5e8f\u5217\u5269\u4e0b\u7684\u6240\u6709\u5143\u7d20\u76f4\u63a5\u590d\u5236\u5230\u5408\u5e76\u5e8f\u5217\u5c3e\uff1b \u9012\u5f52\u6cd5 \u5c06\u5e8f\u5217\u6bcf\u76f8\u90bb\u4e24\u4e2a\u6570\u5b57\u8fdb\u884c\u5f52\u5e76\u64cd\u4f5c\uff0c\u5f62\u6210 floor(n/2) \u4e2a\u5e8f\u5217\uff0c\u6392\u5e8f\u540e\u6bcf\u4e2a\u5e8f\u5217\u5305\u542b\u4e24\u4e2a\u5143\u7d20\uff1b \u5c06\u4e0a\u8ff0\u5e8f\u5217\u518d\u6b21\u5f52\u5e76\uff0c\u5f62\u6210 floor(n/4) \u4e2a\u5e8f\u5217\uff0c\u6bcf\u4e2a\u5e8f\u5217\u5305\u542b\u56db\u4e2a\u5143\u7d20\uff1b \u91cd\u590d\u6b65\u9aa42\uff0c\u76f4\u5230\u6240\u6709\u5143\u7d20\u6392\u5e8f\u5b8c\u6bd5\uff1b \u5728\u9876\u5c42\u5b9a\u4e49\u4e863\u4e2aPython\u51fd\u6570\u8fdb\u884c\u534f\u4f5c\u3002 mergeSort \uff1a\u7528\u6237\u8c03\u7528\u7684\u51fd\u6570\uff1b mergeSortHelper \uff1a\u8f85\u52a9\u51fd\u6570\uff0c\u7528\u6765\u9690\u85cf\u9012\u5f52\u8c03\u7528\u6240\u9700\u8981\u7684\u989d\u5916\u53c2\u6570\uff1b merge \uff1a\u5b9e\u73b0\u5408\u5e76\u8fc7\u7a0b\u7684\u51fd\u6570\uff1b","title":"3.5.2.\u5f52\u5e76\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#3521","text":"\u5408\u5e76\u8fc7\u7a0b\u7528\u5230\u4e00\u4e2a\u4e0e\u5217\u8868\u5927\u5c0f\u76f8\u540c\u7684\u6570\u7ec4\uff0c\u8fd9\u4e2a\u6570\u7ec4\u53ef\u4ee5\u628a\u5b83\u79f0\u4e3a copyBuffer \u3002\u4e3a\u4e86\u907f\u514d\u6bcf\u6b21\u8c03\u7528 merge \u65f6\u90fd\u8981\u4e3a copyBuffer \u7684\u5206\u914d\u548c\u91ca\u653e\u4ea7\u751f\u5f00\u9500\uff0c\u8fd9\u4e2a\u7f13\u51b2\u533a\u4f1a\u5728 mergeSort \u51fd\u6570\u91cc\u5c31\u5206\u914d\u597d\uff0c\u7136\u540e\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7ed9 mergeSortHelper \u548c merge \u51fd\u6570\u3002\u6bcf\u6b21\u8c03\u7528 mergeSortHelper \u51fd\u6570\u65f6\uff0c\u5b83\u8fd8\u9700\u8981\u77e5\u9053\u5e94\u8be5\u4f7f\u7528\u7684\u5b50\u5217\u8868\u7684\u8303\u56f4\u3002\u8fd9\u4e2a\u8303\u56f4\u53ef\u4ee5\u7531\u53e6\u5916\u4e24\u4e2a\u53c2\u6570 low \u548c high \u6765\u63d0\u4f9b\u3002\u5177\u4f53\u5b9e\u73b0\u53c2\u8003 mergeSort \u51fd\u6570\u7684\u4ee3\u7801\u3002 \u5728\u68c0\u67e5\u4f20\u9012\u7684\u5b50\u5217\u8868\u662f\u4e0d\u662f\u81f3\u5c11\u6709\u4e24\u4e2a\u5143\u7d20\u4e4b\u540e\uff0c mergeSortHelper \u51fd\u6570\u5c06\u4f1a\u8ba1\u7b97\u8fd9\u4e2a\u5b50\u5217\u8868\u7684\u4e2d\u70b9\uff0c\u5e76\u4e14\u5bf9\u4e2d\u70b9\u5de6\u53f3\u4e24\u90e8\u5206\u8fdb\u884c\u9012\u5f52\u6392\u5e8f\uff0c\u6700\u540e\u518d\u8c03\u7528 merge \u51fd\u6570\u6765\u5408\u5e76\u7ed3\u679c\u3002\u5177\u4f53\u5b9e\u73b0\u53c2\u8003 mergeSortHelper \u51fd\u6570\u7684\u4ee3\u7801\u3002 merge \u51fd\u6570\u4f1a\u628a\u4e24\u4e2a\u5df2\u7ecf\u6392\u597d\u5e8f\u7684\u5b50\u5217\u8868\u5408\u5e76\u6210\u4e00\u4e2a\u66f4\u5927\u7684\u6709\u5e8f\u5217\u8868\u3002\u5728\u539f\u5217\u8868\u91cc\uff0c\u7b2c\u4e00\u4e2a\u5b50\u5217\u8868\u4f1a\u5728 low \u5230 middle \u4e4b\u95f4\uff1b\u7b2c\u4e8c\u4e2a\u5b50\u5217\u8868\u5219\u4f4d\u4e8e middle + 1 \u548c high \u4e4b\u95f4\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u5305\u542b\u5982\u4e0b3\u4e2a\u6b65\u9aa4\u3002 \u8bbe\u7f6e\u6307\u5411\u4e24\u4e2a\u5b50\u5217\u8868\u4e2d\u7b2c\u4e00\u4e2a\u5143\u7d20\u7684\u7d22\u5f15\u6307\u9488\u3002\u5b83\u4eec\u5206\u522b\u4f4d\u4e8e low \u548c middle +1 \uff1b \u4ece\u5b50\u5217\u8868\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\u91cd\u590d\u6bd4\u8f83\u8fd9\u4e9b\u5143\u7d20\u3002\u628a\u66f4\u5c0f\u7684\u90a3\u4e2a\u5143\u7d20\u4ece\u5b83\u6240\u5728\u7684\u5b50\u5217\u8868\u91cc\u590d\u5236\u5230\u62f7\u8d1d\u7f13\u51b2\u533a\u53bb\uff0c\u7136\u540e\u628a\u8fd9\u4e2a\u5b50\u5217\u8868\u7684\u7d22\u5f15\u79fb\u52a8\u5230\u4e0b\u4e00\u4e2a\u5143\u7d20\uff1b \u4e0d\u65ad\u5730\u6267\u884c\u8fd9\u4e2a\u64cd\u4f5c\uff0c\u76f4\u5230\u5df2\u7ecf\u5b8c\u5168\u590d\u5236\u4e86\u4e24\u4e2a\u5b50\u5217\u8868\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u5982\u679c\u5176\u4e2d\u4e00\u4e2a\u5b50\u5217\u8868\u5df2\u7ecf\u5230\u8fbe\u4e86\u672b\u5c3e\uff0c\u90a3\u4e48\u53ef\u4ee5\u628a\u53e6\u4e00\u4e2a\u5b50\u5217\u8868\u91cc\u7684\u5176\u4f59\u5143\u7d20\u76f4\u63a5\u590d\u5236\u8fc7\u53bb\uff1b \u628a copyBuffer \u4e2d low \u5230 high \u4e4b\u95f4\u7684\u90e8\u5206\u590d\u5236\u56de lyst \u4e2d\u7684\u76f8\u5e94\u4f4d\u7f6e\uff1b \u5b9e\u73b0\u4ee3\u7801\uff1a class Array ( object ): \"\"\" \u63cf\u8ff0\u4e00\u4e2a\u6570\u7ec4\u3002 \u6570\u7ec4\u7c7b\u4f3c\u5217\u8868\uff0c\u4f46\u6570\u7ec4\u53ea\u80fd\u4f7f\u7528[], len, iter, \u548c str\u8fd9\u4e9b\u5c5e\u6027\u3002 \u5b9e\u4f8b\u5316\u4e00\u4e2a\u6570\u7ec4\uff0c\u4f7f\u7528 = Array(, ) \u5176\u4e2dfill value\u9ed8\u8ba4\u503c\u662fNone\u3002 \"\"\" def __init__ ( self , capacity , fillValue = None ): \"\"\"Capacity\u662f\u6570\u7ec4\u7684\u5927\u5c0f. fillValue\u4f1a\u586b\u5145\u5728\u6bcf\u4e2a\u5143\u7d20\u4f4d\u7f6e, \u9ed8\u8ba4\u503c\u662fNone\"\"\" self . items = list () for count in range ( capacity ): self . items . append ( fillValue ) def __len__ ( self ): \"\"\"-> \u6570\u7ec4\u7684\u5927\u5c0f\"\"\" return len ( self . items ) def __str__ ( self ): \"\"\"-> \u5c06\u6570\u7ec4\u5b57\u7b26\u4e32\u5316\"\"\" return str ( self . items ) def __iter__ ( self ): \"\"\"\u652f\u6301for\u5faa\u73af\u5bf9\u6570\u7ec4\u8fdb\u884c\u904d\u5386.\"\"\" return iter ( self . items ) def __getitem__ ( self , index ): \"\"\"\u7528\u4e8e\u8bbf\u95ee\u7d22\u5f15\u5904\u7684\u4e0b\u6807\u8fd0\u7b97\u7b26.\"\"\" return self . items [ index ] def __setitem__ ( self , index , newItem ): \"\"\"\u4e0b\u6807\u8fd0\u7b97\u7b26\u7528\u4e8e\u5728\u7d22\u5f15\u5904\u8fdb\u884c\u66ff\u6362.\"\"\" self . items [ index ] = newItem def mergeSort ( lyst ): # lyst : \u7528\u4e8e\u6392\u5e8f\u7684\u5217\u8868 # copyBuffer : \u7528\u4e8e\u5408\u5e76\u7684\u4e34\u65f6\u7a7a\u95f4 copyBuffer = Array ( len ( lyst )) mergeSortHelper ( lyst , copyBuffer , 0 , len ( lyst ) - 1 ) def mergeSortHelper ( lyst , copyBuffer , low , high ): # lyst : \u7528\u4e8e\u6392\u5e8f\u7684\u5217\u8868 # copyBuffer : \u7528\u4e8e\u5408\u5e76\u7684\u4e34\u65f6\u7a7a\u95f4 # low, high : \u5b50\u5217\u8868\u7684\u8fb9\u754c # middle : \u5b50\u5217\u8868\u7684\u4e2d\u70b9 if low < high : middle = ( low + high ) // 2 print ( f 'low: { lyst [ low ] } , middle: { lyst [ middle ] } , high: { lyst [ high ] } , copyBuffer: { copyBuffer } ' ) # \u9012\u5f52\u5904\u7406\u7b2c\u4e00\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\uff0c\u5373\u4e2d\u503c\u7684\u5de6\u6bb5\uff0c\u76f4\u81f3\u4e0d\u6ee1\u8db3low < high\u65f6\u9000\u51fa mergeSortHelper ( lyst , copyBuffer , low , middle ) # \u9012\u5f52\u5904\u7406\u7b2c\u4e8c\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\uff0c\u5373\u4e2d\u503c\u7684\u53f3\u6bb5\uff0c\u76f4\u81f3\u4e0d\u6ee1\u8db3low < high\u65f6\u9000\u51fa mergeSortHelper ( lyst , copyBuffer , middle + 1 , high ) # \u5f53\u524d\u5904\u7406\u7684\u5b50\u8868\u6570\u636e\u9001\u5165copyBuffer\uff0c\u5408\u5e76\u4e14\u6392\u5e8f merge ( lyst , copyBuffer , low , middle , high ) def merge ( lyst , copyBuffer , low , middle , high ): # lyst : \u7528\u4e8e\u6392\u5e8f\u7684\u5217\u8868 # copyBuffer : \u7528\u4e8e\u5408\u5e76\u7684\u4e34\u65f6\u7a7a\u95f4 # low : \u7b2c\u4e00\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u5f00\u5934 # middle : \u7b2c\u4e00\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u7ed3\u5c3e # middle + 1 : \u7b2c\u4e8c\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u5f00\u5934 # high : \u7b2c\u4e8c\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u7ed3\u5c3e # \u5c06 i1 \u548c i2 \u521d\u59cb\u5316\u4e3a\u6bcf\u4e2a\u5b50\u5217\u8868\u4e2d\u7684\u7b2c\u4e00\u9879 i1 = low i2 = middle + 1 # \u5c06\u5b50\u5217\u8868\u4e2d\u7684\u5143\u7d20\u4ea4\u9519\u653e\u5165copyBuffer\u4e2d\uff0c\u5e76\u4fdd\u6301\u987a\u5e8f\u3002 for i in range ( low , high + 1 ): if i1 > middle : copyBuffer [ i ] = lyst [ i2 ] # \u7b2c\u4e00\u4e2a\u5b50\u5217\u8868\u5df2\u7528\u5b8c i2 += 1 elif i2 > high : copyBuffer [ i ] = lyst [ i1 ] # \u7b2c\u4e8c\u4e2a\u5b50\u5217\u8868\u5df2\u7528\u5b8c i1 += 1 elif lyst [ i1 ] < lyst [ i2 ]: copyBuffer [ i ] = lyst [ i1 ] # \u7b2c\u4e00\u4e2a\u5b50\u8868\u4e2d\u7684\u5143\u7d20 < i1 += 1 else : copyBuffer [ i ] = lyst [ i2 ] # \u7b2c\u4e8c\u4e2a\u5b50\u8868\u4e2d\u7684\u5143\u7d20 < i2 += 1 print ( \"i=\" , i , \"\" , \"i1=\" , i1 , \"i2=\" , i2 , \"copyBuffer:\" , copyBuffer ) for i in range ( low , high + 1 ): # \u5c06\u5df2\u6392\u5e8f\u7684\u5143\u7d20\u590d\u5236\u56delyst\u4e2d\u7684\u6b63\u786e\u4f4d\u7f6e lyst [ i ] = copyBuffer [ i ] def main (): lyst = [ 12 , 19 , 17 , 18 , 14 , 11 , 15 , 13 , 16 ] print ( \"Original List\" , lyst ) mergeSort ( lyst ) print ( \"Sorted List\" , lyst ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Original List [12, 19, 17, 18, 14, 11, 15, 13, 16] # low: 12, middle: 14, high: 16, copyBuffer: [None, None, None, None, None, None, None, None, None] # low: 12, middle: 17, high: 14, copyBuffer: [None, None, None, None, None, None, None, None, None] # low: 12, middle: 19, high: 17, copyBuffer: [None, None, None, None, None, None, None, None, None] # low: 12, middle: 12, high: 19, copyBuffer: [None, None, None, None, None, None, None, None, None] # i= 1 i1= 1 i2= 2 copyBuffer: [12, 19, None, None, None, None, None, None, None] # i= 2 i1= 2 i2= 3 copyBuffer: [12, 17, 19, None, None, None, None, None, None] # low: 18, middle: 18, high: 14, copyBuffer: [12, 17, 19, None, None, None, None, None, None] # i= 4 i1= 4 i2= 5 copyBuffer: [12, 17, 19, 14, 18, None, None, None, None] # i= 4 i1= 3 i2= 5 copyBuffer: [12, 14, 17, 18, 19, None, None, None, None] # low: 11, middle: 15, high: 16, copyBuffer: [12, 14, 17, 18, 19, None, None, None, None] # low: 11, middle: 11, high: 15, copyBuffer: [12, 14, 17, 18, 19, None, None, None, None] # i= 6 i1= 6 i2= 7 copyBuffer: [12, 14, 17, 18, 19, 11, 15, None, None] # low: 13, middle: 13, high: 16, copyBuffer: [12, 14, 17, 18, 19, 11, 15, None, None] # i= 8 i1= 8 i2= 9 copyBuffer: [12, 14, 17, 18, 19, 11, 15, 13, 16] # i= 8 i1= 7 i2= 9 copyBuffer: [12, 14, 17, 18, 19, 11, 13, 15, 16] # i= 8 i1= 5 i2= 9 copyBuffer: [11, 12, 13, 14, 15, 16, 17, 18, 19] # Sorted List [11, 12, 13, 14, 15, 16, 17, 18, 19] \u8fd0\u884c\u7ed3\u679c\u56fe\u793a\u5206\u6790\uff1a","title":"3.5.2.1.\u5408\u5e76\u8fc7\u7a0b\u7684\u5b9e\u73b0"},{"location":"python/DataStructure/03_TimeComplexity/#3522","text":"merge \u51fd\u6570\u7684\u8fd0\u884c\u65f6\u7531\u4e24\u4e2a for \u8bed\u53e5\u6765\u51b3\u5b9a\uff0c\u800c\u8fd9\u4e24\u4e2a\u5faa\u73af\u90fd\u4f1a\u88ab\u8fed\u4ee3 (high \u2013 low + 1) \u6b21\uff0c\u56e0\u6b64\uff0c\u8fd9\u4e2a\u51fd\u6570\u7684\u8fd0\u884c\u65f6\u662f O(high\u2212low) \uff0c\u4e8e\u662f\u6bcf\u4e00\u5c42\u4e0a\u7684\u6240\u6709\u5408\u5e76\u603b\u5171\u9700\u8981 O(n) \u7684\u65f6\u95f4\u3002\u56e0\u4e3a mergeSortHelper \u5728\u6bcf\u4e00\u5c42\u90fd\u5c3d\u53ef\u80fd\u5747\u5300\u5730\u62c6\u5206\u5b50\u5217\u8868\uff0c\u6240\u4ee5\u5c42\u6570\u5e94\u8be5\u662f O(log n) \uff0c\u5728\u6240\u6709\u7684\u60c5\u51b5\u4e0b\u8fd9\u4e2a\u51fd\u6570\u7684\u6700\u5927\u8fd0\u884c\u65f6\u90fd\u662f O(n log n) \u3002 \u5f52\u5e76\u6392\u5e8f\u4f1a\u6709\u4e24\u4e2a\u57fa\u4e8e\u5217\u8868\u5927\u5c0f\u7684\u7a7a\u95f4\u9700\u6c42\u3002\u9996\u5148\uff0c\u5728\u8c03\u7528\u6808\u4e0a\u9700\u8981 O(log n) \u7684\u7a7a\u95f4\u6765\u652f\u6301\u9012\u5f52\u8c03\u7528\uff1b\u5176\u6b21\uff0c\u62f7\u8d1d\u7f13\u51b2\u533a\u4f1a\u7528\u5230 O(n) \u7684\u7a7a\u95f4\u3002","title":"3.5.2.2.\u5f52\u5e76\u6392\u5e8f\u7684\u590d\u6742\u5ea6\u5206\u6790"},{"location":"python/DataStructure/03_TimeComplexity/#353","text":"\u63cf\u8ff0\u5feb\u901f\u6392\u5e8f\u7684\u7b56\u7565\uff0c\u5e76\u8bf4\u660e\u4e3a\u4ec0\u4e48\u5b83\u53ef\u4ee5\u628a\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ece O(n^2) \u964d\u4f4e\u5230 O(n log n) \u3002 \u89e3\u7b54\uff1a\u5feb\u901f\u6392\u5e8f\uff08Quick Sort\uff09\u662f\u4e00\u79cd\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u5b83\u91c7\u7528\u5206\u6cbb\u7b56\u7565\u6765\u5c06\u4e00\u4e2a\u5927\u95ee\u9898\u5206\u89e3\u6210\u82e5\u5e72\u4e2a\u5b50\u95ee\u9898\uff0c\u7136\u540e\u9012\u5f52\u5730\u89e3\u51b3\u8fd9\u4e9b\u5b50\u95ee\u9898\u3002\u4ee5\u4e0b\u662f\u5feb\u901f\u6392\u5e8f\u7684\u7b56\u7565\u548c\u539f\u7406\uff0c\u4ee5\u53ca\u4e3a\u4ec0\u4e48\u5b83\u80fd\u591f\u5c06\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ece O(n^2) \u964d\u4f4e\u5230 O(n log n) \uff1a \u5feb\u901f\u6392\u5e8f\u7684\u7b56\u7565\uff1a \u9009\u62e9\u4e3b\u5143\uff08Pivot\uff09\uff1a\u5728\u5feb\u901f\u6392\u5e8f\u4e2d\uff0c\u9996\u5148\u4ece\u5f85\u6392\u5e8f\u7684\u5143\u7d20\u4e2d\u9009\u62e9\u4e00\u4e2a\u4e3b\u5143\uff08\u901a\u5e38\u662f\u7b2c\u4e00\u4e2a\u6216\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff09\uff0c\u4e5f\u53eb\u57fa\u51c6\u5143\u7d20\u3002 \u5206\u5272\u64cd\u4f5c\uff1a\u5c06\u5143\u7d20\u5206\u4e3a\u4e24\u4e2a\u5b50\u6570\u7ec4\uff0c\u4e00\u4e2a\u5c0f\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\uff0c\u4e00\u4e2a\u5927\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u79f0\u4e3a\u5206\u5272\u3002 \u9012\u5f52\u6392\u5e8f\uff1a\u9012\u5f52\u5730\u5bf9\u4e24\u4e2a\u5b50\u6570\u7ec4\u8fdb\u884c\u6392\u5e8f\u3002\u5373\uff0c\u5bf9\u5c0f\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\u548c\u5927\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\u5206\u522b\u8fdb\u884c\u5feb\u901f\u6392\u5e8f\u3002 \u5408\u5e76\uff1a\u5c06\u5df2\u6392\u5e8f\u7684\u5b50\u6570\u7ec4\u5408\u5e76\u6210\u6700\u7ec8\u7684\u6709\u5e8f\u6570\u7ec4\u3002 \u4e3a\u4ec0\u4e48\u5feb\u901f\u6392\u5e8f\u80fd\u591f\u964d\u4f4e\u65f6\u95f4\u590d\u6742\u5ea6\uff1a \u5feb\u901f\u6392\u5e8f\u4e4b\u6240\u4ee5\u80fd\u591f\u5c06\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ece O(n^2) \u964d\u4f4e\u5230 O(n log n) \uff0c\u4e3b\u8981\u6709\u4ee5\u4e0b\u539f\u56e0\uff1a \u5206\u6cbb\u7b56\u7565\uff1a\u5feb\u901f\u6392\u5e8f\u91c7\u7528\u4e86\u5206\u6cbb\u7b56\u7565\uff0c\u5c06\u4e00\u4e2a\u5927\u95ee\u9898\u5206\u89e3\u6210\u4e24\u4e2a\u6216\u591a\u4e2a\u89c4\u6a21\u8f83\u5c0f\u7684\u5b50\u95ee\u9898\u3002\u8fd9\u79cd\u5206\u6cbb\u7b56\u7565\u80fd\u591f\u51cf\u5c0f\u95ee\u9898\u7684\u89c4\u6a21\uff0c\u4ece\u800c\u964d\u4f4e\u4e86\u89e3\u51b3\u95ee\u9898\u7684\u590d\u6742\u5ea6\u3002 \u597d\u7684\u5e73\u5747\u60c5\u51b5\uff1a\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u5bf9\u5f85\u6392\u5e8f\u7684\u6570\u636e\u8fdb\u884c\u4e86\u826f\u597d\u7684\u5e73\u5747\u5206\u5272\uff0c\u6bcf\u6b21\u5206\u5272\u90fd\u5c06\u95ee\u9898\u89c4\u6a21\u51cf\u534a\u3002\u8fd9\u4f7f\u5f97\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n log n) \u3002 **\u4e0d\u7a33\u5b9a\u6027\uff1a\u5feb\u901f\u6392\u5e8f\u662f\u4e0d\u7a33\u5b9a\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u8fd9\u610f\u5473\u7740\u76f8\u540c\u5143\u7d20\u7684\u76f8\u5bf9\u987a\u5e8f\u5728\u6392\u5e8f\u540e\u53ef\u80fd\u4f1a\u6539\u53d8\u3002\u8fd9\u79cd\u4e0d\u7a33\u5b9a\u6027\u4f7f\u5f97\u5feb\u901f\u6392\u5e8f\u53ef\u4ee5\u66f4\u5feb\u5730\u6392\u5e8f\u76f8\u540c\u5143\u7d20\u7684\u5927\u6570\u636e\u96c6\u3002 \u539f\u5730\u6392\u5e8f\uff1a\u5feb\u901f\u6392\u5e8f\u901a\u5e38\u662f\u539f\u5730\u6392\u5e8f\u7684\uff0c\u5b83\u4e0d\u9700\u8981\u989d\u5916\u7684\u5185\u5b58\u6765\u5b58\u50a8\u4e34\u65f6\u6570\u636e\u3002\u8fd9\u5bf9\u4e8e\u5185\u5b58\u5360\u7528\u6709\u9650\u7684\u60c5\u51b5\u5f88\u6709\u5229\u3002 \u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662f O(n^2) \uff0c\u8fd9\u79cd\u60c5\u51b5\u901a\u5e38\u53d1\u751f\u5728\u4e3b\u5143\u9009\u62e9\u4e0d\u5f53\u6216\u8f93\u5165\u6570\u636e\u5df2\u7ecf\u6709\u5e8f\u7684\u60c5\u51b5\u4e0b\u3002\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u901a\u5e38\u9700\u8981\u9009\u62e9\u4e00\u4e2a\u5408\u9002\u7684\u4e3b\u5143\u9009\u62e9\u7b56\u7565\uff0c\u4ee5\u5c3d\u91cf\u907f\u514d\u6700\u574f\u60c5\u51b5\u7684\u53d1\u751f\u3002 \u4e3a\u4ec0\u4e48\u5feb\u901f\u6392\u5e8f\u5e76\u4e0d\u5728\u6240\u6709\u60c5\u51b5\u4e0b\u90fd\u6709 O(n log n) \u7684\u590d\u6742\u5ea6\uff1f\u5bf9\u5feb\u901f\u6392\u5e8f\u7684\u6700\u574f\u60c5\u51b5\u8fdb\u884c\u63cf\u8ff0\uff0c\u5e76\u7ed9\u51fa\u4e00\u4e2a\u4f1a\u4ea7\u751f\u8fd9\u4e2a\u60c5\u51b5\u7684\u5305\u542b10\u4e2a\u6574\u6570\uff081\uff5e10\uff09\u7684\u5217\u8868\u3002 \u89e3\u7b54\uff1a\u5feb\u901f\u6392\u5e8f\u5e76\u4e0d\u5728\u6240\u6709\u60c5\u51b5\u4e0b\u90fd\u5177\u6709 O(n log n) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\uff0c\u5b83\u7684\u6027\u80fd\u53d6\u51b3\u4e8e\u4e3b\u5143\uff08pivot\uff09\u7684\u9009\u62e9\u548c\u8f93\u5165\u6570\u636e\u7684\u5206\u5e03\u60c5\u51b5\u3002\u6700\u574f\u60c5\u51b5\u53d1\u751f\u5728\u4ee5\u4e0b\u60c5\u51b5\u4e0b\uff1a \u4e3b\u5143\u9009\u62e9\u4e0d\u5f53\uff1a\u5982\u679c\u6bcf\u6b21\u9009\u62e9\u7684\u4e3b\u5143\u90fd\u662f\u8f93\u5165\u6570\u636e\u4e2d\u7684\u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\uff0c\u5feb\u901f\u6392\u5e8f\u5c06\u4f1a\u4ea7\u751f\u6700\u574f\u60c5\u51b5\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5206\u5272\u64cd\u4f5c\u5c06\u5bfc\u81f4\u4e00\u4e2a\u5b50\u6570\u7ec4\u4e3a\u7a7a\uff0c\u53e6\u4e00\u4e2a\u5b50\u6570\u7ec4\u7684\u5927\u5c0f\u4e3a\u539f\u59cb\u6570\u7ec4\u5927\u5c0f\u51cf\u4e00\u3002\u8fd9\u4f7f\u5f97\u6bcf\u6b21\u5206\u5272\u64cd\u4f5c\u53ea\u51cf\u5c11\u4e00\u4e2a\u5143\u7d20\uff0c\u5bfc\u81f4\u9012\u5f52\u6df1\u5ea6\u8fbe\u5230\u6700\u5927\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \u3002 \u8f93\u5165\u6570\u636e\u5df2\u7ecf\u6709\u5e8f\uff1a\u5982\u679c\u8f93\u5165\u6570\u636e\u5df2\u7ecf\u662f\u6709\u5e8f\u7684\uff0c\u4e0d\u7ba1\u662f\u5347\u5e8f\u8fd8\u662f\u964d\u5e8f\uff0c\u5feb\u901f\u6392\u5e8f\u4e5f\u4f1a\u4ea7\u751f\u6700\u574f\u60c5\u51b5\u3002\u56e0\u4e3a\u65e0\u8bba\u5982\u4f55\u9009\u62e9\u4e3b\u5143\uff0c\u5206\u5272\u64cd\u4f5c\u90fd\u5c06\u5bfc\u81f4\u4e00\u4e2a\u5b50\u6570\u7ec4\u4e3a\u7a7a\uff0c\u53e6\u4e00\u4e2a\u5b50\u6570\u7ec4\u7684\u5927\u5c0f\u4e3a\u539f\u59cb\u6570\u7ec4\u5927\u5c0f\u51cf\u4e00\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u5305\u542b10\u4e2a\u6574\u6570\uff081\uff5e10\uff09\u7684\u5217\u8868\uff0c\u6f14\u793a\u4e86\u5bfc\u81f4\u5feb\u901f\u6392\u5e8f\u6700\u574f\u60c5\u51b5\u7684\u8f93\u5165\u6570\u636e\uff1a [ 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 ] \u5728\u8fd9\u4e2a\u793a\u4f8b\u4e2d\uff0c\u6bcf\u6b21\u9009\u62e9\u7684\u4e3b\u5143\u90fd\u662f\u6700\u5927\u7684\u5143\u7d20\uff0810\uff09\uff0c\u5bfc\u81f4\u5206\u5272\u64cd\u4f5c\u4e0d\u65ad\u51cf\u5c11\u6570\u7ec4\u7684\u5927\u5c0f\uff0c\u9012\u5f52\u6df1\u5ea6\u8fbe\u5230\u6700\u5927\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \u3002 \u8981\u907f\u514d\u6700\u574f\u60c5\u51b5\uff0c\u901a\u5e38\u91c7\u7528\u4ee5\u4e0b\u7b56\u7565\uff1a \u9009\u62e9\u5408\u9002\u7684\u4e3b\u5143\uff0c\u4f8b\u5982\u9009\u62e9\u4e2d\u95f4\u5143\u7d20\uff0c\u4ee5\u786e\u4fdd\u5e73\u5747\u5206\u5272\u3002 \u968f\u673a\u9009\u62e9\u4e3b\u5143\uff0c\u4ee5\u51cf\u5c11\u51fa\u73b0\u6700\u574f\u60c5\u51b5\u7684\u6982\u7387\u3002 \u8fd9\u4e9b\u7b56\u7565\u6709\u52a9\u4e8e\u7ef4\u6301\u5feb\u901f\u6392\u5e8f\u7684\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n log n) \u3002 \u5feb\u901f\u6392\u5e8f\u91cc\u7684\u5206\u5272\u64cd\u4f5c\u4f1a\u9009\u62e9\u4e2d\u70b9\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\u3002\u8bf7\u63cf\u8ff0\u53e6\u5916\u4e24\u79cd\u9009\u62e9\u57fa\u51c6\u7684\u7b56\u7565\u3002 \u89e3\u7b54\uff1a\u5feb\u901f\u6392\u5e8f\u4e2d\u7684\u5206\u5272\u64cd\u4f5c\u53ef\u4ee5\u9009\u62e9\u4e2d\u70b9\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\uff0c\u4f46\u8fd8\u6709\u5176\u4ed6\u4e24\u79cd\u5e38\u89c1\u7684\u9009\u62e9\u57fa\u51c6\u7684\u7b56\u7565\uff0c\u5b83\u4eec\u5206\u522b\u662f\uff1a \u968f\u673a\u9009\u62e9\u57fa\u51c6\uff08Random Pivot\uff09\uff1a\u8fd9\u79cd\u7b56\u7565\u662f\u5728\u5f85\u6392\u5e8f\u6570\u7ec4\u4e2d\u968f\u673a\u9009\u62e9\u4e00\u4e2a\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\u3002\u968f\u673a\u9009\u62e9\u57fa\u51c6\u7684\u597d\u5904\u662f\u53ef\u4ee5\u964d\u4f4e\u51fa\u73b0\u6700\u574f\u60c5\u51b5\u7684\u6982\u7387\uff0c\u56e0\u4e3a\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u968f\u673a\u9009\u62e9\u7684\u57fa\u51c6\u4f1a\u6bd4\u56fa\u5b9a\u4f4d\u7f6e\u7684\u57fa\u51c6\u66f4\u5e73\u5747\u5730\u5212\u5206\u6570\u636e\u3002\u8fd9\u53ef\u4ee5\u63d0\u9ad8\u7b97\u6cd5\u7684\u6027\u80fd\u3002 \u4e09\u6570\u53d6\u4e2d\u6cd5\uff08Median-of-Three Pivot\uff09\uff1a\u8fd9\u79cd\u7b56\u7565\u662f\u5728\u5f85\u6392\u5e8f\u6570\u7ec4\u4e2d\u9009\u62e9\u4e09\u4e2a\u5143\u7d20\uff08\u901a\u5e38\u662f\u7b2c\u4e00\u4e2a\u3001\u4e2d\u95f4\u4e00\u4e2a\u548c\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff09\uff0c\u7136\u540e\u4ece\u8fd9\u4e09\u4e2a\u5143\u7d20\u4e2d\u9009\u62e9\u4e2d\u95f4\u503c\u4f5c\u4e3a\u57fa\u51c6\u3002\u8fd9\u4e2a\u7b56\u7565\u7684\u76ee\u7684\u662f\u5728\u5c3d\u91cf\u907f\u514d\u6700\u574f\u60c5\u51b5\u7684\u540c\u65f6\uff0c\u4fdd\u6301\u57fa\u51c6\u7684\u76f8\u5bf9\u4e2d\u95f4\u4f4d\u7f6e\u3002\u8fd9\u53ef\u4ee5\u63d0\u9ad8\u7b97\u6cd5\u7684\u5e73\u5747\u6027\u80fd\u3002 \u8fd9\u4e09\u79cd\u9009\u62e9\u57fa\u51c6\u7684\u7b56\u7565\u5404\u6709\u4f18\u52a3\uff0c\u4f46\u5b83\u4eec\u7684\u5171\u540c\u76ee\u6807\u662f\u964d\u4f4e\u6700\u574f\u60c5\u51b5\u7684\u6982\u7387\uff0c\u4ece\u800c\u63d0\u9ad8\u5feb\u901f\u6392\u5e8f\u7684\u6027\u80fd\u3002\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u9009\u62e9\u54ea\u79cd\u7b56\u7565\u53d6\u51b3\u4e8e\u5177\u4f53\u7684\u60c5\u51b5\u548c\u5b9e\u73b0\u3002 \u5f53\u5feb\u901f\u6392\u5e8f\u91cc\u7684\u5b50\u5217\u8868\u7684\u957f\u5ea6\u5c0f\u4e8e\u67d0\u4e2a\u6570\u5b57\uff08\u598230\uff09\u65f6\uff0c\u6267\u884c\u63d2\u5165\u6392\u5e8f\u6765\u5904\u7406\u8fd9\u4e2a\u5b50\u5217\u8868\u3002\u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u8fd9\u662f\u4e00\u4e2a\u597d\u65b9\u6cd5\u3002 \u89e3\u7b54\uff1a\u5728\u5feb\u901f\u6392\u5e8f\u4e2d\uff0c\u5f53\u5b50\u5217\u8868\u7684\u957f\u5ea6\u53d8\u5f97\u5f88\u5c0f\u65f6\uff08\u901a\u5e38\u5c0f\u4e8e\u67d0\u4e2a\u9884\u5b9a\u7684\u9608\u503c\uff0c\u598230\u6216\u5176\u4ed6\u7ecf\u9a8c\u503c\uff09\uff0c\u6267\u884c\u63d2\u5165\u6392\u5e8f\u6765\u5904\u7406\u8fd9\u4e2a\u5b50\u5217\u8868\u662f\u4e00\u4e2a\u597d\u65b9\u6cd5\uff0c\u4e3b\u8981\u57fa\u4e8e\u4ee5\u4e0b\u8003\u8651\uff1a \u63d2\u5165\u6392\u5e8f\u5bf9\u5c0f\u89c4\u6a21\u6570\u636e\u8868\u73b0\u826f\u597d\uff1a\u63d2\u5165\u6392\u5e8f\u662f\u4e00\u79cd\u7b80\u5355\u4f46\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u7279\u522b\u9002\u7528\u4e8e\u5c0f\u89c4\u6a21\u6570\u636e\u96c6\u3002\u5b83\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \uff0c\u4f46\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u5bf9\u4e8e\u5c0f\u89c4\u6a21\u7684\u6570\u636e\uff0c\u5b83\u7684\u6027\u80fd\u901a\u5e38\u5f88\u597d\u3002 \u51cf\u5c11\u9012\u5f52\u6df1\u5ea6\uff1a\u5728\u5feb\u901f\u6392\u5e8f\u4e2d\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u90fd\u4f1a\u589e\u52a0\u9012\u5f52\u6df1\u5ea6\uff0c\u800c\u9012\u5f52\u6df1\u5ea6\u8fc7\u5927\u53ef\u80fd\u4f1a\u5bfc\u81f4\u6808\u6ea2\u51fa\u6216\u6027\u80fd\u4e0b\u964d\u3002\u5f53\u5b50\u5217\u8868\u957f\u5ea6\u5c0f\u4e8e\u67d0\u4e2a\u9608\u503c\u65f6\uff0c\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u53ef\u4ee5\u907f\u514d\u4e0d\u5fc5\u8981\u7684\u9012\u5f52\u6df1\u5ea6\uff0c\u4ece\u800c\u51cf\u5c11\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u3002 \u9002\u7528\u4e8e\u90e8\u5206\u6709\u5e8f\u7684\u5b50\u5217\u8868\uff1a\u5f53\u5b50\u5217\u8868\u5df2\u7ecf\u90e8\u5206\u6709\u5e8f\u65f6\uff0c\u63d2\u5165\u6392\u5e8f\u7684\u6027\u80fd\u901a\u5e38\u6bd4\u5feb\u901f\u6392\u5e8f\u66f4\u597d\u3002\u56e0\u6b64\uff0c\u5bf9\u4e8e\u53ef\u80fd\u5305\u542b\u5df2\u6392\u5e8f\u90e8\u5206\u7684\u5c0f\u5b50\u5217\u8868\uff0c\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u53ef\u4ee5\u63d0\u9ad8\u7b97\u6cd5\u7684\u6548\u7387\u3002 \u51cf\u5c11\u9012\u5f52\u5f00\u9500\uff1a\u9012\u5f52\u5f00\u9500\u662f\u5feb\u901f\u6392\u5e8f\u7684\u4e00\u4e2a\u4e0d\u53ef\u5ffd\u89c6\u7684\u56e0\u7d20\uff0c\u7279\u522b\u662f\u5728\u5904\u7406\u5c0f\u89c4\u6a21\u5b50\u5217\u8868\u65f6\u3002\u901a\u8fc7\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u6765\u5904\u7406\u8fd9\u4e9b\u5c0f\u89c4\u6a21\u5b50\u5217\u8868\uff0c\u53ef\u4ee5\u51cf\u5c11\u9012\u5f52\u5f00\u9500\uff0c\u63d0\u9ad8\u7b97\u6cd5\u7684\u6574\u4f53\u6027\u80fd\u3002 \u5c06\u63d2\u5165\u6392\u5e8f\u4e0e\u5feb\u901f\u6392\u5e8f\u7ed3\u5408\u4f7f\u7528\u662f\u4e00\u79cd\u5e38\u89c1\u7684\u4f18\u5316\u7b56\u7565\uff0c\u5b83\u53ef\u4ee5\u5728\u5904\u7406\u5c0f\u89c4\u6a21\u5b50\u5217\u8868\u65f6\u63d0\u9ad8\u7b97\u6cd5\u7684\u6548\u7387\uff0c\u540c\u65f6\u4fdd\u6301\u5feb\u901f\u6392\u5e8f\u7684\u6574\u4f53\u6027\u80fd\u3002\u8fd9\u79cd\u65b9\u6cd5\u88ab\u79f0\u4e3a\u201c\u5feb\u901f\u6392\u5e8f\u7684\u6539\u8fdb\u201d\u6216\u201c\u5feb\u901f\u6392\u5e8f\u7684\u6df7\u5408\u6392\u5e8f\u201d\u7b56\u7565\uff0c\u7528\u4e8e\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\u63d0\u9ad8\u7b97\u6cd5\u7684\u6548\u7387\u3002 \u4e3a\u4ec0\u4e48\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4e5f\u662f\u4e00\u4e2a O(n log n) \u7b97\u6cd5\uff1f \u89e3\u7b54\uff1a\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4ecd\u7136\u5177\u6709 O(n log n) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\uff0c\u8fd9\u662f\u56e0\u4e3a\u5f52\u5e76\u6392\u5e8f\u7684\u7b97\u6cd5\u8bbe\u8ba1\u4f7f\u5176\u80fd\u591f\u7a33\u5b9a\u5730\u4fdd\u6301\u8fd9\u79cd\u6027\u80fd\uff0c\u4e0d\u53d7\u8f93\u5165\u6570\u636e\u5206\u5e03\u7684\u5f71\u54cd\u3002 \u4ee5\u4e0b\u662f\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4ecd\u7136\u5177\u6709 O(n log n) \u65f6\u95f4\u590d\u6742\u5ea6\u7684\u539f\u56e0\uff1a \u5206\u800c\u6cbb\u4e4b\u7b56\u7565\uff1a\u5f52\u5e76\u6392\u5e8f\u91c7\u7528\u4e86\u5206\u800c\u6cbb\u4e4b\u7684\u7b56\u7565\uff0c\u5c06\u95ee\u9898\u5206\u89e3\u4e3a\u8f83\u5c0f\u7684\u5b50\u95ee\u9898\uff0c\u7136\u540e\u5408\u5e76\u8fd9\u4e9b\u5b50\u95ee\u9898\u7684\u89e3\u3002\u8fd9\u4e2a\u7b56\u7565\u786e\u4fdd\u4e86\u7b97\u6cd5\u7684\u9012\u5f52\u6df1\u5ea6\u5728 log n \u7ea7\u522b\uff0c\u56e0\u4e3a\u6bcf\u6b21\u9012\u5f52\u90fd\u5c06\u6570\u636e\u5212\u5206\u6210\u4e24\u534a\uff0c\u76f4\u5230\u6700\u5c0f\u5b50\u95ee\u9898\u7684\u5927\u5c0f\u4e3a1\u3002 \u5408\u5e76\u64cd\u4f5c\u7684\u7ebf\u6027\u65f6\u95f4\uff1a\u5f52\u5e76\u6392\u5e8f\u7684\u5173\u952e\u64cd\u4f5c\u662f\u5408\u5e76\u5df2\u6392\u5e8f\u7684\u5b50\u6570\u7ec4\u3002\u5408\u5e76\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f\u7ebf\u6027\u7684\uff0c\u4e0e\u8f93\u5165\u6570\u636e\u7684\u89c4\u6a21 n \u6210\u6b63\u6bd4\u3002\u56e0\u6b64\uff0c\u5373\u4f7f\u5728\u5408\u5e76\u9636\u6bb5\uff0c\u7b97\u6cd5\u7684\u603b\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u53d7\u9650\u4e8e O(n log n) \u3002 \u7a33\u5b9a\u6027\uff1a\u5f52\u5e76\u6392\u5e8f\u662f\u4e00\u79cd\u7a33\u5b9a\u6392\u5e8f\u7b97\u6cd5\uff0c\u610f\u5473\u7740\u5b83\u5728\u6392\u5e8f\u76f8\u7b49\u5143\u7d20\u65f6\u4f1a\u4fdd\u6301\u5b83\u4eec\u7684\u76f8\u5bf9\u987a\u5e8f\u3002\u8fd9\u4e00\u6027\u8d28\u4f7f\u5f97\u7b97\u6cd5\u5728\u5904\u7406\u76f8\u7b49\u5143\u7d20\u6216\u8005\u5177\u6709\u7279\u5b9a\u6570\u636e\u5206\u5e03\u7684\u60c5\u51b5\u4e0b\u4ecd\u7136\u4fdd\u6301 O(n log n) \u7684\u6027\u80fd\uff0c\u800c\u4e0d\u4f1a\u51fa\u73b0\u6700\u574f\u60c5\u51b5\u3002 \u65e0\u8bba\u8f93\u5165\u6570\u636e\u5982\u4f55\u5206\u5e03\uff0c\u5f52\u5e76\u6392\u5e8f\u7684\u5206\u5272\u548c\u5408\u5e76\u64cd\u4f5c\u90fd\u662f\u786e\u5b9a\u6027\u7684\uff1a\u5f52\u5e76\u6392\u5e8f\u7684\u6bcf\u4e00\u6b65\u90fd\u662f\u786e\u5b9a\u6027\u7684\uff0c\u4e0d\u53d7\u8f93\u5165\u6570\u636e\u5206\u5e03\u7684\u5f71\u54cd\u3002\u4e0d\u50cf\u5feb\u901f\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u53ef\u80fd\u51fa\u73b0\u5206\u5272\u6781\u4e0d\u5e73\u8861\u7684\u60c5\u51b5\uff0c\u5bfc\u81f4\u6027\u80fd\u4e0b\u964d\u3002 \u56e0\u6b64\uff0c\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4ecd\u7136\u80fd\u591f\u4fdd\u6301 O(n log n) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\uff0c\u4f7f\u5176\u6210\u4e3a\u4e00\u79cd\u53ef\u9760\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u7279\u522b\u9002\u7528\u4e8e\u5bf9\u7a33\u5b9a\u6027\u548c\u6027\u80fd\u6709\u8981\u6c42\u7684\u60c5\u51b5\u3002","title":"3.5.3.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/03_TimeComplexity/#36","text":"","title":"3.6.\u6307\u6570\u590d\u6742\u5ea6\u7684\u7b97\u6cd5"},{"location":"python/DataStructure/03_TimeComplexity/#_1","text":"\u4e0b\u9762\u662f\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7b97\u6cd5\u7684\u4f8b\u5b50\u3002 def fib ( n , depth = 0 ): \"\"\"\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u6570\u5217\"\"\" if n <= 1 : return 1 else : print ( f 'Depth: { depth } ,fib( { n } ) calls fib( { n - 1 } ) and fib( { n - 2 } )' ) return fib ( n - 1 , depth + 1 ) + fib ( n - 2 , depth + 1 ) def main (): fib ( 6 ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Depth:0,fib(6) calls fib(5) and fib(4) # Depth:1,fib(5) calls fib(4) and fib(3) # Depth:2,fib(4) calls fib(3) and fib(2) # Depth:3,fib(3) calls fib(2) and fib(1) # Depth:4,fib(2) calls fib(1) and fib(0) # Depth:3,fib(2) calls fib(1) and fib(0) # Depth:2,fib(3) calls fib(2) and fib(1) # Depth:3,fib(2) calls fib(1) and fib(0) # Depth:1,fib(4) calls fib(3) and fib(2) # Depth:2,fib(3) calls fib(2) and fib(1) # Depth:3,fib(2) calls fib(1) and fib(0) # Depth:2,fib(2) calls fib(1) and fib(0) \u4e0a\u4f8b\u53ef\u4ee5\u770b\u51fa\uff0c\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7b97\u6cd5\u7684\u8c03\u7528\u6b21\u6570\u6bd4\u95ee\u9898\u89c4\u6a21\u7684\u5e73\u65b9\u6570\u589e\u957f\u7684\u8fd8\u8981\u5feb\u5f88\u591a\u3002\u4f8b\u5982\uff0c fib(4) \u53ea\u9700\u89814\u6b21\u9012\u5f52\u8c03\u7528\uff0c\u770b\u8d77\u6765\u5b83\u597d\u50cf\u662f\u7ebf\u6027\u589e\u957f\u7684\uff0c\u4f46\u5728\u603b\u5171\u768414\u6b21\u9012\u5f52\u8c03\u7528\u91cc\uff0c fib(6) \u9700\u8981\u8c03\u75282\u6b21 fib(4) \u3002\u968f\u7740\u95ee\u9898\u89c4\u6a21\u7684\u6269\u5927\uff0c\u5de5\u4f5c\u91cf\u4f1a\u663e\u8457\u589e\u52a0\uff0c\u8fd9\u662f\u56e0\u4e3a\u5728\u8c03\u7528\u6811\uff08call tree\uff09\u91cc\u53ef\u80fd\u6709\u5f88\u591a\u91cd\u590d\u7684\u76f8\u540c\u5b50\u6811\u3002 \u5982\u679c\u8fd9\u68f5\u8c03\u7528\u6811\u662f\u5b8c\u5168\u5e73\u8861\u7684\uff0c\u5e76\u4e14\u5b8c\u5168\u586b\u5145\u4e86\u6700\u4e0b\u9762\u7684\u4e24\u5c42\u8c03\u7528\uff0c\u90a3\u4e48\u5f53\u53c2\u6570\u4e3a6\u65f6\uff0c\u4f1a\u67092 + 4 + 8 + 16 = 30\u6b21\u9012\u5f52\u8c03\u7528\u3002\u6bcf\u4e00\u5c42\u91cc\u7684\u6ee1\u8c03\u7528\u6570\u91cf\u90fd\u662f\u5b83\u4e0a\u4e00\u5c42\u76842\u500d\u3002\u56e0\u6b64\uff0c\u5728\u5b8c\u5168\u5e73\u8861\u7684\u8c03\u7528\u6811\u91cc\uff0c\u9012\u5f52\u8c03\u7528\u7684\u603b\u6570\u91cf\u901a\u5e38\u662f 2^(n+1)-2 \uff0c\u5176\u4e2d n \u662f\u8c03\u7528\u6811\u9876\u90e8\uff08\u6839\uff09\u7684\u53c2\u6570\u3002\u8fd9\u662f\u4e00\u4e2a\u6307\u6570\u7ea7\u7684\u589e\u957f\uff0c\u4e5f\u5c31\u662f O(k^n) \u7b97\u6cd5\u3002 \u5c3d\u7ba1\u5728\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u8c03\u7528\u6811\u7684\u5e95\u90e8\u4e24\u5c42\u5e76\u6ca1\u6709\u88ab\u5b8c\u5168\u586b\u5145\u6ee1\uff0c\u4f46\u5b83\u7684\u8c03\u7528\u6811\u5f62\u72b6\u548c\u5b8c\u5168\u5e73\u8861\u7684\u6811\u5df2\u7ecf\u8db3\u591f\u76f8\u8fd1\u4e86\uff0c\u56e0\u6b64\uff0c\u53ef\u4ee5\u628a\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u5f52\u4e3a\u6307\u6570\u7b97\u6cd5\u3002\u7ecf\u8fc7\u8ba1\u7b97\uff0c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u7684\u5e38\u6570 k \u5927\u7ea6\u662f1.63\u3002 \u6307\u6570\u7b97\u6cd5\u901a\u5e38\u53ea\u9002\u5408\u7528\u4e8e\u975e\u5e38\u5c0f\u7684\u95ee\u9898\u89c4\u6a21\u3002","title":"\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7b97\u6cd5"},{"location":"python/DataStructure/03_TimeComplexity/#_2","text":"\u4e0b\u9762\u7684\u4ee3\u7801\u7528\u7ebf\u6027\u7b97\u6cd5\u6539\u5199\u4e86\u4e0a\u9762\u7684\u9012\u5f52\u7b97\u6cd5\u3002\u5b83\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\u3002 def fibonacci_linear ( n ): if n <= 1 : return 1 prev , current = 0 , 1 for _ in range ( 2 , n + 1 ): next_value = prev + current prev , current = current , next_value return current def main (): n = 6 result = fibonacci_linear ( n ) print ( f \"Fibonacci( { n } ) = { result } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Fibonacci(6) = 8","title":"\u5c06\u6590\u6ce2\u90a3\u5951\u8f6c\u6362\u4e3a\u7ebf\u6027\u7b97\u6cd5"},{"location":"python/DataStructure/03_TimeComplexity/#37","text":"\u76ee\u6807\uff1a\u7f16\u5199\u4e00\u4e2a\u53ef\u4ee5\u7528\u6765\u5206\u6790\u4e0d\u540c\u6392\u5e8f\u7b97\u6cd5\u7684\u7a0b\u5e8f\u3002 \u9700\u6c42\uff1a \u5206\u6790\u5668\u53ef\u4ee5\u8fd0\u884c\u6392\u5e8f\u7b97\u6cd5\u4ee5\u5bf9\u6570\u5b57\u5217\u8868\u8fdb\u884c\u6392\u5e8f\uff1b \u5206\u6790\u5668\u53ef\u4ee5\u8ffd\u8e2a\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u3001\u6bd4\u8f83\u6b21\u6570\u4ee5\u53ca\u6267\u884c\u4ea4\u6362\u7684\u6b21\u6570\uff1b \u5f53\u7b97\u6cd5\u4ea4\u6362\u4e24\u4e2a\u503c\u7684\u65f6\u5019\uff0c\u5206\u6790\u5668\u53ef\u4ee5\u6253\u5370\u51fa\u5217\u8868\u7684\u53d8\u5316\u8f68\u8ff9\uff1b \u5141\u8bb8\u7ed9\u5206\u6790\u5668\u63d0\u4f9b\u81ea\u5b9a\u4e49\u7684\u6570\u5b57\u5217\u8868\uff0c\u6216\u8005\u751f\u6210\u4e00\u4e2a\u5927\u5c0f\u7ed9\u5b9a\u7684\u968f\u673a\u6570\u5b57\u5217\u8868\uff1b\u5141\u8bb8\u5217\u8868\u53ea\u5305\u542b\u4e00\u4e2a\u6570\u5b57\uff0c\u6216\u8005\u5305\u542b\u91cd\u590d\u6570\u503c\uff1b \u5728\u8fd0\u884c\u7b97\u6cd5\u4e4b\u524d\uff0c\u5141\u8bb8\u7528\u6237\u9009\u62e9\u4e0a\u8ff0\u8fd9\u4e9b\u529f\u80fd\uff1b \u5206\u6790\u5668\u7684\u9ed8\u8ba4\u884c\u4e3a\u662f\u5728\u4e00\u4e2a\u5305\u542b10\u4e2a\u4e0d\u91cd\u590d\u6570\u5b57\u7684\u968f\u673a\u5217\u8868\u4e0a\u8fd0\u884c\u7b97\u6cd5\uff0c\u5e76\u8bb0\u5f55\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u3001\u6bd4\u8f83\u6b21\u6570\u4ee5\u53ca\u4ea4\u6362\u6b21\u6570\uff1b \u5b9e\u73b0\uff1a \u5206\u6790\u5668\u662f Profiler \u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\u3002\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u8fd0\u884c\u5206\u6790\u5668\u91cc\u7684 test \u65b9\u6cd5\u6765\u5206\u6790\u6392\u5e8f\u51fd\u6570\uff0c\u8fd9\u4e2a\u6392\u5e8f\u51fd\u6570\u4f1a\u4f5c\u4e3a\u65b9\u6cd5\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\uff0c\u4e0a\u9762\u9700\u6c42\u4e2d\u63d0\u5230\u7684\u90a3\u4e9b\u9009\u9879\u4e5f\u4f1a\u4f5c\u4e3a\u53c2\u6570\u540c\u65f6\u4f20\u9012\u7ed9\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u4e24\u4e2a\u6a21\u5757\uff1a profiler \uff1a\u8fd9\u4e2a\u6a21\u5757\u4f1a\u5b9a\u4e49 Profiler \u7c7b\u3002 algorithms \uff1a\u8fd9\u4e2a\u6a21\u5757\u5b9a\u4e49\u9488\u5bf9\u5206\u6790\u5668\u4fee\u6539\u8fc7\u7684\u6392\u5e8f\u51fd\u6570\u3002 import time import random class Profiler ( object ): \"\"\" \u5b9a\u4e49\u4e00\u4e2aProfiler\u7c7b, \u7528\u6765\u5206\u6790\u6392\u5e8f\u7b97\u6cd5\u3002 Profiler\u5bf9\u8c61\u8ddf\u8e2a\u4e00\u4e2a\u5217\u8868\u7684\u6bd4\u8f83\u6b21\u6570\u3001\u4ea4\u6362\u6b21\u6570\u3001\u548c\u8fd0\u884c\u65f6\u95f4\u3002 Profiler\u5bf9\u8c61\u4e5f\u80fd\u8f93\u51fa\u4e0a\u8ff0\u8ffd\u8e2a\u4fe1\u606f, \u5e76\u521b\u5efa\u4e00\u4e2a\u542b\u6709\u91cd\u590d\u6216\u4e0d\u91cd\u590d\u6570\u5b57\u7684\u5217\u8868\u3002 \u793a\u4f8b\uff1a from profiler import Profiler from algorithms import selectionSort p = Profiler() p.test(selectionSort, size = 15, comp = True, exch = True, trace = True) \"\"\" def test ( self , function , lyst = None , size = 10 , unique = True , comp = True , exch = True , trace = False ): \"\"\" function: \u914d\u7f6e\u7684\u7b97\u6cd5 target: \u914d\u7f6e\u7684\u641c\u7d22\u76ee\u6807 lyst: \u5141\u8bb8\u8c03\u7528\u8005\u4f7f\u7528\u7684\u5217\u8868 size: \u5217\u8868\u7684\u5927\u5c0f, \u9ed8\u8ba4\u503c\u662f10 unique: \u5982\u679c\u662fTrue, \u5219\u5217\u8868\u5305\u542b\u4e0d\u91cd\u590d\u7684\u6574\u6570 comp: \u5982\u679c\u662fTrue, \u5219\u7edf\u8ba1\u6bd4\u8f83\u6b21\u6570 exch: \u5982\u679c\u662fTrue, \u5219\u7edf\u8ba1\u4ea4\u6362\u6b21\u6570 trace: \u5982\u679c\u662fTrue, \u5219\u5728\u6bcf\u6b21\u4ea4\u6362\u540e\u90fd\u8f93\u51fa\u5217\u8868\u5185\u5bb9 \u6b64\u51fd\u6570\u4f9d\u636e\u7ed9\u5b9a\u7684\u4e0a\u8ff0\u5c5e\u6027, \u6253\u5370\u8f93\u51fa\u76f8\u5e94\u7684\u7ed3\u679c \"\"\" self . comp = comp self . exch = exch self . trace = trace if lyst != None : self . lyst = lyst elif unique : self . lyst = list ( range ( 1 , size + 1 )) random . shuffle ( self . lyst ) else : self . lyst = [] for count in range ( size ): self . lyst . append ( random . randint ( 1 , size )) self . exchCount = 0 self . cmpCount = 0 self . startClock () function ( self . lyst , self ) self . stopClock () print ( self ) def exchange ( self ): \"\"\"\u7edf\u8ba1\u4ea4\u6362\u6b21\u6570\"\"\" if self . exch : self . exchCount += 1 if self . trace : print ( self . lyst ) def comparison ( self ): \"\"\"\u7edf\u8ba1\u4ea4\u6362\u6b21\u6570\"\"\" if self . comp : self . cmpCount += 1 def startClock ( self ): \"\"\"\u8bb0\u5f55\u5f00\u59cb\u65f6\u95f4\"\"\" self . start = time . time () def stopClock ( self ): \"\"\"\u505c\u6b62\u8ba1\u65f6\u5e76\u4ee5\u79d2\u4e3a\u5355\u4f4d\u8ba1\u7b97\u6d88\u8017\u65f6\u95f4\"\"\" self . elapsedTime = round ( time . time () - self . start , 3 ) def __str__ ( self ): \"\"\"\u4ee5\u5b57\u7b26\u4e32\u65b9\u5f0f\u8fd4\u56de\u7ed3\u679c\"\"\" result = \"Problem size: \" result += str ( len ( self . lyst )) + \" \\n \" result += \"Elapsed time: \" result += str ( self . elapsedTime ) + \" \\n \" if self . comp : result += \"Comparisons: \" result += str ( self . cmpCount ) + \" \\n \" if self . exch : result += \"Exchanges: \" result += str ( self . exchCount ) + \" \\n \" return result def selectionSort ( lyst , profiler ): i = 0 while i < len ( lyst ) - 1 : minIndex = i j = i + 1 while j < len ( lyst ): profiler . comparison () # Count if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : swap ( lyst , minIndex , i , profiler ) i += 1 def swap ( lyst , i , j , profiler ): \"\"\"\u4ea4\u6362\u5904\u4e8e\u4f4d\u7f6ei\u548cj\u7684\u5143\u7d20\"\"\" profiler . exchange () # Count temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def main (): p = Profiler () # \u9ed8\u8ba4\u884c\u4e3a print ( \"The result of p.test(selectionSort)\" ) p . test ( selectionSort ) print ( \"The result of p.test(selectionSort, size=5, trace=True)\" ) p . test ( selectionSort , size = 5 , trace = True ) print ( \"The result of p.test(selectionSort, size=100)\" ) p . test ( selectionSort , size = 100 ) print ( \"The result of p.test(selectionSort, size=1000)\" ) p . test ( selectionSort , size = 1000 ) print ( \"The result of p.test(selectionSort, size=10000, exch=False, comp=False)\" ) p . test ( selectionSort , size = 10000 , exch = False , comp = False ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # The result of p.test(selectionSort) # Problem size: 20 # Elapsed time: 0.0 # Comparisons: 190 # Exchanges: 12 # The result of p.test(selectionSort, size=5, trace=True) # [5, 1, 4, 3, 2, 1, 1, 2, 4, 4] # [1, 5, 4, 3, 2, 1, 1, 2, 4, 4] # [1, 1, 4, 3, 2, 5, 1, 2, 4, 4] # [1, 1, 1, 3, 2, 5, 4, 2, 4, 4] # [1, 1, 1, 2, 3, 5, 4, 2, 4, 4] # [1, 1, 1, 2, 2, 5, 4, 3, 4, 4] # [1, 1, 1, 2, 2, 3, 4, 5, 4, 4] # [1, 1, 1, 2, 2, 3, 4, 4, 5, 4] # Problem size: 10 # Elapsed time: 0.0 # Comparisons: 45 # Exchanges: 8 # The result of p.test(selectionSort, size=100) # Problem size: 200 # Elapsed time: 0.003 # Comparisons: 19900 # Exchanges: 195 # The result of p.test(selectionSort, size=1000) # Problem size: 2000 # Elapsed time: 0.36 # Comparisons: 1999000 # Exchanges: 1992 # The result of p.test(selectionSort, size=10000, exch=False, comp=False) # Problem size: 20000 # Elapsed time: 26.535","title":"3.7.\u6848\u4f8b\u7814\u7a76:\u7b97\u6cd5\u5206\u6790\u5668"},{"location":"python/DataStructure/03_TimeComplexity/#38","text":"\u6839\u636e\u6240\u9700\u8981\u7684\u65f6\u95f4\u548c\u5185\u5b58\u8d44\u6e90\uff0c\u6211\u4eec\u53ef\u4ee5\u5bf9\u89e3\u51b3\u540c\u4e00\u4e2a\u95ee\u9898\u7684\u4e0d\u540c\u7b97\u6cd5\u8fdb\u884c\u6392\u540d\u3002\u4e0e\u9700\u8981\u66f4\u591a\u8d44\u6e90\u7684\u7b97\u6cd5\u76f8\u6bd4\uff0c\u6211\u4eec\u901a\u5e38\u8ba4\u4e3a\u8017\u8d39\u66f4\u5c11\u8fd0\u884c\u65f6\u548c\u5360\u7528\u66f4\u5c11\u5185\u5b58\u7684\u7b97\u6cd5\u66f4\u597d\u3002\u4f46\u662f\uff0c\u8fd9\u4e24\u79cd\u8d44\u6e90\u4e5f\u901a\u5e38\u9700\u8981\u8fdb\u884c\u6743\u8861\u53d6\u820d\uff1a\u6709\u65f6\u4ee5\u66f4\u591a\u5185\u5b58\u4e3a\u4ee3\u4ef7\u6765\u6539\u5584\u8fd0\u884c\u65f6\uff1b\u6709\u65f6\u4ee5\u8f83\u6162\u7684\u8fd0\u884c\u65f6\u4f5c\u4e3a\u4ee3\u4ef7\u6765\u63d0\u9ad8\u5185\u5b58\u7684\u4f7f\u7528\u7387\u3002 \u53ef\u4ee5\u6839\u636e\u8ba1\u7b97\u673a\u7684\u65f6\u949f\u6309\u7167\u8fc7\u5f80\u7ecf\u9a8c\u6d4b\u7b97\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u3002\u4f46\u662f\uff0c\u8fd9\u4e2a\u65f6\u95f4\u4f1a\u968f\u7740\u786c\u4ef6\u548c\u6240\u7528\u7f16\u7a0b\u8bed\u8a00\u7684\u4e0d\u540c\u800c\u53d8\u5316\u3002 \u7edf\u8ba1\u6307\u4ee4\u7684\u6570\u91cf\u63d0\u4f9b\u4e86\u53e6\u4e00\u79cd\u5bf9\u7b97\u6cd5\u6240\u9700\u5de5\u4f5c\u91cf\u8fdb\u884c\u7ecf\u9a8c\u6027\u5ea6\u91cf\u7684\u65b9\u5f0f\u3002\u6307\u4ee4\u7684\u8ba1\u6570\u53ef\u4ee5\u663e\u793a\u51fa\u7b97\u6cd5\u5de5\u4f5c\u91cf\u7684\u589e\u957f\u7387\u7684\u53d8\u5316\uff0c\u800c\u4e14\u8fd9\u4e2a\u6570\u636e\u548c\u786c\u4ef6\u4ee5\u53ca\u8f6f\u4ef6\u5e73\u53f0\u90fd\u6ca1\u6709\u5173\u7cfb\u3002 \u7b97\u6cd5\u5de5\u4f5c\u91cf\u7684\u589e\u957f\u7387\u53ef\u4ee5\u7528\u57fa\u4e8e\u95ee\u9898\u89c4\u6a21\u7684\u51fd\u6570\u6765\u8868\u793a\u3002\u590d\u6742\u5ea6\u5206\u6790\u67e5\u770b\u7b97\u6cd5\u91cc\u7684\u4ee3\u7801\u4ee5\u5f97\u5230\u8fd9\u4e9b\u6570\u5b66\u8868\u8fbe\u5f0f\uff0c\u4ece\u800c\u8ba9\u7a0b\u5e8f\u5458\u9884\u6d4b\u5728\u4efb\u4f55\u8ba1\u7b97\u673a\u4e0a\u6267\u884c\u8fd9\u4e2a\u7b97\u6cd5\u7684\u6548\u679c\u3002 \u5927O\u8868\u793a\u6cd5\u662f\u7528\u6765\u8868\u793a\u7b97\u6cd5\u8fd0\u884c\u65f6\u884c\u4e3a\u7684\u5e38\u7528\u65b9\u6cd5\u3002\u5b83\u7528 O(f(n)) \u7684\u5f62\u5f0f\u6765\u8868\u793a\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u6240\u9700\u8981\u7684\u5de5\u4f5c\u91cf\uff0c\u5176\u4e2d n \u662f\u7b97\u6cd5\u95ee\u9898\u7684\u89c4\u6a21\u3001 f(n) \u662f\u6570\u5b66\u51fd\u6570\u3002 \u8fd0\u884c\u65f6\u884c\u4e3a\u7684\u5e38\u89c1\u8868\u8fbe\u5f0f\u6709 O(log(n, 2)) \uff08\u5bf9\u6570\uff09\u3001 O(n) \uff08\u7ebf\u6027\uff09\u3001 O(n^2) \uff08\u5e73\u65b9\uff09\u4ee5\u53ca O(k^n) \uff08\u6307\u6570\uff09\u3002 \u7b97\u6cd5\u5728\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u53ef\u4ee5\u662f\u4e0d\u540c\u7684\u3002\u6bd4\u5982\uff0c\u5192\u6ce1\u6392\u5e8f\u548c\u63d2\u5165\u6392\u5e8f\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u90fd\u662f\u7ebf\u6027\u590d\u6742\u5ea6\uff0c\u4f46\u662f\u5b83\u4eec\u5728\u5e73\u5747\u60c5\u51b5\u548c\u6700\u574f\u60c5\u51b5\u4e0b\u662f\u5e73\u65b9\u9636\u590d\u6742\u5ea6\u3002 \u901a\u5e38\u6765\u8bf4\uff0c\u8981\u63d0\u9ad8\u7b97\u6cd5\u7684\u6027\u80fd\u6700\u597d\u662f\u5c1d\u8bd5\u964d\u4f4e\u5b83\u7684\u8fd0\u884c\u65f6\u590d\u6742\u5ea6\u7684\u9636\u6570\uff0c\u800c\u4e0d\u662f\u5bf9\u4ee3\u7801\u8fdb\u884c\u5fae\u8c03\u3002 \u4e8c\u5206\u641c\u7d22\u4f1a\u6bd4\u987a\u5e8f\u641c\u7d22\u8981\u5feb\u5f97\u591a\u3002\u4f46\u662f\uff0c\u5728\u7528\u4e8c\u5206\u641c\u7d22\u8fdb\u884c\u641c\u7d22\u65f6\uff0c\u6570\u636e\u5fc5\u987b\u662f\u6709\u5e8f\u7684\u3002 nlogn \u6392\u5e8f\u7b97\u6cd5\u901a\u8fc7\u9012\u5f52\u3001\u5206\u6cbb\u6cd5\u7b56\u7565\u6765\u7a81\u7834 n^2 \u7684\u6027\u80fd\u969c\u788d\u3002\u5feb\u901f\u6392\u5e8f\u4f1a\u5728\u57fa\u51c6\u5143\u7d20\u5de6\u53f3\u5bf9\u5176\u4ed6\u5143\u7d20\u91cd\u65b0\u6392\u5217\uff0c\u7136\u540e\u5bf9\u57fa\u51c6\u4e24\u4fa7\u7684\u5b50\u5217\u8868\u9012\u5f52\u5730\u6392\u5e8f\u3002\u5f52\u5e76\u6392\u5e8f\u5219\u4f1a\u628a\u4e00\u4e2a\u5217\u8868\u8fdb\u884c\u62c6\u5206\uff0c\u9012\u5f52\u5730\u5bf9\u6bcf\u4e2a\u90e8\u5206\u8fdb\u884c\u6392\u5e8f\uff0c\u7136\u540e\u5408\u5e76\u51fa\u6700\u7ec8\u7ed3\u679c\u3002 \u6307\u6570\u590d\u6742\u5ea6\u7684\u7b97\u6cd5\u901a\u5e38\u53ea\u5728\u7406\u8bba\u4e0a\u88ab\u5173\u6ce8\uff0c\u5728\u5904\u7406\u5927\u578b\u95ee\u9898\u7684\u65f6\u5019\uff0c\u5b83\u4eec\u662f\u6ca1\u6709\u4f7f\u7528\u4ef7\u503c\u7684\u3002","title":"3.8.\u5c0f\u7ed3"},{"location":"python/DataStructure/03_TimeComplexity/#39","text":"\u5728\u4e0d\u540c\u95ee\u9898\u89c4\u6a21\u7684\u60c5\u51b5\u4e0b\u8bb0\u5f55\u7b97\u6cd5\u8fd0\u884c\u65f6\uff1a \u53ef\u4ee5\u8ba9\u4f60\u5927\u81f4\u4e86\u89e3\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u884c\u4e3a \u53ef\u4ee5\u8ba9\u4f60\u4e86\u89e3\u7b97\u6cd5\u5728\u7279\u5b9a\u786c\u4ef6\u5e73\u53f0\u548c\u7279\u5b9a\u8f6f\u4ef6\u5e73\u53f0\u4e0a\u7684\u8fd0\u884c\u65f6\u884c\u4e3a \u7edf\u8ba1\u6307\u4ee4\u7684\u6570\u91cf\u4f1a\uff1a \u5728\u4e0d\u540c\u7684\u786c\u4ef6\u548c\u8f6f\u4ef6\u5e73\u53f0\u4e0a\u5f97\u5230\u76f8\u540c\u7684\u6570\u636e \u53ef\u4ee5\u8bc1\u660e\u5728\u95ee\u9898\u89c4\u6a21\u5f88\u5927\u7684\u60c5\u51b5\u4e0b\uff0c\u6307\u6570\u7b97\u6cd5\u662f\u6ca1\u6cd5\u4f7f\u7528\u7684 \u8868\u8fbe\u5f0f O(n) \u3001 O(n^2) \u548c O(k^n) \u5206\u522b\u4ee3\u8868\u7684\u590d\u6742\u5ea6\u662f\uff1a \u6307\u6570\u3001\u7ebf\u6027\u548c\u5e73\u65b9 \u7ebf\u6027\u3001\u5e73\u65b9\u548c\u6307\u6570 \u5bf9\u6570\u3001\u7ebf\u6027\u548c\u5e73\u65b9 \u4e8c\u5206\u641c\u7d22\u9700\u8981\u5047\u5b9a\u6570\u636e\uff1a \u6ca1\u6709\u4efb\u4f55\u7279\u522b\u7684\u987a\u5e8f\u5173\u7cfb \u6709\u5e8f\u7684 \u9009\u62e9\u6392\u5e8f\u6700\u591a\u53ef\u4ee5\u6709\uff1a n^2 \u6b21\u6570\u636e\u5143\u7d20\u7684\u4ea4\u6362 n \u6b21\u6570\u636e\u5143\u7d20\u7684\u4ea4\u6362 \u63d2\u5165\u6392\u5e8f\u548c\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u662f\uff1a \u7ebf\u6027\u7684 \u5e73\u65b9\u7684 \u6307\u6570\u7684 \u6700\u597d\u60c5\u51b5\u3001\u5e73\u5747\u60c5\u51b5\u4ee5\u53ca\u6700\u574f\u60c5\u51b5\u4e0b\u590d\u6742\u5ea6\u90fd\u76f8\u540c\u7684\u7b97\u6cd5\u662f\uff1a \u987a\u5e8f\u641c\u7d22 \u9009\u62e9\u6392\u5e8f \u5feb\u901f\u6392\u5e8f \u4e00\u822c\u6765\u8bf4\uff0c\u4e0b\u9762\u54ea\u4e2a\u9009\u62e9\u66f4\u597d\uff1a \u8c03\u6574\u7b97\u6cd5\u4ece\u800c\u8282\u7701\u82e5\u5e72\u79d2\u7684\u8fd0\u884c\u65f6 \u9009\u62e9\u8ba1\u7b97\u590d\u6742\u5ea6\u66f4\u4f4e\u7684\u7b97\u6cd5 \u5bf9\u4e8e\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\uff1a \u95ee\u9898\u89c4\u6a21\u4e3a n \u7684\u65f6\u5019\uff0c\u6709 n^2 \u6b21\u9012\u5f52\u8c03\u7528 \u95ee\u9898\u89c4\u6a21\u4e3a n \u7684\u65f6\u5019\uff0c\u6709 2n \u6b21\u9012\u5f52\u8c03\u7528 \u5b8c\u5168\u586b\u5145\u7684\u4e8c\u53c9\u8c03\u7528\u6811\u91cc\u6bcf\u4e00\u5c42\uff1a \u8c03\u7528\u6b21\u6570\u662f\u4e0a\u4e00\u5c42\u8c03\u7528\u6b21\u6570\u76842\u500d \u4e0e\u4e0a\u4e00\u5c42\u76f8\u540c\u7684\u8c03\u7528\u6b21\u6570","title":"3.9.\u590d\u4e60\u9898"},{"location":"python/DataStructure/03_TimeComplexity/#310","text":"1\uff0e\u5bf9\u4e00\u4e2a\u6709\u5e8f\u5217\u8868\u8fdb\u884c\u987a\u5e8f\u641c\u7d22\uff0c\u5f53\u76ee\u6807\u5c0f\u4e8e\u6709\u5e8f\u5217\u8868\u91cc\u7684\u67d0\u4e2a\u5143\u7d20\u65f6\uff0c\u987a\u5e8f\u641c\u7d22\u53ef\u4ee5\u63d0\u524d\u505c\u6b62\u3002\u5b9a\u4e49\u8fd9\u4e2a\u7b97\u6cd5\u7684\u4fee\u6539\u7248\u672c\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u6765\u63cf\u8ff0\u5b83\u5728\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 \u89e3\u7b54\uff1a \u5728\u6700\u597d\u7684\u60c5\u51b5\u4e0b\uff0c\u76ee\u6807\u5143\u7d20\u5728\u6709\u5e8f\u5217\u8868\u7684\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u51fd\u6570\u53ea\u9700\u8981\u8fdb\u884c\u4e00\u6b21\u6bd4\u8f83\u3002\u6240\u4ee5\uff0c\u6700\u4f73\u60c5\u51b5\u590d\u6742\u5ea6\u4e3a O(1) \u3002 \u5728\u6700\u574f\u7684\u60c5\u51b5\u4e0b\uff0c\u76ee\u6807\u5143\u7d20\u4e0d\u5728\u5217\u8868\u4e2d\uff0c\u5e76\u4e14\u6240\u6709\u5217\u8868\u5143\u7d20\u90fd\u5c0f\u4e8e\u76ee\u6807\u5143\u7d20\u3002\u8fd9\u5c06\u5bfc\u81f4\u51fd\u6570\u904d\u5386\u6574\u4e2a\u5217\u8868\uff0c\u6240\u4ee5\u6700\u574f\u60c5\u51b5\u590d\u6742\u5ea6\u4e3a O(n) \u3002 \u5bf9\u4e8e\u5e73\u5747\u60c5\u51b5\uff0c\u5047\u8bbe\u6709 n \u4e2a\u9879\u5728\u5217\u8868\u4e2d\uff0c\u641c\u7d22\u76ee\u6807\u4f1a\u5728\u5217\u8868\u524d n/2 \u4e2a\u9879\u6216\u8005\u4e0d\u5728\u6240\u6709\u3002\u5728\u8fd9\u4e2a\u7ea6\u5b9a\u4e0b\uff0c\u5e73\u5747\u6211\u4eec\u9700\u8981\u5bfb\u627e n/2 \u4e2a\u9879\uff0c\u56e0\u6b64\u590d\u6742\u5ea6\u4e3a O(n) \u3002\u4e4b\u6240\u4ee5\u662f n/2 \uff0c\u662f\u56e0\u4e3a\u8fd9\u4e2a\u4efb\u52a1\u53ef\u80fd\u4f1a\u5728\u4efb\u4f55\u5730\u65b9\u88ab\u505c\u6b62\uff0c\u6211\u4eec\u5bf9\u6b64\u505a\u5e73\u5747\u5904\u7406\u3002\u7136\u800c\u5728\u5927O\u6807\u8bb0\u6cd5\u4e2d\uff0c\u5e38\u6570\u5c06\u88ab\u9057\u5fd8\uff0c\u6240\u4ee5\u5b83\u4ecd\u7136\u662f O(n) \u3002 \u4ee3\u7801\u5982\u4e0b\uff1a def ordered_sequential_search ( arr , target ): comparisons = 0 # \u7528\u4e8e\u7edf\u8ba1\u6bd4\u8f83\u6b21\u6570 index = 0 while index < len ( arr ): comparisons += 1 if arr [ index ] == target : return comparisons , index # \u627e\u5230\u76ee\u6807\u5e76\u8fd4\u56de\u6bd4\u8f83\u6b21\u6570\u548c\u7d22\u5f15 elif arr [ index ] > target : break # \u5982\u679c\u76ee\u6807\u5c0f\u4e8e\u5f53\u524d\u5143\u7d20\uff0c\u63d0\u524d\u505c\u6b62\u641c\u7d22 index += 1 return comparisons , - 1 # \u6ca1\u627e\u5230\u76ee\u6807\u8fd4\u56de\u6bd4\u8f83\u6b21\u6570\u548c-1 def main (): # \u6d4b\u8bd5 arr = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] for target in [ 5 , 11 ]: comparisons , index = ordered_sequential_search ( arr , target ) if index != - 1 : print ( f \"\u76ee\u6807 { target } \u5728\u7d22\u5f15 { index } \u5904\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a { comparisons } \" ) else : print ( f \"\u76ee\u6807 { target } \u672a\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a { comparisons } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # \u76ee\u6807 5 \u5728\u7d22\u5f15 4 \u5904\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a 5 # \u76ee\u6807 11 \u672a\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a 10 2\uff0e\u5217\u8868\u7684 reverse \u65b9\u6cd5\u7528\u6765\u53cd\u8f6c\u5217\u8868\u91cc\u7684\u5143\u7d20\u3002\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c reverse \u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u53ef\u4ee5\u5728\u4e0d\u4f7f\u7528 reverse \u65b9\u6cd5\u7684\u60c5\u51b5\u4e0b\uff0c\u53cd\u8f6c\u5217\u8868\u53c2\u6570\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u5c1d\u8bd5\u8ba9\u8fd9\u4e2a\u51fd\u6570\u5c3d\u53ef\u80fd\u5730\u9ad8\u6548\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 \u89e3\u7b54\uff1a \u53ea\u9700\u8981\u904d\u5386\u5217\u8868\u7684\u4e00\u534a\uff0c\u6211\u4eec\u5c31\u80fd\u5230\u8fbe\u5217\u8868\u7684\u4e2d\u95f4\u4f4d\u7f6e\u628a\u5217\u8868\u4e24\u8fb9\u7684\u5143\u7d20\u4e92\u6362\uff0c\u8fd9\u6837\u5c31\u5b8c\u6210\u4e86\u5217\u8868\u7684\u53cd\u8f6c\u3002 \u8fd9\u4e2a\u7b97\u6cd5\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n/2) \uff0c\u5176\u4e2d n \u662f\u5217\u8868\u7684\u957f\u5ea6\u3002\u4f46\u5728\u5927O\u8868\u793a\u6cd5\u4e2d\uff0c\u5e38\u6570\u88ab\u5ffd\u7565\uff0c\u56e0\u6b64\u8be5\u7b97\u6cd5\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002\u5728\u8fd9\u4e2a\u7b97\u6cd5\u4e2d\uff0c n \u5c31\u4ee3\u8868\u7740\u5217\u8868\u7684\u957f\u5ea6\u3002\u610f\u5473\u7740\u65f6\u95f4\u590d\u6742\u5ea6\u53d7\u5217\u8868\u957f\u5ea6\u7684\u5f71\u54cd\u3002\u5217\u8868\u957f\u5ea6\u6bcf\u589e\u52a0\u4e00\u6b21\uff0c\u6267\u884c\u53cd\u8f6c\u7684\u65f6\u95f4\u5c31\u589e\u52a0\u4e00\u6b21\u3002\u8fd9\u5c31\u662f O(n) \u7684\u6982\u5ff5\u3002 \u8fd9\u4e2a\u51fd\u6570\u7684\u7a7a\u95f4\u590d\u6742\u5ea6\u662f O(1) \uff0c\u56e0\u4e3a\u5b83\u53ea\u662f\u5728\u539f\u5730\u4fee\u6539\u5217\u8868\uff0c\u4e0d\u9700\u8981\u989d\u5916\u7684\u5b58\u50a8\u7a7a\u95f4\u3002 \u4ee3\u7801\u5982\u4e0b\uff1a def custom_reverse ( arr ): left , right = 0 , len ( arr ) - 1 while left < right : arr [ left ], arr [ right ] = arr [ right ], arr [ left ] left += 1 right -= 1 def main (): # \u6d4b\u8bd5\u5217\u8868reverse\u65b9\u6cd5 my_list = [ 1 , 2 , 3 , 4 , 5 ] my_list . reverse () print ( my_list ) # \u6d4b\u8bd5\u81ea\u5b9a\u4e49\u7684reverse\u65b9\u6cd5 my_list = [ 1 , 2 , 3 , 4 , 5 ] custom_reverse ( my_list ) print ( my_list ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # [5, 4, 3, 2, 1] # [5, 4, 3, 2, 1] 3\uff0ePython\u7684pow\u51fd\u6570\u4f1a\u8fd4\u56de\u6570\u5b57\u7279\u5b9a\u5e42\u6b21\u7684\u7ed3\u679c\u3002\u5b9a\u4e49\u6267\u884c\u8fd9\u4e2a\u4efb\u52a1\u7684expo\u51fd\u6570\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002\u8fd9\u4e2a\u51fd\u6570\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u6570\u5b57\uff0c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u6307\u6570\uff08\u975e\u8d1f\u6570\uff09\u3002\u4f60\u53ef\u4ee5\u901a\u8fc7\u5faa\u73af\u6216\u9012\u5f52\u51fd\u6570\u6765\u5b9e\u73b0\uff0c\u4f46\u4e0d\u8981\u4f7f\u7528Python\u5185\u7f6e\u7684**\u8fd0\u7b97\u7b26\u6216\u662fpow\u51fd\u6570\u3002 \u89e3\u7b54\uff1a \u4e0b\u9762\u5b9e\u73b0\u7684 expo \u51fd\u6570\u4f7f\u7528\u5faa\u73af\u6765\u8fde\u7eed\u4e58\u4ee5 base \uff0c\u5faa\u73af\u7684\u6b21\u6570\u7b49\u4e8e exponent \u7684\u503c\u3002 \u65f6\u95f4\u590d\u6742\u5ea6\u662f O(exponent) \uff0c\u5176\u4e2d exponent \u662f\u6307\u6570\u7684\u503c\u3002 \u6700\u597d\u60c5\u51b5\uff1aO(exponent) \u6700\u574f\u60c5\u51b5\uff1aO(exponent) \u5e73\u5747\u60c5\u51b5\uff1aO(exponent) def expo ( base , exponent ): result = 1 for _ in range ( exponent ): result *= base return result def main (): # \u6d4b\u8bd5 base = 2 for exponent in [ 3 , - 3 ]: result = expo ( base , exponent ) print ( f \" { base } \u7684 { exponent } \u6b21\u65b9\u7b49\u4e8e { result } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # 2 \u7684 3 \u6b21\u65b9\u7b49\u4e8e 8 # 2 \u7684 -3 \u6b21\u65b9\u7b49\u4e8e 1 4\uff0e\u53e6\u4e00\u4e2a\u5b9e\u73b0 expo \u51fd\u6570\u7684\u7b56\u7565\u4f7f\u7528\u4e0b\u9762\u8fd9\u4e2a\u9012\u5f52\u3002\u8bf7\u5b9a\u4e49\u4f7f\u7528\u8fd9\u4e2a\u7b56\u7565\u7684\u9012\u5f52\u51fd\u6570 expo \uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 expo ( number \uff0c exponent ) = 1 \uff0c \u5f53 exponent = 0 \u7684\u65f6\u5019 = number * expo ( number , exponent \u2212 1 ) \uff0c \u5f53exponent\u4e3a\u5947\u6570\u7684\u65f6\u5019 = ( expo ( number , exponent / 2 )) 2 \uff0c \u5f53exponent\u4e3a\u5076\u6570\u7684\u65f6\u5019 \u89e3\u7b54\uff1a \u4e0b\u9762\u5b9e\u73b0expo\u51fd\u6570\u662f\u901a\u8fc7\u9012\u5f52\u5b9e\u73b0\uff0c\u5e76\u91c7\u7528\u4e86\u5206\u800c\u6cbb\u4e4b\u7684\u7b56\u7565\u3002 \u5982\u679c\u6307\u6570\u662f\u5947\u6570\uff0c\u5c31\u628a\u95ee\u9898\u5206\u89e3\u4e3a\u4e00\u4e2a\u66f4\u5c0f\u7684\u7248\u672c\uff08\u5373 num * num^(exp - 1) \uff09\uff1b \u5982\u679c\u6307\u6570\u662f\u5076\u6570\uff0c\u5219\u53ef\u4ee5\u5c06\u6307\u6570\u5206\u6210\u4e24\u534a\uff0c\u5e76\u53ea\u8ba1\u7b97\u5176\u4e2d\u7684\u4e00\u534a\uff08\u5373 num^(exp / 2) * num^(exp / 2) \uff09\u3002 \u8fd9\u5c31\u5229\u7528\u4e86\u5e42\u7684\u6027\u8d28 a^(m * n) = (a^m)^n \u3002 \u8be5\u9012\u5f52\u5b9e\u73b0\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(log n) \uff0c\u5176\u4e2dn\u4e3a\u6307\u6570\u3002\u8fd9\u662f\u56e0\u4e3a\u5728\u6307\u6570\u4e3a\u5076\u6570\u7684\u60c5\u51b5\u4e0b\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u90fd\u4f1a\u628a\u95ee\u9898\u89c4\u6a21\u7f29\u5c0f\u4e00\u534a\uff0c\u7c7b\u4f3c\u4e8e\u4e8c\u5206\u67e5\u627e\u7b49\u8bfe\u5206\u5272\u95ee\u9898\u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\u4e5f\u662f O(log n) \uff0c\u8fd9\u4e3b\u8981\u662f\u7531\u4e8e\u51fd\u6570\u8c03\u7528\u6808\u7684\u6df1\u5ea6\u5728\u6307\u6570\u4e3a\u5076\u6570\u7684\u60c5\u51b5\u4e0b\uff0c\u4f1a\u53d8\u4e3a\u539f\u6765\u7684\u4e00\u534a\u3002 def expo ( number , exponent ): if exponent <= 0 : return 1 elif exponent % 2 == 1 : # \u5f53 exponent \u4e3a\u5947\u6570 return number * expo ( number , exponent - 1 ) else : # \u5f53 exponent \u4e3a\u5076\u6570 half_expo = expo ( number , exponent // 2 ) return half_expo * half_expo def main (): # \u6d4b\u8bd5 base = 2 for exponent in [ 3 , - 3 ]: result = expo ( base , exponent ) print ( f \" { base } \u7684 { exponent } \u6b21\u65b9\u7b49\u4e8e { result } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # 2 \u7684 3 \u6b21\u65b9\u7b49\u4e8e 8 # 2 \u7684 -3 \u6b21\u65b9\u7b49\u4e8e 1 5\uff0ePython\u4e2dlist\u91cc\u7684sort\u65b9\u6cd5\u5305\u542b\u4e00\u4e2a\u7528\u5173\u952e\u5b57\u547d\u540d\u7684\u53c2\u6570reverse\uff0c\u5b83\u7684\u9ed8\u8ba4\u503c\u4e3aFalse\u3002\u7a0b\u5e8f\u5458\u53ef\u4ee5\u901a\u8fc7\u8986\u76d6\u8fd9\u4e2a\u503c\u4ee5\u5bf9\u5217\u8868\u8fdb\u884c\u964d\u5e8f\u6392\u5e8f\u3002\u4fee\u6539\u672c\u7ae0\u8ba8\u8bba\u7684selectionSort\u51fd\u6570\uff0c\u4f7f\u5b83\u53ef\u4ee5\u63d0\u4f9b\u8fd9\u4e2a\u9644\u52a0\u53c2\u6570\u6765\u8ba9\u7a0b\u5e8f\u5458\u51b3\u5b9a\u6392\u5e8f\u7684\u65b9\u5411\u3002 \u89e3\u7b54\uff1a \u901a\u8fc7\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a reverse \u7684\u53c2\u6570\u6765\u4fee\u6539 selectionSort \u51fd\u6570\uff0c\u4ee5\u4fbf\u8ba9\u7a0b\u5e8f\u5458\u51b3\u5b9a\u6392\u5e8f\u7684\u65b9\u5411\u3002\u5982\u679c reverse \u4e3a True \uff0c\u6392\u5e8f\u5c06\u662f\u964d\u5e8f\u7684\uff0c\u5982\u679c\u4e3a False \uff08\u9ed8\u8ba4\u503c\uff09\uff0c\u6392\u5e8f\u5c06\u662f\u5347\u5e8f\u7684\u3002 \u4e0b\u9762\u662f\u4fee\u6539\u540e\u7684 selectionSort \u51fd\u6570\uff1a def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst , reverse = False ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\uff0c\u53ef\u4ee5\u9009\u62e9\u5347\u5e8f\u6216\u964d\u5e8f\u6392\u5e8f\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 index = i # \u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\u4f4d\u7f6e if not reverse : if ( lyst [ j ] < lyst [ index ]): index = j else : if ( lyst [ j ] > lyst [ index ]): index = j j += 1 if index != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , index , i ) i += 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] 6\uff0e\u4fee\u6539\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\uff0c\u8ba9\u5b83\u652f\u6301\u672c\u7ae0\u91cc\u8ba8\u8bba\u8fc7\u7684\u8bb0\u5fc6\u5316\u6280\u672f\u3002\u8fd9\u4e2a\u51fd\u6570\u5e94\u6dfb\u52a0\u4e00\u4e2a\u5b57\u5178\u7c7b\u578b\u7684\u53c2\u6570\u3002\u5b83\u7684\u9876\u5c42\u8c03\u7528\u4f1a\u63a5\u6536\u4e00\u4e2a\u7a7a\u5b57\u5178\u4f5c\u4e3a\u53c2\u6570\uff0c\u8fd9\u4e2a\u5b57\u5178\u7684\u952e\u548c\u503c\u5e94\u8be5\u662f\u9012\u5f52\u8c03\u7528\u6240\u4f20\u9012\u7684\u53c2\u6570\u548c\u8ba1\u7b97\u51fa\u7684\u503c\u3002\u4e4b\u540e\uff0c\u7528\u672c\u7ae0\u8ba8\u8bba\u8fc7\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u5bf9\u9012\u5f52\u8c03\u7528\u7684\u6570\u91cf\u8fdb\u884c\u7edf\u8ba1\u3002 \u89e3\u7b54\uff1a \u4e0b\u9762\u662f\u4e00\u4e2a\u4fee\u6539\u540e\u7684\u7248\u672c\uff0c\u5b83\u4f7f\u7528\u4e00\u4e2a\u5b57\u5178\uff08\u7f13\u5b58\uff09\u6765\u5b58\u50a8\u5df2\u8ba1\u7b97\u7684\u7ed3\u679c\uff0c\u5e76\u4e14\u6dfb\u52a0\u4e86\u4e00\u4e2a\u8ba1\u6570\u5668\u5bf9\u8c61\u6765\u7edf\u8ba1\u9012\u5f52\u8c03\u7528\u6b21\u6570\u3002\u8fd9\u4e2a\u4ee3\u7801\u4f1a\u8f93\u51fa\u6307\u5b9a\u9879\u6570\u7684\u6590\u6ce2\u90a3\u5951\u6570\u4ee5\u53ca\u9012\u5f52\u8c03\u7528\u7684\u603b\u6b21\u6570\u3002\u8bb0\u5fc6\u5316\u6280\u672f\u53ef\u4ee5\u663e\u8457\u63d0\u9ad8\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u6027\u80fd\uff0c\u907f\u514d\u4e86\u91cd\u590d\u8ba1\u7b97\u3002 class Counter : def __init__ ( self ): self . count = 0 def increment ( self ): self . count += 1 def fib ( n , cache , counter ): \"\"\"\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u6570\u5217\uff0c\u5e26\u6709\u8bb0\u5fc6\u5316\u548c\u8c03\u7528\u8ba1\u6570\u5668\"\"\" if n in cache : return cache [ n ] counter . increment () if n <= 1 : result = 1 else : result = fib ( n - 1 , cache , counter ) + fib ( n - 2 , cache , counter ) cache [ n ] = result return result def main (): n = 10 # \u4f60\u53ef\u4ee5\u8bbe\u7f6e\u4e0d\u540c\u7684\u6590\u6ce2\u90a3\u5951\u6570\u5217\u9879\u6570 cache = {} # \u7528\u4e8e\u7f13\u5b58\u5df2\u8ba1\u7b97\u7ed3\u679c\u7684\u5b57\u5178 counter = Counter () # \u7528\u4e8e\u8ba1\u6570\u9012\u5f52\u8c03\u7528\u6b21\u6570\u7684\u8ba1\u6570\u5668\u5bf9\u8c61 result = fib ( n , cache , counter ) print ( f \"Fibonacci( { n } ) = { result } \" ) print ( f \"Total recursive calls: { counter . count } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Fibonacci(10) = 89 # Total recursive calls: 11 7\uff0e\u5206\u6790\u4e0a\u9762\u6590\u6ce2\u90a3\u5951\u6570\u5217\u91cc\u5b9a\u4e49\u7684\u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u6027\u80fd\uff0c\u7edf\u8ba1\u8fd9\u4e2a\u51fd\u6570\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u3002\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\uff0c\u5e76\u8bc1\u660e\u4f60\u7684\u7b54\u6848\u662f\u5408\u7406\u7684\u3002 \u89e3\u7b54\uff1a \u5728\u4e0a\u9762\u7684\u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u4e2d\uff0c\u6211\u4eec\u4f7f\u7528\u4e86\u8bb0\u5fc6\u5316\u6280\u672f\u6765\u907f\u514d\u91cd\u590d\u8ba1\u7b97\u3002\u8fd9\u79cd\u4f18\u5316\u4f1a\u663e\u8457\u51cf\u5c11\u8ba1\u7b97\u65f6\u95f4\uff0c\u56e0\u4e3a\u6bcf\u4e2a\u6590\u6ce2\u90a3\u5951\u6570\u53ea\u4f1a\u88ab\u8ba1\u7b97\u4e00\u6b21\u3002 \u8ba1\u7b97\u590d\u6742\u5ea6\u5206\u6790\uff1a \u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u662f O(n) \u3002\u8fd9\u662f\u56e0\u4e3a\u5b83\u9700\u8981\u8ba1\u7b97\u6590\u6ce2\u90a3\u5951\u6570\u5217\u7684\u524d n \u9879\uff0c\u6bcf\u4e00\u9879\u53ea\u9700\u8ba1\u7b97\u4e00\u6b21\uff0c\u7136\u540e\u5b58\u50a8\u5728\u7f13\u5b58\u4e2d\u3002\u56e0\u6b64\uff0c\u603b\u5171\u6267\u884c\u7684\u8ba1\u7b97\u91cf\u4e0e n \u6210\u6b63\u6bd4\uff0c\u5373 O(n) \u3002 \u9012\u5f52\u8c03\u7528\u6b21\u6570\uff1a \u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u53d6\u51b3\u4e8e\u8f93\u5165\u53c2\u6570 n \u3002\u5bf9\u4e8e\u6590\u6ce2\u90a3\u5951\u6570\u5217\uff0c\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u5927\u81f4\u7b49\u4e8e n \u3002\u56e0\u4e3a\u6bcf\u4e2a\u9879\u9700\u8981\u8ba1\u7b97\u4e00\u6b21\uff0c\u6240\u4ee5\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u4e0e\u8ba1\u7b97\u7684\u9879\u6570\u662f\u4e00\u81f4\u7684\u3002 \u6240\u4ee5\uff0c\u8fd9\u4e2a\u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u662f O(n) \uff0c\u800c\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u4e5f\u5927\u81f4\u7b49\u4e8e n \u3002\u8fd9\u4e2a\u6027\u80fd\u662f\u76f8\u5bf9\u8f83\u597d\u7684\uff0c\u56e0\u4e3a\u5b83\u907f\u514d\u4e86\u6307\u6570\u7ea7\u522b\u7684\u91cd\u590d\u8ba1\u7b97\uff0c\u800c\u662f\u7ebf\u6027\u5730\u8ba1\u7b97\u6590\u6ce2\u90a3\u5951\u6570\u5217\u7684\u5404\u9879\u3002 8\uff0e\u51fd\u6570makeRandomList\u4f1a\u521b\u5efa\u5e76\u8fd4\u56de\u4e00\u4e2a\u7ed9\u5b9a\u5927\u5c0f\uff08\u5b83\u7684\u53c2\u6570\uff09\u7684\u6570\u5b57\u5217\u8868\u3002\u5217\u8868\u91cc\u7684\u6570\u5b57\u6ca1\u6709\u91cd\u590d\uff0c\u5b83\u4eec\u7684\u8303\u56f4\u4e3a1\uff5esize\uff0c\u4f4d\u7f6e\u662f\u968f\u673a\u7684\u3002\u4e0b\u9762\u662f\u8fd9\u4e2a\u51fd\u6570\u7684\u4ee3\u7801\u3002\u53ef\u4ee5\u5047\u5b9arange\u3001randint\u548cappend\u51fd\u6570\u90fd\u662f\u5e38\u6570\u65f6\u95f4\u7684\u590d\u6742\u5ea6\u3002\u8fd8\u53ef\u4ee5\u5047\u8bberandom.randint\u968f\u7740\u53c2\u6570\u4e4b\u95f4\u5dee\u503c\u7684\u589e\u52a0\u800c\u66f4\u5c11\u5730\u8fd4\u56de\u91cd\u590d\u7684\u6570\u5b57\u3002\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u8fd9\u4e2a\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\uff0c\u5e76\u8bc1\u660e\u4f60\u7684\u7b54\u6848\u662f\u5408\u7406\u7684\u3002 def makeRandomList ( size ): lyst = [] for count in range ( size ): while True : number = random . randint ( 1 , size ) if not number in lyst : lyst . append ( number ) break return lyst \u89e3\u7b54\uff1a \u8fd9\u4e2a\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u5b83\u7684\u5185\u90e8\u5faa\u73af\uff0c\u8be5\u5faa\u73af\u4f1a\u4e0d\u65ad\u751f\u6210\u968f\u673a\u6570\uff0c\u5e76\u68c0\u67e5\u5b83\u662f\u5426\u5df2\u7ecf\u5728\u5217\u8868 lyst \u4e2d\u3002\u5177\u4f53\u5206\u6790\u5982\u4e0b\uff1a \u521b\u5efa\u4e00\u4e2a\u7a7a\u5217\u8868 lyst \uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(1)\u3002 \u8fdb\u5165 for \u5faa\u73af\uff0c\u5faa\u73af\u6b21\u6570\u4e3a size \uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(size)\u3002 \u5728\u5185\u90e8 while \u5faa\u73af\u4e2d\uff0c\u751f\u6210\u4e00\u4e2a\u968f\u673a\u6570 number \uff0c\u6700\u574f\u60c5\u51b5\u4e0b\u9700\u8981\u751f\u6210 size \u6b21\u968f\u673a\u6570\u624d\u80fd\u627e\u5230\u4e00\u4e2a\u4e0d\u5728 lyst \u4e2d\u7684\u6570\u5b57\u3002\u8fd9\u90e8\u5206\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(size)\u3002 \u7efc\u4e0a\u6240\u8ff0\uff0c\u8fd9\u4e2a\u51fd\u6570\u7684\u603b\u4f53\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(size^2)\u3002\u8fd9\u662f\u56e0\u4e3a\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u6bcf\u6b21\u751f\u6210\u7684\u968f\u673a\u6570\u90fd\u9700\u8981\u68c0\u67e5\u662f\u5426\u5728 lyst \u4e2d\uff0c\u800c\u968f\u673a\u6570\u7684\u751f\u6210\u53ef\u80fd\u9700\u8981\u591a\u6b21\u624d\u80fd\u751f\u6210\u4e00\u4e2a\u4e0d\u5728\u5217\u8868\u4e2d\u7684\u6570\u5b57\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u968f\u7740 size \u7684\u589e\u52a0\uff0c\u5185\u90e8\u5faa\u73af\u7684\u8fed\u4ee3\u6b21\u6570\u4e5f\u4f1a\u589e\u52a0\uff0c\u5bfc\u81f4\u65f6\u95f4\u590d\u6742\u5ea6\u5448\u4e8c\u6b21\u589e\u957f\u3002\u56e0\u6b64\uff0c\u8fd9\u4e2a\u51fd\u6570\u7684\u6027\u80fd\u5728\u5927\u89c4\u6a21\u6570\u636e\u4e0a\u53ef\u80fd\u4f1a\u53d7\u5230\u9650\u5236\u3002\u5982\u679c\u9700\u8981\u66f4\u597d\u7684\u6027\u80fd\uff0c\u53ef\u4ee5\u8003\u8651\u5176\u4ed6\u7b97\u6cd5\uff0c\u4ee5\u907f\u514d\u91cd\u590d\u68c0\u67e5\u548c\u751f\u6210\u968f\u673a\u6570\u3002 import random def makeRandomList ( size ): lyst = [] for count in range ( size ): while True : number = random . randint ( 1 , size ) if not number in lyst : lyst . append ( number ) break print ( \"count=\" , count , \"list=\" , lyst ) return lyst def main (): print ( \"final list=\" , makeRandomList ( 10 )) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # count= 0 list= [2] # count= 1 list= [2, 10] # count= 2 list= [2, 10, 9] # count= 3 list= [2, 10, 9, 5] # count= 4 list= [2, 10, 9, 5, 3] # count= 5 list= [2, 10, 9, 5, 3, 4] # count= 6 list= [2, 10, 9, 5, 3, 4, 8] # count= 7 list= [2, 10, 9, 5, 3, 4, 8, 7] # count= 8 list= [2, 10, 9, 5, 3, 4, 8, 7, 6] # count= 9 list= [2, 10, 9, 5, 3, 4, 8, 7, 6, 1] # final list= [2, 10, 9, 5, 3, 4, 8, 7, 6, 1] 9\uff0e\u4fee\u6539quicksort\u51fd\u6570\uff0c\u8ba9\u5b83\u53ef\u4ee5\u5bf9\u4efb\u4f55\u5c3a\u5bf8\u5c0f\u4e8e50\u7684\u5b50\u5217\u8868\u8c03\u7528\u63d2\u5165\u6392\u5e8f\u3002\u4f7f\u7528\u670950\u3001500\u548c5000\u4e2a\u5143\u7d20\u7684\u6570\u636e\u96c6\u6bd4\u8f83\u8fd9\u4e2a\u7248\u672c\u4e0e\u539f\u59cb\u7248\u672c\u7684\u6027\u80fd\u3002\u7136\u540e\u8c03\u6574\u8fd9\u4e2a\u9608\u503c\uff0c\u4ece\u800c\u786e\u5b9a\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u7684\u6700\u4f73\u8bbe\u7f6e\u3002 \u89e3\u7b54\uff1a \u53ef\u4ee5\u5728 quicksortHelper \u51fd\u6570\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u6761\u4ef6\uff0c\u68c0\u67e5\u5b50\u5217\u8868\u7684\u5927\u5c0f\u3002\u7136\u540e\u518d\u4fee\u6539 quicksort \u51fd\u6570\uff0c\u5b9e\u73b0\u5728\u5c0f\u4e8e50\u7684\u5b50\u5217\u8868\u4e0a\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u3002 \u5982\u679c\u5b50\u5217\u8868\u7684\u5927\u5c0f\u5c0f\u4e8e50\uff0c\u5c31\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u7b97\u6cd5\uff0c\u5426\u5219\u4f7f\u7528\u5feb\u901f\u6392\u5e8f\u7b97\u6cd5\u3002\u4e0b\u9762\u662f\u4fee\u6539\u540e\u7684\u4ee3\u7801\uff1a import random def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def quicksort ( lyst ): quicksortHelper ( lyst , 0 , len ( lyst ) - 1 ) def quicksortHelper ( lyst , left , right ): if left < right : # \u68c0\u67e5\u5b50\u5217\u8868\u7684\u5927\u5c0f\u662f\u5426\u5c0f\u4e8e50 if right - left < 50 : # \u5982\u679c\u5c0f\u4e8e50\uff0c\u4f7f\u7528\u63d2\u5165\u6392\u5e8f insertionSort ( lyst , left , right ) else : pivotLocation = partition ( lyst , left , right ) quicksortHelper ( lyst , left , pivotLocation - 1 ) quicksortHelper ( lyst , pivotLocation + 1 , right ) def partition ( lyst , left , right ): \"\"\"\u5bf9\u5217\u8868\u8fdb\u884c\u5206\u533a\"\"\" # \u627e\u5230\u57fa\u51c6\u5143\u7d20\uff08pivot\uff09\uff0c\u5e76\u548c\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u4e92\u6362 middle = ( left + right ) // 2 pivot = lyst [ middle ] lyst [ middle ] = lyst [ right ] lyst [ right ] = pivot # \u8bbe\u5b9a\u8fb9\u754c\u5143\u7d20\uff08boundary point\uff09\uff0c\u521d\u59cb\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20 boundary = left print ( \"pivot: \" , pivot , \"boundary: \" , lyst [ boundary ]) # \u628a\u6240\u6709\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u90fd\u79fb\u52a8\u5230\u8fb9\u754c\u7684\u5de6\u8fb9 for index in range ( left , right ): if lyst [ index ] < pivot : swap ( lyst , index , boundary ) boundary += 1 # \u4ea4\u6362\u57fa\u51c6\u5143\u7d20\u548c\u8fb9\u754c\u5143\u7d20 swap ( lyst , right , boundary ) print ( lyst ) return boundary def insertionSort ( lyst , left , right ): \"\"\"\u63d2\u5165\u6392\u5e8f\u7b97\u6cd5\"\"\" for i in range ( left + 1 , right + 1 ): currentElement = lyst [ i ] j = i while j > left and currentElement < lyst [ j - 1 ]: lyst [ j ] = lyst [ j - 1 ] j -= 1 lyst [ j ] = currentElement def main ( size = 20 , sort = quicksort ): lyst = [ random . randint ( 1 , size ) for _ in range ( size )] print ( \"Before sorted\" , lyst ) sort ( lyst ) print ( \"After sorted\" , lyst ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before sorted [1, 3, 6, 14, 9, 6, 14, 15, 17, 13, 4, 3, 1, 13, 11, 16, 2, 4, 6, 2] # After sorted [1, 1, 2, 2, 3, 3, 4, 4, 6, 6, 6, 9, 11, 13, 13, 14, 14, 15, 16, 17] 10\uff0e\u8ba1\u7b97\u673a\u4f7f\u7528\u540d\u4e3a\u8c03\u7528\u6808\u7684\u7ed3\u6784\u6765\u4e3a\u9012\u5f52\u51fd\u6570\u7684\u8c03\u7528\u63d0\u4f9b\u652f\u6301\u3002\u4e00\u822c\u800c\u8a00\uff0c\u8ba1\u7b97\u673a\u4f1a\u4e3a\u51fd\u6570\u7684\u6bcf\u6b21\u8c03\u7528\u90fd\u4fdd\u7559\u4e00\u5b9a\u6570\u91cf\u7684\u5185\u5b58\u3002\u56e0\u6b64\uff0c\u53ef\u4ee5\u5bf9\u9012\u5f52\u51fd\u6570\u4f7f\u7528\u7684\u5185\u5b58\u6570\u91cf\u8fdb\u884c\u590d\u6742\u5ea6\u5206\u6790\u3002\u8bf7\u8bf4\u660e\u9012\u5f52\u9636\u4e58\u51fd\u6570\u548c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u4f7f\u7528\u7684\u5185\u5b58\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 \u89e3\u7b54\uff1a \u9012\u5f52\u9636\u4e58\u51fd\u6570\u548c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u4f7f\u7528\u7684\u5185\u5b58\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u90fd\u4e0e\u9012\u5f52\u7684\u6df1\u5ea6\uff08\u9012\u5f52\u8c03\u7528\u7684\u5c42\u6570\uff09\u76f8\u5173\u3002\u9012\u5f52\u51fd\u6570\u6bcf\u6b21\u8c03\u7528\u90fd\u4f1a\u5728\u8c03\u7528\u6808\u4e2d\u5206\u914d\u4e00\u5b9a\u6570\u91cf\u7684\u5185\u5b58\uff0c\u5305\u62ec\u51fd\u6570\u7684\u53c2\u6570\u3001\u5c40\u90e8\u53d8\u91cf\u4ee5\u53ca\u8fd4\u56de\u5730\u5740\u7b49\u4fe1\u606f\u3002 \u9012\u5f52\u9636\u4e58\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\uff1a \u9012\u5f52\u9636\u4e58\u51fd\u6570\u662f\u4e00\u4e2a\u975e\u5e38\u7b80\u5355\u7684\u9012\u5f52\u51fd\u6570\uff0c\u5b83\u53ea\u9700\u8981\u4fdd\u5b58\u4e00\u4e2a\u6574\u6570\u53c2\u6570 n \u548c\u8fd4\u56de\u5730\u5740\u3002\u56e0\u6b64\uff0c\u5b83\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(1)\uff0c\u4e0e\u8f93\u5165\u53c2\u6570 n \u7684\u5927\u5c0f\u65e0\u5173\u3002\u6bcf\u4e2a\u9012\u5f52\u8c03\u7528\u90fd\u53ea\u9700\u8981\u5e38\u6570\u7ea7\u522b\u7684\u5185\u5b58\u7a7a\u95f4\u3002 \u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\uff1a \u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u9012\u5f52\u7684\u6df1\u5ea6\u3002\u6bcf\u4e2a\u9012\u5f52\u8c03\u7528\u90fd\u9700\u8981\u4fdd\u5b58\u4e24\u4e2a\u6574\u6570\u53c2\u6570 n \u548c depth \uff0c\u4ee5\u53ca\u8fd4\u56de\u5730\u5740\u3002\u56e0\u6b64\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u9700\u8981\u7684\u5185\u5b58\u7a7a\u95f4\u662f\u5e38\u6570\u7ea7\u522b\u7684\u3002 \u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u9012\u5f52\u6df1\u5ea6\u53d6\u51b3\u4e8e\u8f93\u5165\u53c2\u6570 n \u3002\u5177\u4f53\u6765\u8bf4\uff0c\u9012\u5f52\u6df1\u5ea6\u7b49\u4e8e n \u3002\u56e0\u6b64\uff0c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(n)\uff0c\u4e0e\u8f93\u5165\u53c2\u6570 n \u6210\u6b63\u6bd4\u3002 \u603b\u7ed3\u6765\u8bf4\uff0c\u9012\u5f52\u9636\u4e58\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(1)\uff0c\u800c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(n)\u3002\u5728\u9012\u5f52\u7b97\u6cd5\u4e2d\uff0c\u5185\u5b58\u590d\u6742\u5ea6\u901a\u5e38\u4e0e\u9012\u5f52\u6df1\u5ea6\u6210\u6b63\u6bd4\uff0c\u56e0\u6b64\u9700\u8981\u8c28\u614e\u5904\u7406\u9012\u5f52\u8c03\u7528\uff0c\u4ee5\u907f\u514d\u51fa\u73b0\u6808\u6ea2\u51fa\u7b49\u95ee\u9898\u3002\u53ef\u4ee5\u4f7f\u7528\u8fed\u4ee3\u6216\u52a8\u6001\u89c4\u5212\u7b49\u65b9\u6cd5\u6765\u964d\u4f4e\u5185\u5b58\u6d88\u8017\u3002","title":"3.10.\u7f16\u7a0b\u7ec3\u4e60"},{"location":"python/DataStructure/04_ArrayChain/","text":"4.\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784 \u00b6 \u6570\u636e\u7ed3\u6784\uff08data structure\uff09\u6216\u5177\u4f53\u6570\u636e\u7c7b\u578b\uff08concrete data type\uff09\u662f\u6307\u4e00\u7ec4\u6570\u636e\u7684\u5185\u90e8\u5b58\u50a8\u65b9\u5f0f\u3002 \u6570\u7ec4\uff08array\uff09\u548c\u94fe\u63a5\u7ed3\u6784\uff08linked structure\uff09\u8fd9\u4e24\u79cd\u6570\u636e\u7ed3\u6784\u662f\u7f16\u7a0b\u8bed\u8a00\u91cc\u591a\u9879\u96c6\u6700\u5e38\u7528\u7684\u5b9e\u73b0\u3002 \u76ee\u6807\uff1a \u521b\u5efa\u6570\u7ec4\uff1b \u5bf9\u6570\u7ec4\u6267\u884c\u5404\u79cd\u64cd\u4f5c\uff1b \u786e\u5b9a\u6570\u7ec4\u76f8\u5173\u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u7684\u4f7f\u7528\u60c5\u51b5\uff1b \u57fa\u4e8e\u6570\u7ec4\u5728\u8ba1\u7b97\u673a\u5185\u5b58\u91cc\u7684\u4e0d\u540c\u5b58\u50a8\u65b9\u5f0f\uff0c\u63cf\u8ff0\u6570\u7ec4\u76f8\u5173\u64cd\u4f5c\u7684\u6210\u672c\u548c\u6536\u76ca\uff1b \u4f7f\u7528\u5355\u5411\u94fe\u63a5\u8282\u70b9\u521b\u5efa\u94fe\u63a5\u7ed3\u6784\uff1b \u5bf9\u7531\u5355\u5411\u94fe\u63a5\u8282\u70b9\u6784\u6210\u7684\u94fe\u63a5\u7ed3\u6784\u6267\u884c\u5404\u79cd\u64cd\u4f5c\uff1b \u57fa\u4e8e\u94fe\u63a5\u7ed3\u6784\u5728\u8ba1\u7b97\u673a\u5185\u5b58\u91cc\u7684\u4e0d\u540c\u5b58\u50a8\u65b9\u5f0f\uff0c\u63cf\u8ff0\u5728\u94fe\u63a5\u7ed3\u6784\u4e0a\u6267\u884c\u76f8\u5173\u64cd\u4f5c\u7684\u6210\u672c\u548c\u6536\u76ca\uff1b \u6bd4\u8f83\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784\u5728\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u4f7f\u7528\u4e0a\u7684\u6743\u8861\uff1b 4.1.\u6570\u7ec4\u6570\u636e\u7ed3\u6784 \u00b6 \u5173\u4e8e\u6570\u7ec4\uff08array\uff09\uff1a \u6570\u7ec4\u662f\u6307\u5728\u7ed9\u5b9a\u7d22\u5f15\u4f4d\u7f6e\u53ef\u4ee5\u8bbf\u95ee\u548c\u66ff\u6362\u7684\u5143\u7d20\u5e8f\u5217\u3002 Python\u5217\u8868\u7684\u5e95\u5c42\u6570\u636e\u7ed3\u6784\u6b63\u662f\u4e00\u4e2a\u6570\u7ec4\u3002 Python\u4e2d\u6570\u7ec4\u7684\u9650\u5236\u8981\u6bd4\u5217\u8868\u66f4\u591a\u3002\u53ea\u80fd\u5728\u6307\u5b9a\u4f4d\u7f6e\u8bbf\u95ee\u548c\u66ff\u6362\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u3001\u68c0\u67e5\u6570\u7ec4\u7684\u957f\u5ea6\u3001\u83b7\u53d6\u5b83\u7684\u5b57\u7b26\u4e32\u8868\u8fbe\u5f0f\uff1b\u4e0d\u80fd\u57fa\u4e8e\u4f4d\u7f6e\u6dfb\u52a0\u6216\u5220\u9664\u5143\u7d20\uff1b\u6570\u7ec4\u7684\u957f\u5ea6\u4e5f\u5c31\u662f\u5b83\u7684\u5bb9\u91cf\uff0c\u5728\u521b\u5efa\u4e4b\u540e\u5c31\u662f\u56fa\u5b9a\u7684\u3002 Python\u7684 array \u6a21\u5757\u5305\u542b\u4e00\u4e2a\u53eb\u4f5c array \u7684\u7c7b\uff0c\u5b83\u975e\u5e38\u7c7b\u4f3c\u4e8e\u5217\u8868\uff0c\u4f46\u662f\u53ea\u80fd\u5b58\u50a8\u6570\u5b57\u3002\u6211\u4eec\u4f1a\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c Array \u7684\u65b0\u7c7b\uff0c\u4f7f\u7528\u5217\u8868\u4fdd\u5b58\u5143\u7d20\uff0c\u5b58\u50a8\u4efb\u4f55\u7c7b\u578b\u7684\u5143\u7d20\u3002 \u4e0b\u9762\u7684\u793a\u4f8b\u5b9a\u4e49\u4e86\u4e00\u4e2a\u6570\u7ec4\u4ee5\u53ca\u5bf9\u5e94\u7528\u6cd5\u3002 class Array ( object ): \"\"\" \u63cf\u8ff0\u4e00\u4e2a\u6570\u7ec4\u3002 \u6570\u7ec4\u7c7b\u4f3c\u5217\u8868\uff0c\u4f46\u6570\u7ec4\u53ea\u80fd\u4f7f\u7528[], len, iter, \u548c str\u8fd9\u4e9b\u5c5e\u6027\u3002 \u5b9e\u4f8b\u5316\u4e00\u4e2a\u6570\u7ec4\uff0c\u4f7f\u7528 = Array(, ) \u5176\u4e2dfill value\u9ed8\u8ba4\u503c\u662fNone\u3002 \"\"\" def __init__ ( self , capacity , fillValue = None ): \"\"\"Capacity\u662f\u6570\u7ec4\u7684\u5927\u5c0f. fillValue\u4f1a\u586b\u5145\u5728\u6bcf\u4e2a\u5143\u7d20\u4f4d\u7f6e, \u9ed8\u8ba4\u503c\u662fNone\"\"\" self . items = list () for count in range ( capacity ): self . items . append ( fillValue ) def __len__ ( self ): \"\"\"-> \u6570\u7ec4\u7684\u5927\u5c0f\"\"\" return len ( self . items ) def __str__ ( self ): \"\"\"-> \u5c06\u6570\u7ec4\u5b57\u7b26\u4e32\u5316\"\"\" return str ( self . items ) def __iter__ ( self ): \"\"\"\u652f\u6301for\u5faa\u73af\u5bf9\u6570\u7ec4\u8fdb\u884c\u904d\u5386.\"\"\" return iter ( self . items ) def __getitem__ ( self , index ): \"\"\"\u7528\u4e8e\u8bbf\u95ee\u7d22\u5f15\u5904\u7684\u4e0b\u6807\u8fd0\u7b97\u7b26.\"\"\" return self . items [ index ] def __setitem__ ( self , index , newItem ): \"\"\"\u4e0b\u6807\u8fd0\u7b97\u7b26\u7528\u4e8e\u5728\u7d22\u5f15\u5904\u8fdb\u884c\u66ff\u6362.\"\"\" self . items [ index ] = newItem def main ( size = 10 ): my_array = Array ( 5 ) print ( \"The array is: \" , my_array ) print ( \"__len__() of the array: \" , my_array . __len__ ()) print ( \"len() of the arry: \" , len ( my_array )) for i in range ( len ( my_array )): my_array [ i ] = i for i in my_array : print ( my_array [ i ], end = \" \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # The array is [None, None, None, None, None] # __len__() of the array: 5 # len() of the arry: 5 # 0 1 2 3 4 4.1.1.\u968f\u673a\u8bbf\u95ee\u548c\u8fde\u7eed\u5185\u5b58 \u00b6 \u901a\u8fc7\u4e0b\u6807\u64cd\u4f5c\u6216\u7d22\u5f15\u64cd\u4f5c\u5b9e\u73b0\u5bf9\u6570\u7ec4\u5728\u6307\u5b9a\u4f4d\u7f6e\u5bf9\u5143\u7d20\u8fdb\u884c\u5b58\u50a8\u6216\u68c0\u7d22\u3002 \u6570\u7ec4\u7d22\u5f15\u662f\u968f\u673a\u8bbf\u95ee\uff08random access\uff09\u64cd\u4f5c\uff0c\u800c\u5728\u968f\u673a\u8bbf\u95ee\u65f6\uff0c\u8ba1\u7b97\u673a\u603b\u4f1a\u6267\u884c\u56fa\u5b9a\u7684\u6b65\u9aa4\u6765\u83b7\u53d6\u7b2c i \u4e2a\u5143\u7d20\u7684\u4f4d\u7f6e\u3002\u56e0\u6b64\uff0c\u4e0d\u8bba\u6570\u7ec4\u6709\u591a\u5927\uff0c\u8bbf\u95ee\u7b2c\u4e00\u4e2a\u5143\u7d20\u6240\u9700\u7684\u65f6\u95f4\u548c\u8bbf\u95ee\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u6240\u9700\u8981\u7684\u65f6\u95f4\u90fd\u662f\u76f8\u540c\u7684\u3002 \u8ba1\u7b97\u673a\u901a\u8fc7\u5206\u914d\u4e00\u5757\u8fde\u7eed\u5185\u5b58\uff08contiguous memory\uff09\u5355\u5143\u6765\u5b58\u50a8\u6570\u7ec4\u91cc\u7684\u5143\u7d20\uff0c\u4ece\u800c\u652f\u6301\u5bf9\u6570\u7ec4\u7684\u968f\u673a\u8bbf\u95ee\u3002 \u7531\u4e8e\u6570\u7ec4\u91cc\u7684\u5143\u7d20\u5730\u5740\u90fd\u662f\u6309\u7167\u6570\u5b57\u987a\u5e8f\u8fdb\u884c\u6392\u5217\u7684\uff0c\u56e0\u6b64\u53ef\u4ee5\u901a\u8fc7\u6dfb\u52a0\u4e24\u4e2a\u503c\u6765\u8ba1\u7b97\u51fa\u6570\u7ec4\u5143\u7d20\u7684\u673a\u5668\u5730\u5740\uff0c\u5b83\u4eec\u662f\u6570\u7ec4\u7684\u57fa\u5730\u5740\uff08base address\uff09\u4ee5\u53ca\u5143\u7d20\u7684\u504f\u79fb\u91cf\uff08offset\uff09\u3002\u5176\u4e2d\uff0c\u6570\u7ec4\u7684\u57fa\u5730\u5740\u5c31\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20\u7684\u673a\u5668\u5730\u5740\uff0c\u800c\u5143\u7d20\u7684\u504f\u79fb\u91cf\u5c31\u662f\u5b83\u7684\u7d22\u5f15\u503c\u518d\u4e58\u4ee5\u4e00\u4e2a\u4ee3\u8868\u6570\u7ec4\u5143\u7d20\u6240\u9700\u5185\u5b58\u5355\u5143\u6570\u7684\u5e38\u91cf\uff08\u5728Python\u91cc\uff0c\u8fd9\u4e2a\u503c\u59cb\u7ec8\u662f1\uff09\u3002 \u7b80\u800c\u8a00\u4e4b\uff0cPython\u6570\u7ec4\u91cc\u7684\u7d22\u5f15\u64cd\u4f5c\u5305\u62ec\u4e0b\u9762\u4e24\u4e2a\u6b65\u9aa4\uff1a \u5f97\u5230\u6570\u7ec4\u5185\u5b58\u5757\u7684\u57fa\u5730\u5740\u3002 \u5c06\u7d22\u5f15\u503c\u6dfb\u52a0\u5230\u8fd9\u4e2a\u5730\u5740\u5e76\u8fd4\u56de\u3002 4.1.2.\u9759\u6001\u5185\u5b58\u548c\u52a8\u6001\u5185\u5b58 \u00b6 \u5728\u6bd4\u8f83\u8001\u7684\u7f16\u7a0b\u8bed\u8a00\uff08\u5982FORTRAN\u6216Pascal\uff09\u91cc\uff0c\u6570\u7ec4\u662f\u9759\u6001\u6570\u636e\u7ed3\u6784\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u7684\u957f\u5ea6\u6216\u5bb9\u91cf\u5728\u7f16\u8bd1\u65f6\u5c31\u786e\u5b9a\u4e86\uff0c\u7a0b\u5e8f\u5458\u9700\u8981\u7533\u8bf7\u8db3\u591f\u591a\u7684\u5185\u5b58\u6765\u6ee1\u8db3\u5728\u6570\u7ec4\u91cc\u5b58\u50a8\u53ef\u80fd\u6709\u6700\u5927\u6570\u91cf\u5143\u7d20\u7684\u60c5\u51b5\uff0c\u8fd9\u6837\u505a\u4f1a\u6d6a\u8d39\u5927\u91cf\u7684\u5185\u5b58\u3002 \u50cfJava\u548cC++\u8fd9\u7c7b\u7684\u73b0\u4ee3\u7f16\u7a0b\u8bed\u8a00\u4f1a\u5141\u8bb8\u7a0b\u5e8f\u5458\u521b\u5efa\u52a8\u6001\u6570\u7ec4\uff08dynamic array\uff09\uff0c\u4ece\u800c\u4e3a\u8fd9\u4e2a\u95ee\u9898\u63d0\u4f9b\u4e86\u4e00\u79cd\u8865\u6551\u65b9\u6cd5\u3002\u548c\u9759\u6001\u6570\u7ec4\u76f8\u4f3c\u7684\u662f\uff0c\u52a8\u6001\u6570\u7ec4\u4e5f\u4f1a\u5360\u7528\u4e00\u5757\u8fde\u7eed\u5185\u5b58\uff0c\u5e76\u652f\u6301\u968f\u673a\u8bbf\u95ee\u3002\u52a8\u6001\u6570\u7ec4\u7684\u957f\u5ea6\u53ea\u5728\u8fd0\u884c\u65f6\u624d\u77e5\u9053\uff0c\u5728\u52a8\u6001\u6570\u7ec4\u5b9e\u4f8b\u5316\u7684\u65f6\u5019\u6307\u5b9a\u5b83\u7684\u957f\u5ea6\u3002\u5728Python\u91cc\u5b9e\u73b0\u7684Array\u7c7b\u7684\u884c\u4e3a\u4e5f\u662f\u8fd9\u6837\u7684\u3002 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u53e6\u4e00\u79cd\u65b9\u6cd5\u5728\u8fd0\u884c\u65f6\u6839\u636e\u5e94\u7528\u7a0b\u5e8f\u7684\u6570\u636e\u8981\u6c42\u6765\u8c03\u6574\u6570\u7ec4\u7684\u957f\u5ea6\uff0c\u8fd9\u4e9b\u8c03\u6574\u4f1a\u7531Python\u5217\u8868\u81ea\u52a8\u8fdb\u884c\u3002\u8fd9\u65f6\uff0c\u6570\u7ec4\u6709\u4ee5\u4e0b3\u79cd\u4e0d\u540c\u5f62\u5f0f\u3002 \u5728\u7a0b\u5e8f\u542f\u52a8\u65f6\u521b\u5efa\u4e00\u4e2a\u5177\u6709\u5408\u7406\u9ed8\u8ba4\u5927\u5c0f\u7684\u6570\u7ec4\u3002 \u5f53\u6570\u7ec4\u65e0\u6cd5\u5bb9\u7eb3\u66f4\u591a\u6570\u636e\u65f6\uff0c\u521b\u5efa\u4e00\u4e2a\u66f4\u5927\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u628a\u65e7\u6570\u7ec4\u91cc\u7684\u6570\u636e\u5143\u7d20\u4f20\u8f93\u7ed9\u5b83\u3002 \u5982\u679c\u6570\u7ec4\u5728\u6d6a\u8d39\u5185\u5b58\uff08\u5e94\u7528\u7a0b\u5e8f\u5220\u9664\u4e86\u4e00\u4e9b\u6570\u636e\uff09\uff0c\u90a3\u4e48\u7528\u7c7b\u4f3c\u7684\u65b9\u5f0f\u51cf\u5c0f\u6570\u7ec4\u7684\u957f\u5ea6\u3002 4.1.3.\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8 \u00b6 \u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\uff08physical size\uff09\u662f\u6307\u6570\u7ec4\u5355\u5143\u7684\u603b\u6570\uff0c\u6216\u8005\u521b\u5efa\u6570\u7ec4\u65f6\u6307\u5b9a\u5176\u5bb9\u91cf\u7684\u90a3\u4e2a\u6570\u5b57\uff1b \u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\uff08logical size\uff09\u662f\u6307\u5f53\u524d\u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528\u7684\u5143\u7d20\u6570\u91cf\u3002 \u5f53\u6570\u7ec4\u88ab\u586b\u6ee1\u7684\u65f6\u5019\uff0c\u6211\u4eec\u4e0d\u9700\u8981\u62c5\u5fc3\u5b83\u4eec\u7684\u4e0d\u540c\u3002\u5f53\u6570\u7ec4\u88ab\u90e8\u5206\u586b\u6ee1\u7684\u65f6\u5019\uff0c\u672a\u88ab\u586b\u5145\u7684\u5185\u5b58\u5355\u5143\u91cc\u7684\u6570\u636e\u5bf9\u5f53\u524d\u5e94\u7528\u7a0b\u5e8f\u662f\u6ca1\u6709\u7528\u7684\uff0c\u6211\u4eec\u79f0\u4e4b\u5783\u573e\u5185\u5bb9\uff08garbage\uff09\u3002\u5728\u5927\u591a\u6570\u5e94\u7528\u7a0b\u5e8f\u91cc\uff0c\u6211\u4eec\u662f\u8981\u6ce8\u610f\u5bf9\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u8fdb\u884c\u8ffd\u8e2a\u3002\u901a\u5e38\u6765\u8bf4\uff0c\u903b\u8f91\u5c3a\u5bf8\u548c\u7269\u7406\u5c3a\u5bf8\u4f1a\u53cd\u6620\u51fa\u6709\u5173\u6570\u7ec4\u72b6\u6001\u7684\u51e0\u4e2a\u91cd\u70b9\u3002 \u5982\u679c\u903b\u8f91\u5c3a\u5bf8\u4e3a0\uff0c\u90a3\u4e48\u6570\u7ec4\u5c31\u4e3a\u7a7a\u3002\u4e5f\u5c31\u662f\u8bf4\uff0c\u8fd9\u4e2a\u6570\u7ec4\u4e0d\u5305\u542b\u4efb\u4f55\u6570\u636e\u5143\u7d20\u3002 \u5982\u679c\u5e76\u975e\u4e0a\u8ff0\u60c5\u51b5\uff0c\u5728\u4efb\u4f55\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u4e2d\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u7684\u7d22\u5f15\u90fd\u662f\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\u51cf1\u3002 \u5982\u679c\u903b\u8f91\u5c3a\u5bf8\u7b49\u4e8e\u7269\u7406\u5c3a\u5bf8\uff0c\u90a3\u4e48\u8868\u793a\u6570\u7ec4\u5df2\u88ab\u586b\u6ee1\u4e86\u3002 4.1.4.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u8bf7\u8bf4\u660e\u968f\u673a\u8bbf\u95ee\u7684\u5de5\u4f5c\u539f\u7406\uff0c\u4ee5\u53ca\u8fd9\u4e2a\u64cd\u4f5c\u8fd9\u4e48\u5feb\u7684\u539f\u56e0\u3002 \u89e3\u7b54\uff1a\u968f\u673a\u8bbf\u95ee\u662f\u4e00\u79cd\u8ba1\u7b97\u673a\u5b58\u50a8\u7cfb\u7edf\u4e2d\u7684\u8bfb\u53d6\u6216\u5199\u5165\u6570\u636e\u7684\u64cd\u4f5c\uff0c\u5176\u4e2d\u6570\u636e\u53ef\u4ee5\u901a\u8fc7\u76f4\u63a5\u8df3\u8f6c\u5230\u5176\u5b58\u50a8\u4f4d\u7f6e\u800c\u4e0d\u9700\u8981\u987a\u5e8f\u626b\u63cf\u6765\u8bbf\u95ee\u3002\u8fd9\u4e0e\u987a\u5e8f\u8bbf\u95ee\u4e0d\u540c\uff0c\u540e\u8005\u9700\u8981\u6309\u987a\u5e8f\u904d\u5386\u6570\u636e\u4ee5\u627e\u5230\u6240\u9700\u7684\u4fe1\u606f\u3002\u968f\u673a\u8bbf\u95ee\u7684\u5de5\u4f5c\u539f\u7406\u5982\u4e0b\uff1a \u5b58\u50a8\u4ecb\u8d28\uff1a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u786c\u76d8\u7b49\u5b58\u50a8\u8bbe\u5907\u90fd\u652f\u6301\u968f\u673a\u8bbf\u95ee\u3002\u8fd9\u4e9b\u5b58\u50a8\u4ecb\u8d28\u4e2d\u7684\u6570\u636e\u901a\u5e38\u88ab\u5212\u5206\u4e3a\u5757\u6216\u6247\u533a\uff0c\u5e76\u4e14\u6bcf\u4e2a\u5757\u6216\u6247\u533a\u90fd\u6709\u4e00\u4e2a\u552f\u4e00\u7684\u5730\u5740\u6216\u7d22\u5f15\u3002 \u8bbf\u95ee\u5730\u5740\uff1a\u4e3a\u4e86\u8fdb\u884c\u968f\u673a\u8bbf\u95ee\uff0c\u8ba1\u7b97\u673a\u9700\u8981\u77e5\u9053\u8981\u8bbf\u95ee\u7684\u6570\u636e\u7684\u5730\u5740\u3002\u8fd9\u4e2a\u5730\u5740\u53ef\u4ee5\u662f\u5185\u5b58\u4e2d\u7684\u7279\u5b9a\u4f4d\u7f6e\uff0c\u4e5f\u53ef\u4ee5\u662f\u786c\u76d8\u4e0a\u7684\u67d0\u4e2a\u6247\u533a\u7684\u5730\u5740\u3002 \u5bfb\u5740\u548c\u4f20\u8f93\uff1a\u8ba1\u7b97\u673a\u4f7f\u7528\u5b58\u50a8\u8bbe\u5907\u7684\u63a7\u5236\u5668\u6216\u5b58\u50a8\u5668\u7ba1\u7406\u5355\u5143\u6765\u67e5\u627e\u6570\u636e\u7684\u5730\u5740\u3002\u4e00\u65e6\u627e\u5230\u4e86\u6b63\u786e\u7684\u5730\u5740\uff0c\u5b58\u50a8\u8bbe\u5907\u4f1a\u5c06\u6570\u636e\u4f20\u8f93\u5230\u8ba1\u7b97\u673a\u7684\u5185\u5b58\u4e2d\u4f9b\u5904\u7406\u5668\u4f7f\u7528\u3002 \u8bbf\u95ee\u901f\u5ea6\uff1a\u968f\u673a\u8bbf\u95ee\u4e4b\u6240\u4ee5\u5982\u6b64\u5feb\u901f\uff0c\u662f\u56e0\u4e3a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u73b0\u4ee3\u786c\u76d8\u9a71\u52a8\u5668\u7b49\u5b58\u50a8\u8bbe\u5907\u90fd\u7ecf\u8fc7\u4e86\u4f18\u5316\uff0c\u53ef\u4ee5\u5feb\u901f\u54cd\u5e94\u8bbf\u95ee\u8bf7\u6c42\u3002\u8fd9\u4e9b\u8bbe\u5907\u4f7f\u7528\u4e86\u9ad8\u901f\u7f13\u5b58\u3001\u8bfb\u5199\u5934\u3001\u5bfb\u9053\u673a\u6784\u7b49\u6280\u672f\u6765\u6700\u5c0f\u5316\u6570\u636e\u8bbf\u95ee\u7684\u5ef6\u8fdf\u3002 \u539f\u56e0\uff1a \u5b58\u50a8\u8bbe\u5907\u7684\u7269\u7406\u7ed3\u6784\uff1a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u786c\u76d8\u7b49\u5b58\u50a8\u8bbe\u5907\u7684\u7269\u7406\u7ed3\u6784\u88ab\u8bbe\u8ba1\u6210\u53ef\u4ee5\u968f\u673a\u8bbf\u95ee\u7684\u3002\u5185\u5b58\u4e2d\u7684\u6bcf\u4e2a\u5730\u5740\u90fd\u53ef\u4ee5\u77ac\u95f4\u8bbf\u95ee\uff0c\u800c\u786c\u76d8\u4e0a\u7684\u6247\u533a\u4e5f\u53ef\u4ee5\u901a\u8fc7\u78c1\u5934\u5bfb\u9053\u548c\u65cb\u8f6c\u78c1\u76d8\u7b49\u673a\u5236\u8fc5\u901f\u8bbf\u95ee\u3002 \u9ad8\u901f\u7f13\u5b58\uff1a\u73b0\u4ee3\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u5904\u7406\u5668\u90fd\u914d\u5907\u4e86\u9ad8\u901f\u7f13\u5b58\uff08\u4f8b\u5982\uff0cCPU\u7f13\u5b58\uff09\u3002\u8fd9\u4e9b\u9ad8\u901f\u7f13\u5b58\u5b58\u50a8\u4e86\u6700\u8fd1\u8bbf\u95ee\u7684\u6570\u636e\uff0c\u53ef\u4ee5\u5feb\u901f\u63d0\u4f9b\u7ed9\u5904\u7406\u5668\uff0c\u4ece\u800c\u964d\u4f4e\u4e86\u8bbf\u95ee\u5ef6\u8fdf\u3002 \u5b58\u50a8\u5668\u7ba1\u7406\uff1a\u64cd\u4f5c\u7cfb\u7edf\u548c\u5b58\u50a8\u8bbe\u5907\u7684\u63a7\u5236\u5668\u4f1a\u7ba1\u7406\u5b58\u50a8\u5668\u7684\u8bbf\u95ee\uff0c\u4ee5\u786e\u4fdd\u6570\u636e\u53ef\u4ee5\u9ad8\u6548\u5730\u88ab\u8bbf\u95ee\u548c\u4f20\u8f93\u3002\u8fd9\u5305\u62ec\u4e86\u78c1\u76d8\u8c03\u5ea6\u7b97\u6cd5\u3001\u5185\u5b58\u5206\u9875\u7b49\u7b56\u7565\u3002 \u6280\u672f\u8fdb\u6b65\uff1a\u786c\u4ef6\u5236\u9020\u6280\u672f\u7684\u8fdb\u6b65\u548c\u5b58\u50a8\u8bbe\u5907\u7684\u4f18\u5316\u4f7f\u5f97\u968f\u673a\u8bbf\u95ee\u901f\u5ea6\u66f4\u5feb\u3002\u4f8b\u5982\uff0c\u56fa\u6001\u786c\u76d8\uff08SSD\uff09\u7684\u51fa\u73b0\u663e\u8457\u63d0\u9ad8\u4e86\u6570\u636e\u7684\u968f\u673a\u8bbf\u95ee\u901f\u5ea6\u3002 \u603b\u4e4b\uff0c\u968f\u673a\u8bbf\u95ee\u4e4b\u6240\u4ee5\u5982\u6b64\u5feb\u901f\uff0c\u662f\u56e0\u4e3a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u5b58\u50a8\u8bbe\u5907\u7684\u7269\u7406\u548c\u6280\u672f\u7279\u6027\u4f7f\u5176\u80fd\u591f\u4ee5\u9ad8\u6548\u3001\u8fc5\u901f\u7684\u65b9\u5f0f\u8bbf\u95ee\u6570\u636e\u3002\u8fd9\u79cd\u8bbf\u95ee\u901f\u5ea6\u5bf9\u4e8e\u8ba1\u7b97\u673a\u7684\u6027\u80fd\u548c\u54cd\u5e94\u65f6\u95f4\u81f3\u5173\u91cd\u8981\u3002 2\uff0e\u6570\u7ec4\u548cPython\u5217\u8868\u4e4b\u95f4\u6709\u4ec0\u4e48\u533a\u522b\uff1f \u89e3\u7b54\uff1a\u6570\u7ec4\u548cPython\u5217\u8868\u4e4b\u95f4\u6709\u51e0\u4e2a\u5173\u952e\u533a\u522b\uff0c\u8fd9\u4e9b\u533a\u522b\u5728\u6570\u636e\u7ed3\u6784\u3001\u529f\u80fd\u548c\u7528\u9014\u4e0a\u5b58\u5728\u5dee\u5f02\uff1a \u6570\u636e\u7c7b\u578b\uff1a \u6570\u7ec4\uff1a\u901a\u5e38\u8981\u6c42\u6240\u6709\u5143\u7d20\u5177\u6709\u76f8\u540c\u7684\u6570\u636e\u7c7b\u578b\u3002\u8fd9\u662f\u56e0\u4e3a\u6570\u7ec4\u5728\u5185\u5b58\u4e2d\u4ee5\u7d27\u51d1\u7684\u65b9\u5f0f\u5b58\u50a8\u6570\u636e\uff0c\u9700\u8981\u77e5\u9053\u6bcf\u4e2a\u5143\u7d20\u7684\u5927\u5c0f\u4ee5\u4fbf\u8fdb\u884c\u968f\u673a\u8bbf\u95ee\u3002 Python\u5217\u8868\uff1aPython\u7684\u5217\u8868\u53ef\u4ee5\u5bb9\u7eb3\u4e0d\u540c\u6570\u636e\u7c7b\u578b\u7684\u5143\u7d20\uff0c\u56e0\u4e3a\u5b83\u4eec\u662f\u52a8\u6001\u7c7b\u578b\u7684\u3002 \u5185\u5b58\u7ba1\u7406\uff1a \u6570\u7ec4\uff1a\u901a\u5e38\u5728\u521b\u5efa\u65f6\u9700\u8981\u6307\u5b9a\u56fa\u5b9a\u5927\u5c0f\uff0c\u56e0\u6b64\u5728\u5185\u5b58\u4e2d\u4f1a\u5206\u914d\u4e00\u5757\u8fde\u7eed\u7684\u7a7a\u95f4\uff0c\u8fd9\u4f7f\u5f97\u6570\u7ec4\u5bf9\u4e8e\u9ad8\u6548\u7684\u968f\u673a\u8bbf\u95ee\u975e\u5e38\u9002\u7528\u3002 Python\u5217\u8868\uff1aPython\u7684\u5217\u8868\u662f\u52a8\u6001\u7684\uff0c\u5b83\u4eec\u53ef\u4ee5\u6839\u636e\u9700\u8981\u81ea\u52a8\u6269\u5c55\u6216\u7f29\u5c0f\u3002\u8fd9\u5bfc\u81f4\u4e86\u4e00\u4e9b\u989d\u5916\u7684\u5185\u5b58\u5f00\u9500\uff0c\u56e0\u4e3a\u5217\u8868\u9700\u8981\u66f4\u591a\u7684\u7a7a\u95f4\u6765\u7ba1\u7406\u5143\u7d20\u7684\u6dfb\u52a0\u548c\u5220\u9664\u3002 \u6027\u80fd\uff1a \u6570\u7ec4\uff1a\u7531\u4e8e\u5185\u5b58\u5e03\u5c40\u8fde\u7eed\uff0c\u56e0\u6b64\u6570\u7ec4\u901a\u5e38\u5728\u8bbf\u95ee\u5143\u7d20\u65f6\u66f4\u5feb\u3002\u6570\u7ec4\u8fd8\u652f\u6301\u66f4\u591a\u7684\u5e95\u5c42\u64cd\u4f5c\uff0c\u5982\u4f4d\u64cd\u4f5c\u3002 Python\u5217\u8868\uff1aPython\u5217\u8868\u66f4\u52a0\u7075\u6d3b\uff0c\u4f46\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\u53ef\u80fd\u4f1a\u5bfc\u81f4\u6027\u80fd\u4e0b\u964d\uff0c\u7279\u522b\u662f\u5f53\u6d89\u53ca\u5927\u91cf\u5143\u7d20\u7684\u63d2\u5165\u548c\u5220\u9664\u64cd\u4f5c\u65f6\u3002 \u64cd\u4f5c\u548c\u65b9\u6cd5\uff1a \u6570\u7ec4\uff1a\u901a\u5e38\u63d0\u4f9b\u4e00\u7ec4\u57fa\u672c\u64cd\u4f5c\uff0c\u5982\u8bfb\u53d6\u548c\u5199\u5165\u5143\u7d20\uff0c\u4ee5\u53ca\u4e00\u4e9b\u6570\u5b66\u8fd0\u7b97\uff0c\u5982\u5411\u91cf\u5316\u64cd\u4f5c\u3002 Python\u5217\u8868\uff1aPython\u5217\u8868\u63d0\u4f9b\u4e86\u66f4\u4e30\u5bcc\u7684\u65b9\u6cd5\u548c\u64cd\u4f5c\uff0c\u5305\u62ec\u5143\u7d20\u7684\u63d2\u5165\u3001\u5220\u9664\u3001\u8ffd\u52a0\u3001\u5207\u7247\u3001\u8fde\u63a5\u7b49\u3002 \u8bed\u8a00\u4f9d\u8d56\u6027\uff1a \u6570\u7ec4\uff1a\u6570\u7ec4\u901a\u5e38\u662f\u7f16\u7a0b\u8bed\u8a00\u7684\u4e00\u90e8\u5206\uff0c\u5177\u6709\u56fa\u5b9a\u7684\u8bed\u6cd5\u548c\u8bed\u4e49\u3002 Python\u5217\u8868\uff1aPython\u7684\u5217\u8868\u662fPython\u6807\u51c6\u5e93\u7684\u4e00\u90e8\u5206\uff0c\u4e0ePython\u7684\u52a8\u6001\u7279\u6027\u76f8\u9002\u5e94\u3002 \u9002\u7528\u573a\u666f\uff1a \u6570\u7ec4\uff1a\u9002\u7528\u4e8e\u9700\u8981\u9ad8\u6548\u968f\u673a\u8bbf\u95ee\u7684\u60c5\u51b5\uff0c\u5982\u6570\u503c\u8ba1\u7b97\u3001\u56fe\u50cf\u5904\u7406\u7b49\u3002 Python\u5217\u8868\uff1a\u9002\u7528\u4e8e\u66f4\u5e7f\u6cdb\u7684\u5e94\u7528\uff0c\u7279\u522b\u662f\u5728\u7f16\u5199Python\u4ee3\u7801\u65f6\uff0c\u56e0\u4e3a\u5b83\u4eec\u66f4\u7075\u6d3b\u4e14\u6613\u4e8e\u4f7f\u7528\u3002 \u603b\u4e4b\uff0c\u6570\u7ec4\u548cPython\u5217\u8868\u90fd\u6709\u81ea\u5df1\u7684\u4f18\u52bf\u548c\u9002\u7528\u573a\u666f\u3002\u9009\u62e9\u4f7f\u7528\u54ea\u79cd\u6570\u636e\u7ed3\u6784\u53d6\u51b3\u4e8e\u5177\u4f53\u7684\u9700\u6c42\u548c\u7f16\u7a0b\u8bed\u8a00\u3002\u5728Python\u4e2d\uff0c\u901a\u5e38\u4f1a\u4f18\u5148\u9009\u62e9\u4f7f\u7528\u5217\u8868\uff0c\u56e0\u4e3a\u5b83\u4eec\u66f4\u65b9\u4fbf\uff0c\u800c\u5728\u5176\u4ed6\u7f16\u7a0b\u8bed\u8a00\u4e2d\uff0c\u5982C\u6216Java\uff0c\u6570\u7ec4\u53ef\u80fd\u66f4\u4e3a\u5e38\u89c1\u3002 \u5728\u8fd9\u91cc\u9700\u8981\u8bf4\u660e\u4e00\u4e2a\u6982\u5ff5\u3002\u5728Python\u4e2d\uff0c\u672f\u8bed\"\u6570\u7ec4\"\u901a\u5e38\u6307\u7684\u662fNumPy\u5e93\u4e2d\u7684\u6570\u7ec4\u5bf9\u8c61\uff0c\u800c\"\u5217\u8868\"\u6307\u7684\u662fPython\u7684\u5185\u7f6e\u5217\u8868\uff08list\uff09\u6570\u636e\u7ed3\u6784\u3002\u8fd9\u4e24\u8005\u4e4b\u95f4\u6709\u4ee5\u4e0b\u533a\u522b\uff1a \u6570\u636e\u7c7b\u578b\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1aNumPy\u5e93\u63d0\u4f9b\u4e86\u4e00\u4e2a\u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61\uff0c\u5b83\u53ef\u4ee5\u5305\u542b\u76f8\u540c\u6570\u636e\u7c7b\u578b\u7684\u5143\u7d20\uff0c\u5e76\u652f\u6301\u9ad8\u7ea7\u6570\u5b66\u3001\u79d1\u5b66\u548c\u5de5\u7a0b\u8ba1\u7b97\u3002NumPy\u6570\u7ec4\u7684\u5143\u7d20\u7c7b\u578b\u901a\u5e38\u662f\u56fa\u5b9a\u7684\uff0c\u4f8b\u5982\uff0c\u53ef\u4ee5\u662f\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u590d\u6570\u7b49\u3002\u8fd9\u4e9b\u6570\u7ec4\u662f\u9ad8\u6027\u80fd\u7684\uff0c\u652f\u6301\u5411\u91cf\u5316\u64cd\u4f5c\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u7684\u5185\u7f6e\u5217\u8868\u662f\u4e00\u79cd\u901a\u7528\u7684\u3001\u52a8\u6001\u7c7b\u578b\u7684\u6570\u636e\u7ed3\u6784\uff0c\u53ef\u4ee5\u5305\u542b\u4e0d\u540c\u6570\u636e\u7c7b\u578b\u7684\u5143\u7d20\uff0c\u4f8b\u5982\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u5b57\u7b26\u4e32\u3001\u5bf9\u8c61\u7b49\u3002\u5217\u8868\u53ef\u4ee5\u52a8\u6001\u6269\u5c55\u548c\u7f29\u5c0f\uff0c\u5e76\u63d0\u4f9b\u4e86\u4e30\u5bcc\u7684\u5185\u7f6e\u65b9\u6cd5\u548c\u64cd\u4f5c\u3002 \u6027\u80fd\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1aNumPy\u6570\u7ec4\u901a\u5e38\u6bd4Python\u5217\u8868\u66f4\u9ad8\u6548\uff0c\u7279\u522b\u662f\u5728\u8fdb\u884c\u6570\u503c\u8ba1\u7b97\u548c\u79d1\u5b66\u8ba1\u7b97\u65f6\u3002\u5b83\u4eec\u5185\u90e8\u4f7f\u7528\u4e86C\u8bed\u8a00\u5b9e\u73b0\uff0c\u652f\u6301\u5411\u91cf\u5316\u64cd\u4f5c\uff0c\u56e0\u6b64\u5728\u5927\u89c4\u6a21\u6570\u636e\u5904\u7406\u4e2d\u901a\u5e38\u66f4\u5feb\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u5217\u8868\u867d\u7136\u7075\u6d3b\uff0c\u4f46\u6027\u80fd\u76f8\u5bf9\u8f83\u4f4e\uff0c\u4e0d\u9002\u5408\u5927\u89c4\u6a21\u7684\u6570\u503c\u8ba1\u7b97\u3002\u5b83\u4eec\u7684\u5143\u7d20\u7c7b\u578b\u53ef\u4ee5\u4e0d\u540c\uff0c\u8fd9\u610f\u5473\u7740\u9700\u8981\u66f4\u591a\u7684\u5185\u5b58\u548c\u5904\u7406\u65f6\u95f4\u6765\u7ba1\u7406\u5143\u7d20\u3002 \u5e93\u4f9d\u8d56\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1a\u4f7f\u7528NumPy\u5e93\u9700\u8981\u5b89\u88c5NumPy\u6a21\u5757\u3002NumPy\u662fPython\u4e2d\u7528\u4e8e\u6570\u503c\u8ba1\u7b97\u7684\u6838\u5fc3\u5e93\uff0c\u5e7f\u6cdb\u5e94\u7528\u4e8e\u79d1\u5b66\u8ba1\u7b97\u3001\u673a\u5668\u5b66\u4e60\u7b49\u9886\u57df\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u7684\u5185\u7f6e\u5217\u8868\u662fPython\u6807\u51c6\u5e93\u7684\u4e00\u90e8\u5206\uff0c\u65e0\u9700\u989d\u5916\u5b89\u88c5\u3002 \u529f\u80fd\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1aNumPy\u6570\u7ec4\u63d0\u4f9b\u4e86\u8bb8\u591a\u6570\u5b66\u548c\u79d1\u5b66\u8ba1\u7b97\u51fd\u6570\uff0c\u5982\u7ebf\u6027\u4ee3\u6570\u3001\u5085\u7acb\u53f6\u53d8\u6362\u3001\u7edf\u8ba1\u5206\u6790\u7b49\u3002\u5b83\u4eec\u9002\u7528\u4e8e\u5904\u7406\u5927\u91cf\u6570\u503c\u6570\u636e\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u5217\u8868\u63d0\u4f9b\u4e86\u901a\u7528\u7684\u6570\u636e\u5bb9\u5668\uff0c\u7528\u4e8e\u5b58\u50a8\u548c\u7ba1\u7406\u5404\u79cd\u7c7b\u578b\u7684\u6570\u636e\uff0c\u4f46\u4e0d\u63d0\u4f9b\u4e13\u95e8\u7684\u6570\u5b66\u548c\u79d1\u5b66\u8ba1\u7b97\u529f\u80fd\u3002 \u5982\u679c\u9700\u8981\u8fdb\u884c\u6570\u503c\u8ba1\u7b97\u3001\u79d1\u5b66\u8ba1\u7b97\u6216\u6570\u636e\u5206\u6790\uff0c\u901a\u5e38\u4f1a\u4f7f\u7528NumPy\u6570\u7ec4\u3002\u5982\u679c\u53ea\u662f\u9700\u8981\u4e00\u4e2a\u901a\u7528\u7684\u6570\u636e\u5bb9\u5668\uff0c\u7528\u4e8e\u5b58\u50a8\u548c\u7ba1\u7406\u6570\u636e\uff0c\u90a3\u4e48Python\u5217\u8868\u901a\u5e38\u8db3\u591f\u4e86\u3002 3\uff0e\u8bf7\u8bf4\u660e\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u4e4b\u95f4\u7684\u533a\u522b\u3002 \u89e3\u7b54\uff1a\"\u7269\u7406\u5c3a\u5bf8\"\u548c\"\u903b\u8f91\u5c3a\u5bf8\"\u901a\u5e38\u7528\u4e8e\u63cf\u8ff0\u6570\u636e\u7ed3\u6784\u4e2d\u7684\u4e24\u4e2a\u4e0d\u540c\u65b9\u9762\uff1a \u7269\u7406\u5c3a\u5bf8\uff08Physical Size\uff09\uff1a \u7269\u7406\u5c3a\u5bf8\u662f\u6307\u6570\u636e\u7ed3\u6784\u5b9e\u9645\u5360\u7528\u7684\u5185\u5b58\u7a7a\u95f4\u6216\u5b58\u50a8\u4ecb\u8d28\u4e2d\u7684\u7a7a\u95f4\u5927\u5c0f\u3002 \u5b83\u8868\u793a\u6570\u636e\u7ed3\u6784\u5728\u8ba1\u7b97\u673a\u5185\u5b58\u6216\u78c1\u76d8\u4e2d\u6240\u5360\u636e\u7684\u5b9e\u9645\u5b57\u8282\u6570\u3002 \u7269\u7406\u5c3a\u5bf8\u4e0e\u6570\u636e\u7ed3\u6784\u7684\u5b58\u50a8\u65b9\u5f0f\u3001\u6570\u636e\u7c7b\u578b\u4ee5\u53ca\u8ba1\u7b97\u673a\u67b6\u6784\u6709\u5173\u3002 \u903b\u8f91\u5c3a\u5bf8\uff08Logical Size\uff09\uff1a \u903b\u8f91\u5c3a\u5bf8\u662f\u6307\u6570\u636e\u7ed3\u6784\u4e2d\u5305\u542b\u7684\u5143\u7d20\u6570\u91cf\u6216\u6570\u636e\u9879\u7684\u6570\u91cf\u3002 \u5b83\u8868\u793a\u6570\u636e\u7ed3\u6784\u5185\u90e8\u7684\u5143\u7d20\u6570\u91cf\u6216\u6570\u636e\u9879\u7684\u4e2a\u6570\uff0c\u4e0d\u6d89\u53ca\u5b9e\u9645\u7684\u5b58\u50a8\u5927\u5c0f\u3002 \u903b\u8f91\u5c3a\u5bf8\u901a\u5e38\u7528\u4e8e\u63cf\u8ff0\u6570\u636e\u7ed3\u6784\u7684\u5bb9\u91cf\u3001\u89c4\u6a21\u6216\u7ef4\u5ea6\u3002 \u8fd9\u4e24\u4e2a\u6982\u5ff5\u4e4b\u95f4\u7684\u5173\u7cfb\u5982\u4e0b\uff1a \u4e00\u4e2a\u6570\u636e\u7ed3\u6784\u53ef\u4ee5\u5177\u6709\u56fa\u5b9a\u7684\u7269\u7406\u5c3a\u5bf8\uff08\u5360\u636e\u56fa\u5b9a\u6570\u91cf\u7684\u5b57\u8282\uff09\uff0c\u4f46\u5176\u903b\u8f91\u5c3a\u5bf8\u53ef\u4ee5\u6839\u636e\u5b9e\u9645\u5b58\u50a8\u7684\u5143\u7d20\u6570\u91cf\u800c\u53d8\u5316\u3002 \u7269\u7406\u5c3a\u5bf8\u901a\u5e38\u662f\u7531\u8ba1\u7b97\u673a\u786c\u4ef6\u548c\u64cd\u4f5c\u7cfb\u7edf\u7ba1\u7406\u7684\uff0c\u800c\u903b\u8f91\u5c3a\u5bf8\u5219\u662f\u7a0b\u5e8f\u5458\u6839\u636e\u6570\u636e\u7ed3\u6784\u7684\u8bbe\u8ba1\u6765\u7ba1\u7406\u7684\u3002 \u4e3e\u4f8b\u6765\u8bf4\uff0c\u4e00\u4e2a\u6574\u6570\u6570\u7ec4\u53ef\u4ee5\u5177\u6709\u56fa\u5b9a\u7684\u7269\u7406\u5c3a\u5bf8\uff0c\u4f8b\u59824\u5b57\u8282/\u6574\u6570\uff0c\u4f46\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\u53ef\u4ee5\u662f\u6570\u7ec4\u4e2d\u6574\u6570\u7684\u6570\u91cf\uff0c\u53ef\u4ee5\u662f0\u4e2a\u300110\u4e2a\u3001100\u4e2a\u7b49\u7b49\u3002\u56e0\u6b64\uff0c\u903b\u8f91\u5c3a\u5bf8\u63cf\u8ff0\u4e86\u6570\u7ec4\u53ef\u4ee5\u5bb9\u7eb3\u7684\u5143\u7d20\u6570\u91cf\uff0c\u800c\u7269\u7406\u5c3a\u5bf8\u63cf\u8ff0\u4e86\u5b9e\u9645\u5360\u7528\u7684\u5185\u5b58\u7a7a\u95f4\u3002 \u5728\u6570\u636e\u7ed3\u6784\u7684\u8bbe\u8ba1\u548c\u4f7f\u7528\u4e2d\uff0c\u4e86\u89e3\u548c\u7ba1\u7406\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u5bf9\u4e8e\u6709\u6548\u5730\u5229\u7528\u8ba1\u7b97\u673a\u8d44\u6e90\u975e\u5e38\u91cd\u8981\u3002 4.2.\u6570\u7ec4\u7684\u64cd\u4f5c \u00b6 \u5728\u4e0b\u9762\u7684\u4f8b\u5b50\u91cc\uff0c\u6211\u4eec\u5047\u5b9a\u6709\u4e0b\u9762\u8fd9\u4e9b\u6570\u636e\u914d\u7f6e\u3002 DEFAULT_CAPACITY = 5 # \u6570\u7ec4\u9ed8\u8ba4\u7684\u7269\u7406\u5c3a\u5bf8\uff08\u4e5f\u5c31\u662f\u5bb9\u91cf\uff09\u662f5 logicalSize = 0 # \u6570\u7ec4\u7684\u521d\u59cb\u903b\u8f91\u5c3a\u5bf8\u662f0 a = Array ( DEFAULT_CAPACITY ) 4.2.1.\u589e\u5927\u6570\u7ec4\u7684\u5c3a\u5bf8 \u00b6 \u5f53\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u7b49\u4e8e\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u65f6\uff0c\u5982\u679c\u8981\u63d2\u5165\u65b0\u7684\u5143\u7d20\uff0c\u5c31\u9700\u8981\u589e\u5927\u6570\u7ec4\u7684\u5c3a\u5bf8\u3002 \u5982\u679c\u9700\u8981\u4e3a\u6570\u7ec4\u63d0\u4f9b\u66f4\u591a\u5185\u5b58\uff0cPython\u7684list\u7c7b\u578b\u4f1a\u5728\u8c03\u7528insert\u6216append\u65b9\u6cd5\u65f6\u6267\u884c\u8fd9\u4e2a\u64cd\u4f5c\u3002 \u8c03\u6574\u6570\u7ec4\u5c3a\u5bf8\u7684\u8fc7\u7a0b\u5305\u542b\u5982\u4e0b3\u4e2a\u6b65\u9aa4\u3002 \u521b\u5efa\u4e00\u4e2a\u66f4\u5927\u7684\u65b0\u6570\u7ec4\u3002 \u5c06\u6570\u636e\u4ece\u65e7\u6570\u7ec4\u4e2d\u590d\u5236\u5230\u65b0\u6570\u7ec4\u3002 \u5c06\u6307\u5411\u65e7\u6570\u7ec4\u7684\u53d8\u91cf\u6307\u5411\u65b0\u6570\u7ec4\u5bf9\u8c61\u3002 \u4e0b\u9762\u4ee3\u7801\u5b9e\u73b0\u3002 class Array ( object ): ... def main ( size = 10 ): DEFAULT_CAPACITY = 5 logicalSize = 0 my_array = Array ( DEFAULT_CAPACITY ) print ( \"Initial array is: \" , my_array ) print ( \"Len of the array: \" , my_array . __len__ ()) for i in range ( len ( my_array )): my_array [ i ] = i print ( \"The array is: \" , my_array . items ) # \u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 if logicalSize == len ( my_array ): temp = Array ( len ( my_array ) + 1 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 if __name__ == \"__main__\" : main () \u5728\u4e0a\u9762\u4ee3\u7801\u4e2d\uff0c\u901a\u8fc7 temp[i] = my_array[i] \u6765\u8c03\u6574\u6570\u7ec4\u5c3a\u5bf8\uff0c\u8fd9\u4e2a\u590d\u5236\u64cd\u4f5c\u7684\u6570\u91cf\u662f\u7ebf\u6027\u589e\u957f\u7684\u3002\u56e0\u6b64\uff0c\u5c06 n \u4e2a\u5143\u7d20\u6dfb\u52a0\u5230\u6570\u7ec4\u91cc\u7684\u603b\u65f6\u95f4\u590d\u6742\u5ea6\u662f 1+2+3...+n \uff0c\u4e5f\u5c31\u662f n(n+1)/2 \uff0c\u56e0\u6b64\u662f O(n^2) \u3002 \u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\uff0c\u901a\u8fc7 temp = Array(len(my_array) + 1) \u5bf9\u6570\u7ec4\u8fdb\u884c\u52a8\u6001\u6269\u5c55\uff0c\u5bf9\u6027\u80fd\u4f1a\u4ea7\u751f\u4e00\u4e9b\u53ef\u80fd\u7684\u5f71\u54cd\uff1a \u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u52a8\u6001\u6269\u5c55\u6570\u7ec4\u901a\u5e38\u9700\u8981\u590d\u5236\u73b0\u6709\u6570\u636e\u5230\u65b0\u7684\u5185\u5b58\u4f4d\u7f6e\uff0c\u8fd9\u5c06\u6d89\u53ca\u5230\u5143\u7d20\u7684\u590d\u5236\u64cd\u4f5c\u3002\u8fd9\u4e9b\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u6570\u7ec4\u7684\u957f\u5ea6\uff0c\u901a\u5e38\u662f O(n) \uff0c\u5176\u4e2d n \u662f\u6570\u7ec4\u7684\u957f\u5ea6\u3002\u56e0\u6b64\uff0c\u5f53\u6570\u7ec4\u9700\u8981\u6269\u5c55\u65f6\uff0c\u53ef\u80fd\u4f1a\u4ea7\u751f\u4e00\u4e9b\u989d\u5916\u7684\u65f6\u95f4\u5f00\u9500\u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\uff1a\u52a8\u6001\u6269\u5c55\u6570\u7ec4\u4f1a\u5360\u7528\u989d\u5916\u7684\u5185\u5b58\u7a7a\u95f4\uff0c\u56e0\u4e3a\u9700\u8981\u5206\u914d\u65b0\u7684\u5185\u5b58\u5757\u6765\u5bb9\u7eb3\u6269\u5c55\u540e\u7684\u6570\u7ec4\u3002\u8fd9\u53ef\u80fd\u4f1a\u5bfc\u81f4\u5185\u5b58\u788e\u7247\u5316\uff0c\u7279\u522b\u662f\u5728\u9891\u7e41\u6269\u5c55\u548c\u7f29\u5c0f\u6570\u7ec4\u65f6\u3002 \u6269\u5c55\u9891\u7387\uff1a\u6269\u5c55\u6570\u7ec4\u7684\u9891\u7387\u4f1a\u5f71\u54cd\u6027\u80fd\u3002\u5982\u679c\u6570\u7ec4\u9700\u8981\u9891\u7e41\u6269\u5c55\uff0c\u90a3\u4e48\u590d\u5236\u548c\u5185\u5b58\u5206\u914d\u7684\u5f00\u9500\u4f1a\u66f4\u52a0\u663e\u8457\uff0c\u4ece\u800c\u964d\u4f4e\u6027\u80fd\u3002\u56e0\u6b64\uff0c\u5728\u8bbe\u8ba1\u6570\u636e\u7ed3\u6784\u65f6\uff0c\u901a\u5e38\u4f1a\u8003\u8651\u521d\u59cb\u5bb9\u91cf\u548c\u6269\u5c55\u7b56\u7565\uff0c\u4ee5\u51cf\u5c11\u4e0d\u5fc5\u8981\u7684\u6269\u5c55\u6b21\u6570\u3002 Amortized Analysis\uff1a\u4e00\u4e9b\u6570\u636e\u7ed3\u6784\uff0c\u4f8b\u5982Python\u7684\u5217\u8868\uff08list\uff09\uff0c\u91c7\u7528\u644a\u8fd8\u5206\u6790\u6765\u5e73\u644a\u52a8\u6001\u6269\u5c55\u7684\u5f00\u9500\u3002\u8fd9\u610f\u5473\u7740\u867d\u7136\u67d0\u4e9b\u64cd\u4f5c\u53ef\u80fd\u4f1a\u82b1\u8d39 O(n) \u7684\u65f6\u95f4\uff0c\u4f46\u8fd9\u4e9b\u5f00\u9500\u5728\u4e00\u7cfb\u5217\u64cd\u4f5c\u4e2d\u88ab\u5206\u644a\uff0c\u5e73\u5747\u4e0b\u6765\u4ecd\u7136\u4fdd\u6301\u8f83\u4f4e\u7684\u590d\u6742\u5ea6\u3002\u8fd9\u53ef\u4ee5\u5728\u4e00\u5b9a\u7a0b\u5ea6\u4e0a\u7f13\u89e3\u6027\u80fd\u95ee\u9898\u3002 \u52a8\u6001\u6269\u5c55\u6570\u7ec4\u4f1a\u5f15\u5165\u4e00\u4e9b\u6027\u80fd\u5f00\u9500\uff0c\u4f46\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u8fd9\u79cd\u5f00\u9500\u901a\u5e38\u662f\u53ef\u4ee5\u63a5\u53d7\u7684\u3002\u4e3a\u4e86\u4f18\u5316\u6027\u80fd\uff0c\u53ef\u4ee5\u8003\u8651\u4ee5\u4e0b\u51e0\u70b9\u7b56\u7565\uff0c\u9700\u8981\u6839\u636e\u5177\u4f53\u5e94\u7528\u7684\u9700\u6c42\u548c\u6027\u80fd\u8981\u6c42\u6765\u6743\u8861\u8fd9\u4e9b\u56e0\u7d20\uff1a \u9884\u5148\u5206\u914d\u8db3\u591f\u7684\u521d\u59cb\u5bb9\u91cf\uff0c\u4ee5\u51cf\u5c11\u6269\u5c55\u7684\u9891\u7387\u3002 \u4f7f\u7528\u644a\u8fd8\u5206\u6790\u6765\u5e73\u644a\u5f00\u9500\u3002 \u8003\u8651\u4f7f\u7528\u5176\u4ed6\u6570\u636e\u7ed3\u6784\uff0c\u5982\u94fe\u8868\uff0c\u5bf9\u63d2\u5165\u548c\u5220\u9664\u64cd\u4f5c\u7684\u6027\u80fd\u66f4\u52a0\u53cb\u597d\u3002 \u4e0b\u9762\uff0c\u5c1d\u8bd5\u5728\u6bcf\u6b21\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u65f6\u628a\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\uff0c\u4ee3\u7801\u5b9e\u73b0\u5982\u4e0b\uff1a class Array ( object ): ... def main ( size = 10 ): # \u521d\u59cb\u503c DEFAULT_CAPACITY = 5 logicalSize = 0 my_array = Array ( DEFAULT_CAPACITY ) # \u6253\u5370\u8f93\u51fa\u521d\u59cb\u6570\u7ec4\u4fe1\u606f print ( \"Initial array is: \" , my_array ) print ( \"Len of the array: \" , my_array . __len__ ()) # \u7ed9\u6570\u7ec4\u8d4b\u503c for i in range ( len ( my_array )): my_array [ i ] = i print ( \"The array is: \" , my_array . items ) # \u6253\u5370\u8f93\u51fa\u6570\u7ec4 # \u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 while logicalSize < DEFAULT_CAPACITY * 2 : logicalSize += 1 if logicalSize == len ( my_array ): # \u89e6\u53d1\u6761\u4ef6 temp = Array ( len ( my_array ) + 1 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 print ( \"The array after increased is: \" , my_array . items ) # \u6253\u5370\u8f93\u51fa\u6570\u7ec4 if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Initial array is: [None, None, None, None, None] # Len of the array: 5 # The array is: [0, 1, 2, 3, 4] # The array after increased is: [0, 1, 2, 3, 4, None, None, None, None, None, None] \u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u6765\u6269\u5c55\u6570\u7ec4\u7684\u65b9\u5f0f\u662f\u4e00\u79cd\u5e38\u89c1\u7684\u7b56\u7565\uff0c\u901a\u5e38\u7528\u4e8e\u51cf\u5c11\u52a8\u6001\u6570\u7ec4\u7684\u9891\u7e41\u6269\u5c55\u6b21\u6570\uff0c\u4ee5\u63d0\u9ad8\u6027\u80fd\u3002\u8fd9\u79cd\u65b9\u5f0f\u7684\u64cd\u4f5c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3b\u8981\u53d6\u51b3\u4e8e\u6269\u5c55\u64cd\u4f5c\u7684\u9891\u7387\u548c\u5143\u7d20\u7684\u590d\u5236\u6210\u672c\u3002 \u644a\u8fd8\u5206\u6790\uff1a\u5bf9\u4e8e\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u7684\u7b56\u7565\uff0c\u644a\u8fd8\u5206\u6790\u8868\u660e\uff0c\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u7684\u644a\u8fd8\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662f\u5e38\u6570\u65f6\u95f4\u7684\uff08\u901a\u5e38\u662fO(1)\uff09\uff0c\u8fd9\u610f\u5473\u7740\u5e73\u5747\u4e0b\u6765\uff0c\u6bcf\u6b21\u6269\u5c55\u7684\u5f00\u9500\u662f\u56fa\u5b9a\u7684\uff0c\u800c\u4e0d\u4f1a\u968f\u6570\u7ec4\u7684\u5927\u5c0f\u7ebf\u6027\u589e\u52a0\u3002 \u64cd\u4f5c\u65f6\u95f4\uff1a\u5047\u8bbe\u6570\u7ec4\u9700\u8981\u6269\u5c55\uff0c\u90a3\u4e48\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u9700\u8981\u5206\u914d\u65b0\u7684\u5185\u5b58\u5757\u5e76\u590d\u5236\u73b0\u6709\u5143\u7d20\uff0c\u8fd9\u4e2a\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\uff0c\u5176\u4e2dn\u662f\u6570\u7ec4\u7684\u5f53\u524d\u5927\u5c0f\u3002\u7136\u800c\uff0c\u7531\u4e8e\u6269\u5c55\u64cd\u4f5c\u4e0d\u662f\u6bcf\u6b21\u90fd\u6267\u884c\u7684\uff0c\u800c\u662f\u5f53\u6570\u7ec4\u5df2\u6ee1\u65f6\u624d\u6267\u884c\uff0c\u56e0\u6b64\u53ef\u4ee5\u8ba4\u4e3a\u8fd9\u4e2a\u64cd\u4f5c\u7684\u644a\u8fd8\u65f6\u95f4\u662f\u5e38\u6570\u65f6\u95f4\uff0c\u5373O(1)\u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\uff1a\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u4f1a\u5360\u7528\u989d\u5916\u7684\u5185\u5b58\u7a7a\u95f4\uff0c\u4f46\u968f\u7740\u6570\u7ec4\u7684\u589e\u957f\uff0c\u989d\u5916\u5185\u5b58\u7684\u5360\u7528\u76f8\u5bf9\u4e8e\u6570\u7ec4\u672c\u8eab\u7684\u5927\u5c0f\u6765\u8bf4\u662f\u6709\u9650\u7684\u3002\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u8fd9\u79cd\u5360\u7528\u53ef\u4ee5\u63a5\u53d7\u3002 \u603b\u7ed3\uff0c\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u7684\u7b56\u7565\u53ef\u4ee5\u663e\u8457\u51cf\u5c11\u52a8\u6001\u6570\u7ec4\u7684\u6269\u5c55\u6b21\u6570\uff0c\u4ece\u800c\u63d0\u9ad8\u6027\u80fd\u3002\u867d\u7136\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u53ef\u80fd\u4f1a\u82b1\u8d39\u4e00\u4e9b\u65f6\u95f4\u548c\u989d\u5916\u5185\u5b58\uff0c\u4f46\u8fd9\u4e9b\u5f00\u9500\u5728\u4e00\u7cfb\u5217\u64cd\u4f5c\u4e2d\u88ab\u5e73\u644a\uff0c\u5e73\u5747\u4e0b\u6765\u662f\u5e38\u6570\u65f6\u95f4\u3002\u8fd9\u662f\u4e00\u79cd\u9ad8\u6548\u7684\u52a8\u6001\u6570\u7ec4\u5b9e\u73b0\u65b9\u5f0f\uff0c\u5e38\u89c1\u4e8e\u8bb8\u591a\u7f16\u7a0b\u8bed\u8a00\u7684\u6807\u51c6\u5e93\u4e2d\uff0c\u5305\u62ecPython\u7684\u5217\u8868\uff08list\uff09\u3002 \u5728\u589e\u52a0\u6570\u7ec4\u7684\u957f\u5ea6\u65f6\uff0c\u6bcf\u6b21\u589e\u52a0\u4e00\u4e2a\u5185\u5b58\u5355\u5143\uff0c\u4e0e\u6bcf\u6b21\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u65f6\u628a\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u76f8\u6bd4\uff0c\u540e\u8005\u7684\u65b9\u6cd5\u901a\u5e38\u66f4\u9ad8\u6548\u3002 \u6bcf\u6b21\u589e\u52a0\u4e00\u4e2a\u5185\u5b58\u5355\u5143\uff1a\u8fd9\u79cd\u65b9\u5f0f\u5728\u6bcf\u6b21\u6dfb\u52a0\u65b0\u5143\u7d20\u65f6\u90fd\u9700\u8981\u5206\u914d\u989d\u5916\u7684\u5185\u5b58\uff0c\u5bfc\u81f4\u6570\u7ec4\u5c3a\u5bf8\u7684\u589e\u957f\u662f\u7ebf\u6027\u7684\u3002\u5982\u679c\u9891\u7e41\u6dfb\u52a0\u5143\u7d20\uff0c\u8fd9\u5c06\u5bfc\u81f4\u5927\u91cf\u7684\u5185\u5b58\u5206\u914d\u548c\u6570\u636e\u590d\u5236\u64cd\u4f5c\uff0c\u56e0\u6b64\u65f6\u95f4\u590d\u6742\u5ea6\u4f1a\u53d8\u5f97\u76f8\u5bf9\u8f83\u9ad8\u3002 \u6bcf\u6b21\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u65f6\u628a\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\uff1a\u8fd9\u662f\u4e00\u79cd\u66f4\u9ad8\u6548\u7684\u7b56\u7565\u3002\u5728\u8fd9\u79cd\u65b9\u5f0f\u4e0b\uff0c\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u90fd\u4f1a\u589e\u52a0\u6570\u7ec4\u7684\u5c3a\u5bf8\uff0c\u4f46\u589e\u5e45\u662f\u6307\u6570\u7ea7\u7684\uff0c\u800c\u4e0d\u662f\u7ebf\u6027\u7684\u3002\u8fd9\u610f\u5473\u7740\u968f\u7740\u6570\u7ec4\u7684\u589e\u957f\uff0c\u6269\u5c55\u64cd\u4f5c\u7684\u9891\u7387\u4f1a\u51cf\u5c11\uff0c\u56e0\u4e3a\u6570\u7ec4\u80fd\u591f\u5bb9\u7eb3\u66f4\u591a\u5143\u7d20\u3002\u8fd9\u6837\uff0c\u867d\u7136\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u9700\u8981\u590d\u5236\u66f4\u591a\u7684\u5143\u7d20\uff0c\u4f46\u5b83\u4eec\u7684\u644a\u8fd8\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662f\u5e38\u6570\u65f6\u95f4\uff0c\u56e0\u4e3a\u5b83\u4eec\u4e0d\u662f\u6bcf\u6b21\u90fd\u6267\u884c\u7684\u3002 \u603b\u7ed3\uff0c\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u7684\u7b56\u7565\u901a\u5e38\u66f4\u9ad8\u6548\uff0c\u56e0\u4e3a\u5b83\u53ef\u4ee5\u51cf\u5c11\u9891\u7e41\u7684\u5185\u5b58\u5206\u914d\u548c\u590d\u5236\u64cd\u4f5c\uff0c\u964d\u4f4e\u4e86\u65f6\u95f4\u590d\u6742\u5ea6\u3002\u8fd9\u662f\u8bb8\u591a\u52a8\u6001\u6570\u7ec4\u5b9e\u73b0\u7684\u5e38\u89c1\u505a\u6cd5\uff0c\u5305\u62ecPython\u7684\u5217\u8868\uff08list\uff09\u3002 4.2.2.\u51cf\u5c0f\u6570\u7ec4\u7684\u5c3a\u5bf8 \u00b6 \u5982\u679c\u51cf\u5c0f\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\uff0c\u5c31\u4f1a\u6d6a\u8d39\u76f8\u5e94\u7684\u5185\u5b58\u5355\u5143\u3002\u56e0\u6b64\uff0c\u5f53\u5220\u9664\u67d0\u4e00\u4e2a\u5143\u7d20\uff0c\u5982\u679c\u672a\u4f7f\u7528\u7684\u5185\u5b58\u5355\u5143\u6570\u8fbe\u5230\u6216\u8d85\u8fc7\u4e86\u67d0\u4e2a\u9608\u503c\uff08\u5982\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\u7684\u00be\uff09\u65f6\uff0c\u5219\u5e94\u8be5\u51cf\u5c0f\u7269\u7406\u5c3a\u5bf8\u4e86\u3002\u5982\u679c\u6d6a\u8d39\u7684\u5185\u5b58\u8d85\u8fc7\u7279\u5b9a\u9608\u503c\uff0c\u90a3\u4e48Python\u7684list\u7c7b\u578b\u4f1a\u5728\u8c03\u7528 pop \u65b9\u6cd5\u65f6\u6267\u884c\u51cf\u5c0f\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\u7684\u64cd\u4f5c\u3002 \u51cf\u5c0f\u6570\u7ec4\u5c3a\u5bf8\u7684\u8fc7\u7a0b\u4e0e\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u7684\u8fc7\u7a0b\u76f8\u53cd\uff0c\u6b65\u9aa4\u5982\u4e0b\uff1a \u521b\u5efa\u4e00\u4e2a\u66f4\u5c0f\u7684\u65b0\u6570\u7ec4\u3002 \u5c06\u6570\u636e\u4ece\u65e7\u6570\u7ec4\u4e2d\u590d\u5236\u5230\u65b0\u6570\u7ec4\u3002 \u5c06\u6307\u5411\u65e7\u6570\u7ec4\u7684\u53d8\u91cf\u6307\u5411\u65b0\u6570\u7ec4\u5bf9\u8c61\u3002 \u4e0b\u9762\u7684\u4ee3\u7801\u5b9e\u73b0\u4e86\u51cf\u5c0f\u6570\u7ec4\u5c3a\u5bf8\u3002 \u5f53\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u5c0f\u4e8e\u6216\u7b49\u4e8e\u5176\u7269\u7406\u5c3a\u5bf8\u7684\u00bc\uff0c\u5e76\u4e14\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u81f3\u5c11\u662f\u8fd9\u4e2a\u6570\u7ec4\u5efa\u7acb\u65f6\u9ed8\u8ba4\u5bb9\u91cf\u76842\u500d\u65f6\uff0c\u5219\u4e0b\u9762\u7684\u7b97\u6cd5\u628a\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u51cf\u5c0f\u5230\u539f\u6765\u7684\u4e00\u534a\uff0c\u5e76\u4e14\u4e5f\u4e0d\u4f1a\u5c0f\u4e8e\u5176\u9ed8\u8ba4\u5bb9\u91cf\u3002 def main ( size = 10 ): # \u521d\u59cb\u503c DEFAULT_CAPACITY = 5 logicalSize = 0 my_array = Array ( DEFAULT_CAPACITY ) # \u6253\u5370\u8f93\u51fa\u521d\u59cb\u6570\u7ec4\u4fe1\u606f print ( \"Initial array is: \" , my_array ) print ( \"Len of the array: \" , my_array . __len__ ()) # \u7ed9\u6570\u7ec4\u8d4b\u503c for i in range ( len ( my_array )): my_array [ i ] = i print ( \"The array is: \" , my_array . items ) # \u6253\u5370\u8f93\u51fa\u6570\u7ec4 # \u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 while logicalSize < DEFAULT_CAPACITY * 2 : logicalSize += 1 if logicalSize == len ( my_array ): # \u89e6\u53d1\u6761\u4ef6 temp = Array ( len ( my_array ) + 1 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 print ( \"The array after increased is: \" , my_array . items ) # \u6253\u5370\u8f93\u51fa\u6570\u7ec4 # \u51cf\u5c0f\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 while logicalSize > len ( my_array ) // 4 : logicalSize -= 1 if logicalSize <= len ( my_array ) // 4 and len ( my_array ) >= DEFAULT_CAPACITY * 2 : # \u89e6\u53d1\u6761\u4ef6 temp = Array ( len ( my_array ) // 2 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 print ( \"The array after decreased is: \" , my_array . items ) # \u6253\u5370\u8f93\u51fa\u6570\u7ec4 if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Initial array is: [None, None, None, None, None] # Len of the array: 5 # The array is: [0, 1, 2, 3, 4] # The array after increased is: [0, 1, 2, 3, 4, None, None, None, None, None, None] # The array after decreased is: [0, 1, None, None, None] \u6309\u7167\u4e0a\u9762\u7b97\u6cd5\u51cf\u5c11\u6570\u7ec4\u7684\u5c3a\u5bf8\uff0c\u6211\u4eec\u53ef\u4ee5\u5206\u6790\u5176\u65f6\u95f4\u548c\u7a7a\u95f4\u590d\u6742\u5ea6\u5982\u4e0b\uff1a \u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u4e3b\u8981\u6d89\u53ca\u4e24\u4e2a\u64cd\u4f5c\uff1a \u521b\u5efa\u65b0\u6570\u7ec4\u5e76\u5c06\u5143\u7d20\u4ece\u65e7\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\uff1b \u5c06\u65e7\u6570\u7ec4\u5f15\u7528\u66f4\u6539\u4e3a\u65b0\u6570\u7ec4\u3002 \u590d\u5236\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\uff0c\u53ef\u4ee5\u8868\u793a\u4e3a O(n) \uff0c\u5176\u4e2d n \u662f\u6570\u7ec4\u7684\u5f53\u524d\u7269\u7406\u5c3a\u5bf8\u3002\u5f15\u7528\u66f4\u6539\u662f\u4e00\u4e2a\u5e38\u6570\u65f6\u95f4\u64cd\u4f5c\uff0c\u4e0d\u5f71\u54cd\u65f6\u95f4\u590d\u6742\u5ea6\u3002\u6240\u4ee5\uff0c\u6574\u4f53\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\uff1a\u7a7a\u95f4\u590d\u6742\u5ea6\u4e5f\u6d89\u53ca\u4e24\u4e2a\u65b9\u9762\uff1a \u521b\u5efa\u65b0\u6570\u7ec4\u7684\u5185\u5b58\u6d88\u8017\uff0c\u5176\u7a7a\u95f4\u590d\u6742\u5ea6\u662fO(N)\uff1b \u5f15\u7528\u66f4\u6539\u6240\u9700\u7684\u5e38\u6570\u989d\u5916\u7a7a\u95f4\uff0c\u901a\u5e38\u5ffd\u7565\u4e0d\u8ba1\u3002 \u6240\u4ee5\uff0c\u603b\u7684\u7a7a\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002 \u8fd9\u4e2a\u7b97\u6cd5\u7b56\u7565\u4f1a\u5728\u9002\u5f53\u7684\u65f6\u5019\u51cf\u5c0f\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\uff0c\u4ee5\u51cf\u5c11\u5185\u5b58\u5360\u7528\uff0c\u4f46\u4ecd\u7136\u4fdd\u6301\u7740\u6570\u7ec4\u7684\u52a8\u6001\u6027\u3002\u65f6\u95f4\u590d\u6742\u5ea6\u548c\u7a7a\u95f4\u590d\u6742\u5ea6\u90fd\u4e0e\u5f53\u524d\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u6210\u7ebf\u6027\u5173\u7cfb\uff0c\u56e0\u6b64\u662f\u7ebf\u6027\u7684\uff0c\u8fd9\u662f\u4e00\u79cd\u6709\u6548\u7684\u7b56\u7565\u6765\u4f18\u5316\u5185\u5b58\u4f7f\u7528\u3002\u540c\u65f6\uff0c\u4fdd\u7559\u4e86\u4e00\u5b9a\u7684\u5197\u4f59\u7a7a\u95f4\uff0c\u4ee5\u907f\u514d\u9891\u7e41\u5730\u6269\u5c55\u548c\u7f29\u5c0f\u6570\u7ec4\uff0c\u4ece\u800c\u63d0\u9ad8\u4e86\u6027\u80fd\u3002 4.2.3.\u5c06\u5143\u7d20\u63d2\u5165\u589e\u5927\u7684\u6570\u7ec4 \u00b6 4.2.4.\u4ece\u6570\u7ec4\u91cc\u5220\u9664\u5143\u7d20 \u00b6 4.2.5.\u590d\u6742\u5ea6\u7684\u6743\u8861\uff1a\u65f6\u95f4\u3001\u7a7a\u95f4\u548c\u6570\u7ec4 \u00b6 4.2.6.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u63d2\u5165\u6216\u5220\u9664\u7ed9\u5b9a\u5143\u7d20\u65f6\u5fc5\u987b\u8981\u79fb\u52a8\u6570\u7ec4\u91cc\u7684\u67d0\u4e9b\u5143\u7d20\u3002 2\uff0e\u5728\u63d2\u5165\u8fc7\u7a0b\u4e2d\uff0c\u79fb\u52a8\u6570\u7ec4\u5143\u7d20\u65f6\uff0c\u8981\u5148\u79fb\u52a8\u54ea\u4e2a\u5143\u7d20\uff1f\u5148\u79fb\u52a8\u63d2\u5165\u4f4d\u7f6e\u7684\u5143\u7d20\uff0c\u8fd8\u662f\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff1f\u4e3a\u4ec0\u4e48\uff1f 3\uff0e\u5982\u679c\u63d2\u5165\u4f4d\u7f6e\u662f\u6570\u7ec4\u7684\u903b\u8f91\u672b\u5c3e\uff0c\u8bf7\u8bf4\u660e\u8fd9\u4e2a\u63d2\u5165\u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u590d\u6742\u5ea6\u3002 4\uff0e\u5047\u8bbe\u6570\u7ec4\u5f53\u524d\u5305\u542b14\u4e2a\u5143\u7d20\uff0c\u5b83\u7684\u8d1f\u8f7d\u56e0\u5b50\u4e3a0.70\uff0c\u90a3\u4e48\u5b83\u7684\u7269\u7406\u5bb9\u91cf\u662f\u591a\u5c11\uff1f 4.3.\u4e8c\u7ef4\u6570\u7ec4\uff08\u7f51\u683c\uff09 \u00b6 4.3.1.\u4f7f\u7528\u7f51\u683c \u00b6 4.3.2.\u521b\u5efa\u5e76\u521d\u59cb\u5316\u7f51\u683c \u00b6 4.3.3.\u5b9a\u4e49Grid\u7c7b \u00b6 4.3.4.\u53c2\u5dee\u4e0d\u9f50\u7684\u7f51\u683c\u548c\u591a\u7ef4\u6570\u7ec4 \u00b6 4.3.5.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u4ec0\u4e48\u662f\u4e8c\u7ef4\u6570\u7ec4\uff08\u7f51\u683c\uff09\uff1f 2\uff0e\u8bf7\u63cf\u8ff0\u4e00\u4e2a\u53ef\u80fd\u4f1a\u7528\u5230\u4e8c\u7ef4\u6570\u7ec4\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 3\uff0e\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u4f7f\u4e4b\u53ef\u4ee5\u5728Grid\u5bf9\u8c61\u91cc\u641c\u7d22\u4e00\u4e2a\u8d1f\u6574\u6570\u3002\u5faa\u73af\u5e94\u8be5\u5728\u9047\u5230\u7f51\u683c\u91cc\u7684\u7b2c\u4e00\u4e2a\u8d1f\u6574\u6570\u7684\u5730\u65b9\u7ec8\u6b62\uff0c\u8fd9\u65f6\u53d8\u91cfrow\u548ccolumn\u5e94\u8be5\u88ab\u8bbe\u7f6e\u4e3a\u8fd9\u4e2a\u8d1f\u6570\u7684\u4f4d\u7f6e\u3002\u5982\u679c\u5728\u7f51\u683c\u91cc\u627e\u4e0d\u5230\u8d1f\u6570\uff0c\u90a3\u4e48\u53d8\u91cfrow\u548ccolumn\u5e94\u8be5\u7b49\u4e8e\u7f51\u683c\u7684\u884c\u6570\u548c\u5217\u6570\u3002 4\uff0e\u8bf4\u8bf4\u8fd0\u884c\u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u540e\u7f51\u683c\u91cc\u7684\u5185\u5bb9\u662f\u4ec0\u4e48\u3002 matrix = Grid ( 3 , 3 ) for row in range ( matrix . getHeight ()): for column in range ( matrix . getWidth ()): matrix [ row ][ column ] = row * column 5\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\u4ee5\u521b\u5efa\u4e00\u4e2a\u53c2\u5dee\u4e0d\u9f50\u7684\u7f51\u683c\uff0c\u5b83\u7684\u884c\u5206\u522b\u7528\u6765\u5b58\u50a83\u4e2a\u30016\u4e2a\u548c9\u4e2a\u5143\u7d20\u3002 6\uff0e\u63d0\u4f9b\u4e00\u4e2a\u628aGrid\u7c7b\u7528\u4f5c\u6570\u636e\u7ed3\u6784\u6765\u5b9e\u73b0\u4e09\u7ef4array\u7c7b\u7684\u7b56\u7565\u3002 7\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\uff1a\u8fd9\u6bb5\u4ee3\u7801\u4f1a\u628a\u4e09\u7ef4\u6570\u7ec4\u91cc\u6bcf\u4e2a\u5355\u5143\u7684\u503c\u90fd\u521d\u59cb\u5316\u4e3a\u5b83\u76843\u4e2a\u7d22\u5f15\u4f4d\u7f6e\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4f4d\u7f6e\u662f\uff08\u6df1\u5ea6\u3001\u884c\u3001\u5217\uff09\uff0c\u5219\u5bf9\u4e8e\u4f4d\u7f6e\uff082\u30013\u30013\uff09\u6765\u8bf4\uff0c\u5b83\u7684\u503c\u5c31\u662f233\u3002 8\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\uff1a\u8fd9\u6bb5\u4ee3\u7801\u53ef\u4ee5\u663e\u793a\u51fa\u4e09\u7ef4\u6570\u7ec4\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u6253\u5370\u51fa\u7684\u6bcf\u4e00\u884c\u6570\u636e\u90fd\u5e94\u8be5\u4ee3\u8868\u7ed9\u5b9a\u884c\u548c\u5217\u91cc\u7684\u6240\u6709\u5143\u7d20\uff0c\u800c\u6df1\u5ea6\u5c06\u4ece\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u5411\u540e\u9012\u5f52\u5230\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u3002\u904d\u5386\u5e94\u8be5\u4ece\u7b2c1\u884c\u3001\u7b2c1\u5217\u4ee5\u53ca\u7b2c\u4e00\u4e2a\u6df1\u5ea6\u4f4d\u7f6e\u5f00\u59cb\uff0c\u4f9d\u6b21\u904d\u5386\u6240\u6709\u7684\u6df1\u5ea6\u3001\u5217\u548c\u884c\u3002 4.4.\u94fe\u63a5\u7ed3\u6784 \u00b6 4.4.1.\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u548c\u53cc\u5411\u94fe\u63a5\u7ed3\u6784 \u00b6 4.4.2.\u975e\u8fde\u7eed\u5185\u5b58\u548c\u8282\u70b9 \u00b6 4.4.3.\u5b9a\u4e49\u5355\u5411\u94fe\u63a5\u8282\u70b9\u7c7b \u00b6 4.4.4.\u4f7f\u7528\u5355\u5411\u94fe\u63a5\u8282\u70b9\u7c7b \u00b6 4.4.5.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u7528\u6846\u548c\u6307\u9488\u7ed8\u5236\u6d4b\u8bd5\u7a0b\u5e8f\u91cc\u7b2c\u4e00\u4e2a\u5faa\u73af\u6240\u521b\u5efa\u7684\u8282\u70b9\u7684\u793a\u610f\u56fe\u3002 2\uff0e\u5f53\u8282\u70b9\u53d8\u91cf\u5f15\u7528\u7684\u662fNone\u65f6\uff0c\u5982\u679c\u7a0b\u5e8f\u5458\u5c1d\u8bd5\u8bbf\u95ee\u8282\u70b9\u7684\u6570\u636e\u5b57\u6bb5\uff0c\u5219\u4f1a\u53d1\u751f\u4ec0\u4e48\uff1f\u5982\u4f55\u9632\u6b62\u8fd9\u79cd\u60c5\u51b5\u7684\u53d1\u751f\uff1f 3\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\uff1a\u8fd9\u6bb5\u4ee3\u7801\u4f1a\u628a\u4e00\u4e2a\u88ab\u586b\u6ee1\u7684\u6570\u7ec4\u91cc\u7684\u5143\u7d20\u90fd\u8f6c\u79fb\u4e3a\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u6570\u636e\u3002\u8fd9\u4e2a\u64cd\u4f5c\u5e94\u4fdd\u7559\u5143\u7d20\u7684\u987a\u5e8f\u4e0d\u53d8\u3002 4.5.\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4e0a\u7684\u64cd\u4f5c \u00b6 4.5.1.\u904d\u5386 \u00b6 4.5.2.\u641c\u7d22 \u00b6 4.5.3.\u66ff\u6362 \u00b6 4.5.4.\u5728\u5f00\u59cb\u5904\u63d2\u5165 \u00b6 4.5.5.\u5728\u7ed3\u5c3e\u5904\u63d2\u5165 \u00b6 4.5.6.\u5728\u5f00\u59cb\u5904\u5220\u9664 \u00b6 4.5.7.\u5728\u7ed3\u5c3e\u5904\u5220\u9664 \u00b6 4.5.8.\u5728\u4efb\u610f\u4f4d\u7f6e\u5904\u63d2\u5165 \u00b6 4.5.9.\u5728\u4efb\u610f\u4f4d\u7f6e\u5904\u5220\u9664 \u00b6 4.5.10.\u590d\u6742\u5ea6\u7684\u6743\u8861\uff1a\u65f6\u95f4\u3001\u7a7a\u95f4\u548c\u5355\u5411\u94fe\u63a5\u7ed3\u6784 \u00b6 4.5.11.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u5047\u8bbe\u5df2\u7ecf\u627e\u5230\u4e86\u4ece\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u5220\u9664\u5143\u7d20\u7684\u4f4d\u7f6e\uff0c\u8bf7\u8bf4\u660e\u4ece\u8fd9\u4e2a\u65f6\u5019\u5f00\u59cb\u5b8c\u6210\u5220\u9664\u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u590d\u6742\u5ea6\u3002 2\uff0e\u53ef\u4ee5\u5bf9\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u6309\u987a\u5e8f\u6392\u5217\u7684\u5143\u7d20\u6267\u884c\u4e8c\u5206\u641c\u7d22\u5417\uff1f\u5982\u679c\u4e0d\u53ef\u4ee5\uff0c\u4e3a\u4ec0\u4e48\uff1f 3\uff0e\u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48Python\u5217\u8868\u4f1a\u4f7f\u7528\u6570\u7ec4\u800c\u4e0d\u662f\u94fe\u63a5\u7ed3\u6784\u6765\u4fdd\u5b58\u5b83\u7684\u5143\u7d20\u3002 4.6.\u94fe\u63a5\u4e0a\u7684\u53d8\u5316 \u00b6 4.6.1.\u5305\u542b\u865a\u62df\u5934\u8282\u70b9\u7684\u73af\u72b6\u94fe\u63a5\u7ed3\u6784 \u00b6 4.6.2.\u53cc\u5411\u94fe\u63a5\u7ed3\u6784 \u00b6 4.6.3.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u5305\u542b\u865a\u62df\u5934\u8282\u70b9\u7684\u73af\u72b6\u94fe\u63a5\u7ed3\u6784\u7ed9\u7a0b\u5e8f\u5458\u5e26\u6765\u4e86\u4ec0\u4e48\u597d\u5904\uff1f 2\uff0e\u548c\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u76f8\u6bd4\uff0c\u8bf7\u63cf\u8ff0\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u4e00\u4e2a\u597d\u5904\u548c\u4e00\u4e2a\u989d\u5916\u5f00\u9500\u3002 4.7.\u5c0f\u7ed3 \u00b6 \u6570\u636e\u7ed3\u6784\u662f\u4e00\u4e2a\u8868\u793a\u591a\u9879\u96c6\u91cc\u6240\u5305\u542b\u6570\u636e\u7684\u5bf9\u8c61\u3002 \u6570\u7ec4\u662f\u4e00\u79cd\u5728\u5e38\u6570\u65f6\u95f4\u5185\u652f\u6301\u5bf9\u4f4d\u7f6e\u9010\u9879\u968f\u673a\u8bbf\u95ee\u7684\u6570\u636e\u7ed3\u6784\u3002\u5728\u521b\u5efa\u6570\u7ec4\u65f6\uff0c\u4f1a\u4e3a\u5b83\u5206\u914d\u82e5\u5e72\u4e2a\u7528\u6765\u5b58\u653e\u6570\u636e\u7684\u5185\u5b58\u7a7a\u95f4\uff0c\u5e76\u4e14\u6570\u7ec4\u7684\u957f\u5ea6\u4f1a\u4fdd\u6301\u4e0d\u53d8\u3002\u63d2\u5165\u548c\u5220\u9664\u64cd\u4f5c\u9700\u8981\u79fb\u52a8\u6570\u636e\u5143\u7d20\uff0c\u5e76\u4e14\u53ef\u80fd\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u3001\u66f4\u5927\u6216\u66f4\u5c0f\u7684\u6570\u7ec4\u3002 \u4e8c\u7ef4\u6570\u7ec4\u91cc\u7684\u6bcf\u4e2a\u6570\u636e\u503c\u90fd\u4f4d\u4e8e\u77e9\u5f62\u7f51\u683c\u7684\u884c\u548c\u5217\u4e0a\u3002 \u94fe\u63a5\u7ed3\u6784\u662f\u75310\u4e2a\u6216\u591a\u4e2a\u8282\u70b9\u7ec4\u6210\u7684\u6570\u636e\u7ed3\u6784\u3002\u6bcf\u4e2a\u8282\u70b9\u90fd\u5305\u542b\u4e00\u4e2a\u6570\u636e\u5143\u7d20\u548c\u4e00\u4e2a\u6216\u591a\u4e2a\u6307\u5411\u5176\u4ed6\u8282\u70b9\u7684\u94fe\u63a5\u3002 \u5355\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u8282\u70b9\u5305\u542b\u6570\u636e\u5143\u7d20\u548c\u5230\u4e0b\u4e00\u4e2a\u8282\u70b9\u7684\u94fe\u63a5\u3002\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u8282\u70b9\u8fd8\u5305\u542b\u5230\u524d\u4e00\u4e2a\u8282\u70b9\u7684\u94fe\u63a5\u3002 \u5728\u94fe\u63a5\u7ed3\u6784\u91cc\u8fdb\u884c\u63d2\u5165\u6216\u5220\u9664\u64cd\u4f5c\u4e0d\u9700\u8981\u79fb\u52a8\u6570\u636e\u5143\u7d20\uff0c\u6bcf\u6b21\u6700\u591a\u53ea\u4f1a\u521b\u5efa\u4e00\u4e2a\u8282\u70b9\u3002\u4f46\u662f\uff0c\u5728\u94fe\u63a5\u7ed3\u6784\u91cc\u6267\u884c\u63d2\u5165\u3001\u5220\u9664\u548c\u8bbf\u95ee\u64cd\u4f5c\u9700\u8981\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662f\u7ebf\u6027\u7684\u3002 \u5728\u94fe\u63a5\u7ed3\u6784\u91cc\u4f7f\u7528\u5934\u8282\u70b9\u53ef\u4ee5\u7b80\u5316\u67d0\u4e9b\u64cd\u4f5c\uff0c\u5982\u6dfb\u52a0\u6216\u5220\u9664\u5143\u7d20\u3002 4.8.\u590d\u4e60\u9898 \u00b6 1\uff0e\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784\u90fd\u662f\uff1a \u62bd\u8c61\u6570\u636e\u7c7b\u578b\uff08ADT\uff09 \u6570\u636e\u7ed3\u6784 2\uff0e\u6570\u7ec4\u7684\u957f\u5ea6\uff1a \u5728\u521b\u5efa\u4e4b\u540e\u5927\u5c0f\u662f\u56fa\u5b9a\u7684 \u5728\u521b\u5efa\u4e4b\u540e\u5927\u5c0f\u53ef\u4ee5\u589e\u52a0\u6216\u51cf\u5c11 3\uff0e\u5728\u6570\u7ec4\u91cc\u8fdb\u884c\u968f\u673a\u8bbf\u95ee\u652f\u6301\u5728\uff1a \u5e38\u6570\u65f6\u95f4\u91cc\u8bbf\u95ee\u6570\u636e \u7ebf\u6027\u65f6\u95f4\u91cc\u8bbf\u95ee\u6570\u636e 4\uff0e\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u6570\u636e\u5305\u542b\u5728\uff1a \u5355\u5143\u91cc \u8282\u70b9\u91cc 5\uff0e\u5bf9\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u6267\u884c\u7684\u5927\u591a\u6570\u64cd\u4f5c\u90fd\u9700\u8981\uff1a \u5e38\u6570\u65f6\u95f4 \u7ebf\u6027\u65f6\u95f4 6\uff0e\u4ece\u4ee5\u4e0b\u54ea\u79cd\u7c7b\u578b\u91cc\u5220\u9664\u7b2c\u4e00\u4e2a\u5143\u7d20\u9700\u8981\u5e38\u6570\u65f6\u95f4\uff1a \u6570\u7ec4 \u5355\u5411\u94fe\u63a5\u7ed3\u6784 7\uff0e\u5728\u4e0b\u9762\u54ea\u79cd\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u91cc\u4f7f\u7528\u7684\u5185\u5b58\u4f1a\u5c11\u4e8e\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u7684\uff1a \u4e0d\u5230\u4e00\u534a\u7684\u4f4d\u7f6e\u653e\u7f6e\u4e86\u6570\u636e \u4e00\u534a\u4ee5\u4e0a\u7684\u4f4d\u7f6e\u653e\u7f6e\u4e86\u6570\u636e 8\uff0e\u5f53\u6570\u7ec4\u7684\u5185\u5b58\u4e0d\u8db3\u4ee5\u4fdd\u5b58\u6570\u636e\u65f6\uff0c\u6700\u597d\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u6570\u7ec4\uff0c\u8fd9\u4e2a\u65b0\u6570\u7ec4\u5e94\u8be5\uff1a \u5927\u5c0f\u6bd4\u65e7\u6570\u7ec4\u591a1\u4e2a\u4f4d\u7f6e \u5927\u5c0f\u662f\u65e7\u6570\u7ec4\u76842\u500d 9\uff0e\u5bf9\u4e8e\u5355\u5411\u94fe\u63a5\u7ed3\u6784\uff0c\u5f53\u4f60\u5728\u4ec0\u4e48\u5730\u65b9\u6267\u884c\u63d2\u5165\u64cd\u4f5c\u4f1a\u5f97\u5230\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u8fd0\u884c\u65f6\uff1a \u5728\u7ed3\u6784\u7684\u5f00\u5934 \u5728\u7ed3\u6784\u7684\u672b\u5c3e 10\uff0e\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u8ba9\u7a0b\u5e8f\u5458\u53ef\u4ee5\u79fb\u52a8\u5230\uff1a \u7ed9\u5b9a\u8282\u70b9\u7684\u540e\u4e00\u4e2a\u8282\u70b9\u6216\u524d\u4e00\u4e2a\u8282\u70b9 \u7ed9\u5b9a\u8282\u70b9\u7684\u540e\u4e00\u4e2a\u8282\u70b9 4.9.\u7f16\u7a0b\u7ec3\u4e60 \u00b6 \u5728\u524d6\u4e2a\u9879\u76ee\u91cc\uff0c\u4f60\u5c06\u4fee\u6539\u5728\u672c\u7ae0\u5b9a\u4e49\u7684Array\u7c7b\uff0c\u4ece\u800c\u8ba9\u5b83\u66f4\u50cfPython\u7684list\u7c7b\u3002\u5bf9\u4e8e\u8fd9\u4e9b\u9879\u76ee\u7684\u7b54\u6848\uff0c\u8bf7\u5305\u542b\u4f60\u5bf9Array\u7c7b\u6240\u505a\u4fee\u6539\u7684\u4ee3\u7801\u6d4b\u8bd5\u3002 1\uff0e\u4e3aArray\u7c7b\u6dfb\u52a0\u4e00\u4e2a\u5b9e\u4f8b\u53d8\u91cf logicalSize \u3002\u8fd9\u4e2a\u53d8\u91cf\u7684\u521d\u59cb\u503c\u4e3a 0 \uff0c\u7528\u6765\u8bb0\u5f55\u6570\u7ec4\u91cc\u5f53\u524d\u5df2\u7ecf\u5305\u542b\u7684\u5143\u7d20\u6570\u91cf\u3002\u7136\u540e\u4e3aArray\u7c7b\u6dfb\u52a0 size() \u65b9\u6cd5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u7528\u6765\u8fd4\u56de\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u3002 __len__ \u65b9\u6cd5\u4f9d\u7136\u4f1a\u8fd4\u56de\u6570\u7ec4\u7684\u5bb9\u91cf\uff0c\u4e5f\u5c31\u662f\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u3002 2\uff0e\u4e3aArray\u7c7b\u7684 __getitem__ \u548c_ _setitem__ \u65b9\u6cd5\u6dfb\u52a0\u5148\u9a8c\u6761\u4ef6\u3002\u5b83\u4eec\u7684\u5148\u9a8c\u6761\u4ef6\u662f 0<=index < size() \u3002\u5982\u679c\u4e0d\u6ee1\u8db3\u5148\u9a8c\u6761\u4ef6\uff0c\u5c31\u5f15\u53d1\u5f02\u5e38\u3002 3\uff0e\u5c06 grow \u548c shrink \u65b9\u6cd5\u6dfb\u52a0\u5230Array\u7c7b\u3002\u5b83\u4eec\u80fd\u591f\u57fa\u4e8e\u672c\u7ae0\u6240\u8ba8\u8bba\u7684\u7b56\u7565\u6765\u589e\u52a0\u6216\u51cf\u5c11\u6570\u7ec4\u91cc\u6240\u5305\u542b\u7684\u5217\u8868\u957f\u5ea6\u3002\u5728\u5b9e\u73b0\u65f6\uff0c\u8981\u4fdd\u8bc1\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u4e0d\u4f1a\u7f29\u5c0f\u5230\u7528\u6237\u6307\u5b9a\u7684\u5bb9\u91cf\u4e4b\u4e0b\uff0c\u5e76\u4e14\u5728\u589e\u52a0\u6570\u7ec4\u5c3a\u5bf8\u65f6\uff0c\u6570\u7ec4\u7684\u5185\u5b58\u5355\u5143\u5c06\u4f1a\u7528\u9ed8\u8ba4\u503c\u6765\u586b\u5145\u3002 4\uff0e\u5c06\u65b9\u6cd5 insert \u548c pop \u6dfb\u52a0\u5230Array\u7c7b\u4e2d\u3002\u5b83\u4eec\u57fa\u4e8e\u672c\u7ae0\u5df2\u7ecf\u8ba8\u8bba\u8fc7\u7684\u7b56\u7565\uff0c\u5728\u9700\u8981\u7684\u65f6\u5019\u5bf9\u6570\u7ec4\u7684\u957f\u5ea6\u8fdb\u884c\u8c03\u6574\u3002 insert \u65b9\u6cd5\u4f1a\u63a5\u6536\u4e00\u4e2a\u4f4d\u7f6e\u548c\u4e00\u4e2a\u5143\u7d20\u503c\u4f5c\u4e3a\u53c2\u6570\uff0c\u7136\u540e\u628a\u8fd9\u4e2a\u5143\u7d20\u63d2\u5165\u6307\u5b9a\u7684\u4f4d\u7f6e\u3002\u5982\u679c\u4f4d\u7f6e\u5927\u4e8e\u6216\u7b49\u4e8e\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u628a\u5143\u7d20\u63d2\u5165\u6570\u7ec4\u91cc\u5f53\u524d\u53ef\u83b7\u5f97\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u4e4b\u540e\u3002 pop \u65b9\u6cd5\u4f1a\u63a5\u6536\u4e00\u4e2a\u4f4d\u7f6e\u4f5c\u4e3a\u53c2\u6570\uff0c\u7136\u540e\u5220\u9664\u5e76\u8fd4\u56de\u8fd9\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u3002 pop \u65b9\u6cd5\u7684\u5148\u9a8c\u6761\u4ef6\u662f 0<=index < size() \u3002 pop \u65b9\u6cd5\u8fd8\u5e94\u8be5\u628a\u817e\u51fa\u6765\u7684\u6570\u7ec4\u5185\u5b58\u5355\u5143\u91cd\u7f6e\u4e3a\u586b\u5145\u503c\u3002 5\uff0e\u5c06\u65b9\u6cd5 __eq__ \u6dfb\u52a0\u5230Array\u7c7b\u4e2d\u3002\u5f53Array\u5bf9\u8c61\u4f5c\u4e3a == \u8fd0\u7b97\u7b26\u7684\u5de6\u64cd\u4f5c\u6570\u65f6\uff0cPython\u4f1a\u8fd0\u884c\u8fd9\u4e2a\u65b9\u6cd5\u3002\u5982\u679c\u8fd9\u4e2a\u65b9\u6cd5\u7684\u53c2\u6570\u4e5f\u662f\u4e00\u4e2aArray\u5bf9\u8c61\uff0c\u5e76\u4e14\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\u548c\u5de6\u64cd\u4f5c\u6570\u76f8\u540c\uff0c\u4e14\u5728\u4e24\u4e2a\u6570\u7ec4\u91cc\u6bcf\u4e2a\u903b\u8f91\u4f4d\u7f6e\u4e0a\u7684\u5143\u7d20\u90fd\u76f8\u7b49\uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u8fd4\u56de True \uff1b\u5426\u5219\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u8fd4\u56de False \u3002 6\uff0e\u4e3a\u4e86\u8ba9Array\u7c7b\u548c\u5217\u8868\u4e00\u6837\uff0c\u5e94\u8be5\u5220\u9664 __iter__ \u65b9\u6cd5\u7684\u5f53\u524d\u5b9e\u73b0\u3002\u8bf7\u89e3\u91ca\u8fd9\u4e3a\u4ec0\u4e48\u662f\u4e00\u4e2a\u597d\u5efa\u8bae\uff0c\u5e76\u8bf4\u660e\u5728\u8fd9\u4e2a\u60c5\u51b5\u4e0b\u5e94\u8be5\u5982\u4f55\u5bf9 __str__ \u65b9\u6cd5\u8fdb\u884c\u4fee\u6539\u3002 7\uff0e Matrix \u7c7b\u53ef\u4ee5\u6267\u884c\u7ebf\u6027\u4ee3\u6570\u91cc\u7684\u67d0\u4e9b\u8fd0\u7b97\uff0c\u6bd4\u5982\u77e9\u9635\u8fd0\u7b97\u3002\u5f00\u53d1\u4e00\u4e2a\u4f7f\u7528\u5185\u7f6e\u8fd0\u7b97\u7b26\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97\u7684 Matrix \u7c7b\uff0c\u8fd9\u4e2a Matrix \u7c7b\u5e94\u6269\u5c55\u81ea Grid \u7c7b\u3002\u5728\u63a5\u4e0b\u6765\u76844\u4e2a\u9879\u76ee\u91cc\uff0c\u4f60\u5e94\u5b9a\u4e49\u4e00\u4e9b\u7528\u6765\u64cd\u4f5c\u94fe\u63a5\u7ed3\u6784\u7684\u51fd\u6570\u3002\u5728\u89e3\u7b54\u7684\u8fc7\u7a0b\u4e2d\uff0c\u4f60\u5e94\u8be5\u7ee7\u7eed\u4f7f\u7528\u672c\u7ae0\u5b9a\u4e49\u7684 Node \u548c TwoWayNode \u7c7b\u3002\u521b\u5efa\u4e00\u4e2a\u6d4b\u8bd5\u6a21\u5757\u4ee5\u5305\u542b\u4f60\u7684\u51fd\u6570\u5b9a\u4e49\u548c\u7528\u6765\u6d4b\u8bd5\u5b83\u4eec\u7684\u4ee3\u7801\u3002 8\uff0e\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c length \u7684\u51fd\u6570\uff08\u4e0d\u662f len \uff09\uff0c\u8fd9\u4e2a\u51fd\u6570\u4f1a\u63a5\u53d7\u4e00\u4e2a\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u80fd\u591f\u8fd4\u56de\u7ed3\u6784\u91cc\u7684\u5143\u7d20\u6570\u91cf\u3002 9\uff0e\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c insert \u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u5177\u6709\u628a\u5143\u7d20\u63d2\u5165\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4e2d\u6307\u5b9a\u4f4d\u7f6e\u7684\u529f\u80fd\u3002\u8fd9\u4e2a\u51fd\u6570\u67093\u4e2a\u53c2\u6570\uff1a\u5143\u7d20\u3001\u4f4d\u7f6e\u4ee5\u53ca\u4e00\u4e2a\u94fe\u63a5\u7ed3\u6784\uff08\u8fd9\u4e2a\u94fe\u63a5\u7ed3\u6784\u53ef\u80fd\u4e3a\u7a7a\uff09\u3002\u8fd9\u4e2a\u51fd\u6570\u80fd\u591f\u8fd4\u56de\u4fee\u6539\u4e4b\u540e\u7684\u94fe\u63a5\u7ed3\u6784\u3002\u5982\u679c\u4f20\u9012\u7684\u4f4d\u7f6e\u5927\u4e8e\u6216\u7b49\u4e8e\u94fe\u63a5\u7ed3\u6784\u7684\u957f\u5ea6\uff0c\u90a3\u4e48\u8fd9\u4e2a\u51fd\u6570\u4f1a\u628a\u5143\u7d20\u63d2\u5165\u5b83\u7684\u672b\u5c3e\u3002\u8fd9\u4e2a\u51fd\u6570\u7684\u8c03\u7528\u793a\u4f8b\u662f head =insert(1,data,head) \uff0c\u5176\u4e2d head \u662f\u4e00\u4e2a\u53d8\u91cf\uff0c\u8fd9\u4e2a\u53d8\u91cf\u8981\u4e48\u4e3a\u7a7a\u94fe\u63a5\uff0c\u8981\u4e48\u6307\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u7b2c\u4e00\u4e2a\u8282\u70b9\u3002 10\uff0e\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c pop \u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u80fd\u591f\u5728\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u6307\u5b9a\u4f4d\u7f6e\u4e0a\u5220\u9664\u5143\u7d20\u3002\u8fd9\u4e2a\u51fd\u6570\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u4f4d\u7f6e\uff0c\u5b83\u7684\u5148\u9a8c\u6761\u4ef6\u662f 0<=position<\u7ed3\u6784\u7684\u957f\u5ea6 \u3002\u5b83\u7684\u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u4e00\u4e2a\u94fe\u63a5\u7ed3\u6784\uff0c\u5f88\u660e\u663e\u5b83\u4e0d\u5e94\u8be5\u4e3a\u7a7a\u3002\u8fd9\u4e2a\u51fd\u6570\u5c06\u4f1a\u8fd4\u56de\u4e00\u4e2a\u5143\u7ec4\uff0c\u5305\u542b\u4fee\u6539\u540e\u7684\u94fe\u63a5\u7ed3\u6784\u548c\u5220\u9664\u7684\u5143\u7d20\u3002\u5b83\u7684\u8c03\u7528\u793a\u4f8b\u662f (head, item) = pop(1,head) \u3002 11\uff0e\u5b9a\u4e49\u4e00\u4e2a\u51fd\u6570 makeTwoWay \uff0c\u8fd9\u4e2a\u51fd\u6570\u4f1a\u63a5\u53d7\u4e00\u4e2a\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4f5c\u4e3a\u53c2\u6570\uff0c\u7136\u540e\u751f\u6210\u5e76\u8fd4\u56de\u4e00\u4e2a\u5305\u542b\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u5143\u7d20\u7684\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u3002\uff08\u6ce8\u610f\uff1a\u8fd9\u4e2a\u51fd\u6570\u4e0d\u5e94\u8be5\u5bf9\u4f5c\u4e3a\u53c2\u6570\u7684\u94fe\u63a5\u7ed3\u6784\u8fdb\u884c\u4efb\u4f55\u4fee\u6539\u3002\uff09","title":"\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#4","text":"\u6570\u636e\u7ed3\u6784\uff08data structure\uff09\u6216\u5177\u4f53\u6570\u636e\u7c7b\u578b\uff08concrete data type\uff09\u662f\u6307\u4e00\u7ec4\u6570\u636e\u7684\u5185\u90e8\u5b58\u50a8\u65b9\u5f0f\u3002 \u6570\u7ec4\uff08array\uff09\u548c\u94fe\u63a5\u7ed3\u6784\uff08linked structure\uff09\u8fd9\u4e24\u79cd\u6570\u636e\u7ed3\u6784\u662f\u7f16\u7a0b\u8bed\u8a00\u91cc\u591a\u9879\u96c6\u6700\u5e38\u7528\u7684\u5b9e\u73b0\u3002 \u76ee\u6807\uff1a \u521b\u5efa\u6570\u7ec4\uff1b \u5bf9\u6570\u7ec4\u6267\u884c\u5404\u79cd\u64cd\u4f5c\uff1b \u786e\u5b9a\u6570\u7ec4\u76f8\u5173\u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u7684\u4f7f\u7528\u60c5\u51b5\uff1b \u57fa\u4e8e\u6570\u7ec4\u5728\u8ba1\u7b97\u673a\u5185\u5b58\u91cc\u7684\u4e0d\u540c\u5b58\u50a8\u65b9\u5f0f\uff0c\u63cf\u8ff0\u6570\u7ec4\u76f8\u5173\u64cd\u4f5c\u7684\u6210\u672c\u548c\u6536\u76ca\uff1b \u4f7f\u7528\u5355\u5411\u94fe\u63a5\u8282\u70b9\u521b\u5efa\u94fe\u63a5\u7ed3\u6784\uff1b \u5bf9\u7531\u5355\u5411\u94fe\u63a5\u8282\u70b9\u6784\u6210\u7684\u94fe\u63a5\u7ed3\u6784\u6267\u884c\u5404\u79cd\u64cd\u4f5c\uff1b \u57fa\u4e8e\u94fe\u63a5\u7ed3\u6784\u5728\u8ba1\u7b97\u673a\u5185\u5b58\u91cc\u7684\u4e0d\u540c\u5b58\u50a8\u65b9\u5f0f\uff0c\u63cf\u8ff0\u5728\u94fe\u63a5\u7ed3\u6784\u4e0a\u6267\u884c\u76f8\u5173\u64cd\u4f5c\u7684\u6210\u672c\u548c\u6536\u76ca\uff1b \u6bd4\u8f83\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784\u5728\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u4f7f\u7528\u4e0a\u7684\u6743\u8861\uff1b","title":"4.\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#41","text":"\u5173\u4e8e\u6570\u7ec4\uff08array\uff09\uff1a \u6570\u7ec4\u662f\u6307\u5728\u7ed9\u5b9a\u7d22\u5f15\u4f4d\u7f6e\u53ef\u4ee5\u8bbf\u95ee\u548c\u66ff\u6362\u7684\u5143\u7d20\u5e8f\u5217\u3002 Python\u5217\u8868\u7684\u5e95\u5c42\u6570\u636e\u7ed3\u6784\u6b63\u662f\u4e00\u4e2a\u6570\u7ec4\u3002 Python\u4e2d\u6570\u7ec4\u7684\u9650\u5236\u8981\u6bd4\u5217\u8868\u66f4\u591a\u3002\u53ea\u80fd\u5728\u6307\u5b9a\u4f4d\u7f6e\u8bbf\u95ee\u548c\u66ff\u6362\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u3001\u68c0\u67e5\u6570\u7ec4\u7684\u957f\u5ea6\u3001\u83b7\u53d6\u5b83\u7684\u5b57\u7b26\u4e32\u8868\u8fbe\u5f0f\uff1b\u4e0d\u80fd\u57fa\u4e8e\u4f4d\u7f6e\u6dfb\u52a0\u6216\u5220\u9664\u5143\u7d20\uff1b\u6570\u7ec4\u7684\u957f\u5ea6\u4e5f\u5c31\u662f\u5b83\u7684\u5bb9\u91cf\uff0c\u5728\u521b\u5efa\u4e4b\u540e\u5c31\u662f\u56fa\u5b9a\u7684\u3002 Python\u7684 array \u6a21\u5757\u5305\u542b\u4e00\u4e2a\u53eb\u4f5c array \u7684\u7c7b\uff0c\u5b83\u975e\u5e38\u7c7b\u4f3c\u4e8e\u5217\u8868\uff0c\u4f46\u662f\u53ea\u80fd\u5b58\u50a8\u6570\u5b57\u3002\u6211\u4eec\u4f1a\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c Array \u7684\u65b0\u7c7b\uff0c\u4f7f\u7528\u5217\u8868\u4fdd\u5b58\u5143\u7d20\uff0c\u5b58\u50a8\u4efb\u4f55\u7c7b\u578b\u7684\u5143\u7d20\u3002 \u4e0b\u9762\u7684\u793a\u4f8b\u5b9a\u4e49\u4e86\u4e00\u4e2a\u6570\u7ec4\u4ee5\u53ca\u5bf9\u5e94\u7528\u6cd5\u3002 class Array ( object ): \"\"\" \u63cf\u8ff0\u4e00\u4e2a\u6570\u7ec4\u3002 \u6570\u7ec4\u7c7b\u4f3c\u5217\u8868\uff0c\u4f46\u6570\u7ec4\u53ea\u80fd\u4f7f\u7528[], len, iter, \u548c str\u8fd9\u4e9b\u5c5e\u6027\u3002 \u5b9e\u4f8b\u5316\u4e00\u4e2a\u6570\u7ec4\uff0c\u4f7f\u7528 = Array(, ) \u5176\u4e2dfill value\u9ed8\u8ba4\u503c\u662fNone\u3002 \"\"\" def __init__ ( self , capacity , fillValue = None ): \"\"\"Capacity\u662f\u6570\u7ec4\u7684\u5927\u5c0f. fillValue\u4f1a\u586b\u5145\u5728\u6bcf\u4e2a\u5143\u7d20\u4f4d\u7f6e, \u9ed8\u8ba4\u503c\u662fNone\"\"\" self . items = list () for count in range ( capacity ): self . items . append ( fillValue ) def __len__ ( self ): \"\"\"-> \u6570\u7ec4\u7684\u5927\u5c0f\"\"\" return len ( self . items ) def __str__ ( self ): \"\"\"-> \u5c06\u6570\u7ec4\u5b57\u7b26\u4e32\u5316\"\"\" return str ( self . items ) def __iter__ ( self ): \"\"\"\u652f\u6301for\u5faa\u73af\u5bf9\u6570\u7ec4\u8fdb\u884c\u904d\u5386.\"\"\" return iter ( self . items ) def __getitem__ ( self , index ): \"\"\"\u7528\u4e8e\u8bbf\u95ee\u7d22\u5f15\u5904\u7684\u4e0b\u6807\u8fd0\u7b97\u7b26.\"\"\" return self . items [ index ] def __setitem__ ( self , index , newItem ): \"\"\"\u4e0b\u6807\u8fd0\u7b97\u7b26\u7528\u4e8e\u5728\u7d22\u5f15\u5904\u8fdb\u884c\u66ff\u6362.\"\"\" self . items [ index ] = newItem def main ( size = 10 ): my_array = Array ( 5 ) print ( \"The array is: \" , my_array ) print ( \"__len__() of the array: \" , my_array . __len__ ()) print ( \"len() of the arry: \" , len ( my_array )) for i in range ( len ( my_array )): my_array [ i ] = i for i in my_array : print ( my_array [ i ], end = \" \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # The array is [None, None, None, None, None] # __len__() of the array: 5 # len() of the arry: 5 # 0 1 2 3 4","title":"4.1.\u6570\u7ec4\u6570\u636e\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#411","text":"\u901a\u8fc7\u4e0b\u6807\u64cd\u4f5c\u6216\u7d22\u5f15\u64cd\u4f5c\u5b9e\u73b0\u5bf9\u6570\u7ec4\u5728\u6307\u5b9a\u4f4d\u7f6e\u5bf9\u5143\u7d20\u8fdb\u884c\u5b58\u50a8\u6216\u68c0\u7d22\u3002 \u6570\u7ec4\u7d22\u5f15\u662f\u968f\u673a\u8bbf\u95ee\uff08random access\uff09\u64cd\u4f5c\uff0c\u800c\u5728\u968f\u673a\u8bbf\u95ee\u65f6\uff0c\u8ba1\u7b97\u673a\u603b\u4f1a\u6267\u884c\u56fa\u5b9a\u7684\u6b65\u9aa4\u6765\u83b7\u53d6\u7b2c i \u4e2a\u5143\u7d20\u7684\u4f4d\u7f6e\u3002\u56e0\u6b64\uff0c\u4e0d\u8bba\u6570\u7ec4\u6709\u591a\u5927\uff0c\u8bbf\u95ee\u7b2c\u4e00\u4e2a\u5143\u7d20\u6240\u9700\u7684\u65f6\u95f4\u548c\u8bbf\u95ee\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u6240\u9700\u8981\u7684\u65f6\u95f4\u90fd\u662f\u76f8\u540c\u7684\u3002 \u8ba1\u7b97\u673a\u901a\u8fc7\u5206\u914d\u4e00\u5757\u8fde\u7eed\u5185\u5b58\uff08contiguous memory\uff09\u5355\u5143\u6765\u5b58\u50a8\u6570\u7ec4\u91cc\u7684\u5143\u7d20\uff0c\u4ece\u800c\u652f\u6301\u5bf9\u6570\u7ec4\u7684\u968f\u673a\u8bbf\u95ee\u3002 \u7531\u4e8e\u6570\u7ec4\u91cc\u7684\u5143\u7d20\u5730\u5740\u90fd\u662f\u6309\u7167\u6570\u5b57\u987a\u5e8f\u8fdb\u884c\u6392\u5217\u7684\uff0c\u56e0\u6b64\u53ef\u4ee5\u901a\u8fc7\u6dfb\u52a0\u4e24\u4e2a\u503c\u6765\u8ba1\u7b97\u51fa\u6570\u7ec4\u5143\u7d20\u7684\u673a\u5668\u5730\u5740\uff0c\u5b83\u4eec\u662f\u6570\u7ec4\u7684\u57fa\u5730\u5740\uff08base address\uff09\u4ee5\u53ca\u5143\u7d20\u7684\u504f\u79fb\u91cf\uff08offset\uff09\u3002\u5176\u4e2d\uff0c\u6570\u7ec4\u7684\u57fa\u5730\u5740\u5c31\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20\u7684\u673a\u5668\u5730\u5740\uff0c\u800c\u5143\u7d20\u7684\u504f\u79fb\u91cf\u5c31\u662f\u5b83\u7684\u7d22\u5f15\u503c\u518d\u4e58\u4ee5\u4e00\u4e2a\u4ee3\u8868\u6570\u7ec4\u5143\u7d20\u6240\u9700\u5185\u5b58\u5355\u5143\u6570\u7684\u5e38\u91cf\uff08\u5728Python\u91cc\uff0c\u8fd9\u4e2a\u503c\u59cb\u7ec8\u662f1\uff09\u3002 \u7b80\u800c\u8a00\u4e4b\uff0cPython\u6570\u7ec4\u91cc\u7684\u7d22\u5f15\u64cd\u4f5c\u5305\u62ec\u4e0b\u9762\u4e24\u4e2a\u6b65\u9aa4\uff1a \u5f97\u5230\u6570\u7ec4\u5185\u5b58\u5757\u7684\u57fa\u5730\u5740\u3002 \u5c06\u7d22\u5f15\u503c\u6dfb\u52a0\u5230\u8fd9\u4e2a\u5730\u5740\u5e76\u8fd4\u56de\u3002","title":"4.1.1.\u968f\u673a\u8bbf\u95ee\u548c\u8fde\u7eed\u5185\u5b58"},{"location":"python/DataStructure/04_ArrayChain/#412","text":"\u5728\u6bd4\u8f83\u8001\u7684\u7f16\u7a0b\u8bed\u8a00\uff08\u5982FORTRAN\u6216Pascal\uff09\u91cc\uff0c\u6570\u7ec4\u662f\u9759\u6001\u6570\u636e\u7ed3\u6784\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u7684\u957f\u5ea6\u6216\u5bb9\u91cf\u5728\u7f16\u8bd1\u65f6\u5c31\u786e\u5b9a\u4e86\uff0c\u7a0b\u5e8f\u5458\u9700\u8981\u7533\u8bf7\u8db3\u591f\u591a\u7684\u5185\u5b58\u6765\u6ee1\u8db3\u5728\u6570\u7ec4\u91cc\u5b58\u50a8\u53ef\u80fd\u6709\u6700\u5927\u6570\u91cf\u5143\u7d20\u7684\u60c5\u51b5\uff0c\u8fd9\u6837\u505a\u4f1a\u6d6a\u8d39\u5927\u91cf\u7684\u5185\u5b58\u3002 \u50cfJava\u548cC++\u8fd9\u7c7b\u7684\u73b0\u4ee3\u7f16\u7a0b\u8bed\u8a00\u4f1a\u5141\u8bb8\u7a0b\u5e8f\u5458\u521b\u5efa\u52a8\u6001\u6570\u7ec4\uff08dynamic array\uff09\uff0c\u4ece\u800c\u4e3a\u8fd9\u4e2a\u95ee\u9898\u63d0\u4f9b\u4e86\u4e00\u79cd\u8865\u6551\u65b9\u6cd5\u3002\u548c\u9759\u6001\u6570\u7ec4\u76f8\u4f3c\u7684\u662f\uff0c\u52a8\u6001\u6570\u7ec4\u4e5f\u4f1a\u5360\u7528\u4e00\u5757\u8fde\u7eed\u5185\u5b58\uff0c\u5e76\u652f\u6301\u968f\u673a\u8bbf\u95ee\u3002\u52a8\u6001\u6570\u7ec4\u7684\u957f\u5ea6\u53ea\u5728\u8fd0\u884c\u65f6\u624d\u77e5\u9053\uff0c\u5728\u52a8\u6001\u6570\u7ec4\u5b9e\u4f8b\u5316\u7684\u65f6\u5019\u6307\u5b9a\u5b83\u7684\u957f\u5ea6\u3002\u5728Python\u91cc\u5b9e\u73b0\u7684Array\u7c7b\u7684\u884c\u4e3a\u4e5f\u662f\u8fd9\u6837\u7684\u3002 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u53e6\u4e00\u79cd\u65b9\u6cd5\u5728\u8fd0\u884c\u65f6\u6839\u636e\u5e94\u7528\u7a0b\u5e8f\u7684\u6570\u636e\u8981\u6c42\u6765\u8c03\u6574\u6570\u7ec4\u7684\u957f\u5ea6\uff0c\u8fd9\u4e9b\u8c03\u6574\u4f1a\u7531Python\u5217\u8868\u81ea\u52a8\u8fdb\u884c\u3002\u8fd9\u65f6\uff0c\u6570\u7ec4\u6709\u4ee5\u4e0b3\u79cd\u4e0d\u540c\u5f62\u5f0f\u3002 \u5728\u7a0b\u5e8f\u542f\u52a8\u65f6\u521b\u5efa\u4e00\u4e2a\u5177\u6709\u5408\u7406\u9ed8\u8ba4\u5927\u5c0f\u7684\u6570\u7ec4\u3002 \u5f53\u6570\u7ec4\u65e0\u6cd5\u5bb9\u7eb3\u66f4\u591a\u6570\u636e\u65f6\uff0c\u521b\u5efa\u4e00\u4e2a\u66f4\u5927\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u628a\u65e7\u6570\u7ec4\u91cc\u7684\u6570\u636e\u5143\u7d20\u4f20\u8f93\u7ed9\u5b83\u3002 \u5982\u679c\u6570\u7ec4\u5728\u6d6a\u8d39\u5185\u5b58\uff08\u5e94\u7528\u7a0b\u5e8f\u5220\u9664\u4e86\u4e00\u4e9b\u6570\u636e\uff09\uff0c\u90a3\u4e48\u7528\u7c7b\u4f3c\u7684\u65b9\u5f0f\u51cf\u5c0f\u6570\u7ec4\u7684\u957f\u5ea6\u3002","title":"4.1.2.\u9759\u6001\u5185\u5b58\u548c\u52a8\u6001\u5185\u5b58"},{"location":"python/DataStructure/04_ArrayChain/#413","text":"\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\uff08physical size\uff09\u662f\u6307\u6570\u7ec4\u5355\u5143\u7684\u603b\u6570\uff0c\u6216\u8005\u521b\u5efa\u6570\u7ec4\u65f6\u6307\u5b9a\u5176\u5bb9\u91cf\u7684\u90a3\u4e2a\u6570\u5b57\uff1b \u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\uff08logical size\uff09\u662f\u6307\u5f53\u524d\u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528\u7684\u5143\u7d20\u6570\u91cf\u3002 \u5f53\u6570\u7ec4\u88ab\u586b\u6ee1\u7684\u65f6\u5019\uff0c\u6211\u4eec\u4e0d\u9700\u8981\u62c5\u5fc3\u5b83\u4eec\u7684\u4e0d\u540c\u3002\u5f53\u6570\u7ec4\u88ab\u90e8\u5206\u586b\u6ee1\u7684\u65f6\u5019\uff0c\u672a\u88ab\u586b\u5145\u7684\u5185\u5b58\u5355\u5143\u91cc\u7684\u6570\u636e\u5bf9\u5f53\u524d\u5e94\u7528\u7a0b\u5e8f\u662f\u6ca1\u6709\u7528\u7684\uff0c\u6211\u4eec\u79f0\u4e4b\u5783\u573e\u5185\u5bb9\uff08garbage\uff09\u3002\u5728\u5927\u591a\u6570\u5e94\u7528\u7a0b\u5e8f\u91cc\uff0c\u6211\u4eec\u662f\u8981\u6ce8\u610f\u5bf9\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u8fdb\u884c\u8ffd\u8e2a\u3002\u901a\u5e38\u6765\u8bf4\uff0c\u903b\u8f91\u5c3a\u5bf8\u548c\u7269\u7406\u5c3a\u5bf8\u4f1a\u53cd\u6620\u51fa\u6709\u5173\u6570\u7ec4\u72b6\u6001\u7684\u51e0\u4e2a\u91cd\u70b9\u3002 \u5982\u679c\u903b\u8f91\u5c3a\u5bf8\u4e3a0\uff0c\u90a3\u4e48\u6570\u7ec4\u5c31\u4e3a\u7a7a\u3002\u4e5f\u5c31\u662f\u8bf4\uff0c\u8fd9\u4e2a\u6570\u7ec4\u4e0d\u5305\u542b\u4efb\u4f55\u6570\u636e\u5143\u7d20\u3002 \u5982\u679c\u5e76\u975e\u4e0a\u8ff0\u60c5\u51b5\uff0c\u5728\u4efb\u4f55\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u4e2d\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u7684\u7d22\u5f15\u90fd\u662f\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\u51cf1\u3002 \u5982\u679c\u903b\u8f91\u5c3a\u5bf8\u7b49\u4e8e\u7269\u7406\u5c3a\u5bf8\uff0c\u90a3\u4e48\u8868\u793a\u6570\u7ec4\u5df2\u88ab\u586b\u6ee1\u4e86\u3002","title":"4.1.3.\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8"},{"location":"python/DataStructure/04_ArrayChain/#414","text":"1\uff0e\u8bf7\u8bf4\u660e\u968f\u673a\u8bbf\u95ee\u7684\u5de5\u4f5c\u539f\u7406\uff0c\u4ee5\u53ca\u8fd9\u4e2a\u64cd\u4f5c\u8fd9\u4e48\u5feb\u7684\u539f\u56e0\u3002 \u89e3\u7b54\uff1a\u968f\u673a\u8bbf\u95ee\u662f\u4e00\u79cd\u8ba1\u7b97\u673a\u5b58\u50a8\u7cfb\u7edf\u4e2d\u7684\u8bfb\u53d6\u6216\u5199\u5165\u6570\u636e\u7684\u64cd\u4f5c\uff0c\u5176\u4e2d\u6570\u636e\u53ef\u4ee5\u901a\u8fc7\u76f4\u63a5\u8df3\u8f6c\u5230\u5176\u5b58\u50a8\u4f4d\u7f6e\u800c\u4e0d\u9700\u8981\u987a\u5e8f\u626b\u63cf\u6765\u8bbf\u95ee\u3002\u8fd9\u4e0e\u987a\u5e8f\u8bbf\u95ee\u4e0d\u540c\uff0c\u540e\u8005\u9700\u8981\u6309\u987a\u5e8f\u904d\u5386\u6570\u636e\u4ee5\u627e\u5230\u6240\u9700\u7684\u4fe1\u606f\u3002\u968f\u673a\u8bbf\u95ee\u7684\u5de5\u4f5c\u539f\u7406\u5982\u4e0b\uff1a \u5b58\u50a8\u4ecb\u8d28\uff1a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u786c\u76d8\u7b49\u5b58\u50a8\u8bbe\u5907\u90fd\u652f\u6301\u968f\u673a\u8bbf\u95ee\u3002\u8fd9\u4e9b\u5b58\u50a8\u4ecb\u8d28\u4e2d\u7684\u6570\u636e\u901a\u5e38\u88ab\u5212\u5206\u4e3a\u5757\u6216\u6247\u533a\uff0c\u5e76\u4e14\u6bcf\u4e2a\u5757\u6216\u6247\u533a\u90fd\u6709\u4e00\u4e2a\u552f\u4e00\u7684\u5730\u5740\u6216\u7d22\u5f15\u3002 \u8bbf\u95ee\u5730\u5740\uff1a\u4e3a\u4e86\u8fdb\u884c\u968f\u673a\u8bbf\u95ee\uff0c\u8ba1\u7b97\u673a\u9700\u8981\u77e5\u9053\u8981\u8bbf\u95ee\u7684\u6570\u636e\u7684\u5730\u5740\u3002\u8fd9\u4e2a\u5730\u5740\u53ef\u4ee5\u662f\u5185\u5b58\u4e2d\u7684\u7279\u5b9a\u4f4d\u7f6e\uff0c\u4e5f\u53ef\u4ee5\u662f\u786c\u76d8\u4e0a\u7684\u67d0\u4e2a\u6247\u533a\u7684\u5730\u5740\u3002 \u5bfb\u5740\u548c\u4f20\u8f93\uff1a\u8ba1\u7b97\u673a\u4f7f\u7528\u5b58\u50a8\u8bbe\u5907\u7684\u63a7\u5236\u5668\u6216\u5b58\u50a8\u5668\u7ba1\u7406\u5355\u5143\u6765\u67e5\u627e\u6570\u636e\u7684\u5730\u5740\u3002\u4e00\u65e6\u627e\u5230\u4e86\u6b63\u786e\u7684\u5730\u5740\uff0c\u5b58\u50a8\u8bbe\u5907\u4f1a\u5c06\u6570\u636e\u4f20\u8f93\u5230\u8ba1\u7b97\u673a\u7684\u5185\u5b58\u4e2d\u4f9b\u5904\u7406\u5668\u4f7f\u7528\u3002 \u8bbf\u95ee\u901f\u5ea6\uff1a\u968f\u673a\u8bbf\u95ee\u4e4b\u6240\u4ee5\u5982\u6b64\u5feb\u901f\uff0c\u662f\u56e0\u4e3a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u73b0\u4ee3\u786c\u76d8\u9a71\u52a8\u5668\u7b49\u5b58\u50a8\u8bbe\u5907\u90fd\u7ecf\u8fc7\u4e86\u4f18\u5316\uff0c\u53ef\u4ee5\u5feb\u901f\u54cd\u5e94\u8bbf\u95ee\u8bf7\u6c42\u3002\u8fd9\u4e9b\u8bbe\u5907\u4f7f\u7528\u4e86\u9ad8\u901f\u7f13\u5b58\u3001\u8bfb\u5199\u5934\u3001\u5bfb\u9053\u673a\u6784\u7b49\u6280\u672f\u6765\u6700\u5c0f\u5316\u6570\u636e\u8bbf\u95ee\u7684\u5ef6\u8fdf\u3002 \u539f\u56e0\uff1a \u5b58\u50a8\u8bbe\u5907\u7684\u7269\u7406\u7ed3\u6784\uff1a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u786c\u76d8\u7b49\u5b58\u50a8\u8bbe\u5907\u7684\u7269\u7406\u7ed3\u6784\u88ab\u8bbe\u8ba1\u6210\u53ef\u4ee5\u968f\u673a\u8bbf\u95ee\u7684\u3002\u5185\u5b58\u4e2d\u7684\u6bcf\u4e2a\u5730\u5740\u90fd\u53ef\u4ee5\u77ac\u95f4\u8bbf\u95ee\uff0c\u800c\u786c\u76d8\u4e0a\u7684\u6247\u533a\u4e5f\u53ef\u4ee5\u901a\u8fc7\u78c1\u5934\u5bfb\u9053\u548c\u65cb\u8f6c\u78c1\u76d8\u7b49\u673a\u5236\u8fc5\u901f\u8bbf\u95ee\u3002 \u9ad8\u901f\u7f13\u5b58\uff1a\u73b0\u4ee3\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u5904\u7406\u5668\u90fd\u914d\u5907\u4e86\u9ad8\u901f\u7f13\u5b58\uff08\u4f8b\u5982\uff0cCPU\u7f13\u5b58\uff09\u3002\u8fd9\u4e9b\u9ad8\u901f\u7f13\u5b58\u5b58\u50a8\u4e86\u6700\u8fd1\u8bbf\u95ee\u7684\u6570\u636e\uff0c\u53ef\u4ee5\u5feb\u901f\u63d0\u4f9b\u7ed9\u5904\u7406\u5668\uff0c\u4ece\u800c\u964d\u4f4e\u4e86\u8bbf\u95ee\u5ef6\u8fdf\u3002 \u5b58\u50a8\u5668\u7ba1\u7406\uff1a\u64cd\u4f5c\u7cfb\u7edf\u548c\u5b58\u50a8\u8bbe\u5907\u7684\u63a7\u5236\u5668\u4f1a\u7ba1\u7406\u5b58\u50a8\u5668\u7684\u8bbf\u95ee\uff0c\u4ee5\u786e\u4fdd\u6570\u636e\u53ef\u4ee5\u9ad8\u6548\u5730\u88ab\u8bbf\u95ee\u548c\u4f20\u8f93\u3002\u8fd9\u5305\u62ec\u4e86\u78c1\u76d8\u8c03\u5ea6\u7b97\u6cd5\u3001\u5185\u5b58\u5206\u9875\u7b49\u7b56\u7565\u3002 \u6280\u672f\u8fdb\u6b65\uff1a\u786c\u4ef6\u5236\u9020\u6280\u672f\u7684\u8fdb\u6b65\u548c\u5b58\u50a8\u8bbe\u5907\u7684\u4f18\u5316\u4f7f\u5f97\u968f\u673a\u8bbf\u95ee\u901f\u5ea6\u66f4\u5feb\u3002\u4f8b\u5982\uff0c\u56fa\u6001\u786c\u76d8\uff08SSD\uff09\u7684\u51fa\u73b0\u663e\u8457\u63d0\u9ad8\u4e86\u6570\u636e\u7684\u968f\u673a\u8bbf\u95ee\u901f\u5ea6\u3002 \u603b\u4e4b\uff0c\u968f\u673a\u8bbf\u95ee\u4e4b\u6240\u4ee5\u5982\u6b64\u5feb\u901f\uff0c\u662f\u56e0\u4e3a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u5b58\u50a8\u8bbe\u5907\u7684\u7269\u7406\u548c\u6280\u672f\u7279\u6027\u4f7f\u5176\u80fd\u591f\u4ee5\u9ad8\u6548\u3001\u8fc5\u901f\u7684\u65b9\u5f0f\u8bbf\u95ee\u6570\u636e\u3002\u8fd9\u79cd\u8bbf\u95ee\u901f\u5ea6\u5bf9\u4e8e\u8ba1\u7b97\u673a\u7684\u6027\u80fd\u548c\u54cd\u5e94\u65f6\u95f4\u81f3\u5173\u91cd\u8981\u3002 2\uff0e\u6570\u7ec4\u548cPython\u5217\u8868\u4e4b\u95f4\u6709\u4ec0\u4e48\u533a\u522b\uff1f \u89e3\u7b54\uff1a\u6570\u7ec4\u548cPython\u5217\u8868\u4e4b\u95f4\u6709\u51e0\u4e2a\u5173\u952e\u533a\u522b\uff0c\u8fd9\u4e9b\u533a\u522b\u5728\u6570\u636e\u7ed3\u6784\u3001\u529f\u80fd\u548c\u7528\u9014\u4e0a\u5b58\u5728\u5dee\u5f02\uff1a \u6570\u636e\u7c7b\u578b\uff1a \u6570\u7ec4\uff1a\u901a\u5e38\u8981\u6c42\u6240\u6709\u5143\u7d20\u5177\u6709\u76f8\u540c\u7684\u6570\u636e\u7c7b\u578b\u3002\u8fd9\u662f\u56e0\u4e3a\u6570\u7ec4\u5728\u5185\u5b58\u4e2d\u4ee5\u7d27\u51d1\u7684\u65b9\u5f0f\u5b58\u50a8\u6570\u636e\uff0c\u9700\u8981\u77e5\u9053\u6bcf\u4e2a\u5143\u7d20\u7684\u5927\u5c0f\u4ee5\u4fbf\u8fdb\u884c\u968f\u673a\u8bbf\u95ee\u3002 Python\u5217\u8868\uff1aPython\u7684\u5217\u8868\u53ef\u4ee5\u5bb9\u7eb3\u4e0d\u540c\u6570\u636e\u7c7b\u578b\u7684\u5143\u7d20\uff0c\u56e0\u4e3a\u5b83\u4eec\u662f\u52a8\u6001\u7c7b\u578b\u7684\u3002 \u5185\u5b58\u7ba1\u7406\uff1a \u6570\u7ec4\uff1a\u901a\u5e38\u5728\u521b\u5efa\u65f6\u9700\u8981\u6307\u5b9a\u56fa\u5b9a\u5927\u5c0f\uff0c\u56e0\u6b64\u5728\u5185\u5b58\u4e2d\u4f1a\u5206\u914d\u4e00\u5757\u8fde\u7eed\u7684\u7a7a\u95f4\uff0c\u8fd9\u4f7f\u5f97\u6570\u7ec4\u5bf9\u4e8e\u9ad8\u6548\u7684\u968f\u673a\u8bbf\u95ee\u975e\u5e38\u9002\u7528\u3002 Python\u5217\u8868\uff1aPython\u7684\u5217\u8868\u662f\u52a8\u6001\u7684\uff0c\u5b83\u4eec\u53ef\u4ee5\u6839\u636e\u9700\u8981\u81ea\u52a8\u6269\u5c55\u6216\u7f29\u5c0f\u3002\u8fd9\u5bfc\u81f4\u4e86\u4e00\u4e9b\u989d\u5916\u7684\u5185\u5b58\u5f00\u9500\uff0c\u56e0\u4e3a\u5217\u8868\u9700\u8981\u66f4\u591a\u7684\u7a7a\u95f4\u6765\u7ba1\u7406\u5143\u7d20\u7684\u6dfb\u52a0\u548c\u5220\u9664\u3002 \u6027\u80fd\uff1a \u6570\u7ec4\uff1a\u7531\u4e8e\u5185\u5b58\u5e03\u5c40\u8fde\u7eed\uff0c\u56e0\u6b64\u6570\u7ec4\u901a\u5e38\u5728\u8bbf\u95ee\u5143\u7d20\u65f6\u66f4\u5feb\u3002\u6570\u7ec4\u8fd8\u652f\u6301\u66f4\u591a\u7684\u5e95\u5c42\u64cd\u4f5c\uff0c\u5982\u4f4d\u64cd\u4f5c\u3002 Python\u5217\u8868\uff1aPython\u5217\u8868\u66f4\u52a0\u7075\u6d3b\uff0c\u4f46\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\u53ef\u80fd\u4f1a\u5bfc\u81f4\u6027\u80fd\u4e0b\u964d\uff0c\u7279\u522b\u662f\u5f53\u6d89\u53ca\u5927\u91cf\u5143\u7d20\u7684\u63d2\u5165\u548c\u5220\u9664\u64cd\u4f5c\u65f6\u3002 \u64cd\u4f5c\u548c\u65b9\u6cd5\uff1a \u6570\u7ec4\uff1a\u901a\u5e38\u63d0\u4f9b\u4e00\u7ec4\u57fa\u672c\u64cd\u4f5c\uff0c\u5982\u8bfb\u53d6\u548c\u5199\u5165\u5143\u7d20\uff0c\u4ee5\u53ca\u4e00\u4e9b\u6570\u5b66\u8fd0\u7b97\uff0c\u5982\u5411\u91cf\u5316\u64cd\u4f5c\u3002 Python\u5217\u8868\uff1aPython\u5217\u8868\u63d0\u4f9b\u4e86\u66f4\u4e30\u5bcc\u7684\u65b9\u6cd5\u548c\u64cd\u4f5c\uff0c\u5305\u62ec\u5143\u7d20\u7684\u63d2\u5165\u3001\u5220\u9664\u3001\u8ffd\u52a0\u3001\u5207\u7247\u3001\u8fde\u63a5\u7b49\u3002 \u8bed\u8a00\u4f9d\u8d56\u6027\uff1a \u6570\u7ec4\uff1a\u6570\u7ec4\u901a\u5e38\u662f\u7f16\u7a0b\u8bed\u8a00\u7684\u4e00\u90e8\u5206\uff0c\u5177\u6709\u56fa\u5b9a\u7684\u8bed\u6cd5\u548c\u8bed\u4e49\u3002 Python\u5217\u8868\uff1aPython\u7684\u5217\u8868\u662fPython\u6807\u51c6\u5e93\u7684\u4e00\u90e8\u5206\uff0c\u4e0ePython\u7684\u52a8\u6001\u7279\u6027\u76f8\u9002\u5e94\u3002 \u9002\u7528\u573a\u666f\uff1a \u6570\u7ec4\uff1a\u9002\u7528\u4e8e\u9700\u8981\u9ad8\u6548\u968f\u673a\u8bbf\u95ee\u7684\u60c5\u51b5\uff0c\u5982\u6570\u503c\u8ba1\u7b97\u3001\u56fe\u50cf\u5904\u7406\u7b49\u3002 Python\u5217\u8868\uff1a\u9002\u7528\u4e8e\u66f4\u5e7f\u6cdb\u7684\u5e94\u7528\uff0c\u7279\u522b\u662f\u5728\u7f16\u5199Python\u4ee3\u7801\u65f6\uff0c\u56e0\u4e3a\u5b83\u4eec\u66f4\u7075\u6d3b\u4e14\u6613\u4e8e\u4f7f\u7528\u3002 \u603b\u4e4b\uff0c\u6570\u7ec4\u548cPython\u5217\u8868\u90fd\u6709\u81ea\u5df1\u7684\u4f18\u52bf\u548c\u9002\u7528\u573a\u666f\u3002\u9009\u62e9\u4f7f\u7528\u54ea\u79cd\u6570\u636e\u7ed3\u6784\u53d6\u51b3\u4e8e\u5177\u4f53\u7684\u9700\u6c42\u548c\u7f16\u7a0b\u8bed\u8a00\u3002\u5728Python\u4e2d\uff0c\u901a\u5e38\u4f1a\u4f18\u5148\u9009\u62e9\u4f7f\u7528\u5217\u8868\uff0c\u56e0\u4e3a\u5b83\u4eec\u66f4\u65b9\u4fbf\uff0c\u800c\u5728\u5176\u4ed6\u7f16\u7a0b\u8bed\u8a00\u4e2d\uff0c\u5982C\u6216Java\uff0c\u6570\u7ec4\u53ef\u80fd\u66f4\u4e3a\u5e38\u89c1\u3002 \u5728\u8fd9\u91cc\u9700\u8981\u8bf4\u660e\u4e00\u4e2a\u6982\u5ff5\u3002\u5728Python\u4e2d\uff0c\u672f\u8bed\"\u6570\u7ec4\"\u901a\u5e38\u6307\u7684\u662fNumPy\u5e93\u4e2d\u7684\u6570\u7ec4\u5bf9\u8c61\uff0c\u800c\"\u5217\u8868\"\u6307\u7684\u662fPython\u7684\u5185\u7f6e\u5217\u8868\uff08list\uff09\u6570\u636e\u7ed3\u6784\u3002\u8fd9\u4e24\u8005\u4e4b\u95f4\u6709\u4ee5\u4e0b\u533a\u522b\uff1a \u6570\u636e\u7c7b\u578b\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1aNumPy\u5e93\u63d0\u4f9b\u4e86\u4e00\u4e2a\u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61\uff0c\u5b83\u53ef\u4ee5\u5305\u542b\u76f8\u540c\u6570\u636e\u7c7b\u578b\u7684\u5143\u7d20\uff0c\u5e76\u652f\u6301\u9ad8\u7ea7\u6570\u5b66\u3001\u79d1\u5b66\u548c\u5de5\u7a0b\u8ba1\u7b97\u3002NumPy\u6570\u7ec4\u7684\u5143\u7d20\u7c7b\u578b\u901a\u5e38\u662f\u56fa\u5b9a\u7684\uff0c\u4f8b\u5982\uff0c\u53ef\u4ee5\u662f\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u590d\u6570\u7b49\u3002\u8fd9\u4e9b\u6570\u7ec4\u662f\u9ad8\u6027\u80fd\u7684\uff0c\u652f\u6301\u5411\u91cf\u5316\u64cd\u4f5c\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u7684\u5185\u7f6e\u5217\u8868\u662f\u4e00\u79cd\u901a\u7528\u7684\u3001\u52a8\u6001\u7c7b\u578b\u7684\u6570\u636e\u7ed3\u6784\uff0c\u53ef\u4ee5\u5305\u542b\u4e0d\u540c\u6570\u636e\u7c7b\u578b\u7684\u5143\u7d20\uff0c\u4f8b\u5982\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u5b57\u7b26\u4e32\u3001\u5bf9\u8c61\u7b49\u3002\u5217\u8868\u53ef\u4ee5\u52a8\u6001\u6269\u5c55\u548c\u7f29\u5c0f\uff0c\u5e76\u63d0\u4f9b\u4e86\u4e30\u5bcc\u7684\u5185\u7f6e\u65b9\u6cd5\u548c\u64cd\u4f5c\u3002 \u6027\u80fd\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1aNumPy\u6570\u7ec4\u901a\u5e38\u6bd4Python\u5217\u8868\u66f4\u9ad8\u6548\uff0c\u7279\u522b\u662f\u5728\u8fdb\u884c\u6570\u503c\u8ba1\u7b97\u548c\u79d1\u5b66\u8ba1\u7b97\u65f6\u3002\u5b83\u4eec\u5185\u90e8\u4f7f\u7528\u4e86C\u8bed\u8a00\u5b9e\u73b0\uff0c\u652f\u6301\u5411\u91cf\u5316\u64cd\u4f5c\uff0c\u56e0\u6b64\u5728\u5927\u89c4\u6a21\u6570\u636e\u5904\u7406\u4e2d\u901a\u5e38\u66f4\u5feb\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u5217\u8868\u867d\u7136\u7075\u6d3b\uff0c\u4f46\u6027\u80fd\u76f8\u5bf9\u8f83\u4f4e\uff0c\u4e0d\u9002\u5408\u5927\u89c4\u6a21\u7684\u6570\u503c\u8ba1\u7b97\u3002\u5b83\u4eec\u7684\u5143\u7d20\u7c7b\u578b\u53ef\u4ee5\u4e0d\u540c\uff0c\u8fd9\u610f\u5473\u7740\u9700\u8981\u66f4\u591a\u7684\u5185\u5b58\u548c\u5904\u7406\u65f6\u95f4\u6765\u7ba1\u7406\u5143\u7d20\u3002 \u5e93\u4f9d\u8d56\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1a\u4f7f\u7528NumPy\u5e93\u9700\u8981\u5b89\u88c5NumPy\u6a21\u5757\u3002NumPy\u662fPython\u4e2d\u7528\u4e8e\u6570\u503c\u8ba1\u7b97\u7684\u6838\u5fc3\u5e93\uff0c\u5e7f\u6cdb\u5e94\u7528\u4e8e\u79d1\u5b66\u8ba1\u7b97\u3001\u673a\u5668\u5b66\u4e60\u7b49\u9886\u57df\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u7684\u5185\u7f6e\u5217\u8868\u662fPython\u6807\u51c6\u5e93\u7684\u4e00\u90e8\u5206\uff0c\u65e0\u9700\u989d\u5916\u5b89\u88c5\u3002 \u529f\u80fd\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1aNumPy\u6570\u7ec4\u63d0\u4f9b\u4e86\u8bb8\u591a\u6570\u5b66\u548c\u79d1\u5b66\u8ba1\u7b97\u51fd\u6570\uff0c\u5982\u7ebf\u6027\u4ee3\u6570\u3001\u5085\u7acb\u53f6\u53d8\u6362\u3001\u7edf\u8ba1\u5206\u6790\u7b49\u3002\u5b83\u4eec\u9002\u7528\u4e8e\u5904\u7406\u5927\u91cf\u6570\u503c\u6570\u636e\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u5217\u8868\u63d0\u4f9b\u4e86\u901a\u7528\u7684\u6570\u636e\u5bb9\u5668\uff0c\u7528\u4e8e\u5b58\u50a8\u548c\u7ba1\u7406\u5404\u79cd\u7c7b\u578b\u7684\u6570\u636e\uff0c\u4f46\u4e0d\u63d0\u4f9b\u4e13\u95e8\u7684\u6570\u5b66\u548c\u79d1\u5b66\u8ba1\u7b97\u529f\u80fd\u3002 \u5982\u679c\u9700\u8981\u8fdb\u884c\u6570\u503c\u8ba1\u7b97\u3001\u79d1\u5b66\u8ba1\u7b97\u6216\u6570\u636e\u5206\u6790\uff0c\u901a\u5e38\u4f1a\u4f7f\u7528NumPy\u6570\u7ec4\u3002\u5982\u679c\u53ea\u662f\u9700\u8981\u4e00\u4e2a\u901a\u7528\u7684\u6570\u636e\u5bb9\u5668\uff0c\u7528\u4e8e\u5b58\u50a8\u548c\u7ba1\u7406\u6570\u636e\uff0c\u90a3\u4e48Python\u5217\u8868\u901a\u5e38\u8db3\u591f\u4e86\u3002 3\uff0e\u8bf7\u8bf4\u660e\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u4e4b\u95f4\u7684\u533a\u522b\u3002 \u89e3\u7b54\uff1a\"\u7269\u7406\u5c3a\u5bf8\"\u548c\"\u903b\u8f91\u5c3a\u5bf8\"\u901a\u5e38\u7528\u4e8e\u63cf\u8ff0\u6570\u636e\u7ed3\u6784\u4e2d\u7684\u4e24\u4e2a\u4e0d\u540c\u65b9\u9762\uff1a \u7269\u7406\u5c3a\u5bf8\uff08Physical Size\uff09\uff1a \u7269\u7406\u5c3a\u5bf8\u662f\u6307\u6570\u636e\u7ed3\u6784\u5b9e\u9645\u5360\u7528\u7684\u5185\u5b58\u7a7a\u95f4\u6216\u5b58\u50a8\u4ecb\u8d28\u4e2d\u7684\u7a7a\u95f4\u5927\u5c0f\u3002 \u5b83\u8868\u793a\u6570\u636e\u7ed3\u6784\u5728\u8ba1\u7b97\u673a\u5185\u5b58\u6216\u78c1\u76d8\u4e2d\u6240\u5360\u636e\u7684\u5b9e\u9645\u5b57\u8282\u6570\u3002 \u7269\u7406\u5c3a\u5bf8\u4e0e\u6570\u636e\u7ed3\u6784\u7684\u5b58\u50a8\u65b9\u5f0f\u3001\u6570\u636e\u7c7b\u578b\u4ee5\u53ca\u8ba1\u7b97\u673a\u67b6\u6784\u6709\u5173\u3002 \u903b\u8f91\u5c3a\u5bf8\uff08Logical Size\uff09\uff1a \u903b\u8f91\u5c3a\u5bf8\u662f\u6307\u6570\u636e\u7ed3\u6784\u4e2d\u5305\u542b\u7684\u5143\u7d20\u6570\u91cf\u6216\u6570\u636e\u9879\u7684\u6570\u91cf\u3002 \u5b83\u8868\u793a\u6570\u636e\u7ed3\u6784\u5185\u90e8\u7684\u5143\u7d20\u6570\u91cf\u6216\u6570\u636e\u9879\u7684\u4e2a\u6570\uff0c\u4e0d\u6d89\u53ca\u5b9e\u9645\u7684\u5b58\u50a8\u5927\u5c0f\u3002 \u903b\u8f91\u5c3a\u5bf8\u901a\u5e38\u7528\u4e8e\u63cf\u8ff0\u6570\u636e\u7ed3\u6784\u7684\u5bb9\u91cf\u3001\u89c4\u6a21\u6216\u7ef4\u5ea6\u3002 \u8fd9\u4e24\u4e2a\u6982\u5ff5\u4e4b\u95f4\u7684\u5173\u7cfb\u5982\u4e0b\uff1a \u4e00\u4e2a\u6570\u636e\u7ed3\u6784\u53ef\u4ee5\u5177\u6709\u56fa\u5b9a\u7684\u7269\u7406\u5c3a\u5bf8\uff08\u5360\u636e\u56fa\u5b9a\u6570\u91cf\u7684\u5b57\u8282\uff09\uff0c\u4f46\u5176\u903b\u8f91\u5c3a\u5bf8\u53ef\u4ee5\u6839\u636e\u5b9e\u9645\u5b58\u50a8\u7684\u5143\u7d20\u6570\u91cf\u800c\u53d8\u5316\u3002 \u7269\u7406\u5c3a\u5bf8\u901a\u5e38\u662f\u7531\u8ba1\u7b97\u673a\u786c\u4ef6\u548c\u64cd\u4f5c\u7cfb\u7edf\u7ba1\u7406\u7684\uff0c\u800c\u903b\u8f91\u5c3a\u5bf8\u5219\u662f\u7a0b\u5e8f\u5458\u6839\u636e\u6570\u636e\u7ed3\u6784\u7684\u8bbe\u8ba1\u6765\u7ba1\u7406\u7684\u3002 \u4e3e\u4f8b\u6765\u8bf4\uff0c\u4e00\u4e2a\u6574\u6570\u6570\u7ec4\u53ef\u4ee5\u5177\u6709\u56fa\u5b9a\u7684\u7269\u7406\u5c3a\u5bf8\uff0c\u4f8b\u59824\u5b57\u8282/\u6574\u6570\uff0c\u4f46\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\u53ef\u4ee5\u662f\u6570\u7ec4\u4e2d\u6574\u6570\u7684\u6570\u91cf\uff0c\u53ef\u4ee5\u662f0\u4e2a\u300110\u4e2a\u3001100\u4e2a\u7b49\u7b49\u3002\u56e0\u6b64\uff0c\u903b\u8f91\u5c3a\u5bf8\u63cf\u8ff0\u4e86\u6570\u7ec4\u53ef\u4ee5\u5bb9\u7eb3\u7684\u5143\u7d20\u6570\u91cf\uff0c\u800c\u7269\u7406\u5c3a\u5bf8\u63cf\u8ff0\u4e86\u5b9e\u9645\u5360\u7528\u7684\u5185\u5b58\u7a7a\u95f4\u3002 \u5728\u6570\u636e\u7ed3\u6784\u7684\u8bbe\u8ba1\u548c\u4f7f\u7528\u4e2d\uff0c\u4e86\u89e3\u548c\u7ba1\u7406\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u5bf9\u4e8e\u6709\u6548\u5730\u5229\u7528\u8ba1\u7b97\u673a\u8d44\u6e90\u975e\u5e38\u91cd\u8981\u3002","title":"4.1.4.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#42","text":"\u5728\u4e0b\u9762\u7684\u4f8b\u5b50\u91cc\uff0c\u6211\u4eec\u5047\u5b9a\u6709\u4e0b\u9762\u8fd9\u4e9b\u6570\u636e\u914d\u7f6e\u3002 DEFAULT_CAPACITY = 5 # \u6570\u7ec4\u9ed8\u8ba4\u7684\u7269\u7406\u5c3a\u5bf8\uff08\u4e5f\u5c31\u662f\u5bb9\u91cf\uff09\u662f5 logicalSize = 0 # \u6570\u7ec4\u7684\u521d\u59cb\u903b\u8f91\u5c3a\u5bf8\u662f0 a = Array ( DEFAULT_CAPACITY )","title":"4.2.\u6570\u7ec4\u7684\u64cd\u4f5c"},{"location":"python/DataStructure/04_ArrayChain/#421","text":"\u5f53\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u7b49\u4e8e\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u65f6\uff0c\u5982\u679c\u8981\u63d2\u5165\u65b0\u7684\u5143\u7d20\uff0c\u5c31\u9700\u8981\u589e\u5927\u6570\u7ec4\u7684\u5c3a\u5bf8\u3002 \u5982\u679c\u9700\u8981\u4e3a\u6570\u7ec4\u63d0\u4f9b\u66f4\u591a\u5185\u5b58\uff0cPython\u7684list\u7c7b\u578b\u4f1a\u5728\u8c03\u7528insert\u6216append\u65b9\u6cd5\u65f6\u6267\u884c\u8fd9\u4e2a\u64cd\u4f5c\u3002 \u8c03\u6574\u6570\u7ec4\u5c3a\u5bf8\u7684\u8fc7\u7a0b\u5305\u542b\u5982\u4e0b3\u4e2a\u6b65\u9aa4\u3002 \u521b\u5efa\u4e00\u4e2a\u66f4\u5927\u7684\u65b0\u6570\u7ec4\u3002 \u5c06\u6570\u636e\u4ece\u65e7\u6570\u7ec4\u4e2d\u590d\u5236\u5230\u65b0\u6570\u7ec4\u3002 \u5c06\u6307\u5411\u65e7\u6570\u7ec4\u7684\u53d8\u91cf\u6307\u5411\u65b0\u6570\u7ec4\u5bf9\u8c61\u3002 \u4e0b\u9762\u4ee3\u7801\u5b9e\u73b0\u3002 class Array ( object ): ... def main ( size = 10 ): DEFAULT_CAPACITY = 5 logicalSize = 0 my_array = Array ( DEFAULT_CAPACITY ) print ( \"Initial array is: \" , my_array ) print ( \"Len of the array: \" , my_array . __len__ ()) for i in range ( len ( my_array )): my_array [ i ] = i print ( \"The array is: \" , my_array . items ) # \u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 if logicalSize == len ( my_array ): temp = Array ( len ( my_array ) + 1 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 if __name__ == \"__main__\" : main () \u5728\u4e0a\u9762\u4ee3\u7801\u4e2d\uff0c\u901a\u8fc7 temp[i] = my_array[i] \u6765\u8c03\u6574\u6570\u7ec4\u5c3a\u5bf8\uff0c\u8fd9\u4e2a\u590d\u5236\u64cd\u4f5c\u7684\u6570\u91cf\u662f\u7ebf\u6027\u589e\u957f\u7684\u3002\u56e0\u6b64\uff0c\u5c06 n \u4e2a\u5143\u7d20\u6dfb\u52a0\u5230\u6570\u7ec4\u91cc\u7684\u603b\u65f6\u95f4\u590d\u6742\u5ea6\u662f 1+2+3...+n \uff0c\u4e5f\u5c31\u662f n(n+1)/2 \uff0c\u56e0\u6b64\u662f O(n^2) \u3002 \u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\uff0c\u901a\u8fc7 temp = Array(len(my_array) + 1) \u5bf9\u6570\u7ec4\u8fdb\u884c\u52a8\u6001\u6269\u5c55\uff0c\u5bf9\u6027\u80fd\u4f1a\u4ea7\u751f\u4e00\u4e9b\u53ef\u80fd\u7684\u5f71\u54cd\uff1a \u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u52a8\u6001\u6269\u5c55\u6570\u7ec4\u901a\u5e38\u9700\u8981\u590d\u5236\u73b0\u6709\u6570\u636e\u5230\u65b0\u7684\u5185\u5b58\u4f4d\u7f6e\uff0c\u8fd9\u5c06\u6d89\u53ca\u5230\u5143\u7d20\u7684\u590d\u5236\u64cd\u4f5c\u3002\u8fd9\u4e9b\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u6570\u7ec4\u7684\u957f\u5ea6\uff0c\u901a\u5e38\u662f O(n) \uff0c\u5176\u4e2d n \u662f\u6570\u7ec4\u7684\u957f\u5ea6\u3002\u56e0\u6b64\uff0c\u5f53\u6570\u7ec4\u9700\u8981\u6269\u5c55\u65f6\uff0c\u53ef\u80fd\u4f1a\u4ea7\u751f\u4e00\u4e9b\u989d\u5916\u7684\u65f6\u95f4\u5f00\u9500\u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\uff1a\u52a8\u6001\u6269\u5c55\u6570\u7ec4\u4f1a\u5360\u7528\u989d\u5916\u7684\u5185\u5b58\u7a7a\u95f4\uff0c\u56e0\u4e3a\u9700\u8981\u5206\u914d\u65b0\u7684\u5185\u5b58\u5757\u6765\u5bb9\u7eb3\u6269\u5c55\u540e\u7684\u6570\u7ec4\u3002\u8fd9\u53ef\u80fd\u4f1a\u5bfc\u81f4\u5185\u5b58\u788e\u7247\u5316\uff0c\u7279\u522b\u662f\u5728\u9891\u7e41\u6269\u5c55\u548c\u7f29\u5c0f\u6570\u7ec4\u65f6\u3002 \u6269\u5c55\u9891\u7387\uff1a\u6269\u5c55\u6570\u7ec4\u7684\u9891\u7387\u4f1a\u5f71\u54cd\u6027\u80fd\u3002\u5982\u679c\u6570\u7ec4\u9700\u8981\u9891\u7e41\u6269\u5c55\uff0c\u90a3\u4e48\u590d\u5236\u548c\u5185\u5b58\u5206\u914d\u7684\u5f00\u9500\u4f1a\u66f4\u52a0\u663e\u8457\uff0c\u4ece\u800c\u964d\u4f4e\u6027\u80fd\u3002\u56e0\u6b64\uff0c\u5728\u8bbe\u8ba1\u6570\u636e\u7ed3\u6784\u65f6\uff0c\u901a\u5e38\u4f1a\u8003\u8651\u521d\u59cb\u5bb9\u91cf\u548c\u6269\u5c55\u7b56\u7565\uff0c\u4ee5\u51cf\u5c11\u4e0d\u5fc5\u8981\u7684\u6269\u5c55\u6b21\u6570\u3002 Amortized Analysis\uff1a\u4e00\u4e9b\u6570\u636e\u7ed3\u6784\uff0c\u4f8b\u5982Python\u7684\u5217\u8868\uff08list\uff09\uff0c\u91c7\u7528\u644a\u8fd8\u5206\u6790\u6765\u5e73\u644a\u52a8\u6001\u6269\u5c55\u7684\u5f00\u9500\u3002\u8fd9\u610f\u5473\u7740\u867d\u7136\u67d0\u4e9b\u64cd\u4f5c\u53ef\u80fd\u4f1a\u82b1\u8d39 O(n) \u7684\u65f6\u95f4\uff0c\u4f46\u8fd9\u4e9b\u5f00\u9500\u5728\u4e00\u7cfb\u5217\u64cd\u4f5c\u4e2d\u88ab\u5206\u644a\uff0c\u5e73\u5747\u4e0b\u6765\u4ecd\u7136\u4fdd\u6301\u8f83\u4f4e\u7684\u590d\u6742\u5ea6\u3002\u8fd9\u53ef\u4ee5\u5728\u4e00\u5b9a\u7a0b\u5ea6\u4e0a\u7f13\u89e3\u6027\u80fd\u95ee\u9898\u3002 \u52a8\u6001\u6269\u5c55\u6570\u7ec4\u4f1a\u5f15\u5165\u4e00\u4e9b\u6027\u80fd\u5f00\u9500\uff0c\u4f46\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u8fd9\u79cd\u5f00\u9500\u901a\u5e38\u662f\u53ef\u4ee5\u63a5\u53d7\u7684\u3002\u4e3a\u4e86\u4f18\u5316\u6027\u80fd\uff0c\u53ef\u4ee5\u8003\u8651\u4ee5\u4e0b\u51e0\u70b9\u7b56\u7565\uff0c\u9700\u8981\u6839\u636e\u5177\u4f53\u5e94\u7528\u7684\u9700\u6c42\u548c\u6027\u80fd\u8981\u6c42\u6765\u6743\u8861\u8fd9\u4e9b\u56e0\u7d20\uff1a \u9884\u5148\u5206\u914d\u8db3\u591f\u7684\u521d\u59cb\u5bb9\u91cf\uff0c\u4ee5\u51cf\u5c11\u6269\u5c55\u7684\u9891\u7387\u3002 \u4f7f\u7528\u644a\u8fd8\u5206\u6790\u6765\u5e73\u644a\u5f00\u9500\u3002 \u8003\u8651\u4f7f\u7528\u5176\u4ed6\u6570\u636e\u7ed3\u6784\uff0c\u5982\u94fe\u8868\uff0c\u5bf9\u63d2\u5165\u548c\u5220\u9664\u64cd\u4f5c\u7684\u6027\u80fd\u66f4\u52a0\u53cb\u597d\u3002 \u4e0b\u9762\uff0c\u5c1d\u8bd5\u5728\u6bcf\u6b21\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u65f6\u628a\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\uff0c\u4ee3\u7801\u5b9e\u73b0\u5982\u4e0b\uff1a class Array ( object ): ... def main ( size = 10 ): # \u521d\u59cb\u503c DEFAULT_CAPACITY = 5 logicalSize = 0 my_array = Array ( DEFAULT_CAPACITY ) # \u6253\u5370\u8f93\u51fa\u521d\u59cb\u6570\u7ec4\u4fe1\u606f print ( \"Initial array is: \" , my_array ) print ( \"Len of the array: \" , my_array . __len__ ()) # \u7ed9\u6570\u7ec4\u8d4b\u503c for i in range ( len ( my_array )): my_array [ i ] = i print ( \"The array is: \" , my_array . items ) # \u6253\u5370\u8f93\u51fa\u6570\u7ec4 # \u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 while logicalSize < DEFAULT_CAPACITY * 2 : logicalSize += 1 if logicalSize == len ( my_array ): # \u89e6\u53d1\u6761\u4ef6 temp = Array ( len ( my_array ) + 1 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 print ( \"The array after increased is: \" , my_array . items ) # \u6253\u5370\u8f93\u51fa\u6570\u7ec4 if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Initial array is: [None, None, None, None, None] # Len of the array: 5 # The array is: [0, 1, 2, 3, 4] # The array after increased is: [0, 1, 2, 3, 4, None, None, None, None, None, None] \u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u6765\u6269\u5c55\u6570\u7ec4\u7684\u65b9\u5f0f\u662f\u4e00\u79cd\u5e38\u89c1\u7684\u7b56\u7565\uff0c\u901a\u5e38\u7528\u4e8e\u51cf\u5c11\u52a8\u6001\u6570\u7ec4\u7684\u9891\u7e41\u6269\u5c55\u6b21\u6570\uff0c\u4ee5\u63d0\u9ad8\u6027\u80fd\u3002\u8fd9\u79cd\u65b9\u5f0f\u7684\u64cd\u4f5c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3b\u8981\u53d6\u51b3\u4e8e\u6269\u5c55\u64cd\u4f5c\u7684\u9891\u7387\u548c\u5143\u7d20\u7684\u590d\u5236\u6210\u672c\u3002 \u644a\u8fd8\u5206\u6790\uff1a\u5bf9\u4e8e\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u7684\u7b56\u7565\uff0c\u644a\u8fd8\u5206\u6790\u8868\u660e\uff0c\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u7684\u644a\u8fd8\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662f\u5e38\u6570\u65f6\u95f4\u7684\uff08\u901a\u5e38\u662fO(1)\uff09\uff0c\u8fd9\u610f\u5473\u7740\u5e73\u5747\u4e0b\u6765\uff0c\u6bcf\u6b21\u6269\u5c55\u7684\u5f00\u9500\u662f\u56fa\u5b9a\u7684\uff0c\u800c\u4e0d\u4f1a\u968f\u6570\u7ec4\u7684\u5927\u5c0f\u7ebf\u6027\u589e\u52a0\u3002 \u64cd\u4f5c\u65f6\u95f4\uff1a\u5047\u8bbe\u6570\u7ec4\u9700\u8981\u6269\u5c55\uff0c\u90a3\u4e48\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u9700\u8981\u5206\u914d\u65b0\u7684\u5185\u5b58\u5757\u5e76\u590d\u5236\u73b0\u6709\u5143\u7d20\uff0c\u8fd9\u4e2a\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\uff0c\u5176\u4e2dn\u662f\u6570\u7ec4\u7684\u5f53\u524d\u5927\u5c0f\u3002\u7136\u800c\uff0c\u7531\u4e8e\u6269\u5c55\u64cd\u4f5c\u4e0d\u662f\u6bcf\u6b21\u90fd\u6267\u884c\u7684\uff0c\u800c\u662f\u5f53\u6570\u7ec4\u5df2\u6ee1\u65f6\u624d\u6267\u884c\uff0c\u56e0\u6b64\u53ef\u4ee5\u8ba4\u4e3a\u8fd9\u4e2a\u64cd\u4f5c\u7684\u644a\u8fd8\u65f6\u95f4\u662f\u5e38\u6570\u65f6\u95f4\uff0c\u5373O(1)\u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\uff1a\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u4f1a\u5360\u7528\u989d\u5916\u7684\u5185\u5b58\u7a7a\u95f4\uff0c\u4f46\u968f\u7740\u6570\u7ec4\u7684\u589e\u957f\uff0c\u989d\u5916\u5185\u5b58\u7684\u5360\u7528\u76f8\u5bf9\u4e8e\u6570\u7ec4\u672c\u8eab\u7684\u5927\u5c0f\u6765\u8bf4\u662f\u6709\u9650\u7684\u3002\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u8fd9\u79cd\u5360\u7528\u53ef\u4ee5\u63a5\u53d7\u3002 \u603b\u7ed3\uff0c\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u7684\u7b56\u7565\u53ef\u4ee5\u663e\u8457\u51cf\u5c11\u52a8\u6001\u6570\u7ec4\u7684\u6269\u5c55\u6b21\u6570\uff0c\u4ece\u800c\u63d0\u9ad8\u6027\u80fd\u3002\u867d\u7136\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u53ef\u80fd\u4f1a\u82b1\u8d39\u4e00\u4e9b\u65f6\u95f4\u548c\u989d\u5916\u5185\u5b58\uff0c\u4f46\u8fd9\u4e9b\u5f00\u9500\u5728\u4e00\u7cfb\u5217\u64cd\u4f5c\u4e2d\u88ab\u5e73\u644a\uff0c\u5e73\u5747\u4e0b\u6765\u662f\u5e38\u6570\u65f6\u95f4\u3002\u8fd9\u662f\u4e00\u79cd\u9ad8\u6548\u7684\u52a8\u6001\u6570\u7ec4\u5b9e\u73b0\u65b9\u5f0f\uff0c\u5e38\u89c1\u4e8e\u8bb8\u591a\u7f16\u7a0b\u8bed\u8a00\u7684\u6807\u51c6\u5e93\u4e2d\uff0c\u5305\u62ecPython\u7684\u5217\u8868\uff08list\uff09\u3002 \u5728\u589e\u52a0\u6570\u7ec4\u7684\u957f\u5ea6\u65f6\uff0c\u6bcf\u6b21\u589e\u52a0\u4e00\u4e2a\u5185\u5b58\u5355\u5143\uff0c\u4e0e\u6bcf\u6b21\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u65f6\u628a\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u76f8\u6bd4\uff0c\u540e\u8005\u7684\u65b9\u6cd5\u901a\u5e38\u66f4\u9ad8\u6548\u3002 \u6bcf\u6b21\u589e\u52a0\u4e00\u4e2a\u5185\u5b58\u5355\u5143\uff1a\u8fd9\u79cd\u65b9\u5f0f\u5728\u6bcf\u6b21\u6dfb\u52a0\u65b0\u5143\u7d20\u65f6\u90fd\u9700\u8981\u5206\u914d\u989d\u5916\u7684\u5185\u5b58\uff0c\u5bfc\u81f4\u6570\u7ec4\u5c3a\u5bf8\u7684\u589e\u957f\u662f\u7ebf\u6027\u7684\u3002\u5982\u679c\u9891\u7e41\u6dfb\u52a0\u5143\u7d20\uff0c\u8fd9\u5c06\u5bfc\u81f4\u5927\u91cf\u7684\u5185\u5b58\u5206\u914d\u548c\u6570\u636e\u590d\u5236\u64cd\u4f5c\uff0c\u56e0\u6b64\u65f6\u95f4\u590d\u6742\u5ea6\u4f1a\u53d8\u5f97\u76f8\u5bf9\u8f83\u9ad8\u3002 \u6bcf\u6b21\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u65f6\u628a\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\uff1a\u8fd9\u662f\u4e00\u79cd\u66f4\u9ad8\u6548\u7684\u7b56\u7565\u3002\u5728\u8fd9\u79cd\u65b9\u5f0f\u4e0b\uff0c\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u90fd\u4f1a\u589e\u52a0\u6570\u7ec4\u7684\u5c3a\u5bf8\uff0c\u4f46\u589e\u5e45\u662f\u6307\u6570\u7ea7\u7684\uff0c\u800c\u4e0d\u662f\u7ebf\u6027\u7684\u3002\u8fd9\u610f\u5473\u7740\u968f\u7740\u6570\u7ec4\u7684\u589e\u957f\uff0c\u6269\u5c55\u64cd\u4f5c\u7684\u9891\u7387\u4f1a\u51cf\u5c11\uff0c\u56e0\u4e3a\u6570\u7ec4\u80fd\u591f\u5bb9\u7eb3\u66f4\u591a\u5143\u7d20\u3002\u8fd9\u6837\uff0c\u867d\u7136\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u9700\u8981\u590d\u5236\u66f4\u591a\u7684\u5143\u7d20\uff0c\u4f46\u5b83\u4eec\u7684\u644a\u8fd8\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662f\u5e38\u6570\u65f6\u95f4\uff0c\u56e0\u4e3a\u5b83\u4eec\u4e0d\u662f\u6bcf\u6b21\u90fd\u6267\u884c\u7684\u3002 \u603b\u7ed3\uff0c\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u7684\u7b56\u7565\u901a\u5e38\u66f4\u9ad8\u6548\uff0c\u56e0\u4e3a\u5b83\u53ef\u4ee5\u51cf\u5c11\u9891\u7e41\u7684\u5185\u5b58\u5206\u914d\u548c\u590d\u5236\u64cd\u4f5c\uff0c\u964d\u4f4e\u4e86\u65f6\u95f4\u590d\u6742\u5ea6\u3002\u8fd9\u662f\u8bb8\u591a\u52a8\u6001\u6570\u7ec4\u5b9e\u73b0\u7684\u5e38\u89c1\u505a\u6cd5\uff0c\u5305\u62ecPython\u7684\u5217\u8868\uff08list\uff09\u3002","title":"4.2.1.\u589e\u5927\u6570\u7ec4\u7684\u5c3a\u5bf8"},{"location":"python/DataStructure/04_ArrayChain/#422","text":"\u5982\u679c\u51cf\u5c0f\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\uff0c\u5c31\u4f1a\u6d6a\u8d39\u76f8\u5e94\u7684\u5185\u5b58\u5355\u5143\u3002\u56e0\u6b64\uff0c\u5f53\u5220\u9664\u67d0\u4e00\u4e2a\u5143\u7d20\uff0c\u5982\u679c\u672a\u4f7f\u7528\u7684\u5185\u5b58\u5355\u5143\u6570\u8fbe\u5230\u6216\u8d85\u8fc7\u4e86\u67d0\u4e2a\u9608\u503c\uff08\u5982\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\u7684\u00be\uff09\u65f6\uff0c\u5219\u5e94\u8be5\u51cf\u5c0f\u7269\u7406\u5c3a\u5bf8\u4e86\u3002\u5982\u679c\u6d6a\u8d39\u7684\u5185\u5b58\u8d85\u8fc7\u7279\u5b9a\u9608\u503c\uff0c\u90a3\u4e48Python\u7684list\u7c7b\u578b\u4f1a\u5728\u8c03\u7528 pop \u65b9\u6cd5\u65f6\u6267\u884c\u51cf\u5c0f\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\u7684\u64cd\u4f5c\u3002 \u51cf\u5c0f\u6570\u7ec4\u5c3a\u5bf8\u7684\u8fc7\u7a0b\u4e0e\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u7684\u8fc7\u7a0b\u76f8\u53cd\uff0c\u6b65\u9aa4\u5982\u4e0b\uff1a \u521b\u5efa\u4e00\u4e2a\u66f4\u5c0f\u7684\u65b0\u6570\u7ec4\u3002 \u5c06\u6570\u636e\u4ece\u65e7\u6570\u7ec4\u4e2d\u590d\u5236\u5230\u65b0\u6570\u7ec4\u3002 \u5c06\u6307\u5411\u65e7\u6570\u7ec4\u7684\u53d8\u91cf\u6307\u5411\u65b0\u6570\u7ec4\u5bf9\u8c61\u3002 \u4e0b\u9762\u7684\u4ee3\u7801\u5b9e\u73b0\u4e86\u51cf\u5c0f\u6570\u7ec4\u5c3a\u5bf8\u3002 \u5f53\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u5c0f\u4e8e\u6216\u7b49\u4e8e\u5176\u7269\u7406\u5c3a\u5bf8\u7684\u00bc\uff0c\u5e76\u4e14\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u81f3\u5c11\u662f\u8fd9\u4e2a\u6570\u7ec4\u5efa\u7acb\u65f6\u9ed8\u8ba4\u5bb9\u91cf\u76842\u500d\u65f6\uff0c\u5219\u4e0b\u9762\u7684\u7b97\u6cd5\u628a\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u51cf\u5c0f\u5230\u539f\u6765\u7684\u4e00\u534a\uff0c\u5e76\u4e14\u4e5f\u4e0d\u4f1a\u5c0f\u4e8e\u5176\u9ed8\u8ba4\u5bb9\u91cf\u3002 def main ( size = 10 ): # \u521d\u59cb\u503c DEFAULT_CAPACITY = 5 logicalSize = 0 my_array = Array ( DEFAULT_CAPACITY ) # \u6253\u5370\u8f93\u51fa\u521d\u59cb\u6570\u7ec4\u4fe1\u606f print ( \"Initial array is: \" , my_array ) print ( \"Len of the array: \" , my_array . __len__ ()) # \u7ed9\u6570\u7ec4\u8d4b\u503c for i in range ( len ( my_array )): my_array [ i ] = i print ( \"The array is: \" , my_array . items ) # \u6253\u5370\u8f93\u51fa\u6570\u7ec4 # \u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 while logicalSize < DEFAULT_CAPACITY * 2 : logicalSize += 1 if logicalSize == len ( my_array ): # \u89e6\u53d1\u6761\u4ef6 temp = Array ( len ( my_array ) + 1 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 print ( \"The array after increased is: \" , my_array . items ) # \u6253\u5370\u8f93\u51fa\u6570\u7ec4 # \u51cf\u5c0f\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 while logicalSize > len ( my_array ) // 4 : logicalSize -= 1 if logicalSize <= len ( my_array ) // 4 and len ( my_array ) >= DEFAULT_CAPACITY * 2 : # \u89e6\u53d1\u6761\u4ef6 temp = Array ( len ( my_array ) // 2 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 print ( \"The array after decreased is: \" , my_array . items ) # \u6253\u5370\u8f93\u51fa\u6570\u7ec4 if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Initial array is: [None, None, None, None, None] # Len of the array: 5 # The array is: [0, 1, 2, 3, 4] # The array after increased is: [0, 1, 2, 3, 4, None, None, None, None, None, None] # The array after decreased is: [0, 1, None, None, None] \u6309\u7167\u4e0a\u9762\u7b97\u6cd5\u51cf\u5c11\u6570\u7ec4\u7684\u5c3a\u5bf8\uff0c\u6211\u4eec\u53ef\u4ee5\u5206\u6790\u5176\u65f6\u95f4\u548c\u7a7a\u95f4\u590d\u6742\u5ea6\u5982\u4e0b\uff1a \u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u4e3b\u8981\u6d89\u53ca\u4e24\u4e2a\u64cd\u4f5c\uff1a \u521b\u5efa\u65b0\u6570\u7ec4\u5e76\u5c06\u5143\u7d20\u4ece\u65e7\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\uff1b \u5c06\u65e7\u6570\u7ec4\u5f15\u7528\u66f4\u6539\u4e3a\u65b0\u6570\u7ec4\u3002 \u590d\u5236\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\uff0c\u53ef\u4ee5\u8868\u793a\u4e3a O(n) \uff0c\u5176\u4e2d n \u662f\u6570\u7ec4\u7684\u5f53\u524d\u7269\u7406\u5c3a\u5bf8\u3002\u5f15\u7528\u66f4\u6539\u662f\u4e00\u4e2a\u5e38\u6570\u65f6\u95f4\u64cd\u4f5c\uff0c\u4e0d\u5f71\u54cd\u65f6\u95f4\u590d\u6742\u5ea6\u3002\u6240\u4ee5\uff0c\u6574\u4f53\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\uff1a\u7a7a\u95f4\u590d\u6742\u5ea6\u4e5f\u6d89\u53ca\u4e24\u4e2a\u65b9\u9762\uff1a \u521b\u5efa\u65b0\u6570\u7ec4\u7684\u5185\u5b58\u6d88\u8017\uff0c\u5176\u7a7a\u95f4\u590d\u6742\u5ea6\u662fO(N)\uff1b \u5f15\u7528\u66f4\u6539\u6240\u9700\u7684\u5e38\u6570\u989d\u5916\u7a7a\u95f4\uff0c\u901a\u5e38\u5ffd\u7565\u4e0d\u8ba1\u3002 \u6240\u4ee5\uff0c\u603b\u7684\u7a7a\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002 \u8fd9\u4e2a\u7b97\u6cd5\u7b56\u7565\u4f1a\u5728\u9002\u5f53\u7684\u65f6\u5019\u51cf\u5c0f\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\uff0c\u4ee5\u51cf\u5c11\u5185\u5b58\u5360\u7528\uff0c\u4f46\u4ecd\u7136\u4fdd\u6301\u7740\u6570\u7ec4\u7684\u52a8\u6001\u6027\u3002\u65f6\u95f4\u590d\u6742\u5ea6\u548c\u7a7a\u95f4\u590d\u6742\u5ea6\u90fd\u4e0e\u5f53\u524d\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u6210\u7ebf\u6027\u5173\u7cfb\uff0c\u56e0\u6b64\u662f\u7ebf\u6027\u7684\uff0c\u8fd9\u662f\u4e00\u79cd\u6709\u6548\u7684\u7b56\u7565\u6765\u4f18\u5316\u5185\u5b58\u4f7f\u7528\u3002\u540c\u65f6\uff0c\u4fdd\u7559\u4e86\u4e00\u5b9a\u7684\u5197\u4f59\u7a7a\u95f4\uff0c\u4ee5\u907f\u514d\u9891\u7e41\u5730\u6269\u5c55\u548c\u7f29\u5c0f\u6570\u7ec4\uff0c\u4ece\u800c\u63d0\u9ad8\u4e86\u6027\u80fd\u3002","title":"4.2.2.\u51cf\u5c0f\u6570\u7ec4\u7684\u5c3a\u5bf8"},{"location":"python/DataStructure/04_ArrayChain/#423","text":"","title":"4.2.3.\u5c06\u5143\u7d20\u63d2\u5165\u589e\u5927\u7684\u6570\u7ec4"},{"location":"python/DataStructure/04_ArrayChain/#424","text":"","title":"4.2.4.\u4ece\u6570\u7ec4\u91cc\u5220\u9664\u5143\u7d20"},{"location":"python/DataStructure/04_ArrayChain/#425","text":"","title":"4.2.5.\u590d\u6742\u5ea6\u7684\u6743\u8861\uff1a\u65f6\u95f4\u3001\u7a7a\u95f4\u548c\u6570\u7ec4"},{"location":"python/DataStructure/04_ArrayChain/#426","text":"1\uff0e\u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u63d2\u5165\u6216\u5220\u9664\u7ed9\u5b9a\u5143\u7d20\u65f6\u5fc5\u987b\u8981\u79fb\u52a8\u6570\u7ec4\u91cc\u7684\u67d0\u4e9b\u5143\u7d20\u3002 2\uff0e\u5728\u63d2\u5165\u8fc7\u7a0b\u4e2d\uff0c\u79fb\u52a8\u6570\u7ec4\u5143\u7d20\u65f6\uff0c\u8981\u5148\u79fb\u52a8\u54ea\u4e2a\u5143\u7d20\uff1f\u5148\u79fb\u52a8\u63d2\u5165\u4f4d\u7f6e\u7684\u5143\u7d20\uff0c\u8fd8\u662f\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff1f\u4e3a\u4ec0\u4e48\uff1f 3\uff0e\u5982\u679c\u63d2\u5165\u4f4d\u7f6e\u662f\u6570\u7ec4\u7684\u903b\u8f91\u672b\u5c3e\uff0c\u8bf7\u8bf4\u660e\u8fd9\u4e2a\u63d2\u5165\u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u590d\u6742\u5ea6\u3002 4\uff0e\u5047\u8bbe\u6570\u7ec4\u5f53\u524d\u5305\u542b14\u4e2a\u5143\u7d20\uff0c\u5b83\u7684\u8d1f\u8f7d\u56e0\u5b50\u4e3a0.70\uff0c\u90a3\u4e48\u5b83\u7684\u7269\u7406\u5bb9\u91cf\u662f\u591a\u5c11\uff1f","title":"4.2.6.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#43","text":"","title":"4.3.\u4e8c\u7ef4\u6570\u7ec4\uff08\u7f51\u683c\uff09"},{"location":"python/DataStructure/04_ArrayChain/#431","text":"","title":"4.3.1.\u4f7f\u7528\u7f51\u683c"},{"location":"python/DataStructure/04_ArrayChain/#432","text":"","title":"4.3.2.\u521b\u5efa\u5e76\u521d\u59cb\u5316\u7f51\u683c"},{"location":"python/DataStructure/04_ArrayChain/#433grid","text":"","title":"4.3.3.\u5b9a\u4e49Grid\u7c7b"},{"location":"python/DataStructure/04_ArrayChain/#434","text":"","title":"4.3.4.\u53c2\u5dee\u4e0d\u9f50\u7684\u7f51\u683c\u548c\u591a\u7ef4\u6570\u7ec4"},{"location":"python/DataStructure/04_ArrayChain/#435","text":"1\uff0e\u4ec0\u4e48\u662f\u4e8c\u7ef4\u6570\u7ec4\uff08\u7f51\u683c\uff09\uff1f 2\uff0e\u8bf7\u63cf\u8ff0\u4e00\u4e2a\u53ef\u80fd\u4f1a\u7528\u5230\u4e8c\u7ef4\u6570\u7ec4\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 3\uff0e\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u4f7f\u4e4b\u53ef\u4ee5\u5728Grid\u5bf9\u8c61\u91cc\u641c\u7d22\u4e00\u4e2a\u8d1f\u6574\u6570\u3002\u5faa\u73af\u5e94\u8be5\u5728\u9047\u5230\u7f51\u683c\u91cc\u7684\u7b2c\u4e00\u4e2a\u8d1f\u6574\u6570\u7684\u5730\u65b9\u7ec8\u6b62\uff0c\u8fd9\u65f6\u53d8\u91cfrow\u548ccolumn\u5e94\u8be5\u88ab\u8bbe\u7f6e\u4e3a\u8fd9\u4e2a\u8d1f\u6570\u7684\u4f4d\u7f6e\u3002\u5982\u679c\u5728\u7f51\u683c\u91cc\u627e\u4e0d\u5230\u8d1f\u6570\uff0c\u90a3\u4e48\u53d8\u91cfrow\u548ccolumn\u5e94\u8be5\u7b49\u4e8e\u7f51\u683c\u7684\u884c\u6570\u548c\u5217\u6570\u3002 4\uff0e\u8bf4\u8bf4\u8fd0\u884c\u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u540e\u7f51\u683c\u91cc\u7684\u5185\u5bb9\u662f\u4ec0\u4e48\u3002 matrix = Grid ( 3 , 3 ) for row in range ( matrix . getHeight ()): for column in range ( matrix . getWidth ()): matrix [ row ][ column ] = row * column 5\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\u4ee5\u521b\u5efa\u4e00\u4e2a\u53c2\u5dee\u4e0d\u9f50\u7684\u7f51\u683c\uff0c\u5b83\u7684\u884c\u5206\u522b\u7528\u6765\u5b58\u50a83\u4e2a\u30016\u4e2a\u548c9\u4e2a\u5143\u7d20\u3002 6\uff0e\u63d0\u4f9b\u4e00\u4e2a\u628aGrid\u7c7b\u7528\u4f5c\u6570\u636e\u7ed3\u6784\u6765\u5b9e\u73b0\u4e09\u7ef4array\u7c7b\u7684\u7b56\u7565\u3002 7\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\uff1a\u8fd9\u6bb5\u4ee3\u7801\u4f1a\u628a\u4e09\u7ef4\u6570\u7ec4\u91cc\u6bcf\u4e2a\u5355\u5143\u7684\u503c\u90fd\u521d\u59cb\u5316\u4e3a\u5b83\u76843\u4e2a\u7d22\u5f15\u4f4d\u7f6e\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4f4d\u7f6e\u662f\uff08\u6df1\u5ea6\u3001\u884c\u3001\u5217\uff09\uff0c\u5219\u5bf9\u4e8e\u4f4d\u7f6e\uff082\u30013\u30013\uff09\u6765\u8bf4\uff0c\u5b83\u7684\u503c\u5c31\u662f233\u3002 8\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\uff1a\u8fd9\u6bb5\u4ee3\u7801\u53ef\u4ee5\u663e\u793a\u51fa\u4e09\u7ef4\u6570\u7ec4\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u6253\u5370\u51fa\u7684\u6bcf\u4e00\u884c\u6570\u636e\u90fd\u5e94\u8be5\u4ee3\u8868\u7ed9\u5b9a\u884c\u548c\u5217\u91cc\u7684\u6240\u6709\u5143\u7d20\uff0c\u800c\u6df1\u5ea6\u5c06\u4ece\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u5411\u540e\u9012\u5f52\u5230\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u3002\u904d\u5386\u5e94\u8be5\u4ece\u7b2c1\u884c\u3001\u7b2c1\u5217\u4ee5\u53ca\u7b2c\u4e00\u4e2a\u6df1\u5ea6\u4f4d\u7f6e\u5f00\u59cb\uff0c\u4f9d\u6b21\u904d\u5386\u6240\u6709\u7684\u6df1\u5ea6\u3001\u5217\u548c\u884c\u3002","title":"4.3.5.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#44","text":"","title":"4.4.\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#441","text":"","title":"4.4.1.\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u548c\u53cc\u5411\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#442","text":"","title":"4.4.2.\u975e\u8fde\u7eed\u5185\u5b58\u548c\u8282\u70b9"},{"location":"python/DataStructure/04_ArrayChain/#443","text":"","title":"4.4.3.\u5b9a\u4e49\u5355\u5411\u94fe\u63a5\u8282\u70b9\u7c7b"},{"location":"python/DataStructure/04_ArrayChain/#444","text":"","title":"4.4.4.\u4f7f\u7528\u5355\u5411\u94fe\u63a5\u8282\u70b9\u7c7b"},{"location":"python/DataStructure/04_ArrayChain/#445","text":"1\uff0e\u7528\u6846\u548c\u6307\u9488\u7ed8\u5236\u6d4b\u8bd5\u7a0b\u5e8f\u91cc\u7b2c\u4e00\u4e2a\u5faa\u73af\u6240\u521b\u5efa\u7684\u8282\u70b9\u7684\u793a\u610f\u56fe\u3002 2\uff0e\u5f53\u8282\u70b9\u53d8\u91cf\u5f15\u7528\u7684\u662fNone\u65f6\uff0c\u5982\u679c\u7a0b\u5e8f\u5458\u5c1d\u8bd5\u8bbf\u95ee\u8282\u70b9\u7684\u6570\u636e\u5b57\u6bb5\uff0c\u5219\u4f1a\u53d1\u751f\u4ec0\u4e48\uff1f\u5982\u4f55\u9632\u6b62\u8fd9\u79cd\u60c5\u51b5\u7684\u53d1\u751f\uff1f 3\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\uff1a\u8fd9\u6bb5\u4ee3\u7801\u4f1a\u628a\u4e00\u4e2a\u88ab\u586b\u6ee1\u7684\u6570\u7ec4\u91cc\u7684\u5143\u7d20\u90fd\u8f6c\u79fb\u4e3a\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u6570\u636e\u3002\u8fd9\u4e2a\u64cd\u4f5c\u5e94\u4fdd\u7559\u5143\u7d20\u7684\u987a\u5e8f\u4e0d\u53d8\u3002","title":"4.4.5.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#45","text":"","title":"4.5.\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4e0a\u7684\u64cd\u4f5c"},{"location":"python/DataStructure/04_ArrayChain/#451","text":"","title":"4.5.1.\u904d\u5386"},{"location":"python/DataStructure/04_ArrayChain/#452","text":"","title":"4.5.2.\u641c\u7d22"},{"location":"python/DataStructure/04_ArrayChain/#453","text":"","title":"4.5.3.\u66ff\u6362"},{"location":"python/DataStructure/04_ArrayChain/#454","text":"","title":"4.5.4.\u5728\u5f00\u59cb\u5904\u63d2\u5165"},{"location":"python/DataStructure/04_ArrayChain/#455","text":"","title":"4.5.5.\u5728\u7ed3\u5c3e\u5904\u63d2\u5165"},{"location":"python/DataStructure/04_ArrayChain/#456","text":"","title":"4.5.6.\u5728\u5f00\u59cb\u5904\u5220\u9664"},{"location":"python/DataStructure/04_ArrayChain/#457","text":"","title":"4.5.7.\u5728\u7ed3\u5c3e\u5904\u5220\u9664"},{"location":"python/DataStructure/04_ArrayChain/#458","text":"","title":"4.5.8.\u5728\u4efb\u610f\u4f4d\u7f6e\u5904\u63d2\u5165"},{"location":"python/DataStructure/04_ArrayChain/#459","text":"","title":"4.5.9.\u5728\u4efb\u610f\u4f4d\u7f6e\u5904\u5220\u9664"},{"location":"python/DataStructure/04_ArrayChain/#4510","text":"","title":"4.5.10.\u590d\u6742\u5ea6\u7684\u6743\u8861\uff1a\u65f6\u95f4\u3001\u7a7a\u95f4\u548c\u5355\u5411\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#4511","text":"1\uff0e\u5047\u8bbe\u5df2\u7ecf\u627e\u5230\u4e86\u4ece\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u5220\u9664\u5143\u7d20\u7684\u4f4d\u7f6e\uff0c\u8bf7\u8bf4\u660e\u4ece\u8fd9\u4e2a\u65f6\u5019\u5f00\u59cb\u5b8c\u6210\u5220\u9664\u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u590d\u6742\u5ea6\u3002 2\uff0e\u53ef\u4ee5\u5bf9\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u6309\u987a\u5e8f\u6392\u5217\u7684\u5143\u7d20\u6267\u884c\u4e8c\u5206\u641c\u7d22\u5417\uff1f\u5982\u679c\u4e0d\u53ef\u4ee5\uff0c\u4e3a\u4ec0\u4e48\uff1f 3\uff0e\u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48Python\u5217\u8868\u4f1a\u4f7f\u7528\u6570\u7ec4\u800c\u4e0d\u662f\u94fe\u63a5\u7ed3\u6784\u6765\u4fdd\u5b58\u5b83\u7684\u5143\u7d20\u3002","title":"4.5.11.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#46","text":"","title":"4.6.\u94fe\u63a5\u4e0a\u7684\u53d8\u5316"},{"location":"python/DataStructure/04_ArrayChain/#461","text":"","title":"4.6.1.\u5305\u542b\u865a\u62df\u5934\u8282\u70b9\u7684\u73af\u72b6\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#462","text":"","title":"4.6.2.\u53cc\u5411\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#463","text":"1\uff0e\u5305\u542b\u865a\u62df\u5934\u8282\u70b9\u7684\u73af\u72b6\u94fe\u63a5\u7ed3\u6784\u7ed9\u7a0b\u5e8f\u5458\u5e26\u6765\u4e86\u4ec0\u4e48\u597d\u5904\uff1f 2\uff0e\u548c\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u76f8\u6bd4\uff0c\u8bf7\u63cf\u8ff0\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u4e00\u4e2a\u597d\u5904\u548c\u4e00\u4e2a\u989d\u5916\u5f00\u9500\u3002","title":"4.6.3.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#47","text":"\u6570\u636e\u7ed3\u6784\u662f\u4e00\u4e2a\u8868\u793a\u591a\u9879\u96c6\u91cc\u6240\u5305\u542b\u6570\u636e\u7684\u5bf9\u8c61\u3002 \u6570\u7ec4\u662f\u4e00\u79cd\u5728\u5e38\u6570\u65f6\u95f4\u5185\u652f\u6301\u5bf9\u4f4d\u7f6e\u9010\u9879\u968f\u673a\u8bbf\u95ee\u7684\u6570\u636e\u7ed3\u6784\u3002\u5728\u521b\u5efa\u6570\u7ec4\u65f6\uff0c\u4f1a\u4e3a\u5b83\u5206\u914d\u82e5\u5e72\u4e2a\u7528\u6765\u5b58\u653e\u6570\u636e\u7684\u5185\u5b58\u7a7a\u95f4\uff0c\u5e76\u4e14\u6570\u7ec4\u7684\u957f\u5ea6\u4f1a\u4fdd\u6301\u4e0d\u53d8\u3002\u63d2\u5165\u548c\u5220\u9664\u64cd\u4f5c\u9700\u8981\u79fb\u52a8\u6570\u636e\u5143\u7d20\uff0c\u5e76\u4e14\u53ef\u80fd\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u3001\u66f4\u5927\u6216\u66f4\u5c0f\u7684\u6570\u7ec4\u3002 \u4e8c\u7ef4\u6570\u7ec4\u91cc\u7684\u6bcf\u4e2a\u6570\u636e\u503c\u90fd\u4f4d\u4e8e\u77e9\u5f62\u7f51\u683c\u7684\u884c\u548c\u5217\u4e0a\u3002 \u94fe\u63a5\u7ed3\u6784\u662f\u75310\u4e2a\u6216\u591a\u4e2a\u8282\u70b9\u7ec4\u6210\u7684\u6570\u636e\u7ed3\u6784\u3002\u6bcf\u4e2a\u8282\u70b9\u90fd\u5305\u542b\u4e00\u4e2a\u6570\u636e\u5143\u7d20\u548c\u4e00\u4e2a\u6216\u591a\u4e2a\u6307\u5411\u5176\u4ed6\u8282\u70b9\u7684\u94fe\u63a5\u3002 \u5355\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u8282\u70b9\u5305\u542b\u6570\u636e\u5143\u7d20\u548c\u5230\u4e0b\u4e00\u4e2a\u8282\u70b9\u7684\u94fe\u63a5\u3002\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u8282\u70b9\u8fd8\u5305\u542b\u5230\u524d\u4e00\u4e2a\u8282\u70b9\u7684\u94fe\u63a5\u3002 \u5728\u94fe\u63a5\u7ed3\u6784\u91cc\u8fdb\u884c\u63d2\u5165\u6216\u5220\u9664\u64cd\u4f5c\u4e0d\u9700\u8981\u79fb\u52a8\u6570\u636e\u5143\u7d20\uff0c\u6bcf\u6b21\u6700\u591a\u53ea\u4f1a\u521b\u5efa\u4e00\u4e2a\u8282\u70b9\u3002\u4f46\u662f\uff0c\u5728\u94fe\u63a5\u7ed3\u6784\u91cc\u6267\u884c\u63d2\u5165\u3001\u5220\u9664\u548c\u8bbf\u95ee\u64cd\u4f5c\u9700\u8981\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662f\u7ebf\u6027\u7684\u3002 \u5728\u94fe\u63a5\u7ed3\u6784\u91cc\u4f7f\u7528\u5934\u8282\u70b9\u53ef\u4ee5\u7b80\u5316\u67d0\u4e9b\u64cd\u4f5c\uff0c\u5982\u6dfb\u52a0\u6216\u5220\u9664\u5143\u7d20\u3002","title":"4.7.\u5c0f\u7ed3"},{"location":"python/DataStructure/04_ArrayChain/#48","text":"1\uff0e\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784\u90fd\u662f\uff1a \u62bd\u8c61\u6570\u636e\u7c7b\u578b\uff08ADT\uff09 \u6570\u636e\u7ed3\u6784 2\uff0e\u6570\u7ec4\u7684\u957f\u5ea6\uff1a \u5728\u521b\u5efa\u4e4b\u540e\u5927\u5c0f\u662f\u56fa\u5b9a\u7684 \u5728\u521b\u5efa\u4e4b\u540e\u5927\u5c0f\u53ef\u4ee5\u589e\u52a0\u6216\u51cf\u5c11 3\uff0e\u5728\u6570\u7ec4\u91cc\u8fdb\u884c\u968f\u673a\u8bbf\u95ee\u652f\u6301\u5728\uff1a \u5e38\u6570\u65f6\u95f4\u91cc\u8bbf\u95ee\u6570\u636e \u7ebf\u6027\u65f6\u95f4\u91cc\u8bbf\u95ee\u6570\u636e 4\uff0e\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u6570\u636e\u5305\u542b\u5728\uff1a \u5355\u5143\u91cc \u8282\u70b9\u91cc 5\uff0e\u5bf9\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u6267\u884c\u7684\u5927\u591a\u6570\u64cd\u4f5c\u90fd\u9700\u8981\uff1a \u5e38\u6570\u65f6\u95f4 \u7ebf\u6027\u65f6\u95f4 6\uff0e\u4ece\u4ee5\u4e0b\u54ea\u79cd\u7c7b\u578b\u91cc\u5220\u9664\u7b2c\u4e00\u4e2a\u5143\u7d20\u9700\u8981\u5e38\u6570\u65f6\u95f4\uff1a \u6570\u7ec4 \u5355\u5411\u94fe\u63a5\u7ed3\u6784 7\uff0e\u5728\u4e0b\u9762\u54ea\u79cd\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u91cc\u4f7f\u7528\u7684\u5185\u5b58\u4f1a\u5c11\u4e8e\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u7684\uff1a \u4e0d\u5230\u4e00\u534a\u7684\u4f4d\u7f6e\u653e\u7f6e\u4e86\u6570\u636e \u4e00\u534a\u4ee5\u4e0a\u7684\u4f4d\u7f6e\u653e\u7f6e\u4e86\u6570\u636e 8\uff0e\u5f53\u6570\u7ec4\u7684\u5185\u5b58\u4e0d\u8db3\u4ee5\u4fdd\u5b58\u6570\u636e\u65f6\uff0c\u6700\u597d\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u6570\u7ec4\uff0c\u8fd9\u4e2a\u65b0\u6570\u7ec4\u5e94\u8be5\uff1a \u5927\u5c0f\u6bd4\u65e7\u6570\u7ec4\u591a1\u4e2a\u4f4d\u7f6e \u5927\u5c0f\u662f\u65e7\u6570\u7ec4\u76842\u500d 9\uff0e\u5bf9\u4e8e\u5355\u5411\u94fe\u63a5\u7ed3\u6784\uff0c\u5f53\u4f60\u5728\u4ec0\u4e48\u5730\u65b9\u6267\u884c\u63d2\u5165\u64cd\u4f5c\u4f1a\u5f97\u5230\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u8fd0\u884c\u65f6\uff1a \u5728\u7ed3\u6784\u7684\u5f00\u5934 \u5728\u7ed3\u6784\u7684\u672b\u5c3e 10\uff0e\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u8ba9\u7a0b\u5e8f\u5458\u53ef\u4ee5\u79fb\u52a8\u5230\uff1a \u7ed9\u5b9a\u8282\u70b9\u7684\u540e\u4e00\u4e2a\u8282\u70b9\u6216\u524d\u4e00\u4e2a\u8282\u70b9 \u7ed9\u5b9a\u8282\u70b9\u7684\u540e\u4e00\u4e2a\u8282\u70b9","title":"4.8.\u590d\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#49","text":"\u5728\u524d6\u4e2a\u9879\u76ee\u91cc\uff0c\u4f60\u5c06\u4fee\u6539\u5728\u672c\u7ae0\u5b9a\u4e49\u7684Array\u7c7b\uff0c\u4ece\u800c\u8ba9\u5b83\u66f4\u50cfPython\u7684list\u7c7b\u3002\u5bf9\u4e8e\u8fd9\u4e9b\u9879\u76ee\u7684\u7b54\u6848\uff0c\u8bf7\u5305\u542b\u4f60\u5bf9Array\u7c7b\u6240\u505a\u4fee\u6539\u7684\u4ee3\u7801\u6d4b\u8bd5\u3002 1\uff0e\u4e3aArray\u7c7b\u6dfb\u52a0\u4e00\u4e2a\u5b9e\u4f8b\u53d8\u91cf logicalSize \u3002\u8fd9\u4e2a\u53d8\u91cf\u7684\u521d\u59cb\u503c\u4e3a 0 \uff0c\u7528\u6765\u8bb0\u5f55\u6570\u7ec4\u91cc\u5f53\u524d\u5df2\u7ecf\u5305\u542b\u7684\u5143\u7d20\u6570\u91cf\u3002\u7136\u540e\u4e3aArray\u7c7b\u6dfb\u52a0 size() \u65b9\u6cd5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u7528\u6765\u8fd4\u56de\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u3002 __len__ \u65b9\u6cd5\u4f9d\u7136\u4f1a\u8fd4\u56de\u6570\u7ec4\u7684\u5bb9\u91cf\uff0c\u4e5f\u5c31\u662f\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u3002 2\uff0e\u4e3aArray\u7c7b\u7684 __getitem__ \u548c_ _setitem__ \u65b9\u6cd5\u6dfb\u52a0\u5148\u9a8c\u6761\u4ef6\u3002\u5b83\u4eec\u7684\u5148\u9a8c\u6761\u4ef6\u662f 0<=index < size() \u3002\u5982\u679c\u4e0d\u6ee1\u8db3\u5148\u9a8c\u6761\u4ef6\uff0c\u5c31\u5f15\u53d1\u5f02\u5e38\u3002 3\uff0e\u5c06 grow \u548c shrink \u65b9\u6cd5\u6dfb\u52a0\u5230Array\u7c7b\u3002\u5b83\u4eec\u80fd\u591f\u57fa\u4e8e\u672c\u7ae0\u6240\u8ba8\u8bba\u7684\u7b56\u7565\u6765\u589e\u52a0\u6216\u51cf\u5c11\u6570\u7ec4\u91cc\u6240\u5305\u542b\u7684\u5217\u8868\u957f\u5ea6\u3002\u5728\u5b9e\u73b0\u65f6\uff0c\u8981\u4fdd\u8bc1\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u4e0d\u4f1a\u7f29\u5c0f\u5230\u7528\u6237\u6307\u5b9a\u7684\u5bb9\u91cf\u4e4b\u4e0b\uff0c\u5e76\u4e14\u5728\u589e\u52a0\u6570\u7ec4\u5c3a\u5bf8\u65f6\uff0c\u6570\u7ec4\u7684\u5185\u5b58\u5355\u5143\u5c06\u4f1a\u7528\u9ed8\u8ba4\u503c\u6765\u586b\u5145\u3002 4\uff0e\u5c06\u65b9\u6cd5 insert \u548c pop \u6dfb\u52a0\u5230Array\u7c7b\u4e2d\u3002\u5b83\u4eec\u57fa\u4e8e\u672c\u7ae0\u5df2\u7ecf\u8ba8\u8bba\u8fc7\u7684\u7b56\u7565\uff0c\u5728\u9700\u8981\u7684\u65f6\u5019\u5bf9\u6570\u7ec4\u7684\u957f\u5ea6\u8fdb\u884c\u8c03\u6574\u3002 insert \u65b9\u6cd5\u4f1a\u63a5\u6536\u4e00\u4e2a\u4f4d\u7f6e\u548c\u4e00\u4e2a\u5143\u7d20\u503c\u4f5c\u4e3a\u53c2\u6570\uff0c\u7136\u540e\u628a\u8fd9\u4e2a\u5143\u7d20\u63d2\u5165\u6307\u5b9a\u7684\u4f4d\u7f6e\u3002\u5982\u679c\u4f4d\u7f6e\u5927\u4e8e\u6216\u7b49\u4e8e\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u628a\u5143\u7d20\u63d2\u5165\u6570\u7ec4\u91cc\u5f53\u524d\u53ef\u83b7\u5f97\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u4e4b\u540e\u3002 pop \u65b9\u6cd5\u4f1a\u63a5\u6536\u4e00\u4e2a\u4f4d\u7f6e\u4f5c\u4e3a\u53c2\u6570\uff0c\u7136\u540e\u5220\u9664\u5e76\u8fd4\u56de\u8fd9\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u3002 pop \u65b9\u6cd5\u7684\u5148\u9a8c\u6761\u4ef6\u662f 0<=index < size() \u3002 pop \u65b9\u6cd5\u8fd8\u5e94\u8be5\u628a\u817e\u51fa\u6765\u7684\u6570\u7ec4\u5185\u5b58\u5355\u5143\u91cd\u7f6e\u4e3a\u586b\u5145\u503c\u3002 5\uff0e\u5c06\u65b9\u6cd5 __eq__ \u6dfb\u52a0\u5230Array\u7c7b\u4e2d\u3002\u5f53Array\u5bf9\u8c61\u4f5c\u4e3a == \u8fd0\u7b97\u7b26\u7684\u5de6\u64cd\u4f5c\u6570\u65f6\uff0cPython\u4f1a\u8fd0\u884c\u8fd9\u4e2a\u65b9\u6cd5\u3002\u5982\u679c\u8fd9\u4e2a\u65b9\u6cd5\u7684\u53c2\u6570\u4e5f\u662f\u4e00\u4e2aArray\u5bf9\u8c61\uff0c\u5e76\u4e14\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\u548c\u5de6\u64cd\u4f5c\u6570\u76f8\u540c\uff0c\u4e14\u5728\u4e24\u4e2a\u6570\u7ec4\u91cc\u6bcf\u4e2a\u903b\u8f91\u4f4d\u7f6e\u4e0a\u7684\u5143\u7d20\u90fd\u76f8\u7b49\uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u8fd4\u56de True \uff1b\u5426\u5219\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u8fd4\u56de False \u3002 6\uff0e\u4e3a\u4e86\u8ba9Array\u7c7b\u548c\u5217\u8868\u4e00\u6837\uff0c\u5e94\u8be5\u5220\u9664 __iter__ \u65b9\u6cd5\u7684\u5f53\u524d\u5b9e\u73b0\u3002\u8bf7\u89e3\u91ca\u8fd9\u4e3a\u4ec0\u4e48\u662f\u4e00\u4e2a\u597d\u5efa\u8bae\uff0c\u5e76\u8bf4\u660e\u5728\u8fd9\u4e2a\u60c5\u51b5\u4e0b\u5e94\u8be5\u5982\u4f55\u5bf9 __str__ \u65b9\u6cd5\u8fdb\u884c\u4fee\u6539\u3002 7\uff0e Matrix \u7c7b\u53ef\u4ee5\u6267\u884c\u7ebf\u6027\u4ee3\u6570\u91cc\u7684\u67d0\u4e9b\u8fd0\u7b97\uff0c\u6bd4\u5982\u77e9\u9635\u8fd0\u7b97\u3002\u5f00\u53d1\u4e00\u4e2a\u4f7f\u7528\u5185\u7f6e\u8fd0\u7b97\u7b26\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97\u7684 Matrix \u7c7b\uff0c\u8fd9\u4e2a Matrix \u7c7b\u5e94\u6269\u5c55\u81ea Grid \u7c7b\u3002\u5728\u63a5\u4e0b\u6765\u76844\u4e2a\u9879\u76ee\u91cc\uff0c\u4f60\u5e94\u5b9a\u4e49\u4e00\u4e9b\u7528\u6765\u64cd\u4f5c\u94fe\u63a5\u7ed3\u6784\u7684\u51fd\u6570\u3002\u5728\u89e3\u7b54\u7684\u8fc7\u7a0b\u4e2d\uff0c\u4f60\u5e94\u8be5\u7ee7\u7eed\u4f7f\u7528\u672c\u7ae0\u5b9a\u4e49\u7684 Node \u548c TwoWayNode \u7c7b\u3002\u521b\u5efa\u4e00\u4e2a\u6d4b\u8bd5\u6a21\u5757\u4ee5\u5305\u542b\u4f60\u7684\u51fd\u6570\u5b9a\u4e49\u548c\u7528\u6765\u6d4b\u8bd5\u5b83\u4eec\u7684\u4ee3\u7801\u3002 8\uff0e\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c length \u7684\u51fd\u6570\uff08\u4e0d\u662f len \uff09\uff0c\u8fd9\u4e2a\u51fd\u6570\u4f1a\u63a5\u53d7\u4e00\u4e2a\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u80fd\u591f\u8fd4\u56de\u7ed3\u6784\u91cc\u7684\u5143\u7d20\u6570\u91cf\u3002 9\uff0e\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c insert \u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u5177\u6709\u628a\u5143\u7d20\u63d2\u5165\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4e2d\u6307\u5b9a\u4f4d\u7f6e\u7684\u529f\u80fd\u3002\u8fd9\u4e2a\u51fd\u6570\u67093\u4e2a\u53c2\u6570\uff1a\u5143\u7d20\u3001\u4f4d\u7f6e\u4ee5\u53ca\u4e00\u4e2a\u94fe\u63a5\u7ed3\u6784\uff08\u8fd9\u4e2a\u94fe\u63a5\u7ed3\u6784\u53ef\u80fd\u4e3a\u7a7a\uff09\u3002\u8fd9\u4e2a\u51fd\u6570\u80fd\u591f\u8fd4\u56de\u4fee\u6539\u4e4b\u540e\u7684\u94fe\u63a5\u7ed3\u6784\u3002\u5982\u679c\u4f20\u9012\u7684\u4f4d\u7f6e\u5927\u4e8e\u6216\u7b49\u4e8e\u94fe\u63a5\u7ed3\u6784\u7684\u957f\u5ea6\uff0c\u90a3\u4e48\u8fd9\u4e2a\u51fd\u6570\u4f1a\u628a\u5143\u7d20\u63d2\u5165\u5b83\u7684\u672b\u5c3e\u3002\u8fd9\u4e2a\u51fd\u6570\u7684\u8c03\u7528\u793a\u4f8b\u662f head =insert(1,data,head) \uff0c\u5176\u4e2d head \u662f\u4e00\u4e2a\u53d8\u91cf\uff0c\u8fd9\u4e2a\u53d8\u91cf\u8981\u4e48\u4e3a\u7a7a\u94fe\u63a5\uff0c\u8981\u4e48\u6307\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u7b2c\u4e00\u4e2a\u8282\u70b9\u3002 10\uff0e\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c pop \u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u80fd\u591f\u5728\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u6307\u5b9a\u4f4d\u7f6e\u4e0a\u5220\u9664\u5143\u7d20\u3002\u8fd9\u4e2a\u51fd\u6570\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u4f4d\u7f6e\uff0c\u5b83\u7684\u5148\u9a8c\u6761\u4ef6\u662f 0<=position<\u7ed3\u6784\u7684\u957f\u5ea6 \u3002\u5b83\u7684\u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u4e00\u4e2a\u94fe\u63a5\u7ed3\u6784\uff0c\u5f88\u660e\u663e\u5b83\u4e0d\u5e94\u8be5\u4e3a\u7a7a\u3002\u8fd9\u4e2a\u51fd\u6570\u5c06\u4f1a\u8fd4\u56de\u4e00\u4e2a\u5143\u7ec4\uff0c\u5305\u542b\u4fee\u6539\u540e\u7684\u94fe\u63a5\u7ed3\u6784\u548c\u5220\u9664\u7684\u5143\u7d20\u3002\u5b83\u7684\u8c03\u7528\u793a\u4f8b\u662f (head, item) = pop(1,head) \u3002 11\uff0e\u5b9a\u4e49\u4e00\u4e2a\u51fd\u6570 makeTwoWay \uff0c\u8fd9\u4e2a\u51fd\u6570\u4f1a\u63a5\u53d7\u4e00\u4e2a\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4f5c\u4e3a\u53c2\u6570\uff0c\u7136\u540e\u751f\u6210\u5e76\u8fd4\u56de\u4e00\u4e2a\u5305\u542b\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u5143\u7d20\u7684\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u3002\uff08\u6ce8\u610f\uff1a\u8fd9\u4e2a\u51fd\u6570\u4e0d\u5e94\u8be5\u5bf9\u4f5c\u4e3a\u53c2\u6570\u7684\u94fe\u63a5\u7ed3\u6784\u8fdb\u884c\u4efb\u4f55\u4fee\u6539\u3002\uff09","title":"4.9.\u7f16\u7a0b\u7ec3\u4e60"},{"location":"python/DataStructure/05_InterfacePolymorphism/","text":"5.\u63a5\u53e3\u3001\u5b9e\u73b0\u548c\u591a\u6001 \u00b6 \u76ee\u6807\uff1a \u4e3a\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u7c7b\u578b\u5f00\u53d1\u63a5\u53e3\uff1b \u6309\u7167\u591a\u9879\u96c6\u7c7b\u578b\u7684\u63a5\u53e3\u5b9e\u73b0\u591a\u4e2a\u7c7b\uff1b \u5bf9\u7ed9\u5b9a\u591a\u9879\u96c6\u7c7b\u578b\u7684\u4e0d\u540c\u5b9e\u73b0\u8bc4\u4f30\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\u7684\u6743\u8861\uff1b \u5b9e\u73b0\u4e00\u4e2a\u7b80\u5355\u7684\u8fed\u4ee3\u5668\uff1b \u4f7f\u7528\u65b9\u6cd5\u5bf9\u5305\u548c\u96c6\u5408\u8fdb\u884c\u64cd\u4f5c\uff1b \u5224\u65ad\u5305\u6216\u96c6\u5408\u662f\u5426\u9002\u5408\u5728\u7ed9\u5b9a\u7684\u5e94\u7528\u7a0b\u5e8f\u91cc\u4f7f\u7528\uff1b \u5c06\u5305\u7684\u5b9e\u73b0\u8f6c\u6362\u6210\u6709\u5e8f\u5305\u7684\u5b9e\u73b0\u3002 5.1.\u5f00\u53d1\u63a5\u53e3 \u00b6 5.1.1.\u8bbe\u8ba1\u5305\u63a5\u53e3 \u00b6 5.1.2.\u6307\u5b9a\u53c2\u6570\u548c\u8fd4\u56de\u503c \u00b6 5.2.\u6784\u9020\u51fd\u6570\u548c\u7c7b\u7684\u5b9e\u73b0 \u00b6 5.2.1.\u524d\u7f6e\u6761\u4ef6\u3001\u540e\u7f6e\u6761\u4ef6\u3001\u5f02\u5e38\u548c\u6587\u6863 \u00b6 5.2.2.\u5728Python\u91cc\u7f16\u5199\u63a5\u53e3 \u00b6 \u7ec3\u4e60\u9898 1\uff0e\u5305\u91cc\u7684\u5143\u7d20\u662f\u6709\u5e8f\u7684\uff0c\u8fd8\u662f\u65e0\u5e8f\u7684\uff1f 2\uff0e\u54ea\u4e9b\u64cd\u4f5c\u4f1a\u51fa\u73b0\u5728\u6240\u6709\u591a\u9879\u96c6\u7684\u63a5\u53e3\u91cc\uff1f 3\uff0e\u54ea\u4e2a\u65b9\u6cd5\u8d1f\u8d23\u521b\u5efa\u591a\u9879\u96c6\u5bf9\u8c61\uff1f 4\uff0e\u8bf7\u8bf4\u51fa\u63a5\u53e3\u4e0e\u5b9e\u73b0\u5206\u79bb\u76843\u4e2a\u539f\u56e0\u3002 5.3.\u5f00\u53d1\u57fa\u4e8e\u6570\u7ec4\u7684\u5b9e\u73b0 \u00b6 5.3.1.\u9009\u62e9\u5e76\u521d\u59cb\u5316\u6570\u636e\u7ed3\u6784 \u00b6 5.3.2.\u5148\u5b8c\u6210\u7b80\u5355\u7684\u65b9\u6cd5 \u00b6 5.3.3.\u5b8c\u6210\u8fed\u4ee3\u5668 \u00b6 5.3.4.\u5b8c\u6210\u4f7f\u7528\u8fed\u4ee3\u5668\u7684\u65b9\u6cd5 \u00b6 5.3.5.in\u8fd0\u7b97\u7b26\u548c__contains__\u65b9\u6cd5 \u00b6 5.3.6.\u5b8c\u6210remove\u65b9\u6cd5 \u00b6 5.3.7.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u89e3\u91ca\u591a\u9879\u96c6\u7c7b\u7684__init__\u65b9\u6cd5\u7684\u4f5c\u7528\u3002 2\uff0e\u4e3a\u4ec0\u4e48\u8c03\u7528\u65b9\u6cd5\u6bd4\u76f4\u63a5\u5728\u7c7b\u91cc\u5f15\u7528\u5b9e\u4f8b\u53d8\u91cf\u66f4\u597d\uff1f 3\uff0e\u5bf9\u4e8eArrayBag\u7684__init__\u65b9\u6cd5\uff0c\u5c55\u793a\u5982\u4f55\u901a\u8fc7\u8c03\u7528clear\u65b9\u6cd5\u6765\u7b80\u5316\u4ee3\u7801\u3002 4\uff0e\u89e3\u91ca\u4e3a\u4ec0\u4e48__iter__\u65b9\u6cd5\u53ef\u80fd\u4f1a\u662f\u591a\u9879\u96c6\u7c7b\u91cc\u6700\u6709\u7528\u7684\u65b9\u6cd5\u3002 5\uff0e\u89e3\u91ca\u4e3a\u4ec0\u4e48\u5728ArrayBag\u7c7b\u4e2d\u4e0d\u7528\u5305\u542b__contains__\u65b9\u6cd5\u3002 5.4.\u5f00\u53d1\u57fa\u4e8e\u94fe\u63a5\u7684\u5b9e\u73b0 \u00b6 5.4.1.\u521d\u59cb\u5316\u6570\u636e\u7ed3\u6784 \u00b6 5.4.2.\u5b8c\u6210\u8fed\u4ee3\u5668 \u00b6 5.4.3.\u5b8c\u6210clear\u548cadd\u65b9\u6cd5 \u00b6 5.4.4.\u5b8c\u6210remove\u65b9\u6cd5 \u00b6 5.4.5.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u5047\u8bbea\u662f\u4e00\u4e2a\u6570\u7ec4\u5305\uff0cb\u662f\u4e00\u4e2a\u94fe\u63a5\u5305\uff0c\u5b83\u4eec\u90fd\u4e0d\u5305\u542b\u4efb\u4f55\u5143\u7d20\u3002\u8bf7\u63cf\u8ff0\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\u5b83\u4eec\u5728\u5185\u5b58\u4f7f\u7528\u4e0a\u7684\u5dee\u5f02\u3002 2\uff0e\u4e3a\u4ec0\u4e48\u94fe\u63a5\u5305\u4ecd\u7136\u9700\u8981\u4e00\u4e2a\u5355\u72ec\u7684\u5b9e\u4f8b\u53d8\u91cf\u6765\u8bb0\u5f55\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\uff1f 3\uff0e\u4e3a\u4ec0\u4e48\u4ece\u94fe\u63a5\u5305\u91cc\u5220\u9664\u5143\u7d20\u4e4b\u540e\uff0c\u7a0b\u5e8f\u5458\u4e0d\u7528\u62c5\u5fc3\u51fa\u73b0\u5185\u5b58\u6d6a\u8d39\u7684\u60c5\u51b5\uff1f 5.5.\u4e24\u79cd\u5305\u5b9e\u73b0\u7684\u8fd0\u884c\u65f6\u6027\u80fd \u00b6 5.6.\u6d4b\u8bd5\u5305\u7684\u4e24\u79cd\u5b9e\u73b0 \u00b6 5.7.\u4f7f\u7528UML\u7ed8\u5236\u5305\u8d44\u6e90 \u00b6 5.8.\u5c0f\u7ed3 \u00b6 \u63a5\u53e3\u662f\u7528\u6237\u7684\u8f6f\u4ef6\u8d44\u6e90\u53ef\u4ee5\u4f7f\u7528\u7684\u4e00\u7ec4\u64cd\u4f5c\u3002 \u63a5\u53e3\u91cc\u7684\u5143\u7d20\u662f\u51fd\u6570\u548c\u65b9\u6cd5\u7684\u5b9a\u4e49\u4ee5\u53ca\u5b83\u4eec\u7684\u6587\u6863\u3002 \u524d\u7f6e\u6761\u4ef6\u662f\u6307\u5728\u51fd\u6570\u6216\u65b9\u6cd5\u53ef\u4ee5\u6b63\u786e\u5b8c\u6210\u4efb\u52a1\u4e4b\u524d\u5fc5\u987b\u8981\u6ee1\u8db3\u7684\u6761\u4ef6\u3002 \u540e\u7f6e\u6761\u4ef6\u662f\u6307\u5728\u51fd\u6570\u6216\u65b9\u6cd5\u6b63\u786e\u5b8c\u6210\u4efb\u52a1\u4e4b\u540e\u5fc5\u987b\u4e3a\u771f\u7684\u6761\u4ef6\u3002 \u8bbe\u8ba1\u826f\u597d\u7684\u8f6f\u4ef6\u7cfb\u7edf\u4f1a\u628a\u63a5\u53e3\u548c\u5b83\u7684\u5b9e\u73b0\u5206\u5f00\u3002 \u5b9e\u73b0\u662f\u6307\u6ee1\u8db3\u63a5\u53e3\u7684\u51fd\u6570\u3001\u65b9\u6cd5\u6216\u7c7b\u3002 \u591a\u9879\u96c6\u7c7b\u578b\u53ef\u4ee5\u901a\u8fc7\u63a5\u53e3\u8fdb\u884c\u6307\u5b9a\u3002 \u591a\u9879\u96c6\u7c7b\u578b\u53ef\u4ee5\u6709\u51e0\u4e2a\u4e0d\u540c\u7684\u5b9e\u73b0\u7c7b\u3002 \u591a\u6001\u662f\u6307\u5728\u4e24\u4e2a\u6216\u591a\u4e2a\u5b9e\u73b0\u91cc\u4f7f\u7528\u76f8\u540c\u7684\u8fd0\u7b97\u7b26\u3001\u51fd\u6570\u540d\u79f0\u6216\u65b9\u6cd5\u540d\u79f0\u3002\u591a\u6001\u51fd\u6570\u7684\u793a\u4f8b\u662f str \u548c len \uff1b\u591a\u6001\u8fd0\u7b97\u7b26\u7684\u793a\u4f8b\u662f + \u548c == \uff1b\u591a\u6001\u65b9\u6cd5\u7684\u793a\u4f8b\u5305\u62ecadd\u548c isEmpty \u3002 \u5305\u591a\u9879\u96c6\u7c7b\u578b\u662f\u65e0\u5e8f\u7684\uff0c\u5e76\u4e14\u652f\u6301\u6dfb\u52a0\u3001\u5220\u9664\u548c\u8bbf\u95ee\u5176\u5143\u7d20\u7b49\u64cd\u4f5c\u3002 \u7c7b\u56fe\u662f\u4e00\u79cd\u63cf\u8ff0\u7c7b\u4e0e\u7c7b\u4e4b\u95f4\u5173\u7cfb\u7684\u53ef\u89c6\u5316\u8868\u793a\u65b9\u6cd5\u3002 \u7ec4\u5408\u8868\u793a\u4e24\u4e2a\u7c7b\u4e4b\u95f4\u6574\u4f53\u4e0e\u5c40\u90e8\u7684\u5173\u7cfb\u3002 \u805a\u5408\u8868\u793a\u4e24\u4e2a\u7c7b\u4e4b\u95f4\u4e00\u5bf9\u591a\u7684\u5173\u7cfb\u3002 UML\u662f\u4e00\u79cd\u63cf\u8ff0\u8f6f\u4ef6\u8d44\u6e90\u4e4b\u95f4\u5173\u7cfb\u7684\u53ef\u89c6\u5316\u8868\u793a\u65b9\u6cd5\u3002 5.9.\u590d\u4e60\u9898 \u00b6 1\uff0e\u5305\u662f\uff1a \u7ebf\u6027\u591a\u9879\u96c6 \u65e0\u5e8f\u591a\u9879\u96c6 2\uff0e\u7528\u6765\u8bbe\u7f6e\u5bf9\u8c61\u5b9e\u4f8b\u53d8\u91cf\u7684\u521d\u59cb\u72b6\u6001\u7684\u65b9\u6cd5\u662f\uff1a __init__ \u65b9\u6cd5 __str__ \u65b9\u6cd5 3\uff0e\u8ba9\u7a0b\u5e8f\u5458\u53ef\u4ee5\u8bbf\u95ee\u591a\u9879\u96c6\u91cc\u6240\u6709\u5143\u7d20\u7684\u65b9\u6cd5\u662f\uff1a __init__ \u65b9\u6cd5 __iter__ \u65b9\u6cd5 4\uff0e\u6539\u53d8\u5bf9\u8c61\u5185\u90e8\u72b6\u6001\u7684\u65b9\u6cd5\u662f\uff1a \u8bbf\u95ee\u5668\u65b9\u6cd5 \u53d8\u5f02\u5668\u65b9\u6cd5 5\uff0e\u4e00\u7ec4\u53ef\u4ee5\u88ab\u7c7b\u7684\u5ba2\u6237\u7aef\u4f7f\u7528\u7684\u65b9\u6cd5\u96c6\u79f0\u4e3a\uff1a \u5b9e\u73b0 \u63a5\u53e3 6\uff0e\u591a\u6001\u7528\u6765\u4ee3\u8868\u7684\u672f\u8bed\u662f\uff1a \u591a\u4e2a\u7c7b\u91cc\u76f8\u540c\u7684\u65b9\u6cd5\u540d\u79f0 \u7528\u6765\u5b58\u50a8\u53e6\u4e00\u4e2a\u7c7b\u91cc\u6240\u5305\u542b\u6570\u636e\u7684\u7c7b 7\uff0e\u7ec4\u5408\u662f\u6307\uff1a \u4e24\u4e2a\u7c7b\u4e4b\u95f4\u90e8\u5206\u4e0e\u6574\u4f53\u5173\u7cfb \u4e24\u4e2a\u7c7b\u4e4b\u95f4\u591a\u5bf9\u4e00\u5173\u7cfb 8\uff0e\u5305\u4e2dadd\u65b9\u6cd5\u7684\u5e73\u5747\u8fd0\u884c\u65f6\u4e3a\uff1a O(n) O(k) 9\uff0e\u5305\u4e2dremove\u65b9\u6cd5\u7684\u5e73\u5747\u8fd0\u884c\u65f6\u4e3a\uff1a O(n) O(k) 10\uff0e\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u5305\u5b9e\u73b0\u4f1a\u6bd4\u94fe\u63a5\u5305\u5b9e\u73b0\u4f7f\u7528\u66f4\u5c11\u7684\u5185\u5b58\uff1a \u542b\u6709\u5c11\u4e8e\u4e00\u534a\u7684\u6570\u636e \u542b\u6709\u4e00\u534a\u4ee5\u4e0a\u7684\u6570\u636e 5.10.\u7f16\u7a0b\u7ec3\u4e60 \u00b6 1\uff0e\u5bf9\u4e8e\u4e24\u4e2a\u5305\u5b9e\u73b0\uff0c\u786e\u5b9a == \u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u3002\u53ef\u4ee5\u9884\u89c1\u5230\uff0c\u8fd9\u91cc\u6709\u51e0\u79cd\u60c5\u51b5\u9700\u8981\u5206\u6790\u3002 2\uff0e\u5bf9\u4e8e\u5305\u7684\u4e24\u4e2a\u5b9e\u73b0\uff0c\u786e\u5b9a + \u8fd0\u7b97\u7b26\u7684\u8fd0\u884c\u65f6\u3002 3\uff0e\u7f16\u7801 ArrayBag \u91cc add \u65b9\u6cd5\u7684\u4ee3\u7801\uff0c\u4ece\u800c\u53ef\u4ee5\u5728\u9700\u8981\u7684\u65f6\u5019\u5bf9\u6570\u7ec4\u5c3a\u5bf8\u8fdb\u884c\u8c03\u6574\u3002 4\uff0e\u7f16\u7801 ArrayBag \u91cc remove \u65b9\u6cd5\u7684\u4ee3\u7801\uff0c\u4ece\u800c\u53ef\u4ee5\u5728\u9700\u8981\u7684\u65f6\u5019\u5bf9\u6570\u7ec4\u5c3a\u5bf8\u8fdb\u884c\u8c03\u6574\u3002 5\uff0e\u5728 ArrayBag \u548c LinkedBag \u7c7b\u91cc\u6dfb\u52a0 clone \u65b9\u6cd5\u3002\u8fd9\u4e2a\u65b9\u6cd5\u5728\u8c03\u7528\u7684\u65f6\u5019\uff0c\u4e0d\u4f1a\u63a5\u6536\u4efb\u4f55\u53c2\u6570\uff0c\u5e76\u4e14\u4f1a\u8fd4\u56de\u5f53\u524d\u5305\u7c7b\u578b\u7684\u4e00\u4e2a\u5b8c\u6574\u526f\u672c\u3002\u5728\u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u7684\u6700\u540e\uff0c\u53d8\u91cf bag2 \u5c06\u5305\u542b\u6570\u5b57 2 \u3001 3 \u548c 4 \u3002 bag1 = ArrayBag ([ 2 , 3 , 4 ]) bag2 = bag1 . clone () bag1 == bag2 # Returns True bag1 is bag2 # Returns False 6\uff0e\u96c6\u5408\u662f\u4e00\u4e2a\u65e0\u5e8f\u591a\u9879\u96c6\uff0c\u5e76\u4e14\u548c\u5305\u5177\u6709\u76f8\u540c\u7684\u63a5\u53e3\u3002\u4f46\u662f\u5728\u96c6\u5408\u91cc\uff0c\u5143\u7d20\u662f\u552f\u4e00\u7684\uff0c\u800c\u5305\u91cc\u53ef\u4ee5\u5305\u542b\u91cd\u590d\u7684\u7269\u54c1\u3002\u5b9a\u4e49\u4e00\u4e2a\u57fa\u4e8e\u6570\u7ec4\u7684\u53eb\u4f5c ArraySet \u7684\u591a\u9879\u96c6\u65b0\u7c7b\u3002\u5982\u679c\u96c6\u5408\u91cc\u7684\u5143\u7d20\u5df2\u7ecf\u5b58\u5728\u4e86\uff0c\u90a3\u4e48 add \u65b9\u6cd5\u5c06\u4f1a\u5ffd\u7565\u8fd9\u4e2a\u5143\u7d20\u3002 7\uff0e\u4f7f\u7528\u94fe\u63a5\u8282\u70b9\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c LinkedSet \u7684\u591a\u9879\u96c6\u65b0\u7c7b\u6765\u5b9e\u73b0\u96c6\u5408\u7c7b\u578b\u3002\u5982\u679c\u96c6\u5408\u91cc\u7684\u5143\u7d20\u5df2\u7ecf\u5b58\u5728\u4e86\uff0c\u90a3\u4e48 add \u65b9\u6cd5\u5c06\u4f1a\u5ffd\u7565\u8fd9\u4e2a\u5143\u7d20\u3002 8\uff0e\u6709\u5e8f\u5305\u7684\u884c\u4e3a\u548c\u666e\u901a\u5305\u7684\u662f\u4e00\u6837\u7684\uff0c\u4f46\u662f\u5b83\u80fd\u591f\u8ba9\u7528\u6237\u5728\u4f7f\u7528 for \u5faa\u73af\u65f6\u6309\u7167\u5347\u5e8f\u8bbf\u95ee\u91cc\u9762\u7684\u5143\u7d20\u3002\u56e0\u6b64\uff0c\u6dfb\u52a0\u5230\u8fd9\u4e2a\u5305\u7c7b\u578b\u91cc\u7684\u5143\u7d20\uff0c\u90fd\u5fc5\u987b\u5177\u6709\u4e00\u5b9a\u7684\u987a\u5e8f\u5e76\u4e14\u652f\u6301\u6bd4\u8f83\u8fd0\u7b97\u7b26\u3002\u8fd9\u79cd\u7c7b\u578b\u5143\u7d20\u7684\u7b80\u5355\u4f8b\u5b50\u662f\uff1a\u5b57\u7b26\u4e32\u548c\u6574\u6570\u3002\u5b9a\u4e49\u4e00\u4e2a\u652f\u6301\u8fd9\u4e2a\u529f\u80fd\u7684\u53eb\u4f5c ArraySortedBag \u7684\u65b0\u7c7b\u3002\u548c ArrayBag \u4e00\u6837\uff0c\u8fd9\u4e2a\u65b0\u7c7b\u4f1a\u57fa\u4e8e\u6570\u7ec4\uff0c\u4f46\u662f\u5b83\u7684 in \u64cd\u4f5c\u73b0\u5728\u53ef\u4ee5\u5728\u5bf9\u6570\u65f6\u95f4\u91cc\u8fd0\u884c\u3002\u8981\u5b8c\u6210\u8fd9\u4e00\u70b9\uff0c ArraySortedBag \u5fc5\u987b\u5c06\u65b0\u6dfb\u52a0\u7684\u5143\u7d20\u6309\u7167\u987a\u5e8f\u653e\u5230\u6570\u7ec4\u91cc\u3002\u6700\u7b80\u5355\u7684\u529e\u6cd5\u662f\u4fee\u6539 add \u65b9\u6cd5\uff0c\u4ece\u800c\u8ba9\u65b0\u5143\u7d20\u63d2\u5165\u9002\u5f53\u7684\u4f4d\u7f6e\uff1b\u7136\u540e\uff0c\u6dfb\u52a0_ _contains__ \u65b9\u6cd5\u6765\u63d0\u4f9b\u65b0\u7684\u4e14\u66f4\u6709\u6548\u7684\u641c\u7d22\uff1b\u6700\u540e\uff0c\u8981\u628a\u5bf9 ArrayBag \u7684\u6240\u6709\u5f15\u7528\u90fd\u66ff\u6362\u4e3a ArraySortedBag \u3002\uff08\u63d0\u793a\uff1a\u628a\u4ee3\u7801\u4ece ArrayBag \u7c7b\u4e2d\u590d\u5236\u5230\u4e00\u4e2a\u65b0\u6587\u4ef6\u91cc\uff0c\u7136\u540e\u5728\u8fd9\u4e2a\u65b0\u6587\u4ef6\u91cc\u5f00\u59cb\u4fee\u6539\u3002\uff09 9\uff0e\u786e\u5b9a ArraySortedBag \u91cc add \u65b9\u6cd5\u7684\u8fd0\u884c\u65f6\u3002 10\uff0ePython\u7684 for \u5faa\u73af\u53ef\u4ee5\u8ba9\u7a0b\u5e8f\u5458\u5728\u5faa\u73af\u8fed\u4ee3\u591a\u9879\u96c6\u7684\u65f6\u5019\u5bf9\u5b83\u6267\u884c\u6dfb\u52a0\u6216\u5220\u9664\u5143\u7d20\u7684\u64cd\u4f5c\u3002\u4e00\u4e9b\u8bbe\u8ba1\u4eba\u5458\u62c5\u5fc3\u5728\u8fed\u4ee3\u8fc7\u7a0b\u4e2d\u5bf9\u591a\u9879\u96c6\u7684\u7ed3\u6784\u8fdb\u884c\u4fee\u6539\u53ef\u80fd\u4f1a\u5bfc\u81f4\u7a0b\u5e8f\u5d29\u6e83\u3002\u6709\u4e00\u79cd\u4fee\u6539\u7b56\u7565\u662f\u901a\u8fc7\u7981\u6b62\u5728\u8fed\u4ee3\u671f\u95f4\u5bf9\u591a\u9879\u96c6\u8fdb\u884c\u53d8\u5f02\u6765\u8ba9 for \u5faa\u73af\u6210\u4e3a\u53ea\u8bfb\u3002\u4f60\u53ef\u4ee5\u901a\u8fc7\u5bf9\u53d8\u5f02\u64cd\u4f5c\u8fdb\u884c\u8ba1\u6570\uff0c\u5e76\u4e14\u5224\u65ad\u8fd9\u4e2a\u8ba1\u6570\u6709\u6ca1\u6709\u5728\u591a\u9879\u96c6\u7684 __iter__ \u65b9\u6cd5\u7684\u4efb\u610f\u8282\u62cd\u4e2d\u88ab\u589e\u52a0\u6765\u68c0\u6d4b\u8fd9\u79cd\u7c7b\u578b\u7684\u53d8\u5f02\u3002\u5f53\u53d1\u751f\u8fd9\u79cd\u60c5\u51b5\u65f6\uff0c\u5c31\u53ef\u4ee5\u5f15\u53d1\u5f02\u5e38\u4ece\u800c\u907f\u514d\u8ba1\u7b97\u7684\u7ee7\u7eed\u8fdb\u884c\u3002\u628a\u8fd9\u4e2a\u673a\u5236\u6dfb\u52a0\u5230 ArrayBag \u7c7b\u91cc\u3002\u53ef\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u53eb\u4f5c modCount \u7684\u65b0\u5b9e\u4f8b\u53d8\u91cf\uff0c\u8fd9\u4e2a\u5b9e\u4f8b\u53d8\u91cf\u4f1a\u5728 __init__ \u65b9\u6cd5\u91cc\u8bbe\u7f6e\u4e3a 0 \uff1b\u7136\u540e\uff0c\u6bcf\u4e2a\u53d8\u5f02\u5668\u65b9\u6cd5\u90fd\u4f1a\u9012\u589e\u8fd9\u4e2a\u53d8\u91cf\uff1b\u6700\u540e\uff0c __iter__ \u65b9\u6cd5\u6709\u4e00\u4e2a\u53eb\u4f5c modCount \u7684\u4e34\u65f6\u53d8\u91cf\uff0c\u8fd9\u4e2a\u4e34\u65f6\u53d8\u91cf\u7684\u521d\u59cb\u503c\u662f\u5b9e\u4f8b\u53d8\u91cf self.modCount \u7684\u503c\u3002\u5728 __iter__ \u65b9\u6cd5\u91cc\u8fd4\u56de\u4e00\u4e2a\u5143\u7d20\u540e\uff0c\u5982\u679c\u8fd9\u4e24\u4e2a\u4fee\u6539\u8fc7\u7684\u8ba1\u6570\u5668\u503c\u4e0d\u76f8\u7b49\uff0c\u5c31\u7acb\u5373\u5f15\u53d1\u5f02\u5e38\u3002\u7528\u4e00\u4e2a\u7a0b\u5e8f\u6765\u6d4b\u8bd5\u4f60\u7684\u4fee\u6539\uff0c\u4ece\u800c\u4fdd\u8bc1\u6ee1\u8db3\u76f8\u5e94\u7684\u9700\u6c42\u3002","title":"\u63a5\u53e3\u3001\u5b9e\u73b0\u548c\u591a\u6001"},{"location":"python/DataStructure/05_InterfacePolymorphism/#5","text":"\u76ee\u6807\uff1a \u4e3a\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u7c7b\u578b\u5f00\u53d1\u63a5\u53e3\uff1b \u6309\u7167\u591a\u9879\u96c6\u7c7b\u578b\u7684\u63a5\u53e3\u5b9e\u73b0\u591a\u4e2a\u7c7b\uff1b \u5bf9\u7ed9\u5b9a\u591a\u9879\u96c6\u7c7b\u578b\u7684\u4e0d\u540c\u5b9e\u73b0\u8bc4\u4f30\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\u7684\u6743\u8861\uff1b \u5b9e\u73b0\u4e00\u4e2a\u7b80\u5355\u7684\u8fed\u4ee3\u5668\uff1b \u4f7f\u7528\u65b9\u6cd5\u5bf9\u5305\u548c\u96c6\u5408\u8fdb\u884c\u64cd\u4f5c\uff1b \u5224\u65ad\u5305\u6216\u96c6\u5408\u662f\u5426\u9002\u5408\u5728\u7ed9\u5b9a\u7684\u5e94\u7528\u7a0b\u5e8f\u91cc\u4f7f\u7528\uff1b \u5c06\u5305\u7684\u5b9e\u73b0\u8f6c\u6362\u6210\u6709\u5e8f\u5305\u7684\u5b9e\u73b0\u3002","title":"5.\u63a5\u53e3\u3001\u5b9e\u73b0\u548c\u591a\u6001"},{"location":"python/DataStructure/05_InterfacePolymorphism/#51","text":"","title":"5.1.\u5f00\u53d1\u63a5\u53e3"},{"location":"python/DataStructure/05_InterfacePolymorphism/#511","text":"","title":"5.1.1.\u8bbe\u8ba1\u5305\u63a5\u53e3"},{"location":"python/DataStructure/05_InterfacePolymorphism/#512","text":"","title":"5.1.2.\u6307\u5b9a\u53c2\u6570\u548c\u8fd4\u56de\u503c"},{"location":"python/DataStructure/05_InterfacePolymorphism/#52","text":"","title":"5.2.\u6784\u9020\u51fd\u6570\u548c\u7c7b\u7684\u5b9e\u73b0"},{"location":"python/DataStructure/05_InterfacePolymorphism/#521","text":"","title":"5.2.1.\u524d\u7f6e\u6761\u4ef6\u3001\u540e\u7f6e\u6761\u4ef6\u3001\u5f02\u5e38\u548c\u6587\u6863"},{"location":"python/DataStructure/05_InterfacePolymorphism/#522python","text":"\u7ec3\u4e60\u9898 1\uff0e\u5305\u91cc\u7684\u5143\u7d20\u662f\u6709\u5e8f\u7684\uff0c\u8fd8\u662f\u65e0\u5e8f\u7684\uff1f 2\uff0e\u54ea\u4e9b\u64cd\u4f5c\u4f1a\u51fa\u73b0\u5728\u6240\u6709\u591a\u9879\u96c6\u7684\u63a5\u53e3\u91cc\uff1f 3\uff0e\u54ea\u4e2a\u65b9\u6cd5\u8d1f\u8d23\u521b\u5efa\u591a\u9879\u96c6\u5bf9\u8c61\uff1f 4\uff0e\u8bf7\u8bf4\u51fa\u63a5\u53e3\u4e0e\u5b9e\u73b0\u5206\u79bb\u76843\u4e2a\u539f\u56e0\u3002","title":"5.2.2.\u5728Python\u91cc\u7f16\u5199\u63a5\u53e3"},{"location":"python/DataStructure/05_InterfacePolymorphism/#53","text":"","title":"5.3.\u5f00\u53d1\u57fa\u4e8e\u6570\u7ec4\u7684\u5b9e\u73b0"},{"location":"python/DataStructure/05_InterfacePolymorphism/#531","text":"","title":"5.3.1.\u9009\u62e9\u5e76\u521d\u59cb\u5316\u6570\u636e\u7ed3\u6784"},{"location":"python/DataStructure/05_InterfacePolymorphism/#532","text":"","title":"5.3.2.\u5148\u5b8c\u6210\u7b80\u5355\u7684\u65b9\u6cd5"},{"location":"python/DataStructure/05_InterfacePolymorphism/#533","text":"","title":"5.3.3.\u5b8c\u6210\u8fed\u4ee3\u5668"},{"location":"python/DataStructure/05_InterfacePolymorphism/#534","text":"","title":"5.3.4.\u5b8c\u6210\u4f7f\u7528\u8fed\u4ee3\u5668\u7684\u65b9\u6cd5"},{"location":"python/DataStructure/05_InterfacePolymorphism/#535in__contains__","text":"","title":"5.3.5.in\u8fd0\u7b97\u7b26\u548c__contains__\u65b9\u6cd5"},{"location":"python/DataStructure/05_InterfacePolymorphism/#536remove","text":"","title":"5.3.6.\u5b8c\u6210remove\u65b9\u6cd5"},{"location":"python/DataStructure/05_InterfacePolymorphism/#537","text":"1\uff0e\u89e3\u91ca\u591a\u9879\u96c6\u7c7b\u7684__init__\u65b9\u6cd5\u7684\u4f5c\u7528\u3002 2\uff0e\u4e3a\u4ec0\u4e48\u8c03\u7528\u65b9\u6cd5\u6bd4\u76f4\u63a5\u5728\u7c7b\u91cc\u5f15\u7528\u5b9e\u4f8b\u53d8\u91cf\u66f4\u597d\uff1f 3\uff0e\u5bf9\u4e8eArrayBag\u7684__init__\u65b9\u6cd5\uff0c\u5c55\u793a\u5982\u4f55\u901a\u8fc7\u8c03\u7528clear\u65b9\u6cd5\u6765\u7b80\u5316\u4ee3\u7801\u3002 4\uff0e\u89e3\u91ca\u4e3a\u4ec0\u4e48__iter__\u65b9\u6cd5\u53ef\u80fd\u4f1a\u662f\u591a\u9879\u96c6\u7c7b\u91cc\u6700\u6709\u7528\u7684\u65b9\u6cd5\u3002 5\uff0e\u89e3\u91ca\u4e3a\u4ec0\u4e48\u5728ArrayBag\u7c7b\u4e2d\u4e0d\u7528\u5305\u542b__contains__\u65b9\u6cd5\u3002","title":"5.3.7.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/05_InterfacePolymorphism/#54","text":"","title":"5.4.\u5f00\u53d1\u57fa\u4e8e\u94fe\u63a5\u7684\u5b9e\u73b0"},{"location":"python/DataStructure/05_InterfacePolymorphism/#541","text":"","title":"5.4.1.\u521d\u59cb\u5316\u6570\u636e\u7ed3\u6784"},{"location":"python/DataStructure/05_InterfacePolymorphism/#542","text":"","title":"5.4.2.\u5b8c\u6210\u8fed\u4ee3\u5668"},{"location":"python/DataStructure/05_InterfacePolymorphism/#543clearadd","text":"","title":"5.4.3.\u5b8c\u6210clear\u548cadd\u65b9\u6cd5"},{"location":"python/DataStructure/05_InterfacePolymorphism/#544remove","text":"","title":"5.4.4.\u5b8c\u6210remove\u65b9\u6cd5"},{"location":"python/DataStructure/05_InterfacePolymorphism/#545","text":"1\uff0e\u5047\u8bbea\u662f\u4e00\u4e2a\u6570\u7ec4\u5305\uff0cb\u662f\u4e00\u4e2a\u94fe\u63a5\u5305\uff0c\u5b83\u4eec\u90fd\u4e0d\u5305\u542b\u4efb\u4f55\u5143\u7d20\u3002\u8bf7\u63cf\u8ff0\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\u5b83\u4eec\u5728\u5185\u5b58\u4f7f\u7528\u4e0a\u7684\u5dee\u5f02\u3002 2\uff0e\u4e3a\u4ec0\u4e48\u94fe\u63a5\u5305\u4ecd\u7136\u9700\u8981\u4e00\u4e2a\u5355\u72ec\u7684\u5b9e\u4f8b\u53d8\u91cf\u6765\u8bb0\u5f55\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\uff1f 3\uff0e\u4e3a\u4ec0\u4e48\u4ece\u94fe\u63a5\u5305\u91cc\u5220\u9664\u5143\u7d20\u4e4b\u540e\uff0c\u7a0b\u5e8f\u5458\u4e0d\u7528\u62c5\u5fc3\u51fa\u73b0\u5185\u5b58\u6d6a\u8d39\u7684\u60c5\u51b5\uff1f","title":"5.4.5.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/05_InterfacePolymorphism/#55","text":"","title":"5.5.\u4e24\u79cd\u5305\u5b9e\u73b0\u7684\u8fd0\u884c\u65f6\u6027\u80fd"},{"location":"python/DataStructure/05_InterfacePolymorphism/#56","text":"","title":"5.6.\u6d4b\u8bd5\u5305\u7684\u4e24\u79cd\u5b9e\u73b0"},{"location":"python/DataStructure/05_InterfacePolymorphism/#57uml","text":"","title":"5.7.\u4f7f\u7528UML\u7ed8\u5236\u5305\u8d44\u6e90"},{"location":"python/DataStructure/05_InterfacePolymorphism/#58","text":"\u63a5\u53e3\u662f\u7528\u6237\u7684\u8f6f\u4ef6\u8d44\u6e90\u53ef\u4ee5\u4f7f\u7528\u7684\u4e00\u7ec4\u64cd\u4f5c\u3002 \u63a5\u53e3\u91cc\u7684\u5143\u7d20\u662f\u51fd\u6570\u548c\u65b9\u6cd5\u7684\u5b9a\u4e49\u4ee5\u53ca\u5b83\u4eec\u7684\u6587\u6863\u3002 \u524d\u7f6e\u6761\u4ef6\u662f\u6307\u5728\u51fd\u6570\u6216\u65b9\u6cd5\u53ef\u4ee5\u6b63\u786e\u5b8c\u6210\u4efb\u52a1\u4e4b\u524d\u5fc5\u987b\u8981\u6ee1\u8db3\u7684\u6761\u4ef6\u3002 \u540e\u7f6e\u6761\u4ef6\u662f\u6307\u5728\u51fd\u6570\u6216\u65b9\u6cd5\u6b63\u786e\u5b8c\u6210\u4efb\u52a1\u4e4b\u540e\u5fc5\u987b\u4e3a\u771f\u7684\u6761\u4ef6\u3002 \u8bbe\u8ba1\u826f\u597d\u7684\u8f6f\u4ef6\u7cfb\u7edf\u4f1a\u628a\u63a5\u53e3\u548c\u5b83\u7684\u5b9e\u73b0\u5206\u5f00\u3002 \u5b9e\u73b0\u662f\u6307\u6ee1\u8db3\u63a5\u53e3\u7684\u51fd\u6570\u3001\u65b9\u6cd5\u6216\u7c7b\u3002 \u591a\u9879\u96c6\u7c7b\u578b\u53ef\u4ee5\u901a\u8fc7\u63a5\u53e3\u8fdb\u884c\u6307\u5b9a\u3002 \u591a\u9879\u96c6\u7c7b\u578b\u53ef\u4ee5\u6709\u51e0\u4e2a\u4e0d\u540c\u7684\u5b9e\u73b0\u7c7b\u3002 \u591a\u6001\u662f\u6307\u5728\u4e24\u4e2a\u6216\u591a\u4e2a\u5b9e\u73b0\u91cc\u4f7f\u7528\u76f8\u540c\u7684\u8fd0\u7b97\u7b26\u3001\u51fd\u6570\u540d\u79f0\u6216\u65b9\u6cd5\u540d\u79f0\u3002\u591a\u6001\u51fd\u6570\u7684\u793a\u4f8b\u662f str \u548c len \uff1b\u591a\u6001\u8fd0\u7b97\u7b26\u7684\u793a\u4f8b\u662f + \u548c == \uff1b\u591a\u6001\u65b9\u6cd5\u7684\u793a\u4f8b\u5305\u62ecadd\u548c isEmpty \u3002 \u5305\u591a\u9879\u96c6\u7c7b\u578b\u662f\u65e0\u5e8f\u7684\uff0c\u5e76\u4e14\u652f\u6301\u6dfb\u52a0\u3001\u5220\u9664\u548c\u8bbf\u95ee\u5176\u5143\u7d20\u7b49\u64cd\u4f5c\u3002 \u7c7b\u56fe\u662f\u4e00\u79cd\u63cf\u8ff0\u7c7b\u4e0e\u7c7b\u4e4b\u95f4\u5173\u7cfb\u7684\u53ef\u89c6\u5316\u8868\u793a\u65b9\u6cd5\u3002 \u7ec4\u5408\u8868\u793a\u4e24\u4e2a\u7c7b\u4e4b\u95f4\u6574\u4f53\u4e0e\u5c40\u90e8\u7684\u5173\u7cfb\u3002 \u805a\u5408\u8868\u793a\u4e24\u4e2a\u7c7b\u4e4b\u95f4\u4e00\u5bf9\u591a\u7684\u5173\u7cfb\u3002 UML\u662f\u4e00\u79cd\u63cf\u8ff0\u8f6f\u4ef6\u8d44\u6e90\u4e4b\u95f4\u5173\u7cfb\u7684\u53ef\u89c6\u5316\u8868\u793a\u65b9\u6cd5\u3002","title":"5.8.\u5c0f\u7ed3"},{"location":"python/DataStructure/05_InterfacePolymorphism/#59","text":"1\uff0e\u5305\u662f\uff1a \u7ebf\u6027\u591a\u9879\u96c6 \u65e0\u5e8f\u591a\u9879\u96c6 2\uff0e\u7528\u6765\u8bbe\u7f6e\u5bf9\u8c61\u5b9e\u4f8b\u53d8\u91cf\u7684\u521d\u59cb\u72b6\u6001\u7684\u65b9\u6cd5\u662f\uff1a __init__ \u65b9\u6cd5 __str__ \u65b9\u6cd5 3\uff0e\u8ba9\u7a0b\u5e8f\u5458\u53ef\u4ee5\u8bbf\u95ee\u591a\u9879\u96c6\u91cc\u6240\u6709\u5143\u7d20\u7684\u65b9\u6cd5\u662f\uff1a __init__ \u65b9\u6cd5 __iter__ \u65b9\u6cd5 4\uff0e\u6539\u53d8\u5bf9\u8c61\u5185\u90e8\u72b6\u6001\u7684\u65b9\u6cd5\u662f\uff1a \u8bbf\u95ee\u5668\u65b9\u6cd5 \u53d8\u5f02\u5668\u65b9\u6cd5 5\uff0e\u4e00\u7ec4\u53ef\u4ee5\u88ab\u7c7b\u7684\u5ba2\u6237\u7aef\u4f7f\u7528\u7684\u65b9\u6cd5\u96c6\u79f0\u4e3a\uff1a \u5b9e\u73b0 \u63a5\u53e3 6\uff0e\u591a\u6001\u7528\u6765\u4ee3\u8868\u7684\u672f\u8bed\u662f\uff1a \u591a\u4e2a\u7c7b\u91cc\u76f8\u540c\u7684\u65b9\u6cd5\u540d\u79f0 \u7528\u6765\u5b58\u50a8\u53e6\u4e00\u4e2a\u7c7b\u91cc\u6240\u5305\u542b\u6570\u636e\u7684\u7c7b 7\uff0e\u7ec4\u5408\u662f\u6307\uff1a \u4e24\u4e2a\u7c7b\u4e4b\u95f4\u90e8\u5206\u4e0e\u6574\u4f53\u5173\u7cfb \u4e24\u4e2a\u7c7b\u4e4b\u95f4\u591a\u5bf9\u4e00\u5173\u7cfb 8\uff0e\u5305\u4e2dadd\u65b9\u6cd5\u7684\u5e73\u5747\u8fd0\u884c\u65f6\u4e3a\uff1a O(n) O(k) 9\uff0e\u5305\u4e2dremove\u65b9\u6cd5\u7684\u5e73\u5747\u8fd0\u884c\u65f6\u4e3a\uff1a O(n) O(k) 10\uff0e\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u5305\u5b9e\u73b0\u4f1a\u6bd4\u94fe\u63a5\u5305\u5b9e\u73b0\u4f7f\u7528\u66f4\u5c11\u7684\u5185\u5b58\uff1a \u542b\u6709\u5c11\u4e8e\u4e00\u534a\u7684\u6570\u636e \u542b\u6709\u4e00\u534a\u4ee5\u4e0a\u7684\u6570\u636e","title":"5.9.\u590d\u4e60\u9898"},{"location":"python/DataStructure/05_InterfacePolymorphism/#510","text":"1\uff0e\u5bf9\u4e8e\u4e24\u4e2a\u5305\u5b9e\u73b0\uff0c\u786e\u5b9a == \u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u3002\u53ef\u4ee5\u9884\u89c1\u5230\uff0c\u8fd9\u91cc\u6709\u51e0\u79cd\u60c5\u51b5\u9700\u8981\u5206\u6790\u3002 2\uff0e\u5bf9\u4e8e\u5305\u7684\u4e24\u4e2a\u5b9e\u73b0\uff0c\u786e\u5b9a + \u8fd0\u7b97\u7b26\u7684\u8fd0\u884c\u65f6\u3002 3\uff0e\u7f16\u7801 ArrayBag \u91cc add \u65b9\u6cd5\u7684\u4ee3\u7801\uff0c\u4ece\u800c\u53ef\u4ee5\u5728\u9700\u8981\u7684\u65f6\u5019\u5bf9\u6570\u7ec4\u5c3a\u5bf8\u8fdb\u884c\u8c03\u6574\u3002 4\uff0e\u7f16\u7801 ArrayBag \u91cc remove \u65b9\u6cd5\u7684\u4ee3\u7801\uff0c\u4ece\u800c\u53ef\u4ee5\u5728\u9700\u8981\u7684\u65f6\u5019\u5bf9\u6570\u7ec4\u5c3a\u5bf8\u8fdb\u884c\u8c03\u6574\u3002 5\uff0e\u5728 ArrayBag \u548c LinkedBag \u7c7b\u91cc\u6dfb\u52a0 clone \u65b9\u6cd5\u3002\u8fd9\u4e2a\u65b9\u6cd5\u5728\u8c03\u7528\u7684\u65f6\u5019\uff0c\u4e0d\u4f1a\u63a5\u6536\u4efb\u4f55\u53c2\u6570\uff0c\u5e76\u4e14\u4f1a\u8fd4\u56de\u5f53\u524d\u5305\u7c7b\u578b\u7684\u4e00\u4e2a\u5b8c\u6574\u526f\u672c\u3002\u5728\u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u7684\u6700\u540e\uff0c\u53d8\u91cf bag2 \u5c06\u5305\u542b\u6570\u5b57 2 \u3001 3 \u548c 4 \u3002 bag1 = ArrayBag ([ 2 , 3 , 4 ]) bag2 = bag1 . clone () bag1 == bag2 # Returns True bag1 is bag2 # Returns False 6\uff0e\u96c6\u5408\u662f\u4e00\u4e2a\u65e0\u5e8f\u591a\u9879\u96c6\uff0c\u5e76\u4e14\u548c\u5305\u5177\u6709\u76f8\u540c\u7684\u63a5\u53e3\u3002\u4f46\u662f\u5728\u96c6\u5408\u91cc\uff0c\u5143\u7d20\u662f\u552f\u4e00\u7684\uff0c\u800c\u5305\u91cc\u53ef\u4ee5\u5305\u542b\u91cd\u590d\u7684\u7269\u54c1\u3002\u5b9a\u4e49\u4e00\u4e2a\u57fa\u4e8e\u6570\u7ec4\u7684\u53eb\u4f5c ArraySet \u7684\u591a\u9879\u96c6\u65b0\u7c7b\u3002\u5982\u679c\u96c6\u5408\u91cc\u7684\u5143\u7d20\u5df2\u7ecf\u5b58\u5728\u4e86\uff0c\u90a3\u4e48 add \u65b9\u6cd5\u5c06\u4f1a\u5ffd\u7565\u8fd9\u4e2a\u5143\u7d20\u3002 7\uff0e\u4f7f\u7528\u94fe\u63a5\u8282\u70b9\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c LinkedSet \u7684\u591a\u9879\u96c6\u65b0\u7c7b\u6765\u5b9e\u73b0\u96c6\u5408\u7c7b\u578b\u3002\u5982\u679c\u96c6\u5408\u91cc\u7684\u5143\u7d20\u5df2\u7ecf\u5b58\u5728\u4e86\uff0c\u90a3\u4e48 add \u65b9\u6cd5\u5c06\u4f1a\u5ffd\u7565\u8fd9\u4e2a\u5143\u7d20\u3002 8\uff0e\u6709\u5e8f\u5305\u7684\u884c\u4e3a\u548c\u666e\u901a\u5305\u7684\u662f\u4e00\u6837\u7684\uff0c\u4f46\u662f\u5b83\u80fd\u591f\u8ba9\u7528\u6237\u5728\u4f7f\u7528 for \u5faa\u73af\u65f6\u6309\u7167\u5347\u5e8f\u8bbf\u95ee\u91cc\u9762\u7684\u5143\u7d20\u3002\u56e0\u6b64\uff0c\u6dfb\u52a0\u5230\u8fd9\u4e2a\u5305\u7c7b\u578b\u91cc\u7684\u5143\u7d20\uff0c\u90fd\u5fc5\u987b\u5177\u6709\u4e00\u5b9a\u7684\u987a\u5e8f\u5e76\u4e14\u652f\u6301\u6bd4\u8f83\u8fd0\u7b97\u7b26\u3002\u8fd9\u79cd\u7c7b\u578b\u5143\u7d20\u7684\u7b80\u5355\u4f8b\u5b50\u662f\uff1a\u5b57\u7b26\u4e32\u548c\u6574\u6570\u3002\u5b9a\u4e49\u4e00\u4e2a\u652f\u6301\u8fd9\u4e2a\u529f\u80fd\u7684\u53eb\u4f5c ArraySortedBag \u7684\u65b0\u7c7b\u3002\u548c ArrayBag \u4e00\u6837\uff0c\u8fd9\u4e2a\u65b0\u7c7b\u4f1a\u57fa\u4e8e\u6570\u7ec4\uff0c\u4f46\u662f\u5b83\u7684 in \u64cd\u4f5c\u73b0\u5728\u53ef\u4ee5\u5728\u5bf9\u6570\u65f6\u95f4\u91cc\u8fd0\u884c\u3002\u8981\u5b8c\u6210\u8fd9\u4e00\u70b9\uff0c ArraySortedBag \u5fc5\u987b\u5c06\u65b0\u6dfb\u52a0\u7684\u5143\u7d20\u6309\u7167\u987a\u5e8f\u653e\u5230\u6570\u7ec4\u91cc\u3002\u6700\u7b80\u5355\u7684\u529e\u6cd5\u662f\u4fee\u6539 add \u65b9\u6cd5\uff0c\u4ece\u800c\u8ba9\u65b0\u5143\u7d20\u63d2\u5165\u9002\u5f53\u7684\u4f4d\u7f6e\uff1b\u7136\u540e\uff0c\u6dfb\u52a0_ _contains__ \u65b9\u6cd5\u6765\u63d0\u4f9b\u65b0\u7684\u4e14\u66f4\u6709\u6548\u7684\u641c\u7d22\uff1b\u6700\u540e\uff0c\u8981\u628a\u5bf9 ArrayBag \u7684\u6240\u6709\u5f15\u7528\u90fd\u66ff\u6362\u4e3a ArraySortedBag \u3002\uff08\u63d0\u793a\uff1a\u628a\u4ee3\u7801\u4ece ArrayBag \u7c7b\u4e2d\u590d\u5236\u5230\u4e00\u4e2a\u65b0\u6587\u4ef6\u91cc\uff0c\u7136\u540e\u5728\u8fd9\u4e2a\u65b0\u6587\u4ef6\u91cc\u5f00\u59cb\u4fee\u6539\u3002\uff09 9\uff0e\u786e\u5b9a ArraySortedBag \u91cc add \u65b9\u6cd5\u7684\u8fd0\u884c\u65f6\u3002 10\uff0ePython\u7684 for \u5faa\u73af\u53ef\u4ee5\u8ba9\u7a0b\u5e8f\u5458\u5728\u5faa\u73af\u8fed\u4ee3\u591a\u9879\u96c6\u7684\u65f6\u5019\u5bf9\u5b83\u6267\u884c\u6dfb\u52a0\u6216\u5220\u9664\u5143\u7d20\u7684\u64cd\u4f5c\u3002\u4e00\u4e9b\u8bbe\u8ba1\u4eba\u5458\u62c5\u5fc3\u5728\u8fed\u4ee3\u8fc7\u7a0b\u4e2d\u5bf9\u591a\u9879\u96c6\u7684\u7ed3\u6784\u8fdb\u884c\u4fee\u6539\u53ef\u80fd\u4f1a\u5bfc\u81f4\u7a0b\u5e8f\u5d29\u6e83\u3002\u6709\u4e00\u79cd\u4fee\u6539\u7b56\u7565\u662f\u901a\u8fc7\u7981\u6b62\u5728\u8fed\u4ee3\u671f\u95f4\u5bf9\u591a\u9879\u96c6\u8fdb\u884c\u53d8\u5f02\u6765\u8ba9 for \u5faa\u73af\u6210\u4e3a\u53ea\u8bfb\u3002\u4f60\u53ef\u4ee5\u901a\u8fc7\u5bf9\u53d8\u5f02\u64cd\u4f5c\u8fdb\u884c\u8ba1\u6570\uff0c\u5e76\u4e14\u5224\u65ad\u8fd9\u4e2a\u8ba1\u6570\u6709\u6ca1\u6709\u5728\u591a\u9879\u96c6\u7684 __iter__ \u65b9\u6cd5\u7684\u4efb\u610f\u8282\u62cd\u4e2d\u88ab\u589e\u52a0\u6765\u68c0\u6d4b\u8fd9\u79cd\u7c7b\u578b\u7684\u53d8\u5f02\u3002\u5f53\u53d1\u751f\u8fd9\u79cd\u60c5\u51b5\u65f6\uff0c\u5c31\u53ef\u4ee5\u5f15\u53d1\u5f02\u5e38\u4ece\u800c\u907f\u514d\u8ba1\u7b97\u7684\u7ee7\u7eed\u8fdb\u884c\u3002\u628a\u8fd9\u4e2a\u673a\u5236\u6dfb\u52a0\u5230 ArrayBag \u7c7b\u91cc\u3002\u53ef\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u53eb\u4f5c modCount \u7684\u65b0\u5b9e\u4f8b\u53d8\u91cf\uff0c\u8fd9\u4e2a\u5b9e\u4f8b\u53d8\u91cf\u4f1a\u5728 __init__ \u65b9\u6cd5\u91cc\u8bbe\u7f6e\u4e3a 0 \uff1b\u7136\u540e\uff0c\u6bcf\u4e2a\u53d8\u5f02\u5668\u65b9\u6cd5\u90fd\u4f1a\u9012\u589e\u8fd9\u4e2a\u53d8\u91cf\uff1b\u6700\u540e\uff0c __iter__ \u65b9\u6cd5\u6709\u4e00\u4e2a\u53eb\u4f5c modCount \u7684\u4e34\u65f6\u53d8\u91cf\uff0c\u8fd9\u4e2a\u4e34\u65f6\u53d8\u91cf\u7684\u521d\u59cb\u503c\u662f\u5b9e\u4f8b\u53d8\u91cf self.modCount \u7684\u503c\u3002\u5728 __iter__ \u65b9\u6cd5\u91cc\u8fd4\u56de\u4e00\u4e2a\u5143\u7d20\u540e\uff0c\u5982\u679c\u8fd9\u4e24\u4e2a\u4fee\u6539\u8fc7\u7684\u8ba1\u6570\u5668\u503c\u4e0d\u76f8\u7b49\uff0c\u5c31\u7acb\u5373\u5f15\u53d1\u5f02\u5e38\u3002\u7528\u4e00\u4e2a\u7a0b\u5e8f\u6765\u6d4b\u8bd5\u4f60\u7684\u4fee\u6539\uff0c\u4ece\u800c\u4fdd\u8bc1\u6ee1\u8db3\u76f8\u5e94\u7684\u9700\u6c42\u3002","title":"5.10.\u7f16\u7a0b\u7ec3\u4e60"},{"location":"python/DataStructure/06_InheritanceAbstractClass/","text":"\u7ee7\u627f\u4e0e\u62bd\u8c61\u7c7b \u00b6","title":"\u7ee7\u627f\u4e0e\u62bd\u8c61\u7c7b"},{"location":"python/DataStructure/06_InheritanceAbstractClass/#_1","text":"","title":"\u7ee7\u627f\u4e0e\u62bd\u8c61\u7c7b"},{"location":"python/Demo/CourseSystem/","text":"\u9009\u8bfe\u7cfb\u7edf \u00b6 \u4efb\u52a1\u9700\u6c42 \u00b6 \u89d2\u8272\uff1a\u5b66\u6821\u3001\u5b66\u5458\u3001\u8bfe\u7a0b\u3001\u8bb2\u5e08 \u8981\u6c42\uff1a \u521b\u5efa\u5317\u4eac\u3001\u4e0a\u6d772\u6240\u5b66\u6821\u3002 \u521b\u5efaLinux\u3001Python\u3001go\u4e09\u4e2a\u8bfe\u7a0b\uff0cLinux\u548cPython\u5728\u5317\u4eac\u5f00\uff0cgo\u5728\u4e0a\u6d77\u5f00\u3002 \u8bfe\u7a0b\u5305\u542b\u5468\u671f\u3001\u4ef7\u683c\uff0c\u901a\u8fc7\u5b66\u6821\u521b\u5efa\u8bfe\u7a0b\u3002 \u901a\u8fc7\u5b66\u6821\u521b\u5efa\u73ed\u7ea7\uff0c\u73ed\u7ea7\u5173\u8054\u8bfe\u7a0b\u3001\u8bb2\u5e08\u3002 \u521b\u5efa\u8bb2\u5e08\u3002 \u521b\u5efa\u5b66\u5458\u65f6\uff0c\u9009\u62e9\u5b66\u6821\uff0c\u5173\u8054\u73ed\u7ea7\u3002 \u521b\u5efa\u8bb2\u5e08\u89d2\u8272\uff08\u4e0d\u9700\u8981\u5173\u8054\u5b66\u6821\uff09\u3002 \u63d0\u4f9b\u4e24\u4e2a\u89d2\u8272\u63a5\u53e3\u3002 \u5b66\u5458\u89c6\u56fe\uff1a\u53ef\u4ee5\u6ce8\u518c\uff0c\u4ea4\u5b66\u8d39\uff0c\u9009\u62e9\u73ed\u7ea7\u3002 \u8bb2\u5e08\u89c6\u56fe\uff1a\u8bb2\u5e08\u53ef\u4ee5\u7ba1\u7406\u81ea\u5df1\u7684\u73ed\u7ea7\uff0c\u4e0a\u8bfe\u65f6\u9009\u62e9\u73ed\u7ea7\uff0c\u67e5\u770b\u73ed\u7ea7\u5b66\u5458\u5217\u8868\uff0c\u4fee\u6539\u6240\u7ba1\u7406\u7684\u5b66\u5458\u7684\u6210\u7ee9\u3002 \u7ba1\u7406\u89c6\u56fe\uff1a\u521b\u5efa\u8bb2\u5e08\uff0c\u521b\u5efa\u73ed\u7ea7\uff0c\u521b\u5efa\u8bfe\u7a0b\u3002 \u4e0a\u8ff0\u64cd\u4f5c\u6240\u4ea7\u751f\u7684\u6570\u636e\u901a\u8fc7pickle\u4fdd\u5b58\u5230\u6587\u4ef6\u3002 \u9700\u6c42\u5206\u6790 \u00b6 \u7ba1\u7406\u89c6\u56fe \u6ce8\u518c \u767b\u5f55 \u521b\u5efa\u5b66\u6821 \u521b\u5efa\u8bfe\u7a0b\uff08\u5148\u9009\u62e9\u5b66\u6821\uff09 \u521b\u5efa\u8bb2\u5e08 \u5b66\u5458\u89c6\u56fe \u6ce8\u518c \u767b\u5f55\u529f\u80fd \u9009\u62e9\u6821\u533a \u9009\u62e9\u8bfe\u7a0b\uff08\u5148\u9009\u62e9\u6821\u533a\uff0c\u5728\u9009\u62e9\u6821\u533a\u4e2d\u7684\u67d0\u4e00\u95e8\u8bfe\u7a0b\uff0c\u9009\u62e9\u8bfe\u7a0b\u5373\u9009\u62e9\u73ed\u7ea7\uff09 \u5b66\u751f\u9009\u62e9\u8bfe\u7a0b\uff0c\u8bfe\u7a0b\u4e5f\u9009\u62e9\u5b66\u751f \u67e5\u770b\u5206\u6570 \u4ea4\u5b66\u8d39 \u8bb2\u5e08\u89c6\u56fe \u767b\u5f55 \u67e5\u770b\u6559\u6388\u8bfe\u7a0b \u9009\u62e9\u6559\u6388\u8bfe\u7a0b \u67e5\u770b\u8bfe\u7a0b\u4e0b\u7684\u5b66\u751f \u4fee\u6539\u5b66\u751f\u5206\u6570 \u67b6\u6784\u8bbe\u8ba1\uff08\u4e09\u5c42\u67b6\u6784\uff09 \u00b6 \u7528\u6237\u89c6\u56fe\u5c42 \u7528\u4e8e\u4e0e\u7528\u6237\u8fdb\u884c\u4ea4\u4e92\u3002 \u5b9e\u73b0\u7b80\u5355\u7684\u903b\u8f91\u5224\u65ad\uff0c\u6bd4\u5982\u6ce8\u518c\u529f\u80fd\u4e2d\u4e24\u6b21\u5bc6\u7801\u662f\u5426\u4e00\u81f4\u7684\u6821\u9a8c\u3002 core src.py \u4e3b\u89c6\u56fe admin.py: \u7ba1\u7406\u89c6\u56fe student.py: \u5b66\u5458\u89c6\u56fe teacher.py: \u8bb2\u5e08\u89c6\u56fe \u903b\u8f91\u63a5\u53e3\u5c42 \u6838\u5fc3\u4e1a\u52a1\u903b\u8f91\u7684\u5904\u7406 interface admin_interface.py studeng_interface.py teacher_interface.py \u6570\u636e\u5904\u7406\u5c42 \u6570\u636e\u5904\u7406\uff0c\u6bd4\u5982\u589e\u5220\u6539\u67e5\u3002 db models.py db_handler.py pickle\u4fdd\u5b58\u5bf9\u8c61 object \u2192 pickle \u6587\u4ef6\u7ed3\u6784 \u00b6 /--conf/ | |--settings.py | |--core/ | |--src.py | |--admin.py | |--student.py | |--teacher.py | |--db/ | |--models.py | |--db_handler.py | |--pickle | |--interface/ | |--admin_interface.py | |--student_interface.py | |--teacher_interface.py | |--common_interface.py | |--lib/ | |--common.py | |--start.py \u9009\u8bfe\u7cfb\u7edf\u603b\u7ed3 \u00b6 1.\u7ba1\u7406\u5458 \u00b6 1.1.\u6ce8\u518c \u00b6 \u7528\u6237\u518d\u89c6\u56fe\u5c42\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u4ea4\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u7684models.get()\u8fdb\u884c\u6821\u9a8c\u3002 \u82e5\u4e0d\u5b58\u5728\u5219\u521b\u5efa\uff0c\u5e76\u8bb2\u6ce8\u518c\u6210\u529f\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 1.2.\u767b\u5f55 \u00b6 \u7528\u6237\u5728\u89c6\u56fe\u5c42\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u4ea4\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u7684models.get()\u8fdb\u884c\u6821\u9a8c\u3002 \u82e5\u4e0d\u5b58\u5728\u5219\u521b\u5efa\uff0c\u5e76\u8bb2\u6ce8\u518c\u6210\u529f\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 1.3.\u521b\u5efa\u5b66\u6821 \u00b6 \u8ba9\u7528\u6237\u8f93\u5165\u5b66\u6821\u540d\u548c\u5b66\u6821\u5730\u5740\u3002 \u8c03\u7528\u7ba1\u7406\u5458\u63a5\u53e3\u521b\u5efa\u5b66\u6821\u3002 \u5224\u65ad\u5b66\u6821\u662f\u5426\u5b58\u5728\uff0c\u82e5\u5b58\u5728\uff0c\u4e0d\u521b\u5efa\u3002 \u82e5\u4e0d\u5b58\u5728\uff0c\u5219\u8c03\u7528\u63a5\u53e3\u5c42\u521b\u5efa\u5b66\u6821\uff0c\u83b7\u53d6\u7ba1\u7406\u5458\u5bf9\u8c61\u7684\u521b\u5efa\u5b66\u6821\u65b9\u6cd5\u4fdd\u6301\u5b66\u6821\u5bf9\u8c61\u3002 \u5c06\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 1.4.\u521b\u5efa\u8bfe\u7a0b \u00b6 \u83b7\u53d6\u6240\u6709\u5b66\u6821\uff0c\u5e76\u6253\u5370\uff0c\u8ba9\u7528\u6237\u9009\u62e9\u3002 \u83b7\u53d6\u7528\u6237\u9009\u62e9\u7684\u5b66\u6821\u4e0e\u521b\u5efa\u7684\u8bfe\u7a0b\uff0c\u4ea4\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u7ba1\u7406\u5458\u5bf9\u8c61\u4e2d\u7684\u521b\u5efa\u8bfe\u7a0b\u65b9\u6cd5\uff0c\u4fdd\u5b58\u8bfe\u7a0b\u5bf9\u8c61\u3002 \u8bfe\u7a0b\u9700\u8981\u7ed1\u5b9a\u7ed9\u5b66\u6821\u5bf9\u8c61\uff0c\u6700\u7ec8\u5c06\u521b\u5efa\u6210\u529f\u7684\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 1.5.\u521b\u5efa\u8001\u5e08 \u00b6 \u7528\u6237\u8f93\u5165\u8001\u5e08\u540d\u79f0\u3002 \u8c03\u7528\u63a5\u53e3\u5c42\uff0c\u63a5\u53e3\u5c42\u4e2d\u8bbe\u7f6e\u9ed8\u8ba4\u5bc6\u7801123\uff0c\u8c03\u7528\u6570\u636e\u5c42\u3002 \u5224\u65ad\u8001\u5e08\u662f\u5426\u5b58\u5728\uff0c\u4e0d\u5b58\u5728\u5219\u8c03\u7528\u7ba1\u7406\u5458\u5bf9\u8c61\u4e2d\u7684\u521b\u5efa\u8001\u5e08\u65b9\u6cd5\u3002 \u4fdd\u5b58\u8001\u5e08\u5bf9\u8c61\uff0c\u5e76\u5c06\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 2.\u5b66\u751f \u00b6 2.1.\u6ce8\u518c \u00b6 \u540c\u4e0a 2.2.\u767b\u5f55 \u00b6 \u540c\u4e0a 2.3.\u9009\u62e9\u5b66\u6821 \u00b6 \u83b7\u53d6\u6240\u6709\u5b66\u6821\uff0c\u8ba9\u5b66\u751f\u9009\u62e9\uff0c\u5e76\u5c06\u9009\u62e9\u7684\u5b66\u6821\u4f20\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u5224\u65ad\u5f53\u524d\u5b66\u751f\u662f\u5426\u9009\u62e9\u5b66\u6821\u3002 \u82e5\u6ca1\u6709\u9009\u62e9\uff0c\u5219\u8c03\u7528\u5b66\u751f\u5bf9\u8c61\u4e2d\u7684\u6dfb\u52a0\u5b66\u6821\u65b9\u6cd5\u3002 \u5c06\u6dfb\u52a0\u540e\u6d88\u606f\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 2.4.\u9009\u62e9\u8bfe\u7a0b \u00b6 \u5148\u83b7\u53d6\u5f53\u524d\u5b66\u751f\u6240\u5728\u5b66\u6821\u7684\u6240\u6709\u8bfe\u7a0b\uff0c\u5e76\u9009\u62e9\u3002 \u63a5\u53e3\u5c42\u5c06\u9009\u62e9\u540e\u7684\u8bfe\u7a0b\uff0c\u8c03\u7528\u6570\u636e\u5c42\u7684\u6dfb\u52a0\u8bfe\u7a0b\u65b9\u6cd5\u4fdd\u5b58\u3002 \u5b66\u751f\u5bf9\u8c61\u4e2d\u8bfe\u7a0b\u5217\u8868\u6dfb\u52a0\u8bfe\u7a0b\uff0c\u8bbe\u7f6e\u8bfe\u7a0b\u5206\u6570\uff0c\u9ed8\u8ba4\u4e3a0. \u6700\u7ec8\u5c06\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 2.5.\u67e5\u770b\u6210\u7ee9 \u00b6 \u76f4\u63a5\u8c03\u7528\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u7684\u67e5\u770b\u6210\u7ee9\u65b9\u6cd5\u3002 \u8fd4\u56de\u6210\u7ee9\u7ed9\u89c6\u56fe\u5c42\u5e76\u6253\u5370\u3002 3.\u8001\u5e08 \u00b6 3.1.\u767b\u5f55 \u00b6 \u540c\u4e0a 3.2.\u67e5\u770b\u6559\u6388\u8bfe\u7a0b \u00b6 \u76f4\u63a5\u8c03\u7528\u63a5\u53e3\u5c42\uff0c\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\u4e0b\u8bfe\u7a0b\u5217\u8868\u6570\u636e\u3002 \u82e5\u6709\u5219\u6253\u5370\uff0c\u6ca1\u6709\u5219\u9000\u51fa\u3002 3.3.\u9009\u62e9\u6559\u6388\u8bfe\u7a0b \u00b6 \u8c03\u7528\u63a5\u53e3\u5c42\u4e2d\u7684\u9009\u62e9\u6559\u6388\u8bfe\u7a0b\u63a5\u53e3\uff0c\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u6539\u8bfe\u7a0b\u4e0b\u6240\u6709\u7684\u5b66\u751f\uff0c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 \u6253\u5370\u6240\u6709\u7684\u8bfe\u7a0b\uff0c\u8ba9\u8001\u5e08\u9009\u62e9\uff0c\u82e5\u8001\u5e08\u8bfe\u7a0b\u4e2d\u6709\u8be5\u8bfe\u7a0b\u5219\u4e0d\u6dfb\u52a0\u3002 \u6ca1\u6709\uff0c\u5219\u55f2\u7528\u8001\u5e08\u5bf9\u8c61\u4e2d\u7684\u6dfb\u52a0\u8bfe\u7a0b\u65b9\u6cd5\u8fdb\u884c\u6dfb\u52a0\u3002 3.4.\u67e5\u770b\u8bfe\u7a0b\u4e0b\u7684\u5b66\u751f \u00b6 \u76f4\u63a5\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\u4e0b\u6240\u6709\u7684\u8bfe\u7a0b\uff0c\u9009\u62e9\u8bfe\u7a0b\u3002 \u4ece\u8001\u5e08\u5bf9\u8c61\u4e2d\uff0c\u8c03\u7528\u67e5\u770b\u8bfe\u7a0b\u4e0b\u5b66\u751f\u7684\u65b9\u6cd5\uff0c\u83b7\u53d6\u8bfe\u7a0b\u5bf9\u8c61\u4e0b\u7684\u6240\u6709\u5b66\u751f\uff0c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 \u89c6\u56fe\u5c42\u6253\u5370\u8be5\u8bfe\u7a0b\u4e0b\u6240\u6709\u7684\u5b66\u751f\u3002 3.5.\u4fee\u6539\u5b66\u751f\u5206\u6570 \u00b6 \u76f4\u63a5\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\u4e0b\u6240\u6709\u7684\u8bfe\u7a0b\u3002 \u4ece\u8001\u5e08\u5bf9\u8c61\u4e2d\uff0c\u8c03\u7528\u67e5\u770b\u8bfe\u7a0b\u4e0b\u5b66\u751f\u65b9\u6cd5\uff0c\u83b7\u53d6\u8bfe\u7a0b\u5bf9\u8c61\u4e0b\u6240\u6709\u7684\u5b66\u751f\uff0c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 \u89c6\u56fe\u5c42\u6253\u5370\u6539\u8bfe\u7a0b\u4e0b\u6240\u6709\u7684\u5b66\u751f\uff0c\u5e76\u8ba9\u7528\u6237\u9009\u62e9\u9700\u8981\u5206\u6570\u7684\u5b66\u751f\u3002 \u55f2\u7528\u8001\u5e08\u4fee\u6539\u5206\u6570\u63a5\u53e3\uff0c\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\uff0c\u8c03\u7528\u5bf9\u8c61\u4e2d\u4fee\u6539\u5206\u6570\u65b9\u6cd5\u3002 \u83b7\u53d6\u5b66\u751f\u5bf9\u8c61\u4e2d\u7684\u5206\u6570\u5b57\u5178\uff0c\u8fdb\u884c\u4fee\u6539\u3002 3.4.\u67e5\u770b\u6210\u7ee9 \u00b6 \u793a\u610f\u56fe \u00b6 \u53c2\u8003\u4ee3\u7801 \u00b6 \u4ee3\u7801","title":"\u9009\u8bfe\u7cfb\u7edf"},{"location":"python/Demo/CourseSystem/#_1","text":"","title":"\u9009\u8bfe\u7cfb\u7edf"},{"location":"python/Demo/CourseSystem/#_2","text":"\u89d2\u8272\uff1a\u5b66\u6821\u3001\u5b66\u5458\u3001\u8bfe\u7a0b\u3001\u8bb2\u5e08 \u8981\u6c42\uff1a \u521b\u5efa\u5317\u4eac\u3001\u4e0a\u6d772\u6240\u5b66\u6821\u3002 \u521b\u5efaLinux\u3001Python\u3001go\u4e09\u4e2a\u8bfe\u7a0b\uff0cLinux\u548cPython\u5728\u5317\u4eac\u5f00\uff0cgo\u5728\u4e0a\u6d77\u5f00\u3002 \u8bfe\u7a0b\u5305\u542b\u5468\u671f\u3001\u4ef7\u683c\uff0c\u901a\u8fc7\u5b66\u6821\u521b\u5efa\u8bfe\u7a0b\u3002 \u901a\u8fc7\u5b66\u6821\u521b\u5efa\u73ed\u7ea7\uff0c\u73ed\u7ea7\u5173\u8054\u8bfe\u7a0b\u3001\u8bb2\u5e08\u3002 \u521b\u5efa\u8bb2\u5e08\u3002 \u521b\u5efa\u5b66\u5458\u65f6\uff0c\u9009\u62e9\u5b66\u6821\uff0c\u5173\u8054\u73ed\u7ea7\u3002 \u521b\u5efa\u8bb2\u5e08\u89d2\u8272\uff08\u4e0d\u9700\u8981\u5173\u8054\u5b66\u6821\uff09\u3002 \u63d0\u4f9b\u4e24\u4e2a\u89d2\u8272\u63a5\u53e3\u3002 \u5b66\u5458\u89c6\u56fe\uff1a\u53ef\u4ee5\u6ce8\u518c\uff0c\u4ea4\u5b66\u8d39\uff0c\u9009\u62e9\u73ed\u7ea7\u3002 \u8bb2\u5e08\u89c6\u56fe\uff1a\u8bb2\u5e08\u53ef\u4ee5\u7ba1\u7406\u81ea\u5df1\u7684\u73ed\u7ea7\uff0c\u4e0a\u8bfe\u65f6\u9009\u62e9\u73ed\u7ea7\uff0c\u67e5\u770b\u73ed\u7ea7\u5b66\u5458\u5217\u8868\uff0c\u4fee\u6539\u6240\u7ba1\u7406\u7684\u5b66\u5458\u7684\u6210\u7ee9\u3002 \u7ba1\u7406\u89c6\u56fe\uff1a\u521b\u5efa\u8bb2\u5e08\uff0c\u521b\u5efa\u73ed\u7ea7\uff0c\u521b\u5efa\u8bfe\u7a0b\u3002 \u4e0a\u8ff0\u64cd\u4f5c\u6240\u4ea7\u751f\u7684\u6570\u636e\u901a\u8fc7pickle\u4fdd\u5b58\u5230\u6587\u4ef6\u3002","title":"\u4efb\u52a1\u9700\u6c42"},{"location":"python/Demo/CourseSystem/#_3","text":"\u7ba1\u7406\u89c6\u56fe \u6ce8\u518c \u767b\u5f55 \u521b\u5efa\u5b66\u6821 \u521b\u5efa\u8bfe\u7a0b\uff08\u5148\u9009\u62e9\u5b66\u6821\uff09 \u521b\u5efa\u8bb2\u5e08 \u5b66\u5458\u89c6\u56fe \u6ce8\u518c \u767b\u5f55\u529f\u80fd \u9009\u62e9\u6821\u533a \u9009\u62e9\u8bfe\u7a0b\uff08\u5148\u9009\u62e9\u6821\u533a\uff0c\u5728\u9009\u62e9\u6821\u533a\u4e2d\u7684\u67d0\u4e00\u95e8\u8bfe\u7a0b\uff0c\u9009\u62e9\u8bfe\u7a0b\u5373\u9009\u62e9\u73ed\u7ea7\uff09 \u5b66\u751f\u9009\u62e9\u8bfe\u7a0b\uff0c\u8bfe\u7a0b\u4e5f\u9009\u62e9\u5b66\u751f \u67e5\u770b\u5206\u6570 \u4ea4\u5b66\u8d39 \u8bb2\u5e08\u89c6\u56fe \u767b\u5f55 \u67e5\u770b\u6559\u6388\u8bfe\u7a0b \u9009\u62e9\u6559\u6388\u8bfe\u7a0b \u67e5\u770b\u8bfe\u7a0b\u4e0b\u7684\u5b66\u751f \u4fee\u6539\u5b66\u751f\u5206\u6570","title":"\u9700\u6c42\u5206\u6790"},{"location":"python/Demo/CourseSystem/#_4","text":"\u7528\u6237\u89c6\u56fe\u5c42 \u7528\u4e8e\u4e0e\u7528\u6237\u8fdb\u884c\u4ea4\u4e92\u3002 \u5b9e\u73b0\u7b80\u5355\u7684\u903b\u8f91\u5224\u65ad\uff0c\u6bd4\u5982\u6ce8\u518c\u529f\u80fd\u4e2d\u4e24\u6b21\u5bc6\u7801\u662f\u5426\u4e00\u81f4\u7684\u6821\u9a8c\u3002 core src.py \u4e3b\u89c6\u56fe admin.py: \u7ba1\u7406\u89c6\u56fe student.py: \u5b66\u5458\u89c6\u56fe teacher.py: \u8bb2\u5e08\u89c6\u56fe \u903b\u8f91\u63a5\u53e3\u5c42 \u6838\u5fc3\u4e1a\u52a1\u903b\u8f91\u7684\u5904\u7406 interface admin_interface.py studeng_interface.py teacher_interface.py \u6570\u636e\u5904\u7406\u5c42 \u6570\u636e\u5904\u7406\uff0c\u6bd4\u5982\u589e\u5220\u6539\u67e5\u3002 db models.py db_handler.py pickle\u4fdd\u5b58\u5bf9\u8c61 object \u2192 pickle","title":"\u67b6\u6784\u8bbe\u8ba1\uff08\u4e09\u5c42\u67b6\u6784\uff09"},{"location":"python/Demo/CourseSystem/#_5","text":"/--conf/ | |--settings.py | |--core/ | |--src.py | |--admin.py | |--student.py | |--teacher.py | |--db/ | |--models.py | |--db_handler.py | |--pickle | |--interface/ | |--admin_interface.py | |--student_interface.py | |--teacher_interface.py | |--common_interface.py | |--lib/ | |--common.py | |--start.py","title":"\u6587\u4ef6\u7ed3\u6784"},{"location":"python/Demo/CourseSystem/#_6","text":"","title":"\u9009\u8bfe\u7cfb\u7edf\u603b\u7ed3"},{"location":"python/Demo/CourseSystem/#1","text":"","title":"1.\u7ba1\u7406\u5458"},{"location":"python/Demo/CourseSystem/#11","text":"\u7528\u6237\u518d\u89c6\u56fe\u5c42\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u4ea4\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u7684models.get()\u8fdb\u884c\u6821\u9a8c\u3002 \u82e5\u4e0d\u5b58\u5728\u5219\u521b\u5efa\uff0c\u5e76\u8bb2\u6ce8\u518c\u6210\u529f\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"1.1.\u6ce8\u518c"},{"location":"python/Demo/CourseSystem/#12","text":"\u7528\u6237\u5728\u89c6\u56fe\u5c42\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u4ea4\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u7684models.get()\u8fdb\u884c\u6821\u9a8c\u3002 \u82e5\u4e0d\u5b58\u5728\u5219\u521b\u5efa\uff0c\u5e76\u8bb2\u6ce8\u518c\u6210\u529f\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"1.2.\u767b\u5f55"},{"location":"python/Demo/CourseSystem/#13","text":"\u8ba9\u7528\u6237\u8f93\u5165\u5b66\u6821\u540d\u548c\u5b66\u6821\u5730\u5740\u3002 \u8c03\u7528\u7ba1\u7406\u5458\u63a5\u53e3\u521b\u5efa\u5b66\u6821\u3002 \u5224\u65ad\u5b66\u6821\u662f\u5426\u5b58\u5728\uff0c\u82e5\u5b58\u5728\uff0c\u4e0d\u521b\u5efa\u3002 \u82e5\u4e0d\u5b58\u5728\uff0c\u5219\u8c03\u7528\u63a5\u53e3\u5c42\u521b\u5efa\u5b66\u6821\uff0c\u83b7\u53d6\u7ba1\u7406\u5458\u5bf9\u8c61\u7684\u521b\u5efa\u5b66\u6821\u65b9\u6cd5\u4fdd\u6301\u5b66\u6821\u5bf9\u8c61\u3002 \u5c06\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"1.3.\u521b\u5efa\u5b66\u6821"},{"location":"python/Demo/CourseSystem/#14","text":"\u83b7\u53d6\u6240\u6709\u5b66\u6821\uff0c\u5e76\u6253\u5370\uff0c\u8ba9\u7528\u6237\u9009\u62e9\u3002 \u83b7\u53d6\u7528\u6237\u9009\u62e9\u7684\u5b66\u6821\u4e0e\u521b\u5efa\u7684\u8bfe\u7a0b\uff0c\u4ea4\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u7ba1\u7406\u5458\u5bf9\u8c61\u4e2d\u7684\u521b\u5efa\u8bfe\u7a0b\u65b9\u6cd5\uff0c\u4fdd\u5b58\u8bfe\u7a0b\u5bf9\u8c61\u3002 \u8bfe\u7a0b\u9700\u8981\u7ed1\u5b9a\u7ed9\u5b66\u6821\u5bf9\u8c61\uff0c\u6700\u7ec8\u5c06\u521b\u5efa\u6210\u529f\u7684\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"1.4.\u521b\u5efa\u8bfe\u7a0b"},{"location":"python/Demo/CourseSystem/#15","text":"\u7528\u6237\u8f93\u5165\u8001\u5e08\u540d\u79f0\u3002 \u8c03\u7528\u63a5\u53e3\u5c42\uff0c\u63a5\u53e3\u5c42\u4e2d\u8bbe\u7f6e\u9ed8\u8ba4\u5bc6\u7801123\uff0c\u8c03\u7528\u6570\u636e\u5c42\u3002 \u5224\u65ad\u8001\u5e08\u662f\u5426\u5b58\u5728\uff0c\u4e0d\u5b58\u5728\u5219\u8c03\u7528\u7ba1\u7406\u5458\u5bf9\u8c61\u4e2d\u7684\u521b\u5efa\u8001\u5e08\u65b9\u6cd5\u3002 \u4fdd\u5b58\u8001\u5e08\u5bf9\u8c61\uff0c\u5e76\u5c06\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"1.5.\u521b\u5efa\u8001\u5e08"},{"location":"python/Demo/CourseSystem/#2","text":"","title":"2.\u5b66\u751f"},{"location":"python/Demo/CourseSystem/#21","text":"\u540c\u4e0a","title":"2.1.\u6ce8\u518c"},{"location":"python/Demo/CourseSystem/#22","text":"\u540c\u4e0a","title":"2.2.\u767b\u5f55"},{"location":"python/Demo/CourseSystem/#23","text":"\u83b7\u53d6\u6240\u6709\u5b66\u6821\uff0c\u8ba9\u5b66\u751f\u9009\u62e9\uff0c\u5e76\u5c06\u9009\u62e9\u7684\u5b66\u6821\u4f20\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u5224\u65ad\u5f53\u524d\u5b66\u751f\u662f\u5426\u9009\u62e9\u5b66\u6821\u3002 \u82e5\u6ca1\u6709\u9009\u62e9\uff0c\u5219\u8c03\u7528\u5b66\u751f\u5bf9\u8c61\u4e2d\u7684\u6dfb\u52a0\u5b66\u6821\u65b9\u6cd5\u3002 \u5c06\u6dfb\u52a0\u540e\u6d88\u606f\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"2.3.\u9009\u62e9\u5b66\u6821"},{"location":"python/Demo/CourseSystem/#24","text":"\u5148\u83b7\u53d6\u5f53\u524d\u5b66\u751f\u6240\u5728\u5b66\u6821\u7684\u6240\u6709\u8bfe\u7a0b\uff0c\u5e76\u9009\u62e9\u3002 \u63a5\u53e3\u5c42\u5c06\u9009\u62e9\u540e\u7684\u8bfe\u7a0b\uff0c\u8c03\u7528\u6570\u636e\u5c42\u7684\u6dfb\u52a0\u8bfe\u7a0b\u65b9\u6cd5\u4fdd\u5b58\u3002 \u5b66\u751f\u5bf9\u8c61\u4e2d\u8bfe\u7a0b\u5217\u8868\u6dfb\u52a0\u8bfe\u7a0b\uff0c\u8bbe\u7f6e\u8bfe\u7a0b\u5206\u6570\uff0c\u9ed8\u8ba4\u4e3a0. \u6700\u7ec8\u5c06\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"2.4.\u9009\u62e9\u8bfe\u7a0b"},{"location":"python/Demo/CourseSystem/#25","text":"\u76f4\u63a5\u8c03\u7528\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u7684\u67e5\u770b\u6210\u7ee9\u65b9\u6cd5\u3002 \u8fd4\u56de\u6210\u7ee9\u7ed9\u89c6\u56fe\u5c42\u5e76\u6253\u5370\u3002","title":"2.5.\u67e5\u770b\u6210\u7ee9"},{"location":"python/Demo/CourseSystem/#3","text":"","title":"3.\u8001\u5e08"},{"location":"python/Demo/CourseSystem/#31","text":"\u540c\u4e0a","title":"3.1.\u767b\u5f55"},{"location":"python/Demo/CourseSystem/#32","text":"\u76f4\u63a5\u8c03\u7528\u63a5\u53e3\u5c42\uff0c\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\u4e0b\u8bfe\u7a0b\u5217\u8868\u6570\u636e\u3002 \u82e5\u6709\u5219\u6253\u5370\uff0c\u6ca1\u6709\u5219\u9000\u51fa\u3002","title":"3.2.\u67e5\u770b\u6559\u6388\u8bfe\u7a0b"},{"location":"python/Demo/CourseSystem/#33","text":"\u8c03\u7528\u63a5\u53e3\u5c42\u4e2d\u7684\u9009\u62e9\u6559\u6388\u8bfe\u7a0b\u63a5\u53e3\uff0c\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u6539\u8bfe\u7a0b\u4e0b\u6240\u6709\u7684\u5b66\u751f\uff0c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 \u6253\u5370\u6240\u6709\u7684\u8bfe\u7a0b\uff0c\u8ba9\u8001\u5e08\u9009\u62e9\uff0c\u82e5\u8001\u5e08\u8bfe\u7a0b\u4e2d\u6709\u8be5\u8bfe\u7a0b\u5219\u4e0d\u6dfb\u52a0\u3002 \u6ca1\u6709\uff0c\u5219\u55f2\u7528\u8001\u5e08\u5bf9\u8c61\u4e2d\u7684\u6dfb\u52a0\u8bfe\u7a0b\u65b9\u6cd5\u8fdb\u884c\u6dfb\u52a0\u3002","title":"3.3.\u9009\u62e9\u6559\u6388\u8bfe\u7a0b"},{"location":"python/Demo/CourseSystem/#34","text":"\u76f4\u63a5\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\u4e0b\u6240\u6709\u7684\u8bfe\u7a0b\uff0c\u9009\u62e9\u8bfe\u7a0b\u3002 \u4ece\u8001\u5e08\u5bf9\u8c61\u4e2d\uff0c\u8c03\u7528\u67e5\u770b\u8bfe\u7a0b\u4e0b\u5b66\u751f\u7684\u65b9\u6cd5\uff0c\u83b7\u53d6\u8bfe\u7a0b\u5bf9\u8c61\u4e0b\u7684\u6240\u6709\u5b66\u751f\uff0c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 \u89c6\u56fe\u5c42\u6253\u5370\u8be5\u8bfe\u7a0b\u4e0b\u6240\u6709\u7684\u5b66\u751f\u3002","title":"3.4.\u67e5\u770b\u8bfe\u7a0b\u4e0b\u7684\u5b66\u751f"},{"location":"python/Demo/CourseSystem/#35","text":"\u76f4\u63a5\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\u4e0b\u6240\u6709\u7684\u8bfe\u7a0b\u3002 \u4ece\u8001\u5e08\u5bf9\u8c61\u4e2d\uff0c\u8c03\u7528\u67e5\u770b\u8bfe\u7a0b\u4e0b\u5b66\u751f\u65b9\u6cd5\uff0c\u83b7\u53d6\u8bfe\u7a0b\u5bf9\u8c61\u4e0b\u6240\u6709\u7684\u5b66\u751f\uff0c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 \u89c6\u56fe\u5c42\u6253\u5370\u6539\u8bfe\u7a0b\u4e0b\u6240\u6709\u7684\u5b66\u751f\uff0c\u5e76\u8ba9\u7528\u6237\u9009\u62e9\u9700\u8981\u5206\u6570\u7684\u5b66\u751f\u3002 \u55f2\u7528\u8001\u5e08\u4fee\u6539\u5206\u6570\u63a5\u53e3\uff0c\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\uff0c\u8c03\u7528\u5bf9\u8c61\u4e2d\u4fee\u6539\u5206\u6570\u65b9\u6cd5\u3002 \u83b7\u53d6\u5b66\u751f\u5bf9\u8c61\u4e2d\u7684\u5206\u6570\u5b57\u5178\uff0c\u8fdb\u884c\u4fee\u6539\u3002","title":"3.5.\u4fee\u6539\u5b66\u751f\u5206\u6570"},{"location":"python/Demo/CourseSystem/#34_1","text":"","title":"3.4.\u67e5\u770b\u6210\u7ee9"},{"location":"python/Demo/CourseSystem/#_7","text":"","title":"\u793a\u610f\u56fe"},{"location":"python/Demo/CourseSystem/#_8","text":"\u4ee3\u7801","title":"\u53c2\u8003\u4ee3\u7801"},{"location":"python/Foundation/Algorithms/","text":"Python\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5 \u00b6 \u53c2\u8003\u4e66\u76ee\uff1a \"Problem Solving with Algorithms and Data Structures Using Python (Second Edition)\" by Bradley N.Miller and David L.Ranum. \u5927O\u8bb0\u6cd5 \u00b6 \u7b97\u6cd5\u5206\u6790\u662f\u4e00\u79cd\u72ec\u7acb\u4e8e\u5b9e\u73b0\u7684\u7b97\u6cd5\u5ea6\u91cf\u65b9\u6cd5\u3002 \u6570\u91cf\u7ea7\uff08order of magnitude\uff09\u5e38\u88ab\u79f0\u4f5c\u5927O\u8bb0\u6cd5\uff08O\u6307order\uff09\uff0c\u8bb0\u4f5cO(f(n))\u3002\u5b83\u63d0\u4f9b\u4e86\u6b65\u9aa4\u6570\u7684\u4e00\u4e2a\u6709\u7528\u7684\u8fd1\u4f3c\u65b9\u6cd5\u3002f(n)\u51fd\u6570\u4e3aT(n)\u51fd\u6570\u4e2d\u8d77\u51b3\u5b9a\u6027\u4f5c\u7528\u7684\u90e8\u5206\u63d0\u4f9b\u4e86\u7b80\u5355\u7684\u8868\u793a\u3002 \u5927O\u8bb0\u6cd5\u4f7f\u5f97\u7b97\u6cd5\u53ef\u4ee5\u6839\u636e\u968f\u95ee\u9898\u89c4\u6a21\u589e\u957f\u800c\u8d77\u4e3b\u5bfc\u4f5c\u7528\u7684\u90e8\u5206\u8fdb\u884c\u5f52\u7c7b\u3002 \u5f02\u5e8f\u8bcd\u68c0\u6d4b\u95ee\u9898 \u00b6 \u5982\u679c\u4e00\u4e2a\u5b57\u7b26\u4e32\u53ea\u662f\u91cd\u6392\u4e86\u53e6\u4e00\u4e2a\u5b57\u7b26\u4e32\u7684\u5b57\u7b26\uff0c\u90a3\u4e48\u8fd9\u4e2a\u5b57\u7b26\u4e32\u5c31\u662f\u53e6\u4e00\u4e2a\u7684\u5f02\u5e8f\u8bcd\u3002 \u65b9\u68481\uff1a\u6e05\u70b9\u6cd5 \u6e05\u70b9\u7b2c1\u4e2a\u5b57\u7b26\u4e32\u7684\u6bcf\u4e2a\u5b57\u7b26\uff0c\u770b\u770b\u5b83\u4eec\u662f\u5426\u90fd\u51fa\u73b0\u5728\u7b2c2\u4e2a\u5b57\u7b26\u4e32\u4e2d\u3002 \u5728\u5b57\u7b26\u5217\u8868\u4e2d\u68c0\u67e5\u7b2c1\u4e2a\u5b57\u7b26\u4e32\u4e2d\u7684\u6bcf\u4e2a\u5b57\u7b26\uff0c\u5982\u679c\u627e\u5230\u4e86\uff0c\u5c31\u66ff\u6362\u6389\u3002 \u8fd9\u4e2a\u65b9\u6848\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n^2)\u3002 def allotropyWord_1 ( s1 , s2 ): list_a = list ( s2 ) pos1 = 0 stillOK = True while pos1 < len ( s1 ) and stillOK : pos2 = 0 found = False while pos2 < len ( list_a ) and not found : if s1 [ pos1 ] == list_a [ pos2 ]: found = True else : pos2 = pos2 + 1 if found : list_a [ pos2 ] = None else : stillOK = False pos1 = pos1 + 1 return stillOK \u8fd0\u884c\uff1a allotropyWord_1 ( 'hello' , 'olleh' ) \u6ce8\u610flist_a\u7684\u53d8\u5316\u8fc7\u7a0b(\u5339\u914d\u5230\u5373\u66ff\u6362None)\u3002 [ 'o' , 'l' , 'l' , 'e' , None ] [ 'o' , 'l' , 'l' , None , None ] [ 'o' , None , 'l' , None , None ] [ 'o' , None , None , None , None ] [ None , None , None , None , None ] \u65b9\u68482\uff1a\u6392\u5e8f\u6cd5 \u6309\u7167\u5b57\u6bcd\u8868\u987a\u5e8f\u7ed9\u5b57\u7b26\u6392\u5e8f\uff0c\u5f02\u5e8f\u8bcd\u5f97\u5230\u7684\u7ed3\u679c\u5c06\u662f\u540c\u4e00\u4e2a\u5b57\u7b26\u4e32\u3002 \u8fd9\u4e2a\u65b9\u6848\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n^2)\u3002 def allotropyWord_2 ( s1 , s2 ): list1 = list ( s1 ) list2 = list ( s2 ) list1 . sort () list2 . sort () pos = 0 matched = True while pos < len ( s1 ) and matched : if list1 [ pos ] == list2 [ pos ]: pos = pos + 1 else : matched = False return matched \u8fd0\u884c\uff1a allotropyWord_2 ( 'hello' , 'olleh' ) \u65b9\u68483\uff1a\u8ba1\u6570\u6cd5 \u4e24\u4e2a\u5f02\u5e8f\u8bcd\u6709\u540c\u6837\u6570\u76ee\u7684a\u3001\u540c\u6837\u6570\u76ee\u7684b\u3001\u540c\u6837\u6570\u76ee\u7684c\uff0c\u7b49\u7b49\u3002 \u4f7f\u752826\u4e2a\u8ba1\u6570\u5668\uff0c\u5bf9\u5e94\u6bcf\u4e2a\u5b57\u7b26\u3002\u6bcf\u9047\u5230\u4e00\u4e2a\u5b57\u7b26\uff0c\u5c31\u5c06\u5bf9\u5e94\u7684\u8ba1\u6570\u5668\u52a01\u3002 \u5982\u679c\u4e24\u4e2a\u8ba1\u6570\u5668\u5217\u8868\u76f8\u540c\uff0c\u90a3\u4e48\u4e24\u4e2a\u5b57\u7b26\u4e32\u80af\u5b9a\u662f\u5f02\u5e8f\u8bcd\u3002 \u8fd9\u4e2a\u65b9\u6848\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\u3002 def allotropyWord_3 ( s1 , s2 ): c1 = [ 0 ] * 26 c2 = [ 0 ] * 26 for i in range ( len ( s1 )): # \u6bcf\u4e2a\u5b57\u7b26\u7684ASCII\u7801\u4e0e\u5b57\u7b26a\u7684ASCII\u7801\u7684\u5dee\u503c(\u504f\u79fb\u91cf) pos = ord ( s1 [ i ]) - ord ( 'a' ) c1 [ pos ] = c1 [ pos ] + 1 for i in range ( len ( s2 )): pos = ord ( s2 [ i ]) - ord ( 'a' ) c2 [ pos ] = c2 [ pos ] + 1 j = 0 stillOK = True while j < 26 and stillOK : if c1 [ j ] == c2 [ j ]: j = j + 1 else : stillOK = False return stillOK \u8fd0\u884c\uff1a allotropyWord_3 ( 'hello' , 'olleh' ) \u53c2\u8003\uff1a Python\u7684\u65f6\u95f4\u590d\u6742\u5ea6(Time Complexity) \u7ebf\u6027\u6570\u636e\u7ed3\u6784 \u00b6 \u771f\u6b63\u533a\u5206\u7ebf\u6027\u6570\u636e\u7ed3\u6784\u7684\u662f\u5143\u7d20\u7684\u6dfb\u52a0\u65b9\u5f0f\u548c\u79fb\u9664\u65b9\u5f0f\uff0c\u5c24\u5176\u662f\u6dfb\u52a0\u64cd\u4f5c\u548c\u79fb\u9664\u64cd\u4f5c\u53d1\u751f\u7684\u4f4d\u7f6e\u3002 \u6808 \u00b6 \u6808\u6709\u65f6\u4e5f\u88ab\u79f0\u4f5c\u201c\u4e0b\u63a8\u6808\u201d\u3002\u5b83\u662f\u6709\u5e8f\u96c6\u5408\uff0c\u6dfb\u52a0\u64cd\u4f5c\u548c\u79fb\u9664\u64cd\u4f5c\u603b\u53d1\u751f\u5728\u540c\u4e00\u7aef\uff0c\u5373\u201c\u9876\u7aef\u201d\uff0c\u53e6\u4e00\u7aef\u5219\u88ab\u79f0\u4e3a\u201c\u5e95\u7aef\u201d\u3002 \u6700\u65b0\u6dfb\u52a0\u7684\u5143\u7d20\u5c06\u88ab\u6700\u5148\u79fb\u9664\u3002\u8fd9\u79cd\u6392\u5e8f\u539f\u5219\u88ab\u79f0\u4f5cLIFO\uff08last-in first-out\uff09\uff0c\u5373\u540e\u8fdb\u5148\u51fa\u3002 \u6808\u7684\u53cd\u8f6c\u7279\u6027\u3002 \u6808\u7684\u5b9e\u73b0\u65b9\u6cd51: append() \u548c pop() \u7684\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662fO(1)\uff0c\u6240\u4ee5\u4e0d\u8bba\u6808\u4e2d\u6709\u591a\u5c11\u4e2a\u5143\u7d20\uff0c push \u64cd\u4f5c\u548c pop \u64cd\u4f5c\u90fd\u4f1a\u5728\u6052\u5b9a\u7684\u65f6\u95f4\u5185\u5b8c\u6210\u3002 class Stack (): def __init__ ( self ) -> None : self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . append ( item ) def pop ( self ): return self . items . pop () def peek ( self ): return self . items [ len ( self . items ) - 1 ] def size ( self ): return len ( self . items ) \u6808\u7684\u5b9e\u73b0\u65b9\u6cd52: insert(0) \u548c pop(0) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662fO(n)\uff0c\u5143\u7d20\u8d8a\u591a\u5c31\u8d8a\u6162\uff0c\u6027\u80fd\u5219\u53d7\u5236\u4e8e\u6808\u4e2d\u7684\u5143\u7d20\u4e2a\u6570\u3002 class Stack (): def __init__ ( self ) -> None : self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . insert ( 0 , item ) def pop ( self ): return self . items . pop ( 0 ) def peek ( self ): return self . items [ 0 ] def size ( self ): return len ( self . items ) \u5bf9\u4e0a\u9762\u7684\u5b9e\u73b0\uff0c\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u8fdb\u884c\u5206\u522b\u9a8c\u8bc1\uff1a s = Stack () s . isEmpty () s . push ( 3 ) s . push ( 'dog' ) s . peek () s . size () s . isEmpty () s . push ( 6.6 ) s . pop () s . size () \u62ec\u53f7\u5339\u914d\u95ee\u9898 \u00b6 #!/usr/bin/python3 #!/usr/bin/env python3 # -*- coding: utf-8 -*- class Stack (): def __init__ ( self ): self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . append ( item ) def pop ( self ): return self . items . pop () def peek ( self ): return self . items [ len ( self . items ) - 1 ] def size ( self ): return len ( self . items ) # \u5173\u8054\u5de6\u53f3\u62ec\u53f7 def matches ( open , close ): opens = \"([{\" closers = \")]}\" # \u7b26\u5408\u5173\u8054\u7684\uff0c\u8fd4\u56deTrue return opens . index ( open ) == closers . index ( close ) def parChecker ( symbolString ): s = Stack () matched = True index = 0 # \u8bfb\u53d6\u8f93\u5165\u5b57\u4e32\u6bcf\u4e2a\u5b57\u7b26 while index < len ( symbolString ) and matched : symbol = symbolString [ index ] if symbol in \"([{\" : # \u5de6\u62ec\u53f7\u5165\u6808 s . push ( symbol ) else : if s . isEmpty (): # \u9047\u5230\u975e\u5de6\u62ec\u53f7\u5b57\u7b26\uff0c\u5982\u4e3a\u7a7a\uff0c\u5219\u9000\u51fa\u5faa\u73af matched = False else : top = s . pop () # \u9047\u5230\u975e\u5de6\u62ec\u53f7\u5b57\u7b26\uff0c\u5982\u4e0d\u4e3a\u7a7a\uff0c\u5219\u51fa\u6808\uff0c\u5e76\u5224\u65ad\u662f\u5426\u672a\u4e3a\u5bf9\u5e94\u7684\u53f3\u62ec\u53f7 if not matches ( top , symbol ): # \u5426\u5219\u9000\u51fa\u5faa\u73af matched = False index = index + 1 # \u5b8c\u6210\u6bcf\u4e2a\u5b57\u7b26\u7684\u51fa\u5165\u6808\u68c0\u67e5\uff0c\u5f53\u524d\u6808\u4e3a\u7a7a\uff0c\u4e14\u90fd\u5339\u914d\uff0c\u5219\u8fd4\u56deTrue if matched and s . isEmpty (): return True else : return False if __name__ == '__main__' : parChecker ( \"([[ {} ])\" ) parChecker ( \"([ {} ])\" ) \u6267\u884c\u7ed3\u679c\u5982\u4e0b\uff0c\u7b26\u5408\u9884\u671f\u3002 False True \u8fdb\u5236\u8f6c\u6362\u95ee\u9898 \u00b6 \u4f8b\u5982\uff0c\u4f7f\u7528\u201c\u9664\u4ee52\u201d\u7684\u7b97\u6cd5\uff0c\u5341\u8fdb\u5236\u6570\u8f6c\u6362\u6210\u4e8c\u8fdb\u5236\u6570\uff0c\u5229\u7528\u6808\u6765\u4fdd\u5b58\u4e8c\u8fdb\u5236\u7ed3\u679c\u7684\u6bcf\u4e00\u4f4d\u3002 \u201c\u9664\u4ee52\u201d\u7b97\u6cd5\u5047\u8bbe\u5f85\u5904\u7406\u7684\u6574\u6570\u5927\u4e8e0\u3002 \u5b83\u7528\u4e00\u4e2a\u7b80\u5355\u7684\u5faa\u73af\u4e0d\u505c\u5730\u5c06\u5341\u8fdb\u5236\u6570\u9664\u4ee52\uff0c\u5e76\u4e14\u8bb0\u5f55\u4f59\u6570\u3002 \u7b2c\u4e00\u6b21\u9664\u4ee52\u7684\u7ed3\u679c\u80fd\u591f\u7528\u4e8e\u533a\u5206\u5076\u6570\u548c\u5947\u6570\u3002 \u5982\u679c\u662f\u5076\u6570\uff0c\u5219\u4f59\u6570\u4e3a0\uff0c\u56e0\u6b64\u4e2a\u4f4d\u4e0a\u7684\u6570\u5b57\u4e3a0\uff1b \u5982\u679c\u662f\u5947\u6570\uff0c\u5219\u4f59\u6570\u4e3a1\uff0c\u56e0\u6b64\u4e2a\u4f4d\u4e0a\u7684\u6570\u5b57\u4e3a1\u3002 \u53ef\u4ee5\u5c06\u8981\u6784\u5efa\u7684\u4e8c\u8fdb\u5236\u6570\u770b\u6210\u4e00\u7cfb\u5217\u6570\u5b57\uff1b\u8ba1\u7b97\u51fa\u7684\u7b2c\u4e00\u4e2a\u4f59\u6570\u662f\u6700\u540e\u4e00\u4f4d\u3002 \u8fd9\u4f53\u73b0\u4e86\u53cd\u8f6c\u7279\u6027\uff0c\u56e0\u6b64\u9002\u7528\u6808\u6765\u5904\u7406\u3002 class Stack (): def __init__ ( self ): self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . append ( item ) def pop ( self ): return self . items . pop () def peek ( self ): return self . items [ len ( self . items ) - 1 ] def size ( self ): return len ( self . items ) def decConverter ( decNumber , baseNumber ): remstack = Stack () digits = \"0123456789ABCDEF\" while decNumber > 0 : rem = decNumber % baseNumber remstack . push ( rem ) decNumber = decNumber // baseNumber newString = \"\" while not remstack . isEmpty (): newString = newString + digits [ remstack . pop ()] return newString if __name__ == '__main__' : decConverter ( 233 , 2 ) decConverter ( 233 , 8 ) decConverter ( 233 , 10 ) decConverter ( 233 , 16 ) \u8fd0\u884c\u7ed3\u679c\uff1a '11101001' '351' '233' 'E9' \u961f\u5217 \u00b6 \u4f7f\u7528 insert() \u5411\u961f\u5217\u7684\u5c3e\u90e8\u6dfb\u52a0\u65b0\u5143\u7d20\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\u3002 \u4f7f\u7528 pop() \u79fb\u9664\u961f\u5217\u5934\u90e8\u7684\u5143\u7d20\uff08\u5217\u8868\u4e2d\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff09\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(1)\u3002 class Queue (): def __init__ ( self ): self . items = [] def isEmpty ( self ): return self . items == [] def enqueue ( self , item ): return self . items . insert ( 0 , item ) def dequeue ( self ): return self . items . pop () def size ( self ): return len ( self . items ) if __name__ == '__main__' : q = Queue () q . isEmpty () q . enqueue ( 2 ) q . enqueue ( 'h' ) q . size () q . isEmpty () q . dequeue () q . size () \u8fd0\u884c\u7ed3\u679c: True 2 False 2 1 \u7ea6\u745f\u592b\u65af\u95ee\u9898 \u00b6 \u901a\u8fc7\u6a21\u62df\u5b9e\u73b0\u4f20\u571f\u8c46\u6e38\u620f\u6765\u89e3\u91ca\u7ea6\u745f\u592b\u65af\u95ee\u9898\u3002 ```python class Queue(): def init (self): self.items = [] def isEmpty(self): return self.items == [] def enqueue(self, item): return self.items.insert(0, item) def dequeue(self): return self.items.pop() def size(self): return len(self.items) def hotPotato(namelist, num): simqueue = Queue() for name in namelist: simqueue.enqueue(name) while simqueue.size() > 1: for i in range(num): simqueue.enqueue(simqueue.dequeue()) simqueue.dequeue() return simqueue.dequeue() if name == ' main ': hotPotato([\"Bill\", \"David\", \"Susan\", \"Jane\", \"Ken\", \"Brad\"], 7) ``` \u8fd0\u884c\u7ed3\u679c\u5982\u4e0b\uff0c\u6700\u540e\u53ea\u5269Susan\u3002\u8bbe\u5b9a\u4e0d\u540c\u7684num\uff08\u8fd9\u91cc\u662f7\uff09\u4f1a\u5f97\u5230\u4e0d\u540c\u7684\u7ed3\u679c\u3002 python 'Susan' \u6253\u5370\u4efb\u52a1 \u00b6 \u53cc\u7aef\u961f\u5217 \u00b6 \u5217\u8868 \u00b6","title":"Python\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5"},{"location":"python/Foundation/Algorithms/#python","text":"\u53c2\u8003\u4e66\u76ee\uff1a \"Problem Solving with Algorithms and Data Structures Using Python (Second Edition)\" by Bradley N.Miller and David L.Ranum.","title":"Python\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5"},{"location":"python/Foundation/Algorithms/#o","text":"\u7b97\u6cd5\u5206\u6790\u662f\u4e00\u79cd\u72ec\u7acb\u4e8e\u5b9e\u73b0\u7684\u7b97\u6cd5\u5ea6\u91cf\u65b9\u6cd5\u3002 \u6570\u91cf\u7ea7\uff08order of magnitude\uff09\u5e38\u88ab\u79f0\u4f5c\u5927O\u8bb0\u6cd5\uff08O\u6307order\uff09\uff0c\u8bb0\u4f5cO(f(n))\u3002\u5b83\u63d0\u4f9b\u4e86\u6b65\u9aa4\u6570\u7684\u4e00\u4e2a\u6709\u7528\u7684\u8fd1\u4f3c\u65b9\u6cd5\u3002f(n)\u51fd\u6570\u4e3aT(n)\u51fd\u6570\u4e2d\u8d77\u51b3\u5b9a\u6027\u4f5c\u7528\u7684\u90e8\u5206\u63d0\u4f9b\u4e86\u7b80\u5355\u7684\u8868\u793a\u3002 \u5927O\u8bb0\u6cd5\u4f7f\u5f97\u7b97\u6cd5\u53ef\u4ee5\u6839\u636e\u968f\u95ee\u9898\u89c4\u6a21\u589e\u957f\u800c\u8d77\u4e3b\u5bfc\u4f5c\u7528\u7684\u90e8\u5206\u8fdb\u884c\u5f52\u7c7b\u3002","title":"\u5927O\u8bb0\u6cd5"},{"location":"python/Foundation/Algorithms/#_1","text":"\u5982\u679c\u4e00\u4e2a\u5b57\u7b26\u4e32\u53ea\u662f\u91cd\u6392\u4e86\u53e6\u4e00\u4e2a\u5b57\u7b26\u4e32\u7684\u5b57\u7b26\uff0c\u90a3\u4e48\u8fd9\u4e2a\u5b57\u7b26\u4e32\u5c31\u662f\u53e6\u4e00\u4e2a\u7684\u5f02\u5e8f\u8bcd\u3002 \u65b9\u68481\uff1a\u6e05\u70b9\u6cd5 \u6e05\u70b9\u7b2c1\u4e2a\u5b57\u7b26\u4e32\u7684\u6bcf\u4e2a\u5b57\u7b26\uff0c\u770b\u770b\u5b83\u4eec\u662f\u5426\u90fd\u51fa\u73b0\u5728\u7b2c2\u4e2a\u5b57\u7b26\u4e32\u4e2d\u3002 \u5728\u5b57\u7b26\u5217\u8868\u4e2d\u68c0\u67e5\u7b2c1\u4e2a\u5b57\u7b26\u4e32\u4e2d\u7684\u6bcf\u4e2a\u5b57\u7b26\uff0c\u5982\u679c\u627e\u5230\u4e86\uff0c\u5c31\u66ff\u6362\u6389\u3002 \u8fd9\u4e2a\u65b9\u6848\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n^2)\u3002 def allotropyWord_1 ( s1 , s2 ): list_a = list ( s2 ) pos1 = 0 stillOK = True while pos1 < len ( s1 ) and stillOK : pos2 = 0 found = False while pos2 < len ( list_a ) and not found : if s1 [ pos1 ] == list_a [ pos2 ]: found = True else : pos2 = pos2 + 1 if found : list_a [ pos2 ] = None else : stillOK = False pos1 = pos1 + 1 return stillOK \u8fd0\u884c\uff1a allotropyWord_1 ( 'hello' , 'olleh' ) \u6ce8\u610flist_a\u7684\u53d8\u5316\u8fc7\u7a0b(\u5339\u914d\u5230\u5373\u66ff\u6362None)\u3002 [ 'o' , 'l' , 'l' , 'e' , None ] [ 'o' , 'l' , 'l' , None , None ] [ 'o' , None , 'l' , None , None ] [ 'o' , None , None , None , None ] [ None , None , None , None , None ] \u65b9\u68482\uff1a\u6392\u5e8f\u6cd5 \u6309\u7167\u5b57\u6bcd\u8868\u987a\u5e8f\u7ed9\u5b57\u7b26\u6392\u5e8f\uff0c\u5f02\u5e8f\u8bcd\u5f97\u5230\u7684\u7ed3\u679c\u5c06\u662f\u540c\u4e00\u4e2a\u5b57\u7b26\u4e32\u3002 \u8fd9\u4e2a\u65b9\u6848\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n^2)\u3002 def allotropyWord_2 ( s1 , s2 ): list1 = list ( s1 ) list2 = list ( s2 ) list1 . sort () list2 . sort () pos = 0 matched = True while pos < len ( s1 ) and matched : if list1 [ pos ] == list2 [ pos ]: pos = pos + 1 else : matched = False return matched \u8fd0\u884c\uff1a allotropyWord_2 ( 'hello' , 'olleh' ) \u65b9\u68483\uff1a\u8ba1\u6570\u6cd5 \u4e24\u4e2a\u5f02\u5e8f\u8bcd\u6709\u540c\u6837\u6570\u76ee\u7684a\u3001\u540c\u6837\u6570\u76ee\u7684b\u3001\u540c\u6837\u6570\u76ee\u7684c\uff0c\u7b49\u7b49\u3002 \u4f7f\u752826\u4e2a\u8ba1\u6570\u5668\uff0c\u5bf9\u5e94\u6bcf\u4e2a\u5b57\u7b26\u3002\u6bcf\u9047\u5230\u4e00\u4e2a\u5b57\u7b26\uff0c\u5c31\u5c06\u5bf9\u5e94\u7684\u8ba1\u6570\u5668\u52a01\u3002 \u5982\u679c\u4e24\u4e2a\u8ba1\u6570\u5668\u5217\u8868\u76f8\u540c\uff0c\u90a3\u4e48\u4e24\u4e2a\u5b57\u7b26\u4e32\u80af\u5b9a\u662f\u5f02\u5e8f\u8bcd\u3002 \u8fd9\u4e2a\u65b9\u6848\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\u3002 def allotropyWord_3 ( s1 , s2 ): c1 = [ 0 ] * 26 c2 = [ 0 ] * 26 for i in range ( len ( s1 )): # \u6bcf\u4e2a\u5b57\u7b26\u7684ASCII\u7801\u4e0e\u5b57\u7b26a\u7684ASCII\u7801\u7684\u5dee\u503c(\u504f\u79fb\u91cf) pos = ord ( s1 [ i ]) - ord ( 'a' ) c1 [ pos ] = c1 [ pos ] + 1 for i in range ( len ( s2 )): pos = ord ( s2 [ i ]) - ord ( 'a' ) c2 [ pos ] = c2 [ pos ] + 1 j = 0 stillOK = True while j < 26 and stillOK : if c1 [ j ] == c2 [ j ]: j = j + 1 else : stillOK = False return stillOK \u8fd0\u884c\uff1a allotropyWord_3 ( 'hello' , 'olleh' ) \u53c2\u8003\uff1a Python\u7684\u65f6\u95f4\u590d\u6742\u5ea6(Time Complexity)","title":"\u5f02\u5e8f\u8bcd\u68c0\u6d4b\u95ee\u9898"},{"location":"python/Foundation/Algorithms/#_2","text":"\u771f\u6b63\u533a\u5206\u7ebf\u6027\u6570\u636e\u7ed3\u6784\u7684\u662f\u5143\u7d20\u7684\u6dfb\u52a0\u65b9\u5f0f\u548c\u79fb\u9664\u65b9\u5f0f\uff0c\u5c24\u5176\u662f\u6dfb\u52a0\u64cd\u4f5c\u548c\u79fb\u9664\u64cd\u4f5c\u53d1\u751f\u7684\u4f4d\u7f6e\u3002","title":"\u7ebf\u6027\u6570\u636e\u7ed3\u6784"},{"location":"python/Foundation/Algorithms/#_3","text":"\u6808\u6709\u65f6\u4e5f\u88ab\u79f0\u4f5c\u201c\u4e0b\u63a8\u6808\u201d\u3002\u5b83\u662f\u6709\u5e8f\u96c6\u5408\uff0c\u6dfb\u52a0\u64cd\u4f5c\u548c\u79fb\u9664\u64cd\u4f5c\u603b\u53d1\u751f\u5728\u540c\u4e00\u7aef\uff0c\u5373\u201c\u9876\u7aef\u201d\uff0c\u53e6\u4e00\u7aef\u5219\u88ab\u79f0\u4e3a\u201c\u5e95\u7aef\u201d\u3002 \u6700\u65b0\u6dfb\u52a0\u7684\u5143\u7d20\u5c06\u88ab\u6700\u5148\u79fb\u9664\u3002\u8fd9\u79cd\u6392\u5e8f\u539f\u5219\u88ab\u79f0\u4f5cLIFO\uff08last-in first-out\uff09\uff0c\u5373\u540e\u8fdb\u5148\u51fa\u3002 \u6808\u7684\u53cd\u8f6c\u7279\u6027\u3002 \u6808\u7684\u5b9e\u73b0\u65b9\u6cd51: append() \u548c pop() \u7684\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662fO(1)\uff0c\u6240\u4ee5\u4e0d\u8bba\u6808\u4e2d\u6709\u591a\u5c11\u4e2a\u5143\u7d20\uff0c push \u64cd\u4f5c\u548c pop \u64cd\u4f5c\u90fd\u4f1a\u5728\u6052\u5b9a\u7684\u65f6\u95f4\u5185\u5b8c\u6210\u3002 class Stack (): def __init__ ( self ) -> None : self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . append ( item ) def pop ( self ): return self . items . pop () def peek ( self ): return self . items [ len ( self . items ) - 1 ] def size ( self ): return len ( self . items ) \u6808\u7684\u5b9e\u73b0\u65b9\u6cd52: insert(0) \u548c pop(0) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662fO(n)\uff0c\u5143\u7d20\u8d8a\u591a\u5c31\u8d8a\u6162\uff0c\u6027\u80fd\u5219\u53d7\u5236\u4e8e\u6808\u4e2d\u7684\u5143\u7d20\u4e2a\u6570\u3002 class Stack (): def __init__ ( self ) -> None : self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . insert ( 0 , item ) def pop ( self ): return self . items . pop ( 0 ) def peek ( self ): return self . items [ 0 ] def size ( self ): return len ( self . items ) \u5bf9\u4e0a\u9762\u7684\u5b9e\u73b0\uff0c\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u8fdb\u884c\u5206\u522b\u9a8c\u8bc1\uff1a s = Stack () s . isEmpty () s . push ( 3 ) s . push ( 'dog' ) s . peek () s . size () s . isEmpty () s . push ( 6.6 ) s . pop () s . size ()","title":"\u6808"},{"location":"python/Foundation/Algorithms/#_4","text":"#!/usr/bin/python3 #!/usr/bin/env python3 # -*- coding: utf-8 -*- class Stack (): def __init__ ( self ): self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . append ( item ) def pop ( self ): return self . items . pop () def peek ( self ): return self . items [ len ( self . items ) - 1 ] def size ( self ): return len ( self . items ) # \u5173\u8054\u5de6\u53f3\u62ec\u53f7 def matches ( open , close ): opens = \"([{\" closers = \")]}\" # \u7b26\u5408\u5173\u8054\u7684\uff0c\u8fd4\u56deTrue return opens . index ( open ) == closers . index ( close ) def parChecker ( symbolString ): s = Stack () matched = True index = 0 # \u8bfb\u53d6\u8f93\u5165\u5b57\u4e32\u6bcf\u4e2a\u5b57\u7b26 while index < len ( symbolString ) and matched : symbol = symbolString [ index ] if symbol in \"([{\" : # \u5de6\u62ec\u53f7\u5165\u6808 s . push ( symbol ) else : if s . isEmpty (): # \u9047\u5230\u975e\u5de6\u62ec\u53f7\u5b57\u7b26\uff0c\u5982\u4e3a\u7a7a\uff0c\u5219\u9000\u51fa\u5faa\u73af matched = False else : top = s . pop () # \u9047\u5230\u975e\u5de6\u62ec\u53f7\u5b57\u7b26\uff0c\u5982\u4e0d\u4e3a\u7a7a\uff0c\u5219\u51fa\u6808\uff0c\u5e76\u5224\u65ad\u662f\u5426\u672a\u4e3a\u5bf9\u5e94\u7684\u53f3\u62ec\u53f7 if not matches ( top , symbol ): # \u5426\u5219\u9000\u51fa\u5faa\u73af matched = False index = index + 1 # \u5b8c\u6210\u6bcf\u4e2a\u5b57\u7b26\u7684\u51fa\u5165\u6808\u68c0\u67e5\uff0c\u5f53\u524d\u6808\u4e3a\u7a7a\uff0c\u4e14\u90fd\u5339\u914d\uff0c\u5219\u8fd4\u56deTrue if matched and s . isEmpty (): return True else : return False if __name__ == '__main__' : parChecker ( \"([[ {} ])\" ) parChecker ( \"([ {} ])\" ) \u6267\u884c\u7ed3\u679c\u5982\u4e0b\uff0c\u7b26\u5408\u9884\u671f\u3002 False True","title":"\u62ec\u53f7\u5339\u914d\u95ee\u9898"},{"location":"python/Foundation/Algorithms/#_5","text":"\u4f8b\u5982\uff0c\u4f7f\u7528\u201c\u9664\u4ee52\u201d\u7684\u7b97\u6cd5\uff0c\u5341\u8fdb\u5236\u6570\u8f6c\u6362\u6210\u4e8c\u8fdb\u5236\u6570\uff0c\u5229\u7528\u6808\u6765\u4fdd\u5b58\u4e8c\u8fdb\u5236\u7ed3\u679c\u7684\u6bcf\u4e00\u4f4d\u3002 \u201c\u9664\u4ee52\u201d\u7b97\u6cd5\u5047\u8bbe\u5f85\u5904\u7406\u7684\u6574\u6570\u5927\u4e8e0\u3002 \u5b83\u7528\u4e00\u4e2a\u7b80\u5355\u7684\u5faa\u73af\u4e0d\u505c\u5730\u5c06\u5341\u8fdb\u5236\u6570\u9664\u4ee52\uff0c\u5e76\u4e14\u8bb0\u5f55\u4f59\u6570\u3002 \u7b2c\u4e00\u6b21\u9664\u4ee52\u7684\u7ed3\u679c\u80fd\u591f\u7528\u4e8e\u533a\u5206\u5076\u6570\u548c\u5947\u6570\u3002 \u5982\u679c\u662f\u5076\u6570\uff0c\u5219\u4f59\u6570\u4e3a0\uff0c\u56e0\u6b64\u4e2a\u4f4d\u4e0a\u7684\u6570\u5b57\u4e3a0\uff1b \u5982\u679c\u662f\u5947\u6570\uff0c\u5219\u4f59\u6570\u4e3a1\uff0c\u56e0\u6b64\u4e2a\u4f4d\u4e0a\u7684\u6570\u5b57\u4e3a1\u3002 \u53ef\u4ee5\u5c06\u8981\u6784\u5efa\u7684\u4e8c\u8fdb\u5236\u6570\u770b\u6210\u4e00\u7cfb\u5217\u6570\u5b57\uff1b\u8ba1\u7b97\u51fa\u7684\u7b2c\u4e00\u4e2a\u4f59\u6570\u662f\u6700\u540e\u4e00\u4f4d\u3002 \u8fd9\u4f53\u73b0\u4e86\u53cd\u8f6c\u7279\u6027\uff0c\u56e0\u6b64\u9002\u7528\u6808\u6765\u5904\u7406\u3002 class Stack (): def __init__ ( self ): self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . append ( item ) def pop ( self ): return self . items . pop () def peek ( self ): return self . items [ len ( self . items ) - 1 ] def size ( self ): return len ( self . items ) def decConverter ( decNumber , baseNumber ): remstack = Stack () digits = \"0123456789ABCDEF\" while decNumber > 0 : rem = decNumber % baseNumber remstack . push ( rem ) decNumber = decNumber // baseNumber newString = \"\" while not remstack . isEmpty (): newString = newString + digits [ remstack . pop ()] return newString if __name__ == '__main__' : decConverter ( 233 , 2 ) decConverter ( 233 , 8 ) decConverter ( 233 , 10 ) decConverter ( 233 , 16 ) \u8fd0\u884c\u7ed3\u679c\uff1a '11101001' '351' '233' 'E9'","title":"\u8fdb\u5236\u8f6c\u6362\u95ee\u9898"},{"location":"python/Foundation/Algorithms/#_6","text":"\u4f7f\u7528 insert() \u5411\u961f\u5217\u7684\u5c3e\u90e8\u6dfb\u52a0\u65b0\u5143\u7d20\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\u3002 \u4f7f\u7528 pop() \u79fb\u9664\u961f\u5217\u5934\u90e8\u7684\u5143\u7d20\uff08\u5217\u8868\u4e2d\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff09\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(1)\u3002 class Queue (): def __init__ ( self ): self . items = [] def isEmpty ( self ): return self . items == [] def enqueue ( self , item ): return self . items . insert ( 0 , item ) def dequeue ( self ): return self . items . pop () def size ( self ): return len ( self . items ) if __name__ == '__main__' : q = Queue () q . isEmpty () q . enqueue ( 2 ) q . enqueue ( 'h' ) q . size () q . isEmpty () q . dequeue () q . size () \u8fd0\u884c\u7ed3\u679c: True 2 False 2 1","title":"\u961f\u5217"},{"location":"python/Foundation/Algorithms/#_7","text":"\u901a\u8fc7\u6a21\u62df\u5b9e\u73b0\u4f20\u571f\u8c46\u6e38\u620f\u6765\u89e3\u91ca\u7ea6\u745f\u592b\u65af\u95ee\u9898\u3002 ```python class Queue(): def init (self): self.items = [] def isEmpty(self): return self.items == [] def enqueue(self, item): return self.items.insert(0, item) def dequeue(self): return self.items.pop() def size(self): return len(self.items) def hotPotato(namelist, num): simqueue = Queue() for name in namelist: simqueue.enqueue(name) while simqueue.size() > 1: for i in range(num): simqueue.enqueue(simqueue.dequeue()) simqueue.dequeue() return simqueue.dequeue() if name == ' main ': hotPotato([\"Bill\", \"David\", \"Susan\", \"Jane\", \"Ken\", \"Brad\"], 7) ``` \u8fd0\u884c\u7ed3\u679c\u5982\u4e0b\uff0c\u6700\u540e\u53ea\u5269Susan\u3002\u8bbe\u5b9a\u4e0d\u540c\u7684num\uff08\u8fd9\u91cc\u662f7\uff09\u4f1a\u5f97\u5230\u4e0d\u540c\u7684\u7ed3\u679c\u3002 python 'Susan'","title":"\u7ea6\u745f\u592b\u65af\u95ee\u9898"},{"location":"python/Foundation/Algorithms/#_8","text":"","title":"\u6253\u5370\u4efb\u52a1"},{"location":"python/Foundation/Algorithms/#_9","text":"","title":"\u53cc\u7aef\u961f\u5217"},{"location":"python/Foundation/Algorithms/#_10","text":"","title":"\u5217\u8868"},{"location":"python/Foundation/ch00/","text":"Python\u5b89\u88c5 \u00b6 Python\u73af\u5883 \u00b6 \u8fd9\u91cc\u4f7f\u7528\u7cfb\u7edf\u81ea\u5e26\u7684Python\u73af\u5883\uff1a \u4e3b\u673a\uff1aVMWare\u865a\u62df\u673a \u64cd\u4f5c\u7cfb\u7edf(Guest)\uff1aopenSUSE 15.3 Python\u7248\u672c\uff1a3.6.15(openSUSE\u81ea\u5e26) \u68c0\u67e5Python\u7248\u672c \u00b6 $ python --version Python 2 .7.18 $ python3 --version Python 3 .6.15 \u5347\u7ea7pip \u00b6 $ pip3 install --upgrade pip $ pip --version pip 21 .3.1 from /home/james/.local/lib/python3.6/site-packages/pip ( python 3 .6 ) $ pip3 --version pip 21 .3.1 from /home/james/.local/lib/python3.6/site-packages/pip ( python 3 .6 ) pip\u56fd\u5185\u6e90 \u00b6 https://mirrors.aliyun.com/pypi/simple/ https://pypi.tuna.tsinghua.edu.cn/simple/ http://pypi.doubanio.com/simple/ https://mirrors.cloud.tencent.com/pypi/simple/ \u5b89\u88c5Python\u5305(\u6307\u5b9a\u6e90) \u00b6 pip3 install jinja2 -i https://mirrors.aliyun.com/pypi/simple/ pip3 install Django -i https://mirrors.aliyun.com/pypi/simple/ pip3 install sqlite_utils -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pymongo -i https://mirrors.aliyun.com/pypi/simple/ pip3 install numpy -i https://mirrors.aliyun.com/pypi/simple/ pip3 install matplotlib -i https://mirrors.aliyun.com/pypi/simple/ pip3 install scikit-learn -i https://mirrors.aliyun.com/pypi/simple/ pip3 install xlrd -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pandas -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pydotplus -i https://mirrors.aliyun.com/pypi/simple/ pip3 install seaborn -i https://mirrors.aliyun.com/pypi/simple/ pip3 install selenium -i https://mirrors.aliyun.com/pypi/simple/ pip3 install mlxtend -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pandas-datareader -i https://mirrors.aliyun.com/pypi/simple/ pip3 install lxml -i https://mirrors.aliyun.com/pypi/simple/ pip3 install beautifulsoup4 -i https://mirrors.aliyun.com/pypi/simple/ pip3 install html5lib -i https://mirrors.aliyun.com/pypi/simple/ pip3 install tables -i https://mirrors.aliyun.com/pypi/simple/ pip3 install openpyxl -i https://mirrors.aliyun.com/pypi/simple/ pip3 install sqlalchemy -i https://mirrors.aliyun.com/pypi/simple/ pip3 install statsmodels -i https://mirrors.aliyun.com/pypi/simple/ pip3 install patsy -i https://mirrors.aliyun.com/pypi/simple/ pip3 install numba -i https://mirrors.aliyun.com/pypi/simple/ pip3 install jason -i https://mirrors.aliyun.com/pypi/simple/ pip3 install openpyxl -i https://mirrors.aliyun.com/pypi/simple/ \u6e90\u7801\u7f16\u8bd1\u65b9\u6cd5 \u00b6 \u4e0b\u9762\u662f\u6e90\u7801\u7f16\u8bd1\u65b9\u5f0f\u81ea\u884c\u5b89\u88c5Python\u7684\u65b9\u6cd5\uff0c\u4ee53.9.6\u7248\u672c\u4e3a\u4f8b\u3002 \u5b98\u7f51\u4e0b\u8f7dpython3.9.6 \uff08 \u8fde\u63a5 \uff09 \u89e3\u538b\u5b89\u88c5\u5305 tar xvf Python-3.9.6.tgz \u5b89\u88c5\u8def\u5f84\u4e3a /opt/Python-3.9.6/ \uff0c\u9700\u8981\u628a\u5b89\u88c5\u8def\u5f84\u7684owner\u6539\u4e3a\u5f53\u524d\u7528\u6237\uff0c\u5426\u5219\u540e\u671fpython\u7f16\u8bd1\u4ee5\u53ca\u4f7f\u7528pip\u5b89\u88c5python\u5305\u4f1a\u62a5\u9519\u3002 chown -R james.wheel /opt/Python-3.9.6 \u5728\u5b89\u88c5\u524d\u7684\u4e00\u4e9b\u5efa\u8bae \u5728openSUSE\u4e2d\u628a\u5f00\u53d1\u5305\u90fd\u5b89\u88c5\u4e00\u4e0b\uff0c\u7279\u522b\u662fc\u548cc++\u7684\u5f00\u53d1\u5305\u3002\u8fd9\u4e9b\u90fd\u662fPython\u7f16\u8bd1\u7684\u4f9d\u8d56\u5305\u3002 \u5728openSUSE\u4e2d\u5b89\u88c5sqlite3. \u4f7f\u7528openSUSE\u81ea\u5e26\u7684openSSL\uff0c\u5982\u679c\u81ea\u884c\u7f16\u8bd1openSSL\uff0c\u5728\u7f16\u8bd1Python\u65f6\u4f1a\u9047\u5230\u4e00\u4e9b\u672a\u77e5\u95ee\u9898\u3002 \u7f16\u8bd1\u548c\u5b89\u88c5\uff1a cd /opt/Python-3.9.6 sudo ./configure --enable-optimizations --with-ensurepip = install sudo make sudo make test sudo make install \u4fee\u6539\u7cfb\u7edf\u9ed8\u8ba4Python\u7684\u914d\u7f6e\uff0c\u5c06python3\u6307\u5411\u65b0\u5b89\u88c5\u7684Python\u3002\u9700\u8981\u4fee\u6539\u7684\u8def\u5f84\u67092\u4e2a\uff0c /usr/bin/python3 \u548c /usr/local/bin/ \u5c06 /usr/bin/python3 \u91cd\u65b0\u6307\u5411\u65b0\u5b89\u88c5\u7684Python\u3002 sudo rm /usr/bin/python3 sudo ln -s /opt/Python-3.9.6/python /usr/bin/python3 \u68c0\u67e5 /usr/local/bin/ \u76ee\u5f55\u4e0b\u7684python\u6587\u4ef6\u662f\u5426\u6307\u5411\u65b0\u5b89\u88c5\u7684Pyton\u3002\u9ed8\u8ba4\u662f\u7f16\u8bd1\u5b89\u88c5\u5b8c\u6210\u540e\u5df2\u7ecf\u88ab\u4fee\u6539\u4e86\u3002 $ ls -l /usr/local/bin/python* lrwxrwxrwx 1 root root 9 Jul 25 02 :15 python3 -> python3.9 -rwxr-xr-x 1 root root 17645928 Jul 25 02 :14 python3.9 -rwxr-xr-x 1 root root 3087 Jul 25 02 :15 python3.9-config lrwxrwxrwx 1 root root 16 Jul 25 02 :15 python3-config -> python3.9-config \u9a8c\u8bc1python\u7684\u7248\u672c\u3002 $ python Python 2 .7.18 ( default, Mar 04 2021 , 23 :25:57 ) [ GCC ] on linux2 $ python3 Python 3 .9.6 ( default, Jul 25 2021 , 02 :13:27 ) [ GCC 7 .5.0 ] on linux \u6dfb\u52a0\u4e0b\u9762\u7684\u73af\u5883\u53d8\u91cf\u5230\u914d\u7f6e\u6587\u4ef6 /etc/profile.local \u3002 export PATH = /usr/local/bin:/home/ $USER /.local/bin: $PATH \u5e76\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u4f7f\u4e4b\u751f\u6548\u3002 source /etc/profile.local \u4e0b\u9762\u4fee\u6539pip\u7684\u914d\u7f6e\u3002 $ whereis pip pip: /usr/bin/pip /usr/bin/pip3.6 /usr/local/bin/pip3.9 \u901a\u8fc7\u4e0b\u9762\u53ef\u4ee5\u770b\u5230pip\u5b9e\u9645\u6307\u5411\u7684\u662f\u7cfb\u7edf\u9ed8\u8ba4\u76843.6\u7248\u672c\u3002 $ l /usr/bin/pip* lrwxrwxrwx 1 root root 21 Dec 4 2020 /usr/bin/pip -> /etc/alternatives/pip* -rwxr-xr-x 1 root root 367 Dec 4 2020 /usr/bin/pip3* -rwxr-xr-x 1 root root 371 Dec 4 2020 /usr/bin/pip3.6* -rwxr-xr-x 1 root root 10608 Jun 10 06 :15 /usr/bin/pipewire* -rwxr-xr-x 1 root root 720208 Jun 10 06 :15 /usr/bin/pipewire-media-session* james@lizard:/opt> l /etc/alternatives/pip* lrwxrwxrwx 1 root root 15 Jul 24 20 :24 /etc/alternatives/pip -> /usr/bin/pip3.6* \u68c0\u67e5\u4e00\u4e0b\u5f53\u524dpip\u5728alternative\u91cc\u9762\u7684\u8bbe\u7f6e\u3002 $ sudo update-alternatives --display pip pip - auto mode link best version is /usr/bin/pip3.6 link currently points to /usr/bin/pip3.6 link pip is /usr/bin/pip /usr/bin/pip3.6 - priority 36 \u5220\u9664\u8001\u7248\u672c\uff0c\u6dfb\u52a0\u65b0\u7248\u672c\u3002 $ sudo update-alternatives --remove pip /usr/bin/pip3.6 $ sudo update-alternatives --install /usr/bin/pip pip /usr/bin/pip3.9 100 update-alternatives: using /usr/bin/pip3.9 to provide /usr/bin/pip ( pip ) in auto mode","title":"Python\u5b89\u88c5"},{"location":"python/Foundation/ch00/#python","text":"","title":"Python\u5b89\u88c5"},{"location":"python/Foundation/ch00/#python_1","text":"\u8fd9\u91cc\u4f7f\u7528\u7cfb\u7edf\u81ea\u5e26\u7684Python\u73af\u5883\uff1a \u4e3b\u673a\uff1aVMWare\u865a\u62df\u673a \u64cd\u4f5c\u7cfb\u7edf(Guest)\uff1aopenSUSE 15.3 Python\u7248\u672c\uff1a3.6.15(openSUSE\u81ea\u5e26)","title":"Python\u73af\u5883"},{"location":"python/Foundation/ch00/#python_2","text":"$ python --version Python 2 .7.18 $ python3 --version Python 3 .6.15","title":"\u68c0\u67e5Python\u7248\u672c"},{"location":"python/Foundation/ch00/#pip","text":"$ pip3 install --upgrade pip $ pip --version pip 21 .3.1 from /home/james/.local/lib/python3.6/site-packages/pip ( python 3 .6 ) $ pip3 --version pip 21 .3.1 from /home/james/.local/lib/python3.6/site-packages/pip ( python 3 .6 )","title":"\u5347\u7ea7pip"},{"location":"python/Foundation/ch00/#pip_1","text":"https://mirrors.aliyun.com/pypi/simple/ https://pypi.tuna.tsinghua.edu.cn/simple/ http://pypi.doubanio.com/simple/ https://mirrors.cloud.tencent.com/pypi/simple/","title":"pip\u56fd\u5185\u6e90"},{"location":"python/Foundation/ch00/#python_3","text":"pip3 install jinja2 -i https://mirrors.aliyun.com/pypi/simple/ pip3 install Django -i https://mirrors.aliyun.com/pypi/simple/ pip3 install sqlite_utils -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pymongo -i https://mirrors.aliyun.com/pypi/simple/ pip3 install numpy -i https://mirrors.aliyun.com/pypi/simple/ pip3 install matplotlib -i https://mirrors.aliyun.com/pypi/simple/ pip3 install scikit-learn -i https://mirrors.aliyun.com/pypi/simple/ pip3 install xlrd -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pandas -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pydotplus -i https://mirrors.aliyun.com/pypi/simple/ pip3 install seaborn -i https://mirrors.aliyun.com/pypi/simple/ pip3 install selenium -i https://mirrors.aliyun.com/pypi/simple/ pip3 install mlxtend -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pandas-datareader -i https://mirrors.aliyun.com/pypi/simple/ pip3 install lxml -i https://mirrors.aliyun.com/pypi/simple/ pip3 install beautifulsoup4 -i https://mirrors.aliyun.com/pypi/simple/ pip3 install html5lib -i https://mirrors.aliyun.com/pypi/simple/ pip3 install tables -i https://mirrors.aliyun.com/pypi/simple/ pip3 install openpyxl -i https://mirrors.aliyun.com/pypi/simple/ pip3 install sqlalchemy -i https://mirrors.aliyun.com/pypi/simple/ pip3 install statsmodels -i https://mirrors.aliyun.com/pypi/simple/ pip3 install patsy -i https://mirrors.aliyun.com/pypi/simple/ pip3 install numba -i https://mirrors.aliyun.com/pypi/simple/ pip3 install jason -i https://mirrors.aliyun.com/pypi/simple/ pip3 install openpyxl -i https://mirrors.aliyun.com/pypi/simple/","title":"\u5b89\u88c5Python\u5305(\u6307\u5b9a\u6e90)"},{"location":"python/Foundation/ch00/#_1","text":"\u4e0b\u9762\u662f\u6e90\u7801\u7f16\u8bd1\u65b9\u5f0f\u81ea\u884c\u5b89\u88c5Python\u7684\u65b9\u6cd5\uff0c\u4ee53.9.6\u7248\u672c\u4e3a\u4f8b\u3002 \u5b98\u7f51\u4e0b\u8f7dpython3.9.6 \uff08 \u8fde\u63a5 \uff09 \u89e3\u538b\u5b89\u88c5\u5305 tar xvf Python-3.9.6.tgz \u5b89\u88c5\u8def\u5f84\u4e3a /opt/Python-3.9.6/ \uff0c\u9700\u8981\u628a\u5b89\u88c5\u8def\u5f84\u7684owner\u6539\u4e3a\u5f53\u524d\u7528\u6237\uff0c\u5426\u5219\u540e\u671fpython\u7f16\u8bd1\u4ee5\u53ca\u4f7f\u7528pip\u5b89\u88c5python\u5305\u4f1a\u62a5\u9519\u3002 chown -R james.wheel /opt/Python-3.9.6 \u5728\u5b89\u88c5\u524d\u7684\u4e00\u4e9b\u5efa\u8bae \u5728openSUSE\u4e2d\u628a\u5f00\u53d1\u5305\u90fd\u5b89\u88c5\u4e00\u4e0b\uff0c\u7279\u522b\u662fc\u548cc++\u7684\u5f00\u53d1\u5305\u3002\u8fd9\u4e9b\u90fd\u662fPython\u7f16\u8bd1\u7684\u4f9d\u8d56\u5305\u3002 \u5728openSUSE\u4e2d\u5b89\u88c5sqlite3. \u4f7f\u7528openSUSE\u81ea\u5e26\u7684openSSL\uff0c\u5982\u679c\u81ea\u884c\u7f16\u8bd1openSSL\uff0c\u5728\u7f16\u8bd1Python\u65f6\u4f1a\u9047\u5230\u4e00\u4e9b\u672a\u77e5\u95ee\u9898\u3002 \u7f16\u8bd1\u548c\u5b89\u88c5\uff1a cd /opt/Python-3.9.6 sudo ./configure --enable-optimizations --with-ensurepip = install sudo make sudo make test sudo make install \u4fee\u6539\u7cfb\u7edf\u9ed8\u8ba4Python\u7684\u914d\u7f6e\uff0c\u5c06python3\u6307\u5411\u65b0\u5b89\u88c5\u7684Python\u3002\u9700\u8981\u4fee\u6539\u7684\u8def\u5f84\u67092\u4e2a\uff0c /usr/bin/python3 \u548c /usr/local/bin/ \u5c06 /usr/bin/python3 \u91cd\u65b0\u6307\u5411\u65b0\u5b89\u88c5\u7684Python\u3002 sudo rm /usr/bin/python3 sudo ln -s /opt/Python-3.9.6/python /usr/bin/python3 \u68c0\u67e5 /usr/local/bin/ \u76ee\u5f55\u4e0b\u7684python\u6587\u4ef6\u662f\u5426\u6307\u5411\u65b0\u5b89\u88c5\u7684Pyton\u3002\u9ed8\u8ba4\u662f\u7f16\u8bd1\u5b89\u88c5\u5b8c\u6210\u540e\u5df2\u7ecf\u88ab\u4fee\u6539\u4e86\u3002 $ ls -l /usr/local/bin/python* lrwxrwxrwx 1 root root 9 Jul 25 02 :15 python3 -> python3.9 -rwxr-xr-x 1 root root 17645928 Jul 25 02 :14 python3.9 -rwxr-xr-x 1 root root 3087 Jul 25 02 :15 python3.9-config lrwxrwxrwx 1 root root 16 Jul 25 02 :15 python3-config -> python3.9-config \u9a8c\u8bc1python\u7684\u7248\u672c\u3002 $ python Python 2 .7.18 ( default, Mar 04 2021 , 23 :25:57 ) [ GCC ] on linux2 $ python3 Python 3 .9.6 ( default, Jul 25 2021 , 02 :13:27 ) [ GCC 7 .5.0 ] on linux \u6dfb\u52a0\u4e0b\u9762\u7684\u73af\u5883\u53d8\u91cf\u5230\u914d\u7f6e\u6587\u4ef6 /etc/profile.local \u3002 export PATH = /usr/local/bin:/home/ $USER /.local/bin: $PATH \u5e76\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u4f7f\u4e4b\u751f\u6548\u3002 source /etc/profile.local \u4e0b\u9762\u4fee\u6539pip\u7684\u914d\u7f6e\u3002 $ whereis pip pip: /usr/bin/pip /usr/bin/pip3.6 /usr/local/bin/pip3.9 \u901a\u8fc7\u4e0b\u9762\u53ef\u4ee5\u770b\u5230pip\u5b9e\u9645\u6307\u5411\u7684\u662f\u7cfb\u7edf\u9ed8\u8ba4\u76843.6\u7248\u672c\u3002 $ l /usr/bin/pip* lrwxrwxrwx 1 root root 21 Dec 4 2020 /usr/bin/pip -> /etc/alternatives/pip* -rwxr-xr-x 1 root root 367 Dec 4 2020 /usr/bin/pip3* -rwxr-xr-x 1 root root 371 Dec 4 2020 /usr/bin/pip3.6* -rwxr-xr-x 1 root root 10608 Jun 10 06 :15 /usr/bin/pipewire* -rwxr-xr-x 1 root root 720208 Jun 10 06 :15 /usr/bin/pipewire-media-session* james@lizard:/opt> l /etc/alternatives/pip* lrwxrwxrwx 1 root root 15 Jul 24 20 :24 /etc/alternatives/pip -> /usr/bin/pip3.6* \u68c0\u67e5\u4e00\u4e0b\u5f53\u524dpip\u5728alternative\u91cc\u9762\u7684\u8bbe\u7f6e\u3002 $ sudo update-alternatives --display pip pip - auto mode link best version is /usr/bin/pip3.6 link currently points to /usr/bin/pip3.6 link pip is /usr/bin/pip /usr/bin/pip3.6 - priority 36 \u5220\u9664\u8001\u7248\u672c\uff0c\u6dfb\u52a0\u65b0\u7248\u672c\u3002 $ sudo update-alternatives --remove pip /usr/bin/pip3.6 $ sudo update-alternatives --install /usr/bin/pip pip /usr/bin/pip3.9 100 update-alternatives: using /usr/bin/pip3.9 to provide /usr/bin/pip ( pip ) in auto mode","title":"\u6e90\u7801\u7f16\u8bd1\u65b9\u6cd5"},{"location":"python/Foundation/ch01/","text":"Python\u8bed\u8a00\u57fa\u7840 \u00b6 1. Python\u6570\u636e\u7c7b\u578b\uff086\u4e2a\uff09 \u00b6 6\u4e2aPython\u6570\u636e\u7c7b\u578b\uff1a \u6570\u503c\u578b\uff08number\uff09\uff1a\u8868\u793a\u6570\u636e\u7ec4\u6210\u4e3a\u6570\u5b57 \u6574\u578b\uff08int\uff09 \u5341\u8fdb\u5236 \u516b\u8fdb\u5236 \u5341\u516d\u8fdb\u5236 \u6d6e\u70b9\u578b\uff08float\uff09 \u5e03\u5c14\u578b\uff08bool\uff09 \u590d\u6570\u6027\uff08complex\uff09 \u5b57\u7b26\u578b\uff08string\uff09\uff1a\u8868\u793a\u6570\u636e\u7ec4\u6210\u662f\u5b57\u7b26 \u5217\u8868\uff08list\uff09\uff1a\u7528\u6765\u8868\u793a\u4e00\u7ec4\u6709\u5e8f\u5143\u7d20\uff0c\u540e\u671f\u6570\u636e\u53ef\u4ee5\u4fee\u6539 ['A','B','C'] \u5143\u7ec4\uff08tuple\uff09\uff1a\u7528\u6765\u8868\u793a\u4e00\u7ec4\u6709\u5e8f\u5143\u7d20\uff0c\u540e\u671f\u6570\u636e\u4e0d\u53ef\u4fee\u6539 ('A','B','C','1') \u96c6\u5408\uff08set\uff09\uff1a\u4e00\u7ec4\u6570\u636e\u65e0\u5e8f\u4e0d\u91cd\u590d\u5143\u7d20 set([1,2,3,4]) \u5b57\u5178\uff08dictionary\uff09\uff1a\u7528\u952e\u503c\u5bf9\u7684\u5f62\u5f0f\u4fdd\u5b58\u4e00\u7ec4\u5143\u7d20 {'A':7,'B':1,'C':9} \u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08Iterable\uff09\uff1a An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an iter() method or with a getitem() method that implements Sequence semantics. \u5e8f\u5217\uff08Sequence\uff09\uff1a An iterable which supports efficient element access using integer indices via the getitem() special method and defines a len() method that returns the length of the sequence. Some built-in sequence types are list, str, tuple, and bytes. Note that dict also supports getitem() and len(), but is considered a mapping rather than a sequence because the lookups use arbitrary immutable keys rather than integers. \u8fed\u4ee3\u5668\uff08Iterator\uff09\uff1a An object representing a stream of data. Repeated calls to the iterator\u2019s next() method (or passing it to the built-in function next()) return successive items in the stream. When no more data are available a StopIteration exception is raised instead. At this point, the iterator object is exhausted and any further calls to its next() method just raise StopIteration again. Iterators are required to have an iter() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a list) produces a fresh new iterator each time you pass it to the iter() function or use it in a for loop. Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container. \u53ef\u53d8\u6570\u636e\uff08immutable\uff09 \u5217\u8868\uff08list\uff09 \u5b57\u5178\uff08dictionary\uff09 \u96c6\u5408\uff08set\uff09\u3002 \u4e0d\u53ef\u53d8\u6570\u636e\uff08immutable\uff09 \u6570\u5b57\uff08number\uff09 \u5b57\u7b26\uff08string\uff09 \u5143\u7ec4\uff08tuple\uff09 \u53ef\u8fed\u4ee3\uff08iterable\uff09 \u5b57\u7b26\uff08string\uff09 \u5143\u7ec4\uff08tuple\uff09 \u5217\u8868\uff08list\uff09 \u5b57\u5178\uff08dictionary\uff09 \u96c6\u5408\uff08set\uff09 \u5e8f\u5217 \u6709\u5e8f\u5e8f\u5217\uff1a\u5b57\u7b26\uff08string\uff09\uff0c\u5143\u7ec4\uff08tuple\uff09\uff0c\u5217\u8868\uff08list\uff09 \u65e0\u5e8f\u5e8f\u5217\uff1a\u5b57\u5178\uff08dictionary\uff09\uff0c\u96c6\u5408\uff08set\uff09 Python\u5e8f\u5217\u7c7b\u578b\u6700\u5e38\u89c1\u7684\u5206\u7c7b\u5c31\u662f\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u5e8f\u5217\u3002\u4f46\u53e6\u5916\u4e00\u79cd\u5206\u7c7b\u65b9\u5f0f\u4e5f\u5f88\u6709\u7528\uff0c\u90a3\u5c31\u662f\u628a\u5b83\u4eec\u5206\u4e3a**\u6241\u5e73\u5e8f\u5217**\u548c**\u5bb9\u5668\u5e8f\u5217**\u3002\u524d\u8005\u7684\u4f53\u79ef\u66f4\u5c0f\u3001\u901f\u5ea6\u66f4\u5feb\u800c\u4e14\u7528\u8d77\u6765\u66f4\u7b80\u5355\uff0c\u4f46\u662f\u5b83\u53ea\u80fd\u4fdd\u5b58\u4e00\u4e9b\u539f\u5b50\u6027\u7684\u6570\u636e\uff0c\u6bd4\u5982\u6570\u5b57\u3001\u5b57\u7b26\u548c\u5b57\u8282\u3002\u5bb9\u5668\u5e8f\u5217\u5219\u6bd4\u8f83\u7075\u6d3b\uff0c\u4f46\u662f\u5f53\u5bb9\u5668\u5e8f\u5217\u9047\u5230\u53ef\u53d8\u5bf9\u8c61\u65f6\uff0c\u5c31\u9700\u8981\u683c\u5916\u5c0f\u5fc3\uff0c\u56e0\u4e3a\u8fd9\u79cd\u7ec4\u5408\u65f6\u5e38\u4f1a\u51fa\u73b0\u4e00\u4e9b\u201c\u610f\u5916\u201d\uff0c\u7279\u522b\u662f\u5e26\u5d4c\u5957\u7684\u6570\u636e\u7ed3\u6784\u51fa\u73b0\u65f6\uff0c\u66f4\u9700\u8981\u9a8c\u8bc1\u4ee3\u7801\u7684\u6b63\u786e\u6027\u3002 Python\u4e2d\u7684\u53d8\u91cf\u3001\u5e38\u91cf\u548c\u5b57\u9762\u91cf \u53d8\u91cf \u53d8\u91cf\u662f\u7528\u4e8e\u5728\u5185\u5b58\u4e2d\u5b58\u50a8\u6570\u636e\u7684\u547d\u540d\u4f4d\u7f6e\u3002\u53ef\u4ee5\u5c06\u53d8\u91cf\u89c6\u4e3a\u4fdd\u5b58\u6570\u636e\u7684\u5bb9\u5668\uff0c\u8fd9\u4e9b\u6570\u636e\u53ef\u4ee5\u5728\u540e\u9762\u7a0b\u5e8f\u4e2d\u8fdb\u884c\u66f4\u6539\u3002\u4f8b\u5982\uff1a number = 10 \u3002\u4ece\u4f8b\u5b50\u4e2d\u53ef\u4ee5\u770b\u5230\uff0cPython\u4f7f\u7528\u8d4b\u503c\u8fd0\u7b97\u7b26 = \u4e3a\u53d8\u91cf\u8d4b\u503c\u3002 \u5e38\u91cf \u5e38\u91cf\u4e5f\u662f\u4e00\u79cd\u53d8\u91cf\uff0c\u53ea\u662f\u5176\u503c\u4e00\u65e6\u8d4b\u4e88\u540e\u65e0\u6cd5\u66f4\u6539\u3002\u53ef\u4ee5\u5c06\u5e38\u91cf\u89c6\u4e3a\u4fdd\u5b58\u4e86\u4ee5\u540e\u65e0\u6cd5\u66f4\u6539\u7684\u4fe1\u606f\u7684\u5bb9\u5668\u3002 \u5728Python\u4e2d\uff0c\u5e38\u91cf\u901a\u5e38\u662f\u5728\u6a21\u5757\u4e2d\u58f0\u660e\u548c\u5206\u914d\u7684\u3002\u5728\u8fd9\u91cc\uff0c\u6a21\u5757\u662f\u4e00\u4e2a\u5305\u542b\u53d8\u91cf\uff0c\u51fd\u6570\u7b49\u7684\u65b0\u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u88ab\u5bfc\u5165\u5230\u4e3b\u6587\u4ef6\u4e2d\u3002\u5728\u6a21\u5757\u5185\u90e8\uff0c\u7528\u6240\u6709\u5927\u5199\u5b57\u6bcd\u5199\u7684\u5e38\u91cf\u548c\u4e0b\u5212\u7ebf\u5c06\u5355\u8bcd\u5206\u5f00\u3002\u5b9e\u9645\u4e0a\uff0c\u6211\u4eec\u4e0d\u5728Python\u4e2d\u4f7f\u7528\u5e38\u91cf\u3002\u7528\u5927\u5199\u5b57\u6bcd\u547d\u540d\u5b83\u4eec\u662f\u4e00\u79cd\u5c06\u5176\u4e0e\u666e\u901a\u53d8\u91cf\u5206\u5f00\u7684\u4e00\u79cd\u7ea6\u5b9a\uff0c\u4f46\u662f\uff0c\u5b9e\u9645\u4e0a\u5e76\u4e0d\u80fd\u963b\u6b62\u91cd\u65b0\u5206\u914d\u3002 \u5b57\u9762\u91cf\uff08literal\uff09 \u5b57\u9762\u91cf\u662f\u4ee5\u53d8\u91cf\u6216\u5e38\u91cf\u7ed9\u51fa\u7684\u539f\u59cb\u6570\u636e\uff08\u5176\u5b9e\u5c31\u662f\u6307\u53d8\u91cf\u7684\u5e38\u6570\u503c\uff0c\u5b57\u9762\u4e0a\u6240\u770b\u5230\u7684\u503c\uff09\u3002\u5728Python\u4e2d\u5b57\u9762\u91cf\u7c7b\u578b\u5982\u4e0b\uff1a \u6570\u5b57\u5b57\u9762\u91cf\u3002\u6570\u5b57\u5b57\u9762\u91cf\u662f\u4e0d\u53ef\u53d8\u7684\uff08\u4e0d\u53ef\u66f4\u6539\uff09\u3002\u6570\u5b57\u5b57\u9762\u91cf\u53ef\u4ee5\u5c5e\u4e8e3\u79cd\u4e0d\u540c\u7684\u6570\u503c\u7c7b\u578b\uff1aInteger\uff0cFloat \u548c Complex\u3002\u4f8b\u5982\uff1a float_1 = 10.5 \u662f\u5c5e\u4e8eFloat\u5b57\u9762\u91cf\u3002 \u5b57\u7b26\u4e32\u5b57\u9762\u91cf\u662f\u7531\u5f15\u53f7\u62ec\u8d77\u6765\u7684\u4e00\u7cfb\u5217\u5b57\u7b26\u3002\u6211\u4eec\u53ef\u4ee5\u5bf9\u5b57\u7b26\u4e32\u4f7f\u7528\u5355\u5f15\u53f7\uff0c\u53cc\u5f15\u53f7 \u6216 \u4e09\u5f15\u53f7\u3002\u5e76\u4e14\uff0c\u5b57\u7b26\u5b57\u9762\u91cf\u662f\u7528\u5355\u5f15\u53f7\u6216\u53cc\u5f15\u53f7\u5f15\u8d77\u6765\u7684\u5355\u4e2a\u5b57\u7b26\u3002\u4f8b\u5982\uff1a strings = \"This is Python\" \u3002 \u5e03\u5c14\u5b57\u9762\u91cf\u3002\u5e03\u5c14\u5b57\u9762\u91cf\u53ef\u4ee5\u5177\u6709\u4e24\u4e2a\u503c\u4e2d\u7684\u4efb\u4f55\u4e00\u4e2a\uff1a True \u6216 False \u3002\u4f8b\u5982\uff1a a = True + 4 \u3002 \u7279\u6b8a\u5b57\u9762\u91cf\u3002Python\u5305\u542b\u4e00\u4e2a\u7279\u6b8a\u5b57\u9762\u91cf\uff0c\u5373 None \u3002 \u5b57\u9762\u91cf\u96c6\u3002\u6709\u56db\u79cd\u4e0d\u540c\u7684\u5b57\u9762\u91cf\u96c6\u5408\uff1a\u5217\u8868\u5b57\u9762\u91cf\uff0c\u5143\u7ec4\u5b57\u9762\u91cf\uff0c\u5b57\u5178\u5b57\u9762\u91cf \u548c \u96c6\u5408\u5b57\u9762\u91cf\u3002 1.1 \u6570\u503c\u578b\uff08number\uff09 \u00b6 \u4f8b\u5b50\uff1a a , b , c , d = 20 , 5.5 , True , 4 + 3 j print ( a , b , c , d ) # 20 5.5 True (4+3j) print ( type ( a ), type ( b ), type ( c ), type ( d )) # Python\u4e5f\u53ef\u4ee5\u8fd9\u6837\u8d4b\u503c\uff1a a = b = c = d = 1 print ( a , b , c , d ) # 1 1 1 1 \u8fdb\u5236\u8f6c\u6362\uff1a a = - 15 print ( f ' { a } \u5bf9\u5e94\u7684\u5341\u8fdb\u5236\u662f { a } , \u4e8c\u8fdb\u5236\u662f { a : b } , \u516b\u8fdb\u5236\u662f { a : o } , \u5341\u516d\u8fdb\u5236\u662f { a : x } ' ) 1.2 \u5b57\u7b26\u578b\uff08string\uff09 \u00b6 \u5355\u5f15\u53f7\uff1a\u5185\u5bb9\u4e2d\u5305\u542b\u5927\u91cf\u53cc\u5f15\u53f7 \u53cc\u5f15\u53f7\uff1a\u5185\u5bb9\u4e2d\u5305\u542b\u5927\u91cf\u5355\u5f15\u53f7 \u4e09\u5f15\u53f7\uff1a\u5185\u5bb9\u4e2d\u540c\u65f6\u5305\u542b\u5355\u53cc\u5f15\u53f7\uff0c\u4e09\u4e2a\u5355\u5f15\u53f7\u6bd4\u8f83\u597d\u3002 a = 'string is \"special\"' b = \"string's value\" c = '''string's value is \"special\"''' d = \"\"\"string's context \"\"\" \u5b57\u7b26\u4e32\u5e38\u7528\u65b9\u6cd5 \u00b6 \u5b57\u7b26\u4e32\u5207\u7247 s = 'Python is very good' print ( s [ 2 : 4 ]) # th print ( s [ 5 ]) # n print ( s [ - 1 ]) # d print ( s [ - 3 : - 1 ]) # oo # \u975e\u8fed\u4ee3\u578b\uff0c\u4e0d\u53ef\u4fee\u6539 s [ 3 ] = 'b' # Traceback (most recent call last): # File \"\", line 1, in # TypeError: 'str' object does not support item assignment \u5b57\u7b26\u4e32\u5408\u5e76 print ( s + '!!!' ) # Python is very good!!! replace( a,b \u5c06\u5b57\u7b26\u4e32\u4e2d\u7684 a \u66ff\u6362\u6210 b print ( s . replace ( 'is' , 'we' )) # Python we very good find(str) : \u8fd4\u56de str \u51fa\u73b0\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0c\u5982\u679c\u627e\u4e0d\u5230\u8be5\u503c\uff0c\u5219 find() \u65b9\u6cd5\u5c06\u8fd4\u56de -1\u3002 print ( s . find ( 'a' )) # -1 print ( s . find ( 's' )) # 8 str.index(a): \u67e5\u627e\u6307\u5b9a\u503c\u7684\u9996\u6b21\u51fa\u73b0\u3002\u5982\u679c\u627e\u4e0d\u5230\u8be5\u503c\uff0cindex() \u65b9\u6cd5\u5c06\u5f15\u53d1\u5f02\u5e38\u3002 print ( s . index ( 's' )) # 8 print ( s . index ( 'a' )) # Traceback (most recent call last): # File \"\", line 1, in # ValueError: substring not found str.count(a): \u7edf\u8ba1\u5b57\u7b26\u4e32\u4e2d a \u51fa\u73b0\u7684\u6b21\u6570 print ( s . count ( 'a' )) # 0 print ( s . count ( 'o' )) # 3 split: \u5bf9\u5b57\u7b26\u4e32\u8fdb\u884c\u5206\u5272\u3002\u5982\u679c\u53c2\u6570 num \u6709\u6307\u5b9a\u503c\uff0c\u5219\u5206\u9694 num+1 \u4e2a\u5b50\u5b57\u7b26\u4e32\u3002 # \u6309\u7a7a\u683c\u5206\u5272 print ( s . split ( ' ' )) # ['Python', 'is', 'very', 'good'] # \u6309\u7a7a\u683c\u5206\u5272\u62102\u4e2a\u5b50\u5b57\u7b26\u4e32 print ( s . split ( ' ' , 1 )) # ['Python', 'is very good'] strip: \u79fb\u9664\u5b57\u7b26\u4e32\u9996\u5c3e\u6307\u5b9a\u7684\u5b57\u7b26 \u9ed8\u8ba4\u4e3a\u7a7a\u683c\u3002\u8be5\u65b9\u6cd5\u53ea\u80fd\u5220\u9664\u5f00\u5934\u6216\u662f\u7ed3\u5c3e\u7684\u5b57\u7b26\uff0c\u4e0d\u80fd\u5220\u9664\u4e2d\u95f4\u90e8\u5206\u7684\u5b57\u7b26\u3002 print ( s ) # Python is very good # \u79fb\u9664\u672b\u5c3e\u5b57\u7b26d print ( s . strip ( 'd' )) # Python is very goo endswith (str): \u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u4ee5 str \u7ed3\u5c3e print ( s . endswith ( 'd' )) # True print ( s . endswith ( 'a' )) # False startswith (str): \u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u4ee5 str \u5f00\u5934 print ( s . startswith ( 'p' )) # False print ( s . startswith ( 'P' )) # True isdigit \uff1a\u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u5168\u4e3a\u6570\u5b57 d = '+86-123' print ( d . isdigit ()) # False d = '86123' print ( d . isdigit ()) # True isalpha \uff1a\u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u5168\u4e3a\u5b57\u6bcd b = 'Ab?' print ( b . isalpha ()) # False c = 'Ab' print () c . isalpha () # True \u8f6c\u4e49\u5b57\u7b26 \u00b6 \u4f7f\u7528\u53cd\u659c\u6760\\\u8868\u793a\u8f6c\u4e49\u5b57\u7b26\u3002\u53cd\u659c\u6760\u524d\u9762\u52a0r\u4ee3\u8868\u539f\u59cb\u5b57\u7b26\u3002 a = 'str \\n ing' print ( a ) # str # ing a = r 'str\\ning' print ( a ) # str\\ning \u8f6c\u4e49\u7b26 \u63cf\u8ff0 \\\u5728\u884c\u5c3e \u7eed\u884c\u7b26 \\\\ \u53cd\u659c\u6760\u7b26\u53f7\\ \\' \u5355\u5f15\u53f7 \\b \u9000\u683c(Backspace) \\000 \u7a7a \\n \u6362\u884c \\v \u7eb5\u5411\u5236\u8868\u7b26 \\t \u6a2a\u5411\u5236\u8868\u7b26 \\r \u56de\u8f66\uff0c\u5c06 \\r \u540e\u9762\u7684\u5185\u5bb9\u79fb\u5230\u5b57\u7b26\u4e32\u5f00\u5934\uff0c\u5e76\u9010\u4e00\u66ff\u6362\u5f00\u5934\u90e8\u5206\u7684\u5b57\u7b26\uff0c\u76f4\u81f3\u5c06 \\r \u540e\u9762\u7684\u5185\u5bb9\u5b8c\u5168\u66ff\u6362\u5b8c\u6210\u3002 \\yyy \u516b\u8fdb\u5236\u6570\uff0cy \u4ee3\u8868 0~7 \u7684\u5b57\u7b26 \\xyy \u5341\u516d\u8fdb\u5236\u6570\uff0c\u4ee5 \\x \u5f00\u5934\uff0cy \u4ee3\u8868\u7684\u5b57\u7b26 \u53ef\u8fed\u4ee3\u6027 \u00b6 \u5b57\u7b26\u4e32\u662f\u53ef\u8fed\u4ee3\u7684\u3002\u7d22\u5f15\u503c\u4ece0\u5f00\u59cb\uff0c-1\u4ee3\u8868\u4ece\u672b\u5c3e\u5f00\u59cb\u3002\u7d22\u5f15\u533a\u95f4\u662f\u5de6\u95ed\u53f3\u5f00\u3002 a = 'string is \"special\"' print ( a [ 2 : 4 ]) 'ri' print ( a [ - 4 : - 1 ]) # ial f-string \u00b6 f-string\u662fPython3.6\u63a8\u51fa\u7684\u65b0\u529f\u80fd\u3002\u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5bf9\u6bd4\u4f20\u7edf\u8868\u793a\u65b9\u6cd5\u548cf-string\u7684\u65b9\u6cd5\u3002 age = 32 name = 'Tom' fstring = f 'My name is { name } and I am { age } years old.' print ( fstring ) # My name is Tom and I am 32 years old. \u5728f-string\u4e2d\u4f7f\u7528\u8868\u8fbe\u5f0f\u3002 height = 2 base = 3 fstring = f 'The area of the triangle is { base * height / 2 } .' print ( fstring ) # The area of the triangle is 3.0. \u901a\u8fc7f-string\u5bf9\u5b57\u5178\u8fdb\u884c\u64cd\u4f5c\u3002 person1 = { 'name' : 'Tom' , 'age' : 20 , 'gender' : 'male' } person2 = { 'name' : 'Jerry' , 'age' : 20 , 'gender' : 'female' } # \u8bfb\u53d6\u5b57\u5178 fstring = f ' { person1 . get ( \"name\" ) } is { person1 . get ( \"age\" ) } and is { person1 . get ( \"ender\" ) } ' print ( fstring ) # Tom is 20 and is None # \u904d\u5386\u5b57\u5178 people = [ person1 , person2 ] for person in people : fstring = f ' { person . get ( \"name\" ) } is { person . get ( \"age\" ) } and is { person . get ( \"ender\" ) } ' print ( fstring ) # Tom is 20 and is None # Jerry is 20 and is None \u5728f-string\u4e2d\u4f7f\u7528\u6761\u4ef6\u3002 person1 = { 'name' : 'Tom' , 'age' : 20 , 'gender' : 'male' } person2 = { 'name' : 'Jerry' , 'age' : 20 , 'gender' : 'female' } people = [ person1 , person2 ] for person in people : fstring = f ' { \"She\" if person . get ( \"gender\" ) == \"female\" else \"He\" } is watching TV.' print ( fstring ) # He is watching TV. # She is watching TV. \u4f7f\u7528f-string\u683c\u5f0f\u5316\u8f93\u51fa\u3002 \u5de6\u5bf9\u9f50\uff1a< \u53f3\u5bf9\u9f50\uff1a> \u5c45\u4e2d\u5bf9\u9f50\uff1a^ print ( f ' { \"apple\" : >30 } ' ) print ( f ' { \"apple\" : ^30 } ' ) print ( f ' { \"apple\" : <30 } ' ) # apple # apple # apple \u4f7f\u7528f-string\u683c\u5f0f\u5316\u6570\u5b57\u3002 number = 0.9124325345 # \u767e\u5206\u6bd4 fstring = f 'Percentage format for number with two decimal places: { number : .2% } ' print ( fstring ) # Percentage format for number with two decimal places: 91.24% # \u4fdd\u7559\u5c0f\u6570\u70b9\u540e3\u4f4d fstring = f 'Fixed point format for number with three decimal places: { number : .3f } ' print ( fstring ) # Fixed point format for number with three decimal places: 0.912 # \u79d1\u5b66\u8ba1\u6570\u6cd5\u8868\u793a fstring = f 'Exponent format for number: { number : e } ' print ( fstring ) # Exponent format for number: 9.124325e-01 # \u5e26\u8d27\u5e01\u7b26\u53f7 number = 123456.78921 fstring = f 'Currency format for number with two decimal places: $ { number : .2f } ' print ( fstring ) # Currency format for number with two decimal places: $123456.79 # \u5e26\u8d27\u5e01\u7b26\u53f7\u548c\u5343\u5206\u4f4d number = 123456.78921 fstring = f 'Currency format for number with two decimal places and comma seperators: $ { number : ,.2f } ' print ( fstring ) # Currency format for number with two decimal places and comma seperators: $123,456.79 # \u8f93\u51fa\u6570\u503c\u5e26\u6b63\u8d1f\u7b26\u5408 numbers = [ 1 , - 3 , 5 ] for number in numbers : fstring = f 'The number is { number : + } ' print ( fstring ) # The number is +1 # The number is -3 # The number is +5 # Debug\u8c03\u8bd5 number = 2 print ( f ' { number = } ' ) # number = 2 1.3 \u5217\u8868\uff08list\uff09 \u00b6 \u5217\u8868\u662f Python \u5185\u7f6e\u7684\u4e00\u79cd\u6570\u636e\u7ed3\u6784\uff0c\u662f\u4e00\u79cd\u6709\u5e8f\u7684\u96c6\u5408\uff0c\u7528\u6765\u5b58\u50a8\u4e00\u8fde\u4e32\u5143\u7d20\u7684\u5bb9\u5668\u3002\u5217\u8868\u4e2d\u5143\u7d20\u7c7b\u578b\u53ef\u4ee5\u4e0d\u76f8\u540c\uff0c\u5b83\u652f\u6301\u6570\u5b57\u3001\u5b57\u7b26\u4e32\u7b49\u3002 \u5217\u8868\u7684\u6bcf\u4e2a\u503c\u90fd\u6709\u5bf9\u5e94\u7684\u7d22\u5f15\u503c\uff0c\u7d22\u5f15\u503c\u4ece0\u5f00\u59cb\u3002 \u5217\u8868\u5207\u7247\uff1a \u4f7f\u7528\u5207\u7247\u7b26\u53f7\u53ef\u4ee5\u5bf9\u5927\u591a\u6570\u5e8f\u5217\u7c7b\u578b\u9009\u53d6\u5176\u5b50\u96c6\u3002 \u8d77\u59cb\u4f4d\u7f6estart\u7684\u7d22\u5f15\u662f\u5305\u542b\u7684\uff0c\u800c\u7ed3\u675f\u4f4d\u7f6estop\u7684\u7d22\u5f15\u5e76\u4e0d\u5305\u542b\uff08\u5de6\u95ed\u53f3\u5f00\uff09\u3002 \u6b65\u8fdb\u503cstep\u53ef\u4ee5\u5728\u7b2c\u4e8c\u4e2a\u5192\u53f7\u540e\u9762\u4f7f\u7528\uff0c\u610f\u601d\u662f\u6bcf\u9694\u591a\u5c11\u4e2a\u6570\u53d6\u4e00\u4e2a\u503c \u3002 color = [ 'red' , 'green' , 'blue' , 'yellow' , 'white' , 'black' ] # \u4ece0\u5f00\u59cb\u7edf\u8ba1\uff0c\u8bfb\u53d6\u7b2c1\uff0c2\u4f4d print ( color [ 1 : 3 ]) # ['green', 'blue'] # \u4ece0\u5f00\u59cb\u7edf\u8ba1\uff0c\u8bfb\u53d6\u4ece\u7b2c1\u4f4d\u5230\u5012\u6570\u7b2c3\u4f4d print ( color [ 1 : - 2 ]) # ['green', 'blue', 'yellow'] # \u4ece0\u5f00\u59cb\u7edf\u8ba1\uff0c\u8bfb\u53d6\u4ece\u5012\u6570\u7b2c4\u4f4d\u5230\u5012\u6570\u7b2c3\u4f4d print ( color [ - 4 : - 2 ]) # ['blue', 'yellow'] # \u5982\u679c\u5199\u6210\u4e0b\u9762\u8fd9\u6837\uff0c\u5219\u65e0\u8f93\u51fa\u3002 print ( color [ - 2 : - 4 ]) # [] print ( color [:: 2 ]) # ['red', 'blue', 'white'] \u5bf9\u4e8e\u7c7b\u4f3c\u4e0b\u9762 invoice \u683c\u5f0f\u7684\u7eaf\u6587\u672c\u89e3\u6790\uff0c\u4f7f\u7528\u6709\u540d\u5b57\u7684\u5207\u7247\u6bd4\u7528\u4e0a\u9762\u6240\u5217\u4e3e\u7684\u786c\u7f16\u7801\u7684\u6570\u5b57\u533a\u95f4\u8981\u65b9\u4fbf\u5f97\u591a\u3002 invoice = \"\"\" 0 6 40 52 55 1909 Primoroni PiBrella $17.50 3 $52.50 1489 6mm Tactile Switch x20 $4.19 2 $9.90 1510 Panavise JR.-PV-201 $28.00 1 $28.00 1601 PiTFT Mini Kit 320x240 $34.95 1 $34.95 \"\"\" SKU = slice ( 0 , 6 ) DESCRIPTION = slice ( 6 , 40 ) UNIT_PRICE = slice ( 40 , 52 ) QUANTITY = slice ( 52 , 55 ) ITEM_TOTAL = slice ( 55 , None ) line_items = invoice . split ( ' \\n ' )[ 2 :] # \u6309\u4e0a\u9762invoice\u7684\u683c\u5f0f\uff0c\u7b2c0\u548c1\u884c\u820d\u5f03 for item in line_items : print ( item [ UNIT_PRICE ], item [ DESCRIPTION ]) # $17.50 Primoroni PiBrella # $4.19 6mm Tactile Switch x20 # $28.00 Panavise JR.-PV-201 # $34.95 PiTFT Mini Kit 320x240 Python\u5185\u7f6e\u7684\u5e8f\u5217\u7c7b\u578b\u90fd\u662f\u4e00\u7ef4\u7684\uff0c\u56e0\u6b64\u5b83\u4eec\u53ea\u652f\u6301\u5355\u4e00\u7684\u7d22\u5f15\uff0c\u6210\u5bf9\u51fa\u73b0\u7684\u7d22\u5f15\u662f\u6ca1\u6709\u7528\u7684\u3002 **\u7701\u7565\uff08ellipsis\uff09**\u7684\u6b63\u786e\u4e66\u5199\u65b9\u6cd5\u662f\u4e09\u4e2a\u82f1\u8bed\u53e5\u53f7\uff08...\uff09\uff0c\u800c\u4e0d\u662fUnicdoe\u7801\u4f4dU+2026\u8868\u793a\u7684\u534a\u4e2a\u7701\u7565\u53f7\uff08...\uff09\u3002 \u7701\u7565\u5728Python\u89e3\u6790\u5668\u773c\u91cc\u662f\u4e00\u4e2a\u7b26\u53f7\uff0c\u800c\u5b9e\u9645\u4e0a\u5b83\u662f Ellipsis \u5bf9\u8c61\u7684\u522b\u540d\uff0c\u800c Ellipsis \u5bf9\u8c61\u53c8\u662f ellipsis \u7c7b\u7684\u5355\u4e00\u5b9e\u4f8b\u3002 \u5b83\u53ef\u4ee5\u5f53\u4f5c\u5207\u7247\u89c4\u8303\u7684\u4e00\u90e8\u5206\uff0c\u4e5f\u53ef\u4ee5\u7528\u5728\u51fd\u6570\u7684\u53c2\u6570\u6e05\u5355\u4e2d\uff0c\u6bd4\u5982 f(a, ..., z) \uff0c\u6216 a[i:...] \u3002 \u5728NumPy\u4e2d\uff0c ... \u7528\u4f5c\u591a\u7ef4\u6570\u7ec4\u5207\u7247\u7684\u5feb\u6377\u65b9\u5f0f\u3002\u5982\u679c `x\u662f\u56db\u7ef4\u6570\u7ec4\uff0c\u90a3\u4e48 x[i, ...] \u5c31\u662f x[i, :, :, :]`\u7684\u7f29\u5199\u3002\u5982\u679c\u60f3\u4e86\u89e3\u66f4\u591a\uff0c\u8bf7\u53c2\u89c1\u201cTentative NumPy Tutorial\u201d\u3002 \u5217\u8868\u5e38\u7528\u65b9\u6cd5 \u65b9\u6cd5\u540d\u79f0 \u4f5c\u7528 a.index() \u8fd4\u56dea\u4e2d\u9996\u4e2a\u5339\u914d\u9879\u7684\u4f4d\u7f6e a.pop() \u5220\u9664\u6307\u5b9a\u4f4d\u7f6e\u7684\u5143\u7d20 a.insert() \u5411\u6307\u5b9a\u4f4d\u7f6e\u63d2\u5165\u5143\u7d20 a.reverse() \u53cd\u5411\u6392\u5e8f a.append() \u5411\u672b\u5c3e\u6dfb\u52a0\u5143\u7d20 a.sort() \u5bf9\u5217\u8868\u8fdb\u884c\u6392\u5e8f a.remove() \u5220\u9664\u9996\u4e2a\u5339\u914d\u9879\u7684\u5143\u7d20 a.extend() \u5c06\u4e00\u4e2a\u5217\u8868\u6269\u5c55\u81f3\u53e6\u4e00\u4e2a\u5217\u8868 a.count() \u7edf\u8ba1\u67d0\u4e2a\u5143\u7d20\u51fa\u73b0\u7684\u6b21\u6570 \u521b\u5efa\u5217\u8868list a = [ 1 , 2 , 3 , 4 , 5 ] print ( a ) # [1, 2, 3, 4, 5] b = list ( '12345' ) print ( b ) # ['1', '2', '3', '4', '5'] c = list ( 12345 ) # Traceback (most recent call last): # File \"\", line 1, in # TypeError: 'int' object is not iterable \u5217\u8868\u5207\u7247\uff08\u4ece0\u5f00\u59cb\uff0c\u5de6\u95ed\u53f3\u5f00\uff09\uff1a print ( a [ 2 : 3 ]) # [3] print ( a [: 3 ]) # [1, 2, 3] print ( a [:: - 1 ]) # \u5012\u5e8f # [5, 4, 3, 2, 1] print ( a [::]) # [1, 2, 3, 4, 5] print ( a [:: 1 ]) [ 1 , 2 , 3 , 4 , 5 ] \u5217\u8868\u662f\u53ef\u4fee\u6539\u7684\uff1a print ( a [ 1 ]) # 2 a [ 1 ] = 'one' print ( a ) @ [ 1 , 'one' , 3 , 4 , 5 ] \u5217\u8868\u8ffd\u52a0\u548c\u63d2\u5165\u3002insert\u4e0eappend\u76f8\u6bd4\uff0c\u8ba1\u7b97\u4ee3\u4ef7\u66f4\u9ad8\u3002\u56e0\u4e3a\u5b50\u5e8f\u5217\u5143\u7d20\u9700\u8981\u5728\u5185\u90e8\u79fb\u52a8\u4e3a\u65b0\u5143\u7d20\u63d0\u4f9b\u7a7a\u95f4\u3002 a . append ( 6 ) # \u6ce8\u610f\uff0c\u76f4\u63a5\u4fee\u6539\u539f\u5217\u8868\uff0c\u4e0d\u662f\u521b\u5efa\u526f\u672c\u3002 print ( a ) # [1, 'one', 3, 4, 5, 6] a . extend ([ 7 , 8 , 9 ]) print ( a ) # [1, 'one', 3, 4, 5, 6, 7, 8, 9] a . insert ( 0 , 'Italy' ) print ( a ) # ['Italy', 1, 3, 5, 6, 7, 8] \u5217\u8868\u5220\u9664\u5143\u7d20\uff0c\u9ed8\u8ba4\u5220\u9664\u6700\u540e\u4e00\u4e2a\u3002insert\u7684\u53cd\u64cd\u4f5c\u662fpop\u3002 a . pop () # 9 print ( a ) # [1, 'one', 3, 4, 5, 6, 7, 8] a . pop ( 3 ) # 4 print ( a ) # [1, 'one', 3, 5, 6, 7, 8] \u5220\u9664\u5217\u8868\u4e2d\u67d0\u4e2a\u5143\u7d20\u3002 print ( a [ 1 ]) # one del a [ 1 ] print ( a ) [ 1 , 3 , 5 , 6 , 7 , 8 ] \u5220\u9664\u5217\u8868\u4e2d\u67d0\u4e2a\u5143\u7d20\u3002remove\u65b9\u6cd5\u4f1a\u5b9a\u4f4d\u7b2c\u4e00\u4e2a\u7b26\u5408\u8981\u6c42\u7684\u503c\u5e76\u79fb\u9664 a . remove ( 'Italy' ) print ( a ) # [1, 3, 5, 6, 7, 8] \u7edf\u8ba1\u67d0\u4e2a\u5143\u7d20\u51fa\u73b0\u7684\u6b21\u6570\u3002 print ( a . count ( 1 )) # 1 \u8fd4\u56de\u5217\u8868\u4e2d\u5339\u914d\u9879\u7684\u7d22\u5f15\u4f4d\u7f6e\u3002\u5339\u914d\u4e0d\u5230\u629b\u51fa\u5f02\u5e38\u3002 print ( a . index ( 2 )) # Traceback (most recent call last): # File \"\", line 1, in # ValueError: 2 is not in list print ( a . index ( 3 )) # 1 \u5224\u65ad\u5143\u7d20\u662f\u5426\u5b58\u5728\u4e8e\u5217\u8868\u3002 print ( 3 in a ) # True print ( '3' in a ) # False \u53cd\u5411\u8f93\u51fa\u5217\u8868\u3002 a . reverse () print ( a ) # [8, 7, 6, 5, 3, 1] \u53d6\u5217\u8868\u4e2d\u6700\u5927\u503c\u3001\u6700\u5c0f\u503c\u3002 print ( min ( a )) # 1 print ( max ( a )) # 78 \u8ba1\u7b97\u5217\u8868\u957f\u5ea6\u3002 print ( len ( a )) # 6 \u5217\u8868\u6269\u5c55\uff1a a = [ 1 , 2 , 3 ] b = [ 4 , 5 , 6 ] print ( a + b ) # [1, 2, 3, 4, 5, 6] a . extend ( b ) # a\u5217\u8868\u88ab\u4fee\u6539 print ( a ) # [1, 2, 3, 4, 5, 6] print ( b ) # [4, 5, 6] \u4f7f\u7528extend\u6dfb\u52a0\u5143\u7d20\u6bd4\u4f7f\u7528\u52a0\u53f7\uff08+\uff09\u8fde\u63a5\u6548\u7387\u66f4\u9ad8\u3002\u56e0\u4e3a\u4f7f\u7528\u52a0\u53f7\uff08+\uff09\u8fde\u63a5\u8fc7\u7a0b\u4e2d\u521b\u5efa\u4e86\u65b0\u5217\u8868\uff0c\u5e76\u4e14\u8fd8\u8981\u590d\u5236\u5bf9\u8c61\u3002 a_list = [ 4 , None , 'foo' ] b_list = [ 7 , 8 , ( 2 , 3 )] print ( a_list + b_list ) # [4, None, 'foo', 7, 8, (2, 3)] \u4f7f\u7528+\u53f7\u8fde\u63a5 a_list . extend ( b_list ) print ( a_list ) # [4, None, 'foo', 7, 8, (2, 3)] Python\u7684\u4e00\u4e2a\u60ef\u4f8b\uff1a\u5982\u679c\u4e00\u4e2a\u51fd\u6570\u6216\u8005\u65b9\u6cd5\u5bf9\u5bf9\u8c61\u8fdb\u884c\u7684\u662f\u5c31\u5730\u6539\u52a8\uff0c\u90a3\u5b83\u5c31\u5e94\u8be5\u8fd4\u56deNone\uff0c\u597d\u8ba9\u8c03\u7528\u8005\u77e5\u9053\u4f20\u5165\u7684\u53c2\u6570\u53d1\u751f\u4e86\u53d8\u52a8\uff0c\u800c\u4e14\u5e76\u672a\u4ea7\u751f\u65b0\u7684\u5bf9\u8c61\u3002 \u4e0b\u9762\u662f\u6392\u5e8f\u7684\u4f8b\u5b50 list.sort() \u548c sorted(list) \u7684\u533a\u522b\u3002 list1 = [ '1' , 'one' , '3' , 'Four' , '5' , 'two' , 'apple' , '8' , '9' ] print ( list1 ) # ['1', 'one', '3', 'Four', '5', 'two', 'apple', '8', '9'] # \u4e0b\u9762\u7684\u64cd\u4f5c\u4e0d\u6539\u53d8\u539f\u5217\u8868 print ( sorted ( list1 )) # ['1', '3', '5', '8', '9', 'Four', 'apple', 'one', 'two'] print ( sorted ( list1 , reverse = True )) # ['two', 'one', 'apple', 'Four', '9', '8', '5', '3', '1'] print ( sorted ( list1 , key = len )) # ['1', '3', '5', '8', '9', 'one', 'two', 'Four', 'apple'] print ( list1 ) # ['1', 'one', '3', 'Four', '5', 'two', 'apple', '8', '9'] # \u4e0b\u9762\u7684\u64cd\u4f5c\u76f4\u63a5\u4fee\u6539\u539f\u5217\u8868\uff0c\u8fd4\u56de\u503c\u662fNone print ( list1 . sort ()) # None print ( list1 ) # ['1', '3', '5', '8', '9', 'Four', 'apple', 'one', 'two'] \u5217\u8868\u590d\u5236\uff0c + \u548c * \u7684\u64cd\u4f5c\u90fd\u662f\u4e0d\u4fee\u6539\u539f\u6709\u7684\u64cd\u4f5c\u5bf9\u8c61\uff0c\u800c\u662f\u6784\u5efa\u4e00\u4e2a\u5168\u65b0\u7684\u5217\u8868\u3002 c = list ( 'Python' ) print ( a + c ) # [1, 2, 3, 4, 5, 6, 'P', 'y', 't', 'h', 'o', 'n'] print ( a * 3 ) # [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6] \u5982\u679c\u5728 a * n \u8fd9\u4e2a\u8bed\u53e5\u4e2d\uff0c\u5e8f\u5217 a \u91cc\u7684\u5143\u7d20\u662f\u5bf9\u5176\u4ed6\u53ef\u53d8\u5bf9\u8c61\u7684\u5f15\u7528\u7684\u8bdd\uff0c\u5c31\u9700\u8981\u683c\u5916\u6ce8\u610f\u4e86\uff0c\u56e0\u4e3a\u8fd9\u4e2a\u5f0f\u5b50\u7684\u7ed3\u679c\u53ef\u80fd\u4f1a\u51fa\u4e4e\u610f\u6599\u3002 \u6bd4\u5982\uff0c\u6211\u4eec\u60f3\u7528 my_list=[[]] * 3 \u6765\u521d\u59cb\u5316\u4e00\u4e2a\u7531\u5217\u8868\u7ec4\u6210\u7684\u5217\u8868\uff0c\u4f46\u662f\u6211\u4eec\u5b9e\u9645\u5f97\u5230\u7684\u5217\u8868\u91cc\u5305\u542b\u76843\u4e2a\u5143\u7d20\u5176\u5b9e\u662f3\u4e2a\u5f15\u7528\uff0c\u800c\u4e14\u8fd93\u4e2a\u5f15\u7528\u6307\u5411\u7684\u90fd\u662f*\u540c\u4e00\u4e2a*\u5217\u8868\u3002\u770b\u4e0b\u9762\u4f8b\u5b50\u3002 # \u505a\u6cd51 board = [[ '_' ] * 3 for i in range ( 3 )] print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 1 ][ 2 ] = 'X' print ( board ) # [['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']] # \u505a\u6cd52 board = [[ '_' ] * 3 ] * 3 print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 1 ][ 2 ] = 'X' print ( board ) # [['_', '_', 'X'], ['_', '_', 'X'], ['_', '_', 'X']] \u4e0b\u9762\u4e5f\u662f\u540c\u6837\u7684\u95ee\u9898\u3002 # \u65b9\u6cd51 row = [ '_' ] * 3 board = [] for i in range ( 3 ): board . append ( row ) print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 2 ][ 0 ] = 'X' print ( board ) # [['X', '_', '_'], ['X', '_', '_'], ['X', '_', '_']] # \u65b9\u6cd52 row = [] board = [] for i in range ( 3 ): row = [ '_' ] * 3 board . append ( row ) print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 2 ][ 0 ] = 'X' print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['X', '_', '_']] \u53cc\u7aef\u961f\u5217collections.deque \uff0c\u53ef\u4ee5\u6ee1\u8db3\u5217\u8868\u5934\u5c3e\u90e8\u90fd\u589e\u52a0\u7684\u8981\u6c42\u3002 deque() \u4e2d maxlen \u662f\u4e00\u4e2a\u53ef\u9009\u53c2\u6570\uff0c\u4ee3\u8868\u8fd9\u4e2a\u961f\u5217\u53ef\u4ee5\u5bb9\u7eb3\u7684\u5143\u7d20\u7684\u6570\u91cf\uff0c\u800c\u4e14\u4e00\u65e6\u8bbe\u5b9a\uff0c\u8fd9\u4e2a\u5c5e\u6027\u5c31\u4e0d\u80fd\u4fee\u6539\u4e86\u3002 \u5f53\u8bd5\u56fe\u5bf9\u4e00\u4e2a\u5df2\u6ee1 len(d)==d.maxlen \u7684\u961f\u5217\u505a\u5934\u90e8\u6dfb\u52a0\u64cd\u4f5c\u7684\u65f6\u5019\uff0c\u5b83\u5c3e\u90e8\u7684\u5143\u7d20\u4f1a\u88ab\u5220\u9664\u6389\u3002 extendleft(iter) \u65b9\u6cd5\u4f1a\u628a\u8fed\u4ee3\u5668\u91cc\u7684\u5143\u7d20\u9010\u4e2a\u6dfb\u52a0\u5230\u53cc\u5411\u961f\u5217\u7684\u5de6\u8fb9\uff0c\u56e0\u6b64\u8fed\u4ee3\u5668\u91cc\u7684\u5143\u7d20\u4f1a\u9006\u5e8f\u51fa\u73b0\u5728\u961f\u5217\u91cc\u3002 \u961f\u5217\u7684\u65cb\u8f6c\u64cd\u4f5c rotate \u63a5\u53d7\u4e00\u4e2a\u53c2\u6570n\uff0c\u5f53n > 0\u65f6\uff0c\u961f\u5217\u7684\u6700\u53f3\u8fb9\u7684n\u4e2a\u5143\u7d20\u4f1a\u88ab\u79fb\u52a8\u5230\u961f\u5217\u7684\u5de6\u8fb9\u3002\u5f53n < 0\u65f6\uff0c\u6700\u5de6\u8fb9\u7684n\u4e2a\u5143\u7d20\u4f1a\u88ab\u79fb\u52a8\u5230\u53f3\u8fb9\u3002 from collections import deque d = deque ([ 1 , 2 , 3 ]) print ( d ) # deque([1, 2, 3]) # \u6ce8\u610f\u63d2\u5165\u987a\u5e8f d . extendleft ([ 'a' , 'b' , 'c' ]) print ( d ) # deque(['c', 'b', 'a', 1, 2, 3]) print ( len ( d )) # 6 print ( d [ - 2 ]) # 2 # \u7edf\u8ba1\u5b57\u7b26a\u51fa\u73b0\u7684\u6b21\u6570 print ( d . count ( 'a' )) # 1 # \u8fd4\u56de\u5b57\u7b26a\u7684\u7d22\u5f15\u503c print ( d . index ( 'a' )) # 2 # \u7b2c0\u4f4d\u63d2\u5165\u6570\u5b571\uff0c\u5176\u4f59\u987a\u79fb d . insert ( 0 , 1 ) print ( d ) # deque([1, 'c', 'b', 'a', 1, 2, 3]) # \u628a\u53f3\u8fb92\u4e2a\u5143\u7d20\u653e\u5230\u5de6\u8fb9\uff0c\u6ce8\u610f\u987a\u5e8f\uff0c\u548cextendleft\u4e0d\u4e00\u6837 d . rotate ( 2 ) print ( d ) # deque([2, 3, 1, 'c', 'b', 'a', 1]) d . rotate ( - 2 ) print ( d ) # deque([1, 'c', 'b', 'a', 1, 2, 3]) \u4e0b\u8868\u603b\u7ed3\u4e86\u5217\u8868\u548c\u53cc\u5411\u961f\u5217\u7684\u65b9\u6cd5\uff08\u4e0d\u5305\u62ec\u7531\u5bf9\u8c61\u5b9e\u73b0\u7684\u65b9\u6cd5\uff09\u3002 \u5217\u8868\u6392\u5e8f\u3002\u6392\u5e8f\u5bf9\u5217\u8868\u5143\u7d20\u7684\u6570\u636e\u7c7b\u578b\u662f\u6709\u8981\u6c42\u7684\u3002 a_list = [ 4 , None , 'foo' , 7 , 8 , ( 2 , 3 )] a_list . sort () # Traceback (most recent call last): # File \"\", line 1, in # TypeError: '<' not supported between instances of 'NoneType' and 'int' b_list = [ 7 , 8 , ( 2 , 3 )] b_list . sort () # Traceback (most recent call last): # File \"\", line 1, in # TypeError: '<' not supported between instances of 'tuple' and 'int' a_list = [ 7 , 2 , 5 , 1 , 3 ] a_list . sort () # \u6309\u6570\u503c\u5927\u5c0f\u6392\u5e8f print ( a_list ) # [1, 2, 3, 5, 7] b_list = [ 'saw' , 'small' , 'He' , 'foxes' , 'six' ] b_list . sort ( key = len ) # \u901a\u8fc7\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u8fdb\u884c\u6392\u5e8f print ( b_list ) # ['He', 'saw', 'six', 'small', 'foxes'] \u5217\u8868\u4e8c\u5206\u641c\u7d22\u548c\u5df2\u6392\u5e8f\u5217\u8868\u7684\u7ef4\u62a4 bisect \u8fd4\u56de\u8981\u63d2\u5165\u5143\u7d20\u5728\u5217\u8868\u4e2d\u7684\u4e0b\u6807\u3002\u5047\u5b9a\u5217\u8868\u662f\u6709\u5e8f\u7684\u3002 bisect_left \u4e0e bisect \u7c7b\u4f3c\uff0c\u53ea\u4e0d\u8fc7\u5176\u9ed8\u8ba4\u5c06\u5143\u7d20\u63d2\u5230\u5de6\u8fb9\uff0c\u6240\u4ee5\u8fd4\u56de\u7684\u662f\u63d2\u5165\u5230\u5de6\u8fb9\u7684\u4e0b\u6807 bisect_right\u4e0e bisect_left \u76f8\u53cd\u3002 \u4ee5\u4e0a\u65b9\u6cd5\u82e5\u5217\u8868\u65e0\u5e8f\uff0c\u90a3\u4e48\u4f1a\u8fd4\u56de\u63d2\u5165\u5230\u5217\u8868\u6700\u540e\u4e00\u4e2a\u5408\u9002\u7684\u4f4d\u7f6e\u3002 insort \u4f1a\u5728\u5217\u8868\u4e2d\u63d2\u5165\u5143\u7d20\u5230\u6b63\u786e\u4f4d\u7f6e\uff0c\u5047\u5b9a\u5217\u8868\u6709\u5e8f\u3002\u5982\u679c\u5217\u8868\u65e0\u5e8f\uff0c\u90a3\u4e48\u4f1a\u8fd4\u56de\u7a7a\u3002\u9ed8\u8ba4\u63d2\u5165\u5230\u53f3\u8fb9\u3002 insort_left \u548cinsort_right \u7c7b\u4f3c\u3002 import bisect c = [ 1 , 2 , 3 , 4 , 7 ] print ( bisect . bisect ( c , 2 )) # 2 bisect\u4f1a\u627e\u5230\u7b2c\u4e00\u4e2a2,\u5e76\u628a\u65b0\u76842\u63d2\u5165\u5b83\u540e\u9762 bisect . insort ( c , 2 ) # [1, 2, 2, 3, 4, 7] print ( bisect . bisect ( c , 5 )) # 5 bisect\u4f1a\u627e\u5230\u7b2c\u4e00\u4e2a4,\u5e76\u628a\u65b0\u76845\u63d2\u5165\u5b83\u540e\u9762 bisect . insort ( c , 5 ) print ( bisect . bisect ( c , 6 )) # 6 bisect\u4f1a\u627e\u5230\u7b2c\u4e00\u4e2a5,\u5e76\u628a\u65b0\u76846\u63d2\u5165\u5b83\u540e\u9762 bisect . insort ( c , 6 ) print ( c ) # [1, 2, 2, 3, 4, 5, 6, 7] bisect\u53ef\u4ee5\u7528\u6765\u5efa\u7acb\u4e00\u4e2a\u7528\u6570\u5b57\u4f5c\u4e3a\u7d22\u5f15\u7684\u67e5\u8be2\u8868\u683c\uff0c\u5982\u4e0b\u4f8b\uff0c\u628a\u5206\u6570\u548c\u6210\u7ee9\u5bf9\u5e94\u8d77\u6765\uff0c\u6839\u636e\u4e00\u4e2a\u5206\u6570\uff0c\u627e\u5230\u5b83\u6240\u5bf9\u5e94\u7684\u6210\u7ee9\u3002 import bisect def grade ( score , breakpoints = [ 60 , 70 , 80 , 90 ], grades = 'FDCBA' ): i = bisect . bisect ( breakpoints , score ) return grades [ i ] [ grade ( score ) for score in [ 15 , 26 , 31 , 62 , 79 , 85 ]] # ['F', 'F', 'F', 'D', 'C', 'B'] \u7528bisect.insort\u63d2\u5165\u65b0\u5143\u7d20\uff0c\u5e76\u80fd\u4fdd\u6301seq\u7684\u5347\u5e8f\u987a\u5e8f\u3002 import bisect import random size = 7 random . seed ( 1729 ) my_list = [] for i in range ( size ): new_item = random . randrange ( size * 2 ) bisect . insort ( my_list , new_item ) print ( f ' { new_item : 2d } :--> { my_list } ' ) # 10 :--> [10] # 0 :--> [0, 10] # 6 :--> [0, 6, 10] # 8 :--> [0, 6, 8, 10] # 7 :--> [0, 6, 7, 8, 10] # 2 :--> [0, 2, 6, 7, 8, 10] # 10 :--> [0, 2, 6, 7, 8, 10, 10] 1.4 \u5b57\u5178\uff08dictionary\uff09 \u00b6 \u5b57\u5178(dict)\u662f\u4f7f\u7528\u952e-\u503c\uff08key-value\uff09\u5b58\u50a8\uff0c\u952e\u662f\u4e0d\u53ef\u53d8\u5bf9\u8c61\uff0c\u4e14\u4e0d\u5141\u8bb8\u91cd\u590d\u3002 dict\uff08\u5b57\u5178\uff09\u66f4\u4e3a\u5e38\u7528\u7684\u540d\u5b57\u662f\u54c8\u5e0c\u8868\u6216\u8005\u662f\u5173\u8054\u6570\u7ec4\u3002 \u5b57\u5178\u662f\u62e5\u6709\u7075\u6d3b\u5c3a\u5bf8\u7684\u952e\u503c\u5bf9\u96c6\u5408\uff0c\u4e0d\u662f\u901a\u8fc7\u4f4d\u7f6e\u8fdb\u884c\u7d22\u5f15\uff0c\u5176\u4e2d\u952e\u548c\u503c\u90fd\u662fPython\u5bf9\u8c61\u3002\u7528\u5927\u62ec\u53f7{}\u662f\u521b\u5efa\u5b57\u5178\u7684\u4e00\u79cd\u65b9\u5f0f\uff0c\u5728\u5b57\u5178\u4e2d\u7528\u9017\u53f7\u5c06\u952e\u503c\u5bf9\u5206\u9694\u3002 \u521b\u5efa\u5b57\u5178\u7684\u51e0\u79cd\u65b9\u6cd5\uff1a a = dict ( one = 1 , two = 2 , three = 3 ) b = { 'one' : 1 , 'two' : 2 , 'three' : 3 } c = dict ( zip ([ 'one' , 'two' , 'three' ], [ 1 , 2 , 3 ])) d = dict ([( 'two' , 2 ), ( 'three' , 3 ), ( 'one' , 1 )]) e = dict ({ 'three' : 3 , 'one' : 1 , 'two' : 2 }) print ( a == b == c == d == e ) # True \u5b57\u5178\u5e38\u7528\u65b9\u6cd5 \u65b9\u6cd5\u540d\u79f0 \u4f5c\u7528 a.items() \u8fd4\u56dea\u4e2d\u6240\u6709\u952e\u503c\u5bf9 a.values() \u8fd4\u56dea\u4e2d\u6240\u6709\u503c a.keys() \u8fd4\u56dea\u4e2d\u6240\u6709\u952e a.get() \u901a\u8fc7\u952e\u6765\u67e5\u503c\uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u503c a.clear() \u6e05\u7a7a\u5b57\u5178a\u7684\u503c a.setdefault \u901a\u8fc7\u952e\u503c\u6765\u67e5\u627e\u503c\uff0c\u627e\u4e0d\u5230\u5219\u63d2\u5165 a.update() \u952e\u548c\u503c\u66f4\u65b0\u5230\u65b0\u7684\u5b57\u5178 a.pop() \u5220\u9664\u6307\u5b9a\u4f4d\u7f6e\u7684\u5143\u7d20 \u751f\u6210\u4e00\u4e2a\u5b57\u5178\u3002 dict_a = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } print ( type ( dict_a )) # dict_b = dict ( city = 'Shanghai' , strict = 'Xuhui' , zip = '200000' ) print ( type ( dict_b )) # \u901a\u8fc7\u952e\u67e5\u8be2\u503c\uff0c\u67e5\u8be2\u4e0d\u5230\u629b\u51fa\u5f02\u5e38\u3002 print ( dict_a [ 'name' ]) # Ming print ( dict_a [ 'Name' ]) # Traceback (most recent call last): # File \"\", line 1, in # KeyError: 'Name' \u63d2\u5165\u65b0\u7684\u952e\u503c\u5bf9\u3002 dict_a [ 'city' ] = 'Chengdu' print ( dict_a ) # {'name': 'Ming', 'id': 1001, 'city': 'Chengdu'} \u5220\u9664\u67d0\u4e2a\u952e\u503c\u5bf9\u3002pop\u65b9\u6cd5\u4f1a\u5728\u5220\u9664\u7684\u540c\u65f6\u8fd4\u56de\u88ab\u5220\u7684\u503c\uff0c\u5e76\u5220\u9664\u952e\u3002 dict_a . pop ( 'city' ) # Chengdu print ( dict_a ) # {'name': 'Ming', 'id': 1001} \u53e6\u4e00\u79cd\u65b9\u5f0f\u5220\u9664\u67d0\u4e2a\u952e\u503c\u5bf9\u3002 del dict_a [ 'age' ] # Traceback (most recent call last): # File \"\", line 1, in # KeyError: 'age' del dict_a [ 'id' ] print ( dict_a ) # {'name': 'Ming'} \u5224\u65ad\u952e\u662f\u5426\u5b58\u5728\u3002 dict_a [ 23 ] = 'Hello World' print ( dict_a ) # {'name': 'Ming', 23: 'Hello World'} print ( 23 in dict_a ) # True print ( 35 in dict_a ) # False \u901a\u8fc7\u952e\u67e5\u8be2\u503c\u7684\u53e6\u4e00\u79cd\u65b9\u5f0f\uff0c\u67e5\u8be2\u4e0d\u5230\u4e0d\u629b\u5f02\u5e38\u3002 dict_a . get ( 'hai' ) dict_a . get ( 'hai' , 1 ) # 1 dict_a . get ( 'name' , 1 ) # Ming dict_a [ 'hai' ] # Traceback (most recent call last): # File \"\", line 1, in # KeyError: 'hai' \u901a\u8fc7\u952e\u67e5\u8be2\u503c\u7684\u53e6\u4e00\u79cd\u65b9\u5f0f\uff0c\u67e5\u8be2\u4e0d\u5230\u5219\u6dfb\u52a0\u3002 dict_a . setdefault ( 'name' ) # Ming dict_a . setdefault ( 'hai' , 1 ) # 1 print ( dict_a ) # {'name': 'Ming', 23: 'Hello World', 'hai': 1} dict_a . setdefault ( 'go' ) print ( dict_a ) # {'name': 'Ming', 23: 'Hello World', 'hai': 1, 'go': None} \u8bfb\u53d6\u5b57\u5178\u6240\u6709\u952e\u503c\u5bf9\uff0c\u8fd4\u56de\u7684\u662f\u5217\u8868\u5f62\u5f0f\u3002 print ( dict_a . items ()) # dict_items([('name', 'Ming'), (23, 'Hello World'), ('hai', 1), ('go', None)]) \u8bfb\u53d6\u5b57\u5178\u7684\u952e\u3002 print ( dict_a . keys ()) # dict_keys(['name', 23, 'hai', 'go']) \u8bfb\u53d6\u5b57\u5178\u7684\u503c\u3002 print ( dict_a . values ()) # dict_values(['Ming', 'Hello World', 1, None]) \u5c06\u5b57\u5178\u503c\u8f6c\u5316\u6210\u5217\u8868\u3002 print ( list ( dict_a . values ())) # ['Ming', 'Hello World', 1, None] for key in dict_a . keys (): print ( dict_a [ key ]) # Ming # Hello World # 1 # None \u6e05\u7a7a\u5b57\u5178\u3002 dict_a . clear () print ( dict_a ) # {} print ( len ( dict_a )) # 0 \u5bf9\u4e8e\u4efb\u4f55\u539f\u5b57\u5178\u4e2d\u5df2\u7ecf\u5b58\u5728\u7684\u952e\uff0c\u5982\u679c\u4f20\u7ed9update\u65b9\u6cd5\u7684\u6570\u636e\u4e5f\u542b\u6709\u76f8\u540c\u7684\u952e\uff0c\u5219\u5b83\u7684\u503c\u5c06\u4f1a\u88ab\u8986\u76d6\u3002 dict_a = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } dict_b = dict ( city = 'Shanghai' , id = 2001 , zip = '200000' ) dict_a . update ( dict_b ) print ( dict_a ) # {'name': 'Ming', 'id': 2001, 'age': 35, 'city': 'Shanghai', 'zip': '200000'} \u4ece\u5217\u8868\u751f\u6210\u5b57\u5178\u3002 \u5b57\u5178\u672c\u8d28\u4e0a\u662f2-\u5143\u7ec4\uff08\u542b\u67092\u4e2a\u5143\u7d20\u7684\u5143\u7ec4\uff09\u7684\u96c6\u5408\uff0c\u5b57\u5178\u662f\u53ef\u4ee5\u63a5\u53d7\u4e00\u4e2a2-\u5143\u7ec4\u7684\u5217\u8868\u4f5c\u4e3a\u53c2\u6570\u7684\u3002 # \u65b9\u6cd51 mapping = {} key_list = list ( range ( 5 )) value_list = list ( reversed ( range ( 5 ))) for key , value in zip ( key_list , value_list ): mapping [ key ] = value print ( mapping ) # {0: 4, 1: 3, 2: 2, 3: 1, 4: 0} # \u65b9\u6cd52\u3002 mapping = {} key_list = list ( range ( 5 )) value_list = list ( reversed ( range ( 5 ))) mapping = dict ( zip ( key_list , value_list )) print ( mapping ) # {0: 4, 1: 3, 2: 2, 3: 1, 4: 0} \u6709\u6548\u7684\u5b57\u5178\u952e\u7c7b\u578b\u3002 \u5c3d\u7ba1\u5b57\u5178\u7684\u503c\u53ef\u4ee5\u662f\u4efb\u4f55Python\u5bf9\u8c61\uff0c\u4f46\u952e\u5fc5\u987b\u662f\u4e0d\u53ef\u53d8\u7684\u5bf9\u8c61\uff0c\u6bd4\u5982\u6807\u91cf\u7c7b\u578b\uff08\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u5b57\u7b26\u4e32\uff09\u6216\u5143\u7ec4\uff08\u4e14\u5143\u7ec4\u5185\u5bf9\u8c61\u4e5f\u5fc5\u987b\u662f\u4e0d\u53ef\u53d8\u5bf9\u8c61\uff09\u3002 \u901a\u8fc7hash\u51fd\u6570\u53ef\u4ee5\u68c0\u67e5\u4e00\u4e2a\u5bf9\u8c61\u662f\u5426\u53ef\u4ee5\u54c8\u5e0c\u5316\uff08\u5373\u662f\u5426\u53ef\u4ee5\u7528\u4f5c\u5b57\u5178\u7684\u952e\uff09\uff0c\u672f\u8bed\u53eb\u4f5c\u54c8\u5e0c\u5316\u3002 print ( hash ( 'string' )) # -4368784820203065343 print ( hash (( 1 , 2 , ( 2 , 3 )))) # -9209053662355515447 print ( hash (( 1 , 2 , [ 2 , 3 ]))) # TypeError: unhashable type: 'list' print ( hash (( 1 , 2 , tuple ([ 2 , 3 ])))) # -9209053662355515447 \u4e3a\u4e86\u5c06\u5217\u8868\u4f5c\u4e3a\u952e\uff0c\u4e00\u79cd\u65b9\u5f0f\u5c31\u662f\u5c06\u5176\u8f6c\u6362\u4e3a\u5143\u7ec4 \u5b57\u5178\u9ed8\u8ba4\u503c\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5b9e\u73b0\u4e86\u5c06\u4e00\u4e2a\u5355\u8bcd\u7ec4\u6210\u7684\u5217\u8868\uff0c\u8f6c\u6362\u6210\u5355\u8bcd\u9996\u5b57\u6bcd\u548c\u5355\u8bcd\u4e3a\u952e\u503c\u5bf9\u7684\u5b57\u5178\u3002\u5148\u7528\u4f20\u7edf\u65b9\u6cd5\u5b9e\u73b0\uff0c\u518d\u7528\u5b57\u5178\u7684setdefault\u65b9\u6cd5\u8fdb\u884c\u6539\u5199\u3002 \u5148\u770b\u4f20\u7edf\u65b9\u6cd5\u3002 words = [ 'apple' , 'bat' , 'bar' , 'atom' , 'book' ] by_letter = {} for word in words : letter = word [ 0 ] # word[0]\u628a\u5217\u8868words\u7684\u6bcf\u4e2a\u5143\u7d20\u5217\u8868\u5316\uff0c\u5e76\u53d6\u9996\u5b57\u6bcd\u3002\u8f93\u51fa\u7684\u662fa, b, b, a, b\u8fd95\u4e2a\u5217\u8868\u5143\u7d20\u7684\u9996\u5b57\u6bcd if letter not in by_letter : # \u751f\u6210\u7b2c\u4e00\u4e2a\u952e\u503c\u5bf9 print ( letter ) by_letter [ letter ] = [ word ] # \u5bf9\u6bd4[word]\u548cword[]\u7684\u7528\u6cd5 print ( by_letter ) # a # {'a': ['apple']} # b # {'a': ['apple'], 'b': ['bat']} else : # append\u5176\u4ed6\u952e\u503c\u5bf9 print ( letter ) by_letter [ letter ] . append ( word ) print ( by_letter ) # b # {'a': ['apple'], 'b': ['bat', 'bar']} # a # {'a': ['apple', 'atom'], 'b': ['bat', 'bar']} # b # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} print ( by_letter ) # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} \u7528\u5b57\u5178\u7684setdefault\u65b9\u6cd5\uff0c\u4e0a\u8ff0\u7684for\u5faa\u73af\u8bed\u53e5\u53ef\u4ee5\u88ab\u5199\u4e3a\u5982\u4e0b\u3002 words = [ 'apple' , 'bat' , 'bar' , 'atom' , 'book' ] by_letter = {} for word in words : letter = word [ 0 ] # word[0]\u7684\u8f93\u51fa\u4f9d\u7136\u662f5\u4e2a\u5217\u8868\u5143\u7d20\u7684\u9996\u5b57\u6bcda, b, b, a, b by_letter . setdefault ( letter , []) . append ( word ) # \u5982\u679cletter\u4e0d\u5728[]\u5219\u901a\u8fc7append\u6dfb\u52a0word print ( by_letter ) # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} \u5982\u679c\u6539\u5199\u4e3a by_letter.setdefault(letter, ['a']).append(word) \uff0c\u5219\u8f93\u51fa by_letter \u662f {'a': ['a', 'apple', 'atom'], 'b': ['a', 'bat', 'bar', 'book']} \u3002 words = [ 'apple' , 'bat' , 'bar' , 'atom' , 'book' ] by_letter = {} for word in words : letter = word [ 0 ] # word[0]\u7684\u8f93\u51fa\u4f9d\u7136\u662f5\u4e2a\u5217\u8868\u5143\u7d20\u7684\u9996\u5b57\u6bcda, b, b, a, b by_letter . setdefault ( letter , [ 'a' ]) . append ( word ) print ( by_letter ) # {'a': ['a', 'apple', 'atom'], 'b': ['a', 'bat', 'bar', 'book']} \u4f53\u4f1asetdefault()\u7684\u6ce8\u91ca\u201cInsert key with a value of default if key is not in the dictionary. Return the value for key if key is in the dictionary, else default.\u201d \u901a\u8fc7defaultdict\u7c7b\u4f7f\u5f97\u4e0a\u8ff0\u76ee\u7684\u5b9e\u73b0\u66f4\u4e3a\u7b80\u5355\u3002 from collections import defaultdict by_letter = defaultdict ( list ) # list\u662f\u5185\u7f6e\u7684\u53ef\u53d8\u5e8f\u5217(Built-in mutable sequence) print ( dict ( by_letter )) # {} for word in words : by_letter [ word [ 0 ]] . append ( word ) print ( by_letter ) # defaultdict(, {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']}) print ( dict ( by_letter )) # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} \u4e0b\u8868\u5c55\u793a\u4e86 dict \u3001 defaultdict \u548c OrderedDict \u7684\u5e38\u89c1\u65b9\u6cd5\uff0c\u540e\u9762\u4e24\u4e2a\u6570\u636e\u7c7b\u578b\u662f dict \u7684\u53d8\u79cd\uff0c\u4f4d\u4e8e collections \u6a21\u5757\u5185\u3002 default_factory \u5e76\u4e0d\u662f\u4e00\u4e2a\u65b9\u6cd5\uff0c\u800c\u662f\u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61\uff08callable\uff09\uff0c\u5b83\u7684\u503c\u5728 defaultdict \u521d\u59cb\u5316\u7684\u65f6\u5019\u7531\u7528\u6237\u8bbe\u5b9a\u3002 OrderedDict.popitem() \u4f1a\u79fb\u9664\u5b57\u5178\u91cc\u6700\u5148\u63d2\u5165\u7684\u5143\u7d20\uff08\u5148\u8fdb\u5148\u51fa\uff09\uff1b\u540c\u65f6\u8fd9\u4e2a\u65b9\u6cd5\u8fd8\u6709\u4e00\u4e2a\u53ef\u9009\u7684last\u53c2\u6570\uff0c\u82e5\u4e3a\u771f\uff0c\u5219\u4f1a\u79fb\u9664\u6700\u540e\u63d2\u5165\u7684\u5143\u7d20\uff08\u540e\u8fdb\u5148\u51fa\uff09\u3002 \u4e0a\u9762\u7684\u8868\u683c\u4e2d\uff0cupdate\u65b9\u6cd5\u5904\u7406\u53c2\u6570m\u7684\u65b9\u5f0f\uff0c\u662f\u5178\u578b\u7684\u201c\u9e2d\u5b50\u7c7b\u578b\u201d\u3002\u51fd\u6570\u9996\u5148\u68c0\u67e5m\u662f\u5426\u6709keys\u65b9\u6cd5\uff0c\u5982\u679c\u6709\uff0c\u90a3\u4e48update\u51fd\u6570\u5c31\u628a\u5b83\u5f53\u4f5c\u6620\u5c04\u5bf9\u8c61\u6765\u5904\u7406\u3002\u5426\u5219\uff0c\u51fd\u6570\u4f1a\u9000\u4e00\u6b65\uff0c\u8f6c\u800c\u628am\u5f53\u4f5c\u5305\u542b\u4e86\u952e\u503c\u5bf9(key, value)\u5143\u7d20\u7684\u8fed\u4ee3\u5668\u3002Python\u91cc\u5927\u591a\u6570\u6620\u5c04\u7c7b\u578b\u7684\u6784\u9020\u65b9\u6cd5\u90fd\u91c7\u7528\u4e86\u7c7b\u4f3c\u7684\u903b\u8f91\uff0c\u56e0\u6b64\u4f60\u65e2\u53ef\u4ee5\u7528\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\u6765\u65b0\u5efa\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\uff0c\u4e5f\u53ef\u4ee5\u7528\u5305\u542b(key, value)\u5143\u7d20\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\u6765\u521d\u59cb\u5316\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\u3002 \u5b57\u5178\u7684\u53d8\u79cd\uff1a collections.OrderedDict \u8fd9\u4e2a\u7c7b\u578b\u5728\u6dfb\u52a0\u952e\u7684\u65f6\u5019\u4f1a\u4fdd\u6301\u987a\u5e8f\uff0c\u56e0\u6b64\u952e\u7684\u8fed\u4ee3\u6b21\u5e8f\u603b\u662f\u4e00\u81f4\u7684\u3002OrderedDict\u7684popitem\u65b9\u6cd5\u9ed8\u8ba4\u5220\u9664\u5e76\u8fd4\u56de\u7684\u662f\u5b57\u5178\u91cc\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff0c\u4f46\u662f\u5982\u679c\u50cfmy_odict.popitem(last=False)\u8fd9\u6837\u8c03\u7528\u5b83\uff0c\u90a3\u4e48\u5b83\u5220\u9664\u5e76\u8fd4\u56de\u7b2c\u4e00\u4e2a\u88ab\u6dfb\u52a0\u8fdb\u53bb\u7684\u5143\u7d20\u3002 collections.ChainMap \u8be5\u7c7b\u578b\u53ef\u4ee5\u5bb9\u7eb3\u6570\u4e2a\u4e0d\u540c\u7684\u6620\u5c04\u5bf9\u8c61\uff0c\u7136\u540e\u5728\u8fdb\u884c\u952e\u67e5\u627e\u64cd\u4f5c\u7684\u65f6\u5019\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u4f1a\u88ab\u5f53\u4f5c\u4e00\u4e2a\u6574\u4f53\u88ab\u9010\u4e2a\u67e5\u627e\uff0c\u76f4\u5230\u952e\u88ab\u627e\u5230\u4e3a\u6b62\u3002\u8fd9\u4e2a\u529f\u80fd\u5728\u7ed9\u6709\u5d4c\u5957\u4f5c\u7528\u57df\u7684\u8bed\u8a00\u505a\u89e3\u91ca\u5668\u7684\u65f6\u5019\u5f88\u6709\u7528\uff0c\u53ef\u4ee5\u7528\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\u6765\u4ee3\u8868\u4e00\u4e2a\u4f5c\u7528\u57df\u7684\u4e0a\u4e0b\u6587\u3002 collections.Counter \u8fd9\u4e2a\u6620\u5c04\u7c7b\u578b\u4f1a\u7ed9\u952e\u51c6\u5907\u4e00\u4e2a\u6574\u6570\u8ba1\u6570\u5668\u3002\u6bcf\u6b21\u66f4\u65b0\u4e00\u4e2a\u952e\u7684\u65f6\u5019\u90fd\u4f1a\u589e\u52a0\u8fd9\u4e2a\u8ba1\u6570\u5668\u3002\u6240\u4ee5\u8fd9\u4e2a\u7c7b\u578b\u53ef\u4ee5\u7528\u6765\u7ed9\u53ef\u6563\u5217\u8868\u5bf9\u8c61\u8ba1\u6570\uff0c\u6216\u8005\u662f\u5f53\u6210\u591a\u91cd\u96c6\u6765\u7528\u2014\u2014\u591a\u91cd\u96c6\u5408\u5c31\u662f\u96c6\u5408\u91cc\u7684\u5143\u7d20\u53ef\u4ee5\u51fa\u73b0\u4e0d\u6b62\u4e00\u6b21\u3002Counter\u5b9e\u73b0\u4e86+\u548c-\u8fd0\u7b97\u7b26\u7528\u6765\u5408\u5e76\u8bb0\u5f55\uff0c\u8fd8\u6709\u50cfmost_common([n])\u8fd9\u7c7b\u5f88\u6709\u7528\u7684\u65b9\u6cd5\u3002most_common([n])\u4f1a\u6309\u7167\u6b21\u5e8f\u8fd4\u56de\u6620\u5c04\u91cc\u6700\u5e38\u89c1\u7684n\u4e2a\u952e\u548c\u5b83\u4eec\u7684\u8ba1\u6570 collections.UserDict \u8fd9\u4e2a\u7c7b\u5176\u5b9e\u5c31\u662f\u628a\u6807\u51c6dict\u7528\u7eafPython\u53c8\u5b9e\u73b0\u4e86\u4e00\u904d\u3002\u8ddfOrderedDict\u3001ChainMap\u548cCounter\u8fd9\u4e9b\u5f00\u7bb1\u5373\u7528\u7684\u7c7b\u578b\u4e0d\u540c\uff0cUserDict\u662f\u8ba9\u7528\u6237\u7ee7\u627f\u5199\u5b50\u7c7b\u7684\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u5229\u7528Counter\u6765\u8ba1\u7b97\u5355\u8bcd\u4e2d\u5404\u4e2a\u5b57\u6bcd\u51fa\u73b0\u7684\u6b21\u6570\uff1a str = 'abracadabra' ct = collections . Counter ( str ) print ( ct ) # Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}) \u4e0d\u53ef\u53d8\u6620\u5c04\u7c7b\u578b\u3002 \u6807\u51c6\u5e93\u91cc\u6240\u6709\u7684\u6620\u5c04\u7c7b\u578b\u90fd\u662f\u53ef\u53d8\u7684\uff0c\u4f46\u6709\u65f6\u5019\u4f60\u4f1a\u6709\u8fd9\u6837\u7684\u9700\u6c42\uff0c\u6bd4\u5982\u4e0d\u80fd\u8ba9\u7528\u6237\u9519\u8bef\u5730\u4fee\u6539\u67d0\u4e2a\u6620\u5c04\u3002 \u4ecePython 3.3\u5f00\u59cb\uff0c types \u6a21\u5757\u4e2d\u5f15\u5165\u4e86\u4e00\u4e2a\u5c01\u88c5\u7c7b\u540d\u53eb MappingProxyType \u3002\u5982\u679c\u7ed9\u8fd9\u4e2a\u7c7b\u4e00\u4e2a\u6620\u5c04\uff0c\u5b83\u4f1a\u8fd4\u56de\u4e00\u4e2a\u53ea\u8bfb\u7684\u6620\u5c04\u89c6\u56fe\u3002\u867d\u7136\u662f\u4e2a\u53ea\u8bfb\u89c6\u56fe\uff0c\u4f46\u662f\u5b83\u662f\u52a8\u6001\u7684\u3002\u8fd9\u610f\u5473\u7740\u5982\u679c\u5bf9\u539f\u6620\u5c04\u505a\u51fa\u4e86\u6539\u52a8\uff0c\u6211\u4eec\u901a\u8fc7\u8fd9\u4e2a\u89c6\u56fe\u53ef\u4ee5\u89c2\u5bdf\u5230\uff0c\u4f46\u662f\u65e0\u6cd5\u901a\u8fc7\u8fd9\u4e2a\u89c6\u56fe\u5bf9\u539f\u6620\u5c04\u505a\u51fa\u4fee\u6539\u3002 \u901a\u8fc7\u4e0b\u4f8b\u53ef\u4ee5\u770b\u51fa\uff0c d \u4e2d\u7684\u5185\u5bb9\u53ef\u4ee5\u901a\u8fc7 d_proxy \u770b\u5230\u3002\u4f46\u662f\u901a\u8fc7 d_proxy \u5e76\u4e0d\u80fd\u505a\u4efb\u4f55\u4fee\u6539\u3002 d_proxy \u662f\u52a8\u6001\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\u5bf9 d \u6240\u505a\u7684\u4efb\u4f55\u6539\u52a8\u90fd\u4f1a\u53cd\u9988\u5230\u5b83\u4e0a\u9762\u3002 from types import MappingProxyType d = { 1 : 'A' } d_proxy = MappingProxyType ( d ) print ( d ) # {1: 'A'} print ( d_proxy ) # {1: 'A'} print ( d [ 1 ]) # A print ( d_proxy [ 1 ]) # A d [ 2 ] = 'W' print ( d ) # {1: 'A', 2: 'W'} d_proxy [ 2 ] = 'W' # TypeError: 'mappingproxy' object does not support item assignment print ( d_proxy ) # {1: 'A', 2: 'W'} 1.5 \u96c6\u5408\uff08set\uff09 \u00b6 \u201c\u96c6\u201d\u8fd9\u4e2a\u6982\u5ff5\u5728Python\u4e2d\u7b97\u662f\u6bd4\u8f83\u5e74\u8f7b\u7684\uff0c\u540c\u65f6\u5b83\u7684\u4f7f\u7528\u7387\u4e5f\u6bd4\u8f83\u4f4e\u3002set\u548c\u5b83\u7684\u4e0d\u53ef\u53d8\u7684\u59ca\u59b9\u7c7b\u578bfrozenset\u76f4\u5230Python 2.3\u624d\u9996\u6b21\u4ee5\u6a21\u5757\u7684\u5f62\u5f0f\u51fa\u73b0\uff0c\u7136\u540e\u5728Python 2.6\u4e2d\u5b83\u4eec\u5347\u7ea7\u6210\u4e3a\u5185\u7f6e\u7c7b\u578b\u3002 \u96c6\u5408(set) \uff0c\u5305\u542b\u4e0d\u53ef\u53d8\u7684\u96c6\u5408\uff08frozenset\uff09\uff0c\u662f\u4e00\u79cd\u65e0\u5e8f\u4e14\u5143\u7d20\u552f\u4e00\u7684\u5e8f\u5217\uff0c\u6240\u4ee5\u96c6\u5408\u7684\u672c\u8d28\u662f\u8bb8\u591a\u552f\u4e00\u5bf9\u8c61\u7684\u805a\u96c6\u3002 \u548c\u5b57\u5178\u7c7b\u4f3c\uff0c\u96c6\u5408\u7684\u5143\u7d20\u662f\u4e0d\u53ef\u53d8\u7684\u3002\u53ef\u4ee5\u8ba4\u4e3a\u96c6\u5408\u4e5f\u50cf\u5b57\u5178\uff0c\u4f46\u662f\u53ea\u6709\u952e\u6ca1\u6709\u503c\u3002\u57fa\u672c\u529f\u80fd\u662f\u8fdb\u884c\u6210\u5458\u5173\u7cfb\u6d4b\u8bd5\u548c\u5220\u9664\u91cd\u590d\u5143\u7d20\u3002\u6240\u4ee5\u96c6\u5408\u53e6\u4e00\u4e2a\u7528\u9014\u662f\u53bb\u91cd\u590d\u3002 \u96c6\u5408\u4e2d\u7684\u5143\u7d20\u5fc5\u987b\u662f\u53ef\u6563\u5217\u7684\uff0cset\u7c7b\u578b\u672c\u8eab\u662f\u4e0d\u53ef\u6563\u5217\u7684\uff0c\u4f46\u662ffrozenset\u53ef\u4ee5\u3002\u56e0\u6b64\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u5305\u542b\u4e0d\u540cfrozenset\u7684set\u3002 \u96c6\u5408\u53ef\u4ee5\u6709\u4e24\u79cd\u521b\u5efa\u65b9\u5f0f\uff1a\u901a\u8fc7set()\u51fd\u6570\u6216\u8005{}\u6765\u521b\u5efa\uff08\u7528\u5927\u62ec\u53f7\u62ec\u4f4f\u7684\u5185\u5bb9\uff0cPython3\u81ea\u52a8\u5b9a\u4e49\u4e3a\u96c6\u5408\uff09\u3002 \u96c6\u5408\u4e0d\u5c5e\u4e8e\u5e8f\u5217\u7c7b\u6570\u636e\uff0c \u96c6\u5408\u4e0d\u652f\u6301\u901a\u8fc7\u7d22\u5f15\u8bbf\u95ee\u6307\u5b9a\u5143\u7d20\uff0c\u4f46\u53ef\u4ee5\u589e\u52a0\u548c\u5220\u9664\u5143\u7d20\u3002 \u9762\u7684\u4f8b\u5b50\u662f\u6c42 haystacke \u548c needles \u4e24\u4e2a\u96c6\u5408\u7684\u4ea4\u96c6\u5143\u7d20\u4e2a\u6570\u3002 haystacke = { 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'f' , 'g' , 'h' , 'c' , 'd' , 'e' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' } needles = { 'c' , 'h' , 'w' } type ( haystacke ) # type ( needles ) # # \u4f20\u7edf\u65b9\u6cd5 found = 0 for i in needles : if i in haystacke : found += 1 print ( found ) # 2 # \u96c6\u5408\u65b9\u6cd5\u4e00 found = len ( needles & haystacke ) print ( found ) # 2 # \u96c6\u5408\u65b9\u6cd5\u4e8c found = len ( needles . intersection ( haystacke )) print ( found ) # 2 \u96c6\u5408\u5b9e\u73b0\u4e86\u5f88\u591a\u57fa\u7840\u7684\u4e2d\u7f00\u8fd0\u7b97\u7b26\uff0c\u6bd4\u5982\uff0c\u96c6\u5408\u652f\u6301\u6570\u5b66\u4e0a\u7684\u96c6\u5408\u64cd\u4f5c\uff1a\u5e76\u96c6\u3001\u4ea4\u96c6\u3001\u5dee\u96c6\u3001\u5bf9\u79f0\u5dee\u96c6\u3002 \u65b9\u6cd5\u540d\u79f0 \u8bf4\u660e add() \u4e3a\u96c6\u5408\u6dfb\u52a0\u5143\u7d20 update() \u7ed9\u96c6\u5408\u6dfb\u52a0\u5143\u7d20 clear() \u79fb\u9664\u96c6\u5408\u4e2d\u7684\u6240\u6709\u5143\u7d20 copy() \u62f7\u8d1d\u4e00\u4e2a\u96c6\u5408 remove() \u79fb\u9664\u6307\u5b9a\u5143\u7d20 pop() \u968f\u673a\u79fb\u9664\u5143\u7d20 discard() \u5220\u9664\u96c6\u5408\u4e2d\u6307\u5b9a\u7684\u5143\u7d20 < \u6216\u8005issubset() \u5224\u65ad\u6307\u5b9a\u96c6\u5408\u662f\u5426\u4e3a\u8be5\u65b9\u6cd5\u53c2\u6570\u96c6\u5408\u7684\u5b50\u96c6 | \u6216\u8005union() \u8fd4\u56de\u4e24\u4e2a\u96c6\u5408\u7684\u5e76\u96c6 & \u6216\u8005intersection() \u8fd4\u56de\u96c6\u5408\u7684\u4ea4\u96c6 intersection_update() \u8fd4\u56de\u96c6\u5408\u7684\u4ea4\u96c6 - \u6216\u8005difference() \u8fd4\u56de\u591a\u4e2a\u96c6\u5408\u7684\u5dee\u96c6 difference_update() \u79fb\u9664\u96c6\u5408\u4e2d\u7684\u5143\u7d20\uff0c\u8be5\u5143\u7d20\u5728\u6307\u5b9a\u7684\u96c6\u5408\u4e5f\u5b58\u5728 ^ \u6216\u8005symmetric_difference() \u8fd4\u56de\u4e24\u4e2a\u96c6\u5408\u4e2d\u4e0d\u91cd\u590d\u7684\u5143\u7d20\u96c6\u5408(\u4e24\u96c6\u5408\u9664\u53bb\u4ea4\u96c6\u90e8\u5206\u7684\u5143\u7d20) symmetric_difference_update() \u79fb\u9664\u5f53\u524d\u96c6\u5408\u4e2d\u5728\u53e6\u5916\u4e00\u4e2a\u6307\u5b9a\u96c6\u5408\u76f8\u540c\u7684\u5143\u7d20\uff0c\u5e76\u5c06\u53e6\u5916\u4e00\u4e2a\u6307\u5b9a\u96c6\u5408\u4e2d\u4e0d\u540c\u7684\u5143\u7d20\u63d2\u5165\u5230\u5f53\u524d\u96c6\u5408\u4e2d isdisjoint() \u5224\u65ad\u4e24\u4e2a\u96c6\u5408\u662f\u5426\u5305\u542b\u76f8\u540c\u7684\u5143\u7d20\uff0c\u5982\u679c\u6ca1\u6709\u8fd4\u56de True\uff0c\u5426\u5219\u8fd4\u56de False issuperset() \u5224\u65ad\u8be5\u65b9\u6cd5\u7684\u53c2\u6570\u96c6\u5408\u662f\u5426\u4e3a\u6307\u5b9a\u96c6\u5408\u7684\u5b50\u96c6 \u4e3e\u4f8b\uff1a a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } \u5e76\u96c6(a\u548cb\u4e2d\u7684\u6240\u6709\u4e0d\u540c\u5143\u7d20)\u3002 print ( a . union ( b )) # {'c', 1, 2, 'd', 'a', 'b'} print ( a | b ) # {'c', 1, 2, 'd', 'a', 'b'} \u4ea4\u96c6(a\u3001b\u4e2d\u540c\u65f6\u5305\u542b\u7684\u5143\u7d20)\u3002 print ( a . intersection ( b )) # {'c', 1} print ( a & b ) # {'c', 1} \u5c06a\u7684\u5185\u5bb9\u8bbe\u7f6e\u4e3aa\u548cb\u7684\u4ea4\u96c6\u3002 a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a . intersection_update ( b ) print ( a ) # {1, 'c'} \u5728a\u4e0d\u5728b\u7684\u5143\u7d20\u3002 print ( a . difference ( b )) # {'a', 2, 'b'} print ( a - b ) # {2, 'a', 'b'} \u5c06a\u7684\u5185\u5bb9\u8bbe\u4e3a\u5728a\u4e0d\u5728b\u7684\u5143\u7d20\u3002 a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a . difference_update ( b ) print ( a ) # {2, 'b', 'a'} a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a -= b print ( a ) # {2, 'a', 'b'} \u5c06\u5143\u7d20\u52a0\u5165\u96c6\u5408a\u3002 a . add ( 7 ) print ( a ) # {1, 2, 'c', 7, 'a', 'b'} \u6bcf\u6b21\u8f93\u51fa\u7684\u987a\u5e8f\u662f\u4e0d\u4e00\u6837\u7684 \u4ece\u96c6\u5408a\u79fb\u9664\u67d0\u4e2a\u5143\u7d20\u3002 a . remove ( 7 ) print ( a ) # {1, 2, 'c', 'a', 'b'} \u5982\u679ca\u88ab\u6e05\u7a7a\uff0c\u5219\u62a5\u9519 KeyError: 7 \u6240\u6709\u5728a\u6216b\u4e2d\uff0c\u4f46\u4e0d\u662f\u540c\u65f6\u5728a\u3001b\u4e2d\u7684\u5143\u7d20\u3002 print ( a . symmetric_difference ( b )) # {2, 'd', 'b', 'a'} print ( a ^ b ) # {2, 'd', 'b', 'a'} \u5c06a\u7684\u5185\u5bb9\u8bbe\u4e3a\u6240\u6709\u5728a\u6216b\u4e2d\uff0c\u4f46\u4e0d\u662f\u540c\u65f6\u5728a\u3001b\u4e2d\u7684\u5143\u7d20\u3002 a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a . symmetric_difference_update ( b ) print ( a ) # {'a', 2, 'd', 'b'} a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a ^= b print ( a ) # {2, 'd', 'a', 'b'} \u5982\u679ca\u5305\u542b\u4e8eb\uff0c\u8fd4\u56deTure\u3002 print ( a . issubset ( b )) # False \u5c06a\u7684\u5185\u5bb9\u8bbe\u7f6e\u4e3aa\u548cb\u7684\u5e76\u96c6\u3002 print ( a ) # {'a', 2, 'd', 'b'} a = { 'a' , 'b' , 'c' , 1 , 2 } a . update ( b ) print ( a ) # {1, 2, 'a', 'b', 'd', 'c'} \u79fb\u9664\u4efb\u610f\u5143\u7d20\uff0c\u5982\u679c\u96c6\u5408\u662f\u7a7a\u7684\uff0c\u629b\u51fakeyError\u3002 a . pop () # \u968f\u673a\u79fb\u9664\u67d0\u4e2a\u5143\u7d20\uff0c\u6ca1\u6709\u8f93\u5165\u53d8\u91cf\uff0c\u5982\u679c\u96c6\u5408\u662f\u7a7a\u7684\uff0c\u629b\u51faKeyError: 'pop from an empty set' print ( a ) # {2, 1, 'd', 'b', 'a'} \u5c06\u96c6\u5408\u91cd\u7f6e\u4e3a\u7a7a\uff0c\u6e05\u7a7a\u6240\u6709\u5143\u7d20\u3002 a . clear () print ( a ) # set() \u96c6\u5408\u7684\u5143\u7d20\u5fc5\u987b\u662f\u4e0d\u53ef\u53d8\u7684\uff0c\u5982\u679c\u60f3\u8981\u5305\u542b\u5217\u8868\u578b\u7684\u5143\u7d20\uff0c\u5fc5\u987b\u5148\u8f6c\u6362\u4e3a\u5143\u7ec4\u3002 my_data1 = [ 1 , 2 , 3 , 4 ] my_data2 = [ 3 , 4 , 5 , 6 ] my_set = { tuple ( my_data1 ), tuple ( my_data2 )} print ( my_set ) # {(1, 2, 3, 4), (3, 4, 5, 6)} 1.6 \u5143\u7ec4\uff08tuple\uff09 \u00b6 Python \u7684\u5143\u7ec4\u4e0e\u5217\u8868\u7c7b\u4f3c\uff0c\u4e0d\u540c\u4e4b\u5904\u5728\u4e8e\u5143\u7ec4\u7684\u5143\u7d20\u4e0d\u80fd\u4fee\u6539\u3002 \u5143\u7ec4\u4f7f\u7528\u5c0f\u62ec\u53f7( )\uff0c\u5217\u8868\u4f7f\u7528\u65b9\u62ec\u53f7[ ]\u3002 \u5143\u7ec4\u4e2d\u53ea\u5305\u542b\u4e00\u4e2a\u5143\u7d20\u65f6\uff0c\u9700\u8981\u5728\u5143\u7d20\u540e\u9762\u6dfb\u52a0\u9017\u53f7 \uff0c\u5426\u5219\u62ec\u53f7\u4f1a\u88ab\u5f53\u4f5c\u8fd0\u7b97\u7b26\u4f7f\u7528\u3002 \u5143\u7ec4\u53ef\u4ee5\u4f7f\u7528\u4e0b\u6807\u7d22\u5f15\u6765\u8bbf\u95ee\u5143\u7ec4\u4e2d\u7684\u503c\u3002 \u5143\u7ec4\u4e2d\u7684\u5143\u7d20\u503c\u662f\u4e0d\u5141\u8bb8\u4fee\u6539\u7684\uff0c\u4f46\u6211\u4eec\u53ef\u4ee5\u5bf9\u5143\u7ec4\u8fdb\u884c\u8fde\u63a5\u7ec4\u5408\u3002 \u5143\u7ec4\u4e2d\u7684\u5143\u7d20\u503c\u662f\u4e0d\u5141\u8bb8\u5220\u9664\u7684\uff0c\u4f46\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528del\u8bed\u53e5\u6765\u5220\u9664\u6574\u4e2a\u5143\u7ec4\u3002 # \u6b64\u5904\u62ec\u53f7\u88ab\u89e3\u6790\u4e3a\u8fd0\u7b97\u7b26\uff0c\u9700\u8981\u5728\u540e\u9762\u52a0\u4e0a\u9017\u53f7\u624d\u4f1a\u88ab\u89e3\u91ca\u4e3a\u5143\u7ec4 tup1 = ( 10 ) print ( type ( tup1 )) # tup1 = ( 10 ,) print ( type ( tup1 )) # \u521b\u5efa\u5143\u7ec4\u6700\u7b80\u5355\u7684\u529e\u6cd5\u5c31\u662f\u7528\u9017\u53f7\u5206\u9694\u5e8f\u5217\u503c\u3002\u5143\u7ec4\u5bf9\u6570\u636e\u7c7b\u578b\u6ca1\u6709\u4e00\u81f4\u6027\u8981\u6c42\u3002 tup = 4 , 5 , 6 print ( tup ) # (4, 5, 6) nested_tup = ( 4 , 5 , 6 ), ( 7 , 8 ) print ( nested_tup ) # # ((4, 5, 6), (7, 8)) tup = ( 'a' , 'b' , { 'one' : 1 }) print ( type ( tup )) # \u4f7f\u7528\u52a0\u53f7\uff08+\uff09\u8fdb\u884c\u5143\u7ec4\u8fde\u63a5\u5408\u5e76\u3002 tup = tuple (( 4 , None , 'fool' ) + ( 6 , 0 ) + ( 'bar' ,)) print ( tup ) # (4, None, 'fool', 6, 0, 'bar') \u5143\u7ec4\u7684\u4e0d\u53ef\u53d8\u6307\u7684\u662f**\u5143\u7ec4\u6240\u6307\u5411\u7684\u5185\u5b58\u4e2d\u7684\u5185\u5bb9\u4e0d\u53ef\u53d8**\u3002 tup = ( 'h' , 'e' , 'l' , 'l' , 'o' ) print ( id ( tup )) # 139820353350208 tup = ( 1 , 2 , 3 , 4 , 5 ) print ( id ( tup )) # 139820353298896 tup [ 0 ] = 'x' # Traceback (most recent call last): # File \"\", line 1, in # TypeError: 'tuple' object does not support item assignment \u5c06\u5143\u7ec4\u4e58\u4ee5\u6574\u6570\uff0c\u5219\u4f1a\u548c\u5217\u8868\u4e00\u6837\uff0c\u751f\u6210\u542b\u6709\u591a\u4efd\u62f7\u8d1d\u7684\u5143\u7ec4\u3002\u5bf9\u8c61\u81ea\u8eab\u5e76\u6ca1\u6709\u590d\u5236\uff0c\u53ea\u662f\u6307\u5411\u5b83\u4eec\u7684\u5f15\u7528\u8fdb\u884c\u4e86\u590d\u5236\u3002 tup = tuple (( 'fool' , 'bar' ) * 4 ) print ( tup ) # ('fool', 'bar', 'fool', 'bar', 'fool', 'bar', 'fool', 'bar') \u5982\u679c\u5143\u7ec4\u4e2d\u7684\u4e00\u4e2a\u5bf9\u8c61\u662f\u53ef\u53d8\u7684\uff0c\u4f8b\u5982\u5217\u8868\uff0c\u4f60\u53ef\u4ee5\u5728\u5b83\u5185\u90e8\u8fdb\u884c\u4fee\u6539\u3002 tup = tuple ([ 'foo' , [ 4 , 5 , 6 ], True ]) tup [ 1 ] . append ( 0 ) print ( tup ) # ('foo', [4, 5, 6, 0], True) tup [ 1 ] . append ([ 9 ]) print ( tup ) # ('foo', [4, 5, 6, 0, [9]], True) \u4f7f\u7528tuple\u51fd\u6570\u5c06\u4efb\u610f\u5e8f\u5217\u6216\u8fed\u4ee3\u5668\u8f6c\u6362\u4e3a\u5143\u7ec4\u3002 tup = tuple ([ 4 , 5 , 6 ]) print ( tup ) # (4, 5, 6) tup = tuple ( 'string' ) print ( tup ) # ('s', 't', 'r', 'i', 'n', 'g') print ( tup [ 2 ]) # r # \u5143\u7ec4\u7684\u5143\u7d20\u53ef\u4ee5\u901a\u8fc7\u4e2d\u62ec\u53f7[]\u6765\u83b7\u53d6 \u5982\u679c\u8981\u5c06\u5143\u7ec4\u578b\u7684\u8868\u8fbe\u5f0f\u8d4b\u503c\u7ed9\u53d8\u91cf\uff0cPython\u4f1a\u5bf9\u7b49\u53f7\u53f3\u8fb9\u7684\u503c\u8fdb\u884c \u62c6\u5305 \u3002 tup = ( 9 , 5 , ( 8 , 7 )) a , b , c = tup print ( a ) # 9 print ( b ) # 5 print ( c ) # (8, 7) a , b , ( c , d ) = tup print ( a ) # 9 print ( b ) # 5 print ( c ) # 8 print ( d ) # 7 tup = ( 9 , 5 , ( 8 , 7 )) a , b , c = tup c , a = a , c # \u5229\u7528\u62c6\u5305\u5b9e\u73b0\u4ea4\u6362 print ( a ) # (8, 7) print ( b ) # 5 print ( c ) # 9 \u5229\u7528\u62c6\u5305\u5b9e\u73b0\u904d\u5386\u5143\u7ec4\u6216\u5217\u8868\u7ec4\u6210\u7684\u5e8f\u5217\u3002 seq = [( 1 , 2 , 3 ), ( 4 , 5 , 6 ), ( 7 , 8 , 9 )] for a , b , c in seq : print ( 'a= {0} , b= {0} , c= {0} ' . format ( a , b , c )) # \u5217\u8868\u6bcf\u4e2a\u5143\u7d20\u7684\u53d6\u503c\u987a\u5e8f # a=1, b=1, c=1 # a=4, b=4, c=4 # a=7, b=7, c=7 print ( 'a= {0} , b= {1} , c= {2} ' . format ( a , b , c )) # a=1, b=2, c=3 # a=4, b=5, c=6 # a=7, b=8, c=9 print ( 'a= {2} , b= {0} , c= {1} ' . format ( a , b , c )) # a=3, b=1, c=2 # a=6, b=4, c=5 # a=9, b=7, c=8 \u5143\u7ec4\u62c6\u5305\u529f\u80fd\u8fd8\u5305\u62ec\u7279\u6b8a\u7684\u8bed\u6cd5*rest\u3002\u5f88\u591aPython\u7f16\u7a0b\u8005\u4f1a\u4f7f\u7528\u4e0b\u5212\u7ebf\uff08_\uff09\u6765\u8868\u793a\u4e0d\u60f3\u8981\u7684\u53d8\u91cf\u3002 values = 1 , 2 , 3 , 4 , 5 a , b , * rest = values print ( a ) # 1 print ( b ) # 2 print ( * rest ) # 3 4 5 a , b , * _ = values print ( * _ ) # 3 4 5 \u5177\u540d\u5143\u7ec4\u3002 collections.namedtuple \u662f\u4e00\u4e2a\u5de5\u5382\u51fd\u6570\uff0c\u5b83\u53ef\u4ee5\u7528\u6765\u6784\u5efa\u4e00\u4e2a\u5e26\u5b57\u6bb5\u540d\u7684\u5143\u7ec4\u548c\u4e00\u4e2a\u6709\u540d\u5b57\u7684\u7c7b\u3002 \u7528namedtuple\u6784\u5efa\u7684\u7c7b\u7684\u5b9e\u4f8b\u6240\u6d88\u8017\u7684\u5185\u5b58\u8ddf\u5143\u7ec4\u662f\u4e00\u6837\u7684\uff0c\u56e0\u4e3a\u5b57\u6bb5\u540d\u90fd\u88ab\u5b58\u5728\u5bf9\u5e94\u7684\u7c7b\u91cc\u9762\u3002 \u521b\u5efa\u4e00\u4e2a\u5177\u540d\u5143\u7ec4\u9700\u8981\u4e24\u4e2a\u53c2\u6570\uff0c\u4e00\u4e2a\u662f\u7c7b\u540d( City )\uff0c\u53e6\u4e00\u4e2a\u662f\u7c7b\u7684\u5404\u4e2a\u5b57\u6bb5\u7684\u540d\u5b57( 'name country population coordinates' )\u3002\u540e\u8005\u53ef\u4ee5\u662f\u7531\u6570\u4e2a\u5b57\u7b26\u4e32\u7ec4\u6210\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff0c\u6216\u8005\u662f\u7531\u7a7a\u683c\u5206\u9694\u5f00\u7684\u5b57\u6bb5\u540d\u7ec4\u6210\u7684\u5b57\u7b26\u4e32\u3002 \u5b58\u653e\u5728\u5bf9\u5e94\u5b57\u6bb5\u91cc\u7684\u6570\u636e\u8981\u4ee5\u4e00\u4e32\u53c2\u6570\u7684\u5f62\u5f0f\u4f20\u5165\u5230\u6784\u9020\u51fd\u6570\u4e2d\uff08\u6ce8\u610f\uff0c\u5143\u7ec4\u7684\u6784\u9020\u51fd\u6570\u5374\u53ea\u63a5\u53d7\u5355\u4e00\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff09\u3002 \u5177\u540d\u5143\u7ec4\u8fd8\u6709\u4e00\u4e9b\u81ea\u5df1\u4e13\u6709\u7684\u5c5e\u6027\u3002\u4e0b\u9762\u5c55\u793a\u4e86\u51e0\u4e2a\u6700\u6709\u7528\u7684\uff1a _fields \u7c7b\u5c5e\u6027\u3001\u7c7b\u65b9\u6cd5 _make(iterable) \u548c\u5b9e\u4f8b\u65b9\u6cd5 _asdict() \u3002 _fields \u5c5e\u6027\u662f\u4e00\u4e2a\u5305\u542b\u8fd9\u4e2a\u7c7b\u6240\u6709\u5b57\u6bb5\u540d\u79f0\u7684\u5143\u7ec4\u3002 \u7528 _make() \u901a\u8fc7\u63a5\u53d7\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u6765\u751f\u6210\u8fd9\u4e2a\u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u5b83\u7684\u4f5c\u7528\u8ddf City(*delhi_data) \u662f\u4e00\u6837\u7684\u3002 _asdict() \u628a\u5177\u540d\u5143\u7ec4\u4ee5 collections.OrderedDict \u7684\u5f62\u5f0f\u8fd4\u56de\uff0c\u6211\u4eec\u53ef\u4ee5\u5229\u7528\u5b83\u6765\u628a\u5143\u7ec4\u91cc\u7684\u4fe1\u606f\u53cb\u597d\u5730\u5448\u73b0\u51fa\u6765\u3002 from collections import namedtuple City = namedtuple ( 'City' , 'name country population coordinates' ) tokyo = City ( 'Tokyo' , 'JP' , 36.933 , ( 35.689722 , 139691667 )) print ( tokyo ) # City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139691667)) print ( tokyo . population ) # 36.933 print ( tokyo [ 3 ]) # (35.689722, 139691667) print ( City . _fields ) # ('name', 'country', 'population', 'coordinates') LatLong = namedtuple ( 'LatLong' , 'lat long' ) delhi_data = ( 'Delhi NCR' , 'IN' , 21.935 , LatLong ( 28.613899 , 77.208889 )) delhi = City . _make ( delhi_data ) print ( delhi ) # City(name='Delhi NCR', country='IN', population=21.935, coordinates=LatLong(lat=28.613899, long=77.208889)) print ( delhi . _asdict ()) # OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935), ('coordinates', LatLong(lat=28.613899, long=77.208889))]) for key , value in delhi . _asdict () . items (): print ( key + ':' , value ) # name: Delhi NCR # country: IN # population: 21.935 # coordinates: LatLong(lat=28.613899, long=77.208889) \u5143\u7ec4\u8fd8\u6709\u7b2c\u4e8c\u91cd\u529f\u80fd\uff1a\u4f5c\u4e3a\u4e0d\u53ef\u53d8\u5217\u8868\u7684\u5143\u7ec4\u3002 \u4e0b\u9762\u662f\u5217\u8868\u6216\u5143\u7ec4\u7684\u65b9\u6cd5\u548c\u5c5e\u6027\u5bf9\u6bd4\u3002\u9664\u4e86\u8ddf\u589e\u51cf\u5143\u7d20\u76f8\u5173\u7684\u65b9\u6cd5\u4e4b\u5916\uff0c\u5143\u7ec4\u652f\u6301\u5217\u8868\u7684\u5176\u4ed6\u6240\u6709\u65b9\u6cd5\u3002\u8fd8\u6709\u4e00\u4e2a\u4f8b\u5916\uff0c\u5143\u7ec4\u6ca1\u6709__reversed__\u65b9\u6cd5\u3002 \u4e00\u4e2a\u5173\u4e8e+=\u548c*=\u7684\u8c1c\u9898\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u5c55\u793a\u4e86 *= \u5728\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u5e8f\u5217\u4e0a\u7684\u4f5c\u7528\u3002\u5217\u8868\u7684ID\u6ca1\u53d8\uff0c\u65b0\u5143\u7d20\u8ffd\u52a0\u5230\u5217\u8868\u4e0a\uff0c\u4f46\u6267\u884c\u589e\u91cf\u4e58\u6cd5\u540e\uff0c\u65b0\u7684\u5143\u7ec4\u88ab\u521b\u5efa\u3002 list1 = [ 1 , 2 , 3 , 4 ] id ( list1 ) # 140409777308808 list1 *= 2 print ( list1 ) # [1, 2, 3, 4, 1, 2, 3, 4] id ( list1 ) # 140409777308808 tuple1 = ( 1 , 2 , 3 , 4 ) id ( tuple1 ) # 140409777230536 tuple1 *= 2 print ( tuple1 ) # (1, 2, 3, 4, 1, 2, 3, 4) id ( tuple1 ) # 140409780104888 \u4f46\u5bf9\u4e8e\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u867d\u7136 tuple1[2] += [50, 60] \u6267\u884c\u65f6\u6709\u5f02\u5e38\u629b\u51fa\uff0c\u4f46 tuple1 \u5374\u88ab\u4fee\u6539\u4e86\u3002 t = ( 1 , 2 , [ 10 , 20 ]) t [ 2 ] += [ 50 , 60 ] # TypeError: 'tuple' object does not support item assignment print ( t ) # (1, 2, [10, 20, 50, 60]) \u4e0b\u56fe\u5927\u81f4\u63cf\u8ff0\u4e86\u4e0a\u8ff0\u6267\u884c\u8fc7\u7a0b\u3002 \u4e3a\u4e86\u907f\u514d\u4e0a\u9762\u60c5\u51b5\u7684\u53d1\u751f\uff0c\u6211\u4eec**\u4e0d\u8981\u628a\u53ef\u53d8\u5bf9\u8c61\u653e\u5728\u5143\u7ec4\u91cc\u9762**\u3002\u589e\u91cf\u8d4b\u503c\u4e0d\u662f\u4e00\u4e2a\u539f\u5b50\u64cd\u4f5c\uff0c\u5b83\u867d\u7136\u629b\u51fa\u4e86\u5f02\u5e38\uff0c\u4f46\u8fd8\u662f\u5b8c\u6210\u4e86\u64cd\u4f5c\u3002 1.7 \u5185\u5b58\u89c6\u56feMemoryview \u00b6 memoryview \u662f\u4e00\u4e2a\u5185\u7f6e\u7c7b\uff0c\u5b83\u80fd\u8ba9\u7528\u6237\u5728\u4e0d\u590d\u5236\u5185\u5bb9\u7684\u60c5\u51b5\u4e0b\u64cd\u4f5c\u540c\u4e00\u4e2a\u6570\u7ec4\u7684\u4e0d\u540c\u5207\u7247\u3002 \u5185\u5b58\u89c6\u56fe\u5176\u5b9e\u662f\u6cdb\u5316\u548c\u53bb\u6570\u5b66\u5316\u7684NumPy\u6570\u7ec4\u3002\u5b83\u8ba9\u4f60\u5728\u4e0d\u9700\u8981\u590d\u5236\u5185\u5bb9\u7684\u524d\u63d0\u4e0b\uff0c\u5728\u6570\u636e\u7ed3\u6784\u4e4b\u95f4\u5171\u4eab\u5185\u5b58\u3002 \u5176\u4e2d\u6570\u636e\u7ed3\u6784\u53ef\u4ee5\u662f\u4efb\u4f55\u5f62\u5f0f\uff0c\u6bd4\u5982PIL\u56fe\u7247\u3001SQLite\u6570\u636e\u5e93\u548cNumPy\u7684\u6570\u7ec4\uff0c\u7b49\u7b49\u3002\u8fd9\u4e2a\u529f\u80fd\u5728\u5904\u7406\u5927\u578b\u6570\u636e\u96c6\u5408\u7684\u65f6\u5019\u975e\u5e38\u91cd\u8981\u3002 memoryview.cast \u7684\u6982\u5ff5\u8ddf\u6570\u7ec4\u6a21\u5757\u7c7b\u4f3c\uff0c\u80fd\u7528\u4e0d\u540c\u7684\u65b9\u5f0f\u8bfb\u5199\u540c\u4e00\u5757\u5185\u5b58\u6570\u636e\uff0c\u800c\u4e14\u5185\u5bb9\u5b57\u8282\u4e0d\u4f1a\u968f\u610f\u79fb\u52a8\u3002\u8fd9\u8ddfC\u8bed\u8a00\u4e2d\u7c7b\u578b\u8f6c\u6362\u7684\u6982\u5ff5\u5dee\u4e0d\u591a\u3002 memoryview.cast \u4f1a\u628a\u540c\u4e00\u5757\u5185\u5b58\u91cc\u7684\u5185\u5bb9\u6253\u5305\u6210\u4e00\u4e2a\u5168\u65b0\u7684memoryview\u5bf9\u8c61\u7ed9\u4f60\u3002 array \u91cc\u9762\u7684Type code\uff1a 'b' signed integer 1 'B' unsigned integer 1 'u' Unicode character 2 (see note) 'h' signed integer 2 'H' unsigned integer 2 'i' signed integer 2 'I' unsigned integer 2 'l' signed integer 4 'L' unsigned integer 4 'q' signed integer 8 (see note) 'Q' unsigned integer 8 (see note) 'f' floating point 4 'd' floating point 8 numbers = array ( 'h' , [ - 2 , - 1 , 0 , 1 , 2 ]) # array('h', [-2, -1, 0, 1, 2]) # \u75285\u4e2a\u77ed\u6574\u578b\u6709\u7b26\u53f7\u6574\u6570\u7684\u6570\u7ec4\uff08\u7c7b\u578b\u7801\u662f'h'\uff09\u521b\u5efa\u4e00\u4e2amemoryview\u3002 memv = memoryview ( numbers ) # memv\u91cc\u76845\u4e2a\u5143\u7d20\u8ddf\u6570\u7ec4\u91cc\u7684\u6ca1\u6709\u533a\u522b\u3002 print ( len ( memv )) # 5 print ( memv [ 0 ]) # -2 print ( memv . tolist ()) # [-2, -1, 0, 1, 2] # \u521b\u5efa\u4e00\u4e2amemv_oct\uff0c\u8fd9\u4e00\u6b21\u662f\u628amemv\u91cc\u7684\u5185\u5bb9\u8f6c\u6362\u6210'B'\u7c7b\u578b\uff0c\u4e5f\u5c31\u662f\u65e0\u7b26\u53f7\u5b57\u7b26\u3002 memv_oct = memv . cast ( 'B' ) print ( memv_oct . tolist ()) # [254, 255, 255, 255, 0, 0, 1, 0, 2, 0] # \u628a\u4f4d\u4e8e\u4f4d\u7f6e5\u7684\u5b57\u8282\u8d4b\u503c\u62104\u3002\u56e0\u4e3a\u6211\u4eec\u628a\u53602\u4e2a\u5b57\u8282\u7684\u6574\u6570\u7684\u9ad8\u4f4d\u5b57\u8282\u6539\u6210\u4e864\uff0c\u6240\u4ee5\u8fd9\u4e2a\u6709\u7b26\u53f7\u6574\u6570\u7684\u503c\u5c31\u53d8\u6210\u4e861024\u3002 memv_oct [ 5 ] = 4 print ( numbers ) # array('h', [-2, -1, 1024, 1, 2]) 2. \u52a8\u6001\u5f15\u7528\u3001\u5f3a\u7c7b\u578b \u00b6 \u661f\u53f7 * \u7684\u53c2\u6570\u4f1a\u4ee5\u5143\u7ec4(tuple)\u7684\u5f62\u5f0f\u5bfc\u5165\uff0c\u5b58\u653e\u6240\u6709\u672a\u547d\u540d\u7684\u53d8\u91cf\u53c2\u6570 def printinfo ( arg1 , * vartuple ): print ( \"\u8f93\u51fa\u4efb\u4f55\u4f20\u5165\u7684\u53c2\u6570: \" ) print ( arg1 ) print ( vartuple ) for var in vartuple : print ( var ) return printinfo ( 10 ) # 10 # () printinfo ( 70 , 60 , 50 ) # 70 # (60, 50) # 60 # 50 \u4e24\u4e2a\u661f\u53f7 ** \u7684\u53c2\u6570\u4f1a\u4ee5\u5b57\u5178\u7684\u5f62\u5f0f\u5bfc\u5165\u3002 def printinfo ( arg1 , ** vardict ): print ( \"\u8f93\u51fa\u4efb\u4f55\u4f20\u5165\u7684\u53c2\u6570: \" ) print ( arg1 ) print ( vardict ) printinfo ( 1 , a = 2 , b = 3 ) # 1 # {'a': 2, 'b': 3} \u5b57\u5178\u683c\u5f0f\u8f93\u51fa Python\u4e2d\u7684\u5bf9\u8c61\u5f15\u7528\u5e76\u4e0d\u6d89\u53ca\u7c7b\u578b\u3002\u53d8\u91cf\u5bf9\u4e8e\u5bf9\u8c61\u6765\u8bf4\u53ea\u662f\u7279\u5b9a\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u540d\u79f0\uff1b\u7c7b\u578b\u4fe1\u606f\u662f\u5b58\u50a8\u5728\u5bf9\u8c61\u81ea\u8eab\u4e4b\u4e2d\u3002 a = 5 print ( type ( a )) # a = 'foo' print ( type ( a )) # Python\u662f\u5f3a\u7c7b\u578b\u8bed\u8a00\uff0c\u6240\u6709\u7684\u5bf9\u8c61\u90fd\u62e5\u6709\u4e00\u4e2a\u6307\u5b9a\u7684\u7c7b\u578b\uff08\u6216\u7c7b\uff09\uff0c\u9690\u5f0f\u7684\u8f6c\u6362\u53ea\u5728\u67d0\u4e9b\u7279\u5b9a\u3001\u660e\u663e\u7684\u60c5\u51b5\u4e0b\u53d1\u751f\u3002 a = 4.5 b = 2 print ( 'a is {0} , b is {1} ' . format ( type ( a ), type ( b ))) # a is , b is \u5b57\u4e32\u683c\u5f0f\u5316\uff0c\u7528\u4e8e\u540e\u7eed\u8bbf\u95ee print ( a / b ) # 2.25 \u4f7f\u7528isinstance\u51fd\u6570\u6765\u68c0\u67e5\u4e00\u4e2a\u5bf9\u8c61\u662f\u5426\u662f\u7279\u5b9a\u7c7b\u578b\u7684\u5b9e\u4f8b\u3002isinstance\u63a5\u53d7\u4e00\u4e2a\u5305\u542b\u7c7b\u578b\u7684\u5143\u7ec4\uff0c\u53ef\u4ee5\u68c0\u67e5\u5bf9\u8c61\u7684\u7c7b\u578b\u662f\u5426\u5728\u5143\u7ec4\u4e2d\u7684\u7c7b\u578b\u4e2d\u3002 a = 5 b = 4.5 c = 'foo' print ( isinstance ( a , int )) # True print ( isinstance ( b , str )) # False print ( isinstance ( c , ( str , int ))) # True print ( isinstance ( c , ( float , int ))) # False \u5c5e\u6027\u548c\u65b9\u6cd5\u4e5f\u53ef\u4ee5\u901a\u8fc7getattr\u51fd\u6570\u83b7\u5f97\u3002\u5728\u5176\u4ed6\u7684\u8bed\u8a00\u4e2d\uff0c\u901a\u8fc7\u53d8\u91cf\u540d\u8bbf\u95ee\u5bf9\u8c61\u901a\u5e38\u88ab\u79f0\u4e3a\u201c\u53cd\u5c04\u201d\u3002 b = 'foo' print ( getattr ( b , 'split' )) # 3. \u4e8c\u5143\u8fd0\u7b97\u7b26\u548c\u6bd4\u8f83\u8fd0\u7b97 \u00b6 \u68c0\u67e5\u4e24\u4e2a\u5f15\u7528\u662f\u5426\u6307\u5411\u540c\u4e00\u4e2a\u5bf9\u8c61\uff0c\u53ef\u4ee5\u4f7f\u7528is\u5173\u952e\u5b57\u3002 is\u548cis not\u7684\u5e38\u7528\u4e4b\u5904\u662f\u68c0\u67e5\u4e00\u4e2a\u53d8\u91cf\u662f\u5426\u4e3aNone\uff0c\u56e0\u4e3aNone\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b\u3002 a = [ 1 , 2 , 3 ] b = a c = list ( a ) # list\u51fd\u6570\u603b\u662f\u521b\u5efa\u4e00\u4e2a\u65b0\u7684Python\u5217\u8868\uff08\u5373\u4e00\u4efd\u62f7\u8d1d\uff09 print ( a is b ) # True print ( a is not c ) # True print ( a == c ) # True d = None print ( d is None ) # True Python\u4e2d\u7684\u5927\u90e8\u5206\u5bf9\u8c61\uff0c\u4f8b\u5982\u5217\u8868\u3001\u5b57\u5178\u3001NumPy\u6570\u7ec4\u90fd\u662f\u53ef\u53d8\u5bf9\u8c61\uff0c\u5927\u591a\u6570\u7528\u6237\u5b9a\u4e49\u7684\u7c7b\u578b\uff08\u7c7b\uff09\u4e5f\u662f\u53ef\u53d8\u7684\u3002 \u53ef\u53d8\u5bf9\u8c61\u4e2d\u5305\u542b\u7684\u5bf9\u8c61\u548c\u503c\u662f\u53ef\u4ee5\u88ab\u4fee\u6539\u7684\u3002\u8fd8\u6709\u5176\u4ed6\u4e00\u4e9b\u5bf9\u8c61\u662f\u4e0d\u53ef\u53d8\u7684\uff0c\u6bd4\u5982\u5b57\u7b26\u4e32\u3001\u5143\u7ec4\u3002 a_list = [ 'foo' , 2 , [ 4 , 5 ]] # \u5217\u8868 a_list [ 2 ] = ( 3 , 4 ) print ( a_list ) # ['foo', 2, (3, 4)] a_tuple = ( 3 , 5 , ( 4 , 5 )) # \u5143\u7ec4 a_tuple [ 1 ] = 'four' # TypeError: 'tuple' object does not support item assignment \u4e0d\u53ef\u88ab\u4fee\u6539 print ( a_tuple ) # (3, 5, (4, 5)) 4. \u6807\u91cf\u7c7b\u578b \u00b6 Python\u6807\u91cf\u7c7b\u578b\uff1aNone, str, bytes, float, bool, int\u3002 \u6570\u503c\u7c7b\u578b\u3002 \u57fa\u7840\u7684Python\u6570\u5b57\u7c7b\u578b\u5c31\u662fint\u548cfloat\u3002int\u53ef\u4ee5\u5b58\u50a8\u4efb\u610f\u5927\u5c0f\u6570\u5b57\u3002\u6d6e\u70b9\u6570\u5728Python\u4e2d\u7528float\u8868\u793a\uff0c\u6bcf\u4e00\u4e2a\u6d6e\u70b9\u6570\u90fd\u662f\u53cc\u7cbe\u5ea664\u4f4d\u6570\u503c\u3002 ival = 17338971 print ( ival ** 6 ) # 27173145946003847721495630081806010734757321 fval = 17338971.0 print ( fval ** 6 ) # 2.7173145946003847e+43 print ( 3 / 2 ) # 1.5 print ( 3 // 2 ) # 1 \u5b57\u7b26\u4e32\u3002 Python\u7684\u5b57\u7b26\u4e32\u662f\u4e0d\u53ef\u53d8\u7684\u3002 a = 5.6 s = str ( a ) print ( s ) # 5.6 b = 'python' print ( list ( b )) # ['p', 'y', 't', 'h', 'o', 'n'] print ( b [ 2 ]) # t b [ 2 ] = 'f' # TypeError: 'str' object does not support item assignment \u5b57\u7b26\u4e32\u662f\u4e0d\u53ef\u53d8\u7684 \u53cd\u659c\u6760\u7b26\u53f7\\\u662f\u4e00\u79cd\u8f6c\u4e49\u7b26\u53f7\uff0c\u5b83\u7528\u6765\u6307\u660e\u7279\u6b8a\u7b26\u53f7\u3002 \u5982\u679c\u4f60\u6709\u4e00\u4e2a\u4e0d\u542b\u7279\u6b8a\u7b26\u53f7\u4f46\u542b\u6709\u5927\u91cf\u53cd\u659c\u6760\u7684\u5b57\u7b26\u4e32\u65f6\uff0c\u53ef\u4ee5\u5728\u5b57\u7b26\u4e32\u524d\u9762\u52a0\u4e00\u4e2a\u524d\u7f00\u7b26\u53f7r\uff0c\u8868\u660e\u8fd9\u4e9b\u5b57\u7b26\u662f\u539f\u751f\u5b57\u7b26\uff0cr\u662fraw\u7684\u7b80\u5199\uff0c\u8868\u793a\u539f\u751f\u7684\u3002 x = '12 \\\\ 34' y = r 'this\\has\\no\\special\\characters' print ( x ) # 12\\34 print ( y ) # this\\has\\no\\special\\characters \u5b57\u7b26\u4e32\u683c\u5f0f\u5316 {0:.2f}\u8868\u793a\u5c06\u7b2c\u4e00\u4e2a\u53c2\u6570\u683c\u5f0f\u5316\u4e3a2\u4f4d\u5c0f\u6570\u7684\u6d6e\u70b9\u6570 {1:s}\u8868\u793a\u5c06\u7b2c\u4e8c\u4e2a\u53c2\u6570\u683c\u5f0f\u5316\u4e3a\u5b57\u7b26\u4e32 {2:d}\u8868\u793a\u5c06\u7b2c\u4e09\u4e2a\u53c2\u6570\u683c\u5f0f\u5316\u6574\u6570 \u53c2\u8003Python\u5b98\u65b9\u6587\u6863 https://docs.python.org/3.6/library/string.html template = ' {0:.2f} {1:s} are worth US$ {2:d} ' print ( template . format ( 4.5560 , 'Argentine Pesos' , 1 )) # 4.56 Argentine Pesos are worth US$1 \u65e5\u671f\u548c\u65f6\u95f4 from datetime import datetime , date , time dt = datetime ( 2011 , 10 , 29 , 20 , 30 , 21 ) print ( dt . day ) # 29 print ( dt . minute ) # 30 print ( dt . date ()) # 2011-10-29 print ( dt . time ()) # 20:30:21 print ( dt . replace ( minute = 0 , second = 0 )) # 2011-10-29 20:00:00 \u5c06\u5206\u949f\u3001\u79d2\u66ff\u6362\u4e3a0 print ( datetime . strptime ( '20091021' , '%Y%m %d ' )) # 2009-10-21 00:00:00 \u5b57\u7b26\u4e32\u53ef\u4ee5\u901a\u8fc7 strptime \u51fd\u6570\u8f6c\u6362\u4e3adatetime\u5bf9\u8c61 dt2 = datetime ( 2011 , 11 , 15 , 22 , 30 ) delta = dt2 - dt print ( delta ) # 17 days, 1:59:39 print ( dt + delta ) # 2011-11-15 22:30:00 range\u51fd\u6570\u8fd4\u56de\u4e00\u4e2a\u8fed\u4ee3\u5668\uff0c\u8be5\u8fed\u4ee3\u5668\u751f\u6210\u4e00\u4e2a\u7b49\u5dee\u6574\u6570\u5e8f\u5217\u3002 print ( range ( 10 )) # range(0, 10) print ( list ( range ( 10 ))) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print ( list ( range ( 0 , 20 , 2 ))) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 5. \u4e09\u5143\u8868\u8fbe\u5f0f \u00b6 value = true-expr if condition else false-expr x = 5 print ( 'non-negative' if x >= 0 else 'negative' ) # non-negative","title":"Python\u8bed\u8a00\u57fa\u7840"},{"location":"python/Foundation/ch01/#python","text":"","title":"Python\u8bed\u8a00\u57fa\u7840"},{"location":"python/Foundation/ch01/#1-python6","text":"6\u4e2aPython\u6570\u636e\u7c7b\u578b\uff1a \u6570\u503c\u578b\uff08number\uff09\uff1a\u8868\u793a\u6570\u636e\u7ec4\u6210\u4e3a\u6570\u5b57 \u6574\u578b\uff08int\uff09 \u5341\u8fdb\u5236 \u516b\u8fdb\u5236 \u5341\u516d\u8fdb\u5236 \u6d6e\u70b9\u578b\uff08float\uff09 \u5e03\u5c14\u578b\uff08bool\uff09 \u590d\u6570\u6027\uff08complex\uff09 \u5b57\u7b26\u578b\uff08string\uff09\uff1a\u8868\u793a\u6570\u636e\u7ec4\u6210\u662f\u5b57\u7b26 \u5217\u8868\uff08list\uff09\uff1a\u7528\u6765\u8868\u793a\u4e00\u7ec4\u6709\u5e8f\u5143\u7d20\uff0c\u540e\u671f\u6570\u636e\u53ef\u4ee5\u4fee\u6539 ['A','B','C'] \u5143\u7ec4\uff08tuple\uff09\uff1a\u7528\u6765\u8868\u793a\u4e00\u7ec4\u6709\u5e8f\u5143\u7d20\uff0c\u540e\u671f\u6570\u636e\u4e0d\u53ef\u4fee\u6539 ('A','B','C','1') \u96c6\u5408\uff08set\uff09\uff1a\u4e00\u7ec4\u6570\u636e\u65e0\u5e8f\u4e0d\u91cd\u590d\u5143\u7d20 set([1,2,3,4]) \u5b57\u5178\uff08dictionary\uff09\uff1a\u7528\u952e\u503c\u5bf9\u7684\u5f62\u5f0f\u4fdd\u5b58\u4e00\u7ec4\u5143\u7d20 {'A':7,'B':1,'C':9} \u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08Iterable\uff09\uff1a An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an iter() method or with a getitem() method that implements Sequence semantics. \u5e8f\u5217\uff08Sequence\uff09\uff1a An iterable which supports efficient element access using integer indices via the getitem() special method and defines a len() method that returns the length of the sequence. Some built-in sequence types are list, str, tuple, and bytes. Note that dict also supports getitem() and len(), but is considered a mapping rather than a sequence because the lookups use arbitrary immutable keys rather than integers. \u8fed\u4ee3\u5668\uff08Iterator\uff09\uff1a An object representing a stream of data. Repeated calls to the iterator\u2019s next() method (or passing it to the built-in function next()) return successive items in the stream. When no more data are available a StopIteration exception is raised instead. At this point, the iterator object is exhausted and any further calls to its next() method just raise StopIteration again. Iterators are required to have an iter() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a list) produces a fresh new iterator each time you pass it to the iter() function or use it in a for loop. Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container. \u53ef\u53d8\u6570\u636e\uff08immutable\uff09 \u5217\u8868\uff08list\uff09 \u5b57\u5178\uff08dictionary\uff09 \u96c6\u5408\uff08set\uff09\u3002 \u4e0d\u53ef\u53d8\u6570\u636e\uff08immutable\uff09 \u6570\u5b57\uff08number\uff09 \u5b57\u7b26\uff08string\uff09 \u5143\u7ec4\uff08tuple\uff09 \u53ef\u8fed\u4ee3\uff08iterable\uff09 \u5b57\u7b26\uff08string\uff09 \u5143\u7ec4\uff08tuple\uff09 \u5217\u8868\uff08list\uff09 \u5b57\u5178\uff08dictionary\uff09 \u96c6\u5408\uff08set\uff09 \u5e8f\u5217 \u6709\u5e8f\u5e8f\u5217\uff1a\u5b57\u7b26\uff08string\uff09\uff0c\u5143\u7ec4\uff08tuple\uff09\uff0c\u5217\u8868\uff08list\uff09 \u65e0\u5e8f\u5e8f\u5217\uff1a\u5b57\u5178\uff08dictionary\uff09\uff0c\u96c6\u5408\uff08set\uff09 Python\u5e8f\u5217\u7c7b\u578b\u6700\u5e38\u89c1\u7684\u5206\u7c7b\u5c31\u662f\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u5e8f\u5217\u3002\u4f46\u53e6\u5916\u4e00\u79cd\u5206\u7c7b\u65b9\u5f0f\u4e5f\u5f88\u6709\u7528\uff0c\u90a3\u5c31\u662f\u628a\u5b83\u4eec\u5206\u4e3a**\u6241\u5e73\u5e8f\u5217**\u548c**\u5bb9\u5668\u5e8f\u5217**\u3002\u524d\u8005\u7684\u4f53\u79ef\u66f4\u5c0f\u3001\u901f\u5ea6\u66f4\u5feb\u800c\u4e14\u7528\u8d77\u6765\u66f4\u7b80\u5355\uff0c\u4f46\u662f\u5b83\u53ea\u80fd\u4fdd\u5b58\u4e00\u4e9b\u539f\u5b50\u6027\u7684\u6570\u636e\uff0c\u6bd4\u5982\u6570\u5b57\u3001\u5b57\u7b26\u548c\u5b57\u8282\u3002\u5bb9\u5668\u5e8f\u5217\u5219\u6bd4\u8f83\u7075\u6d3b\uff0c\u4f46\u662f\u5f53\u5bb9\u5668\u5e8f\u5217\u9047\u5230\u53ef\u53d8\u5bf9\u8c61\u65f6\uff0c\u5c31\u9700\u8981\u683c\u5916\u5c0f\u5fc3\uff0c\u56e0\u4e3a\u8fd9\u79cd\u7ec4\u5408\u65f6\u5e38\u4f1a\u51fa\u73b0\u4e00\u4e9b\u201c\u610f\u5916\u201d\uff0c\u7279\u522b\u662f\u5e26\u5d4c\u5957\u7684\u6570\u636e\u7ed3\u6784\u51fa\u73b0\u65f6\uff0c\u66f4\u9700\u8981\u9a8c\u8bc1\u4ee3\u7801\u7684\u6b63\u786e\u6027\u3002 Python\u4e2d\u7684\u53d8\u91cf\u3001\u5e38\u91cf\u548c\u5b57\u9762\u91cf \u53d8\u91cf \u53d8\u91cf\u662f\u7528\u4e8e\u5728\u5185\u5b58\u4e2d\u5b58\u50a8\u6570\u636e\u7684\u547d\u540d\u4f4d\u7f6e\u3002\u53ef\u4ee5\u5c06\u53d8\u91cf\u89c6\u4e3a\u4fdd\u5b58\u6570\u636e\u7684\u5bb9\u5668\uff0c\u8fd9\u4e9b\u6570\u636e\u53ef\u4ee5\u5728\u540e\u9762\u7a0b\u5e8f\u4e2d\u8fdb\u884c\u66f4\u6539\u3002\u4f8b\u5982\uff1a number = 10 \u3002\u4ece\u4f8b\u5b50\u4e2d\u53ef\u4ee5\u770b\u5230\uff0cPython\u4f7f\u7528\u8d4b\u503c\u8fd0\u7b97\u7b26 = \u4e3a\u53d8\u91cf\u8d4b\u503c\u3002 \u5e38\u91cf \u5e38\u91cf\u4e5f\u662f\u4e00\u79cd\u53d8\u91cf\uff0c\u53ea\u662f\u5176\u503c\u4e00\u65e6\u8d4b\u4e88\u540e\u65e0\u6cd5\u66f4\u6539\u3002\u53ef\u4ee5\u5c06\u5e38\u91cf\u89c6\u4e3a\u4fdd\u5b58\u4e86\u4ee5\u540e\u65e0\u6cd5\u66f4\u6539\u7684\u4fe1\u606f\u7684\u5bb9\u5668\u3002 \u5728Python\u4e2d\uff0c\u5e38\u91cf\u901a\u5e38\u662f\u5728\u6a21\u5757\u4e2d\u58f0\u660e\u548c\u5206\u914d\u7684\u3002\u5728\u8fd9\u91cc\uff0c\u6a21\u5757\u662f\u4e00\u4e2a\u5305\u542b\u53d8\u91cf\uff0c\u51fd\u6570\u7b49\u7684\u65b0\u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u88ab\u5bfc\u5165\u5230\u4e3b\u6587\u4ef6\u4e2d\u3002\u5728\u6a21\u5757\u5185\u90e8\uff0c\u7528\u6240\u6709\u5927\u5199\u5b57\u6bcd\u5199\u7684\u5e38\u91cf\u548c\u4e0b\u5212\u7ebf\u5c06\u5355\u8bcd\u5206\u5f00\u3002\u5b9e\u9645\u4e0a\uff0c\u6211\u4eec\u4e0d\u5728Python\u4e2d\u4f7f\u7528\u5e38\u91cf\u3002\u7528\u5927\u5199\u5b57\u6bcd\u547d\u540d\u5b83\u4eec\u662f\u4e00\u79cd\u5c06\u5176\u4e0e\u666e\u901a\u53d8\u91cf\u5206\u5f00\u7684\u4e00\u79cd\u7ea6\u5b9a\uff0c\u4f46\u662f\uff0c\u5b9e\u9645\u4e0a\u5e76\u4e0d\u80fd\u963b\u6b62\u91cd\u65b0\u5206\u914d\u3002 \u5b57\u9762\u91cf\uff08literal\uff09 \u5b57\u9762\u91cf\u662f\u4ee5\u53d8\u91cf\u6216\u5e38\u91cf\u7ed9\u51fa\u7684\u539f\u59cb\u6570\u636e\uff08\u5176\u5b9e\u5c31\u662f\u6307\u53d8\u91cf\u7684\u5e38\u6570\u503c\uff0c\u5b57\u9762\u4e0a\u6240\u770b\u5230\u7684\u503c\uff09\u3002\u5728Python\u4e2d\u5b57\u9762\u91cf\u7c7b\u578b\u5982\u4e0b\uff1a \u6570\u5b57\u5b57\u9762\u91cf\u3002\u6570\u5b57\u5b57\u9762\u91cf\u662f\u4e0d\u53ef\u53d8\u7684\uff08\u4e0d\u53ef\u66f4\u6539\uff09\u3002\u6570\u5b57\u5b57\u9762\u91cf\u53ef\u4ee5\u5c5e\u4e8e3\u79cd\u4e0d\u540c\u7684\u6570\u503c\u7c7b\u578b\uff1aInteger\uff0cFloat \u548c Complex\u3002\u4f8b\u5982\uff1a float_1 = 10.5 \u662f\u5c5e\u4e8eFloat\u5b57\u9762\u91cf\u3002 \u5b57\u7b26\u4e32\u5b57\u9762\u91cf\u662f\u7531\u5f15\u53f7\u62ec\u8d77\u6765\u7684\u4e00\u7cfb\u5217\u5b57\u7b26\u3002\u6211\u4eec\u53ef\u4ee5\u5bf9\u5b57\u7b26\u4e32\u4f7f\u7528\u5355\u5f15\u53f7\uff0c\u53cc\u5f15\u53f7 \u6216 \u4e09\u5f15\u53f7\u3002\u5e76\u4e14\uff0c\u5b57\u7b26\u5b57\u9762\u91cf\u662f\u7528\u5355\u5f15\u53f7\u6216\u53cc\u5f15\u53f7\u5f15\u8d77\u6765\u7684\u5355\u4e2a\u5b57\u7b26\u3002\u4f8b\u5982\uff1a strings = \"This is Python\" \u3002 \u5e03\u5c14\u5b57\u9762\u91cf\u3002\u5e03\u5c14\u5b57\u9762\u91cf\u53ef\u4ee5\u5177\u6709\u4e24\u4e2a\u503c\u4e2d\u7684\u4efb\u4f55\u4e00\u4e2a\uff1a True \u6216 False \u3002\u4f8b\u5982\uff1a a = True + 4 \u3002 \u7279\u6b8a\u5b57\u9762\u91cf\u3002Python\u5305\u542b\u4e00\u4e2a\u7279\u6b8a\u5b57\u9762\u91cf\uff0c\u5373 None \u3002 \u5b57\u9762\u91cf\u96c6\u3002\u6709\u56db\u79cd\u4e0d\u540c\u7684\u5b57\u9762\u91cf\u96c6\u5408\uff1a\u5217\u8868\u5b57\u9762\u91cf\uff0c\u5143\u7ec4\u5b57\u9762\u91cf\uff0c\u5b57\u5178\u5b57\u9762\u91cf \u548c \u96c6\u5408\u5b57\u9762\u91cf\u3002","title":"1. Python\u6570\u636e\u7c7b\u578b\uff086\u4e2a\uff09"},{"location":"python/Foundation/ch01/#11-number","text":"\u4f8b\u5b50\uff1a a , b , c , d = 20 , 5.5 , True , 4 + 3 j print ( a , b , c , d ) # 20 5.5 True (4+3j) print ( type ( a ), type ( b ), type ( c ), type ( d )) # Python\u4e5f\u53ef\u4ee5\u8fd9\u6837\u8d4b\u503c\uff1a a = b = c = d = 1 print ( a , b , c , d ) # 1 1 1 1 \u8fdb\u5236\u8f6c\u6362\uff1a a = - 15 print ( f ' { a } \u5bf9\u5e94\u7684\u5341\u8fdb\u5236\u662f { a } , \u4e8c\u8fdb\u5236\u662f { a : b } , \u516b\u8fdb\u5236\u662f { a : o } , \u5341\u516d\u8fdb\u5236\u662f { a : x } ' )","title":"1.1 \u6570\u503c\u578b\uff08number\uff09"},{"location":"python/Foundation/ch01/#12-string","text":"\u5355\u5f15\u53f7\uff1a\u5185\u5bb9\u4e2d\u5305\u542b\u5927\u91cf\u53cc\u5f15\u53f7 \u53cc\u5f15\u53f7\uff1a\u5185\u5bb9\u4e2d\u5305\u542b\u5927\u91cf\u5355\u5f15\u53f7 \u4e09\u5f15\u53f7\uff1a\u5185\u5bb9\u4e2d\u540c\u65f6\u5305\u542b\u5355\u53cc\u5f15\u53f7\uff0c\u4e09\u4e2a\u5355\u5f15\u53f7\u6bd4\u8f83\u597d\u3002 a = 'string is \"special\"' b = \"string's value\" c = '''string's value is \"special\"''' d = \"\"\"string's context \"\"\"","title":"1.2 \u5b57\u7b26\u578b\uff08string\uff09"},{"location":"python/Foundation/ch01/#_1","text":"\u5b57\u7b26\u4e32\u5207\u7247 s = 'Python is very good' print ( s [ 2 : 4 ]) # th print ( s [ 5 ]) # n print ( s [ - 1 ]) # d print ( s [ - 3 : - 1 ]) # oo # \u975e\u8fed\u4ee3\u578b\uff0c\u4e0d\u53ef\u4fee\u6539 s [ 3 ] = 'b' # Traceback (most recent call last): # File \"\", line 1, in # TypeError: 'str' object does not support item assignment \u5b57\u7b26\u4e32\u5408\u5e76 print ( s + '!!!' ) # Python is very good!!! replace( a,b \u5c06\u5b57\u7b26\u4e32\u4e2d\u7684 a \u66ff\u6362\u6210 b print ( s . replace ( 'is' , 'we' )) # Python we very good find(str) : \u8fd4\u56de str \u51fa\u73b0\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0c\u5982\u679c\u627e\u4e0d\u5230\u8be5\u503c\uff0c\u5219 find() \u65b9\u6cd5\u5c06\u8fd4\u56de -1\u3002 print ( s . find ( 'a' )) # -1 print ( s . find ( 's' )) # 8 str.index(a): \u67e5\u627e\u6307\u5b9a\u503c\u7684\u9996\u6b21\u51fa\u73b0\u3002\u5982\u679c\u627e\u4e0d\u5230\u8be5\u503c\uff0cindex() \u65b9\u6cd5\u5c06\u5f15\u53d1\u5f02\u5e38\u3002 print ( s . index ( 's' )) # 8 print ( s . index ( 'a' )) # Traceback (most recent call last): # File \"\", line 1, in # ValueError: substring not found str.count(a): \u7edf\u8ba1\u5b57\u7b26\u4e32\u4e2d a \u51fa\u73b0\u7684\u6b21\u6570 print ( s . count ( 'a' )) # 0 print ( s . count ( 'o' )) # 3 split: \u5bf9\u5b57\u7b26\u4e32\u8fdb\u884c\u5206\u5272\u3002\u5982\u679c\u53c2\u6570 num \u6709\u6307\u5b9a\u503c\uff0c\u5219\u5206\u9694 num+1 \u4e2a\u5b50\u5b57\u7b26\u4e32\u3002 # \u6309\u7a7a\u683c\u5206\u5272 print ( s . split ( ' ' )) # ['Python', 'is', 'very', 'good'] # \u6309\u7a7a\u683c\u5206\u5272\u62102\u4e2a\u5b50\u5b57\u7b26\u4e32 print ( s . split ( ' ' , 1 )) # ['Python', 'is very good'] strip: \u79fb\u9664\u5b57\u7b26\u4e32\u9996\u5c3e\u6307\u5b9a\u7684\u5b57\u7b26 \u9ed8\u8ba4\u4e3a\u7a7a\u683c\u3002\u8be5\u65b9\u6cd5\u53ea\u80fd\u5220\u9664\u5f00\u5934\u6216\u662f\u7ed3\u5c3e\u7684\u5b57\u7b26\uff0c\u4e0d\u80fd\u5220\u9664\u4e2d\u95f4\u90e8\u5206\u7684\u5b57\u7b26\u3002 print ( s ) # Python is very good # \u79fb\u9664\u672b\u5c3e\u5b57\u7b26d print ( s . strip ( 'd' )) # Python is very goo endswith (str): \u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u4ee5 str \u7ed3\u5c3e print ( s . endswith ( 'd' )) # True print ( s . endswith ( 'a' )) # False startswith (str): \u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u4ee5 str \u5f00\u5934 print ( s . startswith ( 'p' )) # False print ( s . startswith ( 'P' )) # True isdigit \uff1a\u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u5168\u4e3a\u6570\u5b57 d = '+86-123' print ( d . isdigit ()) # False d = '86123' print ( d . isdigit ()) # True isalpha \uff1a\u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u5168\u4e3a\u5b57\u6bcd b = 'Ab?' print ( b . isalpha ()) # False c = 'Ab' print () c . isalpha () # True","title":"\u5b57\u7b26\u4e32\u5e38\u7528\u65b9\u6cd5"},{"location":"python/Foundation/ch01/#_2","text":"\u4f7f\u7528\u53cd\u659c\u6760\\\u8868\u793a\u8f6c\u4e49\u5b57\u7b26\u3002\u53cd\u659c\u6760\u524d\u9762\u52a0r\u4ee3\u8868\u539f\u59cb\u5b57\u7b26\u3002 a = 'str \\n ing' print ( a ) # str # ing a = r 'str\\ning' print ( a ) # str\\ning \u8f6c\u4e49\u7b26 \u63cf\u8ff0 \\\u5728\u884c\u5c3e \u7eed\u884c\u7b26 \\\\ \u53cd\u659c\u6760\u7b26\u53f7\\ \\' \u5355\u5f15\u53f7 \\b \u9000\u683c(Backspace) \\000 \u7a7a \\n \u6362\u884c \\v \u7eb5\u5411\u5236\u8868\u7b26 \\t \u6a2a\u5411\u5236\u8868\u7b26 \\r \u56de\u8f66\uff0c\u5c06 \\r \u540e\u9762\u7684\u5185\u5bb9\u79fb\u5230\u5b57\u7b26\u4e32\u5f00\u5934\uff0c\u5e76\u9010\u4e00\u66ff\u6362\u5f00\u5934\u90e8\u5206\u7684\u5b57\u7b26\uff0c\u76f4\u81f3\u5c06 \\r \u540e\u9762\u7684\u5185\u5bb9\u5b8c\u5168\u66ff\u6362\u5b8c\u6210\u3002 \\yyy \u516b\u8fdb\u5236\u6570\uff0cy \u4ee3\u8868 0~7 \u7684\u5b57\u7b26 \\xyy \u5341\u516d\u8fdb\u5236\u6570\uff0c\u4ee5 \\x \u5f00\u5934\uff0cy \u4ee3\u8868\u7684\u5b57\u7b26","title":"\u8f6c\u4e49\u5b57\u7b26"},{"location":"python/Foundation/ch01/#_3","text":"\u5b57\u7b26\u4e32\u662f\u53ef\u8fed\u4ee3\u7684\u3002\u7d22\u5f15\u503c\u4ece0\u5f00\u59cb\uff0c-1\u4ee3\u8868\u4ece\u672b\u5c3e\u5f00\u59cb\u3002\u7d22\u5f15\u533a\u95f4\u662f\u5de6\u95ed\u53f3\u5f00\u3002 a = 'string is \"special\"' print ( a [ 2 : 4 ]) 'ri' print ( a [ - 4 : - 1 ]) # ial","title":"\u53ef\u8fed\u4ee3\u6027"},{"location":"python/Foundation/ch01/#f-string","text":"f-string\u662fPython3.6\u63a8\u51fa\u7684\u65b0\u529f\u80fd\u3002\u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5bf9\u6bd4\u4f20\u7edf\u8868\u793a\u65b9\u6cd5\u548cf-string\u7684\u65b9\u6cd5\u3002 age = 32 name = 'Tom' fstring = f 'My name is { name } and I am { age } years old.' print ( fstring ) # My name is Tom and I am 32 years old. \u5728f-string\u4e2d\u4f7f\u7528\u8868\u8fbe\u5f0f\u3002 height = 2 base = 3 fstring = f 'The area of the triangle is { base * height / 2 } .' print ( fstring ) # The area of the triangle is 3.0. \u901a\u8fc7f-string\u5bf9\u5b57\u5178\u8fdb\u884c\u64cd\u4f5c\u3002 person1 = { 'name' : 'Tom' , 'age' : 20 , 'gender' : 'male' } person2 = { 'name' : 'Jerry' , 'age' : 20 , 'gender' : 'female' } # \u8bfb\u53d6\u5b57\u5178 fstring = f ' { person1 . get ( \"name\" ) } is { person1 . get ( \"age\" ) } and is { person1 . get ( \"ender\" ) } ' print ( fstring ) # Tom is 20 and is None # \u904d\u5386\u5b57\u5178 people = [ person1 , person2 ] for person in people : fstring = f ' { person . get ( \"name\" ) } is { person . get ( \"age\" ) } and is { person . get ( \"ender\" ) } ' print ( fstring ) # Tom is 20 and is None # Jerry is 20 and is None \u5728f-string\u4e2d\u4f7f\u7528\u6761\u4ef6\u3002 person1 = { 'name' : 'Tom' , 'age' : 20 , 'gender' : 'male' } person2 = { 'name' : 'Jerry' , 'age' : 20 , 'gender' : 'female' } people = [ person1 , person2 ] for person in people : fstring = f ' { \"She\" if person . get ( \"gender\" ) == \"female\" else \"He\" } is watching TV.' print ( fstring ) # He is watching TV. # She is watching TV. \u4f7f\u7528f-string\u683c\u5f0f\u5316\u8f93\u51fa\u3002 \u5de6\u5bf9\u9f50\uff1a< \u53f3\u5bf9\u9f50\uff1a> \u5c45\u4e2d\u5bf9\u9f50\uff1a^ print ( f ' { \"apple\" : >30 } ' ) print ( f ' { \"apple\" : ^30 } ' ) print ( f ' { \"apple\" : <30 } ' ) # apple # apple # apple \u4f7f\u7528f-string\u683c\u5f0f\u5316\u6570\u5b57\u3002 number = 0.9124325345 # \u767e\u5206\u6bd4 fstring = f 'Percentage format for number with two decimal places: { number : .2% } ' print ( fstring ) # Percentage format for number with two decimal places: 91.24% # \u4fdd\u7559\u5c0f\u6570\u70b9\u540e3\u4f4d fstring = f 'Fixed point format for number with three decimal places: { number : .3f } ' print ( fstring ) # Fixed point format for number with three decimal places: 0.912 # \u79d1\u5b66\u8ba1\u6570\u6cd5\u8868\u793a fstring = f 'Exponent format for number: { number : e } ' print ( fstring ) # Exponent format for number: 9.124325e-01 # \u5e26\u8d27\u5e01\u7b26\u53f7 number = 123456.78921 fstring = f 'Currency format for number with two decimal places: $ { number : .2f } ' print ( fstring ) # Currency format for number with two decimal places: $123456.79 # \u5e26\u8d27\u5e01\u7b26\u53f7\u548c\u5343\u5206\u4f4d number = 123456.78921 fstring = f 'Currency format for number with two decimal places and comma seperators: $ { number : ,.2f } ' print ( fstring ) # Currency format for number with two decimal places and comma seperators: $123,456.79 # \u8f93\u51fa\u6570\u503c\u5e26\u6b63\u8d1f\u7b26\u5408 numbers = [ 1 , - 3 , 5 ] for number in numbers : fstring = f 'The number is { number : + } ' print ( fstring ) # The number is +1 # The number is -3 # The number is +5 # Debug\u8c03\u8bd5 number = 2 print ( f ' { number = } ' ) # number = 2","title":"f-string"},{"location":"python/Foundation/ch01/#13-list","text":"\u5217\u8868\u662f Python \u5185\u7f6e\u7684\u4e00\u79cd\u6570\u636e\u7ed3\u6784\uff0c\u662f\u4e00\u79cd\u6709\u5e8f\u7684\u96c6\u5408\uff0c\u7528\u6765\u5b58\u50a8\u4e00\u8fde\u4e32\u5143\u7d20\u7684\u5bb9\u5668\u3002\u5217\u8868\u4e2d\u5143\u7d20\u7c7b\u578b\u53ef\u4ee5\u4e0d\u76f8\u540c\uff0c\u5b83\u652f\u6301\u6570\u5b57\u3001\u5b57\u7b26\u4e32\u7b49\u3002 \u5217\u8868\u7684\u6bcf\u4e2a\u503c\u90fd\u6709\u5bf9\u5e94\u7684\u7d22\u5f15\u503c\uff0c\u7d22\u5f15\u503c\u4ece0\u5f00\u59cb\u3002 \u5217\u8868\u5207\u7247\uff1a \u4f7f\u7528\u5207\u7247\u7b26\u53f7\u53ef\u4ee5\u5bf9\u5927\u591a\u6570\u5e8f\u5217\u7c7b\u578b\u9009\u53d6\u5176\u5b50\u96c6\u3002 \u8d77\u59cb\u4f4d\u7f6estart\u7684\u7d22\u5f15\u662f\u5305\u542b\u7684\uff0c\u800c\u7ed3\u675f\u4f4d\u7f6estop\u7684\u7d22\u5f15\u5e76\u4e0d\u5305\u542b\uff08\u5de6\u95ed\u53f3\u5f00\uff09\u3002 \u6b65\u8fdb\u503cstep\u53ef\u4ee5\u5728\u7b2c\u4e8c\u4e2a\u5192\u53f7\u540e\u9762\u4f7f\u7528\uff0c\u610f\u601d\u662f\u6bcf\u9694\u591a\u5c11\u4e2a\u6570\u53d6\u4e00\u4e2a\u503c \u3002 color = [ 'red' , 'green' , 'blue' , 'yellow' , 'white' , 'black' ] # \u4ece0\u5f00\u59cb\u7edf\u8ba1\uff0c\u8bfb\u53d6\u7b2c1\uff0c2\u4f4d print ( color [ 1 : 3 ]) # ['green', 'blue'] # \u4ece0\u5f00\u59cb\u7edf\u8ba1\uff0c\u8bfb\u53d6\u4ece\u7b2c1\u4f4d\u5230\u5012\u6570\u7b2c3\u4f4d print ( color [ 1 : - 2 ]) # ['green', 'blue', 'yellow'] # \u4ece0\u5f00\u59cb\u7edf\u8ba1\uff0c\u8bfb\u53d6\u4ece\u5012\u6570\u7b2c4\u4f4d\u5230\u5012\u6570\u7b2c3\u4f4d print ( color [ - 4 : - 2 ]) # ['blue', 'yellow'] # \u5982\u679c\u5199\u6210\u4e0b\u9762\u8fd9\u6837\uff0c\u5219\u65e0\u8f93\u51fa\u3002 print ( color [ - 2 : - 4 ]) # [] print ( color [:: 2 ]) # ['red', 'blue', 'white'] \u5bf9\u4e8e\u7c7b\u4f3c\u4e0b\u9762 invoice \u683c\u5f0f\u7684\u7eaf\u6587\u672c\u89e3\u6790\uff0c\u4f7f\u7528\u6709\u540d\u5b57\u7684\u5207\u7247\u6bd4\u7528\u4e0a\u9762\u6240\u5217\u4e3e\u7684\u786c\u7f16\u7801\u7684\u6570\u5b57\u533a\u95f4\u8981\u65b9\u4fbf\u5f97\u591a\u3002 invoice = \"\"\" 0 6 40 52 55 1909 Primoroni PiBrella $17.50 3 $52.50 1489 6mm Tactile Switch x20 $4.19 2 $9.90 1510 Panavise JR.-PV-201 $28.00 1 $28.00 1601 PiTFT Mini Kit 320x240 $34.95 1 $34.95 \"\"\" SKU = slice ( 0 , 6 ) DESCRIPTION = slice ( 6 , 40 ) UNIT_PRICE = slice ( 40 , 52 ) QUANTITY = slice ( 52 , 55 ) ITEM_TOTAL = slice ( 55 , None ) line_items = invoice . split ( ' \\n ' )[ 2 :] # \u6309\u4e0a\u9762invoice\u7684\u683c\u5f0f\uff0c\u7b2c0\u548c1\u884c\u820d\u5f03 for item in line_items : print ( item [ UNIT_PRICE ], item [ DESCRIPTION ]) # $17.50 Primoroni PiBrella # $4.19 6mm Tactile Switch x20 # $28.00 Panavise JR.-PV-201 # $34.95 PiTFT Mini Kit 320x240 Python\u5185\u7f6e\u7684\u5e8f\u5217\u7c7b\u578b\u90fd\u662f\u4e00\u7ef4\u7684\uff0c\u56e0\u6b64\u5b83\u4eec\u53ea\u652f\u6301\u5355\u4e00\u7684\u7d22\u5f15\uff0c\u6210\u5bf9\u51fa\u73b0\u7684\u7d22\u5f15\u662f\u6ca1\u6709\u7528\u7684\u3002 **\u7701\u7565\uff08ellipsis\uff09**\u7684\u6b63\u786e\u4e66\u5199\u65b9\u6cd5\u662f\u4e09\u4e2a\u82f1\u8bed\u53e5\u53f7\uff08...\uff09\uff0c\u800c\u4e0d\u662fUnicdoe\u7801\u4f4dU+2026\u8868\u793a\u7684\u534a\u4e2a\u7701\u7565\u53f7\uff08...\uff09\u3002 \u7701\u7565\u5728Python\u89e3\u6790\u5668\u773c\u91cc\u662f\u4e00\u4e2a\u7b26\u53f7\uff0c\u800c\u5b9e\u9645\u4e0a\u5b83\u662f Ellipsis \u5bf9\u8c61\u7684\u522b\u540d\uff0c\u800c Ellipsis \u5bf9\u8c61\u53c8\u662f ellipsis \u7c7b\u7684\u5355\u4e00\u5b9e\u4f8b\u3002 \u5b83\u53ef\u4ee5\u5f53\u4f5c\u5207\u7247\u89c4\u8303\u7684\u4e00\u90e8\u5206\uff0c\u4e5f\u53ef\u4ee5\u7528\u5728\u51fd\u6570\u7684\u53c2\u6570\u6e05\u5355\u4e2d\uff0c\u6bd4\u5982 f(a, ..., z) \uff0c\u6216 a[i:...] \u3002 \u5728NumPy\u4e2d\uff0c ... \u7528\u4f5c\u591a\u7ef4\u6570\u7ec4\u5207\u7247\u7684\u5feb\u6377\u65b9\u5f0f\u3002\u5982\u679c `x\u662f\u56db\u7ef4\u6570\u7ec4\uff0c\u90a3\u4e48 x[i, ...] \u5c31\u662f x[i, :, :, :]`\u7684\u7f29\u5199\u3002\u5982\u679c\u60f3\u4e86\u89e3\u66f4\u591a\uff0c\u8bf7\u53c2\u89c1\u201cTentative NumPy Tutorial\u201d\u3002 \u5217\u8868\u5e38\u7528\u65b9\u6cd5 \u65b9\u6cd5\u540d\u79f0 \u4f5c\u7528 a.index() \u8fd4\u56dea\u4e2d\u9996\u4e2a\u5339\u914d\u9879\u7684\u4f4d\u7f6e a.pop() \u5220\u9664\u6307\u5b9a\u4f4d\u7f6e\u7684\u5143\u7d20 a.insert() \u5411\u6307\u5b9a\u4f4d\u7f6e\u63d2\u5165\u5143\u7d20 a.reverse() \u53cd\u5411\u6392\u5e8f a.append() \u5411\u672b\u5c3e\u6dfb\u52a0\u5143\u7d20 a.sort() \u5bf9\u5217\u8868\u8fdb\u884c\u6392\u5e8f a.remove() \u5220\u9664\u9996\u4e2a\u5339\u914d\u9879\u7684\u5143\u7d20 a.extend() \u5c06\u4e00\u4e2a\u5217\u8868\u6269\u5c55\u81f3\u53e6\u4e00\u4e2a\u5217\u8868 a.count() \u7edf\u8ba1\u67d0\u4e2a\u5143\u7d20\u51fa\u73b0\u7684\u6b21\u6570 \u521b\u5efa\u5217\u8868list a = [ 1 , 2 , 3 , 4 , 5 ] print ( a ) # [1, 2, 3, 4, 5] b = list ( '12345' ) print ( b ) # ['1', '2', '3', '4', '5'] c = list ( 12345 ) # Traceback (most recent call last): # File \"\", line 1, in # TypeError: 'int' object is not iterable \u5217\u8868\u5207\u7247\uff08\u4ece0\u5f00\u59cb\uff0c\u5de6\u95ed\u53f3\u5f00\uff09\uff1a print ( a [ 2 : 3 ]) # [3] print ( a [: 3 ]) # [1, 2, 3] print ( a [:: - 1 ]) # \u5012\u5e8f # [5, 4, 3, 2, 1] print ( a [::]) # [1, 2, 3, 4, 5] print ( a [:: 1 ]) [ 1 , 2 , 3 , 4 , 5 ] \u5217\u8868\u662f\u53ef\u4fee\u6539\u7684\uff1a print ( a [ 1 ]) # 2 a [ 1 ] = 'one' print ( a ) @ [ 1 , 'one' , 3 , 4 , 5 ] \u5217\u8868\u8ffd\u52a0\u548c\u63d2\u5165\u3002insert\u4e0eappend\u76f8\u6bd4\uff0c\u8ba1\u7b97\u4ee3\u4ef7\u66f4\u9ad8\u3002\u56e0\u4e3a\u5b50\u5e8f\u5217\u5143\u7d20\u9700\u8981\u5728\u5185\u90e8\u79fb\u52a8\u4e3a\u65b0\u5143\u7d20\u63d0\u4f9b\u7a7a\u95f4\u3002 a . append ( 6 ) # \u6ce8\u610f\uff0c\u76f4\u63a5\u4fee\u6539\u539f\u5217\u8868\uff0c\u4e0d\u662f\u521b\u5efa\u526f\u672c\u3002 print ( a ) # [1, 'one', 3, 4, 5, 6] a . extend ([ 7 , 8 , 9 ]) print ( a ) # [1, 'one', 3, 4, 5, 6, 7, 8, 9] a . insert ( 0 , 'Italy' ) print ( a ) # ['Italy', 1, 3, 5, 6, 7, 8] \u5217\u8868\u5220\u9664\u5143\u7d20\uff0c\u9ed8\u8ba4\u5220\u9664\u6700\u540e\u4e00\u4e2a\u3002insert\u7684\u53cd\u64cd\u4f5c\u662fpop\u3002 a . pop () # 9 print ( a ) # [1, 'one', 3, 4, 5, 6, 7, 8] a . pop ( 3 ) # 4 print ( a ) # [1, 'one', 3, 5, 6, 7, 8] \u5220\u9664\u5217\u8868\u4e2d\u67d0\u4e2a\u5143\u7d20\u3002 print ( a [ 1 ]) # one del a [ 1 ] print ( a ) [ 1 , 3 , 5 , 6 , 7 , 8 ] \u5220\u9664\u5217\u8868\u4e2d\u67d0\u4e2a\u5143\u7d20\u3002remove\u65b9\u6cd5\u4f1a\u5b9a\u4f4d\u7b2c\u4e00\u4e2a\u7b26\u5408\u8981\u6c42\u7684\u503c\u5e76\u79fb\u9664 a . remove ( 'Italy' ) print ( a ) # [1, 3, 5, 6, 7, 8] \u7edf\u8ba1\u67d0\u4e2a\u5143\u7d20\u51fa\u73b0\u7684\u6b21\u6570\u3002 print ( a . count ( 1 )) # 1 \u8fd4\u56de\u5217\u8868\u4e2d\u5339\u914d\u9879\u7684\u7d22\u5f15\u4f4d\u7f6e\u3002\u5339\u914d\u4e0d\u5230\u629b\u51fa\u5f02\u5e38\u3002 print ( a . index ( 2 )) # Traceback (most recent call last): # File \"\", line 1, in # ValueError: 2 is not in list print ( a . index ( 3 )) # 1 \u5224\u65ad\u5143\u7d20\u662f\u5426\u5b58\u5728\u4e8e\u5217\u8868\u3002 print ( 3 in a ) # True print ( '3' in a ) # False \u53cd\u5411\u8f93\u51fa\u5217\u8868\u3002 a . reverse () print ( a ) # [8, 7, 6, 5, 3, 1] \u53d6\u5217\u8868\u4e2d\u6700\u5927\u503c\u3001\u6700\u5c0f\u503c\u3002 print ( min ( a )) # 1 print ( max ( a )) # 78 \u8ba1\u7b97\u5217\u8868\u957f\u5ea6\u3002 print ( len ( a )) # 6 \u5217\u8868\u6269\u5c55\uff1a a = [ 1 , 2 , 3 ] b = [ 4 , 5 , 6 ] print ( a + b ) # [1, 2, 3, 4, 5, 6] a . extend ( b ) # a\u5217\u8868\u88ab\u4fee\u6539 print ( a ) # [1, 2, 3, 4, 5, 6] print ( b ) # [4, 5, 6] \u4f7f\u7528extend\u6dfb\u52a0\u5143\u7d20\u6bd4\u4f7f\u7528\u52a0\u53f7\uff08+\uff09\u8fde\u63a5\u6548\u7387\u66f4\u9ad8\u3002\u56e0\u4e3a\u4f7f\u7528\u52a0\u53f7\uff08+\uff09\u8fde\u63a5\u8fc7\u7a0b\u4e2d\u521b\u5efa\u4e86\u65b0\u5217\u8868\uff0c\u5e76\u4e14\u8fd8\u8981\u590d\u5236\u5bf9\u8c61\u3002 a_list = [ 4 , None , 'foo' ] b_list = [ 7 , 8 , ( 2 , 3 )] print ( a_list + b_list ) # [4, None, 'foo', 7, 8, (2, 3)] \u4f7f\u7528+\u53f7\u8fde\u63a5 a_list . extend ( b_list ) print ( a_list ) # [4, None, 'foo', 7, 8, (2, 3)] Python\u7684\u4e00\u4e2a\u60ef\u4f8b\uff1a\u5982\u679c\u4e00\u4e2a\u51fd\u6570\u6216\u8005\u65b9\u6cd5\u5bf9\u5bf9\u8c61\u8fdb\u884c\u7684\u662f\u5c31\u5730\u6539\u52a8\uff0c\u90a3\u5b83\u5c31\u5e94\u8be5\u8fd4\u56deNone\uff0c\u597d\u8ba9\u8c03\u7528\u8005\u77e5\u9053\u4f20\u5165\u7684\u53c2\u6570\u53d1\u751f\u4e86\u53d8\u52a8\uff0c\u800c\u4e14\u5e76\u672a\u4ea7\u751f\u65b0\u7684\u5bf9\u8c61\u3002 \u4e0b\u9762\u662f\u6392\u5e8f\u7684\u4f8b\u5b50 list.sort() \u548c sorted(list) \u7684\u533a\u522b\u3002 list1 = [ '1' , 'one' , '3' , 'Four' , '5' , 'two' , 'apple' , '8' , '9' ] print ( list1 ) # ['1', 'one', '3', 'Four', '5', 'two', 'apple', '8', '9'] # \u4e0b\u9762\u7684\u64cd\u4f5c\u4e0d\u6539\u53d8\u539f\u5217\u8868 print ( sorted ( list1 )) # ['1', '3', '5', '8', '9', 'Four', 'apple', 'one', 'two'] print ( sorted ( list1 , reverse = True )) # ['two', 'one', 'apple', 'Four', '9', '8', '5', '3', '1'] print ( sorted ( list1 , key = len )) # ['1', '3', '5', '8', '9', 'one', 'two', 'Four', 'apple'] print ( list1 ) # ['1', 'one', '3', 'Four', '5', 'two', 'apple', '8', '9'] # \u4e0b\u9762\u7684\u64cd\u4f5c\u76f4\u63a5\u4fee\u6539\u539f\u5217\u8868\uff0c\u8fd4\u56de\u503c\u662fNone print ( list1 . sort ()) # None print ( list1 ) # ['1', '3', '5', '8', '9', 'Four', 'apple', 'one', 'two'] \u5217\u8868\u590d\u5236\uff0c + \u548c * \u7684\u64cd\u4f5c\u90fd\u662f\u4e0d\u4fee\u6539\u539f\u6709\u7684\u64cd\u4f5c\u5bf9\u8c61\uff0c\u800c\u662f\u6784\u5efa\u4e00\u4e2a\u5168\u65b0\u7684\u5217\u8868\u3002 c = list ( 'Python' ) print ( a + c ) # [1, 2, 3, 4, 5, 6, 'P', 'y', 't', 'h', 'o', 'n'] print ( a * 3 ) # [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6] \u5982\u679c\u5728 a * n \u8fd9\u4e2a\u8bed\u53e5\u4e2d\uff0c\u5e8f\u5217 a \u91cc\u7684\u5143\u7d20\u662f\u5bf9\u5176\u4ed6\u53ef\u53d8\u5bf9\u8c61\u7684\u5f15\u7528\u7684\u8bdd\uff0c\u5c31\u9700\u8981\u683c\u5916\u6ce8\u610f\u4e86\uff0c\u56e0\u4e3a\u8fd9\u4e2a\u5f0f\u5b50\u7684\u7ed3\u679c\u53ef\u80fd\u4f1a\u51fa\u4e4e\u610f\u6599\u3002 \u6bd4\u5982\uff0c\u6211\u4eec\u60f3\u7528 my_list=[[]] * 3 \u6765\u521d\u59cb\u5316\u4e00\u4e2a\u7531\u5217\u8868\u7ec4\u6210\u7684\u5217\u8868\uff0c\u4f46\u662f\u6211\u4eec\u5b9e\u9645\u5f97\u5230\u7684\u5217\u8868\u91cc\u5305\u542b\u76843\u4e2a\u5143\u7d20\u5176\u5b9e\u662f3\u4e2a\u5f15\u7528\uff0c\u800c\u4e14\u8fd93\u4e2a\u5f15\u7528\u6307\u5411\u7684\u90fd\u662f*\u540c\u4e00\u4e2a*\u5217\u8868\u3002\u770b\u4e0b\u9762\u4f8b\u5b50\u3002 # \u505a\u6cd51 board = [[ '_' ] * 3 for i in range ( 3 )] print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 1 ][ 2 ] = 'X' print ( board ) # [['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']] # \u505a\u6cd52 board = [[ '_' ] * 3 ] * 3 print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 1 ][ 2 ] = 'X' print ( board ) # [['_', '_', 'X'], ['_', '_', 'X'], ['_', '_', 'X']] \u4e0b\u9762\u4e5f\u662f\u540c\u6837\u7684\u95ee\u9898\u3002 # \u65b9\u6cd51 row = [ '_' ] * 3 board = [] for i in range ( 3 ): board . append ( row ) print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 2 ][ 0 ] = 'X' print ( board ) # [['X', '_', '_'], ['X', '_', '_'], ['X', '_', '_']] # \u65b9\u6cd52 row = [] board = [] for i in range ( 3 ): row = [ '_' ] * 3 board . append ( row ) print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 2 ][ 0 ] = 'X' print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['X', '_', '_']] \u53cc\u7aef\u961f\u5217collections.deque \uff0c\u53ef\u4ee5\u6ee1\u8db3\u5217\u8868\u5934\u5c3e\u90e8\u90fd\u589e\u52a0\u7684\u8981\u6c42\u3002 deque() \u4e2d maxlen \u662f\u4e00\u4e2a\u53ef\u9009\u53c2\u6570\uff0c\u4ee3\u8868\u8fd9\u4e2a\u961f\u5217\u53ef\u4ee5\u5bb9\u7eb3\u7684\u5143\u7d20\u7684\u6570\u91cf\uff0c\u800c\u4e14\u4e00\u65e6\u8bbe\u5b9a\uff0c\u8fd9\u4e2a\u5c5e\u6027\u5c31\u4e0d\u80fd\u4fee\u6539\u4e86\u3002 \u5f53\u8bd5\u56fe\u5bf9\u4e00\u4e2a\u5df2\u6ee1 len(d)==d.maxlen \u7684\u961f\u5217\u505a\u5934\u90e8\u6dfb\u52a0\u64cd\u4f5c\u7684\u65f6\u5019\uff0c\u5b83\u5c3e\u90e8\u7684\u5143\u7d20\u4f1a\u88ab\u5220\u9664\u6389\u3002 extendleft(iter) \u65b9\u6cd5\u4f1a\u628a\u8fed\u4ee3\u5668\u91cc\u7684\u5143\u7d20\u9010\u4e2a\u6dfb\u52a0\u5230\u53cc\u5411\u961f\u5217\u7684\u5de6\u8fb9\uff0c\u56e0\u6b64\u8fed\u4ee3\u5668\u91cc\u7684\u5143\u7d20\u4f1a\u9006\u5e8f\u51fa\u73b0\u5728\u961f\u5217\u91cc\u3002 \u961f\u5217\u7684\u65cb\u8f6c\u64cd\u4f5c rotate \u63a5\u53d7\u4e00\u4e2a\u53c2\u6570n\uff0c\u5f53n > 0\u65f6\uff0c\u961f\u5217\u7684\u6700\u53f3\u8fb9\u7684n\u4e2a\u5143\u7d20\u4f1a\u88ab\u79fb\u52a8\u5230\u961f\u5217\u7684\u5de6\u8fb9\u3002\u5f53n < 0\u65f6\uff0c\u6700\u5de6\u8fb9\u7684n\u4e2a\u5143\u7d20\u4f1a\u88ab\u79fb\u52a8\u5230\u53f3\u8fb9\u3002 from collections import deque d = deque ([ 1 , 2 , 3 ]) print ( d ) # deque([1, 2, 3]) # \u6ce8\u610f\u63d2\u5165\u987a\u5e8f d . extendleft ([ 'a' , 'b' , 'c' ]) print ( d ) # deque(['c', 'b', 'a', 1, 2, 3]) print ( len ( d )) # 6 print ( d [ - 2 ]) # 2 # \u7edf\u8ba1\u5b57\u7b26a\u51fa\u73b0\u7684\u6b21\u6570 print ( d . count ( 'a' )) # 1 # \u8fd4\u56de\u5b57\u7b26a\u7684\u7d22\u5f15\u503c print ( d . index ( 'a' )) # 2 # \u7b2c0\u4f4d\u63d2\u5165\u6570\u5b571\uff0c\u5176\u4f59\u987a\u79fb d . insert ( 0 , 1 ) print ( d ) # deque([1, 'c', 'b', 'a', 1, 2, 3]) # \u628a\u53f3\u8fb92\u4e2a\u5143\u7d20\u653e\u5230\u5de6\u8fb9\uff0c\u6ce8\u610f\u987a\u5e8f\uff0c\u548cextendleft\u4e0d\u4e00\u6837 d . rotate ( 2 ) print ( d ) # deque([2, 3, 1, 'c', 'b', 'a', 1]) d . rotate ( - 2 ) print ( d ) # deque([1, 'c', 'b', 'a', 1, 2, 3]) \u4e0b\u8868\u603b\u7ed3\u4e86\u5217\u8868\u548c\u53cc\u5411\u961f\u5217\u7684\u65b9\u6cd5\uff08\u4e0d\u5305\u62ec\u7531\u5bf9\u8c61\u5b9e\u73b0\u7684\u65b9\u6cd5\uff09\u3002 \u5217\u8868\u6392\u5e8f\u3002\u6392\u5e8f\u5bf9\u5217\u8868\u5143\u7d20\u7684\u6570\u636e\u7c7b\u578b\u662f\u6709\u8981\u6c42\u7684\u3002 a_list = [ 4 , None , 'foo' , 7 , 8 , ( 2 , 3 )] a_list . sort () # Traceback (most recent call last): # File \"\", line 1, in # TypeError: '<' not supported between instances of 'NoneType' and 'int' b_list = [ 7 , 8 , ( 2 , 3 )] b_list . sort () # Traceback (most recent call last): # File \"\", line 1, in # TypeError: '<' not supported between instances of 'tuple' and 'int' a_list = [ 7 , 2 , 5 , 1 , 3 ] a_list . sort () # \u6309\u6570\u503c\u5927\u5c0f\u6392\u5e8f print ( a_list ) # [1, 2, 3, 5, 7] b_list = [ 'saw' , 'small' , 'He' , 'foxes' , 'six' ] b_list . sort ( key = len ) # \u901a\u8fc7\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u8fdb\u884c\u6392\u5e8f print ( b_list ) # ['He', 'saw', 'six', 'small', 'foxes'] \u5217\u8868\u4e8c\u5206\u641c\u7d22\u548c\u5df2\u6392\u5e8f\u5217\u8868\u7684\u7ef4\u62a4 bisect \u8fd4\u56de\u8981\u63d2\u5165\u5143\u7d20\u5728\u5217\u8868\u4e2d\u7684\u4e0b\u6807\u3002\u5047\u5b9a\u5217\u8868\u662f\u6709\u5e8f\u7684\u3002 bisect_left \u4e0e bisect \u7c7b\u4f3c\uff0c\u53ea\u4e0d\u8fc7\u5176\u9ed8\u8ba4\u5c06\u5143\u7d20\u63d2\u5230\u5de6\u8fb9\uff0c\u6240\u4ee5\u8fd4\u56de\u7684\u662f\u63d2\u5165\u5230\u5de6\u8fb9\u7684\u4e0b\u6807 bisect_right\u4e0e bisect_left \u76f8\u53cd\u3002 \u4ee5\u4e0a\u65b9\u6cd5\u82e5\u5217\u8868\u65e0\u5e8f\uff0c\u90a3\u4e48\u4f1a\u8fd4\u56de\u63d2\u5165\u5230\u5217\u8868\u6700\u540e\u4e00\u4e2a\u5408\u9002\u7684\u4f4d\u7f6e\u3002 insort \u4f1a\u5728\u5217\u8868\u4e2d\u63d2\u5165\u5143\u7d20\u5230\u6b63\u786e\u4f4d\u7f6e\uff0c\u5047\u5b9a\u5217\u8868\u6709\u5e8f\u3002\u5982\u679c\u5217\u8868\u65e0\u5e8f\uff0c\u90a3\u4e48\u4f1a\u8fd4\u56de\u7a7a\u3002\u9ed8\u8ba4\u63d2\u5165\u5230\u53f3\u8fb9\u3002 insort_left \u548cinsort_right \u7c7b\u4f3c\u3002 import bisect c = [ 1 , 2 , 3 , 4 , 7 ] print ( bisect . bisect ( c , 2 )) # 2 bisect\u4f1a\u627e\u5230\u7b2c\u4e00\u4e2a2,\u5e76\u628a\u65b0\u76842\u63d2\u5165\u5b83\u540e\u9762 bisect . insort ( c , 2 ) # [1, 2, 2, 3, 4, 7] print ( bisect . bisect ( c , 5 )) # 5 bisect\u4f1a\u627e\u5230\u7b2c\u4e00\u4e2a4,\u5e76\u628a\u65b0\u76845\u63d2\u5165\u5b83\u540e\u9762 bisect . insort ( c , 5 ) print ( bisect . bisect ( c , 6 )) # 6 bisect\u4f1a\u627e\u5230\u7b2c\u4e00\u4e2a5,\u5e76\u628a\u65b0\u76846\u63d2\u5165\u5b83\u540e\u9762 bisect . insort ( c , 6 ) print ( c ) # [1, 2, 2, 3, 4, 5, 6, 7] bisect\u53ef\u4ee5\u7528\u6765\u5efa\u7acb\u4e00\u4e2a\u7528\u6570\u5b57\u4f5c\u4e3a\u7d22\u5f15\u7684\u67e5\u8be2\u8868\u683c\uff0c\u5982\u4e0b\u4f8b\uff0c\u628a\u5206\u6570\u548c\u6210\u7ee9\u5bf9\u5e94\u8d77\u6765\uff0c\u6839\u636e\u4e00\u4e2a\u5206\u6570\uff0c\u627e\u5230\u5b83\u6240\u5bf9\u5e94\u7684\u6210\u7ee9\u3002 import bisect def grade ( score , breakpoints = [ 60 , 70 , 80 , 90 ], grades = 'FDCBA' ): i = bisect . bisect ( breakpoints , score ) return grades [ i ] [ grade ( score ) for score in [ 15 , 26 , 31 , 62 , 79 , 85 ]] # ['F', 'F', 'F', 'D', 'C', 'B'] \u7528bisect.insort\u63d2\u5165\u65b0\u5143\u7d20\uff0c\u5e76\u80fd\u4fdd\u6301seq\u7684\u5347\u5e8f\u987a\u5e8f\u3002 import bisect import random size = 7 random . seed ( 1729 ) my_list = [] for i in range ( size ): new_item = random . randrange ( size * 2 ) bisect . insort ( my_list , new_item ) print ( f ' { new_item : 2d } :--> { my_list } ' ) # 10 :--> [10] # 0 :--> [0, 10] # 6 :--> [0, 6, 10] # 8 :--> [0, 6, 8, 10] # 7 :--> [0, 6, 7, 8, 10] # 2 :--> [0, 2, 6, 7, 8, 10] # 10 :--> [0, 2, 6, 7, 8, 10, 10]","title":"1.3 \u5217\u8868\uff08list\uff09"},{"location":"python/Foundation/ch01/#14-dictionary","text":"\u5b57\u5178(dict)\u662f\u4f7f\u7528\u952e-\u503c\uff08key-value\uff09\u5b58\u50a8\uff0c\u952e\u662f\u4e0d\u53ef\u53d8\u5bf9\u8c61\uff0c\u4e14\u4e0d\u5141\u8bb8\u91cd\u590d\u3002 dict\uff08\u5b57\u5178\uff09\u66f4\u4e3a\u5e38\u7528\u7684\u540d\u5b57\u662f\u54c8\u5e0c\u8868\u6216\u8005\u662f\u5173\u8054\u6570\u7ec4\u3002 \u5b57\u5178\u662f\u62e5\u6709\u7075\u6d3b\u5c3a\u5bf8\u7684\u952e\u503c\u5bf9\u96c6\u5408\uff0c\u4e0d\u662f\u901a\u8fc7\u4f4d\u7f6e\u8fdb\u884c\u7d22\u5f15\uff0c\u5176\u4e2d\u952e\u548c\u503c\u90fd\u662fPython\u5bf9\u8c61\u3002\u7528\u5927\u62ec\u53f7{}\u662f\u521b\u5efa\u5b57\u5178\u7684\u4e00\u79cd\u65b9\u5f0f\uff0c\u5728\u5b57\u5178\u4e2d\u7528\u9017\u53f7\u5c06\u952e\u503c\u5bf9\u5206\u9694\u3002 \u521b\u5efa\u5b57\u5178\u7684\u51e0\u79cd\u65b9\u6cd5\uff1a a = dict ( one = 1 , two = 2 , three = 3 ) b = { 'one' : 1 , 'two' : 2 , 'three' : 3 } c = dict ( zip ([ 'one' , 'two' , 'three' ], [ 1 , 2 , 3 ])) d = dict ([( 'two' , 2 ), ( 'three' , 3 ), ( 'one' , 1 )]) e = dict ({ 'three' : 3 , 'one' : 1 , 'two' : 2 }) print ( a == b == c == d == e ) # True \u5b57\u5178\u5e38\u7528\u65b9\u6cd5 \u65b9\u6cd5\u540d\u79f0 \u4f5c\u7528 a.items() \u8fd4\u56dea\u4e2d\u6240\u6709\u952e\u503c\u5bf9 a.values() \u8fd4\u56dea\u4e2d\u6240\u6709\u503c a.keys() \u8fd4\u56dea\u4e2d\u6240\u6709\u952e a.get() \u901a\u8fc7\u952e\u6765\u67e5\u503c\uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u503c a.clear() \u6e05\u7a7a\u5b57\u5178a\u7684\u503c a.setdefault \u901a\u8fc7\u952e\u503c\u6765\u67e5\u627e\u503c\uff0c\u627e\u4e0d\u5230\u5219\u63d2\u5165 a.update() \u952e\u548c\u503c\u66f4\u65b0\u5230\u65b0\u7684\u5b57\u5178 a.pop() \u5220\u9664\u6307\u5b9a\u4f4d\u7f6e\u7684\u5143\u7d20 \u751f\u6210\u4e00\u4e2a\u5b57\u5178\u3002 dict_a = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } print ( type ( dict_a )) # dict_b = dict ( city = 'Shanghai' , strict = 'Xuhui' , zip = '200000' ) print ( type ( dict_b )) # \u901a\u8fc7\u952e\u67e5\u8be2\u503c\uff0c\u67e5\u8be2\u4e0d\u5230\u629b\u51fa\u5f02\u5e38\u3002 print ( dict_a [ 'name' ]) # Ming print ( dict_a [ 'Name' ]) # Traceback (most recent call last): # File \"\", line 1, in # KeyError: 'Name' \u63d2\u5165\u65b0\u7684\u952e\u503c\u5bf9\u3002 dict_a [ 'city' ] = 'Chengdu' print ( dict_a ) # {'name': 'Ming', 'id': 1001, 'city': 'Chengdu'} \u5220\u9664\u67d0\u4e2a\u952e\u503c\u5bf9\u3002pop\u65b9\u6cd5\u4f1a\u5728\u5220\u9664\u7684\u540c\u65f6\u8fd4\u56de\u88ab\u5220\u7684\u503c\uff0c\u5e76\u5220\u9664\u952e\u3002 dict_a . pop ( 'city' ) # Chengdu print ( dict_a ) # {'name': 'Ming', 'id': 1001} \u53e6\u4e00\u79cd\u65b9\u5f0f\u5220\u9664\u67d0\u4e2a\u952e\u503c\u5bf9\u3002 del dict_a [ 'age' ] # Traceback (most recent call last): # File \"\", line 1, in # KeyError: 'age' del dict_a [ 'id' ] print ( dict_a ) # {'name': 'Ming'} \u5224\u65ad\u952e\u662f\u5426\u5b58\u5728\u3002 dict_a [ 23 ] = 'Hello World' print ( dict_a ) # {'name': 'Ming', 23: 'Hello World'} print ( 23 in dict_a ) # True print ( 35 in dict_a ) # False \u901a\u8fc7\u952e\u67e5\u8be2\u503c\u7684\u53e6\u4e00\u79cd\u65b9\u5f0f\uff0c\u67e5\u8be2\u4e0d\u5230\u4e0d\u629b\u5f02\u5e38\u3002 dict_a . get ( 'hai' ) dict_a . get ( 'hai' , 1 ) # 1 dict_a . get ( 'name' , 1 ) # Ming dict_a [ 'hai' ] # Traceback (most recent call last): # File \"\", line 1, in # KeyError: 'hai' \u901a\u8fc7\u952e\u67e5\u8be2\u503c\u7684\u53e6\u4e00\u79cd\u65b9\u5f0f\uff0c\u67e5\u8be2\u4e0d\u5230\u5219\u6dfb\u52a0\u3002 dict_a . setdefault ( 'name' ) # Ming dict_a . setdefault ( 'hai' , 1 ) # 1 print ( dict_a ) # {'name': 'Ming', 23: 'Hello World', 'hai': 1} dict_a . setdefault ( 'go' ) print ( dict_a ) # {'name': 'Ming', 23: 'Hello World', 'hai': 1, 'go': None} \u8bfb\u53d6\u5b57\u5178\u6240\u6709\u952e\u503c\u5bf9\uff0c\u8fd4\u56de\u7684\u662f\u5217\u8868\u5f62\u5f0f\u3002 print ( dict_a . items ()) # dict_items([('name', 'Ming'), (23, 'Hello World'), ('hai', 1), ('go', None)]) \u8bfb\u53d6\u5b57\u5178\u7684\u952e\u3002 print ( dict_a . keys ()) # dict_keys(['name', 23, 'hai', 'go']) \u8bfb\u53d6\u5b57\u5178\u7684\u503c\u3002 print ( dict_a . values ()) # dict_values(['Ming', 'Hello World', 1, None]) \u5c06\u5b57\u5178\u503c\u8f6c\u5316\u6210\u5217\u8868\u3002 print ( list ( dict_a . values ())) # ['Ming', 'Hello World', 1, None] for key in dict_a . keys (): print ( dict_a [ key ]) # Ming # Hello World # 1 # None \u6e05\u7a7a\u5b57\u5178\u3002 dict_a . clear () print ( dict_a ) # {} print ( len ( dict_a )) # 0 \u5bf9\u4e8e\u4efb\u4f55\u539f\u5b57\u5178\u4e2d\u5df2\u7ecf\u5b58\u5728\u7684\u952e\uff0c\u5982\u679c\u4f20\u7ed9update\u65b9\u6cd5\u7684\u6570\u636e\u4e5f\u542b\u6709\u76f8\u540c\u7684\u952e\uff0c\u5219\u5b83\u7684\u503c\u5c06\u4f1a\u88ab\u8986\u76d6\u3002 dict_a = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } dict_b = dict ( city = 'Shanghai' , id = 2001 , zip = '200000' ) dict_a . update ( dict_b ) print ( dict_a ) # {'name': 'Ming', 'id': 2001, 'age': 35, 'city': 'Shanghai', 'zip': '200000'} \u4ece\u5217\u8868\u751f\u6210\u5b57\u5178\u3002 \u5b57\u5178\u672c\u8d28\u4e0a\u662f2-\u5143\u7ec4\uff08\u542b\u67092\u4e2a\u5143\u7d20\u7684\u5143\u7ec4\uff09\u7684\u96c6\u5408\uff0c\u5b57\u5178\u662f\u53ef\u4ee5\u63a5\u53d7\u4e00\u4e2a2-\u5143\u7ec4\u7684\u5217\u8868\u4f5c\u4e3a\u53c2\u6570\u7684\u3002 # \u65b9\u6cd51 mapping = {} key_list = list ( range ( 5 )) value_list = list ( reversed ( range ( 5 ))) for key , value in zip ( key_list , value_list ): mapping [ key ] = value print ( mapping ) # {0: 4, 1: 3, 2: 2, 3: 1, 4: 0} # \u65b9\u6cd52\u3002 mapping = {} key_list = list ( range ( 5 )) value_list = list ( reversed ( range ( 5 ))) mapping = dict ( zip ( key_list , value_list )) print ( mapping ) # {0: 4, 1: 3, 2: 2, 3: 1, 4: 0} \u6709\u6548\u7684\u5b57\u5178\u952e\u7c7b\u578b\u3002 \u5c3d\u7ba1\u5b57\u5178\u7684\u503c\u53ef\u4ee5\u662f\u4efb\u4f55Python\u5bf9\u8c61\uff0c\u4f46\u952e\u5fc5\u987b\u662f\u4e0d\u53ef\u53d8\u7684\u5bf9\u8c61\uff0c\u6bd4\u5982\u6807\u91cf\u7c7b\u578b\uff08\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u5b57\u7b26\u4e32\uff09\u6216\u5143\u7ec4\uff08\u4e14\u5143\u7ec4\u5185\u5bf9\u8c61\u4e5f\u5fc5\u987b\u662f\u4e0d\u53ef\u53d8\u5bf9\u8c61\uff09\u3002 \u901a\u8fc7hash\u51fd\u6570\u53ef\u4ee5\u68c0\u67e5\u4e00\u4e2a\u5bf9\u8c61\u662f\u5426\u53ef\u4ee5\u54c8\u5e0c\u5316\uff08\u5373\u662f\u5426\u53ef\u4ee5\u7528\u4f5c\u5b57\u5178\u7684\u952e\uff09\uff0c\u672f\u8bed\u53eb\u4f5c\u54c8\u5e0c\u5316\u3002 print ( hash ( 'string' )) # -4368784820203065343 print ( hash (( 1 , 2 , ( 2 , 3 )))) # -9209053662355515447 print ( hash (( 1 , 2 , [ 2 , 3 ]))) # TypeError: unhashable type: 'list' print ( hash (( 1 , 2 , tuple ([ 2 , 3 ])))) # -9209053662355515447 \u4e3a\u4e86\u5c06\u5217\u8868\u4f5c\u4e3a\u952e\uff0c\u4e00\u79cd\u65b9\u5f0f\u5c31\u662f\u5c06\u5176\u8f6c\u6362\u4e3a\u5143\u7ec4 \u5b57\u5178\u9ed8\u8ba4\u503c\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5b9e\u73b0\u4e86\u5c06\u4e00\u4e2a\u5355\u8bcd\u7ec4\u6210\u7684\u5217\u8868\uff0c\u8f6c\u6362\u6210\u5355\u8bcd\u9996\u5b57\u6bcd\u548c\u5355\u8bcd\u4e3a\u952e\u503c\u5bf9\u7684\u5b57\u5178\u3002\u5148\u7528\u4f20\u7edf\u65b9\u6cd5\u5b9e\u73b0\uff0c\u518d\u7528\u5b57\u5178\u7684setdefault\u65b9\u6cd5\u8fdb\u884c\u6539\u5199\u3002 \u5148\u770b\u4f20\u7edf\u65b9\u6cd5\u3002 words = [ 'apple' , 'bat' , 'bar' , 'atom' , 'book' ] by_letter = {} for word in words : letter = word [ 0 ] # word[0]\u628a\u5217\u8868words\u7684\u6bcf\u4e2a\u5143\u7d20\u5217\u8868\u5316\uff0c\u5e76\u53d6\u9996\u5b57\u6bcd\u3002\u8f93\u51fa\u7684\u662fa, b, b, a, b\u8fd95\u4e2a\u5217\u8868\u5143\u7d20\u7684\u9996\u5b57\u6bcd if letter not in by_letter : # \u751f\u6210\u7b2c\u4e00\u4e2a\u952e\u503c\u5bf9 print ( letter ) by_letter [ letter ] = [ word ] # \u5bf9\u6bd4[word]\u548cword[]\u7684\u7528\u6cd5 print ( by_letter ) # a # {'a': ['apple']} # b # {'a': ['apple'], 'b': ['bat']} else : # append\u5176\u4ed6\u952e\u503c\u5bf9 print ( letter ) by_letter [ letter ] . append ( word ) print ( by_letter ) # b # {'a': ['apple'], 'b': ['bat', 'bar']} # a # {'a': ['apple', 'atom'], 'b': ['bat', 'bar']} # b # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} print ( by_letter ) # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} \u7528\u5b57\u5178\u7684setdefault\u65b9\u6cd5\uff0c\u4e0a\u8ff0\u7684for\u5faa\u73af\u8bed\u53e5\u53ef\u4ee5\u88ab\u5199\u4e3a\u5982\u4e0b\u3002 words = [ 'apple' , 'bat' , 'bar' , 'atom' , 'book' ] by_letter = {} for word in words : letter = word [ 0 ] # word[0]\u7684\u8f93\u51fa\u4f9d\u7136\u662f5\u4e2a\u5217\u8868\u5143\u7d20\u7684\u9996\u5b57\u6bcda, b, b, a, b by_letter . setdefault ( letter , []) . append ( word ) # \u5982\u679cletter\u4e0d\u5728[]\u5219\u901a\u8fc7append\u6dfb\u52a0word print ( by_letter ) # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} \u5982\u679c\u6539\u5199\u4e3a by_letter.setdefault(letter, ['a']).append(word) \uff0c\u5219\u8f93\u51fa by_letter \u662f {'a': ['a', 'apple', 'atom'], 'b': ['a', 'bat', 'bar', 'book']} \u3002 words = [ 'apple' , 'bat' , 'bar' , 'atom' , 'book' ] by_letter = {} for word in words : letter = word [ 0 ] # word[0]\u7684\u8f93\u51fa\u4f9d\u7136\u662f5\u4e2a\u5217\u8868\u5143\u7d20\u7684\u9996\u5b57\u6bcda, b, b, a, b by_letter . setdefault ( letter , [ 'a' ]) . append ( word ) print ( by_letter ) # {'a': ['a', 'apple', 'atom'], 'b': ['a', 'bat', 'bar', 'book']} \u4f53\u4f1asetdefault()\u7684\u6ce8\u91ca\u201cInsert key with a value of default if key is not in the dictionary. Return the value for key if key is in the dictionary, else default.\u201d \u901a\u8fc7defaultdict\u7c7b\u4f7f\u5f97\u4e0a\u8ff0\u76ee\u7684\u5b9e\u73b0\u66f4\u4e3a\u7b80\u5355\u3002 from collections import defaultdict by_letter = defaultdict ( list ) # list\u662f\u5185\u7f6e\u7684\u53ef\u53d8\u5e8f\u5217(Built-in mutable sequence) print ( dict ( by_letter )) # {} for word in words : by_letter [ word [ 0 ]] . append ( word ) print ( by_letter ) # defaultdict(, {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']}) print ( dict ( by_letter )) # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} \u4e0b\u8868\u5c55\u793a\u4e86 dict \u3001 defaultdict \u548c OrderedDict \u7684\u5e38\u89c1\u65b9\u6cd5\uff0c\u540e\u9762\u4e24\u4e2a\u6570\u636e\u7c7b\u578b\u662f dict \u7684\u53d8\u79cd\uff0c\u4f4d\u4e8e collections \u6a21\u5757\u5185\u3002 default_factory \u5e76\u4e0d\u662f\u4e00\u4e2a\u65b9\u6cd5\uff0c\u800c\u662f\u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61\uff08callable\uff09\uff0c\u5b83\u7684\u503c\u5728 defaultdict \u521d\u59cb\u5316\u7684\u65f6\u5019\u7531\u7528\u6237\u8bbe\u5b9a\u3002 OrderedDict.popitem() \u4f1a\u79fb\u9664\u5b57\u5178\u91cc\u6700\u5148\u63d2\u5165\u7684\u5143\u7d20\uff08\u5148\u8fdb\u5148\u51fa\uff09\uff1b\u540c\u65f6\u8fd9\u4e2a\u65b9\u6cd5\u8fd8\u6709\u4e00\u4e2a\u53ef\u9009\u7684last\u53c2\u6570\uff0c\u82e5\u4e3a\u771f\uff0c\u5219\u4f1a\u79fb\u9664\u6700\u540e\u63d2\u5165\u7684\u5143\u7d20\uff08\u540e\u8fdb\u5148\u51fa\uff09\u3002 \u4e0a\u9762\u7684\u8868\u683c\u4e2d\uff0cupdate\u65b9\u6cd5\u5904\u7406\u53c2\u6570m\u7684\u65b9\u5f0f\uff0c\u662f\u5178\u578b\u7684\u201c\u9e2d\u5b50\u7c7b\u578b\u201d\u3002\u51fd\u6570\u9996\u5148\u68c0\u67e5m\u662f\u5426\u6709keys\u65b9\u6cd5\uff0c\u5982\u679c\u6709\uff0c\u90a3\u4e48update\u51fd\u6570\u5c31\u628a\u5b83\u5f53\u4f5c\u6620\u5c04\u5bf9\u8c61\u6765\u5904\u7406\u3002\u5426\u5219\uff0c\u51fd\u6570\u4f1a\u9000\u4e00\u6b65\uff0c\u8f6c\u800c\u628am\u5f53\u4f5c\u5305\u542b\u4e86\u952e\u503c\u5bf9(key, value)\u5143\u7d20\u7684\u8fed\u4ee3\u5668\u3002Python\u91cc\u5927\u591a\u6570\u6620\u5c04\u7c7b\u578b\u7684\u6784\u9020\u65b9\u6cd5\u90fd\u91c7\u7528\u4e86\u7c7b\u4f3c\u7684\u903b\u8f91\uff0c\u56e0\u6b64\u4f60\u65e2\u53ef\u4ee5\u7528\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\u6765\u65b0\u5efa\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\uff0c\u4e5f\u53ef\u4ee5\u7528\u5305\u542b(key, value)\u5143\u7d20\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\u6765\u521d\u59cb\u5316\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\u3002 \u5b57\u5178\u7684\u53d8\u79cd\uff1a collections.OrderedDict \u8fd9\u4e2a\u7c7b\u578b\u5728\u6dfb\u52a0\u952e\u7684\u65f6\u5019\u4f1a\u4fdd\u6301\u987a\u5e8f\uff0c\u56e0\u6b64\u952e\u7684\u8fed\u4ee3\u6b21\u5e8f\u603b\u662f\u4e00\u81f4\u7684\u3002OrderedDict\u7684popitem\u65b9\u6cd5\u9ed8\u8ba4\u5220\u9664\u5e76\u8fd4\u56de\u7684\u662f\u5b57\u5178\u91cc\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff0c\u4f46\u662f\u5982\u679c\u50cfmy_odict.popitem(last=False)\u8fd9\u6837\u8c03\u7528\u5b83\uff0c\u90a3\u4e48\u5b83\u5220\u9664\u5e76\u8fd4\u56de\u7b2c\u4e00\u4e2a\u88ab\u6dfb\u52a0\u8fdb\u53bb\u7684\u5143\u7d20\u3002 collections.ChainMap \u8be5\u7c7b\u578b\u53ef\u4ee5\u5bb9\u7eb3\u6570\u4e2a\u4e0d\u540c\u7684\u6620\u5c04\u5bf9\u8c61\uff0c\u7136\u540e\u5728\u8fdb\u884c\u952e\u67e5\u627e\u64cd\u4f5c\u7684\u65f6\u5019\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u4f1a\u88ab\u5f53\u4f5c\u4e00\u4e2a\u6574\u4f53\u88ab\u9010\u4e2a\u67e5\u627e\uff0c\u76f4\u5230\u952e\u88ab\u627e\u5230\u4e3a\u6b62\u3002\u8fd9\u4e2a\u529f\u80fd\u5728\u7ed9\u6709\u5d4c\u5957\u4f5c\u7528\u57df\u7684\u8bed\u8a00\u505a\u89e3\u91ca\u5668\u7684\u65f6\u5019\u5f88\u6709\u7528\uff0c\u53ef\u4ee5\u7528\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\u6765\u4ee3\u8868\u4e00\u4e2a\u4f5c\u7528\u57df\u7684\u4e0a\u4e0b\u6587\u3002 collections.Counter \u8fd9\u4e2a\u6620\u5c04\u7c7b\u578b\u4f1a\u7ed9\u952e\u51c6\u5907\u4e00\u4e2a\u6574\u6570\u8ba1\u6570\u5668\u3002\u6bcf\u6b21\u66f4\u65b0\u4e00\u4e2a\u952e\u7684\u65f6\u5019\u90fd\u4f1a\u589e\u52a0\u8fd9\u4e2a\u8ba1\u6570\u5668\u3002\u6240\u4ee5\u8fd9\u4e2a\u7c7b\u578b\u53ef\u4ee5\u7528\u6765\u7ed9\u53ef\u6563\u5217\u8868\u5bf9\u8c61\u8ba1\u6570\uff0c\u6216\u8005\u662f\u5f53\u6210\u591a\u91cd\u96c6\u6765\u7528\u2014\u2014\u591a\u91cd\u96c6\u5408\u5c31\u662f\u96c6\u5408\u91cc\u7684\u5143\u7d20\u53ef\u4ee5\u51fa\u73b0\u4e0d\u6b62\u4e00\u6b21\u3002Counter\u5b9e\u73b0\u4e86+\u548c-\u8fd0\u7b97\u7b26\u7528\u6765\u5408\u5e76\u8bb0\u5f55\uff0c\u8fd8\u6709\u50cfmost_common([n])\u8fd9\u7c7b\u5f88\u6709\u7528\u7684\u65b9\u6cd5\u3002most_common([n])\u4f1a\u6309\u7167\u6b21\u5e8f\u8fd4\u56de\u6620\u5c04\u91cc\u6700\u5e38\u89c1\u7684n\u4e2a\u952e\u548c\u5b83\u4eec\u7684\u8ba1\u6570 collections.UserDict \u8fd9\u4e2a\u7c7b\u5176\u5b9e\u5c31\u662f\u628a\u6807\u51c6dict\u7528\u7eafPython\u53c8\u5b9e\u73b0\u4e86\u4e00\u904d\u3002\u8ddfOrderedDict\u3001ChainMap\u548cCounter\u8fd9\u4e9b\u5f00\u7bb1\u5373\u7528\u7684\u7c7b\u578b\u4e0d\u540c\uff0cUserDict\u662f\u8ba9\u7528\u6237\u7ee7\u627f\u5199\u5b50\u7c7b\u7684\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u5229\u7528Counter\u6765\u8ba1\u7b97\u5355\u8bcd\u4e2d\u5404\u4e2a\u5b57\u6bcd\u51fa\u73b0\u7684\u6b21\u6570\uff1a str = 'abracadabra' ct = collections . Counter ( str ) print ( ct ) # Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}) \u4e0d\u53ef\u53d8\u6620\u5c04\u7c7b\u578b\u3002 \u6807\u51c6\u5e93\u91cc\u6240\u6709\u7684\u6620\u5c04\u7c7b\u578b\u90fd\u662f\u53ef\u53d8\u7684\uff0c\u4f46\u6709\u65f6\u5019\u4f60\u4f1a\u6709\u8fd9\u6837\u7684\u9700\u6c42\uff0c\u6bd4\u5982\u4e0d\u80fd\u8ba9\u7528\u6237\u9519\u8bef\u5730\u4fee\u6539\u67d0\u4e2a\u6620\u5c04\u3002 \u4ecePython 3.3\u5f00\u59cb\uff0c types \u6a21\u5757\u4e2d\u5f15\u5165\u4e86\u4e00\u4e2a\u5c01\u88c5\u7c7b\u540d\u53eb MappingProxyType \u3002\u5982\u679c\u7ed9\u8fd9\u4e2a\u7c7b\u4e00\u4e2a\u6620\u5c04\uff0c\u5b83\u4f1a\u8fd4\u56de\u4e00\u4e2a\u53ea\u8bfb\u7684\u6620\u5c04\u89c6\u56fe\u3002\u867d\u7136\u662f\u4e2a\u53ea\u8bfb\u89c6\u56fe\uff0c\u4f46\u662f\u5b83\u662f\u52a8\u6001\u7684\u3002\u8fd9\u610f\u5473\u7740\u5982\u679c\u5bf9\u539f\u6620\u5c04\u505a\u51fa\u4e86\u6539\u52a8\uff0c\u6211\u4eec\u901a\u8fc7\u8fd9\u4e2a\u89c6\u56fe\u53ef\u4ee5\u89c2\u5bdf\u5230\uff0c\u4f46\u662f\u65e0\u6cd5\u901a\u8fc7\u8fd9\u4e2a\u89c6\u56fe\u5bf9\u539f\u6620\u5c04\u505a\u51fa\u4fee\u6539\u3002 \u901a\u8fc7\u4e0b\u4f8b\u53ef\u4ee5\u770b\u51fa\uff0c d \u4e2d\u7684\u5185\u5bb9\u53ef\u4ee5\u901a\u8fc7 d_proxy \u770b\u5230\u3002\u4f46\u662f\u901a\u8fc7 d_proxy \u5e76\u4e0d\u80fd\u505a\u4efb\u4f55\u4fee\u6539\u3002 d_proxy \u662f\u52a8\u6001\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\u5bf9 d \u6240\u505a\u7684\u4efb\u4f55\u6539\u52a8\u90fd\u4f1a\u53cd\u9988\u5230\u5b83\u4e0a\u9762\u3002 from types import MappingProxyType d = { 1 : 'A' } d_proxy = MappingProxyType ( d ) print ( d ) # {1: 'A'} print ( d_proxy ) # {1: 'A'} print ( d [ 1 ]) # A print ( d_proxy [ 1 ]) # A d [ 2 ] = 'W' print ( d ) # {1: 'A', 2: 'W'} d_proxy [ 2 ] = 'W' # TypeError: 'mappingproxy' object does not support item assignment print ( d_proxy ) # {1: 'A', 2: 'W'}","title":"1.4 \u5b57\u5178\uff08dictionary\uff09"},{"location":"python/Foundation/ch01/#15-set","text":"\u201c\u96c6\u201d\u8fd9\u4e2a\u6982\u5ff5\u5728Python\u4e2d\u7b97\u662f\u6bd4\u8f83\u5e74\u8f7b\u7684\uff0c\u540c\u65f6\u5b83\u7684\u4f7f\u7528\u7387\u4e5f\u6bd4\u8f83\u4f4e\u3002set\u548c\u5b83\u7684\u4e0d\u53ef\u53d8\u7684\u59ca\u59b9\u7c7b\u578bfrozenset\u76f4\u5230Python 2.3\u624d\u9996\u6b21\u4ee5\u6a21\u5757\u7684\u5f62\u5f0f\u51fa\u73b0\uff0c\u7136\u540e\u5728Python 2.6\u4e2d\u5b83\u4eec\u5347\u7ea7\u6210\u4e3a\u5185\u7f6e\u7c7b\u578b\u3002 \u96c6\u5408(set) \uff0c\u5305\u542b\u4e0d\u53ef\u53d8\u7684\u96c6\u5408\uff08frozenset\uff09\uff0c\u662f\u4e00\u79cd\u65e0\u5e8f\u4e14\u5143\u7d20\u552f\u4e00\u7684\u5e8f\u5217\uff0c\u6240\u4ee5\u96c6\u5408\u7684\u672c\u8d28\u662f\u8bb8\u591a\u552f\u4e00\u5bf9\u8c61\u7684\u805a\u96c6\u3002 \u548c\u5b57\u5178\u7c7b\u4f3c\uff0c\u96c6\u5408\u7684\u5143\u7d20\u662f\u4e0d\u53ef\u53d8\u7684\u3002\u53ef\u4ee5\u8ba4\u4e3a\u96c6\u5408\u4e5f\u50cf\u5b57\u5178\uff0c\u4f46\u662f\u53ea\u6709\u952e\u6ca1\u6709\u503c\u3002\u57fa\u672c\u529f\u80fd\u662f\u8fdb\u884c\u6210\u5458\u5173\u7cfb\u6d4b\u8bd5\u548c\u5220\u9664\u91cd\u590d\u5143\u7d20\u3002\u6240\u4ee5\u96c6\u5408\u53e6\u4e00\u4e2a\u7528\u9014\u662f\u53bb\u91cd\u590d\u3002 \u96c6\u5408\u4e2d\u7684\u5143\u7d20\u5fc5\u987b\u662f\u53ef\u6563\u5217\u7684\uff0cset\u7c7b\u578b\u672c\u8eab\u662f\u4e0d\u53ef\u6563\u5217\u7684\uff0c\u4f46\u662ffrozenset\u53ef\u4ee5\u3002\u56e0\u6b64\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u5305\u542b\u4e0d\u540cfrozenset\u7684set\u3002 \u96c6\u5408\u53ef\u4ee5\u6709\u4e24\u79cd\u521b\u5efa\u65b9\u5f0f\uff1a\u901a\u8fc7set()\u51fd\u6570\u6216\u8005{}\u6765\u521b\u5efa\uff08\u7528\u5927\u62ec\u53f7\u62ec\u4f4f\u7684\u5185\u5bb9\uff0cPython3\u81ea\u52a8\u5b9a\u4e49\u4e3a\u96c6\u5408\uff09\u3002 \u96c6\u5408\u4e0d\u5c5e\u4e8e\u5e8f\u5217\u7c7b\u6570\u636e\uff0c \u96c6\u5408\u4e0d\u652f\u6301\u901a\u8fc7\u7d22\u5f15\u8bbf\u95ee\u6307\u5b9a\u5143\u7d20\uff0c\u4f46\u53ef\u4ee5\u589e\u52a0\u548c\u5220\u9664\u5143\u7d20\u3002 \u9762\u7684\u4f8b\u5b50\u662f\u6c42 haystacke \u548c needles \u4e24\u4e2a\u96c6\u5408\u7684\u4ea4\u96c6\u5143\u7d20\u4e2a\u6570\u3002 haystacke = { 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'f' , 'g' , 'h' , 'c' , 'd' , 'e' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' } needles = { 'c' , 'h' , 'w' } type ( haystacke ) # type ( needles ) # # \u4f20\u7edf\u65b9\u6cd5 found = 0 for i in needles : if i in haystacke : found += 1 print ( found ) # 2 # \u96c6\u5408\u65b9\u6cd5\u4e00 found = len ( needles & haystacke ) print ( found ) # 2 # \u96c6\u5408\u65b9\u6cd5\u4e8c found = len ( needles . intersection ( haystacke )) print ( found ) # 2 \u96c6\u5408\u5b9e\u73b0\u4e86\u5f88\u591a\u57fa\u7840\u7684\u4e2d\u7f00\u8fd0\u7b97\u7b26\uff0c\u6bd4\u5982\uff0c\u96c6\u5408\u652f\u6301\u6570\u5b66\u4e0a\u7684\u96c6\u5408\u64cd\u4f5c\uff1a\u5e76\u96c6\u3001\u4ea4\u96c6\u3001\u5dee\u96c6\u3001\u5bf9\u79f0\u5dee\u96c6\u3002 \u65b9\u6cd5\u540d\u79f0 \u8bf4\u660e add() \u4e3a\u96c6\u5408\u6dfb\u52a0\u5143\u7d20 update() \u7ed9\u96c6\u5408\u6dfb\u52a0\u5143\u7d20 clear() \u79fb\u9664\u96c6\u5408\u4e2d\u7684\u6240\u6709\u5143\u7d20 copy() \u62f7\u8d1d\u4e00\u4e2a\u96c6\u5408 remove() \u79fb\u9664\u6307\u5b9a\u5143\u7d20 pop() \u968f\u673a\u79fb\u9664\u5143\u7d20 discard() \u5220\u9664\u96c6\u5408\u4e2d\u6307\u5b9a\u7684\u5143\u7d20 < \u6216\u8005issubset() \u5224\u65ad\u6307\u5b9a\u96c6\u5408\u662f\u5426\u4e3a\u8be5\u65b9\u6cd5\u53c2\u6570\u96c6\u5408\u7684\u5b50\u96c6 | \u6216\u8005union() \u8fd4\u56de\u4e24\u4e2a\u96c6\u5408\u7684\u5e76\u96c6 & \u6216\u8005intersection() \u8fd4\u56de\u96c6\u5408\u7684\u4ea4\u96c6 intersection_update() \u8fd4\u56de\u96c6\u5408\u7684\u4ea4\u96c6 - \u6216\u8005difference() \u8fd4\u56de\u591a\u4e2a\u96c6\u5408\u7684\u5dee\u96c6 difference_update() \u79fb\u9664\u96c6\u5408\u4e2d\u7684\u5143\u7d20\uff0c\u8be5\u5143\u7d20\u5728\u6307\u5b9a\u7684\u96c6\u5408\u4e5f\u5b58\u5728 ^ \u6216\u8005symmetric_difference() \u8fd4\u56de\u4e24\u4e2a\u96c6\u5408\u4e2d\u4e0d\u91cd\u590d\u7684\u5143\u7d20\u96c6\u5408(\u4e24\u96c6\u5408\u9664\u53bb\u4ea4\u96c6\u90e8\u5206\u7684\u5143\u7d20) symmetric_difference_update() \u79fb\u9664\u5f53\u524d\u96c6\u5408\u4e2d\u5728\u53e6\u5916\u4e00\u4e2a\u6307\u5b9a\u96c6\u5408\u76f8\u540c\u7684\u5143\u7d20\uff0c\u5e76\u5c06\u53e6\u5916\u4e00\u4e2a\u6307\u5b9a\u96c6\u5408\u4e2d\u4e0d\u540c\u7684\u5143\u7d20\u63d2\u5165\u5230\u5f53\u524d\u96c6\u5408\u4e2d isdisjoint() \u5224\u65ad\u4e24\u4e2a\u96c6\u5408\u662f\u5426\u5305\u542b\u76f8\u540c\u7684\u5143\u7d20\uff0c\u5982\u679c\u6ca1\u6709\u8fd4\u56de True\uff0c\u5426\u5219\u8fd4\u56de False issuperset() \u5224\u65ad\u8be5\u65b9\u6cd5\u7684\u53c2\u6570\u96c6\u5408\u662f\u5426\u4e3a\u6307\u5b9a\u96c6\u5408\u7684\u5b50\u96c6 \u4e3e\u4f8b\uff1a a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } \u5e76\u96c6(a\u548cb\u4e2d\u7684\u6240\u6709\u4e0d\u540c\u5143\u7d20)\u3002 print ( a . union ( b )) # {'c', 1, 2, 'd', 'a', 'b'} print ( a | b ) # {'c', 1, 2, 'd', 'a', 'b'} \u4ea4\u96c6(a\u3001b\u4e2d\u540c\u65f6\u5305\u542b\u7684\u5143\u7d20)\u3002 print ( a . intersection ( b )) # {'c', 1} print ( a & b ) # {'c', 1} \u5c06a\u7684\u5185\u5bb9\u8bbe\u7f6e\u4e3aa\u548cb\u7684\u4ea4\u96c6\u3002 a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a . intersection_update ( b ) print ( a ) # {1, 'c'} \u5728a\u4e0d\u5728b\u7684\u5143\u7d20\u3002 print ( a . difference ( b )) # {'a', 2, 'b'} print ( a - b ) # {2, 'a', 'b'} \u5c06a\u7684\u5185\u5bb9\u8bbe\u4e3a\u5728a\u4e0d\u5728b\u7684\u5143\u7d20\u3002 a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a . difference_update ( b ) print ( a ) # {2, 'b', 'a'} a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a -= b print ( a ) # {2, 'a', 'b'} \u5c06\u5143\u7d20\u52a0\u5165\u96c6\u5408a\u3002 a . add ( 7 ) print ( a ) # {1, 2, 'c', 7, 'a', 'b'} \u6bcf\u6b21\u8f93\u51fa\u7684\u987a\u5e8f\u662f\u4e0d\u4e00\u6837\u7684 \u4ece\u96c6\u5408a\u79fb\u9664\u67d0\u4e2a\u5143\u7d20\u3002 a . remove ( 7 ) print ( a ) # {1, 2, 'c', 'a', 'b'} \u5982\u679ca\u88ab\u6e05\u7a7a\uff0c\u5219\u62a5\u9519 KeyError: 7 \u6240\u6709\u5728a\u6216b\u4e2d\uff0c\u4f46\u4e0d\u662f\u540c\u65f6\u5728a\u3001b\u4e2d\u7684\u5143\u7d20\u3002 print ( a . symmetric_difference ( b )) # {2, 'd', 'b', 'a'} print ( a ^ b ) # {2, 'd', 'b', 'a'} \u5c06a\u7684\u5185\u5bb9\u8bbe\u4e3a\u6240\u6709\u5728a\u6216b\u4e2d\uff0c\u4f46\u4e0d\u662f\u540c\u65f6\u5728a\u3001b\u4e2d\u7684\u5143\u7d20\u3002 a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a . symmetric_difference_update ( b ) print ( a ) # {'a', 2, 'd', 'b'} a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a ^= b print ( a ) # {2, 'd', 'a', 'b'} \u5982\u679ca\u5305\u542b\u4e8eb\uff0c\u8fd4\u56deTure\u3002 print ( a . issubset ( b )) # False \u5c06a\u7684\u5185\u5bb9\u8bbe\u7f6e\u4e3aa\u548cb\u7684\u5e76\u96c6\u3002 print ( a ) # {'a', 2, 'd', 'b'} a = { 'a' , 'b' , 'c' , 1 , 2 } a . update ( b ) print ( a ) # {1, 2, 'a', 'b', 'd', 'c'} \u79fb\u9664\u4efb\u610f\u5143\u7d20\uff0c\u5982\u679c\u96c6\u5408\u662f\u7a7a\u7684\uff0c\u629b\u51fakeyError\u3002 a . pop () # \u968f\u673a\u79fb\u9664\u67d0\u4e2a\u5143\u7d20\uff0c\u6ca1\u6709\u8f93\u5165\u53d8\u91cf\uff0c\u5982\u679c\u96c6\u5408\u662f\u7a7a\u7684\uff0c\u629b\u51faKeyError: 'pop from an empty set' print ( a ) # {2, 1, 'd', 'b', 'a'} \u5c06\u96c6\u5408\u91cd\u7f6e\u4e3a\u7a7a\uff0c\u6e05\u7a7a\u6240\u6709\u5143\u7d20\u3002 a . clear () print ( a ) # set() \u96c6\u5408\u7684\u5143\u7d20\u5fc5\u987b\u662f\u4e0d\u53ef\u53d8\u7684\uff0c\u5982\u679c\u60f3\u8981\u5305\u542b\u5217\u8868\u578b\u7684\u5143\u7d20\uff0c\u5fc5\u987b\u5148\u8f6c\u6362\u4e3a\u5143\u7ec4\u3002 my_data1 = [ 1 , 2 , 3 , 4 ] my_data2 = [ 3 , 4 , 5 , 6 ] my_set = { tuple ( my_data1 ), tuple ( my_data2 )} print ( my_set ) # {(1, 2, 3, 4), (3, 4, 5, 6)}","title":"1.5 \u96c6\u5408\uff08set\uff09"},{"location":"python/Foundation/ch01/#16-tuple","text":"Python \u7684\u5143\u7ec4\u4e0e\u5217\u8868\u7c7b\u4f3c\uff0c\u4e0d\u540c\u4e4b\u5904\u5728\u4e8e\u5143\u7ec4\u7684\u5143\u7d20\u4e0d\u80fd\u4fee\u6539\u3002 \u5143\u7ec4\u4f7f\u7528\u5c0f\u62ec\u53f7( )\uff0c\u5217\u8868\u4f7f\u7528\u65b9\u62ec\u53f7[ ]\u3002 \u5143\u7ec4\u4e2d\u53ea\u5305\u542b\u4e00\u4e2a\u5143\u7d20\u65f6\uff0c\u9700\u8981\u5728\u5143\u7d20\u540e\u9762\u6dfb\u52a0\u9017\u53f7 \uff0c\u5426\u5219\u62ec\u53f7\u4f1a\u88ab\u5f53\u4f5c\u8fd0\u7b97\u7b26\u4f7f\u7528\u3002 \u5143\u7ec4\u53ef\u4ee5\u4f7f\u7528\u4e0b\u6807\u7d22\u5f15\u6765\u8bbf\u95ee\u5143\u7ec4\u4e2d\u7684\u503c\u3002 \u5143\u7ec4\u4e2d\u7684\u5143\u7d20\u503c\u662f\u4e0d\u5141\u8bb8\u4fee\u6539\u7684\uff0c\u4f46\u6211\u4eec\u53ef\u4ee5\u5bf9\u5143\u7ec4\u8fdb\u884c\u8fde\u63a5\u7ec4\u5408\u3002 \u5143\u7ec4\u4e2d\u7684\u5143\u7d20\u503c\u662f\u4e0d\u5141\u8bb8\u5220\u9664\u7684\uff0c\u4f46\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528del\u8bed\u53e5\u6765\u5220\u9664\u6574\u4e2a\u5143\u7ec4\u3002 # \u6b64\u5904\u62ec\u53f7\u88ab\u89e3\u6790\u4e3a\u8fd0\u7b97\u7b26\uff0c\u9700\u8981\u5728\u540e\u9762\u52a0\u4e0a\u9017\u53f7\u624d\u4f1a\u88ab\u89e3\u91ca\u4e3a\u5143\u7ec4 tup1 = ( 10 ) print ( type ( tup1 )) # tup1 = ( 10 ,) print ( type ( tup1 )) # \u521b\u5efa\u5143\u7ec4\u6700\u7b80\u5355\u7684\u529e\u6cd5\u5c31\u662f\u7528\u9017\u53f7\u5206\u9694\u5e8f\u5217\u503c\u3002\u5143\u7ec4\u5bf9\u6570\u636e\u7c7b\u578b\u6ca1\u6709\u4e00\u81f4\u6027\u8981\u6c42\u3002 tup = 4 , 5 , 6 print ( tup ) # (4, 5, 6) nested_tup = ( 4 , 5 , 6 ), ( 7 , 8 ) print ( nested_tup ) # # ((4, 5, 6), (7, 8)) tup = ( 'a' , 'b' , { 'one' : 1 }) print ( type ( tup )) # \u4f7f\u7528\u52a0\u53f7\uff08+\uff09\u8fdb\u884c\u5143\u7ec4\u8fde\u63a5\u5408\u5e76\u3002 tup = tuple (( 4 , None , 'fool' ) + ( 6 , 0 ) + ( 'bar' ,)) print ( tup ) # (4, None, 'fool', 6, 0, 'bar') \u5143\u7ec4\u7684\u4e0d\u53ef\u53d8\u6307\u7684\u662f**\u5143\u7ec4\u6240\u6307\u5411\u7684\u5185\u5b58\u4e2d\u7684\u5185\u5bb9\u4e0d\u53ef\u53d8**\u3002 tup = ( 'h' , 'e' , 'l' , 'l' , 'o' ) print ( id ( tup )) # 139820353350208 tup = ( 1 , 2 , 3 , 4 , 5 ) print ( id ( tup )) # 139820353298896 tup [ 0 ] = 'x' # Traceback (most recent call last): # File \"\", line 1, in # TypeError: 'tuple' object does not support item assignment \u5c06\u5143\u7ec4\u4e58\u4ee5\u6574\u6570\uff0c\u5219\u4f1a\u548c\u5217\u8868\u4e00\u6837\uff0c\u751f\u6210\u542b\u6709\u591a\u4efd\u62f7\u8d1d\u7684\u5143\u7ec4\u3002\u5bf9\u8c61\u81ea\u8eab\u5e76\u6ca1\u6709\u590d\u5236\uff0c\u53ea\u662f\u6307\u5411\u5b83\u4eec\u7684\u5f15\u7528\u8fdb\u884c\u4e86\u590d\u5236\u3002 tup = tuple (( 'fool' , 'bar' ) * 4 ) print ( tup ) # ('fool', 'bar', 'fool', 'bar', 'fool', 'bar', 'fool', 'bar') \u5982\u679c\u5143\u7ec4\u4e2d\u7684\u4e00\u4e2a\u5bf9\u8c61\u662f\u53ef\u53d8\u7684\uff0c\u4f8b\u5982\u5217\u8868\uff0c\u4f60\u53ef\u4ee5\u5728\u5b83\u5185\u90e8\u8fdb\u884c\u4fee\u6539\u3002 tup = tuple ([ 'foo' , [ 4 , 5 , 6 ], True ]) tup [ 1 ] . append ( 0 ) print ( tup ) # ('foo', [4, 5, 6, 0], True) tup [ 1 ] . append ([ 9 ]) print ( tup ) # ('foo', [4, 5, 6, 0, [9]], True) \u4f7f\u7528tuple\u51fd\u6570\u5c06\u4efb\u610f\u5e8f\u5217\u6216\u8fed\u4ee3\u5668\u8f6c\u6362\u4e3a\u5143\u7ec4\u3002 tup = tuple ([ 4 , 5 , 6 ]) print ( tup ) # (4, 5, 6) tup = tuple ( 'string' ) print ( tup ) # ('s', 't', 'r', 'i', 'n', 'g') print ( tup [ 2 ]) # r # \u5143\u7ec4\u7684\u5143\u7d20\u53ef\u4ee5\u901a\u8fc7\u4e2d\u62ec\u53f7[]\u6765\u83b7\u53d6 \u5982\u679c\u8981\u5c06\u5143\u7ec4\u578b\u7684\u8868\u8fbe\u5f0f\u8d4b\u503c\u7ed9\u53d8\u91cf\uff0cPython\u4f1a\u5bf9\u7b49\u53f7\u53f3\u8fb9\u7684\u503c\u8fdb\u884c \u62c6\u5305 \u3002 tup = ( 9 , 5 , ( 8 , 7 )) a , b , c = tup print ( a ) # 9 print ( b ) # 5 print ( c ) # (8, 7) a , b , ( c , d ) = tup print ( a ) # 9 print ( b ) # 5 print ( c ) # 8 print ( d ) # 7 tup = ( 9 , 5 , ( 8 , 7 )) a , b , c = tup c , a = a , c # \u5229\u7528\u62c6\u5305\u5b9e\u73b0\u4ea4\u6362 print ( a ) # (8, 7) print ( b ) # 5 print ( c ) # 9 \u5229\u7528\u62c6\u5305\u5b9e\u73b0\u904d\u5386\u5143\u7ec4\u6216\u5217\u8868\u7ec4\u6210\u7684\u5e8f\u5217\u3002 seq = [( 1 , 2 , 3 ), ( 4 , 5 , 6 ), ( 7 , 8 , 9 )] for a , b , c in seq : print ( 'a= {0} , b= {0} , c= {0} ' . format ( a , b , c )) # \u5217\u8868\u6bcf\u4e2a\u5143\u7d20\u7684\u53d6\u503c\u987a\u5e8f # a=1, b=1, c=1 # a=4, b=4, c=4 # a=7, b=7, c=7 print ( 'a= {0} , b= {1} , c= {2} ' . format ( a , b , c )) # a=1, b=2, c=3 # a=4, b=5, c=6 # a=7, b=8, c=9 print ( 'a= {2} , b= {0} , c= {1} ' . format ( a , b , c )) # a=3, b=1, c=2 # a=6, b=4, c=5 # a=9, b=7, c=8 \u5143\u7ec4\u62c6\u5305\u529f\u80fd\u8fd8\u5305\u62ec\u7279\u6b8a\u7684\u8bed\u6cd5*rest\u3002\u5f88\u591aPython\u7f16\u7a0b\u8005\u4f1a\u4f7f\u7528\u4e0b\u5212\u7ebf\uff08_\uff09\u6765\u8868\u793a\u4e0d\u60f3\u8981\u7684\u53d8\u91cf\u3002 values = 1 , 2 , 3 , 4 , 5 a , b , * rest = values print ( a ) # 1 print ( b ) # 2 print ( * rest ) # 3 4 5 a , b , * _ = values print ( * _ ) # 3 4 5 \u5177\u540d\u5143\u7ec4\u3002 collections.namedtuple \u662f\u4e00\u4e2a\u5de5\u5382\u51fd\u6570\uff0c\u5b83\u53ef\u4ee5\u7528\u6765\u6784\u5efa\u4e00\u4e2a\u5e26\u5b57\u6bb5\u540d\u7684\u5143\u7ec4\u548c\u4e00\u4e2a\u6709\u540d\u5b57\u7684\u7c7b\u3002 \u7528namedtuple\u6784\u5efa\u7684\u7c7b\u7684\u5b9e\u4f8b\u6240\u6d88\u8017\u7684\u5185\u5b58\u8ddf\u5143\u7ec4\u662f\u4e00\u6837\u7684\uff0c\u56e0\u4e3a\u5b57\u6bb5\u540d\u90fd\u88ab\u5b58\u5728\u5bf9\u5e94\u7684\u7c7b\u91cc\u9762\u3002 \u521b\u5efa\u4e00\u4e2a\u5177\u540d\u5143\u7ec4\u9700\u8981\u4e24\u4e2a\u53c2\u6570\uff0c\u4e00\u4e2a\u662f\u7c7b\u540d( City )\uff0c\u53e6\u4e00\u4e2a\u662f\u7c7b\u7684\u5404\u4e2a\u5b57\u6bb5\u7684\u540d\u5b57( 'name country population coordinates' )\u3002\u540e\u8005\u53ef\u4ee5\u662f\u7531\u6570\u4e2a\u5b57\u7b26\u4e32\u7ec4\u6210\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff0c\u6216\u8005\u662f\u7531\u7a7a\u683c\u5206\u9694\u5f00\u7684\u5b57\u6bb5\u540d\u7ec4\u6210\u7684\u5b57\u7b26\u4e32\u3002 \u5b58\u653e\u5728\u5bf9\u5e94\u5b57\u6bb5\u91cc\u7684\u6570\u636e\u8981\u4ee5\u4e00\u4e32\u53c2\u6570\u7684\u5f62\u5f0f\u4f20\u5165\u5230\u6784\u9020\u51fd\u6570\u4e2d\uff08\u6ce8\u610f\uff0c\u5143\u7ec4\u7684\u6784\u9020\u51fd\u6570\u5374\u53ea\u63a5\u53d7\u5355\u4e00\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff09\u3002 \u5177\u540d\u5143\u7ec4\u8fd8\u6709\u4e00\u4e9b\u81ea\u5df1\u4e13\u6709\u7684\u5c5e\u6027\u3002\u4e0b\u9762\u5c55\u793a\u4e86\u51e0\u4e2a\u6700\u6709\u7528\u7684\uff1a _fields \u7c7b\u5c5e\u6027\u3001\u7c7b\u65b9\u6cd5 _make(iterable) \u548c\u5b9e\u4f8b\u65b9\u6cd5 _asdict() \u3002 _fields \u5c5e\u6027\u662f\u4e00\u4e2a\u5305\u542b\u8fd9\u4e2a\u7c7b\u6240\u6709\u5b57\u6bb5\u540d\u79f0\u7684\u5143\u7ec4\u3002 \u7528 _make() \u901a\u8fc7\u63a5\u53d7\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u6765\u751f\u6210\u8fd9\u4e2a\u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u5b83\u7684\u4f5c\u7528\u8ddf City(*delhi_data) \u662f\u4e00\u6837\u7684\u3002 _asdict() \u628a\u5177\u540d\u5143\u7ec4\u4ee5 collections.OrderedDict \u7684\u5f62\u5f0f\u8fd4\u56de\uff0c\u6211\u4eec\u53ef\u4ee5\u5229\u7528\u5b83\u6765\u628a\u5143\u7ec4\u91cc\u7684\u4fe1\u606f\u53cb\u597d\u5730\u5448\u73b0\u51fa\u6765\u3002 from collections import namedtuple City = namedtuple ( 'City' , 'name country population coordinates' ) tokyo = City ( 'Tokyo' , 'JP' , 36.933 , ( 35.689722 , 139691667 )) print ( tokyo ) # City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139691667)) print ( tokyo . population ) # 36.933 print ( tokyo [ 3 ]) # (35.689722, 139691667) print ( City . _fields ) # ('name', 'country', 'population', 'coordinates') LatLong = namedtuple ( 'LatLong' , 'lat long' ) delhi_data = ( 'Delhi NCR' , 'IN' , 21.935 , LatLong ( 28.613899 , 77.208889 )) delhi = City . _make ( delhi_data ) print ( delhi ) # City(name='Delhi NCR', country='IN', population=21.935, coordinates=LatLong(lat=28.613899, long=77.208889)) print ( delhi . _asdict ()) # OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935), ('coordinates', LatLong(lat=28.613899, long=77.208889))]) for key , value in delhi . _asdict () . items (): print ( key + ':' , value ) # name: Delhi NCR # country: IN # population: 21.935 # coordinates: LatLong(lat=28.613899, long=77.208889) \u5143\u7ec4\u8fd8\u6709\u7b2c\u4e8c\u91cd\u529f\u80fd\uff1a\u4f5c\u4e3a\u4e0d\u53ef\u53d8\u5217\u8868\u7684\u5143\u7ec4\u3002 \u4e0b\u9762\u662f\u5217\u8868\u6216\u5143\u7ec4\u7684\u65b9\u6cd5\u548c\u5c5e\u6027\u5bf9\u6bd4\u3002\u9664\u4e86\u8ddf\u589e\u51cf\u5143\u7d20\u76f8\u5173\u7684\u65b9\u6cd5\u4e4b\u5916\uff0c\u5143\u7ec4\u652f\u6301\u5217\u8868\u7684\u5176\u4ed6\u6240\u6709\u65b9\u6cd5\u3002\u8fd8\u6709\u4e00\u4e2a\u4f8b\u5916\uff0c\u5143\u7ec4\u6ca1\u6709__reversed__\u65b9\u6cd5\u3002 \u4e00\u4e2a\u5173\u4e8e+=\u548c*=\u7684\u8c1c\u9898\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u5c55\u793a\u4e86 *= \u5728\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u5e8f\u5217\u4e0a\u7684\u4f5c\u7528\u3002\u5217\u8868\u7684ID\u6ca1\u53d8\uff0c\u65b0\u5143\u7d20\u8ffd\u52a0\u5230\u5217\u8868\u4e0a\uff0c\u4f46\u6267\u884c\u589e\u91cf\u4e58\u6cd5\u540e\uff0c\u65b0\u7684\u5143\u7ec4\u88ab\u521b\u5efa\u3002 list1 = [ 1 , 2 , 3 , 4 ] id ( list1 ) # 140409777308808 list1 *= 2 print ( list1 ) # [1, 2, 3, 4, 1, 2, 3, 4] id ( list1 ) # 140409777308808 tuple1 = ( 1 , 2 , 3 , 4 ) id ( tuple1 ) # 140409777230536 tuple1 *= 2 print ( tuple1 ) # (1, 2, 3, 4, 1, 2, 3, 4) id ( tuple1 ) # 140409780104888 \u4f46\u5bf9\u4e8e\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u867d\u7136 tuple1[2] += [50, 60] \u6267\u884c\u65f6\u6709\u5f02\u5e38\u629b\u51fa\uff0c\u4f46 tuple1 \u5374\u88ab\u4fee\u6539\u4e86\u3002 t = ( 1 , 2 , [ 10 , 20 ]) t [ 2 ] += [ 50 , 60 ] # TypeError: 'tuple' object does not support item assignment print ( t ) # (1, 2, [10, 20, 50, 60]) \u4e0b\u56fe\u5927\u81f4\u63cf\u8ff0\u4e86\u4e0a\u8ff0\u6267\u884c\u8fc7\u7a0b\u3002 \u4e3a\u4e86\u907f\u514d\u4e0a\u9762\u60c5\u51b5\u7684\u53d1\u751f\uff0c\u6211\u4eec**\u4e0d\u8981\u628a\u53ef\u53d8\u5bf9\u8c61\u653e\u5728\u5143\u7ec4\u91cc\u9762**\u3002\u589e\u91cf\u8d4b\u503c\u4e0d\u662f\u4e00\u4e2a\u539f\u5b50\u64cd\u4f5c\uff0c\u5b83\u867d\u7136\u629b\u51fa\u4e86\u5f02\u5e38\uff0c\u4f46\u8fd8\u662f\u5b8c\u6210\u4e86\u64cd\u4f5c\u3002","title":"1.6 \u5143\u7ec4\uff08tuple\uff09"},{"location":"python/Foundation/ch01/#17-memoryview","text":"memoryview \u662f\u4e00\u4e2a\u5185\u7f6e\u7c7b\uff0c\u5b83\u80fd\u8ba9\u7528\u6237\u5728\u4e0d\u590d\u5236\u5185\u5bb9\u7684\u60c5\u51b5\u4e0b\u64cd\u4f5c\u540c\u4e00\u4e2a\u6570\u7ec4\u7684\u4e0d\u540c\u5207\u7247\u3002 \u5185\u5b58\u89c6\u56fe\u5176\u5b9e\u662f\u6cdb\u5316\u548c\u53bb\u6570\u5b66\u5316\u7684NumPy\u6570\u7ec4\u3002\u5b83\u8ba9\u4f60\u5728\u4e0d\u9700\u8981\u590d\u5236\u5185\u5bb9\u7684\u524d\u63d0\u4e0b\uff0c\u5728\u6570\u636e\u7ed3\u6784\u4e4b\u95f4\u5171\u4eab\u5185\u5b58\u3002 \u5176\u4e2d\u6570\u636e\u7ed3\u6784\u53ef\u4ee5\u662f\u4efb\u4f55\u5f62\u5f0f\uff0c\u6bd4\u5982PIL\u56fe\u7247\u3001SQLite\u6570\u636e\u5e93\u548cNumPy\u7684\u6570\u7ec4\uff0c\u7b49\u7b49\u3002\u8fd9\u4e2a\u529f\u80fd\u5728\u5904\u7406\u5927\u578b\u6570\u636e\u96c6\u5408\u7684\u65f6\u5019\u975e\u5e38\u91cd\u8981\u3002 memoryview.cast \u7684\u6982\u5ff5\u8ddf\u6570\u7ec4\u6a21\u5757\u7c7b\u4f3c\uff0c\u80fd\u7528\u4e0d\u540c\u7684\u65b9\u5f0f\u8bfb\u5199\u540c\u4e00\u5757\u5185\u5b58\u6570\u636e\uff0c\u800c\u4e14\u5185\u5bb9\u5b57\u8282\u4e0d\u4f1a\u968f\u610f\u79fb\u52a8\u3002\u8fd9\u8ddfC\u8bed\u8a00\u4e2d\u7c7b\u578b\u8f6c\u6362\u7684\u6982\u5ff5\u5dee\u4e0d\u591a\u3002 memoryview.cast \u4f1a\u628a\u540c\u4e00\u5757\u5185\u5b58\u91cc\u7684\u5185\u5bb9\u6253\u5305\u6210\u4e00\u4e2a\u5168\u65b0\u7684memoryview\u5bf9\u8c61\u7ed9\u4f60\u3002 array \u91cc\u9762\u7684Type code\uff1a 'b' signed integer 1 'B' unsigned integer 1 'u' Unicode character 2 (see note) 'h' signed integer 2 'H' unsigned integer 2 'i' signed integer 2 'I' unsigned integer 2 'l' signed integer 4 'L' unsigned integer 4 'q' signed integer 8 (see note) 'Q' unsigned integer 8 (see note) 'f' floating point 4 'd' floating point 8 numbers = array ( 'h' , [ - 2 , - 1 , 0 , 1 , 2 ]) # array('h', [-2, -1, 0, 1, 2]) # \u75285\u4e2a\u77ed\u6574\u578b\u6709\u7b26\u53f7\u6574\u6570\u7684\u6570\u7ec4\uff08\u7c7b\u578b\u7801\u662f'h'\uff09\u521b\u5efa\u4e00\u4e2amemoryview\u3002 memv = memoryview ( numbers ) # memv\u91cc\u76845\u4e2a\u5143\u7d20\u8ddf\u6570\u7ec4\u91cc\u7684\u6ca1\u6709\u533a\u522b\u3002 print ( len ( memv )) # 5 print ( memv [ 0 ]) # -2 print ( memv . tolist ()) # [-2, -1, 0, 1, 2] # \u521b\u5efa\u4e00\u4e2amemv_oct\uff0c\u8fd9\u4e00\u6b21\u662f\u628amemv\u91cc\u7684\u5185\u5bb9\u8f6c\u6362\u6210'B'\u7c7b\u578b\uff0c\u4e5f\u5c31\u662f\u65e0\u7b26\u53f7\u5b57\u7b26\u3002 memv_oct = memv . cast ( 'B' ) print ( memv_oct . tolist ()) # [254, 255, 255, 255, 0, 0, 1, 0, 2, 0] # \u628a\u4f4d\u4e8e\u4f4d\u7f6e5\u7684\u5b57\u8282\u8d4b\u503c\u62104\u3002\u56e0\u4e3a\u6211\u4eec\u628a\u53602\u4e2a\u5b57\u8282\u7684\u6574\u6570\u7684\u9ad8\u4f4d\u5b57\u8282\u6539\u6210\u4e864\uff0c\u6240\u4ee5\u8fd9\u4e2a\u6709\u7b26\u53f7\u6574\u6570\u7684\u503c\u5c31\u53d8\u6210\u4e861024\u3002 memv_oct [ 5 ] = 4 print ( numbers ) # array('h', [-2, -1, 1024, 1, 2])","title":"1.7 \u5185\u5b58\u89c6\u56feMemoryview"},{"location":"python/Foundation/ch01/#2","text":"\u661f\u53f7 * \u7684\u53c2\u6570\u4f1a\u4ee5\u5143\u7ec4(tuple)\u7684\u5f62\u5f0f\u5bfc\u5165\uff0c\u5b58\u653e\u6240\u6709\u672a\u547d\u540d\u7684\u53d8\u91cf\u53c2\u6570 def printinfo ( arg1 , * vartuple ): print ( \"\u8f93\u51fa\u4efb\u4f55\u4f20\u5165\u7684\u53c2\u6570: \" ) print ( arg1 ) print ( vartuple ) for var in vartuple : print ( var ) return printinfo ( 10 ) # 10 # () printinfo ( 70 , 60 , 50 ) # 70 # (60, 50) # 60 # 50 \u4e24\u4e2a\u661f\u53f7 ** \u7684\u53c2\u6570\u4f1a\u4ee5\u5b57\u5178\u7684\u5f62\u5f0f\u5bfc\u5165\u3002 def printinfo ( arg1 , ** vardict ): print ( \"\u8f93\u51fa\u4efb\u4f55\u4f20\u5165\u7684\u53c2\u6570: \" ) print ( arg1 ) print ( vardict ) printinfo ( 1 , a = 2 , b = 3 ) # 1 # {'a': 2, 'b': 3} \u5b57\u5178\u683c\u5f0f\u8f93\u51fa Python\u4e2d\u7684\u5bf9\u8c61\u5f15\u7528\u5e76\u4e0d\u6d89\u53ca\u7c7b\u578b\u3002\u53d8\u91cf\u5bf9\u4e8e\u5bf9\u8c61\u6765\u8bf4\u53ea\u662f\u7279\u5b9a\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u540d\u79f0\uff1b\u7c7b\u578b\u4fe1\u606f\u662f\u5b58\u50a8\u5728\u5bf9\u8c61\u81ea\u8eab\u4e4b\u4e2d\u3002 a = 5 print ( type ( a )) # a = 'foo' print ( type ( a )) # Python\u662f\u5f3a\u7c7b\u578b\u8bed\u8a00\uff0c\u6240\u6709\u7684\u5bf9\u8c61\u90fd\u62e5\u6709\u4e00\u4e2a\u6307\u5b9a\u7684\u7c7b\u578b\uff08\u6216\u7c7b\uff09\uff0c\u9690\u5f0f\u7684\u8f6c\u6362\u53ea\u5728\u67d0\u4e9b\u7279\u5b9a\u3001\u660e\u663e\u7684\u60c5\u51b5\u4e0b\u53d1\u751f\u3002 a = 4.5 b = 2 print ( 'a is {0} , b is {1} ' . format ( type ( a ), type ( b ))) # a is , b is \u5b57\u4e32\u683c\u5f0f\u5316\uff0c\u7528\u4e8e\u540e\u7eed\u8bbf\u95ee print ( a / b ) # 2.25 \u4f7f\u7528isinstance\u51fd\u6570\u6765\u68c0\u67e5\u4e00\u4e2a\u5bf9\u8c61\u662f\u5426\u662f\u7279\u5b9a\u7c7b\u578b\u7684\u5b9e\u4f8b\u3002isinstance\u63a5\u53d7\u4e00\u4e2a\u5305\u542b\u7c7b\u578b\u7684\u5143\u7ec4\uff0c\u53ef\u4ee5\u68c0\u67e5\u5bf9\u8c61\u7684\u7c7b\u578b\u662f\u5426\u5728\u5143\u7ec4\u4e2d\u7684\u7c7b\u578b\u4e2d\u3002 a = 5 b = 4.5 c = 'foo' print ( isinstance ( a , int )) # True print ( isinstance ( b , str )) # False print ( isinstance ( c , ( str , int ))) # True print ( isinstance ( c , ( float , int ))) # False \u5c5e\u6027\u548c\u65b9\u6cd5\u4e5f\u53ef\u4ee5\u901a\u8fc7getattr\u51fd\u6570\u83b7\u5f97\u3002\u5728\u5176\u4ed6\u7684\u8bed\u8a00\u4e2d\uff0c\u901a\u8fc7\u53d8\u91cf\u540d\u8bbf\u95ee\u5bf9\u8c61\u901a\u5e38\u88ab\u79f0\u4e3a\u201c\u53cd\u5c04\u201d\u3002 b = 'foo' print ( getattr ( b , 'split' )) # ","title":"2. \u52a8\u6001\u5f15\u7528\u3001\u5f3a\u7c7b\u578b"},{"location":"python/Foundation/ch01/#3","text":"\u68c0\u67e5\u4e24\u4e2a\u5f15\u7528\u662f\u5426\u6307\u5411\u540c\u4e00\u4e2a\u5bf9\u8c61\uff0c\u53ef\u4ee5\u4f7f\u7528is\u5173\u952e\u5b57\u3002 is\u548cis not\u7684\u5e38\u7528\u4e4b\u5904\u662f\u68c0\u67e5\u4e00\u4e2a\u53d8\u91cf\u662f\u5426\u4e3aNone\uff0c\u56e0\u4e3aNone\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b\u3002 a = [ 1 , 2 , 3 ] b = a c = list ( a ) # list\u51fd\u6570\u603b\u662f\u521b\u5efa\u4e00\u4e2a\u65b0\u7684Python\u5217\u8868\uff08\u5373\u4e00\u4efd\u62f7\u8d1d\uff09 print ( a is b ) # True print ( a is not c ) # True print ( a == c ) # True d = None print ( d is None ) # True Python\u4e2d\u7684\u5927\u90e8\u5206\u5bf9\u8c61\uff0c\u4f8b\u5982\u5217\u8868\u3001\u5b57\u5178\u3001NumPy\u6570\u7ec4\u90fd\u662f\u53ef\u53d8\u5bf9\u8c61\uff0c\u5927\u591a\u6570\u7528\u6237\u5b9a\u4e49\u7684\u7c7b\u578b\uff08\u7c7b\uff09\u4e5f\u662f\u53ef\u53d8\u7684\u3002 \u53ef\u53d8\u5bf9\u8c61\u4e2d\u5305\u542b\u7684\u5bf9\u8c61\u548c\u503c\u662f\u53ef\u4ee5\u88ab\u4fee\u6539\u7684\u3002\u8fd8\u6709\u5176\u4ed6\u4e00\u4e9b\u5bf9\u8c61\u662f\u4e0d\u53ef\u53d8\u7684\uff0c\u6bd4\u5982\u5b57\u7b26\u4e32\u3001\u5143\u7ec4\u3002 a_list = [ 'foo' , 2 , [ 4 , 5 ]] # \u5217\u8868 a_list [ 2 ] = ( 3 , 4 ) print ( a_list ) # ['foo', 2, (3, 4)] a_tuple = ( 3 , 5 , ( 4 , 5 )) # \u5143\u7ec4 a_tuple [ 1 ] = 'four' # TypeError: 'tuple' object does not support item assignment \u4e0d\u53ef\u88ab\u4fee\u6539 print ( a_tuple ) # (3, 5, (4, 5))","title":"3. \u4e8c\u5143\u8fd0\u7b97\u7b26\u548c\u6bd4\u8f83\u8fd0\u7b97"},{"location":"python/Foundation/ch01/#4","text":"Python\u6807\u91cf\u7c7b\u578b\uff1aNone, str, bytes, float, bool, int\u3002 \u6570\u503c\u7c7b\u578b\u3002 \u57fa\u7840\u7684Python\u6570\u5b57\u7c7b\u578b\u5c31\u662fint\u548cfloat\u3002int\u53ef\u4ee5\u5b58\u50a8\u4efb\u610f\u5927\u5c0f\u6570\u5b57\u3002\u6d6e\u70b9\u6570\u5728Python\u4e2d\u7528float\u8868\u793a\uff0c\u6bcf\u4e00\u4e2a\u6d6e\u70b9\u6570\u90fd\u662f\u53cc\u7cbe\u5ea664\u4f4d\u6570\u503c\u3002 ival = 17338971 print ( ival ** 6 ) # 27173145946003847721495630081806010734757321 fval = 17338971.0 print ( fval ** 6 ) # 2.7173145946003847e+43 print ( 3 / 2 ) # 1.5 print ( 3 // 2 ) # 1 \u5b57\u7b26\u4e32\u3002 Python\u7684\u5b57\u7b26\u4e32\u662f\u4e0d\u53ef\u53d8\u7684\u3002 a = 5.6 s = str ( a ) print ( s ) # 5.6 b = 'python' print ( list ( b )) # ['p', 'y', 't', 'h', 'o', 'n'] print ( b [ 2 ]) # t b [ 2 ] = 'f' # TypeError: 'str' object does not support item assignment \u5b57\u7b26\u4e32\u662f\u4e0d\u53ef\u53d8\u7684 \u53cd\u659c\u6760\u7b26\u53f7\\\u662f\u4e00\u79cd\u8f6c\u4e49\u7b26\u53f7\uff0c\u5b83\u7528\u6765\u6307\u660e\u7279\u6b8a\u7b26\u53f7\u3002 \u5982\u679c\u4f60\u6709\u4e00\u4e2a\u4e0d\u542b\u7279\u6b8a\u7b26\u53f7\u4f46\u542b\u6709\u5927\u91cf\u53cd\u659c\u6760\u7684\u5b57\u7b26\u4e32\u65f6\uff0c\u53ef\u4ee5\u5728\u5b57\u7b26\u4e32\u524d\u9762\u52a0\u4e00\u4e2a\u524d\u7f00\u7b26\u53f7r\uff0c\u8868\u660e\u8fd9\u4e9b\u5b57\u7b26\u662f\u539f\u751f\u5b57\u7b26\uff0cr\u662fraw\u7684\u7b80\u5199\uff0c\u8868\u793a\u539f\u751f\u7684\u3002 x = '12 \\\\ 34' y = r 'this\\has\\no\\special\\characters' print ( x ) # 12\\34 print ( y ) # this\\has\\no\\special\\characters \u5b57\u7b26\u4e32\u683c\u5f0f\u5316 {0:.2f}\u8868\u793a\u5c06\u7b2c\u4e00\u4e2a\u53c2\u6570\u683c\u5f0f\u5316\u4e3a2\u4f4d\u5c0f\u6570\u7684\u6d6e\u70b9\u6570 {1:s}\u8868\u793a\u5c06\u7b2c\u4e8c\u4e2a\u53c2\u6570\u683c\u5f0f\u5316\u4e3a\u5b57\u7b26\u4e32 {2:d}\u8868\u793a\u5c06\u7b2c\u4e09\u4e2a\u53c2\u6570\u683c\u5f0f\u5316\u6574\u6570 \u53c2\u8003Python\u5b98\u65b9\u6587\u6863 https://docs.python.org/3.6/library/string.html template = ' {0:.2f} {1:s} are worth US$ {2:d} ' print ( template . format ( 4.5560 , 'Argentine Pesos' , 1 )) # 4.56 Argentine Pesos are worth US$1 \u65e5\u671f\u548c\u65f6\u95f4 from datetime import datetime , date , time dt = datetime ( 2011 , 10 , 29 , 20 , 30 , 21 ) print ( dt . day ) # 29 print ( dt . minute ) # 30 print ( dt . date ()) # 2011-10-29 print ( dt . time ()) # 20:30:21 print ( dt . replace ( minute = 0 , second = 0 )) # 2011-10-29 20:00:00 \u5c06\u5206\u949f\u3001\u79d2\u66ff\u6362\u4e3a0 print ( datetime . strptime ( '20091021' , '%Y%m %d ' )) # 2009-10-21 00:00:00 \u5b57\u7b26\u4e32\u53ef\u4ee5\u901a\u8fc7 strptime \u51fd\u6570\u8f6c\u6362\u4e3adatetime\u5bf9\u8c61 dt2 = datetime ( 2011 , 11 , 15 , 22 , 30 ) delta = dt2 - dt print ( delta ) # 17 days, 1:59:39 print ( dt + delta ) # 2011-11-15 22:30:00 range\u51fd\u6570\u8fd4\u56de\u4e00\u4e2a\u8fed\u4ee3\u5668\uff0c\u8be5\u8fed\u4ee3\u5668\u751f\u6210\u4e00\u4e2a\u7b49\u5dee\u6574\u6570\u5e8f\u5217\u3002 print ( range ( 10 )) # range(0, 10) print ( list ( range ( 10 ))) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print ( list ( range ( 0 , 20 , 2 ))) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]","title":"4. \u6807\u91cf\u7c7b\u578b"},{"location":"python/Foundation/ch01/#5","text":"value = true-expr if condition else false-expr x = 5 print ( 'non-negative' if x >= 0 else 'negative' ) # non-negative","title":"5. \u4e09\u5143\u8868\u8fbe\u5f0f"},{"location":"python/Foundation/ch02/","text":"Python\u6253\u5305\u548c\u89e3\u5305 \u00b6 \u89e3\u5305Unpacking \u00b6 Python \u5141\u8bb8\u53d8\u91cf\u7684\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\u51fa\u73b0\u5728\u8d4b\u503c\u64cd\u4f5c\u7684\u5de6\u4fa7\u3002 \u5143\u7ec4\u4e2d\u7684\u6bcf\u4e2a\u53d8\u91cf\u90fd\u53ef\u4ee5\u4ece\u8d4b\u503c\u53f3\u4fa7\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08iterable\uff09\u4e2d\u63a5\u6536\u4e00\u4e2a\u503c\uff08\u6216\u8005\u66f4\u591a\uff0c\u5982\u679c\u6211\u4eec\u4f7f\u7528 * \u8fd0\u7b97\u7b26\uff09\u3002 Python \u4e2d\u7684\u89e3\u5305\u662f\u6307\u4e00\u79cd\u64cd\u4f5c\uff0c\u8be5\u64cd\u4f5c\u5305\u62ec\u5728\u5355\u4e2a\u8d4b\u503c\u8bed\u53e5\u4e2d\u5c06\u53ef\u8fed\u4ee3\u7684\u503c\u5206\u914d\u7ed9\u53d8\u91cf\u7684\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\u3002 \u5728 Python \u4e2d\uff0c\u53ef\u4ee5\u5728\u8d4b\u503c\u8fd0\u7b97\u7b26 = \u7684\u5de6\u4fa7\u653e\u7f6e\u4e00\u4e2a\u53d8\u91cf\u5143\u7ec4\uff0c\u5728\u53f3\u4fa7\u653e\u7f6e\u4e00\u4e2a\u503c\u5143\u7ec4\u3002 \u53f3\u8fb9\u7684\u503c\u5c06\u6839\u636e\u5b83\u4eec\u5728\u5143\u7ec4\u4e2d\u7684\u4f4d\u7f6e\u81ea\u52a8\u5206\u914d\u7ed9\u5de6\u8fb9\u7684\u53d8\u91cf\u3002 \u8fd9\u5728 Python \u4e2d\u901a\u5e38\u79f0\u4e3a\u5143\u7ec4\u89e3\u5305\u3002 \u5982\u4e0b\u793a\u4f8b\uff1a >>> ( a , b , c ) = ( 1 , 2 , 3 ) >>> a 1 >>> b 2 >>> c 3 >>> birthday = ( 'April' , 5 , 2001 ) >>> month , day , year = birthday >>> month 'April' >>> day 5 >>> year 2001 \u5143\u7ec4\u89e3\u5305\u529f\u80fd\u5728 Python \u4e2d\u53ef\u4ee5\u6269\u5c55\u4e3a\u9002\u7528\u4e8e\u4efb\u4f55\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 \u552f\u4e00\u7684\u8981\u6c42\u662f\u53ef\u8fed\u4ee3\u7684\u63a5\u6536\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\u4e2d\u7684\u6bcf\u4e2a\u53d8\u91cf\u6070\u597d\u5bf9\u5e94\u53ef\u8fed\u4ee3\u5bf9\u8c61\u7684\u4e00\u4e2a\u5143\u7d20\uff08item\uff09\u3002 \u4e0b\u9762\u7684\u793a\u4f8b\u4ecb\u7ecd\u4e86 Python \u4e2d\u53ef\u8fed\u4ee3\u89e3\u5305\u7684\u5de5\u4f5c\u539f\u7406\uff1a >>> # Unpackage strings >>> a , b , c = '123' >>> a '1' >>> b '2' >>> c '3' >>> # Unpacking lists >>> a , b , c = [ 1 , 2 , 3 ] >>> a 1 >>> b 2 >>> c 3 >>> # Unpacking generators >>> gen = ( i ** 2 for i in range ( 3 )) >>> a , b , c = gen >>> a 0 >>> b 1 >>> c 4 >>> # Upacking dictionaries (keys, values, and items) >>> my_dict = { 'one' : 1 , 'two' : 2 , 'three' : 3 } >>> a , b , c = my_dict >>> a 'one' >>> b 'two' >>> c 'three' >>> a , b , c = my_dict . values () >>> a 1 >>> b 2 >>> c 3 >>> a , b , c = my_dict . items () >>> a ( 'one' , 1 ) >>> b ( 'two' , 2 ) >>> c ( 'three' , 3 ) >>> # Use a tuple on the right side of assignment statement >>> [ a , b , c ] = 1 , 2 , 3 >>> a 1 >>> b 2 >>> c 3 >>> # Use range() iterator >>> x , y , z = range ( 3 ) >>> x 0 >>> y 1 >>> z 2 \u6253\u5305Packing \u00b6 \u6253\u5305\u53ef\u4ee5\u7406\u89e3\u4e3a\u4f7f\u7528\u53ef\u8fed\u4ee3\u89e3\u5305\u8fd0\u7b97\u7b26\u5728\u5355\u4e2a\u53d8\u91cf\u4e2d\u6536\u96c6\u591a\u4e2a\u503c\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c * \u8fd0\u7b97\u7b26\u88ab\u79f0\u4e3a\u5143\u7ec4\uff08\u6216\u53ef\u8fed\u4ee3\uff09\u89e3\u5305\u8fd0\u7b97\u7b26\u3002 \u5b83\u6269\u5c55\u4e86\u89e3\u5305\u529f\u80fd\uff0c\u5141\u8bb8\u5728\u5355\u4e2a\u53d8\u91cf\u4e2d\u6536\u96c6\u6216\u6253\u5305\u591a\u4e2a\u503c\u3002 \u5728\u4ee5\u4e0b\u793a\u4f8b\u4e2d\u53ef\u4ee5\u770b\u5230 * \u8fd0\u7b97\u7b26\u5c06\u5143\u7ec4\u503c\u6253\u5305\u5230\u5355\u4e2a\u53d8\u91cf\u4e2d\uff1a >>> # The right side is a tuple, the left side is a list >>> * a , = 1 , 2 >>> a [ 1 , 2 ] >>> type ( a ) < class ' list '> \u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\uff0c\u8d4b\u503c\u7684\u5de6\u4fa7\u5fc5\u987b\u662f\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\uff0c\u8fd9\u5c31\u662f\u4f7f\u7528\u5c3e\u968f\u9017\u53f7\u7684\u539f\u56e0\u3002\u8fd9\u4e2a\u5143\u7ec4\u53ef\u4ee5\u5305\u542b\u6240\u9700\u8981\u7684\u5c3d\u53ef\u80fd\u591a\u7684\u53d8\u91cf\uff0c\u4f46\u662f\uff0c\u5b83\u53ea\u80fd\u5305\u542b\u4e00\u4e2a\u661f\u53f7\u8868\u8fbe\u5f0f(starred expression)\u3002 >>> # Packing trailing values >>> a , * b = 1 , 2 , 3 >>> a 1 >>> b [ 2 , 3 ] >>> type ( a ) < class ' int '> >>> type ( b ) < class ' list '> >>> >>> * a , b , c = 1 , 2 , 3 >>> a [ 1 ] >>> b 2 >>> c 3 >>> * a , b , c , d , e = 1 , 2 , 3 Traceback ( most recent call last ): File \"\" , line 1 , in < module > ValueError : not enough values to unpack ( expected at least 4 , got 3 ) >>> * a , b , c , d = 1 , 2 , 3 >>> a [] >>> b 1 >>> c 2 >>> d 3 >>> >>> seq = [ 1 , 2 , 3 , 4 ] >>> first , * body , last = seq >>> first , body , last ( 1 , [ 2 , 3 ], 4 ) >>> first , body , * last = seq >>> first , body , last ( 1 , 2 , [ 3 , 4 ]) >>> >>> ran = range ( 10 ) >>> * r , = ran >>> r [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] \u4e0b\u9762\u662f\u4e00\u4e9b\u6253\u5305\u548c\u89e3\u5305\u7684\u4f8b\u5b50\u3002 >>> employee = [ 'John Doe' , '40' , 'Software Engineer' ] >>> name = employee [ 0 ] >>> age = employee [ 1 ] >>> job = employee [ 2 ] >>> name 'John Doe' >>> age '40' >>> job 'Software Engineer' >>> >>> name , age , job = [ 'John Doe' , '40' , 'Software Engineer' ] >>> name 'John Doe' >>> age '40' >>> job 'Software Engineer' >>> >>> a = 100 >>> b = 200 >>> a , b = b , a >>> a 200 >>> b 100 \u4f7f\u7528 * \u5220\u9664\u4e0d\u9700\u8981\u7684\u503c\u3002 >>> a , b , * _ = 1 , 2 , 0 , 0 , 0 , 0 >>> a 1 >>> b 2 >>> _ [ 0 , 0 , 0 , 0 ] \u5728\u4e0a\u4f8b\u4e2d\uff0c\u4e0d\u9700\u8981\u7684\u4fe1\u606f\u5b58\u50a8\u5728\u865a\u62df\u53d8\u91cf _ \u4e2d\uff0c\u5728\u540e\u7eed\u7684\u4f7f\u7528\u4e2d\u53ef\u4ee5\u5ffd\u7565\u5b83\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cPython \u89e3\u91ca\u5668\u4f7f\u7528\u4e0b\u5212\u7ebf\u5b57\u7b26 _ \u6765\u5b58\u50a8\u5728\u4ea4\u4e92\u5f0f\u4f1a\u8bdd\u4e2d\u8fd0\u884c\u7684\u8bed\u53e5\u7684\u7ed3\u679c\u503c\u3002 \u56e0\u6b64\uff0c\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528\u8fd9\u4e2a\u5b57\u7b26\u6765\u8bc6\u522b\u865a\u62df\u53d8\u91cf\u53ef\u80fd\u662f\u6a21\u68f1\u4e24\u53ef\u7684\u3002 \u5728\u51fd\u6570\u4e2d\u8fd4\u56de\u5143\u7ec4\u3002 >>> def powers ( num ): ... return num , num ** 2 , num ** 3 ... >>> # Packaging returned values in a tuple >>> result = powers ( 3 ) >>> result ( 3 , 9 , 27 ) >>> # Unpacking returned values to multiple variables >>> number , square , cube = powers ( 3 ) >>> number 3 >>> square 9 >>> cube 27 >>> * _ , cube = powers ( 3 ) >>> cube 27 \u4f7f\u7528 * \u548c ** \u8fd0\u7b97\u7b26 \u00b6 \u4f7f\u7528 * \u8fd0\u7b97\u7b26\u5408\u5e76\u8fed\u4ee3\u53d8\u91cf\uff08iterables\uff09\u3002\u4e0a\u9762\u4e24\u4e2a\u4f8b\u5b50\u8bf4\u660e\uff0c\u8fd9\u4e2d\u65b9\u6cd5\u4e5f\u662f\u8fde\u63a5\u8fed\u4ee3\u53d8\u91cf\uff08iterables\uff09\u7684\u4e00\u79cd\u66f4\u6613\u8bfb\u548c\u66f4\u6709\u6548\u7684\u65b9\u6cd5\u3002 \u8fd9\u4e2a\u65b9\u6cd5 (my_set) + my_list + list(my_tuple) + list(range(1, 4)) + list(my_str) \u53ef\u4ee5\u751f\u6210\u4e00\u4e2a\u5217\u8868 \uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u66f4\u7b80\u6d01\u7684\u65b9\u6cd5 [*my_set, *my_list, *my_tuple, *range(1, 4), *my_str] \u3002 >>> my_tuple = ( 1 , 2 , 3 ) >>> ( 0 , * my_tuple , 4 ) ( 0 , 1 , 2 , 3 , 4 ) >>> my_list = [ 1 , 2 , 3 ] >>> [ 0 , * my_list , 4 ] [ 0 , 1 , 2 , 3 , 4 ] >>> my_set = { 1 , 2 , 3 } >>> { 0 , * my_set , 4 } { 0 , 1 , 2 , 3 , 4 } >>> [ * my_set , * my_list , * my_tuple , * range ( 1 , 4 )] [ 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 ] >>> my_str = \"123\" >>> [ * my_set , * my_list , * my_tuple , * range ( 1 , 4 ), * my_str ] [ 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 , '1' , '2' , '3' ] \u4f7f\u7528 ** \u8fd0\u7b97\u7b26\u89e3\u5305\u5b57\u5178\u3002 >>> numbers = { 'one' : 1 , 'two' : 2 , 'three' : 3 } >>> letters = { 'a' : 'A' , 'b' : 'B' , 'c' : 'C' } >>> combination = { ** numbers , ** letters } >>> combination { 'one' : 1 , 'two' : 2 , 'three' : 3 , 'a' : 'A' , 'b' : 'B' , 'c' : 'C' } \u9700\u8981\u6ce8\u610f\u7684\u91cd\u8981\u4e00\u70b9\u662f\uff0c\u5982\u679c\u6211\u4eec\u5408\u5e76\u7684\u5b57\u5178\u5177\u6709\u91cd\u590d\u952e\u6216\u516c\u5171\u952e\uff0c\u5219\u6700\u53f3\u4fa7\u5b57\u5178\u7684\u503c\u5c06\u8986\u76d6\u6700\u5de6\u4fa7\u5b57\u5178\u7684\u503c\u3002\u4f8b\u5982: >>> letters = { 'a' : 'A' , 'b' : 'B' , 'c' : 'C' } >>> vowels = { 'a' : 'a' , 'e' : 'e' , 'i' : 'i' , 'o' : 'o' , 'u' : 'u' } >>> { ** letters , ** vowels } { 'a' : 'a' , 'b' : 'B' , 'c' : 'C' , 'e' : 'e' , 'i' : 'i' , 'o' : 'o' , 'u' : 'u' } >>> { ** vowels , ** letters } { 'a' : 'A' , 'e' : 'e' , 'i' : 'i' , 'o' : 'o' , 'u' : 'u' , 'b' : 'B' , 'c' : 'C' } \u901a\u8fc7 For-Loops \u89e3\u5305 \u00b6 \u6211\u4eec\u8fd8\u53ef\u4ee5\u5728 for \u5faa\u73af\u7684\u4e0a\u4e0b\u6587\u4e2d\u4f7f\u7528\u53ef\u8fed\u4ee3\u89e3\u5305\u3002 \u5f53\u6211\u4eec\u8fd0\u884c for \u5faa\u73af\u65f6\uff0c\u5728\u6bcf\u6b21\u5faa\u73af\u8fed\u4ee3\u4e2d\u5c06\u5176\u53ef\u8fed\u4ee3\u5bf9\u8c61\u4e2d\u7684\u4e00\u9879(item)\u5206\u914d\u7ed9\u76ee\u6807\u53d8\u91cf\u3002 \u5982\u679c\u8981\u5206\u914d\u7684\u9879(item)\u662f\u53ef\u8fed\u4ee3\u7684\uff0c\u90a3\u4e48\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u5143\u7ec4\u4f5c\u4e3a\u76ee\u6807\u53d8\u91cf\uff0c\u901a\u8fc7\u5faa\u73af\u5c06\u53ef\u8fed\u4ee3\u5bf9\u8c61\u89e3\u5305\u5230\u76ee\u6807\u53d8\u91cf\u7684\u5143\u7ec4\u4e2d\u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u6784\u5efa\u4e00\u4e2a\u5305\u542b\u4e24\u4e2a\u5143\u7d20\u7684\u5143\u7ec4\u7684\u5217\u8868\u3002 \u6bcf\u4e2a\u5143\u7ec4\u5c06\u5305\u542b\u4ea7\u54c1\u540d\u79f0\u3001\u4ef7\u683c\u548c\u9500\u552e\u5355\u4f4d\uff0c\u6211\u4eec\u901a\u8fc7 for \u5faa\u73af\u904d\u5386\u6bcf\u4e2a\u5143\u7ec4\u5143\u7d20\u6765\u8ba1\u7b97\u6bcf\u4e2a\u4ea7\u54c1\u7684\u6536\u5165\u3002 >>> sales = [( 'Pencle' , 0.22 , 1500 ), ( 'Notebook' , 1.30 , 550 ), ( 'Eraser' , 0.75 , 1000 )] >>> for items in sales : ... print ( f \"Income for { items [ 0 ] } is: { items [ 1 ] * items [ 2 ] } \" ) ... Income for Pencle is : 330.0 Income for Notebook is : 715.0 Income for Eraser is : 750.0 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u7d22\u5f15\u6765\u8bbf\u95ee\u6bcf\u4e2a\u5143\u7ec4\u7684\u5404\u4e2a\u5143\u7d20\u3002\u4e0b\u9762\u7684\u793a\u4f8b\u4ee3\u7801\u4e2d\uff0c\u5728 for \u5faa\u73af\u4f7f\u7528\u89e3\u5305\uff0c\u8fd9\u4e5f\u662f Python \u4e2d\u89e3\u5305\u7684\u4e00\u79cd\u5b9e\u73b0\u3002 >>> sales = [( 'Pencle' , 0.22 , 1500 ), ( 'Notebook' , 1.30 , 550 ), ( 'Eraser' , 0.75 , 1000 )] >>> for product , price , sold_units in sales : ... print ( f \"Income for { product } is: { price * sold_units } \" ) ... Income for Pencle is : 330.0 Income for Notebook is : 715.0 Income for Eraser is : 750.0 \u4e5f\u53ef\u4ee5\u5728 for \u5faa\u73af\u4e2d\u4f7f\u7528 * \u8fd0\u7b97\u7b26\u5c06\u591a\u4e2a\u9879\u6253\u5305\u5230\u5355\u4e2a\u76ee\u6807\u53d8\u91cf\u4e2d\u3002 \u5728\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u9996\u5148\u53d6\u5f97\u6bcf\u4e2a\u5e8f\u5217\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u3002 \u5176\u4f59\u503c\u901a\u8fc7 * \u8fd0\u7b97\u7b26\u8d4b\u7ed9\u76ee\u6807\u53d8\u91cf rest \u3002 >>> for first , * rest in [( 1 , 2 , 3 ),( 4 , 5 , 6 )]: ... print ( 'First: ' , first ) ... print ( 'Rest: ' , rest ) ... First : 1 Rest : [ 2 , 3 ] First : 4 Rest : [ 5 , 6 ] >>> \u76ee\u6807\u53d8\u91cf\u7684\u7ed3\u6784\u5fc5\u987b\u4e0e\u53ef\u8fed\u4ee3\u5bf9\u8c61\u7684\u7ed3\u6784\u4e00\u81f4\uff0c\u5426\u5219\u4f1a\u62a5\u9519\u3002\u770b\u4e0b\u9762\u7684\u4f8b\u5b50\u3002 >>> data = [(( 1 , 2 ), 3 ), (( 2 , 3 ), 3 )] >>> for ( a , b ), c in data : ... print ( a , b , c ) ... 1 2 3 2 3 3 >>> for a , b , c in data : ... print ( a , b , c ) ... Traceback ( most recent call last ): File \"\" , line 1 , in < module > ValueError : not enough values to unpack ( expected 3 , got 2 ) \u7528 * \u548c ** \u5b9a\u4e49\u51fd\u6570 \u00b6 \u4e0b\u9762\u4f8b\u5b50\u4e2d\u7684\u51fd\u6570func\u81f3\u5c11\u9700\u8981\u4e00\u4e2a\u540d\u4e3a required \u7684\u53c2\u6570\u3002 \u5b83\u4e5f\u53ef\u4ee5\u63a5\u53d7\u4e00\u4e2a\u6216\u591a\u4e2a\u4f4d\u7f6e\u53c2\u6570\u6216\u5173\u952e\u5b57\u53c2\u6570\u3002 \u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c * \u8fd0\u7b97\u7b26\u5728\u4e00\u4e2a\u53eb args \u7684\u5143\u7ec4\u4e2d\u6536\u96c6\u6216\u6253\u5305\u989d\u5916\u7684\u4f4d\u7f6e\u53c2\u6570\uff0c\u800c ** \u8fd0\u7b97\u7b26\u5728\u4e00\u4e2a\u53eb kwargs \u7684\u5b57\u5178\u4e2d\u6536\u96c6\u6216\u6253\u5305\u989d\u5916\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 args \u548c kwargs \u90fd\u662f\u53ef\u9009\u7684\uff0c\u5e76\u4e14\u5206\u522b\u81ea\u52a8\u9ed8\u8ba4\u4e3a\u5143\u7ec4 () \u548c\u5b57\u5178 {} \u3002 \u8fd9\u91cc args \u548c kwargs \u7684\u547d\u540d\u5e76\u4e0d\u662f\u5fc5\u987b\u7684\uff0c\u8bed\u6cd5\u4e0a\u53ea\u9700\u8981 * \u6216 ** \u540e\u8ddf\u6709\u6548\u6807\u8bc6\u7b26\u5373\u53ef\uff0c\u5efa\u8bae\u7ed9\u53d8\u91cf\u8d77\u4e2a\u6709\u610f\u4e49\u7684\u540d\u5b57\uff0c\u63d0\u9ad8\u4ee3\u7801\u7684\u53ef\u8bfb\u6027\u3002 >>> def func ( required , * args , ** kwargs ): ... print ( required ) ... print ( args ) ... print ( kwargs ) ... >>> func ( 'Welcome to ...' , 1 , 2 , 3 , site = 'CloudAcademy.com' ) Welcome to ... ( 1 , 2 , 3 ) { 'site' : 'CloudAcademy.com' } >>> func ( 'Welcome to ...' , 1 , 2 , 3 , 4 ) Welcome to ... ( 1 , 2 , 3 , 4 ) {} >>> func ( 'Welcome to ...' , 1 , 2 , 3 , ( 1 , 2 )) Welcome to ... ( 1 , 2 , 3 , ( 1 , 2 )) {} >>> func ( 'Welcome to ...' , 1 , 2 , 3 , [ 1 , 2 ]) Welcome to ... ( 1 , 2 , 3 , [ 1 , 2 ]) {} >>> func ( 'Welcome to ...' , 1 , 2 , 3 , ([ 2 , 3 ], [ 1 , 2 ])) Welcome to ... ( 1 , 2 , 3 , ([ 2 , 3 ], [ 1 , 2 ])) {} \u4f7f\u7528 * \u548c ** \u8c03\u7528\u51fd\u6570 \u00b6 \u8c03\u7528\u51fd\u6570\u65f6\uff0c\u6211\u4eec\u8fd8\u53ef\u4ee5\u53d7\u76ca\u4e8e\u4f7f\u7528 * \u548c ** \u8fd0\u7b97\u7b26\u5c06\u53c2\u6570\u96c6\u5408\u5206\u522b\u89e3\u538b\u7f29\u4e3a\u5355\u72ec\u7684\u4f4d\u7f6e\u53c2\u6570\u6216\u5173\u952e\u5b57\u53c2\u6570\u3002 \u8fd9\u4e0e\u5728\u51fd\u6570\u7b7e\u540d(signature of a function)\u4e2d\u4f7f\u7528 * \u548c ** \u662f\u76f8\u53cd\u7684\u3002 \u5728\u51fd\u6570\u7b7e\u540d\u4e2d\uff0c\u8fd0\u7b97\u7b26\u7684\u610f\u601d\u662f\u5728\u4e00\u4e2a\u6807\u8bc6\u7b26\u4e2d\u6536\u96c6\u6216\u6253\u5305\u53ef\u53d8\u6570\u91cf\u7684\u53c2\u6570\u3002 \u5728\u8c03\u7528(calling)\u4e2d\uff0c\u5b83\u4eec\u7684\u610f\u601d\u662f\u89e3\u5305(unpack)\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u5230\u591a\u4e2a\u53c2\u6570\u4e2d\u3002 \u7eed\u4e0a\u4f8b\uff0c * \u8fd0\u7b97\u7b26\u5c06\u50cf [\"Welcome\", \"to\"] \u8fd9\u6837\u7684\u5e8f\u5217\u89e3\u5305\u5230\u4f4d\u7f6e\u53c2\u6570\u4e2d\u3002 \u7c7b\u4f3c\u5730\uff0c ** \u8fd0\u7b97\u7b26\u5c06\u5b57\u5178\u89e3\u5305\u4e3a\u4e0e\u5b57\u5178\u7684\u952e\u503c\u5339\u914d\u7684\u53c2\u6570\u540d\u3002 >>> def func ( welcome , to , site ): ... print ( welcome , to , site ) ... >>> func ( * [ 'Welcome' , 'to' ], ** { 'site' : 'CloudAcademy.com' }) Welcome to CloudAcademy . com \u7efc\u5408\u8fd0\u7528\u524d\u9762\u7684\u65b9\u6cd5\u6765\u7f16\u5199\u975e\u5e38\u7075\u6d3b\u7684\u51fd\u6570\uff0c\u6bd4\u5982\uff0c\u5728\u5b9a\u4e49\u548c\u8c03\u7528 Python \u51fd\u6570\u65f6\uff0c\u66f4\u7075\u6d3b\u7684\u4f7f\u7528 * \u548c ** \u8fd0\u7b97\u7b26\u3002 \u4f8b\u5982\uff1a >>> def func ( required , * args , ** kwargs ): ... print ( required ) ... print ( args ) ... print ( kwargs ) ... >>> func ( 'Welcome to...' , * ( 1 , 2 , 3 ), ** { 'Site' : 'CloudAcademy.com' }) Welcome to ... ( 1 , 2 , 3 ) { 'Site' : 'CloudAcademy.com' } \u603b\u7ed3 \u00b6 \u53ef\u8fed\u4ee3\u89e3\u5305\uff08iterable unpacking\uff09\u8fd9\u4e2a\u7279\u6027\u5141\u8bb8\u6211\u4eec\u5c06\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u89e3\u5305\u6210\u51e0\u4e2a\u53d8\u91cf\u3002 \u53e6\u4e00\u65b9\u9762\uff0c\u6253\u5305\u5305\u62ec\u4f7f\u7528\u89e3\u5305\u8fd0\u7b97\u7b26 * \u5c06\u591a\u4e2a\u503c\u8d4b\u5230\u4e00\u4e2a\u53d8\u91cf\u4e2d\u3002 \u53ef\u8fed\u4ee3\u89e3\u5305\uff08iterable unpacking\uff09\u4e5f\u53ef\u4ee5\u7528\u6765\u8fdb\u884c\u5e76\u884c\u8d4b\u503c\u548c\u53d8\u91cf\u4e4b\u95f4\u7684\u503c\u4ea4\u6362\uff0c\u4e5f\u53ef\u4ee5\u7528\u5728 for \u5faa\u73af\u3001\u51fd\u6570\u8c03\u7528\u548c\u51fd\u6570\u5b9a\u4e49\u4e2d\u3002","title":"Python\u6253\u5305\u548c\u89e3\u5305"},{"location":"python/Foundation/ch02/#python","text":"","title":"Python\u6253\u5305\u548c\u89e3\u5305"},{"location":"python/Foundation/ch02/#unpacking","text":"Python \u5141\u8bb8\u53d8\u91cf\u7684\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\u51fa\u73b0\u5728\u8d4b\u503c\u64cd\u4f5c\u7684\u5de6\u4fa7\u3002 \u5143\u7ec4\u4e2d\u7684\u6bcf\u4e2a\u53d8\u91cf\u90fd\u53ef\u4ee5\u4ece\u8d4b\u503c\u53f3\u4fa7\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08iterable\uff09\u4e2d\u63a5\u6536\u4e00\u4e2a\u503c\uff08\u6216\u8005\u66f4\u591a\uff0c\u5982\u679c\u6211\u4eec\u4f7f\u7528 * \u8fd0\u7b97\u7b26\uff09\u3002 Python \u4e2d\u7684\u89e3\u5305\u662f\u6307\u4e00\u79cd\u64cd\u4f5c\uff0c\u8be5\u64cd\u4f5c\u5305\u62ec\u5728\u5355\u4e2a\u8d4b\u503c\u8bed\u53e5\u4e2d\u5c06\u53ef\u8fed\u4ee3\u7684\u503c\u5206\u914d\u7ed9\u53d8\u91cf\u7684\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\u3002 \u5728 Python \u4e2d\uff0c\u53ef\u4ee5\u5728\u8d4b\u503c\u8fd0\u7b97\u7b26 = \u7684\u5de6\u4fa7\u653e\u7f6e\u4e00\u4e2a\u53d8\u91cf\u5143\u7ec4\uff0c\u5728\u53f3\u4fa7\u653e\u7f6e\u4e00\u4e2a\u503c\u5143\u7ec4\u3002 \u53f3\u8fb9\u7684\u503c\u5c06\u6839\u636e\u5b83\u4eec\u5728\u5143\u7ec4\u4e2d\u7684\u4f4d\u7f6e\u81ea\u52a8\u5206\u914d\u7ed9\u5de6\u8fb9\u7684\u53d8\u91cf\u3002 \u8fd9\u5728 Python \u4e2d\u901a\u5e38\u79f0\u4e3a\u5143\u7ec4\u89e3\u5305\u3002 \u5982\u4e0b\u793a\u4f8b\uff1a >>> ( a , b , c ) = ( 1 , 2 , 3 ) >>> a 1 >>> b 2 >>> c 3 >>> birthday = ( 'April' , 5 , 2001 ) >>> month , day , year = birthday >>> month 'April' >>> day 5 >>> year 2001 \u5143\u7ec4\u89e3\u5305\u529f\u80fd\u5728 Python \u4e2d\u53ef\u4ee5\u6269\u5c55\u4e3a\u9002\u7528\u4e8e\u4efb\u4f55\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 \u552f\u4e00\u7684\u8981\u6c42\u662f\u53ef\u8fed\u4ee3\u7684\u63a5\u6536\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\u4e2d\u7684\u6bcf\u4e2a\u53d8\u91cf\u6070\u597d\u5bf9\u5e94\u53ef\u8fed\u4ee3\u5bf9\u8c61\u7684\u4e00\u4e2a\u5143\u7d20\uff08item\uff09\u3002 \u4e0b\u9762\u7684\u793a\u4f8b\u4ecb\u7ecd\u4e86 Python \u4e2d\u53ef\u8fed\u4ee3\u89e3\u5305\u7684\u5de5\u4f5c\u539f\u7406\uff1a >>> # Unpackage strings >>> a , b , c = '123' >>> a '1' >>> b '2' >>> c '3' >>> # Unpacking lists >>> a , b , c = [ 1 , 2 , 3 ] >>> a 1 >>> b 2 >>> c 3 >>> # Unpacking generators >>> gen = ( i ** 2 for i in range ( 3 )) >>> a , b , c = gen >>> a 0 >>> b 1 >>> c 4 >>> # Upacking dictionaries (keys, values, and items) >>> my_dict = { 'one' : 1 , 'two' : 2 , 'three' : 3 } >>> a , b , c = my_dict >>> a 'one' >>> b 'two' >>> c 'three' >>> a , b , c = my_dict . values () >>> a 1 >>> b 2 >>> c 3 >>> a , b , c = my_dict . items () >>> a ( 'one' , 1 ) >>> b ( 'two' , 2 ) >>> c ( 'three' , 3 ) >>> # Use a tuple on the right side of assignment statement >>> [ a , b , c ] = 1 , 2 , 3 >>> a 1 >>> b 2 >>> c 3 >>> # Use range() iterator >>> x , y , z = range ( 3 ) >>> x 0 >>> y 1 >>> z 2","title":"\u89e3\u5305Unpacking"},{"location":"python/Foundation/ch02/#packing","text":"\u6253\u5305\u53ef\u4ee5\u7406\u89e3\u4e3a\u4f7f\u7528\u53ef\u8fed\u4ee3\u89e3\u5305\u8fd0\u7b97\u7b26\u5728\u5355\u4e2a\u53d8\u91cf\u4e2d\u6536\u96c6\u591a\u4e2a\u503c\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c * \u8fd0\u7b97\u7b26\u88ab\u79f0\u4e3a\u5143\u7ec4\uff08\u6216\u53ef\u8fed\u4ee3\uff09\u89e3\u5305\u8fd0\u7b97\u7b26\u3002 \u5b83\u6269\u5c55\u4e86\u89e3\u5305\u529f\u80fd\uff0c\u5141\u8bb8\u5728\u5355\u4e2a\u53d8\u91cf\u4e2d\u6536\u96c6\u6216\u6253\u5305\u591a\u4e2a\u503c\u3002 \u5728\u4ee5\u4e0b\u793a\u4f8b\u4e2d\u53ef\u4ee5\u770b\u5230 * \u8fd0\u7b97\u7b26\u5c06\u5143\u7ec4\u503c\u6253\u5305\u5230\u5355\u4e2a\u53d8\u91cf\u4e2d\uff1a >>> # The right side is a tuple, the left side is a list >>> * a , = 1 , 2 >>> a [ 1 , 2 ] >>> type ( a ) < class ' list '> \u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\uff0c\u8d4b\u503c\u7684\u5de6\u4fa7\u5fc5\u987b\u662f\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\uff0c\u8fd9\u5c31\u662f\u4f7f\u7528\u5c3e\u968f\u9017\u53f7\u7684\u539f\u56e0\u3002\u8fd9\u4e2a\u5143\u7ec4\u53ef\u4ee5\u5305\u542b\u6240\u9700\u8981\u7684\u5c3d\u53ef\u80fd\u591a\u7684\u53d8\u91cf\uff0c\u4f46\u662f\uff0c\u5b83\u53ea\u80fd\u5305\u542b\u4e00\u4e2a\u661f\u53f7\u8868\u8fbe\u5f0f(starred expression)\u3002 >>> # Packing trailing values >>> a , * b = 1 , 2 , 3 >>> a 1 >>> b [ 2 , 3 ] >>> type ( a ) < class ' int '> >>> type ( b ) < class ' list '> >>> >>> * a , b , c = 1 , 2 , 3 >>> a [ 1 ] >>> b 2 >>> c 3 >>> * a , b , c , d , e = 1 , 2 , 3 Traceback ( most recent call last ): File \"\" , line 1 , in < module > ValueError : not enough values to unpack ( expected at least 4 , got 3 ) >>> * a , b , c , d = 1 , 2 , 3 >>> a [] >>> b 1 >>> c 2 >>> d 3 >>> >>> seq = [ 1 , 2 , 3 , 4 ] >>> first , * body , last = seq >>> first , body , last ( 1 , [ 2 , 3 ], 4 ) >>> first , body , * last = seq >>> first , body , last ( 1 , 2 , [ 3 , 4 ]) >>> >>> ran = range ( 10 ) >>> * r , = ran >>> r [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] \u4e0b\u9762\u662f\u4e00\u4e9b\u6253\u5305\u548c\u89e3\u5305\u7684\u4f8b\u5b50\u3002 >>> employee = [ 'John Doe' , '40' , 'Software Engineer' ] >>> name = employee [ 0 ] >>> age = employee [ 1 ] >>> job = employee [ 2 ] >>> name 'John Doe' >>> age '40' >>> job 'Software Engineer' >>> >>> name , age , job = [ 'John Doe' , '40' , 'Software Engineer' ] >>> name 'John Doe' >>> age '40' >>> job 'Software Engineer' >>> >>> a = 100 >>> b = 200 >>> a , b = b , a >>> a 200 >>> b 100 \u4f7f\u7528 * \u5220\u9664\u4e0d\u9700\u8981\u7684\u503c\u3002 >>> a , b , * _ = 1 , 2 , 0 , 0 , 0 , 0 >>> a 1 >>> b 2 >>> _ [ 0 , 0 , 0 , 0 ] \u5728\u4e0a\u4f8b\u4e2d\uff0c\u4e0d\u9700\u8981\u7684\u4fe1\u606f\u5b58\u50a8\u5728\u865a\u62df\u53d8\u91cf _ \u4e2d\uff0c\u5728\u540e\u7eed\u7684\u4f7f\u7528\u4e2d\u53ef\u4ee5\u5ffd\u7565\u5b83\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cPython \u89e3\u91ca\u5668\u4f7f\u7528\u4e0b\u5212\u7ebf\u5b57\u7b26 _ \u6765\u5b58\u50a8\u5728\u4ea4\u4e92\u5f0f\u4f1a\u8bdd\u4e2d\u8fd0\u884c\u7684\u8bed\u53e5\u7684\u7ed3\u679c\u503c\u3002 \u56e0\u6b64\uff0c\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528\u8fd9\u4e2a\u5b57\u7b26\u6765\u8bc6\u522b\u865a\u62df\u53d8\u91cf\u53ef\u80fd\u662f\u6a21\u68f1\u4e24\u53ef\u7684\u3002 \u5728\u51fd\u6570\u4e2d\u8fd4\u56de\u5143\u7ec4\u3002 >>> def powers ( num ): ... return num , num ** 2 , num ** 3 ... >>> # Packaging returned values in a tuple >>> result = powers ( 3 ) >>> result ( 3 , 9 , 27 ) >>> # Unpacking returned values to multiple variables >>> number , square , cube = powers ( 3 ) >>> number 3 >>> square 9 >>> cube 27 >>> * _ , cube = powers ( 3 ) >>> cube 27","title":"\u6253\u5305Packing"},{"location":"python/Foundation/ch02/#_1","text":"\u4f7f\u7528 * \u8fd0\u7b97\u7b26\u5408\u5e76\u8fed\u4ee3\u53d8\u91cf\uff08iterables\uff09\u3002\u4e0a\u9762\u4e24\u4e2a\u4f8b\u5b50\u8bf4\u660e\uff0c\u8fd9\u4e2d\u65b9\u6cd5\u4e5f\u662f\u8fde\u63a5\u8fed\u4ee3\u53d8\u91cf\uff08iterables\uff09\u7684\u4e00\u79cd\u66f4\u6613\u8bfb\u548c\u66f4\u6709\u6548\u7684\u65b9\u6cd5\u3002 \u8fd9\u4e2a\u65b9\u6cd5 (my_set) + my_list + list(my_tuple) + list(range(1, 4)) + list(my_str) \u53ef\u4ee5\u751f\u6210\u4e00\u4e2a\u5217\u8868 \uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u66f4\u7b80\u6d01\u7684\u65b9\u6cd5 [*my_set, *my_list, *my_tuple, *range(1, 4), *my_str] \u3002 >>> my_tuple = ( 1 , 2 , 3 ) >>> ( 0 , * my_tuple , 4 ) ( 0 , 1 , 2 , 3 , 4 ) >>> my_list = [ 1 , 2 , 3 ] >>> [ 0 , * my_list , 4 ] [ 0 , 1 , 2 , 3 , 4 ] >>> my_set = { 1 , 2 , 3 } >>> { 0 , * my_set , 4 } { 0 , 1 , 2 , 3 , 4 } >>> [ * my_set , * my_list , * my_tuple , * range ( 1 , 4 )] [ 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 ] >>> my_str = \"123\" >>> [ * my_set , * my_list , * my_tuple , * range ( 1 , 4 ), * my_str ] [ 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 , '1' , '2' , '3' ] \u4f7f\u7528 ** \u8fd0\u7b97\u7b26\u89e3\u5305\u5b57\u5178\u3002 >>> numbers = { 'one' : 1 , 'two' : 2 , 'three' : 3 } >>> letters = { 'a' : 'A' , 'b' : 'B' , 'c' : 'C' } >>> combination = { ** numbers , ** letters } >>> combination { 'one' : 1 , 'two' : 2 , 'three' : 3 , 'a' : 'A' , 'b' : 'B' , 'c' : 'C' } \u9700\u8981\u6ce8\u610f\u7684\u91cd\u8981\u4e00\u70b9\u662f\uff0c\u5982\u679c\u6211\u4eec\u5408\u5e76\u7684\u5b57\u5178\u5177\u6709\u91cd\u590d\u952e\u6216\u516c\u5171\u952e\uff0c\u5219\u6700\u53f3\u4fa7\u5b57\u5178\u7684\u503c\u5c06\u8986\u76d6\u6700\u5de6\u4fa7\u5b57\u5178\u7684\u503c\u3002\u4f8b\u5982: >>> letters = { 'a' : 'A' , 'b' : 'B' , 'c' : 'C' } >>> vowels = { 'a' : 'a' , 'e' : 'e' , 'i' : 'i' , 'o' : 'o' , 'u' : 'u' } >>> { ** letters , ** vowels } { 'a' : 'a' , 'b' : 'B' , 'c' : 'C' , 'e' : 'e' , 'i' : 'i' , 'o' : 'o' , 'u' : 'u' } >>> { ** vowels , ** letters } { 'a' : 'A' , 'e' : 'e' , 'i' : 'i' , 'o' : 'o' , 'u' : 'u' , 'b' : 'B' , 'c' : 'C' }","title":"\u4f7f\u7528*\u548c**\u8fd0\u7b97\u7b26"},{"location":"python/Foundation/ch02/#for-loops","text":"\u6211\u4eec\u8fd8\u53ef\u4ee5\u5728 for \u5faa\u73af\u7684\u4e0a\u4e0b\u6587\u4e2d\u4f7f\u7528\u53ef\u8fed\u4ee3\u89e3\u5305\u3002 \u5f53\u6211\u4eec\u8fd0\u884c for \u5faa\u73af\u65f6\uff0c\u5728\u6bcf\u6b21\u5faa\u73af\u8fed\u4ee3\u4e2d\u5c06\u5176\u53ef\u8fed\u4ee3\u5bf9\u8c61\u4e2d\u7684\u4e00\u9879(item)\u5206\u914d\u7ed9\u76ee\u6807\u53d8\u91cf\u3002 \u5982\u679c\u8981\u5206\u914d\u7684\u9879(item)\u662f\u53ef\u8fed\u4ee3\u7684\uff0c\u90a3\u4e48\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u5143\u7ec4\u4f5c\u4e3a\u76ee\u6807\u53d8\u91cf\uff0c\u901a\u8fc7\u5faa\u73af\u5c06\u53ef\u8fed\u4ee3\u5bf9\u8c61\u89e3\u5305\u5230\u76ee\u6807\u53d8\u91cf\u7684\u5143\u7ec4\u4e2d\u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u6784\u5efa\u4e00\u4e2a\u5305\u542b\u4e24\u4e2a\u5143\u7d20\u7684\u5143\u7ec4\u7684\u5217\u8868\u3002 \u6bcf\u4e2a\u5143\u7ec4\u5c06\u5305\u542b\u4ea7\u54c1\u540d\u79f0\u3001\u4ef7\u683c\u548c\u9500\u552e\u5355\u4f4d\uff0c\u6211\u4eec\u901a\u8fc7 for \u5faa\u73af\u904d\u5386\u6bcf\u4e2a\u5143\u7ec4\u5143\u7d20\u6765\u8ba1\u7b97\u6bcf\u4e2a\u4ea7\u54c1\u7684\u6536\u5165\u3002 >>> sales = [( 'Pencle' , 0.22 , 1500 ), ( 'Notebook' , 1.30 , 550 ), ( 'Eraser' , 0.75 , 1000 )] >>> for items in sales : ... print ( f \"Income for { items [ 0 ] } is: { items [ 1 ] * items [ 2 ] } \" ) ... Income for Pencle is : 330.0 Income for Notebook is : 715.0 Income for Eraser is : 750.0 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u7d22\u5f15\u6765\u8bbf\u95ee\u6bcf\u4e2a\u5143\u7ec4\u7684\u5404\u4e2a\u5143\u7d20\u3002\u4e0b\u9762\u7684\u793a\u4f8b\u4ee3\u7801\u4e2d\uff0c\u5728 for \u5faa\u73af\u4f7f\u7528\u89e3\u5305\uff0c\u8fd9\u4e5f\u662f Python \u4e2d\u89e3\u5305\u7684\u4e00\u79cd\u5b9e\u73b0\u3002 >>> sales = [( 'Pencle' , 0.22 , 1500 ), ( 'Notebook' , 1.30 , 550 ), ( 'Eraser' , 0.75 , 1000 )] >>> for product , price , sold_units in sales : ... print ( f \"Income for { product } is: { price * sold_units } \" ) ... Income for Pencle is : 330.0 Income for Notebook is : 715.0 Income for Eraser is : 750.0 \u4e5f\u53ef\u4ee5\u5728 for \u5faa\u73af\u4e2d\u4f7f\u7528 * \u8fd0\u7b97\u7b26\u5c06\u591a\u4e2a\u9879\u6253\u5305\u5230\u5355\u4e2a\u76ee\u6807\u53d8\u91cf\u4e2d\u3002 \u5728\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u9996\u5148\u53d6\u5f97\u6bcf\u4e2a\u5e8f\u5217\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u3002 \u5176\u4f59\u503c\u901a\u8fc7 * \u8fd0\u7b97\u7b26\u8d4b\u7ed9\u76ee\u6807\u53d8\u91cf rest \u3002 >>> for first , * rest in [( 1 , 2 , 3 ),( 4 , 5 , 6 )]: ... print ( 'First: ' , first ) ... print ( 'Rest: ' , rest ) ... First : 1 Rest : [ 2 , 3 ] First : 4 Rest : [ 5 , 6 ] >>> \u76ee\u6807\u53d8\u91cf\u7684\u7ed3\u6784\u5fc5\u987b\u4e0e\u53ef\u8fed\u4ee3\u5bf9\u8c61\u7684\u7ed3\u6784\u4e00\u81f4\uff0c\u5426\u5219\u4f1a\u62a5\u9519\u3002\u770b\u4e0b\u9762\u7684\u4f8b\u5b50\u3002 >>> data = [(( 1 , 2 ), 3 ), (( 2 , 3 ), 3 )] >>> for ( a , b ), c in data : ... print ( a , b , c ) ... 1 2 3 2 3 3 >>> for a , b , c in data : ... print ( a , b , c ) ... Traceback ( most recent call last ): File \"\" , line 1 , in < module > ValueError : not enough values to unpack ( expected 3 , got 2 )","title":"\u901a\u8fc7 For-Loops \u89e3\u5305"},{"location":"python/Foundation/ch02/#_2","text":"\u4e0b\u9762\u4f8b\u5b50\u4e2d\u7684\u51fd\u6570func\u81f3\u5c11\u9700\u8981\u4e00\u4e2a\u540d\u4e3a required \u7684\u53c2\u6570\u3002 \u5b83\u4e5f\u53ef\u4ee5\u63a5\u53d7\u4e00\u4e2a\u6216\u591a\u4e2a\u4f4d\u7f6e\u53c2\u6570\u6216\u5173\u952e\u5b57\u53c2\u6570\u3002 \u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c * \u8fd0\u7b97\u7b26\u5728\u4e00\u4e2a\u53eb args \u7684\u5143\u7ec4\u4e2d\u6536\u96c6\u6216\u6253\u5305\u989d\u5916\u7684\u4f4d\u7f6e\u53c2\u6570\uff0c\u800c ** \u8fd0\u7b97\u7b26\u5728\u4e00\u4e2a\u53eb kwargs \u7684\u5b57\u5178\u4e2d\u6536\u96c6\u6216\u6253\u5305\u989d\u5916\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 args \u548c kwargs \u90fd\u662f\u53ef\u9009\u7684\uff0c\u5e76\u4e14\u5206\u522b\u81ea\u52a8\u9ed8\u8ba4\u4e3a\u5143\u7ec4 () \u548c\u5b57\u5178 {} \u3002 \u8fd9\u91cc args \u548c kwargs \u7684\u547d\u540d\u5e76\u4e0d\u662f\u5fc5\u987b\u7684\uff0c\u8bed\u6cd5\u4e0a\u53ea\u9700\u8981 * \u6216 ** \u540e\u8ddf\u6709\u6548\u6807\u8bc6\u7b26\u5373\u53ef\uff0c\u5efa\u8bae\u7ed9\u53d8\u91cf\u8d77\u4e2a\u6709\u610f\u4e49\u7684\u540d\u5b57\uff0c\u63d0\u9ad8\u4ee3\u7801\u7684\u53ef\u8bfb\u6027\u3002 >>> def func ( required , * args , ** kwargs ): ... print ( required ) ... print ( args ) ... print ( kwargs ) ... >>> func ( 'Welcome to ...' , 1 , 2 , 3 , site = 'CloudAcademy.com' ) Welcome to ... ( 1 , 2 , 3 ) { 'site' : 'CloudAcademy.com' } >>> func ( 'Welcome to ...' , 1 , 2 , 3 , 4 ) Welcome to ... ( 1 , 2 , 3 , 4 ) {} >>> func ( 'Welcome to ...' , 1 , 2 , 3 , ( 1 , 2 )) Welcome to ... ( 1 , 2 , 3 , ( 1 , 2 )) {} >>> func ( 'Welcome to ...' , 1 , 2 , 3 , [ 1 , 2 ]) Welcome to ... ( 1 , 2 , 3 , [ 1 , 2 ]) {} >>> func ( 'Welcome to ...' , 1 , 2 , 3 , ([ 2 , 3 ], [ 1 , 2 ])) Welcome to ... ( 1 , 2 , 3 , ([ 2 , 3 ], [ 1 , 2 ])) {}","title":"\u7528*\u548c**\u5b9a\u4e49\u51fd\u6570"},{"location":"python/Foundation/ch02/#_3","text":"\u8c03\u7528\u51fd\u6570\u65f6\uff0c\u6211\u4eec\u8fd8\u53ef\u4ee5\u53d7\u76ca\u4e8e\u4f7f\u7528 * \u548c ** \u8fd0\u7b97\u7b26\u5c06\u53c2\u6570\u96c6\u5408\u5206\u522b\u89e3\u538b\u7f29\u4e3a\u5355\u72ec\u7684\u4f4d\u7f6e\u53c2\u6570\u6216\u5173\u952e\u5b57\u53c2\u6570\u3002 \u8fd9\u4e0e\u5728\u51fd\u6570\u7b7e\u540d(signature of a function)\u4e2d\u4f7f\u7528 * \u548c ** \u662f\u76f8\u53cd\u7684\u3002 \u5728\u51fd\u6570\u7b7e\u540d\u4e2d\uff0c\u8fd0\u7b97\u7b26\u7684\u610f\u601d\u662f\u5728\u4e00\u4e2a\u6807\u8bc6\u7b26\u4e2d\u6536\u96c6\u6216\u6253\u5305\u53ef\u53d8\u6570\u91cf\u7684\u53c2\u6570\u3002 \u5728\u8c03\u7528(calling)\u4e2d\uff0c\u5b83\u4eec\u7684\u610f\u601d\u662f\u89e3\u5305(unpack)\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u5230\u591a\u4e2a\u53c2\u6570\u4e2d\u3002 \u7eed\u4e0a\u4f8b\uff0c * \u8fd0\u7b97\u7b26\u5c06\u50cf [\"Welcome\", \"to\"] \u8fd9\u6837\u7684\u5e8f\u5217\u89e3\u5305\u5230\u4f4d\u7f6e\u53c2\u6570\u4e2d\u3002 \u7c7b\u4f3c\u5730\uff0c ** \u8fd0\u7b97\u7b26\u5c06\u5b57\u5178\u89e3\u5305\u4e3a\u4e0e\u5b57\u5178\u7684\u952e\u503c\u5339\u914d\u7684\u53c2\u6570\u540d\u3002 >>> def func ( welcome , to , site ): ... print ( welcome , to , site ) ... >>> func ( * [ 'Welcome' , 'to' ], ** { 'site' : 'CloudAcademy.com' }) Welcome to CloudAcademy . com \u7efc\u5408\u8fd0\u7528\u524d\u9762\u7684\u65b9\u6cd5\u6765\u7f16\u5199\u975e\u5e38\u7075\u6d3b\u7684\u51fd\u6570\uff0c\u6bd4\u5982\uff0c\u5728\u5b9a\u4e49\u548c\u8c03\u7528 Python \u51fd\u6570\u65f6\uff0c\u66f4\u7075\u6d3b\u7684\u4f7f\u7528 * \u548c ** \u8fd0\u7b97\u7b26\u3002 \u4f8b\u5982\uff1a >>> def func ( required , * args , ** kwargs ): ... print ( required ) ... print ( args ) ... print ( kwargs ) ... >>> func ( 'Welcome to...' , * ( 1 , 2 , 3 ), ** { 'Site' : 'CloudAcademy.com' }) Welcome to ... ( 1 , 2 , 3 ) { 'Site' : 'CloudAcademy.com' }","title":"\u4f7f\u7528*\u548c**\u8c03\u7528\u51fd\u6570"},{"location":"python/Foundation/ch02/#_4","text":"\u53ef\u8fed\u4ee3\u89e3\u5305\uff08iterable unpacking\uff09\u8fd9\u4e2a\u7279\u6027\u5141\u8bb8\u6211\u4eec\u5c06\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u89e3\u5305\u6210\u51e0\u4e2a\u53d8\u91cf\u3002 \u53e6\u4e00\u65b9\u9762\uff0c\u6253\u5305\u5305\u62ec\u4f7f\u7528\u89e3\u5305\u8fd0\u7b97\u7b26 * \u5c06\u591a\u4e2a\u503c\u8d4b\u5230\u4e00\u4e2a\u53d8\u91cf\u4e2d\u3002 \u53ef\u8fed\u4ee3\u89e3\u5305\uff08iterable unpacking\uff09\u4e5f\u53ef\u4ee5\u7528\u6765\u8fdb\u884c\u5e76\u884c\u8d4b\u503c\u548c\u53d8\u91cf\u4e4b\u95f4\u7684\u503c\u4ea4\u6362\uff0c\u4e5f\u53ef\u4ee5\u7528\u5728 for \u5faa\u73af\u3001\u51fd\u6570\u8c03\u7528\u548c\u51fd\u6570\u5b9a\u4e49\u4e2d\u3002","title":"\u603b\u7ed3"},{"location":"python/Foundation/ch03/","text":"Python\u5185\u7f6e\u51fd\u6570\u53ca\u6587\u4ef6 \u00b6 1. \u533f\u540d\uff08Lambda\uff09\u51fd\u6570 \u00b6 \u533f\u540d\u51fd\u6570\u662f\u4e00\u79cd\u901a\u8fc7\u5355\u4e2a\u8bed\u53e5\u751f\u6210\u51fd\u6570\u7684\u65b9\u5f0f\uff0c\u5176\u7ed3\u679c\u662f\u8fd4\u56de\u503c\u3002\u533f\u540d\u51fd\u6570\u4f7f\u7528lambda\u5173\u952e\u5b57\u5b9a\u4e49\uff0c\u8be5\u5173\u952e\u5b57\u4ec5\u8868\u8fbe\u201c\u6211\u4eec\u58f0\u660e\u4e00\u4e2a\u533f\u540d\u51fd\u6570\u201d\u7684\u610f\u601d\u3002 lambda \u51fd\u6570\u53ef\u4ee5\u63a5\u6536\u4efb\u610f\u591a\u4e2a\u53c2\u6570 (\u5305\u62ec\u53ef\u9009\u53c2\u6570) \u5e76\u4e14\u8fd4\u56de\u5355\u4e2a\u8868\u8fbe\u5f0f\u7684\u503c\u3002 \u8bed\u6cd5\u683c\u5f0f\uff1a lambda arg1,arg2,arg3\u2026 :<\u8868\u8fbe\u5f0f> f = lambda x , y : x * y print ( f ( 2 , 3 )) # 6 f = [ lambda a : a * 2 , lambda b : b * 3 ] print ( f [ 0 ]( 5 )) # \u6267\u884cf\u5217\u8868\u7b2c\u4e00\u4e2a\u5143\u7d20 # 10 print ( f [ 1 ]( 5 )) # \u6267\u884cf\u5143\u7d20\u7b2c\u4e8c\u4e2a\u5143\u7d20 # 15 print ( f [ 0 , 1 ]( 5 , 5 )) # TypeError: list indices must be integers or slices, not tuple \u793a\u4f8b1\uff1a def short_func1 ( x ): return x * 2 short_func2 = lambda x : x * 2 print ( short_func1 ( 5 )) # 10 print ( short_func2 ( 5 )) # 10 \u793a\u4f8b2\uff1a def apply_to_list ( some_list , f ): return [ f ( x ) for x in some_list ] ints = [ 4 , 0 , 1 , 5 , 6 ] result5 = apply_to_list ( ints , lambda x : x * 2 ) print ( result5 ) # [8, 0, 2, 10, 12] lambda: None \u51fd\u6570\u6ca1\u6709\u8f93\u5165\u53c2\u6570\uff0c\u8f93\u51fa\u662fNone\u3002 print ( lambda : None ) # at 0x7fa5c4097670> lambda **kwargs: 1 \u8f93\u5165\u662f\u4efb\u610f\u952e\u503c\u5bf9\u53c2\u6570\uff0c\u8f93\u51fa\u662f1\u3002 print ( lambda ** kwargs : 1 ) # at 0x7fa5c4097670> 2. \u5185\u7f6e\u5e8f\u5217\u51fd\u6570enumerate \u00b6 \u5f53\u9700\u8981\u5bf9\u6570\u636e\u5efa\u7acb\u7d22\u5f15\u65f6\uff0c\u4e00\u79cd\u6709\u6548\u7684\u6a21\u5f0f\u5c31\u662f\u4f7f\u7528enumerate\u6784\u9020\u4e00\u4e2a\u5b57\u5178\uff0c\u5c06\u5e8f\u5217\u503c\uff08\u5047\u8bbe\u662f\u552f\u4e00\u7684\uff09\u6620\u5c04\u5230\u7d22\u5f15\u4f4d\u7f6e\u4e0a\u3002 seasons = [ 'Spring' , 'Summer' , 'Fall' , 'Winter' ] print ( list ( enumerate ( seasons ))) # [(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')] \u5bf9\u6bd4\u4e0b\u97622\u4e2a\u5faa\u73af a_list = [ 'foo' , 'bar' , 'baz' ] mapping = {} for i , v in enumerate ( a_list ): # enumerate\u751f\u6210\u7d22\u5f15\u503ci\u548c\u5e8f\u5217\u503cv mapping [ v ] = i print ( mapping ) # {'foo': 0, 'bar': 1, 'baz': 2} i = 0 mapping = {} for v in a_list : print ( i , a_list [ i ]) mapping [ v ] = i # \u53ef\u4ee5\u628ai\u548cv\u4e92\u6362 i += 1 print ( mapping ) # {'foo': 0, 'bar': 1, 'baz': 2} \u5229\u7528 enumerate() \u6279\u91cf\u4fee\u6539\u5217\u8868\u5185\u7684\u5143\u7d20 a_list = [ '01' , '02' , '03' ] unit_element = '1' for i , element in enumerate ( a_list ): a_list [ i ] = unit_element + element print ( a_list ) # ['101', '102', '103'] sorted\u51fd\u6570\u8fd4\u56de\u4e00\u4e2a\u6839\u636e\u4efb\u610f\u5e8f\u5217\u4e2d\u7684\u5143\u7d20\u65b0\u5efa\u7684\u5df2\u6392\u5e8f\u5217\u8868\u3002sorted\u51fd\u6570\u63a5\u53d7\u7684\u53c2\u6570\u4e0e\u5217\u8868\u7684sort\u65b9\u6cd5\u4e00\u81f4\u3002 y = sorted ([ 7 , 1 , 2 , 6 , 0 , 3 , 2 ]) print ( y ) # [0, 1, 2, 2, 3, 6, 7] \u7ed3\u679c\u5df2\u6392\u5e8f z = sorted ( 'Hello World' ) print ( z ) # [' ', 'H', 'W', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r'] zip\u5c06\u5217\u8868\u3001\u5143\u7ec4\u6216\u5176\u4ed6\u5e8f\u5217\u7684\u5143\u7d20\u914d\u5bf9\uff0c\u65b0\u5efa\u4e00\u4e2a\u5143\u7ec4\u6784\u6210\u7684\u5217\u8868\u3002 seq1 = [ 'foo' , 'bar' , 'baz' ] seq2 = [ 'one' , 'two' , 'three' ] seq3 = [ False , True ] zipped = zip ( seq1 , seq2 ) print ( list ( zipped )) # [('foo', 'one'), ('bar', 'two'), ('baz', 'three')] zipped = zip ( seq1 , seq2 , seq3 ) print ( list ( zipped )) # [('foo', 'one', False), ('bar', 'two', True)] for i , ( a , b ) in enumerate ( zip ( seq1 , seq2 )): print ( ' {0} : {1} , {2} ' . format ( i , a , b )) # \u65b9\u6cd51 {0}\u5217\u8868\u5143\u7d20\u7684\u7d22\u5f15, {1}\u5143\u7ec4\u4e2d\u7b2c\u4e00\u4e2a\u503c, {2}\u5143\u7ec4\u4e2d\u7b2c\u4e8c\u4e2a\u503c print ( f ' { i } : { a } , { b } ' ) # \u65b9\u6cd52 # 0: foo, one # 1: bar, two # 2: baz, three \u7ed9\u5b9a\u4e00\u4e2a\u5df2\u201c\u914d\u5bf9\u201d\u7684\u5e8f\u5217\u65f6\uff0czip\u51fd\u6570\u53ef\u4ee5\u53bb\u201c\u62c6\u5206\u201d\u5e8f\u5217\u3002\u8fd9\u79cd\u65b9\u5f0f\u7684\u53e6\u4e00\u79cd\u601d\u8def\u5c31\u662f\u5c06\u884c\u7684\u5217\u8868\u8f6c\u6362\u4e3a\u5217\u7684\u5217\u8868\u3002\u53c2\u8003Python\u7684 Unpacking pitchers = [( 'Jack' , 'Ma' ), ( 'Tom' , 'Li' ), ( 'Jimmy' , 'Zhang' )] first_names , last_names = zip ( * pitchers ) print ( first_names ) # ('Jack', 'Tom', 'Jimmy') print ( last_names ) # ('Ma', 'Li', 'Zhang') reversed\u51fd\u6570\u5c06\u5e8f\u5217\u7684\u5143\u7d20\u5012\u5e8f\u6392\u5217 print ( list ( reversed ( range ( 10 )))) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 3. \u5217\u8868\u3001\u96c6\u5408\u548c\u5b57\u5178\u7684\u63a8\u5bfc\u5f0f \u00b6 \u63a8\u5bfc\u5f0fcomprehensions\uff08\u53c8\u79f0\u89e3\u6790\u5f0f\uff09\uff0c\u662fPython\u7684\u4e00\u79cd\u7279\u6027\u3002\u4f7f\u7528\u63a8\u5bfc\u5f0f\u53ef\u4ee5\u5feb\u901f\u751f\u6210\u5217\u8868\u3001\u5143\u7ec4\u3001\u96c6\u5408\u3001\u5b57\u5178\u7c7b\u578b\u7684\u6570\u636e\u3002\u63a8\u5bfc\u5f0f\u53c8\u5206\u4e3a\u5217\u8868\u63a8\u5bfc\u5f0f\u3001\u5143\u7ec4\u63a8\u5bfc\u5f0f\u3001\u96c6\u5408\u63a8\u5bfc\u5f0f\u3001\u5b57\u5178\u63a8\u5bfc\u5f0f\u3002 \u5217\u8868\u63a8\u5bfc\u5f0f(list comprehension) \u00b6 \u5217\u8868\u63a8\u5bfc\u5f0f(list comprehension)\u5141\u8bb8\u4f60\u8fc7\u6ee4\u4e00\u4e2a\u5bb9\u5668\u7684\u5143\u7d20\uff0c\u7528\u4e00\u79cd\u7b80\u660e\u7684\u8868\u8fbe\u5f0f\u8f6c\u6362\u4f20\u9012\u7ed9\u8fc7\u6ee4\u5668\u7684\u5143\u7d20\uff0c\u4ece\u800c\u751f\u6210\u4e00\u4e2a\u65b0\u7684\u5217\u8868\u3002 \u5217\u8868\u63a8\u5bfc\u5f0f\u7684\u57fa\u672c\u5f62\u5f0f\u4e3a\uff1a[expr for val in collection if condition]\uff0c\u6761\u4ef6if-condition\u4e0d\u662f\u5fc5\u987b\u7684\uff0c\u53ef\u4ee5\u53ea\u4fdd\u7559\u8868\u8fbe\u5f0f\u3002\u5217\u8868\u63a8\u5bfc\u5f0f\u4e0e\u4e0b\u9762\u7684for\u5faa\u73af\u662f\u7b49\u4ef7\u7684\uff1a result = [] for val in collection : if condition : result . append ( expr ) \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a data = [] for i in range ( - 5 , 5 ): if i >= - 1 : data . append ( i ** 2 ) print ( data ) # [1, 0, 1, 4, 9, 16] data = [ i ** 2 for i in range ( - 5 , 5 ) if i >= - 1 ] print ( data ) # [1, 0, 1, 4, 9, 16] \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u4f7f\u7528for\u53bb\u904d\u5386\u4e00\u4e2a\u53ef\u8fed\u4ee3\u7684\u5217\u8868\u3002 data = [] fruit = [ 'pomegranate' , 'cherry' , 'apricot' , 'date' , 'Apple' , 'lemon' , 'kiwi' , 'ORANGE' , 'lime' , 'Watermelon' , 'guava' , 'papaya' , 'FIG' , 'pear' , 'banana' , 'Tamarind' , 'persimmon' , 'elderberry' , 'peach' , 'BLUEberry' , 'lychee' , 'grape' ] data = [ x . upper () if x . startswith ( 'p' ) else x . title () for x in fruit ] print ( data ) # ['POMEGRANATE', 'Cherry', 'Apricot', 'Date', 'Apple', 'Lemon', 'Kiwi', 'Orange', 'Lime', 'Watermelon', 'Guava', 'PAPAYA', 'Fig', 'PEAR', 'Banana', 'Tamarind', 'PERSIMMON', 'Elderberry', 'PEACH', 'Blueberry', 'Lychee', 'Grape'] \u5957\u5217\u8868\u63a8\u5bfc\u5f0f \u00b6 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u7528\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u4ee3\u66ff2\u5c42for\u5faa\u73af\u3002 data = [] for i in range ( 1 , 3 ): if i >= 0 : for j in range ( 1 , 3 ): data . append (( i , j )) print ( data ) # [(1, 1), (1, 2), (2, 1), (2, 2)] data = [( i , j ) for i in range ( 1 , 3 ) if i >= - 1 for j in range ( 1 , 3 )] print ( data ) # [(1, 1), (1, 2), (2, 1), (2, 2)] \u518d\u4e3e\u4e00\u4e2a\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u7684\u4f8b\u5b50\u3002 all_data = [ [ 'John' , 'Emily' , 'Michael' , 'Lee' , 'Steven' ], [ 'Maria' , 'Juan' , 'Javier' , 'Natalia' , 'Pilar' ], ] names_of_interest = [] for names in all_data : enough_es = [ name for name in names if name . count ( 'e' ) >= 2 ] names_of_interest . extend ( enough_es ) print ( names_of_interest ) # ['Lee', 'Steven'] result = [ name for names in all_data for name in names if name . count ( 'e' ) >= 2 ] print ( result ) # ['Lee', 'Steven'] \u7528\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u5c06\u77e9\u9635\u6241\u5e73\u5316\u3002 \u8003\u8651\u4e0b\u9762\u8fd9\u4e2a3x4\u7684\u77e9\u9635\uff0c\u5b83\u75313\u4e2a\u957f\u5ea6\u4e3a4\u7684\u5217\u8868\u7ec4\u6210\u3002\u4e0b\u9762\u4f8b\u5b50\u5bf9\u6bd4\u4e86\u7528\u4f20\u7edffor\u5faa\u73af\u5c06\u77e9\u9635\u6241\u5e73\u5316\uff0c\u548c\u7528\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u5c06\u77e9\u9635\u6241\u5e73\u5316\u3002\u5e76\u4e14\u901a\u8fc7\u5217\u8868\u63a8\u5bfc\u5f0f\u4e2d\u7684\u5217\u8868\u63a8\u5bfc\u5f0f\u5c06\u6241\u5e73\u77e9\u9635\u8fd8\u539f\u4e3a3x4\u77e9\u9635\u3002 matrix = [ [ 1 , 2 , 3 , 4 ], [ 5 , 6 , 7 , 8 ], [ 9 , 10 , 11 , 12 ], ] flattened = [] # \u4f20\u7edffor\u5faa\u73af\u5d4c\u5957 for m in matrix : for x in m : flattened . append ( x ) print ( flattened ) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] # \u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f flattened = [ x for m in matrix for x in m ] print ( flattened ) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] # \u5217\u8868\u63a8\u5bfc\u5f0f\u4e2d\u7684\u5217\u8868\u63a8\u5bfc\u5f0f z = [[ x for x in m ] for m in matrix ] print ( z ) # [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] \u5143\u7ec4\u63a8\u5bfc\u5f0f \u00b6 \u4e0b\u9762\u7684\u4f8b\u5b50\u751f\u6210\u4e00\u4e2a\u5305\u542b\u6570\u5b571~5\u7684\u5143\u7ec4\u3002\u4ece\u7ed3\u679c\u53ef\u4ee5\u770b\u5230\uff0c\u5143\u7ec4\u63a8\u5bfc\u5f0f\u751f\u6210\u7684\u7ed3\u679c\u5e76\u4e0d\u662f\u4e00\u4e2a\u5143\u7ec4\uff0c\u800c\u662f\u4e00\u4e2a\u751f\u6210\u5668\u5bf9\u8c61\uff0c\u9700\u8981\u901a\u8fc7tuple()\u51fd\u6570\uff0c\u5c06\u751f\u6210\u5668\u5bf9\u8c61\u8f6c\u6362\u6210\u5143\u7ec4\u3002 data = ( x for x in range ( 5 )) print ( data ) # at 0x7f87217a8e40> print ( type ( data )) # print ( tuple ( data )) # (0, 1, 2, 3, 4) \u96c6\u5408\u63a8\u5bfc\u5f0f \u00b6 \u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u96c6\u5408\u63a8\u5bfc\u5f0f\u4f8b\u5b50\u3002 data = { x ** 2 for x in range ( 5 )} print ( data ) # {0, 1, 4, 9, 16} print ( type ( data )) # \u96c6\u5408\u8981\u4fdd\u8bc1\u5143\u7d20\u5fc5\u987b\u662f\u552f\u4e00\u7684\u3002 data = ( 1 , 1 , 2 , 2 , 3 , 3 , 4 , 5 , 6 ) newset = { x ** 2 for x in data } print ( newset ) # {1, 4, 36, 9, 16, 25} print ( type ( newset ) # \u5b57\u5178\u63a8\u5bfc\u5f0f \u00b6 \u5b57\u5178\u63a8\u5bfc\u5f0f: dict_comp = {key-expr : value-expr for value in collection if condition} \u5b57\u5178\u63a8\u5bfc\u5f0f\u7684\u7b80\u5355\u793a\u4f8b\uff1a strings = [ 'a' , 'as' , 'bat' , 'car' , 'dove' , 'python' ] loc_mapping = { index : val for index , val in enumerate ( strings )} print ( loc_mapping ) # {0: 'a', 1: 'as', 2: 'bat', 3: 'car', 4: 'dove', 5: 'python'} # \u4ea4\u6362\u952e\u548c\u503c loc_mapping = { index : val for val , index in enumerate ( strings )} print ( loc_mapping ) # {'a': 0, 'as': 1, 'bat': 2, 'car': 3, 'dove': 4, 'python': 5} 4. \u51fd\u6570\u58f0\u660e \u00b6 \u5982\u679cPython\u8fbe\u5230\u51fd\u6570\u7684\u5c3e\u90e8\u65f6\u4ecd\u7136\u6ca1\u6709\u9047\u5230return\u8bed\u53e5\uff0c\u5c31\u4f1a\u81ea\u52a8\u8fd4\u56deNone\u3002 \u6bcf\u4e2a\u51fd\u6570\u90fd\u53ef\u4ee5\u6709\u4f4d\u7f6e\u53c2\u6570\u548c\u5173\u952e\u5b57\u53c2\u6570\u3002\u5173\u952e\u5b57\u53c2\u6570\u6700\u5e38\u7528\u4e8e\u6307\u5b9a\u9ed8\u8ba4\u503c\u6216\u53ef\u9009\u53c2\u6570\u3002\u5173\u952e\u5b57\u53c2\u6570\u5fc5\u987b\u8ddf\u5728\u4f4d\u7f6e\u53c2\u6570\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u5173\u952e\u5b57\u53c2\u6570\u5411\u4f4d\u7f6e\u53c2\u6570\u4f20\u53c2\u3002 import sys def my_function1 ( x , y , z = 1.5 ): if z > 1 : return z * ( x + y ) else : return z / ( x + y ) result1 = my_function1 ( 5 , 6 , z = 0.7 ) print ( result1 ) # 0.06363636363636363 result1 = my_function1 ( x = 5 , y = 6 , z = 0.7 ) print ( result1 ) # 0.06363636363636363 result1 = my_function1 ( 3.14 , 7 , 3.5 ) print ( result1 ) # 35.49 result1 = my_function1 ( 10 , 20 ) print ( result1 ) # 45.0 5. \u547d\u540d\u7a7a\u95f4\u3001\u4f5c\u7528\u57df\u548c\u672c\u5730\u51fd\u6570 \u00b6 \u51fd\u6570\u6709\u4e24\u79cd\u8fde\u63a5\u53d8\u91cf\u7684\u65b9\u5f0f\uff1a\u5168\u5c40\u3001\u672c\u5730\u3002 def func1 (): list1 = [] # \u672c\u5730\u53d8\u91cf for i in range ( 5 ): list1 . append ( i ) print ( list1 ) func1 () # [0, 1, 2, 3, 4] list2 = [] # \u5168\u5c40\u53d8\u91cf def func2 (): global list2 # \u5168\u5c40\u53d8\u91cf for i in range ( 5 ): list2 . append ( i ) print ( list2 ) func2 () # [0, 1, 2, 3, 4] \u6570\u636e\u6e05\u6d17\u793a\u4f8b states = [ ' Alabama' , 'Georgia!' , 'georgia' , 'Georgia' , 'FlOrIda' , 'south carolina##' , 'West virginia? ' ] # \u65b9\u6cd51 import re def clean_string1 ( strings ): result2 = [] for value in strings : value = value . strip () value = re . sub ( '[! #? ]' , '' , value ) value = value . title () result2 . append ( value ) return result2 print ( clean_string1 (( states ))) # ['Alabama', 'Georgia', 'Georgia', 'Georgia', 'Florida', 'Southcarolina', 'Westvirginia'] # \u65b9\u6cd52 def remove_punctuaion ( value ): return re . sub ( '[! #? ]' , '' , value ) clean_ops = [ str . strip , remove_punctuaion , str . title ] def clean_string2 ( strings , ops ): result3 = [] for value in strings : for function in ops : value = function ( value ) result3 . append ( value ) return result3 result4 = clean_string2 ( states , clean_ops ) print ( result4 ) # ['Alabama', 'Georgia', 'Georgia', 'Georgia', 'Florida', 'Southcarolina', 'Westvirginia'] # \u53ef\u4ee5\u5c06\u51fd\u6570\u4f5c\u4e3a\u4e00\u4e2a\u53c2\u6570\u4f20\u7ed9\u5176\u4ed6\u7684\u51fd\u6570\u3002 for x in map ( remove_punctuaion , states ): print ( x ) # Alabama # Georgia # georgia # Georgia # FlOrIda # southcarolina # Westvirginia 6. \u67ef\u91cc\u5316\uff1a\u90e8\u5206\u53c2\u6570\u5e94\u7528 \u00b6 \u67ef\u91cc\u5316\u662f\u8ba1\u7b97\u673a\u79d1\u5b66\u672f\u8bed\uff08\u4ee5\u6570\u5b66\u5bb6Haskell Curry\u547d\u540d\uff09\uff0c\u5b83\u8868\u793a\u901a\u8fc7\u90e8\u5206\u53c2\u6570\u5e94\u7528\u7684\u65b9\u5f0f\u4ece\u5df2\u6709\u7684\u51fd\u6570\u4e2d\u884d\u751f\u51fa\u65b0\u7684\u51fd\u6570\u3002\u67ef\u91cc\u5316\u662f\u4e00\u79cd\u5c06\u591a\u53c2\u6570\u51fd\u6570\u8f6c\u5316\u4e3a\u5355\u53c2\u6570\u9ad8\u9636\u51fd\u6570\u7684\u6280\u672f\uff0c\u5982\u679c\u4f60\u56fa\u5b9a\u67d0\u4e9b\u53c2\u6570\uff0c\u4f60\u5c06\u5f97\u5230\u63a5\u53d7\u4f59\u4e0b\u53c2\u6570\u7684\u4e00\u4e2a\u51fd\u6570\u3002 \u5b9a\u4e49\u4e00\uff1a \u67ef\u91cc\u5316\uff1a\u4e00\u4e2a\u51fd\u6570\u4e2d\u6709\u4e2a\u591a\u4e2a\u53c2\u6570\uff0c\u60f3\u56fa\u5b9a\u5176\u4e2d\u67d0\u4e2a\u6216\u8005\u51e0\u4e2a\u53c2\u6570\u7684\u503c\uff0c\u800c\u53ea\u63a5\u53d7\u53e6\u5916\u51e0\u4e2a\u8fd8\u672a\u56fa\u5b9a\u7684\u53c2\u6570\uff0c\u8fd9\u6837\u51fd\u6570\u6f14\u53d8\u6210\u65b0\u7684\u51fd\u6570\u3002 \u5b9a\u4e49\u4e8c\uff1a \u51fd\u6570\u67ef\u91cc\u5316\uff08currying\uff09\u53c8\u79f0\u90e8\u5206\u6c42\u503c\u3002\u4e00\u4e2a currying \u7684\u51fd\u6570\u9996\u5148\u4f1a\u63a5\u53d7\u4e00\u4e9b\u53c2\u6570\uff0c\u63a5\u53d7\u4e86\u8fd9\u4e9b\u53c2\u6570\u4e4b\u540e\uff0c\u8be5\u51fd\u6570\u5e76\u4e0d\u4f1a\u7acb\u5373\u6c42\u503c\uff0c\u800c\u662f\u7ee7\u7eed\u8fd4\u56de\u53e6\u5916\u4e00\u4e2a\u51fd\u6570\uff0c\u521a\u624d\u4f20\u5165\u7684\u53c2\u6570\u5728\u51fd\u6570\u5f62\u6210\u7684\u95ed\u5305\u4e2d\u88ab\u4fdd\u5b58\u8d77\u6765\u3002\u5f85\u5230\u51fd\u6570\u88ab\u771f\u6b63\u9700\u8981\u6c42\u503c\u7684\u65f6\u5019\uff0c\u4e4b\u524d\u4f20\u5165\u7684\u6240\u6709\u53c2\u6570\u90fd\u4f1a\u88ab\u4e00\u6b21\u6027\u7528\u4e8e\u6c42\u503c\u3002 \u5b9a\u4e49\u4e09\uff1a \u4e00\u4e9b\u51fd\u6570\u5f0f\u8bed\u8a00\u7684\u5de5\u4f5c\u539f\u7406\u662f\u5c06\u591a\u53c2\u6570\u51fd\u6570\u8bed\u6cd5\u8f6c\u5316\u4e3a\u5355\u53c2\u6570\u51fd\u6570\u96c6\u5408\uff0c\u8fd9\u4e00\u8fc7\u7a0b\u79f0\u4e3a\u67ef\u91cc\u5316\uff0c\u5b83\u662f\u4ee5\u903b\u8f91\u5b66\u5bb6Haskell Curry\u7684\u540d\u5b57\u547d\u540d\u7684\u3002Haskell Curry\u4ece\u65e9\u671f\u6982\u5ff5\u4e2d\u53d1\u5c55\u51fa\u4e86\u8be5\u7406\u8bba\u3002\u5176\u5f62\u5f0f\u76f8\u5f53\u4e8e\u5c06z=f(x, y)\u8f6c\u6362\u6210z=f(x)(y)\u7684\u5f62\u5f0f\uff0c\u539f\u51fd\u6570\u7531\u4e24\u4e2a\u53c2\u6570\uff0c\u73b0\u5728\u53d8\u4e3a\u4e24\u4e2a\u63a5\u53d7\u5355\u53c2\u6570\u7684\u51fd\u6570\uff0c \u793a\u4f8b1\uff1a\u67ef\u91cc\u5316\u7684\u8fc7\u7a0b\u5c31\u662f\u628a\u539f\u6765\u5e26\u4e24\u4e2a\u53c2\u6570\u7684\u51fd\u6570add(x, y)\uff0c\u53d8\u6210\u4e86\u4e00\u4e2a\u5d4c\u5957\u51fd\u6570\uff0c\u5728add_currying\u51fd\u6570\u5185\uff0c\u53c8\u5b9a\u4e49\u4e86\u4e00\u4e2a_add\u51fd\u6570\uff0c\u5e76\u4e14_add\u51fd\u6570\u53c8\u5f15\u7528\u4e86\u5916\u90e8\u51fd\u6570add_currying\u7684\u53d8\u91cfx\uff0c\u8fd9\u5c31\u662f\u4e00\u4e2a\u95ed\u5305\u3002 \u95ed\u5305\uff0c\u4e00\u53e5\u8bdd\u8bf4\u5c31\u662f\u5728\u51fd\u6570\u4e2d\u518d\u5d4c\u5957\u4e00\u4e2a\u51fd\u6570\uff0c\u5e76\u4e14\u5f15\u7528\u5916\u90e8\u51fd\u6570\u7684\u53d8\u91cf\u3002 # \u666e\u901a\u5199\u6cd5 def add ( x , y ): return x + y print ( add ( 1 , 2 )) # 3 # \u67ef\u91cc\u5316\u5199\u6cd5 def add_currying ( x ): def _add ( y ): return x + y return _add print ( add_currying ( 1 )( 2 )) # 3 \u793a\u4f8b2\uff0c\u901a\u8fc7\u56fa\u5b9a\u5176\u4e2d\u7684\u7b2c\u4e8c\u4e2a\u53c2\u6570\u4e0d\u53d8\u6765\u5b9e\u73b0\u67ef\u91cc\u5316\u3002 def add2 ( a , b ): def add1 ( a , b , c ): return a + b + c return add1 ( a , 666 , b ) result6 = add2 ( 12 , 13 ) print ( result6 ) # 691 result6 = add2 ( 12 , 555 , 13 ) # TypeError: add2() takes 2 positional arguments but 3 were given \u793a\u4f8b3\uff0c\u901a\u8fc7functools\u63d0\u4f9b\u7684\u504f\u51fd\u6570\u6765\u5b9e\u73b0\u67ef\u91cc\u5316\u3002 from functools import partial def add1 ( a , b , c ): return a + b + c add3 = partial ( add1 , b = 666 ) result7 = add3 ( a = 12 , c = 13 ) print ( result7 ) # 691 \u793a\u4f8b4\uff0c\u901a\u8fc7lambda\u8868\u8fbe\u5f0f\u6765\u5b9e\u73b0\u67ef\u91cc\u5316\u3002 def add1 ( a , b , c ): return a + b + c add4 = lambda x , y : add1 ( x , 666 , y ) result8 = add4 ( 12 , 13 ) print ( result8 ) # 691 \u793a\u4f8b5\uff0c\u901a\u8fc7python\u7684\u88c5\u9970\u5668\u6765\u5b9e\u73b0\u67ef\u91cc\u5316 def add1 ( a , b , c ): return a + b + c def currying_add ( func ): def wrapper ( a , c , b = 666 ): return func ( a , b , c ) return wrapper result9 = currying_add ( add1 )( 12 , 13 ) print ( result9 ) # 691 \u793a\u4f8b6\uff0c\u901a\u8fc7python\u7684\u88c5\u9970\u5668\u7b26\u53f7@\u6765\u5b9e\u73b0\u67ef\u91cc\u5316 def currying_add ( func ): def wrapper ( a , c , b = 666 ): return func ( a , b , c ) return wrapper @currying_add def add5 ( a , b , c ): return a + b + c result10 = add5 ( 12 , 13 ) print ( result10 ) # 691 7. \u8fed\u4ee3\u5668\u4e0e\u751f\u6210\u5668 \u00b6 \u8fed\u4ee3\u5668 \u00b6 \u8fed\u4ee3\u662fPython\u6700\u5f3a\u5927\u7684\u529f\u80fd\u4e4b\u4e00\uff0c\u662f\u8bbf\u95ee\u96c6\u5408\u5143\u7d20\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u8fed\u4ee3\u5668\u662f\u4e00\u4e2a\u53ef\u4ee5\u8bb0\u4f4f\u904d\u5386\u7684\u4f4d\u7f6e\u7684\u5bf9\u8c61\u3002 \u8fed\u4ee3\u5668\u5bf9\u8c61\u4ece\u96c6\u5408\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\u8bbf\u95ee\uff0c\u76f4\u5230\u6240\u6709\u7684\u5143\u7d20\u88ab\u8bbf\u95ee\u5b8c\u7ed3\u675f\u3002\u8fed\u4ee3\u5668\u53ea\u80fd\u5f80\u524d\u4e0d\u4f1a\u540e\u9000\u3002 \u8fed\u4ee3\u5668\u6709\u4e24\u4e2a\u57fa\u672c\u7684\u65b9\u6cd5\uff1aiter() \u548c next()\u3002 \u8fed\u4ee3\u5668\u793a\u4f8b\uff1a list_a = [ 1 , 2 , 3 , 4 ] it = iter ( list_a ) # \u521b\u5efa\u8fed\u4ee3\u5668\u5bf9\u8c61 print ( next ( it )) # \u8f93\u51fa\u8fed\u4ee3\u5668\u7684\u4e0b\u4e00\u4e2a\u5143\u7d20 # 1 print ( next ( it )) # \u8f93\u51fa\u8fed\u4ee3\u5668\u7684\u4e0b\u4e00\u4e2a\u5143\u7d20 # 2 \u8fed\u4ee3\u5668\u5bf9\u8c61\u53ef\u4ee5\u4f7f\u7528\u5e38\u89c4for\u8bed\u53e5\u8fdb\u884c\u904d\u5386\u3002 list_a = [ 1 , 2 , 3 , 4 ] it = iter ( list_a ) # \u521b\u5efa\u8fed\u4ee3\u5668\u5bf9\u8c61 for x in it : print ( x , end = \" \" ) print ( end = \" \\n \" ) # 1 2 3 4 \u751f\u6210\u5668 \u00b6 \u5728 Python \u4e2d\uff0c\u4f7f\u7528\u4e86 yield \u7684\u51fd\u6570\u88ab\u79f0\u4e3a\u751f\u6210\u5668\uff08generator\uff09\u3002\u8ddf\u666e\u901a\u51fd\u6570\u4e0d\u540c\u7684\u662f\uff0c\u751f\u6210\u5668\u662f\u4e00\u4e2a\u8fd4\u56de\u8fed\u4ee3\u5668\u7684\u51fd\u6570\uff0c\u53ea\u80fd\u7528\u4e8e\u8fed\u4ee3\u64cd\u4f5c\uff0c\u751f\u6210\u5668\u5c31\u662f\u4e00\u4e2a\u8fed\u4ee3\u5668\u3002 \u5728\u8c03\u7528\u751f\u6210\u5668\u8fd0\u884c\u7684\u8fc7\u7a0b\u4e2d\uff0c\u6bcf\u6b21\u9047\u5230 yield \u65f6\u51fd\u6570\u4f1a\u6682\u505c\u5e76\u4fdd\u5b58\u5f53\u524d\u6240\u6709\u7684\u8fd0\u884c\u4fe1\u606f\uff0c\u8fd4\u56de yield \u7684\u503c, \u5e76\u5728\u4e0b\u4e00\u6b21\u6267\u884c next() \u65b9\u6cd5\u65f6\u4ece\u5f53\u524d\u4f4d\u7f6e\u7ee7\u7eed\u8fd0\u884c\u3002 \u8c03\u7528\u4e00\u4e2a\u751f\u6210\u5668\u51fd\u6570\uff0c\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u8fed\u4ee3\u5668\u5bf9\u8c61\u3002 \u793a\u4f8b, \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a def fibonacci ( n ): a , b , counter = 0 , 1 , 0 while True : if ( counter > n ): return yield a a , b = b , a + b counter += 1 f = fibonacci ( 10 ) # f \u662f\u4e00\u4e2a\u8fed\u4ee3\u5668\uff0c\u7531\u751f\u6210\u5668\u8fd4\u56de\u751f\u6210 print ( f ) # \u5b9e\u9645\u8c03\u7528\u751f\u6210\u5668\u65f6\uff0c\u4ee3\u7801\u5e76\u4e0d\u4f1a\u7acb\u5373\u6267\u884c for x in f : # \u8bf7\u6c42\u751f\u6210\u5668\u4e2d\u7684\u5143\u7d20\u65f6\uff0c\u5b83\u624d\u4f1a\u6267\u884c\u5b83\u7684\u4ee3\u7801 print ( x , end = \" \" ) print ( end = \" \\n \" ) # 0 1 1 2 3 5 8 13 21 34 55 \u751f\u6210\u5668\u8868\u8fbe\u5f0f\uff1a \u7528\u751f\u6210\u5668\u8868\u8fbe\u5f0f\u6765\u521b\u5efa\u751f\u6210\u5668\u66f4\u4e3a\u7b80\u5355\u3002\u751f\u6210\u5668\u8868\u8fbe\u5f0f\u4e0e\u5217\u8868\u3001\u5b57\u5178\u3001\u96c6\u5408\u7684\u63a8\u5bfc\u5f0f\u5f88\u7c7b\u4f3c\uff0c\u521b\u5efa\u4e00\u4e2a\u751f\u6210\u5668\u8868\u8fbe\u5f0f\uff0c\u53ea\u9700\u8981\u5c06\u5217\u8868\u63a8\u5bfc\u5f0f\u7684\u4e2d\u62ec\u53f7\u66ff\u6362\u4e3a\u5c0f\u62ec\u53f7\u5373\u53ef\u3002 gen1 = ( x ** 2 for x in range ( 100 )) print ( gen1 ) # at 0x7fd3f30c9580> \u4e0a\u9762\u7684\u4ee3\u7801\u4e0e\u4e0b\u9762\u7684\u751f\u6210\u5668\u662f\u7b49\u4ef7\u7684 def _make_gen (): for x in range ( 100 ): yield x ** 2 gen2 = _make_gen () print ( gen2 ) # \u751f\u6210\u5668\u8868\u8fbe\u5f0f\u53ef\u4ee5\u4f5c\u4e3a\u51fd\u6570\u53c2\u6570\u7528\u4e8e\u66ff\u4ee3\u5217\u8868\u63a8\u5bfc\u5f0f\u3002\u5bf9\u6bd4\u4e0b\u97622\u4e2a\u4f8b\u5b50\u3002 # \u793a\u4f8b1 result11 = sum ( x ** 2 for x in range ( 100 )) print ( result11 ) # 328350 gen1 = ( x ** 2 for x in range ( 100 )) result11 = sum ( gen1 ) print ( result11 ) # 328350 # \u793a\u4f8b2 result12 = dict (( i , i ** 2 ) for i in range ( 5 )) print ( result12 ) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} gen2 = (( i , i ** 2 ) for i in range ( 5 )) result12 = dict ( gen2 ) print ( result12 ) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} \u751f\u6210\u5668\uff1aitertools\u6a21\u5757 \u00b6 \u6807\u51c6\u5e93\u4e2d\u7684itertools\u6a21\u5757\u662f\u9002\u7528\u4e8e\u5927\u591a\u6570\u6570\u636e\u7b97\u6cd5\u7684\u751f\u6210\u5668\u96c6\u5408\u3002 import itertools first_letter = lambda x : x [ 0 ] names = [ 'Alan' , 'Adam' , 'Wes' , 'Will' , 'Albert' , 'Steven' ] for letter , names in itertools . groupby ( names , first_letter ): print ( letter ) print ( first_letter ) print ( letter , list ( names )) # names is generator # A # at 0x7fa598a7a0d0> # A ['Alan', 'Adam'] # W # at 0x7fa598a7a0d0> # W ['Wes', 'Will'] # A # at 0x7fa598a7a0d0> # A ['Albert'] # S # at 0x7fa598a7a0d0> # S ['Steven'] 8. \u9519\u8bef\u548c\u5f02\u5e38\u5904\u7406 \u00b6 Python\u7528\u5f02\u5e38\u5bf9\u8c61(exception object)\u6765\u8868\u793a\u5f02\u5e38\u60c5\u51b5\u3002\u9047\u5230\u9519\u8bef\u540e\uff0c\u4f1a\u5f15\u53d1\u5f02\u5e38\u3002\u5982\u679c\u5f02\u5e38\u5bf9\u8c61\u5e76\u672a\u88ab\u5904\u7406\u6216\u6355\u6349\uff0c\u7a0b\u5e8f\u5c31\u4f1a\u7528\u6240\u8c13\u7684\u56de\u6eaf(traceback\uff0c \u4e00\u79cd\u9519\u8bef\u4fe1\u606f)\u7ec8\u6b62\u6267\u884c\u3002 \u5f02\u5e38\u548c\u8bed\u6cd5\u9519\u8bef\u662f\u6709\u533a\u522b\u7684\u3002 \u9519\u8bef\uff1a\u662f\u6307\u4ee3\u7801\u4e0d\u7b26\u5408\u89e3\u91ca\u5668\u6216\u8005\u7f16\u8bd1\u5668\u8bed\u6cd5\u3002 \u5f02\u5e38\uff1a\u662f\u6307\u4e0d\u5b8c\u6574\u3001\u4e0d\u5408\u6cd5\u8f93\u5165\uff0c\u6216\u8005\u8ba1\u7b97\u51fa\u73b0\u9519\u8bef\u3002 python\u91cc\u7528try...except...\u8bed\u53e5\u6765\u5904\u7406\u5f02\u5e38\u60c5\u51b5\u3002 def attempt_float ( x ): try : return float ( x ) except ( TypeError , ValueError ): return \"Type error, not numbers\" r1 = attempt_float ( '1.2256' ) print ( r1 ) # 1.2256 r1 = attempt_float ( 'friends' ) print ( r1 ) # Type error, not numbers 9. \u6587\u4ef6\u4e0e\u64cd\u4f5c\u7cfb\u7edf \u00b6 f=open(path, 'w')\uff0c\u4e00\u4e2a\u65b0\u7684\u6587\u4ef6\u4f1a\u5728path\u6307\u5b9a\u7684\u8def\u5f84\u88ab\u521b\u5efa\uff0c\u5e76\u5728\u540c\u4e00\u8def\u5f84\u4e0b\u8986\u76d6\u540c\u540d\u6587\u4ef6\u3002\uff08\u8bf7\u5c0f\u5fc3\uff01\uff09 f=open(path, 'x')\uff0c\u4e00\u4e2a\u65b0\u7684\u6587\u4ef6\u4f1a\u5728path\u6307\u5b9a\u7684\u8def\u5f84\u88ab\u521b\u5efa\uff0c\u5982\u679c\u7ed9\u5b9a\u8def\u5f84\u4e0b\u5df2\u7ecf\u5b58\u5728\u540c\u540d\u6587\u4ef6\u5c31\u4f1a\u521b\u5efa\u5931\u8d25\u3002 import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f = open ( path ) # \u8bfb\u53d6\u6587\u4ef6\u6bcf\u4e00\u884c\uff0c\u6587\u4ef6\u6bcf\u4e00\u884c\u4f5c\u4e3a\u5217\u8868\u4e00\u4e2a\u5143\u7d20 lines = [ x . rstrip () for x in open ( path )] # \u8f93\u51fa\u5217\u8868 print ( lines ) # \u5173\u95ed\u6587\u4ef6\u4f1a\u5c06\u8d44\u6e90\u91ca\u653e\u56de\u64cd\u4f5c\u7cfb\u7edf f . close () \u53e6\u4e00\u79cd\u66f4\u7b80\u5355\u7684\u5173\u95ed\u6587\u4ef6\u7684\u65b9\u5f0f import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f = open ( path ) # \u4f7f\u7528with\u8bed\u53e5\u8bfb\u53d6\u6587\u4ef6\uff0c\u6587\u4ef6\u4f1a\u5728with\u4ee3\u7801\u5757\u7ed3\u675f\u540e\u81ea\u52a8\u5173\u95ed\u3002 with open ( path ) as f : lines = [ x . rstrip () for x in open ( path )] # \u8f93\u51fa\uff1a\u6587\u4ef6\u6bcf\u4e00\u884c\u4f5c\u4e3a\u5217\u8868\u4e00\u4e2a\u5143\u7d20 print ( lines ) \u5728\u6253\u5f00\u6587\u4ef6\u65f6\u4f7f\u7528seek\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u8981\u5f53\u5fc3\u3002\u5982\u679c\u6587\u4ef6\u7684\u53e5\u67c4\u4f4d\u7f6e\u6070\u597d\u5728\u4e00\u4e2aUnicode\u7b26\u53f7\u7684\u5b57\u8282\u4e2d\u95f4\u65f6\uff0c\u540e\u7eed\u7684\u8bfb\u53d6\u4f1a\u5bfc\u81f4\u9519\u8bef\u3002 import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f = open ( path ) # \u8bfb\u53d6\u6587\u4ef6\u3002 print ( f . read ( 5 )) # \u8f93\u51fa\u524d5\u4e2a\u5b57\u7b26\u3002 read\u65b9\u6cd5\u901a\u8fc7\u8bfb\u53d6\u7684\u5b57\u8282\u6570\u6765\u63a8\u8fdb\u6587\u4ef6\u53e5\u67c4\u7684\u4f4d\u7f6e\u3002 # I Thi print ( f . tell ()) # tell\u65b9\u6cd5\u53ef\u4ee5\u7ed9\u51fa\u53e5\u67c4\u5f53\u524d\u7684\u4f4d\u7f6e # 5 print ( f . seek ( 6 )) # seek\u65b9\u6cd5\u53ef\u4ee5\u5c06\u53e5\u67c4\u4f4d\u7f6e\u6539\u53d8\u5230\u6587\u4ef6\u4e2d\u7279\u5b9a\u7684\u5b57\u8282 # 6 print ( f . read ( 1 )) # \u4ece\u7b2c7\u4e2a\u5b57\u8282\u5f00\u59cb\uff0c\u8f93\u51fa1\u4e2a\u5b57\u8282 # k # \u5173\u95ed\u6587\u4ef6\u4f1a\u5c06\u8d44\u6e90\u91ca\u653e\u56de\u64cd\u4f5c\u7cfb\u7edf f . close () \u5982\u679c\u4f7f\u7528\u4e8c\u8fdb\u5236\u65b9\u5f0f\u6253\u5f00\u6587\u4ef6\uff0c\u5219\uff1a import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f2 = open ( path , 'rb' ) # \u4e8c\u8fdb\u5236\u6a21\u5f0f # \u8bfb\u53d6\u6587\u4ef6 print ( f2 . read ( 5 )) # \u7b2c\u4e00\u4e2ab\u4ee3\u8868\u4e8c\u8fdb\u5236\u683c\u5f0f # b'I Thi' print ( f2 . tell ()) # 5 print ( f2 . seek ( 6 )) # 6 print ( f2 . read ( 2 )) # \u4ece\u7b2c7\u4e2a\u5b57\u8282\u5f00\u59cb\uff0c\u8f93\u51fa2\u4e2a\u5b57\u8282 # b'k ' # \u5173\u95ed\u6587\u4ef6\u4f1a\u5c06\u8d44\u6e90\u91ca\u653e\u56de\u64cd\u4f5c\u7cfb\u7edf f2 . close () \u5c06\u672c\u6587\u5199\u5165\u6587\u4ef6\uff0c\u53ef\u4ee5\u4f7f\u7528\u6587\u4ef6\u5bf9\u8c61\u7684write\u6216wirtelines\u65b9\u6cd5\u3002 import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path1 = 'file01.txt' path2 = 'file02.txt' # file02.txt\u662f\u4e00\u4e2a\u7a7a\u6587\u4ef6 with open ( path2 , 'r+' , encoding = 'utf-8' ) as f : f . writelines ( x for x in open ( path1 , 'r' , encoding = 'utf-8' ) if len ( x ) > 1 ) # \u628afile01.txt\u7684\u5185\u5bb9\u5199\u5165file02.txt lines = f . readlines () print ( lines ) 10. \u88c5\u9970\u5668 \u00b6 \u95ed\u5305 \u00b6 \u7ef4\u57fa\u767e\u79d1\u4e2d\u7684\u89e3\u91ca\uff1a \u95ed\u5305\uff08Closure\uff09 \uff0c\u53c8\u79f0\u8bcd\u6cd5\u95ed\u5305\uff08Lexical Closure\uff09\u6216\u51fd\u6570\u95ed\u5305\uff08function closures\uff09\uff0c\u662f\u5f15\u7528\u4e86\u81ea\u7531\u53d8\u91cf\u7684\u51fd\u6570\u3002\u8fd9\u4e2a\u88ab\u5f15\u7528\u7684\u81ea\u7531\u53d8\u91cf\u5c06\u548c\u8fd9\u4e2a\u51fd\u6570\u4e00\u540c\u5b58\u5728\uff0c\u5373\u4f7f\u5df2\u7ecf\u79bb\u5f00\u4e86\u521b\u9020\u5b83\u7684\u73af\u5883\u4e5f\u4e0d\u4f8b\u5916\u3002 \u95ed\u5305\u5ef6\u4f38\u4e86\u4f5c\u7528\u57df\u7684\u51fd\u6570\uff0c\u5176\u4e2d\u5305\u542b\u51fd\u6570\u5b9a\u4e49\u4f53\u4e2d\u5f15\u7528\u3001\u4f46\u662f\u4e0d\u5728\u5b9a\u4e49\u4f53\u4e2d\u5b9a\u4e49\u7684\u975e\u5168\u5c40\u53d8\u91cf\u3002\u51fd\u6570\u662f\u4e0d\u662f\u533f\u540d\u7684\u6ca1\u6709\u5173\u7cfb\uff0c\u5173\u952e\u662f\u5b83\u80fd\u8bbf\u95ee\u5b9a\u4e49\u4f53\u4e4b\u5916\u5b9a\u4e49\u7684\u975e\u5168\u5c40\u53d8\u91cf\u3002 \u4f8b\u4e00\uff0c\u8ba1\u7b97\u79fb\u52a8\u5e73\u5747\u503c\u3002 \u4e0b\u9762\u662f\u662f\u4f20\u7edf\u7c7b\u5b9e\u73b0\u65b9\u5f0f\uff0cAvg\u7684\u5b9e\u4f8b\u662f\u53ef\u8c03\u7528\u7684\u5bf9\u8c61\u3002 class Avg (): def __init__ ( self ): self . mylist = [] def __call__ ( self , newValue ): self . mylist . append ( newValue ) total = sum ( self . mylist ) return total / len ( self . mylist ) avg = Avg () avg ( 10 ) # 10.0 avg ( 20 ) # 15.0 avg ( 30 ) # 20.0 \u4e0b\u9762\u662f\u9ad8\u9636\u51fd\u6570\u5b9e\u73b0\u65b9\u5f0f\u3002\u8c03\u7528 make_avg \u65f6\uff0c\u8fd4\u56de\u4e00\u4e2a my_avg \u51fd\u6570\u5bf9\u8c61\u3002\u6bcf\u6b21\u8c03\u7528 my_avg \u65f6\uff0c\u5b83\u4f1a\u628a\u53c2\u6570\u6dfb\u52a0\u5230\u7cfb\u5217\u503c\u4e2d\uff0c\u7136\u540e\u8ba1\u7b97\u5f53\u524d\u5e73\u5747\u503c\u3002 def make_avg (): my_list = [] def avg ( newValue ): my_list . append ( newValue ) total = sum ( my_list ) return total / len ( my_list ) return avg my_avg = make_avg () my_avg ( 10 ) # 10.0 my_avg ( 20 ) # 15.0 my_avg ( 30 ) # 20.0 my_avg . __code__ . co_varnames # ('newValue', 'total') my_avg . __code__ . co_freevars # ('my_list',) my_avg . __closure__ # (,) my_avg . __closure__ [ 0 ] . cell_contents # [10, 20, 30] \u8fd9\u4e24\u4e2a\u793a\u4f8b\u6709\u5171\u901a\u4e4b\u5904\uff1a\u8c03\u7528 Avg() \u6216 make_avg() \u5f97\u5230\u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61 avg \uff0c\u5b83\u4f1a\u66f4\u65b0\u5386\u53f2\u503c\uff0c\u7136\u540e\u8ba1\u7b97\u5f53\u524d\u5747\u503c\u3002 \u5728\u7c7b\u5b9e\u73b0\u4e2d\uff0c avg \u662f Avg \u7684\u5b9e\u4f8b\uff1b\u5728\u9ad8\u9636\u51fd\u6570\u5b9e\u73b0\u4e2d\u662f\u5185\u90e8\u51fd\u6570 avg \u3002 \u4e24\u79cd\u5b9e\u73b0\u65b9\u5f0f\u4e2d\uff0c\u6211\u4eec\u90fd\u53ea\u9700\u8c03\u7528 avg(n) \uff0c\u628a n \u653e\u5165\u7cfb\u5217\u503c\u4e2d\uff0c\u7136\u540e\u91cd\u65b0\u8ba1\u7b97\u5747\u503c\u3002 \u7b2c\u4e00\u4e2a\u4f8b\u5b50\u4e2d\uff0c Avg \u7c7b\u7684\u5b9e\u4f8b avg \u5728 self.series \u5b9e\u4f8b\u5c5e\u6027\u4e2d\u5b58\u50a8\u5386\u53f2\u503c\u3002 \u7b2c\u4e8c\u4e2a\u4f8b\u5b50\u4e2d\u7684 my_list \u662f\u51fd\u6570 make_avg() \u7684\u5c40\u90e8\u53d8\u91cf\uff0c\u4e5f\u79f0\u4e3a\u8be5\u51fd\u6570\u7684**\u81ea\u7531\u53d8\u91cf\uff08free variable\uff09**\uff0c\u6307\u672a\u5728\u672c\u5730\u4f5c\u7528\u57df\u4e2d\u7ed1\u5b9a\u7684\u53d8\u91cf\u3002 avg() \u51fd\u6570\u7684\u95ed\u5305\u5ef6\u4f38\u5230\u51fd\u6570\u7684\u4f5c\u7528\u57df\u4e4b\u5916\uff0c\u5305\u542b\u4e86 make_avg() \u7684\u81ea\u7531\u53d8\u91cf my_list \u7684\u7ed1\u5b9a\u3002 \u5bf9\u4e8e\u8fd4\u56de\u7684 my_avg \u5bf9\u8c61\uff0c\u5176 __code__ \u5c5e\u6027\uff08\u8868\u793a\u7f16\u8bd1\u540e\u7684\u51fd\u6570\u5b9a\u4e49\u4f53\uff09\u4e2d\u4fdd\u5b58\u4e86\u5c40\u90e8\u53d8\u91cf\u548c\u81ea\u7531\u53d8\u91cf\u7684\u540d\u79f0\uff0c\u5373 my_avg.__code__.co_varnames \u8fd4\u56de\u4e86\u5c40\u90e8\u53d8\u91cf ('newValue', 'total') \u548c my_avg.__code__.co_freevars \u8fd4\u56de\u4e86\u81ea\u7531\u53d8\u91cf ('my_list',) \u3002 \u81ea\u7531\u53d8\u91cf my_list \u7ed1\u5b9a\u5728\u8fd4\u56de\u7684 my_avg \u7684 __closure__ \u7684\u5c5e\u6027\u4e2d\uff0c my_avg.__closure__ \u4e2d\u7684\u5404\u4e2a\u5143\u7d20\u5bf9\u5e94\u4e86 my_avg.__code__.co_freevars \u4e2d\u7684\u4e00\u4e2a\u540d\u79f0\u3002\u8fd9\u4e9b\u5143\u7d20\u662f cell \u5bf9\u8c61\uff0c\u6709\u4e2a cell_contents \u5c5e\u6027\uff0c\u5982\uff1a my_avg.__closure__ \u8fd4\u56de (,) \uff0c\u91cc\u9762\u4fdd\u5b58\u7740\u771f\u6b63\u7684\u503c\uff0c\u5982 my_avg.__closure__[0].cell_contents \u91cc\u9762\u4fdd\u5b58\u6bcf\u6b21\u8c03\u7528\u7684\u771f\u5b9e\u503c [10, 20, 30] \u3002 \u4e0a\u9762 my_list \u662f\u4e00\u4e2a\u53ef\u53d8\u7c7b\u578b\uff0c\u5982\u679c\u7528\u4e0d\u53ef\u53d8\u7c7b\u578b\u6539\u5199\uff0c\u5e76\u5b9e\u73b0\u95ed\u5305\uff0c\u53ef\u4ee5\u4f7f\u7528 nolocal \u8fdb\u884c\u58f0\u660e\u3002\u5b83\u7684\u4f5c\u7528\u662f\u628a\u53d8\u91cf\u6807\u8bb0\u4e3a\u81ea\u7531\u53d8\u91cf\uff0c\u5373\u4f7f\u5728\u51fd\u6570\u4e2d\u4e3a\u53d8\u91cf\u8d4b\u4e88\u65b0\u503c\u4e86\uff0c\u4e5f\u4f1a\u53d8\u6210\u81ea\u7531\u53d8\u91cf\u3002\u5982\u679c\u4e3anonlocal\u58f0\u660e\u7684\u53d8\u91cf\u8d4b\u4e88\u65b0\u503c\uff0c\u95ed\u5305\u4e2d\u4fdd\u5b58\u7684\u7ed1\u5b9a\u4f1a\u66f4\u65b0\u3002 my_avg.__code__.co_freevars \u8fd4\u56de\u4e862\u4e2a\u81ea\u7531\u53d8\u91cf ('count', 'total') \uff0c\u5e76\u5728 my_avg.__closure__[0].cell_contents \u548c my_avg.__closure__[1].cell_contents \u91cc\u9762\u4fdd\u5b58\u4e86\u6700\u540e\u4e00\u6b21\u6267\u884c\u7684\u771f\u5b9e\u503c\u3002 def make_avg (): count = 0 total = 0 def avg ( newValue ): nonlocal count , total count += 1 total += newValue return total / count return avg my_avg = make_avg () my_avg ( 10 ) # 10.0 my_avg ( 20 ) # 15.0 my_avg ( 30 ) # 20.0 my_avg . __code__ . co_varnames # ('newValue',) my_avg . __code__ . co_freevars # ('count', 'total') my_avg . __closure__ # (, ) my_avg . __closure__ [ 0 ] . cell_contents # 3 my_avg . __closure__ [ 1 ] . cell_contents # 60 \u4f8b\u4e8c\uff1a money \u662f\u4e00\u4e2a\u5c40\u90e8\u53d8\u91cf\uff0c\u5728 get_money \u662f\u5916\u56f4\u51fd\u6570\uff0c\u51fd\u6570\u6267\u884c\u4e4b\u540e\u5e94\u8be5\u5c31\u4e0d\u4f1a\u5b58\u5728\u4e86\u3002 \u4f46\u662f\u5d4c\u5957\u51fd\u6570 work \u5f15\u7528\u4e86 money \u8fd9\u4e2a\u81ea\u7531\u53d8\u91cf\uff0c\u5c06\u8fd9\u4e2a\u5c40\u90e8\u53d8\u91cf\u5c01\u95ed\u5728\u4e86\u5d4c\u5957\u51fd\u6570 work \u4e2d\uff0c\u8fd9\u6837\u5c31\u5f62\u6210\u4e86\u4e00\u4e2a\u95ed\u5305\u3002 closure = get_money() \u83b7\u5f97\u7684\u5c31\u662f\u4e00\u4e2a\u95ed\u5305\u3002 closure() \u8f93\u51fa\u95ed\u5305\uff0c\u5373\uff0c\u6267\u884c\u4e86 work() \uff0c\u6253\u5370\u8f93\u51fa money \u7684\u503c\u3002 \u672c\u5730\u51fd\u6570\u901a\u8fc7global\u58f0\u660e\u5bf9\u5168\u5c40\u53d8\u91cf\u8fdb\u884c\u5f15\u7528\u4fee\u6539\uff0c\u90a3\u4e48\u5bf9\u4e8e\u5185\u5d4c\u51fd\u6570 work() \u4f5c\u7528\u57df\u4e2d\u7684\u53d8\u91cf\u8fdb\u884c\u4fee\u6539\uff0c\u5c31\u8981\u4f7f\u7528 nonlocal \u8fdb\u884c\u58f0\u660e\u3002 def get_money (): money = 0 def work (): nonlocal money money += 100 print ( money ) return work closure = get_money () closure () # 100 closure () # 200 closure () # 300 \u4f8b\u4e09\uff1a \u51fd\u6570 maker \u4e2d\u5b9a\u4e49\u4e86\u51fd\u6570 action \uff0c action \u5f15\u7528\u4e86 maker \u5d4c\u5957\u4f5c\u7528\u57df\u5185\u7684\u53d8\u91cf k \uff0c\u5e76\u4e14\uff0c maker \u5c06\u51fd\u6570 action \u4f5c\u4e3a\u8fd4\u56de\u5bf9\u8c61\u8fdb\u884c\u8fd4\u56de\u3002 \u8fd9\u6837\uff0c\u6211\u4eec\u901a\u8fc7\u6267\u884c f = maker(2) \uff0c f \u83b7\u53d6\u4e86\u8fd4\u56de\u5bf9\u8c61 action \uff0c\u867d\u7136\u6b64\u65f6 maker \u51fd\u6570\u4ee5\u53ca\u7ed3\u675f\u9000\u51fa\u4e86\uff0c\u4f46\u5bf9\u8c61 f \u4ecd\u7136\u8bb0\u4f4f\u4e86\u51fd\u6570 maker \u5d4c\u5957\u4f5c\u7528\u57df\u5185\u7684\u53d8\u91cf k \u548c n \uff0c\u5e76\u5728\u6267\u884c f(3) \u65f6\uff0c\u5c06 x=3 \u4ee5\u53ca\u4e4b\u524d\u8bb0\u4f4f\u7684 k \u548c n \uff0c\u4e00\u5e76\u4f20\u5165 action() \uff0c\u8ba1\u7b97\u5e76\u8fd4\u56de x + n + k \u503c\u3002 make \u4e5f\u79f0\u4e3a**\u5de5\u5382\u51fd\u6570**\u3002 def maker ( n ): k = 8 def action ( x ): return x + n + k return action f = maker ( 2 ) print ( f ( 3 )) # 13 print ( f ( 4 )) # 14 print ( f ( 5 )) # 15 \u7ed3\u5408\u524d\u97622\u4e2a\u4f8b\u5b50\u518d\u770b\u4e0a\u9762\u7684\u89e3\u91ca\uff0c\u95ed\u5305\u5c31\u662f\u5f15\u7528\u4e86\u81ea\u7531\u53d8\u91cf\u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u4fdd\u5b58\u4e86\u6267\u884c\u7684\u4e0a\u4e0b\u6587\uff0c\u53ef\u4ee5\u8131\u79bb\u539f\u672c\u7684\u4f5c\u7528\u57df\u72ec\u7acb\u5b58\u5728\u3002 \u88c5\u9970\u5668 \u00b6 \u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u5c06\u51fd\u6570\u4f5c\u4e3a\u53c2\u6570\u4f20\u7ed9\u53e6\u4e00\u4e2a\u51fd\u6570\uff0c\u51fd\u6570 my_decorator \u7684\u4f20\u5165\u53c2\u6570\u6b63\u597d\u662f\u5176\u5d4c\u5957\u51fd\u6570 myFunc \u3002 def my_decorator ( nestedFunc ): def myFunc (): print ( \"Before executing nestedFunc()\" ) nestedFunc () print ( \"After executing nestedFunc()\" ) return myFunc def nestedFunc (): print ( \"Decoration - executing nestedFunc()\" ) nestedFunc () # Decoration - executing nestedFunc() nestedFunc = my_decorator ( nestedFunc ) nestedFunc () # Before executing nestedFunc() # Decoration - executing nestedFunc() # After executing nestedFunc() \u88c5\u9970\u5668\u53ea\u662f\u4e2a\u65b9\u6cd5\uff0c\u4f7f\u7528\u65f6\u7528\u4e86 @ \u8bed\u6cd5\u3002 @ \u8bed\u6cd5\u53ea\u662f\u5c06\u51fd\u6570 nestedFunc \u4f20\u5165\u88c5\u9970\u5668\u51fd\u6570 my_decorator \u3002 @my_decorator \u662f nestedFunc = my_decorator(nestedFunc) \u7684\u5feb\u6377\u8868\u8fbe\u65b9\u5f0f\uff0c @my_decorator def nestedFunc (): print ( \"New added to decoration - executing nestedFunc()\" ) nestedFunc () # Before executing nestedFunc() # New added to decoration - executing nestedFunc() # After executing nestedFunc() print ( nestedFunc . __name__ ) # myFunc \u4f46\u4e0a\u4f8b\u6700\u540e\u7684\u8f93\u51fa\u4e0d\u662f\u6211\u4eec\u60f3\u8981\u7684\uff0c\u6211\u4eec\u5e0c\u671b\u8f93\u51fa nestedFunc \uff0c\u4f46\u5374\u88ab myFunc \u66ff\u4ee3\u4e86\uff0c\u5b83\u91cd\u5199\u4e86\u6211\u4eec\u51fd\u6570\u7684\u540d\u5b57\u548c\u6ce8\u91ca\u6587\u6863(docstring)\u3002 \u4e0b\u9762\u4f7f\u7528 functools.wraps \u6765\u4fee\u6b63\u4e0a\u9762\u7684\u95ee\u9898\u3002 from functools import wraps def my_decorator ( nestedFunc ): @wraps ( nestedFunc ) def myFunc (): print ( \"Before executing nestedFunc()\" ) nestedFunc () print ( \"After executing nestedFunc()\" ) return myFunc def nestedFunc (): print ( \"Decoration - executing nestedFunc()\" ) @my_decorator def nestedFunc (): print ( \"New added to decoration - executing nestedFunc()\" ) nestedFunc () # Before executing nestedFunc() # New added to decoration - executing nestedFunc() # After executing nestedFunc() print ( nestedFunc . __name__ ) # nestedFunc \u4e0b\u9762\u662f\u88c5\u9970\u5668\u7684\u84dd\u672c\u89c4\u8303\u3002 from functools import wraps def decorator_name ( f ): @wraps ( f ) def decorated ( * args , ** kwargs ): if not can_run : return \"Function will not run\" return f ( * args , ** kwargs ) return decorated @decorator_name def func (): return ( \"Function is running\" ) can_run = True print ( func ()) # Output: Function is running can_run = False print ( func ()) # Output: Function will not run \u4e0b\u9762\u8fd8\u662f\u4e00\u4e2a\u88c5\u9970\u5668\u7684\u4f8b\u5b50\u3002\u628a\u4e0b\u9762\u7684\u4ee3\u7801\u6bb5\u4fdd\u5b58\u5230\u6587\u4ef6 test.py \u3002 registry = [] def register ( func ): print ( f 'running register { func } ' ) registry . append ( func ) return func @register def f1 (): print ( 'running f1()' ) @register def f2 (): print ( 'running f2()' ) def f3 (): print ( 'running f3()' ) def main (): print ( 'runnning main()' ) print ( f 'registry--> { registry } ' ) f1 () f2 () f3 () if __name__ == '__main__' : main () \u6267\u884c\u4e0a\u8ff0\u4ee3\u7801\u6bb5 python3 test.py \uff0c\u5f97\u5230\u4e0b\u9762\u7684\u7ed3\u679c\u3002 running register < function f1 at 0x7f70847bec80 > running register < function f2 at 0x7f70705aa9d8 > runnning main () registry --> [ < function f1 at 0x7f70847bec80 > , < function f2 at 0x7f70705aa9d8 > ] running f1 () running f2 () running f3 () register \u5728\u6a21\u5757\u4e2d\u5176\u4ed6\u51fd\u6570\u4e4b\u524d\u8fd0\u884c\uff08\u4e24\u6b21\uff09\u3002\u8c03\u7528 register \u65f6\uff0c\u4f20\u7ed9\u5b83\u7684\u53c2\u6570\u662f\u88ab\u88c5\u9970\u7684\u51fd\u6570\uff0c\u4f8b\u5982 function f1 at 0x7f70847bec80> \u3002\u52a0\u8f7d\u6a21\u5757\u540e\uff0c registry \u4e2d\u6709\u4e24\u4e2a\u88ab\u88c5\u9970\u51fd\u6570\u7684\u5f15\u7528\uff1a f1 \u548c f2 \u3002\u8fd9\u4e24\u4e2a\u51fd\u6570\uff0c\u4ee5\u53ca f3 \uff0c\u53ea\u5728 main \u660e\u786e\u8c03\u7528\u5b83\u4eec\u65f6\u624d\u6267\u884c\u3002 \u7531\u6b64\u5f97\uff0c\u51fd\u6570\u88c5\u9970\u5668\u5728\u5bfc\u5165\u6a21\u5757\u65f6\u7acb\u5373\u6267\u884c\uff0c\u800c\u88ab\u88c5\u9970\u7684\u51fd\u6570\u53ea\u5728\u660e\u786e\u8c03\u7528\u65f6\u8fd0\u884c\uff0c\u5373Python\u4e2d\u63d0\u5230\u7684**\u5bfc\u5165\u65f6**\u548c**\u8fd0\u884c\u65f6**\u4e4b\u95f4\u7684\u533a\u522b\u3002 \u4e0a\u9762\u4f8b\u5b50\u4e2d\u88c5\u9970\u5668\u51fd\u6570\u4e0e\u88ab\u88c5\u9970\u7684\u51fd\u6570\u5728\u540c\u4e00\u4e2a\u6a21\u5757\u4e2d\u5b9a\u4e49\u3002\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u88c5\u9970\u5668\u901a\u5e38\u5728\u4e00\u4e2a\u6a21\u5757\u4e2d\u5b9a\u4e49\uff0c\u7136\u540e\u5e94\u7528\u5230\u5176\u4ed6\u6a21\u5757\u4e2d\u7684\u51fd\u6570\u4e0a\u3002 \u4e0a\u9762\u4f8b\u5b50\u4e2d register \u88c5\u9970\u5668\u8fd4\u56de\u7684\u51fd\u6570\u4e0e\u901a\u8fc7\u53c2\u6570\u4f20\u5165\u7684\u76f8\u540c\u3002\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u5927\u591a\u6570\u88c5\u9970\u5668\u4f1a\u5728\u5185\u90e8\u5b9a\u4e49\u4e00\u4e2a\u51fd\u6570\uff0c\u7136\u540e\u5c06\u5176\u8fd4\u56de\u3002","title":"Python\u5185\u7f6e\u51fd\u6570\u53ca\u6587\u4ef6"},{"location":"python/Foundation/ch03/#python","text":"","title":"Python\u5185\u7f6e\u51fd\u6570\u53ca\u6587\u4ef6"},{"location":"python/Foundation/ch03/#1-lambda","text":"\u533f\u540d\u51fd\u6570\u662f\u4e00\u79cd\u901a\u8fc7\u5355\u4e2a\u8bed\u53e5\u751f\u6210\u51fd\u6570\u7684\u65b9\u5f0f\uff0c\u5176\u7ed3\u679c\u662f\u8fd4\u56de\u503c\u3002\u533f\u540d\u51fd\u6570\u4f7f\u7528lambda\u5173\u952e\u5b57\u5b9a\u4e49\uff0c\u8be5\u5173\u952e\u5b57\u4ec5\u8868\u8fbe\u201c\u6211\u4eec\u58f0\u660e\u4e00\u4e2a\u533f\u540d\u51fd\u6570\u201d\u7684\u610f\u601d\u3002 lambda \u51fd\u6570\u53ef\u4ee5\u63a5\u6536\u4efb\u610f\u591a\u4e2a\u53c2\u6570 (\u5305\u62ec\u53ef\u9009\u53c2\u6570) \u5e76\u4e14\u8fd4\u56de\u5355\u4e2a\u8868\u8fbe\u5f0f\u7684\u503c\u3002 \u8bed\u6cd5\u683c\u5f0f\uff1a lambda arg1,arg2,arg3\u2026 :<\u8868\u8fbe\u5f0f> f = lambda x , y : x * y print ( f ( 2 , 3 )) # 6 f = [ lambda a : a * 2 , lambda b : b * 3 ] print ( f [ 0 ]( 5 )) # \u6267\u884cf\u5217\u8868\u7b2c\u4e00\u4e2a\u5143\u7d20 # 10 print ( f [ 1 ]( 5 )) # \u6267\u884cf\u5143\u7d20\u7b2c\u4e8c\u4e2a\u5143\u7d20 # 15 print ( f [ 0 , 1 ]( 5 , 5 )) # TypeError: list indices must be integers or slices, not tuple \u793a\u4f8b1\uff1a def short_func1 ( x ): return x * 2 short_func2 = lambda x : x * 2 print ( short_func1 ( 5 )) # 10 print ( short_func2 ( 5 )) # 10 \u793a\u4f8b2\uff1a def apply_to_list ( some_list , f ): return [ f ( x ) for x in some_list ] ints = [ 4 , 0 , 1 , 5 , 6 ] result5 = apply_to_list ( ints , lambda x : x * 2 ) print ( result5 ) # [8, 0, 2, 10, 12] lambda: None \u51fd\u6570\u6ca1\u6709\u8f93\u5165\u53c2\u6570\uff0c\u8f93\u51fa\u662fNone\u3002 print ( lambda : None ) # at 0x7fa5c4097670> lambda **kwargs: 1 \u8f93\u5165\u662f\u4efb\u610f\u952e\u503c\u5bf9\u53c2\u6570\uff0c\u8f93\u51fa\u662f1\u3002 print ( lambda ** kwargs : 1 ) # at 0x7fa5c4097670>","title":"1. \u533f\u540d\uff08Lambda\uff09\u51fd\u6570"},{"location":"python/Foundation/ch03/#2-enumerate","text":"\u5f53\u9700\u8981\u5bf9\u6570\u636e\u5efa\u7acb\u7d22\u5f15\u65f6\uff0c\u4e00\u79cd\u6709\u6548\u7684\u6a21\u5f0f\u5c31\u662f\u4f7f\u7528enumerate\u6784\u9020\u4e00\u4e2a\u5b57\u5178\uff0c\u5c06\u5e8f\u5217\u503c\uff08\u5047\u8bbe\u662f\u552f\u4e00\u7684\uff09\u6620\u5c04\u5230\u7d22\u5f15\u4f4d\u7f6e\u4e0a\u3002 seasons = [ 'Spring' , 'Summer' , 'Fall' , 'Winter' ] print ( list ( enumerate ( seasons ))) # [(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')] \u5bf9\u6bd4\u4e0b\u97622\u4e2a\u5faa\u73af a_list = [ 'foo' , 'bar' , 'baz' ] mapping = {} for i , v in enumerate ( a_list ): # enumerate\u751f\u6210\u7d22\u5f15\u503ci\u548c\u5e8f\u5217\u503cv mapping [ v ] = i print ( mapping ) # {'foo': 0, 'bar': 1, 'baz': 2} i = 0 mapping = {} for v in a_list : print ( i , a_list [ i ]) mapping [ v ] = i # \u53ef\u4ee5\u628ai\u548cv\u4e92\u6362 i += 1 print ( mapping ) # {'foo': 0, 'bar': 1, 'baz': 2} \u5229\u7528 enumerate() \u6279\u91cf\u4fee\u6539\u5217\u8868\u5185\u7684\u5143\u7d20 a_list = [ '01' , '02' , '03' ] unit_element = '1' for i , element in enumerate ( a_list ): a_list [ i ] = unit_element + element print ( a_list ) # ['101', '102', '103'] sorted\u51fd\u6570\u8fd4\u56de\u4e00\u4e2a\u6839\u636e\u4efb\u610f\u5e8f\u5217\u4e2d\u7684\u5143\u7d20\u65b0\u5efa\u7684\u5df2\u6392\u5e8f\u5217\u8868\u3002sorted\u51fd\u6570\u63a5\u53d7\u7684\u53c2\u6570\u4e0e\u5217\u8868\u7684sort\u65b9\u6cd5\u4e00\u81f4\u3002 y = sorted ([ 7 , 1 , 2 , 6 , 0 , 3 , 2 ]) print ( y ) # [0, 1, 2, 2, 3, 6, 7] \u7ed3\u679c\u5df2\u6392\u5e8f z = sorted ( 'Hello World' ) print ( z ) # [' ', 'H', 'W', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r'] zip\u5c06\u5217\u8868\u3001\u5143\u7ec4\u6216\u5176\u4ed6\u5e8f\u5217\u7684\u5143\u7d20\u914d\u5bf9\uff0c\u65b0\u5efa\u4e00\u4e2a\u5143\u7ec4\u6784\u6210\u7684\u5217\u8868\u3002 seq1 = [ 'foo' , 'bar' , 'baz' ] seq2 = [ 'one' , 'two' , 'three' ] seq3 = [ False , True ] zipped = zip ( seq1 , seq2 ) print ( list ( zipped )) # [('foo', 'one'), ('bar', 'two'), ('baz', 'three')] zipped = zip ( seq1 , seq2 , seq3 ) print ( list ( zipped )) # [('foo', 'one', False), ('bar', 'two', True)] for i , ( a , b ) in enumerate ( zip ( seq1 , seq2 )): print ( ' {0} : {1} , {2} ' . format ( i , a , b )) # \u65b9\u6cd51 {0}\u5217\u8868\u5143\u7d20\u7684\u7d22\u5f15, {1}\u5143\u7ec4\u4e2d\u7b2c\u4e00\u4e2a\u503c, {2}\u5143\u7ec4\u4e2d\u7b2c\u4e8c\u4e2a\u503c print ( f ' { i } : { a } , { b } ' ) # \u65b9\u6cd52 # 0: foo, one # 1: bar, two # 2: baz, three \u7ed9\u5b9a\u4e00\u4e2a\u5df2\u201c\u914d\u5bf9\u201d\u7684\u5e8f\u5217\u65f6\uff0czip\u51fd\u6570\u53ef\u4ee5\u53bb\u201c\u62c6\u5206\u201d\u5e8f\u5217\u3002\u8fd9\u79cd\u65b9\u5f0f\u7684\u53e6\u4e00\u79cd\u601d\u8def\u5c31\u662f\u5c06\u884c\u7684\u5217\u8868\u8f6c\u6362\u4e3a\u5217\u7684\u5217\u8868\u3002\u53c2\u8003Python\u7684 Unpacking pitchers = [( 'Jack' , 'Ma' ), ( 'Tom' , 'Li' ), ( 'Jimmy' , 'Zhang' )] first_names , last_names = zip ( * pitchers ) print ( first_names ) # ('Jack', 'Tom', 'Jimmy') print ( last_names ) # ('Ma', 'Li', 'Zhang') reversed\u51fd\u6570\u5c06\u5e8f\u5217\u7684\u5143\u7d20\u5012\u5e8f\u6392\u5217 print ( list ( reversed ( range ( 10 )))) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]","title":"2. \u5185\u7f6e\u5e8f\u5217\u51fd\u6570enumerate"},{"location":"python/Foundation/ch03/#3","text":"\u63a8\u5bfc\u5f0fcomprehensions\uff08\u53c8\u79f0\u89e3\u6790\u5f0f\uff09\uff0c\u662fPython\u7684\u4e00\u79cd\u7279\u6027\u3002\u4f7f\u7528\u63a8\u5bfc\u5f0f\u53ef\u4ee5\u5feb\u901f\u751f\u6210\u5217\u8868\u3001\u5143\u7ec4\u3001\u96c6\u5408\u3001\u5b57\u5178\u7c7b\u578b\u7684\u6570\u636e\u3002\u63a8\u5bfc\u5f0f\u53c8\u5206\u4e3a\u5217\u8868\u63a8\u5bfc\u5f0f\u3001\u5143\u7ec4\u63a8\u5bfc\u5f0f\u3001\u96c6\u5408\u63a8\u5bfc\u5f0f\u3001\u5b57\u5178\u63a8\u5bfc\u5f0f\u3002","title":"3. \u5217\u8868\u3001\u96c6\u5408\u548c\u5b57\u5178\u7684\u63a8\u5bfc\u5f0f"},{"location":"python/Foundation/ch03/#list-comprehension","text":"\u5217\u8868\u63a8\u5bfc\u5f0f(list comprehension)\u5141\u8bb8\u4f60\u8fc7\u6ee4\u4e00\u4e2a\u5bb9\u5668\u7684\u5143\u7d20\uff0c\u7528\u4e00\u79cd\u7b80\u660e\u7684\u8868\u8fbe\u5f0f\u8f6c\u6362\u4f20\u9012\u7ed9\u8fc7\u6ee4\u5668\u7684\u5143\u7d20\uff0c\u4ece\u800c\u751f\u6210\u4e00\u4e2a\u65b0\u7684\u5217\u8868\u3002 \u5217\u8868\u63a8\u5bfc\u5f0f\u7684\u57fa\u672c\u5f62\u5f0f\u4e3a\uff1a[expr for val in collection if condition]\uff0c\u6761\u4ef6if-condition\u4e0d\u662f\u5fc5\u987b\u7684\uff0c\u53ef\u4ee5\u53ea\u4fdd\u7559\u8868\u8fbe\u5f0f\u3002\u5217\u8868\u63a8\u5bfc\u5f0f\u4e0e\u4e0b\u9762\u7684for\u5faa\u73af\u662f\u7b49\u4ef7\u7684\uff1a result = [] for val in collection : if condition : result . append ( expr ) \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a data = [] for i in range ( - 5 , 5 ): if i >= - 1 : data . append ( i ** 2 ) print ( data ) # [1, 0, 1, 4, 9, 16] data = [ i ** 2 for i in range ( - 5 , 5 ) if i >= - 1 ] print ( data ) # [1, 0, 1, 4, 9, 16] \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u4f7f\u7528for\u53bb\u904d\u5386\u4e00\u4e2a\u53ef\u8fed\u4ee3\u7684\u5217\u8868\u3002 data = [] fruit = [ 'pomegranate' , 'cherry' , 'apricot' , 'date' , 'Apple' , 'lemon' , 'kiwi' , 'ORANGE' , 'lime' , 'Watermelon' , 'guava' , 'papaya' , 'FIG' , 'pear' , 'banana' , 'Tamarind' , 'persimmon' , 'elderberry' , 'peach' , 'BLUEberry' , 'lychee' , 'grape' ] data = [ x . upper () if x . startswith ( 'p' ) else x . title () for x in fruit ] print ( data ) # ['POMEGRANATE', 'Cherry', 'Apricot', 'Date', 'Apple', 'Lemon', 'Kiwi', 'Orange', 'Lime', 'Watermelon', 'Guava', 'PAPAYA', 'Fig', 'PEAR', 'Banana', 'Tamarind', 'PERSIMMON', 'Elderberry', 'PEACH', 'Blueberry', 'Lychee', 'Grape']","title":"\u5217\u8868\u63a8\u5bfc\u5f0f(list comprehension)"},{"location":"python/Foundation/ch03/#_1","text":"\u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u7528\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u4ee3\u66ff2\u5c42for\u5faa\u73af\u3002 data = [] for i in range ( 1 , 3 ): if i >= 0 : for j in range ( 1 , 3 ): data . append (( i , j )) print ( data ) # [(1, 1), (1, 2), (2, 1), (2, 2)] data = [( i , j ) for i in range ( 1 , 3 ) if i >= - 1 for j in range ( 1 , 3 )] print ( data ) # [(1, 1), (1, 2), (2, 1), (2, 2)] \u518d\u4e3e\u4e00\u4e2a\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u7684\u4f8b\u5b50\u3002 all_data = [ [ 'John' , 'Emily' , 'Michael' , 'Lee' , 'Steven' ], [ 'Maria' , 'Juan' , 'Javier' , 'Natalia' , 'Pilar' ], ] names_of_interest = [] for names in all_data : enough_es = [ name for name in names if name . count ( 'e' ) >= 2 ] names_of_interest . extend ( enough_es ) print ( names_of_interest ) # ['Lee', 'Steven'] result = [ name for names in all_data for name in names if name . count ( 'e' ) >= 2 ] print ( result ) # ['Lee', 'Steven'] \u7528\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u5c06\u77e9\u9635\u6241\u5e73\u5316\u3002 \u8003\u8651\u4e0b\u9762\u8fd9\u4e2a3x4\u7684\u77e9\u9635\uff0c\u5b83\u75313\u4e2a\u957f\u5ea6\u4e3a4\u7684\u5217\u8868\u7ec4\u6210\u3002\u4e0b\u9762\u4f8b\u5b50\u5bf9\u6bd4\u4e86\u7528\u4f20\u7edffor\u5faa\u73af\u5c06\u77e9\u9635\u6241\u5e73\u5316\uff0c\u548c\u7528\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u5c06\u77e9\u9635\u6241\u5e73\u5316\u3002\u5e76\u4e14\u901a\u8fc7\u5217\u8868\u63a8\u5bfc\u5f0f\u4e2d\u7684\u5217\u8868\u63a8\u5bfc\u5f0f\u5c06\u6241\u5e73\u77e9\u9635\u8fd8\u539f\u4e3a3x4\u77e9\u9635\u3002 matrix = [ [ 1 , 2 , 3 , 4 ], [ 5 , 6 , 7 , 8 ], [ 9 , 10 , 11 , 12 ], ] flattened = [] # \u4f20\u7edffor\u5faa\u73af\u5d4c\u5957 for m in matrix : for x in m : flattened . append ( x ) print ( flattened ) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] # \u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f flattened = [ x for m in matrix for x in m ] print ( flattened ) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] # \u5217\u8868\u63a8\u5bfc\u5f0f\u4e2d\u7684\u5217\u8868\u63a8\u5bfc\u5f0f z = [[ x for x in m ] for m in matrix ] print ( z ) # [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]","title":"\u5957\u5217\u8868\u63a8\u5bfc\u5f0f"},{"location":"python/Foundation/ch03/#_2","text":"\u4e0b\u9762\u7684\u4f8b\u5b50\u751f\u6210\u4e00\u4e2a\u5305\u542b\u6570\u5b571~5\u7684\u5143\u7ec4\u3002\u4ece\u7ed3\u679c\u53ef\u4ee5\u770b\u5230\uff0c\u5143\u7ec4\u63a8\u5bfc\u5f0f\u751f\u6210\u7684\u7ed3\u679c\u5e76\u4e0d\u662f\u4e00\u4e2a\u5143\u7ec4\uff0c\u800c\u662f\u4e00\u4e2a\u751f\u6210\u5668\u5bf9\u8c61\uff0c\u9700\u8981\u901a\u8fc7tuple()\u51fd\u6570\uff0c\u5c06\u751f\u6210\u5668\u5bf9\u8c61\u8f6c\u6362\u6210\u5143\u7ec4\u3002 data = ( x for x in range ( 5 )) print ( data ) # at 0x7f87217a8e40> print ( type ( data )) # print ( tuple ( data )) # (0, 1, 2, 3, 4)","title":"\u5143\u7ec4\u63a8\u5bfc\u5f0f"},{"location":"python/Foundation/ch03/#_3","text":"\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u96c6\u5408\u63a8\u5bfc\u5f0f\u4f8b\u5b50\u3002 data = { x ** 2 for x in range ( 5 )} print ( data ) # {0, 1, 4, 9, 16} print ( type ( data )) # \u96c6\u5408\u8981\u4fdd\u8bc1\u5143\u7d20\u5fc5\u987b\u662f\u552f\u4e00\u7684\u3002 data = ( 1 , 1 , 2 , 2 , 3 , 3 , 4 , 5 , 6 ) newset = { x ** 2 for x in data } print ( newset ) # {1, 4, 36, 9, 16, 25} print ( type ( newset ) # ","title":"\u96c6\u5408\u63a8\u5bfc\u5f0f"},{"location":"python/Foundation/ch03/#_4","text":"\u5b57\u5178\u63a8\u5bfc\u5f0f: dict_comp = {key-expr : value-expr for value in collection if condition} \u5b57\u5178\u63a8\u5bfc\u5f0f\u7684\u7b80\u5355\u793a\u4f8b\uff1a strings = [ 'a' , 'as' , 'bat' , 'car' , 'dove' , 'python' ] loc_mapping = { index : val for index , val in enumerate ( strings )} print ( loc_mapping ) # {0: 'a', 1: 'as', 2: 'bat', 3: 'car', 4: 'dove', 5: 'python'} # \u4ea4\u6362\u952e\u548c\u503c loc_mapping = { index : val for val , index in enumerate ( strings )} print ( loc_mapping ) # {'a': 0, 'as': 1, 'bat': 2, 'car': 3, 'dove': 4, 'python': 5}","title":"\u5b57\u5178\u63a8\u5bfc\u5f0f"},{"location":"python/Foundation/ch03/#4","text":"\u5982\u679cPython\u8fbe\u5230\u51fd\u6570\u7684\u5c3e\u90e8\u65f6\u4ecd\u7136\u6ca1\u6709\u9047\u5230return\u8bed\u53e5\uff0c\u5c31\u4f1a\u81ea\u52a8\u8fd4\u56deNone\u3002 \u6bcf\u4e2a\u51fd\u6570\u90fd\u53ef\u4ee5\u6709\u4f4d\u7f6e\u53c2\u6570\u548c\u5173\u952e\u5b57\u53c2\u6570\u3002\u5173\u952e\u5b57\u53c2\u6570\u6700\u5e38\u7528\u4e8e\u6307\u5b9a\u9ed8\u8ba4\u503c\u6216\u53ef\u9009\u53c2\u6570\u3002\u5173\u952e\u5b57\u53c2\u6570\u5fc5\u987b\u8ddf\u5728\u4f4d\u7f6e\u53c2\u6570\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u5173\u952e\u5b57\u53c2\u6570\u5411\u4f4d\u7f6e\u53c2\u6570\u4f20\u53c2\u3002 import sys def my_function1 ( x , y , z = 1.5 ): if z > 1 : return z * ( x + y ) else : return z / ( x + y ) result1 = my_function1 ( 5 , 6 , z = 0.7 ) print ( result1 ) # 0.06363636363636363 result1 = my_function1 ( x = 5 , y = 6 , z = 0.7 ) print ( result1 ) # 0.06363636363636363 result1 = my_function1 ( 3.14 , 7 , 3.5 ) print ( result1 ) # 35.49 result1 = my_function1 ( 10 , 20 ) print ( result1 ) # 45.0","title":"4. \u51fd\u6570\u58f0\u660e"},{"location":"python/Foundation/ch03/#5","text":"\u51fd\u6570\u6709\u4e24\u79cd\u8fde\u63a5\u53d8\u91cf\u7684\u65b9\u5f0f\uff1a\u5168\u5c40\u3001\u672c\u5730\u3002 def func1 (): list1 = [] # \u672c\u5730\u53d8\u91cf for i in range ( 5 ): list1 . append ( i ) print ( list1 ) func1 () # [0, 1, 2, 3, 4] list2 = [] # \u5168\u5c40\u53d8\u91cf def func2 (): global list2 # \u5168\u5c40\u53d8\u91cf for i in range ( 5 ): list2 . append ( i ) print ( list2 ) func2 () # [0, 1, 2, 3, 4] \u6570\u636e\u6e05\u6d17\u793a\u4f8b states = [ ' Alabama' , 'Georgia!' , 'georgia' , 'Georgia' , 'FlOrIda' , 'south carolina##' , 'West virginia? ' ] # \u65b9\u6cd51 import re def clean_string1 ( strings ): result2 = [] for value in strings : value = value . strip () value = re . sub ( '[! #? ]' , '' , value ) value = value . title () result2 . append ( value ) return result2 print ( clean_string1 (( states ))) # ['Alabama', 'Georgia', 'Georgia', 'Georgia', 'Florida', 'Southcarolina', 'Westvirginia'] # \u65b9\u6cd52 def remove_punctuaion ( value ): return re . sub ( '[! #? ]' , '' , value ) clean_ops = [ str . strip , remove_punctuaion , str . title ] def clean_string2 ( strings , ops ): result3 = [] for value in strings : for function in ops : value = function ( value ) result3 . append ( value ) return result3 result4 = clean_string2 ( states , clean_ops ) print ( result4 ) # ['Alabama', 'Georgia', 'Georgia', 'Georgia', 'Florida', 'Southcarolina', 'Westvirginia'] # \u53ef\u4ee5\u5c06\u51fd\u6570\u4f5c\u4e3a\u4e00\u4e2a\u53c2\u6570\u4f20\u7ed9\u5176\u4ed6\u7684\u51fd\u6570\u3002 for x in map ( remove_punctuaion , states ): print ( x ) # Alabama # Georgia # georgia # Georgia # FlOrIda # southcarolina # Westvirginia","title":"5. \u547d\u540d\u7a7a\u95f4\u3001\u4f5c\u7528\u57df\u548c\u672c\u5730\u51fd\u6570"},{"location":"python/Foundation/ch03/#6","text":"\u67ef\u91cc\u5316\u662f\u8ba1\u7b97\u673a\u79d1\u5b66\u672f\u8bed\uff08\u4ee5\u6570\u5b66\u5bb6Haskell Curry\u547d\u540d\uff09\uff0c\u5b83\u8868\u793a\u901a\u8fc7\u90e8\u5206\u53c2\u6570\u5e94\u7528\u7684\u65b9\u5f0f\u4ece\u5df2\u6709\u7684\u51fd\u6570\u4e2d\u884d\u751f\u51fa\u65b0\u7684\u51fd\u6570\u3002\u67ef\u91cc\u5316\u662f\u4e00\u79cd\u5c06\u591a\u53c2\u6570\u51fd\u6570\u8f6c\u5316\u4e3a\u5355\u53c2\u6570\u9ad8\u9636\u51fd\u6570\u7684\u6280\u672f\uff0c\u5982\u679c\u4f60\u56fa\u5b9a\u67d0\u4e9b\u53c2\u6570\uff0c\u4f60\u5c06\u5f97\u5230\u63a5\u53d7\u4f59\u4e0b\u53c2\u6570\u7684\u4e00\u4e2a\u51fd\u6570\u3002 \u5b9a\u4e49\u4e00\uff1a \u67ef\u91cc\u5316\uff1a\u4e00\u4e2a\u51fd\u6570\u4e2d\u6709\u4e2a\u591a\u4e2a\u53c2\u6570\uff0c\u60f3\u56fa\u5b9a\u5176\u4e2d\u67d0\u4e2a\u6216\u8005\u51e0\u4e2a\u53c2\u6570\u7684\u503c\uff0c\u800c\u53ea\u63a5\u53d7\u53e6\u5916\u51e0\u4e2a\u8fd8\u672a\u56fa\u5b9a\u7684\u53c2\u6570\uff0c\u8fd9\u6837\u51fd\u6570\u6f14\u53d8\u6210\u65b0\u7684\u51fd\u6570\u3002 \u5b9a\u4e49\u4e8c\uff1a \u51fd\u6570\u67ef\u91cc\u5316\uff08currying\uff09\u53c8\u79f0\u90e8\u5206\u6c42\u503c\u3002\u4e00\u4e2a currying \u7684\u51fd\u6570\u9996\u5148\u4f1a\u63a5\u53d7\u4e00\u4e9b\u53c2\u6570\uff0c\u63a5\u53d7\u4e86\u8fd9\u4e9b\u53c2\u6570\u4e4b\u540e\uff0c\u8be5\u51fd\u6570\u5e76\u4e0d\u4f1a\u7acb\u5373\u6c42\u503c\uff0c\u800c\u662f\u7ee7\u7eed\u8fd4\u56de\u53e6\u5916\u4e00\u4e2a\u51fd\u6570\uff0c\u521a\u624d\u4f20\u5165\u7684\u53c2\u6570\u5728\u51fd\u6570\u5f62\u6210\u7684\u95ed\u5305\u4e2d\u88ab\u4fdd\u5b58\u8d77\u6765\u3002\u5f85\u5230\u51fd\u6570\u88ab\u771f\u6b63\u9700\u8981\u6c42\u503c\u7684\u65f6\u5019\uff0c\u4e4b\u524d\u4f20\u5165\u7684\u6240\u6709\u53c2\u6570\u90fd\u4f1a\u88ab\u4e00\u6b21\u6027\u7528\u4e8e\u6c42\u503c\u3002 \u5b9a\u4e49\u4e09\uff1a \u4e00\u4e9b\u51fd\u6570\u5f0f\u8bed\u8a00\u7684\u5de5\u4f5c\u539f\u7406\u662f\u5c06\u591a\u53c2\u6570\u51fd\u6570\u8bed\u6cd5\u8f6c\u5316\u4e3a\u5355\u53c2\u6570\u51fd\u6570\u96c6\u5408\uff0c\u8fd9\u4e00\u8fc7\u7a0b\u79f0\u4e3a\u67ef\u91cc\u5316\uff0c\u5b83\u662f\u4ee5\u903b\u8f91\u5b66\u5bb6Haskell Curry\u7684\u540d\u5b57\u547d\u540d\u7684\u3002Haskell Curry\u4ece\u65e9\u671f\u6982\u5ff5\u4e2d\u53d1\u5c55\u51fa\u4e86\u8be5\u7406\u8bba\u3002\u5176\u5f62\u5f0f\u76f8\u5f53\u4e8e\u5c06z=f(x, y)\u8f6c\u6362\u6210z=f(x)(y)\u7684\u5f62\u5f0f\uff0c\u539f\u51fd\u6570\u7531\u4e24\u4e2a\u53c2\u6570\uff0c\u73b0\u5728\u53d8\u4e3a\u4e24\u4e2a\u63a5\u53d7\u5355\u53c2\u6570\u7684\u51fd\u6570\uff0c \u793a\u4f8b1\uff1a\u67ef\u91cc\u5316\u7684\u8fc7\u7a0b\u5c31\u662f\u628a\u539f\u6765\u5e26\u4e24\u4e2a\u53c2\u6570\u7684\u51fd\u6570add(x, y)\uff0c\u53d8\u6210\u4e86\u4e00\u4e2a\u5d4c\u5957\u51fd\u6570\uff0c\u5728add_currying\u51fd\u6570\u5185\uff0c\u53c8\u5b9a\u4e49\u4e86\u4e00\u4e2a_add\u51fd\u6570\uff0c\u5e76\u4e14_add\u51fd\u6570\u53c8\u5f15\u7528\u4e86\u5916\u90e8\u51fd\u6570add_currying\u7684\u53d8\u91cfx\uff0c\u8fd9\u5c31\u662f\u4e00\u4e2a\u95ed\u5305\u3002 \u95ed\u5305\uff0c\u4e00\u53e5\u8bdd\u8bf4\u5c31\u662f\u5728\u51fd\u6570\u4e2d\u518d\u5d4c\u5957\u4e00\u4e2a\u51fd\u6570\uff0c\u5e76\u4e14\u5f15\u7528\u5916\u90e8\u51fd\u6570\u7684\u53d8\u91cf\u3002 # \u666e\u901a\u5199\u6cd5 def add ( x , y ): return x + y print ( add ( 1 , 2 )) # 3 # \u67ef\u91cc\u5316\u5199\u6cd5 def add_currying ( x ): def _add ( y ): return x + y return _add print ( add_currying ( 1 )( 2 )) # 3 \u793a\u4f8b2\uff0c\u901a\u8fc7\u56fa\u5b9a\u5176\u4e2d\u7684\u7b2c\u4e8c\u4e2a\u53c2\u6570\u4e0d\u53d8\u6765\u5b9e\u73b0\u67ef\u91cc\u5316\u3002 def add2 ( a , b ): def add1 ( a , b , c ): return a + b + c return add1 ( a , 666 , b ) result6 = add2 ( 12 , 13 ) print ( result6 ) # 691 result6 = add2 ( 12 , 555 , 13 ) # TypeError: add2() takes 2 positional arguments but 3 were given \u793a\u4f8b3\uff0c\u901a\u8fc7functools\u63d0\u4f9b\u7684\u504f\u51fd\u6570\u6765\u5b9e\u73b0\u67ef\u91cc\u5316\u3002 from functools import partial def add1 ( a , b , c ): return a + b + c add3 = partial ( add1 , b = 666 ) result7 = add3 ( a = 12 , c = 13 ) print ( result7 ) # 691 \u793a\u4f8b4\uff0c\u901a\u8fc7lambda\u8868\u8fbe\u5f0f\u6765\u5b9e\u73b0\u67ef\u91cc\u5316\u3002 def add1 ( a , b , c ): return a + b + c add4 = lambda x , y : add1 ( x , 666 , y ) result8 = add4 ( 12 , 13 ) print ( result8 ) # 691 \u793a\u4f8b5\uff0c\u901a\u8fc7python\u7684\u88c5\u9970\u5668\u6765\u5b9e\u73b0\u67ef\u91cc\u5316 def add1 ( a , b , c ): return a + b + c def currying_add ( func ): def wrapper ( a , c , b = 666 ): return func ( a , b , c ) return wrapper result9 = currying_add ( add1 )( 12 , 13 ) print ( result9 ) # 691 \u793a\u4f8b6\uff0c\u901a\u8fc7python\u7684\u88c5\u9970\u5668\u7b26\u53f7@\u6765\u5b9e\u73b0\u67ef\u91cc\u5316 def currying_add ( func ): def wrapper ( a , c , b = 666 ): return func ( a , b , c ) return wrapper @currying_add def add5 ( a , b , c ): return a + b + c result10 = add5 ( 12 , 13 ) print ( result10 ) # 691","title":"6. \u67ef\u91cc\u5316\uff1a\u90e8\u5206\u53c2\u6570\u5e94\u7528"},{"location":"python/Foundation/ch03/#7","text":"","title":"7. \u8fed\u4ee3\u5668\u4e0e\u751f\u6210\u5668"},{"location":"python/Foundation/ch03/#_5","text":"\u8fed\u4ee3\u662fPython\u6700\u5f3a\u5927\u7684\u529f\u80fd\u4e4b\u4e00\uff0c\u662f\u8bbf\u95ee\u96c6\u5408\u5143\u7d20\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u8fed\u4ee3\u5668\u662f\u4e00\u4e2a\u53ef\u4ee5\u8bb0\u4f4f\u904d\u5386\u7684\u4f4d\u7f6e\u7684\u5bf9\u8c61\u3002 \u8fed\u4ee3\u5668\u5bf9\u8c61\u4ece\u96c6\u5408\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\u8bbf\u95ee\uff0c\u76f4\u5230\u6240\u6709\u7684\u5143\u7d20\u88ab\u8bbf\u95ee\u5b8c\u7ed3\u675f\u3002\u8fed\u4ee3\u5668\u53ea\u80fd\u5f80\u524d\u4e0d\u4f1a\u540e\u9000\u3002 \u8fed\u4ee3\u5668\u6709\u4e24\u4e2a\u57fa\u672c\u7684\u65b9\u6cd5\uff1aiter() \u548c next()\u3002 \u8fed\u4ee3\u5668\u793a\u4f8b\uff1a list_a = [ 1 , 2 , 3 , 4 ] it = iter ( list_a ) # \u521b\u5efa\u8fed\u4ee3\u5668\u5bf9\u8c61 print ( next ( it )) # \u8f93\u51fa\u8fed\u4ee3\u5668\u7684\u4e0b\u4e00\u4e2a\u5143\u7d20 # 1 print ( next ( it )) # \u8f93\u51fa\u8fed\u4ee3\u5668\u7684\u4e0b\u4e00\u4e2a\u5143\u7d20 # 2 \u8fed\u4ee3\u5668\u5bf9\u8c61\u53ef\u4ee5\u4f7f\u7528\u5e38\u89c4for\u8bed\u53e5\u8fdb\u884c\u904d\u5386\u3002 list_a = [ 1 , 2 , 3 , 4 ] it = iter ( list_a ) # \u521b\u5efa\u8fed\u4ee3\u5668\u5bf9\u8c61 for x in it : print ( x , end = \" \" ) print ( end = \" \\n \" ) # 1 2 3 4","title":"\u8fed\u4ee3\u5668"},{"location":"python/Foundation/ch03/#_6","text":"\u5728 Python \u4e2d\uff0c\u4f7f\u7528\u4e86 yield \u7684\u51fd\u6570\u88ab\u79f0\u4e3a\u751f\u6210\u5668\uff08generator\uff09\u3002\u8ddf\u666e\u901a\u51fd\u6570\u4e0d\u540c\u7684\u662f\uff0c\u751f\u6210\u5668\u662f\u4e00\u4e2a\u8fd4\u56de\u8fed\u4ee3\u5668\u7684\u51fd\u6570\uff0c\u53ea\u80fd\u7528\u4e8e\u8fed\u4ee3\u64cd\u4f5c\uff0c\u751f\u6210\u5668\u5c31\u662f\u4e00\u4e2a\u8fed\u4ee3\u5668\u3002 \u5728\u8c03\u7528\u751f\u6210\u5668\u8fd0\u884c\u7684\u8fc7\u7a0b\u4e2d\uff0c\u6bcf\u6b21\u9047\u5230 yield \u65f6\u51fd\u6570\u4f1a\u6682\u505c\u5e76\u4fdd\u5b58\u5f53\u524d\u6240\u6709\u7684\u8fd0\u884c\u4fe1\u606f\uff0c\u8fd4\u56de yield \u7684\u503c, \u5e76\u5728\u4e0b\u4e00\u6b21\u6267\u884c next() \u65b9\u6cd5\u65f6\u4ece\u5f53\u524d\u4f4d\u7f6e\u7ee7\u7eed\u8fd0\u884c\u3002 \u8c03\u7528\u4e00\u4e2a\u751f\u6210\u5668\u51fd\u6570\uff0c\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u8fed\u4ee3\u5668\u5bf9\u8c61\u3002 \u793a\u4f8b, \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a def fibonacci ( n ): a , b , counter = 0 , 1 , 0 while True : if ( counter > n ): return yield a a , b = b , a + b counter += 1 f = fibonacci ( 10 ) # f \u662f\u4e00\u4e2a\u8fed\u4ee3\u5668\uff0c\u7531\u751f\u6210\u5668\u8fd4\u56de\u751f\u6210 print ( f ) # \u5b9e\u9645\u8c03\u7528\u751f\u6210\u5668\u65f6\uff0c\u4ee3\u7801\u5e76\u4e0d\u4f1a\u7acb\u5373\u6267\u884c for x in f : # \u8bf7\u6c42\u751f\u6210\u5668\u4e2d\u7684\u5143\u7d20\u65f6\uff0c\u5b83\u624d\u4f1a\u6267\u884c\u5b83\u7684\u4ee3\u7801 print ( x , end = \" \" ) print ( end = \" \\n \" ) # 0 1 1 2 3 5 8 13 21 34 55 \u751f\u6210\u5668\u8868\u8fbe\u5f0f\uff1a \u7528\u751f\u6210\u5668\u8868\u8fbe\u5f0f\u6765\u521b\u5efa\u751f\u6210\u5668\u66f4\u4e3a\u7b80\u5355\u3002\u751f\u6210\u5668\u8868\u8fbe\u5f0f\u4e0e\u5217\u8868\u3001\u5b57\u5178\u3001\u96c6\u5408\u7684\u63a8\u5bfc\u5f0f\u5f88\u7c7b\u4f3c\uff0c\u521b\u5efa\u4e00\u4e2a\u751f\u6210\u5668\u8868\u8fbe\u5f0f\uff0c\u53ea\u9700\u8981\u5c06\u5217\u8868\u63a8\u5bfc\u5f0f\u7684\u4e2d\u62ec\u53f7\u66ff\u6362\u4e3a\u5c0f\u62ec\u53f7\u5373\u53ef\u3002 gen1 = ( x ** 2 for x in range ( 100 )) print ( gen1 ) # at 0x7fd3f30c9580> \u4e0a\u9762\u7684\u4ee3\u7801\u4e0e\u4e0b\u9762\u7684\u751f\u6210\u5668\u662f\u7b49\u4ef7\u7684 def _make_gen (): for x in range ( 100 ): yield x ** 2 gen2 = _make_gen () print ( gen2 ) # \u751f\u6210\u5668\u8868\u8fbe\u5f0f\u53ef\u4ee5\u4f5c\u4e3a\u51fd\u6570\u53c2\u6570\u7528\u4e8e\u66ff\u4ee3\u5217\u8868\u63a8\u5bfc\u5f0f\u3002\u5bf9\u6bd4\u4e0b\u97622\u4e2a\u4f8b\u5b50\u3002 # \u793a\u4f8b1 result11 = sum ( x ** 2 for x in range ( 100 )) print ( result11 ) # 328350 gen1 = ( x ** 2 for x in range ( 100 )) result11 = sum ( gen1 ) print ( result11 ) # 328350 # \u793a\u4f8b2 result12 = dict (( i , i ** 2 ) for i in range ( 5 )) print ( result12 ) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} gen2 = (( i , i ** 2 ) for i in range ( 5 )) result12 = dict ( gen2 ) print ( result12 ) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}","title":"\u751f\u6210\u5668"},{"location":"python/Foundation/ch03/#itertools","text":"\u6807\u51c6\u5e93\u4e2d\u7684itertools\u6a21\u5757\u662f\u9002\u7528\u4e8e\u5927\u591a\u6570\u6570\u636e\u7b97\u6cd5\u7684\u751f\u6210\u5668\u96c6\u5408\u3002 import itertools first_letter = lambda x : x [ 0 ] names = [ 'Alan' , 'Adam' , 'Wes' , 'Will' , 'Albert' , 'Steven' ] for letter , names in itertools . groupby ( names , first_letter ): print ( letter ) print ( first_letter ) print ( letter , list ( names )) # names is generator # A # at 0x7fa598a7a0d0> # A ['Alan', 'Adam'] # W # at 0x7fa598a7a0d0> # W ['Wes', 'Will'] # A # at 0x7fa598a7a0d0> # A ['Albert'] # S # at 0x7fa598a7a0d0> # S ['Steven']","title":"\u751f\u6210\u5668\uff1aitertools\u6a21\u5757"},{"location":"python/Foundation/ch03/#8","text":"Python\u7528\u5f02\u5e38\u5bf9\u8c61(exception object)\u6765\u8868\u793a\u5f02\u5e38\u60c5\u51b5\u3002\u9047\u5230\u9519\u8bef\u540e\uff0c\u4f1a\u5f15\u53d1\u5f02\u5e38\u3002\u5982\u679c\u5f02\u5e38\u5bf9\u8c61\u5e76\u672a\u88ab\u5904\u7406\u6216\u6355\u6349\uff0c\u7a0b\u5e8f\u5c31\u4f1a\u7528\u6240\u8c13\u7684\u56de\u6eaf(traceback\uff0c \u4e00\u79cd\u9519\u8bef\u4fe1\u606f)\u7ec8\u6b62\u6267\u884c\u3002 \u5f02\u5e38\u548c\u8bed\u6cd5\u9519\u8bef\u662f\u6709\u533a\u522b\u7684\u3002 \u9519\u8bef\uff1a\u662f\u6307\u4ee3\u7801\u4e0d\u7b26\u5408\u89e3\u91ca\u5668\u6216\u8005\u7f16\u8bd1\u5668\u8bed\u6cd5\u3002 \u5f02\u5e38\uff1a\u662f\u6307\u4e0d\u5b8c\u6574\u3001\u4e0d\u5408\u6cd5\u8f93\u5165\uff0c\u6216\u8005\u8ba1\u7b97\u51fa\u73b0\u9519\u8bef\u3002 python\u91cc\u7528try...except...\u8bed\u53e5\u6765\u5904\u7406\u5f02\u5e38\u60c5\u51b5\u3002 def attempt_float ( x ): try : return float ( x ) except ( TypeError , ValueError ): return \"Type error, not numbers\" r1 = attempt_float ( '1.2256' ) print ( r1 ) # 1.2256 r1 = attempt_float ( 'friends' ) print ( r1 ) # Type error, not numbers","title":"8. \u9519\u8bef\u548c\u5f02\u5e38\u5904\u7406"},{"location":"python/Foundation/ch03/#9","text":"f=open(path, 'w')\uff0c\u4e00\u4e2a\u65b0\u7684\u6587\u4ef6\u4f1a\u5728path\u6307\u5b9a\u7684\u8def\u5f84\u88ab\u521b\u5efa\uff0c\u5e76\u5728\u540c\u4e00\u8def\u5f84\u4e0b\u8986\u76d6\u540c\u540d\u6587\u4ef6\u3002\uff08\u8bf7\u5c0f\u5fc3\uff01\uff09 f=open(path, 'x')\uff0c\u4e00\u4e2a\u65b0\u7684\u6587\u4ef6\u4f1a\u5728path\u6307\u5b9a\u7684\u8def\u5f84\u88ab\u521b\u5efa\uff0c\u5982\u679c\u7ed9\u5b9a\u8def\u5f84\u4e0b\u5df2\u7ecf\u5b58\u5728\u540c\u540d\u6587\u4ef6\u5c31\u4f1a\u521b\u5efa\u5931\u8d25\u3002 import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f = open ( path ) # \u8bfb\u53d6\u6587\u4ef6\u6bcf\u4e00\u884c\uff0c\u6587\u4ef6\u6bcf\u4e00\u884c\u4f5c\u4e3a\u5217\u8868\u4e00\u4e2a\u5143\u7d20 lines = [ x . rstrip () for x in open ( path )] # \u8f93\u51fa\u5217\u8868 print ( lines ) # \u5173\u95ed\u6587\u4ef6\u4f1a\u5c06\u8d44\u6e90\u91ca\u653e\u56de\u64cd\u4f5c\u7cfb\u7edf f . close () \u53e6\u4e00\u79cd\u66f4\u7b80\u5355\u7684\u5173\u95ed\u6587\u4ef6\u7684\u65b9\u5f0f import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f = open ( path ) # \u4f7f\u7528with\u8bed\u53e5\u8bfb\u53d6\u6587\u4ef6\uff0c\u6587\u4ef6\u4f1a\u5728with\u4ee3\u7801\u5757\u7ed3\u675f\u540e\u81ea\u52a8\u5173\u95ed\u3002 with open ( path ) as f : lines = [ x . rstrip () for x in open ( path )] # \u8f93\u51fa\uff1a\u6587\u4ef6\u6bcf\u4e00\u884c\u4f5c\u4e3a\u5217\u8868\u4e00\u4e2a\u5143\u7d20 print ( lines ) \u5728\u6253\u5f00\u6587\u4ef6\u65f6\u4f7f\u7528seek\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u8981\u5f53\u5fc3\u3002\u5982\u679c\u6587\u4ef6\u7684\u53e5\u67c4\u4f4d\u7f6e\u6070\u597d\u5728\u4e00\u4e2aUnicode\u7b26\u53f7\u7684\u5b57\u8282\u4e2d\u95f4\u65f6\uff0c\u540e\u7eed\u7684\u8bfb\u53d6\u4f1a\u5bfc\u81f4\u9519\u8bef\u3002 import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f = open ( path ) # \u8bfb\u53d6\u6587\u4ef6\u3002 print ( f . read ( 5 )) # \u8f93\u51fa\u524d5\u4e2a\u5b57\u7b26\u3002 read\u65b9\u6cd5\u901a\u8fc7\u8bfb\u53d6\u7684\u5b57\u8282\u6570\u6765\u63a8\u8fdb\u6587\u4ef6\u53e5\u67c4\u7684\u4f4d\u7f6e\u3002 # I Thi print ( f . tell ()) # tell\u65b9\u6cd5\u53ef\u4ee5\u7ed9\u51fa\u53e5\u67c4\u5f53\u524d\u7684\u4f4d\u7f6e # 5 print ( f . seek ( 6 )) # seek\u65b9\u6cd5\u53ef\u4ee5\u5c06\u53e5\u67c4\u4f4d\u7f6e\u6539\u53d8\u5230\u6587\u4ef6\u4e2d\u7279\u5b9a\u7684\u5b57\u8282 # 6 print ( f . read ( 1 )) # \u4ece\u7b2c7\u4e2a\u5b57\u8282\u5f00\u59cb\uff0c\u8f93\u51fa1\u4e2a\u5b57\u8282 # k # \u5173\u95ed\u6587\u4ef6\u4f1a\u5c06\u8d44\u6e90\u91ca\u653e\u56de\u64cd\u4f5c\u7cfb\u7edf f . close () \u5982\u679c\u4f7f\u7528\u4e8c\u8fdb\u5236\u65b9\u5f0f\u6253\u5f00\u6587\u4ef6\uff0c\u5219\uff1a import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f2 = open ( path , 'rb' ) # \u4e8c\u8fdb\u5236\u6a21\u5f0f # \u8bfb\u53d6\u6587\u4ef6 print ( f2 . read ( 5 )) # \u7b2c\u4e00\u4e2ab\u4ee3\u8868\u4e8c\u8fdb\u5236\u683c\u5f0f # b'I Thi' print ( f2 . tell ()) # 5 print ( f2 . seek ( 6 )) # 6 print ( f2 . read ( 2 )) # \u4ece\u7b2c7\u4e2a\u5b57\u8282\u5f00\u59cb\uff0c\u8f93\u51fa2\u4e2a\u5b57\u8282 # b'k ' # \u5173\u95ed\u6587\u4ef6\u4f1a\u5c06\u8d44\u6e90\u91ca\u653e\u56de\u64cd\u4f5c\u7cfb\u7edf f2 . close () \u5c06\u672c\u6587\u5199\u5165\u6587\u4ef6\uff0c\u53ef\u4ee5\u4f7f\u7528\u6587\u4ef6\u5bf9\u8c61\u7684write\u6216wirtelines\u65b9\u6cd5\u3002 import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path1 = 'file01.txt' path2 = 'file02.txt' # file02.txt\u662f\u4e00\u4e2a\u7a7a\u6587\u4ef6 with open ( path2 , 'r+' , encoding = 'utf-8' ) as f : f . writelines ( x for x in open ( path1 , 'r' , encoding = 'utf-8' ) if len ( x ) > 1 ) # \u628afile01.txt\u7684\u5185\u5bb9\u5199\u5165file02.txt lines = f . readlines () print ( lines )","title":"9. \u6587\u4ef6\u4e0e\u64cd\u4f5c\u7cfb\u7edf"},{"location":"python/Foundation/ch03/#10","text":"","title":"10. \u88c5\u9970\u5668"},{"location":"python/Foundation/ch03/#_7","text":"\u7ef4\u57fa\u767e\u79d1\u4e2d\u7684\u89e3\u91ca\uff1a \u95ed\u5305\uff08Closure\uff09 \uff0c\u53c8\u79f0\u8bcd\u6cd5\u95ed\u5305\uff08Lexical Closure\uff09\u6216\u51fd\u6570\u95ed\u5305\uff08function closures\uff09\uff0c\u662f\u5f15\u7528\u4e86\u81ea\u7531\u53d8\u91cf\u7684\u51fd\u6570\u3002\u8fd9\u4e2a\u88ab\u5f15\u7528\u7684\u81ea\u7531\u53d8\u91cf\u5c06\u548c\u8fd9\u4e2a\u51fd\u6570\u4e00\u540c\u5b58\u5728\uff0c\u5373\u4f7f\u5df2\u7ecf\u79bb\u5f00\u4e86\u521b\u9020\u5b83\u7684\u73af\u5883\u4e5f\u4e0d\u4f8b\u5916\u3002 \u95ed\u5305\u5ef6\u4f38\u4e86\u4f5c\u7528\u57df\u7684\u51fd\u6570\uff0c\u5176\u4e2d\u5305\u542b\u51fd\u6570\u5b9a\u4e49\u4f53\u4e2d\u5f15\u7528\u3001\u4f46\u662f\u4e0d\u5728\u5b9a\u4e49\u4f53\u4e2d\u5b9a\u4e49\u7684\u975e\u5168\u5c40\u53d8\u91cf\u3002\u51fd\u6570\u662f\u4e0d\u662f\u533f\u540d\u7684\u6ca1\u6709\u5173\u7cfb\uff0c\u5173\u952e\u662f\u5b83\u80fd\u8bbf\u95ee\u5b9a\u4e49\u4f53\u4e4b\u5916\u5b9a\u4e49\u7684\u975e\u5168\u5c40\u53d8\u91cf\u3002 \u4f8b\u4e00\uff0c\u8ba1\u7b97\u79fb\u52a8\u5e73\u5747\u503c\u3002 \u4e0b\u9762\u662f\u662f\u4f20\u7edf\u7c7b\u5b9e\u73b0\u65b9\u5f0f\uff0cAvg\u7684\u5b9e\u4f8b\u662f\u53ef\u8c03\u7528\u7684\u5bf9\u8c61\u3002 class Avg (): def __init__ ( self ): self . mylist = [] def __call__ ( self , newValue ): self . mylist . append ( newValue ) total = sum ( self . mylist ) return total / len ( self . mylist ) avg = Avg () avg ( 10 ) # 10.0 avg ( 20 ) # 15.0 avg ( 30 ) # 20.0 \u4e0b\u9762\u662f\u9ad8\u9636\u51fd\u6570\u5b9e\u73b0\u65b9\u5f0f\u3002\u8c03\u7528 make_avg \u65f6\uff0c\u8fd4\u56de\u4e00\u4e2a my_avg \u51fd\u6570\u5bf9\u8c61\u3002\u6bcf\u6b21\u8c03\u7528 my_avg \u65f6\uff0c\u5b83\u4f1a\u628a\u53c2\u6570\u6dfb\u52a0\u5230\u7cfb\u5217\u503c\u4e2d\uff0c\u7136\u540e\u8ba1\u7b97\u5f53\u524d\u5e73\u5747\u503c\u3002 def make_avg (): my_list = [] def avg ( newValue ): my_list . append ( newValue ) total = sum ( my_list ) return total / len ( my_list ) return avg my_avg = make_avg () my_avg ( 10 ) # 10.0 my_avg ( 20 ) # 15.0 my_avg ( 30 ) # 20.0 my_avg . __code__ . co_varnames # ('newValue', 'total') my_avg . __code__ . co_freevars # ('my_list',) my_avg . __closure__ # (,) my_avg . __closure__ [ 0 ] . cell_contents # [10, 20, 30] \u8fd9\u4e24\u4e2a\u793a\u4f8b\u6709\u5171\u901a\u4e4b\u5904\uff1a\u8c03\u7528 Avg() \u6216 make_avg() \u5f97\u5230\u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61 avg \uff0c\u5b83\u4f1a\u66f4\u65b0\u5386\u53f2\u503c\uff0c\u7136\u540e\u8ba1\u7b97\u5f53\u524d\u5747\u503c\u3002 \u5728\u7c7b\u5b9e\u73b0\u4e2d\uff0c avg \u662f Avg \u7684\u5b9e\u4f8b\uff1b\u5728\u9ad8\u9636\u51fd\u6570\u5b9e\u73b0\u4e2d\u662f\u5185\u90e8\u51fd\u6570 avg \u3002 \u4e24\u79cd\u5b9e\u73b0\u65b9\u5f0f\u4e2d\uff0c\u6211\u4eec\u90fd\u53ea\u9700\u8c03\u7528 avg(n) \uff0c\u628a n \u653e\u5165\u7cfb\u5217\u503c\u4e2d\uff0c\u7136\u540e\u91cd\u65b0\u8ba1\u7b97\u5747\u503c\u3002 \u7b2c\u4e00\u4e2a\u4f8b\u5b50\u4e2d\uff0c Avg \u7c7b\u7684\u5b9e\u4f8b avg \u5728 self.series \u5b9e\u4f8b\u5c5e\u6027\u4e2d\u5b58\u50a8\u5386\u53f2\u503c\u3002 \u7b2c\u4e8c\u4e2a\u4f8b\u5b50\u4e2d\u7684 my_list \u662f\u51fd\u6570 make_avg() \u7684\u5c40\u90e8\u53d8\u91cf\uff0c\u4e5f\u79f0\u4e3a\u8be5\u51fd\u6570\u7684**\u81ea\u7531\u53d8\u91cf\uff08free variable\uff09**\uff0c\u6307\u672a\u5728\u672c\u5730\u4f5c\u7528\u57df\u4e2d\u7ed1\u5b9a\u7684\u53d8\u91cf\u3002 avg() \u51fd\u6570\u7684\u95ed\u5305\u5ef6\u4f38\u5230\u51fd\u6570\u7684\u4f5c\u7528\u57df\u4e4b\u5916\uff0c\u5305\u542b\u4e86 make_avg() \u7684\u81ea\u7531\u53d8\u91cf my_list \u7684\u7ed1\u5b9a\u3002 \u5bf9\u4e8e\u8fd4\u56de\u7684 my_avg \u5bf9\u8c61\uff0c\u5176 __code__ \u5c5e\u6027\uff08\u8868\u793a\u7f16\u8bd1\u540e\u7684\u51fd\u6570\u5b9a\u4e49\u4f53\uff09\u4e2d\u4fdd\u5b58\u4e86\u5c40\u90e8\u53d8\u91cf\u548c\u81ea\u7531\u53d8\u91cf\u7684\u540d\u79f0\uff0c\u5373 my_avg.__code__.co_varnames \u8fd4\u56de\u4e86\u5c40\u90e8\u53d8\u91cf ('newValue', 'total') \u548c my_avg.__code__.co_freevars \u8fd4\u56de\u4e86\u81ea\u7531\u53d8\u91cf ('my_list',) \u3002 \u81ea\u7531\u53d8\u91cf my_list \u7ed1\u5b9a\u5728\u8fd4\u56de\u7684 my_avg \u7684 __closure__ \u7684\u5c5e\u6027\u4e2d\uff0c my_avg.__closure__ \u4e2d\u7684\u5404\u4e2a\u5143\u7d20\u5bf9\u5e94\u4e86 my_avg.__code__.co_freevars \u4e2d\u7684\u4e00\u4e2a\u540d\u79f0\u3002\u8fd9\u4e9b\u5143\u7d20\u662f cell \u5bf9\u8c61\uff0c\u6709\u4e2a cell_contents \u5c5e\u6027\uff0c\u5982\uff1a my_avg.__closure__ \u8fd4\u56de (,) \uff0c\u91cc\u9762\u4fdd\u5b58\u7740\u771f\u6b63\u7684\u503c\uff0c\u5982 my_avg.__closure__[0].cell_contents \u91cc\u9762\u4fdd\u5b58\u6bcf\u6b21\u8c03\u7528\u7684\u771f\u5b9e\u503c [10, 20, 30] \u3002 \u4e0a\u9762 my_list \u662f\u4e00\u4e2a\u53ef\u53d8\u7c7b\u578b\uff0c\u5982\u679c\u7528\u4e0d\u53ef\u53d8\u7c7b\u578b\u6539\u5199\uff0c\u5e76\u5b9e\u73b0\u95ed\u5305\uff0c\u53ef\u4ee5\u4f7f\u7528 nolocal \u8fdb\u884c\u58f0\u660e\u3002\u5b83\u7684\u4f5c\u7528\u662f\u628a\u53d8\u91cf\u6807\u8bb0\u4e3a\u81ea\u7531\u53d8\u91cf\uff0c\u5373\u4f7f\u5728\u51fd\u6570\u4e2d\u4e3a\u53d8\u91cf\u8d4b\u4e88\u65b0\u503c\u4e86\uff0c\u4e5f\u4f1a\u53d8\u6210\u81ea\u7531\u53d8\u91cf\u3002\u5982\u679c\u4e3anonlocal\u58f0\u660e\u7684\u53d8\u91cf\u8d4b\u4e88\u65b0\u503c\uff0c\u95ed\u5305\u4e2d\u4fdd\u5b58\u7684\u7ed1\u5b9a\u4f1a\u66f4\u65b0\u3002 my_avg.__code__.co_freevars \u8fd4\u56de\u4e862\u4e2a\u81ea\u7531\u53d8\u91cf ('count', 'total') \uff0c\u5e76\u5728 my_avg.__closure__[0].cell_contents \u548c my_avg.__closure__[1].cell_contents \u91cc\u9762\u4fdd\u5b58\u4e86\u6700\u540e\u4e00\u6b21\u6267\u884c\u7684\u771f\u5b9e\u503c\u3002 def make_avg (): count = 0 total = 0 def avg ( newValue ): nonlocal count , total count += 1 total += newValue return total / count return avg my_avg = make_avg () my_avg ( 10 ) # 10.0 my_avg ( 20 ) # 15.0 my_avg ( 30 ) # 20.0 my_avg . __code__ . co_varnames # ('newValue',) my_avg . __code__ . co_freevars # ('count', 'total') my_avg . __closure__ # (, ) my_avg . __closure__ [ 0 ] . cell_contents # 3 my_avg . __closure__ [ 1 ] . cell_contents # 60 \u4f8b\u4e8c\uff1a money \u662f\u4e00\u4e2a\u5c40\u90e8\u53d8\u91cf\uff0c\u5728 get_money \u662f\u5916\u56f4\u51fd\u6570\uff0c\u51fd\u6570\u6267\u884c\u4e4b\u540e\u5e94\u8be5\u5c31\u4e0d\u4f1a\u5b58\u5728\u4e86\u3002 \u4f46\u662f\u5d4c\u5957\u51fd\u6570 work \u5f15\u7528\u4e86 money \u8fd9\u4e2a\u81ea\u7531\u53d8\u91cf\uff0c\u5c06\u8fd9\u4e2a\u5c40\u90e8\u53d8\u91cf\u5c01\u95ed\u5728\u4e86\u5d4c\u5957\u51fd\u6570 work \u4e2d\uff0c\u8fd9\u6837\u5c31\u5f62\u6210\u4e86\u4e00\u4e2a\u95ed\u5305\u3002 closure = get_money() \u83b7\u5f97\u7684\u5c31\u662f\u4e00\u4e2a\u95ed\u5305\u3002 closure() \u8f93\u51fa\u95ed\u5305\uff0c\u5373\uff0c\u6267\u884c\u4e86 work() \uff0c\u6253\u5370\u8f93\u51fa money \u7684\u503c\u3002 \u672c\u5730\u51fd\u6570\u901a\u8fc7global\u58f0\u660e\u5bf9\u5168\u5c40\u53d8\u91cf\u8fdb\u884c\u5f15\u7528\u4fee\u6539\uff0c\u90a3\u4e48\u5bf9\u4e8e\u5185\u5d4c\u51fd\u6570 work() \u4f5c\u7528\u57df\u4e2d\u7684\u53d8\u91cf\u8fdb\u884c\u4fee\u6539\uff0c\u5c31\u8981\u4f7f\u7528 nonlocal \u8fdb\u884c\u58f0\u660e\u3002 def get_money (): money = 0 def work (): nonlocal money money += 100 print ( money ) return work closure = get_money () closure () # 100 closure () # 200 closure () # 300 \u4f8b\u4e09\uff1a \u51fd\u6570 maker \u4e2d\u5b9a\u4e49\u4e86\u51fd\u6570 action \uff0c action \u5f15\u7528\u4e86 maker \u5d4c\u5957\u4f5c\u7528\u57df\u5185\u7684\u53d8\u91cf k \uff0c\u5e76\u4e14\uff0c maker \u5c06\u51fd\u6570 action \u4f5c\u4e3a\u8fd4\u56de\u5bf9\u8c61\u8fdb\u884c\u8fd4\u56de\u3002 \u8fd9\u6837\uff0c\u6211\u4eec\u901a\u8fc7\u6267\u884c f = maker(2) \uff0c f \u83b7\u53d6\u4e86\u8fd4\u56de\u5bf9\u8c61 action \uff0c\u867d\u7136\u6b64\u65f6 maker \u51fd\u6570\u4ee5\u53ca\u7ed3\u675f\u9000\u51fa\u4e86\uff0c\u4f46\u5bf9\u8c61 f \u4ecd\u7136\u8bb0\u4f4f\u4e86\u51fd\u6570 maker \u5d4c\u5957\u4f5c\u7528\u57df\u5185\u7684\u53d8\u91cf k \u548c n \uff0c\u5e76\u5728\u6267\u884c f(3) \u65f6\uff0c\u5c06 x=3 \u4ee5\u53ca\u4e4b\u524d\u8bb0\u4f4f\u7684 k \u548c n \uff0c\u4e00\u5e76\u4f20\u5165 action() \uff0c\u8ba1\u7b97\u5e76\u8fd4\u56de x + n + k \u503c\u3002 make \u4e5f\u79f0\u4e3a**\u5de5\u5382\u51fd\u6570**\u3002 def maker ( n ): k = 8 def action ( x ): return x + n + k return action f = maker ( 2 ) print ( f ( 3 )) # 13 print ( f ( 4 )) # 14 print ( f ( 5 )) # 15 \u7ed3\u5408\u524d\u97622\u4e2a\u4f8b\u5b50\u518d\u770b\u4e0a\u9762\u7684\u89e3\u91ca\uff0c\u95ed\u5305\u5c31\u662f\u5f15\u7528\u4e86\u81ea\u7531\u53d8\u91cf\u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u4fdd\u5b58\u4e86\u6267\u884c\u7684\u4e0a\u4e0b\u6587\uff0c\u53ef\u4ee5\u8131\u79bb\u539f\u672c\u7684\u4f5c\u7528\u57df\u72ec\u7acb\u5b58\u5728\u3002","title":"\u95ed\u5305"},{"location":"python/Foundation/ch03/#_8","text":"\u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u5c06\u51fd\u6570\u4f5c\u4e3a\u53c2\u6570\u4f20\u7ed9\u53e6\u4e00\u4e2a\u51fd\u6570\uff0c\u51fd\u6570 my_decorator \u7684\u4f20\u5165\u53c2\u6570\u6b63\u597d\u662f\u5176\u5d4c\u5957\u51fd\u6570 myFunc \u3002 def my_decorator ( nestedFunc ): def myFunc (): print ( \"Before executing nestedFunc()\" ) nestedFunc () print ( \"After executing nestedFunc()\" ) return myFunc def nestedFunc (): print ( \"Decoration - executing nestedFunc()\" ) nestedFunc () # Decoration - executing nestedFunc() nestedFunc = my_decorator ( nestedFunc ) nestedFunc () # Before executing nestedFunc() # Decoration - executing nestedFunc() # After executing nestedFunc() \u88c5\u9970\u5668\u53ea\u662f\u4e2a\u65b9\u6cd5\uff0c\u4f7f\u7528\u65f6\u7528\u4e86 @ \u8bed\u6cd5\u3002 @ \u8bed\u6cd5\u53ea\u662f\u5c06\u51fd\u6570 nestedFunc \u4f20\u5165\u88c5\u9970\u5668\u51fd\u6570 my_decorator \u3002 @my_decorator \u662f nestedFunc = my_decorator(nestedFunc) \u7684\u5feb\u6377\u8868\u8fbe\u65b9\u5f0f\uff0c @my_decorator def nestedFunc (): print ( \"New added to decoration - executing nestedFunc()\" ) nestedFunc () # Before executing nestedFunc() # New added to decoration - executing nestedFunc() # After executing nestedFunc() print ( nestedFunc . __name__ ) # myFunc \u4f46\u4e0a\u4f8b\u6700\u540e\u7684\u8f93\u51fa\u4e0d\u662f\u6211\u4eec\u60f3\u8981\u7684\uff0c\u6211\u4eec\u5e0c\u671b\u8f93\u51fa nestedFunc \uff0c\u4f46\u5374\u88ab myFunc \u66ff\u4ee3\u4e86\uff0c\u5b83\u91cd\u5199\u4e86\u6211\u4eec\u51fd\u6570\u7684\u540d\u5b57\u548c\u6ce8\u91ca\u6587\u6863(docstring)\u3002 \u4e0b\u9762\u4f7f\u7528 functools.wraps \u6765\u4fee\u6b63\u4e0a\u9762\u7684\u95ee\u9898\u3002 from functools import wraps def my_decorator ( nestedFunc ): @wraps ( nestedFunc ) def myFunc (): print ( \"Before executing nestedFunc()\" ) nestedFunc () print ( \"After executing nestedFunc()\" ) return myFunc def nestedFunc (): print ( \"Decoration - executing nestedFunc()\" ) @my_decorator def nestedFunc (): print ( \"New added to decoration - executing nestedFunc()\" ) nestedFunc () # Before executing nestedFunc() # New added to decoration - executing nestedFunc() # After executing nestedFunc() print ( nestedFunc . __name__ ) # nestedFunc \u4e0b\u9762\u662f\u88c5\u9970\u5668\u7684\u84dd\u672c\u89c4\u8303\u3002 from functools import wraps def decorator_name ( f ): @wraps ( f ) def decorated ( * args , ** kwargs ): if not can_run : return \"Function will not run\" return f ( * args , ** kwargs ) return decorated @decorator_name def func (): return ( \"Function is running\" ) can_run = True print ( func ()) # Output: Function is running can_run = False print ( func ()) # Output: Function will not run \u4e0b\u9762\u8fd8\u662f\u4e00\u4e2a\u88c5\u9970\u5668\u7684\u4f8b\u5b50\u3002\u628a\u4e0b\u9762\u7684\u4ee3\u7801\u6bb5\u4fdd\u5b58\u5230\u6587\u4ef6 test.py \u3002 registry = [] def register ( func ): print ( f 'running register { func } ' ) registry . append ( func ) return func @register def f1 (): print ( 'running f1()' ) @register def f2 (): print ( 'running f2()' ) def f3 (): print ( 'running f3()' ) def main (): print ( 'runnning main()' ) print ( f 'registry--> { registry } ' ) f1 () f2 () f3 () if __name__ == '__main__' : main () \u6267\u884c\u4e0a\u8ff0\u4ee3\u7801\u6bb5 python3 test.py \uff0c\u5f97\u5230\u4e0b\u9762\u7684\u7ed3\u679c\u3002 running register < function f1 at 0x7f70847bec80 > running register < function f2 at 0x7f70705aa9d8 > runnning main () registry --> [ < function f1 at 0x7f70847bec80 > , < function f2 at 0x7f70705aa9d8 > ] running f1 () running f2 () running f3 () register \u5728\u6a21\u5757\u4e2d\u5176\u4ed6\u51fd\u6570\u4e4b\u524d\u8fd0\u884c\uff08\u4e24\u6b21\uff09\u3002\u8c03\u7528 register \u65f6\uff0c\u4f20\u7ed9\u5b83\u7684\u53c2\u6570\u662f\u88ab\u88c5\u9970\u7684\u51fd\u6570\uff0c\u4f8b\u5982 function f1 at 0x7f70847bec80> \u3002\u52a0\u8f7d\u6a21\u5757\u540e\uff0c registry \u4e2d\u6709\u4e24\u4e2a\u88ab\u88c5\u9970\u51fd\u6570\u7684\u5f15\u7528\uff1a f1 \u548c f2 \u3002\u8fd9\u4e24\u4e2a\u51fd\u6570\uff0c\u4ee5\u53ca f3 \uff0c\u53ea\u5728 main \u660e\u786e\u8c03\u7528\u5b83\u4eec\u65f6\u624d\u6267\u884c\u3002 \u7531\u6b64\u5f97\uff0c\u51fd\u6570\u88c5\u9970\u5668\u5728\u5bfc\u5165\u6a21\u5757\u65f6\u7acb\u5373\u6267\u884c\uff0c\u800c\u88ab\u88c5\u9970\u7684\u51fd\u6570\u53ea\u5728\u660e\u786e\u8c03\u7528\u65f6\u8fd0\u884c\uff0c\u5373Python\u4e2d\u63d0\u5230\u7684**\u5bfc\u5165\u65f6**\u548c**\u8fd0\u884c\u65f6**\u4e4b\u95f4\u7684\u533a\u522b\u3002 \u4e0a\u9762\u4f8b\u5b50\u4e2d\u88c5\u9970\u5668\u51fd\u6570\u4e0e\u88ab\u88c5\u9970\u7684\u51fd\u6570\u5728\u540c\u4e00\u4e2a\u6a21\u5757\u4e2d\u5b9a\u4e49\u3002\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u88c5\u9970\u5668\u901a\u5e38\u5728\u4e00\u4e2a\u6a21\u5757\u4e2d\u5b9a\u4e49\uff0c\u7136\u540e\u5e94\u7528\u5230\u5176\u4ed6\u6a21\u5757\u4e2d\u7684\u51fd\u6570\u4e0a\u3002 \u4e0a\u9762\u4f8b\u5b50\u4e2d register \u88c5\u9970\u5668\u8fd4\u56de\u7684\u51fd\u6570\u4e0e\u901a\u8fc7\u53c2\u6570\u4f20\u5165\u7684\u76f8\u540c\u3002\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u5927\u591a\u6570\u88c5\u9970\u5668\u4f1a\u5728\u5185\u90e8\u5b9a\u4e49\u4e00\u4e2a\u51fd\u6570\uff0c\u7136\u540e\u5c06\u5176\u8fd4\u56de\u3002","title":"\u88c5\u9970\u5668"},{"location":"python/Foundation/ch04/","text":"Python\u9762\u5411\u5bf9\u8c61\u6982\u5ff5 \u00b6 \u7c7b(class)\u628a\u6570\u636e\u4e0e\u529f\u80fd\u7ed1\u5b9a\u5728\u4e00\u8d77\u3002\u521b\u5efa\u65b0\u7c7b\u5c31\u662f\u521b\u5efa\u65b0\u7684\u5bf9\u8c61\u7c7b\u578b\uff08type of object\uff09\uff0c\u4ece\u800c\u521b\u5efa\u8be5\u7c7b\u578b\u7684\u65b0\u5b9e\u4f8b\uff08instances\uff09\u3002 \u7c7b\u5b9e\u4f8b\u5177\u6709\u591a\u79cd\u4fdd\u6301\u81ea\u8eab\u72b6\u6001\u7684\u5c5e\u6027\uff08attributes\uff09\u3002 \u7c7b\u5b9e\u4f8b\u8fd8\u652f\u6301\uff08\u7531\u7c7b\u5b9a\u4e49\u7684\uff09\u4fee\u6539\u81ea\u8eab\u72b6\u6001\u7684\u65b9\u6cd5\uff08methods\uff09\u3002 Python\u7684\u7c7b\u652f\u6301\u6240\u6709\u9762\u5411\u5bf9\u8c61\u7f16\u7a0b\uff08OOP\uff09\u7684\u6807\u51c6\u7279\u6027\uff1a \u7c7b\u7ee7\u627f\uff08class inheritance\uff09\u673a\u5236\u652f\u6301\u591a\u4e2a\u57fa\u7c7b\uff08base classes\uff09\uff1b \u6d3e\u751f\u7c7b\uff08derived class\uff09\u53ef\u4ee5\u8986\u76d6\u57fa\u7c7b\u7684\u4efb\u4f55\u65b9\u6cd5\uff08methods\uff09\uff1b \u7c7b\u7684\u65b9\u6cd5\u53ef\u4ee5\u8c03\u7528\u57fa\u7c7b\u4e2d\u76f8\u540c\u540d\u79f0\u7684\u65b9\u6cd5 \u5bf9\u8c61\u53ef\u4ee5\u5305\u542b\u4efb\u610f\u6570\u91cf\u548c\u7c7b\u578b\u7684\u6570\u636e\u3002 \u7c7b\uff08class\uff09\u548c\u6a21\u5757\uff08module\uff09\u90fd\u62e5\u6709\u52a8\u6001\u7279\u6027\uff08dynamic nature\uff09\uff1a\u5728\u8fd0\u884c\u65f6\u521b\u5efa\uff0c\u521b\u5efa\u540e\u4e5f\u53ef\u4ee5\u4fee\u6539\u3002 \u540d\u79f0Names\u548c\u5bf9\u8c61Objects \u00b6 \u5bf9\u8c61\u4e4b\u95f4\u76f8\u4e92\u72ec\u7acb\uff0c\u591a\u4e2a\u540d\u79f0\uff08names\uff09\uff08\u5728\u591a\u4e2a\u4f5c\u7528\u57df\u5185\uff09\u53ef\u4ee5\u7ed1\u5b9a\u5230\u540c\u4e00\u4e2a\u5bf9\u8c61\u3002 \u5176\u4ed6\u8bed\u8a00\u79f0\u4e4b\u4e3a\u522b\u540d\uff08alias\uff09\u3002 \u522b\u540d\u5728\u67d0\u4e9b\u65b9\u9762\u5c31\u50cf\u6307\u9488\u3002\u4f8b\u5982\uff0c\u4f20\u9012\u5bf9\u8c61\u7684\u4ee3\u4ef7\u5f88\u5c0f\uff0c\u56e0\u4e3a\u5b9e\u73b0\u53ea\u4f20\u9012\u4e00\u4e2a\u6307\u9488\uff1b\u5982\u679c\u51fd\u6570\u4fee\u6539\u4e86\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7684\u5bf9\u8c61\uff0c\u8c03\u7528\u8005\u5c31\u53ef\u4ee5\u770b\u5230\u66f4\u6539\u3002 \u4f5c\u7528\u57dfScopes\u548c\u547d\u540d\u7a7a\u95f4Namespaces \u00b6 **\u547d\u540d\u7a7a\u95f4\uff08namespace\uff09**\u662f\u4e00\u4e2a\u4ece\u540d\u5b57\u5230\u5bf9\u8c61\u7684\u6620\u5c04\u3002 \u5f53\u524d\u5927\u90e8\u5206\u547d\u540d\u7a7a\u95f4\u90fd\u7531 Python \u5b57\u5178\u5b9e\u73b0\u3002 \u4e0b\u9762\u662f\u51e0\u4e2a\u547d\u540d\u7a7a\u95f4\u7684\u4f8b\u5b50\uff1a \u5b58\u653e\u5185\u7f6e\u51fd\u6570\u7684\u96c6\u5408\uff08\u5305\u542b abs() \u8fd9\u6837\u7684\u51fd\u6570\uff0c\u548c\u5185\u5efa\u7684\u5f02\u5e38\u7b49\uff09\uff1b \u6a21\u5757\u4e2d\u7684\u5168\u5c40\u540d\u79f0\uff1b \u51fd\u6570\u8c03\u7528\u4e2d\u7684\u5c40\u90e8\u540d\u79f0\uff1b \u4ece\u67d0\u79cd\u610f\u4e49\u4e0a\u8bf4\uff0c \u5bf9\u8c61\u7684\u5c5e\u6027\u96c6\u5408\uff08the set of attributes of an object\uff09\u4e5f\u662f\u4e00\u79cd\u547d\u540d\u7a7a\u95f4\u7684\u5f62\u5f0f \u3002 \u5173\u4e8e\u547d\u540d\u7a7a\u95f4\u7684\u91cd\u8981\u4e00\u70b9\u662f\uff0c\u4e0d\u540c\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u540d\u79f0\u4e4b\u95f4\u7edd\u5bf9\u6ca1\u6709\u5173\u7cfb\uff1b \u4f8b\u5982\uff0c\u5728\u4e24\u4e2a\u4e0d\u540c\u7684\u6a21\u5757\u4e2d\u90fd\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a maximize \u51fd\u6570\u800c\u4e0d\u4f1a\u4ea7\u751f\u6df7\u6dc6\uff0c\u4f46\u5728\u8c03\u7528 maximize \u51fd\u6570\u65f6\u5fc5\u987b\u5fc5\u987b\u5728\u5176\u524d\u9762\u52a0\u4e0a\u6a21\u5757\u540d\u79f0\u3002 \u4efb\u4f55\u8ddf\u5728\u4e00\u4e2a\u70b9\u53f7\u4e4b\u540e\u7684\u540d\u79f0\u90fd\u79f0\u4e3a**\u5c5e\u6027\uff08attribute\uff09**\u3002\u4f8b\u5982\uff0c\u5728\u8868\u8fbe\u5f0f z.real \u4e2d\uff0c real \u662f\u5bf9\u8c61 z \u7684\u4e00\u4e2a\u5c5e\u6027\u3002 \u6309\u4e25\u683c\u7684\u8bf4\u6cd5\uff0c \u5bf9\u6a21\u5757\uff08module\uff09\u4e2d\u7684\u540d\u79f0\u7684\u5f15\u7528\uff08reference\uff09\u90fd\u5c5e\u4e8e\u5c5e\u6027\u5f15\u7528\uff08attribute reference\uff09 \uff1a \u5728\u8868\u8fbe\u5f0f modname.funcname \u4e2d\uff0c modname \u662f\u4e00\u4e2a\u6a21\u5757\u5bf9\u8c61\uff08module object\uff09\u800c funcname \u662f\u5b83\u7684\u4e00\u4e2a\u5c5e\u6027\u3002 \u5728\u6b64\u60c5\u51b5\u4e0b\u5728\u6a21\u5757\u7684\u5c5e\u6027\uff08module\u2019s attribute\uff09\u548c\u6a21\u5757\u4e2d\u5b9a\u4e49\u7684\u5168\u5c40\u540d\u79f0\u4e4b\u95f4\u6b63\u597d\u5b58\u5728\u4e00\u4e2a\u76f4\u89c2\u7684\u6620\u5c04\uff1a\u5b83\u4eec\u5171\u4eab\u76f8\u540c\u7684\u547d\u540d\u7a7a\u95f4\u3002 \u4f46\u5b58\u5728\u4e00\u4e2a\u4f8b\u5916\u3002 \u6a21\u5757\u5bf9\u8c61\u6709\u4e00\u4e2a\u53ea\u8bfb\u5c5e\u6027 __dict__ \uff0c\u5b83\u8fd4\u56de\u7528\u4e8e\u5b9e\u73b0\u6a21\u5757\u547d\u540d\u7a7a\u95f4\u7684\u5b57\u5178\uff1b __dict__ \u662f\u5c5e\u6027\u4f46\u4e0d\u662f\u5168\u5c40\u540d\u79f0\u3002 \u4f7f\u7528\u8fd9\u4e2a\u5c06\u8fdd\u53cd\u547d\u540d\u7a7a\u95f4\u5b9e\u73b0\u7684\u62bd\u8c61\uff0c\u5e94\u5f53\u4ec5\u88ab\u7528\u4e8e\u4e8b\u540e\u8c03\u8bd5\u5668\u4e4b\u7c7b\u7684\u573a\u5408\u3002 **\u5c5e\u6027\uff08attribute\uff09**\u53ef\u4ee5\u662f\u53ea\u8bfb\u6216\u8005\u53ef\u5199\u7684\uff0c\u6240\u4ee5\u53ef\u4ee5\u5bf9\u5c5e\u6027\u8fdb\u884c\u8d4b\u503c\uff0c\u4f8b\u5982 modname.the_answer = 42 \u3002 \u5220\u9664\u5c5e\u6027\u53ef\u4ee5\u7528del\u8bed\u53e5\uff0c\u4f8b\u5982\uff0c del modname.the_answer \u5c06\u4f1a\u4ece\u540d\u4e3a modname \u7684\u5bf9\u8c61\u4e2d\u79fb\u9664 the_answer \u5c5e\u6027\u3002 \u547d\u540d\u7a7a\u95f4\u5728\u4e0d\u540c\u65f6\u523b\u88ab\u521b\u5efa\uff0c\u62e5\u6709\u4e0d\u540c\u7684\u751f\u5b58\u671f\uff08lifetimes\uff09\u3002\u5305\u542b\u5185\u7f6e\u540d\u79f0\uff08built-in names\uff09\u7684\u547d\u540d\u7a7a\u95f4\u662f\u5728Python\u89e3\u91ca\u5668\u542f\u52a8\u65f6\u521b\u5efa\u7684\uff0c\u6c38\u8fdc\u4e0d\u4f1a\u88ab\u5220\u9664\u3002 \u6a21\u5757\u7684\u5168\u5c40\u547d\u540d\u7a7a\u95f4\uff08global namespace\uff09\u5728\u6a21\u5757\u5b9a\u4e49\u88ab\u8bfb\u5165\u65f6\u521b\u5efa\uff1b\u901a\u5e38\uff0c\u6a21\u5757\u547d\u540d\u7a7a\u95f4\u4e5f\u4f1a\u6301\u7eed\u5230\u89e3\u91ca\u5668\u9000\u51fa\u3002 \u88ab\u89e3\u91ca\u5668\u7684\u9876\u5c42\u8c03\u7528\uff08top-level invocation\uff09\u6267\u884c\u7684\u8bed\u53e5\uff0c\u4ece\u4e00\u4e2a\u811a\u672c\u6587\u4ef6\u8bfb\u53d6\u6216\u4ea4\u4e92\u5f0f\u5730\u8bfb\u53d6\uff0c\u88ab\u8ba4\u4e3a\u662f __main__ \u6a21\u5757\u8c03\u7528\u7684\u4e00\u90e8\u5206\uff0c\u56e0\u6b64\u5b83\u4eec\u62e5\u6709\u81ea\u5df1\u7684\u5168\u5c40\u547d\u540d\u7a7a\u95f4\u3002 \u5185\u7f6e\u540d\u79f0\uff08built-in names\uff09\u5b9e\u9645\u4e0a\u4e5f\u5b58\u5728\u4e8e\u4e00\u4e2a\u6a21\u5757\u4e2d\uff0c\u8fd9\u4e2a\u6a21\u5757\u88ab\u79f0\u4f5c builtins \u3002 \u4e00\u4e2a\u51fd\u6570\u7684\u672c\u5730\u547d\u540d\u7a7a\u95f4\uff08local namespace\uff09\u5728\u8fd9\u4e2a\u51fd\u6570\u88ab\u8c03\u7528\u65f6\u521b\u5efa\uff0c\u5e76\u5728\u51fd\u6570\u8fd4\u56de\u6216\u629b\u51fa\u4e00\u4e2a\u65e0\u6cd5\u5728\u8be5\u51fd\u6570\u5185\u90e8\u5904\u7406\u7684\u9519\u8bef\u65f6\u88ab\u5220\u9664\u3002 \u6bcf\u6b21\u9012\u5f52\u8c03\u7528\uff08recursive invocations\uff09\u90fd\u4f1a\u6709\u5b83\u81ea\u5df1\u7684\u672c\u5730\u547d\u540d\u7a7a\u95f4\u3002 \u4e00\u4e2a**\u4f5c\u7528\u57df\uff08scope\uff09**\u662f\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4\u53ef\u76f4\u63a5\u8bbf\u95ee\uff08directly accessible\uff09\u7684Python\u7a0b\u5e8f\u7684\u4ee3\u7801\u533a\u57df\u3002 \u8fd9\u91cc\u7684 \u201c\u53ef\u76f4\u63a5\u8bbf\u95ee\u201d \u610f\u5473\u7740\u4e0d\u52a0\u4efb\u4f55\u9650\u5b9a\u7684\u540d\u79f0\u5f15\u7528\u4f1a\u5728\u547d\u540d\u7a7a\u95f4\u4e2d\u8fdb\u884c\u67e5\u627e\u3002 \u867d\u7136\u4f5c\u7528\u57df\u662f\u9759\u6001\u5730\u786e\u5b9a\u7684\uff0c\u4f46\u5b83\u4eec\u4f1a\u88ab\u52a8\u6001\u5730\u4f7f\u7528\u3002 \u5728\u4ee3\u7801\u6267\u884c\u671f\u95f4\u7684\u4efb\u4f55\u65f6\u523b\uff0c\u4f1a\u67093\u62164\u4e2a\u7684\u5d4c\u5957\u4f5c\u7528\u57df\u4f9b\u547d\u540d\u7a7a\u95f4\u76f4\u63a5\u8bbf\u95ee: \u6700\u5148\u641c\u7d22\u7684\u6700\u5185\u90e8\u4f5c\u7528\u57df\u5305\u542b\u5c40\u90e8\u540d\u79f0 \u4ece\u6700\u8fd1\u7684\u5c01\u95ed\u4f5c\u7528\u57df\u5f00\u59cb\u641c\u7d22\u7684\u4efb\u4f55\u5c01\u95ed\u51fd\u6570\u7684\u4f5c\u7528\u57df\u5305\u542b\u975e\u5c40\u90e8\u540d\u79f0\uff0c\u4e5f\u5305\u62ec\u975e\u5168\u5c40\u540d\u79f0 \u5012\u6570\u7b2c\u4e8c\u4e2a\u4f5c\u7528\u57df\u5305\u542b\u5f53\u524d\u6a21\u5757\u7684\u5168\u5c40\u540d\u79f0 \u6700\u5916\u9762\u7684\u4f5c\u7528\u57df\uff08\u6700\u540e\u641c\u7d22\uff09\u662f\u5305\u542b\u5185\u7f6e\u540d\u79f0\u7684\u547d\u540d\u7a7a\u95f4 \u5982\u679c\u4e00\u4e2a\u540d\u79f0\u88ab\u58f0\u660e\u4e3a\u5168\u5c40\u53d8\u91cf\uff0c\u5219\u6240\u6709\u5f15\u7528\u548c\u8d4b\u503c\u5c06\u76f4\u63a5\u6307\u5411\u8be5\u6a21\u5757\u5168\u5c40\u540d\u79f0\u6240\u5728\u7684\u4e2d\u95f4\u4f5c\u7528\u57df\u3002 \u5982\u679c\u8981\u91cd\u65b0\u7ed1\u5b9a\u5728\u6700\u5185\u5c42\u4f5c\u7528\u57df\u4ee5\u5916\u7684\u53d8\u91cf\uff0c\u53ef\u4ee5\u4f7f\u7528 nonlocal \u8bed\u53e5\u58f0\u660e\u4e3a\u975e\u672c\u5730\u53d8\u91cf\u3002 \u5982\u679c\u6ca1\u6709\u88ab\u58f0\u660e\u4e3a\u975e\u672c\u5730\u53d8\u91cf\uff0c\u8fd9\u4e9b\u53d8\u91cf\u5c06\u662f\u53ea\u8bfb\u7684\u3002\u7ed9\u8fd9\u6837\u7684\u53d8\u91cf\u8d4b\u65b0\u503c\u53ea\u4f1a\u5728\u6700\u5185\u5c42\u4f5c\u7528\u57df\u4e2d\u521b\u5efa\u4e00\u4e2a*\u65b0\u7684*\u5c40\u90e8\u53d8\u91cf\uff0c\u800c\u540c\u540d\u7684\u5916\u90e8\u5168\u5c40\u53d8\u91cf\u5c06\u4fdd\u6301\u4e0d\u53d8\u3002 \u901a\u5e38\uff0c\u5f53\u524d\u5c40\u90e8\u4f5c\u7528\u57df\uff08local scope\uff09\u5c06\u5f15\u7528\u5f53\u524d\u51fd\u6570\u4f5c\u7528\u57df\u7684\u540d\u79f0\uff08local name\uff09\u3002 \u5728\u51fd\u6570\u4f5c\u7528\u57df\u4ee5\u5916\uff0c\u5f53\u524d\u5c40\u90e8\u4f5c\u7528\u57df\u5c06\u5f15\u7528\u4e0e\u5168\u5c40\u4f5c\u7528\u57df\u76f8\u4e00\u81f4\u7684\u547d\u540d\u7a7a\u95f4\uff1a\u6a21\u5757\u7684\u547d\u540d\u7a7a\u95f4\uff08the module\u2019s namespace\uff09\u3002 \u5b9a\u4e49\u4e00\u4e2a\u7c7b\uff0c\u662f\u5728\u672c\u5730\u5c40\u90e8\u547d\u540d\u7a7a\u95f4\u5185\u5efa\u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u3002 \u5728\u4e00\u4e2a\u6a21\u5757\uff08module \uff09\u5185\u5b9a\u4e49\u7684\u51fd\u6570\u7684\u4f5c\u7528\u57df\u5c31\u662f\u8be5\u6a21\u5757\u7684\u547d\u540d\u7a7a\u95f4\uff0c\u65e0\u8bba\u8be5\u51fd\u6570\u4ece\u4ec0\u4e48\u5730\u65b9\u6216\u4ee5\u4ec0\u4e48\u522b\u540d\u88ab\u8c03\u7528\u3002 \u53e6\u4e00\u65b9\u9762\uff0c\u5b9e\u9645\u7684\u540d\u79f0\u641c\u7d22\u662f\u5728\u8fd0\u884c\u65f6\u52a8\u6001\u5b8c\u6210\u7684\u3002 \u4f46\u662f\uff0cPython\u6b63\u5728\u671d\u7740\u201c\u7f16\u8bd1\u65f6\u9759\u6001\u540d\u79f0\u89e3\u6790\u201d\u7684\u65b9\u5411\u53d1\u5c55\uff0c\u56e0\u6b64\u4e0d\u8981\u8fc7\u4e8e\u4f9d\u8d56\u52a8\u6001\u540d\u79f0\u89e3\u6790\uff01\u4e8b\u5b9e\u4e0a\uff0c\u5c40\u90e8\u53d8\u91cf\u5df2\u7ecf\u662f\u88ab\u9759\u6001\u786e\u5b9a\u4e86\u3002 \u5982\u679c\u4e0d\u5b58\u5728\u751f\u6548\u7684 global \u6216 nonlocal \u8bed\u53e5\uff0c\u5219\u5bf9\u540d\u79f0\u7684\u8d4b\u503c\u603b\u662f\u4f1a\u8fdb\u5165\u6700\u5185\u5c42\u4f5c\u7528\u57df\u3002\u8d4b\u503c\u4e0d\u4f1a\u590d\u5236\u6570\u636e\uff0c\u662f\u5c06\u540d\u79f0\u7ed1\u5b9a\u5230\u5bf9\u8c61\u3002 \u5220\u9664\u4e5f\u662f\u5982\u6b64\uff1a\u8bed\u53e5 del x \u4f1a\u4ece\u5c40\u90e8\u4f5c\u7528\u57df\u6240\u5f15\u7528\u7684\u547d\u540d\u7a7a\u95f4\u4e2d\u79fb\u9664\u5bf9 x \u7684\u7ed1\u5b9a\u3002\u4e8b\u5b9e\u4e0a\uff0c\u6240\u6709\u5f15\u5165\u65b0\u540d\u79f0\u7684\u64cd\u4f5c\u90fd\u662f\u4f7f\u7528\u5c40\u90e8\u4f5c\u7528\u57df\u3002\u7279\u522b\u5730\uff0c import \u8bed\u53e5\u548c\u51fd\u6570\u5b9a\u4e49\u4f1a\u5728\u5c40\u90e8\u4f5c\u7528\u57df\u4e2d\u7ed1\u5b9a\u6a21\u5757\u6216\u51fd\u6570\u540d\u79f0\u3002 global \u8bed\u53e5\u53ef\u88ab\u7528\u6765\u8868\u660e\u7279\u5b9a\u53d8\u91cf\u5b58\u5728\u4e8e\u5168\u5c40\u4f5c\u7528\u57df\uff0c\u5e76\u4e14\u5e94\u5f53\u5728\u5168\u5c40\u4f5c\u7528\u57df\u4e2d\u88ab**\u91cd\u65b0**\u7ed1\u5b9a\uff1b nonlocal \u8bed\u53e5\u8868\u660e\u7279\u5b9a\u53d8\u91cf\u751f\u5b58\u4e8e\u5916\u5c42\u4f5c\u7528\u57df\u4e2d\uff0c\u5e76\u4e14\u5e94\u5f53\u5728\u5176\u6240\u5904\u7684\u5916\u5c42\u4f5c\u7528\u57df\u4e2d\u88ab**\u91cd\u65b0**\u7ed1\u5b9a\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a \u5c40\u90e8\u8d4b\u503c\uff08local assignment\uff0c\u8fd9\u662f\u9ed8\u8ba4\u72b6\u6001\uff09\u4e0d\u4f1a\u6539\u53d8 scope_test \u5bf9 spam \u7684\u7ed1\u5b9a\u3002 nonlocal \u8d4b\u503c\u4f1a\u6539\u53d8 scope_test \u5bf9 spam \u7684\u7ed1\u5b9a\u3002 global \u8d4b\u503c\u4f1a\u6539\u53d8\u6a21\u5757\u5c42\u7ea7\u7684\u7ed1\u5b9a\uff0c\u5373\uff0c global spam \u91cd\u65b0\u7ed1\u5b9a\u4e86spam\u7684\u5168\u5c40\u5b9a\u4e49\uff0c\u4ece spam = \"spam out of func\" \u53d8\u6210\u4e86 spam = \"global spam\" \u3002\u5982\u679c\u6ce8\u91ca\u6389def do_global()\u8fd9\u4e00\u6bb5\u4ee3\u7801\uff0c\u5219 spam = \"spam out of func\" \u8d77\u4f5c\u7528\u3002 spam = \"spam out of func\" def scope_test (): def do_local (): spam = \"local spam\" def do_nonlocal (): nonlocal spam spam = \"nonlocal spam\" def do_global (): global spam spam = \"global spam\" spam = \"test spam\" do_local () print ( \"After local assignment:\" , spam ) do_nonlocal () print ( \"After nonlocal assignment:\" , spam ) do_global () print ( \"After global assignment:\" , spam ) scope_test () print ( \"In global scope:\" , spam ) # \u8fd0\u884c\u7ed3\u679c # scope_test() After local assignment : test spam After nonlocal assignment : nonlocal spam After global assignment : nonlocal spam # print(\"In global scope:\", spam) In global scope : global spam \u7c7bClass \u00b6 \u7c7b\u5b9a\u4e49 Class Definition \u00b6 \u7c7b\u5b9a\u4e49\u4e0e\u51fd\u6570\u5b9a\u4e49 (def \u8bed\u53e5) \u4e00\u6837\u5fc5\u987b\u88ab\u6267\u884c\u624d\u4f1a\u8d77\u4f5c\u7528\u3002 class ClassName : < statement - 1 > ... < statement - N > \u5728\u5b9e\u8df5\u4e2d\uff0c\u7c7b\u5b9a\u4e49\u5185\u7684\u8bed\u53e5\u901a\u5e38\u90fd\u662f\u51fd\u6570\u5b9a\u4e49\uff0c\u4f46\u4e5f\u5141\u8bb8\u6709\u5176\u4ed6\u8bed\u53e5\u3002\u5728\u7c7b\u5185\u90e8\u7684\u51fd\u6570\u5b9a\u4e49\u901a\u5e38\u5177\u6709\u4e00\u79cd\u7279\u6709\u5f62\u5f0f\u7684\u53c2\u6570\u5217\u8868\uff0c\u8fd9\u662f\u7ea6\u5b9a\u7684\u65b9\u6cd5\u89c4\u8303\uff08conventions for methods\uff09\u3002 \u7f16\u8bd1\u8fc7\u7a0b\u4e2d\uff0c\u8fdb\u5165\u4e00\u4e2a\u7c7b\u7684\u5185\u90e8\uff0c\u5c06\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\uff0c\u4e00\u4e2a\u5c40\u90e8\u4f5c\u7528\u57df\u3002\u56e0\u6b64\uff0c\u6240\u6709\u5bf9\u7c7b\u5185\u90e8\u5c40\u90e8\u53d8\u91cf\u7684\u8d4b\u503c\u90fd\u662f\u5728\u8fd9\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u4e4b\u5185\uff0c\u5305\u62ec\u65b0\u5b9a\u4e49\u7684\u51fd\u6570\u540d\u79f0\u3002 \u5f53\u6b63\u5e38\u79bb\u5f00\u4e00\u4e2a\u7c7b\u65f6\uff0c\u7f16\u8bd1\u8fc7\u7a0b\u5c06\u521b\u5efa\u4e00\u4e2a\u7c7b\u5bf9\u8c61\uff08class object\uff09\uff0c\u5c01\u88c5\u4e86\u7c7b\u5b9a\u4e49\u6240\u521b\u5efa\u7684\u547d\u540d\u7a7a\u95f4\u91cc\u7684\u5185\u5bb9\u3002 \u6700\u521d\u7684\uff08\u5728\u8fdb\u5165\u7c7b\u5b9a\u4e49\u4e4b\u524d\u8d77\u4f5c\u7528\u7684\uff09\u5c40\u90e8\u4f5c\u7528\u57df\u5c06\u91cd\u65b0\u751f\u6548\uff0c\u7c7b\u5bf9\u8c61\uff08class object\uff09\u5c06\u5728\u8fd9\u91cc\u88ab\u7ed1\u5b9a\u5230\u7c7b\u5b9a\u4e49\u5934\u90e8\u6240\u58f0\u660e\u7684\u7c7b\u540d\u79f0 (\u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\u662f ClassName )\u3002 \u7c7b\u5bf9\u8c61 Class Objects \u00b6 \u7c7b\u5bf9\u8c61\u652f\u6301\u4e24\u79cd\u64cd\u4f5c\uff1a\u5c5e\u6027\u5f15\u7528\uff08attribute references\uff09\u548c\u5b9e\u4f8b\u5316\uff08instantiation\uff09\u3002 \u5c5e\u6027\u5f15\u7528\uff08attribute references\uff09 \u4f7f\u7528Python\u4e2d\u5c5e\u6027\u5f15\u7528\u7684\u6807\u51c6\u8bed\u6cd5: obj.name \u3002 \u5b58\u5728\u4e8e\u7c7b\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u6240\u6709\u540d\u79f0\uff0c\u7c7b\u5bf9\u8c61\u88ab\u521b\u5efa\u65f6\u540c\u65f6\u88ab\u521b\u5efa\u4e86\uff0c\u8fd9\u4e9b\u5c31\u662f\u6709\u6548\u7684\u5c5e\u6027\u540d\u79f0\u3002\u56e0\u6b64\uff0c\u5982\u679c\u7c7b\u5b9a\u4e49\u662f\u5982\u4e0b\u6240\u793a\uff0c\u90a3\u4e48 MyClass.i \u548c MyClass.f \u5c31\u662f\u6709\u6548\u7684\u5c5e\u6027\u5f15\u7528\uff0c\u5c06\u5206\u522b\u8fd4\u56de\u4e00\u4e2a\u6574\u6570\u548c\u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\u3002 \u7c7b\u5c5e\u6027\u4e5f\u53ef\u4ee5\u88ab\u8d4b\u503c\uff0c\u56e0\u6b64\u53ef\u4ee5\u901a\u8fc7\u8d4b\u503c\u6765\u66f4\u6539 MyClass.i \u7684\u503c\u3002 __doc__ \u4e5f\u662f\u4e00\u4e2a\u6709\u6548\u7684\u5c5e\u6027\uff0c\u5c06\u8fd4\u56de\u6240\u5c5e\u7c7b\u7684\u6587\u6863\u5b57\u7b26\u4e32: \"A simple example class\"\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' print ( MyClass . i ) # 12345 print ( MyClass . __doc__ ) # A simple example class MyClass . i = 10 print ( MyClass . i ) # 10 \u7c7b\u7684**\u5b9e\u4f8b\u5316\uff08instantiation\uff09**\u4f7f\u7528\u51fd\u6570\u8868\u793a\u6cd5\u3002 \u53ef\u4ee5\u628a\u7c7b\u5bf9\u8c61\uff08class object\uff09\u770b\u4f5c\u662f\u4e00\u4e2a\u4e0d\u5e26\u53c2\u6570\u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u8fd4\u56de\u4e86\u8be5\u7c7b\u7684\u4e00\u4e2a\u65b0\u5b9e\u4f8b\u3002 \u5728\u4e0b\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c x = MyClass() \u521b\u5efa\u4e86 MyClass() \u8fd9\u4e2a\u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u5e76\u8d4b\u503c\u7ed9\u5c40\u90e8\u53d8\u91cf x \u3002 \u5b9e\u4f8b\u5316\u64cd\u4f5c\uff08\u8c03\u7528\u7c7b\u5bf9\u8c61\uff09\u4f1a\u521b\u5efa\u4e00\u4e2a\u7a7a\u5bf9\u8c61\u3002\u8bb8\u591a\u7c7b\u4f1a\u521b\u5efa\u5e26\u6709\u7279\u5b9a\u521d\u59cb\u72b6\u6001\u7684\u81ea\u5b9a\u4e49\u5b9e\u4f8b\u3002\u4e3a\u6b64\u7c7b\u5b9a\u4e49\u4e2d\u9700\u8981\u5305\u542b\u4e00\u4e2a\u540d\u4e3a __init__() \u7684\u7279\u6b8a\u65b9\u6cd5\u3002 \u5f53\u4e00\u4e2a\u7c7b\u5b9a\u4e49\u4e86 __init__() \u65b9\u6cd5\u65f6\uff0c\u7c7b\u7684\u5b9e\u4f8b\u5316\u64cd\u4f5c\u4f1a\u81ea\u52a8\u4e3a\u65b0\u521b\u5efa\u7684\u7c7b\u5b9e\u4f8b\u8c03\u7528 __init__() \u3002 \u66f4\u65b0\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u6ce8\u610f __dict__ \u4e24\u6b21\u8fd4\u56de\u7684\u4e0d\u540c\u7684\u5b57\u5178\u3002\u590d\u4e60\u4e00\u4e0b\uff0c\u5728\u547d\u540d\u7a7a\u95f4\u4e2d\u63d0\u5230\uff0c __dict__ \u662f\u5c5e\u6027\u4f46\u4e0d\u662f\u5168\u5c40\u540d\u79f0\uff0c\u8fd4\u56de\u7528\u4e8e\u5b9e\u73b0\u6a21\u5757\u547d\u540d\u7a7a\u95f4\u7684\u5b57\u5178\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' def __init__ ( self ): self . data = [] x = MyClass () print ( x . __dict__ ) # {'data': []} x . i = 10 print ( x . __dict__ ) # {'data': [], 'i': 10} __init__() \u65b9\u6cd5\u53ef\u4ee5\u6709\u989d\u5916\u7684\u53c2\u6570\u8f93\u5165\uff0c\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u7c7b\u5b9e\u4f8b\u5316\u7684\u53c2\u6570\u5c06\u88ab\u4f20\u9012\u7ed9 __init__() \u3002 \u5982\u4e0b\u4f8b: class Complex : def __init__ ( self , realpart , imagpart ): self . r = realpart self . i = imagpart x = Complex ( 3.0 , - 4.5 ) print ( x . r , x . i ) # 3.0 -4.5 \u5b9e\u4f8b\u5bf9\u8c61 Instance Objects \u00b6 \u5bf9\u5b9e\u4f8b\u5bf9\u8c61\u552f\u4e00\u7684\u64cd\u4f5c\u662f\u5c5e\u6027\u5f15\u7528\u3002\u6709\u4e24\u79cd\u6709\u6548\u7684\u5c5e\u6027\u540d\u79f0\uff1a\u6570\u636e\u5c5e\u6027\uff08data attributes\uff09\u548c\u65b9\u6cd5\uff08methods\uff09\u3002 **\u6570\u636e\u5c5e\u6027\uff08data attributes\uff09**\u7c7b\u4f3c\u4e8e\u5b9e\u4f8b\u53d8\u91cf\uff0c\u6570\u636e\u5c5e\u6027\u4e0d\u9700\u8981\u58f0\u660e\u3002\u50cf\u5c40\u90e8\u53d8\u91cf\u4e00\u6837\uff0c\u6570\u636e\u5c5e\u6027\u5c06\u5728\u7b2c\u4e00\u6b21\u88ab\u8d4b\u503c\u65f6\u4ea7\u751f\u3002 \u4f8b\u5982\uff0c\u5982\u679c x \u662f\u4e0a\u9762\u521b\u5efa\u7684 MyClass \u7684\u5b9e\u4f8b\uff0c\u5219\u4ee5\u4e0b\u4ee3\u7801\u6bb5\u5c06\u6253\u5370\u6570\u503c 16 \uff0c\u4e14\u6ca1\u6709\u7559\u4e0b\u5173\u4e8e x.counter \u7684\u75d5\u8ff9\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' def __init__ ( self ): self . data = [] x = MyClass () x . counter = 1 while x . counter < 10 : x . counter = x . counter * 2 print ( x . counter ) # 16 print ( x . __dict__ ) # {'data': [], 'counter': 16} del x . counter print ( x . __dict__ ) # {'data': []} \u53e6\u4e00\u7c7b\u5b9e\u4f8b\u5c5e\u6027\u5f15\u7528\u79f0\u4e3a**\u65b9\u6cd5\uff08methods\uff09 \u3002 \u65b9\u6cd5\u662f\u96b6\u5c5e\u4e8e\u5bf9\u8c61\u7684**\u51fd\u6570 \u3002 \u5728Python\u4e2d\uff0c\u65b9\u6cd5\u8fd9\u4e2a\u672f\u8bed\u5e76\u4e0d\u662f\u7c7b\u5b9e\u4f8b\u6240\u7279\u6709\u7684\uff0c\u5176\u4ed6\u5bf9\u8c61\u4e5f\u53ef\u4ee5\u6709\u65b9\u6cd5\u3002 \u4f8b\u5982\uff0c\u5217\u8868\u5bf9\u8c61\uff08list objects\uff09\u5177\u6709append, insert, remove, sort\u7b49\u65b9\u6cd5\u3002 \u5728\u4ee5\u4e0b\u8ba8\u8bba\u4e2d\uff0c\u6211\u4eec\u4f7f\u7528\u65b9\u6cd5\u4e00\u8bcd\u5c06\u4e13\u6307\u7c7b\u5b9e\u4f8b\u5bf9\u8c61\u7684\u65b9\u6cd5\uff0c\u9664\u975e\u53e6\u5916\u660e\u786e\u8bf4\u660e\u3002 \u5b9e\u4f8b\u5bf9\u8c61\u7684\u6709\u6548\u65b9\u6cd5\u540d\u79f0\u4f9d\u8d56\u4e8e\u5176\u6240\u5c5e\u7684\u7c7b\u3002 \u6839\u636e\u5b9a\u4e49\uff0c\u4e00\u4e2a\u7c7b\u5b9a\u4e49\u4e2d\u6240\u5305\u542b\u7684\u6240\u6709\u51fd\u6570\u5bf9\u8c61\uff08function objects\uff09\u90fd\u79f0\u4e3a\u5c5e\u6027\u3002 \u56e0\u6b64\u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c x.f \u662f\u6709\u6548\u7684\u65b9\u6cd5\u5f15\u7528\uff0c\u56e0\u4e3a MyClass.f \u662f\u4e00\u4e2a\u51fd\u6570\uff0c\u800c x.i \u4e0d\u662f\u65b9\u6cd5\uff0c\u56e0\u4e3a MyClass.i \u4e0d\u662f\u51fd\u6570\u3002\u4f46\u662f x.f \u4e0e MyClass.f \u5e76\u4e0d\u662f\u4e00\u56de\u4e8b\uff0c x.f \u662f\u4e00\u4e2a**\u65b9\u6cd5\u5bf9\u8c61**\uff0c\u800c MyClass.f \u662f\u4e00\u4e2a**\u51fd\u6570\u5bf9\u8c61**\u3002\u5dee\u522b\u5728\u4e8e f() \u662f\u5426\u4e0e\u5b9e\u4f8b\u7ed1\u5b9a\uff0c\u672a\u7ed1\u5b9a\uff0c\u5c31\u662f\u51fd\u6570\uff0c\u7ed1\u5b9a\uff0c\u5c31\u662f\u65b9\u6cd5\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' def __init__ ( self ): self . data = [] x = MyClass () print ( MyClass . f ( 0 )) # hello world print ( x . f ()) # hello world print ( MyClass . f ) # print ( x . f ) # > print ( type ( MyClass . f )) # print ( type ( x . f )) # \u8fd9\u91cc\u505a\u4e2a\u5c0f\u7ed3\uff1a \u51fd\u6570(function)\u662fPython\u4e2d\u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61(callable), \u65b9\u6cd5(method)\u662f\u4e00\u79cd\u7279\u6b8a\u7684\u51fd\u6570\u3002 \u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61\u662f\u65b9\u6cd5\u548c\u51fd\u6570\uff0c\u548c\u8fd9\u4e2a\u5bf9\u8c61\u65e0\u5173\uff0c\u4ec5\u548c\u8fd9\u4e2a\u5bf9\u8c61\u662f\u5426\u4e0e\u7c7b\u6216\u5b9e\u4f8b\u7ed1\u5b9a\u6709\u5173\uff08bound method\uff09\u3002 \u9759\u6001\u65b9\u6cd5\u6ca1\u6709\u548c\u4efb\u4f55\u7c7b\u6216\u5b9e\u4f8b\u7ed1\u5b9a\uff0c\u6240\u4ee5**\u9759\u6001\u65b9\u6cd5\u662f\u4e2a\u51fd\u6570**\u3002 \u65b9\u6cd5\u5bf9\u8c61 Method Objects \u00b6 \u5728 MyClass \u793a\u4f8b\u4e2d\uff0c x.f() \u662f\u4e00\u4e2a\u65b9\u6cd5\u5bf9\u8c61\uff0c\u88ab\u8c03\u7528\u540e\uff0c\u5c06\u8fd4\u56de\u5b57\u7b26\u4e32 'hello world' \u3002\u53ef\u4ee5\u7acb\u5373\u8c03\u7528\uff0c\u4e5f\u53ef\u4ee5\u4fdd\u5b58\u8d77\u6765\u4ee5\u540e\u518d\u8c03\u7528 xf = x.f \u3002 \u867d\u7136 f() \u7684\u51fd\u6570\u5b9a\u4e49\u6307\u5b9a\u4e86\u4e00\u4e2a\u53c2\u6570\uff0c\u4f46\u4e0a\u9762\u4f8b\u5b50\u4e2d\u8c03\u7528 x.f() \u65f6\u5e76\u6ca1\u6709\u5e26\u53c2\u6570\uff0c\u4e5f\u6ca1\u6709\u5f15\u53d1\u5f02\u5e38\u62a5\u9519\u3002\u539f\u56e0\u5728\u4e8e\uff0c \u65b9\u6cd5(method)\u7684\u7279\u6b8a\u4e4b\u5904\u5c31\u5728\u4e8e\u5b9e\u4f8b\u5bf9\u8c61\u4f1a\u4f5c\u4e3a\u51fd\u6570\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u88ab\u4f20\u5165\u3002 \u8c03\u7528 x.f() \u5176\u5b9e\u5c31\u76f8\u5f53\u4e8e MyClass.f(x) \u3002 \u603b\u4e4b\uff0c\u8c03\u7528\u4e00\u4e2a\u5177\u6709 n \u4e2a\u53c2\u6570\u7684\u65b9\u6cd5(method)\u5c31\u76f8\u5f53\u4e8e\u8c03\u7528\u518d\u591a\u4e00\u4e2a\u53c2\u6570\u7684\u5bf9\u5e94\u51fd\u6570\uff0c\u8fd9\u4e2a\u53c2\u6570\u503c\u4e3a\u65b9\u6cd5\u6240\u5c5e\u5b9e\u4f8b\u5bf9\u8c61\uff0c \u4f4d\u7f6e\u5728\u5176\u4ed6\u53c2\u6570\u4e4b\u524d \u3002 \u5f53\u4e00\u4e2a\u5b9e\u4f8b\u7684\u975e\u6570\u636e\u5c5e\u6027\u88ab\u5f15\u7528\u65f6\uff0c\u5c06\u641c\u7d22\u5b9e\u4f8b\u6240\u5c5e\u7684\u7c7b\u3002 \u5982\u679c\u88ab\u5f15\u7528\u7684\u5c5e\u6027\u540d\u79f0\u662f\u7c7b\u4e2d\u4e00\u4e2a\u6709\u6548\u7684\u51fd\u6570\u5bf9\u8c61\uff0c\u5219\u4f1a\u521b\u5efa\u4e00\u4e2a\u62bd\u8c61\u7684\u5bf9\u8c61\uff0c\u901a\u8fc7\u6253\u5305\uff08parking\uff0c\u5373\u6307\u5411\uff09\u5339\u914d\u5230\u7684\u5b9e\u4f8b\u5bf9\u8c61\u548c\u51fd\u6570\u5bf9\u8c61\uff0c\u8fd9\u4e2a\u62bd\u8c61\u5bf9\u8c61\u5c31\u662f\u65b9\u6cd5\u5bf9\u8c61\u3002 \u5f53\u5e26\u53c2\u6570\u8c03\u7528\u65b9\u6cd5\u5bf9\u8c61\u65f6\uff0c\u5c06\u57fa\u4e8e\u5b9e\u4f8b\u5bf9\u8c61\u548c\u53c2\u6570\u5217\u8868\u6784\u5efa\u4e00\u4e2a\u65b0\u7684\u53c2\u6570\u5217\u8868\uff0c\u5e76\u4f7f\u7528\u8fd9\u4e2a\u65b0\u53c2\u6570\u5217\u8868\u8c03\u7528\u76f8\u5e94\u7684\u51fd\u6570\u5bf9\u8c61\u3002 \u7c7b\u548c\u5b9e\u4f8b\u53d8\u91cf Class and Instance Variables \u00b6 \u4e00\u822c\u6765\u8bf4\uff0c**\u5b9e\u4f8b\u53d8\u91cf**\u7528\u4e8e\u6bcf\u4e2a\u5b9e\u4f8b\u7684\u552f\u4e00\u6570\u636e\uff0c\u800c**\u7c7b\u53d8\u91cf**\u7528\u4e8e\u7c7b\u7684\u6240\u6709\u5b9e\u4f8b\u5171\u4eab\u7684\u5c5e\u6027\u548c\u65b9\u6cd5: class Dog : kind = 'canine' # class variable shared by all instances def __init__ ( self , name ): self . name = name # instance variable unique to each instance d = Dog ( 'Fido' ) e = Dog ( 'Buddy' ) print ( d . kind ) # shared by all dogs # 'canine' print ( e . kind ) # shared by all dogs # 'canine' print ( d . name ) # unique to d instance # 'Fido' print ( e . name ) # unique to e instance # 'Buddy' \u4e0b\u4ee3\u7801\u4e2d\u7684 tricks \u5217\u8868\u4e0d\u5e94\u8be5\u88ab\u7528\u4f5c\u7c7b\u53d8\u91cf\uff0c\u56e0\u4e3a\u6240\u6709\u7684 Dog \u5b9e\u4f8b\u5c06\u53ea\u5171\u4eab\u4e00\u4e2a\u5355\u72ec\u7684\u5217\u8868: class Dog : kind = 'canine' # class variable shared by all instances tricks = [] # mistaken use of a class variable def __init__ ( self , name ): self . name = name # instance variable unique to each instance def add_trick ( self , trick ): self . tricks . append ( trick ) d = Dog ( 'Fido' ) e = Dog ( 'Buddy' ) d . add_trick ( 'roll over' ) e . add_trick ( 'play dead' ) print ( d . tricks ) # ['roll over', 'play dead'] \u6b63\u786e\u7684\u7c7b\u8bbe\u8ba1\u5e94\u8be5\u4f7f\u7528\u5b9e\u4f8b\u53d8\u91cf: class Dog : kind = 'canine' # class variable shared by all instances def __init__ ( self , name ): self . name = name # instance variable unique to each instance self . tricks = [] # creates a new empty list for each dog def add_trick ( self , trick ): self . tricks . append ( trick ) d = Dog ( 'Fido' ) e = Dog ( 'Buddy' ) d . add_trick ( 'roll over' ) e . add_trick ( 'play dead' ) print ( d . tricks ) # ['roll over'] print ( e . tricks ) # ['play dead'] \u5982\u679c\u540c\u6837\u7684\u5c5e\u6027\u540d\u79f0\u540c\u65f6\u51fa\u73b0\u5728\u5b9e\u4f8b\u548c\u7c7b\u4e2d\uff0c\u5219\u5c5e\u6027\u67e5\u627e\u4f1a**\u4f18\u5148\u9009\u62e9\u5b9e\u4f8b**: class Warehouse : purpose = 'storage' region = 'west' w1 = Warehouse () print ( w1 . purpose , w1 . region ) # storage west w2 = Warehouse () w2 . region = 'east' # Instance W2 has higher priority than class print ( w2 . purpose , w2 . region ) # storage east \u6570\u636e\u5c5e\u6027\uff08Data attributes\uff09\u53ef\u4ee5\u88ab\u65b9\u6cd5\uff08method\uff09\u4ee5\u53ca\u4e00\u4e2a\u5bf9\u8c61\u7684\u666e\u901a\u7528\u6237\uff08ordinary users\uff09\uff08\u201c\u5ba2\u6237\u7aefClient\u201d\uff09\u6240\u5f15\u7528\u3002 \u6362\u53e5\u8bdd\u8bf4\uff0c\u7c7b\u4e0d\u80fd\u7528\u4e8e\u5b9e\u73b0\u7eaf\u62bd\u8c61\u6570\u636e\u7c7b\u578b\u3002 \u65b9\u6cd5\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u5e38\u5e38\u88ab\u547d\u540d\u4e3a self \uff0c\u8fd9\u53ea\u662f\u4e00\u4e2a\u7ea6\u5b9a: self \u8fd9\u4e00\u540d\u79f0\u5728Python\u4e2d\u6ca1\u6709\u7279\u6b8a\u542b\u4e49\u3002 \u4f46\u662f\u9075\u5faa\u6b64\u7ea6\u5b9a\u4f1a\u4f7f\u5f97\u4ee3\u7801\u5177\u6709\u5f88\u597d\u7684\u53ef\u8bfb\u6027\u3002 \u4efb\u4f55\u4e00\u4e2a\u4f5c\u4e3a\u7c7b\u5c5e\u6027\uff08class attribute\uff09\u7684\u51fd\u6570\u5bf9\u8c61\uff08function object\uff09\u90fd\u4e3a\u8be5\u7c7b\u7684\u5b9e\u4f8b\u5b9a\u4e49\u4e86\u4e00\u4e2a\u76f8\u5e94\u65b9\u6cd5\u3002 \u51fd\u6570\u5b9a\u4e49\u7684\u6587\u672c\u5e76\u975e\u5fc5\u987b\u5305\u542b\u4e8e\u7c7b\u5b9a\u4e49\u4e4b\u5185\uff1a\u5c06\u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\u8d4b\u503c\u7ed9\u4e00\u4e2a\u5c40\u90e8\u53d8\u91cf\u4e5f\u662f\u53ef\u4ee5\u7684\u3002\u5982\u4e0b\u4f8b\u3002\u73b0\u5728 f , g \u548c h \u90fd\u662f\u7c7b C \u7684\u5f15\u7528\u51fd\u6570\u5bf9\u8c61\u7684\u5c5e\u6027\uff0c\u56e0\u800c\u5b83\u4eec\u5c31\u90fd\u662f\u7c7b C \u7684\u5b9e\u4f8b\u7684\u65b9\u6cd5\uff0c\u5176\u4e2d h \u5b8c\u5168\u7b49\u540c\u4e8e g \u3002\u4f46\u8bf7\u6ce8\u610f\uff0c\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u7684\u53ef\u8bfb\u6027\u975e\u5e38\u4e0d\u597d\u3002 # Function defined outside the class def f1 ( self , x , y ): return min ( x , x + y ) class C : f = f1 # Assign a function object to a local variable in the class def g ( self ): return 'hello world' h = g \u65b9\u6cd5\uff08methods\uff09\u53ef\u4ee5\u901a\u8fc7\u4f7f\u7528 self \u53c2\u6570\u7684\u65b9\u6cd5\u5c5e\u6027\uff08method attributes\uff09\u8c03\u7528\u5176\u4ed6\u65b9\u6cd5\uff08method\uff09: class Bag : def __init__ ( self ): self . data = [] def add ( self , x ): self . data . append ( x ) def addtwice ( self , x ): self . add ( x ) self . add ( x ) \u65b9\u6cd5\u53ef\u4ee5\u901a\u8fc7\u4e0e\u666e\u901a\u51fd\u6570\u76f8\u540c\u7684\u65b9\u5f0f\u5f15\u7528\u5168\u5c40\u540d\u79f0\u3002 \u4e0e\u65b9\u6cd5\u76f8\u5173\u8054\u7684\u5168\u5c40\u4f5c\u7528\u57df\u5c31\u662f\u5305\u542b\u5176\u5b9a\u4e49\u7684\u6a21\u5757\u3002 \uff08\u7c7b\u6c38\u8fdc\u4e0d\u4f1a\u88ab\u4f5c\u4e3a\u5168\u5c40\u4f5c\u7528\u57df\u3002\uff09 \u867d\u7136\u6211\u4eec\u5f88\u5c11\u4f1a\u6709\u5145\u5206\u7684\u7406\u7531\u5728\u65b9\u6cd5\u4e2d\u4f7f\u7528\u5168\u5c40\u4f5c\u7528\u57df\uff0c\u4f46\u5168\u5c40\u4f5c\u7528\u57df\u5b58\u5728\u8bb8\u591a\u5408\u7406\u7684\u4f7f\u7528\u573a\u666f\uff1a\u4e3e\u4e2a\u4f8b\u5b50\uff0c\u5bfc\u5165\u5230\u5168\u5c40\u4f5c\u7528\u57df\u7684\u51fd\u6570\u548c\u6a21\u5757\u53ef\u4ee5\u88ab\u65b9\u6cd5\u6240\u4f7f\u7528\uff0c\u5728\u5176\u4e2d\u5b9a\u4e49\u7684\u51fd\u6570\u548c\u7c7b\u4e5f\u4e00\u6837\u3002 \u901a\u5e38\uff0c\u5305\u542b\u8be5\u65b9\u6cd5\u7684\u7c7b\u672c\u8eab\u662f\u5728\u5168\u5c40\u4f5c\u7528\u57df\u4e2d\u5b9a\u4e49\u7684\u3002 \u603b\u7ed3 \u00b6 \u7c7b\u5b9a\u4e49\u5c0f\u7ed3 \u00b6 \u4e00\u4e2a\u7c7b\u5b9a\u4e49\u7c7b\u6210\u5458\u5c5e\u6027\u548c\u6210\u5458\u65b9\u6cd5\u3002 \u4e00\u4e2a\u7c7b\u53ef\u4ee5\u5b9e\u4f8b\u5316\u591a\u4e2a\u5bf9\u8c61\uff0c\u6bcf\u4e2a\u5b9e\u4f8b\u5316\u5bf9\u8c61\u90fd\u662f\u72ec\u7acb\u7684\u3002 \u521b\u5efa\u7684\u7c7b\u5b9e\u4f8b\u5316\u5bf9\u8c61\uff0c\u4f1a\u5f15\u7528\u7236\u7c7b\u4e2d\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\uff0c\u5e76\u4e0d\u4f1a\u628a\u7c7b\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\u590d\u5236\u7ed9\u5bf9\u8c61\uff0c\u56e0\u6b64\uff1a \u5728\u8bbf\u95ee\u5b9e\u4f8b\u5316\u5bf9\u8c61\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\u65f6\uff0c\u4f1a\u5148\u53bb\u627e\u5bf9\u8c61\u81ea\u5df1\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\uff0c\u7136\u540e\u518d\u53bb\u5b9e\u4f8b\u5316\u8fd9\u4e2a\u5bf9\u8c61\u7684\u7c7b\u4e2d\u67e5\u627e\uff08\u5f15\u7528\uff09\u3002 \u5bf9\u8c61\u6210\u5458\u7684\u6dfb\u52a0\u548c\u4fee\u6539\uff0c\u90fd\u53ea\u4f1a\u5f71\u54cd\u5f53\u524d\u5bf9\u8c61\u81ea\u5df1\uff0c\u4e0d\u4f1a\u5f71\u54cd\u7c7b\u548c\u5176\u5b83\u5bf9\u8c61\u3002 \u5220\u9664\u5bf9\u8c61\u6210\u5458\u7684\u65f6\u5019\uff0c\u5fc5\u987b\u662f\u8be5\u5bf9\u8c61\u81ea\u5df1\u5177\u5907\u7684\u6210\u5458\u624d\u53ef\u4ee5\uff0c\u4e0d\u80fd\u5220\u9664\u7c7b\u4e2d\u5f15\u7528\u7684\u6210\u5458\u3002 \u5bf9\u7c7b\u6210\u5458\u7684\u64cd\u4f5c\uff0c\u4f1a\u5f71\u54cd\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\uff0c\u5305\u62ec\u4e4b\u524d\u521b\u5efa\u7684\u5bf9\u8c61\uff08\u5f15\u7528\uff09\u3002 \u7c7b\u6210\u5458\u64cd\u4f5c\uff08\u4e0d\u63a8\u8350\uff09 \u00b6 \u6210\u5458\u5c5e\u6027\uff1a \u8bbf\u95ee\uff1a ClassName.AttributeName \u4fee\u6539\uff1a ClassName.AttributeName = NewValue \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u5c5e\u6027\u3002 \u6dfb\u52a0\uff1a ClassName.NewAttributeName = Value \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u5c5e\u6027\u3002 \u5220\u9664\uff1a del ClassName.AttributeName \uff0c\u6ce8\u610f\uff0c\u53ea\u80fd\u5220\u9664\u7c7b\u5bf9\u8c61\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u4e0d\u518d\u5177\u6709\u8fd9\u4e2a\u5c5e\u6027\u3002 \u6210\u5458\u65b9\u6cd5\uff1a \u8bbf\u95ee\uff1a ClassName.MethodName() \u4fee\u6539\uff1a ClassName.MethodName = NewFunction \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u65b9\u6cd5\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u6dfb\u52a0\uff1a ClassName.MethodName = Function \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u65b9\u6cd5\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u5220\u9664\uff1a del ClassName.MethodName \uff0c\u6ce8\u610f\uff0c\u53ea\u80fd\u5220\u9664\u7c7b\u5bf9\u8c61\u81ea\u5df1\u7684\u65b9\u6cd5\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u4e0d\u518d\u5177\u6709\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u6210\u5458\u65b9\u6cd5\u4e2d\u7684self \u00b6 self \u53ea\u662f\u4e00\u4e2a\u5f62\u53c2\uff0c\u4e0d\u662f\u5173\u952e\u5b57\u3002 self \u5728\u65b9\u6cd5\uff08method\uff09\u4ee3\u8868\u5f53\u524d\u5bf9\u8c61\u81ea\u5df1\u3002\u524d\u9762\u63d0\u5230\u8fc7\uff0c\u65b9\u6cd5\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u5e38\u5e38\u88ab\u547d\u540d\u4e3a self \uff0c\u8fd9\u53ea\u662f\u4e00\u4e2a\u7ea6\u5b9a\u3002 \u53ef\u4ee5\u4f7f\u7528 self \u5728\u7c7b\u5185\u90e8\u64cd\u4f5c\u6210\u5458\uff08\u6dfb\u52a0\u3001\u4fee\u6539\u3001\u5220\u9664\u7b49\uff09\u3002 \u65b9\u6cd5\u7684\u5206\u7c7b\uff1a \u542b\u6709self\u6216\u8005\u53ef\u4ee5\u63a5\u53d7\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\u7684\u65b9\u6cd5\uff0c\u79f0\u4e3a**\u975e\u7ed1\u5b9a\u7c7b\u65b9\u6cd5**\uff0c\u975e\u7ed1\u5b9a\u7c7b\u7684\u65b9\u6cd5\u53ef\u4ee5\u4f7f\u7528\u5bf9\u8c61\u53bb\u8bbf\u95ee\u3002 \u4e0d\u542b\u6709self\u6216\u8005\u4e0d\u80fd\u63a5\u53d7\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\u7684\u65b9\u6cd5\uff0c\u79f0\u4e3a**\u7ed1\u5b9a\u7c7b\u65b9\u6cd5**\uff0c\u7ed1\u5b9a\u65b9\u6cd5\u53ea\u80fd\u4f7f\u7528\u7c7b\u53bb\u8bbf\u95ee\u3002 \u9b54\u672f\u65b9\u6cd5 \u00b6 \u9b54\u672f\u65b9\u6cd5\uff08Magic Method\uff09\u548c\u666e\u901a\u65b9\u6cd5\u4e00\u6837\uff0c\u90fd\u662f\u7c7b\u4e2d\u5b9a\u4e49\u7684\u6210\u5458\u65b9\u6cd5\u3002 \u9b54\u672f\u65b9\u6cd5\u540d\u79f0\u524d\u540e\u5404\u67092\u4e2a\u4e0b\u5212\u7ebf\uff0c\u6bd4\u5982 __init__ \u9b54\u672f\u65b9\u6cd5\u662f\u4e0d\u9700\u8981\u624b\u52a8\u8c03\u7528\u7684\uff0c\u4f1a\u5728\u67d0\u79cd\u60c5\u51b5\u4e0b\u81ea\u52a8\u89e6\u53d1\uff08\u81ea\u52a8\u6267\u884c\uff09\u3002 \u9b54\u672f\u65b9\u6cd5\u662f\u7cfb\u7edf\u5b9a\u4e49\u597d\u7684\uff0c\u4e0d\u662f\u7528\u6237\u5b9a\u4e49\u7684\u3002 __init__ \u521d\u59cb\u5316\u65b9\u6cd5\uff0c\u4e5f\u79f0\u4f5c**\u6784\u9020\u65b9\u6cd5** \u00b6 \u7c7b\u5b9e\u4f8b\u5316\u5bf9\u8c61\u521b\u5efa\u540e\u81ea\u52a8\u89e6\u53d1\u3002 __init__ \u521d\u59cb\u5316\u65b9\u6cd5\u53ef\u4ee5\u7528\u6765\u5728\u5bf9\u8c61\u5b9e\u4f8b\u5316\u540e\u5b8c\u6210\u5bf9\u8c61\u7684\u521d\u59cb\u5316\uff0c\u6bd4\u5982\u5c5e\u6027\u8d4b\u503c\uff0c\u65b9\u6cd5\u8c03\u7528\u7b49\u3002 __del__ \u6790\u6784\u65b9\u6cd5 \u00b6 \u7c7b\u5b9e\u4f8b\u5316\u5bf9\u8c61\u88ab\u9500\u6bc1\u65f6\u81ea\u52a8\u89e6\u53d1\u3002 __del__ \u6790\u6784\u65b9\u6cd5\u53ef\u4ee5\u5728\u9500\u6bc1\u5bf9\u8c61\u65f6\u5b8c\u6210\u4e00\u4e9b\u7279\u6b8a\u4efb\u52a1\uff0c\u5173\u95ed\u5bf9\u8c61\u6253\u5f00\u7684\u4e00\u4e9b\u8d44\u6e90\uff0c\u5982\u6587\u4ef6\u7b49\u3002 \u6ce8\u610f\uff0c\u662f\u5bf9\u8c61\u88ab\u9500\u6bc1\u65f6\u89e6\u53d1\u4e86\u6790\u6784\u65b9\u6cd5\uff0c\u800c\u4e0d\u662f\u8fd9\u4e2a\u6790\u6784\u65b9\u6cd5\u9500\u6bc1\u4e86\u5bf9\u8c61\u3002 \u5bf9\u8c61\u9500\u6bc1\u7684\u60c5\u51b5\uff1a \u5f53\u7a0b\u5e8f\u6267\u884c\u5b8c\u6bd5\uff0c\u9500\u6bc1\u548c\u91ca\u653e\u5185\u5b58\u4e2d\u7684\u8d44\u6e90\u3002 \u4f7f\u7528 del \u5220\u9664\u65f6\u3002 \u5bf9\u8c61\u4e0d\u518d\u88ab\u4efb\u4f55\u5bf9\u8c61\u5f15\u7528\u65f6\uff0c\u4f1a\u81ea\u52a8\u9500\u6bc1\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5bf9\u6bd4 bmw = Car('BMW') \u548c Car('BMW') \u6765\u7406\u89e3 init \u548c del \u7684\u89e6\u53d1\u673a\u5236\u3002 \u7f16\u8f91\u6587\u4ef6 file1.py class Car (): brand = \"\" def __init__ ( self , car_brand ): self . brand = car_brand print ( f \"initial method called, create { self . brand } car\" ) def __del__ ( self ): print ( f \"delete method called, destroy { self . brand } car\" ) bmw = Car ( 'BMW' ) vw = Car ( 'VW' ) \u6267\u884c\u4e0a\u9762\u7684\u4ee3\u7801 python3 file1.py \u5f97\u5230\u5982\u4e0b\u8f93\u51fa\uff0c\u5728\u7a0b\u5e8f\u6267\u884c\u5b8c\u6bd5\u65f6\uff0c\u4f9d\u6b21\u6267\u884c __del__ \u3002 initial method called , create BMW car initial method called , create VW car delete method called , destroy BMW car delete method called , destroy VW car \u7f16\u8f91\u6587\u4ef6 file2.py class Car (): brand = \"\" def __init__ ( self , car_brand ): self . brand = car_brand print ( f \"initial method called, create { self . brand } car\" ) def __del__ ( self ): print ( f \"delete method called, destroy { self . brand } car\" ) Car ( 'BMW' ) Car ( 'VW' ) \u6267\u884c\u4e0a\u9762\u7684\u4ee3\u7801 python3 file2.py \u5f97\u5230\u5982\u4e0b\u8f93\u51fa\uff1a initial method called , create BMW car delete method called , destroy BMW car initial method called , create VW car delete method called , destroy VW car Python\u51fd\u6570\u5185\u7701\u5185\u7701 \u00b6 \u4ece\u9b54\u672f\u65b9\u6cd5\u53ef\u4ee5\u5ef6\u7533\u5230Python\u7684**\u51fd\u6570\u5185\u7701**\uff0c\u51fd\u6570\u5185\u7701\u7684\u610f\u601d\u662f\u8bf4\uff0c\u5f53\u4f60\u62ff\u5230\u4e00\u4e2a\u201c\u51fd\u6570\u5bf9\u8c61\u201d\u7684\u65f6\u5019\uff0c\u4f60\u53ef\u4ee5\u7ee7\u7eed\u77e5\u9053\uff0c\u5b83\u7684\u540d\u5b57\uff0c\u53c2\u6570\u5b9a\u4e49\u7b49\u4fe1\u606f\u3002\u8fd9\u4e9b\u4fe1\u606f\u53ef\u4ee5\u901a\u8fc7\u51fd\u6570\u5bf9\u8c61\u7684\u5c5e\u6027\uff08\u4e00\u4e9b\u53cc\u4e0b\u5212\u7ebf\u7684\u9b54\u6cd5\u65b9\u6cd5\uff09\u5f97\u5230\u3002\u7b80\u8a00\u4e4b\uff0c\u5185\u7701\u662f\u5728\u8fd0\u884c\u65f6\u786e\u5b9a\u5bf9\u8c61\u7c7b\u578b\u7684\u80fd\u529b\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u5217\u51fa\u4e86\u5e38\u89c4\u5bf9\u8c61\u6ca1\u6709\u800c\u51fd\u6570\u6709\u7684\u5c5e\u6027\u3002 class C : pass obj = C () def func (): pass sorted ( set ( dir ( obj )) - set ( dir ( func ))) # ['__weakref__'] sorted ( set ( dir ( func )) - set ( dir ( obj ))) # ['__annotations__', '__call__', '__closure__', '__code__', '__defaults__', '__get__', '__globals__', '__kwdefaults__', '__name__', '__qualname__'] \u4e0b\u8868\u603b\u7ed3\u4e86\u7528\u6237\u5b9a\u4e49\u7684\u51fd\u6570\u7684\u5c5e\u6027\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u6f14\u793a\u4e86\u5728\u6307\u5b9a\u957f\u5ea6\u9644\u8fd1\u622a\u65ad\u5b57\u7b26\u4e32\u7684\u51fd\u6570\uff0c\u4ee5\u53ca\u63d0\u53d6\u5173\u4e8e\u51fd\u6570\u53c2\u6570\u7684\u4fe1\u606f\u7684\u65b9\u6cd5\u3002 \u53c2\u6570\u540d\u79f0\u5728 __code__.co_varnames \u4e2d\uff0c\u4f46\u8fd9\u91cc\u9762\u4e5f\u5305\u542b\u51fd\u6570\u5b9a\u4e49\u4f53\u4e2d\u521b\u5efa\u7684\u5c40\u90e8\u53d8\u91cf\u3002\u56e0\u6b64\uff0c\u53c2\u6570\u540d\u79f0\u662f\u524d N \u4e2a\u5b57\u7b26\u4e32\uff0c N \u7684\u503c\u7531 __code__.co_argcount \u786e\u5b9a\uff0c\u4f8b\u5b50\u91cc\u9762N\u662f2\uff0c\u5373\u53c2\u6570\u540d\u79f0\u662f text \u548c max_len \uff0c\u5c40\u90e8\u53d8\u91cf\u662f end \u3001 space_before \u3001 space_after \u3002 def clip ( text , max_len = 80 ): \"\"\" Get sub-string by the first blank before or after specified position. rfind() \u8fd4\u56de\u5b57\u7b26\u4e32\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u9879\u5219\u8fd4\u56de -1. \"\"\" end = None if len ( text ) > max_len : space_before = text . rfind ( ' ' , 0 , max_len ) if space_before >= 0 : end = space_before else : space_after = text . rfind ( ' ' , max_len ) if space_after >= 0 : end = space_after if end is None : end = len ( text ) return text [: end ] . rstrip () clip ( 'This is the string' , max_len = 10 ) # 'This is' clip . __defaults__ # (80,) clip . __code__ # \", line 1> clip . __code__ . co_varnames # ('text', 'max_len', 'end', 'space_before', 'space_after') clip . __code__ . co_argcount # 2 clip . __doc__ # '\\n Get sub-string by the first blank before or after specified position.\\n rfind() \u8fd4\u56de\u5b57\u7b26\u4e32\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u9879\u5219\u8fd4\u56de -1.\\n ' \u4e0a\u4f8b\u4e2d\uff0c\u53c2\u6570\u7684\u9ed8\u8ba4\u503c\u53ea\u80fd\u901a\u8fc7\u5b83\u4eec\u5728 __defaults__ \u5143\u7ec4\u4e2d\u7684\u4f4d\u7f6e\u786e\u5b9a\uff0c\u56e0\u6b64\u8981\u4ece\u540e\u5411\u524d\u626b\u63cf\u624d\u80fd\u628a\u53c2\u6570\u548c\u9ed8\u8ba4\u503c\u5bf9\u5e94\u8d77\u6765\uff0c\u6709\u4e9b\u4e0d\u5408\u7406\u3002\u5f15\u5165 inspect \u6a21\u5757\u540e\uff0c\u4e0a\u9762\u7684\u64cd\u4f5c\u5c31\u66f4\u5bb9\u6613\u4e86\u3002 inspect.signature \u51fd\u6570\u8fd4\u56de\u4e00\u4e2a inspect.Signature \u5bf9\u8c61\uff0c\u5b83\u6709\u4e00\u4e2a parameters \u5c5e\u6027\uff0c\u8fd9\u662f\u4e00\u4e2a\u6709\u5e8f\u6620\u5c04\uff0c\u628a\u53c2\u6570\u540d\u548c inspect.Parameter \u5bf9\u8c61\u5bf9\u5e94\u8d77\u6765\u3002\u5404\u4e2a Parameter \u5c5e\u6027\u4e5f\u6709\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u4f8b\u5982 name \u3001 default \u548c kind \u3002 from inspect import signature sig = signature ( clip ) type ( sig ) # print ( sig ) # (text, max_len=80) print ( str ( sig )) # (text, max_len=80) for name , param in sig . parameters . items (): print ( f ' { param . kind } : { name } = { param . default } ' ) # 1 : text = # 1 : max_len = 80 \u51fd\u6570\u6ce8\u89e3\u3002 Python 3 \u63d0\u4f9b\u4e86\u4e00\u79cd\u53e5\u6cd5\uff0c\u7528\u4e8e\u4e3a\u51fd\u6570\u58f0\u660e\u4e2d\u7684\u53c2\u6570\u548c\u8fd4\u56de\u503c\u9644\u52a0\u5143\u6570\u636e\u3002\u5bf9\u4e0a\u4f8b\u6dfb\u52a0\u6ce8\u89e3\u540e\u5982\u4e0b\u6240\u793a\uff0c\u4e8c\u8005\u552f\u4e00\u7684\u533a\u522b\u5728\u7b2c\u4e00\u884c\u3002 \u51fd\u6570\u58f0\u660e\u4e2d\u7684\u5404\u4e2a\u53c2\u6570\u53ef\u4ee5\u5728:\u4e4b\u540e\u589e\u52a0\u6ce8\u89e3\u8868\u8fbe\u5f0f\u3002 \u5982\u679c\u53c2\u6570\u6709\u9ed8\u8ba4\u503c\uff0c\u6ce8\u89e3\u653e\u5728\u53c2\u6570\u540d\u548c = \u53f7\u4e4b\u95f4\u3002 \u5982\u679c\u60f3\u6ce8\u89e3\u8fd4\u56de\u503c\uff0c\u5728)\u548c\u51fd\u6570\u58f0\u660e\u672b\u5c3e\u7684 : \u4e4b\u95f4\u6dfb\u52a0 -> \u548c\u4e00\u4e2a\u8868\u8fbe\u5f0f\u3002\u90a3\u4e2a\u8868\u8fbe\u5f0f\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\u3002 \u6ce8\u89e3\u4e2d\u6700\u5e38\u7528\u7684\u7c7b\u578b\u662f\u7c7b\uff08\u5982 str \u6216 int \uff09\u548c\u5b57\u7b26\u4e32\uff08\u5982'int > 0'\uff09\u3002\u5728\u4e0b\u4f8b\u4e2d\uff0cmax_len\u53c2\u6570\u7684\u6ce8\u89e3\u7528\u7684\u662f\u5b57\u7b26\u4e32\u3002 \u6ce8\u89e3\u4e0d\u4f1a\u505a\u4efb\u4f55\u5904\u7406\uff0c\u53ea\u662f\u5b58\u50a8\u5728\u51fd\u6570\u7684 __annotations__ \u5c5e\u6027\uff08\u4e00\u4e2a\u5b57\u5178\uff09\u4e2d\u3002\u6362\u53e5\u8bdd\u8bf4\uff0c\u6ce8\u89e3\u5bf9Python\u89e3\u91ca\u5668\u6ca1\u6709\u4efb\u4f55\u610f\u4e49\u3002 \u6ce8\u89e3\u53ea\u662f\u5143\u6570\u636e \uff0c\u53ef\u4ee5\u4f9bIDE\u3001\u6846\u67b6\u548c\u88c5\u9970\u5668\u7b49\u5de5\u5177\u4f7f\u7528\u3002 return \u952e\u4fdd\u5b58\u7684\u662f\u8fd4\u56de\u503c\u6ce8\u89e3\uff0c\u5373\u4e0b\u4f8b\u4e2d\u51fd\u6570\u58f0\u660e\u91cc\u4ee5 -> \u6807\u8bb0\u7684\u90e8\u5206\u3002 def clip ( text : str , max_len : 'int > 0' = 80 ) -> str : \"\"\" Get sub-string by the first blank before or after specified position. rfind() \u8fd4\u56de\u5b57\u7b26\u4e32\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u9879\u5219\u8fd4\u56de -1. \"\"\" end = None if len ( text ) > max_len : space_before = text . rfind ( ' ' , 0 , max_len ) if space_before >= 0 : end = space_before else : space_after = text . rfind ( ' ' , max_len ) if space_after >= 0 : end = space_after if end is None : end = len ( text ) return text [: end ] . rstrip () clip ( 'This is the string' , max_len = 10 ) # 'This is' clip . __annotations__ # {'text': , 'max_len': 'int > 0', 'return': } signature \u51fd\u6570\u8fd4\u56de\u4e00\u4e2a Signature \u5bf9\u8c61\uff0c\u5b83\u6709\u4e00\u4e2a return_annotation \u5c5e\u6027\u548c\u4e00\u4e2a parameters \u5c5e\u6027\uff0c\u540e\u8005\u662f\u4e00\u4e2a\u5b57\u5178\uff0c\u628a\u53c2\u6570\u540d\u6620\u5c04\u5230 Parameter \u5bf9\u8c61\u4e0a\u3002\u6bcf\u4e2a Parameter \u5bf9\u8c61\u81ea\u5df1\u4e5f\u6709 annotation \u5c5e\u6027\u3002 from inspect import signature sig = signature ( clip ) print ( sig . return_annotation ) # for param in sig . parameters . values (): note = repr ( param . annotation ) . ljust ( 13 ) print ( f ' { note } : { param . name } = { param . default } ' ) # : text = # 'int > 0' : max_len = 80","title":"Python\u9762\u5411\u5bf9\u8c61\u6982\u5ff5"},{"location":"python/Foundation/ch04/#python","text":"\u7c7b(class)\u628a\u6570\u636e\u4e0e\u529f\u80fd\u7ed1\u5b9a\u5728\u4e00\u8d77\u3002\u521b\u5efa\u65b0\u7c7b\u5c31\u662f\u521b\u5efa\u65b0\u7684\u5bf9\u8c61\u7c7b\u578b\uff08type of object\uff09\uff0c\u4ece\u800c\u521b\u5efa\u8be5\u7c7b\u578b\u7684\u65b0\u5b9e\u4f8b\uff08instances\uff09\u3002 \u7c7b\u5b9e\u4f8b\u5177\u6709\u591a\u79cd\u4fdd\u6301\u81ea\u8eab\u72b6\u6001\u7684\u5c5e\u6027\uff08attributes\uff09\u3002 \u7c7b\u5b9e\u4f8b\u8fd8\u652f\u6301\uff08\u7531\u7c7b\u5b9a\u4e49\u7684\uff09\u4fee\u6539\u81ea\u8eab\u72b6\u6001\u7684\u65b9\u6cd5\uff08methods\uff09\u3002 Python\u7684\u7c7b\u652f\u6301\u6240\u6709\u9762\u5411\u5bf9\u8c61\u7f16\u7a0b\uff08OOP\uff09\u7684\u6807\u51c6\u7279\u6027\uff1a \u7c7b\u7ee7\u627f\uff08class inheritance\uff09\u673a\u5236\u652f\u6301\u591a\u4e2a\u57fa\u7c7b\uff08base classes\uff09\uff1b \u6d3e\u751f\u7c7b\uff08derived class\uff09\u53ef\u4ee5\u8986\u76d6\u57fa\u7c7b\u7684\u4efb\u4f55\u65b9\u6cd5\uff08methods\uff09\uff1b \u7c7b\u7684\u65b9\u6cd5\u53ef\u4ee5\u8c03\u7528\u57fa\u7c7b\u4e2d\u76f8\u540c\u540d\u79f0\u7684\u65b9\u6cd5 \u5bf9\u8c61\u53ef\u4ee5\u5305\u542b\u4efb\u610f\u6570\u91cf\u548c\u7c7b\u578b\u7684\u6570\u636e\u3002 \u7c7b\uff08class\uff09\u548c\u6a21\u5757\uff08module\uff09\u90fd\u62e5\u6709\u52a8\u6001\u7279\u6027\uff08dynamic nature\uff09\uff1a\u5728\u8fd0\u884c\u65f6\u521b\u5efa\uff0c\u521b\u5efa\u540e\u4e5f\u53ef\u4ee5\u4fee\u6539\u3002","title":"Python\u9762\u5411\u5bf9\u8c61\u6982\u5ff5"},{"location":"python/Foundation/ch04/#namesobjects","text":"\u5bf9\u8c61\u4e4b\u95f4\u76f8\u4e92\u72ec\u7acb\uff0c\u591a\u4e2a\u540d\u79f0\uff08names\uff09\uff08\u5728\u591a\u4e2a\u4f5c\u7528\u57df\u5185\uff09\u53ef\u4ee5\u7ed1\u5b9a\u5230\u540c\u4e00\u4e2a\u5bf9\u8c61\u3002 \u5176\u4ed6\u8bed\u8a00\u79f0\u4e4b\u4e3a\u522b\u540d\uff08alias\uff09\u3002 \u522b\u540d\u5728\u67d0\u4e9b\u65b9\u9762\u5c31\u50cf\u6307\u9488\u3002\u4f8b\u5982\uff0c\u4f20\u9012\u5bf9\u8c61\u7684\u4ee3\u4ef7\u5f88\u5c0f\uff0c\u56e0\u4e3a\u5b9e\u73b0\u53ea\u4f20\u9012\u4e00\u4e2a\u6307\u9488\uff1b\u5982\u679c\u51fd\u6570\u4fee\u6539\u4e86\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7684\u5bf9\u8c61\uff0c\u8c03\u7528\u8005\u5c31\u53ef\u4ee5\u770b\u5230\u66f4\u6539\u3002","title":"\u540d\u79f0Names\u548c\u5bf9\u8c61Objects"},{"location":"python/Foundation/ch04/#scopesnamespaces","text":"**\u547d\u540d\u7a7a\u95f4\uff08namespace\uff09**\u662f\u4e00\u4e2a\u4ece\u540d\u5b57\u5230\u5bf9\u8c61\u7684\u6620\u5c04\u3002 \u5f53\u524d\u5927\u90e8\u5206\u547d\u540d\u7a7a\u95f4\u90fd\u7531 Python \u5b57\u5178\u5b9e\u73b0\u3002 \u4e0b\u9762\u662f\u51e0\u4e2a\u547d\u540d\u7a7a\u95f4\u7684\u4f8b\u5b50\uff1a \u5b58\u653e\u5185\u7f6e\u51fd\u6570\u7684\u96c6\u5408\uff08\u5305\u542b abs() \u8fd9\u6837\u7684\u51fd\u6570\uff0c\u548c\u5185\u5efa\u7684\u5f02\u5e38\u7b49\uff09\uff1b \u6a21\u5757\u4e2d\u7684\u5168\u5c40\u540d\u79f0\uff1b \u51fd\u6570\u8c03\u7528\u4e2d\u7684\u5c40\u90e8\u540d\u79f0\uff1b \u4ece\u67d0\u79cd\u610f\u4e49\u4e0a\u8bf4\uff0c \u5bf9\u8c61\u7684\u5c5e\u6027\u96c6\u5408\uff08the set of attributes of an object\uff09\u4e5f\u662f\u4e00\u79cd\u547d\u540d\u7a7a\u95f4\u7684\u5f62\u5f0f \u3002 \u5173\u4e8e\u547d\u540d\u7a7a\u95f4\u7684\u91cd\u8981\u4e00\u70b9\u662f\uff0c\u4e0d\u540c\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u540d\u79f0\u4e4b\u95f4\u7edd\u5bf9\u6ca1\u6709\u5173\u7cfb\uff1b \u4f8b\u5982\uff0c\u5728\u4e24\u4e2a\u4e0d\u540c\u7684\u6a21\u5757\u4e2d\u90fd\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a maximize \u51fd\u6570\u800c\u4e0d\u4f1a\u4ea7\u751f\u6df7\u6dc6\uff0c\u4f46\u5728\u8c03\u7528 maximize \u51fd\u6570\u65f6\u5fc5\u987b\u5fc5\u987b\u5728\u5176\u524d\u9762\u52a0\u4e0a\u6a21\u5757\u540d\u79f0\u3002 \u4efb\u4f55\u8ddf\u5728\u4e00\u4e2a\u70b9\u53f7\u4e4b\u540e\u7684\u540d\u79f0\u90fd\u79f0\u4e3a**\u5c5e\u6027\uff08attribute\uff09**\u3002\u4f8b\u5982\uff0c\u5728\u8868\u8fbe\u5f0f z.real \u4e2d\uff0c real \u662f\u5bf9\u8c61 z \u7684\u4e00\u4e2a\u5c5e\u6027\u3002 \u6309\u4e25\u683c\u7684\u8bf4\u6cd5\uff0c \u5bf9\u6a21\u5757\uff08module\uff09\u4e2d\u7684\u540d\u79f0\u7684\u5f15\u7528\uff08reference\uff09\u90fd\u5c5e\u4e8e\u5c5e\u6027\u5f15\u7528\uff08attribute reference\uff09 \uff1a \u5728\u8868\u8fbe\u5f0f modname.funcname \u4e2d\uff0c modname \u662f\u4e00\u4e2a\u6a21\u5757\u5bf9\u8c61\uff08module object\uff09\u800c funcname \u662f\u5b83\u7684\u4e00\u4e2a\u5c5e\u6027\u3002 \u5728\u6b64\u60c5\u51b5\u4e0b\u5728\u6a21\u5757\u7684\u5c5e\u6027\uff08module\u2019s attribute\uff09\u548c\u6a21\u5757\u4e2d\u5b9a\u4e49\u7684\u5168\u5c40\u540d\u79f0\u4e4b\u95f4\u6b63\u597d\u5b58\u5728\u4e00\u4e2a\u76f4\u89c2\u7684\u6620\u5c04\uff1a\u5b83\u4eec\u5171\u4eab\u76f8\u540c\u7684\u547d\u540d\u7a7a\u95f4\u3002 \u4f46\u5b58\u5728\u4e00\u4e2a\u4f8b\u5916\u3002 \u6a21\u5757\u5bf9\u8c61\u6709\u4e00\u4e2a\u53ea\u8bfb\u5c5e\u6027 __dict__ \uff0c\u5b83\u8fd4\u56de\u7528\u4e8e\u5b9e\u73b0\u6a21\u5757\u547d\u540d\u7a7a\u95f4\u7684\u5b57\u5178\uff1b __dict__ \u662f\u5c5e\u6027\u4f46\u4e0d\u662f\u5168\u5c40\u540d\u79f0\u3002 \u4f7f\u7528\u8fd9\u4e2a\u5c06\u8fdd\u53cd\u547d\u540d\u7a7a\u95f4\u5b9e\u73b0\u7684\u62bd\u8c61\uff0c\u5e94\u5f53\u4ec5\u88ab\u7528\u4e8e\u4e8b\u540e\u8c03\u8bd5\u5668\u4e4b\u7c7b\u7684\u573a\u5408\u3002 **\u5c5e\u6027\uff08attribute\uff09**\u53ef\u4ee5\u662f\u53ea\u8bfb\u6216\u8005\u53ef\u5199\u7684\uff0c\u6240\u4ee5\u53ef\u4ee5\u5bf9\u5c5e\u6027\u8fdb\u884c\u8d4b\u503c\uff0c\u4f8b\u5982 modname.the_answer = 42 \u3002 \u5220\u9664\u5c5e\u6027\u53ef\u4ee5\u7528del\u8bed\u53e5\uff0c\u4f8b\u5982\uff0c del modname.the_answer \u5c06\u4f1a\u4ece\u540d\u4e3a modname \u7684\u5bf9\u8c61\u4e2d\u79fb\u9664 the_answer \u5c5e\u6027\u3002 \u547d\u540d\u7a7a\u95f4\u5728\u4e0d\u540c\u65f6\u523b\u88ab\u521b\u5efa\uff0c\u62e5\u6709\u4e0d\u540c\u7684\u751f\u5b58\u671f\uff08lifetimes\uff09\u3002\u5305\u542b\u5185\u7f6e\u540d\u79f0\uff08built-in names\uff09\u7684\u547d\u540d\u7a7a\u95f4\u662f\u5728Python\u89e3\u91ca\u5668\u542f\u52a8\u65f6\u521b\u5efa\u7684\uff0c\u6c38\u8fdc\u4e0d\u4f1a\u88ab\u5220\u9664\u3002 \u6a21\u5757\u7684\u5168\u5c40\u547d\u540d\u7a7a\u95f4\uff08global namespace\uff09\u5728\u6a21\u5757\u5b9a\u4e49\u88ab\u8bfb\u5165\u65f6\u521b\u5efa\uff1b\u901a\u5e38\uff0c\u6a21\u5757\u547d\u540d\u7a7a\u95f4\u4e5f\u4f1a\u6301\u7eed\u5230\u89e3\u91ca\u5668\u9000\u51fa\u3002 \u88ab\u89e3\u91ca\u5668\u7684\u9876\u5c42\u8c03\u7528\uff08top-level invocation\uff09\u6267\u884c\u7684\u8bed\u53e5\uff0c\u4ece\u4e00\u4e2a\u811a\u672c\u6587\u4ef6\u8bfb\u53d6\u6216\u4ea4\u4e92\u5f0f\u5730\u8bfb\u53d6\uff0c\u88ab\u8ba4\u4e3a\u662f __main__ \u6a21\u5757\u8c03\u7528\u7684\u4e00\u90e8\u5206\uff0c\u56e0\u6b64\u5b83\u4eec\u62e5\u6709\u81ea\u5df1\u7684\u5168\u5c40\u547d\u540d\u7a7a\u95f4\u3002 \u5185\u7f6e\u540d\u79f0\uff08built-in names\uff09\u5b9e\u9645\u4e0a\u4e5f\u5b58\u5728\u4e8e\u4e00\u4e2a\u6a21\u5757\u4e2d\uff0c\u8fd9\u4e2a\u6a21\u5757\u88ab\u79f0\u4f5c builtins \u3002 \u4e00\u4e2a\u51fd\u6570\u7684\u672c\u5730\u547d\u540d\u7a7a\u95f4\uff08local namespace\uff09\u5728\u8fd9\u4e2a\u51fd\u6570\u88ab\u8c03\u7528\u65f6\u521b\u5efa\uff0c\u5e76\u5728\u51fd\u6570\u8fd4\u56de\u6216\u629b\u51fa\u4e00\u4e2a\u65e0\u6cd5\u5728\u8be5\u51fd\u6570\u5185\u90e8\u5904\u7406\u7684\u9519\u8bef\u65f6\u88ab\u5220\u9664\u3002 \u6bcf\u6b21\u9012\u5f52\u8c03\u7528\uff08recursive invocations\uff09\u90fd\u4f1a\u6709\u5b83\u81ea\u5df1\u7684\u672c\u5730\u547d\u540d\u7a7a\u95f4\u3002 \u4e00\u4e2a**\u4f5c\u7528\u57df\uff08scope\uff09**\u662f\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4\u53ef\u76f4\u63a5\u8bbf\u95ee\uff08directly accessible\uff09\u7684Python\u7a0b\u5e8f\u7684\u4ee3\u7801\u533a\u57df\u3002 \u8fd9\u91cc\u7684 \u201c\u53ef\u76f4\u63a5\u8bbf\u95ee\u201d \u610f\u5473\u7740\u4e0d\u52a0\u4efb\u4f55\u9650\u5b9a\u7684\u540d\u79f0\u5f15\u7528\u4f1a\u5728\u547d\u540d\u7a7a\u95f4\u4e2d\u8fdb\u884c\u67e5\u627e\u3002 \u867d\u7136\u4f5c\u7528\u57df\u662f\u9759\u6001\u5730\u786e\u5b9a\u7684\uff0c\u4f46\u5b83\u4eec\u4f1a\u88ab\u52a8\u6001\u5730\u4f7f\u7528\u3002 \u5728\u4ee3\u7801\u6267\u884c\u671f\u95f4\u7684\u4efb\u4f55\u65f6\u523b\uff0c\u4f1a\u67093\u62164\u4e2a\u7684\u5d4c\u5957\u4f5c\u7528\u57df\u4f9b\u547d\u540d\u7a7a\u95f4\u76f4\u63a5\u8bbf\u95ee: \u6700\u5148\u641c\u7d22\u7684\u6700\u5185\u90e8\u4f5c\u7528\u57df\u5305\u542b\u5c40\u90e8\u540d\u79f0 \u4ece\u6700\u8fd1\u7684\u5c01\u95ed\u4f5c\u7528\u57df\u5f00\u59cb\u641c\u7d22\u7684\u4efb\u4f55\u5c01\u95ed\u51fd\u6570\u7684\u4f5c\u7528\u57df\u5305\u542b\u975e\u5c40\u90e8\u540d\u79f0\uff0c\u4e5f\u5305\u62ec\u975e\u5168\u5c40\u540d\u79f0 \u5012\u6570\u7b2c\u4e8c\u4e2a\u4f5c\u7528\u57df\u5305\u542b\u5f53\u524d\u6a21\u5757\u7684\u5168\u5c40\u540d\u79f0 \u6700\u5916\u9762\u7684\u4f5c\u7528\u57df\uff08\u6700\u540e\u641c\u7d22\uff09\u662f\u5305\u542b\u5185\u7f6e\u540d\u79f0\u7684\u547d\u540d\u7a7a\u95f4 \u5982\u679c\u4e00\u4e2a\u540d\u79f0\u88ab\u58f0\u660e\u4e3a\u5168\u5c40\u53d8\u91cf\uff0c\u5219\u6240\u6709\u5f15\u7528\u548c\u8d4b\u503c\u5c06\u76f4\u63a5\u6307\u5411\u8be5\u6a21\u5757\u5168\u5c40\u540d\u79f0\u6240\u5728\u7684\u4e2d\u95f4\u4f5c\u7528\u57df\u3002 \u5982\u679c\u8981\u91cd\u65b0\u7ed1\u5b9a\u5728\u6700\u5185\u5c42\u4f5c\u7528\u57df\u4ee5\u5916\u7684\u53d8\u91cf\uff0c\u53ef\u4ee5\u4f7f\u7528 nonlocal \u8bed\u53e5\u58f0\u660e\u4e3a\u975e\u672c\u5730\u53d8\u91cf\u3002 \u5982\u679c\u6ca1\u6709\u88ab\u58f0\u660e\u4e3a\u975e\u672c\u5730\u53d8\u91cf\uff0c\u8fd9\u4e9b\u53d8\u91cf\u5c06\u662f\u53ea\u8bfb\u7684\u3002\u7ed9\u8fd9\u6837\u7684\u53d8\u91cf\u8d4b\u65b0\u503c\u53ea\u4f1a\u5728\u6700\u5185\u5c42\u4f5c\u7528\u57df\u4e2d\u521b\u5efa\u4e00\u4e2a*\u65b0\u7684*\u5c40\u90e8\u53d8\u91cf\uff0c\u800c\u540c\u540d\u7684\u5916\u90e8\u5168\u5c40\u53d8\u91cf\u5c06\u4fdd\u6301\u4e0d\u53d8\u3002 \u901a\u5e38\uff0c\u5f53\u524d\u5c40\u90e8\u4f5c\u7528\u57df\uff08local scope\uff09\u5c06\u5f15\u7528\u5f53\u524d\u51fd\u6570\u4f5c\u7528\u57df\u7684\u540d\u79f0\uff08local name\uff09\u3002 \u5728\u51fd\u6570\u4f5c\u7528\u57df\u4ee5\u5916\uff0c\u5f53\u524d\u5c40\u90e8\u4f5c\u7528\u57df\u5c06\u5f15\u7528\u4e0e\u5168\u5c40\u4f5c\u7528\u57df\u76f8\u4e00\u81f4\u7684\u547d\u540d\u7a7a\u95f4\uff1a\u6a21\u5757\u7684\u547d\u540d\u7a7a\u95f4\uff08the module\u2019s namespace\uff09\u3002 \u5b9a\u4e49\u4e00\u4e2a\u7c7b\uff0c\u662f\u5728\u672c\u5730\u5c40\u90e8\u547d\u540d\u7a7a\u95f4\u5185\u5efa\u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u3002 \u5728\u4e00\u4e2a\u6a21\u5757\uff08module \uff09\u5185\u5b9a\u4e49\u7684\u51fd\u6570\u7684\u4f5c\u7528\u57df\u5c31\u662f\u8be5\u6a21\u5757\u7684\u547d\u540d\u7a7a\u95f4\uff0c\u65e0\u8bba\u8be5\u51fd\u6570\u4ece\u4ec0\u4e48\u5730\u65b9\u6216\u4ee5\u4ec0\u4e48\u522b\u540d\u88ab\u8c03\u7528\u3002 \u53e6\u4e00\u65b9\u9762\uff0c\u5b9e\u9645\u7684\u540d\u79f0\u641c\u7d22\u662f\u5728\u8fd0\u884c\u65f6\u52a8\u6001\u5b8c\u6210\u7684\u3002 \u4f46\u662f\uff0cPython\u6b63\u5728\u671d\u7740\u201c\u7f16\u8bd1\u65f6\u9759\u6001\u540d\u79f0\u89e3\u6790\u201d\u7684\u65b9\u5411\u53d1\u5c55\uff0c\u56e0\u6b64\u4e0d\u8981\u8fc7\u4e8e\u4f9d\u8d56\u52a8\u6001\u540d\u79f0\u89e3\u6790\uff01\u4e8b\u5b9e\u4e0a\uff0c\u5c40\u90e8\u53d8\u91cf\u5df2\u7ecf\u662f\u88ab\u9759\u6001\u786e\u5b9a\u4e86\u3002 \u5982\u679c\u4e0d\u5b58\u5728\u751f\u6548\u7684 global \u6216 nonlocal \u8bed\u53e5\uff0c\u5219\u5bf9\u540d\u79f0\u7684\u8d4b\u503c\u603b\u662f\u4f1a\u8fdb\u5165\u6700\u5185\u5c42\u4f5c\u7528\u57df\u3002\u8d4b\u503c\u4e0d\u4f1a\u590d\u5236\u6570\u636e\uff0c\u662f\u5c06\u540d\u79f0\u7ed1\u5b9a\u5230\u5bf9\u8c61\u3002 \u5220\u9664\u4e5f\u662f\u5982\u6b64\uff1a\u8bed\u53e5 del x \u4f1a\u4ece\u5c40\u90e8\u4f5c\u7528\u57df\u6240\u5f15\u7528\u7684\u547d\u540d\u7a7a\u95f4\u4e2d\u79fb\u9664\u5bf9 x \u7684\u7ed1\u5b9a\u3002\u4e8b\u5b9e\u4e0a\uff0c\u6240\u6709\u5f15\u5165\u65b0\u540d\u79f0\u7684\u64cd\u4f5c\u90fd\u662f\u4f7f\u7528\u5c40\u90e8\u4f5c\u7528\u57df\u3002\u7279\u522b\u5730\uff0c import \u8bed\u53e5\u548c\u51fd\u6570\u5b9a\u4e49\u4f1a\u5728\u5c40\u90e8\u4f5c\u7528\u57df\u4e2d\u7ed1\u5b9a\u6a21\u5757\u6216\u51fd\u6570\u540d\u79f0\u3002 global \u8bed\u53e5\u53ef\u88ab\u7528\u6765\u8868\u660e\u7279\u5b9a\u53d8\u91cf\u5b58\u5728\u4e8e\u5168\u5c40\u4f5c\u7528\u57df\uff0c\u5e76\u4e14\u5e94\u5f53\u5728\u5168\u5c40\u4f5c\u7528\u57df\u4e2d\u88ab**\u91cd\u65b0**\u7ed1\u5b9a\uff1b nonlocal \u8bed\u53e5\u8868\u660e\u7279\u5b9a\u53d8\u91cf\u751f\u5b58\u4e8e\u5916\u5c42\u4f5c\u7528\u57df\u4e2d\uff0c\u5e76\u4e14\u5e94\u5f53\u5728\u5176\u6240\u5904\u7684\u5916\u5c42\u4f5c\u7528\u57df\u4e2d\u88ab**\u91cd\u65b0**\u7ed1\u5b9a\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a \u5c40\u90e8\u8d4b\u503c\uff08local assignment\uff0c\u8fd9\u662f\u9ed8\u8ba4\u72b6\u6001\uff09\u4e0d\u4f1a\u6539\u53d8 scope_test \u5bf9 spam \u7684\u7ed1\u5b9a\u3002 nonlocal \u8d4b\u503c\u4f1a\u6539\u53d8 scope_test \u5bf9 spam \u7684\u7ed1\u5b9a\u3002 global \u8d4b\u503c\u4f1a\u6539\u53d8\u6a21\u5757\u5c42\u7ea7\u7684\u7ed1\u5b9a\uff0c\u5373\uff0c global spam \u91cd\u65b0\u7ed1\u5b9a\u4e86spam\u7684\u5168\u5c40\u5b9a\u4e49\uff0c\u4ece spam = \"spam out of func\" \u53d8\u6210\u4e86 spam = \"global spam\" \u3002\u5982\u679c\u6ce8\u91ca\u6389def do_global()\u8fd9\u4e00\u6bb5\u4ee3\u7801\uff0c\u5219 spam = \"spam out of func\" \u8d77\u4f5c\u7528\u3002 spam = \"spam out of func\" def scope_test (): def do_local (): spam = \"local spam\" def do_nonlocal (): nonlocal spam spam = \"nonlocal spam\" def do_global (): global spam spam = \"global spam\" spam = \"test spam\" do_local () print ( \"After local assignment:\" , spam ) do_nonlocal () print ( \"After nonlocal assignment:\" , spam ) do_global () print ( \"After global assignment:\" , spam ) scope_test () print ( \"In global scope:\" , spam ) # \u8fd0\u884c\u7ed3\u679c # scope_test() After local assignment : test spam After nonlocal assignment : nonlocal spam After global assignment : nonlocal spam # print(\"In global scope:\", spam) In global scope : global spam","title":"\u4f5c\u7528\u57dfScopes\u548c\u547d\u540d\u7a7a\u95f4Namespaces"},{"location":"python/Foundation/ch04/#class","text":"","title":"\u7c7bClass"},{"location":"python/Foundation/ch04/#class-definition","text":"\u7c7b\u5b9a\u4e49\u4e0e\u51fd\u6570\u5b9a\u4e49 (def \u8bed\u53e5) \u4e00\u6837\u5fc5\u987b\u88ab\u6267\u884c\u624d\u4f1a\u8d77\u4f5c\u7528\u3002 class ClassName : < statement - 1 > ... < statement - N > \u5728\u5b9e\u8df5\u4e2d\uff0c\u7c7b\u5b9a\u4e49\u5185\u7684\u8bed\u53e5\u901a\u5e38\u90fd\u662f\u51fd\u6570\u5b9a\u4e49\uff0c\u4f46\u4e5f\u5141\u8bb8\u6709\u5176\u4ed6\u8bed\u53e5\u3002\u5728\u7c7b\u5185\u90e8\u7684\u51fd\u6570\u5b9a\u4e49\u901a\u5e38\u5177\u6709\u4e00\u79cd\u7279\u6709\u5f62\u5f0f\u7684\u53c2\u6570\u5217\u8868\uff0c\u8fd9\u662f\u7ea6\u5b9a\u7684\u65b9\u6cd5\u89c4\u8303\uff08conventions for methods\uff09\u3002 \u7f16\u8bd1\u8fc7\u7a0b\u4e2d\uff0c\u8fdb\u5165\u4e00\u4e2a\u7c7b\u7684\u5185\u90e8\uff0c\u5c06\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\uff0c\u4e00\u4e2a\u5c40\u90e8\u4f5c\u7528\u57df\u3002\u56e0\u6b64\uff0c\u6240\u6709\u5bf9\u7c7b\u5185\u90e8\u5c40\u90e8\u53d8\u91cf\u7684\u8d4b\u503c\u90fd\u662f\u5728\u8fd9\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u4e4b\u5185\uff0c\u5305\u62ec\u65b0\u5b9a\u4e49\u7684\u51fd\u6570\u540d\u79f0\u3002 \u5f53\u6b63\u5e38\u79bb\u5f00\u4e00\u4e2a\u7c7b\u65f6\uff0c\u7f16\u8bd1\u8fc7\u7a0b\u5c06\u521b\u5efa\u4e00\u4e2a\u7c7b\u5bf9\u8c61\uff08class object\uff09\uff0c\u5c01\u88c5\u4e86\u7c7b\u5b9a\u4e49\u6240\u521b\u5efa\u7684\u547d\u540d\u7a7a\u95f4\u91cc\u7684\u5185\u5bb9\u3002 \u6700\u521d\u7684\uff08\u5728\u8fdb\u5165\u7c7b\u5b9a\u4e49\u4e4b\u524d\u8d77\u4f5c\u7528\u7684\uff09\u5c40\u90e8\u4f5c\u7528\u57df\u5c06\u91cd\u65b0\u751f\u6548\uff0c\u7c7b\u5bf9\u8c61\uff08class object\uff09\u5c06\u5728\u8fd9\u91cc\u88ab\u7ed1\u5b9a\u5230\u7c7b\u5b9a\u4e49\u5934\u90e8\u6240\u58f0\u660e\u7684\u7c7b\u540d\u79f0 (\u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\u662f ClassName )\u3002","title":"\u7c7b\u5b9a\u4e49 Class Definition"},{"location":"python/Foundation/ch04/#class-objects","text":"\u7c7b\u5bf9\u8c61\u652f\u6301\u4e24\u79cd\u64cd\u4f5c\uff1a\u5c5e\u6027\u5f15\u7528\uff08attribute references\uff09\u548c\u5b9e\u4f8b\u5316\uff08instantiation\uff09\u3002 \u5c5e\u6027\u5f15\u7528\uff08attribute references\uff09 \u4f7f\u7528Python\u4e2d\u5c5e\u6027\u5f15\u7528\u7684\u6807\u51c6\u8bed\u6cd5: obj.name \u3002 \u5b58\u5728\u4e8e\u7c7b\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u6240\u6709\u540d\u79f0\uff0c\u7c7b\u5bf9\u8c61\u88ab\u521b\u5efa\u65f6\u540c\u65f6\u88ab\u521b\u5efa\u4e86\uff0c\u8fd9\u4e9b\u5c31\u662f\u6709\u6548\u7684\u5c5e\u6027\u540d\u79f0\u3002\u56e0\u6b64\uff0c\u5982\u679c\u7c7b\u5b9a\u4e49\u662f\u5982\u4e0b\u6240\u793a\uff0c\u90a3\u4e48 MyClass.i \u548c MyClass.f \u5c31\u662f\u6709\u6548\u7684\u5c5e\u6027\u5f15\u7528\uff0c\u5c06\u5206\u522b\u8fd4\u56de\u4e00\u4e2a\u6574\u6570\u548c\u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\u3002 \u7c7b\u5c5e\u6027\u4e5f\u53ef\u4ee5\u88ab\u8d4b\u503c\uff0c\u56e0\u6b64\u53ef\u4ee5\u901a\u8fc7\u8d4b\u503c\u6765\u66f4\u6539 MyClass.i \u7684\u503c\u3002 __doc__ \u4e5f\u662f\u4e00\u4e2a\u6709\u6548\u7684\u5c5e\u6027\uff0c\u5c06\u8fd4\u56de\u6240\u5c5e\u7c7b\u7684\u6587\u6863\u5b57\u7b26\u4e32: \"A simple example class\"\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' print ( MyClass . i ) # 12345 print ( MyClass . __doc__ ) # A simple example class MyClass . i = 10 print ( MyClass . i ) # 10 \u7c7b\u7684**\u5b9e\u4f8b\u5316\uff08instantiation\uff09**\u4f7f\u7528\u51fd\u6570\u8868\u793a\u6cd5\u3002 \u53ef\u4ee5\u628a\u7c7b\u5bf9\u8c61\uff08class object\uff09\u770b\u4f5c\u662f\u4e00\u4e2a\u4e0d\u5e26\u53c2\u6570\u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u8fd4\u56de\u4e86\u8be5\u7c7b\u7684\u4e00\u4e2a\u65b0\u5b9e\u4f8b\u3002 \u5728\u4e0b\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c x = MyClass() \u521b\u5efa\u4e86 MyClass() \u8fd9\u4e2a\u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u5e76\u8d4b\u503c\u7ed9\u5c40\u90e8\u53d8\u91cf x \u3002 \u5b9e\u4f8b\u5316\u64cd\u4f5c\uff08\u8c03\u7528\u7c7b\u5bf9\u8c61\uff09\u4f1a\u521b\u5efa\u4e00\u4e2a\u7a7a\u5bf9\u8c61\u3002\u8bb8\u591a\u7c7b\u4f1a\u521b\u5efa\u5e26\u6709\u7279\u5b9a\u521d\u59cb\u72b6\u6001\u7684\u81ea\u5b9a\u4e49\u5b9e\u4f8b\u3002\u4e3a\u6b64\u7c7b\u5b9a\u4e49\u4e2d\u9700\u8981\u5305\u542b\u4e00\u4e2a\u540d\u4e3a __init__() \u7684\u7279\u6b8a\u65b9\u6cd5\u3002 \u5f53\u4e00\u4e2a\u7c7b\u5b9a\u4e49\u4e86 __init__() \u65b9\u6cd5\u65f6\uff0c\u7c7b\u7684\u5b9e\u4f8b\u5316\u64cd\u4f5c\u4f1a\u81ea\u52a8\u4e3a\u65b0\u521b\u5efa\u7684\u7c7b\u5b9e\u4f8b\u8c03\u7528 __init__() \u3002 \u66f4\u65b0\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u6ce8\u610f __dict__ \u4e24\u6b21\u8fd4\u56de\u7684\u4e0d\u540c\u7684\u5b57\u5178\u3002\u590d\u4e60\u4e00\u4e0b\uff0c\u5728\u547d\u540d\u7a7a\u95f4\u4e2d\u63d0\u5230\uff0c __dict__ \u662f\u5c5e\u6027\u4f46\u4e0d\u662f\u5168\u5c40\u540d\u79f0\uff0c\u8fd4\u56de\u7528\u4e8e\u5b9e\u73b0\u6a21\u5757\u547d\u540d\u7a7a\u95f4\u7684\u5b57\u5178\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' def __init__ ( self ): self . data = [] x = MyClass () print ( x . __dict__ ) # {'data': []} x . i = 10 print ( x . __dict__ ) # {'data': [], 'i': 10} __init__() \u65b9\u6cd5\u53ef\u4ee5\u6709\u989d\u5916\u7684\u53c2\u6570\u8f93\u5165\uff0c\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u7c7b\u5b9e\u4f8b\u5316\u7684\u53c2\u6570\u5c06\u88ab\u4f20\u9012\u7ed9 __init__() \u3002 \u5982\u4e0b\u4f8b: class Complex : def __init__ ( self , realpart , imagpart ): self . r = realpart self . i = imagpart x = Complex ( 3.0 , - 4.5 ) print ( x . r , x . i ) # 3.0 -4.5","title":"\u7c7b\u5bf9\u8c61 Class Objects"},{"location":"python/Foundation/ch04/#instance-objects","text":"\u5bf9\u5b9e\u4f8b\u5bf9\u8c61\u552f\u4e00\u7684\u64cd\u4f5c\u662f\u5c5e\u6027\u5f15\u7528\u3002\u6709\u4e24\u79cd\u6709\u6548\u7684\u5c5e\u6027\u540d\u79f0\uff1a\u6570\u636e\u5c5e\u6027\uff08data attributes\uff09\u548c\u65b9\u6cd5\uff08methods\uff09\u3002 **\u6570\u636e\u5c5e\u6027\uff08data attributes\uff09**\u7c7b\u4f3c\u4e8e\u5b9e\u4f8b\u53d8\u91cf\uff0c\u6570\u636e\u5c5e\u6027\u4e0d\u9700\u8981\u58f0\u660e\u3002\u50cf\u5c40\u90e8\u53d8\u91cf\u4e00\u6837\uff0c\u6570\u636e\u5c5e\u6027\u5c06\u5728\u7b2c\u4e00\u6b21\u88ab\u8d4b\u503c\u65f6\u4ea7\u751f\u3002 \u4f8b\u5982\uff0c\u5982\u679c x \u662f\u4e0a\u9762\u521b\u5efa\u7684 MyClass \u7684\u5b9e\u4f8b\uff0c\u5219\u4ee5\u4e0b\u4ee3\u7801\u6bb5\u5c06\u6253\u5370\u6570\u503c 16 \uff0c\u4e14\u6ca1\u6709\u7559\u4e0b\u5173\u4e8e x.counter \u7684\u75d5\u8ff9\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' def __init__ ( self ): self . data = [] x = MyClass () x . counter = 1 while x . counter < 10 : x . counter = x . counter * 2 print ( x . counter ) # 16 print ( x . __dict__ ) # {'data': [], 'counter': 16} del x . counter print ( x . __dict__ ) # {'data': []} \u53e6\u4e00\u7c7b\u5b9e\u4f8b\u5c5e\u6027\u5f15\u7528\u79f0\u4e3a**\u65b9\u6cd5\uff08methods\uff09 \u3002 \u65b9\u6cd5\u662f\u96b6\u5c5e\u4e8e\u5bf9\u8c61\u7684**\u51fd\u6570 \u3002 \u5728Python\u4e2d\uff0c\u65b9\u6cd5\u8fd9\u4e2a\u672f\u8bed\u5e76\u4e0d\u662f\u7c7b\u5b9e\u4f8b\u6240\u7279\u6709\u7684\uff0c\u5176\u4ed6\u5bf9\u8c61\u4e5f\u53ef\u4ee5\u6709\u65b9\u6cd5\u3002 \u4f8b\u5982\uff0c\u5217\u8868\u5bf9\u8c61\uff08list objects\uff09\u5177\u6709append, insert, remove, sort\u7b49\u65b9\u6cd5\u3002 \u5728\u4ee5\u4e0b\u8ba8\u8bba\u4e2d\uff0c\u6211\u4eec\u4f7f\u7528\u65b9\u6cd5\u4e00\u8bcd\u5c06\u4e13\u6307\u7c7b\u5b9e\u4f8b\u5bf9\u8c61\u7684\u65b9\u6cd5\uff0c\u9664\u975e\u53e6\u5916\u660e\u786e\u8bf4\u660e\u3002 \u5b9e\u4f8b\u5bf9\u8c61\u7684\u6709\u6548\u65b9\u6cd5\u540d\u79f0\u4f9d\u8d56\u4e8e\u5176\u6240\u5c5e\u7684\u7c7b\u3002 \u6839\u636e\u5b9a\u4e49\uff0c\u4e00\u4e2a\u7c7b\u5b9a\u4e49\u4e2d\u6240\u5305\u542b\u7684\u6240\u6709\u51fd\u6570\u5bf9\u8c61\uff08function objects\uff09\u90fd\u79f0\u4e3a\u5c5e\u6027\u3002 \u56e0\u6b64\u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c x.f \u662f\u6709\u6548\u7684\u65b9\u6cd5\u5f15\u7528\uff0c\u56e0\u4e3a MyClass.f \u662f\u4e00\u4e2a\u51fd\u6570\uff0c\u800c x.i \u4e0d\u662f\u65b9\u6cd5\uff0c\u56e0\u4e3a MyClass.i \u4e0d\u662f\u51fd\u6570\u3002\u4f46\u662f x.f \u4e0e MyClass.f \u5e76\u4e0d\u662f\u4e00\u56de\u4e8b\uff0c x.f \u662f\u4e00\u4e2a**\u65b9\u6cd5\u5bf9\u8c61**\uff0c\u800c MyClass.f \u662f\u4e00\u4e2a**\u51fd\u6570\u5bf9\u8c61**\u3002\u5dee\u522b\u5728\u4e8e f() \u662f\u5426\u4e0e\u5b9e\u4f8b\u7ed1\u5b9a\uff0c\u672a\u7ed1\u5b9a\uff0c\u5c31\u662f\u51fd\u6570\uff0c\u7ed1\u5b9a\uff0c\u5c31\u662f\u65b9\u6cd5\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' def __init__ ( self ): self . data = [] x = MyClass () print ( MyClass . f ( 0 )) # hello world print ( x . f ()) # hello world print ( MyClass . f ) # print ( x . f ) # > print ( type ( MyClass . f )) # print ( type ( x . f )) # \u8fd9\u91cc\u505a\u4e2a\u5c0f\u7ed3\uff1a \u51fd\u6570(function)\u662fPython\u4e2d\u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61(callable), \u65b9\u6cd5(method)\u662f\u4e00\u79cd\u7279\u6b8a\u7684\u51fd\u6570\u3002 \u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61\u662f\u65b9\u6cd5\u548c\u51fd\u6570\uff0c\u548c\u8fd9\u4e2a\u5bf9\u8c61\u65e0\u5173\uff0c\u4ec5\u548c\u8fd9\u4e2a\u5bf9\u8c61\u662f\u5426\u4e0e\u7c7b\u6216\u5b9e\u4f8b\u7ed1\u5b9a\u6709\u5173\uff08bound method\uff09\u3002 \u9759\u6001\u65b9\u6cd5\u6ca1\u6709\u548c\u4efb\u4f55\u7c7b\u6216\u5b9e\u4f8b\u7ed1\u5b9a\uff0c\u6240\u4ee5**\u9759\u6001\u65b9\u6cd5\u662f\u4e2a\u51fd\u6570**\u3002","title":"\u5b9e\u4f8b\u5bf9\u8c61 Instance Objects"},{"location":"python/Foundation/ch04/#method-objects","text":"\u5728 MyClass \u793a\u4f8b\u4e2d\uff0c x.f() \u662f\u4e00\u4e2a\u65b9\u6cd5\u5bf9\u8c61\uff0c\u88ab\u8c03\u7528\u540e\uff0c\u5c06\u8fd4\u56de\u5b57\u7b26\u4e32 'hello world' \u3002\u53ef\u4ee5\u7acb\u5373\u8c03\u7528\uff0c\u4e5f\u53ef\u4ee5\u4fdd\u5b58\u8d77\u6765\u4ee5\u540e\u518d\u8c03\u7528 xf = x.f \u3002 \u867d\u7136 f() \u7684\u51fd\u6570\u5b9a\u4e49\u6307\u5b9a\u4e86\u4e00\u4e2a\u53c2\u6570\uff0c\u4f46\u4e0a\u9762\u4f8b\u5b50\u4e2d\u8c03\u7528 x.f() \u65f6\u5e76\u6ca1\u6709\u5e26\u53c2\u6570\uff0c\u4e5f\u6ca1\u6709\u5f15\u53d1\u5f02\u5e38\u62a5\u9519\u3002\u539f\u56e0\u5728\u4e8e\uff0c \u65b9\u6cd5(method)\u7684\u7279\u6b8a\u4e4b\u5904\u5c31\u5728\u4e8e\u5b9e\u4f8b\u5bf9\u8c61\u4f1a\u4f5c\u4e3a\u51fd\u6570\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u88ab\u4f20\u5165\u3002 \u8c03\u7528 x.f() \u5176\u5b9e\u5c31\u76f8\u5f53\u4e8e MyClass.f(x) \u3002 \u603b\u4e4b\uff0c\u8c03\u7528\u4e00\u4e2a\u5177\u6709 n \u4e2a\u53c2\u6570\u7684\u65b9\u6cd5(method)\u5c31\u76f8\u5f53\u4e8e\u8c03\u7528\u518d\u591a\u4e00\u4e2a\u53c2\u6570\u7684\u5bf9\u5e94\u51fd\u6570\uff0c\u8fd9\u4e2a\u53c2\u6570\u503c\u4e3a\u65b9\u6cd5\u6240\u5c5e\u5b9e\u4f8b\u5bf9\u8c61\uff0c \u4f4d\u7f6e\u5728\u5176\u4ed6\u53c2\u6570\u4e4b\u524d \u3002 \u5f53\u4e00\u4e2a\u5b9e\u4f8b\u7684\u975e\u6570\u636e\u5c5e\u6027\u88ab\u5f15\u7528\u65f6\uff0c\u5c06\u641c\u7d22\u5b9e\u4f8b\u6240\u5c5e\u7684\u7c7b\u3002 \u5982\u679c\u88ab\u5f15\u7528\u7684\u5c5e\u6027\u540d\u79f0\u662f\u7c7b\u4e2d\u4e00\u4e2a\u6709\u6548\u7684\u51fd\u6570\u5bf9\u8c61\uff0c\u5219\u4f1a\u521b\u5efa\u4e00\u4e2a\u62bd\u8c61\u7684\u5bf9\u8c61\uff0c\u901a\u8fc7\u6253\u5305\uff08parking\uff0c\u5373\u6307\u5411\uff09\u5339\u914d\u5230\u7684\u5b9e\u4f8b\u5bf9\u8c61\u548c\u51fd\u6570\u5bf9\u8c61\uff0c\u8fd9\u4e2a\u62bd\u8c61\u5bf9\u8c61\u5c31\u662f\u65b9\u6cd5\u5bf9\u8c61\u3002 \u5f53\u5e26\u53c2\u6570\u8c03\u7528\u65b9\u6cd5\u5bf9\u8c61\u65f6\uff0c\u5c06\u57fa\u4e8e\u5b9e\u4f8b\u5bf9\u8c61\u548c\u53c2\u6570\u5217\u8868\u6784\u5efa\u4e00\u4e2a\u65b0\u7684\u53c2\u6570\u5217\u8868\uff0c\u5e76\u4f7f\u7528\u8fd9\u4e2a\u65b0\u53c2\u6570\u5217\u8868\u8c03\u7528\u76f8\u5e94\u7684\u51fd\u6570\u5bf9\u8c61\u3002","title":"\u65b9\u6cd5\u5bf9\u8c61 Method Objects"},{"location":"python/Foundation/ch04/#class-and-instance-variables","text":"\u4e00\u822c\u6765\u8bf4\uff0c**\u5b9e\u4f8b\u53d8\u91cf**\u7528\u4e8e\u6bcf\u4e2a\u5b9e\u4f8b\u7684\u552f\u4e00\u6570\u636e\uff0c\u800c**\u7c7b\u53d8\u91cf**\u7528\u4e8e\u7c7b\u7684\u6240\u6709\u5b9e\u4f8b\u5171\u4eab\u7684\u5c5e\u6027\u548c\u65b9\u6cd5: class Dog : kind = 'canine' # class variable shared by all instances def __init__ ( self , name ): self . name = name # instance variable unique to each instance d = Dog ( 'Fido' ) e = Dog ( 'Buddy' ) print ( d . kind ) # shared by all dogs # 'canine' print ( e . kind ) # shared by all dogs # 'canine' print ( d . name ) # unique to d instance # 'Fido' print ( e . name ) # unique to e instance # 'Buddy' \u4e0b\u4ee3\u7801\u4e2d\u7684 tricks \u5217\u8868\u4e0d\u5e94\u8be5\u88ab\u7528\u4f5c\u7c7b\u53d8\u91cf\uff0c\u56e0\u4e3a\u6240\u6709\u7684 Dog \u5b9e\u4f8b\u5c06\u53ea\u5171\u4eab\u4e00\u4e2a\u5355\u72ec\u7684\u5217\u8868: class Dog : kind = 'canine' # class variable shared by all instances tricks = [] # mistaken use of a class variable def __init__ ( self , name ): self . name = name # instance variable unique to each instance def add_trick ( self , trick ): self . tricks . append ( trick ) d = Dog ( 'Fido' ) e = Dog ( 'Buddy' ) d . add_trick ( 'roll over' ) e . add_trick ( 'play dead' ) print ( d . tricks ) # ['roll over', 'play dead'] \u6b63\u786e\u7684\u7c7b\u8bbe\u8ba1\u5e94\u8be5\u4f7f\u7528\u5b9e\u4f8b\u53d8\u91cf: class Dog : kind = 'canine' # class variable shared by all instances def __init__ ( self , name ): self . name = name # instance variable unique to each instance self . tricks = [] # creates a new empty list for each dog def add_trick ( self , trick ): self . tricks . append ( trick ) d = Dog ( 'Fido' ) e = Dog ( 'Buddy' ) d . add_trick ( 'roll over' ) e . add_trick ( 'play dead' ) print ( d . tricks ) # ['roll over'] print ( e . tricks ) # ['play dead'] \u5982\u679c\u540c\u6837\u7684\u5c5e\u6027\u540d\u79f0\u540c\u65f6\u51fa\u73b0\u5728\u5b9e\u4f8b\u548c\u7c7b\u4e2d\uff0c\u5219\u5c5e\u6027\u67e5\u627e\u4f1a**\u4f18\u5148\u9009\u62e9\u5b9e\u4f8b**: class Warehouse : purpose = 'storage' region = 'west' w1 = Warehouse () print ( w1 . purpose , w1 . region ) # storage west w2 = Warehouse () w2 . region = 'east' # Instance W2 has higher priority than class print ( w2 . purpose , w2 . region ) # storage east \u6570\u636e\u5c5e\u6027\uff08Data attributes\uff09\u53ef\u4ee5\u88ab\u65b9\u6cd5\uff08method\uff09\u4ee5\u53ca\u4e00\u4e2a\u5bf9\u8c61\u7684\u666e\u901a\u7528\u6237\uff08ordinary users\uff09\uff08\u201c\u5ba2\u6237\u7aefClient\u201d\uff09\u6240\u5f15\u7528\u3002 \u6362\u53e5\u8bdd\u8bf4\uff0c\u7c7b\u4e0d\u80fd\u7528\u4e8e\u5b9e\u73b0\u7eaf\u62bd\u8c61\u6570\u636e\u7c7b\u578b\u3002 \u65b9\u6cd5\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u5e38\u5e38\u88ab\u547d\u540d\u4e3a self \uff0c\u8fd9\u53ea\u662f\u4e00\u4e2a\u7ea6\u5b9a: self \u8fd9\u4e00\u540d\u79f0\u5728Python\u4e2d\u6ca1\u6709\u7279\u6b8a\u542b\u4e49\u3002 \u4f46\u662f\u9075\u5faa\u6b64\u7ea6\u5b9a\u4f1a\u4f7f\u5f97\u4ee3\u7801\u5177\u6709\u5f88\u597d\u7684\u53ef\u8bfb\u6027\u3002 \u4efb\u4f55\u4e00\u4e2a\u4f5c\u4e3a\u7c7b\u5c5e\u6027\uff08class attribute\uff09\u7684\u51fd\u6570\u5bf9\u8c61\uff08function object\uff09\u90fd\u4e3a\u8be5\u7c7b\u7684\u5b9e\u4f8b\u5b9a\u4e49\u4e86\u4e00\u4e2a\u76f8\u5e94\u65b9\u6cd5\u3002 \u51fd\u6570\u5b9a\u4e49\u7684\u6587\u672c\u5e76\u975e\u5fc5\u987b\u5305\u542b\u4e8e\u7c7b\u5b9a\u4e49\u4e4b\u5185\uff1a\u5c06\u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\u8d4b\u503c\u7ed9\u4e00\u4e2a\u5c40\u90e8\u53d8\u91cf\u4e5f\u662f\u53ef\u4ee5\u7684\u3002\u5982\u4e0b\u4f8b\u3002\u73b0\u5728 f , g \u548c h \u90fd\u662f\u7c7b C \u7684\u5f15\u7528\u51fd\u6570\u5bf9\u8c61\u7684\u5c5e\u6027\uff0c\u56e0\u800c\u5b83\u4eec\u5c31\u90fd\u662f\u7c7b C \u7684\u5b9e\u4f8b\u7684\u65b9\u6cd5\uff0c\u5176\u4e2d h \u5b8c\u5168\u7b49\u540c\u4e8e g \u3002\u4f46\u8bf7\u6ce8\u610f\uff0c\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u7684\u53ef\u8bfb\u6027\u975e\u5e38\u4e0d\u597d\u3002 # Function defined outside the class def f1 ( self , x , y ): return min ( x , x + y ) class C : f = f1 # Assign a function object to a local variable in the class def g ( self ): return 'hello world' h = g \u65b9\u6cd5\uff08methods\uff09\u53ef\u4ee5\u901a\u8fc7\u4f7f\u7528 self \u53c2\u6570\u7684\u65b9\u6cd5\u5c5e\u6027\uff08method attributes\uff09\u8c03\u7528\u5176\u4ed6\u65b9\u6cd5\uff08method\uff09: class Bag : def __init__ ( self ): self . data = [] def add ( self , x ): self . data . append ( x ) def addtwice ( self , x ): self . add ( x ) self . add ( x ) \u65b9\u6cd5\u53ef\u4ee5\u901a\u8fc7\u4e0e\u666e\u901a\u51fd\u6570\u76f8\u540c\u7684\u65b9\u5f0f\u5f15\u7528\u5168\u5c40\u540d\u79f0\u3002 \u4e0e\u65b9\u6cd5\u76f8\u5173\u8054\u7684\u5168\u5c40\u4f5c\u7528\u57df\u5c31\u662f\u5305\u542b\u5176\u5b9a\u4e49\u7684\u6a21\u5757\u3002 \uff08\u7c7b\u6c38\u8fdc\u4e0d\u4f1a\u88ab\u4f5c\u4e3a\u5168\u5c40\u4f5c\u7528\u57df\u3002\uff09 \u867d\u7136\u6211\u4eec\u5f88\u5c11\u4f1a\u6709\u5145\u5206\u7684\u7406\u7531\u5728\u65b9\u6cd5\u4e2d\u4f7f\u7528\u5168\u5c40\u4f5c\u7528\u57df\uff0c\u4f46\u5168\u5c40\u4f5c\u7528\u57df\u5b58\u5728\u8bb8\u591a\u5408\u7406\u7684\u4f7f\u7528\u573a\u666f\uff1a\u4e3e\u4e2a\u4f8b\u5b50\uff0c\u5bfc\u5165\u5230\u5168\u5c40\u4f5c\u7528\u57df\u7684\u51fd\u6570\u548c\u6a21\u5757\u53ef\u4ee5\u88ab\u65b9\u6cd5\u6240\u4f7f\u7528\uff0c\u5728\u5176\u4e2d\u5b9a\u4e49\u7684\u51fd\u6570\u548c\u7c7b\u4e5f\u4e00\u6837\u3002 \u901a\u5e38\uff0c\u5305\u542b\u8be5\u65b9\u6cd5\u7684\u7c7b\u672c\u8eab\u662f\u5728\u5168\u5c40\u4f5c\u7528\u57df\u4e2d\u5b9a\u4e49\u7684\u3002","title":"\u7c7b\u548c\u5b9e\u4f8b\u53d8\u91cf Class and Instance Variables"},{"location":"python/Foundation/ch04/#_1","text":"","title":"\u603b\u7ed3"},{"location":"python/Foundation/ch04/#_2","text":"\u4e00\u4e2a\u7c7b\u5b9a\u4e49\u7c7b\u6210\u5458\u5c5e\u6027\u548c\u6210\u5458\u65b9\u6cd5\u3002 \u4e00\u4e2a\u7c7b\u53ef\u4ee5\u5b9e\u4f8b\u5316\u591a\u4e2a\u5bf9\u8c61\uff0c\u6bcf\u4e2a\u5b9e\u4f8b\u5316\u5bf9\u8c61\u90fd\u662f\u72ec\u7acb\u7684\u3002 \u521b\u5efa\u7684\u7c7b\u5b9e\u4f8b\u5316\u5bf9\u8c61\uff0c\u4f1a\u5f15\u7528\u7236\u7c7b\u4e2d\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\uff0c\u5e76\u4e0d\u4f1a\u628a\u7c7b\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\u590d\u5236\u7ed9\u5bf9\u8c61\uff0c\u56e0\u6b64\uff1a \u5728\u8bbf\u95ee\u5b9e\u4f8b\u5316\u5bf9\u8c61\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\u65f6\uff0c\u4f1a\u5148\u53bb\u627e\u5bf9\u8c61\u81ea\u5df1\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\uff0c\u7136\u540e\u518d\u53bb\u5b9e\u4f8b\u5316\u8fd9\u4e2a\u5bf9\u8c61\u7684\u7c7b\u4e2d\u67e5\u627e\uff08\u5f15\u7528\uff09\u3002 \u5bf9\u8c61\u6210\u5458\u7684\u6dfb\u52a0\u548c\u4fee\u6539\uff0c\u90fd\u53ea\u4f1a\u5f71\u54cd\u5f53\u524d\u5bf9\u8c61\u81ea\u5df1\uff0c\u4e0d\u4f1a\u5f71\u54cd\u7c7b\u548c\u5176\u5b83\u5bf9\u8c61\u3002 \u5220\u9664\u5bf9\u8c61\u6210\u5458\u7684\u65f6\u5019\uff0c\u5fc5\u987b\u662f\u8be5\u5bf9\u8c61\u81ea\u5df1\u5177\u5907\u7684\u6210\u5458\u624d\u53ef\u4ee5\uff0c\u4e0d\u80fd\u5220\u9664\u7c7b\u4e2d\u5f15\u7528\u7684\u6210\u5458\u3002 \u5bf9\u7c7b\u6210\u5458\u7684\u64cd\u4f5c\uff0c\u4f1a\u5f71\u54cd\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\uff0c\u5305\u62ec\u4e4b\u524d\u521b\u5efa\u7684\u5bf9\u8c61\uff08\u5f15\u7528\uff09\u3002","title":"\u7c7b\u5b9a\u4e49\u5c0f\u7ed3"},{"location":"python/Foundation/ch04/#_3","text":"\u6210\u5458\u5c5e\u6027\uff1a \u8bbf\u95ee\uff1a ClassName.AttributeName \u4fee\u6539\uff1a ClassName.AttributeName = NewValue \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u5c5e\u6027\u3002 \u6dfb\u52a0\uff1a ClassName.NewAttributeName = Value \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u5c5e\u6027\u3002 \u5220\u9664\uff1a del ClassName.AttributeName \uff0c\u6ce8\u610f\uff0c\u53ea\u80fd\u5220\u9664\u7c7b\u5bf9\u8c61\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u4e0d\u518d\u5177\u6709\u8fd9\u4e2a\u5c5e\u6027\u3002 \u6210\u5458\u65b9\u6cd5\uff1a \u8bbf\u95ee\uff1a ClassName.MethodName() \u4fee\u6539\uff1a ClassName.MethodName = NewFunction \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u65b9\u6cd5\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u6dfb\u52a0\uff1a ClassName.MethodName = Function \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u65b9\u6cd5\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u5220\u9664\uff1a del ClassName.MethodName \uff0c\u6ce8\u610f\uff0c\u53ea\u80fd\u5220\u9664\u7c7b\u5bf9\u8c61\u81ea\u5df1\u7684\u65b9\u6cd5\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u4e0d\u518d\u5177\u6709\u8fd9\u4e2a\u65b9\u6cd5\u3002","title":"\u7c7b\u6210\u5458\u64cd\u4f5c\uff08\u4e0d\u63a8\u8350\uff09"},{"location":"python/Foundation/ch04/#self","text":"self \u53ea\u662f\u4e00\u4e2a\u5f62\u53c2\uff0c\u4e0d\u662f\u5173\u952e\u5b57\u3002 self \u5728\u65b9\u6cd5\uff08method\uff09\u4ee3\u8868\u5f53\u524d\u5bf9\u8c61\u81ea\u5df1\u3002\u524d\u9762\u63d0\u5230\u8fc7\uff0c\u65b9\u6cd5\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u5e38\u5e38\u88ab\u547d\u540d\u4e3a self \uff0c\u8fd9\u53ea\u662f\u4e00\u4e2a\u7ea6\u5b9a\u3002 \u53ef\u4ee5\u4f7f\u7528 self \u5728\u7c7b\u5185\u90e8\u64cd\u4f5c\u6210\u5458\uff08\u6dfb\u52a0\u3001\u4fee\u6539\u3001\u5220\u9664\u7b49\uff09\u3002 \u65b9\u6cd5\u7684\u5206\u7c7b\uff1a \u542b\u6709self\u6216\u8005\u53ef\u4ee5\u63a5\u53d7\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\u7684\u65b9\u6cd5\uff0c\u79f0\u4e3a**\u975e\u7ed1\u5b9a\u7c7b\u65b9\u6cd5**\uff0c\u975e\u7ed1\u5b9a\u7c7b\u7684\u65b9\u6cd5\u53ef\u4ee5\u4f7f\u7528\u5bf9\u8c61\u53bb\u8bbf\u95ee\u3002 \u4e0d\u542b\u6709self\u6216\u8005\u4e0d\u80fd\u63a5\u53d7\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\u7684\u65b9\u6cd5\uff0c\u79f0\u4e3a**\u7ed1\u5b9a\u7c7b\u65b9\u6cd5**\uff0c\u7ed1\u5b9a\u65b9\u6cd5\u53ea\u80fd\u4f7f\u7528\u7c7b\u53bb\u8bbf\u95ee\u3002","title":"\u6210\u5458\u65b9\u6cd5\u4e2d\u7684self"},{"location":"python/Foundation/ch04/#_4","text":"\u9b54\u672f\u65b9\u6cd5\uff08Magic Method\uff09\u548c\u666e\u901a\u65b9\u6cd5\u4e00\u6837\uff0c\u90fd\u662f\u7c7b\u4e2d\u5b9a\u4e49\u7684\u6210\u5458\u65b9\u6cd5\u3002 \u9b54\u672f\u65b9\u6cd5\u540d\u79f0\u524d\u540e\u5404\u67092\u4e2a\u4e0b\u5212\u7ebf\uff0c\u6bd4\u5982 __init__ \u9b54\u672f\u65b9\u6cd5\u662f\u4e0d\u9700\u8981\u624b\u52a8\u8c03\u7528\u7684\uff0c\u4f1a\u5728\u67d0\u79cd\u60c5\u51b5\u4e0b\u81ea\u52a8\u89e6\u53d1\uff08\u81ea\u52a8\u6267\u884c\uff09\u3002 \u9b54\u672f\u65b9\u6cd5\u662f\u7cfb\u7edf\u5b9a\u4e49\u597d\u7684\uff0c\u4e0d\u662f\u7528\u6237\u5b9a\u4e49\u7684\u3002","title":"\u9b54\u672f\u65b9\u6cd5"},{"location":"python/Foundation/ch04/#__init__","text":"\u7c7b\u5b9e\u4f8b\u5316\u5bf9\u8c61\u521b\u5efa\u540e\u81ea\u52a8\u89e6\u53d1\u3002 __init__ \u521d\u59cb\u5316\u65b9\u6cd5\u53ef\u4ee5\u7528\u6765\u5728\u5bf9\u8c61\u5b9e\u4f8b\u5316\u540e\u5b8c\u6210\u5bf9\u8c61\u7684\u521d\u59cb\u5316\uff0c\u6bd4\u5982\u5c5e\u6027\u8d4b\u503c\uff0c\u65b9\u6cd5\u8c03\u7528\u7b49\u3002","title":"__init__\u521d\u59cb\u5316\u65b9\u6cd5\uff0c\u4e5f\u79f0\u4f5c**\u6784\u9020\u65b9\u6cd5**"},{"location":"python/Foundation/ch04/#__del__","text":"\u7c7b\u5b9e\u4f8b\u5316\u5bf9\u8c61\u88ab\u9500\u6bc1\u65f6\u81ea\u52a8\u89e6\u53d1\u3002 __del__ \u6790\u6784\u65b9\u6cd5\u53ef\u4ee5\u5728\u9500\u6bc1\u5bf9\u8c61\u65f6\u5b8c\u6210\u4e00\u4e9b\u7279\u6b8a\u4efb\u52a1\uff0c\u5173\u95ed\u5bf9\u8c61\u6253\u5f00\u7684\u4e00\u4e9b\u8d44\u6e90\uff0c\u5982\u6587\u4ef6\u7b49\u3002 \u6ce8\u610f\uff0c\u662f\u5bf9\u8c61\u88ab\u9500\u6bc1\u65f6\u89e6\u53d1\u4e86\u6790\u6784\u65b9\u6cd5\uff0c\u800c\u4e0d\u662f\u8fd9\u4e2a\u6790\u6784\u65b9\u6cd5\u9500\u6bc1\u4e86\u5bf9\u8c61\u3002 \u5bf9\u8c61\u9500\u6bc1\u7684\u60c5\u51b5\uff1a \u5f53\u7a0b\u5e8f\u6267\u884c\u5b8c\u6bd5\uff0c\u9500\u6bc1\u548c\u91ca\u653e\u5185\u5b58\u4e2d\u7684\u8d44\u6e90\u3002 \u4f7f\u7528 del \u5220\u9664\u65f6\u3002 \u5bf9\u8c61\u4e0d\u518d\u88ab\u4efb\u4f55\u5bf9\u8c61\u5f15\u7528\u65f6\uff0c\u4f1a\u81ea\u52a8\u9500\u6bc1\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5bf9\u6bd4 bmw = Car('BMW') \u548c Car('BMW') \u6765\u7406\u89e3 init \u548c del \u7684\u89e6\u53d1\u673a\u5236\u3002 \u7f16\u8f91\u6587\u4ef6 file1.py class Car (): brand = \"\" def __init__ ( self , car_brand ): self . brand = car_brand print ( f \"initial method called, create { self . brand } car\" ) def __del__ ( self ): print ( f \"delete method called, destroy { self . brand } car\" ) bmw = Car ( 'BMW' ) vw = Car ( 'VW' ) \u6267\u884c\u4e0a\u9762\u7684\u4ee3\u7801 python3 file1.py \u5f97\u5230\u5982\u4e0b\u8f93\u51fa\uff0c\u5728\u7a0b\u5e8f\u6267\u884c\u5b8c\u6bd5\u65f6\uff0c\u4f9d\u6b21\u6267\u884c __del__ \u3002 initial method called , create BMW car initial method called , create VW car delete method called , destroy BMW car delete method called , destroy VW car \u7f16\u8f91\u6587\u4ef6 file2.py class Car (): brand = \"\" def __init__ ( self , car_brand ): self . brand = car_brand print ( f \"initial method called, create { self . brand } car\" ) def __del__ ( self ): print ( f \"delete method called, destroy { self . brand } car\" ) Car ( 'BMW' ) Car ( 'VW' ) \u6267\u884c\u4e0a\u9762\u7684\u4ee3\u7801 python3 file2.py \u5f97\u5230\u5982\u4e0b\u8f93\u51fa\uff1a initial method called , create BMW car delete method called , destroy BMW car initial method called , create VW car delete method called , destroy VW car","title":"__del__\u6790\u6784\u65b9\u6cd5"},{"location":"python/Foundation/ch04/#python_1","text":"\u4ece\u9b54\u672f\u65b9\u6cd5\u53ef\u4ee5\u5ef6\u7533\u5230Python\u7684**\u51fd\u6570\u5185\u7701**\uff0c\u51fd\u6570\u5185\u7701\u7684\u610f\u601d\u662f\u8bf4\uff0c\u5f53\u4f60\u62ff\u5230\u4e00\u4e2a\u201c\u51fd\u6570\u5bf9\u8c61\u201d\u7684\u65f6\u5019\uff0c\u4f60\u53ef\u4ee5\u7ee7\u7eed\u77e5\u9053\uff0c\u5b83\u7684\u540d\u5b57\uff0c\u53c2\u6570\u5b9a\u4e49\u7b49\u4fe1\u606f\u3002\u8fd9\u4e9b\u4fe1\u606f\u53ef\u4ee5\u901a\u8fc7\u51fd\u6570\u5bf9\u8c61\u7684\u5c5e\u6027\uff08\u4e00\u4e9b\u53cc\u4e0b\u5212\u7ebf\u7684\u9b54\u6cd5\u65b9\u6cd5\uff09\u5f97\u5230\u3002\u7b80\u8a00\u4e4b\uff0c\u5185\u7701\u662f\u5728\u8fd0\u884c\u65f6\u786e\u5b9a\u5bf9\u8c61\u7c7b\u578b\u7684\u80fd\u529b\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u5217\u51fa\u4e86\u5e38\u89c4\u5bf9\u8c61\u6ca1\u6709\u800c\u51fd\u6570\u6709\u7684\u5c5e\u6027\u3002 class C : pass obj = C () def func (): pass sorted ( set ( dir ( obj )) - set ( dir ( func ))) # ['__weakref__'] sorted ( set ( dir ( func )) - set ( dir ( obj ))) # ['__annotations__', '__call__', '__closure__', '__code__', '__defaults__', '__get__', '__globals__', '__kwdefaults__', '__name__', '__qualname__'] \u4e0b\u8868\u603b\u7ed3\u4e86\u7528\u6237\u5b9a\u4e49\u7684\u51fd\u6570\u7684\u5c5e\u6027\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u6f14\u793a\u4e86\u5728\u6307\u5b9a\u957f\u5ea6\u9644\u8fd1\u622a\u65ad\u5b57\u7b26\u4e32\u7684\u51fd\u6570\uff0c\u4ee5\u53ca\u63d0\u53d6\u5173\u4e8e\u51fd\u6570\u53c2\u6570\u7684\u4fe1\u606f\u7684\u65b9\u6cd5\u3002 \u53c2\u6570\u540d\u79f0\u5728 __code__.co_varnames \u4e2d\uff0c\u4f46\u8fd9\u91cc\u9762\u4e5f\u5305\u542b\u51fd\u6570\u5b9a\u4e49\u4f53\u4e2d\u521b\u5efa\u7684\u5c40\u90e8\u53d8\u91cf\u3002\u56e0\u6b64\uff0c\u53c2\u6570\u540d\u79f0\u662f\u524d N \u4e2a\u5b57\u7b26\u4e32\uff0c N \u7684\u503c\u7531 __code__.co_argcount \u786e\u5b9a\uff0c\u4f8b\u5b50\u91cc\u9762N\u662f2\uff0c\u5373\u53c2\u6570\u540d\u79f0\u662f text \u548c max_len \uff0c\u5c40\u90e8\u53d8\u91cf\u662f end \u3001 space_before \u3001 space_after \u3002 def clip ( text , max_len = 80 ): \"\"\" Get sub-string by the first blank before or after specified position. rfind() \u8fd4\u56de\u5b57\u7b26\u4e32\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u9879\u5219\u8fd4\u56de -1. \"\"\" end = None if len ( text ) > max_len : space_before = text . rfind ( ' ' , 0 , max_len ) if space_before >= 0 : end = space_before else : space_after = text . rfind ( ' ' , max_len ) if space_after >= 0 : end = space_after if end is None : end = len ( text ) return text [: end ] . rstrip () clip ( 'This is the string' , max_len = 10 ) # 'This is' clip . __defaults__ # (80,) clip . __code__ # \", line 1> clip . __code__ . co_varnames # ('text', 'max_len', 'end', 'space_before', 'space_after') clip . __code__ . co_argcount # 2 clip . __doc__ # '\\n Get sub-string by the first blank before or after specified position.\\n rfind() \u8fd4\u56de\u5b57\u7b26\u4e32\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u9879\u5219\u8fd4\u56de -1.\\n ' \u4e0a\u4f8b\u4e2d\uff0c\u53c2\u6570\u7684\u9ed8\u8ba4\u503c\u53ea\u80fd\u901a\u8fc7\u5b83\u4eec\u5728 __defaults__ \u5143\u7ec4\u4e2d\u7684\u4f4d\u7f6e\u786e\u5b9a\uff0c\u56e0\u6b64\u8981\u4ece\u540e\u5411\u524d\u626b\u63cf\u624d\u80fd\u628a\u53c2\u6570\u548c\u9ed8\u8ba4\u503c\u5bf9\u5e94\u8d77\u6765\uff0c\u6709\u4e9b\u4e0d\u5408\u7406\u3002\u5f15\u5165 inspect \u6a21\u5757\u540e\uff0c\u4e0a\u9762\u7684\u64cd\u4f5c\u5c31\u66f4\u5bb9\u6613\u4e86\u3002 inspect.signature \u51fd\u6570\u8fd4\u56de\u4e00\u4e2a inspect.Signature \u5bf9\u8c61\uff0c\u5b83\u6709\u4e00\u4e2a parameters \u5c5e\u6027\uff0c\u8fd9\u662f\u4e00\u4e2a\u6709\u5e8f\u6620\u5c04\uff0c\u628a\u53c2\u6570\u540d\u548c inspect.Parameter \u5bf9\u8c61\u5bf9\u5e94\u8d77\u6765\u3002\u5404\u4e2a Parameter \u5c5e\u6027\u4e5f\u6709\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u4f8b\u5982 name \u3001 default \u548c kind \u3002 from inspect import signature sig = signature ( clip ) type ( sig ) # print ( sig ) # (text, max_len=80) print ( str ( sig )) # (text, max_len=80) for name , param in sig . parameters . items (): print ( f ' { param . kind } : { name } = { param . default } ' ) # 1 : text = # 1 : max_len = 80 \u51fd\u6570\u6ce8\u89e3\u3002 Python 3 \u63d0\u4f9b\u4e86\u4e00\u79cd\u53e5\u6cd5\uff0c\u7528\u4e8e\u4e3a\u51fd\u6570\u58f0\u660e\u4e2d\u7684\u53c2\u6570\u548c\u8fd4\u56de\u503c\u9644\u52a0\u5143\u6570\u636e\u3002\u5bf9\u4e0a\u4f8b\u6dfb\u52a0\u6ce8\u89e3\u540e\u5982\u4e0b\u6240\u793a\uff0c\u4e8c\u8005\u552f\u4e00\u7684\u533a\u522b\u5728\u7b2c\u4e00\u884c\u3002 \u51fd\u6570\u58f0\u660e\u4e2d\u7684\u5404\u4e2a\u53c2\u6570\u53ef\u4ee5\u5728:\u4e4b\u540e\u589e\u52a0\u6ce8\u89e3\u8868\u8fbe\u5f0f\u3002 \u5982\u679c\u53c2\u6570\u6709\u9ed8\u8ba4\u503c\uff0c\u6ce8\u89e3\u653e\u5728\u53c2\u6570\u540d\u548c = \u53f7\u4e4b\u95f4\u3002 \u5982\u679c\u60f3\u6ce8\u89e3\u8fd4\u56de\u503c\uff0c\u5728)\u548c\u51fd\u6570\u58f0\u660e\u672b\u5c3e\u7684 : \u4e4b\u95f4\u6dfb\u52a0 -> \u548c\u4e00\u4e2a\u8868\u8fbe\u5f0f\u3002\u90a3\u4e2a\u8868\u8fbe\u5f0f\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\u3002 \u6ce8\u89e3\u4e2d\u6700\u5e38\u7528\u7684\u7c7b\u578b\u662f\u7c7b\uff08\u5982 str \u6216 int \uff09\u548c\u5b57\u7b26\u4e32\uff08\u5982'int > 0'\uff09\u3002\u5728\u4e0b\u4f8b\u4e2d\uff0cmax_len\u53c2\u6570\u7684\u6ce8\u89e3\u7528\u7684\u662f\u5b57\u7b26\u4e32\u3002 \u6ce8\u89e3\u4e0d\u4f1a\u505a\u4efb\u4f55\u5904\u7406\uff0c\u53ea\u662f\u5b58\u50a8\u5728\u51fd\u6570\u7684 __annotations__ \u5c5e\u6027\uff08\u4e00\u4e2a\u5b57\u5178\uff09\u4e2d\u3002\u6362\u53e5\u8bdd\u8bf4\uff0c\u6ce8\u89e3\u5bf9Python\u89e3\u91ca\u5668\u6ca1\u6709\u4efb\u4f55\u610f\u4e49\u3002 \u6ce8\u89e3\u53ea\u662f\u5143\u6570\u636e \uff0c\u53ef\u4ee5\u4f9bIDE\u3001\u6846\u67b6\u548c\u88c5\u9970\u5668\u7b49\u5de5\u5177\u4f7f\u7528\u3002 return \u952e\u4fdd\u5b58\u7684\u662f\u8fd4\u56de\u503c\u6ce8\u89e3\uff0c\u5373\u4e0b\u4f8b\u4e2d\u51fd\u6570\u58f0\u660e\u91cc\u4ee5 -> \u6807\u8bb0\u7684\u90e8\u5206\u3002 def clip ( text : str , max_len : 'int > 0' = 80 ) -> str : \"\"\" Get sub-string by the first blank before or after specified position. rfind() \u8fd4\u56de\u5b57\u7b26\u4e32\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u9879\u5219\u8fd4\u56de -1. \"\"\" end = None if len ( text ) > max_len : space_before = text . rfind ( ' ' , 0 , max_len ) if space_before >= 0 : end = space_before else : space_after = text . rfind ( ' ' , max_len ) if space_after >= 0 : end = space_after if end is None : end = len ( text ) return text [: end ] . rstrip () clip ( 'This is the string' , max_len = 10 ) # 'This is' clip . __annotations__ # {'text': , 'max_len': 'int > 0', 'return': } signature \u51fd\u6570\u8fd4\u56de\u4e00\u4e2a Signature \u5bf9\u8c61\uff0c\u5b83\u6709\u4e00\u4e2a return_annotation \u5c5e\u6027\u548c\u4e00\u4e2a parameters \u5c5e\u6027\uff0c\u540e\u8005\u662f\u4e00\u4e2a\u5b57\u5178\uff0c\u628a\u53c2\u6570\u540d\u6620\u5c04\u5230 Parameter \u5bf9\u8c61\u4e0a\u3002\u6bcf\u4e2a Parameter \u5bf9\u8c61\u81ea\u5df1\u4e5f\u6709 annotation \u5c5e\u6027\u3002 from inspect import signature sig = signature ( clip ) print ( sig . return_annotation ) # for param in sig . parameters . values (): note = repr ( param . annotation ) . ljust ( 13 ) print ( f ' { note } : { param . name } = { param . default } ' ) # : text = # 'int > 0' : max_len = 80","title":"Python\u51fd\u6570\u5185\u7701\u5185\u7701"},{"location":"python/Foundation/ch05/","text":"Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027 \u00b6 Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027\uff1a \u5c01\u88c5 \u7ee7\u627f \u591a\u6001 \u5c01\u88c5 Encapsulation \u00b6 \u5c01\u88c5\u662f\u4f7f\u7528\u7279\u6b8a\u7684\u8bed\u6cd5\uff0c\u5bf9\u6210\u5458\u5c5e\u6027\u548c\u6210\u5458\u65b9\u6cd5\u8fdb\u884c\u5305\u88c5\uff0c\u9650\u5236\u4e00\u4e9b\u8bbf\u95ee\u548c\u64cd\u4f5c\uff0c\u8fbe\u5230\u4fdd\u62a4\u548c\u9690\u85cf\u7684\u76ee\u7684\u3002 \u5c01\u88c5\u673a\u5236\u4fdd\u8bc1\u4e86\u7c7b\u5185\u90e8\u6570\u636e\u7ed3\u6784\u7684\u5b8c\u6574\u6027\uff0c\u56e0\u4e3a\u4f7f\u7528\u7c7b\u7684\u7528\u6237\u65e0\u6cd5\u76f4\u63a5\u770b\u5230\u7c7b\u4e2d\u7684\u6570\u636e\u7ed3\u6784\uff0c\u53ea\u80fd\u4f7f\u7528\u7c7b\u5141\u8bb8\u516c\u5f00\u7684\u6570\u636e\uff0c\u5f88\u597d\u5730\u907f\u514d\u4e86\u5916\u90e8\u5bf9\u5185\u90e8\u6570\u636e\u7684\u5f71\u54cd\uff0c\u63d0\u9ad8\u4e86\u7a0b\u5e8f\u7684\u53ef\u7ef4\u62a4\u6027\u3002 \u5bf9\u4e00\u4e2a\u7c7b\u5b9e\u73b0\u826f\u597d\u7684\u5c01\u88c5\uff0c\u7528\u6237\u53ea\u80fd\u501f\u52a9\u66b4\u9732\u51fa\u6765\u7684\u7c7b\u65b9\u6cd5\u6765\u8bbf\u95ee\u6570\u636e\uff0c\u53ef\u4ee5\u5728\u8fd9\u4e9b\u66b4\u9732\u7684\u65b9\u6cd5\u4e2d\u52a0\u5165\u9002\u5f53\u7684\u63a7\u5236\u903b\u8f91\uff0c\u5373\u53ef\u63a7\u5236\u7528\u6237\u5bf9\u7c7b\u4e2d\u5c5e\u6027\u6216\u65b9\u6cd5\u7684\u64cd\u4f5c\u3002 \u5bf9\u7c7b\u8fdb\u884c\u826f\u597d\u7684\u5c01\u88c5\uff0c\u4e3b\u8981\u662f\u5185\u90e8\u4f7f\u7528\u5c01\u88c5\u7684\u6210\u5458\uff0c\u4e5f\u63d0\u9ad8\u4e86\u4ee3\u7801\u7684\u590d\u7528\u6027\u3002 \u7c7b\u6210\u5458\u5c01\u88c5\u7684\u7ea7\u522b\uff1a \u516c\u6709\u7684\uff08public\uff09 \u4fdd\u62a4\u7684\uff08protected\uff09\uff0c\u5728Python\u4e2d\u5e76\u6ca1\u6709\u5b9e\u73b0protected\u5c01\u88c5\uff0c\u5c5e\u4e8e\u5f00\u53d1\u8005\u7684\u7ea6\u5b9a\u4fd7\u6210\u3002 \u79c1\u6709\u7684\uff08private\uff09\uff0c\u5728Python\u4e2dprivate\u5c01\u88c5\u662f\u901a\u8fc7\u6539\u540d\u7b56\u7565\u6765\u5b9e\u73b0\u7684\uff0c\u5e76\u4e0d\u662f\u771f\u6b63\u7684\u79c1\u6709\u5316\u3002 \u8bbf\u95ee\u9650\u5236 \u5171\u6709\u7684public \u53d7\u4fdd\u62a4\u7684protected \u79c1\u6709\u7684private \u5728\u7c7b\u7684\u5185\u90e8 OK OK OK \u5728\u7c7b\u7684\u5916\u90e8 OK No (Python\u4e2d\u53ef\u4ee5) No \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\u3002(\u53c2\u8003 \u79c1\u6709\u53d8\u91cfPrivate Variables ) name \u662f\u5171\u6709\u5c5e\u6027\uff0c\u53ef\u4ee5\u5728\u5916\u90e8\u8c03\u7528tom.name\u3002 _age \u662f\u53d7\u4fdd\u62a4\u7684\u5c5e\u6027\uff0c\u7406\u8bba\u4e0a\u5728\u5916\u90e8\u662f\u4e0d\u53ef\u8c03\u7528\u7684\uff0c\u4f46\u5728Python\u4e2d\u662f\u53ef\u4ee5\u8c03\u7528\u7684 tom._age \u3002 __phone \u662f\u79c1\u6709\u5c5e\u6027\uff0c\u5728\u5916\u90e8\u662f\u4e0d\u53ef\u8c03\u7528\u7684\uff0c tom.__get_phone() \u62a5\u9519\u201c\u5c5e\u6027\u4e0d\u5b58\u5728\u201d\u3002 \u5bf9\u5e94\u65b9\u6cd5\u4e5f\u662f\u7c7b\u4f3c\u3002 \u5728\u7c7b\u7684\u5185\u90e8\u5bf9\u53d7\u4fdd\u62a4\u5bf9\u8c61\u548c\u79c1\u6709\u5bf9\u8c61\u6ca1\u6709\u8bbf\u95ee\u9650\u5236\u3002 _get_age \u53ef\u4ee5\u8c03\u7528\u79c1\u6709\u5c5e\u6027 __phone \u3002 class Person (): name = 'name' # public _age = 0 # protected __phone = 'phone' # private def __init__ ( self , n , a , p ): self . name = n self . _age = a self . __phone = p def get_name ( self ): print ( f 'My name is { self . name } ' ) def _get_age ( self ): print ( f 'My age is { self . _age } ' ) print ( f 'My age is { self . __phone } ' ) def __get_phone ( self ): print ( f 'My phone is { self . __phone } ' ) tom = Person ( 'Tom' , 18 , 12345678 ) tom . name # 'Tom' tom . _age # 18 tom . __phone # AttributeError: 'Person' object has no attribute '__phone' tom . get_name () # My name is Tom tom . _get_age () # My age is 18 # My age is 12345678 tom . __get_phone () # AttributeError: 'Person' object has no attribute '__get_phone' \u7ee7\u627f Inheritance \u00b6 \u5728\u4e0d\u6307\u5b9a\u7ee7\u627f\u7684\u7236\u7c7b\u65f6\uff0c\u6240\u6709\u7c7b\u90fd\u7ee7\u627fobject\u7c7b\uff08\u7cfb\u7edf\u63d0\u4f9b\uff09\u3002 \u88ab\u5176\u5b83\u7c7b\u7ee7\u627f\u7684\u7c7b\uff0c\u79f0\u4e3a\u7236\u7c7b\uff0c\u6216\u8005\u57fa\u7c7b\uff0c\u6216\u8005\u8d85\u7c7b\u3002 \u7ee7\u627f\u5176\u5b83\u7c7b\u7684\u7c7b\uff0c\u79f0\u4e3a\u5b50\u7c7b\uff0c\u6216\u8005\u6d3e\u751f\u7c7b\uff08derived class\uff09\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u5c31\u62e5\u6709\u4e86\u7236\u7c7b\u4e2d\u7684\u6240\u6709\u6210\u5458\uff08\u9664\u4e86\u79c1\u6709\u6210\u5458\uff09\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u5e76\u4e0d\u4f1a\u628a\u7236\u7c7b\u7684\u6210\u5458\u590d\u5236\u7ed9\u5b50\u7c7b\uff0c\u800c\u662f\u5f15\u7528\u3002 \u5b50\u7c7b\u53ef\u4ee5\u76f4\u63a5\u8c03\u7528\u7236\u7c7b\u7684\u65b9\u6cd5 super().BaseClassName \u3002\u5982\u679c\u7236\u7c7b\u65b9\u6cd5\u6709\u53c2\u6570\u8981\u6c42\uff0c\u5b50\u7c7b\u8c03\u7528\u65f6\u4e5f\u6709\u53c2\u6570\u8981\u6c42\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u53ef\u4ee5\u91cd\u65b0\u5b9a\u4e49\u7236\u7c7b\u4e2d\u7684\u65b9\u6cd5\uff0c\u79f0\u4e3a**\u91cd\u5199\uff08Override\uff09**\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u5b9a\u4e49\u7236\u7c7b\u4e2d\u6ca1\u6709\u7684\u65b9\u6cd5\uff0c\u88ab\u79f0\u4e3a\u5bf9\u7236\u7c7b\u7684\u6269\u5c55\u3002 \u4e00\u4e2a\u7236\u7c7b\u53ef\u4ee5\u88ab\u591a\u4e2a\u5b50\u7c7b\u7ee7\u627f\u3002 **\u6d3e\u751f\u7c7b\uff08derived class\uff09**\u5b9a\u4e49\u7684\u8bed\u6cd5\u5982\u4e0b\u6240\u793a: class BaseClassName (): < statement - 1 > . . . < statement - N > class DerivedClassName ( BaseClassName ): < statement - 1 > . . . < statement - N > \u540d\u79f0 BaseClassName \u5fc5\u987b\u5b9a\u4e49\u4e8e\u5305\u542b\u6d3e\u751f\u7c7b\u5b9a\u4e49\u7684\u4f5c\u7528\u57df\u4e2d\u3002 \u4e5f\u5141\u8bb8\u7528\u5176\u4ed6\u4efb\u610f\u8868\u8fbe\u5f0f\u4ee3\u66ff\u57fa\u7c7b\u540d\u79f0\u6240\u5728\u7684\u4f4d\u7f6e\uff0c\u4f8b\u5982\uff0c\u5f53\u57fa\u7c7b\u5b9a\u4e49\u5728\u53e6\u4e00\u4e2a\u6a21\u5757\u4e2d\u7684\u65f6\u5019: class DerivedClassName ( modname . BaseClassName ): \u6d3e\u751f\u7c7b\u5b9a\u4e49\u7684\u6267\u884c\u8fc7\u7a0b\u4e0e\u57fa\u7c7b\u76f8\u540c\u3002 \u5f53\u6784\u9020\u7c7b\u5bf9\u8c61\u65f6\uff0c\u57fa\u7c7b\u4f1a\u88ab\u8bb0\u4f4f\u3002 \u6b64\u4fe1\u606f\u5c06\u88ab\u7528\u6765\u89e3\u6790\u5c5e\u6027\u5f15\u7528\uff1a\u5982\u679c\u8bf7\u6c42\u7684\u5c5e\u6027\u5728\u7c7b\u4e2d\u627e\u4e0d\u5230\uff0c\u641c\u7d22\u5c06\u8f6c\u5f80\u57fa\u7c7b\u4e2d\u8fdb\u884c\u67e5\u627e\u3002 \u5982\u679c\u57fa\u7c7b\u672c\u8eab\u4e5f\u6d3e\u751f\u81ea\u5176\u4ed6\u67d0\u4e2a\u7c7b\uff0c\u5219\u6b64\u89c4\u5219\u5c06\u88ab\u9012\u5f52\u5730\uff08recursively\uff09\u5e94\u7528\u3002 \u6d3e\u751f\u7c7b\u7684\u5b9e\u4f8b\u5316\u6ca1\u6709\u4efb\u4f55\u7279\u6b8a\u4e4b\u5904: DerivedClassName() \u4f1a\u521b\u5efa\u8be5\u7c7b\u7684\u4e00\u4e2a*\u65b0\u5b9e\u4f8b*\u3002 \u65b9\u6cd5\u5f15\u7528\u5c06\u6309\u4ee5\u4e0b\u65b9\u5f0f\u89e3\u6790\uff1a\u641c\u7d22\u76f8\u5e94\u7684\u7c7b\u5c5e\u6027\uff0c\u5982\u6709\u5fc5\u8981\u5c06\u6309\u57fa\u7c7b\u7ee7\u627f\u94fe\u9010\u6b65\u5411\u4e0b\u67e5\u627e\uff0c\u5982\u679c\u4ea7\u751f\u4e86\u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\u5219\u65b9\u6cd5\u5f15\u7528\u5c31\u751f\u6548\u3002 \u6d3e\u751f\u7c7b\u53ef\u80fd\u4f1a\u91cd\u5199\uff08override\uff09\u5176\u57fa\u7c7b\u7684\u65b9\u6cd5\u3002 \u56e0\u4e3a\u65b9\u6cd5\u5728\u8c03\u7528\u540c\u4e00\u5bf9\u8c61\u7684\u5176\u4ed6\u65b9\u6cd5\u65f6\u6ca1\u6709\u7279\u6b8a\u6743\u9650\uff0c\u6240\u4ee5\u8c03\u7528\u540c\u4e00\u57fa\u7c7b\u4e2d\u5b9a\u4e49\u7684\u53e6\u4e00\u65b9\u6cd5\u7684\u57fa\u7c7b\u65b9\u6cd5\u6700\u7ec8\u53ef\u80fd\u4f1a\u8c03\u7528\u8986\u76d6\u5b83\u7684\u6d3e\u751f\u7c7b\u7684\u65b9\u6cd5\u3002 \u5728\u6d3e\u751f\u7c7b\u4e2d\u7684\u91cd\u8f7d\u65b9\u6cd5\uff08overriding method\uff09\u5b9e\u9645\u4e0a\u53ef\u80fd\u60f3\u8981\u6269\u5c55\u800c\u975e\u7b80\u5355\u5730\u66ff\u6362\u540c\u540d\u7684\u57fa\u7c7b\u65b9\u6cd5\u3002 \u6709\u4e00\u79cd\u65b9\u5f0f\u53ef\u4ee5\u7b80\u5355\u5730\u76f4\u63a5\u8c03\u7528\u57fa\u7c7b\u65b9\u6cd5\uff1a\u5373\u8c03\u7528 BaseClassName.methodname(self, arguments) \u3002 \u8bf7\u6ce8\u610f\uff0c\u4ec5\u5f53\u6b64\u57fa\u7c7b\u53ef\u5728\u5168\u5c40\u4f5c\u7528\u57df\u4e2d\u4ee5 BaseClassName \u7684\u540d\u79f0\u88ab\u8bbf\u95ee\u65f6\u65b9\u53ef\u4f7f\u7528\u6b64\u65b9\u5f0f\u3002 Python\u6709\u4e24\u4e2a\u5185\u7f6e\u51fd\u6570\u53ef\u88ab\u7528\u4e8e\u7ee7\u627f\u673a\u5236\uff1a \u4f7f\u7528 isinstance() \u6765\u68c0\u67e5\u4e00\u4e2a\u5b9e\u4f8b\u7684\u7c7b\u578b: isinstance(obj, int) \u4ec5\u4f1a\u5728 obj.__class__ \u4e3a int \u6216\u67d0\u4e2a\u6d3e\u751f\u81ea int \u7684\u7c7b\u65f6\u4e3a True \u3002 \u4f7f\u7528 issubclass() \u6765\u68c0\u67e5\u7c7b\u7684\u7ee7\u627f\u5173\u7cfb: issubclass(bool, int) \u4e3a True \uff0c\u56e0\u4e3a bool \u662f int \u7684\u5b50\u7c7b\u3002 \u4f46\u662f\uff0c issubclass(float, int) \u4e3a False \uff0c\u56e0\u4e3a float \u4e0d\u662f int \u7684\u5b50\u7c7b\u3002 \u591a\u91cd\u7ee7\u627f Multiple Inheritance \u00b6 \u5355\u7ee7\u627f\uff08single-inheritance\uff09\uff1a\u4e00\u4e2a\u7c7b\u53ea\u80fd\u7ee7\u627f\u4e00\u4e2a\u7236\u7c7b\u65b9\u5f0f\u3002 class DerivedClassName ( BaseClassName ): < statement - 1 > . . . < statement - N > \u591a\u7ee7\u627f\uff08Multiple Inheritance\uff09\uff1a\u4e00\u4e2a\u7c7b\u53bb\u7ee7\u627f\u591a\u4e2a\u7c7b\u7684\u65b9\u5f0f\u3002\u5b9a\u4e49\u8bed\u53e5\u5982\u4e0b\u6240\u793a class DerivedClassName ( Base1 , Base2 , Base3 ): < statement - 1 > . . . < statement - N > \u5728\u6700\u7b80\u5355\u7684\u60c5\u51b5\u4e0b\uff0c\u641c\u7d22\u4ece\u7236\u7c7b\u6240\u7ee7\u627f\u5c5e\u6027\u7684\u64cd\u4f5c\u662f\u6df1\u5ea6\u4f18\u5148\uff08depth-first\uff09\u3001\u4ece\u5de6\u81f3\u53f3\uff08left-to-right\uff09\u7684\uff0c\u5f53\u5c42\u6b21\u7ed3\u6784\u4e2d\u5b58\u5728\u91cd\u53e0\u65f6\u4e0d\u4f1a\u5728\u540c\u4e00\u4e2a\u7c7b\u4e2d\u641c\u7d22\u4e24\u6b21\u3002 \u56e0\u6b64\uff0c\u5982\u679c\u67d0\u4e00\u5c5e\u6027\u5728 DerivedClassName \u4e2d\u672a\u627e\u5230\uff0c\u5219\u4f1a\u5230 Base1 \u4e2d\u641c\u7d22\u5b83\uff0c\u7136\u540e\uff08\u9012\u5f52\u5730\uff09\u5230 Base1 \u7684\u57fa\u7c7b\u4e2d\u641c\u7d22\uff0c\u5982\u679c\u5728\u90a3\u91cc\u672a\u627e\u5230\uff0c\u518d\u5230 Base2 \u4e2d\u641c\u7d22\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002 \u771f\u5b9e\u60c5\u51b5\u66f4\u590d\u6742\uff1b\u65b9\u6cd5\u89e3\u6790\u987a\u5e8f\u4f1a\u52a8\u6001\u6539\u53d8\u4ee5\u652f\u6301\u5bf9 super() \u7684\u534f\u540c\u8c03\u7528\u3002 \u8fd9\u79cd\u65b9\u5f0f\u5728\u67d0\u4e9b\u5176\u4ed6\u591a\u91cd\u7ee7\u627f\u578b\u8bed\u8a00\u4e2d\u88ab\u79f0\u4e3a**\u540e\u7eed\u65b9\u6cd5\u8c03\u7528\uff08call-next-method\uff09**\uff0c\u5b83\u6bd4**\u5355\u7ee7\u627f\uff08single-inheritance\uff09**\u8bed\u8a00\u4e2d\u7684 uper \u8c03\u7528\u66f4\u5f3a\u5927\u3002 \u52a8\u6001\u6539\u53d8\u987a\u5e8f\u662f\u6709\u5fc5\u8981\u7684\uff0c\u56e0\u4e3a\u6240\u6709\u591a\u91cd\u7ee7\u627f\u7684\u60c5\u51b5\u90fd\u4f1a\u663e\u793a\u51fa\u4e00\u4e2a\u6216\u66f4\u591a\u7684\u83f1\u5f62\u5173\u8054\uff08diamond relationships\uff09\uff08\u5373\u81f3\u5c11\u6709\u4e00\u4e2a\u7236\u7c7b\u53ef\u901a\u8fc7\u591a\u6761\u8def\u5f84\u88ab\u6700\u5e95\u5c42\u7c7b\u6240\u8bbf\u95ee\uff09\u3002 \u4f8b\u5982\uff0c\u6240\u6709\u7c7b\u90fd\u662f\u7ee7\u627f\u81ea object \uff0c\u56e0\u6b64\u4efb\u4f55\u591a\u91cd\u7ee7\u627f\u7684\u60c5\u51b5\u90fd\u63d0\u4f9b\u4e86\u4e00\u6761\u4ee5\u4e0a\u7684\u8def\u5f84\u53ef\u4ee5\u901a\u5411 object \u3002 \u4e3a\u4e86\u786e\u4fdd\u57fa\u7c7b\u4e0d\u4f1a\u88ab\u8bbf\u95ee\u4e00\u6b21\u4ee5\u4e0a\uff0c\u52a8\u6001\u7b97\u6cd5\u4f1a\u7528\u4e00\u79cd\u7279\u6b8a\u65b9\u5f0f\u5c06\u641c\u7d22\u987a\u5e8f\u7ebf\u6027\u5316\uff0c \u4fdd\u7559\u6bcf\u4e2a\u7c7b\u6240\u6307\u5b9a\u7684\u4ece\u5de6\u81f3\u53f3\u7684\u987a\u5e8f\uff0c\u53ea\u8c03\u7528\u6bcf\u4e2a\u7236\u7c7b\u4e00\u6b21\uff0c\u5e76\u4e14\u4fdd\u6301\u5355\u8c03\uff08monotonic\uff09\uff08\u5373\u4e00\u4e2a\u7c7b\u53ef\u4ee5\u88ab\u5b50\u7c7b\u5316\u800c\u4e0d\u5f71\u54cd\u5176\u7236\u7c7b\u7684\u4f18\u5148\u987a\u5e8f\uff09\u3002 \u603b\u800c\u8a00\u4e4b\uff0c\u8fd9\u4e9b\u7279\u6027\u4f7f\u5f97\u8bbe\u8ba1\u5177\u6709\u591a\u91cd\u7ee7\u627f\u7684\u53ef\u9760\u4e14\u53ef\u6269\u5c55\u7684\u7c7b\u6210\u4e3a\u53ef\u80fd\u3002 \u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u5b9a\u4e49\u4e863\u4e2a\u7c7b\u548c\u7ee7\u627f\u5173\u7cfb\u3002 class F (): def drink ( self ): print ( \"Drink Beer\" ) class M (): def drink ( self ): print ( \"Drink Red Wine\" ) class C ( F , M ): def drink ( self ): print ( \"Drink Water\" ) \u6267\u884c\u7ed3\u679c\u662f c = C () c . drink () # Drink Water \u65b9\u6cd51\uff1a\u6309\u7167mro\u8fdb\u884c\u7ee7\u627f\u67e5\u627e\u3002 \u5982\u679c\u628a C \u7c7b\u6539\u5199\u4e3a\u5982\u4e0b\uff0c\u53ef\u4ee5\u8c03\u7528\u7236\u7c7b\uff0c\u53c2\u7167 C \u7c7b\u7684mro\u8fdb\u884c\uff0c mro \u91cc\u9762\u7c7b F \u7684\u4e0a\u4e00\u7ea7\u662f\u7c7b M \uff0c\u6240\u4ee5\u7c7b F \u4e2d\u7684 super() \u5c31\u662f\u6307\u7c7b M \u3002 class C ( F , M ): def drink ( self ): super () . drink () print ( \"Drink Water\" ) c = C () c . drink () # Drink Beer # Drink Water C . mro () # [, , , ] \u65b9\u6cd52\uff1a\u201c\u6307\u540d\u9053\u59d3\u201d\u8c03\u7528\u3002\u5982\u679c\u628a C \u7c7b\u6539\u5199\u4e3a\u5982\u4e0b\uff0c\u53ef\u4ee5\u8c03\u7528 M \u7c7b\u3002 class C ( F , M ): def drink ( self ): M . drink ( self ) print ( \"Drink Water\" ) c = C () c . drink () # Drink Red Wine # Drink Water \u83f1\u5f62\u7ee7\u627f\u548c\u7ee7\u627f\u5173\u7cfb\u68c0\u6d4b \u00b6 \u83f1\u5f62\u7ee7\u627f\u7684\u63cf\u8ff0\u662f\uff0c\u7c7b A \u4f5c\u4e3a\u57fa\u7c7b\uff08\u8fd9\u91cc\u57fa\u7c7b\u662f\u6307\u975e object \u7c7b\uff09\uff0c\u7c7b B \u548c\u7c7b C \u540c\u65f6\u7ee7\u627f\u7c7b A \uff0c\u7136\u540e\u7c7b D \u53c8\u7ee7\u627f\u7c7b B \u548c\u7c7b C \uff0c\u5982\u4e0b\u56fe\uff0c\u770b\u8d77\u6765\u50cf\u4e2a\u94bb\u77f3\u7684\u5f62\u72b6\u3002 A / \\ B C \\ / D \u5728\u8fd9\u79cd\u7ed3\u6784\u4e2d\uff0c\u5728\u8c03\u7528\u987a\u5e8f\u4e0a\u5c31\u4f1a\u51fa\u73b0\u7591\u60d1\uff0c\u8c03\u7528\u987a\u5e8f\u7a76\u7adf\u662f\u4ee5\u4e0b\u54ea\u4e00\u79cd\u987a\u5e8f\u5462\uff1f D->B->A->C\uff08\u6df1\u5ea6\u4f18\u5148\uff09 D->B->C->A\uff08\u5e7f\u5ea6\u4f18\u5148\uff09 \u770b\u4e0b\u9762\u4ee3\u7801\uff0c\u5728Python3\u4e2d\uff0c**\u83f1\u5f62**\u7684\u591a\u7ee7\u627f\u5173\u7cfb\u662f\u6309\u7167D->B->C->A**\u5e7f\u5ea6\u4f18\u5148**\u7684\u641c\u7d22\u65b9\u5f0f\u3002 class A (): pass class B ( A ): def test ( self ): print ( \"init B.test()\" ) class C ( A ): def test ( self ): print ( \"init C.test()\" ) class D ( B , C ): pass d = D () d . test () # init B.test() D . mro () # [, , , , ] \u5bf9\u4e8e\u4e0b\u9762\u8fd9\u79cd**\u975e\u83f1\u5f62**\u7684\u591a\u7ee7\u627f\u5173\u7cfb\uff0c\u67e5\u627e\u987a\u5e8f\u662fA->B->E->C->F->D**\u6df1\u5ea6\u4f18\u5148**\u7684\u641c\u7d22\u65b9\u5f0f\u3002 E F | | B ( E ) C ( F ) D | | | \\ | / \\ | / A ( B , C , D ) \u4ee3\u7801\u5b9e\u73b0\uff1a class D (): def test ( self ): print ( \"init D.test()\" ) class F (): def test ( self ): print ( \"init F.test()\" ) class C ( F ): pass class E (): pass class B ( E ): pass class A ( B , C , D ): pass a = A () a . test () # init F.test() A . mro () # [, , , , , , ] \u603b\u7ed3\uff1a \u7ee7\u627f\u7ed3\u6784\u8981\u5c3d\u91cf\u7b80\u5355\uff0c\u4e0d\u8981\u8fc7\u4e8e\u590d\u6742\u3002 \u63a8\u8350\u4f7f\u7528minxins\u673a\u5236\uff0c\u5728\u591a\u7ee7\u627f\u80cc\u666f\u4e0b\uff0c\u6ee1\u8db3\u7ee7\u627f\u7684\u4ec0\u4e48\u662f\u4ec0\u4e48\u7684\u5173\u7cfb\uff08is-a\uff09 \u591a\u7ee7\u627f\u5173\u7cfb\u7684minxins\u673a\u5236 \u00b6 \u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u5982\u679c\u5728 Vehicle \u7c7b\u4e2d\u5b9a\u4e49\u4e86 fly \u7684\u65b9\u6cd5\uff0c\u4f1a\u5bfc\u81f4 Car(Vehicle) \u7684\u7ee7\u627f\u5173\u7cfb\u51fa\u73b0\u77db\u76fe\uff0c\u6c7d\u8f66\u5e76\u4e0d\u4f1a\u98de\uff0c\u4f46\u6309\u7167\u4e0a\u8ff0\u7ee7\u627f\u5173\u7cfb\uff0c\u6c7d\u8f66\u4e5f\u80fd\u98de\u4e86\u3002 \u4f46\u662f\u5982\u679c\u6c11\u822a\u98de\u673a\u548c\u76f4\u5347\u673a\u90fd\u5404\u81ea\u5199\u81ea\u5df1\u7684\u98de\u884cfly\u65b9\u6cd5\uff0c\u53c8\u8fdd\u80cc\u4e86\u4ee3\u7801\u5c3d\u53ef\u80fd\u91cd\u7528\u7684\u539f\u5219\u3002 class Vehicle : # \u4ea4\u901a\u5de5\u5177 def fly ( self ): ''' \u98de\u884c\u529f\u80fd\u76f8\u5e94\u7684\u4ee3\u7801 ''' print ( \"I am flying\" ) # \u6c11\u822a\u98de\u673a class CivilAircraft ( Vehicle ): pass # \u76f4\u5347\u98de\u673a class Helicopter ( Vehicle ): pass # \u6c7d\u8f66 class Car ( Vehicle ): pass Python\u4e2d\u6ca1\u6709\u7c7b\u4f3cJava\u63a5\u53e3interface\u7684\u529f\u80fd\uff0c\u4f46\u63d0\u4f9b\u4e86Mixins\u673a\u5236\u3002 Python\u5bf9\u4e8e Mixin \u7c7b\u7684\u547d\u540d\u65b9\u5f0f\u4e00\u822c\u4ee5 Mixin , able , ible \u4e3a\u540e\u7f00\u3002 Mixin \u7c7b\u5fc5\u987b\u529f\u80fd\u5355\u4e00\uff0c\u5982\u679c\u6709\u591a\u4e2a\u529f\u80fd\uff0c\u90a3\u5c31\u5199\u591a\u4e2aMixin\u7c7b\u3002 \u4e00\u4e2a\u7c7b\u53ef\u4ee5\u7ee7\u627f\u591a\u4e2a Mixin \u7c7b\uff0c\u4e3a\u4e86\u4fdd\u8bc1\u9075\u5faa\u7ee7\u627f\u7684\u201cis-a\u201d\u539f\u5219\uff0c\u53ea\u80fd\u7ee7\u627f\u4e00\u4e2a\u6807\u8bc6\u5176\u5f52\u5c5e\u542b\u4e49\u7684\u7236\u7c7b Mixin \u7c7b\u4e0d\u4f9d\u8d56\u4e8e\u5b50\u7c7b\u7684\u5b9e\u73b0\u3002 \u5b50\u7c7b\u5373\u4fbf\u6ca1\u6709\u7ee7\u627f\u8fd9\u4e2a Mixin \u7c7b\u7c7b\uff0c\u4e5f\u7167\u6837\u53ef\u4ee5\u5de5\u4f5c\uff0c\u5c31\u662f\u7f3a\u5c11\u4e86\u67d0\u4e2a\u529f\u80fd\u3002 \u6211\u4eec\u5b9a\u4e49\u7684 Mixin \u7c7b\u8d8a\u591a\uff0c\u5b50\u7c7b\u7684\u4ee3\u7801\u53ef\u8bfb\u6027\u5c31\u4f1a\u8d8a\u5dee\u3002 # \u4ea4\u901a\u5de5\u5177 class Vehicle : pass # \u4e3a\u5f53\u524d\u7c7b\u6df7\u5165\u4e00\u4e9b\u529f\u80fd\uff0c\u4e0d\u662f\u4e00\u4e2a\u5355\u7eaf\u7684\u7c7b class FlyableMixin : def fly ( self ): ''' \u98de\u884c\u529f\u80fd\u76f8\u5e94\u7684\u4ee3\u7801 ''' print ( \"I am flying\" ) # \u6c11\u822a\u98de\u673a class CivilAircraft ( FlyableMixin , Vehicle ): pass # \u76f4\u5347\u98de\u673a class Helicopter ( FlyableMixin , Vehicle ): pass # \u6c7d\u8f66 class Car ( Vehicle ): pass \u7ec4\u5408\uff08Class Combination\uff09 \u00b6 \u5728\u4e00\u4e2a\u7c7b\u4e2d\u4ee5\u53e6\u4e00\u4e2a\u7c7b\u7684\u5bf9\u8c61\u4f5c\u4e3a\u6570\u636e\u5c5e\u6027\uff0c\u79f0\u4e3a\u7c7b\u7684**\u7ec4\u5408**\u3002\u7ec4\u5408\u4e0e\u7ee7\u627f\u90fd\u662f\u7528\u6765\u89e3\u51b3\u4ee3\u7801\u7684\u91cd\u7528\u6027\u95ee\u9898\u3002 \u7ee7\u627f\u4f53\u73b0\u201c\u662f\u201d\u7684\u5173\u7cfb\uff0c\u5f53\u7c7b\u4e4b\u95f4\u6709\u5f88\u591a\u76f8\u540c\u4e4b\u5904\uff0c\u7528\u7ee7\u627f\u3002 \u7ec4\u5408\u4f53\u73b0\u201c\u6709\u201d\u7684\u5173\u7cfb\uff0c\u5f53\u7c7b\u4e4b\u95f4\u6709\u663e\u8457\u4e0d\u540c\uff0c\u4e00\u4e2a\u7c7b\u662f\u53e6\u4e00\u4e2a\u7c7b\u7684\u5c5e\u6027\u662f\uff0c\u7528\u7ec4\u5408\u3002 \u4e0b\u4f8b\u662f\u8ba1\u7b97\u5706\u73af\u7684\u9762\u79ef\u548c\u5468\u957f\uff0c\u5706\u73af\u662f\u7531\u4e24\u4e2a\u5706\u7ec4\u6210\u7684\uff0c\u5706\u73af\u7684\u9762\u79ef\u662f\u5916\u9762\u5706\u7684\u9762\u79ef\u51cf\u53bb\u5185\u90e8\u5706\u7684\u9762\u79ef\u3002\u5706\u73af\u7684\u5468\u957f\u662f\u5185\u90e8\u5706\u7684\u5468\u957f\u52a0\u4e0a\u5916\u90e8\u5706\u7684\u5468\u957f\u3002 \u8fd9\u4e2a\u4f8b\u5b50\u6f14\u793a\u4e86\u7c7b ring \u91cc\u9762\u7684\u5c5e\u6027 circle1 \u548c circle2 \u6b63\u662f\u53e6\u4e00\u4e2a\u7c7b Circle \u3002 from math import pi class Circle (): def __init__ ( self , r ): self . r = r def area ( self ): return pi * self . r * self . r def perimeter ( self ): return 2 * pi * self . r class Ring (): def __init__ ( self , r1 , r2 ): self . circle1 = Circle ( r1 ) self . circle2 = Circle ( r2 ) def area ( self ): return abs ( self . circle1 . area () - self . circle2 . area ()) def permiter ( self ): return self . circle1 . perimeter () + self . circle2 . perimeter () ring = Ring ( 5 , 8 ) print ( ring . area ()) # 122.52211349000193 print ( ring . permiter ()) # 81.68140899333463 \u4e0b\u9762\u7684\u4f8b\u5b50\u6f14\u793a\u4e86\u5982\u4f55\u901a\u8fc7\u4f20\u53c2\u7684\u65b9\u5f0f\u8fdb\u884c\u7c7b\u7684\u7ec4\u5408\u3002 class Birthday (): def __init__ ( self , year , month , day ): self . year = year self . month = month self . day = day class Course (): def __init__ ( self , course_name , course_period ): self . course_name = course_name self . course_period = course_period class Professor (): def __init__ ( self , name , gender , birth , course ): self . name = name self . gender = gender self . birth = birth self . course = course def teach ( self ): print ( f \"Professor name: { self . name } ; Gender: { self . gender } ; Birthday: { self . birth . year } - { self . birth . month }{ self . birth . day } , Course name: { self . course . course_name } and period: { self . course . course_period } \" ) prof = Professor ( 'Tom' , 'Male' , Birthday ( 1985 , 5 , 5 ), Course ( 'Chinese' , '2022/3/1 ~ 2022/6/30' )) prof . teach () # Professor name: Tom; Gender: Male; Birthday: 1985-55, Course name: Chinese and period: 2022/3/1 ~ 2022/6/30 \u591a\u6001 Polymorphism \u00b6 \u591a\u6001\u610f\u5473\u7740\u76f8\u540c\u7684\u51fd\u6570\u540d\u7528\u4e8e\u4e0d\u540c\u7684\u60c5\u5f62\u3002 \u5982\u4e0b\u4f8b\uff0c len() \u88ab\u7528\u4e8e\u4e0d\u540c\u7684\u60c5\u5f62\u3002 # len() being used for a string print ( len ( \"geeks\" )) # 5 # len() being used for a list print ( len ([ 10 , 20 , 30 ])) # 3 \u7c7b\u65b9\u6cd5\u7684\u591a\u6001\u6027 \u00b6 \u4e0b\u9762\u7684\u4ee3\u7801\u5c55\u793a\u4e86 Python \u5982\u4f55\u4ee5\u76f8\u540c\u7684\u65b9\u5f0f\u4f7f\u7528\u4e24\u79cd\u4e0d\u540c\u7684\u7c7b\u7c7b\u578b\u3002 \u6211\u4eec\u521b\u5efa\u4e86\u4e00\u4e2a\u904d\u5386\u5bf9\u8c61\u5143\u7ec4\u7684 for \u5faa\u73af\u3002 \u7136\u540e\u8c03\u7528\u65b9\u6cd5\u800c\u4e0d\u7528\u5173\u5fc3\u6bcf\u4e2a\u5bf9\u8c61\u662f\u54ea\u4e2a\u7c7b\u7c7b\u578b\u3002 \u6211\u4eec\u5047\u8bbe\u8fd9\u4e9b\u65b9\u6cd5\u5b9e\u9645\u4e0a\u5b58\u5728\u4e8e\u6bcf\u4e2a\u7c7b\u4e2d\u3002 class India (): def capital ( self ): print ( \"New Delhi is the capital of India.\" ) def language ( self ): print ( \"Hindi is the most widely spoken language of India.\" ) def type ( self ): print ( \"India is a developing country.\" ) class USA (): def capital ( self ): print ( \"Washington, D.C. is the capital of USA.\" ) def language ( self ): print ( \"English is the primary language of USA.\" ) def type ( self ): print ( \"USA is a developed country.\" ) obj_ind = India () obj_usa = USA () for country in ( obj_ind , obj_usa ): country . capital () country . language () country . type () # New Delhi is the capital of India. # Hindi is the most widely spoken language of India. # India is a developing country. # Washington, D.C. is the capital of USA. # English is the primary language of USA. # USA is a developed country. \u7ee7\u627f\u7684\u591a\u6001\u6027 \u00b6 \u5728 Python \u4e2d\uff0c\u591a\u6001\u5141\u8bb8\u6211\u4eec\u5728\u5b50\u7c7b\u4e2d\u5b9a\u4e49\u4e0e\u7236\u7c7b\u4e2d\u7684\u65b9\u6cd5\u540c\u540d\u7684\u65b9\u6cd5\u3002 \u5728\u7ee7\u627f\u4e2d\uff0c\u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u7684\u65b9\u6cd5\u3002 \u4f46\u662f\uff0c\u53ef\u4ee5\u4fee\u6539\u4ece\u7236\u7c7b\u7ee7\u627f\u7684\u5b50\u7c7b\u4e2d\u7684\u65b9\u6cd5\u3002 \u8fd9\u5728\u4ece\u7236\u7c7b\u7ee7\u627f\u7684\u65b9\u6cd5\u4e0d\u592a\u9002\u5408\u5b50\u7c7b\u7684\u60c5\u51b5\u4e0b\u7279\u522b\u6709\u7528\u3002 \u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u5728\u5b50\u7c7b\u4e2d\u91cd\u65b0\u5b9e\u73b0\u8be5\u65b9\u6cd5\u3002 \u8fd9\u79cd\u5728\u5b50\u7c7b\u4e2d\u91cd\u65b0\u5b9e\u73b0\u65b9\u6cd5\u7684\u8fc7\u7a0b\u79f0\u4e3a**\u65b9\u6cd5\u8986\u76d6\uff08Method Overriding\uff09**\u3002 class Bird : def intro ( self ): print ( \"There are many types of birds.\" ) def flight ( self ): print ( \"Most of the birds can fly but some cannot.\" ) class sparrow ( Bird ): def flight ( self ): print ( \"Sparrows can fly.\" ) class ostrich ( Bird ): def flight ( self ): print ( \"Ostriches cannot fly.\" ) obj_bird = Bird () obj_spr = sparrow () obj_ost = ostrich () obj_bird . intro () # There are many types of birds. obj_bird . flight () # Most of the birds can fly but some cannot. obj_spr . intro () # There are many types of birds. obj_spr . flight () # Sparrows can fly. obj_ost . intro () # There are many types of birds. obj_ost . flight () # Ostriches cannot fly. \u51fd\u6570\u548c\u5bf9\u8c61\u7684\u591a\u6001\u6027 \u00b6 \u6211\u4eec\u4e5f\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u53ef\u4ee5\u63a5\u53d7\u4efb\u4f55\u5bf9\u8c61\u7684\u51fd\u6570\uff0c\u5141\u8bb8\u591a\u6001\u6027\u3002 \u5728\u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a func() \u7684\u51fd\u6570\uff0c\u4f20\u5165\u53c2\u6570\u662f obj \u7684\u5bf9\u8c61\u3002 \u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u8c03\u7528\u4e09\u4e2a\u65b9\u6cd5\uff0c\u5373 capital() \u3001 language() \u548c type() \uff0c\u6bcf\u4e2a\u65b9\u6cd5\u90fd\u5b9a\u4e49\u5728 India \u548c USA \u4e24\u4e2a\u7c7b\u4e2d\u3002 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u76f8\u540c\u7684 func() \u51fd\u6570\u8c03\u7528\u5b83\u4eec\u7684\u52a8\u4f5c\uff1a class India (): def capital ( self ): print ( \"New Delhi is the capital of India.\" ) def language ( self ): print ( \"Hindi is the most widely spoken language of India.\" ) def type ( self ): print ( \"India is a developing country.\" ) class USA (): def capital ( self ): print ( \"Washington, D.C. is the capital of USA.\" ) def language ( self ): print ( \"English is the primary language of USA.\" ) def type ( self ): print ( \"USA is a developed country.\" ) def func ( obj ): obj . capital () obj . language () obj . type () obj_ind = India () obj_usa = USA () func ( obj_ind ) # New Delhi is the capital of India. # Hindi is the most widely spoken language of India. # India is a developing country. func ( obj_usa ) # Washington, D.C. is the capital of USA. # English is the primary language of USA. # USA is a developed country. \u9e2d\u5b50\u7c7b\u578b\uff08Ducking Typing\uff09\u548c\u767d\u9e45\u7c7b\u578b\uff08Goose Typing\uff09 \u00b6 \u5728Python\u4e2d\u5b9e\u73b0\u591a\u6001\u4e3b\u8981\u6709\u4e24\u79cd\u673a\u5236\uff1a\u767d\u9e45\u7c7b\u578b\u548c\u9e2d\u5b50\u7c7b\u578b\u3002\u767d\u9e45\u7c7b\u578b\u548c\u9e2d\u5b50\u7c7b\u578b\u4e0d\u4ec5\u662f\u4e24\u79cd\u673a\u5236\uff0c\u4e5f\u662f\u4e24\u79cd\u4e0d\u540c\u7684\u7f16\u7a0b\u98ce\u683c\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u6253\u5370\u5546\u54c1\u4ef7\u683c\u7684\u4f8b\u5b50\uff0c\u5206\u522b\u7528\u9e2d\u5b50\u7c7b\u578b\u548c\u767d\u9e45\u7c7b\u578b\u5b9e\u73b0\u3002 \u9e2d\u5b50\u7c7b\u578b\u3002 \u5728\u9e2d\u5b50\u7c7b\u578b\u7684\u5b9e\u73b0\u4e2d\uff0c\u6211\u4eec\u53ea\u9700\u8981\u4fdd\u8bc1\u8c03\u7528 price \u65b9\u6cd5\u7684\u6bcf\u4e2a\u5bf9\u8c61\u90fd\u6709 price \u65b9\u6cd5\u5373\u53ef\u3002 class Food : def price ( self ): print ( \" {} price:$4\" . format ( __class__ . __name__ )) class Clothes : def price ( self ): print ( \" {} price:$5\" . format ( __class__ . __name__ )) class Coffee : def price ( self ): print ( \" {} price:$6\" . format ( __class__ . __name__ )) if __name__ == '__main__' : goods = [ Food (), Clothes (), Coffee ()] for good in goods : good . price () # Food price:$4 # Clothes price:$5 # Coffee price:$6 \u767d\u9e45\u7c7b\u578b\u3002 \u5728\u767d\u9e45\u7c7b\u578b\u4e2d\uff0c\u76f4\u63a5\u8ba9\u6240\u6709\u5bf9\u8c61\u7684\u7c7b\u7ee7\u627f\u7236\u7c7b Good \u4e2d\u7684\u62bd\u8c61\u65b9\u6cd5 price \u3002Python\u4e2d\u7684\u767d\u9e45\u7c7b\u578b\u673a\u5236\u5c31\u662f\u5f3a\u7c7b\u578b\u8bed\u8a00\u4e2d\u5b9e\u73b0\u591a\u6001\u7684\u6807\u51c6\u6a21\u5f0f\uff0c\u5373\u901a\u8fc7\u8c03\u53d6\u7236\u7c7b\u7684\u865a\u51fd\u6570\u6216\u8005\u7ee7\u627f\u7684\u51fd\u6570\u6765\u5b8c\u6210\u4e0d\u540c\u7684\u884c\u4e3a\u3002 import abc class Good ( abc . ABC ): @abc . abstractmethod def price ( self ): pass class Food ( Good ): def price ( self ): print ( \" {} price:$4\" . format ( __class__ . __name__ )) class Clothes ( Good ): def price ( self ): print ( \" {} price:$5\" . format ( __class__ . __name__ )) if __name__ == '__main__' : goods = [ Food (), Clothes (), Coffee ()] for good in goods : good . price () # Food price:$4 # Clothes price:$5 # Coffee price:$6 \u7c7b\u65b9\u6cd5\uff08Class method\uff09\u548c\u9759\u6001\u65b9\u6cd5\uff08Static Method\uff09 \u00b6 \u7c7b\u65b9\u6cd5\uff08Class method\uff09\u4e5f\u53eb\u7ed1\u5b9a\u65b9\u6cd5\uff0c\u5fc5\u987b\u628a\u7c7b\u4f5c\u4e3a\u4f20\u5165\u53c2\u6570\uff0c\u4f7f\u7528 cls \u4f5c\u4e3a\u7b2c\u4e00\u4e2a\u4f20\u5165\u53c2\u6570\uff0c\u800c\u9759\u6001\u65b9\u6cd5\uff08Static Method\uff09\uff0c\u4e5f\u53eb\u975e\u7ed1\u5b9a\u65b9\u6cd5\uff0c\u4e0d\u9700\u8981\u7279\u5b9a\u7684\u53c2\u6570\u3002 \u7c7b\u65b9\u6cd5\u662f\u7ed1\u5b9a\u5230\u7c7b\u7684\uff0c\u4e0d\u662f\u7ed1\u5b9a\u5230\u7c7b\u5bf9\u8c61\uff0c\u6240\u4ee5\u7c7b\u65b9\u6cd5\u53ef\u4ee5\u8bbf\u95ee\u6216\u4fee\u6539\u7c7b\uff0c\u5e76\u5bf9\u6240\u6709\u7c7b\u5b9e\u4f8b\u751f\u6548\u3002 \u9759\u6001\u65b9\u6cd5\u65e0\u6cd5\u76f4\u63a5\u8bbf\u95ee\u6216\u4fee\u6539\u7c7b\uff0c\u56e0\u4e3a\u9759\u6001\u65b9\u6cd5\u662f\u4e0d\u77e5\u9053\u7c7b\u672c\u8eab\u7684\uff0c\u9759\u6001\u65b9\u6cd5\u662f\u5c5e\u4e8e\u5de5\u5177\u7c7b\u65b9\u6cd5\uff0c\u57fa\u4e8e\u4f20\u5165\u7684\u53c2\u6570\u5b8c\u6210\u7279\u5b9a\u7684\u529f\u80fd\uff0c\u5176\u5b9e\u5c31\u662f\u4e00\u4e2a\u666e\u901a\u51fd\u6570\u800c\u5df2\u3002 Python\u4e2d\u4f7f\u7528 @classmethod \u88c5\u9970\u5668\uff08decorator\uff09\u6765\u521b\u5efa\u4e00\u4e2a\u7c7b\u65b9\u6cd5\uff0c\u7528@staticmethod\u88c5\u9970\u5668\u6765\u521b\u5efa\u4e00\u4e2a\u9759\u6001\u65b9\u6cd5\u3002 \u8bed\u6cd5\u683c\u5f0f\uff1a @classmethod def fun ( cls , arg1 , arg2 , ... ): \u5176\u4e2d\uff1a fun : \u9700\u8981\u8f6c\u6362\u6210\u7c7b\u65b9\u6cd5\u7684\u51fd\u6570 returns : \u51fd\u6570\u7684\u7c7b\u65b9\u6cd5 classmethod() \u65b9\u6cd5\u7ed1\u5b9a\u5230\u7c7b\u800c\u4e0d\u662f\u5bf9\u8c61\u3002\u7c7b\u65b9\u6cd5\u53ef\u4ee5\u88ab\u7c7b\u548c\u5bf9\u8c61\u8c03\u7528\u3002\u8fd9\u4e9b\u65b9\u6cd5\u53ef\u4ee5\u901a\u8fc7\u7c7b\u6216\u5bf9\u8c61\u8fdb\u884c\u8c03\u7528\u3002 \u4f8b1\uff1a\u521b\u5efa\u4e00\u4e2a\u7b80\u5355\u7684 classmethod \u3002 \u521b\u5efa\u4e00\u4e2a\u7c7b Training \uff0c\u6709\u7c7b\u53d8\u91cf course \u548c\u65b9\u6cd5 purchase \u3002 \u6211\u4eec\u901a\u8fc7\u628a\u51fd\u6570 Training.purchase \u4f20\u7ed9 classmethod() \uff0c\u628a\u8be5\u65b9\u6cd5\u8f6c\u6210\u7c7b\u65b9\u6cd5\uff0c\u7136\u540e\u76f4\u63a5\u8c03\u7528\u5b83\uff0c\u800c\u65e0\u9700\u5148\u521b\u5efa\u5bf9\u8c61\u3002 \u53ef\u4ee5\u770b\u51fa\u8f6c\u6362\u524d\u540e Training.purchase \u7684\u7c7b\u578b\u53d8\u5316\u3002 class Training : course = 'Python for Data Analysis' def purchase ( obj ): print ( \"Puchase course : \" , obj . course ) type ( Training . purchase ) # Training . purchase = classmethod ( Training . purchase ) Training . purchase () # Puchase course : Python for Data Analysis type ( Training . purchase ) # \u4f8b2\uff1a\u4f7f\u7528\u88c5\u9970\u5668 @classmethod \u521b\u5efa\u5de5\u5382\u7c7b\u3002 class Training : def __init__ ( self , course ): self . course = course @classmethod def purchase ( cls , course ): return cls ( course ) def display ( self ): print ( 'Purchase course: ' , self . course ) training = Training ( \"Python for Data Analysis\" ) training . display () # Purchase course: Python for Data Analysis \u4f8b3\uff1a\u901a\u8fc7 staticmethod() \u548c classmethod() \u6765\u68c0\u67e5\u4e00\u4e2aperson\u662f\u5426\u662fadult\u3002 person1\u662f\u901a\u8fc7\u59d3\u540d\u548c\u5e74\u9f84\u521b\u5efa\u7684\u5b9e\u4f8b\u3002person2\u662f\u901a\u8fc7\u59d3\u540d\u548c\u5e74\u4efd\u521b\u5efa\u7684\u5b9e\u4f8b\u3002 from datetime import date class Person : def __init__ ( self , name , age ): self . name = name self . age = age @classmethod def fromBirthYear ( cls , name , year ): return cls ( name , date . today () . year - year ) @staticmethod def isAdult ( age ): return age > 18 person1 = Person ( 'mayank' , 21 ) person2 = Person . fromBirthYear ( 'mayank' , 1996 ) print ( person1 . age ) # 21 print ( person2 . age ) # 26 print ( Person . isAdult ( 22 )) # True \u5c0f\u7ed3\uff1a \u82e5\u7c7b\u4e2d\u9700\u8981\u4e00\u4e2a\u529f\u80fd\uff0c\u8be5\u529f\u80fd\u7684\u5b9e\u73b0\u4ee3\u7801\u4e2d\u9700\u8981\u5f15\u7528\u5bf9\u8c61\uff0c\u5219\u5c06\u5176\u5b9a\u4e49\u6210\u5bf9\u8c61\u65b9\u6cd5\uff1b\u9700\u8981\u5f15\u7528\u7c7b\uff0c\u5219\u5c06\u5176\u5b9a\u4e49\u6210\u7c7b\u65b9\u6cd5\uff1b\u65e0\u9700\u5f15\u7528\u7c7b\u6216\u5bf9\u8c61\uff0c\u5219\u5c06\u5176\u5b9a\u4e49\u6210\u9759\u6001\u65b9\u6cd5\u3002 \u7334\u5b50\u8865\u4e01\uff08monkey patch\uff09 \u00b6 \u7334\u5b50\u8865\u4e01\u662f\u52a8\u6001\u4e3a\u5df2\u7ecf\u521b\u5efa\u51fa\u7684\u5bf9\u8c61\u589e\u52a0\u65b0\u7684\u65b9\u6cd5\u548c\u5c5e\u6027\u6210\u5458\u7684\u4e00\u79cd\u673a\u5236\uff0c\u4e5f\u5c31\u662f\u52a8\u6001\u6253\u8865\u4e01\u3002 \u5b9e\u4f8b\u5316\u5bf9\u8c61\u7684\u7334\u5b50\u8865\u4e01\u3002 class Test : def __init__ ( self ): self . a = 1 def func1 ( self , x , y ): print ( x + y ) # \u6b63\u5e38\u5b9e\u4f8b\u5316 test = Test () test . func1 ( 1 , 1 ) # 2 # \u4fee\u6539\u5b9e\u4f8b test . func1 = lambda x , y : print ( x + 2 * y ) test . func1 ( 1 , 1 ) # 3 # \u901a\u8fc7\u4fee\u6539\u5b9e\u4f8b\uff0c\u8bbf\u95ee\u5185\u90e8\u6210\u5458\u53d8\u91cf\u3002 test . func1 = lambda x , y : print ( x + 2 * y + self . a ) test . func1 ( 1 , 1 ) # NameError: name 'self' is not defined test . func1 = lambda self , x , y : print ( x + 2 * y + self . a ) test . func1 ( test , 1 , 1 ) # 4 \u7c7b\u5bf9\u8c61\u7684\u7334\u5b50\u8865\u4e01\u3002 class Test : def __init__ ( self ): self . a = 1 def func1 ( self , x , y ): print ( x + y ) # \u4fee\u6539\u7c7b\u6210\u5458\uff0c\u5b9e\u4f8b\u5316\u540e\u7684\u7ed3\u679c\u5df2\u4fee\u6539\u3002 Test . func1 = lambda self , x , y : print ( x + 2 * y ) test = Test () test . func1 ( 1 , 1 ) # 3 # \u4fee\u6539\u7c7b\u6210\u5458\uff0c\u5e76\u8bbf\u95ee\u6210\u5458\u53d8\u91cf\uff0c\u5b9e\u4f8b\u5316\u540e\u7684\u7ed3\u679c\u5df2\u4fee\u6539\u3002 Test . func1 = lambda self , x , y : print ( x + 2 * y + self . a ) test = Test () test . func1 ( 1 , 1 ) # 4 # \u589e\u52a0\u7c7b\u6210\u5458\u3002 Test . func2 = lambda self , p , q : print ( p + 3 * q + self . a ) test = Test () test . func1 ( 1 , 1 ) # 4 test . func2 ( 1 , 3 ) # 11 \u79c1\u6709\u53d8\u91cf Private Variables \u00b6 \u90a3\u79cd\u4ec5\u9650\u4ece\u4e00\u4e2a\u5bf9\u8c61\u5185\u90e8\u8bbf\u95ee\u7684\u201c\u79c1\u6709\u201d\u5b9e\u4f8b\u53d8\u91cf\uff08\u201cPrivate\u201d instance variables\uff09\u5728 Python \u4e2d\u5e76\u4e0d\u5b58\u5728\u3002 \u4f46\u662f\uff0c\u5927\u591a\u6570 Python \u4ee3\u7801\u90fd\u9075\u5faa\u8fd9\u6837\u4e00\u4e2a\u7ea6\u5b9a\uff1a\u5e26\u6709*\u4e00\u4e2a\u524d\u7f00\u4e0b\u5212\u7ebf*\u7684\u540d\u79f0 (\u4f8b\u5982 _spam ) \u5e94\u8be5\u88ab\u5f53\u4f5c\u662f API \u7684\u975e\u516c\u6709\uff08non-public\uff09\u90e8\u5206 (\u65e0\u8bba\u5b83\u662f\u51fd\u6570\u3001\u65b9\u6cd5\u6216\u662f\u6570\u636e\u6210\u5458)\u3002 \u8fd9\u5e94\u5f53\u88ab\u89c6\u4e3a\u4e00\u4e2a\u5b9e\u73b0\u7ec6\u8282\uff0c\u53ef\u80fd\u4e0d\u7ecf\u901a\u77e5\u5373\u52a0\u4ee5\u6539\u53d8\u3002 \u7531\u4e8e\u5b58\u5728\u5bf9\u4e8e\u7c7b\u79c1\u6709\u6210\u5458\uff08class-private members\uff09\u7684\u6709\u6548\u4f7f\u7528\u573a\u666f\uff08\u4f8b\u5982\u907f\u514d\u540d\u79f0\u4e0e\u5b50\u7c7b\u6240\u5b9a\u4e49\u7684\u540d\u79f0\u76f8\u51b2\u7a81\uff09\uff0c\u56e0\u6b64\u5b58\u5728\u5bf9\u6b64\u79cd\u673a\u5236\u7684\u6709\u9650\u652f\u6301\uff0c\u79f0\u4e3a**\u540d\u79f0\u6539\u5199\uff08name mangling\uff09**\u3002 \u4efb\u4f55\u5f62\u5f0f\u4e3a __spam \u7684\u6807\u8bc6\u7b26\uff08\u81f3\u5c11\u5e26\u6709*\u4e24\u4e2a\u524d\u7f00\u4e0b\u5212\u7ebf*\uff0c\u81f3\u591a\u4e00\u4e2a\u540e\u7f00\u4e0b\u5212\u7ebf\uff09\u7684\u6587\u672c\u5c06\u88ab\u66ff\u6362\u4e3a _classname__spam \uff0c\u5176\u4e2d classname \u4e3a\u53bb\u9664\u4e86\u524d\u7f00\u4e0b\u5212\u7ebf\u7684\u5f53\u524d\u7c7b\u540d\u79f0\u3002 \u8fd9\u79cd\u6539\u5199\u4e0d\u8003\u8651\u6807\u8bc6\u7b26\u7684\u53e5\u6cd5\u4f4d\u7f6e\uff0c\u53ea\u8981\u5b83\u51fa\u73b0\u5728\u7c7b\u5b9a\u4e49\u5185\u90e8\u5c31\u4f1a\u8fdb\u884c\u3002 \u540d\u79f0\u6539\u5199\uff08Name mangling\uff09\u6709\u52a9\u4e8e\u8ba9\u5b50\u7c7b\u91cd\u8f7d\u65b9\u6cd5\uff08\uff09override methods\u800c\u4e0d\u7834\u574f\u7c7b\u5185\u65b9\u6cd5\uff08intraclass method\uff09\u8c03\u7528\u3002\u4f8b\u5982: class Mapping : def __init__ ( self , iterable ): self . items_list = [] self . __update ( iterable ) def update ( self , iterable ): for item in iterable : self . items_list . append ( item ) __update = update # private copy of original update() method class MappingSubclass ( Mapping ): def update ( self , keys , values ): # provides new signature for update() # but does not break __init__() for item in zip ( keys , values ): self . items_list . append ( item ) \u4e0a\u9762\u7684\u793a\u4f8b\u5373\u4f7f\u5728 MappingSubclass \u5f15\u5165\u4e86\u4e00\u4e2a __update \u6807\u8bc6\u7b26\u7684\u60c5\u51b5\u4e0b\u4e5f\u4e0d\u4f1a\u51fa\u9519\uff0c\u56e0\u4e3a\u5b83\u4f1a\u5728 Mapping \u7c7b\u4e2d\u88ab\u66ff\u6362\u4e3a _Mapping__update \u800c\u5728 MappingSubclass \u7c7b\u4e2d\u88ab\u66ff\u6362\u4e3a _MappingSubclass__update \u3002 \u8bf7\u6ce8\u610f\uff0c\u6539\u5199\u89c4\u5219\uff08mangling rules\uff09\u7684\u8bbe\u8ba1\u4e3b\u8981\u662f\u4e3a\u4e86\u907f\u514d\u610f\u5916\u51b2\u7a81\uff1b\u8bbf\u95ee\u6216\u4fee\u6539\u79c1\u6709\u53d8\u91cf\u4ecd\u7136\u662f\u53ef\u80fd\u7684\u3002\u8fd9\u5728\u7279\u6b8a\u60c5\u51b5\u4e0b\u751a\u81f3\u4f1a\u5f88\u6709\u7528\uff0c\u4f8b\u5982\u5728\u8c03\u8bd5\u5668\uff08debugger\uff09\u4e2d\u3002 \u8bf7\u6ce8\u610f\u4f20\u9012\u7ed9 exec() \u6216 eval() \u7684\u4ee3\u7801\u4e0d\u4f1a\u628a\u53d1\u8d77\u8c03\u7528\u7c7b\u7684\u7c7b\u540d\u89c6\u4f5c\u5f53\u524d\u7c7b\uff1b\u8fd9\u7c7b\u4f3c\u4e8e global \u8bed\u53e5\u7684\u6548\u679c\uff0c\u56e0\u6b64\u8fd9\u79cd\u6548\u679c\u4ec5\u9650\u4e8e\u540c\u65f6\u7ecf\u8fc7\u5b57\u8282\u7801\u7f16\u8bd1\u7684\u4ee3\u7801\u3002 \u540c\u6837\u7684\u9650\u5236\u4e5f\u9002\u7528\u4e8e getattr() , setattr() \u548c delattr() \uff0c\u4ee5\u53ca\u5bf9\u4e8e __dict__ \u7684\u76f4\u63a5\u5f15\u7528\u3002 \u53cd\u5c04(reflection) \u00b6 \u53cd\u5c04(reflection)\u662f\u52a8\u6001\u8bed\u8a00\u7684\u4e00\u4e2a\u7279\u6027\u3002**\u53cd\u5c04\u673a\u5236**\u6307\u7684\u662f\u5728\u7a0b\u5e8f\u7684\u8fd0\u884c\u72b6\u6001\u4e2d\uff0c\u5bf9\u4e8e\u4efb\u610f\u4e00\u4e2a\u7c7b\uff0c\u90fd\u53ef\u4ee5\u77e5\u9053\u8fd9\u4e2a\u7c7b\u7684\u6240\u6709\u5c5e\u6027\u548c\u65b9\u6cd5\uff1b\u5bf9\u4e8e\u4efb\u610f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u90fd\u80fd\u591f\u8c03\u7528\u4ed6\u7684\u4efb\u610f\u65b9\u6cd5\u548c\u5c5e\u6027\u3002\u8fd9\u79cd\u52a8\u6001\u83b7\u53d6\u7a0b\u5e8f\u4fe1\u606f\u4ee5\u53ca\u52a8\u6001\u8c03\u7528\u5bf9\u8c61\u7684\u529f\u80fd\u79f0\u4e3a\u53cd\u5c04\u673a\u5236\u3002 \u901a\u8fc7\u4e0b\u9762\u4f8b\u5b50\u53ef\u77e5\uff0c\u901a\u8fc7 dir(person) \u83b7\u53d6\u4efb\u610f\u4e00\u4e2a\u7c7b\u6216\u8005\u5bf9\u8c61\u7684\u5c5e\u6027\u5217\u8868\u3002\u901a\u8fc7\u5185\u7f6e\u51fd\u6570 hasattr \u3001 getattr \u3001 setattr \u3001 delattr \u64cd\u4f5c\u7c7b\u548c\u5bf9\u8c61\u3002 class Person : def __init__ ( self , name , age , gender ): self . name = name self . age = age self . gender = gender person = Person ( 'Tom' , 21 , 'Male' ) print ( dir ( person )) # ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'gender', 'name'] # hasattr(object,'name') # \u6309\u5b57\u7b26\u4e32'name'\u5224\u65ad\u6709\u65e0\u5c5e\u6027person.name hasattr ( person , 'name' ) # True # getattr(object, 'name', default=None) # \u7b49\u540c\u4e8eperson.name,\u4e0d\u5b58\u5728\u8be5\u5c5e\u6027\u5219\u8fd4\u56de\u9ed8\u8ba4\u503cNone getattr ( person , 'name' , None ) # 'Tom' # setattr(x, 'y', v) # \u7b49\u540c\u4e8eperson.age = 18 setattr ( person , 'age' , 18 ) print ( person . age ) # 18 # delattr(x, 'y') # \u7b49\u540c\u4e8edel person.age delattr ( person , 'age' ) print ( person . age ) # AttributeError: 'Person' object has no attribute 'age' \u4e0b\u9762\u662f\u4e00\u4e2a\u5b9e\u9645\u5e94\u7528\u7684\u4f8b\u5b50\u3002 class FtpServer (): def server_run ( self ): while True : inp = input ( 'Input your command >>:' ) . strip () cmd , file = inp . split () if hasattr ( self , cmd ): func = getattr ( self , cmd ) func ( file ) def get ( self , file ): print ( f 'Downloading { file } ...' ) def put ( self , file ): print ( f 'Uploading { file } ...' ) ftp_server = FtpServer () ftp_server . server_run () # Input your command >>:get a.ext # Downloading a.ext... # Input your command >>:put a.txt # Uploading a.txt... \u8fed\u4ee3\u5668 Iterators \u00b6 \u5728Python\u4e2d\uff0c\u5927\u591a\u6570\u5bb9\u5668\u5bf9\u8c61\uff08container object\uff09\u90fd\u53ef\u4ee5\u4f7f\u7528 for \u8bed\u53e5: for element in [ 1 , 2 , 3 ]: print ( element ) for element in ( 1 , 2 , 3 ): print ( element ) for key in { 'one' : 1 , 'two' : 2 }: print ( key ) for char in \"123\" : print ( char ) for line in open ( \"myfile.txt\" ): print ( line , end = '' ) for \u8bed\u53e5\u4f1a\u5728\u5bb9\u5668\u5bf9\u8c61\u4e0a\u8c03\u7528 iter()\u3002 \u8be5\u51fd\u6570\u8fd4\u56de\u4e00\u4e2a\u5b9a\u4e49\u4e86 __next__() \u65b9\u6cd5\u7684\u8fed\u4ee3\u5668\u5bf9\u8c61\uff0c\u6b64\u65b9\u6cd5\u5c06\u9010\u4e00\u8bbf\u95ee\u5bb9\u5668\u4e2d\u7684\u5143\u7d20\u3002 \u5f53\u5143\u7d20\u7528\u5c3d\u65f6\uff0c __next__() \u5c06\u5f15\u53d1 StopIteration \u5f02\u5e38\u6765\u901a\u77e5\u7ec8\u6b62 for \u5faa\u73af\u3002 \u53ef\u4ee5\u4f7f\u7528 next() \u5185\u7f6e\u51fd\u6570\u6765\u8c03\u7528 __next__() \u65b9\u6cd5\uff1b\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u5c55\u793a\u4e86\u521a\u521a\u63cf\u8ff0\u7684\u5177\u4f53\u8fd0\u884c\u65b9\u5f0f: >>> s = 'abc' >>> it = iter ( s ) >>> it < str_iterator object at 0x10c90e650 > >>> next ( it ) 'a' >>> next ( it ) 'b' >>> next ( it ) 'c' >>> next ( it ) Traceback ( most recent call last ): File \"\" , line 1 , in < module > next ( it ) StopIteration \u5728\u4e86\u89e3\u4e86\u8fed\u4ee3\u5668\u534f\u8bae\uff08iterator protocol\uff09\u7684\u673a\u5236\u540e\uff0c\u7ed9\u7c7b\u6dfb\u52a0\u8fed\u4ee3\u5668\u5c31\u5f88\u5bb9\u6613\u4e86\u3002 \u5b9a\u4e49\u4e00\u4e2a __iter__() \u65b9\u6cd5\u6765\u8fd4\u56de\u4e00\u4e2a\u5e26\u6709 __next__() \u65b9\u6cd5\u7684\u5bf9\u8c61\u3002 \u5982\u679c\u7c7b\u5df2\u5b9a\u4e49\u4e86 __next__() \uff0c\u5219 __iter__() \u53ef\u4ee5\u7b80\u5355\u5730\u8fd4\u56de self : class Reverse : \"\"\"Iterator for looping over a sequence backwards.\"\"\" def __init__ ( self , data ): self . data = data self . index = len ( data ) def __iter__ ( self ): return self def __next__ ( self ): if self . index == 0 : raise StopIteration self . index = self . index - 1 return self . data [ self . index ] rev = Reverse ( 'spam' ) print ( iter ( rev )) for char in rev : print ( char ) # m # a # p # s \u751f\u6210\u5668 Generators \u00b6 **\u751f\u6210\u5668\uff08Generators\uff09**\u662f\u4e00\u4e2a\u7528\u4e8e\u521b\u5efa\u8fed\u4ee3\u5668\u7684\u7b80\u5355\u800c\u5f3a\u5927\u7684\u5de5\u5177\u3002 \u5b83\u4eec\u7684\u5199\u6cd5\u7c7b\u4f3c\u4e8e\u6807\u51c6\u7684\u51fd\u6570\uff0c\u4f46\u5f53\u5b83\u4eec\u8981\u8fd4\u56de\u6570\u636e\u65f6\u4f1a\u4f7f\u7528 yield \u8bed\u53e5\u3002 \u6bcf\u6b21\u5728\u751f\u6210\u5668\u4e0a\u8c03\u7528 next() \u65f6\uff0c\u5b83\u4f1a\u4ece\u4e0a\u6b21\u79bb\u5f00\u7684\u4f4d\u7f6e\u6062\u590d\u6267\u884c\uff08\u5b83\u4f1a\u8bb0\u4f4f\u4e0a\u6b21\u6267\u884c\u8bed\u53e5\u65f6\u7684\u6240\u6709\u6570\u636e\u503c\uff09\u3002 \u4e00\u4e2a\u521b\u5efa\u751f\u6210\u5668\u7684\u793a\u4f8b\u5982\u4e0b\uff08\u6539\u5199\u4e0a\u9762\u8fed\u4ee3\u5668\u4e2d\u6240\u4e3e\u7684\u4f8b\u5b50\uff09: def reverse ( data ): for index in range ( len ( data ) - 1 , - 1 , - 1 ): yield data [ index ] for char in reverse ( 'golf' ): print ( char ) # f # l # o # g \u53ef\u4ee5\u7528\u751f\u6210\u5668\u6765\u5b8c\u6210\u7684\u64cd\u4f5c\u540c\u6837\u53ef\u4ee5\u7528\u524d\u9762\u6240\u63cf\u8ff0\u7684\u57fa\u4e8e\u7c7b\u7684\u8fed\u4ee3\u5668\u6765\u5b8c\u6210\u3002\u4f46\u751f\u6210\u5668\u7684\u5199\u6cd5\u66f4\u4e3a\u7d27\u51d1\uff0c\u56e0\u4e3a\u5b83\u4f1a\u81ea\u52a8\u521b\u5efa __iter__() \u548c __next__() \u65b9\u6cd5\u3002 \u53e6\u4e00\u4e2a\u5173\u952e\u7279\u6027\u5728\u4e8e\u5c40\u90e8\u53d8\u91cf\u548c\u6267\u884c\u72b6\u6001\u4f1a\u5728\u6bcf\u6b21\u8c03\u7528\u4e4b\u95f4\u81ea\u52a8\u4fdd\u5b58\u3002 \u8fd9\u4f7f\u5f97\u8be5\u51fd\u6570\u76f8\u6bd4\u4f7f\u7528 self.index \u548c self.data \u8fd9\u79cd\u5b9e\u4f8b\u53d8\u91cf\u7684\u65b9\u5f0f\u66f4\u6613\u7f16\u5199\u4e14\u66f4\u4e3a\u6e05\u6670\u3002 \u9664\u4e86\u4f1a\u81ea\u52a8\u521b\u5efa\u65b9\u6cd5\u548c\u4fdd\u5b58\u7a0b\u5e8f\u72b6\u6001\uff0c\u5f53\u751f\u6210\u5668\u7ec8\u7ed3\u65f6\uff0c\u5b83\u4eec\u8fd8\u4f1a\u81ea\u52a8\u5f15\u53d1 StopIteration \u3002 \u751f\u6210\u5668\u8868\u8fbe\u5f0f Generator Expressions \u00b6 \u67d0\u4e9b\u7b80\u5355\u7684\u751f\u6210\u5668\u53ef\u4ee5\u5199\u6210\u7b80\u6d01\u7684\u8868\u8fbe\u5f0f\u4ee3\u7801\uff0c\u6240\u7528\u8bed\u6cd5\u7c7b\u4f3c\u5217\u8868\u63a8\u5bfc\u5f0f\uff0c\u4f46\u5916\u5c42\u4e3a\u5706\u62ec\u53f7\u800c\u975e\u65b9\u62ec\u53f7\u3002 \u8fd9\u79cd\u8868\u8fbe\u5f0f\u88ab\u8bbe\u8ba1\u7528\u4e8e\u751f\u6210\u5668\u5c06\u7acb\u5373\u88ab\u5916\u5c42\u51fd\u6570\u6240\u4f7f\u7528\u7684\u60c5\u51b5\u3002 \u751f\u6210\u5668\u8868\u8fbe\u5f0f\u76f8\u6bd4\u5b8c\u6574\u7684\u751f\u6210\u5668\u66f4\u7d27\u51d1\u4f46\u8f83\u4e0d\u7075\u6d3b\uff0c\u76f8\u6bd4\u7b49\u6548\u7684\u5217\u8868\u63a8\u5bfc\u5f0f\u5219\u66f4\u4e3a\u8282\u7701\u5185\u5b58\u3002 \u793a\u4f8b: >>> sum ( i * i for i in range ( 10 )) # sum of squares 285 >>> xvec = [ 10 , 20 , 30 ] >>> yvec = [ 7 , 5 , 3 ] >>> sum ( x * y for x , y in zip ( xvec , yvec )) # dot product 260 >>> unique_words = set ( word for line in page for word in line . split ()) >>> valedictorian = max (( student . gpa , student . name ) for student in graduates ) >>> data = 'golf' >>> list ( data [ i ] for i in range ( len ( data ) - 1 , - 1 , - 1 )) [ 'f' , 'l' , 'o' , 'g' ] \u5143\u7c7b\uff08metaclass\uff09 \u00b6 \u6240\u6709\u7684\u5bf9\u8c61\u90fd\u662f\u5b9e\u4f8b\u5316\u6216\u8005\u8bf4\u8c03\u7528\u7c7b\u800c\u5f97\u5230\u7684\uff08\u8c03\u7528\u7c7b\u7684\u8fc7\u7a0b\u79f0\u4e3a\u7c7b\u7684\u5b9e\u4f8b\u5316\u3002 class StandfordProfessor ( object ): university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) \u4e0a\u4f8b\u4e2d\uff0c\u5bf9\u8c61 professor \u662f\u8c03\u7528\u7c7b StandfordProfessor \u5f97\u5230\u7684\u3002\u7c7b StandfordProfessor \u672c\u8d28\u4e5f\u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c \u4e0b\u9762\u53ef\u4ee5\u9a8c\u8bc1\uff0c StandfordProfessor \u662f\u8c03\u7528\u4e86\u5185\u7f6e\u7684\u7c7b type \u5f97\u5230\u7684\u3002\u8fd9\u4e2a type \u79f0\u4e3a\u5143\u7c7b\u3002 print ( type ( StandfordProfessor )) # \u5982\u679c\u4e00\u4e2a\u7c7b\u6ca1\u6709\u58f0\u660e\u81ea\u5df1\u7684\u5143\u7c7b\uff0c\u9ed8\u8ba4\u5b83\u7684\u5143\u7c7b\u5c31\u662f type \uff0c\u9664\u4e86\u4f7f\u7528\u5185\u7f6e\u5143\u7c7b type \uff0c\u6211\u4eec\u4e5f\u53ef\u4ee5\u901a\u8fc7\u7ee7\u627f type \u6765\u81ea\u5b9a\u4e49\u5143\u7c7b\uff0c\u7136\u540e\u4f7f\u7528 metaclass \u5173\u952e\u5b57\u53c2\u6570\u4e3a\u4e00\u4e2a\u7c7b\u7684\u6307\u5b9a\u5143\u7c7b\u3002 \u53ea\u6709\u7ee7\u627f\u4e86type\u7c7b\u624d\u80fd\u79f0\u4e4b\u4e3a\u4e00\u4e2a\u5143\u7c7b\uff0c\u5426\u5219\u5c31\u662f\u4e00\u4e2a\u666e\u901a\u7684\u81ea\u5b9a\u4e49\u7c7b\u3002 class Mymeta ( type ): pass class StandfordProfessor ( object , metaclass = Mymeta ): university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) \u4e0b\u9762\u8fdb\u884c\u81ea\u5b9a\u4e49\u5143\u7c7b\uff0c\u63a7\u5236\u7c7b StandfordProfessor \u7684\u8c03\u7528\u3002 \u8981\u60f3\u8ba9 professor \u8fd9\u4e2a\u5bf9\u8c61\u53d8\u6210\u4e00\u4e2a\u53ef\u8c03\u7528\u7684\u5bf9\u8c61\uff0c\u9700\u8981\u5728\u8be5\u5bf9\u8c61\u7684\u7c7b\u4e2d\u5b9a\u4e49\u4e00\u4e2a\u65b9\u6cd5 __call__ \uff0c\u8be5\u65b9\u6cd5\u4f1a\u5728\u8c03\u7528\u5bf9\u8c61\u65f6\u81ea\u52a8\u89e6\u53d1\u3002\u8c03\u7528 professor \u7684\u8fd4\u56de\u503c\u5c31\u662f __call__ \u65b9\u6cd5\u7684\u8fd4\u56de\u503c\u3002 class Mymeta ( type ): def __call__ ( self , * args , ** kwargs ): print ( self ) # \u7c7b\u540d print ( args ) # \u8f93\u5165\u53c2\u6570 print ( kwargs ) # \u8f93\u5165\u53c2\u6570 return 10086 class StandfordProfessor ( object , metaclass = Mymeta ): university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) # # ('Tom', 'Male') # {} \u7c7b\u7684\u4ea7\u751f\u8fc7\u7a0b\u5176\u5b9e\u5c31\u662f\u5143\u7c7b\u7684\u8c03\u7528\u8fc7\u7a0b,\u5373 StandfordProfessor = Mymeta('StandfordProfessor', (object), {...}) \uff0c\u8c03\u7528 Mymeta \u4f1a\u5148\u4ea7\u751f\u4e00\u4e2a\u7a7a\u5bf9\u8c61 StandfordProfessor \uff0c\u7136\u540e\u8fde\u540c\u8c03\u7528 Mymeta \u62ec\u53f7\u5185\u7684\u53c2\u6570\u4e00\u540c\u4f20\u7ed9 Mymeta \u4e0b\u7684 __init__ \u65b9\u6cd5\uff0c\u5b8c\u6210\u521d\u59cb\u5316\u3002\u6211\u4eec\u53ef\u4ee5\u57fa\u4e8e\u4e0a\u4f8b\u505a\u5982\u4e0b\u6539\u5199\u3002 class Mymeta ( type ): def __init__ ( self , class_name , class_bases , class_dic ): super ( Mymeta , self ) . __init__ ( class_name , class_bases , class_dic ) if class_name . islower (): raise TypeError ( f 'Please follow Camel-Case to change class name { class_name } ' ) if '__doc__' not in class_dic or len ( class_dic [ '__doc__' ] . strip ( ' \\n ' )) == 0 : raise TypeError ( 'Please add documentation in class {class_name} , which is mandatory.' ) class StandfordProfessor ( object , metaclass = Mymeta ): \"\"\" Documentation of class StanfordTeacher \"\"\" university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) professor . display () # Professor Tom says welcome to Standford! print ( professor . __dict__ ) # {'name': 'Tom', 'gender': 'Male'} StandfordProfessor . mro () # [, ]","title":"Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027"},{"location":"python/Foundation/ch05/#python","text":"Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027\uff1a \u5c01\u88c5 \u7ee7\u627f \u591a\u6001","title":"Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027"},{"location":"python/Foundation/ch05/#encapsulation","text":"\u5c01\u88c5\u662f\u4f7f\u7528\u7279\u6b8a\u7684\u8bed\u6cd5\uff0c\u5bf9\u6210\u5458\u5c5e\u6027\u548c\u6210\u5458\u65b9\u6cd5\u8fdb\u884c\u5305\u88c5\uff0c\u9650\u5236\u4e00\u4e9b\u8bbf\u95ee\u548c\u64cd\u4f5c\uff0c\u8fbe\u5230\u4fdd\u62a4\u548c\u9690\u85cf\u7684\u76ee\u7684\u3002 \u5c01\u88c5\u673a\u5236\u4fdd\u8bc1\u4e86\u7c7b\u5185\u90e8\u6570\u636e\u7ed3\u6784\u7684\u5b8c\u6574\u6027\uff0c\u56e0\u4e3a\u4f7f\u7528\u7c7b\u7684\u7528\u6237\u65e0\u6cd5\u76f4\u63a5\u770b\u5230\u7c7b\u4e2d\u7684\u6570\u636e\u7ed3\u6784\uff0c\u53ea\u80fd\u4f7f\u7528\u7c7b\u5141\u8bb8\u516c\u5f00\u7684\u6570\u636e\uff0c\u5f88\u597d\u5730\u907f\u514d\u4e86\u5916\u90e8\u5bf9\u5185\u90e8\u6570\u636e\u7684\u5f71\u54cd\uff0c\u63d0\u9ad8\u4e86\u7a0b\u5e8f\u7684\u53ef\u7ef4\u62a4\u6027\u3002 \u5bf9\u4e00\u4e2a\u7c7b\u5b9e\u73b0\u826f\u597d\u7684\u5c01\u88c5\uff0c\u7528\u6237\u53ea\u80fd\u501f\u52a9\u66b4\u9732\u51fa\u6765\u7684\u7c7b\u65b9\u6cd5\u6765\u8bbf\u95ee\u6570\u636e\uff0c\u53ef\u4ee5\u5728\u8fd9\u4e9b\u66b4\u9732\u7684\u65b9\u6cd5\u4e2d\u52a0\u5165\u9002\u5f53\u7684\u63a7\u5236\u903b\u8f91\uff0c\u5373\u53ef\u63a7\u5236\u7528\u6237\u5bf9\u7c7b\u4e2d\u5c5e\u6027\u6216\u65b9\u6cd5\u7684\u64cd\u4f5c\u3002 \u5bf9\u7c7b\u8fdb\u884c\u826f\u597d\u7684\u5c01\u88c5\uff0c\u4e3b\u8981\u662f\u5185\u90e8\u4f7f\u7528\u5c01\u88c5\u7684\u6210\u5458\uff0c\u4e5f\u63d0\u9ad8\u4e86\u4ee3\u7801\u7684\u590d\u7528\u6027\u3002 \u7c7b\u6210\u5458\u5c01\u88c5\u7684\u7ea7\u522b\uff1a \u516c\u6709\u7684\uff08public\uff09 \u4fdd\u62a4\u7684\uff08protected\uff09\uff0c\u5728Python\u4e2d\u5e76\u6ca1\u6709\u5b9e\u73b0protected\u5c01\u88c5\uff0c\u5c5e\u4e8e\u5f00\u53d1\u8005\u7684\u7ea6\u5b9a\u4fd7\u6210\u3002 \u79c1\u6709\u7684\uff08private\uff09\uff0c\u5728Python\u4e2dprivate\u5c01\u88c5\u662f\u901a\u8fc7\u6539\u540d\u7b56\u7565\u6765\u5b9e\u73b0\u7684\uff0c\u5e76\u4e0d\u662f\u771f\u6b63\u7684\u79c1\u6709\u5316\u3002 \u8bbf\u95ee\u9650\u5236 \u5171\u6709\u7684public \u53d7\u4fdd\u62a4\u7684protected \u79c1\u6709\u7684private \u5728\u7c7b\u7684\u5185\u90e8 OK OK OK \u5728\u7c7b\u7684\u5916\u90e8 OK No (Python\u4e2d\u53ef\u4ee5) No \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\u3002(\u53c2\u8003 \u79c1\u6709\u53d8\u91cfPrivate Variables ) name \u662f\u5171\u6709\u5c5e\u6027\uff0c\u53ef\u4ee5\u5728\u5916\u90e8\u8c03\u7528tom.name\u3002 _age \u662f\u53d7\u4fdd\u62a4\u7684\u5c5e\u6027\uff0c\u7406\u8bba\u4e0a\u5728\u5916\u90e8\u662f\u4e0d\u53ef\u8c03\u7528\u7684\uff0c\u4f46\u5728Python\u4e2d\u662f\u53ef\u4ee5\u8c03\u7528\u7684 tom._age \u3002 __phone \u662f\u79c1\u6709\u5c5e\u6027\uff0c\u5728\u5916\u90e8\u662f\u4e0d\u53ef\u8c03\u7528\u7684\uff0c tom.__get_phone() \u62a5\u9519\u201c\u5c5e\u6027\u4e0d\u5b58\u5728\u201d\u3002 \u5bf9\u5e94\u65b9\u6cd5\u4e5f\u662f\u7c7b\u4f3c\u3002 \u5728\u7c7b\u7684\u5185\u90e8\u5bf9\u53d7\u4fdd\u62a4\u5bf9\u8c61\u548c\u79c1\u6709\u5bf9\u8c61\u6ca1\u6709\u8bbf\u95ee\u9650\u5236\u3002 _get_age \u53ef\u4ee5\u8c03\u7528\u79c1\u6709\u5c5e\u6027 __phone \u3002 class Person (): name = 'name' # public _age = 0 # protected __phone = 'phone' # private def __init__ ( self , n , a , p ): self . name = n self . _age = a self . __phone = p def get_name ( self ): print ( f 'My name is { self . name } ' ) def _get_age ( self ): print ( f 'My age is { self . _age } ' ) print ( f 'My age is { self . __phone } ' ) def __get_phone ( self ): print ( f 'My phone is { self . __phone } ' ) tom = Person ( 'Tom' , 18 , 12345678 ) tom . name # 'Tom' tom . _age # 18 tom . __phone # AttributeError: 'Person' object has no attribute '__phone' tom . get_name () # My name is Tom tom . _get_age () # My age is 18 # My age is 12345678 tom . __get_phone () # AttributeError: 'Person' object has no attribute '__get_phone'","title":"\u5c01\u88c5 Encapsulation"},{"location":"python/Foundation/ch05/#inheritance","text":"\u5728\u4e0d\u6307\u5b9a\u7ee7\u627f\u7684\u7236\u7c7b\u65f6\uff0c\u6240\u6709\u7c7b\u90fd\u7ee7\u627fobject\u7c7b\uff08\u7cfb\u7edf\u63d0\u4f9b\uff09\u3002 \u88ab\u5176\u5b83\u7c7b\u7ee7\u627f\u7684\u7c7b\uff0c\u79f0\u4e3a\u7236\u7c7b\uff0c\u6216\u8005\u57fa\u7c7b\uff0c\u6216\u8005\u8d85\u7c7b\u3002 \u7ee7\u627f\u5176\u5b83\u7c7b\u7684\u7c7b\uff0c\u79f0\u4e3a\u5b50\u7c7b\uff0c\u6216\u8005\u6d3e\u751f\u7c7b\uff08derived class\uff09\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u5c31\u62e5\u6709\u4e86\u7236\u7c7b\u4e2d\u7684\u6240\u6709\u6210\u5458\uff08\u9664\u4e86\u79c1\u6709\u6210\u5458\uff09\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u5e76\u4e0d\u4f1a\u628a\u7236\u7c7b\u7684\u6210\u5458\u590d\u5236\u7ed9\u5b50\u7c7b\uff0c\u800c\u662f\u5f15\u7528\u3002 \u5b50\u7c7b\u53ef\u4ee5\u76f4\u63a5\u8c03\u7528\u7236\u7c7b\u7684\u65b9\u6cd5 super().BaseClassName \u3002\u5982\u679c\u7236\u7c7b\u65b9\u6cd5\u6709\u53c2\u6570\u8981\u6c42\uff0c\u5b50\u7c7b\u8c03\u7528\u65f6\u4e5f\u6709\u53c2\u6570\u8981\u6c42\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u53ef\u4ee5\u91cd\u65b0\u5b9a\u4e49\u7236\u7c7b\u4e2d\u7684\u65b9\u6cd5\uff0c\u79f0\u4e3a**\u91cd\u5199\uff08Override\uff09**\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u5b9a\u4e49\u7236\u7c7b\u4e2d\u6ca1\u6709\u7684\u65b9\u6cd5\uff0c\u88ab\u79f0\u4e3a\u5bf9\u7236\u7c7b\u7684\u6269\u5c55\u3002 \u4e00\u4e2a\u7236\u7c7b\u53ef\u4ee5\u88ab\u591a\u4e2a\u5b50\u7c7b\u7ee7\u627f\u3002 **\u6d3e\u751f\u7c7b\uff08derived class\uff09**\u5b9a\u4e49\u7684\u8bed\u6cd5\u5982\u4e0b\u6240\u793a: class BaseClassName (): < statement - 1 > . . . < statement - N > class DerivedClassName ( BaseClassName ): < statement - 1 > . . . < statement - N > \u540d\u79f0 BaseClassName \u5fc5\u987b\u5b9a\u4e49\u4e8e\u5305\u542b\u6d3e\u751f\u7c7b\u5b9a\u4e49\u7684\u4f5c\u7528\u57df\u4e2d\u3002 \u4e5f\u5141\u8bb8\u7528\u5176\u4ed6\u4efb\u610f\u8868\u8fbe\u5f0f\u4ee3\u66ff\u57fa\u7c7b\u540d\u79f0\u6240\u5728\u7684\u4f4d\u7f6e\uff0c\u4f8b\u5982\uff0c\u5f53\u57fa\u7c7b\u5b9a\u4e49\u5728\u53e6\u4e00\u4e2a\u6a21\u5757\u4e2d\u7684\u65f6\u5019: class DerivedClassName ( modname . BaseClassName ): \u6d3e\u751f\u7c7b\u5b9a\u4e49\u7684\u6267\u884c\u8fc7\u7a0b\u4e0e\u57fa\u7c7b\u76f8\u540c\u3002 \u5f53\u6784\u9020\u7c7b\u5bf9\u8c61\u65f6\uff0c\u57fa\u7c7b\u4f1a\u88ab\u8bb0\u4f4f\u3002 \u6b64\u4fe1\u606f\u5c06\u88ab\u7528\u6765\u89e3\u6790\u5c5e\u6027\u5f15\u7528\uff1a\u5982\u679c\u8bf7\u6c42\u7684\u5c5e\u6027\u5728\u7c7b\u4e2d\u627e\u4e0d\u5230\uff0c\u641c\u7d22\u5c06\u8f6c\u5f80\u57fa\u7c7b\u4e2d\u8fdb\u884c\u67e5\u627e\u3002 \u5982\u679c\u57fa\u7c7b\u672c\u8eab\u4e5f\u6d3e\u751f\u81ea\u5176\u4ed6\u67d0\u4e2a\u7c7b\uff0c\u5219\u6b64\u89c4\u5219\u5c06\u88ab\u9012\u5f52\u5730\uff08recursively\uff09\u5e94\u7528\u3002 \u6d3e\u751f\u7c7b\u7684\u5b9e\u4f8b\u5316\u6ca1\u6709\u4efb\u4f55\u7279\u6b8a\u4e4b\u5904: DerivedClassName() \u4f1a\u521b\u5efa\u8be5\u7c7b\u7684\u4e00\u4e2a*\u65b0\u5b9e\u4f8b*\u3002 \u65b9\u6cd5\u5f15\u7528\u5c06\u6309\u4ee5\u4e0b\u65b9\u5f0f\u89e3\u6790\uff1a\u641c\u7d22\u76f8\u5e94\u7684\u7c7b\u5c5e\u6027\uff0c\u5982\u6709\u5fc5\u8981\u5c06\u6309\u57fa\u7c7b\u7ee7\u627f\u94fe\u9010\u6b65\u5411\u4e0b\u67e5\u627e\uff0c\u5982\u679c\u4ea7\u751f\u4e86\u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\u5219\u65b9\u6cd5\u5f15\u7528\u5c31\u751f\u6548\u3002 \u6d3e\u751f\u7c7b\u53ef\u80fd\u4f1a\u91cd\u5199\uff08override\uff09\u5176\u57fa\u7c7b\u7684\u65b9\u6cd5\u3002 \u56e0\u4e3a\u65b9\u6cd5\u5728\u8c03\u7528\u540c\u4e00\u5bf9\u8c61\u7684\u5176\u4ed6\u65b9\u6cd5\u65f6\u6ca1\u6709\u7279\u6b8a\u6743\u9650\uff0c\u6240\u4ee5\u8c03\u7528\u540c\u4e00\u57fa\u7c7b\u4e2d\u5b9a\u4e49\u7684\u53e6\u4e00\u65b9\u6cd5\u7684\u57fa\u7c7b\u65b9\u6cd5\u6700\u7ec8\u53ef\u80fd\u4f1a\u8c03\u7528\u8986\u76d6\u5b83\u7684\u6d3e\u751f\u7c7b\u7684\u65b9\u6cd5\u3002 \u5728\u6d3e\u751f\u7c7b\u4e2d\u7684\u91cd\u8f7d\u65b9\u6cd5\uff08overriding method\uff09\u5b9e\u9645\u4e0a\u53ef\u80fd\u60f3\u8981\u6269\u5c55\u800c\u975e\u7b80\u5355\u5730\u66ff\u6362\u540c\u540d\u7684\u57fa\u7c7b\u65b9\u6cd5\u3002 \u6709\u4e00\u79cd\u65b9\u5f0f\u53ef\u4ee5\u7b80\u5355\u5730\u76f4\u63a5\u8c03\u7528\u57fa\u7c7b\u65b9\u6cd5\uff1a\u5373\u8c03\u7528 BaseClassName.methodname(self, arguments) \u3002 \u8bf7\u6ce8\u610f\uff0c\u4ec5\u5f53\u6b64\u57fa\u7c7b\u53ef\u5728\u5168\u5c40\u4f5c\u7528\u57df\u4e2d\u4ee5 BaseClassName \u7684\u540d\u79f0\u88ab\u8bbf\u95ee\u65f6\u65b9\u53ef\u4f7f\u7528\u6b64\u65b9\u5f0f\u3002 Python\u6709\u4e24\u4e2a\u5185\u7f6e\u51fd\u6570\u53ef\u88ab\u7528\u4e8e\u7ee7\u627f\u673a\u5236\uff1a \u4f7f\u7528 isinstance() \u6765\u68c0\u67e5\u4e00\u4e2a\u5b9e\u4f8b\u7684\u7c7b\u578b: isinstance(obj, int) \u4ec5\u4f1a\u5728 obj.__class__ \u4e3a int \u6216\u67d0\u4e2a\u6d3e\u751f\u81ea int \u7684\u7c7b\u65f6\u4e3a True \u3002 \u4f7f\u7528 issubclass() \u6765\u68c0\u67e5\u7c7b\u7684\u7ee7\u627f\u5173\u7cfb: issubclass(bool, int) \u4e3a True \uff0c\u56e0\u4e3a bool \u662f int \u7684\u5b50\u7c7b\u3002 \u4f46\u662f\uff0c issubclass(float, int) \u4e3a False \uff0c\u56e0\u4e3a float \u4e0d\u662f int \u7684\u5b50\u7c7b\u3002","title":"\u7ee7\u627f Inheritance"},{"location":"python/Foundation/ch05/#multiple-inheritance","text":"\u5355\u7ee7\u627f\uff08single-inheritance\uff09\uff1a\u4e00\u4e2a\u7c7b\u53ea\u80fd\u7ee7\u627f\u4e00\u4e2a\u7236\u7c7b\u65b9\u5f0f\u3002 class DerivedClassName ( BaseClassName ): < statement - 1 > . . . < statement - N > \u591a\u7ee7\u627f\uff08Multiple Inheritance\uff09\uff1a\u4e00\u4e2a\u7c7b\u53bb\u7ee7\u627f\u591a\u4e2a\u7c7b\u7684\u65b9\u5f0f\u3002\u5b9a\u4e49\u8bed\u53e5\u5982\u4e0b\u6240\u793a class DerivedClassName ( Base1 , Base2 , Base3 ): < statement - 1 > . . . < statement - N > \u5728\u6700\u7b80\u5355\u7684\u60c5\u51b5\u4e0b\uff0c\u641c\u7d22\u4ece\u7236\u7c7b\u6240\u7ee7\u627f\u5c5e\u6027\u7684\u64cd\u4f5c\u662f\u6df1\u5ea6\u4f18\u5148\uff08depth-first\uff09\u3001\u4ece\u5de6\u81f3\u53f3\uff08left-to-right\uff09\u7684\uff0c\u5f53\u5c42\u6b21\u7ed3\u6784\u4e2d\u5b58\u5728\u91cd\u53e0\u65f6\u4e0d\u4f1a\u5728\u540c\u4e00\u4e2a\u7c7b\u4e2d\u641c\u7d22\u4e24\u6b21\u3002 \u56e0\u6b64\uff0c\u5982\u679c\u67d0\u4e00\u5c5e\u6027\u5728 DerivedClassName \u4e2d\u672a\u627e\u5230\uff0c\u5219\u4f1a\u5230 Base1 \u4e2d\u641c\u7d22\u5b83\uff0c\u7136\u540e\uff08\u9012\u5f52\u5730\uff09\u5230 Base1 \u7684\u57fa\u7c7b\u4e2d\u641c\u7d22\uff0c\u5982\u679c\u5728\u90a3\u91cc\u672a\u627e\u5230\uff0c\u518d\u5230 Base2 \u4e2d\u641c\u7d22\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002 \u771f\u5b9e\u60c5\u51b5\u66f4\u590d\u6742\uff1b\u65b9\u6cd5\u89e3\u6790\u987a\u5e8f\u4f1a\u52a8\u6001\u6539\u53d8\u4ee5\u652f\u6301\u5bf9 super() \u7684\u534f\u540c\u8c03\u7528\u3002 \u8fd9\u79cd\u65b9\u5f0f\u5728\u67d0\u4e9b\u5176\u4ed6\u591a\u91cd\u7ee7\u627f\u578b\u8bed\u8a00\u4e2d\u88ab\u79f0\u4e3a**\u540e\u7eed\u65b9\u6cd5\u8c03\u7528\uff08call-next-method\uff09**\uff0c\u5b83\u6bd4**\u5355\u7ee7\u627f\uff08single-inheritance\uff09**\u8bed\u8a00\u4e2d\u7684 uper \u8c03\u7528\u66f4\u5f3a\u5927\u3002 \u52a8\u6001\u6539\u53d8\u987a\u5e8f\u662f\u6709\u5fc5\u8981\u7684\uff0c\u56e0\u4e3a\u6240\u6709\u591a\u91cd\u7ee7\u627f\u7684\u60c5\u51b5\u90fd\u4f1a\u663e\u793a\u51fa\u4e00\u4e2a\u6216\u66f4\u591a\u7684\u83f1\u5f62\u5173\u8054\uff08diamond relationships\uff09\uff08\u5373\u81f3\u5c11\u6709\u4e00\u4e2a\u7236\u7c7b\u53ef\u901a\u8fc7\u591a\u6761\u8def\u5f84\u88ab\u6700\u5e95\u5c42\u7c7b\u6240\u8bbf\u95ee\uff09\u3002 \u4f8b\u5982\uff0c\u6240\u6709\u7c7b\u90fd\u662f\u7ee7\u627f\u81ea object \uff0c\u56e0\u6b64\u4efb\u4f55\u591a\u91cd\u7ee7\u627f\u7684\u60c5\u51b5\u90fd\u63d0\u4f9b\u4e86\u4e00\u6761\u4ee5\u4e0a\u7684\u8def\u5f84\u53ef\u4ee5\u901a\u5411 object \u3002 \u4e3a\u4e86\u786e\u4fdd\u57fa\u7c7b\u4e0d\u4f1a\u88ab\u8bbf\u95ee\u4e00\u6b21\u4ee5\u4e0a\uff0c\u52a8\u6001\u7b97\u6cd5\u4f1a\u7528\u4e00\u79cd\u7279\u6b8a\u65b9\u5f0f\u5c06\u641c\u7d22\u987a\u5e8f\u7ebf\u6027\u5316\uff0c \u4fdd\u7559\u6bcf\u4e2a\u7c7b\u6240\u6307\u5b9a\u7684\u4ece\u5de6\u81f3\u53f3\u7684\u987a\u5e8f\uff0c\u53ea\u8c03\u7528\u6bcf\u4e2a\u7236\u7c7b\u4e00\u6b21\uff0c\u5e76\u4e14\u4fdd\u6301\u5355\u8c03\uff08monotonic\uff09\uff08\u5373\u4e00\u4e2a\u7c7b\u53ef\u4ee5\u88ab\u5b50\u7c7b\u5316\u800c\u4e0d\u5f71\u54cd\u5176\u7236\u7c7b\u7684\u4f18\u5148\u987a\u5e8f\uff09\u3002 \u603b\u800c\u8a00\u4e4b\uff0c\u8fd9\u4e9b\u7279\u6027\u4f7f\u5f97\u8bbe\u8ba1\u5177\u6709\u591a\u91cd\u7ee7\u627f\u7684\u53ef\u9760\u4e14\u53ef\u6269\u5c55\u7684\u7c7b\u6210\u4e3a\u53ef\u80fd\u3002 \u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u5b9a\u4e49\u4e863\u4e2a\u7c7b\u548c\u7ee7\u627f\u5173\u7cfb\u3002 class F (): def drink ( self ): print ( \"Drink Beer\" ) class M (): def drink ( self ): print ( \"Drink Red Wine\" ) class C ( F , M ): def drink ( self ): print ( \"Drink Water\" ) \u6267\u884c\u7ed3\u679c\u662f c = C () c . drink () # Drink Water \u65b9\u6cd51\uff1a\u6309\u7167mro\u8fdb\u884c\u7ee7\u627f\u67e5\u627e\u3002 \u5982\u679c\u628a C \u7c7b\u6539\u5199\u4e3a\u5982\u4e0b\uff0c\u53ef\u4ee5\u8c03\u7528\u7236\u7c7b\uff0c\u53c2\u7167 C \u7c7b\u7684mro\u8fdb\u884c\uff0c mro \u91cc\u9762\u7c7b F \u7684\u4e0a\u4e00\u7ea7\u662f\u7c7b M \uff0c\u6240\u4ee5\u7c7b F \u4e2d\u7684 super() \u5c31\u662f\u6307\u7c7b M \u3002 class C ( F , M ): def drink ( self ): super () . drink () print ( \"Drink Water\" ) c = C () c . drink () # Drink Beer # Drink Water C . mro () # [, , , ] \u65b9\u6cd52\uff1a\u201c\u6307\u540d\u9053\u59d3\u201d\u8c03\u7528\u3002\u5982\u679c\u628a C \u7c7b\u6539\u5199\u4e3a\u5982\u4e0b\uff0c\u53ef\u4ee5\u8c03\u7528 M \u7c7b\u3002 class C ( F , M ): def drink ( self ): M . drink ( self ) print ( \"Drink Water\" ) c = C () c . drink () # Drink Red Wine # Drink Water","title":"\u591a\u91cd\u7ee7\u627f Multiple Inheritance"},{"location":"python/Foundation/ch05/#_1","text":"\u83f1\u5f62\u7ee7\u627f\u7684\u63cf\u8ff0\u662f\uff0c\u7c7b A \u4f5c\u4e3a\u57fa\u7c7b\uff08\u8fd9\u91cc\u57fa\u7c7b\u662f\u6307\u975e object \u7c7b\uff09\uff0c\u7c7b B \u548c\u7c7b C \u540c\u65f6\u7ee7\u627f\u7c7b A \uff0c\u7136\u540e\u7c7b D \u53c8\u7ee7\u627f\u7c7b B \u548c\u7c7b C \uff0c\u5982\u4e0b\u56fe\uff0c\u770b\u8d77\u6765\u50cf\u4e2a\u94bb\u77f3\u7684\u5f62\u72b6\u3002 A / \\ B C \\ / D \u5728\u8fd9\u79cd\u7ed3\u6784\u4e2d\uff0c\u5728\u8c03\u7528\u987a\u5e8f\u4e0a\u5c31\u4f1a\u51fa\u73b0\u7591\u60d1\uff0c\u8c03\u7528\u987a\u5e8f\u7a76\u7adf\u662f\u4ee5\u4e0b\u54ea\u4e00\u79cd\u987a\u5e8f\u5462\uff1f D->B->A->C\uff08\u6df1\u5ea6\u4f18\u5148\uff09 D->B->C->A\uff08\u5e7f\u5ea6\u4f18\u5148\uff09 \u770b\u4e0b\u9762\u4ee3\u7801\uff0c\u5728Python3\u4e2d\uff0c**\u83f1\u5f62**\u7684\u591a\u7ee7\u627f\u5173\u7cfb\u662f\u6309\u7167D->B->C->A**\u5e7f\u5ea6\u4f18\u5148**\u7684\u641c\u7d22\u65b9\u5f0f\u3002 class A (): pass class B ( A ): def test ( self ): print ( \"init B.test()\" ) class C ( A ): def test ( self ): print ( \"init C.test()\" ) class D ( B , C ): pass d = D () d . test () # init B.test() D . mro () # [, , , , ] \u5bf9\u4e8e\u4e0b\u9762\u8fd9\u79cd**\u975e\u83f1\u5f62**\u7684\u591a\u7ee7\u627f\u5173\u7cfb\uff0c\u67e5\u627e\u987a\u5e8f\u662fA->B->E->C->F->D**\u6df1\u5ea6\u4f18\u5148**\u7684\u641c\u7d22\u65b9\u5f0f\u3002 E F | | B ( E ) C ( F ) D | | | \\ | / \\ | / A ( B , C , D ) \u4ee3\u7801\u5b9e\u73b0\uff1a class D (): def test ( self ): print ( \"init D.test()\" ) class F (): def test ( self ): print ( \"init F.test()\" ) class C ( F ): pass class E (): pass class B ( E ): pass class A ( B , C , D ): pass a = A () a . test () # init F.test() A . mro () # [, , , , , , ] \u603b\u7ed3\uff1a \u7ee7\u627f\u7ed3\u6784\u8981\u5c3d\u91cf\u7b80\u5355\uff0c\u4e0d\u8981\u8fc7\u4e8e\u590d\u6742\u3002 \u63a8\u8350\u4f7f\u7528minxins\u673a\u5236\uff0c\u5728\u591a\u7ee7\u627f\u80cc\u666f\u4e0b\uff0c\u6ee1\u8db3\u7ee7\u627f\u7684\u4ec0\u4e48\u662f\u4ec0\u4e48\u7684\u5173\u7cfb\uff08is-a\uff09","title":"\u83f1\u5f62\u7ee7\u627f\u548c\u7ee7\u627f\u5173\u7cfb\u68c0\u6d4b"},{"location":"python/Foundation/ch05/#minxins","text":"\u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u5982\u679c\u5728 Vehicle \u7c7b\u4e2d\u5b9a\u4e49\u4e86 fly \u7684\u65b9\u6cd5\uff0c\u4f1a\u5bfc\u81f4 Car(Vehicle) \u7684\u7ee7\u627f\u5173\u7cfb\u51fa\u73b0\u77db\u76fe\uff0c\u6c7d\u8f66\u5e76\u4e0d\u4f1a\u98de\uff0c\u4f46\u6309\u7167\u4e0a\u8ff0\u7ee7\u627f\u5173\u7cfb\uff0c\u6c7d\u8f66\u4e5f\u80fd\u98de\u4e86\u3002 \u4f46\u662f\u5982\u679c\u6c11\u822a\u98de\u673a\u548c\u76f4\u5347\u673a\u90fd\u5404\u81ea\u5199\u81ea\u5df1\u7684\u98de\u884cfly\u65b9\u6cd5\uff0c\u53c8\u8fdd\u80cc\u4e86\u4ee3\u7801\u5c3d\u53ef\u80fd\u91cd\u7528\u7684\u539f\u5219\u3002 class Vehicle : # \u4ea4\u901a\u5de5\u5177 def fly ( self ): ''' \u98de\u884c\u529f\u80fd\u76f8\u5e94\u7684\u4ee3\u7801 ''' print ( \"I am flying\" ) # \u6c11\u822a\u98de\u673a class CivilAircraft ( Vehicle ): pass # \u76f4\u5347\u98de\u673a class Helicopter ( Vehicle ): pass # \u6c7d\u8f66 class Car ( Vehicle ): pass Python\u4e2d\u6ca1\u6709\u7c7b\u4f3cJava\u63a5\u53e3interface\u7684\u529f\u80fd\uff0c\u4f46\u63d0\u4f9b\u4e86Mixins\u673a\u5236\u3002 Python\u5bf9\u4e8e Mixin \u7c7b\u7684\u547d\u540d\u65b9\u5f0f\u4e00\u822c\u4ee5 Mixin , able , ible \u4e3a\u540e\u7f00\u3002 Mixin \u7c7b\u5fc5\u987b\u529f\u80fd\u5355\u4e00\uff0c\u5982\u679c\u6709\u591a\u4e2a\u529f\u80fd\uff0c\u90a3\u5c31\u5199\u591a\u4e2aMixin\u7c7b\u3002 \u4e00\u4e2a\u7c7b\u53ef\u4ee5\u7ee7\u627f\u591a\u4e2a Mixin \u7c7b\uff0c\u4e3a\u4e86\u4fdd\u8bc1\u9075\u5faa\u7ee7\u627f\u7684\u201cis-a\u201d\u539f\u5219\uff0c\u53ea\u80fd\u7ee7\u627f\u4e00\u4e2a\u6807\u8bc6\u5176\u5f52\u5c5e\u542b\u4e49\u7684\u7236\u7c7b Mixin \u7c7b\u4e0d\u4f9d\u8d56\u4e8e\u5b50\u7c7b\u7684\u5b9e\u73b0\u3002 \u5b50\u7c7b\u5373\u4fbf\u6ca1\u6709\u7ee7\u627f\u8fd9\u4e2a Mixin \u7c7b\u7c7b\uff0c\u4e5f\u7167\u6837\u53ef\u4ee5\u5de5\u4f5c\uff0c\u5c31\u662f\u7f3a\u5c11\u4e86\u67d0\u4e2a\u529f\u80fd\u3002 \u6211\u4eec\u5b9a\u4e49\u7684 Mixin \u7c7b\u8d8a\u591a\uff0c\u5b50\u7c7b\u7684\u4ee3\u7801\u53ef\u8bfb\u6027\u5c31\u4f1a\u8d8a\u5dee\u3002 # \u4ea4\u901a\u5de5\u5177 class Vehicle : pass # \u4e3a\u5f53\u524d\u7c7b\u6df7\u5165\u4e00\u4e9b\u529f\u80fd\uff0c\u4e0d\u662f\u4e00\u4e2a\u5355\u7eaf\u7684\u7c7b class FlyableMixin : def fly ( self ): ''' \u98de\u884c\u529f\u80fd\u76f8\u5e94\u7684\u4ee3\u7801 ''' print ( \"I am flying\" ) # \u6c11\u822a\u98de\u673a class CivilAircraft ( FlyableMixin , Vehicle ): pass # \u76f4\u5347\u98de\u673a class Helicopter ( FlyableMixin , Vehicle ): pass # \u6c7d\u8f66 class Car ( Vehicle ): pass","title":"\u591a\u7ee7\u627f\u5173\u7cfb\u7684minxins\u673a\u5236"},{"location":"python/Foundation/ch05/#class-combination","text":"\u5728\u4e00\u4e2a\u7c7b\u4e2d\u4ee5\u53e6\u4e00\u4e2a\u7c7b\u7684\u5bf9\u8c61\u4f5c\u4e3a\u6570\u636e\u5c5e\u6027\uff0c\u79f0\u4e3a\u7c7b\u7684**\u7ec4\u5408**\u3002\u7ec4\u5408\u4e0e\u7ee7\u627f\u90fd\u662f\u7528\u6765\u89e3\u51b3\u4ee3\u7801\u7684\u91cd\u7528\u6027\u95ee\u9898\u3002 \u7ee7\u627f\u4f53\u73b0\u201c\u662f\u201d\u7684\u5173\u7cfb\uff0c\u5f53\u7c7b\u4e4b\u95f4\u6709\u5f88\u591a\u76f8\u540c\u4e4b\u5904\uff0c\u7528\u7ee7\u627f\u3002 \u7ec4\u5408\u4f53\u73b0\u201c\u6709\u201d\u7684\u5173\u7cfb\uff0c\u5f53\u7c7b\u4e4b\u95f4\u6709\u663e\u8457\u4e0d\u540c\uff0c\u4e00\u4e2a\u7c7b\u662f\u53e6\u4e00\u4e2a\u7c7b\u7684\u5c5e\u6027\u662f\uff0c\u7528\u7ec4\u5408\u3002 \u4e0b\u4f8b\u662f\u8ba1\u7b97\u5706\u73af\u7684\u9762\u79ef\u548c\u5468\u957f\uff0c\u5706\u73af\u662f\u7531\u4e24\u4e2a\u5706\u7ec4\u6210\u7684\uff0c\u5706\u73af\u7684\u9762\u79ef\u662f\u5916\u9762\u5706\u7684\u9762\u79ef\u51cf\u53bb\u5185\u90e8\u5706\u7684\u9762\u79ef\u3002\u5706\u73af\u7684\u5468\u957f\u662f\u5185\u90e8\u5706\u7684\u5468\u957f\u52a0\u4e0a\u5916\u90e8\u5706\u7684\u5468\u957f\u3002 \u8fd9\u4e2a\u4f8b\u5b50\u6f14\u793a\u4e86\u7c7b ring \u91cc\u9762\u7684\u5c5e\u6027 circle1 \u548c circle2 \u6b63\u662f\u53e6\u4e00\u4e2a\u7c7b Circle \u3002 from math import pi class Circle (): def __init__ ( self , r ): self . r = r def area ( self ): return pi * self . r * self . r def perimeter ( self ): return 2 * pi * self . r class Ring (): def __init__ ( self , r1 , r2 ): self . circle1 = Circle ( r1 ) self . circle2 = Circle ( r2 ) def area ( self ): return abs ( self . circle1 . area () - self . circle2 . area ()) def permiter ( self ): return self . circle1 . perimeter () + self . circle2 . perimeter () ring = Ring ( 5 , 8 ) print ( ring . area ()) # 122.52211349000193 print ( ring . permiter ()) # 81.68140899333463 \u4e0b\u9762\u7684\u4f8b\u5b50\u6f14\u793a\u4e86\u5982\u4f55\u901a\u8fc7\u4f20\u53c2\u7684\u65b9\u5f0f\u8fdb\u884c\u7c7b\u7684\u7ec4\u5408\u3002 class Birthday (): def __init__ ( self , year , month , day ): self . year = year self . month = month self . day = day class Course (): def __init__ ( self , course_name , course_period ): self . course_name = course_name self . course_period = course_period class Professor (): def __init__ ( self , name , gender , birth , course ): self . name = name self . gender = gender self . birth = birth self . course = course def teach ( self ): print ( f \"Professor name: { self . name } ; Gender: { self . gender } ; Birthday: { self . birth . year } - { self . birth . month }{ self . birth . day } , Course name: { self . course . course_name } and period: { self . course . course_period } \" ) prof = Professor ( 'Tom' , 'Male' , Birthday ( 1985 , 5 , 5 ), Course ( 'Chinese' , '2022/3/1 ~ 2022/6/30' )) prof . teach () # Professor name: Tom; Gender: Male; Birthday: 1985-55, Course name: Chinese and period: 2022/3/1 ~ 2022/6/30","title":"\u7ec4\u5408\uff08Class Combination\uff09"},{"location":"python/Foundation/ch05/#polymorphism","text":"\u591a\u6001\u610f\u5473\u7740\u76f8\u540c\u7684\u51fd\u6570\u540d\u7528\u4e8e\u4e0d\u540c\u7684\u60c5\u5f62\u3002 \u5982\u4e0b\u4f8b\uff0c len() \u88ab\u7528\u4e8e\u4e0d\u540c\u7684\u60c5\u5f62\u3002 # len() being used for a string print ( len ( \"geeks\" )) # 5 # len() being used for a list print ( len ([ 10 , 20 , 30 ])) # 3","title":"\u591a\u6001 Polymorphism"},{"location":"python/Foundation/ch05/#_2","text":"\u4e0b\u9762\u7684\u4ee3\u7801\u5c55\u793a\u4e86 Python \u5982\u4f55\u4ee5\u76f8\u540c\u7684\u65b9\u5f0f\u4f7f\u7528\u4e24\u79cd\u4e0d\u540c\u7684\u7c7b\u7c7b\u578b\u3002 \u6211\u4eec\u521b\u5efa\u4e86\u4e00\u4e2a\u904d\u5386\u5bf9\u8c61\u5143\u7ec4\u7684 for \u5faa\u73af\u3002 \u7136\u540e\u8c03\u7528\u65b9\u6cd5\u800c\u4e0d\u7528\u5173\u5fc3\u6bcf\u4e2a\u5bf9\u8c61\u662f\u54ea\u4e2a\u7c7b\u7c7b\u578b\u3002 \u6211\u4eec\u5047\u8bbe\u8fd9\u4e9b\u65b9\u6cd5\u5b9e\u9645\u4e0a\u5b58\u5728\u4e8e\u6bcf\u4e2a\u7c7b\u4e2d\u3002 class India (): def capital ( self ): print ( \"New Delhi is the capital of India.\" ) def language ( self ): print ( \"Hindi is the most widely spoken language of India.\" ) def type ( self ): print ( \"India is a developing country.\" ) class USA (): def capital ( self ): print ( \"Washington, D.C. is the capital of USA.\" ) def language ( self ): print ( \"English is the primary language of USA.\" ) def type ( self ): print ( \"USA is a developed country.\" ) obj_ind = India () obj_usa = USA () for country in ( obj_ind , obj_usa ): country . capital () country . language () country . type () # New Delhi is the capital of India. # Hindi is the most widely spoken language of India. # India is a developing country. # Washington, D.C. is the capital of USA. # English is the primary language of USA. # USA is a developed country.","title":"\u7c7b\u65b9\u6cd5\u7684\u591a\u6001\u6027"},{"location":"python/Foundation/ch05/#_3","text":"\u5728 Python \u4e2d\uff0c\u591a\u6001\u5141\u8bb8\u6211\u4eec\u5728\u5b50\u7c7b\u4e2d\u5b9a\u4e49\u4e0e\u7236\u7c7b\u4e2d\u7684\u65b9\u6cd5\u540c\u540d\u7684\u65b9\u6cd5\u3002 \u5728\u7ee7\u627f\u4e2d\uff0c\u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u7684\u65b9\u6cd5\u3002 \u4f46\u662f\uff0c\u53ef\u4ee5\u4fee\u6539\u4ece\u7236\u7c7b\u7ee7\u627f\u7684\u5b50\u7c7b\u4e2d\u7684\u65b9\u6cd5\u3002 \u8fd9\u5728\u4ece\u7236\u7c7b\u7ee7\u627f\u7684\u65b9\u6cd5\u4e0d\u592a\u9002\u5408\u5b50\u7c7b\u7684\u60c5\u51b5\u4e0b\u7279\u522b\u6709\u7528\u3002 \u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u5728\u5b50\u7c7b\u4e2d\u91cd\u65b0\u5b9e\u73b0\u8be5\u65b9\u6cd5\u3002 \u8fd9\u79cd\u5728\u5b50\u7c7b\u4e2d\u91cd\u65b0\u5b9e\u73b0\u65b9\u6cd5\u7684\u8fc7\u7a0b\u79f0\u4e3a**\u65b9\u6cd5\u8986\u76d6\uff08Method Overriding\uff09**\u3002 class Bird : def intro ( self ): print ( \"There are many types of birds.\" ) def flight ( self ): print ( \"Most of the birds can fly but some cannot.\" ) class sparrow ( Bird ): def flight ( self ): print ( \"Sparrows can fly.\" ) class ostrich ( Bird ): def flight ( self ): print ( \"Ostriches cannot fly.\" ) obj_bird = Bird () obj_spr = sparrow () obj_ost = ostrich () obj_bird . intro () # There are many types of birds. obj_bird . flight () # Most of the birds can fly but some cannot. obj_spr . intro () # There are many types of birds. obj_spr . flight () # Sparrows can fly. obj_ost . intro () # There are many types of birds. obj_ost . flight () # Ostriches cannot fly.","title":"\u7ee7\u627f\u7684\u591a\u6001\u6027"},{"location":"python/Foundation/ch05/#_4","text":"\u6211\u4eec\u4e5f\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u53ef\u4ee5\u63a5\u53d7\u4efb\u4f55\u5bf9\u8c61\u7684\u51fd\u6570\uff0c\u5141\u8bb8\u591a\u6001\u6027\u3002 \u5728\u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a func() \u7684\u51fd\u6570\uff0c\u4f20\u5165\u53c2\u6570\u662f obj \u7684\u5bf9\u8c61\u3002 \u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u8c03\u7528\u4e09\u4e2a\u65b9\u6cd5\uff0c\u5373 capital() \u3001 language() \u548c type() \uff0c\u6bcf\u4e2a\u65b9\u6cd5\u90fd\u5b9a\u4e49\u5728 India \u548c USA \u4e24\u4e2a\u7c7b\u4e2d\u3002 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u76f8\u540c\u7684 func() \u51fd\u6570\u8c03\u7528\u5b83\u4eec\u7684\u52a8\u4f5c\uff1a class India (): def capital ( self ): print ( \"New Delhi is the capital of India.\" ) def language ( self ): print ( \"Hindi is the most widely spoken language of India.\" ) def type ( self ): print ( \"India is a developing country.\" ) class USA (): def capital ( self ): print ( \"Washington, D.C. is the capital of USA.\" ) def language ( self ): print ( \"English is the primary language of USA.\" ) def type ( self ): print ( \"USA is a developed country.\" ) def func ( obj ): obj . capital () obj . language () obj . type () obj_ind = India () obj_usa = USA () func ( obj_ind ) # New Delhi is the capital of India. # Hindi is the most widely spoken language of India. # India is a developing country. func ( obj_usa ) # Washington, D.C. is the capital of USA. # English is the primary language of USA. # USA is a developed country.","title":"\u51fd\u6570\u548c\u5bf9\u8c61\u7684\u591a\u6001\u6027"},{"location":"python/Foundation/ch05/#ducking-typinggoose-typing","text":"\u5728Python\u4e2d\u5b9e\u73b0\u591a\u6001\u4e3b\u8981\u6709\u4e24\u79cd\u673a\u5236\uff1a\u767d\u9e45\u7c7b\u578b\u548c\u9e2d\u5b50\u7c7b\u578b\u3002\u767d\u9e45\u7c7b\u578b\u548c\u9e2d\u5b50\u7c7b\u578b\u4e0d\u4ec5\u662f\u4e24\u79cd\u673a\u5236\uff0c\u4e5f\u662f\u4e24\u79cd\u4e0d\u540c\u7684\u7f16\u7a0b\u98ce\u683c\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u6253\u5370\u5546\u54c1\u4ef7\u683c\u7684\u4f8b\u5b50\uff0c\u5206\u522b\u7528\u9e2d\u5b50\u7c7b\u578b\u548c\u767d\u9e45\u7c7b\u578b\u5b9e\u73b0\u3002 \u9e2d\u5b50\u7c7b\u578b\u3002 \u5728\u9e2d\u5b50\u7c7b\u578b\u7684\u5b9e\u73b0\u4e2d\uff0c\u6211\u4eec\u53ea\u9700\u8981\u4fdd\u8bc1\u8c03\u7528 price \u65b9\u6cd5\u7684\u6bcf\u4e2a\u5bf9\u8c61\u90fd\u6709 price \u65b9\u6cd5\u5373\u53ef\u3002 class Food : def price ( self ): print ( \" {} price:$4\" . format ( __class__ . __name__ )) class Clothes : def price ( self ): print ( \" {} price:$5\" . format ( __class__ . __name__ )) class Coffee : def price ( self ): print ( \" {} price:$6\" . format ( __class__ . __name__ )) if __name__ == '__main__' : goods = [ Food (), Clothes (), Coffee ()] for good in goods : good . price () # Food price:$4 # Clothes price:$5 # Coffee price:$6 \u767d\u9e45\u7c7b\u578b\u3002 \u5728\u767d\u9e45\u7c7b\u578b\u4e2d\uff0c\u76f4\u63a5\u8ba9\u6240\u6709\u5bf9\u8c61\u7684\u7c7b\u7ee7\u627f\u7236\u7c7b Good \u4e2d\u7684\u62bd\u8c61\u65b9\u6cd5 price \u3002Python\u4e2d\u7684\u767d\u9e45\u7c7b\u578b\u673a\u5236\u5c31\u662f\u5f3a\u7c7b\u578b\u8bed\u8a00\u4e2d\u5b9e\u73b0\u591a\u6001\u7684\u6807\u51c6\u6a21\u5f0f\uff0c\u5373\u901a\u8fc7\u8c03\u53d6\u7236\u7c7b\u7684\u865a\u51fd\u6570\u6216\u8005\u7ee7\u627f\u7684\u51fd\u6570\u6765\u5b8c\u6210\u4e0d\u540c\u7684\u884c\u4e3a\u3002 import abc class Good ( abc . ABC ): @abc . abstractmethod def price ( self ): pass class Food ( Good ): def price ( self ): print ( \" {} price:$4\" . format ( __class__ . __name__ )) class Clothes ( Good ): def price ( self ): print ( \" {} price:$5\" . format ( __class__ . __name__ )) if __name__ == '__main__' : goods = [ Food (), Clothes (), Coffee ()] for good in goods : good . price () # Food price:$4 # Clothes price:$5 # Coffee price:$6","title":"\u9e2d\u5b50\u7c7b\u578b\uff08Ducking Typing\uff09\u548c\u767d\u9e45\u7c7b\u578b\uff08Goose Typing\uff09"},{"location":"python/Foundation/ch05/#class-methodstatic-method","text":"\u7c7b\u65b9\u6cd5\uff08Class method\uff09\u4e5f\u53eb\u7ed1\u5b9a\u65b9\u6cd5\uff0c\u5fc5\u987b\u628a\u7c7b\u4f5c\u4e3a\u4f20\u5165\u53c2\u6570\uff0c\u4f7f\u7528 cls \u4f5c\u4e3a\u7b2c\u4e00\u4e2a\u4f20\u5165\u53c2\u6570\uff0c\u800c\u9759\u6001\u65b9\u6cd5\uff08Static Method\uff09\uff0c\u4e5f\u53eb\u975e\u7ed1\u5b9a\u65b9\u6cd5\uff0c\u4e0d\u9700\u8981\u7279\u5b9a\u7684\u53c2\u6570\u3002 \u7c7b\u65b9\u6cd5\u662f\u7ed1\u5b9a\u5230\u7c7b\u7684\uff0c\u4e0d\u662f\u7ed1\u5b9a\u5230\u7c7b\u5bf9\u8c61\uff0c\u6240\u4ee5\u7c7b\u65b9\u6cd5\u53ef\u4ee5\u8bbf\u95ee\u6216\u4fee\u6539\u7c7b\uff0c\u5e76\u5bf9\u6240\u6709\u7c7b\u5b9e\u4f8b\u751f\u6548\u3002 \u9759\u6001\u65b9\u6cd5\u65e0\u6cd5\u76f4\u63a5\u8bbf\u95ee\u6216\u4fee\u6539\u7c7b\uff0c\u56e0\u4e3a\u9759\u6001\u65b9\u6cd5\u662f\u4e0d\u77e5\u9053\u7c7b\u672c\u8eab\u7684\uff0c\u9759\u6001\u65b9\u6cd5\u662f\u5c5e\u4e8e\u5de5\u5177\u7c7b\u65b9\u6cd5\uff0c\u57fa\u4e8e\u4f20\u5165\u7684\u53c2\u6570\u5b8c\u6210\u7279\u5b9a\u7684\u529f\u80fd\uff0c\u5176\u5b9e\u5c31\u662f\u4e00\u4e2a\u666e\u901a\u51fd\u6570\u800c\u5df2\u3002 Python\u4e2d\u4f7f\u7528 @classmethod \u88c5\u9970\u5668\uff08decorator\uff09\u6765\u521b\u5efa\u4e00\u4e2a\u7c7b\u65b9\u6cd5\uff0c\u7528@staticmethod\u88c5\u9970\u5668\u6765\u521b\u5efa\u4e00\u4e2a\u9759\u6001\u65b9\u6cd5\u3002 \u8bed\u6cd5\u683c\u5f0f\uff1a @classmethod def fun ( cls , arg1 , arg2 , ... ): \u5176\u4e2d\uff1a fun : \u9700\u8981\u8f6c\u6362\u6210\u7c7b\u65b9\u6cd5\u7684\u51fd\u6570 returns : \u51fd\u6570\u7684\u7c7b\u65b9\u6cd5 classmethod() \u65b9\u6cd5\u7ed1\u5b9a\u5230\u7c7b\u800c\u4e0d\u662f\u5bf9\u8c61\u3002\u7c7b\u65b9\u6cd5\u53ef\u4ee5\u88ab\u7c7b\u548c\u5bf9\u8c61\u8c03\u7528\u3002\u8fd9\u4e9b\u65b9\u6cd5\u53ef\u4ee5\u901a\u8fc7\u7c7b\u6216\u5bf9\u8c61\u8fdb\u884c\u8c03\u7528\u3002 \u4f8b1\uff1a\u521b\u5efa\u4e00\u4e2a\u7b80\u5355\u7684 classmethod \u3002 \u521b\u5efa\u4e00\u4e2a\u7c7b Training \uff0c\u6709\u7c7b\u53d8\u91cf course \u548c\u65b9\u6cd5 purchase \u3002 \u6211\u4eec\u901a\u8fc7\u628a\u51fd\u6570 Training.purchase \u4f20\u7ed9 classmethod() \uff0c\u628a\u8be5\u65b9\u6cd5\u8f6c\u6210\u7c7b\u65b9\u6cd5\uff0c\u7136\u540e\u76f4\u63a5\u8c03\u7528\u5b83\uff0c\u800c\u65e0\u9700\u5148\u521b\u5efa\u5bf9\u8c61\u3002 \u53ef\u4ee5\u770b\u51fa\u8f6c\u6362\u524d\u540e Training.purchase \u7684\u7c7b\u578b\u53d8\u5316\u3002 class Training : course = 'Python for Data Analysis' def purchase ( obj ): print ( \"Puchase course : \" , obj . course ) type ( Training . purchase ) # Training . purchase = classmethod ( Training . purchase ) Training . purchase () # Puchase course : Python for Data Analysis type ( Training . purchase ) # \u4f8b2\uff1a\u4f7f\u7528\u88c5\u9970\u5668 @classmethod \u521b\u5efa\u5de5\u5382\u7c7b\u3002 class Training : def __init__ ( self , course ): self . course = course @classmethod def purchase ( cls , course ): return cls ( course ) def display ( self ): print ( 'Purchase course: ' , self . course ) training = Training ( \"Python for Data Analysis\" ) training . display () # Purchase course: Python for Data Analysis \u4f8b3\uff1a\u901a\u8fc7 staticmethod() \u548c classmethod() \u6765\u68c0\u67e5\u4e00\u4e2aperson\u662f\u5426\u662fadult\u3002 person1\u662f\u901a\u8fc7\u59d3\u540d\u548c\u5e74\u9f84\u521b\u5efa\u7684\u5b9e\u4f8b\u3002person2\u662f\u901a\u8fc7\u59d3\u540d\u548c\u5e74\u4efd\u521b\u5efa\u7684\u5b9e\u4f8b\u3002 from datetime import date class Person : def __init__ ( self , name , age ): self . name = name self . age = age @classmethod def fromBirthYear ( cls , name , year ): return cls ( name , date . today () . year - year ) @staticmethod def isAdult ( age ): return age > 18 person1 = Person ( 'mayank' , 21 ) person2 = Person . fromBirthYear ( 'mayank' , 1996 ) print ( person1 . age ) # 21 print ( person2 . age ) # 26 print ( Person . isAdult ( 22 )) # True \u5c0f\u7ed3\uff1a \u82e5\u7c7b\u4e2d\u9700\u8981\u4e00\u4e2a\u529f\u80fd\uff0c\u8be5\u529f\u80fd\u7684\u5b9e\u73b0\u4ee3\u7801\u4e2d\u9700\u8981\u5f15\u7528\u5bf9\u8c61\uff0c\u5219\u5c06\u5176\u5b9a\u4e49\u6210\u5bf9\u8c61\u65b9\u6cd5\uff1b\u9700\u8981\u5f15\u7528\u7c7b\uff0c\u5219\u5c06\u5176\u5b9a\u4e49\u6210\u7c7b\u65b9\u6cd5\uff1b\u65e0\u9700\u5f15\u7528\u7c7b\u6216\u5bf9\u8c61\uff0c\u5219\u5c06\u5176\u5b9a\u4e49\u6210\u9759\u6001\u65b9\u6cd5\u3002","title":"\u7c7b\u65b9\u6cd5\uff08Class method\uff09\u548c\u9759\u6001\u65b9\u6cd5\uff08Static Method\uff09"},{"location":"python/Foundation/ch05/#monkey-patch","text":"\u7334\u5b50\u8865\u4e01\u662f\u52a8\u6001\u4e3a\u5df2\u7ecf\u521b\u5efa\u51fa\u7684\u5bf9\u8c61\u589e\u52a0\u65b0\u7684\u65b9\u6cd5\u548c\u5c5e\u6027\u6210\u5458\u7684\u4e00\u79cd\u673a\u5236\uff0c\u4e5f\u5c31\u662f\u52a8\u6001\u6253\u8865\u4e01\u3002 \u5b9e\u4f8b\u5316\u5bf9\u8c61\u7684\u7334\u5b50\u8865\u4e01\u3002 class Test : def __init__ ( self ): self . a = 1 def func1 ( self , x , y ): print ( x + y ) # \u6b63\u5e38\u5b9e\u4f8b\u5316 test = Test () test . func1 ( 1 , 1 ) # 2 # \u4fee\u6539\u5b9e\u4f8b test . func1 = lambda x , y : print ( x + 2 * y ) test . func1 ( 1 , 1 ) # 3 # \u901a\u8fc7\u4fee\u6539\u5b9e\u4f8b\uff0c\u8bbf\u95ee\u5185\u90e8\u6210\u5458\u53d8\u91cf\u3002 test . func1 = lambda x , y : print ( x + 2 * y + self . a ) test . func1 ( 1 , 1 ) # NameError: name 'self' is not defined test . func1 = lambda self , x , y : print ( x + 2 * y + self . a ) test . func1 ( test , 1 , 1 ) # 4 \u7c7b\u5bf9\u8c61\u7684\u7334\u5b50\u8865\u4e01\u3002 class Test : def __init__ ( self ): self . a = 1 def func1 ( self , x , y ): print ( x + y ) # \u4fee\u6539\u7c7b\u6210\u5458\uff0c\u5b9e\u4f8b\u5316\u540e\u7684\u7ed3\u679c\u5df2\u4fee\u6539\u3002 Test . func1 = lambda self , x , y : print ( x + 2 * y ) test = Test () test . func1 ( 1 , 1 ) # 3 # \u4fee\u6539\u7c7b\u6210\u5458\uff0c\u5e76\u8bbf\u95ee\u6210\u5458\u53d8\u91cf\uff0c\u5b9e\u4f8b\u5316\u540e\u7684\u7ed3\u679c\u5df2\u4fee\u6539\u3002 Test . func1 = lambda self , x , y : print ( x + 2 * y + self . a ) test = Test () test . func1 ( 1 , 1 ) # 4 # \u589e\u52a0\u7c7b\u6210\u5458\u3002 Test . func2 = lambda self , p , q : print ( p + 3 * q + self . a ) test = Test () test . func1 ( 1 , 1 ) # 4 test . func2 ( 1 , 3 ) # 11","title":"\u7334\u5b50\u8865\u4e01\uff08monkey patch\uff09"},{"location":"python/Foundation/ch05/#private-variables","text":"\u90a3\u79cd\u4ec5\u9650\u4ece\u4e00\u4e2a\u5bf9\u8c61\u5185\u90e8\u8bbf\u95ee\u7684\u201c\u79c1\u6709\u201d\u5b9e\u4f8b\u53d8\u91cf\uff08\u201cPrivate\u201d instance variables\uff09\u5728 Python \u4e2d\u5e76\u4e0d\u5b58\u5728\u3002 \u4f46\u662f\uff0c\u5927\u591a\u6570 Python \u4ee3\u7801\u90fd\u9075\u5faa\u8fd9\u6837\u4e00\u4e2a\u7ea6\u5b9a\uff1a\u5e26\u6709*\u4e00\u4e2a\u524d\u7f00\u4e0b\u5212\u7ebf*\u7684\u540d\u79f0 (\u4f8b\u5982 _spam ) \u5e94\u8be5\u88ab\u5f53\u4f5c\u662f API \u7684\u975e\u516c\u6709\uff08non-public\uff09\u90e8\u5206 (\u65e0\u8bba\u5b83\u662f\u51fd\u6570\u3001\u65b9\u6cd5\u6216\u662f\u6570\u636e\u6210\u5458)\u3002 \u8fd9\u5e94\u5f53\u88ab\u89c6\u4e3a\u4e00\u4e2a\u5b9e\u73b0\u7ec6\u8282\uff0c\u53ef\u80fd\u4e0d\u7ecf\u901a\u77e5\u5373\u52a0\u4ee5\u6539\u53d8\u3002 \u7531\u4e8e\u5b58\u5728\u5bf9\u4e8e\u7c7b\u79c1\u6709\u6210\u5458\uff08class-private members\uff09\u7684\u6709\u6548\u4f7f\u7528\u573a\u666f\uff08\u4f8b\u5982\u907f\u514d\u540d\u79f0\u4e0e\u5b50\u7c7b\u6240\u5b9a\u4e49\u7684\u540d\u79f0\u76f8\u51b2\u7a81\uff09\uff0c\u56e0\u6b64\u5b58\u5728\u5bf9\u6b64\u79cd\u673a\u5236\u7684\u6709\u9650\u652f\u6301\uff0c\u79f0\u4e3a**\u540d\u79f0\u6539\u5199\uff08name mangling\uff09**\u3002 \u4efb\u4f55\u5f62\u5f0f\u4e3a __spam \u7684\u6807\u8bc6\u7b26\uff08\u81f3\u5c11\u5e26\u6709*\u4e24\u4e2a\u524d\u7f00\u4e0b\u5212\u7ebf*\uff0c\u81f3\u591a\u4e00\u4e2a\u540e\u7f00\u4e0b\u5212\u7ebf\uff09\u7684\u6587\u672c\u5c06\u88ab\u66ff\u6362\u4e3a _classname__spam \uff0c\u5176\u4e2d classname \u4e3a\u53bb\u9664\u4e86\u524d\u7f00\u4e0b\u5212\u7ebf\u7684\u5f53\u524d\u7c7b\u540d\u79f0\u3002 \u8fd9\u79cd\u6539\u5199\u4e0d\u8003\u8651\u6807\u8bc6\u7b26\u7684\u53e5\u6cd5\u4f4d\u7f6e\uff0c\u53ea\u8981\u5b83\u51fa\u73b0\u5728\u7c7b\u5b9a\u4e49\u5185\u90e8\u5c31\u4f1a\u8fdb\u884c\u3002 \u540d\u79f0\u6539\u5199\uff08Name mangling\uff09\u6709\u52a9\u4e8e\u8ba9\u5b50\u7c7b\u91cd\u8f7d\u65b9\u6cd5\uff08\uff09override methods\u800c\u4e0d\u7834\u574f\u7c7b\u5185\u65b9\u6cd5\uff08intraclass method\uff09\u8c03\u7528\u3002\u4f8b\u5982: class Mapping : def __init__ ( self , iterable ): self . items_list = [] self . __update ( iterable ) def update ( self , iterable ): for item in iterable : self . items_list . append ( item ) __update = update # private copy of original update() method class MappingSubclass ( Mapping ): def update ( self , keys , values ): # provides new signature for update() # but does not break __init__() for item in zip ( keys , values ): self . items_list . append ( item ) \u4e0a\u9762\u7684\u793a\u4f8b\u5373\u4f7f\u5728 MappingSubclass \u5f15\u5165\u4e86\u4e00\u4e2a __update \u6807\u8bc6\u7b26\u7684\u60c5\u51b5\u4e0b\u4e5f\u4e0d\u4f1a\u51fa\u9519\uff0c\u56e0\u4e3a\u5b83\u4f1a\u5728 Mapping \u7c7b\u4e2d\u88ab\u66ff\u6362\u4e3a _Mapping__update \u800c\u5728 MappingSubclass \u7c7b\u4e2d\u88ab\u66ff\u6362\u4e3a _MappingSubclass__update \u3002 \u8bf7\u6ce8\u610f\uff0c\u6539\u5199\u89c4\u5219\uff08mangling rules\uff09\u7684\u8bbe\u8ba1\u4e3b\u8981\u662f\u4e3a\u4e86\u907f\u514d\u610f\u5916\u51b2\u7a81\uff1b\u8bbf\u95ee\u6216\u4fee\u6539\u79c1\u6709\u53d8\u91cf\u4ecd\u7136\u662f\u53ef\u80fd\u7684\u3002\u8fd9\u5728\u7279\u6b8a\u60c5\u51b5\u4e0b\u751a\u81f3\u4f1a\u5f88\u6709\u7528\uff0c\u4f8b\u5982\u5728\u8c03\u8bd5\u5668\uff08debugger\uff09\u4e2d\u3002 \u8bf7\u6ce8\u610f\u4f20\u9012\u7ed9 exec() \u6216 eval() \u7684\u4ee3\u7801\u4e0d\u4f1a\u628a\u53d1\u8d77\u8c03\u7528\u7c7b\u7684\u7c7b\u540d\u89c6\u4f5c\u5f53\u524d\u7c7b\uff1b\u8fd9\u7c7b\u4f3c\u4e8e global \u8bed\u53e5\u7684\u6548\u679c\uff0c\u56e0\u6b64\u8fd9\u79cd\u6548\u679c\u4ec5\u9650\u4e8e\u540c\u65f6\u7ecf\u8fc7\u5b57\u8282\u7801\u7f16\u8bd1\u7684\u4ee3\u7801\u3002 \u540c\u6837\u7684\u9650\u5236\u4e5f\u9002\u7528\u4e8e getattr() , setattr() \u548c delattr() \uff0c\u4ee5\u53ca\u5bf9\u4e8e __dict__ \u7684\u76f4\u63a5\u5f15\u7528\u3002","title":"\u79c1\u6709\u53d8\u91cf Private Variables"},{"location":"python/Foundation/ch05/#reflection","text":"\u53cd\u5c04(reflection)\u662f\u52a8\u6001\u8bed\u8a00\u7684\u4e00\u4e2a\u7279\u6027\u3002**\u53cd\u5c04\u673a\u5236**\u6307\u7684\u662f\u5728\u7a0b\u5e8f\u7684\u8fd0\u884c\u72b6\u6001\u4e2d\uff0c\u5bf9\u4e8e\u4efb\u610f\u4e00\u4e2a\u7c7b\uff0c\u90fd\u53ef\u4ee5\u77e5\u9053\u8fd9\u4e2a\u7c7b\u7684\u6240\u6709\u5c5e\u6027\u548c\u65b9\u6cd5\uff1b\u5bf9\u4e8e\u4efb\u610f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u90fd\u80fd\u591f\u8c03\u7528\u4ed6\u7684\u4efb\u610f\u65b9\u6cd5\u548c\u5c5e\u6027\u3002\u8fd9\u79cd\u52a8\u6001\u83b7\u53d6\u7a0b\u5e8f\u4fe1\u606f\u4ee5\u53ca\u52a8\u6001\u8c03\u7528\u5bf9\u8c61\u7684\u529f\u80fd\u79f0\u4e3a\u53cd\u5c04\u673a\u5236\u3002 \u901a\u8fc7\u4e0b\u9762\u4f8b\u5b50\u53ef\u77e5\uff0c\u901a\u8fc7 dir(person) \u83b7\u53d6\u4efb\u610f\u4e00\u4e2a\u7c7b\u6216\u8005\u5bf9\u8c61\u7684\u5c5e\u6027\u5217\u8868\u3002\u901a\u8fc7\u5185\u7f6e\u51fd\u6570 hasattr \u3001 getattr \u3001 setattr \u3001 delattr \u64cd\u4f5c\u7c7b\u548c\u5bf9\u8c61\u3002 class Person : def __init__ ( self , name , age , gender ): self . name = name self . age = age self . gender = gender person = Person ( 'Tom' , 21 , 'Male' ) print ( dir ( person )) # ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'gender', 'name'] # hasattr(object,'name') # \u6309\u5b57\u7b26\u4e32'name'\u5224\u65ad\u6709\u65e0\u5c5e\u6027person.name hasattr ( person , 'name' ) # True # getattr(object, 'name', default=None) # \u7b49\u540c\u4e8eperson.name,\u4e0d\u5b58\u5728\u8be5\u5c5e\u6027\u5219\u8fd4\u56de\u9ed8\u8ba4\u503cNone getattr ( person , 'name' , None ) # 'Tom' # setattr(x, 'y', v) # \u7b49\u540c\u4e8eperson.age = 18 setattr ( person , 'age' , 18 ) print ( person . age ) # 18 # delattr(x, 'y') # \u7b49\u540c\u4e8edel person.age delattr ( person , 'age' ) print ( person . age ) # AttributeError: 'Person' object has no attribute 'age' \u4e0b\u9762\u662f\u4e00\u4e2a\u5b9e\u9645\u5e94\u7528\u7684\u4f8b\u5b50\u3002 class FtpServer (): def server_run ( self ): while True : inp = input ( 'Input your command >>:' ) . strip () cmd , file = inp . split () if hasattr ( self , cmd ): func = getattr ( self , cmd ) func ( file ) def get ( self , file ): print ( f 'Downloading { file } ...' ) def put ( self , file ): print ( f 'Uploading { file } ...' ) ftp_server = FtpServer () ftp_server . server_run () # Input your command >>:get a.ext # Downloading a.ext... # Input your command >>:put a.txt # Uploading a.txt...","title":"\u53cd\u5c04(reflection)"},{"location":"python/Foundation/ch05/#iterators","text":"\u5728Python\u4e2d\uff0c\u5927\u591a\u6570\u5bb9\u5668\u5bf9\u8c61\uff08container object\uff09\u90fd\u53ef\u4ee5\u4f7f\u7528 for \u8bed\u53e5: for element in [ 1 , 2 , 3 ]: print ( element ) for element in ( 1 , 2 , 3 ): print ( element ) for key in { 'one' : 1 , 'two' : 2 }: print ( key ) for char in \"123\" : print ( char ) for line in open ( \"myfile.txt\" ): print ( line , end = '' ) for \u8bed\u53e5\u4f1a\u5728\u5bb9\u5668\u5bf9\u8c61\u4e0a\u8c03\u7528 iter()\u3002 \u8be5\u51fd\u6570\u8fd4\u56de\u4e00\u4e2a\u5b9a\u4e49\u4e86 __next__() \u65b9\u6cd5\u7684\u8fed\u4ee3\u5668\u5bf9\u8c61\uff0c\u6b64\u65b9\u6cd5\u5c06\u9010\u4e00\u8bbf\u95ee\u5bb9\u5668\u4e2d\u7684\u5143\u7d20\u3002 \u5f53\u5143\u7d20\u7528\u5c3d\u65f6\uff0c __next__() \u5c06\u5f15\u53d1 StopIteration \u5f02\u5e38\u6765\u901a\u77e5\u7ec8\u6b62 for \u5faa\u73af\u3002 \u53ef\u4ee5\u4f7f\u7528 next() \u5185\u7f6e\u51fd\u6570\u6765\u8c03\u7528 __next__() \u65b9\u6cd5\uff1b\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u5c55\u793a\u4e86\u521a\u521a\u63cf\u8ff0\u7684\u5177\u4f53\u8fd0\u884c\u65b9\u5f0f: >>> s = 'abc' >>> it = iter ( s ) >>> it < str_iterator object at 0x10c90e650 > >>> next ( it ) 'a' >>> next ( it ) 'b' >>> next ( it ) 'c' >>> next ( it ) Traceback ( most recent call last ): File \"\" , line 1 , in < module > next ( it ) StopIteration \u5728\u4e86\u89e3\u4e86\u8fed\u4ee3\u5668\u534f\u8bae\uff08iterator protocol\uff09\u7684\u673a\u5236\u540e\uff0c\u7ed9\u7c7b\u6dfb\u52a0\u8fed\u4ee3\u5668\u5c31\u5f88\u5bb9\u6613\u4e86\u3002 \u5b9a\u4e49\u4e00\u4e2a __iter__() \u65b9\u6cd5\u6765\u8fd4\u56de\u4e00\u4e2a\u5e26\u6709 __next__() \u65b9\u6cd5\u7684\u5bf9\u8c61\u3002 \u5982\u679c\u7c7b\u5df2\u5b9a\u4e49\u4e86 __next__() \uff0c\u5219 __iter__() \u53ef\u4ee5\u7b80\u5355\u5730\u8fd4\u56de self : class Reverse : \"\"\"Iterator for looping over a sequence backwards.\"\"\" def __init__ ( self , data ): self . data = data self . index = len ( data ) def __iter__ ( self ): return self def __next__ ( self ): if self . index == 0 : raise StopIteration self . index = self . index - 1 return self . data [ self . index ] rev = Reverse ( 'spam' ) print ( iter ( rev )) for char in rev : print ( char ) # m # a # p # s","title":"\u8fed\u4ee3\u5668 Iterators"},{"location":"python/Foundation/ch05/#generators","text":"**\u751f\u6210\u5668\uff08Generators\uff09**\u662f\u4e00\u4e2a\u7528\u4e8e\u521b\u5efa\u8fed\u4ee3\u5668\u7684\u7b80\u5355\u800c\u5f3a\u5927\u7684\u5de5\u5177\u3002 \u5b83\u4eec\u7684\u5199\u6cd5\u7c7b\u4f3c\u4e8e\u6807\u51c6\u7684\u51fd\u6570\uff0c\u4f46\u5f53\u5b83\u4eec\u8981\u8fd4\u56de\u6570\u636e\u65f6\u4f1a\u4f7f\u7528 yield \u8bed\u53e5\u3002 \u6bcf\u6b21\u5728\u751f\u6210\u5668\u4e0a\u8c03\u7528 next() \u65f6\uff0c\u5b83\u4f1a\u4ece\u4e0a\u6b21\u79bb\u5f00\u7684\u4f4d\u7f6e\u6062\u590d\u6267\u884c\uff08\u5b83\u4f1a\u8bb0\u4f4f\u4e0a\u6b21\u6267\u884c\u8bed\u53e5\u65f6\u7684\u6240\u6709\u6570\u636e\u503c\uff09\u3002 \u4e00\u4e2a\u521b\u5efa\u751f\u6210\u5668\u7684\u793a\u4f8b\u5982\u4e0b\uff08\u6539\u5199\u4e0a\u9762\u8fed\u4ee3\u5668\u4e2d\u6240\u4e3e\u7684\u4f8b\u5b50\uff09: def reverse ( data ): for index in range ( len ( data ) - 1 , - 1 , - 1 ): yield data [ index ] for char in reverse ( 'golf' ): print ( char ) # f # l # o # g \u53ef\u4ee5\u7528\u751f\u6210\u5668\u6765\u5b8c\u6210\u7684\u64cd\u4f5c\u540c\u6837\u53ef\u4ee5\u7528\u524d\u9762\u6240\u63cf\u8ff0\u7684\u57fa\u4e8e\u7c7b\u7684\u8fed\u4ee3\u5668\u6765\u5b8c\u6210\u3002\u4f46\u751f\u6210\u5668\u7684\u5199\u6cd5\u66f4\u4e3a\u7d27\u51d1\uff0c\u56e0\u4e3a\u5b83\u4f1a\u81ea\u52a8\u521b\u5efa __iter__() \u548c __next__() \u65b9\u6cd5\u3002 \u53e6\u4e00\u4e2a\u5173\u952e\u7279\u6027\u5728\u4e8e\u5c40\u90e8\u53d8\u91cf\u548c\u6267\u884c\u72b6\u6001\u4f1a\u5728\u6bcf\u6b21\u8c03\u7528\u4e4b\u95f4\u81ea\u52a8\u4fdd\u5b58\u3002 \u8fd9\u4f7f\u5f97\u8be5\u51fd\u6570\u76f8\u6bd4\u4f7f\u7528 self.index \u548c self.data \u8fd9\u79cd\u5b9e\u4f8b\u53d8\u91cf\u7684\u65b9\u5f0f\u66f4\u6613\u7f16\u5199\u4e14\u66f4\u4e3a\u6e05\u6670\u3002 \u9664\u4e86\u4f1a\u81ea\u52a8\u521b\u5efa\u65b9\u6cd5\u548c\u4fdd\u5b58\u7a0b\u5e8f\u72b6\u6001\uff0c\u5f53\u751f\u6210\u5668\u7ec8\u7ed3\u65f6\uff0c\u5b83\u4eec\u8fd8\u4f1a\u81ea\u52a8\u5f15\u53d1 StopIteration \u3002","title":"\u751f\u6210\u5668 Generators"},{"location":"python/Foundation/ch05/#generator-expressions","text":"\u67d0\u4e9b\u7b80\u5355\u7684\u751f\u6210\u5668\u53ef\u4ee5\u5199\u6210\u7b80\u6d01\u7684\u8868\u8fbe\u5f0f\u4ee3\u7801\uff0c\u6240\u7528\u8bed\u6cd5\u7c7b\u4f3c\u5217\u8868\u63a8\u5bfc\u5f0f\uff0c\u4f46\u5916\u5c42\u4e3a\u5706\u62ec\u53f7\u800c\u975e\u65b9\u62ec\u53f7\u3002 \u8fd9\u79cd\u8868\u8fbe\u5f0f\u88ab\u8bbe\u8ba1\u7528\u4e8e\u751f\u6210\u5668\u5c06\u7acb\u5373\u88ab\u5916\u5c42\u51fd\u6570\u6240\u4f7f\u7528\u7684\u60c5\u51b5\u3002 \u751f\u6210\u5668\u8868\u8fbe\u5f0f\u76f8\u6bd4\u5b8c\u6574\u7684\u751f\u6210\u5668\u66f4\u7d27\u51d1\u4f46\u8f83\u4e0d\u7075\u6d3b\uff0c\u76f8\u6bd4\u7b49\u6548\u7684\u5217\u8868\u63a8\u5bfc\u5f0f\u5219\u66f4\u4e3a\u8282\u7701\u5185\u5b58\u3002 \u793a\u4f8b: >>> sum ( i * i for i in range ( 10 )) # sum of squares 285 >>> xvec = [ 10 , 20 , 30 ] >>> yvec = [ 7 , 5 , 3 ] >>> sum ( x * y for x , y in zip ( xvec , yvec )) # dot product 260 >>> unique_words = set ( word for line in page for word in line . split ()) >>> valedictorian = max (( student . gpa , student . name ) for student in graduates ) >>> data = 'golf' >>> list ( data [ i ] for i in range ( len ( data ) - 1 , - 1 , - 1 )) [ 'f' , 'l' , 'o' , 'g' ]","title":"\u751f\u6210\u5668\u8868\u8fbe\u5f0f Generator Expressions"},{"location":"python/Foundation/ch05/#metaclass","text":"\u6240\u6709\u7684\u5bf9\u8c61\u90fd\u662f\u5b9e\u4f8b\u5316\u6216\u8005\u8bf4\u8c03\u7528\u7c7b\u800c\u5f97\u5230\u7684\uff08\u8c03\u7528\u7c7b\u7684\u8fc7\u7a0b\u79f0\u4e3a\u7c7b\u7684\u5b9e\u4f8b\u5316\u3002 class StandfordProfessor ( object ): university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) \u4e0a\u4f8b\u4e2d\uff0c\u5bf9\u8c61 professor \u662f\u8c03\u7528\u7c7b StandfordProfessor \u5f97\u5230\u7684\u3002\u7c7b StandfordProfessor \u672c\u8d28\u4e5f\u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c \u4e0b\u9762\u53ef\u4ee5\u9a8c\u8bc1\uff0c StandfordProfessor \u662f\u8c03\u7528\u4e86\u5185\u7f6e\u7684\u7c7b type \u5f97\u5230\u7684\u3002\u8fd9\u4e2a type \u79f0\u4e3a\u5143\u7c7b\u3002 print ( type ( StandfordProfessor )) # \u5982\u679c\u4e00\u4e2a\u7c7b\u6ca1\u6709\u58f0\u660e\u81ea\u5df1\u7684\u5143\u7c7b\uff0c\u9ed8\u8ba4\u5b83\u7684\u5143\u7c7b\u5c31\u662f type \uff0c\u9664\u4e86\u4f7f\u7528\u5185\u7f6e\u5143\u7c7b type \uff0c\u6211\u4eec\u4e5f\u53ef\u4ee5\u901a\u8fc7\u7ee7\u627f type \u6765\u81ea\u5b9a\u4e49\u5143\u7c7b\uff0c\u7136\u540e\u4f7f\u7528 metaclass \u5173\u952e\u5b57\u53c2\u6570\u4e3a\u4e00\u4e2a\u7c7b\u7684\u6307\u5b9a\u5143\u7c7b\u3002 \u53ea\u6709\u7ee7\u627f\u4e86type\u7c7b\u624d\u80fd\u79f0\u4e4b\u4e3a\u4e00\u4e2a\u5143\u7c7b\uff0c\u5426\u5219\u5c31\u662f\u4e00\u4e2a\u666e\u901a\u7684\u81ea\u5b9a\u4e49\u7c7b\u3002 class Mymeta ( type ): pass class StandfordProfessor ( object , metaclass = Mymeta ): university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) \u4e0b\u9762\u8fdb\u884c\u81ea\u5b9a\u4e49\u5143\u7c7b\uff0c\u63a7\u5236\u7c7b StandfordProfessor \u7684\u8c03\u7528\u3002 \u8981\u60f3\u8ba9 professor \u8fd9\u4e2a\u5bf9\u8c61\u53d8\u6210\u4e00\u4e2a\u53ef\u8c03\u7528\u7684\u5bf9\u8c61\uff0c\u9700\u8981\u5728\u8be5\u5bf9\u8c61\u7684\u7c7b\u4e2d\u5b9a\u4e49\u4e00\u4e2a\u65b9\u6cd5 __call__ \uff0c\u8be5\u65b9\u6cd5\u4f1a\u5728\u8c03\u7528\u5bf9\u8c61\u65f6\u81ea\u52a8\u89e6\u53d1\u3002\u8c03\u7528 professor \u7684\u8fd4\u56de\u503c\u5c31\u662f __call__ \u65b9\u6cd5\u7684\u8fd4\u56de\u503c\u3002 class Mymeta ( type ): def __call__ ( self , * args , ** kwargs ): print ( self ) # \u7c7b\u540d print ( args ) # \u8f93\u5165\u53c2\u6570 print ( kwargs ) # \u8f93\u5165\u53c2\u6570 return 10086 class StandfordProfessor ( object , metaclass = Mymeta ): university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) # # ('Tom', 'Male') # {} \u7c7b\u7684\u4ea7\u751f\u8fc7\u7a0b\u5176\u5b9e\u5c31\u662f\u5143\u7c7b\u7684\u8c03\u7528\u8fc7\u7a0b,\u5373 StandfordProfessor = Mymeta('StandfordProfessor', (object), {...}) \uff0c\u8c03\u7528 Mymeta \u4f1a\u5148\u4ea7\u751f\u4e00\u4e2a\u7a7a\u5bf9\u8c61 StandfordProfessor \uff0c\u7136\u540e\u8fde\u540c\u8c03\u7528 Mymeta \u62ec\u53f7\u5185\u7684\u53c2\u6570\u4e00\u540c\u4f20\u7ed9 Mymeta \u4e0b\u7684 __init__ \u65b9\u6cd5\uff0c\u5b8c\u6210\u521d\u59cb\u5316\u3002\u6211\u4eec\u53ef\u4ee5\u57fa\u4e8e\u4e0a\u4f8b\u505a\u5982\u4e0b\u6539\u5199\u3002 class Mymeta ( type ): def __init__ ( self , class_name , class_bases , class_dic ): super ( Mymeta , self ) . __init__ ( class_name , class_bases , class_dic ) if class_name . islower (): raise TypeError ( f 'Please follow Camel-Case to change class name { class_name } ' ) if '__doc__' not in class_dic or len ( class_dic [ '__doc__' ] . strip ( ' \\n ' )) == 0 : raise TypeError ( 'Please add documentation in class {class_name} , which is mandatory.' ) class StandfordProfessor ( object , metaclass = Mymeta ): \"\"\" Documentation of class StanfordTeacher \"\"\" university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) professor . display () # Professor Tom says welcome to Standford! print ( professor . __dict__ ) # {'name': 'Tom', 'gender': 'Male'} StandfordProfessor . mro () # [, ]","title":"\u5143\u7c7b\uff08metaclass\uff09"}]} \ No newline at end of file +{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Upskilling \u00b6 1.Linux \u00b6 1.1.Linux SRE \u00b6 \u7b2c\u4e00\u7ae0 Linux\u57fa\u7840 \u7b2c\u4e8c\u7ae0 \u6587\u4ef6\u7cfb\u7edf \u7b2c\u4e09\u7ae0 \u8eab\u4efd\u4e0e\u5b89\u5168 \u7b2c\u56db\u7ae0 \u6587\u672c\u7f16\u8f91 \u7b2c\u4e94\u7ae0 \u6b63\u5219\u8868\u8fbe\u5f0f \u7b2c\u516d\u7ae0 \u6587\u4ef6\u67e5\u627e \u7b2c\u4e03\u7ae0 \u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305 1.2.SUSE Linux Administration \u00b6 Linux File System Overview Useful Commands Shell 1.3.SUSE Enterprise Storage Foundation \u00b6 SUSE Enterprise Storage Foundation SUSE Enterprise Storage Basic Operation 2.Kubernetes \u00b6 2.1.CKA Learning Memo \u00b6 Installation Single Node Installation Multiple Nodes Installation Installation on Aliyun ECS Docker Fundamentals Foundamentals Memo Overview kubectl basics Core Kubernetes Pod Deployment Service Application Modeling Namespace StatefulSet DaemonSet Job and Cronjob Configuration Secrets Persistence Role Based Access Control (RBAC) Ingress Advanced Kubernetes Scheduling Horizontal Pod Autoscaling Policy Network Policy Cluster Management Operating Kubernetes Troubleshooting Health Check Helming Topics Operations on Resources Health Check Calico Installation Kyma 2.2.CKA\u5b66\u4e60\u7b14\u8bb0 \u00b6 \u5b89\u88c5 \u5355\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes \u591a\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes \u963f\u91cc\u4e91ECS\u5b89\u88c5Kubernetes Docker Docker\u57fa\u7840 \u57fa\u7840\u77e5\u8bc6 Kubernetes\u968f\u7b14 Kubernetes\u96c6\u7fa4\u6982\u89c8 kubectl\u57fa\u7840 \u6838\u5fc3\u6982\u5ff5 Pod Deployment Service \u5e94\u7528\u4f53\u7cfb Namespace StatefulSet DaemonSet Job and Cronjob Configuration secrets Persistence RBAC\u9274\u6743 Ingress-nginx \u8fdb\u9636\u6982\u5ff5 Scheduling Horizontal Pod Autoscaling (HPA) Policy Network Policy Cluster Management \u65e5\u5e38\u7ef4\u62a4 Troubleshooting \u5065\u5eb7\u68c0\u67e5 Helm Chart \u4e3b\u9898\u8ba8\u8bba Kubernetes\u8d44\u6e90\u5e38\u89c1\u64cd\u4f5c \u5065\u5eb7\u68c0\u67e5 \u5b89\u88c5Calico Demos Build CAP Application on Kyma 3.Python \u00b6 3.1.Python\u57fa\u7840 \u00b6 Python\u5b89\u88c5 Python\u8bed\u8a00\u57fa\u7840 Python\u6253\u5305\u548c\u89e3\u5305 Python\u5185\u7f6e\u51fd\u6570\u53ca\u6587\u4ef6 Python\u9762\u5411\u5bf9\u8c61\u6982\u5ff5 Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027 Python\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5 3.2.Python\u6570\u636e\u5206\u6790\u57fa\u7840 \u00b6 NumPy\u57fa\u7840 NumPy\u8fdb\u9636 Pandas\u5165\u95e8 \u6570\u636e\u8f7d\u5165\u3001\u5b58\u50a8\u53ca\u6587\u4ef6\u683c\u5f0f \u6570\u636e\u6e05\u6d17\u4e0e\u51c6\u5907 \u6570\u636e\u89c4\u6574\uff1a\u8fde\u63a5\u3001\u8054\u5408\u4e0e\u91cd\u5851 \u7ed8\u56fe\u4e0e\u53ef\u89c6\u5316 \u6570\u636e\u805a\u5408\u4e0e\u5206\u7ec4\u64cd\u4f5c \u65f6\u95f4\u5e8f\u5217 \u9ad8\u9636pandas Python\u5efa\u6a21\u5e93\u4ecb\u7ecd 3.3.\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5 \u00b6 1.\u57fa\u7840\u77e5\u8bc6\u56de\u987e 2.\u591a\u9879\u96c6\u7684\u6982\u8ff0 3.\u641c\u7d22\u3001\u6392\u5e8f\u4ee5\u53ca\u590d\u6742\u5ea6\u5206\u6790 4.\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784 5.\u63a5\u53e3\u3001\u5b9e\u73b0\u548c\u591a\u6001 6.\u7ee7\u627f\u4e0e\u62bd\u8c61\u7c7b 3.4.Demos \u00b6 \u9009\u8bfe\u7cfb\u7edf","title":"Index"},{"location":"#upskilling","text":"","title":"Upskilling"},{"location":"#1linux","text":"","title":"1.Linux"},{"location":"#11linux-sre","text":"\u7b2c\u4e00\u7ae0 Linux\u57fa\u7840 \u7b2c\u4e8c\u7ae0 \u6587\u4ef6\u7cfb\u7edf \u7b2c\u4e09\u7ae0 \u8eab\u4efd\u4e0e\u5b89\u5168 \u7b2c\u56db\u7ae0 \u6587\u672c\u7f16\u8f91 \u7b2c\u4e94\u7ae0 \u6b63\u5219\u8868\u8fbe\u5f0f \u7b2c\u516d\u7ae0 \u6587\u4ef6\u67e5\u627e \u7b2c\u4e03\u7ae0 \u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305","title":"1.1.Linux SRE"},{"location":"#12suse-linux-administration","text":"Linux File System Overview Useful Commands Shell","title":"1.2.SUSE Linux Administration"},{"location":"#13suse-enterprise-storage-foundation","text":"SUSE Enterprise Storage Foundation SUSE Enterprise Storage Basic Operation","title":"1.3.SUSE Enterprise Storage Foundation"},{"location":"#2kubernetes","text":"","title":"2.Kubernetes"},{"location":"#21cka-learning-memo","text":"Installation Single Node Installation Multiple Nodes Installation Installation on Aliyun ECS Docker Fundamentals Foundamentals Memo Overview kubectl basics Core Kubernetes Pod Deployment Service Application Modeling Namespace StatefulSet DaemonSet Job and Cronjob Configuration Secrets Persistence Role Based Access Control (RBAC) Ingress Advanced Kubernetes Scheduling Horizontal Pod Autoscaling Policy Network Policy Cluster Management Operating Kubernetes Troubleshooting Health Check Helming Topics Operations on Resources Health Check Calico Installation Kyma","title":"2.1.CKA Learning Memo"},{"location":"#22cka","text":"\u5b89\u88c5 \u5355\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes \u591a\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes \u963f\u91cc\u4e91ECS\u5b89\u88c5Kubernetes Docker Docker\u57fa\u7840 \u57fa\u7840\u77e5\u8bc6 Kubernetes\u968f\u7b14 Kubernetes\u96c6\u7fa4\u6982\u89c8 kubectl\u57fa\u7840 \u6838\u5fc3\u6982\u5ff5 Pod Deployment Service \u5e94\u7528\u4f53\u7cfb Namespace StatefulSet DaemonSet Job and Cronjob Configuration secrets Persistence RBAC\u9274\u6743 Ingress-nginx \u8fdb\u9636\u6982\u5ff5 Scheduling Horizontal Pod Autoscaling (HPA) Policy Network Policy Cluster Management \u65e5\u5e38\u7ef4\u62a4 Troubleshooting \u5065\u5eb7\u68c0\u67e5 Helm Chart \u4e3b\u9898\u8ba8\u8bba Kubernetes\u8d44\u6e90\u5e38\u89c1\u64cd\u4f5c \u5065\u5eb7\u68c0\u67e5 \u5b89\u88c5Calico Demos Build CAP Application on Kyma","title":"2.2.CKA\u5b66\u4e60\u7b14\u8bb0"},{"location":"#3python","text":"","title":"3.Python"},{"location":"#31python","text":"Python\u5b89\u88c5 Python\u8bed\u8a00\u57fa\u7840 Python\u6253\u5305\u548c\u89e3\u5305 Python\u5185\u7f6e\u51fd\u6570\u53ca\u6587\u4ef6 Python\u9762\u5411\u5bf9\u8c61\u6982\u5ff5 Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027 Python\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5","title":"3.1.Python\u57fa\u7840"},{"location":"#32python","text":"NumPy\u57fa\u7840 NumPy\u8fdb\u9636 Pandas\u5165\u95e8 \u6570\u636e\u8f7d\u5165\u3001\u5b58\u50a8\u53ca\u6587\u4ef6\u683c\u5f0f \u6570\u636e\u6e05\u6d17\u4e0e\u51c6\u5907 \u6570\u636e\u89c4\u6574\uff1a\u8fde\u63a5\u3001\u8054\u5408\u4e0e\u91cd\u5851 \u7ed8\u56fe\u4e0e\u53ef\u89c6\u5316 \u6570\u636e\u805a\u5408\u4e0e\u5206\u7ec4\u64cd\u4f5c \u65f6\u95f4\u5e8f\u5217 \u9ad8\u9636pandas Python\u5efa\u6a21\u5e93\u4ecb\u7ecd","title":"3.2.Python\u6570\u636e\u5206\u6790\u57fa\u7840"},{"location":"#33","text":"1.\u57fa\u7840\u77e5\u8bc6\u56de\u987e 2.\u591a\u9879\u96c6\u7684\u6982\u8ff0 3.\u641c\u7d22\u3001\u6392\u5e8f\u4ee5\u53ca\u590d\u6742\u5ea6\u5206\u6790 4.\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784 5.\u63a5\u53e3\u3001\u5b9e\u73b0\u548c\u591a\u6001 6.\u7ee7\u627f\u4e0e\u62bd\u8c61\u7c7b","title":"3.3.\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5"},{"location":"#34demos","text":"\u9009\u8bfe\u7cfb\u7edf","title":"3.4.Demos"},{"location":"about/","text":"About \u00b6 What's past is prologue. It\u2019s never too late to do. You may also visit my posts on zhihu . --From Shanghai China","title":"About"},{"location":"about/#about","text":"What's past is prologue. It\u2019s never too late to do. You may also visit my posts on zhihu . --From Shanghai China","title":"About"},{"location":"k8s/","text":"\u6211\u7684Kubernetes\u5b66\u4e60\u5fc3\u5f97 \u00b6 \u4f5c\u4e3a\u4e00\u79cd\u5f00\u6e90\u7684\u5bb9\u5668\u7f16\u6392\u7cfb\u7edf\uff0cKubernetes \u4e3a\u8fd0\u884c\u5728\u5bb9\u5668\u4e2d\u7684\u5e94\u7528\u7a0b\u5e8f\u63d0\u4f9b\u4e86\u4e00\u79cd\u7ba1\u7406\u65b9\u5f0f\u3002Kubernetes \u5177\u6709\u5f88\u591a\u5f3a\u5927\u7684\u529f\u80fd\uff0c\u4f8b\u5982\u81ea\u52a8\u5316\u90e8\u7f72\u3001\u8d1f\u8f7d\u5747\u8861\u3001\u81ea\u52a8\u6269\u5c55\u3001\u81ea\u52a8\u6062\u590d\u7b49\u3002 \u516c\u53f8\u5185\u90e8\u7684\u4e91\u5e73\u53f0\u4e5f\u5728\u4eceCloud Foundry\u73af\u5883\u5f00\u59cb\u5411\u57fa\u4e8eKubernetes\u7684Kyma\u73af\u5883\u5ef6\u5c55\uff0c\u518d\u52a0\u4e0a\u5404\u79cd\u5a92\u4f53\u5bf9Kubernetes\u7684\u4ecb\u7ecd\uff0c\u662f\u6211\u5f00\u59cb\u4e86\u89e3Kubernetes\u7684\u5916\u90e8\u52a8\u56e0\u3002 \u5185\u90e8\u52a8\u56e0\uff0c\u5219\u662f\u6e90\u4e8e2022\u5e74\u6625\u8282\u671f\u95f4\u53c2\u52a0\u4e86\u516c\u53f8\u5185\u90e8\u7684\u4e00\u5468Kubernetes\u57fa\u7840\u57f9\u8bad\uff0c\u56e0\u4e3a\u6388\u8bfe\u5185\u5bb9\u662f\u82f1\u8bed\uff0c\u6240\u4ee5\u6709\u5f88\u591a\u7ec6\u8282\u5728\u57f9\u8bad\u4e2d\u662fget\u4e0d\u5230\u7684\uff0c\u4e3b\u8981\u8fd8\u662f\u8bed\u8a00\u80fd\u529b\u4e0d\u591f\u5f3a\u3002\u5f53\u65f6\u7684\u76ee\u6807\u53ea\u662f\u8ddf\u7740\u5b8c\u6210\u8bb2\u5e08\u8bfe\u5802\u6f14\u793a\u3002 \u4ece3\u6708\u5f00\u59cb\uff0c\u6211\u5728\u7f51\u4e0a\u4e86\u53c2\u8003\u4e86\u522b\u4eba\u7684Kubernetes\u7684\u5b66\u4e60\u5fc3\u5f97\u548c\u8def\u7ebf\u56fe\uff0c\u51b3\u5b9a\u4ee5CKA\uff08certificate of Kubernetes administration\uff09\u8ba4\u8bc1\u4f5c\u4e3a\u5f53\u524d\u5b66\u4e60\u7684\u76ee\u6807\uff0c\u5229\u7528B\u7ad9\u7684\u89c6\u9891\uff0c\u53c2\u8003\u5b98\u65b9\u6587\u6863\uff0c\u5f00\u59cb\u4ece\u5934\u5f00\u59cb\u5b66\u4e60Kubernetes\u7684\u57fa\u7840\u77e5\u8bc6\u3002 \u4e0b\u9762\u51c6\u5907CKA\u8003\u8bd5\u7684\u4e00\u4e9b\u5fc3\u5f97\u4f53\u4f1a\uff1a \u5b66\u4e60 Kubernetes \u524d\uff0c\u9700\u8981\u4e86\u89e3\u5bb9\u5668\u6280\u672f\u548c Docker\uff0c\u6216\u8005\u8bf4\u8981\u6709\u5bb9\u5668\u5316\u7684\u57fa\u672c\u6982\u5ff5\u548c\u601d\u60f3\u65b9\u6cd5\uff0c\u56e0\u4e3a Kubernetes \u662f\u57fa\u4e8e\u5bb9\u5668\u6280\u672f\u6784\u5efa\u7684\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1\u5176\u6838\u5fc3\u6982\u5ff5\uff0c\u4f8b\u5982 Pod\u3001ReplicaSet\u3001Deployment\u3001Service \u7b49\u3002\u8fd9\u4e9b\u6982\u5ff5\u662f\u7406\u89e3 Kubernetes \u7684\u57fa\u7840\uff0c\u4e5f\u662f\u540e\u7eed\u5b9e\u9645\u5e94\u7528\u4e2d\u7684\u91cd\u8981\u90e8\u5206\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1 yaml \u6587\u4ef6\u7684\u7f16\u5199\u65b9\u6cd5\uff0c\u7279\u522b\u662f\u90a3\u4e9b\u57fa\u672c\u8d44\u6e90\u7684yaml\u6587\u4ef6\uff0c\u8981\u80fd\u505a\u5230\u4e0d\u501f\u52a9\u5e2e\u52a9\u6587\u6863\u5c31\u80fd\u5199\u51fa\u6846\u67b6\uff0c\u5426\u5219\u8003\u8bd5\u65f6\u505a\u4e0d\u5b8c\u9898\u76ee\u7684\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1 kubectl \u547d\u4ee4\u7684\u4f7f\u7528\uff0c\u5e38\u7528\u8d44\u6e90\u76f8\u5173\u7684\u547d\u4ee4\uff0c\u4e5f\u8981\u505a\u5230\u4e0d\u501f\u52a9\u5e2e\u52a9\u6587\u6863\u5c31\u80fd\u5199\u51fa\uff0c\u5426\u5219\u8003\u8bd5\u65f6\u4e5f\u662f\u505a\u4e0d\u5b8c\u9898\u76ee\u7684\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1\u5176\u7f51\u7edc\u548c\u5b58\u50a8\u914d\u7f6e\uff0c\u4f8b\u5982 Service\u3001Ingress\u3001PersistentVolume\u3001PersistentVolumeClaim \u7b49\uff0c\u8fd9\u4e9b\u90fd\u662f\u8003\u8bd5\u91cd\u70b9\u5185\u5bb9\uff0c\u8981\u719f\u6089yaml\u7279\u6027\uff0c\u80fd\u6309\u4e0d\u540c\u7684\u8981\u6c42\u8fdb\u884c\u62d3\u5c55\u548c\u53d8\u66f4\u3002 \u90e8\u7f72\u548c\u7ba1\u7406 Kubernetes \u96c6\u7fa4\u4e5f\u662f\u4e00\u4e2a\u91cd\u70b9\uff0c\u6211\u662f\u5728\u963f\u91cc\u4e91\u4e0a\u4e70\u4e863\u4e2aECS\u4f5c\u4e3a\u5b9e\u9a8c\u73af\u5883\u3002 \u6211\u7684CKA\u7684\u7b14\u8bb0\u5206\u4e2d\u6587\u548c\u82f1\u6587\u4e24\u79cd\u3002\u82f1\u6587\u7b14\u8bb0\u662f\u57fa\u4e8e\u7b2c\u4e00\u6b21\u53c2\u52a0\u516c\u53f8\u57f9\u8bad\u7684\u77e5\u8bc6\u7ed3\u6784\u505a\u7684\uff0c\u5728\u5907\u8003\u8fc7\u7a0b\u4e2d\u9010\u6b65\u5b8c\u5584\u7684\u3002\u4e2d\u6587\u7b14\u8bb0\u662f\u57282023\u5e744\u6708\u4efd\u57fa\u4e8e\u82f1\u6587\u7b14\u8bb0\u81ea\u5df1\u7ffb\u8bd1\u8fc7\u6765\u7684\uff0c\u5e76\u53d1\u5e03\u5728\u6211\u7684\u77e5\u4e4e\u4e13\u680f\u4e0a\uff0c\u7ffb\u8bd1\u8fc7\u7a0b\u8fd8\u662f\u6bd4\u8f83\u96be\u7684\uff0c\u5f88\u591a\u82f1\u8bed\u5185\u5bb9\u627e\u4e0d\u5230\u5408\u9002\u7684\u4e2d\u6587\u8868\u8fbe\u65b9\u5f0f\uff0c\u4e0d\u8fc7\u5bf9\u4e8e\u8ba1\u7b97\u673a\u884c\u4e1a\u6765\u8bb2\uff0c\u4f7f\u7528\u82f1\u8bed\u9605\u8bfb\u4e13\u4e1a\u8d44\u6599\u5e94\u8be5\u662f\u4e00\u4e2a\u5171\u8bc6\u3002 \u53c2\u8003\u7b14\u8bb0\uff0c\u5e76\u5b8c\u6210\u7b14\u8bb0\u4e2d\u7684\u7ec3\u4e60\uff0c\u518d\u719f\u7ec3\u4f7f\u7528yaml\u6587\u4ef6\u548ckubectl\u547d\u4ee4\uff0c\u901a\u8fc7\u8003\u8bd5\u6ca1\u4ec0\u4e48\u56f0\u96be\u3002","title":"Index"},{"location":"k8s/#kubernetes","text":"\u4f5c\u4e3a\u4e00\u79cd\u5f00\u6e90\u7684\u5bb9\u5668\u7f16\u6392\u7cfb\u7edf\uff0cKubernetes \u4e3a\u8fd0\u884c\u5728\u5bb9\u5668\u4e2d\u7684\u5e94\u7528\u7a0b\u5e8f\u63d0\u4f9b\u4e86\u4e00\u79cd\u7ba1\u7406\u65b9\u5f0f\u3002Kubernetes \u5177\u6709\u5f88\u591a\u5f3a\u5927\u7684\u529f\u80fd\uff0c\u4f8b\u5982\u81ea\u52a8\u5316\u90e8\u7f72\u3001\u8d1f\u8f7d\u5747\u8861\u3001\u81ea\u52a8\u6269\u5c55\u3001\u81ea\u52a8\u6062\u590d\u7b49\u3002 \u516c\u53f8\u5185\u90e8\u7684\u4e91\u5e73\u53f0\u4e5f\u5728\u4eceCloud Foundry\u73af\u5883\u5f00\u59cb\u5411\u57fa\u4e8eKubernetes\u7684Kyma\u73af\u5883\u5ef6\u5c55\uff0c\u518d\u52a0\u4e0a\u5404\u79cd\u5a92\u4f53\u5bf9Kubernetes\u7684\u4ecb\u7ecd\uff0c\u662f\u6211\u5f00\u59cb\u4e86\u89e3Kubernetes\u7684\u5916\u90e8\u52a8\u56e0\u3002 \u5185\u90e8\u52a8\u56e0\uff0c\u5219\u662f\u6e90\u4e8e2022\u5e74\u6625\u8282\u671f\u95f4\u53c2\u52a0\u4e86\u516c\u53f8\u5185\u90e8\u7684\u4e00\u5468Kubernetes\u57fa\u7840\u57f9\u8bad\uff0c\u56e0\u4e3a\u6388\u8bfe\u5185\u5bb9\u662f\u82f1\u8bed\uff0c\u6240\u4ee5\u6709\u5f88\u591a\u7ec6\u8282\u5728\u57f9\u8bad\u4e2d\u662fget\u4e0d\u5230\u7684\uff0c\u4e3b\u8981\u8fd8\u662f\u8bed\u8a00\u80fd\u529b\u4e0d\u591f\u5f3a\u3002\u5f53\u65f6\u7684\u76ee\u6807\u53ea\u662f\u8ddf\u7740\u5b8c\u6210\u8bb2\u5e08\u8bfe\u5802\u6f14\u793a\u3002 \u4ece3\u6708\u5f00\u59cb\uff0c\u6211\u5728\u7f51\u4e0a\u4e86\u53c2\u8003\u4e86\u522b\u4eba\u7684Kubernetes\u7684\u5b66\u4e60\u5fc3\u5f97\u548c\u8def\u7ebf\u56fe\uff0c\u51b3\u5b9a\u4ee5CKA\uff08certificate of Kubernetes administration\uff09\u8ba4\u8bc1\u4f5c\u4e3a\u5f53\u524d\u5b66\u4e60\u7684\u76ee\u6807\uff0c\u5229\u7528B\u7ad9\u7684\u89c6\u9891\uff0c\u53c2\u8003\u5b98\u65b9\u6587\u6863\uff0c\u5f00\u59cb\u4ece\u5934\u5f00\u59cb\u5b66\u4e60Kubernetes\u7684\u57fa\u7840\u77e5\u8bc6\u3002 \u4e0b\u9762\u51c6\u5907CKA\u8003\u8bd5\u7684\u4e00\u4e9b\u5fc3\u5f97\u4f53\u4f1a\uff1a \u5b66\u4e60 Kubernetes \u524d\uff0c\u9700\u8981\u4e86\u89e3\u5bb9\u5668\u6280\u672f\u548c Docker\uff0c\u6216\u8005\u8bf4\u8981\u6709\u5bb9\u5668\u5316\u7684\u57fa\u672c\u6982\u5ff5\u548c\u601d\u60f3\u65b9\u6cd5\uff0c\u56e0\u4e3a Kubernetes \u662f\u57fa\u4e8e\u5bb9\u5668\u6280\u672f\u6784\u5efa\u7684\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1\u5176\u6838\u5fc3\u6982\u5ff5\uff0c\u4f8b\u5982 Pod\u3001ReplicaSet\u3001Deployment\u3001Service \u7b49\u3002\u8fd9\u4e9b\u6982\u5ff5\u662f\u7406\u89e3 Kubernetes \u7684\u57fa\u7840\uff0c\u4e5f\u662f\u540e\u7eed\u5b9e\u9645\u5e94\u7528\u4e2d\u7684\u91cd\u8981\u90e8\u5206\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1 yaml \u6587\u4ef6\u7684\u7f16\u5199\u65b9\u6cd5\uff0c\u7279\u522b\u662f\u90a3\u4e9b\u57fa\u672c\u8d44\u6e90\u7684yaml\u6587\u4ef6\uff0c\u8981\u80fd\u505a\u5230\u4e0d\u501f\u52a9\u5e2e\u52a9\u6587\u6863\u5c31\u80fd\u5199\u51fa\u6846\u67b6\uff0c\u5426\u5219\u8003\u8bd5\u65f6\u505a\u4e0d\u5b8c\u9898\u76ee\u7684\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1 kubectl \u547d\u4ee4\u7684\u4f7f\u7528\uff0c\u5e38\u7528\u8d44\u6e90\u76f8\u5173\u7684\u547d\u4ee4\uff0c\u4e5f\u8981\u505a\u5230\u4e0d\u501f\u52a9\u5e2e\u52a9\u6587\u6863\u5c31\u80fd\u5199\u51fa\uff0c\u5426\u5219\u8003\u8bd5\u65f6\u4e5f\u662f\u505a\u4e0d\u5b8c\u9898\u76ee\u7684\u3002 \u5b66\u4e60 Kubernetes \u65f6\uff0c\u9700\u8981\u638c\u63e1\u5176\u7f51\u7edc\u548c\u5b58\u50a8\u914d\u7f6e\uff0c\u4f8b\u5982 Service\u3001Ingress\u3001PersistentVolume\u3001PersistentVolumeClaim \u7b49\uff0c\u8fd9\u4e9b\u90fd\u662f\u8003\u8bd5\u91cd\u70b9\u5185\u5bb9\uff0c\u8981\u719f\u6089yaml\u7279\u6027\uff0c\u80fd\u6309\u4e0d\u540c\u7684\u8981\u6c42\u8fdb\u884c\u62d3\u5c55\u548c\u53d8\u66f4\u3002 \u90e8\u7f72\u548c\u7ba1\u7406 Kubernetes \u96c6\u7fa4\u4e5f\u662f\u4e00\u4e2a\u91cd\u70b9\uff0c\u6211\u662f\u5728\u963f\u91cc\u4e91\u4e0a\u4e70\u4e863\u4e2aECS\u4f5c\u4e3a\u5b9e\u9a8c\u73af\u5883\u3002 \u6211\u7684CKA\u7684\u7b14\u8bb0\u5206\u4e2d\u6587\u548c\u82f1\u6587\u4e24\u79cd\u3002\u82f1\u6587\u7b14\u8bb0\u662f\u57fa\u4e8e\u7b2c\u4e00\u6b21\u53c2\u52a0\u516c\u53f8\u57f9\u8bad\u7684\u77e5\u8bc6\u7ed3\u6784\u505a\u7684\uff0c\u5728\u5907\u8003\u8fc7\u7a0b\u4e2d\u9010\u6b65\u5b8c\u5584\u7684\u3002\u4e2d\u6587\u7b14\u8bb0\u662f\u57282023\u5e744\u6708\u4efd\u57fa\u4e8e\u82f1\u6587\u7b14\u8bb0\u81ea\u5df1\u7ffb\u8bd1\u8fc7\u6765\u7684\uff0c\u5e76\u53d1\u5e03\u5728\u6211\u7684\u77e5\u4e4e\u4e13\u680f\u4e0a\uff0c\u7ffb\u8bd1\u8fc7\u7a0b\u8fd8\u662f\u6bd4\u8f83\u96be\u7684\uff0c\u5f88\u591a\u82f1\u8bed\u5185\u5bb9\u627e\u4e0d\u5230\u5408\u9002\u7684\u4e2d\u6587\u8868\u8fbe\u65b9\u5f0f\uff0c\u4e0d\u8fc7\u5bf9\u4e8e\u8ba1\u7b97\u673a\u884c\u4e1a\u6765\u8bb2\uff0c\u4f7f\u7528\u82f1\u8bed\u9605\u8bfb\u4e13\u4e1a\u8d44\u6599\u5e94\u8be5\u662f\u4e00\u4e2a\u5171\u8bc6\u3002 \u53c2\u8003\u7b14\u8bb0\uff0c\u5e76\u5b8c\u6210\u7b14\u8bb0\u4e2d\u7684\u7ec3\u4e60\uff0c\u518d\u719f\u7ec3\u4f7f\u7528yaml\u6587\u4ef6\u548ckubectl\u547d\u4ee4\uff0c\u901a\u8fc7\u8003\u8bd5\u6ca1\u4ec0\u4e48\u56f0\u96be\u3002","title":"\u6211\u7684Kubernetes\u5b66\u4e60\u5fc3\u5f97"},{"location":"k8s/cka_cn/foundamentals/basics/","text":"CKA\u81ea\u5b66\u7b14\u8bb07:kubectl\u57fa\u7840 \u00b6 \u6458\u8981 \u00b6 \u4e86\u89e3\u5982\u4f55\u4f7f\u7528 kubectl \u64cd\u4f5cKubernetes\u96c6\u7fa4\u3002 via API via kubectl via Dashboard \u68c0\u67e5\u5f53\u524dkubeconfig\u6587\u4ef6\u914d\u7f6e \u00b6 \u901a\u8fc7\u547d\u4ee4 kubectl config \u68c0\u67e5\u5f53\u524d\u914d\u7f6e\u6587\u4ef6\u4e2d\u7684\u4e0a\u4e0b\u6587\u3002 echo $KUBECONFIG kubectl config view kubectl config get-contexts \u83b7\u53d6\u8d44\u6e90\u6e05\u5355 \u00b6 \u8bfb\u53d6\u6240\u6709\u652f\u6301\u7684\u8d44\u6e90\u6e05\u5355\u3002 kubectl api-resources \u83b7\u53d6\u96c6\u7fa4\u72b6\u6001 \u00b6 Kubernetes \u63a7\u5236\u9762\u677f\u8fd0\u884c\u5728 https://:6443 \u3002 CoreDNS \u8fd0\u884c\u5728 https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy \u3002 kubectl cluster-info kubectl cluster-info dump \u8bfb\u53d6\u5f53\u524d\u8d44\u6e90 \u00b6 \u6267\u884c\u547d\u4ee4 kubectl get --help \u53ef\u4ee5\u5f97\u5230get\u547d\u4ee4\u7684\u793a\u4f8b\u548c\u4f7f\u7528\u65b9\u6cd5\u3002 \u8bfb\u53d6\u5f53\u524d\u63a7\u5236\u9762\u677f\u7684\u5065\u5eb7\u72b6\u6001\u3002 kubectl get componentstatuses kubectl get cs \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS MESSAGE ERROR etcd-0 Healthy {\"health\":\"true\",\"reason\":\"\"} scheduler Healthy ok controller-manager Healthy ok \u8bfb\u53d6\u8282\u70b9\u72b6\u6001\u548c\u4fe1\u606f \u00b6 kubectl get nodes kubectl get nodes -o wide kubectl describe node cka001 \u53ef\u4ee5\u901a\u8fc7\u547d\u4ee4 kubectl create --help \u6765\u83b7\u53d6get\u547d\u4ee4\u7684\u5e2e\u52a9\u548c\u793a\u4f8b\u3002 \u521b\u5efaNamespace \u00b6 kubectl create namespace --help kubectl create namespace my-namespace \u63d0\u793a\uff1a \u547d\u540d\u7a7a\u95f4Namespace\u662f\u4e00\u4e2a\u96c6\u7fa4\uff0c\u5305\u542b\u4e86\u670d\u52a1\u3002\u670d\u52a1\u53ef\u80fd\u5728\u4e00\u4e2a\u8282\u70b9\u4e0a\uff0c\u4e5f\u53ef\u80fd\u4e0d\u5728\u3002 Namespace\u662f\u4e00\u79cd\u7528\u6765\u7ec4\u7ec7\u670d\u52a1\u7684\u65b9\u5f0f\uff0c\u5b83\u53ef\u4ee5\u5bf9\u670d\u52a1\u8fdb\u884c\u9694\u79bb\u548c\u5212\u5206\u3002 \u4e0d\u540c\u7684Namespace\u4e0b\uff0c\u53ef\u4ee5\u5b58\u5728\u76f8\u540c\u7684\u670d\u52a1\u540d\uff0c\u4f46\u662f\u4e0d\u540c\u7684Namespace\u4e4b\u95f4\u7684\u670d\u52a1\u4e0d\u80fd\u76f4\u63a5\u901a\u4fe1\uff0c\u9700\u8981\u901a\u8fc7Service\u6216Ingress\u6765\u66b4\u9732\u3002 \u670d\u52a1\u662f\u4e00\u79cd\u63d0\u4f9b\u529f\u80fd\u7684\u5b9e\u4f53 \u8282\u70b9\u662f\u4e00\u79cd\u8fd0\u884c\u670d\u52a1\u7684\u7269\u7406\u6216\u865a\u62df\u673a\u5668 \u521b\u5efadeployment \u00b6 \u5728\u67d0\u4e2aNamespace\u4e2d\u521b\u5efaDeployment\u3002 kubectl -n my-namespace create deployment my-busybox \\ --image = busybox \\ --replicas = 3 \\ --port = 5701 \u521b\u5efaClusterRole \u00b6 kubectl create clusterrole --help kubectl create clusterrole pod-creater \\ -n my-namespace \\ --verb = create \\ --resource = deployment \\ --resource-name = my-busybox \u521b\u5efaServiceAccount \u00b6 kubectl create serviceaccount --help kubectl -n my-namespace create serviceaccount my-service-account \u521b\u5efaRoleBinding \u00b6 RoleBinding \u53ef\u4ee5\u5f15\u7528\u540c\u4e00\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u4e00\u4e2aRole\uff0c\u6216\u8005\u5168\u5c40\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u4e00\u4e2aClusterRole\u3002 RoleBinding \u662f\u4e00\u79cd\u7528\u6765\u6388\u6743\u89d2\u8272\u7684\u8d44\u6e90\u3002 Role\u662f\u4e00\u79cd\u5b9a\u4e49\u6743\u9650\u7684\u8d44\u6e90\uff0c\u53ea\u80fd\u5728\u540c\u4e00\u547d\u540d\u7a7a\u95f4\u5185\u751f\u6548\u3002 ClusterRole\u662f\u4e00\u79cd\u5b9a\u4e49\u6743\u9650\u7684\u8d44\u6e90\uff0c\u53ef\u4ee5\u5728\u6574\u4e2a\u96c6\u7fa4\u5185\u751f\u6548\u3002 kubectl create rolebinding --help kubectl create rolebinding NAME \\ --clusterrole = NAME | --role = NAME \\ [ --user = username ] \\ [ --group = groupname ] \\ [ --serviceaccount = namespace:serviceaccountname ] \\ [ --dry-run = server | client | none ] kubectl create rolebinding my-admin \\ --clusterrole = pod-creater \\ --serviceaccount = my-namespace:my-service-account \u4f7f\u7528proxy \u00b6 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 kubectl proxy \u547d\u4ee4\u6765\u6253\u5f00\u4e00\u4e2a\u5230API\u670d\u52a1\u5668\u7684\u96a7\u9053\uff08tunnel\uff09\uff0c\u5e76\u4f7f\u5b83\u5728\u672c\u5730\u53ef\u7528 - \u901a\u5e38\u662f\u5728 localhost:8001 / 127.0.0.1:8001 \u3002\u5f53\u6211\u60f3\u8981\u4f7f\u7528API\u65f6\uff0c\u6700\u7b80\u5355\u7684\u65b9\u6cd5\u5c31\u662f\u83b7\u53d6\u8bbf\u95ee\u6743\u9650\u3002 \u8fd0\u884c\u547d\u4ee4 kubectl proxy & \u5e76\u5728\u6d4f\u89c8\u5668\u4e2d\u6253\u5f00 http://localhost:8001/api/v1 \u3002 \u53ea\u6253\u5f00 http://localhost:8001 \u4f1a\u8fd4\u56de\u9519\u8bef\uff0c\u56e0\u4e3a\u6211\u4eec\u53ea\u80fd\u8bbf\u95eeAPI\u7684\u67d0\u4e9b\u5185\u5bb9\uff0c\u56e0\u6b64API\u8def\u5f84\u5f88\u91cd\u8981\u3002 \u8981\u70b9\u662f\uff1a kubectl proxy \u547d\u4ee4\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u672c\u5730\u4ee3\u7406\uff0c\u8ba9\u6211\u4eec\u53ef\u4ee5\u8bbf\u95eeAPI\u670d\u52a1\u5668\u3002 API\u670d\u52a1\u5668\u63d0\u4f9b\u4e86\u96c6\u7fa4\u7684\u5404\u79cd\u4fe1\u606f\u548c\u64cd\u4f5c\u3002 \u6211\u4eec\u9700\u8981\u6307\u5b9a\u6b63\u786e\u7684API\u8def\u5f84\uff0c\u624d\u80fd\u8bbf\u95ee\u6211\u4eec\u60f3\u8981\u7684\u8d44\u6e90\u3002 kubectl proxy & \u8f93\u51fa\u7ed3\u679c\uff1a [1] 102358 Starting to serve on 127.0.0.1:8001 \u6bd4\u5982\uff1a http://127.0.0.1:8001/ http://127.0.0.1:8001/api/v1 http://127.0.0.1:8001/api/v1/namespaces http://127.0.0.1:8001/api/v1/namespaces/default http://127.0.0.1:8001/api/v1/namespaces/sock-shop/pods \u4f5c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u8bbf\u95ee \u00b6 \u5982\u679c\u6211\u4eec\u4f5c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u800c\u4e0d\u662f\u7ba1\u7406\u5458\u6765\u8bbf\u95eekubernetes\uff0c\u5c31\u4e0d\u80fd\u4f7f\u7528 kubectl \uff0c\u53ef\u4ee5\u7528 curl \u7a0b\u5e8f\u6765\u4ee3\u66ff kubectl \u3002 \u6211\u4eec\u5fc5\u987b\u5411\u96c6\u7fa4\u53d1\u9001HTTP\u8bf7\u6c42\uff0c\u8be2\u95ee\u53ef\u7528\u7684\u8282\u70b9\u3002 \u786e\u4fdd kubectl proxy \u6b63\u5728\u8fd0\u884c\uff0c\u5e76\u5728 http://localhost:8001/ \u4e0a\u63d0\u4f9b\u670d\u52a1\u3002 \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u65f6\u52a0\u4e0a\u4e00\u4e2a -v=9 \u7684\u6807\u5fd7\uff0c\u5b83\u4f1a\u663e\u793a\u6240\u6709\u9700\u8981\u7684\u4fe1\u606f\u3002 \u8981\u70b9\uff1a \u8bbf\u95ee\uff08access\uff09\u662f\u4e00\u79cd\u83b7\u53d6\u8d44\u6e90\u6216\u670d\u52a1\u7684\u884c\u4e3a\u3002 \u5e94\u7528\u7a0b\u5e8f\uff08application\uff09\u662f\u4e00\u79cd\u6267\u884c\u7279\u5b9a\u529f\u80fd\u7684\u8f6f\u4ef6\u3002 \u4f5c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u8bbf\u95ee\u610f\u5473\u7740\u4f7f\u7528\u5e94\u7528\u7a0b\u5e8f\u7684\u8eab\u4efd\u6216\u51ed\u8bc1\u6765\u8bbf\u95ee\u3002 kubernetes\u662f\u4e00\u79cd\u7ba1\u7406\u5bb9\u5668\u5316\u5e94\u7528\u7a0b\u5e8f\u7684\u5e73\u53f0\u3002 kubectl \u662f\u4e00\u79cd\u7528\u6765\u548ckubernetes\u4ea4\u4e92\u7684\u547d\u4ee4\u884c\u5de5\u5177\u3002 curl \u662f\u4e00\u79cd\u7528\u6765\u53d1\u9001HTTP\u8bf7\u6c42\u7684\u547d\u4ee4\u884c\u5de5\u5177\u3002 kubectl proxy \u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u672c\u5730\u4ee3\u7406\uff0c\u8ba9\u6211\u4eec\u53ef\u4ee5\u8bbf\u95eekubernetes\u7684API\u670d\u52a1\u5668\u3002 -v=9 \u662f\u4e00\u79cd\u7528\u6765\u663e\u793a\u8be6\u7ec6\u4fe1\u606f\u7684\u9009\u9879\u3002 kubectl get nodes \u5728\u4e0a\u9762\u547d\u4ee4\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u627e\u5230\u5bf9\u5e94\u7684curl\u8bf7\u6c42\u4fe1\u606f\u3002 curl -v -XGET \\ -H \"Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json\" \\ -H \"User-Agent: kubectl/v1.24.1 (linux/amd64) kubernetes/3ddd0f4\" \\ 'https:///api/v1/nodes?limit=500' \u53c2\u8003\u4fe1\u606f\uff1a forum-like page \u662f\u6709K8s\u8fd0\u8425\u7684\u5e73\u53f0\uff0c\u63d0\u4f9b\u4e86\u5f88\u591a\u5173\u4e8e\u5982\u4f55\u4f7f\u7528 kubectl \u7684\u8be6\u7ec6\u4fe1\u606f\u548c\u4f8b\u5b50\u3002 Manage multiple clusters and multiple config files kubectl command documentation Shell autocompletion kubectl cheat sheet jsonpath in kubectl kubectl","title":"kubectl\u57fa\u7840"},{"location":"k8s/cka_cn/foundamentals/basics/#cka7kubectl","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb07:kubectl\u57fa\u7840"},{"location":"k8s/cka_cn/foundamentals/basics/#_1","text":"\u4e86\u89e3\u5982\u4f55\u4f7f\u7528 kubectl \u64cd\u4f5cKubernetes\u96c6\u7fa4\u3002 via API via kubectl via Dashboard","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/basics/#kubeconfig","text":"\u901a\u8fc7\u547d\u4ee4 kubectl config \u68c0\u67e5\u5f53\u524d\u914d\u7f6e\u6587\u4ef6\u4e2d\u7684\u4e0a\u4e0b\u6587\u3002 echo $KUBECONFIG kubectl config view kubectl config get-contexts","title":"\u68c0\u67e5\u5f53\u524dkubeconfig\u6587\u4ef6\u914d\u7f6e"},{"location":"k8s/cka_cn/foundamentals/basics/#_2","text":"\u8bfb\u53d6\u6240\u6709\u652f\u6301\u7684\u8d44\u6e90\u6e05\u5355\u3002 kubectl api-resources","title":"\u83b7\u53d6\u8d44\u6e90\u6e05\u5355"},{"location":"k8s/cka_cn/foundamentals/basics/#_3","text":"Kubernetes \u63a7\u5236\u9762\u677f\u8fd0\u884c\u5728 https://:6443 \u3002 CoreDNS \u8fd0\u884c\u5728 https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy \u3002 kubectl cluster-info kubectl cluster-info dump","title":"\u83b7\u53d6\u96c6\u7fa4\u72b6\u6001"},{"location":"k8s/cka_cn/foundamentals/basics/#_4","text":"\u6267\u884c\u547d\u4ee4 kubectl get --help \u53ef\u4ee5\u5f97\u5230get\u547d\u4ee4\u7684\u793a\u4f8b\u548c\u4f7f\u7528\u65b9\u6cd5\u3002 \u8bfb\u53d6\u5f53\u524d\u63a7\u5236\u9762\u677f\u7684\u5065\u5eb7\u72b6\u6001\u3002 kubectl get componentstatuses kubectl get cs \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS MESSAGE ERROR etcd-0 Healthy {\"health\":\"true\",\"reason\":\"\"} scheduler Healthy ok controller-manager Healthy ok","title":"\u8bfb\u53d6\u5f53\u524d\u8d44\u6e90"},{"location":"k8s/cka_cn/foundamentals/basics/#_5","text":"kubectl get nodes kubectl get nodes -o wide kubectl describe node cka001 \u53ef\u4ee5\u901a\u8fc7\u547d\u4ee4 kubectl create --help \u6765\u83b7\u53d6get\u547d\u4ee4\u7684\u5e2e\u52a9\u548c\u793a\u4f8b\u3002","title":"\u8bfb\u53d6\u8282\u70b9\u72b6\u6001\u548c\u4fe1\u606f"},{"location":"k8s/cka_cn/foundamentals/basics/#namespace","text":"kubectl create namespace --help kubectl create namespace my-namespace \u63d0\u793a\uff1a \u547d\u540d\u7a7a\u95f4Namespace\u662f\u4e00\u4e2a\u96c6\u7fa4\uff0c\u5305\u542b\u4e86\u670d\u52a1\u3002\u670d\u52a1\u53ef\u80fd\u5728\u4e00\u4e2a\u8282\u70b9\u4e0a\uff0c\u4e5f\u53ef\u80fd\u4e0d\u5728\u3002 Namespace\u662f\u4e00\u79cd\u7528\u6765\u7ec4\u7ec7\u670d\u52a1\u7684\u65b9\u5f0f\uff0c\u5b83\u53ef\u4ee5\u5bf9\u670d\u52a1\u8fdb\u884c\u9694\u79bb\u548c\u5212\u5206\u3002 \u4e0d\u540c\u7684Namespace\u4e0b\uff0c\u53ef\u4ee5\u5b58\u5728\u76f8\u540c\u7684\u670d\u52a1\u540d\uff0c\u4f46\u662f\u4e0d\u540c\u7684Namespace\u4e4b\u95f4\u7684\u670d\u52a1\u4e0d\u80fd\u76f4\u63a5\u901a\u4fe1\uff0c\u9700\u8981\u901a\u8fc7Service\u6216Ingress\u6765\u66b4\u9732\u3002 \u670d\u52a1\u662f\u4e00\u79cd\u63d0\u4f9b\u529f\u80fd\u7684\u5b9e\u4f53 \u8282\u70b9\u662f\u4e00\u79cd\u8fd0\u884c\u670d\u52a1\u7684\u7269\u7406\u6216\u865a\u62df\u673a\u5668","title":"\u521b\u5efaNamespace"},{"location":"k8s/cka_cn/foundamentals/basics/#deployment","text":"\u5728\u67d0\u4e2aNamespace\u4e2d\u521b\u5efaDeployment\u3002 kubectl -n my-namespace create deployment my-busybox \\ --image = busybox \\ --replicas = 3 \\ --port = 5701","title":"\u521b\u5efadeployment"},{"location":"k8s/cka_cn/foundamentals/basics/#clusterrole","text":"kubectl create clusterrole --help kubectl create clusterrole pod-creater \\ -n my-namespace \\ --verb = create \\ --resource = deployment \\ --resource-name = my-busybox","title":"\u521b\u5efaClusterRole"},{"location":"k8s/cka_cn/foundamentals/basics/#serviceaccount","text":"kubectl create serviceaccount --help kubectl -n my-namespace create serviceaccount my-service-account","title":"\u521b\u5efaServiceAccount"},{"location":"k8s/cka_cn/foundamentals/basics/#rolebinding","text":"RoleBinding \u53ef\u4ee5\u5f15\u7528\u540c\u4e00\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u4e00\u4e2aRole\uff0c\u6216\u8005\u5168\u5c40\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u4e00\u4e2aClusterRole\u3002 RoleBinding \u662f\u4e00\u79cd\u7528\u6765\u6388\u6743\u89d2\u8272\u7684\u8d44\u6e90\u3002 Role\u662f\u4e00\u79cd\u5b9a\u4e49\u6743\u9650\u7684\u8d44\u6e90\uff0c\u53ea\u80fd\u5728\u540c\u4e00\u547d\u540d\u7a7a\u95f4\u5185\u751f\u6548\u3002 ClusterRole\u662f\u4e00\u79cd\u5b9a\u4e49\u6743\u9650\u7684\u8d44\u6e90\uff0c\u53ef\u4ee5\u5728\u6574\u4e2a\u96c6\u7fa4\u5185\u751f\u6548\u3002 kubectl create rolebinding --help kubectl create rolebinding NAME \\ --clusterrole = NAME | --role = NAME \\ [ --user = username ] \\ [ --group = groupname ] \\ [ --serviceaccount = namespace:serviceaccountname ] \\ [ --dry-run = server | client | none ] kubectl create rolebinding my-admin \\ --clusterrole = pod-creater \\ --serviceaccount = my-namespace:my-service-account","title":"\u521b\u5efaRoleBinding"},{"location":"k8s/cka_cn/foundamentals/basics/#proxy","text":"\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 kubectl proxy \u547d\u4ee4\u6765\u6253\u5f00\u4e00\u4e2a\u5230API\u670d\u52a1\u5668\u7684\u96a7\u9053\uff08tunnel\uff09\uff0c\u5e76\u4f7f\u5b83\u5728\u672c\u5730\u53ef\u7528 - \u901a\u5e38\u662f\u5728 localhost:8001 / 127.0.0.1:8001 \u3002\u5f53\u6211\u60f3\u8981\u4f7f\u7528API\u65f6\uff0c\u6700\u7b80\u5355\u7684\u65b9\u6cd5\u5c31\u662f\u83b7\u53d6\u8bbf\u95ee\u6743\u9650\u3002 \u8fd0\u884c\u547d\u4ee4 kubectl proxy & \u5e76\u5728\u6d4f\u89c8\u5668\u4e2d\u6253\u5f00 http://localhost:8001/api/v1 \u3002 \u53ea\u6253\u5f00 http://localhost:8001 \u4f1a\u8fd4\u56de\u9519\u8bef\uff0c\u56e0\u4e3a\u6211\u4eec\u53ea\u80fd\u8bbf\u95eeAPI\u7684\u67d0\u4e9b\u5185\u5bb9\uff0c\u56e0\u6b64API\u8def\u5f84\u5f88\u91cd\u8981\u3002 \u8981\u70b9\u662f\uff1a kubectl proxy \u547d\u4ee4\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u672c\u5730\u4ee3\u7406\uff0c\u8ba9\u6211\u4eec\u53ef\u4ee5\u8bbf\u95eeAPI\u670d\u52a1\u5668\u3002 API\u670d\u52a1\u5668\u63d0\u4f9b\u4e86\u96c6\u7fa4\u7684\u5404\u79cd\u4fe1\u606f\u548c\u64cd\u4f5c\u3002 \u6211\u4eec\u9700\u8981\u6307\u5b9a\u6b63\u786e\u7684API\u8def\u5f84\uff0c\u624d\u80fd\u8bbf\u95ee\u6211\u4eec\u60f3\u8981\u7684\u8d44\u6e90\u3002 kubectl proxy & \u8f93\u51fa\u7ed3\u679c\uff1a [1] 102358 Starting to serve on 127.0.0.1:8001 \u6bd4\u5982\uff1a http://127.0.0.1:8001/ http://127.0.0.1:8001/api/v1 http://127.0.0.1:8001/api/v1/namespaces http://127.0.0.1:8001/api/v1/namespaces/default http://127.0.0.1:8001/api/v1/namespaces/sock-shop/pods","title":"\u4f7f\u7528proxy"},{"location":"k8s/cka_cn/foundamentals/basics/#_6","text":"\u5982\u679c\u6211\u4eec\u4f5c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u800c\u4e0d\u662f\u7ba1\u7406\u5458\u6765\u8bbf\u95eekubernetes\uff0c\u5c31\u4e0d\u80fd\u4f7f\u7528 kubectl \uff0c\u53ef\u4ee5\u7528 curl \u7a0b\u5e8f\u6765\u4ee3\u66ff kubectl \u3002 \u6211\u4eec\u5fc5\u987b\u5411\u96c6\u7fa4\u53d1\u9001HTTP\u8bf7\u6c42\uff0c\u8be2\u95ee\u53ef\u7528\u7684\u8282\u70b9\u3002 \u786e\u4fdd kubectl proxy \u6b63\u5728\u8fd0\u884c\uff0c\u5e76\u5728 http://localhost:8001/ \u4e0a\u63d0\u4f9b\u670d\u52a1\u3002 \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u65f6\u52a0\u4e0a\u4e00\u4e2a -v=9 \u7684\u6807\u5fd7\uff0c\u5b83\u4f1a\u663e\u793a\u6240\u6709\u9700\u8981\u7684\u4fe1\u606f\u3002 \u8981\u70b9\uff1a \u8bbf\u95ee\uff08access\uff09\u662f\u4e00\u79cd\u83b7\u53d6\u8d44\u6e90\u6216\u670d\u52a1\u7684\u884c\u4e3a\u3002 \u5e94\u7528\u7a0b\u5e8f\uff08application\uff09\u662f\u4e00\u79cd\u6267\u884c\u7279\u5b9a\u529f\u80fd\u7684\u8f6f\u4ef6\u3002 \u4f5c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u8bbf\u95ee\u610f\u5473\u7740\u4f7f\u7528\u5e94\u7528\u7a0b\u5e8f\u7684\u8eab\u4efd\u6216\u51ed\u8bc1\u6765\u8bbf\u95ee\u3002 kubernetes\u662f\u4e00\u79cd\u7ba1\u7406\u5bb9\u5668\u5316\u5e94\u7528\u7a0b\u5e8f\u7684\u5e73\u53f0\u3002 kubectl \u662f\u4e00\u79cd\u7528\u6765\u548ckubernetes\u4ea4\u4e92\u7684\u547d\u4ee4\u884c\u5de5\u5177\u3002 curl \u662f\u4e00\u79cd\u7528\u6765\u53d1\u9001HTTP\u8bf7\u6c42\u7684\u547d\u4ee4\u884c\u5de5\u5177\u3002 kubectl proxy \u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u672c\u5730\u4ee3\u7406\uff0c\u8ba9\u6211\u4eec\u53ef\u4ee5\u8bbf\u95eekubernetes\u7684API\u670d\u52a1\u5668\u3002 -v=9 \u662f\u4e00\u79cd\u7528\u6765\u663e\u793a\u8be6\u7ec6\u4fe1\u606f\u7684\u9009\u9879\u3002 kubectl get nodes \u5728\u4e0a\u9762\u547d\u4ee4\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u627e\u5230\u5bf9\u5e94\u7684curl\u8bf7\u6c42\u4fe1\u606f\u3002 curl -v -XGET \\ -H \"Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json\" \\ -H \"User-Agent: kubectl/v1.24.1 (linux/amd64) kubernetes/3ddd0f4\" \\ 'https:///api/v1/nodes?limit=500' \u53c2\u8003\u4fe1\u606f\uff1a forum-like page \u662f\u6709K8s\u8fd0\u8425\u7684\u5e73\u53f0\uff0c\u63d0\u4f9b\u4e86\u5f88\u591a\u5173\u4e8e\u5982\u4f55\u4f7f\u7528 kubectl \u7684\u8be6\u7ec6\u4fe1\u606f\u548c\u4f8b\u5b50\u3002 Manage multiple clusters and multiple config files kubectl command documentation Shell autocompletion kubectl cheat sheet jsonpath in kubectl kubectl","title":"\u4f5c\u4e3a\u5e94\u7528\u7a0b\u5e8f\u8bbf\u95ee"},{"location":"k8s/cka_cn/foundamentals/casestudy-calico/","text":"\u4e3b\u9898\u8ba8\u8bba:\u5b89\u88c5Calico \u00b6 \u6f14\u793a\u573a\u666f\uff1a\u5b89\u88c5Calico \u8fd9\u662f\u4e00\u4e2a\u5173\u4e8e\u5982\u4f55\u914d\u7f6e\u548c\u6d4b\u8bd5Calico\u7f51\u7edc\u7684\u7b80\u8981\u6b65\u9aa4\uff1a Calico\u6570\u636e\u5e93\uff08Datastore\uff09\uff1aCalico\u652f\u6301\u4f7f\u7528etcd\u6216Kubernetes API server\u4f5c\u4e3a\u6570\u636e\u5b58\u50a8\u540e\u7aef\u3002\u9009\u62e9\u5e76\u90e8\u7f72\u5176\u4e2d\u4e00\u4e2a\u6570\u636e\u5b58\u50a8\u540e\u7aef\u3002 \u914d\u7f6eIP\u6c60\uff1a\u4e3a\u4e86\u4e3aKubernetes\u96c6\u7fa4\u4e2d\u7684\u8282\u70b9\u5206\u914dIP\u5730\u5740\uff0c\u9700\u8981\u914d\u7f6eIP\u6c60\u3002\u53ef\u4ee5\u901a\u8fc7Calico\u81ea\u5b9a\u4e49\u8d44\u6e90\uff08CRD\uff09\u6765\u5b9a\u4e49IP\u6c60\u3002 \u5b89\u88c5CNI\u63d2\u4ef6\uff1aCNI\u63d2\u4ef6\u8d1f\u8d23\u5728\u8282\u70b9\u4e0a\u521b\u5efa\u548c\u5220\u9664\u7f51\u7edc\u63a5\u53e3\uff0c\u5b83\u4eec\u662f\u5e94\u7528\u7a0b\u5e8f\u5bb9\u5668\u548c\u7269\u7406\u7f51\u7edc\u4e4b\u95f4\u7684\u6865\u6881\u3002\u9700\u8981\u5728Kubernetes\u8282\u70b9\u4e0a\u5b89\u88c5Calico CNI\u63d2\u4ef6\u3002 \u5b89\u88c5Typha\uff1aTypha\u662fCalico\u4e2d\u592e\u63a7\u5236\u5e73\u9762\u7684\u4e00\u4e2a\u7ec4\u4ef6\u3002\u5b83\u4eceKubernetes API server\u4e2d\u83b7\u53d6\u7f51\u7edc\u7b56\u7565\u548c\u5176\u4ed6\u4fe1\u606f\uff0c\u5e76\u5c06\u5b83\u4eec\u5206\u53d1\u7ed9\u6240\u6709\u8282\u70b9\u4e0a\u7684calico/node\u3002 \u5b89\u88c5calico/node\uff1acalico/node\u662f\u4e00\u4e2a\u8fd0\u884c\u5728Kubernetes\u8282\u70b9\u4e0a\u7684\u5b88\u62a4\u8fdb\u7a0b\u3002\u5b83\u7ba1\u7406\u8282\u70b9\u4e0a\u7684\u7f51\u7edc\u63a5\u53e3\uff0c\u5e76\u4e3a\u5bb9\u5668\u5206\u914d\u548c\u91ca\u653eIP\u5730\u5740\u3002 \u6d4b\u8bd5\u7f51\u7edc\uff1a\u5728\u5b8c\u6210\u4e0a\u8ff0\u6b65\u9aa4\u540e\uff0c\u53ef\u4ee5\u901a\u8fc7\u5728Pod\u4e4b\u95f4\u8fdb\u884c\u7f51\u7edc\u901a\u4fe1\u6765\u6d4b\u8bd5Calico\u7f51\u7edc\u662f\u5426\u6b63\u5e38\u5de5\u4f5c\u3002\u53ef\u4ee5\u521b\u5efa\u4e24\u4e2a\u8fd0\u884c\u5728\u4e0d\u540c\u8282\u70b9\u4e0a\u7684Pod\uff0c\u5e76\u5c1d\u8bd5\u4ece\u4e00\u4e2aPod ping\u53e6\u4e00\u4e2aPod\u3002\u5982\u679cping\u6210\u529f\uff0c\u5219\u8868\u793aCalico\u7f51\u7edc\u5df2\u6210\u529f\u914d\u7f6e\u548c\u8fd0\u884c\u3002 Calico\u6570\u636e\u5e93 \u00b6 \u4e3a\u4e86\u5c06Kubernetes\u7528\u4f5cCalico\u6570\u636e\u5b58\u50a8\u5e93\uff0c\u6211\u4eec\u9700\u8981\u5b9a\u4e49Calico\u4f7f\u7528\u7684\u81ea\u5b9a\u4e49\u8d44\u6e90\u3002 \u4e0b\u8f7d\u5e76\u68c0\u67e5Calico\u81ea\u5b9a\u4e49\u8d44\u6e90\u5b9a\u4e49\u5217\u8868\uff0c\u5e76\u5728\u6587\u4ef6\u7f16\u8f91\u5668\u4e2d\u6253\u5f00\u5b83\u3002 wget https://projectcalico.docs.tigera.io/manifests/crds.yaml \u5728 Kubernetes \u4e2d\u521b\u5efa Calico \u7684\u81ea\u5b9a\u4e49\u8d44\u6e90\u3002 kubectl apply -f crds.yaml \u5b89\u88c5 calicoctl \u3002 \u4e0b\u8f7d calicoctl \u4e8c\u8fdb\u5236\u6587\u4ef6\u5230\u4e00\u4e2a\u53ef\u4ee5\u8bbf\u95ee Kubernetes \u7684 Linux \u4e3b\u673a\u4e0a\uff0c\u4ee5\u76f4\u63a5\u4e0e Calico \u6570\u636e\u5b58\u50a8\u4ea4\u4e92\u3002 \u6700\u65b0\u7248\u7684calicoctl\u53ef\u4ee5\u901a\u8fc7 git page \u8fdb\u884c\u4e0b\u8f7d\uff0c\u9700\u8981\u7528\u5b9e\u9645\u7248\u672c\u53f7\u66ff\u6362\u4e0b\u9762\u7684 v3.23.2 \u7684\u7248\u672c\u53f7\u3002 wget https://github.com/projectcalico/calico/releases/download/v3.23.3/calicoctl-linux-amd64 chmod +x calicoctl-linux-amd64 sudo cp calicoctl-linux-amd64 /usr/local/bin/calicoctl \u914d\u7f6e calicoctl \u4ee5\u8bbf\u95ee Kubernetes\u3002 echo \"export KUBECONFIG=/root/.kube/config\" >> ~/.bashrc echo \"export DATASTORE_TYPE=kubernetes\" >> ~/.bashrc echo $KUBECONFIG echo $DATASTORE_TYPE \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u9a8c\u8bc1 calicoctl \u80fd\u591f\u8bbf\u95ee\u6570\u636e\u5e93\u3002 calicoctl get nodes -o wide \u8fd0\u884c\u7ed3\u679c\u7c7b\u4f3c\u5982\u4e0b\uff1a NAME ASN IPV4 IPV6 cka001 cka002 cka003 \u8282\u70b9\u662f\u7531 Kubernetes \u8282\u70b9\u5bf9\u8c61\u652f\u6301\u7684\uff0c\u56e0\u6b64\u6211\u4eec\u5e94\u8be5\u770b\u5230\u4e0e kubectl get nodes \u5339\u914d\u7684\u540d\u79f0\u3002 kubectl get nodes -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 NotReady control-plane,master 23m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka002 NotReady 22m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka003 NotReady 21m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 \u914d\u7f6eIP\u6c60 \u00b6 \u4e00\u4e2a\u5de5\u4f5c\u8d1f\u8f7d\uff08workload\uff09\u662f\u5bb9\u5668\u6216\u865a\u62df\u673a\uff0c\u57fa\u4e8eCalico\u7684\u865a\u62df\u7f51\u7edc\u3002 \u5728Kubernetes\u4e2d\uff0c\u5de5\u4f5c\u8d1f\u8f7d\u662fPod\u3002\u4e00\u4e2a\u5de5\u4f5c\u8d1f\u8f7d\u7aef\u70b9\uff08endpoint\uff09\u662f\u5de5\u4f5c\u8d1f\u8f7d\u7528\u6765\u8fde\u63a5Calico\u7f51\u7edc\u7684\u865a\u62df\u7f51\u7edc\u63a5\u53e3\u3002 IP\u6c60\u662fCalico\u4e3a\u5de5\u4f5c\u8d1f\u8f7d\u7aef\u70b9\u4f7f\u7528\u7684IP\u5730\u5740\u8303\u56f4\u3002 \u83b7\u53d6\u96c6\u7fa4\u4e2d\u5f53\u524d\u7684IP\u6c60\u3002\u76ee\u524d\uff0c\u5728\u521a\u521a\u5b89\u88c5\u5b8c\u4e4b\u540e\uff0c\u5b83\u662f\u7a7a\u7684\u3002 calicoctl get ippools \u8fd0\u884c\u7ed3\u679c\uff1a NAME CIDR SELECTOR \u6211\u4eec\u901a\u8fc7 kubeadm init \u547d\u4ee4\u6307\u5b9a\u4e86 Pod CIDR \u4e3a 10.244.0.0/16 \u3002 \u73b0\u5728\uff0c\u6211\u4eec\u4e3a\u96c6\u7fa4\u521b\u5efa\u4e24\u4e2a IP \u6c60\uff08IP pool\uff09\uff0c\u6bcf\u4e2a\u6c60\u4e4b\u95f4\u4e0d\u80fd\u91cd\u53e0\u3002 \u521b\u5efaIP\u6c60 ipv4-ippool-1 : 10.244.0.0/18 calicoctl apply -f - < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < 4h49m v1.24.0 cka003 Ready 4h49m v1.24.0 \u5b89\u88c5Typha \u00b6 Typha \u5904\u4e8e Kubernetes API \u670d\u52a1\u5668\u548c\u6bcf\u4e2a\u8282\u70b9\u5b88\u62a4\u8fdb\u7a0b\uff08\u5982\u8fd0\u884c\u5728 calico/node \u4e2d\u7684 Felix \u548c confd\uff09\u4e4b\u95f4\u3002 \u5b83\u76d1\u89c6\u8fd9\u4e9b\u5b88\u62a4\u8fdb\u7a0b\u4f7f\u7528\u7684 Kubernetes \u8d44\u6e90\u548c Calico \u81ea\u5b9a\u4e49\u8d44\u6e90\uff0c\u6bcf\u5f53\u8d44\u6e90\u66f4\u6539\u65f6\uff0c\u5b83\u4f1a\u5c06\u66f4\u65b0\u6269\u6563\u5230\u8fd9\u4e9b\u5b88\u62a4\u8fdb\u7a0b\u3002 \u8fd9\u51cf\u5c11\u4e86 Kubernetes API \u670d\u52a1\u5668\u9700\u8981\u670d\u52a1\u7684\u76d1\u89c6\u6570\uff0c\u63d0\u9ad8\u4e86\u96c6\u7fa4\u7684\u53ef\u6269\u5c55\u6027\u3002 \u51c6\u5907\u8bc1\u4e66 \u4e0b\u9762\uff0c\u6211\u4eec\u4f7f\u7528\u76f8\u4e92\u8ba4\u8bc1\u7684TLS\u6765\u786e\u4fddcalico/node\u548cTypha\u4e4b\u95f4\u7684\u901a\u4fe1\u5b89\u5168\u3002 \u751f\u6210\u4e00\u4e2a\u8bc1\u4e66\u6388\u6743\u673a\u6784\uff08CA\uff09\u5e76\u4f7f\u7528\u5b83\u6765\u4e3aTypha\u7b7e\u7f72\u8bc1\u4e66\u3002 \u5c06\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u6539\u4e3a /etc/kubernetes/pki/ \u3002 cd /etc/kubernetes/pki/ \u521b\u5efaCA\u8bc1\u4e66\u548c\u5bc6\u94a5\u3002 openssl req -x509 -newkey rsa:4096 \\ -keyout typhaca.key \\ -nodes \\ -out typhaca.crt \\ -subj \"/CN=Calico Typha CA\" \\ -days 365 \u628aCA\u8bc1\u4e66\u5b58\u653e\u5728ConfigMap\u4e2d\uff0c\u4f7fTypha\u548ccalico/node\u80fd\u591f\u8bbf\u95ee\u3002 kubectl create configmap -n kube-system calico-typha-ca --from-file = typhaca.crt \u751f\u6210Typha\u5bc6\u94a5\u548c\u8bc1\u4e66\u7b7e\u540d\u8bf7\u6c42\uff08certificate signing request\uff0cCSR\uff09\u3002 openssl req -newkey rsa:4096 \\ -keyout typha.key \\ -nodes \\ -out typha.csr \\ -subj \"/CN=calico-typha\" \u8bc1\u4e66\u7684\u901a\u7528\u540d\u79f0\uff08CN\uff09\u8bbe\u7f6e\u4e3a calico-typha \u3002 calico/node \u5c06\u88ab\u7528\u6765\u9a8c\u8bc1\u6b64\u540d\u79f0\u3002 \u4f7f\u7528 CA \u5bf9 Typha \u8bc1\u4e66\u8fdb\u884c\u7b7e\u540d\u3002 openssl x509 -req -in typha.csr \\ -CA typhaca.crt \\ -CAkey typhaca.key \\ -CAcreateserial \\ -out typha.crt \\ -days 365 \u8fd0\u884c\u7ed3\u679c\uff1a Signature ok subject=CN = calico-typha Getting CA Private Key \u5c06 Typha \u5bc6\u94a5\u548c\u8bc1\u4e66\u5b58\u50a8\u5728\u4e00\u4e2a secret \u4e2d\uff0c\u4ee5\u4fbf Typha \u53ef\u4ee5\u8bbf\u95ee\u3002 kubectl create secret generic -n kube-system calico-typha-certs --from-file = typha.key --from-file = typha.crt \u914d\u7f6eRBAC \u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u4e3ahome\u8def\u5f84\u3002 cd ~ \u521b\u5efa\u4e00\u4e2aTypha\u4f7f\u7528\u7684ServiceAccount\u3002 kubectl create serviceaccount -n kube-system calico-typha \u4e3a Typha \u521b\u5efa\u4e00\u4e2a\u96c6\u7fa4\u89d2\u8272\uff0c\u6709\u89c2\u5bdf Calico \u6570\u636e\u5b58\u50a8\u5bf9\u8c61\u7684\u6743\u9650\u3002 kubectl apply -f - < pingtest-585b76c894-s2tbs 1/1 Running 0 7s 10.244.31.0 cka002 pingtest-585b76c894-vm9wn 1/1 Running 0 7s 10.244.28.64 cka003 \u7559\u610f\u7b2c\u4e8c\u4e2a\u548c\u7b2c\u4e09\u4e2a pod \u7684 IP \u5730\u5740\u3002 \u968f\u540e\u6211\u4eec\u4f1a\u5728\u7b2c\u4e00\u4e2a pod \u4e2d\u8fd0\u884c exec \u547d\u4ee4\u3002 \u5728\u7b2c\u4e00\u4e2a pod \u5185\u90e8\uff0c\u5bf9\u53e6\u5916\u4e24\u4e2a pod \u7684 IP \u5730\u5740\u8fdb\u884c ping \u6d4b\u8bd5\u3002 \u4f8b\u5982\uff1a kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # ping 10.244.31.1 -c 4 4 packets transmitted, 4 packets received, 0 % packet loss / # ping 10.244.31.0 -c 4 4 packets transmitted, 4 packets received, 0 % packet loss / # ping 10.244.28.64 -c 4 4 packets transmitted, 0 packets received, 100 % packet loss \u8def\u7531\u68c0\u67e5 \u00b6 \u4ece\u5176\u4e2d\u4e00\u4e2a\u8282\u70b9\u9a8c\u8bc1\u662f\u5426\u80fdping\u901a\u5230\u6bcf\u4e2apod\u7684IP\u5730\u5740\u3002\u4f8b\u5982\uff1a ip route get 10 .244.31.1 ip route get 10 .244.31.0 ip route get 10 .244.28.64 \u5728\u4e0a\u9762\u7684\u7ed3\u679c\u4e2d\uff0c\u793a\u4f8b\u4e2d\u7684 via \uff08\u5b83\u662f\u63a7\u5236\u5e73\u9762\uff09\u8868\u793a\u6b64Pod IP\u7684\u4e0b\u4e00\u8df3\uff0c\u8fd9\u4e0ePod\u6240\u5728\u8282\u70b9\u7684IP\u5730\u5740\u5339\u914d\uff0c\u7b26\u5408\u9884\u671f\u3002 \u4e0d\u540cIP\u6c60\u7684IPAM\u5206\u914d\u3002\u5728\u524d\u9762\u7684\u6f14\u793a\u4e2d\uff0c\u6211\u4eec\u521b\u5efa\u4e86\u4e24\u4e2aIP\u6c60\uff0c\u4f46\u5c06\u4e00\u4e2a\u7981\u7528\u4e86\u3002 calicoctl get ippools -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR ipv4-ippool-1 10.244.0.0/18 true Never Never false false all() ipv4-ippool-2 10.244.192.0/19 true Never Never true false all() \u6fc0\u6d3b\u7b2c\u4e8c\u4e2aIP\u6c60\u3002 calicoctl --allow-version-mismatch apply -f - < \u8fde\u63a5\u5e76\u8fdb\u5165Pod pingtest-585b76c894-chwjq \u5185\u90e8\u3002 kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # 10.244.203.192 -c 4 4 packets transmitted, 0 packets received, 100 % packet loss \u6807\u8bb0\uff1a \u6f14\u793a\u6b62\u4e8e\u6b64\uff0c\u8def\u7531\u6ca1\u6709\u5b89\u88c5\u9884\u671f\u5de5\u4f5c\uff0c\u539f\u56e0\u67e5\u627e\u4e2d\u3002 \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete deployments.apps pingtest kubectl delete pod pingtest-ippool-2 \u53c2\u8003\uff1a End-to-end Calico installation","title":"\u5b89\u88c5Calico"},{"location":"k8s/cka_cn/foundamentals/casestudy-calico/#calico","text":"\u6f14\u793a\u573a\u666f\uff1a\u5b89\u88c5Calico \u8fd9\u662f\u4e00\u4e2a\u5173\u4e8e\u5982\u4f55\u914d\u7f6e\u548c\u6d4b\u8bd5Calico\u7f51\u7edc\u7684\u7b80\u8981\u6b65\u9aa4\uff1a Calico\u6570\u636e\u5e93\uff08Datastore\uff09\uff1aCalico\u652f\u6301\u4f7f\u7528etcd\u6216Kubernetes API server\u4f5c\u4e3a\u6570\u636e\u5b58\u50a8\u540e\u7aef\u3002\u9009\u62e9\u5e76\u90e8\u7f72\u5176\u4e2d\u4e00\u4e2a\u6570\u636e\u5b58\u50a8\u540e\u7aef\u3002 \u914d\u7f6eIP\u6c60\uff1a\u4e3a\u4e86\u4e3aKubernetes\u96c6\u7fa4\u4e2d\u7684\u8282\u70b9\u5206\u914dIP\u5730\u5740\uff0c\u9700\u8981\u914d\u7f6eIP\u6c60\u3002\u53ef\u4ee5\u901a\u8fc7Calico\u81ea\u5b9a\u4e49\u8d44\u6e90\uff08CRD\uff09\u6765\u5b9a\u4e49IP\u6c60\u3002 \u5b89\u88c5CNI\u63d2\u4ef6\uff1aCNI\u63d2\u4ef6\u8d1f\u8d23\u5728\u8282\u70b9\u4e0a\u521b\u5efa\u548c\u5220\u9664\u7f51\u7edc\u63a5\u53e3\uff0c\u5b83\u4eec\u662f\u5e94\u7528\u7a0b\u5e8f\u5bb9\u5668\u548c\u7269\u7406\u7f51\u7edc\u4e4b\u95f4\u7684\u6865\u6881\u3002\u9700\u8981\u5728Kubernetes\u8282\u70b9\u4e0a\u5b89\u88c5Calico CNI\u63d2\u4ef6\u3002 \u5b89\u88c5Typha\uff1aTypha\u662fCalico\u4e2d\u592e\u63a7\u5236\u5e73\u9762\u7684\u4e00\u4e2a\u7ec4\u4ef6\u3002\u5b83\u4eceKubernetes API server\u4e2d\u83b7\u53d6\u7f51\u7edc\u7b56\u7565\u548c\u5176\u4ed6\u4fe1\u606f\uff0c\u5e76\u5c06\u5b83\u4eec\u5206\u53d1\u7ed9\u6240\u6709\u8282\u70b9\u4e0a\u7684calico/node\u3002 \u5b89\u88c5calico/node\uff1acalico/node\u662f\u4e00\u4e2a\u8fd0\u884c\u5728Kubernetes\u8282\u70b9\u4e0a\u7684\u5b88\u62a4\u8fdb\u7a0b\u3002\u5b83\u7ba1\u7406\u8282\u70b9\u4e0a\u7684\u7f51\u7edc\u63a5\u53e3\uff0c\u5e76\u4e3a\u5bb9\u5668\u5206\u914d\u548c\u91ca\u653eIP\u5730\u5740\u3002 \u6d4b\u8bd5\u7f51\u7edc\uff1a\u5728\u5b8c\u6210\u4e0a\u8ff0\u6b65\u9aa4\u540e\uff0c\u53ef\u4ee5\u901a\u8fc7\u5728Pod\u4e4b\u95f4\u8fdb\u884c\u7f51\u7edc\u901a\u4fe1\u6765\u6d4b\u8bd5Calico\u7f51\u7edc\u662f\u5426\u6b63\u5e38\u5de5\u4f5c\u3002\u53ef\u4ee5\u521b\u5efa\u4e24\u4e2a\u8fd0\u884c\u5728\u4e0d\u540c\u8282\u70b9\u4e0a\u7684Pod\uff0c\u5e76\u5c1d\u8bd5\u4ece\u4e00\u4e2aPod ping\u53e6\u4e00\u4e2aPod\u3002\u5982\u679cping\u6210\u529f\uff0c\u5219\u8868\u793aCalico\u7f51\u7edc\u5df2\u6210\u529f\u914d\u7f6e\u548c\u8fd0\u884c\u3002","title":"\u4e3b\u9898\u8ba8\u8bba:\u5b89\u88c5Calico"},{"location":"k8s/cka_cn/foundamentals/casestudy-calico/#calico_1","text":"\u4e3a\u4e86\u5c06Kubernetes\u7528\u4f5cCalico\u6570\u636e\u5b58\u50a8\u5e93\uff0c\u6211\u4eec\u9700\u8981\u5b9a\u4e49Calico\u4f7f\u7528\u7684\u81ea\u5b9a\u4e49\u8d44\u6e90\u3002 \u4e0b\u8f7d\u5e76\u68c0\u67e5Calico\u81ea\u5b9a\u4e49\u8d44\u6e90\u5b9a\u4e49\u5217\u8868\uff0c\u5e76\u5728\u6587\u4ef6\u7f16\u8f91\u5668\u4e2d\u6253\u5f00\u5b83\u3002 wget https://projectcalico.docs.tigera.io/manifests/crds.yaml \u5728 Kubernetes \u4e2d\u521b\u5efa Calico \u7684\u81ea\u5b9a\u4e49\u8d44\u6e90\u3002 kubectl apply -f crds.yaml \u5b89\u88c5 calicoctl \u3002 \u4e0b\u8f7d calicoctl \u4e8c\u8fdb\u5236\u6587\u4ef6\u5230\u4e00\u4e2a\u53ef\u4ee5\u8bbf\u95ee Kubernetes \u7684 Linux \u4e3b\u673a\u4e0a\uff0c\u4ee5\u76f4\u63a5\u4e0e Calico \u6570\u636e\u5b58\u50a8\u4ea4\u4e92\u3002 \u6700\u65b0\u7248\u7684calicoctl\u53ef\u4ee5\u901a\u8fc7 git page \u8fdb\u884c\u4e0b\u8f7d\uff0c\u9700\u8981\u7528\u5b9e\u9645\u7248\u672c\u53f7\u66ff\u6362\u4e0b\u9762\u7684 v3.23.2 \u7684\u7248\u672c\u53f7\u3002 wget https://github.com/projectcalico/calico/releases/download/v3.23.3/calicoctl-linux-amd64 chmod +x calicoctl-linux-amd64 sudo cp calicoctl-linux-amd64 /usr/local/bin/calicoctl \u914d\u7f6e calicoctl \u4ee5\u8bbf\u95ee Kubernetes\u3002 echo \"export KUBECONFIG=/root/.kube/config\" >> ~/.bashrc echo \"export DATASTORE_TYPE=kubernetes\" >> ~/.bashrc echo $KUBECONFIG echo $DATASTORE_TYPE \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u9a8c\u8bc1 calicoctl \u80fd\u591f\u8bbf\u95ee\u6570\u636e\u5e93\u3002 calicoctl get nodes -o wide \u8fd0\u884c\u7ed3\u679c\u7c7b\u4f3c\u5982\u4e0b\uff1a NAME ASN IPV4 IPV6 cka001 cka002 cka003 \u8282\u70b9\u662f\u7531 Kubernetes \u8282\u70b9\u5bf9\u8c61\u652f\u6301\u7684\uff0c\u56e0\u6b64\u6211\u4eec\u5e94\u8be5\u770b\u5230\u4e0e kubectl get nodes \u5339\u914d\u7684\u540d\u79f0\u3002 kubectl get nodes -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 NotReady control-plane,master 23m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka002 NotReady 22m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka003 NotReady 21m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9","title":"Calico\u6570\u636e\u5e93"},{"location":"k8s/cka_cn/foundamentals/casestudy-calico/#ip","text":"\u4e00\u4e2a\u5de5\u4f5c\u8d1f\u8f7d\uff08workload\uff09\u662f\u5bb9\u5668\u6216\u865a\u62df\u673a\uff0c\u57fa\u4e8eCalico\u7684\u865a\u62df\u7f51\u7edc\u3002 \u5728Kubernetes\u4e2d\uff0c\u5de5\u4f5c\u8d1f\u8f7d\u662fPod\u3002\u4e00\u4e2a\u5de5\u4f5c\u8d1f\u8f7d\u7aef\u70b9\uff08endpoint\uff09\u662f\u5de5\u4f5c\u8d1f\u8f7d\u7528\u6765\u8fde\u63a5Calico\u7f51\u7edc\u7684\u865a\u62df\u7f51\u7edc\u63a5\u53e3\u3002 IP\u6c60\u662fCalico\u4e3a\u5de5\u4f5c\u8d1f\u8f7d\u7aef\u70b9\u4f7f\u7528\u7684IP\u5730\u5740\u8303\u56f4\u3002 \u83b7\u53d6\u96c6\u7fa4\u4e2d\u5f53\u524d\u7684IP\u6c60\u3002\u76ee\u524d\uff0c\u5728\u521a\u521a\u5b89\u88c5\u5b8c\u4e4b\u540e\uff0c\u5b83\u662f\u7a7a\u7684\u3002 calicoctl get ippools \u8fd0\u884c\u7ed3\u679c\uff1a NAME CIDR SELECTOR \u6211\u4eec\u901a\u8fc7 kubeadm init \u547d\u4ee4\u6307\u5b9a\u4e86 Pod CIDR \u4e3a 10.244.0.0/16 \u3002 \u73b0\u5728\uff0c\u6211\u4eec\u4e3a\u96c6\u7fa4\u521b\u5efa\u4e24\u4e2a IP \u6c60\uff08IP pool\uff09\uff0c\u6bcf\u4e2a\u6c60\u4e4b\u95f4\u4e0d\u80fd\u91cd\u53e0\u3002 \u521b\u5efaIP\u6c60 ipv4-ippool-1 : 10.244.0.0/18 calicoctl apply -f - < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < 4h49m v1.24.0 cka003 Ready 4h49m v1.24.0","title":"\u5b89\u88c5CNI\u63d2\u4ef6"},{"location":"k8s/cka_cn/foundamentals/casestudy-calico/#typha","text":"Typha \u5904\u4e8e Kubernetes API \u670d\u52a1\u5668\u548c\u6bcf\u4e2a\u8282\u70b9\u5b88\u62a4\u8fdb\u7a0b\uff08\u5982\u8fd0\u884c\u5728 calico/node \u4e2d\u7684 Felix \u548c confd\uff09\u4e4b\u95f4\u3002 \u5b83\u76d1\u89c6\u8fd9\u4e9b\u5b88\u62a4\u8fdb\u7a0b\u4f7f\u7528\u7684 Kubernetes \u8d44\u6e90\u548c Calico \u81ea\u5b9a\u4e49\u8d44\u6e90\uff0c\u6bcf\u5f53\u8d44\u6e90\u66f4\u6539\u65f6\uff0c\u5b83\u4f1a\u5c06\u66f4\u65b0\u6269\u6563\u5230\u8fd9\u4e9b\u5b88\u62a4\u8fdb\u7a0b\u3002 \u8fd9\u51cf\u5c11\u4e86 Kubernetes API \u670d\u52a1\u5668\u9700\u8981\u670d\u52a1\u7684\u76d1\u89c6\u6570\uff0c\u63d0\u9ad8\u4e86\u96c6\u7fa4\u7684\u53ef\u6269\u5c55\u6027\u3002 \u51c6\u5907\u8bc1\u4e66 \u4e0b\u9762\uff0c\u6211\u4eec\u4f7f\u7528\u76f8\u4e92\u8ba4\u8bc1\u7684TLS\u6765\u786e\u4fddcalico/node\u548cTypha\u4e4b\u95f4\u7684\u901a\u4fe1\u5b89\u5168\u3002 \u751f\u6210\u4e00\u4e2a\u8bc1\u4e66\u6388\u6743\u673a\u6784\uff08CA\uff09\u5e76\u4f7f\u7528\u5b83\u6765\u4e3aTypha\u7b7e\u7f72\u8bc1\u4e66\u3002 \u5c06\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u6539\u4e3a /etc/kubernetes/pki/ \u3002 cd /etc/kubernetes/pki/ \u521b\u5efaCA\u8bc1\u4e66\u548c\u5bc6\u94a5\u3002 openssl req -x509 -newkey rsa:4096 \\ -keyout typhaca.key \\ -nodes \\ -out typhaca.crt \\ -subj \"/CN=Calico Typha CA\" \\ -days 365 \u628aCA\u8bc1\u4e66\u5b58\u653e\u5728ConfigMap\u4e2d\uff0c\u4f7fTypha\u548ccalico/node\u80fd\u591f\u8bbf\u95ee\u3002 kubectl create configmap -n kube-system calico-typha-ca --from-file = typhaca.crt \u751f\u6210Typha\u5bc6\u94a5\u548c\u8bc1\u4e66\u7b7e\u540d\u8bf7\u6c42\uff08certificate signing request\uff0cCSR\uff09\u3002 openssl req -newkey rsa:4096 \\ -keyout typha.key \\ -nodes \\ -out typha.csr \\ -subj \"/CN=calico-typha\" \u8bc1\u4e66\u7684\u901a\u7528\u540d\u79f0\uff08CN\uff09\u8bbe\u7f6e\u4e3a calico-typha \u3002 calico/node \u5c06\u88ab\u7528\u6765\u9a8c\u8bc1\u6b64\u540d\u79f0\u3002 \u4f7f\u7528 CA \u5bf9 Typha \u8bc1\u4e66\u8fdb\u884c\u7b7e\u540d\u3002 openssl x509 -req -in typha.csr \\ -CA typhaca.crt \\ -CAkey typhaca.key \\ -CAcreateserial \\ -out typha.crt \\ -days 365 \u8fd0\u884c\u7ed3\u679c\uff1a Signature ok subject=CN = calico-typha Getting CA Private Key \u5c06 Typha \u5bc6\u94a5\u548c\u8bc1\u4e66\u5b58\u50a8\u5728\u4e00\u4e2a secret \u4e2d\uff0c\u4ee5\u4fbf Typha \u53ef\u4ee5\u8bbf\u95ee\u3002 kubectl create secret generic -n kube-system calico-typha-certs --from-file = typha.key --from-file = typha.crt \u914d\u7f6eRBAC \u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u4e3ahome\u8def\u5f84\u3002 cd ~ \u521b\u5efa\u4e00\u4e2aTypha\u4f7f\u7528\u7684ServiceAccount\u3002 kubectl create serviceaccount -n kube-system calico-typha \u4e3a Typha \u521b\u5efa\u4e00\u4e2a\u96c6\u7fa4\u89d2\u8272\uff0c\u6709\u89c2\u5bdf Calico \u6570\u636e\u5b58\u50a8\u5bf9\u8c61\u7684\u6743\u9650\u3002 kubectl apply -f - < pingtest-585b76c894-s2tbs 1/1 Running 0 7s 10.244.31.0 cka002 pingtest-585b76c894-vm9wn 1/1 Running 0 7s 10.244.28.64 cka003 \u7559\u610f\u7b2c\u4e8c\u4e2a\u548c\u7b2c\u4e09\u4e2a pod \u7684 IP \u5730\u5740\u3002 \u968f\u540e\u6211\u4eec\u4f1a\u5728\u7b2c\u4e00\u4e2a pod \u4e2d\u8fd0\u884c exec \u547d\u4ee4\u3002 \u5728\u7b2c\u4e00\u4e2a pod \u5185\u90e8\uff0c\u5bf9\u53e6\u5916\u4e24\u4e2a pod \u7684 IP \u5730\u5740\u8fdb\u884c ping \u6d4b\u8bd5\u3002 \u4f8b\u5982\uff1a kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # ping 10.244.31.1 -c 4 4 packets transmitted, 4 packets received, 0 % packet loss / # ping 10.244.31.0 -c 4 4 packets transmitted, 4 packets received, 0 % packet loss / # ping 10.244.28.64 -c 4 4 packets transmitted, 0 packets received, 100 % packet loss","title":"pod\u4e4b\u95f4\u7684ping"},{"location":"k8s/cka_cn/foundamentals/casestudy-calico/#_2","text":"\u4ece\u5176\u4e2d\u4e00\u4e2a\u8282\u70b9\u9a8c\u8bc1\u662f\u5426\u80fdping\u901a\u5230\u6bcf\u4e2apod\u7684IP\u5730\u5740\u3002\u4f8b\u5982\uff1a ip route get 10 .244.31.1 ip route get 10 .244.31.0 ip route get 10 .244.28.64 \u5728\u4e0a\u9762\u7684\u7ed3\u679c\u4e2d\uff0c\u793a\u4f8b\u4e2d\u7684 via \uff08\u5b83\u662f\u63a7\u5236\u5e73\u9762\uff09\u8868\u793a\u6b64Pod IP\u7684\u4e0b\u4e00\u8df3\uff0c\u8fd9\u4e0ePod\u6240\u5728\u8282\u70b9\u7684IP\u5730\u5740\u5339\u914d\uff0c\u7b26\u5408\u9884\u671f\u3002 \u4e0d\u540cIP\u6c60\u7684IPAM\u5206\u914d\u3002\u5728\u524d\u9762\u7684\u6f14\u793a\u4e2d\uff0c\u6211\u4eec\u521b\u5efa\u4e86\u4e24\u4e2aIP\u6c60\uff0c\u4f46\u5c06\u4e00\u4e2a\u7981\u7528\u4e86\u3002 calicoctl get ippools -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR ipv4-ippool-1 10.244.0.0/18 true Never Never false false all() ipv4-ippool-2 10.244.192.0/19 true Never Never true false all() \u6fc0\u6d3b\u7b2c\u4e8c\u4e2aIP\u6c60\u3002 calicoctl --allow-version-mismatch apply -f - < \u8fde\u63a5\u5e76\u8fdb\u5165Pod pingtest-585b76c894-chwjq \u5185\u90e8\u3002 kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # 10.244.203.192 -c 4 4 packets transmitted, 0 packets received, 100 % packet loss \u6807\u8bb0\uff1a \u6f14\u793a\u6b62\u4e8e\u6b64\uff0c\u8def\u7531\u6ca1\u6709\u5b89\u88c5\u9884\u671f\u5de5\u4f5c\uff0c\u539f\u56e0\u67e5\u627e\u4e2d\u3002 \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete deployments.apps pingtest kubectl delete pod pingtest-ippool-2 \u53c2\u8003\uff1a End-to-end Calico installation","title":"\u8def\u7531\u68c0\u67e5"},{"location":"k8s/cka_cn/foundamentals/casestudy-health-check/","text":"\u4e3b\u9898\u8ba8\u8bba:\u5065\u5eb7\u68c0\u67e5 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa Deployment \u548c Service \u6a21\u62df\u4e00\u4e2a\u9519\u8bef\uff08\u5220\u9664 index.html\uff09 Pod \u5904\u4e8e\u4e0d\u5065\u5eb7\u72b6\u6001\u5e76\u4ece endpoint \u5217\u8868\u4e2d\u5220\u9664 \u4fee\u590d\u9519\u8bef\uff08\u6062\u590d index.html\uff09 Pod \u56de\u5230\u6b63\u5e38\u72b6\u6001\u5e76\u91cd\u65b0\u52a0\u5165 endpoint \u5217\u8868 \u521b\u5efa Deployment \u548c Service \u00b6 \u521b\u5efaDeployment nginx-healthcheck \u548cService nginx-healthcheck \u3002 kubectl apply -f - < nginx-healthcheck-79fc55d944-nwwjc 1/1 Running 0 9s 10.244.112.13 cka002 \u901a\u8fc7\u547d\u4ee4 curl \u6765\u8bbf\u95ee\u4e0a\u9762\u8fd0\u884c\u7ed3\u679c\u4e2dpod\u7684IP\u5730\u5740\u3002 curl 10 .244.102.14 curl 10 .244.112.13 \u5982\u679c\u4e0a\u9762\u547d\u4ee4\u6210\u529f\u6267\u884c\uff0c\u5219\u4f1a\u8fd4\u56deNginx\u4e2d index.html \u7684\u5185\u5bb9\u3002 \u83b7\u53d6\u524d\u9762\u521b\u5efa\u7684Service\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl describe svc nginx-healthcheck \u8f93\u51fa\u7ed3\u679c\u5982\u4e0b\u3002\u5728 Endpoints \u90e8\u5206\u6211\u4eec\u53ef\u4ee5\u770b\u52302\u4e2apod\u3002 Name : nginx-healthcheck Namespace : dev Labels : Annotations : Selector : name=nginx-healthcheck Type : NodePort IP Family Policy : SingleStack IP Families : IPv4 IP : 11.244.238.20 IPs : 11.244.238.20 Port : 80/TCP TargetPort : 80/TCP NodePort : 31795/TCP Endpoints : 10.244.102.14:80,10.244.112.13:80 Session Affinity : None External Traffic Policy : Cluster Events : \u83b7\u53d6Endpoints\u7684\u4fe1\u606f\u3002 kubectl get endpoints nginx-healthcheck \u8fd0\u884c\u7ed3\u679c NAME ENDPOINTS AGE nginx-healthcheck 10.244.102.14:80,10.244.112.13:80 72s \u81f3\u6b64\uff0c2\u4e2apod nginx-healthcheck \u90fd\u80fd\u6309\u7167\u6211\u4eec\u7684\u671f\u671b\u6b63\u5e38\u5de5\u4f5c\u3002 \u6a21\u62dfreadinessProbe\u9519\u8bef \u00b6 \u8ba9\u6211\u4eec\u901a\u8fc7\u5220\u9664 nginx-healthcheck Pod \u4e2d\u7684 index.html \u6587\u4ef6\u6765\u6a21\u62df\u9519\u8bef\uff0c\u89c2\u5bdf readinessProbe \u7684\u8868\u73b0\u3002 \u9996\u5148\uff0c\u6267\u884c kubectl exec -it -- bash \u547d\u4ee4\u4ee5\u767b\u5f55\u5230 nginx-healthcheck Pod\uff0c\u5e76\u5220\u9664 index.html \u6587\u4ef6\u3002 kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ rm -rf index.html exit \u5728\u6267\u884c\u4e86\u5220\u9664 nginx-healthcheck Pod \u4e2d\u7684 index.html \u6587\u4ef6\u4e4b\u540e\uff0c\u6211\u4eec\u68c0\u67e5\u8be5 Pod \u7684\u72b6\u6001\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-jw887 \u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230 Readiness probe failed \u8fd9\u4e2a\u9519\u8bef\u4e8b\u4ef6\u4fe1\u606f\u3002 ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m8s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-jw887 to cka003 Normal Pulled 2m7s kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m7s kubelet Created container nginx-healthcheck Normal Started 2m7s kubelet Started container nginx-healthcheck Warning Unhealthy 2s (x2 over 7s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 403 \u68c0\u67e5\u53e6\u4e00\u4e2apod\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-nwwjc \u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6ca1\u6709\u53d1\u73b0\u9519\u8bef\u3002 ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 3m46s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-nwwjc to cka002 Normal Pulled 3m45s kubelet Container image \"nginx:latest\" already present on machine Normal Created 3m45s kubelet Created container nginx-healthcheck Normal Started 3m45s kubelet Started container nginx-healthcheck \u73b0\u5728\uff0c\u901a\u8fc7 curl \u547d\u4ee4\u6765\u8bbf\u95ee2\u4e2apod\u7684IP\u5730\u5740\uff0c\u6211\u4eec\u6765\u89c2\u5bdf\u4f1a\u5f97\u5230\u600e\u6837\u7684\u7ed3\u679c\u3002 curl 10 .244.102.14 curl 10 .244.112.13 \u8fd0\u884c\u7ed3\u679c\uff1a curl 10.244.102.14 \u5931\u8d25\uff0c\u9519\u8bef\u4fe1\u606f\u662f 403 Forbidden \u3002 curl 10.244.112.13 \u6210\u529f\u3002 \u6211\u4eec\u73b0\u5728\u6765\u67e5\u8be2Nginx service\u5728\u4e00\u4e2apod\u5931\u8d25\u65f6\u7684\u72b6\u6001\u3002 kubectl describe svc nginx-healthcheck \u5728\u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6211\u4eec\u770b\u5230Endpoint\u90e8\u5206\u4e2d\u53ea\u6709\u4e00\u4e2apod\u7684\u4fe1\u606f\u3002 Name : nginx-healthcheck Namespace : dev Labels : Annotations : Selector : name=nginx-healthcheck Type : NodePort IP Family Policy : SingleStack IP Families : IPv4 IP : 11.244.238.20 IPs : 11.244.238.20 Port : 80/TCP TargetPort : 80/TCP NodePort : 31795/TCP Endpoints : 10.244.112.13:80 Session Affinity : None External Traffic Policy : Cluster Events : \u540c\u6837\u7684\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u68c0\u67e5Endpoint\u7684\u4fe1\u606f\uff0c\u4e5f\u80fd\u53d1\u73b0\u53ea\u6709\u4e00\u4e2apod\u6b63\u5728\u8fd0\u884c\u3002 kubectl get endpoints nginx-healthcheck \u8fd0\u884c\u7ed3\u679c\uff1a NAME ENDPOINTS AGE nginx-healthcheck 10.244.112.13:80 6m5s \u4fee\u590dreadinessProbe\u9519\u8bef \u00b6 \u73b0\u5728\uff0c\u6211\u4eec\u5728pod\u4e2d\u91cd\u65b0\u521b\u5efa index.html \u6587\u4ef6\uff0c\u6765\u4fee\u590d\u9519\u8bef\u3002 kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ cat > index.html << EOF Welcome to nginx!

    Welcome to nginx!

    If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

    For online documentation and support please refer to nginx.org.
    Commercial support is available at nginx.com.

    Thank you for using nginx.

    EOF exit \u73b0\u5728\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u4e24\u4e2aPod\u5df2\u7ecf\u91cd\u65b0\u52a0\u5165\u4e86Endpoint\u5217\u8868\uff0c\u53ef\u4ee5\u63d0\u4f9b\u670d\u52a1\u4e86\u3002 kubectl describe svc nginx-healthcheck kubectl get endpoints nginx-healthcheck \u91cd\u65b0\u901a\u8fc7 curl \u547d\u4ee4\u8bbf\u95ee2\u4e2apod\u7684IP\u5730\u5740\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5b83\u4eec\u90fd\u5df2\u7ecf\u6062\u590d\u5230\u6b63\u5e38\u72b6\u6001\u4e86\u3002 curl 10 .244.102.14 curl 10 .244.112.13 \u518d\u6b21\u9a8c\u8bc1pod\u7684\u72b6\u6001\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-jw887 \u7ed3\u8bba\uff1a \u901a\u8fc7\u5220\u9664 index.html \u6587\u4ef6\uff0cPod \u8fdb\u5165\u4e0d\u5065\u5eb7\u72b6\u6001\u5e76\u4ece\u7aef\u70b9\u5217\u8868\u4e2d\u5220\u9664\u3002 \u53ea\u6709\u4e00\u4e2a\u5065\u5eb7\u7684 Pod \u53ef\u4ee5\u63d0\u4f9b\u6b63\u5e38\u7684\u670d\u52a1\u3002 \u6e05\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete service nginx-healthcheck kubectl delete deployment nginx-healthcheck \u6a21\u62dflivenessProbe\u9519\u8bef \u00b6 \u91cd\u65b0\u521b\u5efadeployment nginx-healthcheck \u548cservice nginx-healthcheck \u3002 Deployment: NAME READY UP-TO-DATE AVAILABLE AGE nginx-healthcheck 0/2 2 0 7s Pods: NAME READY STATUS RESTARTS AGE nginx-healthcheck-79fc55d944-lknp9 1/1 Running 0 96s nginx-healthcheck-79fc55d944-wntmg 1/1 Running 0 96s \u5c06 Nginx \u9ed8\u8ba4\u76d1\u542c\u7aef\u53e3\u4ece 80 \u6539\u4e3a 90 \uff0c\u4ee5\u6a21\u62df livenessProbe \u5931\u8d25\u3002livenessProbe \u901a\u8fc7\u7aef\u53e3 80 \u68c0\u67e5\u751f\u5b58\u72b6\u6001\u3002 kubectl exec -it nginx-healthcheck-79fc55d944-lknp9 -- bash root@nginx-healthcheck-79fc55d944-lknp9:/# cd /etc/nginx/conf.d root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# sed -i 's/80/90/g' default.conf root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# nginx -s reload 2022 /07/24 12 :59:45 [ notice ] 79 #79: signal process started Pod\u73b0\u5728\u8868\u73b0\u4e3a\u5931\u8d25\u72b6\u6001\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-lknp9 \u5728pod\u7684\u4e8b\u4ef6\u4fe1\u606f\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u53d1\u73b0 livenessProbe \u9519\u8bef\u4fe1\u606f\u3002 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 17m default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-lknp9 to cka003 Normal Pulled 2m47s (x2 over 17m) kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m47s (x2 over 17m) kubelet Created container nginx-healthcheck Normal Started 2m47s (x2 over 17m) kubelet Started container nginx-healthcheck Warning Unhealthy 2m47s (x4 over 2m57s) kubelet Readiness probe failed: Get \"http://10.244.102.46:80/\": dial tcp 10.244.102.46:80: connect: connection refused Warning Unhealthy 2m47s (x3 over 2m57s) kubelet Liveness probe failed: dial tcp 10.244.102.46:80: connect: connection refused Normal Killing 2m47s kubelet Container nginx-healthcheck failed liveness probe, will be restarted \u5f53 livenessProbe \u68c0\u6d4b\u5230\u5931\u8d25\u540e\uff0c\u5bb9\u5668\u5c06\u81ea\u52a8\u91cd\u65b0\u542f\u52a8\u3002\u6211\u4eec\u4fee\u6539\u7684 default.conf \u6587\u4ef6\u5c06\u88ab\u9ed8\u8ba4\u6587\u4ef6\u66ff\u6362\uff0c\u5bb9\u5668\u72b6\u6001\u5c06\u6062\u590d\u6b63\u5e38\u3002","title":"\u5065\u5eb7\u68c0\u67e5"},{"location":"k8s/cka_cn/foundamentals/casestudy-health-check/#_1","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa Deployment \u548c Service \u6a21\u62df\u4e00\u4e2a\u9519\u8bef\uff08\u5220\u9664 index.html\uff09 Pod \u5904\u4e8e\u4e0d\u5065\u5eb7\u72b6\u6001\u5e76\u4ece endpoint \u5217\u8868\u4e2d\u5220\u9664 \u4fee\u590d\u9519\u8bef\uff08\u6062\u590d index.html\uff09 Pod \u56de\u5230\u6b63\u5e38\u72b6\u6001\u5e76\u91cd\u65b0\u52a0\u5165 endpoint \u5217\u8868","title":"\u4e3b\u9898\u8ba8\u8bba:\u5065\u5eb7\u68c0\u67e5"},{"location":"k8s/cka_cn/foundamentals/casestudy-health-check/#deployment-service","text":"\u521b\u5efaDeployment nginx-healthcheck \u548cService nginx-healthcheck \u3002 kubectl apply -f - < nginx-healthcheck-79fc55d944-nwwjc 1/1 Running 0 9s 10.244.112.13 cka002 \u901a\u8fc7\u547d\u4ee4 curl \u6765\u8bbf\u95ee\u4e0a\u9762\u8fd0\u884c\u7ed3\u679c\u4e2dpod\u7684IP\u5730\u5740\u3002 curl 10 .244.102.14 curl 10 .244.112.13 \u5982\u679c\u4e0a\u9762\u547d\u4ee4\u6210\u529f\u6267\u884c\uff0c\u5219\u4f1a\u8fd4\u56deNginx\u4e2d index.html \u7684\u5185\u5bb9\u3002 \u83b7\u53d6\u524d\u9762\u521b\u5efa\u7684Service\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl describe svc nginx-healthcheck \u8f93\u51fa\u7ed3\u679c\u5982\u4e0b\u3002\u5728 Endpoints \u90e8\u5206\u6211\u4eec\u53ef\u4ee5\u770b\u52302\u4e2apod\u3002 Name : nginx-healthcheck Namespace : dev Labels : Annotations : Selector : name=nginx-healthcheck Type : NodePort IP Family Policy : SingleStack IP Families : IPv4 IP : 11.244.238.20 IPs : 11.244.238.20 Port : 80/TCP TargetPort : 80/TCP NodePort : 31795/TCP Endpoints : 10.244.102.14:80,10.244.112.13:80 Session Affinity : None External Traffic Policy : Cluster Events : \u83b7\u53d6Endpoints\u7684\u4fe1\u606f\u3002 kubectl get endpoints nginx-healthcheck \u8fd0\u884c\u7ed3\u679c NAME ENDPOINTS AGE nginx-healthcheck 10.244.102.14:80,10.244.112.13:80 72s \u81f3\u6b64\uff0c2\u4e2apod nginx-healthcheck \u90fd\u80fd\u6309\u7167\u6211\u4eec\u7684\u671f\u671b\u6b63\u5e38\u5de5\u4f5c\u3002","title":"\u521b\u5efa Deployment \u548c Service"},{"location":"k8s/cka_cn/foundamentals/casestudy-health-check/#readinessprobe","text":"\u8ba9\u6211\u4eec\u901a\u8fc7\u5220\u9664 nginx-healthcheck Pod \u4e2d\u7684 index.html \u6587\u4ef6\u6765\u6a21\u62df\u9519\u8bef\uff0c\u89c2\u5bdf readinessProbe \u7684\u8868\u73b0\u3002 \u9996\u5148\uff0c\u6267\u884c kubectl exec -it -- bash \u547d\u4ee4\u4ee5\u767b\u5f55\u5230 nginx-healthcheck Pod\uff0c\u5e76\u5220\u9664 index.html \u6587\u4ef6\u3002 kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ rm -rf index.html exit \u5728\u6267\u884c\u4e86\u5220\u9664 nginx-healthcheck Pod \u4e2d\u7684 index.html \u6587\u4ef6\u4e4b\u540e\uff0c\u6211\u4eec\u68c0\u67e5\u8be5 Pod \u7684\u72b6\u6001\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-jw887 \u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230 Readiness probe failed \u8fd9\u4e2a\u9519\u8bef\u4e8b\u4ef6\u4fe1\u606f\u3002 ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m8s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-jw887 to cka003 Normal Pulled 2m7s kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m7s kubelet Created container nginx-healthcheck Normal Started 2m7s kubelet Started container nginx-healthcheck Warning Unhealthy 2s (x2 over 7s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 403 \u68c0\u67e5\u53e6\u4e00\u4e2apod\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-nwwjc \u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6ca1\u6709\u53d1\u73b0\u9519\u8bef\u3002 ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 3m46s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-nwwjc to cka002 Normal Pulled 3m45s kubelet Container image \"nginx:latest\" already present on machine Normal Created 3m45s kubelet Created container nginx-healthcheck Normal Started 3m45s kubelet Started container nginx-healthcheck \u73b0\u5728\uff0c\u901a\u8fc7 curl \u547d\u4ee4\u6765\u8bbf\u95ee2\u4e2apod\u7684IP\u5730\u5740\uff0c\u6211\u4eec\u6765\u89c2\u5bdf\u4f1a\u5f97\u5230\u600e\u6837\u7684\u7ed3\u679c\u3002 curl 10 .244.102.14 curl 10 .244.112.13 \u8fd0\u884c\u7ed3\u679c\uff1a curl 10.244.102.14 \u5931\u8d25\uff0c\u9519\u8bef\u4fe1\u606f\u662f 403 Forbidden \u3002 curl 10.244.112.13 \u6210\u529f\u3002 \u6211\u4eec\u73b0\u5728\u6765\u67e5\u8be2Nginx service\u5728\u4e00\u4e2apod\u5931\u8d25\u65f6\u7684\u72b6\u6001\u3002 kubectl describe svc nginx-healthcheck \u5728\u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\u4e2d\uff0c\u6211\u4eec\u770b\u5230Endpoint\u90e8\u5206\u4e2d\u53ea\u6709\u4e00\u4e2apod\u7684\u4fe1\u606f\u3002 Name : nginx-healthcheck Namespace : dev Labels : Annotations : Selector : name=nginx-healthcheck Type : NodePort IP Family Policy : SingleStack IP Families : IPv4 IP : 11.244.238.20 IPs : 11.244.238.20 Port : 80/TCP TargetPort : 80/TCP NodePort : 31795/TCP Endpoints : 10.244.112.13:80 Session Affinity : None External Traffic Policy : Cluster Events : \u540c\u6837\u7684\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u68c0\u67e5Endpoint\u7684\u4fe1\u606f\uff0c\u4e5f\u80fd\u53d1\u73b0\u53ea\u6709\u4e00\u4e2apod\u6b63\u5728\u8fd0\u884c\u3002 kubectl get endpoints nginx-healthcheck \u8fd0\u884c\u7ed3\u679c\uff1a NAME ENDPOINTS AGE nginx-healthcheck 10.244.112.13:80 6m5s","title":"\u6a21\u62dfreadinessProbe\u9519\u8bef"},{"location":"k8s/cka_cn/foundamentals/casestudy-health-check/#readinessprobe_1","text":"\u73b0\u5728\uff0c\u6211\u4eec\u5728pod\u4e2d\u91cd\u65b0\u521b\u5efa index.html \u6587\u4ef6\uff0c\u6765\u4fee\u590d\u9519\u8bef\u3002 kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ cat > index.html << EOF Welcome to nginx!

    Welcome to nginx!

    If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

    For online documentation and support please refer to nginx.org.
    Commercial support is available at nginx.com.

    Thank you for using nginx.

    EOF exit \u73b0\u5728\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u4e24\u4e2aPod\u5df2\u7ecf\u91cd\u65b0\u52a0\u5165\u4e86Endpoint\u5217\u8868\uff0c\u53ef\u4ee5\u63d0\u4f9b\u670d\u52a1\u4e86\u3002 kubectl describe svc nginx-healthcheck kubectl get endpoints nginx-healthcheck \u91cd\u65b0\u901a\u8fc7 curl \u547d\u4ee4\u8bbf\u95ee2\u4e2apod\u7684IP\u5730\u5740\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5b83\u4eec\u90fd\u5df2\u7ecf\u6062\u590d\u5230\u6b63\u5e38\u72b6\u6001\u4e86\u3002 curl 10 .244.102.14 curl 10 .244.112.13 \u518d\u6b21\u9a8c\u8bc1pod\u7684\u72b6\u6001\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-jw887 \u7ed3\u8bba\uff1a \u901a\u8fc7\u5220\u9664 index.html \u6587\u4ef6\uff0cPod \u8fdb\u5165\u4e0d\u5065\u5eb7\u72b6\u6001\u5e76\u4ece\u7aef\u70b9\u5217\u8868\u4e2d\u5220\u9664\u3002 \u53ea\u6709\u4e00\u4e2a\u5065\u5eb7\u7684 Pod \u53ef\u4ee5\u63d0\u4f9b\u6b63\u5e38\u7684\u670d\u52a1\u3002 \u6e05\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete service nginx-healthcheck kubectl delete deployment nginx-healthcheck","title":"\u4fee\u590dreadinessProbe\u9519\u8bef"},{"location":"k8s/cka_cn/foundamentals/casestudy-health-check/#livenessprobe","text":"\u91cd\u65b0\u521b\u5efadeployment nginx-healthcheck \u548cservice nginx-healthcheck \u3002 Deployment: NAME READY UP-TO-DATE AVAILABLE AGE nginx-healthcheck 0/2 2 0 7s Pods: NAME READY STATUS RESTARTS AGE nginx-healthcheck-79fc55d944-lknp9 1/1 Running 0 96s nginx-healthcheck-79fc55d944-wntmg 1/1 Running 0 96s \u5c06 Nginx \u9ed8\u8ba4\u76d1\u542c\u7aef\u53e3\u4ece 80 \u6539\u4e3a 90 \uff0c\u4ee5\u6a21\u62df livenessProbe \u5931\u8d25\u3002livenessProbe \u901a\u8fc7\u7aef\u53e3 80 \u68c0\u67e5\u751f\u5b58\u72b6\u6001\u3002 kubectl exec -it nginx-healthcheck-79fc55d944-lknp9 -- bash root@nginx-healthcheck-79fc55d944-lknp9:/# cd /etc/nginx/conf.d root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# sed -i 's/80/90/g' default.conf root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# nginx -s reload 2022 /07/24 12 :59:45 [ notice ] 79 #79: signal process started Pod\u73b0\u5728\u8868\u73b0\u4e3a\u5931\u8d25\u72b6\u6001\u3002 kubectl describe pod nginx-healthcheck-79fc55d944-lknp9 \u5728pod\u7684\u4e8b\u4ef6\u4fe1\u606f\u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u53d1\u73b0 livenessProbe \u9519\u8bef\u4fe1\u606f\u3002 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 17m default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-lknp9 to cka003 Normal Pulled 2m47s (x2 over 17m) kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m47s (x2 over 17m) kubelet Created container nginx-healthcheck Normal Started 2m47s (x2 over 17m) kubelet Started container nginx-healthcheck Warning Unhealthy 2m47s (x4 over 2m57s) kubelet Readiness probe failed: Get \"http://10.244.102.46:80/\": dial tcp 10.244.102.46:80: connect: connection refused Warning Unhealthy 2m47s (x3 over 2m57s) kubelet Liveness probe failed: dial tcp 10.244.102.46:80: connect: connection refused Normal Killing 2m47s kubelet Container nginx-healthcheck failed liveness probe, will be restarted \u5f53 livenessProbe \u68c0\u6d4b\u5230\u5931\u8d25\u540e\uff0c\u5bb9\u5668\u5c06\u81ea\u52a8\u91cd\u65b0\u542f\u52a8\u3002\u6211\u4eec\u4fee\u6539\u7684 default.conf \u6587\u4ef6\u5c06\u88ab\u9ed8\u8ba4\u6587\u4ef6\u66ff\u6362\uff0c\u5bb9\u5668\u72b6\u6001\u5c06\u6062\u590d\u6b63\u5e38\u3002","title":"\u6a21\u62dflivenessProbe\u9519\u8bef"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/","text":"\u4e3b\u9898\u8ba8\u8bba:Kubernetes\u8d44\u6e90\u5e38\u89c1\u64cd\u4f5c \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u8282\u70b9\u6807\u7b7e\uff08Node Label\uff09 \u6ce8\u89e3\uff08Annotation\uff09 \u547d\u540d\u7a7a\u95f4\uff08Namespace\uff09 ServiceAccount \u6388\u6743\uff08ServiceAccount Authorization\uff09 \u6388\u6743\u9ed8\u8ba4 ServiceAccount \u8bbf\u95ee API \u90e8\u7f72\uff08Deployment\uff09 \u66b4\u9732\u670d\u52a1\uff08Expose Service\uff09 \u6269\u5c55\u90e8\u7f72\uff08Scale out the Deployment\uff09 \u6eda\u52a8\u5347\u7ea7\uff08Rolling update\uff09 \u56de\u6eda\u5347\u7ea7\uff08Rolling back update\uff09 \u4e8b\u4ef6\uff08Event\uff09 \u65e5\u5fd7\u8bb0\u5f55\uff08Logging\uff09 \u8282\u70b9\u6807\u7b7e\uff08Node Label\uff09 \u00b6 \u6dfb\u52a0/\u4fee\u6539/\u79fb\u51fa\u8282\u70b9\u6807\u7b7e\u3002 # Update node label kubectl label node cka002 node = demonode # Get node info with label info kubectl get node --show-labels # Search node by label kubectl get node -l node = demonode # Remove a lable of node kubectl label node cka002 node- \u6ce8\u89e3\uff08Annotation\uff09 \u00b6 \u521b\u5efadeployment Nginx \u3002 kubectl create deploy nginx --image = nginx:mainline \u83b7\u53d6\u6ce8\u89e3\u4fe1\u606f kubectl describe deployment/nginx \u8fd0\u884c\u7ed3\u679c\uff1a ...... Labels : app=nginx Annotations: deployment.kubernetes.io/revision : 1 Selector : app=nginx ...... \u6dfb\u52a0\u65b0\u7684\u6ce8\u89e3\u4fe1\u606f\u3002 kubectl annotate deployment nginx owner = James.H \u518d\u6b21\u67e5\u8be2\u6ce8\u89e3\u4fe1\u606f\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 ...... Labels : app=nginx Annotations: deployment.kubernetes.io/revision : 1 owner : James.H Selector : app=nginx ...... \u66f4\u65b0/\u8986\u76d6\u6ce8\u89e3\u4fe1\u606f\u3002 kubectl annotate deployment/nginx owner = K8s --overwrite \u518d\u6b21\u67e5\u8be2\u6ce8\u89e3\u4fe1\u606f\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 ...... Annotations : deployment.kubernetes.io/revision : 1 owner : K8s Selector : app=nginx ...... \u79fb\u9664\u6ce8\u89e3\u4fe1\u606f\u3002 kubectl annotate deployment/nginx owner- \u8fd0\u884c\u7ed3\u679c\uff1a ...... Labels : app=nginx Annotations: deployment.kubernetes.io/revision : 1 Selector : app=nginx ...... \u5220\u9664\u4e0a\u9762\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete deployment nginx \u547d\u540d\u7a7a\u95f4\uff08Namespace\uff09 \u00b6 \u67e5\u8be2\u5f53\u524d\u53ef\u7528namespace\u3002 kubectl get namespace \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS AGE default Active 3h45m dev Active 3h11m kube-node-lease Active 3h45m kube-public Active 3h45m kube-system Active 3h45m \u67e5\u8be2\u67d0\u4e2anamespace\u4e0a\u8fd0\u884c\u7684pod\u4fe1\u606f\u3002 kubectl get pod -n kube-system \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE calico-kube-controllers-5c64b68895-jr4nl 1/1 Running 0 3h25m calico-node-dsx76 1/1 Running 0 3h25m calico-node-p5rf2 1/1 Running 0 3h25m calico-node-tr22l 1/1 Running 0 3h25m coredns-6d8c4cb4d-g4jxc 1/1 Running 0 3h45m coredns-6d8c4cb4d-sqcvj 1/1 Running 0 3h45m etcd-cka001 1/1 Running 0 3h45m kube-apiserver-cka001 1/1 Running 0 3h45m kube-controller-manager-cka001 1/1 Running 0 3h45m kube-proxy-5cdbj 1/1 Running 0 3h41m kube-proxy-cm4hc 1/1 Running 0 3h45m kube-proxy-g4w52 1/1 Running 0 3h41m kube-scheduler-cka001 1/1 Running 0 3h45m \u67e5\u8be2\u6240\u6709namespace\u4e0a\u7684pod\u4fe1\u606f\u3002 kubectl get pod --all-namespaces kubectl get pod -A ServiceAccount \u6388\u6743\uff08ServiceAccount Authorization\uff09 \u00b6 \u5728 Kubernetes 1.23 \u53ca\u66f4\u4f4e\u7248\u672c\u4e2d\uff0c\u5f53\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u65f6\uff0cKubernetes \u4f1a\u81ea\u52a8\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a default \u7684 ServiceAccount \u548c\u4e00\u4e2a\u540d\u4e3a default-token-xxxxx \u7684\u4ee4\u724c\u3002 \u800c\u5728 Kubernetes 1.24 \u4e2d\uff0c\u521b\u5efa\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u65f6\u4ec5\u4f1a\u81ea\u52a8\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a default \u7684 ServiceAccount\uff0c\u9700\u8981\u624b\u52a8\u521b\u5efa\u4e0e default ServiceAccount \u76f8\u5173\u8054\u7684\u4ee4\u724c\u3002 \u4ee5\u4e0b\u662f\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a dev \u7684\u65b0\u547d\u540d\u7a7a\u95f4\u7684\u793a\u4f8b\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5728\u547d\u540d\u7a7a\u95f4 dev \u4e2d\u4ec5\u521b\u5efa\u4e86 ServiceAccount\uff1a default \uff0c\u6ca1\u6709\u4e0e ServiceAccount default \u76f8\u5173\u8054\u7684\u4ee4\u724c\uff08secret\uff09\u3002 kubectl create namespace dev kubectl get serviceaccount -n dev kubectl get secrets -n dev \u6709\u4e00\u4e2a\u9ed8\u8ba4\u7684\u96c6\u7fa4\u89d2\u8272 admin \uff0c\u4f46\u662f\u6ca1\u6709\u5c06\u5176\u7ed1\u5b9a\u5230\u4efb\u4f55\u96c6\u7fa4\u89d2\u8272\u7ed1\u5b9a\uff08clusterrole binding\uff09\u4e2d\u3002 kubectl get clusterrole admin kubectl get clusterrolebinding | grep ClusterRole/admin \u89d2\u8272Role\u548c\u89d2\u8272\u7ed1\u5b9aRoleBinding\u662f\u57fa\u4e8e\u547d\u540d\u7a7a\u95f4\u7684\u3002\u5728\u547d\u540d\u7a7a\u95f4 dev \u4e2d\uff0c\u6ca1\u6709\u89d2\u8272\u548c\u89d2\u8272\u7ed1\u5b9a\u3002 kubectl get role -n dev kubectl get rolebinding -n dev \u5728 Kubernetes \u96c6\u7fa4\u4e2d\uff0cSecret \u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u7528\u4e8e\u5b58\u50a8\u654f\u611f\u4fe1\u606f\uff0c\u5982\u7528\u6237\u540d\u3001\u5bc6\u7801\u548c\u4ee4\u724c\u7b49\u3002Secret \u7684\u76ee\u6807\u662f\u5bf9\u51ed\u636e\u8fdb\u884c\u7f16\u7801\u6216\u54c8\u5e0c\u5316\u3002\u8fd9\u4e9b\u51ed\u636e\u53ef\u4ee5\u5728\u5404\u79cd Pod \u5b9a\u4e49\u6587\u4ef6\u4e2d\u91cd\u590d\u4f7f\u7528\u3002 kubernetes.io/service-account-token \u7c7b\u578b\u7684 Secret \u7528\u4e8e\u5b58\u50a8\u6807\u8bc6\u670d\u52a1\u8d26\u6237\u7684\u4ee4\u724c\u3002\u4f7f\u7528\u6b64\u7c7b\u578b\u7684 Secret \u65f6\uff0c\u9700\u8981\u786e\u4fdd kubernetes.io/service-account.name \u6ce8\u91ca\u8bbe\u7f6e\u4e3a\u73b0\u6709\u670d\u52a1\u8d26\u6237\u540d\u79f0\u3002 \u8ba9\u6211\u4eec\u5728 dev \u547d\u540d\u7a7a\u95f4\u4e2d\u4e3a ServiceAccount default \u521b\u5efa\u4e00\u4e2a\u4ee4\u724c\u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Secret metadata: name: default-token-dev namespace: dev annotations: kubernetes.io/service-account.name: \"default\" type: kubernetes.io/service-account-token EOF \u73b0\u5728\u5728 dev \u547d\u540d\u7a7a\u95f4\u4e2d\u521b\u5efa\u4e86 ServiceAccount default \u548c Secret\uff08\u4ee4\u724c\uff09 default-token-dev \u3002 kubectl get serviceaccount -n dev kubectl get secrets -n dev \u83b7\u53d6\u9ed8\u8ba4 Service Account \u7684 token\uff0c\u5e76\u8d4b\u503c\u7ed9\u73af\u5883\u53d8\u91cf $TOKEN \u3002 TOKEN = $( kubectl -n dev describe secret $( kubectl -n dev get secrets | grep default | cut -f1 -d ' ' ) | grep -E '^token' | cut -f2 -d ':' | tr -d ' ' ) echo $TOKEN \u83b7\u53d6 API Service \u5730\u5740\uff0c\u5e76\u8d4b\u503c\u7ed9\u73af\u5883\u53d8\u91cf $APISERVER \u3002 APISERVER = $( kubectl config view | grep https | cut -f 2 - -d \":\" | tr -d \" \" ) echo $APISERVER \u901a\u8fc7 API Server \u4ee5 JSON \u683c\u5f0f\u83b7\u53d6\u547d\u540d\u7a7a\u95f4 dev \u4e2d\u7684 Pod \u8d44\u6e90\u3002 curl $APISERVER /api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN \" --insecure \u6211\u4eec\u5c06\u6536\u5230\u201c403 forbidden\u201d\u7684\u9519\u8bef\u6d88\u606f\u3002ServiceAccount default \u6ca1\u6709\u8bbf\u95ee\u540d\u79f0\u7a7a\u95f4 dev \u4e2d\u7684Pod\u7684\u6388\u6743\u3002 \u8ba9\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a rolebinding-admin \u7684RoleBinding\uff0c\u5c06\u96c6\u7fa4\u89d2\u8272 admin \u7ed1\u5b9a\u5230\u540d\u79f0\u7a7a\u95f4 dev \u4e2d\u7684ServiceAccount default \u3002 \u56e0\u6b64\uff0cServiceAccount default \u88ab\u6388\u4e88\u5728\u540d\u79f0\u7a7a\u95f4 dev \u4e2d\u7684\u7ba1\u7406\u5458\u6388\u6743\u3002 # Usage: kubectl create rolebinding --clusterrole = --serviceaccount = : --namespace = # Crate rolebinding: kubectl create rolebinding rolebinding-admin --clusterrole = admin --serviceaccount = dev:default --namespace = dev \u6267\u884c\u547d\u4ee4 kubectl get rolebinding -n dev \uff0c\u5f97\u5230\u7c7b\u4f3c\u5982\u4e0b\u7684\u7ed3\u679c\u3002 NAME ROLE AGE rolebinding-admin ClusterRole/admin 10s \u518d\u6b21\u901a\u8fc7 API Server \u4ee5 JSON \u683c\u5f0f\u83b7\u53d6\u547d\u540d\u7a7a\u95f4 dev \u4e2d\u7684 Pod \u8d44\u6e90\uff0c\u6210\u529f\u3002 curl $APISERVER /api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN \" --insecure \u5220\u9664\u4e0a\u9762\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete namespace dev \u90e8\u7f72\uff08Deployment\uff09 \u00b6 \u521b\u5efa\u4e00\u4e2a Ubuntu Pod \u4ee5\u8fdb\u884c\u64cd\u4f5c\uff0c\u5e76\u9644\u52a0\u5230\u8fd0\u884c\u4e2d\u7684 Pod\u3002 kubectl create -f - << EOF apiVersion: v1 kind: Pod metadata: name: ubuntu labels: app: ubuntu spec: containers: - name: ubuntu image: ubuntu:latest command: [\"/bin/sleep\", \"3650d\"] imagePullPolicy: IfNotPresent restartPolicy: Always EOF kubectl exec --stdin --tty ubuntu -- /bin/bash \u521b\u5efa\u4e00\u4e2a Deployment\uff0c\u9009\u9879 --image \u6307\u5b9a\u4e86\u4e00\u4e2a\u955c\u50cf\uff0c\u9009\u9879 --port \u6307\u5b9a\u4e86\u5916\u90e8\u8bbf\u95ee\u7684\u7aef\u53e3\u3002 \u5728\u521b\u5efa Deployment \u7684\u540c\u65f6\u4e5f\u4f1a\u521b\u5efa\u4e00\u4e2a Pod\u3002 kubectl create deployment myapp --image = docker.io/jocatalin/kubernetes-bootcamp:v1 --replicas = 1 --port = 8080 \u67e5\u8be2deployment\u7684\u72b6\u6001\u3002 kubectl get deployment myapp -o wide \u8f93\u51fa\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR myapp 1/1 1 1 79s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp \u67e5\u8be2deployment\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl describe deployment myapp \u8fd0\u884c\u7ed3\u679c\uff1a Name: myapp Namespace: dev CreationTimestamp: Sat, 23 Jul 2022 14:36:43 +0800 Labels: app=myapp Annotations: deployment.kubernetes.io/revision: 1 Selector: app=myapp Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=myapp Containers: kubernetes-bootcamp: Image: docker.io/jocatalin/kubernetes-bootcamp:v1 Port: 8080/TCP Host Port: 0/TCP Environment: Mounts: Volumes: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: NewReplicaSet: myapp-b5d775f5d (1/1 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 95s deployment-controller Scaled up replica set myapp-b5d775f5d to 1 \u66b4\u9732\u670d\u52a1\uff08Expose Service\uff09 \u00b6 \u83b7\u53d6\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u548cdeployment\u7684\u4fe1\u606f\u3002 kubectl get deployment myapp -o wide kubectl get pod -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-b5d775f5d-cx8dx 1/1 Running 0 2m34s 10.244.102.7 cka003 \u6267\u884c\u547d\u4ee4 curl 10.244.102.7:8080 \uff0c\u4ee5\u53d1\u9001HTTP\u8bf7\u6c42\u5230pod\u7684\u7aef\u53e3\uff0c\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 \u8981\u4f7f Pod \u53ef\u4ee5\u4ece\u5916\u90e8\u8bbf\u95ee\uff0c\u9700\u8981\u5c06\u7aef\u53e3 8080 \u66b4\u9732\u7ed9\u8282\u70b9\u7aef\u53e3\uff08NodePort\uff09\u3002\u8fd9\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u76f8\u5173\u7684 Service\u3002 kubectl expose deployment myapp --type = NodePort --port = 8080 \u6267\u884c\u547d\u4ee4 kubectl get svc myapp -o wide \uff0c\u83b7\u53d6service myapp \u7684\u8be6\u7ec6\u4fe1\u606f\u3002 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR myapp NodePort 11.244.74.3 8080:30514/TCP 7s app=myapp \u6267\u884c\u547d\u4ee4 curl 11.244.74.3:8080 \uff0c\u4ee5\u53d1\u9001HTTP\u8bf7\u6c42\u5230service\u7684\u7aef\u53e3\uff0c\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-cx8dx | v=1 \u83b7\u53d6service\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get svc myapp -o yaml kubectl describe svc myapp \u6267\u884c kubectl get endpoints myapp -o wide \u547d\u4ee4\u4ee5\u83b7\u53d6\u76f8\u5173\u7684 myapp \u7aef\u70b9\uff08endpoint\uff09\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 NAME ENDPOINTS AGE myapp 10.244.102.7:8080 43s \u63d0\u793a\uff1a Endpoint\uff08\u7aef\u70b9\uff09\u662f\u4e00\u4e2aKubernetes\u4e2d\u7684\u5bf9\u8c61\uff0c\u7528\u4e8e\u5b58\u50a8\u53ef\u4ee5\u88ab\u670d\u52a1\u8bbf\u95ee\u7684Pod\u7684\u7f51\u7edc\u5730\u5740\u548c\u7aef\u53e3\u4fe1\u606f\u3002 \u5f53Service\u521b\u5efa\u65f6\uff0cKubernetes\u4f1a\u81ea\u52a8\u521b\u5efa\u548c\u66f4\u65b0\u76f8\u5e94\u7684Endpoint\u3002 Endpoint\u662f\u7531kube-proxy\u81ea\u52a8\u521b\u5efa\u548c\u7ef4\u62a4\u7684\uff0c\u5e76\u6839\u636e\u9009\u62e9\u5668\u5339\u914d\u5bf9\u5e94\u7684Service\u548cPod\u3002 \u80fd\u6210\u529f\u7684\u53d1\u9001HTTP\u8bf7\u6c42\u5230service\u548c\u8282\u70b9\uff0c\u8bf4\u660epod\u7684\u7aef\u53e3 8080 \u88ab\u6b63\u786e\u7684\u6620\u5c04\u5230\u8282\u70b9\u7684\u7aef\u53e3 32566 \u3002 \u6267\u884c\u547d\u4ee4curl :30514\uff0c\u53d1\u9001HTTP\u8bf7\u6c42\u5230\u8282\u70b9 cka003 \u4e0a\u5bf9\u5e94\u7684\u7aef\u53e3\u3002 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 \u767b\u5f55\u8fdb\u5165Ubuntu pod\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u53d1\u9001HTTP\u8bf7\u6c42\u5230 myapp \u6240\u6620\u5c04\u7684service\u3001pod\u548c\u8282\u70b9\u7684\u7aef\u53e3\u3002 kubectl exec --stdin --tty ubuntu -- /bin/bash curl 10 .244.102.7:8080 curl 11 .244.74.3:8080 curl :30514 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v = 1 \u6269\u5bb9\u90e8\u7f72\uff08Scale out the Deployment\uff09 \u00b6 Scale out by replicaset. We set three replicasets to scale out deployment myapp . The number of deployment myapp is now three. \u901a\u8fc7\u526f\u672c\u96c6replicaset\u8fdb\u884c\u6269\u5c55\u3002\u6211\u4eec\u901a\u8fc7\u6307\u5b9a\u526f\u672c\u96c6\u7684\u65b9\u5f0f\uff0c\u5bf9deployment myapp \u8fdb\u884c\u6269\u5c55\u90e8\u7f72\uff0c\u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0cdeployment myapp \u7684\u526f\u672c\u6570\u662f\u4e09\u4e2a\u3002 kubectl scale deployment myapp --replicas = 3 \u67e5\u8be2deployment\u7684\u4fe1\u606f\u3002 kubectl get deployment myapp \u67e5\u8be2replicaset\u7684\u4fe1\u606f kubectl get replicaset \u6eda\u52a8\u5347\u7ea7\uff08Rolling update\uff09 \u00b6 \u547d\u4ee4\u7528\u6cd5\uff1a kubectl set image (-f \u6587\u4ef6\u540d | \u7c7b\u578b \u540d\u79f0) \u5bb9\u5668\u540d\u79f0_1=\u5bb9\u5668\u955c\u50cf_1 ... \u5bb9\u5668\u540d\u79f0_N=\u5bb9\u5668\u955c\u50cf_N \u3002 \u4f7f\u7528\u547d\u4ee4 kubectl get deployment \uff0c\u6211\u4eec\u53ef\u4ee5\u83b7\u53d6deployment myapp \u548c\u76f8\u5173\u5bb9\u5668 kubernetes-bootcamp \u3002 kubectl get deployment myapp -o wide \u4f7f\u7528\u547d\u4ee4 kubectl set image \u6765\u66f4\u65b0\u591a\u4e2a\u7248\u672c\u7684\u955c\u50cf\uff0c\u5e76\u4f7f\u7528\u9009\u9879 --record \u5c06\u66f4\u6539\u8bb0\u5f55\u5728\u90e8\u7f72\u7684\u6ce8\u91ca\u4e2d\u3002 kubectl set image deployment/myapp kubernetes-bootcamp = docker.io/jocatalin/kubernetes-bootcamp:v2 --record \u67e5\u8be2\u5f53\u524dreplicas\u7684\u72b6\u6001\u3002 kubectl get replicaset -o wide -l app = myapp \u8f93\u51fa\u7ed3\u679c\u5982\u4e0b\uff0cpod\u6b63\u4ee5\u65b0\u7684\u526f\u672c\u96c6replicas\u6570\u91cf\u8fd0\u884c\u3002 NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR myapp-5dbd68cc99 1 1 0 8s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v2 app=myapp,pod-template-hash=5dbd68cc99 myapp-b5d775f5d 3 3 3 14m kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp,pod-template-hash=b5d775f5d \u6211\u4eec\u53ef\u4ee5\u5728\u5bf9\u5e94\u7684yaml\u6587\u4ef6\u4e2d metadata.annotations \u90e8\u5206\u83b7\u53d6\u53d8\u66f4\u5386\u53f2\u8bb0\u5f55\u3002 kubectl get deployment myapp -o yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion : apps/v1 kind : Deployment metadata : annotations : deployment.kubernetes.io/revision : \"2\" kubernetes.io/change-cause : kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true ...... \u6211\u4eec\u4e5f\u53ef\u4ee5\u4f7f\u7528\u547d\u4ee4 kubectl rollout history \u83b7\u53d6\u66f4\u65b0\u5386\u53f2\u8bb0\u5f55\uff0c\u5e76\u4f7f\u7528\u7279\u5b9a\u4fee\u8ba2\u7248\u672c\u53f7 --revision= \u663e\u793a\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl rollout history deployment/myapp \u8fd0\u884c\u7ed3\u679c\uff1a deployment.apps/myapp REVISION CHANGE-CAUSE 1 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true \u83b7\u53d6\u7279\u5b9a\u7248\u672c\u56de\u6eda\u5386\u53f2\u8bb0\u5f55\u3002 kubectl rollout history deployment/myapp --revision = 2 \u6267\u884c\u547d\u4ee4 kubectl rollout undo \u53ef\u4ee5\u56de\u6eda\u5230\u4e0a\u4e00\u4e2a\u7248\u672c\uff0c\u6216\u4f7f\u7528\u9009\u9879 --to-revision= \u56de\u6eda\u5230\u6307\u5b9a\u7684\u7248\u672c\u3002 kubectl rollout undo deployment/myapp --to-revision = 1 \u7248\u672c 1 \u73b0\u5728\u5df2\u7ecf\u88ab\u66ff\u6362\u6210\u7248\u672c 3 \u4e86\u3002 kubectl rollout history deployment/myapp \u8fd0\u884c\u7ed3\u679c\uff1a deployment.apps/myapp REVISION CHANGE-CAUSE 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true 3 \u4e8b\u4ef6\uff08Event\uff09 \u00b6 \u83b7\u53d6\u6307\u5b9apod\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl describe pod myapp-b5d775f5d-jlx6g \u8f93\u51fa\u7ed3\u679c\uff1a ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 54s default-scheduler Successfully assigned dev/myapp-b5d775f5d-jlx6g to cka003 Normal Pulled 53s kubelet Container image \"docker.io/jocatalin/kubernetes-bootcamp:v1\" already present on machine Normal Created 53s kubelet Created container kubernetes-bootcamp Normal Started 53s kubelet Started container kubernetes-bootcamp \u67e5\u8be2\u96c6\u7fa4\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl get event \u65e5\u5fd7\u8bb0\u5f55\uff08Logging\uff09 \u00b6 \u67e5\u8be2pod\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl logs -f kubectl logs -f -c \u4f8b\u5982\uff1a kubectl logs -f myapp-b5d775f5d-jlx6g \u8fd0\u884c\u7ed3\u679c\uff1a Kubernetes Bootcamp App Started At: 2022-07-23T06:54:18.532Z | Running On: myapp-b5d775f5d-jlx6g \u67e5\u8be2K8s\u4e0d\u540c\u7ec4\u4ef6\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl logs kube-apiserver-cka001 -n kube-system kubectl logs kube-controller-manager-cka001 -n kube-system kubectl logs kube-scheduler-cka001 -n kube-system kubectl logs etcd-cka001 -n kube-system systemctl status kubelet journalctl -fu kubelet kubectl logs kube-proxy-5cdbj -n kube-system \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete service myapp kubectl delete deployment myapp","title":"Kubernetes\u8d44\u6e90\u5e38\u89c1\u64cd\u4f5c"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#kubernetes","text":"\u6f14\u793a\u573a\u666f\uff1a \u8282\u70b9\u6807\u7b7e\uff08Node Label\uff09 \u6ce8\u89e3\uff08Annotation\uff09 \u547d\u540d\u7a7a\u95f4\uff08Namespace\uff09 ServiceAccount \u6388\u6743\uff08ServiceAccount Authorization\uff09 \u6388\u6743\u9ed8\u8ba4 ServiceAccount \u8bbf\u95ee API \u90e8\u7f72\uff08Deployment\uff09 \u66b4\u9732\u670d\u52a1\uff08Expose Service\uff09 \u6269\u5c55\u90e8\u7f72\uff08Scale out the Deployment\uff09 \u6eda\u52a8\u5347\u7ea7\uff08Rolling update\uff09 \u56de\u6eda\u5347\u7ea7\uff08Rolling back update\uff09 \u4e8b\u4ef6\uff08Event\uff09 \u65e5\u5fd7\u8bb0\u5f55\uff08Logging\uff09","title":"\u4e3b\u9898\u8ba8\u8bba:Kubernetes\u8d44\u6e90\u5e38\u89c1\u64cd\u4f5c"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#node-label","text":"\u6dfb\u52a0/\u4fee\u6539/\u79fb\u51fa\u8282\u70b9\u6807\u7b7e\u3002 # Update node label kubectl label node cka002 node = demonode # Get node info with label info kubectl get node --show-labels # Search node by label kubectl get node -l node = demonode # Remove a lable of node kubectl label node cka002 node-","title":"\u8282\u70b9\u6807\u7b7e\uff08Node Label\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#annotation","text":"\u521b\u5efadeployment Nginx \u3002 kubectl create deploy nginx --image = nginx:mainline \u83b7\u53d6\u6ce8\u89e3\u4fe1\u606f kubectl describe deployment/nginx \u8fd0\u884c\u7ed3\u679c\uff1a ...... Labels : app=nginx Annotations: deployment.kubernetes.io/revision : 1 Selector : app=nginx ...... \u6dfb\u52a0\u65b0\u7684\u6ce8\u89e3\u4fe1\u606f\u3002 kubectl annotate deployment nginx owner = James.H \u518d\u6b21\u67e5\u8be2\u6ce8\u89e3\u4fe1\u606f\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 ...... Labels : app=nginx Annotations: deployment.kubernetes.io/revision : 1 owner : James.H Selector : app=nginx ...... \u66f4\u65b0/\u8986\u76d6\u6ce8\u89e3\u4fe1\u606f\u3002 kubectl annotate deployment/nginx owner = K8s --overwrite \u518d\u6b21\u67e5\u8be2\u6ce8\u89e3\u4fe1\u606f\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 ...... Annotations : deployment.kubernetes.io/revision : 1 owner : K8s Selector : app=nginx ...... \u79fb\u9664\u6ce8\u89e3\u4fe1\u606f\u3002 kubectl annotate deployment/nginx owner- \u8fd0\u884c\u7ed3\u679c\uff1a ...... Labels : app=nginx Annotations: deployment.kubernetes.io/revision : 1 Selector : app=nginx ...... \u5220\u9664\u4e0a\u9762\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete deployment nginx","title":"\u6ce8\u89e3\uff08Annotation\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#namespace","text":"\u67e5\u8be2\u5f53\u524d\u53ef\u7528namespace\u3002 kubectl get namespace \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS AGE default Active 3h45m dev Active 3h11m kube-node-lease Active 3h45m kube-public Active 3h45m kube-system Active 3h45m \u67e5\u8be2\u67d0\u4e2anamespace\u4e0a\u8fd0\u884c\u7684pod\u4fe1\u606f\u3002 kubectl get pod -n kube-system \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE calico-kube-controllers-5c64b68895-jr4nl 1/1 Running 0 3h25m calico-node-dsx76 1/1 Running 0 3h25m calico-node-p5rf2 1/1 Running 0 3h25m calico-node-tr22l 1/1 Running 0 3h25m coredns-6d8c4cb4d-g4jxc 1/1 Running 0 3h45m coredns-6d8c4cb4d-sqcvj 1/1 Running 0 3h45m etcd-cka001 1/1 Running 0 3h45m kube-apiserver-cka001 1/1 Running 0 3h45m kube-controller-manager-cka001 1/1 Running 0 3h45m kube-proxy-5cdbj 1/1 Running 0 3h41m kube-proxy-cm4hc 1/1 Running 0 3h45m kube-proxy-g4w52 1/1 Running 0 3h41m kube-scheduler-cka001 1/1 Running 0 3h45m \u67e5\u8be2\u6240\u6709namespace\u4e0a\u7684pod\u4fe1\u606f\u3002 kubectl get pod --all-namespaces kubectl get pod -A","title":"\u547d\u540d\u7a7a\u95f4\uff08Namespace\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#serviceaccount-serviceaccount-authorization","text":"\u5728 Kubernetes 1.23 \u53ca\u66f4\u4f4e\u7248\u672c\u4e2d\uff0c\u5f53\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u65f6\uff0cKubernetes \u4f1a\u81ea\u52a8\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a default \u7684 ServiceAccount \u548c\u4e00\u4e2a\u540d\u4e3a default-token-xxxxx \u7684\u4ee4\u724c\u3002 \u800c\u5728 Kubernetes 1.24 \u4e2d\uff0c\u521b\u5efa\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u65f6\u4ec5\u4f1a\u81ea\u52a8\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a default \u7684 ServiceAccount\uff0c\u9700\u8981\u624b\u52a8\u521b\u5efa\u4e0e default ServiceAccount \u76f8\u5173\u8054\u7684\u4ee4\u724c\u3002 \u4ee5\u4e0b\u662f\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a dev \u7684\u65b0\u547d\u540d\u7a7a\u95f4\u7684\u793a\u4f8b\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5728\u547d\u540d\u7a7a\u95f4 dev \u4e2d\u4ec5\u521b\u5efa\u4e86 ServiceAccount\uff1a default \uff0c\u6ca1\u6709\u4e0e ServiceAccount default \u76f8\u5173\u8054\u7684\u4ee4\u724c\uff08secret\uff09\u3002 kubectl create namespace dev kubectl get serviceaccount -n dev kubectl get secrets -n dev \u6709\u4e00\u4e2a\u9ed8\u8ba4\u7684\u96c6\u7fa4\u89d2\u8272 admin \uff0c\u4f46\u662f\u6ca1\u6709\u5c06\u5176\u7ed1\u5b9a\u5230\u4efb\u4f55\u96c6\u7fa4\u89d2\u8272\u7ed1\u5b9a\uff08clusterrole binding\uff09\u4e2d\u3002 kubectl get clusterrole admin kubectl get clusterrolebinding | grep ClusterRole/admin \u89d2\u8272Role\u548c\u89d2\u8272\u7ed1\u5b9aRoleBinding\u662f\u57fa\u4e8e\u547d\u540d\u7a7a\u95f4\u7684\u3002\u5728\u547d\u540d\u7a7a\u95f4 dev \u4e2d\uff0c\u6ca1\u6709\u89d2\u8272\u548c\u89d2\u8272\u7ed1\u5b9a\u3002 kubectl get role -n dev kubectl get rolebinding -n dev \u5728 Kubernetes \u96c6\u7fa4\u4e2d\uff0cSecret \u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u7528\u4e8e\u5b58\u50a8\u654f\u611f\u4fe1\u606f\uff0c\u5982\u7528\u6237\u540d\u3001\u5bc6\u7801\u548c\u4ee4\u724c\u7b49\u3002Secret \u7684\u76ee\u6807\u662f\u5bf9\u51ed\u636e\u8fdb\u884c\u7f16\u7801\u6216\u54c8\u5e0c\u5316\u3002\u8fd9\u4e9b\u51ed\u636e\u53ef\u4ee5\u5728\u5404\u79cd Pod \u5b9a\u4e49\u6587\u4ef6\u4e2d\u91cd\u590d\u4f7f\u7528\u3002 kubernetes.io/service-account-token \u7c7b\u578b\u7684 Secret \u7528\u4e8e\u5b58\u50a8\u6807\u8bc6\u670d\u52a1\u8d26\u6237\u7684\u4ee4\u724c\u3002\u4f7f\u7528\u6b64\u7c7b\u578b\u7684 Secret \u65f6\uff0c\u9700\u8981\u786e\u4fdd kubernetes.io/service-account.name \u6ce8\u91ca\u8bbe\u7f6e\u4e3a\u73b0\u6709\u670d\u52a1\u8d26\u6237\u540d\u79f0\u3002 \u8ba9\u6211\u4eec\u5728 dev \u547d\u540d\u7a7a\u95f4\u4e2d\u4e3a ServiceAccount default \u521b\u5efa\u4e00\u4e2a\u4ee4\u724c\u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Secret metadata: name: default-token-dev namespace: dev annotations: kubernetes.io/service-account.name: \"default\" type: kubernetes.io/service-account-token EOF \u73b0\u5728\u5728 dev \u547d\u540d\u7a7a\u95f4\u4e2d\u521b\u5efa\u4e86 ServiceAccount default \u548c Secret\uff08\u4ee4\u724c\uff09 default-token-dev \u3002 kubectl get serviceaccount -n dev kubectl get secrets -n dev \u83b7\u53d6\u9ed8\u8ba4 Service Account \u7684 token\uff0c\u5e76\u8d4b\u503c\u7ed9\u73af\u5883\u53d8\u91cf $TOKEN \u3002 TOKEN = $( kubectl -n dev describe secret $( kubectl -n dev get secrets | grep default | cut -f1 -d ' ' ) | grep -E '^token' | cut -f2 -d ':' | tr -d ' ' ) echo $TOKEN \u83b7\u53d6 API Service \u5730\u5740\uff0c\u5e76\u8d4b\u503c\u7ed9\u73af\u5883\u53d8\u91cf $APISERVER \u3002 APISERVER = $( kubectl config view | grep https | cut -f 2 - -d \":\" | tr -d \" \" ) echo $APISERVER \u901a\u8fc7 API Server \u4ee5 JSON \u683c\u5f0f\u83b7\u53d6\u547d\u540d\u7a7a\u95f4 dev \u4e2d\u7684 Pod \u8d44\u6e90\u3002 curl $APISERVER /api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN \" --insecure \u6211\u4eec\u5c06\u6536\u5230\u201c403 forbidden\u201d\u7684\u9519\u8bef\u6d88\u606f\u3002ServiceAccount default \u6ca1\u6709\u8bbf\u95ee\u540d\u79f0\u7a7a\u95f4 dev \u4e2d\u7684Pod\u7684\u6388\u6743\u3002 \u8ba9\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a rolebinding-admin \u7684RoleBinding\uff0c\u5c06\u96c6\u7fa4\u89d2\u8272 admin \u7ed1\u5b9a\u5230\u540d\u79f0\u7a7a\u95f4 dev \u4e2d\u7684ServiceAccount default \u3002 \u56e0\u6b64\uff0cServiceAccount default \u88ab\u6388\u4e88\u5728\u540d\u79f0\u7a7a\u95f4 dev \u4e2d\u7684\u7ba1\u7406\u5458\u6388\u6743\u3002 # Usage: kubectl create rolebinding --clusterrole = --serviceaccount = : --namespace = # Crate rolebinding: kubectl create rolebinding rolebinding-admin --clusterrole = admin --serviceaccount = dev:default --namespace = dev \u6267\u884c\u547d\u4ee4 kubectl get rolebinding -n dev \uff0c\u5f97\u5230\u7c7b\u4f3c\u5982\u4e0b\u7684\u7ed3\u679c\u3002 NAME ROLE AGE rolebinding-admin ClusterRole/admin 10s \u518d\u6b21\u901a\u8fc7 API Server \u4ee5 JSON \u683c\u5f0f\u83b7\u53d6\u547d\u540d\u7a7a\u95f4 dev \u4e2d\u7684 Pod \u8d44\u6e90\uff0c\u6210\u529f\u3002 curl $APISERVER /api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN \" --insecure \u5220\u9664\u4e0a\u9762\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete namespace dev","title":"ServiceAccount \u6388\u6743\uff08ServiceAccount Authorization\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#deployment","text":"\u521b\u5efa\u4e00\u4e2a Ubuntu Pod \u4ee5\u8fdb\u884c\u64cd\u4f5c\uff0c\u5e76\u9644\u52a0\u5230\u8fd0\u884c\u4e2d\u7684 Pod\u3002 kubectl create -f - << EOF apiVersion: v1 kind: Pod metadata: name: ubuntu labels: app: ubuntu spec: containers: - name: ubuntu image: ubuntu:latest command: [\"/bin/sleep\", \"3650d\"] imagePullPolicy: IfNotPresent restartPolicy: Always EOF kubectl exec --stdin --tty ubuntu -- /bin/bash \u521b\u5efa\u4e00\u4e2a Deployment\uff0c\u9009\u9879 --image \u6307\u5b9a\u4e86\u4e00\u4e2a\u955c\u50cf\uff0c\u9009\u9879 --port \u6307\u5b9a\u4e86\u5916\u90e8\u8bbf\u95ee\u7684\u7aef\u53e3\u3002 \u5728\u521b\u5efa Deployment \u7684\u540c\u65f6\u4e5f\u4f1a\u521b\u5efa\u4e00\u4e2a Pod\u3002 kubectl create deployment myapp --image = docker.io/jocatalin/kubernetes-bootcamp:v1 --replicas = 1 --port = 8080 \u67e5\u8be2deployment\u7684\u72b6\u6001\u3002 kubectl get deployment myapp -o wide \u8f93\u51fa\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR myapp 1/1 1 1 79s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp \u67e5\u8be2deployment\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl describe deployment myapp \u8fd0\u884c\u7ed3\u679c\uff1a Name: myapp Namespace: dev CreationTimestamp: Sat, 23 Jul 2022 14:36:43 +0800 Labels: app=myapp Annotations: deployment.kubernetes.io/revision: 1 Selector: app=myapp Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=myapp Containers: kubernetes-bootcamp: Image: docker.io/jocatalin/kubernetes-bootcamp:v1 Port: 8080/TCP Host Port: 0/TCP Environment: Mounts: Volumes: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: NewReplicaSet: myapp-b5d775f5d (1/1 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 95s deployment-controller Scaled up replica set myapp-b5d775f5d to 1","title":"\u90e8\u7f72\uff08Deployment\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#expose-service","text":"\u83b7\u53d6\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u548cdeployment\u7684\u4fe1\u606f\u3002 kubectl get deployment myapp -o wide kubectl get pod -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-b5d775f5d-cx8dx 1/1 Running 0 2m34s 10.244.102.7 cka003 \u6267\u884c\u547d\u4ee4 curl 10.244.102.7:8080 \uff0c\u4ee5\u53d1\u9001HTTP\u8bf7\u6c42\u5230pod\u7684\u7aef\u53e3\uff0c\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 \u8981\u4f7f Pod \u53ef\u4ee5\u4ece\u5916\u90e8\u8bbf\u95ee\uff0c\u9700\u8981\u5c06\u7aef\u53e3 8080 \u66b4\u9732\u7ed9\u8282\u70b9\u7aef\u53e3\uff08NodePort\uff09\u3002\u8fd9\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u76f8\u5173\u7684 Service\u3002 kubectl expose deployment myapp --type = NodePort --port = 8080 \u6267\u884c\u547d\u4ee4 kubectl get svc myapp -o wide \uff0c\u83b7\u53d6service myapp \u7684\u8be6\u7ec6\u4fe1\u606f\u3002 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR myapp NodePort 11.244.74.3 8080:30514/TCP 7s app=myapp \u6267\u884c\u547d\u4ee4 curl 11.244.74.3:8080 \uff0c\u4ee5\u53d1\u9001HTTP\u8bf7\u6c42\u5230service\u7684\u7aef\u53e3\uff0c\u5f97\u5230\u5982\u4e0b\u7ed3\u679c\u3002 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-cx8dx | v=1 \u83b7\u53d6service\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get svc myapp -o yaml kubectl describe svc myapp \u6267\u884c kubectl get endpoints myapp -o wide \u547d\u4ee4\u4ee5\u83b7\u53d6\u76f8\u5173\u7684 myapp \u7aef\u70b9\uff08endpoint\uff09\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 NAME ENDPOINTS AGE myapp 10.244.102.7:8080 43s \u63d0\u793a\uff1a Endpoint\uff08\u7aef\u70b9\uff09\u662f\u4e00\u4e2aKubernetes\u4e2d\u7684\u5bf9\u8c61\uff0c\u7528\u4e8e\u5b58\u50a8\u53ef\u4ee5\u88ab\u670d\u52a1\u8bbf\u95ee\u7684Pod\u7684\u7f51\u7edc\u5730\u5740\u548c\u7aef\u53e3\u4fe1\u606f\u3002 \u5f53Service\u521b\u5efa\u65f6\uff0cKubernetes\u4f1a\u81ea\u52a8\u521b\u5efa\u548c\u66f4\u65b0\u76f8\u5e94\u7684Endpoint\u3002 Endpoint\u662f\u7531kube-proxy\u81ea\u52a8\u521b\u5efa\u548c\u7ef4\u62a4\u7684\uff0c\u5e76\u6839\u636e\u9009\u62e9\u5668\u5339\u914d\u5bf9\u5e94\u7684Service\u548cPod\u3002 \u80fd\u6210\u529f\u7684\u53d1\u9001HTTP\u8bf7\u6c42\u5230service\u548c\u8282\u70b9\uff0c\u8bf4\u660epod\u7684\u7aef\u53e3 8080 \u88ab\u6b63\u786e\u7684\u6620\u5c04\u5230\u8282\u70b9\u7684\u7aef\u53e3 32566 \u3002 \u6267\u884c\u547d\u4ee4curl :30514\uff0c\u53d1\u9001HTTP\u8bf7\u6c42\u5230\u8282\u70b9 cka003 \u4e0a\u5bf9\u5e94\u7684\u7aef\u53e3\u3002 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 \u767b\u5f55\u8fdb\u5165Ubuntu pod\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u53d1\u9001HTTP\u8bf7\u6c42\u5230 myapp \u6240\u6620\u5c04\u7684service\u3001pod\u548c\u8282\u70b9\u7684\u7aef\u53e3\u3002 kubectl exec --stdin --tty ubuntu -- /bin/bash curl 10 .244.102.7:8080 curl 11 .244.74.3:8080 curl :30514 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v = 1","title":"\u66b4\u9732\u670d\u52a1\uff08Expose Service\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#scale-out-the-deployment","text":"Scale out by replicaset. We set three replicasets to scale out deployment myapp . The number of deployment myapp is now three. \u901a\u8fc7\u526f\u672c\u96c6replicaset\u8fdb\u884c\u6269\u5c55\u3002\u6211\u4eec\u901a\u8fc7\u6307\u5b9a\u526f\u672c\u96c6\u7684\u65b9\u5f0f\uff0c\u5bf9deployment myapp \u8fdb\u884c\u6269\u5c55\u90e8\u7f72\uff0c\u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0cdeployment myapp \u7684\u526f\u672c\u6570\u662f\u4e09\u4e2a\u3002 kubectl scale deployment myapp --replicas = 3 \u67e5\u8be2deployment\u7684\u4fe1\u606f\u3002 kubectl get deployment myapp \u67e5\u8be2replicaset\u7684\u4fe1\u606f kubectl get replicaset","title":"\u6269\u5bb9\u90e8\u7f72\uff08Scale out the Deployment\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#rolling-update","text":"\u547d\u4ee4\u7528\u6cd5\uff1a kubectl set image (-f \u6587\u4ef6\u540d | \u7c7b\u578b \u540d\u79f0) \u5bb9\u5668\u540d\u79f0_1=\u5bb9\u5668\u955c\u50cf_1 ... \u5bb9\u5668\u540d\u79f0_N=\u5bb9\u5668\u955c\u50cf_N \u3002 \u4f7f\u7528\u547d\u4ee4 kubectl get deployment \uff0c\u6211\u4eec\u53ef\u4ee5\u83b7\u53d6deployment myapp \u548c\u76f8\u5173\u5bb9\u5668 kubernetes-bootcamp \u3002 kubectl get deployment myapp -o wide \u4f7f\u7528\u547d\u4ee4 kubectl set image \u6765\u66f4\u65b0\u591a\u4e2a\u7248\u672c\u7684\u955c\u50cf\uff0c\u5e76\u4f7f\u7528\u9009\u9879 --record \u5c06\u66f4\u6539\u8bb0\u5f55\u5728\u90e8\u7f72\u7684\u6ce8\u91ca\u4e2d\u3002 kubectl set image deployment/myapp kubernetes-bootcamp = docker.io/jocatalin/kubernetes-bootcamp:v2 --record \u67e5\u8be2\u5f53\u524dreplicas\u7684\u72b6\u6001\u3002 kubectl get replicaset -o wide -l app = myapp \u8f93\u51fa\u7ed3\u679c\u5982\u4e0b\uff0cpod\u6b63\u4ee5\u65b0\u7684\u526f\u672c\u96c6replicas\u6570\u91cf\u8fd0\u884c\u3002 NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR myapp-5dbd68cc99 1 1 0 8s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v2 app=myapp,pod-template-hash=5dbd68cc99 myapp-b5d775f5d 3 3 3 14m kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp,pod-template-hash=b5d775f5d \u6211\u4eec\u53ef\u4ee5\u5728\u5bf9\u5e94\u7684yaml\u6587\u4ef6\u4e2d metadata.annotations \u90e8\u5206\u83b7\u53d6\u53d8\u66f4\u5386\u53f2\u8bb0\u5f55\u3002 kubectl get deployment myapp -o yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion : apps/v1 kind : Deployment metadata : annotations : deployment.kubernetes.io/revision : \"2\" kubernetes.io/change-cause : kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true ...... \u6211\u4eec\u4e5f\u53ef\u4ee5\u4f7f\u7528\u547d\u4ee4 kubectl rollout history \u83b7\u53d6\u66f4\u65b0\u5386\u53f2\u8bb0\u5f55\uff0c\u5e76\u4f7f\u7528\u7279\u5b9a\u4fee\u8ba2\u7248\u672c\u53f7 --revision= \u663e\u793a\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl rollout history deployment/myapp \u8fd0\u884c\u7ed3\u679c\uff1a deployment.apps/myapp REVISION CHANGE-CAUSE 1 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true \u83b7\u53d6\u7279\u5b9a\u7248\u672c\u56de\u6eda\u5386\u53f2\u8bb0\u5f55\u3002 kubectl rollout history deployment/myapp --revision = 2 \u6267\u884c\u547d\u4ee4 kubectl rollout undo \u53ef\u4ee5\u56de\u6eda\u5230\u4e0a\u4e00\u4e2a\u7248\u672c\uff0c\u6216\u4f7f\u7528\u9009\u9879 --to-revision= \u56de\u6eda\u5230\u6307\u5b9a\u7684\u7248\u672c\u3002 kubectl rollout undo deployment/myapp --to-revision = 1 \u7248\u672c 1 \u73b0\u5728\u5df2\u7ecf\u88ab\u66ff\u6362\u6210\u7248\u672c 3 \u4e86\u3002 kubectl rollout history deployment/myapp \u8fd0\u884c\u7ed3\u679c\uff1a deployment.apps/myapp REVISION CHANGE-CAUSE 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true 3 ","title":"\u6eda\u52a8\u5347\u7ea7\uff08Rolling update\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#event","text":"\u83b7\u53d6\u6307\u5b9apod\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl describe pod myapp-b5d775f5d-jlx6g \u8f93\u51fa\u7ed3\u679c\uff1a ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 54s default-scheduler Successfully assigned dev/myapp-b5d775f5d-jlx6g to cka003 Normal Pulled 53s kubelet Container image \"docker.io/jocatalin/kubernetes-bootcamp:v1\" already present on machine Normal Created 53s kubelet Created container kubernetes-bootcamp Normal Started 53s kubelet Started container kubernetes-bootcamp \u67e5\u8be2\u96c6\u7fa4\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl get event","title":"\u4e8b\u4ef6\uff08Event\uff09"},{"location":"k8s/cka_cn/foundamentals/casestudy-operation-resources/#logging","text":"\u67e5\u8be2pod\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl logs -f kubectl logs -f -c \u4f8b\u5982\uff1a kubectl logs -f myapp-b5d775f5d-jlx6g \u8fd0\u884c\u7ed3\u679c\uff1a Kubernetes Bootcamp App Started At: 2022-07-23T06:54:18.532Z | Running On: myapp-b5d775f5d-jlx6g \u67e5\u8be2K8s\u4e0d\u540c\u7ec4\u4ef6\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl logs kube-apiserver-cka001 -n kube-system kubectl logs kube-controller-manager-cka001 -n kube-system kubectl logs kube-scheduler-cka001 -n kube-system kubectl logs etcd-cka001 -n kube-system systemctl status kubelet journalctl -fu kubelet kubectl logs kube-proxy-5cdbj -n kube-system \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete service myapp kubectl delete deployment myapp","title":"\u65e5\u5fd7\u8bb0\u5f55\uff08Logging\uff09"},{"location":"k8s/cka_cn/foundamentals/clustermgt/","text":"CKA\u81ea\u5b66\u7b14\u8bb024:Cluster Management \u00b6 \u6f14\u793a\u573a\u666f\uff1a etcd Backup and Restore \u5b89\u88c5 etcdctl \u5728\u5907\u4efd\u4e4b\u524d\u521b\u5efa Deployment \u5907\u4efd etcd \u5728\u5907\u4efd\u4e4b\u540e\u521b\u5efa Deployment \u505c\u6b62\u670d\u52a1 \u505c\u6b62 etcd \u6062\u590d etcd \u542f\u52a8\u670d\u52a1 \u9a8c\u8bc1 etcd \u5907\u4efd\u548c\u6062\u590d \u00b6 \u5b89\u88c5 etcdctl \u00b6 \u4e0b\u8f7d etcd \u5b89\u88c5\u5305\u3002 wget https://github.com/etcd-io/etcd/releases/download/v3.5.3/etcd-v3.5.3-linux-amd64.tar.gz \u89e3\u538b etcd \u5b89\u88c5\u5305\uff0c\u5e76\u8d4b\u4e88\u6267\u884c\u6743\u9650\u3002 tar -zxvf etcd-v3.5.3-linux-amd64.tar.gz cp etcd-v3.5.3-linux-amd64/etcdctl /usr/local/bin/ sudo chmod u+x /usr/local/bin/etcdctl \u9a8c\u8bc1\uff1a etcdctl --help \u521b\u5efa\u4e00\u4e2adeployment\uff08\u5907\u4efd\u524d\uff09 \u00b6 \u5907\u4efd\u524d\u521b\u5efa\u4e00\u4e2adeployment\u3002 kubectl create deployment app-before-backup --image = nginx \u5907\u4efd etcd \u00b6 \u8bf4\u660e\uff1a \u662f\u63a7\u5236\u5e73\u9762\u8282\u70b9\u7684\u5b9e\u9645IP\u5730\u5740\u3002 --endpoints \uff1a\u6307\u5b9a etcd \u5907\u4efd\u7684\u4fdd\u5b58\u4f4d\u7f6e\uff0c2379 \u662f etcd \u7684\u7aef\u53e3\u53f7\u3002 --cert \uff1a\u6307\u5b9a etcd \u8bc1\u4e66\u7684\u4f4d\u7f6e\uff0c\u8bc1\u4e66\u662f\u7531 kubeadm \u751f\u6210\u5e76\u4fdd\u5b58\u5728 /etc/kubernetes/pki/etcd/ \u76ee\u5f55\u4e0b\u7684\u3002 --key \uff1a\u6307\u5b9a etcd \u8bc1\u4e66\u7684\u79c1\u94a5\u7684\u4f4d\u7f6e\uff0c\u8bc1\u4e66\u662f\u7531 kubeadm \u751f\u6210\u5e76\u4fdd\u5b58\u5728 /etc/kubernetes/pki/etcd/ \u76ee\u5f55\u4e0b\u7684\u3002 --cacert \uff1a\u6307\u5b9a etcd \u8bc1\u4e66\u7684 CA \u7684\u4f4d\u7f6e\uff0c\u8bc1\u4e66\u662f\u7531 kubeadm \u751f\u6210\u5e76\u4fdd\u5b58\u5728 /etc/kubernetes/pki/etcd/ \u76ee\u5f55\u4e0b\u7684\u3002 etcdctl \\ --endpoints = https://:2379 \\ --cert = /etc/kubernetes/pki/etcd/server.crt \\ --key = /etc/kubernetes/pki/etcd/server.key \\ --cacert = /etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot- $( date + \"%Y%m%d%H%M%S\" ) .db \u6216\u8005 etcdctl \\ --endpoints = https://:2379 \\ --cert = /etc/kubernetes/pki/etcd/server.crt \\ --key = /etc/kubernetes/pki/etcd/server.key \\ --cacert = /etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot- $( date + \"%Y%m%d%H%M%S\" ) .db Output: {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.328+0800\",\"caller\":\"snapshot/v3_snapshot.go:65\",\"msg\":\"created temporary db file\",\"path\":\"snapshot-20220724185121.db.part\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:211\",\"msg\":\"opened snapshot stream; downloading\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"caller\":\"snapshot/v3_snapshot.go:73\",\"msg\":\"fetching snapshot\",\"endpoint\":\"https://:2379\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.415+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:219\",\"msg\":\"completed snapshot read; closing\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:88\",\"msg\":\"fetched snapshot\",\"endpoint\":\"https://:2379\",\"size\":\"3.6 MB\",\"took\":\"now\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:97\",\"msg\":\"saved\",\"path\":\"snapshot-20220724185121.db\"} Snapshot saved at snapshot-20220724185121.db \u6267\u884c\u547d\u4ee4 ls -al \u5728\u5f53\u524d\u76ee\u5f55\u4e2d\u8bfb\u53d6\u6211\u4eec\u521a\u521a\u521b\u5efa\u7684\u5907\u4efd\u6587\u4ef6\u3002 -rw------- 1 root root 3616800 Jul 24 18 :51 snapshot-20220724185121.db \u521b\u5efa\u4e00\u4e2adeployment\uff08\u5907\u4efd\u540e\uff09 \u00b6 \u5907\u4efd\u540e\uff0c\u6211\u4eec\u521b\u5efa\u53e6\u5916\u4e00\u4e2adeployment\u3002 kubectl create deployment app-after-backup --image = nginx \u5220\u9664\u5907\u4efd\u524d\u6211\u4eec\u521b\u5efa\u7684\u90a3\u4e2adeployment\u3002 kubectl delete deployment app-before-backup \u68c0\u67e5deployment\u7684\u72b6\u6001\u3002 kubectl get deploy \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE app-after-backup 1/1 1 1 108s \u505c\u6b62Services \u00b6 \u5220\u9664 etcd \u7684\u76ee\u5f55\u3002 mv /var/lib/etcd/ /var/lib/etcd.bak \u505c\u6b62 kubelet \u3002 systemctl stop kubelet \u505c\u6b62 kube-apiserver \u3002 nerdctl -n k8s.io ps -a | grep apiserver \u8fd0\u884c\u7ed3\u679c\uff1a 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001 \u505c\u6b62\u90a3\u4e9b\u4ecd\u65e7\u5904\u4e8e up \u72b6\u6001\u7684\u5bb9\u5668\u3002 nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0c5e69118f1b nerdctl -n k8s.io stop 638bb602c310 \u76f4\u81f3\u6ca1\u6709\u5904\u4e8e up \u72b6\u6001\u7684 kube-apiserver \u3002 nerdctl -n k8s.io ps -a | grep apiserver \u8fd0\u884c\u7ed3\u679c\uff1a 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001 \u505c\u6b62etcd \u00b6 nerdctl -n k8s.io ps -a | grep etcd \u8fd0\u884c\u7ed3\u679c\uff1a 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/etcd-cka001 \u505c\u6b62\u90a3\u4e9b\u4ecd\u65e7\u5904\u4e8e up \u72b6\u6001\u7684\u5bb9\u5668\u3002 nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0965b195f41a nerdctl -n k8s.io stop 9e1bea9f25d1 \u76f4\u81f3\u6ca1\u6709\u5904\u4e8e up \u72b6\u6001\u7684 kube-apiserver \u3002 nerdctl -n k8s.io ps -a | grep etcd \u8fd0\u884c\u7ed3\u679c\uff1a 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001 \u6062\u590d etcd \u00b6 \u5728\u63a7\u5236\u5e73\u9762\u8282\u70b9\u4e0a\u6267\u884c\u6062\u590d\u64cd\u4f5c\uff0c\u4f7f\u7528\u5b9e\u9645\u7684\u5907\u4efd\u6587\u4ef6\uff0c\u8fd9\u91cc\u662f\u6587\u4ef6 snapshot-20220724185121.db \u3002 etcdctl snapshot restore snapshot-20220724185121.db \\ --endpoints = :2379 \\ --cert = /etc/kubernetes/pki/etcd/server.crt \\ --key = /etc/kubernetes/pki/etcd/server.key \\ --cacert = /etc/kubernetes/pki/etcd/ca.crt \\ --data-dir = /var/lib/etcd \u8fd0\u884c\u7ed3\u679c\uff1a Deprecated: Use `etcdutl snapshot restore` instead. 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:248 restoring snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\", \"stack\": \"go.etcd.io/etcd/etcdutl/v3/snapshot.(*v3Manager).Restore\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/snapshot/v3_snapshot.go:254\\ngo.etcd.io/etcd/etcdutl/v3/etcdutl.SnapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/etcdutl/snapshot_command.go:147\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3/command.snapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/command/snapshot_command.go:129\\ngithub.com/spf13/cobra.(*Command).execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856\\ngithub.com/spf13/cobra.(*Command).ExecuteC\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960\\ngithub.com/spf13/cobra.(*Command).Execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:897\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.Start\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:107\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.MustStart\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:111\\nmain.main\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/main.go:59\\nruntime.main\\n\\t/go/gos/go1.16.15/src/runtime/proc.go:225\"} 2022-07-24T18:57:49+08:00 info membership/store.go:141 Trimming membership information from the backend... 2022-07-24T18:57:49+08:00 info membership/cluster.go:421 added member {\"cluster-id\": \"cdf818194e3a8c32\", \"local-member-id\": \"0\", \"added-peer-id\": \"8e9e05c52164694d\", \"added-peer-peer-urls\": [\"http://localhost:2380\"]} 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:269 restored snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\"} \u68c0\u67e5\u88ab\u5220\u9664\u7684 etcd \u76ee\u5f55\u662f\u5426\u5df2\u7ecf\u4ece\u5907\u4efd\u4e2d\u6062\u590d\u4e86\u3002 tree /var/lib/etcd \u8fd0\u884c\u7ed3\u679c\uff1a /var/lib/etcd \u2514\u2500\u2500 member \u251c\u2500\u2500 snap \u2502 \u251c\u2500\u2500 0000000000000001-0000000000000001.snap \u2502 \u2514\u2500\u2500 db \u2514\u2500\u2500 wal \u2514\u2500\u2500 0000000000000000-0000000000000000.wal \u542f\u52a8\u670d\u52a1Services \u00b6 \u542f\u52a8 kubelet \u3002\u670d\u52a1 kube-apiserver \u548c etcd \u4e5f\u4f1a\u7ee7 kubelet \u542f\u52a8\u540e\u88ab\u81ea\u52a8\u542f\u52a8\u3002 systemctl start kubelet \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u786e\u8ba4\u6240\u6709\u670d\u52a1\u90fd\u5df2\u7ecf\u542f\u52a8\u548c\u6b63\u5e38\u8fd0\u884c\u3002 systemctl status kubelet.service nerdctl -n k8s.io ps -a | grep etcd nerdctl -n k8s.io ps -a | grep apiserver \u67e5\u770b\u5f53\u524d etcd \u7684\u72b6\u6001\u3002 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 3b8f37c87782 registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 6 seconds ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001 fbbbb628a945 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 6 seconds ago Up k8s://kube-system/etcd-cka001 \u67e5\u770b\u5f53\u524d apiserver \u7684\u72b6\u6001\u3002 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 281cf4c6670d registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 14 seconds ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 5ed8295d92da registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 15 seconds ago Up k8s://kube-system/kube-apiserver-cka001 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001 \u9a8c\u8bc1 \u00b6 \u68c0\u67e5\u96c6\u7fa4\u7684\u72b6\u6001\uff0c\u67e5\u770b\u662f\u5426pod app-before-backup \u5b58\u5728\u3002 kubectl get deploy \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE app-before-backup 1/1 1 1 11m \u96c6\u7fa4\u5347\u7ea7 \u00b6 \u6f14\u793a\u573a\u666f\uff1a\u96c6\u7fa4\u5347\u7ea7 \u9a71\u9010\u63a7\u5236\u5e73\u9762\u8282\u70b9 \u68c0\u67e5\u5f53\u524d\u53ef\u7528\u7684 kubeadm \u7248\u672c \u5c06 kubeadm \u5347\u7ea7\u5230\u65b0\u7248\u672c \u68c0\u67e5\u5347\u7ea7\u8ba1\u5212 \u5e94\u7528\u5347\u7ea7\u8ba1\u5212\u4ee5\u5347\u7ea7\u5230\u65b0\u7248\u672c \u5347\u7ea7 kubelet \u548c kubectl \u542f\u7528\u63a7\u5236\u5e73\u9762\u8282\u70b9\u8c03\u5ea6 \u9a71\u9010\u5de5\u4f5c\u8282\u70b9 \u5347\u7ea7 kubeadm \u548c kubelet \u542f\u7528\u5de5\u4f5c\u8282\u70b9\u8c03\u5ea6 \u53c2\u8003\uff1a kubeadm\u5347\u7ea7 \u5347\u7ea7\u63a7\u5236\u5e73\u9762 \u00b6 \u63a7\u5236\u5e73\u9762\u51c6\u5907 \u00b6 \u9a71\u9010\u63a7\u5236\u5e73\u9762\u8282\u70b9\u3002 kubectl drain --ignore-daemonsets \u8fd9\u91cc\u662f\uff1a kubectl drain cka001 --ignore-daemonsets \u8fd0\u884c\u7ed3\u679c\uff1a node/cka001 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-dsx76, kube-system/kube-proxy-cm4hc evicting pod kube-system/calico-kube-controllers-5c64b68895-jr4nl evicting pod kube-system/coredns-6d8c4cb4d-g4jxc evicting pod kube-system/coredns-6d8c4cb4d-sqcvj pod/calico-kube-controllers-5c64b68895-jr4nl evicted pod/coredns-6d8c4cb4d-g4jxc evicted pod/coredns-6d8c4cb4d-sqcvj evicted node/cka001 drained \u63a7\u5236\u5e73\u9762\u8282\u70b9\u73b0\u5728\u5904\u4e8e SchedulingDisabled \u72b6\u6001\u3002 kubectl get node -owide \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 \u67e5\u8be2\u5f53\u524d kubeadm \u53ef\u7528\u7248\u672c\u3002 apt policy kubeadm \u8f93\u51fa\u7ed3\u679c\uff1a kubeadm: Installed: 1.24.0-00 Candidate: 1.24.3-00 Version table: 1.24.3-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.1-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages *** 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 100 /var/lib/dpkg/status 1.23.7-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages ...... \u5347\u7ea7 kubeadm \u5230 Candidate: 1.24.2-00 \u7248\u672c\u3002 sudo apt-get -y install kubeadm = 1 .24.2-00 --allow-downgrades \u67e5\u8be2\u5347\u7ea7\u8ba1\u5212\u3002 kubeadm upgrade plan \u8f93\u51fa\u7c7b\u4f3c\u4e0b\u9762\u7684\u5347\u7ea7\u8ba1\u5212\u3002 [upgrade/config] Making sure the configuration is correct: [upgrade/config] Reading configuration from the cluster... [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [preflight] Running pre-flight checks. [upgrade] Running cluster health checks [upgrade] Fetching available versions to upgrade to [upgrade/versions] Cluster version: v1.24.0 [upgrade/versions] kubeadm version: v1.24.2 I0724 19:05:00.111855 1142460 version.go:255] remote version is much newer: v1.24.3; falling back to: stable-1.23 [upgrade/versions] Target version: v1.24.2 [upgrade/versions] Latest version in the v1.23 series: v1.24.2 Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply': COMPONENT CURRENT TARGET kubelet 3 x v1.24.0 v1.24.2 Upgrade to the latest version in the v1.23 series: COMPONENT CURRENT TARGET kube-apiserver v1.24.0 v1.24.2 kube-controller-manager v1.24.0 v1.24.2 kube-scheduler v1.24.0 v1.24.2 kube-proxy v1.24.0 v1.24.2 CoreDNS v1.8.6 v1.8.6 etcd 3.5.1-0 3.5.1-0 You can now apply the upgrade by executing the following command: kubeadm upgrade apply v1.24.2 _____________________________________________________________________ The table below shows the current state of component configs as understood by this version of kubeadm. Configs that have a \"yes\" mark in the \"MANUAL UPGRADE REQUIRED\" column require manual config upgrade or resetting to kubeadm defaults before a successful upgrade can be performed. The version to manually upgrade to is denoted in the \"PREFERRED VERSION\" column. API GROUP CURRENT VERSION PREFERRED VERSION MANUAL UPGRADE REQUIRED kubeproxy.config.k8s.io v1alpha1 v1alpha1 no kubelet.config.k8s.io v1beta1 v1beta1 no _____________________________________________________________________ \u63a7\u5236\u5e73\u9762\u5347\u7ea7 \u00b6 \u53c2\u8003\u524d\u9762\u7684\u5347\u7ea7\u8ba1\u5212\uff0c\u6211\u4eec\u5347\u7ea7\u5230 v1.24.2 \u7248\u672c\u3002 kubeadm upgrade apply v1.24.2 \u901a\u8fc7\u9009\u9879 --etcd-upgrade=false \uff0c\u6211\u4eec\u628a etcd \u6392\u9664\u51fa\u5f53\u524d\u5347\u7ea7\u8303\u56f4\u3002 kubeadm upgrade apply v1.24.2 --etcd-upgrade = false \u6536\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u5219\u4ee3\u8868\u4e0a\u9762\u7684\u5347\u7ea7\u547d\u4ee4\u6210\u529f\u4e86\u3002 [upgrade/successful] SUCCESS! Your cluster was upgraded to \"v1.24.2\". Enjoy! [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so. \u5347\u7ea7 kubelet \u548c kubectl \u3002 sudo apt-get -y install kubelet = 1 .24.2-00 kubectl = 1 .24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet \u67e5\u8be2\u8282\u70b9\u5f53\u524d\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0 After verify that each node is in Ready status, enable node scheduling. \u5728\u786e\u8ba4\u6240\u6709\u8282\u70b9\u90fd\u5904\u4e8eReady\u72b6\u6001\uff0c\u5219\u6fc0\u6d3bscheduling\u3002 kubectl uncordon \u8fd9\u91cc\u662f\uff1a kubectl uncordon cka001 \u8f93\u51fa\u7ed3\u679c\uff1a node/cka001 uncordoned \u518d\u6b21\u68c0\u67e5\u8282\u70b9\u72b6\u6001\uff0c\u786e\u4fdd\u6240\u6709\u8282\u70b9\u90fd\u5904\u4e8eReady\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0 \u5347\u7ea7\u5de5\u4f5c\u8282\u70b9 \u00b6 \u5de5\u4f5c\u8282\u70b9\u51c6\u5907 \u00b6 \u767b\u5f55\u8282\u70b9 cka001 \u3002 \u9a71\u9010 Worker \u8282\u70b9\uff0c\u9700\u8981\u663e\u5f0f\u6307\u5b9a\u662f\u5426\u5220\u9664\u672c\u5730\u5b58\u50a8\u3002 kubectl drain --ignore-daemonsets --force kubectl drain --ignore-daemonsets --delete-emptydir-data --force \u5982\u679c\u9047\u5230\u5173\u4e8e emptydir \u4f9d\u8d56\u7684\u9519\u8bef\uff0c\u5219\u6267\u884c\u7b2c\u4e8c\u4e2a\u547d\u4ee4\u3002 kubectl drain cka002 --ignore-daemonsets --force kubectl drain cka002 --ignore-daemonsets --delete-emptydir-data --force \u8f93\u51fa\u7ed3\u679c\uff1a node/cka002 cordoned WARNING: deleting Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet: dev/ubuntu; ignoring DaemonSet-managed Pods: kube-system/calico-node-p5rf2, kube-system/kube-proxy-zvs68 evicting pod ns-netpol/pod-netpol-5b67b6b496-2cgnw evicting pod dev/ubuntu evicting pod dev/app-before-backup-66dc9d5cb-6xc8c evicting pod dev/nfs-client-provisioner-86d7fb78b6-2f5dx evicting pod dev/pod-netpol-2-77478d77ff-l6rzm evicting pod ingress-nginx/ingress-nginx-admission-patch-nk9fv evicting pod ingress-nginx/ingress-nginx-admission-create-lgtdj evicting pod kube-system/coredns-6d8c4cb4d-l4kx4 pod/ingress-nginx-admission-create-lgtdj evicted pod/ingress-nginx-admission-patch-nk9fv evicted pod/nfs-client-provisioner-86d7fb78b6-2f5dx evicted pod/app-before-backup-66dc9d5cb-6xc8c evicted pod/coredns-6d8c4cb4d-l4kx4 evicted pod/pod-netpol-5b67b6b496-2cgnw evicted pod/pod-netpol-2-77478d77ff-l6rzm evicted pod/ubuntu evicted node/cka002 drained \u5de5\u4f5c\u8282\u70b9\u5347\u7ea7 \u00b6 \u767b\u5f55\u8282\u70b9 cka002 \u3002 \u4e0b\u8f7d kubeadm \u7684 v1.24.2 \u7248\u672c\u3002 sudo apt-get -y install kubeadm = 1 .24.2-00 --allow-downgrades \u5347\u7ea7 kubeadm \u3002 sudo kubeadm upgrade node \u5347\u7ea7 kubelet \u3002 sudo apt-get -y install kubelet = 1 .24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet \u786e\u8ba4\u6240\u6709\u8282\u70b9\u90fd\u5904\u4e8eReady\u72b6\u6001\uff0c\u5219\u6fc0\u6d3bscheduling\u3002 kubectl uncordon \u8fd9\u91cc\u662f\uff1a kubectl uncordon cka002 \u5de5\u4f5c\u8282\u70b9\u9a8c\u8bc1 \u00b6 \u67e5\u8be2\u8282\u70b9\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.0 \u5728\u8282\u70b9 cka003 \u4e0a\u91cd\u590d\u4e0a\u9762\u7684\u6b65\u9aa4\u3002 \u767b\u5f55\u8282\u70b9 cka003 \u3002\u5982\u679c\u9047\u5230\u5173\u4e8e emptydir \u4f9d\u8d56\u7684\u9519\u8bef\uff0c\u5219\u6267\u884c\u7b2c\u4e8c\u4e2a\u547d\u4ee4\u3002 kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --force kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --delete-emptydir-data --force \u767b\u5f55\u8282\u70b9 cka003 \uff0c\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u3002 sudo apt-get -y install kubeadm = 1 .24.2-00 --allow-downgrades sudo kubeadm upgrade node sudo apt-get -y install kubelet = 1 .24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet kubectl get node kubectl uncordon cka003 \u67e5\u8be2\u8282\u70b9\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.2 \u603b\u7ed3 \u00b6 \u5728\u63a7\u5236\u9762\u677f\u4e0a\u7684\u6267\u884c\u6b65\u9aa4\uff1a kubectl get node -owide kubectl drain cka001 --ignore-daemonsets kubectl get node -owide apt policy kubeadm apt-get -y install kubeadm = 1 .24.0-00 --allow-downgrades kubeadm upgrade plan kubeadm upgrade apply v1.24.0 # kubeadm upgrade apply v1.24.0 --etcd-upgrade=false apt-get -y install kubelet = 1 .24.0-00 kubectl = 1 .24.0-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl get node kubectl uncordon cka001 \u5728\u5de5\u4f5c\u8282\u70b9\u4e0a\u7684\u6267\u884c\u6b65\u9aa4\uff1a \u5728\u63a7\u5236\u9762\u677f\u4e0a\uff1a kubectl drain cka002 --ignore-daemonsets \u5728\u5de5\u4f5c\u8282\u70b9\u4e0a\uff1a apt-get -y install kubeadm = 1 .24.1-00 --allow-downgrades kubeadm upgrade node apt-get -y install kubelet = 1 .24.1-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl uncordon cka002 \u5728\u5176\u4ed6\u5de5\u4f5c\u8282\u70b9\u4e0a\u91cd\u590d\u4e0a\u9762\u7684\u6b65\u9aa4\u3002","title":"Cluster Management"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#cka24cluster-management","text":"\u6f14\u793a\u573a\u666f\uff1a etcd Backup and Restore \u5b89\u88c5 etcdctl \u5728\u5907\u4efd\u4e4b\u524d\u521b\u5efa Deployment \u5907\u4efd etcd \u5728\u5907\u4efd\u4e4b\u540e\u521b\u5efa Deployment \u505c\u6b62\u670d\u52a1 \u505c\u6b62 etcd \u6062\u590d etcd \u542f\u52a8\u670d\u52a1 \u9a8c\u8bc1","title":"CKA\u81ea\u5b66\u7b14\u8bb024:Cluster Management"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#etcd","text":"","title":"etcd\u5907\u4efd\u548c\u6062\u590d"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#etcdctl","text":"\u4e0b\u8f7d etcd \u5b89\u88c5\u5305\u3002 wget https://github.com/etcd-io/etcd/releases/download/v3.5.3/etcd-v3.5.3-linux-amd64.tar.gz \u89e3\u538b etcd \u5b89\u88c5\u5305\uff0c\u5e76\u8d4b\u4e88\u6267\u884c\u6743\u9650\u3002 tar -zxvf etcd-v3.5.3-linux-amd64.tar.gz cp etcd-v3.5.3-linux-amd64/etcdctl /usr/local/bin/ sudo chmod u+x /usr/local/bin/etcdctl \u9a8c\u8bc1\uff1a etcdctl --help","title":"\u5b89\u88c5etcdctl"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#deployment","text":"\u5907\u4efd\u524d\u521b\u5efa\u4e00\u4e2adeployment\u3002 kubectl create deployment app-before-backup --image = nginx","title":"\u521b\u5efa\u4e00\u4e2adeployment\uff08\u5907\u4efd\u524d\uff09"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#etcd_1","text":"\u8bf4\u660e\uff1a \u662f\u63a7\u5236\u5e73\u9762\u8282\u70b9\u7684\u5b9e\u9645IP\u5730\u5740\u3002 --endpoints \uff1a\u6307\u5b9a etcd \u5907\u4efd\u7684\u4fdd\u5b58\u4f4d\u7f6e\uff0c2379 \u662f etcd \u7684\u7aef\u53e3\u53f7\u3002 --cert \uff1a\u6307\u5b9a etcd \u8bc1\u4e66\u7684\u4f4d\u7f6e\uff0c\u8bc1\u4e66\u662f\u7531 kubeadm \u751f\u6210\u5e76\u4fdd\u5b58\u5728 /etc/kubernetes/pki/etcd/ \u76ee\u5f55\u4e0b\u7684\u3002 --key \uff1a\u6307\u5b9a etcd \u8bc1\u4e66\u7684\u79c1\u94a5\u7684\u4f4d\u7f6e\uff0c\u8bc1\u4e66\u662f\u7531 kubeadm \u751f\u6210\u5e76\u4fdd\u5b58\u5728 /etc/kubernetes/pki/etcd/ \u76ee\u5f55\u4e0b\u7684\u3002 --cacert \uff1a\u6307\u5b9a etcd \u8bc1\u4e66\u7684 CA \u7684\u4f4d\u7f6e\uff0c\u8bc1\u4e66\u662f\u7531 kubeadm \u751f\u6210\u5e76\u4fdd\u5b58\u5728 /etc/kubernetes/pki/etcd/ \u76ee\u5f55\u4e0b\u7684\u3002 etcdctl \\ --endpoints = https://:2379 \\ --cert = /etc/kubernetes/pki/etcd/server.crt \\ --key = /etc/kubernetes/pki/etcd/server.key \\ --cacert = /etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot- $( date + \"%Y%m%d%H%M%S\" ) .db \u6216\u8005 etcdctl \\ --endpoints = https://:2379 \\ --cert = /etc/kubernetes/pki/etcd/server.crt \\ --key = /etc/kubernetes/pki/etcd/server.key \\ --cacert = /etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot- $( date + \"%Y%m%d%H%M%S\" ) .db Output: {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.328+0800\",\"caller\":\"snapshot/v3_snapshot.go:65\",\"msg\":\"created temporary db file\",\"path\":\"snapshot-20220724185121.db.part\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:211\",\"msg\":\"opened snapshot stream; downloading\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"caller\":\"snapshot/v3_snapshot.go:73\",\"msg\":\"fetching snapshot\",\"endpoint\":\"https://:2379\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.415+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:219\",\"msg\":\"completed snapshot read; closing\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:88\",\"msg\":\"fetched snapshot\",\"endpoint\":\"https://:2379\",\"size\":\"3.6 MB\",\"took\":\"now\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:97\",\"msg\":\"saved\",\"path\":\"snapshot-20220724185121.db\"} Snapshot saved at snapshot-20220724185121.db \u6267\u884c\u547d\u4ee4 ls -al \u5728\u5f53\u524d\u76ee\u5f55\u4e2d\u8bfb\u53d6\u6211\u4eec\u521a\u521a\u521b\u5efa\u7684\u5907\u4efd\u6587\u4ef6\u3002 -rw------- 1 root root 3616800 Jul 24 18 :51 snapshot-20220724185121.db","title":"\u5907\u4efdetcd"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#deployment_1","text":"\u5907\u4efd\u540e\uff0c\u6211\u4eec\u521b\u5efa\u53e6\u5916\u4e00\u4e2adeployment\u3002 kubectl create deployment app-after-backup --image = nginx \u5220\u9664\u5907\u4efd\u524d\u6211\u4eec\u521b\u5efa\u7684\u90a3\u4e2adeployment\u3002 kubectl delete deployment app-before-backup \u68c0\u67e5deployment\u7684\u72b6\u6001\u3002 kubectl get deploy \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE app-after-backup 1/1 1 1 108s","title":"\u521b\u5efa\u4e00\u4e2adeployment\uff08\u5907\u4efd\u540e\uff09"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#services","text":"\u5220\u9664 etcd \u7684\u76ee\u5f55\u3002 mv /var/lib/etcd/ /var/lib/etcd.bak \u505c\u6b62 kubelet \u3002 systemctl stop kubelet \u505c\u6b62 kube-apiserver \u3002 nerdctl -n k8s.io ps -a | grep apiserver \u8fd0\u884c\u7ed3\u679c\uff1a 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001 \u505c\u6b62\u90a3\u4e9b\u4ecd\u65e7\u5904\u4e8e up \u72b6\u6001\u7684\u5bb9\u5668\u3002 nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0c5e69118f1b nerdctl -n k8s.io stop 638bb602c310 \u76f4\u81f3\u6ca1\u6709\u5904\u4e8e up \u72b6\u6001\u7684 kube-apiserver \u3002 nerdctl -n k8s.io ps -a | grep apiserver \u8fd0\u884c\u7ed3\u679c\uff1a 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001","title":"\u505c\u6b62Services"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#etcd_2","text":"nerdctl -n k8s.io ps -a | grep etcd \u8fd0\u884c\u7ed3\u679c\uff1a 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/etcd-cka001 \u505c\u6b62\u90a3\u4e9b\u4ecd\u65e7\u5904\u4e8e up \u72b6\u6001\u7684\u5bb9\u5668\u3002 nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0965b195f41a nerdctl -n k8s.io stop 9e1bea9f25d1 \u76f4\u81f3\u6ca1\u6709\u5904\u4e8e up \u72b6\u6001\u7684 kube-apiserver \u3002 nerdctl -n k8s.io ps -a | grep etcd \u8fd0\u884c\u7ed3\u679c\uff1a 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001","title":"\u505c\u6b62etcd"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#etcd_3","text":"\u5728\u63a7\u5236\u5e73\u9762\u8282\u70b9\u4e0a\u6267\u884c\u6062\u590d\u64cd\u4f5c\uff0c\u4f7f\u7528\u5b9e\u9645\u7684\u5907\u4efd\u6587\u4ef6\uff0c\u8fd9\u91cc\u662f\u6587\u4ef6 snapshot-20220724185121.db \u3002 etcdctl snapshot restore snapshot-20220724185121.db \\ --endpoints = :2379 \\ --cert = /etc/kubernetes/pki/etcd/server.crt \\ --key = /etc/kubernetes/pki/etcd/server.key \\ --cacert = /etc/kubernetes/pki/etcd/ca.crt \\ --data-dir = /var/lib/etcd \u8fd0\u884c\u7ed3\u679c\uff1a Deprecated: Use `etcdutl snapshot restore` instead. 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:248 restoring snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\", \"stack\": \"go.etcd.io/etcd/etcdutl/v3/snapshot.(*v3Manager).Restore\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/snapshot/v3_snapshot.go:254\\ngo.etcd.io/etcd/etcdutl/v3/etcdutl.SnapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/etcdutl/snapshot_command.go:147\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3/command.snapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/command/snapshot_command.go:129\\ngithub.com/spf13/cobra.(*Command).execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856\\ngithub.com/spf13/cobra.(*Command).ExecuteC\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960\\ngithub.com/spf13/cobra.(*Command).Execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:897\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.Start\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:107\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.MustStart\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:111\\nmain.main\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/main.go:59\\nruntime.main\\n\\t/go/gos/go1.16.15/src/runtime/proc.go:225\"} 2022-07-24T18:57:49+08:00 info membership/store.go:141 Trimming membership information from the backend... 2022-07-24T18:57:49+08:00 info membership/cluster.go:421 added member {\"cluster-id\": \"cdf818194e3a8c32\", \"local-member-id\": \"0\", \"added-peer-id\": \"8e9e05c52164694d\", \"added-peer-peer-urls\": [\"http://localhost:2380\"]} 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:269 restored snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\"} \u68c0\u67e5\u88ab\u5220\u9664\u7684 etcd \u76ee\u5f55\u662f\u5426\u5df2\u7ecf\u4ece\u5907\u4efd\u4e2d\u6062\u590d\u4e86\u3002 tree /var/lib/etcd \u8fd0\u884c\u7ed3\u679c\uff1a /var/lib/etcd \u2514\u2500\u2500 member \u251c\u2500\u2500 snap \u2502 \u251c\u2500\u2500 0000000000000001-0000000000000001.snap \u2502 \u2514\u2500\u2500 db \u2514\u2500\u2500 wal \u2514\u2500\u2500 0000000000000000-0000000000000000.wal","title":"\u6062\u590detcd"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#services_1","text":"\u542f\u52a8 kubelet \u3002\u670d\u52a1 kube-apiserver \u548c etcd \u4e5f\u4f1a\u7ee7 kubelet \u542f\u52a8\u540e\u88ab\u81ea\u52a8\u542f\u52a8\u3002 systemctl start kubelet \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u786e\u8ba4\u6240\u6709\u670d\u52a1\u90fd\u5df2\u7ecf\u542f\u52a8\u548c\u6b63\u5e38\u8fd0\u884c\u3002 systemctl status kubelet.service nerdctl -n k8s.io ps -a | grep etcd nerdctl -n k8s.io ps -a | grep apiserver \u67e5\u770b\u5f53\u524d etcd \u7684\u72b6\u6001\u3002 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 3b8f37c87782 registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 6 seconds ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001 fbbbb628a945 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 6 seconds ago Up k8s://kube-system/etcd-cka001 \u67e5\u770b\u5f53\u524d apiserver \u7684\u72b6\u6001\u3002 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 281cf4c6670d registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 14 seconds ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 5ed8295d92da registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 15 seconds ago Up k8s://kube-system/kube-apiserver-cka001 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001","title":"\u542f\u52a8\u670d\u52a1Services"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_1","text":"\u68c0\u67e5\u96c6\u7fa4\u7684\u72b6\u6001\uff0c\u67e5\u770b\u662f\u5426pod app-before-backup \u5b58\u5728\u3002 kubectl get deploy \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE app-before-backup 1/1 1 1 11m","title":"\u9a8c\u8bc1"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_2","text":"\u6f14\u793a\u573a\u666f\uff1a\u96c6\u7fa4\u5347\u7ea7 \u9a71\u9010\u63a7\u5236\u5e73\u9762\u8282\u70b9 \u68c0\u67e5\u5f53\u524d\u53ef\u7528\u7684 kubeadm \u7248\u672c \u5c06 kubeadm \u5347\u7ea7\u5230\u65b0\u7248\u672c \u68c0\u67e5\u5347\u7ea7\u8ba1\u5212 \u5e94\u7528\u5347\u7ea7\u8ba1\u5212\u4ee5\u5347\u7ea7\u5230\u65b0\u7248\u672c \u5347\u7ea7 kubelet \u548c kubectl \u542f\u7528\u63a7\u5236\u5e73\u9762\u8282\u70b9\u8c03\u5ea6 \u9a71\u9010\u5de5\u4f5c\u8282\u70b9 \u5347\u7ea7 kubeadm \u548c kubelet \u542f\u7528\u5de5\u4f5c\u8282\u70b9\u8c03\u5ea6 \u53c2\u8003\uff1a kubeadm\u5347\u7ea7","title":"\u96c6\u7fa4\u5347\u7ea7"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_3","text":"","title":"\u5347\u7ea7\u63a7\u5236\u5e73\u9762"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_4","text":"\u9a71\u9010\u63a7\u5236\u5e73\u9762\u8282\u70b9\u3002 kubectl drain --ignore-daemonsets \u8fd9\u91cc\u662f\uff1a kubectl drain cka001 --ignore-daemonsets \u8fd0\u884c\u7ed3\u679c\uff1a node/cka001 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-dsx76, kube-system/kube-proxy-cm4hc evicting pod kube-system/calico-kube-controllers-5c64b68895-jr4nl evicting pod kube-system/coredns-6d8c4cb4d-g4jxc evicting pod kube-system/coredns-6d8c4cb4d-sqcvj pod/calico-kube-controllers-5c64b68895-jr4nl evicted pod/coredns-6d8c4cb4d-g4jxc evicted pod/coredns-6d8c4cb4d-sqcvj evicted node/cka001 drained \u63a7\u5236\u5e73\u9762\u8282\u70b9\u73b0\u5728\u5904\u4e8e SchedulingDisabled \u72b6\u6001\u3002 kubectl get node -owide \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 \u67e5\u8be2\u5f53\u524d kubeadm \u53ef\u7528\u7248\u672c\u3002 apt policy kubeadm \u8f93\u51fa\u7ed3\u679c\uff1a kubeadm: Installed: 1.24.0-00 Candidate: 1.24.3-00 Version table: 1.24.3-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.1-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages *** 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 100 /var/lib/dpkg/status 1.23.7-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages ...... \u5347\u7ea7 kubeadm \u5230 Candidate: 1.24.2-00 \u7248\u672c\u3002 sudo apt-get -y install kubeadm = 1 .24.2-00 --allow-downgrades \u67e5\u8be2\u5347\u7ea7\u8ba1\u5212\u3002 kubeadm upgrade plan \u8f93\u51fa\u7c7b\u4f3c\u4e0b\u9762\u7684\u5347\u7ea7\u8ba1\u5212\u3002 [upgrade/config] Making sure the configuration is correct: [upgrade/config] Reading configuration from the cluster... [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [preflight] Running pre-flight checks. [upgrade] Running cluster health checks [upgrade] Fetching available versions to upgrade to [upgrade/versions] Cluster version: v1.24.0 [upgrade/versions] kubeadm version: v1.24.2 I0724 19:05:00.111855 1142460 version.go:255] remote version is much newer: v1.24.3; falling back to: stable-1.23 [upgrade/versions] Target version: v1.24.2 [upgrade/versions] Latest version in the v1.23 series: v1.24.2 Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply': COMPONENT CURRENT TARGET kubelet 3 x v1.24.0 v1.24.2 Upgrade to the latest version in the v1.23 series: COMPONENT CURRENT TARGET kube-apiserver v1.24.0 v1.24.2 kube-controller-manager v1.24.0 v1.24.2 kube-scheduler v1.24.0 v1.24.2 kube-proxy v1.24.0 v1.24.2 CoreDNS v1.8.6 v1.8.6 etcd 3.5.1-0 3.5.1-0 You can now apply the upgrade by executing the following command: kubeadm upgrade apply v1.24.2 _____________________________________________________________________ The table below shows the current state of component configs as understood by this version of kubeadm. Configs that have a \"yes\" mark in the \"MANUAL UPGRADE REQUIRED\" column require manual config upgrade or resetting to kubeadm defaults before a successful upgrade can be performed. The version to manually upgrade to is denoted in the \"PREFERRED VERSION\" column. API GROUP CURRENT VERSION PREFERRED VERSION MANUAL UPGRADE REQUIRED kubeproxy.config.k8s.io v1alpha1 v1alpha1 no kubelet.config.k8s.io v1beta1 v1beta1 no _____________________________________________________________________","title":"\u63a7\u5236\u5e73\u9762\u51c6\u5907"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_5","text":"\u53c2\u8003\u524d\u9762\u7684\u5347\u7ea7\u8ba1\u5212\uff0c\u6211\u4eec\u5347\u7ea7\u5230 v1.24.2 \u7248\u672c\u3002 kubeadm upgrade apply v1.24.2 \u901a\u8fc7\u9009\u9879 --etcd-upgrade=false \uff0c\u6211\u4eec\u628a etcd \u6392\u9664\u51fa\u5f53\u524d\u5347\u7ea7\u8303\u56f4\u3002 kubeadm upgrade apply v1.24.2 --etcd-upgrade = false \u6536\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u5219\u4ee3\u8868\u4e0a\u9762\u7684\u5347\u7ea7\u547d\u4ee4\u6210\u529f\u4e86\u3002 [upgrade/successful] SUCCESS! Your cluster was upgraded to \"v1.24.2\". Enjoy! [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so. \u5347\u7ea7 kubelet \u548c kubectl \u3002 sudo apt-get -y install kubelet = 1 .24.2-00 kubectl = 1 .24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet \u67e5\u8be2\u8282\u70b9\u5f53\u524d\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0 After verify that each node is in Ready status, enable node scheduling. \u5728\u786e\u8ba4\u6240\u6709\u8282\u70b9\u90fd\u5904\u4e8eReady\u72b6\u6001\uff0c\u5219\u6fc0\u6d3bscheduling\u3002 kubectl uncordon \u8fd9\u91cc\u662f\uff1a kubectl uncordon cka001 \u8f93\u51fa\u7ed3\u679c\uff1a node/cka001 uncordoned \u518d\u6b21\u68c0\u67e5\u8282\u70b9\u72b6\u6001\uff0c\u786e\u4fdd\u6240\u6709\u8282\u70b9\u90fd\u5904\u4e8eReady\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0","title":"\u63a7\u5236\u5e73\u9762\u5347\u7ea7"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_6","text":"","title":"\u5347\u7ea7\u5de5\u4f5c\u8282\u70b9"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_7","text":"\u767b\u5f55\u8282\u70b9 cka001 \u3002 \u9a71\u9010 Worker \u8282\u70b9\uff0c\u9700\u8981\u663e\u5f0f\u6307\u5b9a\u662f\u5426\u5220\u9664\u672c\u5730\u5b58\u50a8\u3002 kubectl drain --ignore-daemonsets --force kubectl drain --ignore-daemonsets --delete-emptydir-data --force \u5982\u679c\u9047\u5230\u5173\u4e8e emptydir \u4f9d\u8d56\u7684\u9519\u8bef\uff0c\u5219\u6267\u884c\u7b2c\u4e8c\u4e2a\u547d\u4ee4\u3002 kubectl drain cka002 --ignore-daemonsets --force kubectl drain cka002 --ignore-daemonsets --delete-emptydir-data --force \u8f93\u51fa\u7ed3\u679c\uff1a node/cka002 cordoned WARNING: deleting Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet: dev/ubuntu; ignoring DaemonSet-managed Pods: kube-system/calico-node-p5rf2, kube-system/kube-proxy-zvs68 evicting pod ns-netpol/pod-netpol-5b67b6b496-2cgnw evicting pod dev/ubuntu evicting pod dev/app-before-backup-66dc9d5cb-6xc8c evicting pod dev/nfs-client-provisioner-86d7fb78b6-2f5dx evicting pod dev/pod-netpol-2-77478d77ff-l6rzm evicting pod ingress-nginx/ingress-nginx-admission-patch-nk9fv evicting pod ingress-nginx/ingress-nginx-admission-create-lgtdj evicting pod kube-system/coredns-6d8c4cb4d-l4kx4 pod/ingress-nginx-admission-create-lgtdj evicted pod/ingress-nginx-admission-patch-nk9fv evicted pod/nfs-client-provisioner-86d7fb78b6-2f5dx evicted pod/app-before-backup-66dc9d5cb-6xc8c evicted pod/coredns-6d8c4cb4d-l4kx4 evicted pod/pod-netpol-5b67b6b496-2cgnw evicted pod/pod-netpol-2-77478d77ff-l6rzm evicted pod/ubuntu evicted node/cka002 drained","title":"\u5de5\u4f5c\u8282\u70b9\u51c6\u5907"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_8","text":"\u767b\u5f55\u8282\u70b9 cka002 \u3002 \u4e0b\u8f7d kubeadm \u7684 v1.24.2 \u7248\u672c\u3002 sudo apt-get -y install kubeadm = 1 .24.2-00 --allow-downgrades \u5347\u7ea7 kubeadm \u3002 sudo kubeadm upgrade node \u5347\u7ea7 kubelet \u3002 sudo apt-get -y install kubelet = 1 .24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet \u786e\u8ba4\u6240\u6709\u8282\u70b9\u90fd\u5904\u4e8eReady\u72b6\u6001\uff0c\u5219\u6fc0\u6d3bscheduling\u3002 kubectl uncordon \u8fd9\u91cc\u662f\uff1a kubectl uncordon cka002","title":"\u5de5\u4f5c\u8282\u70b9\u5347\u7ea7"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_9","text":"\u67e5\u8be2\u8282\u70b9\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.0 \u5728\u8282\u70b9 cka003 \u4e0a\u91cd\u590d\u4e0a\u9762\u7684\u6b65\u9aa4\u3002 \u767b\u5f55\u8282\u70b9 cka003 \u3002\u5982\u679c\u9047\u5230\u5173\u4e8e emptydir \u4f9d\u8d56\u7684\u9519\u8bef\uff0c\u5219\u6267\u884c\u7b2c\u4e8c\u4e2a\u547d\u4ee4\u3002 kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --force kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --delete-emptydir-data --force \u767b\u5f55\u8282\u70b9 cka003 \uff0c\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u3002 sudo apt-get -y install kubeadm = 1 .24.2-00 --allow-downgrades sudo kubeadm upgrade node sudo apt-get -y install kubelet = 1 .24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet kubectl get node kubectl uncordon cka003 \u67e5\u8be2\u8282\u70b9\u72b6\u6001\u3002 kubectl get node \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.2","title":"\u5de5\u4f5c\u8282\u70b9\u9a8c\u8bc1"},{"location":"k8s/cka_cn/foundamentals/clustermgt/#_10","text":"\u5728\u63a7\u5236\u9762\u677f\u4e0a\u7684\u6267\u884c\u6b65\u9aa4\uff1a kubectl get node -owide kubectl drain cka001 --ignore-daemonsets kubectl get node -owide apt policy kubeadm apt-get -y install kubeadm = 1 .24.0-00 --allow-downgrades kubeadm upgrade plan kubeadm upgrade apply v1.24.0 # kubeadm upgrade apply v1.24.0 --etcd-upgrade=false apt-get -y install kubelet = 1 .24.0-00 kubectl = 1 .24.0-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl get node kubectl uncordon cka001 \u5728\u5de5\u4f5c\u8282\u70b9\u4e0a\u7684\u6267\u884c\u6b65\u9aa4\uff1a \u5728\u63a7\u5236\u9762\u677f\u4e0a\uff1a kubectl drain cka002 --ignore-daemonsets \u5728\u5de5\u4f5c\u8282\u70b9\u4e0a\uff1a apt-get -y install kubeadm = 1 .24.1-00 --allow-downgrades kubeadm upgrade node apt-get -y install kubelet = 1 .24.1-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl uncordon cka002 \u5728\u5176\u4ed6\u5de5\u4f5c\u8282\u70b9\u4e0a\u91cd\u590d\u4e0a\u9762\u7684\u6b65\u9aa4\u3002","title":"\u603b\u7ed3"},{"location":"k8s/cka_cn/foundamentals/configuration/","text":"CKA\u81ea\u5b66\u7b14\u8bb015:Configuration \u00b6","title":"Configuration"},{"location":"k8s/cka_cn/foundamentals/configuration/#cka15configuration","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb015:Configuration"},{"location":"k8s/cka_cn/foundamentals/daemonset/","text":"CKA\u81ea\u5b66\u7b14\u8bb013:DaemonSet \u00b6 \u6f14\u793a\u573a\u666f \u00b6 \u521b\u5efa\u4e00\u4e2aDaemonSet \u521b\u5efa\u7684DaemonSet\u4f1a\u5728\u6bcf\u4e2anode\u8282\u70b9\u4e0a\u8fd0\u884c\u81ea\u5df1\u7684pod\u3002 \u6f14\u793a \u00b6 \u521b\u5efa DaemonSet daemonset-busybox \u3002 kubectl apply -f - << EOF apiVersion: apps/v1 kind: DaemonSet metadata: name: daemonset-busybox labels: app: daemonset-busybox spec: selector: matchLabels: app: daemonset-busybox template: metadata: labels: app: daemonset-busybox spec: tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: busybox image: busybox:1.28 args: - sleep - \"10000\" EOF \u83b7\u53d6DaemonSet\u7684\u8fd0\u884c\u72b6\u6001\u3002 kubectl get daemonsets daemonset-busybox \u8fd0\u884c\u7ed3\u679c NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset-busybox 3 3 3 3 3 5m33s \u83b7\u53d6 DaemonSet \u7684 Pod \u7684\u72b6\u6001\u3002\u8fd9\u4e9bpod\u4f1a\u90e8\u7f72\u5728\u6bcf\u4e2a\u8282\u70b9node\u4e0a\u3002 kubectl get pod -o wide \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES daemonset-busybox-54cj5 1 /1 Running 0 44s 10 .244.102.4 cka003 daemonset-busybox-5tl55 1 /1 Running 0 44s 10 .244.228.197 cka001 daemonset-busybox-wg225 1 /1 Running 0 44s 10 .244.112.5 cka002 \u5220\u9664\u6240\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete daemonset daemonset-busybox","title":"DaemonSet"},{"location":"k8s/cka_cn/foundamentals/daemonset/#cka13daemonset","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb013:DaemonSet"},{"location":"k8s/cka_cn/foundamentals/daemonset/#_1","text":"\u521b\u5efa\u4e00\u4e2aDaemonSet \u521b\u5efa\u7684DaemonSet\u4f1a\u5728\u6bcf\u4e2anode\u8282\u70b9\u4e0a\u8fd0\u884c\u81ea\u5df1\u7684pod\u3002","title":"\u6f14\u793a\u573a\u666f"},{"location":"k8s/cka_cn/foundamentals/daemonset/#_2","text":"\u521b\u5efa DaemonSet daemonset-busybox \u3002 kubectl apply -f - << EOF apiVersion: apps/v1 kind: DaemonSet metadata: name: daemonset-busybox labels: app: daemonset-busybox spec: selector: matchLabels: app: daemonset-busybox template: metadata: labels: app: daemonset-busybox spec: tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: busybox image: busybox:1.28 args: - sleep - \"10000\" EOF \u83b7\u53d6DaemonSet\u7684\u8fd0\u884c\u72b6\u6001\u3002 kubectl get daemonsets daemonset-busybox \u8fd0\u884c\u7ed3\u679c NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset-busybox 3 3 3 3 3 5m33s \u83b7\u53d6 DaemonSet \u7684 Pod \u7684\u72b6\u6001\u3002\u8fd9\u4e9bpod\u4f1a\u90e8\u7f72\u5728\u6bcf\u4e2a\u8282\u70b9node\u4e0a\u3002 kubectl get pod -o wide \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES daemonset-busybox-54cj5 1 /1 Running 0 44s 10 .244.102.4 cka003 daemonset-busybox-5tl55 1 /1 Running 0 44s 10 .244.228.197 cka001 daemonset-busybox-wg225 1 /1 Running 0 44s 10 .244.112.5 cka002 \u5220\u9664\u6240\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete daemonset daemonset-busybox","title":"\u6f14\u793a"},{"location":"k8s/cka_cn/foundamentals/deployment/","text":"CKA\u81ea\u5b66\u7b14\u8bb09:Deployment \u00b6 \u6458\u8981 \u00b6 \u4fee\u6539\u5df2\u6709\u7684Deployment\uff0c\u6bd4\u5982\uff0c\u589e\u52a0\u7aef\u53e3\u53f7\u7b49\u3002 \u6f14\u793a \u00b6 \u521b\u5efaDeployment nginx \u3002 kubectl create deployment nginx --image = nginx \u6267\u884c\u4ee5\u4e0b\u547d\u4ee4\u4ee5\u83b7\u53d6\u5e26\u6709\u7aef\u53e3\u53f7\u7684yaml\u6a21\u677f\u3002 \u9009\u9879 --port=8080 \u6307\u5b9a\u4e86\u8be5\u5bb9\u5668\u66b4\u9732\u7684\u7aef\u53e3\u53f7\u3002 kubectl create deployment nginx --image = nginx --port = 8080 --dry-run = client -o yaml \u8fd9\u6837\u6211\u4eec\u5c31\u77e5\u9053\u4e86\u6dfb\u52a0\u7aef\u53e3\u53f7\u7684\u8def\u5f84\uff0c\u5c31\u50cf\u4e0b\u9762\u8fd9\u6837\uff1a kubectl explain deployment.spec.template.spec.containers.ports.containerPort \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u6765\u4fee\u6539\u5f53\u524d\u6b63\u5728\u8fd0\u884c\u7684Deployment\u3002 kubectl edit deployment nginx \u6dfb\u52a0\u4e0b\u97622\u884c\u6765\u5236\u5b9a 8080 \u7aef\u53e3\u548c TCP \u534f\u8bae\u3002 spec : template : spec : containers : - image : nginx name : nginx ports : - containerPort : 8080 protocol : TCP \u901a\u8fc7\u547d\u4ee4 kubectl describe deployment \u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5728Deployment\u4e2d\u7aef\u53e3\u53f7\u548c\u534f\u8bae\u5df2\u7ecf\u88ab\u6b63\u786e\u6dfb\u52a0\u4e86\u3002 Pod Template : Labels : app=nginx Containers : nginx : Image : nginx Port : 8080/TCP Host Port : 0/TCP Environment : Mounts : Volumes : \u901a\u8fc7\u547d\u4ee4 kubectl describe pod \u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5728pod\u4e2d\u7aef\u53e3\u53f7\u548c\u534f\u8bae\u5df2\u7ecf\u88ab\u6b63\u786e\u6dfb\u52a0\u4e86\u3002 Containers : nginx : Container ID : containerd://af4a1243f981497074b5c006ac55fcf795688399871d1dfe91a095321f5c91aa Image : nginx Image ID : docker.io/library/nginx@sha256:1761fb5661e4d77e107427d8012ad3a5955007d997e0f4a3d41acc9ff20467c7 Port : 8080/TCP Host Port : 0/TCP State : Running Started : Sun, 24 Jul 2022 22:50:12 +0800 Ready : True Restart Count : 0 Environment : Mounts : /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hftdt (ro) \u4ee5\u4e0b\u662fDeployment\u7684\u4e00\u4e9b\u5173\u952e\u5b57\u6bb5\uff08\u4f7f\u7528 kubectl explain \uff09\uff1a deployment.spec.revisionHistoryLimit \uff1a\u4fdd\u7559\u65e7\u7684 ReplicaSets \u7684\u6570\u91cf\uff0c\u4ee5\u4fbf\u8fdb\u884c\u56de\u6eda\u3002\u9ed8\u8ba4\u4e3a 10 \u3002 deployment.spec.strategy.type \uff1a\u90e8\u7f72\u7684\u7c7b\u578b\u3002\u53ef\u4ee5\u662f Recreate \u6216 RollingUpdate \u3002\u9ed8\u8ba4\u4e3a RollingUpdate \u3002 deployment.spec.strategy.rollingUpdate.maxUnavailable \uff1a\u5728\u66f4\u65b0\u671f\u95f4\u53ef\u4ee5\u4e0d\u53ef\u7528\u7684Pod\u7684\u6700\u5927\u6570\u91cf\u3002\u9ed8\u8ba4\u4e3a 25\uff05 \u3002 deployment.spec.strategy.rollingUpdate.maxSurge \uff1a\u53ef\u4ee5\u5b89\u6392\u7684Pod\u6570\u91cf\u8d85\u51fa\u6240\u9700Pod\u6570\u91cf\u7684\u6700\u5927\u503c\u3002\u9ed8\u8ba4\u4e3a 25\uff05 \u3002\u5982\u679c MaxUnavailable \u4e3a 0 \uff0c\u5219\u6b64\u503c\u4e0d\u80fd\u4e3a 0 \u3002 deployment.spec.minReadySeconds \uff1a\u65b0\u521b\u5efa\u7684Pod\u7684\u6700\u5c0f\u51c6\u5907\u65f6\u95f4\uff08\u6240\u6709\u5bb9\u5668\u90fd\u6ca1\u6709\u5d29\u6e83\uff09\uff0c\u4ee5\u4fbf\u88ab\u89c6\u4e3a\u53ef\u7528\u3002\u9ed8\u8ba4\u4e3a 0 \uff08\u4e00\u65e6\u51c6\u5907\u597d\u5c31\u4f1a\u88ab\u89c6\u4e3a\u53ef\u7528\uff09\u3002","title":"Deployment"},{"location":"k8s/cka_cn/foundamentals/deployment/#cka9deployment","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb09:Deployment"},{"location":"k8s/cka_cn/foundamentals/deployment/#_1","text":"\u4fee\u6539\u5df2\u6709\u7684Deployment\uff0c\u6bd4\u5982\uff0c\u589e\u52a0\u7aef\u53e3\u53f7\u7b49\u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/deployment/#_2","text":"\u521b\u5efaDeployment nginx \u3002 kubectl create deployment nginx --image = nginx \u6267\u884c\u4ee5\u4e0b\u547d\u4ee4\u4ee5\u83b7\u53d6\u5e26\u6709\u7aef\u53e3\u53f7\u7684yaml\u6a21\u677f\u3002 \u9009\u9879 --port=8080 \u6307\u5b9a\u4e86\u8be5\u5bb9\u5668\u66b4\u9732\u7684\u7aef\u53e3\u53f7\u3002 kubectl create deployment nginx --image = nginx --port = 8080 --dry-run = client -o yaml \u8fd9\u6837\u6211\u4eec\u5c31\u77e5\u9053\u4e86\u6dfb\u52a0\u7aef\u53e3\u53f7\u7684\u8def\u5f84\uff0c\u5c31\u50cf\u4e0b\u9762\u8fd9\u6837\uff1a kubectl explain deployment.spec.template.spec.containers.ports.containerPort \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u6765\u4fee\u6539\u5f53\u524d\u6b63\u5728\u8fd0\u884c\u7684Deployment\u3002 kubectl edit deployment nginx \u6dfb\u52a0\u4e0b\u97622\u884c\u6765\u5236\u5b9a 8080 \u7aef\u53e3\u548c TCP \u534f\u8bae\u3002 spec : template : spec : containers : - image : nginx name : nginx ports : - containerPort : 8080 protocol : TCP \u901a\u8fc7\u547d\u4ee4 kubectl describe deployment \u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5728Deployment\u4e2d\u7aef\u53e3\u53f7\u548c\u534f\u8bae\u5df2\u7ecf\u88ab\u6b63\u786e\u6dfb\u52a0\u4e86\u3002 Pod Template : Labels : app=nginx Containers : nginx : Image : nginx Port : 8080/TCP Host Port : 0/TCP Environment : Mounts : Volumes : \u901a\u8fc7\u547d\u4ee4 kubectl describe pod \u6211\u4eec\u53ef\u4ee5\u770b\u5230\u5728pod\u4e2d\u7aef\u53e3\u53f7\u548c\u534f\u8bae\u5df2\u7ecf\u88ab\u6b63\u786e\u6dfb\u52a0\u4e86\u3002 Containers : nginx : Container ID : containerd://af4a1243f981497074b5c006ac55fcf795688399871d1dfe91a095321f5c91aa Image : nginx Image ID : docker.io/library/nginx@sha256:1761fb5661e4d77e107427d8012ad3a5955007d997e0f4a3d41acc9ff20467c7 Port : 8080/TCP Host Port : 0/TCP State : Running Started : Sun, 24 Jul 2022 22:50:12 +0800 Ready : True Restart Count : 0 Environment : Mounts : /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hftdt (ro) \u4ee5\u4e0b\u662fDeployment\u7684\u4e00\u4e9b\u5173\u952e\u5b57\u6bb5\uff08\u4f7f\u7528 kubectl explain \uff09\uff1a deployment.spec.revisionHistoryLimit \uff1a\u4fdd\u7559\u65e7\u7684 ReplicaSets \u7684\u6570\u91cf\uff0c\u4ee5\u4fbf\u8fdb\u884c\u56de\u6eda\u3002\u9ed8\u8ba4\u4e3a 10 \u3002 deployment.spec.strategy.type \uff1a\u90e8\u7f72\u7684\u7c7b\u578b\u3002\u53ef\u4ee5\u662f Recreate \u6216 RollingUpdate \u3002\u9ed8\u8ba4\u4e3a RollingUpdate \u3002 deployment.spec.strategy.rollingUpdate.maxUnavailable \uff1a\u5728\u66f4\u65b0\u671f\u95f4\u53ef\u4ee5\u4e0d\u53ef\u7528\u7684Pod\u7684\u6700\u5927\u6570\u91cf\u3002\u9ed8\u8ba4\u4e3a 25\uff05 \u3002 deployment.spec.strategy.rollingUpdate.maxSurge \uff1a\u53ef\u4ee5\u5b89\u6392\u7684Pod\u6570\u91cf\u8d85\u51fa\u6240\u9700Pod\u6570\u91cf\u7684\u6700\u5927\u503c\u3002\u9ed8\u8ba4\u4e3a 25\uff05 \u3002\u5982\u679c MaxUnavailable \u4e3a 0 \uff0c\u5219\u6b64\u503c\u4e0d\u80fd\u4e3a 0 \u3002 deployment.spec.minReadySeconds \uff1a\u65b0\u521b\u5efa\u7684Pod\u7684\u6700\u5c0f\u51c6\u5907\u65f6\u95f4\uff08\u6240\u6709\u5bb9\u5668\u90fd\u6ca1\u6709\u5d29\u6e83\uff09\uff0c\u4ee5\u4fbf\u88ab\u89c6\u4e3a\u53ef\u7528\u3002\u9ed8\u8ba4\u4e3a 0 \uff08\u4e00\u65e6\u51c6\u5907\u597d\u5c31\u4f1a\u88ab\u89c6\u4e3a\u53ef\u7528\uff09\u3002","title":"\u6f14\u793a"},{"location":"k8s/cka_cn/foundamentals/docker/","text":"CKA\u81ea\u5b66\u7b14\u8bb04:Docker\u57fa\u7840 \u00b6 \u6458\u8981 \u00b6 \u4e86\u89e3Linux\u539f\u8bed\u7684\u6982\u5ff5\u548c\u5305\u542b\u7684\u7279\u6027\u3002 \u5b89\u88c5Docker\uff0c\u4e86\u89e3\u57fa\u672c\u7684Docker\u547d\u4ee4\u548cDockerfile\u7684\u4f7f\u7528\u3002 \u7ec3\u4e60\u73af\u5883 \u00b6 \u64cd\u4f5c\u7cfb\u7edf\uff1aopenSUSE 15.3 cat /etc/os-release \u8f93\u51fa\u7ed3\u679c\uff1a NAME=\"openSUSE Leap\" VERSION=\"15.3\" ID=\"opensuse-leap\" ID_LIKE=\"suse opensuse\" VERSION_ID=\"15.3\" PRETTY_NAME=\"openSUSE Leap 15.3\" ANSI_COLOR=\"0;32\" CPE_NAME=\"cpe:/o:opensuse:leap:15.3\" BUG_REPORT_URL=\"https://bugs.opensuse.org\" HOME_URL=\"https://www.opensuse.org/\" Linux\u539f\u8bed \u00b6 \u5728\u64cd\u4f5c\u7cfb\u7edf\u4e2d\uff0c\u539f\u8bed\uff08primitives\uff09\u662f\u7528\u4e8e\u521b\u5efa\u66f4\u590d\u6742\u529f\u80fd\u7684\u57fa\u672c\u6784\u5efa\u5757\u6216\u64cd\u4f5c\u3002\u5728Linux\u4e2d\uff0c\u6709\u51e0\u79cd\u5e38\u7528\u7684\u539f\u8bed\u3002\u5305\u62ec\uff1a \u8fdb\u7a0b\uff08Processes\uff09\uff1a\u8fdb\u7a0b\u662f\u7a0b\u5e8f\u6216\u5e94\u7528\u7a0b\u5e8f\u7684\u8fd0\u884c\u5b9e\u4f8b\u3002\u5b83\u4eec\u662fLinux\u4e2d\u7684\u57fa\u672c\u5de5\u4f5c\u5355\u5143\uff0c\u7531\u5185\u6838\u7ba1\u7406\u3002 \u6587\u4ef6\uff08Files\uff09\uff1a\u6587\u4ef6\u662f\u5728Linux\u4e2d\u5b58\u50a8\u6570\u636e\u7684\u4e3b\u8981\u65b9\u5f0f\u3002\u5b83\u4eec\u53ef\u4ee5\u662f\u6587\u672c\u6587\u4ef6\u3001\u4e8c\u8fdb\u5236\u6587\u4ef6\u3001\u76ee\u5f55\u6216\u7279\u6b8a\u6587\u4ef6\uff0c\u5982\u8bbe\u5907\u6587\u4ef6\u3002 \u4fe1\u53f7\uff08Signals\uff09\uff1a\u4fe1\u53f7\u662f\u8fdb\u7a0b\u4e4b\u95f4\u6216\u8fdb\u7a0b\u4e0e\u5185\u6838\u4e4b\u95f4\u901a\u4fe1\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u5b83\u4eec\u7528\u4e8e\u901a\u77e5\u8fdb\u7a0b\u4e8b\u4ef6\uff0c\u4f8b\u5982\u4efb\u52a1\u5b8c\u6210\u6216\u9519\u8bef\u53d1\u751f\u7684\u60c5\u51b5\u3002 \u5957\u63a5\u5b57\uff08Sockets\uff09\uff1a\u5957\u63a5\u5b57\u662fLinux\u4e2d\u8fdb\u7a0b\u95f4\u901a\u4fe1\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u5b83\u4eec\u5141\u8bb8\u8fdb\u7a0b\u5728\u7f51\u7edc\u6216\u672c\u5730\u673a\u5668\u4e0a\u53d1\u9001\u548c\u63a5\u6536\u6570\u636e\u3002 \u7ebf\u7a0b\uff08Threads\uff09\uff1a\u7ebf\u7a0b\u662f\u8f7b\u91cf\u7ea7\u7684\u8fdb\u7a0b\uff0c\u4e0e\u5176\u7236\u8fdb\u7a0b\u5171\u4eab\u76f8\u540c\u7684\u5185\u5b58\u7a7a\u95f4\u548c\u8d44\u6e90\u3002\u5b83\u4eec\u901a\u5e38\u7528\u4e8e\u901a\u8fc7\u5141\u8bb8\u540c\u65f6\u6267\u884c\u591a\u4e2a\u4efb\u52a1\u6765\u63d0\u9ad8\u5e94\u7528\u7a0b\u5e8f\u7684\u6027\u80fd\u3002 \u7ba1\u9053\uff08Pipes\uff09\uff1a\u7ba1\u9053\u662f\u4e00\u79cd\u5c06\u4e00\u4e2a\u8fdb\u7a0b\u7684\u8f93\u51fa\u8fde\u63a5\u5230\u53e6\u4e00\u4e2a\u8fdb\u7a0b\u7684\u8f93\u5165\u7684\u65b9\u5f0f\u3002\u5b83\u4eec\u5141\u8bb8\u8fdb\u7a0b\u4ee5\u53d7\u63a7\u7684\u65b9\u5f0f\u8fdb\u884c\u901a\u4fe1\u548c\u4ea4\u6362\u6570\u636e\u3002 \u4fe1\u53f7\u91cf\uff08Semaphores\uff09\uff1a\u4fe1\u53f7\u91cf\u662fLinux\u4e2d\u63a7\u5236\u5bf9\u5171\u4eab\u8d44\u6e90\u8bbf\u95ee\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u5b83\u4eec\u5141\u8bb8\u8fdb\u7a0b\u534f\u8c03\u5b83\u4eec\u5bf9\u5171\u4eab\u8d44\u6e90\u7684\u8bbf\u95ee\uff0c\u5982\u6587\u4ef6\u6216\u5185\u5b58\u3002 chroot \u00b6 chroot\u4f7f\u7528pivot_root\uff0c\u4ee5\u5b9e\u73b0\u5c06*\u8fdb\u7a0b*\u7684\u6839\u76ee\u5f55\u66f4\u6539\u4e3a\u4efb\u4f55\u7ed9\u5b9a\u7684\u76ee\u5f55\u3002 a. \u6a21\u62df\u5bb9\u5668 \u4f7f\u7528 chroot \u547d\u4ee4\u53ef\u4ee5\u5728Linux\u7cfb\u7edf\u4e2d\u521b\u5efa\u4e00\u4e2a\u5bb9\u5668\u3002\u8be5\u5bb9\u5668\u53ef\u4ee5\u770b\u4f5c\u662f\u4e00\u4e2a\u865a\u62df\u7684\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u5176\u4e2d\u8fd0\u884c\u7684\u8fdb\u7a0b\u53ea\u80fd\u8bbf\u95ee\u8be5\u6839\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u8d44\u6e90\u3002 \u4f8b\u5982\uff0c\u4ee5\u4e0b\u547d\u4ee4\u4f1a\u5c06\u5f53\u524d\u6839\u6587\u4ef6\u7cfb\u7edf\u66f4\u6539\u4e3a /tmp/myroot \u76ee\u5f55\uff1a chroot /tmp/myroot /bin/bash \u8fd9\u6761\u547d\u4ee4\u4f1a\u542f\u52a8\u4e00\u4e2a\u65b0\u7684Bash shell\uff0c\u8be5shell\u7684\u6839\u76ee\u5f55\u4e3a /tmp/myroot \u3002 b. \u66f4\u6539\u6839\u6587\u4ef6\u7cfb\u7edf chroot \u547d\u4ee4\u8fd8\u53ef\u7528\u4e8e\u66f4\u6539\u8fdb\u7a0b\u7684\u6839\u6587\u4ef6\u7cfb\u7edf\u3002\u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 chroot \u547d\u4ee4\u542f\u52a8\u4e00\u4e2a\u5177\u6709\u53e6\u4e00\u4e2a\u6839\u6587\u4ef6\u7cfb\u7edf\u7684\u8fdb\u7a0b\uff0c\u800c\u4e0d\u662f\u7cfb\u7edf\u7684\u9ed8\u8ba4\u6839\u6587\u4ef6\u7cfb\u7edf\u3002 \u4f8b\u5982\uff0c\u4ee5\u4e0b\u547d\u4ee4\u4f1a\u5c06\u5f53\u524d\u76ee\u5f55\uff08\u5373 ./ \uff09\u4f5c\u4e3a\u6839\u76ee\u5f55\uff0c\u5e76\u5728\u5176\u4e2d\u542f\u52a8\u4e00\u4e2a\u65b0\u7684Bash shell\uff1a sudo chroot . /bin/bash \u547d\u540d\u7a7a\u95f4 \u00b6 \u5728Linux\u64cd\u4f5c\u7cfb\u7edf\u4e2d\uff0cNamespace\uff08\u547d\u540d\u7a7a\u95f4\uff09\u662f\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u9694\u79bb\u4e0d\u540c\u8fdb\u7a0b\u7684\u8d44\u6e90\u3002\u901a\u8fc7Namespace\u673a\u5236\uff0c\u53ef\u4ee5\u5c06\u4e00\u7ec4\u8fdb\u7a0b\u53ca\u5176\u5b50\u8fdb\u7a0b\u7684\u89c6\u56fe\u9694\u79bb\u5728\u4e00\u4e2a\u72ec\u7acb\u7684Namespace\u4e2d\uff0c\u4ece\u800c\u5b9e\u73b0\u8fdb\u7a0b\u4e4b\u95f4\u8d44\u6e90\u9694\u79bb\u7684\u76ee\u7684\u3002 \u4e0b\u9762\u662f\u4e00\u4e9b\u5e38\u89c1\u7684Namespace\u7c7b\u578b\u53ca\u5176\u4f5c\u7528\uff1a Mount Namespace\uff1a\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\u6302\u8f7d\u70b9\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u3002 PID Namespace\uff1a\u9694\u79bb\u8fdb\u7a0bID\u53f7\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u8fdb\u7a0bID\u53f7\u7a7a\u95f4\uff0c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684PID\u51b2\u7a81\u3002 Network Namespace\uff1a\u9694\u79bb\u7f51\u7edc\u6808\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u7f51\u7edc\u6808\uff0c\u4ece\u800c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684\u7f51\u7edc\u51b2\u7a81\u3002 IPC Namespace\uff1a\u9694\u79bb\u8fdb\u7a0b\u95f4\u901a\u4fe1\uff08IPC\uff09\u673a\u5236\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684IPC\u7a7a\u95f4\uff0c\u4ece\u800c\u907f\u514dIPC\u673a\u5236\u5e26\u6765\u7684\u8d44\u6e90\u7ade\u4e89\u3002 UTS Namespace\uff1a\u9694\u79bb\u4e3b\u673a\u540d\u548c\u57df\u540d\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u4e3b\u673a\u540d\u548c\u57df\u540d\u7a7a\u95f4\uff0c\u4ece\u800c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684\u547d\u540d\u51b2\u7a81\u3002 Primitives namespace\u548cNamespace\u662f\u4e24\u4e2a\u4e0d\u540c\u7684\u6982\u5ff5\u3002 Namespace\u662fLinux\u64cd\u4f5c\u7cfb\u7edf\u63d0\u4f9b\u7684\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u9694\u79bb\u4e0d\u540c\u8fdb\u7a0b\u7684\u8d44\u6e90\uff0c\u4ee5\u5b9e\u73b0\u8fdb\u7a0b\u4e4b\u95f4\u7684\u8d44\u6e90\u9694\u79bb\u548c\u73af\u5883\u9694\u79bb\u3002\u4f8b\u5982\uff0cPID Namespace\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684PID\u53f7\u7a7a\u95f4\uff0c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684PID\u51b2\u7a81\uff1bNetwork Namespace\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u7f51\u7edc\u6808\uff0c\u4ece\u800c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684\u7f51\u7edc\u51b2\u7a81\u7b49\u3002 Primitives namespace\u662f\u4e00\u79cd\u65b0\u7684\u6280\u672f\u6982\u5ff5\uff0c\u5b83\u662f\u6307\u5c06\u4e0d\u540c\u7684\u57fa\u672c\u64cd\u4f5c\uff08\u4f8b\u5982\u8bfb\u5199\u6587\u4ef6\u3001\u521b\u5efa\u8fdb\u7a0b\u3001\u7f51\u7edc\u901a\u4fe1\u7b49\uff09\u4f5c\u4e3a\u539f\u8bed\u8fdb\u884c\u9694\u79bb\u548c\u5c01\u88c5\uff0c\u4f7f\u5f97\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u5728\u8fd9\u4e9b\u9694\u79bb\u7684\u539f\u8bed\u4e0a\u6784\u5efa\u51fa\u81ea\u5df1\u7684\u9694\u79bb\u73af\u5883\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u901a\u8fc7\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\u8bfb\u5199\u64cd\u4f5c\u6765\u5b9e\u73b0\u5bb9\u5668\u7ea7\u522b\u7684\u6587\u4ef6\u7cfb\u7edf\u9694\u79bb\uff1b\u901a\u8fc7\u9694\u79bb\u7f51\u7edc\u901a\u4fe1\u64cd\u4f5c\u6765\u5b9e\u73b0\u5bb9\u5668\u7ea7\u522b\u7684\u7f51\u7edc\u9694\u79bb\u7b49\u3002 \u56e0\u6b64\uff0cNamespace\u548cPrimitives namespace\u662f\u4e24\u4e2a\u4e0d\u540c\u7684\u6982\u5ff5\uff0c\u867d\u7136\u5b83\u4eec\u90fd\u53ef\u4ee5\u7528\u4e8e\u5b9e\u73b0\u9694\u79bb\u548c\u5c01\u88c5\u7684\u529f\u80fd\uff0c\u4f46\u662fNamespace\u662f\u4e00\u79cd\u66f4\u4e3a\u901a\u7528\u548c\u5e95\u5c42\u7684\u673a\u5236\uff0cPrimitives namespace\u662f\u4e00\u79cd\u66f4\u4e3a\u9ad8\u5c42\u7684\u62bd\u8c61\u6982\u5ff5\uff0c\u901a\u5e38\u7528\u4e8e\u6784\u5efa\u5bb9\u5668\u7b49\u5e94\u7528\u7ea7\u522b\u7684\u9694\u79bb\u73af\u5883\u3002 Namespace\u793a\u4f8b\uff1a \u5728Linux\u7cfb\u7edf\u4e2d\uff0c\u53ef\u4ee5\u4f7f\u7528PID Namespace\u6765\u9694\u79bb\u8fdb\u7a0bID\u53f7\u7a7a\u95f4\uff0c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684PID\u51b2\u7a81\u3002\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\uff1a # \u521b\u5efa\u4e00\u4e2a\u65b0\u7684PID Namespace unshare -p /bin/bash # \u5728\u65b0\u7684PID Namespace\u4e2d\u8fd0\u884c\u4e00\u4e2a\u8fdb\u7a0b echo $$ # \u663e\u793a\u5f53\u524d\u8fdb\u7a0b\u7684PID ps aux # \u663e\u793a\u5f53\u524d\u8fdb\u7a0b\u53ca\u5176\u5b50\u8fdb\u7a0b \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c unshare -p \u547d\u4ee4\u521b\u5efa\u4e86\u4e00\u4e2a\u65b0\u7684PID Namespace\uff0c\u5e76\u5728\u5176\u4e2d\u542f\u52a8\u4e86\u4e00\u4e2a\u65b0\u7684bash\u8fdb\u7a0b\u3002\u7531\u4e8e\u8be5\u8fdb\u7a0b\u8fd0\u884c\u5728\u4e00\u4e2a\u72ec\u7acb\u7684PID Namespace\u4e2d\uff0c\u56e0\u6b64\u5b83\u7684PID\u53f7\u4e0e\u4e3b\u673a\u4e0a\u7684\u5176\u4ed6\u8fdb\u7a0b\u4e0d\u4f1a\u51b2\u7a81\u3002\u5728\u8fd9\u4e2a\u65b0\u7684bash\u8fdb\u7a0b\u4e2d\uff0c $$ \u547d\u4ee4\u663e\u793a\u7684\u662f\u8be5\u8fdb\u7a0b\u5728PID Namespace\u4e2d\u7684PID\u53f7\uff0c\u800c ps aux \u547d\u4ee4\u53ea\u4f1a\u663e\u793a\u5f53\u524dPID Namespace\u4e2d\u7684\u8fdb\u7a0b\uff0c\u4e0d\u4f1a\u663e\u793a\u4e3b\u673a\u4e0a\u7684\u5176\u4ed6\u8fdb\u7a0b\u3002 Primitives Namespace\u793a\u4f8b\uff1a \u5728Docker\u5bb9\u5668\u4e2d\uff0c\u53ef\u4ee5\u4f7f\u7528Filesystem Namespace\u6765\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\uff0c\u4f7f\u5f97\u4e0d\u540c\u7684\u5bb9\u5668\u4e4b\u95f4\u62e5\u6709\u72ec\u7acb\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u3002\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\uff1a # \u5728\u5bb9\u5668\u4e2d\u8fd0\u884c\u4e00\u4e2a\u547d\u4ee4 docker run --rm -it --name mycontainer ubuntu bash # \u5728\u5bb9\u5668\u4e2d\u521b\u5efa\u4e00\u4e2a\u6587\u4ef6\u5e76\u9000\u51fa touch myfile exit # \u5728\u4e3b\u673a\u4e0a\u67e5\u770b\u6587\u4ef6 ls myfile # myfile\u6587\u4ef6\u4e0d\u5b58\u5728 # \u518d\u6b21\u8fdb\u5165\u5bb9\u5668 docker start -i mycontainer # \u5728\u5bb9\u5668\u4e2d\u67e5\u770b\u6587\u4ef6 ls myfile # myfile\u6587\u4ef6\u5b58\u5728 \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c docker run \u547d\u4ee4\u542f\u52a8\u4e86\u4e00\u4e2a\u65b0\u7684Docker\u5bb9\u5668\uff0c\u5e76\u5728\u5176\u4e2d\u8fd0\u884c\u4e86\u4e00\u4e2abash\u8fdb\u7a0b\u3002\u7531\u4e8e\u8be5\u5bb9\u5668\u4f7f\u7528\u4e86Filesystem Namespace\uff0c\u56e0\u6b64\u5bb9\u5668\u5185\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u4e0e\u4e3b\u673a\u4e0a\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u662f\u9694\u79bb\u7684\u3002\u5728\u5bb9\u5668\u5185\u521b\u5efa\u7684\u6587\u4ef6 myfile \u53ea\u5b58\u5728\u4e8e\u5bb9\u5668\u5185\u90e8\uff0c\u5728\u4e3b\u673a\u4e0a\u662f\u770b\u4e0d\u5230\u7684\u3002\u5f53\u518d\u6b21\u8fdb\u5165\u5bb9\u5668\u65f6\uff0c myfile \u6587\u4ef6\u5c31\u53ef\u4ee5\u88ab\u770b\u5230\u4e86\u3002 \u603b\u7ed3\uff1a Namespace\u662fLinux\u5185\u6838\u63d0\u4f9b\u7684\u673a\u5236\uff0c\u800cPrimitives Namespace\u5219\u662f\u4e00\u79cd\u57fa\u4e8eNamespace\u7684\u9ad8\u5c42\u62bd\u8c61\uff0c\u7528\u4e8e\u5b9e\u73b0\u5e94\u7528\u7ea7\u522b\u7684\u9694\u79bb\u548c\u5c01\u88c5\u3002Namespace\u53ef\u4ee5\u7528\u4e8e\u9694\u79bb\u591a\u79cd\u8d44\u6e90\uff0c\u800cPrimitives Namespace\u901a\u5e38\u7528\u4e8e\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\u3001\u7f51\u7edc\u3001\u8fdb\u7a0b\u7b49\u64cd\u4f5c\u7684\u539f\u8bed\u3002 \u63a7\u5236\u7ec4 \u00b6 cgroup\uff0c\u5168\u79f0\u4e3aControl Group\uff0c\u5373\u63a7\u5236\u7ec4\uff0c\u662fLinux\u5185\u6838\u63d0\u4f9b\u7684\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u9650\u5236\u3001\u8bb0\u5f55\u3001\u9694\u79bb\u548c\u4f18\u5148\u7ea7\u63a7\u5236\u4e00\u7ec4\u8fdb\u7a0b\u7684\u8d44\u6e90\u4f7f\u7528\u3002\u5b83\u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7ec4\u7684CPU\u3001\u5185\u5b58\u3001\u78c1\u76d8\u3001\u7f51\u7edc\u7b49\u8d44\u6e90\u7684\u4f7f\u7528\uff0c\u540c\u65f6\u4e5f\u53ef\u4ee5\u8bb0\u5f55\u8fdb\u7a0b\u7ec4\u7684\u8d44\u6e90\u4f7f\u7528\u60c5\u51b5\u548c\u884c\u4e3a\u3002 cgroup\u901a\u8fc7\u5c06\u4e00\u7ec4\u8fdb\u7a0b\u7ec4\u7ec7\u6210\u4e00\u4e2a\u5c42\u6b21\u7ed3\u6784\uff0c\u5c06\u8d44\u6e90\u5206\u914d\u7ed9\u4e0d\u540c\u7684cgroup\u6765\u5b9e\u73b0\u8d44\u6e90\u9650\u5236\u548c\u4f18\u5148\u7ea7\u63a7\u5236\u3002\u6bcf\u4e2acgroup\u53ef\u4ee5\u8bbe\u7f6e\u8d44\u6e90\u9650\u5236\u548c\u63a7\u5236\u7b56\u7565\uff0c\u4f8b\u5982\u53ef\u4ee5\u9650\u5236\u4e00\u4e2a\u8fdb\u7a0b\u7ec4\u6700\u591a\u4f7f\u752850%\u7684CPU\u65f6\u95f4\uff0c\u6216\u8005\u9650\u5236\u4e00\u4e2a\u8fdb\u7a0b\u7ec4\u6700\u591a\u4f7f\u7528100MB\u7684\u5185\u5b58\u7b49\u3002 cgroup\u6700\u521d\u7531Google\u516c\u53f8\u5f00\u53d1\uff0c\u540e\u6765\u88abLinux\u5185\u6838\u793e\u533a\u91c7\u7eb3\u5e76\u52a0\u5165\u5230\u5185\u6838\u4e2d\uff0c\u6210\u4e3aLinux\u7cfb\u7edf\u7684\u4e00\u90e8\u5206\u3002\u5b83\u5728\u5bb9\u5668\u6280\u672f\u3001\u865a\u62df\u5316\u3001\u4e91\u8ba1\u7b97\u7b49\u9886\u57df\u90fd\u6709\u5e7f\u6cdb\u7684\u5e94\u7528\u3002 \u4e0b\u9762\u662fcgroup \u7684\u4e00\u4e9b\u5e38\u89c1\u7528\u9014\uff1a CPU \u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684 CPU \u4f7f\u7528\u7387\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684 CPU \u8d44\u6e90\u5bfc\u81f4\u7cfb\u7edf\u8d1f\u8f7d\u8fc7\u9ad8\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u7a33\u5b9a\u6027\u548c\u5176\u4ed6\u8fdb\u7a0b\u7684\u6b63\u5e38\u8fd0\u884c\u3002 \u5185\u5b58\u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684\u5185\u5b58\u4f7f\u7528\u91cf\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684\u5185\u5b58\u8d44\u6e90\u5bfc\u81f4\u7cfb\u7edf\u5185\u5b58\u4e0d\u8db3\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u6027\u80fd\u548c\u5176\u4ed6\u8fdb\u7a0b\u7684\u6b63\u5e38\u8fd0\u884c\u3002 IO \u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684 IO \u5e26\u5bbd\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684 IO \u8d44\u6e90\u5bfc\u81f4\u5176\u4ed6\u8fdb\u7a0b\u7684 IO \u64cd\u4f5c\u53d7\u5230\u5f71\u54cd\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u6027\u80fd\u548c\u54cd\u5e94\u901f\u5ea6\u3002 \u7f51\u7edc\u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684\u7f51\u7edc\u5e26\u5bbd\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684\u7f51\u7edc\u8d44\u6e90\u5bfc\u81f4\u7f51\u7edc\u62e5\u585e\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u6027\u80fd\u548c\u5176\u4ed6\u8fdb\u7a0b\u7684\u6b63\u5e38\u8fd0\u884c\u3002 \u8fdb\u7a0b\u63a7\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684\u542f\u52a8\u3001\u505c\u6b62\u548c\u8c03\u5ea6\u7b49\u884c\u4e3a\uff0c\u4ece\u800c\u5b9e\u73b0\u5bf9\u7cfb\u7edf\u8fdb\u7a0b\u7684\u63a7\u5236\u548c\u7ba1\u7406\u3002 \u8d44\u6e90\u7edf\u8ba1\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u5b9e\u65f6\u7edf\u8ba1\u7cfb\u7edf\u4e2d\u5404\u4e2a\u8fdb\u7a0b\u7684\u8d44\u6e90\u4f7f\u7528\u60c5\u51b5\uff0c\u4ece\u800c\u5e2e\u52a9\u7ba1\u7406\u5458\u4e86\u89e3\u7cfb\u7edf\u8d1f\u8f7d\u72b6\u51b5\u548c\u5404\u4e2a\u8fdb\u7a0b\u7684\u6027\u80fd\u74f6\u9888\uff0c\u4ece\u800c\u91c7\u53d6\u76f8\u5e94\u7684\u63aa\u65bd\u4f18\u5316\u7cfb\u7edf\u6027\u80fd\u3002 \u4e0b\u9762\u662fopenSUSE\u4e2d\u7684\u793a\u4f8b\uff1a \u5b89\u88c5\u9700\u8981\u7684\u8f6f\u4ef6\u5305\uff1a sudo zypper install libcgroup-tools \u9650\u5236CPU\u4f7f\u7528\u4e0a\u9650\uff1a # \u521b\u5efa\u65b0\u7684cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/cpu/mygroup # \u7cfb\u7edf\u4f1a\u521b\u5efa\u9ed8\u8ba4\u7684\u4e00\u4e9b\u6587\u4ef6\uff0c\u542b\u521d\u59cb\u503c\uff0c\u6bd4\u5982CPU\u4f7f\u7528\u65f6\u95f4\u7684\u9650\u989d\u7684\u9ed8\u8ba4\u503c\u662f-1 cat /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us # \u8bbe\u5b9aCPU\u4f7f\u7528\u65f6\u95f4\u4e0a\u9650 sudo sh -c \"echo 50000 > /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us\" # \u542f\u52a8\u4e00\u4e2a\u65b0\u7684\u8fdb\u7a0b\uff0c\u5e76\u4e14\u5173\u8054\u5230 sudo cgcreate -g cpu:mygroup sudo cgexec -g cpu:mygroup /bin/bash \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c cpu.cfs_quota_us \u6587\u4ef6\u8bbe\u7f6e\u4e86 cgroup \u4e2d\u7684\u8fdb\u7a0b\u53ef\u4ee5\u4f7f\u7528\u7684\u6700\u5927 CPU \u65f6\u95f4\u3002\u8be5\u503c\u4ee5\u5fae\u79d2\u4e3a\u5355\u4f4d\uff0c\u56e0\u6b64\u5c06\u5176\u8bbe\u7f6e\u4e3a 50000 \u8868\u793a\u8fdb\u7a0b\u6700\u591a\u53ef\u4ee5\u4f7f\u7528\u5355\u4e2a CPU \u6838\u5fc3\u7684 50%\u3002 cgcreate \u548c cgexec \u547d\u4ee4\u521b\u5efa\u5e76\u5c06\u8fdb\u7a0b /bin/bash \u79fb\u52a8\u5230 mygroup cgroup \u4e2d\u3002 \u9650\u5236\u5185\u5b58\u4f7f\u7528\u4e0a\u9650\uff1a # \u521b\u5efa\u65b0\u7684cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/memory/mygroup # \u7cfb\u7edf\u4f1a\u521b\u5efa\u9ed8\u8ba4\u7684\u4e00\u4e9b\u6587\u4ef6\uff0c\u542b\u521d\u59cb\u503c\uff0c\u6bd4\u5982\u5185\u5b58\u4f7f\u7528\u4e0a\u9650\u7684\u9ed8\u8ba4\u503c\u662f9223372036854771712 cat /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes # \u8bbe\u7f6e\u5185\u5b58\u4f7f\u7528\u4e0a\u9650512MB sudo sh -c \"echo 536870912 > /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes\" # \u542f\u52a8\u4e00\u4e2a\u65b0\u7684\u8fdb\u7a0b\uff0c\u5e76\u4e14\u5173\u8054\u5230'mygroup' sudo cgcreate -g memory:mygroup sudo cgexec -g memory:mygroup /bin/bash \u5728\u4e0a\u9762\u4f8b\u5b50\u4e2d\uff0c memory.limit_in_bytes \u6587\u4ef6\u8bbe\u7f6e\u4e86 cgroup \u4e2d\u8fdb\u7a0b\u53ef\u4ee5\u4f7f\u7528\u7684\u6700\u5927\u5185\u5b58\u91cf\u3002\u8be5\u503c\u4ee5\u5b57\u8282\u4e3a\u5355\u4f4d\uff0c\u56e0\u6b64\u5c06\u5176\u8bbe\u7f6e\u4e3a 536870912 \u8868\u793a\u8fdb\u7a0b\u6700\u591a\u53ef\u4ee5\u4f7f\u7528 512MB \u7684\u5185\u5b58\u3002 \u8bbe\u7f6e\u4f18\u5148\u8fdb\u7a0b\u7684 I/O \u4f7f\u7528\u7387\uff1a # \u521b\u5efa\u65b0cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/blkio/mygroup # \u8bbe\u7f6e\u8fdb\u7a0b\u6700\u5927\u8bfb\u548c\u5199\u7684\u901f\u738710MB/s sudo sh -c \"echo '8:0 10485760' > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.read_bps_device\" sudo sh -c \"echo '8:0 10485760' > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.write_bps_device\" # \u542f\u52a8\u4e00\u4e2a\u65b0\u7684\u8fdb\u7a0b\uff0c\u5e76\u4e14\u5173\u8054\u5230'mygroup' sudo cgcreate -g blkio:mygroup sudo cgexec -g blkio:mygroup /bin/bash \u5728\u4e0a\u9762\u4f8b\u5b50\u4e2d\uff0c blkio.throttle.read_bps_device \u548c blkio.throttle.write_bps_device \u6587\u4ef6\u8bbe\u7f6e\u4e86cgroup\u4e2d\u8fdb\u7a0b\u53ef\u4ee5\u4f7f\u7528\u7684\u6700\u5927\u8bfb\u53d6\u548c\u5199\u5165\u5e26\u5bbd\u3002\u8be5\u503c\u4ee5\u6bcf\u79d2\u5b57\u8282\u6570\u4e3a\u5355\u4f4d\uff0c\u56e0\u6b64\u5c06\u5176\u8bbe\u7f6e\u4e3a10485760\u610f\u5473\u7740\u8fdb\u7a0b\u5728\u4e3b\u8bbe\u5907\u53f7:\u6b21\u8bbe\u5907\u53f7\u4e3a8:0\u7684\u8bbe\u5907\uff08\u901a\u5e38\u662f\u7b2c\u4e00\u4e2a\u786c\u76d8\uff09\u4e0a\u8bfb\u53d6\u6216\u5199\u5165\u7684\u5e26\u5bbd\u6700\u591a\u4e3a10MB/s\u3002 \u5c06 8:0 10485760 \u8fd9\u4e2a\u5b57\u7b26\u4e32\u5199\u5165\u5230 /sys/fs/cgroup/blkio/mygroup/blkio.throttle.read_bps_device \u6587\u4ef6\u4e2d\u7684\u4f5c\u7528\u662f\u9650\u5236 mygroup \u63a7\u5236\u7ec4\u4e2d\u5173\u8054\u7684\u5757\u8bbe\u5907\uff08block device\uff09\u7684\u8bfb\u53d6\u901f\u7387\u3002 \u5728 Linux \u4e2d\uff0c blkio \u63a7\u5236\u7ec4\u5b50\u7cfb\u7edf\u53ef\u4ee5\u7528\u6765\u5bf9\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u7684\u5757\u8bbe\u5907\u8bbf\u95ee\u8fdb\u884c\u9650\u5236\uff0c\u5982\u9650\u5236\u8bfb\u5199\u901f\u7387\u3001I/O \u4f18\u5148\u7ea7\u7b49\u3002\u800c blkio.throttle.read_bps_device \u8fd9\u4e2a\u6587\u4ef6\u5219\u7528\u4e8e\u8bbe\u7f6e\u67d0\u4e2a\u5757\u8bbe\u5907\u7684\u8bfb\u53d6\u901f\u7387\u9650\u5236\u3002 \u5177\u4f53\u6765\u8bf4\uff0c 8:0 \u8868\u793a\u8bbe\u5907\u7684\u4e3b\u6b21\u7f16\u53f7\uff08major:minor\uff09\uff0c\u8fd9\u91cc\u662f\u6307\u78c1\u76d8 /dev/sda \u3002 10485760 \u5219\u662f\u8bfb\u53d6\u901f\u7387\u7684\u9650\u5236\u503c\uff0c\u5355\u4f4d\u662f\u5b57\u8282/\u79d2\u3002\u8fd9\u4e2a\u503c\u8868\u793a /dev/sda \u6700\u5927\u8bfb\u53d6\u901f\u7387\u4e3a 10MB/s\uff0c\u8d85\u8fc7\u8fd9\u4e2a\u901f\u7387\u7684\u8bfb\u53d6\u8bf7\u6c42\u4f1a\u88ab\u5ef6\u8fdf\u6267\u884c\uff0c\u4ece\u800c\u9650\u5236\u4e86\u78c1\u76d8\u7684\u8bfb\u53d6\u5e26\u5bbd\u3002 \u56e0\u6b64\uff0c\u4ee5\u4e0a\u547d\u4ee4\u7684\u542b\u4e49\u662f\u5c06 mygroup \u63a7\u5236\u7ec4\u4e2d\u5173\u8054\u7684 /dev/sda \u78c1\u76d8\u7684\u8bfb\u53d6\u901f\u7387\u9650\u5236\u4e3a 10MB/s\uff0c\u4ece\u800c\u5b9e\u73b0\u5bf9\u8be5\u63a7\u5236\u7ec4\u4e2d\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u5bf9\u78c1\u76d8\u8bfb\u53d6\u7684\u9650\u5236\u3002 \u540c\u7406\uff0c\u5c06 8:0 10485760 \u8fd9\u4e2a\u5b57\u7b26\u4e32\u5199\u5165\u5230 /sys/fs/cgroup/blkio/mygroup/blkio.throttle.write_bps_device \u6587\u4ef6\u4e2d\uff0c\u4ee5\u9650\u5236 mygroup \u63a7\u5236\u7ec4\u4e2d\u5173\u8054\u7684\u5757\u8bbe\u5907\uff08block device\uff09\u7684\u5199\u5165\u901f\u7387\u3002 \u9650\u5236\u4e00\u7ec4\u8fdb\u7a0b\u7684\u7f51\u7edc\u5e26\u5bbd\uff1a # \u521b\u5efa\u65b0\u7684cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/net_cls/mygroup # \u5c06\u6b64\u7ec4\u4e2d\u7684\u8fdb\u7a0b\u7684\u7f51\u7edc\u7c7bID\u8bbe\u7f6e\u4e3a\u201cmyclass\u201d sudo sh -c \"echo 0x10001 > /sys/fs/cgroup/net_cls/mygroup/net_cls.classid\" \u4e0a\u9762\u7684\u4f8b\u5b50\u662f\u5c06 0x10001 \u8fd9\u4e2a\u5341\u516d\u8fdb\u5236\u6570\u503c\u5199\u5165\u5230 /sys/fs/cgroup/net_cls/mygroup/net_cls.classid \u6587\u4ef6\u4e2d\uff0c\u4ee5\u6307\u5b9a mygroup \u63a7\u5236\u7ec4\u7684\u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\uff08classid\uff09\u3002 \u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\u662f Linux \u5185\u6838\u4e2d\u7528\u6765\u5b9e\u73b0\u6d41\u91cf\u63a7\u5236\u548c\u6d41\u91cf\u5206\u7c7b\u7684\u4e00\u4e2a\u673a\u5236\uff0c\u5b83\u53ef\u4ee5\u5c06\u6570\u636e\u5305\u6309\u7167\u4e0d\u540c\u7684\u7c7b\u522b\uff08class\uff09\u8fdb\u884c\u6807\u8bb0\u548c\u533a\u5206\uff0c\u7136\u540e\u5728\u7f51\u7edc\u8bbe\u5907\u4e0a\u9488\u5bf9\u4e0d\u540c\u7684\u7c7b\u522b\u8fdb\u884c\u4e0d\u540c\u7684\u5904\u7406\uff0c\u5982\u9650\u901f\u3001\u4f18\u5148\u7ea7\u8c03\u6574\u7b49\u3002\u63a7\u5236\u7ec4\u4e2d\u7684 net_cls \u5b50\u7cfb\u7edf\u53ef\u4ee5\u7528\u6765\u5c06\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u4e0e\u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\u5173\u8054\u8d77\u6765\uff0c\u4ece\u800c\u5b9e\u73b0\u5bf9\u5b83\u4eec\u7684\u7f51\u7edc\u6d41\u91cf\u8fdb\u884c\u63a7\u5236\u548c\u5206\u7c7b\u3002 \u56e0\u6b64\uff0c\u4ee5\u4e0a\u547d\u4ee4\u662f\u5c06 mygroup \u63a7\u5236\u7ec4\u7684\u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\u8bbe\u7f6e\u4e3a 0x10001 \uff0c\u8fd9\u6837\u4e0e\u8be5\u63a7\u5236\u7ec4\u76f8\u5173\u8054\u7684\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u5c31\u4f1a\u88ab\u6807\u8bb0\u4e3a\u8be5\u7c7b\u522b\uff0c\u7136\u540e\u53ef\u4ee5\u901a\u8fc7\u5176\u4ed6\u5de5\u5177\uff08\u5982 tc \u547d\u4ee4\uff09\u5bf9\u5176\u8fdb\u884c\u7f51\u7edc\u6d41\u91cf\u63a7\u5236\u548c\u5206\u7c7b\u3002 \u5982\u679c\u9047\u5230\u5bf9\u5e94\u9650\u5236\u6587\u4ef6\u4e0d\u5b58\u5728\uff0c\u4e00\u79cd\u53ef\u80fd\u662f\u9700\u8981\u68c0\u67e5cgroup\u5b50\u7cfb\u6709\u6ca1\u6709\u6b63\u786e\u7edf\u8f7d\u6216\u8005\u6ca1\u6709\u542f\u7528\u5185\u5b58\u5b50\u7cfb\u7edf\u3002 mount | grep cgroup \u5982\u679c cgroups \u6587\u4ef6\u7cfb\u7edf\u5df2\u7ecf\u6302\u8f7d\uff0c\u5e94\u8be5\u4f1a\u770b\u5230\u8f93\u51fa\u7c7b\u4f3c\u4e8e\u4ee5\u4e0b\u5185\u5bb9\uff08\uff09\u4ee5memory\u4e3a\u4f8b\uff09\uff1a cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory) \u5982\u679c\u6ca1\u6709\u770b\u5230 memory \u5b57\u6bb5\uff0c\u5219\u8868\u793a\u5185\u5b58\u5b50\u7cfb\u7edf\u6ca1\u6709\u542f\u7528\u3002\u53ef\u4ee5\u7f16\u8f91 /etc/default/grub \u6587\u4ef6\uff0c\u6dfb\u52a0\u6216\u4fee\u6539\u4ee5\u4e0b\u884c\uff1a GRUB_CMDLINE_LINUX_DEFAULT=\"cgroup_enable=memory\" \u7136\u540e\u66f4\u65b0 GRUB \u914d\u7f6e\u5e76\u91cd\u542f\u7cfb\u7edf\uff1a sudo update-grub sudo reboot \u91cd\u542f\u540e\u518d\u6b21\u68c0\u67e5 /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes \u6587\u4ef6\u662f\u5426\u5b58\u5728\u3002\u5982\u679c\u8fd8\u662f\u4e0d\u5b58\u5728\uff0c\u53ef\u80fd\u9700\u8981\u624b\u52a8\u521b\u5efa\u5b83\u4ee5\u53ca\u5176\u4ed6\u76f8\u5173\u7684 cgroups \u6587\u4ef6\u3002\u4f8b\u5982\uff0c\u8fd0\u884c\u4ee5\u4e0b\u547d\u4ee4\uff1a sudo mkdir /sys/fs/cgroup/memory/mygroup sudo touch /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes \u7136\u540e\u5c31\u53ef\u4ee5\u50cf\u4e4b\u524d\u7684\u4f8b\u5b50\u4e00\u6837\u8bbe\u7f6e\u5185\u5b58\u9650\u5236\u4e86 Apparmor\u548cSELinux\u914d\u7f6e\u6587\u4ef6 \u00b6 \u5b89\u5168\u914d\u7f6e\u6587\u4ef6\uff0c\u7528\u4e8e\u63a7\u5236\u5bf9\u8d44\u6e90\u7684\u8bbf\u95ee AppArmor \u548c SELinux \u90fd\u662f\u5e38\u89c1\u7684\u5f3a\u5236\u8bbf\u95ee\u63a7\u5236\uff08MAC\uff09\u673a\u5236\uff0c\u53ef\u4ee5\u5bf9\u8fdb\u7a0b\u6216\u5e94\u7528\u7a0b\u5e8f\u7684\u8bbf\u95ee\u6743\u9650\u8fdb\u884c\u7cbe\u7ec6\u63a7\u5236\u3002\u4e0b\u9762\u5206\u522b\u4e3e\u4f8b\u8bf4\u660e\u8fd9\u4e24\u79cd\u673a\u5236\u7684\u914d\u7f6e\u6587\u4ef6\u4f7f\u7528\u3002 AppArmor AppArmor \u7684\u4e3b\u914d\u7f6e\u6587\u4ef6\u662f /etc/apparmor/profiles.d/ \u76ee\u5f55\u4e0b\u7684\u5404\u4e2a\u6587\u4ef6\uff0c\u6bcf\u4e2a\u6587\u4ef6\u5bf9\u5e94\u4e00\u4e2a\u5e94\u7528\u7a0b\u5e8f\u6216\u8fdb\u7a0b\u7684\u914d\u7f6e\u3002\u4ee5 sshd \u670d\u52a1\u4e3a\u4f8b\uff0c\u8be5\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6\u662f /etc/apparmor.d/usr.sbin.sshd \u3002 \u8be5\u914d\u7f6e\u6587\u4ef6\u7684\u5185\u5bb9\u7c7b\u4f3c\u4e8e\u4e0b\u9762\u8fd9\u6837\uff1a # Last Modified: Sun Mar 14 18 :53:00 2023 # include /usr/sbin/sshd { # include # include # allow read access to user home directories /home/** r, # allow sshd to execute /usr/bin/which to determine full path of shell /usr/bin/which ix, # allow sshd to read its own configuration file /etc/ssh/sshd_config r, # allow sshd to read the SSH host keys /etc/ssh/ssh_host_* r, # allow sshd to use pam for authentication /usr/share/pam/** r, # allow sshd to use nsswitch for name resolution /etc/nsswitch.conf r, /etc/hosts r, /etc/hostname r, /etc/resolv.conf r, # allow sshd to write to its own log file /var/log/auth.log w, # allow sshd to create and manage pid files /var/run/sshd.pid w, /var/run/sshd.dir/ w, /var/run/sshd.dir/* rw, # allow sshd to access systemd-logind /run/systemd/* r, /run/systemd/session/*.scope r, /run/systemd/sessions/*.scope r, # deny everything else deny /, } \u8be5\u914d\u7f6e\u6587\u4ef6\u5b9a\u4e49\u4e86 /usr/sbin/sshd \u8fdb\u7a0b\u7684\u6743\u9650\u9650\u5236\u89c4\u5219\uff0c\u5305\u62ec\u5141\u8bb8\u8bbf\u95ee\u7684\u6587\u4ef6\u3001\u7981\u6b62\u8bbf\u95ee\u7684\u6587\u4ef6\u7b49\u3002\u5176\u4e2d #include \u8868\u793a\u5305\u542b\u4e86\u4e00\u7ec4\u901a\u7528\u7684\u6743\u9650\u89c4\u5219\uff0c\u53ef\u4ee5\u5728\u4e0d\u540c\u7684\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u4e2d\u91cd\u590d\u4f7f\u7528\u3002 2.SELinux SELinux \u7684\u4e3b\u914d\u7f6e\u6587\u4ef6\u662f /etc/selinux/config \uff0c\u8be5\u6587\u4ef6\u5b9a\u4e49\u4e86\u7cfb\u7edf\u7684 SELinux \u7b56\u7565\u548c\u6a21\u5f0f\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0copenSUSE \u4f7f\u7528\u7684\u662f targeted \u6a21\u5f0f\u3002 \u6bcf\u4e2a\u8fdb\u7a0b\u6216\u5e94\u7528\u7a0b\u5e8f\u8fd8\u9700\u8981\u5bf9\u5e94\u4e00\u4e2a SELinux \u914d\u7f6e\u6587\u4ef6\uff0c\u4ee5\u5b9a\u4e49\u5b83\u4eec\u7684\u8bbf\u95ee\u6743\u9650\u3002\u4ee5 httpd \u670d\u52a1\u4e3a\u4f8b\uff0c\u8be5\u670d\u52a1\u7684 SELinux \u914d\u7f6e\u6587\u4ef6\u662f /etc/selinux/targeted/contexts/httpd.te \u3002 \u8be5\u914d\u7f6e\u6587\u4ef6\u7684\u5185\u5bb9\u7c7b\u4f3c\u4e8e\u4e0b\u9762\u8fd9\u6837\uff1a # HTTPD server type httpd_t ; type httpd_sys_script_t ; init_daemon_domain ( httpd_t, httpd_sys_script_t ) \u8be5\u914d\u7f6e\u6587\u4ef6\u5b9a\u4e49\u4e86 httpd \u670d\u52a1\u7684 SELinux \u7c7b\u578b\u4e3a httpd_t \uff0c\u5e76\u4f7f\u7528\u4e86 httpd_sys_script_t \u4f5c\u4e3a\u5176\u521d\u59cb\u5316\u57df\u3002\u5176\u4e2d type \u8868\u793a SELinux \u7c7b\u578b\uff0c init_daemon_domain \u5219\u662f\u4e00\u4e2a SELinux \u5b8f\uff0c\u7528\u4e8e\u5b9a\u4e49\u670d\u52a1\u7684\u521d\u59cb\u57df\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u5728 SELinux \u4e2d\uff0c\u8bbf\u95ee\u6743\u9650\u89c4\u5219\u4e0d\u662f\u76f4\u63a5\u5728\u914d\u7f6e\u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\uff0c\u800c\u662f\u901a\u8fc7\u8bbf\u95ee\u63a7\u5236\u7b56\u7565\u548c\u89c4\u5219\u8fdb\u884c\u63a7\u5236\u3002\u8fd9\u4e9b\u7b56\u7565\u548c\u89c4\u5219\u53ef\u4ee5\u4f7f\u7528 SELinux \u5de5\u5177\u96c6\uff08\u5982 semanage \u3001 setsebool \u3001 restorecon \u7b49\uff09\u8fdb\u884c\u7ba1\u7406\u548c\u8bbe\u7f6e\u3002 \u6bd4\u5982\uff0c\u5728openSUSE\u4e2d\u53ef\u4ee5\u770b\u5230 /etc/selinux/semanage.conf \u6587\u4ef6\u548c\u5176\u4e2d\u7684\u914d\u7f6e\u3002 \u5185\u6838\u80fd\u529b \u00b6 \u5185\u6838\u80fd\u529b\uff08Kernel capabilities\uff09 \u6ca1\u6709\u80fd\u529b\uff1aroot\u53ef\u4ee5\u6267\u884c\u6240\u6709\u64cd\u4f5c\uff0c\u5176\u4ed6\u7528\u6237\u53ef\u80fd\u4ec0\u4e48\u4e5f\u505a\u4e0d\u4e86 38\u4e2a\u7ec6\u7c92\u5ea6\u7684\u529f\u80fd\u6765\u63a7\u5236\u6743\u9650 Kernel capabilities \u662f Linux \u5185\u6838\u63d0\u4f9b\u7684\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u63a7\u5236\u8fdb\u7a0b\u5bf9\u7cfb\u7edf\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u3002\u4e0e\u4f20\u7edf\u7684 Unix \u6743\u9650\u673a\u5236\u4e0d\u540c\uff0cKernel capabilities \u53ef\u4ee5\u4f7f\u7ba1\u7406\u5458\u5728\u7cbe\u7ec6\u63a7\u5236\u7cfb\u7edf\u8d44\u6e90\u8bbf\u95ee\u7684\u540c\u65f6\uff0c\u907f\u514d\u5c06\u8fc7\u591a\u6743\u9650\u6388\u4e88\u8fdb\u7a0b\uff0c\u63d0\u9ad8\u4e86\u7cfb\u7edf\u7684\u5b89\u5168\u6027\u3002 \u5728\u4f20\u7edf Unix \u6743\u9650\u673a\u5236\u4e2d\uff0c\u6bcf\u4e2a\u8fdb\u7a0b\u90fd\u6709\u4e00\u4e2a\u6709\u6548\u7528\u6237 ID \u548c\u4e00\u4e2a\u6709\u6548\u7ec4 ID\uff0c\u8fd9\u4e9b ID \u51b3\u5b9a\u4e86\u8be5\u8fdb\u7a0b\u5bf9\u6587\u4ef6\u3001\u8bbe\u5907\u3001\u7f51\u7edc\u7b49\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u3002\u4f46\u662f\uff0c\u8fd9\u79cd\u6743\u9650\u673a\u5236\u4e0d\u591f\u7075\u6d3b\uff0c\u5982\u679c\u8981\u6388\u4e88\u8fdb\u7a0b\u67d0\u4e9b\u7279\u5b9a\u7684\u6743\u9650\uff0c\u53ef\u80fd\u9700\u8981\u5c06\u6240\u6709\u7684\u6743\u9650\u90fd\u6388\u4e88\u7ed9\u5b83\uff0c\u4ece\u800c\u964d\u4f4e\u4e86\u7cfb\u7edf\u7684\u5b89\u5168\u6027\u3002 Kernel capabilities \u63d0\u4f9b\u4e86\u4e00\u79cd\u66f4\u7ec6\u7c92\u5ea6\u7684\u6743\u9650\u63a7\u5236\u65b9\u5f0f\u3002\u6bcf\u4e2a\u8fdb\u7a0b\u90fd\u6709\u4e00\u7ec4 capabilities\uff0c\u6bcf\u4e2a capability \u8868\u793a\u4e00\u79cd\u7279\u5b9a\u7684\u6743\u9650\u3002\u8fdb\u7a0b\u53ef\u4ee5\u8bf7\u6c42\u548c\u91ca\u653e\u67d0\u4e9b capability\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u5c06\u6743\u9650\u6388\u4e88\u8fdb\u7a0b\uff0c\u800c\u4e0d\u5fc5\u6388\u4e88\u6240\u6709\u6743\u9650\u3002 \u4f8b\u5982\uff0c\u53ef\u4ee5\u5c06 CAP_NET_BIND_SERVICE capability \u6388\u4e88\u67d0\u4e2a\u8fdb\u7a0b\uff0c\u8fd9\u6837\u8be5\u8fdb\u7a0b\u5c31\u53ef\u4ee5\u7ed1\u5b9a 1-1023 \u7684\u7aef\u53e3\uff0c\u800c\u4e0d\u5fc5\u5177\u6709 root \u6743\u9650\u3002\u7c7b\u4f3c\u5730\uff0c\u53ef\u4ee5\u5c06 CAP_SYS_ADMIN capability \u6388\u4e88\u67d0\u4e2a\u8fdb\u7a0b\uff0c\u8fd9\u6837\u8be5\u8fdb\u7a0b\u5c31\u53ef\u4ee5\u6267\u884c\u7cfb\u7edf\u7ba1\u7406\u4efb\u52a1\uff0c\u5982\u6302\u8f7d\u6587\u4ef6\u7cfb\u7edf\u548c\u521b\u5efa\u8bbe\u5907\u8282\u70b9\u7b49\u3002 Linux \u5185\u6838\u63d0\u4f9b\u4e86\u4e00\u7ec4\u9ed8\u8ba4\u7684 capabilities\uff0c\u4e5f\u53ef\u4ee5\u901a\u8fc7\u81ea\u5b9a\u4e49\u7684\u65b9\u5f0f\u521b\u5efa\u65b0\u7684 capabilities\uff0c\u4ee5\u4fbf\u66f4\u597d\u5730\u63a7\u5236\u7cfb\u7edf\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u3002\u53ef\u4ee5\u4f7f\u7528 setcap \u547d\u4ee4\u4e3a\u4e8c\u8fdb\u5236\u6587\u4ef6\u8bbe\u7f6e capabilities\u3002\u4f8b\u5982\uff0c\u4e0b\u9762\u7684\u547d\u4ee4\u5c06 CAP_NET_RAW capability \u6388\u4e88 /usr/bin/ping \u547d\u4ee4\uff1a sudo setcap cap_net_raw+ep /usr/bin/ping \u8fd9\u6837\uff0c\u7528\u6237\u5c31\u53ef\u4ee5\u4f7f\u7528 ping \u547d\u4ee4\u800c\u4e0d\u5fc5\u4ee5 root \u7528\u6237\u7684\u8eab\u4efd\u767b\u5f55\u3002 \u9664\u4e86 CAP_NET_BIND_SERVICE \u548c CAP_SYS_ADMIN \uff0c\u8fd8\u6709\u4e00\u4e9b\u5176\u4ed6\u7684 capabilities\uff0c\u4ee5\u4e0b\u662f\u4e00\u4e9b\u4f8b\u5b50\uff1a CAP_DAC_OVERRIDE \uff1a\u5141\u8bb8\u8fdb\u7a0b\u5ffd\u7565\u6587\u4ef6\u6743\u9650\uff0c\u53ef\u4ee5\u8bbf\u95ee\u4efb\u4f55\u6587\u4ef6\u3002 CAP_CHOWN \uff1a\u5141\u8bb8\u8fdb\u7a0b\u4fee\u6539\u6587\u4ef6\u7684\u6240\u6709\u8005\u3002 CAP_SETUID \u548c CAP_SETGID \uff1a\u5141\u8bb8\u8fdb\u7a0b\u4fee\u6539\u81ea\u5df1\u7684\u7528\u6237 ID \u548c\u7ec4 ID\u3002 CAP_NET_ADMIN \uff1a\u5141\u8bb8\u8fdb\u7a0b\u6267\u884c\u7f51\u7edc\u7ba1\u7406\u4efb\u52a1\uff0c\u5982\u914d\u7f6e\u7f51\u7edc\u63a5\u53e3\u548c\u8def\u7531\u8868\u7b49\u3002 CAP_SYS_RESOURCE \uff1a\u5141\u8bb8\u8fdb\u7a0b\u4fee\u6539\u7cfb\u7edf\u8d44\u6e90\u9650\u5236\uff0c\u5982 CPU \u65f6\u95f4\u548c\u5185\u5b58\u9650\u5236\u7b49\u3002 \u53ef\u4ee5\u901a\u8fc7\u547d\u4ee4 man 7 capabilities \u6765\u67e5\u770b\u7cfb\u7edf\u63d0\u4f9b\u7684 capabilities \u5217\u8868\u548c\u8be6\u7ec6\u8bf4\u660e\u3002\u5728\u4f7f\u7528 Kernel capabilities \u65f6\uff0c\u9700\u8981\u6ce8\u610f\uff0c\u53ea\u6709\u62e5\u6709 CAP_SETFCAP \u6216 CAP_SYS_ADMIN capability \u7684\u8fdb\u7a0b\u624d\u80fd\u591f\u4fee\u6539\u81ea\u5df1\u6216\u5176\u4ed6\u8fdb\u7a0b\u7684 capabilities\uff0c\u8fd9\u4e5f\u662f\u4e3a\u4e86\u4fdd\u62a4\u7cfb\u7edf\u7684\u5b89\u5168\u6027\u3002 \u5982\u679c\u6267\u884c setcap \u547d\u4ee4\u65f6\u51fa\u73b0 \"command not found\" \u7684\u9519\u8bef\uff0c\u8fd9\u901a\u5e38\u610f\u5473\u7740 setcap \u547d\u4ee4\u6240\u5728\u7684\u5305\u5c1a\u672a\u5b89\u88c5\u3002\u5728 openSUSE \u4e2d\uff0csetcap \u547d\u4ee4\u5305\u542b\u5728 libcap-progs \u8f6f\u4ef6\u5305\u4e2d\u3002 \u5728 openSUSE \u7cfb\u7edf\u4e2d\u9700\u8981\u5b89\u88c5 libcap-progs \u8f6f\u4ef6\u5305\uff1a sudo zypper in libcap-progs \u5728 Ubuntu/Debian \u7cfb\u7edf\u4e0a\u9700\u8981\u5b89\u88c5 libcap \u5e93\uff1a sudo apt-get install libcap2-bin \u5728 CentOS/RHEL \u7cfb\u7edf\u4e0a\u9700\u8981\u5b89\u88c5 libcap \u5e93\uff1a sudo yum install libcap-devel \u5b89\u88c5\u5b8c\u6210\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528 setcap \u547d\u4ee4\u4e3a\u4e8c\u8fdb\u5236\u6587\u4ef6\u8bbe\u7f6e capabilities\u3002\u5982\u679c\u8fd8\u662f\u65e0\u6cd5\u627e\u5230 setcap \u547d\u4ee4\uff0c\u53ef\u4ee5\u5c1d\u8bd5\u4f7f\u7528\u5b8c\u6574\u8def\u5f84 /sbin/setcap \u6216\u8005 /usr/sbin/setcap\u3002 seccomp\u7b56\u7565 \u00b6 seccomp\uff08secure computing mode\uff09\u662f Linux \u5185\u6838\u63d0\u4f9b\u7684\u4e00\u79cd\u5b89\u5168\u673a\u5236\uff0c\u5b83\u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u80fd\u591f\u8fdb\u884c\u7684\u7cfb\u7edf\u8c03\u7528\u3002\u901a\u8fc7\u4f7f\u7528 seccomp\uff0c\u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u53ea\u80fd\u591f\u4f7f\u7528\u5fc5\u8981\u7684\u7cfb\u7edf\u8c03\u7528\uff0c\u4ece\u800c\u51cf\u5c11\u7cfb\u7edf\u88ab\u653b\u51fb\u7684\u98ce\u9669\u3002 seccomp \u7b56\u7565\u53ef\u4ee5\u4f7f\u7528 BPF\uff08Berkeley Packet Filter\uff09\u8bed\u8a00\u7f16\u5199\uff0c\u5e76\u4f7f\u7528 seccomp() \u7cfb\u7edf\u8c03\u7528\u52a0\u8f7d\u3002\u4ee5\u4e0b\u662f\u4e00\u4e2a\u4f7f\u7528 seccomp \u7b56\u7565\u9650\u5236\u8fdb\u7a0b\u80fd\u591f\u8fdb\u884c\u7684\u7cfb\u7edf\u8c03\u7528\u7684\u793a\u4f8b\uff1a #include #include #include int main () { // \u521b\u5efa seccomp \u8fc7\u6ee4\u5668 struct sock_filter filter [] = { BPF_STMT ( BPF_LD | BPF_W | BPF_ABS , 0 ), BPF_JUMP ( BPF_JMP | BPF_JEQ | BPF_K , __NR_write , 0 , 1 ), BPF_STMT ( BPF_RET | BPF_K , SECCOMP_RET_ALLOW ), BPF_STMT ( BPF_RET | BPF_K , SECCOMP_RET_KILL ), }; struct sock_fprog prog = { . len = sizeof ( filter ) / sizeof ( filter [ 0 ]), . filter = filter , }; // \u52a0\u8f7d seccomp \u8fc7\u6ee4\u5668 if ( prctl ( PR_SET_SECCOMP , SECCOMP_MODE_FILTER , & prog ) < 0 ) { perror ( \"prctl\" ); return 1 ; } // \u8c03\u7528 write \u7cfb\u7edf\u8c03\u7528 char buf [] = \"Hello, world!\" ; write ( 1 , buf , sizeof ( buf )); return 0 ; } \u4e0a\u8ff0\u4ee3\u7801\u521b\u5efa\u4e86\u4e00\u4e2a seccomp \u8fc7\u6ee4\u5668\uff0c\u4ec5\u5141\u8bb8\u8fdb\u7a0b\u8c03\u7528 write() \u7cfb\u7edf\u8c03\u7528\uff0c\u5176\u4ed6\u7cfb\u7edf\u8c03\u7528\u5747\u4f1a\u88ab\u7981\u6b62\u3002\u53ef\u4ee5\u901a\u8fc7\u7f16\u8bd1\u5e76\u8fd0\u884c\u4e0a\u8ff0\u4ee3\u7801\u6765\u6f14\u793a seccomp \u7b56\u7565\u7684\u4f5c\u7528\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0cseccomp \u7b56\u7565\u53ea\u80fd\u591f\u9650\u5236\u8fdb\u7a0b\u8fdb\u884c\u7684\u7cfb\u7edf\u8c03\u7528\uff0c\u4f46\u4e0d\u80fd\u591f\u9650\u5236\u7cfb\u7edf\u8c03\u7528\u7684\u53c2\u6570\u6216\u8fd4\u56de\u503c\u3002\u56e0\u6b64\uff0c\u4f7f\u7528 seccomp \u7b56\u7565\u65f6\u9700\u8981\u7279\u522b\u5c0f\u5fc3\uff0c\u907f\u514d\u8bef\u7528\u6216\u4ea7\u751f\u6f0f\u6d1e\u3002 Netlink \u00b6 Netlink \u662f\u4e00\u79cd Linux \u5185\u6838\u63d0\u4f9b\u7684\u901a\u4fe1\u673a\u5236\uff0c\u7528\u4e8e\u5185\u6838\u548c\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4e4b\u95f4\u7684\u53cc\u5411\u901a\u4fe1\uff08IPC\uff09\u3002Netlink \u53ef\u4ee5\u7528\u4e8e\u8bb8\u591a\u76ee\u7684\uff0c\u4f8b\u5982\uff1a \u914d\u7f6e\u7f51\u7edc\u8bbe\u5907\u548c\u8def\u7531\u8868\uff1a\u4f7f\u7528 Netlink \u53ef\u4ee5\u901a\u8fc7\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4fee\u6539\u5185\u6838\u7684\u7f51\u7edc\u8bbe\u5907\u548c\u8def\u7531\u8868\u914d\u7f6e\uff0c\u4f8b\u5982\u6dfb\u52a0\u3001\u5220\u9664\u3001\u4fee\u6539\u7f51\u7edc\u63a5\u53e3\u3001IP \u5730\u5740\u3001\u8def\u7531\u7b49\u3002 \u76d1\u89c6\u7f51\u7edc\u4e8b\u4ef6\uff1a\u4f7f\u7528 Netlink \u53ef\u4ee5\u5b9e\u65f6\u5730\u4ece\u5185\u6838\u83b7\u53d6\u7f51\u7edc\u4e8b\u4ef6\u7684\u901a\u77e5\uff0c\u4f8b\u5982\u7f51\u7edc\u63a5\u53e3\u7684\u72b6\u6001\u53d8\u5316\u3001\u8def\u7531\u7684\u53d8\u5316\u7b49\u3002 \u7a0b\u5e8f\u95f4\u901a\u4fe1\uff1a\u4f7f\u7528 Netlink \u53ef\u4ee5\u5728\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4e4b\u95f4\u8fdb\u884c\u901a\u4fe1\uff0c\u7c7b\u4f3c\u4e8e Unix \u57df\u5957\u63a5\u5b57\u3002 Netlink \u673a\u5236\u57fa\u4e8e\u4e00\u79cd\u7279\u6b8a\u7684\u5957\u63a5\u5b57\u7c7b\u578b\uff08PF_NETLINK\uff09\u548c\u4e00\u4e2a\u7279\u5b9a\u7684\u534f\u8bae\uff08NETLINK\uff09\u3002\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u53ef\u4ee5\u901a\u8fc7\u521b\u5efa Netlink \u5957\u63a5\u5b57\u548c\u5185\u6838\u901a\u4fe1\u3002\u5185\u6838\u548c\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4e4b\u95f4\u7684\u901a\u4fe1\u662f\u57fa\u4e8e Netlink \u6d88\u606f\u7684\uff0c\u6bcf\u4e2a Netlink \u6d88\u606f\u5305\u542b\u4e00\u4e2a\u6d88\u606f\u5934\u548c\u4e00\u4e2a\u8d1f\u8f7d\uff08payload\uff09\uff0c\u8d1f\u8f7d\u53ef\u4ee5\u662f\u4efb\u4f55\u7ed3\u6784\u4f53\u6216\u4e8c\u8fdb\u5236\u6570\u636e\u3002 Netlink \u6d88\u606f\u7684\u7c7b\u578b\u548c\u683c\u5f0f\u7531\u5185\u6838\u5b9a\u4e49\u3002\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u9700\u8981\u4e86\u89e3\u5185\u6838\u7684 Netlink \u6d88\u606f\u683c\u5f0f\u548c\u7c7b\u578b\uff0c\u624d\u80fd\u6b63\u786e\u5730\u6784\u9020\u548c\u89e3\u6790 Netlink \u6d88\u606f\u3002\u5e38\u7528\u7684 Netlink \u6d88\u606f\u7c7b\u578b\u5305\u62ec\uff1a RTM_NEWLINK \u548c RTM_DELLINK\uff1a\u6dfb\u52a0\u548c\u5220\u9664\u7f51\u7edc\u63a5\u53e3\u3002 RTM_NEWADDR \u548c RTM_DELADDR\uff1a\u6dfb\u52a0\u548c\u5220\u9664 IP \u5730\u5740\u3002 RTM_NEWROUTE \u548c RTM_DELROUTE\uff1a\u6dfb\u52a0\u548c\u5220\u9664\u8def\u7531\u3002 RTM_NEWNEIGH \u548c RTM_DELNEIGH\uff1a\u6dfb\u52a0\u548c\u5220\u9664 ARP \u8868\u9879\u3002 Netlink \u53ef\u4ee5\u4f7f\u7528 C \u8bed\u8a00\u7684 socket API \u8fdb\u884c\u7f16\u7a0b\u3002 Netfilter \u00b6 Netfilter\u662fLinux\u5185\u6838\u4e2d\u7684\u4e00\u4e2a\u5b50\u7cfb\u7edf\uff0c\u7528\u4e8e\u5728\u6570\u636e\u5305\u4f20\u8f93\u8fc7\u7a0b\u4e2d\u8fdb\u884c\u8fc7\u6ee4\u548c\u64cd\u4f5c\u3002\u5b83\u652f\u6301\u5bf9\u7f51\u7edc\u6570\u636e\u5305\u8fdb\u884c\u5404\u79cd\u7c7b\u578b\u7684\u5904\u7406\uff0c\u5305\u62ec\u8fc7\u6ee4\u3001\u4fee\u6539\u3001\u91cd\u5b9a\u5411\u7b49\u3002Netfilter\u901a\u8fc7\u5728\u5185\u6838\u4e2d\u6ce8\u518c\u94a9\u5b50\u51fd\u6570\uff0c\u5728\u6570\u636e\u5305\u901a\u8fc7\u7f51\u7edc\u6808\u7684\u4e0d\u540c\u9636\u6bb5\u65f6\u8fdb\u884c\u62e6\u622a\u548c\u5904\u7406\u3002 Netfilter\u7684\u6838\u5fc3\u662fiptables\u547d\u4ee4\uff0c\u5b83\u53ef\u4ee5\u7528\u6765\u914d\u7f6eNetfilter\u89c4\u5219\u3002iptables\u547d\u4ee4\u53ef\u4ee5\u7528\u6765\u914d\u7f6e\u9632\u706b\u5899\u89c4\u5219\uff0cNAT\u89c4\u5219\uff0c\u9650\u5236\u8fde\u63a5\u901f\u5ea6\u7b49\u3002iptables\u547d\u4ee4\u901a\u8fc7\u5339\u914d\u4e0d\u540c\u7684\u6570\u636e\u5305\u5b57\u6bb5\uff08\u4f8b\u5982\u6e90IP\u5730\u5740\u3001\u76ee\u7684IP\u5730\u5740\u3001\u6e90\u7aef\u53e3\u3001\u76ee\u7684\u7aef\u53e3\u7b49\uff09\u6765\u8fdb\u884c\u8fc7\u6ee4\u3002 \u9664\u4e86iptables\u547d\u4ee4\uff0c\u8fd8\u6709\u5176\u4ed6\u4e00\u4e9b\u5de5\u5177\u53ef\u4ee5\u7528\u4e8e\u914d\u7f6eNetfilter\u89c4\u5219\uff0c\u4f8b\u5982nftables\u547d\u4ee4\u548cfirewalld\u670d\u52a1\u3002\u8fd9\u4e9b\u5de5\u5177\u63d0\u4f9b\u4e86\u66f4\u7075\u6d3b\u3001\u66f4\u5f3a\u5927\u7684\u914d\u7f6e\u9009\u9879\uff0c\u53ef\u4ee5\u5e2e\u52a9\u7ba1\u7406\u5458\u66f4\u597d\u5730\u7ba1\u7406\u548c\u4fdd\u62a4\u7f51\u7edc\u5b89\u5168\u3002 \u4e5f\u53ef\u4ee5\u7528\u4e8e\u5c06\u7f51\u7edc\u6570\u636e\u5305\u5b9a\u5411\u5230\u5355\u4e2a\u5bb9\u5668\u3002 \u66f4\u591a\u4fe1\u606f\u53ef\u4ee5\u53c2\u8003 LXC/LXD \u3002 \u5b89\u88c5Docker \u00b6 \u53c2\u8003 \u6307\u5bfc \u5b89\u88c5Docker\u5f15\u64ce\u3002 \u53c2\u8003 \u6307\u5bfc \u5b89\u88c5Docker\u684c\u9762\u7248\u3002 \u4e0b\u9762\u4ee5openSUSE\u4e3a\u4f8b\u5b89\u88c5Docker\u5f15\u64ce\u3002 sudo zypper in docker \u5728\u5b89\u88c5\u8fc7\u7a0b\u4e2d\uff0c\u5728\u64cd\u4f5c\u7cfb\u7edf\u4e2d\u4f1a\u81ea\u52a8\u521b\u5efa\u7ec4 docker \u3002 \u5c06vagrant\u7528\u6237\u52a0\u5165docker\u7ec4\uff0c\u5219vagrant\u7528\u6237\u53ef\u4ee5\u5728\u4e0b\u6b21\u767b\u5f55\u540e\u4e0e\u672c\u673a\u7684Docker\u5b88\u62a4\u8fdb\u7a0b\uff08daemon\uff09\u8fdb\u884c\u901a\u4fe1\u3002Docker\u5b88\u62a4\u8fdb\u7a0b\u76d1\u542c\u672c\u5730\u5957\u63a5\u5b57\uff0c\u53ea\u80fd\u7531root\u7528\u6237\u548cdocker\u7ec4\u7684\u6210\u5458\u8bbf\u95ee\u3002 sudo usermod -aG docker $USER \u542f\u7528\u5e76\u542f\u52a8 Docker \u5f15\u64ce\u3002 sudo systemctl enable docker.service sudo systemctl start docker.service sudo systemctl status docker.service \u4e0b\u9762\u901a\u8fc7\u4e00\u4e2a\u5bb9\u5668 alpine \u7684\u4f8b\u5b50\u6765\u6f14\u793a\u5728\u76ee\u5f55 /opt/test \u4e0b\u6a21\u62df\u5b9e\u73b0choot\u3002 mkdir test cd test wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.4-x86_64.tar.gz tar zxvf alpine-minirootfs-3.13.4-x86_64.tar.gz -C alpine-minirootfs/ \u67e5\u770b\u5f53\u524d\u76ee\u5f55\u7ed3\u6784\uff1a tree ./test -L 1 \u8f93\u51fa\u7ed3\u679c\uff1a ./test \u251c\u2500\u2500 alpine-minirootfs-3.13.4-x86_64.tar.gz \u251c\u2500\u2500 bin \u251c\u2500\u2500 dev \u251c\u2500\u2500 etc \u251c\u2500\u2500 home \u251c\u2500\u2500 lib \u251c\u2500\u2500 media \u251c\u2500\u2500 mnt \u251c\u2500\u2500 opt \u251c\u2500\u2500 proc \u251c\u2500\u2500 root \u251c\u2500\u2500 run \u251c\u2500\u2500 sbin \u251c\u2500\u2500 srv \u251c\u2500\u2500 sys \u251c\u2500\u2500 tmp \u251c\u2500\u2500 usr \u2514\u2500\u2500 var \u901a\u8fc7\u547d\u4ee4 unshare \u6302\u8f7d\u76ee\u5f55 /opt/test/proc \u5230\u67d0\u4e2a\u6587\u4ef6\u6765\u5b9e\u73b0\u5ba2\u6237\u5b50\u7cfb\u7edf\u3002 sudo mount -t tmpfs tmpfs /opt/test/proc sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # ps -ef PID USER TIME COMMAND 1 root 0 :00 /bin/sh 2 root 0 :00 ps -ef / # touch 123 / # ls 123 123 \u6587\u4ef6 123 \u5728\u5ba2\u6237\u5b50\u7cfb\u7edf\u4e2d\u5df2\u521b\u5efa\uff0c\u5bf9\u5e94\u4e3b\u7cfb\u7edf\u4e2d\u4e5f\u53ef\u4ee5\u5bf9\u5176\u8fdb\u884c\u8bfb\u5199\u64cd\u4f5c\u3002\u6bd4\u5982\uff0c\u4fee\u6539\u6587\u4ef6 123 \u7684\u5185\u5bb9\u3002 su - ls 123 echo hello > 123 \u6587\u4ef6 123 \u4fee\u6539\u540e\u7684\u5185\u5bb9\u5728\u5ba2\u6237\u673a\u91cc\u9762\u4e5f\u53ef\u89c1\u3002 / # cat 123 hello \u5728\u4e3b\u7cfb\u7edf\u4e2d\u518d\u521b\u5efa\u4e24\u4e2a\u5b50\u76ee\u5f55 /opt/test-1 \u548c /opt/test-2 \u3002 mkdir test-1 mkdir test-2 \u521b\u5efa2\u4e2a\u5ba2\u6237\u5b50\u7cfb\u7edf\uff0c\u5e76\u5c06\u4e0a\u9762\u7684\u4e24\u4e2a\u5b50\u76ee\u5f55\u6302\u5728\u5230\u5404\u81ea\u7684 /opt/test/home/ \u76ee\u5f55\u3002 sudo mount --bind /opt/test-1 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-1\" > 123.1 /home # cat 123.1 test-1 sudo mount --bind /opt/test-2 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-2\" > 123.2 /home # cat 123.2 test-2 ll test/home ll test-1/ ll test-2/ \u901a\u8fc7\u4e0a\u9762\u7684\u6f14\u793a\uff0c\u53ef\u4ee5\u5f97\u51fa\u7ed3\u8bba\uff0c\u4e24\u4e2a\u5ba2\u6237\u5b50\u7cfb\u7edf\u6302\u5728\u5230\u540c\u4e00\u4e2a\u4e3b\u7cfb\u7edf\u76ee\u5f55\u65f6\uff0c\u5b50\u7cfb\u7edf\u65f6\u5171\u4eab\u4e3b\u7cfb\u7edf\u76ee\u5f55\uff0c\u5e76\u76f8\u4e92\u5f71\u54cd\u3002 \u5bb9\u5668\u751f\u547d\u5468\u671f \u00b6 \u6982\u8ff0 \u00b6 \u9884\u5148\u4e0b\u8f7d\u4e0b\u5217\u955c\u50cf\u3002 docker image pull busybox docker image pull nginx docker image pull alpine docker image pull jenkins/jenkins:lts docker image pull golang:1.12-alpine docker image pull golang \u521b\u5efa\u5e76\u4ea4\u4e92\u5f0f\u8fd0\u884c\u4e00\u4e2a\u65b0\u7684busybox\u5bb9\u5668\uff0c\u5e76\u8fde\u63a5\u4e00\u4e2a\u4f2a\u7ec8\u7aef\uff08pseudo terminal\uff09\u3002 \u5728\u5bb9\u5668\u5185\uff0c\u4f7f\u7528 top \u547d\u4ee4\u67e5\u627e /bin/sh \u6b63\u5728\u4f5c\u4e3aPID\u4e3a1\u7684\u8fdb\u7a0b\u8fd0\u884c\uff0c\u4ee5\u53ca top \u8fdb\u7a0b\u4e5f\u5728\u8fd0\u884c\u3002 \u7136\u540e\uff0c\u9000\u51fa\u5bb9\u5668\u3002 docker image ls docker run -d -it --name busybox_v1 -v /opt/test:/docker busybox:latest /bin/sh docker container ps -a docker exec -it 185efe490507 /bin/sh / # top Mem: 3627396K used, 12731512K free, 10080K shrd, 2920K buff, 2999340K cached CPU: 0 .0% usr 0 .1% sys 0 .0% nic 99 .8% idle 0 .0% io 0 .0% irq 0 .0% sirq Load average: 0 .38 1 .09 1 .29 2 /277 14 PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND 1 0 root S 1332 0 .0 1 0 .0 /bin/sh 8 0 root S 1332 0 .0 2 0 .0 /bin/sh 14 8 root R 1328 0 .0 1 0 .0 top / # exitbuild \u542f\u52a8\u4e00\u4e2a\u65b0\u7684 Nginx \u5bb9\u5668\uff0c\u5e76\u4ee5\u72ec\u7acb\u6a21\u5f0f\uff08detached mode\uff09\u8fd0\u884c\u3002 \u4f7f\u7528 docker exec \u547d\u4ee4\u5728 Nginx \u5bb9\u5668\u4e2d\u542f\u52a8\u53e6\u4e00\u4e2a shell\uff08 /bin/sh \uff09\u3002 \u4f7f\u7528 ps \u547d\u4ee4\u67e5\u770b\u5bb9\u5668\u4e2d\u6b63\u5728\u8fd0\u884c\u7684 sh \u548c ps \u547d\u4ee4\uff08\u5728\u4e0a\u4e00\u6b65\u6267\u884c\u7684\uff09\u3002 docker run -d -it --name nginx_v1 -v /opt/test:/docker nginx:latest /bin/sh docker container ps -a docker exec -it edb640127a0d /bin/sh # ps /bin/sh: 2 : ps: not found # apt-get update && apt-get install -y procps # ps PID TTY TIME CMD 8 pts/1 00 :00:00 sh 351 pts/1 00 :00:00 ps # exit \u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u770b\u52302\u4e2a\u73b0\u5728\u8fd0\u884c\u4e2d\u7684\u5bb9\u5668\u3002 docker container ps -a \u4f7f\u7528 docker logs \u547d\u4ee4\u663e\u793a\u6211\u4eec\u521a\u521a\u9000\u51fa\u7684\u5bb9\u5668\u7684\u65e5\u5fd7\u3002\u9009\u9879 --since 35m \u8868\u793a\u663e\u793a\u6700\u8fd1 35 \u5206\u949f\u5185\u7684\u65e5\u5fd7\u3002 docker logs nginx_v1 --details --since 35m docker logs busybox_v1 --details --since 35m \u4f7f\u7528 docker stop \u547d\u4ee4\u6765\u505c\u6b62 nginx \u5bb9\u5668\u3002 docker stop busybox_v1 docker stop nginx_v1 docker container ps -a \u4f7f\u7528\u4e0a\u8ff0\u547d\u4ee4 docker container ps -a \uff0c\u6211\u4eec\u53ef\u4ee5\u83b7\u53d6\u6240\u6709\u6b63\u5728\u8fd0\u884c\u548c\u5df2\u9000\u51fa\u7684\u5bb9\u5668\u5217\u8868\u3002\u4f7f\u7528 docker rm \u5c06\u5176\u5220\u9664\u3002\u4f7f\u7528 docker rm $(docker ps -aq) \u6765\u6e05\u7406\u4e3b\u673a\u4e0a\u7684\u6240\u6709\u5bb9\u5668\u3002\u8bf7\u8c28\u614e\u4f7f\u7528\uff01 docker rm busybox_v1 docker container ps -a \u7aef\u53e3\u548c\u5377 \u00b6 \u73b0\u5728\u542f\u52a8\u4e00\u4e2a\u65b0\u7684 nginx \u5bb9\u5668\uff0c\u5e76\u5c06 nginx web \u670d\u52a1\u5668\u7684\u7aef\u53e3\u5bfc\u51fa\u5230 Docker \u968f\u673a\u9009\u62e9\u7684\u7aef\u53e3\u3002 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u547d\u4ee4 docker ps \u627e\u51fa web \u670d\u52a1\u5668\u8f6c\u53d1\u5230\u4e86\u54ea\u4e2a\u7aef\u53e3\u3002\u5728\u4e3b\u673a\u4e0a\u4f7f\u7528\u8f6c\u53d1\u7684\u7aef\u53e3\u53f7\u8bbf\u95ee docker http://localhost: \u3002 docker container ps -a docker run -d -P --name nginx_v2 nginx:latest docker container ps -a Start another nginx container and expose port to 1080 on host as an example via http://localhost:1080 . \u542f\u52a8\u53e6\u4e00\u4e2anginx\u5bb9\u5668\uff0c\u5c06\u5176\u7aef\u53e3\u6620\u5c04\u5230\u4e3b\u673a\u76841080\u7aef\u53e3\uff0c\u53ef\u4ee5\u901a\u8fc7 http://localhost:1080 \u8bbf\u95ee\u3002 docker run -d -p 1080 :80 --name nginx_v3 nginx:latest docker container ps -a \u4f7f\u7528 docker inspect \u547d\u4ee4\u67e5\u627e\u955c\u50cf\u66b4\u9732\u7684\u7aef\u53e3\u53f7\uff0c\u8f93\u51faJSON\u683c\u5f0f\u6587\u4ef6\uff0c\u7f51\u7edc\u4fe1\u606f\uff08IP\u3001\u7f51\u5173\u3001\u7aef\u53e3\u7b49\uff09\u662f\u8f93\u51faJSON\u683c\u5f0f\u7684\u4e00\u90e8\u5206\u3002 docker inspect nginx_v3 \u5728\u76ee\u5f55 /opt/test \u4e2d\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a index.html \u7684\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u5982\u4e0b\uff1a < html > < head > < title > Sample Website from my container < body > < h1 > This is a custom website. < p > This website is served from my < a href = \"http://www.docker.com\" target = \"_blank\" > Docker container. \u542f\u52a8\u4e00\u4e2a\u65b0\u5bb9\u5668\uff0c\u5c06\u4e3b\u673a\u76ee\u5f55 /opt/test \u4e0e\u5bb9\u5668\u76ee\u5f55 /usr/share/nginx/html \u7ed1\u5b9a\u6302\u8f7d\u4e3a\u4e00\u4e2a\u5377\uff0c\u4ee5\u4fbfNginx\u53ef\u4ee5\u901a\u8fc7 http://localhost:49159/ \u53d1\u5e03\u6211\u4eec\u521a\u521b\u5efa\u7684html\u6587\u4ef6\uff0c\u800c\u4e0d\u662fNginx\u9ed8\u8ba4\u7684\u9875\u9762\u3002 docker run -d -P --mount type = bind,source = /opt/test/,target = /usr/share/nginx/html --name nginx_v3-1 nginx:latest docker container ps -a \u68c0\u67e5Nginx\u914d\u7f6e\u6587\u4ef6\uff0c\u67e5\u770b\u5bb9\u5668\u4e2dhtml\u4e3b\u9875\u5b58\u50a8\u7684\u4f4d\u7f6e\u3002 docker exec -it nginx_v3-1 /bin/sh # cd /etc/nginx/conf.d # ls default.conf # cat default.conf server { listen 80 ; listen [ :: ] :80 ; server_name localhost ; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html ; <-- index index.html index.htm ; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html ; location = /50x.html { root /usr/share/nginx/html ; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \\.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \\.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\\.ht { # deny all; #} } # cd /usr/share/nginx/html # cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    # \u63a8\u8350\u4f7f\u7528\u5377 API \u6765\u5b9e\u73b0\u6570\u636e\u6301\u4e45\u5316\uff0c\u800c\u4e0d\u662f\u5c06\u6570\u636e\u5b58\u50a8\u5728 Docker \u5bb9\u5668\u4e2d\u3002Docker \u652f\u6301\u4e24\u79cd\u6302\u8f7d\u65b9\u5f0f\uff1a \u7ed1\u5b9a\u6302\u8f7d\uff08Bind mounts\uff09\uff1a \u5c06\u672c\u5730\u4e3b\u673a\u76ee\u5f55\u6302\u8f7d\u5230\u5bb9\u5668\u4e2d\u7684\u67d0\u4e2a\u8def\u5f84\u3002 \u6302\u8f7d\u540e\uff0c\u76ee\u6807\u76ee\u5f55\u4e2d\u539f\u6709\u7684\u6240\u6709\u5185\u5bb9\u5c06\u88ab\u9690\u85cf\u3002 \u4f8b\u5982\uff0c\u5982\u679c\u6211\u4eec\u60f3\u8981\u6ce8\u5165\u67d0\u4e9b\u914d\u7f6e\u6587\u4ef6\uff0c\u6211\u4eec\u9700\u8981\u81ea\u5df1\u5199\u5bf9\u5e94\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5c06\u5176\u5b58\u50a8\u5728 Docker \u4e3b\u673a\u4e0a\u7684 /home/container/config \u8def\u5f84\u4e0b\uff0c\u5e76\u5c06\u6b64\u76ee\u5f55\u7684\u5185\u5bb9\u6302\u8f7d\u5230 /usr/application/config \uff08\u5047\u8bbe\u5e94\u7528\u7a0b\u5e8f\u4ece\u6b64\u5904\u8bfb\u53d6\u914d\u7f6e\uff09\u3002 \u547d\u4ee4\uff1a docker run --mount type=bind,source=,target= \u2026 \u547d\u540d\u5377\uff08Named volumes\uff09\uff1a Docker \u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u72ec\u7acb\u7684\u5b58\u50a8\u5377\uff0c\u5176\u751f\u547d\u5468\u671f\u72ec\u7acb\u4e8e\u5bb9\u5668\u4f46\u4ecd\u7531 Docker \u7ba1\u7406\u3002 \u5728\u521b\u5efa\u65f6\uff0c\u6302\u8f7d\u76ee\u6807\u7684\u5185\u5bb9\u5c06\u5408\u5e76\u5230\u5377\u4e2d\u3002 \u547d\u4ee4\uff1a docker run --mount source=,target= \u2026 \u5982\u4f55\u533a\u5206\u7ed1\u5b9a\u6302\u8f7d\u548c\u547d\u540d\u5377\uff1f \u5f53\u6307\u5b9a\u7edd\u5bf9\u8def\u5f84\u65f6\uff0cDocker \u4f1a\u8ba4\u4e3a\u8fd9\u662f\u4e00\u4e2a\u7ed1\u5b9a\u6302\u8f7d\u3002 \u5f53\u6211\u4eec\u4ec5\u63d0\u4f9b\u540d\u79f0\uff08\u5982\u76f8\u5bf9\u8def\u5f84 config \uff09\u65f6\uff0c\u5b83\u4f1a\u8ba4\u4e3a\u8fd9\u662f\u4e00\u4e2a\u547d\u540d\u5377\uff0c\u5e76\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a config \u7684\u5377\u3002 \u6ce8\uff1a\u6301\u4e45\u5b58\u50a8\u7531\u4e3b\u673a\u63d0\u4f9b\uff0c\u53ef\u4ee5\u76f4\u63a5\u662f\u4e3b\u673a\u6587\u4ef6\u7cfb\u7edf\u7684\u4e00\u90e8\u5206\uff0c\u4e5f\u53ef\u4ee5\u662f NFS \u6302\u8f7d\u3002 Dockerfile \u00b6 \u8ba9\u6211\u4eec\u7528 Dockerfile \u6784\u5efa\u4e00\u4e2a\u955c\u50cf\uff0c\u5bf9\u5176\u8fdb\u884c\u6253\u6807\u7b7e\u5e76\u4e0a\u4f20\u5230\u955c\u50cf\u4ed3\u5e93\u3002 \u83b7\u53d6 Docker \u955c\u50cf\u7684\u6784\u5efa\u5386\u53f2\u8bb0\u5f55\u3002 docker image history nginx:latest \u521b\u5efa\u4e00\u4e2a\u7a7a\u7684\u76ee\u5f55 /opt/tmp-1 \uff0c\u8fdb\u5165\u8be5\u76ee\u5f55\u5e76\u5728\u5176\u4e2d\u521b\u5efa index.html \u6587\u4ef6\u3002 /opt/tmp-1> cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    \u4f7f\u7528 FROM \u6765\u6269\u5c55\u4e00\u4e2a\u5df2\u6709\u7684\u955c\u50cf\uff0c\u5e76\u6307\u5b9a\u7248\u672c\u53f7\u3002 \u4f7f\u7528 COPY \u5c06\u4e00\u4e2a\u65b0\u7684\u9ed8\u8ba4\u7f51\u7ad9\u590d\u5236\u5230\u955c\u50cf\u4e2d\uff0c\u4f8b\u5982 /usr/share/nginx/html \u3002 \u4e3aNginx\u521b\u5efaSSL\u914d\u7f6e /opt/tmp-1/ssl.conf \u3002 server { listen 443 ssl; server_name localhost; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; location / { root /usr/share/nginx/html; index index.html index.htm; } } \u4f7f\u7528OpenSSL\u521b\u5efa\u4e00\u4e2a\u81ea\u7b7e\u540d\u8bc1\u4e66\uff0c\u4ee5\u4fbfSSL/TLS\u5de5\u4f5c\u3002 \u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u521b\u5efa\u4e00\u4e2a\u52a0\u5bc6\u5bc6\u94a5\u548c\u8bc1\u4e66\u3002 openssl req -x509 -nodes -newkey rsa:4096 -keyout nginx.key -out nginx.crt -days 365 -subj \"/CN= $( hostname ) \" \u4e3a\u4e86\u542f\u7528\u52a0\u5bc6\u7684HTTPS\uff0c\u6211\u4eec\u9700\u8981\u4f7f\u7528 EXPOSE \u6307\u4ee4\u516c\u5f00 443 \u7aef\u53e3\u3002\u9ed8\u8ba4\u7684nginx\u955c\u50cf\u4ec5\u516c\u5f00\u7aef\u53e3 80 \uff0c\u7528\u4e8e\u975e\u52a0\u5bc6\u7684HTTP\u3002 \u5728 /opt/tmp-1 \u6587\u4ef6\u5939\u4e2d\u521b\u5efa\u4ee5\u4e0bDockerfile\u3002 cat Dockerfile \u8f93\u51fa\uff1a FROM nginx:latest # copy the custom website into the image COPY index.html /usr/share/nginx/html # copy the SSL configuration file into the image COPY ssl.conf /etc/nginx/conf.d/ssl.conf # download the SSL key and certificate into the image COPY nginx.key /etc/nginx/ssl/ COPY nginx.crt /etc/nginx/ssl/ # expose the HTTPS port EXPOSE 443 \u81f3\u6b64\uff0c\u6211\u4eec\u5728\u76ee\u5f55 /opt/tmp-1 \u4e0b\u67095\u4e2a\u6587\u4ef6\u3002 ls /opt/tmp-1 \u8f93\u51fa\uff1a Dockerfile index.html nginx.crt nginx.key ssl.conf \u4f7f\u7528 docker build \u547d\u4ee4\u6765\u6784\u5efa\u955c\u50cf\uff0c\u5e76\u5c06\u5bb9\u5668\u768480\u548c443\u7aef\u53e3\u8f6c\u53d1\u3002 docker build -t nginx:my1 /opt/tmp-1/ docker image ls docker run -d -p 1086 :80 -p 1088 :443 --name nginx_v5 nginx:my1 docker container ps -a \u901a\u8fc7\u4e0b\u9762\u4e24\u4e2a\u94fe\u63a5\u6765\u9a8c\u8bc1\u4e0a\u9762\u7684\u53d8\u5316\u662f\u5426\u751f\u6548\u3002 http://localhost:1086/ https://localhost:1088/ \u5728 DockerHub \u6ce8\u518c\u4e00\u4e2a\u4e2a\u4eba\u8d26\u53f7\uff0c\u542f\u7528 Docker Hub \u4e2d\u7684\u8bbf\u95ee\u4ee4\u724c\u4ee5\u8fdb\u884c CLI \u5ba2\u6237\u7aef\u8eab\u4efd\u9a8c\u8bc1\u3002 docker login \u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002 Username: Password: \u7ed9\u8fd9\u4e2a\u955c\u50cf\u52a0\u4e0a\u4e00\u4e2a\u6807\u7b7e\uff0c\u4f8b\u5982\uff1asecure_nginx_0001\uff0c\u7248\u672c\u53f7\u4e3a v1\u3002 docker tag nginx:my1 secure_nginx_0001:v1 docker push secure_nginx_0001:v1 docker image ls \u591a\u9636\u6bb5Dockerfile \u00b6 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u6f14\u793a\u4e00\u4e2a\u591a\u9636\u6bb5\uff08Multi-stage\uff09\u6784\u5efa\u7684\u4f8b\u5b50\u3002\u5728Docker\u7684\u4e0a\u4e0b\u6587\u4e2d\uff0c\u591a\u9636\u6bb5\uff08Multi-stage\uff09\u610f\u5473\u7740\u6211\u4eec\u53ef\u4ee5\u6709\u591a\u4e2a\u5e26\u6709 FROM \u5173\u952e\u5b57\u7684\u884c\u3002 \u521b\u5efa\u6587\u4ef6\u5939 /opt/tmp-2 \u548c /opt/tmp-2/tmpl \u3002\u521b\u5efa\u6587\u4ef6 edit.html \uff0c view.html \uff0c wiki.go \u3002 \u6587\u4ef6\u7ed3\u6784\u5982\u4e0b\uff1a tree -l /opt/tmp-2 \u8f93\u51fa\u7ed3\u679c\uff1a . \u251c\u2500\u2500 tmpl \u2502 \u251c\u2500\u2500 edit.html \u2502 \u2514\u2500\u2500 view.html \u2514\u2500\u2500 wiki.go \u521b\u5efa\u4e00\u4e2a\u65b0\u7684Dockerfile\u3002 cat Dockerfile \u6587\u4ef6\u5185\u5bb9\uff1a # app builder stage FROM golang:1.12-alpine as builder # # copy the go source code over and build the binary WORKDIR /go/src COPY wiki.go /go/src/wiki.go RUN go build wiki.go # app exec stage # separate & new image starts here!# FROM alpine:3.9 # prepare file system etc RUN mkdir -p /app/data /app/tmpl && adduser -S -D -H -h /app appuser COPY tmpl/* /app/tmpl/ # get the compiled binary from the previous stage COPY --from=builder /go/src/wiki /app/wiki # prepare runtime env RUN chown -R appuser /app USER appuser WORKDIR /app # expose app port & set default command EXPOSE 8080 CMD [\"/app/wiki\"] \u7528\u4e0a\u4e00\u6b65\u521b\u5efa\u7684Dockerfile\u6765\u521b\u5efa\u65b0\u666f\u8c61\u3002 docker build -t lizard/golang:my1 /opt/tmp-2/ \u4ee5\u72ec\u7acb\u6a21\u5f0f\uff08detached\uff09\u8fd0\u884c\u8fd9\u4e2a\u955c\u50cf\uff0c\u5e76\u5c06\u5bb9\u5668\u7aef\u53e3 8080 \u8f6c\u53d1\u5230\u4e3b\u673a\u7aef\u53e3 1090 \u3002 docker run -d -p 1090 :8080 --name golan_v1 lizard/golang:my1 \u901a\u8fc7\u94fe\u63a5 http://localhost:1090 \u8bbf\u95ee\u8fd9\u4e2a\u8fd0\u884c\u7684\u5bb9\u5668\u3002 \u5bf9\u6211\u4eec\u521a\u521a\u521b\u5efa\u7684\u65b0\u7684golang\u955c\u50cf\u8fdb\u884c\u6807\u7b7e\uff0c\u5e76\u4e14\u4e0a\u4f20\u5230Dockerhub\u3002 docker tag lizard/golang:my1 /golang_0001:v1 docker push /golang_0001:v1","title":"Docker\u57fa\u7840"},{"location":"k8s/cka_cn/foundamentals/docker/#cka4docker","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb04:Docker\u57fa\u7840"},{"location":"k8s/cka_cn/foundamentals/docker/#_1","text":"\u4e86\u89e3Linux\u539f\u8bed\u7684\u6982\u5ff5\u548c\u5305\u542b\u7684\u7279\u6027\u3002 \u5b89\u88c5Docker\uff0c\u4e86\u89e3\u57fa\u672c\u7684Docker\u547d\u4ee4\u548cDockerfile\u7684\u4f7f\u7528\u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/docker/#_2","text":"\u64cd\u4f5c\u7cfb\u7edf\uff1aopenSUSE 15.3 cat /etc/os-release \u8f93\u51fa\u7ed3\u679c\uff1a NAME=\"openSUSE Leap\" VERSION=\"15.3\" ID=\"opensuse-leap\" ID_LIKE=\"suse opensuse\" VERSION_ID=\"15.3\" PRETTY_NAME=\"openSUSE Leap 15.3\" ANSI_COLOR=\"0;32\" CPE_NAME=\"cpe:/o:opensuse:leap:15.3\" BUG_REPORT_URL=\"https://bugs.opensuse.org\" HOME_URL=\"https://www.opensuse.org/\"","title":"\u7ec3\u4e60\u73af\u5883"},{"location":"k8s/cka_cn/foundamentals/docker/#linux","text":"\u5728\u64cd\u4f5c\u7cfb\u7edf\u4e2d\uff0c\u539f\u8bed\uff08primitives\uff09\u662f\u7528\u4e8e\u521b\u5efa\u66f4\u590d\u6742\u529f\u80fd\u7684\u57fa\u672c\u6784\u5efa\u5757\u6216\u64cd\u4f5c\u3002\u5728Linux\u4e2d\uff0c\u6709\u51e0\u79cd\u5e38\u7528\u7684\u539f\u8bed\u3002\u5305\u62ec\uff1a \u8fdb\u7a0b\uff08Processes\uff09\uff1a\u8fdb\u7a0b\u662f\u7a0b\u5e8f\u6216\u5e94\u7528\u7a0b\u5e8f\u7684\u8fd0\u884c\u5b9e\u4f8b\u3002\u5b83\u4eec\u662fLinux\u4e2d\u7684\u57fa\u672c\u5de5\u4f5c\u5355\u5143\uff0c\u7531\u5185\u6838\u7ba1\u7406\u3002 \u6587\u4ef6\uff08Files\uff09\uff1a\u6587\u4ef6\u662f\u5728Linux\u4e2d\u5b58\u50a8\u6570\u636e\u7684\u4e3b\u8981\u65b9\u5f0f\u3002\u5b83\u4eec\u53ef\u4ee5\u662f\u6587\u672c\u6587\u4ef6\u3001\u4e8c\u8fdb\u5236\u6587\u4ef6\u3001\u76ee\u5f55\u6216\u7279\u6b8a\u6587\u4ef6\uff0c\u5982\u8bbe\u5907\u6587\u4ef6\u3002 \u4fe1\u53f7\uff08Signals\uff09\uff1a\u4fe1\u53f7\u662f\u8fdb\u7a0b\u4e4b\u95f4\u6216\u8fdb\u7a0b\u4e0e\u5185\u6838\u4e4b\u95f4\u901a\u4fe1\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u5b83\u4eec\u7528\u4e8e\u901a\u77e5\u8fdb\u7a0b\u4e8b\u4ef6\uff0c\u4f8b\u5982\u4efb\u52a1\u5b8c\u6210\u6216\u9519\u8bef\u53d1\u751f\u7684\u60c5\u51b5\u3002 \u5957\u63a5\u5b57\uff08Sockets\uff09\uff1a\u5957\u63a5\u5b57\u662fLinux\u4e2d\u8fdb\u7a0b\u95f4\u901a\u4fe1\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u5b83\u4eec\u5141\u8bb8\u8fdb\u7a0b\u5728\u7f51\u7edc\u6216\u672c\u5730\u673a\u5668\u4e0a\u53d1\u9001\u548c\u63a5\u6536\u6570\u636e\u3002 \u7ebf\u7a0b\uff08Threads\uff09\uff1a\u7ebf\u7a0b\u662f\u8f7b\u91cf\u7ea7\u7684\u8fdb\u7a0b\uff0c\u4e0e\u5176\u7236\u8fdb\u7a0b\u5171\u4eab\u76f8\u540c\u7684\u5185\u5b58\u7a7a\u95f4\u548c\u8d44\u6e90\u3002\u5b83\u4eec\u901a\u5e38\u7528\u4e8e\u901a\u8fc7\u5141\u8bb8\u540c\u65f6\u6267\u884c\u591a\u4e2a\u4efb\u52a1\u6765\u63d0\u9ad8\u5e94\u7528\u7a0b\u5e8f\u7684\u6027\u80fd\u3002 \u7ba1\u9053\uff08Pipes\uff09\uff1a\u7ba1\u9053\u662f\u4e00\u79cd\u5c06\u4e00\u4e2a\u8fdb\u7a0b\u7684\u8f93\u51fa\u8fde\u63a5\u5230\u53e6\u4e00\u4e2a\u8fdb\u7a0b\u7684\u8f93\u5165\u7684\u65b9\u5f0f\u3002\u5b83\u4eec\u5141\u8bb8\u8fdb\u7a0b\u4ee5\u53d7\u63a7\u7684\u65b9\u5f0f\u8fdb\u884c\u901a\u4fe1\u548c\u4ea4\u6362\u6570\u636e\u3002 \u4fe1\u53f7\u91cf\uff08Semaphores\uff09\uff1a\u4fe1\u53f7\u91cf\u662fLinux\u4e2d\u63a7\u5236\u5bf9\u5171\u4eab\u8d44\u6e90\u8bbf\u95ee\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u5b83\u4eec\u5141\u8bb8\u8fdb\u7a0b\u534f\u8c03\u5b83\u4eec\u5bf9\u5171\u4eab\u8d44\u6e90\u7684\u8bbf\u95ee\uff0c\u5982\u6587\u4ef6\u6216\u5185\u5b58\u3002","title":"Linux\u539f\u8bed"},{"location":"k8s/cka_cn/foundamentals/docker/#chroot","text":"chroot\u4f7f\u7528pivot_root\uff0c\u4ee5\u5b9e\u73b0\u5c06*\u8fdb\u7a0b*\u7684\u6839\u76ee\u5f55\u66f4\u6539\u4e3a\u4efb\u4f55\u7ed9\u5b9a\u7684\u76ee\u5f55\u3002 a. \u6a21\u62df\u5bb9\u5668 \u4f7f\u7528 chroot \u547d\u4ee4\u53ef\u4ee5\u5728Linux\u7cfb\u7edf\u4e2d\u521b\u5efa\u4e00\u4e2a\u5bb9\u5668\u3002\u8be5\u5bb9\u5668\u53ef\u4ee5\u770b\u4f5c\u662f\u4e00\u4e2a\u865a\u62df\u7684\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u5176\u4e2d\u8fd0\u884c\u7684\u8fdb\u7a0b\u53ea\u80fd\u8bbf\u95ee\u8be5\u6839\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u8d44\u6e90\u3002 \u4f8b\u5982\uff0c\u4ee5\u4e0b\u547d\u4ee4\u4f1a\u5c06\u5f53\u524d\u6839\u6587\u4ef6\u7cfb\u7edf\u66f4\u6539\u4e3a /tmp/myroot \u76ee\u5f55\uff1a chroot /tmp/myroot /bin/bash \u8fd9\u6761\u547d\u4ee4\u4f1a\u542f\u52a8\u4e00\u4e2a\u65b0\u7684Bash shell\uff0c\u8be5shell\u7684\u6839\u76ee\u5f55\u4e3a /tmp/myroot \u3002 b. \u66f4\u6539\u6839\u6587\u4ef6\u7cfb\u7edf chroot \u547d\u4ee4\u8fd8\u53ef\u7528\u4e8e\u66f4\u6539\u8fdb\u7a0b\u7684\u6839\u6587\u4ef6\u7cfb\u7edf\u3002\u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 chroot \u547d\u4ee4\u542f\u52a8\u4e00\u4e2a\u5177\u6709\u53e6\u4e00\u4e2a\u6839\u6587\u4ef6\u7cfb\u7edf\u7684\u8fdb\u7a0b\uff0c\u800c\u4e0d\u662f\u7cfb\u7edf\u7684\u9ed8\u8ba4\u6839\u6587\u4ef6\u7cfb\u7edf\u3002 \u4f8b\u5982\uff0c\u4ee5\u4e0b\u547d\u4ee4\u4f1a\u5c06\u5f53\u524d\u76ee\u5f55\uff08\u5373 ./ \uff09\u4f5c\u4e3a\u6839\u76ee\u5f55\uff0c\u5e76\u5728\u5176\u4e2d\u542f\u52a8\u4e00\u4e2a\u65b0\u7684Bash shell\uff1a sudo chroot . /bin/bash","title":"chroot"},{"location":"k8s/cka_cn/foundamentals/docker/#_3","text":"\u5728Linux\u64cd\u4f5c\u7cfb\u7edf\u4e2d\uff0cNamespace\uff08\u547d\u540d\u7a7a\u95f4\uff09\u662f\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u9694\u79bb\u4e0d\u540c\u8fdb\u7a0b\u7684\u8d44\u6e90\u3002\u901a\u8fc7Namespace\u673a\u5236\uff0c\u53ef\u4ee5\u5c06\u4e00\u7ec4\u8fdb\u7a0b\u53ca\u5176\u5b50\u8fdb\u7a0b\u7684\u89c6\u56fe\u9694\u79bb\u5728\u4e00\u4e2a\u72ec\u7acb\u7684Namespace\u4e2d\uff0c\u4ece\u800c\u5b9e\u73b0\u8fdb\u7a0b\u4e4b\u95f4\u8d44\u6e90\u9694\u79bb\u7684\u76ee\u7684\u3002 \u4e0b\u9762\u662f\u4e00\u4e9b\u5e38\u89c1\u7684Namespace\u7c7b\u578b\u53ca\u5176\u4f5c\u7528\uff1a Mount Namespace\uff1a\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\u6302\u8f7d\u70b9\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u3002 PID Namespace\uff1a\u9694\u79bb\u8fdb\u7a0bID\u53f7\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u8fdb\u7a0bID\u53f7\u7a7a\u95f4\uff0c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684PID\u51b2\u7a81\u3002 Network Namespace\uff1a\u9694\u79bb\u7f51\u7edc\u6808\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u7f51\u7edc\u6808\uff0c\u4ece\u800c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684\u7f51\u7edc\u51b2\u7a81\u3002 IPC Namespace\uff1a\u9694\u79bb\u8fdb\u7a0b\u95f4\u901a\u4fe1\uff08IPC\uff09\u673a\u5236\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684IPC\u7a7a\u95f4\uff0c\u4ece\u800c\u907f\u514dIPC\u673a\u5236\u5e26\u6765\u7684\u8d44\u6e90\u7ade\u4e89\u3002 UTS Namespace\uff1a\u9694\u79bb\u4e3b\u673a\u540d\u548c\u57df\u540d\u3002\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u4e3b\u673a\u540d\u548c\u57df\u540d\u7a7a\u95f4\uff0c\u4ece\u800c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684\u547d\u540d\u51b2\u7a81\u3002 Primitives namespace\u548cNamespace\u662f\u4e24\u4e2a\u4e0d\u540c\u7684\u6982\u5ff5\u3002 Namespace\u662fLinux\u64cd\u4f5c\u7cfb\u7edf\u63d0\u4f9b\u7684\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u9694\u79bb\u4e0d\u540c\u8fdb\u7a0b\u7684\u8d44\u6e90\uff0c\u4ee5\u5b9e\u73b0\u8fdb\u7a0b\u4e4b\u95f4\u7684\u8d44\u6e90\u9694\u79bb\u548c\u73af\u5883\u9694\u79bb\u3002\u4f8b\u5982\uff0cPID Namespace\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684PID\u53f7\u7a7a\u95f4\uff0c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684PID\u51b2\u7a81\uff1bNetwork Namespace\u53ef\u4ee5\u4f7f\u4e0d\u540c\u8fdb\u7a0b\u62e5\u6709\u81ea\u5df1\u7684\u72ec\u7acb\u7684\u7f51\u7edc\u6808\uff0c\u4ece\u800c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684\u7f51\u7edc\u51b2\u7a81\u7b49\u3002 Primitives namespace\u662f\u4e00\u79cd\u65b0\u7684\u6280\u672f\u6982\u5ff5\uff0c\u5b83\u662f\u6307\u5c06\u4e0d\u540c\u7684\u57fa\u672c\u64cd\u4f5c\uff08\u4f8b\u5982\u8bfb\u5199\u6587\u4ef6\u3001\u521b\u5efa\u8fdb\u7a0b\u3001\u7f51\u7edc\u901a\u4fe1\u7b49\uff09\u4f5c\u4e3a\u539f\u8bed\u8fdb\u884c\u9694\u79bb\u548c\u5c01\u88c5\uff0c\u4f7f\u5f97\u5e94\u7528\u7a0b\u5e8f\u53ef\u4ee5\u5728\u8fd9\u4e9b\u9694\u79bb\u7684\u539f\u8bed\u4e0a\u6784\u5efa\u51fa\u81ea\u5df1\u7684\u9694\u79bb\u73af\u5883\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u901a\u8fc7\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\u8bfb\u5199\u64cd\u4f5c\u6765\u5b9e\u73b0\u5bb9\u5668\u7ea7\u522b\u7684\u6587\u4ef6\u7cfb\u7edf\u9694\u79bb\uff1b\u901a\u8fc7\u9694\u79bb\u7f51\u7edc\u901a\u4fe1\u64cd\u4f5c\u6765\u5b9e\u73b0\u5bb9\u5668\u7ea7\u522b\u7684\u7f51\u7edc\u9694\u79bb\u7b49\u3002 \u56e0\u6b64\uff0cNamespace\u548cPrimitives namespace\u662f\u4e24\u4e2a\u4e0d\u540c\u7684\u6982\u5ff5\uff0c\u867d\u7136\u5b83\u4eec\u90fd\u53ef\u4ee5\u7528\u4e8e\u5b9e\u73b0\u9694\u79bb\u548c\u5c01\u88c5\u7684\u529f\u80fd\uff0c\u4f46\u662fNamespace\u662f\u4e00\u79cd\u66f4\u4e3a\u901a\u7528\u548c\u5e95\u5c42\u7684\u673a\u5236\uff0cPrimitives namespace\u662f\u4e00\u79cd\u66f4\u4e3a\u9ad8\u5c42\u7684\u62bd\u8c61\u6982\u5ff5\uff0c\u901a\u5e38\u7528\u4e8e\u6784\u5efa\u5bb9\u5668\u7b49\u5e94\u7528\u7ea7\u522b\u7684\u9694\u79bb\u73af\u5883\u3002 Namespace\u793a\u4f8b\uff1a \u5728Linux\u7cfb\u7edf\u4e2d\uff0c\u53ef\u4ee5\u4f7f\u7528PID Namespace\u6765\u9694\u79bb\u8fdb\u7a0bID\u53f7\u7a7a\u95f4\uff0c\u907f\u514d\u8fdb\u7a0b\u4e4b\u95f4\u7684PID\u51b2\u7a81\u3002\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\uff1a # \u521b\u5efa\u4e00\u4e2a\u65b0\u7684PID Namespace unshare -p /bin/bash # \u5728\u65b0\u7684PID Namespace\u4e2d\u8fd0\u884c\u4e00\u4e2a\u8fdb\u7a0b echo $$ # \u663e\u793a\u5f53\u524d\u8fdb\u7a0b\u7684PID ps aux # \u663e\u793a\u5f53\u524d\u8fdb\u7a0b\u53ca\u5176\u5b50\u8fdb\u7a0b \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c unshare -p \u547d\u4ee4\u521b\u5efa\u4e86\u4e00\u4e2a\u65b0\u7684PID Namespace\uff0c\u5e76\u5728\u5176\u4e2d\u542f\u52a8\u4e86\u4e00\u4e2a\u65b0\u7684bash\u8fdb\u7a0b\u3002\u7531\u4e8e\u8be5\u8fdb\u7a0b\u8fd0\u884c\u5728\u4e00\u4e2a\u72ec\u7acb\u7684PID Namespace\u4e2d\uff0c\u56e0\u6b64\u5b83\u7684PID\u53f7\u4e0e\u4e3b\u673a\u4e0a\u7684\u5176\u4ed6\u8fdb\u7a0b\u4e0d\u4f1a\u51b2\u7a81\u3002\u5728\u8fd9\u4e2a\u65b0\u7684bash\u8fdb\u7a0b\u4e2d\uff0c $$ \u547d\u4ee4\u663e\u793a\u7684\u662f\u8be5\u8fdb\u7a0b\u5728PID Namespace\u4e2d\u7684PID\u53f7\uff0c\u800c ps aux \u547d\u4ee4\u53ea\u4f1a\u663e\u793a\u5f53\u524dPID Namespace\u4e2d\u7684\u8fdb\u7a0b\uff0c\u4e0d\u4f1a\u663e\u793a\u4e3b\u673a\u4e0a\u7684\u5176\u4ed6\u8fdb\u7a0b\u3002 Primitives Namespace\u793a\u4f8b\uff1a \u5728Docker\u5bb9\u5668\u4e2d\uff0c\u53ef\u4ee5\u4f7f\u7528Filesystem Namespace\u6765\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\uff0c\u4f7f\u5f97\u4e0d\u540c\u7684\u5bb9\u5668\u4e4b\u95f4\u62e5\u6709\u72ec\u7acb\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u3002\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\uff1a # \u5728\u5bb9\u5668\u4e2d\u8fd0\u884c\u4e00\u4e2a\u547d\u4ee4 docker run --rm -it --name mycontainer ubuntu bash # \u5728\u5bb9\u5668\u4e2d\u521b\u5efa\u4e00\u4e2a\u6587\u4ef6\u5e76\u9000\u51fa touch myfile exit # \u5728\u4e3b\u673a\u4e0a\u67e5\u770b\u6587\u4ef6 ls myfile # myfile\u6587\u4ef6\u4e0d\u5b58\u5728 # \u518d\u6b21\u8fdb\u5165\u5bb9\u5668 docker start -i mycontainer # \u5728\u5bb9\u5668\u4e2d\u67e5\u770b\u6587\u4ef6 ls myfile # myfile\u6587\u4ef6\u5b58\u5728 \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c docker run \u547d\u4ee4\u542f\u52a8\u4e86\u4e00\u4e2a\u65b0\u7684Docker\u5bb9\u5668\uff0c\u5e76\u5728\u5176\u4e2d\u8fd0\u884c\u4e86\u4e00\u4e2abash\u8fdb\u7a0b\u3002\u7531\u4e8e\u8be5\u5bb9\u5668\u4f7f\u7528\u4e86Filesystem Namespace\uff0c\u56e0\u6b64\u5bb9\u5668\u5185\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u4e0e\u4e3b\u673a\u4e0a\u7684\u6587\u4ef6\u7cfb\u7edf\u89c6\u56fe\u662f\u9694\u79bb\u7684\u3002\u5728\u5bb9\u5668\u5185\u521b\u5efa\u7684\u6587\u4ef6 myfile \u53ea\u5b58\u5728\u4e8e\u5bb9\u5668\u5185\u90e8\uff0c\u5728\u4e3b\u673a\u4e0a\u662f\u770b\u4e0d\u5230\u7684\u3002\u5f53\u518d\u6b21\u8fdb\u5165\u5bb9\u5668\u65f6\uff0c myfile \u6587\u4ef6\u5c31\u53ef\u4ee5\u88ab\u770b\u5230\u4e86\u3002 \u603b\u7ed3\uff1a Namespace\u662fLinux\u5185\u6838\u63d0\u4f9b\u7684\u673a\u5236\uff0c\u800cPrimitives Namespace\u5219\u662f\u4e00\u79cd\u57fa\u4e8eNamespace\u7684\u9ad8\u5c42\u62bd\u8c61\uff0c\u7528\u4e8e\u5b9e\u73b0\u5e94\u7528\u7ea7\u522b\u7684\u9694\u79bb\u548c\u5c01\u88c5\u3002Namespace\u53ef\u4ee5\u7528\u4e8e\u9694\u79bb\u591a\u79cd\u8d44\u6e90\uff0c\u800cPrimitives Namespace\u901a\u5e38\u7528\u4e8e\u9694\u79bb\u6587\u4ef6\u7cfb\u7edf\u3001\u7f51\u7edc\u3001\u8fdb\u7a0b\u7b49\u64cd\u4f5c\u7684\u539f\u8bed\u3002","title":"\u547d\u540d\u7a7a\u95f4"},{"location":"k8s/cka_cn/foundamentals/docker/#_4","text":"cgroup\uff0c\u5168\u79f0\u4e3aControl Group\uff0c\u5373\u63a7\u5236\u7ec4\uff0c\u662fLinux\u5185\u6838\u63d0\u4f9b\u7684\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u9650\u5236\u3001\u8bb0\u5f55\u3001\u9694\u79bb\u548c\u4f18\u5148\u7ea7\u63a7\u5236\u4e00\u7ec4\u8fdb\u7a0b\u7684\u8d44\u6e90\u4f7f\u7528\u3002\u5b83\u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7ec4\u7684CPU\u3001\u5185\u5b58\u3001\u78c1\u76d8\u3001\u7f51\u7edc\u7b49\u8d44\u6e90\u7684\u4f7f\u7528\uff0c\u540c\u65f6\u4e5f\u53ef\u4ee5\u8bb0\u5f55\u8fdb\u7a0b\u7ec4\u7684\u8d44\u6e90\u4f7f\u7528\u60c5\u51b5\u548c\u884c\u4e3a\u3002 cgroup\u901a\u8fc7\u5c06\u4e00\u7ec4\u8fdb\u7a0b\u7ec4\u7ec7\u6210\u4e00\u4e2a\u5c42\u6b21\u7ed3\u6784\uff0c\u5c06\u8d44\u6e90\u5206\u914d\u7ed9\u4e0d\u540c\u7684cgroup\u6765\u5b9e\u73b0\u8d44\u6e90\u9650\u5236\u548c\u4f18\u5148\u7ea7\u63a7\u5236\u3002\u6bcf\u4e2acgroup\u53ef\u4ee5\u8bbe\u7f6e\u8d44\u6e90\u9650\u5236\u548c\u63a7\u5236\u7b56\u7565\uff0c\u4f8b\u5982\u53ef\u4ee5\u9650\u5236\u4e00\u4e2a\u8fdb\u7a0b\u7ec4\u6700\u591a\u4f7f\u752850%\u7684CPU\u65f6\u95f4\uff0c\u6216\u8005\u9650\u5236\u4e00\u4e2a\u8fdb\u7a0b\u7ec4\u6700\u591a\u4f7f\u7528100MB\u7684\u5185\u5b58\u7b49\u3002 cgroup\u6700\u521d\u7531Google\u516c\u53f8\u5f00\u53d1\uff0c\u540e\u6765\u88abLinux\u5185\u6838\u793e\u533a\u91c7\u7eb3\u5e76\u52a0\u5165\u5230\u5185\u6838\u4e2d\uff0c\u6210\u4e3aLinux\u7cfb\u7edf\u7684\u4e00\u90e8\u5206\u3002\u5b83\u5728\u5bb9\u5668\u6280\u672f\u3001\u865a\u62df\u5316\u3001\u4e91\u8ba1\u7b97\u7b49\u9886\u57df\u90fd\u6709\u5e7f\u6cdb\u7684\u5e94\u7528\u3002 \u4e0b\u9762\u662fcgroup \u7684\u4e00\u4e9b\u5e38\u89c1\u7528\u9014\uff1a CPU \u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684 CPU \u4f7f\u7528\u7387\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684 CPU \u8d44\u6e90\u5bfc\u81f4\u7cfb\u7edf\u8d1f\u8f7d\u8fc7\u9ad8\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u7a33\u5b9a\u6027\u548c\u5176\u4ed6\u8fdb\u7a0b\u7684\u6b63\u5e38\u8fd0\u884c\u3002 \u5185\u5b58\u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684\u5185\u5b58\u4f7f\u7528\u91cf\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684\u5185\u5b58\u8d44\u6e90\u5bfc\u81f4\u7cfb\u7edf\u5185\u5b58\u4e0d\u8db3\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u6027\u80fd\u548c\u5176\u4ed6\u8fdb\u7a0b\u7684\u6b63\u5e38\u8fd0\u884c\u3002 IO \u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684 IO \u5e26\u5bbd\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684 IO \u8d44\u6e90\u5bfc\u81f4\u5176\u4ed6\u8fdb\u7a0b\u7684 IO \u64cd\u4f5c\u53d7\u5230\u5f71\u54cd\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u6027\u80fd\u548c\u54cd\u5e94\u901f\u5ea6\u3002 \u7f51\u7edc\u9650\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684\u7f51\u7edc\u5e26\u5bbd\uff0c\u907f\u514d\u67d0\u4e2a\u8fdb\u7a0b\u5360\u7528\u8fc7\u591a\u7684\u7f51\u7edc\u8d44\u6e90\u5bfc\u81f4\u7f51\u7edc\u62e5\u585e\uff0c\u4ece\u800c\u5f71\u54cd\u7cfb\u7edf\u6027\u80fd\u548c\u5176\u4ed6\u8fdb\u7a0b\u7684\u6b63\u5e38\u8fd0\u884c\u3002 \u8fdb\u7a0b\u63a7\u5236\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u7684\u542f\u52a8\u3001\u505c\u6b62\u548c\u8c03\u5ea6\u7b49\u884c\u4e3a\uff0c\u4ece\u800c\u5b9e\u73b0\u5bf9\u7cfb\u7edf\u8fdb\u7a0b\u7684\u63a7\u5236\u548c\u7ba1\u7406\u3002 \u8d44\u6e90\u7edf\u8ba1\uff1a\u4f7f\u7528 cgroup \u53ef\u4ee5\u5b9e\u65f6\u7edf\u8ba1\u7cfb\u7edf\u4e2d\u5404\u4e2a\u8fdb\u7a0b\u7684\u8d44\u6e90\u4f7f\u7528\u60c5\u51b5\uff0c\u4ece\u800c\u5e2e\u52a9\u7ba1\u7406\u5458\u4e86\u89e3\u7cfb\u7edf\u8d1f\u8f7d\u72b6\u51b5\u548c\u5404\u4e2a\u8fdb\u7a0b\u7684\u6027\u80fd\u74f6\u9888\uff0c\u4ece\u800c\u91c7\u53d6\u76f8\u5e94\u7684\u63aa\u65bd\u4f18\u5316\u7cfb\u7edf\u6027\u80fd\u3002 \u4e0b\u9762\u662fopenSUSE\u4e2d\u7684\u793a\u4f8b\uff1a \u5b89\u88c5\u9700\u8981\u7684\u8f6f\u4ef6\u5305\uff1a sudo zypper install libcgroup-tools \u9650\u5236CPU\u4f7f\u7528\u4e0a\u9650\uff1a # \u521b\u5efa\u65b0\u7684cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/cpu/mygroup # \u7cfb\u7edf\u4f1a\u521b\u5efa\u9ed8\u8ba4\u7684\u4e00\u4e9b\u6587\u4ef6\uff0c\u542b\u521d\u59cb\u503c\uff0c\u6bd4\u5982CPU\u4f7f\u7528\u65f6\u95f4\u7684\u9650\u989d\u7684\u9ed8\u8ba4\u503c\u662f-1 cat /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us # \u8bbe\u5b9aCPU\u4f7f\u7528\u65f6\u95f4\u4e0a\u9650 sudo sh -c \"echo 50000 > /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us\" # \u542f\u52a8\u4e00\u4e2a\u65b0\u7684\u8fdb\u7a0b\uff0c\u5e76\u4e14\u5173\u8054\u5230 sudo cgcreate -g cpu:mygroup sudo cgexec -g cpu:mygroup /bin/bash \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c cpu.cfs_quota_us \u6587\u4ef6\u8bbe\u7f6e\u4e86 cgroup \u4e2d\u7684\u8fdb\u7a0b\u53ef\u4ee5\u4f7f\u7528\u7684\u6700\u5927 CPU \u65f6\u95f4\u3002\u8be5\u503c\u4ee5\u5fae\u79d2\u4e3a\u5355\u4f4d\uff0c\u56e0\u6b64\u5c06\u5176\u8bbe\u7f6e\u4e3a 50000 \u8868\u793a\u8fdb\u7a0b\u6700\u591a\u53ef\u4ee5\u4f7f\u7528\u5355\u4e2a CPU \u6838\u5fc3\u7684 50%\u3002 cgcreate \u548c cgexec \u547d\u4ee4\u521b\u5efa\u5e76\u5c06\u8fdb\u7a0b /bin/bash \u79fb\u52a8\u5230 mygroup cgroup \u4e2d\u3002 \u9650\u5236\u5185\u5b58\u4f7f\u7528\u4e0a\u9650\uff1a # \u521b\u5efa\u65b0\u7684cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/memory/mygroup # \u7cfb\u7edf\u4f1a\u521b\u5efa\u9ed8\u8ba4\u7684\u4e00\u4e9b\u6587\u4ef6\uff0c\u542b\u521d\u59cb\u503c\uff0c\u6bd4\u5982\u5185\u5b58\u4f7f\u7528\u4e0a\u9650\u7684\u9ed8\u8ba4\u503c\u662f9223372036854771712 cat /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes # \u8bbe\u7f6e\u5185\u5b58\u4f7f\u7528\u4e0a\u9650512MB sudo sh -c \"echo 536870912 > /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes\" # \u542f\u52a8\u4e00\u4e2a\u65b0\u7684\u8fdb\u7a0b\uff0c\u5e76\u4e14\u5173\u8054\u5230'mygroup' sudo cgcreate -g memory:mygroup sudo cgexec -g memory:mygroup /bin/bash \u5728\u4e0a\u9762\u4f8b\u5b50\u4e2d\uff0c memory.limit_in_bytes \u6587\u4ef6\u8bbe\u7f6e\u4e86 cgroup \u4e2d\u8fdb\u7a0b\u53ef\u4ee5\u4f7f\u7528\u7684\u6700\u5927\u5185\u5b58\u91cf\u3002\u8be5\u503c\u4ee5\u5b57\u8282\u4e3a\u5355\u4f4d\uff0c\u56e0\u6b64\u5c06\u5176\u8bbe\u7f6e\u4e3a 536870912 \u8868\u793a\u8fdb\u7a0b\u6700\u591a\u53ef\u4ee5\u4f7f\u7528 512MB \u7684\u5185\u5b58\u3002 \u8bbe\u7f6e\u4f18\u5148\u8fdb\u7a0b\u7684 I/O \u4f7f\u7528\u7387\uff1a # \u521b\u5efa\u65b0cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/blkio/mygroup # \u8bbe\u7f6e\u8fdb\u7a0b\u6700\u5927\u8bfb\u548c\u5199\u7684\u901f\u738710MB/s sudo sh -c \"echo '8:0 10485760' > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.read_bps_device\" sudo sh -c \"echo '8:0 10485760' > /sys/fs/cgroup/blkio/mygroup/blkio.throttle.write_bps_device\" # \u542f\u52a8\u4e00\u4e2a\u65b0\u7684\u8fdb\u7a0b\uff0c\u5e76\u4e14\u5173\u8054\u5230'mygroup' sudo cgcreate -g blkio:mygroup sudo cgexec -g blkio:mygroup /bin/bash \u5728\u4e0a\u9762\u4f8b\u5b50\u4e2d\uff0c blkio.throttle.read_bps_device \u548c blkio.throttle.write_bps_device \u6587\u4ef6\u8bbe\u7f6e\u4e86cgroup\u4e2d\u8fdb\u7a0b\u53ef\u4ee5\u4f7f\u7528\u7684\u6700\u5927\u8bfb\u53d6\u548c\u5199\u5165\u5e26\u5bbd\u3002\u8be5\u503c\u4ee5\u6bcf\u79d2\u5b57\u8282\u6570\u4e3a\u5355\u4f4d\uff0c\u56e0\u6b64\u5c06\u5176\u8bbe\u7f6e\u4e3a10485760\u610f\u5473\u7740\u8fdb\u7a0b\u5728\u4e3b\u8bbe\u5907\u53f7:\u6b21\u8bbe\u5907\u53f7\u4e3a8:0\u7684\u8bbe\u5907\uff08\u901a\u5e38\u662f\u7b2c\u4e00\u4e2a\u786c\u76d8\uff09\u4e0a\u8bfb\u53d6\u6216\u5199\u5165\u7684\u5e26\u5bbd\u6700\u591a\u4e3a10MB/s\u3002 \u5c06 8:0 10485760 \u8fd9\u4e2a\u5b57\u7b26\u4e32\u5199\u5165\u5230 /sys/fs/cgroup/blkio/mygroup/blkio.throttle.read_bps_device \u6587\u4ef6\u4e2d\u7684\u4f5c\u7528\u662f\u9650\u5236 mygroup \u63a7\u5236\u7ec4\u4e2d\u5173\u8054\u7684\u5757\u8bbe\u5907\uff08block device\uff09\u7684\u8bfb\u53d6\u901f\u7387\u3002 \u5728 Linux \u4e2d\uff0c blkio \u63a7\u5236\u7ec4\u5b50\u7cfb\u7edf\u53ef\u4ee5\u7528\u6765\u5bf9\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u7684\u5757\u8bbe\u5907\u8bbf\u95ee\u8fdb\u884c\u9650\u5236\uff0c\u5982\u9650\u5236\u8bfb\u5199\u901f\u7387\u3001I/O \u4f18\u5148\u7ea7\u7b49\u3002\u800c blkio.throttle.read_bps_device \u8fd9\u4e2a\u6587\u4ef6\u5219\u7528\u4e8e\u8bbe\u7f6e\u67d0\u4e2a\u5757\u8bbe\u5907\u7684\u8bfb\u53d6\u901f\u7387\u9650\u5236\u3002 \u5177\u4f53\u6765\u8bf4\uff0c 8:0 \u8868\u793a\u8bbe\u5907\u7684\u4e3b\u6b21\u7f16\u53f7\uff08major:minor\uff09\uff0c\u8fd9\u91cc\u662f\u6307\u78c1\u76d8 /dev/sda \u3002 10485760 \u5219\u662f\u8bfb\u53d6\u901f\u7387\u7684\u9650\u5236\u503c\uff0c\u5355\u4f4d\u662f\u5b57\u8282/\u79d2\u3002\u8fd9\u4e2a\u503c\u8868\u793a /dev/sda \u6700\u5927\u8bfb\u53d6\u901f\u7387\u4e3a 10MB/s\uff0c\u8d85\u8fc7\u8fd9\u4e2a\u901f\u7387\u7684\u8bfb\u53d6\u8bf7\u6c42\u4f1a\u88ab\u5ef6\u8fdf\u6267\u884c\uff0c\u4ece\u800c\u9650\u5236\u4e86\u78c1\u76d8\u7684\u8bfb\u53d6\u5e26\u5bbd\u3002 \u56e0\u6b64\uff0c\u4ee5\u4e0a\u547d\u4ee4\u7684\u542b\u4e49\u662f\u5c06 mygroup \u63a7\u5236\u7ec4\u4e2d\u5173\u8054\u7684 /dev/sda \u78c1\u76d8\u7684\u8bfb\u53d6\u901f\u7387\u9650\u5236\u4e3a 10MB/s\uff0c\u4ece\u800c\u5b9e\u73b0\u5bf9\u8be5\u63a7\u5236\u7ec4\u4e2d\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u5bf9\u78c1\u76d8\u8bfb\u53d6\u7684\u9650\u5236\u3002 \u540c\u7406\uff0c\u5c06 8:0 10485760 \u8fd9\u4e2a\u5b57\u7b26\u4e32\u5199\u5165\u5230 /sys/fs/cgroup/blkio/mygroup/blkio.throttle.write_bps_device \u6587\u4ef6\u4e2d\uff0c\u4ee5\u9650\u5236 mygroup \u63a7\u5236\u7ec4\u4e2d\u5173\u8054\u7684\u5757\u8bbe\u5907\uff08block device\uff09\u7684\u5199\u5165\u901f\u7387\u3002 \u9650\u5236\u4e00\u7ec4\u8fdb\u7a0b\u7684\u7f51\u7edc\u5e26\u5bbd\uff1a # \u521b\u5efa\u65b0\u7684cgroup 'mygroup' sudo mkdir /sys/fs/cgroup/net_cls/mygroup # \u5c06\u6b64\u7ec4\u4e2d\u7684\u8fdb\u7a0b\u7684\u7f51\u7edc\u7c7bID\u8bbe\u7f6e\u4e3a\u201cmyclass\u201d sudo sh -c \"echo 0x10001 > /sys/fs/cgroup/net_cls/mygroup/net_cls.classid\" \u4e0a\u9762\u7684\u4f8b\u5b50\u662f\u5c06 0x10001 \u8fd9\u4e2a\u5341\u516d\u8fdb\u5236\u6570\u503c\u5199\u5165\u5230 /sys/fs/cgroup/net_cls/mygroup/net_cls.classid \u6587\u4ef6\u4e2d\uff0c\u4ee5\u6307\u5b9a mygroup \u63a7\u5236\u7ec4\u7684\u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\uff08classid\uff09\u3002 \u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\u662f Linux \u5185\u6838\u4e2d\u7528\u6765\u5b9e\u73b0\u6d41\u91cf\u63a7\u5236\u548c\u6d41\u91cf\u5206\u7c7b\u7684\u4e00\u4e2a\u673a\u5236\uff0c\u5b83\u53ef\u4ee5\u5c06\u6570\u636e\u5305\u6309\u7167\u4e0d\u540c\u7684\u7c7b\u522b\uff08class\uff09\u8fdb\u884c\u6807\u8bb0\u548c\u533a\u5206\uff0c\u7136\u540e\u5728\u7f51\u7edc\u8bbe\u5907\u4e0a\u9488\u5bf9\u4e0d\u540c\u7684\u7c7b\u522b\u8fdb\u884c\u4e0d\u540c\u7684\u5904\u7406\uff0c\u5982\u9650\u901f\u3001\u4f18\u5148\u7ea7\u8c03\u6574\u7b49\u3002\u63a7\u5236\u7ec4\u4e2d\u7684 net_cls \u5b50\u7cfb\u7edf\u53ef\u4ee5\u7528\u6765\u5c06\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u4e0e\u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\u5173\u8054\u8d77\u6765\uff0c\u4ece\u800c\u5b9e\u73b0\u5bf9\u5b83\u4eec\u7684\u7f51\u7edc\u6d41\u91cf\u8fdb\u884c\u63a7\u5236\u548c\u5206\u7c7b\u3002 \u56e0\u6b64\uff0c\u4ee5\u4e0a\u547d\u4ee4\u662f\u5c06 mygroup \u63a7\u5236\u7ec4\u7684\u7f51\u7edc\u7c7b\u522b\u6807\u8bc6\u7b26\u8bbe\u7f6e\u4e3a 0x10001 \uff0c\u8fd9\u6837\u4e0e\u8be5\u63a7\u5236\u7ec4\u76f8\u5173\u8054\u7684\u8fdb\u7a0b\u6216\u7ebf\u7a0b\u5c31\u4f1a\u88ab\u6807\u8bb0\u4e3a\u8be5\u7c7b\u522b\uff0c\u7136\u540e\u53ef\u4ee5\u901a\u8fc7\u5176\u4ed6\u5de5\u5177\uff08\u5982 tc \u547d\u4ee4\uff09\u5bf9\u5176\u8fdb\u884c\u7f51\u7edc\u6d41\u91cf\u63a7\u5236\u548c\u5206\u7c7b\u3002 \u5982\u679c\u9047\u5230\u5bf9\u5e94\u9650\u5236\u6587\u4ef6\u4e0d\u5b58\u5728\uff0c\u4e00\u79cd\u53ef\u80fd\u662f\u9700\u8981\u68c0\u67e5cgroup\u5b50\u7cfb\u6709\u6ca1\u6709\u6b63\u786e\u7edf\u8f7d\u6216\u8005\u6ca1\u6709\u542f\u7528\u5185\u5b58\u5b50\u7cfb\u7edf\u3002 mount | grep cgroup \u5982\u679c cgroups \u6587\u4ef6\u7cfb\u7edf\u5df2\u7ecf\u6302\u8f7d\uff0c\u5e94\u8be5\u4f1a\u770b\u5230\u8f93\u51fa\u7c7b\u4f3c\u4e8e\u4ee5\u4e0b\u5185\u5bb9\uff08\uff09\u4ee5memory\u4e3a\u4f8b\uff09\uff1a cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory) \u5982\u679c\u6ca1\u6709\u770b\u5230 memory \u5b57\u6bb5\uff0c\u5219\u8868\u793a\u5185\u5b58\u5b50\u7cfb\u7edf\u6ca1\u6709\u542f\u7528\u3002\u53ef\u4ee5\u7f16\u8f91 /etc/default/grub \u6587\u4ef6\uff0c\u6dfb\u52a0\u6216\u4fee\u6539\u4ee5\u4e0b\u884c\uff1a GRUB_CMDLINE_LINUX_DEFAULT=\"cgroup_enable=memory\" \u7136\u540e\u66f4\u65b0 GRUB \u914d\u7f6e\u5e76\u91cd\u542f\u7cfb\u7edf\uff1a sudo update-grub sudo reboot \u91cd\u542f\u540e\u518d\u6b21\u68c0\u67e5 /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes \u6587\u4ef6\u662f\u5426\u5b58\u5728\u3002\u5982\u679c\u8fd8\u662f\u4e0d\u5b58\u5728\uff0c\u53ef\u80fd\u9700\u8981\u624b\u52a8\u521b\u5efa\u5b83\u4ee5\u53ca\u5176\u4ed6\u76f8\u5173\u7684 cgroups \u6587\u4ef6\u3002\u4f8b\u5982\uff0c\u8fd0\u884c\u4ee5\u4e0b\u547d\u4ee4\uff1a sudo mkdir /sys/fs/cgroup/memory/mygroup sudo touch /sys/fs/cgroup/memory/mygroup/memory.limit_in_bytes \u7136\u540e\u5c31\u53ef\u4ee5\u50cf\u4e4b\u524d\u7684\u4f8b\u5b50\u4e00\u6837\u8bbe\u7f6e\u5185\u5b58\u9650\u5236\u4e86","title":"\u63a7\u5236\u7ec4"},{"location":"k8s/cka_cn/foundamentals/docker/#apparmorselinux","text":"\u5b89\u5168\u914d\u7f6e\u6587\u4ef6\uff0c\u7528\u4e8e\u63a7\u5236\u5bf9\u8d44\u6e90\u7684\u8bbf\u95ee AppArmor \u548c SELinux \u90fd\u662f\u5e38\u89c1\u7684\u5f3a\u5236\u8bbf\u95ee\u63a7\u5236\uff08MAC\uff09\u673a\u5236\uff0c\u53ef\u4ee5\u5bf9\u8fdb\u7a0b\u6216\u5e94\u7528\u7a0b\u5e8f\u7684\u8bbf\u95ee\u6743\u9650\u8fdb\u884c\u7cbe\u7ec6\u63a7\u5236\u3002\u4e0b\u9762\u5206\u522b\u4e3e\u4f8b\u8bf4\u660e\u8fd9\u4e24\u79cd\u673a\u5236\u7684\u914d\u7f6e\u6587\u4ef6\u4f7f\u7528\u3002 AppArmor AppArmor \u7684\u4e3b\u914d\u7f6e\u6587\u4ef6\u662f /etc/apparmor/profiles.d/ \u76ee\u5f55\u4e0b\u7684\u5404\u4e2a\u6587\u4ef6\uff0c\u6bcf\u4e2a\u6587\u4ef6\u5bf9\u5e94\u4e00\u4e2a\u5e94\u7528\u7a0b\u5e8f\u6216\u8fdb\u7a0b\u7684\u914d\u7f6e\u3002\u4ee5 sshd \u670d\u52a1\u4e3a\u4f8b\uff0c\u8be5\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6\u662f /etc/apparmor.d/usr.sbin.sshd \u3002 \u8be5\u914d\u7f6e\u6587\u4ef6\u7684\u5185\u5bb9\u7c7b\u4f3c\u4e8e\u4e0b\u9762\u8fd9\u6837\uff1a # Last Modified: Sun Mar 14 18 :53:00 2023 # include /usr/sbin/sshd { # include # include # allow read access to user home directories /home/** r, # allow sshd to execute /usr/bin/which to determine full path of shell /usr/bin/which ix, # allow sshd to read its own configuration file /etc/ssh/sshd_config r, # allow sshd to read the SSH host keys /etc/ssh/ssh_host_* r, # allow sshd to use pam for authentication /usr/share/pam/** r, # allow sshd to use nsswitch for name resolution /etc/nsswitch.conf r, /etc/hosts r, /etc/hostname r, /etc/resolv.conf r, # allow sshd to write to its own log file /var/log/auth.log w, # allow sshd to create and manage pid files /var/run/sshd.pid w, /var/run/sshd.dir/ w, /var/run/sshd.dir/* rw, # allow sshd to access systemd-logind /run/systemd/* r, /run/systemd/session/*.scope r, /run/systemd/sessions/*.scope r, # deny everything else deny /, } \u8be5\u914d\u7f6e\u6587\u4ef6\u5b9a\u4e49\u4e86 /usr/sbin/sshd \u8fdb\u7a0b\u7684\u6743\u9650\u9650\u5236\u89c4\u5219\uff0c\u5305\u62ec\u5141\u8bb8\u8bbf\u95ee\u7684\u6587\u4ef6\u3001\u7981\u6b62\u8bbf\u95ee\u7684\u6587\u4ef6\u7b49\u3002\u5176\u4e2d #include \u8868\u793a\u5305\u542b\u4e86\u4e00\u7ec4\u901a\u7528\u7684\u6743\u9650\u89c4\u5219\uff0c\u53ef\u4ee5\u5728\u4e0d\u540c\u7684\u5e94\u7528\u7a0b\u5e8f\u914d\u7f6e\u4e2d\u91cd\u590d\u4f7f\u7528\u3002 2.SELinux SELinux \u7684\u4e3b\u914d\u7f6e\u6587\u4ef6\u662f /etc/selinux/config \uff0c\u8be5\u6587\u4ef6\u5b9a\u4e49\u4e86\u7cfb\u7edf\u7684 SELinux \u7b56\u7565\u548c\u6a21\u5f0f\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0copenSUSE \u4f7f\u7528\u7684\u662f targeted \u6a21\u5f0f\u3002 \u6bcf\u4e2a\u8fdb\u7a0b\u6216\u5e94\u7528\u7a0b\u5e8f\u8fd8\u9700\u8981\u5bf9\u5e94\u4e00\u4e2a SELinux \u914d\u7f6e\u6587\u4ef6\uff0c\u4ee5\u5b9a\u4e49\u5b83\u4eec\u7684\u8bbf\u95ee\u6743\u9650\u3002\u4ee5 httpd \u670d\u52a1\u4e3a\u4f8b\uff0c\u8be5\u670d\u52a1\u7684 SELinux \u914d\u7f6e\u6587\u4ef6\u662f /etc/selinux/targeted/contexts/httpd.te \u3002 \u8be5\u914d\u7f6e\u6587\u4ef6\u7684\u5185\u5bb9\u7c7b\u4f3c\u4e8e\u4e0b\u9762\u8fd9\u6837\uff1a # HTTPD server type httpd_t ; type httpd_sys_script_t ; init_daemon_domain ( httpd_t, httpd_sys_script_t ) \u8be5\u914d\u7f6e\u6587\u4ef6\u5b9a\u4e49\u4e86 httpd \u670d\u52a1\u7684 SELinux \u7c7b\u578b\u4e3a httpd_t \uff0c\u5e76\u4f7f\u7528\u4e86 httpd_sys_script_t \u4f5c\u4e3a\u5176\u521d\u59cb\u5316\u57df\u3002\u5176\u4e2d type \u8868\u793a SELinux \u7c7b\u578b\uff0c init_daemon_domain \u5219\u662f\u4e00\u4e2a SELinux \u5b8f\uff0c\u7528\u4e8e\u5b9a\u4e49\u670d\u52a1\u7684\u521d\u59cb\u57df\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u5728 SELinux \u4e2d\uff0c\u8bbf\u95ee\u6743\u9650\u89c4\u5219\u4e0d\u662f\u76f4\u63a5\u5728\u914d\u7f6e\u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\uff0c\u800c\u662f\u901a\u8fc7\u8bbf\u95ee\u63a7\u5236\u7b56\u7565\u548c\u89c4\u5219\u8fdb\u884c\u63a7\u5236\u3002\u8fd9\u4e9b\u7b56\u7565\u548c\u89c4\u5219\u53ef\u4ee5\u4f7f\u7528 SELinux \u5de5\u5177\u96c6\uff08\u5982 semanage \u3001 setsebool \u3001 restorecon \u7b49\uff09\u8fdb\u884c\u7ba1\u7406\u548c\u8bbe\u7f6e\u3002 \u6bd4\u5982\uff0c\u5728openSUSE\u4e2d\u53ef\u4ee5\u770b\u5230 /etc/selinux/semanage.conf \u6587\u4ef6\u548c\u5176\u4e2d\u7684\u914d\u7f6e\u3002","title":"Apparmor\u548cSELinux\u914d\u7f6e\u6587\u4ef6"},{"location":"k8s/cka_cn/foundamentals/docker/#_5","text":"\u5185\u6838\u80fd\u529b\uff08Kernel capabilities\uff09 \u6ca1\u6709\u80fd\u529b\uff1aroot\u53ef\u4ee5\u6267\u884c\u6240\u6709\u64cd\u4f5c\uff0c\u5176\u4ed6\u7528\u6237\u53ef\u80fd\u4ec0\u4e48\u4e5f\u505a\u4e0d\u4e86 38\u4e2a\u7ec6\u7c92\u5ea6\u7684\u529f\u80fd\u6765\u63a7\u5236\u6743\u9650 Kernel capabilities \u662f Linux \u5185\u6838\u63d0\u4f9b\u7684\u4e00\u79cd\u673a\u5236\uff0c\u7528\u4e8e\u63a7\u5236\u8fdb\u7a0b\u5bf9\u7cfb\u7edf\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u3002\u4e0e\u4f20\u7edf\u7684 Unix \u6743\u9650\u673a\u5236\u4e0d\u540c\uff0cKernel capabilities \u53ef\u4ee5\u4f7f\u7ba1\u7406\u5458\u5728\u7cbe\u7ec6\u63a7\u5236\u7cfb\u7edf\u8d44\u6e90\u8bbf\u95ee\u7684\u540c\u65f6\uff0c\u907f\u514d\u5c06\u8fc7\u591a\u6743\u9650\u6388\u4e88\u8fdb\u7a0b\uff0c\u63d0\u9ad8\u4e86\u7cfb\u7edf\u7684\u5b89\u5168\u6027\u3002 \u5728\u4f20\u7edf Unix \u6743\u9650\u673a\u5236\u4e2d\uff0c\u6bcf\u4e2a\u8fdb\u7a0b\u90fd\u6709\u4e00\u4e2a\u6709\u6548\u7528\u6237 ID \u548c\u4e00\u4e2a\u6709\u6548\u7ec4 ID\uff0c\u8fd9\u4e9b ID \u51b3\u5b9a\u4e86\u8be5\u8fdb\u7a0b\u5bf9\u6587\u4ef6\u3001\u8bbe\u5907\u3001\u7f51\u7edc\u7b49\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u3002\u4f46\u662f\uff0c\u8fd9\u79cd\u6743\u9650\u673a\u5236\u4e0d\u591f\u7075\u6d3b\uff0c\u5982\u679c\u8981\u6388\u4e88\u8fdb\u7a0b\u67d0\u4e9b\u7279\u5b9a\u7684\u6743\u9650\uff0c\u53ef\u80fd\u9700\u8981\u5c06\u6240\u6709\u7684\u6743\u9650\u90fd\u6388\u4e88\u7ed9\u5b83\uff0c\u4ece\u800c\u964d\u4f4e\u4e86\u7cfb\u7edf\u7684\u5b89\u5168\u6027\u3002 Kernel capabilities \u63d0\u4f9b\u4e86\u4e00\u79cd\u66f4\u7ec6\u7c92\u5ea6\u7684\u6743\u9650\u63a7\u5236\u65b9\u5f0f\u3002\u6bcf\u4e2a\u8fdb\u7a0b\u90fd\u6709\u4e00\u7ec4 capabilities\uff0c\u6bcf\u4e2a capability \u8868\u793a\u4e00\u79cd\u7279\u5b9a\u7684\u6743\u9650\u3002\u8fdb\u7a0b\u53ef\u4ee5\u8bf7\u6c42\u548c\u91ca\u653e\u67d0\u4e9b capability\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u5c06\u6743\u9650\u6388\u4e88\u8fdb\u7a0b\uff0c\u800c\u4e0d\u5fc5\u6388\u4e88\u6240\u6709\u6743\u9650\u3002 \u4f8b\u5982\uff0c\u53ef\u4ee5\u5c06 CAP_NET_BIND_SERVICE capability \u6388\u4e88\u67d0\u4e2a\u8fdb\u7a0b\uff0c\u8fd9\u6837\u8be5\u8fdb\u7a0b\u5c31\u53ef\u4ee5\u7ed1\u5b9a 1-1023 \u7684\u7aef\u53e3\uff0c\u800c\u4e0d\u5fc5\u5177\u6709 root \u6743\u9650\u3002\u7c7b\u4f3c\u5730\uff0c\u53ef\u4ee5\u5c06 CAP_SYS_ADMIN capability \u6388\u4e88\u67d0\u4e2a\u8fdb\u7a0b\uff0c\u8fd9\u6837\u8be5\u8fdb\u7a0b\u5c31\u53ef\u4ee5\u6267\u884c\u7cfb\u7edf\u7ba1\u7406\u4efb\u52a1\uff0c\u5982\u6302\u8f7d\u6587\u4ef6\u7cfb\u7edf\u548c\u521b\u5efa\u8bbe\u5907\u8282\u70b9\u7b49\u3002 Linux \u5185\u6838\u63d0\u4f9b\u4e86\u4e00\u7ec4\u9ed8\u8ba4\u7684 capabilities\uff0c\u4e5f\u53ef\u4ee5\u901a\u8fc7\u81ea\u5b9a\u4e49\u7684\u65b9\u5f0f\u521b\u5efa\u65b0\u7684 capabilities\uff0c\u4ee5\u4fbf\u66f4\u597d\u5730\u63a7\u5236\u7cfb\u7edf\u8d44\u6e90\u7684\u8bbf\u95ee\u6743\u9650\u3002\u53ef\u4ee5\u4f7f\u7528 setcap \u547d\u4ee4\u4e3a\u4e8c\u8fdb\u5236\u6587\u4ef6\u8bbe\u7f6e capabilities\u3002\u4f8b\u5982\uff0c\u4e0b\u9762\u7684\u547d\u4ee4\u5c06 CAP_NET_RAW capability \u6388\u4e88 /usr/bin/ping \u547d\u4ee4\uff1a sudo setcap cap_net_raw+ep /usr/bin/ping \u8fd9\u6837\uff0c\u7528\u6237\u5c31\u53ef\u4ee5\u4f7f\u7528 ping \u547d\u4ee4\u800c\u4e0d\u5fc5\u4ee5 root \u7528\u6237\u7684\u8eab\u4efd\u767b\u5f55\u3002 \u9664\u4e86 CAP_NET_BIND_SERVICE \u548c CAP_SYS_ADMIN \uff0c\u8fd8\u6709\u4e00\u4e9b\u5176\u4ed6\u7684 capabilities\uff0c\u4ee5\u4e0b\u662f\u4e00\u4e9b\u4f8b\u5b50\uff1a CAP_DAC_OVERRIDE \uff1a\u5141\u8bb8\u8fdb\u7a0b\u5ffd\u7565\u6587\u4ef6\u6743\u9650\uff0c\u53ef\u4ee5\u8bbf\u95ee\u4efb\u4f55\u6587\u4ef6\u3002 CAP_CHOWN \uff1a\u5141\u8bb8\u8fdb\u7a0b\u4fee\u6539\u6587\u4ef6\u7684\u6240\u6709\u8005\u3002 CAP_SETUID \u548c CAP_SETGID \uff1a\u5141\u8bb8\u8fdb\u7a0b\u4fee\u6539\u81ea\u5df1\u7684\u7528\u6237 ID \u548c\u7ec4 ID\u3002 CAP_NET_ADMIN \uff1a\u5141\u8bb8\u8fdb\u7a0b\u6267\u884c\u7f51\u7edc\u7ba1\u7406\u4efb\u52a1\uff0c\u5982\u914d\u7f6e\u7f51\u7edc\u63a5\u53e3\u548c\u8def\u7531\u8868\u7b49\u3002 CAP_SYS_RESOURCE \uff1a\u5141\u8bb8\u8fdb\u7a0b\u4fee\u6539\u7cfb\u7edf\u8d44\u6e90\u9650\u5236\uff0c\u5982 CPU \u65f6\u95f4\u548c\u5185\u5b58\u9650\u5236\u7b49\u3002 \u53ef\u4ee5\u901a\u8fc7\u547d\u4ee4 man 7 capabilities \u6765\u67e5\u770b\u7cfb\u7edf\u63d0\u4f9b\u7684 capabilities \u5217\u8868\u548c\u8be6\u7ec6\u8bf4\u660e\u3002\u5728\u4f7f\u7528 Kernel capabilities \u65f6\uff0c\u9700\u8981\u6ce8\u610f\uff0c\u53ea\u6709\u62e5\u6709 CAP_SETFCAP \u6216 CAP_SYS_ADMIN capability \u7684\u8fdb\u7a0b\u624d\u80fd\u591f\u4fee\u6539\u81ea\u5df1\u6216\u5176\u4ed6\u8fdb\u7a0b\u7684 capabilities\uff0c\u8fd9\u4e5f\u662f\u4e3a\u4e86\u4fdd\u62a4\u7cfb\u7edf\u7684\u5b89\u5168\u6027\u3002 \u5982\u679c\u6267\u884c setcap \u547d\u4ee4\u65f6\u51fa\u73b0 \"command not found\" \u7684\u9519\u8bef\uff0c\u8fd9\u901a\u5e38\u610f\u5473\u7740 setcap \u547d\u4ee4\u6240\u5728\u7684\u5305\u5c1a\u672a\u5b89\u88c5\u3002\u5728 openSUSE \u4e2d\uff0csetcap \u547d\u4ee4\u5305\u542b\u5728 libcap-progs \u8f6f\u4ef6\u5305\u4e2d\u3002 \u5728 openSUSE \u7cfb\u7edf\u4e2d\u9700\u8981\u5b89\u88c5 libcap-progs \u8f6f\u4ef6\u5305\uff1a sudo zypper in libcap-progs \u5728 Ubuntu/Debian \u7cfb\u7edf\u4e0a\u9700\u8981\u5b89\u88c5 libcap \u5e93\uff1a sudo apt-get install libcap2-bin \u5728 CentOS/RHEL \u7cfb\u7edf\u4e0a\u9700\u8981\u5b89\u88c5 libcap \u5e93\uff1a sudo yum install libcap-devel \u5b89\u88c5\u5b8c\u6210\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528 setcap \u547d\u4ee4\u4e3a\u4e8c\u8fdb\u5236\u6587\u4ef6\u8bbe\u7f6e capabilities\u3002\u5982\u679c\u8fd8\u662f\u65e0\u6cd5\u627e\u5230 setcap \u547d\u4ee4\uff0c\u53ef\u4ee5\u5c1d\u8bd5\u4f7f\u7528\u5b8c\u6574\u8def\u5f84 /sbin/setcap \u6216\u8005 /usr/sbin/setcap\u3002","title":"\u5185\u6838\u80fd\u529b"},{"location":"k8s/cka_cn/foundamentals/docker/#seccomp","text":"seccomp\uff08secure computing mode\uff09\u662f Linux \u5185\u6838\u63d0\u4f9b\u7684\u4e00\u79cd\u5b89\u5168\u673a\u5236\uff0c\u5b83\u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u80fd\u591f\u8fdb\u884c\u7684\u7cfb\u7edf\u8c03\u7528\u3002\u901a\u8fc7\u4f7f\u7528 seccomp\uff0c\u53ef\u4ee5\u9650\u5236\u8fdb\u7a0b\u53ea\u80fd\u591f\u4f7f\u7528\u5fc5\u8981\u7684\u7cfb\u7edf\u8c03\u7528\uff0c\u4ece\u800c\u51cf\u5c11\u7cfb\u7edf\u88ab\u653b\u51fb\u7684\u98ce\u9669\u3002 seccomp \u7b56\u7565\u53ef\u4ee5\u4f7f\u7528 BPF\uff08Berkeley Packet Filter\uff09\u8bed\u8a00\u7f16\u5199\uff0c\u5e76\u4f7f\u7528 seccomp() \u7cfb\u7edf\u8c03\u7528\u52a0\u8f7d\u3002\u4ee5\u4e0b\u662f\u4e00\u4e2a\u4f7f\u7528 seccomp \u7b56\u7565\u9650\u5236\u8fdb\u7a0b\u80fd\u591f\u8fdb\u884c\u7684\u7cfb\u7edf\u8c03\u7528\u7684\u793a\u4f8b\uff1a #include #include #include int main () { // \u521b\u5efa seccomp \u8fc7\u6ee4\u5668 struct sock_filter filter [] = { BPF_STMT ( BPF_LD | BPF_W | BPF_ABS , 0 ), BPF_JUMP ( BPF_JMP | BPF_JEQ | BPF_K , __NR_write , 0 , 1 ), BPF_STMT ( BPF_RET | BPF_K , SECCOMP_RET_ALLOW ), BPF_STMT ( BPF_RET | BPF_K , SECCOMP_RET_KILL ), }; struct sock_fprog prog = { . len = sizeof ( filter ) / sizeof ( filter [ 0 ]), . filter = filter , }; // \u52a0\u8f7d seccomp \u8fc7\u6ee4\u5668 if ( prctl ( PR_SET_SECCOMP , SECCOMP_MODE_FILTER , & prog ) < 0 ) { perror ( \"prctl\" ); return 1 ; } // \u8c03\u7528 write \u7cfb\u7edf\u8c03\u7528 char buf [] = \"Hello, world!\" ; write ( 1 , buf , sizeof ( buf )); return 0 ; } \u4e0a\u8ff0\u4ee3\u7801\u521b\u5efa\u4e86\u4e00\u4e2a seccomp \u8fc7\u6ee4\u5668\uff0c\u4ec5\u5141\u8bb8\u8fdb\u7a0b\u8c03\u7528 write() \u7cfb\u7edf\u8c03\u7528\uff0c\u5176\u4ed6\u7cfb\u7edf\u8c03\u7528\u5747\u4f1a\u88ab\u7981\u6b62\u3002\u53ef\u4ee5\u901a\u8fc7\u7f16\u8bd1\u5e76\u8fd0\u884c\u4e0a\u8ff0\u4ee3\u7801\u6765\u6f14\u793a seccomp \u7b56\u7565\u7684\u4f5c\u7528\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0cseccomp \u7b56\u7565\u53ea\u80fd\u591f\u9650\u5236\u8fdb\u7a0b\u8fdb\u884c\u7684\u7cfb\u7edf\u8c03\u7528\uff0c\u4f46\u4e0d\u80fd\u591f\u9650\u5236\u7cfb\u7edf\u8c03\u7528\u7684\u53c2\u6570\u6216\u8fd4\u56de\u503c\u3002\u56e0\u6b64\uff0c\u4f7f\u7528 seccomp \u7b56\u7565\u65f6\u9700\u8981\u7279\u522b\u5c0f\u5fc3\uff0c\u907f\u514d\u8bef\u7528\u6216\u4ea7\u751f\u6f0f\u6d1e\u3002","title":"seccomp\u7b56\u7565"},{"location":"k8s/cka_cn/foundamentals/docker/#netlink","text":"Netlink \u662f\u4e00\u79cd Linux \u5185\u6838\u63d0\u4f9b\u7684\u901a\u4fe1\u673a\u5236\uff0c\u7528\u4e8e\u5185\u6838\u548c\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4e4b\u95f4\u7684\u53cc\u5411\u901a\u4fe1\uff08IPC\uff09\u3002Netlink \u53ef\u4ee5\u7528\u4e8e\u8bb8\u591a\u76ee\u7684\uff0c\u4f8b\u5982\uff1a \u914d\u7f6e\u7f51\u7edc\u8bbe\u5907\u548c\u8def\u7531\u8868\uff1a\u4f7f\u7528 Netlink \u53ef\u4ee5\u901a\u8fc7\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4fee\u6539\u5185\u6838\u7684\u7f51\u7edc\u8bbe\u5907\u548c\u8def\u7531\u8868\u914d\u7f6e\uff0c\u4f8b\u5982\u6dfb\u52a0\u3001\u5220\u9664\u3001\u4fee\u6539\u7f51\u7edc\u63a5\u53e3\u3001IP \u5730\u5740\u3001\u8def\u7531\u7b49\u3002 \u76d1\u89c6\u7f51\u7edc\u4e8b\u4ef6\uff1a\u4f7f\u7528 Netlink \u53ef\u4ee5\u5b9e\u65f6\u5730\u4ece\u5185\u6838\u83b7\u53d6\u7f51\u7edc\u4e8b\u4ef6\u7684\u901a\u77e5\uff0c\u4f8b\u5982\u7f51\u7edc\u63a5\u53e3\u7684\u72b6\u6001\u53d8\u5316\u3001\u8def\u7531\u7684\u53d8\u5316\u7b49\u3002 \u7a0b\u5e8f\u95f4\u901a\u4fe1\uff1a\u4f7f\u7528 Netlink \u53ef\u4ee5\u5728\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4e4b\u95f4\u8fdb\u884c\u901a\u4fe1\uff0c\u7c7b\u4f3c\u4e8e Unix \u57df\u5957\u63a5\u5b57\u3002 Netlink \u673a\u5236\u57fa\u4e8e\u4e00\u79cd\u7279\u6b8a\u7684\u5957\u63a5\u5b57\u7c7b\u578b\uff08PF_NETLINK\uff09\u548c\u4e00\u4e2a\u7279\u5b9a\u7684\u534f\u8bae\uff08NETLINK\uff09\u3002\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u53ef\u4ee5\u901a\u8fc7\u521b\u5efa Netlink \u5957\u63a5\u5b57\u548c\u5185\u6838\u901a\u4fe1\u3002\u5185\u6838\u548c\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u4e4b\u95f4\u7684\u901a\u4fe1\u662f\u57fa\u4e8e Netlink \u6d88\u606f\u7684\uff0c\u6bcf\u4e2a Netlink \u6d88\u606f\u5305\u542b\u4e00\u4e2a\u6d88\u606f\u5934\u548c\u4e00\u4e2a\u8d1f\u8f7d\uff08payload\uff09\uff0c\u8d1f\u8f7d\u53ef\u4ee5\u662f\u4efb\u4f55\u7ed3\u6784\u4f53\u6216\u4e8c\u8fdb\u5236\u6570\u636e\u3002 Netlink \u6d88\u606f\u7684\u7c7b\u578b\u548c\u683c\u5f0f\u7531\u5185\u6838\u5b9a\u4e49\u3002\u7528\u6237\u7a7a\u95f4\u8fdb\u7a0b\u9700\u8981\u4e86\u89e3\u5185\u6838\u7684 Netlink \u6d88\u606f\u683c\u5f0f\u548c\u7c7b\u578b\uff0c\u624d\u80fd\u6b63\u786e\u5730\u6784\u9020\u548c\u89e3\u6790 Netlink \u6d88\u606f\u3002\u5e38\u7528\u7684 Netlink \u6d88\u606f\u7c7b\u578b\u5305\u62ec\uff1a RTM_NEWLINK \u548c RTM_DELLINK\uff1a\u6dfb\u52a0\u548c\u5220\u9664\u7f51\u7edc\u63a5\u53e3\u3002 RTM_NEWADDR \u548c RTM_DELADDR\uff1a\u6dfb\u52a0\u548c\u5220\u9664 IP \u5730\u5740\u3002 RTM_NEWROUTE \u548c RTM_DELROUTE\uff1a\u6dfb\u52a0\u548c\u5220\u9664\u8def\u7531\u3002 RTM_NEWNEIGH \u548c RTM_DELNEIGH\uff1a\u6dfb\u52a0\u548c\u5220\u9664 ARP \u8868\u9879\u3002 Netlink \u53ef\u4ee5\u4f7f\u7528 C \u8bed\u8a00\u7684 socket API \u8fdb\u884c\u7f16\u7a0b\u3002","title":"Netlink"},{"location":"k8s/cka_cn/foundamentals/docker/#netfilter","text":"Netfilter\u662fLinux\u5185\u6838\u4e2d\u7684\u4e00\u4e2a\u5b50\u7cfb\u7edf\uff0c\u7528\u4e8e\u5728\u6570\u636e\u5305\u4f20\u8f93\u8fc7\u7a0b\u4e2d\u8fdb\u884c\u8fc7\u6ee4\u548c\u64cd\u4f5c\u3002\u5b83\u652f\u6301\u5bf9\u7f51\u7edc\u6570\u636e\u5305\u8fdb\u884c\u5404\u79cd\u7c7b\u578b\u7684\u5904\u7406\uff0c\u5305\u62ec\u8fc7\u6ee4\u3001\u4fee\u6539\u3001\u91cd\u5b9a\u5411\u7b49\u3002Netfilter\u901a\u8fc7\u5728\u5185\u6838\u4e2d\u6ce8\u518c\u94a9\u5b50\u51fd\u6570\uff0c\u5728\u6570\u636e\u5305\u901a\u8fc7\u7f51\u7edc\u6808\u7684\u4e0d\u540c\u9636\u6bb5\u65f6\u8fdb\u884c\u62e6\u622a\u548c\u5904\u7406\u3002 Netfilter\u7684\u6838\u5fc3\u662fiptables\u547d\u4ee4\uff0c\u5b83\u53ef\u4ee5\u7528\u6765\u914d\u7f6eNetfilter\u89c4\u5219\u3002iptables\u547d\u4ee4\u53ef\u4ee5\u7528\u6765\u914d\u7f6e\u9632\u706b\u5899\u89c4\u5219\uff0cNAT\u89c4\u5219\uff0c\u9650\u5236\u8fde\u63a5\u901f\u5ea6\u7b49\u3002iptables\u547d\u4ee4\u901a\u8fc7\u5339\u914d\u4e0d\u540c\u7684\u6570\u636e\u5305\u5b57\u6bb5\uff08\u4f8b\u5982\u6e90IP\u5730\u5740\u3001\u76ee\u7684IP\u5730\u5740\u3001\u6e90\u7aef\u53e3\u3001\u76ee\u7684\u7aef\u53e3\u7b49\uff09\u6765\u8fdb\u884c\u8fc7\u6ee4\u3002 \u9664\u4e86iptables\u547d\u4ee4\uff0c\u8fd8\u6709\u5176\u4ed6\u4e00\u4e9b\u5de5\u5177\u53ef\u4ee5\u7528\u4e8e\u914d\u7f6eNetfilter\u89c4\u5219\uff0c\u4f8b\u5982nftables\u547d\u4ee4\u548cfirewalld\u670d\u52a1\u3002\u8fd9\u4e9b\u5de5\u5177\u63d0\u4f9b\u4e86\u66f4\u7075\u6d3b\u3001\u66f4\u5f3a\u5927\u7684\u914d\u7f6e\u9009\u9879\uff0c\u53ef\u4ee5\u5e2e\u52a9\u7ba1\u7406\u5458\u66f4\u597d\u5730\u7ba1\u7406\u548c\u4fdd\u62a4\u7f51\u7edc\u5b89\u5168\u3002 \u4e5f\u53ef\u4ee5\u7528\u4e8e\u5c06\u7f51\u7edc\u6570\u636e\u5305\u5b9a\u5411\u5230\u5355\u4e2a\u5bb9\u5668\u3002 \u66f4\u591a\u4fe1\u606f\u53ef\u4ee5\u53c2\u8003 LXC/LXD \u3002","title":"Netfilter"},{"location":"k8s/cka_cn/foundamentals/docker/#docker","text":"\u53c2\u8003 \u6307\u5bfc \u5b89\u88c5Docker\u5f15\u64ce\u3002 \u53c2\u8003 \u6307\u5bfc \u5b89\u88c5Docker\u684c\u9762\u7248\u3002 \u4e0b\u9762\u4ee5openSUSE\u4e3a\u4f8b\u5b89\u88c5Docker\u5f15\u64ce\u3002 sudo zypper in docker \u5728\u5b89\u88c5\u8fc7\u7a0b\u4e2d\uff0c\u5728\u64cd\u4f5c\u7cfb\u7edf\u4e2d\u4f1a\u81ea\u52a8\u521b\u5efa\u7ec4 docker \u3002 \u5c06vagrant\u7528\u6237\u52a0\u5165docker\u7ec4\uff0c\u5219vagrant\u7528\u6237\u53ef\u4ee5\u5728\u4e0b\u6b21\u767b\u5f55\u540e\u4e0e\u672c\u673a\u7684Docker\u5b88\u62a4\u8fdb\u7a0b\uff08daemon\uff09\u8fdb\u884c\u901a\u4fe1\u3002Docker\u5b88\u62a4\u8fdb\u7a0b\u76d1\u542c\u672c\u5730\u5957\u63a5\u5b57\uff0c\u53ea\u80fd\u7531root\u7528\u6237\u548cdocker\u7ec4\u7684\u6210\u5458\u8bbf\u95ee\u3002 sudo usermod -aG docker $USER \u542f\u7528\u5e76\u542f\u52a8 Docker \u5f15\u64ce\u3002 sudo systemctl enable docker.service sudo systemctl start docker.service sudo systemctl status docker.service \u4e0b\u9762\u901a\u8fc7\u4e00\u4e2a\u5bb9\u5668 alpine \u7684\u4f8b\u5b50\u6765\u6f14\u793a\u5728\u76ee\u5f55 /opt/test \u4e0b\u6a21\u62df\u5b9e\u73b0choot\u3002 mkdir test cd test wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.4-x86_64.tar.gz tar zxvf alpine-minirootfs-3.13.4-x86_64.tar.gz -C alpine-minirootfs/ \u67e5\u770b\u5f53\u524d\u76ee\u5f55\u7ed3\u6784\uff1a tree ./test -L 1 \u8f93\u51fa\u7ed3\u679c\uff1a ./test \u251c\u2500\u2500 alpine-minirootfs-3.13.4-x86_64.tar.gz \u251c\u2500\u2500 bin \u251c\u2500\u2500 dev \u251c\u2500\u2500 etc \u251c\u2500\u2500 home \u251c\u2500\u2500 lib \u251c\u2500\u2500 media \u251c\u2500\u2500 mnt \u251c\u2500\u2500 opt \u251c\u2500\u2500 proc \u251c\u2500\u2500 root \u251c\u2500\u2500 run \u251c\u2500\u2500 sbin \u251c\u2500\u2500 srv \u251c\u2500\u2500 sys \u251c\u2500\u2500 tmp \u251c\u2500\u2500 usr \u2514\u2500\u2500 var \u901a\u8fc7\u547d\u4ee4 unshare \u6302\u8f7d\u76ee\u5f55 /opt/test/proc \u5230\u67d0\u4e2a\u6587\u4ef6\u6765\u5b9e\u73b0\u5ba2\u6237\u5b50\u7cfb\u7edf\u3002 sudo mount -t tmpfs tmpfs /opt/test/proc sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # ps -ef PID USER TIME COMMAND 1 root 0 :00 /bin/sh 2 root 0 :00 ps -ef / # touch 123 / # ls 123 123 \u6587\u4ef6 123 \u5728\u5ba2\u6237\u5b50\u7cfb\u7edf\u4e2d\u5df2\u521b\u5efa\uff0c\u5bf9\u5e94\u4e3b\u7cfb\u7edf\u4e2d\u4e5f\u53ef\u4ee5\u5bf9\u5176\u8fdb\u884c\u8bfb\u5199\u64cd\u4f5c\u3002\u6bd4\u5982\uff0c\u4fee\u6539\u6587\u4ef6 123 \u7684\u5185\u5bb9\u3002 su - ls 123 echo hello > 123 \u6587\u4ef6 123 \u4fee\u6539\u540e\u7684\u5185\u5bb9\u5728\u5ba2\u6237\u673a\u91cc\u9762\u4e5f\u53ef\u89c1\u3002 / # cat 123 hello \u5728\u4e3b\u7cfb\u7edf\u4e2d\u518d\u521b\u5efa\u4e24\u4e2a\u5b50\u76ee\u5f55 /opt/test-1 \u548c /opt/test-2 \u3002 mkdir test-1 mkdir test-2 \u521b\u5efa2\u4e2a\u5ba2\u6237\u5b50\u7cfb\u7edf\uff0c\u5e76\u5c06\u4e0a\u9762\u7684\u4e24\u4e2a\u5b50\u76ee\u5f55\u6302\u5728\u5230\u5404\u81ea\u7684 /opt/test/home/ \u76ee\u5f55\u3002 sudo mount --bind /opt/test-1 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-1\" > 123.1 /home # cat 123.1 test-1 sudo mount --bind /opt/test-2 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-2\" > 123.2 /home # cat 123.2 test-2 ll test/home ll test-1/ ll test-2/ \u901a\u8fc7\u4e0a\u9762\u7684\u6f14\u793a\uff0c\u53ef\u4ee5\u5f97\u51fa\u7ed3\u8bba\uff0c\u4e24\u4e2a\u5ba2\u6237\u5b50\u7cfb\u7edf\u6302\u5728\u5230\u540c\u4e00\u4e2a\u4e3b\u7cfb\u7edf\u76ee\u5f55\u65f6\uff0c\u5b50\u7cfb\u7edf\u65f6\u5171\u4eab\u4e3b\u7cfb\u7edf\u76ee\u5f55\uff0c\u5e76\u76f8\u4e92\u5f71\u54cd\u3002","title":"\u5b89\u88c5Docker"},{"location":"k8s/cka_cn/foundamentals/docker/#_6","text":"","title":"\u5bb9\u5668\u751f\u547d\u5468\u671f"},{"location":"k8s/cka_cn/foundamentals/docker/#_7","text":"\u9884\u5148\u4e0b\u8f7d\u4e0b\u5217\u955c\u50cf\u3002 docker image pull busybox docker image pull nginx docker image pull alpine docker image pull jenkins/jenkins:lts docker image pull golang:1.12-alpine docker image pull golang \u521b\u5efa\u5e76\u4ea4\u4e92\u5f0f\u8fd0\u884c\u4e00\u4e2a\u65b0\u7684busybox\u5bb9\u5668\uff0c\u5e76\u8fde\u63a5\u4e00\u4e2a\u4f2a\u7ec8\u7aef\uff08pseudo terminal\uff09\u3002 \u5728\u5bb9\u5668\u5185\uff0c\u4f7f\u7528 top \u547d\u4ee4\u67e5\u627e /bin/sh \u6b63\u5728\u4f5c\u4e3aPID\u4e3a1\u7684\u8fdb\u7a0b\u8fd0\u884c\uff0c\u4ee5\u53ca top \u8fdb\u7a0b\u4e5f\u5728\u8fd0\u884c\u3002 \u7136\u540e\uff0c\u9000\u51fa\u5bb9\u5668\u3002 docker image ls docker run -d -it --name busybox_v1 -v /opt/test:/docker busybox:latest /bin/sh docker container ps -a docker exec -it 185efe490507 /bin/sh / # top Mem: 3627396K used, 12731512K free, 10080K shrd, 2920K buff, 2999340K cached CPU: 0 .0% usr 0 .1% sys 0 .0% nic 99 .8% idle 0 .0% io 0 .0% irq 0 .0% sirq Load average: 0 .38 1 .09 1 .29 2 /277 14 PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND 1 0 root S 1332 0 .0 1 0 .0 /bin/sh 8 0 root S 1332 0 .0 2 0 .0 /bin/sh 14 8 root R 1328 0 .0 1 0 .0 top / # exitbuild \u542f\u52a8\u4e00\u4e2a\u65b0\u7684 Nginx \u5bb9\u5668\uff0c\u5e76\u4ee5\u72ec\u7acb\u6a21\u5f0f\uff08detached mode\uff09\u8fd0\u884c\u3002 \u4f7f\u7528 docker exec \u547d\u4ee4\u5728 Nginx \u5bb9\u5668\u4e2d\u542f\u52a8\u53e6\u4e00\u4e2a shell\uff08 /bin/sh \uff09\u3002 \u4f7f\u7528 ps \u547d\u4ee4\u67e5\u770b\u5bb9\u5668\u4e2d\u6b63\u5728\u8fd0\u884c\u7684 sh \u548c ps \u547d\u4ee4\uff08\u5728\u4e0a\u4e00\u6b65\u6267\u884c\u7684\uff09\u3002 docker run -d -it --name nginx_v1 -v /opt/test:/docker nginx:latest /bin/sh docker container ps -a docker exec -it edb640127a0d /bin/sh # ps /bin/sh: 2 : ps: not found # apt-get update && apt-get install -y procps # ps PID TTY TIME CMD 8 pts/1 00 :00:00 sh 351 pts/1 00 :00:00 ps # exit \u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u770b\u52302\u4e2a\u73b0\u5728\u8fd0\u884c\u4e2d\u7684\u5bb9\u5668\u3002 docker container ps -a \u4f7f\u7528 docker logs \u547d\u4ee4\u663e\u793a\u6211\u4eec\u521a\u521a\u9000\u51fa\u7684\u5bb9\u5668\u7684\u65e5\u5fd7\u3002\u9009\u9879 --since 35m \u8868\u793a\u663e\u793a\u6700\u8fd1 35 \u5206\u949f\u5185\u7684\u65e5\u5fd7\u3002 docker logs nginx_v1 --details --since 35m docker logs busybox_v1 --details --since 35m \u4f7f\u7528 docker stop \u547d\u4ee4\u6765\u505c\u6b62 nginx \u5bb9\u5668\u3002 docker stop busybox_v1 docker stop nginx_v1 docker container ps -a \u4f7f\u7528\u4e0a\u8ff0\u547d\u4ee4 docker container ps -a \uff0c\u6211\u4eec\u53ef\u4ee5\u83b7\u53d6\u6240\u6709\u6b63\u5728\u8fd0\u884c\u548c\u5df2\u9000\u51fa\u7684\u5bb9\u5668\u5217\u8868\u3002\u4f7f\u7528 docker rm \u5c06\u5176\u5220\u9664\u3002\u4f7f\u7528 docker rm $(docker ps -aq) \u6765\u6e05\u7406\u4e3b\u673a\u4e0a\u7684\u6240\u6709\u5bb9\u5668\u3002\u8bf7\u8c28\u614e\u4f7f\u7528\uff01 docker rm busybox_v1 docker container ps -a","title":"\u6982\u8ff0"},{"location":"k8s/cka_cn/foundamentals/docker/#_8","text":"\u73b0\u5728\u542f\u52a8\u4e00\u4e2a\u65b0\u7684 nginx \u5bb9\u5668\uff0c\u5e76\u5c06 nginx web \u670d\u52a1\u5668\u7684\u7aef\u53e3\u5bfc\u51fa\u5230 Docker \u968f\u673a\u9009\u62e9\u7684\u7aef\u53e3\u3002 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u547d\u4ee4 docker ps \u627e\u51fa web \u670d\u52a1\u5668\u8f6c\u53d1\u5230\u4e86\u54ea\u4e2a\u7aef\u53e3\u3002\u5728\u4e3b\u673a\u4e0a\u4f7f\u7528\u8f6c\u53d1\u7684\u7aef\u53e3\u53f7\u8bbf\u95ee docker http://localhost: \u3002 docker container ps -a docker run -d -P --name nginx_v2 nginx:latest docker container ps -a Start another nginx container and expose port to 1080 on host as an example via http://localhost:1080 . \u542f\u52a8\u53e6\u4e00\u4e2anginx\u5bb9\u5668\uff0c\u5c06\u5176\u7aef\u53e3\u6620\u5c04\u5230\u4e3b\u673a\u76841080\u7aef\u53e3\uff0c\u53ef\u4ee5\u901a\u8fc7 http://localhost:1080 \u8bbf\u95ee\u3002 docker run -d -p 1080 :80 --name nginx_v3 nginx:latest docker container ps -a \u4f7f\u7528 docker inspect \u547d\u4ee4\u67e5\u627e\u955c\u50cf\u66b4\u9732\u7684\u7aef\u53e3\u53f7\uff0c\u8f93\u51faJSON\u683c\u5f0f\u6587\u4ef6\uff0c\u7f51\u7edc\u4fe1\u606f\uff08IP\u3001\u7f51\u5173\u3001\u7aef\u53e3\u7b49\uff09\u662f\u8f93\u51faJSON\u683c\u5f0f\u7684\u4e00\u90e8\u5206\u3002 docker inspect nginx_v3 \u5728\u76ee\u5f55 /opt/test \u4e2d\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a index.html \u7684\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u5982\u4e0b\uff1a < html > < head > < title > Sample Website from my container < body > < h1 > This is a custom website. < p > This website is served from my < a href = \"http://www.docker.com\" target = \"_blank\" > Docker container. \u542f\u52a8\u4e00\u4e2a\u65b0\u5bb9\u5668\uff0c\u5c06\u4e3b\u673a\u76ee\u5f55 /opt/test \u4e0e\u5bb9\u5668\u76ee\u5f55 /usr/share/nginx/html \u7ed1\u5b9a\u6302\u8f7d\u4e3a\u4e00\u4e2a\u5377\uff0c\u4ee5\u4fbfNginx\u53ef\u4ee5\u901a\u8fc7 http://localhost:49159/ \u53d1\u5e03\u6211\u4eec\u521a\u521b\u5efa\u7684html\u6587\u4ef6\uff0c\u800c\u4e0d\u662fNginx\u9ed8\u8ba4\u7684\u9875\u9762\u3002 docker run -d -P --mount type = bind,source = /opt/test/,target = /usr/share/nginx/html --name nginx_v3-1 nginx:latest docker container ps -a \u68c0\u67e5Nginx\u914d\u7f6e\u6587\u4ef6\uff0c\u67e5\u770b\u5bb9\u5668\u4e2dhtml\u4e3b\u9875\u5b58\u50a8\u7684\u4f4d\u7f6e\u3002 docker exec -it nginx_v3-1 /bin/sh # cd /etc/nginx/conf.d # ls default.conf # cat default.conf server { listen 80 ; listen [ :: ] :80 ; server_name localhost ; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html ; <-- index index.html index.htm ; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html ; location = /50x.html { root /usr/share/nginx/html ; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \\.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \\.php$ { # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\\.ht { # deny all; #} } # cd /usr/share/nginx/html # cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    # \u63a8\u8350\u4f7f\u7528\u5377 API \u6765\u5b9e\u73b0\u6570\u636e\u6301\u4e45\u5316\uff0c\u800c\u4e0d\u662f\u5c06\u6570\u636e\u5b58\u50a8\u5728 Docker \u5bb9\u5668\u4e2d\u3002Docker \u652f\u6301\u4e24\u79cd\u6302\u8f7d\u65b9\u5f0f\uff1a \u7ed1\u5b9a\u6302\u8f7d\uff08Bind mounts\uff09\uff1a \u5c06\u672c\u5730\u4e3b\u673a\u76ee\u5f55\u6302\u8f7d\u5230\u5bb9\u5668\u4e2d\u7684\u67d0\u4e2a\u8def\u5f84\u3002 \u6302\u8f7d\u540e\uff0c\u76ee\u6807\u76ee\u5f55\u4e2d\u539f\u6709\u7684\u6240\u6709\u5185\u5bb9\u5c06\u88ab\u9690\u85cf\u3002 \u4f8b\u5982\uff0c\u5982\u679c\u6211\u4eec\u60f3\u8981\u6ce8\u5165\u67d0\u4e9b\u914d\u7f6e\u6587\u4ef6\uff0c\u6211\u4eec\u9700\u8981\u81ea\u5df1\u5199\u5bf9\u5e94\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5c06\u5176\u5b58\u50a8\u5728 Docker \u4e3b\u673a\u4e0a\u7684 /home/container/config \u8def\u5f84\u4e0b\uff0c\u5e76\u5c06\u6b64\u76ee\u5f55\u7684\u5185\u5bb9\u6302\u8f7d\u5230 /usr/application/config \uff08\u5047\u8bbe\u5e94\u7528\u7a0b\u5e8f\u4ece\u6b64\u5904\u8bfb\u53d6\u914d\u7f6e\uff09\u3002 \u547d\u4ee4\uff1a docker run --mount type=bind,source=,target= \u2026 \u547d\u540d\u5377\uff08Named volumes\uff09\uff1a Docker \u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u72ec\u7acb\u7684\u5b58\u50a8\u5377\uff0c\u5176\u751f\u547d\u5468\u671f\u72ec\u7acb\u4e8e\u5bb9\u5668\u4f46\u4ecd\u7531 Docker \u7ba1\u7406\u3002 \u5728\u521b\u5efa\u65f6\uff0c\u6302\u8f7d\u76ee\u6807\u7684\u5185\u5bb9\u5c06\u5408\u5e76\u5230\u5377\u4e2d\u3002 \u547d\u4ee4\uff1a docker run --mount source=,target= \u2026 \u5982\u4f55\u533a\u5206\u7ed1\u5b9a\u6302\u8f7d\u548c\u547d\u540d\u5377\uff1f \u5f53\u6307\u5b9a\u7edd\u5bf9\u8def\u5f84\u65f6\uff0cDocker \u4f1a\u8ba4\u4e3a\u8fd9\u662f\u4e00\u4e2a\u7ed1\u5b9a\u6302\u8f7d\u3002 \u5f53\u6211\u4eec\u4ec5\u63d0\u4f9b\u540d\u79f0\uff08\u5982\u76f8\u5bf9\u8def\u5f84 config \uff09\u65f6\uff0c\u5b83\u4f1a\u8ba4\u4e3a\u8fd9\u662f\u4e00\u4e2a\u547d\u540d\u5377\uff0c\u5e76\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a config \u7684\u5377\u3002 \u6ce8\uff1a\u6301\u4e45\u5b58\u50a8\u7531\u4e3b\u673a\u63d0\u4f9b\uff0c\u53ef\u4ee5\u76f4\u63a5\u662f\u4e3b\u673a\u6587\u4ef6\u7cfb\u7edf\u7684\u4e00\u90e8\u5206\uff0c\u4e5f\u53ef\u4ee5\u662f NFS \u6302\u8f7d\u3002","title":"\u7aef\u53e3\u548c\u5377"},{"location":"k8s/cka_cn/foundamentals/docker/#dockerfile","text":"\u8ba9\u6211\u4eec\u7528 Dockerfile \u6784\u5efa\u4e00\u4e2a\u955c\u50cf\uff0c\u5bf9\u5176\u8fdb\u884c\u6253\u6807\u7b7e\u5e76\u4e0a\u4f20\u5230\u955c\u50cf\u4ed3\u5e93\u3002 \u83b7\u53d6 Docker \u955c\u50cf\u7684\u6784\u5efa\u5386\u53f2\u8bb0\u5f55\u3002 docker image history nginx:latest \u521b\u5efa\u4e00\u4e2a\u7a7a\u7684\u76ee\u5f55 /opt/tmp-1 \uff0c\u8fdb\u5165\u8be5\u76ee\u5f55\u5e76\u5728\u5176\u4e2d\u521b\u5efa index.html \u6587\u4ef6\u3002 /opt/tmp-1> cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    \u4f7f\u7528 FROM \u6765\u6269\u5c55\u4e00\u4e2a\u5df2\u6709\u7684\u955c\u50cf\uff0c\u5e76\u6307\u5b9a\u7248\u672c\u53f7\u3002 \u4f7f\u7528 COPY \u5c06\u4e00\u4e2a\u65b0\u7684\u9ed8\u8ba4\u7f51\u7ad9\u590d\u5236\u5230\u955c\u50cf\u4e2d\uff0c\u4f8b\u5982 /usr/share/nginx/html \u3002 \u4e3aNginx\u521b\u5efaSSL\u914d\u7f6e /opt/tmp-1/ssl.conf \u3002 server { listen 443 ssl; server_name localhost; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; location / { root /usr/share/nginx/html; index index.html index.htm; } } \u4f7f\u7528OpenSSL\u521b\u5efa\u4e00\u4e2a\u81ea\u7b7e\u540d\u8bc1\u4e66\uff0c\u4ee5\u4fbfSSL/TLS\u5de5\u4f5c\u3002 \u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u521b\u5efa\u4e00\u4e2a\u52a0\u5bc6\u5bc6\u94a5\u548c\u8bc1\u4e66\u3002 openssl req -x509 -nodes -newkey rsa:4096 -keyout nginx.key -out nginx.crt -days 365 -subj \"/CN= $( hostname ) \" \u4e3a\u4e86\u542f\u7528\u52a0\u5bc6\u7684HTTPS\uff0c\u6211\u4eec\u9700\u8981\u4f7f\u7528 EXPOSE \u6307\u4ee4\u516c\u5f00 443 \u7aef\u53e3\u3002\u9ed8\u8ba4\u7684nginx\u955c\u50cf\u4ec5\u516c\u5f00\u7aef\u53e3 80 \uff0c\u7528\u4e8e\u975e\u52a0\u5bc6\u7684HTTP\u3002 \u5728 /opt/tmp-1 \u6587\u4ef6\u5939\u4e2d\u521b\u5efa\u4ee5\u4e0bDockerfile\u3002 cat Dockerfile \u8f93\u51fa\uff1a FROM nginx:latest # copy the custom website into the image COPY index.html /usr/share/nginx/html # copy the SSL configuration file into the image COPY ssl.conf /etc/nginx/conf.d/ssl.conf # download the SSL key and certificate into the image COPY nginx.key /etc/nginx/ssl/ COPY nginx.crt /etc/nginx/ssl/ # expose the HTTPS port EXPOSE 443 \u81f3\u6b64\uff0c\u6211\u4eec\u5728\u76ee\u5f55 /opt/tmp-1 \u4e0b\u67095\u4e2a\u6587\u4ef6\u3002 ls /opt/tmp-1 \u8f93\u51fa\uff1a Dockerfile index.html nginx.crt nginx.key ssl.conf \u4f7f\u7528 docker build \u547d\u4ee4\u6765\u6784\u5efa\u955c\u50cf\uff0c\u5e76\u5c06\u5bb9\u5668\u768480\u548c443\u7aef\u53e3\u8f6c\u53d1\u3002 docker build -t nginx:my1 /opt/tmp-1/ docker image ls docker run -d -p 1086 :80 -p 1088 :443 --name nginx_v5 nginx:my1 docker container ps -a \u901a\u8fc7\u4e0b\u9762\u4e24\u4e2a\u94fe\u63a5\u6765\u9a8c\u8bc1\u4e0a\u9762\u7684\u53d8\u5316\u662f\u5426\u751f\u6548\u3002 http://localhost:1086/ https://localhost:1088/ \u5728 DockerHub \u6ce8\u518c\u4e00\u4e2a\u4e2a\u4eba\u8d26\u53f7\uff0c\u542f\u7528 Docker Hub \u4e2d\u7684\u8bbf\u95ee\u4ee4\u724c\u4ee5\u8fdb\u884c CLI \u5ba2\u6237\u7aef\u8eab\u4efd\u9a8c\u8bc1\u3002 docker login \u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002 Username: Password: \u7ed9\u8fd9\u4e2a\u955c\u50cf\u52a0\u4e0a\u4e00\u4e2a\u6807\u7b7e\uff0c\u4f8b\u5982\uff1asecure_nginx_0001\uff0c\u7248\u672c\u53f7\u4e3a v1\u3002 docker tag nginx:my1 secure_nginx_0001:v1 docker push secure_nginx_0001:v1 docker image ls","title":"Dockerfile"},{"location":"k8s/cka_cn/foundamentals/docker/#dockerfile_1","text":"\u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u6f14\u793a\u4e00\u4e2a\u591a\u9636\u6bb5\uff08Multi-stage\uff09\u6784\u5efa\u7684\u4f8b\u5b50\u3002\u5728Docker\u7684\u4e0a\u4e0b\u6587\u4e2d\uff0c\u591a\u9636\u6bb5\uff08Multi-stage\uff09\u610f\u5473\u7740\u6211\u4eec\u53ef\u4ee5\u6709\u591a\u4e2a\u5e26\u6709 FROM \u5173\u952e\u5b57\u7684\u884c\u3002 \u521b\u5efa\u6587\u4ef6\u5939 /opt/tmp-2 \u548c /opt/tmp-2/tmpl \u3002\u521b\u5efa\u6587\u4ef6 edit.html \uff0c view.html \uff0c wiki.go \u3002 \u6587\u4ef6\u7ed3\u6784\u5982\u4e0b\uff1a tree -l /opt/tmp-2 \u8f93\u51fa\u7ed3\u679c\uff1a . \u251c\u2500\u2500 tmpl \u2502 \u251c\u2500\u2500 edit.html \u2502 \u2514\u2500\u2500 view.html \u2514\u2500\u2500 wiki.go \u521b\u5efa\u4e00\u4e2a\u65b0\u7684Dockerfile\u3002 cat Dockerfile \u6587\u4ef6\u5185\u5bb9\uff1a # app builder stage FROM golang:1.12-alpine as builder # # copy the go source code over and build the binary WORKDIR /go/src COPY wiki.go /go/src/wiki.go RUN go build wiki.go # app exec stage # separate & new image starts here!# FROM alpine:3.9 # prepare file system etc RUN mkdir -p /app/data /app/tmpl && adduser -S -D -H -h /app appuser COPY tmpl/* /app/tmpl/ # get the compiled binary from the previous stage COPY --from=builder /go/src/wiki /app/wiki # prepare runtime env RUN chown -R appuser /app USER appuser WORKDIR /app # expose app port & set default command EXPOSE 8080 CMD [\"/app/wiki\"] \u7528\u4e0a\u4e00\u6b65\u521b\u5efa\u7684Dockerfile\u6765\u521b\u5efa\u65b0\u666f\u8c61\u3002 docker build -t lizard/golang:my1 /opt/tmp-2/ \u4ee5\u72ec\u7acb\u6a21\u5f0f\uff08detached\uff09\u8fd0\u884c\u8fd9\u4e2a\u955c\u50cf\uff0c\u5e76\u5c06\u5bb9\u5668\u7aef\u53e3 8080 \u8f6c\u53d1\u5230\u4e3b\u673a\u7aef\u53e3 1090 \u3002 docker run -d -p 1090 :8080 --name golan_v1 lizard/golang:my1 \u901a\u8fc7\u94fe\u63a5 http://localhost:1090 \u8bbf\u95ee\u8fd9\u4e2a\u8fd0\u884c\u7684\u5bb9\u5668\u3002 \u5bf9\u6211\u4eec\u521a\u521a\u521b\u5efa\u7684\u65b0\u7684golang\u955c\u50cf\u8fdb\u884c\u6807\u7b7e\uff0c\u5e76\u4e14\u4e0a\u4f20\u5230Dockerhub\u3002 docker tag lizard/golang:my1 /golang_0001:v1 docker push /golang_0001:v1","title":"\u591a\u9636\u6bb5Dockerfile"},{"location":"k8s/cka_cn/foundamentals/healthcheck/","text":"CKA\u81ea\u5b66\u7b14\u8bb026:\u5065\u5eb7\u68c0\u67e5 \u00b6 Pod\u548cContainer\u7684\u72b6\u6001 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u67092\u4e2a\u5bb9\u5668\u7684pod\u3002 \u6f14\u793a\uff1a \u521b\u5efa\u4e00\u4e2a\u5305\u542b\u4e24\u4e2a\u5bb9\u5668 nginx \u548c busybox \u7684 Pod\uff0c\u547d\u540d\u4e3a multi-pods \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: labels: run: multi-pods name: multi-pods spec: containers: - image: nginx name: nginx - image: busybox name: busybox dnsPolicy: ClusterFirst restartPolicy: Always EOF \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u6765\u76d1\u63a7\u72b6\u6001\uff0c\u4f7f\u7528\u9009\u9879 --watch \u3002 \u6ce8\u610f\uff0cpod\u7684\u72b6\u6001\u5df2\u7ecf\u4ece ContainerCreating \u53d8\u4e3a NotReady \uff0c\u518d\u53d8\u4e3a CrashLoopBackOff \u3002 kubectl get pod multi-pods --watch \u83b7\u53d6 Pod multi-pods \u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u5173\u6ce8 Containers \u90e8\u5206\u4e0b\u7684\u5bb9\u5668\u72b6\u6001\u548c Conditions \u90e8\u5206\u4e0b\u7684 Pod \u72b6\u6001\u3002 kubectl describe pod multi-pods \u8fd0\u884c\u7ed3\u679c\uff08\u90e8\u5206\uff09\uff1a ...... Containers : nginx : ...... State : Running Started : Sat, 23 Jul 2022 15:06:56 +0800 Ready : True Restart Count : 0 ...... busybox : ...... State : Terminated Reason : Completed Exit Code : 0 ...... Conditions : Type Status Initialized True Ready False ContainersReady False PodScheduled True ...... LivenessProbe \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2apod\uff0c\u5185\u542b livenessProbe \u68c0\u67e5\u3002 \u6f14\u793a\u7684\u8be6\u7ec6\u8bf4\u660e\u53ef\u4ee5\u67e5\u8be2 Kubernetes document \u3002 \u6f14\u793a\uff1a \u521b\u5efayaml\u6587\u4ef6 liveness.yaml \uff0c\u5e76\u5305\u542b livenessProbe \u914d\u7f6e\uff0c\u5e76\u5e94\u7528\u4e4b\u3002 kubectl apply -f - <> ~/.bashrc source < ( helm completion bash ) \u901a\u8fc7Helm\u5b89\u88c5MySQL \u00b6 \u6dfb\u52a0Bitnami Chartes\u4ed3\u5e93\u3002 helm repo add bitnami https://charts.bitnami.com/bitnami \u67e5\u8be2\u5f53\u524d\u53ef\u7528\u7684Chartes\u4ed3\u5e93\u3002 helm repo list \u8fd0\u884c\u7ed3\u679c\uff1a NAME URL bitnami https://charts.bitnami.com/bitnami \u540c\u6b65\u672c\u5730Charts\u4ed3\u5e93\u3002 helm repo update \u5728Charts\u4ed3\u5e93\u4e2d\u67e5\u627ebitnami Charts\u4ed3\u5e93\u3002 helm search repo bitnami \u5728\u4ed3\u5e93\u4e2d\u641c\u7d22bitnami/mysql Charts\u3002 helm search repo bitnami/mysql \u5728namespace dev \u4e0a\u5b89\u88c5MySQL Chart\u3002 helm install mysql bitnami/mysql -n dev \u8fd0\u884c\u7ed3\u679c\uff1a NAME: mysql LAST DEPLOYED: Sun Jul 24 19:37:20 2022 NAMESPACE: dev STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: mysql CHART VERSION: 9.2.1 APP VERSION: 8.0.29 ** Please be patient while the chart is being deployed ** Tip: Watch the deployment status using the command: kubectl get pods -w --namespace dev Services: echo Primary: mysql.dev.svc.cluster.local:3306 Execute the following to get the administrator credentials: echo Username: root MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace dev mysql -o jsonpath=\"{.data.mysql-root-password}\" | base64 -d) To connect to your database: 1. Run a pod that you can use as a client: kubectl run mysql-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mysql:8.0.29-debian-11-r9 --namespace dev --env MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD --command -- bash 2. To connect to primary service (read/write): mysql -h mysql.dev.svc.cluster.local -uroot -p\"$MYSQL_ROOT_PASSWORD\" \u67e5\u770b\u5f53\u524d\u5b89\u88c5\u5305\u7684\u4fe1\u606f\u3002 helm list \u8fd0\u884c\u7ed3\u679c\uff1a NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 \u68c0\u67e5\u5f53\u524d\u5b89\u88c5\u7684mysql\u7248\u672c\u4fe1\u606f\u3002 helm status mysql \u68c0\u67e5pod mysql \u7684\u72b6\u6001\u3002 kubectl get pod \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE mysql-0 1/1 Running 0 72s \u90e8\u7f72\u4e00\u4e2aChart \u00b6 \u4e0b\u9762\u6f14\u793a\u4e86\u5982\u4f55\u90e8\u7f72\u4e00\u4e2aChart\u3002 \u6267\u884c\u547d\u4ee4 helm create \u6765\u521d\u59cb\u5316\u4e00\u4e2aChart\u3002 # Naming conventions of Chart: lowercase a~z and -(minus sign) helm create cka-demo \u76ee\u5f55 cka-demo \u4f1a\u88ab\u521b\u5efa\uff0c\u67e5\u770b\u8fd9\u4e2a\u76ee\u5f55\u7684\u7ed3\u6784\u3002 tree cka-demo/ \u8fd0\u884c\u7ed3\u679c\uff1a cka-demo/ \u251c\u2500\u2500 charts \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 deployment.yaml \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u251c\u2500\u2500 hpa.yaml \u2502 \u251c\u2500\u2500 ingress.yaml \u2502 \u251c\u2500\u2500 NOTES.txt \u2502 \u251c\u2500\u2500 serviceaccount.yaml \u2502 \u251c\u2500\u2500 service.yaml \u2502 \u2514\u2500\u2500 tests \u2502 \u2514\u2500\u2500 test-connection.yaml \u2514\u2500\u2500 values.yaml \u5220\u9664\u6216\u6e05\u7a7a\u67d0\u4e9b\u6587\u4ef6\uff0c\u6211\u4eec\u4f1a\u5728\u540e\u9762\u91cd\u65b0\u521b\u5efa\u8fd9\u4e9b\u6587\u4ef6\u3002 cd cka-demo rm -rf charts rm -rf templates/tests rm -rf templates/*.yaml echo \"\" > values.yaml echo \"\" > templates/NOTES.txt echo \"\" > templates/_helpers.tpl cd .. \u76ee\u5f55 cka-demo \u7684\u67b6\u6784\u73b0\u5728\u5e94\u8be5\u770b\u8d77\u6765\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\u3002 tree cka-demo/ \u8fd0\u884c\u7ed3\u679c\uff1a cka-demo/ \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u2514\u2500\u2500 NOTES.txt \u2514\u2500\u2500 values.yaml NOTES.txt \u00b6 NOTES.txt \u7528\u4e8e\u5411 Chart \u7528\u6237\u63d0\u4f9b\u6982\u8981\u4fe1\u606f\u3002\u5728\u6f14\u793a\u4e2d\uff0c\u6211\u4eec\u5c06\u4f7f\u7528 NOTES.txt \u63d0\u4f9b\u5173\u4e8e\u7528\u6237\u662f\u5426\u901a\u8fc7 CKA \u8ba4\u8bc1\u7684\u6982\u8981\u4fe1\u606f\u3002 cd cka-demo/ vi templates/NOTES.txt \u6dfb\u52a0\u4e0b\u9762\u7684\u5185\u5bb9\u3002 {{- if .Values.passExam }} Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: {{ .Values.ckaScore }} Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard {{- else }} Come on! you can do it next time! {{- end }} \u90e8\u7f72\u6a21\u7248 \u00b6 \u4e0b\u9762\u4f1a\u4f7f\u7528 Busybox \u670d\u52a1\u6765\u751f\u6210\u4fe1\u606f\u3002 \u901a\u8fc7\u547d\u4ee4 kubectl create deployment --dry-run=client -oyaml \u751f\u6210 Deployment \u7684 YAML \u6587\u4ef6\uff0c\u5e76\u5c06\u5176\u5185\u5bb9\u5199\u5165\u6587\u4ef6 templates/deployment.yaml \u3002 kubectl create deployment cka-demo-busybox --image = busybox:latest --dry-run = client -oyaml > templates/deployment.yaml \u68c0\u67e5deployment\u7684yaml\u6587\u4ef6 templates/deployment.yaml \u7684\u5185\u5bb9\u3002 cat templates/deployment.yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : 1 selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} \u7f16\u8f91\u4fee\u6539\u6587\u4ef6 templates/deployment.yaml \u3002 vi templates/deployment.yaml \u8ba9\u6211\u4eec\u5c06 .spec.replicas \u7684\u503c\u4ece 1 \u66ff\u6362\u4e3a\u53d8\u91cf {{ .Values.replicaCount }} \uff0c\u8fd9\u6837\u6211\u4eec\u53ef\u4ee5\u4e3a\u5176\u4ed6 Deployment \u52a8\u6001\u5206\u914d\u526f\u672c\u6570\u3002 apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} .spec.replicas \u5c06\u5728\u90e8\u7f72\u671f\u95f4\u88ab\u5b9e\u9645\u7684 .Values.replicaCount \u503c\u66ff\u6362\u3002 \u73b0\u5728\u521b\u5efa\u53e6\u4e00\u4e2a\u6587\u4ef6 values.yaml \u5e76\u5728\u6587\u4ef6\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u53d8\u91cf replicaCount \uff0c\u9ed8\u8ba4\u503c\u4e3a1\u3002 \u5f3a\u70c8\u5efa\u8bae\u5728\u6587\u4ef6 values.yaml \u4e2d\u5b9a\u4e49\u7684\u6bcf\u4e2a\u503c\u6dfb\u52a0\u6ce8\u91ca\u3002 vi values.yaml \u8f93\u51fa\u7ed3\u679c\uff1a # Number of deployment replicas replicaCount: 1 \u4e0b\u9762\u5bf9\u6587\u4ef6 templates/deployment.yaml \u6dfb\u52a0\u66f4\u591a\u7684\u53d8\u91cf\u3002 \u5c06 .metadata.name \u7684 Release \u540d\u79f0\u66ff\u6362\u4e3a {{ .Release.Name }} \uff0c\u5e76\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u586b\u5145\u3002 \u5c06\u6807\u7b7e\u540d\u79f0 .metadata.labels \u66ff\u6362\u4e3a {{- include \"cka-demo.labels\" . | nindent 4 }} \uff0c\u5e76\u7528\u5728 _helpers.tpl \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u6807\u7b7e\u540d\u79f0 cka-demo.labels \u586b\u5145\u3002 \u5c06 .spec.replicas \u66ff\u6362\u4e3a {{ .Values.replicaCount }} \uff0c\u5e76\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u586b\u5145\u3002 \u5c06 .spec.selector.matchLabels \u66ff\u6362\u4e3a {{- include \"cka-demo.selectorLabels\" . | nindent 6 }} \u5e76\u4f7f\u7528\u5728 _helpers.tpl \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684 cka-demo.selectorLabels \u8fdb\u884c\u586b\u5145\u3002 \u5c06 .spec.template.metadata.labels \u66ff\u6362\u4e3a {{- include \"cka-demo.selectorLabels\" . | nindent 8 }} \u5e76\u4f7f\u7528\u5728 _helpers.tpl \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684 cka-demo.selectorLabels \u8fdb\u884c\u586b\u5145\u3002 \u5c06 .spec.template.spec.containers[0].image \u66ff\u6362\u4e3a {{ .Values.image.repository }} \u548c {{ .Values.image.tag }} \u5e76\u4f7f\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u586b\u5145\u955c\u50cf\u540d\u79f0\u548c\u955c\u50cf\u6807\u7b7e\u3002 \u5c06 .spec.template.spec.containers[0].command \u66ff\u6362\u4e3a\u4e00\u4e2a if-else \u8bed\u53e5\uff0c\u5982\u679c .Values.passExam \u4e3a\u771f\uff0c\u5219\u6267\u884c\u5728 .Values.passCommand \u4e2d\u5b9a\u4e49\u7684\u547d\u4ee4\uff0c\u5426\u5219\u6267\u884c\u5728 .Values.lostCommand \u4e2d\u5b9a\u4e49\u7684\u547d\u4ee4\u3002 \u4f7f\u7528 .spec.template.spec.containers[0].env \u4e2d\u7684 key \u4f5c\u4e3a ConfigMap \u540d\u79f0\u7684\u524d\u7f00\uff0c\u5e76\u4f7f\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684 {{ .Values.studentName }} \u8fdb\u884c\u586b\u5145\u3002 \u5c06 .spec.template.spec.containers[0].resources \u66ff\u6362\u4e3a {{ .Values.resources }} \u5e76\u4f7f\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u8fdb\u884c\u586b\u5145\u3002 .Release.Name \u662f\u5185\u7f6e\u5bf9\u8c61\uff0c\u5728\u6587\u4ef6 values.yaml \u4e2d\u4e0d\u9700\u8981\u6307\u5b9a\u3002\u5b83\u662f\u7531 helm install \u751f\u6210\u7684Release\u3002 \u79fb\u9664\u4e0d\u5fc5\u8981\u7684\u884c\uff0c\u6700\u7ec8\u6587\u4ef6\u770b\u8d77\u6765\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\uff1a apiVersion : apps/v1 kind : Deployment metadata : name : {{ .Release.Name }} labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : {{ - include \"cka-demo.selectorLabels\" . | nindent 6 }} template : metadata : labels : {{ - include \"cka-demo.selectorLabels\" . | nindent 8 }} spec : containers : - name : id-generator image : \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\" {{ - if .Values.passExam }} {{ - with .Values.passCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - else }} {{ - with .Values.lostCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - end }} env : - name : CKA_SCORE valueFrom : configMapKeyRef : name : {{ .Values.studentName }} -cka-score key : cka_score {{ - with .Values.resources }} resources : {{ - toYaml . | nindent 12 }} {{ - end }} restartPolicy : Always \u66f4\u65b0\u6587\u4ef6 values.yaml \u4e2d\u53d8\u91cf\u7684\u9ed8\u8ba4\u503c\u3002\u5efa\u8bae\u9010\u4e2a\u6dfb\u52a0\u53d8\u91cf\u5e76\u6d4b\u8bd5\uff0c\u4e0d\u8981\u4e00\u6b21\u6dfb\u52a0\u6240\u6709\u53d8\u91cf\u3002 vi values.yaml \u8fd0\u884c\u7ed3\u679c\uff1a # Number of deployment replicas replicaCount: 1 # Image repository and tag image: repository: busybox tag: latest # Container start command passCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE) and your CKA certificate ID number is $(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 13; echo) ; sleep 86400\" lostCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE), Come on! you can do it next time! ; sleep 86400\" # Container resources resources: limits: cpu: 200m memory: 256Mi requests: cpu: 100m memory: 128Mi # Student Name studentName: whoareyou # Student pass CKA exam or not passExam: true ConfigMap\u6a21\u7248 \u00b6 ConfigMap\u88ab\u90e8\u7f72\u4e2d\u7684Deployment\u6240\u5f15\u7528\uff0c\u56e0\u6b64\u6211\u4eec\u9700\u8981\u5b9a\u4e49ConfigMap\u7684\u6a21\u677f\u3002 \u6211\u4eec\u5c06\u628aConfigMap\u7684\u540d\u79f0\u548c cka_score \u7ec4\u5408\u6210\u4e00\u4e2a\u53d8\u91cf\uff0c\u4f8b\u5982 name-cka-score \u3002 vi templates/configmap.yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion : v1 kind : ConfigMap metadata : name : {{ .Values.studentName }} -cka-score labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} data : cka_score : {{ .Values.ckaScore | quote }} studentName \u5df2\u7ecf\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u8fc7\u4e86\uff0c\u6211\u4eec\u53ea\u9700\u8981\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a ckaScore \u7684\u53d8\u91cf\u5e76\u7ed9\u5b83\u4e00\u4e2a\u9ed8\u8ba4\u503c\u5373\u53ef\u3002 vi values.yaml \u8fd0\u884c\u7ed3\u679c # Student CKA Score ckaScore: 100 _helpers.tpl \u00b6 \u5b9a\u4e49\u4e00\u4e2a\u901a\u7528\u7684\u6a21\u677f _helpers.tpl \uff0c\u4e3aDeployment\u548cConfigMap\u7684\u6807\u7b7e\u548c\u9009\u62e9\u5668\u6807\u7b7e\u6dfb\u52a0\u6807\u7b7e\u3002 vi templates/_helpers.tpl \u8fd0\u884c\u7ed3\u679c\uff1a {{/* Common labels */}} {{- define \"cka-demo.labels\" -}} {{ include \"cka-demo.selectorLabels\" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end -}} {{/* Selector labels */}} {{- define \"cka-demo.selectorLabels\" -}} app: {{ .Chart.Name }} release: {{ .Release.Name }} {{- end -}} Chart.yaml \u00b6 \u8fd9\u91cc\u6211\u4eec\u4f7f\u7528CKA\u7684logo\u6765\u4f5c\u4e3aChart\u7684\u56fe\u6807\u3002 wget https://www.cncf.io/wp-content/uploads/2021/09/kubernetes-cka-color.svg \u7f16\u8f91\u4fee\u6539 Chart.yaml \u6587\u4ef6\u3002 vi Chart.yaml \u628a\u56fe\u6807\u4fe1\u606f\u6dfb\u52a0\u5230Chart.yaml\u6587\u4ef6\u672b\u5c3e\u3002 icon: file://./kubernetes-cka-color.svg \u628a\u4f5c\u8005\u4fe1\u606f\u6dfb\u52a0\u5230Chart.yaml\u6587\u4ef6\u672b\u5c3e\u3002 vi Chart.yaml \u8fd0\u884c\u7ed3\u679c\uff1a maintainers: - name: James.H \u6700\u7ec8\u7684 Chart.yaml \u7c7b\u4f3c\u5982\u4e0b\u5185\u5bb9\u3002\u522b\u5fd8\u8bb0\u66f4\u65b0 appVersion: \"v1.23\" \u4e3a\u5f53\u524dKubernetes\u7684\u7248\u672c\u3002 apiVersion: v2 name: cka-demo description: A Helm chart for CKA demo. type: application version: 0.1.0 appVersion: \"v1.23\" maintainers: - name: James.H icon: file://./kubernetes-cka-color.svg Chart Debug \u00b6 \u4f7f\u7528 helm lint \u6765\u9a8c\u8bc1\u4e0a\u8ff0\u53d8\u66f4\u3002 helm lint \u8fd0\u884c\u7ed3\u679c\uff1a 1 chart(s) linted, 0 chart(s) failed helm lint \u53ea\u68c0\u67e5Chart\u7684\u683c\u5f0f\uff0c\u4e0d\u68c0\u67e5Manifest\u6587\u4ef6\u3002 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 helm install --debug --dry-run \u6216 helm template \u547d\u4ee4\u6765\u68c0\u67e5\u751f\u6210\u7684 Manifest \u662f\u5426\u6b63\u786e\u3002 helm template cka-demo ./ \u901a\u8fc7\u547d\u4ee4 helm install --debug --dry-run \u6765\u6a21\u62df\u5b89\u88c5\u3002\u6211\u4eec\u53ef\u4ee5\u4ece\u4e24\u4e2a\u4e0d\u540c\u7684\u9009\u9879\uff08\u901a\u8fc7\u6216\u672a\u901a\u8fc7CKA\u8ba4\u8bc1\uff09\u4e2d\u83b7\u5f97\u9884\u671f\u7684\u7ed3\u679c\u3002 helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 99 \\ --set passExam = true helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 0 \\ --set passExam = false \u628a Chart \u6253\u5305\u6210 .tgz \u6587\u4ef6\uff0c\u5e76\u4e0a\u4f20\u5230\u4ed3\u5e93\uff0c\u4f8b\u5982 Chart Museum \u6216\u8005 OCI Repo\u3002 cd ../ helm package cka-demo \u8fd0\u884c\u7ed3\u679c\uff1a Successfully packaged chart and saved it to: /root/cka-demo-0.1.0.tgz \u81f3\u6b64\uff0c\u6211\u4eec\u5df2\u7ecf\u5b8c\u6210\u4e86\u914d\u7f6e\u4e00\u4e2a\u65b0\u7684Chart\uff0c\u73b0\u5728\u5f00\u59cb\u5b89\u88c5\u8fd9\u4e2aChart\u3002 helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 0 \\ --set passExam = false \u8fd0\u884c\u7ed3\u679c\uff1a NAME: cka-demo LAST DEPLOYED: Sun Jul 24 19:58:36 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Come on! you can do it next time! \u68c0\u67e5\u90e8\u7f72\u60c5\u51b5\uff1a helm list --all-namespaces \u8fd0\u884c\u7ed3\u679c\uff1a NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION cka-demo cka 1 2022-07-24 19:58:36.272093383 +0800 CST deployed cka-demo-0.1.0 v1.23 mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 \u5982\u679c\u9047\u5230\u9519\u8bef\uff0c\u5219\u9700\u8981\u5378\u8f7d cka-demo \u5e76\u91cd\u65b0\u5b89\u88c5\u5b83\u3002 helm uninstall cka-demo -n \u68c0\u67e5 cka-demo \u7684\u65e5\u5fd7\u3002 kubectl logs -n cka -l app = cka-demo \u8fd0\u884c\u7ed3\u679c Your CKA score is 0, Come on! you can do it next time! \u901a\u8fc7\u5176\u4ed6\u9009\u9879\u5b89\u88c5 cka-demo \u3002 helm uninstall cka-demo -n cka helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 100 \\ --set passExam = true \u8fd0\u884c\u7ed3\u679c\uff1a NAME: cka-demo LAST DEPLOYED: Sun Jul 24 20:01:34 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: 100 Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard \u68c0\u67e5 cka-demo \u7684\u65e5\u5fd7\u3002 kubectl logs -n cka -l app = cka-demo \u8fd0\u884c\u7ed3\u679c\uff1a Your CKA score is 100 and your CKA certificate ID number is BQKoVYVhjzl3G Built-in Objects\u5217\u8868 Release.Name # \u53d1\u5e03\u540d\u79f0 Release.Namespace # \u53d1\u5e03Namespace Release.Service # \u6e32\u67d3\u6a21\u677f\u7684\u670d\u52a1\uff0c\u5728Helm\u4e2d\u9ed8\u8ba4\u503c\u4e3a\"Helm\" Release.IsUpgrade # \u5982\u679c\u5f53\u524d\u662f\u5347\u7ea7\u6216\u56de\u6eda\uff0c\u8bbe\u7f6e\u4e3atrue Release.IsInstall # \u5982\u679c\u5f53\u524d\u662f\u5b89\u88c5\uff0c\u8bbe\u7f6e\u4e3atrue Release.Revision # \u53d1\u5e03\u7248\u672c\u53f7 Values # \u4ecevalues.yaml\u548c--set\u4f20\u5165\uff0c\u9ed8\u8ba4\u4e3a\u7a7a Chart # \u6240\u6709Chart.yaml\u4e2d\u7684\u5185\u5bb9 Chart.Version # Chart.Maintainers # Files # \u5728chart\u4e2d\u8bbf\u95ee\u975e\u7279\u6b8a\u6587\u4ef6 Capabilities # \u63d0\u4f9b\u5173\u4e8e\u652f\u6301\u80fd\u529b\u7684\u4fe1\u606f\uff08K8s API\u7248\u672c\u3001K8s\u7248\u672c\u3001Helm\u7248\u672c\uff09 Capabilities.KubeVersion # Kubernetes\u7684\u7248\u672c\u53f7 Capabilities.APIVersions.Has \"batch/v1\" # K8s API\u7248\u672c\u5305\u542b\"batch/v1\" Template # \u5f53\u524d\u6a21\u677f\u4fe1\u606f Template.Name # \u5f53\u524d\u6a21\u677f\u6587\u4ef6\u8def\u5f84 Template.BasePath # \u5f53\u524d\u6a21\u677f\u76ee\u5f55\u8def\u5f84 \u53c2\u8003\uff1a Helm \u5b98\u7f51 Helm \u7248\u672c\u652f\u6301\u7b56\u7565 Helm Chart \u8d44\u6e90\u5bf9\u8c61\u5b89\u88c5\u987a\u5e8f","title":"Helm Chart"},{"location":"k8s/cka_cn/foundamentals/helming/#cka27helm-chart","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb027:Helm Chart"},{"location":"k8s/cka_cn/foundamentals/helming/#helm","text":"\u5728\u8282\u70b9 cka001 \u4e0a\u5b89\u88c5Helm\u3002 # https://github.com/helm/helm/releases wget https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz tar -zxvf helm-v3.8.2-linux-amd64.tar.gz cp linux-amd64/helm /usr/bin/ rm -rf linux-amd64 helm-v3.8.2-linux-amd64.tar.gz \u6216\u8005\u4ece\u94fe\u63a5 https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz \u624b\u5de5\u4e0b\u8f7d\u5b89\u88c5\u5305\uff0c\u5e76\u62f7\u8d1d\u5230\u8282\u70b9 cka001 \u4e0a\u3002 scp -i cka-key-pair.pem ./Package/helm-v3.8.2-linux-amd64.tar.gz root@cka001:/root/ ssh -i cka-key-pair.pem root@cka001 tar -zxvf helm-v3.8.2-linux-amd64.tar.gz cp linux-amd64/helm /usr/bin/ rm -rf linux-amd64 helm-v3.8.2-linux-amd64.tar.gz","title":"\u5b89\u88c5Helm"},{"location":"k8s/cka_cn/foundamentals/helming/#helm_1","text":"\u68c0\u67e5 helm \u7684\u7248\u672c\u3002 helm version \u8fd0\u884c\u7ed3\u679c\uff1a version.BuildInfo{Version:\"v3.8.2\", GitCommit:\"6e3701edea09e5d55a8ca2aae03a68917630e91b\", GitTreeState:\"clean\", GoVersion:\"go1.17.5\"} \u83b7\u53d6 helm \u7684\u5e2e\u52a9\u4fe1\u606f\u3002 helm help \u914d\u7f6e helm \u7684\u547d\u4ee4\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 echo \"source <(helm completion bash)\" >> ~/.bashrc source < ( helm completion bash )","title":"Helm\u7528\u6cd5"},{"location":"k8s/cka_cn/foundamentals/helming/#helmmysql","text":"\u6dfb\u52a0Bitnami Chartes\u4ed3\u5e93\u3002 helm repo add bitnami https://charts.bitnami.com/bitnami \u67e5\u8be2\u5f53\u524d\u53ef\u7528\u7684Chartes\u4ed3\u5e93\u3002 helm repo list \u8fd0\u884c\u7ed3\u679c\uff1a NAME URL bitnami https://charts.bitnami.com/bitnami \u540c\u6b65\u672c\u5730Charts\u4ed3\u5e93\u3002 helm repo update \u5728Charts\u4ed3\u5e93\u4e2d\u67e5\u627ebitnami Charts\u4ed3\u5e93\u3002 helm search repo bitnami \u5728\u4ed3\u5e93\u4e2d\u641c\u7d22bitnami/mysql Charts\u3002 helm search repo bitnami/mysql \u5728namespace dev \u4e0a\u5b89\u88c5MySQL Chart\u3002 helm install mysql bitnami/mysql -n dev \u8fd0\u884c\u7ed3\u679c\uff1a NAME: mysql LAST DEPLOYED: Sun Jul 24 19:37:20 2022 NAMESPACE: dev STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: mysql CHART VERSION: 9.2.1 APP VERSION: 8.0.29 ** Please be patient while the chart is being deployed ** Tip: Watch the deployment status using the command: kubectl get pods -w --namespace dev Services: echo Primary: mysql.dev.svc.cluster.local:3306 Execute the following to get the administrator credentials: echo Username: root MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace dev mysql -o jsonpath=\"{.data.mysql-root-password}\" | base64 -d) To connect to your database: 1. Run a pod that you can use as a client: kubectl run mysql-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mysql:8.0.29-debian-11-r9 --namespace dev --env MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD --command -- bash 2. To connect to primary service (read/write): mysql -h mysql.dev.svc.cluster.local -uroot -p\"$MYSQL_ROOT_PASSWORD\" \u67e5\u770b\u5f53\u524d\u5b89\u88c5\u5305\u7684\u4fe1\u606f\u3002 helm list \u8fd0\u884c\u7ed3\u679c\uff1a NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 \u68c0\u67e5\u5f53\u524d\u5b89\u88c5\u7684mysql\u7248\u672c\u4fe1\u606f\u3002 helm status mysql \u68c0\u67e5pod mysql \u7684\u72b6\u6001\u3002 kubectl get pod \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE mysql-0 1/1 Running 0 72s","title":"\u901a\u8fc7Helm\u5b89\u88c5MySQL"},{"location":"k8s/cka_cn/foundamentals/helming/#chart","text":"\u4e0b\u9762\u6f14\u793a\u4e86\u5982\u4f55\u90e8\u7f72\u4e00\u4e2aChart\u3002 \u6267\u884c\u547d\u4ee4 helm create \u6765\u521d\u59cb\u5316\u4e00\u4e2aChart\u3002 # Naming conventions of Chart: lowercase a~z and -(minus sign) helm create cka-demo \u76ee\u5f55 cka-demo \u4f1a\u88ab\u521b\u5efa\uff0c\u67e5\u770b\u8fd9\u4e2a\u76ee\u5f55\u7684\u7ed3\u6784\u3002 tree cka-demo/ \u8fd0\u884c\u7ed3\u679c\uff1a cka-demo/ \u251c\u2500\u2500 charts \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 deployment.yaml \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u251c\u2500\u2500 hpa.yaml \u2502 \u251c\u2500\u2500 ingress.yaml \u2502 \u251c\u2500\u2500 NOTES.txt \u2502 \u251c\u2500\u2500 serviceaccount.yaml \u2502 \u251c\u2500\u2500 service.yaml \u2502 \u2514\u2500\u2500 tests \u2502 \u2514\u2500\u2500 test-connection.yaml \u2514\u2500\u2500 values.yaml \u5220\u9664\u6216\u6e05\u7a7a\u67d0\u4e9b\u6587\u4ef6\uff0c\u6211\u4eec\u4f1a\u5728\u540e\u9762\u91cd\u65b0\u521b\u5efa\u8fd9\u4e9b\u6587\u4ef6\u3002 cd cka-demo rm -rf charts rm -rf templates/tests rm -rf templates/*.yaml echo \"\" > values.yaml echo \"\" > templates/NOTES.txt echo \"\" > templates/_helpers.tpl cd .. \u76ee\u5f55 cka-demo \u7684\u67b6\u6784\u73b0\u5728\u5e94\u8be5\u770b\u8d77\u6765\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\u3002 tree cka-demo/ \u8fd0\u884c\u7ed3\u679c\uff1a cka-demo/ \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u2514\u2500\u2500 NOTES.txt \u2514\u2500\u2500 values.yaml","title":"\u90e8\u7f72\u4e00\u4e2aChart"},{"location":"k8s/cka_cn/foundamentals/helming/#notestxt","text":"NOTES.txt \u7528\u4e8e\u5411 Chart \u7528\u6237\u63d0\u4f9b\u6982\u8981\u4fe1\u606f\u3002\u5728\u6f14\u793a\u4e2d\uff0c\u6211\u4eec\u5c06\u4f7f\u7528 NOTES.txt \u63d0\u4f9b\u5173\u4e8e\u7528\u6237\u662f\u5426\u901a\u8fc7 CKA \u8ba4\u8bc1\u7684\u6982\u8981\u4fe1\u606f\u3002 cd cka-demo/ vi templates/NOTES.txt \u6dfb\u52a0\u4e0b\u9762\u7684\u5185\u5bb9\u3002 {{- if .Values.passExam }} Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: {{ .Values.ckaScore }} Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard {{- else }} Come on! you can do it next time! {{- end }}","title":"NOTES.txt"},{"location":"k8s/cka_cn/foundamentals/helming/#_1","text":"\u4e0b\u9762\u4f1a\u4f7f\u7528 Busybox \u670d\u52a1\u6765\u751f\u6210\u4fe1\u606f\u3002 \u901a\u8fc7\u547d\u4ee4 kubectl create deployment --dry-run=client -oyaml \u751f\u6210 Deployment \u7684 YAML \u6587\u4ef6\uff0c\u5e76\u5c06\u5176\u5185\u5bb9\u5199\u5165\u6587\u4ef6 templates/deployment.yaml \u3002 kubectl create deployment cka-demo-busybox --image = busybox:latest --dry-run = client -oyaml > templates/deployment.yaml \u68c0\u67e5deployment\u7684yaml\u6587\u4ef6 templates/deployment.yaml \u7684\u5185\u5bb9\u3002 cat templates/deployment.yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : 1 selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} \u7f16\u8f91\u4fee\u6539\u6587\u4ef6 templates/deployment.yaml \u3002 vi templates/deployment.yaml \u8ba9\u6211\u4eec\u5c06 .spec.replicas \u7684\u503c\u4ece 1 \u66ff\u6362\u4e3a\u53d8\u91cf {{ .Values.replicaCount }} \uff0c\u8fd9\u6837\u6211\u4eec\u53ef\u4ee5\u4e3a\u5176\u4ed6 Deployment \u52a8\u6001\u5206\u914d\u526f\u672c\u6570\u3002 apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} .spec.replicas \u5c06\u5728\u90e8\u7f72\u671f\u95f4\u88ab\u5b9e\u9645\u7684 .Values.replicaCount \u503c\u66ff\u6362\u3002 \u73b0\u5728\u521b\u5efa\u53e6\u4e00\u4e2a\u6587\u4ef6 values.yaml \u5e76\u5728\u6587\u4ef6\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u53d8\u91cf replicaCount \uff0c\u9ed8\u8ba4\u503c\u4e3a1\u3002 \u5f3a\u70c8\u5efa\u8bae\u5728\u6587\u4ef6 values.yaml \u4e2d\u5b9a\u4e49\u7684\u6bcf\u4e2a\u503c\u6dfb\u52a0\u6ce8\u91ca\u3002 vi values.yaml \u8f93\u51fa\u7ed3\u679c\uff1a # Number of deployment replicas replicaCount: 1 \u4e0b\u9762\u5bf9\u6587\u4ef6 templates/deployment.yaml \u6dfb\u52a0\u66f4\u591a\u7684\u53d8\u91cf\u3002 \u5c06 .metadata.name \u7684 Release \u540d\u79f0\u66ff\u6362\u4e3a {{ .Release.Name }} \uff0c\u5e76\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u586b\u5145\u3002 \u5c06\u6807\u7b7e\u540d\u79f0 .metadata.labels \u66ff\u6362\u4e3a {{- include \"cka-demo.labels\" . | nindent 4 }} \uff0c\u5e76\u7528\u5728 _helpers.tpl \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u6807\u7b7e\u540d\u79f0 cka-demo.labels \u586b\u5145\u3002 \u5c06 .spec.replicas \u66ff\u6362\u4e3a {{ .Values.replicaCount }} \uff0c\u5e76\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u586b\u5145\u3002 \u5c06 .spec.selector.matchLabels \u66ff\u6362\u4e3a {{- include \"cka-demo.selectorLabels\" . | nindent 6 }} \u5e76\u4f7f\u7528\u5728 _helpers.tpl \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684 cka-demo.selectorLabels \u8fdb\u884c\u586b\u5145\u3002 \u5c06 .spec.template.metadata.labels \u66ff\u6362\u4e3a {{- include \"cka-demo.selectorLabels\" . | nindent 8 }} \u5e76\u4f7f\u7528\u5728 _helpers.tpl \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684 cka-demo.selectorLabels \u8fdb\u884c\u586b\u5145\u3002 \u5c06 .spec.template.spec.containers[0].image \u66ff\u6362\u4e3a {{ .Values.image.repository }} \u548c {{ .Values.image.tag }} \u5e76\u4f7f\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u586b\u5145\u955c\u50cf\u540d\u79f0\u548c\u955c\u50cf\u6807\u7b7e\u3002 \u5c06 .spec.template.spec.containers[0].command \u66ff\u6362\u4e3a\u4e00\u4e2a if-else \u8bed\u53e5\uff0c\u5982\u679c .Values.passExam \u4e3a\u771f\uff0c\u5219\u6267\u884c\u5728 .Values.passCommand \u4e2d\u5b9a\u4e49\u7684\u547d\u4ee4\uff0c\u5426\u5219\u6267\u884c\u5728 .Values.lostCommand \u4e2d\u5b9a\u4e49\u7684\u547d\u4ee4\u3002 \u4f7f\u7528 .spec.template.spec.containers[0].env \u4e2d\u7684 key \u4f5c\u4e3a ConfigMap \u540d\u79f0\u7684\u524d\u7f00\uff0c\u5e76\u4f7f\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684 {{ .Values.studentName }} \u8fdb\u884c\u586b\u5145\u3002 \u5c06 .spec.template.spec.containers[0].resources \u66ff\u6362\u4e3a {{ .Values.resources }} \u5e76\u4f7f\u7528\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u53d8\u91cf\u8fdb\u884c\u586b\u5145\u3002 .Release.Name \u662f\u5185\u7f6e\u5bf9\u8c61\uff0c\u5728\u6587\u4ef6 values.yaml \u4e2d\u4e0d\u9700\u8981\u6307\u5b9a\u3002\u5b83\u662f\u7531 helm install \u751f\u6210\u7684Release\u3002 \u79fb\u9664\u4e0d\u5fc5\u8981\u7684\u884c\uff0c\u6700\u7ec8\u6587\u4ef6\u770b\u8d77\u6765\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\uff1a apiVersion : apps/v1 kind : Deployment metadata : name : {{ .Release.Name }} labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : {{ - include \"cka-demo.selectorLabels\" . | nindent 6 }} template : metadata : labels : {{ - include \"cka-demo.selectorLabels\" . | nindent 8 }} spec : containers : - name : id-generator image : \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\" {{ - if .Values.passExam }} {{ - with .Values.passCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - else }} {{ - with .Values.lostCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - end }} env : - name : CKA_SCORE valueFrom : configMapKeyRef : name : {{ .Values.studentName }} -cka-score key : cka_score {{ - with .Values.resources }} resources : {{ - toYaml . | nindent 12 }} {{ - end }} restartPolicy : Always \u66f4\u65b0\u6587\u4ef6 values.yaml \u4e2d\u53d8\u91cf\u7684\u9ed8\u8ba4\u503c\u3002\u5efa\u8bae\u9010\u4e2a\u6dfb\u52a0\u53d8\u91cf\u5e76\u6d4b\u8bd5\uff0c\u4e0d\u8981\u4e00\u6b21\u6dfb\u52a0\u6240\u6709\u53d8\u91cf\u3002 vi values.yaml \u8fd0\u884c\u7ed3\u679c\uff1a # Number of deployment replicas replicaCount: 1 # Image repository and tag image: repository: busybox tag: latest # Container start command passCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE) and your CKA certificate ID number is $(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 13; echo) ; sleep 86400\" lostCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE), Come on! you can do it next time! ; sleep 86400\" # Container resources resources: limits: cpu: 200m memory: 256Mi requests: cpu: 100m memory: 128Mi # Student Name studentName: whoareyou # Student pass CKA exam or not passExam: true","title":"\u90e8\u7f72\u6a21\u7248"},{"location":"k8s/cka_cn/foundamentals/helming/#configmap","text":"ConfigMap\u88ab\u90e8\u7f72\u4e2d\u7684Deployment\u6240\u5f15\u7528\uff0c\u56e0\u6b64\u6211\u4eec\u9700\u8981\u5b9a\u4e49ConfigMap\u7684\u6a21\u677f\u3002 \u6211\u4eec\u5c06\u628aConfigMap\u7684\u540d\u79f0\u548c cka_score \u7ec4\u5408\u6210\u4e00\u4e2a\u53d8\u91cf\uff0c\u4f8b\u5982 name-cka-score \u3002 vi templates/configmap.yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion : v1 kind : ConfigMap metadata : name : {{ .Values.studentName }} -cka-score labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} data : cka_score : {{ .Values.ckaScore | quote }} studentName \u5df2\u7ecf\u5728 values.yaml \u6587\u4ef6\u4e2d\u5b9a\u4e49\u8fc7\u4e86\uff0c\u6211\u4eec\u53ea\u9700\u8981\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a ckaScore \u7684\u53d8\u91cf\u5e76\u7ed9\u5b83\u4e00\u4e2a\u9ed8\u8ba4\u503c\u5373\u53ef\u3002 vi values.yaml \u8fd0\u884c\u7ed3\u679c # Student CKA Score ckaScore: 100","title":"ConfigMap\u6a21\u7248"},{"location":"k8s/cka_cn/foundamentals/helming/#_helperstpl","text":"\u5b9a\u4e49\u4e00\u4e2a\u901a\u7528\u7684\u6a21\u677f _helpers.tpl \uff0c\u4e3aDeployment\u548cConfigMap\u7684\u6807\u7b7e\u548c\u9009\u62e9\u5668\u6807\u7b7e\u6dfb\u52a0\u6807\u7b7e\u3002 vi templates/_helpers.tpl \u8fd0\u884c\u7ed3\u679c\uff1a {{/* Common labels */}} {{- define \"cka-demo.labels\" -}} {{ include \"cka-demo.selectorLabels\" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end -}} {{/* Selector labels */}} {{- define \"cka-demo.selectorLabels\" -}} app: {{ .Chart.Name }} release: {{ .Release.Name }} {{- end -}}","title":"_helpers.tpl"},{"location":"k8s/cka_cn/foundamentals/helming/#chartyaml","text":"\u8fd9\u91cc\u6211\u4eec\u4f7f\u7528CKA\u7684logo\u6765\u4f5c\u4e3aChart\u7684\u56fe\u6807\u3002 wget https://www.cncf.io/wp-content/uploads/2021/09/kubernetes-cka-color.svg \u7f16\u8f91\u4fee\u6539 Chart.yaml \u6587\u4ef6\u3002 vi Chart.yaml \u628a\u56fe\u6807\u4fe1\u606f\u6dfb\u52a0\u5230Chart.yaml\u6587\u4ef6\u672b\u5c3e\u3002 icon: file://./kubernetes-cka-color.svg \u628a\u4f5c\u8005\u4fe1\u606f\u6dfb\u52a0\u5230Chart.yaml\u6587\u4ef6\u672b\u5c3e\u3002 vi Chart.yaml \u8fd0\u884c\u7ed3\u679c\uff1a maintainers: - name: James.H \u6700\u7ec8\u7684 Chart.yaml \u7c7b\u4f3c\u5982\u4e0b\u5185\u5bb9\u3002\u522b\u5fd8\u8bb0\u66f4\u65b0 appVersion: \"v1.23\" \u4e3a\u5f53\u524dKubernetes\u7684\u7248\u672c\u3002 apiVersion: v2 name: cka-demo description: A Helm chart for CKA demo. type: application version: 0.1.0 appVersion: \"v1.23\" maintainers: - name: James.H icon: file://./kubernetes-cka-color.svg","title":"Chart.yaml"},{"location":"k8s/cka_cn/foundamentals/helming/#chart-debug","text":"\u4f7f\u7528 helm lint \u6765\u9a8c\u8bc1\u4e0a\u8ff0\u53d8\u66f4\u3002 helm lint \u8fd0\u884c\u7ed3\u679c\uff1a 1 chart(s) linted, 0 chart(s) failed helm lint \u53ea\u68c0\u67e5Chart\u7684\u683c\u5f0f\uff0c\u4e0d\u68c0\u67e5Manifest\u6587\u4ef6\u3002 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 helm install --debug --dry-run \u6216 helm template \u547d\u4ee4\u6765\u68c0\u67e5\u751f\u6210\u7684 Manifest \u662f\u5426\u6b63\u786e\u3002 helm template cka-demo ./ \u901a\u8fc7\u547d\u4ee4 helm install --debug --dry-run \u6765\u6a21\u62df\u5b89\u88c5\u3002\u6211\u4eec\u53ef\u4ee5\u4ece\u4e24\u4e2a\u4e0d\u540c\u7684\u9009\u9879\uff08\u901a\u8fc7\u6216\u672a\u901a\u8fc7CKA\u8ba4\u8bc1\uff09\u4e2d\u83b7\u5f97\u9884\u671f\u7684\u7ed3\u679c\u3002 helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 99 \\ --set passExam = true helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 0 \\ --set passExam = false \u628a Chart \u6253\u5305\u6210 .tgz \u6587\u4ef6\uff0c\u5e76\u4e0a\u4f20\u5230\u4ed3\u5e93\uff0c\u4f8b\u5982 Chart Museum \u6216\u8005 OCI Repo\u3002 cd ../ helm package cka-demo \u8fd0\u884c\u7ed3\u679c\uff1a Successfully packaged chart and saved it to: /root/cka-demo-0.1.0.tgz \u81f3\u6b64\uff0c\u6211\u4eec\u5df2\u7ecf\u5b8c\u6210\u4e86\u914d\u7f6e\u4e00\u4e2a\u65b0\u7684Chart\uff0c\u73b0\u5728\u5f00\u59cb\u5b89\u88c5\u8fd9\u4e2aChart\u3002 helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 0 \\ --set passExam = false \u8fd0\u884c\u7ed3\u679c\uff1a NAME: cka-demo LAST DEPLOYED: Sun Jul 24 19:58:36 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Come on! you can do it next time! \u68c0\u67e5\u90e8\u7f72\u60c5\u51b5\uff1a helm list --all-namespaces \u8fd0\u884c\u7ed3\u679c\uff1a NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION cka-demo cka 1 2022-07-24 19:58:36.272093383 +0800 CST deployed cka-demo-0.1.0 v1.23 mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 \u5982\u679c\u9047\u5230\u9519\u8bef\uff0c\u5219\u9700\u8981\u5378\u8f7d cka-demo \u5e76\u91cd\u65b0\u5b89\u88c5\u5b83\u3002 helm uninstall cka-demo -n \u68c0\u67e5 cka-demo \u7684\u65e5\u5fd7\u3002 kubectl logs -n cka -l app = cka-demo \u8fd0\u884c\u7ed3\u679c Your CKA score is 0, Come on! you can do it next time! \u901a\u8fc7\u5176\u4ed6\u9009\u9879\u5b89\u88c5 cka-demo \u3002 helm uninstall cka-demo -n cka helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName = kubernetes \\ --set ckaScore = 100 \\ --set passExam = true \u8fd0\u884c\u7ed3\u679c\uff1a NAME: cka-demo LAST DEPLOYED: Sun Jul 24 20:01:34 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: 100 Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard \u68c0\u67e5 cka-demo \u7684\u65e5\u5fd7\u3002 kubectl logs -n cka -l app = cka-demo \u8fd0\u884c\u7ed3\u679c\uff1a Your CKA score is 100 and your CKA certificate ID number is BQKoVYVhjzl3G Built-in Objects\u5217\u8868 Release.Name # \u53d1\u5e03\u540d\u79f0 Release.Namespace # \u53d1\u5e03Namespace Release.Service # \u6e32\u67d3\u6a21\u677f\u7684\u670d\u52a1\uff0c\u5728Helm\u4e2d\u9ed8\u8ba4\u503c\u4e3a\"Helm\" Release.IsUpgrade # \u5982\u679c\u5f53\u524d\u662f\u5347\u7ea7\u6216\u56de\u6eda\uff0c\u8bbe\u7f6e\u4e3atrue Release.IsInstall # \u5982\u679c\u5f53\u524d\u662f\u5b89\u88c5\uff0c\u8bbe\u7f6e\u4e3atrue Release.Revision # \u53d1\u5e03\u7248\u672c\u53f7 Values # \u4ecevalues.yaml\u548c--set\u4f20\u5165\uff0c\u9ed8\u8ba4\u4e3a\u7a7a Chart # \u6240\u6709Chart.yaml\u4e2d\u7684\u5185\u5bb9 Chart.Version # Chart.Maintainers # Files # \u5728chart\u4e2d\u8bbf\u95ee\u975e\u7279\u6b8a\u6587\u4ef6 Capabilities # \u63d0\u4f9b\u5173\u4e8e\u652f\u6301\u80fd\u529b\u7684\u4fe1\u606f\uff08K8s API\u7248\u672c\u3001K8s\u7248\u672c\u3001Helm\u7248\u672c\uff09 Capabilities.KubeVersion # Kubernetes\u7684\u7248\u672c\u53f7 Capabilities.APIVersions.Has \"batch/v1\" # K8s API\u7248\u672c\u5305\u542b\"batch/v1\" Template # \u5f53\u524d\u6a21\u677f\u4fe1\u606f Template.Name # \u5f53\u524d\u6a21\u677f\u6587\u4ef6\u8def\u5f84 Template.BasePath # \u5f53\u524d\u6a21\u677f\u76ee\u5f55\u8def\u5f84 \u53c2\u8003\uff1a Helm \u5b98\u7f51 Helm \u7248\u672c\u652f\u6301\u7b56\u7565 Helm Chart \u8d44\u6e90\u5bf9\u8c61\u5b89\u88c5\u987a\u5e8f","title":"Chart Debug"},{"location":"k8s/cka_cn/foundamentals/hpa/","text":"CKA\u81ea\u5b66\u7b14\u8bb021:Horizontal Pod Autoscaling (HPA) \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u5b89\u88c5 Metrics Server \u7ec4\u4ef6 \u521b\u5efa Deployment podinfo \u548c Service podinfo \u7528\u4e8e\u538b\u529b\u6d4b\u8bd5 \u521b\u5efa HPA my-hpa \u8fdb\u884c\u538b\u529b\u6d4b\u8bd5 \u5b89\u88c5Metrics Server \u00b6 \u4e0b\u8f7d components.yaml \u6587\u4ef6\uff0c\u6765\u90e8\u7f72Metrics Server\u3002 wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml \u628ayaml\u6587\u4ef6\u4e2dgoogle\u7684\u955c\u50cf\u6e90\u66ff\u6362\u4e3a\u963f\u91cc\u7684\u955c\u50cf\u6e90 image: registry.aliyuncs.com/google_containers/metrics-server:v0.6.1 \u3002 sed -i 's/k8s\\.gcr\\.io\\/metrics-server\\/metrics-server\\:v0\\.6\\.1/registry\\.aliyuncs\\.com\\/google_containers\\/metrics-server\\:v0\\.6\\.1/g' components.yaml \u4fee\u6539deployment metrics-server \u7684 args \uff0c\u6dfb\u52a0\u9009\u9879 --kubelet-insecure-tls \u4ee5\u7981\u7528\u8bc1\u4e66\u9a8c\u8bc1\u3002 vi components.yaml \u66f4\u65b0 args \u3002 ...... template : metadata : labels : k8s-app : metrics-server spec : containers : - args : - --cert-dir=/tmp - --secure-port=4443 - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname - --kubelet-use-node-status-port - --metric-resolution=15s - --kubelet-insecure-tls image : registry.aliyuncs.com/google_containers/metrics-server:v0.6.1 ...... \u5e94\u7528\u6587\u4ef6 components.yaml \u6765\u90e8\u7f72 metrics-server \u3002 kubectl apply -f components.yaml \u4e0b\u9762\u662f\u8fd0\u884c\u7ed3\u679c\uff0c\u76f8\u5173\u8d44\u6e90\u88ab\u521b\u5efa\u3002 serviceaccount/metrics-server created clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created clusterrole.rbac.authorization.k8s.io/system:metrics-server created rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created service/metrics-server created deployment.apps/metrics-server created apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created \u9a8c\u8bc1 pod metrics-server \u662f\u5426\u6309\u9884\u671f\u5728\u6b63\u5e38\u8fd0\u884c\u3002 kubectl get pod -n kube-system -owide | grep metrics-server \u8fd0\u884c\u7ed3\u679c\u3002\u5173\u6ce8READY\u4e0b\u7684\u72b6\u6001\uff1a 1/1 running\u4ee3\u8868\u6b63\u5e38\u8fd0\u884c\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES metrics-server-7fd564dc66-sdhdc 1/1 Running 0 61s 10.244.102.15 cka003 \u67e5\u8be2\u6bcf\u4e2a\u8282\u70b9\u4e0a\u5f53\u524dCPU\u548c\u5185\u5b58\u7684\u7528\u91cf\u60c5\u51b5\u3002 kubectl top node \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 595m 29% 1937Mi 50% cka002 75m 3% 1081Mi 28% cka003 79m 3% 1026Mi 26% \u90e8\u7f72\u670d\u52a1 podinfo \u00b6 \u521b\u5efa Deployment podinfo \u548c Service podinfo \uff0c\u540e\u9762\u4f1a\u8fdb\u884c\u66f4\u8fdb\u4e00\u6b65\u7684\u538b\u529b\u6d4b\u8bd5\u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: podinfo labels: app: podinfo spec: type: NodePort ports: - port: 9898 targetPort: 9898 nodePort: 31198 protocol: TCP selector: app: podinfo --- apiVersion: apps/v1 kind: Deployment metadata: name: podinfo labels: app: podinfo spec: replicas: 2 selector: matchLabels: app: podinfo template: metadata: labels: app: podinfo spec: containers: - name: podinfod image: stefanprodan/podinfo:0.0.1 imagePullPolicy: Always command: - ./podinfo - -port=9898 - -logtostderr=true - -v=2 ports: - containerPort: 9898 protocol: TCP resources: requests: memory: \"32Mi\" cpu: \"10m\" limits: memory: \"256Mi\" cpu: \"100m\" EOF Config HPA \u00b6 \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a my-hpa \u7684 HPA\uff0c\u5e76\u5c06\u5176\u7ed1\u5b9a\u5230\u540d\u4e3a podinfo \u7684\u90e8\u7f72\u4e2d\uff0c\u8bbe\u5b9a\u5176 CPU \u5229\u7528\u7387\u4e3a 50% \u4f5c\u4e3a\u89e6\u53d1\u81ea\u52a8\u7f29\u653e\u7684\u9608\u503c\uff0c\u6700\u5c0f\u526f\u672c\u6570\u4e3a 2 \uff0c\u6700\u5927\u526f\u672c\u6570\u4e3a 10 \u3002 \u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u521b\u5efa my-hpa HPA\uff1a kubectl autoscale deployment podinfo --cpu-percent = 50 --min = 2 --max = 10 --name = my-hpa kubectl autoscale deployment podinfo --cpu-percent = 50 --min = 1 --max = 10 \u4f7f\u7528 autoscaling/v1 \u7248\u672c\u7684\u6a21\u7248\u6765\u521b\u5efaHPA my-hpa \u3002 kubectl apply -f - < \u67e5\u8be2\u6bcf\u4e2a\u8282\u70b9\u4e0a\u5f53\u524dCPU\u548c\u5185\u5b58\u7684\u7528\u91cf\u60c5\u51b5\u3002 kubectl top node \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 595m 29% 1937Mi 50% cka002 75m 3% 1081Mi 28% cka003 79m 3% 1026Mi 26%","title":"\u5b89\u88c5Metrics Server"},{"location":"k8s/cka_cn/foundamentals/hpa/#podinfo","text":"\u521b\u5efa Deployment podinfo \u548c Service podinfo \uff0c\u540e\u9762\u4f1a\u8fdb\u884c\u66f4\u8fdb\u4e00\u6b65\u7684\u538b\u529b\u6d4b\u8bd5\u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: podinfo labels: app: podinfo spec: type: NodePort ports: - port: 9898 targetPort: 9898 nodePort: 31198 protocol: TCP selector: app: podinfo --- apiVersion: apps/v1 kind: Deployment metadata: name: podinfo labels: app: podinfo spec: replicas: 2 selector: matchLabels: app: podinfo template: metadata: labels: app: podinfo spec: containers: - name: podinfod image: stefanprodan/podinfo:0.0.1 imagePullPolicy: Always command: - ./podinfo - -port=9898 - -logtostderr=true - -v=2 ports: - containerPort: 9898 protocol: TCP resources: requests: memory: \"32Mi\" cpu: \"10m\" limits: memory: \"256Mi\" cpu: \"100m\" EOF","title":"\u90e8\u7f72\u670d\u52a1podinfo"},{"location":"k8s/cka_cn/foundamentals/hpa/#config-hpa","text":"\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a my-hpa \u7684 HPA\uff0c\u5e76\u5c06\u5176\u7ed1\u5b9a\u5230\u540d\u4e3a podinfo \u7684\u90e8\u7f72\u4e2d\uff0c\u8bbe\u5b9a\u5176 CPU \u5229\u7528\u7387\u4e3a 50% \u4f5c\u4e3a\u89e6\u53d1\u81ea\u52a8\u7f29\u653e\u7684\u9608\u503c\uff0c\u6700\u5c0f\u526f\u672c\u6570\u4e3a 2 \uff0c\u6700\u5927\u526f\u672c\u6570\u4e3a 10 \u3002 \u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u521b\u5efa my-hpa HPA\uff1a kubectl autoscale deployment podinfo --cpu-percent = 50 --min = 2 --max = 10 --name = my-hpa kubectl autoscale deployment podinfo --cpu-percent = 50 --min = 1 --max = 10 \u4f7f\u7528 autoscaling/v1 \u7248\u672c\u7684\u6a21\u7248\u6765\u521b\u5efaHPA my-hpa \u3002 kubectl apply -f - << body >< h1 > It works! \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete ingress demo-localhost kubectl delete service demo kubectl delete deployment demo \u521b\u5efaDeployments \u00b6 \u521b\u5efa2\u4e2adeployment nginx-app-1 \u548c nginx-app-2 \u3002 kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-1 spec: selector: matchLabels: app: nginx-app-1 replicas: 1 template: metadata: labels: app: nginx-app-1 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-1 --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-2 spec: selector: matchLabels: app: nginx-app-2 replicas: 1 template: metadata: labels: app: nginx-app-2 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-2 EOF \u6267\u884c\u547d\u4ee4 kubectl get pod -o wide \u6765\u83b7\u53d6pod\u7684\u72b6\u6001\u3002 \u53ef\u4ee5\u770b\u5230\u4e00\u4e2apod\u8fd0\u884c\u5728\u8282\u70b9 cka002 \uff0c\u53e6\u5916\u4e00\u4e2apod\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u3002 Directory /opt/html-2/ is on cka002 Directory /opt/html-1/ is on cka002 \u901a\u8fc7 curl \u547d\u4ee4\u6765\u8bbf\u95ee\u8fd92\u4e2apod\uff0c\u6536\u5230 403 Forbidden \u9519\u8bef\u3002 curl 10 .244.102.13 curl 10 .244.112.19 \u767b\u5f55\u5230\u8282\u70b9 cka002 \uff0c\u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u5728 /opt/html-2/ \u8def\u5f84\u4e0b\u521b\u5efa\u6587\u4ef6 index.html \u3002 cat < app1.com app2.com EOF \u6267\u884c\u4ee5\u4e0b\u547d\u4ee4\uff0c\u53ef\u4ee5\u5f97\u5230 IP \u5730\u5740\u6216 FQDN\u3002 kubectl get service ingress-nginx-controller --namespace = ingress-nginx \u5728\u8f93\u51fa\u7ed3\u679c\u4e2d\u53ef\u4ee5\u770b\u5230 EXTERNAL-IP \u5b57\u6bb5\u3002\u5982\u679c\u8be5\u5b57\u6bb5\u50cf\u4e0b\u9762\u4e00\u6837\u663e\u793a\u4e3a \uff0c\u8fd9\u610f\u5473\u7740 Kubernetes \u96c6\u7fa4\u65e0\u6cd5\u63d0\u4f9b\u8d1f\u8f7d\u5747\u8861\u5668\uff08\u901a\u5e38\u662f\u56e0\u4e3a\u5b83\u4e0d\u652f\u6301 LoadBalancer \u7c7b\u578b\u7684\u670d\u52a1\uff09\u3002 \u7531\u4e8e\u6ca1\u6709\u914d\u7f6e\u963f\u91cc\u4e91 ELB\uff0c\u56e0\u6b64\u6709\u4ee5\u4e0b\u4e24\u4e2a\u9009\u9879\u53ef\u4ee5\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u3002 \u9009\u9879 1\uff1a\u624b\u52a8\u5c06\u8282\u70b9 IP \u6dfb\u52a0\u5230\u8fd0\u884c ingress \u63a7\u5236\u5668\u7684\u8282\u70b9\u4e0a\u3002 \u6267\u884c\u547d\u4ee4 kubectl get pod -n ingress-nginx -o wide \u6765\u67e5\u770b ingress \u63a7\u5236\u5668 pod \u8fd0\u884c\u5728\u54ea\u4e2a\u8282\u70b9\u4e0a\u3002 \u624b\u52a8\u5c06 cka003 \u7684\u5916\u90e8 IP \u8865\u4e01\u5230 EXTERNAL-IP \u5b57\u6bb5\u3002 kubectl patch svc ingress-nginx-controller \\ --namespace = ingress-nginx \\ -p '{\"spec\": {\"type\": \"LoadBalancer\", \"externalIPs\":[\"\"]}}' \u9009\u9879 2\uff1a\u5c06 ingress \u63a7\u5236\u5668\u4ece LoadBalancer \u7c7b\u578b\u66f4\u6539\u4e3a NodePort \u7c7b\u578b\u3002 \u4e24\u4e2a Pod \u4e2d\u5404\u6709\u4e00\u4e2a index.html \u6587\u4ef6\uff0cWeb \u670d\u52a1\u901a\u8fc7\u8282\u70b9 IP \u5bf9\u5916\u66b4\u9732\u3002 ingress-nginx-controller \u4f5c\u4e3a\u4e2d\u5fc3\u5165\u53e3\u70b9\uff0c\u4e3a\u6765\u81ea Pod \u7684\u4e0d\u540c\u540e\u7aef\u670d\u52a1\u63d0\u4f9b\u4e86\u4e24\u4e2a\u7aef\u53e3\u3002 \u53d1\u9001HTTP\u8bf7\u6c42\u5230\u5728Ingress\u4e2d\u5b9a\u4e49\u76842\u4e2a\u4e3b\u673a\u8282\u70b9\u3002 curl http://app1.com:30011 curl http://app2.com:30011 curl app1.com:30011 curl app2.com:30011 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002 This is test 1 !! This is test 2 !! \u5220\u9664\u4e0a\u9762\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete ingress ingress-nginx-app kubectl delete service nginx-app-1 kubectl delete service nginx-app-2 kubectl delete deployment nginx-app-1 kubectl delete deployment nginx-app-2","title":"Ingress-nginx"},{"location":"k8s/cka_cn/foundamentals/ingress/#cka19ingress-nginx","text":"\u6f14\u793a\u573a\u666f\uff1a \u90e8\u7f72Ingress Controller\u3002 \u521b\u5efa\u4e24\u4e2aDeployment nginx-app-1 \u548c nginx-app-2 \u3002 \u5728\u8fd0\u884c\u4e3b\u673a\u4e0a\u521b\u5efa\u4e3b\u673a\u76ee\u5f55 /root/html-1 \u548c /root/html-2 \u5e76\u6302\u8f7d\u5230\u4e24\u4e2aDeployment\u4e0a\u3002 \u521b\u5efaService\u3002 \u521b\u5efaService nginx-app-1 \u548c nginx-app-2 \u5e76\u5c06\u5176\u6620\u5c04\u5230\u76f8\u5173\u7684Deployment nginx-app-1 \u548c nginx-app-2 \u3002 \u521b\u5efaIngress\u3002 \u521b\u5efaIngress\u8d44\u6e90 nginx-app \u5e76\u5c06\u5176\u6620\u5c04\u5230\u4e24\u4e2aServices nginx-app-1 \u548c nginx-app-1 \u3002 \u6d4b\u8bd5\u53ef\u8bbf\u95ee\u6027\u3002 \u5411Ingress\u4e2d\u5b9a\u4e49\u7684\u4e24\u4e2a\u4e3b\u673a\u53d1\u9001HTTP\u8bf7\u6c42\u3002 \u53c2\u8003\uff1a Github ingress-nginx Installation Guide","title":"CKA\u81ea\u5b66\u7b14\u8bb019:Ingress-nginx"},{"location":"k8s/cka_cn/foundamentals/ingress/#ingress","text":"\u83b7\u53d6Ingress\u63a7\u5236\u5668\u7684yaml\u6587\u4ef6\u3002\u6700\u65b0\u7248\u672c\u7684\u94fe\u63a5\u5728 \u5b89\u88c5\u6307\u5357 \u4e2d\u3002 wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml \u4fee\u6539 deploy.yaml \u6587\u4ef6\u4e2d\u955c\u50cf\u6e90\u4e3a\u963f\u91cc\u4e91\u7684\u6e90\u3002 deploy.yaml \u6587\u4ef6\u4e2d\u9700\u8981\u4fee\u6539\u7684\u884c\uff1a image : k8s.gcr.io/ingress-nginx/controller:v1.2.1@sha256:5516d103a9c2ecc4f026efbd4b40662ce22dc1f824fb129ed121460aaa5c47f8 image : registry.k8s.io/ingress-nginx/controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5 image : k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660 \u4fee\u6539\u5185\u5bb9\uff1a k8s.gcr.io/ingress-nginx/controller \u6539\u4e3a registry.aliyuncs.com/google_containers/nginx-ingress-controller \u3002 registry.k8s.io/ingress-nginx/controller \u6539\u4e3a registry.aliyuncs.com/google_containers/nginx-ingress-controller \u3002 k8s.gcr.io/ingress-nginx/kube-webhook-certgen \u6539\u4e3a registry.aliyuncs.com/google_containers/kube-webhook-certgen \u3002 \u4fee\u6539\u547d\u4ee4\uff1a sed -i 's/k8s.gcr.io\\/ingress-nginx\\/kube-webhook-certgen/registry.aliyuncs.com\\/google\\_containers\\/kube-webhook-certgen/g' deploy.yaml sed -i 's/k8s.gcr.io\\/ingress-nginx\\/controller/registry.aliyuncs.com\\/google\\_containers\\/nginx-ingress-controller/g' deploy.yaml \u5e94\u7528\u6587\u4ef6 deploy.yaml \u6765\u521b\u5efa Ingress Nginx\u3002 \u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4namespace ingress-nginx \u4f1a\u88ab\u521b\u5efa\uff0cIngress Nginx\u76f8\u5173\u7684\u8d44\u6e90\u8fd0\u884c\u5728\u8fd9\u4e2anamespace\u4e0a\u3002 kubectl apply -f deploy.yaml \u67e5\u770bPod\u7684\u72b6\u6001\u3002 kubectl get pod -n ingress-nginx \u786e\u4fdd\u6240\u4ee5pod\u7684\u8fd0\u884c\u72b6\u6001\u90fd\u6b63\u5e38\uff0c\u7c7b\u4f3c\u5982\u4e0b\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE ingress-nginx-admission-create-lgtdj 0/1 Completed 0 49s ingress-nginx-admission-patch-nk9fv 0/1 Completed 0 49s ingress-nginx-controller-556fbd6d6f-6jl4x 1/1 Running 0 49s","title":"\u90e8\u7f72Ingress\u63a7\u5236\u5668"},{"location":"k8s/cka_cn/foundamentals/ingress/#_1","text":"\u8ba9\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u7b80\u5355\u7684 Web \u670d\u52a1\u5668\u548c\u76f8\u5173\u7684\u670d\u52a1\uff1a kubectl create deployment demo --image = httpd --port = 80 kubectl expose deployment demo \u63a5\u4e0b\u6765\u521b\u5efa\u4e00\u4e2a Ingress \u8d44\u6e90\u3002\u4ee5\u4e0b\u793a\u4f8b\u4f7f\u7528\u5c06\u4e3b\u673a\u6620\u5c04\u5230 localhost: kubectl create ingress demo-localhost --class = nginx --rule = \"demo.localdev.me/*=demo:80\" \u73b0\u5728\uff0c\u5c06\u672c\u5730\u7aef\u53e3\u8f6c\u53d1\u5230Ingress\u63a7\u5236\u5668\uff1a kubectl port-forward --namespace = ingress-nginx service/ingress-nginx-controller 8080 :80 \u73b0\u5728\uff0c\u5728\u53e6\u4e00\u4e2a\u7ec8\u7aef\u4e2d\u8bbf\u95ee http://demo.localdev.me:8080/ \uff0c\u6211\u4eec\u5e94\u8be5\u770b\u5230\u4e00\u4e2a HTML \u9875\u9762\uff0c\u4e0a\u9762\u5199\u7740 \"It works!\"\u3002 curl http://demo.localdev.me:8080/ \u8fd0\u884c\u7ed3\u679c\uff1b < html >< body >< h1 > It works! \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete ingress demo-localhost kubectl delete service demo kubectl delete deployment demo","title":"\u672c\u5730\u6d4b\u8bd5\u65b9\u5f0f"},{"location":"k8s/cka_cn/foundamentals/ingress/#deployments","text":"\u521b\u5efa2\u4e2adeployment nginx-app-1 \u548c nginx-app-2 \u3002 kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-1 spec: selector: matchLabels: app: nginx-app-1 replicas: 1 template: metadata: labels: app: nginx-app-1 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-1 --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-2 spec: selector: matchLabels: app: nginx-app-2 replicas: 1 template: metadata: labels: app: nginx-app-2 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-2 EOF \u6267\u884c\u547d\u4ee4 kubectl get pod -o wide \u6765\u83b7\u53d6pod\u7684\u72b6\u6001\u3002 \u53ef\u4ee5\u770b\u5230\u4e00\u4e2apod\u8fd0\u884c\u5728\u8282\u70b9 cka002 \uff0c\u53e6\u5916\u4e00\u4e2apod\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u3002 Directory /opt/html-2/ is on cka002 Directory /opt/html-1/ is on cka002 \u901a\u8fc7 curl \u547d\u4ee4\u6765\u8bbf\u95ee\u8fd92\u4e2apod\uff0c\u6536\u5230 403 Forbidden \u9519\u8bef\u3002 curl 10 .244.102.13 curl 10 .244.112.19 \u767b\u5f55\u5230\u8282\u70b9 cka002 \uff0c\u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u5728 /opt/html-2/ \u8def\u5f84\u4e0b\u521b\u5efa\u6587\u4ef6 index.html \u3002 cat < app1.com app2.com EOF \u6267\u884c\u4ee5\u4e0b\u547d\u4ee4\uff0c\u53ef\u4ee5\u5f97\u5230 IP \u5730\u5740\u6216 FQDN\u3002 kubectl get service ingress-nginx-controller --namespace = ingress-nginx \u5728\u8f93\u51fa\u7ed3\u679c\u4e2d\u53ef\u4ee5\u770b\u5230 EXTERNAL-IP \u5b57\u6bb5\u3002\u5982\u679c\u8be5\u5b57\u6bb5\u50cf\u4e0b\u9762\u4e00\u6837\u663e\u793a\u4e3a \uff0c\u8fd9\u610f\u5473\u7740 Kubernetes \u96c6\u7fa4\u65e0\u6cd5\u63d0\u4f9b\u8d1f\u8f7d\u5747\u8861\u5668\uff08\u901a\u5e38\u662f\u56e0\u4e3a\u5b83\u4e0d\u652f\u6301 LoadBalancer \u7c7b\u578b\u7684\u670d\u52a1\uff09\u3002 \u7531\u4e8e\u6ca1\u6709\u914d\u7f6e\u963f\u91cc\u4e91 ELB\uff0c\u56e0\u6b64\u6709\u4ee5\u4e0b\u4e24\u4e2a\u9009\u9879\u53ef\u4ee5\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u3002 \u9009\u9879 1\uff1a\u624b\u52a8\u5c06\u8282\u70b9 IP \u6dfb\u52a0\u5230\u8fd0\u884c ingress \u63a7\u5236\u5668\u7684\u8282\u70b9\u4e0a\u3002 \u6267\u884c\u547d\u4ee4 kubectl get pod -n ingress-nginx -o wide \u6765\u67e5\u770b ingress \u63a7\u5236\u5668 pod \u8fd0\u884c\u5728\u54ea\u4e2a\u8282\u70b9\u4e0a\u3002 \u624b\u52a8\u5c06 cka003 \u7684\u5916\u90e8 IP \u8865\u4e01\u5230 EXTERNAL-IP \u5b57\u6bb5\u3002 kubectl patch svc ingress-nginx-controller \\ --namespace = ingress-nginx \\ -p '{\"spec\": {\"type\": \"LoadBalancer\", \"externalIPs\":[\"\"]}}' \u9009\u9879 2\uff1a\u5c06 ingress \u63a7\u5236\u5668\u4ece LoadBalancer \u7c7b\u578b\u66f4\u6539\u4e3a NodePort \u7c7b\u578b\u3002 \u4e24\u4e2a Pod \u4e2d\u5404\u6709\u4e00\u4e2a index.html \u6587\u4ef6\uff0cWeb \u670d\u52a1\u901a\u8fc7\u8282\u70b9 IP \u5bf9\u5916\u66b4\u9732\u3002 ingress-nginx-controller \u4f5c\u4e3a\u4e2d\u5fc3\u5165\u53e3\u70b9\uff0c\u4e3a\u6765\u81ea Pod \u7684\u4e0d\u540c\u540e\u7aef\u670d\u52a1\u63d0\u4f9b\u4e86\u4e24\u4e2a\u7aef\u53e3\u3002 \u53d1\u9001HTTP\u8bf7\u6c42\u5230\u5728Ingress\u4e2d\u5b9a\u4e49\u76842\u4e2a\u4e3b\u673a\u8282\u70b9\u3002 curl http://app1.com:30011 curl http://app2.com:30011 curl app1.com:30011 curl app2.com:30011 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002 This is test 1 !! This is test 2 !! \u5220\u9664\u4e0a\u9762\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete ingress ingress-nginx-app kubectl delete service nginx-app-1 kubectl delete service nginx-app-2 kubectl delete deployment nginx-app-1 kubectl delete deployment nginx-app-2","title":"\u53ef\u8bbf\u95ee\u6027\u6d4b\u8bd5"},{"location":"k8s/cka_cn/foundamentals/job/","text":"CKA\u81ea\u5b66\u7b14\u8bb014:Job and Cronjob \u00b6 Job \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efaJob\u3002 \u6f14\u793a\uff1a \u521b\u5efaJob pi \u3002 kubectl apply -f - << EOF apiVersion: batch/v1 kind: Job metadata: name: pi spec: template: spec: containers: - name: pi image: perl:5.34 command: [\"perl\", \"-Mbignum=bpi\", \"-wle\", \"print bpi(2000)\"] restartPolicy: Never backoffLimit: 4 EOF \u83b7\u53d6Job\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get jobs \u83b7\u53d6Job\u7684Pod\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 Completed \u7684\u72b6\u6001\u4ee3\u8868\u8fd9\u4e2ajob\u5df2\u7ecf\u6210\u529f\u5b8c\u6210\u4e86\u3002 kubectl get pod \u83b7\u53d6Job\u7684Pod\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl pi-2s74d 3 .141592653589793.............. \u5220\u9664\u6240\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete job pi Cronjob \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efaCronjob\u3002 \u6f14\u793a\uff1a \u521b\u5efaCronjob hello \u3002 kubectl apply -f - << EOF apiVersion: batch/v1 kind: CronJob metadata: name: hello spec: schedule: \"*/1 * * * *\" jobTemplate: spec: template: spec: containers: - name: hello image: busybox args: - /bin/sh - -c - date ; echo Hello from the kubernetes cluster restartPolicy: OnFailure EOF \u83b7\u53d6Cronjob\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get cronjobs -o wide \u8fd0\u884c\u7ed3\u679c NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE CONTAINERS IMAGES SELECTOR hello */1 * * * * False 0 25s hello busybox \u76d1\u63a7Jobs\u3002\u6bcf\u96941\u5206\u949f\uff0c\u4e00\u4e2a\u65b0\u7684job\u4f1a\u88ab\u521b\u5efa\u3002 kubectl get jobs -w \u5220\u9664\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete cronjob hello","title":"Job and Cronjob"},{"location":"k8s/cka_cn/foundamentals/job/#cka14job-and-cronjob","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb014:Job and Cronjob"},{"location":"k8s/cka_cn/foundamentals/job/#job","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efaJob\u3002 \u6f14\u793a\uff1a \u521b\u5efaJob pi \u3002 kubectl apply -f - << EOF apiVersion: batch/v1 kind: Job metadata: name: pi spec: template: spec: containers: - name: pi image: perl:5.34 command: [\"perl\", \"-Mbignum=bpi\", \"-wle\", \"print bpi(2000)\"] restartPolicy: Never backoffLimit: 4 EOF \u83b7\u53d6Job\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get jobs \u83b7\u53d6Job\u7684Pod\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 Completed \u7684\u72b6\u6001\u4ee3\u8868\u8fd9\u4e2ajob\u5df2\u7ecf\u6210\u529f\u5b8c\u6210\u4e86\u3002 kubectl get pod \u83b7\u53d6Job\u7684Pod\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl pi-2s74d 3 .141592653589793.............. \u5220\u9664\u6240\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete job pi","title":"Job"},{"location":"k8s/cka_cn/foundamentals/job/#cronjob","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efaCronjob\u3002 \u6f14\u793a\uff1a \u521b\u5efaCronjob hello \u3002 kubectl apply -f - << EOF apiVersion: batch/v1 kind: CronJob metadata: name: hello spec: schedule: \"*/1 * * * *\" jobTemplate: spec: template: spec: containers: - name: hello image: busybox args: - /bin/sh - -c - date ; echo Hello from the kubernetes cluster restartPolicy: OnFailure EOF \u83b7\u53d6Cronjob\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get cronjobs -o wide \u8fd0\u884c\u7ed3\u679c NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE CONTAINERS IMAGES SELECTOR hello */1 * * * * False 0 25s hello busybox \u76d1\u63a7Jobs\u3002\u6bcf\u96941\u5206\u949f\uff0c\u4e00\u4e2a\u65b0\u7684job\u4f1a\u88ab\u521b\u5efa\u3002 kubectl get jobs -w \u5220\u9664\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete cronjob hello","title":"Cronjob"},{"location":"k8s/cka_cn/foundamentals/memo/","text":"CKA\u81ea\u5b66\u7b14\u8bb05:Kubernetes\u968f\u7b14 \u00b6 \u6458\u8981 \u00b6 \u8fb9\u7ec3\u4e60\u8fb9\u8bb0\u5f55\u7684\u5185\u5bb9\uff0c\u4e0d\u662f\u5168\u9762\u7cfb\u7edf\u7684\uff0c\u5305\u62ec\u4e0b\u9762\u4e3b\u8981\u5185\u5bb9\uff1a Kubernetes\u57fa\u672c\u6982\u5ff5 \u7ec4\u4ef6 API \u5bf9\u8c61 \u8d44\u6e90 \u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90 Pod Deployment ReplicaSet StatefulSet DaemonSet Job CronJob \u670d\u52a1\u8d44\u6e90 Service Endpoints \u914d\u7f6e\u548c\u5b58\u50a8\u8d44\u6e90 \u5377 Storage Class PV Access Modes Kubernetes\u57fa\u672c\u6982\u5ff5 \u00b6 Kubernetes\u7ec4\u4ef6 \u00b6 \u4e00\u4e2aKubernetes\u96c6\u7fa4\u7531\u4ee3\u8868\u63a7\u5236\u5e73\u9762\uff08control plane\uff09\u7684\u7ec4\u4ef6\u548c\u4e00\u7ec4\u79f0\u4e3a\u8282\u70b9\uff08nodes\uff09\u7684\u673a\u5668\u7ec4\u6210\u3002 Kubernetes\u7ec4\u4ef6: \u63a7\u5236\u5e73\u9762\u7ec4\u4ef6 Control Plane Components kube-apiserver: \u67e5\u8be2\u548c\u64cd\u4f5c Kubernetes \u4e2d\u5bf9\u8c61\u7684\u72b6\u6001\u3002 \u5145\u5f53\u6240\u6709\u8d44\u6e90\u4e4b\u95f4\u7684\u901a\u4fe1\u4e2d\u5fc3\uff08communication hub\uff09\u3002 \u63d0\u4f9b\u96c6\u7fa4\u5b89\u5168\u8eab\u4efd\u9a8c\u8bc1\u3001\u6388\u6743\u548c\u89d2\u8272\u5206\u914d\u3002 \u662f\u552f\u4e00\u80fd\u8fde\u63a5\u5230 etcd \u7684\u7ec4\u4ef6\u3002 etcd: \u6240\u6709 Kubernetes \u5bf9\u8c61\u90fd\u5b58\u50a8\u5728 etcd \u4e2d\u3002 Kubernetes \u5bf9\u8c61\u662f Kubernetes \u7cfb\u7edf\u4e2d\u7684\u6301\u4e45\u5b9e\u4f53(entities)\uff0c\u7528\u4e8e\u8868\u793a\u96c6\u7fa4\u7684\u72b6\u6001\u3002 kube-scheduler: \u76d1\u89c6\u6ca1\u6709\u5206\u914d\u8282\u70b9\u7684\u65b0\u521b\u5efa\u7684 Pod\uff0c\u5e76\u4e3a\u5b83\u4eec\u9009\u62e9\u4e00\u4e2a\u8282\u70b9\u6765\u8fd0\u884c\u3002 kube-controller-manager: \u8fd0\u884c\u63a7\u5236\u5668\u8fdb\u7a0b\u3002 Node controller : \u8d1f\u8d23\u8b66\u793a\u548c\u54cd\u5e94\u8282\u70b9\u7684\u6545\u969c\u3002 Job controller : \u76d1\u89c6\u8868\u793a\u4e00\u6b21\u6027\u4efb\u52a1\u7684 Job \u5bf9\u8c61\uff0c\u7136\u540e\u521b\u5efa Pod \u6765\u5b8c\u6210\u8fd9\u4e9b\u4efb\u52a1\u3002 Endpoints controller : \u586b\u5145 Endpoints \u5bf9\u8c61\uff08\u5373\u5c06 Service \u548c Pod \u8fde\u63a5\u8d77\u6765\uff09\u3002 Service Account & Token controllers : \u4e3a\u65b0\u547d\u540d\u7a7a\u95f4\u521b\u5efa\u9ed8\u8ba4\u5e10\u6237\u548c API \u8bbf\u95ee\u4ee4\u724c\u3002 cloud-controller-manager: \u5d4c\u5165\u4e91\u7279\u5b9a\u7684\u63a7\u5236\u903b\u8f91\uff0c\u4ec5\u8fd0\u884c\u7279\u5b9a\u4e8e\u6211\u4eec\u9009\u62e9\u7684\u4e91\u63d0\u4f9b\u5546\u7684\u63a7\u5236\u5668\uff0c\u65e0\u9700\u81ea\u5df1\u7684\u57fa\u7840\u8bbe\u65bd\u548c\u5b66\u4e60\u73af\u5883\u3002 Node controller : \u7528\u4e8e\u68c0\u67e5\u4e91\u63d0\u4f9b\u5546\uff0c\u4ee5\u786e\u5b9a\u8282\u70b9\u5728\u5728\u5b83\u505c\u6b62\u54cd\u5e94\u540e\u662f\u5426\u5df2\u5728\u4e91\u4e2d\u88ab\u5220\u9664\u3002 Route controller : \u7528\u4e8e\u5728\u5e95\u5c42\u4e91\u57fa\u7840\u67b6\u6784\u4e2d\u8bbe\u7f6e\u8def\u7531\u3002 Service controller : \u7528\u4e8e\u521b\u5efa\u3001\u66f4\u65b0\u548c\u5220\u9664\u4e91\u63d0\u4f9b\u5546\u8d1f\u8f7d\u5747\u8861\u5668\u3002 \u8282\u70b9\u7ec4\u4ef6 Node Components kubelet: \u5728\u96c6\u7fa4\u4e2d\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u7684\u4ee3\u7406\u3002 \u7ba1\u7406\u8282\u70b9\u3002\u5b83\u786e\u4fdd Pod \u4e2d\u8fd0\u884c\u5bb9\u5668\u3002 kubelet \u5411 APIServer \u6ce8\u518c\u548c\u66f4\u65b0\u8282\u70b9\u4fe1\u606f\uff0cAPIServer \u5c06\u5b83\u4eec\u5b58\u50a8\u5230 etcd \u4e2d\u3002 \u7ba1\u7406 Pod\u3002\u901a\u8fc7 APIServer \u76d1\u89c6 Pod\uff0c\u5e76\u5bf9 Pod \u6216 Pod \u4e2d\u7684\u5bb9\u5668\u91c7\u53d6\u884c\u52a8\u3002 \u5728\u5bb9\u5668\u7ea7\u522b\u8fdb\u884c\u5065\u5eb7\u68c0\u67e5\u3002 kube-proxy: \u662f\u5728\u96c6\u7fa4\u4e2d\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u7684\u7f51\u7edc\u4ee3\u7406\u3002 iptables ipvs \u7ef4\u62a4\u8282\u70b9\u4e0a\u7684\u7f51\u7edc\u89c4\u5219\u3002 \u5bb9\u5668\u8fd0\u884c\u65f6Container runtime\uff1a \u8d1f\u8d23\u8fd0\u884c\u5bb9\u5668\u7684\u8f6f\u4ef6\u3002 \u63d2\u4ef6Addons DNS: \u662f DNS \u670d\u52a1\u5668\uff0c\u662f\u6240\u6709 Kubernetes \u96c6\u7fa4\u6240\u5fc5\u9700\u7684\u3002 Web UI\uff08\u4eea\u8868\u76d8\uff09\uff1a\u7528\u4e8e Kubernetes \u96c6\u7fa4\u7684\u57fa\u4e8e Web \u7684\u7528\u6237\u754c\u9762\u3002 \u5bb9\u5668\u8d44\u6e90\u76d1\u63a7\uff1a\u8bb0\u5f55\u6709\u5173\u96c6\u4e2d\u5f0f\u6570\u636e\u5e93\u4e2d\u5bb9\u5668\u7684\u901a\u7528\u65f6\u95f4\u5e8f\u5217\u5ea6\u91cf\u3002 Cluster-level Logging\uff1a\u8d1f\u8d23\u5c06\u5bb9\u5668\u65e5\u5fd7\u4fdd\u5b58\u5230\u5177\u6709\u641c\u7d22/\u6d4f\u89c8\u63a5\u53e3\u7684\u4e2d\u592e\u65e5\u5fd7\u5b58\u50a8\u4e2d\u3002 \u53ef\u6269\u5c55\u6027\uff1a \u6c34\u5e73\u6269\u5c55\uff08Scaling out\uff09\u901a\u8fc7\u6dfb\u52a0\u66f4\u591a\u7684\u670d\u52a1\u5668\u5230\u67b6\u6784\u4e2d\uff0c\u5c06\u5de5\u4f5c\u8d1f\u8f7d\u5206\u6563\u5230\u66f4\u591a\u7684\u673a\u5668\u4e0a\u3002 \u5782\u76f4\u6269\u5c55\uff08Scaling up\uff09\u901a\u8fc7\u6dfb\u52a0\u66f4\u591a\u7684\u786c\u76d8\u548c\u5185\u5b58\u6765\u589e\u52a0\u7269\u7406\u670d\u52a1\u5668\u7684\u8ba1\u7b97\u80fd\u529b\u3002 Kubernetes API \u00b6 REST API\u662fKubernetes\u7684\u57fa\u672c\u6846\u67b6\u3002\u6240\u6709\u7ec4\u4ef6\u4e4b\u95f4\u7684\u64cd\u4f5c\u548c\u901a\u4fe1\uff0c\u4ee5\u53ca\u5916\u90e8\u7528\u6237\u547d\u4ee4\u90fd\u662f\u7531API\u670d\u52a1\u5668\u5904\u7406\u7684REST API\u8c03\u7528\u3002\u56e0\u6b64\uff0cKubernetes\u5e73\u53f0\u4e2d\u7684\u6240\u6709\u5185\u5bb9\u90fd\u88ab\u89c6\u4e3aAPI\u5bf9\u8c61\uff08API object\uff09\uff0c\u5e76\u5728API\u4e2d\u6709\u76f8\u5e94\u7684\u6761\u76ee\u3002 Kubernetes\u63a7\u5236\u5e73\u9762\u7684\u6838\u5fc3\u662fAPI\u670d\u52a1\u5668\u3002 CRI\uff1a\u5bb9\u5668\u8fd0\u884c\u65f6\u63a5\u53e3 CNI\uff1a\u5bb9\u5668\u7f51\u7edc\u63a5\u53e3 CSI\uff1a\u5bb9\u5668\u5b58\u50a8\u63a5\u53e3 API\u670d\u52a1\u5668\u516c\u5f00\u4e86\u4e00\u4e2aHTTP API\uff0c\u5141\u8bb8\u6700\u7ec8\u7528\u6237\u3001\u96c6\u7fa4\u7684\u4e0d\u540c\u90e8\u5206\u548c\u5916\u90e8\u7ec4\u4ef6\u5f7c\u6b64\u901a\u4fe1\u3002 Kubernetes API\u5141\u8bb8\u6211\u4eec\u67e5\u8be2\u548c\u64cd\u4f5cKubernetes\u4e2dAPI\u5bf9\u8c61\u7684\u72b6\u6001\uff08\u4f8b\u5982\uff1aPod\u3001Namespace\u3001ConfigMap\u548cEvent\uff09\u3002 Kubernetes API\uff1a OpenAPI\u89c4\u8303 OpenAPI V2 OpenAPI V3 \u6301\u4e45\u6027\u3002Kubernetes\u901a\u8fc7\u5c06\u5bf9\u8c61\u7684\u5e8f\u5217\u5316\u72b6\u6001\u5199\u5165etcd\u6765\u5b58\u50a8\u5b83\u4eec\u3002 API\u7ec4\u548c\u7248\u672c\u63a7\u5236\u3002\u7248\u672c\u63a7\u5236\u662f\u5728API\u7ea7\u522b\u8fdb\u884c\u7684\u3002API\u8d44\u6e90\u901a\u8fc7\u5b83\u4eec\u7684API\u7ec4\u3001\u8d44\u6e90\u7c7b\u578b\u3001\u547d\u540d\u7a7a\u95f4\uff08\u7528\u4e8e\u547d\u540d\u7a7a\u95f4\u8d44\u6e90\uff09\u548c\u540d\u79f0\u8fdb\u884c\u533a\u5206\u3002 API\u66f4\u6539 API\u6269\u5c55 API Version \u00b6 API\u7248\u672c\u548c\u8f6f\u4ef6\u7248\u672c\u95f4\u5b58\u5728\u95f4\u63a5\u5173\u7cfb\u3002API\u548c\u53d1\u5e03\u7248\u672c\u8ba1\u5212\u63cf\u8ff0\u4e86API\u7248\u672c\u548c\u8f6f\u4ef6\u7248\u672c\u4e4b\u95f4\u7684\u5173\u7cfb\u3002\u4e0d\u540c\u7684API\u7248\u672c\u8868\u793a\u4e0d\u540c\u7684\u7a33\u5b9a\u6027\u548c\u652f\u6301\u7ea7\u522b\u3002 \u4ee5\u4e0b\u662f\u6bcf\u4e2a\u7ea7\u522b\u7684\u6458\u8981\uff1a Alpha\uff1a \u7248\u672c\u540d\u79f0\u5305\u542balpha\uff08\u4f8b\u5982\uff0cv1alpha1\uff09\u3002 \u8f6f\u4ef6\u53ef\u80fd\u5305\u542b\u9519\u8bef\u3002\u542f\u7528\u529f\u80fd\u53ef\u80fd\u4f1a\u66b4\u9732\u9519\u8bef\u3002\u67d0\u4e9b\u529f\u80fd\u53ef\u80fd\u9ed8\u8ba4\u7981\u7528\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u529f\u80fd\u7684\u652f\u6301\u53ef\u4ee5\u968f\u65f6\u53d6\u6d88\uff0c\u800c\u4e0d\u4f1a\u63d0\u524d\u901a\u77e5\u3002 API\u53ef\u80fd\u4f1a\u5728\u4ee5\u540e\u7684\u8f6f\u4ef6\u53d1\u5e03\u4e2d\u4ee5\u4e0d\u517c\u5bb9\u7684\u65b9\u5f0f\u66f4\u6539\uff0c\u800c\u4e0d\u4f1a\u63d0\u524d\u901a\u77e5\u3002 \u7531\u4e8e\u9519\u8bef\u98ce\u9669\u589e\u52a0\u548c\u957f\u671f\u652f\u6301\u4e0d\u8db3\uff0c\u5efa\u8bae\u4ec5\u5728\u77ed\u6682\u7684\u6d4b\u8bd5\u96c6\u7fa4\u4e2d\u4f7f\u7528\u8be5\u8f6f\u4ef6\u3002 Beta\uff1a \u7248\u672c\u540d\u79f0\u5305\u542bbeta\uff08\u4f8b\u5982\uff0cv2beta3\uff09\u3002 \u8f6f\u4ef6\u7ecf\u8fc7\u5145\u5206\u6d4b\u8bd5\u3002\u542f\u7528\u529f\u80fd\u88ab\u8ba4\u4e3a\u662f\u5b89\u5168\u7684\u3002\u67d0\u4e9b\u529f\u80fd\u9ed8\u8ba4\u542f\u7528\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u529f\u80fd\u7684\u652f\u6301\u4e0d\u4f1a\u53d6\u6d88\uff0c\u4f46\u7ec6\u8282\u53ef\u80fd\u4f1a\u66f4\u6539\u3002 \u5bf9\u8c61\u7684\u6a21\u5f0f\u548c/\u6216\u8bed\u4e49\u53ef\u80fd\u4f1a\u5728\u540e\u7eed\u7684Beta\u6216\u7a33\u5b9a\u7248\u53d1\u5e03\u4e2d\u4ee5\u4e0d\u517c\u5bb9\u7684\u65b9\u5f0f\u66f4\u6539\u3002\u5f53\u53d1\u751f\u8fd9\u79cd\u60c5\u51b5\u65f6\uff0c\u5c06\u63d0\u4f9b\u8fc1\u79fb\u8bf4\u660e\u3002\u6a21\u5f0f\u66f4\u6539\u53ef\u80fd\u9700\u8981\u5220\u9664\u3001\u7f16\u8f91\u548c\u91cd\u65b0\u521b\u5efa API\u5bf9\u8c61\u3002\u7f16\u8f91\u8fc7\u7a0b\u53ef\u80fd\u4e0d\u7b80\u5355\u3002\u8fc1\u79fb\u53ef\u80fd\u9700\u8981\u505c\u673a\uff0c\u4ee5\u4fbf\u4f9d\u8d56\u4e8e\u8be5\u529f\u80fd\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 \u4e0d\u5efa\u8bae\u5c06\u8be5\u8f6f\u4ef6\u7528\u4e8e\u751f\u4ea7\u7528\u9014\u3002\u540e\u7eed\u7684\u53d1\u5e03\u53ef\u80fd\u4f1a\u5f15\u5165\u4e0d\u517c\u5bb9\u7684\u66f4\u6539\u3002\u5982\u679c\u60a8\u6709\u591a\u4e2a\u53ef\u4ee5\u72ec\u7acb\u5347\u7ea7\u7684\u96c6\u7fa4\uff0c\u5219\u53ef\u4ee5\u653e\u5bbd\u6b64\u9650\u5236\u3002 \u6ce8\u610f\uff1a\u8bf7\u5c1d\u8bd5beta\u529f\u80fd\u5e76\u63d0\u4f9b\u53cd\u9988\u3002\u529f\u80fd\u9000\u51fabeta\u540e\uff0c\u53ef\u80fd\u4e0d\u5b9e\u9645\u518d\u8fdb\u884c\u66f4\u6539\u3002 \u7a33\u5b9a\u7248\uff1a \u7248\u672c\u540d\u79f0\u4e3avX\uff0c\u5176\u4e2dX\u662f\u6574\u6570\u3002 \u529f\u80fd\u7684\u7a33\u5b9a\u7248\u672c\u51fa\u73b0\u5728\u53d1\u5e03\u7684\u8f6f\u4ef6\u4e2d\u7684\u8bb8\u591a\u540e\u7eed\u7248\u672c\u4e2d\u3002 \u8bfb\u53d6\u5f53\u524dAPI\u7684\u7248\u672c\u547d\u4ee4\uff1a kubectl api-resources API Group \u00b6 API\u7ec4\uff08API groups\uff09 \u4f7f\u6269\u5c55Kubernetes API\u66f4\u52a0\u5bb9\u6613\u3002API\u7ec4\u5728REST\u8def\u5f84\u548c\u5e8f\u5217\u5316\u5bf9\u8c61\u7684apiVersion\u5b57\u6bb5\u4e2d\u6307\u5b9a\u3002 Kubernetes\u6709\u51e0\u4e2aAPI\u7ec4\uff1a \u6838\u5fc3\u7ec4\uff08\u4e5f\u79f0\u4e3a\u9057\u7559legacy\uff09\u4f4d\u4e8eREST\u8def\u5f84 /api/v1 \u3002 \u6838\u5fc3\u7ec4\u4e0d\u4f5c\u4e3aapiVersion\u5b57\u6bb5\u7684\u4e00\u90e8\u5206\u6307\u5b9a\uff0c\u4f8b\u5982 apiVersion: v1\u3002 \u547d\u540d\u7ec4\u4f4d\u4e8eREST\u8def\u5f84 /apis/$GROUP_NAME/$VERSION \uff0c\u5e76\u4f7f\u7528 apiVersion: $GROUP_NAME/$VERSION \uff08\u4f8b\u5982 apiVersion: batch/v1\uff09\u3002 Kubernetes\u5bf9\u8c61 \u00b6 \u5bf9\u8c61\u6982\u8ff0 \u00b6 \u5bf9\u8c61\u89c4\u8303\uff08Object Spec\uff09\uff1a \u63d0\u4f9b\u4e86\u4e00\u4e2a\u63cf\u8ff0\u6240\u521b\u5efa\u8d44\u6e90\u7684\u7279\u6027\u7684\u8bf4\u660e\uff1a \u5176\u671f\u671b\u7684\u72b6\u6001 \u3002 \u5bf9\u8c61\u72b6\u6001\uff08Object Status\uff09\uff1a \u63cf\u8ff0\u4e86\u5bf9\u8c61\u7684\u5f53\u524d\u72b6\u6001\u3002 \u6bd4\u5982\uff0cDeployment\u662f\u4e00\u4e2a\u53ef\u4ee5\u4ee3\u8868\u96c6\u7fa4\u4e0a\u8fd0\u884c\u7684\u5e94\u7528\u7a0b\u5e8f\u7684\u5bf9\u8c61\u3002 apiVersion : apps/v1 # \u5f53\u524d\u7528\u6765\u521b\u5efa\u5bf9\u8c61\u7684API\u7248\u672c kind : Deployment # \u521b\u5efa\u5bf9\u8c61\u7684\u7c7b\u578b metadata : # \u7528\u6765\u533a\u5206\u5bf9\u8c61\u7684\u5143\u6570\u636e\uff0c\u6bd4\u5982\uff1a\u540d\u79f0\uff0cUID\uff0c\u547d\u540d\u7a7a\u95f4\u7b49 name : nginx-deployment spec : # \u671f\u671b\u6240\u521b\u5efa\u5bf9\u8c61\u7684\u72b6\u6001 selector : matchLabels : app : nginx replicas : 2 # \u544a\u8bc9Deployment\u57fa\u4e8e\u4e0b\u9762\u7684\u6a21\u677ftemplate\u521b\u5efa2\u4e2aPods template : metadata : labels : app : nginx spec : containers : - name : nginx image : nginx:1.14.2 ports : - containerPort : 80 \u5bf9\u8c61\u7ba1\u7406 \u00b6 kubectl \u547d\u4ee4\u884c\u5de5\u5177\u652f\u6301\u591a\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u6765\u521b\u5efa\u548c\u7ba1\u7406 Kubernetes \u5bf9\u8c61\u3002\u8be6\u7ec6\u4fe1\u606f\u8bf7\u9605\u8bfb Kubectl book \u3002 \u4e00\u4e2a Kubernetes \u5bf9\u8c61\u5e94\u8be5\u4ec5\u4f7f\u7528\u4e00\u79cd\u6280\u672f\u8fdb\u884c\u7ba1\u7406\u3002\u6df7\u5408\u4f7f\u7528\u4e0d\u540c\u7684\u6280\u672f\u6765\u7ba1\u7406\u540c\u4e00\u4e2a\u5bf9\u8c61\u4f1a\u5bfc\u81f4\u975e\u9884\u671f\u7684\u7ed3\u679c\u3002 \u4e09\u79cd\u7ba1\u7406\u6280\u672f: \u547d\u4ee4\u5f0f\u547d\u4ee4 \u76f4\u63a5\u5728\u96c6\u7fa4\u4e2d\u64cd\u4f5c\u5b9e\u65f6\u5bf9\u8c61\u3002 kubectl create deployment nginx --image nginx \u547d\u4ee4\u5f0f\u5bf9\u8c61\u914d\u7f6e kubectl create -f nginx.yaml kubectl delete -f nginx.yaml -f redis.yaml kubectl replace -f nginx.yaml \u58f0\u660e\u5f0f\u5bf9\u8c61\u914d\u7f6e kubectl diff -f configs/ kubectl apply -f configs/ \u5bf9\u8c61\u540d\u79f0\u548cID \u00b6 \u96c6\u7fa4\u4e2d\u7684\u6bcf\u4e2a\u5bf9\u8c61\u90fd\u6709\u4e00\u4e2a\u5728\u8be5\u8d44\u6e90\u7c7b\u578b\u4e2d\u552f\u4e00\u7684\u540d\u79f0\u3002 DNS \u5b50\u57df\u540d \u6807\u7b7e\u540d\u79f0 \u8def\u5f84\u6bb5\u540d\u79f0 \u6bcf\u4e2a Kubernetes \u5bf9\u8c61\u8fd8\u6709\u4e00\u4e2a UID\uff0c\u5728\u6574\u4e2a\u96c6\u7fa4\u4e2d\u662f\u552f\u4e00\u7684\u3002 \u547d\u540d\u7a7a\u95f4 \u00b6 \u5728Kubernetes\u4e2d\uff0c\u547d\u540d\u7a7a\u95f4\u63d0\u4f9b\u4e86\u4e00\u79cd\u5728\u5355\u4e2a\u96c6\u7fa4\u5185\u9694\u79bb\u8d44\u6e90\u7ec4\u7684\u673a\u5236\u3002 \u8d44\u6e90\u7684\u540d\u79f0\u9700\u8981\u5728\u547d\u540d\u7a7a\u95f4\u5185\u662f\u552f\u4e00\u7684\uff0c\u4f46\u4e0d\u9700\u8981\u8de8\u547d\u540d\u7a7a\u95f4\u552f\u4e00\u3002 \u57fa\u4e8e\u547d\u540d\u7a7a\u95f4\u7684\u8303\u56f4\u4ec5\u9002\u7528\u4e8e\u547d\u540d\u7a7a\u95f4\u5bf9\u8c61\uff08\u4f8b\u5982\u90e8\u7f72\uff0c\u670d\u52a1\u7b49\uff09\uff0c\u800c\u4e0d\u9002\u7528\u4e8e\u96c6\u7fa4\u8303\u56f4\u7684\u5bf9\u8c61\uff08\u4f8b\u5982StorageClass\uff0c\u8282\u70b9\uff0c\u6301\u4e45\u5377\u7b49\uff09\u3002 \u5e76\u975e\u6240\u6709\u5bf9\u8c61\u90fd\u4f4d\u4e8e\u547d\u540d\u7a7a\u95f4\u4e2d\u3002 Kubernetes\u4ece\u56db\u4e2a\u521d\u59cb\u547d\u540d\u7a7a\u95f4\u5f00\u59cb\uff1a default \u7528\u4e8e\u6ca1\u6709\u5176\u4ed6\u547d\u540d\u7a7a\u95f4\u7684\u5bf9\u8c61\u7684\u9ed8\u8ba4\u547d\u540d\u7a7a\u95f4 kube-system Kubernetes\u7cfb\u7edf\u521b\u5efa\u7684\u5bf9\u8c61\u7684\u547d\u540d\u7a7a\u95f4 kube-public \u8be5\u547d\u540d\u7a7a\u95f4\u662f\u81ea\u52a8\u521b\u5efa\u7684\uff0c\u5e76\u53ef\u7531\u6240\u6709\u7528\u6237\uff08\u5305\u62ec\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\uff09\u8bfb\u53d6\u3002\u6b64\u547d\u540d\u7a7a\u95f4\u5927\u591a\u4fdd\u7559\u4f9b\u96c6\u7fa4\u4f7f\u7528\uff0c\u4ee5\u9632\u4e00\u4e9b\u8d44\u6e90\u5e94\u5728\u6574\u4e2a\u96c6\u7fa4\u8303\u56f4\u5185\u516c\u5f00\u548c\u53ef\u8bfb\u3002\u6b64\u547d\u540d\u7a7a\u95f4\u7684\u516c\u5171\u65b9\u9762\u53ea\u662f\u4e00\u79cd\u7ea6\u5b9a\uff0c\u800c\u4e0d\u662f\u8981\u6c42\u3002 kube-node-lease \u6b64\u547d\u540d\u7a7a\u95f4\u4fdd\u5b58\u4e0e\u6bcf\u4e2a\u8282\u70b9\u5173\u8054\u7684\u79df\u8d41\u5bf9\u8c61\u3002\u8282\u70b9\u79df\u8d41\u5141\u8bb8kubelet\u53d1\u9001\u5fc3\u8df3\uff0c\u4ee5\u4fbf\u63a7\u5236\u5e73\u9762\u53ef\u4ee5\u68c0\u6d4b\u5230\u8282\u70b9\u6545\u969c\u3002 \u67e5\u770b\u547d\u540d\u7a7a\u95f4\uff1a kubectl get namespace \u4e3a\u8bf7\u6c42\u8bbe\u7f6e\u547d\u540d\u7a7a\u95f4 kubectl run nginx --image=nginx --namespace=<\u63d2\u5165\u547d\u540d\u7a7a\u95f4\u540d\u79f0> kubectl get pods --namespace=<\u63d2\u5165\u547d\u540d\u7a7a\u95f4\u540d\u79f0> \u6807\u7b7e\u548c\u9009\u62e9\u5668 \u00b6 \u6807\u7b7e\u662f\u9644\u52a0\u5230\u5bf9\u8c61\uff08\u4f8b\u5982 Pod\uff09\u7684\u952e/\u503c\u5bf9\u3002\u6709\u6548\u7684\u6807\u7b7e\u952e\u6709\u4e24\u4e2a\u90e8\u5206\uff1a\u53ef\u9009\u7684\u524d\u7f00\u548c\u540d\u79f0\uff0c\u7531\u659c\u6760\uff08 / \uff09\u5206\u9694\u3002 \u6807\u7b7e\u65e8\u5728\u7528\u4e8e\u6307\u5b9a\u5bf9\u7528\u6237\u6709\u610f\u4e49\u548c\u76f8\u5173\u7684\u5bf9\u8c61\u8bc6\u522b\u5c5e\u6027\u3002 \u6807\u7b7e\u53ef\u7528\u4e8e\u7ec4\u7ec7\u548c\u9009\u62e9\u5bf9\u8c61\u5b50\u96c6\u3002\u6807\u7b7e\u53ef\u4ee5\u5728\u521b\u5efa\u5bf9\u8c61\u65f6\u9644\u52a0\uff0c\u968f\u540e\u5728\u4efb\u4f55\u65f6\u5019\u6dfb\u52a0\u548c\u4fee\u6539\u3002\u6bcf\u4e2a\u5bf9\u8c61\u53ef\u4ee5\u5b9a\u4e49\u4e00\u7ec4\u952e/\u503c\u6807\u7b7e\uff0c\u6bcf\u4e2a\u952e\u5fc5\u987b\u5bf9\u4e8e\u7ed9\u5b9a\u5bf9\u8c61\u662f\u552f\u4e00\u7684\u3002 \u6807\u7b7e\u7684\u793a\u4f8b\uff1a \"metadata\" : { \"labels\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } \u4e0e\u540d\u79f0\u548c UID \u4e0d\u540c\uff0c\u6807\u7b7e\u4e0d\u63d0\u4f9b\u552f\u4e00\u6027\u3002\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u671f\u671b\u8bb8\u591a\u5bf9\u8c61\u5e26\u6709\u76f8\u540c\u7684\u6807\u7b7e\u3002 \u76ee\u524d API \u652f\u6301\u4e24\u79cd\u7c7b\u578b\u7684\u9009\u62e9\u5668\uff1a \u57fa\u4e8e\u7b49\u5f0f\u7684\u9009\u62e9\u5668\uff0c\u4f8b\u5982\uff1a environment = production \u3001 tier != frontend \u57fa\u4e8e\u96c6\u5408\u7684\u9009\u62e9\u5668\uff0c\u4f8b\u5982\uff1a environment in (production, qa) \u3001 tier notin (frontend, backend) \u4f8b\u5982\uff1a kubectl get pods -l environment = production,tier = frontend kubectl get pods -l 'environment in (production),tier in (frontend)' kubectl get pods -l 'environment in (production, qa)' kubectl get pods -l 'environment,environment notin (frontend)' \u6ce8\u91caAnnotations \u00b6 \u4f7f\u7528 Kubernetes \u6ce8\u91ca\uff08Annotations\uff09\u5c06\u4efb\u610f\u975e\u6807\u8bc6\u5143\u6570\u636e\u9644\u52a0\u5230\u5bf9\u8c61\u4e0a\u3002 \u5de5\u5177\u548c\u5e93\u7b49\u5ba2\u6237\u7aef\u53ef\u4ee5\u68c0\u7d22\u6b64\u5143\u6570\u636e\u3002 \u4f7f\u7528\u6807\u7b7e\u6216\u6ce8\u91ca\u5c06\u5143\u6570\u636e\u9644\u52a0\u5230 Kubernetes \u5bf9\u8c61\u4e0a\u3002 \u6807\u7b7e\u53ef\u7528\u4e8e\u9009\u62e9\u5bf9\u8c61\u5e76\u67e5\u627e\u6ee1\u8db3\u67d0\u4e9b\u6761\u4ef6\u7684\u5bf9\u8c61\u96c6\u5408\u3002 \u6ce8\u91ca\u4e0d\u7528\u4e8e\u6807\u8bc6\u548c\u9009\u62e9\u5bf9\u8c61\u3002 \u6ce8\u91ca\u4e0e\u6807\u7b7e\u7c7b\u4f3c\uff0c\u90fd\u662f\u952e/\u503c\u6620\u5c04\u3002 \u6620\u5c04\u4e2d\u7684\u952e\u548c\u503c\u5fc5\u987b\u662f\u5b57\u7b26\u4e32\u3002 \u4f8b\u5982\uff1a \"metadata\" : { \"annotations\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } \u5408\u6cd5\u7684\u6ce8\u91ca\u952e\u5177\u6709\u4e24\u4e2a\u90e8\u5206\uff1a\u53ef\u9009\u7684\u524d\u7f00\u548c\u540d\u79f0\uff0c\u7531\u659c\u6760 ( / ) \u5206\u9694\u3002 \u5b57\u6bb5\u9009\u62e9\u5668 \u00b6 \u5b57\u6bb5\u9009\u62e9\u5668\uff08field selectors\uff09\u53ef\u4ee5\u6839\u636e\u4e00\u4e2a\u6216\u591a\u4e2a\u8d44\u6e90\u5b57\u6bb5\u7684\u503c\u9009\u62e9Kubernetes\u8d44\u6e90\u3002 \u4e0b\u9762\u662f\u4e00\u4e9b\u4f7f\u7528\u5b57\u6bb5\u9009\u62e9\u5668\u8fdb\u884c\u67e5\u8be2\u7b5b\u9009\u7684\u4f8b\u5b50\uff1a metadata.name=my-service metadata.namespace!=default status.phase=Pending This kubectl command selects all Pods for which the value of the status.phase field is Running: kubectl get pods --field-selector status.phase=Running Supported field selectors vary by Kubernetes resource type. All resource types support the metadata.name and metadata.namespace fields. Use the = , == , and != operators with field selectors ( = and == mean the same thing). \u4e0b\u9762 kubectl \u547d\u4ee4\u9009\u62e9\u6240\u6709\u72b6\u6001(phase)\u5b57\u6bb5\u503c\u4e3a Running \u7684 Pod\uff1a kubectl get pods --field-selector status.phase = Running \u652f\u6301\u7684\u5b57\u6bb5\u9009\u62e9\u5668\u56e0 Kubernetes \u8d44\u6e90\u7c7b\u578b\u800c\u5f02\u3002\u6240\u6709\u8d44\u6e90\u7c7b\u578b\u90fd\u652f\u6301 metadata.name \u548c metadata.namespace \u5b57\u6bb5\u3002 \u5728\u5b57\u6bb5\u9009\u62e9\u5668\u4e2d\u4f7f\u7528 = , == , \u548c != \u8fd0\u7b97\u7b26( = \u548c == \u8868\u793a\u76f8\u540c\u7684\u610f\u601d)\u3002 \u4f8b\u5982\uff1a kubectl get ingress --field-selector foo.bar = baz kubectl get services --all-namespaces --field-selector metadata.namespace! = default kubectl get pods --field-selector = status.phase! = Running,spec.restartPolicy = Always kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace! = default Finalizers\u662f*\u547d\u540d\u7a7a\u95f4\u952e*\uff0c\u544a\u8bc9Kubernetes\u5728\u6ee1\u8db3\u7279\u5b9a\u6761\u4ef6\u4e4b\u524d\u7b49\u5f85\uff0c\u7136\u540e\u518d\u5b8c\u5168\u5220\u9664\u6807\u8bb0\u4e3a*\u5220\u9664*\u7684\u8d44\u6e90\u3002 Finalizer\u8b66\u544a\u63a7\u5236\u5668controller\u6e05\u7406\u5df2\u5220\u9664\u5bf9\u8c61\u6240\u62e5\u6709\u7684\u8d44\u6e90\u3002 \u901a\u5e38\u56e0\u4e3a\u67d0\u79cd\u76ee\u7684\u4e3a\u8d44\u6e90\u6dfb\u52a0Finalizers\uff0c\u5f3a\u5236\u5220\u9664\u5b83\u4eec\u53ef\u80fd\u4f1a\u5bfc\u81f4\u96c6\u7fa4\u4e2d\u51fa\u73b0\u95ee\u9898\u3002 \u4e0e\u6807\u7b7e\u7c7b\u4f3c\uff0c \u6240\u6709\u8005\u5f15\u7528 \uff08Owner references\uff09\u63cf\u8ff0\u4e86Kubernetes\u4e2d\u5bf9\u8c61\u4e4b\u95f4\u7684\u5173\u7cfb\uff0c\u4f46\u7528\u4e8e\u4e0d\u540c\u7684\u76ee\u7684\u3002 Kubernetes\u4f7f\u7528\u6240\u6709\u8005\u5f15\u7528\uff08\u800c\u4e0d\u662f\u6807\u7b7e\uff09\u6765\u786e\u5b9a\u96c6\u7fa4\u4e2d\u54ea\u4e9bPod\u9700\u8981\u6e05\u7406\u3002 \u5f53Kubernetes\u8bc6\u522b\u5230\u76ee\u6807\u5220\u9664\u7684\u8d44\u6e90\u4e0a\u6709\u6240\u6709\u8005\u5f15\u7528\u65f6\uff0c\u5b83\u4f1a\u5904\u7406Finalizer\u3002 \u6240\u6709\u8005\u548c\u4f9d\u8d56\u5173\u7cfb \u00b6 \u5728 Kubernetes \u4e2d\uff0c\u4e00\u4e9b\u5bf9\u8c61\u62e5\u6709\u5176\u4ed6\u5bf9\u8c61\u3002\u4f8b\u5982\uff0cReplicaSet \u662f\u4e00\u7ec4 Pod \u7684\u6240\u6709\u8005\u3002\u8fd9\u4e9b\u88ab\u62e5\u6709\u7684\u5bf9\u8c61\u662f\u5176\u6240\u6709\u8005\u7684\u4ece\u5c5e\u5bf9\u8c61\u3002 \u4ece\u5c5e\u5bf9\u8c61\u5177\u6709\u4e00\u4e2a metadata.ownerReferences \u5b57\u6bb5\uff0c\u8be5\u5b57\u6bb5\u5f15\u7528\u5176\u6240\u6709\u8005\u5bf9\u8c61\u3002 \u6709\u6548\u7684\u6240\u6709\u8005\u5f15\u7528\u5305\u62ec\u5bf9\u8c61\u540d\u79f0\u548c\u4e0e\u4ece\u5c5e\u5bf9\u8c61\u76f8\u540c\u7684\u547d\u540d\u7a7a\u95f4\u4e2d\u7684 UID\u3002 \u4ece\u5c5e\u5bf9\u8c61\u8fd8\u5177\u6709\u4e00\u4e2a ownerReferences.blockOwnerDeletion \u5b57\u6bb5\uff0c\u8be5\u5b57\u6bb5\u5177\u6709\u5e03\u5c14\u503c\uff0c\u63a7\u5236\u7279\u5b9a\u7684\u4ece\u5c5e\u5bf9\u8c61\u662f\u5426\u53ef\u4ee5\u963b\u6b62\u5783\u573e\u56de\u6536\u5220\u9664\u5176\u6240\u6709\u8005\u5bf9\u8c61\u3002 \u8d44\u6e90 \u00b6 Kubernetes\u8d44\u6e90\u548c\u201c\u610f\u5411\u8bb0\u5f55\u201d\u90fd\u4ee5API\u5bf9\u8c61\u7684\u5f62\u5f0f\u5b58\u50a8\uff0c\u5e76\u901a\u8fc7\u5bf9API\u7684RESTful\u8c03\u7528\u8fdb\u884c\u4fee\u6539\u3002 API\u5141\u8bb8\u4ee5\u58f0\u660e\u6027\u65b9\u5f0f\u7ba1\u7406\u914d\u7f6e\u3002 \u7528\u6237\u53ef\u4ee5\u76f4\u63a5\u4e0eKubernetes API\u4ea4\u4e92\uff0c\u4e5f\u53ef\u4ee5\u901a\u8fc7\u50cfkubectl\u8fd9\u6837\u7684\u5de5\u5177\u8fdb\u884c\u4ea4\u4e92\u3002 \u6838\u5fc3Kubernetes API\u5177\u6709\u7075\u6d3b\u6027\uff0c\u4e5f\u53ef\u4ee5\u6269\u5c55\u4ee5\u652f\u6301\u81ea\u5b9a\u4e49\u8d44\u6e90\u3002 \u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\uff08Workload Resources\uff09 Pod \u3002Pod \u662f\u53ef\u4ee5\u5728\u4e3b\u673a\u4e0a\u8fd0\u884c\u7684\u5bb9\u5668\u96c6\u5408\u3002 PodTemplate \u3002PodTemplate \u63cf\u8ff0\u4e86\u9884\u5b9a\u4e49 pod \u7684\u526f\u672c\u6a21\u677f\u3002 ReplicationController \u3002ReplicationController \u8868\u793a\u4e00\u4e2a\u590d\u5236\u63a7\u5236\u5668\u7684\u914d\u7f6e\u3002 ReplicaSet \u3002ReplicaSet \u786e\u4fdd\u5728\u4efb\u4f55\u7ed9\u5b9a\u65f6\u95f4\u6709\u6307\u5b9a\u6570\u91cf\u7684 pod \u526f\u672c\u6b63\u5728\u8fd0\u884c\u3002 Deployment \u3002Deployment \u4f7f Pod \u548c ReplicaSet \u7684\u58f0\u660e\u6027\u66f4\u65b0\u6210\u4e3a\u53ef\u80fd\u3002 StatefulSet \u3002StatefulSet \u8868\u793a\u5177\u6709\u4e00\u81f4\u6807\u8bc6\u7684 pod \u96c6\u5408\u3002 ControllerRevision \u3002ControllerRevision \u5b9e\u73b0\u4e86\u72b6\u6001\u6570\u636e\u7684\u4e0d\u53ef\u53d8\u5feb\u7167\u3002 DaemonSet \u3002DaemonSet \u8868\u793a\u4e00\u4e2a\u5b88\u62a4\u8fdb\u7a0b\u96c6\u7684\u914d\u7f6e\u3002 Job \u3002Job \u8868\u793a\u5355\u4e2a job \u7684\u914d\u7f6e\u3002 CronJob \u3002CronJob \u8868\u793a\u5355\u4e2a cron job \u7684\u914d\u7f6e\u3002 HorizontalPodAutoscaler \u3002HorizontalPodAutoscaler \u8868\u793a\u6c34\u5e73 pod \u81ea\u52a8\u7f29\u653e\u5668\u7684\u914d\u7f6e\u3002 HorizontalPodAutoscaler v2beta2 \u3002HorizontalPodAutoscaler \u662f\u6c34\u5e73 pod \u81ea\u52a8\u7f29\u653e\u5668\u7684\u914d\u7f6e\uff0c\u6839\u636e\u6307\u5b9a\u7684\u6307\u6807\u81ea\u52a8\u7ba1\u7406\u5b9e\u73b0\u6bd4\u4f8b\u5b50\u8d44\u6e90\u7684\u4efb\u4f55\u8d44\u6e90\u7684\u526f\u672c\u8ba1\u6570\u3002 PriorityClass \u3002PriorityClass \u5b9a\u4e49\u4e86\u4ece\u4f18\u5148\u7ea7\u7c7b\u540d\u79f0\u5230\u4f18\u5148\u7ea7\u6574\u6570\u503c\u7684\u6620\u5c04\u3002 \u670d\u52a1\u8d44\u6e90\uff08Service Resources\uff09 Service . Service \u662f\u5bf9\u8f6f\u4ef6\u670d\u52a1\uff08\u4f8b\u5982mysql\uff09\u7684\u547d\u540d\u62bd\u8c61\uff0c\u7531\u4ee3\u7406\u76d1\u542c\u7684\u672c\u5730\u7aef\u53e3\uff08\u4f8b\u59823306\uff09\u548c\u786e\u5b9a\u54ea\u4e9bPod\u5c06\u56de\u7b54\u901a\u8fc7\u4ee3\u7406\u53d1\u9001\u7684\u8bf7\u6c42\u7684\u9009\u62e9\u5668\u7ec4\u6210\u3002 Endpoints . Endpoints \u662f\u5b9e\u73b0\u5b9e\u9645\u670d\u52a1\u7684\u4e00\u7ec4\u7ec8\u7ed3\u70b9\u3002 EndpointSlice . EndpointSlice \u8868\u793a\u5b9e\u73b0\u670d\u52a1\u7684\u7ec8\u7ed3\u70b9\u7684\u5b50\u96c6\u3002 Ingress . Ingress \u662f\u4e00\u7ec4\u89c4\u5219\uff0c\u5141\u8bb8\u5165\u7ad9\u8fde\u63a5\u5230\u8fbe\u7531\u540e\u7aef\u5b9a\u4e49\u7684\u7ec8\u7ed3\u70b9\u3002 IngressClass . IngressClass \u8868\u793a Ingress \u7684\u7c7b\uff0c\u7531 Ingress Spec \u5f15\u7528\u3002 \u914d\u7f6e\u548c\u5b58\u50a8\u8d44\u6e90\uff08Config and Storage Resources\uff09 ConfigMap \u3002ConfigMap\u4fdd\u5b58\u5bb9\u5668\u9700\u8981\u4f7f\u7528\u7684\u914d\u7f6e\u6570\u636e\u3002 Secret \u3002Secret\u4fdd\u5b58\u7279\u5b9a\u7c7b\u578b\u7684\u673a\u5bc6\u6570\u636e\u3002 Volume \u3002Volume\u8868\u793aPod\u4e2d\u7684\u547d\u540d\u5377\uff0c\u53ef\u4ee5\u88abPod\u4e2d\u7684\u4efb\u4f55\u5bb9\u5668\u8bbf\u95ee\u3002 PersistentVolumeClaim \u3002PersistentVolumeClaim\u662f\u7528\u6237\u5bf9\u6301\u4e45\u5377\u7684\u8bf7\u6c42\u548c\u58f0\u660e\u3002 PersistentVolume \u3002PersistentVolume\uff08PV\uff09\u662f\u7531\u7ba1\u7406\u5458\u63d0\u4f9b\u7684\u5b58\u50a8\u8d44\u6e90\u3002 StorageClass \u3002StorageClass\u63cf\u8ff0\u53ef\u52a8\u6001\u5206\u914dPersistentVolumes\u7684\u5b58\u50a8\u7c7b\u522b\u7684\u53c2\u6570\u3002 VolumeAttachment \u3002VolumeAttachment\u8bb0\u5f55\u5c06\u6307\u5b9a\u7684\u5377\u9644\u52a0\u5230/\u4ece\u6307\u5b9a\u8282\u70b9\u4e2d\u5206\u79bb\u7684\u610f\u56fe\u3002 CSIDriver \u3002CSIDriver\u8bb0\u5f55\u96c6\u7fa4\u4e0a\u90e8\u7f72\u7684\u5bb9\u5668\u5b58\u50a8\u63a5\u53e3\uff08CSI\uff09\u5377\u9a71\u52a8\u7a0b\u5e8f\u7684\u4fe1\u606f\u3002 CSINode \u3002CSINode\u4fdd\u5b58\u6709\u5173\u8282\u70b9\u4e0a\u5b89\u88c5\u7684\u6240\u6709CSI\u9a71\u52a8\u7a0b\u5e8f\u7684\u4fe1\u606f\u3002 CSIStorageCapacity \u3002CSIStorageCapacity\u5b58\u50a8\u4e00\u4e2aCSI GetCapacity\u8c03\u7528\u7684\u7ed3\u679c\u3002 \u8ba4\u8bc1\u8d44\u6e90\uff08Authentication Resources\uff09 ServiceAccount*\u3002ServiceAccount\u548c\u4e0b\u9762\u7684\u4fe1\u606f\u7ed1\u5b9a\u5728\u4e00\u8d77\uff1a \u4e00\u4e2a\u53ef\u88ab\u7528\u6237\u548c\u5468\u8fb9\u7cfb\u7edf\u7406\u89e3\u7684\u540d\u79f0\uff0c\u7528\u4e8e\u8eab\u4efd\u8bc6\u522b \u53ef\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u7684\u4e3b\u4f53 \u4e00\u7ec4\u5bc6\u94a5\u3002 TokenRequest*\u3002TokenRequest\u4e3a\u7ed9\u5b9a\u7684ServiceAccount\u8bf7\u6c42\u4e00\u4e2a\u4ee4\u724c\u3002 TokenReview*\u3002TokenReview\u5c1d\u8bd5\u5bf9\u5df2\u77e5\u7528\u6237\u7684\u4ee4\u724c\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u3002 CertificateSigningRequest*\u3002CertificateSigningRequest\u5bf9\u8c61\u63d0\u4f9b\u4e86\u4e00\u79cd\u901a\u8fc7\u63d0\u4ea4\u8bc1\u4e66\u7b7e\u540d\u8bf7\u6c42\u5e76\u5f02\u6b65\u6279\u51c6\u548c\u53d1\u653e\u6765\u83b7\u53d6x509\u8bc1\u4e66\u7684\u673a\u5236\u3002 \u6388\u6743\u8d44\u6e90\uff08Authorization Resources\uff09 LocalSubjectAccessReview*\u3002LocalSubjectAccessReview\u68c0\u67e5\u4e00\u4e2a\u7528\u6237\u6216\u7ec4\u5728\u7ed9\u5b9a\u547d\u540d\u7a7a\u95f4\u4e2d\u662f\u5426\u80fd\u6267\u884c\u67d0\u4e2a\u64cd\u4f5c\u3002 SelfSubjectAccessReview*\u3002SelfSubjectAccessReview\u68c0\u67e5\u5f53\u524d\u7528\u6237\u662f\u5426\u80fd\u6267\u884c\u67d0\u4e2a\u64cd\u4f5c\u3002 SelfSubjectRulesReview*\u3002SelfSubjectRulesReview\u679a\u4e3e\u5f53\u524d\u7528\u6237\u5728\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4\u5185\u53ef\u4ee5\u6267\u884c\u7684\u64cd\u4f5c\u96c6\u5408\u3002 SubjectAccessReview*\u3002SubjectAccessReview\u68c0\u67e5\u4e00\u4e2a\u7528\u6237\u6216\u7ec4\u662f\u5426\u80fd\u6267\u884c\u67d0\u4e2a\u64cd\u4f5c\u3002 ClusterRole*\u3002ClusterRole\u662f\u4e00\u4e2a\u96c6\u7fa4\u7ea7\u522b\u7684PolicyRules\u903b\u8f91\u5206\u7ec4\uff0c\u53ef\u4ee5\u88abRoleBinding\u6216ClusterRoleBinding\u5f15\u7528\u4e3a\u4e00\u4e2a\u5355\u5143\u3002 ClusterRoleBinding*\u3002ClusterRoleBinding\u5f15\u7528\u4e00\u4e2aClusterRole\uff0c\u4f46\u4e0d\u5305\u542b\u5b83\u3002 Role*\u3002Role\u662f\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4\u7ea7\u522b\u7684PolicyRules\u903b\u8f91\u5206\u7ec4\uff0c\u53ef\u4ee5\u88abRoleBinding\u5f15\u7528\u4e3a\u4e00\u4e2a\u5355\u5143\u3002 RoleBinding*\u3002RoleBinding\u5f15\u7528\u4e00\u4e2aRole\uff0c\u4f46\u4e0d\u5305\u542b\u5b83\u3002 \u7b56\u7565\u8d44\u6e90\uff08Policy Resources\uff09 LimitRange*\u3002LimitRange\u4e3a\u547d\u540d\u7a7a\u95f4\u4e2d\u6bcf\u79cd\u8d44\u6e90\u8bbe\u7f6e\u8d44\u6e90\u4f7f\u7528\u9650\u5236\u3002 ResourceQuota*\u3002ResourceQuota\u8bbe\u7f6e\u6bcf\u4e2a\u547d\u540d\u7a7a\u95f4\u5f3a\u5236\u6267\u884c\u7684\u603b\u914d\u989d\u9650\u5236\u3002 NetworkPolicy*\u3002NetworkPolicy\u63cf\u8ff0\u4e86\u4e00\u7ec4Pod\u5141\u8bb8\u7684\u7f51\u7edc\u6d41\u91cf\u3002 PodDisruptionBudget*\u3002PodDisruptionBudget\u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u7528\u4e8e\u5b9a\u4e49\u5bf9\u4e00\u7ec4Pod\u53ef\u80fd\u9020\u6210\u7684\u6700\u5927\u4e2d\u65ad\u3002 PodSecurityPolicy v1beta1*\u3002PodSecurityPolicy\u63a7\u5236\u5bf9\u53ef\u80fd\u5f71\u54cd\u5c06\u5e94\u7528\u4e8ePod\u548c\u5bb9\u5668\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\u7684\u8bf7\u6c42\u7684\u80fd\u529b\u3002 \u6269\u5c55\u8d44\u6e90\uff08Extend Resources\uff09 CustomResourceDefinition*\u3002CustomResourceDefinition\u8868\u793a\u5e94\u5728API\u670d\u52a1\u5668\u4e0a\u516c\u5f00\u7684\u8d44\u6e90\u3002 MutatingWebhookConfiguration*\u3002MutatingWebhookConfiguration\u63cf\u8ff0\u63a5\u53d7\u6216\u62d2\u7edd\u5e76\u53ef\u80fd\u66f4\u6539\u5bf9\u8c61\u7684\u51c6\u5165Webhook\u7684\u914d\u7f6e\u3002 ValidatingWebhookConfiguration*\u3002ValidatingWebhookConfiguration\u63cf\u8ff0\u63a5\u53d7\u6216\u62d2\u7edd\u5bf9\u8c61\u4f46\u4e0d\u66f4\u6539\u5bf9\u8c61\u7684\u51c6\u5165Webhook\u7684\u914d\u7f6e\u3002 \u96c6\u7fa4\u8d44\u6e90\uff08Cluster Resources\uff09 Node*\u3002Node\u662fKubernetes\u4e2d\u7684\u5de5\u4f5c\u8282\u70b9\u3002 Namespace*\u3002Namespace\u4e3a\u540d\u79f0\u63d0\u4f9b\u4e86\u4f5c\u7528\u57df\u3002 Event*\u3002Event\u662f\u5bf9\u96c6\u7fa4\u4e2d\u67d0\u4e2a\u4f4d\u7f6e\u53d1\u751f\u4e8b\u4ef6\u7684\u62a5\u544a\u3002 APIService*\u3002APIService\u8868\u793a\u7279\u5b9aGroupVersion\u7684\u670d\u52a1\u5668\u3002 Lease*\u3002Lease\u5b9a\u4e49\u4e86\u79df\u8d41\u7684\u6982\u5ff5\u3002 RuntimeClass*\u3002RuntimeClass\u5b9a\u4e49\u4e86\u96c6\u7fa4\u4e2d\u652f\u6301\u7684\u5bb9\u5668\u8fd0\u884c\u65f6\u7c7b\u3002 FlowSchema v1beta2*\u3002FlowSchema\u5b9a\u4e49\u4e86\u4e00\u7ec4\u6d41\u7a0b\u7684\u67b6\u6784\u3002 PriorityLevelConfiguration v1beta2*\u3002PriorityLevelConfiguration\u8868\u793a\u4f18\u5148\u7ea7\u7ea7\u522b\u7684\u914d\u7f6e\u3002 Binding*\u3002Binding\u5c06\u4e00\u4e2a\u5bf9\u8c61\u7ed1\u5b9a\u5230\u53e6\u4e00\u4e2a\u5bf9\u8c61\uff1b\u4f8b\u5982\uff0c\u8c03\u5ea6\u7a0b\u5e8f\u5c06Pod\u7ed1\u5b9a\u5230\u8282\u70b9\u4e0a\u3002 ComponentStatus*\u3002ComponentStatus\uff08\u548cComponentStatusList\uff09\u4fdd\u5b58\u96c6\u7fa4\u9a8c\u8bc1\u4fe1\u606f\u3002 \u4f7f\u7528\u547d\u4ee4 kube api-resources \u83b7\u53d6\u652f\u6301\u7684API\u8d44\u6e90\u3002 \u4f7f\u7528\u547d\u4ee4 kubectl explain RESOURCE [options] \u63cf\u8ff0\u4e0e\u6bcf\u4e2a\u652f\u6301\u7684API\u8d44\u6e90\u76f8\u5173\u8054\u7684\u5b57\u6bb5\u3002\u8fd9\u4e9b\u5b57\u6bb5\u53ef\u4ee5\u901a\u8fc7\u7b80\u5355\u7684JSONPath\u6807\u8bc6\u7b26\u8fdb\u884c\u8bc6\u522b\uff1a kubectl explain binding kubectl explain binding.metadata kubectl explain binding.metadata.name \u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90 \u00b6 Pods \u00b6 Pod\u662fKubernetes\u4e2d\u53ef\u521b\u5efa\u548c\u7ba1\u7406\u7684\u6700\u5c0f\u90e8\u7f72\u8ba1\u7b97\u5355\u4f4d\u3002 Pod\u662f\u4e00\u4e2a\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u5bb9\u5668\u3001\u5171\u4eab\u5b58\u50a8\u548c\u7f51\u7edc\u8d44\u6e90\u4ee5\u53ca\u5982\u4f55\u8fd0\u884c\u5bb9\u5668\u7684\u89c4\u8303\u7684\u7ec4\u3002 Pod\u7684\u5185\u5bb9\u59cb\u7ec8\u5171\u540c\u5b9a\u4f4d\u548c\u5171\u540c\u5b89\u6392\uff0c\u5e76\u5728\u5171\u4eab\u73af\u5883\u4e2d\u8fd0\u884c\u3002 Pod\u6a21\u62df\u4e86\u4e00\u4e2a\u7279\u5b9a\u4e8e\u5e94\u7528\u7a0b\u5e8f\u7684\u201c\u903b\u8f91\u4e3b\u673a\u201d\uff1a\u5b83\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u76f8\u5bf9\u7d27\u5bc6\u8026\u5408\u7684\u5e94\u7528\u7a0b\u5e8f\u5bb9\u5668\u3002 \u5728\u975e\u4e91\u73af\u5883\u4e2d\uff0c\u540c\u4e00\u7269\u7406\u6216\u865a\u62df\u673a\u4e0a\u6267\u884c\u7684\u5e94\u7528\u7a0b\u5e8f\u7c7b\u4f3c\u4e8e\u5728\u540c\u4e00\u903b\u8f91\u4e3b\u673a\u4e0a\u6267\u884c\u7684\u4e91\u5e94\u7528\u7a0b\u5e8f\u3002 Pod\u7684\u5171\u4eab\u73af\u5883\u662f\u4e00\u7ec4Linux\u547d\u540d\u7a7a\u95f4\u3001cgroups\u548c\u53ef\u80fd\u7684\u5176\u4ed6\u9694\u79bb\u8981\u7d20 - \u8fd9\u4e9b\u8981\u7d20\u4e0e\u9694\u79bbDocker\u5bb9\u5668\u7684\u65b9\u5f0f\u76f8\u540c\u3002 \u5728Docker\u6982\u5ff5\u65b9\u9762\uff0cPod\u7c7b\u4f3c\u4e8e\u5177\u6709\u5171\u4eab\u547d\u540d\u7a7a\u95f4\u548c\u5171\u4eab\u6587\u4ef6\u7cfb\u7edf\u5377\u7684\u4e00\u7ec4Docker\u5bb9\u5668\u3002 \u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u751a\u81f3\u662f\u5355\u4f8bPod\uff0c\u6211\u4eec\u90fd\u4e0d\u9700\u8981\u76f4\u63a5\u521b\u5efaPod\uff0c\u800c\u662f\u4f7f\u7528\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\uff0c\u4f8b\u5982*Deployment*\u6216*Job*\u6765\u521b\u5efa\u5b83\u4eec\u3002\u5982\u679cPod\u9700\u8981\u8ddf\u8e2a\u72b6\u6001\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528StatefulSet\u8d44\u6e90\u3002 Kubernetes\u96c6\u7fa4\u4e2d\u7684Pod\u6709\u4e24\u79cd\u4e3b\u8981\u7528\u6cd5\uff1a \u8fd0\u884c\u5355\u4e2a\u5bb9\u5668\u7684Pod\u3002 \u8fd0\u884c\u9700\u8981\u5171\u540c\u5de5\u4f5c\u7684\u591a\u4e2a\u5bb9\u5668\u7684Pod\u3002 \u201c\u6bcf\u4e2aPod\u4e00\u4e2a\u5bb9\u5668\u201d\u7684\u6a21\u578b\u662f\u6700\u5e38\u89c1\u7684Kubernetes\u7528\u4f8b\uff1b\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\u53ef\u4ee5\u5c06Pod\u89c6\u4e3a\u5355\u4e2a\u5bb9\u5668\u7684\u5305\u88c5\u5668\uff1bKubernetes\u7ba1\u7406Pod\u800c\u4e0d\u662f\u76f4\u63a5\u7ba1\u7406\u5bb9\u5668\u3002 \u4e00\u4e2aPod\u53ef\u4ee5\u5c01\u88c5\u7531\u591a\u4e2a\u5171\u540c\u5b9a\u4f4d\u3001\u7d27\u5bc6\u8026\u5408\u4e14\u9700\u8981\u5171\u4eab\u8d44\u6e90\u7684\u5bb9\u5668\u7ec4\u6210\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 \u8fd9\u4e9b\u5171\u540c\u5b9a\u4f4d\u7684\u5bb9\u5668\u5f62\u6210\u4e00\u4e2a\u5355\u4e00\u7684\u670d\u52a1\u6574\u4f53\u5355\u5143 - \u4f8b\u5982\uff0c\u4e00\u4e2a\u5bb9\u5668\u5411\u516c\u4f17\u63d0\u4f9b\u5b58\u50a8\u5728\u5171\u4eab\u5377\u4e2d\u7684\u6570\u636e\uff0c\u800c\u53e6\u4e00\u4e2a\u72ec\u7acb\u7684Sidecar\u5bb9\u5668\u5237\u65b0\u6216\u66f4\u65b0\u8fd9\u4e9b\u6587\u4ef6\u3002Pod\u5c06\u8fd9\u4e9b\u5bb9\u5668\u3001\u5b58\u50a8\u8d44\u6e90\u548c\u77ed\u6682\u7684\u7f51\u7edc\u6807\u8bc6\u5305\u88c5\u5728\u4e00\u8d77\uff0c\u4f5c\u4e3a\u4e00\u4e2a\u5355\u72ec\u7684\u5355\u4f4d\u3002 \u5728\u5355\u4e2aPod\u4e2d\u5206\u7ec4\u591a\u4e2a\u5171\u540c\u5b9a\u4f4d\u548c\u5171\u540c\u7ba1\u7406\u7684\u5bb9\u5668\u662f\u76f8\u5bf9\u9ad8\u7ea7\u7684\u7528\u4f8b\u3002\u5e94\u8be5*\u4ec5\u5728*\u5bb9\u5668\u7d27\u5bc6\u8026\u5408\u7684\u7279\u5b9a\u60c5\u51b5\u4e0b\u4f7f\u7528\u6b64\u6a21\u5f0f\u3002 \u6bcf\u4e2aPod\u90fd\u65e8\u5728\u8fd0\u884c\u7ed9\u5b9a\u5e94\u7528\u7a0b\u5e8f\u7684\u5355\u4e2a\u5b9e\u4f8b\u3002\u5982\u679c\u6211\u4eec\u60f3\u6c34\u5e73\u6269\u5c55\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\uff08\u901a\u8fc7\u8fd0\u884c\u66f4\u591a\u5b9e\u4f8b\u63d0\u4f9b\u66f4\u591a\u7684\u603b\u8d44\u6e90\uff09\uff0c\u5219\u5e94\u8be5\u4f7f\u7528\u591a\u4e2aPod\uff0c\u6bcf\u4e2a\u5b9e\u4f8b\u4e00\u4e2aPod\u3002\u5728Kubernetes\u4e2d\uff0c\u8fd9\u901a\u5e38\u79f0\u4e3a*\u590d\u5236*\u3002\u590d\u5236\u7684Pod\u901a\u5e38\u4f5c\u4e3a\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\u53ca\u5176\u63a7\u5236\u5668\u7684\u4e00\u7ec4\u521b\u5efa\u548c\u7ba1\u7406\u3002 Pod\u672c\u5730\u63d0\u4f9b\u4e24\u79cd\u5171\u4eab\u8d44\u6e90\u4ee5\u4f9b\u5176\u7ec4\u6210\u5bb9\u5668\u4f7f\u7528\uff1a \u7f51\u7edc *\u548c \u5b58\u50a8 *\u3002 \u4e00\u4e2aPod\u53ef\u4ee5\u6307\u5b9a\u4e00\u7ec4\u5171\u4eab\u7684\u5b58\u50a8\u5377\u3002Pod\u4e2d\u7684\u6240\u6709\u5bb9\u5668\u90fd\u53ef\u4ee5\u8bbf\u95ee\u8fd9\u4e9b\u5171\u4eab\u5377\uff0c\u4f7f\u8fd9\u4e9b\u5bb9\u5668\u53ef\u4ee5\u5171\u4eab\u6570\u636e\u3002 \u6bcf\u4e2aPod\u4e3a\u6bcf\u4e2a\u5730\u5740\u65cf\u5206\u914d\u4e00\u4e2a\u552f\u4e00\u7684IP\u5730\u5740\u3002 \u5728\u4e00\u4e2aPod\u5185\uff0c\u5bb9\u5668\u5171\u4eab\u4e00\u4e2aIP\u5730\u5740\u548c\u7aef\u53e3\u7a7a\u95f4\uff0c\u5e76\u53ef\u4ee5\u901a\u8fc7\u201clocalhost\u201d\u627e\u5230\u5f7c\u6b64\u3002\u60f3\u8981\u4e0e\u8fd0\u884c\u5728\u4e0d\u540cPod\u4e2d\u7684\u5bb9\u5668\u4ea4\u4e92\u7684\u5bb9\u5668\u53ef\u4ee5\u4f7f\u7528IP\u7f51\u7edc\u8fdb\u884c\u901a\u4fe1\u3002 \u5f53\u521b\u5efa\u4e00\u4e2aPod\u65f6\uff0c\u65b0\u7684Pod\u88ab\u8c03\u5ea6\u5728\u96c6\u7fa4\u4e2d\u7684\u4e00\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u3002Pod\u4fdd\u7559\u5728\u8be5\u8282\u70b9\u4e0a\uff0c\u76f4\u5230Pod\u6267\u884c\u5b8c\u6bd5\u3001Pod\u5bf9\u8c61\u88ab\u5220\u9664\u3001Pod\u56e0\u7f3a\u4e4f\u8d44\u6e90\u800c\u88ab\u9a71\u9010\u6216\u8282\u70b9\u53d1\u751f\u6545\u969c\u3002 \u5728Pod\u4e2d\u91cd\u65b0\u542f\u52a8\u4e00\u4e2a\u5bb9\u5668\u4e0d\u5e94\u4e0e\u91cd\u65b0\u542f\u52a8\u4e00\u4e2aPod\u6df7\u6dc6\u3002Pod\u4e0d\u662f\u4e00\u4e2a\u8fdb\u7a0b\uff0c\u800c\u662f\u4e00\u4e2a\u8fd0\u884c\u5bb9\u5668\u7684\u73af\u5883\u3002Pod\u4f1a\u4e00\u76f4\u4fdd\u7559\uff0c\u76f4\u5230\u88ab\u5220\u9664\u4e3a\u6b62\u3002 \u60a8\u53ef\u4ee5\u4f7f\u7528\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\uff08\u4f8b\u5982Deployment\u3001StatefulSet\u3001DaemonSet\uff09\u4e3a\u81ea\u5df1\u521b\u5efa\u548c\u7ba1\u7406\u591a\u4e2aPod\u3002\u8d44\u6e90\u7684\u63a7\u5236\u5668\u5904\u7406\u590d\u5236\u3001\u6eda\u52a8\u548c\u5728Pod\u5931\u8d25\u65f6\u7684\u81ea\u52a8\u6062\u590d\u3002 \u521d\u59cb\u5316\u5bb9\u5668 \u00b6 \u4e00\u4e9bPod\u8fd8\u6709\u521d\u59cb\u5316\u5bb9\u5668\uff08Init containers\uff09\u548c\u5e94\u7528\u5bb9\u5668\uff08app containers\uff09\u3002\u521d\u59cb\u5316\u5bb9\u5668\u5728\u5e94\u7528\u5bb9\u5668\u542f\u52a8\u4e4b\u524d\u8fd0\u884c\u5e76\u5b8c\u6210\u3002 \u6211\u4eec\u53ef\u4ee5\u5728Pod\u89c4\u8303\u4e2d\u6307\u5b9a\u521d\u59cb\u5316\u5bb9\u5668\uff0c\u540c\u65f6\u4e5f\u53ef\u4ee5\u5728\u5bb9\u5668\u6570\u7ec4\u4e2d\u63cf\u8ff0\u5e94\u7528\u5bb9\u5668\u3002 \u9759\u6001Pod \u00b6 \u9759\u6001Pod\u662f\u76f4\u63a5\u7531\u7279\u5b9a\u8282\u70b9\u4e0a\u7684kubelet\u5b88\u62a4\u7a0b\u5e8f\u7ba1\u7406\u7684\uff0cAPI\u670d\u52a1\u5668\u4e0d\u4f1a\u89c2\u5bdf\u5b83\u4eec\u3002 \u9759\u6001Pod\u59cb\u7ec8\u7ed1\u5b9a\u5230\u7279\u5b9a\u8282\u70b9\u4e0a\u7684\u4e00\u4e2aKubelet\u3002 \u9759\u6001Pod\u7684\u4e3b\u8981\u7528\u9014\u662f\u8fd0\u884c\u81ea\u6258\u7ba1\u63a7\u5236\u9762\u677f\uff1a\u6362\u53e5\u8bdd\u8bf4\uff0c\u4f7f\u7528kubelet\u76d1\u7763\u5404\u4e2a\u63a7\u5236\u9762\u677f\u7ec4\u4ef6\u3002 kubelet\u4f1a\u81ea\u52a8\u5c1d\u8bd5\u4e3a\u6bcf\u4e2a\u9759\u6001Pod\u5728Kubernetes API\u670d\u52a1\u5668\u4e0a\u521b\u5efa\u4e00\u4e2a\u955c\u50cfPod\u3002\u8fd9\u610f\u5473\u7740\u5728\u8282\u70b9\u4e0a\u8fd0\u884c\u7684Pod\u5728API\u670d\u52a1\u5668\u4e0a\u53ef\u89c1\uff0c\u4f46\u65e0\u6cd5\u4ece\u90a3\u91cc\u63a7\u5236\u3002 \u5bb9\u5668\u63a2\u9488 \u00b6 \u63a2\u9488\u662f kubelet \u5b9a\u671f\u5bf9\u5bb9\u5668\u6267\u884c\u7684\u4e00\u79cd\u8bca\u65ad\u3002 \u4e3a\u6267\u884c\u8bca\u65ad\uff0ckubelet \u8981\u4e48\u5728\u5bb9\u5668\u5185\u6267\u884c\u4ee3\u7801\uff0c\u8981\u4e48\u53d1\u8d77\u7f51\u7edc\u8bf7\u6c42\u3002 \u4f7f\u7528\u63a2\u9488\u6709\u56db\u79cd\u4e0d\u540c\u7684\u68c0\u67e5\u5bb9\u5668\u65b9\u5f0f\u3002\u6bcf\u4e2a\u63a2\u9488\u5fc5\u987b\u6070\u597d\u5b9a\u4e49\u8fd9\u56db\u79cd\u673a\u5236\u4e2d\u7684\u4e00\u79cd\uff1a exec \u3002\u5982\u679c\u547d\u4ee4\u4ee5\u72b6\u6001\u4ee3\u7801 0 \u9000\u51fa\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 grpc \u3002\u5982\u679c\u54cd\u5e94\u7684\u72b6\u6001\u4e3a SERVING\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 httpGet \u3002\u5982\u679c\u54cd\u5e94\u7684\u72b6\u6001\u4ee3\u7801\u5927\u4e8e\u6216\u7b49\u4e8e 200 \u4e14\u5c0f\u4e8e 400\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 tcpSocket \u3002\u5982\u679c\u7aef\u53e3\u5f00\u653e\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 \u6bcf\u4e2a\u63a2\u9488\u6709\u4e09\u79cd\u7ed3\u679c\uff1a \u6210\u529f \u5931\u8d25 \u672a\u77e5 \u63a2\u9488\u7c7b\u578b\uff1a livenessProbe \u3002\u6307\u793a\u5bb9\u5668\u662f\u5426\u6b63\u5728\u8fd0\u884c\u3002 readinessProbe \u3002\u6307\u793a\u5bb9\u5668\u662f\u5426\u51c6\u5907\u597d\u54cd\u5e94\u8bf7\u6c42\u3002 startupProbe \u3002\u6307\u793a\u5bb9\u5668\u5185\u7684\u5e94\u7528\u7a0b\u5e8f\u662f\u5426\u542f\u52a8\u3002 Deployment \u00b6 ReplicaSet \u00b6 ReplicaSet\u7684\u76ee\u7684\u662f\u5728\u4efb\u4f55\u65f6\u5019\u7ef4\u62a4\u4e00\u7ec4\u7a33\u5b9a\u7684\u526f\u672cPod\u3002\u56e0\u6b64\uff0c\u5b83\u901a\u5e38\u7528\u4e8e\u4fdd\u8bc1\u6307\u5b9a\u6570\u91cf\u7684\u76f8\u540cPod\u7684\u53ef\u7528\u6027\u3002 \u6211\u4eec\u4e00\u822c\u4e0d\u9700\u8981\u76f4\u63a5\u64cd\u7eb5ReplicaSet\u5bf9\u8c61\uff1a\u4f7f\u7528Deployment\uff0c\u7136\u540e\u5728spec\u90e8\u5206\u4e2d\u5b9a\u4e49\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 \u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e replicaset.spec.replicas \u6765\u6307\u5b9a\u5e94\u540c\u65f6\u8fd0\u884c\u591a\u5c11\u4e2aPod\u3002 ReplicaSet\u5c06\u521b\u5efa/\u5220\u9664\u5176Pod\u4ee5\u5339\u914d\u6b64\u6570\u5b57\u3002 \u5982\u679c\u4e0d\u6307\u5b9a replicaset.spec.replicas \uff0c\u5219\u9ed8\u8ba4\u503c\u4e3a 1 \u3002 StatefulSet \u00b6 StatefulSet \u7279\u70b9\uff08\u53c8\u79f0\u56fa\u5b9a\u6807\u8bc6\uff09\uff1a Pod \u7684\u540d\u79f0\u5728\u521b\u5efa\u540e\u4e0d\u53ef\u53d8\u3002 DNS \u4e3b\u673a\u540d\u5728\u521b\u5efa\u540e\u4e0d\u53ef\u53d8\u3002 \u6302\u8f7d\u7684\u5377\u5728\u521b\u5efa\u540e\u4e0d\u53ef\u53d8\u3002 StatefulSet \u7684\u56fa\u5b9a\u6807\u8bc6\u5728\u5931\u8d25\u3001\u6269\u5c55\u548c\u5176\u4ed6\u64cd\u4f5c\u540e\u4e0d\u4f1a\u6539\u53d8\u3002 StatefulSet \u7684\u547d\u540d\u7ea6\u5b9a\u4e3a\uff1a - \u3002 StatefulSet \u53ef\u4ee5\u81ea\u884c\u8fdb\u884c\u6269\u5c55\uff0c\u4f46\u662f Deployment \u9700\u8981\u4f9d\u9760 ReplicaSet \u8fdb\u884c\u6269\u5c55\u3002 \u5efa\u8bae\uff1a\u5148\u5c06 StatefulSet \u51cf\u5c11\u5230 0\uff0c\u800c\u4e0d\u662f\u76f4\u63a5\u5220\u9664\u5b83\u3002 headless Service \u548c governing Service\uff1a Headless Service \u662f\u4e00\u4e2a\u666e\u901a\u7684 Kubernetes Service \u5bf9\u8c61\uff0c\u5176 spec.clusterIP \u88ab\u8bbe\u7f6e\u4e3a None \u3002 \u5f53 StatefulSet \u7684 spec.ServiceName \u8bbe\u7f6e\u4e3a headless Service \u540d\u79f0\u65f6\uff0cStatefulSet \u73b0\u5728\u662f\u4e00\u4e2a governing Service\u3002 \u521b\u5efa StatefulSet \u7684\u4e00\u822c\u8fc7\u7a0b\uff1a \u521b\u5efa StorageClass\u3002 \u521b\u5efa Headless Service\u3002 \u57fa\u4e8e\u4e0a\u8ff0\u4e24\u4e2a\u521b\u5efa StatefulSet\u3002 DaemonSet \u00b6 DaemonSet\u4fdd\u8bc1\u6240\u6709\uff08\u6216\u90e8\u5206\uff09\u8282\u70b9\u8fd0\u884cPod\u7684\u526f\u672c\u3002\u968f\u7740\u8282\u70b9\u4ece\u96c6\u7fa4\u4e2d\u5220\u9664\uff0c\u8fd9\u4e9bPod\u5c06\u88ab\u5783\u573e\u56de\u6536\u3002 \u5220\u9664DaemonSet\u5c06\u6e05\u7406\u5b83\u521b\u5efa\u7684Pod\u3002 \u4e00\u4e9b\u5178\u578bDaemonSet\u7684\u7528\u9014\u5305\u62ec\uff1a \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u96c6\u7fa4\u5b58\u50a8\u5b88\u62a4\u7a0b\u5e8f\u3002 \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u65e5\u5fd7\u6536\u96c6\u5b88\u62a4\u7a0b\u5e8f\u3002 \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u8282\u70b9\u76d1\u89c6\u5b88\u62a4\u7a0b\u5e8f\u3002 \u5728\u7b80\u5355\u7684\u60c5\u51b5\u4e0b\uff0c\u6bcf\u79cd\u7c7b\u578b\u7684\u5b88\u62a4\u7a0b\u5e8f\u5c06\u4f7f\u7528\u8986\u76d6\u6240\u6709\u8282\u70b9\u7684\u4e00\u4e2aDaemonSet\u3002 \u66f4\u590d\u6742\u7684\u8bbe\u7f6e\u53ef\u80fd\u4f1a\u4e3a\u5355\u4e2a\u5b88\u62a4\u7a0b\u5e8f\u4f7f\u7528\u591a\u4e2aDaemonSet\uff0c\u4f46\u4f7f\u7528\u4e0d\u540c\u7684\u6807\u5fd7\u548c/\u6216\u4e0d\u540c\u7684\u5185\u5b58\u548cCPU\u8bf7\u6c42\u6765\u652f\u6301\u4e0d\u540c\u7684\u786c\u4ef6\u7c7b\u578b\u3002 DaemonSet\u63a7\u5236\u5668\u8c03\u548c\u8fc7\u7a0b\u540c\u65f6\u68c0\u67e5\u73b0\u6709\u8282\u70b9\u548c\u65b0\u521b\u5efa\u7684\u8282\u70b9\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cKubernetes\u8c03\u5ea6\u7a0b\u5e8f\u5ffd\u7565\u7531DamonSet\u521b\u5efa\u7684Pod\uff0c\u5e76\u5141\u8bb8\u5b83\u4eec\u5b58\u5728\u4e8e\u8282\u70b9\u4e0a\uff0c\u76f4\u5230\u5173\u95ed\u8282\u70b9\u672c\u8eab\u3002 \u5728\u9009\u62e9\u8282\u70b9\u4e0a\u8fd0\u884cPod\uff1a \u5982\u679c\u60a8\u6307\u5b9a daemonset.spec.template.spec.nodeSelector \uff0c\u90a3\u4e48DaemonSet\u63a7\u5236\u5668\u5c06\u5728\u4e0e\u8be5\u8282\u70b9\u9009\u62e9\u5668\u5339\u914d\u7684\u8282\u70b9\u4e0a\u521b\u5efaPod\u3002 \u5982\u679c\u60a8\u6307\u5b9a daemonset.spec.template.spec.affinity \uff0c\u90a3\u4e48DaemonSet\u63a7\u5236\u5668\u5c06\u5728\u4e0e\u8be5\u8282\u70b9\u4eb2\u548c\u529b\u5339\u914d\u7684\u8282\u70b9\u4e0a\u521b\u5efaPod\u3002 \u5982\u679c\u4e24\u8005\u90fd\u4e0d\u6307\u5b9a\uff0c\u5219DaemonSet\u63a7\u5236\u5668\u5c06\u5728\u6240\u6709\u8282\u70b9\u4e0a\u521b\u5efaPod\u3002 \u5728 kubectl explain daemonset.spec \u4e2d\u6ca1\u6709 replicas \u5b57\u6bb5\u4e0e kubectl explain deployment.spec.replicas \u76f8\u5bf9\u5e94\u3002\u5f53\u521b\u5efa\u4e00\u4e2aDaemonSet\u65f6\uff0c\u6bcf\u4e2a\u8282\u70b9\u5c06\u8fd0\u884c*\u4e00\u4e2a* DaemonSet Pod\u3002 \u5bf9\u4e8e\u670d\u52a1\uff0c\u901a\u5e38\u662f\u65e0\u72b6\u6001\u7684\uff0c\u4e00\u822c\u4e0d\u5173\u5fc3\u8282\u70b9\u5728\u54ea\u91cc\u8fd0\u884c\uff0c\u66f4\u5173\u5fc3Pod\u526f\u672c\u7684\u6570\u91cf\uff0c\u5e76\u4e14\u6211\u4eec\u53ef\u4ee5\u5c06\u8fd9\u4e9b\u526f\u672c/replicas\u7f29\u653e\u3002\u5728\u8fd9\u91cc\uff0c\u6eda\u52a8\u66f4\u65b0\u4e5f\u5c06\u662f\u4e00\u4e2a\u4f18\u70b9\u3002 \u5f53Pod\u7684\u4e00\u4e2a\u526f\u672c\u5fc5\u987b\u5728\u67d0\u4e2a\u6307\u5b9a\u8282\u70b9\u4e0a\u8fd0\u884c\u65f6\uff0c\u6211\u4eec\u5c06\u4f7f\u7528 DaemonSet \u3002\u6211\u4eec\u7684\u5b88\u62a4\u8fdb\u7a0bPod\u8fd8\u9700\u8981\u5728\u6211\u4eec\u7684\u5176\u4ed6Pod\u4e4b\u524d\u542f\u52a8\u3002 DaemonSet\u662f\u7528\u4e8e\u540e\u53f0\u670d\u52a1\u7684\u7b80\u5355\u53ef\u6269\u5c55\u6027\u7b56\u7565\u3002\u5f53\u66f4\u591a\u7684\u5408\u9002\u7684\u8282\u70b9\u6dfb\u52a0\u5230\u96c6\u7fa4\u65f6\uff0c\u540e\u53f0\u670d\u52a1\u5c06\u6269\u5c55\u3002\u5f53\u8282\u70b9\u88ab\u5220\u9664\u65f6\uff0c\u5b83\u5c06\u81ea\u52a8\u7f29\u5c0f\u3002 Job \u00b6 CronJob \u00b6 \u670d\u52a1\u8d44\u6e90 \u00b6 Service \u00b6 Service\u662f\u8f6f\u4ef6\u670d\u52a1\uff08\u4f8b\u5982mysql\uff09\u7684\u547d\u540d\u62bd\u8c61\uff0c\u7531\u4ee3\u7406\u76d1\u542c\u7684\u672c\u5730\u7aef\u53e3\uff08\u4f8b\u59823306\uff09\u548c\u786e\u5b9a\u54ea\u4e9bPod\u5c06\u56de\u7b54\u901a\u8fc7\u4ee3\u7406\u53d1\u9001\u7684\u8bf7\u6c42\u7684\u9009\u62e9\u5668\u7ec4\u6210\u3002 \u4e00\u4e2aService\u7684\u76ee\u6807Pod\u96c6\u5408\u901a\u5e38\u7531\u4e00\u4e2a\u9009\u62e9\u5668\uff08\u6807\u7b7e\u9009\u62e9\u5668\uff09\u6765\u786e\u5b9a\u3002 Service\u8d44\u6e90\u7684\u7c7b\u578b\u5305\u62ec\uff1a ClusterIP Service\uff08\u9ed8\u8ba4\uff09\uff1a\u53ef\u9760\u7684IP\u3001DNS\u548c\u7aef\u53e3\u3002\u4ec5\u9650\u5185\u90e8\u8bbf\u95ee\u3002 NodePort Service\uff1a\u5411\u5916\u90e8\u63d0\u4f9b\u8bbf\u95ee\u3002 LoadBalancer\uff1a\u57fa\u4e8eNodePort\uff0c\u5e76\u4e0e\u4e91\u4f9b\u5e94\u5546\u63d0\u4f9b\u7684\u8d1f\u8f7d\u5e73\u8861\u96c6\u6210\uff08\u4f8b\u5982AWS\u3001GCP\u7b49\uff09\u3002 ExternalName\uff1a\u8bbf\u95ee\u5c06\u88ab\u8f6c\u53d1\u5230\u5916\u90e8\u670d\u52a1\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u521b\u5efa\u7b80\u5355Service\u7684yaml\u6587\u4ef6\uff1a apiVersion : v1 kind : Service metadata : name : nginx-service labels : tier : application spec : ports : - port : 80 protocol : TCP targetPort : 8080 selector : run : nginx type : NodePort \u4e0b\u9762\u662f\u4e00\u4e2aService\u7684\u4f8b\u5b50\uff1a IP 10.96.17.77 \u662f\u8be5\u670d\u52a1\u7684 ClusterIP(VIP)\u3002 \u7aef\u53e3 80/TCP \u662f Pod \u5728\u96c6\u7fa4\u5185\u76d1\u542c\u7684\u7aef\u53e3\u3002 TargetPort 8080/TCP \u662f\u5bb9\u5668\u5185\u670d\u52a1\u5e94\u8be5\u5b9a\u5411\u6d41\u91cf\u5230\u8fbe\u7684\u7aef\u53e3\u3002 NodePort 31893/TCP \u662f\u53ef\u4ee5\u4ece\u5916\u90e8\u8bbf\u95ee\u7684\u7aef\u53e3\u3002\u9ed8\u8ba4\u8303\u56f4\u662f 30000~32767 \u3002\u8be5\u7aef\u53e3\u4f1a\u5728\u6574\u4e2a\u96c6\u7fa4\u7684\u6240\u6709\u8282\u70b9\u4e0a\u66b4\u9732\u3002 Endpoints \u663e\u793a\u4e86\u5339\u914d\u670d\u52a1\u6807\u7b7e\u7684 Pod \u5217\u8868\u3002 Name : nginx-deployment Namespace : jh-namespace Labels : tier=application Annotations : Selector : run=nginx Type : NodePort IP Family Policy : SingleStack IP Families : IPv4 IP : 10.96.17.77 IPs : 10.96.17.77 Port : 80/TCP TargetPort : 8080/TCP NodePort : 31893/TCP Endpoints : 10.244.1.177:8080,10.244.1.178:8080,10.244.1.179:8080 + 7 more... Session Affinity : None External Traffic Policy : Cluster Events : \u5728 Kubernetes \u96c6\u7fa4\u4e2d\uff0c\u57fa\u4e8eDeployment coredns \u7684Service kube-dns \u63d0\u4f9b\u4e86\u96c6\u7fa4 DNS \u670d\u52a1\u3002 \u670d\u52a1\u6ce8\u518c\uff1a Kubernetes \u4f7f\u7528\u96c6\u7fa4 DNS \u4f5c\u4e3a\u670d\u52a1\u6ce8\u518c\u3002 \u6ce8\u518c\u662f\u57fa\u4e8e Service \u800c\u975e Pod \u7684\u3002 \u96c6\u7fa4 DNS\uff08CoreDNS\uff09\u4e3b\u52a8\u76d1\u89c6\u548c\u53d1\u73b0\u65b0\u670d\u52a1\u3002 Service \u540d\u79f0\u3001IP\u3001\u7aef\u53e3\u5c06\u88ab\u6ce8\u518c\u3002 Service \u6ce8\u518c\u7684\u8fc7\u7a0b\u5982\u4e0b\uff1a \u5c06\u65b0\u7684 Service POST \u5230 API Server\u3002 \u4e3a\u65b0\u7684 Service \u5206\u914d ClusterIP\u3002 \u5c06\u65b0\u7684 Service \u914d\u7f6e\u4fe1\u606f\u4fdd\u5b58\u5230 etcd \u4e2d\u3002 \u521b\u5efa\u4e0e\u65b0 Service \u5173\u8054\u7684\u5e26\u6709\u76f8\u5173 Pod IP \u7684 endpoints\u3002 \u901a\u8fc7 ClusterDNS \u63a2\u7d22\u65b0\u7684 Service\u3002 \u521b\u5efa DNS \u4fe1\u606f\u3002 kube-proxy \u83b7\u53d6 Service \u914d\u7f6e\u4fe1\u606f\u3002 \u521b\u5efa IPSV \u89c4\u5219\u3002 Service \u53d1\u73b0\u7684\u8fc7\u7a0b\u3002 \u8bf7\u6c42\u4e00\u4e2a Service \u540d\u79f0\u7684 DNS \u540d\u79f0\u89e3\u6790\u3002 \u6536\u5230 ClusterIP\u3002 \u8bbf\u95ee ClusterIP\u3002 \u6ca1\u6709\u8def\u7531\u5668\u3002\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230 Pod \u7684\u9ed8\u8ba4\u7f51\u5173\u3002 \u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u8282\u70b9\u3002 \u6ca1\u6709\u8def\u7531\u5668\u3002\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u8282\u70b9\u7684\u9ed8\u8ba4\u7f51\u5173\u3002 \u8282\u70b9\u5185\u6838\u7ee7\u7eed\u5904\u7406\u8bf7\u6c42\u3002 \u4f7f\u7528 IPSV \u89c4\u5219\u6355\u83b7\u8bf7\u6c42\u3002 \u5c06\u76ee\u6807 Pod \u7684 IP \u653e\u5165\u8bf7\u6c42\u7684\u76ee\u6807 IP \u4e2d\u3002 \u8bf7\u6c42\u5230\u8fbe\u76ee\u6807 Pod\u3002 FQDN\u683c\u5f0f\u4e3a\uff1a ..svc.cluster.local \u3002\u6211\u4eec\u79f0 \u4e3a\u975e\u9650\u5b9a\u540d\u79f0\u6216\u7b80\u77ed\u540d\u79f0\u3002 \u547d\u540d\u7a7a\u95f4\u53ef\u4ee5\u9694\u79bb\u96c6\u7fa4\u7684\u5730\u5740\u7a7a\u95f4\u3002\u540c\u65f6\uff0c\u5b83\u8fd8\u53ef\u4ee5\u7528\u4e8e\u5b9e\u73b0\u8bbf\u95ee\u63a7\u5236\u548c\u8d44\u6e90\u914d\u989d\u3002 \u83b7\u53d6Pod\u4e2d\u7684DNS\u914d\u7f6e\u3002 nameserver\u7684IP\u4e0ekube-dns\u670d\u52a1\u7684ClusterIP\u76f8\u540c\uff0c\u8fd9\u662f\u7528\u4e8eDNS\u8bf7\u6c42\u6216\u670d\u52a1\u53d1\u73b0\u8bf7\u6c42\u7684\u4f17\u6240\u5468\u77e5\u7684IP\u3002 $ kubectl get service kube-dns -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT ( S ) AGE kube-dns ClusterIP 10 .96.0.10 53 /UDP,53/TCP,9153/TCP 7d7h $ kubectl exec -it nginx-5f5496dc9-bv5dx -- /bin/bash root@nginx-5f5496dc9-bv5dx:/# cat /etc/resolv.conf search jh-namespace.svc.cluster.local svc.cluster.local cluster.local nameserver 10 .96.0.10 options ndots:5 \u8bfb\u53d6 kube-dns \u4fe1\u606f\uff1a $ kubectl describe service kube-dns -n kube-system Name: kube-dns Namespace: kube-system Labels: k8s-app = kube-dns kubernetes.io/cluster-service = true kubernetes.io/name = CoreDNS Annotations: prometheus.io/port: 9153 prometheus.io/scrape: true Selector: k8s-app = kube-dns Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: 10 .96.0.10 IPs: 10 .96.0.10 Port: dns 53 /UDP TargetPort: 53 /UDP Endpoints: 10 .244.0.2:53,10.244.0.3:53 Port: dns-tcp 53 /TCP TargetPort: 53 /TCP Endpoints: 10 .244.0.2:53,10.244.0.3:53 Port: metrics 9153 /TCP TargetPort: 9153 /TCP Endpoints: 10 .244.0.2:9153,10.244.0.3:9153 Session Affinity: None Events: Endpoints \u00b6 Endpoints\u662f\u4e00\u7ec4\u5b9e\u73b0\u5b9e\u9645\u670d\u52a1\u7684\u7aef\u70b9\u96c6\u5408\u3002 \u5f53\u521b\u5efa\u670d\u52a1\u65f6\uff0c\u5b83\u4f1a\u4e0e\u4e00\u4e2aEndpoint\u5bf9\u8c61\u76f8\u5173\u8054\uff0c\u53ef\u4ee5\u4f7f\u7528\u547d\u4ee4 kubectl get endpoints \u83b7\u53d6\u3002 \u5339\u914d\u670d\u52a1\u6807\u7b7e\u7684Pod\u5217\u8868\u7ef4\u62a4\u4e3aEndpoint\u5bf9\u8c61\uff0c\u6dfb\u52a0\u65b0\u7684\u5339\u914dPod\u5e76\u5220\u9664\u4e0d\u5339\u914d\u7684Pod\u3002 \u914d\u7f6e\u548c\u5b58\u50a8\u8d44\u6e90 \u00b6 \u5377 \u00b6 emptyDir \u00b6 emptyDir \u5377\u662f\u5728Pod\u5206\u914d\u5230\u8282\u70b9\u65f6\u9996\u5148\u521b\u5efa\u7684\uff0c\u5e76\u4e14\u53ea\u8981\u8be5Pod\u5728\u8be5\u8282\u70b9\u4e0a\u8fd0\u884c\uff0c\u5b83\u5c31\u4f1a\u5b58\u5728\u3002 emptyDir \u5377\u6700\u521d\u4e3a\u7a7a\u3002 Pod\u4e2d\u7684\u6240\u6709\u5bb9\u5668\u90fd\u53ef\u4ee5\u8bfb\u53d6\u548c\u5199\u5165 emptyDir \u5377\u4e2d\u7684\u76f8\u540c\u6587\u4ef6\uff0c\u5c3d\u7ba1\u8be5\u5377\u53ef\u4ee5\u5728\u6bcf\u4e2a\u5bb9\u5668\u4e2d\u4ee5\u76f8\u540c\u6216\u4e0d\u540c\u7684\u8def\u5f84\u6302\u8f7d\u3002 \u5f53\u7531\u4e8e\u4efb\u4f55\u539f\u56e0\u4ece\u8282\u70b9\u4e2d\u5220\u9664Pod\u65f6\uff0c emptyDir \u4e2d\u7684\u6570\u636e\u5c06\u6c38\u4e45\u5220\u9664\u3002 \u5bb9\u5668\u5d29\u6e83\u4e0d\u4f1a\u5c06Pod\u4ece\u8282\u70b9\u4e2d\u5220\u9664\u3002 emptyDir \u5377\u4e2d\u7684\u6570\u636e\u53ef\u4ee5\u5728\u5bb9\u5668\u5d29\u6e83\u65f6\u5b89\u5168\u4fdd\u7559\u3002 \u7528\u9014\uff1a \u4e34\u65f6\u7a7a\u95f4\uff0c\u4f8b\u5982\u57fa\u4e8e\u78c1\u76d8\u7684\u5f52\u5e76\u6392\u5e8f \u4e3a\u4e86\u4ece\u5d29\u6e83\u4e2d\u6062\u590d\u800c\u8fdb\u884c\u7684\u957f\u65f6\u95f4\u8ba1\u7b97\u7684\u68c0\u67e5\u70b9 \u4fdd\u5b58\u5185\u5bb9\u7ba1\u7406\u5668\u5bb9\u5668\u63d0\u53d6\u7684\u6587\u4ef6\uff0c\u540c\u65f6Web\u670d\u52a1\u5668\u5bb9\u5668\u63d0\u4f9b\u6570\u636e hostPath \u00b6 hostPath \u5377\u5c06\u4e3b\u673a\u8282\u70b9\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u6302\u8f7d\u5230 Pod \u4e2d\u3002\u8fd9\u4e0d\u662f\u5927\u591a\u6570 Pod \u90fd\u9700\u8981\u7684\uff0c\u4f46\u5bf9\u4e8e\u67d0\u4e9b\u5e94\u7528\u7a0b\u5e8f\u6765\u8bf4\uff0c\u5b83\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5f3a\u5927\u7684\u9003\u751f\u53e3\u3002 hostPath \u5377\u5b58\u5728\u8bb8\u591a\u5b89\u5168\u98ce\u9669\uff0c\u56e0\u6b64\u5728\u53ef\u80fd\u7684\u60c5\u51b5\u4e0b\u6700\u597d\u907f\u514d\u4f7f\u7528 HostPath\u3002\u5f53\u5fc5\u987b\u4f7f\u7528 HostPath \u5377\u65f6\uff0c\u5e94\u5c06\u5176\u8303\u56f4\u9650\u5b9a\u4e3a\u4ec5\u6240\u9700\u7684\u6587\u4ef6\u6216\u76ee\u5f55\uff0c\u5e76\u4ee5\u53ea\u8bfb\u65b9\u5f0f\u6302\u8f7d\u3002 \u5982\u679c\u901a\u8fc7 AdmissionPolicy \u9650\u5236 HostPath \u8bbf\u95ee\u7279\u5b9a\u76ee\u5f55\uff0c\u5219\u5fc5\u987b\u8981\u6c42 volumeMounts \u4f7f\u7528 readOnly \u6302\u8f7d\uff0c\u4ee5\u4f7f\u7b56\u7565\u751f\u6548\u3002 \u7528\u9014\uff1a \u4e0e DaemonSet \u4e00\u8d77\u8fd0\u884c\uff0c\u4f8b\u5982\uff0cEFK Fluentd \u6302\u8f7d\u672c\u5730\u4e3b\u673a\u7684\u65e5\u5fd7\u76ee\u5f55\u4ee5\u6536\u96c6\u4e3b\u673a\u65e5\u5fd7\u4fe1\u606f\u3002 \u901a\u8fc7\u4f7f\u7528 hostPath \u5377\u5728\u7279\u5b9a\u8282\u70b9\u4e0a\u8fd0\u884c\uff0c\u53ef\u4ee5\u83b7\u5f97\u9ad8\u6027\u80fd\u7684\u78c1\u76d8 I/O\u3002 \u8fd0\u884c\u9700\u8981\u8bbf\u95ee Docker \u5185\u90e8\u7684\u5bb9\u5668\uff1b\u4f7f\u7528 /var/lib/docker \u7684 hostPath\u3002 \u5728\u5bb9\u5668\u4e2d\u8fd0\u884c cAdvisor\uff1b\u4f7f\u7528 /sys \u7684 hostPath\u3002 \u5141\u8bb8 Pod \u6307\u5b9a\u7ed9\u5b9a\u7684 hostPath \u662f\u5426\u5e94\u8be5\u5728 Pod \u8fd0\u884c\u4e4b\u524d\u5b58\u5728\uff0c\u662f\u5426\u5e94\u8be5\u521b\u5efa\u5b83\u4ee5\u53ca\u5b83\u5e94\u8be5\u5b58\u5728\u7684\u5185\u5bb9\u3002 Storage Class \u00b6 StorageClass \u90e8\u7f72\u548c\u5b9e\u73b0\u7684\u6b65\u9aa4\u5982\u4e0b\uff1a \u521b\u5efa Kubernetes \u96c6\u7fa4\u548c\u540e\u7aef\u5b58\u50a8\u3002 \u786e\u4fdd Kubernetes \u4e2d\u7684 provisioner/plugin \u53ef\u7528\u3002 \u521b\u5efa\u4e00\u4e2a StorageClass \u5bf9\u8c61\u5e76\u5c06\u5176\u94fe\u63a5\u5230\u540e\u7aef\u5b58\u50a8\u3002StorageClass \u5c06\u81ea\u52a8\u521b\u5efa\u76f8\u5173\u7684 PV\u3002 \u521b\u5efa\u4e00\u4e2a PVC \u5bf9\u8c61\u5e76\u5c06\u5176\u94fe\u63a5\u5230\u6211\u4eec\u521b\u5efa\u7684 StorageClass\u3002 \u90e8\u7f72\u4e00\u4e2a Pod \u5e76\u4f7f\u7528 PVC \u5377\u3002 PV \u00b6 PV\u56de\u6536\u7b56\u7565\uff1a \u4fdd\u7559 (Retain) \u5220\u9664 (Delete) \u56de\u6536 (Recycle) PV in-tree\u7c7b\u578b\uff1a hostPath local NFS CSI Access Modes \u00b6 Access Modes\uff08\u8bbf\u95ee\u6a21\u5f0f\uff09\u4e2d\uff0c spec.accessModes \u5b9a\u4e49\u4e86 PV \u7684\u6302\u8f7d\u9009\u9879\uff1a ReadWriteOnce(RWO)\uff1a\u4e00\u4e2a PV \u53ea\u80fd\u88ab\u4e00\u4e2a\u8bfb\u5199\u6a21\u5f0f\u7684 PVC \u6302\u8f7d\uff0c\u7c7b\u4f3c\u4e8e\u5757\u8bbe\u5907\u3002 ReadWriteMany(RWM)\uff1a\u4e00\u4e2a PV \u53ef\u4ee5\u88ab\u591a\u4e2a\u8bfb\u5199\u6a21\u5f0f\u7684 PVC \u6302\u8f7d\uff0c\u4f8b\u5982 NFS\u3002 ReadOnlyMany(ROM)\uff1a\u4e00\u4e2a PV \u53ef\u4ee5\u88ab\u591a\u4e2a\u53ea\u8bfb\u6a21\u5f0f\u7684 PVC \u6302\u8f7d\u3002 ReadWriteOncePod(RWOP)\uff1a\u53ea\u652f\u6301 CSI \u7c7b\u578b\u7684 PV\uff0c\u53ea\u80fd\u88ab\u5355\u4e2a Pod \u6302\u8f7d\u3002 \u4e00\u4e2a PV \u53ea\u80fd\u8bbe\u7f6e\u4e00\u79cd\u9009\u9879\u3002Pod \u6302\u8f7d PVC\uff0c\u800c\u4e0d\u662f PV\u3002","title":"Kubernetes\u968f\u7b14"},{"location":"k8s/cka_cn/foundamentals/memo/#cka5kubernetes","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb05:Kubernetes\u968f\u7b14"},{"location":"k8s/cka_cn/foundamentals/memo/#_1","text":"\u8fb9\u7ec3\u4e60\u8fb9\u8bb0\u5f55\u7684\u5185\u5bb9\uff0c\u4e0d\u662f\u5168\u9762\u7cfb\u7edf\u7684\uff0c\u5305\u62ec\u4e0b\u9762\u4e3b\u8981\u5185\u5bb9\uff1a Kubernetes\u57fa\u672c\u6982\u5ff5 \u7ec4\u4ef6 API \u5bf9\u8c61 \u8d44\u6e90 \u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90 Pod Deployment ReplicaSet StatefulSet DaemonSet Job CronJob \u670d\u52a1\u8d44\u6e90 Service Endpoints \u914d\u7f6e\u548c\u5b58\u50a8\u8d44\u6e90 \u5377 Storage Class PV Access Modes","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/memo/#kubernetes","text":"","title":"Kubernetes\u57fa\u672c\u6982\u5ff5"},{"location":"k8s/cka_cn/foundamentals/memo/#kubernetes_1","text":"\u4e00\u4e2aKubernetes\u96c6\u7fa4\u7531\u4ee3\u8868\u63a7\u5236\u5e73\u9762\uff08control plane\uff09\u7684\u7ec4\u4ef6\u548c\u4e00\u7ec4\u79f0\u4e3a\u8282\u70b9\uff08nodes\uff09\u7684\u673a\u5668\u7ec4\u6210\u3002 Kubernetes\u7ec4\u4ef6: \u63a7\u5236\u5e73\u9762\u7ec4\u4ef6 Control Plane Components kube-apiserver: \u67e5\u8be2\u548c\u64cd\u4f5c Kubernetes \u4e2d\u5bf9\u8c61\u7684\u72b6\u6001\u3002 \u5145\u5f53\u6240\u6709\u8d44\u6e90\u4e4b\u95f4\u7684\u901a\u4fe1\u4e2d\u5fc3\uff08communication hub\uff09\u3002 \u63d0\u4f9b\u96c6\u7fa4\u5b89\u5168\u8eab\u4efd\u9a8c\u8bc1\u3001\u6388\u6743\u548c\u89d2\u8272\u5206\u914d\u3002 \u662f\u552f\u4e00\u80fd\u8fde\u63a5\u5230 etcd \u7684\u7ec4\u4ef6\u3002 etcd: \u6240\u6709 Kubernetes \u5bf9\u8c61\u90fd\u5b58\u50a8\u5728 etcd \u4e2d\u3002 Kubernetes \u5bf9\u8c61\u662f Kubernetes \u7cfb\u7edf\u4e2d\u7684\u6301\u4e45\u5b9e\u4f53(entities)\uff0c\u7528\u4e8e\u8868\u793a\u96c6\u7fa4\u7684\u72b6\u6001\u3002 kube-scheduler: \u76d1\u89c6\u6ca1\u6709\u5206\u914d\u8282\u70b9\u7684\u65b0\u521b\u5efa\u7684 Pod\uff0c\u5e76\u4e3a\u5b83\u4eec\u9009\u62e9\u4e00\u4e2a\u8282\u70b9\u6765\u8fd0\u884c\u3002 kube-controller-manager: \u8fd0\u884c\u63a7\u5236\u5668\u8fdb\u7a0b\u3002 Node controller : \u8d1f\u8d23\u8b66\u793a\u548c\u54cd\u5e94\u8282\u70b9\u7684\u6545\u969c\u3002 Job controller : \u76d1\u89c6\u8868\u793a\u4e00\u6b21\u6027\u4efb\u52a1\u7684 Job \u5bf9\u8c61\uff0c\u7136\u540e\u521b\u5efa Pod \u6765\u5b8c\u6210\u8fd9\u4e9b\u4efb\u52a1\u3002 Endpoints controller : \u586b\u5145 Endpoints \u5bf9\u8c61\uff08\u5373\u5c06 Service \u548c Pod \u8fde\u63a5\u8d77\u6765\uff09\u3002 Service Account & Token controllers : \u4e3a\u65b0\u547d\u540d\u7a7a\u95f4\u521b\u5efa\u9ed8\u8ba4\u5e10\u6237\u548c API \u8bbf\u95ee\u4ee4\u724c\u3002 cloud-controller-manager: \u5d4c\u5165\u4e91\u7279\u5b9a\u7684\u63a7\u5236\u903b\u8f91\uff0c\u4ec5\u8fd0\u884c\u7279\u5b9a\u4e8e\u6211\u4eec\u9009\u62e9\u7684\u4e91\u63d0\u4f9b\u5546\u7684\u63a7\u5236\u5668\uff0c\u65e0\u9700\u81ea\u5df1\u7684\u57fa\u7840\u8bbe\u65bd\u548c\u5b66\u4e60\u73af\u5883\u3002 Node controller : \u7528\u4e8e\u68c0\u67e5\u4e91\u63d0\u4f9b\u5546\uff0c\u4ee5\u786e\u5b9a\u8282\u70b9\u5728\u5728\u5b83\u505c\u6b62\u54cd\u5e94\u540e\u662f\u5426\u5df2\u5728\u4e91\u4e2d\u88ab\u5220\u9664\u3002 Route controller : \u7528\u4e8e\u5728\u5e95\u5c42\u4e91\u57fa\u7840\u67b6\u6784\u4e2d\u8bbe\u7f6e\u8def\u7531\u3002 Service controller : \u7528\u4e8e\u521b\u5efa\u3001\u66f4\u65b0\u548c\u5220\u9664\u4e91\u63d0\u4f9b\u5546\u8d1f\u8f7d\u5747\u8861\u5668\u3002 \u8282\u70b9\u7ec4\u4ef6 Node Components kubelet: \u5728\u96c6\u7fa4\u4e2d\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u7684\u4ee3\u7406\u3002 \u7ba1\u7406\u8282\u70b9\u3002\u5b83\u786e\u4fdd Pod \u4e2d\u8fd0\u884c\u5bb9\u5668\u3002 kubelet \u5411 APIServer \u6ce8\u518c\u548c\u66f4\u65b0\u8282\u70b9\u4fe1\u606f\uff0cAPIServer \u5c06\u5b83\u4eec\u5b58\u50a8\u5230 etcd \u4e2d\u3002 \u7ba1\u7406 Pod\u3002\u901a\u8fc7 APIServer \u76d1\u89c6 Pod\uff0c\u5e76\u5bf9 Pod \u6216 Pod \u4e2d\u7684\u5bb9\u5668\u91c7\u53d6\u884c\u52a8\u3002 \u5728\u5bb9\u5668\u7ea7\u522b\u8fdb\u884c\u5065\u5eb7\u68c0\u67e5\u3002 kube-proxy: \u662f\u5728\u96c6\u7fa4\u4e2d\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u7684\u7f51\u7edc\u4ee3\u7406\u3002 iptables ipvs \u7ef4\u62a4\u8282\u70b9\u4e0a\u7684\u7f51\u7edc\u89c4\u5219\u3002 \u5bb9\u5668\u8fd0\u884c\u65f6Container runtime\uff1a \u8d1f\u8d23\u8fd0\u884c\u5bb9\u5668\u7684\u8f6f\u4ef6\u3002 \u63d2\u4ef6Addons DNS: \u662f DNS \u670d\u52a1\u5668\uff0c\u662f\u6240\u6709 Kubernetes \u96c6\u7fa4\u6240\u5fc5\u9700\u7684\u3002 Web UI\uff08\u4eea\u8868\u76d8\uff09\uff1a\u7528\u4e8e Kubernetes \u96c6\u7fa4\u7684\u57fa\u4e8e Web \u7684\u7528\u6237\u754c\u9762\u3002 \u5bb9\u5668\u8d44\u6e90\u76d1\u63a7\uff1a\u8bb0\u5f55\u6709\u5173\u96c6\u4e2d\u5f0f\u6570\u636e\u5e93\u4e2d\u5bb9\u5668\u7684\u901a\u7528\u65f6\u95f4\u5e8f\u5217\u5ea6\u91cf\u3002 Cluster-level Logging\uff1a\u8d1f\u8d23\u5c06\u5bb9\u5668\u65e5\u5fd7\u4fdd\u5b58\u5230\u5177\u6709\u641c\u7d22/\u6d4f\u89c8\u63a5\u53e3\u7684\u4e2d\u592e\u65e5\u5fd7\u5b58\u50a8\u4e2d\u3002 \u53ef\u6269\u5c55\u6027\uff1a \u6c34\u5e73\u6269\u5c55\uff08Scaling out\uff09\u901a\u8fc7\u6dfb\u52a0\u66f4\u591a\u7684\u670d\u52a1\u5668\u5230\u67b6\u6784\u4e2d\uff0c\u5c06\u5de5\u4f5c\u8d1f\u8f7d\u5206\u6563\u5230\u66f4\u591a\u7684\u673a\u5668\u4e0a\u3002 \u5782\u76f4\u6269\u5c55\uff08Scaling up\uff09\u901a\u8fc7\u6dfb\u52a0\u66f4\u591a\u7684\u786c\u76d8\u548c\u5185\u5b58\u6765\u589e\u52a0\u7269\u7406\u670d\u52a1\u5668\u7684\u8ba1\u7b97\u80fd\u529b\u3002","title":"Kubernetes\u7ec4\u4ef6"},{"location":"k8s/cka_cn/foundamentals/memo/#kubernetes-api","text":"REST API\u662fKubernetes\u7684\u57fa\u672c\u6846\u67b6\u3002\u6240\u6709\u7ec4\u4ef6\u4e4b\u95f4\u7684\u64cd\u4f5c\u548c\u901a\u4fe1\uff0c\u4ee5\u53ca\u5916\u90e8\u7528\u6237\u547d\u4ee4\u90fd\u662f\u7531API\u670d\u52a1\u5668\u5904\u7406\u7684REST API\u8c03\u7528\u3002\u56e0\u6b64\uff0cKubernetes\u5e73\u53f0\u4e2d\u7684\u6240\u6709\u5185\u5bb9\u90fd\u88ab\u89c6\u4e3aAPI\u5bf9\u8c61\uff08API object\uff09\uff0c\u5e76\u5728API\u4e2d\u6709\u76f8\u5e94\u7684\u6761\u76ee\u3002 Kubernetes\u63a7\u5236\u5e73\u9762\u7684\u6838\u5fc3\u662fAPI\u670d\u52a1\u5668\u3002 CRI\uff1a\u5bb9\u5668\u8fd0\u884c\u65f6\u63a5\u53e3 CNI\uff1a\u5bb9\u5668\u7f51\u7edc\u63a5\u53e3 CSI\uff1a\u5bb9\u5668\u5b58\u50a8\u63a5\u53e3 API\u670d\u52a1\u5668\u516c\u5f00\u4e86\u4e00\u4e2aHTTP API\uff0c\u5141\u8bb8\u6700\u7ec8\u7528\u6237\u3001\u96c6\u7fa4\u7684\u4e0d\u540c\u90e8\u5206\u548c\u5916\u90e8\u7ec4\u4ef6\u5f7c\u6b64\u901a\u4fe1\u3002 Kubernetes API\u5141\u8bb8\u6211\u4eec\u67e5\u8be2\u548c\u64cd\u4f5cKubernetes\u4e2dAPI\u5bf9\u8c61\u7684\u72b6\u6001\uff08\u4f8b\u5982\uff1aPod\u3001Namespace\u3001ConfigMap\u548cEvent\uff09\u3002 Kubernetes API\uff1a OpenAPI\u89c4\u8303 OpenAPI V2 OpenAPI V3 \u6301\u4e45\u6027\u3002Kubernetes\u901a\u8fc7\u5c06\u5bf9\u8c61\u7684\u5e8f\u5217\u5316\u72b6\u6001\u5199\u5165etcd\u6765\u5b58\u50a8\u5b83\u4eec\u3002 API\u7ec4\u548c\u7248\u672c\u63a7\u5236\u3002\u7248\u672c\u63a7\u5236\u662f\u5728API\u7ea7\u522b\u8fdb\u884c\u7684\u3002API\u8d44\u6e90\u901a\u8fc7\u5b83\u4eec\u7684API\u7ec4\u3001\u8d44\u6e90\u7c7b\u578b\u3001\u547d\u540d\u7a7a\u95f4\uff08\u7528\u4e8e\u547d\u540d\u7a7a\u95f4\u8d44\u6e90\uff09\u548c\u540d\u79f0\u8fdb\u884c\u533a\u5206\u3002 API\u66f4\u6539 API\u6269\u5c55","title":"Kubernetes API"},{"location":"k8s/cka_cn/foundamentals/memo/#api-version","text":"API\u7248\u672c\u548c\u8f6f\u4ef6\u7248\u672c\u95f4\u5b58\u5728\u95f4\u63a5\u5173\u7cfb\u3002API\u548c\u53d1\u5e03\u7248\u672c\u8ba1\u5212\u63cf\u8ff0\u4e86API\u7248\u672c\u548c\u8f6f\u4ef6\u7248\u672c\u4e4b\u95f4\u7684\u5173\u7cfb\u3002\u4e0d\u540c\u7684API\u7248\u672c\u8868\u793a\u4e0d\u540c\u7684\u7a33\u5b9a\u6027\u548c\u652f\u6301\u7ea7\u522b\u3002 \u4ee5\u4e0b\u662f\u6bcf\u4e2a\u7ea7\u522b\u7684\u6458\u8981\uff1a Alpha\uff1a \u7248\u672c\u540d\u79f0\u5305\u542balpha\uff08\u4f8b\u5982\uff0cv1alpha1\uff09\u3002 \u8f6f\u4ef6\u53ef\u80fd\u5305\u542b\u9519\u8bef\u3002\u542f\u7528\u529f\u80fd\u53ef\u80fd\u4f1a\u66b4\u9732\u9519\u8bef\u3002\u67d0\u4e9b\u529f\u80fd\u53ef\u80fd\u9ed8\u8ba4\u7981\u7528\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u529f\u80fd\u7684\u652f\u6301\u53ef\u4ee5\u968f\u65f6\u53d6\u6d88\uff0c\u800c\u4e0d\u4f1a\u63d0\u524d\u901a\u77e5\u3002 API\u53ef\u80fd\u4f1a\u5728\u4ee5\u540e\u7684\u8f6f\u4ef6\u53d1\u5e03\u4e2d\u4ee5\u4e0d\u517c\u5bb9\u7684\u65b9\u5f0f\u66f4\u6539\uff0c\u800c\u4e0d\u4f1a\u63d0\u524d\u901a\u77e5\u3002 \u7531\u4e8e\u9519\u8bef\u98ce\u9669\u589e\u52a0\u548c\u957f\u671f\u652f\u6301\u4e0d\u8db3\uff0c\u5efa\u8bae\u4ec5\u5728\u77ed\u6682\u7684\u6d4b\u8bd5\u96c6\u7fa4\u4e2d\u4f7f\u7528\u8be5\u8f6f\u4ef6\u3002 Beta\uff1a \u7248\u672c\u540d\u79f0\u5305\u542bbeta\uff08\u4f8b\u5982\uff0cv2beta3\uff09\u3002 \u8f6f\u4ef6\u7ecf\u8fc7\u5145\u5206\u6d4b\u8bd5\u3002\u542f\u7528\u529f\u80fd\u88ab\u8ba4\u4e3a\u662f\u5b89\u5168\u7684\u3002\u67d0\u4e9b\u529f\u80fd\u9ed8\u8ba4\u542f\u7528\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u529f\u80fd\u7684\u652f\u6301\u4e0d\u4f1a\u53d6\u6d88\uff0c\u4f46\u7ec6\u8282\u53ef\u80fd\u4f1a\u66f4\u6539\u3002 \u5bf9\u8c61\u7684\u6a21\u5f0f\u548c/\u6216\u8bed\u4e49\u53ef\u80fd\u4f1a\u5728\u540e\u7eed\u7684Beta\u6216\u7a33\u5b9a\u7248\u53d1\u5e03\u4e2d\u4ee5\u4e0d\u517c\u5bb9\u7684\u65b9\u5f0f\u66f4\u6539\u3002\u5f53\u53d1\u751f\u8fd9\u79cd\u60c5\u51b5\u65f6\uff0c\u5c06\u63d0\u4f9b\u8fc1\u79fb\u8bf4\u660e\u3002\u6a21\u5f0f\u66f4\u6539\u53ef\u80fd\u9700\u8981\u5220\u9664\u3001\u7f16\u8f91\u548c\u91cd\u65b0\u521b\u5efa API\u5bf9\u8c61\u3002\u7f16\u8f91\u8fc7\u7a0b\u53ef\u80fd\u4e0d\u7b80\u5355\u3002\u8fc1\u79fb\u53ef\u80fd\u9700\u8981\u505c\u673a\uff0c\u4ee5\u4fbf\u4f9d\u8d56\u4e8e\u8be5\u529f\u80fd\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 \u4e0d\u5efa\u8bae\u5c06\u8be5\u8f6f\u4ef6\u7528\u4e8e\u751f\u4ea7\u7528\u9014\u3002\u540e\u7eed\u7684\u53d1\u5e03\u53ef\u80fd\u4f1a\u5f15\u5165\u4e0d\u517c\u5bb9\u7684\u66f4\u6539\u3002\u5982\u679c\u60a8\u6709\u591a\u4e2a\u53ef\u4ee5\u72ec\u7acb\u5347\u7ea7\u7684\u96c6\u7fa4\uff0c\u5219\u53ef\u4ee5\u653e\u5bbd\u6b64\u9650\u5236\u3002 \u6ce8\u610f\uff1a\u8bf7\u5c1d\u8bd5beta\u529f\u80fd\u5e76\u63d0\u4f9b\u53cd\u9988\u3002\u529f\u80fd\u9000\u51fabeta\u540e\uff0c\u53ef\u80fd\u4e0d\u5b9e\u9645\u518d\u8fdb\u884c\u66f4\u6539\u3002 \u7a33\u5b9a\u7248\uff1a \u7248\u672c\u540d\u79f0\u4e3avX\uff0c\u5176\u4e2dX\u662f\u6574\u6570\u3002 \u529f\u80fd\u7684\u7a33\u5b9a\u7248\u672c\u51fa\u73b0\u5728\u53d1\u5e03\u7684\u8f6f\u4ef6\u4e2d\u7684\u8bb8\u591a\u540e\u7eed\u7248\u672c\u4e2d\u3002 \u8bfb\u53d6\u5f53\u524dAPI\u7684\u7248\u672c\u547d\u4ee4\uff1a kubectl api-resources","title":"API Version"},{"location":"k8s/cka_cn/foundamentals/memo/#api-group","text":"API\u7ec4\uff08API groups\uff09 \u4f7f\u6269\u5c55Kubernetes API\u66f4\u52a0\u5bb9\u6613\u3002API\u7ec4\u5728REST\u8def\u5f84\u548c\u5e8f\u5217\u5316\u5bf9\u8c61\u7684apiVersion\u5b57\u6bb5\u4e2d\u6307\u5b9a\u3002 Kubernetes\u6709\u51e0\u4e2aAPI\u7ec4\uff1a \u6838\u5fc3\u7ec4\uff08\u4e5f\u79f0\u4e3a\u9057\u7559legacy\uff09\u4f4d\u4e8eREST\u8def\u5f84 /api/v1 \u3002 \u6838\u5fc3\u7ec4\u4e0d\u4f5c\u4e3aapiVersion\u5b57\u6bb5\u7684\u4e00\u90e8\u5206\u6307\u5b9a\uff0c\u4f8b\u5982 apiVersion: v1\u3002 \u547d\u540d\u7ec4\u4f4d\u4e8eREST\u8def\u5f84 /apis/$GROUP_NAME/$VERSION \uff0c\u5e76\u4f7f\u7528 apiVersion: $GROUP_NAME/$VERSION \uff08\u4f8b\u5982 apiVersion: batch/v1\uff09\u3002","title":"API Group"},{"location":"k8s/cka_cn/foundamentals/memo/#kubernetes_2","text":"","title":"Kubernetes\u5bf9\u8c61"},{"location":"k8s/cka_cn/foundamentals/memo/#_2","text":"\u5bf9\u8c61\u89c4\u8303\uff08Object Spec\uff09\uff1a \u63d0\u4f9b\u4e86\u4e00\u4e2a\u63cf\u8ff0\u6240\u521b\u5efa\u8d44\u6e90\u7684\u7279\u6027\u7684\u8bf4\u660e\uff1a \u5176\u671f\u671b\u7684\u72b6\u6001 \u3002 \u5bf9\u8c61\u72b6\u6001\uff08Object Status\uff09\uff1a \u63cf\u8ff0\u4e86\u5bf9\u8c61\u7684\u5f53\u524d\u72b6\u6001\u3002 \u6bd4\u5982\uff0cDeployment\u662f\u4e00\u4e2a\u53ef\u4ee5\u4ee3\u8868\u96c6\u7fa4\u4e0a\u8fd0\u884c\u7684\u5e94\u7528\u7a0b\u5e8f\u7684\u5bf9\u8c61\u3002 apiVersion : apps/v1 # \u5f53\u524d\u7528\u6765\u521b\u5efa\u5bf9\u8c61\u7684API\u7248\u672c kind : Deployment # \u521b\u5efa\u5bf9\u8c61\u7684\u7c7b\u578b metadata : # \u7528\u6765\u533a\u5206\u5bf9\u8c61\u7684\u5143\u6570\u636e\uff0c\u6bd4\u5982\uff1a\u540d\u79f0\uff0cUID\uff0c\u547d\u540d\u7a7a\u95f4\u7b49 name : nginx-deployment spec : # \u671f\u671b\u6240\u521b\u5efa\u5bf9\u8c61\u7684\u72b6\u6001 selector : matchLabels : app : nginx replicas : 2 # \u544a\u8bc9Deployment\u57fa\u4e8e\u4e0b\u9762\u7684\u6a21\u677ftemplate\u521b\u5efa2\u4e2aPods template : metadata : labels : app : nginx spec : containers : - name : nginx image : nginx:1.14.2 ports : - containerPort : 80","title":"\u5bf9\u8c61\u6982\u8ff0"},{"location":"k8s/cka_cn/foundamentals/memo/#_3","text":"kubectl \u547d\u4ee4\u884c\u5de5\u5177\u652f\u6301\u591a\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u6765\u521b\u5efa\u548c\u7ba1\u7406 Kubernetes \u5bf9\u8c61\u3002\u8be6\u7ec6\u4fe1\u606f\u8bf7\u9605\u8bfb Kubectl book \u3002 \u4e00\u4e2a Kubernetes \u5bf9\u8c61\u5e94\u8be5\u4ec5\u4f7f\u7528\u4e00\u79cd\u6280\u672f\u8fdb\u884c\u7ba1\u7406\u3002\u6df7\u5408\u4f7f\u7528\u4e0d\u540c\u7684\u6280\u672f\u6765\u7ba1\u7406\u540c\u4e00\u4e2a\u5bf9\u8c61\u4f1a\u5bfc\u81f4\u975e\u9884\u671f\u7684\u7ed3\u679c\u3002 \u4e09\u79cd\u7ba1\u7406\u6280\u672f: \u547d\u4ee4\u5f0f\u547d\u4ee4 \u76f4\u63a5\u5728\u96c6\u7fa4\u4e2d\u64cd\u4f5c\u5b9e\u65f6\u5bf9\u8c61\u3002 kubectl create deployment nginx --image nginx \u547d\u4ee4\u5f0f\u5bf9\u8c61\u914d\u7f6e kubectl create -f nginx.yaml kubectl delete -f nginx.yaml -f redis.yaml kubectl replace -f nginx.yaml \u58f0\u660e\u5f0f\u5bf9\u8c61\u914d\u7f6e kubectl diff -f configs/ kubectl apply -f configs/","title":"\u5bf9\u8c61\u7ba1\u7406"},{"location":"k8s/cka_cn/foundamentals/memo/#id","text":"\u96c6\u7fa4\u4e2d\u7684\u6bcf\u4e2a\u5bf9\u8c61\u90fd\u6709\u4e00\u4e2a\u5728\u8be5\u8d44\u6e90\u7c7b\u578b\u4e2d\u552f\u4e00\u7684\u540d\u79f0\u3002 DNS \u5b50\u57df\u540d \u6807\u7b7e\u540d\u79f0 \u8def\u5f84\u6bb5\u540d\u79f0 \u6bcf\u4e2a Kubernetes \u5bf9\u8c61\u8fd8\u6709\u4e00\u4e2a UID\uff0c\u5728\u6574\u4e2a\u96c6\u7fa4\u4e2d\u662f\u552f\u4e00\u7684\u3002","title":"\u5bf9\u8c61\u540d\u79f0\u548cID"},{"location":"k8s/cka_cn/foundamentals/memo/#_4","text":"\u5728Kubernetes\u4e2d\uff0c\u547d\u540d\u7a7a\u95f4\u63d0\u4f9b\u4e86\u4e00\u79cd\u5728\u5355\u4e2a\u96c6\u7fa4\u5185\u9694\u79bb\u8d44\u6e90\u7ec4\u7684\u673a\u5236\u3002 \u8d44\u6e90\u7684\u540d\u79f0\u9700\u8981\u5728\u547d\u540d\u7a7a\u95f4\u5185\u662f\u552f\u4e00\u7684\uff0c\u4f46\u4e0d\u9700\u8981\u8de8\u547d\u540d\u7a7a\u95f4\u552f\u4e00\u3002 \u57fa\u4e8e\u547d\u540d\u7a7a\u95f4\u7684\u8303\u56f4\u4ec5\u9002\u7528\u4e8e\u547d\u540d\u7a7a\u95f4\u5bf9\u8c61\uff08\u4f8b\u5982\u90e8\u7f72\uff0c\u670d\u52a1\u7b49\uff09\uff0c\u800c\u4e0d\u9002\u7528\u4e8e\u96c6\u7fa4\u8303\u56f4\u7684\u5bf9\u8c61\uff08\u4f8b\u5982StorageClass\uff0c\u8282\u70b9\uff0c\u6301\u4e45\u5377\u7b49\uff09\u3002 \u5e76\u975e\u6240\u6709\u5bf9\u8c61\u90fd\u4f4d\u4e8e\u547d\u540d\u7a7a\u95f4\u4e2d\u3002 Kubernetes\u4ece\u56db\u4e2a\u521d\u59cb\u547d\u540d\u7a7a\u95f4\u5f00\u59cb\uff1a default \u7528\u4e8e\u6ca1\u6709\u5176\u4ed6\u547d\u540d\u7a7a\u95f4\u7684\u5bf9\u8c61\u7684\u9ed8\u8ba4\u547d\u540d\u7a7a\u95f4 kube-system Kubernetes\u7cfb\u7edf\u521b\u5efa\u7684\u5bf9\u8c61\u7684\u547d\u540d\u7a7a\u95f4 kube-public \u8be5\u547d\u540d\u7a7a\u95f4\u662f\u81ea\u52a8\u521b\u5efa\u7684\uff0c\u5e76\u53ef\u7531\u6240\u6709\u7528\u6237\uff08\u5305\u62ec\u672a\u7ecf\u8eab\u4efd\u9a8c\u8bc1\u7684\u7528\u6237\uff09\u8bfb\u53d6\u3002\u6b64\u547d\u540d\u7a7a\u95f4\u5927\u591a\u4fdd\u7559\u4f9b\u96c6\u7fa4\u4f7f\u7528\uff0c\u4ee5\u9632\u4e00\u4e9b\u8d44\u6e90\u5e94\u5728\u6574\u4e2a\u96c6\u7fa4\u8303\u56f4\u5185\u516c\u5f00\u548c\u53ef\u8bfb\u3002\u6b64\u547d\u540d\u7a7a\u95f4\u7684\u516c\u5171\u65b9\u9762\u53ea\u662f\u4e00\u79cd\u7ea6\u5b9a\uff0c\u800c\u4e0d\u662f\u8981\u6c42\u3002 kube-node-lease \u6b64\u547d\u540d\u7a7a\u95f4\u4fdd\u5b58\u4e0e\u6bcf\u4e2a\u8282\u70b9\u5173\u8054\u7684\u79df\u8d41\u5bf9\u8c61\u3002\u8282\u70b9\u79df\u8d41\u5141\u8bb8kubelet\u53d1\u9001\u5fc3\u8df3\uff0c\u4ee5\u4fbf\u63a7\u5236\u5e73\u9762\u53ef\u4ee5\u68c0\u6d4b\u5230\u8282\u70b9\u6545\u969c\u3002 \u67e5\u770b\u547d\u540d\u7a7a\u95f4\uff1a kubectl get namespace \u4e3a\u8bf7\u6c42\u8bbe\u7f6e\u547d\u540d\u7a7a\u95f4 kubectl run nginx --image=nginx --namespace=<\u63d2\u5165\u547d\u540d\u7a7a\u95f4\u540d\u79f0> kubectl get pods --namespace=<\u63d2\u5165\u547d\u540d\u7a7a\u95f4\u540d\u79f0>","title":"\u547d\u540d\u7a7a\u95f4"},{"location":"k8s/cka_cn/foundamentals/memo/#_5","text":"\u6807\u7b7e\u662f\u9644\u52a0\u5230\u5bf9\u8c61\uff08\u4f8b\u5982 Pod\uff09\u7684\u952e/\u503c\u5bf9\u3002\u6709\u6548\u7684\u6807\u7b7e\u952e\u6709\u4e24\u4e2a\u90e8\u5206\uff1a\u53ef\u9009\u7684\u524d\u7f00\u548c\u540d\u79f0\uff0c\u7531\u659c\u6760\uff08 / \uff09\u5206\u9694\u3002 \u6807\u7b7e\u65e8\u5728\u7528\u4e8e\u6307\u5b9a\u5bf9\u7528\u6237\u6709\u610f\u4e49\u548c\u76f8\u5173\u7684\u5bf9\u8c61\u8bc6\u522b\u5c5e\u6027\u3002 \u6807\u7b7e\u53ef\u7528\u4e8e\u7ec4\u7ec7\u548c\u9009\u62e9\u5bf9\u8c61\u5b50\u96c6\u3002\u6807\u7b7e\u53ef\u4ee5\u5728\u521b\u5efa\u5bf9\u8c61\u65f6\u9644\u52a0\uff0c\u968f\u540e\u5728\u4efb\u4f55\u65f6\u5019\u6dfb\u52a0\u548c\u4fee\u6539\u3002\u6bcf\u4e2a\u5bf9\u8c61\u53ef\u4ee5\u5b9a\u4e49\u4e00\u7ec4\u952e/\u503c\u6807\u7b7e\uff0c\u6bcf\u4e2a\u952e\u5fc5\u987b\u5bf9\u4e8e\u7ed9\u5b9a\u5bf9\u8c61\u662f\u552f\u4e00\u7684\u3002 \u6807\u7b7e\u7684\u793a\u4f8b\uff1a \"metadata\" : { \"labels\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } \u4e0e\u540d\u79f0\u548c UID \u4e0d\u540c\uff0c\u6807\u7b7e\u4e0d\u63d0\u4f9b\u552f\u4e00\u6027\u3002\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u671f\u671b\u8bb8\u591a\u5bf9\u8c61\u5e26\u6709\u76f8\u540c\u7684\u6807\u7b7e\u3002 \u76ee\u524d API \u652f\u6301\u4e24\u79cd\u7c7b\u578b\u7684\u9009\u62e9\u5668\uff1a \u57fa\u4e8e\u7b49\u5f0f\u7684\u9009\u62e9\u5668\uff0c\u4f8b\u5982\uff1a environment = production \u3001 tier != frontend \u57fa\u4e8e\u96c6\u5408\u7684\u9009\u62e9\u5668\uff0c\u4f8b\u5982\uff1a environment in (production, qa) \u3001 tier notin (frontend, backend) \u4f8b\u5982\uff1a kubectl get pods -l environment = production,tier = frontend kubectl get pods -l 'environment in (production),tier in (frontend)' kubectl get pods -l 'environment in (production, qa)' kubectl get pods -l 'environment,environment notin (frontend)'","title":"\u6807\u7b7e\u548c\u9009\u62e9\u5668"},{"location":"k8s/cka_cn/foundamentals/memo/#annotations","text":"\u4f7f\u7528 Kubernetes \u6ce8\u91ca\uff08Annotations\uff09\u5c06\u4efb\u610f\u975e\u6807\u8bc6\u5143\u6570\u636e\u9644\u52a0\u5230\u5bf9\u8c61\u4e0a\u3002 \u5de5\u5177\u548c\u5e93\u7b49\u5ba2\u6237\u7aef\u53ef\u4ee5\u68c0\u7d22\u6b64\u5143\u6570\u636e\u3002 \u4f7f\u7528\u6807\u7b7e\u6216\u6ce8\u91ca\u5c06\u5143\u6570\u636e\u9644\u52a0\u5230 Kubernetes \u5bf9\u8c61\u4e0a\u3002 \u6807\u7b7e\u53ef\u7528\u4e8e\u9009\u62e9\u5bf9\u8c61\u5e76\u67e5\u627e\u6ee1\u8db3\u67d0\u4e9b\u6761\u4ef6\u7684\u5bf9\u8c61\u96c6\u5408\u3002 \u6ce8\u91ca\u4e0d\u7528\u4e8e\u6807\u8bc6\u548c\u9009\u62e9\u5bf9\u8c61\u3002 \u6ce8\u91ca\u4e0e\u6807\u7b7e\u7c7b\u4f3c\uff0c\u90fd\u662f\u952e/\u503c\u6620\u5c04\u3002 \u6620\u5c04\u4e2d\u7684\u952e\u548c\u503c\u5fc5\u987b\u662f\u5b57\u7b26\u4e32\u3002 \u4f8b\u5982\uff1a \"metadata\" : { \"annotations\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } \u5408\u6cd5\u7684\u6ce8\u91ca\u952e\u5177\u6709\u4e24\u4e2a\u90e8\u5206\uff1a\u53ef\u9009\u7684\u524d\u7f00\u548c\u540d\u79f0\uff0c\u7531\u659c\u6760 ( / ) \u5206\u9694\u3002","title":"\u6ce8\u91caAnnotations"},{"location":"k8s/cka_cn/foundamentals/memo/#_6","text":"\u5b57\u6bb5\u9009\u62e9\u5668\uff08field selectors\uff09\u53ef\u4ee5\u6839\u636e\u4e00\u4e2a\u6216\u591a\u4e2a\u8d44\u6e90\u5b57\u6bb5\u7684\u503c\u9009\u62e9Kubernetes\u8d44\u6e90\u3002 \u4e0b\u9762\u662f\u4e00\u4e9b\u4f7f\u7528\u5b57\u6bb5\u9009\u62e9\u5668\u8fdb\u884c\u67e5\u8be2\u7b5b\u9009\u7684\u4f8b\u5b50\uff1a metadata.name=my-service metadata.namespace!=default status.phase=Pending This kubectl command selects all Pods for which the value of the status.phase field is Running: kubectl get pods --field-selector status.phase=Running Supported field selectors vary by Kubernetes resource type. All resource types support the metadata.name and metadata.namespace fields. Use the = , == , and != operators with field selectors ( = and == mean the same thing). \u4e0b\u9762 kubectl \u547d\u4ee4\u9009\u62e9\u6240\u6709\u72b6\u6001(phase)\u5b57\u6bb5\u503c\u4e3a Running \u7684 Pod\uff1a kubectl get pods --field-selector status.phase = Running \u652f\u6301\u7684\u5b57\u6bb5\u9009\u62e9\u5668\u56e0 Kubernetes \u8d44\u6e90\u7c7b\u578b\u800c\u5f02\u3002\u6240\u6709\u8d44\u6e90\u7c7b\u578b\u90fd\u652f\u6301 metadata.name \u548c metadata.namespace \u5b57\u6bb5\u3002 \u5728\u5b57\u6bb5\u9009\u62e9\u5668\u4e2d\u4f7f\u7528 = , == , \u548c != \u8fd0\u7b97\u7b26( = \u548c == \u8868\u793a\u76f8\u540c\u7684\u610f\u601d)\u3002 \u4f8b\u5982\uff1a kubectl get ingress --field-selector foo.bar = baz kubectl get services --all-namespaces --field-selector metadata.namespace! = default kubectl get pods --field-selector = status.phase! = Running,spec.restartPolicy = Always kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace! = default Finalizers\u662f*\u547d\u540d\u7a7a\u95f4\u952e*\uff0c\u544a\u8bc9Kubernetes\u5728\u6ee1\u8db3\u7279\u5b9a\u6761\u4ef6\u4e4b\u524d\u7b49\u5f85\uff0c\u7136\u540e\u518d\u5b8c\u5168\u5220\u9664\u6807\u8bb0\u4e3a*\u5220\u9664*\u7684\u8d44\u6e90\u3002 Finalizer\u8b66\u544a\u63a7\u5236\u5668controller\u6e05\u7406\u5df2\u5220\u9664\u5bf9\u8c61\u6240\u62e5\u6709\u7684\u8d44\u6e90\u3002 \u901a\u5e38\u56e0\u4e3a\u67d0\u79cd\u76ee\u7684\u4e3a\u8d44\u6e90\u6dfb\u52a0Finalizers\uff0c\u5f3a\u5236\u5220\u9664\u5b83\u4eec\u53ef\u80fd\u4f1a\u5bfc\u81f4\u96c6\u7fa4\u4e2d\u51fa\u73b0\u95ee\u9898\u3002 \u4e0e\u6807\u7b7e\u7c7b\u4f3c\uff0c \u6240\u6709\u8005\u5f15\u7528 \uff08Owner references\uff09\u63cf\u8ff0\u4e86Kubernetes\u4e2d\u5bf9\u8c61\u4e4b\u95f4\u7684\u5173\u7cfb\uff0c\u4f46\u7528\u4e8e\u4e0d\u540c\u7684\u76ee\u7684\u3002 Kubernetes\u4f7f\u7528\u6240\u6709\u8005\u5f15\u7528\uff08\u800c\u4e0d\u662f\u6807\u7b7e\uff09\u6765\u786e\u5b9a\u96c6\u7fa4\u4e2d\u54ea\u4e9bPod\u9700\u8981\u6e05\u7406\u3002 \u5f53Kubernetes\u8bc6\u522b\u5230\u76ee\u6807\u5220\u9664\u7684\u8d44\u6e90\u4e0a\u6709\u6240\u6709\u8005\u5f15\u7528\u65f6\uff0c\u5b83\u4f1a\u5904\u7406Finalizer\u3002","title":"\u5b57\u6bb5\u9009\u62e9\u5668"},{"location":"k8s/cka_cn/foundamentals/memo/#_7","text":"\u5728 Kubernetes \u4e2d\uff0c\u4e00\u4e9b\u5bf9\u8c61\u62e5\u6709\u5176\u4ed6\u5bf9\u8c61\u3002\u4f8b\u5982\uff0cReplicaSet \u662f\u4e00\u7ec4 Pod \u7684\u6240\u6709\u8005\u3002\u8fd9\u4e9b\u88ab\u62e5\u6709\u7684\u5bf9\u8c61\u662f\u5176\u6240\u6709\u8005\u7684\u4ece\u5c5e\u5bf9\u8c61\u3002 \u4ece\u5c5e\u5bf9\u8c61\u5177\u6709\u4e00\u4e2a metadata.ownerReferences \u5b57\u6bb5\uff0c\u8be5\u5b57\u6bb5\u5f15\u7528\u5176\u6240\u6709\u8005\u5bf9\u8c61\u3002 \u6709\u6548\u7684\u6240\u6709\u8005\u5f15\u7528\u5305\u62ec\u5bf9\u8c61\u540d\u79f0\u548c\u4e0e\u4ece\u5c5e\u5bf9\u8c61\u76f8\u540c\u7684\u547d\u540d\u7a7a\u95f4\u4e2d\u7684 UID\u3002 \u4ece\u5c5e\u5bf9\u8c61\u8fd8\u5177\u6709\u4e00\u4e2a ownerReferences.blockOwnerDeletion \u5b57\u6bb5\uff0c\u8be5\u5b57\u6bb5\u5177\u6709\u5e03\u5c14\u503c\uff0c\u63a7\u5236\u7279\u5b9a\u7684\u4ece\u5c5e\u5bf9\u8c61\u662f\u5426\u53ef\u4ee5\u963b\u6b62\u5783\u573e\u56de\u6536\u5220\u9664\u5176\u6240\u6709\u8005\u5bf9\u8c61\u3002","title":"\u6240\u6709\u8005\u548c\u4f9d\u8d56\u5173\u7cfb"},{"location":"k8s/cka_cn/foundamentals/memo/#_8","text":"Kubernetes\u8d44\u6e90\u548c\u201c\u610f\u5411\u8bb0\u5f55\u201d\u90fd\u4ee5API\u5bf9\u8c61\u7684\u5f62\u5f0f\u5b58\u50a8\uff0c\u5e76\u901a\u8fc7\u5bf9API\u7684RESTful\u8c03\u7528\u8fdb\u884c\u4fee\u6539\u3002 API\u5141\u8bb8\u4ee5\u58f0\u660e\u6027\u65b9\u5f0f\u7ba1\u7406\u914d\u7f6e\u3002 \u7528\u6237\u53ef\u4ee5\u76f4\u63a5\u4e0eKubernetes API\u4ea4\u4e92\uff0c\u4e5f\u53ef\u4ee5\u901a\u8fc7\u50cfkubectl\u8fd9\u6837\u7684\u5de5\u5177\u8fdb\u884c\u4ea4\u4e92\u3002 \u6838\u5fc3Kubernetes API\u5177\u6709\u7075\u6d3b\u6027\uff0c\u4e5f\u53ef\u4ee5\u6269\u5c55\u4ee5\u652f\u6301\u81ea\u5b9a\u4e49\u8d44\u6e90\u3002 \u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\uff08Workload Resources\uff09 Pod \u3002Pod \u662f\u53ef\u4ee5\u5728\u4e3b\u673a\u4e0a\u8fd0\u884c\u7684\u5bb9\u5668\u96c6\u5408\u3002 PodTemplate \u3002PodTemplate \u63cf\u8ff0\u4e86\u9884\u5b9a\u4e49 pod \u7684\u526f\u672c\u6a21\u677f\u3002 ReplicationController \u3002ReplicationController \u8868\u793a\u4e00\u4e2a\u590d\u5236\u63a7\u5236\u5668\u7684\u914d\u7f6e\u3002 ReplicaSet \u3002ReplicaSet \u786e\u4fdd\u5728\u4efb\u4f55\u7ed9\u5b9a\u65f6\u95f4\u6709\u6307\u5b9a\u6570\u91cf\u7684 pod \u526f\u672c\u6b63\u5728\u8fd0\u884c\u3002 Deployment \u3002Deployment \u4f7f Pod \u548c ReplicaSet \u7684\u58f0\u660e\u6027\u66f4\u65b0\u6210\u4e3a\u53ef\u80fd\u3002 StatefulSet \u3002StatefulSet \u8868\u793a\u5177\u6709\u4e00\u81f4\u6807\u8bc6\u7684 pod \u96c6\u5408\u3002 ControllerRevision \u3002ControllerRevision \u5b9e\u73b0\u4e86\u72b6\u6001\u6570\u636e\u7684\u4e0d\u53ef\u53d8\u5feb\u7167\u3002 DaemonSet \u3002DaemonSet \u8868\u793a\u4e00\u4e2a\u5b88\u62a4\u8fdb\u7a0b\u96c6\u7684\u914d\u7f6e\u3002 Job \u3002Job \u8868\u793a\u5355\u4e2a job \u7684\u914d\u7f6e\u3002 CronJob \u3002CronJob \u8868\u793a\u5355\u4e2a cron job \u7684\u914d\u7f6e\u3002 HorizontalPodAutoscaler \u3002HorizontalPodAutoscaler \u8868\u793a\u6c34\u5e73 pod \u81ea\u52a8\u7f29\u653e\u5668\u7684\u914d\u7f6e\u3002 HorizontalPodAutoscaler v2beta2 \u3002HorizontalPodAutoscaler \u662f\u6c34\u5e73 pod \u81ea\u52a8\u7f29\u653e\u5668\u7684\u914d\u7f6e\uff0c\u6839\u636e\u6307\u5b9a\u7684\u6307\u6807\u81ea\u52a8\u7ba1\u7406\u5b9e\u73b0\u6bd4\u4f8b\u5b50\u8d44\u6e90\u7684\u4efb\u4f55\u8d44\u6e90\u7684\u526f\u672c\u8ba1\u6570\u3002 PriorityClass \u3002PriorityClass \u5b9a\u4e49\u4e86\u4ece\u4f18\u5148\u7ea7\u7c7b\u540d\u79f0\u5230\u4f18\u5148\u7ea7\u6574\u6570\u503c\u7684\u6620\u5c04\u3002 \u670d\u52a1\u8d44\u6e90\uff08Service Resources\uff09 Service . Service \u662f\u5bf9\u8f6f\u4ef6\u670d\u52a1\uff08\u4f8b\u5982mysql\uff09\u7684\u547d\u540d\u62bd\u8c61\uff0c\u7531\u4ee3\u7406\u76d1\u542c\u7684\u672c\u5730\u7aef\u53e3\uff08\u4f8b\u59823306\uff09\u548c\u786e\u5b9a\u54ea\u4e9bPod\u5c06\u56de\u7b54\u901a\u8fc7\u4ee3\u7406\u53d1\u9001\u7684\u8bf7\u6c42\u7684\u9009\u62e9\u5668\u7ec4\u6210\u3002 Endpoints . Endpoints \u662f\u5b9e\u73b0\u5b9e\u9645\u670d\u52a1\u7684\u4e00\u7ec4\u7ec8\u7ed3\u70b9\u3002 EndpointSlice . EndpointSlice \u8868\u793a\u5b9e\u73b0\u670d\u52a1\u7684\u7ec8\u7ed3\u70b9\u7684\u5b50\u96c6\u3002 Ingress . Ingress \u662f\u4e00\u7ec4\u89c4\u5219\uff0c\u5141\u8bb8\u5165\u7ad9\u8fde\u63a5\u5230\u8fbe\u7531\u540e\u7aef\u5b9a\u4e49\u7684\u7ec8\u7ed3\u70b9\u3002 IngressClass . IngressClass \u8868\u793a Ingress \u7684\u7c7b\uff0c\u7531 Ingress Spec \u5f15\u7528\u3002 \u914d\u7f6e\u548c\u5b58\u50a8\u8d44\u6e90\uff08Config and Storage Resources\uff09 ConfigMap \u3002ConfigMap\u4fdd\u5b58\u5bb9\u5668\u9700\u8981\u4f7f\u7528\u7684\u914d\u7f6e\u6570\u636e\u3002 Secret \u3002Secret\u4fdd\u5b58\u7279\u5b9a\u7c7b\u578b\u7684\u673a\u5bc6\u6570\u636e\u3002 Volume \u3002Volume\u8868\u793aPod\u4e2d\u7684\u547d\u540d\u5377\uff0c\u53ef\u4ee5\u88abPod\u4e2d\u7684\u4efb\u4f55\u5bb9\u5668\u8bbf\u95ee\u3002 PersistentVolumeClaim \u3002PersistentVolumeClaim\u662f\u7528\u6237\u5bf9\u6301\u4e45\u5377\u7684\u8bf7\u6c42\u548c\u58f0\u660e\u3002 PersistentVolume \u3002PersistentVolume\uff08PV\uff09\u662f\u7531\u7ba1\u7406\u5458\u63d0\u4f9b\u7684\u5b58\u50a8\u8d44\u6e90\u3002 StorageClass \u3002StorageClass\u63cf\u8ff0\u53ef\u52a8\u6001\u5206\u914dPersistentVolumes\u7684\u5b58\u50a8\u7c7b\u522b\u7684\u53c2\u6570\u3002 VolumeAttachment \u3002VolumeAttachment\u8bb0\u5f55\u5c06\u6307\u5b9a\u7684\u5377\u9644\u52a0\u5230/\u4ece\u6307\u5b9a\u8282\u70b9\u4e2d\u5206\u79bb\u7684\u610f\u56fe\u3002 CSIDriver \u3002CSIDriver\u8bb0\u5f55\u96c6\u7fa4\u4e0a\u90e8\u7f72\u7684\u5bb9\u5668\u5b58\u50a8\u63a5\u53e3\uff08CSI\uff09\u5377\u9a71\u52a8\u7a0b\u5e8f\u7684\u4fe1\u606f\u3002 CSINode \u3002CSINode\u4fdd\u5b58\u6709\u5173\u8282\u70b9\u4e0a\u5b89\u88c5\u7684\u6240\u6709CSI\u9a71\u52a8\u7a0b\u5e8f\u7684\u4fe1\u606f\u3002 CSIStorageCapacity \u3002CSIStorageCapacity\u5b58\u50a8\u4e00\u4e2aCSI GetCapacity\u8c03\u7528\u7684\u7ed3\u679c\u3002 \u8ba4\u8bc1\u8d44\u6e90\uff08Authentication Resources\uff09 ServiceAccount*\u3002ServiceAccount\u548c\u4e0b\u9762\u7684\u4fe1\u606f\u7ed1\u5b9a\u5728\u4e00\u8d77\uff1a \u4e00\u4e2a\u53ef\u88ab\u7528\u6237\u548c\u5468\u8fb9\u7cfb\u7edf\u7406\u89e3\u7684\u540d\u79f0\uff0c\u7528\u4e8e\u8eab\u4efd\u8bc6\u522b \u53ef\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u548c\u6388\u6743\u7684\u4e3b\u4f53 \u4e00\u7ec4\u5bc6\u94a5\u3002 TokenRequest*\u3002TokenRequest\u4e3a\u7ed9\u5b9a\u7684ServiceAccount\u8bf7\u6c42\u4e00\u4e2a\u4ee4\u724c\u3002 TokenReview*\u3002TokenReview\u5c1d\u8bd5\u5bf9\u5df2\u77e5\u7528\u6237\u7684\u4ee4\u724c\u8fdb\u884c\u8eab\u4efd\u9a8c\u8bc1\u3002 CertificateSigningRequest*\u3002CertificateSigningRequest\u5bf9\u8c61\u63d0\u4f9b\u4e86\u4e00\u79cd\u901a\u8fc7\u63d0\u4ea4\u8bc1\u4e66\u7b7e\u540d\u8bf7\u6c42\u5e76\u5f02\u6b65\u6279\u51c6\u548c\u53d1\u653e\u6765\u83b7\u53d6x509\u8bc1\u4e66\u7684\u673a\u5236\u3002 \u6388\u6743\u8d44\u6e90\uff08Authorization Resources\uff09 LocalSubjectAccessReview*\u3002LocalSubjectAccessReview\u68c0\u67e5\u4e00\u4e2a\u7528\u6237\u6216\u7ec4\u5728\u7ed9\u5b9a\u547d\u540d\u7a7a\u95f4\u4e2d\u662f\u5426\u80fd\u6267\u884c\u67d0\u4e2a\u64cd\u4f5c\u3002 SelfSubjectAccessReview*\u3002SelfSubjectAccessReview\u68c0\u67e5\u5f53\u524d\u7528\u6237\u662f\u5426\u80fd\u6267\u884c\u67d0\u4e2a\u64cd\u4f5c\u3002 SelfSubjectRulesReview*\u3002SelfSubjectRulesReview\u679a\u4e3e\u5f53\u524d\u7528\u6237\u5728\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4\u5185\u53ef\u4ee5\u6267\u884c\u7684\u64cd\u4f5c\u96c6\u5408\u3002 SubjectAccessReview*\u3002SubjectAccessReview\u68c0\u67e5\u4e00\u4e2a\u7528\u6237\u6216\u7ec4\u662f\u5426\u80fd\u6267\u884c\u67d0\u4e2a\u64cd\u4f5c\u3002 ClusterRole*\u3002ClusterRole\u662f\u4e00\u4e2a\u96c6\u7fa4\u7ea7\u522b\u7684PolicyRules\u903b\u8f91\u5206\u7ec4\uff0c\u53ef\u4ee5\u88abRoleBinding\u6216ClusterRoleBinding\u5f15\u7528\u4e3a\u4e00\u4e2a\u5355\u5143\u3002 ClusterRoleBinding*\u3002ClusterRoleBinding\u5f15\u7528\u4e00\u4e2aClusterRole\uff0c\u4f46\u4e0d\u5305\u542b\u5b83\u3002 Role*\u3002Role\u662f\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4\u7ea7\u522b\u7684PolicyRules\u903b\u8f91\u5206\u7ec4\uff0c\u53ef\u4ee5\u88abRoleBinding\u5f15\u7528\u4e3a\u4e00\u4e2a\u5355\u5143\u3002 RoleBinding*\u3002RoleBinding\u5f15\u7528\u4e00\u4e2aRole\uff0c\u4f46\u4e0d\u5305\u542b\u5b83\u3002 \u7b56\u7565\u8d44\u6e90\uff08Policy Resources\uff09 LimitRange*\u3002LimitRange\u4e3a\u547d\u540d\u7a7a\u95f4\u4e2d\u6bcf\u79cd\u8d44\u6e90\u8bbe\u7f6e\u8d44\u6e90\u4f7f\u7528\u9650\u5236\u3002 ResourceQuota*\u3002ResourceQuota\u8bbe\u7f6e\u6bcf\u4e2a\u547d\u540d\u7a7a\u95f4\u5f3a\u5236\u6267\u884c\u7684\u603b\u914d\u989d\u9650\u5236\u3002 NetworkPolicy*\u3002NetworkPolicy\u63cf\u8ff0\u4e86\u4e00\u7ec4Pod\u5141\u8bb8\u7684\u7f51\u7edc\u6d41\u91cf\u3002 PodDisruptionBudget*\u3002PodDisruptionBudget\u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u7528\u4e8e\u5b9a\u4e49\u5bf9\u4e00\u7ec4Pod\u53ef\u80fd\u9020\u6210\u7684\u6700\u5927\u4e2d\u65ad\u3002 PodSecurityPolicy v1beta1*\u3002PodSecurityPolicy\u63a7\u5236\u5bf9\u53ef\u80fd\u5f71\u54cd\u5c06\u5e94\u7528\u4e8ePod\u548c\u5bb9\u5668\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\u7684\u8bf7\u6c42\u7684\u80fd\u529b\u3002 \u6269\u5c55\u8d44\u6e90\uff08Extend Resources\uff09 CustomResourceDefinition*\u3002CustomResourceDefinition\u8868\u793a\u5e94\u5728API\u670d\u52a1\u5668\u4e0a\u516c\u5f00\u7684\u8d44\u6e90\u3002 MutatingWebhookConfiguration*\u3002MutatingWebhookConfiguration\u63cf\u8ff0\u63a5\u53d7\u6216\u62d2\u7edd\u5e76\u53ef\u80fd\u66f4\u6539\u5bf9\u8c61\u7684\u51c6\u5165Webhook\u7684\u914d\u7f6e\u3002 ValidatingWebhookConfiguration*\u3002ValidatingWebhookConfiguration\u63cf\u8ff0\u63a5\u53d7\u6216\u62d2\u7edd\u5bf9\u8c61\u4f46\u4e0d\u66f4\u6539\u5bf9\u8c61\u7684\u51c6\u5165Webhook\u7684\u914d\u7f6e\u3002 \u96c6\u7fa4\u8d44\u6e90\uff08Cluster Resources\uff09 Node*\u3002Node\u662fKubernetes\u4e2d\u7684\u5de5\u4f5c\u8282\u70b9\u3002 Namespace*\u3002Namespace\u4e3a\u540d\u79f0\u63d0\u4f9b\u4e86\u4f5c\u7528\u57df\u3002 Event*\u3002Event\u662f\u5bf9\u96c6\u7fa4\u4e2d\u67d0\u4e2a\u4f4d\u7f6e\u53d1\u751f\u4e8b\u4ef6\u7684\u62a5\u544a\u3002 APIService*\u3002APIService\u8868\u793a\u7279\u5b9aGroupVersion\u7684\u670d\u52a1\u5668\u3002 Lease*\u3002Lease\u5b9a\u4e49\u4e86\u79df\u8d41\u7684\u6982\u5ff5\u3002 RuntimeClass*\u3002RuntimeClass\u5b9a\u4e49\u4e86\u96c6\u7fa4\u4e2d\u652f\u6301\u7684\u5bb9\u5668\u8fd0\u884c\u65f6\u7c7b\u3002 FlowSchema v1beta2*\u3002FlowSchema\u5b9a\u4e49\u4e86\u4e00\u7ec4\u6d41\u7a0b\u7684\u67b6\u6784\u3002 PriorityLevelConfiguration v1beta2*\u3002PriorityLevelConfiguration\u8868\u793a\u4f18\u5148\u7ea7\u7ea7\u522b\u7684\u914d\u7f6e\u3002 Binding*\u3002Binding\u5c06\u4e00\u4e2a\u5bf9\u8c61\u7ed1\u5b9a\u5230\u53e6\u4e00\u4e2a\u5bf9\u8c61\uff1b\u4f8b\u5982\uff0c\u8c03\u5ea6\u7a0b\u5e8f\u5c06Pod\u7ed1\u5b9a\u5230\u8282\u70b9\u4e0a\u3002 ComponentStatus*\u3002ComponentStatus\uff08\u548cComponentStatusList\uff09\u4fdd\u5b58\u96c6\u7fa4\u9a8c\u8bc1\u4fe1\u606f\u3002 \u4f7f\u7528\u547d\u4ee4 kube api-resources \u83b7\u53d6\u652f\u6301\u7684API\u8d44\u6e90\u3002 \u4f7f\u7528\u547d\u4ee4 kubectl explain RESOURCE [options] \u63cf\u8ff0\u4e0e\u6bcf\u4e2a\u652f\u6301\u7684API\u8d44\u6e90\u76f8\u5173\u8054\u7684\u5b57\u6bb5\u3002\u8fd9\u4e9b\u5b57\u6bb5\u53ef\u4ee5\u901a\u8fc7\u7b80\u5355\u7684JSONPath\u6807\u8bc6\u7b26\u8fdb\u884c\u8bc6\u522b\uff1a kubectl explain binding kubectl explain binding.metadata kubectl explain binding.metadata.name","title":"\u8d44\u6e90"},{"location":"k8s/cka_cn/foundamentals/memo/#_9","text":"","title":"\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90"},{"location":"k8s/cka_cn/foundamentals/memo/#pods","text":"Pod\u662fKubernetes\u4e2d\u53ef\u521b\u5efa\u548c\u7ba1\u7406\u7684\u6700\u5c0f\u90e8\u7f72\u8ba1\u7b97\u5355\u4f4d\u3002 Pod\u662f\u4e00\u4e2a\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u5bb9\u5668\u3001\u5171\u4eab\u5b58\u50a8\u548c\u7f51\u7edc\u8d44\u6e90\u4ee5\u53ca\u5982\u4f55\u8fd0\u884c\u5bb9\u5668\u7684\u89c4\u8303\u7684\u7ec4\u3002 Pod\u7684\u5185\u5bb9\u59cb\u7ec8\u5171\u540c\u5b9a\u4f4d\u548c\u5171\u540c\u5b89\u6392\uff0c\u5e76\u5728\u5171\u4eab\u73af\u5883\u4e2d\u8fd0\u884c\u3002 Pod\u6a21\u62df\u4e86\u4e00\u4e2a\u7279\u5b9a\u4e8e\u5e94\u7528\u7a0b\u5e8f\u7684\u201c\u903b\u8f91\u4e3b\u673a\u201d\uff1a\u5b83\u5305\u542b\u4e00\u4e2a\u6216\u591a\u4e2a\u76f8\u5bf9\u7d27\u5bc6\u8026\u5408\u7684\u5e94\u7528\u7a0b\u5e8f\u5bb9\u5668\u3002 \u5728\u975e\u4e91\u73af\u5883\u4e2d\uff0c\u540c\u4e00\u7269\u7406\u6216\u865a\u62df\u673a\u4e0a\u6267\u884c\u7684\u5e94\u7528\u7a0b\u5e8f\u7c7b\u4f3c\u4e8e\u5728\u540c\u4e00\u903b\u8f91\u4e3b\u673a\u4e0a\u6267\u884c\u7684\u4e91\u5e94\u7528\u7a0b\u5e8f\u3002 Pod\u7684\u5171\u4eab\u73af\u5883\u662f\u4e00\u7ec4Linux\u547d\u540d\u7a7a\u95f4\u3001cgroups\u548c\u53ef\u80fd\u7684\u5176\u4ed6\u9694\u79bb\u8981\u7d20 - \u8fd9\u4e9b\u8981\u7d20\u4e0e\u9694\u79bbDocker\u5bb9\u5668\u7684\u65b9\u5f0f\u76f8\u540c\u3002 \u5728Docker\u6982\u5ff5\u65b9\u9762\uff0cPod\u7c7b\u4f3c\u4e8e\u5177\u6709\u5171\u4eab\u547d\u540d\u7a7a\u95f4\u548c\u5171\u4eab\u6587\u4ef6\u7cfb\u7edf\u5377\u7684\u4e00\u7ec4Docker\u5bb9\u5668\u3002 \u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u751a\u81f3\u662f\u5355\u4f8bPod\uff0c\u6211\u4eec\u90fd\u4e0d\u9700\u8981\u76f4\u63a5\u521b\u5efaPod\uff0c\u800c\u662f\u4f7f\u7528\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\uff0c\u4f8b\u5982*Deployment*\u6216*Job*\u6765\u521b\u5efa\u5b83\u4eec\u3002\u5982\u679cPod\u9700\u8981\u8ddf\u8e2a\u72b6\u6001\uff0c\u5219\u53ef\u4ee5\u4f7f\u7528StatefulSet\u8d44\u6e90\u3002 Kubernetes\u96c6\u7fa4\u4e2d\u7684Pod\u6709\u4e24\u79cd\u4e3b\u8981\u7528\u6cd5\uff1a \u8fd0\u884c\u5355\u4e2a\u5bb9\u5668\u7684Pod\u3002 \u8fd0\u884c\u9700\u8981\u5171\u540c\u5de5\u4f5c\u7684\u591a\u4e2a\u5bb9\u5668\u7684Pod\u3002 \u201c\u6bcf\u4e2aPod\u4e00\u4e2a\u5bb9\u5668\u201d\u7684\u6a21\u578b\u662f\u6700\u5e38\u89c1\u7684Kubernetes\u7528\u4f8b\uff1b\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\u53ef\u4ee5\u5c06Pod\u89c6\u4e3a\u5355\u4e2a\u5bb9\u5668\u7684\u5305\u88c5\u5668\uff1bKubernetes\u7ba1\u7406Pod\u800c\u4e0d\u662f\u76f4\u63a5\u7ba1\u7406\u5bb9\u5668\u3002 \u4e00\u4e2aPod\u53ef\u4ee5\u5c01\u88c5\u7531\u591a\u4e2a\u5171\u540c\u5b9a\u4f4d\u3001\u7d27\u5bc6\u8026\u5408\u4e14\u9700\u8981\u5171\u4eab\u8d44\u6e90\u7684\u5bb9\u5668\u7ec4\u6210\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 \u8fd9\u4e9b\u5171\u540c\u5b9a\u4f4d\u7684\u5bb9\u5668\u5f62\u6210\u4e00\u4e2a\u5355\u4e00\u7684\u670d\u52a1\u6574\u4f53\u5355\u5143 - \u4f8b\u5982\uff0c\u4e00\u4e2a\u5bb9\u5668\u5411\u516c\u4f17\u63d0\u4f9b\u5b58\u50a8\u5728\u5171\u4eab\u5377\u4e2d\u7684\u6570\u636e\uff0c\u800c\u53e6\u4e00\u4e2a\u72ec\u7acb\u7684Sidecar\u5bb9\u5668\u5237\u65b0\u6216\u66f4\u65b0\u8fd9\u4e9b\u6587\u4ef6\u3002Pod\u5c06\u8fd9\u4e9b\u5bb9\u5668\u3001\u5b58\u50a8\u8d44\u6e90\u548c\u77ed\u6682\u7684\u7f51\u7edc\u6807\u8bc6\u5305\u88c5\u5728\u4e00\u8d77\uff0c\u4f5c\u4e3a\u4e00\u4e2a\u5355\u72ec\u7684\u5355\u4f4d\u3002 \u5728\u5355\u4e2aPod\u4e2d\u5206\u7ec4\u591a\u4e2a\u5171\u540c\u5b9a\u4f4d\u548c\u5171\u540c\u7ba1\u7406\u7684\u5bb9\u5668\u662f\u76f8\u5bf9\u9ad8\u7ea7\u7684\u7528\u4f8b\u3002\u5e94\u8be5*\u4ec5\u5728*\u5bb9\u5668\u7d27\u5bc6\u8026\u5408\u7684\u7279\u5b9a\u60c5\u51b5\u4e0b\u4f7f\u7528\u6b64\u6a21\u5f0f\u3002 \u6bcf\u4e2aPod\u90fd\u65e8\u5728\u8fd0\u884c\u7ed9\u5b9a\u5e94\u7528\u7a0b\u5e8f\u7684\u5355\u4e2a\u5b9e\u4f8b\u3002\u5982\u679c\u6211\u4eec\u60f3\u6c34\u5e73\u6269\u5c55\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\uff08\u901a\u8fc7\u8fd0\u884c\u66f4\u591a\u5b9e\u4f8b\u63d0\u4f9b\u66f4\u591a\u7684\u603b\u8d44\u6e90\uff09\uff0c\u5219\u5e94\u8be5\u4f7f\u7528\u591a\u4e2aPod\uff0c\u6bcf\u4e2a\u5b9e\u4f8b\u4e00\u4e2aPod\u3002\u5728Kubernetes\u4e2d\uff0c\u8fd9\u901a\u5e38\u79f0\u4e3a*\u590d\u5236*\u3002\u590d\u5236\u7684Pod\u901a\u5e38\u4f5c\u4e3a\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\u53ca\u5176\u63a7\u5236\u5668\u7684\u4e00\u7ec4\u521b\u5efa\u548c\u7ba1\u7406\u3002 Pod\u672c\u5730\u63d0\u4f9b\u4e24\u79cd\u5171\u4eab\u8d44\u6e90\u4ee5\u4f9b\u5176\u7ec4\u6210\u5bb9\u5668\u4f7f\u7528\uff1a \u7f51\u7edc *\u548c \u5b58\u50a8 *\u3002 \u4e00\u4e2aPod\u53ef\u4ee5\u6307\u5b9a\u4e00\u7ec4\u5171\u4eab\u7684\u5b58\u50a8\u5377\u3002Pod\u4e2d\u7684\u6240\u6709\u5bb9\u5668\u90fd\u53ef\u4ee5\u8bbf\u95ee\u8fd9\u4e9b\u5171\u4eab\u5377\uff0c\u4f7f\u8fd9\u4e9b\u5bb9\u5668\u53ef\u4ee5\u5171\u4eab\u6570\u636e\u3002 \u6bcf\u4e2aPod\u4e3a\u6bcf\u4e2a\u5730\u5740\u65cf\u5206\u914d\u4e00\u4e2a\u552f\u4e00\u7684IP\u5730\u5740\u3002 \u5728\u4e00\u4e2aPod\u5185\uff0c\u5bb9\u5668\u5171\u4eab\u4e00\u4e2aIP\u5730\u5740\u548c\u7aef\u53e3\u7a7a\u95f4\uff0c\u5e76\u53ef\u4ee5\u901a\u8fc7\u201clocalhost\u201d\u627e\u5230\u5f7c\u6b64\u3002\u60f3\u8981\u4e0e\u8fd0\u884c\u5728\u4e0d\u540cPod\u4e2d\u7684\u5bb9\u5668\u4ea4\u4e92\u7684\u5bb9\u5668\u53ef\u4ee5\u4f7f\u7528IP\u7f51\u7edc\u8fdb\u884c\u901a\u4fe1\u3002 \u5f53\u521b\u5efa\u4e00\u4e2aPod\u65f6\uff0c\u65b0\u7684Pod\u88ab\u8c03\u5ea6\u5728\u96c6\u7fa4\u4e2d\u7684\u4e00\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u3002Pod\u4fdd\u7559\u5728\u8be5\u8282\u70b9\u4e0a\uff0c\u76f4\u5230Pod\u6267\u884c\u5b8c\u6bd5\u3001Pod\u5bf9\u8c61\u88ab\u5220\u9664\u3001Pod\u56e0\u7f3a\u4e4f\u8d44\u6e90\u800c\u88ab\u9a71\u9010\u6216\u8282\u70b9\u53d1\u751f\u6545\u969c\u3002 \u5728Pod\u4e2d\u91cd\u65b0\u542f\u52a8\u4e00\u4e2a\u5bb9\u5668\u4e0d\u5e94\u4e0e\u91cd\u65b0\u542f\u52a8\u4e00\u4e2aPod\u6df7\u6dc6\u3002Pod\u4e0d\u662f\u4e00\u4e2a\u8fdb\u7a0b\uff0c\u800c\u662f\u4e00\u4e2a\u8fd0\u884c\u5bb9\u5668\u7684\u73af\u5883\u3002Pod\u4f1a\u4e00\u76f4\u4fdd\u7559\uff0c\u76f4\u5230\u88ab\u5220\u9664\u4e3a\u6b62\u3002 \u60a8\u53ef\u4ee5\u4f7f\u7528\u5de5\u4f5c\u8d1f\u8f7d\u8d44\u6e90\uff08\u4f8b\u5982Deployment\u3001StatefulSet\u3001DaemonSet\uff09\u4e3a\u81ea\u5df1\u521b\u5efa\u548c\u7ba1\u7406\u591a\u4e2aPod\u3002\u8d44\u6e90\u7684\u63a7\u5236\u5668\u5904\u7406\u590d\u5236\u3001\u6eda\u52a8\u548c\u5728Pod\u5931\u8d25\u65f6\u7684\u81ea\u52a8\u6062\u590d\u3002","title":"Pods"},{"location":"k8s/cka_cn/foundamentals/memo/#_10","text":"\u4e00\u4e9bPod\u8fd8\u6709\u521d\u59cb\u5316\u5bb9\u5668\uff08Init containers\uff09\u548c\u5e94\u7528\u5bb9\u5668\uff08app containers\uff09\u3002\u521d\u59cb\u5316\u5bb9\u5668\u5728\u5e94\u7528\u5bb9\u5668\u542f\u52a8\u4e4b\u524d\u8fd0\u884c\u5e76\u5b8c\u6210\u3002 \u6211\u4eec\u53ef\u4ee5\u5728Pod\u89c4\u8303\u4e2d\u6307\u5b9a\u521d\u59cb\u5316\u5bb9\u5668\uff0c\u540c\u65f6\u4e5f\u53ef\u4ee5\u5728\u5bb9\u5668\u6570\u7ec4\u4e2d\u63cf\u8ff0\u5e94\u7528\u5bb9\u5668\u3002","title":"\u521d\u59cb\u5316\u5bb9\u5668"},{"location":"k8s/cka_cn/foundamentals/memo/#pod","text":"\u9759\u6001Pod\u662f\u76f4\u63a5\u7531\u7279\u5b9a\u8282\u70b9\u4e0a\u7684kubelet\u5b88\u62a4\u7a0b\u5e8f\u7ba1\u7406\u7684\uff0cAPI\u670d\u52a1\u5668\u4e0d\u4f1a\u89c2\u5bdf\u5b83\u4eec\u3002 \u9759\u6001Pod\u59cb\u7ec8\u7ed1\u5b9a\u5230\u7279\u5b9a\u8282\u70b9\u4e0a\u7684\u4e00\u4e2aKubelet\u3002 \u9759\u6001Pod\u7684\u4e3b\u8981\u7528\u9014\u662f\u8fd0\u884c\u81ea\u6258\u7ba1\u63a7\u5236\u9762\u677f\uff1a\u6362\u53e5\u8bdd\u8bf4\uff0c\u4f7f\u7528kubelet\u76d1\u7763\u5404\u4e2a\u63a7\u5236\u9762\u677f\u7ec4\u4ef6\u3002 kubelet\u4f1a\u81ea\u52a8\u5c1d\u8bd5\u4e3a\u6bcf\u4e2a\u9759\u6001Pod\u5728Kubernetes API\u670d\u52a1\u5668\u4e0a\u521b\u5efa\u4e00\u4e2a\u955c\u50cfPod\u3002\u8fd9\u610f\u5473\u7740\u5728\u8282\u70b9\u4e0a\u8fd0\u884c\u7684Pod\u5728API\u670d\u52a1\u5668\u4e0a\u53ef\u89c1\uff0c\u4f46\u65e0\u6cd5\u4ece\u90a3\u91cc\u63a7\u5236\u3002","title":"\u9759\u6001Pod"},{"location":"k8s/cka_cn/foundamentals/memo/#_11","text":"\u63a2\u9488\u662f kubelet \u5b9a\u671f\u5bf9\u5bb9\u5668\u6267\u884c\u7684\u4e00\u79cd\u8bca\u65ad\u3002 \u4e3a\u6267\u884c\u8bca\u65ad\uff0ckubelet \u8981\u4e48\u5728\u5bb9\u5668\u5185\u6267\u884c\u4ee3\u7801\uff0c\u8981\u4e48\u53d1\u8d77\u7f51\u7edc\u8bf7\u6c42\u3002 \u4f7f\u7528\u63a2\u9488\u6709\u56db\u79cd\u4e0d\u540c\u7684\u68c0\u67e5\u5bb9\u5668\u65b9\u5f0f\u3002\u6bcf\u4e2a\u63a2\u9488\u5fc5\u987b\u6070\u597d\u5b9a\u4e49\u8fd9\u56db\u79cd\u673a\u5236\u4e2d\u7684\u4e00\u79cd\uff1a exec \u3002\u5982\u679c\u547d\u4ee4\u4ee5\u72b6\u6001\u4ee3\u7801 0 \u9000\u51fa\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 grpc \u3002\u5982\u679c\u54cd\u5e94\u7684\u72b6\u6001\u4e3a SERVING\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 httpGet \u3002\u5982\u679c\u54cd\u5e94\u7684\u72b6\u6001\u4ee3\u7801\u5927\u4e8e\u6216\u7b49\u4e8e 200 \u4e14\u5c0f\u4e8e 400\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 tcpSocket \u3002\u5982\u679c\u7aef\u53e3\u5f00\u653e\uff0c\u5219\u5c06\u8bca\u65ad\u89c6\u4e3a\u6210\u529f\u3002 \u6bcf\u4e2a\u63a2\u9488\u6709\u4e09\u79cd\u7ed3\u679c\uff1a \u6210\u529f \u5931\u8d25 \u672a\u77e5 \u63a2\u9488\u7c7b\u578b\uff1a livenessProbe \u3002\u6307\u793a\u5bb9\u5668\u662f\u5426\u6b63\u5728\u8fd0\u884c\u3002 readinessProbe \u3002\u6307\u793a\u5bb9\u5668\u662f\u5426\u51c6\u5907\u597d\u54cd\u5e94\u8bf7\u6c42\u3002 startupProbe \u3002\u6307\u793a\u5bb9\u5668\u5185\u7684\u5e94\u7528\u7a0b\u5e8f\u662f\u5426\u542f\u52a8\u3002","title":"\u5bb9\u5668\u63a2\u9488"},{"location":"k8s/cka_cn/foundamentals/memo/#deployment","text":"","title":"Deployment"},{"location":"k8s/cka_cn/foundamentals/memo/#replicaset","text":"ReplicaSet\u7684\u76ee\u7684\u662f\u5728\u4efb\u4f55\u65f6\u5019\u7ef4\u62a4\u4e00\u7ec4\u7a33\u5b9a\u7684\u526f\u672cPod\u3002\u56e0\u6b64\uff0c\u5b83\u901a\u5e38\u7528\u4e8e\u4fdd\u8bc1\u6307\u5b9a\u6570\u91cf\u7684\u76f8\u540cPod\u7684\u53ef\u7528\u6027\u3002 \u6211\u4eec\u4e00\u822c\u4e0d\u9700\u8981\u76f4\u63a5\u64cd\u7eb5ReplicaSet\u5bf9\u8c61\uff1a\u4f7f\u7528Deployment\uff0c\u7136\u540e\u5728spec\u90e8\u5206\u4e2d\u5b9a\u4e49\u60a8\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 \u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e replicaset.spec.replicas \u6765\u6307\u5b9a\u5e94\u540c\u65f6\u8fd0\u884c\u591a\u5c11\u4e2aPod\u3002 ReplicaSet\u5c06\u521b\u5efa/\u5220\u9664\u5176Pod\u4ee5\u5339\u914d\u6b64\u6570\u5b57\u3002 \u5982\u679c\u4e0d\u6307\u5b9a replicaset.spec.replicas \uff0c\u5219\u9ed8\u8ba4\u503c\u4e3a 1 \u3002","title":"ReplicaSet"},{"location":"k8s/cka_cn/foundamentals/memo/#statefulset","text":"StatefulSet \u7279\u70b9\uff08\u53c8\u79f0\u56fa\u5b9a\u6807\u8bc6\uff09\uff1a Pod \u7684\u540d\u79f0\u5728\u521b\u5efa\u540e\u4e0d\u53ef\u53d8\u3002 DNS \u4e3b\u673a\u540d\u5728\u521b\u5efa\u540e\u4e0d\u53ef\u53d8\u3002 \u6302\u8f7d\u7684\u5377\u5728\u521b\u5efa\u540e\u4e0d\u53ef\u53d8\u3002 StatefulSet \u7684\u56fa\u5b9a\u6807\u8bc6\u5728\u5931\u8d25\u3001\u6269\u5c55\u548c\u5176\u4ed6\u64cd\u4f5c\u540e\u4e0d\u4f1a\u6539\u53d8\u3002 StatefulSet \u7684\u547d\u540d\u7ea6\u5b9a\u4e3a\uff1a - \u3002 StatefulSet \u53ef\u4ee5\u81ea\u884c\u8fdb\u884c\u6269\u5c55\uff0c\u4f46\u662f Deployment \u9700\u8981\u4f9d\u9760 ReplicaSet \u8fdb\u884c\u6269\u5c55\u3002 \u5efa\u8bae\uff1a\u5148\u5c06 StatefulSet \u51cf\u5c11\u5230 0\uff0c\u800c\u4e0d\u662f\u76f4\u63a5\u5220\u9664\u5b83\u3002 headless Service \u548c governing Service\uff1a Headless Service \u662f\u4e00\u4e2a\u666e\u901a\u7684 Kubernetes Service \u5bf9\u8c61\uff0c\u5176 spec.clusterIP \u88ab\u8bbe\u7f6e\u4e3a None \u3002 \u5f53 StatefulSet \u7684 spec.ServiceName \u8bbe\u7f6e\u4e3a headless Service \u540d\u79f0\u65f6\uff0cStatefulSet \u73b0\u5728\u662f\u4e00\u4e2a governing Service\u3002 \u521b\u5efa StatefulSet \u7684\u4e00\u822c\u8fc7\u7a0b\uff1a \u521b\u5efa StorageClass\u3002 \u521b\u5efa Headless Service\u3002 \u57fa\u4e8e\u4e0a\u8ff0\u4e24\u4e2a\u521b\u5efa StatefulSet\u3002","title":"StatefulSet"},{"location":"k8s/cka_cn/foundamentals/memo/#daemonset","text":"DaemonSet\u4fdd\u8bc1\u6240\u6709\uff08\u6216\u90e8\u5206\uff09\u8282\u70b9\u8fd0\u884cPod\u7684\u526f\u672c\u3002\u968f\u7740\u8282\u70b9\u4ece\u96c6\u7fa4\u4e2d\u5220\u9664\uff0c\u8fd9\u4e9bPod\u5c06\u88ab\u5783\u573e\u56de\u6536\u3002 \u5220\u9664DaemonSet\u5c06\u6e05\u7406\u5b83\u521b\u5efa\u7684Pod\u3002 \u4e00\u4e9b\u5178\u578bDaemonSet\u7684\u7528\u9014\u5305\u62ec\uff1a \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u96c6\u7fa4\u5b58\u50a8\u5b88\u62a4\u7a0b\u5e8f\u3002 \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u65e5\u5fd7\u6536\u96c6\u5b88\u62a4\u7a0b\u5e8f\u3002 \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u8282\u70b9\u76d1\u89c6\u5b88\u62a4\u7a0b\u5e8f\u3002 \u5728\u7b80\u5355\u7684\u60c5\u51b5\u4e0b\uff0c\u6bcf\u79cd\u7c7b\u578b\u7684\u5b88\u62a4\u7a0b\u5e8f\u5c06\u4f7f\u7528\u8986\u76d6\u6240\u6709\u8282\u70b9\u7684\u4e00\u4e2aDaemonSet\u3002 \u66f4\u590d\u6742\u7684\u8bbe\u7f6e\u53ef\u80fd\u4f1a\u4e3a\u5355\u4e2a\u5b88\u62a4\u7a0b\u5e8f\u4f7f\u7528\u591a\u4e2aDaemonSet\uff0c\u4f46\u4f7f\u7528\u4e0d\u540c\u7684\u6807\u5fd7\u548c/\u6216\u4e0d\u540c\u7684\u5185\u5b58\u548cCPU\u8bf7\u6c42\u6765\u652f\u6301\u4e0d\u540c\u7684\u786c\u4ef6\u7c7b\u578b\u3002 DaemonSet\u63a7\u5236\u5668\u8c03\u548c\u8fc7\u7a0b\u540c\u65f6\u68c0\u67e5\u73b0\u6709\u8282\u70b9\u548c\u65b0\u521b\u5efa\u7684\u8282\u70b9\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cKubernetes\u8c03\u5ea6\u7a0b\u5e8f\u5ffd\u7565\u7531DamonSet\u521b\u5efa\u7684Pod\uff0c\u5e76\u5141\u8bb8\u5b83\u4eec\u5b58\u5728\u4e8e\u8282\u70b9\u4e0a\uff0c\u76f4\u5230\u5173\u95ed\u8282\u70b9\u672c\u8eab\u3002 \u5728\u9009\u62e9\u8282\u70b9\u4e0a\u8fd0\u884cPod\uff1a \u5982\u679c\u60a8\u6307\u5b9a daemonset.spec.template.spec.nodeSelector \uff0c\u90a3\u4e48DaemonSet\u63a7\u5236\u5668\u5c06\u5728\u4e0e\u8be5\u8282\u70b9\u9009\u62e9\u5668\u5339\u914d\u7684\u8282\u70b9\u4e0a\u521b\u5efaPod\u3002 \u5982\u679c\u60a8\u6307\u5b9a daemonset.spec.template.spec.affinity \uff0c\u90a3\u4e48DaemonSet\u63a7\u5236\u5668\u5c06\u5728\u4e0e\u8be5\u8282\u70b9\u4eb2\u548c\u529b\u5339\u914d\u7684\u8282\u70b9\u4e0a\u521b\u5efaPod\u3002 \u5982\u679c\u4e24\u8005\u90fd\u4e0d\u6307\u5b9a\uff0c\u5219DaemonSet\u63a7\u5236\u5668\u5c06\u5728\u6240\u6709\u8282\u70b9\u4e0a\u521b\u5efaPod\u3002 \u5728 kubectl explain daemonset.spec \u4e2d\u6ca1\u6709 replicas \u5b57\u6bb5\u4e0e kubectl explain deployment.spec.replicas \u76f8\u5bf9\u5e94\u3002\u5f53\u521b\u5efa\u4e00\u4e2aDaemonSet\u65f6\uff0c\u6bcf\u4e2a\u8282\u70b9\u5c06\u8fd0\u884c*\u4e00\u4e2a* DaemonSet Pod\u3002 \u5bf9\u4e8e\u670d\u52a1\uff0c\u901a\u5e38\u662f\u65e0\u72b6\u6001\u7684\uff0c\u4e00\u822c\u4e0d\u5173\u5fc3\u8282\u70b9\u5728\u54ea\u91cc\u8fd0\u884c\uff0c\u66f4\u5173\u5fc3Pod\u526f\u672c\u7684\u6570\u91cf\uff0c\u5e76\u4e14\u6211\u4eec\u53ef\u4ee5\u5c06\u8fd9\u4e9b\u526f\u672c/replicas\u7f29\u653e\u3002\u5728\u8fd9\u91cc\uff0c\u6eda\u52a8\u66f4\u65b0\u4e5f\u5c06\u662f\u4e00\u4e2a\u4f18\u70b9\u3002 \u5f53Pod\u7684\u4e00\u4e2a\u526f\u672c\u5fc5\u987b\u5728\u67d0\u4e2a\u6307\u5b9a\u8282\u70b9\u4e0a\u8fd0\u884c\u65f6\uff0c\u6211\u4eec\u5c06\u4f7f\u7528 DaemonSet \u3002\u6211\u4eec\u7684\u5b88\u62a4\u8fdb\u7a0bPod\u8fd8\u9700\u8981\u5728\u6211\u4eec\u7684\u5176\u4ed6Pod\u4e4b\u524d\u542f\u52a8\u3002 DaemonSet\u662f\u7528\u4e8e\u540e\u53f0\u670d\u52a1\u7684\u7b80\u5355\u53ef\u6269\u5c55\u6027\u7b56\u7565\u3002\u5f53\u66f4\u591a\u7684\u5408\u9002\u7684\u8282\u70b9\u6dfb\u52a0\u5230\u96c6\u7fa4\u65f6\uff0c\u540e\u53f0\u670d\u52a1\u5c06\u6269\u5c55\u3002\u5f53\u8282\u70b9\u88ab\u5220\u9664\u65f6\uff0c\u5b83\u5c06\u81ea\u52a8\u7f29\u5c0f\u3002","title":"DaemonSet"},{"location":"k8s/cka_cn/foundamentals/memo/#job","text":"","title":"Job"},{"location":"k8s/cka_cn/foundamentals/memo/#cronjob","text":"","title":"CronJob"},{"location":"k8s/cka_cn/foundamentals/memo/#_12","text":"","title":"\u670d\u52a1\u8d44\u6e90"},{"location":"k8s/cka_cn/foundamentals/memo/#service","text":"Service\u662f\u8f6f\u4ef6\u670d\u52a1\uff08\u4f8b\u5982mysql\uff09\u7684\u547d\u540d\u62bd\u8c61\uff0c\u7531\u4ee3\u7406\u76d1\u542c\u7684\u672c\u5730\u7aef\u53e3\uff08\u4f8b\u59823306\uff09\u548c\u786e\u5b9a\u54ea\u4e9bPod\u5c06\u56de\u7b54\u901a\u8fc7\u4ee3\u7406\u53d1\u9001\u7684\u8bf7\u6c42\u7684\u9009\u62e9\u5668\u7ec4\u6210\u3002 \u4e00\u4e2aService\u7684\u76ee\u6807Pod\u96c6\u5408\u901a\u5e38\u7531\u4e00\u4e2a\u9009\u62e9\u5668\uff08\u6807\u7b7e\u9009\u62e9\u5668\uff09\u6765\u786e\u5b9a\u3002 Service\u8d44\u6e90\u7684\u7c7b\u578b\u5305\u62ec\uff1a ClusterIP Service\uff08\u9ed8\u8ba4\uff09\uff1a\u53ef\u9760\u7684IP\u3001DNS\u548c\u7aef\u53e3\u3002\u4ec5\u9650\u5185\u90e8\u8bbf\u95ee\u3002 NodePort Service\uff1a\u5411\u5916\u90e8\u63d0\u4f9b\u8bbf\u95ee\u3002 LoadBalancer\uff1a\u57fa\u4e8eNodePort\uff0c\u5e76\u4e0e\u4e91\u4f9b\u5e94\u5546\u63d0\u4f9b\u7684\u8d1f\u8f7d\u5e73\u8861\u96c6\u6210\uff08\u4f8b\u5982AWS\u3001GCP\u7b49\uff09\u3002 ExternalName\uff1a\u8bbf\u95ee\u5c06\u88ab\u8f6c\u53d1\u5230\u5916\u90e8\u670d\u52a1\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u521b\u5efa\u7b80\u5355Service\u7684yaml\u6587\u4ef6\uff1a apiVersion : v1 kind : Service metadata : name : nginx-service labels : tier : application spec : ports : - port : 80 protocol : TCP targetPort : 8080 selector : run : nginx type : NodePort \u4e0b\u9762\u662f\u4e00\u4e2aService\u7684\u4f8b\u5b50\uff1a IP 10.96.17.77 \u662f\u8be5\u670d\u52a1\u7684 ClusterIP(VIP)\u3002 \u7aef\u53e3 80/TCP \u662f Pod \u5728\u96c6\u7fa4\u5185\u76d1\u542c\u7684\u7aef\u53e3\u3002 TargetPort 8080/TCP \u662f\u5bb9\u5668\u5185\u670d\u52a1\u5e94\u8be5\u5b9a\u5411\u6d41\u91cf\u5230\u8fbe\u7684\u7aef\u53e3\u3002 NodePort 31893/TCP \u662f\u53ef\u4ee5\u4ece\u5916\u90e8\u8bbf\u95ee\u7684\u7aef\u53e3\u3002\u9ed8\u8ba4\u8303\u56f4\u662f 30000~32767 \u3002\u8be5\u7aef\u53e3\u4f1a\u5728\u6574\u4e2a\u96c6\u7fa4\u7684\u6240\u6709\u8282\u70b9\u4e0a\u66b4\u9732\u3002 Endpoints \u663e\u793a\u4e86\u5339\u914d\u670d\u52a1\u6807\u7b7e\u7684 Pod \u5217\u8868\u3002 Name : nginx-deployment Namespace : jh-namespace Labels : tier=application Annotations : Selector : run=nginx Type : NodePort IP Family Policy : SingleStack IP Families : IPv4 IP : 10.96.17.77 IPs : 10.96.17.77 Port : 80/TCP TargetPort : 8080/TCP NodePort : 31893/TCP Endpoints : 10.244.1.177:8080,10.244.1.178:8080,10.244.1.179:8080 + 7 more... Session Affinity : None External Traffic Policy : Cluster Events : \u5728 Kubernetes \u96c6\u7fa4\u4e2d\uff0c\u57fa\u4e8eDeployment coredns \u7684Service kube-dns \u63d0\u4f9b\u4e86\u96c6\u7fa4 DNS \u670d\u52a1\u3002 \u670d\u52a1\u6ce8\u518c\uff1a Kubernetes \u4f7f\u7528\u96c6\u7fa4 DNS \u4f5c\u4e3a\u670d\u52a1\u6ce8\u518c\u3002 \u6ce8\u518c\u662f\u57fa\u4e8e Service \u800c\u975e Pod \u7684\u3002 \u96c6\u7fa4 DNS\uff08CoreDNS\uff09\u4e3b\u52a8\u76d1\u89c6\u548c\u53d1\u73b0\u65b0\u670d\u52a1\u3002 Service \u540d\u79f0\u3001IP\u3001\u7aef\u53e3\u5c06\u88ab\u6ce8\u518c\u3002 Service \u6ce8\u518c\u7684\u8fc7\u7a0b\u5982\u4e0b\uff1a \u5c06\u65b0\u7684 Service POST \u5230 API Server\u3002 \u4e3a\u65b0\u7684 Service \u5206\u914d ClusterIP\u3002 \u5c06\u65b0\u7684 Service \u914d\u7f6e\u4fe1\u606f\u4fdd\u5b58\u5230 etcd \u4e2d\u3002 \u521b\u5efa\u4e0e\u65b0 Service \u5173\u8054\u7684\u5e26\u6709\u76f8\u5173 Pod IP \u7684 endpoints\u3002 \u901a\u8fc7 ClusterDNS \u63a2\u7d22\u65b0\u7684 Service\u3002 \u521b\u5efa DNS \u4fe1\u606f\u3002 kube-proxy \u83b7\u53d6 Service \u914d\u7f6e\u4fe1\u606f\u3002 \u521b\u5efa IPSV \u89c4\u5219\u3002 Service \u53d1\u73b0\u7684\u8fc7\u7a0b\u3002 \u8bf7\u6c42\u4e00\u4e2a Service \u540d\u79f0\u7684 DNS \u540d\u79f0\u89e3\u6790\u3002 \u6536\u5230 ClusterIP\u3002 \u8bbf\u95ee ClusterIP\u3002 \u6ca1\u6709\u8def\u7531\u5668\u3002\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230 Pod \u7684\u9ed8\u8ba4\u7f51\u5173\u3002 \u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u8282\u70b9\u3002 \u6ca1\u6709\u8def\u7531\u5668\u3002\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u8282\u70b9\u7684\u9ed8\u8ba4\u7f51\u5173\u3002 \u8282\u70b9\u5185\u6838\u7ee7\u7eed\u5904\u7406\u8bf7\u6c42\u3002 \u4f7f\u7528 IPSV \u89c4\u5219\u6355\u83b7\u8bf7\u6c42\u3002 \u5c06\u76ee\u6807 Pod \u7684 IP \u653e\u5165\u8bf7\u6c42\u7684\u76ee\u6807 IP \u4e2d\u3002 \u8bf7\u6c42\u5230\u8fbe\u76ee\u6807 Pod\u3002 FQDN\u683c\u5f0f\u4e3a\uff1a ..svc.cluster.local \u3002\u6211\u4eec\u79f0 \u4e3a\u975e\u9650\u5b9a\u540d\u79f0\u6216\u7b80\u77ed\u540d\u79f0\u3002 \u547d\u540d\u7a7a\u95f4\u53ef\u4ee5\u9694\u79bb\u96c6\u7fa4\u7684\u5730\u5740\u7a7a\u95f4\u3002\u540c\u65f6\uff0c\u5b83\u8fd8\u53ef\u4ee5\u7528\u4e8e\u5b9e\u73b0\u8bbf\u95ee\u63a7\u5236\u548c\u8d44\u6e90\u914d\u989d\u3002 \u83b7\u53d6Pod\u4e2d\u7684DNS\u914d\u7f6e\u3002 nameserver\u7684IP\u4e0ekube-dns\u670d\u52a1\u7684ClusterIP\u76f8\u540c\uff0c\u8fd9\u662f\u7528\u4e8eDNS\u8bf7\u6c42\u6216\u670d\u52a1\u53d1\u73b0\u8bf7\u6c42\u7684\u4f17\u6240\u5468\u77e5\u7684IP\u3002 $ kubectl get service kube-dns -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT ( S ) AGE kube-dns ClusterIP 10 .96.0.10 53 /UDP,53/TCP,9153/TCP 7d7h $ kubectl exec -it nginx-5f5496dc9-bv5dx -- /bin/bash root@nginx-5f5496dc9-bv5dx:/# cat /etc/resolv.conf search jh-namespace.svc.cluster.local svc.cluster.local cluster.local nameserver 10 .96.0.10 options ndots:5 \u8bfb\u53d6 kube-dns \u4fe1\u606f\uff1a $ kubectl describe service kube-dns -n kube-system Name: kube-dns Namespace: kube-system Labels: k8s-app = kube-dns kubernetes.io/cluster-service = true kubernetes.io/name = CoreDNS Annotations: prometheus.io/port: 9153 prometheus.io/scrape: true Selector: k8s-app = kube-dns Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: 10 .96.0.10 IPs: 10 .96.0.10 Port: dns 53 /UDP TargetPort: 53 /UDP Endpoints: 10 .244.0.2:53,10.244.0.3:53 Port: dns-tcp 53 /TCP TargetPort: 53 /TCP Endpoints: 10 .244.0.2:53,10.244.0.3:53 Port: metrics 9153 /TCP TargetPort: 9153 /TCP Endpoints: 10 .244.0.2:9153,10.244.0.3:9153 Session Affinity: None Events: ","title":"Service"},{"location":"k8s/cka_cn/foundamentals/memo/#endpoints","text":"Endpoints\u662f\u4e00\u7ec4\u5b9e\u73b0\u5b9e\u9645\u670d\u52a1\u7684\u7aef\u70b9\u96c6\u5408\u3002 \u5f53\u521b\u5efa\u670d\u52a1\u65f6\uff0c\u5b83\u4f1a\u4e0e\u4e00\u4e2aEndpoint\u5bf9\u8c61\u76f8\u5173\u8054\uff0c\u53ef\u4ee5\u4f7f\u7528\u547d\u4ee4 kubectl get endpoints \u83b7\u53d6\u3002 \u5339\u914d\u670d\u52a1\u6807\u7b7e\u7684Pod\u5217\u8868\u7ef4\u62a4\u4e3aEndpoint\u5bf9\u8c61\uff0c\u6dfb\u52a0\u65b0\u7684\u5339\u914dPod\u5e76\u5220\u9664\u4e0d\u5339\u914d\u7684Pod\u3002","title":"Endpoints"},{"location":"k8s/cka_cn/foundamentals/memo/#_13","text":"","title":"\u914d\u7f6e\u548c\u5b58\u50a8\u8d44\u6e90"},{"location":"k8s/cka_cn/foundamentals/memo/#_14","text":"","title":"\u5377"},{"location":"k8s/cka_cn/foundamentals/memo/#emptydir","text":"emptyDir \u5377\u662f\u5728Pod\u5206\u914d\u5230\u8282\u70b9\u65f6\u9996\u5148\u521b\u5efa\u7684\uff0c\u5e76\u4e14\u53ea\u8981\u8be5Pod\u5728\u8be5\u8282\u70b9\u4e0a\u8fd0\u884c\uff0c\u5b83\u5c31\u4f1a\u5b58\u5728\u3002 emptyDir \u5377\u6700\u521d\u4e3a\u7a7a\u3002 Pod\u4e2d\u7684\u6240\u6709\u5bb9\u5668\u90fd\u53ef\u4ee5\u8bfb\u53d6\u548c\u5199\u5165 emptyDir \u5377\u4e2d\u7684\u76f8\u540c\u6587\u4ef6\uff0c\u5c3d\u7ba1\u8be5\u5377\u53ef\u4ee5\u5728\u6bcf\u4e2a\u5bb9\u5668\u4e2d\u4ee5\u76f8\u540c\u6216\u4e0d\u540c\u7684\u8def\u5f84\u6302\u8f7d\u3002 \u5f53\u7531\u4e8e\u4efb\u4f55\u539f\u56e0\u4ece\u8282\u70b9\u4e2d\u5220\u9664Pod\u65f6\uff0c emptyDir \u4e2d\u7684\u6570\u636e\u5c06\u6c38\u4e45\u5220\u9664\u3002 \u5bb9\u5668\u5d29\u6e83\u4e0d\u4f1a\u5c06Pod\u4ece\u8282\u70b9\u4e2d\u5220\u9664\u3002 emptyDir \u5377\u4e2d\u7684\u6570\u636e\u53ef\u4ee5\u5728\u5bb9\u5668\u5d29\u6e83\u65f6\u5b89\u5168\u4fdd\u7559\u3002 \u7528\u9014\uff1a \u4e34\u65f6\u7a7a\u95f4\uff0c\u4f8b\u5982\u57fa\u4e8e\u78c1\u76d8\u7684\u5f52\u5e76\u6392\u5e8f \u4e3a\u4e86\u4ece\u5d29\u6e83\u4e2d\u6062\u590d\u800c\u8fdb\u884c\u7684\u957f\u65f6\u95f4\u8ba1\u7b97\u7684\u68c0\u67e5\u70b9 \u4fdd\u5b58\u5185\u5bb9\u7ba1\u7406\u5668\u5bb9\u5668\u63d0\u53d6\u7684\u6587\u4ef6\uff0c\u540c\u65f6Web\u670d\u52a1\u5668\u5bb9\u5668\u63d0\u4f9b\u6570\u636e","title":"emptyDir"},{"location":"k8s/cka_cn/foundamentals/memo/#hostpath","text":"hostPath \u5377\u5c06\u4e3b\u673a\u8282\u70b9\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u6302\u8f7d\u5230 Pod \u4e2d\u3002\u8fd9\u4e0d\u662f\u5927\u591a\u6570 Pod \u90fd\u9700\u8981\u7684\uff0c\u4f46\u5bf9\u4e8e\u67d0\u4e9b\u5e94\u7528\u7a0b\u5e8f\u6765\u8bf4\uff0c\u5b83\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5f3a\u5927\u7684\u9003\u751f\u53e3\u3002 hostPath \u5377\u5b58\u5728\u8bb8\u591a\u5b89\u5168\u98ce\u9669\uff0c\u56e0\u6b64\u5728\u53ef\u80fd\u7684\u60c5\u51b5\u4e0b\u6700\u597d\u907f\u514d\u4f7f\u7528 HostPath\u3002\u5f53\u5fc5\u987b\u4f7f\u7528 HostPath \u5377\u65f6\uff0c\u5e94\u5c06\u5176\u8303\u56f4\u9650\u5b9a\u4e3a\u4ec5\u6240\u9700\u7684\u6587\u4ef6\u6216\u76ee\u5f55\uff0c\u5e76\u4ee5\u53ea\u8bfb\u65b9\u5f0f\u6302\u8f7d\u3002 \u5982\u679c\u901a\u8fc7 AdmissionPolicy \u9650\u5236 HostPath \u8bbf\u95ee\u7279\u5b9a\u76ee\u5f55\uff0c\u5219\u5fc5\u987b\u8981\u6c42 volumeMounts \u4f7f\u7528 readOnly \u6302\u8f7d\uff0c\u4ee5\u4f7f\u7b56\u7565\u751f\u6548\u3002 \u7528\u9014\uff1a \u4e0e DaemonSet \u4e00\u8d77\u8fd0\u884c\uff0c\u4f8b\u5982\uff0cEFK Fluentd \u6302\u8f7d\u672c\u5730\u4e3b\u673a\u7684\u65e5\u5fd7\u76ee\u5f55\u4ee5\u6536\u96c6\u4e3b\u673a\u65e5\u5fd7\u4fe1\u606f\u3002 \u901a\u8fc7\u4f7f\u7528 hostPath \u5377\u5728\u7279\u5b9a\u8282\u70b9\u4e0a\u8fd0\u884c\uff0c\u53ef\u4ee5\u83b7\u5f97\u9ad8\u6027\u80fd\u7684\u78c1\u76d8 I/O\u3002 \u8fd0\u884c\u9700\u8981\u8bbf\u95ee Docker \u5185\u90e8\u7684\u5bb9\u5668\uff1b\u4f7f\u7528 /var/lib/docker \u7684 hostPath\u3002 \u5728\u5bb9\u5668\u4e2d\u8fd0\u884c cAdvisor\uff1b\u4f7f\u7528 /sys \u7684 hostPath\u3002 \u5141\u8bb8 Pod \u6307\u5b9a\u7ed9\u5b9a\u7684 hostPath \u662f\u5426\u5e94\u8be5\u5728 Pod \u8fd0\u884c\u4e4b\u524d\u5b58\u5728\uff0c\u662f\u5426\u5e94\u8be5\u521b\u5efa\u5b83\u4ee5\u53ca\u5b83\u5e94\u8be5\u5b58\u5728\u7684\u5185\u5bb9\u3002","title":"hostPath"},{"location":"k8s/cka_cn/foundamentals/memo/#storage-class","text":"StorageClass \u90e8\u7f72\u548c\u5b9e\u73b0\u7684\u6b65\u9aa4\u5982\u4e0b\uff1a \u521b\u5efa Kubernetes \u96c6\u7fa4\u548c\u540e\u7aef\u5b58\u50a8\u3002 \u786e\u4fdd Kubernetes \u4e2d\u7684 provisioner/plugin \u53ef\u7528\u3002 \u521b\u5efa\u4e00\u4e2a StorageClass \u5bf9\u8c61\u5e76\u5c06\u5176\u94fe\u63a5\u5230\u540e\u7aef\u5b58\u50a8\u3002StorageClass \u5c06\u81ea\u52a8\u521b\u5efa\u76f8\u5173\u7684 PV\u3002 \u521b\u5efa\u4e00\u4e2a PVC \u5bf9\u8c61\u5e76\u5c06\u5176\u94fe\u63a5\u5230\u6211\u4eec\u521b\u5efa\u7684 StorageClass\u3002 \u90e8\u7f72\u4e00\u4e2a Pod \u5e76\u4f7f\u7528 PVC \u5377\u3002","title":"Storage Class"},{"location":"k8s/cka_cn/foundamentals/memo/#pv","text":"PV\u56de\u6536\u7b56\u7565\uff1a \u4fdd\u7559 (Retain) \u5220\u9664 (Delete) \u56de\u6536 (Recycle) PV in-tree\u7c7b\u578b\uff1a hostPath local NFS CSI","title":"PV"},{"location":"k8s/cka_cn/foundamentals/memo/#access-modes","text":"Access Modes\uff08\u8bbf\u95ee\u6a21\u5f0f\uff09\u4e2d\uff0c spec.accessModes \u5b9a\u4e49\u4e86 PV \u7684\u6302\u8f7d\u9009\u9879\uff1a ReadWriteOnce(RWO)\uff1a\u4e00\u4e2a PV \u53ea\u80fd\u88ab\u4e00\u4e2a\u8bfb\u5199\u6a21\u5f0f\u7684 PVC \u6302\u8f7d\uff0c\u7c7b\u4f3c\u4e8e\u5757\u8bbe\u5907\u3002 ReadWriteMany(RWM)\uff1a\u4e00\u4e2a PV \u53ef\u4ee5\u88ab\u591a\u4e2a\u8bfb\u5199\u6a21\u5f0f\u7684 PVC \u6302\u8f7d\uff0c\u4f8b\u5982 NFS\u3002 ReadOnlyMany(ROM)\uff1a\u4e00\u4e2a PV \u53ef\u4ee5\u88ab\u591a\u4e2a\u53ea\u8bfb\u6a21\u5f0f\u7684 PVC \u6302\u8f7d\u3002 ReadWriteOncePod(RWOP)\uff1a\u53ea\u652f\u6301 CSI \u7c7b\u578b\u7684 PV\uff0c\u53ea\u80fd\u88ab\u5355\u4e2a Pod \u6302\u8f7d\u3002 \u4e00\u4e2a PV \u53ea\u80fd\u8bbe\u7f6e\u4e00\u79cd\u9009\u9879\u3002Pod \u6302\u8f7d PVC\uff0c\u800c\u4e0d\u662f PV\u3002","title":"Access Modes"},{"location":"k8s/cka_cn/foundamentals/namespace/","text":"CKA\u81ea\u5b66\u7b14\u8bb011:Namespace \u00b6 \u6f14\u793a\u573a\u666f \u00b6 \u83b7\u53d6namespace\u5217\u8868 \u521b\u5efa\u65b0\u7684namespace \u7ed9namespace\u8bbe\u5b9a\u6807\u7b7e \u5220\u9664\u4e00\u4e2anamespace \u6f14\u793a \u00b6 \u83b7\u53d6\u5f53\u524dnamespace\u5217\u8868\u3002 kubectl get namespace \u83b7\u53d6\u5f53\u524dnamespace\u5217\u8868\u548c\u5bf9\u5e94\u6807\u7b7e\u4fe1\u606f\u3002 kubectl get ns --show-labels \u521b\u5efa\u4e00\u4e2anamespace cka \u3002 kubectl create namespace cka \u7ed9\u65b0\u521b\u5efa\u7684namespace cka \u8bbe\u5b9a\u6807\u7b7e\u3002 kubectl label ns cka cka = true \u5728namespace cka \u4e0a\u521b\u5efa Nginx Deployment\u3002 kubectl create deploy nginx --image = nginx --namespace cka \u5728namespace cka \u4e0a\u68c0\u67e5\u6b63\u5728\u8fd0\u884c\u7684deployment\u548cpod\u3002 kubectl get deploy,pod -n cka \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx 1/1 1 1 2m14s NAME READY STATUS RESTARTS AGE pod/nginx-85b98978db-bmkhf 1/1 Running 0 2m14s \u5220\u9664namespace cka \uff0c\u5219\u6240\u6709\u8fd0\u884c\u5728\u8fd9\u4e2anamespace\u4e0a\u7684\u8d44\u6e90\u90fd\u4f1a\u88ab\u5220\u9664\u3002 kubectl delete ns cka \u5982\u679c\u5728\u5220\u9664\u67d0\u4e2anamespace\u65f6\u9047\u5230\u72b6\u6001\u4e00\u76f4\u662f Terminating \uff0c\u5219\u53ef\u4ee5\u5c1d\u8bd5\u7528\u4e0b\u9762\u7684\u65b9\u6cd5\u89e3\u51b3\u3002 kubectl get namespace $NAMESPACE -o json | sed -e 's/\"kubernetes\"//' | kubectl replace --raw \"/api/v1/namespaces $NAMESPACE /finalize\" -f -","title":"Namespace"},{"location":"k8s/cka_cn/foundamentals/namespace/#cka11namespace","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb011:Namespace"},{"location":"k8s/cka_cn/foundamentals/namespace/#_1","text":"\u83b7\u53d6namespace\u5217\u8868 \u521b\u5efa\u65b0\u7684namespace \u7ed9namespace\u8bbe\u5b9a\u6807\u7b7e \u5220\u9664\u4e00\u4e2anamespace","title":"\u6f14\u793a\u573a\u666f"},{"location":"k8s/cka_cn/foundamentals/namespace/#_2","text":"\u83b7\u53d6\u5f53\u524dnamespace\u5217\u8868\u3002 kubectl get namespace \u83b7\u53d6\u5f53\u524dnamespace\u5217\u8868\u548c\u5bf9\u5e94\u6807\u7b7e\u4fe1\u606f\u3002 kubectl get ns --show-labels \u521b\u5efa\u4e00\u4e2anamespace cka \u3002 kubectl create namespace cka \u7ed9\u65b0\u521b\u5efa\u7684namespace cka \u8bbe\u5b9a\u6807\u7b7e\u3002 kubectl label ns cka cka = true \u5728namespace cka \u4e0a\u521b\u5efa Nginx Deployment\u3002 kubectl create deploy nginx --image = nginx --namespace cka \u5728namespace cka \u4e0a\u68c0\u67e5\u6b63\u5728\u8fd0\u884c\u7684deployment\u548cpod\u3002 kubectl get deploy,pod -n cka \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx 1/1 1 1 2m14s NAME READY STATUS RESTARTS AGE pod/nginx-85b98978db-bmkhf 1/1 Running 0 2m14s \u5220\u9664namespace cka \uff0c\u5219\u6240\u6709\u8fd0\u884c\u5728\u8fd9\u4e2anamespace\u4e0a\u7684\u8d44\u6e90\u90fd\u4f1a\u88ab\u5220\u9664\u3002 kubectl delete ns cka \u5982\u679c\u5728\u5220\u9664\u67d0\u4e2anamespace\u65f6\u9047\u5230\u72b6\u6001\u4e00\u76f4\u662f Terminating \uff0c\u5219\u53ef\u4ee5\u5c1d\u8bd5\u7528\u4e0b\u9762\u7684\u65b9\u6cd5\u89e3\u51b3\u3002 kubectl get namespace $NAMESPACE -o json | sed -e 's/\"kubernetes\"//' | kubectl replace --raw \"/api/v1/namespaces $NAMESPACE /finalize\" -f -","title":"\u6f14\u793a"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/","text":"CKA\u81ea\u5b66\u7b14\u8bb023:Network Policy \u00b6 \u7528Calico\u66ff\u6362Flannel \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u5378\u8f7dFlannel \u5b89\u88c5Calico \u6f14\u793a\uff1a \u5982\u679c\u5728\u5b89\u88c5\u8fc7\u7a0b\u4e2d\u5df2\u7ecf\u5b89\u88c5\u4e86 Calico\uff0c\u5219\u53ef\u4ee5\u5ffd\u7565\u8fd9\u90e8\u5206\u5185\u5bb9\u3002 \u5378\u8f7dFlannel kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/v0.18.1/Documentation/kube-flannel.yml \u6216\u8005 kubectl delete -f kube-flannel.yml \u8f93\u51fa\uff1a Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy \"psp.flannel.unprivileged\" deleted clusterrole.rbac.authorization.k8s.io \"flannel\" deleted clusterrolebinding.rbac.authorization.k8s.io \"flannel\" deleted serviceaccount \"flannel\" deleted configmap \"kube-flannel-cfg\" deleted daemonset.apps \"kube-flannel-ds\" deleted \u5728\u6240\u6709\u8282\u70b9\u4e0a\u6e05\u9664iptables\u8bbe\u7f6e\u3002 rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u91cd\u65b0\u767b\u5f55\u4e3b\u673a\u8282\u70b9\uff0c\u4f8b\u5982 cka001 \uff0c\u5b89\u88c5Calico\uff0c curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Output: configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created \u9a8c\u8bc1Calico\u5b89\u88c5\u72b6\u6001\uff0c\u786e\u4fdd\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u90fd\u6b63\u5e38\u8fd0\u884c\u3002 kubectl get pod -n kube-system | grep calico \u8f93\u51fa\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE calico-kube-controllers-7bc6547ffb-tjfcg 1/1 Running 0 30m calico-node-7x8jm 1/1 Running 0 30m calico-node-cwxj5 1/1 Running 0 30m calico-node-rq978 1/1 Running 0 30m \u5982\u679c\u9047\u5230\u4efb\u4f55\u9519\u8bef\uff0c\u9996\u5148\u68c0\u67e5\u5bb9\u5668container\u65e5\u5fd7\u3002 # Get Container ID crictl ps # Get log info crictl logs \u7531\u4e8e\u6211\u4eec\u5c06 CNI \u4ece Flannel \u66f4\u6539\u4e3a Calico\uff0c\u6211\u4eec\u9700\u8981\u5220\u9664\u6240\u6709 Pod\uff0c\u6240\u6709 Pod \u90fd\u5c06\u81ea\u52a8\u91cd\u65b0\u521b\u5efa\u3002 kubectl delete pod -A --all \u67e5\u8be2\u6240\u6709pod\u90fd\u72b6\u6001\uff0c\u786e\u4fdd\u4ed6\u4eec\u90fd\u6b63\u5e38\u8fd0\u884c\u3002 kubectl get pod -A \u5165\u7ad9\u89c4\u5219\uff08Inbound Rules\uff09 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u7528\u4e8e\u6d4b\u8bd5\u7684\u5de5\u4f5c\u8d1f\u8f7d\u3002 \u7981\u6b62\u6240\u6709\u5165\u7ad9\u6d41\u91cf\u3002 \u5141\u8bb8\u7279\u5b9a\u7684\u5165\u7ad9\u6d41\u91cf\u3002 \u9a8c\u8bc1NetworkPolicy\u3002 \u521b\u5efa\u6d4b\u8bd5\u5de5\u4f5c\u8d1f\u8f7d \u00b6 \u521b\u5efa\u4e09\u4e2a Deployment\uff0c\u540d\u79f0\u4e3a pod-netpol-1 \u3001 pod-netpol-2 \u548c pod-netpol-3 \uff0c\u5b83\u4eec\u90fd\u57fa\u4e8e\u955c\u50cf busybox \u3002 kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-1 name: pod-netpol-1 spec: replicas: 1 selector: matchLabels: app: pod-netpol-1 template: metadata: labels: app: pod-netpol-1 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-2 name: pod-netpol-2 spec: replicas: 1 selector: matchLabels: app: pod-netpol-2 template: metadata: labels: app: pod-netpol-2 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-3 name: pod-netpol-3 spec: replicas: 1 selector: matchLabels: app: pod-netpol-3 template: metadata: labels: app: pod-netpol-3 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] EOF \u68c0\u67e5pod\u7684IP\u5730\u5740\uff1a kubectl get pod -owide \u8f93\u51fa\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-netpol-1-6494f6bf8b-n58r9 1/1 Running 0 29s 10.244.102.30 cka003 pod-netpol-2-77478d77ff-l6rzm 1/1 Running 0 29s 10.244.112.30 cka002 pod-netpol-3-68977dcb48-ql5s6 1/1 Running 0 29s 10.244.102.31 cka003 \u767b\u5f55\u8fdb\u5165pod pod-netpol-1 \u3002 kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh \u6267\u884c\u547d\u4ee4 ping \uff0c\u786e\u4fdd pod-netpol-2 \u548c pod-netpol-3 \u53ef\u4e92\u76f8\u8bbf\u95ee\u3002 / # ping 10.244.112.30 3 packets transmitted, 3 packets received, 0 % packet loss / # ping 10.244.102.31 3 packets transmitted, 3 packets received, 0 % packet loss \u7981\u6b62\u6240\u6709\u5165\u7ad9\u6d41\u91cf \u00b6 \u521b\u5efa\u7b56\u7565\uff0c\u7981\u6b62\u6240\u6709\u5165\u7ad9\u6d41\u91cf\u3002 kubectl apply -f - << EOF apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-ingress spec: podSelector: {} policyTypes: - Ingress EOF \u518d\u6b21\u767b\u5f55\u8fdb\u5165pod pod-netpol-1 \u3002 kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh Execute command ping that pod-netpol-2 and pod-netpol-3 are both unreachable as expected. \u6267\u884c\u547d\u4ee4 ping \uff0c\u548c\u6211\u4eec\u9884\u671f\u4e00\u6837\uff0c pod-netpol-2 \u548c pod-netpol-3 \u6b64\u65f6\u4e92\u76f8\u65e0\u6cd5\u8bbf\u95ee\u3002 / # ping 10.244.112.30 3 packets transmitted, 0 packets received, 100 % packet loss / # ping 10.244.102.31 3 packets transmitted, 0 packets received, 100 % packet loss \u5141\u8bb8\u7279\u5b9a\u7684\u5165\u7ad9\u6d41\u91cf \u00b6 \u521b\u5efa NetworkPolicy\uff0c\u5141\u8bb8\u6765\u81ea pod-netpol-1 \u5230 pod-netpol-2 \u7684\u5165\u7ad9\u6d41\u91cf\u3002 kubectl apply -f - <:80 \u5931\u8d25 \u8fd0\u884c curl :80 \u6210\u529f kubectl run centos --image = centos -n my-ns-1 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-1 -- bash \u5728namespace my-ns-2 \u4e2d\u521b\u5efa\u4e00\u4e2a\u4e34\u65f6 Pod\uff0c\u7136\u540e\u8fde\u63a5\u5230\u8be5 Pod \u5e76\u9a8c\u8bc1\u8bbf\u95ee\u3002 \u547d\u4ee4 curl :80 \u5931\u8d25 \u547d\u4ee4 curl :80 \u5931\u8d25\u3002 kubectl run centos --image = centos -n my-ns-2 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-2 -- bash \u4fee\u6539 my-networkpolicy-1 \uff0c \u628a ingress.from.namespaceSelector.matchLabels \u7684\u503c\u6539\u4e3a my-ns-2 \u3002 \u767b\u5f55\u8fdb\u5165namespace my-ns-2 \u4e0a\u7684\u4e34\u65f6pod\uff0c\u9a8c\u8bc1\u8bbf\u95ee\u3002 \u547d\u4ee4 curl :80 \u5931\u8d25 \u547d\u4ee4 curl :80 \u6210\u529f kubectl exec -it mycentos -n my-ns-2 -- bash \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete namespace my-ns-1 kubectl delete namespace my-ns-2","title":"Network Policy"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/#cka23network-policy","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb023:Network Policy"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/#calicoflannel","text":"\u6f14\u793a\u573a\u666f\uff1a \u5378\u8f7dFlannel \u5b89\u88c5Calico \u6f14\u793a\uff1a \u5982\u679c\u5728\u5b89\u88c5\u8fc7\u7a0b\u4e2d\u5df2\u7ecf\u5b89\u88c5\u4e86 Calico\uff0c\u5219\u53ef\u4ee5\u5ffd\u7565\u8fd9\u90e8\u5206\u5185\u5bb9\u3002 \u5378\u8f7dFlannel kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/v0.18.1/Documentation/kube-flannel.yml \u6216\u8005 kubectl delete -f kube-flannel.yml \u8f93\u51fa\uff1a Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy \"psp.flannel.unprivileged\" deleted clusterrole.rbac.authorization.k8s.io \"flannel\" deleted clusterrolebinding.rbac.authorization.k8s.io \"flannel\" deleted serviceaccount \"flannel\" deleted configmap \"kube-flannel-cfg\" deleted daemonset.apps \"kube-flannel-ds\" deleted \u5728\u6240\u6709\u8282\u70b9\u4e0a\u6e05\u9664iptables\u8bbe\u7f6e\u3002 rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u91cd\u65b0\u767b\u5f55\u4e3b\u673a\u8282\u70b9\uff0c\u4f8b\u5982 cka001 \uff0c\u5b89\u88c5Calico\uff0c curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Output: configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created \u9a8c\u8bc1Calico\u5b89\u88c5\u72b6\u6001\uff0c\u786e\u4fdd\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u90fd\u6b63\u5e38\u8fd0\u884c\u3002 kubectl get pod -n kube-system | grep calico \u8f93\u51fa\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE calico-kube-controllers-7bc6547ffb-tjfcg 1/1 Running 0 30m calico-node-7x8jm 1/1 Running 0 30m calico-node-cwxj5 1/1 Running 0 30m calico-node-rq978 1/1 Running 0 30m \u5982\u679c\u9047\u5230\u4efb\u4f55\u9519\u8bef\uff0c\u9996\u5148\u68c0\u67e5\u5bb9\u5668container\u65e5\u5fd7\u3002 # Get Container ID crictl ps # Get log info crictl logs \u7531\u4e8e\u6211\u4eec\u5c06 CNI \u4ece Flannel \u66f4\u6539\u4e3a Calico\uff0c\u6211\u4eec\u9700\u8981\u5220\u9664\u6240\u6709 Pod\uff0c\u6240\u6709 Pod \u90fd\u5c06\u81ea\u52a8\u91cd\u65b0\u521b\u5efa\u3002 kubectl delete pod -A --all \u67e5\u8be2\u6240\u6709pod\u90fd\u72b6\u6001\uff0c\u786e\u4fdd\u4ed6\u4eec\u90fd\u6b63\u5e38\u8fd0\u884c\u3002 kubectl get pod -A","title":"\u7528Calico\u66ff\u6362Flannel"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/#inbound-rules","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u7528\u4e8e\u6d4b\u8bd5\u7684\u5de5\u4f5c\u8d1f\u8f7d\u3002 \u7981\u6b62\u6240\u6709\u5165\u7ad9\u6d41\u91cf\u3002 \u5141\u8bb8\u7279\u5b9a\u7684\u5165\u7ad9\u6d41\u91cf\u3002 \u9a8c\u8bc1NetworkPolicy\u3002","title":"\u5165\u7ad9\u89c4\u5219\uff08Inbound Rules\uff09"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/#_1","text":"\u521b\u5efa\u4e09\u4e2a Deployment\uff0c\u540d\u79f0\u4e3a pod-netpol-1 \u3001 pod-netpol-2 \u548c pod-netpol-3 \uff0c\u5b83\u4eec\u90fd\u57fa\u4e8e\u955c\u50cf busybox \u3002 kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-1 name: pod-netpol-1 spec: replicas: 1 selector: matchLabels: app: pod-netpol-1 template: metadata: labels: app: pod-netpol-1 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-2 name: pod-netpol-2 spec: replicas: 1 selector: matchLabels: app: pod-netpol-2 template: metadata: labels: app: pod-netpol-2 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-3 name: pod-netpol-3 spec: replicas: 1 selector: matchLabels: app: pod-netpol-3 template: metadata: labels: app: pod-netpol-3 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] EOF \u68c0\u67e5pod\u7684IP\u5730\u5740\uff1a kubectl get pod -owide \u8f93\u51fa\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-netpol-1-6494f6bf8b-n58r9 1/1 Running 0 29s 10.244.102.30 cka003 pod-netpol-2-77478d77ff-l6rzm 1/1 Running 0 29s 10.244.112.30 cka002 pod-netpol-3-68977dcb48-ql5s6 1/1 Running 0 29s 10.244.102.31 cka003 \u767b\u5f55\u8fdb\u5165pod pod-netpol-1 \u3002 kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh \u6267\u884c\u547d\u4ee4 ping \uff0c\u786e\u4fdd pod-netpol-2 \u548c pod-netpol-3 \u53ef\u4e92\u76f8\u8bbf\u95ee\u3002 / # ping 10.244.112.30 3 packets transmitted, 3 packets received, 0 % packet loss / # ping 10.244.102.31 3 packets transmitted, 3 packets received, 0 % packet loss","title":"\u521b\u5efa\u6d4b\u8bd5\u5de5\u4f5c\u8d1f\u8f7d"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/#_2","text":"\u521b\u5efa\u7b56\u7565\uff0c\u7981\u6b62\u6240\u6709\u5165\u7ad9\u6d41\u91cf\u3002 kubectl apply -f - << EOF apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-ingress spec: podSelector: {} policyTypes: - Ingress EOF \u518d\u6b21\u767b\u5f55\u8fdb\u5165pod pod-netpol-1 \u3002 kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh Execute command ping that pod-netpol-2 and pod-netpol-3 are both unreachable as expected. \u6267\u884c\u547d\u4ee4 ping \uff0c\u548c\u6211\u4eec\u9884\u671f\u4e00\u6837\uff0c pod-netpol-2 \u548c pod-netpol-3 \u6b64\u65f6\u4e92\u76f8\u65e0\u6cd5\u8bbf\u95ee\u3002 / # ping 10.244.112.30 3 packets transmitted, 0 packets received, 100 % packet loss / # ping 10.244.102.31 3 packets transmitted, 0 packets received, 100 % packet loss","title":"\u7981\u6b62\u6240\u6709\u5165\u7ad9\u6d41\u91cf"},{"location":"k8s/cka_cn/foundamentals/networkpolicy/#_3","text":"\u521b\u5efa NetworkPolicy\uff0c\u5141\u8bb8\u6765\u81ea pod-netpol-1 \u5230 pod-netpol-2 \u7684\u5165\u7ad9\u6d41\u91cf\u3002 kubectl apply -f - <:80 \u5931\u8d25 \u8fd0\u884c curl :80 \u6210\u529f kubectl run centos --image = centos -n my-ns-1 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-1 -- bash \u5728namespace my-ns-2 \u4e2d\u521b\u5efa\u4e00\u4e2a\u4e34\u65f6 Pod\uff0c\u7136\u540e\u8fde\u63a5\u5230\u8be5 Pod \u5e76\u9a8c\u8bc1\u8bbf\u95ee\u3002 \u547d\u4ee4 curl :80 \u5931\u8d25 \u547d\u4ee4 curl :80 \u5931\u8d25\u3002 kubectl run centos --image = centos -n my-ns-2 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-2 -- bash \u4fee\u6539 my-networkpolicy-1 \uff0c \u628a ingress.from.namespaceSelector.matchLabels \u7684\u503c\u6539\u4e3a my-ns-2 \u3002 \u767b\u5f55\u8fdb\u5165namespace my-ns-2 \u4e0a\u7684\u4e34\u65f6pod\uff0c\u9a8c\u8bc1\u8bbf\u95ee\u3002 \u547d\u4ee4 curl :80 \u5931\u8d25 \u547d\u4ee4 curl :80 \u6210\u529f kubectl exec -it mycentos -n my-ns-2 -- bash \u5220\u9664\u6f14\u793a\u4e2d\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete namespace my-ns-1 kubectl delete namespace my-ns-2","title":"NetworkPolicy"},{"location":"k8s/cka_cn/foundamentals/overview/","text":"CKA\u81ea\u5b66\u7b14\u8bb06:Kubernetes\u96c6\u7fa4\u6982\u89c8 \u00b6 \u6458\u8981 \u00b6 \u5305\u542b\u4e0b\u9762\u5185\u5bb9\uff1a \u5bb9\u5668\u5c42 Kubernetes\u5c42 \u63d0\u793a\uff1a \u540e\u7eed\u5b9e\u9a8c\u73af\u5883\u90fd\u662f\u4f7f\u7528\u5728\u963f\u91cc\u4e91\u90e8\u7f72\u7684Ubuntu\u4e09\u8282\u70b9\u96c6\u7fa4\uff0c\u4e09\u4e2a\u8282\u70b9\u5206\u522b\u4e3a cka001 \u3001 cka002 \u548c cka003 \u3002 \u5bb9\u5668\u5c42 \u00b6 \u573a\u666f\uff1a \u4f7f\u7528Containerd\u670d\u52a1\uff0c\u901a\u8fc7\u547d\u4ee4 nerdctl \u6765\u7ba1\u7406\u6211\u4eec\u7684\u955c\u50cf\u548c\u5bb9\u5668\uff0c\u8fd9\u4e0eDocker\u7684\u6982\u5ff5\u76f8\u540c\u3002 Get namespace. Get containers. Get images. Get volumes. Get overall status. Get network status. \u6f14\u793a\uff1a \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4namespaces\u3002 sudo nerdctl namespace ls \u8fd0\u884c\u7ed3\u679c\uff1a NAME CONTAINERS IMAGES VOLUMES LABELS k8s.io 21 30 0 \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4 k8s.io \u4e0b\u7684\u5bb9\u5668\u3002 sudo nerdctl -n k8s.io ps \u8fd0\u884c\u7ed3\u679c\uff1a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0a3625f22f65 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk 121af2ecd1a1 registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll/coredns 49f6c7e3efe5 registry.aliyuncs.com/google_containers/kube-proxy:v1.24.0 \"/usr/local/bin/kube\u2026\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t/kube-proxy 4bba5fbd701d registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001 57d47b57eb12 docker.io/calico/node:v3.23.3 \"start_runit\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl/calico-node 5ce4c351a886 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl 6456eef784bf registry.aliyuncs.com/google_containers/kube-scheduler:v1.24.0 \"kube-scheduler --au\u2026\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001/kube-scheduler 6a687305871c registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 7dcb24568574 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll a06b101118b8 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001 a07ef8c3fc3a registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/etcd-cka001 b8566d3e4174 registry.aliyuncs.com/google_containers/kube-controller-manager:v1.24.0 \"kube-controller-man\u2026\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001/kube-controller-manager ca6ac26314ff registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk/coredns cdc041b4791e registry.aliyuncs.com/google_containers/etcd:3.5.3-0 \"etcd --advertise-cl\u2026\" 16 hours ago Up k8s://kube-system/etcd-cka001/etcd e0c59abadf2e registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t e0d2e5f6ccff registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001 \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4 k8s.io \u4e0b\u7684\u955c\u50cf\u3002 sudo nerdctl -n k8s.io image ls -a \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4 k8s.io \u4e0b\u7684\u5377Volume\u3002\u521d\u59cb\u5316\u5b89\u88c5\u540e\uff0c\u8be5\u547d\u540d\u7a7a\u95f4\u4e0b\u6ca1\u6709\u4efb\u4f55\u5377\u3002 sudo nerdctl -n k8s.io volume ls \u8bfb\u53d6\u96c6\u7fa4\u72b6\u6001\u3002 sudo nerdctl stats \u8bfb\u53d6\u7f51\u7edc\u72b6\u6001\u3002 sudo nerdctl network ls sudo nerdctl network inspect bridge sudo nerdctl network inspect k8s-pod-network \u8fd0\u884c\u7ed3\u679c\uff1a NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none Get network interface in host cka001 with command ip addr list . IP pool of 10.4.0.1/24 is ipam and defined in /etc/cni/net.d/nerdctl-bridge.conflist . \u4f7f\u7528\u547d\u4ee4 ip addr list \u83b7\u53d6\u4e3b\u673a cka001 \u7684\u7f51\u7edc\u63a5\u53e3\u3002 10.4.0.1/24 \u7684IP\u6c60\u662f ipam \uff0c\u5728 /etc/cni/net.d/nerdctl-bridge.conflist \u4e2d\u5b9a\u4e49\u3002 lo : inet 127.0.0.1/8 qlen 1000 eth0 : inet /24 brd xxx.xxx.xxx.255 scope global dynamic eth0 tunl0@NONE : inet 10.244.228.192/32 scope global tunl0 cali96e32d88db2@if4 : cali93613212490@if4 : nerdctl-bridge.conflist \u6587\u4ef6\u7684\u4f5c\u7528\u662f\uff1a \u5b9a\u4e49\u4e86nerdctl\u4f7f\u7528\u7684\u9ed8\u8ba4\u6865\u63a5CNI\u7f51\u7edc\u7684\u914d\u7f6e\uff0c\u5305\u62ec\u7f51\u7edc\u540d\u79f0\u3001\u5b50\u7f51\u3001\u7f51\u5173\u3001IP\u5206\u914d\u7b56\u7565\u7b49 1 \uff0c 2 \u3002 \u4f7f\u5f97nerdctl\u53ef\u4ee5\u4f7f\u7528docker run -it --rm alpine\u8fd9\u6837\u7684\u547d\u4ee4\u6765\u8fd0\u884c\u4e00\u4e2a\u5bb9\u5668\uff0c\u5e76\u81ea\u52a8\u5206\u914d\u4e00\u4e2a10.4.0.0/24\u7f51\u6bb5\u7684IP\u5730\u5740 1 \uff0c 3 \u3002 \u4f7f\u5f97nerdctl\u53ef\u4ee5\u652f\u6301\u4e00\u4e9b\u57fa\u672c\u7684CNI\u63d2\u4ef6\uff0c\u5982bridge, portmap, firewall, tuning 1 \uff0c 2 \u3002 Kubernetes\u5c42 \u00b6 \u573a\u666f\uff1a \u8282\u70b9Nodes \u547d\u540d\u7a7a\u95f4Namespaces \u7cfb\u7edfPods \u6f14\u793a\uff1a \u8bfb\u53d6\u8282\u70b9\u72b6\u6001\uff1a kubectl get node -o wide \u5728\u4e09\u4e2a\u8282\u70b9\u4e0a\u6709\u56db\u4e2a\u521d\u59cb\u7684\u547d\u540d\u7a7a\u95f4\u3002 kubectl get namespace -A \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS AGE default Active 56m kube-node-lease Active 56m kube-public Active 56m kube-system Active 56m \u5728\u4e09\u4e2a\u8282\u70b9\u4e0a\u7684\u521d\u59cb\u5316Pod\u3002 kubectl get pod -A -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAMESPACE NAME READY STATUS RESTARTS AGE NODE NOMINATED NODE READINESS GATES kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 15h cka003 kube-system calico-node-255pc 1/1 Running 0 15h cka003 kube-system calico-node-7tmnb 1/1 Running 0 15h cka002 kube-system calico-node-w8nvl 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15h cka001 kube-system etcd-cka001 1/1 Running 0 15h cka001 kube-system kube-apiserver-cka001 1/1 Running 0 15h cka001 kube-system kube-controller-manager-cka001 1/1 Running 0 15h cka001 kube-system kube-proxy-dmj2t 1/1 Running 0 15h cka001 kube-system kube-proxy-n77zw 1/1 Running 0 15h cka002 kube-system kube-proxy-qs6rf 1/1 Running 0 15h cka003 kube-system kube-scheduler-cka001 1/1 Running 0 15h cka001 \u603b\u7ed3\uff1a \u4e0b\u9762\u5217\u51fa\u4e86\u521d\u59cb\u96c6\u7fa4\u4e2d\u4e3b\u8282\u70b9\u548c\u6240\u6709\u8282\u70b9\u4e2d\u6240\u5305\u542b\u7684\u5bb9\u5668\u548cPod\u7684\u5173\u7cfb\u3002 Master node: CoreDNS: 2 Pod etcd: 1 Pod apiserver: 1 Pod controller-manager: 1 Pod scheduler: 1 Pod Calico Controller: 1 Pod All nodes: Calico Node: 1 Pod each Proxy: 1 Pod each \u53c2\u8003\uff1a pause\u5bb9\u5668\uff1a \u6587\u7ae01 and \u6587\u7ae02 . nerdctl","title":"Kubernetes\u96c6\u7fa4\u6982\u89c8"},{"location":"k8s/cka_cn/foundamentals/overview/#cka6kubernetes","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb06:Kubernetes\u96c6\u7fa4\u6982\u89c8"},{"location":"k8s/cka_cn/foundamentals/overview/#_1","text":"\u5305\u542b\u4e0b\u9762\u5185\u5bb9\uff1a \u5bb9\u5668\u5c42 Kubernetes\u5c42 \u63d0\u793a\uff1a \u540e\u7eed\u5b9e\u9a8c\u73af\u5883\u90fd\u662f\u4f7f\u7528\u5728\u963f\u91cc\u4e91\u90e8\u7f72\u7684Ubuntu\u4e09\u8282\u70b9\u96c6\u7fa4\uff0c\u4e09\u4e2a\u8282\u70b9\u5206\u522b\u4e3a cka001 \u3001 cka002 \u548c cka003 \u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/overview/#_2","text":"\u573a\u666f\uff1a \u4f7f\u7528Containerd\u670d\u52a1\uff0c\u901a\u8fc7\u547d\u4ee4 nerdctl \u6765\u7ba1\u7406\u6211\u4eec\u7684\u955c\u50cf\u548c\u5bb9\u5668\uff0c\u8fd9\u4e0eDocker\u7684\u6982\u5ff5\u76f8\u540c\u3002 Get namespace. Get containers. Get images. Get volumes. Get overall status. Get network status. \u6f14\u793a\uff1a \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4namespaces\u3002 sudo nerdctl namespace ls \u8fd0\u884c\u7ed3\u679c\uff1a NAME CONTAINERS IMAGES VOLUMES LABELS k8s.io 21 30 0 \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4 k8s.io \u4e0b\u7684\u5bb9\u5668\u3002 sudo nerdctl -n k8s.io ps \u8fd0\u884c\u7ed3\u679c\uff1a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0a3625f22f65 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk 121af2ecd1a1 registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll/coredns 49f6c7e3efe5 registry.aliyuncs.com/google_containers/kube-proxy:v1.24.0 \"/usr/local/bin/kube\u2026\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t/kube-proxy 4bba5fbd701d registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001 57d47b57eb12 docker.io/calico/node:v3.23.3 \"start_runit\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl/calico-node 5ce4c351a886 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl 6456eef784bf registry.aliyuncs.com/google_containers/kube-scheduler:v1.24.0 \"kube-scheduler --au\u2026\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001/kube-scheduler 6a687305871c registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 7dcb24568574 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll a06b101118b8 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001 a07ef8c3fc3a registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/etcd-cka001 b8566d3e4174 registry.aliyuncs.com/google_containers/kube-controller-manager:v1.24.0 \"kube-controller-man\u2026\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001/kube-controller-manager ca6ac26314ff registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk/coredns cdc041b4791e registry.aliyuncs.com/google_containers/etcd:3.5.3-0 \"etcd --advertise-cl\u2026\" 16 hours ago Up k8s://kube-system/etcd-cka001/etcd e0c59abadf2e registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t e0d2e5f6ccff registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001 \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4 k8s.io \u4e0b\u7684\u955c\u50cf\u3002 sudo nerdctl -n k8s.io image ls -a \u8bfb\u53d6\u547d\u540d\u7a7a\u95f4 k8s.io \u4e0b\u7684\u5377Volume\u3002\u521d\u59cb\u5316\u5b89\u88c5\u540e\uff0c\u8be5\u547d\u540d\u7a7a\u95f4\u4e0b\u6ca1\u6709\u4efb\u4f55\u5377\u3002 sudo nerdctl -n k8s.io volume ls \u8bfb\u53d6\u96c6\u7fa4\u72b6\u6001\u3002 sudo nerdctl stats \u8bfb\u53d6\u7f51\u7edc\u72b6\u6001\u3002 sudo nerdctl network ls sudo nerdctl network inspect bridge sudo nerdctl network inspect k8s-pod-network \u8fd0\u884c\u7ed3\u679c\uff1a NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none Get network interface in host cka001 with command ip addr list . IP pool of 10.4.0.1/24 is ipam and defined in /etc/cni/net.d/nerdctl-bridge.conflist . \u4f7f\u7528\u547d\u4ee4 ip addr list \u83b7\u53d6\u4e3b\u673a cka001 \u7684\u7f51\u7edc\u63a5\u53e3\u3002 10.4.0.1/24 \u7684IP\u6c60\u662f ipam \uff0c\u5728 /etc/cni/net.d/nerdctl-bridge.conflist \u4e2d\u5b9a\u4e49\u3002 lo : inet 127.0.0.1/8 qlen 1000 eth0 : inet /24 brd xxx.xxx.xxx.255 scope global dynamic eth0 tunl0@NONE : inet 10.244.228.192/32 scope global tunl0 cali96e32d88db2@if4 : cali93613212490@if4 : nerdctl-bridge.conflist \u6587\u4ef6\u7684\u4f5c\u7528\u662f\uff1a \u5b9a\u4e49\u4e86nerdctl\u4f7f\u7528\u7684\u9ed8\u8ba4\u6865\u63a5CNI\u7f51\u7edc\u7684\u914d\u7f6e\uff0c\u5305\u62ec\u7f51\u7edc\u540d\u79f0\u3001\u5b50\u7f51\u3001\u7f51\u5173\u3001IP\u5206\u914d\u7b56\u7565\u7b49 1 \uff0c 2 \u3002 \u4f7f\u5f97nerdctl\u53ef\u4ee5\u4f7f\u7528docker run -it --rm alpine\u8fd9\u6837\u7684\u547d\u4ee4\u6765\u8fd0\u884c\u4e00\u4e2a\u5bb9\u5668\uff0c\u5e76\u81ea\u52a8\u5206\u914d\u4e00\u4e2a10.4.0.0/24\u7f51\u6bb5\u7684IP\u5730\u5740 1 \uff0c 3 \u3002 \u4f7f\u5f97nerdctl\u53ef\u4ee5\u652f\u6301\u4e00\u4e9b\u57fa\u672c\u7684CNI\u63d2\u4ef6\uff0c\u5982bridge, portmap, firewall, tuning 1 \uff0c 2 \u3002","title":"\u5bb9\u5668\u5c42"},{"location":"k8s/cka_cn/foundamentals/overview/#kubernetes","text":"\u573a\u666f\uff1a \u8282\u70b9Nodes \u547d\u540d\u7a7a\u95f4Namespaces \u7cfb\u7edfPods \u6f14\u793a\uff1a \u8bfb\u53d6\u8282\u70b9\u72b6\u6001\uff1a kubectl get node -o wide \u5728\u4e09\u4e2a\u8282\u70b9\u4e0a\u6709\u56db\u4e2a\u521d\u59cb\u7684\u547d\u540d\u7a7a\u95f4\u3002 kubectl get namespace -A \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS AGE default Active 56m kube-node-lease Active 56m kube-public Active 56m kube-system Active 56m \u5728\u4e09\u4e2a\u8282\u70b9\u4e0a\u7684\u521d\u59cb\u5316Pod\u3002 kubectl get pod -A -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAMESPACE NAME READY STATUS RESTARTS AGE NODE NOMINATED NODE READINESS GATES kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 15h cka003 kube-system calico-node-255pc 1/1 Running 0 15h cka003 kube-system calico-node-7tmnb 1/1 Running 0 15h cka002 kube-system calico-node-w8nvl 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15h cka001 kube-system etcd-cka001 1/1 Running 0 15h cka001 kube-system kube-apiserver-cka001 1/1 Running 0 15h cka001 kube-system kube-controller-manager-cka001 1/1 Running 0 15h cka001 kube-system kube-proxy-dmj2t 1/1 Running 0 15h cka001 kube-system kube-proxy-n77zw 1/1 Running 0 15h cka002 kube-system kube-proxy-qs6rf 1/1 Running 0 15h cka003 kube-system kube-scheduler-cka001 1/1 Running 0 15h cka001 \u603b\u7ed3\uff1a \u4e0b\u9762\u5217\u51fa\u4e86\u521d\u59cb\u96c6\u7fa4\u4e2d\u4e3b\u8282\u70b9\u548c\u6240\u6709\u8282\u70b9\u4e2d\u6240\u5305\u542b\u7684\u5bb9\u5668\u548cPod\u7684\u5173\u7cfb\u3002 Master node: CoreDNS: 2 Pod etcd: 1 Pod apiserver: 1 Pod controller-manager: 1 Pod scheduler: 1 Pod Calico Controller: 1 Pod All nodes: Calico Node: 1 Pod each Proxy: 1 Pod each \u53c2\u8003\uff1a pause\u5bb9\u5668\uff1a \u6587\u7ae01 and \u6587\u7ae02 . nerdctl","title":"Kubernetes\u5c42"},{"location":"k8s/cka_cn/foundamentals/persistence/","text":"CKA\u81ea\u5b66\u7b14\u8bb017:Persistence \u00b6 \u6458\u8981 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u7c7b\u578b\u4e3a emptyDir \u7684\u5377\u6765\u521b\u5efa Pod\uff0cPod \u4e2d\u7684\u5bb9\u5668\u5c06\u4f1a\u6302\u8f7d\u5728\u8fd0\u884c\u8282\u70b9\u4e0a\u7684\u9ed8\u8ba4\u76ee\u5f55 /var/lib/kubelet/pods/ \u4e2d\u3002 \u521b\u5efa\u4e00\u4e2a\u7c7b\u578b\u4e3a hostPath \u7684\u5377\u6765\u521b\u5efa Deployment\uff0cDeployment \u4e2d\u7684\u5bb9\u5668\u5c06\u4f1a\u6302\u8f7d\u5728\u8fd0\u884c\u8282\u70b9\u4e0a\u5b9a\u4e49\u7684\u76ee\u5f55 hostPath: \u4e2d\u3002 \u521b\u5efa PV \u548c PVC\uff1a \u8bbe\u7f6e NFS \u670d\u52a1\u5668\u5e76\u5171\u4eab /nfsdata/ \u76ee\u5f55\u3002 \u521b\u5efa PV mysql-pv \u5e76\u6620\u5c04\u5230\u5171\u4eab\u76ee\u5f55 /nfsdata/ \uff0c\u540c\u65f6\u8bbe\u7f6e StorageClassName \u4e3a nfs \u3002 \u521b\u5efa PVC mysql-pvc \u5e76\u6620\u5c04\u5230 StorageClassName \u4e3a nfs \u7684 PV \u4e0a\u3002 \u521b\u5efa Deployment mysql \u6765\u4f7f\u7528 PVC mysql-pvc \u3002 \u521b\u5efa StorageClass\uff1a \u521b\u5efa ServiceAccount nfs-client-provisioner \u3002 \u521b\u5efa ClusterRole nfs-client-provisioner-runner \u548c Role leader-locking-nfs-client-provisioner \uff0c\u5e76\u5c06\u5176\u7ed1\u5b9a\u5230 ServiceAccount \u4e0a\uff0c\u4ee5\u4fbf\u8be5 ServiceAccount \u53ef\u4ee5\u64cd\u4f5c\u4e0b\u4e00\u6b65\u4e2d\u521b\u5efa\u7684 Deployment\u3002 \u521b\u5efa Deployment nfs-client-provisioner \u6765\u6dfb\u52a0\u8fde\u63a5\u5230 NFS \u670d\u52a1\u5668\u7684\u4fe1\u606f\uff0c\u4f8b\u5982 PROVISIONER_NAME \u662f k8s-sigs.io/nfs-subdir-external-provisioner \u3002 \u521b\u5efa StorageClass nfs-client \u5e76\u94fe\u63a5\u5230 provisioner: k8s-sigs.io/nfs-subdir-external-provisioner \uff0c\u76f8\u5173\u7684 PV \u4f1a\u81ea\u52a8\u521b\u5efa\u3002 \u521b\u5efa PVC nfs-pvc-from-sc \u5e76\u6620\u5c04\u5230 StorageClass nfs-client \u4e0a\u7684 PV\u3002 \u914d\u7f6eConfiguration\uff1a \u521b\u5efa\u4e00\u4e2a ConfigMap \u4ee5\u5305\u542b\u6587\u4ef6\u7684\u5185\u5bb9\uff0c\u5e76\u5c06\u6b64 ConfigMap \u6302\u8f7d\u5230 Pod \u4e2d\u7684\u7279\u5b9a\u6587\u4ef6\u4e2d\u3002 \u521b\u5efa\u4e00\u4e2a ConfigMap \u6765\u5305\u542b\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u5e76\u5728 Pod \u4e2d\u4f7f\u7528\u5b83\u4eec\u3002 \u5728 Pod \u4e2d\u5c06 ConfigMap \u7528\u4f5c\u73af\u5883\u53d8\u91cf\u3002 \u5efa\u8bae\uff1a \u9996\u5148\u5220\u9664 PVC\uff0c\u7136\u540e\u518d\u5220\u9664 PV\u3002 \u5982\u679c\u5220\u9664 PVC \u65f6\u9047\u5230 Terminating \u72b6\u6001\uff0c\u4f7f\u7528 kubectl edit pvc \u547d\u4ee4\uff0c\u7136\u540e\u5220\u9664 finalize: \u3002 emptyDir \u00b6 \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a hello-producer \u7684 Pod\uff0c\u5e76\u4f7f\u7528 emptyDir \u7c7b\u578b\u7684 Volume\u3002 cat > pod-emptydir.yaml < /producer_dir/hello; sleep 30000 volumes: - name: shared-volume emptyDir: {} EOF kubectl apply -f pod-emptydir.yaml \u67e5\u770bPod hello-producer \u7684\u72b6\u6001\u3002 kubectl get pod hello-producer -owide Pod hello-producer \u8fd0\u884c\u5728\u8282\u70b9node cka003 \u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello-producer 1/1 Running 0 6s 10.244.102.24 cka003 \u767b\u5f55 cka003 \uff0c\u56e0\u4e3a Pod hello-producer \u6b63\u5728\u8be5\u8282\u70b9\u4e0a\u8fd0\u884c\u3002 \u4e3a crictl \u547d\u4ee4\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf CONTAINER_RUNTIME_ENDPOINT \u3002\u5efa\u8bae\u5728\u6240\u6709\u8282\u70b9\u4e0a\u6267\u884c\u76f8\u540c\u7684\u64cd\u4f5c\u3002 export CONTAINER_RUNTIME_ENDPOINT = unix:///run/containerd/containerd.sock \u8fd0\u884c\u547d\u4ee4 crictl ps \u6765\u83b7\u53d6 Pod hello-producer \u7684\u5bb9\u5668 ID\u3002 crictl ps | grep hello-producer \u5bb9\u5668 producer \u7684ID\u662f 05f5e1bb6a1bb \u3002 CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD 50058afb3cba5 62aedd01bd852 About an hour ago Running producer 0 e6953bd4833a7 hello-producer \u8fd0\u884c\u547d\u4ee4 crictl inspect \uff0c\u83b7\u53d6\u5df2\u6302\u8f7d\u7684 shared-volume \u7684\u8def\u5f84\uff0c\u5b83\u662f emptyDir \u7c7b\u578b\u7684\u3002 crictl inspect 50058afb3cba5 | grep source | grep empty \u8fd0\u884c\u7ed3\u679c \"source\": \"/var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume\", \u4fee\u6539\u8def\u5f84\u4e3a\u4e0a\u9762\u83b7\u53d6\u5230\u7684 shared-volume \u7684\u6302\u8f7d\u8def\u5f84\u3002\u7136\u540e\u6211\u4eec\u4f1a\u770b\u5230\u6587\u4ef6 hello \u4e2d\u7684\u5185\u5bb9 hello world \u3002 cd /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume cat hello Pod\u5185\u7684\u8def\u5f84 /producer_dir \u88ab\u6302\u8f7d\u5230\u4e86\u672c\u5730\u5bbf\u4e3b\u673a\u8def\u5f84 /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume \u3002 \u6211\u4eec\u5728Pod\u5185\u521b\u5efa\u7684\u6587\u4ef6 /producer_dir/hello \u5b9e\u9645\u4e0a\u5728\u5bbf\u4e3b\u673a\u672c\u5730\u8def\u5f84\u4e2d\u3002 \u8ba9\u6211\u4eec\u5220\u9664\u5bb9\u5668 producer \uff0c\u5bb9\u5668 producer \u5c06\u4ee5\u65b0\u7684\u5bb9\u5668ID\u91cd\u65b0\u542f\u52a8\uff0c\u800c\u6587\u4ef6 hello \u4ecd\u5c06\u5b58\u5728\u3002 crictl ps crictl stop crictl rm \u73b0\u5728\u5220\u9664Pod hello-producer \uff0c\u5bb9\u5668 producer \u4f1a\u88ab\u5220\u9664\uff0c\u6587\u4ef6 hello \u4e5f\u4f1a\u88ab\u5220\u9664\u3002 kubectl delete pod hello-producer hostPath \u00b6 \u5e94\u7528\u4ee5\u4e0b yaml \u6587\u4ef6\u521b\u5efa\u4e00\u4e2a MySQL Pod \u5e76\u6302\u8f7d\u4e00\u4e2a hostPath \u3002 \u5c06\u4e3b\u673a\u76ee\u5f55 /tmp/mysql \u6302\u8f7d\u5230 Pod \u76ee\u5f55 /var/lib/mysql \u3002 \u5728\u672c\u5730\u68c0\u67e5\u662f\u5426\u5b58\u5728\u76ee\u5f55 /tmp/mysql \uff0c\u5982\u679c\u4e0d\u5b58\u5728\uff0c\u5219\u6267\u884c\u547d\u4ee4 mkdir /tmp/mysql \u521b\u5efa\u5b83\u3002 cat > mysql-hostpath.yaml < cka003 \u5728MySQL Pod\u8fd0\u884c\u7684\u8282\u70b9\u767b\u9646\u8fdb\u5165pod\u5185\u90e8\u3002 kubectl exec -it -- bash \u5728 Pod \u4e2d\uff0c\u8fdb\u5165 /var/lib/mysql \u76ee\u5f55\uff0c\u8be5\u76ee\u5f55\u4e2d\u7684\u6240\u6709\u6587\u4ef6\u90fd\u4e0e\u8282\u70b9 cka003 \u4e0a /tmp/mysql \u76ee\u5f55\u4e2d\u7684\u6240\u6709\u6587\u4ef6\u76f8\u540c\u3002 \u8fde\u63a5\u5230 Pod \u4e2d\u7684\u6570\u636e\u5e93\u3002 mysql -h 127 .0.0.1 -uroot -ppassword \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u5bf9\u6570\u636e\u5e93\u8fdb\u884c\u7b80\u5355\u7684\u64cd\u4f5c\u3002 mysql> show databases ; mysql> connect mysql ; mysql> show tables ; mysql> exit PV\u548cPVC \u00b6 \u4e0b\u9762\u7684\u6f14\u793a\u4e2d\uff0c\u6211\u4eec\u5c06\u4f7f\u7528NFS\u4f5c\u4e3a\u540e\u7aef\u5b58\u50a8\u6765\u6f14\u793a\u5982\u4f55\u90e8\u7f72PV\u548cPVC\u3002 \u8bbe\u7f6eNFS\u5171\u4eab \u00b6 \u5b89\u88c5nfs-kernel-server \u767b\u5f55\u5230\u8282\u70b9 cka002 \u3002\u914d\u7f6eWorker cka002 \u6210\u4e3aNFS\u670d\u52a1\u5668\u3002 sudo apt-get install -y nfs-kernel-server 2.\u914d\u7f6e\u5171\u4eab\u76ee\u5f55 \u521b\u5efa\u5171\u4eab\u6587\u4ef6\u5939\u3002 mkdir /nfsdata \u7f16\u8f91\u6587\u4ef6 /etc/exports \uff0c\u6dfb\u52a0\u4e00\u884c /nfsdata *(rw,sync,no_root_squash) \u3002 cat >> /etc/exports << EOF /nfsdata *(rw,sync,no_root_squash) EOF \u6709\u8bb8\u591a\u4e0d\u540c\u7684NFS\u5171\u4eab\u9009\u9879\uff0c\u4f8b\u5982\uff1a * \uff1a\u5bf9\u6240\u6709IP\u6216\u7279\u5b9aIP\u53ef\u8bbf\u95ee\u3002 rw \uff1a\u4f5c\u4e3a\u8bfb\u5199\u5171\u4eab\u3002\u8bf7\u6ce8\u610f\uff0c\u6b63\u5e38\u7684Linux\u6743\u9650\u4ecd\u7136\u9002\u7528\u3002\uff08\u8bf7\u6ce8\u610f\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002\uff09 ro \uff1a\u4f5c\u4e3a\u53ea\u8bfb\u5171\u4eab\u3002 sync \uff1a\u6587\u4ef6\u6570\u636e\u66f4\u6539\u4f1a\u7acb\u5373\u5199\u5165\u78c1\u76d8\uff0c\u8fd9\u4f1a\u5f71\u54cd\u6027\u80fd\uff0c\u4f46\u4e0d\u592a\u53ef\u80fd\u5bfc\u81f4\u6570\u636e\u4e22\u5931\u3002\u5728\u67d0\u4e9b\u53d1\u884c\u7248\u4e0a\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002 async \uff1a\u4e0esync\u76f8\u53cd\uff0c\u6587\u4ef6\u6570\u636e\u66f4\u6539\u6700\u521d\u5199\u5165\u5185\u5b58\u3002\u8fd9\u63d0\u9ad8\u4e86\u6027\u80fd\uff0c\u4f46\u66f4\u5bb9\u6613\u5bfc\u81f4\u6570\u636e\u4e22\u5931\u3002\u5728\u67d0\u4e9b\u53d1\u884c\u7248\u4e0a\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002 root_squash \uff1a\u5c06NFS\u5ba2\u6237\u7aef\u7684root\u7528\u6237\u548c\u7ec4\u5e10\u6237\u6620\u5c04\u5230\u533f\u540d\u5e10\u6237\uff0c\u901a\u5e38\u662fnobody\u5e10\u6237\u6216nfsnobody\u5e10\u6237\u3002\u6709\u5173\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u89c1\u672c\u6587\u540e\u7eed\u7684\u201c\u7528\u6237ID\u6620\u5c04\u201d\u3002\uff08\u8bf7\u6ce8\u610f\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002\uff09 no_root_squash \uff1a\u5c06NFS\u5ba2\u6237\u7aef\u7684root\u7528\u6237\u548c\u7ec4\u5e10\u6237\u6620\u5c04\u5230\u672c\u5730root\u548c\u7ec4\u5e10\u6237\u3002 \u6211\u4eec\u5c06\u4f7f\u7528\u57fa\u4e8eLinux\u670d\u52a1\u5668\u4e4b\u95f4\u7684 nfs \u548c rpcbind \u670d\u52a1\u7684\u65e0\u5bc6\u7801\u8fdc\u7a0b\u6302\u8f7d\uff0c\u800c\u4e0d\u662f\u57fa\u4e8e smb \u670d\u52a1\u3002\u9996\u5148\uff0c\u8fd9\u4e24\u53f0\u670d\u52a1\u5668\u5fc5\u987b\u6388\u6743\u3001\u5b89\u88c5\u5e76\u8bbe\u7f6enfs\u548crpcbind\u670d\u52a1\uff0c\u8bbe\u7f6e\u5171\u4eab\u76ee\u5f55\uff0c\u542f\u52a8\u670d\u52a1\uff0c\u5e76\u5728\u5ba2\u6237\u7aef\u4e0a\u8fdb\u884c\u6302\u8f7d\u3002 \u542f\u52a8 rpcbind \u670d\u52a1\u3002 sudo systemctl enable rpcbind sudo systemctl restart rpcbind \u542f\u52a8 nfs \u670d\u52a1\u3002 sudo systemctl enable nfs-server sudo systemctl start nfs-server \u5982\u679c /etc/exports \u6587\u4ef6\u88ab\u4fee\u6539\uff0c\u6211\u4eec\u9700\u8981\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u4f7f\u4e4b\u751f\u6548\u3002 exportfs -ra \u8fd0\u884c\u7ed3\u679c exportfs: /etc/exports [ 1 ] : Neither 'subtree_check' or 'no_subtree_check' specified for export \"*:/nfsdata\" . Assuming default behaviour ( 'no_subtree_check' ) . NOTE: this default has changed since nfs-utils version 1 .0.x \u68c0\u67e5\u5171\u4eab\u76ee\u5f55\u662f\u5426\u5df2\u7ecf\u88ab\u6b63\u786e\u914d\u7f6e\u4e86\u3002 showmount -e \u5982\u679c\u770b\u5230\u4e0b\u9762\u7684\u7ed3\u679c\uff0c\u5219\u8bf4\u660e\u5171\u4eab\u76ee\u5f55\u5df2\u7ecf\u88ab\u6b63\u786e\u914d\u7f6e\u4e86\u3002 Export list for cka002: /nfsdata * 3.\u5b89\u88c5NFS\u5ba2\u6237\u7aef \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b89\u88c5NFS\u5ba2\u6237\u7aef\u3002 sudo apt-get install -y nfs-common 4.\u9a8c\u8bc1NFS\u670d\u52a1 \u767b\u5f55\u5230\u4efb\u4f55\u4e00\u4e2a\u8282\u70b9\u6765\u9a8c\u8bc1NFS\u670d\u52a1\u662f\u5426\u6b63\u786e\u5de5\u4f5c\uff0c\u4ee5\u53caNFS\u670d\u52a1\u6240\u5171\u4eab\u5230\u76ee\u5f55\u662f\u5426\u53ef\u89c1\u3002 \u767b\u9646\u5230 cka001 \uff0c\u5e76\u68c0\u67e5 cka002 \u7684\u5171\u4eab\u76ee\u5f55\u72b6\u6001\u3002 showmount -e cka002 \u5982\u679c\u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\uff0c\u5219\u8bf4\u660eNFS\u670d\u52a1\u6b63\u5e38\u5de5\u4f5c\uff0c\u5305\u62ec\u5171\u4eab\u76ee\u5f55\u3002 Export list for cka002: /nfsdata * 5.\u6302\u8f7dNFS\u5171\u4eab\u76ee\u5f55 \u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u6302\u8f7dNFS\u5171\u4eab\u76ee\u5f55\u5230\u4efb\u4f55\u4e00\u4e2a\u975eNFS\u670d\u52a1\u5668\u8282\u70b9\uff0c\u6bd4\u5982 cka001 or cka003 \u3002 mkdir /remote-nfs-dir mount -t nfs cka002:/nfsdata /remote-nfs-dir/ \u6267\u884c\u547d\u4ee4 df -h \u6765\u68c0\u67e5NFS\u6302\u8f7d\u70b9\u662f\u5426\u6b63\u786e\uff0c\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\u3002 Filesystem Size Used Avail Use% Mounted on cka002:/nfsdata 40G 5 .8G 32G 16 % /remote-nfs-dir \u521b\u5efa PV \u00b6 \u521b\u5efa\u4e00\u4e2a PV mysql-pv \u3002 \u5c06 NFS \u670d\u52a1\u5668 IP \u66ff\u6362\u4e3a\u5b9e\u9645\u7684 IP\uff08\u8fd9\u91cc\u662f \uff09\uff0c\u5b83\u662f\u8fd0\u884c NFS \u670d\u52a1\u5668 cka002 \u7684 IP\u3002 kubectl apply -f - < EOF \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u68c0\u67e5\u521b\u5efa\u7684PV\u3002 kubectl get pv \u8fd0\u884c\u7ed3\u679c NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mysql-pv 1Gi RWO Retain Available nfs 19s \u521b\u5efa PVC \u00b6 \u521b\u5efa PVC mysql-pvc \u5e76\u6307\u5b9a\u5b58\u50a8\u5927\u5c0f\u3001\u8bbf\u95ee\u6a21\u5f0f\u548c\u5b58\u50a8\u7c7b\u3002 PVC mysql-pvc \u5c06\u901a\u8fc7\u5b58\u50a8\u7c7b\u540d\u79f0\u81ea\u52a8\u4e0e PV \u7ed1\u5b9a\u3002 kubectl apply -f - < nfs-provisioner-rbac.yaml < ( cka002 ) \u4e0a\u7684 /nfsdata \u76ee\u5f55\u7684\u5377 nfs-client-root \u3002 \u628a NFS \u670d\u52a1\u5668\u7684 IP \u66ff\u6362\u4e3a\u5b9e\u9645\u7684 IP \u5730\u5740\u5373\u53ef\uff08\u8fd9\u91cc\u7528 \u8868\u793a\uff09\u3002 cat > nfs-provisioner-deployment.yaml < - name: NFS_PATH value: /nfsdata volumes: - name: nfs-client-root nfs: server: path: /nfsdata EOF kubectl apply -f nfs-provisioner-deployment.yaml \u521b\u5efa NFS StorageClass \u00b6 \u521b\u5efa StorageClass nfs-client \uff0c\u5b9a\u4e49 NFS \u5b50\u76ee\u5f55\u5916\u90e8 provisioner \u7684 Kubernetes Storage Class\u3002 \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u7f16\u8f91 nfs-storageclass.yaml \u6587\u4ef6\u3002 vi nfs-storageclass.yaml \u6dfb\u52a0\u4e0b\u9762\u7684\u4fe1\u606f\u6765\u914d\u7f6e NFS StorageClass\u3002 apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-client annotations: storageclass.kubernetes.io/is-default-class: \"true\" provisioner: k8s-sigs.io/nfs-subdir-external-provisioner parameters: pathPattern: \" ${ .PVC.namespace } / ${ .PVC.annotations.nfs.io/storage-path } \" onDelete: delete \u5e94\u7528\u4e0a\u9762\u7684yaml\u6587\u4ef6\uff0c\u4f7f\u4e4b\u751f\u6548\u3002 kubectl apply -f nfs-storageclass.yaml \u521b\u5efaPVC \u00b6 \u521b\u5efa PVC nfs-pvc-from-sc \u3002 kubectl apply -f - < mysql-with-sc-pvc-7c97d875f8-wkvr9 1/1 Running 0 3m37s 10.244.102.27 cka003 \u6211\u4eec\u73b0\u5728\u6765\u67e5\u770b NFS \u670d\u52a1\u5668 cka002 \u4e0a\u7684\u5171\u4eab\u76ee\u5f55 /nfsdata/ \u3002 ll /nfsdata/ NFS \u670d\u52a1\u5668 cka002 \u4e0a\u7684\u5171\u4eab\u76ee\u5f55 /nfsdata/ \u4e0b\u6709\u4e862\u4e2a\u5b50\u76ee\u5f55\uff0c\u4e0e\u5176\u4ed62\u4e2a\u8282\u70b9\u4e0a\u7684\u76ee\u5f55 /remote-nfs-dir/ \u4e0b\u7684\u5185\u5bb9\u662f\u4e00\u81f4\u3002 drwxrwxrwx 6 systemd-coredump root 4096 Jul 23 23 :35 dev/ drwxr-xr-x 6 systemd-coredump root 4096 Jul 23 22 :29 mysqldata/ \u547d\u540d\u7a7a\u95f4Namespace\u7684\u540d\u79f0\u4f5c\u4e3a\u76ee\u5f55\u540d\u5728 /nfsdata/ \u76ee\u5f55\u4e0b\u7528\u4e8e\u6302\u8f7d\u5230 Pod \u4e2d\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u547d\u540d\u7a7a\u95f4Namespace\u540d\u79f0\u5c06\u7528\u4e8e\u6302\u8f7d\u70b9\u3002 \u5982\u679c\u6211\u4eec\u60f3\u8981\u4f7f\u7528\u81ea\u5b9a\u4e49\u7684\u6587\u4ef6\u5939\u6765\u4ee3\u66ff\uff0c\u6211\u4eec\u9700\u8981\u58f0\u660e\u4e00\u4e2a nfs.io/storage-path \u6ce8\u91ca\uff0c\u4f8b\u5982\u4e0b\u9762\u7684\u4f8b\u5b50\u3002 \u5728\u547d\u540d\u7a7a\u95f4 kube-system \u4e0a\u521b\u5efa PVC test-claim \uff0c\u5e76\u6d88\u8d39 nfs-client \u5377\u3002 kubectl apply -f - < ..data/password lrwxrwxrwx 1 root root 15 Jul 23 16 :30 username -> ..data/username \u800c\u4e14\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u8fd92\u4e2a\u6570\u636e\u5143\u7d20\uff08 username \u548c password \uff09\u7684\u5185\u5bb9\u5c31\u662f\u6211\u4eec\u9884\u5148\u5b9a\u4e49\u7684\u3002 / # cat /tmp/secret/username admin / # cat /tmp/secret/password 123456 \u62d3\u5c55\u6848\u4f8b \u00b6 \u591a\u79cd\u65b9\u6cd5\u521b\u5efaConfigMap \u00b6 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u6587\u4ef6\u3001\u76ee\u5f55\u3001\u6216\u8005\u503c\u6765\u521b\u5efaConfigMap\u3002 \u4e0b\u9762\u6211\u4eec\u521b\u5efaConfigMap colors \uff0c\u5305\u542b\uff1a \u56db\u4e2a\u6587\u4ef6\uff0c\u6587\u4ef6\u540d\u662f\u56db\u4e2a\u989c\u8272\u3002 \u4e00\u4e2a\u6587\u4ef6\uff0c\u6587\u4ef6\u540d\u662f\u6700\u559c\u6b22\u7684\u989c\u8272\u3002 mkdir configmap cd configmap mkdir primary echo c > primary/cyan echo m > primary/magenta echo y > primary/yellow echo k > primary/black echo \"known as key\" >> primary/black echo blue > favorite \u6267\u884c\u547d\u4ee4 tree configmap \uff0c\u53ef\u4ee5\u770b\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u6587\u4ef6\u76ee\u5f55\u7ed3\u6784\u3002 configmap \u251c\u2500\u2500 favorite \u2514\u2500\u2500 primary \u251c\u2500\u2500 black \u251c\u2500\u2500 cyan \u251c\u2500\u2500 magenta \u2514\u2500\u2500 yellow \u521b\u5efa\u4e00\u4e2a ConfigMap\uff0c\u5f15\u7528\u4e0a\u9762\u6211\u4eec\u521b\u5efa\u7684\u6587\u4ef6\u3002\u786e\u4fdd\u6211\u4eec\u73b0\u5728\u5728\u8def\u5f84 ~/configmap \u4e0b\u3002 kubectl create configmap colors \\ --from-literal = text = black \\ --from-file = ./favorite \\ --from-file = ./primary/ \u67e5\u770bConfigMap colors \u7684\u5185\u5bb9\u3002 kubectl get configmap colors -o yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion: v1 data: black: | k known as key cyan: | c favorite: | blue magenta: | m text: black yellow: | y kind: ConfigMap metadata: creationTimestamp: \"2022-07-12T16:38:27Z\" name: colors namespace: dev resourceVersion: \"2377258\" uid: d5ab133f-5e4d-41d4-bc9e-2bbb22a872a1 \u901a\u8fc7ConfigMap\u8bbe\u5b9a\u73af\u5883\u53d8\u91cf \u00b6 \u7ee7\u7eed\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u73b0\u5728\u6211\u4eec\u51c6\u5907\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a pod-configmap-env \u7684Pod\uff0c\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf ilike \u5e76\u4eceConfigMap colors \u4e2d\u5206\u914d\u503c favorite \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env spec: containers: - name: nginx image: nginx env: - name: ilike valueFrom: configMapKeyRef: name: colors key: favorite EOF \u8fde\u63a5\u5e76\u8fdb\u5165Pod pod-configmap-env \u5185\u90e8\u3002 kubectl exec -it pod-configmap-env -- bash \u9a8c\u8bc1\u73af\u5883\u53d8\u91cf ilike \u7684\u503c\u662f blue \uff0c\u8fd9\u662f ConfigMap colors \u7684 favorite \u503c\u3002 root@pod-configmap-env:/# echo $ilike blue \u6211\u4eec\u8fd8\u53ef\u4ee5\u4f7f\u7528 ConfigMap \u7684\u6240\u6709\u952e\u503c\u5bf9\u6765\u8bbe\u7f6e Pod \u7684\u73af\u5883\u53d8\u91cf\u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env-2 spec: containers: - name: nginx image: nginx envFrom: - configMapRef: name: colors EOF \u8fde\u63a5\u5e76\u8fdb\u5165Pod pod-configmap-env-2 \u5185\u90e8\u3002 kubectl exec -it pod-configmap-env-2 -- bash \u9a8c\u8bc1\u73af\u5883\u53d8\u91cf\u7684\u503c\u662f\u6211\u4eec\u5728ConfigMap colors \u6240\u5b9a\u4e49\u7684\u952e\u503c\u5bf9\u3002 root@pod-configmap-env-2:/# echo $black k known as key root@pod-configmap-env-2:/# echo $cyan c root@pod-configmap-env-2:/# echo $favorite blue","title":"Persistence"},{"location":"k8s/cka_cn/foundamentals/persistence/#cka17persistence","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb017:Persistence"},{"location":"k8s/cka_cn/foundamentals/persistence/#_1","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u7c7b\u578b\u4e3a emptyDir \u7684\u5377\u6765\u521b\u5efa Pod\uff0cPod \u4e2d\u7684\u5bb9\u5668\u5c06\u4f1a\u6302\u8f7d\u5728\u8fd0\u884c\u8282\u70b9\u4e0a\u7684\u9ed8\u8ba4\u76ee\u5f55 /var/lib/kubelet/pods/ \u4e2d\u3002 \u521b\u5efa\u4e00\u4e2a\u7c7b\u578b\u4e3a hostPath \u7684\u5377\u6765\u521b\u5efa Deployment\uff0cDeployment \u4e2d\u7684\u5bb9\u5668\u5c06\u4f1a\u6302\u8f7d\u5728\u8fd0\u884c\u8282\u70b9\u4e0a\u5b9a\u4e49\u7684\u76ee\u5f55 hostPath: \u4e2d\u3002 \u521b\u5efa PV \u548c PVC\uff1a \u8bbe\u7f6e NFS \u670d\u52a1\u5668\u5e76\u5171\u4eab /nfsdata/ \u76ee\u5f55\u3002 \u521b\u5efa PV mysql-pv \u5e76\u6620\u5c04\u5230\u5171\u4eab\u76ee\u5f55 /nfsdata/ \uff0c\u540c\u65f6\u8bbe\u7f6e StorageClassName \u4e3a nfs \u3002 \u521b\u5efa PVC mysql-pvc \u5e76\u6620\u5c04\u5230 StorageClassName \u4e3a nfs \u7684 PV \u4e0a\u3002 \u521b\u5efa Deployment mysql \u6765\u4f7f\u7528 PVC mysql-pvc \u3002 \u521b\u5efa StorageClass\uff1a \u521b\u5efa ServiceAccount nfs-client-provisioner \u3002 \u521b\u5efa ClusterRole nfs-client-provisioner-runner \u548c Role leader-locking-nfs-client-provisioner \uff0c\u5e76\u5c06\u5176\u7ed1\u5b9a\u5230 ServiceAccount \u4e0a\uff0c\u4ee5\u4fbf\u8be5 ServiceAccount \u53ef\u4ee5\u64cd\u4f5c\u4e0b\u4e00\u6b65\u4e2d\u521b\u5efa\u7684 Deployment\u3002 \u521b\u5efa Deployment nfs-client-provisioner \u6765\u6dfb\u52a0\u8fde\u63a5\u5230 NFS \u670d\u52a1\u5668\u7684\u4fe1\u606f\uff0c\u4f8b\u5982 PROVISIONER_NAME \u662f k8s-sigs.io/nfs-subdir-external-provisioner \u3002 \u521b\u5efa StorageClass nfs-client \u5e76\u94fe\u63a5\u5230 provisioner: k8s-sigs.io/nfs-subdir-external-provisioner \uff0c\u76f8\u5173\u7684 PV \u4f1a\u81ea\u52a8\u521b\u5efa\u3002 \u521b\u5efa PVC nfs-pvc-from-sc \u5e76\u6620\u5c04\u5230 StorageClass nfs-client \u4e0a\u7684 PV\u3002 \u914d\u7f6eConfiguration\uff1a \u521b\u5efa\u4e00\u4e2a ConfigMap \u4ee5\u5305\u542b\u6587\u4ef6\u7684\u5185\u5bb9\uff0c\u5e76\u5c06\u6b64 ConfigMap \u6302\u8f7d\u5230 Pod \u4e2d\u7684\u7279\u5b9a\u6587\u4ef6\u4e2d\u3002 \u521b\u5efa\u4e00\u4e2a ConfigMap \u6765\u5305\u542b\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u5e76\u5728 Pod \u4e2d\u4f7f\u7528\u5b83\u4eec\u3002 \u5728 Pod \u4e2d\u5c06 ConfigMap \u7528\u4f5c\u73af\u5883\u53d8\u91cf\u3002 \u5efa\u8bae\uff1a \u9996\u5148\u5220\u9664 PVC\uff0c\u7136\u540e\u518d\u5220\u9664 PV\u3002 \u5982\u679c\u5220\u9664 PVC \u65f6\u9047\u5230 Terminating \u72b6\u6001\uff0c\u4f7f\u7528 kubectl edit pvc \u547d\u4ee4\uff0c\u7136\u540e\u5220\u9664 finalize: \u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/persistence/#emptydir","text":"\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a hello-producer \u7684 Pod\uff0c\u5e76\u4f7f\u7528 emptyDir \u7c7b\u578b\u7684 Volume\u3002 cat > pod-emptydir.yaml < /producer_dir/hello; sleep 30000 volumes: - name: shared-volume emptyDir: {} EOF kubectl apply -f pod-emptydir.yaml \u67e5\u770bPod hello-producer \u7684\u72b6\u6001\u3002 kubectl get pod hello-producer -owide Pod hello-producer \u8fd0\u884c\u5728\u8282\u70b9node cka003 \u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello-producer 1/1 Running 0 6s 10.244.102.24 cka003 \u767b\u5f55 cka003 \uff0c\u56e0\u4e3a Pod hello-producer \u6b63\u5728\u8be5\u8282\u70b9\u4e0a\u8fd0\u884c\u3002 \u4e3a crictl \u547d\u4ee4\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf CONTAINER_RUNTIME_ENDPOINT \u3002\u5efa\u8bae\u5728\u6240\u6709\u8282\u70b9\u4e0a\u6267\u884c\u76f8\u540c\u7684\u64cd\u4f5c\u3002 export CONTAINER_RUNTIME_ENDPOINT = unix:///run/containerd/containerd.sock \u8fd0\u884c\u547d\u4ee4 crictl ps \u6765\u83b7\u53d6 Pod hello-producer \u7684\u5bb9\u5668 ID\u3002 crictl ps | grep hello-producer \u5bb9\u5668 producer \u7684ID\u662f 05f5e1bb6a1bb \u3002 CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD 50058afb3cba5 62aedd01bd852 About an hour ago Running producer 0 e6953bd4833a7 hello-producer \u8fd0\u884c\u547d\u4ee4 crictl inspect \uff0c\u83b7\u53d6\u5df2\u6302\u8f7d\u7684 shared-volume \u7684\u8def\u5f84\uff0c\u5b83\u662f emptyDir \u7c7b\u578b\u7684\u3002 crictl inspect 50058afb3cba5 | grep source | grep empty \u8fd0\u884c\u7ed3\u679c \"source\": \"/var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume\", \u4fee\u6539\u8def\u5f84\u4e3a\u4e0a\u9762\u83b7\u53d6\u5230\u7684 shared-volume \u7684\u6302\u8f7d\u8def\u5f84\u3002\u7136\u540e\u6211\u4eec\u4f1a\u770b\u5230\u6587\u4ef6 hello \u4e2d\u7684\u5185\u5bb9 hello world \u3002 cd /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume cat hello Pod\u5185\u7684\u8def\u5f84 /producer_dir \u88ab\u6302\u8f7d\u5230\u4e86\u672c\u5730\u5bbf\u4e3b\u673a\u8def\u5f84 /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume \u3002 \u6211\u4eec\u5728Pod\u5185\u521b\u5efa\u7684\u6587\u4ef6 /producer_dir/hello \u5b9e\u9645\u4e0a\u5728\u5bbf\u4e3b\u673a\u672c\u5730\u8def\u5f84\u4e2d\u3002 \u8ba9\u6211\u4eec\u5220\u9664\u5bb9\u5668 producer \uff0c\u5bb9\u5668 producer \u5c06\u4ee5\u65b0\u7684\u5bb9\u5668ID\u91cd\u65b0\u542f\u52a8\uff0c\u800c\u6587\u4ef6 hello \u4ecd\u5c06\u5b58\u5728\u3002 crictl ps crictl stop crictl rm \u73b0\u5728\u5220\u9664Pod hello-producer \uff0c\u5bb9\u5668 producer \u4f1a\u88ab\u5220\u9664\uff0c\u6587\u4ef6 hello \u4e5f\u4f1a\u88ab\u5220\u9664\u3002 kubectl delete pod hello-producer","title":"emptyDir"},{"location":"k8s/cka_cn/foundamentals/persistence/#hostpath","text":"\u5e94\u7528\u4ee5\u4e0b yaml \u6587\u4ef6\u521b\u5efa\u4e00\u4e2a MySQL Pod \u5e76\u6302\u8f7d\u4e00\u4e2a hostPath \u3002 \u5c06\u4e3b\u673a\u76ee\u5f55 /tmp/mysql \u6302\u8f7d\u5230 Pod \u76ee\u5f55 /var/lib/mysql \u3002 \u5728\u672c\u5730\u68c0\u67e5\u662f\u5426\u5b58\u5728\u76ee\u5f55 /tmp/mysql \uff0c\u5982\u679c\u4e0d\u5b58\u5728\uff0c\u5219\u6267\u884c\u547d\u4ee4 mkdir /tmp/mysql \u521b\u5efa\u5b83\u3002 cat > mysql-hostpath.yaml < cka003 \u5728MySQL Pod\u8fd0\u884c\u7684\u8282\u70b9\u767b\u9646\u8fdb\u5165pod\u5185\u90e8\u3002 kubectl exec -it -- bash \u5728 Pod \u4e2d\uff0c\u8fdb\u5165 /var/lib/mysql \u76ee\u5f55\uff0c\u8be5\u76ee\u5f55\u4e2d\u7684\u6240\u6709\u6587\u4ef6\u90fd\u4e0e\u8282\u70b9 cka003 \u4e0a /tmp/mysql \u76ee\u5f55\u4e2d\u7684\u6240\u6709\u6587\u4ef6\u76f8\u540c\u3002 \u8fde\u63a5\u5230 Pod \u4e2d\u7684\u6570\u636e\u5e93\u3002 mysql -h 127 .0.0.1 -uroot -ppassword \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u5bf9\u6570\u636e\u5e93\u8fdb\u884c\u7b80\u5355\u7684\u64cd\u4f5c\u3002 mysql> show databases ; mysql> connect mysql ; mysql> show tables ; mysql> exit","title":"hostPath"},{"location":"k8s/cka_cn/foundamentals/persistence/#pvpvc","text":"\u4e0b\u9762\u7684\u6f14\u793a\u4e2d\uff0c\u6211\u4eec\u5c06\u4f7f\u7528NFS\u4f5c\u4e3a\u540e\u7aef\u5b58\u50a8\u6765\u6f14\u793a\u5982\u4f55\u90e8\u7f72PV\u548cPVC\u3002","title":"PV\u548cPVC"},{"location":"k8s/cka_cn/foundamentals/persistence/#nfs","text":"\u5b89\u88c5nfs-kernel-server \u767b\u5f55\u5230\u8282\u70b9 cka002 \u3002\u914d\u7f6eWorker cka002 \u6210\u4e3aNFS\u670d\u52a1\u5668\u3002 sudo apt-get install -y nfs-kernel-server 2.\u914d\u7f6e\u5171\u4eab\u76ee\u5f55 \u521b\u5efa\u5171\u4eab\u6587\u4ef6\u5939\u3002 mkdir /nfsdata \u7f16\u8f91\u6587\u4ef6 /etc/exports \uff0c\u6dfb\u52a0\u4e00\u884c /nfsdata *(rw,sync,no_root_squash) \u3002 cat >> /etc/exports << EOF /nfsdata *(rw,sync,no_root_squash) EOF \u6709\u8bb8\u591a\u4e0d\u540c\u7684NFS\u5171\u4eab\u9009\u9879\uff0c\u4f8b\u5982\uff1a * \uff1a\u5bf9\u6240\u6709IP\u6216\u7279\u5b9aIP\u53ef\u8bbf\u95ee\u3002 rw \uff1a\u4f5c\u4e3a\u8bfb\u5199\u5171\u4eab\u3002\u8bf7\u6ce8\u610f\uff0c\u6b63\u5e38\u7684Linux\u6743\u9650\u4ecd\u7136\u9002\u7528\u3002\uff08\u8bf7\u6ce8\u610f\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002\uff09 ro \uff1a\u4f5c\u4e3a\u53ea\u8bfb\u5171\u4eab\u3002 sync \uff1a\u6587\u4ef6\u6570\u636e\u66f4\u6539\u4f1a\u7acb\u5373\u5199\u5165\u78c1\u76d8\uff0c\u8fd9\u4f1a\u5f71\u54cd\u6027\u80fd\uff0c\u4f46\u4e0d\u592a\u53ef\u80fd\u5bfc\u81f4\u6570\u636e\u4e22\u5931\u3002\u5728\u67d0\u4e9b\u53d1\u884c\u7248\u4e0a\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002 async \uff1a\u4e0esync\u76f8\u53cd\uff0c\u6587\u4ef6\u6570\u636e\u66f4\u6539\u6700\u521d\u5199\u5165\u5185\u5b58\u3002\u8fd9\u63d0\u9ad8\u4e86\u6027\u80fd\uff0c\u4f46\u66f4\u5bb9\u6613\u5bfc\u81f4\u6570\u636e\u4e22\u5931\u3002\u5728\u67d0\u4e9b\u53d1\u884c\u7248\u4e0a\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002 root_squash \uff1a\u5c06NFS\u5ba2\u6237\u7aef\u7684root\u7528\u6237\u548c\u7ec4\u5e10\u6237\u6620\u5c04\u5230\u533f\u540d\u5e10\u6237\uff0c\u901a\u5e38\u662fnobody\u5e10\u6237\u6216nfsnobody\u5e10\u6237\u3002\u6709\u5173\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\uff0c\u8bf7\u53c2\u89c1\u672c\u6587\u540e\u7eed\u7684\u201c\u7528\u6237ID\u6620\u5c04\u201d\u3002\uff08\u8bf7\u6ce8\u610f\uff0c\u8fd9\u662f\u9ed8\u8ba4\u9009\u9879\u3002\uff09 no_root_squash \uff1a\u5c06NFS\u5ba2\u6237\u7aef\u7684root\u7528\u6237\u548c\u7ec4\u5e10\u6237\u6620\u5c04\u5230\u672c\u5730root\u548c\u7ec4\u5e10\u6237\u3002 \u6211\u4eec\u5c06\u4f7f\u7528\u57fa\u4e8eLinux\u670d\u52a1\u5668\u4e4b\u95f4\u7684 nfs \u548c rpcbind \u670d\u52a1\u7684\u65e0\u5bc6\u7801\u8fdc\u7a0b\u6302\u8f7d\uff0c\u800c\u4e0d\u662f\u57fa\u4e8e smb \u670d\u52a1\u3002\u9996\u5148\uff0c\u8fd9\u4e24\u53f0\u670d\u52a1\u5668\u5fc5\u987b\u6388\u6743\u3001\u5b89\u88c5\u5e76\u8bbe\u7f6enfs\u548crpcbind\u670d\u52a1\uff0c\u8bbe\u7f6e\u5171\u4eab\u76ee\u5f55\uff0c\u542f\u52a8\u670d\u52a1\uff0c\u5e76\u5728\u5ba2\u6237\u7aef\u4e0a\u8fdb\u884c\u6302\u8f7d\u3002 \u542f\u52a8 rpcbind \u670d\u52a1\u3002 sudo systemctl enable rpcbind sudo systemctl restart rpcbind \u542f\u52a8 nfs \u670d\u52a1\u3002 sudo systemctl enable nfs-server sudo systemctl start nfs-server \u5982\u679c /etc/exports \u6587\u4ef6\u88ab\u4fee\u6539\uff0c\u6211\u4eec\u9700\u8981\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u4f7f\u4e4b\u751f\u6548\u3002 exportfs -ra \u8fd0\u884c\u7ed3\u679c exportfs: /etc/exports [ 1 ] : Neither 'subtree_check' or 'no_subtree_check' specified for export \"*:/nfsdata\" . Assuming default behaviour ( 'no_subtree_check' ) . NOTE: this default has changed since nfs-utils version 1 .0.x \u68c0\u67e5\u5171\u4eab\u76ee\u5f55\u662f\u5426\u5df2\u7ecf\u88ab\u6b63\u786e\u914d\u7f6e\u4e86\u3002 showmount -e \u5982\u679c\u770b\u5230\u4e0b\u9762\u7684\u7ed3\u679c\uff0c\u5219\u8bf4\u660e\u5171\u4eab\u76ee\u5f55\u5df2\u7ecf\u88ab\u6b63\u786e\u914d\u7f6e\u4e86\u3002 Export list for cka002: /nfsdata * 3.\u5b89\u88c5NFS\u5ba2\u6237\u7aef \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b89\u88c5NFS\u5ba2\u6237\u7aef\u3002 sudo apt-get install -y nfs-common 4.\u9a8c\u8bc1NFS\u670d\u52a1 \u767b\u5f55\u5230\u4efb\u4f55\u4e00\u4e2a\u8282\u70b9\u6765\u9a8c\u8bc1NFS\u670d\u52a1\u662f\u5426\u6b63\u786e\u5de5\u4f5c\uff0c\u4ee5\u53caNFS\u670d\u52a1\u6240\u5171\u4eab\u5230\u76ee\u5f55\u662f\u5426\u53ef\u89c1\u3002 \u767b\u9646\u5230 cka001 \uff0c\u5e76\u68c0\u67e5 cka002 \u7684\u5171\u4eab\u76ee\u5f55\u72b6\u6001\u3002 showmount -e cka002 \u5982\u679c\u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\uff0c\u5219\u8bf4\u660eNFS\u670d\u52a1\u6b63\u5e38\u5de5\u4f5c\uff0c\u5305\u62ec\u5171\u4eab\u76ee\u5f55\u3002 Export list for cka002: /nfsdata * 5.\u6302\u8f7dNFS\u5171\u4eab\u76ee\u5f55 \u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u6302\u8f7dNFS\u5171\u4eab\u76ee\u5f55\u5230\u4efb\u4f55\u4e00\u4e2a\u975eNFS\u670d\u52a1\u5668\u8282\u70b9\uff0c\u6bd4\u5982 cka001 or cka003 \u3002 mkdir /remote-nfs-dir mount -t nfs cka002:/nfsdata /remote-nfs-dir/ \u6267\u884c\u547d\u4ee4 df -h \u6765\u68c0\u67e5NFS\u6302\u8f7d\u70b9\u662f\u5426\u6b63\u786e\uff0c\u7c7b\u4f3c\u4e0b\u9762\u7684\u7ed3\u679c\u3002 Filesystem Size Used Avail Use% Mounted on cka002:/nfsdata 40G 5 .8G 32G 16 % /remote-nfs-dir","title":"\u8bbe\u7f6eNFS\u5171\u4eab"},{"location":"k8s/cka_cn/foundamentals/persistence/#pv","text":"\u521b\u5efa\u4e00\u4e2a PV mysql-pv \u3002 \u5c06 NFS \u670d\u52a1\u5668 IP \u66ff\u6362\u4e3a\u5b9e\u9645\u7684 IP\uff08\u8fd9\u91cc\u662f \uff09\uff0c\u5b83\u662f\u8fd0\u884c NFS \u670d\u52a1\u5668 cka002 \u7684 IP\u3002 kubectl apply -f - < EOF \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u68c0\u67e5\u521b\u5efa\u7684PV\u3002 kubectl get pv \u8fd0\u884c\u7ed3\u679c NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mysql-pv 1Gi RWO Retain Available nfs 19s","title":"\u521b\u5efa PV"},{"location":"k8s/cka_cn/foundamentals/persistence/#pvc","text":"\u521b\u5efa PVC mysql-pvc \u5e76\u6307\u5b9a\u5b58\u50a8\u5927\u5c0f\u3001\u8bbf\u95ee\u6a21\u5f0f\u548c\u5b58\u50a8\u7c7b\u3002 PVC mysql-pvc \u5c06\u901a\u8fc7\u5b58\u50a8\u7c7b\u540d\u79f0\u81ea\u52a8\u4e0e PV \u7ed1\u5b9a\u3002 kubectl apply -f - < nfs-provisioner-rbac.yaml < ( cka002 ) \u4e0a\u7684 /nfsdata \u76ee\u5f55\u7684\u5377 nfs-client-root \u3002 \u628a NFS \u670d\u52a1\u5668\u7684 IP \u66ff\u6362\u4e3a\u5b9e\u9645\u7684 IP \u5730\u5740\u5373\u53ef\uff08\u8fd9\u91cc\u7528 \u8868\u793a\uff09\u3002 cat > nfs-provisioner-deployment.yaml < - name: NFS_PATH value: /nfsdata volumes: - name: nfs-client-root nfs: server: path: /nfsdata EOF kubectl apply -f nfs-provisioner-deployment.yaml","title":"\u521b\u5efaProvisioner\u7684Deloyment"},{"location":"k8s/cka_cn/foundamentals/persistence/#nfs-storageclass","text":"\u521b\u5efa StorageClass nfs-client \uff0c\u5b9a\u4e49 NFS \u5b50\u76ee\u5f55\u5916\u90e8 provisioner \u7684 Kubernetes Storage Class\u3002 \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u7f16\u8f91 nfs-storageclass.yaml \u6587\u4ef6\u3002 vi nfs-storageclass.yaml \u6dfb\u52a0\u4e0b\u9762\u7684\u4fe1\u606f\u6765\u914d\u7f6e NFS StorageClass\u3002 apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-client annotations: storageclass.kubernetes.io/is-default-class: \"true\" provisioner: k8s-sigs.io/nfs-subdir-external-provisioner parameters: pathPattern: \" ${ .PVC.namespace } / ${ .PVC.annotations.nfs.io/storage-path } \" onDelete: delete \u5e94\u7528\u4e0a\u9762\u7684yaml\u6587\u4ef6\uff0c\u4f7f\u4e4b\u751f\u6548\u3002 kubectl apply -f nfs-storageclass.yaml","title":"\u521b\u5efa NFS StorageClass"},{"location":"k8s/cka_cn/foundamentals/persistence/#pvc_2","text":"\u521b\u5efa PVC nfs-pvc-from-sc \u3002 kubectl apply -f - < mysql-with-sc-pvc-7c97d875f8-wkvr9 1/1 Running 0 3m37s 10.244.102.27 cka003 \u6211\u4eec\u73b0\u5728\u6765\u67e5\u770b NFS \u670d\u52a1\u5668 cka002 \u4e0a\u7684\u5171\u4eab\u76ee\u5f55 /nfsdata/ \u3002 ll /nfsdata/ NFS \u670d\u52a1\u5668 cka002 \u4e0a\u7684\u5171\u4eab\u76ee\u5f55 /nfsdata/ \u4e0b\u6709\u4e862\u4e2a\u5b50\u76ee\u5f55\uff0c\u4e0e\u5176\u4ed62\u4e2a\u8282\u70b9\u4e0a\u7684\u76ee\u5f55 /remote-nfs-dir/ \u4e0b\u7684\u5185\u5bb9\u662f\u4e00\u81f4\u3002 drwxrwxrwx 6 systemd-coredump root 4096 Jul 23 23 :35 dev/ drwxr-xr-x 6 systemd-coredump root 4096 Jul 23 22 :29 mysqldata/ \u547d\u540d\u7a7a\u95f4Namespace\u7684\u540d\u79f0\u4f5c\u4e3a\u76ee\u5f55\u540d\u5728 /nfsdata/ \u76ee\u5f55\u4e0b\u7528\u4e8e\u6302\u8f7d\u5230 Pod \u4e2d\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u547d\u540d\u7a7a\u95f4Namespace\u540d\u79f0\u5c06\u7528\u4e8e\u6302\u8f7d\u70b9\u3002 \u5982\u679c\u6211\u4eec\u60f3\u8981\u4f7f\u7528\u81ea\u5b9a\u4e49\u7684\u6587\u4ef6\u5939\u6765\u4ee3\u66ff\uff0c\u6211\u4eec\u9700\u8981\u58f0\u660e\u4e00\u4e2a nfs.io/storage-path \u6ce8\u91ca\uff0c\u4f8b\u5982\u4e0b\u9762\u7684\u4f8b\u5b50\u3002 \u5728\u547d\u540d\u7a7a\u95f4 kube-system \u4e0a\u521b\u5efa PVC test-claim \uff0c\u5e76\u6d88\u8d39 nfs-client \u5377\u3002 kubectl apply -f - < ..data/password lrwxrwxrwx 1 root root 15 Jul 23 16 :30 username -> ..data/username \u800c\u4e14\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u8fd92\u4e2a\u6570\u636e\u5143\u7d20\uff08 username \u548c password \uff09\u7684\u5185\u5bb9\u5c31\u662f\u6211\u4eec\u9884\u5148\u5b9a\u4e49\u7684\u3002 / # cat /tmp/secret/username admin / # cat /tmp/secret/password 123456","title":"Secret"},{"location":"k8s/cka_cn/foundamentals/persistence/#_2","text":"","title":"\u62d3\u5c55\u6848\u4f8b"},{"location":"k8s/cka_cn/foundamentals/persistence/#configmap_1","text":"\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u6587\u4ef6\u3001\u76ee\u5f55\u3001\u6216\u8005\u503c\u6765\u521b\u5efaConfigMap\u3002 \u4e0b\u9762\u6211\u4eec\u521b\u5efaConfigMap colors \uff0c\u5305\u542b\uff1a \u56db\u4e2a\u6587\u4ef6\uff0c\u6587\u4ef6\u540d\u662f\u56db\u4e2a\u989c\u8272\u3002 \u4e00\u4e2a\u6587\u4ef6\uff0c\u6587\u4ef6\u540d\u662f\u6700\u559c\u6b22\u7684\u989c\u8272\u3002 mkdir configmap cd configmap mkdir primary echo c > primary/cyan echo m > primary/magenta echo y > primary/yellow echo k > primary/black echo \"known as key\" >> primary/black echo blue > favorite \u6267\u884c\u547d\u4ee4 tree configmap \uff0c\u53ef\u4ee5\u770b\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u6587\u4ef6\u76ee\u5f55\u7ed3\u6784\u3002 configmap \u251c\u2500\u2500 favorite \u2514\u2500\u2500 primary \u251c\u2500\u2500 black \u251c\u2500\u2500 cyan \u251c\u2500\u2500 magenta \u2514\u2500\u2500 yellow \u521b\u5efa\u4e00\u4e2a ConfigMap\uff0c\u5f15\u7528\u4e0a\u9762\u6211\u4eec\u521b\u5efa\u7684\u6587\u4ef6\u3002\u786e\u4fdd\u6211\u4eec\u73b0\u5728\u5728\u8def\u5f84 ~/configmap \u4e0b\u3002 kubectl create configmap colors \\ --from-literal = text = black \\ --from-file = ./favorite \\ --from-file = ./primary/ \u67e5\u770bConfigMap colors \u7684\u5185\u5bb9\u3002 kubectl get configmap colors -o yaml \u8fd0\u884c\u7ed3\u679c\uff1a apiVersion: v1 data: black: | k known as key cyan: | c favorite: | blue magenta: | m text: black yellow: | y kind: ConfigMap metadata: creationTimestamp: \"2022-07-12T16:38:27Z\" name: colors namespace: dev resourceVersion: \"2377258\" uid: d5ab133f-5e4d-41d4-bc9e-2bbb22a872a1","title":"\u591a\u79cd\u65b9\u6cd5\u521b\u5efaConfigMap"},{"location":"k8s/cka_cn/foundamentals/persistence/#configmap_2","text":"\u7ee7\u7eed\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u73b0\u5728\u6211\u4eec\u51c6\u5907\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a pod-configmap-env \u7684Pod\uff0c\u8bbe\u7f6e\u73af\u5883\u53d8\u91cf ilike \u5e76\u4eceConfigMap colors \u4e2d\u5206\u914d\u503c favorite \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env spec: containers: - name: nginx image: nginx env: - name: ilike valueFrom: configMapKeyRef: name: colors key: favorite EOF \u8fde\u63a5\u5e76\u8fdb\u5165Pod pod-configmap-env \u5185\u90e8\u3002 kubectl exec -it pod-configmap-env -- bash \u9a8c\u8bc1\u73af\u5883\u53d8\u91cf ilike \u7684\u503c\u662f blue \uff0c\u8fd9\u662f ConfigMap colors \u7684 favorite \u503c\u3002 root@pod-configmap-env:/# echo $ilike blue \u6211\u4eec\u8fd8\u53ef\u4ee5\u4f7f\u7528 ConfigMap \u7684\u6240\u6709\u952e\u503c\u5bf9\u6765\u8bbe\u7f6e Pod \u7684\u73af\u5883\u53d8\u91cf\u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env-2 spec: containers: - name: nginx image: nginx envFrom: - configMapRef: name: colors EOF \u8fde\u63a5\u5e76\u8fdb\u5165Pod pod-configmap-env-2 \u5185\u90e8\u3002 kubectl exec -it pod-configmap-env-2 -- bash \u9a8c\u8bc1\u73af\u5883\u53d8\u91cf\u7684\u503c\u662f\u6211\u4eec\u5728ConfigMap colors \u6240\u5b9a\u4e49\u7684\u952e\u503c\u5bf9\u3002 root@pod-configmap-env-2:/# echo $black k known as key root@pod-configmap-env-2:/# echo $cyan c root@pod-configmap-env-2:/# echo $favorite blue","title":"\u901a\u8fc7ConfigMap\u8bbe\u5b9a\u73af\u5883\u53d8\u91cf"},{"location":"k8s/cka_cn/foundamentals/pod/","text":"CKA\u81ea\u5b66\u7b14\u8bb08:Pod \u00b6 \u6458\u8981 \u00b6 \u7ec3\u4e60\u76ee\u6807\uff1a \u521b\u5efapod \u8ffd\u8e2apod pod\u6807\u7b7e \u9759\u6001pod \u591a\u5bb9\u5668pod \u542b\u521d\u59cb\u5316\u5bb9\u5668\u7684pod \u521b\u5efaPod \u00b6 \u521b\u5efaPod my-first-podl \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-first-pod spec: containers: - name: nginx image: nginx:mainline ports: - containerPort: 80 EOF \u9a8c\u8bc1\u521a\u521a\u521b\u5efa\u7684pod\u7684\u72b6\u6001\u3002 kubectl get pods -o wide \u8ffd\u8e2apod \u00b6 \u68c0\u67e5\u521a\u521a\u521b\u5efa\u7684pod\u7684\u65e5\u5fd7\u3002 kubectl logs my-first-pod \u5982\u679c\u65e5\u5fd7\u6216\u8005\u5176\u4ed6\u547d\u4ee4\u8f93\u51fa\u7684\u4fe1\u606f\u4e0d\u8db3\u4ee5\u5e2e\u52a9\u6211\u4eec\u67e5\u627e\u6839\u672c\u539f\u56e0\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7 kubectl exec -it -- bash \u6765\u8fdb\u5165pod\u5185\u90e8\u8fdb\u884c\u5206\u6790\u3002 kubectl exec -it my-first-pod -- bash root@my-first-pod:/# ls root@my-first-pod:/# cd bin root@my-first-pod:/bin# ls root@my-first-pod:/bin# exit \u6267\u884c\u547d\u4ee4 kubectl explain pod.spec \u53ef\u4ee5\u5f97\u5230pod\u5bf9\u5e94\u7684yaml\u6587\u4ef6\u4e2dSpec\u533a\u6bb5\u7684\u5185\u5bb9\u3002 \u6211\u4eec\u53ef\u4ee5\u67e5\u770b Pod \u8d44\u6e90\u7684\u5b98\u65b9 API \u53c2\u8003\u6587\u6863\uff0c\u6216\u8005\u4f7f\u7528 kubectl explain pod \u547d\u4ee4\u884c\u83b7\u53d6\u8be5\u8d44\u6e90\u7684\u63cf\u8ff0\u4fe1\u606f\u3002\u901a\u8fc7\u5728\u8d44\u6e90\u7c7b\u578b\u540e\u6dfb\u52a0 . \uff0cexplain \u547d\u4ee4\u4f1a\u63d0\u4f9b\u8be5\u6307\u5b9a\u5b57\u6bb5\u7684\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl explain pod.kind kubectl explain pod.spec kubectl explain pod.spec.containers kubectl explain pod.spec.containers.name pod\u7684\u6807\u7b7e \u00b6 \u901a\u8fc7\u9009\u9879 --show-labels \u6765\u83b7\u5f97pod\u7684\u6807\u7b7e\u3002 kubectl get pods kubectl get pods --show-labels \u7ed9pod pod my-first-pod \u6dfb\u52a02\u4e2a\u6807\u7b7e\u3002 kubectl label pod my-first-pod nginx = mainline kubectl label pod my-first-pod env = demo kubectl get pods --show-labels \u901a\u8fc7\u6807\u7b7e\u6765\u67e5\u627epod\u3002 kubectl get pod -l env = demo kubectl get pod -l env = demo,nginx = mainline kubectl get pod -l env = training \u79fb\u9664pod\u7684\u6807\u7b7e\u3002 kubectl label pods my-first-pod env- kubectl get pods --show-labels \u63cf\u8ff0 Pod\u3002 kubectl describe pod my-first-pod \u5220\u9664pod. \u8fd0\u884c\u547d\u4ee4 watch kubectl get pods \u6765\u83b7\u53d6pod\u7684\u72b6\u6001\u3002 kubectl delete pod my-first-pod watch kubectl get pods \u9759\u6001pod \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u9759\u6001pod\u3002 kubectl \u4f1a\u81ea\u52a8\u68c0\u67e5 /etc/kubernetes/manifests/ \u4e2d\u7684 YAML \u6587\u4ef6\uff0c\u5e76\u5728\u68c0\u6d4b\u5230\u540e\u521b\u5efa\u9759\u6001 Pod\u3002 \u6f14\u793a\uff1a \u67e5\u770b\u7cfb\u7edf\u521d\u59cb\u5316\u540e\u5df2\u7ecf\u5b58\u5728\u7684\u9759\u6001pod\u3002 ll /etc/kubernetes/manifests/ \u8fd0\u884c\u7ed3\u679c\uff1a -rw------- 1 root root 2292 Jul 23 10:45 etcd.yaml -rw------- 1 root root 3889 Jul 23 10:45 kube-apiserver.yaml -rw------- 1 root root 3395 Jul 23 10:45 kube-controller-manager.yaml -rw------- 1 root root 1464 Jul 23 10:45 kube-scheduler.yaml \u5728 /etc/kubernetes/manifests/ \u76ee\u5f55\u4e2d\u521b\u5efayaml\u6587\u4ef6 my-nginx.yaml \uff0c\u4e00\u65e6\u6587\u4ef6\u521b\u5efa\u5b8c\u6210\uff0c\u9759\u6001Pod my-nginx \u5c06\u4f1a\u88ab\u81ea\u52a8\u521b\u5efa\u3002 kubectl run my-nginx --image = nginx:mainline --dry-run = client -n default -oyaml | sudo tee /etc/kubernetes/manifests/my-nginx.yaml \u68c0\u67e5 Pod my-nginx \u7684\u72b6\u6001\u3002Pod \u540d\u79f0\u4e2d\u5305\u542b\u8282\u70b9\u540d\u79f0 cka001 \uff0c\u8fd9\u610f\u5473\u7740\u8be5 Pod \u6b63\u5728\u8282\u70b9 cka001 \u4e0a\u8fd0\u884c\u3002 kubectl get pod -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cka001 1/1 Running 0 20s 10.244.228.196 cka001 \u5220\u9664 /etc/kubernetes/manifests/my-nginx.yaml \u8fd9\u4e2a yaml \u6587\u4ef6\uff0c\u5bf9\u5e94\u7684\u9759\u6001 Pod my-nginx \u5c06\u4f1a\u88ab\u81ea\u52a8\u5220\u9664\u3002 sudo rm /etc/kubernetes/manifests/my-nginx.yaml \u591a\u5bb9\u5668Pod \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u591a\u5bb9\u5668Pod \u63cf\u8ff0\u8be5Pod \u68c0\u67e5Pod\u7684\u65e5\u5fd7 \u68c0\u67e5\u5bb9\u5668\u7684\u65e5\u5fd7 \u6f14\u793a\uff1a \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a multi-container-pod \u7684Pod\uff0c\u5305\u542b\u591a\u4e2a\u5bb9\u5668\uff1a container-1-nginx \u548c container-2-alpine \u3002 kubectl apply -f - << EOF apiVersion : v1 kind : Pod metadata : name : multi-container-pod spec : containers : - name : container-1-nginx image : nginx ports : - containerPort : 80 - name : container-2-alpine image : alpine command : [ \"watch\" , \"wget\" , \"-qO-\" , \"localhost\" ] EOF \u83b7\u53d6pod\u72b6\u6001\u3002 kubectl get pod multi-container-pod \u8fd0\u884c\u7ed3\u679c \u83b7\u53d6pod\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl describe pod multi-container-pod \u8fd0\u884c\u7ed3\u679c\uff1a ....... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 41s default-scheduler Successfully assigned dev/multi-container-pod to cka002 Normal Pulling 40s kubelet Pulling image \"nginx\" Normal Pulled 23s kubelet Successfully pulled image \"nginx\" in 16.767129903s Normal Created 22s kubelet Created container container-1-nginx Normal Started 22s kubelet Started container container-1-nginx Normal Pulling 22s kubelet Pulling image \"alpine\" Normal Pulled 14s kubelet Successfully pulled image \"alpine\" in 7.776104353s Normal Created 14s kubelet Created container container-2-alpine Normal Started 14s kubelet Started container container-2-alpine \u5bf9\u4e8e\u591a\u5bb9\u5668 Pod\uff0c\u5982\u679c\u6211\u4eec\u60f3\u901a\u8fc7\u547d\u4ee4 kubectl logs \u83b7\u53d6 Pod \u7684\u65e5\u5fd7\uff0c\u9700\u8981\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\u3002\u5982\u679c\u4e0d\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\uff0c\u5c06\u4f1a\u6536\u5230\u9519\u8bef\u4fe1\u606f\u3002 kubectl logs multi-container-pod \u8fd0\u884c\u7ed3\u679c error: a container name must be specified for pod multi-container-pod, choose one of: [ container-1-nginx container-2-alpine ] \u6307\u5b9a\u5bb9\u5668\u540d\u79f0\uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u5230\u5bf9\u5e94\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl logs multi-container-pod container-1-nginx \u8fd0\u884c\u7ed3\u679c ...... ::1 - - [ 23 /Jul/2022:04:06:37 +0000 ] \"GET / HTTP/1.1\" 200 615 \"-\" \"Wget\" \"-\" \u5982\u679c\u6211\u4eec\u9700\u8981\u4f7f\u7528\u547d\u4ee4 kubectl exec -it -c -- \u767b\u5f55\u5230 Pod \u4e2d\uff0c\u540c\u6837\u9700\u8981\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\u3002\u5982\u679c\u6ca1\u6709\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\uff0c\u4f1a\u51fa\u73b0\u9519\u8bef\u3002 kubectl exec -it multi-container-pod -c container-1-nginx -- /bin/bash root@multi-container-pod:/# ls \u5220\u9664\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u3002 kubectl delete pod multi-container-pod \u4e0b\u9762\u662f\u4e00\u4e2a\u57fa\u672c\u7684yaml\u6587\u4ef6\u7528\u6765\u521b\u5efa\u591a\u5bb9\u5668pod\u3002 kubectl apply -f - << EOF apiVersion : v1 kind : Pod metadata : name : my-multi-pod spec : containers : - image : nginx name : nginx - image : memcached name : memcached - image : redis name : redis EOF \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a my-busybox \u7684Pod\uff0c\u5e76\u5728\u5176\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a container-1-busybox \u7684\u5bb9\u5668\u3002\u8be5\u5bb9\u5668\u5c06\u628a\u6d88\u606f\u5199\u5165\u5230\u6587\u4ef6 /var/log/my-pod-busybox.log \u4e2d\u3002 \u5411Pod my-busybox \u4e2d\u6dfb\u52a0\u53e6\u4e00\u4e2a\u5bb9\u5668 container-2-busybox \uff08Sidecar\uff09\u3002Sidecar\u5bb9\u5668\u4ece\u6587\u4ef6 /var/log/my-pod-busybox.log \u4e2d\u8bfb\u53d6\u6d88\u606f\u3002 \u63d0\u793a\uff1a\u521b\u5efa\u4e00\u4e2aVolume\u6765\u5b58\u50a8\u65e5\u5fd7\u6587\u4ef6\uff0c\u5e76\u4e0e\u4e24\u4e2a\u5bb9\u5668\u5171\u4eab\u3002 \u6f14\u793a\uff1a \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a my-busybox \u7684 Pod\uff0c\u5176\u4e2d\u5305\u542b\u4e00\u4e2a\u5bb9\u5668 container-1-busybox \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-busybox spec: containers: - name: container-1-busybox image: busybox args: - /bin/sh - -c - > i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=$((i+1)); sleep 1; done EOF \u5728 Kubernetes \u6587\u6863\u4e2d\u641c\u7d22 emptyDir \u3002 \u53c2\u8003\u4ee5\u4e0b\u6a21\u677f\u7528\u4e8e emptyDir \uff1a https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/ \u5c06\u4ee5\u4e0b\u65b0\u529f\u80fd\u6dfb\u52a0\u5230 Pod \u4e2d\uff1a Volume\uff1a \u5377\u540d\u79f0\uff1a logfile \u7c7b\u578b\uff1a emptyDir \u66f4\u65b0\u73b0\u6709\u5bb9\u5668\uff1a name: container-1-busybox volumeMounts name: logfile mounthPath: /var/log \u6dfb\u52a0\u65b0\u5bb9\u5668\uff1a name: container-2-busybox image: busybox args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log'] volumeMounts: name: logfile mountPath: /var/log kubectl get pod my-busybox -o yaml > my-busybox.yaml vi my-busybox.yaml kubectl delete pod my-busybox kubectl apply -f my-busybox.yaml kubectl logs my-busybox -c container-2-busybox \u66f4\u65b0\u540e\u7684\u6587\u4ef6 my-busybox.yaml \u5982\u4e0b\uff1a apiVersion : v1 kind : Pod metadata : annotations : cni.projectcalico.org/containerID : 89644b6b073cd152f94b4cae7bdea6bbc3292cf59afd4f28102bd74f0205c9e4 cni.projectcalico.org/podIP : 10.244.102.20/32 cni.projectcalico.org/podIPs : 10.244.102.20/32 kubectl.kubernetes.io/last-applied-configuration : | {\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"my-busybox\",\"namespace\":\"dev\"},\"spec\":{\"containers\":[{\"args\":[\"/bin/sh\",\"-c\",\"i=0; while true; do\\n echo \\\"Hello message from container-1: \\\" \\u003e\\u003e /var/log/my-pod-busybox.log;\\n i=1;\\n sleep 1;\\ndone\\n\"],\"image\":\"busybox\",\"name\":\"container-1-busybox\"}]}} creationTimestamp : \"2022-07-29T22:58:27Z\" name : my-busybox namespace : dev resourceVersion : \"1185720\" uid : c5e62a16-4459-4828-a441-7d1471b89a56 spec : containers : - name : container-2-busybox image : busybox args : [ '/bin/sh' , '-c' , 'tail -n+1 -f /var/log/my-pod-busybox.log' ] volumeMounts : - name : logfile mountPath : /var/log - args : - /bin/sh - -c - | i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=1; sleep 1; done image : busybox imagePullPolicy : Always name : container-1-busybox resources : {} terminationMessagePath : /dev/termination-log terminationMessagePolicy : File volumeMounts : - name : logfile mountPath : /var/log - mountPath : /var/run/secrets/kubernetes.io/serviceaccount name : kube-api-access-mhxlf readOnly : true dnsPolicy : ClusterFirst enableServiceLinks : true nodeName : cka003 preemptionPolicy : PreemptLowerPriority priority : 0 restartPolicy : Always schedulerName : default-scheduler securityContext : {} serviceAccount : default serviceAccountName : default terminationGracePeriodSeconds : 30 tolerations : - effect : NoExecute key : node.kubernetes.io/not-ready operator : Exists tolerationSeconds : 300 - effect : NoExecute key : node.kubernetes.io/unreachable operator : Exists tolerationSeconds : 300 volumes : - name : logfile emptyDir : {} - name : kube-api-access-mhxlf projected : defaultMode : 420 sources : - serviceAccountToken : expirationSeconds : 3607 path : token - configMap : items : - key : ca.crt path : ca.crt name : kube-root-ca.crt - downwardAPI : items : - fieldRef : apiVersion : v1 fieldPath : metadata.namespace path : namespace status : conditions : - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:27Z\" status : \"True\" type : Initialized - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:30Z\" status : \"True\" type : Ready - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:30Z\" status : \"True\" type : ContainersReady - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:27Z\" status : \"True\" type : PodScheduled containerStatuses : - containerID : containerd://fd42d4ba4d94d8918d8846327b1db2328be13c5f93f381877ff0228ed7b5468d image : docker.io/library/busybox:latest imageID : docker.io/library/busybox@sha256:0e97a8ca6955f22dbc7db9e9dbe970971f423541e52c34b8cb96ccc88d6a3883 lastState : {} name : container-1-busybox ready : true restartCount : 0 started : true state : running : startedAt : \"2022-07-29T22:58:30Z\" hostIP : phase : Running podIP : 10.244.102.20 podIPs : - ip : 10.244.102.20 qosClass : BestEffort startTime : \"2022-07-29T22:58:27Z\" \u6e05\u7406\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u3002 kubectl delete pod my-busybox \u542b\u521d\u59cb\u5316\u5bb9\u5668Pod \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u62e5\u6709\u4e24\u4e2a\u521d\u59cb\u5316\u5bb9\u5668\u7684 Pod myapp-pod \u3002 myapp-container init-mydb \u521b\u5efa\u4e24\u4e2a\u670d\u52a1\uff1a myservice mydb \u6f14\u793a\u9884\u671f\u7ed3\u8bba\uff1a myapp-container \u7b49\u5f85\u670d\u52a1 myservice \u542f\u52a8\uff0c\u4ee5\u89e3\u6790\u540d\u79f0 myservice.dev.svc.cluster.local init-mydb \u7b49\u5f85\u670d\u52a1 mydb \u542f\u52a8\uff0c\u4ee5\u89e3\u6790\u540d\u79f0 mydb.dev.svc.cluster.local \u3002 \u6f14\u793a\uff1a \u521b\u5efa\u540d\u4e3a myapp-pod.yaml \u7684yaml\u6587\u4ef6\uff0c\u5e76\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\u3002 \u6ce8\u610f\uff1a\u7531\u4e8e\u547d\u4ee4 $(cat /var/..... \u5c06\u88ab\u89c6\u4e3a\u4e3b\u673a\u53d8\u91cf\uff0c\u56e0\u6b64\u6211\u4eec\u4e0d\u80fd\u4f7f\u7528echo\u751f\u6210\u8be5\u6587\u4ef6\u3002\u5b83\u662f\u5bb9\u5668\u672c\u8eab\u7684\u53d8\u91cf\u3002 vi myapp-pod.yaml \u6587\u4ef6\u5185\u5bb9 apiVersion : v1 kind : Pod metadata : name : myapp-pod labels : app : myapp spec : containers : - name : myapp-container image : busybox:1.28 command : [ 'sh' , '-c' , 'echo The app is running! && sleep 3600' ] initContainers : - name : init-myservice image : busybox:1.28 command : [ 'sh' , '-c' , \"until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done\" ] - name : init-mydb image : busybox:1.28 command : [ 'sh' , '-c' , \"until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done\" ] \u7528\u4e0a\u9762\u521b\u5efa\u7684yaml\u6587\u4ef6\u521b\u5efaPod myapp-pod \u3002 kubectl apply -f myapp-pod.yaml \u68c0\u67e5pod\u7684\u72b6\u6001\u3002 kubectl get pod myapp-pod \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE myapp-pod 0/1 Init:0/2 0 12m \u68c0\u67e5Pod\uff0c\u53ef\u4ee5\u770b\u5230\u4e24\u4e2a\u9519\u8bef\uff1a nslookup: \u65e0\u6cd5\u89e3\u6790'myservice.dev.svc.cluster.local' Pod \"myapp-pod\"\u4e2d\u7684\u5bb9\u5668\u201cinit-mydb\u201d\u6b63\u5728\u7b49\u5f85\u542f\u52a8\uff1aPodInitializing kubectl logs myapp-pod -c init-myservice # Inspect the first init container kubectl logs myapp-pod -c init-mydb # Inspect the second init container \u5728\u8fd9\u4e2a\u65f6\u5019\uff0c\u8fd9\u4e9b init \u5bb9\u5668\u5c06\u7b49\u5f85\u53d1\u73b0\u540d\u4e3a mydb \u548c myservice \u7684\u670d\u52a1\u3002 \u521b\u5efa mydb \u548c myservice \u670d\u52a1\uff1a kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: myservice spec: ports: - protocol: TCP port: 80 targetPort: 9376 --- apiVersion: v1 kind: Service metadata: name: mydb spec: ports: - protocol: TCP port: 80 targetPort: 9377 EOF \u67e5\u770b\u521b\u5efa\u7684\u670d\u52a1\u7684\u72b6\u6001\u3002 kubectl get service \u521b\u5efa\u76842\u4e2a\u670d\u52a1\u90fd\u662f\u8fd0\u884c\u72b6\u6001\u3002 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mydb ClusterIP 11.244.239.149 80/TCP 6s myservice ClusterIP 11.244.116.126 80/TCP 6s \u518d\u6b21\u67e5\u770bpod\u7684\u72b6\u6001\u3002 kubectl get pod myapp-pod -o wide pod\u5df2\u7ecf\u6b63\u5e38\u8fd0\u884c\u4e86\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-pod 0/1 Init:0/2 0 2m40s 10.244.112.2 cka002 \u73b0\u5728\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u90a3\u4e9b\u521d\u59cb\u5316\u5bb9\u5668\u90fd\u5df2\u7ecf\u5b8c\u6210\uff0c myapp-pod Pod \u8fdb\u5165\u4e86 Running \u72b6\u6001\u3002 \u5220\u9664\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u3002 kubectl delete service mydb myservice kubectl delete pod myapp-pod \u53c2\u8003\uff1a Pod basics Lifecycle & phases Kubernetes pod design pattern","title":"Pod"},{"location":"k8s/cka_cn/foundamentals/pod/#cka8pod","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb08:Pod"},{"location":"k8s/cka_cn/foundamentals/pod/#_1","text":"\u7ec3\u4e60\u76ee\u6807\uff1a \u521b\u5efapod \u8ffd\u8e2apod pod\u6807\u7b7e \u9759\u6001pod \u591a\u5bb9\u5668pod \u542b\u521d\u59cb\u5316\u5bb9\u5668\u7684pod","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/pod/#pod","text":"\u521b\u5efaPod my-first-podl \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-first-pod spec: containers: - name: nginx image: nginx:mainline ports: - containerPort: 80 EOF \u9a8c\u8bc1\u521a\u521a\u521b\u5efa\u7684pod\u7684\u72b6\u6001\u3002 kubectl get pods -o wide","title":"\u521b\u5efaPod"},{"location":"k8s/cka_cn/foundamentals/pod/#pod_1","text":"\u68c0\u67e5\u521a\u521a\u521b\u5efa\u7684pod\u7684\u65e5\u5fd7\u3002 kubectl logs my-first-pod \u5982\u679c\u65e5\u5fd7\u6216\u8005\u5176\u4ed6\u547d\u4ee4\u8f93\u51fa\u7684\u4fe1\u606f\u4e0d\u8db3\u4ee5\u5e2e\u52a9\u6211\u4eec\u67e5\u627e\u6839\u672c\u539f\u56e0\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7 kubectl exec -it -- bash \u6765\u8fdb\u5165pod\u5185\u90e8\u8fdb\u884c\u5206\u6790\u3002 kubectl exec -it my-first-pod -- bash root@my-first-pod:/# ls root@my-first-pod:/# cd bin root@my-first-pod:/bin# ls root@my-first-pod:/bin# exit \u6267\u884c\u547d\u4ee4 kubectl explain pod.spec \u53ef\u4ee5\u5f97\u5230pod\u5bf9\u5e94\u7684yaml\u6587\u4ef6\u4e2dSpec\u533a\u6bb5\u7684\u5185\u5bb9\u3002 \u6211\u4eec\u53ef\u4ee5\u67e5\u770b Pod \u8d44\u6e90\u7684\u5b98\u65b9 API \u53c2\u8003\u6587\u6863\uff0c\u6216\u8005\u4f7f\u7528 kubectl explain pod \u547d\u4ee4\u884c\u83b7\u53d6\u8be5\u8d44\u6e90\u7684\u63cf\u8ff0\u4fe1\u606f\u3002\u901a\u8fc7\u5728\u8d44\u6e90\u7c7b\u578b\u540e\u6dfb\u52a0 . \uff0cexplain \u547d\u4ee4\u4f1a\u63d0\u4f9b\u8be5\u6307\u5b9a\u5b57\u6bb5\u7684\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl explain pod.kind kubectl explain pod.spec kubectl explain pod.spec.containers kubectl explain pod.spec.containers.name","title":"\u8ffd\u8e2apod"},{"location":"k8s/cka_cn/foundamentals/pod/#pod_2","text":"\u901a\u8fc7\u9009\u9879 --show-labels \u6765\u83b7\u5f97pod\u7684\u6807\u7b7e\u3002 kubectl get pods kubectl get pods --show-labels \u7ed9pod pod my-first-pod \u6dfb\u52a02\u4e2a\u6807\u7b7e\u3002 kubectl label pod my-first-pod nginx = mainline kubectl label pod my-first-pod env = demo kubectl get pods --show-labels \u901a\u8fc7\u6807\u7b7e\u6765\u67e5\u627epod\u3002 kubectl get pod -l env = demo kubectl get pod -l env = demo,nginx = mainline kubectl get pod -l env = training \u79fb\u9664pod\u7684\u6807\u7b7e\u3002 kubectl label pods my-first-pod env- kubectl get pods --show-labels \u63cf\u8ff0 Pod\u3002 kubectl describe pod my-first-pod \u5220\u9664pod. \u8fd0\u884c\u547d\u4ee4 watch kubectl get pods \u6765\u83b7\u53d6pod\u7684\u72b6\u6001\u3002 kubectl delete pod my-first-pod watch kubectl get pods","title":"pod\u7684\u6807\u7b7e"},{"location":"k8s/cka_cn/foundamentals/pod/#pod_3","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u9759\u6001pod\u3002 kubectl \u4f1a\u81ea\u52a8\u68c0\u67e5 /etc/kubernetes/manifests/ \u4e2d\u7684 YAML \u6587\u4ef6\uff0c\u5e76\u5728\u68c0\u6d4b\u5230\u540e\u521b\u5efa\u9759\u6001 Pod\u3002 \u6f14\u793a\uff1a \u67e5\u770b\u7cfb\u7edf\u521d\u59cb\u5316\u540e\u5df2\u7ecf\u5b58\u5728\u7684\u9759\u6001pod\u3002 ll /etc/kubernetes/manifests/ \u8fd0\u884c\u7ed3\u679c\uff1a -rw------- 1 root root 2292 Jul 23 10:45 etcd.yaml -rw------- 1 root root 3889 Jul 23 10:45 kube-apiserver.yaml -rw------- 1 root root 3395 Jul 23 10:45 kube-controller-manager.yaml -rw------- 1 root root 1464 Jul 23 10:45 kube-scheduler.yaml \u5728 /etc/kubernetes/manifests/ \u76ee\u5f55\u4e2d\u521b\u5efayaml\u6587\u4ef6 my-nginx.yaml \uff0c\u4e00\u65e6\u6587\u4ef6\u521b\u5efa\u5b8c\u6210\uff0c\u9759\u6001Pod my-nginx \u5c06\u4f1a\u88ab\u81ea\u52a8\u521b\u5efa\u3002 kubectl run my-nginx --image = nginx:mainline --dry-run = client -n default -oyaml | sudo tee /etc/kubernetes/manifests/my-nginx.yaml \u68c0\u67e5 Pod my-nginx \u7684\u72b6\u6001\u3002Pod \u540d\u79f0\u4e2d\u5305\u542b\u8282\u70b9\u540d\u79f0 cka001 \uff0c\u8fd9\u610f\u5473\u7740\u8be5 Pod \u6b63\u5728\u8282\u70b9 cka001 \u4e0a\u8fd0\u884c\u3002 kubectl get pod -o wide \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cka001 1/1 Running 0 20s 10.244.228.196 cka001 \u5220\u9664 /etc/kubernetes/manifests/my-nginx.yaml \u8fd9\u4e2a yaml \u6587\u4ef6\uff0c\u5bf9\u5e94\u7684\u9759\u6001 Pod my-nginx \u5c06\u4f1a\u88ab\u81ea\u52a8\u5220\u9664\u3002 sudo rm /etc/kubernetes/manifests/my-nginx.yaml","title":"\u9759\u6001pod"},{"location":"k8s/cka_cn/foundamentals/pod/#pod_4","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u591a\u5bb9\u5668Pod \u63cf\u8ff0\u8be5Pod \u68c0\u67e5Pod\u7684\u65e5\u5fd7 \u68c0\u67e5\u5bb9\u5668\u7684\u65e5\u5fd7 \u6f14\u793a\uff1a \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a multi-container-pod \u7684Pod\uff0c\u5305\u542b\u591a\u4e2a\u5bb9\u5668\uff1a container-1-nginx \u548c container-2-alpine \u3002 kubectl apply -f - << EOF apiVersion : v1 kind : Pod metadata : name : multi-container-pod spec : containers : - name : container-1-nginx image : nginx ports : - containerPort : 80 - name : container-2-alpine image : alpine command : [ \"watch\" , \"wget\" , \"-qO-\" , \"localhost\" ] EOF \u83b7\u53d6pod\u72b6\u6001\u3002 kubectl get pod multi-container-pod \u8fd0\u884c\u7ed3\u679c \u83b7\u53d6pod\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl describe pod multi-container-pod \u8fd0\u884c\u7ed3\u679c\uff1a ....... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 41s default-scheduler Successfully assigned dev/multi-container-pod to cka002 Normal Pulling 40s kubelet Pulling image \"nginx\" Normal Pulled 23s kubelet Successfully pulled image \"nginx\" in 16.767129903s Normal Created 22s kubelet Created container container-1-nginx Normal Started 22s kubelet Started container container-1-nginx Normal Pulling 22s kubelet Pulling image \"alpine\" Normal Pulled 14s kubelet Successfully pulled image \"alpine\" in 7.776104353s Normal Created 14s kubelet Created container container-2-alpine Normal Started 14s kubelet Started container container-2-alpine \u5bf9\u4e8e\u591a\u5bb9\u5668 Pod\uff0c\u5982\u679c\u6211\u4eec\u60f3\u901a\u8fc7\u547d\u4ee4 kubectl logs \u83b7\u53d6 Pod \u7684\u65e5\u5fd7\uff0c\u9700\u8981\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\u3002\u5982\u679c\u4e0d\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\uff0c\u5c06\u4f1a\u6536\u5230\u9519\u8bef\u4fe1\u606f\u3002 kubectl logs multi-container-pod \u8fd0\u884c\u7ed3\u679c error: a container name must be specified for pod multi-container-pod, choose one of: [ container-1-nginx container-2-alpine ] \u6307\u5b9a\u5bb9\u5668\u540d\u79f0\uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u5230\u5bf9\u5e94\u7684\u65e5\u5fd7\u4fe1\u606f\u3002 kubectl logs multi-container-pod container-1-nginx \u8fd0\u884c\u7ed3\u679c ...... ::1 - - [ 23 /Jul/2022:04:06:37 +0000 ] \"GET / HTTP/1.1\" 200 615 \"-\" \"Wget\" \"-\" \u5982\u679c\u6211\u4eec\u9700\u8981\u4f7f\u7528\u547d\u4ee4 kubectl exec -it -c -- \u767b\u5f55\u5230 Pod \u4e2d\uff0c\u540c\u6837\u9700\u8981\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\u3002\u5982\u679c\u6ca1\u6709\u6307\u5b9a\u5bb9\u5668\u540d\u79f0\uff0c\u4f1a\u51fa\u73b0\u9519\u8bef\u3002 kubectl exec -it multi-container-pod -c container-1-nginx -- /bin/bash root@multi-container-pod:/# ls \u5220\u9664\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u3002 kubectl delete pod multi-container-pod \u4e0b\u9762\u662f\u4e00\u4e2a\u57fa\u672c\u7684yaml\u6587\u4ef6\u7528\u6765\u521b\u5efa\u591a\u5bb9\u5668pod\u3002 kubectl apply -f - << EOF apiVersion : v1 kind : Pod metadata : name : my-multi-pod spec : containers : - image : nginx name : nginx - image : memcached name : memcached - image : redis name : redis EOF \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a my-busybox \u7684Pod\uff0c\u5e76\u5728\u5176\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a container-1-busybox \u7684\u5bb9\u5668\u3002\u8be5\u5bb9\u5668\u5c06\u628a\u6d88\u606f\u5199\u5165\u5230\u6587\u4ef6 /var/log/my-pod-busybox.log \u4e2d\u3002 \u5411Pod my-busybox \u4e2d\u6dfb\u52a0\u53e6\u4e00\u4e2a\u5bb9\u5668 container-2-busybox \uff08Sidecar\uff09\u3002Sidecar\u5bb9\u5668\u4ece\u6587\u4ef6 /var/log/my-pod-busybox.log \u4e2d\u8bfb\u53d6\u6d88\u606f\u3002 \u63d0\u793a\uff1a\u521b\u5efa\u4e00\u4e2aVolume\u6765\u5b58\u50a8\u65e5\u5fd7\u6587\u4ef6\uff0c\u5e76\u4e0e\u4e24\u4e2a\u5bb9\u5668\u5171\u4eab\u3002 \u6f14\u793a\uff1a \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a my-busybox \u7684 Pod\uff0c\u5176\u4e2d\u5305\u542b\u4e00\u4e2a\u5bb9\u5668 container-1-busybox \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-busybox spec: containers: - name: container-1-busybox image: busybox args: - /bin/sh - -c - > i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=$((i+1)); sleep 1; done EOF \u5728 Kubernetes \u6587\u6863\u4e2d\u641c\u7d22 emptyDir \u3002 \u53c2\u8003\u4ee5\u4e0b\u6a21\u677f\u7528\u4e8e emptyDir \uff1a https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/ \u5c06\u4ee5\u4e0b\u65b0\u529f\u80fd\u6dfb\u52a0\u5230 Pod \u4e2d\uff1a Volume\uff1a \u5377\u540d\u79f0\uff1a logfile \u7c7b\u578b\uff1a emptyDir \u66f4\u65b0\u73b0\u6709\u5bb9\u5668\uff1a name: container-1-busybox volumeMounts name: logfile mounthPath: /var/log \u6dfb\u52a0\u65b0\u5bb9\u5668\uff1a name: container-2-busybox image: busybox args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log'] volumeMounts: name: logfile mountPath: /var/log kubectl get pod my-busybox -o yaml > my-busybox.yaml vi my-busybox.yaml kubectl delete pod my-busybox kubectl apply -f my-busybox.yaml kubectl logs my-busybox -c container-2-busybox \u66f4\u65b0\u540e\u7684\u6587\u4ef6 my-busybox.yaml \u5982\u4e0b\uff1a apiVersion : v1 kind : Pod metadata : annotations : cni.projectcalico.org/containerID : 89644b6b073cd152f94b4cae7bdea6bbc3292cf59afd4f28102bd74f0205c9e4 cni.projectcalico.org/podIP : 10.244.102.20/32 cni.projectcalico.org/podIPs : 10.244.102.20/32 kubectl.kubernetes.io/last-applied-configuration : | {\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"my-busybox\",\"namespace\":\"dev\"},\"spec\":{\"containers\":[{\"args\":[\"/bin/sh\",\"-c\",\"i=0; while true; do\\n echo \\\"Hello message from container-1: \\\" \\u003e\\u003e /var/log/my-pod-busybox.log;\\n i=1;\\n sleep 1;\\ndone\\n\"],\"image\":\"busybox\",\"name\":\"container-1-busybox\"}]}} creationTimestamp : \"2022-07-29T22:58:27Z\" name : my-busybox namespace : dev resourceVersion : \"1185720\" uid : c5e62a16-4459-4828-a441-7d1471b89a56 spec : containers : - name : container-2-busybox image : busybox args : [ '/bin/sh' , '-c' , 'tail -n+1 -f /var/log/my-pod-busybox.log' ] volumeMounts : - name : logfile mountPath : /var/log - args : - /bin/sh - -c - | i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=1; sleep 1; done image : busybox imagePullPolicy : Always name : container-1-busybox resources : {} terminationMessagePath : /dev/termination-log terminationMessagePolicy : File volumeMounts : - name : logfile mountPath : /var/log - mountPath : /var/run/secrets/kubernetes.io/serviceaccount name : kube-api-access-mhxlf readOnly : true dnsPolicy : ClusterFirst enableServiceLinks : true nodeName : cka003 preemptionPolicy : PreemptLowerPriority priority : 0 restartPolicy : Always schedulerName : default-scheduler securityContext : {} serviceAccount : default serviceAccountName : default terminationGracePeriodSeconds : 30 tolerations : - effect : NoExecute key : node.kubernetes.io/not-ready operator : Exists tolerationSeconds : 300 - effect : NoExecute key : node.kubernetes.io/unreachable operator : Exists tolerationSeconds : 300 volumes : - name : logfile emptyDir : {} - name : kube-api-access-mhxlf projected : defaultMode : 420 sources : - serviceAccountToken : expirationSeconds : 3607 path : token - configMap : items : - key : ca.crt path : ca.crt name : kube-root-ca.crt - downwardAPI : items : - fieldRef : apiVersion : v1 fieldPath : metadata.namespace path : namespace status : conditions : - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:27Z\" status : \"True\" type : Initialized - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:30Z\" status : \"True\" type : Ready - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:30Z\" status : \"True\" type : ContainersReady - lastProbeTime : null lastTransitionTime : \"2022-07-29T22:58:27Z\" status : \"True\" type : PodScheduled containerStatuses : - containerID : containerd://fd42d4ba4d94d8918d8846327b1db2328be13c5f93f381877ff0228ed7b5468d image : docker.io/library/busybox:latest imageID : docker.io/library/busybox@sha256:0e97a8ca6955f22dbc7db9e9dbe970971f423541e52c34b8cb96ccc88d6a3883 lastState : {} name : container-1-busybox ready : true restartCount : 0 started : true state : running : startedAt : \"2022-07-29T22:58:30Z\" hostIP : phase : Running podIP : 10.244.102.20 podIPs : - ip : 10.244.102.20 qosClass : BestEffort startTime : \"2022-07-29T22:58:27Z\" \u6e05\u7406\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u3002 kubectl delete pod my-busybox","title":"\u591a\u5bb9\u5668Pod"},{"location":"k8s/cka_cn/foundamentals/pod/#pod_5","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u62e5\u6709\u4e24\u4e2a\u521d\u59cb\u5316\u5bb9\u5668\u7684 Pod myapp-pod \u3002 myapp-container init-mydb \u521b\u5efa\u4e24\u4e2a\u670d\u52a1\uff1a myservice mydb \u6f14\u793a\u9884\u671f\u7ed3\u8bba\uff1a myapp-container \u7b49\u5f85\u670d\u52a1 myservice \u542f\u52a8\uff0c\u4ee5\u89e3\u6790\u540d\u79f0 myservice.dev.svc.cluster.local init-mydb \u7b49\u5f85\u670d\u52a1 mydb \u542f\u52a8\uff0c\u4ee5\u89e3\u6790\u540d\u79f0 mydb.dev.svc.cluster.local \u3002 \u6f14\u793a\uff1a \u521b\u5efa\u540d\u4e3a myapp-pod.yaml \u7684yaml\u6587\u4ef6\uff0c\u5e76\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\u3002 \u6ce8\u610f\uff1a\u7531\u4e8e\u547d\u4ee4 $(cat /var/..... \u5c06\u88ab\u89c6\u4e3a\u4e3b\u673a\u53d8\u91cf\uff0c\u56e0\u6b64\u6211\u4eec\u4e0d\u80fd\u4f7f\u7528echo\u751f\u6210\u8be5\u6587\u4ef6\u3002\u5b83\u662f\u5bb9\u5668\u672c\u8eab\u7684\u53d8\u91cf\u3002 vi myapp-pod.yaml \u6587\u4ef6\u5185\u5bb9 apiVersion : v1 kind : Pod metadata : name : myapp-pod labels : app : myapp spec : containers : - name : myapp-container image : busybox:1.28 command : [ 'sh' , '-c' , 'echo The app is running! && sleep 3600' ] initContainers : - name : init-myservice image : busybox:1.28 command : [ 'sh' , '-c' , \"until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done\" ] - name : init-mydb image : busybox:1.28 command : [ 'sh' , '-c' , \"until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done\" ] \u7528\u4e0a\u9762\u521b\u5efa\u7684yaml\u6587\u4ef6\u521b\u5efaPod myapp-pod \u3002 kubectl apply -f myapp-pod.yaml \u68c0\u67e5pod\u7684\u72b6\u6001\u3002 kubectl get pod myapp-pod \u8fd0\u884c\u7ed3\u679c\uff1a NAME READY STATUS RESTARTS AGE myapp-pod 0/1 Init:0/2 0 12m \u68c0\u67e5Pod\uff0c\u53ef\u4ee5\u770b\u5230\u4e24\u4e2a\u9519\u8bef\uff1a nslookup: \u65e0\u6cd5\u89e3\u6790'myservice.dev.svc.cluster.local' Pod \"myapp-pod\"\u4e2d\u7684\u5bb9\u5668\u201cinit-mydb\u201d\u6b63\u5728\u7b49\u5f85\u542f\u52a8\uff1aPodInitializing kubectl logs myapp-pod -c init-myservice # Inspect the first init container kubectl logs myapp-pod -c init-mydb # Inspect the second init container \u5728\u8fd9\u4e2a\u65f6\u5019\uff0c\u8fd9\u4e9b init \u5bb9\u5668\u5c06\u7b49\u5f85\u53d1\u73b0\u540d\u4e3a mydb \u548c myservice \u7684\u670d\u52a1\u3002 \u521b\u5efa mydb \u548c myservice \u670d\u52a1\uff1a kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: myservice spec: ports: - protocol: TCP port: 80 targetPort: 9376 --- apiVersion: v1 kind: Service metadata: name: mydb spec: ports: - protocol: TCP port: 80 targetPort: 9377 EOF \u67e5\u770b\u521b\u5efa\u7684\u670d\u52a1\u7684\u72b6\u6001\u3002 kubectl get service \u521b\u5efa\u76842\u4e2a\u670d\u52a1\u90fd\u662f\u8fd0\u884c\u72b6\u6001\u3002 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mydb ClusterIP 11.244.239.149 80/TCP 6s myservice ClusterIP 11.244.116.126 80/TCP 6s \u518d\u6b21\u67e5\u770bpod\u7684\u72b6\u6001\u3002 kubectl get pod myapp-pod -o wide pod\u5df2\u7ecf\u6b63\u5e38\u8fd0\u884c\u4e86\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-pod 0/1 Init:0/2 0 2m40s 10.244.112.2 cka002 \u73b0\u5728\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u90a3\u4e9b\u521d\u59cb\u5316\u5bb9\u5668\u90fd\u5df2\u7ecf\u5b8c\u6210\uff0c myapp-pod Pod \u8fdb\u5165\u4e86 Running \u72b6\u6001\u3002 \u5220\u9664\u4e0a\u9762\u7ec3\u4e60\u4e2d\u521b\u5efa\u7684pod\u3002 kubectl delete service mydb myservice kubectl delete pod myapp-pod \u53c2\u8003\uff1a Pod basics Lifecycle & phases Kubernetes pod design pattern","title":"\u542b\u521d\u59cb\u5316\u5bb9\u5668Pod"},{"location":"k8s/cka_cn/foundamentals/policy/","text":"CKA\u81ea\u5b66\u7b14\u8bb022:Policy \u00b6 ResourceQuota \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u4e3anamespace quota-object-example \u521b\u5efa\u8d44\u6e90\u914d\u989dResourceQuota object-quota-demo \u3002 \u4e3a NodePort \u6d4b\u8bd5 ResourceQuota object-quota-demo \u3002 \u4e3a PVC \u6d4b\u8bd5 ResourceQuota object-quota-demo \u3002 Create Namespace \u00b6 \u521b\u5efaNamespace\u3002 kubectl create ns quota-object-example \u521b\u5efaResourceQuota \u00b6 \u4e3anamespace quota-object-example \u521b\u5efa\u8d44\u6e90\u914d\u989dResourceQuota object-quota-demo \u3002 \u5728\u8be5namespace\u4e2d\uff0c\u6211\u4eec\u53ea\u80fd\u521b\u5efa 1 \u4e2a\u6c38\u4e45\u5377PVC\u30011 \u4e2a\u8d1f\u8f7d\u5747\u8861LoadBalancer\u670d\u52a1\uff0c\u4e0d\u80fd\u521b\u5efa NodePort \u670d\u52a1\u3002 kubectl apply -f - <@ \uff09 CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev \u521b\u5efaCA\u914d\u7f6e\u6587\u4ef6 \u00b6 CA\uff08Certificate Authority\uff09\u914d\u7f6e\u6587\u4ef6\uff08config file\uff09\u662f\u4e00\u4e2a\u7528\u4e8e\u5b58\u50a8\u8bc1\u4e66\u9881\u53d1\u673a\u6784\uff08CA\uff09\u4fe1\u606f\u7684\u6587\u4ef6\u3002 \u5728\u4f7f\u7528TLS/SSL\u52a0\u5bc6\u901a\u4fe1\u65f6\uff0c\u9700\u8981\u4f7f\u7528\u8bc1\u4e66\u6765\u9a8c\u8bc1\u901a\u4fe1\u53cc\u65b9\u7684\u8eab\u4efd\u3002 \u800cCA\u5219\u662f\u8d1f\u8d23\u7b7e\u53d1\u548c\u9a8c\u8bc1\u8bc1\u4e66\u7684\u673a\u6784\uff0c\u56e0\u6b64\u5728\u5efa\u7acbTLS/SSL\u8fde\u63a5\u65f6\u9700\u8981\u5148\u9a8c\u8bc1CA\u7684\u4fe1\u4efb\u5173\u7cfb\uff0c\u4ee5\u4fdd\u8bc1\u8bc1\u4e66\u7684\u6709\u6548\u6027\u3002 CA\u6587\u4ef6\u4e2d\u5b58\u50a8\u4e86CA\u7684\u516c\u94a5\u4fe1\u606f\u548c\u5176\u4ed6\u76f8\u5173\u7684\u914d\u7f6e\u4fe1\u606f\u3002 \u5728Kubernetes\u4e2d\uff0c\u4f7f\u7528CA\u6587\u4ef6\u6765\u9a8c\u8bc1\u8bc1\u4e66\u7684\u6709\u6548\u6027\u548c\u6388\u6743\u8bbf\u95ee\u3002 \u67e5\u770b\u76ee\u5f55 /etc/kubernetes/pki \u53ca\u5176\u5b50\u76ee\u5f55\u7684\u7ed3\u6784\u60c5\u51b5\u3002 tree /etc/kubernetes/pki \u8fd0\u884c\u7ed3\u679c\uff0c\u4e0b\u9762\u662fKubernetes\u521d\u59cb\u5b89\u88c5\u540e\u7684\u6587\u4ef6\u7ed3\u6784\u7684\u793a\u4f8b\u5185\u5bb9\u3002 /etc/kubernetes/pki \u251c\u2500\u2500 apiserver.crt \u251c\u2500\u2500 apiserver-etcd-client.crt \u251c\u2500\u2500 apiserver-etcd-client.key \u251c\u2500\u2500 apiserver.key \u251c\u2500\u2500 apiserver-kubelet-client.crt \u251c\u2500\u2500 apiserver-kubelet-client.key \u251c\u2500\u2500 ca.crt \u251c\u2500\u2500 ca.key \u251c\u2500\u2500 etcd \u2502 \u251c\u2500\u2500 ca.crt \u2502 \u251c\u2500\u2500 ca.key \u2502 \u251c\u2500\u2500 healthcheck-client.crt \u2502 \u251c\u2500\u2500 healthcheck-client.key \u2502 \u251c\u2500\u2500 peer.crt \u2502 \u251c\u2500\u2500 peer.key \u2502 \u251c\u2500\u2500 server.crt \u2502 \u2514\u2500\u2500 server.key \u251c\u2500\u2500 front-proxy-ca.crt \u251c\u2500\u2500 front-proxy-ca.key \u251c\u2500\u2500 front-proxy-client.crt \u251c\u2500\u2500 front-proxy-client.key \u251c\u2500\u2500 sa.key \u2514\u2500\u2500 sa.pub \u8fdb\u5165\u76ee\u5f55 /etc/kubernetes/pki \uff0c\u5373\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 cd /etc/kubernetes/pki \u68c0\u67e5\u6587\u4ef6 ca-config.json \u662f\u5426\u5df2\u7ecf\u5b58\u5728\u4e0e\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 ll ca-config.json \u5982\u679c\u4e0d\u5b58\u5728\uff0c\u5219\u521b\u5efa\u8fd9\u4e2a\u6587\u4ef6\u3002 \u6211\u4eec\u53ef\u4ee5\u6dfb\u52a0\u591a\u4e2a\u914d\u7f6e\u6587\u4ef6\u6765\u6307\u5b9a\u4e0d\u540c\u7684\u8fc7\u671f\u65e5\u671f\u3001\u573a\u666f\u3001\u53c2\u6570\u7b49\u3002 \u914d\u7f6e\u6587\u4ef6\u5c06\u7528\u4e8e\u7b7e\u7f72\u8bc1\u4e66\u3002 87600 \u5c0f\u65f6\u5927\u7ea6\u662f10\u5e74\u3002 \u8fd9\u91cc\u6211\u4eec\u5c06\u5728 ca-config.json \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a dev \u7684\u914d\u7f6e\u6587\u4ef6\u3002 cat > ca-config.json < cka-dev-csr.json < \uff09\u6765\u62fc\u63a5\u51fa\u73af\u5883\u53d8\u91cf APISERVER \u7684\u503c\uff0c\u5982\uff1a https://: \u3002 kubectl get node -owide \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready control-plane,master 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 \u8bbe\u5b9a\u5e76\u8f93\u51fa\u73af\u5883\u53d8\u91cf APISERVER \u3002 echo \"export APISERVER=\\\"https://:6443\\\"\" >> ~/.bashrc source ~/.bashrc \u9a8c\u8bc1\u73af\u5883\u53d8\u91cf APISERVER \u7684\u503c\u3002 echo $APISERVER \u8fd0\u884c\u7ed3\u679c\uff1a https://:6443 \u8bbe\u7f6e\u96c6\u7fa4 \u00b6 \u4fdd\u6301\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u4e3a /etc/kubernetes/pki \u3002 \u751f\u6210 kubeconfig \u6587\u4ef6\u3002 kubectl config set-cluster kubernetes \\ --certificate-authority = /etc/kubernetes/pki/ca.crt \\ --embed-certs = true \\ --server = ${ APISERVER } \\ --kubeconfig = cka-dev.kubeconfig \u73b0\u5728\u6211\u4eec\u751f\u6210\u4e86\u65b0\u7684\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u3002 ll -tr | grep cka-dev \u8f93\u51fa\u7ed3\u679c\uff1a -rw-r--r-- 1 root root 222 Jul 24 08:49 cka-dev-csr.json -rw-r--r-- 1 root root 1281 Jul 24 09:14 cka-dev.pem -rw------- 1 root root 1675 Jul 24 09:14 cka-dev-key.pem -rw-r--r-- 1 root root 1001 Jul 24 09:14 cka-dev.csr -rw------- 1 root root 1671 Jul 24 09:16 cka-dev.kubeconfig \u8bfb\u53d6\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u7684\u5185\u5bb9\u3002 cat cka-dev.kubeconfig \u8f93\u51fa\u7684\u5185\u5bb9\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : null \u914d\u7f6e\u7528\u6237 \u00b6 \u5728\u6587\u4ef6 cka-dev.kubeconfig \u4e2d\uff0c\u7528\u6237\u4fe1\u606f\u8fd9\u90e8\u5206\u662f\u7a7a\u7684\u3002 \u4e0b\u9762\u6211\u4eec\u914d\u7f6e\u4e00\u4e2a\u7528\u6237 cka-dev \u3002 kubectl config set-credentials cka-dev \\ --client-certificate = /etc/kubernetes/pki/cka-dev.pem \\ --client-key = /etc/kubernetes/pki/cka-dev-key.pem \\ --embed-certs = true \\ --kubeconfig = cka-dev.kubeconfig \u73b0\u5728\uff0c\u7528\u6237\u4fe1\u606f\u5df2\u7ecf\u88ab\u6dfb\u52a0\u5230\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u4e2d\u4e86\u3002 cat cka-dev.kubeconfig \u8f93\u51fa\u7ed3\u679c\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : - name : cka-dev user : client-certificate-data : client-key-data : \u81f3\u6b64\u6211\u4eec\u5f97\u5230\u4e86\u4e00\u4e2a\u5b8c\u6574\u7684\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u3002 \u7531\u4e8e\u6211\u4eec\u6ca1\u6709\u5728 kubeconfig \u6587\u4ef6\u4e2d\u8bbe\u7f6e\u5f53\u524d\u4e0a\u4e0b\u6587\uff0c\u5f53\u6211\u4eec\u4f7f\u7528\u5b83\u6765\u83b7\u53d6\u8282\u70b9\u4fe1\u606f\u65f6\uff0c\u4f1a\u6536\u5230\u4ee5\u4e0b\u9519\u8bef\u3002 kubectl --kubeconfig = cka-dev.kubeconfig get nodes \u8fd0\u884c\u7ed3\u679c\uff1a The connection to the server localhost:8080 was refused - did you specify the right host or port? \u5f53\u524d\u4e0a\u4e0b\u6587\u5185\u5bb9\u662f\u7a7a\u767d\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config get-contexts \u8f93\u51fa\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE \u914d\u7f6e\u4e0a\u4e0b\u6587 \u00b6 \u914d\u7f6e\u4e0a\u4e0b\u6587\u3002 kubectl config set-context dev --cluster = kubernetes --user = cka-dev --kubeconfig = cka-dev.kubeconfig \u73b0\u5728\u6211\u4eec\u914d\u7f6e\u4e86\u4e0a\u4e0b\u6587\uff0c\u4f46\u5176\u4e2d CURRENT \u4ecd\u7136\u662f\u7a7a\u767d\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev \u8bbe\u7f6e\u9ed8\u8ba4\u4e0a\u4e0b\u6587\u3002\u4e0a\u4e0b\u6587\u5c06\u4e3a\u591a\u96c6\u7fa4\u73af\u5883\u4e2d\u7684\u96c6\u7fa4\u548c\u7528\u6237\u94fe\u63a5\uff0c\u5e76\u4e14\u6211\u4eec\u53ef\u4ee5\u5207\u6362\u5230\u4e0d\u540c\u7684\u96c6\u7fa4\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config use-context dev \u9a8c\u8bc1 \u00b6 \u73b0\u5728 CURRENT \u5df2\u7ecf\u88ab\u6807\u8bb0\u4e3a * \u4e86\uff0c\u8fd9\u5c31\u8bf4\u660e\u5f53\u524d\u4e0a\u4e0b\u6587\u5df2\u7ecf\u914d\u7f6e\u597d\u4e86\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev \u56e0\u4e3a\u7528\u6237 cka-dev \u5728\u8be5\u96c6\u7fa4\u4e2d\u6ca1\u6709\u6388\u6743\uff0c\u6240\u4ee5\u5f53\u6211\u4eec\u5c1d\u8bd5\u83b7\u53d6 Pod \u6216 Node \u7684\u4fe1\u606f\u65f6\uff0c\u4f1a\u6536\u5230\u201c\u7981\u6b62\u8bbf\u95ee\uff08forbidden\uff09\u201d\u9519\u8bef\u3002 kubectl --kubeconfig = /etc/kubernetes/pki/cka-dev.kubeconfig get pod kubectl --kubeconfig = /etc/kubernetes/pki/cka-dev.kubeconfig get node \u5408\u5e76kubeconfig\u6587\u4ef6 \u00b6 \u62f7\u8d1d\u5f53\u524d\u914d\u7f6e\u6587\u4ef6\uff0c\u4f5c\u4e3a\u5907\u4efd\u3002 cp ~/.kube/config ~/.kube/config.old \u628a\u4e24\u4e2a\u914d\u7f6e\u6587\u4ef6\u5408\u5e76\u6210\u4e00\u4e2a\u65b0\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5e76\u5b58\u653e\u5728 /tmp/config \u3002 KUBECONFIG = ~/.kube/config:/etc/kubernetes/pki/cka-dev.kubeconfig kubectl config view --flatten > /tmp/config \u7528\u5408\u5e76\u540e\u7684\u65b0\u914d\u7f6e\u6587\u4ef6\u66ff\u6362\u8001\u7684\u914d\u7f6e\u6587\u4ef6\u3002 mv /tmp/config ~/.kube/config \u65b0\u7684\u914d\u7f6e\u6587\u4ef6 ~/.kube/config \u7c7b\u4f3c\u5982\u4e0b\u3002 apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : - context : cluster : kubernetes user : cka-dev name : dev - context : cluster : kubernetes user : kubernetes-admin name : kubernetes-admin@kubernetes current-context : kubernetes-admin@kubernetes kind : Config preferences : {} users : - name : cka-dev user : client-certificate-data : client-key-data : - name : kubernetes-admin user : client-certificate-data : client-key-data : \u68c0\u67e5\u57fa\u4e8e\u65b0\u7684\u914d\u7f6e\u6587\u4ef6\u4e0b\u7684\u5f53\u524d\u4e0a\u4e0b\u6587\u3002 kubectl config get-contexts \u5f53\u524d\u4e0a\u4e0b\u6587\u662f\u7cfb\u7edf\u9ed8\u8ba4\u914d\u7f6e kubernetes-admin@kubernetes \u3002 CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev \u547d\u540d\u7a7a\u95f4\u548c\u4e0a\u4e0b\u6587 \u00b6 \u67e5\u8be2\u5f53\u524d\u547d\u540d\u7a7a\u95f4namespace\u5217\u8868\u548c\u5bf9\u5e94\u6807\u7b7elabel\u7684\u4fe1\u606f\u3002 kubectl get ns --show-labels \u521b\u5efanamespace cka \u3002 kubectl create namespace cka \u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u66f4\u65b0\u4e0a\u4e0b\u6587\u4fe1\u606f\uff0c\u4f8b\u5982\uff0c\u66f4\u65b0\u9ed8\u8ba4\u547d\u540d\u7a7a\u95f4\u7b49\u3002 kubectl config set-context --cluster = --namespace = --user = \u4e0b\u9762\u9488\u5bf9\u6bcf\u4e2a\u4e0a\u4e0b\u6587context\u8bbe\u5b9a\u9ed8\u8ba4\u7684namespace\u3002 kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin kubectl config set-context dev --cluster = kubernetes --namespace = cka --user = cka-dev \u68c0\u67e5\u5f53\u524d\u4e0a\u4e0b\u6587context\u7684\u4fe1\u606f\u3002 kubectl config get-contexts \u8f93\u51fa\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev cka * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev \u901a\u8fc7\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u53ef\u4ee5\u5207\u6362\u5230\u65b0\u7684context\u3002 kubectl config use-contexts \u4f8b\u5982\uff1a kubectl config use-context dev \u68c0\u67e5\u4e0a\u9762\u7684\u53d8\u66f4\u662f\u5426\u751f\u6548\u3002 kubectl config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1b CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev cka kubernetes-admin@kubernetes kubernetes kubernetes-admin dev Be noted, four users beginning with cka-dev created don't have any authorizations, e.g., access namespaces, get pods, etc.. Referring RBAC to grant their authorizations. \u6ce8\u610f\uff1a\u524d\u9762\u521b\u5efa\u7684\u4ee5 cka-dev \u5f00\u5934\u7684\u7528\u6237\u5b9e\u9645\u6ca1\u6709\u4efb\u4f55\u6743\u9650\uff0c\u4f8b\u5982\u8bbf\u95ee\u547d\u540d\u7a7a\u95f4\u3001\u83b7\u53d6 pod \u7b49\uff0c\u4e0b\u9762\u5c06\u901a\u8fc7 RBAC \u6388\u4e88\u4ed6\u4eec\u6388\u6743\u3002 \u89d2\u8272Role\u548c\u89d2\u8272\u7ed1\u5b9aRoleBinding \u00b6 \u5c06\u5f53\u524d\u5de5\u4f5c\u4e0a\u4e0b\u6587\u5207\u6362\u5230 kubernetes-admin@kubernetes \u3002 kubectl config use-context kubernetes-admin@kubernetes \u4f7f\u7528\u5e26\u6709\u9009\u9879 --dry-run=client \u548c -o yaml \u7684 kubectl create role \u547d\u4ee4\uff0c\u751f\u6210\u521b\u5efa\u89d2\u8272role\u7684 yaml \u6a21\u677f\u3002 kubectl create role admin-dev --resource = pods --verb = get --verb = list --verb = watch --dry-run = client -o yaml \u5728namespace cka \u4e0a\u521b\u5efa\u89d2\u8272role admin-dev \u3002 kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: cka name: admin-dev rules: - apiGroups: - \"\" resources: - pods verbs: - get - watch - list EOF \u4f7f\u7528\u5e26\u6709\u9009\u9879 --dry-run=client \u548c -o yaml \u7684 kubectl create rolebinding \u547d\u4ee4\uff0c\u751f\u6210\u521b\u5efa\u89d2\u8272\u7ed1\u5b9arolebinding\u7684 yaml \u6a21\u677f\u3002 kubectl create rolebinding admin --role = admin-dev --user = cka-dev --dry-run = client -o yaml \u5728namespace cka \u4e0a\u521b\u5efa\u4e00\u4e2a\u89d2\u8272\u7ed1\u5b9arolebinding admin \u3002 kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: admin namespace: cka roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: admin-dev subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: cka-dev EOF \u9a8c\u8bc1namespace cka \u4e0a\u7684\u7528\u6237 cka-dev \u7684\u6743\u9650\u3002 \u5207\u6362\u5230\u4e0a\u4e0b\u6587 dev \u3002 kubectl config use-context dev \u67e5\u8be2namespace cka \u4e0apod\u7684\u72b6\u6001\uff0c\u6210\u529f\uff01 kubectl get pod -n cka \u67e5\u8be2namespace kube-system \u4e0apod\u7684\u72b6\u6001\uff0c\u5931\u8d25\uff01\u56e0\u4e3a\u524d\u9762\u6dfb\u52a0\u7684\u6743\u9650\u4ec5\u9650\u4e8enamespace cka \u3002 kubectl get pod -n kube-system \u67e5\u8be2\u8282\u70b9node\u7684\u72b6\u6001\uff0c\u5931\u8d25\uff01\u56e0\u4e3a\u5728\u89d2\u8272role\u91cc\u9762\u6211\u4eec\u53ea\u5b9a\u4e49\u4e86pod\u8fd9\u4e00\u79cd\u8d44\u6e90\u3002 kubectl get node \u5728namespace dev \u4e0a\u521b\u5efa\u4e00\u4e2apod\uff0c\u5931\u8d25\uff01\u56e0\u4e3a\u6211\u4eec\u5728\u53ea\u6709\u5bf9pod\u7684 get , watch , list \u4e09\u79cd\u64cd\u4f5c\u6743\u9650\uff0c\u6ca1\u6709 create \u6743\u9650\u3002 kubectl run nginx --image = nginx -n cka \u96c6\u7fa4\u89d2\u8272ClusterRole\u548c\u96c6\u7fa4\u89d2\u8272\u7ed1\u5b9aClusterRoleBinding \u00b6 \u5207\u6362\u5230\u4e0a\u4e0b\u6587 kubernetes-admin@kubernetes \u3002 kubectl config use-context kubernetes-admin@kubernetes \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a nodes-admin \u7684 ClusterRole\uff0c\u5b83\u6388\u4e88 get \u3001 watch \u3001 list \u5bf9 nodes \u8d44\u6e90\u7684\u6388\u6743\u3002 kubectl apply -f - <@ \uff09 CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev","title":"\u5f53\u524d\u4e0a\u4e0b\u6587"},{"location":"k8s/cka_cn/foundamentals/rbac/#ca","text":"CA\uff08Certificate Authority\uff09\u914d\u7f6e\u6587\u4ef6\uff08config file\uff09\u662f\u4e00\u4e2a\u7528\u4e8e\u5b58\u50a8\u8bc1\u4e66\u9881\u53d1\u673a\u6784\uff08CA\uff09\u4fe1\u606f\u7684\u6587\u4ef6\u3002 \u5728\u4f7f\u7528TLS/SSL\u52a0\u5bc6\u901a\u4fe1\u65f6\uff0c\u9700\u8981\u4f7f\u7528\u8bc1\u4e66\u6765\u9a8c\u8bc1\u901a\u4fe1\u53cc\u65b9\u7684\u8eab\u4efd\u3002 \u800cCA\u5219\u662f\u8d1f\u8d23\u7b7e\u53d1\u548c\u9a8c\u8bc1\u8bc1\u4e66\u7684\u673a\u6784\uff0c\u56e0\u6b64\u5728\u5efa\u7acbTLS/SSL\u8fde\u63a5\u65f6\u9700\u8981\u5148\u9a8c\u8bc1CA\u7684\u4fe1\u4efb\u5173\u7cfb\uff0c\u4ee5\u4fdd\u8bc1\u8bc1\u4e66\u7684\u6709\u6548\u6027\u3002 CA\u6587\u4ef6\u4e2d\u5b58\u50a8\u4e86CA\u7684\u516c\u94a5\u4fe1\u606f\u548c\u5176\u4ed6\u76f8\u5173\u7684\u914d\u7f6e\u4fe1\u606f\u3002 \u5728Kubernetes\u4e2d\uff0c\u4f7f\u7528CA\u6587\u4ef6\u6765\u9a8c\u8bc1\u8bc1\u4e66\u7684\u6709\u6548\u6027\u548c\u6388\u6743\u8bbf\u95ee\u3002 \u67e5\u770b\u76ee\u5f55 /etc/kubernetes/pki \u53ca\u5176\u5b50\u76ee\u5f55\u7684\u7ed3\u6784\u60c5\u51b5\u3002 tree /etc/kubernetes/pki \u8fd0\u884c\u7ed3\u679c\uff0c\u4e0b\u9762\u662fKubernetes\u521d\u59cb\u5b89\u88c5\u540e\u7684\u6587\u4ef6\u7ed3\u6784\u7684\u793a\u4f8b\u5185\u5bb9\u3002 /etc/kubernetes/pki \u251c\u2500\u2500 apiserver.crt \u251c\u2500\u2500 apiserver-etcd-client.crt \u251c\u2500\u2500 apiserver-etcd-client.key \u251c\u2500\u2500 apiserver.key \u251c\u2500\u2500 apiserver-kubelet-client.crt \u251c\u2500\u2500 apiserver-kubelet-client.key \u251c\u2500\u2500 ca.crt \u251c\u2500\u2500 ca.key \u251c\u2500\u2500 etcd \u2502 \u251c\u2500\u2500 ca.crt \u2502 \u251c\u2500\u2500 ca.key \u2502 \u251c\u2500\u2500 healthcheck-client.crt \u2502 \u251c\u2500\u2500 healthcheck-client.key \u2502 \u251c\u2500\u2500 peer.crt \u2502 \u251c\u2500\u2500 peer.key \u2502 \u251c\u2500\u2500 server.crt \u2502 \u2514\u2500\u2500 server.key \u251c\u2500\u2500 front-proxy-ca.crt \u251c\u2500\u2500 front-proxy-ca.key \u251c\u2500\u2500 front-proxy-client.crt \u251c\u2500\u2500 front-proxy-client.key \u251c\u2500\u2500 sa.key \u2514\u2500\u2500 sa.pub \u8fdb\u5165\u76ee\u5f55 /etc/kubernetes/pki \uff0c\u5373\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 cd /etc/kubernetes/pki \u68c0\u67e5\u6587\u4ef6 ca-config.json \u662f\u5426\u5df2\u7ecf\u5b58\u5728\u4e0e\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 ll ca-config.json \u5982\u679c\u4e0d\u5b58\u5728\uff0c\u5219\u521b\u5efa\u8fd9\u4e2a\u6587\u4ef6\u3002 \u6211\u4eec\u53ef\u4ee5\u6dfb\u52a0\u591a\u4e2a\u914d\u7f6e\u6587\u4ef6\u6765\u6307\u5b9a\u4e0d\u540c\u7684\u8fc7\u671f\u65e5\u671f\u3001\u573a\u666f\u3001\u53c2\u6570\u7b49\u3002 \u914d\u7f6e\u6587\u4ef6\u5c06\u7528\u4e8e\u7b7e\u7f72\u8bc1\u4e66\u3002 87600 \u5c0f\u65f6\u5927\u7ea6\u662f10\u5e74\u3002 \u8fd9\u91cc\u6211\u4eec\u5c06\u5728 ca-config.json \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a dev \u7684\u914d\u7f6e\u6587\u4ef6\u3002 cat > ca-config.json < cka-dev-csr.json < \uff09\u6765\u62fc\u63a5\u51fa\u73af\u5883\u53d8\u91cf APISERVER \u7684\u503c\uff0c\u5982\uff1a https://: \u3002 kubectl get node -owide \u8fd0\u884c\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready control-plane,master 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 \u8bbe\u5b9a\u5e76\u8f93\u51fa\u73af\u5883\u53d8\u91cf APISERVER \u3002 echo \"export APISERVER=\\\"https://:6443\\\"\" >> ~/.bashrc source ~/.bashrc \u9a8c\u8bc1\u73af\u5883\u53d8\u91cf APISERVER \u7684\u503c\u3002 echo $APISERVER \u8fd0\u884c\u7ed3\u679c\uff1a https://:6443","title":"\u521b\u5efakubeconfig\u6587\u4ef6"},{"location":"k8s/cka_cn/foundamentals/rbac/#_4","text":"\u4fdd\u6301\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u4e3a /etc/kubernetes/pki \u3002 \u751f\u6210 kubeconfig \u6587\u4ef6\u3002 kubectl config set-cluster kubernetes \\ --certificate-authority = /etc/kubernetes/pki/ca.crt \\ --embed-certs = true \\ --server = ${ APISERVER } \\ --kubeconfig = cka-dev.kubeconfig \u73b0\u5728\u6211\u4eec\u751f\u6210\u4e86\u65b0\u7684\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u3002 ll -tr | grep cka-dev \u8f93\u51fa\u7ed3\u679c\uff1a -rw-r--r-- 1 root root 222 Jul 24 08:49 cka-dev-csr.json -rw-r--r-- 1 root root 1281 Jul 24 09:14 cka-dev.pem -rw------- 1 root root 1675 Jul 24 09:14 cka-dev-key.pem -rw-r--r-- 1 root root 1001 Jul 24 09:14 cka-dev.csr -rw------- 1 root root 1671 Jul 24 09:16 cka-dev.kubeconfig \u8bfb\u53d6\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u7684\u5185\u5bb9\u3002 cat cka-dev.kubeconfig \u8f93\u51fa\u7684\u5185\u5bb9\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : null","title":"\u8bbe\u7f6e\u96c6\u7fa4"},{"location":"k8s/cka_cn/foundamentals/rbac/#_5","text":"\u5728\u6587\u4ef6 cka-dev.kubeconfig \u4e2d\uff0c\u7528\u6237\u4fe1\u606f\u8fd9\u90e8\u5206\u662f\u7a7a\u7684\u3002 \u4e0b\u9762\u6211\u4eec\u914d\u7f6e\u4e00\u4e2a\u7528\u6237 cka-dev \u3002 kubectl config set-credentials cka-dev \\ --client-certificate = /etc/kubernetes/pki/cka-dev.pem \\ --client-key = /etc/kubernetes/pki/cka-dev-key.pem \\ --embed-certs = true \\ --kubeconfig = cka-dev.kubeconfig \u73b0\u5728\uff0c\u7528\u6237\u4fe1\u606f\u5df2\u7ecf\u88ab\u6dfb\u52a0\u5230\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u4e2d\u4e86\u3002 cat cka-dev.kubeconfig \u8f93\u51fa\u7ed3\u679c\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : - name : cka-dev user : client-certificate-data : client-key-data : \u81f3\u6b64\u6211\u4eec\u5f97\u5230\u4e86\u4e00\u4e2a\u5b8c\u6574\u7684\u914d\u7f6e\u6587\u4ef6 cka-dev.kubeconfig \u3002 \u7531\u4e8e\u6211\u4eec\u6ca1\u6709\u5728 kubeconfig \u6587\u4ef6\u4e2d\u8bbe\u7f6e\u5f53\u524d\u4e0a\u4e0b\u6587\uff0c\u5f53\u6211\u4eec\u4f7f\u7528\u5b83\u6765\u83b7\u53d6\u8282\u70b9\u4fe1\u606f\u65f6\uff0c\u4f1a\u6536\u5230\u4ee5\u4e0b\u9519\u8bef\u3002 kubectl --kubeconfig = cka-dev.kubeconfig get nodes \u8fd0\u884c\u7ed3\u679c\uff1a The connection to the server localhost:8080 was refused - did you specify the right host or port? \u5f53\u524d\u4e0a\u4e0b\u6587\u5185\u5bb9\u662f\u7a7a\u767d\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config get-contexts \u8f93\u51fa\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE","title":"\u914d\u7f6e\u7528\u6237"},{"location":"k8s/cka_cn/foundamentals/rbac/#_6","text":"\u914d\u7f6e\u4e0a\u4e0b\u6587\u3002 kubectl config set-context dev --cluster = kubernetes --user = cka-dev --kubeconfig = cka-dev.kubeconfig \u73b0\u5728\u6211\u4eec\u914d\u7f6e\u4e86\u4e0a\u4e0b\u6587\uff0c\u4f46\u5176\u4e2d CURRENT \u4ecd\u7136\u662f\u7a7a\u767d\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev \u8bbe\u7f6e\u9ed8\u8ba4\u4e0a\u4e0b\u6587\u3002\u4e0a\u4e0b\u6587\u5c06\u4e3a\u591a\u96c6\u7fa4\u73af\u5883\u4e2d\u7684\u96c6\u7fa4\u548c\u7528\u6237\u94fe\u63a5\uff0c\u5e76\u4e14\u6211\u4eec\u53ef\u4ee5\u5207\u6362\u5230\u4e0d\u540c\u7684\u96c6\u7fa4\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config use-context dev","title":"\u914d\u7f6e\u4e0a\u4e0b\u6587"},{"location":"k8s/cka_cn/foundamentals/rbac/#_7","text":"\u73b0\u5728 CURRENT \u5df2\u7ecf\u88ab\u6807\u8bb0\u4e3a * \u4e86\uff0c\u8fd9\u5c31\u8bf4\u660e\u5f53\u524d\u4e0a\u4e0b\u6587\u5df2\u7ecf\u914d\u7f6e\u597d\u4e86\u3002 kubectl --kubeconfig = cka-dev.kubeconfig config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev \u56e0\u4e3a\u7528\u6237 cka-dev \u5728\u8be5\u96c6\u7fa4\u4e2d\u6ca1\u6709\u6388\u6743\uff0c\u6240\u4ee5\u5f53\u6211\u4eec\u5c1d\u8bd5\u83b7\u53d6 Pod \u6216 Node \u7684\u4fe1\u606f\u65f6\uff0c\u4f1a\u6536\u5230\u201c\u7981\u6b62\u8bbf\u95ee\uff08forbidden\uff09\u201d\u9519\u8bef\u3002 kubectl --kubeconfig = /etc/kubernetes/pki/cka-dev.kubeconfig get pod kubectl --kubeconfig = /etc/kubernetes/pki/cka-dev.kubeconfig get node","title":"\u9a8c\u8bc1"},{"location":"k8s/cka_cn/foundamentals/rbac/#kubeconfig_1","text":"\u62f7\u8d1d\u5f53\u524d\u914d\u7f6e\u6587\u4ef6\uff0c\u4f5c\u4e3a\u5907\u4efd\u3002 cp ~/.kube/config ~/.kube/config.old \u628a\u4e24\u4e2a\u914d\u7f6e\u6587\u4ef6\u5408\u5e76\u6210\u4e00\u4e2a\u65b0\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5e76\u5b58\u653e\u5728 /tmp/config \u3002 KUBECONFIG = ~/.kube/config:/etc/kubernetes/pki/cka-dev.kubeconfig kubectl config view --flatten > /tmp/config \u7528\u5408\u5e76\u540e\u7684\u65b0\u914d\u7f6e\u6587\u4ef6\u66ff\u6362\u8001\u7684\u914d\u7f6e\u6587\u4ef6\u3002 mv /tmp/config ~/.kube/config \u65b0\u7684\u914d\u7f6e\u6587\u4ef6 ~/.kube/config \u7c7b\u4f3c\u5982\u4e0b\u3002 apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : - context : cluster : kubernetes user : cka-dev name : dev - context : cluster : kubernetes user : kubernetes-admin name : kubernetes-admin@kubernetes current-context : kubernetes-admin@kubernetes kind : Config preferences : {} users : - name : cka-dev user : client-certificate-data : client-key-data : - name : kubernetes-admin user : client-certificate-data : client-key-data : \u68c0\u67e5\u57fa\u4e8e\u65b0\u7684\u914d\u7f6e\u6587\u4ef6\u4e0b\u7684\u5f53\u524d\u4e0a\u4e0b\u6587\u3002 kubectl config get-contexts \u5f53\u524d\u4e0a\u4e0b\u6587\u662f\u7cfb\u7edf\u9ed8\u8ba4\u914d\u7f6e kubernetes-admin@kubernetes \u3002 CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev","title":"\u5408\u5e76kubeconfig\u6587\u4ef6"},{"location":"k8s/cka_cn/foundamentals/rbac/#_8","text":"\u67e5\u8be2\u5f53\u524d\u547d\u540d\u7a7a\u95f4namespace\u5217\u8868\u548c\u5bf9\u5e94\u6807\u7b7elabel\u7684\u4fe1\u606f\u3002 kubectl get ns --show-labels \u521b\u5efanamespace cka \u3002 kubectl create namespace cka \u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u66f4\u65b0\u4e0a\u4e0b\u6587\u4fe1\u606f\uff0c\u4f8b\u5982\uff0c\u66f4\u65b0\u9ed8\u8ba4\u547d\u540d\u7a7a\u95f4\u7b49\u3002 kubectl config set-context --cluster = --namespace = --user = \u4e0b\u9762\u9488\u5bf9\u6bcf\u4e2a\u4e0a\u4e0b\u6587context\u8bbe\u5b9a\u9ed8\u8ba4\u7684namespace\u3002 kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin kubectl config set-context dev --cluster = kubernetes --namespace = cka --user = cka-dev \u68c0\u67e5\u5f53\u524d\u4e0a\u4e0b\u6587context\u7684\u4fe1\u606f\u3002 kubectl config get-contexts \u8f93\u51fa\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev cka * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev \u901a\u8fc7\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u53ef\u4ee5\u5207\u6362\u5230\u65b0\u7684context\u3002 kubectl config use-contexts \u4f8b\u5982\uff1a kubectl config use-context dev \u68c0\u67e5\u4e0a\u9762\u7684\u53d8\u66f4\u662f\u5426\u751f\u6548\u3002 kubectl config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1b CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev cka kubernetes-admin@kubernetes kubernetes kubernetes-admin dev Be noted, four users beginning with cka-dev created don't have any authorizations, e.g., access namespaces, get pods, etc.. Referring RBAC to grant their authorizations. \u6ce8\u610f\uff1a\u524d\u9762\u521b\u5efa\u7684\u4ee5 cka-dev \u5f00\u5934\u7684\u7528\u6237\u5b9e\u9645\u6ca1\u6709\u4efb\u4f55\u6743\u9650\uff0c\u4f8b\u5982\u8bbf\u95ee\u547d\u540d\u7a7a\u95f4\u3001\u83b7\u53d6 pod \u7b49\uff0c\u4e0b\u9762\u5c06\u901a\u8fc7 RBAC \u6388\u4e88\u4ed6\u4eec\u6388\u6743\u3002","title":"\u547d\u540d\u7a7a\u95f4\u548c\u4e0a\u4e0b\u6587"},{"location":"k8s/cka_cn/foundamentals/rbac/#rolerolebinding","text":"\u5c06\u5f53\u524d\u5de5\u4f5c\u4e0a\u4e0b\u6587\u5207\u6362\u5230 kubernetes-admin@kubernetes \u3002 kubectl config use-context kubernetes-admin@kubernetes \u4f7f\u7528\u5e26\u6709\u9009\u9879 --dry-run=client \u548c -o yaml \u7684 kubectl create role \u547d\u4ee4\uff0c\u751f\u6210\u521b\u5efa\u89d2\u8272role\u7684 yaml \u6a21\u677f\u3002 kubectl create role admin-dev --resource = pods --verb = get --verb = list --verb = watch --dry-run = client -o yaml \u5728namespace cka \u4e0a\u521b\u5efa\u89d2\u8272role admin-dev \u3002 kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: cka name: admin-dev rules: - apiGroups: - \"\" resources: - pods verbs: - get - watch - list EOF \u4f7f\u7528\u5e26\u6709\u9009\u9879 --dry-run=client \u548c -o yaml \u7684 kubectl create rolebinding \u547d\u4ee4\uff0c\u751f\u6210\u521b\u5efa\u89d2\u8272\u7ed1\u5b9arolebinding\u7684 yaml \u6a21\u677f\u3002 kubectl create rolebinding admin --role = admin-dev --user = cka-dev --dry-run = client -o yaml \u5728namespace cka \u4e0a\u521b\u5efa\u4e00\u4e2a\u89d2\u8272\u7ed1\u5b9arolebinding admin \u3002 kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: admin namespace: cka roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: admin-dev subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: cka-dev EOF \u9a8c\u8bc1namespace cka \u4e0a\u7684\u7528\u6237 cka-dev \u7684\u6743\u9650\u3002 \u5207\u6362\u5230\u4e0a\u4e0b\u6587 dev \u3002 kubectl config use-context dev \u67e5\u8be2namespace cka \u4e0apod\u7684\u72b6\u6001\uff0c\u6210\u529f\uff01 kubectl get pod -n cka \u67e5\u8be2namespace kube-system \u4e0apod\u7684\u72b6\u6001\uff0c\u5931\u8d25\uff01\u56e0\u4e3a\u524d\u9762\u6dfb\u52a0\u7684\u6743\u9650\u4ec5\u9650\u4e8enamespace cka \u3002 kubectl get pod -n kube-system \u67e5\u8be2\u8282\u70b9node\u7684\u72b6\u6001\uff0c\u5931\u8d25\uff01\u56e0\u4e3a\u5728\u89d2\u8272role\u91cc\u9762\u6211\u4eec\u53ea\u5b9a\u4e49\u4e86pod\u8fd9\u4e00\u79cd\u8d44\u6e90\u3002 kubectl get node \u5728namespace dev \u4e0a\u521b\u5efa\u4e00\u4e2apod\uff0c\u5931\u8d25\uff01\u56e0\u4e3a\u6211\u4eec\u5728\u53ea\u6709\u5bf9pod\u7684 get , watch , list \u4e09\u79cd\u64cd\u4f5c\u6743\u9650\uff0c\u6ca1\u6709 create \u6743\u9650\u3002 kubectl run nginx --image = nginx -n cka","title":"\u89d2\u8272Role\u548c\u89d2\u8272\u7ed1\u5b9aRoleBinding"},{"location":"k8s/cka_cn/foundamentals/rbac/#clusterroleclusterrolebinding","text":"\u5207\u6362\u5230\u4e0a\u4e0b\u6587 kubernetes-admin@kubernetes \u3002 kubectl config use-context kubernetes-admin@kubernetes \u521b\u5efa\u4e00\u4e2a\u540d\u4e3a nodes-admin \u7684 ClusterRole\uff0c\u5b83\u6388\u4e88 get \u3001 watch \u3001 list \u5bf9 nodes \u8d44\u6e90\u7684\u6388\u6743\u3002 kubectl apply -f - < nodeName \u00b6 \u6ce8\u610f\uff0c nodeName \u5177\u6709\u6700\u9ad8\u4f18\u5148\u7ea7\uff0c\u56e0\u4e3a\u5b83\u4e0d\u662f\u7531 Scheduler \u8fdb\u884c\u8c03\u5ea6\u7684\u3002 \u521b\u5efa\u4e00\u4e2a Pod nginx-nodename \uff0c\u5e76\u5c06\u5176\u6307\u5b9a\u5728 cka003 \u8282\u70b9\u4e0a\u3002 kubectl apply -f - < Affinity \u00b6 \u5728 Kubernetes \u96c6\u7fa4\u4e2d\uff0c\u6709\u4e9b Pod \u9700\u8981\u9891\u7e41\u4e0e\u5176\u4ed6 Pod \u8fdb\u884c\u4ea4\u4e92\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5efa\u8bae\u5c06\u8fd9\u4e9b Pod \u8c03\u5ea6\u5230\u540c\u4e00\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u3002\u4f8b\u5982\uff0c\u4e24\u4e2a Pod\uff1a Nginx \u548c Mysql \uff0c\u5982\u679c\u5b83\u4eec\u9891\u7e41\u901a\u4fe1\uff0c\u5219\u9700\u8981\u5728\u540c\u4e00\u4e2a\u8282\u70b9\u4e0a\u90e8\u7f72\u5b83\u4eec\u3002 \u57fa\u4e8epod\u4e4b\u95f4\u7684\u5173\u7cfb\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 podAffinity \u8fdb\u884c\u9009\u62e9\u3002 podAffinity \u6709\u4e24\u79cd\u8c03\u5ea6\u7c7b\u578b\uff1a requiredDuringSchedulingIgnoredDuringExecution \uff08\u786c\u4eb2\u548c\uff09 preferredDuringSchedulingIgnoredDuringExecution \uff08\u8f6f\u4eb2\u548c\uff09 \u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u7c7b\u578b\u8bbe\u7f6e topologyKey \uff1a kubernetes.io/hostname \uff03NodeName failure-domain.beta.kubernetes.io/zone \uff03\u533a\u57df Zone failure-domain.beta.kubernetes.io/region # \u533a\u57df Zone \u6211\u4eec\u53ef\u4ee5\u8bbe\u7f6e\u8282\u70b9\u6807\u7b7e\u6765\u5bf9\u8282\u70b9\u7684\u540d\u79f0/\u533a\u57df\u8fdb\u884c\u5206\u7c7b\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u88ab podAffinity \u6240\u4f7f\u7528\u3002 \u521b\u5efapod Nginx \u3002 kubectl apply -f - < ","title":"nodeSelector"},{"location":"k8s/cka_cn/foundamentals/scheduling/#nodename","text":"\u6ce8\u610f\uff0c nodeName \u5177\u6709\u6700\u9ad8\u4f18\u5148\u7ea7\uff0c\u56e0\u4e3a\u5b83\u4e0d\u662f\u7531 Scheduler \u8fdb\u884c\u8c03\u5ea6\u7684\u3002 \u521b\u5efa\u4e00\u4e2a Pod nginx-nodename \uff0c\u5e76\u5c06\u5176\u6307\u5b9a\u5728 cka003 \u8282\u70b9\u4e0a\u3002 kubectl apply -f - < ","title":"nodeName"},{"location":"k8s/cka_cn/foundamentals/scheduling/#affinity","text":"\u5728 Kubernetes \u96c6\u7fa4\u4e2d\uff0c\u6709\u4e9b Pod \u9700\u8981\u9891\u7e41\u4e0e\u5176\u4ed6 Pod \u8fdb\u884c\u4ea4\u4e92\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5efa\u8bae\u5c06\u8fd9\u4e9b Pod \u8c03\u5ea6\u5230\u540c\u4e00\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u3002\u4f8b\u5982\uff0c\u4e24\u4e2a Pod\uff1a Nginx \u548c Mysql \uff0c\u5982\u679c\u5b83\u4eec\u9891\u7e41\u901a\u4fe1\uff0c\u5219\u9700\u8981\u5728\u540c\u4e00\u4e2a\u8282\u70b9\u4e0a\u90e8\u7f72\u5b83\u4eec\u3002 \u57fa\u4e8epod\u4e4b\u95f4\u7684\u5173\u7cfb\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528 podAffinity \u8fdb\u884c\u9009\u62e9\u3002 podAffinity \u6709\u4e24\u79cd\u8c03\u5ea6\u7c7b\u578b\uff1a requiredDuringSchedulingIgnoredDuringExecution \uff08\u786c\u4eb2\u548c\uff09 preferredDuringSchedulingIgnoredDuringExecution \uff08\u8f6f\u4eb2\u548c\uff09 \u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u7c7b\u578b\u8bbe\u7f6e topologyKey \uff1a kubernetes.io/hostname \uff03NodeName failure-domain.beta.kubernetes.io/zone \uff03\u533a\u57df Zone failure-domain.beta.kubernetes.io/region # \u533a\u57df Zone \u6211\u4eec\u53ef\u4ee5\u8bbe\u7f6e\u8282\u70b9\u6807\u7b7e\u6765\u5bf9\u8282\u70b9\u7684\u540d\u79f0/\u533a\u57df\u8fdb\u884c\u5206\u7c7b\uff0c\u8fd9\u6837\u5c31\u53ef\u4ee5\u88ab podAffinity \u6240\u4f7f\u7528\u3002 \u521b\u5efapod Nginx \u3002 kubectl apply -f - < 80/TCP 14s app=httpd NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/httpd-app-6496d888c9-4nb6z 1/1 Running 0 77s 10.244.102.21 cka003 pod/httpd-app-6496d888c9-b7xht 1/1 Running 0 77s 10.244.112.19 cka002 \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u9a8c\u8bc1\u5bf9pod\u7684IP\u5730\u5740\u7684\u8bbf\u95ee\u3002 curl 10 .244.102.21 curl 10 .244.112.19 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002

    It works!

    \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u9a8c\u8bc1\u901a\u8fc7\u7aef\u53e3\u5bf9ClusterIP\u7684\u8bbf\u95ee\u3002 curl 11 .244.247.7:80 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002

    It works!

    \u66b4\u9732Service \u00b6 \u521b\u5efa\u4e00\u4e2a\u4e34\u65f6\u7684Pod nslookup \uff0c\u5e76\u9644\u52a0\u5230\u5b83\u4ee5\u9a8c\u8bc1DNS\u89e3\u6790\u3002\u9009\u9879 --rm \u8868\u793a\u5728\u9000\u51fa\u540e\u5220\u9664\u8be5Pod\u3002 kubectl run -it nslookup --rm --image = busybox:1.28 \u8fde\u63a5\u5230\u8fd9\u4e2aPod\u540e\uff0c\u8fd0\u884c\u547d\u4ee4 nslookup httpd-app \u3002\u6211\u4eec\u4f1a\u6536\u5230 httpd-app \u670d\u52a1\u7684 ClusterIP \u548c\u5b8c\u6574\u7684\u57df\u540d\u3002 / # nslookup httpd-app Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: httpd-app Address 1: 11.244.247.7 httpd-app.dev.svc.cluster.local \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u6267\u884c\u547d\u4ee4 kubectl get pod -o wide \u6765\u5728\u65b0\u7684\u7ec8\u7aef\u4e2d\u68c0\u67e5\u4e34\u65f6 Pod nslookup \u7684 IP \u5730\u5740\u3002Pod nslookup \u7684 IP \u5730\u5740\u4e3a 10.244.112.20 \u3002 kubectl get pod nslookup \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nslookup 1/1 Running 0 2m44s 10.244.112.20 cka002 NodePort \u00b6 \u521b\u5efa\u5e76\u5e94\u7528\u6587\u4ef6 svc-nodeport.yaml \u6765\u521b\u5efaService httpd-app \u3002 kubectl apply -f - < will update configuration to existing resources. Here the Service httpd-app is changed from ClusterIP to NodePort type. No change to the Deployment httpd-app . \u6211\u4eec\u5c06\u6536\u5230\u4ee5\u4e0b\u8f93\u51fa\u3002 \u5176\u4e2d\uff0c\u547d\u4ee4 kubectl apply -f \u5c06\u66f4\u65b0\u73b0\u6709\u8d44\u6e90\u7684\u914d\u7f6e\u3002 \u5728\u8fd9\u91cc\uff0cService httpd-app \u4ece ClusterIP \u7c7b\u578b\u66f4\u6539\u4e3a NodePort \u7c7b\u578b\u3002 \u5bf9Deployment httpd-app \u6ca1\u6709\u4efb\u4f55\u66f4\u6539\u3002 service/httpd-app configured deployment.apps/httpd-app unchanged \u901a\u8fc7\u547d\u4ee4 kubectl get svc \u6765\u68c0\u67e5Service httpd-app \uff0c\u5176\u4e2d\uff1a Service\u7684IP\u5730\u5740\u4e0d\u53d8\u3002 Service\u7684\u7c7b\u578b\u53d8\u4e3a NodePort \u3002 Service\u7684\u7aef\u53e3\u53f7\u4ece 80/TCP \u53d8\u4e3a 80:30080/TCP \u3002 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpd-app NodePort 11.244.247.7 80:30080/TCP 18m \u5728\u6bcf\u4e2a\u8282\u70b9node\u4e0a\u6267\u884c\u547d\u4ee4 curl :30080 \uff0c\u6d4b\u8bd5\u5bf9Service httpd-app \u7684\u8054\u901a\u6027\u3002 curl :30080 curl :30080 curl :30080 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002

    It works!

    Headless Service \u00b6 \u521b\u5efaHeadless Service web \u548cStatefulSet web . kubectl apply -f - < web-1 1/1 Running 0 6s 10.244.112.21 cka002 \u6267\u884c\u547d\u4ee4 kubectl describe svc -l app=web \uff0c\u68c0\u67e5\u521b\u5efa\u7684Service\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 Name : web Namespace : dev Labels : app=web Annotations : Selector : app=web Type : ClusterIP IP Family Policy : SingleStack IP Families : IPv4 IP : None IPs : None Port : web 80/TCP TargetPort : 80/TCP Endpoints : 10.244.102.22:80,10.244.112.21:80 Session Affinity : None Events : \u8fde\u63a5\u5230\u4e34\u65f6Pod nslookup \uff0c\u901a\u8fc7 nslookup \u6765\u9a8c\u8bc1DNS\u5230\u89e3\u6790\u3002 kubectl run -it nslookup --rm --image = busybox:1.28 \u901a\u8fc7 nslookup \u547d\u4ee4\u8bbf\u95eeHeadless Service web \uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u52302\u4e2apod\u7684IP\u5730\u5740\uff0c\u6ce8\u610f\u4e0d\u662f\u96c6\u7fa4IP\u5730\u5740ClusterIP\uff08\u56e0\u4e3a\u662fHeadless Service\uff09\u3002 / # nslookup web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local Address 2: 10.244.102.22 web-0.web.dev.svc.cluster.local \u6211\u4eec\u4e5f\u53ef\u4ee5\u4f7f\u7528 nslookup \u547d\u4ee4\u6765\u67e5\u627e web-0.web \u548c web-1.web \u3002Headless Service\u7684\u6bcf\u4e2a Pod \u90fd\u6709\u81ea\u5df1\u7684\u670d\u52a1\u540d\u79f0\u7528\u4e8e DNS \u67e5\u627e\u3002 / # nslookup web-0.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.web Address 1: 10.244.102.22 web-0.web.dev.svc.cluster.local / # nslookup web-1.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local \u5220\u9664\u4e0a\u9762\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete sts web kubectl delete service httpd-app web kubectl delete deployment httpd-app \u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7b56\u7565 \u00b6 Service Internal Traffic Policy\uff08\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7b56\u7565\uff09\u662fKubernetes\u4e2d\u4e00\u79cd\u7528\u4e8e\u63a7\u5236\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7684\u7b56\u7565\u3002\u5b83\u7684\u4e3b\u8981\u76ee\u7684\u662f\u63a7\u5236Service\u5bf9\u8c61\u4e2dPod\u7684\u8bbf\u95ee\u7b56\u7565\u3002 \u5728Kubernetes\u4e2d\uff0cService\u5bf9\u8c61\u5c06\u4e00\u4e2a\u865a\u62dfIP\u5730\u5740\u7ed1\u5b9a\u5230\u4e00\u7ec4Pod\u4e0a\uff0c\u4ee5\u4fbf\u53ef\u4ee5\u901a\u8fc7\u8fd9\u4e2a\u865a\u62dfIP\u5730\u5740\u6765\u8bbf\u95ee\u8fd9\u7ec4Pod\u3002Service\u5bf9\u8c61\u5728\u67d0\u79cd\u7a0b\u5ea6\u4e0a\u50cf\u8d1f\u8f7d\u5747\u8861\u5668\uff0c\u53ef\u4ee5\u5c06\u8bf7\u6c42\u6d41\u91cf\u8def\u7531\u5230\u5176\u4e0b\u9762\u7684Pod\u3002 Service\u5bf9\u8c61\u901a\u5e38\u4f1a\u4f7f\u7528\u4ee5\u4e0b\u4e24\u79cd\u7c7b\u578b\u4e4b\u4e00\u6765\u8def\u7531\u6d41\u91cf\uff1a ClusterIP\uff1a\u6b64\u7c7b\u578b\u7684Service\u53ea\u80fd\u4ece\u540c\u4e00Kubernetes\u96c6\u7fa4\u5185\u7684\u5176\u4ed6Pod\u8bbf\u95ee\uff0c\u56e0\u4e3a\u5b83\u662f\u5728Kubernetes\u96c6\u7fa4\u5185\u90e8\u8def\u7531\u8bf7\u6c42\u6d41\u91cf\u7684\u3002 NodePort\uff1a\u6b64\u7c7b\u578b\u7684Service\u5728\u6240\u6709\u8282\u70b9\u4e0a\u516c\u5f00\u4e86\u4e00\u4e2a\u9759\u6001\u7aef\u53e3\uff0c\u4ece\u800c\u53ef\u4ee5\u4ece\u96c6\u7fa4\u5916\u90e8\u8bbf\u95ee\u5b83\u3002\u4f46\u662f\uff0c\u5b83\u4ecd\u7136\u53ef\u4ee5\u4ece\u96c6\u7fa4\u5185\u90e8\u8bbf\u95ee\u3002 Service Internal Traffic Policy\u5b9a\u4e49\u4e86Pod\u5982\u4f55\u8bbf\u95ee\u540c\u4e00\u4e2aService\u4e2d\u7684\u5176\u4ed6Pod\u3002\u53ef\u4ee5\u5c06\u5176\u8bbe\u7f6e\u4e3a\u4ee5\u4e0b\u4e09\u4e2a\u9009\u9879\u4e4b\u4e00\uff1a Cluster\uff1a\u8fd9\u662f\u9ed8\u8ba4\u8bbe\u7f6e\uff0c\u5b83\u5141\u8bb8Service\u4e2d\u7684\u4efb\u4f55Pod\u90fd\u53ef\u4ee5\u8bbf\u95ee\u53e6\u4e00\u4e2aPod\u3002 Local\uff1a\u6b64\u9009\u9879\u5141\u8bb8Pod\u4ec5\u8bbf\u95ee\u5728\u540c\u4e00\u8282\u70b9\u4e0a\u8fd0\u884c\u7684\u5176\u4ed6Pod\u3002\u5982\u679cPod\u9700\u8981\u5feb\u901f\u7684\u3001\u4f4e\u5ef6\u8fdf\u7684\u7f51\u7edc\u8bbf\u95ee\uff0c\u53ef\u4ee5\u4f7f\u7528\u6b64\u9009\u9879\u3002 Disabled\uff1a\u6b64\u9009\u9879\u5c06\u5b8c\u5168\u7981\u6b62Service\u5185\u90e8\u7684\u6d41\u91cf\u3002\u5b83\u9002\u7528\u4e8e\u7279\u5b9a\u7684\u73af\u5883\u548c\u90e8\u7f72\u4e2d\u3002 \u6f14\u793a\u573a\u666f\uff1a \u6a21\u62df Service \u5185\u90e8\u6d41\u91cf\u7b56\u7565\u7684\u5de5\u4f5c\u65b9\u5f0f\u3002 \u9884\u671f\u7ed3\u679c\uff1a \u901a\u8fc7\u8bbe\u7f6e Service \u7684 internalTrafficPolicy: Local \uff0cService \u53ea\u4f1a\u5c06\u6d41\u91cf\u8def\u7531\u5230 Pod \u6240\u5728\u7684\u8282\u70b9\u5185\u90e8\u3002 \u6f14\u793a\u76ee\u7684\uff1a Service Internal Traffic Policy\uff08\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7b56\u7565\uff09\u53ef\u4ee5\u9650\u5236\u5185\u90e8\u6d41\u91cf\u4ec5\u8def\u7531\u5230\u540c\u4e00\u8282\u70b9\u4e2d\u7684\u7ec8\u7aef\u8282\u70b9\u3002 \u8fd9\u91cc\u7684\u201c\u5185\u90e8\u201d\u6d41\u91cf\u662f\u6307\u6e90\u81ea\u5f53\u524d\u96c6\u7fa4\u4e2d\u7684Pod\u7684\u6d41\u91cf\u3002 \u901a\u8fc7\u5c06\u5176 .spec.internalTrafficPolicy \u8bbe\u7f6e\u4e3a Local\uff0c\u53ef\u4ee5\u544a\u8bc9 kube-proxy \u4ec5\u5bf9\u96c6\u7fa4\u5185\u90e8\u6d41\u91cf\u4f7f\u7528\u672c\u5730\u8282\u70b9\u7684\u7ec8\u7aef\u8282\u70b9\u3002 \u5bf9\u4e8e\u4f4d\u4e8e\u6ca1\u6709\u7ed9\u5b9a\u670d\u52a1\u7684\u7ec8\u7aef\u8282\u70b9\u7684\u8282\u70b9\u4e0a\u7684Pod\uff0c\u5373\u4f7f\u670d\u52a1\u5728\u5176\u4ed6\u8282\u70b9\u4e0a\u6709\u7ec8\u7aef\u8282\u70b9\uff0c\u8be5\u670d\u52a1\u4e5f\u4f1a\u88ab\u89c6\u4e3a\u5728\u8be5\u8282\u70b9\u4e0a\u6ca1\u6709\u7ec8\u7aef\u8282\u70b9\uff08\u5bf9\u4e8e\u8be5\u8282\u70b9\u4e0a\u7684Pod\uff09\u3002 \u6f14\u793a\uff1a \u521b\u5efa Deployment my-nginx \u548c Service my-nginx . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx EOF \u4f7f\u7528\u547d\u4ee4 kubectl get pod -o wide \uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u77e5 Deployment my-nginx \u7684 Pod \u6b63\u5728\u8fd0\u884c\u5728 cka003 \u8282\u70b9\u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cf54cdbf7-bscf8 1/1 Running 0 9h 10.244.112.63 cka002 \u8ba9\u6211\u4eec\u4ece cka001 \u53d1\u9001 http \u8bf7\u6c42\u5230\u8fd0\u884c\u5728 cka002 \u4e0a\u7684 Pod\u3002 \u6211\u4eec\u5c06\u6536\u5230 Welcome to nginx! \u4fe1\u606f\uff0c\u8fd9\u610f\u5473\u7740\u8be5 Pod \u53ef\u4ee5\u4ece\u5176\u4ed6\u8282\u70b9\u8bbf\u95ee\u3002 curl 11 .244.163.60 \u73b0\u5728\u6765\u4fee\u6539Service my-nginx \u5e76\u6307\u5b9a internalTrafficPolicy: Local \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx internalTrafficPolicy: Local EOF Let's send http request from cka001 to the http request to the Pod again. We will receive curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused error information. \u6211\u4eec\u518d\u6b21\u4ece cka001 \u53d1\u9001http\u8bf7\u6c42\u5230\u8be5Pod\u3002 \u6211\u4eec\u5c06\u6536\u5230\u9519\u8bef\u4fe1\u606f curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused \u3002 curl 11 .244.163.60 \u8ba9\u6211\u4eec\u767b\u5f55\u5230 cka002 \u8282\u70b9\u5e76\u518d\u6b21\u5411 Pod \u53d1\u9001 HTTP \u8bf7\u6c42\u3002 \u6211\u4eec\u5c06\u6536\u5230 Welcome to nginx! \u7684\u4fe1\u606f\u3002 curl 11 .244.163.60 \u6f14\u793a\u7ed3\u8bba\uff1a \u8bbe\u7f6e Service \u7684 internalTrafficPolicy: Local \u540e\uff0cService \u53ea\u4f1a\u5c06\u6d41\u91cf\u8def\u7531\u5230\u5f53\u524d Pod \u6240\u5728\u7684\u8282\u70b9\u5185\u90e8\u7684 Pod\u3002 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a nginx Deployment \u6dfb\u52a0 nginx Pod\u7684\u7aef\u53e3\u53f7\u548c\u522b\u540d \u4f7f\u7528\u672c\u5730\u6d41\u91cf\u5c06Deployment\u66b4\u9732\u51fa\u53bb\u3002 \u6f14\u793a\uff1a \u4f7f\u7528\u7aef\u53e3\u53f7\u4e3a 80 \u521b\u5efa my-nginx Deployment\u3002 kubectl create deployment my-nginx --image = nginx --port = 80 \u4fee\u6539Deployment\u3002 kubectl edit deployment my-nginx \u5728 my-nginx Deployment\u4e2d\u6dfb\u52a0\u7aef\u53e3\u522b\u540d http \u3002 \u8bf7\u53c2\u8003\u4ee5\u4e0b\u90e8\u7f72\u7684 YAML \u6a21\u677f\u94fe\u63a5\uff1a https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ \u3002 spec : containers : - image : nginx imagePullPolicy : Always name : nginx ports : - containerPort : 80 protocol : TCP name : http \u4f7f\u7528 NodePort \u7c7b\u578b\u66b4\u9732 deployment\u3002 kubectl expose deployment my-nginx --port = 80 --target-port = http --name = my-nginx-svc --type = NodePort \u4fee\u6539service\uff0c\u628a internalTrafficPolicy \u4ece Cluster \u6539\u4e3a Local \u3002 kubectl edit svc my-nginx-svc \u9a8c\u8bc1\u8bbf\u95ee\u3002 \u6ce8\u610f\uff0cPod \u6b63\u5728\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u4e0a\u3002\u6211\u4eec\u5c06\u770b\u5230\u4ee5\u4e0b\u9884\u671f\u7ed3\u679c\u3002 curl :80 # succeed on node cka003. internalTrafficPolicy is effective. curl :80 # succeed on all nodes. curl : # succeed on all nodes.","title":"Service"},{"location":"k8s/cka_cn/foundamentals/service/#cka10service","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb010:Service"},{"location":"k8s/cka_cn/foundamentals/service/#_1","text":"\u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u540d\u4e3a httpd-app \u7684Deployment\u3002 \u521b\u5efa\u7c7b\u578b\u4e3a ClusterIP \u7684 httpd-app \u670d\u52a1\uff0c\u9ed8\u8ba4\u7c7b\u578b\u662f ClusterIP\uff0c\u53ea\u80fd\u5185\u90e8\u8bbf\u95ee\u3002 \u9a8c\u8bc1\u5bf9Pod\u7684IP\u548c\u670d\u52a1\u7684\u96c6\u7fa4IP\u7684\u8bbf\u95ee\u3002 \u5c06 httpd-app \u670d\u52a1\u7c7b\u578b\u66f4\u65b0\u4e3a NodePort \uff0c\u4e0d\u9700\u8981\u5bf9 httpd-app \u8fd9\u4e2aDeployment\u8fdb\u884c\u4efb\u4f55\u66f4\u6539\u3002 \u9a8c\u8bc1\u8282\u70b9node\u7684\u8bbf\u95ee\u3002\u5bf9\u8282\u70b9node\u5bf9\u8bbf\u95ee\u5c06\u88ab\u8def\u7531\u5230Pod\uff0c\u4ece\u800c\u5b9e\u73b0\u4ece\u5916\u90e8\u8bbf\u95ee\u6211\u4eec\u521b\u5efa\u7684\u670d\u52a1 httpd-app \u3002 \u521b\u5efa\u65e0\u5934\u670d\u52a1\uff08Headless Service\uff09 web \u548c \u6709\u72b6\u6001\u526f\u672c\u96c6\uff08StatefulSet\uff09 web \u3002 \u670d\u52a1\u7684\u5185\u90e8\u6d41\u91cf\u7b56\u7565\u3002 NodePort \u53ef\u4ee5\u7ffb\u8bd1\u4e3a\u201c\u8282\u70b9\u7aef\u53e3\u201d\uff0c\u662f\u4e00\u79cdService\u7684\u7c7b\u578b\uff0c\u53ef\u4ee5\u901a\u8fc7\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u6253\u5f00\u4e00\u4e2a\u7aef\u53e3\uff0c\u5c06Service\u66b4\u9732\u5230\u96c6\u7fa4\u5916\u90e8\u3002 ClusterIP \u53ef\u4ee5\u7ffb\u8bd1\u4e3a\u201c\u96c6\u7fa4IP\u201d\uff0c\u4e5f\u662f\u4e00\u79cdService\u7684\u7c7b\u578b\uff0c\u4e3aService\u63d0\u4f9b\u4e86\u4e00\u4e2a\u865a\u62dfIP\u5730\u5740\uff0c\u53ef\u4ee5\u5728\u96c6\u7fa4\u5185\u90e8\u8fdb\u884c\u8bbf\u95ee\u3002\u8fd9\u4e2aIP\u5730\u5740\u901a\u5e38\u7531\u96c6\u7fa4\u4e2d\u7684Kubernetes\u4ee3\u7406\u81ea\u52a8\u5206\u914d\uff0c\u5e76\u4e14\u53ea\u80fd\u5728\u96c6\u7fa4\u5185\u90e8\u4f7f\u7528\u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/foundamentals/service/#clusterip","text":"","title":"ClusterIP"},{"location":"k8s/cka_cn/foundamentals/service/#service","text":"\u521b\u5efaDeployment http-app \u3002 \u521b\u5efaService httpd-app \u5e76\u901a\u8fc7\u6807\u7b7e\u9009\u62e9\u5668\uff08Label Selector\uff09\u5173\u8054\u5230Development http-app \u3002 Service\u7684\u7c7b\u578b\u662f ClusterIP \uff0c\u8fd9\u662fService\u7684\u9ed8\u8ba4\u7c7b\u578b\uff0c\u53ea\u9650\u4e8e\u5185\u90e8\u8bbf\u95ee\u3002 kubectl apply -f - < 80/TCP 14s app=httpd NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/httpd-app-6496d888c9-4nb6z 1/1 Running 0 77s 10.244.102.21 cka003 pod/httpd-app-6496d888c9-b7xht 1/1 Running 0 77s 10.244.112.19 cka002 \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u9a8c\u8bc1\u5bf9pod\u7684IP\u5730\u5740\u7684\u8bbf\u95ee\u3002 curl 10 .244.102.21 curl 10 .244.112.19 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002

    It works!

    \u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u9a8c\u8bc1\u901a\u8fc7\u7aef\u53e3\u5bf9ClusterIP\u7684\u8bbf\u95ee\u3002 curl 11 .244.247.7:80 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002

    It works!

    ","title":"\u521b\u5efaService"},{"location":"k8s/cka_cn/foundamentals/service/#service_1","text":"\u521b\u5efa\u4e00\u4e2a\u4e34\u65f6\u7684Pod nslookup \uff0c\u5e76\u9644\u52a0\u5230\u5b83\u4ee5\u9a8c\u8bc1DNS\u89e3\u6790\u3002\u9009\u9879 --rm \u8868\u793a\u5728\u9000\u51fa\u540e\u5220\u9664\u8be5Pod\u3002 kubectl run -it nslookup --rm --image = busybox:1.28 \u8fde\u63a5\u5230\u8fd9\u4e2aPod\u540e\uff0c\u8fd0\u884c\u547d\u4ee4 nslookup httpd-app \u3002\u6211\u4eec\u4f1a\u6536\u5230 httpd-app \u670d\u52a1\u7684 ClusterIP \u548c\u5b8c\u6574\u7684\u57df\u540d\u3002 / # nslookup httpd-app Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: httpd-app Address 1: 11.244.247.7 httpd-app.dev.svc.cluster.local \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u6267\u884c\u547d\u4ee4 kubectl get pod -o wide \u6765\u5728\u65b0\u7684\u7ec8\u7aef\u4e2d\u68c0\u67e5\u4e34\u65f6 Pod nslookup \u7684 IP \u5730\u5740\u3002Pod nslookup \u7684 IP \u5730\u5740\u4e3a 10.244.112.20 \u3002 kubectl get pod nslookup \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nslookup 1/1 Running 0 2m44s 10.244.112.20 cka002 ","title":"\u66b4\u9732Service"},{"location":"k8s/cka_cn/foundamentals/service/#nodeport","text":"\u521b\u5efa\u5e76\u5e94\u7528\u6587\u4ef6 svc-nodeport.yaml \u6765\u521b\u5efaService httpd-app \u3002 kubectl apply -f - < will update configuration to existing resources. Here the Service httpd-app is changed from ClusterIP to NodePort type. No change to the Deployment httpd-app . \u6211\u4eec\u5c06\u6536\u5230\u4ee5\u4e0b\u8f93\u51fa\u3002 \u5176\u4e2d\uff0c\u547d\u4ee4 kubectl apply -f \u5c06\u66f4\u65b0\u73b0\u6709\u8d44\u6e90\u7684\u914d\u7f6e\u3002 \u5728\u8fd9\u91cc\uff0cService httpd-app \u4ece ClusterIP \u7c7b\u578b\u66f4\u6539\u4e3a NodePort \u7c7b\u578b\u3002 \u5bf9Deployment httpd-app \u6ca1\u6709\u4efb\u4f55\u66f4\u6539\u3002 service/httpd-app configured deployment.apps/httpd-app unchanged \u901a\u8fc7\u547d\u4ee4 kubectl get svc \u6765\u68c0\u67e5Service httpd-app \uff0c\u5176\u4e2d\uff1a Service\u7684IP\u5730\u5740\u4e0d\u53d8\u3002 Service\u7684\u7c7b\u578b\u53d8\u4e3a NodePort \u3002 Service\u7684\u7aef\u53e3\u53f7\u4ece 80/TCP \u53d8\u4e3a 80:30080/TCP \u3002 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpd-app NodePort 11.244.247.7 80:30080/TCP 18m \u5728\u6bcf\u4e2a\u8282\u70b9node\u4e0a\u6267\u884c\u547d\u4ee4 curl :30080 \uff0c\u6d4b\u8bd5\u5bf9Service httpd-app \u7684\u8054\u901a\u6027\u3002 curl :30080 curl :30080 curl :30080 \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff0c\u8bf4\u660e\u8bbf\u95ee\u6210\u529f\u3002

    It works!

    ","title":"NodePort"},{"location":"k8s/cka_cn/foundamentals/service/#headless-service","text":"\u521b\u5efaHeadless Service web \u548cStatefulSet web . kubectl apply -f - < web-1 1/1 Running 0 6s 10.244.112.21 cka002 \u6267\u884c\u547d\u4ee4 kubectl describe svc -l app=web \uff0c\u68c0\u67e5\u521b\u5efa\u7684Service\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 Name : web Namespace : dev Labels : app=web Annotations : Selector : app=web Type : ClusterIP IP Family Policy : SingleStack IP Families : IPv4 IP : None IPs : None Port : web 80/TCP TargetPort : 80/TCP Endpoints : 10.244.102.22:80,10.244.112.21:80 Session Affinity : None Events : \u8fde\u63a5\u5230\u4e34\u65f6Pod nslookup \uff0c\u901a\u8fc7 nslookup \u6765\u9a8c\u8bc1DNS\u5230\u89e3\u6790\u3002 kubectl run -it nslookup --rm --image = busybox:1.28 \u901a\u8fc7 nslookup \u547d\u4ee4\u8bbf\u95eeHeadless Service web \uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u52302\u4e2apod\u7684IP\u5730\u5740\uff0c\u6ce8\u610f\u4e0d\u662f\u96c6\u7fa4IP\u5730\u5740ClusterIP\uff08\u56e0\u4e3a\u662fHeadless Service\uff09\u3002 / # nslookup web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local Address 2: 10.244.102.22 web-0.web.dev.svc.cluster.local \u6211\u4eec\u4e5f\u53ef\u4ee5\u4f7f\u7528 nslookup \u547d\u4ee4\u6765\u67e5\u627e web-0.web \u548c web-1.web \u3002Headless Service\u7684\u6bcf\u4e2a Pod \u90fd\u6709\u81ea\u5df1\u7684\u670d\u52a1\u540d\u79f0\u7528\u4e8e DNS \u67e5\u627e\u3002 / # nslookup web-0.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.web Address 1: 10.244.102.22 web-0.web.dev.svc.cluster.local / # nslookup web-1.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local \u5220\u9664\u4e0a\u9762\u521b\u5efa\u7684\u4e34\u65f6\u8d44\u6e90\u3002 kubectl delete sts web kubectl delete service httpd-app web kubectl delete deployment httpd-app","title":"Headless Service"},{"location":"k8s/cka_cn/foundamentals/service/#_2","text":"Service Internal Traffic Policy\uff08\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7b56\u7565\uff09\u662fKubernetes\u4e2d\u4e00\u79cd\u7528\u4e8e\u63a7\u5236\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7684\u7b56\u7565\u3002\u5b83\u7684\u4e3b\u8981\u76ee\u7684\u662f\u63a7\u5236Service\u5bf9\u8c61\u4e2dPod\u7684\u8bbf\u95ee\u7b56\u7565\u3002 \u5728Kubernetes\u4e2d\uff0cService\u5bf9\u8c61\u5c06\u4e00\u4e2a\u865a\u62dfIP\u5730\u5740\u7ed1\u5b9a\u5230\u4e00\u7ec4Pod\u4e0a\uff0c\u4ee5\u4fbf\u53ef\u4ee5\u901a\u8fc7\u8fd9\u4e2a\u865a\u62dfIP\u5730\u5740\u6765\u8bbf\u95ee\u8fd9\u7ec4Pod\u3002Service\u5bf9\u8c61\u5728\u67d0\u79cd\u7a0b\u5ea6\u4e0a\u50cf\u8d1f\u8f7d\u5747\u8861\u5668\uff0c\u53ef\u4ee5\u5c06\u8bf7\u6c42\u6d41\u91cf\u8def\u7531\u5230\u5176\u4e0b\u9762\u7684Pod\u3002 Service\u5bf9\u8c61\u901a\u5e38\u4f1a\u4f7f\u7528\u4ee5\u4e0b\u4e24\u79cd\u7c7b\u578b\u4e4b\u4e00\u6765\u8def\u7531\u6d41\u91cf\uff1a ClusterIP\uff1a\u6b64\u7c7b\u578b\u7684Service\u53ea\u80fd\u4ece\u540c\u4e00Kubernetes\u96c6\u7fa4\u5185\u7684\u5176\u4ed6Pod\u8bbf\u95ee\uff0c\u56e0\u4e3a\u5b83\u662f\u5728Kubernetes\u96c6\u7fa4\u5185\u90e8\u8def\u7531\u8bf7\u6c42\u6d41\u91cf\u7684\u3002 NodePort\uff1a\u6b64\u7c7b\u578b\u7684Service\u5728\u6240\u6709\u8282\u70b9\u4e0a\u516c\u5f00\u4e86\u4e00\u4e2a\u9759\u6001\u7aef\u53e3\uff0c\u4ece\u800c\u53ef\u4ee5\u4ece\u96c6\u7fa4\u5916\u90e8\u8bbf\u95ee\u5b83\u3002\u4f46\u662f\uff0c\u5b83\u4ecd\u7136\u53ef\u4ee5\u4ece\u96c6\u7fa4\u5185\u90e8\u8bbf\u95ee\u3002 Service Internal Traffic Policy\u5b9a\u4e49\u4e86Pod\u5982\u4f55\u8bbf\u95ee\u540c\u4e00\u4e2aService\u4e2d\u7684\u5176\u4ed6Pod\u3002\u53ef\u4ee5\u5c06\u5176\u8bbe\u7f6e\u4e3a\u4ee5\u4e0b\u4e09\u4e2a\u9009\u9879\u4e4b\u4e00\uff1a Cluster\uff1a\u8fd9\u662f\u9ed8\u8ba4\u8bbe\u7f6e\uff0c\u5b83\u5141\u8bb8Service\u4e2d\u7684\u4efb\u4f55Pod\u90fd\u53ef\u4ee5\u8bbf\u95ee\u53e6\u4e00\u4e2aPod\u3002 Local\uff1a\u6b64\u9009\u9879\u5141\u8bb8Pod\u4ec5\u8bbf\u95ee\u5728\u540c\u4e00\u8282\u70b9\u4e0a\u8fd0\u884c\u7684\u5176\u4ed6Pod\u3002\u5982\u679cPod\u9700\u8981\u5feb\u901f\u7684\u3001\u4f4e\u5ef6\u8fdf\u7684\u7f51\u7edc\u8bbf\u95ee\uff0c\u53ef\u4ee5\u4f7f\u7528\u6b64\u9009\u9879\u3002 Disabled\uff1a\u6b64\u9009\u9879\u5c06\u5b8c\u5168\u7981\u6b62Service\u5185\u90e8\u7684\u6d41\u91cf\u3002\u5b83\u9002\u7528\u4e8e\u7279\u5b9a\u7684\u73af\u5883\u548c\u90e8\u7f72\u4e2d\u3002 \u6f14\u793a\u573a\u666f\uff1a \u6a21\u62df Service \u5185\u90e8\u6d41\u91cf\u7b56\u7565\u7684\u5de5\u4f5c\u65b9\u5f0f\u3002 \u9884\u671f\u7ed3\u679c\uff1a \u901a\u8fc7\u8bbe\u7f6e Service \u7684 internalTrafficPolicy: Local \uff0cService \u53ea\u4f1a\u5c06\u6d41\u91cf\u8def\u7531\u5230 Pod \u6240\u5728\u7684\u8282\u70b9\u5185\u90e8\u3002 \u6f14\u793a\u76ee\u7684\uff1a Service Internal Traffic Policy\uff08\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7b56\u7565\uff09\u53ef\u4ee5\u9650\u5236\u5185\u90e8\u6d41\u91cf\u4ec5\u8def\u7531\u5230\u540c\u4e00\u8282\u70b9\u4e2d\u7684\u7ec8\u7aef\u8282\u70b9\u3002 \u8fd9\u91cc\u7684\u201c\u5185\u90e8\u201d\u6d41\u91cf\u662f\u6307\u6e90\u81ea\u5f53\u524d\u96c6\u7fa4\u4e2d\u7684Pod\u7684\u6d41\u91cf\u3002 \u901a\u8fc7\u5c06\u5176 .spec.internalTrafficPolicy \u8bbe\u7f6e\u4e3a Local\uff0c\u53ef\u4ee5\u544a\u8bc9 kube-proxy \u4ec5\u5bf9\u96c6\u7fa4\u5185\u90e8\u6d41\u91cf\u4f7f\u7528\u672c\u5730\u8282\u70b9\u7684\u7ec8\u7aef\u8282\u70b9\u3002 \u5bf9\u4e8e\u4f4d\u4e8e\u6ca1\u6709\u7ed9\u5b9a\u670d\u52a1\u7684\u7ec8\u7aef\u8282\u70b9\u7684\u8282\u70b9\u4e0a\u7684Pod\uff0c\u5373\u4f7f\u670d\u52a1\u5728\u5176\u4ed6\u8282\u70b9\u4e0a\u6709\u7ec8\u7aef\u8282\u70b9\uff0c\u8be5\u670d\u52a1\u4e5f\u4f1a\u88ab\u89c6\u4e3a\u5728\u8be5\u8282\u70b9\u4e0a\u6ca1\u6709\u7ec8\u7aef\u8282\u70b9\uff08\u5bf9\u4e8e\u8be5\u8282\u70b9\u4e0a\u7684Pod\uff09\u3002 \u6f14\u793a\uff1a \u521b\u5efa Deployment my-nginx \u548c Service my-nginx . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx EOF \u4f7f\u7528\u547d\u4ee4 kubectl get pod -o wide \uff0c\u6211\u4eec\u53ef\u4ee5\u5f97\u77e5 Deployment my-nginx \u7684 Pod \u6b63\u5728\u8fd0\u884c\u5728 cka003 \u8282\u70b9\u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cf54cdbf7-bscf8 1/1 Running 0 9h 10.244.112.63 cka002 \u8ba9\u6211\u4eec\u4ece cka001 \u53d1\u9001 http \u8bf7\u6c42\u5230\u8fd0\u884c\u5728 cka002 \u4e0a\u7684 Pod\u3002 \u6211\u4eec\u5c06\u6536\u5230 Welcome to nginx! \u4fe1\u606f\uff0c\u8fd9\u610f\u5473\u7740\u8be5 Pod \u53ef\u4ee5\u4ece\u5176\u4ed6\u8282\u70b9\u8bbf\u95ee\u3002 curl 11 .244.163.60 \u73b0\u5728\u6765\u4fee\u6539Service my-nginx \u5e76\u6307\u5b9a internalTrafficPolicy: Local \u3002 kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx internalTrafficPolicy: Local EOF Let's send http request from cka001 to the http request to the Pod again. We will receive curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused error information. \u6211\u4eec\u518d\u6b21\u4ece cka001 \u53d1\u9001http\u8bf7\u6c42\u5230\u8be5Pod\u3002 \u6211\u4eec\u5c06\u6536\u5230\u9519\u8bef\u4fe1\u606f curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused \u3002 curl 11 .244.163.60 \u8ba9\u6211\u4eec\u767b\u5f55\u5230 cka002 \u8282\u70b9\u5e76\u518d\u6b21\u5411 Pod \u53d1\u9001 HTTP \u8bf7\u6c42\u3002 \u6211\u4eec\u5c06\u6536\u5230 Welcome to nginx! \u7684\u4fe1\u606f\u3002 curl 11 .244.163.60 \u6f14\u793a\u7ed3\u8bba\uff1a \u8bbe\u7f6e Service \u7684 internalTrafficPolicy: Local \u540e\uff0cService \u53ea\u4f1a\u5c06\u6d41\u91cf\u8def\u7531\u5230\u5f53\u524d Pod \u6240\u5728\u7684\u8282\u70b9\u5185\u90e8\u7684 Pod\u3002 \u6f14\u793a\u573a\u666f\uff1a \u521b\u5efa\u4e00\u4e2a nginx Deployment \u6dfb\u52a0 nginx Pod\u7684\u7aef\u53e3\u53f7\u548c\u522b\u540d \u4f7f\u7528\u672c\u5730\u6d41\u91cf\u5c06Deployment\u66b4\u9732\u51fa\u53bb\u3002 \u6f14\u793a\uff1a \u4f7f\u7528\u7aef\u53e3\u53f7\u4e3a 80 \u521b\u5efa my-nginx Deployment\u3002 kubectl create deployment my-nginx --image = nginx --port = 80 \u4fee\u6539Deployment\u3002 kubectl edit deployment my-nginx \u5728 my-nginx Deployment\u4e2d\u6dfb\u52a0\u7aef\u53e3\u522b\u540d http \u3002 \u8bf7\u53c2\u8003\u4ee5\u4e0b\u90e8\u7f72\u7684 YAML \u6a21\u677f\u94fe\u63a5\uff1a https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ \u3002 spec : containers : - image : nginx imagePullPolicy : Always name : nginx ports : - containerPort : 80 protocol : TCP name : http \u4f7f\u7528 NodePort \u7c7b\u578b\u66b4\u9732 deployment\u3002 kubectl expose deployment my-nginx --port = 80 --target-port = http --name = my-nginx-svc --type = NodePort \u4fee\u6539service\uff0c\u628a internalTrafficPolicy \u4ece Cluster \u6539\u4e3a Local \u3002 kubectl edit svc my-nginx-svc \u9a8c\u8bc1\u8bbf\u95ee\u3002 \u6ce8\u610f\uff0cPod \u6b63\u5728\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u4e0a\u3002\u6211\u4eec\u5c06\u770b\u5230\u4ee5\u4e0b\u9884\u671f\u7ed3\u679c\u3002 curl :80 # succeed on node cka003. internalTrafficPolicy is effective. curl :80 # succeed on all nodes. curl : # succeed on all nodes.","title":"\u670d\u52a1\u5185\u90e8\u6d41\u91cf\u7b56\u7565"},{"location":"k8s/cka_cn/foundamentals/statefulset/","text":"CKA\u81ea\u5b66\u7b14\u8bb012:StatefulSet \u00b6 \u6f14\u793a\u573a\u666f \u00b6 \u521b\u5efa\u4e00\u4e2a Headless Service nginx \u548c\u4e00\u4e2aStatefulSet web \u6269\u5c55 StatefulSet web \u6f14\u793a \u00b6 \u521b\u5efa\u4e00\u4e2a Headless Service nginx \u548c\u4e00\u4e2aStatefulSet web kubectl apply -f - << EOF --- apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: \"nginx\" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web EOF \u8bfb\u53d6\u4e0a\u4e00\u6b65\u521b\u5efa\u7684StatefulSet Pod \u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get pod | grep web \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE web-0 1 /1 Running 0 27s web-1 1 /1 Running 0 10s \u4f7f\u7528\u547d\u4ee4 kubectl edit sts web \u66f4\u65b0\u73b0\u6709\u7684 StatefulSet\u3002 \u53ea\u6709\u4ee5\u4e0b\u5b57\u6bb5\u53ef\u4ee5\u66f4\u65b0\uff1a replicas \u3001 image \u3001 rolling updates \u3001 labels \u3001 resource request/limit \u548c annotations \u3002 \u6ce8\u610f\uff1a\u5f53 StatefulSet Pod \u5728\u5f53\u524d\u8282\u70b9\u4e2d\u6b7b\u4ea1\u65f6\uff0c\u4e0d\u4f1a\u81ea\u52a8\u5728\u5176\u4ed6\u8282\u70b9\u4e2d\u521b\u5efa\u526f\u672c\u3002 \u6269\u5c55 StatefulSet\u3002 \u5c06 StatefulSet web \u7684\u526f\u672c\u6570\u6269\u5c55\u5230 5 \u3002 kubectl scale sts web --replicas = 5 \u53c2\u8003\uff1a Partition\u8868\u793a\u5728\u66f4\u65b0\u671f\u95f4\u5e94\u5c06 StatefulSet \u5212\u5206\u4e3a\u54ea\u4e2a\u5e8f\u53f7\u3002 \u5728\u6eda\u52a8\u66f4\u65b0\u671f\u95f4\uff0c\u4ece\u5e8f\u53f7 Replicas-1 \u5230 Partition \u7684\u6240\u6709 Pod \u90fd\u4f1a\u66f4\u65b0\u3002 \u4ece\u5e8f\u53f7 Partition-1 \u5230 0 \u7684\u6240\u6709 Pod \u90fd\u4fdd\u6301\u4e0d\u53d8\u3002\u8fd9\u5bf9\u4e8e\u8fdb\u884c\u91d1\u4e1d\u96c0\u90e8\u7f72\u975e\u5e38\u6709\u7528\u3002\u9ed8\u8ba4\u503c\u4e3a0\u3002 \u547d\u4ee4\uff1a kubectl explain statefulsets.spec.updateStrategy.rollingUpdate.partition \u91d1\u4e1d\u96c0\u90e8\u7f72\u662f\u4e00\u79cd\u8f6f\u4ef6\u90e8\u7f72\u6280\u672f\uff0c\u5176\u4e2d\u5728\u5c06\u65b0\u529f\u80fd\u6216\u7248\u672c\u53d1\u5e03\u7ed9\u66f4\u5927\u7684\u7528\u6237\u5b50\u96c6\u6216\u6240\u6709\u7528\u6237\u4e4b\u524d\uff0c\u5148\u5c06\u5176\u53d1\u5e03\u7ed9\u751f\u4ea7\u4e2d\u7684\u4e00\u5c0f\u90e8\u5206\u7528\u6237\u3002 \u8fd9\u79cd\u6280\u672f\u662f\u4f4e\u98ce\u9669\u7684\uff0c\u56e0\u4e3a\u65b0\u529f\u80fd\u6700\u521d\u53ea\u90e8\u7f72\u7ed9\u5c11\u91cf\u7528\u6237\u3002 \"Canary\"\u4e00\u8bcd\u6e90\u81ea\u65e7\u7684\u7164\u77ff\u6280\u672f\uff0c\u5f53\u65f6\u91d1\u4e1d\u96c0\u88ab\u7528\u4f5c\u7a7a\u6c14\u4e2d\u6bd2\u7d20\u7684\u65e9\u671f\u63a2\u6d4b\u5668\u3002 \u5728\u91d1\u4e1d\u96c0\u90e8\u7f72\u4e2d\uff0c\u76ee\u6807\u73af\u5883\u4e2d\u7684\u6240\u6709\u57fa\u7840\u8bbe\u65bd\u90fd\u4f1a\u4ee5\u5c0f\u9636\u6bb5\u8fdb\u884c\u66f4\u65b0\u3002 \u5b83\u7528\u4e8e\u6d4b\u8bd5\u65b0\u529f\u80fd\u548c\u5347\u7ea7\u4ee5\u67e5\u770b\u5b83\u4eec\u5982\u4f55\u5904\u7406\u751f\u4ea7\u73af\u5883\u3002 \u5220\u9664\u6240\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete sts web kubectl delete service nginx","title":"StatefulSet"},{"location":"k8s/cka_cn/foundamentals/statefulset/#cka12statefulset","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb012:StatefulSet"},{"location":"k8s/cka_cn/foundamentals/statefulset/#_1","text":"\u521b\u5efa\u4e00\u4e2a Headless Service nginx \u548c\u4e00\u4e2aStatefulSet web \u6269\u5c55 StatefulSet web","title":"\u6f14\u793a\u573a\u666f"},{"location":"k8s/cka_cn/foundamentals/statefulset/#_2","text":"\u521b\u5efa\u4e00\u4e2a Headless Service nginx \u548c\u4e00\u4e2aStatefulSet web kubectl apply -f - << EOF --- apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: \"nginx\" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web EOF \u8bfb\u53d6\u4e0a\u4e00\u6b65\u521b\u5efa\u7684StatefulSet Pod \u7684\u8be6\u7ec6\u4fe1\u606f\u3002 kubectl get pod | grep web \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE web-0 1 /1 Running 0 27s web-1 1 /1 Running 0 10s \u4f7f\u7528\u547d\u4ee4 kubectl edit sts web \u66f4\u65b0\u73b0\u6709\u7684 StatefulSet\u3002 \u53ea\u6709\u4ee5\u4e0b\u5b57\u6bb5\u53ef\u4ee5\u66f4\u65b0\uff1a replicas \u3001 image \u3001 rolling updates \u3001 labels \u3001 resource request/limit \u548c annotations \u3002 \u6ce8\u610f\uff1a\u5f53 StatefulSet Pod \u5728\u5f53\u524d\u8282\u70b9\u4e2d\u6b7b\u4ea1\u65f6\uff0c\u4e0d\u4f1a\u81ea\u52a8\u5728\u5176\u4ed6\u8282\u70b9\u4e2d\u521b\u5efa\u526f\u672c\u3002 \u6269\u5c55 StatefulSet\u3002 \u5c06 StatefulSet web \u7684\u526f\u672c\u6570\u6269\u5c55\u5230 5 \u3002 kubectl scale sts web --replicas = 5 \u53c2\u8003\uff1a Partition\u8868\u793a\u5728\u66f4\u65b0\u671f\u95f4\u5e94\u5c06 StatefulSet \u5212\u5206\u4e3a\u54ea\u4e2a\u5e8f\u53f7\u3002 \u5728\u6eda\u52a8\u66f4\u65b0\u671f\u95f4\uff0c\u4ece\u5e8f\u53f7 Replicas-1 \u5230 Partition \u7684\u6240\u6709 Pod \u90fd\u4f1a\u66f4\u65b0\u3002 \u4ece\u5e8f\u53f7 Partition-1 \u5230 0 \u7684\u6240\u6709 Pod \u90fd\u4fdd\u6301\u4e0d\u53d8\u3002\u8fd9\u5bf9\u4e8e\u8fdb\u884c\u91d1\u4e1d\u96c0\u90e8\u7f72\u975e\u5e38\u6709\u7528\u3002\u9ed8\u8ba4\u503c\u4e3a0\u3002 \u547d\u4ee4\uff1a kubectl explain statefulsets.spec.updateStrategy.rollingUpdate.partition \u91d1\u4e1d\u96c0\u90e8\u7f72\u662f\u4e00\u79cd\u8f6f\u4ef6\u90e8\u7f72\u6280\u672f\uff0c\u5176\u4e2d\u5728\u5c06\u65b0\u529f\u80fd\u6216\u7248\u672c\u53d1\u5e03\u7ed9\u66f4\u5927\u7684\u7528\u6237\u5b50\u96c6\u6216\u6240\u6709\u7528\u6237\u4e4b\u524d\uff0c\u5148\u5c06\u5176\u53d1\u5e03\u7ed9\u751f\u4ea7\u4e2d\u7684\u4e00\u5c0f\u90e8\u5206\u7528\u6237\u3002 \u8fd9\u79cd\u6280\u672f\u662f\u4f4e\u98ce\u9669\u7684\uff0c\u56e0\u4e3a\u65b0\u529f\u80fd\u6700\u521d\u53ea\u90e8\u7f72\u7ed9\u5c11\u91cf\u7528\u6237\u3002 \"Canary\"\u4e00\u8bcd\u6e90\u81ea\u65e7\u7684\u7164\u77ff\u6280\u672f\uff0c\u5f53\u65f6\u91d1\u4e1d\u96c0\u88ab\u7528\u4f5c\u7a7a\u6c14\u4e2d\u6bd2\u7d20\u7684\u65e9\u671f\u63a2\u6d4b\u5668\u3002 \u5728\u91d1\u4e1d\u96c0\u90e8\u7f72\u4e2d\uff0c\u76ee\u6807\u73af\u5883\u4e2d\u7684\u6240\u6709\u57fa\u7840\u8bbe\u65bd\u90fd\u4f1a\u4ee5\u5c0f\u9636\u6bb5\u8fdb\u884c\u66f4\u65b0\u3002 \u5b83\u7528\u4e8e\u6d4b\u8bd5\u65b0\u529f\u80fd\u548c\u5347\u7ea7\u4ee5\u67e5\u770b\u5b83\u4eec\u5982\u4f55\u5904\u7406\u751f\u4ea7\u73af\u5883\u3002 \u5220\u9664\u6240\u521b\u5efa\u7684\u8d44\u6e90\u3002 kubectl delete sts web kubectl delete service nginx","title":"\u6f14\u793a"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/","text":"CKA\u81ea\u5b66\u7b14\u8bb025:Troubleshooting \u00b6 \u4e8b\u4ef6 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u63cf\u8ff0pod\u4ee5\u83b7\u53d6\u4e8b\u4ef6\u4fe1\u606f\u3002 \u6f14\u793a\uff1a \u547d\u4ee4\u7528\u6cd5\uff1a kubectl describe --namespace = \u67e5\u8be2pod\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 \u521b\u5efa\u4e00\u4e2aTomcat\u7684pod\u3002 kubectl run tomcat --image = tomcat \u67e5\u8be2pod\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl describe pod/tomcat \u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 55s default-scheduler Successfully assigned dev/tomcat to cka002 Normal Pulling 54s kubelet Pulling image \"tomcat\" Normal Pulled 21s kubelet Successfully pulled image \"tomcat\" in 33.134162692s Normal Created 19s kubelet Created container tomcat Normal Started 19s kubelet Started container tomcat \u67e5\u8be2namespace\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl get events -n \u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u9ed8\u8ba4namespace\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 LAST SEEN TYPE REASON OBJECT MESSAGE 70s Warning FailedGetScale horizontalpodautoscaler/nginx deployments/scale.apps \"podinfo\" not found 2m16s Normal Scheduled pod/tomcat Successfully assigned dev/tomcat to cka002 2m15s Normal Pulling pod/tomcat Pulling image \"tomcat\" 102s Normal Pulled pod/tomcat Successfully pulled image \"tomcat\" in 33.134162692s 100s Normal Created pod/tomcat Created container tomcat 100s Normal Started pod/tomcat Started container tomcat \u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u6240\u6709\u7684namespace\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl get events -A \u65e5\u5fd7 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u67e5\u8be2pod\u7684\u65e5\u5fd7 \u547d\u4ee4\u7528\u6cd5\uff1a kubectl logs -n \u9009\u9879\uff1a --tail : \u663e\u793a\u8f93\u51fa\u7684\u6700\u8fd1 \u884c\u3002 -f \uff1a\u5b9e\u65f6\u6d41\u5f0f\u663e\u793a\u8f93\u51fa\u3002 \u663e\u793a\u8f93\u51fa\u7684\u6700\u8fd1100\u884c\u8f93\u51fa\u3002 kubectl logs -f tomcat --tail 100 \u5982\u679c\u662f\u4e00\u4e2a\u591a\u5bb9\u5668pod\uff0c\u5219\u4f7f\u7528\u9009\u9879 -c \u6765\u6307\u5b9a\u67d0\u4e2a\u7279\u5b9a\u7684\u5bb9\u5668\u3002 kubectl logs -f tomcat --tail 100 -c tomcat \u8282\u70b9\u53ef\u7528\u6027 \u00b6 \u67e5\u770b\u53ef\u7528\u8282\u70b9 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u67e5\u770b\u8282\u70b9\u53ef\u7528\u6027 \u6f14\u793a\uff1a \u65b9\u5f0f1\uff1a kubectl describe node | grep -i taint \u624b\u5de5\u65b9\u5f0f\u68c0\u67e5\u65e5\u5fd7\uff0c\u4e0b\u9762\u7684\u4f8b\u5b50\u8bf4\u660e2\u4e2a\u8282\u70b9\u5904\u4e8e\u4e0d\u53ef\u7528\u72b6\u6001\u3002 Taints : node-role.kubernetes.io/control-plane:NoSchedule Taints : Taints : \u65b9\u5f0f2\uff1a kubectl describe node | grep -i taint | grep -vc NoSchedule \u8fd9\u91cc\u6211\u4eec\u4f1a\u5f97\u5230\u76f8\u540c\u7684\u7ed3\u679c\uff0c2\u4e2a\u8282\u70b9\u5904\u4e8e\u4e0d\u53ef\u7528\u72b6\u6001\u3002\u8fd9\u91cc\u7684 -v \u8868\u793a\u6392\u9664\uff0c -c \u8868\u793a\u8ba1\u6570\u3002 \u67e5\u770b\u4e0d\u53ef\u7528\u8282\u70b9 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u5f53\u6211\u4eec\u5728Worker\u8282\u70b9 cka002 \u4e0a\u505c\u6b62 kubelet \u670d\u52a1\u65f6\uff0c \u6bcf\u4e2a\u8282\u70b9\u7684\u72b6\u6001\u662f\u4ec0\u4e48\uff1f \u901a\u8fc7 nerdctl \u547d\u4ee4\u66f4\u6539\u4e86\u54ea\u4e9b\u5bb9\u5668\uff1f \u901a\u8fc7\u547d\u4ee4 kubectl get pod -owide -A \u67e5\u770b\u7684Pod\u72b6\u6001\u662f\u4ec0\u4e48\uff1f \u6f14\u793a\uff1a \u5728 cka002 \u8282\u70b9\u4e0a\u6267\u884c\u547d\u4ee4 systemctl stop kubelet.service \u3002 \u5728 cka001 \u6216 cka003 \u4e0a\u6267\u884c\u547d\u4ee4 kubectl get node \uff0c\u53ef\u4ee5\u770b\u5230 cka002 \u7684\u72b6\u6001\u4ece Ready \u53d8\u4e3a NotReady \u3002 \u5728 cka002 \u4e0a\u6267\u884c\u547d\u4ee4 nerdctl -n k8s.io container ls \uff0c\u53ef\u4ee5\u770b\u5230\u6240\u6709\u5bb9\u5668\u90fd\u4ecd\u5728\u8fd0\u884c\uff0c\u5305\u62ecPod my-first-pod \u3002 \u5728 cka002 \u4e0a\u6267\u884c\u547d\u4ee4 systemctl start kubelet.service \u3002 \u7ed3\u8bba\uff1a \u8282\u70b9\u72b6\u6001\u7531 Ready \u53d8\u4e3a NotReady \u3002 \u5bf9\u4e8e\u90a3\u4e9b\u7c7b\u4f3c calico \u3001 kube-proxy \u8fd9\u6837\u7684 DaemonSet Pod\uff0c\u5b83\u4eec\u4e13\u95e8\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u3002\u5728 kubelet \u505c\u6b62\u540e\u5b83\u4eec\u4e0d\u4f1a\u88ab\u7ec8\u6b62\u3002 Pod my-first-pod \u7684\u72b6\u6001\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u4ecd\u7136\u663e\u793a\u4e3a Terminating \uff0c\u56e0\u4e3a\u72b6\u6001\u65e0\u6cd5\u901a\u8fc7 apiserver \u4ece cka002 \u540c\u6b65\u5230\u5176\u4ed6\u8282\u70b9\uff0c\u56e0\u4e3a kubelet \u5df2\u505c\u6b62\u3002 Pod\u7684\u72b6\u6001\u7531\u63a7\u5236\u5668\u6807\u8bb0\u5e76\u7531 kubelet \u56de\u6536\u3002 \u5f53\u6211\u4eec\u5728 cka003 \u4e0a\u542f\u52a8 kubelet \u670d\u52a1\u65f6\uff0cPod my-first-pod \u5c06\u5b8c\u5168\u5728 cka002 \u4e0a\u88ab\u7ec8\u6b62\u3002 \u6b64\u5916\uff0c\u8ba9\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u526f\u672c\u6570\u4e3a3\u7684Deployment\u3002\u5176\u4e2d\u4e24\u4e2a\u526f\u672c\u8fd0\u884c\u5728 cka003 \u4e0a\uff0c\u53e6\u4e00\u4e2a\u526f\u672c\u8fd0\u884c\u5728 cka002 \u4e0a\u3002 kubectl get pod -o wide -w \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-9d745469b-2xdk4 1/1 Running 0 2m8s 10.244.2.3 cka003 nginx-deployment-9d745469b-4gvmr 1/1 Running 0 2m8s 10.244.2.4 cka003 nginx-deployment-9d745469b-5j927 1/1 Running 0 2m8s 10.244.1.3 cka002 \u5728\u6211\u4eec\u505c\u6b62 cka003 \u4e0a\u7684 kubelet \u670d\u52a1\u540e\uff0c\u539f\u5148\u5728 cka003 \u4e0a\u8fd0\u884c\u7684\u4e24\u4e2a\u526f\u672c\u4f1a\u88ab\u7ec8\u6b62\uff0c\u7136\u540e\u4f1a\u81ea\u52a8\u5728 cka002 \u4e0a\u521b\u5efa\u4e24\u4e2a\u65b0\u7684\u526f\u672c\u5e76\u8fd0\u884c\u3002 \u76d1\u63a7\u6307\u6807 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u67e5\u8be2pod\u7684\u76d1\u63a7\u6307\u6807 \u6f14\u793a\uff1a \u67e5\u8be2\u8282\u70b9\u7684\u5065\u5eb7\u4fe1\u606f\u3002 kubectl top node \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 147m 7% 1940Mi 50% cka002 62m 3% 2151Mi 56% cka003 63m 3% 1825Mi 47% \u67e5\u8be2pod\u7684\u76d1\u63a7\u6307\u6807\u3002 kubectl top pod \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) MEMORY(bytes) busybox-with-secret 0m 0Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi tomcat 1m 58Mi \u901a\u8fc7\u9009\u9879 --sort-by \uff0c\u5bf9\u8f93\u51fa\u7ed3\u679c\u6309\u7167CPU\u6216\u8005\u5185\u5b58\u7528\u91cf\u8fdb\u884c\u6392\u5e8f\u3002 kubectl top pod --sort-by = cpu kubectl top pod --sort-by = memory \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) MEMORY(bytes) nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi tomcat 1m 58Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi busybox-with-secret 0m 0Mi \u8282\u70b9\u9a71\u9010 \u00b6 \u8282\u70b9\u7684\u53ef\u8c03\u5ea6\u6027 \u00b6 \u6f14\u793a\u573a\u666f\uff1a \u8282\u70b9\u8c03\u5ea6 \u6f14\u793a\uff1a \u7981\u6b62\u4e00\u4e2a\u8282\u70b9\u7684\u8c03\u5ea6\u3002 kubectl cordon \u4e3e\u4f8b\uff1a kubectl cordon cka003 \u8f93\u51fa\u7ed3\u679c\uff0c\u8282\u70b9\u72b6\u6001\u5982\u4e0b\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready,SchedulingDisabled 18d v1.24.0 \u6fc0\u6d3b\u4e00\u4e2a\u8282\u70b9\u7684\u8c03\u5ea6\u3002 kubectl uncordon \u4e3e\u4f8b\uff1a kubectl uncordon cka003 \u8f93\u51fa\u7ed3\u679c\uff0c\u8282\u70b9\u72b6\u6001\u5982\u4e0b\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready 18d v1.24.0 \u9a71\u9010\u8282\u70b9 \u00b6 \u6f14\u793a\u5185\u5bb9\uff1a \u9a71\u9010\u8282\u70b9 cka003 \u6f14\u793a\uff1a \u83b7\u53d6\u5f53\u524d\u8fd0\u884cpod\u7684\u5217\u8868\u3002 kubectl get pod -o wide \u5176\u4e2d\u6709\u4e00\u4e2apod\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-xk8nw 1/1 Running 0 22h 10.244.102.3 cka003 \u9a71\u9010\u8282\u70b9 cka003 \u3002 kubectl drain cka003 --ignore-daemonsets --delete-emptydir-data --force \u8f93\u51fa\u7ed3\u679c\uff1a node/cka003 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-tr22l, kube-system/kube-proxy-g76kg evicting pod dev/nfs-client-provisioner-86d7fb78b6-xk8nw evicting pod cka/cka-demo-64f88f7f46-dkxmk pod/nfs-client-provisioner-86d7fb78b6-xk8nw evicted pod/cka-demo-64f88f7f46-dkxmk evicted node/cka003 drained \u518d\u6b21\u67e5\u770bpod\u7684\u72b6\u6001\u3002 kubectl get pod -o wide \u5148\u524d\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u4e0a\u7684pod\u73b0\u5728\u6b63\u8fd0\u884c\u5728\u8282\u70b9 cka002 \u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-k8xnl 1/1 Running 0 2m20s 10.244.112.4 cka002 \u5907\u6ce8\uff1a cordon \u547d\u4ee4\u5df2\u7ecf\u5305\u542b\u5728 drain \u547d\u4ee4\u4e2d\uff0c\u4e0d\u9700\u8981\u5728\u6267\u884c drain \u4e4b\u524d\u5355\u72ec\u6267\u884c cordon \u6765\u7981\u6b62node\u7684\u8c03\u5ea6\u3002","title":"Troubleshooting"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#cka25troubleshooting","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb025:Troubleshooting"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_1","text":"\u6f14\u793a\u573a\u666f\uff1a \u63cf\u8ff0pod\u4ee5\u83b7\u53d6\u4e8b\u4ef6\u4fe1\u606f\u3002 \u6f14\u793a\uff1a \u547d\u4ee4\u7528\u6cd5\uff1a kubectl describe --namespace = \u67e5\u8be2pod\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 \u521b\u5efa\u4e00\u4e2aTomcat\u7684pod\u3002 kubectl run tomcat --image = tomcat \u67e5\u8be2pod\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl describe pod/tomcat \u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 55s default-scheduler Successfully assigned dev/tomcat to cka002 Normal Pulling 54s kubelet Pulling image \"tomcat\" Normal Pulled 21s kubelet Successfully pulled image \"tomcat\" in 33.134162692s Normal Created 19s kubelet Created container tomcat Normal Started 19s kubelet Started container tomcat \u67e5\u8be2namespace\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl get events -n \u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u9ed8\u8ba4namespace\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 LAST SEEN TYPE REASON OBJECT MESSAGE 70s Warning FailedGetScale horizontalpodautoscaler/nginx deployments/scale.apps \"podinfo\" not found 2m16s Normal Scheduled pod/tomcat Successfully assigned dev/tomcat to cka002 2m15s Normal Pulling pod/tomcat Pulling image \"tomcat\" 102s Normal Pulled pod/tomcat Successfully pulled image \"tomcat\" in 33.134162692s 100s Normal Created pod/tomcat Created container tomcat 100s Normal Started pod/tomcat Started container tomcat \u5f97\u5230\u7c7b\u4f3c\u4e0b\u9762\u7684\u6240\u6709\u7684namespace\u7684\u4e8b\u4ef6\u4fe1\u606f\u3002 kubectl get events -A","title":"\u4e8b\u4ef6"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_2","text":"\u6f14\u793a\u573a\u666f\uff1a \u67e5\u8be2pod\u7684\u65e5\u5fd7 \u547d\u4ee4\u7528\u6cd5\uff1a kubectl logs -n \u9009\u9879\uff1a --tail : \u663e\u793a\u8f93\u51fa\u7684\u6700\u8fd1 \u884c\u3002 -f \uff1a\u5b9e\u65f6\u6d41\u5f0f\u663e\u793a\u8f93\u51fa\u3002 \u663e\u793a\u8f93\u51fa\u7684\u6700\u8fd1100\u884c\u8f93\u51fa\u3002 kubectl logs -f tomcat --tail 100 \u5982\u679c\u662f\u4e00\u4e2a\u591a\u5bb9\u5668pod\uff0c\u5219\u4f7f\u7528\u9009\u9879 -c \u6765\u6307\u5b9a\u67d0\u4e2a\u7279\u5b9a\u7684\u5bb9\u5668\u3002 kubectl logs -f tomcat --tail 100 -c tomcat","title":"\u65e5\u5fd7"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_3","text":"","title":"\u8282\u70b9\u53ef\u7528\u6027"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_4","text":"\u6f14\u793a\u573a\u666f\uff1a \u67e5\u770b\u8282\u70b9\u53ef\u7528\u6027 \u6f14\u793a\uff1a \u65b9\u5f0f1\uff1a kubectl describe node | grep -i taint \u624b\u5de5\u65b9\u5f0f\u68c0\u67e5\u65e5\u5fd7\uff0c\u4e0b\u9762\u7684\u4f8b\u5b50\u8bf4\u660e2\u4e2a\u8282\u70b9\u5904\u4e8e\u4e0d\u53ef\u7528\u72b6\u6001\u3002 Taints : node-role.kubernetes.io/control-plane:NoSchedule Taints : Taints : \u65b9\u5f0f2\uff1a kubectl describe node | grep -i taint | grep -vc NoSchedule \u8fd9\u91cc\u6211\u4eec\u4f1a\u5f97\u5230\u76f8\u540c\u7684\u7ed3\u679c\uff0c2\u4e2a\u8282\u70b9\u5904\u4e8e\u4e0d\u53ef\u7528\u72b6\u6001\u3002\u8fd9\u91cc\u7684 -v \u8868\u793a\u6392\u9664\uff0c -c \u8868\u793a\u8ba1\u6570\u3002","title":"\u67e5\u770b\u53ef\u7528\u8282\u70b9"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_5","text":"\u6f14\u793a\u573a\u666f\uff1a \u5f53\u6211\u4eec\u5728Worker\u8282\u70b9 cka002 \u4e0a\u505c\u6b62 kubelet \u670d\u52a1\u65f6\uff0c \u6bcf\u4e2a\u8282\u70b9\u7684\u72b6\u6001\u662f\u4ec0\u4e48\uff1f \u901a\u8fc7 nerdctl \u547d\u4ee4\u66f4\u6539\u4e86\u54ea\u4e9b\u5bb9\u5668\uff1f \u901a\u8fc7\u547d\u4ee4 kubectl get pod -owide -A \u67e5\u770b\u7684Pod\u72b6\u6001\u662f\u4ec0\u4e48\uff1f \u6f14\u793a\uff1a \u5728 cka002 \u8282\u70b9\u4e0a\u6267\u884c\u547d\u4ee4 systemctl stop kubelet.service \u3002 \u5728 cka001 \u6216 cka003 \u4e0a\u6267\u884c\u547d\u4ee4 kubectl get node \uff0c\u53ef\u4ee5\u770b\u5230 cka002 \u7684\u72b6\u6001\u4ece Ready \u53d8\u4e3a NotReady \u3002 \u5728 cka002 \u4e0a\u6267\u884c\u547d\u4ee4 nerdctl -n k8s.io container ls \uff0c\u53ef\u4ee5\u770b\u5230\u6240\u6709\u5bb9\u5668\u90fd\u4ecd\u5728\u8fd0\u884c\uff0c\u5305\u62ecPod my-first-pod \u3002 \u5728 cka002 \u4e0a\u6267\u884c\u547d\u4ee4 systemctl start kubelet.service \u3002 \u7ed3\u8bba\uff1a \u8282\u70b9\u72b6\u6001\u7531 Ready \u53d8\u4e3a NotReady \u3002 \u5bf9\u4e8e\u90a3\u4e9b\u7c7b\u4f3c calico \u3001 kube-proxy \u8fd9\u6837\u7684 DaemonSet Pod\uff0c\u5b83\u4eec\u4e13\u95e8\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u8fd0\u884c\u3002\u5728 kubelet \u505c\u6b62\u540e\u5b83\u4eec\u4e0d\u4f1a\u88ab\u7ec8\u6b62\u3002 Pod my-first-pod \u7684\u72b6\u6001\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u4ecd\u7136\u663e\u793a\u4e3a Terminating \uff0c\u56e0\u4e3a\u72b6\u6001\u65e0\u6cd5\u901a\u8fc7 apiserver \u4ece cka002 \u540c\u6b65\u5230\u5176\u4ed6\u8282\u70b9\uff0c\u56e0\u4e3a kubelet \u5df2\u505c\u6b62\u3002 Pod\u7684\u72b6\u6001\u7531\u63a7\u5236\u5668\u6807\u8bb0\u5e76\u7531 kubelet \u56de\u6536\u3002 \u5f53\u6211\u4eec\u5728 cka003 \u4e0a\u542f\u52a8 kubelet \u670d\u52a1\u65f6\uff0cPod my-first-pod \u5c06\u5b8c\u5168\u5728 cka002 \u4e0a\u88ab\u7ec8\u6b62\u3002 \u6b64\u5916\uff0c\u8ba9\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u526f\u672c\u6570\u4e3a3\u7684Deployment\u3002\u5176\u4e2d\u4e24\u4e2a\u526f\u672c\u8fd0\u884c\u5728 cka003 \u4e0a\uff0c\u53e6\u4e00\u4e2a\u526f\u672c\u8fd0\u884c\u5728 cka002 \u4e0a\u3002 kubectl get pod -o wide -w \u8fd0\u884c\u7ed3\u679c NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-9d745469b-2xdk4 1/1 Running 0 2m8s 10.244.2.3 cka003 nginx-deployment-9d745469b-4gvmr 1/1 Running 0 2m8s 10.244.2.4 cka003 nginx-deployment-9d745469b-5j927 1/1 Running 0 2m8s 10.244.1.3 cka002 \u5728\u6211\u4eec\u505c\u6b62 cka003 \u4e0a\u7684 kubelet \u670d\u52a1\u540e\uff0c\u539f\u5148\u5728 cka003 \u4e0a\u8fd0\u884c\u7684\u4e24\u4e2a\u526f\u672c\u4f1a\u88ab\u7ec8\u6b62\uff0c\u7136\u540e\u4f1a\u81ea\u52a8\u5728 cka002 \u4e0a\u521b\u5efa\u4e24\u4e2a\u65b0\u7684\u526f\u672c\u5e76\u8fd0\u884c\u3002","title":"\u67e5\u770b\u4e0d\u53ef\u7528\u8282\u70b9"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_6","text":"\u6f14\u793a\u573a\u666f\uff1a \u67e5\u8be2pod\u7684\u76d1\u63a7\u6307\u6807 \u6f14\u793a\uff1a \u67e5\u8be2\u8282\u70b9\u7684\u5065\u5eb7\u4fe1\u606f\u3002 kubectl top node \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 147m 7% 1940Mi 50% cka002 62m 3% 2151Mi 56% cka003 63m 3% 1825Mi 47% \u67e5\u8be2pod\u7684\u76d1\u63a7\u6307\u6807\u3002 kubectl top pod \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) MEMORY(bytes) busybox-with-secret 0m 0Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi tomcat 1m 58Mi \u901a\u8fc7\u9009\u9879 --sort-by \uff0c\u5bf9\u8f93\u51fa\u7ed3\u679c\u6309\u7167CPU\u6216\u8005\u5185\u5b58\u7528\u91cf\u8fdb\u884c\u6392\u5e8f\u3002 kubectl top pod --sort-by = cpu kubectl top pod --sort-by = memory \u8fd0\u884c\u7ed3\u679c\uff1a NAME CPU(cores) MEMORY(bytes) nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi tomcat 1m 58Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi busybox-with-secret 0m 0Mi","title":"\u76d1\u63a7\u6307\u6807"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_7","text":"","title":"\u8282\u70b9\u9a71\u9010"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_8","text":"\u6f14\u793a\u573a\u666f\uff1a \u8282\u70b9\u8c03\u5ea6 \u6f14\u793a\uff1a \u7981\u6b62\u4e00\u4e2a\u8282\u70b9\u7684\u8c03\u5ea6\u3002 kubectl cordon \u4e3e\u4f8b\uff1a kubectl cordon cka003 \u8f93\u51fa\u7ed3\u679c\uff0c\u8282\u70b9\u72b6\u6001\u5982\u4e0b\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready,SchedulingDisabled 18d v1.24.0 \u6fc0\u6d3b\u4e00\u4e2a\u8282\u70b9\u7684\u8c03\u5ea6\u3002 kubectl uncordon \u4e3e\u4f8b\uff1a kubectl uncordon cka003 \u8f93\u51fa\u7ed3\u679c\uff0c\u8282\u70b9\u72b6\u6001\u5982\u4e0b\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready 18d v1.24.0","title":"\u8282\u70b9\u7684\u53ef\u8c03\u5ea6\u6027"},{"location":"k8s/cka_cn/foundamentals/troubleshooting/#_9","text":"\u6f14\u793a\u5185\u5bb9\uff1a \u9a71\u9010\u8282\u70b9 cka003 \u6f14\u793a\uff1a \u83b7\u53d6\u5f53\u524d\u8fd0\u884cpod\u7684\u5217\u8868\u3002 kubectl get pod -o wide \u5176\u4e2d\u6709\u4e00\u4e2apod\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-xk8nw 1/1 Running 0 22h 10.244.102.3 cka003 \u9a71\u9010\u8282\u70b9 cka003 \u3002 kubectl drain cka003 --ignore-daemonsets --delete-emptydir-data --force \u8f93\u51fa\u7ed3\u679c\uff1a node/cka003 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-tr22l, kube-system/kube-proxy-g76kg evicting pod dev/nfs-client-provisioner-86d7fb78b6-xk8nw evicting pod cka/cka-demo-64f88f7f46-dkxmk pod/nfs-client-provisioner-86d7fb78b6-xk8nw evicted pod/cka-demo-64f88f7f46-dkxmk evicted node/cka003 drained \u518d\u6b21\u67e5\u770bpod\u7684\u72b6\u6001\u3002 kubectl get pod -o wide \u5148\u524d\u8fd0\u884c\u5728\u8282\u70b9 cka003 \u4e0a\u7684pod\u73b0\u5728\u6b63\u8fd0\u884c\u5728\u8282\u70b9 cka002 \u4e0a\u3002 NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-k8xnl 1/1 Running 0 2m20s 10.244.112.4 cka002 \u5907\u6ce8\uff1a cordon \u547d\u4ee4\u5df2\u7ecf\u5305\u542b\u5728 drain \u547d\u4ee4\u4e2d\uff0c\u4e0d\u9700\u8981\u5728\u6267\u884c drain \u4e4b\u524d\u5355\u72ec\u6267\u884c cordon \u6765\u7981\u6b62node\u7684\u8c03\u5ea6\u3002","title":"\u9a71\u9010\u8282\u70b9"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/","text":"CKA\u81ea\u5b66\u7b14\u8bb03:\u963f\u91cc\u4e91ECS\u5b89\u88c5Kubernetes \u00b6 \u6458\u8981 \u00b6 \u5728\u963f\u91cc\u4e91ECS\u88c5\u4e09\u53f0Ubuntu\u865a\u62df\u673a\u3002\u5728Ubuntu\u865a\u62df\u673a\u4e2d\u5b89\u88c5\u57fa\u4e8eContainerd\u7684Kubernetes\u7cfb\u7edf\uff0c\u5e76\u5206\u522b\u914d\u7f6e\u4e00\u4e2a\u4e3b\u8282\u70b9Master\u548c\u4e24\u4e2a\u5de5\u4f5c\u8282\u70b9Worker\uff0c\u3002 \u51c6\u5907\u5de5\u4f5c \u00b6 \u6ce8\u518c\u963f\u91cc\u4e91\u8d26\u53f7\uff1a Alibaba Cloud home console \u3002\u6ce8\u610f\u4fdd\u7559\u8bbf\u95ee\u5bc6\u94a5key\u6587\u4ef6\uff0c\u53ea\u80fd\u5bfc\u51fa\u4e00\u6b21\uff0c\u5f53\u524d\u7ec3\u4e60\u4e2dkey\u6587\u4ef6\u662f aliyun-root \u3002 \u53c2\u8003\u4e0b\u9762\u914d\u7f6e\u6ce8\u518c\u7533\u8bf7\u4e09\u4e2aECS\uff08Elastic Computer Service\uff09\u670d\u52a1\u5b9e\u4f8b\uff1a \u4e3b\u673a\uff1a2vCPU+4GiB \u64cd\u4f5c\u7cfb\u7edf\uff1aUbuntu 20.04 x86_64 \u5b9e\u4f8b\u7c7b\u578b\uff1aecs.sn1.medium \u5b9e\u4f8b\u540d\u79f0\uff1acka001, cka002, cka003 \u7f51\u7edc\u914d\u7f6e\uff1aboth public IPs and private IPs \u6700\u5927\u7f51\u7edc\u5e26\u5bbd\uff1a100Mbps (Peak Value) \u4e91\u76d8\uff1a40GiB \u652f\u4ed8\u65b9\u5f0f\uff1a\u62a2\u5360\u5f0f\u5b9e\u4f8b \u5728\u672c\u5730\u6253\u5f00\u7ec8\u7aef\u7a97\u53e3\uff0c\u901a\u8fc7\u5bc6\u94a5\u6587\u4ef6 aliyun-root \u8bbf\u95ee\u8fdc\u7a0bECS\u8282\u70b9 cka001 \u3002 ssh -i aliyun-root root@cka001 \u521b\u5efa\u4e00\u4e2a\u666e\u901a\u7528\u6237\uff0c\u7528\u6765\u5b89\u88c5Kubernetes\uff0c\u5f53\u524d\u7ec3\u4e60\u4e2d\u521b\u5efa\u7528\u6237 vagrant \uff0c\u4e14\u4fee\u6539\u8be5\u7528\u6237\u7684\u4e3b\u8981\u7ec4\u4e3a sudo \u6b21\u8981\u7ec4\u5305\u542b root \u3002 adduser vagrant usermod -g sudo vagrant usermod -a -G root vagrant \u65b0\u5f00\u4e00\u4e2a\u672c\u5730\u7ec8\u7aef\u7a97\u53e3\uff0c\u4e3a\u7528\u6237 vagrant \u521b\u5efa\u5bc6\u94a5key\u3002 # Windows ssh-keygen.exe # Linux ssh-keygen \u4e0a\u9762\u7684\u547d\u4ee4\u4f1a\u751f\u62102\u4e2a\u6587\u4ef6\uff0c\u5f53\u524d\u7ec3\u4e60\u4e2d\u8fd92\u4e2a\u6587\u4ef6\u662f aliyun-vagrant and aliyun-vagrant.pub \u901a\u8fc7 sftp \u547d\u4ee4\u5c06\u516c\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u4e0a\u4f20\u5230\u8fdc\u7a0b\u8282\u70b9 cka001 \u3002 sftp -i aliyun-root root@cka001 put aliyun-vagrant.pub \u65b0\u5f00\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\uff0c\u7528 root \u7684\u5bc6\u94a5\u767b\u5f55 cka001 \u8282\u70b9\u3002 \u5c06\u4e0a\u4e00\u6b65\u4e0a\u4f20\u7684\u5bc6\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u4ece /root \u76ee\u5f55\u62f7\u8d1d\u5230 /home/vagrant/.ssh/ \u3002 \u5c06\u516c\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u91cd\u547d\u540d\u4e3a authorized_keys \u3002 \u66f4\u6539\u6587\u4ef6 authorized_keys \u7684\u6240\u6709\u8005owner\u4e3a vagrant . \u66f4\u6539\u6587\u4ef6 authorized_keys \u7684\u4e3b\u8981\u7ec4\u4e3a sudo \u3002 mkdir /home/vagrant/.ssh/ mv aliyun-james.pub /home/vagrant/.ssh/authorized_keys chown vagrant.sudo /home/vagrant/.ssh/authorized_keys chmod 600 /home/vagrant/.ssh/authorized_keys \u68c0\u67e5\u6587\u4ef6 /etc/ssh/sshd_config \uff0c\u786e\u5b9a\u5bc6\u7801\u767b\u5f55\u9a8c\u8bc1\u53c2\u6570 asswordAuthentication \u8bbe\u5b9a\u4e3a no \uff0c\u5373\u53ea\u80fd\u901a\u8fc7\u8bc1\u4e66\u8fdc\u7a0b\u767b\u5f55\u3002 cat /etc/ssh/sshd_config \u65b0\u5f00\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\uff0c\u4f7f\u7528\u7528\u6237vagrant\u767b\u5f55\u8fdc\u7a0b\u8282\u70b9 cka001 \uff0c\u9a8c\u8bc1\u7528\u6237 vagrant \u80fd\u901a\u8fc7\u524d\u9762\u521b\u5efa\u7684\u8bc1\u4e66\u767b\u5f55\u8282\u70b9 cka001 \u3002 ssh -i aliyun-vagrant vagrant@cka001 \u91cd\u590d\u4e0a\u8ff0\u6b65\u9aa4\uff0c\u901a\u8fc7 sftp \u547d\u4ee4\u5c06\u516c\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u5206\u522b\u4e0a\u4f20\u5230\u8fdc\u7a0b\u8282\u70b9 cka002 \u548c cka003 \uff0c\u4e14\u5b8c\u6210\u540c\u6837\u7684\u914d\u7f6e\uff0c\u4f7f\u7528\u6237 vagrant \u4e5f\u80fd\u901a\u8fc7\u5bc6\u94a5\u6587\u4ef6\u767b\u5f55\u8fdc\u7a0b\u8282\u70b9 cka002 \u548c cka003 \u3002 \u81f3\u6b64\uff0c\u7528\u6237 vagrant \u53ef\u4ee5\u901a\u8fc7\u5bc6\u94a5\u6587\u4ef6 aliyun-vagrant \u4ece\u672c\u5730\u7ec8\u7aef\u7a97\u53e3\u767b\u5f55\u8fdc\u7a0b\u8282\u70b9 cka001 , cka002 \u548c cka003 \u3002 \u4e0b\u9762\u6240\u6709\u6b65\u9aa4\u90fd\u662f\u901a\u8fc7\u7528\u6237 vagrant \u5b8c\u6210\u3002 \u521d\u59cb\u5316ECS\u8282\u70b9 \u00b6 \u914d\u7f6e\u6587\u4ef6/etc/hosts \u00b6 \u66f4\u65b0\u6240\u6709ECS\u8282\u70b9\u7684\u6587\u4ef6/etc/hosts\uff0c\u6dfb\u52a0\u5176\u4ed6\u8282\u70b9\u7684\u79c1\u6709IP\uff08private IP\uff09\u3002 vi /etc/hosts \u7981\u7528firewall \u00b6 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u7981\u7528\u9632\u706b\u5899\u3002 sudo ufw disable \u68c0\u67e5\u9632\u706b\u5899\u72b6\u6001\u3002 sudo ufw status verbose \u5173\u95edswap \u00b6 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5173\u95edswap\u3002 sudo swapoff -a \u8bbe\u7f6e\u65f6\u533a\u548c\u5730\u57df \u00b6 \u5728\u6240\u6709\u8282\u70b9\u8bbe\u5b9a\u65f6\u533a\u548c\u5730\u57df\u3002\u8fd9\u4e00\u5e03\u5728\u521d\u59cb\u5316ECS\u65f6\u5019\u5df2\u7ecf\u5b8c\u6210\u3002\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u8fdb\u884c\u8bbe\u5b9a\u3002 ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile \u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u68c0\u67e5\u65f6\u533a\u548c\u5730\u57df\u7684\u8bbe\u7f6e\u3002 ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 5 14:51 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai \u5185\u6838\u8bbe\u7f6e \u00b6 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u4ee5\u914d\u7f6e\u5185\u6838\u3002 \u4f7f\u7528\u6a21\u5757overlay\uff1a \u521b\u5efaContainerd\u670d\u52a1\u914d\u7f6e\u6587\u4ef6 /etc/modules-load.d/containerd.conf \uff0c\u5982\u679c\u5df2\u5b58\u5728\u5219\u8df3\u8fc7\u8fd9\u4e00\u6b65\u3002\u914d\u7f6e\u8fd9\u4e2a\u6587\u4ef6\u7684\u76ee\u7684\u662f\u4e3a\u4e86\u52a0\u8f7d\u6a21\u5757 overlay \u548c br_netfilter \u5230\u5185\u6838\u4e2d\u3002 \u670d\u52a1Containerd\u4f9d\u8d56\u6a21\u5757 overlay \u5b9e\u73b0 overlay-filesystem \u6587\u4ef6\u7cfb\u7edf\u529f\u80fd\u3002 Linux\u4e2d\u7684overlay\u6a21\u5757\u63d0\u4f9b\u4e86\u521b\u5efa\u4e24\u4e2a\u76ee\u5f55\u7684\u5408\u5e76\u89c6\u56fe\u7684\u80fd\u529b\uff0c\u8fd9\u4e24\u4e2a\u76ee\u5f55\u79f0\u4e3a\u5c42\u3002\u5b83\u7ecf\u5e38\u88ab\u7528\u4e8e\u5b9e\u73b0\u8054\u5408\u6302\u8f7d\uff0c\u8fd9\u662f\u4e00\u79cd\u5c06\u4e24\u4e2a\u6216\u66f4\u591a\u76ee\u5f55\u4e00\u8d77\u6302\u8f7d\u7684\u65b9\u5f0f\uff0c\u5c31\u50cf\u5b83\u4eec\u662f\u4e00\u4e2a\u76ee\u5f55\u4e00\u6837\uff08union-filesystems\uff09\u3002 overlay\u6a21\u5757\u5728\u5bb9\u5668\u6280\u672f\u4e2d\u88ab\u5e7f\u6cdb\u4f7f\u7528\uff0c\u6bd4\u5982Docker\uff0c\u56e0\u4e3a\u5b83\u5141\u8bb8\u591a\u4e2a\u5bb9\u5668\u5171\u4eab\u57fa\u7840\u955c\u50cf\uff0c\u540c\u65f6\u4fdd\u6301\u5b83\u4eec\u81ea\u5df1\u7684\u6587\u4ef6\u7cfb\u7edf\u3002 \u8981\u4f7f\u7528overlay\u6a21\u5757\uff0c\u9700\u8981\u4e24\u4e2a\u76ee\u5f55\uff1a\u8f83\u4f4e\u7684\u76ee\u5f55\uff08lower directory\uff09\u548c\u8f83\u9ad8\u7684\u76ee\u5f55\uff08upper directory\uff09\u3002\u8f83\u4f4e\u7684\u76ee\u5f55\u901a\u5e38\u662f\u53ea\u8bfb\u7684\uff0c\u5305\u542b\u539f\u59cb\u6587\u4ef6\uff0c\u800c\u8f83\u9ad8\u7684\u76ee\u5f55\u662f\u53ef\u8bfb\u5199\u7684\uff0c\u5305\u542b\u5bf9\u6587\u4ef6\u7684\u66f4\u6539\u3002\u5f53\u8bf7\u6c42\u6587\u4ef6\u65f6\uff0coverlay\u6a21\u5757\u9996\u5148\u67e5\u627e\u4e0a\u5c42\u76ee\u5f55\uff0c\u5982\u679c\u672a\u627e\u5230\uff0c\u5219\u67e5\u627e\u4e0b\u5c42\u76ee\u5f55\u3002 \u6bd4\u5982\uff1a \u521b\u5efa\u4e24\u4e2a\u76ee\u5f55\uff0c\u4e00\u4e2a\u7528\u4e8e\u8f83\u4f4e\u7684\u76ee\u5f55\uff0c\u4e00\u4e2a\u7528\u4e8e\u8f83\u9ad8\u7684\u76ee\u5f55\u3002\u7136\u540e\u4f7f\u7528overlay\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u5c06\u5b83\u4eec\u6302\u8f7d\u8d77\u6765\uff1a sudo mkdir /lower sudo mkdir /upper sudo mount -t overlay overlay -o lowerdir = /lower,upperdir = /upper /merged \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c\u4e24\u4e2a\u76ee\u5f55\u7684\u5408\u5e76\u89c6\u56fe\u88ab\u521b\u5efa\u5728 /merged \u76ee\u5f55\u4e2d\u3002\u5728 /merged \u76ee\u5f55\u4e2d\u5bf9\u6587\u4ef6\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u5b58\u50a8\u5728\u4e0a\u5c42\u76ee\u5f55\u4e2d\uff0c\u800c\u539f\u59cb\u6587\u4ef6\u4ecd\u7136\u5728\u4e0b\u5c42\u76ee\u5f55\u4e2d\u3002 \u4f7f\u7528\u6a21\u5757br_netfilter\uff1a br_netfilter \u662fLinux\u5185\u6838\u4e2d\u7684\u4e00\u4e2a\u6a21\u5757\uff0c\u5b83\u63d0\u4f9b\u4e86\u4e00\u79cd\u673a\u5236\u6765\u8fc7\u6ee4\u7f51\u6865\u7684\u7f51\u7edc\u6d41\u91cf\u3002\u8be5\u6a21\u5757\u5141\u8bb8\u7ba1\u7406\u5458\u914d\u7f6e\u89c4\u5219\uff0c\u4ee5\u5141\u8bb8\u6216\u62d2\u7edd\u7279\u5b9a\u7684\u7f51\u7edc\u6d41\u91cf\u901a\u8fc7\u7f51\u6865\u3002 \u7f51\u6865\u662f\u4e00\u79cd\u7f51\u7edc\u8bbe\u5907\uff0c\u5b83\u53ef\u4ee5\u8fde\u63a5\u591a\u4e2a\u7f51\u7edc\u6bb5\uff0c\u5e76\u8f6c\u53d1\u6d41\u91cf\u4ee5\u4f7f\u4e0d\u540c\u7684\u7f51\u7edc\u6bb5\u4e4b\u95f4\u901a\u4fe1\u3002 br_netfilter \u6a21\u5757\u53ef\u4ee5\u7528\u6765\u9650\u5236\u6216\u8fc7\u6ee4\u8fd9\u4e9b\u6d41\u91cf\u3002 \u5f53\u542f\u7528\u4e86 br_netfilter \u6a21\u5757\u65f6\uff0c\u5b83\u4f1a\u81ea\u52a8\u542f\u7528\u4e00\u4e2a\u79f0\u4e3a bridge-nf \u7684\u529f\u80fd\uff0c\u8be5\u529f\u80fd\u5c06\u5728\u7f51\u7edc\u6d41\u91cf\u901a\u8fc7\u7f51\u6865\u65f6\u5e94\u7528\u89c4\u5219\u3002\u7ba1\u7406\u5458\u53ef\u4ee5\u4f7f\u7528iptables\u7b49\u5de5\u5177\u6765\u914d\u7f6e\u8fd9\u4e9b\u89c4\u5219\u3002\u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u8bbe\u5b9a\u5141\u8bb8\u4ece\u4e00\u4e2a\u7f51\u7edc\u6bb5\u5230\u53e6\u4e00\u4e2a\u7f51\u7edc\u6bb5\u7684\u6d41\u91cf\uff0c\u6216\u8005\u62d2\u7edd\u6765\u81ea\u7279\u5b9aIP\u5730\u5740\u6216\u7aef\u53e3\u7684\u6d41\u91cf\u3002 \u5728Kubernetes\u4e2d\uff0c br_netfilter \u6a21\u5757\u4e3b\u8981\u7528\u4e8e\u542f\u7528Kubernetes\u670d\u52a1\u7684\u6d41\u91cf\u8f6c\u53d1\u548c\u8d1f\u8f7d\u5747\u8861\u3002\u8fd9\u4e9b\u670d\u52a1\u4f7f\u7528\u4e86Linux\u5185\u6838\u4e2d\u7684iptables\u89c4\u5219\u6765\u7ba1\u7406\u6d41\u91cf\uff0c\u8fd9\u4e9b\u89c4\u5219\u662f\u901a\u8fc7 br_netfilter \u6a21\u5757\u5b9e\u73b0\u7684\u3002 \u5177\u4f53\u6765\u8bf4\uff0c\u5f53\u6211\u4eec\u5728Kubernetes\u96c6\u7fa4\u4e2d\u521b\u5efa\u4e00\u4e2a\u670d\u52a1\u65f6\uff0c\u8be5\u670d\u52a1\u5c06\u5206\u914d\u4e00\u4e2a\u865a\u62dfIP\u5730\u5740\uff0c\u7528\u4e8e\u4ee3\u8868\u670d\u52a1\u3002\u7136\u540e\uff0c\u901a\u8fc7iptables\u89c4\u5219\uff0c\u5c06\u8fd9\u4e2a\u865a\u62dfIP\u5730\u5740\u6620\u5c04\u5230\u4e00\u4e2a\u6216\u591a\u4e2a\u540e\u7aefPod\u7684IP\u5730\u5740\uff0c\u4ee5\u4fbf\u5728\u9700\u8981\u65f6\u5c06\u6d41\u91cf\u8def\u7531\u5230\u8fd9\u4e9bPod\u3002 \u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e2d\uff0c br_netfilter \u6a21\u5757\u8d1f\u8d23\u76d1\u89c6\u670d\u52a1\u7684\u6d41\u91cf\uff0c\u5e76\u6839\u636eiptables\u89c4\u5219\u8fdb\u884c\u8f6c\u53d1\u548c\u8d1f\u8f7d\u5747\u8861\u3002\u8fd9\u5305\u62ec\u8fc7\u6ee4\u6765\u81ea\u4e0d\u53d7\u4fe1\u4efb\u6e90\u7684\u6d41\u91cf\u4ee5\u53ca\u9650\u5236\u670d\u52a1\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u4e3a\u4e86\u542f\u7528Kubernetes\u670d\u52a1\u7684\u6d41\u91cf\u8f6c\u53d1\u548c\u8d1f\u8f7d\u5747\u8861\uff0c br_netfilter \u6a21\u5757\u5fc5\u987b\u5728\u6240\u6709\u8282\u70b9\u4e0a\u542f\u7528\uff0c\u5e76\u4e14\u5fc5\u987b\u914d\u7f6e\u6b63\u786e\u7684iptables\u89c4\u5219\u3002 \u7531\u4e8e br_netfilter \u6a21\u5757\u7684\u4f5c\u7528\u975e\u5e38\u5173\u952e\uff0c\u56e0\u6b64\u5728\u5347\u7ea7\u6216\u66f4\u6539\u7cfb\u7edf\u65f6\u9700\u8981\u7279\u522b\u6ce8\u610f\u5b83\u7684\u914d\u7f6e\u548c\u72b6\u6001\u3002 \u4e0b\u9762\u547d\u4ee4\u5c06\u6a21\u5757 overlay \u548c br_netfilter \u6dfb\u52a0\u5230\u914d\u7f6e\u6587\u4ef6 containerd.conf \u4e2d\u3002 cat < /etc/apt/sources.list << EOF deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multivers deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe # deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse # deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse EOF \u5b89\u88c5Containered\u3002 sudo apt-get update && sudo apt-get install -y containerd \u914d\u7f6eContainerd\u3002\u4fee\u6539\u6587\u4ef6 /etc/containerd/config.toml \u3002 sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml \u4fee\u6539\u53c2\u6570 sandbox_image \u7684\u503c\u4e3a \"registry.aliyuncs.com/google_containers/pause:3.6\" \u3002 \u4fee\u6539\u53c2\u6570 SystemdCgroup \u7684\u503c\u4e3a true \u3002 [plugins] [plugins.\"io.containerd.gc.v1.scheduler\"] [plugins.\"io.containerd.grpc.v1.cri\"] sandbox_image = \"registry.aliyuncs.com/google_containers/pause:3.6\" [plugins.\"io.containerd.grpc.v1.cri\".cni] [plugins.\"io.containerd.grpc.v1.cri\".containerd] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime.options] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc.options] SystemdCgroup = true \u91cd\u542fContainerd\u670d\u52a1\u3002 sudo systemctl restart containerd sudo systemctl status containerd \u5b89\u88c5nerdctl \u00b6 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b89\u88c5nerdctl\u670d\u52a1\u3002 nerdctl \u670d\u52a1\u652f\u6301Contanerd\u6240\u63d0\u4f9b\u7684\u5bb9\u5668\u5316\u7279\u6027\uff0c\u7279\u522b\u662f\u4e00\u4e9bDocker\u4e0d\u5177\u5907\u7684\u65b0\u7279\u6027\u3002 \u4e8c\u8fdb\u5236\u5b89\u88c5\u5305\u53ef\u4ee5\u901a\u8fc7\u8fd9\u4e2a\u94fe\u63a5\u53d6\u5f97: Releases \u00b7 containerd/nerdctl \u00b7 GitHub \u3002 wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-0.22.2-linux-amd64.tar.gz tar -zxvf nerdctl-0.22.2-linux-amd64.tar.gz sudo cp nerdctl /usr/bin/ \u9a8c\u8bc1 nerdctl \u670d\u52a1\u3002 sudo nerdctl --help \u5217\u51fa\u521d\u59cb\u5b89\u88c5Kubernetes\u65f6\u7684\u5bb9\u5668container\u5217\u8868\u3002 nerdctl -n k8s.io ps \u5b89\u88c5kubeadm \u00b6 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b89\u88c5Kubeadm\uff0ckubectl\uff0ckubelet\u3002 \u5b89\u88c5\u548c\u5347\u7ea7Ubuntu\u7cfb\u7edf\u4f9d\u8d56\u5305 apt-transport-https , ca-certificates , curl \u3002 sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl \u5b89\u88c5gpg\u8bc1\u4e66\u3002 curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - \u6dfb\u52a0Kubernetes\u5b89\u88c5\u6e90\u3002 cat << EOF > /etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF \u5b89\u88c5\u548c\u5347\u7ea7Ubuntu\u7cfb\u7edf\u4f9d\u8d56\u5305\u3002 sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables \u68c0\u67e5\u5f53\u524d\u53ef\u7528\u7684 kubeadm \u7248\u672c\u3002 apt policy kubeadm \u5f53\u524d\u5b89\u88c5 1.24.0-00 \u7248\u672c\u7684 kubeadm \uff0c\u540e\u7eed\u4f1a\u5347\u7ea7\u5230 1.24.2 \u7248\u672c\u3002 sudo apt-get -y install kubelet = 1 .24.0-00 kubeadm = 1 .24.0-00 kubectl = 1 .24.0-00 --allow-downgrades \u914d\u7f6e\u4e3b\u8282\u70b9 \u00b6 kubeadm\u521d\u59cb\u5316 \u00b6 \u5728\u627f\u62c5\u4e3b\u8282\u70b9\u7684\u865a\u62df\u673a\u91cc\u914d\u7f6e\u63a7\u5236\u5e73\u9762\uff08Control Plane\uff09\u3002 \u68c0\u67e5 kubeadm \u5f53\u524d\u9ed8\u8ba4\u914d\u7f6e\u53c2\u6570\u3002 kubeadm config print init-defaults \u7c7b\u4f3c\u7ed3\u679c\u5982\u4e0b\u3002\u4fdd\u5b58\u9ed8\u8ba4\u914d\u7f6e\u7684\u7ed3\u679c\uff0c\u540e\u7eed\u4f1a\u4f5c\u4e3a\u53c2\u8003\u3002 apiVersion : kubeadm.k8s.io/v1beta3 bootstrapTokens : - groups : - system:bootstrappers:kubeadm:default-node-token token : abcdef.0123456789abcdef ttl : 24h0m0s usages : - signing - authentication kind : InitConfiguration localAPIEndpoint : advertiseAddress : 1.2.3.4 bindPort : 6443 nodeRegistration : criSocket : unix:///var/run/containerd/containerd.sock imagePullPolicy : IfNotPresent name : node taints : null --- apiServer : timeoutForControlPlane : 4m0s apiVersion : kubeadm.k8s.io/v1beta3 certificatesDir : /etc/kubernetes/pki clusterName : kubernetes controllerManager : {} dns : {} etcd : local : dataDir : /var/lib/etcd imageRepository : k8s.gcr.io kind : ClusterConfiguration kubernetesVersion : 1.24.0 networking : dnsDomain : cluster.local serviceSubnet : 10.96.0.0/12 scheduler : {} \u6a21\u62df\u5b89\u88c5\u548c\u6b63\u5f0f\u5b89\u88c5\u3002 \u901a\u8fc7\u547d\u4ee4 kubeadm init \u8fdb\u884c\u4e3b\u8282\u70b9\u7684\u521d\u59cb\u5316\uff0c\u4e0b\u9762\u662f\u8fd9\u4e2a\u547d\u4ee4\u4e3b\u8981\u53c2\u6570\u7684\u8bf4\u660e\uff0c\u7279\u522b\u662f\u7f51\u7edc\u53c2\u6570\u7684\u4e09\u4e2a\u9009\u62e9\u3002 --pod-network-cidr : \u6307\u5b9apod\u4f7f\u7528\u7684IP\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u6307\u5b9a\u4e86\u8be5\u53c2\u6570\uff0c\u5219Control Plane\u4f1a\u81ea\u52a8\u8bb2\u6307\u5b9a\u7684CIDR\u5206\u914d\u7ed9\u6bcf\u4e2a\u8282\u70b9\u3002 IP\u5730\u5740\u6bb5 10.244.0.0/16 \u662fFlannel\u7f51\u7edc\u7ec4\u4ef6\u9ed8\u8ba4\u7684\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u9700\u8981\u4fee\u6539Flannel\u7684IP\u5730\u5740\u6bb5\uff0c\u9700\u8981\u5728\u8fd9\u91cc\u6307\u5b9a\uff0c\u4e14\u5728\u90e8\u7f72Flannel\u65f6\u4e5f\u8981\u4fdd\u6301\u4e00\u81f4\u7684IP\u6bb5\u3002 --apiserver-bind-port : API\u670d\u52a1\uff08API Server\uff09\u7684\u7aef\u53e3\uff0c\u9ed8\u8ba4\u65f66443\u3002 --service-cidr : \u6307\u5b9a\u670d\u52a1\uff08service\uff09\u7684IP\u5730\u5740\u6bb5\uff0c\u9ed8\u8ba4\u662f 10.96.0.0/12 \u3002 \u63d0\u793a\uff1a \u670d\u52a1VIPs\uff08service VIPs\uff09\uff0c\u4e5f\u79f0\u4f5c\u96c6\u7fa4IP\uff08Cluster IP\uff09\uff0c\u901a\u8fc7\u53c2\u6570 --service-cidr \u6307\u5b9a\u3002 podCIDR\uff0c\u4e5f\u79f0\u4e3aendpoint IP\uff0c\u901a\u8fc7\u53c2\u6570 --pod-network-cidr \u6307\u5b9a\u3002 \u67094\u79cd\u5178\u578b\u7684\u7f51\u7edc\u95ee\u9898\uff1a \u9ad8\u5ea6\u8026\u5408\u7684\u5bb9\u5668\u4e0e\u5bb9\u5668\u4e4b\u95f4\u7684\u901a\u4fe1\uff1a\u8fd9\u53ef\u4ee5\u901a\u8fc7Pod\uff08podCIDR\uff09\u548c\u672c\u5730\u4e3b\u673a\u901a\u4fe1\u6765\u89e3\u51b3\u3002 Pod\u5bf9Pod\u901a\u4fe1\uff08Pod-to-Pod\uff09\uff1a \u4e5f\u88ab\u79f0\u4e3a\u5bb9\u5668\u5bf9\u5bb9\u5668\u901a\u4fe1\uff08container-to-container\uff09\u3002 \u5728Flannel\u7f51\u7edc\u63d2\u4ef6\u4e2d\u7684\u793a\u4f8b\u6d41\u7a0b\u662f\uff1aPod \u2192 veth\u5bf9 \u2192 cni0 \u2192 flannel.1 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 flannel.1 \u2192 cni0 \u2192 veth\u5bf9 \u2192 Pod\u3002 Pod\u5bf9Service\u901a\u4fe1\uff08Pod-to-Service\uff09\uff1a \u6d41\u7a0b: Pod \u2192 \u5185\u6838 \u2192 Service iptables \u2192 Service \u2192 Pod iptables \u2192 Pod\u3002 \u5916\u90e8\u5bf9Service\u901a\u4fe1\uff08External-to-Service\uff09\uff1a \u8d1f\u8f7d\u5747\u8861\u5668: SLB \u2192 NodePort \u2192 Service \u2192 Pod\u3002 kube-proxy \u662f\u5bf9iptables\u8d1f\u8d23\uff0c\u4e0d\u662f\u7f51\u7edc\u6d41\u91cf\uff08traffic\uff09\u3002 kube-proxy \u662fKubernetes\u96c6\u7fa4\u4e2d\u7684\u4e00\u4e2a\u7ec4\u4ef6\uff0c\u8d1f\u8d23\u4e3aService\u63d0\u4f9b\u4ee3\u7406\u670d\u52a1\uff0c\u540c\u65f6\u4e5f\u662fKubernetes\u7f51\u7edc\u6a21\u578b\u4e2d\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\u4e4b\u4e00\u3002 kube-proxy \u4f1a\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u542f\u52a8\u4e00\u4e2a\u4ee3\u7406\u8fdb\u7a0b\uff0c\u901a\u8fc7\u76d1\u542cKubernetes API Server\u7684Service\u548cEndpoint\u7684\u53d8\u5316\u6765\u7ef4\u62a4\u4e00\u4e2a\u672c\u5730\u7684Service\u548cEndpoint\u7684\u7f13\u5b58\u3002\u5f53\u6709\u8bf7\u6c42\u5230\u8fbe\u67d0\u4e2aService\u65f6\uff0c kube-proxy \u4f1a\u6839\u636e\u8be5Service\u7684\u7c7b\u578b\uff08ClusterIP\u3001NodePort\u3001LoadBalancer\u3001ExternalName\uff09\u548c\u7aef\u53e3\u53f7\uff0c\u751f\u6210\u76f8\u5e94\u7684iptables\u89c4\u5219\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u7ed9Service\u6240\u4ee3\u7406\u7684\u540e\u7aefPod\u3002 iptables\u662fLinux\u7cfb\u7edf\u4e2d\u7684\u4e00\u4e2a\u91cd\u8981\u7f51\u7edc\u5de5\u5177\uff0c\u53ef\u4ee5\u8bbe\u7f6eIP\u5305\u7684\u8fc7\u6ee4\u3001\u8f6c\u53d1\u548c\u4fee\u6539\u89c4\u5219\uff0c\u53ef\u4ee5\u5b9e\u73b0\u7f51\u7edc\u5c42\u7684\u9632\u706b\u5899\u3001NAT\u7b49\u529f\u80fd\u3002\u5728Kubernetes\u96c6\u7fa4\u4e2d\uff0c kube-proxy \u901a\u8fc7\u751f\u6210\u548c\u66f4\u65b0iptables\u89c4\u5219\uff0c\u6765\u5b9e\u73b0Service\u548cEndpoint\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u5177\u4f53\u6765\u8bf4\uff0ckube-proxy\u4f1a\u4e3a\u6bcf\u4e2aService\u521b\u5efa\u4e09\u6761iptables\u89c4\u5219\u94fe\uff08nat\u8868\u4e2d\u7684KUBE-SERVICES\u548cKUBE-NODEPORTS\u94fe\uff0c\u4ee5\u53cafilter\u8868\u4e2d\u7684KUBE-SVC-XXXXX\u94fe\uff09\uff0c\u901a\u8fc7\u8fd9\u4e9b\u89c4\u5219\u94fe\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u76f8\u5e94\u7684Pod\u6216\u8005Service\u4e0a\u3002 \u56e0\u6b64\uff0c kube-proxy \u548ciptables\u662f\u7d27\u5bc6\u76f8\u5173\u7684\u4e24\u4e2a\u7ec4\u4ef6\uff0c\u901a\u8fc7iptables\u89c4\u5219\u6765\u5b9e\u73b0Service\u548cPod\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u8fd9\u79cd\u5b9e\u73b0\u65b9\u5f0f\u5177\u6709\u53ef\u6269\u5c55\u6027\u548c\u9ad8\u53ef\u7528\u6027\uff0c\u540c\u65f6\u4e5f\u63d0\u4f9b\u4e86\u4e00\u79cd\u7075\u6d3b\u7684\u7f51\u7edc\u6a21\u578b\uff0c\u53ef\u4ee5\u65b9\u4fbf\u5730\u5b9e\u73b0\u670d\u52a1\u53d1\u73b0\u3001\u8d1f\u8f7d\u5747\u8861\u7b49\u529f\u80fd\u3002 sudo kubeadm init \\ --dry-run \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --kubernetes-version = v1.24.0 kubeconfig\u6587\u4ef6 \u00b6 \u7ed9\u5f53\u524d\u5b89\u88c5\u7528\u6237\u914d\u7f6e kubeconfig \u6587\u4ef6\uff08\u5f53\u524d\u4f8b\u5b50\u662f\u7528\u6237 vagrant \uff09\u3002 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Kubernetes \u63d0\u4f9b\u4e86\u4e00\u4e2a\u547d\u4ee4\u884c\u5de5\u5177 kubectl \uff0c\u7528\u4e8e\u4f7f\u7528 Kubernetes API \u4e0e Kubernetes \u96c6\u7fa4\u7684\u63a7\u5236\u5e73\u9762\u8fdb\u884c\u901a\u4fe1\u3002 kubectl \u63a7\u5236 Kubernetes cluster manager \uff08\u96c6\u7fa4\u7ba1\u7406\u5668\uff09\u3002 \u5bf9\u4e8e\u914d\u7f6e\uff0ckubectl \u5728 $HOME/.kube \u76ee\u5f55\u4e2d\u67e5\u627e\u4e00\u4e2a\u540d\u4e3a config \u7684\u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u662f\u7531 kubeadm init \u751f\u6210\u7684\u6587\u4ef6 /etc/kubernetes/admin.conf \u7684\u526f\u672c\u3002 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e KUBECONFIG \u73af\u5883\u53d8\u91cf\u6216\u8bbe\u7f6e --kubeconfig flag \u6807\u5fd7\u6765\u6307\u5b9a\u5176\u4ed6 kubeconfig \u6587\u4ef6\u3002\u5982\u679c KUBECONFIG \u73af\u5883\u53d8\u91cf\u4e0d\u5b58\u5728\uff0ckubectl \u5c06\u4f7f\u7528\u9ed8\u8ba4\u7684 kubeconfig \u6587\u4ef6 $HOME/.kube/config \u3002 kubeconfig \u6587\u4ef6\u4e2d\u7684 context\uff08\u4e0a\u4e0b\u6587\uff09 \u5143\u7d20\u7528\u4e8e\u5c06\u8bbf\u95ee\u53c2\u6570\u5206\u7ec4\u5230\u4e00\u4e2a\u65b9\u4fbf\u7684\u540d\u79f0\u4e0b\u3002\u6bcf\u4e2a\u4e0a\u4e0b\u6587\u90fd\u6709\u4e09\u4e2a\u53c2\u6570\uff1a\u96c6\u7fa4\u3001\u547d\u540d\u7a7a\u95f4\u548c\u7528\u6237\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0ckubectl \u547d\u4ee4\u884c\u5de5\u5177\u4f7f\u7528\u5f53\u524d\u4e0a\u4e0b\u6587\u4e2d\u7684\u53c2\u6570\u4e0e\u96c6\u7fa4\u901a\u4fe1\u3002 \u6587\u4ef6 .kube/config \u7684\u4f8b\u5b50\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : \u8bfb\u53d6\u5f53\u524d\u4e0a\u4e0b\u6587\uff1a kubectl config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin \u914d\u7f6e\u5de5\u4f5c\u8282\u70b9 \u00b6 \u4f7f\u7528 kubeadm token \u6765\u751f\u6210\u52a0\u5165\u96c6\u7fa4\u7684\u4ee4\u724c\uff08token\uff09\u548c\u54c8\u897f\u503c\uff08hash value\uff09\u3002 kubeadm token create --print-join-command \u5728\u6240\u6709\u5de5\u4f5c\u8282\u70b9\u4e0a\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u5c06\u5de5\u4f5c\u8282\u70b9\u52a0\u5165Kubernetes\u96c6\u7fa4\u3002 # kubeadm join :6443 --token --discovery-token-ca-cert-hash \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u68c0\u67e5\u6240\u6709\u8282\u70b9\u7684\u72b6\u6001\u3002 \u5f53\u524d\u6240\u6709\u8282\u70b9\u7684\u72b6\u6001\u90fd\u662f NotReady \u3002\u76ee\u524d\u4e0d\u9700\u8981\u505a\u4ec0\u4e48\uff0c\u540e\u9762\u6211\u4eec\u4f1a\u5b89\u88c5\u76f8\u5173\u7684\u7f51\u7edc\u670d\u52a1\uff08Calico \u6216 Flannel\uff09\uff0c\u5404\u8282\u70b9\u7684\u72b6\u6001\u5c31\u4f1a\u53d8\u6210Ready\u72b6\u6001\u3002 \u5b89\u88c5Calico\u6216Flannel \u00b6 \u5728\u63a7\u5236\u5e73\u9762Control Plane\u4e0a\u5b89\u88c5Calico\u6216\u8005Flannel\u3002\u5982\u679c\u9700\u8981\u914d\u7f6e\u7f51\u7edc\u7b56\u7565\uff0c\u5219\u9009\u62e9Calico\u3002 \u5b89\u88c5Flannel \u00b6 Flannel \u662f\u4e3a Kubernetes \u8bbe\u8ba1\u7684\u4e00\u79cd\u7b80\u5355\u6613\u7528\u7684\u914d\u7f6e\u4e09\u5c42\u7f51\u7edc\u7684\u65b9\u6cd5\u3002 \u90e8\u7f72Flannel\uff1a \u5728 kube-flannel.yml \u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u83b7\u53d6 Flannel \u7684\u9ed8\u8ba4\u7f51\u7edc\u8bbe\u7f6e\uff0c\u5b83\u4e0e\u6211\u4eec\u5728\u4f7f\u7528 kubeadm \u521d\u59cb\u5316\u96c6\u7fa4\u65f6\u6307\u5b9a\u7684\u53c2\u6570 --pod-network-cidr=10.244.0.0/16 \u76f8\u540c\u3002 net - co nf .jso n : | { \"Network\" : \"10.244.0.0/16\" , \"Backend\" : { \"Type\" : \"vxlan\" } } \u521b\u5efaFlannel\u670d\u52a1\u3002 apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml \u8f93\u51fa\u7ed3\u679c\uff1a Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy/psp.flannel.unprivileged created clusterrole.rbac.authorization.k8s.io/flannel created clusterrolebinding.rbac.authorization.k8s.io/flannel created serviceaccount/flannel created configmap/kube-flannel-cfg created daemonset.apps/kube-flannel-ds created \u5b89\u88c5Calico \u00b6 \u5b89\u88c5\u6307\u5bfc\u624b\u518c\uff1a End-to-end Calico installation \u3002 \u4e0b\u8f7d\u5e76\u5b89\u88c5Calico\u670d\u52a1\u3002 curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml \u8f93\u51fa\u7ed3\u679c\uff1a configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created \u9a8c\u8bc1Calico\u670d\u52a1\u72b6\u6001\uff1a kubectl get pod -n kube-system | grep calico \u8f93\u51fa\u7ed3\u679c\uff1a calico-kube-controllers-555bc4b957-l8bn2 0 /1 Pending 0 28s calico-node-255pc 0 /1 Init:1/3 0 29s calico-node-7tmnb 0 /1 Init:1/3 0 29s calico-node-w8nvl 0 /1 Init:1/3 0 29s \u68c0\u67e5\u96c6\u7fa4\u7684\u7f51\u7edc\u72b6\u6001\uff1a sudo nerdctl network ls \u8f93\u51fa\u7ed3\u679c\uff1a NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none \u68c0\u67e5\u96c6\u7fa4\u72b6\u6001 \u00b6 \u5728\u4e3b\u8282\u70b9\u4e0a\u6267\u884c\u547d\u4ee4 kubectl cluster-info \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff1a \u63a7\u5236\u5e73\u9762\uff08control plane\uff09\u8fd0\u884c\u5728 https://:6443 CoreDNS\u670d\u52a1\u8fd0\u884c\u5728 https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy kubectl cluster-info \u67e5\u770b\u8282\u70b9\u8fd0\u884c\u72b6\u6001\u3002\u6b64\u65f6\uff0c\u6240\u6709\u8282\u70b9\u90fd\u662f Ready \u7684\u6b63\u5e38\u72b6\u6001\u4e86\u3002 OS Image: Ubuntu 20.04.4 LTS Kernel Version: 5.4.0-122-generic Container Runtime: containerd://1.5.9 kubectl get nodes -owide \u8f93\u51fa\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane 13m v1.24.0 cka002 Ready 8m35s v1.24.0 cka003 Ready 8m26s v1.24.0 \u67e5\u770bPods\u7684\u72b6\u6001\u3002 kubectl get pod -A \u8f93\u51fa\u7ed3\u679c\uff1a NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 7m18s kube-system calico-node-255pc 1/1 Running 0 7m19s kube-system calico-node-7tmnb 1/1 Running 0 7m19s kube-system calico-node-w8nvl 1/1 Running 0 7m19s kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15m kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15m kube-system etcd-cka001 1/1 Running 0 15m kube-system kube-apiserver-cka001 1/1 Running 0 15m kube-system kube-controller-manager-cka001 1/1 Running 0 15m kube-system kube-proxy-dmj2t 1/1 Running 0 15m kube-system kube-proxy-n77zw 1/1 Running 0 11m kube-system kube-proxy-qs6rf 1/1 Running 0 11m kube-system kube-scheduler-cka001 1/1 Running 0 15m \u66f4\u65b0\u5b89\u88c5 \u00b6 Bash\u81ea\u52a8\u8865\u5168 \u00b6 \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u914d\u7f6eBash\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 \u53c2\u8003 \u6307\u5bfc \u8bbe\u7f6e kubectl \u81ea\u52a8\u8865\u5168\u529f\u80fdauto-completion \u3002 apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc source ~/.bashrc \u522b\u540d \u00b6 \u5982\u679c\u6211\u4eec\u4e3a kubectl \u8bbe\u7f6e\u4e00\u4e2a\u522b\u540d\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u4e00\u4e9b\u65b9\u6cd5\u6765\u6269\u5c55 shell \u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u4f7f\u5176\u80fd\u591f\u4e0e\u8be5\u522b\u540d\u4e00\u8d77\u4f7f\u7528\u3002 \u4e00\u79cd\u65b9\u6cd5\u662f\u5728 Bash shell \u914d\u7f6e\u6587\u4ef6\uff08\u5982 .bashrc \u6216 .bash_profile\uff09\u4e2d\u8bbe\u7f6e\u522b\u540d\uff0c\u5e76\u4e3a\u8be5\u522b\u540d\u6307\u5b9a kubectl \u7684\u5b8c\u6574\u8def\u5f84\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a alias k = 'path/to/kubectl' \u7136\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u91cd\u65b0\u52a0\u8f7d .bashrc \u6587\u4ef6\uff1a source ~/.bashrc \u63a5\u4e0b\u6765\uff0c\u53ef\u4ee5\u4f7f\u7528 k \u547d\u4ee4\u6765\u4ee3\u66ff kubectl \u547d\u4ee4\uff0c\u5e76\u5728\u5176\u540e\u9762\u6dfb\u52a0\u76f8\u5e94\u7684\u53c2\u6570\u548c\u9009\u9879\u3002\u5f53\u4f7f\u7528\u81ea\u52a8\u8865\u5168\u529f\u80fd\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u5c06 k \u522b\u540d\u8f6c\u6362\u4e3a kubectl \u7684\u5b8c\u6574\u8def\u5f84\uff0c\u5e76\u5bf9\u5176\u8fdb\u884c\u81ea\u52a8\u8865\u5168\u3002 \u53e6\u4e00\u79cd\u65b9\u6cd5\u662f\u4f7f\u7528 Bash shell \u5185\u7f6e\u7684 complete \u51fd\u6570\u6765\u4e3a\u522b\u540d\u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc \u8fd9\u5c06\u4e3a\u522b\u540d k \u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u5e76\u5c06\u5176\u4e0e kubectl \u7684\u81ea\u52a8\u8865\u5168\u51fd\u6570 __start_kubectl \u5173\u8054\u8d77\u6765\u3002\u8fd9\u6837\uff0c\u5f53\u7528\u6237\u5728 k \u547d\u4ee4\u540e\u8f93\u5165Tab\u952e\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u8c03\u7528 __start_kubectl \u51fd\u6570\uff0c\u5e76\u4e3a\u7528\u6237\u63d0\u4f9b\u76f8\u5e94\u7684\u81ea\u52a8\u8865\u5168\u5efa\u8bae\u3002 \u66f4\u65b0\u9ed8\u8ba4Context \u00b6 \u67e5\u770b\u5f53\u524d\u7684 context \u5217\u8868\uff1a kubectl config get-contexts \u8fd9\u4e2a\u547d\u4ee4\u4f1a\u5217\u51fa\u6240\u6709\u53ef\u7528\u7684 context \u5217\u8868\uff0c\u5e76\u6807\u8bb0\u51fa\u5f53\u524d\u6b63\u5728\u4f7f\u7528\u7684 context\u3002 \u7c7b\u4f3c\u4e0b\u9762\u7ed3\u679c\uff1a kubernetes-admin@kubernetes \u662fContext\u540d\u3002 kubernetes \u662f\u96c6\u7fa4\u540d\u3002 kubernetes-admin \u662f\u7528\u6237\u540d\u3002 \u5f53\u524d\u4f8b\u5b50\u4e2d\u6ca1\u6709\u6307\u5b9a\u540d\u79f0\u7a7a\u95f4\u3002 CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin \u66f4\u65b0context\u3002\u4f8b\u5982\uff0c\u66f4\u65b0context\u7684\u9ed8\u8ba4\u540d\u79f0\u7a7a\u95f4\u7b49\u3002 # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin \u5728\u4e0d\u540c\u7684context\u4e4b\u95f4\u5207\u6362\u3002 # Usage: kubectl config use-context # Switch to new context kubectl config use-context kubernetes-admin@kubernetes \u53c2\u8003\u8d44\u6599\uff1a kubectl [commandline \u91cd\u7f6e\u96c6\u7fa4 \u00b6 \u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u64cd\u4f5c\u4f1a\u91cd\u7f6e\u5f53\u524d\u96c6\u7fa4\uff08\u5220\u9664\u96c6\u7fa4\uff09\u3002 \u5220\u9664\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u3002 kubeadm reset \u6e05\u9664 iptables \u4e2d\u5df2\u5b9a\u4e49\u7684\u89c4\u5219\u3002 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u6e05\u9664 IPVS \u4e2d\u5b9a\u4e49\u7684\u89c4\u5219\uff08\u5982\u679c\u4f7f\u7528 IPVS \uff09\u3002 ipvsadm --clear \u6392\u9519 \u00b6 \u9519\u8bef1 \u00b6 \u62a5\u9519\u4fe1\u606f\uff1a The connection to the server :6443 was refused - did you specify the right host or port? \u89e3\u51b3\u5c1d\u8bd5\uff1a Reference \u68c0\u67e5\u6587\u4ef6kubeconfig\u7684\u5185\u5bb9\u548c\u6587\u4ef6\u8def\u5f84\u662f\u5426\u6b63\u786e\u3002 \u68c0\u67e5\u73af\u5883\u53d8\u91cf\u8bbe\u7f6e\u3002 env | grep -i kub \u68c0\u67e5\u5bb9\u5668\u8fd0\u884c\u72b6\u6001\u3002 sudo systemctl status containerd.service \u68c0\u67e5kubelet\u670d\u52a1\u3002 sudo systemctl status kubelet.service \u68c0\u67e5 6443 \u7aef\u53e3\u76d1\u542c\u72b6\u6001\u3002 netstat -pnlt | grep 6443 \u68c0\u67e5\u9632\u706b\u5899\u72b6\u6001\u3002 sudo systemctl status firewalld.service \u68c0\u67e5kubelet\u65e5\u5fd7\u3002 journalctl -xeu kubelet \u9519\u8bef2 \u00b6 \u62a5\u9519\u4fe1\u606f\uff1a \"Container runtime network not ready\" networkReady=\"NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized\" \u5c1d\u8bd5\u65b9\u6cd5\uff1a \u91cd\u542fContainerd\u670d\u52a1\u3002 sudo systemctl restart containerd sudo systemctl status containerd","title":"\u963f\u91cc\u4e91ECS\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#cka3ecskubernetes","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb03:\u963f\u91cc\u4e91ECS\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_1","text":"\u5728\u963f\u91cc\u4e91ECS\u88c5\u4e09\u53f0Ubuntu\u865a\u62df\u673a\u3002\u5728Ubuntu\u865a\u62df\u673a\u4e2d\u5b89\u88c5\u57fa\u4e8eContainerd\u7684Kubernetes\u7cfb\u7edf\uff0c\u5e76\u5206\u522b\u914d\u7f6e\u4e00\u4e2a\u4e3b\u8282\u70b9Master\u548c\u4e24\u4e2a\u5de5\u4f5c\u8282\u70b9Worker\uff0c\u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_2","text":"\u6ce8\u518c\u963f\u91cc\u4e91\u8d26\u53f7\uff1a Alibaba Cloud home console \u3002\u6ce8\u610f\u4fdd\u7559\u8bbf\u95ee\u5bc6\u94a5key\u6587\u4ef6\uff0c\u53ea\u80fd\u5bfc\u51fa\u4e00\u6b21\uff0c\u5f53\u524d\u7ec3\u4e60\u4e2dkey\u6587\u4ef6\u662f aliyun-root \u3002 \u53c2\u8003\u4e0b\u9762\u914d\u7f6e\u6ce8\u518c\u7533\u8bf7\u4e09\u4e2aECS\uff08Elastic Computer Service\uff09\u670d\u52a1\u5b9e\u4f8b\uff1a \u4e3b\u673a\uff1a2vCPU+4GiB \u64cd\u4f5c\u7cfb\u7edf\uff1aUbuntu 20.04 x86_64 \u5b9e\u4f8b\u7c7b\u578b\uff1aecs.sn1.medium \u5b9e\u4f8b\u540d\u79f0\uff1acka001, cka002, cka003 \u7f51\u7edc\u914d\u7f6e\uff1aboth public IPs and private IPs \u6700\u5927\u7f51\u7edc\u5e26\u5bbd\uff1a100Mbps (Peak Value) \u4e91\u76d8\uff1a40GiB \u652f\u4ed8\u65b9\u5f0f\uff1a\u62a2\u5360\u5f0f\u5b9e\u4f8b \u5728\u672c\u5730\u6253\u5f00\u7ec8\u7aef\u7a97\u53e3\uff0c\u901a\u8fc7\u5bc6\u94a5\u6587\u4ef6 aliyun-root \u8bbf\u95ee\u8fdc\u7a0bECS\u8282\u70b9 cka001 \u3002 ssh -i aliyun-root root@cka001 \u521b\u5efa\u4e00\u4e2a\u666e\u901a\u7528\u6237\uff0c\u7528\u6765\u5b89\u88c5Kubernetes\uff0c\u5f53\u524d\u7ec3\u4e60\u4e2d\u521b\u5efa\u7528\u6237 vagrant \uff0c\u4e14\u4fee\u6539\u8be5\u7528\u6237\u7684\u4e3b\u8981\u7ec4\u4e3a sudo \u6b21\u8981\u7ec4\u5305\u542b root \u3002 adduser vagrant usermod -g sudo vagrant usermod -a -G root vagrant \u65b0\u5f00\u4e00\u4e2a\u672c\u5730\u7ec8\u7aef\u7a97\u53e3\uff0c\u4e3a\u7528\u6237 vagrant \u521b\u5efa\u5bc6\u94a5key\u3002 # Windows ssh-keygen.exe # Linux ssh-keygen \u4e0a\u9762\u7684\u547d\u4ee4\u4f1a\u751f\u62102\u4e2a\u6587\u4ef6\uff0c\u5f53\u524d\u7ec3\u4e60\u4e2d\u8fd92\u4e2a\u6587\u4ef6\u662f aliyun-vagrant and aliyun-vagrant.pub \u901a\u8fc7 sftp \u547d\u4ee4\u5c06\u516c\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u4e0a\u4f20\u5230\u8fdc\u7a0b\u8282\u70b9 cka001 \u3002 sftp -i aliyun-root root@cka001 put aliyun-vagrant.pub \u65b0\u5f00\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\uff0c\u7528 root \u7684\u5bc6\u94a5\u767b\u5f55 cka001 \u8282\u70b9\u3002 \u5c06\u4e0a\u4e00\u6b65\u4e0a\u4f20\u7684\u5bc6\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u4ece /root \u76ee\u5f55\u62f7\u8d1d\u5230 /home/vagrant/.ssh/ \u3002 \u5c06\u516c\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u91cd\u547d\u540d\u4e3a authorized_keys \u3002 \u66f4\u6539\u6587\u4ef6 authorized_keys \u7684\u6240\u6709\u8005owner\u4e3a vagrant . \u66f4\u6539\u6587\u4ef6 authorized_keys \u7684\u4e3b\u8981\u7ec4\u4e3a sudo \u3002 mkdir /home/vagrant/.ssh/ mv aliyun-james.pub /home/vagrant/.ssh/authorized_keys chown vagrant.sudo /home/vagrant/.ssh/authorized_keys chmod 600 /home/vagrant/.ssh/authorized_keys \u68c0\u67e5\u6587\u4ef6 /etc/ssh/sshd_config \uff0c\u786e\u5b9a\u5bc6\u7801\u767b\u5f55\u9a8c\u8bc1\u53c2\u6570 asswordAuthentication \u8bbe\u5b9a\u4e3a no \uff0c\u5373\u53ea\u80fd\u901a\u8fc7\u8bc1\u4e66\u8fdc\u7a0b\u767b\u5f55\u3002 cat /etc/ssh/sshd_config \u65b0\u5f00\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\uff0c\u4f7f\u7528\u7528\u6237vagrant\u767b\u5f55\u8fdc\u7a0b\u8282\u70b9 cka001 \uff0c\u9a8c\u8bc1\u7528\u6237 vagrant \u80fd\u901a\u8fc7\u524d\u9762\u521b\u5efa\u7684\u8bc1\u4e66\u767b\u5f55\u8282\u70b9 cka001 \u3002 ssh -i aliyun-vagrant vagrant@cka001 \u91cd\u590d\u4e0a\u8ff0\u6b65\u9aa4\uff0c\u901a\u8fc7 sftp \u547d\u4ee4\u5c06\u516c\u94a5\u6587\u4ef6 aliyun-vagrant.pub \u5206\u522b\u4e0a\u4f20\u5230\u8fdc\u7a0b\u8282\u70b9 cka002 \u548c cka003 \uff0c\u4e14\u5b8c\u6210\u540c\u6837\u7684\u914d\u7f6e\uff0c\u4f7f\u7528\u6237 vagrant \u4e5f\u80fd\u901a\u8fc7\u5bc6\u94a5\u6587\u4ef6\u767b\u5f55\u8fdc\u7a0b\u8282\u70b9 cka002 \u548c cka003 \u3002 \u81f3\u6b64\uff0c\u7528\u6237 vagrant \u53ef\u4ee5\u901a\u8fc7\u5bc6\u94a5\u6587\u4ef6 aliyun-vagrant \u4ece\u672c\u5730\u7ec8\u7aef\u7a97\u53e3\u767b\u5f55\u8fdc\u7a0b\u8282\u70b9 cka001 , cka002 \u548c cka003 \u3002 \u4e0b\u9762\u6240\u6709\u6b65\u9aa4\u90fd\u662f\u901a\u8fc7\u7528\u6237 vagrant \u5b8c\u6210\u3002","title":"\u51c6\u5907\u5de5\u4f5c"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#ecs","text":"","title":"\u521d\u59cb\u5316ECS\u8282\u70b9"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#etchosts","text":"\u66f4\u65b0\u6240\u6709ECS\u8282\u70b9\u7684\u6587\u4ef6/etc/hosts\uff0c\u6dfb\u52a0\u5176\u4ed6\u8282\u70b9\u7684\u79c1\u6709IP\uff08private IP\uff09\u3002 vi /etc/hosts","title":"\u914d\u7f6e\u6587\u4ef6/etc/hosts"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#firewall","text":"\u5728\u6240\u6709\u8282\u70b9\u4e0a\u7981\u7528\u9632\u706b\u5899\u3002 sudo ufw disable \u68c0\u67e5\u9632\u706b\u5899\u72b6\u6001\u3002 sudo ufw status verbose","title":"\u7981\u7528firewall"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#swap","text":"\u5728\u6240\u6709\u8282\u70b9\u4e0a\u5173\u95edswap\u3002 sudo swapoff -a","title":"\u5173\u95edswap"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_3","text":"\u5728\u6240\u6709\u8282\u70b9\u8bbe\u5b9a\u65f6\u533a\u548c\u5730\u57df\u3002\u8fd9\u4e00\u5e03\u5728\u521d\u59cb\u5316ECS\u65f6\u5019\u5df2\u7ecf\u5b8c\u6210\u3002\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u8fdb\u884c\u8bbe\u5b9a\u3002 ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile \u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u68c0\u67e5\u65f6\u533a\u548c\u5730\u57df\u7684\u8bbe\u7f6e\u3002 ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 5 14:51 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai","title":"\u8bbe\u7f6e\u65f6\u533a\u548c\u5730\u57df"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_4","text":"\u5728\u6240\u6709\u8282\u70b9\u4e0a\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u4ee5\u914d\u7f6e\u5185\u6838\u3002 \u4f7f\u7528\u6a21\u5757overlay\uff1a \u521b\u5efaContainerd\u670d\u52a1\u914d\u7f6e\u6587\u4ef6 /etc/modules-load.d/containerd.conf \uff0c\u5982\u679c\u5df2\u5b58\u5728\u5219\u8df3\u8fc7\u8fd9\u4e00\u6b65\u3002\u914d\u7f6e\u8fd9\u4e2a\u6587\u4ef6\u7684\u76ee\u7684\u662f\u4e3a\u4e86\u52a0\u8f7d\u6a21\u5757 overlay \u548c br_netfilter \u5230\u5185\u6838\u4e2d\u3002 \u670d\u52a1Containerd\u4f9d\u8d56\u6a21\u5757 overlay \u5b9e\u73b0 overlay-filesystem \u6587\u4ef6\u7cfb\u7edf\u529f\u80fd\u3002 Linux\u4e2d\u7684overlay\u6a21\u5757\u63d0\u4f9b\u4e86\u521b\u5efa\u4e24\u4e2a\u76ee\u5f55\u7684\u5408\u5e76\u89c6\u56fe\u7684\u80fd\u529b\uff0c\u8fd9\u4e24\u4e2a\u76ee\u5f55\u79f0\u4e3a\u5c42\u3002\u5b83\u7ecf\u5e38\u88ab\u7528\u4e8e\u5b9e\u73b0\u8054\u5408\u6302\u8f7d\uff0c\u8fd9\u662f\u4e00\u79cd\u5c06\u4e24\u4e2a\u6216\u66f4\u591a\u76ee\u5f55\u4e00\u8d77\u6302\u8f7d\u7684\u65b9\u5f0f\uff0c\u5c31\u50cf\u5b83\u4eec\u662f\u4e00\u4e2a\u76ee\u5f55\u4e00\u6837\uff08union-filesystems\uff09\u3002 overlay\u6a21\u5757\u5728\u5bb9\u5668\u6280\u672f\u4e2d\u88ab\u5e7f\u6cdb\u4f7f\u7528\uff0c\u6bd4\u5982Docker\uff0c\u56e0\u4e3a\u5b83\u5141\u8bb8\u591a\u4e2a\u5bb9\u5668\u5171\u4eab\u57fa\u7840\u955c\u50cf\uff0c\u540c\u65f6\u4fdd\u6301\u5b83\u4eec\u81ea\u5df1\u7684\u6587\u4ef6\u7cfb\u7edf\u3002 \u8981\u4f7f\u7528overlay\u6a21\u5757\uff0c\u9700\u8981\u4e24\u4e2a\u76ee\u5f55\uff1a\u8f83\u4f4e\u7684\u76ee\u5f55\uff08lower directory\uff09\u548c\u8f83\u9ad8\u7684\u76ee\u5f55\uff08upper directory\uff09\u3002\u8f83\u4f4e\u7684\u76ee\u5f55\u901a\u5e38\u662f\u53ea\u8bfb\u7684\uff0c\u5305\u542b\u539f\u59cb\u6587\u4ef6\uff0c\u800c\u8f83\u9ad8\u7684\u76ee\u5f55\u662f\u53ef\u8bfb\u5199\u7684\uff0c\u5305\u542b\u5bf9\u6587\u4ef6\u7684\u66f4\u6539\u3002\u5f53\u8bf7\u6c42\u6587\u4ef6\u65f6\uff0coverlay\u6a21\u5757\u9996\u5148\u67e5\u627e\u4e0a\u5c42\u76ee\u5f55\uff0c\u5982\u679c\u672a\u627e\u5230\uff0c\u5219\u67e5\u627e\u4e0b\u5c42\u76ee\u5f55\u3002 \u6bd4\u5982\uff1a \u521b\u5efa\u4e24\u4e2a\u76ee\u5f55\uff0c\u4e00\u4e2a\u7528\u4e8e\u8f83\u4f4e\u7684\u76ee\u5f55\uff0c\u4e00\u4e2a\u7528\u4e8e\u8f83\u9ad8\u7684\u76ee\u5f55\u3002\u7136\u540e\u4f7f\u7528overlay\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u5c06\u5b83\u4eec\u6302\u8f7d\u8d77\u6765\uff1a sudo mkdir /lower sudo mkdir /upper sudo mount -t overlay overlay -o lowerdir = /lower,upperdir = /upper /merged \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c\u4e24\u4e2a\u76ee\u5f55\u7684\u5408\u5e76\u89c6\u56fe\u88ab\u521b\u5efa\u5728 /merged \u76ee\u5f55\u4e2d\u3002\u5728 /merged \u76ee\u5f55\u4e2d\u5bf9\u6587\u4ef6\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u5b58\u50a8\u5728\u4e0a\u5c42\u76ee\u5f55\u4e2d\uff0c\u800c\u539f\u59cb\u6587\u4ef6\u4ecd\u7136\u5728\u4e0b\u5c42\u76ee\u5f55\u4e2d\u3002 \u4f7f\u7528\u6a21\u5757br_netfilter\uff1a br_netfilter \u662fLinux\u5185\u6838\u4e2d\u7684\u4e00\u4e2a\u6a21\u5757\uff0c\u5b83\u63d0\u4f9b\u4e86\u4e00\u79cd\u673a\u5236\u6765\u8fc7\u6ee4\u7f51\u6865\u7684\u7f51\u7edc\u6d41\u91cf\u3002\u8be5\u6a21\u5757\u5141\u8bb8\u7ba1\u7406\u5458\u914d\u7f6e\u89c4\u5219\uff0c\u4ee5\u5141\u8bb8\u6216\u62d2\u7edd\u7279\u5b9a\u7684\u7f51\u7edc\u6d41\u91cf\u901a\u8fc7\u7f51\u6865\u3002 \u7f51\u6865\u662f\u4e00\u79cd\u7f51\u7edc\u8bbe\u5907\uff0c\u5b83\u53ef\u4ee5\u8fde\u63a5\u591a\u4e2a\u7f51\u7edc\u6bb5\uff0c\u5e76\u8f6c\u53d1\u6d41\u91cf\u4ee5\u4f7f\u4e0d\u540c\u7684\u7f51\u7edc\u6bb5\u4e4b\u95f4\u901a\u4fe1\u3002 br_netfilter \u6a21\u5757\u53ef\u4ee5\u7528\u6765\u9650\u5236\u6216\u8fc7\u6ee4\u8fd9\u4e9b\u6d41\u91cf\u3002 \u5f53\u542f\u7528\u4e86 br_netfilter \u6a21\u5757\u65f6\uff0c\u5b83\u4f1a\u81ea\u52a8\u542f\u7528\u4e00\u4e2a\u79f0\u4e3a bridge-nf \u7684\u529f\u80fd\uff0c\u8be5\u529f\u80fd\u5c06\u5728\u7f51\u7edc\u6d41\u91cf\u901a\u8fc7\u7f51\u6865\u65f6\u5e94\u7528\u89c4\u5219\u3002\u7ba1\u7406\u5458\u53ef\u4ee5\u4f7f\u7528iptables\u7b49\u5de5\u5177\u6765\u914d\u7f6e\u8fd9\u4e9b\u89c4\u5219\u3002\u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u8bbe\u5b9a\u5141\u8bb8\u4ece\u4e00\u4e2a\u7f51\u7edc\u6bb5\u5230\u53e6\u4e00\u4e2a\u7f51\u7edc\u6bb5\u7684\u6d41\u91cf\uff0c\u6216\u8005\u62d2\u7edd\u6765\u81ea\u7279\u5b9aIP\u5730\u5740\u6216\u7aef\u53e3\u7684\u6d41\u91cf\u3002 \u5728Kubernetes\u4e2d\uff0c br_netfilter \u6a21\u5757\u4e3b\u8981\u7528\u4e8e\u542f\u7528Kubernetes\u670d\u52a1\u7684\u6d41\u91cf\u8f6c\u53d1\u548c\u8d1f\u8f7d\u5747\u8861\u3002\u8fd9\u4e9b\u670d\u52a1\u4f7f\u7528\u4e86Linux\u5185\u6838\u4e2d\u7684iptables\u89c4\u5219\u6765\u7ba1\u7406\u6d41\u91cf\uff0c\u8fd9\u4e9b\u89c4\u5219\u662f\u901a\u8fc7 br_netfilter \u6a21\u5757\u5b9e\u73b0\u7684\u3002 \u5177\u4f53\u6765\u8bf4\uff0c\u5f53\u6211\u4eec\u5728Kubernetes\u96c6\u7fa4\u4e2d\u521b\u5efa\u4e00\u4e2a\u670d\u52a1\u65f6\uff0c\u8be5\u670d\u52a1\u5c06\u5206\u914d\u4e00\u4e2a\u865a\u62dfIP\u5730\u5740\uff0c\u7528\u4e8e\u4ee3\u8868\u670d\u52a1\u3002\u7136\u540e\uff0c\u901a\u8fc7iptables\u89c4\u5219\uff0c\u5c06\u8fd9\u4e2a\u865a\u62dfIP\u5730\u5740\u6620\u5c04\u5230\u4e00\u4e2a\u6216\u591a\u4e2a\u540e\u7aefPod\u7684IP\u5730\u5740\uff0c\u4ee5\u4fbf\u5728\u9700\u8981\u65f6\u5c06\u6d41\u91cf\u8def\u7531\u5230\u8fd9\u4e9bPod\u3002 \u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e2d\uff0c br_netfilter \u6a21\u5757\u8d1f\u8d23\u76d1\u89c6\u670d\u52a1\u7684\u6d41\u91cf\uff0c\u5e76\u6839\u636eiptables\u89c4\u5219\u8fdb\u884c\u8f6c\u53d1\u548c\u8d1f\u8f7d\u5747\u8861\u3002\u8fd9\u5305\u62ec\u8fc7\u6ee4\u6765\u81ea\u4e0d\u53d7\u4fe1\u4efb\u6e90\u7684\u6d41\u91cf\u4ee5\u53ca\u9650\u5236\u670d\u52a1\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u4e3a\u4e86\u542f\u7528Kubernetes\u670d\u52a1\u7684\u6d41\u91cf\u8f6c\u53d1\u548c\u8d1f\u8f7d\u5747\u8861\uff0c br_netfilter \u6a21\u5757\u5fc5\u987b\u5728\u6240\u6709\u8282\u70b9\u4e0a\u542f\u7528\uff0c\u5e76\u4e14\u5fc5\u987b\u914d\u7f6e\u6b63\u786e\u7684iptables\u89c4\u5219\u3002 \u7531\u4e8e br_netfilter \u6a21\u5757\u7684\u4f5c\u7528\u975e\u5e38\u5173\u952e\uff0c\u56e0\u6b64\u5728\u5347\u7ea7\u6216\u66f4\u6539\u7cfb\u7edf\u65f6\u9700\u8981\u7279\u522b\u6ce8\u610f\u5b83\u7684\u914d\u7f6e\u548c\u72b6\u6001\u3002 \u4e0b\u9762\u547d\u4ee4\u5c06\u6a21\u5757 overlay \u548c br_netfilter \u6dfb\u52a0\u5230\u914d\u7f6e\u6587\u4ef6 containerd.conf \u4e2d\u3002 cat < /etc/apt/sources.list << EOF deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multivers deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe # deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse # deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse EOF \u5b89\u88c5Containered\u3002 sudo apt-get update && sudo apt-get install -y containerd \u914d\u7f6eContainerd\u3002\u4fee\u6539\u6587\u4ef6 /etc/containerd/config.toml \u3002 sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml \u4fee\u6539\u53c2\u6570 sandbox_image \u7684\u503c\u4e3a \"registry.aliyuncs.com/google_containers/pause:3.6\" \u3002 \u4fee\u6539\u53c2\u6570 SystemdCgroup \u7684\u503c\u4e3a true \u3002 [plugins] [plugins.\"io.containerd.gc.v1.scheduler\"] [plugins.\"io.containerd.grpc.v1.cri\"] sandbox_image = \"registry.aliyuncs.com/google_containers/pause:3.6\" [plugins.\"io.containerd.grpc.v1.cri\".cni] [plugins.\"io.containerd.grpc.v1.cri\".containerd] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime.options] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc.options] SystemdCgroup = true \u91cd\u542fContainerd\u670d\u52a1\u3002 sudo systemctl restart containerd sudo systemctl status containerd","title":"\u5b89\u88c5Containerd"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#nerdctl","text":"\u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b89\u88c5nerdctl\u670d\u52a1\u3002 nerdctl \u670d\u52a1\u652f\u6301Contanerd\u6240\u63d0\u4f9b\u7684\u5bb9\u5668\u5316\u7279\u6027\uff0c\u7279\u522b\u662f\u4e00\u4e9bDocker\u4e0d\u5177\u5907\u7684\u65b0\u7279\u6027\u3002 \u4e8c\u8fdb\u5236\u5b89\u88c5\u5305\u53ef\u4ee5\u901a\u8fc7\u8fd9\u4e2a\u94fe\u63a5\u53d6\u5f97: Releases \u00b7 containerd/nerdctl \u00b7 GitHub \u3002 wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-0.22.2-linux-amd64.tar.gz tar -zxvf nerdctl-0.22.2-linux-amd64.tar.gz sudo cp nerdctl /usr/bin/ \u9a8c\u8bc1 nerdctl \u670d\u52a1\u3002 sudo nerdctl --help \u5217\u51fa\u521d\u59cb\u5b89\u88c5Kubernetes\u65f6\u7684\u5bb9\u5668container\u5217\u8868\u3002 nerdctl -n k8s.io ps","title":"\u5b89\u88c5nerdctl"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#kubeadm","text":"\u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b89\u88c5Kubeadm\uff0ckubectl\uff0ckubelet\u3002 \u5b89\u88c5\u548c\u5347\u7ea7Ubuntu\u7cfb\u7edf\u4f9d\u8d56\u5305 apt-transport-https , ca-certificates , curl \u3002 sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl \u5b89\u88c5gpg\u8bc1\u4e66\u3002 curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - \u6dfb\u52a0Kubernetes\u5b89\u88c5\u6e90\u3002 cat << EOF > /etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF \u5b89\u88c5\u548c\u5347\u7ea7Ubuntu\u7cfb\u7edf\u4f9d\u8d56\u5305\u3002 sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables \u68c0\u67e5\u5f53\u524d\u53ef\u7528\u7684 kubeadm \u7248\u672c\u3002 apt policy kubeadm \u5f53\u524d\u5b89\u88c5 1.24.0-00 \u7248\u672c\u7684 kubeadm \uff0c\u540e\u7eed\u4f1a\u5347\u7ea7\u5230 1.24.2 \u7248\u672c\u3002 sudo apt-get -y install kubelet = 1 .24.0-00 kubeadm = 1 .24.0-00 kubectl = 1 .24.0-00 --allow-downgrades","title":"\u5b89\u88c5kubeadm"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_5","text":"","title":"\u914d\u7f6e\u4e3b\u8282\u70b9"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#kubeadm_1","text":"\u5728\u627f\u62c5\u4e3b\u8282\u70b9\u7684\u865a\u62df\u673a\u91cc\u914d\u7f6e\u63a7\u5236\u5e73\u9762\uff08Control Plane\uff09\u3002 \u68c0\u67e5 kubeadm \u5f53\u524d\u9ed8\u8ba4\u914d\u7f6e\u53c2\u6570\u3002 kubeadm config print init-defaults \u7c7b\u4f3c\u7ed3\u679c\u5982\u4e0b\u3002\u4fdd\u5b58\u9ed8\u8ba4\u914d\u7f6e\u7684\u7ed3\u679c\uff0c\u540e\u7eed\u4f1a\u4f5c\u4e3a\u53c2\u8003\u3002 apiVersion : kubeadm.k8s.io/v1beta3 bootstrapTokens : - groups : - system:bootstrappers:kubeadm:default-node-token token : abcdef.0123456789abcdef ttl : 24h0m0s usages : - signing - authentication kind : InitConfiguration localAPIEndpoint : advertiseAddress : 1.2.3.4 bindPort : 6443 nodeRegistration : criSocket : unix:///var/run/containerd/containerd.sock imagePullPolicy : IfNotPresent name : node taints : null --- apiServer : timeoutForControlPlane : 4m0s apiVersion : kubeadm.k8s.io/v1beta3 certificatesDir : /etc/kubernetes/pki clusterName : kubernetes controllerManager : {} dns : {} etcd : local : dataDir : /var/lib/etcd imageRepository : k8s.gcr.io kind : ClusterConfiguration kubernetesVersion : 1.24.0 networking : dnsDomain : cluster.local serviceSubnet : 10.96.0.0/12 scheduler : {} \u6a21\u62df\u5b89\u88c5\u548c\u6b63\u5f0f\u5b89\u88c5\u3002 \u901a\u8fc7\u547d\u4ee4 kubeadm init \u8fdb\u884c\u4e3b\u8282\u70b9\u7684\u521d\u59cb\u5316\uff0c\u4e0b\u9762\u662f\u8fd9\u4e2a\u547d\u4ee4\u4e3b\u8981\u53c2\u6570\u7684\u8bf4\u660e\uff0c\u7279\u522b\u662f\u7f51\u7edc\u53c2\u6570\u7684\u4e09\u4e2a\u9009\u62e9\u3002 --pod-network-cidr : \u6307\u5b9apod\u4f7f\u7528\u7684IP\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u6307\u5b9a\u4e86\u8be5\u53c2\u6570\uff0c\u5219Control Plane\u4f1a\u81ea\u52a8\u8bb2\u6307\u5b9a\u7684CIDR\u5206\u914d\u7ed9\u6bcf\u4e2a\u8282\u70b9\u3002 IP\u5730\u5740\u6bb5 10.244.0.0/16 \u662fFlannel\u7f51\u7edc\u7ec4\u4ef6\u9ed8\u8ba4\u7684\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u9700\u8981\u4fee\u6539Flannel\u7684IP\u5730\u5740\u6bb5\uff0c\u9700\u8981\u5728\u8fd9\u91cc\u6307\u5b9a\uff0c\u4e14\u5728\u90e8\u7f72Flannel\u65f6\u4e5f\u8981\u4fdd\u6301\u4e00\u81f4\u7684IP\u6bb5\u3002 --apiserver-bind-port : API\u670d\u52a1\uff08API Server\uff09\u7684\u7aef\u53e3\uff0c\u9ed8\u8ba4\u65f66443\u3002 --service-cidr : \u6307\u5b9a\u670d\u52a1\uff08service\uff09\u7684IP\u5730\u5740\u6bb5\uff0c\u9ed8\u8ba4\u662f 10.96.0.0/12 \u3002 \u63d0\u793a\uff1a \u670d\u52a1VIPs\uff08service VIPs\uff09\uff0c\u4e5f\u79f0\u4f5c\u96c6\u7fa4IP\uff08Cluster IP\uff09\uff0c\u901a\u8fc7\u53c2\u6570 --service-cidr \u6307\u5b9a\u3002 podCIDR\uff0c\u4e5f\u79f0\u4e3aendpoint IP\uff0c\u901a\u8fc7\u53c2\u6570 --pod-network-cidr \u6307\u5b9a\u3002 \u67094\u79cd\u5178\u578b\u7684\u7f51\u7edc\u95ee\u9898\uff1a \u9ad8\u5ea6\u8026\u5408\u7684\u5bb9\u5668\u4e0e\u5bb9\u5668\u4e4b\u95f4\u7684\u901a\u4fe1\uff1a\u8fd9\u53ef\u4ee5\u901a\u8fc7Pod\uff08podCIDR\uff09\u548c\u672c\u5730\u4e3b\u673a\u901a\u4fe1\u6765\u89e3\u51b3\u3002 Pod\u5bf9Pod\u901a\u4fe1\uff08Pod-to-Pod\uff09\uff1a \u4e5f\u88ab\u79f0\u4e3a\u5bb9\u5668\u5bf9\u5bb9\u5668\u901a\u4fe1\uff08container-to-container\uff09\u3002 \u5728Flannel\u7f51\u7edc\u63d2\u4ef6\u4e2d\u7684\u793a\u4f8b\u6d41\u7a0b\u662f\uff1aPod \u2192 veth\u5bf9 \u2192 cni0 \u2192 flannel.1 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 flannel.1 \u2192 cni0 \u2192 veth\u5bf9 \u2192 Pod\u3002 Pod\u5bf9Service\u901a\u4fe1\uff08Pod-to-Service\uff09\uff1a \u6d41\u7a0b: Pod \u2192 \u5185\u6838 \u2192 Service iptables \u2192 Service \u2192 Pod iptables \u2192 Pod\u3002 \u5916\u90e8\u5bf9Service\u901a\u4fe1\uff08External-to-Service\uff09\uff1a \u8d1f\u8f7d\u5747\u8861\u5668: SLB \u2192 NodePort \u2192 Service \u2192 Pod\u3002 kube-proxy \u662f\u5bf9iptables\u8d1f\u8d23\uff0c\u4e0d\u662f\u7f51\u7edc\u6d41\u91cf\uff08traffic\uff09\u3002 kube-proxy \u662fKubernetes\u96c6\u7fa4\u4e2d\u7684\u4e00\u4e2a\u7ec4\u4ef6\uff0c\u8d1f\u8d23\u4e3aService\u63d0\u4f9b\u4ee3\u7406\u670d\u52a1\uff0c\u540c\u65f6\u4e5f\u662fKubernetes\u7f51\u7edc\u6a21\u578b\u4e2d\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\u4e4b\u4e00\u3002 kube-proxy \u4f1a\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u542f\u52a8\u4e00\u4e2a\u4ee3\u7406\u8fdb\u7a0b\uff0c\u901a\u8fc7\u76d1\u542cKubernetes API Server\u7684Service\u548cEndpoint\u7684\u53d8\u5316\u6765\u7ef4\u62a4\u4e00\u4e2a\u672c\u5730\u7684Service\u548cEndpoint\u7684\u7f13\u5b58\u3002\u5f53\u6709\u8bf7\u6c42\u5230\u8fbe\u67d0\u4e2aService\u65f6\uff0c kube-proxy \u4f1a\u6839\u636e\u8be5Service\u7684\u7c7b\u578b\uff08ClusterIP\u3001NodePort\u3001LoadBalancer\u3001ExternalName\uff09\u548c\u7aef\u53e3\u53f7\uff0c\u751f\u6210\u76f8\u5e94\u7684iptables\u89c4\u5219\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u7ed9Service\u6240\u4ee3\u7406\u7684\u540e\u7aefPod\u3002 iptables\u662fLinux\u7cfb\u7edf\u4e2d\u7684\u4e00\u4e2a\u91cd\u8981\u7f51\u7edc\u5de5\u5177\uff0c\u53ef\u4ee5\u8bbe\u7f6eIP\u5305\u7684\u8fc7\u6ee4\u3001\u8f6c\u53d1\u548c\u4fee\u6539\u89c4\u5219\uff0c\u53ef\u4ee5\u5b9e\u73b0\u7f51\u7edc\u5c42\u7684\u9632\u706b\u5899\u3001NAT\u7b49\u529f\u80fd\u3002\u5728Kubernetes\u96c6\u7fa4\u4e2d\uff0c kube-proxy \u901a\u8fc7\u751f\u6210\u548c\u66f4\u65b0iptables\u89c4\u5219\uff0c\u6765\u5b9e\u73b0Service\u548cEndpoint\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u5177\u4f53\u6765\u8bf4\uff0ckube-proxy\u4f1a\u4e3a\u6bcf\u4e2aService\u521b\u5efa\u4e09\u6761iptables\u89c4\u5219\u94fe\uff08nat\u8868\u4e2d\u7684KUBE-SERVICES\u548cKUBE-NODEPORTS\u94fe\uff0c\u4ee5\u53cafilter\u8868\u4e2d\u7684KUBE-SVC-XXXXX\u94fe\uff09\uff0c\u901a\u8fc7\u8fd9\u4e9b\u89c4\u5219\u94fe\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u76f8\u5e94\u7684Pod\u6216\u8005Service\u4e0a\u3002 \u56e0\u6b64\uff0c kube-proxy \u548ciptables\u662f\u7d27\u5bc6\u76f8\u5173\u7684\u4e24\u4e2a\u7ec4\u4ef6\uff0c\u901a\u8fc7iptables\u89c4\u5219\u6765\u5b9e\u73b0Service\u548cPod\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u8fd9\u79cd\u5b9e\u73b0\u65b9\u5f0f\u5177\u6709\u53ef\u6269\u5c55\u6027\u548c\u9ad8\u53ef\u7528\u6027\uff0c\u540c\u65f6\u4e5f\u63d0\u4f9b\u4e86\u4e00\u79cd\u7075\u6d3b\u7684\u7f51\u7edc\u6a21\u578b\uff0c\u53ef\u4ee5\u65b9\u4fbf\u5730\u5b9e\u73b0\u670d\u52a1\u53d1\u73b0\u3001\u8d1f\u8f7d\u5747\u8861\u7b49\u529f\u80fd\u3002 sudo kubeadm init \\ --dry-run \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --kubernetes-version = v1.24.0","title":"kubeadm\u521d\u59cb\u5316"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#kubeconfig","text":"\u7ed9\u5f53\u524d\u5b89\u88c5\u7528\u6237\u914d\u7f6e kubeconfig \u6587\u4ef6\uff08\u5f53\u524d\u4f8b\u5b50\u662f\u7528\u6237 vagrant \uff09\u3002 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Kubernetes \u63d0\u4f9b\u4e86\u4e00\u4e2a\u547d\u4ee4\u884c\u5de5\u5177 kubectl \uff0c\u7528\u4e8e\u4f7f\u7528 Kubernetes API \u4e0e Kubernetes \u96c6\u7fa4\u7684\u63a7\u5236\u5e73\u9762\u8fdb\u884c\u901a\u4fe1\u3002 kubectl \u63a7\u5236 Kubernetes cluster manager \uff08\u96c6\u7fa4\u7ba1\u7406\u5668\uff09\u3002 \u5bf9\u4e8e\u914d\u7f6e\uff0ckubectl \u5728 $HOME/.kube \u76ee\u5f55\u4e2d\u67e5\u627e\u4e00\u4e2a\u540d\u4e3a config \u7684\u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u662f\u7531 kubeadm init \u751f\u6210\u7684\u6587\u4ef6 /etc/kubernetes/admin.conf \u7684\u526f\u672c\u3002 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e KUBECONFIG \u73af\u5883\u53d8\u91cf\u6216\u8bbe\u7f6e --kubeconfig flag \u6807\u5fd7\u6765\u6307\u5b9a\u5176\u4ed6 kubeconfig \u6587\u4ef6\u3002\u5982\u679c KUBECONFIG \u73af\u5883\u53d8\u91cf\u4e0d\u5b58\u5728\uff0ckubectl \u5c06\u4f7f\u7528\u9ed8\u8ba4\u7684 kubeconfig \u6587\u4ef6 $HOME/.kube/config \u3002 kubeconfig \u6587\u4ef6\u4e2d\u7684 context\uff08\u4e0a\u4e0b\u6587\uff09 \u5143\u7d20\u7528\u4e8e\u5c06\u8bbf\u95ee\u53c2\u6570\u5206\u7ec4\u5230\u4e00\u4e2a\u65b9\u4fbf\u7684\u540d\u79f0\u4e0b\u3002\u6bcf\u4e2a\u4e0a\u4e0b\u6587\u90fd\u6709\u4e09\u4e2a\u53c2\u6570\uff1a\u96c6\u7fa4\u3001\u547d\u540d\u7a7a\u95f4\u548c\u7528\u6237\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0ckubectl \u547d\u4ee4\u884c\u5de5\u5177\u4f7f\u7528\u5f53\u524d\u4e0a\u4e0b\u6587\u4e2d\u7684\u53c2\u6570\u4e0e\u96c6\u7fa4\u901a\u4fe1\u3002 \u6587\u4ef6 .kube/config \u7684\u4f8b\u5b50\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : \u8bfb\u53d6\u5f53\u524d\u4e0a\u4e0b\u6587\uff1a kubectl config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin","title":"kubeconfig\u6587\u4ef6"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_6","text":"\u4f7f\u7528 kubeadm token \u6765\u751f\u6210\u52a0\u5165\u96c6\u7fa4\u7684\u4ee4\u724c\uff08token\uff09\u548c\u54c8\u897f\u503c\uff08hash value\uff09\u3002 kubeadm token create --print-join-command \u5728\u6240\u6709\u5de5\u4f5c\u8282\u70b9\u4e0a\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u5c06\u5de5\u4f5c\u8282\u70b9\u52a0\u5165Kubernetes\u96c6\u7fa4\u3002 # kubeadm join :6443 --token --discovery-token-ca-cert-hash \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u68c0\u67e5\u6240\u6709\u8282\u70b9\u7684\u72b6\u6001\u3002 \u5f53\u524d\u6240\u6709\u8282\u70b9\u7684\u72b6\u6001\u90fd\u662f NotReady \u3002\u76ee\u524d\u4e0d\u9700\u8981\u505a\u4ec0\u4e48\uff0c\u540e\u9762\u6211\u4eec\u4f1a\u5b89\u88c5\u76f8\u5173\u7684\u7f51\u7edc\u670d\u52a1\uff08Calico \u6216 Flannel\uff09\uff0c\u5404\u8282\u70b9\u7684\u72b6\u6001\u5c31\u4f1a\u53d8\u6210Ready\u72b6\u6001\u3002","title":"\u914d\u7f6e\u5de5\u4f5c\u8282\u70b9"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#calicoflannel","text":"\u5728\u63a7\u5236\u5e73\u9762Control Plane\u4e0a\u5b89\u88c5Calico\u6216\u8005Flannel\u3002\u5982\u679c\u9700\u8981\u914d\u7f6e\u7f51\u7edc\u7b56\u7565\uff0c\u5219\u9009\u62e9Calico\u3002","title":"\u5b89\u88c5Calico\u6216Flannel"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#flannel","text":"Flannel \u662f\u4e3a Kubernetes \u8bbe\u8ba1\u7684\u4e00\u79cd\u7b80\u5355\u6613\u7528\u7684\u914d\u7f6e\u4e09\u5c42\u7f51\u7edc\u7684\u65b9\u6cd5\u3002 \u90e8\u7f72Flannel\uff1a \u5728 kube-flannel.yml \u4e2d\uff0c\u6211\u4eec\u53ef\u4ee5\u83b7\u53d6 Flannel \u7684\u9ed8\u8ba4\u7f51\u7edc\u8bbe\u7f6e\uff0c\u5b83\u4e0e\u6211\u4eec\u5728\u4f7f\u7528 kubeadm \u521d\u59cb\u5316\u96c6\u7fa4\u65f6\u6307\u5b9a\u7684\u53c2\u6570 --pod-network-cidr=10.244.0.0/16 \u76f8\u540c\u3002 net - co nf .jso n : | { \"Network\" : \"10.244.0.0/16\" , \"Backend\" : { \"Type\" : \"vxlan\" } } \u521b\u5efaFlannel\u670d\u52a1\u3002 apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml \u8f93\u51fa\u7ed3\u679c\uff1a Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy/psp.flannel.unprivileged created clusterrole.rbac.authorization.k8s.io/flannel created clusterrolebinding.rbac.authorization.k8s.io/flannel created serviceaccount/flannel created configmap/kube-flannel-cfg created daemonset.apps/kube-flannel-ds created","title":"\u5b89\u88c5Flannel"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#calico","text":"\u5b89\u88c5\u6307\u5bfc\u624b\u518c\uff1a End-to-end Calico installation \u3002 \u4e0b\u8f7d\u5e76\u5b89\u88c5Calico\u670d\u52a1\u3002 curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml \u8f93\u51fa\u7ed3\u679c\uff1a configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created \u9a8c\u8bc1Calico\u670d\u52a1\u72b6\u6001\uff1a kubectl get pod -n kube-system | grep calico \u8f93\u51fa\u7ed3\u679c\uff1a calico-kube-controllers-555bc4b957-l8bn2 0 /1 Pending 0 28s calico-node-255pc 0 /1 Init:1/3 0 29s calico-node-7tmnb 0 /1 Init:1/3 0 29s calico-node-w8nvl 0 /1 Init:1/3 0 29s \u68c0\u67e5\u96c6\u7fa4\u7684\u7f51\u7edc\u72b6\u6001\uff1a sudo nerdctl network ls \u8f93\u51fa\u7ed3\u679c\uff1a NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none","title":"\u5b89\u88c5Calico"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_7","text":"\u5728\u4e3b\u8282\u70b9\u4e0a\u6267\u884c\u547d\u4ee4 kubectl cluster-info \u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u4fe1\u606f\uff1a \u63a7\u5236\u5e73\u9762\uff08control plane\uff09\u8fd0\u884c\u5728 https://:6443 CoreDNS\u670d\u52a1\u8fd0\u884c\u5728 https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy kubectl cluster-info \u67e5\u770b\u8282\u70b9\u8fd0\u884c\u72b6\u6001\u3002\u6b64\u65f6\uff0c\u6240\u6709\u8282\u70b9\u90fd\u662f Ready \u7684\u6b63\u5e38\u72b6\u6001\u4e86\u3002 OS Image: Ubuntu 20.04.4 LTS Kernel Version: 5.4.0-122-generic Container Runtime: containerd://1.5.9 kubectl get nodes -owide \u8f93\u51fa\u7ed3\u679c\uff1a NAME STATUS ROLES AGE VERSION cka001 Ready control-plane 13m v1.24.0 cka002 Ready 8m35s v1.24.0 cka003 Ready 8m26s v1.24.0 \u67e5\u770bPods\u7684\u72b6\u6001\u3002 kubectl get pod -A \u8f93\u51fa\u7ed3\u679c\uff1a NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 7m18s kube-system calico-node-255pc 1/1 Running 0 7m19s kube-system calico-node-7tmnb 1/1 Running 0 7m19s kube-system calico-node-w8nvl 1/1 Running 0 7m19s kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15m kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15m kube-system etcd-cka001 1/1 Running 0 15m kube-system kube-apiserver-cka001 1/1 Running 0 15m kube-system kube-controller-manager-cka001 1/1 Running 0 15m kube-system kube-proxy-dmj2t 1/1 Running 0 15m kube-system kube-proxy-n77zw 1/1 Running 0 11m kube-system kube-proxy-qs6rf 1/1 Running 0 11m kube-system kube-scheduler-cka001 1/1 Running 0 15m","title":"\u68c0\u67e5\u96c6\u7fa4\u72b6\u6001"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_8","text":"","title":"\u66f4\u65b0\u5b89\u88c5"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#bash","text":"\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u914d\u7f6eBash\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 \u53c2\u8003 \u6307\u5bfc \u8bbe\u7f6e kubectl \u81ea\u52a8\u8865\u5168\u529f\u80fdauto-completion \u3002 apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc source ~/.bashrc","title":"Bash\u81ea\u52a8\u8865\u5168"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_9","text":"\u5982\u679c\u6211\u4eec\u4e3a kubectl \u8bbe\u7f6e\u4e00\u4e2a\u522b\u540d\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u4e00\u4e9b\u65b9\u6cd5\u6765\u6269\u5c55 shell \u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u4f7f\u5176\u80fd\u591f\u4e0e\u8be5\u522b\u540d\u4e00\u8d77\u4f7f\u7528\u3002 \u4e00\u79cd\u65b9\u6cd5\u662f\u5728 Bash shell \u914d\u7f6e\u6587\u4ef6\uff08\u5982 .bashrc \u6216 .bash_profile\uff09\u4e2d\u8bbe\u7f6e\u522b\u540d\uff0c\u5e76\u4e3a\u8be5\u522b\u540d\u6307\u5b9a kubectl \u7684\u5b8c\u6574\u8def\u5f84\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a alias k = 'path/to/kubectl' \u7136\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u91cd\u65b0\u52a0\u8f7d .bashrc \u6587\u4ef6\uff1a source ~/.bashrc \u63a5\u4e0b\u6765\uff0c\u53ef\u4ee5\u4f7f\u7528 k \u547d\u4ee4\u6765\u4ee3\u66ff kubectl \u547d\u4ee4\uff0c\u5e76\u5728\u5176\u540e\u9762\u6dfb\u52a0\u76f8\u5e94\u7684\u53c2\u6570\u548c\u9009\u9879\u3002\u5f53\u4f7f\u7528\u81ea\u52a8\u8865\u5168\u529f\u80fd\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u5c06 k \u522b\u540d\u8f6c\u6362\u4e3a kubectl \u7684\u5b8c\u6574\u8def\u5f84\uff0c\u5e76\u5bf9\u5176\u8fdb\u884c\u81ea\u52a8\u8865\u5168\u3002 \u53e6\u4e00\u79cd\u65b9\u6cd5\u662f\u4f7f\u7528 Bash shell \u5185\u7f6e\u7684 complete \u51fd\u6570\u6765\u4e3a\u522b\u540d\u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc \u8fd9\u5c06\u4e3a\u522b\u540d k \u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u5e76\u5c06\u5176\u4e0e kubectl \u7684\u81ea\u52a8\u8865\u5168\u51fd\u6570 __start_kubectl \u5173\u8054\u8d77\u6765\u3002\u8fd9\u6837\uff0c\u5f53\u7528\u6237\u5728 k \u547d\u4ee4\u540e\u8f93\u5165Tab\u952e\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u8c03\u7528 __start_kubectl \u51fd\u6570\uff0c\u5e76\u4e3a\u7528\u6237\u63d0\u4f9b\u76f8\u5e94\u7684\u81ea\u52a8\u8865\u5168\u5efa\u8bae\u3002","title":"\u522b\u540d"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#context","text":"\u67e5\u770b\u5f53\u524d\u7684 context \u5217\u8868\uff1a kubectl config get-contexts \u8fd9\u4e2a\u547d\u4ee4\u4f1a\u5217\u51fa\u6240\u6709\u53ef\u7528\u7684 context \u5217\u8868\uff0c\u5e76\u6807\u8bb0\u51fa\u5f53\u524d\u6b63\u5728\u4f7f\u7528\u7684 context\u3002 \u7c7b\u4f3c\u4e0b\u9762\u7ed3\u679c\uff1a kubernetes-admin@kubernetes \u662fContext\u540d\u3002 kubernetes \u662f\u96c6\u7fa4\u540d\u3002 kubernetes-admin \u662f\u7528\u6237\u540d\u3002 \u5f53\u524d\u4f8b\u5b50\u4e2d\u6ca1\u6709\u6307\u5b9a\u540d\u79f0\u7a7a\u95f4\u3002 CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin \u66f4\u65b0context\u3002\u4f8b\u5982\uff0c\u66f4\u65b0context\u7684\u9ed8\u8ba4\u540d\u79f0\u7a7a\u95f4\u7b49\u3002 # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin \u5728\u4e0d\u540c\u7684context\u4e4b\u95f4\u5207\u6362\u3002 # Usage: kubectl config use-context # Switch to new context kubectl config use-context kubernetes-admin@kubernetes \u53c2\u8003\u8d44\u6599\uff1a kubectl [commandline","title":"\u66f4\u65b0\u9ed8\u8ba4Context"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_10","text":"\u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u64cd\u4f5c\u4f1a\u91cd\u7f6e\u5f53\u524d\u96c6\u7fa4\uff08\u5220\u9664\u96c6\u7fa4\uff09\u3002 \u5220\u9664\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u3002 kubeadm reset \u6e05\u9664 iptables \u4e2d\u5df2\u5b9a\u4e49\u7684\u89c4\u5219\u3002 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u6e05\u9664 IPVS \u4e2d\u5b9a\u4e49\u7684\u89c4\u5219\uff08\u5982\u679c\u4f7f\u7528 IPVS \uff09\u3002 ipvsadm --clear","title":"\u91cd\u7f6e\u96c6\u7fa4"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#_11","text":"","title":"\u6392\u9519"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#1","text":"\u62a5\u9519\u4fe1\u606f\uff1a The connection to the server :6443 was refused - did you specify the right host or port? \u89e3\u51b3\u5c1d\u8bd5\uff1a Reference \u68c0\u67e5\u6587\u4ef6kubeconfig\u7684\u5185\u5bb9\u548c\u6587\u4ef6\u8def\u5f84\u662f\u5426\u6b63\u786e\u3002 \u68c0\u67e5\u73af\u5883\u53d8\u91cf\u8bbe\u7f6e\u3002 env | grep -i kub \u68c0\u67e5\u5bb9\u5668\u8fd0\u884c\u72b6\u6001\u3002 sudo systemctl status containerd.service \u68c0\u67e5kubelet\u670d\u52a1\u3002 sudo systemctl status kubelet.service \u68c0\u67e5 6443 \u7aef\u53e3\u76d1\u542c\u72b6\u6001\u3002 netstat -pnlt | grep 6443 \u68c0\u67e5\u9632\u706b\u5899\u72b6\u6001\u3002 sudo systemctl status firewalld.service \u68c0\u67e5kubelet\u65e5\u5fd7\u3002 journalctl -xeu kubelet","title":"\u9519\u8bef1"},{"location":"k8s/cka_cn/installation/aliyun-ubuntu/#2","text":"\u62a5\u9519\u4fe1\u606f\uff1a \"Container runtime network not ready\" networkReady=\"NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized\" \u5c1d\u8bd5\u65b9\u6cd5\uff1a \u91cd\u542fContainerd\u670d\u52a1\u3002 sudo systemctl restart containerd sudo systemctl status containerd","title":"\u9519\u8bef2"},{"location":"k8s/cka_cn/installation/multiple-local/","text":"CKA\u81ea\u5b66\u7b14\u8bb02:\u591a\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes \u00b6 \u6458\u8981 \u00b6 \u5728\u672c\u5730Windows\u73af\u5883\u4e2d\uff0c\u901a\u8fc7VMWare\u5b89\u88c5\u4e09\u53f0Ubuntu\u865a\u62df\u673a\u3002\u5728Ubuntu\u865a\u62df\u673a\u4e2d\u5b89\u88c5\u57fa\u4e8eContainerd\u7684Kubernetes\u7cfb\u7edf\uff0c\u5e76\u5206\u522b\u914d\u7f6e\u4e00\u4e2a\u4e3b\u8282\u70b9Master\u548c\u4e24\u4e2a\u5de5\u4f5c\u8282\u70b9Worker\u3002 \u672c\u5730\u865a\u62df\u673a\u8bbe\u7f6e \u00b6 VMWare \u8bbe\u7f6e VMnet1: host-only\u6a21\u5f0f, \u7f51\u7edcsubnet: 192.168.150.0/24 VMnet8: NAT\u6a21\u5f0f, \u7f51\u7edcsubnet: 11.0.1.0/24 \u901a\u8fc7VMWare\u521b\u5efa\u5ba2\u6237\u865a\u62df\u673a\u3002 \u5185\u5b58\uff1a4 GB CPU\uff1a1 CPUs with 2 Cores \u64cd\u4f5c\u7cfb\u7edf\uff1aUbuntu Server 22.04 \u7f51\u7edc\uff1aNAT \u63d0\u793a\uff1a \u5f53\u524d\u7ec3\u4e60\u4e2d\uff0cKubernetes\u662f\u57fa\u4e8eContainerd\uff0c\u4e0d\u662fDocker\u3002 Ubuntu\u9884\u914d\u7f6e \u00b6 \u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u4efb\u52a1\uff0c\u9700\u8981\u5728\u6bcf\u53f0\u865a\u62df\u673a\u4e2d\u6267\u884c\u4e00\u6b21\u3002\u4ee5\u4e0b\u7b80\u79f0\u865a\u62df\u673a\u4e3a\u8282\u70b9\u3002 \u5728\u6240\u6709\u8282\u70b9\u4e2d\u521b\u5efa\u7528\u6237 vagrant \u3002 sudo adduser vagrant sudo usermod -g sudo vagrant sudo usermod -a -G root vagrant sudo passwd vagrant \u5728\u6240\u6709\u8282\u70b9\u4e2d\u8bbe\u7f6e\u7528\u6237 root \u7684\u5bc6\u7801\u3002 sudo passwd root \u4fee\u6539ssh\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6\u3002\u5f00\u653e root \u7528\u6237\u901a\u8fc7ssh\u767b\u5f55\uff08\u9ed8\u8ba4\u662f\u7981\u7528\u7684\uff09\u3002 sudo vi /etc/ssh/sshd_config \u628a\u53c2\u6570 PermitRootLogin \u7684\u503c\u4ece prohibit-password \u6539\u4e3a yes \u3002 PermitRootLogin yes # PermitRootLogin prohibit-password \u91cd\u65b0\u542f\u52a8sshd\u670d\u52a1\u3002 sudo systemctl restart sshd \u66f4\u6539\u4e3b\u673a\u540d\uff0c\u8fd9\u91cc\u662f ubu1 . sudo hostnamectl set-hostname ubu1 sudo hostnamectl set-hostname ubu1 --pretty \u9a8c\u8bc1\u4e3b\u673a\u540d\u662f\u5426\u88ab\u6b63\u786e\u4fee\u6539\u4e86\uff0c\u6bd4\u5982\u6539\u4e3a ubu1 \u3002 cat /etc/machine-info \u9a8c\u8bc1\u4e3b\u673a\u540d\u662f\u5426\u88ab\u6b63\u786e\u4fee\u6539\u4e86\uff0c\u6bd4\u5982\u6539\u4e3a ubu1 \u3002 cat /etc/hostname \u9a8c\u8bc1\u4e3b\u673aIP\u5730\u5740 127.0.1.1 \u5df2\u7ecf\u914d\u7f6e\u7ed9\u5f53\u524d\u8282\u70b9\uff0c\u6bd4\u5982 ubu1 \u3002\u540c\u65f6\uff0c\u5728\u6240\u6709\u8282\u70b9\u7684 /etc/hosts \u6587\u4ef6\u4e2d\u6dfb\u52a0\u5176\u4ed6\u8282\u70b9\u7684IP\u548c\u4e3b\u673a\u5bf9\u5e94\u4fe1\u606f\u3002 sudo vi /etc/hosts \u4ee5\u5f53\u524d\u7ec3\u4e60\u4e3a\u4f8b\uff0c\u4fee\u6539\u540e\u7684 /etc/hosts \u6587\u4ef6\u7c7b\u4f3c\u5982\u4e0b\u5185\u5bb9\u3002 127.0.1.1 ubu1 11.0.1.129 ubu1 11.0.1.130 ubu2 11.0.1.131 ubu3 11.0.1.132 ubu4 \u521b\u5efa\u6587\u4ef6 /etc/netplan/00-installer-config.yaml \u3002 sudo vi /etc/netplan/00-installer-config.yaml \u66f4\u65b0\u6b64\u6587\u4ef6\uff0c\u8bbe\u5b9a\u5f53\u524d\u8282\u70b9\u4f7f\u7528\u56fa\u5b9aIP\u5730\u5740\uff0c\u6bd4\u5982\uff0c 11.0.1.129 \u3002 network : ethernets : ens33 : dhcp4 : false addresses : - 11.0.1.129/24 nameservers : addresses : - 11.0.1.2 routes : - to : default via : 11.0.1.2 version : 2 \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u65f6\uff0c\u4f7f\u4e0a\u8ff0\u6539\u52a8\u751f\u6548\u3002\u6ce8\u610f\uff0c\u5f53\u524dssh\u8fde\u63a5\u4f1a\u56e0\u6b64\u800c\u65ad\u5f00\u3002 sudo netplan apply \u5728\u6240\u6709\u8282\u70b9\u7981\u7528\u4ea4\u6362\u5206\u533aswap\u548c\u9632\u706b\u5899firewall\u3002 sudo swapoff -a sudo ufw disable sudo ufw status verbose \u5728\u6240\u6709\u8282\u70b9\u7684\u6587\u4ef6 /etc/fstab \u4e2d\u6ce8\u91ca\u6389\u6d89\u53caswap\u7684\u90a3\u4e00\u884c\uff0c\u4fee\u6539\u540e\u9700\u8981\u91cd\u542f\u5f53\u524d\u8282\u70b9\u3002 sudo vi /etc/fstab \u4fee\u6539\u540e\u7684\u7ed3\u679c\u7c7b\u4f3c\u5982\u4e0b\u3002 /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 \u5728\u6240\u6709\u8282\u70b9\u8bbe\u7f6e\u7edf\u4e00\u7684\u65f6\u533a\u3002 sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo cp /etc/profile /etc/profile.bak echo 'LANG=\"en_US.UTF-8\"' | sudo tee -a /etc/profile source /etc/profile \u6267\u884c\u547d\u4ee4 ll /etc/localtime \u6765\u9a8c\u8bc1\u65f6\u533a\u662f\u5426\u4fee\u6539\u6b63\u786e\u3002 lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai \u5728\u6240\u6709\u8282\u70b9\u4fee\u6539\u5185\u6838\u8bbe\u7f6e\u3002 cat < /etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF \u68c0\u67e5\u5f53\u524d kubeadm \u7684\u7248\u672c\u3002 apt policy kubeadm \u5b89\u88c5 1.24.1-00 \u7248\u672c\u7684 kubeadm . sudo apt-get -y install kubelet = 1 .24.1-00 kubeadm = 1 .24.1-00 kubectl = 1 .24.1-00 --allow-downgrades \u914d\u7f6e\u4e3b\u8282\u70b9 \u00b6 kubeadm\u521d\u59cb\u5316 \u00b6 \u5728\u627f\u62c5\u4e3b\u8282\u70b9\u7684\u865a\u62df\u673a\u91cc\u914d\u7f6e\u63a7\u5236\u5e73\u9762\uff08Control Plane\uff09\u3002 \u68c0\u67e5 kubeadm \u5f53\u524d\u9ed8\u8ba4\u914d\u7f6e\u53c2\u6570\u3002 kubeadm config print init-defaults \u7c7b\u4f3c\u7ed3\u679c\u5982\u4e0b\u3002\u4fdd\u5b58\u9ed8\u8ba4\u914d\u7f6e\u7684\u7ed3\u679c\uff0c\u540e\u7eed\u4f1a\u4f5c\u4e3a\u53c2\u8003\u3002 apiVersion : kubeadm.k8s.io/v1beta3 bootstrapTokens : - groups : - system:bootstrappers:kubeadm:default-node-token token : abcdef.0123456789abcdef ttl : 24h0m0s usages : - signing - authentication kind : InitConfiguration localAPIEndpoint : advertiseAddress : 1.2.3.4 bindPort : 6443 nodeRegistration : criSocket : unix:///var/run/containerd/containerd.sock imagePullPolicy : IfNotPresent name : node taints : null --- apiServer : timeoutForControlPlane : 4m0s apiVersion : kubeadm.k8s.io/v1beta3 certificatesDir : /etc/kubernetes/pki clusterName : kubernetes controllerManager : {} dns : {} etcd : local : dataDir : /var/lib/etcd imageRepository : k8s.gcr.io kind : ClusterConfiguration kubernetesVersion : 1.24.0 networking : dnsDomain : cluster.local serviceSubnet : 10.96.0.0/12 scheduler : {} \u6a21\u62df\u5b89\u88c5\u548c\u6b63\u5f0f\u5b89\u88c5\u3002 \u901a\u8fc7\u547d\u4ee4 kubeadm init \u8fdb\u884c\u4e3b\u8282\u70b9\u7684\u521d\u59cb\u5316\uff0c\u4e0b\u9762\u662f\u8fd9\u4e2a\u547d\u4ee4\u4e3b\u8981\u53c2\u6570\u7684\u8bf4\u660e\uff0c\u7279\u522b\u662f\u7f51\u7edc\u53c2\u6570\u7684\u4e09\u4e2a\u9009\u62e9\u3002 --pod-network-cidr : \u6307\u5b9apod\u4f7f\u7528\u7684IP\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u6307\u5b9a\u4e86\u8be5\u53c2\u6570\uff0c\u5219Control Plane\u4f1a\u81ea\u52a8\u8bb2\u6307\u5b9a\u7684CIDR\u5206\u914d\u7ed9\u6bcf\u4e2a\u8282\u70b9\u3002 IP\u5730\u5740\u6bb5 10.244.0.0/16 \u662fFlannel\u7f51\u7edc\u7ec4\u4ef6\u9ed8\u8ba4\u7684\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u9700\u8981\u4fee\u6539Flannel\u7684IP\u5730\u5740\u6bb5\uff0c\u9700\u8981\u5728\u8fd9\u91cc\u6307\u5b9a\uff0c\u4e14\u5728\u90e8\u7f72Flannel\u65f6\u4e5f\u8981\u4fdd\u6301\u4e00\u81f4\u7684IP\u6bb5\u3002 --apiserver-bind-port : API\u670d\u52a1\uff08API Server\uff09\u7684\u7aef\u53e3\uff0c\u9ed8\u8ba4\u65f66443\u3002 --service-cidr : \u6307\u5b9a\u670d\u52a1\uff08service\uff09\u7684IP\u5730\u5740\u6bb5\uff0c\u9ed8\u8ba4\u662f 10.96.0.0/12 \u3002 \u63d0\u793a\uff1a \u670d\u52a1VIPs\uff08service VIPs\uff09\uff0c\u4e5f\u79f0\u4f5c\u96c6\u7fa4IP\uff08Cluster IP\uff09\uff0c\u901a\u8fc7\u53c2\u6570 --service-cidr \u6307\u5b9a\u3002 podCIDR\uff0c\u4e5f\u79f0\u4e3aendpoint IP\uff0c\u901a\u8fc7\u53c2\u6570 --pod-network-cidr \u6307\u5b9a\u3002 \u67094\u79cd\u5178\u578b\u7684\u7f51\u7edc\u95ee\u9898\uff1a \u9ad8\u5ea6\u8026\u5408\u7684\u5bb9\u5668\u4e0e\u5bb9\u5668\u4e4b\u95f4\u7684\u901a\u4fe1\uff1a\u8fd9\u53ef\u4ee5\u901a\u8fc7Pod\uff08podCIDR\uff09\u548c\u672c\u5730\u4e3b\u673a\u901a\u4fe1\u6765\u89e3\u51b3\u3002 Pod\u5bf9Pod\u901a\u4fe1\uff08Pod-to-Pod\uff09\uff1a \u4e5f\u88ab\u79f0\u4e3a\u5bb9\u5668\u5bf9\u5bb9\u5668\u901a\u4fe1\uff08container-to-container\uff09\u3002 \u5728Flannel\u7f51\u7edc\u63d2\u4ef6\u4e2d\u7684\u793a\u4f8b\u6d41\u7a0b\u662f\uff1aPod \u2192 veth\u5bf9 \u2192 cni0 \u2192 flannel.1 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 flannel.1 \u2192 cni0 \u2192 veth\u5bf9 \u2192 Pod\u3002 Pod\u5bf9Service\u901a\u4fe1\uff08Pod-to-Service\uff09\uff1a \u6d41\u7a0b: Pod \u2192 \u5185\u6838 \u2192 Service iptables \u2192 Service \u2192 Pod iptables \u2192 Pod\u3002 \u5916\u90e8\u5bf9Service\u901a\u4fe1\uff08External-to-Service\uff09\uff1a \u8d1f\u8f7d\u5747\u8861\u5668: SLB \u2192 NodePort \u2192 Service \u2192 Pod\u3002 kube-proxy \u662f\u5bf9iptables\u8d1f\u8d23\uff0c\u4e0d\u662f\u7f51\u7edc\u6d41\u91cf\uff08traffic\uff09\u3002 kube-proxy \u662fKubernetes\u96c6\u7fa4\u4e2d\u7684\u4e00\u4e2a\u7ec4\u4ef6\uff0c\u8d1f\u8d23\u4e3aService\u63d0\u4f9b\u4ee3\u7406\u670d\u52a1\uff0c\u540c\u65f6\u4e5f\u662fKubernetes\u7f51\u7edc\u6a21\u578b\u4e2d\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\u4e4b\u4e00\u3002 kube-proxy \u4f1a\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u542f\u52a8\u4e00\u4e2a\u4ee3\u7406\u8fdb\u7a0b\uff0c\u901a\u8fc7\u76d1\u542cKubernetes API Server\u7684Service\u548cEndpoint\u7684\u53d8\u5316\u6765\u7ef4\u62a4\u4e00\u4e2a\u672c\u5730\u7684Service\u548cEndpoint\u7684\u7f13\u5b58\u3002\u5f53\u6709\u8bf7\u6c42\u5230\u8fbe\u67d0\u4e2aService\u65f6\uff0c kube-proxy \u4f1a\u6839\u636e\u8be5Service\u7684\u7c7b\u578b\uff08ClusterIP\u3001NodePort\u3001LoadBalancer\u3001ExternalName\uff09\u548c\u7aef\u53e3\u53f7\uff0c\u751f\u6210\u76f8\u5e94\u7684iptables\u89c4\u5219\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u7ed9Service\u6240\u4ee3\u7406\u7684\u540e\u7aefPod\u3002 iptables\u662fLinux\u7cfb\u7edf\u4e2d\u7684\u4e00\u4e2a\u91cd\u8981\u7f51\u7edc\u5de5\u5177\uff0c\u53ef\u4ee5\u8bbe\u7f6eIP\u5305\u7684\u8fc7\u6ee4\u3001\u8f6c\u53d1\u548c\u4fee\u6539\u89c4\u5219\uff0c\u53ef\u4ee5\u5b9e\u73b0\u7f51\u7edc\u5c42\u7684\u9632\u706b\u5899\u3001NAT\u7b49\u529f\u80fd\u3002\u5728Kubernetes\u96c6\u7fa4\u4e2d\uff0c kube-proxy \u901a\u8fc7\u751f\u6210\u548c\u66f4\u65b0iptables\u89c4\u5219\uff0c\u6765\u5b9e\u73b0Service\u548cEndpoint\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u5177\u4f53\u6765\u8bf4\uff0ckube-proxy\u4f1a\u4e3a\u6bcf\u4e2aService\u521b\u5efa\u4e09\u6761iptables\u89c4\u5219\u94fe\uff08nat\u8868\u4e2d\u7684KUBE-SERVICES\u548cKUBE-NODEPORTS\u94fe\uff0c\u4ee5\u53cafilter\u8868\u4e2d\u7684KUBE-SVC-XXXXX\u94fe\uff09\uff0c\u901a\u8fc7\u8fd9\u4e9b\u89c4\u5219\u94fe\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u76f8\u5e94\u7684Pod\u6216\u8005Service\u4e0a\u3002 \u56e0\u6b64\uff0c kube-proxy \u548ciptables\u662f\u7d27\u5bc6\u76f8\u5173\u7684\u4e24\u4e2a\u7ec4\u4ef6\uff0c\u901a\u8fc7iptables\u89c4\u5219\u6765\u5b9e\u73b0Service\u548cPod\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u8fd9\u79cd\u5b9e\u73b0\u65b9\u5f0f\u5177\u6709\u53ef\u6269\u5c55\u6027\u548c\u9ad8\u53ef\u7528\u6027\uff0c\u540c\u65f6\u4e5f\u63d0\u4f9b\u4e86\u4e00\u79cd\u7075\u6d3b\u7684\u7f51\u7edc\u6a21\u578b\uff0c\u53ef\u4ee5\u65b9\u4fbf\u5730\u5b9e\u73b0\u670d\u52a1\u53d1\u73b0\u3001\u8d1f\u8f7d\u5747\u8861\u7b49\u529f\u80fd\u3002 sudo kubeadm init \\ --dry-run \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr = 192 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr = 192 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 kubeconfig\u6587\u4ef6 \u00b6 \u7ed9\u5f53\u524d\u5b89\u88c5\u7528\u6237\u914d\u7f6e kubeconfig \u6587\u4ef6\uff08\u5f53\u524d\u4f8b\u5b50\u662f\u7528\u6237 vagrant \uff09\u3002 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Kubernetes \u63d0\u4f9b\u4e86\u4e00\u4e2a\u547d\u4ee4\u884c\u5de5\u5177 kubectl \uff0c\u7528\u4e8e\u4f7f\u7528 Kubernetes API \u4e0e Kubernetes \u96c6\u7fa4\u7684\u63a7\u5236\u5e73\u9762\u8fdb\u884c\u901a\u4fe1\u3002 kubectl \u63a7\u5236 Kubernetes cluster manager \uff08\u96c6\u7fa4\u7ba1\u7406\u5668\uff09\u3002 \u5bf9\u4e8e\u914d\u7f6e\uff0ckubectl \u5728 $HOME/.kube \u76ee\u5f55\u4e2d\u67e5\u627e\u4e00\u4e2a\u540d\u4e3a config \u7684\u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u662f\u7531 kubeadm init \u751f\u6210\u7684\u6587\u4ef6 /etc/kubernetes/admin.conf \u7684\u526f\u672c\u3002 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e KUBECONFIG \u73af\u5883\u53d8\u91cf\u6216\u8bbe\u7f6e --kubeconfig flag \u6807\u5fd7\u6765\u6307\u5b9a\u5176\u4ed6 kubeconfig \u6587\u4ef6\u3002\u5982\u679c KUBECONFIG \u73af\u5883\u53d8\u91cf\u4e0d\u5b58\u5728\uff0ckubectl \u5c06\u4f7f\u7528\u9ed8\u8ba4\u7684 kubeconfig \u6587\u4ef6 $HOME/.kube/config \u3002 kubeconfig \u6587\u4ef6\u4e2d\u7684 context\uff08\u4e0a\u4e0b\u6587\uff09 \u5143\u7d20\u7528\u4e8e\u5c06\u8bbf\u95ee\u53c2\u6570\u5206\u7ec4\u5230\u4e00\u4e2a\u65b9\u4fbf\u7684\u540d\u79f0\u4e0b\u3002\u6bcf\u4e2a\u4e0a\u4e0b\u6587\u90fd\u6709\u4e09\u4e2a\u53c2\u6570\uff1a\u96c6\u7fa4\u3001\u547d\u540d\u7a7a\u95f4\u548c\u7528\u6237\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0ckubectl \u547d\u4ee4\u884c\u5de5\u5177\u4f7f\u7528\u5f53\u524d\u4e0a\u4e0b\u6587\u4e2d\u7684\u53c2\u6570\u4e0e\u96c6\u7fa4\u901a\u4fe1\u3002 \u6587\u4ef6 .kube/config \u7684\u4f8b\u5b50\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : \u8bfb\u53d6\u5f53\u524d\u4e0a\u4e0b\u6587\uff1a kubectl config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin \u5b89\u88c5Calico \u00b6 \u53c2\u8003\u5b89\u88c5\u6307\u5bfc End-to-end Calico installation \u3002 \u5feb\u901f\u5b89\u88c5\u624b\u518c QuickStart \u5b89\u88c5 Calico\uff1a kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/tigera-operator.yaml \u8fd0\u884c\u7ed3\u679c\uff1a namespace/tigera-operator created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/apiservers.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/imagesets.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/installations.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/tigerastatuses.operator.tigera.io created serviceaccount/tigera-operator created clusterrole.rbac.authorization.k8s.io/tigera-operator created clusterrolebinding.rbac.authorization.k8s.io/tigera-operator created deployment.apps/tigera-operator created kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/calicoctl.yaml \u8fd0\u884c\u7ed3\u679c\uff1a serviceaccount/calicoctl created pod/calicoctl created clusterrole.rbac.authorization.k8s.io/calicoctl created clusterrolebinding.rbac.authorization.k8s.io/calicoctl created \u9a8c\u8bc1Calico\u7684\u72b6\u6001\u3002Calico\u7684\u521d\u59cb\u5316\u8fc7\u7a0b\u53ef\u80fd\u9700\u8981\u51e0\u5206\u949f\u65f6\u95f4\u5b8c\u6210\u3002 kubectl get pod -n kube-system | grep calico \u8fd0\u884c\u7ed3\u679c\uff1a calico-kube-controllers-555bc4b957-l8bn2 0/1 Pending 0 28s calico-node-255pc 0/1 Init:1/3 0 29s calico-node-7tmnb 0/1 Init:1/3 0 29s calico-node-w8nvl 0/1 Init:1/3 0 29s \u9a8c\u8bc1\u7f51\u7edc\u72b6\u6001\u3002 sudo nerdctl network ls \u8fd0\u884c\u7ed3\u679c\uff1a NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 17f29b073143 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none \u914d\u7f6e\u5de5\u4f5c\u8282\u70b9 \u00b6 \u4f7f\u7528 kubeadm token \u6765\u751f\u6210\u52a0\u5165\u96c6\u7fa4\u7684\u4ee4\u724c\uff08token\uff09\u548c\u54c8\u897f\u503c\uff08hash value\uff09\u3002 kubeadm token create --print-join-command \u547d\u4ee4\u7528\u6cd5\uff1a sudo kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> \u8fd0\u884c\u7ed3\u679c\uff1a [preflight] Running pre-flight checks [WARNING SystemVerification]: missing optional cgroups: blkio [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [kubelet-start] Writing kubelet configuration to file \"/var/lib/kubelet/config.yaml\" [kubelet-start] Writing kubelet environment file with flags to file \"/var/lib/kubelet/kubeadm-flags.env\" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster. \u68c0\u67e5\u96c6\u7fa4\u72b6\u6001 \u00b6 \u67e5\u770b Kubernetes \u96c6\u7fa4\u7684\u4fe1\u606f\uff0c\u5305\u62ec\u96c6\u7fa4 API Server \u7684\u5730\u5740\u3001Kubernetes DNS \u670d\u52a1\u7684\u5730\u5740\u7b49\u3002 kubectl cluster-info \u8fd0\u884c\u7ed3\u679c\uff1a bKubernetes control plane is running at https://11.0.1.129:6443 CoreDNS is running at https://11.0.1.129:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. \u5217\u51fa\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u5305\u62ec\u8282\u70b9\u540d\u79f0\u3001\u8282\u70b9 IP\u3001\u8282\u70b9\u6807\u7b7e\u3001\u8282\u70b9\u72b6\u6001\u7b49\u3002 kubectl get nodes -owide \u5217\u51fa Kubernetes \u96c6\u7fa4\u4e2d\u6240\u6709 Namespace \u4e0b\u7684 Pod\u3002 kubectl get pod -A \u66f4\u65b0\u5b89\u88c5 \u00b6 Bash\u81ea\u52a8\u8865\u5168 \u00b6 \u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u914d\u7f6eBash\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 \u53c2\u8003 \u6307\u5bfc \u8bbe\u7f6e kubectl \u81ea\u52a8\u8865\u5168\u529f\u80fdauto-completion \u3002 apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc source ~/.bashrc \u522b\u540d \u00b6 \u5982\u679c\u6211\u4eec\u4e3a kubectl \u8bbe\u7f6e\u4e00\u4e2a\u522b\u540d\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u4e00\u4e9b\u65b9\u6cd5\u6765\u6269\u5c55 shell \u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u4f7f\u5176\u80fd\u591f\u4e0e\u8be5\u522b\u540d\u4e00\u8d77\u4f7f\u7528\u3002 \u4e00\u79cd\u65b9\u6cd5\u662f\u5728 Bash shell \u914d\u7f6e\u6587\u4ef6\uff08\u5982 .bashrc \u6216 .bash_profile\uff09\u4e2d\u8bbe\u7f6e\u522b\u540d\uff0c\u5e76\u4e3a\u8be5\u522b\u540d\u6307\u5b9a kubectl \u7684\u5b8c\u6574\u8def\u5f84\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a alias k = 'path/to/kubectl' \u7136\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u91cd\u65b0\u52a0\u8f7d .bashrc \u6587\u4ef6\uff1a source ~/.bashrc \u63a5\u4e0b\u6765\uff0c\u53ef\u4ee5\u4f7f\u7528 k \u547d\u4ee4\u6765\u4ee3\u66ff kubectl \u547d\u4ee4\uff0c\u5e76\u5728\u5176\u540e\u9762\u6dfb\u52a0\u76f8\u5e94\u7684\u53c2\u6570\u548c\u9009\u9879\u3002\u5f53\u4f7f\u7528\u81ea\u52a8\u8865\u5168\u529f\u80fd\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u5c06 k \u522b\u540d\u8f6c\u6362\u4e3a kubectl \u7684\u5b8c\u6574\u8def\u5f84\uff0c\u5e76\u5bf9\u5176\u8fdb\u884c\u81ea\u52a8\u8865\u5168\u3002 \u53e6\u4e00\u79cd\u65b9\u6cd5\u662f\u4f7f\u7528 Bash shell \u5185\u7f6e\u7684 complete \u51fd\u6570\u6765\u4e3a\u522b\u540d\u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc \u8fd9\u5c06\u4e3a\u522b\u540d k \u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u5e76\u5c06\u5176\u4e0e kubectl \u7684\u81ea\u52a8\u8865\u5168\u51fd\u6570 __start_kubectl \u5173\u8054\u8d77\u6765\u3002\u8fd9\u6837\uff0c\u5f53\u7528\u6237\u5728 k \u547d\u4ee4\u540e\u8f93\u5165Tab\u952e\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u8c03\u7528 __start_kubectl \u51fd\u6570\uff0c\u5e76\u4e3a\u7528\u6237\u63d0\u4f9b\u76f8\u5e94\u7684\u81ea\u52a8\u8865\u5168\u5efa\u8bae\u3002 \u66f4\u65b0\u9ed8\u8ba4Context \u00b6 \u67e5\u770b\u5f53\u524d\u7684 context \u5217\u8868\uff1a kubectl config get-contexts \u8fd9\u4e2a\u547d\u4ee4\u4f1a\u5217\u51fa\u6240\u6709\u53ef\u7528\u7684 context \u5217\u8868\uff0c\u5e76\u6807\u8bb0\u51fa\u5f53\u524d\u6b63\u5728\u4f7f\u7528\u7684 context\u3002 \u7c7b\u4f3c\u4e0b\u9762\u7ed3\u679c\uff1a kubernetes-admin@kubernetes \u662fContext\u540d\u3002 kubernetes \u662f\u96c6\u7fa4\u540d\u3002 kubernetes-admin \u662f\u7528\u6237\u540d\u3002 \u5f53\u524d\u4f8b\u5b50\u4e2d\u6ca1\u6709\u6307\u5b9a\u540d\u79f0\u7a7a\u95f4\u3002 CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin \u66f4\u65b0context\u3002\u4f8b\u5982\uff0c\u66f4\u65b0context\u7684\u9ed8\u8ba4\u540d\u79f0\u7a7a\u95f4\u7b49\u3002 # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin \u5728\u4e0d\u540c\u7684context\u4e4b\u95f4\u5207\u6362\u3002 # Usage: kubectl config use-context # Switch to new context kubectl config use-context kubernetes-admin@kubernetes \u53c2\u8003\u8d44\u6599\uff1a * kubectl * commandline \u5b89\u88c5Helm \u00b6 Helm \u662f Kubernetes \u7684\u5305\u7ba1\u7406\u5de5\u5177\uff0c\u5b83\u4e0d\u968f Kubernetes \u4e00\u8d77\u63d0\u4f9b\u3002 Helm \u6709\u4e09\u4e2a\u6838\u5fc3\u6982\u5ff5\uff1a Chart\uff08\u56fe\u8868\uff09\u662f Helm \u7684\u8f6f\u4ef6\u5305\uff0c\u5b83\u5305\u542b\u4e86\u5728 Kubernetes \u96c6\u7fa4\u4e2d\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u3001\u5de5\u5177\u6216\u670d\u52a1\u6240\u9700\u7684\u6240\u6709\u8d44\u6e90\u5b9a\u4e49\u3002\u53ef\u4ee5\u5c06\u5176\u89c6\u4e3a Kubernetes \u7684 Homebrew \u516c\u5f0f\u3001Apt dpkg \u6216 Yum RPM \u6587\u4ef6\u7b49\u7b49\u3002 Repository\uff08\u4ed3\u5e93\uff09\u662f\u56fe\u8868\u53ef\u4ee5\u88ab\u6536\u96c6\u548c\u5171\u4eab\u7684\u5730\u65b9\uff0c\u7c7b\u4f3c\u4e8e Perl \u7684 CPAN \u5b58\u50a8\u5e93\u6216 Fedora \u7684\u8f6f\u4ef6\u5305\u6570\u636e\u5e93\uff0c\u4f46\u7528\u4e8e Kubernetes \u8f6f\u4ef6\u5305\u3002 Release\uff08\u53d1\u5e03\uff09\u662f\u5728 Kubernetes \u96c6\u7fa4\u4e2d\u8fd0\u884c\u7684\u56fe\u8868\u5b9e\u4f8b\u3002\u4e00\u4e2a\u56fe\u8868\u901a\u5e38\u53ef\u4ee5\u5728\u540c\u4e00\u96c6\u7fa4\u4e2d\u5b89\u88c5\u591a\u6b21\uff0c\u5e76\u4e14\u6bcf\u6b21\u5b89\u88c5\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u53d1\u5e03\u3002\u4ee5 MySQL \u56fe\u8868\u4e3a\u4f8b\uff0c\u5982\u679c\u60f3\u8981\u5728\u96c6\u7fa4\u4e2d\u8fd0\u884c\u4e24\u4e2a\u6570\u636e\u5e93\uff0c\u5219\u53ef\u4ee5\u5b89\u88c5\u8be5\u56fe\u8868\u4e24\u6b21\uff0c\u6bcf\u6b21\u5b89\u88c5\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u53d1\u5e03\uff0c\u6bcf\u4e2a\u53d1\u5e03\u90fd\u6709\u81ea\u5df1\u7684\u53d1\u5e03\u540d\u79f0\u3002 \u53c2\u8003\u6587\u6863\uff1a installation guide binary release source code . Helm\u5ba2\u6237\u7aef\u5b89\u88c5\uff1a curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh \u8fd0\u884c\u7ed3\u679c\uff1a Downloading https://get.helm.sh/helm-v3.9.1-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm \u63d0\u793a\uff1a * helm init \u5728Helm 3\u4e2d\u5df2\u53d6\u6d88\uff0c\u4e14Tiller\u4e5f\u4e00\u540c\u53d6\u6d88\u3002\u4eca\u540e\u5728\u96c6\u7fa4\u4e2d\u4f7f\u7528Helm\u65f6\u4e0d\u518d\u9700\u8981\u5b89\u88c5Tiller\u3002 * helm search \u53ef\u4ee5\u7528\u6765\u641c\u7d22\u4e24\u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u8d44\u6e90\uff1a * helm search hub \u5728 Artifact Hub \u4e2d\u641c\u7d22\uff0c\u8fd9\u4e2ahub\u91cc\u5217\u51fa\u6765\u81ea\u6570\u5341\u4e2a\u4e0d\u540c\u4ed3\u5e93\u7684 Helm Chart\u3002 * helm search repo \u547d\u4ee4\u7528\u4e8e\u641c\u7d22\u5df2\u6dfb\u52a0\u5230\u672c\u5730 Helm \u5ba2\u6237\u7aef\u7684\u4ed3\u5e93\uff08\u4f7f\u7528 helm repo add \u547d\u4ee4\uff09\u3002\u6b64\u641c\u7d22\u662f\u5728\u672c\u5730\u6570\u636e\u4e0a\u8fdb\u884c\u7684\uff0c\u4e0d\u9700\u8981\u516c\u5171\u7f51\u7edc\u8fde\u63a5\u3002 \u53c2\u8003\u8d44\u6599\uff1a Helming development \u91cd\u7f6e\u96c6\u7fa4 \u00b6 \u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u64cd\u4f5c\u4f1a\u91cd\u7f6e\u5f53\u524d\u96c6\u7fa4\uff08\u5220\u9664\u96c6\u7fa4\uff09\u3002 \u5220\u9664\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u3002 kubeadm reset \u6e05\u9664 iptables \u4e2d\u5df2\u5b9a\u4e49\u7684\u89c4\u5219\u3002 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u6e05\u9664 IPVS \u4e2d\u5b9a\u4e49\u7684\u89c4\u5219\uff08\u5982\u679c\u4f7f\u7528 IPVS \uff09\u3002 ipvsadm --clear","title":"\u591a\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/multiple-local/#cka2kubernetes","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb02:\u591a\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/multiple-local/#_1","text":"\u5728\u672c\u5730Windows\u73af\u5883\u4e2d\uff0c\u901a\u8fc7VMWare\u5b89\u88c5\u4e09\u53f0Ubuntu\u865a\u62df\u673a\u3002\u5728Ubuntu\u865a\u62df\u673a\u4e2d\u5b89\u88c5\u57fa\u4e8eContainerd\u7684Kubernetes\u7cfb\u7edf\uff0c\u5e76\u5206\u522b\u914d\u7f6e\u4e00\u4e2a\u4e3b\u8282\u70b9Master\u548c\u4e24\u4e2a\u5de5\u4f5c\u8282\u70b9Worker\u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/installation/multiple-local/#_2","text":"VMWare \u8bbe\u7f6e VMnet1: host-only\u6a21\u5f0f, \u7f51\u7edcsubnet: 192.168.150.0/24 VMnet8: NAT\u6a21\u5f0f, \u7f51\u7edcsubnet: 11.0.1.0/24 \u901a\u8fc7VMWare\u521b\u5efa\u5ba2\u6237\u865a\u62df\u673a\u3002 \u5185\u5b58\uff1a4 GB CPU\uff1a1 CPUs with 2 Cores \u64cd\u4f5c\u7cfb\u7edf\uff1aUbuntu Server 22.04 \u7f51\u7edc\uff1aNAT \u63d0\u793a\uff1a \u5f53\u524d\u7ec3\u4e60\u4e2d\uff0cKubernetes\u662f\u57fa\u4e8eContainerd\uff0c\u4e0d\u662fDocker\u3002","title":"\u672c\u5730\u865a\u62df\u673a\u8bbe\u7f6e"},{"location":"k8s/cka_cn/installation/multiple-local/#ubuntu","text":"\u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u4efb\u52a1\uff0c\u9700\u8981\u5728\u6bcf\u53f0\u865a\u62df\u673a\u4e2d\u6267\u884c\u4e00\u6b21\u3002\u4ee5\u4e0b\u7b80\u79f0\u865a\u62df\u673a\u4e3a\u8282\u70b9\u3002 \u5728\u6240\u6709\u8282\u70b9\u4e2d\u521b\u5efa\u7528\u6237 vagrant \u3002 sudo adduser vagrant sudo usermod -g sudo vagrant sudo usermod -a -G root vagrant sudo passwd vagrant \u5728\u6240\u6709\u8282\u70b9\u4e2d\u8bbe\u7f6e\u7528\u6237 root \u7684\u5bc6\u7801\u3002 sudo passwd root \u4fee\u6539ssh\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6\u3002\u5f00\u653e root \u7528\u6237\u901a\u8fc7ssh\u767b\u5f55\uff08\u9ed8\u8ba4\u662f\u7981\u7528\u7684\uff09\u3002 sudo vi /etc/ssh/sshd_config \u628a\u53c2\u6570 PermitRootLogin \u7684\u503c\u4ece prohibit-password \u6539\u4e3a yes \u3002 PermitRootLogin yes # PermitRootLogin prohibit-password \u91cd\u65b0\u542f\u52a8sshd\u670d\u52a1\u3002 sudo systemctl restart sshd \u66f4\u6539\u4e3b\u673a\u540d\uff0c\u8fd9\u91cc\u662f ubu1 . sudo hostnamectl set-hostname ubu1 sudo hostnamectl set-hostname ubu1 --pretty \u9a8c\u8bc1\u4e3b\u673a\u540d\u662f\u5426\u88ab\u6b63\u786e\u4fee\u6539\u4e86\uff0c\u6bd4\u5982\u6539\u4e3a ubu1 \u3002 cat /etc/machine-info \u9a8c\u8bc1\u4e3b\u673a\u540d\u662f\u5426\u88ab\u6b63\u786e\u4fee\u6539\u4e86\uff0c\u6bd4\u5982\u6539\u4e3a ubu1 \u3002 cat /etc/hostname \u9a8c\u8bc1\u4e3b\u673aIP\u5730\u5740 127.0.1.1 \u5df2\u7ecf\u914d\u7f6e\u7ed9\u5f53\u524d\u8282\u70b9\uff0c\u6bd4\u5982 ubu1 \u3002\u540c\u65f6\uff0c\u5728\u6240\u6709\u8282\u70b9\u7684 /etc/hosts \u6587\u4ef6\u4e2d\u6dfb\u52a0\u5176\u4ed6\u8282\u70b9\u7684IP\u548c\u4e3b\u673a\u5bf9\u5e94\u4fe1\u606f\u3002 sudo vi /etc/hosts \u4ee5\u5f53\u524d\u7ec3\u4e60\u4e3a\u4f8b\uff0c\u4fee\u6539\u540e\u7684 /etc/hosts \u6587\u4ef6\u7c7b\u4f3c\u5982\u4e0b\u5185\u5bb9\u3002 127.0.1.1 ubu1 11.0.1.129 ubu1 11.0.1.130 ubu2 11.0.1.131 ubu3 11.0.1.132 ubu4 \u521b\u5efa\u6587\u4ef6 /etc/netplan/00-installer-config.yaml \u3002 sudo vi /etc/netplan/00-installer-config.yaml \u66f4\u65b0\u6b64\u6587\u4ef6\uff0c\u8bbe\u5b9a\u5f53\u524d\u8282\u70b9\u4f7f\u7528\u56fa\u5b9aIP\u5730\u5740\uff0c\u6bd4\u5982\uff0c 11.0.1.129 \u3002 network : ethernets : ens33 : dhcp4 : false addresses : - 11.0.1.129/24 nameservers : addresses : - 11.0.1.2 routes : - to : default via : 11.0.1.2 version : 2 \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u65f6\uff0c\u4f7f\u4e0a\u8ff0\u6539\u52a8\u751f\u6548\u3002\u6ce8\u610f\uff0c\u5f53\u524dssh\u8fde\u63a5\u4f1a\u56e0\u6b64\u800c\u65ad\u5f00\u3002 sudo netplan apply \u5728\u6240\u6709\u8282\u70b9\u7981\u7528\u4ea4\u6362\u5206\u533aswap\u548c\u9632\u706b\u5899firewall\u3002 sudo swapoff -a sudo ufw disable sudo ufw status verbose \u5728\u6240\u6709\u8282\u70b9\u7684\u6587\u4ef6 /etc/fstab \u4e2d\u6ce8\u91ca\u6389\u6d89\u53caswap\u7684\u90a3\u4e00\u884c\uff0c\u4fee\u6539\u540e\u9700\u8981\u91cd\u542f\u5f53\u524d\u8282\u70b9\u3002 sudo vi /etc/fstab \u4fee\u6539\u540e\u7684\u7ed3\u679c\u7c7b\u4f3c\u5982\u4e0b\u3002 /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 \u5728\u6240\u6709\u8282\u70b9\u8bbe\u7f6e\u7edf\u4e00\u7684\u65f6\u533a\u3002 sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo cp /etc/profile /etc/profile.bak echo 'LANG=\"en_US.UTF-8\"' | sudo tee -a /etc/profile source /etc/profile \u6267\u884c\u547d\u4ee4 ll /etc/localtime \u6765\u9a8c\u8bc1\u65f6\u533a\u662f\u5426\u4fee\u6539\u6b63\u786e\u3002 lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai \u5728\u6240\u6709\u8282\u70b9\u4fee\u6539\u5185\u6838\u8bbe\u7f6e\u3002 cat < /etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF \u68c0\u67e5\u5f53\u524d kubeadm \u7684\u7248\u672c\u3002 apt policy kubeadm \u5b89\u88c5 1.24.1-00 \u7248\u672c\u7684 kubeadm . sudo apt-get -y install kubelet = 1 .24.1-00 kubeadm = 1 .24.1-00 kubectl = 1 .24.1-00 --allow-downgrades","title":"\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/multiple-local/#_3","text":"","title":"\u914d\u7f6e\u4e3b\u8282\u70b9"},{"location":"k8s/cka_cn/installation/multiple-local/#kubeadm","text":"\u5728\u627f\u62c5\u4e3b\u8282\u70b9\u7684\u865a\u62df\u673a\u91cc\u914d\u7f6e\u63a7\u5236\u5e73\u9762\uff08Control Plane\uff09\u3002 \u68c0\u67e5 kubeadm \u5f53\u524d\u9ed8\u8ba4\u914d\u7f6e\u53c2\u6570\u3002 kubeadm config print init-defaults \u7c7b\u4f3c\u7ed3\u679c\u5982\u4e0b\u3002\u4fdd\u5b58\u9ed8\u8ba4\u914d\u7f6e\u7684\u7ed3\u679c\uff0c\u540e\u7eed\u4f1a\u4f5c\u4e3a\u53c2\u8003\u3002 apiVersion : kubeadm.k8s.io/v1beta3 bootstrapTokens : - groups : - system:bootstrappers:kubeadm:default-node-token token : abcdef.0123456789abcdef ttl : 24h0m0s usages : - signing - authentication kind : InitConfiguration localAPIEndpoint : advertiseAddress : 1.2.3.4 bindPort : 6443 nodeRegistration : criSocket : unix:///var/run/containerd/containerd.sock imagePullPolicy : IfNotPresent name : node taints : null --- apiServer : timeoutForControlPlane : 4m0s apiVersion : kubeadm.k8s.io/v1beta3 certificatesDir : /etc/kubernetes/pki clusterName : kubernetes controllerManager : {} dns : {} etcd : local : dataDir : /var/lib/etcd imageRepository : k8s.gcr.io kind : ClusterConfiguration kubernetesVersion : 1.24.0 networking : dnsDomain : cluster.local serviceSubnet : 10.96.0.0/12 scheduler : {} \u6a21\u62df\u5b89\u88c5\u548c\u6b63\u5f0f\u5b89\u88c5\u3002 \u901a\u8fc7\u547d\u4ee4 kubeadm init \u8fdb\u884c\u4e3b\u8282\u70b9\u7684\u521d\u59cb\u5316\uff0c\u4e0b\u9762\u662f\u8fd9\u4e2a\u547d\u4ee4\u4e3b\u8981\u53c2\u6570\u7684\u8bf4\u660e\uff0c\u7279\u522b\u662f\u7f51\u7edc\u53c2\u6570\u7684\u4e09\u4e2a\u9009\u62e9\u3002 --pod-network-cidr : \u6307\u5b9apod\u4f7f\u7528\u7684IP\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u6307\u5b9a\u4e86\u8be5\u53c2\u6570\uff0c\u5219Control Plane\u4f1a\u81ea\u52a8\u8bb2\u6307\u5b9a\u7684CIDR\u5206\u914d\u7ed9\u6bcf\u4e2a\u8282\u70b9\u3002 IP\u5730\u5740\u6bb5 10.244.0.0/16 \u662fFlannel\u7f51\u7edc\u7ec4\u4ef6\u9ed8\u8ba4\u7684\u5730\u5740\u8303\u56f4\u3002\u5982\u679c\u9700\u8981\u4fee\u6539Flannel\u7684IP\u5730\u5740\u6bb5\uff0c\u9700\u8981\u5728\u8fd9\u91cc\u6307\u5b9a\uff0c\u4e14\u5728\u90e8\u7f72Flannel\u65f6\u4e5f\u8981\u4fdd\u6301\u4e00\u81f4\u7684IP\u6bb5\u3002 --apiserver-bind-port : API\u670d\u52a1\uff08API Server\uff09\u7684\u7aef\u53e3\uff0c\u9ed8\u8ba4\u65f66443\u3002 --service-cidr : \u6307\u5b9a\u670d\u52a1\uff08service\uff09\u7684IP\u5730\u5740\u6bb5\uff0c\u9ed8\u8ba4\u662f 10.96.0.0/12 \u3002 \u63d0\u793a\uff1a \u670d\u52a1VIPs\uff08service VIPs\uff09\uff0c\u4e5f\u79f0\u4f5c\u96c6\u7fa4IP\uff08Cluster IP\uff09\uff0c\u901a\u8fc7\u53c2\u6570 --service-cidr \u6307\u5b9a\u3002 podCIDR\uff0c\u4e5f\u79f0\u4e3aendpoint IP\uff0c\u901a\u8fc7\u53c2\u6570 --pod-network-cidr \u6307\u5b9a\u3002 \u67094\u79cd\u5178\u578b\u7684\u7f51\u7edc\u95ee\u9898\uff1a \u9ad8\u5ea6\u8026\u5408\u7684\u5bb9\u5668\u4e0e\u5bb9\u5668\u4e4b\u95f4\u7684\u901a\u4fe1\uff1a\u8fd9\u53ef\u4ee5\u901a\u8fc7Pod\uff08podCIDR\uff09\u548c\u672c\u5730\u4e3b\u673a\u901a\u4fe1\u6765\u89e3\u51b3\u3002 Pod\u5bf9Pod\u901a\u4fe1\uff08Pod-to-Pod\uff09\uff1a \u4e5f\u88ab\u79f0\u4e3a\u5bb9\u5668\u5bf9\u5bb9\u5668\u901a\u4fe1\uff08container-to-container\uff09\u3002 \u5728Flannel\u7f51\u7edc\u63d2\u4ef6\u4e2d\u7684\u793a\u4f8b\u6d41\u7a0b\u662f\uff1aPod \u2192 veth\u5bf9 \u2192 cni0 \u2192 flannel.1 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 \u5bbf\u4e3b\u673aeth0 \u2192 flannel.1 \u2192 cni0 \u2192 veth\u5bf9 \u2192 Pod\u3002 Pod\u5bf9Service\u901a\u4fe1\uff08Pod-to-Service\uff09\uff1a \u6d41\u7a0b: Pod \u2192 \u5185\u6838 \u2192 Service iptables \u2192 Service \u2192 Pod iptables \u2192 Pod\u3002 \u5916\u90e8\u5bf9Service\u901a\u4fe1\uff08External-to-Service\uff09\uff1a \u8d1f\u8f7d\u5747\u8861\u5668: SLB \u2192 NodePort \u2192 Service \u2192 Pod\u3002 kube-proxy \u662f\u5bf9iptables\u8d1f\u8d23\uff0c\u4e0d\u662f\u7f51\u7edc\u6d41\u91cf\uff08traffic\uff09\u3002 kube-proxy \u662fKubernetes\u96c6\u7fa4\u4e2d\u7684\u4e00\u4e2a\u7ec4\u4ef6\uff0c\u8d1f\u8d23\u4e3aService\u63d0\u4f9b\u4ee3\u7406\u670d\u52a1\uff0c\u540c\u65f6\u4e5f\u662fKubernetes\u7f51\u7edc\u6a21\u578b\u4e2d\u7684\u91cd\u8981\u7ec4\u6210\u90e8\u5206\u4e4b\u4e00\u3002 kube-proxy \u4f1a\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u542f\u52a8\u4e00\u4e2a\u4ee3\u7406\u8fdb\u7a0b\uff0c\u901a\u8fc7\u76d1\u542cKubernetes API Server\u7684Service\u548cEndpoint\u7684\u53d8\u5316\u6765\u7ef4\u62a4\u4e00\u4e2a\u672c\u5730\u7684Service\u548cEndpoint\u7684\u7f13\u5b58\u3002\u5f53\u6709\u8bf7\u6c42\u5230\u8fbe\u67d0\u4e2aService\u65f6\uff0c kube-proxy \u4f1a\u6839\u636e\u8be5Service\u7684\u7c7b\u578b\uff08ClusterIP\u3001NodePort\u3001LoadBalancer\u3001ExternalName\uff09\u548c\u7aef\u53e3\u53f7\uff0c\u751f\u6210\u76f8\u5e94\u7684iptables\u89c4\u5219\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u7ed9Service\u6240\u4ee3\u7406\u7684\u540e\u7aefPod\u3002 iptables\u662fLinux\u7cfb\u7edf\u4e2d\u7684\u4e00\u4e2a\u91cd\u8981\u7f51\u7edc\u5de5\u5177\uff0c\u53ef\u4ee5\u8bbe\u7f6eIP\u5305\u7684\u8fc7\u6ee4\u3001\u8f6c\u53d1\u548c\u4fee\u6539\u89c4\u5219\uff0c\u53ef\u4ee5\u5b9e\u73b0\u7f51\u7edc\u5c42\u7684\u9632\u706b\u5899\u3001NAT\u7b49\u529f\u80fd\u3002\u5728Kubernetes\u96c6\u7fa4\u4e2d\uff0c kube-proxy \u901a\u8fc7\u751f\u6210\u548c\u66f4\u65b0iptables\u89c4\u5219\uff0c\u6765\u5b9e\u73b0Service\u548cEndpoint\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u5177\u4f53\u6765\u8bf4\uff0ckube-proxy\u4f1a\u4e3a\u6bcf\u4e2aService\u521b\u5efa\u4e09\u6761iptables\u89c4\u5219\u94fe\uff08nat\u8868\u4e2d\u7684KUBE-SERVICES\u548cKUBE-NODEPORTS\u94fe\uff0c\u4ee5\u53cafilter\u8868\u4e2d\u7684KUBE-SVC-XXXXX\u94fe\uff09\uff0c\u901a\u8fc7\u8fd9\u4e9b\u89c4\u5219\u94fe\uff0c\u5c06\u8bf7\u6c42\u8f6c\u53d1\u5230\u76f8\u5e94\u7684Pod\u6216\u8005Service\u4e0a\u3002 \u56e0\u6b64\uff0c kube-proxy \u548ciptables\u662f\u7d27\u5bc6\u76f8\u5173\u7684\u4e24\u4e2a\u7ec4\u4ef6\uff0c\u901a\u8fc7iptables\u89c4\u5219\u6765\u5b9e\u73b0Service\u548cPod\u4e4b\u95f4\u7684\u8f6c\u53d1\u548c\u4ee3\u7406\u3002\u8fd9\u79cd\u5b9e\u73b0\u65b9\u5f0f\u5177\u6709\u53ef\u6269\u5c55\u6027\u548c\u9ad8\u53ef\u7528\u6027\uff0c\u540c\u65f6\u4e5f\u63d0\u4f9b\u4e86\u4e00\u79cd\u7075\u6d3b\u7684\u7f51\u7edc\u6a21\u578b\uff0c\u53ef\u4ee5\u65b9\u4fbf\u5730\u5b9e\u73b0\u670d\u52a1\u53d1\u73b0\u3001\u8d1f\u8f7d\u5747\u8861\u7b49\u529f\u80fd\u3002 sudo kubeadm init \\ --dry-run \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr = 192 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr = 192 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0","title":"kubeadm\u521d\u59cb\u5316"},{"location":"k8s/cka_cn/installation/multiple-local/#kubeconfig","text":"\u7ed9\u5f53\u524d\u5b89\u88c5\u7528\u6237\u914d\u7f6e kubeconfig \u6587\u4ef6\uff08\u5f53\u524d\u4f8b\u5b50\u662f\u7528\u6237 vagrant \uff09\u3002 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Kubernetes \u63d0\u4f9b\u4e86\u4e00\u4e2a\u547d\u4ee4\u884c\u5de5\u5177 kubectl \uff0c\u7528\u4e8e\u4f7f\u7528 Kubernetes API \u4e0e Kubernetes \u96c6\u7fa4\u7684\u63a7\u5236\u5e73\u9762\u8fdb\u884c\u901a\u4fe1\u3002 kubectl \u63a7\u5236 Kubernetes cluster manager \uff08\u96c6\u7fa4\u7ba1\u7406\u5668\uff09\u3002 \u5bf9\u4e8e\u914d\u7f6e\uff0ckubectl \u5728 $HOME/.kube \u76ee\u5f55\u4e2d\u67e5\u627e\u4e00\u4e2a\u540d\u4e3a config \u7684\u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u662f\u7531 kubeadm init \u751f\u6210\u7684\u6587\u4ef6 /etc/kubernetes/admin.conf \u7684\u526f\u672c\u3002 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e KUBECONFIG \u73af\u5883\u53d8\u91cf\u6216\u8bbe\u7f6e --kubeconfig flag \u6807\u5fd7\u6765\u6307\u5b9a\u5176\u4ed6 kubeconfig \u6587\u4ef6\u3002\u5982\u679c KUBECONFIG \u73af\u5883\u53d8\u91cf\u4e0d\u5b58\u5728\uff0ckubectl \u5c06\u4f7f\u7528\u9ed8\u8ba4\u7684 kubeconfig \u6587\u4ef6 $HOME/.kube/config \u3002 kubeconfig \u6587\u4ef6\u4e2d\u7684 context\uff08\u4e0a\u4e0b\u6587\uff09 \u5143\u7d20\u7528\u4e8e\u5c06\u8bbf\u95ee\u53c2\u6570\u5206\u7ec4\u5230\u4e00\u4e2a\u65b9\u4fbf\u7684\u540d\u79f0\u4e0b\u3002\u6bcf\u4e2a\u4e0a\u4e0b\u6587\u90fd\u6709\u4e09\u4e2a\u53c2\u6570\uff1a\u96c6\u7fa4\u3001\u547d\u540d\u7a7a\u95f4\u548c\u7528\u6237\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0ckubectl \u547d\u4ee4\u884c\u5de5\u5177\u4f7f\u7528\u5f53\u524d\u4e0a\u4e0b\u6587\u4e2d\u7684\u53c2\u6570\u4e0e\u96c6\u7fa4\u901a\u4fe1\u3002 \u6587\u4ef6 .kube/config \u7684\u4f8b\u5b50\uff1a apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : \u8bfb\u53d6\u5f53\u524d\u4e0a\u4e0b\u6587\uff1a kubectl config get-contexts \u8fd0\u884c\u7ed3\u679c\uff1a CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin","title":"kubeconfig\u6587\u4ef6"},{"location":"k8s/cka_cn/installation/multiple-local/#calico","text":"\u53c2\u8003\u5b89\u88c5\u6307\u5bfc End-to-end Calico installation \u3002 \u5feb\u901f\u5b89\u88c5\u624b\u518c QuickStart \u5b89\u88c5 Calico\uff1a kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/tigera-operator.yaml \u8fd0\u884c\u7ed3\u679c\uff1a namespace/tigera-operator created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/apiservers.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/imagesets.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/installations.operator.tigera.io created customresourcedefinition.apiextensions.k8s.io/tigerastatuses.operator.tigera.io created serviceaccount/tigera-operator created clusterrole.rbac.authorization.k8s.io/tigera-operator created clusterrolebinding.rbac.authorization.k8s.io/tigera-operator created deployment.apps/tigera-operator created kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.25.1/manifests/calicoctl.yaml \u8fd0\u884c\u7ed3\u679c\uff1a serviceaccount/calicoctl created pod/calicoctl created clusterrole.rbac.authorization.k8s.io/calicoctl created clusterrolebinding.rbac.authorization.k8s.io/calicoctl created \u9a8c\u8bc1Calico\u7684\u72b6\u6001\u3002Calico\u7684\u521d\u59cb\u5316\u8fc7\u7a0b\u53ef\u80fd\u9700\u8981\u51e0\u5206\u949f\u65f6\u95f4\u5b8c\u6210\u3002 kubectl get pod -n kube-system | grep calico \u8fd0\u884c\u7ed3\u679c\uff1a calico-kube-controllers-555bc4b957-l8bn2 0/1 Pending 0 28s calico-node-255pc 0/1 Init:1/3 0 29s calico-node-7tmnb 0/1 Init:1/3 0 29s calico-node-w8nvl 0/1 Init:1/3 0 29s \u9a8c\u8bc1\u7f51\u7edc\u72b6\u6001\u3002 sudo nerdctl network ls \u8fd0\u884c\u7ed3\u679c\uff1a NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 17f29b073143 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none","title":"\u5b89\u88c5Calico"},{"location":"k8s/cka_cn/installation/multiple-local/#_4","text":"\u4f7f\u7528 kubeadm token \u6765\u751f\u6210\u52a0\u5165\u96c6\u7fa4\u7684\u4ee4\u724c\uff08token\uff09\u548c\u54c8\u897f\u503c\uff08hash value\uff09\u3002 kubeadm token create --print-join-command \u547d\u4ee4\u7528\u6cd5\uff1a sudo kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> \u8fd0\u884c\u7ed3\u679c\uff1a [preflight] Running pre-flight checks [WARNING SystemVerification]: missing optional cgroups: blkio [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [kubelet-start] Writing kubelet configuration to file \"/var/lib/kubelet/config.yaml\" [kubelet-start] Writing kubelet environment file with flags to file \"/var/lib/kubelet/kubeadm-flags.env\" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster.","title":"\u914d\u7f6e\u5de5\u4f5c\u8282\u70b9"},{"location":"k8s/cka_cn/installation/multiple-local/#_5","text":"\u67e5\u770b Kubernetes \u96c6\u7fa4\u7684\u4fe1\u606f\uff0c\u5305\u62ec\u96c6\u7fa4 API Server \u7684\u5730\u5740\u3001Kubernetes DNS \u670d\u52a1\u7684\u5730\u5740\u7b49\u3002 kubectl cluster-info \u8fd0\u884c\u7ed3\u679c\uff1a bKubernetes control plane is running at https://11.0.1.129:6443 CoreDNS is running at https://11.0.1.129:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. \u5217\u51fa\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u7684\u8be6\u7ec6\u4fe1\u606f\uff0c\u5305\u62ec\u8282\u70b9\u540d\u79f0\u3001\u8282\u70b9 IP\u3001\u8282\u70b9\u6807\u7b7e\u3001\u8282\u70b9\u72b6\u6001\u7b49\u3002 kubectl get nodes -owide \u5217\u51fa Kubernetes \u96c6\u7fa4\u4e2d\u6240\u6709 Namespace \u4e0b\u7684 Pod\u3002 kubectl get pod -A","title":"\u68c0\u67e5\u96c6\u7fa4\u72b6\u6001"},{"location":"k8s/cka_cn/installation/multiple-local/#_6","text":"","title":"\u66f4\u65b0\u5b89\u88c5"},{"location":"k8s/cka_cn/installation/multiple-local/#bash","text":"\u5728\u6bcf\u4e2a\u8282\u70b9\u4e0a\u914d\u7f6eBash\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 \u53c2\u8003 \u6307\u5bfc \u8bbe\u7f6e kubectl \u81ea\u52a8\u8865\u5168\u529f\u80fdauto-completion \u3002 apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc source ~/.bashrc","title":"Bash\u81ea\u52a8\u8865\u5168"},{"location":"k8s/cka_cn/installation/multiple-local/#_7","text":"\u5982\u679c\u6211\u4eec\u4e3a kubectl \u8bbe\u7f6e\u4e00\u4e2a\u522b\u540d\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u4e00\u4e9b\u65b9\u6cd5\u6765\u6269\u5c55 shell \u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u4f7f\u5176\u80fd\u591f\u4e0e\u8be5\u522b\u540d\u4e00\u8d77\u4f7f\u7528\u3002 \u4e00\u79cd\u65b9\u6cd5\u662f\u5728 Bash shell \u914d\u7f6e\u6587\u4ef6\uff08\u5982 .bashrc \u6216 .bash_profile\uff09\u4e2d\u8bbe\u7f6e\u522b\u540d\uff0c\u5e76\u4e3a\u8be5\u522b\u540d\u6307\u5b9a kubectl \u7684\u5b8c\u6574\u8def\u5f84\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a alias k = 'path/to/kubectl' \u7136\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u547d\u4ee4\u91cd\u65b0\u52a0\u8f7d .bashrc \u6587\u4ef6\uff1a source ~/.bashrc \u63a5\u4e0b\u6765\uff0c\u53ef\u4ee5\u4f7f\u7528 k \u547d\u4ee4\u6765\u4ee3\u66ff kubectl \u547d\u4ee4\uff0c\u5e76\u5728\u5176\u540e\u9762\u6dfb\u52a0\u76f8\u5e94\u7684\u53c2\u6570\u548c\u9009\u9879\u3002\u5f53\u4f7f\u7528\u81ea\u52a8\u8865\u5168\u529f\u80fd\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u5c06 k \u522b\u540d\u8f6c\u6362\u4e3a kubectl \u7684\u5b8c\u6574\u8def\u5f84\uff0c\u5e76\u5bf9\u5176\u8fdb\u884c\u81ea\u52a8\u8865\u5168\u3002 \u53e6\u4e00\u79cd\u65b9\u6cd5\u662f\u4f7f\u7528 Bash shell \u5185\u7f6e\u7684 complete \u51fd\u6570\u6765\u4e3a\u522b\u540d\u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002\u4f8b\u5982\uff0c\u53ef\u4ee5\u5728 .bashrc \u6587\u4ef6\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u5185\u5bb9\uff1a echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc \u8fd9\u5c06\u4e3a\u522b\u540d k \u8bbe\u7f6e\u81ea\u52a8\u8865\u5168\u529f\u80fd\uff0c\u5e76\u5c06\u5176\u4e0e kubectl \u7684\u81ea\u52a8\u8865\u5168\u51fd\u6570 __start_kubectl \u5173\u8054\u8d77\u6765\u3002\u8fd9\u6837\uff0c\u5f53\u7528\u6237\u5728 k \u547d\u4ee4\u540e\u8f93\u5165Tab\u952e\u65f6\uff0cBash shell \u4f1a\u81ea\u52a8\u8c03\u7528 __start_kubectl \u51fd\u6570\uff0c\u5e76\u4e3a\u7528\u6237\u63d0\u4f9b\u76f8\u5e94\u7684\u81ea\u52a8\u8865\u5168\u5efa\u8bae\u3002","title":"\u522b\u540d"},{"location":"k8s/cka_cn/installation/multiple-local/#context","text":"\u67e5\u770b\u5f53\u524d\u7684 context \u5217\u8868\uff1a kubectl config get-contexts \u8fd9\u4e2a\u547d\u4ee4\u4f1a\u5217\u51fa\u6240\u6709\u53ef\u7528\u7684 context \u5217\u8868\uff0c\u5e76\u6807\u8bb0\u51fa\u5f53\u524d\u6b63\u5728\u4f7f\u7528\u7684 context\u3002 \u7c7b\u4f3c\u4e0b\u9762\u7ed3\u679c\uff1a kubernetes-admin@kubernetes \u662fContext\u540d\u3002 kubernetes \u662f\u96c6\u7fa4\u540d\u3002 kubernetes-admin \u662f\u7528\u6237\u540d\u3002 \u5f53\u524d\u4f8b\u5b50\u4e2d\u6ca1\u6709\u6307\u5b9a\u540d\u79f0\u7a7a\u95f4\u3002 CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin \u66f4\u65b0context\u3002\u4f8b\u5982\uff0c\u66f4\u65b0context\u7684\u9ed8\u8ba4\u540d\u79f0\u7a7a\u95f4\u7b49\u3002 # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin \u5728\u4e0d\u540c\u7684context\u4e4b\u95f4\u5207\u6362\u3002 # Usage: kubectl config use-context # Switch to new context kubectl config use-context kubernetes-admin@kubernetes \u53c2\u8003\u8d44\u6599\uff1a * kubectl * commandline","title":"\u66f4\u65b0\u9ed8\u8ba4Context"},{"location":"k8s/cka_cn/installation/multiple-local/#helm","text":"Helm \u662f Kubernetes \u7684\u5305\u7ba1\u7406\u5de5\u5177\uff0c\u5b83\u4e0d\u968f Kubernetes \u4e00\u8d77\u63d0\u4f9b\u3002 Helm \u6709\u4e09\u4e2a\u6838\u5fc3\u6982\u5ff5\uff1a Chart\uff08\u56fe\u8868\uff09\u662f Helm \u7684\u8f6f\u4ef6\u5305\uff0c\u5b83\u5305\u542b\u4e86\u5728 Kubernetes \u96c6\u7fa4\u4e2d\u8fd0\u884c\u5e94\u7528\u7a0b\u5e8f\u3001\u5de5\u5177\u6216\u670d\u52a1\u6240\u9700\u7684\u6240\u6709\u8d44\u6e90\u5b9a\u4e49\u3002\u53ef\u4ee5\u5c06\u5176\u89c6\u4e3a Kubernetes \u7684 Homebrew \u516c\u5f0f\u3001Apt dpkg \u6216 Yum RPM \u6587\u4ef6\u7b49\u7b49\u3002 Repository\uff08\u4ed3\u5e93\uff09\u662f\u56fe\u8868\u53ef\u4ee5\u88ab\u6536\u96c6\u548c\u5171\u4eab\u7684\u5730\u65b9\uff0c\u7c7b\u4f3c\u4e8e Perl \u7684 CPAN \u5b58\u50a8\u5e93\u6216 Fedora \u7684\u8f6f\u4ef6\u5305\u6570\u636e\u5e93\uff0c\u4f46\u7528\u4e8e Kubernetes \u8f6f\u4ef6\u5305\u3002 Release\uff08\u53d1\u5e03\uff09\u662f\u5728 Kubernetes \u96c6\u7fa4\u4e2d\u8fd0\u884c\u7684\u56fe\u8868\u5b9e\u4f8b\u3002\u4e00\u4e2a\u56fe\u8868\u901a\u5e38\u53ef\u4ee5\u5728\u540c\u4e00\u96c6\u7fa4\u4e2d\u5b89\u88c5\u591a\u6b21\uff0c\u5e76\u4e14\u6bcf\u6b21\u5b89\u88c5\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u53d1\u5e03\u3002\u4ee5 MySQL \u56fe\u8868\u4e3a\u4f8b\uff0c\u5982\u679c\u60f3\u8981\u5728\u96c6\u7fa4\u4e2d\u8fd0\u884c\u4e24\u4e2a\u6570\u636e\u5e93\uff0c\u5219\u53ef\u4ee5\u5b89\u88c5\u8be5\u56fe\u8868\u4e24\u6b21\uff0c\u6bcf\u6b21\u5b89\u88c5\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u53d1\u5e03\uff0c\u6bcf\u4e2a\u53d1\u5e03\u90fd\u6709\u81ea\u5df1\u7684\u53d1\u5e03\u540d\u79f0\u3002 \u53c2\u8003\u6587\u6863\uff1a installation guide binary release source code . Helm\u5ba2\u6237\u7aef\u5b89\u88c5\uff1a curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh \u8fd0\u884c\u7ed3\u679c\uff1a Downloading https://get.helm.sh/helm-v3.9.1-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm \u63d0\u793a\uff1a * helm init \u5728Helm 3\u4e2d\u5df2\u53d6\u6d88\uff0c\u4e14Tiller\u4e5f\u4e00\u540c\u53d6\u6d88\u3002\u4eca\u540e\u5728\u96c6\u7fa4\u4e2d\u4f7f\u7528Helm\u65f6\u4e0d\u518d\u9700\u8981\u5b89\u88c5Tiller\u3002 * helm search \u53ef\u4ee5\u7528\u6765\u641c\u7d22\u4e24\u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u8d44\u6e90\uff1a * helm search hub \u5728 Artifact Hub \u4e2d\u641c\u7d22\uff0c\u8fd9\u4e2ahub\u91cc\u5217\u51fa\u6765\u81ea\u6570\u5341\u4e2a\u4e0d\u540c\u4ed3\u5e93\u7684 Helm Chart\u3002 * helm search repo \u547d\u4ee4\u7528\u4e8e\u641c\u7d22\u5df2\u6dfb\u52a0\u5230\u672c\u5730 Helm \u5ba2\u6237\u7aef\u7684\u4ed3\u5e93\uff08\u4f7f\u7528 helm repo add \u547d\u4ee4\uff09\u3002\u6b64\u641c\u7d22\u662f\u5728\u672c\u5730\u6570\u636e\u4e0a\u8fdb\u884c\u7684\uff0c\u4e0d\u9700\u8981\u516c\u5171\u7f51\u7edc\u8fde\u63a5\u3002 \u53c2\u8003\u8d44\u6599\uff1a Helming development","title":"\u5b89\u88c5Helm"},{"location":"k8s/cka_cn/installation/multiple-local/#_8","text":"\u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u64cd\u4f5c\u4f1a\u91cd\u7f6e\u5f53\u524d\u96c6\u7fa4\uff08\u5220\u9664\u96c6\u7fa4\uff09\u3002 \u5220\u9664\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u3002 kubeadm reset \u6e05\u9664 iptables \u4e2d\u5df2\u5b9a\u4e49\u7684\u89c4\u5219\u3002 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u6e05\u9664 IPVS \u4e2d\u5b9a\u4e49\u7684\u89c4\u5219\uff08\u5982\u679c\u4f7f\u7528 IPVS \uff09\u3002 ipvsadm --clear","title":"\u91cd\u7f6e\u96c6\u7fa4"},{"location":"k8s/cka_cn/installation/single-local/","text":"CKA\u81ea\u5b66\u7b14\u8bb01:\u5355\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes \u00b6 \u6458\u8981 \u00b6 \u5728\u672c\u5730Windows\u73af\u5883\u4e2d\uff0c\u901a\u8fc7VMWare\u5b89\u88c5Ubuntu\u865a\u62df\u673a\u3002\u5728Ubuntu\u865a\u62df\u673a\u4e2d\u5b89\u88c5\u57fa\u4e8eDocker\u7684Kubernetes\u7cfb\u7edf\u3002\u5728\u8be5\u865a\u62df\u673a\u4e2d\u540c\u65f6\u914d\u7f6e\u4e3b\u8282\u70b9Master\u548c\u5de5\u4f5c\u8282\u70b9Worker\u3002 \u672c\u5730\u865a\u62df\u673a\u8bbe\u7f6e \u00b6 VMWare\u865a\u62df\u673a\u8bbe\u7f6e\u3002 VMnet1: host-only\u6a21\u5f0f, \u7f51\u7edcsubnet: 192.168.150.0/24 VMnet8: NAT\u6a21\u5f0f, \u7f51\u7edcsubnet: 11.0.1.0/24 \u901a\u8fc7VMWare\u521b\u5efa\u5ba2\u6237\u673a\u3002 \u5185\u5b58\uff1a4 GB CPU\uff1a2 CPUs with 2 Cores \u64cd\u4f5c\u7cfb\u7edf\uff1aUbuntu Server 22.04 \u7f51\u7edc\uff1aNAT Kubernetes\u8fd0\u884c\u5728Docker\u4e0a\u3002 Ubuntu\u9884\u914d\u7f6e \u00b6 \u521b\u5efa\u7528\u6237 vagrant \u3002 sudo adduser vagrant sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd vagrant sudo passwd vagrant \u8bbe\u7f6e\u7528\u6237 root \u7684\u5bc6\u7801\u3002 sudo passwd root \u66f4\u65b0\u5ba2\u6237\u673a\u7684\u4e3b\u673a\u540d\uff0c\u8fd9\u91cc\u662f ubusvr \u3002 sudo hostnamectl set-hostname ubusvr sudo hostnamectl set-hostname ubusvr --pretty \u9a8c\u8bc1\u4e3b\u673a\u540d\u662f\u5426\u5df2\u6210\u529f\u66f4\u65b0\u4e3a ubusvr \u3002 cat /etc/machine-info cat /etc/hostname \u9a8c\u8bc1\u4e3b\u673aIP\u5730\u5740 127.0.1.1 \u5df2\u7ecf\u914d\u7f6e\u7ed9\u5f53\u524d\u865a\u62df\u673a ubusvr \u3002 cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 ubusrv # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters \u8bbe\u7f6e\u5ba2\u6237\u673a\u4e3a\u56fa\u5b9aIP\u5730\u5740\uff0c\u8fd9\u91cc\u662f 11.0.1.136 \u3002 sudo vi 00 -installer-config.yaml network : ethernets : ens33 : dhcp4 : false addresses : - 11.0.1.136/24 nameservers : addresses : - 11.0.1.2 routes : - to : default via : 11.0.1.2 version : 2 sudo netplan apply \u7981\u7528\u4ea4\u6362\u5206\u533aswap\u3002 sudo swapoff -a sudo ufw disable sudo ufw status verbose \u6ce8\u91ca\u6389\u6587\u4ef6 /etc/fstab \u7684\u6700\u540e\u4e00\u884c\uff0c\u5373\u7981\u7528\u4ea4\u6362\u5206\u533a\u3002\u9700\u8981\u91cd\u542f\u5ba2\u6237\u673a\u4f7f\u4e4b\u751f\u6548\u3002 /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 \u8bbe\u7f6e\u5ba2\u6237\u673a\u65f6\u533a\u3002 sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile \u6267\u884c\u547d\u4ee4 ll /etc/localtime \u9a8c\u8bc1\u65f6\u533a\u662f\u5426\u5df2\u6b63\u786e\u8bbe\u7f6e\u5e76\u751f\u6548\u3002 lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai \u5ba2\u6237\u673a\u5185\u6838\u8bbe\u7f6e\u3002 cat < /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl status docker.service sudo systemctl status containerd.service sudo groupadd docker sudo usermod -aG docker $USER \u8bbe\u7f6eContainerd\u3002 containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml sudo systemctl restart containerd sudo systemctl status containerd \u5b89\u88c5Kubernetes \u00b6 \u5b89\u88c5kubeadm sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - cat << EOF > /etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables apt policy kubeadm sudo apt-get -y install kubelet = 1 .23.8-00 kubeadm = 1 .23.8-00 kubectl = 1 .23.8-00 --allow-downgrades \u914d\u7f6e\u4e3b\u8282\u70b9\uff08Master\uff09\u3002 sudo kubeadm config print init-defaults \u5b89\u88c5\u9884\u6f14Dry run\u3002 sudo kubeadm init --dry-run --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 \u5b89\u88c5\u3002 sudo kubeadm init --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config \u5b89\u88c5Flannel\u3002\u5982\u679c\u9700\u8981\u8003\u8651\u7f51\u7edc\u7b56\u7565\uff0c\u5219\u5b89\u88c5Calico\u3002\u53c2\u7167 \u963f\u91cc\u4e91ECS \u4e2dInstall Calico or Flannel\u90e8\u5206\u3002 kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml \u914d\u7f6e\u5de5\u4f5c\u8282\u70b9\uff08Worker Node\uff09\u3002 kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> kubeadm join 11 .0.1.136:6443 --token 6zqh1u.8b4afzc2ov4e7iuj \\ --discovery-token-ca-cert-hash sha256:815fdb9dd9e3ae0af07ffaf6c216964388098b150ef01ee3ae900c261a429d24 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u914d\u7f6ebash\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 sudo apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b9a\u4e49\u522b\u540d\uff08alias\uff09\u3002 echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc \u67e5\u770b\u5f53\u524d\u96c6\u7fa4\u72b6\u6001\u3002 kubectl cluster-info kubectl get nodes -owide kubectl get pod -A \u5b89\u88c5Helm \u00b6 \u5b89\u88c5Helm\u5ba2\u6237\u7aef\u3002 curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh \u8f93\u51fa\u7ed3\u679c\uff1a Downloading https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm \u91cd\u7f6e\u96c6\u7fa4 \u00b6 \u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u64cd\u4f5c\u4f1a\u91cd\u7f6e\u5f53\u524d\u96c6\u7fa4\uff08\u5220\u9664\u96c6\u7fa4\uff09\u3002 \u5220\u9664\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u3002 kubeadm reset \u6e05\u9664 iptables \u4e2d\u5df2\u5b9a\u4e49\u7684\u89c4\u5219\u3002 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u6e05\u9664 IPVS \u4e2d\u5b9a\u4e49\u7684\u89c4\u5219\uff08\u5982\u679c\u4f7f\u7528 IPVS \uff09\u3002 ipvsadm --clear","title":"\u5355\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/single-local/#cka1kubernetes","text":"","title":"CKA\u81ea\u5b66\u7b14\u8bb01:\u5355\u8282\u70b9\u865a\u62df\u673a\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/single-local/#_1","text":"\u5728\u672c\u5730Windows\u73af\u5883\u4e2d\uff0c\u901a\u8fc7VMWare\u5b89\u88c5Ubuntu\u865a\u62df\u673a\u3002\u5728Ubuntu\u865a\u62df\u673a\u4e2d\u5b89\u88c5\u57fa\u4e8eDocker\u7684Kubernetes\u7cfb\u7edf\u3002\u5728\u8be5\u865a\u62df\u673a\u4e2d\u540c\u65f6\u914d\u7f6e\u4e3b\u8282\u70b9Master\u548c\u5de5\u4f5c\u8282\u70b9Worker\u3002","title":"\u6458\u8981"},{"location":"k8s/cka_cn/installation/single-local/#_2","text":"VMWare\u865a\u62df\u673a\u8bbe\u7f6e\u3002 VMnet1: host-only\u6a21\u5f0f, \u7f51\u7edcsubnet: 192.168.150.0/24 VMnet8: NAT\u6a21\u5f0f, \u7f51\u7edcsubnet: 11.0.1.0/24 \u901a\u8fc7VMWare\u521b\u5efa\u5ba2\u6237\u673a\u3002 \u5185\u5b58\uff1a4 GB CPU\uff1a2 CPUs with 2 Cores \u64cd\u4f5c\u7cfb\u7edf\uff1aUbuntu Server 22.04 \u7f51\u7edc\uff1aNAT Kubernetes\u8fd0\u884c\u5728Docker\u4e0a\u3002","title":"\u672c\u5730\u865a\u62df\u673a\u8bbe\u7f6e"},{"location":"k8s/cka_cn/installation/single-local/#ubuntu","text":"\u521b\u5efa\u7528\u6237 vagrant \u3002 sudo adduser vagrant sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd vagrant sudo passwd vagrant \u8bbe\u7f6e\u7528\u6237 root \u7684\u5bc6\u7801\u3002 sudo passwd root \u66f4\u65b0\u5ba2\u6237\u673a\u7684\u4e3b\u673a\u540d\uff0c\u8fd9\u91cc\u662f ubusvr \u3002 sudo hostnamectl set-hostname ubusvr sudo hostnamectl set-hostname ubusvr --pretty \u9a8c\u8bc1\u4e3b\u673a\u540d\u662f\u5426\u5df2\u6210\u529f\u66f4\u65b0\u4e3a ubusvr \u3002 cat /etc/machine-info cat /etc/hostname \u9a8c\u8bc1\u4e3b\u673aIP\u5730\u5740 127.0.1.1 \u5df2\u7ecf\u914d\u7f6e\u7ed9\u5f53\u524d\u865a\u62df\u673a ubusvr \u3002 cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 ubusrv # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters \u8bbe\u7f6e\u5ba2\u6237\u673a\u4e3a\u56fa\u5b9aIP\u5730\u5740\uff0c\u8fd9\u91cc\u662f 11.0.1.136 \u3002 sudo vi 00 -installer-config.yaml network : ethernets : ens33 : dhcp4 : false addresses : - 11.0.1.136/24 nameservers : addresses : - 11.0.1.2 routes : - to : default via : 11.0.1.2 version : 2 sudo netplan apply \u7981\u7528\u4ea4\u6362\u5206\u533aswap\u3002 sudo swapoff -a sudo ufw disable sudo ufw status verbose \u6ce8\u91ca\u6389\u6587\u4ef6 /etc/fstab \u7684\u6700\u540e\u4e00\u884c\uff0c\u5373\u7981\u7528\u4ea4\u6362\u5206\u533a\u3002\u9700\u8981\u91cd\u542f\u5ba2\u6237\u673a\u4f7f\u4e4b\u751f\u6548\u3002 /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 \u8bbe\u7f6e\u5ba2\u6237\u673a\u65f6\u533a\u3002 sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile \u6267\u884c\u547d\u4ee4 ll /etc/localtime \u9a8c\u8bc1\u65f6\u533a\u662f\u5426\u5df2\u6b63\u786e\u8bbe\u7f6e\u5e76\u751f\u6548\u3002 lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai \u5ba2\u6237\u673a\u5185\u6838\u8bbe\u7f6e\u3002 cat < /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl status docker.service sudo systemctl status containerd.service sudo groupadd docker sudo usermod -aG docker $USER \u8bbe\u7f6eContainerd\u3002 containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml sudo systemctl restart containerd sudo systemctl status containerd","title":"\u5b89\u88c5Docker"},{"location":"k8s/cka_cn/installation/single-local/#kubernetes","text":"\u5b89\u88c5kubeadm sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - cat << EOF > /etc/apt/sources.list.d/kubernetes.list deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main EOF sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables apt policy kubeadm sudo apt-get -y install kubelet = 1 .23.8-00 kubeadm = 1 .23.8-00 kubectl = 1 .23.8-00 --allow-downgrades \u914d\u7f6e\u4e3b\u8282\u70b9\uff08Master\uff09\u3002 sudo kubeadm config print init-defaults \u5b89\u88c5\u9884\u6f14Dry run\u3002 sudo kubeadm init --dry-run --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 \u5b89\u88c5\u3002 sudo kubeadm init --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config \u5b89\u88c5Flannel\u3002\u5982\u679c\u9700\u8981\u8003\u8651\u7f51\u7edc\u7b56\u7565\uff0c\u5219\u5b89\u88c5Calico\u3002\u53c2\u7167 \u963f\u91cc\u4e91ECS \u4e2dInstall Calico or Flannel\u90e8\u5206\u3002 kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml \u914d\u7f6e\u5de5\u4f5c\u8282\u70b9\uff08Worker Node\uff09\u3002 kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> kubeadm join 11 .0.1.136:6443 --token 6zqh1u.8b4afzc2ov4e7iuj \\ --discovery-token-ca-cert-hash sha256:815fdb9dd9e3ae0af07ffaf6c216964388098b150ef01ee3ae900c261a429d24 \u5728\u6240\u6709\u8282\u70b9\u4e0a\u914d\u7f6ebash\u81ea\u52a8\u8865\u5168\u529f\u80fd\u3002 sudo apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc \u5728\u6240\u6709\u8282\u70b9\u4e0a\u5b9a\u4e49\u522b\u540d\uff08alias\uff09\u3002 echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc \u67e5\u770b\u5f53\u524d\u96c6\u7fa4\u72b6\u6001\u3002 kubectl cluster-info kubectl get nodes -owide kubectl get pod -A","title":"\u5b89\u88c5Kubernetes"},{"location":"k8s/cka_cn/installation/single-local/#helm","text":"\u5b89\u88c5Helm\u5ba2\u6237\u7aef\u3002 curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh \u8f93\u51fa\u7ed3\u679c\uff1a Downloading https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm","title":"\u5b89\u88c5Helm"},{"location":"k8s/cka_cn/installation/single-local/#_3","text":"\u6ce8\u610f\uff1a\u4e0b\u9762\u7684\u64cd\u4f5c\u4f1a\u91cd\u7f6e\u5f53\u524d\u96c6\u7fa4\uff08\u5220\u9664\u96c6\u7fa4\uff09\u3002 \u5220\u9664\u96c6\u7fa4\u4e2d\u6240\u6709\u8282\u70b9\u3002 kubeadm reset \u6e05\u9664 iptables \u4e2d\u5df2\u5b9a\u4e49\u7684\u89c4\u5219\u3002 iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X \u6e05\u9664 IPVS \u4e2d\u5b9a\u4e49\u7684\u89c4\u5219\uff08\u5982\u679c\u4f7f\u7528 IPVS \uff09\u3002 ipvsadm --clear","title":"\u91cd\u7f6e\u96c6\u7fa4"},{"location":"k8s/cka_en/foundamentals/basics/","text":"kubectl basics \u00b6 Scenario: get to know how to operate Kubernetes cluster using kubectl . via API via kubectl via Dashboard Demo: Check current kubeconfig file \u00b6 Use the kubectl config command to get current context of configuration file. echo $KUBECONFIG kubectl config view kubectl config get-contexts Get resource list \u00b6 Get a complete list of supported resources kubectl api-resources Get cluster status \u00b6 Kubernetes control plane is running at https://:6443 CoreDNS is running at https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy kubectl cluster-info kubectl cluster-info dump Display resources \u00b6 Use kubectl get --help to get examples of displaying one or many resources. Get health status of control plane. kubectl get componentstatuses kubectl get cs Result NAME STATUS MESSAGE ERROR etcd-0 Healthy {\"health\":\"true\",\"reason\":\"\"} scheduler Healthy ok controller-manager Healthy ok Get node status and details \u00b6 kubectl get nodes kubectl get nodes -o wide kubectl describe node cka001 Use command kubectl create --help to get examples of creating resources. Create namespace \u00b6 kubectl create namespace --help kubectl create namespace my-namespace Information Namespace is a cluster, which includes services. Service may be on a node, may be not. Create deployment \u00b6 Create Deployment on the namespace. kubectl -n my-namespace create deployment my-busybox \\ --image=busybox \\ --replicas=3 \\ --port=5701 Create ClusterRole \u00b6 kubectl create clusterrole --help kubectl create clusterrole pod-creater \\ -n my-namespace \\ --verb=create \\ --resource=deployment \\ --resource-name=my-busybox Create ServiceAccount \u00b6 kubectl create serviceaccount --help kubectl -n my-namespace create serviceaccount my-service-account Create RoleBinding \u00b6 Note RoleBinding can reference a Role in the same namespace or a ClusterRole in the global namespace. kubectl create rolebinding --help kubectl create rolebinding NAME \\ --clusterrole=NAME|--role=NAME \\ [--user=username] \\ [--group=groupname] \\ [--serviceaccount=namespace:serviceaccountname] \\ [--dry-run=server|client|none] kubectl create rolebinding my-admin \\ --clusterrole=pod-creater \\ --serviceaccount=my-namespace:my-service-account Use the proxy \u00b6 We can use kubectl proxy command to open a tunnel to the API server and make it available locally - usually on localhost:8001 / 127.0.0.1:8001. When I want to explore the API, this is an easy way to gain access. Run the command kubectl proxy & and open http://localhost:8001/api/v1 in browser. Just opening http://localhost:8001 will return an error because we are only allowed to access certain parts of the API. Hence the API path is important kubectl proxy & Output [1] 102358 Starting to serve on 127.0.0.1:8001 Example, get available API groups and so on via below link: http://127.0.0.1:8001/ http://127.0.0.1:8001/api/v1 http://127.0.0.1:8001/api/v1/namespaces http://127.0.0.1:8001/api/v1/namespaces/default http://127.0.0.1:8001/api/v1/namespaces/sock-shop/pods Access as application \u00b6 If we access kubernetes as an application rather than an administrator, we cannot use the kubectl . Instead of kubectl we can use the program curl . We have to send HTTP requests to the cluster. asking for the available nodes. Make sure kubectl proxy is running and serving on http://localhost:8001/ . Execute command below with a -v=9 flag, it shows all the information needed. kubectl get nodes Go through the command's output and find the correct curl request below. curl -v -XGET \\ -H \"Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json\" \\ -H \"User-Agent: kubectl/v1.24.1 (linux/amd64) kubernetes/3ddd0f4\" \\ 'https:///api/v1/nodes?limit=500' Reference *There is a forum-like page hosted by K8s with lots of information around kubectl and how to use it best. * Manage multiple clusters and multiple config files * kubectl command documentation * Shell autocompletion * kubectl cheat sheet * jsonpath in kubectl * kubectl","title":"kubectl basics"},{"location":"k8s/cka_en/foundamentals/basics/#kubectl-basics","text":"Scenario: get to know how to operate Kubernetes cluster using kubectl . via API via kubectl via Dashboard Demo:","title":"kubectl basics"},{"location":"k8s/cka_en/foundamentals/basics/#check-current-kubeconfig-file","text":"Use the kubectl config command to get current context of configuration file. echo $KUBECONFIG kubectl config view kubectl config get-contexts","title":"Check current kubeconfig file"},{"location":"k8s/cka_en/foundamentals/basics/#get-resource-list","text":"Get a complete list of supported resources kubectl api-resources","title":"Get resource list"},{"location":"k8s/cka_en/foundamentals/basics/#get-cluster-status","text":"Kubernetes control plane is running at https://:6443 CoreDNS is running at https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy kubectl cluster-info kubectl cluster-info dump","title":"Get cluster status"},{"location":"k8s/cka_en/foundamentals/basics/#display-resources","text":"Use kubectl get --help to get examples of displaying one or many resources. Get health status of control plane. kubectl get componentstatuses kubectl get cs Result NAME STATUS MESSAGE ERROR etcd-0 Healthy {\"health\":\"true\",\"reason\":\"\"} scheduler Healthy ok controller-manager Healthy ok","title":"Display resources"},{"location":"k8s/cka_en/foundamentals/basics/#get-node-status-and-details","text":"kubectl get nodes kubectl get nodes -o wide kubectl describe node cka001 Use command kubectl create --help to get examples of creating resources.","title":"Get node status and details"},{"location":"k8s/cka_en/foundamentals/basics/#create-namespace","text":"kubectl create namespace --help kubectl create namespace my-namespace Information Namespace is a cluster, which includes services. Service may be on a node, may be not.","title":"Create namespace"},{"location":"k8s/cka_en/foundamentals/basics/#create-deployment","text":"Create Deployment on the namespace. kubectl -n my-namespace create deployment my-busybox \\ --image=busybox \\ --replicas=3 \\ --port=5701","title":"Create deployment"},{"location":"k8s/cka_en/foundamentals/basics/#create-clusterrole","text":"kubectl create clusterrole --help kubectl create clusterrole pod-creater \\ -n my-namespace \\ --verb=create \\ --resource=deployment \\ --resource-name=my-busybox","title":"Create ClusterRole"},{"location":"k8s/cka_en/foundamentals/basics/#create-serviceaccount","text":"kubectl create serviceaccount --help kubectl -n my-namespace create serviceaccount my-service-account","title":"Create ServiceAccount"},{"location":"k8s/cka_en/foundamentals/basics/#create-rolebinding","text":"Note RoleBinding can reference a Role in the same namespace or a ClusterRole in the global namespace. kubectl create rolebinding --help kubectl create rolebinding NAME \\ --clusterrole=NAME|--role=NAME \\ [--user=username] \\ [--group=groupname] \\ [--serviceaccount=namespace:serviceaccountname] \\ [--dry-run=server|client|none] kubectl create rolebinding my-admin \\ --clusterrole=pod-creater \\ --serviceaccount=my-namespace:my-service-account","title":"Create RoleBinding"},{"location":"k8s/cka_en/foundamentals/basics/#use-the-proxy","text":"We can use kubectl proxy command to open a tunnel to the API server and make it available locally - usually on localhost:8001 / 127.0.0.1:8001. When I want to explore the API, this is an easy way to gain access. Run the command kubectl proxy & and open http://localhost:8001/api/v1 in browser. Just opening http://localhost:8001 will return an error because we are only allowed to access certain parts of the API. Hence the API path is important kubectl proxy & Output [1] 102358 Starting to serve on 127.0.0.1:8001 Example, get available API groups and so on via below link: http://127.0.0.1:8001/ http://127.0.0.1:8001/api/v1 http://127.0.0.1:8001/api/v1/namespaces http://127.0.0.1:8001/api/v1/namespaces/default http://127.0.0.1:8001/api/v1/namespaces/sock-shop/pods","title":"Use the proxy"},{"location":"k8s/cka_en/foundamentals/basics/#access-as-application","text":"If we access kubernetes as an application rather than an administrator, we cannot use the kubectl . Instead of kubectl we can use the program curl . We have to send HTTP requests to the cluster. asking for the available nodes. Make sure kubectl proxy is running and serving on http://localhost:8001/ . Execute command below with a -v=9 flag, it shows all the information needed. kubectl get nodes Go through the command's output and find the correct curl request below. curl -v -XGET \\ -H \"Accept: application/json;as=Table;v=v1;g=meta.k8s.io,application/json;as=Table;v=v1beta1;g=meta.k8s.io,application/json\" \\ -H \"User-Agent: kubectl/v1.24.1 (linux/amd64) kubernetes/3ddd0f4\" \\ 'https:///api/v1/nodes?limit=500' Reference *There is a forum-like page hosted by K8s with lots of information around kubectl and how to use it best. * Manage multiple clusters and multiple config files * kubectl command documentation * Shell autocompletion * kubectl cheat sheet * jsonpath in kubectl * kubectl","title":"Access as application"},{"location":"k8s/cka_en/foundamentals/casestudy-calico/","text":"Case Study: Install Calico \u00b6 Scenario: Install Calico Calico Datastore Configure IP Pools Install CNI plugin Install Typha Install calico/node Test networking The Calico Datastore \u00b6 In order to use Kubernetes as the Calico datastore, we need to define the custom resources Calico uses. Download and examine the list of Calico custom resource definitions, and open it in a file editor. wget https://projectcalico.docs.tigera.io/manifests/crds.yaml Create the custom resource definitions in Kubernetes. kubectl apply -f crds.yaml Install calicoctl . To interact directly with the Calico datastore, use the calicoctl client tool. Download the calicoctl binary to a Linux host with access to Kubernetes. The latest release of calicoctl can be found in the git page and replace below v3.23.2 by actual release number. wget https://github.com/projectcalico/calico/releases/download/v3.23.3/calicoctl-linux-amd64 chmod +x calicoctl-linux-amd64 sudo cp calicoctl-linux-amd64 /usr/local/bin/calicoctl Configure calicoctl to access Kubernetes echo \"export KUBECONFIG=/root/.kube/config\" >> ~/.bashrc echo \"export DATASTORE_TYPE=kubernetes\" >> ~/.bashrc echo $KUBECONFIG echo $DATASTORE_TYPE Verify calicoctl can reach the datastore by running\uff1a calicoctl get nodes -o wide Output similar to below: NAME ASN IPV4 IPV6 cka001 cka002 cka003 Nodes are backed by the Kubernetes node object, so we should see names that match kubectl get nodes . kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 NotReady control-plane,master 23m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka002 NotReady 22m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka003 NotReady 21m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 Configure IP Pools \u00b6 A workload is a container or VM that Calico handles the virtual networking for. In Kubernetes, workloads are pods. A workload endpoint is the virtual network interface a workload uses to connect to the Calico network. IP pools are ranges of IP addresses that Calico uses for workload endpoints. Get current IP pools in the cluster. So far, it's empty after fresh installation. calicoctl get ippools NAME CIDR SELECTOR The Pod CIDR is 10.244.0.0/16 we specified via kubeadm init . Let's create two IP pools for use in the cluster. Each pool can not have any overlaps. ipv4-ippool-1: 10.244.0.0/18 ipv4-ippool-2: 10.244.192.0/19 calicoctl apply -f - < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < 4h49m v1.24.0 cka003 Ready 4h49m v1.24.0 Install Typha \u00b6 Typha sits between the Kubernetes API server and per-node daemons like Felix and confd (running in calico/node). It watches the Kubernetes resources and Calico custom resources used by these daemons, and whenever a resource changes it fans out the update to the daemons. This reduces the number of watches the Kubernetes API server needs to serve and improves scalability of the cluster. Provision Certificates We will use mutually authenticated TLS to ensure that calico/node and Typha communicate securely. We generate a certificate authority (CA) and use it to sign a certificate for Typha. Change to directory /etc/kubernetes/pki/ . cd /etc/kubernetes/pki/ Create the CA certificate and key openssl req -x509 -newkey rsa:4096 \\ -keyout typhaca.key \\ -nodes \\ -out typhaca.crt \\ -subj \"/CN=Calico Typha CA\" \\ -days 365 Store the CA certificate in a ConfigMap that Typha & calico/node will access. kubectl create configmap -n kube-system calico-typha-ca --from-file=typhaca.crt Create the Typha key and certificate signing request (CSR). openssl req -newkey rsa:4096 \\ -keyout typha.key \\ -nodes \\ -out typha.csr \\ -subj \"/CN=calico-typha\" The certificate presents the Common Name (CN) as calico-typha . calico/node will be configured to verify this name. Sign the Typha certificate with the CA. openssl x509 -req -in typha.csr \\ -CA typhaca.crt \\ -CAkey typhaca.key \\ -CAcreateserial \\ -out typha.crt \\ -days 365 Signature ok subject=CN = calico-typha Getting CA Private Key Store the Typha key and certificate in a secret that Typha will access kubectl create secret generic -n kube-system calico-typha-certs --from-file=typha.key --from-file=typha.crt Provision RBAC Change to home directory. cd ~ Create a ServiceAccount that will be used to run Typha. kubectl create serviceaccount -n kube-system calico-typha Define a cluster role for Typha with permission to watch Calico datastore objects. kubectl apply -f - < pingtest-585b76c894-s2tbs 1/1 Running 0 7s 10.244.31.0 cka002 pingtest-585b76c894-vm9wn 1/1 Running 0 7s 10.244.28.64 cka003 Note the IP addresses of the second two pods, then exec into the first one. From inside the pod, ping the other two pod IP addresses. For example: kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # ping 10.244.31.1 -c 4 4 packets transmitted, 4 packets received, 0% packet loss / # ping 10.244.31.0 -c 4 4 packets transmitted, 4 packets received, 0% packet loss / # ping 10.244.28.64 -c 4 4 packets transmitted, 0 packets received, 100% packet loss Check routes \u00b6 From one of the nodes, verify that routes exist to each of the pingtest pods\u2019 IP addresses. For example ip route get 10.244.31.1 ip route get 10.244.31.0 ip route get 10.244.28.64 In the result, the via (it's control-plane) in this example indicates the next-hop for this pod IP, which matches the IP address of the node the pod is scheduled on, as expected. IPAM allocations from different pools. Recall that we created two IP pools, but left one disabled. calicoctl get ippools -o wide Result NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR ipv4-ippool-1 10.244.0.0/18 true Never Never false false all() ipv4-ippool-2 10.244.192.0/19 true Never Never true false all() Enable the second pool. calicoctl --allow-version-mismatch apply -f - < Let's attach to the Pod pingtest-585b76c894-chwjq again. kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # 10.244.203.192 -c 4 4 packets transmitted, 0 packets received, 100 % packet loss Mark here. it's failed. Need further check why the route does not work. Clean up kubectl delete deployments.apps pingtest kubectl delete pod pingtest-ippool-2 Reference End-to-end Calico installation","title":"Calico Installation"},{"location":"k8s/cka_en/foundamentals/casestudy-calico/#case-study-install-calico","text":"Scenario: Install Calico Calico Datastore Configure IP Pools Install CNI plugin Install Typha Install calico/node Test networking","title":"Case Study: Install Calico"},{"location":"k8s/cka_en/foundamentals/casestudy-calico/#the-calico-datastore","text":"In order to use Kubernetes as the Calico datastore, we need to define the custom resources Calico uses. Download and examine the list of Calico custom resource definitions, and open it in a file editor. wget https://projectcalico.docs.tigera.io/manifests/crds.yaml Create the custom resource definitions in Kubernetes. kubectl apply -f crds.yaml Install calicoctl . To interact directly with the Calico datastore, use the calicoctl client tool. Download the calicoctl binary to a Linux host with access to Kubernetes. The latest release of calicoctl can be found in the git page and replace below v3.23.2 by actual release number. wget https://github.com/projectcalico/calico/releases/download/v3.23.3/calicoctl-linux-amd64 chmod +x calicoctl-linux-amd64 sudo cp calicoctl-linux-amd64 /usr/local/bin/calicoctl Configure calicoctl to access Kubernetes echo \"export KUBECONFIG=/root/.kube/config\" >> ~/.bashrc echo \"export DATASTORE_TYPE=kubernetes\" >> ~/.bashrc echo $KUBECONFIG echo $DATASTORE_TYPE Verify calicoctl can reach the datastore by running\uff1a calicoctl get nodes -o wide Output similar to below: NAME ASN IPV4 IPV6 cka001 cka002 cka003 Nodes are backed by the Kubernetes node object, so we should see names that match kubectl get nodes . kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 NotReady control-plane,master 23m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka002 NotReady 22m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9 cka003 NotReady 21m v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-113-generic containerd://1.5.9","title":"The Calico Datastore"},{"location":"k8s/cka_en/foundamentals/casestudy-calico/#configure-ip-pools","text":"A workload is a container or VM that Calico handles the virtual networking for. In Kubernetes, workloads are pods. A workload endpoint is the virtual network interface a workload uses to connect to the Calico network. IP pools are ranges of IP addresses that Calico uses for workload endpoints. Get current IP pools in the cluster. So far, it's empty after fresh installation. calicoctl get ippools NAME CIDR SELECTOR The Pod CIDR is 10.244.0.0/16 we specified via kubeadm init . Let's create two IP pools for use in the cluster. Each pool can not have any overlaps. ipv4-ippool-1: 10.244.0.0/18 ipv4-ippool-2: 10.244.192.0/19 calicoctl apply -f - < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < /etc/cni/net.d/10-calico.conflist < 4h49m v1.24.0 cka003 Ready 4h49m v1.24.0","title":"Install CNI plugin"},{"location":"k8s/cka_en/foundamentals/casestudy-calico/#install-typha","text":"Typha sits between the Kubernetes API server and per-node daemons like Felix and confd (running in calico/node). It watches the Kubernetes resources and Calico custom resources used by these daemons, and whenever a resource changes it fans out the update to the daemons. This reduces the number of watches the Kubernetes API server needs to serve and improves scalability of the cluster. Provision Certificates We will use mutually authenticated TLS to ensure that calico/node and Typha communicate securely. We generate a certificate authority (CA) and use it to sign a certificate for Typha. Change to directory /etc/kubernetes/pki/ . cd /etc/kubernetes/pki/ Create the CA certificate and key openssl req -x509 -newkey rsa:4096 \\ -keyout typhaca.key \\ -nodes \\ -out typhaca.crt \\ -subj \"/CN=Calico Typha CA\" \\ -days 365 Store the CA certificate in a ConfigMap that Typha & calico/node will access. kubectl create configmap -n kube-system calico-typha-ca --from-file=typhaca.crt Create the Typha key and certificate signing request (CSR). openssl req -newkey rsa:4096 \\ -keyout typha.key \\ -nodes \\ -out typha.csr \\ -subj \"/CN=calico-typha\" The certificate presents the Common Name (CN) as calico-typha . calico/node will be configured to verify this name. Sign the Typha certificate with the CA. openssl x509 -req -in typha.csr \\ -CA typhaca.crt \\ -CAkey typhaca.key \\ -CAcreateserial \\ -out typha.crt \\ -days 365 Signature ok subject=CN = calico-typha Getting CA Private Key Store the Typha key and certificate in a secret that Typha will access kubectl create secret generic -n kube-system calico-typha-certs --from-file=typha.key --from-file=typha.crt Provision RBAC Change to home directory. cd ~ Create a ServiceAccount that will be used to run Typha. kubectl create serviceaccount -n kube-system calico-typha Define a cluster role for Typha with permission to watch Calico datastore objects. kubectl apply -f - < pingtest-585b76c894-s2tbs 1/1 Running 0 7s 10.244.31.0 cka002 pingtest-585b76c894-vm9wn 1/1 Running 0 7s 10.244.28.64 cka003 Note the IP addresses of the second two pods, then exec into the first one. From inside the pod, ping the other two pod IP addresses. For example: kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # ping 10.244.31.1 -c 4 4 packets transmitted, 4 packets received, 0% packet loss / # ping 10.244.31.0 -c 4 4 packets transmitted, 4 packets received, 0% packet loss / # ping 10.244.28.64 -c 4 4 packets transmitted, 0 packets received, 100% packet loss","title":"Pod to pod pings"},{"location":"k8s/cka_en/foundamentals/casestudy-calico/#check-routes","text":"From one of the nodes, verify that routes exist to each of the pingtest pods\u2019 IP addresses. For example ip route get 10.244.31.1 ip route get 10.244.31.0 ip route get 10.244.28.64 In the result, the via (it's control-plane) in this example indicates the next-hop for this pod IP, which matches the IP address of the node the pod is scheduled on, as expected. IPAM allocations from different pools. Recall that we created two IP pools, but left one disabled. calicoctl get ippools -o wide Result NAME CIDR NAT IPIPMODE VXLANMODE DISABLED DISABLEBGPEXPORT SELECTOR ipv4-ippool-1 10.244.0.0/18 true Never Never false false all() ipv4-ippool-2 10.244.192.0/19 true Never Never true false all() Enable the second pool. calicoctl --allow-version-mismatch apply -f - < Let's attach to the Pod pingtest-585b76c894-chwjq again. kubectl exec -ti pingtest-585b76c894-chwjq -- sh / # 10.244.203.192 -c 4 4 packets transmitted, 0 packets received, 100 % packet loss Mark here. it's failed. Need further check why the route does not work. Clean up kubectl delete deployments.apps pingtest kubectl delete pod pingtest-ippool-2 Reference End-to-end Calico installation","title":"Check routes"},{"location":"k8s/cka_en/foundamentals/casestudy-health-check/","text":"Case Study: Health Check \u00b6 Scenario: Create Deployment and Service Simulate an error (delete index.html) Pod is in unhealth status and is removed from endpoint list Fix the error (revert the index.html) Pod is back to normal and in endpoint list Create Deployment and Service \u00b6 Create Deployment nginx-healthcheck and Service nginx-healthcheck . kubectl apply -f - < nginx-healthcheck-79fc55d944-nwwjc 1/1 Running 0 9s 10.244.112.13 cka002 Access Pod IP via curl command, e.g., above example. curl 10.244.102.14 curl 10.244.112.13 We see a successful index.html content of Nginx below with above example. Check details of Service craeted in above example. kubectl describe svc nginx-healthcheck We will see below output. There are two Pods information listed in Endpoints . Name: nginx-healthcheck Namespace: dev Labels: Annotations: Selector: name=nginx-healthcheck Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 11.244.238.20 IPs: 11.244.238.20 Port: 80/TCP TargetPort: 80/TCP NodePort: 31795/TCP Endpoints: 10.244.102.14:80,10.244.112.13:80 Session Affinity: None External Traffic Policy: Cluster Events: We can also get information of Endpoints. kubectl get endpoints nginx-healthcheck Result NAME ENDPOINTS AGE nginx-healthcheck 10.244.102.14:80,10.244.112.13:80 72s Till now, two nginx-healthcheck Pods are working and providing service as expected. Simulate readinessProbe Failure \u00b6 Let's simulate an error by deleting and index.html file in on of nginx-healthcheck Pod and see what's readinessProbe will do. First, execute kubectl exec -it -- bash to log into nginx-healthcheck Pod, and delete the index.html file. kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ rm -rf index.html exit After that, let's check the status of above Pod that index.html file was deleted. kubectl describe pod nginx-healthcheck-79fc55d944-jw887 We can now see Readiness probe failed error event message. ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m8s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-jw887 to cka003 Normal Pulled 2m7s kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m7s kubelet Created container nginx-healthcheck Normal Started 2m7s kubelet Started container nginx-healthcheck Warning Unhealthy 2s (x2 over 7s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 403 Let's check another Pod. kubectl describe pod nginx-healthcheck-79fc55d944-nwwjc There is no error info. ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 3m46s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-nwwjc to cka002 Normal Pulled 3m45s kubelet Container image \"nginx:latest\" already present on machine Normal Created 3m45s kubelet Created container nginx-healthcheck Normal Started 3m45s kubelet Started container nginx-healthcheck Now, access Pod IP via curl command and see what the result of each Pod. curl 10.244.102.14 curl 10.244.112.13 Result: curl 10.244.102.14 failed with 403 Forbidden error below. curl 10.244.112.13 works well. Let's check current status of Nginx Service after one of Pods runs into failure. kubectl describe svc nginx-healthcheck In below output, there is only one Pod information listed in Endpoint. Name: nginx-healthcheck Namespace: dev Labels: Annotations: Selector: name=nginx-healthcheck Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 11.244.238.20 IPs: 11.244.238.20 Port: 80/TCP TargetPort: 80/TCP NodePort: 31795/TCP Endpoints: 10.244.112.13:80 Session Affinity: None External Traffic Policy: Cluster Events: Same result we can get by checking information of Endpoints, which is only Pod is running. kubectl get endpoints nginx-healthcheck Output: NAME ENDPOINTS AGE nginx-healthcheck 10.244.112.13:80 6m5s Fix readinessProbe Failure \u00b6 Let's re-create the index.html file again in the Pod. kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ cat > index.html << EOF Welcome to nginx!

    Welcome to nginx!

    If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

    For online documentation and support please refer to nginx.org.
    Commercial support is available at nginx.com.

    Thank you for using nginx.

    EOF exit We now can see that two Pods are back to Endpoints to provide service now. kubectl describe svc nginx-healthcheck kubectl get endpoints nginx-healthcheck Re-access Pod IP via curl command and we can see both are back to normal status. curl 10.244.102.14 curl 10.244.112.13 Verify the Pod status again. kubectl describe pod nginx-healthcheck-79fc55d944-jw887 Conclusion: By delete the index.html file, the Pod is in unhealth status and is removed from endpoint list. One one health Pod can provide normal service. Clean up kubectl delete service nginx-healthcheck kubectl delete deployment nginx-healthcheck Simulate livenessProbe Failure \u00b6 Re-create Deployment nginx-healthcheck and Service nginx-healthcheck . Deployment: NAME READY UP-TO-DATE AVAILABLE AGE nginx-healthcheck 0/2 2 0 7s Pods: NAME READY STATUS RESTARTS AGE nginx-healthcheck-79fc55d944-lknp9 1/1 Running 0 96s nginx-healthcheck-79fc55d944-wntmg 1/1 Running 0 96s Change nginx default listening port from 80 to 90 to simulate livenessProbe Failure. livenessProbe check the live status via port 80 . kubectl exec -it nginx-healthcheck-79fc55d944-lknp9 -- bash root@nginx-healthcheck-79fc55d944-lknp9:/# cd /etc/nginx/conf.d root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# sed -i 's/80/90/g' default.conf root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# nginx -s reload 2022/07/24 12:59:45 [notice] 79#79: signal process started The Pod runs into failure. kubectl describe pod nginx-healthcheck-79fc55d944-lknp9 We can see livenessProbe failed error event message. Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 17m default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-lknp9 to cka003 Normal Pulled 2m47s (x2 over 17m) kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m47s (x2 over 17m) kubelet Created container nginx-healthcheck Normal Started 2m47s (x2 over 17m) kubelet Started container nginx-healthcheck Warning Unhealthy 2m47s (x4 over 2m57s) kubelet Readiness probe failed: Get \"http://10.244.102.46:80/\": dial tcp 10.244.102.46:80: connect: connection refused Warning Unhealthy 2m47s (x3 over 2m57s) kubelet Liveness probe failed: dial tcp 10.244.102.46:80: connect: connection refused Normal Killing 2m47s kubelet Container nginx-healthcheck failed liveness probe, will be restarted Once failure detected by livenessProbe , the container will restarted again automatically. The default.conf we modified will be replaced by default file and the container status is up and normal.","title":"Health Check"},{"location":"k8s/cka_en/foundamentals/casestudy-health-check/#case-study-health-check","text":"Scenario: Create Deployment and Service Simulate an error (delete index.html) Pod is in unhealth status and is removed from endpoint list Fix the error (revert the index.html) Pod is back to normal and in endpoint list","title":"Case Study: Health Check"},{"location":"k8s/cka_en/foundamentals/casestudy-health-check/#create-deployment-and-service","text":"Create Deployment nginx-healthcheck and Service nginx-healthcheck . kubectl apply -f - < nginx-healthcheck-79fc55d944-nwwjc 1/1 Running 0 9s 10.244.112.13 cka002 Access Pod IP via curl command, e.g., above example. curl 10.244.102.14 curl 10.244.112.13 We see a successful index.html content of Nginx below with above example. Check details of Service craeted in above example. kubectl describe svc nginx-healthcheck We will see below output. There are two Pods information listed in Endpoints . Name: nginx-healthcheck Namespace: dev Labels: Annotations: Selector: name=nginx-healthcheck Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 11.244.238.20 IPs: 11.244.238.20 Port: 80/TCP TargetPort: 80/TCP NodePort: 31795/TCP Endpoints: 10.244.102.14:80,10.244.112.13:80 Session Affinity: None External Traffic Policy: Cluster Events: We can also get information of Endpoints. kubectl get endpoints nginx-healthcheck Result NAME ENDPOINTS AGE nginx-healthcheck 10.244.102.14:80,10.244.112.13:80 72s Till now, two nginx-healthcheck Pods are working and providing service as expected.","title":"Create Deployment and Service"},{"location":"k8s/cka_en/foundamentals/casestudy-health-check/#simulate-readinessprobe-failure","text":"Let's simulate an error by deleting and index.html file in on of nginx-healthcheck Pod and see what's readinessProbe will do. First, execute kubectl exec -it -- bash to log into nginx-healthcheck Pod, and delete the index.html file. kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ rm -rf index.html exit After that, let's check the status of above Pod that index.html file was deleted. kubectl describe pod nginx-healthcheck-79fc55d944-jw887 We can now see Readiness probe failed error event message. ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 2m8s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-jw887 to cka003 Normal Pulled 2m7s kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m7s kubelet Created container nginx-healthcheck Normal Started 2m7s kubelet Started container nginx-healthcheck Warning Unhealthy 2s (x2 over 7s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 403 Let's check another Pod. kubectl describe pod nginx-healthcheck-79fc55d944-nwwjc There is no error info. ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 3m46s default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-nwwjc to cka002 Normal Pulled 3m45s kubelet Container image \"nginx:latest\" already present on machine Normal Created 3m45s kubelet Created container nginx-healthcheck Normal Started 3m45s kubelet Started container nginx-healthcheck Now, access Pod IP via curl command and see what the result of each Pod. curl 10.244.102.14 curl 10.244.112.13 Result: curl 10.244.102.14 failed with 403 Forbidden error below. curl 10.244.112.13 works well. Let's check current status of Nginx Service after one of Pods runs into failure. kubectl describe svc nginx-healthcheck In below output, there is only one Pod information listed in Endpoint. Name: nginx-healthcheck Namespace: dev Labels: Annotations: Selector: name=nginx-healthcheck Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 11.244.238.20 IPs: 11.244.238.20 Port: 80/TCP TargetPort: 80/TCP NodePort: 31795/TCP Endpoints: 10.244.112.13:80 Session Affinity: None External Traffic Policy: Cluster Events: Same result we can get by checking information of Endpoints, which is only Pod is running. kubectl get endpoints nginx-healthcheck Output: NAME ENDPOINTS AGE nginx-healthcheck 10.244.112.13:80 6m5s","title":"Simulate readinessProbe Failure"},{"location":"k8s/cka_en/foundamentals/casestudy-health-check/#fix-readinessprobe-failure","text":"Let's re-create the index.html file again in the Pod. kubectl exec -it nginx-healthcheck-79fc55d944-jw887 -- bash cd /usr/share/nginx/html/ cat > index.html << EOF Welcome to nginx!

    Welcome to nginx!

    If you see this page, the nginx web server is successfully installed and working. Further configuration is required.

    For online documentation and support please refer to nginx.org.
    Commercial support is available at nginx.com.

    Thank you for using nginx.

    EOF exit We now can see that two Pods are back to Endpoints to provide service now. kubectl describe svc nginx-healthcheck kubectl get endpoints nginx-healthcheck Re-access Pod IP via curl command and we can see both are back to normal status. curl 10.244.102.14 curl 10.244.112.13 Verify the Pod status again. kubectl describe pod nginx-healthcheck-79fc55d944-jw887 Conclusion: By delete the index.html file, the Pod is in unhealth status and is removed from endpoint list. One one health Pod can provide normal service. Clean up kubectl delete service nginx-healthcheck kubectl delete deployment nginx-healthcheck","title":"Fix readinessProbe Failure"},{"location":"k8s/cka_en/foundamentals/casestudy-health-check/#simulate-livenessprobe-failure","text":"Re-create Deployment nginx-healthcheck and Service nginx-healthcheck . Deployment: NAME READY UP-TO-DATE AVAILABLE AGE nginx-healthcheck 0/2 2 0 7s Pods: NAME READY STATUS RESTARTS AGE nginx-healthcheck-79fc55d944-lknp9 1/1 Running 0 96s nginx-healthcheck-79fc55d944-wntmg 1/1 Running 0 96s Change nginx default listening port from 80 to 90 to simulate livenessProbe Failure. livenessProbe check the live status via port 80 . kubectl exec -it nginx-healthcheck-79fc55d944-lknp9 -- bash root@nginx-healthcheck-79fc55d944-lknp9:/# cd /etc/nginx/conf.d root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# sed -i 's/80/90/g' default.conf root@nginx-healthcheck-79fc55d944-lknp9:/etc/nginx/conf.d# nginx -s reload 2022/07/24 12:59:45 [notice] 79#79: signal process started The Pod runs into failure. kubectl describe pod nginx-healthcheck-79fc55d944-lknp9 We can see livenessProbe failed error event message. Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 17m default-scheduler Successfully assigned dev/nginx-healthcheck-79fc55d944-lknp9 to cka003 Normal Pulled 2m47s (x2 over 17m) kubelet Container image \"nginx:latest\" already present on machine Normal Created 2m47s (x2 over 17m) kubelet Created container nginx-healthcheck Normal Started 2m47s (x2 over 17m) kubelet Started container nginx-healthcheck Warning Unhealthy 2m47s (x4 over 2m57s) kubelet Readiness probe failed: Get \"http://10.244.102.46:80/\": dial tcp 10.244.102.46:80: connect: connection refused Warning Unhealthy 2m47s (x3 over 2m57s) kubelet Liveness probe failed: dial tcp 10.244.102.46:80: connect: connection refused Normal Killing 2m47s kubelet Container nginx-healthcheck failed liveness probe, will be restarted Once failure detected by livenessProbe , the container will restarted again automatically. The default.conf we modified will be replaced by default file and the container status is up and normal.","title":"Simulate livenessProbe Failure"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/","text":"Case Study: Operations on Resources \u00b6 Scenario: Node Label Annotation Namespace ServiceAccount Authorization Grant API access authorization to default ServiceAccount Deployment Expose Service Scale out the Deployment Rolling update Rolling back update Event Logging Node Label \u00b6 Add/update/remove node Label. # Update node label kubectl label node cka002 node=demonode # Get node info with label info kubectl get node --show-labels # Search node by label kubectl get node -l node=demonode # Remove a lable of node kubectl label node cka002 node- Annotation \u00b6 Create Nginx deployment kubectl create deploy nginx --image=nginx:mainline Get Annotation info. kubectl describe deployment/nginx Result ...... Labels: app=nginx Annotations: deployment.kubernetes.io/revision: 1 Selector: app=nginx ...... Add new Annotation. kubectl annotate deployment nginx owner=James.H Now annotation looks like below. ...... Labels: app=nginx Annotations: deployment.kubernetes.io/revision: 1 owner: James.H Selector: app=nginx ...... Update/Overwrite Annotation. kubectl annotate deployment/nginx owner=K8s --overwrite Now annotation looks like below. ...... Annotations: deployment.kubernetes.io/revision: 1 owner: K8s Selector: app=nginx ...... Remove Annotation kubectl annotate deployment/nginx owner- ...... Labels: app=nginx Annotations: deployment.kubernetes.io/revision: 1 Selector: app=nginx ...... Clean up kubectl delete deployment nginx Namespace \u00b6 Get current available namespaces. kubectl get namespace Result NAME STATUS AGE default Active 3h45m dev Active 3h11m kube-node-lease Active 3h45m kube-public Active 3h45m kube-system Active 3h45m Get Pod under a specific namespace. kubectl get pod -n kube-system Result NAME READY STATUS RESTARTS AGE calico-kube-controllers-5c64b68895-jr4nl 1/1 Running 0 3h25m calico-node-dsx76 1/1 Running 0 3h25m calico-node-p5rf2 1/1 Running 0 3h25m calico-node-tr22l 1/1 Running 0 3h25m coredns-6d8c4cb4d-g4jxc 1/1 Running 0 3h45m coredns-6d8c4cb4d-sqcvj 1/1 Running 0 3h45m etcd-cka001 1/1 Running 0 3h45m kube-apiserver-cka001 1/1 Running 0 3h45m kube-controller-manager-cka001 1/1 Running 0 3h45m kube-proxy-5cdbj 1/1 Running 0 3h41m kube-proxy-cm4hc 1/1 Running 0 3h45m kube-proxy-g4w52 1/1 Running 0 3h41m kube-scheduler-cka001 1/1 Running 0 3h45m Get Pods in all namespaces. kubectl get pod --all-namespaces kubectl get pod -A ServiceAccount Authorization \u00b6 With Kubernetes 1.23 and lower version, when we create a new namespace, Kubernetes will automatically create a ServiceAccount default and a token default-token-xxxxx . With Kubernetes 1.24, only ServiceAccount default is created automatically when a new namespace is created, need manually create a toke linked to the ServiceAccount default . Here is an example to create a new namespace dev , we can see that only ServiceAcccount: default was created in namespace dev , no secretes (token) linked to the ServiceAccount default . kubectl create namespace dev kubectl get serviceaccount -n dev kubectl get secrets -n dev There is a default cluster role admin . But there is no clusterrole binding to the cluster role admin . kubectl get clusterrole admin kubectl get clusterrolebinding | grep ClusterRole/admin Role and rolebinding is namespaces based. On namespace dev , there is no role and rolebinding. kubectl get role -n dev kubectl get rolebinding -n dev A Secret in the Kubernetes cluster is an object and it is used to store sensitive information such as username, password, and token, etc. The objective of Secrets is to encode or hash the credentials. The secrets can be reused in the various Pod definition file. A kubernetes.io/service-account-token type of Secret is used to store a token that identifies a service account. When using this Secret type, you need to ensure that the kubernetes.io/service-account.name annotation is set to an existing service account name. Let's create token for the ServiceAcccount: default in namespace dev . kubectl apply -f - << EOF apiVersion: v1 kind: Secret metadata: name: default-token-dev namespace: dev annotations: kubernetes.io/service-account.name: \"default\" type: kubernetes.io/service-account-token EOF Now we get ServiceAcccount: default and Secret (token) default-token-dev in namespace dev . kubectl get serviceaccount -n dev kubectl get secrets -n dev Get token of the service account default . TOKEN=$(kubectl -n dev describe secret $(kubectl -n dev get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d ' ') echo $TOKEN Get API Service address. APISERVER=$(kubectl config view | grep https | cut -f 2- -d \":\" | tr -d \" \") echo $APISERVER Get Pod resources in namespace dev via API server with JSON layout. curl $APISERVER/api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN\" --insecure We will receive 403 forbidden error message. The ServiceAccount default does not have authorization to access pod in namespace dev . Let's create a rolebinding rolebinding-admin to bind cluster role admin to service account default in namespapce dev . Hence service account default is granted adminstrator authorization in namespace dev . # Usage: kubectl create rolebinding --clusterrole= --serviceaccount=: --namespace= # Crate rolebinding: kubectl create rolebinding rolebinding-admin --clusterrole=admin --serviceaccount=dev:default --namespace=dev Result looks like below by executing kubectl get rolebinding -n dev . NAME ROLE AGE rolebinding-admin ClusterRole/admin 10s Try again, get pod resources in namespace dev via API server with JSON layout. curl $APISERVER/api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN\" --insecure Clean up. kubectl delete namespace dev Deployment \u00b6 Create a Ubuntu Pod for operation. And attach to the running Pod. kubectl create -f - << EOF apiVersion: v1 kind: Pod metadata: name: ubuntu labels: app: ubuntu spec: containers: - name: ubuntu image: ubuntu:latest command: [\"/bin/sleep\", \"3650d\"] imagePullPolicy: IfNotPresent restartPolicy: Always EOF kubectl exec --stdin --tty ubuntu -- /bin/bash Create a deployment, option --image specifies a image\uff0coption --port specifies port for external access. A pod is also created when deployment is created. kubectl create deployment myapp --image=docker.io/jocatalin/kubernetes-bootcamp:v1 --replicas=1 --port=8080 Get deployment status kubectl get deployment myapp -o wide Result NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR myapp 1/1 1 1 79s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp Get detail information of deployment. kubectl describe deployment myapp Result Name: myapp Namespace: dev CreationTimestamp: Sat, 23 Jul 2022 14:36:43 +0800 Labels: app=myapp Annotations: deployment.kubernetes.io/revision: 1 Selector: app=myapp Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=myapp Containers: kubernetes-bootcamp: Image: docker.io/jocatalin/kubernetes-bootcamp:v1 Port: 8080/TCP Host Port: 0/TCP Environment: Mounts: Volumes: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: NewReplicaSet: myapp-b5d775f5d (1/1 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 95s deployment-controller Scaled up replica set myapp-b5d775f5d to 1 Expose Service \u00b6 Get the Pod and Deployment we created just now. kubectl get deployment myapp -o wide kubectl get pod -o wide Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-b5d775f5d-cx8dx 1/1 Running 0 2m34s 10.244.102.7 cka003 Send http request to the Pod curl 10.244.102.7:8080 with below result. Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 To make pod be accessed outside, we need expose port 8080 to a node port. A related service will be created. kubectl expose deployment myapp --type=NodePort --port=8080 Get details of service myapp by executing kubectl get svc myapp -o wide . NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR myapp NodePort 11.244.74.3 8080:30514/TCP 7s app=myapp Send http request to service port. curl 11.244.74.3:8080 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-cx8dx | v=1 Get more details of the service. kubectl get svc myapp -o yaml kubectl describe svc myapp Get details of related endpoint myapp by executing kubectl get endpoints myapp -o wide . NAME ENDPOINTS AGE myapp 10.244.102.7:8080 43s Send http request to the service and node sucessfully. Pod port 8080 is mapped to node port 32566 . Send http request to node port on cka003 . curl :30514 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 Attach to Ubuntu Pod we created and send http request to the Service and Pod and Node of myapp . kubectl exec --stdin --tty ubuntu -- /bin/bash curl 10.244.102.7:8080 curl 11.244.74.3:8080 curl :30514 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 Scale out Deployment \u00b6 Scale out by replicaset. We set three replicasets to scale out deployment myapp . The number of deployment myapp is now three. kubectl scale deployment myapp --replicas=3 Get status of deployment kubectl get deployment myapp Get status of replicaset kubectl get replicaset Rolling update \u00b6 Command usage: kubectl set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N . With the command kubectl get deployment , we will get deployment name myapp and related container name kubernetes-bootcamp . kubectl get deployment myapp -o wide With the command kubectl set image to update image to many versions and log the change under deployment's annotations with option --record . kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record Current replicas status kubectl get replicaset -o wide -l app=myapp Result. Pods are running on new Replicas. NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR myapp-5dbd68cc99 1 1 0 8s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v2 app=myapp,pod-template-hash=5dbd68cc99 myapp-b5d775f5d 3 3 3 14m kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp,pod-template-hash=b5d775f5d We can get the change history under metadata.annotations . kubectl get deployment myapp -o yaml Result apiVersion : apps/v1 kind : Deployment metadata : annotations : deployment.kubernetes.io/revision : \"2\" kubernetes.io/change-cause : kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true ...... We can also get the change history by command kubectl rollout history , and show details with specific revision --revision= . kubectl rollout history deployment/myapp Result deployment.apps/myapp REVISION CHANGE-CAUSE 1 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true Get rollout history with specific revision. kubectl rollout history deployment/myapp --revision=2 Roll back to previous revision with command kubectl rollout undo , or roll back to specific revision with option --to-revision= . kubectl rollout undo deployment/myapp --to-revision=1 Revision 1 was replaced by new revision 3 now. kubectl rollout history deployment/myapp Result deployment.apps/myapp REVISION CHANGE-CAUSE 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true 3 Event \u00b6 Get detail event info of related Pod. kubectl describe pod myapp-b5d775f5d-jlx6g Result looks like below. ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 54s default-scheduler Successfully assigned dev/myapp-b5d775f5d-jlx6g to cka003 Normal Pulled 53s kubelet Container image \"docker.io/jocatalin/kubernetes-bootcamp:v1\" already present on machine Normal Created 53s kubelet Created container kubernetes-bootcamp Normal Started 53s kubelet Started container kubernetes-bootcamp Get detail event info of entire cluster. kubectl get event Logging \u00b6 Get log info of Pod. kubectl logs -f kubectl logs -f -c Get a Pod logs kubectl logs -f myapp-b5d775f5d-jlx6g Kubernetes Bootcamp App Started At: 2022-07-23T06:54:18.532Z | Running On: myapp-b5d775f5d-jlx6g Get log info of K8s components. kubectl logs kube-apiserver-cka001 -n kube-system kubectl logs kube-controller-manager-cka001 -n kube-system kubectl logs kube-scheduler-cka001 -n kube-system kubectl logs etcd-cka001 -n kube-system systemctl status kubelet journalctl -fu kubelet kubectl logs kube-proxy-5cdbj -n kube-system Clean up. kubectl delete service myapp kubectl delete deployment myapp","title":"Operations on Resources"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#case-study-operations-on-resources","text":"Scenario: Node Label Annotation Namespace ServiceAccount Authorization Grant API access authorization to default ServiceAccount Deployment Expose Service Scale out the Deployment Rolling update Rolling back update Event Logging","title":"Case Study: Operations on Resources"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#node-label","text":"Add/update/remove node Label. # Update node label kubectl label node cka002 node=demonode # Get node info with label info kubectl get node --show-labels # Search node by label kubectl get node -l node=demonode # Remove a lable of node kubectl label node cka002 node-","title":"Node Label"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#annotation","text":"Create Nginx deployment kubectl create deploy nginx --image=nginx:mainline Get Annotation info. kubectl describe deployment/nginx Result ...... Labels: app=nginx Annotations: deployment.kubernetes.io/revision: 1 Selector: app=nginx ...... Add new Annotation. kubectl annotate deployment nginx owner=James.H Now annotation looks like below. ...... Labels: app=nginx Annotations: deployment.kubernetes.io/revision: 1 owner: James.H Selector: app=nginx ...... Update/Overwrite Annotation. kubectl annotate deployment/nginx owner=K8s --overwrite Now annotation looks like below. ...... Annotations: deployment.kubernetes.io/revision: 1 owner: K8s Selector: app=nginx ...... Remove Annotation kubectl annotate deployment/nginx owner- ...... Labels: app=nginx Annotations: deployment.kubernetes.io/revision: 1 Selector: app=nginx ...... Clean up kubectl delete deployment nginx","title":"Annotation"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#namespace","text":"Get current available namespaces. kubectl get namespace Result NAME STATUS AGE default Active 3h45m dev Active 3h11m kube-node-lease Active 3h45m kube-public Active 3h45m kube-system Active 3h45m Get Pod under a specific namespace. kubectl get pod -n kube-system Result NAME READY STATUS RESTARTS AGE calico-kube-controllers-5c64b68895-jr4nl 1/1 Running 0 3h25m calico-node-dsx76 1/1 Running 0 3h25m calico-node-p5rf2 1/1 Running 0 3h25m calico-node-tr22l 1/1 Running 0 3h25m coredns-6d8c4cb4d-g4jxc 1/1 Running 0 3h45m coredns-6d8c4cb4d-sqcvj 1/1 Running 0 3h45m etcd-cka001 1/1 Running 0 3h45m kube-apiserver-cka001 1/1 Running 0 3h45m kube-controller-manager-cka001 1/1 Running 0 3h45m kube-proxy-5cdbj 1/1 Running 0 3h41m kube-proxy-cm4hc 1/1 Running 0 3h45m kube-proxy-g4w52 1/1 Running 0 3h41m kube-scheduler-cka001 1/1 Running 0 3h45m Get Pods in all namespaces. kubectl get pod --all-namespaces kubectl get pod -A","title":"Namespace"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#serviceaccount-authorization","text":"With Kubernetes 1.23 and lower version, when we create a new namespace, Kubernetes will automatically create a ServiceAccount default and a token default-token-xxxxx . With Kubernetes 1.24, only ServiceAccount default is created automatically when a new namespace is created, need manually create a toke linked to the ServiceAccount default . Here is an example to create a new namespace dev , we can see that only ServiceAcccount: default was created in namespace dev , no secretes (token) linked to the ServiceAccount default . kubectl create namespace dev kubectl get serviceaccount -n dev kubectl get secrets -n dev There is a default cluster role admin . But there is no clusterrole binding to the cluster role admin . kubectl get clusterrole admin kubectl get clusterrolebinding | grep ClusterRole/admin Role and rolebinding is namespaces based. On namespace dev , there is no role and rolebinding. kubectl get role -n dev kubectl get rolebinding -n dev A Secret in the Kubernetes cluster is an object and it is used to store sensitive information such as username, password, and token, etc. The objective of Secrets is to encode or hash the credentials. The secrets can be reused in the various Pod definition file. A kubernetes.io/service-account-token type of Secret is used to store a token that identifies a service account. When using this Secret type, you need to ensure that the kubernetes.io/service-account.name annotation is set to an existing service account name. Let's create token for the ServiceAcccount: default in namespace dev . kubectl apply -f - << EOF apiVersion: v1 kind: Secret metadata: name: default-token-dev namespace: dev annotations: kubernetes.io/service-account.name: \"default\" type: kubernetes.io/service-account-token EOF Now we get ServiceAcccount: default and Secret (token) default-token-dev in namespace dev . kubectl get serviceaccount -n dev kubectl get secrets -n dev Get token of the service account default . TOKEN=$(kubectl -n dev describe secret $(kubectl -n dev get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d ' ') echo $TOKEN Get API Service address. APISERVER=$(kubectl config view | grep https | cut -f 2- -d \":\" | tr -d \" \") echo $APISERVER Get Pod resources in namespace dev via API server with JSON layout. curl $APISERVER/api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN\" --insecure We will receive 403 forbidden error message. The ServiceAccount default does not have authorization to access pod in namespace dev . Let's create a rolebinding rolebinding-admin to bind cluster role admin to service account default in namespapce dev . Hence service account default is granted adminstrator authorization in namespace dev . # Usage: kubectl create rolebinding --clusterrole= --serviceaccount=: --namespace= # Crate rolebinding: kubectl create rolebinding rolebinding-admin --clusterrole=admin --serviceaccount=dev:default --namespace=dev Result looks like below by executing kubectl get rolebinding -n dev . NAME ROLE AGE rolebinding-admin ClusterRole/admin 10s Try again, get pod resources in namespace dev via API server with JSON layout. curl $APISERVER/api/v1/namespaces/dev/pods --header \"Authorization: Bearer $TOKEN\" --insecure Clean up. kubectl delete namespace dev","title":"ServiceAccount Authorization"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#deployment","text":"Create a Ubuntu Pod for operation. And attach to the running Pod. kubectl create -f - << EOF apiVersion: v1 kind: Pod metadata: name: ubuntu labels: app: ubuntu spec: containers: - name: ubuntu image: ubuntu:latest command: [\"/bin/sleep\", \"3650d\"] imagePullPolicy: IfNotPresent restartPolicy: Always EOF kubectl exec --stdin --tty ubuntu -- /bin/bash Create a deployment, option --image specifies a image\uff0coption --port specifies port for external access. A pod is also created when deployment is created. kubectl create deployment myapp --image=docker.io/jocatalin/kubernetes-bootcamp:v1 --replicas=1 --port=8080 Get deployment status kubectl get deployment myapp -o wide Result NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR myapp 1/1 1 1 79s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp Get detail information of deployment. kubectl describe deployment myapp Result Name: myapp Namespace: dev CreationTimestamp: Sat, 23 Jul 2022 14:36:43 +0800 Labels: app=myapp Annotations: deployment.kubernetes.io/revision: 1 Selector: app=myapp Replicas: 1 desired | 1 updated | 1 total | 1 available | 0 unavailable StrategyType: RollingUpdate MinReadySeconds: 0 RollingUpdateStrategy: 25% max unavailable, 25% max surge Pod Template: Labels: app=myapp Containers: kubernetes-bootcamp: Image: docker.io/jocatalin/kubernetes-bootcamp:v1 Port: 8080/TCP Host Port: 0/TCP Environment: Mounts: Volumes: Conditions: Type Status Reason ---- ------ ------ Available True MinimumReplicasAvailable Progressing True NewReplicaSetAvailable OldReplicaSets: NewReplicaSet: myapp-b5d775f5d (1/1 replicas created) Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal ScalingReplicaSet 95s deployment-controller Scaled up replica set myapp-b5d775f5d to 1","title":"Deployment"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#expose-service","text":"Get the Pod and Deployment we created just now. kubectl get deployment myapp -o wide kubectl get pod -o wide Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-b5d775f5d-cx8dx 1/1 Running 0 2m34s 10.244.102.7 cka003 Send http request to the Pod curl 10.244.102.7:8080 with below result. Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 To make pod be accessed outside, we need expose port 8080 to a node port. A related service will be created. kubectl expose deployment myapp --type=NodePort --port=8080 Get details of service myapp by executing kubectl get svc myapp -o wide . NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR myapp NodePort 11.244.74.3 8080:30514/TCP 7s app=myapp Send http request to service port. curl 11.244.74.3:8080 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-cx8dx | v=1 Get more details of the service. kubectl get svc myapp -o yaml kubectl describe svc myapp Get details of related endpoint myapp by executing kubectl get endpoints myapp -o wide . NAME ENDPOINTS AGE myapp 10.244.102.7:8080 43s Send http request to the service and node sucessfully. Pod port 8080 is mapped to node port 32566 . Send http request to node port on cka003 . curl :30514 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1 Attach to Ubuntu Pod we created and send http request to the Service and Pod and Node of myapp . kubectl exec --stdin --tty ubuntu -- /bin/bash curl 10.244.102.7:8080 curl 11.244.74.3:8080 curl :30514 Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1","title":"Expose Service"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#scale-out-deployment","text":"Scale out by replicaset. We set three replicasets to scale out deployment myapp . The number of deployment myapp is now three. kubectl scale deployment myapp --replicas=3 Get status of deployment kubectl get deployment myapp Get status of replicaset kubectl get replicaset","title":"Scale out Deployment"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#rolling-update","text":"Command usage: kubectl set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N . With the command kubectl get deployment , we will get deployment name myapp and related container name kubernetes-bootcamp . kubectl get deployment myapp -o wide With the command kubectl set image to update image to many versions and log the change under deployment's annotations with option --record . kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record Current replicas status kubectl get replicaset -o wide -l app=myapp Result. Pods are running on new Replicas. NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR myapp-5dbd68cc99 1 1 0 8s kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v2 app=myapp,pod-template-hash=5dbd68cc99 myapp-b5d775f5d 3 3 3 14m kubernetes-bootcamp docker.io/jocatalin/kubernetes-bootcamp:v1 app=myapp,pod-template-hash=b5d775f5d We can get the change history under metadata.annotations . kubectl get deployment myapp -o yaml Result apiVersion : apps/v1 kind : Deployment metadata : annotations : deployment.kubernetes.io/revision : \"2\" kubernetes.io/change-cause : kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true ...... We can also get the change history by command kubectl rollout history , and show details with specific revision --revision= . kubectl rollout history deployment/myapp Result deployment.apps/myapp REVISION CHANGE-CAUSE 1 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true Get rollout history with specific revision. kubectl rollout history deployment/myapp --revision=2 Roll back to previous revision with command kubectl rollout undo , or roll back to specific revision with option --to-revision= . kubectl rollout undo deployment/myapp --to-revision=1 Revision 1 was replaced by new revision 3 now. kubectl rollout history deployment/myapp Result deployment.apps/myapp REVISION CHANGE-CAUSE 2 kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true 3 ","title":"Rolling update"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#event","text":"Get detail event info of related Pod. kubectl describe pod myapp-b5d775f5d-jlx6g Result looks like below. ...... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 54s default-scheduler Successfully assigned dev/myapp-b5d775f5d-jlx6g to cka003 Normal Pulled 53s kubelet Container image \"docker.io/jocatalin/kubernetes-bootcamp:v1\" already present on machine Normal Created 53s kubelet Created container kubernetes-bootcamp Normal Started 53s kubelet Started container kubernetes-bootcamp Get detail event info of entire cluster. kubectl get event","title":"Event"},{"location":"k8s/cka_en/foundamentals/casestudy-operation-resources/#logging","text":"Get log info of Pod. kubectl logs -f kubectl logs -f -c Get a Pod logs kubectl logs -f myapp-b5d775f5d-jlx6g Kubernetes Bootcamp App Started At: 2022-07-23T06:54:18.532Z | Running On: myapp-b5d775f5d-jlx6g Get log info of K8s components. kubectl logs kube-apiserver-cka001 -n kube-system kubectl logs kube-controller-manager-cka001 -n kube-system kubectl logs kube-scheduler-cka001 -n kube-system kubectl logs etcd-cka001 -n kube-system systemctl status kubelet journalctl -fu kubelet kubectl logs kube-proxy-5cdbj -n kube-system Clean up. kubectl delete service myapp kubectl delete deployment myapp","title":"Logging"},{"location":"k8s/cka_en/foundamentals/clustermgt/","text":"Cluster Management \u00b6 Scenario: etcd Backup and Restore Install etcdctl Create Deployment Before Backup Backup etcd Create Deployment After Backup Stop Services Stop etcd Restore etcd Start Services Verify etcd Backup and Restore \u00b6 Install etcdctl \u00b6 Download etcd package from Github. wget https://github.com/etcd-io/etcd/releases/download/v3.5.3/etcd-v3.5.3-linux-amd64.tar.gz Unzip and grant execute permission. tar -zxvf etcd-v3.5.3-linux-amd64.tar.gz cp etcd-v3.5.3-linux-amd64/etcdctl /usr/local/bin/ sudo chmod u+x /usr/local/bin/etcdctl Verify etcdctl --help Create Deployment Before Backup \u00b6 Create Deployment before backup. kubectl create deployment app-before-backup --image=nginx Backup etcd \u00b6 Usage * is the actual IP address of Control Plane. * --endpoints : specify where to save backup of etcd, 2379 is etcd port. * --cert : sepcify etcd certificate, which was generated by kubeadm and saved in /etc/kubernetes/pki/etcd/ . * --key : specify etcd certificate key, which was generated by kubeadm and saved in /etc/kubernetes/pki/etcd/ . * --cacert : specify etcd certificate CA, which was generated by kubeadm and saved in /etc/kubernetes/pki/etcd/ . etcdctl \\ --endpoints=https://:2379 \\ --cert=/etc/kubernetes/pki/etcd/server.crt \\ --key=/etc/kubernetes/pki/etcd/server.key \\ --cacert=/etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot-$(date +\"%Y%m%d%H%M%S\").db etcdctl \\ --endpoints=https://:2379 \\ --cert=/etc/kubernetes/pki/etcd/server.crt \\ --key=/etc/kubernetes/pki/etcd/server.key \\ --cacert=/etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot-$(date +\"%Y%m%d%H%M%S\").db Output: {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.328+0800\",\"caller\":\"snapshot/v3_snapshot.go:65\",\"msg\":\"created temporary db file\",\"path\":\"snapshot-20220724185121.db.part\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:211\",\"msg\":\"opened snapshot stream; downloading\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"caller\":\"snapshot/v3_snapshot.go:73\",\"msg\":\"fetching snapshot\",\"endpoint\":\"https://:2379\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.415+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:219\",\"msg\":\"completed snapshot read; closing\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:88\",\"msg\":\"fetched snapshot\",\"endpoint\":\"https://:2379\",\"size\":\"3.6 MB\",\"took\":\"now\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:97\",\"msg\":\"saved\",\"path\":\"snapshot-20220724185121.db\"} Snapshot saved at snapshot-20220724185121.db We can get the backup file in current directory with ls -al command. -rw------- 1 root root 3616800 Jul 24 18:51 snapshot-20220724185121.db Create Deployment After Backup \u00b6 Create Deployment after backup. kubectl create deployment app-after-backup --image=nginx Delete Deployment we created before backup. kubectl delete deployment app-before-backup Check Deployment status kubectl get deploy NAME READY UP-TO-DATE AVAILABLE AGE app-after-backup 1/1 1 1 108s Stop Services \u00b6 Delete etcd directory. mv /var/lib/etcd/ /var/lib/etcd.bak Stop kubelet systemctl stop kubelet Stop kube-apiserver nerdctl -n k8s.io ps -a | grep apiserver 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001 Stop those up status containers. nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0c5e69118f1b nerdctl -n k8s.io stop 638bb602c310 No up status kube-apiserver now. nerdctl -n k8s.io ps -a | grep apiserver 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001 Stop etcd \u00b6 nerdctl -n k8s.io ps -a | grep etcd 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/etcd-cka001 Stop those up status containers. nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0965b195f41a nerdctl -n k8s.io stop 9e1bea9f25d1 No up status etcd now. nerdctl -n k8s.io ps -a | grep etcd 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001 Restore etcd \u00b6 Execute the restore operation on Control Plane node with actual backup file, here it's file snapshot-20220724185121.db . etcdctl snapshot restore snapshot-20220724185121.db \\ --endpoints=:2379 \\ --cert=/etc/kubernetes/pki/etcd/server.crt \\ --key=/etc/kubernetes/pki/etcd/server.key \\ --cacert=/etc/kubernetes/pki/etcd/ca.crt\\ --data-dir=/var/lib/etcd Output: Deprecated: Use `etcdutl snapshot restore` instead. 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:248 restoring snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\", \"stack\": \"go.etcd.io/etcd/etcdutl/v3/snapshot.(*v3Manager).Restore\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/snapshot/v3_snapshot.go:254\\ngo.etcd.io/etcd/etcdutl/v3/etcdutl.SnapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/etcdutl/snapshot_command.go:147\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3/command.snapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/command/snapshot_command.go:129\\ngithub.com/spf13/cobra.(*Command).execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856\\ngithub.com/spf13/cobra.(*Command).ExecuteC\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960\\ngithub.com/spf13/cobra.(*Command).Execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:897\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.Start\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:107\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.MustStart\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:111\\nmain.main\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/main.go:59\\nruntime.main\\n\\t/go/gos/go1.16.15/src/runtime/proc.go:225\"} 2022-07-24T18:57:49+08:00 info membership/store.go:141 Trimming membership information from the backend... 2022-07-24T18:57:49+08:00 info membership/cluster.go:421 added member {\"cluster-id\": \"cdf818194e3a8c32\", \"local-member-id\": \"0\", \"added-peer-id\": \"8e9e05c52164694d\", \"added-peer-peer-urls\": [\"http://localhost:2380\"]} 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:269 restored snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\"} Check if etcd folder is back from restore. tree /var/lib/etcd /var/lib/etcd \u2514\u2500\u2500 member \u251c\u2500\u2500 snap \u2502 \u251c\u2500\u2500 0000000000000001-0000000000000001.snap \u2502 \u2514\u2500\u2500 db \u2514\u2500\u2500 wal \u2514\u2500\u2500 0000000000000000-0000000000000000.wal Start Services \u00b6 Start kubelet . The kube-apiserver and etcd will be started automatically by kubelet . systemctl start kubelet Execute below comamnds to make sure services are all up. systemctl status kubelet.service nerdctl -n k8s.io ps -a | grep etcd nerdctl -n k8s.io ps -a | grep apiserver The current status of etcd . 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 3b8f37c87782 registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 6 seconds ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001 fbbbb628a945 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 6 seconds ago Up k8s://kube-system/etcd-cka001 The current status of apiserver . 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 281cf4c6670d registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 14 seconds ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 5ed8295d92da registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 15 seconds ago Up k8s://kube-system/kube-apiserver-cka001 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001 Verify \u00b6 Check cluster status, if the Pod app-before-backup is there. kubectl get deploy Result NAME READY UP-TO-DATE AVAILABLE AGE app-before-backup 1/1 1 1 11m Upgrade \u00b6 Scenario: Upgrade Evict Control Plane node Check current available version of kubeadm Upgrade kubeadm to new version Check upgrade plan Apply upgrade plan to upgrade to new version Upgrade kubelet and kubectl Enable Control Plane node scheduling Evict Worker nodes Upgrade kubeadm and kubelet Enable Worker node scheduling Reference documentation Upgrade Control Plane \u00b6 Preparation \u00b6 Evict Control Plane node. kubectl drain --ignore-daemonsets kubectl drain cka001 --ignore-daemonsets node/cka001 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-dsx76, kube-system/kube-proxy-cm4hc evicting pod kube-system/calico-kube-controllers-5c64b68895-jr4nl evicting pod kube-system/coredns-6d8c4cb4d-g4jxc evicting pod kube-system/coredns-6d8c4cb4d-sqcvj pod/calico-kube-controllers-5c64b68895-jr4nl evicted pod/coredns-6d8c4cb4d-g4jxc evicted pod/coredns-6d8c4cb4d-sqcvj evicted node/cka001 drained The Control Plane node is now in SchedulingDisabled status. kubectl get node -owide Result NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 Check current available version of kubeadm . apt policy kubeadm kubeadm: Installed: 1.24.0-00 Candidate: 1.24.3-00 Version table: 1.24.3-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.1-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages *** 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 100 /var/lib/dpkg/status 1.23.7-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages ...... Upgrade kubeadm to Candidate: 1.24.2-00 version. sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades Check upgrade plan. kubeadm upgrade plan Get below guideline of upgrade. [upgrade/config] Making sure the configuration is correct: [upgrade/config] Reading configuration from the cluster... [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [preflight] Running pre-flight checks. [upgrade] Running cluster health checks [upgrade] Fetching available versions to upgrade to [upgrade/versions] Cluster version: v1.24.0 [upgrade/versions] kubeadm version: v1.24.2 I0724 19:05:00.111855 1142460 version.go:255] remote version is much newer: v1.24.3; falling back to: stable-1.23 [upgrade/versions] Target version: v1.24.2 [upgrade/versions] Latest version in the v1.23 series: v1.24.2 Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply': COMPONENT CURRENT TARGET kubelet 3 x v1.24.0 v1.24.2 Upgrade to the latest version in the v1.23 series: COMPONENT CURRENT TARGET kube-apiserver v1.24.0 v1.24.2 kube-controller-manager v1.24.0 v1.24.2 kube-scheduler v1.24.0 v1.24.2 kube-proxy v1.24.0 v1.24.2 CoreDNS v1.8.6 v1.8.6 etcd 3.5.1-0 3.5.1-0 You can now apply the upgrade by executing the following command: kubeadm upgrade apply v1.24.2 _____________________________________________________________________ The table below shows the current state of component configs as understood by this version of kubeadm. Configs that have a \"yes\" mark in the \"MANUAL UPGRADE REQUIRED\" column require manual config upgrade or resetting to kubeadm defaults before a successful upgrade can be performed. The version to manually upgrade to is denoted in the \"PREFERRED VERSION\" column. API GROUP CURRENT VERSION PREFERRED VERSION MANUAL UPGRADE REQUIRED kubeproxy.config.k8s.io v1alpha1 v1alpha1 no kubelet.config.k8s.io v1beta1 v1beta1 no _____________________________________________________________________ Upgrade Control Plane \u00b6 Refer to upgrade plan, let's upgrade to v1.24.2 version. kubeadm upgrade apply v1.24.2 With option --etcd-upgrade=false , the etcd can be excluded from the upgrade. kubeadm upgrade apply v1.24.2 --etcd-upgrade=false It's successful when receiving below message. [upgrade/successful] SUCCESS! Your cluster was upgraded to \"v1.24.2\". Enjoy! [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so. Upgrade kubelet and kubectl . sudo apt-get -y install kubelet=1.24.2-00 kubectl=1.24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet Get current node status. kubectl get node NAME STATUS ROLES AGE VERSION cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0 After verify that each node is in Ready status, enable node scheduling. kubectl uncordon kubectl uncordon cka001 Output: node/cka001 uncordoned Check node status again. Make sure all nodes are in Ready status. kubectl get node Output: NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0 Upgrade Worker \u00b6 Preparation for Worker \u00b6 Log on to cka001 Evict Worker nodes, explicitly specify to remove local storage if needed. kubectl drain --ignore-daemonsets --force kubectl drain --ignore-daemonsets --delete-emptydir-data --force If have error on dependency of emptydir , use the 2 nd command. kubectl drain cka002 --ignore-daemonsets --force kubectl drain cka002 --ignore-daemonsets --delete-emptydir-data --force node/cka002 cordoned WARNING: deleting Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet: dev/ubuntu; ignoring DaemonSet-managed Pods: kube-system/calico-node-p5rf2, kube-system/kube-proxy-zvs68 evicting pod ns-netpol/pod-netpol-5b67b6b496-2cgnw evicting pod dev/ubuntu evicting pod dev/app-before-backup-66dc9d5cb-6xc8c evicting pod dev/nfs-client-provisioner-86d7fb78b6-2f5dx evicting pod dev/pod-netpol-2-77478d77ff-l6rzm evicting pod ingress-nginx/ingress-nginx-admission-patch-nk9fv evicting pod ingress-nginx/ingress-nginx-admission-create-lgtdj evicting pod kube-system/coredns-6d8c4cb4d-l4kx4 pod/ingress-nginx-admission-create-lgtdj evicted pod/ingress-nginx-admission-patch-nk9fv evicted pod/nfs-client-provisioner-86d7fb78b6-2f5dx evicted pod/app-before-backup-66dc9d5cb-6xc8c evicted pod/coredns-6d8c4cb4d-l4kx4 evicted pod/pod-netpol-5b67b6b496-2cgnw evicted pod/pod-netpol-2-77478d77ff-l6rzm evicted pod/ubuntu evicted node/cka002 drained Upgrade Workers \u00b6 Log on to cka002 . Download kubeadm with version v1.24.2 . sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades Upgrade kubeadm . sudo kubeadm upgrade node Upgrade kubelet . sudo apt-get -y install kubelet=1.24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet Make sure all nodes are in Ready status, then, enable node scheduling. kubectl uncordon kubectl uncordon cka002 Verify Upgrade \u00b6 Check node status. kubectl get node Result NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.0 Repeat the same on node cka003 . Log onto cka001 . If have error on dependency of emptydir , use the 2 nd command. kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --force kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --delete-emptydir-data --force Log onto cka003 and perform below commands. sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades sudo kubeadm upgrade node sudo apt-get -y install kubelet=1.24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet kubectl get node kubectl uncordon cka003 Get final status of all nodes. kubectl get node NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.2 Summary: Control Plane kubectl get node -owide kubectl drain cka001 --ignore-daemonsets kubectl get node -owide apt policy kubeadm apt-get -y install kubeadm=1.24.0-00 --allow-downgrades kubeadm upgrade plan kubeadm upgrade apply v1.24.0 # kubeadm upgrade apply v1.24.0 --etcd-upgrade = false apt-get -y install kubelet=1.24.0-00 kubectl=1.24.0-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl get node kubectl uncordon cka001 Worker Node On Control Plane kubectl drain cka002 --ignore-daemonsets On Workder Node apt-get -y install kubeadm=1.24.1-00 --allow-downgrades kubeadm upgrade node apt-get -y install kubelet=1.24.1-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl uncordon cka002 Repeat for other Worker nodes","title":"Cluster Management"},{"location":"k8s/cka_en/foundamentals/clustermgt/#cluster-management","text":"Scenario: etcd Backup and Restore Install etcdctl Create Deployment Before Backup Backup etcd Create Deployment After Backup Stop Services Stop etcd Restore etcd Start Services Verify","title":"Cluster Management"},{"location":"k8s/cka_en/foundamentals/clustermgt/#etcd-backup-and-restore","text":"","title":"etcd Backup and Restore"},{"location":"k8s/cka_en/foundamentals/clustermgt/#install-etcdctl","text":"Download etcd package from Github. wget https://github.com/etcd-io/etcd/releases/download/v3.5.3/etcd-v3.5.3-linux-amd64.tar.gz Unzip and grant execute permission. tar -zxvf etcd-v3.5.3-linux-amd64.tar.gz cp etcd-v3.5.3-linux-amd64/etcdctl /usr/local/bin/ sudo chmod u+x /usr/local/bin/etcdctl Verify etcdctl --help","title":"Install etcdctl"},{"location":"k8s/cka_en/foundamentals/clustermgt/#create-deployment-before-backup","text":"Create Deployment before backup. kubectl create deployment app-before-backup --image=nginx","title":"Create Deployment Before Backup"},{"location":"k8s/cka_en/foundamentals/clustermgt/#backup-etcd","text":"Usage * is the actual IP address of Control Plane. * --endpoints : specify where to save backup of etcd, 2379 is etcd port. * --cert : sepcify etcd certificate, which was generated by kubeadm and saved in /etc/kubernetes/pki/etcd/ . * --key : specify etcd certificate key, which was generated by kubeadm and saved in /etc/kubernetes/pki/etcd/ . * --cacert : specify etcd certificate CA, which was generated by kubeadm and saved in /etc/kubernetes/pki/etcd/ . etcdctl \\ --endpoints=https://:2379 \\ --cert=/etc/kubernetes/pki/etcd/server.crt \\ --key=/etc/kubernetes/pki/etcd/server.key \\ --cacert=/etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot-$(date +\"%Y%m%d%H%M%S\").db etcdctl \\ --endpoints=https://:2379 \\ --cert=/etc/kubernetes/pki/etcd/server.crt \\ --key=/etc/kubernetes/pki/etcd/server.key \\ --cacert=/etc/kubernetes/pki/etcd/ca.crt \\ snapshot save snapshot-$(date +\"%Y%m%d%H%M%S\").db Output: {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.328+0800\",\"caller\":\"snapshot/v3_snapshot.go:65\",\"msg\":\"created temporary db file\",\"path\":\"snapshot-20220724185121.db.part\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:211\",\"msg\":\"opened snapshot stream; downloading\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.337+0800\",\"caller\":\"snapshot/v3_snapshot.go:73\",\"msg\":\"fetching snapshot\",\"endpoint\":\"https://:2379\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.415+0800\",\"logger\":\"client\",\"caller\":\"v3/maintenance.go:219\",\"msg\":\"completed snapshot read; closing\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:88\",\"msg\":\"fetched snapshot\",\"endpoint\":\"https://:2379\",\"size\":\"3.6 MB\",\"took\":\"now\"} {\"level\":\"info\",\"ts\":\"2022-07-24T18:51:21.477+0800\",\"caller\":\"snapshot/v3_snapshot.go:97\",\"msg\":\"saved\",\"path\":\"snapshot-20220724185121.db\"} Snapshot saved at snapshot-20220724185121.db We can get the backup file in current directory with ls -al command. -rw------- 1 root root 3616800 Jul 24 18:51 snapshot-20220724185121.db","title":"Backup etcd"},{"location":"k8s/cka_en/foundamentals/clustermgt/#create-deployment-after-backup","text":"Create Deployment after backup. kubectl create deployment app-after-backup --image=nginx Delete Deployment we created before backup. kubectl delete deployment app-before-backup Check Deployment status kubectl get deploy NAME READY UP-TO-DATE AVAILABLE AGE app-after-backup 1/1 1 1 108s","title":"Create Deployment After Backup"},{"location":"k8s/cka_en/foundamentals/clustermgt/#stop-services","text":"Delete etcd directory. mv /var/lib/etcd/ /var/lib/etcd.bak Stop kubelet systemctl stop kubelet Stop kube-apiserver nerdctl -n k8s.io ps -a | grep apiserver 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/kube-apiserver-cka001 Stop those up status containers. nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0c5e69118f1b nerdctl -n k8s.io stop 638bb602c310 No up status kube-apiserver now. nerdctl -n k8s.io ps -a | grep apiserver 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001","title":"Stop Services"},{"location":"k8s/cka_en/foundamentals/clustermgt/#stop-etcd","text":"nerdctl -n k8s.io ps -a | grep etcd 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Up k8s://kube-system/etcd-cka001 Stop those up status containers. nerdctl -n k8s.io stop nerdctl -n k8s.io stop 0965b195f41a nerdctl -n k8s.io stop 9e1bea9f25d1 No up status etcd now. nerdctl -n k8s.io ps -a | grep etcd 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001","title":"Stop etcd"},{"location":"k8s/cka_en/foundamentals/clustermgt/#restore-etcd","text":"Execute the restore operation on Control Plane node with actual backup file, here it's file snapshot-20220724185121.db . etcdctl snapshot restore snapshot-20220724185121.db \\ --endpoints=:2379 \\ --cert=/etc/kubernetes/pki/etcd/server.crt \\ --key=/etc/kubernetes/pki/etcd/server.key \\ --cacert=/etc/kubernetes/pki/etcd/ca.crt\\ --data-dir=/var/lib/etcd Output: Deprecated: Use `etcdutl snapshot restore` instead. 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:248 restoring snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\", \"stack\": \"go.etcd.io/etcd/etcdutl/v3/snapshot.(*v3Manager).Restore\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/snapshot/v3_snapshot.go:254\\ngo.etcd.io/etcd/etcdutl/v3/etcdutl.SnapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdutl/etcdutl/snapshot_command.go:147\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3/command.snapshotRestoreCommandFunc\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/command/snapshot_command.go:129\\ngithub.com/spf13/cobra.(*Command).execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856\\ngithub.com/spf13/cobra.(*Command).ExecuteC\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960\\ngithub.com/spf13/cobra.(*Command).Execute\\n\\t/go/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:897\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.Start\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:107\\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.MustStart\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/ctlv3/ctl.go:111\\nmain.main\\n\\t/go/src/go.etcd.io/etcd/release/etcd/etcdctl/main.go:59\\nruntime.main\\n\\t/go/gos/go1.16.15/src/runtime/proc.go:225\"} 2022-07-24T18:57:49+08:00 info membership/store.go:141 Trimming membership information from the backend... 2022-07-24T18:57:49+08:00 info membership/cluster.go:421 added member {\"cluster-id\": \"cdf818194e3a8c32\", \"local-member-id\": \"0\", \"added-peer-id\": \"8e9e05c52164694d\", \"added-peer-peer-urls\": [\"http://localhost:2380\"]} 2022-07-24T18:57:49+08:00 info snapshot/v3_snapshot.go:269 restored snapshot {\"path\": \"snapshot-20220724185121.db\", \"wal-dir\": \"/var/lib/etcd/member/wal\", \"data-dir\": \"/var/lib/etcd\", \"snap-dir\": \"/var/lib/etcd/member/snap\"} Check if etcd folder is back from restore. tree /var/lib/etcd /var/lib/etcd \u2514\u2500\u2500 member \u251c\u2500\u2500 snap \u2502 \u251c\u2500\u2500 0000000000000001-0000000000000001.snap \u2502 \u2514\u2500\u2500 db \u2514\u2500\u2500 wal \u2514\u2500\u2500 0000000000000000-0000000000000000.wal","title":"Restore etcd"},{"location":"k8s/cka_en/foundamentals/clustermgt/#start-services","text":"Start kubelet . The kube-apiserver and etcd will be started automatically by kubelet . systemctl start kubelet Execute below comamnds to make sure services are all up. systemctl status kubelet.service nerdctl -n k8s.io ps -a | grep etcd nerdctl -n k8s.io ps -a | grep apiserver The current status of etcd . 0965b195f41a registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 32 hours ago Created k8s://kube-system/etcd-cka001/etcd 3b8f37c87782 registry.aliyuncs.com/google_containers/etcd:3.5.1-0 \"etcd --advertise-cl\u2026\" 6 seconds ago Up k8s://kube-system/etcd-cka001/etcd 9e1bea9f25d1 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/etcd-cka001 fbbbb628a945 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 6 seconds ago Up k8s://kube-system/etcd-cka001 The current status of apiserver . 0c5e69118f1b registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001/kube-apiserver 281cf4c6670d registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 14 seconds ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 5ed8295d92da registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 15 seconds ago Up k8s://kube-system/kube-apiserver-cka001 638bb602c310 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 32 hours ago Created k8s://kube-system/kube-apiserver-cka001","title":"Start Services"},{"location":"k8s/cka_en/foundamentals/clustermgt/#verify","text":"Check cluster status, if the Pod app-before-backup is there. kubectl get deploy Result NAME READY UP-TO-DATE AVAILABLE AGE app-before-backup 1/1 1 1 11m","title":"Verify"},{"location":"k8s/cka_en/foundamentals/clustermgt/#upgrade","text":"Scenario: Upgrade Evict Control Plane node Check current available version of kubeadm Upgrade kubeadm to new version Check upgrade plan Apply upgrade plan to upgrade to new version Upgrade kubelet and kubectl Enable Control Plane node scheduling Evict Worker nodes Upgrade kubeadm and kubelet Enable Worker node scheduling Reference documentation","title":"Upgrade"},{"location":"k8s/cka_en/foundamentals/clustermgt/#upgrade-control-plane","text":"","title":"Upgrade Control Plane"},{"location":"k8s/cka_en/foundamentals/clustermgt/#preparation","text":"Evict Control Plane node. kubectl drain --ignore-daemonsets kubectl drain cka001 --ignore-daemonsets node/cka001 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-dsx76, kube-system/kube-proxy-cm4hc evicting pod kube-system/calico-kube-controllers-5c64b68895-jr4nl evicting pod kube-system/coredns-6d8c4cb4d-g4jxc evicting pod kube-system/coredns-6d8c4cb4d-sqcvj pod/calico-kube-controllers-5c64b68895-jr4nl evicted pod/coredns-6d8c4cb4d-g4jxc evicted pod/coredns-6d8c4cb4d-sqcvj evicted node/cka001 drained The Control Plane node is now in SchedulingDisabled status. kubectl get node -owide Result NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 32h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 Check current available version of kubeadm . apt policy kubeadm kubeadm: Installed: 1.24.0-00 Candidate: 1.24.3-00 Version table: 1.24.3-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.1-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 1.24.2-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages *** 1.24.0-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages 100 /var/lib/dpkg/status 1.23.7-00 500 500 https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial/main amd64 Packages ...... Upgrade kubeadm to Candidate: 1.24.2-00 version. sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades Check upgrade plan. kubeadm upgrade plan Get below guideline of upgrade. [upgrade/config] Making sure the configuration is correct: [upgrade/config] Reading configuration from the cluster... [upgrade/config] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [preflight] Running pre-flight checks. [upgrade] Running cluster health checks [upgrade] Fetching available versions to upgrade to [upgrade/versions] Cluster version: v1.24.0 [upgrade/versions] kubeadm version: v1.24.2 I0724 19:05:00.111855 1142460 version.go:255] remote version is much newer: v1.24.3; falling back to: stable-1.23 [upgrade/versions] Target version: v1.24.2 [upgrade/versions] Latest version in the v1.23 series: v1.24.2 Components that must be upgraded manually after you have upgraded the control plane with 'kubeadm upgrade apply': COMPONENT CURRENT TARGET kubelet 3 x v1.24.0 v1.24.2 Upgrade to the latest version in the v1.23 series: COMPONENT CURRENT TARGET kube-apiserver v1.24.0 v1.24.2 kube-controller-manager v1.24.0 v1.24.2 kube-scheduler v1.24.0 v1.24.2 kube-proxy v1.24.0 v1.24.2 CoreDNS v1.8.6 v1.8.6 etcd 3.5.1-0 3.5.1-0 You can now apply the upgrade by executing the following command: kubeadm upgrade apply v1.24.2 _____________________________________________________________________ The table below shows the current state of component configs as understood by this version of kubeadm. Configs that have a \"yes\" mark in the \"MANUAL UPGRADE REQUIRED\" column require manual config upgrade or resetting to kubeadm defaults before a successful upgrade can be performed. The version to manually upgrade to is denoted in the \"PREFERRED VERSION\" column. API GROUP CURRENT VERSION PREFERRED VERSION MANUAL UPGRADE REQUIRED kubeproxy.config.k8s.io v1alpha1 v1alpha1 no kubelet.config.k8s.io v1beta1 v1beta1 no _____________________________________________________________________","title":"Preparation"},{"location":"k8s/cka_en/foundamentals/clustermgt/#upgrade-control-plane_1","text":"Refer to upgrade plan, let's upgrade to v1.24.2 version. kubeadm upgrade apply v1.24.2 With option --etcd-upgrade=false , the etcd can be excluded from the upgrade. kubeadm upgrade apply v1.24.2 --etcd-upgrade=false It's successful when receiving below message. [upgrade/successful] SUCCESS! Your cluster was upgraded to \"v1.24.2\". Enjoy! [upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so. Upgrade kubelet and kubectl . sudo apt-get -y install kubelet=1.24.2-00 kubectl=1.24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet Get current node status. kubectl get node NAME STATUS ROLES AGE VERSION cka001 Ready,SchedulingDisabled control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0 After verify that each node is in Ready status, enable node scheduling. kubectl uncordon kubectl uncordon cka001 Output: node/cka001 uncordoned Check node status again. Make sure all nodes are in Ready status. kubectl get node Output: NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.0 cka003 Ready 32h v1.24.0","title":"Upgrade Control Plane"},{"location":"k8s/cka_en/foundamentals/clustermgt/#upgrade-worker","text":"","title":"Upgrade Worker"},{"location":"k8s/cka_en/foundamentals/clustermgt/#preparation-for-worker","text":"Log on to cka001 Evict Worker nodes, explicitly specify to remove local storage if needed. kubectl drain --ignore-daemonsets --force kubectl drain --ignore-daemonsets --delete-emptydir-data --force If have error on dependency of emptydir , use the 2 nd command. kubectl drain cka002 --ignore-daemonsets --force kubectl drain cka002 --ignore-daemonsets --delete-emptydir-data --force node/cka002 cordoned WARNING: deleting Pods not managed by ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet: dev/ubuntu; ignoring DaemonSet-managed Pods: kube-system/calico-node-p5rf2, kube-system/kube-proxy-zvs68 evicting pod ns-netpol/pod-netpol-5b67b6b496-2cgnw evicting pod dev/ubuntu evicting pod dev/app-before-backup-66dc9d5cb-6xc8c evicting pod dev/nfs-client-provisioner-86d7fb78b6-2f5dx evicting pod dev/pod-netpol-2-77478d77ff-l6rzm evicting pod ingress-nginx/ingress-nginx-admission-patch-nk9fv evicting pod ingress-nginx/ingress-nginx-admission-create-lgtdj evicting pod kube-system/coredns-6d8c4cb4d-l4kx4 pod/ingress-nginx-admission-create-lgtdj evicted pod/ingress-nginx-admission-patch-nk9fv evicted pod/nfs-client-provisioner-86d7fb78b6-2f5dx evicted pod/app-before-backup-66dc9d5cb-6xc8c evicted pod/coredns-6d8c4cb4d-l4kx4 evicted pod/pod-netpol-5b67b6b496-2cgnw evicted pod/pod-netpol-2-77478d77ff-l6rzm evicted pod/ubuntu evicted node/cka002 drained","title":"Preparation for Worker"},{"location":"k8s/cka_en/foundamentals/clustermgt/#upgrade-workers","text":"Log on to cka002 . Download kubeadm with version v1.24.2 . sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades Upgrade kubeadm . sudo kubeadm upgrade node Upgrade kubelet . sudo apt-get -y install kubelet=1.24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet Make sure all nodes are in Ready status, then, enable node scheduling. kubectl uncordon kubectl uncordon cka002","title":"Upgrade Workers"},{"location":"k8s/cka_en/foundamentals/clustermgt/#verify-upgrade","text":"Check node status. kubectl get node Result NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.0 Repeat the same on node cka003 . Log onto cka001 . If have error on dependency of emptydir , use the 2 nd command. kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --force kubectl drain cka003 --ignore-daemonsets --ignore-daemonsets --delete-emptydir-data --force Log onto cka003 and perform below commands. sudo apt-get -y install kubeadm=1.24.2-00 --allow-downgrades sudo kubeadm upgrade node sudo apt-get -y install kubelet=1.24.2-00 --allow-downgrades sudo systemctl daemon-reload sudo systemctl restart kubelet kubectl get node kubectl uncordon cka003 Get final status of all nodes. kubectl get node NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 32h v1.24.2 cka002 Ready 32h v1.24.2 cka003 Ready 32h v1.24.2 Summary: Control Plane kubectl get node -owide kubectl drain cka001 --ignore-daemonsets kubectl get node -owide apt policy kubeadm apt-get -y install kubeadm=1.24.0-00 --allow-downgrades kubeadm upgrade plan kubeadm upgrade apply v1.24.0 # kubeadm upgrade apply v1.24.0 --etcd-upgrade = false apt-get -y install kubelet=1.24.0-00 kubectl=1.24.0-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl get node kubectl uncordon cka001 Worker Node On Control Plane kubectl drain cka002 --ignore-daemonsets On Workder Node apt-get -y install kubeadm=1.24.1-00 --allow-downgrades kubeadm upgrade node apt-get -y install kubelet=1.24.1-00 --allow-downgrades systemctl daemon-reload systemctl restart kubelet kubectl uncordon cka002 Repeat for other Worker nodes","title":"Verify Upgrade"},{"location":"k8s/cka_en/foundamentals/configuration/","text":"","title":"Configuration"},{"location":"k8s/cka_en/foundamentals/daemonset/","text":"DaemonSet \u00b6 Scenario: Create DaemonSet. The DaemonSet will run its pod on each node. Demo: Create DaemonSet daemonset-busybox . kubectl apply -f - << EOF apiVersion: apps/v1 kind: DaemonSet metadata: name: daemonset-busybox labels: app: daemonset-busybox spec: selector: matchLabels: app: daemonset-busybox template: metadata: labels: app: daemonset-busybox spec: tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: busybox image: busybox:1.28 args: - sleep - \"10000\" EOF Get status of DaemonSet. kubectl get daemonsets daemonset-busybox Result NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset-busybox 3 3 3 3 3 5m33s Get DaemonSet Pod status. It's deployed on each node. kubectl get pod -o wide Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES daemonset-busybox-54cj5 1/1 Running 0 44s 10.244.102.4 cka003 daemonset-busybox-5tl55 1/1 Running 0 44s 10.244.228.197 cka001 daemonset-busybox-wg225 1/1 Running 0 44s 10.244.112.5 cka002 Clean up. kubectl delete daemonset daemonset-busybox","title":"DaemonSet"},{"location":"k8s/cka_en/foundamentals/daemonset/#daemonset","text":"Scenario: Create DaemonSet. The DaemonSet will run its pod on each node. Demo: Create DaemonSet daemonset-busybox . kubectl apply -f - << EOF apiVersion: apps/v1 kind: DaemonSet metadata: name: daemonset-busybox labels: app: daemonset-busybox spec: selector: matchLabels: app: daemonset-busybox template: metadata: labels: app: daemonset-busybox spec: tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: busybox image: busybox:1.28 args: - sleep - \"10000\" EOF Get status of DaemonSet. kubectl get daemonsets daemonset-busybox Result NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset-busybox 3 3 3 3 3 5m33s Get DaemonSet Pod status. It's deployed on each node. kubectl get pod -o wide Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES daemonset-busybox-54cj5 1/1 Running 0 44s 10.244.102.4 cka003 daemonset-busybox-5tl55 1/1 Running 0 44s 10.244.228.197 cka001 daemonset-busybox-wg225 1/1 Running 0 44s 10.244.112.5 cka002 Clean up. kubectl delete daemonset daemonset-busybox","title":"DaemonSet"},{"location":"k8s/cka_en/foundamentals/deployment/","text":"Deployment \u00b6 Scenario: Modify Existing Deployment, e.g., add port number in below demo. Demo: Create Deployment nginx . kubectl create deployment nginx --image = nginx Execute command below to get yaml template with port number. The option --port=8080 specified the port that this container exposes. kubectl create deployment nginx --image = nginx --port = 8080 --dry-run = client -o yaml Then we get to know the path to add port number, like below. kubectl explain deployment.spec.template.spec.containers.ports.containerPort Execute command below to edit the Deployemnt. kubectl edit deployment nginx Add below two lines to specify port number with 8080 and protocol is TCP . spec : template : spec : containers : - image : nginx name : nginx ports : - containerPort : 8080 protocol : TCP Use command kubectl describe deployment , we can see the port number was added. Pod Template : Labels : app=nginx Containers : nginx : Image : nginx Port : 8080/TCP Host Port : 0/TCP Environment : Mounts : Volumes : With command kubectl describe pod , we can see the port number was added. Containers : nginx : Container ID : containerd://af4a1243f981497074b5c006ac55fcf795688399871d1dfe91a095321f5c91aa Image : nginx Image ID : docker.io/library/nginx@sha256:1761fb5661e4d77e107427d8012ad3a5955007d997e0f4a3d41acc9ff20467c7 Port : 8080/TCP Host Port : 0/TCP State : Running Started : Sun, 24 Jul 2022 22:50:12 +0800 Ready : True Restart Count : 0 Environment : Mounts : /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hftdt (ro) Info: Some key fields of deployment (use kubectl explain ): deployment.spec.revisionHistoryLimit : The number of old ReplicaSets to retain to allow rollback. Defaults to 10 . deployment.spec.strategy.type : Type of deployment. Can be Recreate or RollingUpdate . Default is RollingUpdate . deployment.spec.strategy.rollingUpdate.maxUnavailable : The maximum number of pods that can be unavailable during the update. Defaults to 25%. deployment.spec.strategy.rollingUpdate.maxSurge : The maximum number of pods that can be scheduled above the desired number of pods. Defaults to 25%. This can not be 0 if MaxUnavailable is 0. deployment.spec.minReadySeconds : Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready).","title":"Deployment"},{"location":"k8s/cka_en/foundamentals/deployment/#deployment","text":"Scenario: Modify Existing Deployment, e.g., add port number in below demo. Demo: Create Deployment nginx . kubectl create deployment nginx --image = nginx Execute command below to get yaml template with port number. The option --port=8080 specified the port that this container exposes. kubectl create deployment nginx --image = nginx --port = 8080 --dry-run = client -o yaml Then we get to know the path to add port number, like below. kubectl explain deployment.spec.template.spec.containers.ports.containerPort Execute command below to edit the Deployemnt. kubectl edit deployment nginx Add below two lines to specify port number with 8080 and protocol is TCP . spec : template : spec : containers : - image : nginx name : nginx ports : - containerPort : 8080 protocol : TCP Use command kubectl describe deployment , we can see the port number was added. Pod Template : Labels : app=nginx Containers : nginx : Image : nginx Port : 8080/TCP Host Port : 0/TCP Environment : Mounts : Volumes : With command kubectl describe pod , we can see the port number was added. Containers : nginx : Container ID : containerd://af4a1243f981497074b5c006ac55fcf795688399871d1dfe91a095321f5c91aa Image : nginx Image ID : docker.io/library/nginx@sha256:1761fb5661e4d77e107427d8012ad3a5955007d997e0f4a3d41acc9ff20467c7 Port : 8080/TCP Host Port : 0/TCP State : Running Started : Sun, 24 Jul 2022 22:50:12 +0800 Ready : True Restart Count : 0 Environment : Mounts : /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-hftdt (ro) Info: Some key fields of deployment (use kubectl explain ): deployment.spec.revisionHistoryLimit : The number of old ReplicaSets to retain to allow rollback. Defaults to 10 . deployment.spec.strategy.type : Type of deployment. Can be Recreate or RollingUpdate . Default is RollingUpdate . deployment.spec.strategy.rollingUpdate.maxUnavailable : The maximum number of pods that can be unavailable during the update. Defaults to 25%. deployment.spec.strategy.rollingUpdate.maxSurge : The maximum number of pods that can be scheduled above the desired number of pods. Defaults to 25%. This can not be 0 if MaxUnavailable is 0. deployment.spec.minReadySeconds : Minimum number of seconds for which a newly created pod should be ready without any of its container crashing, for it to be considered available. Defaults to 0 (pod will be considered available as soon as it is ready).","title":"Deployment"},{"location":"k8s/cka_en/foundamentals/docker/","text":"Docker Fundamentals \u00b6 Demo environment \u00b6 Linux: openSUSE 15.3 cat /etc/os-release Output NAME=\"openSUSE Leap\" VERSION=\"15.3\" ID=\"opensuse-leap\" ID_LIKE=\"suse opensuse\" VERSION_ID=\"15.3\" PRETTY_NAME=\"openSUSE Leap 15.3\" ANSI_COLOR=\"0;32\" CPE_NAME=\"cpe:/o:opensuse:leap:15.3\" BUG_REPORT_URL=\"https://bugs.opensuse.org\" HOME_URL=\"https://www.opensuse.org/\" Linux Primitives \u00b6 chroot(using pivot_root) Changes the root directory for a process to any given directory namespaces Different processes see different environments even though they are on the same host/OS mnt (mount points) pid (process tree) net (network interfaces and connectivity) ipc (interprocess communication framework) uts (unix timesharing - domain name, hostname, etc.) uid (user IDs and mappings) cgroups(control groups) manage/limit resource allocation to individual processes Prioritization of processes Apparmor and SELinux profiles Security profiles to govern access to resources Kernel capabilities without capabilities: root can do everything, everybody else may do nothing 38 granular facilities to control privileges seccomp policies Limitation of allowed kernel syscalls Unallowed syscalls lead to process termination Netlink A Linux kernel interface used for inter-process communication (IPC) between both the kernel and userspace processes, and between different userspace processes. Netfilter A framework provided by the Linux kernel that allows various networking-related operations Packet filtering, network address translation, and port translation(iptables/nftables) used to direct network packages to individual containers More inforamtion could refer to LXC/LXD Let's download an image alpine to simulate an root file system under /opt/test folder. mkdir test cd test wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.4-x86_64.tar.gz tar zxvf alpine-minirootfs-3.13.4-x86_64.tar.gz -C alpine-minirootfs/ Current directory structure. tree ./test -L 1 Output ./test \u251c\u2500\u2500 alpine-minirootfs-3.13.4-x86_64.tar.gz \u251c\u2500\u2500 bin \u251c\u2500\u2500 dev \u251c\u2500\u2500 etc \u251c\u2500\u2500 home \u251c\u2500\u2500 lib \u251c\u2500\u2500 media \u251c\u2500\u2500 mnt \u251c\u2500\u2500 opt \u251c\u2500\u2500 proc \u251c\u2500\u2500 root \u251c\u2500\u2500 run \u251c\u2500\u2500 sbin \u251c\u2500\u2500 srv \u251c\u2500\u2500 sys \u251c\u2500\u2500 tmp \u251c\u2500\u2500 usr \u2514\u2500\u2500 var Mount folder /opt/test/proc to a file and use command unshare to build a guest system. sudo mount -t tmpfs tmpfs /opt/test/proc sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # ps -ef PID USER TIME COMMAND 1 root 0 :00 /bin/sh 2 root 0 :00 ps -ef / # touch 123 / # ls 123 123 The file 123 created in guest system is accessable and writable from host system. su - ls 123 echo hello > 123 We will see above change in guest system. / # cat 123 hello Let's create two folders /opt/test-1 and /opt/test-2 . mkdir test-1 mkdir test-2 Create two guests system. Mount /opt/test/home/ to different folders for different guests. sudo mount --bind /opt/test-1 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-1\" > 123.1 /home # cat 123.1 test-1 sudo mount --bind /opt/test-2 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-2\" > 123.2 /home # cat 123.2 test-2 ll test/home ll test-1/ ll test-2/ With above demo, the conclusion is that two guests share same home folder on host system and will impact each other. Installing Docker \u00b6 Install Docker engine by referring the guide , and Docker Desktop by referring the guide . Install engine via openSUSE repository automatically. sudo zypper in docker The docker group is automatically created at package installation time. The user can communicate with the local Docker daemon upon its next login. The Docker daemon listens on a local socket which is accessible only by the root user and by the members of the docker group. Add current user to docker group. sudo usermod -aG docker $USER Enable and start Docker engine. sudo systemctl enable docker.service sudo systemctl start docker.service sudo systemctl status docker.service Container lifecycle \u00b6 Overview \u00b6 Pull down below images in advance. docker image pull busybox docker image pull nginx docker image pull alpine docker image pull jenkins/jenkins:lts docker image pull golang:1.12-alpine docker image pull golang Download some docker images. Create and run a new busybox container interactively and connect a pseudo terminal to it. Inside the container, use the top command to find out that /bin/sh is running as process with the PID 1 and top process is also running. After that, just exit. docker image ls docker run -d -it --name busybox_v1 -v /opt/test:/docker busybox:latest /bin/sh docker container ps -a docker exec -it 185efe490507 /bin/sh / # top Mem: 3627396K used, 12731512K free, 10080K shrd, 2920K buff, 2999340K cached CPU: 0 .0% usr 0 .1% sys 0 .0% nic 99 .8% idle 0 .0% io 0 .0% irq 0 .0% sirq Load average: 0 .38 1 .09 1 .29 2 /277 14 PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND 1 0 root S 1332 0 .0 1 0 .0 /bin/sh 8 0 root S 1332 0 .0 2 0 .0 /bin/sh 14 8 root R 1328 0 .0 1 0 .0 top / # exitbuild Start a new nginx container in detached mode. Use the docker exec command to start another shell ( /bin/sh ) in the nginx container. Use ps to find out that sh and ps commands are running in your container. docker run -d -it --name nginx_v1 -v /opt/test:/docker nginx:latest /bin/sh docker container ps -a docker exec -it edb640127a0d /bin/sh # ps /bin/sh: 2 : ps: not found # apt-get update && apt-get install -y procps # ps PID TTY TIME CMD 8 pts/1 00 :00:00 sh 351 pts/1 00 :00:00 ps # exit Now we have two running containers below. docker container ps -a Let's use docker logs to display the logs of the container we just exited from. The option --since 35m means display log in last 35 minutes. docker logs nginx_v1 --details --since 35m docker logs busybox_v1 --details --since 35m Let's make use of this to create a new stage: Use the docker stop command to end your nginx container. docker stop busybox_v1 docker stop nginx_v1 docker container ps -a With above command docker container ps -a , we get a list of all running and exited containers. Remove them with docker rm. Use docker rm $(docker ps -aq) to clean up all containers on your host. Use it with caution! docker rm busybox_v1 docker container ps -a Ports and volumes \u00b6 Now, let's run an nginx webserver in a container and serve a website to the outside world. Start a new nginx container and export the port of the nginx webserver to a random port that is chosen by Docker. Use command docker ps to find you which port the webserver is forwarded. Access the docker with the forwarded port number on host http://localhost: . docker container ps -a docker run -d -P --name nginx_v2 nginx:latest docker container ps -a Start another nginx container and expose port to 1080 on host as an example via http://localhost:1080 . docker run -d -p 1080:80 --name nginx_v3 nginx:latest docker container ps -a Let's make use of this to create a new stage: Use command docker inspect to find out which port is exposed by the image. Network information (ip, gateway, ports, etc.) is part of the output JSON format. docker inspect nginx_v3 Create a file index.html in folder /opt/test with below sample content. < html > < head > < title > Sample Website from my container < body > < h1 > This is a custom website. < p > This website is served from my < a href = \"http://www.docker.com\" target = \"_blank\" > Docker container. Start a new container that bind-mounts host directory /opt/test to container directory /usr/share/nginx/html as a volume, so that NGINX will publish the HTML file wee just created instead of its default message via http://localhost:49159/ below. docker run -d -P --mount type=bind,source=/opt/test/,target=/usr/share/nginx/html --name nginx_v3-1 nginx:latest docker container ps -a Check nginx config file on where is the html home page stored in container. docker exec -it nginx_v3-1 /bin/sh # cd /etc/nginx/conf.d # ls default.conf # cat default.conf server { listen 80; listen [::]:80; server_name localhost; # access_log /var/log/nginx/host.access.log main ; location / { root /usr/share/nginx/html; <-- index index.html index.htm; } # error_page 404 /404.html ; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } # proxy the PHP scripts to Apache listening on 127 .0.0.1:80 # # location ~ \\. php$ { # proxy_pass http://127.0.0.1 ; # } # pass the PHP scripts to FastCGI server listening on 127 .0.0.1:9000 # # location ~ \\. php$ { # root html ; # fastcgi_pass 127 .0.0.1:9000 ; # fastcgi_index index.php ; # fastcgi_param SCRIPT_FILENAME /scripts $fastcgi_script_name ; # include fastcgi_params ; # } # deny access to .htaccess files, if Apache 's document root # concurs with nginx' s one # # location ~ / \\. ht { # deny all ; # } } # cd /usr/share/nginx/html # cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    # It's recommendable to add a persistence with volumes API, instead of storing data in a docker container. Docker supports 2 ways of mount: Bind mounts: mount a local host directory onto a certain path in the container. Everything that was present before in the target directory is hidden (nature of the bind mount). For example, if you have some configuration you want to inject, write your config file, store it on your docker host at /home/container/config and mount the content of this directory to /usr/application/config (assuming the application reads config from there). Command: docker run --mount type=bind,source=,target= \u2026 Named volumes: docker can create a separated storage volume. Its lifecycle is independent from the container but still managed by docker. Upon creation, the content of the mount target is merged into the volume. Command: docker run --mount source=,target= \u2026 How to differentiate between bind mountbuild s and named volumes? When specifying an absolute path, docker assumes a bind mount. When you just give a name (like in a relative path \u201cconfig\u201d), it will assume a named volume and create a volume \u201cconfig\u201d. Note: Persistent storage is 'provided' by the host. It can be a part of the file system on the host directly but also an NFS mount. Dockerfile \u00b6 Let's build an image with a Dockerfile,build tag it and upload it to a registry. Get docker image build history. docker image history nginx:latest Create an empty directory /opt/tmp-1 , change to the directory and create an sample index.html file in /opt/tmp-1 . /opt/tmp-1> cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    Use FROM to extend an existing image, specify the release number. Use COPY to copy a new default website into the image, e.g., /usr/share/nginx/html Create SSL configuration /opt/tmp-1/ssl.conf for nginx. server { listen 443 ssl; server_name localhost; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; location / { root /usr/share/nginx/html; index index.html index.htm; } } Use OpenSSL to create a self-signed certificate so SSL/TLS to work would work. Use the following command to create an encryption key and a certificate. openssl req -x509 -nodes -newkey rsa:4096 -keyout nginx.key -out nginx.crt -days 365 -subj \"/CN=$(hostname)\" To enable encrypted HTTPS, we need to expose port 443 with the EXPOSE directive. The default nginx image only exposes port 80 for unencrypted HTTP. In summary, we create below Dockerfile in foder /opt/tmp-1 . cat Dockerfile Output FROM nginx:latest # copy the custom website into the image COPY index.html /usr/share/nginx/html # copy the SSL configuration file into the image COPY ssl.conf /etc/nginx/conf.d/ssl.conf # download the SSL key and certificate into the image COPY nginx.key /etc/nginx/ssl/ COPY nginx.crt /etc/nginx/ssl/ # expose the HTTPS port EXPOSE 443 We have five files in foder /opt/tmp-1 till now. ls /opt/tmp-1 Output Dockerfile index.html nginx.crt nginx.key ssl.conf Now let's use the docker build command to build the image, forward the containers ports 80 and 443. docker build -t nginx:my1 /opt/tmp-1/ docker image ls docker run -d -p 1086:80 -p 1088:443 --name nginx_v5 nginx:my1 docker container ps -a Above changes can be validated via below links: http://localhost:1086/ https://localhost:1088/ Register an account in DockerHub and enable access token in Docker Hub for CLI client authentication. docker login Input username and password. Username: Password: Tag the image to give image a nice name and a release number as tag, e.g., name is secure_nginx_0001 , tag is v1 . docker tag nginx:my1 secure_nginx_0001:v1 docker push secure_nginx_0001:v1 docker image ls Multi-stage Dockerfile \u00b6 Let's show an example of multi-stage build. The multi-stage in the context of Docker means, we can have more than one line with a FROM keyword. Create folder /opt/tmp-2 and /opt/tmp-2/tmpl . Create files edit.html , view.html , wiki.go and structure likes below. tree -l /opt/tmp-2 . \u251c\u2500\u2500 tmpl \u2502 \u251c\u2500\u2500 edit.html \u2502 \u2514\u2500\u2500 view.html \u2514\u2500\u2500 wiki.go Create an new Dockerfile that starts cat Dockerfile # app builder stage FROM golang:1.12-alpine as builder ## copy the go source code over and build the binary WORKDIR /go/src COPY wiki.go /go/src/wiki.go RUN go build wiki.go # app exec stage # separate & new image starts here!# FROM alpine:3.9 # prepare file system etc RUN mkdir -p /app/data /app/tmpl && adduser -S -D -H -h /app appuser COPY tmpl/* /app/tmpl/ # get the compiled binary from the previous stage COPY --from = builder /go/src/wiki /app/wiki # prepare runtime env RUN chown -R appuser /app USER appuser WORKDIR /app # expose app port & set default command EXPOSE 8080 CMD [ \"/app/wiki\" ] Build the images by Dockerfile we created above. docker build -t lizard/golang:my1 /opt/tmp-2/ Run the image in detached mode, create a port forwarding from port 8080 in the container to port 1090 on the host. docker run -d -p 1090:8080 --name golan_v1 lizard/golang:my1 Access the container via link http://localhost:1090 Tab the golang image we created and push it to DockerHub. docker tag lizard/golang:my1 /golang_0001:v1 docker push /golang_0001:v1","title":"Fundamentals"},{"location":"k8s/cka_en/foundamentals/docker/#docker-fundamentals","text":"","title":"Docker Fundamentals"},{"location":"k8s/cka_en/foundamentals/docker/#demo-environment","text":"Linux: openSUSE 15.3 cat /etc/os-release Output NAME=\"openSUSE Leap\" VERSION=\"15.3\" ID=\"opensuse-leap\" ID_LIKE=\"suse opensuse\" VERSION_ID=\"15.3\" PRETTY_NAME=\"openSUSE Leap 15.3\" ANSI_COLOR=\"0;32\" CPE_NAME=\"cpe:/o:opensuse:leap:15.3\" BUG_REPORT_URL=\"https://bugs.opensuse.org\" HOME_URL=\"https://www.opensuse.org/\"","title":"Demo environment"},{"location":"k8s/cka_en/foundamentals/docker/#linux-primitives","text":"chroot(using pivot_root) Changes the root directory for a process to any given directory namespaces Different processes see different environments even though they are on the same host/OS mnt (mount points) pid (process tree) net (network interfaces and connectivity) ipc (interprocess communication framework) uts (unix timesharing - domain name, hostname, etc.) uid (user IDs and mappings) cgroups(control groups) manage/limit resource allocation to individual processes Prioritization of processes Apparmor and SELinux profiles Security profiles to govern access to resources Kernel capabilities without capabilities: root can do everything, everybody else may do nothing 38 granular facilities to control privileges seccomp policies Limitation of allowed kernel syscalls Unallowed syscalls lead to process termination Netlink A Linux kernel interface used for inter-process communication (IPC) between both the kernel and userspace processes, and between different userspace processes. Netfilter A framework provided by the Linux kernel that allows various networking-related operations Packet filtering, network address translation, and port translation(iptables/nftables) used to direct network packages to individual containers More inforamtion could refer to LXC/LXD Let's download an image alpine to simulate an root file system under /opt/test folder. mkdir test cd test wget https://dl-cdn.alpinelinux.org/alpine/v3.13/releases/x86_64/alpine-minirootfs-3.13.4-x86_64.tar.gz tar zxvf alpine-minirootfs-3.13.4-x86_64.tar.gz -C alpine-minirootfs/ Current directory structure. tree ./test -L 1 Output ./test \u251c\u2500\u2500 alpine-minirootfs-3.13.4-x86_64.tar.gz \u251c\u2500\u2500 bin \u251c\u2500\u2500 dev \u251c\u2500\u2500 etc \u251c\u2500\u2500 home \u251c\u2500\u2500 lib \u251c\u2500\u2500 media \u251c\u2500\u2500 mnt \u251c\u2500\u2500 opt \u251c\u2500\u2500 proc \u251c\u2500\u2500 root \u251c\u2500\u2500 run \u251c\u2500\u2500 sbin \u251c\u2500\u2500 srv \u251c\u2500\u2500 sys \u251c\u2500\u2500 tmp \u251c\u2500\u2500 usr \u2514\u2500\u2500 var Mount folder /opt/test/proc to a file and use command unshare to build a guest system. sudo mount -t tmpfs tmpfs /opt/test/proc sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # ps -ef PID USER TIME COMMAND 1 root 0 :00 /bin/sh 2 root 0 :00 ps -ef / # touch 123 / # ls 123 123 The file 123 created in guest system is accessable and writable from host system. su - ls 123 echo hello > 123 We will see above change in guest system. / # cat 123 hello Let's create two folders /opt/test-1 and /opt/test-2 . mkdir test-1 mkdir test-2 Create two guests system. Mount /opt/test/home/ to different folders for different guests. sudo mount --bind /opt/test-1 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-1\" > 123.1 /home # cat 123.1 test-1 sudo mount --bind /opt/test-2 /opt/test/home/ sudo unshare --pid --mount-proc = $PWD /test/proc --fork chroot ./test/ /bin/sh / # cd /home /home # echo \"test-2\" > 123.2 /home # cat 123.2 test-2 ll test/home ll test-1/ ll test-2/ With above demo, the conclusion is that two guests share same home folder on host system and will impact each other.","title":"Linux Primitives"},{"location":"k8s/cka_en/foundamentals/docker/#installing-docker","text":"Install Docker engine by referring the guide , and Docker Desktop by referring the guide . Install engine via openSUSE repository automatically. sudo zypper in docker The docker group is automatically created at package installation time. The user can communicate with the local Docker daemon upon its next login. The Docker daemon listens on a local socket which is accessible only by the root user and by the members of the docker group. Add current user to docker group. sudo usermod -aG docker $USER Enable and start Docker engine. sudo systemctl enable docker.service sudo systemctl start docker.service sudo systemctl status docker.service","title":"Installing Docker"},{"location":"k8s/cka_en/foundamentals/docker/#container-lifecycle","text":"","title":"Container lifecycle"},{"location":"k8s/cka_en/foundamentals/docker/#overview","text":"Pull down below images in advance. docker image pull busybox docker image pull nginx docker image pull alpine docker image pull jenkins/jenkins:lts docker image pull golang:1.12-alpine docker image pull golang Download some docker images. Create and run a new busybox container interactively and connect a pseudo terminal to it. Inside the container, use the top command to find out that /bin/sh is running as process with the PID 1 and top process is also running. After that, just exit. docker image ls docker run -d -it --name busybox_v1 -v /opt/test:/docker busybox:latest /bin/sh docker container ps -a docker exec -it 185efe490507 /bin/sh / # top Mem: 3627396K used, 12731512K free, 10080K shrd, 2920K buff, 2999340K cached CPU: 0 .0% usr 0 .1% sys 0 .0% nic 99 .8% idle 0 .0% io 0 .0% irq 0 .0% sirq Load average: 0 .38 1 .09 1 .29 2 /277 14 PID PPID USER STAT VSZ %VSZ CPU %CPU COMMAND 1 0 root S 1332 0 .0 1 0 .0 /bin/sh 8 0 root S 1332 0 .0 2 0 .0 /bin/sh 14 8 root R 1328 0 .0 1 0 .0 top / # exitbuild Start a new nginx container in detached mode. Use the docker exec command to start another shell ( /bin/sh ) in the nginx container. Use ps to find out that sh and ps commands are running in your container. docker run -d -it --name nginx_v1 -v /opt/test:/docker nginx:latest /bin/sh docker container ps -a docker exec -it edb640127a0d /bin/sh # ps /bin/sh: 2 : ps: not found # apt-get update && apt-get install -y procps # ps PID TTY TIME CMD 8 pts/1 00 :00:00 sh 351 pts/1 00 :00:00 ps # exit Now we have two running containers below. docker container ps -a Let's use docker logs to display the logs of the container we just exited from. The option --since 35m means display log in last 35 minutes. docker logs nginx_v1 --details --since 35m docker logs busybox_v1 --details --since 35m Let's make use of this to create a new stage: Use the docker stop command to end your nginx container. docker stop busybox_v1 docker stop nginx_v1 docker container ps -a With above command docker container ps -a , we get a list of all running and exited containers. Remove them with docker rm. Use docker rm $(docker ps -aq) to clean up all containers on your host. Use it with caution! docker rm busybox_v1 docker container ps -a","title":"Overview"},{"location":"k8s/cka_en/foundamentals/docker/#ports-and-volumes","text":"Now, let's run an nginx webserver in a container and serve a website to the outside world. Start a new nginx container and export the port of the nginx webserver to a random port that is chosen by Docker. Use command docker ps to find you which port the webserver is forwarded. Access the docker with the forwarded port number on host http://localhost: . docker container ps -a docker run -d -P --name nginx_v2 nginx:latest docker container ps -a Start another nginx container and expose port to 1080 on host as an example via http://localhost:1080 . docker run -d -p 1080:80 --name nginx_v3 nginx:latest docker container ps -a Let's make use of this to create a new stage: Use command docker inspect to find out which port is exposed by the image. Network information (ip, gateway, ports, etc.) is part of the output JSON format. docker inspect nginx_v3 Create a file index.html in folder /opt/test with below sample content. < html > < head > < title > Sample Website from my container < body > < h1 > This is a custom website. < p > This website is served from my < a href = \"http://www.docker.com\" target = \"_blank\" > Docker container. Start a new container that bind-mounts host directory /opt/test to container directory /usr/share/nginx/html as a volume, so that NGINX will publish the HTML file wee just created instead of its default message via http://localhost:49159/ below. docker run -d -P --mount type=bind,source=/opt/test/,target=/usr/share/nginx/html --name nginx_v3-1 nginx:latest docker container ps -a Check nginx config file on where is the html home page stored in container. docker exec -it nginx_v3-1 /bin/sh # cd /etc/nginx/conf.d # ls default.conf # cat default.conf server { listen 80; listen [::]:80; server_name localhost; # access_log /var/log/nginx/host.access.log main ; location / { root /usr/share/nginx/html; <-- index index.html index.htm; } # error_page 404 /404.html ; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } # proxy the PHP scripts to Apache listening on 127 .0.0.1:80 # # location ~ \\. php$ { # proxy_pass http://127.0.0.1 ; # } # pass the PHP scripts to FastCGI server listening on 127 .0.0.1:9000 # # location ~ \\. php$ { # root html ; # fastcgi_pass 127 .0.0.1:9000 ; # fastcgi_index index.php ; # fastcgi_param SCRIPT_FILENAME /scripts $fastcgi_script_name ; # include fastcgi_params ; # } # deny access to .htaccess files, if Apache 's document root # concurs with nginx' s one # # location ~ / \\. ht { # deny all ; # } } # cd /usr/share/nginx/html # cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    # It's recommendable to add a persistence with volumes API, instead of storing data in a docker container. Docker supports 2 ways of mount: Bind mounts: mount a local host directory onto a certain path in the container. Everything that was present before in the target directory is hidden (nature of the bind mount). For example, if you have some configuration you want to inject, write your config file, store it on your docker host at /home/container/config and mount the content of this directory to /usr/application/config (assuming the application reads config from there). Command: docker run --mount type=bind,source=,target= \u2026 Named volumes: docker can create a separated storage volume. Its lifecycle is independent from the container but still managed by docker. Upon creation, the content of the mount target is merged into the volume. Command: docker run --mount source=,target= \u2026 How to differentiate between bind mountbuild s and named volumes? When specifying an absolute path, docker assumes a bind mount. When you just give a name (like in a relative path \u201cconfig\u201d), it will assume a named volume and create a volume \u201cconfig\u201d. Note: Persistent storage is 'provided' by the host. It can be a part of the file system on the host directly but also an NFS mount.","title":"Ports and volumes"},{"location":"k8s/cka_en/foundamentals/docker/#dockerfile","text":"Let's build an image with a Dockerfile,build tag it and upload it to a registry. Get docker image build history. docker image history nginx:latest Create an empty directory /opt/tmp-1 , change to the directory and create an sample index.html file in /opt/tmp-1 . /opt/tmp-1> cat index.html Sample Website from my container

    This is a custom website.

    This website is served from my Docker container.

    Use FROM to extend an existing image, specify the release number. Use COPY to copy a new default website into the image, e.g., /usr/share/nginx/html Create SSL configuration /opt/tmp-1/ssl.conf for nginx. server { listen 443 ssl; server_name localhost; ssl_certificate /etc/nginx/ssl/nginx.crt; ssl_certificate_key /etc/nginx/ssl/nginx.key; location / { root /usr/share/nginx/html; index index.html index.htm; } } Use OpenSSL to create a self-signed certificate so SSL/TLS to work would work. Use the following command to create an encryption key and a certificate. openssl req -x509 -nodes -newkey rsa:4096 -keyout nginx.key -out nginx.crt -days 365 -subj \"/CN=$(hostname)\" To enable encrypted HTTPS, we need to expose port 443 with the EXPOSE directive. The default nginx image only exposes port 80 for unencrypted HTTP. In summary, we create below Dockerfile in foder /opt/tmp-1 . cat Dockerfile Output FROM nginx:latest # copy the custom website into the image COPY index.html /usr/share/nginx/html # copy the SSL configuration file into the image COPY ssl.conf /etc/nginx/conf.d/ssl.conf # download the SSL key and certificate into the image COPY nginx.key /etc/nginx/ssl/ COPY nginx.crt /etc/nginx/ssl/ # expose the HTTPS port EXPOSE 443 We have five files in foder /opt/tmp-1 till now. ls /opt/tmp-1 Output Dockerfile index.html nginx.crt nginx.key ssl.conf Now let's use the docker build command to build the image, forward the containers ports 80 and 443. docker build -t nginx:my1 /opt/tmp-1/ docker image ls docker run -d -p 1086:80 -p 1088:443 --name nginx_v5 nginx:my1 docker container ps -a Above changes can be validated via below links: http://localhost:1086/ https://localhost:1088/ Register an account in DockerHub and enable access token in Docker Hub for CLI client authentication. docker login Input username and password. Username: Password: Tag the image to give image a nice name and a release number as tag, e.g., name is secure_nginx_0001 , tag is v1 . docker tag nginx:my1 secure_nginx_0001:v1 docker push secure_nginx_0001:v1 docker image ls","title":"Dockerfile"},{"location":"k8s/cka_en/foundamentals/docker/#multi-stage-dockerfile","text":"Let's show an example of multi-stage build. The multi-stage in the context of Docker means, we can have more than one line with a FROM keyword. Create folder /opt/tmp-2 and /opt/tmp-2/tmpl . Create files edit.html , view.html , wiki.go and structure likes below. tree -l /opt/tmp-2 . \u251c\u2500\u2500 tmpl \u2502 \u251c\u2500\u2500 edit.html \u2502 \u2514\u2500\u2500 view.html \u2514\u2500\u2500 wiki.go Create an new Dockerfile that starts cat Dockerfile # app builder stage FROM golang:1.12-alpine as builder ## copy the go source code over and build the binary WORKDIR /go/src COPY wiki.go /go/src/wiki.go RUN go build wiki.go # app exec stage # separate & new image starts here!# FROM alpine:3.9 # prepare file system etc RUN mkdir -p /app/data /app/tmpl && adduser -S -D -H -h /app appuser COPY tmpl/* /app/tmpl/ # get the compiled binary from the previous stage COPY --from = builder /go/src/wiki /app/wiki # prepare runtime env RUN chown -R appuser /app USER appuser WORKDIR /app # expose app port & set default command EXPOSE 8080 CMD [ \"/app/wiki\" ] Build the images by Dockerfile we created above. docker build -t lizard/golang:my1 /opt/tmp-2/ Run the image in detached mode, create a port forwarding from port 8080 in the container to port 1090 on the host. docker run -d -p 1090:8080 --name golan_v1 lizard/golang:my1 Access the container via link http://localhost:1090 Tab the golang image we created and push it to DockerHub. docker tag lizard/golang:my1 /golang_0001:v1 docker push /golang_0001:v1","title":"Multi-stage Dockerfile"},{"location":"k8s/cka_en/foundamentals/healthcheck/","text":"Health Check \u00b6 Status of Pod and Container \u00b6 Scenario: Create a pod with two containers. Demo: Create a Pod multi-pods with two containers nginx and busybox . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: labels: run: multi-pods name: multi-pods spec: containers: - image: nginx name: nginx - image: busybox name: busybox dnsPolicy: ClusterFirst restartPolicy: Always EOF Minotor the status with option --watch . The status of Pod was changed from ContainerCreating to NotReady to CrashLoopBackOff . kubectl get pod multi-pods --watch Get details of the Pod multi-pods , focus on Container's state under segment Containers and Conditions of Pod under segment Conditions . kubectl describe pod multi-pods Result ...... Containers: nginx: ...... State: Running Started: Sat, 23 Jul 2022 15:06:56 +0800 Ready: True Restart Count: 0 ...... busybox: ...... State: Terminated Reason: Completed Exit Code: 0 ...... Conditions: Type Status Initialized True Ready False ContainersReady False PodScheduled True ...... LivenessProbe \u00b6 Scenario: Create pod with livenessProbe check. Detail description of the demo can be found on the Kubernetes document . Demo: Create a yaml file liveness.yaml with livenessProbe setting and apply it. kubectl apply -f - <> ~/.bashrc source <(helm completion bash) Install MySQL from Helm \u00b6 Add bitnami Chartes Repository. helm repo add bitnami https://charts.bitnami.com/bitnami Get current Charts repositories. helm repo list NAME URL bitnami https://charts.bitnami.com/bitnami Sync up local Charts repositories. helm repo update Search bitnami Charts in repositories. helm search repo bitnami Search bitnami/mysql Charts in repositories. helm search repo bitnami/mysql Install MySQL Chart on namespace dev \uff1a helm install mysql bitnami/mysql -n dev Output NAME: mysql LAST DEPLOYED: Sun Jul 24 19:37:20 2022 NAMESPACE: dev STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: mysql CHART VERSION: 9.2.1 APP VERSION: 8.0.29 ** Please be patient while the chart is being deployed ** Tip: Watch the deployment status using the command: kubectl get pods -w --namespace dev Services: echo Primary: mysql.dev.svc.cluster.local:3306 Execute the following to get the administrator credentials: echo Username: root MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace dev mysql -o jsonpath=\"{.data.mysql-root-password}\" | base64 -d) To connect to your database: 1. Run a pod that you can use as a client: kubectl run mysql-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mysql:8.0.29-debian-11-r9 --namespace dev --env MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD --command -- bash 2. To connect to primary service (read/write): mysql -h mysql.dev.svc.cluster.local -uroot -p\"$MYSQL_ROOT_PASSWORD\" Check installed release\uff1a helm list Result NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 Check installed mysql release information. helm status mysql Check mysql Pod status. kubectl get pod Result NAME READY STATUS RESTARTS AGE mysql-0 1/1 Running 0 72s Develop a Chart \u00b6 Below is a demo on how to develop a Chart. Execute helm create to initiate a Chart\uff1a # Naming conventions of Chart: lowercase a~z and - ( minus sign ) helm create cka-demo A folder cka-demo was created. Check the folder structure. tree cka-demo/ Output cka-demo/ \u251c\u2500\u2500 charts \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 deployment.yaml \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u251c\u2500\u2500 hpa.yaml \u2502 \u251c\u2500\u2500 ingress.yaml \u2502 \u251c\u2500\u2500 NOTES.txt \u2502 \u251c\u2500\u2500 serviceaccount.yaml \u2502 \u251c\u2500\u2500 service.yaml \u2502 \u2514\u2500\u2500 tests \u2502 \u2514\u2500\u2500 test-connection.yaml \u2514\u2500\u2500 values.yaml Delete or empty some files, which will be re-created later. cd cka-demo rm -rf charts rm -rf templates/tests rm -rf templates/*.yaml echo \"\" > values.yaml echo \"\" > templates/NOTES.txt echo \"\" > templates/_helpers.tpl cd .. Now new structure looks like below. tree cka-demo/ Output cka-demo/ \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u2514\u2500\u2500 NOTES.txt \u2514\u2500\u2500 values.yaml NOTES.txt \u00b6 NOTES.txt is used to provide summary information to Chart users. In the demo, we will use NOTES.txt to privide summary info about whether the user passed CKA certificate or not. cd cka-demo/ vi templates/NOTES.txt Add below info. {{- if .Values.passExam }} Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: {{ .Values.ckaScore }} Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard {{- else }} Come on! you can do it next time! {{- end }} Deployment Template \u00b6 Let's use Busybox service to generate information. We use kubectl create deployment --dry-run=client -oyaml to generate Deployment yaml file and write it the yaml file content into file templates/deployment.yaml . kubectl create deployment cka-demo-busybox --image=busybox:latest --dry-run=client -oyaml > templates/deployment.yaml Check content of deployment yaml file templates/deployment.yaml . cat templates/deployment.yaml apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : 1 selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} Edit file templates/deployment.yaml . vi templates/deployment.yaml Let's replace value of .spec.replicas from 1 to a variable {{ .Values.replicaCount }} , so we can dynamicly assign replicas number for other Deployment. apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} The .spec.replicas will be replaced by actula value of .Values.replicaCount during deployment. Let's create another file values.yaml and add a variable replicaCount with default value 1 into the file. Strong recommended to add comments for each value we defined in file values.yaml . vi values.yaml # Number of deployment replicas replicaCount: 1 Let's add more variables into file templates/deployment.yaml . Replace Release name .metadata.name by {{ .Release.Name }} and filled with variable defined in file values.yaml . Replace label name .metadata.labels by {{- include \"cka-demo.labels\" . | nindent 4 }} , and filled with labels name cka-demo.labels defined in file _helpers.tpl . Replace .spec.replicas by {{ .Values.replicaCount }} and filled with variable defined in file values.yaml . Replace .spec.selector.matchLabels by {{- include \"cka-demo.selectorLabels\" . | nindent 6 }} and filled with cka-demo.selectorLabels defined in file _helpers.tpl . Replace .spec.template.metadata.labels by {{- include \"cka-demo.selectorLabels\" . | nindent 8 }} and filled with cka-demo.selectorLabels defined in file _helpers.tpl . Replace .spec.template.spec.containers[0].image by {{ .Values.image.repository }} and {{ .Values.image.tag }} and filled with variables defined in values.yaml for image name and image tag. Replace .spec.template.spec.containers[0].command and add if-else statement, if .Values.passExam is true, execute commands defined in .Values.passCommand , if false, execute commands defined in .Values.lostCommand . Use key from ConfigMap from .spec.template.spec.containers[0].env as prefix of ConfigMap name and filled with {{ .Values.studentName }} defined in file values.yaml . Replace .spec.template.spec.containers[0].resources by {{ .Values.resources }} and filled with variable defined in file values.yaml . The .Release.Name is built-in object, no need to be specified in file values.yaml . It's generated by Release by helm install . Remove unused lines and final one looks like below. apiVersion : apps/v1 kind : Deployment metadata : name : {{ .Release.Name }} labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : {{ - include \"cka-demo.selectorLabels\" . | nindent 6 }} template : metadata : labels : {{ - include \"cka-demo.selectorLabels\" . | nindent 8 }} spec : containers : - name : id-generator image : \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\" {{ - if .Values.passExam }} {{ - with .Values.passCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - else }} {{ - with .Values.lostCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - end }} env : - name : CKA_SCORE valueFrom : configMapKeyRef : name : {{ .Values.studentName }} -cka-score key : cka_score {{ - with .Values.resources }} resources : {{ - toYaml . | nindent 12 }} {{ - end }} restartPolicy : Always Update file values.yaml with variables default values. Suggestions\uff1aadd variables one and test one, don't add all at one time. vi values.yaml # Number of deployment replicas replicaCount: 1 # Image repository and tag image: repository: busybox tag: latest # Container start command passCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE) and your CKA certificate ID number is $(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 13; echo) ; sleep 86400\" lostCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE), Come on! you can do it next time! ; sleep 86400\" # Container resources resources: limits: cpu: 200m memory: 256Mi requests: cpu: 100m memory: 128Mi # Student Name studentName: whoareyou # Student pass CKA exam or not passExam: true ConfigMap Template \u00b6 ConfigMap is referred in the Deployment, hence we need define the ConfigMap template. We will combine name of ConfigMap and cka_score as a variable, like name-cka-score . vi templates/configmap.yaml apiVersion : v1 kind : ConfigMap metadata : name : {{ .Values.studentName }} -cka-score labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} data : cka_score : {{ .Values.ckaScore | quote }} The studentName was already defined in file values.yaml , we just need add ckaScore with default value. vi values.yaml # Student CKA Score ckaScore: 100 _helpers.tpl \u00b6 Define a common template _helpers.tpl to add labels and labels of Selector for labels of Deployment and ConfigMap. vi templates/_helpers.tpl {{/* Common labels */}} {{- define \"cka-demo.labels\" -}} {{ include \"cka-demo.selectorLabels\" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end -}} {{/* Selector labels */}} {{- define \"cka-demo.selectorLabels\" -}} app: {{ .Chart.Name }} release: {{ .Release.Name }} {{- end -}} Chart.yaml \u00b6 We use CKA logo as the icon of Chart wget https://www.cncf.io/wp-content/uploads/2021/09/kubernetes-cka-color.svg Edit Chart.yaml file. vi Chart.yaml Append icon info in the file. icon: file://./kubernetes-cka-color.svg Add author info for the Chart vi Chart.yaml maintainers: - name: James.H Final Chart.yaml looks like below. Don't forget to update appVersion: \"v1.23\" to current Kubernetes API version. apiVersion : v2 name : cka-demo description : A Helm chart for CKA demo. type : application version : 0.1.0 appVersion : \"v1.23\" maintainers : - name : James.H icon : file://./kubernetes-cka-color.svg Chart Debug \u00b6 Use helm lint to verify above change. helm lint 1 chart(s) linted, 0 chart(s) failed helm lint only check format of Chart, won't check Manifest file. We can use helm install --debug --dry-run or helm template to check Manifest output in order to verify all yaml files are correct or not. helm template cka-demo ./ Use helm install --debug --dry-run to simulate the installation. We can get expected results from two different options (passed or failed the CKA certificate). helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=99 \\ --set passExam=true helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=0 \\ --set passExam=false Package Chart to .tgz file, and upload to repository, e.g., Chart Museum or OCI Repo. cd ../ helm package cka-demo Successfully packaged chart and saved it to: /root/cka-demo-0.1.0.tgz Till now, we have done our task to develop a Chart. Let's install the Chart. helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=0 \\ --set passExam=false Result NAME: cka-demo LAST DEPLOYED: Sun Jul 24 19:58:36 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Come on! you can do it next time! Check the deployment helm list --all-namespaces Result NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION cka-demo cka 1 2022-07-24 19:58:36.272093383 +0800 CST deployed cka-demo-0.1.0 v1.23 mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 If any error, need to unstall cka-demo and reinstall it. helm uninstall cka-demo -n Check log of cka-demo . kubectl logs -n cka -l app=cka-demo Result Your CKA score is 0, Come on! you can do it next time! Install cka-demo with different options. helm uninstall cka-demo -n cka helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=100 \\ --set passExam=true NAME: cka-demo LAST DEPLOYED: Sun Jul 24 20:01:34 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: 100 Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard Check log of cka-demo . kubectl logs -n cka -l app=cka-demo Your CKA score is 100 and your CKA certificate ID number is BQKoVYVhjzl3G Built-in Objects: Release.Name # \u53d1\u5e03\u540d\u79f0 Release.Namespace # \u53d1\u5e03Namespace Release.Service # \u6e32\u67d3\u6a21\u677f\u7684\u670d\u52a1\uff0c\u5728Helm\u4e2d\u9ed8\u8ba4\u503c\u4e3a\"Helm\" Release.IsUpgrade # \u5982\u679c\u5f53\u524d\u662f\u5347\u7ea7\u6216\u56de\u6eda\uff0c\u8bbe\u7f6e\u4e3atrue Release.IsInstall # \u5982\u679c\u5f53\u524d\u662f\u5b89\u88c5\uff0c\u8bbe\u7f6e\u4e3atrue Release.Revision # \u53d1\u5e03\u7248\u672c\u53f7 Values # \u4ecevalues.yaml\u548c--set\u4f20\u5165\uff0c\u9ed8\u8ba4\u4e3a\u7a7a Chart # \u6240\u6709Chart.yaml\u4e2d\u7684\u5185\u5bb9 Chart.Version # Chart.Maintainers # Files # \u5728chart\u4e2d\u8bbf\u95ee\u975e\u7279\u6b8a\u6587\u4ef6 Capabilities # \u63d0\u4f9b\u5173\u4e8e\u652f\u6301\u80fd\u529b\u7684\u4fe1\u606f\uff08K8s API\u7248\u672c\u3001K8s\u7248\u672c\u3001Helm\u7248\u672c\uff09 Capabilities.KubeVersion # Kubernetes\u7684\u7248\u672c\u53f7 Capabilities.APIVersions.Has \"batch/v1\" # K8s API\u7248\u672c\u5305\u542b\"batch/v1\" Template # \u5f53\u524d\u6a21\u677f\u4fe1\u606f Template.Name # \u5f53\u524d\u6a21\u677f\u6587\u4ef6\u8def\u5f84 Template.BasePath # \u5f53\u524d\u6a21\u677f\u76ee\u5f55\u8def\u5f84 Reference: Helm \u5b98\u7f51 Helm \u7248\u672c\u652f\u6301\u7b56\u7565 Helm Chart \u8d44\u6e90\u5bf9\u8c61\u5b89\u88c5\u987a\u5e8f","title":"Helming"},{"location":"k8s/cka_en/foundamentals/helming/#helm-chart","text":"","title":"Helm Chart"},{"location":"k8s/cka_en/foundamentals/helming/#install-helm","text":"Install Helm on cka001 . # https://github.com/helm/helm/releases wget https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz tar -zxvf helm-v3.8.2-linux-amd64.tar.gz cp linux-amd64/helm /usr/bin/ rm -rf linux-amd64 helm-v3.8.2-linux-amd64.tar.gz Or manually download the file via link https://get.helm.sh/helm-v3.8.2-linux-amd64.tar.gz , and remote copy to cka001 . scp -i cka-key-pair.pem ./Package/helm-v3.8.2-linux-amd64.tar.gz root@cka001:/root/ ssh -i cka-key-pair.pem root@cka001 tar -zxvf helm-v3.8.2-linux-amd64.tar.gz cp linux-amd64/helm /usr/bin/ rm -rf linux-amd64 helm-v3.8.2-linux-amd64.tar.gz","title":"Install Helm"},{"location":"k8s/cka_en/foundamentals/helming/#usage-of-helm","text":"Check helm version helm version version.BuildInfo{Version:\"v3.8.2\", GitCommit:\"6e3701edea09e5d55a8ca2aae03a68917630e91b\", GitTreeState:\"clean\", GoVersion:\"go1.17.5\"} Get help of helm . helm help Configure auto-completion for helm . echo \"source <(helm completion bash)\" >> ~/.bashrc source <(helm completion bash)","title":"Usage of Helm"},{"location":"k8s/cka_en/foundamentals/helming/#install-mysql-from-helm","text":"Add bitnami Chartes Repository. helm repo add bitnami https://charts.bitnami.com/bitnami Get current Charts repositories. helm repo list NAME URL bitnami https://charts.bitnami.com/bitnami Sync up local Charts repositories. helm repo update Search bitnami Charts in repositories. helm search repo bitnami Search bitnami/mysql Charts in repositories. helm search repo bitnami/mysql Install MySQL Chart on namespace dev \uff1a helm install mysql bitnami/mysql -n dev Output NAME: mysql LAST DEPLOYED: Sun Jul 24 19:37:20 2022 NAMESPACE: dev STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: CHART NAME: mysql CHART VERSION: 9.2.1 APP VERSION: 8.0.29 ** Please be patient while the chart is being deployed ** Tip: Watch the deployment status using the command: kubectl get pods -w --namespace dev Services: echo Primary: mysql.dev.svc.cluster.local:3306 Execute the following to get the administrator credentials: echo Username: root MYSQL_ROOT_PASSWORD=$(kubectl get secret --namespace dev mysql -o jsonpath=\"{.data.mysql-root-password}\" | base64 -d) To connect to your database: 1. Run a pod that you can use as a client: kubectl run mysql-client --rm --tty -i --restart='Never' --image docker.io/bitnami/mysql:8.0.29-debian-11-r9 --namespace dev --env MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD --command -- bash 2. To connect to primary service (read/write): mysql -h mysql.dev.svc.cluster.local -uroot -p\"$MYSQL_ROOT_PASSWORD\" Check installed release\uff1a helm list Result NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 Check installed mysql release information. helm status mysql Check mysql Pod status. kubectl get pod Result NAME READY STATUS RESTARTS AGE mysql-0 1/1 Running 0 72s","title":"Install MySQL from Helm"},{"location":"k8s/cka_en/foundamentals/helming/#develop-a-chart","text":"Below is a demo on how to develop a Chart. Execute helm create to initiate a Chart\uff1a # Naming conventions of Chart: lowercase a~z and - ( minus sign ) helm create cka-demo A folder cka-demo was created. Check the folder structure. tree cka-demo/ Output cka-demo/ \u251c\u2500\u2500 charts \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 deployment.yaml \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u251c\u2500\u2500 hpa.yaml \u2502 \u251c\u2500\u2500 ingress.yaml \u2502 \u251c\u2500\u2500 NOTES.txt \u2502 \u251c\u2500\u2500 serviceaccount.yaml \u2502 \u251c\u2500\u2500 service.yaml \u2502 \u2514\u2500\u2500 tests \u2502 \u2514\u2500\u2500 test-connection.yaml \u2514\u2500\u2500 values.yaml Delete or empty some files, which will be re-created later. cd cka-demo rm -rf charts rm -rf templates/tests rm -rf templates/*.yaml echo \"\" > values.yaml echo \"\" > templates/NOTES.txt echo \"\" > templates/_helpers.tpl cd .. Now new structure looks like below. tree cka-demo/ Output cka-demo/ \u251c\u2500\u2500 Chart.yaml \u251c\u2500\u2500 templates \u2502 \u251c\u2500\u2500 _helpers.tpl \u2502 \u2514\u2500\u2500 NOTES.txt \u2514\u2500\u2500 values.yaml","title":"Develop a Chart"},{"location":"k8s/cka_en/foundamentals/helming/#notestxt","text":"NOTES.txt is used to provide summary information to Chart users. In the demo, we will use NOTES.txt to privide summary info about whether the user passed CKA certificate or not. cd cka-demo/ vi templates/NOTES.txt Add below info. {{- if .Values.passExam }} Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: {{ .Values.ckaScore }} Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard {{- else }} Come on! you can do it next time! {{- end }}","title":"NOTES.txt"},{"location":"k8s/cka_en/foundamentals/helming/#deployment-template","text":"Let's use Busybox service to generate information. We use kubectl create deployment --dry-run=client -oyaml to generate Deployment yaml file and write it the yaml file content into file templates/deployment.yaml . kubectl create deployment cka-demo-busybox --image=busybox:latest --dry-run=client -oyaml > templates/deployment.yaml Check content of deployment yaml file templates/deployment.yaml . cat templates/deployment.yaml apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : 1 selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} Edit file templates/deployment.yaml . vi templates/deployment.yaml Let's replace value of .spec.replicas from 1 to a variable {{ .Values.replicaCount }} , so we can dynamicly assign replicas number for other Deployment. apiVersion : apps/v1 kind : Deployment metadata : creationTimestamp : null labels : app : cka-demo-busybox name : cka-demo-busybox spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : app : cka-demo-busybox strategy : {} template : metadata : creationTimestamp : null labels : app : cka-demo-busybox spec : containers : - image : busybox:latest name : busybox resources : {} status : {} The .spec.replicas will be replaced by actula value of .Values.replicaCount during deployment. Let's create another file values.yaml and add a variable replicaCount with default value 1 into the file. Strong recommended to add comments for each value we defined in file values.yaml . vi values.yaml # Number of deployment replicas replicaCount: 1 Let's add more variables into file templates/deployment.yaml . Replace Release name .metadata.name by {{ .Release.Name }} and filled with variable defined in file values.yaml . Replace label name .metadata.labels by {{- include \"cka-demo.labels\" . | nindent 4 }} , and filled with labels name cka-demo.labels defined in file _helpers.tpl . Replace .spec.replicas by {{ .Values.replicaCount }} and filled with variable defined in file values.yaml . Replace .spec.selector.matchLabels by {{- include \"cka-demo.selectorLabels\" . | nindent 6 }} and filled with cka-demo.selectorLabels defined in file _helpers.tpl . Replace .spec.template.metadata.labels by {{- include \"cka-demo.selectorLabels\" . | nindent 8 }} and filled with cka-demo.selectorLabels defined in file _helpers.tpl . Replace .spec.template.spec.containers[0].image by {{ .Values.image.repository }} and {{ .Values.image.tag }} and filled with variables defined in values.yaml for image name and image tag. Replace .spec.template.spec.containers[0].command and add if-else statement, if .Values.passExam is true, execute commands defined in .Values.passCommand , if false, execute commands defined in .Values.lostCommand . Use key from ConfigMap from .spec.template.spec.containers[0].env as prefix of ConfigMap name and filled with {{ .Values.studentName }} defined in file values.yaml . Replace .spec.template.spec.containers[0].resources by {{ .Values.resources }} and filled with variable defined in file values.yaml . The .Release.Name is built-in object, no need to be specified in file values.yaml . It's generated by Release by helm install . Remove unused lines and final one looks like below. apiVersion : apps/v1 kind : Deployment metadata : name : {{ .Release.Name }} labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} spec : replicas : {{ .Values.replicaCount }} selector : matchLabels : {{ - include \"cka-demo.selectorLabels\" . | nindent 6 }} template : metadata : labels : {{ - include \"cka-demo.selectorLabels\" . | nindent 8 }} spec : containers : - name : id-generator image : \"{{ .Values.image.repository }}:{{ .Values.image.tag }}\" {{ - if .Values.passExam }} {{ - with .Values.passCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - else }} {{ - with .Values.lostCommand }} command : {{ range . }} - {{ . | quote }} {{ - end }} {{ - end }} {{ - end }} env : - name : CKA_SCORE valueFrom : configMapKeyRef : name : {{ .Values.studentName }} -cka-score key : cka_score {{ - with .Values.resources }} resources : {{ - toYaml . | nindent 12 }} {{ - end }} restartPolicy : Always Update file values.yaml with variables default values. Suggestions\uff1aadd variables one and test one, don't add all at one time. vi values.yaml # Number of deployment replicas replicaCount: 1 # Image repository and tag image: repository: busybox tag: latest # Container start command passCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE) and your CKA certificate ID number is $(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 13; echo) ; sleep 86400\" lostCommand: - '/bin/sh' - '-c' - \"echo Your CKA score is $(CKA_SCORE), Come on! you can do it next time! ; sleep 86400\" # Container resources resources: limits: cpu: 200m memory: 256Mi requests: cpu: 100m memory: 128Mi # Student Name studentName: whoareyou # Student pass CKA exam or not passExam: true","title":"Deployment Template"},{"location":"k8s/cka_en/foundamentals/helming/#configmap-template","text":"ConfigMap is referred in the Deployment, hence we need define the ConfigMap template. We will combine name of ConfigMap and cka_score as a variable, like name-cka-score . vi templates/configmap.yaml apiVersion : v1 kind : ConfigMap metadata : name : {{ .Values.studentName }} -cka-score labels : {{ - include \"cka-demo.labels\" . | nindent 4 }} data : cka_score : {{ .Values.ckaScore | quote }} The studentName was already defined in file values.yaml , we just need add ckaScore with default value. vi values.yaml # Student CKA Score ckaScore: 100","title":"ConfigMap Template"},{"location":"k8s/cka_en/foundamentals/helming/#_helperstpl","text":"Define a common template _helpers.tpl to add labels and labels of Selector for labels of Deployment and ConfigMap. vi templates/_helpers.tpl {{/* Common labels */}} {{- define \"cka-demo.labels\" -}} {{ include \"cka-demo.selectorLabels\" . }} {{- if .Chart.AppVersion }} app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} {{- end }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end -}} {{/* Selector labels */}} {{- define \"cka-demo.selectorLabels\" -}} app: {{ .Chart.Name }} release: {{ .Release.Name }} {{- end -}}","title":"_helpers.tpl"},{"location":"k8s/cka_en/foundamentals/helming/#chartyaml","text":"We use CKA logo as the icon of Chart wget https://www.cncf.io/wp-content/uploads/2021/09/kubernetes-cka-color.svg Edit Chart.yaml file. vi Chart.yaml Append icon info in the file. icon: file://./kubernetes-cka-color.svg Add author info for the Chart vi Chart.yaml maintainers: - name: James.H Final Chart.yaml looks like below. Don't forget to update appVersion: \"v1.23\" to current Kubernetes API version. apiVersion : v2 name : cka-demo description : A Helm chart for CKA demo. type : application version : 0.1.0 appVersion : \"v1.23\" maintainers : - name : James.H icon : file://./kubernetes-cka-color.svg","title":"Chart.yaml"},{"location":"k8s/cka_en/foundamentals/helming/#chart-debug","text":"Use helm lint to verify above change. helm lint 1 chart(s) linted, 0 chart(s) failed helm lint only check format of Chart, won't check Manifest file. We can use helm install --debug --dry-run or helm template to check Manifest output in order to verify all yaml files are correct or not. helm template cka-demo ./ Use helm install --debug --dry-run to simulate the installation. We can get expected results from two different options (passed or failed the CKA certificate). helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=99 \\ --set passExam=true helm install --debug --dry-run cka-demo ./ --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=0 \\ --set passExam=false Package Chart to .tgz file, and upload to repository, e.g., Chart Museum or OCI Repo. cd ../ helm package cka-demo Successfully packaged chart and saved it to: /root/cka-demo-0.1.0.tgz Till now, we have done our task to develop a Chart. Let's install the Chart. helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=0 \\ --set passExam=false Result NAME: cka-demo LAST DEPLOYED: Sun Jul 24 19:58:36 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Come on! you can do it next time! Check the deployment helm list --all-namespaces Result NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION cka-demo cka 1 2022-07-24 19:58:36.272093383 +0800 CST deployed cka-demo-0.1.0 v1.23 mysql dev 1 2022-07-24 19:37:20.710988009 +0800 CST deployed mysql-9.2.1 8.0.29 If any error, need to unstall cka-demo and reinstall it. helm uninstall cka-demo -n Check log of cka-demo . kubectl logs -n cka -l app=cka-demo Result Your CKA score is 0, Come on! you can do it next time! Install cka-demo with different options. helm uninstall cka-demo -n cka helm install cka-demo cka-demo-0.1.0.tgz --create-namespace \\ -n cka \\ --set studentName=kubernetes \\ --set ckaScore=100 \\ --set passExam=true NAME: cka-demo LAST DEPLOYED: Sun Jul 24 20:01:34 2022 NAMESPACE: cka STATUS: deployed REVISION: 1 TEST SUITE: None NOTES: Congratulations! You have successfully completed Certified Kubernetes Administrator China Exam (CKA-CN). Your CKA score is: 100 Click the link below to view and download your certificate. https://trainingportal.linuxfoundation.org/learn/dashboard Check log of cka-demo . kubectl logs -n cka -l app=cka-demo Your CKA score is 100 and your CKA certificate ID number is BQKoVYVhjzl3G Built-in Objects: Release.Name # \u53d1\u5e03\u540d\u79f0 Release.Namespace # \u53d1\u5e03Namespace Release.Service # \u6e32\u67d3\u6a21\u677f\u7684\u670d\u52a1\uff0c\u5728Helm\u4e2d\u9ed8\u8ba4\u503c\u4e3a\"Helm\" Release.IsUpgrade # \u5982\u679c\u5f53\u524d\u662f\u5347\u7ea7\u6216\u56de\u6eda\uff0c\u8bbe\u7f6e\u4e3atrue Release.IsInstall # \u5982\u679c\u5f53\u524d\u662f\u5b89\u88c5\uff0c\u8bbe\u7f6e\u4e3atrue Release.Revision # \u53d1\u5e03\u7248\u672c\u53f7 Values # \u4ecevalues.yaml\u548c--set\u4f20\u5165\uff0c\u9ed8\u8ba4\u4e3a\u7a7a Chart # \u6240\u6709Chart.yaml\u4e2d\u7684\u5185\u5bb9 Chart.Version # Chart.Maintainers # Files # \u5728chart\u4e2d\u8bbf\u95ee\u975e\u7279\u6b8a\u6587\u4ef6 Capabilities # \u63d0\u4f9b\u5173\u4e8e\u652f\u6301\u80fd\u529b\u7684\u4fe1\u606f\uff08K8s API\u7248\u672c\u3001K8s\u7248\u672c\u3001Helm\u7248\u672c\uff09 Capabilities.KubeVersion # Kubernetes\u7684\u7248\u672c\u53f7 Capabilities.APIVersions.Has \"batch/v1\" # K8s API\u7248\u672c\u5305\u542b\"batch/v1\" Template # \u5f53\u524d\u6a21\u677f\u4fe1\u606f Template.Name # \u5f53\u524d\u6a21\u677f\u6587\u4ef6\u8def\u5f84 Template.BasePath # \u5f53\u524d\u6a21\u677f\u76ee\u5f55\u8def\u5f84 Reference: Helm \u5b98\u7f51 Helm \u7248\u672c\u652f\u6301\u7b56\u7565 Helm Chart \u8d44\u6e90\u5bf9\u8c61\u5b89\u88c5\u987a\u5e8f","title":"Chart Debug"},{"location":"k8s/cka_en/foundamentals/hpa/","text":"Horizontal Pod Autoscaling (HPA) \u00b6 Scenario: Install Metrics Server component Create Deployment podinfo and Service podinfo for stress testing Create HPA my-hpa Stress Testing Demo: Install Metrics Server component \u00b6 Download yaml file for Metrics Server component wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml Replace Google image by Aliyun image image: registry.aliyuncs.com/google_containers/metrics-server:v0.6.1 . sed -i 's/k8s\\.gcr\\.io\\/metrics-server\\/metrics-server\\:v0\\.6\\.1/registry\\.aliyuncs\\.com\\/google_containers\\/metrics-server\\:v0\\.6\\.1/g' components.yaml Change arg of deployment metrics-server by adding --kubelet-insecure-tls to disable tls certificate validation. vi components.yaml Updated arg of metrics-server is below. ...... template : metadata : labels : k8s-app : metrics-server spec : containers : - args : - --cert-dir=/tmp - --secure-port=4443 - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname - --kubelet-use-node-status-port - --metric-resolution=15s - --kubelet-insecure-tls image : registry.aliyuncs.com/google_containers/metrics-server:v0.6.1 ...... Appy the yaml file components.yaml to deploy metrics-server . kubectl apply -f components.yaml Below resources were crested. serviceaccount/metrics-server created clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created clusterrole.rbac.authorization.k8s.io/system:metrics-server created rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created service/metrics-server created deployment.apps/metrics-server created apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created Verify if metrics-server Pod is running as expected ( 1/1 running) kubectl get pod -n kube-system -owide | grep metrics-server Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES metrics-server-7fd564dc66-sdhdc 1/1 Running 0 61s 10.244.102.15 cka003 Get current usage of CPU, memory of each node. kubectl top node Result: NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 595m 29% 1937Mi 50% cka002 75m 3% 1081Mi 28% cka003 79m 3% 1026Mi 26% Deploy a Service podinfo \u00b6 Create Deployment podinfo and Service podinfo for further stress testing. kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: podinfo labels: app: podinfo spec: type: NodePort ports: - port: 9898 targetPort: 9898 nodePort: 31198 protocol: TCP selector: app: podinfo --- apiVersion: apps/v1 kind: Deployment metadata: name: podinfo labels: app: podinfo spec: replicas: 2 selector: matchLabels: app: podinfo template: metadata: labels: app: podinfo spec: containers: - name: podinfod image: stefanprodan/podinfo:0.0.1 imagePullPolicy: Always command: - ./podinfo - -port=9898 - -logtostderr=true - -v=2 ports: - containerPort: 9898 protocol: TCP resources: requests: memory: \"32Mi\" cpu: \"10m\" limits: memory: \"256Mi\" cpu: \"100m\" EOF Config HPA \u00b6 Create HPA my-hpa by setting CPU threshold 50% to trigger auto-scalling with minimal 2 and maximal 10 Replicas. Use kubectl autoscal to create HPA my-hpa . kubectl autoscale deployment podinfo --cpu-percent=50 --min=1 --max=10 Use autoscaling/v1 version template to crreate HPA my-hpa . kubectl apply -f - < Get current usage of CPU, memory of each node. kubectl top node Result: NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 595m 29% 1937Mi 50% cka002 75m 3% 1081Mi 28% cka003 79m 3% 1026Mi 26%","title":"Install Metrics Server component"},{"location":"k8s/cka_en/foundamentals/hpa/#deploy-a-service-podinfo","text":"Create Deployment podinfo and Service podinfo for further stress testing. kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: podinfo labels: app: podinfo spec: type: NodePort ports: - port: 9898 targetPort: 9898 nodePort: 31198 protocol: TCP selector: app: podinfo --- apiVersion: apps/v1 kind: Deployment metadata: name: podinfo labels: app: podinfo spec: replicas: 2 selector: matchLabels: app: podinfo template: metadata: labels: app: podinfo spec: containers: - name: podinfod image: stefanprodan/podinfo:0.0.1 imagePullPolicy: Always command: - ./podinfo - -port=9898 - -logtostderr=true - -v=2 ports: - containerPort: 9898 protocol: TCP resources: requests: memory: \"32Mi\" cpu: \"10m\" limits: memory: \"256Mi\" cpu: \"100m\" EOF","title":"Deploy a Service podinfo"},{"location":"k8s/cka_en/foundamentals/hpa/#config-hpa","text":"Create HPA my-hpa by setting CPU threshold 50% to trigger auto-scalling with minimal 2 and maximal 10 Replicas. Use kubectl autoscal to create HPA my-hpa . kubectl autoscale deployment podinfo --cpu-percent=50 --min=1 --max=10 Use autoscaling/v1 version template to crreate HPA my-hpa . kubectl apply -f - <

    It works!

    Clean up. kubectl delete ingress demo-localhost kubectl delete service demo kubectl delete deployment demo Create Deployments \u00b6 Create two deployment nginx-app-1 and nginx-app-2 . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-1 spec: selector: matchLabels: app: nginx-app-1 replicas: 1 template: metadata: labels: app: nginx-app-1 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-1 --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-2 spec: selector: matchLabels: app: nginx-app-2 replicas: 1 template: metadata: labels: app: nginx-app-2 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-2 EOF Get status of Pods by executing kubectl get pod -o wide . One pod is running on node cka002 , another pod is running on node cka003 . Directory /opt/html-2/ is on cka002 Directory /opt/html-1/ is on cka002 Access to two Pod via curl. We get 403 Forbidden error. curl 10.244.102.13 curl 10.244.112.19 Log onto node cka002 , create index.html file in path /opt/html-2/ with below command. cat < app1.com app2.com EOF Get IP address or FQDN with the following command: kubectl get service ingress-nginx-controller --namespace=ingress-nginx It will be the EXTERNAL-IP field. If that field shows like below, this means that the Kubernetes cluster wasn't able to provision the load balancer (generally, this is because it doesn't support services of type LoadBalancer). As there is no Aliyun ELB configured, use below two options to make the external IP in place. Option 1: manually add node ip to ingress controller, which the controller pod is running on. Execute command kubectl get pod -n ingress-nginx -o wide to see that ingress controller pod is running on node cka003 . Manually patch the external ip of cak003 to the EXTERNAL-IP field. kubectl patch svc ingress-nginx-controller \\ --namespace=ingress-nginx \\ -p '{\"spec\": {\"type\": \"LoadBalancer\", \"externalIPs\":[\"\"]}}' Option 2: change ingress controller from LoadBalancer to NodePort . Two files index.html are in two Pods, the web services are exposed to outside via node IP. The ingress-nginx-controller plays a central entry point for outside access, and provide two ports for different backend services from Pods. Send HTTP request to two hosts defined in Ingress. curl http://app1.com:30011 curl http://app2.com:30011 curl app1.com:30011 curl app2.com:30011 Get below successful information. This is test 1 !! This is test 2 !! Clean up. kubectl delete ingress ingress-nginx-app kubectl delete service nginx-app-1 kubectl delete service nginx-app-2 kubectl delete deployment nginx-app-1 kubectl delete deployment nginx-app-2","title":"Ingress"},{"location":"k8s/cka_en/foundamentals/ingress/#ingress-nginx","text":"Scenario *Deploy Ingress Controller. * Create two deployment nginx-app-1 and nginx-app-2 . *Host directory /root/html-1 and /root/html-2 will be created and mounted to two Deployments on running host. * Create Service. *Create Service nginx-app-1 and nginx-app-2 and map to related Deployment nginx-app-1 and nginx-app-2 . * Create Ingress. *Create Ingress resource nginx-app and map to two Services nginx-app-1 and nginx-app-1 . * Test Accessibility. * Send HTTP request to two hosts defined in Ingress Reference *Github ingress-nginx * Installation Guide","title":"Ingress-nginx"},{"location":"k8s/cka_en/foundamentals/ingress/#deploy-ingress-controller","text":"Get Ingress Controller yaml file. The latest version link is in Installation Guide . wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml Below two images's sources needto be changed to Aliyun. image: k8s.gcr.io/ingress-nginx/controller:v1.2.1@sha256:5516d103a9c2ecc4f026efbd4b40662ce22dc1f824fb129ed121460aaa5c47f8 image: registry.k8s.io/ingress-nginx/controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5 image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660 From grc.io to Aliyun. k8s.gcr.io/ingress-nginx/controller to registry.aliyuncs.com/google_containers/nginx-ingress-controller registry.k8s.io/ingress-nginx/controller to registry.aliyuncs.com/google_containers/nginx-ingress-controller * k8s.gcr.io/ingress-nginx/kube-webhook-certgen to registry.aliyuncs.com/google_containers/kube-webhook-certgen Commands: sed -i 's/k8s.gcr.io\\/ingress-nginx\\/kube-webhook-certgen/registry.aliyuncs.com\\/google\\_containers\\/kube-webhook-certgen/g' deploy.yaml sed -i 's/k8s.gcr.io\\/ingress-nginx\\/controller/registry.aliyuncs.com\\/google\\_containers\\/nginx-ingress-controller/g' deploy.yaml Apply the yaml file deploy.yaml to create Ingress Nginx. A new namespace ingress-nginx was created and Ingress Nginx resources are running under the new namespace. kubectl apply -f deploy.yaml Check the status of Pod. kubectl get pod -n ingress-nginx Make sure all pods are not in error status, like below. NAME READY STATUS RESTARTS AGE ingress-nginx-admission-create-lgtdj 0/1 Completed 0 49s ingress-nginx-admission-patch-nk9fv 0/1 Completed 0 49s ingress-nginx-controller-556fbd6d6f-6jl4x 1/1 Running 0 49s","title":"Deploy Ingress Controller"},{"location":"k8s/cka_en/foundamentals/ingress/#local-testing","text":"Let's create a simple web server and the associated service: kubectl create deployment demo --image=httpd --port=80 kubectl expose deployment demo Then create an ingress resource. The following example uses a host that maps to localhost: kubectl create ingress demo-localhost --class=nginx --rule=\"demo.localdev.me/*=demo:80\" Now, forward a local port to the ingress controller: kubectl port-forward --namespace=ingress-nginx service/ingress-nginx-controller 8080:80 At this point, open another terminal to access http://demo.localdev.me:8080/ , we should see an HTML page telling you \"It works!\". curl http://demo.localdev.me:8080/ Result

    It works!

    Clean up. kubectl delete ingress demo-localhost kubectl delete service demo kubectl delete deployment demo","title":"Local testing"},{"location":"k8s/cka_en/foundamentals/ingress/#create-deployments","text":"Create two deployment nginx-app-1 and nginx-app-2 . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-1 spec: selector: matchLabels: app: nginx-app-1 replicas: 1 template: metadata: labels: app: nginx-app-1 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-1 --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-app-2 spec: selector: matchLabels: app: nginx-app-2 replicas: 1 template: metadata: labels: app: nginx-app-2 spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /opt/html-2 EOF Get status of Pods by executing kubectl get pod -o wide . One pod is running on node cka002 , another pod is running on node cka003 . Directory /opt/html-2/ is on cka002 Directory /opt/html-1/ is on cka002 Access to two Pod via curl. We get 403 Forbidden error. curl 10.244.102.13 curl 10.244.112.19 Log onto node cka002 , create index.html file in path /opt/html-2/ with below command. cat < app1.com app2.com EOF Get IP address or FQDN with the following command: kubectl get service ingress-nginx-controller --namespace=ingress-nginx It will be the EXTERNAL-IP field. If that field shows like below, this means that the Kubernetes cluster wasn't able to provision the load balancer (generally, this is because it doesn't support services of type LoadBalancer). As there is no Aliyun ELB configured, use below two options to make the external IP in place. Option 1: manually add node ip to ingress controller, which the controller pod is running on. Execute command kubectl get pod -n ingress-nginx -o wide to see that ingress controller pod is running on node cka003 . Manually patch the external ip of cak003 to the EXTERNAL-IP field. kubectl patch svc ingress-nginx-controller \\ --namespace=ingress-nginx \\ -p '{\"spec\": {\"type\": \"LoadBalancer\", \"externalIPs\":[\"\"]}}' Option 2: change ingress controller from LoadBalancer to NodePort . Two files index.html are in two Pods, the web services are exposed to outside via node IP. The ingress-nginx-controller plays a central entry point for outside access, and provide two ports for different backend services from Pods. Send HTTP request to two hosts defined in Ingress. curl http://app1.com:30011 curl http://app2.com:30011 curl app1.com:30011 curl app2.com:30011 Get below successful information. This is test 1 !! This is test 2 !! Clean up. kubectl delete ingress ingress-nginx-app kubectl delete service nginx-app-1 kubectl delete service nginx-app-2 kubectl delete deployment nginx-app-1 kubectl delete deployment nginx-app-2","title":"Test Accessiblity"},{"location":"k8s/cka_en/foundamentals/job/","text":"Job and Cronjob \u00b6 Job \u00b6 Scenario Create Job. Demo: Create Job pi . kubectl apply -f - << EOF apiVersion: batch/v1 kind: Job metadata: name: pi spec: template: spec: containers: - name: pi image: perl:5.34 command: [\"perl\", \"-Mbignum=bpi\", \"-wle\", \"print bpi(2000)\"] restartPolicy: Never backoffLimit: 4 EOF Get details of Job. kubectl get jobs Get details of Job Pod. The status Completed means the job was done successfully. kubectl get pod Get log info of the Job Pod. kubectl pi-2s74d 3.141592653589793.............. Clean up kubectl delete job pi Cronjob \u00b6 Scenario Create Cronjob. Demo: Create Cronjob hello . kubectl apply -f - << EOF apiVersion: batch/v1 kind: CronJob metadata: name: hello spec: schedule: \"*/1 * * * *\" jobTemplate: spec: template: spec: containers: - name: hello image: busybox args: - /bin/sh - -c - date ; echo Hello from the kubernetes cluster restartPolicy: OnFailure EOF Get detail of Cronjob kubectl get cronjobs -o wide Result NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE CONTAINERS IMAGES SELECTOR hello */1 * * * * False 0 25s hello busybox Monitor Jobs. Every 1 minute a new job will be created. kubectl get jobs -w Clean up kubectl delete cronjob hello","title":"Job and Cronjob"},{"location":"k8s/cka_en/foundamentals/job/#job-and-cronjob","text":"","title":"Job and Cronjob"},{"location":"k8s/cka_en/foundamentals/job/#job","text":"Scenario Create Job. Demo: Create Job pi . kubectl apply -f - << EOF apiVersion: batch/v1 kind: Job metadata: name: pi spec: template: spec: containers: - name: pi image: perl:5.34 command: [\"perl\", \"-Mbignum=bpi\", \"-wle\", \"print bpi(2000)\"] restartPolicy: Never backoffLimit: 4 EOF Get details of Job. kubectl get jobs Get details of Job Pod. The status Completed means the job was done successfully. kubectl get pod Get log info of the Job Pod. kubectl pi-2s74d 3.141592653589793.............. Clean up kubectl delete job pi","title":"Job"},{"location":"k8s/cka_en/foundamentals/job/#cronjob","text":"Scenario Create Cronjob. Demo: Create Cronjob hello . kubectl apply -f - << EOF apiVersion: batch/v1 kind: CronJob metadata: name: hello spec: schedule: \"*/1 * * * *\" jobTemplate: spec: template: spec: containers: - name: hello image: busybox args: - /bin/sh - -c - date ; echo Hello from the kubernetes cluster restartPolicy: OnFailure EOF Get detail of Cronjob kubectl get cronjobs -o wide Result NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE CONTAINERS IMAGES SELECTOR hello */1 * * * * False 0 25s hello busybox Monitor Jobs. Every 1 minute a new job will be created. kubectl get jobs -w Clean up kubectl delete cronjob hello","title":"Cronjob"},{"location":"k8s/cka_en/foundamentals/kyma/","text":"Kyma \u00b6 Deploy Kyma on control plane node. Install Kyma CLI \u00b6 Install Kyma CLI on Linux, run: curl -Lo kyma.tar.gz \"https://github.com/kyma-project/cli/releases/download/$(curl -s https://api.github.com/repos/kyma-project/cli/releases/latest | grep tag_name | cut -d '\"' -f 4)/kyma_Linux_x86_64.tar.gz\" mkdir /opt/kyma-release tar -C /opt/kyma-release -zxvf kyma.tar.gz chmod +x /opt/kyma-release/kyma sudo cp /opt/kyma-release/kyma /usr/local/bin rm -rf kyma-release kyma.tar.gz Reference Install Kyma CLI Install Kyma \u00b6 Use the deploy command to install Kyma. kyma deploy Get file components.yaml to manually install failed components. If no Namespace provided, the default Namespace called kyma-system is used. For example: kyma deploy --component serverless@kyma-integration kyma deploy --component monitoring@kyma-integration kyma deploy --component kiali@kyma-integration File components.yaml looks like below. --- defaultNamespace: kyma-system prerequisites: - name: \"cluster-essentials\" - name: \"istio\" namespace: \"istio-system\" - name: \"certificates\" namespace: \"istio-system\" components: - name: \"istio-resources\" - name: \"logging\" - name: \"telemetry\" - name: \"tracing\" - name: \"kiali\" - name: \"monitoring\" - name: \"eventing\" - name: \"ory\" - name: \"api-gateway\" - name: \"cluster-users\" - name: \"serverless\" - name: \"application-connector\" namespace: \"kyma-integration\" Reference: By default, Kyma is installed with the default chart values defined in the values.yaml files. You can also control the allocation of resources, such as memory and CPU, that the components consume by installing Kyma with the following pre-defined profiles: Evaluation needs limited resources and is suited for trial purposes. Production is configured for high availability and scalability. It requires more resources than the evaluation profile but is a better choice for production workload. Install Kyma To see a complete list of all Kyma components go to the components.yaml file. Install specific components kyma deploy --components-file {COMPONENTS_FILE_PATH}","title":"Kyma"},{"location":"k8s/cka_en/foundamentals/kyma/#kyma","text":"Deploy Kyma on control plane node.","title":"Kyma"},{"location":"k8s/cka_en/foundamentals/kyma/#install-kyma-cli","text":"Install Kyma CLI on Linux, run: curl -Lo kyma.tar.gz \"https://github.com/kyma-project/cli/releases/download/$(curl -s https://api.github.com/repos/kyma-project/cli/releases/latest | grep tag_name | cut -d '\"' -f 4)/kyma_Linux_x86_64.tar.gz\" mkdir /opt/kyma-release tar -C /opt/kyma-release -zxvf kyma.tar.gz chmod +x /opt/kyma-release/kyma sudo cp /opt/kyma-release/kyma /usr/local/bin rm -rf kyma-release kyma.tar.gz Reference Install Kyma CLI","title":"Install Kyma CLI"},{"location":"k8s/cka_en/foundamentals/kyma/#install-kyma","text":"Use the deploy command to install Kyma. kyma deploy Get file components.yaml to manually install failed components. If no Namespace provided, the default Namespace called kyma-system is used. For example: kyma deploy --component serverless@kyma-integration kyma deploy --component monitoring@kyma-integration kyma deploy --component kiali@kyma-integration File components.yaml looks like below. --- defaultNamespace: kyma-system prerequisites: - name: \"cluster-essentials\" - name: \"istio\" namespace: \"istio-system\" - name: \"certificates\" namespace: \"istio-system\" components: - name: \"istio-resources\" - name: \"logging\" - name: \"telemetry\" - name: \"tracing\" - name: \"kiali\" - name: \"monitoring\" - name: \"eventing\" - name: \"ory\" - name: \"api-gateway\" - name: \"cluster-users\" - name: \"serverless\" - name: \"application-connector\" namespace: \"kyma-integration\" Reference: By default, Kyma is installed with the default chart values defined in the values.yaml files. You can also control the allocation of resources, such as memory and CPU, that the components consume by installing Kyma with the following pre-defined profiles: Evaluation needs limited resources and is suited for trial purposes. Production is configured for high availability and scalability. It requires more resources than the evaluation profile but is a better choice for production workload. Install Kyma To see a complete list of all Kyma components go to the components.yaml file. Install specific components kyma deploy --components-file {COMPONENTS_FILE_PATH}","title":"Install Kyma"},{"location":"k8s/cka_en/foundamentals/memo/","text":"Kubernetes Learning Memo \u00b6 Basic Concepts of Kubernetes \u00b6 Kubernetes Components \u00b6 A Kubernetes cluster consists of the components that represent the control plane and a set of machines called nodes . Kubernetes Components : Control Plane Components kube-apiserver: query and manipulate the state of objects in Kubernetes. play as \"communication hub\" among all resources in cluster. provide cluster security authentication, authorization, and role assignment. the only one can connect to etcd . etcd: all Kubernetes objects are stored on etcd. Kubernetes objects are persistent entities in the Kubernetes system, which are used to represent the state of your cluster. kube-scheduler: watches for newly created Pods with no assigned node, and selects a node for them to run on. kube-controller-manager: runs controller processes. Node controller : Responsible for noticing and responding when nodes go down. Job controller : Watches for Job objects that represent one-off tasks, then creates Pods to run those tasks to completion. Endpoints controller : Populates the Endpoints object (that is, joins Services & Pods). Service Account & Token controllers : Create default accounts and API access tokens for new namespaces. cloud-controller-manager: embeds cloud-specific control logic and only runs controllers that are specific to your cloud provider, no need for own premises and learning environment. Node controller : For checking the cloud provider to determine if a node has been deleted in the cloud after it stops responding Route controller : For setting up routes in the underlying cloud infrastructure Service controller : For creating, updating and deleting cloud provider load balancers Node Components kubelet: An agent that runs on each node in the cluster. Manage node. It makes sure that containers are running in a Pod. kubelet registers and updates nodes information to APIServer, and APIServer stores them into etcd . Manage pod. Watch pod via APIServer, and action on pods or containers in pods. Health check at container level. kube-proxy: is a network proxy that runs on each node in cluster. iptables ipvs maintains network rules on nodes. Container runtime: is the software that is responsible for running containers. Addons DNS: is a DNS server and required by all Kubernetes clusters. Web UI (Dashboard): web-based UI for Kubernetes clusters. Container Resource Monitoring: records generic time-series metrics about containers in a central database Cluster-level Logging: is responsible for saving container logs to a central log store with search/browsing interface. Scalability: Scaling out (horizontal scaling) by adding more servers to your architecture to spread the workload across more machines. Scaling up (vertical scaling) by adding more hard drives and memory to increase the computing capacity of physical servers. Kubernetes API \u00b6 The REST API is the fundamental fabric of Kubernetes. All operations and communications between components, and external user commands are REST API calls that the API Server handles. Consequently, everything in the Kubernetes platform is treated as an API object and has a corresponding entry in the API. The core of Kubernetes' control plane is the API server. CRI: Container Runtime Interface CNI: Container Network Interface CSI: Container Storage Interface The API server exposes an HTTP API that lets end users, different parts of cluster, and external components communicate with one another. The Kubernetes API lets we query and manipulate the state of API objects in Kubernetes (for example: Pods, Namespaces, ConfigMaps, and Events). Kubernetes API: OpenAPI specification OpenAPI V2 OpenAPI V3 Persistence. Kubernetes stores the serialized state of objects by writing them into etcd. API groups and versioning. Versioning is done at the API level. API resources are distinguished by their API group, resource type, namespace (for namespaced resources), and name. API changes API Extension API Version \u00b6 The API versioning and software versioning are indirectly related. The API and release versioning proposal describes the relationship between API versioning and software versioning. Different API versions indicate different levels of stability and support. Here's a summary of each level: Alpha: The version names contain alpha (for example, v1alpha1). The software may contain bugs. Enabling a feature may expose bugs. A feature may be disabled by default. The support for a feature may be dropped at any time without notice. The API may change in incompatible ways in a later software release without notice. The software is recommended for use only in short-lived testing clusters, due to increased risk of bugs and lack of long-term support. Beta: The version names contain beta (for example, v2beta3). The software is well tested. Enabling a feature is considered safe. Features are enabled by default. The support for a feature will not be dropped, though the details may change. The schema and/or semantics of objects may change in incompatible ways in a subsequent beta or stable release. When this happens, migration instructions are provided. Schema changes may require deleting, editing, and re-creating API objects. The editing process may not be straightforward. The migration may require downtime for applications that rely on the feature. The software is not recommended for production uses. Subsequent releases may introduce incompatible changes. If you have multiple clusters which can be upgraded independently, you may be able to relax this restriction. Note: Please try beta features and provide feedback. After the features exit beta, it may not be practical to make more changes. Stable: The version name is vX where X is an integer. The stable versions of features appear in released software for many subsequent versions. Command to get current API kubectl api-resources API Group \u00b6 API groups make it easier to extend the Kubernetes API. The API group is specified in a REST path and in the apiVersion field of a serialized object. There are several API groups in Kubernetes: The core (also called legacy) group is found at REST path /api/v1 . The core group is not specified as part of the apiVersion field, for example, apiVersion: v1. The named groups are at REST path /apis/$GROUP_NAME/$VERSION and use apiVersion: $GROUP_NAME/$VERSION (for example, apiVersion: batch/v1). Kubernetes Objects \u00b6 Objects Overview \u00b6 Object Spec: providing a description of the characteristics the resource created to have: its desired state . Object Status: describes the current state of the object. Example of Deployment as an object that can represent an application running on cluster. apiVersion : apps/v1 # Which version of the Kubernetes API you're using to create this object kind : Deployment # What kind of object you want to create metadata : # Data that helps uniquely identify the object, including a name string, UID, and optional namespace name : nginx-deployment spec : # What state you desire for the object selector : matchLabels : app : nginx replicas : 2 # tells deployment to run 2 pods matching the template template : metadata : labels : app : nginx spec : containers : - name : nginx image : nginx:1.14.2 ports : - containerPort : 80 Object Management \u00b6 The kubectl command-line tool supports several different ways to create and manage Kubernetes objects. Read the Kubectl book for details. A Kubernetes object should be managed using ONLY one technique. Mixing and matching techniques for the same object results in undefined behavior. Three management techniques: Imperative commands operates directly on live objects in a cluster. kubectl create deployment nginx --image nginx Imperative object configuration kubectl create -f nginx.yaml kubectl delete -f nginx.yaml -f redis.yaml kubectl replace -f nginx.yaml Declarative object configuration kubectl diff -f configs/ kubectl apply -f configs/ Object Names and IDs \u00b6 Each object in your cluster has a Name that is unique for that type of resource. DNS Subdomain Names Label Names Path Segment Names Every Kubernetes object also has a UID that is unique across the whole cluster. Namespaces \u00b6 In Kubernetes, namespaces provides a mechanism for isolating groups of resources within a single cluster. Names of resources need to be unique within a namespace, but not across namespaces. Namespace-based scoping is applicable only for namespaced objects (e.g. Deployments, Services, etc) and not for cluster-wide objects (e.g. StorageClass, Nodes, PersistentVolumes, etc) Not All Objects are in a Namespace. Kubernetes starts with four initial namespaces: default The default namespace for objects with no other namespace kube-system The namespace for objects created by the Kubernetes system kube-public This namespace is created automatically and is readable by all users (including those not authenticated). This namespace is mostly reserved for cluster usage, in case that some resources should be visible and readable publicly throughout the whole cluster. The public aspect of this namespace is only a convention, not a requirement. kube-node-lease This namespace holds Lease objects associated with each node. Node leases allow the kubelet to send heartbeats so that the control plane can detect node failure. Viewing namespaces: kubectl get namespace Setting the namespace for a request kubectl run nginx --image=nginx --namespace= kubectl get pods --namespace= Labels and Selectors \u00b6 Labels are key/value pairs that are attached to objects, such as pods. Valid label keys have two segments: an optional prefix and name, separated by a slash ( / ). Labels are intended to be used to specify identifying attributes of objects that are meaningful and relevant to users. Labels can be used to organize and to select subsets of objects. Labels can be attached to objects at creation time and subsequently added and modified at any time. Each object can have a set of key/value labels defined. Each Key must be unique for a given object. Example of labels: \"metadata\" : { \"labels\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } Unlike names and UIDs, labels do not provide uniqueness. In general, we expect many objects to carry the same label(s). The API currently supports two types of selectors: equality-based, e.g., environment = production , tier != frontend set-based, e.g., environment in (production, qa) , tier notin (frontend, backend) Sample commands: kubectl get pods -l environment=production,tier=frontend kubectl get pods -l 'environment in (production),tier in (frontend)' kubectl get pods -l 'environment in (production, qa)' kubectl get pods -l 'environment,environment notin (frontend)' Annotations \u00b6 Use Kubernetes annotations to attach arbitrary non-identifying metadata to objects. Clients such as tools and libraries can retrieve this metadata. Use either labels or annotations to attach metadata to Kubernetes objects. Labels can be used to select objects and to find collections of objects that satisfy certain conditions. Annotations are not used to identify and select objects. Annotations, like labels, are key/value maps. The keys and the values in the map must be strings. \"metadata\" : { \"annotations\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } Valid annotation keys have two segments: an optional prefix and name, separated by a slash ( / ). Field Selectors \u00b6 Field selectors let you select Kubernetes resources based on the value of one or more resource fields. Here are some examples of field selector queries: metadata.name=my-service metadata.namespace!=default status.phase=Pending This kubectl command selects all Pods for which the value of the status.phase field is Running: kubectl get pods --field-selector status.phase=Running Supported field selectors vary by Kubernetes resource type. All resource types support the metadata.name and metadata.namespace fields. Use the = , == , and != operators with field selectors ( = and == mean the same thing). For example: kubectl get ingress --field-selector foo.bar=baz With operators, kubectl get services --all-namespaces --field-selector metadata.namespace!=default Chained selectors, kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always Multiple resource types, kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default Finalizers \u00b6 Finalizers are namespaced keys that tell Kubernetes to wait until specific conditions are met before it fully deletes resources marked for deletion . Finalizers alert controllers to clean up resources the deleted object owned. Finalizers are usually added to resources for a reason, so forcefully removing them can lead to issues in the cluster. Like labels, owner references describe the relationships between objects in Kubernetes, but are used for a different purpose. Kubernetes uses the owner references (not labels) to determine which Pods in the cluster need cleanup. Kubernetes processes finalizers when it identifies owner references on a resource targeted for deletion. Owners and Dependents \u00b6 In Kubernetes, some objects are owners of other objects. For example, a ReplicaSet is the owner of a set of Pods. These owned objects are dependents of their owner. Dependent objects have a metadata.ownerReferences field that references their owner object. A valid owner reference consists of the object name and a UID within the same namespace as the dependent object. Dependent objects also have an ownerReferences.blockOwnerDeletion field that takes a boolean value and controls whether specific dependents can block garbage collection from deleting their owner object. Resource \u00b6 Kubernetes resources and \"records of intent\" are all stored as API objects, and modified via RESTful calls to the API. The API allows configuration to be managed in a declarative way. Users can interact with the Kubernetes API directly, or via tools like kubectl. The core Kubernetes API is flexible and can also be extended to support custom resources. Workload Resources Pod . Pod is a collection of containers that can run on a host. PodTemplate . PodTemplate describes a template for creating copies of a predefined pod. ReplicationController . ReplicationController represents the configuration of a replication controller. ReplicaSet . ReplicaSet ensures that a specified number of pod replicas are running at any given time. Deployment . Deployment enables declarative updates for Pods and ReplicaSets. StatefulSet . StatefulSet represents a set of pods with consistent identities. ControllerRevision . ControllerRevision implements an immutable snapshot of state data. DaemonSet . DaemonSet represents the configuration of a daemon set. Job . Job represents the configuration of a single job. CronJob . CronJob represents the configuration of a single cron job. HorizontalPodAutoscaler . configuration of a horizontal pod autoscaler. HorizontalPodAutoscaler . HorizontalPodAutoscaler is the configuration for a horizontal pod autoscaler, which automatically manages the replica count of any resource implementing the scale subresource based on the metrics specified. HorizontalPodAutoscaler v2beta2 . HorizontalPodAutoscaler is the configuration for a horizontal pod autoscaler, which automatically manages the replica count of any resource implementing the scale subresource based on the metrics specified. PriorityClass . PriorityClass defines mapping from a priority class name to the priority integer value. Service Resources Service . Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy. Endpoints . Endpoints is a collection of endpoints that implement the actual service. EndpointSlice . EndpointSlice represents a subset of the endpoints that implement a service. Ingress . Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend. IngressClass . IngressClass represents the class of the Ingress, referenced by the Ingress Spec. Config and Storage Resources ConfigMap . ConfigMap holds configuration data for pods to consume. Secret . Secret holds secret data of a certain type. Volume . Volume represents a named volume in a pod that may be accessed by any container in the pod. PersistentVolumeClaim . PersistentVolumeClaim is a user's request for and claim to a persistent volume. PersistentVolume . PersistentVolume (PV) is a storage resource provisioned by an administrator. StorageClass . StorageClass describes the parameters for a class of storage for which PersistentVolumes can be dynamically provisioned. VolumeAttachment . VolumeAttachment captures the intent to attach or detach the specified volume to/from the specified node. CSIDriver . CSIDriver captures information about a Container Storage Interface (CSI) volume driver deployed on the cluster. CSINode . CSINode holds information about all CSI drivers installed on a node. CSIStorageCapacity . CSIStorageCapacity stores the result of one CSI GetCapacity call. Authentication Resources ServiceAccount . ServiceAccount binds together: a name, understood by users, and perhaps by peripheral systems, for an identity a principal that can be authenticated and authorized a set of secrets. TokenRequest . TokenRequest requests a token for a given service account. TokenReview . TokenReview attempts to authenticate a token to a known user. CertificateSigningRequest . CertificateSigningRequest objects provide a mechanism to obtain x509 certificates by submitting a certificate signing request, and having it asynchronously approved and issued. Authorization Resources LocalSubjectAccessReview . LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace. SelfSubjectAccessReview . SelfSubjectAccessReview checks whether or the current user can perform an action. SelfSubjectRulesReview . SelfSubjectRulesReview enumerates the set of actions the current user can perform within a namespace. SubjectAccessReview . SubjectAccessReview checks whether or not a user or group can perform an action. ClusterRole . ClusterRole is a cluster level, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding or ClusterRoleBinding. ClusterRoleBinding . ClusterRoleBinding references a ClusterRole, but not contain it. Role . Role is a namespaced, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding. RoleBinding . RoleBinding references a role, but does not contain it. Policy Resources LimitRange . LimitRange sets resource usage limits for each kind of resource in a Namespace. ResourceQuota . ResourceQuota sets aggregate quota restrictions enforced per namespace. NetworkPolicy . NetworkPolicy describes what network traffic is allowed for a set of Pods. PodDisruptionBudget . PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods. PodSecurityPolicy v1beta1 . PodSecurityPolicy governs the ability to make requests that affect the Security Context that will be applied to a pod and container. Extend Resources CustomResourceDefinition . CustomResourceDefinition represents a resource that should be exposed on the API server. MutatingWebhookConfiguration . MutatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and may change the object. *ValidatingWebhookConfiguration(). ValidatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and object without changing it. Cluster Resources Node . Node is a worker node in Kubernetes. Namespace . Namespace provides a scope for Names. Event . Event is a report of an event somewhere in the cluster. APIService . APIService represents a server for a particular GroupVersion. Lease . Lease defines a lease concept. RuntimeClass . RuntimeClass defines a class of container runtime supported in the cluster. FlowSchema v1beta2 . FlowSchema defines the schema of a group of flows. PriorityLevelConfiguration v1beta2 . PriorityLevelConfiguration represents the configuration of a priority level. Binding . Binding ties one object to another; for example, a pod is bound to a node by a scheduler. ComponentStatus . ComponentStatus (and ComponentStatusList) holds the cluster validation info. Command kube api-resources to get the supported API resources. Command kubectl explain RESOURCE [options] describes the fields associated with each supported API resource. Fields are identified via a simple JSONPath identifier: kubectl explain binding kubectl explain binding.metadata kubectl explain binding.metadata.name Workload Resources \u00b6 Pods \u00b6 Pods are the smallest deployable units of computing that you can create and manage in Kubernetes. A Pod is a group of one or more containers, with shared storage and network resources, and a specification for how to run the containers. A Pod's contents are always co-located and co-scheduled, and run in a shared context. A Pod models an application-specific \"logical host\": it contains one or more application containers which are relatively tightly coupled. In non-cloud contexts, applications executed on the same physical or virtual machine are analogous to cloud applications executed on the same logical host. The shared context of a Pod is a set of Linux namespaces, cgroups, and potentially other facets of isolation - the same things that isolate a Docker container. In terms of Docker concepts, a Pod is similar to a group of Docker containers with shared namespaces and shared filesystem volumes. Usually you don't need to create Pods directly, even singleton Pods. Instead, create them using workload resources such as Deployment or Job . If your Pods need to track state, consider the StatefulSet resource. Pods in a Kubernetes cluster are used in two main ways: Pods that run a single container. Pods that run multiple containers that need to work together. The \"one-container-per-Pod\" model is the most common Kubernetes use case; in this case, you can think of a Pod as a wrapper around a single container; Kubernetes manages Pods rather than managing the containers directly. A Pod can encapsulate an application composed of multiple co-located containers that are tightly coupled and need to share resources. These co-located containers form a single cohesive unit of service\u2014for example, one container serving data stored in a shared volume to the public, while a separate sidecar container refreshes or updates those files. The Pod wraps these containers, storage resources, and an ephemeral network identity together as a single unit. Grouping multiple co-located and co-managed containers in a single Pod is a relatively advanced use case. You should use this pattern only in specific instances in which your containers are tightly coupled. Each Pod is meant to run a single instance of a given application. If you want to scale your application horizontally (to provide more overall resources by running more instances), you should use multiple Pods, one for each instance. In Kubernetes, this is typically referred to as replication . Replicated Pods are usually created and managed as a group by a workload resource and its controller. Pods natively provide two kinds of shared resources for their constituent containers: networking and storage . A Pod can specify a set of shared storage volumes. All containers in the Pod can access the shared volumes, allowing those containers to share data. Each Pod is assigned a unique IP address for each address family. Within a Pod, containers share an IP address and port space, and can find each other via localhost . Containers that want to interact with a container running in a different Pod can use IP networking to communicate. When a Pod gets created, the new Pod is scheduled to run on a Node in your cluster. The Pod remains on that node until the Pod finishes execution, the Pod object is deleted, the Pod is evicted for lack of resources, or the node fails. Restarting a container in a Pod should not be confused with restarting a Pod. A Pod is not a process, but an environment for running container(s). A Pod persists until it is deleted. You can use workload resources (e.g., Deployment, StatefulSet, DaemonSet) to create and manage multiple Pods for you. A controller for the resource handles replication and rollout and automatic healing in case of Pod failure. InitContainer \u00b6 Some Pods have init containers as well as app containers. Init containers run and complete before the app containers are started. You can specify init containers in the Pod specification alongside the containers array (which describes app containers). Static Pod \u00b6 Static Pods are managed directly by the kubelet daemon on a specific node, without the API server observing them. Static Pods are always bound to one Kubelet on a specific node. The main use for static Pods is to run a self-hosted control plane: in other words, using the kubelet to supervise the individual control plane components. The kubelet automatically tries to create a mirror Pod on the Kubernetes API server for each static Pod. This means that the Pods running on a node are visible on the API server, but cannot be controlled from there. Container probes \u00b6 A probe is a diagnostic performed periodically by the kubelet on a container. To perform a diagnostic, the kubelet either executes code within the container, or makes a network request. There are four different ways to check a container using a probe. Each probe must define exactly one of these four mechanisms: exec . The diagnostic is considered successful if the command exits with a status code of 0. grpc . The diagnostic is considered successful if the status of the response is SERVING. httpGet . The diagnostic is considered successful if the response has a status code greater than or equal to 200 and less than 400. tcpSocket . The diagnostic is considered successful if the port is open. Each probe has one of three results: Success Failure Unknown Types of probe: livenessProbe . Indicates whether the container is running. readinessProbe . Indicates whether the container is ready to respond to requests. startupProbe . Indicates whether the application within the container is started. Deployment \u00b6 ReplicaSet \u00b6 A ReplicaSet\u2019s purpose is to maintain a stable set of replica Pods running at any given time. As such, it is often used to guarantee the availability of a specified number of identical Pods. You may never need to manipulate ReplicaSet objects: use a Deployment instead, and define your application in the spec section. You can specify how many Pods should run concurrently by setting replicaset.spec.replicas . The ReplicaSet will create/delete its Pods to match this number. If you do not specify replicaset.spec.replicas , then it defaults to 1 . StatefulSet \u00b6 StatefulSet Characteristics (aka, stick ID): Pod's name is immutable after created. DNS hostname is immutable after created. Mounted volume is immutable after created. Stick ID of StatefulSet won't be changed after failure, scaling, and other operations. Naming convention of StatefulSet: - . StatefulSet can be scalling by itsself, but Deployment need rely on ReplicaSet for scalling. Recommendation: reduce StatefulSet to 0 first instead of delete it directly. headless Service and governing Service: Headless Service is a normal Kubernetes Service object that its spec.clusterIP is set to None . When spec.ServiceName of StatefulSet is set to the headless Service name, the StatefulSet is now a governing Service. General procedure to create a StatefulSet: Create a StorageClass Create Headless Service Create StatefulSet based on above two. DaemonSet \u00b6 A DaemonSet ensures that all (or some) Nodes run a copy of a Pod. As nodes are removed from the cluster, those Pods are garbage collected. Deleting a DaemonSet will clean up the Pods it created. Some typical uses of a DaemonSet are: running a cluster storage daemon on every node running a logs collection daemon on every node running a node monitoring daemon on every node In a simple case, one DaemonSet, covering all nodes, would be used for each type of daemon. A more complex setup might use multiple DaemonSets for a single type of daemon, but with different flags and/or different memory and cpu requests for different hardware types. The DaemonSet controller reconciliation process reviews both existing nodes and newly created nodes. By default, the Kubernetes scheduler ignores the pods created by the DamonSet, and lets them exist on the node until the node itself is shut down. Running Pods on select Nodes: If you specify a daemonset.spec.template.spec.nodeSelector , then the DaemonSet controller will create Pods on nodes which match that node selector. If you specify a daemonset.spec.template.spec.affinity , then DaemonSet controller will create Pods on nodes which match that node affinity. If you do not specify either, then the DaemonSet controller will create Pods on all nodes. There is no field replicas in kubectl explain daemonset.spec against with kubectl explain deployment.spec.replicas . When a DaemonSet is created, each node will have one DaemonSet Pod running. We\u2019ll use a Deployment / ReplicaSet for services, mostly stateless, where we don\u2019t care where the node is running, but we care more about the number of copies of our pod is running, and we can scale those copies/replicas up or down. Rolling updates would also be a benefit here. We\u2019ll use a DaemonSet when a copy of our pod must be running on the specific nodes that we require. Our daemon pod also needs to start before any of our other pods. A DaemonSet is a simple scalability strategy for background services. When more eligible nodes are added to the cluster, the background service scales up. When nodes are removed, it will automatically scale down. Job \u00b6 CronJob \u00b6 Service Resource \u00b6 Service \u00b6 Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy. The set of Pods targeted by a Service is usually determined by a selector (label selector). Type of service resource: ClusterIP Service (default): Reliable IP, DNS, and Port. Internal acess only. NodePort Service: Expose to external access. LoadBalancer: Based on NodePort and integrated with loader balance provided by cloud venders (e.g., AWS, GCP, etc.). ExternalName: Acces will be trafficed to external service. Here is an example of yaml file to create a Service. apiVersion : v1 kind : Service metadata : name : nginx-service labels : tier : application spec : ports : - port : 80 protocol : TCP targetPort : 8080 selector : run : nginx type : NodePort Here is an example of Service. IP 10.96.17.77 is ClusterIP(VIP) of the service Port 80/TCP is the port on Pod that service listening within the cluster. TargetPort 8080/TCP is the port on the container that the service should direct traffic to. NodePort 31893/TCP is the port that can be accessed outside. Default range is 30000~32767 . The port is exposed across all nodes in cluster. Endpoints show the list of Pods matched the service labels. Name: nginx-deployment Namespace: jh-namespace Labels: tier=application Annotations: Selector: run=nginx Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 10.96.17.77 IPs: 10.96.17.77 Port: 80/TCP TargetPort: 8080/TCP NodePort: 31893/TCP Endpoints: 10.244.1.177:8080,10.244.1.178:8080,10.244.1.179:8080 + 7 more... Session Affinity: None External Traffic Policy: Cluster Events: Service kube-dns beyond Deployment coredns provides cluster DNS service in Kubernetes cluster. Service registration: Kubernetes uses cluster DNS as service registration. Registration is Service based, not Pod based. Cluster DNS (CoreDNS) is monitoring and discvering new service actively. Service Name, IP, Port will be registered. Procedure of Service registration. POST new Service to API Server. Assign ClusterIP to the new Service. Save new Service configuration info to etcd. Create endpoints with related Pod IPs associated with the new Service. Explore the new Service by ClusterDNS. Create DNS info. kube-proxy fetch Service configration info. Create IPSV rule. Procedure of Service discovery. Request DNS name resolution for a Service name. Receive ClusterIP. Traffic access to ClusterIP. No router. Forward request to Pod's default gateway. Forward request to node. No router. Forward request to Node's default gateway. Proceed the request by Node kernel. Trap the request by IPSV rule. Put destination Pod's IP into the request's destination IP. The request arrives destination Pod. FQDN format: ..svc.cluster.local . We call as unqualified name, or short name. Namespaces can segregate the cluster's address space. At the same time, it can also be used to implement access control and resource quotas. Get DNS configuration in a Pod. The IP of nameserver is same with ClusterIP of kube-dns Service, which is well-known IP for request of DNS or service discovery. root@cka001:/etc# kubectl get service kube-dns -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP,9153/TCP 7d7h root@cka001:~# kubectl exec -it nginx-5f5496dc9-bv5dx -- /bin/bash root@nginx-5f5496dc9-bv5dx:/# cat /etc/resolv.conf search jh-namespace.svc.cluster.local svc.cluster.local cluster.local nameserver 10.96.0.10 options ndots:5 Get information of kube-dns . root@cka001:~# kubectl describe service kube-dns -n kube-system Name: kube-dns Namespace: kube-system Labels: k8s-app=kube-dns kubernetes.io/cluster-service=true kubernetes.io/name=CoreDNS Annotations: prometheus.io/port: 9153 prometheus.io/scrape: true Selector: k8s-app=kube-dns Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: 10.96.0.10 IPs: 10.96.0.10 Port: dns 53/UDP TargetPort: 53/UDP Endpoints: 10.244.0.2:53,10.244.0.3:53 Port: dns-tcp 53/TCP TargetPort: 53/TCP Endpoints: 10.244.0.2:53,10.244.0.3:53 Port: metrics 9153/TCP TargetPort: 9153/TCP Endpoints: 10.244.0.2:9153,10.244.0.3:9153 Session Affinity: None Events: Endpoints \u00b6 Endpoints is a collection of endpoints that implement the actual service. When a service is created, it associates with a Endpoint object, kubectl get endpoints . A list of matched Pod by service label is maintained as Endpoint object, add new matched Pods and remove not matched Pods. Config and Storage Resources \u00b6 Volumes \u00b6 emptyDir \u00b6 An emptyDir volume is first created when a Pod is assigned to a node, and exists as long as that Pod is running on that node. The emptyDir volume is initially empty. All containers in the Pod can read and write the same files in the emptyDir volume, though that volume can be mounted at the same or different paths in each container. When a Pod is removed from a node for any reason, the data in the emptyDir is deleted permanently. A container crashing does not remove a Pod from a node. The data in an emptyDir volume is safe across container crashes. Usage: scratch space, such as for a disk-based merge sort checkpointing a long computation for recovery from crashes holding files that a content-manager container fetches while a webserver container serves the data hostPath \u00b6 A hostPath volume mounts a file or directory from the host node's filesystem into your Pod. This is not something that most Pods will need, but it offers a powerful escape hatch for some applications. hostPath volumes present many security risks, and it is a best practice to avoid the use of HostPaths when possible. When a HostPath volume MUST be used, it should be scoped to only the required file or directory, and mounted as ReadOnly. If restricting HostPath access to specific directories through AdmissionPolicy, volumeMounts MUST be required to use readOnly mounts for the policy to be effective. Usage: Running together with DaemonSet, e.g., EFK Fluentd mount log directory of local host in order to collect host log information. Running on a specific node by using hostPath volumne, which can get high performance disk I/O. Running a container that needs access to Docker internals; use a hostPath of /var/lib/docker . Running cAdvisor in a container; use a hostPath of /sys . Allowing a Pod to specify whether a given hostPath should exist prior to the Pod running, whether it should be created, and what it should exist as. Storage Class \u00b6 Procedure of StorageClass deployment and implementation: Create Kubernetes cluster and backend storage. Make sure the provisioner/plugin is ready in Kubernetes. Create a StorageClass object to link to backend storage. The StorageClass will create related PV automatically. Create a PVC object to link to the StorageClass we created. Deploy a Pod and use the PVC volume. PV \u00b6 PV Recycle Policy. Retain. Delete. Recycle. PV in-tree type: hostPath local NFS CSI Access Modes \u00b6 spec.accessModes defines mount option of a PV: ReadWriteOnce(RWO). A PV can be mounted only to a PVC with read/write mode, like block device. ReadWriteMany(RWM). A PV can be mounted to more than one PVC with read/write mode, like NFS. ReadOnlyMany(ROM). A PV can be mounted to more than one PVC with read only mode. ReadWriteOncePod (RWOP). Only support CSI type PV, can be mounted by single Pod. A PV can only be set with one option. Pod mount PVC, not PV.","title":"Memo"},{"location":"k8s/cka_en/foundamentals/memo/#kubernetes-learning-memo","text":"","title":"Kubernetes Learning Memo"},{"location":"k8s/cka_en/foundamentals/memo/#basic-concepts-of-kubernetes","text":"","title":"Basic Concepts of Kubernetes"},{"location":"k8s/cka_en/foundamentals/memo/#kubernetes-components","text":"A Kubernetes cluster consists of the components that represent the control plane and a set of machines called nodes . Kubernetes Components : Control Plane Components kube-apiserver: query and manipulate the state of objects in Kubernetes. play as \"communication hub\" among all resources in cluster. provide cluster security authentication, authorization, and role assignment. the only one can connect to etcd . etcd: all Kubernetes objects are stored on etcd. Kubernetes objects are persistent entities in the Kubernetes system, which are used to represent the state of your cluster. kube-scheduler: watches for newly created Pods with no assigned node, and selects a node for them to run on. kube-controller-manager: runs controller processes. Node controller : Responsible for noticing and responding when nodes go down. Job controller : Watches for Job objects that represent one-off tasks, then creates Pods to run those tasks to completion. Endpoints controller : Populates the Endpoints object (that is, joins Services & Pods). Service Account & Token controllers : Create default accounts and API access tokens for new namespaces. cloud-controller-manager: embeds cloud-specific control logic and only runs controllers that are specific to your cloud provider, no need for own premises and learning environment. Node controller : For checking the cloud provider to determine if a node has been deleted in the cloud after it stops responding Route controller : For setting up routes in the underlying cloud infrastructure Service controller : For creating, updating and deleting cloud provider load balancers Node Components kubelet: An agent that runs on each node in the cluster. Manage node. It makes sure that containers are running in a Pod. kubelet registers and updates nodes information to APIServer, and APIServer stores them into etcd . Manage pod. Watch pod via APIServer, and action on pods or containers in pods. Health check at container level. kube-proxy: is a network proxy that runs on each node in cluster. iptables ipvs maintains network rules on nodes. Container runtime: is the software that is responsible for running containers. Addons DNS: is a DNS server and required by all Kubernetes clusters. Web UI (Dashboard): web-based UI for Kubernetes clusters. Container Resource Monitoring: records generic time-series metrics about containers in a central database Cluster-level Logging: is responsible for saving container logs to a central log store with search/browsing interface. Scalability: Scaling out (horizontal scaling) by adding more servers to your architecture to spread the workload across more machines. Scaling up (vertical scaling) by adding more hard drives and memory to increase the computing capacity of physical servers.","title":"Kubernetes Components"},{"location":"k8s/cka_en/foundamentals/memo/#kubernetes-api","text":"The REST API is the fundamental fabric of Kubernetes. All operations and communications between components, and external user commands are REST API calls that the API Server handles. Consequently, everything in the Kubernetes platform is treated as an API object and has a corresponding entry in the API. The core of Kubernetes' control plane is the API server. CRI: Container Runtime Interface CNI: Container Network Interface CSI: Container Storage Interface The API server exposes an HTTP API that lets end users, different parts of cluster, and external components communicate with one another. The Kubernetes API lets we query and manipulate the state of API objects in Kubernetes (for example: Pods, Namespaces, ConfigMaps, and Events). Kubernetes API: OpenAPI specification OpenAPI V2 OpenAPI V3 Persistence. Kubernetes stores the serialized state of objects by writing them into etcd. API groups and versioning. Versioning is done at the API level. API resources are distinguished by their API group, resource type, namespace (for namespaced resources), and name. API changes API Extension","title":"Kubernetes API"},{"location":"k8s/cka_en/foundamentals/memo/#api-version","text":"The API versioning and software versioning are indirectly related. The API and release versioning proposal describes the relationship between API versioning and software versioning. Different API versions indicate different levels of stability and support. Here's a summary of each level: Alpha: The version names contain alpha (for example, v1alpha1). The software may contain bugs. Enabling a feature may expose bugs. A feature may be disabled by default. The support for a feature may be dropped at any time without notice. The API may change in incompatible ways in a later software release without notice. The software is recommended for use only in short-lived testing clusters, due to increased risk of bugs and lack of long-term support. Beta: The version names contain beta (for example, v2beta3). The software is well tested. Enabling a feature is considered safe. Features are enabled by default. The support for a feature will not be dropped, though the details may change. The schema and/or semantics of objects may change in incompatible ways in a subsequent beta or stable release. When this happens, migration instructions are provided. Schema changes may require deleting, editing, and re-creating API objects. The editing process may not be straightforward. The migration may require downtime for applications that rely on the feature. The software is not recommended for production uses. Subsequent releases may introduce incompatible changes. If you have multiple clusters which can be upgraded independently, you may be able to relax this restriction. Note: Please try beta features and provide feedback. After the features exit beta, it may not be practical to make more changes. Stable: The version name is vX where X is an integer. The stable versions of features appear in released software for many subsequent versions. Command to get current API kubectl api-resources","title":"API Version"},{"location":"k8s/cka_en/foundamentals/memo/#api-group","text":"API groups make it easier to extend the Kubernetes API. The API group is specified in a REST path and in the apiVersion field of a serialized object. There are several API groups in Kubernetes: The core (also called legacy) group is found at REST path /api/v1 . The core group is not specified as part of the apiVersion field, for example, apiVersion: v1. The named groups are at REST path /apis/$GROUP_NAME/$VERSION and use apiVersion: $GROUP_NAME/$VERSION (for example, apiVersion: batch/v1).","title":"API Group"},{"location":"k8s/cka_en/foundamentals/memo/#kubernetes-objects","text":"","title":"Kubernetes Objects"},{"location":"k8s/cka_en/foundamentals/memo/#objects-overview","text":"Object Spec: providing a description of the characteristics the resource created to have: its desired state . Object Status: describes the current state of the object. Example of Deployment as an object that can represent an application running on cluster. apiVersion : apps/v1 # Which version of the Kubernetes API you're using to create this object kind : Deployment # What kind of object you want to create metadata : # Data that helps uniquely identify the object, including a name string, UID, and optional namespace name : nginx-deployment spec : # What state you desire for the object selector : matchLabels : app : nginx replicas : 2 # tells deployment to run 2 pods matching the template template : metadata : labels : app : nginx spec : containers : - name : nginx image : nginx:1.14.2 ports : - containerPort : 80","title":"Objects Overview"},{"location":"k8s/cka_en/foundamentals/memo/#object-management","text":"The kubectl command-line tool supports several different ways to create and manage Kubernetes objects. Read the Kubectl book for details. A Kubernetes object should be managed using ONLY one technique. Mixing and matching techniques for the same object results in undefined behavior. Three management techniques: Imperative commands operates directly on live objects in a cluster. kubectl create deployment nginx --image nginx Imperative object configuration kubectl create -f nginx.yaml kubectl delete -f nginx.yaml -f redis.yaml kubectl replace -f nginx.yaml Declarative object configuration kubectl diff -f configs/ kubectl apply -f configs/","title":"Object Management"},{"location":"k8s/cka_en/foundamentals/memo/#object-names-and-ids","text":"Each object in your cluster has a Name that is unique for that type of resource. DNS Subdomain Names Label Names Path Segment Names Every Kubernetes object also has a UID that is unique across the whole cluster.","title":"Object Names and IDs"},{"location":"k8s/cka_en/foundamentals/memo/#namespaces","text":"In Kubernetes, namespaces provides a mechanism for isolating groups of resources within a single cluster. Names of resources need to be unique within a namespace, but not across namespaces. Namespace-based scoping is applicable only for namespaced objects (e.g. Deployments, Services, etc) and not for cluster-wide objects (e.g. StorageClass, Nodes, PersistentVolumes, etc) Not All Objects are in a Namespace. Kubernetes starts with four initial namespaces: default The default namespace for objects with no other namespace kube-system The namespace for objects created by the Kubernetes system kube-public This namespace is created automatically and is readable by all users (including those not authenticated). This namespace is mostly reserved for cluster usage, in case that some resources should be visible and readable publicly throughout the whole cluster. The public aspect of this namespace is only a convention, not a requirement. kube-node-lease This namespace holds Lease objects associated with each node. Node leases allow the kubelet to send heartbeats so that the control plane can detect node failure. Viewing namespaces: kubectl get namespace Setting the namespace for a request kubectl run nginx --image=nginx --namespace= kubectl get pods --namespace=","title":"Namespaces"},{"location":"k8s/cka_en/foundamentals/memo/#labels-and-selectors","text":"Labels are key/value pairs that are attached to objects, such as pods. Valid label keys have two segments: an optional prefix and name, separated by a slash ( / ). Labels are intended to be used to specify identifying attributes of objects that are meaningful and relevant to users. Labels can be used to organize and to select subsets of objects. Labels can be attached to objects at creation time and subsequently added and modified at any time. Each object can have a set of key/value labels defined. Each Key must be unique for a given object. Example of labels: \"metadata\" : { \"labels\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } Unlike names and UIDs, labels do not provide uniqueness. In general, we expect many objects to carry the same label(s). The API currently supports two types of selectors: equality-based, e.g., environment = production , tier != frontend set-based, e.g., environment in (production, qa) , tier notin (frontend, backend) Sample commands: kubectl get pods -l environment=production,tier=frontend kubectl get pods -l 'environment in (production),tier in (frontend)' kubectl get pods -l 'environment in (production, qa)' kubectl get pods -l 'environment,environment notin (frontend)'","title":"Labels and Selectors"},{"location":"k8s/cka_en/foundamentals/memo/#annotations","text":"Use Kubernetes annotations to attach arbitrary non-identifying metadata to objects. Clients such as tools and libraries can retrieve this metadata. Use either labels or annotations to attach metadata to Kubernetes objects. Labels can be used to select objects and to find collections of objects that satisfy certain conditions. Annotations are not used to identify and select objects. Annotations, like labels, are key/value maps. The keys and the values in the map must be strings. \"metadata\" : { \"annotations\" : { \"key1\" : \"value1\" , \"key2\" : \"value2\" } } Valid annotation keys have two segments: an optional prefix and name, separated by a slash ( / ).","title":"Annotations"},{"location":"k8s/cka_en/foundamentals/memo/#field-selectors","text":"Field selectors let you select Kubernetes resources based on the value of one or more resource fields. Here are some examples of field selector queries: metadata.name=my-service metadata.namespace!=default status.phase=Pending This kubectl command selects all Pods for which the value of the status.phase field is Running: kubectl get pods --field-selector status.phase=Running Supported field selectors vary by Kubernetes resource type. All resource types support the metadata.name and metadata.namespace fields. Use the = , == , and != operators with field selectors ( = and == mean the same thing). For example: kubectl get ingress --field-selector foo.bar=baz With operators, kubectl get services --all-namespaces --field-selector metadata.namespace!=default Chained selectors, kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always Multiple resource types, kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default","title":"Field Selectors"},{"location":"k8s/cka_en/foundamentals/memo/#finalizers","text":"Finalizers are namespaced keys that tell Kubernetes to wait until specific conditions are met before it fully deletes resources marked for deletion . Finalizers alert controllers to clean up resources the deleted object owned. Finalizers are usually added to resources for a reason, so forcefully removing them can lead to issues in the cluster. Like labels, owner references describe the relationships between objects in Kubernetes, but are used for a different purpose. Kubernetes uses the owner references (not labels) to determine which Pods in the cluster need cleanup. Kubernetes processes finalizers when it identifies owner references on a resource targeted for deletion.","title":"Finalizers"},{"location":"k8s/cka_en/foundamentals/memo/#owners-and-dependents","text":"In Kubernetes, some objects are owners of other objects. For example, a ReplicaSet is the owner of a set of Pods. These owned objects are dependents of their owner. Dependent objects have a metadata.ownerReferences field that references their owner object. A valid owner reference consists of the object name and a UID within the same namespace as the dependent object. Dependent objects also have an ownerReferences.blockOwnerDeletion field that takes a boolean value and controls whether specific dependents can block garbage collection from deleting their owner object.","title":"Owners and Dependents"},{"location":"k8s/cka_en/foundamentals/memo/#resource","text":"Kubernetes resources and \"records of intent\" are all stored as API objects, and modified via RESTful calls to the API. The API allows configuration to be managed in a declarative way. Users can interact with the Kubernetes API directly, or via tools like kubectl. The core Kubernetes API is flexible and can also be extended to support custom resources. Workload Resources Pod . Pod is a collection of containers that can run on a host. PodTemplate . PodTemplate describes a template for creating copies of a predefined pod. ReplicationController . ReplicationController represents the configuration of a replication controller. ReplicaSet . ReplicaSet ensures that a specified number of pod replicas are running at any given time. Deployment . Deployment enables declarative updates for Pods and ReplicaSets. StatefulSet . StatefulSet represents a set of pods with consistent identities. ControllerRevision . ControllerRevision implements an immutable snapshot of state data. DaemonSet . DaemonSet represents the configuration of a daemon set. Job . Job represents the configuration of a single job. CronJob . CronJob represents the configuration of a single cron job. HorizontalPodAutoscaler . configuration of a horizontal pod autoscaler. HorizontalPodAutoscaler . HorizontalPodAutoscaler is the configuration for a horizontal pod autoscaler, which automatically manages the replica count of any resource implementing the scale subresource based on the metrics specified. HorizontalPodAutoscaler v2beta2 . HorizontalPodAutoscaler is the configuration for a horizontal pod autoscaler, which automatically manages the replica count of any resource implementing the scale subresource based on the metrics specified. PriorityClass . PriorityClass defines mapping from a priority class name to the priority integer value. Service Resources Service . Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy. Endpoints . Endpoints is a collection of endpoints that implement the actual service. EndpointSlice . EndpointSlice represents a subset of the endpoints that implement a service. Ingress . Ingress is a collection of rules that allow inbound connections to reach the endpoints defined by a backend. IngressClass . IngressClass represents the class of the Ingress, referenced by the Ingress Spec. Config and Storage Resources ConfigMap . ConfigMap holds configuration data for pods to consume. Secret . Secret holds secret data of a certain type. Volume . Volume represents a named volume in a pod that may be accessed by any container in the pod. PersistentVolumeClaim . PersistentVolumeClaim is a user's request for and claim to a persistent volume. PersistentVolume . PersistentVolume (PV) is a storage resource provisioned by an administrator. StorageClass . StorageClass describes the parameters for a class of storage for which PersistentVolumes can be dynamically provisioned. VolumeAttachment . VolumeAttachment captures the intent to attach or detach the specified volume to/from the specified node. CSIDriver . CSIDriver captures information about a Container Storage Interface (CSI) volume driver deployed on the cluster. CSINode . CSINode holds information about all CSI drivers installed on a node. CSIStorageCapacity . CSIStorageCapacity stores the result of one CSI GetCapacity call. Authentication Resources ServiceAccount . ServiceAccount binds together: a name, understood by users, and perhaps by peripheral systems, for an identity a principal that can be authenticated and authorized a set of secrets. TokenRequest . TokenRequest requests a token for a given service account. TokenReview . TokenReview attempts to authenticate a token to a known user. CertificateSigningRequest . CertificateSigningRequest objects provide a mechanism to obtain x509 certificates by submitting a certificate signing request, and having it asynchronously approved and issued. Authorization Resources LocalSubjectAccessReview . LocalSubjectAccessReview checks whether or not a user or group can perform an action in a given namespace. SelfSubjectAccessReview . SelfSubjectAccessReview checks whether or the current user can perform an action. SelfSubjectRulesReview . SelfSubjectRulesReview enumerates the set of actions the current user can perform within a namespace. SubjectAccessReview . SubjectAccessReview checks whether or not a user or group can perform an action. ClusterRole . ClusterRole is a cluster level, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding or ClusterRoleBinding. ClusterRoleBinding . ClusterRoleBinding references a ClusterRole, but not contain it. Role . Role is a namespaced, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding. RoleBinding . RoleBinding references a role, but does not contain it. Policy Resources LimitRange . LimitRange sets resource usage limits for each kind of resource in a Namespace. ResourceQuota . ResourceQuota sets aggregate quota restrictions enforced per namespace. NetworkPolicy . NetworkPolicy describes what network traffic is allowed for a set of Pods. PodDisruptionBudget . PodDisruptionBudget is an object to define the max disruption that can be caused to a collection of pods. PodSecurityPolicy v1beta1 . PodSecurityPolicy governs the ability to make requests that affect the Security Context that will be applied to a pod and container. Extend Resources CustomResourceDefinition . CustomResourceDefinition represents a resource that should be exposed on the API server. MutatingWebhookConfiguration . MutatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and may change the object. *ValidatingWebhookConfiguration(). ValidatingWebhookConfiguration describes the configuration of and admission webhook that accept or reject and object without changing it. Cluster Resources Node . Node is a worker node in Kubernetes. Namespace . Namespace provides a scope for Names. Event . Event is a report of an event somewhere in the cluster. APIService . APIService represents a server for a particular GroupVersion. Lease . Lease defines a lease concept. RuntimeClass . RuntimeClass defines a class of container runtime supported in the cluster. FlowSchema v1beta2 . FlowSchema defines the schema of a group of flows. PriorityLevelConfiguration v1beta2 . PriorityLevelConfiguration represents the configuration of a priority level. Binding . Binding ties one object to another; for example, a pod is bound to a node by a scheduler. ComponentStatus . ComponentStatus (and ComponentStatusList) holds the cluster validation info. Command kube api-resources to get the supported API resources. Command kubectl explain RESOURCE [options] describes the fields associated with each supported API resource. Fields are identified via a simple JSONPath identifier: kubectl explain binding kubectl explain binding.metadata kubectl explain binding.metadata.name","title":"Resource"},{"location":"k8s/cka_en/foundamentals/memo/#workload-resources","text":"","title":"Workload Resources"},{"location":"k8s/cka_en/foundamentals/memo/#pods","text":"Pods are the smallest deployable units of computing that you can create and manage in Kubernetes. A Pod is a group of one or more containers, with shared storage and network resources, and a specification for how to run the containers. A Pod's contents are always co-located and co-scheduled, and run in a shared context. A Pod models an application-specific \"logical host\": it contains one or more application containers which are relatively tightly coupled. In non-cloud contexts, applications executed on the same physical or virtual machine are analogous to cloud applications executed on the same logical host. The shared context of a Pod is a set of Linux namespaces, cgroups, and potentially other facets of isolation - the same things that isolate a Docker container. In terms of Docker concepts, a Pod is similar to a group of Docker containers with shared namespaces and shared filesystem volumes. Usually you don't need to create Pods directly, even singleton Pods. Instead, create them using workload resources such as Deployment or Job . If your Pods need to track state, consider the StatefulSet resource. Pods in a Kubernetes cluster are used in two main ways: Pods that run a single container. Pods that run multiple containers that need to work together. The \"one-container-per-Pod\" model is the most common Kubernetes use case; in this case, you can think of a Pod as a wrapper around a single container; Kubernetes manages Pods rather than managing the containers directly. A Pod can encapsulate an application composed of multiple co-located containers that are tightly coupled and need to share resources. These co-located containers form a single cohesive unit of service\u2014for example, one container serving data stored in a shared volume to the public, while a separate sidecar container refreshes or updates those files. The Pod wraps these containers, storage resources, and an ephemeral network identity together as a single unit. Grouping multiple co-located and co-managed containers in a single Pod is a relatively advanced use case. You should use this pattern only in specific instances in which your containers are tightly coupled. Each Pod is meant to run a single instance of a given application. If you want to scale your application horizontally (to provide more overall resources by running more instances), you should use multiple Pods, one for each instance. In Kubernetes, this is typically referred to as replication . Replicated Pods are usually created and managed as a group by a workload resource and its controller. Pods natively provide two kinds of shared resources for their constituent containers: networking and storage . A Pod can specify a set of shared storage volumes. All containers in the Pod can access the shared volumes, allowing those containers to share data. Each Pod is assigned a unique IP address for each address family. Within a Pod, containers share an IP address and port space, and can find each other via localhost . Containers that want to interact with a container running in a different Pod can use IP networking to communicate. When a Pod gets created, the new Pod is scheduled to run on a Node in your cluster. The Pod remains on that node until the Pod finishes execution, the Pod object is deleted, the Pod is evicted for lack of resources, or the node fails. Restarting a container in a Pod should not be confused with restarting a Pod. A Pod is not a process, but an environment for running container(s). A Pod persists until it is deleted. You can use workload resources (e.g., Deployment, StatefulSet, DaemonSet) to create and manage multiple Pods for you. A controller for the resource handles replication and rollout and automatic healing in case of Pod failure.","title":"Pods"},{"location":"k8s/cka_en/foundamentals/memo/#initcontainer","text":"Some Pods have init containers as well as app containers. Init containers run and complete before the app containers are started. You can specify init containers in the Pod specification alongside the containers array (which describes app containers).","title":"InitContainer"},{"location":"k8s/cka_en/foundamentals/memo/#static-pod","text":"Static Pods are managed directly by the kubelet daemon on a specific node, without the API server observing them. Static Pods are always bound to one Kubelet on a specific node. The main use for static Pods is to run a self-hosted control plane: in other words, using the kubelet to supervise the individual control plane components. The kubelet automatically tries to create a mirror Pod on the Kubernetes API server for each static Pod. This means that the Pods running on a node are visible on the API server, but cannot be controlled from there.","title":"Static Pod"},{"location":"k8s/cka_en/foundamentals/memo/#container-probes","text":"A probe is a diagnostic performed periodically by the kubelet on a container. To perform a diagnostic, the kubelet either executes code within the container, or makes a network request. There are four different ways to check a container using a probe. Each probe must define exactly one of these four mechanisms: exec . The diagnostic is considered successful if the command exits with a status code of 0. grpc . The diagnostic is considered successful if the status of the response is SERVING. httpGet . The diagnostic is considered successful if the response has a status code greater than or equal to 200 and less than 400. tcpSocket . The diagnostic is considered successful if the port is open. Each probe has one of three results: Success Failure Unknown Types of probe: livenessProbe . Indicates whether the container is running. readinessProbe . Indicates whether the container is ready to respond to requests. startupProbe . Indicates whether the application within the container is started.","title":"Container probes"},{"location":"k8s/cka_en/foundamentals/memo/#deployment","text":"","title":"Deployment"},{"location":"k8s/cka_en/foundamentals/memo/#replicaset","text":"A ReplicaSet\u2019s purpose is to maintain a stable set of replica Pods running at any given time. As such, it is often used to guarantee the availability of a specified number of identical Pods. You may never need to manipulate ReplicaSet objects: use a Deployment instead, and define your application in the spec section. You can specify how many Pods should run concurrently by setting replicaset.spec.replicas . The ReplicaSet will create/delete its Pods to match this number. If you do not specify replicaset.spec.replicas , then it defaults to 1 .","title":"ReplicaSet"},{"location":"k8s/cka_en/foundamentals/memo/#statefulset","text":"StatefulSet Characteristics (aka, stick ID): Pod's name is immutable after created. DNS hostname is immutable after created. Mounted volume is immutable after created. Stick ID of StatefulSet won't be changed after failure, scaling, and other operations. Naming convention of StatefulSet: - . StatefulSet can be scalling by itsself, but Deployment need rely on ReplicaSet for scalling. Recommendation: reduce StatefulSet to 0 first instead of delete it directly. headless Service and governing Service: Headless Service is a normal Kubernetes Service object that its spec.clusterIP is set to None . When spec.ServiceName of StatefulSet is set to the headless Service name, the StatefulSet is now a governing Service. General procedure to create a StatefulSet: Create a StorageClass Create Headless Service Create StatefulSet based on above two.","title":"StatefulSet"},{"location":"k8s/cka_en/foundamentals/memo/#daemonset","text":"A DaemonSet ensures that all (or some) Nodes run a copy of a Pod. As nodes are removed from the cluster, those Pods are garbage collected. Deleting a DaemonSet will clean up the Pods it created. Some typical uses of a DaemonSet are: running a cluster storage daemon on every node running a logs collection daemon on every node running a node monitoring daemon on every node In a simple case, one DaemonSet, covering all nodes, would be used for each type of daemon. A more complex setup might use multiple DaemonSets for a single type of daemon, but with different flags and/or different memory and cpu requests for different hardware types. The DaemonSet controller reconciliation process reviews both existing nodes and newly created nodes. By default, the Kubernetes scheduler ignores the pods created by the DamonSet, and lets them exist on the node until the node itself is shut down. Running Pods on select Nodes: If you specify a daemonset.spec.template.spec.nodeSelector , then the DaemonSet controller will create Pods on nodes which match that node selector. If you specify a daemonset.spec.template.spec.affinity , then DaemonSet controller will create Pods on nodes which match that node affinity. If you do not specify either, then the DaemonSet controller will create Pods on all nodes. There is no field replicas in kubectl explain daemonset.spec against with kubectl explain deployment.spec.replicas . When a DaemonSet is created, each node will have one DaemonSet Pod running. We\u2019ll use a Deployment / ReplicaSet for services, mostly stateless, where we don\u2019t care where the node is running, but we care more about the number of copies of our pod is running, and we can scale those copies/replicas up or down. Rolling updates would also be a benefit here. We\u2019ll use a DaemonSet when a copy of our pod must be running on the specific nodes that we require. Our daemon pod also needs to start before any of our other pods. A DaemonSet is a simple scalability strategy for background services. When more eligible nodes are added to the cluster, the background service scales up. When nodes are removed, it will automatically scale down.","title":"DaemonSet"},{"location":"k8s/cka_en/foundamentals/memo/#job","text":"","title":"Job"},{"location":"k8s/cka_en/foundamentals/memo/#cronjob","text":"","title":"CronJob"},{"location":"k8s/cka_en/foundamentals/memo/#service-resource","text":"","title":"Service Resource"},{"location":"k8s/cka_en/foundamentals/memo/#service","text":"Service is a named abstraction of software service (for example, mysql) consisting of local port (for example 3306) that the proxy listens on, and the selector that determines which pods will answer requests sent through the proxy. The set of Pods targeted by a Service is usually determined by a selector (label selector). Type of service resource: ClusterIP Service (default): Reliable IP, DNS, and Port. Internal acess only. NodePort Service: Expose to external access. LoadBalancer: Based on NodePort and integrated with loader balance provided by cloud venders (e.g., AWS, GCP, etc.). ExternalName: Acces will be trafficed to external service. Here is an example of yaml file to create a Service. apiVersion : v1 kind : Service metadata : name : nginx-service labels : tier : application spec : ports : - port : 80 protocol : TCP targetPort : 8080 selector : run : nginx type : NodePort Here is an example of Service. IP 10.96.17.77 is ClusterIP(VIP) of the service Port 80/TCP is the port on Pod that service listening within the cluster. TargetPort 8080/TCP is the port on the container that the service should direct traffic to. NodePort 31893/TCP is the port that can be accessed outside. Default range is 30000~32767 . The port is exposed across all nodes in cluster. Endpoints show the list of Pods matched the service labels. Name: nginx-deployment Namespace: jh-namespace Labels: tier=application Annotations: Selector: run=nginx Type: NodePort IP Family Policy: SingleStack IP Families: IPv4 IP: 10.96.17.77 IPs: 10.96.17.77 Port: 80/TCP TargetPort: 8080/TCP NodePort: 31893/TCP Endpoints: 10.244.1.177:8080,10.244.1.178:8080,10.244.1.179:8080 + 7 more... Session Affinity: None External Traffic Policy: Cluster Events: Service kube-dns beyond Deployment coredns provides cluster DNS service in Kubernetes cluster. Service registration: Kubernetes uses cluster DNS as service registration. Registration is Service based, not Pod based. Cluster DNS (CoreDNS) is monitoring and discvering new service actively. Service Name, IP, Port will be registered. Procedure of Service registration. POST new Service to API Server. Assign ClusterIP to the new Service. Save new Service configuration info to etcd. Create endpoints with related Pod IPs associated with the new Service. Explore the new Service by ClusterDNS. Create DNS info. kube-proxy fetch Service configration info. Create IPSV rule. Procedure of Service discovery. Request DNS name resolution for a Service name. Receive ClusterIP. Traffic access to ClusterIP. No router. Forward request to Pod's default gateway. Forward request to node. No router. Forward request to Node's default gateway. Proceed the request by Node kernel. Trap the request by IPSV rule. Put destination Pod's IP into the request's destination IP. The request arrives destination Pod. FQDN format: ..svc.cluster.local . We call as unqualified name, or short name. Namespaces can segregate the cluster's address space. At the same time, it can also be used to implement access control and resource quotas. Get DNS configuration in a Pod. The IP of nameserver is same with ClusterIP of kube-dns Service, which is well-known IP for request of DNS or service discovery. root@cka001:/etc# kubectl get service kube-dns -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP,9153/TCP 7d7h root@cka001:~# kubectl exec -it nginx-5f5496dc9-bv5dx -- /bin/bash root@nginx-5f5496dc9-bv5dx:/# cat /etc/resolv.conf search jh-namespace.svc.cluster.local svc.cluster.local cluster.local nameserver 10.96.0.10 options ndots:5 Get information of kube-dns . root@cka001:~# kubectl describe service kube-dns -n kube-system Name: kube-dns Namespace: kube-system Labels: k8s-app=kube-dns kubernetes.io/cluster-service=true kubernetes.io/name=CoreDNS Annotations: prometheus.io/port: 9153 prometheus.io/scrape: true Selector: k8s-app=kube-dns Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: 10.96.0.10 IPs: 10.96.0.10 Port: dns 53/UDP TargetPort: 53/UDP Endpoints: 10.244.0.2:53,10.244.0.3:53 Port: dns-tcp 53/TCP TargetPort: 53/TCP Endpoints: 10.244.0.2:53,10.244.0.3:53 Port: metrics 9153/TCP TargetPort: 9153/TCP Endpoints: 10.244.0.2:9153,10.244.0.3:9153 Session Affinity: None Events: ","title":"Service"},{"location":"k8s/cka_en/foundamentals/memo/#endpoints","text":"Endpoints is a collection of endpoints that implement the actual service. When a service is created, it associates with a Endpoint object, kubectl get endpoints . A list of matched Pod by service label is maintained as Endpoint object, add new matched Pods and remove not matched Pods.","title":"Endpoints"},{"location":"k8s/cka_en/foundamentals/memo/#config-and-storage-resources","text":"","title":"Config and Storage Resources"},{"location":"k8s/cka_en/foundamentals/memo/#volumes","text":"","title":"Volumes"},{"location":"k8s/cka_en/foundamentals/memo/#emptydir","text":"An emptyDir volume is first created when a Pod is assigned to a node, and exists as long as that Pod is running on that node. The emptyDir volume is initially empty. All containers in the Pod can read and write the same files in the emptyDir volume, though that volume can be mounted at the same or different paths in each container. When a Pod is removed from a node for any reason, the data in the emptyDir is deleted permanently. A container crashing does not remove a Pod from a node. The data in an emptyDir volume is safe across container crashes. Usage: scratch space, such as for a disk-based merge sort checkpointing a long computation for recovery from crashes holding files that a content-manager container fetches while a webserver container serves the data","title":"emptyDir"},{"location":"k8s/cka_en/foundamentals/memo/#hostpath","text":"A hostPath volume mounts a file or directory from the host node's filesystem into your Pod. This is not something that most Pods will need, but it offers a powerful escape hatch for some applications. hostPath volumes present many security risks, and it is a best practice to avoid the use of HostPaths when possible. When a HostPath volume MUST be used, it should be scoped to only the required file or directory, and mounted as ReadOnly. If restricting HostPath access to specific directories through AdmissionPolicy, volumeMounts MUST be required to use readOnly mounts for the policy to be effective. Usage: Running together with DaemonSet, e.g., EFK Fluentd mount log directory of local host in order to collect host log information. Running on a specific node by using hostPath volumne, which can get high performance disk I/O. Running a container that needs access to Docker internals; use a hostPath of /var/lib/docker . Running cAdvisor in a container; use a hostPath of /sys . Allowing a Pod to specify whether a given hostPath should exist prior to the Pod running, whether it should be created, and what it should exist as.","title":"hostPath"},{"location":"k8s/cka_en/foundamentals/memo/#storage-class","text":"Procedure of StorageClass deployment and implementation: Create Kubernetes cluster and backend storage. Make sure the provisioner/plugin is ready in Kubernetes. Create a StorageClass object to link to backend storage. The StorageClass will create related PV automatically. Create a PVC object to link to the StorageClass we created. Deploy a Pod and use the PVC volume.","title":"Storage Class"},{"location":"k8s/cka_en/foundamentals/memo/#pv","text":"PV Recycle Policy. Retain. Delete. Recycle. PV in-tree type: hostPath local NFS CSI","title":"PV"},{"location":"k8s/cka_en/foundamentals/memo/#access-modes","text":"spec.accessModes defines mount option of a PV: ReadWriteOnce(RWO). A PV can be mounted only to a PVC with read/write mode, like block device. ReadWriteMany(RWM). A PV can be mounted to more than one PVC with read/write mode, like NFS. ReadOnlyMany(ROM). A PV can be mounted to more than one PVC with read only mode. ReadWriteOncePod (RWOP). Only support CSI type PV, can be mounted by single Pod. A PV can only be set with one option. Pod mount PVC, not PV.","title":"Access Modes"},{"location":"k8s/cka_en/foundamentals/namespace/","text":"Namespace \u00b6 Scenario: Get namespace list Create new namespace Label a namespace Delete a namespace Demo: Get list of Namespace kubectl get namespace Get list of Namespace with Label information. kubectl get ns --show-labels Create a Namespace kubectl create namespace cka Label the new created Namespace cka . kubectl label ns cka cka=true Create Nginx Deployment in Namespace cka . kubectl create deploy nginx --image=nginx --namespace cka Check Deployments and Pods running in namespace cka . kubectl get deploy,pod -n cka Result is below. NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx 1/1 1 1 2m14s NAME READY STATUS RESTARTS AGE pod/nginx-85b98978db-bmkhf 1/1 Running 0 2m14s Delete namespace cka . All resources in the namespaces will be gone. kubectl delete ns cka Tip: Kubernetes Namespaces stuck in Terminating status. kubectl get namespace $NAMESPACE -o json | sed -e 's/\"kubernetes\"//' | kubectl replace --raw \"/api/v1/namespaces/$NAMESPACE/finalize\" -f -","title":"Namespace"},{"location":"k8s/cka_en/foundamentals/namespace/#namespace","text":"Scenario: Get namespace list Create new namespace Label a namespace Delete a namespace Demo: Get list of Namespace kubectl get namespace Get list of Namespace with Label information. kubectl get ns --show-labels Create a Namespace kubectl create namespace cka Label the new created Namespace cka . kubectl label ns cka cka=true Create Nginx Deployment in Namespace cka . kubectl create deploy nginx --image=nginx --namespace cka Check Deployments and Pods running in namespace cka . kubectl get deploy,pod -n cka Result is below. NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nginx 1/1 1 1 2m14s NAME READY STATUS RESTARTS AGE pod/nginx-85b98978db-bmkhf 1/1 Running 0 2m14s Delete namespace cka . All resources in the namespaces will be gone. kubectl delete ns cka Tip: Kubernetes Namespaces stuck in Terminating status. kubectl get namespace $NAMESPACE -o json | sed -e 's/\"kubernetes\"//' | kubectl replace --raw \"/api/v1/namespaces/$NAMESPACE/finalize\" -f -","title":"Namespace"},{"location":"k8s/cka_en/foundamentals/networkpolicy/","text":"Network Policy \u00b6 Replace Flannel by Calico \u00b6 Scenario Remove Flannel Install Calico Demo: If Calico was installed at the installation phase, ignore this section. Delete Flannel kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/v0.18.1/Documentation/kube-flannel.yml or kubectl delete -f kube-flannel.yml Output: Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy \"psp.flannel.unprivileged\" deleted clusterrole.rbac.authorization.k8s.io \"flannel\" deleted clusterrolebinding.rbac.authorization.k8s.io \"flannel\" deleted serviceaccount \"flannel\" deleted configmap \"kube-flannel-cfg\" deleted daemonset.apps \"kube-flannel-ds\" deleted Clean up iptables for all nodes. rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Log out and log on to host (e.g., cka001) again. Install Calico. curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Output: configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created Verify status of Calico. Make sure all Pods are running kubectl get pod -n kube-system | grep calico Output: NAME READY STATUS RESTARTS AGE calico-kube-controllers-7bc6547ffb-tjfcg 1/1 Running 0 30m calico-node-7x8jm 1/1 Running 0 30m calico-node-cwxj5 1/1 Running 0 30m calico-node-rq978 1/1 Running 0 30m If facing any error, check log in the Container. # Get Container ID crictl ps # Get log info crictl logs As we change CNI from Flannel to Calico, we need delete all Pods. All of Pods will be created automatically again. kubectl delete pod -A --all Make sure all Pods are up and running successfully. kubectl get pod -A Inbound Rules \u00b6 Scenario Create workload for test. Deny For All Ingress Allow For Specific Ingress Verify NetworkPolicy Demo: Create workload for test. \u00b6 Create three Deployments pod-netpol-1 , pod-netpol-2 , pod-netpol-3 based on image busybox . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-1 name: pod-netpol-1 spec: replicas: 1 selector: matchLabels: app: pod-netpol-1 template: metadata: labels: app: pod-netpol-1 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-2 name: pod-netpol-2 spec: replicas: 1 selector: matchLabels: app: pod-netpol-2 template: metadata: labels: app: pod-netpol-2 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-3 name: pod-netpol-3 spec: replicas: 1 selector: matchLabels: app: pod-netpol-3 template: metadata: labels: app: pod-netpol-3 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] EOF Check Pods IP. kubectl get pod -owide Output: NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-netpol-1-6494f6bf8b-n58r9 1/1 Running 0 29s 10.244.102.30 cka003 pod-netpol-2-77478d77ff-l6rzm 1/1 Running 0 29s 10.244.112.30 cka002 pod-netpol-3-68977dcb48-ql5s6 1/1 Running 0 29s 10.244.102.31 cka003 Attach to Pod pod-netpol-1 kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh Execute command ping that pod-netpol-2 and pod-netpol-3 are both reachable. / # ping 10.244.112.30 3 packets transmitted, 3 packets received, 0% packet loss / # ping 10.244.102.31 3 packets transmitted, 3 packets received, 0% packet loss Deny For All Ingress \u00b6 Create deny policy for all ingress. kubectl apply -f - << EOF apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-ingress spec: podSelector: {} policyTypes: - Ingress EOF Attach to Pod pod-netpol-1 again kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh Execute command ping that pod-netpol-2 and pod-netpol-3 are both unreachable as expected. / # ping 10.244.112.30 3 packets transmitted, 0 packets received, 100% packet loss / # ping 10.244.102.31 3 packets transmitted, 0 packets received, 100% packet loss Allow For Specific Ingress \u00b6 Create NetworkPlicy to allow ingress from pod-netpol-1 to pod-netpol-2 . kubectl apply -f - <:80 failed. Command curl :80 succeed. kubectl run centos --image=centos -n my-ns-1 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-1 -- bash Create temp pod on namespace my-ns-2 . Attach to the pod and verify the access. Command curl :80 failed. Command curl :80 failed. kubectl run centos --image=centos -n my-ns-2 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-2 -- bash Edit my-networkpolicy-1 to change ingress.from.namespaceSelector.matchLabels to my-ns-2 . Attach to temp pod on namespace my-ns-2 . Verify the access. Command curl :80 failed. Command curl :80 succeed. kubectl exec -it mycentos -n my-ns-2 -- bash Clean up: kubectl delete namespace my-ns-1 kubectl delete namespace my-ns-2","title":"Network Policy"},{"location":"k8s/cka_en/foundamentals/networkpolicy/#network-policy","text":"","title":"Network Policy"},{"location":"k8s/cka_en/foundamentals/networkpolicy/#replace-flannel-by-calico","text":"Scenario Remove Flannel Install Calico Demo: If Calico was installed at the installation phase, ignore this section. Delete Flannel kubectl delete -f https://raw.githubusercontent.com/coreos/flannel/v0.18.1/Documentation/kube-flannel.yml or kubectl delete -f kube-flannel.yml Output: Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy \"psp.flannel.unprivileged\" deleted clusterrole.rbac.authorization.k8s.io \"flannel\" deleted clusterrolebinding.rbac.authorization.k8s.io \"flannel\" deleted serviceaccount \"flannel\" deleted configmap \"kube-flannel-cfg\" deleted daemonset.apps \"kube-flannel-ds\" deleted Clean up iptables for all nodes. rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Log out and log on to host (e.g., cka001) again. Install Calico. curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Output: configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created Verify status of Calico. Make sure all Pods are running kubectl get pod -n kube-system | grep calico Output: NAME READY STATUS RESTARTS AGE calico-kube-controllers-7bc6547ffb-tjfcg 1/1 Running 0 30m calico-node-7x8jm 1/1 Running 0 30m calico-node-cwxj5 1/1 Running 0 30m calico-node-rq978 1/1 Running 0 30m If facing any error, check log in the Container. # Get Container ID crictl ps # Get log info crictl logs As we change CNI from Flannel to Calico, we need delete all Pods. All of Pods will be created automatically again. kubectl delete pod -A --all Make sure all Pods are up and running successfully. kubectl get pod -A","title":"Replace Flannel by Calico"},{"location":"k8s/cka_en/foundamentals/networkpolicy/#inbound-rules","text":"Scenario Create workload for test. Deny For All Ingress Allow For Specific Ingress Verify NetworkPolicy Demo:","title":"Inbound Rules"},{"location":"k8s/cka_en/foundamentals/networkpolicy/#create-workload-for-test","text":"Create three Deployments pod-netpol-1 , pod-netpol-2 , pod-netpol-3 based on image busybox . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-1 name: pod-netpol-1 spec: replicas: 1 selector: matchLabels: app: pod-netpol-1 template: metadata: labels: app: pod-netpol-1 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-2 name: pod-netpol-2 spec: replicas: 1 selector: matchLabels: app: pod-netpol-2 template: metadata: labels: app: pod-netpol-2 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] --- apiVersion: apps/v1 kind: Deployment metadata: labels: app: pod-netpol-3 name: pod-netpol-3 spec: replicas: 1 selector: matchLabels: app: pod-netpol-3 template: metadata: labels: app: pod-netpol-3 spec: containers: - image: busybox name: busybox command: [\"sh\", \"-c\", \"sleep 1h\"] EOF Check Pods IP. kubectl get pod -owide Output: NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-netpol-1-6494f6bf8b-n58r9 1/1 Running 0 29s 10.244.102.30 cka003 pod-netpol-2-77478d77ff-l6rzm 1/1 Running 0 29s 10.244.112.30 cka002 pod-netpol-3-68977dcb48-ql5s6 1/1 Running 0 29s 10.244.102.31 cka003 Attach to Pod pod-netpol-1 kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh Execute command ping that pod-netpol-2 and pod-netpol-3 are both reachable. / # ping 10.244.112.30 3 packets transmitted, 3 packets received, 0% packet loss / # ping 10.244.102.31 3 packets transmitted, 3 packets received, 0% packet loss","title":"Create workload for test."},{"location":"k8s/cka_en/foundamentals/networkpolicy/#deny-for-all-ingress","text":"Create deny policy for all ingress. kubectl apply -f - << EOF apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-ingress spec: podSelector: {} policyTypes: - Ingress EOF Attach to Pod pod-netpol-1 again kubectl exec -it pod-netpol-1-6494f6bf8b-n58r9 -- sh Execute command ping that pod-netpol-2 and pod-netpol-3 are both unreachable as expected. / # ping 10.244.112.30 3 packets transmitted, 0 packets received, 100% packet loss / # ping 10.244.102.31 3 packets transmitted, 0 packets received, 100% packet loss","title":"Deny For All Ingress"},{"location":"k8s/cka_en/foundamentals/networkpolicy/#allow-for-specific-ingress","text":"Create NetworkPlicy to allow ingress from pod-netpol-1 to pod-netpol-2 . kubectl apply -f - <:80 failed. Command curl :80 succeed. kubectl run centos --image=centos -n my-ns-1 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-1 -- bash Create temp pod on namespace my-ns-2 . Attach to the pod and verify the access. Command curl :80 failed. Command curl :80 failed. kubectl run centos --image=centos -n my-ns-2 -- \"/bin/sh\" \"-c\" \"sleep 3600\" kubectl exec -it mycentos -n my-ns-2 -- bash Edit my-networkpolicy-1 to change ingress.from.namespaceSelector.matchLabels to my-ns-2 . Attach to temp pod on namespace my-ns-2 . Verify the access. Command curl :80 failed. Command curl :80 succeed. kubectl exec -it mycentos -n my-ns-2 -- bash Clean up: kubectl delete namespace my-ns-1 kubectl delete namespace my-ns-2","title":"NetworkPolicy"},{"location":"k8s/cka_en/foundamentals/overview/","text":"Cluster Overview \u00b6 Contents \u00b6 Container Layer Kubernetes Layer Information: For environment setup, refer to Installation on Aliyun Ubuntu Container Layer \u00b6 Scenario: Use Containerd service to manage our images and containers via command nerdctl , which is same concept with Docker. Get namespace. Get containers. Get images. Get volumes. Get overall status. Get network status. Demo: Get namespaces. sudo nerdctl namespace ls Result NAME CONTAINERS IMAGES VOLUMES LABELS k8s.io 21 30 0 Get containers under specific namespace k8s.io . sudo nerdctl -n k8s.io ps Result CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0a3625f22f65 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk 121af2ecd1a1 registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll/coredns 49f6c7e3efe5 registry.aliyuncs.com/google_containers/kube-proxy:v1.24.0 \"/usr/local/bin/kube\u2026\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t/kube-proxy 4bba5fbd701d registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001 57d47b57eb12 docker.io/calico/node:v3.23.3 \"start_runit\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl/calico-node 5ce4c351a886 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl 6456eef784bf registry.aliyuncs.com/google_containers/kube-scheduler:v1.24.0 \"kube-scheduler --au\u2026\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001/kube-scheduler 6a687305871c registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 7dcb24568574 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll a06b101118b8 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001 a07ef8c3fc3a registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/etcd-cka001 b8566d3e4174 registry.aliyuncs.com/google_containers/kube-controller-manager:v1.24.0 \"kube-controller-man\u2026\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001/kube-controller-manager ca6ac26314ff registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk/coredns cdc041b4791e registry.aliyuncs.com/google_containers/etcd:3.5.3-0 \"etcd --advertise-cl\u2026\" 16 hours ago Up k8s://kube-system/etcd-cka001/etcd e0c59abadf2e registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t e0d2e5f6ccff registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001 Get images. sudo nerdctl -n k8s.io image ls -a Get volumes. After inintial installation, no volume within namespaces. sudo nerdctl -n k8s.io volume ls Get overall status sudo nerdctl stats Get network status. sudo nerdctl network ls sudo nerdctl network inspect bridge sudo nerdctl network inspect k8s-pod-network Result NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none Get network interface in host cka001 with command ip addr list . IP pool of 10.4.0.1/24 is ipam and defined in /etc/cni/net.d/nerdctl-bridge.conflist . lo : inet 127.0.0.1/8 qlen 1000 eth0 : inet /24 brd xxx.xxx.xxx.255 scope global dynamic eth0 tunl0@NONE : inet 10.244.228.192/32 scope global tunl0 cali96e32d88db2@if4 : cali93613212490@if4 : Kubernetes Layer \u00b6 Scenario: Nodes Namespaces System Pods Demo: Information: In the demo, there are three nodes, cka001 , cka002 , and cka003 . Get nodes status. kubectl get node -o wide There are four initial namespaces across three nodes. kubectl get namespace -A Result NAME STATUS AGE default Active 56m kube-node-lease Active 56m kube-public Active 56m kube-system Active 56m There are some initial pods. kubectl get pod -A -o wide Result NAMESPACE NAME READY STATUS RESTARTS AGE NODE NOMINATED NODE READINESS GATES kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 15h cka003 kube-system calico-node-255pc 1/1 Running 0 15h cka003 kube-system calico-node-7tmnb 1/1 Running 0 15h cka002 kube-system calico-node-w8nvl 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15h cka001 kube-system etcd-cka001 1/1 Running 0 15h cka001 kube-system kube-apiserver-cka001 1/1 Running 0 15h cka001 kube-system kube-controller-manager-cka001 1/1 Running 0 15h cka001 kube-system kube-proxy-dmj2t 1/1 Running 0 15h cka001 kube-system kube-proxy-n77zw 1/1 Running 0 15h cka002 kube-system kube-proxy-qs6rf 1/1 Running 0 15h cka003 kube-system kube-scheduler-cka001 1/1 Running 0 15h cka001 Summary: Below shows the relationship between containers and pods. Master node: CoreDNS: 2 Pod etcd: 1 Pod apiserver: 1 Pod controller-manager: 1 Pod scheduler: 1 Pod Calico Controller: 1 Pod All nodes: Calico Node: 1 Pod each Proxy: 1 Pod each Reference Container pause: article and artical . nerdctl","title":"Overview"},{"location":"k8s/cka_en/foundamentals/overview/#cluster-overview","text":"","title":"Cluster Overview"},{"location":"k8s/cka_en/foundamentals/overview/#contents","text":"Container Layer Kubernetes Layer Information: For environment setup, refer to Installation on Aliyun Ubuntu","title":"Contents"},{"location":"k8s/cka_en/foundamentals/overview/#container-layer","text":"Scenario: Use Containerd service to manage our images and containers via command nerdctl , which is same concept with Docker. Get namespace. Get containers. Get images. Get volumes. Get overall status. Get network status. Demo: Get namespaces. sudo nerdctl namespace ls Result NAME CONTAINERS IMAGES VOLUMES LABELS k8s.io 21 30 0 Get containers under specific namespace k8s.io . sudo nerdctl -n k8s.io ps Result CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0a3625f22f65 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk 121af2ecd1a1 registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll/coredns 49f6c7e3efe5 registry.aliyuncs.com/google_containers/kube-proxy:v1.24.0 \"/usr/local/bin/kube\u2026\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t/kube-proxy 4bba5fbd701d registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001 57d47b57eb12 docker.io/calico/node:v3.23.3 \"start_runit\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl/calico-node 5ce4c351a886 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/calico-node-w8nvl 6456eef784bf registry.aliyuncs.com/google_containers/kube-scheduler:v1.24.0 \"kube-scheduler --au\u2026\" 16 hours ago Up k8s://kube-system/kube-scheduler-cka001/kube-scheduler 6a687305871c registry.aliyuncs.com/google_containers/kube-apiserver:v1.24.0 \"kube-apiserver --ad\u2026\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001/kube-apiserver 7dcb24568574 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-c5mll a06b101118b8 registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001 a07ef8c3fc3a registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/etcd-cka001 b8566d3e4174 registry.aliyuncs.com/google_containers/kube-controller-manager:v1.24.0 \"kube-controller-man\u2026\" 16 hours ago Up k8s://kube-system/kube-controller-manager-cka001/kube-controller-manager ca6ac26314ff registry.aliyuncs.com/google_containers/coredns:v1.8.6 \"/coredns -conf /etc\u2026\" 16 hours ago Up k8s://kube-system/coredns-74586cf9b6-4jwmk/coredns cdc041b4791e registry.aliyuncs.com/google_containers/etcd:3.5.3-0 \"etcd --advertise-cl\u2026\" 16 hours ago Up k8s://kube-system/etcd-cka001/etcd e0c59abadf2e registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-proxy-dmj2t e0d2e5f6ccff registry.aliyuncs.com/google_containers/pause:3.6 \"/pause\" 16 hours ago Up k8s://kube-system/kube-apiserver-cka001 Get images. sudo nerdctl -n k8s.io image ls -a Get volumes. After inintial installation, no volume within namespaces. sudo nerdctl -n k8s.io volume ls Get overall status sudo nerdctl stats Get network status. sudo nerdctl network ls sudo nerdctl network inspect bridge sudo nerdctl network inspect k8s-pod-network Result NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none Get network interface in host cka001 with command ip addr list . IP pool of 10.4.0.1/24 is ipam and defined in /etc/cni/net.d/nerdctl-bridge.conflist . lo : inet 127.0.0.1/8 qlen 1000 eth0 : inet /24 brd xxx.xxx.xxx.255 scope global dynamic eth0 tunl0@NONE : inet 10.244.228.192/32 scope global tunl0 cali96e32d88db2@if4 : cali93613212490@if4 :","title":"Container Layer"},{"location":"k8s/cka_en/foundamentals/overview/#kubernetes-layer","text":"Scenario: Nodes Namespaces System Pods Demo: Information: In the demo, there are three nodes, cka001 , cka002 , and cka003 . Get nodes status. kubectl get node -o wide There are four initial namespaces across three nodes. kubectl get namespace -A Result NAME STATUS AGE default Active 56m kube-node-lease Active 56m kube-public Active 56m kube-system Active 56m There are some initial pods. kubectl get pod -A -o wide Result NAMESPACE NAME READY STATUS RESTARTS AGE NODE NOMINATED NODE READINESS GATES kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 15h cka003 kube-system calico-node-255pc 1/1 Running 0 15h cka003 kube-system calico-node-7tmnb 1/1 Running 0 15h cka002 kube-system calico-node-w8nvl 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15h cka001 kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15h cka001 kube-system etcd-cka001 1/1 Running 0 15h cka001 kube-system kube-apiserver-cka001 1/1 Running 0 15h cka001 kube-system kube-controller-manager-cka001 1/1 Running 0 15h cka001 kube-system kube-proxy-dmj2t 1/1 Running 0 15h cka001 kube-system kube-proxy-n77zw 1/1 Running 0 15h cka002 kube-system kube-proxy-qs6rf 1/1 Running 0 15h cka003 kube-system kube-scheduler-cka001 1/1 Running 0 15h cka001 Summary: Below shows the relationship between containers and pods. Master node: CoreDNS: 2 Pod etcd: 1 Pod apiserver: 1 Pod controller-manager: 1 Pod scheduler: 1 Pod Calico Controller: 1 Pod All nodes: Calico Node: 1 Pod each Proxy: 1 Pod each Reference Container pause: article and artical . nerdctl","title":"Kubernetes Layer"},{"location":"k8s/cka_en/foundamentals/persistence/","text":"Persistence \u00b6 Scenario Creat Pod with emptyDir type Volume. Container in the Pod will mount default directory /var/lib/kubelet/pods/ on running node. Create Deployment Deployment with hostPath type volume. Container in the Deployment will mount directory defined in hostPath: on running node. PV and PVC. Set up NFS Server and share folder /nfsdata/ . Create PV mysql-pv to link to the share folder /nfsdata/ and set StorageClassName nfs . Create PVC mysql-pvc mapped with StorageClassName nfs . Create Deployment mysql to consume PVC mysql-pvc . StorageClass Create ServiceAccount nfs-client-provisioner . Create ClusterRole nfs-client-provisioner-runner and Role leader-locking-nfs-client-provisioner and bind them to the ServiceAccount so the ServiceAccount has authorization to operate the Deployment created in next step. Create Deployment nfs-client-provisioner to to add connection information for your NFS server, e.g, PROVISIONER_NAME is k8s-sigs.io/ nfs-subdir-external-provisioner Create StorageClass nfs-client link to provisioner: k8s-sigs.io/nfs-subdir-external-provisioner . Releated PV is created automatically. Create PVC nfs-pvc-from-sc mapped to PV and StorageClass nfs-client . Configuration Create a ConfigMap for content of a file, and mount this ConfigMap to a specific file in a Pod. Create a ConfigMap for username and password, and consume them within a Pod. Use ConfigMap as environment variables in Pod. Tips Delete PVC first, then delete PV. If facing Terminating status when delete a PVC, use kubectl edit pvc and remove finalize: . emptyDir \u00b6 Create a Pod hello-producer with emptyDir type Volume. cat > pod-emptydir.yaml < /producer_dir/hello; sleep 30000 volumes: - name: shared-volume emptyDir: {} EOF kubectl apply -f pod-emptydir.yaml The Pod hello-producer is running on node cka003 . kubectl get pod hello-producer -owide The Pod is running on node cka003 . NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello-producer 1/1 Running 0 6s 10.244.102.24 cka003 Log onto cka003 because the Pod hello-producer is running on the node. Set up the environment CONTAINER_RUNTIME_ENDPOINT for command crictl . Suggest to do the same for all nodes. export CONTAINER_RUNTIME_ENDPOINT=unix:///run/containerd/containerd.sock Run command crictl ps to get the container ID of Pod hello-producer . crictl ps |grep hello-producer The ID of container producer is 05f5e1bb6a1bb . CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD 50058afb3cba5 62aedd01bd852 About an hour ago Running producer 0 e6953bd4833a7 hello-producer Run command crictl inspect to get the path of mounted shared-volume , which is emptyDir . crictl inspect 50058afb3cba5 | grep source | grep empty The result is below. \"source\": \"/var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume\", Change the path to the path of mounted shared-volume we get above. We will see the content hello world of file hello . cd /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume cat hello The path /producer_dir inside the Pod is mounted to the local host path /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume . The file /producer_dir/hello we created inside the Pod is actually in the host local path. Let's delete the container producer , the container producer will be started again with new container ID and the file hello is still there. crictl ps crictl stop crictl rm Let's delete the Pod hello-producer , the container producer is deleted, file hello is deleted. kubectl delete pod hello-producer hostPath \u00b6 Apply below yaml file to create a MySQL Pod and mount a hostPath . It'll mount host directory /tmp/mysql to Pod directory /var/lib/mysql . Check locally if directory /tmp/mysql is in place. If not, create it using mkdir /tmp/mysql . cat > mysql-hostpath.yaml < cka003 Attach into the MySQL Pod on the running node. kubectl exec -it -- bash Within the Pod, go to directory /var/lib/mysql , all files in the directory are same with all files in directory /tmp/mysql on node cka003 . Connect to the database in the Pod. mysql -h 127.0.0.1 -uroot -ppassword Operate the database. mysql> show databases; mysql> connect mysql; mysql> show tables; mysql> exit PV and PVC \u00b6 Here we will use NFS as backend storage to demo how to deploy PV and PVC. Set up NFS Share \u00b6 Install nfs-kernel-server Log onto cka002 . Choose one Worker cka002 to build NFS server. sudo apt-get install -y nfs-kernel-server Configure Share Folder Create share folder. mkdir /nfsdata Append one line in file /etc/exports . cat >> /etc/exports << EOF /nfsdata *(rw,sync,no_root_squash) EOF There are many different NFS sharing options, including these: * : accessable to all IPs, or specific IPs. rw : Share as read-write. Keep in mind that normal Linux permissions still apply. (Note that this is a default option.) ro : Share as read-only. sync : File data changes are made to disk immediately, which has an impact on performance, but is less likely to result in data loss. On som* `distributions this is the default. async : The opposite of sync; file data changes are made initially to memory. This speeds up performance but is more likely to result in data loss. O* `some distributions this is the default. root_squash : Map the root user and group account from the NFS client to the anonymous accounts, typically either the nobody account or the nfsnobod* `account. See the next section, \u201cUser ID Mapping,\u201d for more details. (Note that this is a default option.) no_root_squash : Map the root user and group account from the NFS client to the local root and group accounts. We will use password-free remote mount based on nfs and rpcbind services between Linux servers, not based on smb service. The two servers must first grant credit, install and set up nfs and rpcbind services on the server side, set the common directory, start the service, and mount it on the client Start rpcbind service. sudo systemctl enable rpcbind sudo systemctl restart rpcbind Start nfs service. sudo systemctl enable nfs-server sudo systemctl start nfs-server Once /etc/exports is changed, we need run below command to make change effected. exportfs -ra Result exportfs: /etc/exports [1]: Neither 'subtree_check' or 'no_subtree_check' specified for export \"*:/nfsdata\". Assuming default behaviour ('no_subtree_check'). NOTE: this default has changed since nfs-utils version 1.0.x Check whether sharefolder is configured. showmount -e And see below output. Export list for cka002: /nfsdata * Install NFS Client Install NFS client on all nodes. sudo apt-get install -y nfs-common Verify NFS Server Log onto any nodes to verify NFS service and sharefolder list. Log onto cka001 and check sharefolder status on cka002 . showmount -e cka002 Below result will be shown if no issues. Export list for cka002: /nfsdata * Mount NFS Execute below command to mount remote NFS folder on any other non-NFS-server node, e.g., cka001 or cka003 . mkdir /remote-nfs-dir mount -t nfs cka002:/nfsdata /remote-nfs-dir/ Use command df -h to verify mount point. Below is the sample output. Filesystem Size Used Avail Use% Mounted on cka002:/nfsdata 40G 5.8G 32G 16% /remote-nfs-dir Create PV \u00b6 Create a PV mysql-pv . Replace the NFS Server IP with actual IP (here is ) that NFS server cka002 is running on. kubectl apply -f - < EOF Check the PV. kubectl get pv The result: NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mysql-pv 1Gi RWO Retain Available nfs 19s Create PVC \u00b6 Create a PVC mysql-pvc and specify storage size, access mode, and storage class. The PVC mysql-pvc will be binded with PV automatically via storage class name. kubectl apply -f - < nfs-provisioner-rbac.yaml < ( cka002 ). Replace NFS server IP with actual IP (here is ) cat > nfs-provisioner-deployment.yaml < - name: NFS_PATH value: /nfsdata volumes: - name: nfs-client-root nfs: server: path: /nfsdata EOF kubectl apply -f nfs-provisioner-deployment.yaml Create NFS StorageClass \u00b6 Create StorageClass nfs-client . Define the NFS subdir external provisioner's Kubernetes Storage Class. vi nfs-storageclass.yaml And add below info to create NFS StorageClass. apiVersion : storage.k8s.io/v1 kind : StorageClass metadata : name : nfs-client annotations : storageclass.kubernetes.io/is-default-class : \"true\" provisioner : k8s-sigs.io/nfs-subdir-external-provisioner parameters : pathPattern : \"${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}\" onDelete : delete Apply the yaml file. kubectl apply -f nfs-storageclass.yaml Create PVC \u00b6 Create PVC nfs-pvc-from-sc . kubectl apply -f - < mysql-with-sc-pvc-7c97d875f8-wkvr9 1/1 Running 0 3m37s 10.244.102.27 cka003 Let's check directory /nfsdata/ on NFS server cka002 . ll /nfsdata/ Two folders were created. Same content of /remote-nfs-dir/ on other nodes. drwxrwxrwx 6 systemd-coredump root 4096 Jul 23 23:35 dev/ drwxr-xr-x 6 systemd-coredump root 4096 Jul 23 22:29 mysqldata/ Namespace name is used as folder name under directory /nfsdata/ and it is mounted to Pod. By default, namespace name will be used at mount point. If we want to use customized folder for that purpose, we need claim an annotation nfs.io/storage-path , e.g., below example. Create PVC test-claim on Namespace kube-system and consume volume nfs-client . kubectl apply -f - < ..data/password lrwxrwxrwx 1 root root 15 Jul 23 16:30 username -> ..data/username And we can get the content of each element, which are predefined before. / # cat /tmp/secret/username admin / # cat /tmp/secret/password 123456 Additional Cases \u00b6 Various way to create ConfigMap \u00b6 ConfigMap can be created by file, directory, or value. Let's create a ConfigMap colors includes: Four files with four color names. One file with favorite color name. mkdir configmap cd configmap mkdir primary echo c > primary/cyan echo m > primary/magenta echo y > primary/yellow echo k > primary/black echo \"known as key\" >> primary/black echo blue > favorite Final structure looks like below via command tree configmap . configmap \u251c\u2500\u2500 favorite \u2514\u2500\u2500 primary \u251c\u2500\u2500 black \u251c\u2500\u2500 cyan \u251c\u2500\u2500 magenta \u2514\u2500\u2500 yellow Create ConfigMap referring above files we created. Make sure we are now in the path ~/configmap . kubectl create configmap colors \\ --from-literal=text=black \\ --from-file=./favorite \\ --from-file=./primary/ Check content of the ConfigMap colors . kubectl get configmap colors -o yaml apiVersion : v1 data : black : | k known as key cyan : | c favorite : | blue magenta : | m text : black yellow : | y kind : ConfigMap metadata : creationTimestamp : \"2022-07-12T16:38:27Z\" name : colors namespace : dev resourceVersion : \"2377258\" uid : d5ab133f-5e4d-41d4-bc9e-2bbb22a872a1 Set environment variable via ConfigMap \u00b6 Here we will create a Pod pod-configmap-env and set the environment variable ilike and assign value of favorite from ConfigMap colors . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env spec: containers: - name: nginx image: nginx env: - name: ilike valueFrom: configMapKeyRef: name: colors key: favorite EOF Attach to the Pod pod-configmap-env . kubectl exec -it pod-configmap-env -- bash Verify the value of env variable ilike is blue , which is the value of favorite of ConfigMap colors . root@pod-configmap-env:/# echo $ ilike blue We can also use all key-value of ConfigMap to set up environment variables of Pod. kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env-2 spec: containers: - name: nginx image: nginx envFrom: - configMapRef: name: colors EOF Attach to the Pod pod-configmap-env-2 . kubectl exec -it pod-configmap-env-2 -- bash Verify the value of env variables based on key-values we defined in ConfigMap colors . root@pod-configmap-env-2:/# echo $ black k known as key root@pod-configmap-env-2:/# echo $ cyan c root@pod-configmap-env-2:/# echo $ favorite blue","title":"Persistence"},{"location":"k8s/cka_en/foundamentals/persistence/#persistence","text":"Scenario Creat Pod with emptyDir type Volume. Container in the Pod will mount default directory /var/lib/kubelet/pods/ on running node. Create Deployment Deployment with hostPath type volume. Container in the Deployment will mount directory defined in hostPath: on running node. PV and PVC. Set up NFS Server and share folder /nfsdata/ . Create PV mysql-pv to link to the share folder /nfsdata/ and set StorageClassName nfs . Create PVC mysql-pvc mapped with StorageClassName nfs . Create Deployment mysql to consume PVC mysql-pvc . StorageClass Create ServiceAccount nfs-client-provisioner . Create ClusterRole nfs-client-provisioner-runner and Role leader-locking-nfs-client-provisioner and bind them to the ServiceAccount so the ServiceAccount has authorization to operate the Deployment created in next step. Create Deployment nfs-client-provisioner to to add connection information for your NFS server, e.g, PROVISIONER_NAME is k8s-sigs.io/ nfs-subdir-external-provisioner Create StorageClass nfs-client link to provisioner: k8s-sigs.io/nfs-subdir-external-provisioner . Releated PV is created automatically. Create PVC nfs-pvc-from-sc mapped to PV and StorageClass nfs-client . Configuration Create a ConfigMap for content of a file, and mount this ConfigMap to a specific file in a Pod. Create a ConfigMap for username and password, and consume them within a Pod. Use ConfigMap as environment variables in Pod. Tips Delete PVC first, then delete PV. If facing Terminating status when delete a PVC, use kubectl edit pvc and remove finalize: .","title":"Persistence"},{"location":"k8s/cka_en/foundamentals/persistence/#emptydir","text":"Create a Pod hello-producer with emptyDir type Volume. cat > pod-emptydir.yaml < /producer_dir/hello; sleep 30000 volumes: - name: shared-volume emptyDir: {} EOF kubectl apply -f pod-emptydir.yaml The Pod hello-producer is running on node cka003 . kubectl get pod hello-producer -owide The Pod is running on node cka003 . NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES hello-producer 1/1 Running 0 6s 10.244.102.24 cka003 Log onto cka003 because the Pod hello-producer is running on the node. Set up the environment CONTAINER_RUNTIME_ENDPOINT for command crictl . Suggest to do the same for all nodes. export CONTAINER_RUNTIME_ENDPOINT=unix:///run/containerd/containerd.sock Run command crictl ps to get the container ID of Pod hello-producer . crictl ps |grep hello-producer The ID of container producer is 05f5e1bb6a1bb . CONTAINER IMAGE CREATED STATE NAME ATTEMPT POD ID POD 50058afb3cba5 62aedd01bd852 About an hour ago Running producer 0 e6953bd4833a7 hello-producer Run command crictl inspect to get the path of mounted shared-volume , which is emptyDir . crictl inspect 50058afb3cba5 | grep source | grep empty The result is below. \"source\": \"/var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume\", Change the path to the path of mounted shared-volume we get above. We will see the content hello world of file hello . cd /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume cat hello The path /producer_dir inside the Pod is mounted to the local host path /var/lib/kubelet/pods/d7424f86-534a-48f9-9001-9d2a6e822b12/volumes/kubernetes.io~empty-dir/shared-volume . The file /producer_dir/hello we created inside the Pod is actually in the host local path. Let's delete the container producer , the container producer will be started again with new container ID and the file hello is still there. crictl ps crictl stop crictl rm Let's delete the Pod hello-producer , the container producer is deleted, file hello is deleted. kubectl delete pod hello-producer","title":"emptyDir"},{"location":"k8s/cka_en/foundamentals/persistence/#hostpath","text":"Apply below yaml file to create a MySQL Pod and mount a hostPath . It'll mount host directory /tmp/mysql to Pod directory /var/lib/mysql . Check locally if directory /tmp/mysql is in place. If not, create it using mkdir /tmp/mysql . cat > mysql-hostpath.yaml < cka003 Attach into the MySQL Pod on the running node. kubectl exec -it -- bash Within the Pod, go to directory /var/lib/mysql , all files in the directory are same with all files in directory /tmp/mysql on node cka003 . Connect to the database in the Pod. mysql -h 127.0.0.1 -uroot -ppassword Operate the database. mysql> show databases; mysql> connect mysql; mysql> show tables; mysql> exit","title":"hostPath"},{"location":"k8s/cka_en/foundamentals/persistence/#pv-and-pvc","text":"Here we will use NFS as backend storage to demo how to deploy PV and PVC.","title":"PV and PVC"},{"location":"k8s/cka_en/foundamentals/persistence/#set-up-nfs-share","text":"Install nfs-kernel-server Log onto cka002 . Choose one Worker cka002 to build NFS server. sudo apt-get install -y nfs-kernel-server Configure Share Folder Create share folder. mkdir /nfsdata Append one line in file /etc/exports . cat >> /etc/exports << EOF /nfsdata *(rw,sync,no_root_squash) EOF There are many different NFS sharing options, including these: * : accessable to all IPs, or specific IPs. rw : Share as read-write. Keep in mind that normal Linux permissions still apply. (Note that this is a default option.) ro : Share as read-only. sync : File data changes are made to disk immediately, which has an impact on performance, but is less likely to result in data loss. On som* `distributions this is the default. async : The opposite of sync; file data changes are made initially to memory. This speeds up performance but is more likely to result in data loss. O* `some distributions this is the default. root_squash : Map the root user and group account from the NFS client to the anonymous accounts, typically either the nobody account or the nfsnobod* `account. See the next section, \u201cUser ID Mapping,\u201d for more details. (Note that this is a default option.) no_root_squash : Map the root user and group account from the NFS client to the local root and group accounts. We will use password-free remote mount based on nfs and rpcbind services between Linux servers, not based on smb service. The two servers must first grant credit, install and set up nfs and rpcbind services on the server side, set the common directory, start the service, and mount it on the client Start rpcbind service. sudo systemctl enable rpcbind sudo systemctl restart rpcbind Start nfs service. sudo systemctl enable nfs-server sudo systemctl start nfs-server Once /etc/exports is changed, we need run below command to make change effected. exportfs -ra Result exportfs: /etc/exports [1]: Neither 'subtree_check' or 'no_subtree_check' specified for export \"*:/nfsdata\". Assuming default behaviour ('no_subtree_check'). NOTE: this default has changed since nfs-utils version 1.0.x Check whether sharefolder is configured. showmount -e And see below output. Export list for cka002: /nfsdata * Install NFS Client Install NFS client on all nodes. sudo apt-get install -y nfs-common Verify NFS Server Log onto any nodes to verify NFS service and sharefolder list. Log onto cka001 and check sharefolder status on cka002 . showmount -e cka002 Below result will be shown if no issues. Export list for cka002: /nfsdata * Mount NFS Execute below command to mount remote NFS folder on any other non-NFS-server node, e.g., cka001 or cka003 . mkdir /remote-nfs-dir mount -t nfs cka002:/nfsdata /remote-nfs-dir/ Use command df -h to verify mount point. Below is the sample output. Filesystem Size Used Avail Use% Mounted on cka002:/nfsdata 40G 5.8G 32G 16% /remote-nfs-dir","title":"Set up NFS Share"},{"location":"k8s/cka_en/foundamentals/persistence/#create-pv","text":"Create a PV mysql-pv . Replace the NFS Server IP with actual IP (here is ) that NFS server cka002 is running on. kubectl apply -f - < EOF Check the PV. kubectl get pv The result: NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mysql-pv 1Gi RWO Retain Available nfs 19s","title":"Create PV"},{"location":"k8s/cka_en/foundamentals/persistence/#create-pvc","text":"Create a PVC mysql-pvc and specify storage size, access mode, and storage class. The PVC mysql-pvc will be binded with PV automatically via storage class name. kubectl apply -f - < nfs-provisioner-rbac.yaml < ( cka002 ). Replace NFS server IP with actual IP (here is ) cat > nfs-provisioner-deployment.yaml < - name: NFS_PATH value: /nfsdata volumes: - name: nfs-client-root nfs: server: path: /nfsdata EOF kubectl apply -f nfs-provisioner-deployment.yaml","title":"Create Provisioner's Deloyment"},{"location":"k8s/cka_en/foundamentals/persistence/#create-nfs-storageclass","text":"Create StorageClass nfs-client . Define the NFS subdir external provisioner's Kubernetes Storage Class. vi nfs-storageclass.yaml And add below info to create NFS StorageClass. apiVersion : storage.k8s.io/v1 kind : StorageClass metadata : name : nfs-client annotations : storageclass.kubernetes.io/is-default-class : \"true\" provisioner : k8s-sigs.io/nfs-subdir-external-provisioner parameters : pathPattern : \"${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}\" onDelete : delete Apply the yaml file. kubectl apply -f nfs-storageclass.yaml","title":"Create NFS StorageClass"},{"location":"k8s/cka_en/foundamentals/persistence/#create-pvc_1","text":"Create PVC nfs-pvc-from-sc . kubectl apply -f - < mysql-with-sc-pvc-7c97d875f8-wkvr9 1/1 Running 0 3m37s 10.244.102.27 cka003 Let's check directory /nfsdata/ on NFS server cka002 . ll /nfsdata/ Two folders were created. Same content of /remote-nfs-dir/ on other nodes. drwxrwxrwx 6 systemd-coredump root 4096 Jul 23 23:35 dev/ drwxr-xr-x 6 systemd-coredump root 4096 Jul 23 22:29 mysqldata/ Namespace name is used as folder name under directory /nfsdata/ and it is mounted to Pod. By default, namespace name will be used at mount point. If we want to use customized folder for that purpose, we need claim an annotation nfs.io/storage-path , e.g., below example. Create PVC test-claim on Namespace kube-system and consume volume nfs-client . kubectl apply -f - < ..data/password lrwxrwxrwx 1 root root 15 Jul 23 16:30 username -> ..data/username And we can get the content of each element, which are predefined before. / # cat /tmp/secret/username admin / # cat /tmp/secret/password 123456","title":"Secret"},{"location":"k8s/cka_en/foundamentals/persistence/#additional-cases","text":"","title":"Additional Cases"},{"location":"k8s/cka_en/foundamentals/persistence/#various-way-to-create-configmap","text":"ConfigMap can be created by file, directory, or value. Let's create a ConfigMap colors includes: Four files with four color names. One file with favorite color name. mkdir configmap cd configmap mkdir primary echo c > primary/cyan echo m > primary/magenta echo y > primary/yellow echo k > primary/black echo \"known as key\" >> primary/black echo blue > favorite Final structure looks like below via command tree configmap . configmap \u251c\u2500\u2500 favorite \u2514\u2500\u2500 primary \u251c\u2500\u2500 black \u251c\u2500\u2500 cyan \u251c\u2500\u2500 magenta \u2514\u2500\u2500 yellow Create ConfigMap referring above files we created. Make sure we are now in the path ~/configmap . kubectl create configmap colors \\ --from-literal=text=black \\ --from-file=./favorite \\ --from-file=./primary/ Check content of the ConfigMap colors . kubectl get configmap colors -o yaml apiVersion : v1 data : black : | k known as key cyan : | c favorite : | blue magenta : | m text : black yellow : | y kind : ConfigMap metadata : creationTimestamp : \"2022-07-12T16:38:27Z\" name : colors namespace : dev resourceVersion : \"2377258\" uid : d5ab133f-5e4d-41d4-bc9e-2bbb22a872a1","title":"Various way to create ConfigMap"},{"location":"k8s/cka_en/foundamentals/persistence/#set-environment-variable-via-configmap","text":"Here we will create a Pod pod-configmap-env and set the environment variable ilike and assign value of favorite from ConfigMap colors . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env spec: containers: - name: nginx image: nginx env: - name: ilike valueFrom: configMapKeyRef: name: colors key: favorite EOF Attach to the Pod pod-configmap-env . kubectl exec -it pod-configmap-env -- bash Verify the value of env variable ilike is blue , which is the value of favorite of ConfigMap colors . root@pod-configmap-env:/# echo $ ilike blue We can also use all key-value of ConfigMap to set up environment variables of Pod. kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: pod-configmap-env-2 spec: containers: - name: nginx image: nginx envFrom: - configMapRef: name: colors EOF Attach to the Pod pod-configmap-env-2 . kubectl exec -it pod-configmap-env-2 -- bash Verify the value of env variables based on key-values we defined in ConfigMap colors . root@pod-configmap-env-2:/# echo $ black k known as key root@pod-configmap-env-2:/# echo $ cyan c root@pod-configmap-env-2:/# echo $ favorite blue","title":"Set environment variable via ConfigMap"},{"location":"k8s/cka_en/foundamentals/pod/","text":"Work on pod \u00b6 Create pod \u00b6 Create pod my-first-podl . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-first-pod spec: containers: - name: nginx image: nginx:mainline ports: - containerPort: 80 EOF Verify status of the pod just created. kubectl get pods -o wide Track pod \u00b6 Check logs of the pod just created. kubectl logs my-first-pod In case logs or describe or any other of the output generating commands don't help us to get to the root cause of an issue, we can use use kubectl exec -it -- bash command to look into it ourselves. kubectl exec -it my-first-pod -- bash root@my-first-pod:/# ls root@my-first-pod:/# cd bin root@my-first-pod:/bin# ls root@my-first-pod:/bin# exit Execute command kubectl explain pod.spec will get details of Spec segment of Pod kind in yaml file. We can check the official API reference of the pod resource for help or use kubectl explain pod to get a command-line based description of the resource. By appending . to the resource type, the explain command will provide more details on the specified field. kubectl explain pod.kind kubectl explain pod.spec kubectl explain pod.spec.containers kubectl explain pod.spec.containers.name Label pod \u00b6 Get pod's label with option --show-labels . kubectl get pods kubectl get pods --show-labels Add two labels to the pod pod my-first-pod . kubectl label pod my-first-pod nginx=mainline kubectl label pod my-first-pod env=demo kubectl get pods --show-labels Search pod by labels. kubectl get pod -l env=demo kubectl get pod -l env=demo,nginx=mainline kubectl get pod -l env=training Remove label kubectl label pods my-first-pod env- kubectl get pods --show-labels Describe pod. kubectl describe pod my-first-pod Delete pod. Run watch kubectl get pods to monitor the pod status. kubectl delete pod my-first-pod watch kubectl get pods Static Pod \u00b6 Scenario *Create a static pod. * kubectl will automatically check yaml file in /etc/kubernetes/manifests/ and create the static pod once it's detected. Demo: Some system static Pods are already in place. ll /etc/kubernetes/manifests/ Result -rw------- 1 root root 2292 Jul 23 10:45 etcd.yaml -rw------- 1 root root 3889 Jul 23 10:45 kube-apiserver.yaml -rw------- 1 root root 3395 Jul 23 10:45 kube-controller-manager.yaml -rw------- 1 root root 1464 Jul 23 10:45 kube-scheduler.yaml Create yaml file my-nginx.yaml in directory /etc/kubernetes/manifests/ . Once the file is created, the static pod my-nginx is created automatically. kubectl run my-nginx --image=nginx:mainline --dry-run=client -n default -oyaml | sudo tee /etc/kubernetes/manifests/my-nginx.yaml Check status of the Pod my-nginx . The node name cka001 is part of the Pod name, which means the Pod is running on node cka001 . kubectl get pod -o wide Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cka001 1/1 Running 0 20s 10.244.228.196 cka001 Delete the yaml file /etc/kubernetes/manifests/my-nginx.yaml , the static pod will be deleted automatically. sudo rm /etc/kubernetes/manifests/my-nginx.yaml Multi-Container Pod \u00b6 Scenario: Create Multi-Container Pod Describe the Pod Check the log of Pod Check the log of Containers Create a Pod multi-container-pod with multiple container container-1-nginx and container-2-alpine . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: multi-container-pod spec: containers: - name: container-1-nginx image: nginx ports: - containerPort: 80 - name: container-2-alpine image: alpine command: [\"watch\", \"wget\", \"-qO-\", \"localhost\"] EOF Get the status. kubectl get pod multi-container-pod Result NAME READY STATUS RESTARTS AGE multi-container-pod 2/2 Running 0 81s Get details of the pod. kubectl describe pod multi-container-pod Result ....... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 41s default-scheduler Successfully assigned dev/multi-container-pod to cka002 Normal Pulling 40s kubelet Pulling image \"nginx\" Normal Pulled 23s kubelet Successfully pulled image \"nginx\" in 16.767129903s Normal Created 22s kubelet Created container container-1-nginx Normal Started 22s kubelet Started container container-1-nginx Normal Pulling 22s kubelet Pulling image \"alpine\" Normal Pulled 14s kubelet Successfully pulled image \"alpine\" in 7.776104353s Normal Created 14s kubelet Created container container-2-alpine Normal Started 14s kubelet Started container container-2-alpine For multi-container pod, container name is needed if we want to get log of pod via command kubectl logs . Without the container name, we receive error. kubectl logs multi-container-pod Result error: a container name must be specified for pod multi-container-pod, choose one of: [container-1-nginx container-2-alpine] With specified container name, we get the log info. kubectl logs multi-container-pod container-1-nginx Result ...... ::1 - - [23/Jul/2022:04:06:37 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"Wget\" \"-\" Same if we need specify container name to login into the pod via command kubectl exec -it -c -- . kubectl exec -it multi-container-pod -c container-1-nginx -- /bin/bash root@multi-container-pod:/# ls Clean up kubectl delete pod multi-container-pod Quick reference of a simple yaml file to create Multiple Containers. kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-multi-pod spec: containers: - image: nginx name: nginx - image: memcached name: memcached - image: redis name: redis EOF Scenario: Create a Pod my-busybox with a container container-1-busybox . The container will write message to file /var/log/my-pod-busybox.log . Add another container container-2-busybox (Sidecar) to the Pod my-busybox . The sidecar container read message from file /var/log/my-pod-busybox.log . Tips: create a Volume to store the log file, which is shared with two containers. Demo: Create a Pod my-busybox with a container container-1-busybox . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-busybox spec: containers: - name: container-1-busybox image: busybox args: - /bin/sh - -c - > i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=$((i+1)); sleep 1; done EOF Search emptyDir in the Kubernetes documetation. Refer to below template for emptyDir via https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/ Add below new features into the Pod Volume: volume name: logfile type: emptyDir Update existing container: name: container-1-busybox volumeMounts name: logfile mounthPath: /var/log Add new container: name: container-2-busybox image: busybox args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log'] volumeMounts: name: logfile mountPath: /var/log kubectl get pod my-busybox -o yaml > my-busybox.yaml vi my-busybox.yaml kubectl delete pod my-busybox kubectl apply -f my-busybox.yaml kubectl logs my-busybox -c container-2-busybox The final file my-busybox.yaml looks like below. apiVersion: v1 kind: Pod metadata: annotations: cni.projectcalico.org/containerID: 89644b6b073cd152f94b4cae7bdea6bbc3292cf59afd4f28102bd74f0205c9e4 cni.projectcalico.org/podIP: 10.244.102.20/32 cni.projectcalico.org/podIPs: 10.244.102.20/32 kubectl.kubernetes.io/last-applied-configuration: | {\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"my-busybox\",\"namespace\":\"dev\"},\"spec\":{\"containers\":[{\"args\":[\"/bin/sh\",\"-c\",\"i=0; while true; do\\n echo \\\"Hello message from container-1: \\\" \\u003e\\u003e /var/log/my-pod-busybox.log;\\n i=1;\\n sleep 1;\\ndone\\n\"],\"image\":\"busybox\",\"name\":\"container-1-busybox\"}]}} creationTimestamp: \"2022-07-29T22:58:27Z\" name: my-busybox namespace: dev resourceVersion: \"1185720\" uid: c5e62a16-4459-4828-a441-7d1471b89a56 spec: containers: - name: container-2-busybox image: busybox args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log'] volumeMounts: - name: logfile mountPath: /var/log - args: - /bin/sh - -c - | i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=1; sleep 1; done image: busybox imagePullPolicy: Always name: container-1-busybox resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - name: logfile mountPath: /var/log - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: kube-api-access-mhxlf readOnly: true dnsPolicy: ClusterFirst enableServiceLinks: true nodeName: cka003 preemptionPolicy: PreemptLowerPriority priority: 0 restartPolicy: Always schedulerName: default-scheduler securityContext: {} serviceAccount: default serviceAccountName: default terminationGracePeriodSeconds: 30 tolerations: - effect: NoExecute key: node.kubernetes.io/not-ready operator: Exists tolerationSeconds: 300 - effect: NoExecute key: node.kubernetes.io/unreachable operator: Exists tolerationSeconds: 300 volumes: - name: logfile emptyDir: {} - name: kube-api-access-mhxlf projected: defaultMode: 420 sources: - serviceAccountToken: expirationSeconds: 3607 path: token - configMap: items: - key: ca.crt path: ca.crt name: kube-root-ca.crt - downwardAPI: items: - fieldRef: apiVersion: v1 fieldPath: metadata.namespace path: namespace status: conditions: - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:27Z\" status: \"True\" type: Initialized - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:30Z\" status: \"True\" type: Ready - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:30Z\" status: \"True\" type: ContainersReady - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:27Z\" status: \"True\" type: PodScheduled containerStatuses: - containerID: containerd://fd42d4ba4d94d8918d8846327b1db2328be13c5f93f381877ff0228ed7b5468d image: docker.io/library/busybox:latest imageID: docker.io/library/busybox@sha256:0e97a8ca6955f22dbc7db9e9dbe970971f423541e52c34b8cb96ccc88d6a3883 lastState: {} name: container-1-busybox ready: true restartCount: 0 started: true state: running: startedAt: \"2022-07-29T22:58:30Z\" hostIP: phase: Running podIP: 10.244.102.20 podIPs: - ip: 10.244.102.20 qosClass: BestEffort startTime: \"2022-07-29T22:58:27Z\" Clean up: kubectl delete pod my-busybox initContainer Pod \u00b6 Scenario: Create Pod myapp-pod that has two init containers. myapp-container init-mydb Create two Services. myservice mydb Conclusion: myapp-container waits for Service myservice up in order to resolve the name myservice.dev.svc.cluster.local init-mydb waits for Service mydb up in order to resolve the name mydb.dev.svc.cluster.local . Demo: Create Pod myapp-pod with below yaml file. Create yaml file myapp-pod.yaml and add below content. Note: Due to the command $(cat /var/..... will be treated as host variable, we can not use echo to generate the file. It's the variabel in container itself. vi myapp-pod.yaml Content apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp spec: containers: - name: myapp-container image: busybox:1.28 command: ['sh', '-c', 'echo The app is running! && sleep 3600'] initContainers: - name: init-myservice image: busybox:1.28 command: ['sh', '-c', \"until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done\"] - name: init-mydb image: busybox:1.28 command: ['sh', '-c', \"until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done\"] Apply the yaml file to create the Pod. kubectl apply -f myapp-pod.yaml Check Pod status. kubectl get pod myapp-pod Result NAME READY STATUS RESTARTS AGE myapp-pod 0/1 Init:0/2 0 12m Inspect Pods. Get two errors: nslookup: can't resolve 'myservice.dev.svc.cluster.local' container \"init-mydb\" in pod \"myapp-pod\" is waiting to start: PodInitializing kubectl logs myapp-pod -c init-myservice # Inspect the first init container kubectl logs myapp-pod -c init-mydb # Inspect the second init container At this point, those init containers will be waiting to discover Services named mydb and myservice. Create the mydb and myservice services: kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: myservice spec: ports: - protocol: TCP port: 80 targetPort: 9376 --- apiVersion: v1 kind: Service metadata: name: mydb spec: ports: - protocol: TCP port: 80 targetPort: 9377 EOF Get current status of Services. kubectl get service Both of Services are up. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mydb ClusterIP 11.244.239.149 80/TCP 6s myservice ClusterIP 11.244.116.126 80/TCP 6s Get current Pod status. kubectl get pod myapp-pod -o wide The Pod is up. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-pod 0/1 Init:0/2 0 2m40s 10.244.112.2 cka002 We now see that those init containers complete, and that the myapp-pod Pod moves into the Running state. Clean up. kubectl delete service mydb myservice kubectl delete pod myapp-pod References: Pod basics Lifecycle & phases Kubernetes pod design pattern","title":"Pod"},{"location":"k8s/cka_en/foundamentals/pod/#work-on-pod","text":"","title":"Work on pod"},{"location":"k8s/cka_en/foundamentals/pod/#create-pod","text":"Create pod my-first-podl . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-first-pod spec: containers: - name: nginx image: nginx:mainline ports: - containerPort: 80 EOF Verify status of the pod just created. kubectl get pods -o wide","title":"Create pod"},{"location":"k8s/cka_en/foundamentals/pod/#track-pod","text":"Check logs of the pod just created. kubectl logs my-first-pod In case logs or describe or any other of the output generating commands don't help us to get to the root cause of an issue, we can use use kubectl exec -it -- bash command to look into it ourselves. kubectl exec -it my-first-pod -- bash root@my-first-pod:/# ls root@my-first-pod:/# cd bin root@my-first-pod:/bin# ls root@my-first-pod:/bin# exit Execute command kubectl explain pod.spec will get details of Spec segment of Pod kind in yaml file. We can check the official API reference of the pod resource for help or use kubectl explain pod to get a command-line based description of the resource. By appending . to the resource type, the explain command will provide more details on the specified field. kubectl explain pod.kind kubectl explain pod.spec kubectl explain pod.spec.containers kubectl explain pod.spec.containers.name","title":"Track pod"},{"location":"k8s/cka_en/foundamentals/pod/#label-pod","text":"Get pod's label with option --show-labels . kubectl get pods kubectl get pods --show-labels Add two labels to the pod pod my-first-pod . kubectl label pod my-first-pod nginx=mainline kubectl label pod my-first-pod env=demo kubectl get pods --show-labels Search pod by labels. kubectl get pod -l env=demo kubectl get pod -l env=demo,nginx=mainline kubectl get pod -l env=training Remove label kubectl label pods my-first-pod env- kubectl get pods --show-labels Describe pod. kubectl describe pod my-first-pod Delete pod. Run watch kubectl get pods to monitor the pod status. kubectl delete pod my-first-pod watch kubectl get pods","title":"Label pod"},{"location":"k8s/cka_en/foundamentals/pod/#static-pod","text":"Scenario *Create a static pod. * kubectl will automatically check yaml file in /etc/kubernetes/manifests/ and create the static pod once it's detected. Demo: Some system static Pods are already in place. ll /etc/kubernetes/manifests/ Result -rw------- 1 root root 2292 Jul 23 10:45 etcd.yaml -rw------- 1 root root 3889 Jul 23 10:45 kube-apiserver.yaml -rw------- 1 root root 3395 Jul 23 10:45 kube-controller-manager.yaml -rw------- 1 root root 1464 Jul 23 10:45 kube-scheduler.yaml Create yaml file my-nginx.yaml in directory /etc/kubernetes/manifests/ . Once the file is created, the static pod my-nginx is created automatically. kubectl run my-nginx --image=nginx:mainline --dry-run=client -n default -oyaml | sudo tee /etc/kubernetes/manifests/my-nginx.yaml Check status of the Pod my-nginx . The node name cka001 is part of the Pod name, which means the Pod is running on node cka001 . kubectl get pod -o wide Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cka001 1/1 Running 0 20s 10.244.228.196 cka001 Delete the yaml file /etc/kubernetes/manifests/my-nginx.yaml , the static pod will be deleted automatically. sudo rm /etc/kubernetes/manifests/my-nginx.yaml","title":"Static Pod"},{"location":"k8s/cka_en/foundamentals/pod/#multi-container-pod","text":"Scenario: Create Multi-Container Pod Describe the Pod Check the log of Pod Check the log of Containers Create a Pod multi-container-pod with multiple container container-1-nginx and container-2-alpine . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: multi-container-pod spec: containers: - name: container-1-nginx image: nginx ports: - containerPort: 80 - name: container-2-alpine image: alpine command: [\"watch\", \"wget\", \"-qO-\", \"localhost\"] EOF Get the status. kubectl get pod multi-container-pod Result NAME READY STATUS RESTARTS AGE multi-container-pod 2/2 Running 0 81s Get details of the pod. kubectl describe pod multi-container-pod Result ....... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 41s default-scheduler Successfully assigned dev/multi-container-pod to cka002 Normal Pulling 40s kubelet Pulling image \"nginx\" Normal Pulled 23s kubelet Successfully pulled image \"nginx\" in 16.767129903s Normal Created 22s kubelet Created container container-1-nginx Normal Started 22s kubelet Started container container-1-nginx Normal Pulling 22s kubelet Pulling image \"alpine\" Normal Pulled 14s kubelet Successfully pulled image \"alpine\" in 7.776104353s Normal Created 14s kubelet Created container container-2-alpine Normal Started 14s kubelet Started container container-2-alpine For multi-container pod, container name is needed if we want to get log of pod via command kubectl logs . Without the container name, we receive error. kubectl logs multi-container-pod Result error: a container name must be specified for pod multi-container-pod, choose one of: [container-1-nginx container-2-alpine] With specified container name, we get the log info. kubectl logs multi-container-pod container-1-nginx Result ...... ::1 - - [23/Jul/2022:04:06:37 +0000] \"GET / HTTP/1.1\" 200 615 \"-\" \"Wget\" \"-\" Same if we need specify container name to login into the pod via command kubectl exec -it -c -- . kubectl exec -it multi-container-pod -c container-1-nginx -- /bin/bash root@multi-container-pod:/# ls Clean up kubectl delete pod multi-container-pod Quick reference of a simple yaml file to create Multiple Containers. kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-multi-pod spec: containers: - image: nginx name: nginx - image: memcached name: memcached - image: redis name: redis EOF Scenario: Create a Pod my-busybox with a container container-1-busybox . The container will write message to file /var/log/my-pod-busybox.log . Add another container container-2-busybox (Sidecar) to the Pod my-busybox . The sidecar container read message from file /var/log/my-pod-busybox.log . Tips: create a Volume to store the log file, which is shared with two containers. Demo: Create a Pod my-busybox with a container container-1-busybox . kubectl apply -f - << EOF apiVersion: v1 kind: Pod metadata: name: my-busybox spec: containers: - name: container-1-busybox image: busybox args: - /bin/sh - -c - > i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=$((i+1)); sleep 1; done EOF Search emptyDir in the Kubernetes documetation. Refer to below template for emptyDir via https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/ Add below new features into the Pod Volume: volume name: logfile type: emptyDir Update existing container: name: container-1-busybox volumeMounts name: logfile mounthPath: /var/log Add new container: name: container-2-busybox image: busybox args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log'] volumeMounts: name: logfile mountPath: /var/log kubectl get pod my-busybox -o yaml > my-busybox.yaml vi my-busybox.yaml kubectl delete pod my-busybox kubectl apply -f my-busybox.yaml kubectl logs my-busybox -c container-2-busybox The final file my-busybox.yaml looks like below. apiVersion: v1 kind: Pod metadata: annotations: cni.projectcalico.org/containerID: 89644b6b073cd152f94b4cae7bdea6bbc3292cf59afd4f28102bd74f0205c9e4 cni.projectcalico.org/podIP: 10.244.102.20/32 cni.projectcalico.org/podIPs: 10.244.102.20/32 kubectl.kubernetes.io/last-applied-configuration: | {\"apiVersion\":\"v1\",\"kind\":\"Pod\",\"metadata\":{\"annotations\":{},\"name\":\"my-busybox\",\"namespace\":\"dev\"},\"spec\":{\"containers\":[{\"args\":[\"/bin/sh\",\"-c\",\"i=0; while true; do\\n echo \\\"Hello message from container-1: \\\" \\u003e\\u003e /var/log/my-pod-busybox.log;\\n i=1;\\n sleep 1;\\ndone\\n\"],\"image\":\"busybox\",\"name\":\"container-1-busybox\"}]}} creationTimestamp: \"2022-07-29T22:58:27Z\" name: my-busybox namespace: dev resourceVersion: \"1185720\" uid: c5e62a16-4459-4828-a441-7d1471b89a56 spec: containers: - name: container-2-busybox image: busybox args: ['/bin/sh', '-c', 'tail -n+1 -f /var/log/my-pod-busybox.log'] volumeMounts: - name: logfile mountPath: /var/log - args: - /bin/sh - -c - | i=0; while true; do echo \"Hello message from container-1: $i\" >> /var/log/my-pod-busybox.log; i=1; sleep 1; done image: busybox imagePullPolicy: Always name: container-1-busybox resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - name: logfile mountPath: /var/log - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: kube-api-access-mhxlf readOnly: true dnsPolicy: ClusterFirst enableServiceLinks: true nodeName: cka003 preemptionPolicy: PreemptLowerPriority priority: 0 restartPolicy: Always schedulerName: default-scheduler securityContext: {} serviceAccount: default serviceAccountName: default terminationGracePeriodSeconds: 30 tolerations: - effect: NoExecute key: node.kubernetes.io/not-ready operator: Exists tolerationSeconds: 300 - effect: NoExecute key: node.kubernetes.io/unreachable operator: Exists tolerationSeconds: 300 volumes: - name: logfile emptyDir: {} - name: kube-api-access-mhxlf projected: defaultMode: 420 sources: - serviceAccountToken: expirationSeconds: 3607 path: token - configMap: items: - key: ca.crt path: ca.crt name: kube-root-ca.crt - downwardAPI: items: - fieldRef: apiVersion: v1 fieldPath: metadata.namespace path: namespace status: conditions: - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:27Z\" status: \"True\" type: Initialized - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:30Z\" status: \"True\" type: Ready - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:30Z\" status: \"True\" type: ContainersReady - lastProbeTime: null lastTransitionTime: \"2022-07-29T22:58:27Z\" status: \"True\" type: PodScheduled containerStatuses: - containerID: containerd://fd42d4ba4d94d8918d8846327b1db2328be13c5f93f381877ff0228ed7b5468d image: docker.io/library/busybox:latest imageID: docker.io/library/busybox@sha256:0e97a8ca6955f22dbc7db9e9dbe970971f423541e52c34b8cb96ccc88d6a3883 lastState: {} name: container-1-busybox ready: true restartCount: 0 started: true state: running: startedAt: \"2022-07-29T22:58:30Z\" hostIP: phase: Running podIP: 10.244.102.20 podIPs: - ip: 10.244.102.20 qosClass: BestEffort startTime: \"2022-07-29T22:58:27Z\" Clean up: kubectl delete pod my-busybox","title":"Multi-Container Pod"},{"location":"k8s/cka_en/foundamentals/pod/#initcontainer-pod","text":"Scenario: Create Pod myapp-pod that has two init containers. myapp-container init-mydb Create two Services. myservice mydb Conclusion: myapp-container waits for Service myservice up in order to resolve the name myservice.dev.svc.cluster.local init-mydb waits for Service mydb up in order to resolve the name mydb.dev.svc.cluster.local . Demo: Create Pod myapp-pod with below yaml file. Create yaml file myapp-pod.yaml and add below content. Note: Due to the command $(cat /var/..... will be treated as host variable, we can not use echo to generate the file. It's the variabel in container itself. vi myapp-pod.yaml Content apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp spec: containers: - name: myapp-container image: busybox:1.28 command: ['sh', '-c', 'echo The app is running! && sleep 3600'] initContainers: - name: init-myservice image: busybox:1.28 command: ['sh', '-c', \"until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done\"] - name: init-mydb image: busybox:1.28 command: ['sh', '-c', \"until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done\"] Apply the yaml file to create the Pod. kubectl apply -f myapp-pod.yaml Check Pod status. kubectl get pod myapp-pod Result NAME READY STATUS RESTARTS AGE myapp-pod 0/1 Init:0/2 0 12m Inspect Pods. Get two errors: nslookup: can't resolve 'myservice.dev.svc.cluster.local' container \"init-mydb\" in pod \"myapp-pod\" is waiting to start: PodInitializing kubectl logs myapp-pod -c init-myservice # Inspect the first init container kubectl logs myapp-pod -c init-mydb # Inspect the second init container At this point, those init containers will be waiting to discover Services named mydb and myservice. Create the mydb and myservice services: kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: myservice spec: ports: - protocol: TCP port: 80 targetPort: 9376 --- apiVersion: v1 kind: Service metadata: name: mydb spec: ports: - protocol: TCP port: 80 targetPort: 9377 EOF Get current status of Services. kubectl get service Both of Services are up. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mydb ClusterIP 11.244.239.149 80/TCP 6s myservice ClusterIP 11.244.116.126 80/TCP 6s Get current Pod status. kubectl get pod myapp-pod -o wide The Pod is up. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-pod 0/1 Init:0/2 0 2m40s 10.244.112.2 cka002 We now see that those init containers complete, and that the myapp-pod Pod moves into the Running state. Clean up. kubectl delete service mydb myservice kubectl delete pod myapp-pod References: Pod basics Lifecycle & phases Kubernetes pod design pattern","title":"initContainer Pod"},{"location":"k8s/cka_en/foundamentals/policy/","text":"Policy \u00b6 ResourceQuota \u00b6 Scenario: Create ResourceQuota object-quota-demo for namespace quota-object-example . Test ResourceQuota object-quota-demo for NodePort Test ResourceQuota object-quota-demo for PVC Create Namespace \u00b6 Ceate a Namespace kubectl create ns quota-object-example Create ResourceQuota for Namespace \u00b6 Create ResourceQuota object-quota-demo for namespace quota-object-example . Within the namespace, we can only create 1 PVC, 1 LoadBalancer Service, can not create NodePort Service. kubectl apply -f - <@ ) CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev Create CA Config File \u00b6 Get overview of directory /etc/kubernetes/pki . tree /etc/kubernetes/pki Result /etc/kubernetes/pki \u251c\u2500\u2500 apiserver.crt \u251c\u2500\u2500 apiserver-etcd-client.crt \u251c\u2500\u2500 apiserver-etcd-client.key \u251c\u2500\u2500 apiserver.key \u251c\u2500\u2500 apiserver-kubelet-client.crt \u251c\u2500\u2500 apiserver-kubelet-client.key \u251c\u2500\u2500 ca.crt \u251c\u2500\u2500 ca.key \u251c\u2500\u2500 etcd \u2502 \u251c\u2500\u2500 ca.crt \u2502 \u251c\u2500\u2500 ca.key \u2502 \u251c\u2500\u2500 healthcheck-client.crt \u2502 \u251c\u2500\u2500 healthcheck-client.key \u2502 \u251c\u2500\u2500 peer.crt \u2502 \u251c\u2500\u2500 peer.key \u2502 \u251c\u2500\u2500 server.crt \u2502 \u2514\u2500\u2500 server.key \u251c\u2500\u2500 front-proxy-ca.crt \u251c\u2500\u2500 front-proxy-ca.key \u251c\u2500\u2500 front-proxy-client.crt \u251c\u2500\u2500 front-proxy-client.key \u251c\u2500\u2500 sa.key \u2514\u2500\u2500 sa.pub Change to directory /etc/kubernetes/pki . cd /etc/kubernetes/pki Check if file ca-config.json is in place in current directory. ll ca-config.json If not, create it. We can add multiple profiles to specify different expiry date, scenario, parameters, etc.. Profile will be used to sign certificate. 87600 hours are about 10 years. Here we will create 1 additional profile dev . cat > ca-config.json < cka-dev-csr.json < here) to composite evn variable APISERVER ( https://: ). kubectl get node -owide NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready control-plane,master 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 Export env APISERVER . echo \"export APISERVER=\\\"https://:6443\\\"\" >> ~/.bashrc source ~/.bashrc Verify the setting. echo $APISERVER Output: https://:6443 1.Set up cluster Stay in the directory /etc/kubernetes/pki . Generate kubeconfig file. kubectl config set-cluster kubernetes \\ --certificate-authority=/etc/kubernetes/pki/ca.crt \\ --embed-certs=true \\ --server=${APISERVER} \\ --kubeconfig=cka-dev.kubeconfig Now we get the new config file cka-dev.kubeconfig ll -tr | grep cka-dev Output: -rw-r--r-- 1 root root 222 Jul 24 08:49 cka-dev-csr.json -rw-r--r-- 1 root root 1281 Jul 24 09:14 cka-dev.pem -rw------- 1 root root 1675 Jul 24 09:14 cka-dev-key.pem -rw-r--r-- 1 root root 1001 Jul 24 09:14 cka-dev.csr -rw------- 1 root root 1671 Jul 24 09:16 cka-dev.kubeconfig Get content of file cka-dev.kubeconfig . cat cka-dev.kubeconfig apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : null 2.Set up user In file cka-dev.kubeconfig , user info is null. Set up user cka-dev . kubectl config set-credentials cka-dev \\ --client-certificate=/etc/kubernetes/pki/cka-dev.pem \\ --client-key=/etc/kubernetes/pki/cka-dev-key.pem \\ --embed-certs=true \\ --kubeconfig=cka-dev.kubeconfig Now file cka-dev.kubeconfig was updated and user information was added. cat cka-dev.kubeconfig apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : - name : cka-dev user : client-certificate-data : client-key-data : Now we have a complete kubeconfig file cka-dev.kubeconfig . When we use it to get node information, receive error below because we did not set up current-context in kubeconfig file. kubectl --kubeconfig=cka-dev.kubeconfig get nodes The connection to the server localhost:8080 was refused - did you specify the right host or port? Current contents is empty. kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE 3.Set up Context Set up context. kubectl config set-context dev --cluster=kubernetes --user=cka-dev --kubeconfig=cka-dev.kubeconfig Now we have context now but the CURRENT flag is empty. kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts Output: CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev Set up default context. The context will link clusters and users for multiple clusters environment and we can switch to different cluster. kubectl --kubeconfig=cka-dev.kubeconfig config use-context dev 4.Verify Now CURRENT is marked with * , that is, current-context is set up. kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev Because user cka-dev does not have authorization in the cluster, we will receive forbidden error when we try to get information of Pods or Nodes. kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get pod kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get node Merge kubeconfig files \u00b6 Make a copy of your existing config cp ~/.kube/config ~/.kube/config.old Merge the two config files together into a new config file /tmp/config . KUBECONFIG=~/.kube/config:/etc/kubernetes/pki/cka-dev.kubeconfig kubectl config view --flatten > /tmp/config Replace the old config with the new merged config mv /tmp/config ~/.kube/config Now the new ~/.kube/config looks like below. apiVersion: v1 clusters: - cluster: certificate-authority-data: server: https://:6443 name: kubernetes contexts: - context: cluster: kubernetes user: cka-dev name: dev - context: cluster: kubernetes user: kubernetes-admin name: kubernetes-admin@kubernetes current-context: kubernetes-admin@kubernetes kind: Config preferences: {} users: - name: cka-dev user: client-certificate-data: client-key-data: - name: kubernetes-admin user: client-certificate-data: client-key-data: Verify contexts after kubeconfig merged. kubectl config get-contexts Current context is the system default kubernetes-admin@kubernetes . CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev Namespaces & Contexts \u00b6 Get list of Namespace with Label information. kubectl get ns --show-labels Create Namespace cka . kubectl create namespace cka Use below command to set a context with new update, e.g, update default namespace, etc.. kubectl config set-context --cluster= --namespace= --user= Let's set default namespace to each context. kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin kubectl config set-context dev --cluster=kubernetes --namespace=cka --user=cka-dev Let's check current context information. kubectl config get-contexts Output: CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev cka * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev To switch to a new context, use below command. kubectl config use-contexts For example. kubectl config use-context dev Verify if it's changed as expected. kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev cka kubernetes-admin@kubernetes kubernetes kubernetes-admin dev Be noted, four users beginning with cka-dev created don't have any authorizations, e.g., access namespaces, get pods, etc.. Referring RBAC to grant their authorizations. Role & RoleBinding \u00b6 Switch to context kubernetes-admin@kubernetes . kubectl config use-context kubernetes-admin@kubernetes Use kubectl create role command with option --dry-run=client and -o yaml to generate yaml template for customizing. kubectl create role admin-dev --resource=pods --verb=get --verb=list --verb=watch --dry-run=client -o yaml Create role admin-dev on namespace cka . kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: cka name: admin-dev rules: - apiGroups: - \"\" resources: - pods verbs: - get - watch - list EOF Use kubectl create rolebinding command with option --dry-run=client and -o yaml to generate yaml template for customizing. kubectl create rolebinding admin --role=admin-dev --user=cka-dev --dry-run=client -o yaml Create rolebinding admin on namespace cka . kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: admin namespace: cka roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: admin-dev subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: cka-dev EOF Verify authorzation of user cka-dev on Namespace cka . Switch to context dev . kubectl config use-context dev Get Pods status in Namespace cka . Success! kubectl get pod -n cka Get Pods status in Namespace kube-system . Failed, because the authorzation is only for Namespace cka . kubectl get pod -n kube-system Get Nodes status. Failed, because the role we defined is only for Pod resource. kubectl get node Create a Pod in Namespace dev . Failed because we only have get , watch , list for Pod, no create authorization. kubectl run nginx --image=nginx -n cka ClusterRole & ClusterRoleBinding \u00b6 Switch to context kubernetes-admin@kubernetes . kubectl config use-context kubernetes-admin@kubernetes Create a ClusterRole nodes-admin with authorization get , watch , list for nodes resource. kubectl apply -f - <@ ) CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev","title":"Current Context"},{"location":"k8s/cka_en/foundamentals/rbac/#create-ca-config-file","text":"Get overview of directory /etc/kubernetes/pki . tree /etc/kubernetes/pki Result /etc/kubernetes/pki \u251c\u2500\u2500 apiserver.crt \u251c\u2500\u2500 apiserver-etcd-client.crt \u251c\u2500\u2500 apiserver-etcd-client.key \u251c\u2500\u2500 apiserver.key \u251c\u2500\u2500 apiserver-kubelet-client.crt \u251c\u2500\u2500 apiserver-kubelet-client.key \u251c\u2500\u2500 ca.crt \u251c\u2500\u2500 ca.key \u251c\u2500\u2500 etcd \u2502 \u251c\u2500\u2500 ca.crt \u2502 \u251c\u2500\u2500 ca.key \u2502 \u251c\u2500\u2500 healthcheck-client.crt \u2502 \u251c\u2500\u2500 healthcheck-client.key \u2502 \u251c\u2500\u2500 peer.crt \u2502 \u251c\u2500\u2500 peer.key \u2502 \u251c\u2500\u2500 server.crt \u2502 \u2514\u2500\u2500 server.key \u251c\u2500\u2500 front-proxy-ca.crt \u251c\u2500\u2500 front-proxy-ca.key \u251c\u2500\u2500 front-proxy-client.crt \u251c\u2500\u2500 front-proxy-client.key \u251c\u2500\u2500 sa.key \u2514\u2500\u2500 sa.pub Change to directory /etc/kubernetes/pki . cd /etc/kubernetes/pki Check if file ca-config.json is in place in current directory. ll ca-config.json If not, create it. We can add multiple profiles to specify different expiry date, scenario, parameters, etc.. Profile will be used to sign certificate. 87600 hours are about 10 years. Here we will create 1 additional profile dev . cat > ca-config.json < cka-dev-csr.json < here) to composite evn variable APISERVER ( https://: ). kubectl get node -owide NAME STATUS ROLES AGE VERSION OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME cka001 Ready control-plane,master 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka002 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 cka003 Ready 14h v1.24.0 Ubuntu 20.04.4 LTS 5.4.0-122-generic containerd://1.5.9 Export env APISERVER . echo \"export APISERVER=\\\"https://:6443\\\"\" >> ~/.bashrc source ~/.bashrc Verify the setting. echo $APISERVER Output: https://:6443 1.Set up cluster Stay in the directory /etc/kubernetes/pki . Generate kubeconfig file. kubectl config set-cluster kubernetes \\ --certificate-authority=/etc/kubernetes/pki/ca.crt \\ --embed-certs=true \\ --server=${APISERVER} \\ --kubeconfig=cka-dev.kubeconfig Now we get the new config file cka-dev.kubeconfig ll -tr | grep cka-dev Output: -rw-r--r-- 1 root root 222 Jul 24 08:49 cka-dev-csr.json -rw-r--r-- 1 root root 1281 Jul 24 09:14 cka-dev.pem -rw------- 1 root root 1675 Jul 24 09:14 cka-dev-key.pem -rw-r--r-- 1 root root 1001 Jul 24 09:14 cka-dev.csr -rw------- 1 root root 1671 Jul 24 09:16 cka-dev.kubeconfig Get content of file cka-dev.kubeconfig . cat cka-dev.kubeconfig apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : null 2.Set up user In file cka-dev.kubeconfig , user info is null. Set up user cka-dev . kubectl config set-credentials cka-dev \\ --client-certificate=/etc/kubernetes/pki/cka-dev.pem \\ --client-key=/etc/kubernetes/pki/cka-dev-key.pem \\ --embed-certs=true \\ --kubeconfig=cka-dev.kubeconfig Now file cka-dev.kubeconfig was updated and user information was added. cat cka-dev.kubeconfig apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : kubernetes contexts : null current-context : \"\" kind : Config preferences : {} users : - name : cka-dev user : client-certificate-data : client-key-data : Now we have a complete kubeconfig file cka-dev.kubeconfig . When we use it to get node information, receive error below because we did not set up current-context in kubeconfig file. kubectl --kubeconfig=cka-dev.kubeconfig get nodes The connection to the server localhost:8080 was refused - did you specify the right host or port? Current contents is empty. kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE 3.Set up Context Set up context. kubectl config set-context dev --cluster=kubernetes --user=cka-dev --kubeconfig=cka-dev.kubeconfig Now we have context now but the CURRENT flag is empty. kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts Output: CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev Set up default context. The context will link clusters and users for multiple clusters environment and we can switch to different cluster. kubectl --kubeconfig=cka-dev.kubeconfig config use-context dev 4.Verify Now CURRENT is marked with * , that is, current-context is set up. kubectl --kubeconfig=cka-dev.kubeconfig config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev Because user cka-dev does not have authorization in the cluster, we will receive forbidden error when we try to get information of Pods or Nodes. kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get pod kubectl --kubeconfig=/etc/kubernetes/pki/cka-dev.kubeconfig get node","title":"Create file kubeconfig"},{"location":"k8s/cka_en/foundamentals/rbac/#merge-kubeconfig-files","text":"Make a copy of your existing config cp ~/.kube/config ~/.kube/config.old Merge the two config files together into a new config file /tmp/config . KUBECONFIG=~/.kube/config:/etc/kubernetes/pki/cka-dev.kubeconfig kubectl config view --flatten > /tmp/config Replace the old config with the new merged config mv /tmp/config ~/.kube/config Now the new ~/.kube/config looks like below. apiVersion: v1 clusters: - cluster: certificate-authority-data: server: https://:6443 name: kubernetes contexts: - context: cluster: kubernetes user: cka-dev name: dev - context: cluster: kubernetes user: kubernetes-admin name: kubernetes-admin@kubernetes current-context: kubernetes-admin@kubernetes kind: Config preferences: {} users: - name: cka-dev user: client-certificate-data: client-key-data: - name: kubernetes-admin user: client-certificate-data: client-key-data: Verify contexts after kubeconfig merged. kubectl config get-contexts Current context is the system default kubernetes-admin@kubernetes . CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev","title":"Merge kubeconfig files"},{"location":"k8s/cka_en/foundamentals/rbac/#namespaces-contexts","text":"Get list of Namespace with Label information. kubectl get ns --show-labels Create Namespace cka . kubectl create namespace cka Use below command to set a context with new update, e.g, update default namespace, etc.. kubectl config set-context --cluster= --namespace= --user= Let's set default namespace to each context. kubectl config set-context kubernetes-admin@kubernetes --cluster=kubernetes --namespace=default --user=kubernetes-admin kubectl config set-context dev --cluster=kubernetes --namespace=cka --user=cka-dev Let's check current context information. kubectl config get-contexts Output: CURRENT NAME CLUSTER AUTHINFO NAMESPACE dev kubernetes cka-dev cka * kubernetes-admin@kubernetes kubernetes kubernetes-admin dev To switch to a new context, use below command. kubectl config use-contexts For example. kubectl config use-context dev Verify if it's changed as expected. kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE * dev kubernetes cka-dev cka kubernetes-admin@kubernetes kubernetes kubernetes-admin dev Be noted, four users beginning with cka-dev created don't have any authorizations, e.g., access namespaces, get pods, etc.. Referring RBAC to grant their authorizations.","title":"Namespaces & Contexts"},{"location":"k8s/cka_en/foundamentals/rbac/#role-rolebinding","text":"Switch to context kubernetes-admin@kubernetes . kubectl config use-context kubernetes-admin@kubernetes Use kubectl create role command with option --dry-run=client and -o yaml to generate yaml template for customizing. kubectl create role admin-dev --resource=pods --verb=get --verb=list --verb=watch --dry-run=client -o yaml Create role admin-dev on namespace cka . kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: cka name: admin-dev rules: - apiGroups: - \"\" resources: - pods verbs: - get - watch - list EOF Use kubectl create rolebinding command with option --dry-run=client and -o yaml to generate yaml template for customizing. kubectl create rolebinding admin --role=admin-dev --user=cka-dev --dry-run=client -o yaml Create rolebinding admin on namespace cka . kubectl apply -f - << EOF apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: admin namespace: cka roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: admin-dev subjects: - apiGroup: rbac.authorization.k8s.io kind: User name: cka-dev EOF Verify authorzation of user cka-dev on Namespace cka . Switch to context dev . kubectl config use-context dev Get Pods status in Namespace cka . Success! kubectl get pod -n cka Get Pods status in Namespace kube-system . Failed, because the authorzation is only for Namespace cka . kubectl get pod -n kube-system Get Nodes status. Failed, because the role we defined is only for Pod resource. kubectl get node Create a Pod in Namespace dev . Failed because we only have get , watch , list for Pod, no create authorization. kubectl run nginx --image=nginx -n cka","title":"Role & RoleBinding"},{"location":"k8s/cka_en/foundamentals/rbac/#clusterrole-clusterrolebinding","text":"Switch to context kubernetes-admin@kubernetes . kubectl config use-context kubernetes-admin@kubernetes Create a ClusterRole nodes-admin with authorization get , watch , list for nodes resource. kubectl apply -f - < nodeName \u00b6 Be noted, nodeName has hightest priority as it's not scheduled by Scheduler . Create a Pod nginx-nodename with nodeName=cka003 . kubectl apply -f - < Affinity \u00b6 In Kubernetes cluster, some Pods have frequent interaction with other Pods. With that situation, it's suggested to schedule these Pods running on same node. For example, Two Pods Nginx and Mysql, we need deploy them on one node if they frequently communicate. We can use podAffinity to select Pods based on their relationship. There are two scheduling type of podAffinity . requiredDuringSchedulingIgnoredDuringExecution (\u786c\u4eb2\u548c) preferredDuringSchedulingIgnoredDuringExecution (\u8f6f\u4eb2\u548c) topologyKey could be set by below types: kubernetes.io/hostname \uff03NodeName failure-domain.beta.kubernetes.io/zone \uff03Zone failure-domain.beta.kubernetes.io/region # Region We can set node Label to classify Name/Zone/Region of node, which can be used by podAffinity . Create a Pod Nginx. kubectl apply -f - < ","title":"nodeSelector"},{"location":"k8s/cka_en/foundamentals/scheduling/#nodename","text":"Be noted, nodeName has hightest priority as it's not scheduled by Scheduler . Create a Pod nginx-nodename with nodeName=cka003 . kubectl apply -f - < ","title":"nodeName"},{"location":"k8s/cka_en/foundamentals/scheduling/#affinity","text":"In Kubernetes cluster, some Pods have frequent interaction with other Pods. With that situation, it's suggested to schedule these Pods running on same node. For example, Two Pods Nginx and Mysql, we need deploy them on one node if they frequently communicate. We can use podAffinity to select Pods based on their relationship. There are two scheduling type of podAffinity . requiredDuringSchedulingIgnoredDuringExecution (\u786c\u4eb2\u548c) preferredDuringSchedulingIgnoredDuringExecution (\u8f6f\u4eb2\u548c) topologyKey could be set by below types: kubernetes.io/hostname \uff03NodeName failure-domain.beta.kubernetes.io/zone \uff03Zone failure-domain.beta.kubernetes.io/region # Region We can set node Label to classify Name/Zone/Region of node, which can be used by podAffinity . Create a Pod Nginx. kubectl apply -f - < 80/TCP 14s app=httpd NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/httpd-app-6496d888c9-4nb6z 1/1 Running 0 77s 10.244.102.21 cka003 pod/httpd-app-6496d888c9-b7xht 1/1 Running 0 77s 10.244.112.19 cka002 Verify the access to Pod IPs. curl 10.244.102.21 curl 10.244.112.19 And receive below successful information.

    It works!

    Verify the access via ClusterIP with Port. curl 11.244.247.7:80 And receive below successful information.

    It works!

    Expose Service \u00b6 Create and attach to a temporary Pod nslookup and to verify DNS resolution. The option --rm means delete the Pod after exit. kubectl run -it nslookup --rm --image=busybox:1.28 After attach to the Pod, run command nslookup httpd-app . We receive the ClusterIP of Service httpd-app and full domain name. / # nslookup httpd-app Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: httpd-app Address 1: 11.244.247.7 httpd-app.dev.svc.cluster.local We can check the IP of temporary Pod nslookup in a new terminal by executing command kubectl get pod -o wide . The Pod nslookup has Pod IP 10.244.112.20 . kubectl get pod nslookup Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nslookup 1/1 Running 0 2m44s 10.244.112.20 cka002 NodePort \u00b6 Create and apply yaml file svc-nodeport.yaml to create a Service httpd-app . kubectl apply -f - < will update configuration to existing resources. Here the Service httpd-app is changed from ClusterIP to NodePort type. No change to the Deployment httpd-app . service/httpd-app configured deployment.apps/httpd-app unchanged Check the Service httpd-app via kubectl get svc . IP is the same. Type is changed to NodePort. Port numbers is changed from 80/TCP to 80:30080/TCP . NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpd-app NodePort 11.244.247.7 80:30080/TCP 18m Test the connection to the Service httpd-app via command curl :30080 to each node. curl :30080 curl :30080 curl :30080 We will receive below successful information.

    It works!

    Headless Service \u00b6 Create Headless Service web and StatefulSet web . kubectl apply -f - < web-1 1/1 Running 0 6s 10.244.112.21 cka002 Get details of the Service by command kubectl describe svc -l app=web . Name: web Namespace: dev Labels: app=web Annotations: Selector: app=web Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: None IPs: None Port: web 80/TCP TargetPort: 80/TCP Endpoints: 10.244.102.22:80,10.244.112.21:80 Session Affinity: None Events: Attach to the temporary Pod nslookup and use nslookup to verify DNS resolution. kubectl run -it nslookup --rm --image=busybox:1.28 With nslookup command for Headless Service web , we received two Pod IPs, not ClusterIP due to Headless Service. / # nslookup web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local Address 2: 10.244.102.22 web-0.web.dev.svc.cluster.local We can also use nslookup for web-0.web and web-1.web . Every Pod of Headless Service has own Service Name for DNS lookup. / # nslookup web-0.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.web Address 1: 10.244.102.22 web-0.web.dev.svc.cluster.local / # nslookup web-1.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local Clean up. kubectl delete sts web kubectl delete service httpd-app web kubectl delete deployment httpd-app Service Internal Traffic Policy \u00b6 Scenario Simulate how Service Internal Traffic Policy works. Expected result: With setting Service internalTrafficPolicy: Local , the Service only route internal traffic within the nodes that Pods are running. Backgroud: Service Internal Traffic Policy enables internal traffic restrictions to only route internal traffic to endpoints within the node the traffic originated from. The \"internal\" traffic here refers to traffic originated from Pods in the current cluster. By setting its .spec.internalTrafficPolicy to Local. This tells kube-proxy to only use node local endpoints for cluster internal traffic. For pods on nodes with no endpoints for a given Service, the Service behaves as if it has zero endpoints (for Pods on this node) even if the service does have endpoints on other nodes. Demo: Create Deployment my-nginx and Service my-nginx . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx EOF With command kubectl get pod -o wide , we know the Pod of Deployment my-nginx is running on node cka003 . NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cf54cdbf7-bscf8 1/1 Running 0 9h 10.244.112.63 cka002 Let's send http request from cka001 to the Pod on cka002 . We will receive Welcome to nginx! information, which means the Pod is accessable from other nodes. curl 11.244.163.60 Let's modify the Serivce my-nginx and specify internalTrafficPolicy: Local . kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx internalTrafficPolicy: Local EOF Let's send http request from cka001 to the http request to the Pod again. We will receive curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused error information. curl 11.244.163.60 Let's log onto cka002 and the http request to the Pod again. We will receive Welcome to nginx! information, curl 11.244.163.60 Conclution With setting Service internalTrafficPolicy: Local , the Service only route internal traffic within the nodes that Pods are running. Scenario *Create a nginx deployment * Add port number and alias name of the nginx Pod. * Expose the deployment with internal traffic to local only. Demo: Create deployment my-nginx with port number 80 . kubectl create deployment my-nginx --image=nginx --port=80 Edit deployment. kubectl edit deployment my-nginx Add port alias name http . Refer to the link for deployment yaml template https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ spec : containers : - image : nginx imagePullPolicy : Always name : nginx ports : - containerPort : 80 protocol : TCP name : http Expose the deployment with NodePort type. kubectl expose deployment my-nginx --port=80 --target-port=http --name=my-nginx-svc --type=NodePort Edit the service. Change internalTrafficPolicy from Cluster to Local . kubectl edit svc my-nginx-svc Verify the access. Note, the pod is running on node cka003 . We will see below expected results. curl :80 # succeed on node cka003. internalTrafficPolicy is effective. curl :80 # succeed on all nodes. curl : # succeed on all nodes.","title":"Service"},{"location":"k8s/cka_en/foundamentals/service/#service","text":"Scenario: Create Deployment httpd-app . Create Service httpd-app with type ClusterIP , which is default type and accessable internally. Verify the access to Pod IP and Service ClusterIP. Update Service httpd-app with type NodePort . No change to the Deployment httpd-app . Verify the access to Node. The access will route to Pod. The service is now accesable from outside. Create Headless Service web and StatefulSet web . Service Internal Traffic Policy","title":"Service"},{"location":"k8s/cka_en/foundamentals/service/#clusterip","text":"","title":"ClusterIP"},{"location":"k8s/cka_en/foundamentals/service/#create-service","text":"Create a Deployment http-app . Create a Service httpd-app link to Development http-app by Label Selector. Service type is ClusterIP , which is default type and accessable internally. kubectl apply -f - < 80/TCP 14s app=httpd NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/httpd-app-6496d888c9-4nb6z 1/1 Running 0 77s 10.244.102.21 cka003 pod/httpd-app-6496d888c9-b7xht 1/1 Running 0 77s 10.244.112.19 cka002 Verify the access to Pod IPs. curl 10.244.102.21 curl 10.244.112.19 And receive below successful information.

    It works!

    Verify the access via ClusterIP with Port. curl 11.244.247.7:80 And receive below successful information.

    It works!

    ","title":"Create Service"},{"location":"k8s/cka_en/foundamentals/service/#expose-service","text":"Create and attach to a temporary Pod nslookup and to verify DNS resolution. The option --rm means delete the Pod after exit. kubectl run -it nslookup --rm --image=busybox:1.28 After attach to the Pod, run command nslookup httpd-app . We receive the ClusterIP of Service httpd-app and full domain name. / # nslookup httpd-app Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: httpd-app Address 1: 11.244.247.7 httpd-app.dev.svc.cluster.local We can check the IP of temporary Pod nslookup in a new terminal by executing command kubectl get pod -o wide . The Pod nslookup has Pod IP 10.244.112.20 . kubectl get pod nslookup Result NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nslookup 1/1 Running 0 2m44s 10.244.112.20 cka002 ","title":"Expose Service"},{"location":"k8s/cka_en/foundamentals/service/#nodeport","text":"Create and apply yaml file svc-nodeport.yaml to create a Service httpd-app . kubectl apply -f - < will update configuration to existing resources. Here the Service httpd-app is changed from ClusterIP to NodePort type. No change to the Deployment httpd-app . service/httpd-app configured deployment.apps/httpd-app unchanged Check the Service httpd-app via kubectl get svc . IP is the same. Type is changed to NodePort. Port numbers is changed from 80/TCP to 80:30080/TCP . NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpd-app NodePort 11.244.247.7 80:30080/TCP 18m Test the connection to the Service httpd-app via command curl :30080 to each node. curl :30080 curl :30080 curl :30080 We will receive below successful information.

    It works!

    ","title":"NodePort"},{"location":"k8s/cka_en/foundamentals/service/#headless-service","text":"Create Headless Service web and StatefulSet web . kubectl apply -f - < web-1 1/1 Running 0 6s 10.244.112.21 cka002 Get details of the Service by command kubectl describe svc -l app=web . Name: web Namespace: dev Labels: app=web Annotations: Selector: app=web Type: ClusterIP IP Family Policy: SingleStack IP Families: IPv4 IP: None IPs: None Port: web 80/TCP TargetPort: 80/TCP Endpoints: 10.244.102.22:80,10.244.112.21:80 Session Affinity: None Events: Attach to the temporary Pod nslookup and use nslookup to verify DNS resolution. kubectl run -it nslookup --rm --image=busybox:1.28 With nslookup command for Headless Service web , we received two Pod IPs, not ClusterIP due to Headless Service. / # nslookup web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local Address 2: 10.244.102.22 web-0.web.dev.svc.cluster.local We can also use nslookup for web-0.web and web-1.web . Every Pod of Headless Service has own Service Name for DNS lookup. / # nslookup web-0.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-0.web Address 1: 10.244.102.22 web-0.web.dev.svc.cluster.local / # nslookup web-1.web Server: 11.244.0.10 Address 1: 11.244.0.10 kube-dns.kube-system.svc.cluster.local Name: web-1.web Address 1: 10.244.112.21 web-1.web.dev.svc.cluster.local Clean up. kubectl delete sts web kubectl delete service httpd-app web kubectl delete deployment httpd-app","title":"Headless Service"},{"location":"k8s/cka_en/foundamentals/service/#service-internal-traffic-policy","text":"Scenario Simulate how Service Internal Traffic Policy works. Expected result: With setting Service internalTrafficPolicy: Local , the Service only route internal traffic within the nodes that Pods are running. Backgroud: Service Internal Traffic Policy enables internal traffic restrictions to only route internal traffic to endpoints within the node the traffic originated from. The \"internal\" traffic here refers to traffic originated from Pods in the current cluster. By setting its .spec.internalTrafficPolicy to Local. This tells kube-proxy to only use node local endpoints for cluster internal traffic. For pods on nodes with no endpoints for a given Service, the Service behaves as if it has zero endpoints (for Pods on this node) even if the service does have endpoints on other nodes. Demo: Create Deployment my-nginx and Service my-nginx . kubectl apply -f - << EOF apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx spec: selector: matchLabels: run: my-nginx replicas: 1 template: metadata: labels: run: my-nginx spec: containers: - name: my-nginx image: nginx ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx EOF With command kubectl get pod -o wide , we know the Pod of Deployment my-nginx is running on node cka003 . NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-nginx-cf54cdbf7-bscf8 1/1 Running 0 9h 10.244.112.63 cka002 Let's send http request from cka001 to the Pod on cka002 . We will receive Welcome to nginx! information, which means the Pod is accessable from other nodes. curl 11.244.163.60 Let's modify the Serivce my-nginx and specify internalTrafficPolicy: Local . kubectl apply -f - << EOF apiVersion: v1 kind: Service metadata: name: my-nginx labels: run: my-nginx spec: ports: - port: 80 protocol: TCP selector: run: my-nginx internalTrafficPolicy: Local EOF Let's send http request from cka001 to the http request to the Pod again. We will receive curl: (7) Failed to connect to 11.244.163.60 port 80: Connection refused error information. curl 11.244.163.60 Let's log onto cka002 and the http request to the Pod again. We will receive Welcome to nginx! information, curl 11.244.163.60 Conclution With setting Service internalTrafficPolicy: Local , the Service only route internal traffic within the nodes that Pods are running. Scenario *Create a nginx deployment * Add port number and alias name of the nginx Pod. * Expose the deployment with internal traffic to local only. Demo: Create deployment my-nginx with port number 80 . kubectl create deployment my-nginx --image=nginx --port=80 Edit deployment. kubectl edit deployment my-nginx Add port alias name http . Refer to the link for deployment yaml template https://kubernetes.io/docs/concepts/workloads/controllers/deployment/ spec : containers : - image : nginx imagePullPolicy : Always name : nginx ports : - containerPort : 80 protocol : TCP name : http Expose the deployment with NodePort type. kubectl expose deployment my-nginx --port=80 --target-port=http --name=my-nginx-svc --type=NodePort Edit the service. Change internalTrafficPolicy from Cluster to Local . kubectl edit svc my-nginx-svc Verify the access. Note, the pod is running on node cka003 . We will see below expected results. curl :80 # succeed on node cka003. internalTrafficPolicy is effective. curl :80 # succeed on all nodes. curl : # succeed on all nodes.","title":"Service Internal Traffic Policy"},{"location":"k8s/cka_en/foundamentals/statefulset/","text":"StatefulSet \u00b6 Scenario: Create Headless Service nginx and StatefulSet web Scale out StatefulSet web Demo: Create Headless Service nginx and StatefulSet web . kubectl apply -f - << EOF --- apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: \"nginx\" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web EOF Get details of StatefulSet Pod created just now. kubectl get pod | grep web Result NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 27s web-1 1/1 Running 0 10s Use command kubectl edit sts web to update an existing StatefulSet. ONLY these fields can be updated: replicas \u3001 image \u3001 rolling updates \u3001 labels \u3001 resource request/limit and annotations . Note: When StatefulSet Pod is dead in current node, no copies will be created in other node automatically. Scale out StatefulSet. Scale StatefulSet web to 5 Replicas. kubectl scale sts web --replicas=5 Info Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0. Command: kubectl explain statefulsets.spec.updateStrategy.rollingUpdate.partition Clean up. kubectl delete sts web kubectl delete service nginx","title":"StatefulSet"},{"location":"k8s/cka_en/foundamentals/statefulset/#statefulset","text":"Scenario: Create Headless Service nginx and StatefulSet web Scale out StatefulSet web Demo: Create Headless Service nginx and StatefulSet web . kubectl apply -f - << EOF --- apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 80 name: web clusterIP: None selector: app: nginx --- apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: serviceName: \"nginx\" replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web EOF Get details of StatefulSet Pod created just now. kubectl get pod | grep web Result NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 27s web-1 1/1 Running 0 10s Use command kubectl edit sts web to update an existing StatefulSet. ONLY these fields can be updated: replicas \u3001 image \u3001 rolling updates \u3001 labels \u3001 resource request/limit and annotations . Note: When StatefulSet Pod is dead in current node, no copies will be created in other node automatically. Scale out StatefulSet. Scale StatefulSet web to 5 Replicas. kubectl scale sts web --replicas=5 Info Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0. Command: kubectl explain statefulsets.spec.updateStrategy.rollingUpdate.partition Clean up. kubectl delete sts web kubectl delete service nginx","title":"StatefulSet"},{"location":"k8s/cka_en/foundamentals/troubleshooting/","text":"Troubleshooting \u00b6 Event \u00b6 Scenario Describe pod to get event information. Demo: Usage: kubectl describe --namespace= Get event information of a Pod Create a Tomcat Pod. kubectl run tomcat --image=tomcat Check event of above deplyment. kubectl describe pod/tomcat Get below event information. Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 55s default-scheduler Successfully assigned dev/tomcat to cka002 Normal Pulling 54s kubelet Pulling image \"tomcat\" Normal Pulled 21s kubelet Successfully pulled image \"tomcat\" in 33.134162692s Normal Created 19s kubelet Created container tomcat Normal Started 19s kubelet Started container tomcat Get event information for a Namespace. kubectl get events -n Get current default namespace event information. LAST SEEN TYPE REASON OBJECT MESSAGE 70s Warning FailedGetScale horizontalpodautoscaler/nginx deployments/scale.apps \"podinfo\" not found 2m16s Normal Scheduled pod/tomcat Successfully assigned dev/tomcat to cka002 2m15s Normal Pulling pod/tomcat Pulling image \"tomcat\" 102s Normal Pulled pod/tomcat Successfully pulled image \"tomcat\" in 33.134162692s 100s Normal Created pod/tomcat Created container tomcat 100s Normal Started pod/tomcat Started container tomcat Get event information for all Namespace. kubectl get events -A Logs \u00b6 Scenario Get log of pod Usage: kubectl logs -n Options: --tail : display only the most recent lines of output -f : streaming the output Get the most recent 100 lines of output. kubectl logs -f tomcat --tail 100 If it's multipPod, use -c to specify Container. kubectl logs -f tomcat --tail 100 -c tomcat Node Availability \u00b6 Check Available Node \u00b6 Scenario Check node availibility. Demo: Option 1: kubectl describe node | grep -i taint Manual check the result, here it's 2 nodes are available Taints: node-role.kubernetes.io/control-plane:NoSchedule Taints: Taints: Option 2: kubectl describe node | grep -i taint |grep -vc NoSchedule We will get same result 2 . Here -v means exclude, -c count numbers. Node NotReady \u00b6 Scenario: When we stop kubelet service on worker node cka002 , What's the status of each node? What's containers changed via command nerdctl ? What's pods status via command kubectl get pod -owide -A ? Demo: Execute command systemctl stop kubelet.service on cka002 . Execute command kubectl get node on either cka001 or cka003 , the status of cka002 is NotReady . Execute command nerdctl -n k8s.io container ls on cka002 and we can observe all containers are still up and running, including the pod my-first-pod . Execute command systemctl start kubelet.service on cka002 . Conclusion: The node status is changed to NotReady from Ready . For those DaemonSet pods, like calico \u3001 kube-proxy , are exclusively running on each node. They won't be terminated after kubelet is down. The status of pod my-first-pod keeps showing Terminating on each node because status can not be synced to other nodes via apiserver from cka002 because kubelet is down. The status of pod is marked by controller and recycled by kubelet . When we start kubelet service on cka003 , the pod my-first-pod will be termiated completely on cka002 . In addition, let's create a deployment with 3 replicas. Two are running on cka003 and one is running on cka002 . root@cka001:~# kubectl get pod -o wide -w NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-9d745469b-2xdk4 1/1 Running 0 2m8s 10.244.2.3 cka003 nginx-deployment-9d745469b-4gvmr 1/1 Running 0 2m8s 10.244.2.4 cka003 nginx-deployment-9d745469b-5j927 1/1 Running 0 2m8s 10.244.1.3 cka002 After we stop kubelet service on cka003 , the two running on cka003 are terminated and another two are created and running on cka002 automatically. Monitoring Indicators \u00b6 Scenario: Get monitoring indicators of pod Demo: Get node monitoring information kubectl top node Output: NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 147m 7% 1940Mi 50% cka002 62m 3% 2151Mi 56% cka003 63m 3% 1825Mi 47% Get Pod monitoring information kubectl top pod Output: root@cka001:~# kubectl top pod NAME CPU(cores) MEMORY(bytes) busybox-with-secret 0m 0Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi tomcat 1m 58Mi Sort output by CPU or Memory using option --sort-by , the field can be either 'cpu' or 'memory'. kubectl top pod --sort-by=cpu kubectl top pod --sort-by=memory Output: NAME CPU(cores) MEMORY(bytes) nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi tomcat 1m 58Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi busybox-with-secret 0m 0Mi Node Eviction \u00b6 Cordon/Uncordon \u00b6 Scenario Scheduling for a node Demo: Disable scheduling for a Node. kubectl cordon Example: kubectl cordon cka003 Node status: NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready,SchedulingDisabled 18d v1.24.0 Enable scheduling for a Node. kubectl uncordon Example: kubectl uncordon cka003 Node status: NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready 18d v1.24.0 Drain Node \u00b6 Scenario Drain the node cka003 Demo: Get list of Pods running. kubectl get pod -o wide We know that a Pod is running on cka003 . NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-xk8nw 1/1 Running 0 22h 10.244.102.3 cka003 Evict node cka003 . kubectl drain cka003 --ignore-daemonsets --delete-emptydir-data --force Output looks like below. node/cka003 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-tr22l, kube-system/kube-proxy-g76kg evicting pod dev/nfs-client-provisioner-86d7fb78b6-xk8nw evicting pod cka/cka-demo-64f88f7f46-dkxmk pod/nfs-client-provisioner-86d7fb78b6-xk8nw evicted pod/cka-demo-64f88f7f46-dkxmk evicted node/cka003 drained Check pod status again. kubectl get pod -o wide The pod is running on cka002 now. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-k8xnl 1/1 Running 0 2m20s 10.244.112.4 cka002 Note cordon is included in drain , no need additional step to cordon node before drain node.","title":"Troubleshooting"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#troubleshooting","text":"","title":"Troubleshooting"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#event","text":"Scenario Describe pod to get event information. Demo: Usage: kubectl describe --namespace= Get event information of a Pod Create a Tomcat Pod. kubectl run tomcat --image=tomcat Check event of above deplyment. kubectl describe pod/tomcat Get below event information. Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 55s default-scheduler Successfully assigned dev/tomcat to cka002 Normal Pulling 54s kubelet Pulling image \"tomcat\" Normal Pulled 21s kubelet Successfully pulled image \"tomcat\" in 33.134162692s Normal Created 19s kubelet Created container tomcat Normal Started 19s kubelet Started container tomcat Get event information for a Namespace. kubectl get events -n Get current default namespace event information. LAST SEEN TYPE REASON OBJECT MESSAGE 70s Warning FailedGetScale horizontalpodautoscaler/nginx deployments/scale.apps \"podinfo\" not found 2m16s Normal Scheduled pod/tomcat Successfully assigned dev/tomcat to cka002 2m15s Normal Pulling pod/tomcat Pulling image \"tomcat\" 102s Normal Pulled pod/tomcat Successfully pulled image \"tomcat\" in 33.134162692s 100s Normal Created pod/tomcat Created container tomcat 100s Normal Started pod/tomcat Started container tomcat Get event information for all Namespace. kubectl get events -A","title":"Event"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#logs","text":"Scenario Get log of pod Usage: kubectl logs -n Options: --tail : display only the most recent lines of output -f : streaming the output Get the most recent 100 lines of output. kubectl logs -f tomcat --tail 100 If it's multipPod, use -c to specify Container. kubectl logs -f tomcat --tail 100 -c tomcat","title":"Logs"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#node-availability","text":"","title":"Node Availability"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#check-available-node","text":"Scenario Check node availibility. Demo: Option 1: kubectl describe node | grep -i taint Manual check the result, here it's 2 nodes are available Taints: node-role.kubernetes.io/control-plane:NoSchedule Taints: Taints: Option 2: kubectl describe node | grep -i taint |grep -vc NoSchedule We will get same result 2 . Here -v means exclude, -c count numbers.","title":"Check Available Node"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#node-notready","text":"Scenario: When we stop kubelet service on worker node cka002 , What's the status of each node? What's containers changed via command nerdctl ? What's pods status via command kubectl get pod -owide -A ? Demo: Execute command systemctl stop kubelet.service on cka002 . Execute command kubectl get node on either cka001 or cka003 , the status of cka002 is NotReady . Execute command nerdctl -n k8s.io container ls on cka002 and we can observe all containers are still up and running, including the pod my-first-pod . Execute command systemctl start kubelet.service on cka002 . Conclusion: The node status is changed to NotReady from Ready . For those DaemonSet pods, like calico \u3001 kube-proxy , are exclusively running on each node. They won't be terminated after kubelet is down. The status of pod my-first-pod keeps showing Terminating on each node because status can not be synced to other nodes via apiserver from cka002 because kubelet is down. The status of pod is marked by controller and recycled by kubelet . When we start kubelet service on cka003 , the pod my-first-pod will be termiated completely on cka002 . In addition, let's create a deployment with 3 replicas. Two are running on cka003 and one is running on cka002 . root@cka001:~# kubectl get pod -o wide -w NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-9d745469b-2xdk4 1/1 Running 0 2m8s 10.244.2.3 cka003 nginx-deployment-9d745469b-4gvmr 1/1 Running 0 2m8s 10.244.2.4 cka003 nginx-deployment-9d745469b-5j927 1/1 Running 0 2m8s 10.244.1.3 cka002 After we stop kubelet service on cka003 , the two running on cka003 are terminated and another two are created and running on cka002 automatically.","title":"Node NotReady"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#monitoring-indicators","text":"Scenario: Get monitoring indicators of pod Demo: Get node monitoring information kubectl top node Output: NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% cka001 147m 7% 1940Mi 50% cka002 62m 3% 2151Mi 56% cka003 63m 3% 1825Mi 47% Get Pod monitoring information kubectl top pod Output: root@cka001:~# kubectl top pod NAME CPU(cores) MEMORY(bytes) busybox-with-secret 0m 0Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi tomcat 1m 58Mi Sort output by CPU or Memory using option --sort-by , the field can be either 'cpu' or 'memory'. kubectl top pod --sort-by=cpu kubectl top pod --sort-by=memory Output: NAME CPU(cores) MEMORY(bytes) nfs-client-provisioner-699db7fd58-bccqs 2m 7Mi mysql 2m 366Mi mysql-774db46945-sztrp 2m 349Mi mysql-nodeselector-6b7d9c875d-227t6 2m 365Mi mysql-tolerations-5c5986944b-cg9bs 2m 366Mi mysql-with-sc-pvc-7c97d875f8-dwfkc 2m 349Mi tomcat 1m 58Mi nginx 0m 3Mi nginx-app-1-695b7b647d-l76bh 0m 3Mi nginx-app-2-7f6bf6f4d4-lvbz8 0m 3Mi nginx-nodename 0m 3Mi nginx-with-cm 0m 3Mi pod-configmap-env 0m 3Mi pod-configmap-env-2 0m 3Mi busybox-with-secret 0m 0Mi","title":"Monitoring Indicators"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#node-eviction","text":"","title":"Node Eviction"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#cordonuncordon","text":"Scenario Scheduling for a node Demo: Disable scheduling for a Node. kubectl cordon Example: kubectl cordon cka003 Node status: NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready,SchedulingDisabled 18d v1.24.0 Enable scheduling for a Node. kubectl uncordon Example: kubectl uncordon cka003 Node status: NAME STATUS ROLES AGE VERSION cka001 Ready control-plane,master 18d v1.24.0 cka002 Ready 18d v1.24.0 cka003 Ready 18d v1.24.0","title":"Cordon/Uncordon"},{"location":"k8s/cka_en/foundamentals/troubleshooting/#drain-node","text":"Scenario Drain the node cka003 Demo: Get list of Pods running. kubectl get pod -o wide We know that a Pod is running on cka003 . NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-xk8nw 1/1 Running 0 22h 10.244.102.3 cka003 Evict node cka003 . kubectl drain cka003 --ignore-daemonsets --delete-emptydir-data --force Output looks like below. node/cka003 cordoned WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-tr22l, kube-system/kube-proxy-g76kg evicting pod dev/nfs-client-provisioner-86d7fb78b6-xk8nw evicting pod cka/cka-demo-64f88f7f46-dkxmk pod/nfs-client-provisioner-86d7fb78b6-xk8nw evicted pod/cka-demo-64f88f7f46-dkxmk evicted node/cka003 drained Check pod status again. kubectl get pod -o wide The pod is running on cka002 now. NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nfs-client-provisioner-86d7fb78b6-k8xnl 1/1 Running 0 2m20s 10.244.112.4 cka002 Note cordon is included in drain , no need additional step to cordon node before drain node.","title":"Drain Node"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/","text":"Installation on Aliyun Ubuntu \u00b6 Preparation \u00b6 Register Aliyun account via Alibaba Cloud home console . Request three Elastic Computer Service(ECS) instances with below sizing: System: 2vCPU+4GiB OS: Ubuntu 20.04 x86_64 Instance Type: ecs.sn1.medium Instance Name: cka001, cka002, cka003 Network: both public IPs and private IPs Maximum Bandwidth: 100Mbps (Peak Value) Cloud disk: 40GiB Billing Method: Preemptible instance (spot price) Open a local terminal, log onto remote ECS cka001 using the key pair (e.g., aliyun-root ) from Aliyun cloud. ssh -i aliyun-root root@cka001 Create a common user (e.g., james ), and set primary group as sudo and other group as root . adduser james usermod -g sudo james usermod -a -G root james Back to the local terminal, generate key for common user james by below command. # Windows ssh-keygen.exe # Linux ssh-keygen Two files will be created, e.g., aliyun-james and aliyun-james.pub Upload the public key aliyun-james.pub to remote cka001 using sftp command. sftp -i aliyun-root root@cka001 put aliyun-james.pub Log onto remote ECS cka001 using root account again. Move the key aliyun-james.pub to /home/james/.ssh/ . Rename file aliyun-james.pub to authorized_keys . Change ower of file authorized_keys to james . Change default group of file authorized_keys to sudo . mkdir /home/james/.ssh/ mv aliyun-james.pub /home/james/.ssh/authorized_keys chown james.sudo /home/james/.ssh/authorized_keys chmod 600 /home/james/.ssh/authorized_keys Check file /etc/ssh/sshd_config , make sure password authentication is disabled PasswordAuthentication no cat /etc/ssh/sshd_config Back to the local terminal, use james to log onto remote cka001 . ssh -i aliyun-james james@cka001 Upload the public key aliyun-james.pub to remote cka002 and cka003 using sftp command and do the same set up on cka002 and cka003 in order to enable user james to log onto cka002 and cka003 . Till now, user james can log onto cka001 , cka002 and cka003 using key aliyun-james . All demo below will be done by user james . Initialize VMs \u00b6 Configure /etc/hosts file \u00b6 Add private IPs in the /etc/hosts file in all VMs. vi /etc/hosts Disable firewall \u00b6 Disable firewall by command ufw disable in all VMs. Disable swap on Ubuntu. sudo ufw disable Check status of swap on Ubuntu. sudo ufw status verbose Turn off swap \u00b6 Turn off swap in all VMs. sudo swapoff -a Set timezone and locale \u00b6 Set timezone and local for all VMs. This step was already done during Aliyun ECS installation. ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile Something like this: ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 5 14 :51 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai Kernel setting \u00b6 Perform below kernel setting in all VMs. Create file /etc/modules-load.d/containerd.conf to set up containerd configure file. It's to load two modules overlay and br_netfilter . Service containerd depends on overlay filesystem. Sometimes referred to as union-filesystems. An overlay-filesystem tries to present a filesystem which is the result over overlaying one filesystem on top of the other. The br_netfilter module is required to enable transparent masquerading and to facilitate Virtual Extensible LAN (VxLAN) traffic for communication between Kubernetes pods across the cluster. cat < /etc/apt/sources.list << EOF deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multivers deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe # deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse # deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse EOF Install Containered. sudo apt-get update && sudo apt-get install -y containerd Configure Containerd. Modify file /etc/containerd/config.toml . sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml Update sandbox_image with new value \"registry.aliyuncs.com/google_containers/pause:3.6\" . Update SystemdCgroup with new value true . [plugins] [plugins.\"io.containerd.gc.v1.scheduler\"] [plugins.\"io.containerd.grpc.v1.cri\"] sandbox_image = \"registry.aliyuncs.com/google_containers/pause:3.6\" [plugins.\"io.containerd.grpc.v1.cri\".cni] [plugins.\"io.containerd.grpc.v1.cri\".containerd] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime.options] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc.options] SystemdCgroup = true Restart Containerd service. sudo systemctl restart containerd sudo systemctl status containerd Install nerdctl \u00b6 Install nerdctl sevice fro all VMs. The goal of nerdctl is to facilitate experimenting the cutting-edge features of containerd that are not present in Docker. Get the release from the link https://github.com/containerd/nerdctl/releases . wget https://github.com/containerd/nerdctl/releases/download/v0.22.0/nerdctl-0.22.0-linux-amd64.tar.gz tar -zxvf nerdctl-0.22.0-linux-amd64.tar.gz sudo cp nerdctl /usr/bin/ sudo cp containerd-rootless* /usr/bin/ Verify nerdctl. nerdctl --help To list local Kubernetes containers. nerdctl -n k8s.io ps Install kubeadm \u00b6 Update apt-transport-https , ca-certificates , and curl . sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl Install gpg certificate. sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg Add Kubernetes repo. Just choose one of below command and execute. echo \"deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ \\ kubernetes-xenial main\" | sudo tee /etc/apt/sources.list.d/kubernetes.list Update and install dependencied packages. sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables Check available versions of kubeadm. apt policy kubeadm Install 1.24.0-00 version of kubeadm and will upgrade to 1.24.2 later. sudo apt-get -y install kubelet = 1 .24.0-00 kubeadm = 1 .24.0-00 kubectl = 1 .24.0-00 --allow-downgrades Setup Master Node \u00b6 kubeadm init \u00b6 Set up Control Plane on VM playing master node. Check kubeadm default parameters for initialization. kubeadm config print init-defaults Reuslt: apiVersion : kubeadm.k8s.io/v1beta3 bootstrapTokens : - groups : - system:bootstrappers:kubeadm:default-node-token token : abcdef.0123456789abcdef ttl : 24h0m0s usages : - signing - authentication kind : InitConfiguration localAPIEndpoint : advertiseAddress : 1.2.3.4 bindPort : 6443 nodeRegistration : criSocket : unix:///var/run/containerd/containerd.sock imagePullPolicy : IfNotPresent name : node taints : null --- apiServer : timeoutForControlPlane : 4m0s apiVersion : kubeadm.k8s.io/v1beta3 certificatesDir : /etc/kubernetes/pki clusterName : kubernetes controllerManager : {} dns : {} etcd : local : dataDir : /var/lib/etcd imageRepository : k8s.gcr.io kind : ClusterConfiguration kubernetesVersion : 1.24.0 networking : dnsDomain : cluster.local serviceSubnet : 10.96.0.0/12 scheduler : {} Dry rune and run. Save the output, which will be used later on work nodes. With kubeadm init to initiate cluster, we need understand below three options about network. --pod-network-cidr : Specify range of IP addresses for the pod network. If set, the control plane will automatically allocate CIDRs for every node. Be noted that 10.244.0.0/16 is default range of flannel. If it's changed here, please do change the same when deploy Flannel . --apiserver-bind-port : Port for the API Server to bind to. (default 6443) --service-cidr : Use alternative range of IP address for service VIPs. (default \"10.96.0.0/12\") Note: service VIPs (a.k.a. Cluster IP), specified by option --service-cidr . podCIDR (a.k.a. endpoint IP)\uff0cspecified by option --pod-network-cidr . There are 4 distinct networking problems to address: Highly-coupled container-to-container communications: this is solved by Pods (podCIDR) and localhost communications. Pod-to-Pod communications: a.k.a. container-to-container. Example with Flannel, the flow is: Pod \u2192 veth pair \u2192 cni0 \u2192 flannel.1 \u2192 host eth0 \u2192 host eth0 \u2192 flannel.1 \u2192 cni0 \u2192 veth pair \u2192 Pod. Pod-to-Service communications: Flow: Pod \u2192 Kernel \u2192 Servive iptables \u2192 service \u2192 Pod iptables \u2192 Pod External-to-Service communications: LoadBalancer: SLB \u2192 NodePort \u2192 Service \u2192 Pod kube-proxy is responsible for iptables, not traffic. sudo kubeadm init \\ --dry-run \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --kubernetes-version = v1.24.0 kubeconfig file \u00b6 Set kubeconfig file for current user (here it's james ). mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Kubernetes provides a command line tool kubectl for communicating with a Kubernetes cluster's control plane, using the Kubernetes API. kubectl controls the Kubernetes cluster manager . For configuration, kubectl looks for a file named config in the $HOME/.kube directory, which is a copy of file /etc/kubernetes/admin.conf generated by kubeadm init . We can specify other kubeconfig files by setting the KUBECONFIG environment variable or by setting the --kubeconfig flag . If the KUBECONFIG environment variable doesn't exist, kubectl uses the default kubeconfig file, $HOME/.kube/config . A context element in a kubeconfig file is used to group access parameters under a convenient name. Each context has three parameters: cluster, namespace, and user. By default, the kubectl command-line tool uses parameters from the current context to communicate with the cluster. A sample of .kube/config . apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : To get the current context: kubectl config get-contexts Result CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin Setup Work Nodes \u00b6 Perform on all VMs playing work nodes. # kubeadm join :6443 --token --discovery-token-ca-cert-hash Use kubeadm token to generate the join token and hash value. kubeadm token create --print-join-command Execute the command generated above on each node that we want to join the cluster as Worker node. Verify status on master node. All nodes' status is NotReady . Leave it at the moment and continue to install network plugin. kubectl get node -o wide Install Calico or Flannel \u00b6 Choose Calico or Flannel on control plane node. For NetworkPolicy purpose, choose Calico. Install Flannel \u00b6 Flannel is a simple and easy way to configure a layer 3 network fabric designed for Kubernetes. Deploy Flannel. In the kube-flannel.yml we can get the default network setting of Flannel, which is same with --pod-network-cidr=10.244.0.0/16 we defined before when we initiated kubeadm . net-conf.json : | { \"Network\": \"10.244.0.0/16\", \"Backend\": { \"Type\": \"vxlan\" } } Create Flannel apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml Result Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy/psp.flannel.unprivileged created clusterrole.rbac.authorization.k8s.io/flannel created clusterrolebinding.rbac.authorization.k8s.io/flannel created serviceaccount/flannel created configmap/kube-flannel-cfg created daemonset.apps/kube-flannel-ds created Install Calico \u00b6 Here is guidance of End-to-end Calico installation . Detail practice demo, can be found in section \"Install Calico\" of \"A1.Discussion\" below. Install Calico curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Result configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created Verify status of Calico. kubectl get pod -n kube-system | grep calico Result calico-kube-controllers-555bc4b957-l8bn2 0/1 Pending 0 28s calico-node-255pc 0/1 Init:1/3 0 29s calico-node-7tmnb 0/1 Init:1/3 0 29s calico-node-w8nvl 0/1 Init:1/3 0 29s Verify network status. sudo nerdctl network ls Result NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none Check Cluster Status \u00b6 Perform kubectl cluster-info command on master node we will get below information. Kubernetes control plane is running at https://:6443 CoreDNS is running at https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy kubectl cluster-info Get nodes status. kubectl get nodes -owide All nodes are up with normal status. OS Image: Ubuntu 20.04.4 LTS Kernel Version: 5.4.0-122-generic Container Runtime: containerd://1.5.9 NAME STATUS ROLES AGE VERSION cka001 Ready control-plane 13m v1.24.0 cka002 Ready 8m35s v1.24.0 cka003 Ready 8m26s v1.24.0 Get pods status kubectl get pod -A Result: NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 7m18s kube-system calico-node-255pc 1/1 Running 0 7m19s kube-system calico-node-7tmnb 1/1 Running 0 7m19s kube-system calico-node-w8nvl 1/1 Running 0 7m19s kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15m kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15m kube-system etcd-cka001 1/1 Running 0 15m kube-system kube-apiserver-cka001 1/1 Running 0 15m kube-system kube-controller-manager-cka001 1/1 Running 0 15m kube-system kube-proxy-dmj2t 1/1 Running 0 15m kube-system kube-proxy-n77zw 1/1 Running 0 11m kube-system kube-proxy-qs6rf 1/1 Running 0 11m kube-system kube-scheduler-cka001 1/1 Running 0 15m Reset cluster \u00b6 CAUTION: below steps will destroy current cluster. Delete all nodes in the cluster. kubeadm reset Output: [reset] Reading configuration from the cluster... [reset] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' W0717 08:15:17.411992 3913615 preflight.go:55] [reset] WARNING: Changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted. [reset] Are you sure you want to proceed? [y/N]: y [preflight] Running pre-flight checks [reset] Stopping the kubelet service [reset] Unmounting mounted directories in \"/var/lib/kubelet\" [reset] Deleting contents of directories: [/etc/kubernetes/manifests /etc/kubernetes/pki] [reset] Deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf] [reset] Deleting contents of stateful directories: [/var/lib/etcd /var/lib/kubelet /var/lib/dockershim /var/run/kubernetes /var/lib/cni] The reset process does not clean CNI configuration. To do so, you must remove /etc/cni/net.d The reset process does not reset or clean up iptables rules or IPVS tables. If you wish to reset iptables, you must do so manually by using the \"iptables\" command. If your cluster was setup to utilize IPVS, run ipvsadm --clear (or similar) to reset your system's IPVS tables. The reset process does not clean your kubeconfig files and you must remove them manually. Please, check the contents of the $HOME/.kube/config file. Clean up network setting rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni Clean up rule of iptables . iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Clean up rule of IPVS if using IPVS . ipvsadm --clear Troubleshooting \u00b6 Issue 1 \u00b6 The connection to the server :6443 was refused - did you specify the right host or port? Try : Reference Check if the kubeconfig file is update to udpate and exists in right place. Check environment setting. env | grep -i kub Check container status. sudo systemctl status containerd.service Check kubelet service. sudo systemctl status kubelet.service Check port listening status. netstat -pnlt | grep 6443 Check firewall status. sudo systemctl status firewalld.service Check log. journalctl -xeu kubelet Issue 2 \u00b6 \"Container runtime network not ready\" networkReady=\"NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized\" Try : Restart Containerd service. sudo systemctl restart containerd sudo systemctl status containerd Post Installation \u00b6 Bash Autocomplete \u00b6 On each node. Set kubectl auto-completion following the guideline . apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc Alias \u00b6 If we set an alias for kubectl, we can extend shell completion to work with that alias: echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc Update Default Context \u00b6 Get current context. kubectl config get-contexts In below result, we know: Contenxt name is kubernetes-admin@kubernetes . Cluster name is kubernetes . User is kubernetes-admin . No namespace explicitly defined. CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin To set a context with new update, e.g, update default namespace, etc.. # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin To switch to a new context. kubectl config use-context kubectl config use-context kubernetes-admin@kubernetes Reference of kubectl and commandline .","title":"Installation on Aliyun ECS"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#installation-on-aliyun-ubuntu","text":"","title":"Installation on Aliyun Ubuntu"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#preparation","text":"Register Aliyun account via Alibaba Cloud home console . Request three Elastic Computer Service(ECS) instances with below sizing: System: 2vCPU+4GiB OS: Ubuntu 20.04 x86_64 Instance Type: ecs.sn1.medium Instance Name: cka001, cka002, cka003 Network: both public IPs and private IPs Maximum Bandwidth: 100Mbps (Peak Value) Cloud disk: 40GiB Billing Method: Preemptible instance (spot price) Open a local terminal, log onto remote ECS cka001 using the key pair (e.g., aliyun-root ) from Aliyun cloud. ssh -i aliyun-root root@cka001 Create a common user (e.g., james ), and set primary group as sudo and other group as root . adduser james usermod -g sudo james usermod -a -G root james Back to the local terminal, generate key for common user james by below command. # Windows ssh-keygen.exe # Linux ssh-keygen Two files will be created, e.g., aliyun-james and aliyun-james.pub Upload the public key aliyun-james.pub to remote cka001 using sftp command. sftp -i aliyun-root root@cka001 put aliyun-james.pub Log onto remote ECS cka001 using root account again. Move the key aliyun-james.pub to /home/james/.ssh/ . Rename file aliyun-james.pub to authorized_keys . Change ower of file authorized_keys to james . Change default group of file authorized_keys to sudo . mkdir /home/james/.ssh/ mv aliyun-james.pub /home/james/.ssh/authorized_keys chown james.sudo /home/james/.ssh/authorized_keys chmod 600 /home/james/.ssh/authorized_keys Check file /etc/ssh/sshd_config , make sure password authentication is disabled PasswordAuthentication no cat /etc/ssh/sshd_config Back to the local terminal, use james to log onto remote cka001 . ssh -i aliyun-james james@cka001 Upload the public key aliyun-james.pub to remote cka002 and cka003 using sftp command and do the same set up on cka002 and cka003 in order to enable user james to log onto cka002 and cka003 . Till now, user james can log onto cka001 , cka002 and cka003 using key aliyun-james . All demo below will be done by user james .","title":"Preparation"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#initialize-vms","text":"","title":"Initialize VMs"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#configure-etchosts-file","text":"Add private IPs in the /etc/hosts file in all VMs. vi /etc/hosts","title":"Configure /etc/hosts file"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#disable-firewall","text":"Disable firewall by command ufw disable in all VMs. Disable swap on Ubuntu. sudo ufw disable Check status of swap on Ubuntu. sudo ufw status verbose","title":"Disable firewall"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#turn-off-swap","text":"Turn off swap in all VMs. sudo swapoff -a","title":"Turn off swap"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#set-timezone-and-locale","text":"Set timezone and local for all VMs. This step was already done during Aliyun ECS installation. ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile Something like this: ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 5 14 :51 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai","title":"Set timezone and locale"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#kernel-setting","text":"Perform below kernel setting in all VMs. Create file /etc/modules-load.d/containerd.conf to set up containerd configure file. It's to load two modules overlay and br_netfilter . Service containerd depends on overlay filesystem. Sometimes referred to as union-filesystems. An overlay-filesystem tries to present a filesystem which is the result over overlaying one filesystem on top of the other. The br_netfilter module is required to enable transparent masquerading and to facilitate Virtual Extensible LAN (VxLAN) traffic for communication between Kubernetes pods across the cluster. cat < /etc/apt/sources.list << EOF deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates universe deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-updates multiverse deb http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multiverse deb-src http://mirrors.cloud.aliyuncs.com/ubuntu/ focal-backports main restricted universe multivers deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security main restricted deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security universe # deb http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse # deb-src http://mirrors.cloud.aliyuncs.com/ubuntu focal-security multiverse EOF Install Containered. sudo apt-get update && sudo apt-get install -y containerd Configure Containerd. Modify file /etc/containerd/config.toml . sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml Update sandbox_image with new value \"registry.aliyuncs.com/google_containers/pause:3.6\" . Update SystemdCgroup with new value true . [plugins] [plugins.\"io.containerd.gc.v1.scheduler\"] [plugins.\"io.containerd.grpc.v1.cri\"] sandbox_image = \"registry.aliyuncs.com/google_containers/pause:3.6\" [plugins.\"io.containerd.grpc.v1.cri\".cni] [plugins.\"io.containerd.grpc.v1.cri\".containerd] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime] [plugins.\"io.containerd.grpc.v1.cri\".containerd.default_runtime.options] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc] [plugins.\"io.containerd.grpc.v1.cri\".containerd.runtimes.runc.options] SystemdCgroup = true Restart Containerd service. sudo systemctl restart containerd sudo systemctl status containerd","title":"Install Containerd"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#install-nerdctl","text":"Install nerdctl sevice fro all VMs. The goal of nerdctl is to facilitate experimenting the cutting-edge features of containerd that are not present in Docker. Get the release from the link https://github.com/containerd/nerdctl/releases . wget https://github.com/containerd/nerdctl/releases/download/v0.22.0/nerdctl-0.22.0-linux-amd64.tar.gz tar -zxvf nerdctl-0.22.0-linux-amd64.tar.gz sudo cp nerdctl /usr/bin/ sudo cp containerd-rootless* /usr/bin/ Verify nerdctl. nerdctl --help To list local Kubernetes containers. nerdctl -n k8s.io ps","title":"Install nerdctl"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#install-kubeadm","text":"Update apt-transport-https , ca-certificates , and curl . sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl Install gpg certificate. sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg Add Kubernetes repo. Just choose one of below command and execute. echo \"deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ \\ kubernetes-xenial main\" | sudo tee /etc/apt/sources.list.d/kubernetes.list Update and install dependencied packages. sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables Check available versions of kubeadm. apt policy kubeadm Install 1.24.0-00 version of kubeadm and will upgrade to 1.24.2 later. sudo apt-get -y install kubelet = 1 .24.0-00 kubeadm = 1 .24.0-00 kubectl = 1 .24.0-00 --allow-downgrades","title":"Install kubeadm"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#setup-master-node","text":"","title":"Setup Master Node"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#kubeadm-init","text":"Set up Control Plane on VM playing master node. Check kubeadm default parameters for initialization. kubeadm config print init-defaults Reuslt: apiVersion : kubeadm.k8s.io/v1beta3 bootstrapTokens : - groups : - system:bootstrappers:kubeadm:default-node-token token : abcdef.0123456789abcdef ttl : 24h0m0s usages : - signing - authentication kind : InitConfiguration localAPIEndpoint : advertiseAddress : 1.2.3.4 bindPort : 6443 nodeRegistration : criSocket : unix:///var/run/containerd/containerd.sock imagePullPolicy : IfNotPresent name : node taints : null --- apiServer : timeoutForControlPlane : 4m0s apiVersion : kubeadm.k8s.io/v1beta3 certificatesDir : /etc/kubernetes/pki clusterName : kubernetes controllerManager : {} dns : {} etcd : local : dataDir : /var/lib/etcd imageRepository : k8s.gcr.io kind : ClusterConfiguration kubernetesVersion : 1.24.0 networking : dnsDomain : cluster.local serviceSubnet : 10.96.0.0/12 scheduler : {} Dry rune and run. Save the output, which will be used later on work nodes. With kubeadm init to initiate cluster, we need understand below three options about network. --pod-network-cidr : Specify range of IP addresses for the pod network. If set, the control plane will automatically allocate CIDRs for every node. Be noted that 10.244.0.0/16 is default range of flannel. If it's changed here, please do change the same when deploy Flannel . --apiserver-bind-port : Port for the API Server to bind to. (default 6443) --service-cidr : Use alternative range of IP address for service VIPs. (default \"10.96.0.0/12\") Note: service VIPs (a.k.a. Cluster IP), specified by option --service-cidr . podCIDR (a.k.a. endpoint IP)\uff0cspecified by option --pod-network-cidr . There are 4 distinct networking problems to address: Highly-coupled container-to-container communications: this is solved by Pods (podCIDR) and localhost communications. Pod-to-Pod communications: a.k.a. container-to-container. Example with Flannel, the flow is: Pod \u2192 veth pair \u2192 cni0 \u2192 flannel.1 \u2192 host eth0 \u2192 host eth0 \u2192 flannel.1 \u2192 cni0 \u2192 veth pair \u2192 Pod. Pod-to-Service communications: Flow: Pod \u2192 Kernel \u2192 Servive iptables \u2192 service \u2192 Pod iptables \u2192 Pod External-to-Service communications: LoadBalancer: SLB \u2192 NodePort \u2192 Service \u2192 Pod kube-proxy is responsible for iptables, not traffic. sudo kubeadm init \\ --dry-run \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --image-repository = registry.aliyuncs.com/google_containers \\ --kubernetes-version = v1.24.0 sudo kubeadm init \\ --pod-network-cidr = 10 .244.0.0/16 \\ --service-cidr 11 .244.0.0/16 \\ --kubernetes-version = v1.24.0","title":"kubeadm init"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#kubeconfig-file","text":"Set kubeconfig file for current user (here it's james ). mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Kubernetes provides a command line tool kubectl for communicating with a Kubernetes cluster's control plane, using the Kubernetes API. kubectl controls the Kubernetes cluster manager . For configuration, kubectl looks for a file named config in the $HOME/.kube directory, which is a copy of file /etc/kubernetes/admin.conf generated by kubeadm init . We can specify other kubeconfig files by setting the KUBECONFIG environment variable or by setting the --kubeconfig flag . If the KUBECONFIG environment variable doesn't exist, kubectl uses the default kubeconfig file, $HOME/.kube/config . A context element in a kubeconfig file is used to group access parameters under a convenient name. Each context has three parameters: cluster, namespace, and user. By default, the kubectl command-line tool uses parameters from the current context to communicate with the cluster. A sample of .kube/config . apiVersion : v1 clusters : - cluster : certificate-authority-data : server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : To get the current context: kubectl config get-contexts Result CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin","title":"kubeconfig file"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#setup-work-nodes","text":"Perform on all VMs playing work nodes. # kubeadm join :6443 --token --discovery-token-ca-cert-hash Use kubeadm token to generate the join token and hash value. kubeadm token create --print-join-command Execute the command generated above on each node that we want to join the cluster as Worker node. Verify status on master node. All nodes' status is NotReady . Leave it at the moment and continue to install network plugin. kubectl get node -o wide","title":"Setup Work Nodes"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#install-calico-or-flannel","text":"Choose Calico or Flannel on control plane node. For NetworkPolicy purpose, choose Calico.","title":"Install Calico or Flannel"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#install-flannel","text":"Flannel is a simple and easy way to configure a layer 3 network fabric designed for Kubernetes. Deploy Flannel. In the kube-flannel.yml we can get the default network setting of Flannel, which is same with --pod-network-cidr=10.244.0.0/16 we defined before when we initiated kubeadm . net-conf.json : | { \"Network\": \"10.244.0.0/16\", \"Backend\": { \"Type\": \"vxlan\" } } Create Flannel apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml Result Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+ podsecuritypolicy.policy/psp.flannel.unprivileged created clusterrole.rbac.authorization.k8s.io/flannel created clusterrolebinding.rbac.authorization.k8s.io/flannel created serviceaccount/flannel created configmap/kube-flannel-cfg created daemonset.apps/kube-flannel-ds created","title":"Install Flannel"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#install-calico","text":"Here is guidance of End-to-end Calico installation . Detail practice demo, can be found in section \"Install Calico\" of \"A1.Discussion\" below. Install Calico curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Result configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created Verify status of Calico. kubectl get pod -n kube-system | grep calico Result calico-kube-controllers-555bc4b957-l8bn2 0/1 Pending 0 28s calico-node-255pc 0/1 Init:1/3 0 29s calico-node-7tmnb 0/1 Init:1/3 0 29s calico-node-w8nvl 0/1 Init:1/3 0 29s Verify network status. sudo nerdctl network ls Result NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 0 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none","title":"Install Calico"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#check-cluster-status","text":"Perform kubectl cluster-info command on master node we will get below information. Kubernetes control plane is running at https://:6443 CoreDNS is running at https://:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy kubectl cluster-info Get nodes status. kubectl get nodes -owide All nodes are up with normal status. OS Image: Ubuntu 20.04.4 LTS Kernel Version: 5.4.0-122-generic Container Runtime: containerd://1.5.9 NAME STATUS ROLES AGE VERSION cka001 Ready control-plane 13m v1.24.0 cka002 Ready 8m35s v1.24.0 cka003 Ready 8m26s v1.24.0 Get pods status kubectl get pod -A Result: NAMESPACE NAME READY STATUS RESTARTS AGE kube-system calico-kube-controllers-555bc4b957-l8bn2 1/1 Running 0 7m18s kube-system calico-node-255pc 1/1 Running 0 7m19s kube-system calico-node-7tmnb 1/1 Running 0 7m19s kube-system calico-node-w8nvl 1/1 Running 0 7m19s kube-system coredns-74586cf9b6-4jwmk 1/1 Running 0 15m kube-system coredns-74586cf9b6-c5mll 1/1 Running 0 15m kube-system etcd-cka001 1/1 Running 0 15m kube-system kube-apiserver-cka001 1/1 Running 0 15m kube-system kube-controller-manager-cka001 1/1 Running 0 15m kube-system kube-proxy-dmj2t 1/1 Running 0 15m kube-system kube-proxy-n77zw 1/1 Running 0 11m kube-system kube-proxy-qs6rf 1/1 Running 0 11m kube-system kube-scheduler-cka001 1/1 Running 0 15m","title":"Check Cluster Status"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#reset-cluster","text":"CAUTION: below steps will destroy current cluster. Delete all nodes in the cluster. kubeadm reset Output: [reset] Reading configuration from the cluster... [reset] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' W0717 08:15:17.411992 3913615 preflight.go:55] [reset] WARNING: Changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted. [reset] Are you sure you want to proceed? [y/N]: y [preflight] Running pre-flight checks [reset] Stopping the kubelet service [reset] Unmounting mounted directories in \"/var/lib/kubelet\" [reset] Deleting contents of directories: [/etc/kubernetes/manifests /etc/kubernetes/pki] [reset] Deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf] [reset] Deleting contents of stateful directories: [/var/lib/etcd /var/lib/kubelet /var/lib/dockershim /var/run/kubernetes /var/lib/cni] The reset process does not clean CNI configuration. To do so, you must remove /etc/cni/net.d The reset process does not reset or clean up iptables rules or IPVS tables. If you wish to reset iptables, you must do so manually by using the \"iptables\" command. If your cluster was setup to utilize IPVS, run ipvsadm --clear (or similar) to reset your system's IPVS tables. The reset process does not clean your kubeconfig files and you must remove them manually. Please, check the contents of the $HOME/.kube/config file. Clean up network setting rm -rf /var/run/flannel /opt/cni /etc/cni /var/lib/cni Clean up rule of iptables . iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Clean up rule of IPVS if using IPVS . ipvsadm --clear","title":"Reset cluster"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#troubleshooting","text":"","title":"Troubleshooting"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#issue-1","text":"The connection to the server :6443 was refused - did you specify the right host or port? Try : Reference Check if the kubeconfig file is update to udpate and exists in right place. Check environment setting. env | grep -i kub Check container status. sudo systemctl status containerd.service Check kubelet service. sudo systemctl status kubelet.service Check port listening status. netstat -pnlt | grep 6443 Check firewall status. sudo systemctl status firewalld.service Check log. journalctl -xeu kubelet","title":"Issue 1"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#issue-2","text":"\"Container runtime network not ready\" networkReady=\"NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: cni plugin not initialized\" Try : Restart Containerd service. sudo systemctl restart containerd sudo systemctl status containerd","title":"Issue 2"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#post-installation","text":"","title":"Post Installation"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#bash-autocomplete","text":"On each node. Set kubectl auto-completion following the guideline . apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc","title":"Bash Autocomplete"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#alias","text":"If we set an alias for kubectl, we can extend shell completion to work with that alias: echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc","title":"Alias"},{"location":"k8s/cka_en/installation/aliyun-ubuntu/#update-default-context","text":"Get current context. kubectl config get-contexts In below result, we know: Contenxt name is kubernetes-admin@kubernetes . Cluster name is kubernetes . User is kubernetes-admin . No namespace explicitly defined. CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin To set a context with new update, e.g, update default namespace, etc.. # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin To switch to a new context. kubectl config use-context kubectl config use-context kubernetes-admin@kubernetes Reference of kubectl and commandline .","title":"Update Default Context"},{"location":"k8s/cka_en/installation/multiple-local/","text":"Multiple Nodes Installation \u00b6 Local VM setting \u00b6 VMWare Setting. VMnet1: host-only, subnet: 192.168.150.0/24 VMnet8: NAT, subnet: 11.0.1.0/24 Create guest machine with VMWare Player. 4 GB RAM 1 CPUs with 2 Cores Ubuntu Server 22.04 NAT Info: Kubernetes running on Containerd. Ubuntu Post Installation \u00b6 Info: Log onto each VM with the account created during Ubuntu installation, and perform below tasks on every VM. Create user vagrant on all guests. sudo adduser vagrant sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd,root vagrant sudo passwd vagrant Set password for root on all guests. sudo passwd root Enable root ssh logon. sudo vi /etc/ssh/sshd_config Update parameter PermitRootLogin from prohibit-password to yes . PermitRootLogin yes # PermitRootLogin prohibit-password Restart the sshd service. sudo systemctl restart sshd Change host name, e.g., ubu1 . sudo hostnamectl set-hostname ubu1 sudo hostnamectl set-hostname ubu1 --pretty Verify if the hostname is set to expected name, e.g., ubu1 . cat /etc/machine-info Verify if the hostname is set to expected name, e.g., ubu1 . cat /etc/hostname Verify if the hostname of 127.0.1.1 is set to expected name, e.g., ubu1 . And add all nodes into the file /etc/hosts . sudo vi /etc/hosts Related setting looks like below. 127.0.1.1 ubu1 11.0.1.129 ubu1 11.0.1.130 ubu2 11.0.1.131 ubu3 11.0.1.132 ubu4 Create file /etc/netplan/00-installer-config.yaml . sudo vi /etc/netplan/00-installer-config.yaml Update it with information below to set VM with fixed IP with actual IP address, e.g, 11.0.1.129 . network : ethernets : ens33 : dhcp4 : false addresses : - 11.0.1.129/24 nameservers : addresses : - 11.0.1.2 routes : - to : default via : 11.0.1.2 version : 2 Effect above change. sudo netplan apply Attention: The current ssh connection will be broken due to network setting change. Disable swap and firewall on all nodes. sudo swapoff -a sudo ufw disable sudo ufw status verbose And comment the last line of swap setting in file /etc/fstab . Need reboot guest here. sudo vi /etc/fstab Result likes below. /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 Setup timezone on all nodes sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo cp /etc/profile /etc/profile.bak echo 'LANG=\"en_US.UTF-8\"' | sudo tee -a /etc/profile source /etc/profile Something like this after execute command ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai Kernel setting. cat < server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : To get the current context: kubectl config get-contexts Result CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin Install Calico \u00b6 Here is guidance of End-to-end Calico installation . Detail practice demo, can be found in section \"Install Calico\" of \"A1.Discussion\" below. Install Calico curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Result configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created Verify status of Calico. It may take minutes to complete initialization. kubectl get pod -n kube-system | grep calico Result calico-kube-controllers-555bc4b957-l8bn2 0/1 Pending 0 28s calico-node-255pc 0/1 Init:1/3 0 29s calico-node-7tmnb 0/1 Init:1/3 0 29s calico-node-w8nvl 0/1 Init:1/3 0 29s Verify network status. sudo nerdctl network ls Result NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 17f29b073143 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none Setup Work Nodes \u00b6 Use kubeadm token to generate the join token and hash value. kubeadm token create --print-join-command Command usage: sudo kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> Result looks like below. [preflight] Running pre-flight checks [WARNING SystemVerification]: missing optional cgroups: blkio [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [kubelet-start] Writing kubelet configuration to file \"/var/lib/kubelet/config.yaml\" [kubelet-start] Writing kubelet environment file with flags to file \"/var/lib/kubelet/kubeadm-flags.env\" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster. Check Cluster Status \u00b6 Cluster info: kubectl cluster-info Output Kubernetes control plane is running at https://11.0.1.129:6443 CoreDNS is running at https://11.0.1.129:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. Node info: kubectl get nodes -owide Pod info: kubectl get pod -A Post Installation \u00b6 Bash Autocomplete \u00b6 On each node. Set kubectl auto-completion following the guideline . apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc source ~/.bashrc Alias \u00b6 If we set an alias for kubectl, we can extend shell completion to work with that alias: echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc Update Default Context \u00b6 Get current context. kubectl config get-contexts In below result, we know: Contenxt name is kubernetes-admin@kubernetes . Cluster name is kubernetes . User is kubernetes-admin . No namespace explicitly defined. CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin To set a context with new update, e.g, update default namespace, etc.. # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin To switch to a new context. kubectl config use-context kubectl config use-context kubernetes-admin@kubernetes Reference: kubectl commandline Install Helm \u00b6 Helm is the Kubernetes package manager. It doesn't come with Kubernetes. Three concepts of helm: A Chart is a Helm package. It contains all of the resource definitions necessary to run an application, tool, or service inside of a Kubernetes cluster. Think of it like the Kubernetes equivalent of a Homebrew formula, an Apt dpkg, or a Yum RPM file. A Repository is the place where charts can be collected and shared. It's like Perl's CPAN archive or the Fedora Package Database, but for Kubernetes packages. A Release is an instance of a chart running in a Kubernetes cluster. One chart can often be installed many times into the same cluster. And each time it is installed, a new release is created. Consider a MySQL chart. If you want two databases running in your cluster, you can install that chart twice. Each one will have its own release, which will in turn have its own release name. Reference: installation guide binary release source code . Helm Client Installation: curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh Output: Downloading https://get.helm.sh/helm-v3.9.1-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm Note: helm init does not exist in Helm 3, following the removal of Tiller. You no longer need to install Tiller in your cluster in order to use Helm. helm search can be used to search two different types of source: helm search hub searches the Artifact Hub , which lists helm charts from dozens of different repositories. helm search repo searches the repositories that you have added to your local helm client (with helm repo add). This search is done over local data, and no public network connection is needed. Reference: Helming development Reset cluster \u00b6 Caution: below steps will destroy current cluster. Delete all nodes in the cluster. kubeadm reset Clean up rule of iptables . iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Clean up rule of IPVS if using IPVS . ipvsadm --clear","title":"Multiple Nodes Installation"},{"location":"k8s/cka_en/installation/multiple-local/#multiple-nodes-installation","text":"","title":"Multiple Nodes Installation"},{"location":"k8s/cka_en/installation/multiple-local/#local-vm-setting","text":"VMWare Setting. VMnet1: host-only, subnet: 192.168.150.0/24 VMnet8: NAT, subnet: 11.0.1.0/24 Create guest machine with VMWare Player. 4 GB RAM 1 CPUs with 2 Cores Ubuntu Server 22.04 NAT Info: Kubernetes running on Containerd.","title":"Local VM setting"},{"location":"k8s/cka_en/installation/multiple-local/#ubuntu-post-installation","text":"Info: Log onto each VM with the account created during Ubuntu installation, and perform below tasks on every VM. Create user vagrant on all guests. sudo adduser vagrant sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd,root vagrant sudo passwd vagrant Set password for root on all guests. sudo passwd root Enable root ssh logon. sudo vi /etc/ssh/sshd_config Update parameter PermitRootLogin from prohibit-password to yes . PermitRootLogin yes # PermitRootLogin prohibit-password Restart the sshd service. sudo systemctl restart sshd Change host name, e.g., ubu1 . sudo hostnamectl set-hostname ubu1 sudo hostnamectl set-hostname ubu1 --pretty Verify if the hostname is set to expected name, e.g., ubu1 . cat /etc/machine-info Verify if the hostname is set to expected name, e.g., ubu1 . cat /etc/hostname Verify if the hostname of 127.0.1.1 is set to expected name, e.g., ubu1 . And add all nodes into the file /etc/hosts . sudo vi /etc/hosts Related setting looks like below. 127.0.1.1 ubu1 11.0.1.129 ubu1 11.0.1.130 ubu2 11.0.1.131 ubu3 11.0.1.132 ubu4 Create file /etc/netplan/00-installer-config.yaml . sudo vi /etc/netplan/00-installer-config.yaml Update it with information below to set VM with fixed IP with actual IP address, e.g, 11.0.1.129 . network : ethernets : ens33 : dhcp4 : false addresses : - 11.0.1.129/24 nameservers : addresses : - 11.0.1.2 routes : - to : default via : 11.0.1.2 version : 2 Effect above change. sudo netplan apply Attention: The current ssh connection will be broken due to network setting change. Disable swap and firewall on all nodes. sudo swapoff -a sudo ufw disable sudo ufw status verbose And comment the last line of swap setting in file /etc/fstab . Need reboot guest here. sudo vi /etc/fstab Result likes below. /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 Setup timezone on all nodes sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo cp /etc/profile /etc/profile.bak echo 'LANG=\"en_US.UTF-8\"' | sudo tee -a /etc/profile source /etc/profile Something like this after execute command ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 15 22:00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai Kernel setting. cat < server : https://:6443 name : contexts : - context : cluster : namespace : user : name : @ current-context : kind : Config preferences : {} users : - name : user : client-certificate-data : client-key-data : To get the current context: kubectl config get-contexts Result CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin","title":"kubeconfig file"},{"location":"k8s/cka_en/installation/multiple-local/#install-calico","text":"Here is guidance of End-to-end Calico installation . Detail practice demo, can be found in section \"Install Calico\" of \"A1.Discussion\" below. Install Calico curl https://docs.projectcalico.org/manifests/calico.yaml -O kubectl apply -f calico.yaml Result configmap/calico-config created customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/caliconodestatuses.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/ipreservations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/kubecontrollersconfigurations.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created clusterrole.rbac.authorization.k8s.io/calico-node created clusterrolebinding.rbac.authorization.k8s.io/calico-node created daemonset.apps/calico-node created serviceaccount/calico-node created deployment.apps/calico-kube-controllers created serviceaccount/calico-kube-controllers created poddisruptionbudget.policy/calico-kube-controllers created Verify status of Calico. It may take minutes to complete initialization. kubectl get pod -n kube-system | grep calico Result calico-kube-controllers-555bc4b957-l8bn2 0/1 Pending 0 28s calico-node-255pc 0/1 Init:1/3 0 29s calico-node-7tmnb 0/1 Init:1/3 0 29s calico-node-w8nvl 0/1 Init:1/3 0 29s Verify network status. sudo nerdctl network ls Result NETWORK ID NAME FILE k8s-pod-network /etc/cni/net.d/10-calico.conflist 17f29b073143 bridge /etc/cni/net.d/nerdctl-bridge.conflist host none","title":"Install Calico"},{"location":"k8s/cka_en/installation/multiple-local/#setup-work-nodes","text":"Use kubeadm token to generate the join token and hash value. kubeadm token create --print-join-command Command usage: sudo kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> Result looks like below. [preflight] Running pre-flight checks [WARNING SystemVerification]: missing optional cgroups: blkio [preflight] Reading configuration from the cluster... [preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml' [kubelet-start] Writing kubelet configuration to file \"/var/lib/kubelet/config.yaml\" [kubelet-start] Writing kubelet environment file with flags to file \"/var/lib/kubelet/kubeadm-flags.env\" [kubelet-start] Starting the kubelet [kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap... This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the control-plane to see this node join the cluster.","title":"Setup Work Nodes"},{"location":"k8s/cka_en/installation/multiple-local/#check-cluster-status","text":"Cluster info: kubectl cluster-info Output Kubernetes control plane is running at https://11.0.1.129:6443 CoreDNS is running at https://11.0.1.129:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. Node info: kubectl get nodes -owide Pod info: kubectl get pod -A","title":"Check Cluster Status"},{"location":"k8s/cka_en/installation/multiple-local/#post-installation","text":"","title":"Post Installation"},{"location":"k8s/cka_en/installation/multiple-local/#bash-autocomplete","text":"On each node. Set kubectl auto-completion following the guideline . apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc source ~/.bashrc","title":"Bash Autocomplete"},{"location":"k8s/cka_en/installation/multiple-local/#alias","text":"If we set an alias for kubectl, we can extend shell completion to work with that alias: echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc","title":"Alias"},{"location":"k8s/cka_en/installation/multiple-local/#update-default-context","text":"Get current context. kubectl config get-contexts In below result, we know: Contenxt name is kubernetes-admin@kubernetes . Cluster name is kubernetes . User is kubernetes-admin . No namespace explicitly defined. CURRENT NAME CLUSTER AUTHINFO NAMESPACE * kubernetes-admin@kubernetes kubernetes kubernetes-admin To set a context with new update, e.g, update default namespace, etc.. # Usage: kubectl config set-context --cluster = --namespace = --user = # Set default namespace kubectl config set-context kubernetes-admin@kubernetes --cluster = kubernetes --namespace = default --user = kubernetes-admin To switch to a new context. kubectl config use-context kubectl config use-context kubernetes-admin@kubernetes Reference: kubectl commandline","title":"Update Default Context"},{"location":"k8s/cka_en/installation/multiple-local/#install-helm","text":"Helm is the Kubernetes package manager. It doesn't come with Kubernetes. Three concepts of helm: A Chart is a Helm package. It contains all of the resource definitions necessary to run an application, tool, or service inside of a Kubernetes cluster. Think of it like the Kubernetes equivalent of a Homebrew formula, an Apt dpkg, or a Yum RPM file. A Repository is the place where charts can be collected and shared. It's like Perl's CPAN archive or the Fedora Package Database, but for Kubernetes packages. A Release is an instance of a chart running in a Kubernetes cluster. One chart can often be installed many times into the same cluster. And each time it is installed, a new release is created. Consider a MySQL chart. If you want two databases running in your cluster, you can install that chart twice. Each one will have its own release, which will in turn have its own release name. Reference: installation guide binary release source code . Helm Client Installation: curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh Output: Downloading https://get.helm.sh/helm-v3.9.1-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm Note: helm init does not exist in Helm 3, following the removal of Tiller. You no longer need to install Tiller in your cluster in order to use Helm. helm search can be used to search two different types of source: helm search hub searches the Artifact Hub , which lists helm charts from dozens of different repositories. helm search repo searches the repositories that you have added to your local helm client (with helm repo add). This search is done over local data, and no public network connection is needed. Reference: Helming development","title":"Install Helm"},{"location":"k8s/cka_en/installation/multiple-local/#reset-cluster","text":"Caution: below steps will destroy current cluster. Delete all nodes in the cluster. kubeadm reset Clean up rule of iptables . iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Clean up rule of IPVS if using IPVS . ipvsadm --clear","title":"Reset cluster"},{"location":"k8s/cka_en/installation/single-local/","text":"Single Node Installation \u00b6 Local VM setting \u00b6 VMWare Setting. VMnet1: host-only, subnet: 192.168.150.0/24 VMnet8: NAT, subnet: 11.0.1.0/24 Create guest machine with VMWare Player. 4 GB RAM 2 CPUs with 2 Cores Ubuntu Server 22.04 NAT Kubernetes running on Docker. Ubuntu Post Installation \u00b6 Create user vagrant . sudo adduser vagrant sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd vagrant sudo passwd vagrant Set password for root . sudo passwd root Update guest's hostname. Here it's ubusvr . sudo hostnamectl set-hostname ubusvr sudo hostnamectl set-hostname ubusvr --pretty Verify if the hostname is set to ubusvr . cat /etc/machine-info Verify if the hostname is set to ubusvr . cat /etc/hostname Verify if the hostname of 127.0.1.1 is set to ubusvr . cat /etc/hosts 127 .0.0.1 localhost 127 .0.1.1 ubusrv # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters Set guest with fix ip, e.g, 11.0.1.136 . sudo vi 00 -installer-config.yaml network: ethernets: ens33: dhcp4: false addresses: - 11 .0.1.136/24 nameservers: addresses: - 11 .0.1.2 routes: - to: default via: 11 .0.1.2 version: 2 sudo netplan apply Disable swap sudo swapoff -a sudo ufw disable sudo ufw status verbose And comment the last line of swap setting in file /etc/fstab . Need reboot guest here. /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 Setup timezone sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile Something like this after execute command ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 15 22 :00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai Kernel setting cat < /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl status docker.service sudo systemctl status containerd.service sudo groupadd docker sudo usermod -aG docker $USER Setup Containerd containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml sudo systemctl restart containerd sudo systemctl status containerd Install Kubernetes \u00b6 Install kubeadm sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg echo \"deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main\" | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables apt policy kubeadm sudo apt-get -y install kubelet = 1 .23.8-00 kubeadm = 1 .23.8-00 kubectl = 1 .23.8-00 --allow-downgrades Setup Master Node sudo kubeadm config print init-defaults Dry run sudo kubeadm init --dry-run --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 Run sudo kubeadm init --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Install Flannel. If NetworkPolicy is the case, then install Calico. Refer to the \"Install Calico or Flannel\" of below section \"Installation on Aliyun Ubuntu\". kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml Setup on Worker Node Command usage: kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> kubeadm join 11 .0.1.136:6443 --token 6zqh1u.8b4afzc2ov4e7iuj \\ --discovery-token-ca-cert-hash sha256:815fdb9dd9e3ae0af07ffaf6c216964388098b150ef01ee3ae900c261a429d24 Setup bash auto completion on all nodes sudo apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc Create alias echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc Check Cluster Status kubectl cluster-info kubectl get nodes -owide kubectl get pod -A Reset cluster \u00b6 CAUTION: below steps will destroy current cluster. Delete all nodes in the cluster. kubeadm reset Clean up rule of iptables . iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Clean up rule of IPVS if using IPVS . ipvsadm --clear Install Helm \u00b6 Helm Client Installation: curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh Output: Downloading https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm","title":"Single Node Installation"},{"location":"k8s/cka_en/installation/single-local/#single-node-installation","text":"","title":"Single Node Installation"},{"location":"k8s/cka_en/installation/single-local/#local-vm-setting","text":"VMWare Setting. VMnet1: host-only, subnet: 192.168.150.0/24 VMnet8: NAT, subnet: 11.0.1.0/24 Create guest machine with VMWare Player. 4 GB RAM 2 CPUs with 2 Cores Ubuntu Server 22.04 NAT Kubernetes running on Docker.","title":"Local VM setting"},{"location":"k8s/cka_en/installation/single-local/#ubuntu-post-installation","text":"Create user vagrant . sudo adduser vagrant sudo usermod -aG adm,sudo,syslog,cdrom,dip,plugdev,lxd vagrant sudo passwd vagrant Set password for root . sudo passwd root Update guest's hostname. Here it's ubusvr . sudo hostnamectl set-hostname ubusvr sudo hostnamectl set-hostname ubusvr --pretty Verify if the hostname is set to ubusvr . cat /etc/machine-info Verify if the hostname is set to ubusvr . cat /etc/hostname Verify if the hostname of 127.0.1.1 is set to ubusvr . cat /etc/hosts 127 .0.0.1 localhost 127 .0.1.1 ubusrv # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters Set guest with fix ip, e.g, 11.0.1.136 . sudo vi 00 -installer-config.yaml network: ethernets: ens33: dhcp4: false addresses: - 11 .0.1.136/24 nameservers: addresses: - 11 .0.1.2 routes: - to: default via: 11 .0.1.2 version: 2 sudo netplan apply Disable swap sudo swapoff -a sudo ufw disable sudo ufw status verbose And comment the last line of swap setting in file /etc/fstab . Need reboot guest here. /dev/disk/by-uuid/df370d2a-83e5-4895-8c7f-633f2545e3fe / ext4 defaults 0 1 # /swap.img none swap sw 0 0 Setup timezone sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime sudo echo 'LANG=\"en_US.UTF-8\"' >> /etc/profile source /etc/profile Something like this after execute command ll /etc/localtime lrwxrwxrwx 1 root root 33 Jul 15 22 :00 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai Kernel setting cat < /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin sudo systemctl status docker.service sudo systemctl status containerd.service sudo groupadd docker sudo usermod -aG docker $USER Setup Containerd containerd config default | sudo tee /etc/containerd/config.toml sudo vi /etc/containerd/config.toml sudo systemctl restart containerd sudo systemctl status containerd","title":"Install Docker"},{"location":"k8s/cka_en/installation/single-local/#install-kubernetes","text":"Install kubeadm sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl sudo curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg echo \"deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main\" | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install ebtables sudo apt-get install libxtables12 sudo apt-get upgrade iptables apt policy kubeadm sudo apt-get -y install kubelet = 1 .23.8-00 kubeadm = 1 .23.8-00 kubectl = 1 .23.8-00 --allow-downgrades Setup Master Node sudo kubeadm config print init-defaults Dry run sudo kubeadm init --dry-run --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 Run sudo kubeadm init --pod-network-cidr = 10 .244.0.0/16 --image-repository = registry.aliyuncs.com/google_containers --kubernetes-version = v1.23.8 mkdir -p $HOME /.kube sudo cp -i /etc/kubernetes/admin.conf $HOME /.kube/config sudo chown $( id -u ) : $( id -g ) $HOME /.kube/config Install Flannel. If NetworkPolicy is the case, then install Calico. Refer to the \"Install Calico or Flannel\" of below section \"Installation on Aliyun Ubuntu\". kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml Setup on Worker Node Command usage: kubeadm join :6443 --token --discovery-token-ca-cert-hash < hash key generated by kubeadm init> kubeadm join 11 .0.1.136:6443 --token 6zqh1u.8b4afzc2ov4e7iuj \\ --discovery-token-ca-cert-hash sha256:815fdb9dd9e3ae0af07ffaf6c216964388098b150ef01ee3ae900c261a429d24 Setup bash auto completion on all nodes sudo apt install -y bash-completion source /usr/share/bash-completion/bash_completion source < ( kubectl completion bash ) echo \"source <(kubectl completion bash)\" >> ~/.bashrc Create alias echo 'alias k=kubectl' >>~/.bashrc echo 'complete -o default -F __start_kubectl k' >>~/.bashrc Check Cluster Status kubectl cluster-info kubectl get nodes -owide kubectl get pod -A","title":"Install Kubernetes"},{"location":"k8s/cka_en/installation/single-local/#reset-cluster","text":"CAUTION: below steps will destroy current cluster. Delete all nodes in the cluster. kubeadm reset Clean up rule of iptables . iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X Clean up rule of IPVS if using IPVS . ipvsadm --clear","title":"Reset cluster"},{"location":"k8s/cka_en/installation/single-local/#install-helm","text":"Helm Client Installation: curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh Output: Downloading https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm","title":"Install Helm"},{"location":"k8s/demo/cap_on_kyma/","text":"Build CAP Application on Kyma \u00b6 This is the memo of self-practice following the tutorials from Deploy Your CAP Application on SAP BTP Kyma Runtime . Prerequisites: Register account in Developer@SAP . Register trial account in SAP BTP . Tasks: Configure Kyma in SAP Business Technology Platform (SAP BTP) subaccount and prepare Kyma development environment. Create an HDI container for an SAP HANA Cloud instance on Cloud Foundry and create credentials for this SAP HANA cloud instance in Kyma cluster. Develop a business application using SAP Cloud Application Programming Model (CAP). Start on local environment, enhance it with an SAP Fiori UI, add business logic to it, and also roles and authorization check. Add a Helm chart to the application, build docker images, push them to your container registry, and deploy your application to your Kyma cluster on SAP BTP. Local environment: Applel Silicon M1 chipset macOS 12.6 (command sw_vers ) Nodejs version: CDS version: jq - for JSON processing in CLI ( brew install jq ) SAP BTP subaccount configuration \u00b6 For the SAP BTP free tier, the recommendation is as well to use an AWS-based subaccount. Kyma runtime in the free tier is only available on AWS. Choose the entitlements for the subdomain: Alert Notification: Standard plan Continuous Integration & Delivery: default (Application) or the trial (Application) or free (Application) plans which are not charged Kyma runtime: any available plan in the list (trial and free are not charged) Launchpad Service: standard (Application) or free (Application) SAP HANA Cloud: hana SAP HANA Schemas & HDI Containers: hdi-shared Set up local BTP environment \u00b6 Here we will use btp command to set up cloud environment. Details we can refer to help document Working with Environments Using the btp CLI . Download BTP CLI package btp-cli-darwin-amd64-.tar.gz via link and unpackage it. tar xvf btp-cli-darwin-amd64-.tar.gz A new subfolder darwin-amd64 will be created in current path and a bin file btp is under the subfolder. Move file btp to folder /usr/local/bin/ . sudo mv ./darwin-amd64/btp /usr/local/bin/ Log on to the subaccount on BTP. btp login --url https://cpcli.cf.eu10.hana.ondemand.com --subdomain --user Configuration file was stored at /Users/$USER/Library/Application Support/.btp/config.json . In Linux, the configuration file is on /home/$USER/.config/.btp/config.json . We can get current user via command echo $USER . Tips: Commands are executed in the target, unless specified otherwise using a parameter. To change the target, use btp target . For an explanation of the targeting mechanism, use btp help target . Get the subaccount ID in BTP and we will know that kyma and cloundfoundry are available in current trial account. btp list accounts/available-environment --subaccount Get details about an environment available for a subaccount btp get accounts/available-environment --subaccount --environment cloudfoundry --service cloudfoundry --plan standard btp get accounts/available-environment --subaccount --environment kyma --service kymaruntime --plan trial Get status running instances. Here we will also get environment ID of running instances. btp list accounts/environment-instance --subaccount Delete a running instance if needed. btp delete accounts/environment-instance --subaccount Create Kyma instance. btp create accounts/environment-instance --subaccount --environment kyma --service kymaruntime --plan trial --parameters '{\"name\": \"\"}' btp get accounts/environment-instance --subaccount Create CloudFoundry instance btp create accounts/environment-instance --subaccount --environment cloudfoundry --service cloudfoundry --plan standard --parameters '{\"instance_name\": \"\"}' btp get accounts/environment-instance --subaccount Log onto CF to create space DEV by providing API endpoint, Email and Password, which are ready in the subaccount overview page. cf login cf create-space DEV Install Homebrew \u00b6 Refer to installation guide . Set environment variables export HOMEBREW_BREW_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/brew.git\" export HOMEBREW_CORE_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/homebrew-core.git\" export HOMEBREW_BOTTLE_DOMAIN = \"https://mirrors.ustc.edu.cn/homebrew-bottles\" Install Homebrew /bin/bash -c \" $( curl -fsSL https://github.com/Homebrew/install/raw/HEAD/install.sh ) \" Add below in file ~/.zprofile . export HOMEBREW_BREW_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/brew.git\" export HOMEBREW_CORE_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/homebrew-core.git\" export HOMEBREW_BOTTLE_DOMAIN = \"https://mirrors.ustc.edu.cn/homebrew-bottles\" eval \" $( /opt/homebrew/bin/brew shellenv ) \" Make it effected. source ~/.zprofile Install kubetcl \u00b6 The kubectl installation guide curl -LO \"https://dl.k8s.io/release/ $( curl -L -s https://dl.k8s.io/release/stable.txt ) /bin/darwin/arm64/kubectl\" chmod +x ./kubectl sudo mv ./kubectl /usr/local/bin/kubectl sudo chown root: /usr/local/bin/kubectl kubectl version --client Install plugin oidc-login . curl -fsSLO https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-darwin_arm64.tar.gz tar xvf krew-darwin_arm64.tar.gz ./krew-darwin_arm64 install krew Add the $HOME/.krew/bin directory to the PATH environment variable by updating ~/.zprofile . export PATH = $HOME /.krew/bin: $PATH : $PATH Make it effected source ~/.zprofile Run kubectl krew to check the installation. Install/uninstall plugin oidc-login . kubectl krew install oidc-login kubectl krew uninstall oidc-login SAP Kyma runtime \u00b6 In the Overview area of your subaccount open the Link to dashboard link which appears next to the Console URL under the Kyma Environment area. At the top left of the window choose the Clusters Overview drop down and choose your cluster. In the Clusters Overview window choose the Download Kubeconfig for your Kyma runtime to download your KUBECONFIG. Add below to ~/.zprofile to set the kubeconfig to an environment variable. export KUBECONFIG = Make above change effected. source ~/.zprofile chmod 600 Test connection between kubectl and Kyma on BTP. kubectl cluster-info Install Node.js \u00b6 Refer to installation guide brew search node brew install node@16 brew unlink node brew link node@16 node -v Install SQLite \u00b6 Install SQLite via brew . brew search sqlite brew install sqlite Add below to ~/.zprofile export PATH = /opt/homebrew/opt/sqlite/bin: $PATH Make it effected source ~/.zprofile Install Xcode \u00b6 (For macOS) We have to install Command-Line Tools for Xcode , cause some node modules need binary modules (node-gyp). xcode-select --install xcode-select --help Install Git \u00b6 Refer to installation guide . brew install git git version Install SAPUI5 \u00b6 Install the UI5 CLI. npm search --global @ui5/cli npm install --global @ui5/cli npm list --global @ui5/cli ui5 --version npm search --global grunt-cli npm install --global grunt-cli npm list --global grunt-cli Install CF CLI \u00b6 Refer to installation guide . brew install cloudfoundry/tap/cf-cli@8 cf --version Install CAP Tooling \u00b6 See the details in the CAP documentation . npm search --global @sap/cds-dk npm install --global @sap/cds-dk npm list --global @sap/cds-dk cds --version Install VSCode \u00b6 In VS Code, invoke the Command Palette ( View \u2192 Command Palette or \u21e7\u2318P) and type shell command to find the Shell Command: Install 'code' command in PATH . Install SAP CDS Language Support extension. Install SAP Fiori tools - Extension Pack extension. Install Yeoman \u00b6 Yeoman is a tool for scaffolding web apps. You\u2019ll need it if you want to carry out the tutorial Add the SAP Launchpad Service. npm install --global yo yo --version Install Docker \u00b6 brew install docker --cask Install Helm \u00b6 Refer to installation guide brew install helm Install Paketo(pack) \u00b6 Refer to installation guide . brew install buildpacks/tap/pack Install Rancher Desktop \u00b6 Download the Rancher Desktop installer for macOS from the release page . Refer to installation guide . Download tutorial \u00b6 Go to tutorial root directory and clone the code. git clone https://github.com/SAP-samples/cloud-cap-risk-management tutorial Initialize the project \u00b6 Install required Node.js modules in the app directory cpapp . cd app cds init npm install cds watch Add files to the project \u00b6 Copy the file schema.cds from templates/create-cap-application/db to the db folder of the app. It creates two entities in the namespace sap.ui.riskmanagement : Risks and Mitigations . Copy the file risk-service.cds from templates/create-cap-application/srv to the srv folder of the app. It creates a new service RiskService in the namespace sap.ui.riskmanagement . This service exposes two entities: Risks and Mitigations , which are exposing the entities of the database schema we've created in the step before. Copy the folder data from templates/create-cap-application/db to the db folder of the app. There are two comma-separated value (CSV) files that contain local data for both the Risks and the Mitigations entities. Use Fiori Application Generator (VSCode extension) to generate Risk UI with Fiori element template. The generation will create a risks and a webapp folder with a Component.js file in the app folder of the project. Copy the file risks-service-ui.cds from templates/create-ui-fiori-elements/srv to the srv folder of the app. It defines annotations to show a work list with some columns and the data from the service in the Risk UI. Edit app/risks/webapp/manifest.json file to make the header fields editable, that is, shows title and description in Risk UI. Copy the file risk-service.js from templates/cap-business-logic/srv to the srv folder of the app. It now shows the work list in Risk UI with the columns Priority and Impact with color and an icon, depending on the amount in Impact . Use Fiori Application Generator (VSCode extension) to generate Migration UI with Fiori free-style template. The generation will create a migrations and a webapp folder with a Component.js file in the app folder of the project. Update file cpapp/app/mitigations/webapp/view/Worklist.view.xml to show Description , Owner , and Timeline columns, as well as in detail object page. Till now, our risks and mitigations application have been generated by the SAP Fiori Tools Generator and can be started independently. They are launched without a launch page. Copy the file launchpage.html from templates/launchpage/app to the app folder of the app. There are two applications in the launch page with URLs that point to the respective apps. We now see the Mitigations app next to the Risks app on the launch page. Open the file srv/risk-service.cds and add role restrictions to entities. Copy the file templates/cap-roles/.cdsrc.json to the project directory cpapp . The file defines two users risk.viewer@tester.sap.com and risk.manager@tester.sap.com . The default password can be found in the file .cdsrc.json . We will see the CAP server to show above applications via link http://localhost:4004 . Prepare Kyma Development Environment \u00b6 Execute cds version to make sure the package.json is using @sap/cds 6.0.1 or newer and we have @sap/cds-dk 6.0.1 or newer globally installed. Create namespace on Kyma. kubectl create namespace risk-management Switch to the namespace. kubectl config set-context --current --namespace risk-management Create container registry secret. Copy the folder scripts from templates/Kyma-Prepare-Dev-Environment to the project root folder cpapp . In the root folder cpapp of the project, run the script to create the secret. ./scripts/create-container-registry-secret.sh Need provide below input: docker-server = https://registry-1.docker.io docker-username = docker-email = docker-password = Verify kubectl get secret Set Up SAP HANA Cloud for Kyma \u00b6 Add SAP HANA support to your project. This adds the db module for SAP HANA access to the package.json file. Execute the command below in the project root directory cpapp . cds add hana --for production Verify the access to both CF and Kyma by executing below commands. cf login kubectl cluster-info Create HANA Cloud instance cpapp-db in CloudFoundry DEV namespace. The admin user id is DBADMIN . In the root folder cpapp of the project, execute: ./scripts/create-db-secret.sh cpapp-db Get the host name pattern of the cluster with the following command. Result looks like *.c-.sap.kyma.ondemand.com . kubectl get gateway -n kyma-system kyma-gateway -o jsonpath = '{.spec.servers[0].hosts[0]}' The script will: Create service key cpapp-db-key for HANA Cloud service instance cpapp-db as . Create Kubernetes secret cpapp-db for HANA DB instance. View it using kubectl get secret cpapp-db -o yaml . User Authentication and Authorization (XSUAA) Setup \u00b6 Set up XSUAA. cds add xsuaa --for production Above command will do: Adds the XSUAA service to the package.json file of the project Creates the XSUAA security configuration xs-security.json for the project Add Helm Chart \u00b6 Add Helm Chart. cds add helm Get docker server URL by command: cat ~/.docker/config.json Get the image pull secret for container registry. In the demo, it's container-registry . kubectl get secret Get the host name pattern of the cluster. kubectl get gateway -n kyma-system kyma-gateway -o jsonpath = '{.spec.servers[0].hosts[0]}' Open the file chart/values.yaml : Replace the placeholder with docker server URL https://docker.io/ . Set imagePullSecret with value name: container-registry . Add host name of the cluster without leading *. . Add the binding db pointing to the SAP HANA Cloud instance secret cpapp-db . Point the binding hana of the SAP HANA Cloud instance secret cpapp-db . Add the Authorization and Trust Management service to allow user login. Deploy CAP Application to Kyma \u00b6 Build docker image. CONTAINER_REGISTRY = https://index.docker.io/v1 CONTAINER_REGISTRY = https://registry-1.docker.io/yuhuihu CONTAINER_REGISTRY = yuhuihu CAP build. cds build --production Build CAP service. pack build $CONTAINER_REGISTRY /cpapp-srv --path gen/srv \\ --buildpack gcr.io/paketo-buildpacks/nodejs \\ --builder paketobuildpacks/builder:base","title":"Build CAP Application on Kyma"},{"location":"k8s/demo/cap_on_kyma/#build-cap-application-on-kyma","text":"This is the memo of self-practice following the tutorials from Deploy Your CAP Application on SAP BTP Kyma Runtime . Prerequisites: Register account in Developer@SAP . Register trial account in SAP BTP . Tasks: Configure Kyma in SAP Business Technology Platform (SAP BTP) subaccount and prepare Kyma development environment. Create an HDI container for an SAP HANA Cloud instance on Cloud Foundry and create credentials for this SAP HANA cloud instance in Kyma cluster. Develop a business application using SAP Cloud Application Programming Model (CAP). Start on local environment, enhance it with an SAP Fiori UI, add business logic to it, and also roles and authorization check. Add a Helm chart to the application, build docker images, push them to your container registry, and deploy your application to your Kyma cluster on SAP BTP. Local environment: Applel Silicon M1 chipset macOS 12.6 (command sw_vers ) Nodejs version: CDS version: jq - for JSON processing in CLI ( brew install jq )","title":"Build CAP Application on Kyma"},{"location":"k8s/demo/cap_on_kyma/#sap-btp-subaccount-configuration","text":"For the SAP BTP free tier, the recommendation is as well to use an AWS-based subaccount. Kyma runtime in the free tier is only available on AWS. Choose the entitlements for the subdomain: Alert Notification: Standard plan Continuous Integration & Delivery: default (Application) or the trial (Application) or free (Application) plans which are not charged Kyma runtime: any available plan in the list (trial and free are not charged) Launchpad Service: standard (Application) or free (Application) SAP HANA Cloud: hana SAP HANA Schemas & HDI Containers: hdi-shared","title":"SAP BTP subaccount configuration"},{"location":"k8s/demo/cap_on_kyma/#set-up-local-btp-environment","text":"Here we will use btp command to set up cloud environment. Details we can refer to help document Working with Environments Using the btp CLI . Download BTP CLI package btp-cli-darwin-amd64-.tar.gz via link and unpackage it. tar xvf btp-cli-darwin-amd64-.tar.gz A new subfolder darwin-amd64 will be created in current path and a bin file btp is under the subfolder. Move file btp to folder /usr/local/bin/ . sudo mv ./darwin-amd64/btp /usr/local/bin/ Log on to the subaccount on BTP. btp login --url https://cpcli.cf.eu10.hana.ondemand.com --subdomain --user Configuration file was stored at /Users/$USER/Library/Application Support/.btp/config.json . In Linux, the configuration file is on /home/$USER/.config/.btp/config.json . We can get current user via command echo $USER . Tips: Commands are executed in the target, unless specified otherwise using a parameter. To change the target, use btp target . For an explanation of the targeting mechanism, use btp help target . Get the subaccount ID in BTP and we will know that kyma and cloundfoundry are available in current trial account. btp list accounts/available-environment --subaccount Get details about an environment available for a subaccount btp get accounts/available-environment --subaccount --environment cloudfoundry --service cloudfoundry --plan standard btp get accounts/available-environment --subaccount --environment kyma --service kymaruntime --plan trial Get status running instances. Here we will also get environment ID of running instances. btp list accounts/environment-instance --subaccount Delete a running instance if needed. btp delete accounts/environment-instance --subaccount Create Kyma instance. btp create accounts/environment-instance --subaccount --environment kyma --service kymaruntime --plan trial --parameters '{\"name\": \"\"}' btp get accounts/environment-instance --subaccount Create CloudFoundry instance btp create accounts/environment-instance --subaccount --environment cloudfoundry --service cloudfoundry --plan standard --parameters '{\"instance_name\": \"\"}' btp get accounts/environment-instance --subaccount Log onto CF to create space DEV by providing API endpoint, Email and Password, which are ready in the subaccount overview page. cf login cf create-space DEV","title":"Set up local BTP environment"},{"location":"k8s/demo/cap_on_kyma/#install-homebrew","text":"Refer to installation guide . Set environment variables export HOMEBREW_BREW_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/brew.git\" export HOMEBREW_CORE_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/homebrew-core.git\" export HOMEBREW_BOTTLE_DOMAIN = \"https://mirrors.ustc.edu.cn/homebrew-bottles\" Install Homebrew /bin/bash -c \" $( curl -fsSL https://github.com/Homebrew/install/raw/HEAD/install.sh ) \" Add below in file ~/.zprofile . export HOMEBREW_BREW_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/brew.git\" export HOMEBREW_CORE_GIT_REMOTE = \"https://mirrors.ustc.edu.cn/homebrew-core.git\" export HOMEBREW_BOTTLE_DOMAIN = \"https://mirrors.ustc.edu.cn/homebrew-bottles\" eval \" $( /opt/homebrew/bin/brew shellenv ) \" Make it effected. source ~/.zprofile","title":"Install Homebrew"},{"location":"k8s/demo/cap_on_kyma/#install-kubetcl","text":"The kubectl installation guide curl -LO \"https://dl.k8s.io/release/ $( curl -L -s https://dl.k8s.io/release/stable.txt ) /bin/darwin/arm64/kubectl\" chmod +x ./kubectl sudo mv ./kubectl /usr/local/bin/kubectl sudo chown root: /usr/local/bin/kubectl kubectl version --client Install plugin oidc-login . curl -fsSLO https://github.com/kubernetes-sigs/krew/releases/latest/download/krew-darwin_arm64.tar.gz tar xvf krew-darwin_arm64.tar.gz ./krew-darwin_arm64 install krew Add the $HOME/.krew/bin directory to the PATH environment variable by updating ~/.zprofile . export PATH = $HOME /.krew/bin: $PATH : $PATH Make it effected source ~/.zprofile Run kubectl krew to check the installation. Install/uninstall plugin oidc-login . kubectl krew install oidc-login kubectl krew uninstall oidc-login","title":"Install kubetcl"},{"location":"k8s/demo/cap_on_kyma/#sap-kyma-runtime","text":"In the Overview area of your subaccount open the Link to dashboard link which appears next to the Console URL under the Kyma Environment area. At the top left of the window choose the Clusters Overview drop down and choose your cluster. In the Clusters Overview window choose the Download Kubeconfig for your Kyma runtime to download your KUBECONFIG. Add below to ~/.zprofile to set the kubeconfig to an environment variable. export KUBECONFIG = Make above change effected. source ~/.zprofile chmod 600 Test connection between kubectl and Kyma on BTP. kubectl cluster-info","title":"SAP Kyma runtime"},{"location":"k8s/demo/cap_on_kyma/#install-nodejs","text":"Refer to installation guide brew search node brew install node@16 brew unlink node brew link node@16 node -v","title":"Install Node.js"},{"location":"k8s/demo/cap_on_kyma/#install-sqlite","text":"Install SQLite via brew . brew search sqlite brew install sqlite Add below to ~/.zprofile export PATH = /opt/homebrew/opt/sqlite/bin: $PATH Make it effected source ~/.zprofile","title":"Install SQLite"},{"location":"k8s/demo/cap_on_kyma/#install-xcode","text":"(For macOS) We have to install Command-Line Tools for Xcode , cause some node modules need binary modules (node-gyp). xcode-select --install xcode-select --help","title":"Install Xcode"},{"location":"k8s/demo/cap_on_kyma/#install-git","text":"Refer to installation guide . brew install git git version","title":"Install Git"},{"location":"k8s/demo/cap_on_kyma/#install-sapui5","text":"Install the UI5 CLI. npm search --global @ui5/cli npm install --global @ui5/cli npm list --global @ui5/cli ui5 --version npm search --global grunt-cli npm install --global grunt-cli npm list --global grunt-cli","title":"Install SAPUI5"},{"location":"k8s/demo/cap_on_kyma/#install-cf-cli","text":"Refer to installation guide . brew install cloudfoundry/tap/cf-cli@8 cf --version","title":"Install CF CLI"},{"location":"k8s/demo/cap_on_kyma/#install-cap-tooling","text":"See the details in the CAP documentation . npm search --global @sap/cds-dk npm install --global @sap/cds-dk npm list --global @sap/cds-dk cds --version","title":"Install CAP Tooling"},{"location":"k8s/demo/cap_on_kyma/#install-vscode","text":"In VS Code, invoke the Command Palette ( View \u2192 Command Palette or \u21e7\u2318P) and type shell command to find the Shell Command: Install 'code' command in PATH . Install SAP CDS Language Support extension. Install SAP Fiori tools - Extension Pack extension.","title":"Install VSCode"},{"location":"k8s/demo/cap_on_kyma/#install-yeoman","text":"Yeoman is a tool for scaffolding web apps. You\u2019ll need it if you want to carry out the tutorial Add the SAP Launchpad Service. npm install --global yo yo --version","title":"Install Yeoman"},{"location":"k8s/demo/cap_on_kyma/#install-docker","text":"brew install docker --cask","title":"Install Docker"},{"location":"k8s/demo/cap_on_kyma/#install-helm","text":"Refer to installation guide brew install helm","title":"Install Helm"},{"location":"k8s/demo/cap_on_kyma/#install-paketopack","text":"Refer to installation guide . brew install buildpacks/tap/pack","title":"Install Paketo(pack)"},{"location":"k8s/demo/cap_on_kyma/#install-rancher-desktop","text":"Download the Rancher Desktop installer for macOS from the release page . Refer to installation guide .","title":"Install Rancher Desktop"},{"location":"k8s/demo/cap_on_kyma/#download-tutorial","text":"Go to tutorial root directory and clone the code. git clone https://github.com/SAP-samples/cloud-cap-risk-management tutorial","title":"Download tutorial"},{"location":"k8s/demo/cap_on_kyma/#initialize-the-project","text":"Install required Node.js modules in the app directory cpapp . cd app cds init npm install cds watch","title":"Initialize the project"},{"location":"k8s/demo/cap_on_kyma/#add-files-to-the-project","text":"Copy the file schema.cds from templates/create-cap-application/db to the db folder of the app. It creates two entities in the namespace sap.ui.riskmanagement : Risks and Mitigations . Copy the file risk-service.cds from templates/create-cap-application/srv to the srv folder of the app. It creates a new service RiskService in the namespace sap.ui.riskmanagement . This service exposes two entities: Risks and Mitigations , which are exposing the entities of the database schema we've created in the step before. Copy the folder data from templates/create-cap-application/db to the db folder of the app. There are two comma-separated value (CSV) files that contain local data for both the Risks and the Mitigations entities. Use Fiori Application Generator (VSCode extension) to generate Risk UI with Fiori element template. The generation will create a risks and a webapp folder with a Component.js file in the app folder of the project. Copy the file risks-service-ui.cds from templates/create-ui-fiori-elements/srv to the srv folder of the app. It defines annotations to show a work list with some columns and the data from the service in the Risk UI. Edit app/risks/webapp/manifest.json file to make the header fields editable, that is, shows title and description in Risk UI. Copy the file risk-service.js from templates/cap-business-logic/srv to the srv folder of the app. It now shows the work list in Risk UI with the columns Priority and Impact with color and an icon, depending on the amount in Impact . Use Fiori Application Generator (VSCode extension) to generate Migration UI with Fiori free-style template. The generation will create a migrations and a webapp folder with a Component.js file in the app folder of the project. Update file cpapp/app/mitigations/webapp/view/Worklist.view.xml to show Description , Owner , and Timeline columns, as well as in detail object page. Till now, our risks and mitigations application have been generated by the SAP Fiori Tools Generator and can be started independently. They are launched without a launch page. Copy the file launchpage.html from templates/launchpage/app to the app folder of the app. There are two applications in the launch page with URLs that point to the respective apps. We now see the Mitigations app next to the Risks app on the launch page. Open the file srv/risk-service.cds and add role restrictions to entities. Copy the file templates/cap-roles/.cdsrc.json to the project directory cpapp . The file defines two users risk.viewer@tester.sap.com and risk.manager@tester.sap.com . The default password can be found in the file .cdsrc.json . We will see the CAP server to show above applications via link http://localhost:4004 .","title":"Add files to the project"},{"location":"k8s/demo/cap_on_kyma/#prepare-kyma-development-environment","text":"Execute cds version to make sure the package.json is using @sap/cds 6.0.1 or newer and we have @sap/cds-dk 6.0.1 or newer globally installed. Create namespace on Kyma. kubectl create namespace risk-management Switch to the namespace. kubectl config set-context --current --namespace risk-management Create container registry secret. Copy the folder scripts from templates/Kyma-Prepare-Dev-Environment to the project root folder cpapp . In the root folder cpapp of the project, run the script to create the secret. ./scripts/create-container-registry-secret.sh Need provide below input: docker-server = https://registry-1.docker.io docker-username = docker-email = docker-password = Verify kubectl get secret","title":"Prepare Kyma Development Environment"},{"location":"k8s/demo/cap_on_kyma/#set-up-sap-hana-cloud-for-kyma","text":"Add SAP HANA support to your project. This adds the db module for SAP HANA access to the package.json file. Execute the command below in the project root directory cpapp . cds add hana --for production Verify the access to both CF and Kyma by executing below commands. cf login kubectl cluster-info Create HANA Cloud instance cpapp-db in CloudFoundry DEV namespace. The admin user id is DBADMIN . In the root folder cpapp of the project, execute: ./scripts/create-db-secret.sh cpapp-db Get the host name pattern of the cluster with the following command. Result looks like *.c-.sap.kyma.ondemand.com . kubectl get gateway -n kyma-system kyma-gateway -o jsonpath = '{.spec.servers[0].hosts[0]}' The script will: Create service key cpapp-db-key for HANA Cloud service instance cpapp-db as . Create Kubernetes secret cpapp-db for HANA DB instance. View it using kubectl get secret cpapp-db -o yaml .","title":"Set Up SAP HANA Cloud for Kyma"},{"location":"k8s/demo/cap_on_kyma/#user-authentication-and-authorization-xsuaa-setup","text":"Set up XSUAA. cds add xsuaa --for production Above command will do: Adds the XSUAA service to the package.json file of the project Creates the XSUAA security configuration xs-security.json for the project","title":"User Authentication and Authorization (XSUAA) Setup"},{"location":"k8s/demo/cap_on_kyma/#add-helm-chart","text":"Add Helm Chart. cds add helm Get docker server URL by command: cat ~/.docker/config.json Get the image pull secret for container registry. In the demo, it's container-registry . kubectl get secret Get the host name pattern of the cluster. kubectl get gateway -n kyma-system kyma-gateway -o jsonpath = '{.spec.servers[0].hosts[0]}' Open the file chart/values.yaml : Replace the placeholder with docker server URL https://docker.io/ . Set imagePullSecret with value name: container-registry . Add host name of the cluster without leading *. . Add the binding db pointing to the SAP HANA Cloud instance secret cpapp-db . Point the binding hana of the SAP HANA Cloud instance secret cpapp-db . Add the Authorization and Trust Management service to allow user login.","title":"Add Helm Chart"},{"location":"k8s/demo/cap_on_kyma/#deploy-cap-application-to-kyma","text":"Build docker image. CONTAINER_REGISTRY = https://index.docker.io/v1 CONTAINER_REGISTRY = https://registry-1.docker.io/yuhuihu CONTAINER_REGISTRY = yuhuihu CAP build. cds build --production Build CAP service. pack build $CONTAINER_REGISTRY /cpapp-srv --path gen/srv \\ --buildpack gcr.io/paketo-buildpacks/nodejs \\ --builder paketobuildpacks/builder:base","title":"Deploy CAP Application to Kyma"},{"location":"linux/","text":"Content \u00b6 Memo Linux SRE is online training hosted by Magedu that I am taking part in. SUSE Linux Administration is the learning memo for certificate of SLES Administration. SUSE Enterprise Storage Foundation is the learning memo for certificate of SES Basic Ops and Data Access. Linux SRE SUSE Linux Adminstration SUSE Enterprise Storage Foundation","title":"Index"},{"location":"linux/#content","text":"Memo Linux SRE is online training hosted by Magedu that I am taking part in. SUSE Linux Administration is the learning memo for certificate of SLES Administration. SUSE Enterprise Storage Foundation is the learning memo for certificate of SES Basic Ops and Data Access. Linux SRE SUSE Linux Adminstration SUSE Enterprise Storage Foundation","title":"Content"},{"location":"linux/Administration/01/","text":"Linux File System Overview \u00b6 Linux File System Overview \u00b6 Filesystem Hierarchy Standard (FHS), which is part of the LSB (Linux Standards Base) specifications. The Root directory \"/\". Refers to the highest layer of the file system tree. This root partition is mounted first at system boot. All programs that are run at system startup must be in this partition. The following directories must be in the root partition: /bin - User binaries. \u57fa\u672c\u7a0b\u5e8f Contains executables required when no other file systems are mounted. For example, programs required for system booting, working with files and configuration. /bin/bash - The bash shell /bin/cat - Display file contents /bin/cp - Copy files /bin/dd - Copy files byte-wise /bin/gzip - Compress files /bin/mount - Mount file systems /bin/rm - Delete files /bin/vi - Edit files /sbin - System binaries. \u7cfb\u7edf\u7a0b\u5e8f Contains programs important for system administration. \u5b58\u653e\u7cfb\u7edf\u7ba1\u7406\u7684\u7a0b\u5e8f Typically are intended to be run by the root user and therefore it is not in the regular users path. \u9ed8\u8ba4\u662froot\u7528\u6237\u6709\u6743\u9650\u6267\u884c Some important files: /sbin/yast - Administration tool /sbin/fdisk* - Modifies partitions /sbin/fsck* - File system check \u4e0d\u80fd\u5728\u8fd0\u884c\u7684\u7cfb\u7edf\u4e0a\u9762\u76f4\u63a5\u6267\u884cfsck\uff0c\u635f\u574f\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u9700\u8981umount /sbin/mkfs - Creates file systems /sbin/shutdown - Shuts down the system /dev - Device files Each system hardware component is represented (except network cards, which are kernel modules). \u4ee5\u592a\u7f51\u5361\u662f\u5185\u6838\u6a21\u5757\uff0c\u5176\u4ed6\u786c\u4ef6\u90fd\u4ee5\u8bbe\u5907dev\u7684\u65b9\u5f0f\u5c55\u73b0 Applications read from and write to these files to address hardware components. Two kinds of device files: Character-oriented \u2013 Sequential devices (printer, tape and mouse) \u5b57\u7b26\u8bbe\u5907 Block-oriented \u2013 Hard disks and DVDs \u5757\u8bbe\u5907 Connections to device drivers are implemented in the kernel using channels called major device numbers. \u4e0e\u8bbe\u5907\u9a71\u52a8\u7a0b\u5e8f\u7684\u8fde\u63a5\u901a\u8fc7\u5185\u6838\u4e2d\u79f0\u4e3a\u4e3b\u8bbe\u5907\u53f7\u7684\u901a\u9053\u5b9e\u73b0\u3002 When using ls -l the file size is replaced with the device numbers, such as 8, 0. In the past these files were created manually using the mknod command. Today they are created automatically (by udev) when the devices are discovered by the kernel. Some important device files: Null device: - /dev/null Zero device: - /dev/zero System Console: - /dev/console Virtual Terminal: - /dev/tty1 Serial ports - /dev/ttyS0 Parallel port: - /dev/lp0 Floppy disk drive: - /dev/fd0 Hard drive: - /dev/sda Hard disk partition: - /dev/sda1 CD-ROM drive: - /dev/scd0 /etc - Configuration files Contains system and services configuration files. \u5b58\u653e\u7cfb\u7edf\u548c\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6 Most of these files are ASCII files. \u5927\u90e8\u5206\u90fd\u662fASCII\u6587\u4ef6 Normal users can read most of these by default. This can be a security issue since some of these files contain passwords so it important that these files are only readable by the rootuser. \u666e\u901a\u7528\u6237\u53ef\u4ee5\u9ed8\u8ba4\u8bfb\u53d6\u5176\u4e2d\u7684\u5927\u90e8\u5206\u5185\u5bb9\u3002 \u8fd9\u53ef\u80fd\u662f\u4e00\u4e2a\u5b89\u5168\u95ee\u9898\uff0c\u56e0\u4e3a\u5176\u4e2d\u4e00\u4e9b\u6587\u4ef6\u5305\u542b\u5bc6\u7801\uff0c\u56e0\u6b64\u91cd\u8981\u7684\u662f\u8fd9\u4e9b\u6587\u4ef6\u53ea\u80fd\u7531root\u7528\u6237\u8bfb\u53d6 No executables can be put here according to the FHS, however subdirectories may contain shell scripts. \u6839\u636eFHS\uff0c\u6b64\u5904\u4e0d\u80fd\u653e\u7f6e\u4efb\u4f55\u53ef\u6267\u884c\u6587\u4ef6\uff0c\u4f46\u5b50\u76ee\u5f55\u53ef\u80fd\u5305\u542bshell\u811a\u672c\u3002 Almost every installed service has at least one configuration file in /etc or a subdirectory. \u51e0\u4e4e\u6bcf\u4e2a\u5df2\u5b89\u88c5\u7684\u670d\u52a1\u5728/ etc\u6216\u5b50\u76ee\u5f55\u4e2d\u81f3\u5c11\u6709\u4e00\u4e2a\u914d\u7f6e\u6587\u4ef6\u3002 Some important configuration files: /etc/SuSE-release - Version of installed system /etc/DIR_COLORS - Colors for the ls command /etc/fstab - For file systems to be mounted /etc/profile - Shell login script /etc/passwd - User database, except passwords /etc/shadow - Password and password info /etc/group - Database of user groups /etc/cups/* - For the CUPS printing system (CUPS=Common UNIX Printing System) /etc/hosts - Host names to IP addresses /etc/motd - Message after login /etc/issue - Message before login /etc/sysconfig/* - System configuration files /lib - Libraries. Many programs have common functions they need. The functions can be kept in a shared library. Libraries are called shared objects and end with the .so extension. \u5171\u4eab\u5e93 Libraries in /lib are used by programs in /bin and /sbin . There are additional libraries in subdirectories. Kernel modules are located in /lib/modules . /lib64 - 64-Bit Libraries. Similar to the /lib directory. This is an architecture dependent directory. Some systems support different binary formats and keep different versions of the same shared library. /usr - Contains application programs, graphical interface files, libraries, local programs, documentation and more. /usr means Unix System Resources. Examples: /usr/X11R6/ - X Window System Files /usr/bin/ - Almost all executables /usr/lib/ - Libraries and application directories /usr/local/ - Locally installed programs (i.e. on local system if /usr is mounted from the network). The content is not overwritten by system updates. \u4e0b\u97623\u4e2a\u76ee\u5f55\u5728\u521d\u59cb\u5b89\u88c5\u540e\u662f\u7a7a\u7684 /usr/local/bin - /usr/local/sbin - /usr/local/lib - /usr/sbin/ - System administration programs /usr/share/doc/ - Documentation /usr/src/ - Source code of kernel and programs /usr/src/linux - /usr/share/man/ - Manual pages /opt - Optional Application Directory Where optional or third party applications that are not considered to be \u201cpart of the distribution\u201d store their static files. Applications considered to be \u201cpart of the distribution\u201d are usually installed under /usr/lib/ rather than /opt . At installation a directory is created for each application's files with the name of the application. Example: /opt/novell - /boot - The Boot Directory /boot/grub2 - Contains static boot loader files for GRUB2. (GRUB = Grand Unified Boot Loader) Contains the kernel and initrd file identified with the links vmlinuz and initrd. /root - Administrator's Home Directory The root user's home directory. Not under /home with regular users' home directories. Needs to be in the root partition so that root can always log in with his configured environment. /home - User Directories Every system user has an assigned file area which becomes the current working directory after log in. By default they exist in /home . The files and directories in /home could be in a separate partition or on another computer on the network. The user profile and configuration files are found here: .profile - Private user login script .bashrc - Configuration file for bash .bash_history - Previous commands run in bash /run/media//* - Mount Point for Removable Media SLE 12 creates directories here for mounting removable media. The name depends on the device that is mounted/discovered. Examples: /run/media/media_name/ (Created if labeled media is inserted) /run/media/cdrom/ - /run/media/dvd/ - /run/media/usbdisk/ - /mnt - Temporarily Mounted File Systems \u6587\u4ef6\u7cfb\u7edf\u4e34\u65f6\u6302\u8f7d\u70b9 Standard directory for integrating file systems that are used temporarily. File systems are mounted using the mount command and removed using the umount command. Subdirectories do not exist by default and are not automatically created. /srv - Service Data Directories Contains subdirectories for various services. Examples: \u5b58\u653e\u5404\u79cd\u670d\u52a1\u7684\u6570\u636e /srv/www - for the Apache Web Server /srv/ftp - for an FTP server /var - Variable Files Contains files that can be modified while the system is running. \u5728\u7cfb\u7edf\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u4f1a\u88ab\u4fee\u6539\u7684\u6587\u4ef6 Important subdirectories: /var/lib/ - Variable libraries, like databases \u53ef\u53d8\u5e93\u6587\u4ef6 /var/log/ - Services log files \u65e5\u5fd7\u6587\u4ef6 /var/run/ - Information on running processes \u8fd0\u884c\u4e2d\u7684\u7ebf\u7a0b\u7684\u4fe1\u606f /var/spool/ - Queues (printers, email) /var/spool/mail - /var/spool/cron - /var/lock/ - Lock files for multiuser access /var/cache - /var/mail - /tmp - Temporary Area Where programs create temporary files while they are running /proc - Process Files A virtual file system that exists only in memory and is used to display the current state of processes running on the system. (Takes no space - file size always 0) \u865a\u62df\u6587\u4ef6\u7cfb\u7edf\uff0c\u4e0d\u5360\u95f4\uff0c\u5927\u5c0f* \u59cb\u7ec8\u96f6\uff0c\u663e\u793a\u5f53\u524d\u8fdb\u7a0b\u7684\u72b6\u6001\u4fe1\u606f Directories containing information about individual processes are named according to the PID number of the process. Some values can be modified to change how things are running in real time. Any changes made are lost at reboot. Examples: \u6709\u4e9b\u503c\u53ef\u4ee5\u4e34\u65f6\u5728\u7ebf\u66f4\u6539\u751f\u6548\uff0c\u4f46\u91cd\u542f\u540e\u4e22\u5931 /proc/cpuinfo/ - Processor information /proc/dma/ - Use of DMA ports /proc/interrupts/ - Use of interrupts /proc/ioports/ - Use of I/O ports /proc/filesystems/ - File system formats the kernel knows /proc/modules/ - Active modules /proc/mounts/ - Mounted file systems /proc/net/* - Network information and statistics /proc/partitions/ - Existing partitions /proc/bus/pci/ - Connected PCI devices /proc/bus/scsi/ - Connected SCSI devices /proc/sys/* - System and kernel information /proc/version - Kernel version /sys - System Information Directory A virtual file system that exists only in memory. Takes no space so file size always 0 \u865a\u62df\u6587\u4ef6\u7cfb\u7edf Provides information on: hardware buses hardware devices active devices drivers Lab: Explore Filesystem Hierarchy \u00b6 Show the directory structure of the /data folder hierarchy of current logon user: mySUSE:~ # tree /data /data \u2514\u2500\u2500 linktype \u251c\u2500\u2500 file \u251c\u2500\u2500 hardlinkfile1 \u251c\u2500\u2500 hardlinkfile2 \u251c\u2500\u2500 symlinkfile1 -> file \u251c\u2500\u2500 symlinkfile1-1 -> symlinkfile1 \u2514\u2500\u2500 symlinkfile2 -> file Show only directories in the /data hierarchhy, not the files in them: mySUSE:~ # tree -d /data /data \u2514\u2500\u2500 linktype Show the files and directories in the /data hierarchy, including the full path and filename of each object. mySUSE:~ # tree -f /data /data \u2514\u2500\u2500 /data/linktype \u251c\u2500\u2500 /data/linktype/file \u251c\u2500\u2500 /data/linktype/hardlinkfile1 \u251c\u2500\u2500 /data/linktype/hardlinkfile2 \u251c\u2500\u2500 /data/linktype/symlinkfile1 -> file \u251c\u2500\u2500 /data/linktype/symlinkfile1-1 -> symlinkfile1 \u2514\u2500\u2500 /data/linktype/symlinkfile2 -> file Seven Different types of files \u00b6 Normal files , examples: ASCII text files Executable files Graphics files Directories Organize files on the disk Contain files and subdirectories Implement the hierarchical file system Links Hard links Secondary file names for files on the disk Multiple file names referencing a single inode Referenced file must reside in the same file system Symbolic links: References to other files on the disk The inode contains a reference to another file name .Referenced files can exist in the same file system or in other file systems A symbolic link can reference a non-existent file (broken link) Sockets - Used for two-way communication between processes. \u5957\u63a5\u5b57 Pipes (FIFOs) - Used for one-way communication from one process to another. \u7ba1\u9053 Block Devices \u5757\u8bbe\u5907 Character Devices \u5b57\u7b26\u8bbe\u5907 Linux Link Type \u00b6 Hard links : A hard link is a directory reference, or pointer, to a file on a storage volume. The name associated with the file is a label stored in a directory structure that refers the operating system to the file data. As such, more than one name can be associated with the same file. When accessed through different names, any changes made will affect the same file data. \u786c\u94fe\u63a5\u662f\u5b58\u50a8\u5377\u4e0a\u6587\u4ef6\u7684\u76ee\u5f55\u5f15\u7528\u6216\u6307\u9488\u3002 \u6587\u4ef6\u540d\u662f\u5b58\u50a8\u5728\u76ee\u5f55\u7ed3\u6784\u4e2d\u7684\u6807\u7b7e\uff0c\u76ee\u5f55\u7ed3\u6784\u6307\u5411\u6587\u4ef6\u6570\u636e\u3002 \u56e0\u6b64\uff0c\u53ef\u4ee5\u5c06\u591a\u4e2a\u6587\u4ef6\u540d\u4e0e\u540c\u4e00\u6587\u4ef6\u5173\u8054\u3002 \u901a\u8fc7\u4e0d\u540c\u7684\u6587\u4ef6\u540d\u8bbf\u95ee\u65f6\uff0c\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u662f\u9488\u5bf9\u6e90\u6587\u4ef6\u6570\u636e\u3002 Symbolic links : A symbolic link contains a text string that is interpreted and followed by the operating system as a path to another file or directory. It is a file on its own and can exist independently of its target. If a symbolic link is deleted, its target remains unaffected. If the target is moved, renamed or deleted, any symbolic link that used to point to it continues to exist but now points to a non-existing file. \u7b26\u53f7\u94fe\u63a5\u5305\u542b\u4e00\u4e2a\u6587\u672c\u5b57\u7b26\u4e32\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5c06\u5176\u89e3\u91ca\u5e76\u4f5c\u4e3a\u53e6\u4e00\u4e2a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u8def\u5f84\u3002 \u5b83\u672c\u8eab\u5c31\u662f\u4e00\u4e2a\u6587\u4ef6\uff0c\u53ef\u4ee5\u72ec\u7acb\u4e8e\u76ee\u6807\u800c\u5b58\u5728\u3002 \u5982\u679c\u5220\u9664\u4e86\u7b26\u53f7\u94fe\u63a5\uff0c\u5219\u5176\u76ee\u6807\u4e0d\u53d7\u5f71\u54cd\u3002 \u5982\u679c\u79fb\u52a8\uff0c\u91cd\u547d\u540d\u6216\u5220\u9664\u76ee\u6807\uff0c\u5219\u7528\u4e8e\u6307\u5411\u5b83\u7684\u4efb\u4f55\u7b26\u53f7\u94fe\u63a5\u5c06\u7ee7\u7eed\u5b58\u5728\uff0c\u4f46\u73b0\u5728\u6307\u5411\u4e0d\u5b58\u5728\u7684\u6587\u4ef6\u3002 Hard links can only be used when both the file and the link are in the same file system (on the same partition), because inode numbers are only unique within the same file system. You create a hard link by using the ln command, which points to the inode of an already existing file. Thereafter, the file can be accessed under both names\u2013that of the file and that of the link, and you can no longer discern which name existed first or how the original file and the link differ. \u4ec5\u5f53\u6587\u4ef6\u548c\u94fe\u63a5\u6587\u4ef6\u4f4d\u4e8e\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\uff08\u5728\u540c\u4e00\u5206\u533a\u4e0a\uff09\u65f6\uff0c\u624d\u80fd\u4f7f\u7528\u786c\u94fe\u63a5\uff0c\u56e0\u4e3ainode\u7f16\u53f7\u5728\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\u4e2d\u4ec5\u662f\u552f\u4e00\u7684\u3002 \u60a8\u53ef\u4ee5\u4f7f\u7528ln\u547d\u4ee4\u521b\u5efa\u786c\u94fe\u63a5\uff0c\u8be5\u547d\u4ee4\u6307\u5411\u5df2\u5b58\u5728\u6587\u4ef6\u7684inode\u3002 \u6b64\u540e\uff0c\u53ef\u4ee5\u5728\u6587\u4ef6\u7684\u540d\u79f0\u548c\u94fe\u63a5\u7684\u540d\u79f0\u4e0b\u8bbf\u95ee\u6587\u4ef6\uff0c\u5e76\u4e14\u65e0\u6cd5\u518d\u8bc6\u522b\u9996\u5148\u5b58\u5728\u7684\u540d\u79f0\u6216\u539f\u59cb\u6587\u4ef6\u548c\u94fe\u63a5\u7684\u4e0d\u540c\u4e4b\u5904\u3002 You can create a symbolic link with the ln command and the -s option. A symbolic link is assigned its own inode\u2014the link refers to a file, so a distinction can always be made between the link and the actual file. \u8f6f\u8fde\u63a5\u53ef\u4ee5\u9488\u5bf9\u76ee\u5f55\uff0c\u786c\u8fde\u63a5\u53ea\u80fd\u9488\u5bf9\u6587\u4ef6\u3002 A file system is essentially a database that is used to keep track of files in a volume. For normal files, data blocks are allocated to store the file's data, an inode is allocated to point to the data blocks as well as store the metadata about the file and then a file name is assigned to the inode. A hard link is a secondary file name associated with an existing inode. For symbolic links, a new inode is allocated with a new file name associated with it but the inode references another file name rather than referencing datablocks. \u6587\u4ef6\u7cfb\u7edf\u672c\u8d28\u4e0a\u662f\u4e00\u4e2a\u7528\u4e8e\u8ddf\u8e2a\u5377\u4e2d\u6587\u4ef6\u7684\u6570\u636e\u5e93\u3002 \u5bf9\u4e8e\u666e\u901a\u6587\u4ef6\uff0c\u5206\u914d\u6570\u636e\u5757\u4ee5\u5b58\u50a8\u6587\u4ef6\u7684\u6570\u636e\uff0c\u5206\u914dinode\u4ee5\u6307\u5411\u6570\u636e\u5757\u4ee5\u53ca\u5b58\u50a8\u5173\u4e8e\u6587\u4ef6\u7684\u5143\u6570\u636e\uff0c\u7136\u540e\u5c06\u6587\u4ef6\u540d\u5206\u914d\u7ed9inode\u3002 \u786c\u94fe\u63a5\u662f\u4e0e\u73b0\u6709inode\u5173\u8054\u7684\u8f85\u52a9\u6587\u4ef6\u540d\u3002 \u5bf9\u4e8e\u7b26\u53f7\u94fe\u63a5\uff0c\u5c06\u4e3a\u65b0\u7684inode\u5206\u914d\u4e00\u4e2a\u4e0e\u4e4b\u5173\u8054\u7684\u65b0\u6587\u4ef6\u540d\uff0c\u4f46inode\u5f15\u7528\u53e6\u4e00\u4e2a\u6587\u4ef6\u540d\u800c\u4e0d\u662f\u5f15\u7528\u6570\u636e\u5757\u3002 A good way to see the relationship between file names and inodes is to use the ls -il command. The typical size of an inode is 128 Bit and data blocks can range in size from 1k, 2k, 4k or larger depending on the file system type. \u67e5\u770b\u6587\u4ef6\u540d\u548cinode\u4e4b\u95f4\u5173\u7cfb\u7684\u597d\u65b9\u6cd5\u662f\u4f7f\u7528ls -il\u547d\u4ee4\u3002inode\u7684\u5178\u578b\u5927\u5c0f\u4e3a128\u4f4d\uff0c\u6570\u636e\u5757\u7684\u5927\u5c0f\u8303\u56f4\u53ef\u4ee5\u662f1k\uff0c2k\uff0c4k\u6216\u66f4\u5927\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u3002 \u786c\u94fe\u63a5\u76f8\u5f53\u4e8e\u589e\u52a0\u4e86\u4e00\u4e2a\u767b\u8bb0\u9879\uff0c\u4f7f\u5f97\u539f\u6765\u7684\u6587\u4ef6\u591a\u4e86\u4e00\u4e2a\u540d\u5b57\uff0c\u81f3\u4e8einode\u90fd\u6ca1\u53d8\u3002\u6240\u8c13\u7684\u767b\u8bb0\u9879\u5176\u5b9e\u662f\u76ee\u5f55\u6587\u4ef6\u4e2d\u7684\u4e00\u4e2a\u6761\u76ee(\u76ee\u5f55\u9879)\uff0c\u4f7f\u7528hard link \u662f\u8ba9\u591a\u4e2a\u4e0d\u540c\u7684\u76ee\u5f55\u9879\u6307\u5411\u540c\u4e00\u4e2a\u6587\u4ef6\u7684inode\uff0c\u6ca1\u6709\u591a\u4f59\u7684\u5185\u5bb9\u9700\u8981\u5b58\u50a8\u5728\u78c1\u76d8\u6247\u533a\u4e2d\uff0c\u6240\u4ee5hardlink\u4e0d\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 \u7b26\u53f7\u94fe\u63a5\u6709\u5355\u72ec\u7684inode\uff0c\u5728inode\u4e2d\u5b58\u653e\u53e6\u4e00\u4e2a\u6587\u4ef6\u7684\u8def\u5f84\u800c\u4e0d\u662f\u6587\u4ef6\u6570\u636e\uff0c\u6240\u4ee5\u7b26\u53f7\u94fe\u63a5\u4f1a\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 Lab: File Link Type \u00b6 Create original file mySUSE:/data/linktype # echo \"it's original file\" > file mySUSE:/data/linktype # l -rw-r--r-- 1 root root 19 Mar 28 15 :20 file Create hardlink file (\u6ce8\u610ffile\u3001hardlinkfile1\u3001hardlinkfile2\u7684link\u4f4d\u7f6e\u7684\u6570\u503c\u7684\u53d8\u5316[\u7ea2\u8272]) mySUSE:/data/linktype # ln file hardlinkfile1 mySUSE:/data/linktype # ln -s file symlinkfile1 mySUSE:/data/linktype # ln -s file symlinkfile2 mySUSE:/data/linktype # l -rw-r--r-- 2 root root 19 Mar 28 15 :20 file -rw-r--r-- 2 root root 19 Mar 28 15 :20 hardlinkfile1 lrwxrwxrwx 1 root root 4 Mar 28 15 :21 symlinkfile1 -> file lrwxrwxrwx 1 root root 4 Mar 28 15 :23 symlinkfile2 -> file mySUSE:/data/linktype # ln file hardlinkfile2 mySUSE:/data/linktype # l -rw-r--r-- 3 root root 19 Mar 28 15 :20 file ( \u5305\u62ec\u81ea\u5df1\uff0c\u4e00\u5171\u67093\u4e2a\u786c\u94fe\u63a5 ) -rw-r--r-- 3 root root 19 Mar 28 15 :20 hardlinkfile1 ( \u7ee7\u627f\u4e86\u539f\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u91cf ) -rw-r--r-- 3 root root 19 Mar 28 15 :20 hardlinkfile2 ( \u7ee7\u627f\u4e86\u539f\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u91cf ) lrwxrwxrwx 1 root root 4 Mar 28 15 :21 symlinkfile1 -> file lrwxrwxrwx 1 root root 4 Mar 28 15 :23 symlinkfile2 -> file Modify content of file (original file). Content change were shown in all hard/soft link files mySUSE:/data/linktype # echo \"add oneline\" >> file mySUSE:/data/linktype # cat file it 's original file add oneline mySUSE:/data/linktype # cat hardlinkfile1 it' s original file add oneline mySUSE:/data/linktype # cat hardlinkfile2 it 's original file add oneline mySUSE:/data/linktype # cat symlinkfile1 it' s original file add oneline mySUSE:/data/linktype # cat symlinkfile2 it ' s original file add oneline To view the value stored in a symbolic link use the command readlink. mySUSE:/data/linktype # ln -s symlinkfile1 symlinkfile1-1 mySUSE:/data/linktype # ls -il 258 -rw-r--r-- 3 root root 31 Mar 28 15 :42 file 258 -rw-r--r-- 3 root root 31 Mar 28 15 :42 hardlinkfile1 258 -rw-r--r-- 3 root root 31 Mar 28 15 :42 hardlinkfile2 259 lrwxrwxrwx 1 root root 4 Mar 28 15 :21 symlinkfile1 -> file 265 lrwxrwxrwx 1 root root 12 Mar 28 15 :49 symlinkfile1-1 -> symlinkfile1 260 lrwxrwxrwx 1 root root 4 Mar 28 15 :23 symlinkfile2 -> file mySUSE:/data/linktype # readlink symlinkfile1 file mySUSE:/data/linktype # readlink symlinkfile2 file mySUSE:/data/linktype # readlink symlinkfile1-1 symlinkfile1 ( \u6ce8\u610f\uff1a\u8fd9\u4ecd\u7136\u662f\u4e00\u4e2a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6 ) mySUSE:/data/linktype # readlink -f symlinkfile1-1(\u53c2\u6570-f\u53ef\u4ee5\u76f4\u63a5\u5b9a\u4f4d\u771f\u6b63\u7684\u6e90\u6587\u4ef6) /data/linktype/file ( \u6ce8\u610f\uff1a\u8fd9\u624d\u662f\u771f\u6b63\u7684\u539f\u6587\u4ef6 ) Linux Device File \u00b6 Represent hardware (except network cards). Each piece of hardware is represented by a device file. Network cards are interfaces. (\u533a\u522b) Link between hardware devices and the kernel drivers \u8bbe\u5907\u6587\u4ef6\u628a\u5185\u6838\u9a71\u52a8\u548c\u7269\u7406\u786c\u4ef6\u8bbe\u5907\u8fde\u63a5\u8d77\u6765 Kernel drivers read from and write to the device file \u5185\u6838\u9a71\u52a8\u7a0b\u5e8f\u5bf9\u8bbe\u5907\u6587\u4ef6\u8fdb\u884c\u8bfb\u5199\u6765\u5b9e\u73b0\u5bf9\u786c\u4ef6\u7684\u8bfb\u5199 The kernel gets the data to the actual hardware in the correct format \u5185\u6838\u4ee5\u6b63\u786e\u7684\u683c\u5f0f\u5bf9\u7269\u7406\u8bbe\u5907\u8fdb\u884c\u8bfb\u5199 Types: Block Devices. A block device reads/writes information in (normally) 512 byte large blocks. Character Devices. A character device reads/writes information character wise. Character devices provide unbuffered access directly to a hardware device. \u76f4\u63a5\u8bfb\u5199\uff0c\u4e0d\u901a\u8fc7\u7f13\u5b58 Sometimes referred to as raw devices. \u88f8\u8bbe\u5907\uff08\u6ce8\u610f\uff1a\u88f8\u8bbe\u5907\u88ab\u89c6\u4e3a\u5b57\u7b26\u8bbe\u5907\uff0c\u4e0d\u662f\u5757\u8bbe\u5907\uff09 any different options for character devices, making their use and application wide and varied. Created automatically by the OS (udev) when the device is discovered by the kernel. \u5185\u6838\u76f4\u63a5\u521b\u5efa\u5bf9\u5e94\u786c\u4ef6\u7684\u8bbe\u5907\u6587\u4ef6","title":"Linux File System Overview"},{"location":"linux/Administration/01/#linux-file-system-overview","text":"","title":"Linux File System Overview"},{"location":"linux/Administration/01/#linux-file-system-overview_1","text":"Filesystem Hierarchy Standard (FHS), which is part of the LSB (Linux Standards Base) specifications. The Root directory \"/\". Refers to the highest layer of the file system tree. This root partition is mounted first at system boot. All programs that are run at system startup must be in this partition. The following directories must be in the root partition: /bin - User binaries. \u57fa\u672c\u7a0b\u5e8f Contains executables required when no other file systems are mounted. For example, programs required for system booting, working with files and configuration. /bin/bash - The bash shell /bin/cat - Display file contents /bin/cp - Copy files /bin/dd - Copy files byte-wise /bin/gzip - Compress files /bin/mount - Mount file systems /bin/rm - Delete files /bin/vi - Edit files /sbin - System binaries. \u7cfb\u7edf\u7a0b\u5e8f Contains programs important for system administration. \u5b58\u653e\u7cfb\u7edf\u7ba1\u7406\u7684\u7a0b\u5e8f Typically are intended to be run by the root user and therefore it is not in the regular users path. \u9ed8\u8ba4\u662froot\u7528\u6237\u6709\u6743\u9650\u6267\u884c Some important files: /sbin/yast - Administration tool /sbin/fdisk* - Modifies partitions /sbin/fsck* - File system check \u4e0d\u80fd\u5728\u8fd0\u884c\u7684\u7cfb\u7edf\u4e0a\u9762\u76f4\u63a5\u6267\u884cfsck\uff0c\u635f\u574f\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u9700\u8981umount /sbin/mkfs - Creates file systems /sbin/shutdown - Shuts down the system /dev - Device files Each system hardware component is represented (except network cards, which are kernel modules). \u4ee5\u592a\u7f51\u5361\u662f\u5185\u6838\u6a21\u5757\uff0c\u5176\u4ed6\u786c\u4ef6\u90fd\u4ee5\u8bbe\u5907dev\u7684\u65b9\u5f0f\u5c55\u73b0 Applications read from and write to these files to address hardware components. Two kinds of device files: Character-oriented \u2013 Sequential devices (printer, tape and mouse) \u5b57\u7b26\u8bbe\u5907 Block-oriented \u2013 Hard disks and DVDs \u5757\u8bbe\u5907 Connections to device drivers are implemented in the kernel using channels called major device numbers. \u4e0e\u8bbe\u5907\u9a71\u52a8\u7a0b\u5e8f\u7684\u8fde\u63a5\u901a\u8fc7\u5185\u6838\u4e2d\u79f0\u4e3a\u4e3b\u8bbe\u5907\u53f7\u7684\u901a\u9053\u5b9e\u73b0\u3002 When using ls -l the file size is replaced with the device numbers, such as 8, 0. In the past these files were created manually using the mknod command. Today they are created automatically (by udev) when the devices are discovered by the kernel. Some important device files: Null device: - /dev/null Zero device: - /dev/zero System Console: - /dev/console Virtual Terminal: - /dev/tty1 Serial ports - /dev/ttyS0 Parallel port: - /dev/lp0 Floppy disk drive: - /dev/fd0 Hard drive: - /dev/sda Hard disk partition: - /dev/sda1 CD-ROM drive: - /dev/scd0 /etc - Configuration files Contains system and services configuration files. \u5b58\u653e\u7cfb\u7edf\u548c\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6 Most of these files are ASCII files. \u5927\u90e8\u5206\u90fd\u662fASCII\u6587\u4ef6 Normal users can read most of these by default. This can be a security issue since some of these files contain passwords so it important that these files are only readable by the rootuser. \u666e\u901a\u7528\u6237\u53ef\u4ee5\u9ed8\u8ba4\u8bfb\u53d6\u5176\u4e2d\u7684\u5927\u90e8\u5206\u5185\u5bb9\u3002 \u8fd9\u53ef\u80fd\u662f\u4e00\u4e2a\u5b89\u5168\u95ee\u9898\uff0c\u56e0\u4e3a\u5176\u4e2d\u4e00\u4e9b\u6587\u4ef6\u5305\u542b\u5bc6\u7801\uff0c\u56e0\u6b64\u91cd\u8981\u7684\u662f\u8fd9\u4e9b\u6587\u4ef6\u53ea\u80fd\u7531root\u7528\u6237\u8bfb\u53d6 No executables can be put here according to the FHS, however subdirectories may contain shell scripts. \u6839\u636eFHS\uff0c\u6b64\u5904\u4e0d\u80fd\u653e\u7f6e\u4efb\u4f55\u53ef\u6267\u884c\u6587\u4ef6\uff0c\u4f46\u5b50\u76ee\u5f55\u53ef\u80fd\u5305\u542bshell\u811a\u672c\u3002 Almost every installed service has at least one configuration file in /etc or a subdirectory. \u51e0\u4e4e\u6bcf\u4e2a\u5df2\u5b89\u88c5\u7684\u670d\u52a1\u5728/ etc\u6216\u5b50\u76ee\u5f55\u4e2d\u81f3\u5c11\u6709\u4e00\u4e2a\u914d\u7f6e\u6587\u4ef6\u3002 Some important configuration files: /etc/SuSE-release - Version of installed system /etc/DIR_COLORS - Colors for the ls command /etc/fstab - For file systems to be mounted /etc/profile - Shell login script /etc/passwd - User database, except passwords /etc/shadow - Password and password info /etc/group - Database of user groups /etc/cups/* - For the CUPS printing system (CUPS=Common UNIX Printing System) /etc/hosts - Host names to IP addresses /etc/motd - Message after login /etc/issue - Message before login /etc/sysconfig/* - System configuration files /lib - Libraries. Many programs have common functions they need. The functions can be kept in a shared library. Libraries are called shared objects and end with the .so extension. \u5171\u4eab\u5e93 Libraries in /lib are used by programs in /bin and /sbin . There are additional libraries in subdirectories. Kernel modules are located in /lib/modules . /lib64 - 64-Bit Libraries. Similar to the /lib directory. This is an architecture dependent directory. Some systems support different binary formats and keep different versions of the same shared library. /usr - Contains application programs, graphical interface files, libraries, local programs, documentation and more. /usr means Unix System Resources. Examples: /usr/X11R6/ - X Window System Files /usr/bin/ - Almost all executables /usr/lib/ - Libraries and application directories /usr/local/ - Locally installed programs (i.e. on local system if /usr is mounted from the network). The content is not overwritten by system updates. \u4e0b\u97623\u4e2a\u76ee\u5f55\u5728\u521d\u59cb\u5b89\u88c5\u540e\u662f\u7a7a\u7684 /usr/local/bin - /usr/local/sbin - /usr/local/lib - /usr/sbin/ - System administration programs /usr/share/doc/ - Documentation /usr/src/ - Source code of kernel and programs /usr/src/linux - /usr/share/man/ - Manual pages /opt - Optional Application Directory Where optional or third party applications that are not considered to be \u201cpart of the distribution\u201d store their static files. Applications considered to be \u201cpart of the distribution\u201d are usually installed under /usr/lib/ rather than /opt . At installation a directory is created for each application's files with the name of the application. Example: /opt/novell - /boot - The Boot Directory /boot/grub2 - Contains static boot loader files for GRUB2. (GRUB = Grand Unified Boot Loader) Contains the kernel and initrd file identified with the links vmlinuz and initrd. /root - Administrator's Home Directory The root user's home directory. Not under /home with regular users' home directories. Needs to be in the root partition so that root can always log in with his configured environment. /home - User Directories Every system user has an assigned file area which becomes the current working directory after log in. By default they exist in /home . The files and directories in /home could be in a separate partition or on another computer on the network. The user profile and configuration files are found here: .profile - Private user login script .bashrc - Configuration file for bash .bash_history - Previous commands run in bash /run/media//* - Mount Point for Removable Media SLE 12 creates directories here for mounting removable media. The name depends on the device that is mounted/discovered. Examples: /run/media/media_name/ (Created if labeled media is inserted) /run/media/cdrom/ - /run/media/dvd/ - /run/media/usbdisk/ - /mnt - Temporarily Mounted File Systems \u6587\u4ef6\u7cfb\u7edf\u4e34\u65f6\u6302\u8f7d\u70b9 Standard directory for integrating file systems that are used temporarily. File systems are mounted using the mount command and removed using the umount command. Subdirectories do not exist by default and are not automatically created. /srv - Service Data Directories Contains subdirectories for various services. Examples: \u5b58\u653e\u5404\u79cd\u670d\u52a1\u7684\u6570\u636e /srv/www - for the Apache Web Server /srv/ftp - for an FTP server /var - Variable Files Contains files that can be modified while the system is running. \u5728\u7cfb\u7edf\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u4f1a\u88ab\u4fee\u6539\u7684\u6587\u4ef6 Important subdirectories: /var/lib/ - Variable libraries, like databases \u53ef\u53d8\u5e93\u6587\u4ef6 /var/log/ - Services log files \u65e5\u5fd7\u6587\u4ef6 /var/run/ - Information on running processes \u8fd0\u884c\u4e2d\u7684\u7ebf\u7a0b\u7684\u4fe1\u606f /var/spool/ - Queues (printers, email) /var/spool/mail - /var/spool/cron - /var/lock/ - Lock files for multiuser access /var/cache - /var/mail - /tmp - Temporary Area Where programs create temporary files while they are running /proc - Process Files A virtual file system that exists only in memory and is used to display the current state of processes running on the system. (Takes no space - file size always 0) \u865a\u62df\u6587\u4ef6\u7cfb\u7edf\uff0c\u4e0d\u5360\u95f4\uff0c\u5927\u5c0f* \u59cb\u7ec8\u96f6\uff0c\u663e\u793a\u5f53\u524d\u8fdb\u7a0b\u7684\u72b6\u6001\u4fe1\u606f Directories containing information about individual processes are named according to the PID number of the process. Some values can be modified to change how things are running in real time. Any changes made are lost at reboot. Examples: \u6709\u4e9b\u503c\u53ef\u4ee5\u4e34\u65f6\u5728\u7ebf\u66f4\u6539\u751f\u6548\uff0c\u4f46\u91cd\u542f\u540e\u4e22\u5931 /proc/cpuinfo/ - Processor information /proc/dma/ - Use of DMA ports /proc/interrupts/ - Use of interrupts /proc/ioports/ - Use of I/O ports /proc/filesystems/ - File system formats the kernel knows /proc/modules/ - Active modules /proc/mounts/ - Mounted file systems /proc/net/* - Network information and statistics /proc/partitions/ - Existing partitions /proc/bus/pci/ - Connected PCI devices /proc/bus/scsi/ - Connected SCSI devices /proc/sys/* - System and kernel information /proc/version - Kernel version /sys - System Information Directory A virtual file system that exists only in memory. Takes no space so file size always 0 \u865a\u62df\u6587\u4ef6\u7cfb\u7edf Provides information on: hardware buses hardware devices active devices drivers","title":"Linux File System Overview"},{"location":"linux/Administration/01/#lab-explore-filesystem-hierarchy","text":"Show the directory structure of the /data folder hierarchy of current logon user: mySUSE:~ # tree /data /data \u2514\u2500\u2500 linktype \u251c\u2500\u2500 file \u251c\u2500\u2500 hardlinkfile1 \u251c\u2500\u2500 hardlinkfile2 \u251c\u2500\u2500 symlinkfile1 -> file \u251c\u2500\u2500 symlinkfile1-1 -> symlinkfile1 \u2514\u2500\u2500 symlinkfile2 -> file Show only directories in the /data hierarchhy, not the files in them: mySUSE:~ # tree -d /data /data \u2514\u2500\u2500 linktype Show the files and directories in the /data hierarchy, including the full path and filename of each object. mySUSE:~ # tree -f /data /data \u2514\u2500\u2500 /data/linktype \u251c\u2500\u2500 /data/linktype/file \u251c\u2500\u2500 /data/linktype/hardlinkfile1 \u251c\u2500\u2500 /data/linktype/hardlinkfile2 \u251c\u2500\u2500 /data/linktype/symlinkfile1 -> file \u251c\u2500\u2500 /data/linktype/symlinkfile1-1 -> symlinkfile1 \u2514\u2500\u2500 /data/linktype/symlinkfile2 -> file","title":"Lab: Explore Filesystem Hierarchy"},{"location":"linux/Administration/01/#seven-different-types-of-files","text":"Normal files , examples: ASCII text files Executable files Graphics files Directories Organize files on the disk Contain files and subdirectories Implement the hierarchical file system Links Hard links Secondary file names for files on the disk Multiple file names referencing a single inode Referenced file must reside in the same file system Symbolic links: References to other files on the disk The inode contains a reference to another file name .Referenced files can exist in the same file system or in other file systems A symbolic link can reference a non-existent file (broken link) Sockets - Used for two-way communication between processes. \u5957\u63a5\u5b57 Pipes (FIFOs) - Used for one-way communication from one process to another. \u7ba1\u9053 Block Devices \u5757\u8bbe\u5907 Character Devices \u5b57\u7b26\u8bbe\u5907","title":"Seven Different types of files"},{"location":"linux/Administration/01/#linux-link-type","text":"Hard links : A hard link is a directory reference, or pointer, to a file on a storage volume. The name associated with the file is a label stored in a directory structure that refers the operating system to the file data. As such, more than one name can be associated with the same file. When accessed through different names, any changes made will affect the same file data. \u786c\u94fe\u63a5\u662f\u5b58\u50a8\u5377\u4e0a\u6587\u4ef6\u7684\u76ee\u5f55\u5f15\u7528\u6216\u6307\u9488\u3002 \u6587\u4ef6\u540d\u662f\u5b58\u50a8\u5728\u76ee\u5f55\u7ed3\u6784\u4e2d\u7684\u6807\u7b7e\uff0c\u76ee\u5f55\u7ed3\u6784\u6307\u5411\u6587\u4ef6\u6570\u636e\u3002 \u56e0\u6b64\uff0c\u53ef\u4ee5\u5c06\u591a\u4e2a\u6587\u4ef6\u540d\u4e0e\u540c\u4e00\u6587\u4ef6\u5173\u8054\u3002 \u901a\u8fc7\u4e0d\u540c\u7684\u6587\u4ef6\u540d\u8bbf\u95ee\u65f6\uff0c\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u662f\u9488\u5bf9\u6e90\u6587\u4ef6\u6570\u636e\u3002 Symbolic links : A symbolic link contains a text string that is interpreted and followed by the operating system as a path to another file or directory. It is a file on its own and can exist independently of its target. If a symbolic link is deleted, its target remains unaffected. If the target is moved, renamed or deleted, any symbolic link that used to point to it continues to exist but now points to a non-existing file. \u7b26\u53f7\u94fe\u63a5\u5305\u542b\u4e00\u4e2a\u6587\u672c\u5b57\u7b26\u4e32\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5c06\u5176\u89e3\u91ca\u5e76\u4f5c\u4e3a\u53e6\u4e00\u4e2a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u8def\u5f84\u3002 \u5b83\u672c\u8eab\u5c31\u662f\u4e00\u4e2a\u6587\u4ef6\uff0c\u53ef\u4ee5\u72ec\u7acb\u4e8e\u76ee\u6807\u800c\u5b58\u5728\u3002 \u5982\u679c\u5220\u9664\u4e86\u7b26\u53f7\u94fe\u63a5\uff0c\u5219\u5176\u76ee\u6807\u4e0d\u53d7\u5f71\u54cd\u3002 \u5982\u679c\u79fb\u52a8\uff0c\u91cd\u547d\u540d\u6216\u5220\u9664\u76ee\u6807\uff0c\u5219\u7528\u4e8e\u6307\u5411\u5b83\u7684\u4efb\u4f55\u7b26\u53f7\u94fe\u63a5\u5c06\u7ee7\u7eed\u5b58\u5728\uff0c\u4f46\u73b0\u5728\u6307\u5411\u4e0d\u5b58\u5728\u7684\u6587\u4ef6\u3002 Hard links can only be used when both the file and the link are in the same file system (on the same partition), because inode numbers are only unique within the same file system. You create a hard link by using the ln command, which points to the inode of an already existing file. Thereafter, the file can be accessed under both names\u2013that of the file and that of the link, and you can no longer discern which name existed first or how the original file and the link differ. \u4ec5\u5f53\u6587\u4ef6\u548c\u94fe\u63a5\u6587\u4ef6\u4f4d\u4e8e\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\uff08\u5728\u540c\u4e00\u5206\u533a\u4e0a\uff09\u65f6\uff0c\u624d\u80fd\u4f7f\u7528\u786c\u94fe\u63a5\uff0c\u56e0\u4e3ainode\u7f16\u53f7\u5728\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\u4e2d\u4ec5\u662f\u552f\u4e00\u7684\u3002 \u60a8\u53ef\u4ee5\u4f7f\u7528ln\u547d\u4ee4\u521b\u5efa\u786c\u94fe\u63a5\uff0c\u8be5\u547d\u4ee4\u6307\u5411\u5df2\u5b58\u5728\u6587\u4ef6\u7684inode\u3002 \u6b64\u540e\uff0c\u53ef\u4ee5\u5728\u6587\u4ef6\u7684\u540d\u79f0\u548c\u94fe\u63a5\u7684\u540d\u79f0\u4e0b\u8bbf\u95ee\u6587\u4ef6\uff0c\u5e76\u4e14\u65e0\u6cd5\u518d\u8bc6\u522b\u9996\u5148\u5b58\u5728\u7684\u540d\u79f0\u6216\u539f\u59cb\u6587\u4ef6\u548c\u94fe\u63a5\u7684\u4e0d\u540c\u4e4b\u5904\u3002 You can create a symbolic link with the ln command and the -s option. A symbolic link is assigned its own inode\u2014the link refers to a file, so a distinction can always be made between the link and the actual file. \u8f6f\u8fde\u63a5\u53ef\u4ee5\u9488\u5bf9\u76ee\u5f55\uff0c\u786c\u8fde\u63a5\u53ea\u80fd\u9488\u5bf9\u6587\u4ef6\u3002 A file system is essentially a database that is used to keep track of files in a volume. For normal files, data blocks are allocated to store the file's data, an inode is allocated to point to the data blocks as well as store the metadata about the file and then a file name is assigned to the inode. A hard link is a secondary file name associated with an existing inode. For symbolic links, a new inode is allocated with a new file name associated with it but the inode references another file name rather than referencing datablocks. \u6587\u4ef6\u7cfb\u7edf\u672c\u8d28\u4e0a\u662f\u4e00\u4e2a\u7528\u4e8e\u8ddf\u8e2a\u5377\u4e2d\u6587\u4ef6\u7684\u6570\u636e\u5e93\u3002 \u5bf9\u4e8e\u666e\u901a\u6587\u4ef6\uff0c\u5206\u914d\u6570\u636e\u5757\u4ee5\u5b58\u50a8\u6587\u4ef6\u7684\u6570\u636e\uff0c\u5206\u914dinode\u4ee5\u6307\u5411\u6570\u636e\u5757\u4ee5\u53ca\u5b58\u50a8\u5173\u4e8e\u6587\u4ef6\u7684\u5143\u6570\u636e\uff0c\u7136\u540e\u5c06\u6587\u4ef6\u540d\u5206\u914d\u7ed9inode\u3002 \u786c\u94fe\u63a5\u662f\u4e0e\u73b0\u6709inode\u5173\u8054\u7684\u8f85\u52a9\u6587\u4ef6\u540d\u3002 \u5bf9\u4e8e\u7b26\u53f7\u94fe\u63a5\uff0c\u5c06\u4e3a\u65b0\u7684inode\u5206\u914d\u4e00\u4e2a\u4e0e\u4e4b\u5173\u8054\u7684\u65b0\u6587\u4ef6\u540d\uff0c\u4f46inode\u5f15\u7528\u53e6\u4e00\u4e2a\u6587\u4ef6\u540d\u800c\u4e0d\u662f\u5f15\u7528\u6570\u636e\u5757\u3002 A good way to see the relationship between file names and inodes is to use the ls -il command. The typical size of an inode is 128 Bit and data blocks can range in size from 1k, 2k, 4k or larger depending on the file system type. \u67e5\u770b\u6587\u4ef6\u540d\u548cinode\u4e4b\u95f4\u5173\u7cfb\u7684\u597d\u65b9\u6cd5\u662f\u4f7f\u7528ls -il\u547d\u4ee4\u3002inode\u7684\u5178\u578b\u5927\u5c0f\u4e3a128\u4f4d\uff0c\u6570\u636e\u5757\u7684\u5927\u5c0f\u8303\u56f4\u53ef\u4ee5\u662f1k\uff0c2k\uff0c4k\u6216\u66f4\u5927\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u3002 \u786c\u94fe\u63a5\u76f8\u5f53\u4e8e\u589e\u52a0\u4e86\u4e00\u4e2a\u767b\u8bb0\u9879\uff0c\u4f7f\u5f97\u539f\u6765\u7684\u6587\u4ef6\u591a\u4e86\u4e00\u4e2a\u540d\u5b57\uff0c\u81f3\u4e8einode\u90fd\u6ca1\u53d8\u3002\u6240\u8c13\u7684\u767b\u8bb0\u9879\u5176\u5b9e\u662f\u76ee\u5f55\u6587\u4ef6\u4e2d\u7684\u4e00\u4e2a\u6761\u76ee(\u76ee\u5f55\u9879)\uff0c\u4f7f\u7528hard link \u662f\u8ba9\u591a\u4e2a\u4e0d\u540c\u7684\u76ee\u5f55\u9879\u6307\u5411\u540c\u4e00\u4e2a\u6587\u4ef6\u7684inode\uff0c\u6ca1\u6709\u591a\u4f59\u7684\u5185\u5bb9\u9700\u8981\u5b58\u50a8\u5728\u78c1\u76d8\u6247\u533a\u4e2d\uff0c\u6240\u4ee5hardlink\u4e0d\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 \u7b26\u53f7\u94fe\u63a5\u6709\u5355\u72ec\u7684inode\uff0c\u5728inode\u4e2d\u5b58\u653e\u53e6\u4e00\u4e2a\u6587\u4ef6\u7684\u8def\u5f84\u800c\u4e0d\u662f\u6587\u4ef6\u6570\u636e\uff0c\u6240\u4ee5\u7b26\u53f7\u94fe\u63a5\u4f1a\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002","title":"Linux Link Type"},{"location":"linux/Administration/01/#lab-file-link-type","text":"Create original file mySUSE:/data/linktype # echo \"it's original file\" > file mySUSE:/data/linktype # l -rw-r--r-- 1 root root 19 Mar 28 15 :20 file Create hardlink file (\u6ce8\u610ffile\u3001hardlinkfile1\u3001hardlinkfile2\u7684link\u4f4d\u7f6e\u7684\u6570\u503c\u7684\u53d8\u5316[\u7ea2\u8272]) mySUSE:/data/linktype # ln file hardlinkfile1 mySUSE:/data/linktype # ln -s file symlinkfile1 mySUSE:/data/linktype # ln -s file symlinkfile2 mySUSE:/data/linktype # l -rw-r--r-- 2 root root 19 Mar 28 15 :20 file -rw-r--r-- 2 root root 19 Mar 28 15 :20 hardlinkfile1 lrwxrwxrwx 1 root root 4 Mar 28 15 :21 symlinkfile1 -> file lrwxrwxrwx 1 root root 4 Mar 28 15 :23 symlinkfile2 -> file mySUSE:/data/linktype # ln file hardlinkfile2 mySUSE:/data/linktype # l -rw-r--r-- 3 root root 19 Mar 28 15 :20 file ( \u5305\u62ec\u81ea\u5df1\uff0c\u4e00\u5171\u67093\u4e2a\u786c\u94fe\u63a5 ) -rw-r--r-- 3 root root 19 Mar 28 15 :20 hardlinkfile1 ( \u7ee7\u627f\u4e86\u539f\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u91cf ) -rw-r--r-- 3 root root 19 Mar 28 15 :20 hardlinkfile2 ( \u7ee7\u627f\u4e86\u539f\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u91cf ) lrwxrwxrwx 1 root root 4 Mar 28 15 :21 symlinkfile1 -> file lrwxrwxrwx 1 root root 4 Mar 28 15 :23 symlinkfile2 -> file Modify content of file (original file). Content change were shown in all hard/soft link files mySUSE:/data/linktype # echo \"add oneline\" >> file mySUSE:/data/linktype # cat file it 's original file add oneline mySUSE:/data/linktype # cat hardlinkfile1 it' s original file add oneline mySUSE:/data/linktype # cat hardlinkfile2 it 's original file add oneline mySUSE:/data/linktype # cat symlinkfile1 it' s original file add oneline mySUSE:/data/linktype # cat symlinkfile2 it ' s original file add oneline To view the value stored in a symbolic link use the command readlink. mySUSE:/data/linktype # ln -s symlinkfile1 symlinkfile1-1 mySUSE:/data/linktype # ls -il 258 -rw-r--r-- 3 root root 31 Mar 28 15 :42 file 258 -rw-r--r-- 3 root root 31 Mar 28 15 :42 hardlinkfile1 258 -rw-r--r-- 3 root root 31 Mar 28 15 :42 hardlinkfile2 259 lrwxrwxrwx 1 root root 4 Mar 28 15 :21 symlinkfile1 -> file 265 lrwxrwxrwx 1 root root 12 Mar 28 15 :49 symlinkfile1-1 -> symlinkfile1 260 lrwxrwxrwx 1 root root 4 Mar 28 15 :23 symlinkfile2 -> file mySUSE:/data/linktype # readlink symlinkfile1 file mySUSE:/data/linktype # readlink symlinkfile2 file mySUSE:/data/linktype # readlink symlinkfile1-1 symlinkfile1 ( \u6ce8\u610f\uff1a\u8fd9\u4ecd\u7136\u662f\u4e00\u4e2a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6 ) mySUSE:/data/linktype # readlink -f symlinkfile1-1(\u53c2\u6570-f\u53ef\u4ee5\u76f4\u63a5\u5b9a\u4f4d\u771f\u6b63\u7684\u6e90\u6587\u4ef6) /data/linktype/file ( \u6ce8\u610f\uff1a\u8fd9\u624d\u662f\u771f\u6b63\u7684\u539f\u6587\u4ef6 )","title":"Lab: File Link Type"},{"location":"linux/Administration/01/#linux-device-file","text":"Represent hardware (except network cards). Each piece of hardware is represented by a device file. Network cards are interfaces. (\u533a\u522b) Link between hardware devices and the kernel drivers \u8bbe\u5907\u6587\u4ef6\u628a\u5185\u6838\u9a71\u52a8\u548c\u7269\u7406\u786c\u4ef6\u8bbe\u5907\u8fde\u63a5\u8d77\u6765 Kernel drivers read from and write to the device file \u5185\u6838\u9a71\u52a8\u7a0b\u5e8f\u5bf9\u8bbe\u5907\u6587\u4ef6\u8fdb\u884c\u8bfb\u5199\u6765\u5b9e\u73b0\u5bf9\u786c\u4ef6\u7684\u8bfb\u5199 The kernel gets the data to the actual hardware in the correct format \u5185\u6838\u4ee5\u6b63\u786e\u7684\u683c\u5f0f\u5bf9\u7269\u7406\u8bbe\u5907\u8fdb\u884c\u8bfb\u5199 Types: Block Devices. A block device reads/writes information in (normally) 512 byte large blocks. Character Devices. A character device reads/writes information character wise. Character devices provide unbuffered access directly to a hardware device. \u76f4\u63a5\u8bfb\u5199\uff0c\u4e0d\u901a\u8fc7\u7f13\u5b58 Sometimes referred to as raw devices. \u88f8\u8bbe\u5907\uff08\u6ce8\u610f\uff1a\u88f8\u8bbe\u5907\u88ab\u89c6\u4e3a\u5b57\u7b26\u8bbe\u5907\uff0c\u4e0d\u662f\u5757\u8bbe\u5907\uff09 any different options for character devices, making their use and application wide and varied. Created automatically by the OS (udev) when the device is discovered by the kernel. \u5185\u6838\u76f4\u63a5\u521b\u5efa\u5bf9\u5e94\u786c\u4ef6\u7684\u8bbe\u5907\u6587\u4ef6","title":"Linux Device File"},{"location":"linux/Administration/02/","text":"Useful Commands \u00b6 Some common abbreviations \u00b6 Abbreviations Description . represents the current directory .. represents the parent directory ~ represents the home directory ~username represents the home directory of user username Software package documentation \u00b6 /usr/share/doc/packages/ Release Notes \u00b6 /usr/share/doc/release-notes/ Command help \u00b6 -h or --help # tree --help Manual pages \u00b6 man [ section ] command # man 5 crontab # man /sestion options Show tree command manual: # man tree List for keywords: # man -k keyword Force mandb to update. Normally this is done daily via a cron job. # mandb Search for all instances of a command or a file named crontab # man -f crontab # whatis crontab (same output with above command) # man -k crontab # apropos crontab (same output with above command) To go directly to a given man page: # man 5 crontab * 1G : go to the 1 st line * 10G : go to the 10 th line * G : go to the end of the page * /^SELinux : search the word SELinux * /section OPTIONS : go to the section OPTIONS man\u5171\u6709\u4ee5\u4e0b\u51e0\u4e2a\u7ae0\u8282\uff0c\u6bd4\u5982\uff0cman 5 crontab\u5c31\u662f\u8fdb\u5165crontab\u7684\u7b2c5\u7ae0\u8282\uff1a Executable programs or shell commands \uff08\u6807\u51c6\u547d\u4ee4\uff09 System calls (functions provided by the kernel)\uff08\u7cfb\u7edf\u8c03\u7528\uff09 Library calls (functions within program libraries)\uff08\u5e93\u51fd\u6570\uff09 Special files (usually found in /dev)\uff08\u8bbe\u5907\u8bf4\u660e\uff09 File formats and conventions eg /etc/passwd \uff08\u6587\u4ef6\u683c\u5f0f\uff09 Games \uff08\u6e38\u620f\u548c\u5a31\u4e50\uff09 Miscellaneous (including macro packages and conventions)\uff08\u6742\u9879\uff0c\u60ef\u4f8b\u4e0e\u534f\u5b9a\u7b49\u7f51\u7edc\u534f\u5b9a\u3001ASCII code\u7b49\u7b49\u7684\u8aaa\u660e\uff09 System administration commands (usually only for root) \uff08\u7ba1\u7406\u5458\u547d\u4ee4\uff09 Kernel routines [Non standard] \uff08\u5176\u4ed6Linux\u7279\u5b9a\u7684\uff0c\u7528\u6765\u5b58\u653e\u5185\u6838\u4f8b\u884c\u7a0b\u5e8f\u7684\u6587\u6863\u3002\uff09 man\u5e38\u7528\u5feb\u6377\u952e \u7ffb\u5c4f \u5411\u540e\u7ffb\u4e00\u5c4f\uff1aspace(\u7a7a\u683c\u952e) \u5411\u524d\u7ffb\u4e00\u5c4f\uff1ab \u5411\u540e\u7ffb\u4e00\u884c\uff1aEnter(\u56de\u8f66\u952e) \u5411\u524d\u7ffb\u4e00\u884c\uff1ak \u67e5\u627e /\u5173\u952e\u8bcd ?\u5173\u952e\u8bcd n (\u4e0b\u4e00\u4e2a) N (\u524d\u4e00\u4e2a) man \u4e2d\u6587\u5316\u3002\u5728 /etc/profile \u52a0\u5165\u4e0b\u9762alias\uff0c\u53ef\u4ee5\u5728man\u4e2d\u8f93\u51fa\u4e2d\u6587 # For man in zh_CH alias cman='man -M /usr/share/man/zh_CN' Display descriptions: \u00b6 whatis command Info pages: \u00b6 info command # info # info top From the terminal window display the info pages for the info command by entering: # info info Move the cursor to the line referring to (Invoking Info) by pressing Tab Tab Follow the link by pressing Enter Move the cursor to the link Note Custom Key Bindings: by pressing Tab (6 times) Follow the link by pressing Enter Return to the page Note Custom Key Bindings: by typing (lowercase L): l Exit the info file by typing: q pwd command \u00b6 Display the current working directory cd command \u00b6 Change directory ls command \u00b6 Display directory contents * Display hidden files with -a option * Detailed listing with -l option * Output is recursive, including all subdirectories with -R option * With option -F After each name, a character indicates the file type (\u201c/\u201d for directories, \u201c*\u201d for executable files, \u201c|\u201d for FIFO files, \u201c@\u201d symbolic link). cp command \u00b6 Copy a file or directory Syntax: cp [option] Option -a : Copies a directory and subdirectories (compare -R ); symbolic links, file permissions, owners, and time stamps are not changed. \u5b83\u4fdd\u7559\u7b26\u53f7\u94fe\u63a5\u3001\u6587\u4ef6\u5c5e\u6027\uff0c\u5e76\u590d\u5236\u76ee\u5f55\u4e0b\u7684\u6240\u6709\u5185\u5bb9\u3002\u5176\u4f5c\u7528\u7b49\u4e8e-dpR\u53c2\u6570\u7ec4\u5408\u3002 Option -I : Asks before overwriting. Option -R , -r : Copies directories recursively (the directory and any subdirectories). \u9012\u5f52\u62f7\u8d1d\uff0c\u5305\u542b\u5b50\u76ee\u5f55\u53ca\uff08\u9690\u542b\uff09\u6587\u4ef6\uff0c\u7ee7\u627f\u76ee\u6807\u76ee\u5f55\u7684\u6743\u9650\u548c\u5c5e\u6027\u7b49 Option -l : Makes hardlinks instead of copying (\u521b\u5efa\u786c\u94fe\u63a5\u7684\u53e6\u5916\u4e00\u4e2a\u65b9\u6cd5) Option -s : Makes symbolic instead of copying (\u521b\u5efa\u7b26\u53f7\u94fe\u63a5\u7684\u53e6\u5916\u4e00\u4e2a\u65b9\u6cd5) Option -u : Copies a file only when the source file is newer than the destination file or when the destination file is missing. Option -p : \u8fde\u540c\u6863\u6848\u7684\u5c5e\u6027\u4e00\u8d77\u590d\u5236\u8fc7\u53bb\uff0c\u5305\u62ec\u4fee\u6539\u65f6\u95f4\u3001\u8bbf\u95ee\u6743\u9650\u3001\u6240\u6709\u8005\u7ec4\u7b49\uff0c\u800c\u975e\u4f7f\u7528\u9884\u8bbe\u5c5e\u6027\uff1b Labs: Initiate directories and files mySUSE:~ # su - pmgr pmgr@mySUSE:~> mkdir /data/program pmgr@mySUSE:~> mkdir /data/program/general pmgr@mySUSE:~> mkdir /data/program/general/staffing pmgr@mySUSE:~> touch /data/program/general/program_scope pmgr@mySUSE:~> touch /data/program/general/staffing/assignment mySUSE:~ # su - pm1 pm1@mySUSE:~> mkdir /data/project1 pm1@mySUSE:~> mkdir /data/project1/iot pm1@mySUSE:~> mkdir /data/project1/iot/bigdata pm1@mySUSE:~> touch /data/project1/iot/devicelist pm1@mySUSE:~> touch /data/project1/iot/bigdata/math_lib mySUSE:~ # su - pm2 pm2@mySUSE:~> mkdir /data/project2 pm2@mySUSE:~> mkdir /data/project2/erp pm2@mySUSE:~> mkdir /data/project2/erp/fin pm2@mySUSE:~> touch /data/project2/erp/erp_vision pm2@mySUSE:~> touch /data/project2/erp/fin/fin_ar pm2@mySUSE:~> chmod g+w /data/project2/erp/erp_vision pmgr@mySUSE:~> ln /data/project2/erp/erp_vision /data/program/general/p2_erp_version ( \u521b\u5efa\u786c\u94fe\u63a5\uff0c\u5f53\u524d\u7528\u6237\u9700\u8981\u5bf9\u6e90\u6587\u4ef6erp_vision\u6709w\u6743\u9650 ) pmgr@mySUSE:~> ln -s /data/project1/iot/devicelist /data/program/general/p1_devicelist ( \u521b\u5efa\u7b26\u53f7\u94fe\u63a5\uff0c\u4e0d\u9a8c\u8bc1\u5f53\u524d\u7528\u6237\u662f\u5426\u5bf9\u6e90\u6587\u4ef6devicelist\u6709\u6743\u9650 ) mySUSE:~ # tree /data /data \u251c\u2500\u2500 program \u2502 \u2514\u2500\u2500 general \u2502 \u251c\u2500\u2500 p1_devicelist -> /data/project1/iot/devicelist \u2502 \u251c\u2500\u2500 p2_erp_version \u2502 \u251c\u2500\u2500 program_scope \u2502 \u2514\u2500\u2500 staffing \u2502 \u2514\u2500\u2500 assignment \u251c\u2500\u2500 project1 \u2502 \u2514\u2500\u2500 iot \u2502 \u251c\u2500\u2500 bigdata \u2502 \u2502 \u2514\u2500\u2500 math_lib \u2502 \u2514\u2500\u2500 devicelist \u2514\u2500\u2500 project2 \u2514\u2500\u2500 erp \u251c\u2500\u2500 erp_vision \u2514\u2500\u2500 fin \u2514\u2500\u2500 fin_ar pmgr@mySUSE:~> cp -R /data/project1 /data/program/ ( /data/program/project1\u7684\u7528\u6237\u548c\u7ec4\u90fd\u7ee7\u627f\u4e86/data/program/ ) pmgr@mySUSE:~> cp -a /data/project2 /data/program/ ( /data/program/project2\u7684\u7528\u6237\u7ee7\u627f\u4e86/data/program/\uff0c\u4f46\u7ec4\u8fd8\u662f\u4fdd\u7559\u539f\u6765\u7684 ) mv command \u00b6 Move or rename a file or directory Option -i : Asks for confirmation before moving or renaming a file. This prevents existing files with the same name from being overwritten. Option -u : Only moves files that are newer than the target files of the same name. pmgr@mySUSE:/data/program/general> cp program_scope ./staffing/ pmgr@mySUSE:/data/program/general> mv -i program_scope ./staffing/ mv: overwrite './staffing/program_scope'? n rm command \u00b6 Delete a file or directory Option -i : Asks for confirmation before deleting. Option -r : (recursively) Allows full directories to be deleted. Option -f : (force) By default, rm asks for confirmation if the file that should be deleted is read-only. Using this option, the files are deleted without asking for confirmation. mkdir command \u00b6 Create a new directory Option -p lets you create a complete path (\u5c42\u7ea7\u8def\u5f84\u4e00\u6b21\u521b\u5efa) pmgr@mySUSE:/data> mkdir -p industry/utilities pmgr@mySUSE:/data> tree ./industry/ ./industry/ \u2514\u2500\u2500 utilities rmdir command \u00b6 Remove an empty directory. The directory or directories must be empty before you can delete them. ln command \u00b6 Create a link Default: Hard link Symbolic link with -s option Syntax: ln [-s] touch command \u00b6 Change the access and modification times Create an empty file if the given file does not exist. Change the time stamp of a file. Option -a : Changes only the time of the last read access (access time). Option -m : Changes only the time of the last modification (modification time). Option -r file : Sets the time stamp of file instead of the current time. Option -t time : Instead of the current time, sets time (structure: [[CC]YY]MMDDhhmm.[ss] ([Century]Year] Month Day Hour Minute [Seconds], two digits in each)) pmgr@mySUSE:/data/industry> touch readme pmgr@mySUSE:/data/industry> touch -a readme pmgr@mySUSE:/data/industry> touch -m readme pmgr@mySUSE:/data/industry> stat readme File: readme Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: 3dh/61d Inode: 338 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 1003/ pmgr) Gid: ( 1000/ admins) Access: 2019-03-31 10:07:47.489055973 +0800 Modify: 2019-03-31 10:07:58.805109884 +0800 Change: 2019-03-31 10:07:58.805109884 +0800 Birth: - cat command \u00b6 Concatenates files tac command \u00b6 Same as cat, but displays the file(s) in reverse pmgr@mySUSE:/data/industry> cat readme line 1 line 2 line 3 pmgr@mySUSE:/data/industry> tac readme line 3 line 2 line 1 more command \u00b6 Display file contents one page at a time less command \u00b6 Displays file contents for better navigation head command \u00b6 Displays the first 10 lines of a file. To set the number of lines use the -n option pmgr@mySUSE:/data/industry> head readme line 1 line 2 line 3 line 4 line 5 line 6 line 7 line 8 line 9 line 10 pmgr@mySUSE:/data/industry> head -n 5 readme line 1 line 2 line 3 line 4 line 5 tail command \u00b6 Display the last lines of a file To set the number of lines use the -n option To output appended data use -f option, displays a continuously updated view of the last lines of a file. To exit tail -f, press Ctrl+C. pmgr@mySUSE:/data/industry> tail -n 6 readme line 10 line 11 line 12 line 13 line 14 line 15 tar command \u00b6 Create, expand or list archive files Use option c to create an archive Use option f to specify the archive file name Use option v for verbose mode Use option x to extract an archive Use option t to list the content of an archive Use option z to (un-)compress the archive with gzip Use option j to (un-)compress the archive with bzip The /etc directory (include sub-directories) is backed up to the /backup/etc.tar file pmgr@mySUSE:~> tar -cvf /data/backup/project1.tar /data/project1/ pmgr@mySUSE:~> tar -cvf /data/backup/project2.tar /data/project2/ pmgr@mySUSE:~> tar -cv --exclude='*.conf' -f /data/backup/project2a.tar /data/project2/ View the contents of an archive. Some .conf files are excluded in project2a.tar file. pmgr@mySUSE:~> tar -tvf /data/backup/project2.tar drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/fin/ -rw-r--r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/fin/fin_ar -rw-r--r-- pm2/project2 0 2019-03-31 16:47 data/project2/erp/fin/fin.conf -rw-rw-r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/erp_vision -rw-r--r-- pm2/project2 0 2019-03-31 16:47 data/project2/erp/erp.conf -rw-r--r-- pm2/project2 0 2019-03-31 16:47 data/project2/project2.conf pmgr@mySUSE:~> tar -tvf /data/backup/project2a.tar drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/fin/ -rw-r--r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/fin/fin_ar -rw-rw-r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/erp_vision Unpack and write all files in the archive to the current directory. Extract to another directory by using the -C option pmgr@mySUSE:~> mkdir project1.backup pmgr@mySUSE:~> tar -xvf /data/backup/project1.tar -C /data/backup/project1.backup/ Incremental backup with tar command pmgr@mySUSE:~> tar -g snapshot_program -cvf /data/backup/bkp_program_full.tar /data/program/ pmgr@mySUSE:~> tar -tvf /data/backup/bkp_program_full.tar pmgr@mySUSE:~> touch /data/program/general/general.conf pmgr@mySUSE:~> tar -g snapshot_program -cvf /data/backup/bkp_program_inc.tar /data/program/ pmgr@mySUSE:~> rm -rf program/ pmgr@mySUSE:~> tar -xvf /data/backup/bkp_program_inc.tar -C /data/ cpio command \u00b6 Another archiving command gzip command \u00b6 Compress files using the gzip algorithm Option -c : Compresses the file without modifying the original file. The result is written to the standard output (usually the screen). From there, it can be redirected to a file with \u201c>\u201d. Option -d : Decompresses the specified file (gunzip) Option -r : Compresses and decompresses files in all subdirectories. Option -1 to -9, --fast, --best : Controls the compression speed: -1 means --fast and causes a quick compression but produces larger files, -9 corresponds to --best and requires more computing time but produces smaller files. The default setting is -6. gunzip command \u00b6 Expand files compressed with gzip bzip2 command \u00b6 Compress files using the bzip2 algorithm Option -c : Option -d : Decompresses the specified file (bunzip2). Option -1 to -9 : Controls the compression speed: -1 causes a quick compression but produces larger files, -9 requires more computing time but produces smaller files. The default setting is -9 . bunzip2 command \u00b6 Expand files compressed with bzip rsync command \u00b6 Copy only deltas between two directories. A key benefit of using rsync is that when copying data, rsync compares the source and the target directory and transfers only data that has changed or has been created. \u4ec5\u590d\u5236\u4e24\u4e2a\u76ee\u5f55\u4e4b\u95f4\u7684\u589e\u91cf\u3002 \u4f7f\u7528rsync\u7684\u4e00\u4e2a\u4e3b\u8981\u597d\u5904\u662f\uff0c\u5728\u590d\u5236\u6570\u636e\u65f6\uff0crsync\u4f1a\u6bd4\u8f83\u6e90\u76ee\u5f55\u548c\u76ee\u6807\u76ee\u5f55\uff0c\u5e76\u4ec5\u4f20\u8f93\u5df2\u66f4\u6539\u6216\u5df2\u521b\u5efa\u7684\u6570\u636e\u3002 Local or via network \u672c\u5730\u6216\u901a\u8fc7\u7f51\u7edc Uses ssh as default transport \u4f7f\u7528ssh\u4f5c\u4e3a\u9ed8\u8ba4\u4f20\u8f93 Can talk to rsync daemon on the remote machine \u53ef\u4ee5\u4e0e\u8fdc\u7a0b\u8ba1\u7b97\u673a\u4e0a\u7684rsync\u5b88\u62a4\u7a0b\u5e8f\u901a\u4fe1 Note: rsync must be installed on both the source and the target computer for this to work. \u5fc5\u987b\u5728\u6e90\u8ba1\u7b97\u673a\u548c\u76ee\u6807\u8ba1\u7b97\u673a\u4e0a\u5b89\u88c5rsync\u624d\u80fd\u4f7f\u5176\u6b63\u5e38\u5de5\u4f5c\u3002 As the default shell used by rsync is ssh, the -e option only needs to be used when you want to use something else than ssh. \u7531\u4e8ersync\u4f7f\u7528\u7684\u9ed8\u8ba4shell\u662fssh\uff0c\u56e0\u6b64\u53ea\u6709\u5728\u60f3\u8981\u4f7f\u7528\u9664ssh\u4ee5\u5916\u7684\u5176\u4ed6\u5de5\u5177\u65f6\u624d\u9700\u8981\u4f7f\u7528-e\u9009\u9879\u3002 Options Option -a : Puts rsync into the archive mode. The -a option ensures the following are preserved \u4fdd\u7559 in the mirrored copy of the directory: Symbolic links (l option) Access permissions (p option) Owners (o option) Group membership (g option) Time stamp (t option) Option -x : Saves files on one file system only, which means that rsync does not follow symbolic links to other file systems. \u4e0d\u8de8\u6587\u4ef6\u7cfb\u7edf\uff0c\u53ea\u5728\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u5185(don't cross filesyste* undaries) Option -v : Enables the verbose mode. Use this mode to output information about the transferred files and the progress of the copying process. \u8f93\u51fa\u4f20\u8f93\u8fc7\u7a0b\u7684\u7ec6\u8282\u4fe1\u606f Option -z : Compresses the data during the transfer. This is especially useful for remote synchronization. \u538b\u7f29\u65b9\u5f0f\u4f20\u8f93 Option --delete : Deletes files from the mirrored directory that no longer exist in the original directory. Option --exclude-from : Does not back up files listed in an exclude file. Local backup via rsync command pmgr@mySUSE:/data> rsync -av /data/industry/* /data/backup/industry/ sending incremental file list created directory /data/backup/industry readme utilities/ sent 264 bytes received 87 bytes 702.00 bytes/sec total size is 111 speedup is 0.32 pmgr@mySUSE:/data/industry/utilities> touch roadmap.txt pmgr@mySUSE:/data> rsync -av /data/industry/* /data/backup/industry/ sending incremental file list utilities/ utilities/roadmap.txt sent 171 bytes received 39 bytes 420.00 bytes/sec total size is 111 speedup is 0.53 pmgr@mySUSE:/data> rm roadmap.txt pmgr@mySUSE:/data> rsync -av /data/industry/* --delete /data/backup/industry/ sending incremental file list deleting utilities/roadmap.txt utilities/ sent 102 bytes received 41 bytes 286.00 bytes/sec total size is 111 speedup is 0.78 dd command \u00b6 Copies files block by block Used to create disk or partition images Most important options: if =input_file `of``=output_file bs =block_size You can use the dd command to convert and copy files byte-wise. Normally dd reads from the standard input and writes the result to the standard output. But with the appropriate parameters, regular files can be addressed as well. You can copy all kinds of Linux data with this command, including entire hard disk partitions. You can even copy an entire installed system (or just parts of it). Copy file /etc/protocols to protocols.old. The default size for a record is 512 bytes. Below 45+1 means, 45 complete record of standard size and 1 incomplete record (less than 512 bytes pmgr@mySUSE:/data/program> dd if=/etc/protocols of=protocols.old bs=512 45+1 records in 45+1 records out 23259 bytes (23 kB, 23 KiB) copied, 0.000595392 s, 39.1 MB/s \u521b\u5efa\u4e00\u4e2a100M\u7684\u7a7a\u6587\u4ef6 pmgr@mySUSE:/data/program> dd if=/dev/zero of=datafile bs=100M count=2 2+0 records in 2+0 records out 209715200 bytes (210 MB, 200 MiB) copied, 2.79311 s, 75.1 MB/s \u5907\u4efd\u6574\u4e2a\u5206\u533a #dd if=/dev/sda1 of=boot.partition \u5236\u4f5cU\u76d8\u542f\u52a8\u76d8\uff08U\u76d8\u6302\u8f7d\u5230/dev/sdb\uff09 #dd if=/root/diskboot.img of=/dev/sdb bs=125682176 \u5907\u4efd\u786c\u76d8\u4e3b\u5f15\u5bfc\u8bb0\u5f55 #dd if=/dev/sda of=/tmp/mbr_copy bs=512 count=1 \u8fd8\u539f\u786c\u76d8\u4e3b\u5f15\u5bfc\u8bb0\u5f55 #dd if=/disk.mbr of=/dev/hda bs=512 count=1 \u5c06\u5185\u5b58\u91cc\u7684\u6570\u636e\u62f7\u8d1d\u5230root\u76ee\u5f55\u4e0b\u7684mem.bin\u6587\u4ef6 # dd if=/dev/mem of=/root/mem.bin bs=1024 \u62f7\u8d1d\u5149\u76d8\u6570\u636e\u5230root\u6587\u4ef6\u5939\u4e0b\uff0c\u5e76\u4fdd\u5b58\u4e3acd.iso\u6587\u4ef6 # dd if=/dev/cdrom of=/root/cd.iso \u5229\u7528\u968f\u673a\u7684\u6570\u636e\u586b\u5145\u786c\u76d8(\u9500\u6bc1\u786c\u76d8\u6570\u636e) # dd if=/dev/urandom of=/dev/hda1 \u6d4b\u8bd5\u786c\u76d8\u8bfb\u5199\u901f\u5ea6\u3002\u901a\u8fc7\u4e24\u4e2a\u547d\u4ee4\u8f93\u51fa\u7684\u6267\u884c\u65f6\u95f4\uff0c\u53ef\u4ee5\u8ba1\u7b97\u51fa\u6d4b\u8bd5\u786c\u76d8\u7684\u8bfb\uff0f\u5199\u901f\u5ea6\uff1a mySUSE:/data # dd if=/data/program/datafile bs=64k | dd of=/dev/null 3200+0 records in 3200+0 records out 209715200 bytes (210 MB, 200 MiB) copied, 0.67138 s, 312 MB/s 409600+0 records in 409600+0 records out 209715200 bytes (210 MB, 200 MiB) copied, 0.675912 s, 310 MB/s # dd if=/dev/zero of=/data/program/datafile bs=1024 count=100 \u5207\u5272\u5927\u6587\u4ef6bigfile\uff0c\u517198336321\u5b57\u8282\uff0c\u5219\uff1a # dd if=bigfile of=smallfile1 bs=1 count=20000000 # dd if=bigfile of=smallfile2 bs=1 count=20000000 skip=20000000 # dd if=bigfile of=smallfile3 bs=1 count=20000000 skip=40000000 # dd if=bigfile of=smallfile4 bs=1 count=20000000 skip=60000000 # dd if=bigfile of=smallfile5 bs=1 count=18336321 skip=80000000 \u5c06\u5207\u5272\u6587\u4ef6\u7ec4\u88c5 # dd if=smallfile1 of=bigfile bs=1 count=20000000 # dd if=smallfile2 of=bigfile bs=1 count=20000000 seek=20000000 # dd if=smallfile3 of=bigfile bs=1 count=20000000 seek=40000000 # dd if=smallfile4 of=bigfile bs=1 count=20000000 seek=60000000 # dd if=smallfile5 of=bigfile bs=1 count=18336321 seek=80000000 if: \u8981\u5207\u5272\u7684\u5927\u6587\u4ef6\u540d of: \u5207\u5272\u540e\u7684\u5b50\u6587\u4ef6\u540d bs: \u4ee5\u591a\u5c11\u5b57\u8282\u4f5c\u4e3a\u4e00\u4e2a\u5207\u5272\u8bb0\u5f55\u5355\u4f4d count: \u662f\u8981\u5207\u5272\u7684\u5355\u4f4d\u8bb0\u5f55\u6570 skip: \u8bf4\u660e\u5207\u5272\u65f6\u7684\u8d77\u70b9 seek: \u660e\u786e\u6307\u51fa\u5f00\u59cb\u4f4d\u7f6e find command \u00b6 Search for files or directories Syntax: find path criterion [action] The find command has a multitude of options, a few of which are explained here. You can use the following arguments with the command: path: The section of the file system to search (the specified directory and all its subdirectories). If nothing is specified, the file system below the current directory is used. criterion: The properties the file should have (see below) action: Options that influence the following conditions or control the search as a whole The most important actions are: -print (default) -exec command With the -exec option, you can call up another command. This option is frequently used to link find and grep, as in the following: \u627e\u51fagen\u5f00\u5934\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -name gen\\* ./program/general ./program/general/general.conf \u627e\u51fagen\u5f00\u5934\u7684\u6587\u4ef6\uff0c\u5e76\u5728\u6587\u4ef6\u5185\u5bb9\u4e2d\u67e5\u627exen\uff0c\u627e\u5230\u540e\u7ed3\u679c\u8f93\u51faxen pmgr@dcmaster:/data> find . -name gen\\* -type f -exec grep xen {} \\; xen xening The two brackets \u201c{}\u201d stand as placeholders for the file names which are found and passed to the grep command. The semicolon closes the -exec instruction. Because this is a special character, it is masked by placing a backslash in front of it. -ctime [\u00b1]days Searches for files whose last change took place no later than (no earlier than) a specified number of days ago. \u5728\u8fc7\u53bbn\u5929\u5185\u88ab\u4fee\u6539\u8fc7\u7684\u6587\u4ef6 mgr@dcmaster:/data> find . -ctime 1 . ./program/datafile -gid number Searches for files with the numeric GID (Group ID) number. (gid \u662f n) -group name Searches for files that are owned by the group name. Instead of a name, the numeric GID is allowed. (group \u540d\u79f0\u662f name) -name pattern Searches for files whose names contain the given pattern. If the pattern contains meta characters or wild cards, the name must be enclosed by quotation marks. Otherwise thename will be interpreted by the shell and not by find. -newer file Searches for files that were modified more recently than file. \u6bd4\u6587\u4ef6 file \u66f4\u65b0\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -cnewer ./program/datafile . -size [\u00b1]size Matches files that are above or below a certain size. The size (in blocks of 512 bytes) is given as an argument. The suffix \u201cc\u201cswitches to byte and \u201ck\u201d to blocks of 1024bytes. A preceding \u201c+\u201d stands for all larger files and a \u201c-\u201d for all smaller files. (\u6587\u4ef6\u5927\u5c0f \u662f n \u2022 b \u4ee3\u8868 512 \u4f4d\u5143\u7ec4\u7684\u533a\u5757 \u2022 c \u8868\u793a\u5b57\u5143\u6570 \u2022 k \u8868\u793a kilo bytes \u2022 w \u662f\u4e8c\u4e2a\u4f4d\u5143\u7ec4 pmgr@dcmaster:/data> find . -size 20k ./backup/project2.tar -type file_type Searches for a file type. A file type can be one of the following: * c : \u6587\u4ef6\u7c7b\u578b\u662f c \u7684\u6587\u4ef6\u3002 * d: \u76ee\u5f55 * c: \u5b57\u578b\u88c5\u7f6e\u6587\u4ef6 * b: \u533a\u5757\u88c5\u7f6e\u6587\u4ef6 * p: \u5177\u540d\u8d2e\u5217 * f: \u4e00\u822c\u6587\u4ef6 * l: \u7b26\u53f7\u8fde\u7ed3 * s: socket -uid number Searches for files with the numeric UID (User ID) number. -user name Searches for files, which are owned by user name. Instead of a name, the numeric UID is allowed. \u5e38\u7528\u53c2\u6570 mount, -xdev : \u53ea\u68c0\u67e5\u548c\u6307\u5b9a\u76ee\u5f55\u5728\u540c\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u4e0b\u7684\u6587\u4ef6\uff0c\u907f\u514d\u5217\u51fa\u5176\u5b83\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6587\u4ef6 amin n : \u5728\u8fc7\u53bb n \u5206\u949f\u5185\u88ab\u8bfb\u53d6\u8fc7 anewer file : \u6bd4\u6587\u4ef6 file \u66f4\u665a\u88ab\u8bfb\u53d6\u8fc7\u7684\u6587\u4ef6 atime n : \u5728\u8fc7\u53bbn\u5929\u5185\u88ab\u8bfb\u53d6\u8fc7\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -atime 1 ./program/datafile cmin n : \u5728\u8fc7\u53bb n \u5206\u949f\u5185\u88ab\u4fee\u6539\u8fc7 pmgr@dcmaster:/data> find . -cmin 20 empty : \u7a7a\u7684\u6587\u4ef6 ipath p, -path p : \u8def\u5f84\u540d\u79f0\u7b26\u5408 p \u7684\u6587\u4ef6\uff0cipath \u4f1a\u5ffd\u7565\u5927\u5c0f\u5199 name name, -iname name : \u6587\u4ef6\u540d\u79f0\u7b26\u5408 name \u7684\u6587\u4ef6\u3002iname \u4f1a\u5ffd\u7565\u5927\u5c0f\u5199 pid n : process id \u662f n \u7684\u6587\u4ef6 \u67e5\u627e\u5f53\u524d\u76ee\u5f55\u53ca\u5b50\u76ee\u5f55\u4e2d\u6240\u6709\u6587\u4ef6\u957f\u5ea6\u4e3a0\u7684\u666e\u901a\u6587\u4ef6\uff0c\u5e76\u5217\u51fa\u5b83\u4eec\u7684\u5b8c\u6574\u8def\u5f84 pmgr@dcmaster:/data> find . -type f -size 0 -exec ls -l {} \\; \u67e5\u627e\u524d\u76ee\u5f55\u4e2d\u6587\u4ef6\u5c5e\u4e3b\u5177\u6709\u8bfb\u3001\u5199\u6743\u9650\uff0c\u5e76\u4e14\u6587\u4ef6\u6240\u5c5e\u7ec4\u7684\u7528\u6237\u548c\u5176\u4ed6\u7528\u6237\u5177\u6709\u8bfb\u6743\u9650\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -type f -perm 644 -exec ls -l {} \\; \u67e5\u627e/var/log\u76ee\u5f55\u4e2d\u66f4\u6539\u65f6\u95f4\u572817\u65e5\u4ee5\u524d\u7684\u666e\u901a\u6587\u4ef6\uff0c\u5e76\u5728\u5220\u9664\u4e4b\u524d\u8be2\u95ee\u5b83\u4eec pmgr@dcmaster:/data> find /var/log -type f -mtime +17 -ok rm {} \\; \u5c06\u76ee\u524d\u76ee\u5f55\u53ca\u5176\u5b50\u76ee\u5f55\u4e0b\u6240\u6709\u6700\u8fd1 1 \u5929\u5185\u66f4\u65b0\u8fc7\u7684\u6587\u4ef6\u5217\u51fa mgr@dcmaster:/data> find . -ctime 1 \u5c06\u76ee\u524d\u76ee\u5f55\u5176\u5176\u4e0b\u5b50\u76ee\u5f55\u4e2d\u6240\u6709\u4e00\u822c\u6587\u4ef6\u5217\u51fa pmgr@dcmaster:/data> find . -type f \u5c06\u76ee\u524d\u76ee\u5f55\u53ca\u5176\u5b50\u76ee\u5f55\u4e0b\u6240\u6709\u5ef6\u4f38\u6863\u540d\u662fconf \u7684\u6587\u4ef6\u5217\u51fa\u6765 pmgr@dcmaster:/data> find . -name \"*.conf\" which command \u00b6 Searches all paths listed in the variable $PATH and returns the full path of the command The which command searches all paths listed in the variable $PATH for the specified command and returns the full path of the command. In the variable \\(PATH, the most important directoriesare listed where the shell looks for executable files. which\u547d\u4ee4\u641c\u7d22\u53d8\u91cf\\) PATH\u4e2d\u5217\u51fa\u7684\u6240\u6709\u8def\u5f84\u4ee5\u83b7\u53d6\u6307\u5b9a\u547d\u4ee4\uff0c\u5e76\u8fd4\u56de\u547d\u4ee4\u7684\u5b8c\u6574\u8def\u5f84\u3002 The which command is especially useful if several versions of a command exist in different directories and you want to know which version is executed when entered without specifying apath. \u5982\u679c\u547d\u4ee4\u7684\u591a\u4e2a\u7248\u672c\u5b58\u5728\u4e8e\u4e0d\u540c\u7684\u76ee\u5f55\u4e2d\uff0c\u5e76\u4e14\u60a8\u60f3\u77e5\u9053\u5728\u8f93\u5165\u65f6\u6267\u884c\u4e86\u54ea\u4e2a\u7248\u672c\u800c\u672a\u6307\u5b9a\u8def\u5f84\uff0c\u90a3\u4e48which\u547d\u4ee4\u7279\u522b\u6709\u7528\u3002 NOTE: To see the content of a variable, use the echo command Options Description -n<\u6587\u4ef6\u540d\u957f\u5ea6> \u6307\u5b9a\u6587\u4ef6\u540d\u957f\u5ea6\uff0c\u6307\u5b9a\u7684\u957f\u5ea6\u5fc5\u987b\u5927\u4e8e\u6216\u7b49\u4e8e\u6240\u6709\u6587\u4ef6\u4e2d\u6700\u957f\u7684\u6587\u4ef6\u540d\u3002 -p<\u6587\u4ef6\u540d\u957f\u5ea6> \u4e0e-n\u53c2\u6570\u76f8\u540c\uff0c\u4f46\u6b64\u5904\u7684<\u6587\u4ef6\u540d\u957f\u5ea6>\u5305\u62ec\u4e86\u6587\u4ef6\u7684\u8def\u5f84\u3002 -w \u6307\u5b9a\u8f93\u51fa\u65f6\u680f\u4f4d\u7684\u5bbd\u5ea6\u3002 -V \u663e\u793a\u7248\u672c\u4fe1\u606f # which grep /usr/bin/grep # which -V grep GNU which v2.21, Copyright (C) 1999 - 2015 Carlo Wood. GNU which comes with ABSOLUTELY NO WARRANTY; This program is free software; your freedom to use, change and distribute this program is protected by the GPL. whereis command \u00b6 The whereis command returns the binaries (option -b), manual pages (option -m), and the source code (option -s) of the specified command. If no option is used, all this information is returned, provided the information is available. This command is faster than find, but it is less thorough. Attempts to locate the desired program in the standard Linux places, and in the places specified by $PATH and $MANPATH . \u5c1d\u8bd5\u5728\u6807\u51c6Linux\u4f4d\u7f6e\u548c\u6307\u5b9a\u4f4d\u7f6e( \\(PATH\u548c\\) MANPATH)\u627e\u5230\u6240\u9700\u7684\u7a0b\u5e8f Options Description -b \u53ea\u67e5\u627e\u4e8c\u8fdb\u5236\u6587\u4ef6\u3002 -B<\u76ee\u5f55> \u53ea\u5728\u8bbe\u7f6e\u7684\u76ee\u5f55\u4e0b\u67e5\u627e\u4e8c\u8fdb\u5236\u6587\u4ef6\u3002 -f \u4e0d\u663e\u793a\u6587\u4ef6\u540d\u524d\u7684\u8def\u5f84\u540d\u79f0\u3002 -m \u53ea\u67e5\u627e\u8bf4\u660e\u6587\u4ef6\u3002 -M<\u76ee\u5f55> \u53ea\u5728\u8bbe\u7f6e\u7684\u76ee\u5f55\u4e0b\u67e5\u627e\u8bf4\u660e\u6587\u4ef6\u3002 -s \u53ea\u67e5\u627e\u539f\u59cb\u4ee3\u7801\u6587\u4ef6\u3002 -S<\u76ee\u5f55> \u53ea\u5728\u8bbe\u7f6e\u7684\u76ee\u5f55\u4e0b\u67e5\u627e\u539f\u59cb\u4ee3\u7801\u6587\u4ef6\u3002 -u \u67e5\u627e\u4e0d\u5305\u542b\u6307\u5b9a\u7c7b\u578b\u7684\u6587\u4ef6\u3002 \u4ee5\u4e0b\u8f93\u51fa\u4fe1\u606f\u4ece\u5de6\u81f3\u53f3\u5206\u522b\u4e3a\u67e5\u8be2\u7684\u7a0b\u5e8f\u540d\u3001bash\u8def\u5f84\u3001bash\u7684man\u624b\u518c\u9875\u8def\u5f84\u3002 # whereis grep grep: /usr/bin/grep /bin/grep /usr/share/man/man1/grep.1.gz /usr/share/info/grep.info.gz \u663e\u793abash \u547d\u4ee4\u7684\u4e8c\u8fdb\u5236\u7a0b\u5e8f # whereis -b grep grep: /usr/bin/grep /bin/grep \u663e\u793abash \u547d\u4ee4\u7684\u5e2e\u52a9\u6587\u4ef6 # whereis -m grep grep: /usr/share/man/man1/grep.1.gz /usr/share/info/grep.info.gz type command \u00b6 The type command shows what kind of command is executed when you enter it: \u547d\u4ee4\u7684\u7c7b\u578b a shell built-in command (an essential command that is hard coded in the shell), for example type or cd an external command (called by the shell) an alias, for example ls. An alias defines shortcuts and synonyms for commonly used shell commands. a function The -a option delivers all instances of a command bearing this name in the file system. NOTE: If you want to have more information about a file format, you can use the file command. \u4e0d\u9002\u7528\u4e8e\u666e\u901a\u6587\u4ef6 dcmaster:/data/shell # type pwd.txt -bash: type: pwd.txt: not found \u4e0d\u9002\u7528\u4e8e\u81ea\u5b9a\u4e49\u53ef\u6267\u884c\u811a\u672c dcmaster:/data/shell # type math.sh -bash: type: math.sh: not found \u7cfb\u7edf\u547d\u4ee4 dcmaster:/data/shell # type rsync rsync is /usr/bin/rsync \u522b\u540d dcmaster:/data/shell # type l l is aliased to `ls -alF' file command \u00b6 file\u547d\u4ee4\u7528\u4e8e\u8fa8\u8bc6\u6587\u4ef6\u7c7b\u578b -b \u5217\u51fa\u8fa8\u8bc6\u7ed3\u679c\u65f6\uff0c\u4e0d\u663e\u793a\u6587\u4ef6\u540d\u79f0\u3002 -c \u8be6\u7ec6\u663e\u793a\u6307\u4ee4\u6267\u884c\u8fc7\u7a0b\uff0c\u4fbf\u4e8e\u6392\u9519\u6216\u5206\u6790\u7a0b\u5e8f\u6267\u884c\u7684\u60c5\u5f62\u3002 -f <\u540d\u79f0\u6587\u4ef6> \u6307\u5b9a\u540d\u79f0\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u6587\u4ef6\u540d\u79f0\u65f6\uff0c\u8ba9file\u4f9d\u5e8f\u8fa8\u8bc6\u8fd9\u4e9b\u6587\u4ef6\uff0c\u683c\u5f0f\u4e3a\u6bcf\u5217\u4e00\u4e2a\u6587\u4ef6\u540d\u79f0\u3002 -L \u76f4\u63a5\u663e\u793a\u7b26\u53f7\u8fde\u63a5\u6240\u6307\u5411\u7684\u6587\u4ef6\u7684\u7c7b\u522b\u3002 -m<\u9b54\u6cd5\u6570\u5b57\u6587\u4ef6> \u6307\u5b9a\u9b54\u6cd5\u6570\u5b57\u6587\u4ef6\u3002 -v \u663e\u793a\u7248\u672c\u4fe1\u606f\u3002 -z \u5c1d\u8bd5\u53bb\u89e3\u8bfb\u538b\u7f29\u6587\u4ef6\u7684\u5185\u5bb9\u3002 dcmaster:/data/linktype # l -rw-r--r-- 3 root root 44 May 3 09:50 file -rw-r--r-- 3 root root 44 May 3 09:50 hardlinkfile1 -rw-r--r-- 3 root root 44 May 3 09:50 hardlinkfile2 lrwxrwxrwx 1 root root 4 Mar 28 15:21 symlinkfile1 -> file lrwxrwxrwx 1 root root 12 Mar 28 15:49 symlinkfile1-1 -> symlinkfile1 lrwxrwxrwx 1 root root 4 Mar 28 15:23 symlinkfile2 -> file dcmaster:/data/linktype # file hardlinkfile1 hardlinkfile1: ASCII text dcmaster:/data/linktype # file -i hardlinkfile1 hardlinkfile1: text/plain; charset=us-ascii dcmaster:/data/linktype # file /data/linktype/ /data/linktype/: directory dcmaster:/data/linktype # file -L /data/linktype/ /data/linktype/: directory dcmaster:/data/linktype # file -i /data/linktype/ /data/linktype/: inode/directory; charset=binary dcmaster:/data/linktype # file symlinkfile1 symlinkfile1: symbolic link to file dcmaster:/data/linktype # file -i symlinkfile1 symlinkfile1: inode/symlink; charset=binary grep command \u00b6 You can specify search patterns in the form of regular expressions, although the basic grep command is limited in this regard. To search for more complex patterns, use the egrep command (or grep -E ) instead, which accepts extended regular expressions. To avoid having special characters in search patterns interpreted by the shell, enclose the pattern in quotation marks. Syntax: grep [options] search_pattern filename * egrep = grep -E * rgrep \u53c2\u6570 -a \u6216 --text : \u4e0d\u8981\u5ffd\u7565\u4e8c\u8fdb\u5236\u7684\u6570\u636e\u3002 -A<\u663e\u793a\u884c\u6570> \u6216 --after-context=<\u663e\u793a\u884c\u6570> : \u9664\u4e86\u663e\u793a\u7b26\u5408\u8303\u672c\u6837\u5f0f\u7684\u90a3\u4e00\u5217\u4e4b\u5916\uff0c\u5e76\u663e\u793a\u8be5\u884c\u4e4b\u540e\u7684\u5185\u5bb9\u3002 -b \u6216 --byte-offset : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u6807\u793a\u51fa\u8be5\u884c\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u7f16\u53f7\u3002 -B<\u663e\u793a\u884c\u6570> \u6216 --before-context=<\u663e\u793a\u884c\u6570> : \u9664\u4e86\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u5916\uff0c\u5e76\u663e\u793a\u8be5\u884c\u4e4b\u524d\u7684\u5185\u5bb9\u3002 -c \u6216 --count : \u8ba1\u7b97\u7b26\u5408\u6837\u5f0f\u7684\u5217\u6570\u3002 -C<\u663e\u793a\u884c\u6570> \u6216 --context=<\u663e\u793a\u884c\u6570> \u6216 -<\u663e\u793a\u884c\u6570> : \u9664\u4e86\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u5916\uff0c\u5e76\u663e\u793a\u8be5\u884c\u4e4b\u524d\u540e\u7684\u5185\u5bb9\u3002 -d <\u52a8\u4f5c> \u6216 --directories=<\u52a8\u4f5c> : \u5f53\u6307\u5b9a\u8981\u67e5\u627e\u7684\u662f\u76ee\u5f55\u800c\u975e\u6587\u4ef6\u65f6\uff0c\u5fc5\u987b\u4f7f\u7528\u8fd9\u9879\u53c2\u6570\uff0c\u5426\u5219grep\u6307\u4ee4\u5c06\u56de\u62a5\u4fe1\u606f\u5e76\u505c\u6b62\u52a8\u4f5c\u3002 -e<\u8303\u672c\u6837\u5f0f> \u6216 --regexp=<\u8303\u672c\u6837\u5f0f> : \u6307\u5b9a\u5b57\u7b26\u4e32\u505a\u4e3a\u67e5\u627e\u6587\u4ef6\u5185\u5bb9\u7684\u6837\u5f0f\u3002 -E \u6216 --extended-regexp : \u5c06\u6837\u5f0f\u4e3a\u5ef6\u4f38\u7684\u666e\u901a\u8868\u793a\u6cd5\u6765\u4f7f\u7528\u3002 -f<\u89c4\u5219\u6587\u4ef6> \u6216 --file=<\u89c4\u5219\u6587\u4ef6> : \u6307\u5b9a\u89c4\u5219\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u542b\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u89c4\u5219\u6837\u5f0f\uff0c\u8ba9grep\u67e5\u627e\u7b26\u5408\u89c4\u5219\u6761\u4ef6\u7684\u6587\u4ef6\u5185\u5bb9\uff0c\u683c\u5f0f\u4e3a\u6bcf\u884c\u4e00\u4e2a\u89c4\u5219\u6837\u5f0f\u3002 -F \u6216 --fixed-regexp : \u5c06\u6837\u5f0f\u89c6\u4e3a\u56fa\u5b9a\u5b57\u7b26\u4e32\u7684\u5217\u8868\u3002 -G \u6216 --basic-regexp : \u5c06\u6837\u5f0f\u89c6\u4e3a\u666e\u901a\u7684\u8868\u793a\u6cd5\u6765\u4f7f\u7528\u3002 -h \u6216 --no-filename : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u4e0d\u6807\u793a\u8be5\u884c\u6240\u5c5e\u7684\u6587\u4ef6\u540d\u79f0\u3002 -H \u6216 --with-filename : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u8868\u793a\u8be5\u884c\u6240\u5c5e\u7684\u6587\u4ef6\u540d\u79f0\u3002 -i \u6216 --ignore-case : \u5ffd\u7565\u5b57\u7b26\u5927\u5c0f\u5199\u7684\u5dee\u522b\u3002 -l \u6216 --file-with-matches : \u5217\u51fa\u6587\u4ef6\u5185\u5bb9\u7b26\u5408\u6307\u5b9a\u7684\u6837\u5f0f\u7684\u6587\u4ef6\u540d\u79f0\u3002 -L \u6216 --files-without-match : \u5217\u51fa\u6587\u4ef6\u5185\u5bb9\u4e0d\u7b26\u5408\u6307\u5b9a\u7684\u6837\u5f0f\u7684\u6587\u4ef6\u540d\u79f0\u3002 -n \u6216 --line-number : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u6807\u793a\u51fa\u8be5\u884c\u7684\u5217\u6570\u7f16\u53f7\u3002 -o \u6216 --only-matching : \u53ea\u663e\u793a\u5339\u914dPATTERN \u90e8\u5206\u3002 -q \u6216 --quiet\u6216--silent : \u4e0d\u663e\u793a\u4efb\u4f55\u4fe1\u606f\u3002 -r \u6216 --recursive : \u6b64\u53c2\u6570\u7684\u6548\u679c\u548c\u6307\u5b9a\"-d recurse\"\u53c2\u6570\u76f8\u540c\u3002 -s \u6216 --no-messages : \u4e0d\u663e\u793a\u9519\u8bef\u4fe1\u606f\u3002 -v \u6216 --revert-match : \u663e\u793a\u4e0d\u5305\u542b\u5339\u914d\u6587\u672c\u7684\u6240\u6709\u884c\u3002 -V \u6216 --version : \u663e\u793a\u7248\u672c\u4fe1\u606f\u3002 -w \u6216 --word-regexp : \u53ea\u663e\u793a\u5168\u5b57\u7b26\u5408\u7684\u5217\u3002 -x --line-regexp : \u53ea\u663e\u793a\u5168\u5217\u7b26\u5408\u7684\u5217\u3002 -y : \u6b64\u53c2\u6570\u7684\u6548\u679c\u548c\u6307\u5b9a\"-i\"\u53c2\u6570\u76f8\u540c\u3002 \u5728\u5f53\u524d\u76ee\u5f55\u4e2d\uff0c\u67e5\u627e\u540e\u7f00\u6709conf\u5b57\u6837\u7684\u6587\u4ef6\u4e2d\u5305\u542bxen\u5b57\u7b26\u4e32\u7684\u6587\u4ef6\uff0c\u5e76\u6253\u5370\u51fa\u8be5\u5b57\u7b26\u4e32\u7684\u884c\u3002 pmgr@dcmaster:/data/program/general> grep xen *.conf xen xening \u67e5\u627e\u524d\u7f00\u6709gen\u7684\u6587\u4ef6\u5305\u542bxen\u5b57\u7b26\u4e32\u7684\u6587\u4ef6 pmgr@dcmaster:/data/program/general> grep xen gen* xen xening \u4ee5\u9012\u5f52\u7684\u65b9\u5f0f\u67e5\u627e\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u3002\u67e5\u627e\u6307\u5b9a\u76ee\u5f55/data/program/\u53ca\u5176\u5b50\u76ee\u5f55\uff08\u5982\u679c\u5b58\u5728\u5b50\u76ee\u5f55\u7684\u8bdd\uff09\u4e0b\u6240\u6709\u6587\u4ef6\u4e2d\u5305\u542b\u5b57\u7b26\u4e32xen\u7684\u6587\u4ef6\uff0c\u5e76\u6253\u5370\u51fa\u8be5\u5b57\u7b26\u4e32\u6240\u5728\u884c\u7684\u5185\u5bb9 pmgr@dcmaster:/data> grep -r xen /data/program/ ./program/general/general.conf:xen ./program/general/general.conf:xening \u53cd\u5411\u67e5\u627e\u3002\u524d\u9762\u5404\u4e2a\u4f8b\u5b50\u662f\u67e5\u627e\u5e76\u6253\u5370\u51fa\u7b26\u5408\u6761\u4ef6\u7684\u884c\uff0c\u901a\u8fc7 -v \u53c2\u6570\u53ef\u4ee5\u6253\u5370\u51fa\u4e0d\u7b26\u5408\u6761\u4ef6\u884c\u7684\u5185\u5bb9\u3002\u67e5\u627e\u6587\u4ef6\u540d\u4e2d\u5305\u542bxen\u7684\u6587\u4ef6\u4e2d\u4e0d\u5305\u542bxen\u7684\u884c pmgr@dcmaster:/data/program/general> grep -v xen gen* Linux Test test \u67e5\u627e\u5f53\u524d\u76ee\u5f55\u4e0b\u5305\u542b\u5b57\u7b26\u4e32\u201cLinux\u201d\u7684\u6587\u4ef6 pmgr@dcmaster:/data/program/general> grep Linux * general.conf:Linux grep: staffing: Is a directory pmgr@dcmaster:/data/program/general> egrep Linux * general.conf:Linux grep: staffing: Is a directory","title":"Useful Commands"},{"location":"linux/Administration/02/#useful-commands","text":"","title":"Useful Commands"},{"location":"linux/Administration/02/#some-common-abbreviations","text":"Abbreviations Description . represents the current directory .. represents the parent directory ~ represents the home directory ~username represents the home directory of user username","title":"Some common abbreviations"},{"location":"linux/Administration/02/#software-package-documentation","text":"/usr/share/doc/packages/","title":"Software package documentation"},{"location":"linux/Administration/02/#release-notes","text":"/usr/share/doc/release-notes/","title":"Release Notes"},{"location":"linux/Administration/02/#command-help","text":" -h or --help # tree --help","title":"Command help"},{"location":"linux/Administration/02/#manual-pages","text":"man [ section ] command # man 5 crontab # man /sestion options Show tree command manual: # man tree List for keywords: # man -k keyword Force mandb to update. Normally this is done daily via a cron job. # mandb Search for all instances of a command or a file named crontab # man -f crontab # whatis crontab (same output with above command) # man -k crontab # apropos crontab (same output with above command) To go directly to a given man page: # man 5 crontab * 1G : go to the 1 st line * 10G : go to the 10 th line * G : go to the end of the page * /^SELinux : search the word SELinux * /section OPTIONS : go to the section OPTIONS man\u5171\u6709\u4ee5\u4e0b\u51e0\u4e2a\u7ae0\u8282\uff0c\u6bd4\u5982\uff0cman 5 crontab\u5c31\u662f\u8fdb\u5165crontab\u7684\u7b2c5\u7ae0\u8282\uff1a Executable programs or shell commands \uff08\u6807\u51c6\u547d\u4ee4\uff09 System calls (functions provided by the kernel)\uff08\u7cfb\u7edf\u8c03\u7528\uff09 Library calls (functions within program libraries)\uff08\u5e93\u51fd\u6570\uff09 Special files (usually found in /dev)\uff08\u8bbe\u5907\u8bf4\u660e\uff09 File formats and conventions eg /etc/passwd \uff08\u6587\u4ef6\u683c\u5f0f\uff09 Games \uff08\u6e38\u620f\u548c\u5a31\u4e50\uff09 Miscellaneous (including macro packages and conventions)\uff08\u6742\u9879\uff0c\u60ef\u4f8b\u4e0e\u534f\u5b9a\u7b49\u7f51\u7edc\u534f\u5b9a\u3001ASCII code\u7b49\u7b49\u7684\u8aaa\u660e\uff09 System administration commands (usually only for root) \uff08\u7ba1\u7406\u5458\u547d\u4ee4\uff09 Kernel routines [Non standard] \uff08\u5176\u4ed6Linux\u7279\u5b9a\u7684\uff0c\u7528\u6765\u5b58\u653e\u5185\u6838\u4f8b\u884c\u7a0b\u5e8f\u7684\u6587\u6863\u3002\uff09 man\u5e38\u7528\u5feb\u6377\u952e \u7ffb\u5c4f \u5411\u540e\u7ffb\u4e00\u5c4f\uff1aspace(\u7a7a\u683c\u952e) \u5411\u524d\u7ffb\u4e00\u5c4f\uff1ab \u5411\u540e\u7ffb\u4e00\u884c\uff1aEnter(\u56de\u8f66\u952e) \u5411\u524d\u7ffb\u4e00\u884c\uff1ak \u67e5\u627e /\u5173\u952e\u8bcd ?\u5173\u952e\u8bcd n (\u4e0b\u4e00\u4e2a) N (\u524d\u4e00\u4e2a) man \u4e2d\u6587\u5316\u3002\u5728 /etc/profile \u52a0\u5165\u4e0b\u9762alias\uff0c\u53ef\u4ee5\u5728man\u4e2d\u8f93\u51fa\u4e2d\u6587 # For man in zh_CH alias cman='man -M /usr/share/man/zh_CN'","title":"Manual pages"},{"location":"linux/Administration/02/#display-descriptions","text":"whatis command","title":"Display descriptions:"},{"location":"linux/Administration/02/#info-pages","text":"info command # info # info top From the terminal window display the info pages for the info command by entering: # info info Move the cursor to the line referring to (Invoking Info) by pressing Tab Tab Follow the link by pressing Enter Move the cursor to the link Note Custom Key Bindings: by pressing Tab (6 times) Follow the link by pressing Enter Return to the page Note Custom Key Bindings: by typing (lowercase L): l Exit the info file by typing: q","title":"Info pages:"},{"location":"linux/Administration/02/#pwd-command","text":"Display the current working directory","title":"pwd command"},{"location":"linux/Administration/02/#cd-command","text":"Change directory","title":"cd command"},{"location":"linux/Administration/02/#ls-command","text":"Display directory contents * Display hidden files with -a option * Detailed listing with -l option * Output is recursive, including all subdirectories with -R option * With option -F After each name, a character indicates the file type (\u201c/\u201d for directories, \u201c*\u201d for executable files, \u201c|\u201d for FIFO files, \u201c@\u201d symbolic link).","title":"ls command"},{"location":"linux/Administration/02/#cp-command","text":"Copy a file or directory Syntax: cp [option] Option -a : Copies a directory and subdirectories (compare -R ); symbolic links, file permissions, owners, and time stamps are not changed. \u5b83\u4fdd\u7559\u7b26\u53f7\u94fe\u63a5\u3001\u6587\u4ef6\u5c5e\u6027\uff0c\u5e76\u590d\u5236\u76ee\u5f55\u4e0b\u7684\u6240\u6709\u5185\u5bb9\u3002\u5176\u4f5c\u7528\u7b49\u4e8e-dpR\u53c2\u6570\u7ec4\u5408\u3002 Option -I : Asks before overwriting. Option -R , -r : Copies directories recursively (the directory and any subdirectories). \u9012\u5f52\u62f7\u8d1d\uff0c\u5305\u542b\u5b50\u76ee\u5f55\u53ca\uff08\u9690\u542b\uff09\u6587\u4ef6\uff0c\u7ee7\u627f\u76ee\u6807\u76ee\u5f55\u7684\u6743\u9650\u548c\u5c5e\u6027\u7b49 Option -l : Makes hardlinks instead of copying (\u521b\u5efa\u786c\u94fe\u63a5\u7684\u53e6\u5916\u4e00\u4e2a\u65b9\u6cd5) Option -s : Makes symbolic instead of copying (\u521b\u5efa\u7b26\u53f7\u94fe\u63a5\u7684\u53e6\u5916\u4e00\u4e2a\u65b9\u6cd5) Option -u : Copies a file only when the source file is newer than the destination file or when the destination file is missing. Option -p : \u8fde\u540c\u6863\u6848\u7684\u5c5e\u6027\u4e00\u8d77\u590d\u5236\u8fc7\u53bb\uff0c\u5305\u62ec\u4fee\u6539\u65f6\u95f4\u3001\u8bbf\u95ee\u6743\u9650\u3001\u6240\u6709\u8005\u7ec4\u7b49\uff0c\u800c\u975e\u4f7f\u7528\u9884\u8bbe\u5c5e\u6027\uff1b Labs: Initiate directories and files mySUSE:~ # su - pmgr pmgr@mySUSE:~> mkdir /data/program pmgr@mySUSE:~> mkdir /data/program/general pmgr@mySUSE:~> mkdir /data/program/general/staffing pmgr@mySUSE:~> touch /data/program/general/program_scope pmgr@mySUSE:~> touch /data/program/general/staffing/assignment mySUSE:~ # su - pm1 pm1@mySUSE:~> mkdir /data/project1 pm1@mySUSE:~> mkdir /data/project1/iot pm1@mySUSE:~> mkdir /data/project1/iot/bigdata pm1@mySUSE:~> touch /data/project1/iot/devicelist pm1@mySUSE:~> touch /data/project1/iot/bigdata/math_lib mySUSE:~ # su - pm2 pm2@mySUSE:~> mkdir /data/project2 pm2@mySUSE:~> mkdir /data/project2/erp pm2@mySUSE:~> mkdir /data/project2/erp/fin pm2@mySUSE:~> touch /data/project2/erp/erp_vision pm2@mySUSE:~> touch /data/project2/erp/fin/fin_ar pm2@mySUSE:~> chmod g+w /data/project2/erp/erp_vision pmgr@mySUSE:~> ln /data/project2/erp/erp_vision /data/program/general/p2_erp_version ( \u521b\u5efa\u786c\u94fe\u63a5\uff0c\u5f53\u524d\u7528\u6237\u9700\u8981\u5bf9\u6e90\u6587\u4ef6erp_vision\u6709w\u6743\u9650 ) pmgr@mySUSE:~> ln -s /data/project1/iot/devicelist /data/program/general/p1_devicelist ( \u521b\u5efa\u7b26\u53f7\u94fe\u63a5\uff0c\u4e0d\u9a8c\u8bc1\u5f53\u524d\u7528\u6237\u662f\u5426\u5bf9\u6e90\u6587\u4ef6devicelist\u6709\u6743\u9650 ) mySUSE:~ # tree /data /data \u251c\u2500\u2500 program \u2502 \u2514\u2500\u2500 general \u2502 \u251c\u2500\u2500 p1_devicelist -> /data/project1/iot/devicelist \u2502 \u251c\u2500\u2500 p2_erp_version \u2502 \u251c\u2500\u2500 program_scope \u2502 \u2514\u2500\u2500 staffing \u2502 \u2514\u2500\u2500 assignment \u251c\u2500\u2500 project1 \u2502 \u2514\u2500\u2500 iot \u2502 \u251c\u2500\u2500 bigdata \u2502 \u2502 \u2514\u2500\u2500 math_lib \u2502 \u2514\u2500\u2500 devicelist \u2514\u2500\u2500 project2 \u2514\u2500\u2500 erp \u251c\u2500\u2500 erp_vision \u2514\u2500\u2500 fin \u2514\u2500\u2500 fin_ar pmgr@mySUSE:~> cp -R /data/project1 /data/program/ ( /data/program/project1\u7684\u7528\u6237\u548c\u7ec4\u90fd\u7ee7\u627f\u4e86/data/program/ ) pmgr@mySUSE:~> cp -a /data/project2 /data/program/ ( /data/program/project2\u7684\u7528\u6237\u7ee7\u627f\u4e86/data/program/\uff0c\u4f46\u7ec4\u8fd8\u662f\u4fdd\u7559\u539f\u6765\u7684 )","title":"cp command"},{"location":"linux/Administration/02/#mv-command","text":"Move or rename a file or directory Option -i : Asks for confirmation before moving or renaming a file. This prevents existing files with the same name from being overwritten. Option -u : Only moves files that are newer than the target files of the same name. pmgr@mySUSE:/data/program/general> cp program_scope ./staffing/ pmgr@mySUSE:/data/program/general> mv -i program_scope ./staffing/ mv: overwrite './staffing/program_scope'? n","title":"mv command"},{"location":"linux/Administration/02/#rm-command","text":"Delete a file or directory Option -i : Asks for confirmation before deleting. Option -r : (recursively) Allows full directories to be deleted. Option -f : (force) By default, rm asks for confirmation if the file that should be deleted is read-only. Using this option, the files are deleted without asking for confirmation.","title":"rm command"},{"location":"linux/Administration/02/#mkdir-command","text":"Create a new directory Option -p lets you create a complete path (\u5c42\u7ea7\u8def\u5f84\u4e00\u6b21\u521b\u5efa) pmgr@mySUSE:/data> mkdir -p industry/utilities pmgr@mySUSE:/data> tree ./industry/ ./industry/ \u2514\u2500\u2500 utilities","title":"mkdir command"},{"location":"linux/Administration/02/#rmdir-command","text":"Remove an empty directory. The directory or directories must be empty before you can delete them.","title":"rmdir command"},{"location":"linux/Administration/02/#ln-command","text":"Create a link Default: Hard link Symbolic link with -s option Syntax: ln [-s] ","title":"ln command"},{"location":"linux/Administration/02/#touch-command","text":"Change the access and modification times Create an empty file if the given file does not exist. Change the time stamp of a file. Option -a : Changes only the time of the last read access (access time). Option -m : Changes only the time of the last modification (modification time). Option -r file : Sets the time stamp of file instead of the current time. Option -t time : Instead of the current time, sets time (structure: [[CC]YY]MMDDhhmm.[ss] ([Century]Year] Month Day Hour Minute [Seconds], two digits in each)) pmgr@mySUSE:/data/industry> touch readme pmgr@mySUSE:/data/industry> touch -a readme pmgr@mySUSE:/data/industry> touch -m readme pmgr@mySUSE:/data/industry> stat readme File: readme Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: 3dh/61d Inode: 338 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 1003/ pmgr) Gid: ( 1000/ admins) Access: 2019-03-31 10:07:47.489055973 +0800 Modify: 2019-03-31 10:07:58.805109884 +0800 Change: 2019-03-31 10:07:58.805109884 +0800 Birth: -","title":"touch command"},{"location":"linux/Administration/02/#cat-command","text":"Concatenates files","title":"cat command"},{"location":"linux/Administration/02/#tac-command","text":"Same as cat, but displays the file(s) in reverse pmgr@mySUSE:/data/industry> cat readme line 1 line 2 line 3 pmgr@mySUSE:/data/industry> tac readme line 3 line 2 line 1","title":"tac command"},{"location":"linux/Administration/02/#more-command","text":"Display file contents one page at a time","title":"more command"},{"location":"linux/Administration/02/#less-command","text":"Displays file contents for better navigation","title":"less command"},{"location":"linux/Administration/02/#head-command","text":"Displays the first 10 lines of a file. To set the number of lines use the -n option pmgr@mySUSE:/data/industry> head readme line 1 line 2 line 3 line 4 line 5 line 6 line 7 line 8 line 9 line 10 pmgr@mySUSE:/data/industry> head -n 5 readme line 1 line 2 line 3 line 4 line 5","title":"head command"},{"location":"linux/Administration/02/#tail-command","text":"Display the last lines of a file To set the number of lines use the -n option To output appended data use -f option, displays a continuously updated view of the last lines of a file. To exit tail -f, press Ctrl+C. pmgr@mySUSE:/data/industry> tail -n 6 readme line 10 line 11 line 12 line 13 line 14 line 15","title":"tail command"},{"location":"linux/Administration/02/#tar-command","text":"Create, expand or list archive files Use option c to create an archive Use option f to specify the archive file name Use option v for verbose mode Use option x to extract an archive Use option t to list the content of an archive Use option z to (un-)compress the archive with gzip Use option j to (un-)compress the archive with bzip The /etc directory (include sub-directories) is backed up to the /backup/etc.tar file pmgr@mySUSE:~> tar -cvf /data/backup/project1.tar /data/project1/ pmgr@mySUSE:~> tar -cvf /data/backup/project2.tar /data/project2/ pmgr@mySUSE:~> tar -cv --exclude='*.conf' -f /data/backup/project2a.tar /data/project2/ View the contents of an archive. Some .conf files are excluded in project2a.tar file. pmgr@mySUSE:~> tar -tvf /data/backup/project2.tar drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/fin/ -rw-r--r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/fin/fin_ar -rw-r--r-- pm2/project2 0 2019-03-31 16:47 data/project2/erp/fin/fin.conf -rw-rw-r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/erp_vision -rw-r--r-- pm2/project2 0 2019-03-31 16:47 data/project2/erp/erp.conf -rw-r--r-- pm2/project2 0 2019-03-31 16:47 data/project2/project2.conf pmgr@mySUSE:~> tar -tvf /data/backup/project2a.tar drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/ drwxr-xr-x pm2/project2 0 2019-03-31 16:47 data/project2/erp/fin/ -rw-r--r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/fin/fin_ar -rw-rw-r-- pm2/project2 0 2019-03-29 16:06 data/project2/erp/erp_vision Unpack and write all files in the archive to the current directory. Extract to another directory by using the -C option pmgr@mySUSE:~> mkdir project1.backup pmgr@mySUSE:~> tar -xvf /data/backup/project1.tar -C /data/backup/project1.backup/ Incremental backup with tar command pmgr@mySUSE:~> tar -g snapshot_program -cvf /data/backup/bkp_program_full.tar /data/program/ pmgr@mySUSE:~> tar -tvf /data/backup/bkp_program_full.tar pmgr@mySUSE:~> touch /data/program/general/general.conf pmgr@mySUSE:~> tar -g snapshot_program -cvf /data/backup/bkp_program_inc.tar /data/program/ pmgr@mySUSE:~> rm -rf program/ pmgr@mySUSE:~> tar -xvf /data/backup/bkp_program_inc.tar -C /data/","title":"tar command"},{"location":"linux/Administration/02/#cpio-command","text":"Another archiving command","title":"cpio command"},{"location":"linux/Administration/02/#gzip-command","text":"Compress files using the gzip algorithm Option -c : Compresses the file without modifying the original file. The result is written to the standard output (usually the screen). From there, it can be redirected to a file with \u201c>\u201d. Option -d : Decompresses the specified file (gunzip) Option -r : Compresses and decompresses files in all subdirectories. Option -1 to -9, --fast, --best : Controls the compression speed: -1 means --fast and causes a quick compression but produces larger files, -9 corresponds to --best and requires more computing time but produces smaller files. The default setting is -6.","title":"gzip command"},{"location":"linux/Administration/02/#gunzip-command","text":"Expand files compressed with gzip","title":"gunzip command"},{"location":"linux/Administration/02/#bzip2-command","text":"Compress files using the bzip2 algorithm Option -c : Option -d : Decompresses the specified file (bunzip2). Option -1 to -9 : Controls the compression speed: -1 causes a quick compression but produces larger files, -9 requires more computing time but produces smaller files. The default setting is -9 .","title":"bzip2 command"},{"location":"linux/Administration/02/#bunzip2-command","text":"Expand files compressed with bzip","title":"bunzip2 command"},{"location":"linux/Administration/02/#rsync-command","text":"Copy only deltas between two directories. A key benefit of using rsync is that when copying data, rsync compares the source and the target directory and transfers only data that has changed or has been created. \u4ec5\u590d\u5236\u4e24\u4e2a\u76ee\u5f55\u4e4b\u95f4\u7684\u589e\u91cf\u3002 \u4f7f\u7528rsync\u7684\u4e00\u4e2a\u4e3b\u8981\u597d\u5904\u662f\uff0c\u5728\u590d\u5236\u6570\u636e\u65f6\uff0crsync\u4f1a\u6bd4\u8f83\u6e90\u76ee\u5f55\u548c\u76ee\u6807\u76ee\u5f55\uff0c\u5e76\u4ec5\u4f20\u8f93\u5df2\u66f4\u6539\u6216\u5df2\u521b\u5efa\u7684\u6570\u636e\u3002 Local or via network \u672c\u5730\u6216\u901a\u8fc7\u7f51\u7edc Uses ssh as default transport \u4f7f\u7528ssh\u4f5c\u4e3a\u9ed8\u8ba4\u4f20\u8f93 Can talk to rsync daemon on the remote machine \u53ef\u4ee5\u4e0e\u8fdc\u7a0b\u8ba1\u7b97\u673a\u4e0a\u7684rsync\u5b88\u62a4\u7a0b\u5e8f\u901a\u4fe1 Note: rsync must be installed on both the source and the target computer for this to work. \u5fc5\u987b\u5728\u6e90\u8ba1\u7b97\u673a\u548c\u76ee\u6807\u8ba1\u7b97\u673a\u4e0a\u5b89\u88c5rsync\u624d\u80fd\u4f7f\u5176\u6b63\u5e38\u5de5\u4f5c\u3002 As the default shell used by rsync is ssh, the -e option only needs to be used when you want to use something else than ssh. \u7531\u4e8ersync\u4f7f\u7528\u7684\u9ed8\u8ba4shell\u662fssh\uff0c\u56e0\u6b64\u53ea\u6709\u5728\u60f3\u8981\u4f7f\u7528\u9664ssh\u4ee5\u5916\u7684\u5176\u4ed6\u5de5\u5177\u65f6\u624d\u9700\u8981\u4f7f\u7528-e\u9009\u9879\u3002 Options Option -a : Puts rsync into the archive mode. The -a option ensures the following are preserved \u4fdd\u7559 in the mirrored copy of the directory: Symbolic links (l option) Access permissions (p option) Owners (o option) Group membership (g option) Time stamp (t option) Option -x : Saves files on one file system only, which means that rsync does not follow symbolic links to other file systems. \u4e0d\u8de8\u6587\u4ef6\u7cfb\u7edf\uff0c\u53ea\u5728\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u5185(don't cross filesyste* undaries) Option -v : Enables the verbose mode. Use this mode to output information about the transferred files and the progress of the copying process. \u8f93\u51fa\u4f20\u8f93\u8fc7\u7a0b\u7684\u7ec6\u8282\u4fe1\u606f Option -z : Compresses the data during the transfer. This is especially useful for remote synchronization. \u538b\u7f29\u65b9\u5f0f\u4f20\u8f93 Option --delete : Deletes files from the mirrored directory that no longer exist in the original directory. Option --exclude-from : Does not back up files listed in an exclude file. Local backup via rsync command pmgr@mySUSE:/data> rsync -av /data/industry/* /data/backup/industry/ sending incremental file list created directory /data/backup/industry readme utilities/ sent 264 bytes received 87 bytes 702.00 bytes/sec total size is 111 speedup is 0.32 pmgr@mySUSE:/data/industry/utilities> touch roadmap.txt pmgr@mySUSE:/data> rsync -av /data/industry/* /data/backup/industry/ sending incremental file list utilities/ utilities/roadmap.txt sent 171 bytes received 39 bytes 420.00 bytes/sec total size is 111 speedup is 0.53 pmgr@mySUSE:/data> rm roadmap.txt pmgr@mySUSE:/data> rsync -av /data/industry/* --delete /data/backup/industry/ sending incremental file list deleting utilities/roadmap.txt utilities/ sent 102 bytes received 41 bytes 286.00 bytes/sec total size is 111 speedup is 0.78","title":"rsync command"},{"location":"linux/Administration/02/#dd-command","text":"Copies files block by block Used to create disk or partition images Most important options: if =input_file `of``=output_file bs =block_size You can use the dd command to convert and copy files byte-wise. Normally dd reads from the standard input and writes the result to the standard output. But with the appropriate parameters, regular files can be addressed as well. You can copy all kinds of Linux data with this command, including entire hard disk partitions. You can even copy an entire installed system (or just parts of it). Copy file /etc/protocols to protocols.old. The default size for a record is 512 bytes. Below 45+1 means, 45 complete record of standard size and 1 incomplete record (less than 512 bytes pmgr@mySUSE:/data/program> dd if=/etc/protocols of=protocols.old bs=512 45+1 records in 45+1 records out 23259 bytes (23 kB, 23 KiB) copied, 0.000595392 s, 39.1 MB/s \u521b\u5efa\u4e00\u4e2a100M\u7684\u7a7a\u6587\u4ef6 pmgr@mySUSE:/data/program> dd if=/dev/zero of=datafile bs=100M count=2 2+0 records in 2+0 records out 209715200 bytes (210 MB, 200 MiB) copied, 2.79311 s, 75.1 MB/s \u5907\u4efd\u6574\u4e2a\u5206\u533a #dd if=/dev/sda1 of=boot.partition \u5236\u4f5cU\u76d8\u542f\u52a8\u76d8\uff08U\u76d8\u6302\u8f7d\u5230/dev/sdb\uff09 #dd if=/root/diskboot.img of=/dev/sdb bs=125682176 \u5907\u4efd\u786c\u76d8\u4e3b\u5f15\u5bfc\u8bb0\u5f55 #dd if=/dev/sda of=/tmp/mbr_copy bs=512 count=1 \u8fd8\u539f\u786c\u76d8\u4e3b\u5f15\u5bfc\u8bb0\u5f55 #dd if=/disk.mbr of=/dev/hda bs=512 count=1 \u5c06\u5185\u5b58\u91cc\u7684\u6570\u636e\u62f7\u8d1d\u5230root\u76ee\u5f55\u4e0b\u7684mem.bin\u6587\u4ef6 # dd if=/dev/mem of=/root/mem.bin bs=1024 \u62f7\u8d1d\u5149\u76d8\u6570\u636e\u5230root\u6587\u4ef6\u5939\u4e0b\uff0c\u5e76\u4fdd\u5b58\u4e3acd.iso\u6587\u4ef6 # dd if=/dev/cdrom of=/root/cd.iso \u5229\u7528\u968f\u673a\u7684\u6570\u636e\u586b\u5145\u786c\u76d8(\u9500\u6bc1\u786c\u76d8\u6570\u636e) # dd if=/dev/urandom of=/dev/hda1 \u6d4b\u8bd5\u786c\u76d8\u8bfb\u5199\u901f\u5ea6\u3002\u901a\u8fc7\u4e24\u4e2a\u547d\u4ee4\u8f93\u51fa\u7684\u6267\u884c\u65f6\u95f4\uff0c\u53ef\u4ee5\u8ba1\u7b97\u51fa\u6d4b\u8bd5\u786c\u76d8\u7684\u8bfb\uff0f\u5199\u901f\u5ea6\uff1a mySUSE:/data # dd if=/data/program/datafile bs=64k | dd of=/dev/null 3200+0 records in 3200+0 records out 209715200 bytes (210 MB, 200 MiB) copied, 0.67138 s, 312 MB/s 409600+0 records in 409600+0 records out 209715200 bytes (210 MB, 200 MiB) copied, 0.675912 s, 310 MB/s # dd if=/dev/zero of=/data/program/datafile bs=1024 count=100 \u5207\u5272\u5927\u6587\u4ef6bigfile\uff0c\u517198336321\u5b57\u8282\uff0c\u5219\uff1a # dd if=bigfile of=smallfile1 bs=1 count=20000000 # dd if=bigfile of=smallfile2 bs=1 count=20000000 skip=20000000 # dd if=bigfile of=smallfile3 bs=1 count=20000000 skip=40000000 # dd if=bigfile of=smallfile4 bs=1 count=20000000 skip=60000000 # dd if=bigfile of=smallfile5 bs=1 count=18336321 skip=80000000 \u5c06\u5207\u5272\u6587\u4ef6\u7ec4\u88c5 # dd if=smallfile1 of=bigfile bs=1 count=20000000 # dd if=smallfile2 of=bigfile bs=1 count=20000000 seek=20000000 # dd if=smallfile3 of=bigfile bs=1 count=20000000 seek=40000000 # dd if=smallfile4 of=bigfile bs=1 count=20000000 seek=60000000 # dd if=smallfile5 of=bigfile bs=1 count=18336321 seek=80000000 if: \u8981\u5207\u5272\u7684\u5927\u6587\u4ef6\u540d of: \u5207\u5272\u540e\u7684\u5b50\u6587\u4ef6\u540d bs: \u4ee5\u591a\u5c11\u5b57\u8282\u4f5c\u4e3a\u4e00\u4e2a\u5207\u5272\u8bb0\u5f55\u5355\u4f4d count: \u662f\u8981\u5207\u5272\u7684\u5355\u4f4d\u8bb0\u5f55\u6570 skip: \u8bf4\u660e\u5207\u5272\u65f6\u7684\u8d77\u70b9 seek: \u660e\u786e\u6307\u51fa\u5f00\u59cb\u4f4d\u7f6e","title":"dd command"},{"location":"linux/Administration/02/#find-command","text":"Search for files or directories Syntax: find path criterion [action] The find command has a multitude of options, a few of which are explained here. You can use the following arguments with the command: path: The section of the file system to search (the specified directory and all its subdirectories). If nothing is specified, the file system below the current directory is used. criterion: The properties the file should have (see below) action: Options that influence the following conditions or control the search as a whole The most important actions are: -print (default) -exec command With the -exec option, you can call up another command. This option is frequently used to link find and grep, as in the following: \u627e\u51fagen\u5f00\u5934\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -name gen\\* ./program/general ./program/general/general.conf \u627e\u51fagen\u5f00\u5934\u7684\u6587\u4ef6\uff0c\u5e76\u5728\u6587\u4ef6\u5185\u5bb9\u4e2d\u67e5\u627exen\uff0c\u627e\u5230\u540e\u7ed3\u679c\u8f93\u51faxen pmgr@dcmaster:/data> find . -name gen\\* -type f -exec grep xen {} \\; xen xening The two brackets \u201c{}\u201d stand as placeholders for the file names which are found and passed to the grep command. The semicolon closes the -exec instruction. Because this is a special character, it is masked by placing a backslash in front of it. -ctime [\u00b1]days Searches for files whose last change took place no later than (no earlier than) a specified number of days ago. \u5728\u8fc7\u53bbn\u5929\u5185\u88ab\u4fee\u6539\u8fc7\u7684\u6587\u4ef6 mgr@dcmaster:/data> find . -ctime 1 . ./program/datafile -gid number Searches for files with the numeric GID (Group ID) number. (gid \u662f n) -group name Searches for files that are owned by the group name. Instead of a name, the numeric GID is allowed. (group \u540d\u79f0\u662f name) -name pattern Searches for files whose names contain the given pattern. If the pattern contains meta characters or wild cards, the name must be enclosed by quotation marks. Otherwise thename will be interpreted by the shell and not by find. -newer file Searches for files that were modified more recently than file. \u6bd4\u6587\u4ef6 file \u66f4\u65b0\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -cnewer ./program/datafile . -size [\u00b1]size Matches files that are above or below a certain size. The size (in blocks of 512 bytes) is given as an argument. The suffix \u201cc\u201cswitches to byte and \u201ck\u201d to blocks of 1024bytes. A preceding \u201c+\u201d stands for all larger files and a \u201c-\u201d for all smaller files. (\u6587\u4ef6\u5927\u5c0f \u662f n \u2022 b \u4ee3\u8868 512 \u4f4d\u5143\u7ec4\u7684\u533a\u5757 \u2022 c \u8868\u793a\u5b57\u5143\u6570 \u2022 k \u8868\u793a kilo bytes \u2022 w \u662f\u4e8c\u4e2a\u4f4d\u5143\u7ec4 pmgr@dcmaster:/data> find . -size 20k ./backup/project2.tar -type file_type Searches for a file type. A file type can be one of the following: * c : \u6587\u4ef6\u7c7b\u578b\u662f c \u7684\u6587\u4ef6\u3002 * d: \u76ee\u5f55 * c: \u5b57\u578b\u88c5\u7f6e\u6587\u4ef6 * b: \u533a\u5757\u88c5\u7f6e\u6587\u4ef6 * p: \u5177\u540d\u8d2e\u5217 * f: \u4e00\u822c\u6587\u4ef6 * l: \u7b26\u53f7\u8fde\u7ed3 * s: socket -uid number Searches for files with the numeric UID (User ID) number. -user name Searches for files, which are owned by user name. Instead of a name, the numeric UID is allowed. \u5e38\u7528\u53c2\u6570 mount, -xdev : \u53ea\u68c0\u67e5\u548c\u6307\u5b9a\u76ee\u5f55\u5728\u540c\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u4e0b\u7684\u6587\u4ef6\uff0c\u907f\u514d\u5217\u51fa\u5176\u5b83\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6587\u4ef6 amin n : \u5728\u8fc7\u53bb n \u5206\u949f\u5185\u88ab\u8bfb\u53d6\u8fc7 anewer file : \u6bd4\u6587\u4ef6 file \u66f4\u665a\u88ab\u8bfb\u53d6\u8fc7\u7684\u6587\u4ef6 atime n : \u5728\u8fc7\u53bbn\u5929\u5185\u88ab\u8bfb\u53d6\u8fc7\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -atime 1 ./program/datafile cmin n : \u5728\u8fc7\u53bb n \u5206\u949f\u5185\u88ab\u4fee\u6539\u8fc7 pmgr@dcmaster:/data> find . -cmin 20 empty : \u7a7a\u7684\u6587\u4ef6 ipath p, -path p : \u8def\u5f84\u540d\u79f0\u7b26\u5408 p \u7684\u6587\u4ef6\uff0cipath \u4f1a\u5ffd\u7565\u5927\u5c0f\u5199 name name, -iname name : \u6587\u4ef6\u540d\u79f0\u7b26\u5408 name \u7684\u6587\u4ef6\u3002iname \u4f1a\u5ffd\u7565\u5927\u5c0f\u5199 pid n : process id \u662f n \u7684\u6587\u4ef6 \u67e5\u627e\u5f53\u524d\u76ee\u5f55\u53ca\u5b50\u76ee\u5f55\u4e2d\u6240\u6709\u6587\u4ef6\u957f\u5ea6\u4e3a0\u7684\u666e\u901a\u6587\u4ef6\uff0c\u5e76\u5217\u51fa\u5b83\u4eec\u7684\u5b8c\u6574\u8def\u5f84 pmgr@dcmaster:/data> find . -type f -size 0 -exec ls -l {} \\; \u67e5\u627e\u524d\u76ee\u5f55\u4e2d\u6587\u4ef6\u5c5e\u4e3b\u5177\u6709\u8bfb\u3001\u5199\u6743\u9650\uff0c\u5e76\u4e14\u6587\u4ef6\u6240\u5c5e\u7ec4\u7684\u7528\u6237\u548c\u5176\u4ed6\u7528\u6237\u5177\u6709\u8bfb\u6743\u9650\u7684\u6587\u4ef6 pmgr@dcmaster:/data> find . -type f -perm 644 -exec ls -l {} \\; \u67e5\u627e/var/log\u76ee\u5f55\u4e2d\u66f4\u6539\u65f6\u95f4\u572817\u65e5\u4ee5\u524d\u7684\u666e\u901a\u6587\u4ef6\uff0c\u5e76\u5728\u5220\u9664\u4e4b\u524d\u8be2\u95ee\u5b83\u4eec pmgr@dcmaster:/data> find /var/log -type f -mtime +17 -ok rm {} \\; \u5c06\u76ee\u524d\u76ee\u5f55\u53ca\u5176\u5b50\u76ee\u5f55\u4e0b\u6240\u6709\u6700\u8fd1 1 \u5929\u5185\u66f4\u65b0\u8fc7\u7684\u6587\u4ef6\u5217\u51fa mgr@dcmaster:/data> find . -ctime 1 \u5c06\u76ee\u524d\u76ee\u5f55\u5176\u5176\u4e0b\u5b50\u76ee\u5f55\u4e2d\u6240\u6709\u4e00\u822c\u6587\u4ef6\u5217\u51fa pmgr@dcmaster:/data> find . -type f \u5c06\u76ee\u524d\u76ee\u5f55\u53ca\u5176\u5b50\u76ee\u5f55\u4e0b\u6240\u6709\u5ef6\u4f38\u6863\u540d\u662fconf \u7684\u6587\u4ef6\u5217\u51fa\u6765 pmgr@dcmaster:/data> find . -name \"*.conf\"","title":"find command"},{"location":"linux/Administration/02/#which-command","text":"Searches all paths listed in the variable $PATH and returns the full path of the command The which command searches all paths listed in the variable $PATH for the specified command and returns the full path of the command. In the variable \\(PATH, the most important directoriesare listed where the shell looks for executable files. which\u547d\u4ee4\u641c\u7d22\u53d8\u91cf\\) PATH\u4e2d\u5217\u51fa\u7684\u6240\u6709\u8def\u5f84\u4ee5\u83b7\u53d6\u6307\u5b9a\u547d\u4ee4\uff0c\u5e76\u8fd4\u56de\u547d\u4ee4\u7684\u5b8c\u6574\u8def\u5f84\u3002 The which command is especially useful if several versions of a command exist in different directories and you want to know which version is executed when entered without specifying apath. \u5982\u679c\u547d\u4ee4\u7684\u591a\u4e2a\u7248\u672c\u5b58\u5728\u4e8e\u4e0d\u540c\u7684\u76ee\u5f55\u4e2d\uff0c\u5e76\u4e14\u60a8\u60f3\u77e5\u9053\u5728\u8f93\u5165\u65f6\u6267\u884c\u4e86\u54ea\u4e2a\u7248\u672c\u800c\u672a\u6307\u5b9a\u8def\u5f84\uff0c\u90a3\u4e48which\u547d\u4ee4\u7279\u522b\u6709\u7528\u3002 NOTE: To see the content of a variable, use the echo command Options Description -n<\u6587\u4ef6\u540d\u957f\u5ea6> \u6307\u5b9a\u6587\u4ef6\u540d\u957f\u5ea6\uff0c\u6307\u5b9a\u7684\u957f\u5ea6\u5fc5\u987b\u5927\u4e8e\u6216\u7b49\u4e8e\u6240\u6709\u6587\u4ef6\u4e2d\u6700\u957f\u7684\u6587\u4ef6\u540d\u3002 -p<\u6587\u4ef6\u540d\u957f\u5ea6> \u4e0e-n\u53c2\u6570\u76f8\u540c\uff0c\u4f46\u6b64\u5904\u7684<\u6587\u4ef6\u540d\u957f\u5ea6>\u5305\u62ec\u4e86\u6587\u4ef6\u7684\u8def\u5f84\u3002 -w \u6307\u5b9a\u8f93\u51fa\u65f6\u680f\u4f4d\u7684\u5bbd\u5ea6\u3002 -V \u663e\u793a\u7248\u672c\u4fe1\u606f # which grep /usr/bin/grep # which -V grep GNU which v2.21, Copyright (C) 1999 - 2015 Carlo Wood. GNU which comes with ABSOLUTELY NO WARRANTY; This program is free software; your freedom to use, change and distribute this program is protected by the GPL.","title":"which command"},{"location":"linux/Administration/02/#whereis-command","text":"The whereis command returns the binaries (option -b), manual pages (option -m), and the source code (option -s) of the specified command. If no option is used, all this information is returned, provided the information is available. This command is faster than find, but it is less thorough. Attempts to locate the desired program in the standard Linux places, and in the places specified by $PATH and $MANPATH . \u5c1d\u8bd5\u5728\u6807\u51c6Linux\u4f4d\u7f6e\u548c\u6307\u5b9a\u4f4d\u7f6e( \\(PATH\u548c\\) MANPATH)\u627e\u5230\u6240\u9700\u7684\u7a0b\u5e8f Options Description -b \u53ea\u67e5\u627e\u4e8c\u8fdb\u5236\u6587\u4ef6\u3002 -B<\u76ee\u5f55> \u53ea\u5728\u8bbe\u7f6e\u7684\u76ee\u5f55\u4e0b\u67e5\u627e\u4e8c\u8fdb\u5236\u6587\u4ef6\u3002 -f \u4e0d\u663e\u793a\u6587\u4ef6\u540d\u524d\u7684\u8def\u5f84\u540d\u79f0\u3002 -m \u53ea\u67e5\u627e\u8bf4\u660e\u6587\u4ef6\u3002 -M<\u76ee\u5f55> \u53ea\u5728\u8bbe\u7f6e\u7684\u76ee\u5f55\u4e0b\u67e5\u627e\u8bf4\u660e\u6587\u4ef6\u3002 -s \u53ea\u67e5\u627e\u539f\u59cb\u4ee3\u7801\u6587\u4ef6\u3002 -S<\u76ee\u5f55> \u53ea\u5728\u8bbe\u7f6e\u7684\u76ee\u5f55\u4e0b\u67e5\u627e\u539f\u59cb\u4ee3\u7801\u6587\u4ef6\u3002 -u \u67e5\u627e\u4e0d\u5305\u542b\u6307\u5b9a\u7c7b\u578b\u7684\u6587\u4ef6\u3002 \u4ee5\u4e0b\u8f93\u51fa\u4fe1\u606f\u4ece\u5de6\u81f3\u53f3\u5206\u522b\u4e3a\u67e5\u8be2\u7684\u7a0b\u5e8f\u540d\u3001bash\u8def\u5f84\u3001bash\u7684man\u624b\u518c\u9875\u8def\u5f84\u3002 # whereis grep grep: /usr/bin/grep /bin/grep /usr/share/man/man1/grep.1.gz /usr/share/info/grep.info.gz \u663e\u793abash \u547d\u4ee4\u7684\u4e8c\u8fdb\u5236\u7a0b\u5e8f # whereis -b grep grep: /usr/bin/grep /bin/grep \u663e\u793abash \u547d\u4ee4\u7684\u5e2e\u52a9\u6587\u4ef6 # whereis -m grep grep: /usr/share/man/man1/grep.1.gz /usr/share/info/grep.info.gz","title":"whereis command"},{"location":"linux/Administration/02/#type-command","text":"The type command shows what kind of command is executed when you enter it: \u547d\u4ee4\u7684\u7c7b\u578b a shell built-in command (an essential command that is hard coded in the shell), for example type or cd an external command (called by the shell) an alias, for example ls. An alias defines shortcuts and synonyms for commonly used shell commands. a function The -a option delivers all instances of a command bearing this name in the file system. NOTE: If you want to have more information about a file format, you can use the file command. \u4e0d\u9002\u7528\u4e8e\u666e\u901a\u6587\u4ef6 dcmaster:/data/shell # type pwd.txt -bash: type: pwd.txt: not found \u4e0d\u9002\u7528\u4e8e\u81ea\u5b9a\u4e49\u53ef\u6267\u884c\u811a\u672c dcmaster:/data/shell # type math.sh -bash: type: math.sh: not found \u7cfb\u7edf\u547d\u4ee4 dcmaster:/data/shell # type rsync rsync is /usr/bin/rsync \u522b\u540d dcmaster:/data/shell # type l l is aliased to `ls -alF'","title":"type command"},{"location":"linux/Administration/02/#file-command","text":"file\u547d\u4ee4\u7528\u4e8e\u8fa8\u8bc6\u6587\u4ef6\u7c7b\u578b -b \u5217\u51fa\u8fa8\u8bc6\u7ed3\u679c\u65f6\uff0c\u4e0d\u663e\u793a\u6587\u4ef6\u540d\u79f0\u3002 -c \u8be6\u7ec6\u663e\u793a\u6307\u4ee4\u6267\u884c\u8fc7\u7a0b\uff0c\u4fbf\u4e8e\u6392\u9519\u6216\u5206\u6790\u7a0b\u5e8f\u6267\u884c\u7684\u60c5\u5f62\u3002 -f <\u540d\u79f0\u6587\u4ef6> \u6307\u5b9a\u540d\u79f0\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u6587\u4ef6\u540d\u79f0\u65f6\uff0c\u8ba9file\u4f9d\u5e8f\u8fa8\u8bc6\u8fd9\u4e9b\u6587\u4ef6\uff0c\u683c\u5f0f\u4e3a\u6bcf\u5217\u4e00\u4e2a\u6587\u4ef6\u540d\u79f0\u3002 -L \u76f4\u63a5\u663e\u793a\u7b26\u53f7\u8fde\u63a5\u6240\u6307\u5411\u7684\u6587\u4ef6\u7684\u7c7b\u522b\u3002 -m<\u9b54\u6cd5\u6570\u5b57\u6587\u4ef6> \u6307\u5b9a\u9b54\u6cd5\u6570\u5b57\u6587\u4ef6\u3002 -v \u663e\u793a\u7248\u672c\u4fe1\u606f\u3002 -z \u5c1d\u8bd5\u53bb\u89e3\u8bfb\u538b\u7f29\u6587\u4ef6\u7684\u5185\u5bb9\u3002 dcmaster:/data/linktype # l -rw-r--r-- 3 root root 44 May 3 09:50 file -rw-r--r-- 3 root root 44 May 3 09:50 hardlinkfile1 -rw-r--r-- 3 root root 44 May 3 09:50 hardlinkfile2 lrwxrwxrwx 1 root root 4 Mar 28 15:21 symlinkfile1 -> file lrwxrwxrwx 1 root root 12 Mar 28 15:49 symlinkfile1-1 -> symlinkfile1 lrwxrwxrwx 1 root root 4 Mar 28 15:23 symlinkfile2 -> file dcmaster:/data/linktype # file hardlinkfile1 hardlinkfile1: ASCII text dcmaster:/data/linktype # file -i hardlinkfile1 hardlinkfile1: text/plain; charset=us-ascii dcmaster:/data/linktype # file /data/linktype/ /data/linktype/: directory dcmaster:/data/linktype # file -L /data/linktype/ /data/linktype/: directory dcmaster:/data/linktype # file -i /data/linktype/ /data/linktype/: inode/directory; charset=binary dcmaster:/data/linktype # file symlinkfile1 symlinkfile1: symbolic link to file dcmaster:/data/linktype # file -i symlinkfile1 symlinkfile1: inode/symlink; charset=binary","title":"file command"},{"location":"linux/Administration/02/#grep-command","text":"You can specify search patterns in the form of regular expressions, although the basic grep command is limited in this regard. To search for more complex patterns, use the egrep command (or grep -E ) instead, which accepts extended regular expressions. To avoid having special characters in search patterns interpreted by the shell, enclose the pattern in quotation marks. Syntax: grep [options] search_pattern filename * egrep = grep -E * rgrep \u53c2\u6570 -a \u6216 --text : \u4e0d\u8981\u5ffd\u7565\u4e8c\u8fdb\u5236\u7684\u6570\u636e\u3002 -A<\u663e\u793a\u884c\u6570> \u6216 --after-context=<\u663e\u793a\u884c\u6570> : \u9664\u4e86\u663e\u793a\u7b26\u5408\u8303\u672c\u6837\u5f0f\u7684\u90a3\u4e00\u5217\u4e4b\u5916\uff0c\u5e76\u663e\u793a\u8be5\u884c\u4e4b\u540e\u7684\u5185\u5bb9\u3002 -b \u6216 --byte-offset : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u6807\u793a\u51fa\u8be5\u884c\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u7f16\u53f7\u3002 -B<\u663e\u793a\u884c\u6570> \u6216 --before-context=<\u663e\u793a\u884c\u6570> : \u9664\u4e86\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u5916\uff0c\u5e76\u663e\u793a\u8be5\u884c\u4e4b\u524d\u7684\u5185\u5bb9\u3002 -c \u6216 --count : \u8ba1\u7b97\u7b26\u5408\u6837\u5f0f\u7684\u5217\u6570\u3002 -C<\u663e\u793a\u884c\u6570> \u6216 --context=<\u663e\u793a\u884c\u6570> \u6216 -<\u663e\u793a\u884c\u6570> : \u9664\u4e86\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u5916\uff0c\u5e76\u663e\u793a\u8be5\u884c\u4e4b\u524d\u540e\u7684\u5185\u5bb9\u3002 -d <\u52a8\u4f5c> \u6216 --directories=<\u52a8\u4f5c> : \u5f53\u6307\u5b9a\u8981\u67e5\u627e\u7684\u662f\u76ee\u5f55\u800c\u975e\u6587\u4ef6\u65f6\uff0c\u5fc5\u987b\u4f7f\u7528\u8fd9\u9879\u53c2\u6570\uff0c\u5426\u5219grep\u6307\u4ee4\u5c06\u56de\u62a5\u4fe1\u606f\u5e76\u505c\u6b62\u52a8\u4f5c\u3002 -e<\u8303\u672c\u6837\u5f0f> \u6216 --regexp=<\u8303\u672c\u6837\u5f0f> : \u6307\u5b9a\u5b57\u7b26\u4e32\u505a\u4e3a\u67e5\u627e\u6587\u4ef6\u5185\u5bb9\u7684\u6837\u5f0f\u3002 -E \u6216 --extended-regexp : \u5c06\u6837\u5f0f\u4e3a\u5ef6\u4f38\u7684\u666e\u901a\u8868\u793a\u6cd5\u6765\u4f7f\u7528\u3002 -f<\u89c4\u5219\u6587\u4ef6> \u6216 --file=<\u89c4\u5219\u6587\u4ef6> : \u6307\u5b9a\u89c4\u5219\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u542b\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u89c4\u5219\u6837\u5f0f\uff0c\u8ba9grep\u67e5\u627e\u7b26\u5408\u89c4\u5219\u6761\u4ef6\u7684\u6587\u4ef6\u5185\u5bb9\uff0c\u683c\u5f0f\u4e3a\u6bcf\u884c\u4e00\u4e2a\u89c4\u5219\u6837\u5f0f\u3002 -F \u6216 --fixed-regexp : \u5c06\u6837\u5f0f\u89c6\u4e3a\u56fa\u5b9a\u5b57\u7b26\u4e32\u7684\u5217\u8868\u3002 -G \u6216 --basic-regexp : \u5c06\u6837\u5f0f\u89c6\u4e3a\u666e\u901a\u7684\u8868\u793a\u6cd5\u6765\u4f7f\u7528\u3002 -h \u6216 --no-filename : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u4e0d\u6807\u793a\u8be5\u884c\u6240\u5c5e\u7684\u6587\u4ef6\u540d\u79f0\u3002 -H \u6216 --with-filename : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u8868\u793a\u8be5\u884c\u6240\u5c5e\u7684\u6587\u4ef6\u540d\u79f0\u3002 -i \u6216 --ignore-case : \u5ffd\u7565\u5b57\u7b26\u5927\u5c0f\u5199\u7684\u5dee\u522b\u3002 -l \u6216 --file-with-matches : \u5217\u51fa\u6587\u4ef6\u5185\u5bb9\u7b26\u5408\u6307\u5b9a\u7684\u6837\u5f0f\u7684\u6587\u4ef6\u540d\u79f0\u3002 -L \u6216 --files-without-match : \u5217\u51fa\u6587\u4ef6\u5185\u5bb9\u4e0d\u7b26\u5408\u6307\u5b9a\u7684\u6837\u5f0f\u7684\u6587\u4ef6\u540d\u79f0\u3002 -n \u6216 --line-number : \u5728\u663e\u793a\u7b26\u5408\u6837\u5f0f\u7684\u90a3\u4e00\u884c\u4e4b\u524d\uff0c\u6807\u793a\u51fa\u8be5\u884c\u7684\u5217\u6570\u7f16\u53f7\u3002 -o \u6216 --only-matching : \u53ea\u663e\u793a\u5339\u914dPATTERN \u90e8\u5206\u3002 -q \u6216 --quiet\u6216--silent : \u4e0d\u663e\u793a\u4efb\u4f55\u4fe1\u606f\u3002 -r \u6216 --recursive : \u6b64\u53c2\u6570\u7684\u6548\u679c\u548c\u6307\u5b9a\"-d recurse\"\u53c2\u6570\u76f8\u540c\u3002 -s \u6216 --no-messages : \u4e0d\u663e\u793a\u9519\u8bef\u4fe1\u606f\u3002 -v \u6216 --revert-match : \u663e\u793a\u4e0d\u5305\u542b\u5339\u914d\u6587\u672c\u7684\u6240\u6709\u884c\u3002 -V \u6216 --version : \u663e\u793a\u7248\u672c\u4fe1\u606f\u3002 -w \u6216 --word-regexp : \u53ea\u663e\u793a\u5168\u5b57\u7b26\u5408\u7684\u5217\u3002 -x --line-regexp : \u53ea\u663e\u793a\u5168\u5217\u7b26\u5408\u7684\u5217\u3002 -y : \u6b64\u53c2\u6570\u7684\u6548\u679c\u548c\u6307\u5b9a\"-i\"\u53c2\u6570\u76f8\u540c\u3002 \u5728\u5f53\u524d\u76ee\u5f55\u4e2d\uff0c\u67e5\u627e\u540e\u7f00\u6709conf\u5b57\u6837\u7684\u6587\u4ef6\u4e2d\u5305\u542bxen\u5b57\u7b26\u4e32\u7684\u6587\u4ef6\uff0c\u5e76\u6253\u5370\u51fa\u8be5\u5b57\u7b26\u4e32\u7684\u884c\u3002 pmgr@dcmaster:/data/program/general> grep xen *.conf xen xening \u67e5\u627e\u524d\u7f00\u6709gen\u7684\u6587\u4ef6\u5305\u542bxen\u5b57\u7b26\u4e32\u7684\u6587\u4ef6 pmgr@dcmaster:/data/program/general> grep xen gen* xen xening \u4ee5\u9012\u5f52\u7684\u65b9\u5f0f\u67e5\u627e\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u3002\u67e5\u627e\u6307\u5b9a\u76ee\u5f55/data/program/\u53ca\u5176\u5b50\u76ee\u5f55\uff08\u5982\u679c\u5b58\u5728\u5b50\u76ee\u5f55\u7684\u8bdd\uff09\u4e0b\u6240\u6709\u6587\u4ef6\u4e2d\u5305\u542b\u5b57\u7b26\u4e32xen\u7684\u6587\u4ef6\uff0c\u5e76\u6253\u5370\u51fa\u8be5\u5b57\u7b26\u4e32\u6240\u5728\u884c\u7684\u5185\u5bb9 pmgr@dcmaster:/data> grep -r xen /data/program/ ./program/general/general.conf:xen ./program/general/general.conf:xening \u53cd\u5411\u67e5\u627e\u3002\u524d\u9762\u5404\u4e2a\u4f8b\u5b50\u662f\u67e5\u627e\u5e76\u6253\u5370\u51fa\u7b26\u5408\u6761\u4ef6\u7684\u884c\uff0c\u901a\u8fc7 -v \u53c2\u6570\u53ef\u4ee5\u6253\u5370\u51fa\u4e0d\u7b26\u5408\u6761\u4ef6\u884c\u7684\u5185\u5bb9\u3002\u67e5\u627e\u6587\u4ef6\u540d\u4e2d\u5305\u542bxen\u7684\u6587\u4ef6\u4e2d\u4e0d\u5305\u542bxen\u7684\u884c pmgr@dcmaster:/data/program/general> grep -v xen gen* Linux Test test \u67e5\u627e\u5f53\u524d\u76ee\u5f55\u4e0b\u5305\u542b\u5b57\u7b26\u4e32\u201cLinux\u201d\u7684\u6587\u4ef6 pmgr@dcmaster:/data/program/general> grep Linux * general.conf:Linux grep: staffing: Is a directory pmgr@dcmaster:/data/program/general> egrep Linux * general.conf:Linux grep: staffing: Is a directory","title":"grep command"},{"location":"linux/Administration/03/","text":"Shell \u00b6","title":"Shell"},{"location":"linux/Administration/03/#shell","text":"","title":"Shell"},{"location":"linux/SES/linux_ses_demo/","text":"SUSE Enterprise Storage 6 Installation and Basic Operation \u00b6 1. Installation \u00b6 1.1. Environment Setup \u00b6 In this demo, I use below environment, including VM setting and software installed. All VMs installed here was built on a physical host 10.58.121.68 . Host Server: 10.58.121.68 root / rootroot Account root / root123 Gateway: 10.58.120.1 Network Mask: 255.255.254.0 Nameserver: 10.58.32.32 10.33.50.20 Domain Search sha.me.corp dhcp.sha.me.corp me.corp ind.me.corp bgr.me.corp SUSE Server 15 SP1 Extensions and Modules were installed as below. [x] SUSE Enterprise Storage 6 [x] Basesystem Module 15 SP1 x86_64 [x] Server Applications Module 15 SP1 x86_64 Disable Services is as below: AppArmor Firewall Enable Services is as below. SSH Register SLES15.1 to local SMT. # SUSEConnect --url https://smtproxy.ind.me.corp Demo Environment summary is below. Alias Host Name Memory Disk eth0 eth0 mac address sles01 admin (salt-master) 16GB Disk1: 20G 10.58.121.181/23 52:54:00:23:7d:cd sles02 data1 16GB Disk1: 20G 10.58.121.182/23 52:54:00:5f:ce:6f Disk2: 8G Disk3: 8G Disk4: 8G sles03 data2 16GB Disk1: 20G 10.58.121.183/23 52:54:00:6f:f2:23 Disk2: 8G Disk3: 8G Disk4: 8G sles04 data3 16GB Disk1: 20G 10.58.121.184/23 52:54:00:93:4c:67 Disk2: 8G Disk3: 8G Disk4: 8G sles05 data4 16GB Disk1: 20G 10.58.121.185/23 52:54:00:90:b0:b0 Disk2: 8G Disk3: 8G Disk4: 8G sles06 mon1 16GB Disk1: 20G 10.58.121.186/23 52:54:00:46:43:7a sles07 mon2 16GB Disk1: 20G 10.58.121.187/23 52:54:00:00:fe:6b sles08 mon3 16GB Disk1: 20G 10.58.121.188/23 52:54:00:60:a3:92 Add hostname to file /etc/hosts (all nodes) If you do not specify a cluster network during Ceph deployment, it assumes a single public network environment. Make sure that the fully qualified domain name (FQDN) of each node can be resolved to the public network IP address by all other nodes. # vi /etc/hosts 10.58.121.181 admin.sha.me.corp admin salt 10.58.121.182 data1.sha.me.corp data1 10.58.121.183 data2.sha.me.corp data2 10.58.121.184 data3.sha.me.corp data3 10.58.121.185 data4.sha.me.corp data4 10.58.121.186 mon1.sha.me.corp mon1 10.58.121.187 mon2.sha.me.corp mon2 10.58.121.188 mon3.sha.me.corp mon3 Add all nodes as trust ssh access (root account) # cd ~ # ssh-keygen -t rsa # ssh-copy-id -i ~/.ssh/id_rsa.pub root@admin # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data1 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data2 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data3 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data4 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@mon1 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@mon2 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@mon3 # ssh admin.sha.me.corp # ssh data1.sha.me.corp # ssh data2.sha.me.corp # ssh data3.sha.me.corp # ssh data4.sha.me.corp # ssh mon1.sha.me.corp # ssh mon2.sha.me.corp # ssh mon3.sha.me.corp # ssh salt # ssh admin # ssh data1 # ssh data2 # ssh data3 # ssh data4 # ssh mon1 # ssh mon2 # ssh mon3 Disable firewall (all nodes) # sudo /sbin/SuSEfirewall2 off # firewall-cmd --state not running # systemctl stop firewalld.service # systemctl status firewalld.service firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: disabled) Active: inactive (dead) Docs: man:firewalld(1) Disable IPv6 (all nodes) and Set kernel pid to max value (all nodes) # vi /etc/sysctl.conf net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 net.ipv6.conf.lo.disable_ipv6 = 1 kernel.pid_max = 4194303 # sysctl -p Set DEV_ENV=true in /etc/profile.local in all nodes Install basic software (all nodes) # zypper in -y -t pattern yast2_basis base # zypper in -y net-tools vim man sudo tuned irqbalance # zypper in -y ethtool rsyslog iputils less supportutils-plugin-ses # zypper in -y net-tools-deprecated tree wget Configure NTP service (all nodes), Setting via YaST2 and add server cn.pool.ntp.,org . And /etc/chrony.conf file looks like below. admin:~ # cat /etc/chrony.conf # Use public servers from the pool.ntp.org project. pool cn.pool.ntp.org iburst ! pool pool.ntp.org iburst # Record the rate at which the system clock gains/losses time. driftfile /var/lib/chrony/drift # Allow the system clock to be stepped in the first three updates # if its offset is larger than 1 second. makestep 1.0 3 # Enable kernel synchronization of the real-time clock (RTC). rtcsync # Enable hardware timestamping on all interfaces that support it. #hwtimestamp * # Increase the minimum numbgr of selectable sources required to adjust # the system clock. #minsources 2 # Allow NTP client access from local network. #allow 192.168.0.0/16 # Serve time even if not synchronized to a time source. #local stratum 10 # Specify file containing keys for NTP authentication. #keyfile /etc/chrony.keys # Get TAI-UTC offset and leap seconds from the system tz database. #leapsectz right/UTC # Specify directory for log files. logdir /var/log/chrony # Select which information is logged. #log measurements statistics tracking # Also include any directives found in configuration files in /etc/chrony.d include /etc/chrony.d/*.conf Make /etc/chrony.conf effective. # systemctl enable chronyd.service # systemctl restart chronyd.service # systemctl status chronyd.service # chronyc sources 1.2. Install Packages \u00b6 Install salt-minion on all nodes. And start the service. Hostname is in file `/etc/salt/minion_id` # zypper in -y salt-minion Uncomment below to let all nodes know who is master # vi /etc/salt/minion master: salt # systemctl enable salt-minion.service # systemctl start salt-minion.service # systemctl status salt-minion.service Install Ceph in admin node. Check log in /var/log/salt admin:~ # zypper in -y salt-master admin:~ # systemctl enable salt-master.service admin:~ # systemctl start salt-master.service admin:~ # systemctl status salt-master.service Note: ganesha will be installed on mon1, not admin node. admin:~ # zypper se ganesha admin:~ # zypper in nfs-ganesha admin:~ # systemctl enable nfs-ganesha admin:~ # systemctl start nfs-ganesha admin:~ # systemctl status nfs-ganesha admin:~ # cd /var/log/salt List fingerprints of all unaccepted minion keys on the Salt master. admin:~ # salt-key -F Local Keys: master.pem: c0:e5:***:04:c7 master.pub: 43:73:***:6a:34 Unaccepted Keys: admin.sha.me.corp: fe:51:***:b9:48 mon1.sha.me.corp: 94:13:***:91:63 mon2.sha.me.corp: c0:fd:***:39:3f mon3.sha.me.corp: 38:fc:***:2e:05 data1.sha.me.corp: b6:6c:***:63:4f data2.sha.me.corp: ab:14:***:c8:ac data3.sha.me.corp: 90:3f:***:76:3b data4.sha.me.corp: d8:12:***:f1:20 If the minions' fingerprints match, accept them admin:~ # salt-key --accept-all The following keys are going to be accepted: Unaccepted Keys: admin.sha.me.corp mon1.sha.me.corp mon2.sha.me.corp mon3.sha.me.corp data1.sha.me.corp data2.sha.me.corp data3.sha.me.corp data4.sha.me.corp Proceed? [n/Y] Y Key for minion admin.sha.me.corp accepted. Key for minion mon1.sha.me.corp accepted. Key for minion mon2.sha.me.corp accepted. Key for minion mon3.sha.me.corp accepted. Key for minion data1.sha.me.corp accepted. Key for minion data2.sha.me.corp accepted. Key for minion data3.sha.me.corp accepted. Key for minion data4.sha.me.corp accepted. Verify that the keys have been accepted admin:~ # salt-key -F admin:~ # salt-key --list-all Accepted Keys: admin.sha.me.corp data1.sha.me.corp data2.sha.me.corp data3.sha.me.corp data4.sha.me.corp mon1.sha.me.corp mon2.sha.me.corp mon3.sha.me.corp Denied Keys: Unaccepted Keys: Rejected Keys: Zero out all drivers which will be used as OSDs (optional) data1:~ lsblk data1:~ # for I in {b,c,d}; do dd if=/dev/zero of=dev/sd$i bs=512 count=40 oflag=direct; done data2:~ # for I in {b,c,d}; do dd if=/dev/zero of=dev/sd$i bs=512 count=40 oflag=direct; done data3:~ # for I in {b,c,d}; do dd if=/dev/zero of=dev/sd$i bs=512 count=40 oflag=direct; done Install DeepSea admin:~ # zypper in -y deepsea Edit the /srv/pillar/ceph/deepsea_minions.sls file on the Salt master (admin node) and add or replace the following line: admin:~ # vi /srv/pillar/ceph/deepsea_minions.sls # Choose minions with a deepsea grain deepsea_minions: 'G@deepsea:*' #Match all Salt minions in the cluster # Choose all minions # deepsea_minions: '*' #Match all minions with the 'deepsea' grain # Choose custom Salt targeting # deepsea_minions: 'ses*' # deepsea_minions: 'ceph* or salt' Target the Minions Affirm salt-master (admin node) can communicate with the minions. And deploy the grains from admin node to all minions. admin:~ # salt '*' test.ping mon1.sha.me.corp: True data4.sha.me.corp: True data3.sha.me.corp: True data2.sha.me.corp: True data1.sha.me.corp: True mon3.sha.me.corp: True admin.sha.me.corp: True mon2.sha.me.corp: True Apply the 'deepsea' grain to a group of minions, and target with a DeepSea Grain admin:~ # salt '*' grains.append deepsea default data3.sha.me.corp: The val default was already in the list deepsea mon2.sha.me.corp: The val default was already in the list deepsea data1.sha.me.corp: The val default was already in the list deepsea data4.sha.me.corp: The val default was already in the list deepsea data2.sha.me.corp: The val default was already in the list deepsea mon3.sha.me.corp: The val default was already in the list deepsea admin.sha.me.corp: The val default was already in the list deepsea mon1.sha.me.corp: The val default was already in the list deepsea admin:~ # salt -G 'deepsea:*' test.ping (The following command is an equivalent) admin:~ # salt -C 'G@deepsea:*' test.ping admin.sha.me.corp: True data3.sha.me.corp: True mon1.sha.me.corp: True mon2.sha.me.corp: True data2.sha.me.corp: True data4.sha.me.corp: True mon3.sha.me.corp: True data1.sha.me.corp: True 1.3. Stage 0 \u2014 the preparation \u00b6 Run Stage 0\u2014the preparation During this stage, all required updates are applied and your system may be rebooted. If there are errors, re-run the stage. admin:~ # deepsea stage run ceph.stage.0 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.0 admin:~ # salt-run state.orch ceph.stage.prep Run Stage 1\u2014the discovery Here all hardware in your cluster is being detected and necessary information for the Ceph configuration is being collected. The discovery stage collects data from all minions and creates configuration fragments that are stored in the directory /srv/pillar/ceph/proposals . The data are stored in the YAML format in *.sls or *.yml files admin:~ # deepsea stage run ceph.stage.1 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.1 admin:~ # salt-run state.orch ceph.stage.discovery 1.4. Stage 2 \u2014 the configuration \u00b6 Run Stage 2 \u2014 the configuration \u2014 you need to prepare configuration data in a particular format. The assignment follows this pattern: role-ROLE_NAME/PATH/FILES_TO_INCLUDE (NOTE, the parent directory of PATH is /srv/pillar/ceph/ ) To avoid trouble with performance and the upgrade procedure, do not deploy the Ceph OSD, Metadata Server, or Ceph Monitor role to the Admin Node. Monitors, Metadata Server, and gateways can be co-located on the OSD nodes. If you are using CephFS, S3/Swift, iSCSI, at least two instances of the respective roles (Metadata Server, Object Gateway, iSCSI) are required for redundancy and availability. admin:~ # cp /usr/share/doc/packages/deepsea/examples/policy.cfg-rolebased /srv/pillar/ceph/proposals/policy.cfg admin:~ # vi /srv/pillar/ceph/proposals/policy.cfg ## Cluster Assignment # Add all nodes into Ceph cluster cluster-ceph/cluster/*.sls ## Roles # The Admin node fills the \u201cmaster\u201d and \u201cadmin\u201d roles for DeepSea # The master role is mandatory, always add a similar line to the following role-master/cluster/admin*.sls role-admin/cluster/admin*.sls # Monitoring # Cluster monitoring and data graphs, most commonly they run on Admin node # NFS Ganesha is configured via the file /etc/ganesha/ganesha.conf # As additional configuration is required to install NFS Ganesha, you can install NFS Ganesha later. # The following requirements need to be met before DeepSea stages 2 and 4 can be executed to install NFS Ganesha: # a)At least one node needs to be assigned the role-ganesha. # b)You can define only one role-ganesha per minion. # c)NFS Ganesha needs either an Object Gateway or CephFS to work, otherwise the validation will fail in Stage 3. # d)The kernel based NFS needs to be disabled on minions with the role-ganesha role. role-prometheus/cluster/admin*.sls role-grafana/cluster/mon1*.sls # MON # The minion will provide the monitor service to the Ceph cluster role-mon/cluster/mon*.sls # MGR # The Ceph manager daemon which collects all the state information from the whole cluster # Deploy it on all minions where you plan to deploy the Ceph monitor role role-mgr/cluster/mon1*.sls # MDS # The minion will provide the metadata service to support CephFS role-mds/cluster/mon*.sls # IGW # The minion will act as an iSCSI Gateway role-igw/cluster/mon2*.sls # RGW # The minion will act as an Object Gateway role-rgw/cluster/mon3*.sls # Storage # Use this role to specify storage nodes # It points to data1~4 nodes with a wildcard. role-storage/cluster/data*.sls # COMMON # It includes configuration files generated during the discovery (Stage 1) # Accept the default values for common configuration parameters such as fsid and public_network config/stack/default/global.yml config/stack/default/ceph/cluster.yml admin:~ # deepsea stage run ceph.stage.2 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.2 admin:~ # salt-run state.orch ceph.stage.configure After the command succeeds, run below command to view the pillar data for the specified minions admin:~ # salt 'mon*' pillar.items admin:~ # salt '*' saltutil.pillar_refresh Check time server (admin node) (the directory /srv/pillar/ceph/stack was initialized after deepsea installed, but global.yml file was not created yet until stage 2) By default, DeepSea uses the Admin Node as the time server for other cluster nodes. admin:~ # cat /srv/pillar/ceph/stack/default/global.yml (this file will be generated after stage 2) monitoring: prometheus: metric_relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] rule_files: [] scrape_interval: ceph: 10s grafana: 10s node_exporter: 10s prometheus: 10s target_partition: ceph: 1/1 grafana: 1/1 node_exporter: 1/1 prometheus: 1/1 time_server: admin.sha.me.corp Verify network (the directory /srv/pillar/ceph/stack was initialized after deepsea installed, but cluster.yml file was not created until stage 2 ) admin:~ # cat /srv/pillar/ceph/stack/ceph/cluster.yml --nothing admin:~ # cat /srv/pillar/ceph/stack/default/ceph/cluster.yml available_roles: - storage - admin - mon - mds - mgr - igw - grafana - prometheus - storage - rgw - ganesha - client-cephfs - client-radosgw - client-iscsi - client-nfs - benchmark-rbd - benchmark-blockdev - benchmark-fs - master cluster_network: 10.58.120.0/23 fsid: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 public_network: 10.58.120.0/23 Note: customized file will overwrite default one. Default file: /srv/pillar/ceph/stack/default/ceph/cluster.yml Customized file: /srv/pillar/ceph/stack/ceph/cluster.yml Check DriveGroup DriveGroups specify the layouts of OSDs in the Ceph cluster. They are defined in a single file /srv/salt/ceph/configuration/files/drive_groups.yml admin:~ # cat /srv/salt/ceph/configuration/files/drive_groups.yml default_drive_group_name: target: 'data*' <--original: 'I@role:storage' data_devices: all: true admin:~ # salt 'data*' pillar.items | grep -B5 stroage 1.5. Stage 3 \u2014 the deployment \u00b6 Run Stage 3 \u2014 the deployment \u2014 creates a basic Ceph cluster with mandatory Ceph services. This Deployment stage has more than 60 automated steps. Be patient and make sure the stage completes successfully before proceeding. Set dev environment and disable subvolume: admin:~ # vi /srv/pillar/ceph/stack/global.yml admin:~ # vi /srv/pillar/ceph/stack/default/global.yml monitoring: prometheus: metric_relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] rule_files: [] scrape_interval: ceph: 10s grafana: 10s node_exporter: 10s prometheus: 10s target_partition: ceph: 1/1 grafana: 1/1 node_exporter: 1/1 prometheus: 1/1 time_server: admin.sha.me.corp DEV_ENV: True subvolume_init: disabled admin:~ # salt '*' saltutil.pillar_refresh Note: customized file will overwrite default one. Default file: /srv/pillar/ceph/stack/default/global.yml Customized file: /srv/pillar/ceph/stack/global.yml admin:~ # deepsea stage run ceph.stage.3 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.3 admin:~ # salt-run state.orch ceph.stage.deploy After the command succeeds, run the following to check the status: admin:~ # ceph -s Below comands return you a structure of matching disks based on your DriveGroups. (will show available information after stage 3) admin:~ # salt-run disks.Report admin:~ # salt-run disks.list admin:~ # salt-run disks.details 1.6. Stage 4 \u2014 the services \u00b6 Run Stage 4 \u2014 the services \u2014 additional features of Ceph like iSCSI, Object Gateway and CephFS can be installed in this stage. Each is optional. admin:~ # deepsea stage run ceph.stage.4 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.4 admin:~ # salt-run state.orch ceph.stage.services admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log Before logon to dashboard via url, need get credentials first admin:~ # salt-call grains.get dashboard_creds local: ---------- admin: --> the password was changed to mypassword to log on to dashboard admin:~ # ceph mgr services { \"dashboard\": \"https://mon1.sha.me.corp:8443/\", \"prometheus\": \"http://mon1.sha.me.corp:9283/\" } https://10.58.121.186:8443 http://10.58.121.186:9283 admin:~ # watch ceph -s Every 2.0s: ceph -s admin: Mon Oct 5 14:41:51 2020 cluster: id: health: HEALTH_OK services:s: ceph -s mon: 3 daemons, quorum mon1,mon2,mon3 (age 87m) mgr: mon1(active, since 82m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 85m), 12 in (since 85m) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 576 pgs objects: 213 objects, 4.2 KiB usage: 12 GiB used, 84 GiB / 96 GiB avail pgs: 576 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr 1.7. Stage 5 \u2014 the removal stage \u00b6 Run Stage 5 \u2014 the removal stage. This stage is not mandatory and during the initial setup it is usually not needed. In this stage the roles of minions and also the cluster configuration are removed. You need to run this stage when you need to remove a storage node from your cluster. admin:~ # deepsea stage run ceph.stage. 1.8. Installation Guide \u00b6 Deployment Guide (EN) Deployment Guide (ZH) 1.9. Issues during installation \u00b6 [ERROR]: The Salt Master has cached the public key for this node SOLUTION : Restart minions service [ERROR]: This server_id is computed nor by Adler32 neither by CRC32 [QUESTION]: How to change new salt key Stop salt-minion service # systemctl stop salt-minion Delete salt-minion pulic key # rm /etc/salt/pki/minion/minion.pub # rm /etc/salt/pki/minion/minion.pem Change new minion_id admin:~ # echo admin.sha.me.corp > /etc/salt/minion_id data1:~ # echo data1.sha.me.corp > /etc/salt/minion_id data2:~ # echo data2.sha.me.corp > /etc/salt/minion_id data3:~ # echo data3.sha.me.corp > /etc/salt/minion_id data4:~ # echo data4.sha.me.corp > /etc/salt/minion_id mon1:~ # echo mon1.sha.me.corp > /etc/salt/minion_id mon2:~ # echo mon2.sha.me.corp > /etc/salt/minion_id mon3:~ # echo mon3.sha.me.corp > /etc/salt/minion_id Delete old ID on admin node # salt-key -D Restart salt-minion service # systemctl restart salt-minion Accept all new key on admin node admin:~ # salt-key -L admin:~ # salt-key -A or admin:~ # salt-key -a admin.sha.me.corp data1:~ # salt-key -a data1.sha.me.corp data2:~ # salt-key -a data2.sha.me.corp data3:~ # salt-key -a data3.sha.me.corp data4:~ # salt-key -a data4.sha.me.corp mon1:~ # salt-key -a mon1.sha.me.corp mon2:~ # salt-key -a mon2.sha.me.corp mon3:~ # salt-key -a mon3.sha.me.corp [ERROR] ['/var/lib/ceph subvolume missing on mon3.sha.me.corp', '/var/lib/ceph subvolume missing on mon1.sha.me.corp', '/var/lib/ceph subvolume missing on mon2.sha.me.corp', 'See /srv/salt/ceph/subvolume/README.md'] SOLUTION Edit /srv/pillar/ceph/stack/global.yml and add the following line: subvolume_init: disabled Then refresh the Salt pillar and re-run DeepSea stage.3: admin:~ # salt '*' saltutil.refresh_pillar admin:~ # salt-run state.orch ceph.stage.3 After DeepSea successfully finished stage.3, the Ceph Dashboard will be running. Refer to Book \u201cAdministration Guide\u201d, Chapter 20 \u201cCeph Dashboard\u201d for a detailed overview of Ceph Dashboard features. To list nodes running dashboard, run: admin:~ # ceph mgr services | grep dashboard To list admin credentials, run: admin:~ # salt-call grains.get dashboard_creds [ERROR] module function cephprocesses.wait executed on nodes mon1~3 and data1~4 in Stage 0 SOLUTION Check below on all nodes # salt-call cephprocesses.check ERROR: process ceph-mds for role mds is not running ERROR: process radosgw for role rgw is not running admin:~ # ceph -s Clock skew detected on mon ceph (mon.mon2, mon.mon3) Set time server to public server (China) # chronyc sources 1.10. Shutting Down the Whole Ceph Cluster \u00b6 Shut down or disconnect any clients accessing the cluster. To prevent CRUSH from automatically rebalancing the cluster, set the cluster to noout: # ceph osd set noout Other flags you can set per osd: nodown noup noin noout Disable safety measures and run the ceph.shutdown runner: admin:~ # salt-run disengage.safety safety is now disabled for cluster ceph admin:~ # salt-run state.orch ceph.shutdown admin.sha.me.corp_master: Name: set noout - Function: salt.state - Result: Changed Started: - 14:32:14.398022 Duration: 2266.75 ms Name: Shutting down radosgw for rgw - Function: salt.state - Result: Changed Started: - 14:32:16.665452 Duration: 1461.23 ms Name: Shutting down cephfs - Function: salt.state - Result: Changed Started: - 14:32:18.127353 Duration: 30326.193 ms Name: Shutting down iscsi - Function: salt.state - Result: Clean Started: - 14:32:48.454187 Duration: 30142.468 ms Name: Shutting down storage - Function: salt.state - Result: Changed Started: - 14:33:18.597321 Duration: 10841.45 ms Name: Shutting down mgr - Function: salt.state - Result: Changed Started: - 14:33:29.439442 Duration: 29209.141 ms Name: Shutting down mon - Function: salt.state - Result: Changed Started: - 14:33:58.649221 Duration: 30519.97 ms Summary for admin.sha.me.corp_master ------------ Succeeded: 7 (changed=6) Failed: 0 ------------ Total states run: 7 Total run time: 134.767 s Power off all cluster nodes: admin:~ # salt -C 'G@deepsea:*' cmd.run \"shutdown -h\" Broadcast message from root@admin (Sat 2021-03-06 14:40:37 CST): The system is going down for poweroff at Sat 2021-03-06 14:41:37 CST! admin.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. mon2.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data2.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. mon3.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data3.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data4.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. mon1.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data1.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. 1.11. Starting, Stopping, and Restarting Services Using Targets \u00b6 # ls /usr/lib/systemd/system/ceph*.target ceph.target ceph-osd.target ceph-mon.target ceph-mgr.target ceph-mds.target ceph-radosgw.target ceph-rbd-mirror.target To start/stop/restart all Ceph services on the node, run: # systemctl start ceph.target # systemctl stop ceph.target # systemctl restart ceph.target To start/stop/restart all OSDs on the node, run: # systemctl start ceph-osd.target # systemctl stop ceph-osd.target # systemctl restart ceph-osd.target Starting, Stopping, and Restarting Individual Services # systemctl list-unit-files --all --type=service ceph* ceph-osd@.service ceph-mon@.service ceph-mds@.service ceph-mgr@.service ceph-radosgw@.service ceph-rbd-mirror@.service Example : # systemctl status ceph-mon@HOSTNAME.service (e.g., ceph-mon@mon1.service) # systemctl start ceph-osd@1.service # systemctl stop ceph-osd@1.service # systemctl restart ceph-osd@1.service # systemctl status ceph-osd@1.service 1.12. Restarting All Services \u00b6 # salt-run state.orch ceph.restart 1.13. Restarting Specific Services \u00b6 Example: salt-run state.orch ceph.restart.service_name # salt-run state.orch ceph.restart.mon # salt-run state.orch ceph.restart.mgr # salt-run state.orch ceph.restart.osd # salt-run state.orch ceph.restart.mds # salt-run state.orch ceph.restart.rgw # salt-run state.orch ceph.restart.igw # salt-run state.orch ceph.restart.ganesha Default log file path of salt-run: /var/log/salt/master 2. Basic Operation \u00b6 2.1. Pools and Data Placement \u00b6 2.1.1. Enable the PG Autoscaler and Balancer Modules \u00b6 Task 1: View the state of all the Manager Modules \u00b6 List all the existing Manager Modules admin:~ # ceph mgr module ls | less Task 2: List the Existing Pools \u00b6 List the pools that already exist in the cluster admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log List the pools again, but this time using the rados command: admin:~ # rados lspools iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log View the output of placement group autoscale-status command for the pools admin:~ # ceph osd pool autoscale-status Error ENOTSUP: Module 'pg_autoscaler' is not enabled (required by command 'osd pool autoscale-status'): use `ceph mgr module enable pg_autoscaler` to enable it Task 3: Enable the pg_autoscaler module \u00b6 Enable the pg_autoscaler module admin:~ # ceph mgr module enable pg_autoscaler admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 128 32 warn cephfs_data 0 3.0 98256M 0.0000 1.0 256 32 warn cephfs_metadata 7285 3.0 98256M 0.0000 4.0 64 16 warn .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 18078 3.0 98256M 0.0000 1.0 32 warn Note that for the iscsi-images pool the PG_NUM value is 128. And note that the NEW PG_NUM value is 32. The PGs won\u2019t be adjusted automatically because the default setting for the autoscaler is \u201cwarn\u201d. Note the last column (mode) that shows status \u201cwarn\u201d for all the pools. Check current status. \u201chave too many placement groups\u201d. That\u2019s exactly what we want the pg_autoscaler to tell us. admin:~ # ceph health HEALTH_WARN 3 pools have too many placement groups Turn off the pg_autoscaler feature for CephFS pools admin:~ # ceph osd pool set cephfs_data pg_autoscale_mode off set pool 2 pg_autoscale_mode to off admin:~ # ceph osd pool set cephfs_metadata pg_autoscale_mode off set pool 3 pg_autoscale_mode to off admin:~ # ceph health HEALTH_WARN 1 pools have too many placement groups Set the pg_autoscaler mode to \u201con\u201d for the iscs-images pool: admin:~ # ceph osd pool set iscsi-images pg_autoscale_mode on set pool 1 pg_autoscale_mode to on admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 128 32 on cephfs_data 0 3.0 98256M 0.0000 1.0 256 32 off cephfs_metadata 7412 3.0 98256M 0.0000 4.0 64 16 off .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 18078 3.0 98256M 0.0000 1.0 32 warn Turn on the pg_autoscaler feature for CephFS pools admin:~ # ceph osd pool set cephfs_data pg_autoscale_mode on set pool 2 pg_autoscale_mode to on admin:~ # ceph osd pool set cephfs_metadata pg_autoscale_mode on set pool 3 pg_autoscale_mode to on PG numbgrs must always be a power of 2 admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 32 on cephfs_data 0 3.0 98256M 0.0000 1.0 32 off cephfs_metadata 7412 3.0 98256M 0.0000 4.0 16 off .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 35900 3.0 98256M 0.0000 1.0 32 warn Show the cluster health admin:~ # ceph -s cluster: id: health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 4w) mgr: mon1(active, since 46h) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 8w), 12 in (since 8w) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 433 pgs objects: 246 objects, 4.7 KiB usage: 13 GiB used, 83 GiB / 96 GiB avail pgs: 0.462% pgs not active 431 active+clean 2 peering io: client: 45 KiB/s rd, 0 B/s wr, 44 op/s rd, 28 op/s wr Task 4: Turn on the Placement Group balancer feature \u00b6 1). Show the \u201cstatus\u201d of the balancer: admin:~ # ceph balancer status { \"plans\": [], \"active\": false, \"last_optimize_started\": \"\", \"last_optimize_duration\": \"\", \"optimize_result\": \"\", \"mode\": \"none\" } admin:~ # ceph balancer on admin:~ # ceph balancer status { \"plans\": [], \"active\": true, \"last_optimize_started\": \"Mon Jan 4 20:22:57 2021\", \"last_optimize_duration\": \"0:00:00.001379\", \"optimize_result\": \"Please do \\\"ceph balancer mode\\\" to choose a valid mode first\", \"mode\": \"none\" } 2). Set the mode for the balancer to \u201cupmap\u201d: admin:~ # ceph balancer mode upmap Error EPERM: min_compat_client \"jewel\" < \"luminous\", which is required for pg-upmap. Try \"ceph osd set-require-min-compat-client luminous\" before enabling this mode admin:~ # ceph osd set-require-min-compat-client luminous --yes-i-really-mean-it set require_min_compat_client to luminous admin:~ # ceph balancer mode upmap admin:~ # ceph balancer status { \"plans\": [], \"active\": true, \"last_optimize_started\": \"Mon Jan 4 20:23:57 2021\", \"last_optimize_duration\": \"0:00:00.001807\", \"optimize_result\": \"Please do \\\"ceph balancer mode\\\" to choose a valid mode first\", \"mode\": \"upmap\" } 3). Create a balancer optimization plan called basic-plan. Ceph won\u2019t let you do this yet. Because you just recently enabled the pg_autoscaler, Ceph is moving objects around, and the PGs are quite busy with re-peering. admin:~ # ceph balancer optimize basic-plan Error EINVAL: Balancer enabled, disable to optimize manually 4). Show the details of the plan: This shows what \u201cexecute\u201d-ing the plan will do, itemizing which PGs will be affected. admin:~ # ceph balancer show basic-plan Error ENOENT: plan basic-plan not found <--- failed here 5). Show the effectiveness of the plan by comparing the current score for the pre-planned balancing and the score for the planned balancing: admin:~ # ceph balancer eval current cluster score 0.118731 (lower is better) admin:~ # ceph balancer eval basic-plan Error EINVAL: option \"basic-plan\" not a plan or a pool 6). Show the status of the balancer, now with all of these settings having been set, but before putting them into effect: The pg_autoscaler has already optimized the balance of PGs sufficiently. That\u2019s because this cluster is very small and has no significant content stored in it yet. If that\u2019s the case, you would see a message like \u201cError EALREADY: Unable to find further optimization, or pool(s)' pg_num is decreasing, or distribution is already perfect.\u201d If you receive this message, then you will not be able to complete this task. At some later time in the course you may choose to revisit this task to complete it. admin:~ # ceph balancer status { \"plans\": [], \"active\": true, \"last_optimize_started\": \"Mon Jan 4 20:32:59 2021\", \"last_optimize_duration\": \"0:00:00.004170\", \"optimize_result\": \"Unable to find further optimization, or pool(s) pg_num is decreasing, or distribution is already perfect\", \"mode\": \"upmap\" } 7). Set the basic-plan into effect: admin:~ # ceph balancer execute basic-plan Error EINVAL: Balancer enabled, disable to execute a plan 8). Now re-show the current score for the balanced cluster: admin:~ # ceph balancer eval current cluster score 0.118731 (lower is better) 2.1.2. Manipulate Erasure Code Profiles \u00b6 Task 1: Display a list of the current Erasure Code profiles \u00b6 admin:~ # ceph osd erasure-code-profile no valid command found; 4 closest matches: osd erasure-code-profile set { [...]} {--force} osd erasure-code-profile get osd erasure-code-profile rm osd erasure-code-profile ls Error EINVAL: invalid command admin:~ # ceph osd erasure-code-profile ls default Task 2: Examine the details of the default EC profile \u00b6 admin:~ # ceph osd erasure-code-profile get default k=2 m=1 plugin=jerasure technique=reed_sol_van Task 3: Create and remove a new EC profile \u00b6 1. Create a new EC profile from the command line. This is going to be a \u201cbad\u201d profile that will be removed in a moment: admin:~ # ceph osd erasure-code-profile set bad_profile k=2 m=4 plugin=jerasure admin:~ # ceph osd erasure-code-profile ls bad_profile default admin:~ # ceph osd erasure-code-profile get bad_profile crush-device-class= crush-failure-domain=host crush-root=default jerasure-per-chunk-alignment=false k=2 m=4 plugin=jerasure technique=reed_sol_van w=8 admin:~ # ceph osd erasure-code-profile rm bad_profile admin:~ # ceph osd erasure-code-profile ls default Task 4: Create a better EC profile \u00b6 admin:~ # ceph osd erasure-code-profile set usable_profile k=2 m=1 plugin=jerasure technique=reed_sol_van stripe_unit=4K crush-failure-domain=host admin:~ # ceph osd erasure-code-profile get usable_profile crush-device-class= crush-failure-domain=host crush-root=default jerasure-per-chunk-alignment=false k=2 m=1 plugin=jerasure stripe_unit=4K technique=reed_sol_van w=8 2.1.3. Manipulate CRUSH Map Rulesets \u00b6 Task 1: Display a list of the current CRUSH Map rules \u00b6 admin:~ # ceph osd crush rule ls replicated_rule admin:~ # ceph osd crush osd crush rule ls osd crush rule ls-by-class osd crush rule dump {} osd crush dump osd crush set {} osd crush add-bucket { [...]} osd crush rename-bucket osd crush set [...] osd crush add [...] osd crush set-all-straw-buckets-to-straw2 admin:~ # ceph osd crush rule osd crush rule ls osd crush rule ls-by-class osd crush rule dump {} osd crush rule create-simple {firstn|indep} osd crush rule create-replicated {} osd crush rule create-erasure {} osd crush rule rm osd crush rule rename List the existing CRUSH Map rulesets that have been defined according to a particular device class: admin:~ # ceph osd crush rule ls-by-class hdd admin:~ # ceph osd crush rule ls-by-class ssd Error ENOENT: failed to get rules by class 'ssd' admin:~ # ceph osd crush rule ls-by-class nvme Error ENOENT: failed to get rules by class 'nvme' Task 2: Examine the details of the default CRUSH Map rule \u00b6 Show the details of the default CRUSH Map rule with the dump sub-command: The \u201crule_id\u201d and \u201cruleset\u201d values just numbgrs to keep track of rules similar to a DB key id. \u201cmin_size\u201d and \u201cmax_size\u201d are related to how CRUSH behaves when a certain numbgr of replicas are created. The \u201csteps\u201d section is the most functional portion of the rule, providing an ordered set of rules for how CRUSH should behave. Note that there are three \u201cop\u201d parts, one each for \u201ctake\u201d, \u201cchooseleaf_firstn\u201d, and \u201cemit\u201d. \u201ctake\u201d in a replicated rule is always the first step, and \u201cemit\u201d is always the last step. The \u201citem_type\u201d in the \u201ctake\u201d step is the crush_root value, and the \u201chost\u201d in the \u201cchooseleaf_firstn\u201d step is the failure_domain. admin:~ # ceph osd crush rule dump replicated_rule { \"rule_id\": 0, \"rule_name\": \"replicated_rule\", \"ruleset\": 0, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } Task 3: Create and remove a new CRUSH Map rule \u00b6 1). Create a new CRUSH ruleset from the command line.We made two mistakes here: First, we named it \u201cbud\u201d instead of \u201cbad\u201d. admin:~ # ceph osd crush rule create-replicated bud_ruleset default host admin:~ # ceph osd crush rule ls replicated_rule bud_ruleset 2). Rename the ruleset: admin:~ # ceph osd crush rule rename bud_ruleset bad_ruleset admin:~ # ceph osd crush rule ls replicated_rule bad_ruleset 3). The second mistake was that we specified the failure-domain at the host-bucket level. This is technically not a bad thing to do, in fact it would be a common use case. But for this demo we want to set the failure domain at the rack-bucket level. We can\u2019t change a defined CRUSH Map ruleset, so delete the bad one: admin:~ # ceph osd crush rule rm bad_ruleset admin:~ # ceph osd crush rule ls replicated_rule Task 4: Create a better CRUSH Map rule \u00b6 Create a more appropriate CRUSH Map rule from the CLI, that will survive the failure of a rack: admin:~ # ceph osd crush rule create-replicated better_ruleset default rack admin:~ # ceph osd crush rule dump better_ruleset { \"rule_id\": 1, \"rule_name\": \"better_ruleset\", \"ruleset\": 1, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"rack\" }, { \"op\": \"emit\" } ] } Task 5: Create CRUSH Map rules for different classes of devices \u00b6 1). Create two different CRUSH Map rules from the CLI, that will accommodate a slow set of devices (HDDs) and a fast set of devices (SDDs): The error of 2 nd is because the cluster does not have any SSD devices. admin:~ # ceph osd crush rule create-replicated slow_devices default host hdd admin:~ # ceph osd crush rule create-replicated fast_devices default host sdd Error EINVAL: device class sdd does not exist 2). Display the details of the new \u201cslow\u201d rule: admin:~ # ceph osd crush rule dump slow_devices { \"rule_id\": 2, \"rule_name\": \"slow_devices\", \"ruleset\": 2, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -2, \"item_name\": \"default~hdd\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } Task 6: Change the ruleset used by a pool \u00b6 1). Show which CRUSH Map Ruleset is being used by the cephfs_data pool: The rule should be listed as replicated_rule. admin:~ # ceph osd pool get cephfs_data crush_rule crush_rule: replicated_rule 2). Change the cephfs_data pool to use the new CRUSH Map ruleset that you created in the previous task. admin:~ # ceph osd pool set cephfs_data crush_rule better_ruleset set pool 2 crush_rule to better_ruleset 3). Verify that the rule has been changed by re-running the earlier command: admin:~ # ceph osd pool get cephfs_data crush_rule crush_rule: better_ruleset 4). In this demo cluster, making the cephfs_data pool use the \u201cbetter_ruleset\u201d will result in problems. (There\u2019s no rack for the CRUSH Map, and not enough nodes to accommodate the requirement for a large numbgr of PGs.) So change the setting back to the replicated_rule. admin:~ # ceph osd pool set cephfs_data crush_rule replicated_rule set pool 2 crush_rule to replicated_rule admin:~ # ceph osd pool get cephfs_data crush_rule crush_rule: replicated_rule Task 7: Create a CRUSH Map rule enhanced with an EC profile 1). Combine the benefits of Erasure Coding with a CRUSH Map rule: This will only work if you have already created an appropriate EC profile called usable_profile. In this demo you would have done in an earlier exercise. And in this demo you need to tie this ec_rule to the usable_profile, not the better_profile.Or else any pool that you create using the ec_rule will fail due to insufficient resources. admin:~ # ceph osd crush rule create-erasure ec_rule usable_profile Link the CRUSH map rule (ec_rule) to EC profile (usable_profile) created rule ec_rule at 3 P.S., The useable_profile was created by : admin:~ # ceph osd erasure-code-profile set usable_profile k=2 m=1 plugin=jerasure technique=reed_sol_van stripe_unit=4K crush-failure-domain=host 2). Display the details of the EC-enhanced CRUSH Map rule: See the added, extra \u201cop\u201d steps. You might also notice the different values for \u201ctype,\u201d \u201cmin_size,\u201d and \u201cmax_size\u201d than what you saw in the standard replicated rules. admin:~ # ceph osd crush rule dump ec_rule { \"rule_id\": 3, \"rule_name\": \"ec_rule\", \"ruleset\": 3, \"type\": 3, \"min_size\": 3, \"max_size\": 3, \"steps\": [ { \"op\": \"set_chooseleaf_tries\", \"num\": 5 }, { \"op\": \"set_choose_tries\", \"num\": 100 }, { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_indep\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd crush rule ls replicated_rule better_ruleset slow_devices ec_rule admin:~ # ceph osd crush rule create-replicated better_ruleset default rack admin:~ # ceph osd crush rule create-replicated slow_devices default host hdd admin:~ # ceph osd crush rule create-erasure ec_rule usable_profile admin:~ # ceph osd crush rule dump replicated_rule { \"rule_id\": 0, \"rule_name\": \"replicated_rule\", \"ruleset\": 0, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd crush rule dump better_ruleset { \"rule_id\": 1, \"rule_name\": \"better_ruleset\", \"ruleset\": 1, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"rack\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd crush rule dump slow_devices { \"rule_id\": 2, \"rule_name\": \"slow_devices\", \"ruleset\": 2, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -2, \"item_name\": \"default~hdd\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd pool osd pool stats {} osd pool scrub [...] osd pool deep-scrub [...] osd pool repair [...] osd pool force-recovery [...] osd pool force-backfill [...] osd pool cancel-force-recovery [...] osd pool cancel-force-backfill [...] osd pool autoscale-status osd pool mksnap admin:~ # ceph osd pool get size min_size pg_num pgp_num crush_rule Hashpspool Nodelete Nopgchange Nosizechange write_fadvise_dontneed Noscrub nodeep-scrub hit_set_type hit_set_period hit_set_count hit_set_fpp use_gmt_hitset target_max_objects target_max_bytes cache_target_dirty_ratio cache_target_dirty_high_ratio cache_target_full_ratio cache_min_flush_age cache_min_evict_age erasure_code_profile min_read_recency_for_promote All min_write_recency_for_promote fast_read hit_set_grade_decay_rate hit_set_search_last_n scrub_min_interval scrub_max_interval deep_scrub_interval recovery_priority recovery_op_priority scrub_priority compression_mode compression_algorithm compression_required_ratio compression_max_blob_size compression_min_blob_size csum_type csum_min_block csum_max_block allow_ec_overwrites fingerprint_algorithm pg_autoscale_mode pg_autoscale_bias pg_num_min target_size_bytes target_size_ratio 2.1.4. Investigate BlueStore \u00b6 Task 1: Explore the drive_groups.yml configuration \u00b6 After deployment, the drive_groups.yml file is where the storage administrator defines the configuration of the cluster\u2019s storage devices. Note the \u201cdata_devices\u201d parameter. In this demo, \u201call\u201d storage devices are data devices for BlueStore. Note that there are no definitions for \u201cwal_devices\u201d or \u201cdb_devices.\u201d That\u2019s because in this demo environment we don\u2019t have any other \u201cfast\u201d devices that would be appropriate for these roles. Since BlueStore is the default, there is no definition of a \u201cformat\u201d for the devices. Otherwise, a \u201cFormat: bluestore\u201d key-value pair might exist to ensure that BlueStore is used. admin:~ # cd /srv/salt/ceph/configuration/files admin:/srv/salt/ceph/configuration/files # cat drive_groups.yml # default: <- just a name - can be anything # target: 'data*' <- must be resolvable by salt's targeting processor # data_devices: # size: 20G # db_devices: # size: 10G # rotational: 1 # allflash: # target: 'fast_nodes*' # data_devices: # size: 100G # db_devices: # size: 50G # rotational: 0 # This is the default configuration and # will create an OSD on all available drives default: target: 'data*' data_devices: all: true Task 2: Examine a storage host\u2019s storage devices \u00b6 admin:~ # ssh data1 Last login: Tue Jan 5 18:06:40 2021 from 10.58.121.181 Should see 3 devices, which are named ceph LVM-type devices data1:~ # lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 8G 0 disk \u2514\u2500ceph--14c886af--269d--475f--8ee3--f5e4abbb222d-osd--data--38911b2d--f30a--4b09--9010--8dd6fad2fcc6 254:0 0 8G 0 lvm sdb 8:16 0 8G 0 disk \u2514\u2500ceph--9ec4a77a--5d67--4b21--be53--d7e9221082de-osd--data--00cb3dc6--c28b--41ae--95de--efb86da254da 254:1 0 8G 0 lvm sdc 8:32 0 8G 0 disk \u2514\u2500ceph--5eaea8a8--bb68--49dd--a1e3--b82c5464ab1f-osd--data--a4a05f70--53d9--41d4--a273--4f47a088968a 254:2 0 8G 0 lvm sr0 11:0 1 672M 0 rom vda 253:0 0 20G 0 disk \u251c\u2500vda1 253:1 0 8M 0 part \u251c\u2500vda2 253:2 0 18.4G 0 part / \u2514\u2500vda3 253:3 0 1.7G 0 part [SWAP] See the raw ceph devices data1:~ # ls -lad /dev/ceph* drwxr-xr-x 2 root root 60 Oct 5 13:15 /dev/ceph-14c886af-269d-475f-8ee3-f5e4abbb222d drwxr-xr-x 2 root root 60 Oct 5 13:16 /dev/ceph-5eaea8a8-bb68-49dd-a1e3-b82c5464ab1f drwxr-xr-x 2 root root 60 Oct 5 13:15 /dev/ceph-9ec4a77a-5d67-4b21-be53-d7e9221082de Dig down even farther by examining the content of one of the directories, see a symlink to an LVM device-mapper device. All the devices are tied together with LVM. Note that the name of the symlink is named osd-data- . data1:~ # ls -l /dev/ceph-14c886af-269d-475f-8ee3-f5e4abbb222d lrwxrwxrwx 1 ceph ceph 7 Oct 5 13:15 osd-data-38911b2d-f30a-4b09-9010-8dd6fad2fcc6 -> ../dm-0 data1:~ # l /dev/dm* brw-rw---- 1 ceph ceph 254, 0 Jan 5 18:10 /dev/dm-0 brw-rw---- 1 ceph ceph 254, 1 Jan 5 18:10 /dev/dm-1 brw-rw---- 1 ceph ceph 254, 2 Jan 5 18:10 /dev/dm-2 Task 3: Examine a storage host\u2019s OSD details \u00b6 data1:~ # cd /var/lib/ceph/ data1:/var/lib/ceph # ls -l drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-mds drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-mgr drwxr-x--- 1 ceph ceph 24 Oct 5 13:15 bootstrap-osd drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-rbd drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-rbd-mirror drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-rgw drwxr-x--- 1 ceph ceph 12 Oct 5 09:04 crash drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 mds drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 mgr drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 mon drwxr-x--- 1 ceph ceph 38 Oct 5 13:16 osd drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 tmp See 3 different sub-directories, each representing the 3 different OSDs (ceph-2, ceph-6, ceph-10) that are running on this storage server data1:/var/lib/ceph # cd osd/ data1:/var/lib/ceph/osd # ls -l drwxrwxrwt 2 ceph ceph 320 Oct 5 13:16 ceph-10 drwxrwxrwt 2 ceph ceph 320 Oct 5 13:15 ceph-2 drwxrwxrwt 2 ceph ceph 320 Oct 5 13:16 ceph-6 See some functional files associated with the OSD and BlueStore. See a block file, which is a symlink to one of the ceph devices, which stores the raw objects for the OSD. data1:/var/lib/ceph/osd # cd ceph-2 data1:/var/lib/ceph/osd/ceph-2 # ls -l -rw-r--r-- 1 ceph ceph 400 Oct 5 13:15 activate.monmap lrwxrwxrwx 1 ceph ceph 92 Oct 5 13:15 block -> /dev/ceph-14c886af-269d-475f-8ee3-f5e4abbb222d/osd-data-38911b2d-f30a-4b09-9010-8dd6fad2fcc6 -rw------- 1 ceph ceph 2 Oct 5 13:15 bluefs -rw------- 1 ceph ceph 37 Oct 5 13:15 ceph_fsid -rw-r--r-- 1 ceph ceph 37 Oct 5 13:15 fsid -rw------- 1 ceph ceph 55 Oct 5 13:15 keyring -rw------- 1 ceph ceph 8 Oct 5 13:15 kv_backend -rw------- 1 ceph ceph 21 Oct 5 13:15 magic -rw------- 1 ceph ceph 4 Oct 5 13:15 mkfs_done -rw------- 1 ceph ceph 41 Oct 5 13:15 osd_key -rw------- 1 ceph ceph 6 Oct 5 13:15 ready -rw------- 1 ceph ceph 3 Oct 5 13:15 require_osd_release -rw------- 1 ceph ceph 10 Oct 5 13:15 type -rw------- 1 ceph ceph 2 Oct 5 13:15 whoami data1:/var/lib/ceph/osd/ceph-2 # cat ceph_fsid # The unique ID of this Ceph cluster 343ee7d3-232f-4c71-8216-1edbc55ac6e0 data1:/var/lib/ceph/osd/ceph-2 # cat fsid # The unique ID of this OSD 6df58ebc-dbfe-4822-9714-90212c06ea05 data1:/var/lib/ceph/osd/ceph-2 # cat keyring # The Ceph key for this OSD [osd.2] key = data1:/var/lib/ceph/osd/ceph-2 # cat ready # Indication of the readiness of this OSD ready data1:/var/lib/ceph/osd/ceph-2 # cat type # filestore or bluestore (in this case: bluestore) bluestore data1:/var/lib/ceph/osd/ceph-2 # cat whoami # The integer id of this OSD (in this case: 2) 2 Task 4: Display BlueStore information using ceph-bluestore-tool \u00b6 Show BlueStore metadata for osd.2: data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool show-label --path /var/lib/ceph/osd/ceph-2 inferring bluefs devices from bluestore path { \"/var/lib/ceph/osd/ceph-2/block\": { \"osd_uuid\": \"6df58ebc-dbfe-4822-9714-90212c06ea05\", \"size\": 8585740288, \"btime\": \"2020-10-05 13:15:51.227799\", \"description\": \"main\", \"bluefs\": \"1\", \"ceph_fsid\": \"343ee7d3-232f-4c71-8216-1edbc55ac6e0\", \"kv_backend\": \"rocksdb\", \"magic\": \"ceph osd volume v026\", \"mkfs_done\": \"yes\", \"osd_key\": , \"ready\": \"ready\", \"require_osd_release\": \"14\", \"whoami\": \"2\" } Run a manual \u201cscrub\u201d on osd.7 using ceph-blestore-tool. (Received error, the tool won\u2019t allow you to do this while the OSD is running.) data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool fsck --path /var/lib/ceph/osd/ceph-2 error from fsck: (11) Resource temporarily unavailable 2021-01-05 18:32:25.528 7f4abad6e180 -1 bluestore(/var/lib/ceph/osd/ceph-2) _lock_fsid failed to lock /var/lib/ceph/osd/ceph-2/fsid (is another ceph-osd still running?)(11) Resource temporarily unavailable Simulate that the OSD is down, shutdown the OSD: data1:/var/lib/ceph/osd/ceph-2 # systemctl stop ceph-osd@2.service Now run the \u201cfsck\u201d command again. This time the \u201cfsck\u201d has worked, with the output showing: \u201cfsck success\u201d data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool fsck --path /var/lib/ceph/osd/ceph-2 fsck success Restart the OSD: data1:/var/lib/ceph/osd/ceph-2 # systemctl start ceph-osd@2.service data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool show-label --path /var/lib/ceph/osd/ceph-2 inferring bluefs devices from bluestore path { \"/var/lib/ceph/osd/ceph-2/block\": { \"osd_uuid\": \"6df58ebc-dbfe-4822-9714-90212c06ea05\", \"size\": 8585740288, \"btime\": \"2020-10-05 13:15:51.227799\", \"description\": \"main\", \"bluefs\": \"1\", \"ceph_fsid\": \"343ee7d3-232f-4c71-8216-1edbc55ac6e0\", \"kv_backend\": \"rocksdb\", \"magic\": \"ceph osd volume v026\", \"mkfs_done\": \"yes\", \"osd_key\": , \"ready\": \"ready\", \"require_osd_release\": \"14\", \"whoami\": \"2\" } } 2.2. Common Day 1 Tasks Using the CLI \u00b6 Including ollowing topics in relation to the commandline: Users and Ceph Configuration Health commands Erasure Code Profiles CRUSH Map rules Pools Scrubbing OSDs and Placement Groups Manager modules The tell commands 2.2.1. Ceph Users and Configuration \u00b6 Task 1: View the current user keyrings \u00b6 Ceph keyrings are stored in below directory admin:~ # cd /etc/ceph/ admin:/etc/ceph # ls -l -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap The value of 'key' is the key that\u2019s on the keyring. The admin keyring is \u201callow\u201ded all capabilities (permissions) to all services in the cluster, as expected. there are more than just client keys. admin:/etc/ceph # cat ceph.client.admin.keyring [client.admin] key = caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" Display the existing users with the \u201cauth\u201d command: Below two commands are equivalent admin:/etc/ceph # ceph -n client.admin -keyring=/etc/ceph/ceph.client.admin.keyring auth ls -- failed??? no valid command found admin:/etc/ceph # ceph auth ls installed auth entries: mds.mon1 key: caps: [mds] allow * caps: [mgr] allow profile mds caps: [mon] allow profile mds caps: [osd] allow rwx mds.mon2 key: caps: [mds] allow * caps: [mgr] allow profile mds caps: [mon] allow profile mds caps: [osd] allow rwx mds.mon3 key: caps: [mds] allow * caps: [mgr] allow profile mds caps: [mon] allow profile mds caps: [osd] allow rwx osd.0 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.1 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.10 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.11 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.2 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.3 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.4 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.5 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.6 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.7 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.8 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.9 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * client.admin key: caps: [mds] allow * caps: [mgr] allow * caps: [mon] allow * caps: [osd] allow * client.bootstrap-mds key: caps: [mon] allow profile bootstrap-mds client.bootstrap-mgr key: caps: [mon] allow profile bootstrap-mgr client.bootstrap-osd key: caps: [mgr] allow r caps: [mon] allow profile bootstrap-osd client.bootstrap-rbd key: caps: [mon] allow profile bootstrap-rbd client.bootstrap-rbd-mirror key: caps: [mon] allow profile bootstrap-rbd-mirror client.bootstrap-rgw key: caps: [mon] allow profile bootstrap-rgw client.igw.mon2 key: caps: [mgr] allow r caps: [mon] allow * caps: [osd] allow * client.rgw.mon3 key: caps: [mgr] allow r caps: [mon] allow rwx caps: [osd] allow rwx client.storage key: caps: [mon] allow rw mgr.mon1 key: caps: [mds] allow * caps: [mon] allow profile mgr caps: [osd] allow * Task 2: Create a new keyring and associated user \u00b6 1). There are several different ways to create a new keyring and user. This is just one way. Create a new keyring and associated user named James . Remembgr that typically all new users will need read rights for the mon capability, and will need read/write rights for the osd capability, including a specification of rights to a pool. admin:/etc/ceph # ceph-authtool -g -n client.james --cap mon 'allow r' --cap osd 'allow rw pool=iscsi-images' -C /etc/ceph/ceph.client.james.keyring creating /etc/ceph/ceph.client.james.keyring admin:/etc/ceph # l total 16 drwxr-xr-x 1 root root 130 Jan 5 19:31 ./ drwxr-xr-x 1 root root 4392 Oct 5 13:03 ../ -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw------- 1 root root 126 Jan 5 19:31 ceph.client.james.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap 2). Show the content of the newly created keyring: admin:/etc/ceph # cat ceph.client.james.keyring [client.james] key = caps mon = \"allow r\" caps osd = \"allow rw pool=iscsi-images\" 3). Officially add the new keyring to Ceph: admin:/etc/ceph # ceph auth add client.james -i /etc/ceph/ceph.client.james.keyring added key for client.james 4). Show the key information using the \u201cauth\u201d function: admin:/etc/ceph # ceph auth get client.james exported keyring for client.james [client.james] key = caps mon = \"allow r\" caps osd = \"allow rw pool=iscsi-images\" Task 3: Create a client key for RBD \u00b6 1). Change to the directory that contains the ceph keyrings. admin:~ # cd /etc/ceph/ 2). List the content of the directory: Although you see the admin users\u2019s keyring, ceph.client.admin.keyring, there is not yet a file that is appropriate for a specific application to use. Also note that the permissions on the keyring file are quite restrictive: 0600 admin:/etc/ceph # ls -l -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw------- 1 root root 126 Jan 5 19:31 ceph.client.james.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap 3). Show the content of the admin user\u2019s keyring: You will use the value associated with the \u201ckey\u201d key to create a new file. Copy the \u201ckey\u201d value using your favorite method. admin:/etc/ceph # cat ceph.client.admin.keyring [client.admin] key = caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" 4). Open a new file for editing called admin.secret using your favorite editor (such as vi): The name of the file isn\u2019t very important, but naming it this way will help to identify its purpose: it\u2019s a secret key for the admin user. Note that there are many ways to do this. An alternative way is mentioned in the tip below that will do this in one step using grep and awk. admin:/etc/ceph # vi admin.secret 5). Paste the \u201ckey\u201d value into the new file. It will be the only content of the file. It will look like this (in fact it\u2019s probably exactly the same as this, if you\u2019re using the demo environment provided to you): admin:/etc/ceph # cat admin.secret 6). Save the file and exist out of the editor. 7). Change the permissions of the file so that no other user on the host can see the content of the file: admin:/etc/ceph # chmod 0600 admin.secret admin:/etc/ceph # l drwxr-xr-x 1 root root 154 Jan 5 20:03 ./ drwxr-xr-x 1 root root 4392 Oct 5 13:03 ../ -rw------- 1 root root 41 Jan 5 20:03 admin.secret -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw------- 1 root root 126 Jan 5 19:31 ceph.client.james.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap Tip: An alternative way to create this key file is to simply use grep/awk together in one bash command, like this: admin:/etc/ceph # grep \"key =\" ceph.client.admin.keyring | awk -F\" = \" '{ print $2 }' admin:/etc/ceph # grep \"key =\" ceph.client.admin.keyring | awk -F\" = \" '{ print $2 }' > admin.secret admin:/etc/ceph # cat admin.secret Task 4: View the Ceph master configuration file \u00b6 View the content of the file. The file is managed and controlled by DeepSea. The comment makes reference to the control files in the /srv/salt/ceph/configuration/ directory hierarchy. This is a very simple storage cluster. In a more diverse and sophisticated ceph cluster there may be more configuration settings defined. Although this exercise doesn\u2019t call out any more specific information about this configuration file, you may take a moment to consider the content of the file before finishing the task. admin:/etc/ceph # cat ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.186, 10.58.121.187, 10.58.121.188 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] admin:/etc/ceph # ls -l /srv/salt/ceph/configuration/ drwxr-xr-x 1 salt salt 18 Oct 5 13:13 cache drwxr-xr-x 1 root root 38 Oct 5 09:04 check drwxr-xr-x 1 root root 74 Oct 5 09:04 create -rw-r--r-- 1 root root 217 May 14 2020 default-import.sls -rw-r--r-- 1 root root 222 May 14 2020 default.sls drwxr-xr-x 1 root root 276 Oct 5 12:55 files -rw-r--r-- 1 root root 74 May 14 2020 init.sls 2.2.2. Run the Ceph Health Commands \u00b6 Get overall health status admin:~ # ceph health HEALTH_OK admin:~ # ceph -s admin:~ # ceph status cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 5w) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 98m), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 208 pgs objects: 246 objects, 4.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 208 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr Run the \u201cstatus\u201d command for the monitors: admin:~ # ceph mon stat e1: 3 mons at { mon1=[v2:10.58.121.186:3300/0,v1:10.58.121.186:6789/0], mon2=[v2:10.58.121.187:3300/0,v1:10.58.121.187:6789/0], mon3=[v2:10.58.121.188:3300/0,v1:10.58.121.188:6789/0] }, election epoch 22, leader 0 mon1, quorum 0,1,2 mon1,mon2,mon3 Run the \u201cstatus\u201d command for the placement groups: admin:~ # ceph pg stat 208 pgs: 208 active+clean; 4.7 KiB data, 2.1 GiB used, 82 GiB / 96 GiB avail; 852 B/s rd, 0 op/s Run the ceph \u201cstatus\u201d command while watching for changes to the status: admin:~ # ceph -s --watch-debug cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 5w) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 104m), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 208 pgs objects: 246 objects, 4.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 208 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr 2021-01-05 20:20:53.947298 mgr.mon1 [DBG] pgmap v1597415: 208 pgs: 208 active+clean; 4.7 KiB data, 2.1 GiB used, 82 GiB / 96 GiB avail; 852 B/s rd, 0 op/s 2021-01-05 20:20:55.949294 mgr.mon1 [DBG] pgmap v1597416: 208 pgs: 208 active+clean; 4.7 KiB data, 2.1 GiB used, 82 GiB / 96 GiB avail; 1.2 KiB/s rd, 1 op/s ....... 2.2.3. Manipulate Pools \u00b6 Task 1: Display a list of the current pools \u00b6 admin:~ # ceph osd pool ls iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log admin:~ # ceph osd pool ls detail pool 1 'iscsi-images' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 448 lfor 0/448/446 flags hashpspool stripe_width 0 application rbd pool 2 'cephfs_data' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 1395 lfor 0/1374/1372 flags hashpspool stripe_width 0 application cephfs pool 3 'cephfs_metadata' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 1385 lfor 0/975/973 flags hashpspool stripe_width 0 pg_autoscale_bias 4 pg_num_min 16 recovery_priority 5 application cephfs pool 4 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 31 flags hashpspool stripe_width 0 application rgw pool 5 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 33 flags hashpspool stripe_width 0 application rgw pool 6 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 35 flags hashpspool stripe_width 0 application rgw pool 7 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 37 flags hashpspool stripe_width 0 application rgw List pools with their index numbgr. Note how the index numbgr matches the index numbgr of the detail listing above. admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log Task 2: Display the usage data and stats of the current pools \u00b6 Display pool usages. Note again index \u201cID\u201d for the pool. admin:~ # ceph df RAW STORAGE: CLASS SIZE AVAIL USED RAW USED %RAW USED hdd 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 TOTAL 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 POOLS: POOL ID STORED OBJECTS USED %USED MAX AVAIL iscsi-images 1 389 B 2 192 KiB 0 25 GiB cephfs_data 2 0 B 0 0 B 0 25 GiB cephfs_metadata 3 7.2 KiB 48 1.5 MiB 0 25 GiB .rgw.root 4 1.2 KiB 4 768 KiB 0 25 GiB default.rgw.control 5 0 B 8 0 B 0 25 GiB default.rgw.meta 6 381 B 3 576 KiB 0 25 GiB default.rgw.log 7 35 KiB 208 35 KiB 0 25 GiB admin:~ # ceph df detail RAW STORAGE: CLASS SIZE AVAIL USED RAW USED %RAW USED hdd 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 TOTAL 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 POOLS: POOL ID STORED OBJECTS USED %USED MAX AVAIL QUOTA OBJECTS QUOTA BYTES DIRTY USED COMPR UNDER COMPR iscsi-images 1 389 B 2 192 KiB 0 25 GiB N/A N/A 2 0 B 0 B cephfs_data 2 0 B 0 0 B 0 25 GiB N/A N/A 0 0 B 0 B cephfs_metadata 3 7.2 KiB 48 1.5 MiB 0 25 GiB N/A N/A 48 0 B 0 B .rgw.root 4 1.2 KiB 4 768 KiB 0 25 GiB N/A N/A 4 0 B 0 B default.rgw.control 5 0 B 8 0 B 0 25 GiB N/A N/A 8 0 B 0 B default.rgw.meta 6 381 B 3 576 KiB 0 25 GiB N/A N/A 3 0 B 0 B default.rgw.log 7 35 KiB 208 35 KiB 0 25 GiB N/A N/A 208 0 B 0 B Display pool usages using rados command admin:~ # rados df POOL_NAME USED OBJECTS CLONES COPIES MISSING_ON_PRIMARY UNFOUND DEGRADED RD_OPS RD WR_OPS WR USED COMPR UNDER COMPR .rgw.root 768 KiB 4 0 12 0 0 0 40 40 KiB 4 4 KiB 0 B 0 B cephfs_data 0 B 0 0 0 0 0 0 0 0 B 0 0 B 0 B 0 B cephfs_metadata 1.5 MiB 48 0 144 0 0 0 0 0 B 111 42 KiB 0 B 0 B default.rgw.control 0 B 8 0 24 0 0 0 0 0 B 0 0 B 0 B 0 B default.rgw.log 35 KiB 208 0 624 0 0 0 5919671 5.6 GiB 3945118 946 KiB 0 B 0 B default.rgw.meta 576 KiB 3 0 9 0 0 0 38 28 KiB 4 3 KiB 0 B 0 B iscsi-images 192 KiB 2 0 6 0 0 0 4184657 4.0 GiB 8 2 KiB 0 B 0 B total_objects 246 total_used 14 GiB total_avail 82 GiB total_space 96 GiB Show the statistics of the pools: admin:~ # ceph osd pool stats pool iscsi-images id 1 client io 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr pool cephfs_data id 2 nothing is going on pool cephfs_metadata id 3 nothing is going on pool .rgw.root id 4 nothing is going on pool default.rgw.control id 5 nothing is going on pool default.rgw.meta id 6 nothing is going on pool default.rgw.log id 7 nothing is going on Show only the statistics about a specific pool: admin:~ # ceph osd pool stats .rgw.root pool .rgw.root id 4 nothing is going on Show which CRUSH Map ruleset was used to create the .rgw.root pool: admin:~ # ceph osd pool get .rgw.root crush_rule crush_rule: replicated_rule Show the list of all the attributes of a pool that can be queried: admin:~ # ceph osd pool get .rgw.root size min_size pg_num pgp_num crush_rule Hashpspool Nodelete Nopgchange Nosizechange write_fadvise_dontneed noscrub|nodeep-scrub hit_set_type hit_set_period hit_set_count hit_set_fpp use_gmt_hitset target_max_objects target_max_bytes cache_target_dirty_ratio cache_target_dirty_high_ratio cache_target_full_ratio cache_min_flush_age cache_min_evict_age erasure_code_profile min_read_recency_for_promote all|min_write_recency_for_promote fast_read|hit_set_grade_decay_rate hit_set_search_last_n scrub_min_interval scrub_max_interval deep_scrub_interval recovery_priority recovery_op_priority scrub_priority compression_mode compression_algorithm compression_required_ratio compression_max_blob_size compression_min_blob_size csum_type|csum_min_block csum_max_block allow_ec_overwrites fingerprint_algorithm pg_autoscale_mode pg_autoscale_bias pg_num_min target_size_bytes target_size_ratio Task 3: Create two new pools, one replicated, one EC \u00b6 1). Create a new replicated pool that will be used for storing block data for RBD. Use the standard replicated_ruleset CRUSH Map: It would be tempting to the use the better_ruleset, but this demo environment doesn\u2019t have enough resources for that. This is a demo environment, so the PG numbgrs will be low. In your production environments, be sure to assign an appropriately high numbgr, or use the pg_autoscaler manager module. admin:~ # ceph osd pool create rbd_pool 4 4 replicated replicated_rule pool 'rbd_pool' created 2). Tell the cluster that you expect to have this new rbd_pool to use 50% of the total capacity: admin:~ # ceph osd pool set rbd_pool target_size_ratio .5 set pool 8 target_size_ratio to .5 3). Create a new EC pool that will be used for storing RGW buckets and objects. Use the usable_profile Erasure Code profile that was created in an earlier exercise. And use the ec_rule CRUSH Map ruleset that was created in an earlier exercise: admin:~ # ceph osd pool create bucket_pool 4 4 erasure usable_profile ec_rule pool 'bucket_pool' created 4). Tell the cluster that you expect to have this new bucket_pool to use 100GB of data: POOL_TARGET_SIZE_BYTES_OVERCOMMITTED admin:~ # ceph osd pool set bucket_pool target_size_bytes 100000000000 set pool 9 target_size_bytes to 100000000000 5). Enable the PG Autoscaler feature on the two new pools, to ensure that we have an appropriate assignment of placement groups in the demo cluster: This presumes that you completed an earlier exercise that enable the pg_autoscaler manager module. admin:~ # ceph osd pool set bucket_pool pg_autoscale_mode on set pool 9 pg_autoscale_mode to on admin:~ # ceph osd pool set rbd_pool pg_autoscale_mode on set pool 8 pg_autoscale_mode to on 6). Again display a list of all the pools, which will now include the two new pools that you\u2019ve just created: Notice in the detail listing that the two new pools don\u2019t have an application attribute assigned to them. admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log 8 rbd_pool 9 bucket_pool admin:~ # ceph osd pool ls detail pool 1 'iscsi-images' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 448 lfor 0/448/446 flags hashpspool stripe_width 0 application rbd pool 2 'cephfs_data' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 1395 lfor 0/1374/1372 flags hashpspool stripe_width 0 application cephfs pool 3 'cephfs_metadata' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 1385 lfor 0/975/973 flags hashpspool stripe_width 0 pg_autoscale_bias 4 pg_num_min 16 recovery_priority 5 application cephfs pool 4 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 31 flags hashpspool stripe_width 0 application rgw pool 5 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 33 flags hashpspool stripe_width 0 application rgw pool 6 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 35 flags hashpspool stripe_width 0 application rgw pool 7 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 37 flags hashpspool stripe_width 0 application rgw pool 8 'rbd_pool' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 1415 lfor 0/0/1413 flags hashpspool stripe_width 0 target_size_ratio 0.5 pool 9 'bucket_pool' erasure size 3 min_size 2 crush_rule 3 object_hash rjenkins pg_num 4 pgp_num 4 autoscale_mode on last_change 1410 flags hashpspool stripe_width 8192 target_size_bytes 100000000000 7). Check the pg_autoscale status, particularly to see a comparison of how much raw space is being consumed by the two pools: See that the RATE column for all of the replicated pools shows the value of 3.0, while the value for the bucket_pool \u2013 which is an EC pool \u2013 is 1.5. The EC pool, with a K+M of 2+1 consumes considerably less raw storage space. See the TARGET RATIO for the rbd_pool. Notice that the autoscaler has automatically adjusted the numbgr PGs assigned to rbd_pool from \u201c4\u201d to \u201c128\u201d because you told the cluster to have the pool use 50% of the capacity. See the TARGET SIZE for the bucket_pool, roughly 100GB. But the cluster may not have changed the PG_NUM value yet. The autoscaler will adjust the numbgr of PGs gradually, so as not to disrupt the performance too dramatically. While you\u2019re here, you might also notice the RAW CAPACITY column. All pools are expecting to divide the cluster space equally, even though you\u2019ve explicitly told the cluster that rbd_pool and bucket_pool will deviate from that even division. admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 32 on cephfs_data 0 3.0 98256M 0.0000 1.0 32 off cephfs_metadata 7412 3.0 98256M 0.0000 4.0 16 off .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 35900 3.0 98256M 0.0000 1.0 32 warn rbd_pool 0 3.0 98256M 0.0000 0.5000 1.0 32 on bucket_pool 0 95367M 1.5 98256M 1.4559 1.0 4 on Task 4: Assign an application to the two new pools \u00b6 1). Assign the rbd application to the new rbd_pool that you created in the previous task: admin:~ # ceph osd pool application enable rbd_pool rbd enabled application 'rbd' on pool 'rbd_pool' 2). Instruct the cluster to prepare the new rbd_pool for storing block device images: admin:~ # rbd pool init rbd_pool 3). Assign the rgw application to the new bucket_pool that you created in the previous task: admin:~ # ceph osd pool application enable bucket_pool rgw enabled application 'rgw' on pool 'bucket_pool' 4). Display a list of all the pools again, this time noticing that the application attribute is set on the two new pools. admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log 8 rbd_pool 9 bucket_pool admin:~ # ceph osd pool ls detail pool 1 'iscsi-images' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 448 lfor 0/448/446 flags hashpspool stripe_width 0 application rbd pool 2 'cephfs_data' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 1395 lfor 0/1374/1372 flags hashpspool stripe_width 0 application cephfs pool 3 'cephfs_metadata' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 1385 lfor 0/975/973 flags hashpspool stripe_width 0 pg_autoscale_bias 4 pg_num_min 16 recovery_priority 5 application cephfs pool 4 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 31 flags hashpspool stripe_width 0 application rgw pool 5 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 33 flags hashpspool stripe_width 0 application rgw pool 6 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 35 flags hashpspool stripe_width 0 application rgw pool 7 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 37 flags hashpspool stripe_width 0 application rgw pool 8 'rbd_pool' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 1420 lfor 0/0/1413 flags hashpspool,selfmanaged_snaps stripe_width 0 target_size_ratio 0.5 application rbd removed_snaps [1~3] pool 9 'bucket_pool' erasure size 3 min_size 2 crush_rule 3 object_hash rjenkins pg_num 4 pgp_num 4 autoscale_mode on last_change 1422 flags hashpspool stripe_width 8192 target_size_bytes 100000000000 application rgw 5). Another way to display which application is assigned to a pool is: admin:~ # ceph osd pool application get bucket_pool { \"rgw\": {} } admin:~ # ceph osd pool application get rbd_pool { \"rbd\": {} } Task 5: Manage snapshots of the new RGW bucket pool \u00b6 1). Display a list of the snapshots that exist of the bucket_pool that you created in the previous task: The output show that there are \u201c0 snaps.\u201d Right, it is a little funny that you only list the snapshots with rados command; no such functionality exists with the ceph osd pool command. admin:~ # rados -p bucket_pool lssnap 0 snaps 2). Take (make) a snapshot of the rbd_pool: admin:~ # ceph osd pool mksnap bucket_pool brand_new_pool_snapshot created pool bucket_pool snap brand_new_pool_snapshot 3). Display the list of the snapshots again: admin:~ # rados -p bucket_pool lssnap 1 brand_new_pool_snapshot 2021.01.05 22:23:23 1 snaps 4). Remove the snapshot: admin:~ # ceph osd pool rmsnap bucket_pool brand_new_pool_snapshot removed pool bucket_pool snap brand_new_pool_snapshot 5). Display the list of the snapshots again: admin:~ # rados -p bucket_pool lssnap 0 snaps 2.2.4. Maintain consistency of data with Scrub and Repair \u00b6 Scrubbing is like \u201cfsck,\u201d which ensures that OSDs have durable, consistent data. Most of the scrubbing of OSDs happens automatically on a periodic basis. Task 1: Display a few of the Scrub settings \u00b6 1). Show the possible configuration settings related to scrub: If you simply grep for \u201cscrub\u201d you\u2019ll get more than you really want; there are some mon_scrub settings that aren\u2019t related to this exercise. admin:~ # ceph config ls | grep osd_scrub osd_scrub_invalid_stats osd_scrub_during_recovery osd_scrub_begin_hour osd_scrub_end_hour osd_scrub_begin_week_day osd_scrub_end_week_day osd_scrub_load_threshold osd_scrub_min_interval osd_scrub_max_interval osd_scrub_interval_randomize_ratio osd_scrub_backoff_ratio osd_scrub_chunk_min osd_scrub_chunk_max osd_scrub_sleep osd_scrub_auto_repair osd_scrub_auto_repair_num_errors osd_scrub_max_preemptions osd_scrub_priority osd_scrub_cost admin:~ # ceph config ls | grep osd_deep_scrub osd_deep_scrub_interval osd_deep_scrub_randomize_ratio osd_deep_scrub_stride osd_deep_scrub_keys osd_deep_scrub_update_digest_min_age osd_deep_scrub_large_omap_object_key_threshold osd_deep_scrub_large_omap_object_value_sum_threshold admin:~ # ceph config ls | grep scrub mon_warn_pg_not_scrubbed_ratio mon_warn_pg_not_deep_scrubbed_ratio mon_scrub_interval mon_scrub_timeout mon_scrub_max_keys mon_scrub_inject_crc_mismatch mon_scrub_inject_missing_keys osd_op_queue_mclock_scrub_res osd_op_queue_mclock_scrub_wgt osd_op_queue_mclock_scrub_lim osd_scrub_invalid_stats osd_max_scrubs osd_scrub_during_recovery osd_scrub_begin_hour osd_scrub_end_hour osd_scrub_begin_week_day osd_scrub_end_week_day osd_scrub_load_threshold osd_scrub_min_interval osd_scrub_max_interval osd_scrub_interval_randomize_ratio osd_scrub_backoff_ratio osd_scrub_chunk_min osd_scrub_chunk_max osd_scrub_sleep osd_scrub_auto_repair osd_scrub_auto_repair_num_errors osd_scrub_max_preemptions osd_deep_scrub_interval osd_deep_scrub_randomize_ratio osd_deep_scrub_stride osd_deep_scrub_keys osd_deep_scrub_update_digest_min_age osd_deep_scrub_large_omap_object_key_threshold osd_deep_scrub_large_omap_object_value_sum_threshold osd_debug_deep_scrub_sleep osd_scrub_priority osd_scrub_cost osd_requested_scrub_priority mds_max_scrub_ops_in_progress 2). Get the value of a few of the different scrub schedule settings: Note that \u201c0\u201d and \u201c24\u201d are the same setting. admin:~ # ceph config get osd.* osd_scrub_begin_hour 0 admin:~ # ceph config get osd.* osd_scrub_end_hour 24 3). Get the value of the scrub and repair settings: The \u201cauto repair\u201d feature is turned off, and the maximum numbgr of errors that \u201cauto repair\u201d would automatically repair is 5. admin:~ # ceph config get osd.* osd_scrub_auto_repair false admin:~ # ceph config get osd.* osd_scrub_auto_repair_num_errors 5 Task 2: Change the Scrub settings in ceph.conf \u00b6 1). Display the ceph.conf, and verify that the file doesn\u2019t have any settings defined yet that are related to scrub. The settings would be located in the [global] section of the file: # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.186, 10.58.121.187, 10.58.121.188 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] 2). Change to the Salt File Server directory that will have Salt control the master ceph.conf configuration file: admin:~ # cd /srv/salt/ceph/configuration/files/ceph.conf.d/ 3). List the content of the directory: The directory is empty. (Well, there is a README, but no other functional files.) admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ls -l -rw-r--r-- 1 root root 1989 May 14 2020 README 4). Create and edit a new file called global.conf. You don\u2019t have to use vi, but this step uses vi as one way of doing it: Be sure that you spell everything correctly, including the absence of \u201c_\u201d characters; there are spaces. Save the file and exit out of the editor. admin:/srv/salt/ceph/configuration/files/ceph.conf.d # vi global.conf Add the following content to the file: osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 5). Use DeepSea (Salt) to stage the file properly in Salt\u2019s File Server on the Salt Master (admin): admin:/srv/salt/ceph/configuration/files/ceph.conf.d # salt admin* state.apply ceph.configuration.create admin.sha.me.corp: Name: /var/cache/salt/minion/files/base/ceph/configuration - Function: file.absent - Result: Changed Started: - 22:42:34.900173 Duration: 20.891 ms Name: /srv/salt/ceph/configuration/cache/ceph.conf - Function: file.managed - Result: Changed Started: - 22:42:34.921454 Duration: 8576.516 ms Name: find /var/cache/salt/master/jobs -user root -exec chown salt:salt {} ';' - Function: cmd.run - Result: Changed Started: - 22:42:43.535022 Duration: 71.957 ms Summary for admin.sha.me.corp ------------ Succeeded: 3 (changed=3) Failed: 0 ------------ Total states run: 3 Total run time: 8.669 s 6). Using DeepSea (Salt), distribute the new ceph.conf configuration settings to all the nodes in the cluster: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # salt \\* state.apply ceph.configuration mon3.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:07.986661 Duration: 101.977 ms Summary for mon3.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 101.977 ms mon1.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.012479 Duration: 108.888 ms Summary for mon1.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 108.888 ms data3.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.052247 Duration: 98.681 ms Summary for data3.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 98.681 ms admin.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.072402 Duration: 97.231 ms Summary for admin.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 97.231 ms data1.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.076279 Duration: 104.169 ms Summary for data1.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 104.169 ms data4.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.081635 Duration: 105.13 ms Summary for data4.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 105.130 ms mon2.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.155758 Duration: 105.004 ms Summary for mon2.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 105.004 ms data2.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.252200 Duration: 109.552 ms Summary for data2.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 109.552 ms 7). Verify that the new ceph.conf settings have been put into place on the admin node: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # cat /etc/ceph/ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] 8). Also verify that other minions in the cluster have also received the updated configuration file, such as on the mon1 and data2 nodes: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ssh mon1 cat /etc/ceph/ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ssh data1 cat /etc/ceph/ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] 9). Apply the settings of the ceph.conf file to appropriate nodes in the cluster: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ceph config assimilate-conf -i /etc/ceph/ceph.conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_health_preluminous_compat = true mon_health_preluminous_compat_warning = false mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 mon_initial_membgrs = mon1, mon2, mon3 Task 3: Change the Scrub settings directly in the Configuration DB \u00b6 1). Query the configuration database to see the value of \u201cosd_scrub_auto_repair_num_errors\u201d: You changed this value to \u201c10\u201d in the previous Task. admin:~ # ceph config get osd.* osd_scrub_auto_repair_num_errors 10 2). Change the value of \u201cosd_scrub_auto_repair_num_errors\u201d to \u201c8\u201d: admin:~ # ceph config set osd.* osd_scrub_auto_repair_num_errors 8 3). Show that the change has taken immediate effect by re-running the same command that was used in the first step: admin:~ # ceph config get osd.* osd_scrub_auto_repair_num_errors 8 Task 4: Manually scrub and repair an OSD and a PG \u00b6 This won\u2019t do much in this demo environment, because the OSDs aren\u2019t storing very much data. But it\u2019s worth having some practice. 1). Start a scrubbing of one of the OSDs: admin:~ # ceph osd scrub osd.1 instructed osd(s) 1 to scrub 2). Scrub a Placement Group: admin:~ # ceph pg scrub 8.1 instructing pg 8.1 on osd.0 to scrub 3). Repair an OSD: admin:~ # ceph osd repair osd.1 instructed osd(s) 1 to repair 4). Repair a PG: admin:~ # ceph pg repair 8.1 instructing pg 8.1 on osd.0 to repair 5). Show what\u2019s currently happening to the OSD that you instructed to have scrubbed and repaired: admin:~ # ceph osd dump | grep osd.1 max_osd 12 osd.1 up in weight 1 up_from 10 up_thru 1415 down_at 0 last_clean_interval [0,0) v1:10.58.121.185:6800/11157 v1:10.58.121.185:6801/11157 exists,up 32c78078-1878-4fac-9738-00d8bf80deea osd.10 up in weight 1 up_from 18 up_thru 1413 down_at 0 last_clean_interval [0,0) v1:10.58.121.182:6808/11130 v1:10.58.121.182:6809/11130 exists,up 6cb26fdc-09b1-42de-8855-7203931a0101 osd.11 up in weight 1 up_from 18 up_thru 1415 down_at 0 last_clean_interval [0,0) v1:10.58.121.185:6808/11995 v1:10.58.121.185:6809/11995 exists,up cc22107d-0239-4874-8308-6c137c8a0931 6). Show what\u2019s currently happening to the PG that you instructed to have scrubbed and repaired: admin:~ # ceph pg dump | grep \"8\\.1\" dumped all 8.16 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.383909 0'0 1423:27 [6,4,5] 6 [6,4,5] 6 0'0 2021-01-05 20:53:47.314062 0'0 2021-01-05 20:53:47.314062 0 8.17 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:01.044252 0'0 1424:30 [1,6,8] 1 [1,6,8] 1 0'0 2021-01-05 22:57:01.044098 0'0 2021-01-05 22:57:01.044098 0 8.14 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:56:56.081480 0'0 1424:30 [1,2,4] 1 [1,2,4] 1 0'0 2021-01-05 22:56:56.081356 0'0 2021-01-05 22:56:56.081356 0 8.15 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.375386 0'0 1423:27 [3,5,0] 3 [3,5,0] 3 0'0 2021-01-05 20:53:53.231124 0'0 2021-01-05 20:48:05.301705 0 8.12 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.370121 0'0 1423:27 [11,2,8] 11 [11,2,8] 11 0'0 2021-01-05 20:53:48.149449 0'0 2021-01-05 20:48:05.301705 0 2.18 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 16:44:58.986205 0'0 1423:1630 [10,1,8] 10 [10,1,8] 10 0'0 2021-01-05 13:02:00.365382 0'0 2021-01-02 00:38:58.134100 0 8.13 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.387832 0'0 1423:27 [0,8,1] 0 [0,8,1] 0 0'0 2021-01-05 20:53:56.132358 0'0 2021-01-05 20:48:05.301705 0 8.10 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.368416 0'0 1423:27 [11,3,6] 11 [11,3,6] 11 0'0 2021-01-05 20:53:51.152790 0'0 2021-01-05 20:48:05.301705 0 8.11 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.377871 0'0 1423:24 [3,10,5] 3 [3,10,5] 3 0'0 2021-01-05 20:53:45.195257 0'0 2021-01-05 20:48:05.301705 0 8.1e 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.391754 0'0 1423:47 [0,11,8] 0 [0,11,8] 0 0'0 2021-01-05 20:53:55.081582 0'0 2021-01-05 20:48:05.301705 0 8.1 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:56:39.829397 0'0 1424:54 [0,7,10] 0 [0,7,10] 0 0'0 2021-01-05 22:56:39.829241 0'0 2021-01-05 22:56:39.829241 0 8.1f 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.392315 0'0 1423:27 [7,5,9] 7 [7,5,9] 7 0'0 2021-01-05 20:53:59.988252 0'0 2021-01-05 20:48:05.301705 0 5.4 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 18:21:28.179266 0'0 1423:1554 [7,9,6] 7 [7,9,6] 7 0'0 2021-01-05 18:21:28.179166 0'0 2021-01-05 18:21:28.179166 0 5.b 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 18:37:01.467457 0'0 1423:1547 [2,0,11] 2 [2,0,11] 2 0'0 2021-01-04 23:46:58.132824 0'0 2021-01-02 03:35:41.214192 0 8.19 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:06.059090 0'0 1424:30 [1,8,2] 1 [1,8,2] 1 0'0 2021-01-05 22:57:06.058935 0'0 2021-01-05 22:57:06.058935 0 8.18 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:05.097742 0'0 1424:30 [1,3,6] 1 [1,3,6] 1 0'0 2021-01-05 22:57:05.097670 0'0 2021-01-05 22:57:05.097670 0 1.11 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 00:30:18.193988 0'0 1423:1605 [0,8,6] 0 [0,8,6] 0 0'0 2021-01-05 00:30:18.193868 0'0 2020-12-29 06:30:58.897565 0 8.1b 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:13.146469 0'0 1424:30 [1,4,6] 1 [1,4,6] 1 0'0 2021-01-05 22:57:13.146390 0'0 2021-01-05 22:57:13.146390 0 8.1a 1 0 0 0 0 19 0 0 2 2 active+clean 2021-01-05 21:01:16.386166 1420'2 1423:29 [9,11,10] 9 [9,11,10] 9 0'0 2021-01-05 20:53:48.690239 0'0 2021-01-05 20:48:05.301705 0 8.1d 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.388079 0'0 1423:56 [0,2,3] 0 [0,2,3] 0 0'0 2021-01-05 20:53:54.121281 0'0 2021-01-05 20:48:05.301705 0 8.1c 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.385846 0'0 1423:27 [2,11,7] 2 [2,11,7] 2 0'0 2021-01-05 20:53:55.458714 0'0 2021-01-05 20:48:05.301705 0 2.2.5. Manipulate Manager Modules \u00b6 Task 1: Display the list of enabled Manager Modules \u00b6 1). Run the following command to show the list of enabled manager modules: Note that several modules are already enabled, such as: dashboard, iostat, pg_autosclater, prometheus, and restful. Even though they are not listed, the crash module and the balancer module are already enabled by default. admin:~ # ceph mgr module ls | head { \"always_on_modules\": [ \"balancer\", \"crash\", \"devicehealth\", \"orchestrator_cli\", \"progress\", \"rbd_support\", \"status\", \"volumes\" 2). Demonstrate that the crash module is enabled by running its command with no arguments: A list of \u201c7 closest matches\u201d is displayed, representing possible additional arguments to be used with the crash command. The crash module is therefore available. admin:~ # ceph crash crash info crash ls crash ls-new crash post crash prune crash rm crash stat crash json_report crash archive crash archive-all admin:~ # ceph crash stat 0 crashes recorded Task 2: Use the iostat module to display statistics for the IO of the cluster The iostat module is really simple, but very helpful. Run the command: admin:~ # ceph iostat +-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+ | Read | Write | Total | Read IOPS | Write IOPS | Total IOPS | +-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+ | 1024 B/s | 0 B/s | 1024 B/s | 1 | 0 | 1 | | 1024 B/s | 0 B/s | 1024 B/s | 1 | 0 | 1 | | 0 B/s | 0 B/s | 0 B/s | 0 | 0 | 0 | Task 3: Enable and configure the telemetry manager module 1). Enable the telemetry manager module: admin:~ # ceph mgr module enable telemetry 2). Show the various sub-commands that are associated with the telemetry command: A list of \u201c5 closest matches\u201d is displayed, showing various options. admin:~ # ceph telemetry telemetry status telemetry send {ceph|device [ceph|device...]} {} telemetry show { [...]} telemetry show-device telemetry on {} telemetry off 3). Show the status of the telemetry module: Notice that the output is returned as key/value pairs. Notice also that although the module has been enabled (which you accomplished in the first step of this task), the functionality is not enabled (enable=false). And for most of the keys, a null value is set. See that the url value is set to https://telemetry.ceph.com/report. That means that crash reports and other usage information about this cluster are going to be sent to the Ceph Community. admin:~ # ceph telemetry status { \"url\": \"https://telemetry.ceph.com/report\", \"device_url\": \"https://telemetry.ceph.com/device\", \"enabled\": false, \"last_opt_revision\": 1, \"leaderboard\": false, \"description\": null, \"contact\": null, \"organization\": null, \"proxy\": null, \"interval\": 24, \"channel_basic\": true, \"channel_ident\": false, \"channel_crash\": true, \"channel_device\": true, \"last_upload\": null } 4). Set the description, contact, and organization values: admin:~ # ceph config set mgr mgr/telemetry/contact 'JD ' admin:~ # ceph config set mgr mgr/telemetry/description 'Training Cluster' admin:~ # ceph config set mgr mgr/telemetry/organization 'SUSE Training' 5). Display the telemetry data that is collected to be sent: admin:~ # ceph telemetry show | less 6). With the contact information properly set, enable the telemetry functionality: This is a demo cluster with no connection to the internet, so no telemetry data will actually be sent. admin:~ # ceph telemetry on Error EPERM: Telemetry data is licensed under the Community Data License Agreement - Sharing - Version 1.0 (https://cdla.io/sharing-1-0/). To enable, add '--license sharing-1-0' to the 'ceph telemetry on' command. admin:~ # ceph telemetry on --license sharing-1-0 7). Disable the telemetry module: admin:~ # ceph mgr module disable telemetry admin:~ # ceph telemetry show | less Error ENOTSUP: Module 'telemetry' is not enabled (required by command 'telemetry show'): use `ceph mgr module enable telemetry` to enable it Task 4: Briefly attempt to use the crash manager module \u00b6 1). Show (again) the various sub-commands that are associated with the crash command: admin:~ # ceph crash crash info crash ls crash ls-new crash post crash prune crash rm crash stat crash json_report crash archive crash archive-all 2). Show the current status of the crash database, including the numbgr of crash reports that have been collected so far: It\u2019s likely that the numbgr of crashes recorded in the demo environment is 0. admin:~ # ceph crash stat 0 crashes recorded 2.2.6. Introduction to the Tell command \u00b6 Tell is a very powerful command within Ceph to control the cluster. You don\u2019t use it everyday, but you need to know how to use it when the occasion to use it arises. It\u2019s mostly an Advanced Command, but exposure to it now reduces the stress of learning about it in a more advanced setting later. Run the tell command in a few different circumstances to control the behavior of various Ceph services. Task 1: Run a benchmark test on an OSD \u00b6 1). Run the following command to run and see the result of a benchmark test on osd.8: admin:~ # ceph tell osd.8 bench { \"bytes_written\": 1073741824, \"blocksize\": 4194304, \"elapsed_sec\": 3.7797023200000002, \"bytes_per_sec\": 284081055.35676152, \"iops\": 67.730201567831401 } Task 2: Change the protection setting regarding the deletion of pools \u00b6 1). The default behavior in Ceph is that you can\u2019t delete pools. Try to delete a pool: The output says that you have to be VERY careful and provide more arguments in order to delete a pool admin:~ # ceph osd pool delete rbd_pool Error EPERM: WARNING: this will *PERMANENTLY DESTROY* all data stored in pool rbd_pool. If you are *ABSOLUTELY CERTAIN* that is what you want, pass the pool name *twice*, followed by --yes-i-really-really-mean-it. 2). Try deleting the pool again, this time with the extra arguments: Ceph still won\u2019t let you do it because the mon allow pool delete setting has the value of false. admin:~ # ceph osd pool delete rbd_pool rbd_pool --yes-i-really-really-mean-it Error EPERM: pool deletion is disabled; you must first set the mon_allow_pool_delete config option to true before you can destroy a pool 3). Show that the mon allow pool delete setting has the value of false: Indeed, the output shows that the value is false. admin:~ # ceph config get mon.mon\\* mon_allow_pool_delete false 4). Change to value of the setting using injectargs: Note that the \u201c-\u201d and \u201c_\u201d characters can be confusing. And note that the setting is preceded with the double \u201c--\u201d. The injected args must be enclosed in single quotes. You could have done this with ceph config set, but this is an alternative way to directly \u201ctell\u201d the cluster to change a setting. admin:~ # ceph tell mon.\\* injectargs '--mon-allow-pool-delete=true' mon.mon1: injectargs:mon_allow_pool_delete = 'true' mon.mon2: injectargs:mon_allow_pool_delete = 'true' mon.mon3: injectargs:mon_allow_pool_delete = 'true' 2.3. Ceph Dashboard \u00b6 2.3.1. Access Dashboard \u00b6 Task 1: Set the password for the admin user of the Ceph Dashboard \u00b6 1). In a Bash terminal as the root user, show that the Dashboard module is enabled: \u201cdashboard\u201d should be included in the list of \u201cenabled_modules\u201d at the top of the output. admin:~ # ceph mgr module ls | more \"enabled_modules\": [ \"dashboard\", \"iostat\", \"pg_autoscaler\", \"prometheus\", \"restful\" ], 2). Show the valid dashboard users that have already been created by DeepSea during initial deployment: It\u2019s possible that other users will be listed, but at least the \u201cadmin\u201d user should be displayed in the output. admin:~ # ceph dashboard ac-user-show [\"admin\"] 3). Show the \u201cadmin\u201d user\u2019s information as stored in the user database: You can see that the admin user has a password set, but it is stored as a hash. So you don\u2019t really know what the password is, and have no way of discovering it. admin:~ # ceph dashboard ac-user-show admin {\"username\": \"admin\", \"password\": , \"roles\": [\"administrator\"], \"name\": null, \"email\": null, \"lastUpdate\": 1601874928} 4). Change the \u201cadmin\u201d user\u2019s password for the dashboard: This sets the \u201cadmin\u201d user\u2019s password to the string: mypassword admin:~ # ceph dashboard ac-user-set-password admin mypassword {\"username\": \"admin\", \"password\": , \"roles\": [\"administrator\"], \"name\": null, \"email\": null, \"lastUpdate\": 1609860842} admin:~ # Task 3: Visit the Ceph Dashboard URL \u00b6 admin:~ # salt-call grains.get dashboard_creds local: ---------- admin: admin:~ # ceph mgr services { \"dashboard\": \"https://mon1.sha.me.corp:8443/\", \"prometheus\": \"http://mon1.sha.me.corp:9283/\" } admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 25m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 5h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 9 pools, 244 pgs objects: 247 objects, 5.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 244 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr URL: https://mon1.sha.me.corp:8443/ https://10.58.121.186:8443 2.3.2. Explore the Dashboard Health, Performance, Status \u00b6 Dashboard Status Cluster Status Monitors OSDs Manager Daemons Hosts Object Gateway Metadata Service iSCSI Gateway Performance Client IOPS Client Throughput Client Read/Write Recovery Throughput Scrub Capacity Pools Raw Capacity Objects PGs per OSD PG Status [SUSE Enterprise Storage Portal Cluster\u2192Configuration Cluster\u2192Manager Modules Pools\u2192Create Pool 2.4. Storage Data Access \u00b6 2.4.1. Ensure the SES Cluster is Healthy \u00b6 Task 1: Check the Cluster\u2019s health \u00b6 1). Run the following command to check the status (health) of the SES cluster: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 18h) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 23h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 5.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr 2). Evaluate the output. The cluster in this demonstration environment often doesn\u2019t startup correctly due to the nature of a demo environment and it\u2019s less-predictable resources. Depending on whether any of the following tasks are necessary, followup accordingly to ensure that the cluster is healthy before proceeding with the course lectures or any further exercises. 3). Run the following series of commands to restart the Monitor daemons on each of the Monitor nodes: It\u2019s certainly not necessary to restart the monitor daemons on all of the monitor nodes if only one is down. If you prefer, you can take a different approach to starting the daemon on a single monitor node. admin:~ # for h in mon1 mon2 mon3; \\ do \\ ssh $h systemctl restart ceph-mon@$h; \\ done 4). After waiting a few moments for the daemons to restart, check the status again: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 15s) mgr: mon1(active, since 21h) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 26h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 5.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 767 B/s rd, 0 op/s rd, 0 op/s wr 5). Run the following series of commands to restart the Manager daemons on each of the Monitor nodes: admin:~ # for h in mon1 mon2 mon3; \\ do \\ ssh $h systemctl restart ceph-mgr@$h; \\ done 6). After waiting a few moments for the daemons to restart, check the status again: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 8m) mgr: mon1(active, since 18s) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 26h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.1 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr 7). Run the following command to restart the MDS daemon on the MDS node (mon1): admin:~ # ssh mon1 systemctl restart ceph-mds@mon1.service 8). After waiting a few moments for the mds daemon to restart, check the status again: Look for the mds service to be plain active rather than laggy or crashed admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 17m) mgr: mon1(active, since 8m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 26h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.2 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr 9). Verify if the OSDs \u201cup\u201d and running properly. It is only necessary if the output of ceph -s shows that there are fewer than 9 OSDs shown as being \u201cup\u201d. It\u2019s most likely that a storage node is simply not quite fully booted yet, such that the OSD daemons haven\u2019t fully come up. But if you suspect that the solution requires something different than simply waiting a little longer, you should try the following steps. First, identify which server is hosting the down\u2019d OSDs. One way of doing that is with this command: admin:~ # ceph osd tree ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF -1 0.09357 root default -9 0.02339 host data1 2 hdd 0.00780 osd.2 up 1.00000 1.00000 6 hdd 0.00780 osd.6 up 1.00000 1.00000 10 hdd 0.00780 osd.10 up 1.00000 1.00000 -3 0.02339 host data2 0 hdd 0.00780 osd.0 up 1.00000 1.00000 4 hdd 0.00780 osd.4 up 1.00000 1.00000 9 hdd 0.00780 osd.9 up 1.00000 1.00000 -7 0.02339 host data3 3 hdd 0.00780 osd.3 up 1.00000 1.00000 7 hdd 0.00780 osd.7 up 1.00000 1.00000 8 hdd 0.00780 osd.8 up 1.00000 1.00000 -5 0.02339 host data4 1 hdd 0.00780 osd.1 up 1.00000 1.00000 5 hdd 0.00780 osd.5 up 1.00000 1.00000 11 hdd 0.00780 osd.11 up 1.00000 1.00000 Simply try restarting the storage daemon processes on the affected host, such as with this example: admin:~ # ssh data2 systemctl restart ceph-osd@9.service admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 32m) mgr: mon1(active, since 24m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 27s), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.2 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr If the OSD daemon processes are being stubborn and uncooperative, you may choose to reboot the storage virtual machine entirely. This is one way to do that: admin:~ # ssh data1 systemctl reboot After waiting some time for the daemons to get started, verify that all the OSDs are \u201cup\u201d and that the cluster is healthy: admin:~ # ceph osd tree admin:~ # ceph status 10). Run the following command to restart the RADOS Gateway daemon on the node that is hosting the gateway (mon3): admin:~ # ssh mon3 systemctl restart ceph-radosgw@rgw.mon3.service admin:~ # ssh mon3 systemctl status ceph-radosgw@rgw.mon3.service \u25cf ceph-radosgw@rgw.mon3.service - Ceph rados gateway Loaded: loaded (/usr/lib/systemd/system/ceph-radosgw@.service; enabled; vendor preset: disabled) Active: active (running) since Wed 2021-01-06 21:37:53 CST; 23s ago Main PID: 781880 (radosgw) Tasks: 588 CGroup: /system.slice/system-ceph\\x2dradosgw.slice/ceph-radosgw@rgw.mon3.service \u2514\u2500781880 /usr/bin/radosgw -f --cluster ceph --name client.rgw.mon3 --setuser ceph --setgroup ceph Jan 06 21:37:53 mon3 systemd[1]: Started Ceph rados gateway. 11). After waiting a few moments for the daemon to restart, check the status again: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 39m) mgr: mon1(active, since 30m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 6m), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.2 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr 2.4.2. Use the S3 API to Interact with the RADOS Gateway \u00b6 In this lab we used the s3cmd and radosgw-admin utilities to interact with the SUSE Enterprise Storage cluster. We created a new user, a new bucket, and a new file. We then uploaded the file to the cluster and verified that the object gateway stored it to the cluster. Task 1: Using the s3cmd tool and create an S3 user \u00b6 1). As the root user (password is linux) in a shell or terminal, verify that the s3cmd is available on the admin node: You will likely see an error about configuration files missing, etc. This is enough information to validate the utility is installed. admin:~ # pip --version pip 10.0.1 from /usr/lib/python3.6/site-packages/pip (python 3.6) admin:~ # pip install s3cmd Collecting s3cmd Downloading https://files.pythonhosted.org/packages/26/44/19e08f69b2169003f7307565f19449d997895251c6a6566ce21d5d636435/s3cmd-2.1.0-py2.py3-none-any.whl (145kB) 100% | 153kB 2.7MB/s Collecting python-magic (from s3cmd) Downloading https://files.pythonhosted.org/packages/59/77/c76dc35249df428ce2c38a3196e2b2e8f9d2f847a8ca1d4d7a3973c28601/python_magic-0.4.18-py2.py3-none-any.whl Requirement already satisfied: python-dateutil in /usr/lib/python3.6/site-packages (from s3cmd) (2.7.3) Requirement already satisfied: six>=1.5 in /usr/lib/python3.6/site-packages (from python-dateutil->s3cmd) (1.11.0) Installing collected packages: python-magic, s3cmd Successfully installed python-magic-0.4.18 s3cmd-2.1.0 2). Create a new S3 user to be used: The output will include an access_key value and a secret_key value. You will need both of those values in later steps. admin:~ # radosgw-admin user create --uid=s3user --display-name=S3 User --email=s3user@example.net { \"user_id\": \"s3user\", \"display_name\": \"S3\", \"email\": \"s3user@example.net\", \"suspended\": 0, \"max_buckets\": 1000, \"subusers\": [], \"keys\": [ { \"user\": \"s3user\", \"access_key\": , \"secret_key\": } ], \"swift_keys\": [], \"caps\": [], \"op_mask\": \"read, write, delete\", \"default_placement\": \"\", \"default_storage_class\": \"\", \"placement_tags\": [], \"bucket_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"user_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"temp_url_keys\": [], \"type\": \"rgw\", \"mfa_ids\": [] } Retrieve above information admin:~ # radosgw-admin user info --uid=s3user Task 2: Create a new s3cmd configuration file and a new S3 bucket \u00b6 1). Generate a new s3cmd configuration file from a shell on the admin node: Fill in as listed below: admin:~ # cd ~ admin:~ # s3cmd --configure Enter new values or accept defaults in brackets with Enter. Refer to user manual for detailed description of all options. Access key and Secret key are your identifiers for Amazon S3. Leave them empty for using the env variables. Access Key: Secret Key: Default Region [US]: Use \"s3.amazonaws.com\" for S3 Endpoint and not modify it to the target Amazon S3. S3 Endpoint [s3.amazonaws.com]: mon3.sha.me.corp Use \"%(bucket)s.s3.amazonaws.com\" to the target Amazon S3. \"%(bucket)s\" and \"%(location)s\" vars can be used if the target S3 system supports dns based buckets. DNS-style bucket+hostname:port template for accessing a bucket [%(bucket)s.s3.amazonaws.com]: %(bucket)s.mon3.sha.me.corp Encryption password is used to protect your files from reading by unauthorized persons while in transfer to S3 Encryption password: Path to GPG program [/usr/bin/gpg]: When using secure HTTPS protocol all communication with Amazon S3 servers is protected from 3 rd party eavesdropping. This method is slower than plain HTTP, and can only be proxied with Python 2.7 or newer Use HTTPS protocol [Yes]: No On some networks all internet access must go through a HTTP proxy. Try setting it here if you can't connect to S3 directly HTTP Proxy server name: New settings: Access Key: Secret Key: Default Region: US S3 Endpoint: mon3.sha.me.corp DNS-style bucket+hostname:port template for accessing a bucket: %(bucket)s.mon3.sha.me.corp Encryption password: Path to GPG program: /usr/bin/gpg Use HTTPS protocol: False HTTP Proxy server name: HTTP Proxy server port: 0 Test access with supplied credentials? [Y/n] n Save settings? [y/N] y Configuration saved to '/root/.s3cfg' 2). Test the configuration by checking for existing files or directories: Since no buckets or files have been made available for the user, no items are listed and the command returns you to the prompt with no output. This is normal. If there is an error, your configuration may have a typo in it. The configuration file will have been saved as .s3cfg. Edit the file to match the configuration in step one. admin:~ # s3cmd ls 3). Create a new bucket for uploading files to using the s3cmd: You should see feedback that the bucket has been created. Although not technically required by the S3 API, the bucket name needs to be in all uppercase to avoid a bug with the s3cmd tool itself. admin:~ # s3cmd mb s3://S3CMDTEST Bucket 's3://S3CMDTEST/' created admin:~ # s3cmd ls 2021-01-06 14:04 s3://S3CMDTEST (it's GMT timezone) Task3: Create and upload a file to a bucket using the S3 API \u00b6 1). Create a file with a few words of text: admin:~ # echo \"The mountains are beautiful\" > newfile 2). Put the new file into your bucket using s3cmd: You should see the file being uploaded. admin:~ # s3cmd put newfile s3://S3CMDTEST upload: 'newfile' -> 's3://S3CMDTEST/newfile' [1 of 1] 28 of 28 100% in 3s 7.66 B/s done 3). Verify the file is now in your bucket, safely stored in you SES cluster: admin:~ # s3cmd ls s3://S3CMDTEST 2021-01-06 14:11 28 s3://S3CMDTEST/newfile 2.4.3. Use the swift API to Interact with the RADOS Gateway \u00b6 OpenStack packages for SUSE Install and configure the storage nodes for openSUSE and SUSE Linux Enterprise SUSE Package Hub: python-PasteDeploy Enable SUSE Package Hub extension admin:~ # SUSEConnect -p PackageHub/15.1/x86_64 Install python3-PasteDeploy, which is dependency of python-swift installation admin:~ # zypper in python3-PasteDeploy admin:~ # rpm -ivh python3-PyECLib-1.6.0-1.6.x86_64.rpm warning: python3-PyECLib-1.6.0-1.6.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 3dbdc284: NOKEY error: Failed dependencies: python(abi) = 3.8 is needed by python3-PyECLib-1.6.0-1.6.x86_64 rpmlib(PayloadIsZstd) <= 5.4.18-1 is needed by python3-PyECLib-1.6.0-1.6.x86_64 Add OpenStack Swift Repository for SUSE admin:~ # zypper addrepo -f obs://Cloud:OpenStack:Train/SLE_15_SP1 Train admin:~ # zypper in openstack-swift openstack-swift-account openstack-swift-container openstack-swift-object Task 1: Create a swift subuser \u00b6 1). In a shell or terminal as the root user (password of linux) on the admin node, create a new subuser: The output will contain the access and secret keys for the s3user and a secret key for the new swift subuser.. admin:~ # radosgw-admin subuser create --uid=s3user --subuser=s3user:swift --access=full { \"user_id\": \"s3user\", \"display_name\": \"S3\", \"email\": \"s3user@example.net\", \"suspended\": 0, \"max_buckets\": 1000, \"subusers\": [ { \"id\": \"s3user:swift\", \"permissions\": \"full-control\" } ], \"keys\": [ { \"user\": \"s3user\", \"access_key\": , \"secret_key\": } ], \"swift_keys\": [ { \"user\": \"s3user:swift\", \"secret_key\": } ], \"caps\": [], \"op_mask\": \"read, write, delete\", \"default_placement\": \"\", \"default_storage_class\": \"\", \"placement_tags\": [], \"bucket_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"user_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"temp_url_keys\": [], \"type\": \"rgw\", \"mfa_ids\": [] } 2). Verify that the subuser has access to at least one bucket and list the buckets with a swift command: swift -A http://mon3.sha.me.corp/auth/1.0 -U s3user:swift -K '{SECRET_KEY_FROM_STEP_1}' list admin:~ # swift -A http://mon3.sha.me.corp/auth/1.0 -U s3user:swift -K '' list S3CMDTEST Task 2: Use the swift command to access a file created with the S3cmd tool \u00b6 1). Since the S3 API and the swift API are accessing the same SUSE Enterprise Storage cluster, and since the RADOS gateway is built to be inter-operable with both, you can use the swift API to retrieve the object which was uploaded to SES via the S3 API: swift -A http://mon3.example.net/auth/1.0 -U s3user:swift -K '{SECRET_KEY_FROM_STEP_1}' download -a An example of the command is listed here: admin:~ # swift -A http://mon3.sha.me.corp/auth/1.0 -U s3user:swift -K '' download -a Although we have taken a shortcut by using the -a option (meaning grab every object this user has access to), it illustrates the tool\u2019s capability. We\u2019ve uploaded the newfile with S3, we\u2019ve retrieved it with swift. 2.4.4. Create Snapshots on SES using RBD \u00b6 In this lab we worked with rbd images. We mapped an rbd image to a Linux device file, then created a filesystem and mounted it. Then we created snapshots to preserve the images data state at a particular time, and rolled it back to demonstrate functionality. Task 1: Create a new pool for RBD images \u00b6 1). Access https://mon1.pvg.me.corp:8443 or https://10.58.121.186:8443 2). Log in with the following credentials: Username: admin Password: mypassword 3). Click on the Pools tab near the top of the page 4). Click the Create button and use the following in the available fields: Name: rbd-images Pool type: replicated Placement groups: 16 Crush ruleset: replicated_rule Replicted size: 2 Applications: rbd Compression Mode: none 5). Click Create Pool Task 2: Create a new RBD image in the rbd-images pool \u00b6 6). Create a new RBD image using the rbd command: admin:~ # rbd create --size 1024 rbd-images/barfoo 7). Verify the new image has been created in the rbd-images pool: The new image named barfoo should be displayed. admin:~ # rbd ls -p rbd-images barfoo Task 3: Mount the new image on the admin node and create a filesystem \u00b6 1). As the root user in a shell or terminal on the admin node, map the new rbd image to a block device: admin:~ # rbd map rbd-images/barfoo /dev/rbd0 2). Create a filesystem on the newly mapped device: admin:~ # mkfs.ext4 /dev/rbd0 mke2fs 1.43.8 (1-Jan-2018) Discarding device blocks: done Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: 19da6b86-1989-4834-a365-2f654fcce6f6 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done 3). Mount the image to the /mnt directory: admin:~ # mount /dev/rbd0 /mnt admin:~ # l /mnt total 20 drwxr-xr-x 3 root root 4096 Jan 6 23:48 ./ drwxr-xr-x 1 root root 156 Oct 5 08:53 ../ drwx------ 2 root root 16384 Jan 6 23:48 lost+found/ Task 4: Create a file on the new filesystem and snapshot the rbd image and make some additional changes \u00b6 1). Change to the /mnt directory and create a simple file: admin:~ # cd /mnt admin:/mnt # echo \"This is some sample text\" > start.txt 2). List the directories contents to see that the start.txt file has been created on the storage cluster. admin:/mnt # ls -l total 20 drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 3). Create a snapshot of what the rbd image contained: Wait for confirmation that the snapshot has been created. It should only take a few seconds. admin:/mnt # rbd snap create rbd-images/barfoo@begin 4). List the rbd snapshots for the rbd-images/barfoo image: You should see the new snap called begin listed. admin:/mnt # rbd snap ls rbd-images/barfoo SNAPID NAME SIZE PROTECTED TIMESTAMP 4 begin 1 GiB Wed Jan 6 23:51:12 2021 5). Add another file to the filesystem: admin:/mnt # echo \"Some more text\" > end.txt 6). List the contents of the /mnt to verify the existence of two files. admin:/mnt # ls -l total 24 -rw-r--r-- 1 root root 15 Jan 6 23:52 end.txt drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 7). Create a second snapshot of the rbd-images/barfoo image: admin:/mnt # rbd snap create rbd-images/barfoo@finish 8). List the rbd snapshots: There should be begin and finish snapshots. admin:/mnt # rbd snap ls rbd-images/barfoo SNAPID NAME SIZE PROTECTED TIMESTAMP 4 begin 1 GiB Wed Jan 6 23:51:12 2021 5 finish 1 GiB Wed Jan 6 23:53:15 2021 9). List the contents of the /mnt directory again and verify the two files. 10). Rollback the data to the begin snapshot: This process will be relatively quick because the size of the image is small and we have very little data on it. admin:/mnt # rbd snap rollback rbd-images/barfoo@begin Rolling back to snapshot: 100% complete...done. 11). Change to the root user\u2019s home directory, then remount the image in order to see that the rbd image has been rolled back: admin:/mnt # cd ~ admin:~ # umount /mnt admin:~ # mount /dev/rbd0 /mnt 12). List the contents of the /mnt directory to verify that only the start.txt file exists on the image. admin:/mnt # ls -l total 20 drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 13). Rollback the data to the finish snapshot: admin:/mnt # rbd snap rollback rbd-images/barfoo@finish Rolling back to snapshot: 100% complete...done. 14). Unmount and remount the image: admin:/mnt # cd ~ admin:~ # umount /mnt admin:~ # mount /dev/rbd0 /mnt 15). List the contents of the /mnt directory to show it has indeed been rolled back and contains the start.txt and end.txt files admin:/mnt # ls -l total 24 -rw-r--r-- 1 root root 15 Jan 6 23:52 end.txt drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 16). Change to the root user\u2019s home directory and unmount the image: admin:/mnt # cd ~ admin:~ # umount /mnt 2.4.5. Create and manage COW Clones with rbd \u00b6 In this lab you will created a new pool and block device image in the pool. You then mapped the block storage to a linux device and took a snapshot. Finally you protected the snapshot from modification. This would be done so the snapshot can be safely used as a parent cow image which can then be cloned to create new virtual machines. Task 1: Create a new pool \u00b6 1). View the current osds and pools: admin:~ # ceph osd ls 0 1 2 3 4 5 6 7 8 9 10 11 admin:~ # ceph osd pool ls iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log rbd_pool bucket_pool EC_RBD_Pool default.rgw.buckets.index default.rgw.buckets.data rbd-images 2). Create a new pool called cow-pool: admin:~ # ceph osd pool create cow-pool 128 pool 'cow-pool' created 3). List the available pools to view the new pool using either of the following commands: admin:~ # ceph osd pool ls iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log rbd_pool bucket_pool EC_RBD_Pool default.rgw.buckets.index default.rgw.buckets.data rbd-images cow-pool admin:~ # rados lspools iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log rbd_pool bucket_pool EC_RBD_Pool default.rgw.buckets.index default.rgw.buckets.data rbd-images cow-pool Task 2: Create a block device image in a pool 1). Create a format 2 rbd image called cow-base in the cow-pool storage pool with a size of 1GB *Note that the \u2013image-format statement is optional as format 2 is default admin:~ # rbd create -p cow-pool cow-base --size 1024 --image-format 2 2). Check that the image has been created, that the format is 2 and that layering (COW Clones) is supported admin:~ # rbd -p cow-pool list cow-base admin:~ # rbd -p cow-pool info cow-base rbd image 'cow-base': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 269d5b817222aa block_name_prefix: rbd_data.269d5b817222aa format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:12:31 2021 access_timestamp: Thu Jan 7 10:12:31 2021 modify_timestamp: Thu Jan 7 10:12:31 2021 Task 3: Map the block storage image to a Linux host 1). In a shell or terminal as user root open a terminal window. Using the rbd map command, map an rbd device to the block-storage image created above. admin:~ # rbd map -p cow-pool --image cow-base /dev/rbd1 2). View the mapped block devices admin:~ # rbd showmapped id pool namespace image snap device 0 rbd-images barfoo - /dev/rbd0 1 cow-pool cow-base - /dev/rbd1 3). Note the rbd index numbgr (e.g. rbd0, rbd1) associated with the cow-base image: RBD ___1____ 4). View the devices in /dev. Note the device name(s) admin:~ # ls -l /dev/rbd* brw-rw---- 1 root disk 252, 0 Jan 6 23:49 /dev/rbd0 brw-rw---- 1 root disk 252, 16 Jan 7 10:14 /dev/rbd1 /dev/rbd: total 0 drwxr-xr-x 2 root root 60 Jan 7 10:14 cow-pool drwxr-xr-x 2 root root 60 Jan 6 23:48 rbd-images 5). View the block device:(use the device numbgr from step above) admin:~ # fdisk -l /dev/rbd1 Disk /dev/rbd1: 1 GiB, 1073741824 bytes, 2097152 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 4194304 bytes / 4194304 bytes 6). Format the device with an ext4 filesystem: admin:~ # mkfs.ext4 /dev/rbd1 mke2fs 1.43.8 (1-Jan-2018) Discarding device blocks: done Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: 64c9a973-cf31-4239-881f-ec5642bf34e3 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done 7). Mount the block device on the local filesystem: admin:~ # mkdir /mnt/cow-base admin:~ # mount /dev/rbd1 /mnt/cow-base 8). Test the storage access by creating a file: admin:~ # cd /mnt/cow-base admin:/mnt/cow-base # touch base-image-file admin:/mnt/cow-base # ls base-image-file lost+found Task 4: Snapshot the rbd image and protect the snapshot \u00b6 1). List the snapshots in the cow-base image: admin:/mnt/cow-base # rbd snap ls cow-pool/cow-base 2). Create a snapshot of the cow-base rbd image which contains the base-image-file file admin:/mnt/cow-base # rbd snap create cow-pool/cow-base@base-snap 3). List the snapshot: admin:/mnt/cow-base # rbd snap ls cow-pool/cow-base SNAPID NAME SIZE PROTECTED TIMESTAMP 4 base-snap 1 GiB Thu Jan 7 10:37:13 2021 4). This snapshot will form the parent snapshot for COW clone images so you will now protected it from modification: admin:/mnt/cow-base # rbd snap protect cow-pool/cow-base@base-snap admin:/mnt/cow-base # rbd snap ls cow-pool/cow-base SNAPID NAME SIZE PROTECTED TIMESTAMP 4 base-snap 1 GiB yes Thu Jan 7 10:37:13 2021 Task 5: Create writable COW clones from the parent snapshot 1). Create a COW clone from the cow-base with the base-snap snapshot as the parent image admin:/mnt/cow-base # rbd clone cow-pool/cow-base@base-snap cow-pool/cow-image1 2). Check the information for the new image admin:/mnt/cow-base # rbd -p cow-pool --image cow-image1 info rbd image 'cow-image1': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a1209678cad4 block_name_prefix: rbd_data.26a1209678cad4 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:38:58 2021 access_timestamp: Thu Jan 7 10:38:58 2021 modify_timestamp: Thu Jan 7 10:38:58 2021 parent: cow-pool/cow-base@base-snap overlap: 1 GiB 3). Note that the image has details of the parent image and overlap 4). Repeat steps 2 & 3 for an additional image called cow-image2 admin:/mnt/cow-base # rbd clone cow-pool/cow-base@base-snap cow-pool/cow-image2 admin:/mnt/cow-base # rbd -p cow-pool --image cow-image2 info rbd image 'cow-image2': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a2fbcec7b8d9 block_name_prefix: rbd_data.26a2fbcec7b8d9 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:47:28 2021 access_timestamp: Thu Jan 7 10:47:28 2021 modify_timestamp: Thu Jan 7 10:47:28 2021 parent: cow-pool/cow-base@base-snap overlap: 1 GiB Task 6: Test that the COW clones are functional 1). Create a new directory and mount the COW clone called cow-image1 Note the rbd device name and use it to mount the file system admin:/mnt # mkdir /mnt/cow-image1 admin:/mnt # rbd map -p cow-pool --image cow-image1 /dev/rbd2 admin:/mnt # l total 4 drwxr-xr-x 1 root root 36 Jan 7 10:54 ./ drwxr-xr-x 1 root root 156 Oct 5 08:53 ../ drwxr-xr-x 3 root root 4096 Jan 7 10:19 cow-base/ drwxr-xr-x 1 root root 0 Jan 7 10:54 cow-image1/ admin:/mnt # ls -l /dev/rbd* brw-rw---- 1 root disk 252, 0 Jan 6 23:49 /dev/rbd0 brw-rw---- 1 root disk 252, 16 Jan 7 10:18 /dev/rbd1 brw-rw---- 1 root disk 252, 32 Jan 7 10:55 /dev/rbd2 /dev/rbd: total 0 drwxr-xr-x 2 root root 80 Jan 7 10:55 cow-pool drwxr-xr-x 2 root root 60 Jan 6 23:48 rbd-images admin:/mnt # mount /dev/rbd2 /mnt/cow-image1 2). Check that the base-image-file which was created in the parent snapshot is present admin:/mnt # cd /mnt/cow-image1 admin:/mnt/cow-image1 # ls base-image-file lost+found 3). Repeat steps 1 and 2 for cow-image2 admin:/mnt # mkdir /mnt/cow-image2 admin:/mnt # rbd map -p cow-pool --image cow-image2 /dev/rbd3 admin:/mnt # mount /dev/rbd3 /mnt/cow-image2 admin:/mnt # ls ./cow-image2/ base-image-file lost+found --> same file with image1 4). Create a new file in the directory where cow-image1 is mounted admin:/mnt # cd cow-image1 admin:/mnt/cow-image1 # touch additional-file admin:/mnt/cow-image1 # ls additional-file base-image-file lost+found 5). Look in the cow-image2 directory. Although they share the same parent snapshot, you can see that the files contained in each COW image are now different. admin:/mnt # ls ./cow-image2/ base-image-file lost+found Task 7: Flatten a COW Clone and remove the parent image \u00b6 1). Convert the COW clone called cow-image1 to a standalone rbd image Wait while the flatten process completes. Unlike a clone process this is not instantaneous and can take considerable time. admin:/mnt # rbd flatten cow-pool/cow-image1 Image flatten: 100% complete...done. 2). Check to see that the flatten process has removed the link to the parent snapshot admin:/mnt # rbd -p cow-pool --image cow-image1 info rbd image 'cow-image1': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a1209678cad4 block_name_prefix: rbd_data.26a1209678cad4 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:38:58 2021 access_timestamp: Thu Jan 7 10:38:58 2021 modify_timestamp: Thu Jan 7 10:38:58 2021 admin:/mnt # rbd -p cow-pool --image cow-image2 info rbd image 'cow-image2': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a2fbcec7b8d9 block_name_prefix: rbd_data.26a2fbcec7b8d9 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:47:28 2021 access_timestamp: Thu Jan 7 10:47:28 2021 modify_timestamp: Thu Jan 7 10:47:28 2021 parent: cow-pool/cow-base@base-snap overlap: 1 GiB 3). Unmount the images admin:/mnt # umount /mnt/cow-image1 admin:/mnt # umount /mnt/cow-image2 admin:/mnt # umount /mnt/cow-base 2.4.6. Configure iSCSI on SES \u00b6 In this lab an iSCSI Target was configured via the iSCSI gateway on our SUSE Enterprise Storage. An image was added to it. An iSCSI initiator then connected to the target, created a filesystem, and mounted it. Task 1: Create a new RBD image in the iscsi-images pool \u00b6 1). Create a new RBD image using the rbd command: admin:~ # rbd create --size 1024 iscsi-images/fooiscsi 2). Verify the new image has been created in the iscsi-images pool: The new image named fooiscsi should be displayed. admin:~ # rbd ls iscsi-images fooiscsi Task 2: Define a new iSCSI target with the Ceph Dashboard \u00b6 1). Access the Ceph Dashboard and log in: https://mon1.pvg.me.corp:8443 or https://10.58.121.186:8443 Username: admin Password: mypassword 2). Once logged in, click on the Block drop-down item near the top. Select iSCSI. 3). With the Overview tab showing for iSCSI, click on the Targets tab near the top. Note: When clicking on the Targets tab, if you see an error that says something about \u201cUnsupported `ceph-iscsi` config version\u2026\u201d, perform the following steps: 1. Close the browser window where the error occurred 2. Restart the mon1 virtual machine. Do this with the following steps: from the Virtual Machine Manager on your lab machine (not in the admin virtual machine), restart the mon1 virtual machine by right-clicking on the mon1 virtual machine > Shut Down > Reboot 3. Wait at least 30 seconds, then from the admin node, open up the browser again and log in to the Ceph Dashboard: https://mon1.pvg.me.corp:8443 or https://10.58.121.186:8443 Username: admin Password: mypassword 4. Continue the lab as directed below by navigating to the Block > iSCSI section, clicking on the Targets tab, and completing the steps below 4). Click Add. Use the following values: Target IQN: Portals: mon2.example.net:172.17.6.132 Images: iscsi-images/fooiscsi ACL authentication: Click Create Target. Task 3: Access the new iSCSI target from the admin node \u00b6 1). On the admin node, launch YaST either the ncurses or GUI interface, and select the iSCSI Initiator module: YaST > Network Services > iSCSI Initiator 2). Select the Discovered Targets tab (alt-v) 3). Select Discovery at the bottom of the frame (alt-d) 4). Add the ip address of mon2: 10.58.121.187. Leave the port as the default of 3260. Select Next. 5). Once again on the Discovered Targets tab, the mon2 target should be listed. With the new target highlighted, select Connect (alt-e) at the bottom of the frame. 6). Leave the Startup (in YaST2) or On boot (in YaST) value as manual. Select Next. 7). Select OK to exit the iscsi client configuration module 8). To verify that the iscsi device is now connected, use the lsscsi command to list devices: You should see there is one disk of type RBD connected on a device file similar to the following: admin:~ # lsscsi [0:0:0:0] cd/dvd QEMU QEMU DVD-ROM 1.4. /dev/sr0 [2:0:0:0] disk SUSE RBD 4.0 /dev/sda 9). Create an ext4 filesystem on the connected device file: admin:~ # mkfs.ext4 /dev/sda mke2fs 1.43.8 (1-Jan-2018) Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: e3896f7e-0664-4b14-85db-0f77cb234c43 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done 10). Mount the device to /mnt: admin:~ # mount /dev/sda /mnt 11). Use the mount command to list the connected device: admin:/mnt # mount | grep sda /dev/sda on /mnt type ext4 (rw,relatime,stripe=1024,data=ordered) 12).Change the root user\u2019s home directory and unmount the device: admin:/mnt # cd .. admin:/ # umount /mnt 2.4.7. Mount CephFS Provided by SUSE Enterprise Storage \u00b6 In this lab a ceph user was configured to mount the ceph filesystem provided by the SUSE Enterprise Cluster. A keyfile was generated, then used in the process. Task 1: Verify cephfs configuration of the SES cluster \u00b6 1). Cephfs requires two pools for operation: one for data, the other for metadata. Verify that the cluster has two pools for this purpose: admin:~ # ceph fs ls name: cephfs, metadata pool: cephfs_metadata, data pools: [cephfs_data ] Task 2: Create a secret key file for the admin user on the admin node 1). Because cephx authentication is enabled by default on SUSE Enterprise Storage, a secret key will need to be provided to allow access to mount the ceph filesystem. The admin user (identified \u2013 in this case \u2013 on the system as root) on the admin node has a key, but we will need to either provide it on the command line during the mount process (less secure), or put it in a permissions-restricted file and point to the file when mounting (more secure). If we do not specify the key or a file with the key, we will get an error. The following command will return an error: admin:~ # mount -t ceph mon1:6789:/ /mnt 2021-01-07 14:16:36.924 7f45108a9d80 -1 auth: unable to find a keyring on /etc/ceph/ceph.client.guest.keyring,/etc/ceph/ceph.keyring,/etc/ceph/keyring,/etc/ceph/keyring.bin,: (2) No such file or directory mount error 22 = Invalid argument 2). Take secret key value found in the /etc/ceph/ceph.client.admin.keyring file and put it in a new file: admin:~ # cat /etc/ceph/ceph.client.admin.keyring [client.admin] key = caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" 3). Create a new file and paste the secret key value into it: admin:~ # vi /etc/ceph/admin.secret Put the key value into the file and save it. 4). Change the permissions of the file to be read only by the user: admin:~ # ls -l /etc/ceph/admin.secret -r-------- 1 root root 41 Jan 5 20:05 /etc/ceph/admin.secret Task 3: Mount the ceph filesystem on the admin node \u00b6 1). Now that the keyfile is created, we can mount the filesystem: admin:~ # mount -t ceph mon1:6789:/ /mnt -o name=admin,secretfile=/etc/ceph/admin.secret admin:~ # ls -l /mnt total 0 2). Verify that the mount shows as expected: admin:~ # mount | grep ceph 10.58.121.186:6789:/ on /mnt type ceph (rw,relatime,name=admin,secret=,acl) 3). Change to the root user\u2019s home directory and unmount the filesystem: admin:~ # cd ~ admin:~ # umount /mnt 2.4.8. Export an NFS Share from SES with NFS Ganesha \u00b6 Task 0: Install and configure Ganesha (Ganesha config location is not configured. Please set the GANESHA_RADOS_POOL_NAMESPACE setting.) \u00b6 admin:~ # zypper in nfs-ganesha admin:/etc/ganesha # cat ganesha.conf NFSv4 { RecoveryBackend = 'rados_cluster'; #RecoveryBackend = 'rados_ng'; } RADOS_URLS { ceph_conf = '/etc/ceph/ceph.conf'; userid = \"admin\"; watch_url = \"rados://data/ganesha-export-index/conf-nfs1\"; } RADOS_KV { pool = \"metadata\"; namespace = \"ganesha-grace\"; nodeid = \"nfs1\"; } %url rados://data/ganesha-export-index/conf-nfs1 admin:/etc/ganesha # ganesha-rados-grace -p metadata -n ganesha-grace add nfs1 nfs2 nfs3 admin:/etc/ganesha # ganesha-rados-grace -p metadata -n ganesha-grace cur=1 rec=0 ====================================================== nfs1 E nfs2 E nfs3 E http://images.45drives.com/ceph/cephfs/nfs-ganesha-ceph.conf Task 1: Create an NFS export using the Ceph Dashboard \u00b6 1). In a browser, navigate to a monitor to access the Ceph Dashboard and log in: https://10.58.121.186:8443/ Username: admin Password: mypassword 2). Click on the NFS tab near the top of the page 3). Click on the green Add button 4). Click on the Add daemon button to the right and select mon1 5). Complete the configuration with the following values: Storage Backend: Object Gateway Object Storage User: s3user Path: S3CMDTEST NFS Protocol: NFSv3 and NFSv4 checked NFS Tag: Pseudo: /S3BKT Access Type: RW Squash: root_squash Transport Protocol: UDP and TCP checked Clients: Click Submit Task 2: Mount the NFS export on the admin node \u00b6 1). As the root user on the admin node, query the NFS Ganesha gateway node to see what mounts are available: showmount -e mon1 You should see something similar to the following: Export list for mon1: S3CMDTEST (everyone) 2). Mount the available nfs share to the /mnt directory on the admin server: mount -t nfs mon1:/S3BKT /mnt 3). List the nfs mount: mount | grep mnt Note the type listed as nfs4 4). Change to the root user\u2019s home directory and unmount the export: cd umount /mnt 2.4.9. Configure and Mount CIFS \u00b6 In this lab the Samba gateway was configured. A keyring for the Samba gateway was created, the Samba service was modified, and a user created to allow CIFS access to the SES cluster. Task 1: Prepare the CephFS share for CIFS \u00b6 1). In order for CIFS to work in our SES environment, a valid CephFS share must be available. The CephFS lab previously done in this workbook is sufficient. Using the same configuration that we used previously, mount the CephFS share and give permissions to all users at the root of the share: admin:~ # mount -t ceph mon1:6789:/ /mnt -o name=admin,secretfile=/etc/ceph/admin.secret admin:~ # chmod 777 /mnt admin:~ # l /mnt total 0 drwxrwxrwx 2 root root 0 Oct 5 14:30 ./ drwxr-xr-x 1 root root 156 Oct 5 08:53 ../ admin:~ # umount /mnt Task 2: Create a Samba gateway specific keyring on the Ceph admin node and copy it to the Samba gateway node \u00b6 1). A new keyring will be needed for the Samba gateway to allow access to the Ceph cluster. As root, perform the following: admin:~ # ceph auth get-or-create client.samba.gw mon 'allow r' osd 'allow *' mds 'allow *' -o ceph.client.samba.gw.keyring 2). Copy the new keyring to the Samba gateway node: admin:~ # scp ceph.client.samba.gw.keyring mon1:/etc/ceph/ ceph.client.samba.gw.keyring admin:~ # ssh mon1 Last login: Thu Jan 7 14:35:58 2021 from 10.58.121.181 mon1:~ # ls -l /etc/ceph/ total 12 -rw-r--r-- 1 root root 66 Jan 7 15:15 ceph.client.samba.gw.keyring -rw-r--r-- 1 root root 1095 Jan 5 22:44 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap Task 3: Configure Samba on the Samba gateway node \u00b6 1). The /etc/samba/smb.conf file will need to be edited to allow CIFS access to the storage cluster. On the mon1 node, replace all of the contents of the file with the following: admin:~ # ssh mon1 mon1:~ # vi /etc/samba/smb.conf mon1:/etc/samba # cat smb.conf [global] netbios name = SAMBA-GW clustering = no idmap config * : backend = tdb2 passdb backend = tdbsam # disable print server load printers = no smbd: backgroundqueue = no [ceph-smb] path = / vfs objects = ceph ceph: config_file = /etc/ceph/ceph.conf ceph: user_id = samba.gw read only = no oplocks = no kernel share modes = no 2). Create a smb user on the mon1 node named joesmb with a password of mypassword: mon1:/etc/samba # useradd joesmb mon1:/etc/samba # passwd joesmb ---> 123 Add joesmb to the smb password database with a password of mypassword: mon1:/etc/samba # smbpasswd -a joesmb New SMB password: ---> 123 Retype new SMB password: ---> 123 Added user joesmb. 3). Start and enable the smb and nmb daemons on mon1: mon1:/etc/samba # systemctl start smb nmb mon1:/etc/samba # systemctl enable smb nmb Created symlink /etc/systemd/system/multi-user.target.wants/smb.service \u2192 /usr/lib/systemd/system/smb.service. Created symlink /etc/systemd/system/multi-user.target.wants/nmb.service \u2192 /usr/lib/systemd/system/nmb.service. 4). Unmount the filesystem: mon1:~ # umount /mnt umount: /mnt: not mounted. Task 4: Connect a client to the Samba gateway \u00b6 1). On the admin node, verify that the Samba gateway is sharing via CIFS. The password is 123 admin:~ # smbclient -U joesmb -L //mon1 Enter WORKGROUP\\joesmb's password: ---> 123 Sharename Type Comment --------- ---- ------- ceph-smb Disk IPC$ IPC IPC Service (Samba 4.9.5-git.373.26895a83dbf3.44.1-SUSE-oS15.0-x86_64) Reconnecting with SMB1 for workgroup listing. Server Comment --------- ------- Workgroup Master --------- ------- GLOBAL CNPVGVSYB900 WORKGROUP SAMBA-GW 2). Connect to the ceph-smb share as joesmb. The password is 123 admin:~ # smbclient -U joesmb //mon1/ceph-smb Enter WORKGROUP\\joesmb's password: ---> 123 tree connect failed: NT_STATUS_BAD_NETWORK_NAME You should see output similar to the following: Try \u201chelp\u201d to get a list of possible commands. smb: \\>","title":"SUSE Enterprise Storage Basic Operation"},{"location":"linux/SES/linux_ses_demo/#suse-enterprise-storage-6-installation-and-basic-operation","text":"","title":"SUSE Enterprise Storage 6 Installation and Basic Operation"},{"location":"linux/SES/linux_ses_demo/#1-installation","text":"","title":"1. Installation"},{"location":"linux/SES/linux_ses_demo/#11-environment-setup","text":"In this demo, I use below environment, including VM setting and software installed. All VMs installed here was built on a physical host 10.58.121.68 . Host Server: 10.58.121.68 root / rootroot Account root / root123 Gateway: 10.58.120.1 Network Mask: 255.255.254.0 Nameserver: 10.58.32.32 10.33.50.20 Domain Search sha.me.corp dhcp.sha.me.corp me.corp ind.me.corp bgr.me.corp SUSE Server 15 SP1 Extensions and Modules were installed as below. [x] SUSE Enterprise Storage 6 [x] Basesystem Module 15 SP1 x86_64 [x] Server Applications Module 15 SP1 x86_64 Disable Services is as below: AppArmor Firewall Enable Services is as below. SSH Register SLES15.1 to local SMT. # SUSEConnect --url https://smtproxy.ind.me.corp Demo Environment summary is below. Alias Host Name Memory Disk eth0 eth0 mac address sles01 admin (salt-master) 16GB Disk1: 20G 10.58.121.181/23 52:54:00:23:7d:cd sles02 data1 16GB Disk1: 20G 10.58.121.182/23 52:54:00:5f:ce:6f Disk2: 8G Disk3: 8G Disk4: 8G sles03 data2 16GB Disk1: 20G 10.58.121.183/23 52:54:00:6f:f2:23 Disk2: 8G Disk3: 8G Disk4: 8G sles04 data3 16GB Disk1: 20G 10.58.121.184/23 52:54:00:93:4c:67 Disk2: 8G Disk3: 8G Disk4: 8G sles05 data4 16GB Disk1: 20G 10.58.121.185/23 52:54:00:90:b0:b0 Disk2: 8G Disk3: 8G Disk4: 8G sles06 mon1 16GB Disk1: 20G 10.58.121.186/23 52:54:00:46:43:7a sles07 mon2 16GB Disk1: 20G 10.58.121.187/23 52:54:00:00:fe:6b sles08 mon3 16GB Disk1: 20G 10.58.121.188/23 52:54:00:60:a3:92 Add hostname to file /etc/hosts (all nodes) If you do not specify a cluster network during Ceph deployment, it assumes a single public network environment. Make sure that the fully qualified domain name (FQDN) of each node can be resolved to the public network IP address by all other nodes. # vi /etc/hosts 10.58.121.181 admin.sha.me.corp admin salt 10.58.121.182 data1.sha.me.corp data1 10.58.121.183 data2.sha.me.corp data2 10.58.121.184 data3.sha.me.corp data3 10.58.121.185 data4.sha.me.corp data4 10.58.121.186 mon1.sha.me.corp mon1 10.58.121.187 mon2.sha.me.corp mon2 10.58.121.188 mon3.sha.me.corp mon3 Add all nodes as trust ssh access (root account) # cd ~ # ssh-keygen -t rsa # ssh-copy-id -i ~/.ssh/id_rsa.pub root@admin # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data1 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data2 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data3 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@data4 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@mon1 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@mon2 # ssh-copy-id -i ~/.ssh/id_rsa.pub root@mon3 # ssh admin.sha.me.corp # ssh data1.sha.me.corp # ssh data2.sha.me.corp # ssh data3.sha.me.corp # ssh data4.sha.me.corp # ssh mon1.sha.me.corp # ssh mon2.sha.me.corp # ssh mon3.sha.me.corp # ssh salt # ssh admin # ssh data1 # ssh data2 # ssh data3 # ssh data4 # ssh mon1 # ssh mon2 # ssh mon3 Disable firewall (all nodes) # sudo /sbin/SuSEfirewall2 off # firewall-cmd --state not running # systemctl stop firewalld.service # systemctl status firewalld.service firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: disabled) Active: inactive (dead) Docs: man:firewalld(1) Disable IPv6 (all nodes) and Set kernel pid to max value (all nodes) # vi /etc/sysctl.conf net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 net.ipv6.conf.lo.disable_ipv6 = 1 kernel.pid_max = 4194303 # sysctl -p Set DEV_ENV=true in /etc/profile.local in all nodes Install basic software (all nodes) # zypper in -y -t pattern yast2_basis base # zypper in -y net-tools vim man sudo tuned irqbalance # zypper in -y ethtool rsyslog iputils less supportutils-plugin-ses # zypper in -y net-tools-deprecated tree wget Configure NTP service (all nodes), Setting via YaST2 and add server cn.pool.ntp.,org . And /etc/chrony.conf file looks like below. admin:~ # cat /etc/chrony.conf # Use public servers from the pool.ntp.org project. pool cn.pool.ntp.org iburst ! pool pool.ntp.org iburst # Record the rate at which the system clock gains/losses time. driftfile /var/lib/chrony/drift # Allow the system clock to be stepped in the first three updates # if its offset is larger than 1 second. makestep 1.0 3 # Enable kernel synchronization of the real-time clock (RTC). rtcsync # Enable hardware timestamping on all interfaces that support it. #hwtimestamp * # Increase the minimum numbgr of selectable sources required to adjust # the system clock. #minsources 2 # Allow NTP client access from local network. #allow 192.168.0.0/16 # Serve time even if not synchronized to a time source. #local stratum 10 # Specify file containing keys for NTP authentication. #keyfile /etc/chrony.keys # Get TAI-UTC offset and leap seconds from the system tz database. #leapsectz right/UTC # Specify directory for log files. logdir /var/log/chrony # Select which information is logged. #log measurements statistics tracking # Also include any directives found in configuration files in /etc/chrony.d include /etc/chrony.d/*.conf Make /etc/chrony.conf effective. # systemctl enable chronyd.service # systemctl restart chronyd.service # systemctl status chronyd.service # chronyc sources","title":"1.1. Environment Setup"},{"location":"linux/SES/linux_ses_demo/#12-install-packages","text":"Install salt-minion on all nodes. And start the service. Hostname is in file `/etc/salt/minion_id` # zypper in -y salt-minion Uncomment below to let all nodes know who is master # vi /etc/salt/minion master: salt # systemctl enable salt-minion.service # systemctl start salt-minion.service # systemctl status salt-minion.service Install Ceph in admin node. Check log in /var/log/salt admin:~ # zypper in -y salt-master admin:~ # systemctl enable salt-master.service admin:~ # systemctl start salt-master.service admin:~ # systemctl status salt-master.service Note: ganesha will be installed on mon1, not admin node. admin:~ # zypper se ganesha admin:~ # zypper in nfs-ganesha admin:~ # systemctl enable nfs-ganesha admin:~ # systemctl start nfs-ganesha admin:~ # systemctl status nfs-ganesha admin:~ # cd /var/log/salt List fingerprints of all unaccepted minion keys on the Salt master. admin:~ # salt-key -F Local Keys: master.pem: c0:e5:***:04:c7 master.pub: 43:73:***:6a:34 Unaccepted Keys: admin.sha.me.corp: fe:51:***:b9:48 mon1.sha.me.corp: 94:13:***:91:63 mon2.sha.me.corp: c0:fd:***:39:3f mon3.sha.me.corp: 38:fc:***:2e:05 data1.sha.me.corp: b6:6c:***:63:4f data2.sha.me.corp: ab:14:***:c8:ac data3.sha.me.corp: 90:3f:***:76:3b data4.sha.me.corp: d8:12:***:f1:20 If the minions' fingerprints match, accept them admin:~ # salt-key --accept-all The following keys are going to be accepted: Unaccepted Keys: admin.sha.me.corp mon1.sha.me.corp mon2.sha.me.corp mon3.sha.me.corp data1.sha.me.corp data2.sha.me.corp data3.sha.me.corp data4.sha.me.corp Proceed? [n/Y] Y Key for minion admin.sha.me.corp accepted. Key for minion mon1.sha.me.corp accepted. Key for minion mon2.sha.me.corp accepted. Key for minion mon3.sha.me.corp accepted. Key for minion data1.sha.me.corp accepted. Key for minion data2.sha.me.corp accepted. Key for minion data3.sha.me.corp accepted. Key for minion data4.sha.me.corp accepted. Verify that the keys have been accepted admin:~ # salt-key -F admin:~ # salt-key --list-all Accepted Keys: admin.sha.me.corp data1.sha.me.corp data2.sha.me.corp data3.sha.me.corp data4.sha.me.corp mon1.sha.me.corp mon2.sha.me.corp mon3.sha.me.corp Denied Keys: Unaccepted Keys: Rejected Keys: Zero out all drivers which will be used as OSDs (optional) data1:~ lsblk data1:~ # for I in {b,c,d}; do dd if=/dev/zero of=dev/sd$i bs=512 count=40 oflag=direct; done data2:~ # for I in {b,c,d}; do dd if=/dev/zero of=dev/sd$i bs=512 count=40 oflag=direct; done data3:~ # for I in {b,c,d}; do dd if=/dev/zero of=dev/sd$i bs=512 count=40 oflag=direct; done Install DeepSea admin:~ # zypper in -y deepsea Edit the /srv/pillar/ceph/deepsea_minions.sls file on the Salt master (admin node) and add or replace the following line: admin:~ # vi /srv/pillar/ceph/deepsea_minions.sls # Choose minions with a deepsea grain deepsea_minions: 'G@deepsea:*' #Match all Salt minions in the cluster # Choose all minions # deepsea_minions: '*' #Match all minions with the 'deepsea' grain # Choose custom Salt targeting # deepsea_minions: 'ses*' # deepsea_minions: 'ceph* or salt' Target the Minions Affirm salt-master (admin node) can communicate with the minions. And deploy the grains from admin node to all minions. admin:~ # salt '*' test.ping mon1.sha.me.corp: True data4.sha.me.corp: True data3.sha.me.corp: True data2.sha.me.corp: True data1.sha.me.corp: True mon3.sha.me.corp: True admin.sha.me.corp: True mon2.sha.me.corp: True Apply the 'deepsea' grain to a group of minions, and target with a DeepSea Grain admin:~ # salt '*' grains.append deepsea default data3.sha.me.corp: The val default was already in the list deepsea mon2.sha.me.corp: The val default was already in the list deepsea data1.sha.me.corp: The val default was already in the list deepsea data4.sha.me.corp: The val default was already in the list deepsea data2.sha.me.corp: The val default was already in the list deepsea mon3.sha.me.corp: The val default was already in the list deepsea admin.sha.me.corp: The val default was already in the list deepsea mon1.sha.me.corp: The val default was already in the list deepsea admin:~ # salt -G 'deepsea:*' test.ping (The following command is an equivalent) admin:~ # salt -C 'G@deepsea:*' test.ping admin.sha.me.corp: True data3.sha.me.corp: True mon1.sha.me.corp: True mon2.sha.me.corp: True data2.sha.me.corp: True data4.sha.me.corp: True mon3.sha.me.corp: True data1.sha.me.corp: True","title":"1.2. Install Packages"},{"location":"linux/SES/linux_ses_demo/#13-stage-0-the-preparation","text":"Run Stage 0\u2014the preparation During this stage, all required updates are applied and your system may be rebooted. If there are errors, re-run the stage. admin:~ # deepsea stage run ceph.stage.0 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.0 admin:~ # salt-run state.orch ceph.stage.prep Run Stage 1\u2014the discovery Here all hardware in your cluster is being detected and necessary information for the Ceph configuration is being collected. The discovery stage collects data from all minions and creates configuration fragments that are stored in the directory /srv/pillar/ceph/proposals . The data are stored in the YAML format in *.sls or *.yml files admin:~ # deepsea stage run ceph.stage.1 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.1 admin:~ # salt-run state.orch ceph.stage.discovery","title":"1.3. Stage 0 \u2014 the preparation"},{"location":"linux/SES/linux_ses_demo/#14-stage-2-the-configuration","text":"Run Stage 2 \u2014 the configuration \u2014 you need to prepare configuration data in a particular format. The assignment follows this pattern: role-ROLE_NAME/PATH/FILES_TO_INCLUDE (NOTE, the parent directory of PATH is /srv/pillar/ceph/ ) To avoid trouble with performance and the upgrade procedure, do not deploy the Ceph OSD, Metadata Server, or Ceph Monitor role to the Admin Node. Monitors, Metadata Server, and gateways can be co-located on the OSD nodes. If you are using CephFS, S3/Swift, iSCSI, at least two instances of the respective roles (Metadata Server, Object Gateway, iSCSI) are required for redundancy and availability. admin:~ # cp /usr/share/doc/packages/deepsea/examples/policy.cfg-rolebased /srv/pillar/ceph/proposals/policy.cfg admin:~ # vi /srv/pillar/ceph/proposals/policy.cfg ## Cluster Assignment # Add all nodes into Ceph cluster cluster-ceph/cluster/*.sls ## Roles # The Admin node fills the \u201cmaster\u201d and \u201cadmin\u201d roles for DeepSea # The master role is mandatory, always add a similar line to the following role-master/cluster/admin*.sls role-admin/cluster/admin*.sls # Monitoring # Cluster monitoring and data graphs, most commonly they run on Admin node # NFS Ganesha is configured via the file /etc/ganesha/ganesha.conf # As additional configuration is required to install NFS Ganesha, you can install NFS Ganesha later. # The following requirements need to be met before DeepSea stages 2 and 4 can be executed to install NFS Ganesha: # a)At least one node needs to be assigned the role-ganesha. # b)You can define only one role-ganesha per minion. # c)NFS Ganesha needs either an Object Gateway or CephFS to work, otherwise the validation will fail in Stage 3. # d)The kernel based NFS needs to be disabled on minions with the role-ganesha role. role-prometheus/cluster/admin*.sls role-grafana/cluster/mon1*.sls # MON # The minion will provide the monitor service to the Ceph cluster role-mon/cluster/mon*.sls # MGR # The Ceph manager daemon which collects all the state information from the whole cluster # Deploy it on all minions where you plan to deploy the Ceph monitor role role-mgr/cluster/mon1*.sls # MDS # The minion will provide the metadata service to support CephFS role-mds/cluster/mon*.sls # IGW # The minion will act as an iSCSI Gateway role-igw/cluster/mon2*.sls # RGW # The minion will act as an Object Gateway role-rgw/cluster/mon3*.sls # Storage # Use this role to specify storage nodes # It points to data1~4 nodes with a wildcard. role-storage/cluster/data*.sls # COMMON # It includes configuration files generated during the discovery (Stage 1) # Accept the default values for common configuration parameters such as fsid and public_network config/stack/default/global.yml config/stack/default/ceph/cluster.yml admin:~ # deepsea stage run ceph.stage.2 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.2 admin:~ # salt-run state.orch ceph.stage.configure After the command succeeds, run below command to view the pillar data for the specified minions admin:~ # salt 'mon*' pillar.items admin:~ # salt '*' saltutil.pillar_refresh Check time server (admin node) (the directory /srv/pillar/ceph/stack was initialized after deepsea installed, but global.yml file was not created yet until stage 2) By default, DeepSea uses the Admin Node as the time server for other cluster nodes. admin:~ # cat /srv/pillar/ceph/stack/default/global.yml (this file will be generated after stage 2) monitoring: prometheus: metric_relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] rule_files: [] scrape_interval: ceph: 10s grafana: 10s node_exporter: 10s prometheus: 10s target_partition: ceph: 1/1 grafana: 1/1 node_exporter: 1/1 prometheus: 1/1 time_server: admin.sha.me.corp Verify network (the directory /srv/pillar/ceph/stack was initialized after deepsea installed, but cluster.yml file was not created until stage 2 ) admin:~ # cat /srv/pillar/ceph/stack/ceph/cluster.yml --nothing admin:~ # cat /srv/pillar/ceph/stack/default/ceph/cluster.yml available_roles: - storage - admin - mon - mds - mgr - igw - grafana - prometheus - storage - rgw - ganesha - client-cephfs - client-radosgw - client-iscsi - client-nfs - benchmark-rbd - benchmark-blockdev - benchmark-fs - master cluster_network: 10.58.120.0/23 fsid: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 public_network: 10.58.120.0/23 Note: customized file will overwrite default one. Default file: /srv/pillar/ceph/stack/default/ceph/cluster.yml Customized file: /srv/pillar/ceph/stack/ceph/cluster.yml Check DriveGroup DriveGroups specify the layouts of OSDs in the Ceph cluster. They are defined in a single file /srv/salt/ceph/configuration/files/drive_groups.yml admin:~ # cat /srv/salt/ceph/configuration/files/drive_groups.yml default_drive_group_name: target: 'data*' <--original: 'I@role:storage' data_devices: all: true admin:~ # salt 'data*' pillar.items | grep -B5 stroage","title":"1.4. Stage 2 \u2014 the configuration"},{"location":"linux/SES/linux_ses_demo/#15-stage-3-the-deployment","text":"Run Stage 3 \u2014 the deployment \u2014 creates a basic Ceph cluster with mandatory Ceph services. This Deployment stage has more than 60 automated steps. Be patient and make sure the stage completes successfully before proceeding. Set dev environment and disable subvolume: admin:~ # vi /srv/pillar/ceph/stack/global.yml admin:~ # vi /srv/pillar/ceph/stack/default/global.yml monitoring: prometheus: metric_relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] relabel_config: ceph: [] grafana: [] node_exporter: [] prometheus: [] rule_files: [] scrape_interval: ceph: 10s grafana: 10s node_exporter: 10s prometheus: 10s target_partition: ceph: 1/1 grafana: 1/1 node_exporter: 1/1 prometheus: 1/1 time_server: admin.sha.me.corp DEV_ENV: True subvolume_init: disabled admin:~ # salt '*' saltutil.pillar_refresh Note: customized file will overwrite default one. Default file: /srv/pillar/ceph/stack/default/global.yml Customized file: /srv/pillar/ceph/stack/global.yml admin:~ # deepsea stage run ceph.stage.3 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.3 admin:~ # salt-run state.orch ceph.stage.deploy After the command succeeds, run the following to check the status: admin:~ # ceph -s Below comands return you a structure of matching disks based on your DriveGroups. (will show available information after stage 3) admin:~ # salt-run disks.Report admin:~ # salt-run disks.list admin:~ # salt-run disks.details","title":"1.5. Stage 3 \u2014 the deployment"},{"location":"linux/SES/linux_ses_demo/#16-stage-4-the-services","text":"Run Stage 4 \u2014 the services \u2014 additional features of Ceph like iSCSI, Object Gateway and CephFS can be installed in this stage. Each is optional. admin:~ # deepsea stage run ceph.stage.4 (The following commands are equivalents) admin:~ # salt-run state.orch ceph.stage.4 admin:~ # salt-run state.orch ceph.stage.services admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log Before logon to dashboard via url, need get credentials first admin:~ # salt-call grains.get dashboard_creds local: ---------- admin: --> the password was changed to mypassword to log on to dashboard admin:~ # ceph mgr services { \"dashboard\": \"https://mon1.sha.me.corp:8443/\", \"prometheus\": \"http://mon1.sha.me.corp:9283/\" } https://10.58.121.186:8443 http://10.58.121.186:9283 admin:~ # watch ceph -s Every 2.0s: ceph -s admin: Mon Oct 5 14:41:51 2020 cluster: id: health: HEALTH_OK services:s: ceph -s mon: 3 daemons, quorum mon1,mon2,mon3 (age 87m) mgr: mon1(active, since 82m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 85m), 12 in (since 85m) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 576 pgs objects: 213 objects, 4.2 KiB usage: 12 GiB used, 84 GiB / 96 GiB avail pgs: 576 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr","title":"1.6. Stage 4 \u2014 the services"},{"location":"linux/SES/linux_ses_demo/#17-stage-5-the-removal-stage","text":"Run Stage 5 \u2014 the removal stage. This stage is not mandatory and during the initial setup it is usually not needed. In this stage the roles of minions and also the cluster configuration are removed. You need to run this stage when you need to remove a storage node from your cluster. admin:~ # deepsea stage run ceph.stage.","title":"1.7. Stage 5 \u2014 the removal stage"},{"location":"linux/SES/linux_ses_demo/#18-installation-guide","text":"Deployment Guide (EN) Deployment Guide (ZH)","title":"1.8. Installation Guide"},{"location":"linux/SES/linux_ses_demo/#19-issues-during-installation","text":"[ERROR]: The Salt Master has cached the public key for this node SOLUTION : Restart minions service [ERROR]: This server_id is computed nor by Adler32 neither by CRC32 [QUESTION]: How to change new salt key Stop salt-minion service # systemctl stop salt-minion Delete salt-minion pulic key # rm /etc/salt/pki/minion/minion.pub # rm /etc/salt/pki/minion/minion.pem Change new minion_id admin:~ # echo admin.sha.me.corp > /etc/salt/minion_id data1:~ # echo data1.sha.me.corp > /etc/salt/minion_id data2:~ # echo data2.sha.me.corp > /etc/salt/minion_id data3:~ # echo data3.sha.me.corp > /etc/salt/minion_id data4:~ # echo data4.sha.me.corp > /etc/salt/minion_id mon1:~ # echo mon1.sha.me.corp > /etc/salt/minion_id mon2:~ # echo mon2.sha.me.corp > /etc/salt/minion_id mon3:~ # echo mon3.sha.me.corp > /etc/salt/minion_id Delete old ID on admin node # salt-key -D Restart salt-minion service # systemctl restart salt-minion Accept all new key on admin node admin:~ # salt-key -L admin:~ # salt-key -A or admin:~ # salt-key -a admin.sha.me.corp data1:~ # salt-key -a data1.sha.me.corp data2:~ # salt-key -a data2.sha.me.corp data3:~ # salt-key -a data3.sha.me.corp data4:~ # salt-key -a data4.sha.me.corp mon1:~ # salt-key -a mon1.sha.me.corp mon2:~ # salt-key -a mon2.sha.me.corp mon3:~ # salt-key -a mon3.sha.me.corp [ERROR] ['/var/lib/ceph subvolume missing on mon3.sha.me.corp', '/var/lib/ceph subvolume missing on mon1.sha.me.corp', '/var/lib/ceph subvolume missing on mon2.sha.me.corp', 'See /srv/salt/ceph/subvolume/README.md'] SOLUTION Edit /srv/pillar/ceph/stack/global.yml and add the following line: subvolume_init: disabled Then refresh the Salt pillar and re-run DeepSea stage.3: admin:~ # salt '*' saltutil.refresh_pillar admin:~ # salt-run state.orch ceph.stage.3 After DeepSea successfully finished stage.3, the Ceph Dashboard will be running. Refer to Book \u201cAdministration Guide\u201d, Chapter 20 \u201cCeph Dashboard\u201d for a detailed overview of Ceph Dashboard features. To list nodes running dashboard, run: admin:~ # ceph mgr services | grep dashboard To list admin credentials, run: admin:~ # salt-call grains.get dashboard_creds [ERROR] module function cephprocesses.wait executed on nodes mon1~3 and data1~4 in Stage 0 SOLUTION Check below on all nodes # salt-call cephprocesses.check ERROR: process ceph-mds for role mds is not running ERROR: process radosgw for role rgw is not running admin:~ # ceph -s Clock skew detected on mon ceph (mon.mon2, mon.mon3) Set time server to public server (China) # chronyc sources","title":"1.9. Issues during installation"},{"location":"linux/SES/linux_ses_demo/#110-shutting-down-the-whole-ceph-cluster","text":"Shut down or disconnect any clients accessing the cluster. To prevent CRUSH from automatically rebalancing the cluster, set the cluster to noout: # ceph osd set noout Other flags you can set per osd: nodown noup noin noout Disable safety measures and run the ceph.shutdown runner: admin:~ # salt-run disengage.safety safety is now disabled for cluster ceph admin:~ # salt-run state.orch ceph.shutdown admin.sha.me.corp_master: Name: set noout - Function: salt.state - Result: Changed Started: - 14:32:14.398022 Duration: 2266.75 ms Name: Shutting down radosgw for rgw - Function: salt.state - Result: Changed Started: - 14:32:16.665452 Duration: 1461.23 ms Name: Shutting down cephfs - Function: salt.state - Result: Changed Started: - 14:32:18.127353 Duration: 30326.193 ms Name: Shutting down iscsi - Function: salt.state - Result: Clean Started: - 14:32:48.454187 Duration: 30142.468 ms Name: Shutting down storage - Function: salt.state - Result: Changed Started: - 14:33:18.597321 Duration: 10841.45 ms Name: Shutting down mgr - Function: salt.state - Result: Changed Started: - 14:33:29.439442 Duration: 29209.141 ms Name: Shutting down mon - Function: salt.state - Result: Changed Started: - 14:33:58.649221 Duration: 30519.97 ms Summary for admin.sha.me.corp_master ------------ Succeeded: 7 (changed=6) Failed: 0 ------------ Total states run: 7 Total run time: 134.767 s Power off all cluster nodes: admin:~ # salt -C 'G@deepsea:*' cmd.run \"shutdown -h\" Broadcast message from root@admin (Sat 2021-03-06 14:40:37 CST): The system is going down for poweroff at Sat 2021-03-06 14:41:37 CST! admin.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. mon2.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data2.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. mon3.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data3.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data4.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. mon1.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel. data1.sha.me.corp: Shutdown scheduled for Sat 2021-03-06 14:41:37 CST, use 'shutdown -c' to cancel.","title":"1.10. Shutting Down the Whole Ceph Cluster"},{"location":"linux/SES/linux_ses_demo/#111-starting-stopping-and-restarting-services-using-targets","text":"# ls /usr/lib/systemd/system/ceph*.target ceph.target ceph-osd.target ceph-mon.target ceph-mgr.target ceph-mds.target ceph-radosgw.target ceph-rbd-mirror.target To start/stop/restart all Ceph services on the node, run: # systemctl start ceph.target # systemctl stop ceph.target # systemctl restart ceph.target To start/stop/restart all OSDs on the node, run: # systemctl start ceph-osd.target # systemctl stop ceph-osd.target # systemctl restart ceph-osd.target Starting, Stopping, and Restarting Individual Services # systemctl list-unit-files --all --type=service ceph* ceph-osd@.service ceph-mon@.service ceph-mds@.service ceph-mgr@.service ceph-radosgw@.service ceph-rbd-mirror@.service Example : # systemctl status ceph-mon@HOSTNAME.service (e.g., ceph-mon@mon1.service) # systemctl start ceph-osd@1.service # systemctl stop ceph-osd@1.service # systemctl restart ceph-osd@1.service # systemctl status ceph-osd@1.service","title":"1.11. Starting, Stopping, and Restarting Services Using Targets"},{"location":"linux/SES/linux_ses_demo/#112-restarting-all-services","text":"# salt-run state.orch ceph.restart","title":"1.12. Restarting All Services"},{"location":"linux/SES/linux_ses_demo/#113-restarting-specific-services","text":"Example: salt-run state.orch ceph.restart.service_name # salt-run state.orch ceph.restart.mon # salt-run state.orch ceph.restart.mgr # salt-run state.orch ceph.restart.osd # salt-run state.orch ceph.restart.mds # salt-run state.orch ceph.restart.rgw # salt-run state.orch ceph.restart.igw # salt-run state.orch ceph.restart.ganesha Default log file path of salt-run: /var/log/salt/master","title":"1.13. Restarting Specific Services"},{"location":"linux/SES/linux_ses_demo/#2-basic-operation","text":"","title":"2. Basic Operation"},{"location":"linux/SES/linux_ses_demo/#21-pools-and-data-placement","text":"","title":"2.1. Pools and Data Placement"},{"location":"linux/SES/linux_ses_demo/#211-enable-the-pg-autoscaler-and-balancer-modules","text":"","title":"2.1.1. Enable the PG Autoscaler and Balancer Modules"},{"location":"linux/SES/linux_ses_demo/#task-1-view-the-state-of-all-the-manager-modules","text":"List all the existing Manager Modules admin:~ # ceph mgr module ls | less","title":"Task 1: View the state of all the Manager Modules"},{"location":"linux/SES/linux_ses_demo/#task-2-list-the-existing-pools","text":"List the pools that already exist in the cluster admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log List the pools again, but this time using the rados command: admin:~ # rados lspools iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log View the output of placement group autoscale-status command for the pools admin:~ # ceph osd pool autoscale-status Error ENOTSUP: Module 'pg_autoscaler' is not enabled (required by command 'osd pool autoscale-status'): use `ceph mgr module enable pg_autoscaler` to enable it","title":"Task 2: List the Existing Pools"},{"location":"linux/SES/linux_ses_demo/#task-3-enable-the-pg_autoscaler-module","text":"Enable the pg_autoscaler module admin:~ # ceph mgr module enable pg_autoscaler admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 128 32 warn cephfs_data 0 3.0 98256M 0.0000 1.0 256 32 warn cephfs_metadata 7285 3.0 98256M 0.0000 4.0 64 16 warn .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 18078 3.0 98256M 0.0000 1.0 32 warn Note that for the iscsi-images pool the PG_NUM value is 128. And note that the NEW PG_NUM value is 32. The PGs won\u2019t be adjusted automatically because the default setting for the autoscaler is \u201cwarn\u201d. Note the last column (mode) that shows status \u201cwarn\u201d for all the pools. Check current status. \u201chave too many placement groups\u201d. That\u2019s exactly what we want the pg_autoscaler to tell us. admin:~ # ceph health HEALTH_WARN 3 pools have too many placement groups Turn off the pg_autoscaler feature for CephFS pools admin:~ # ceph osd pool set cephfs_data pg_autoscale_mode off set pool 2 pg_autoscale_mode to off admin:~ # ceph osd pool set cephfs_metadata pg_autoscale_mode off set pool 3 pg_autoscale_mode to off admin:~ # ceph health HEALTH_WARN 1 pools have too many placement groups Set the pg_autoscaler mode to \u201con\u201d for the iscs-images pool: admin:~ # ceph osd pool set iscsi-images pg_autoscale_mode on set pool 1 pg_autoscale_mode to on admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 128 32 on cephfs_data 0 3.0 98256M 0.0000 1.0 256 32 off cephfs_metadata 7412 3.0 98256M 0.0000 4.0 64 16 off .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 18078 3.0 98256M 0.0000 1.0 32 warn Turn on the pg_autoscaler feature for CephFS pools admin:~ # ceph osd pool set cephfs_data pg_autoscale_mode on set pool 2 pg_autoscale_mode to on admin:~ # ceph osd pool set cephfs_metadata pg_autoscale_mode on set pool 3 pg_autoscale_mode to on PG numbgrs must always be a power of 2 admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 32 on cephfs_data 0 3.0 98256M 0.0000 1.0 32 off cephfs_metadata 7412 3.0 98256M 0.0000 4.0 16 off .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 35900 3.0 98256M 0.0000 1.0 32 warn Show the cluster health admin:~ # ceph -s cluster: id: health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 4w) mgr: mon1(active, since 46h) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 8w), 12 in (since 8w) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 433 pgs objects: 246 objects, 4.7 KiB usage: 13 GiB used, 83 GiB / 96 GiB avail pgs: 0.462% pgs not active 431 active+clean 2 peering io: client: 45 KiB/s rd, 0 B/s wr, 44 op/s rd, 28 op/s wr","title":"Task 3: Enable the pg_autoscaler module"},{"location":"linux/SES/linux_ses_demo/#task-4-turn-on-the-placement-group-balancer-feature","text":"1). Show the \u201cstatus\u201d of the balancer: admin:~ # ceph balancer status { \"plans\": [], \"active\": false, \"last_optimize_started\": \"\", \"last_optimize_duration\": \"\", \"optimize_result\": \"\", \"mode\": \"none\" } admin:~ # ceph balancer on admin:~ # ceph balancer status { \"plans\": [], \"active\": true, \"last_optimize_started\": \"Mon Jan 4 20:22:57 2021\", \"last_optimize_duration\": \"0:00:00.001379\", \"optimize_result\": \"Please do \\\"ceph balancer mode\\\" to choose a valid mode first\", \"mode\": \"none\" } 2). Set the mode for the balancer to \u201cupmap\u201d: admin:~ # ceph balancer mode upmap Error EPERM: min_compat_client \"jewel\" < \"luminous\", which is required for pg-upmap. Try \"ceph osd set-require-min-compat-client luminous\" before enabling this mode admin:~ # ceph osd set-require-min-compat-client luminous --yes-i-really-mean-it set require_min_compat_client to luminous admin:~ # ceph balancer mode upmap admin:~ # ceph balancer status { \"plans\": [], \"active\": true, \"last_optimize_started\": \"Mon Jan 4 20:23:57 2021\", \"last_optimize_duration\": \"0:00:00.001807\", \"optimize_result\": \"Please do \\\"ceph balancer mode\\\" to choose a valid mode first\", \"mode\": \"upmap\" } 3). Create a balancer optimization plan called basic-plan. Ceph won\u2019t let you do this yet. Because you just recently enabled the pg_autoscaler, Ceph is moving objects around, and the PGs are quite busy with re-peering. admin:~ # ceph balancer optimize basic-plan Error EINVAL: Balancer enabled, disable to optimize manually 4). Show the details of the plan: This shows what \u201cexecute\u201d-ing the plan will do, itemizing which PGs will be affected. admin:~ # ceph balancer show basic-plan Error ENOENT: plan basic-plan not found <--- failed here 5). Show the effectiveness of the plan by comparing the current score for the pre-planned balancing and the score for the planned balancing: admin:~ # ceph balancer eval current cluster score 0.118731 (lower is better) admin:~ # ceph balancer eval basic-plan Error EINVAL: option \"basic-plan\" not a plan or a pool 6). Show the status of the balancer, now with all of these settings having been set, but before putting them into effect: The pg_autoscaler has already optimized the balance of PGs sufficiently. That\u2019s because this cluster is very small and has no significant content stored in it yet. If that\u2019s the case, you would see a message like \u201cError EALREADY: Unable to find further optimization, or pool(s)' pg_num is decreasing, or distribution is already perfect.\u201d If you receive this message, then you will not be able to complete this task. At some later time in the course you may choose to revisit this task to complete it. admin:~ # ceph balancer status { \"plans\": [], \"active\": true, \"last_optimize_started\": \"Mon Jan 4 20:32:59 2021\", \"last_optimize_duration\": \"0:00:00.004170\", \"optimize_result\": \"Unable to find further optimization, or pool(s) pg_num is decreasing, or distribution is already perfect\", \"mode\": \"upmap\" } 7). Set the basic-plan into effect: admin:~ # ceph balancer execute basic-plan Error EINVAL: Balancer enabled, disable to execute a plan 8). Now re-show the current score for the balanced cluster: admin:~ # ceph balancer eval current cluster score 0.118731 (lower is better)","title":"Task 4: Turn on the Placement Group balancer feature"},{"location":"linux/SES/linux_ses_demo/#212-manipulate-erasure-code-profiles","text":"","title":"2.1.2. Manipulate Erasure Code Profiles"},{"location":"linux/SES/linux_ses_demo/#task-1-display-a-list-of-the-current-erasure-code-profiles","text":"admin:~ # ceph osd erasure-code-profile no valid command found; 4 closest matches: osd erasure-code-profile set { [...]} {--force} osd erasure-code-profile get osd erasure-code-profile rm osd erasure-code-profile ls Error EINVAL: invalid command admin:~ # ceph osd erasure-code-profile ls default","title":"Task 1: Display a list of the current Erasure Code profiles"},{"location":"linux/SES/linux_ses_demo/#task-2-examine-the-details-of-the-default-ec-profile","text":"admin:~ # ceph osd erasure-code-profile get default k=2 m=1 plugin=jerasure technique=reed_sol_van","title":"Task 2: Examine the details of the default EC profile"},{"location":"linux/SES/linux_ses_demo/#task-3-create-and-remove-a-new-ec-profile","text":"1. Create a new EC profile from the command line. This is going to be a \u201cbad\u201d profile that will be removed in a moment: admin:~ # ceph osd erasure-code-profile set bad_profile k=2 m=4 plugin=jerasure admin:~ # ceph osd erasure-code-profile ls bad_profile default admin:~ # ceph osd erasure-code-profile get bad_profile crush-device-class= crush-failure-domain=host crush-root=default jerasure-per-chunk-alignment=false k=2 m=4 plugin=jerasure technique=reed_sol_van w=8 admin:~ # ceph osd erasure-code-profile rm bad_profile admin:~ # ceph osd erasure-code-profile ls default","title":"Task 3: Create and remove a new EC profile"},{"location":"linux/SES/linux_ses_demo/#task-4-create-a-better-ec-profile","text":"admin:~ # ceph osd erasure-code-profile set usable_profile k=2 m=1 plugin=jerasure technique=reed_sol_van stripe_unit=4K crush-failure-domain=host admin:~ # ceph osd erasure-code-profile get usable_profile crush-device-class= crush-failure-domain=host crush-root=default jerasure-per-chunk-alignment=false k=2 m=1 plugin=jerasure stripe_unit=4K technique=reed_sol_van w=8","title":"Task 4: Create a better EC profile"},{"location":"linux/SES/linux_ses_demo/#213-manipulate-crush-map-rulesets","text":"","title":"2.1.3. Manipulate CRUSH Map Rulesets"},{"location":"linux/SES/linux_ses_demo/#task-1-display-a-list-of-the-current-crush-map-rules","text":"admin:~ # ceph osd crush rule ls replicated_rule admin:~ # ceph osd crush osd crush rule ls osd crush rule ls-by-class osd crush rule dump {} osd crush dump osd crush set {} osd crush add-bucket { [...]} osd crush rename-bucket osd crush set [...] osd crush add [...] osd crush set-all-straw-buckets-to-straw2 admin:~ # ceph osd crush rule osd crush rule ls osd crush rule ls-by-class osd crush rule dump {} osd crush rule create-simple {firstn|indep} osd crush rule create-replicated {} osd crush rule create-erasure {} osd crush rule rm osd crush rule rename List the existing CRUSH Map rulesets that have been defined according to a particular device class: admin:~ # ceph osd crush rule ls-by-class hdd admin:~ # ceph osd crush rule ls-by-class ssd Error ENOENT: failed to get rules by class 'ssd' admin:~ # ceph osd crush rule ls-by-class nvme Error ENOENT: failed to get rules by class 'nvme'","title":"Task 1: Display a list of the current CRUSH Map rules"},{"location":"linux/SES/linux_ses_demo/#task-2-examine-the-details-of-the-default-crush-map-rule","text":"Show the details of the default CRUSH Map rule with the dump sub-command: The \u201crule_id\u201d and \u201cruleset\u201d values just numbgrs to keep track of rules similar to a DB key id. \u201cmin_size\u201d and \u201cmax_size\u201d are related to how CRUSH behaves when a certain numbgr of replicas are created. The \u201csteps\u201d section is the most functional portion of the rule, providing an ordered set of rules for how CRUSH should behave. Note that there are three \u201cop\u201d parts, one each for \u201ctake\u201d, \u201cchooseleaf_firstn\u201d, and \u201cemit\u201d. \u201ctake\u201d in a replicated rule is always the first step, and \u201cemit\u201d is always the last step. The \u201citem_type\u201d in the \u201ctake\u201d step is the crush_root value, and the \u201chost\u201d in the \u201cchooseleaf_firstn\u201d step is the failure_domain. admin:~ # ceph osd crush rule dump replicated_rule { \"rule_id\": 0, \"rule_name\": \"replicated_rule\", \"ruleset\": 0, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] }","title":"Task 2: Examine the details of the default CRUSH Map rule"},{"location":"linux/SES/linux_ses_demo/#task-3-create-and-remove-a-new-crush-map-rule","text":"1). Create a new CRUSH ruleset from the command line.We made two mistakes here: First, we named it \u201cbud\u201d instead of \u201cbad\u201d. admin:~ # ceph osd crush rule create-replicated bud_ruleset default host admin:~ # ceph osd crush rule ls replicated_rule bud_ruleset 2). Rename the ruleset: admin:~ # ceph osd crush rule rename bud_ruleset bad_ruleset admin:~ # ceph osd crush rule ls replicated_rule bad_ruleset 3). The second mistake was that we specified the failure-domain at the host-bucket level. This is technically not a bad thing to do, in fact it would be a common use case. But for this demo we want to set the failure domain at the rack-bucket level. We can\u2019t change a defined CRUSH Map ruleset, so delete the bad one: admin:~ # ceph osd crush rule rm bad_ruleset admin:~ # ceph osd crush rule ls replicated_rule","title":"Task 3: Create and remove a new CRUSH Map rule"},{"location":"linux/SES/linux_ses_demo/#task-4-create-a-better-crush-map-rule","text":"Create a more appropriate CRUSH Map rule from the CLI, that will survive the failure of a rack: admin:~ # ceph osd crush rule create-replicated better_ruleset default rack admin:~ # ceph osd crush rule dump better_ruleset { \"rule_id\": 1, \"rule_name\": \"better_ruleset\", \"ruleset\": 1, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"rack\" }, { \"op\": \"emit\" } ] }","title":"Task 4: Create a better CRUSH Map rule"},{"location":"linux/SES/linux_ses_demo/#task-5-create-crush-map-rules-for-different-classes-of-devices","text":"1). Create two different CRUSH Map rules from the CLI, that will accommodate a slow set of devices (HDDs) and a fast set of devices (SDDs): The error of 2 nd is because the cluster does not have any SSD devices. admin:~ # ceph osd crush rule create-replicated slow_devices default host hdd admin:~ # ceph osd crush rule create-replicated fast_devices default host sdd Error EINVAL: device class sdd does not exist 2). Display the details of the new \u201cslow\u201d rule: admin:~ # ceph osd crush rule dump slow_devices { \"rule_id\": 2, \"rule_name\": \"slow_devices\", \"ruleset\": 2, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -2, \"item_name\": \"default~hdd\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] }","title":"Task 5: Create CRUSH Map rules for different classes of devices"},{"location":"linux/SES/linux_ses_demo/#task-6-change-the-ruleset-used-by-a-pool","text":"1). Show which CRUSH Map Ruleset is being used by the cephfs_data pool: The rule should be listed as replicated_rule. admin:~ # ceph osd pool get cephfs_data crush_rule crush_rule: replicated_rule 2). Change the cephfs_data pool to use the new CRUSH Map ruleset that you created in the previous task. admin:~ # ceph osd pool set cephfs_data crush_rule better_ruleset set pool 2 crush_rule to better_ruleset 3). Verify that the rule has been changed by re-running the earlier command: admin:~ # ceph osd pool get cephfs_data crush_rule crush_rule: better_ruleset 4). In this demo cluster, making the cephfs_data pool use the \u201cbetter_ruleset\u201d will result in problems. (There\u2019s no rack for the CRUSH Map, and not enough nodes to accommodate the requirement for a large numbgr of PGs.) So change the setting back to the replicated_rule. admin:~ # ceph osd pool set cephfs_data crush_rule replicated_rule set pool 2 crush_rule to replicated_rule admin:~ # ceph osd pool get cephfs_data crush_rule crush_rule: replicated_rule Task 7: Create a CRUSH Map rule enhanced with an EC profile 1). Combine the benefits of Erasure Coding with a CRUSH Map rule: This will only work if you have already created an appropriate EC profile called usable_profile. In this demo you would have done in an earlier exercise. And in this demo you need to tie this ec_rule to the usable_profile, not the better_profile.Or else any pool that you create using the ec_rule will fail due to insufficient resources. admin:~ # ceph osd crush rule create-erasure ec_rule usable_profile Link the CRUSH map rule (ec_rule) to EC profile (usable_profile) created rule ec_rule at 3 P.S., The useable_profile was created by : admin:~ # ceph osd erasure-code-profile set usable_profile k=2 m=1 plugin=jerasure technique=reed_sol_van stripe_unit=4K crush-failure-domain=host 2). Display the details of the EC-enhanced CRUSH Map rule: See the added, extra \u201cop\u201d steps. You might also notice the different values for \u201ctype,\u201d \u201cmin_size,\u201d and \u201cmax_size\u201d than what you saw in the standard replicated rules. admin:~ # ceph osd crush rule dump ec_rule { \"rule_id\": 3, \"rule_name\": \"ec_rule\", \"ruleset\": 3, \"type\": 3, \"min_size\": 3, \"max_size\": 3, \"steps\": [ { \"op\": \"set_chooseleaf_tries\", \"num\": 5 }, { \"op\": \"set_choose_tries\", \"num\": 100 }, { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_indep\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd crush rule ls replicated_rule better_ruleset slow_devices ec_rule admin:~ # ceph osd crush rule create-replicated better_ruleset default rack admin:~ # ceph osd crush rule create-replicated slow_devices default host hdd admin:~ # ceph osd crush rule create-erasure ec_rule usable_profile admin:~ # ceph osd crush rule dump replicated_rule { \"rule_id\": 0, \"rule_name\": \"replicated_rule\", \"ruleset\": 0, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd crush rule dump better_ruleset { \"rule_id\": 1, \"rule_name\": \"better_ruleset\", \"ruleset\": 1, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -1, \"item_name\": \"default\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"rack\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd crush rule dump slow_devices { \"rule_id\": 2, \"rule_name\": \"slow_devices\", \"ruleset\": 2, \"type\": 1, \"min_size\": 1, \"max_size\": 10, \"steps\": [ { \"op\": \"take\", \"item\": -2, \"item_name\": \"default~hdd\" }, { \"op\": \"chooseleaf_firstn\", \"num\": 0, \"type\": \"host\" }, { \"op\": \"emit\" } ] } admin:~ # ceph osd pool osd pool stats {} osd pool scrub [...] osd pool deep-scrub [...] osd pool repair [...] osd pool force-recovery [...] osd pool force-backfill [...] osd pool cancel-force-recovery [...] osd pool cancel-force-backfill [...] osd pool autoscale-status osd pool mksnap admin:~ # ceph osd pool get size min_size pg_num pgp_num crush_rule Hashpspool Nodelete Nopgchange Nosizechange write_fadvise_dontneed Noscrub nodeep-scrub hit_set_type hit_set_period hit_set_count hit_set_fpp use_gmt_hitset target_max_objects target_max_bytes cache_target_dirty_ratio cache_target_dirty_high_ratio cache_target_full_ratio cache_min_flush_age cache_min_evict_age erasure_code_profile min_read_recency_for_promote All min_write_recency_for_promote fast_read hit_set_grade_decay_rate hit_set_search_last_n scrub_min_interval scrub_max_interval deep_scrub_interval recovery_priority recovery_op_priority scrub_priority compression_mode compression_algorithm compression_required_ratio compression_max_blob_size compression_min_blob_size csum_type csum_min_block csum_max_block allow_ec_overwrites fingerprint_algorithm pg_autoscale_mode pg_autoscale_bias pg_num_min target_size_bytes target_size_ratio","title":"Task 6: Change the ruleset used by a pool"},{"location":"linux/SES/linux_ses_demo/#214-investigate-bluestore","text":"","title":"2.1.4. Investigate BlueStore"},{"location":"linux/SES/linux_ses_demo/#task-1-explore-the-drive_groupsyml-configuration","text":"After deployment, the drive_groups.yml file is where the storage administrator defines the configuration of the cluster\u2019s storage devices. Note the \u201cdata_devices\u201d parameter. In this demo, \u201call\u201d storage devices are data devices for BlueStore. Note that there are no definitions for \u201cwal_devices\u201d or \u201cdb_devices.\u201d That\u2019s because in this demo environment we don\u2019t have any other \u201cfast\u201d devices that would be appropriate for these roles. Since BlueStore is the default, there is no definition of a \u201cformat\u201d for the devices. Otherwise, a \u201cFormat: bluestore\u201d key-value pair might exist to ensure that BlueStore is used. admin:~ # cd /srv/salt/ceph/configuration/files admin:/srv/salt/ceph/configuration/files # cat drive_groups.yml # default: <- just a name - can be anything # target: 'data*' <- must be resolvable by salt's targeting processor # data_devices: # size: 20G # db_devices: # size: 10G # rotational: 1 # allflash: # target: 'fast_nodes*' # data_devices: # size: 100G # db_devices: # size: 50G # rotational: 0 # This is the default configuration and # will create an OSD on all available drives default: target: 'data*' data_devices: all: true","title":"Task 1: Explore the drive_groups.yml configuration"},{"location":"linux/SES/linux_ses_demo/#task-2-examine-a-storage-hosts-storage-devices","text":"admin:~ # ssh data1 Last login: Tue Jan 5 18:06:40 2021 from 10.58.121.181 Should see 3 devices, which are named ceph LVM-type devices data1:~ # lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 8G 0 disk \u2514\u2500ceph--14c886af--269d--475f--8ee3--f5e4abbb222d-osd--data--38911b2d--f30a--4b09--9010--8dd6fad2fcc6 254:0 0 8G 0 lvm sdb 8:16 0 8G 0 disk \u2514\u2500ceph--9ec4a77a--5d67--4b21--be53--d7e9221082de-osd--data--00cb3dc6--c28b--41ae--95de--efb86da254da 254:1 0 8G 0 lvm sdc 8:32 0 8G 0 disk \u2514\u2500ceph--5eaea8a8--bb68--49dd--a1e3--b82c5464ab1f-osd--data--a4a05f70--53d9--41d4--a273--4f47a088968a 254:2 0 8G 0 lvm sr0 11:0 1 672M 0 rom vda 253:0 0 20G 0 disk \u251c\u2500vda1 253:1 0 8M 0 part \u251c\u2500vda2 253:2 0 18.4G 0 part / \u2514\u2500vda3 253:3 0 1.7G 0 part [SWAP] See the raw ceph devices data1:~ # ls -lad /dev/ceph* drwxr-xr-x 2 root root 60 Oct 5 13:15 /dev/ceph-14c886af-269d-475f-8ee3-f5e4abbb222d drwxr-xr-x 2 root root 60 Oct 5 13:16 /dev/ceph-5eaea8a8-bb68-49dd-a1e3-b82c5464ab1f drwxr-xr-x 2 root root 60 Oct 5 13:15 /dev/ceph-9ec4a77a-5d67-4b21-be53-d7e9221082de Dig down even farther by examining the content of one of the directories, see a symlink to an LVM device-mapper device. All the devices are tied together with LVM. Note that the name of the symlink is named osd-data- . data1:~ # ls -l /dev/ceph-14c886af-269d-475f-8ee3-f5e4abbb222d lrwxrwxrwx 1 ceph ceph 7 Oct 5 13:15 osd-data-38911b2d-f30a-4b09-9010-8dd6fad2fcc6 -> ../dm-0 data1:~ # l /dev/dm* brw-rw---- 1 ceph ceph 254, 0 Jan 5 18:10 /dev/dm-0 brw-rw---- 1 ceph ceph 254, 1 Jan 5 18:10 /dev/dm-1 brw-rw---- 1 ceph ceph 254, 2 Jan 5 18:10 /dev/dm-2","title":"Task 2: Examine a storage host\u2019s storage devices"},{"location":"linux/SES/linux_ses_demo/#task-3-examine-a-storage-hosts-osd-details","text":"data1:~ # cd /var/lib/ceph/ data1:/var/lib/ceph # ls -l drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-mds drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-mgr drwxr-x--- 1 ceph ceph 24 Oct 5 13:15 bootstrap-osd drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-rbd drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-rbd-mirror drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 bootstrap-rgw drwxr-x--- 1 ceph ceph 12 Oct 5 09:04 crash drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 mds drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 mgr drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 mon drwxr-x--- 1 ceph ceph 38 Oct 5 13:16 osd drwxr-x--- 1 ceph ceph 0 Aug 24 22:03 tmp See 3 different sub-directories, each representing the 3 different OSDs (ceph-2, ceph-6, ceph-10) that are running on this storage server data1:/var/lib/ceph # cd osd/ data1:/var/lib/ceph/osd # ls -l drwxrwxrwt 2 ceph ceph 320 Oct 5 13:16 ceph-10 drwxrwxrwt 2 ceph ceph 320 Oct 5 13:15 ceph-2 drwxrwxrwt 2 ceph ceph 320 Oct 5 13:16 ceph-6 See some functional files associated with the OSD and BlueStore. See a block file, which is a symlink to one of the ceph devices, which stores the raw objects for the OSD. data1:/var/lib/ceph/osd # cd ceph-2 data1:/var/lib/ceph/osd/ceph-2 # ls -l -rw-r--r-- 1 ceph ceph 400 Oct 5 13:15 activate.monmap lrwxrwxrwx 1 ceph ceph 92 Oct 5 13:15 block -> /dev/ceph-14c886af-269d-475f-8ee3-f5e4abbb222d/osd-data-38911b2d-f30a-4b09-9010-8dd6fad2fcc6 -rw------- 1 ceph ceph 2 Oct 5 13:15 bluefs -rw------- 1 ceph ceph 37 Oct 5 13:15 ceph_fsid -rw-r--r-- 1 ceph ceph 37 Oct 5 13:15 fsid -rw------- 1 ceph ceph 55 Oct 5 13:15 keyring -rw------- 1 ceph ceph 8 Oct 5 13:15 kv_backend -rw------- 1 ceph ceph 21 Oct 5 13:15 magic -rw------- 1 ceph ceph 4 Oct 5 13:15 mkfs_done -rw------- 1 ceph ceph 41 Oct 5 13:15 osd_key -rw------- 1 ceph ceph 6 Oct 5 13:15 ready -rw------- 1 ceph ceph 3 Oct 5 13:15 require_osd_release -rw------- 1 ceph ceph 10 Oct 5 13:15 type -rw------- 1 ceph ceph 2 Oct 5 13:15 whoami data1:/var/lib/ceph/osd/ceph-2 # cat ceph_fsid # The unique ID of this Ceph cluster 343ee7d3-232f-4c71-8216-1edbc55ac6e0 data1:/var/lib/ceph/osd/ceph-2 # cat fsid # The unique ID of this OSD 6df58ebc-dbfe-4822-9714-90212c06ea05 data1:/var/lib/ceph/osd/ceph-2 # cat keyring # The Ceph key for this OSD [osd.2] key = data1:/var/lib/ceph/osd/ceph-2 # cat ready # Indication of the readiness of this OSD ready data1:/var/lib/ceph/osd/ceph-2 # cat type # filestore or bluestore (in this case: bluestore) bluestore data1:/var/lib/ceph/osd/ceph-2 # cat whoami # The integer id of this OSD (in this case: 2) 2","title":"Task 3: Examine a storage host\u2019s OSD details"},{"location":"linux/SES/linux_ses_demo/#task-4-display-bluestore-information-using-ceph-bluestore-tool","text":"Show BlueStore metadata for osd.2: data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool show-label --path /var/lib/ceph/osd/ceph-2 inferring bluefs devices from bluestore path { \"/var/lib/ceph/osd/ceph-2/block\": { \"osd_uuid\": \"6df58ebc-dbfe-4822-9714-90212c06ea05\", \"size\": 8585740288, \"btime\": \"2020-10-05 13:15:51.227799\", \"description\": \"main\", \"bluefs\": \"1\", \"ceph_fsid\": \"343ee7d3-232f-4c71-8216-1edbc55ac6e0\", \"kv_backend\": \"rocksdb\", \"magic\": \"ceph osd volume v026\", \"mkfs_done\": \"yes\", \"osd_key\": , \"ready\": \"ready\", \"require_osd_release\": \"14\", \"whoami\": \"2\" } Run a manual \u201cscrub\u201d on osd.7 using ceph-blestore-tool. (Received error, the tool won\u2019t allow you to do this while the OSD is running.) data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool fsck --path /var/lib/ceph/osd/ceph-2 error from fsck: (11) Resource temporarily unavailable 2021-01-05 18:32:25.528 7f4abad6e180 -1 bluestore(/var/lib/ceph/osd/ceph-2) _lock_fsid failed to lock /var/lib/ceph/osd/ceph-2/fsid (is another ceph-osd still running?)(11) Resource temporarily unavailable Simulate that the OSD is down, shutdown the OSD: data1:/var/lib/ceph/osd/ceph-2 # systemctl stop ceph-osd@2.service Now run the \u201cfsck\u201d command again. This time the \u201cfsck\u201d has worked, with the output showing: \u201cfsck success\u201d data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool fsck --path /var/lib/ceph/osd/ceph-2 fsck success Restart the OSD: data1:/var/lib/ceph/osd/ceph-2 # systemctl start ceph-osd@2.service data1:/var/lib/ceph/osd/ceph-2 # ceph-bluestore-tool show-label --path /var/lib/ceph/osd/ceph-2 inferring bluefs devices from bluestore path { \"/var/lib/ceph/osd/ceph-2/block\": { \"osd_uuid\": \"6df58ebc-dbfe-4822-9714-90212c06ea05\", \"size\": 8585740288, \"btime\": \"2020-10-05 13:15:51.227799\", \"description\": \"main\", \"bluefs\": \"1\", \"ceph_fsid\": \"343ee7d3-232f-4c71-8216-1edbc55ac6e0\", \"kv_backend\": \"rocksdb\", \"magic\": \"ceph osd volume v026\", \"mkfs_done\": \"yes\", \"osd_key\": , \"ready\": \"ready\", \"require_osd_release\": \"14\", \"whoami\": \"2\" } }","title":"Task 4: Display BlueStore information using ceph-bluestore-tool"},{"location":"linux/SES/linux_ses_demo/#22-common-day-1-tasks-using-the-cli","text":"Including ollowing topics in relation to the commandline: Users and Ceph Configuration Health commands Erasure Code Profiles CRUSH Map rules Pools Scrubbing OSDs and Placement Groups Manager modules The tell commands","title":"2.2. Common Day 1 Tasks Using the CLI"},{"location":"linux/SES/linux_ses_demo/#221-ceph-users-and-configuration","text":"","title":"2.2.1. Ceph Users and Configuration"},{"location":"linux/SES/linux_ses_demo/#task-1-view-the-current-user-keyrings","text":"Ceph keyrings are stored in below directory admin:~ # cd /etc/ceph/ admin:/etc/ceph # ls -l -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap The value of 'key' is the key that\u2019s on the keyring. The admin keyring is \u201callow\u201ded all capabilities (permissions) to all services in the cluster, as expected. there are more than just client keys. admin:/etc/ceph # cat ceph.client.admin.keyring [client.admin] key = caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" Display the existing users with the \u201cauth\u201d command: Below two commands are equivalent admin:/etc/ceph # ceph -n client.admin -keyring=/etc/ceph/ceph.client.admin.keyring auth ls -- failed??? no valid command found admin:/etc/ceph # ceph auth ls installed auth entries: mds.mon1 key: caps: [mds] allow * caps: [mgr] allow profile mds caps: [mon] allow profile mds caps: [osd] allow rwx mds.mon2 key: caps: [mds] allow * caps: [mgr] allow profile mds caps: [mon] allow profile mds caps: [osd] allow rwx mds.mon3 key: caps: [mds] allow * caps: [mgr] allow profile mds caps: [mon] allow profile mds caps: [osd] allow rwx osd.0 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.1 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.10 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.11 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.2 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.3 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.4 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.5 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.6 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.7 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.8 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * osd.9 key: caps: [mgr] allow profile osd caps: [mon] allow profile osd caps: [osd] allow * client.admin key: caps: [mds] allow * caps: [mgr] allow * caps: [mon] allow * caps: [osd] allow * client.bootstrap-mds key: caps: [mon] allow profile bootstrap-mds client.bootstrap-mgr key: caps: [mon] allow profile bootstrap-mgr client.bootstrap-osd key: caps: [mgr] allow r caps: [mon] allow profile bootstrap-osd client.bootstrap-rbd key: caps: [mon] allow profile bootstrap-rbd client.bootstrap-rbd-mirror key: caps: [mon] allow profile bootstrap-rbd-mirror client.bootstrap-rgw key: caps: [mon] allow profile bootstrap-rgw client.igw.mon2 key: caps: [mgr] allow r caps: [mon] allow * caps: [osd] allow * client.rgw.mon3 key: caps: [mgr] allow r caps: [mon] allow rwx caps: [osd] allow rwx client.storage key: caps: [mon] allow rw mgr.mon1 key: caps: [mds] allow * caps: [mon] allow profile mgr caps: [osd] allow *","title":"Task 1: View the current user keyrings"},{"location":"linux/SES/linux_ses_demo/#task-2-create-a-new-keyring-and-associated-user","text":"1). There are several different ways to create a new keyring and user. This is just one way. Create a new keyring and associated user named James . Remembgr that typically all new users will need read rights for the mon capability, and will need read/write rights for the osd capability, including a specification of rights to a pool. admin:/etc/ceph # ceph-authtool -g -n client.james --cap mon 'allow r' --cap osd 'allow rw pool=iscsi-images' -C /etc/ceph/ceph.client.james.keyring creating /etc/ceph/ceph.client.james.keyring admin:/etc/ceph # l total 16 drwxr-xr-x 1 root root 130 Jan 5 19:31 ./ drwxr-xr-x 1 root root 4392 Oct 5 13:03 ../ -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw------- 1 root root 126 Jan 5 19:31 ceph.client.james.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap 2). Show the content of the newly created keyring: admin:/etc/ceph # cat ceph.client.james.keyring [client.james] key = caps mon = \"allow r\" caps osd = \"allow rw pool=iscsi-images\" 3). Officially add the new keyring to Ceph: admin:/etc/ceph # ceph auth add client.james -i /etc/ceph/ceph.client.james.keyring added key for client.james 4). Show the key information using the \u201cauth\u201d function: admin:/etc/ceph # ceph auth get client.james exported keyring for client.james [client.james] key = caps mon = \"allow r\" caps osd = \"allow rw pool=iscsi-images\"","title":"Task 2: Create a new keyring and associated user"},{"location":"linux/SES/linux_ses_demo/#task-3-create-a-client-key-for-rbd","text":"1). Change to the directory that contains the ceph keyrings. admin:~ # cd /etc/ceph/ 2). List the content of the directory: Although you see the admin users\u2019s keyring, ceph.client.admin.keyring, there is not yet a file that is appropriate for a specific application to use. Also note that the permissions on the keyring file are quite restrictive: 0600 admin:/etc/ceph # ls -l -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw------- 1 root root 126 Jan 5 19:31 ceph.client.james.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap 3). Show the content of the admin user\u2019s keyring: You will use the value associated with the \u201ckey\u201d key to create a new file. Copy the \u201ckey\u201d value using your favorite method. admin:/etc/ceph # cat ceph.client.admin.keyring [client.admin] key = caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" 4). Open a new file for editing called admin.secret using your favorite editor (such as vi): The name of the file isn\u2019t very important, but naming it this way will help to identify its purpose: it\u2019s a secret key for the admin user. Note that there are many ways to do this. An alternative way is mentioned in the tip below that will do this in one step using grep and awk. admin:/etc/ceph # vi admin.secret 5). Paste the \u201ckey\u201d value into the new file. It will be the only content of the file. It will look like this (in fact it\u2019s probably exactly the same as this, if you\u2019re using the demo environment provided to you): admin:/etc/ceph # cat admin.secret 6). Save the file and exist out of the editor. 7). Change the permissions of the file so that no other user on the host can see the content of the file: admin:/etc/ceph # chmod 0600 admin.secret admin:/etc/ceph # l drwxr-xr-x 1 root root 154 Jan 5 20:03 ./ drwxr-xr-x 1 root root 4392 Oct 5 13:03 ../ -rw------- 1 root root 41 Jan 5 20:03 admin.secret -rw------- 1 root root 151 Oct 5 13:13 ceph.client.admin.keyring -rw------- 1 root root 126 Jan 5 19:31 ceph.client.james.keyring -rw-r--r-- 1 root root 980 Oct 5 13:13 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap Tip: An alternative way to create this key file is to simply use grep/awk together in one bash command, like this: admin:/etc/ceph # grep \"key =\" ceph.client.admin.keyring | awk -F\" = \" '{ print $2 }' admin:/etc/ceph # grep \"key =\" ceph.client.admin.keyring | awk -F\" = \" '{ print $2 }' > admin.secret admin:/etc/ceph # cat admin.secret ","title":"Task 3: Create a client key for RBD"},{"location":"linux/SES/linux_ses_demo/#task-4-view-the-ceph-master-configuration-file","text":"View the content of the file. The file is managed and controlled by DeepSea. The comment makes reference to the control files in the /srv/salt/ceph/configuration/ directory hierarchy. This is a very simple storage cluster. In a more diverse and sophisticated ceph cluster there may be more configuration settings defined. Although this exercise doesn\u2019t call out any more specific information about this configuration file, you may take a moment to consider the content of the file before finishing the task. admin:/etc/ceph # cat ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.186, 10.58.121.187, 10.58.121.188 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] admin:/etc/ceph # ls -l /srv/salt/ceph/configuration/ drwxr-xr-x 1 salt salt 18 Oct 5 13:13 cache drwxr-xr-x 1 root root 38 Oct 5 09:04 check drwxr-xr-x 1 root root 74 Oct 5 09:04 create -rw-r--r-- 1 root root 217 May 14 2020 default-import.sls -rw-r--r-- 1 root root 222 May 14 2020 default.sls drwxr-xr-x 1 root root 276 Oct 5 12:55 files -rw-r--r-- 1 root root 74 May 14 2020 init.sls","title":"Task 4: View the Ceph master configuration file"},{"location":"linux/SES/linux_ses_demo/#222-run-the-ceph-health-commands","text":"Get overall health status admin:~ # ceph health HEALTH_OK admin:~ # ceph -s admin:~ # ceph status cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 5w) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 98m), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 208 pgs objects: 246 objects, 4.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 208 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr Run the \u201cstatus\u201d command for the monitors: admin:~ # ceph mon stat e1: 3 mons at { mon1=[v2:10.58.121.186:3300/0,v1:10.58.121.186:6789/0], mon2=[v2:10.58.121.187:3300/0,v1:10.58.121.187:6789/0], mon3=[v2:10.58.121.188:3300/0,v1:10.58.121.188:6789/0] }, election epoch 22, leader 0 mon1, quorum 0,1,2 mon1,mon2,mon3 Run the \u201cstatus\u201d command for the placement groups: admin:~ # ceph pg stat 208 pgs: 208 active+clean; 4.7 KiB data, 2.1 GiB used, 82 GiB / 96 GiB avail; 852 B/s rd, 0 op/s Run the ceph \u201cstatus\u201d command while watching for changes to the status: admin:~ # ceph -s --watch-debug cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 5w) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 104m), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 208 pgs objects: 246 objects, 4.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 208 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr 2021-01-05 20:20:53.947298 mgr.mon1 [DBG] pgmap v1597415: 208 pgs: 208 active+clean; 4.7 KiB data, 2.1 GiB used, 82 GiB / 96 GiB avail; 852 B/s rd, 0 op/s 2021-01-05 20:20:55.949294 mgr.mon1 [DBG] pgmap v1597416: 208 pgs: 208 active+clean; 4.7 KiB data, 2.1 GiB used, 82 GiB / 96 GiB avail; 1.2 KiB/s rd, 1 op/s .......","title":"2.2.2. Run the Ceph Health Commands"},{"location":"linux/SES/linux_ses_demo/#223-manipulate-pools","text":"","title":"2.2.3. Manipulate Pools"},{"location":"linux/SES/linux_ses_demo/#task-1-display-a-list-of-the-current-pools","text":"admin:~ # ceph osd pool ls iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log admin:~ # ceph osd pool ls detail pool 1 'iscsi-images' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 448 lfor 0/448/446 flags hashpspool stripe_width 0 application rbd pool 2 'cephfs_data' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 1395 lfor 0/1374/1372 flags hashpspool stripe_width 0 application cephfs pool 3 'cephfs_metadata' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 1385 lfor 0/975/973 flags hashpspool stripe_width 0 pg_autoscale_bias 4 pg_num_min 16 recovery_priority 5 application cephfs pool 4 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 31 flags hashpspool stripe_width 0 application rgw pool 5 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 33 flags hashpspool stripe_width 0 application rgw pool 6 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 35 flags hashpspool stripe_width 0 application rgw pool 7 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 37 flags hashpspool stripe_width 0 application rgw List pools with their index numbgr. Note how the index numbgr matches the index numbgr of the detail listing above. admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log","title":"Task 1: Display a list of the current pools"},{"location":"linux/SES/linux_ses_demo/#task-2-display-the-usage-data-and-stats-of-the-current-pools","text":"Display pool usages. Note again index \u201cID\u201d for the pool. admin:~ # ceph df RAW STORAGE: CLASS SIZE AVAIL USED RAW USED %RAW USED hdd 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 TOTAL 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 POOLS: POOL ID STORED OBJECTS USED %USED MAX AVAIL iscsi-images 1 389 B 2 192 KiB 0 25 GiB cephfs_data 2 0 B 0 0 B 0 25 GiB cephfs_metadata 3 7.2 KiB 48 1.5 MiB 0 25 GiB .rgw.root 4 1.2 KiB 4 768 KiB 0 25 GiB default.rgw.control 5 0 B 8 0 B 0 25 GiB default.rgw.meta 6 381 B 3 576 KiB 0 25 GiB default.rgw.log 7 35 KiB 208 35 KiB 0 25 GiB admin:~ # ceph df detail RAW STORAGE: CLASS SIZE AVAIL USED RAW USED %RAW USED hdd 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 TOTAL 96 GiB 82 GiB 2.1 GiB 14 GiB 14.81 POOLS: POOL ID STORED OBJECTS USED %USED MAX AVAIL QUOTA OBJECTS QUOTA BYTES DIRTY USED COMPR UNDER COMPR iscsi-images 1 389 B 2 192 KiB 0 25 GiB N/A N/A 2 0 B 0 B cephfs_data 2 0 B 0 0 B 0 25 GiB N/A N/A 0 0 B 0 B cephfs_metadata 3 7.2 KiB 48 1.5 MiB 0 25 GiB N/A N/A 48 0 B 0 B .rgw.root 4 1.2 KiB 4 768 KiB 0 25 GiB N/A N/A 4 0 B 0 B default.rgw.control 5 0 B 8 0 B 0 25 GiB N/A N/A 8 0 B 0 B default.rgw.meta 6 381 B 3 576 KiB 0 25 GiB N/A N/A 3 0 B 0 B default.rgw.log 7 35 KiB 208 35 KiB 0 25 GiB N/A N/A 208 0 B 0 B Display pool usages using rados command admin:~ # rados df POOL_NAME USED OBJECTS CLONES COPIES MISSING_ON_PRIMARY UNFOUND DEGRADED RD_OPS RD WR_OPS WR USED COMPR UNDER COMPR .rgw.root 768 KiB 4 0 12 0 0 0 40 40 KiB 4 4 KiB 0 B 0 B cephfs_data 0 B 0 0 0 0 0 0 0 0 B 0 0 B 0 B 0 B cephfs_metadata 1.5 MiB 48 0 144 0 0 0 0 0 B 111 42 KiB 0 B 0 B default.rgw.control 0 B 8 0 24 0 0 0 0 0 B 0 0 B 0 B 0 B default.rgw.log 35 KiB 208 0 624 0 0 0 5919671 5.6 GiB 3945118 946 KiB 0 B 0 B default.rgw.meta 576 KiB 3 0 9 0 0 0 38 28 KiB 4 3 KiB 0 B 0 B iscsi-images 192 KiB 2 0 6 0 0 0 4184657 4.0 GiB 8 2 KiB 0 B 0 B total_objects 246 total_used 14 GiB total_avail 82 GiB total_space 96 GiB Show the statistics of the pools: admin:~ # ceph osd pool stats pool iscsi-images id 1 client io 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr pool cephfs_data id 2 nothing is going on pool cephfs_metadata id 3 nothing is going on pool .rgw.root id 4 nothing is going on pool default.rgw.control id 5 nothing is going on pool default.rgw.meta id 6 nothing is going on pool default.rgw.log id 7 nothing is going on Show only the statistics about a specific pool: admin:~ # ceph osd pool stats .rgw.root pool .rgw.root id 4 nothing is going on Show which CRUSH Map ruleset was used to create the .rgw.root pool: admin:~ # ceph osd pool get .rgw.root crush_rule crush_rule: replicated_rule Show the list of all the attributes of a pool that can be queried: admin:~ # ceph osd pool get .rgw.root size min_size pg_num pgp_num crush_rule Hashpspool Nodelete Nopgchange Nosizechange write_fadvise_dontneed noscrub|nodeep-scrub hit_set_type hit_set_period hit_set_count hit_set_fpp use_gmt_hitset target_max_objects target_max_bytes cache_target_dirty_ratio cache_target_dirty_high_ratio cache_target_full_ratio cache_min_flush_age cache_min_evict_age erasure_code_profile min_read_recency_for_promote all|min_write_recency_for_promote fast_read|hit_set_grade_decay_rate hit_set_search_last_n scrub_min_interval scrub_max_interval deep_scrub_interval recovery_priority recovery_op_priority scrub_priority compression_mode compression_algorithm compression_required_ratio compression_max_blob_size compression_min_blob_size csum_type|csum_min_block csum_max_block allow_ec_overwrites fingerprint_algorithm pg_autoscale_mode pg_autoscale_bias pg_num_min target_size_bytes target_size_ratio","title":"Task 2: Display the usage data and stats of the current pools"},{"location":"linux/SES/linux_ses_demo/#task-3-create-two-new-pools-one-replicated-one-ec","text":"1). Create a new replicated pool that will be used for storing block data for RBD. Use the standard replicated_ruleset CRUSH Map: It would be tempting to the use the better_ruleset, but this demo environment doesn\u2019t have enough resources for that. This is a demo environment, so the PG numbgrs will be low. In your production environments, be sure to assign an appropriately high numbgr, or use the pg_autoscaler manager module. admin:~ # ceph osd pool create rbd_pool 4 4 replicated replicated_rule pool 'rbd_pool' created 2). Tell the cluster that you expect to have this new rbd_pool to use 50% of the total capacity: admin:~ # ceph osd pool set rbd_pool target_size_ratio .5 set pool 8 target_size_ratio to .5 3). Create a new EC pool that will be used for storing RGW buckets and objects. Use the usable_profile Erasure Code profile that was created in an earlier exercise. And use the ec_rule CRUSH Map ruleset that was created in an earlier exercise: admin:~ # ceph osd pool create bucket_pool 4 4 erasure usable_profile ec_rule pool 'bucket_pool' created 4). Tell the cluster that you expect to have this new bucket_pool to use 100GB of data: POOL_TARGET_SIZE_BYTES_OVERCOMMITTED admin:~ # ceph osd pool set bucket_pool target_size_bytes 100000000000 set pool 9 target_size_bytes to 100000000000 5). Enable the PG Autoscaler feature on the two new pools, to ensure that we have an appropriate assignment of placement groups in the demo cluster: This presumes that you completed an earlier exercise that enable the pg_autoscaler manager module. admin:~ # ceph osd pool set bucket_pool pg_autoscale_mode on set pool 9 pg_autoscale_mode to on admin:~ # ceph osd pool set rbd_pool pg_autoscale_mode on set pool 8 pg_autoscale_mode to on 6). Again display a list of all the pools, which will now include the two new pools that you\u2019ve just created: Notice in the detail listing that the two new pools don\u2019t have an application attribute assigned to them. admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log 8 rbd_pool 9 bucket_pool admin:~ # ceph osd pool ls detail pool 1 'iscsi-images' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 448 lfor 0/448/446 flags hashpspool stripe_width 0 application rbd pool 2 'cephfs_data' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 1395 lfor 0/1374/1372 flags hashpspool stripe_width 0 application cephfs pool 3 'cephfs_metadata' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 1385 lfor 0/975/973 flags hashpspool stripe_width 0 pg_autoscale_bias 4 pg_num_min 16 recovery_priority 5 application cephfs pool 4 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 31 flags hashpspool stripe_width 0 application rgw pool 5 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 33 flags hashpspool stripe_width 0 application rgw pool 6 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 35 flags hashpspool stripe_width 0 application rgw pool 7 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 37 flags hashpspool stripe_width 0 application rgw pool 8 'rbd_pool' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 1415 lfor 0/0/1413 flags hashpspool stripe_width 0 target_size_ratio 0.5 pool 9 'bucket_pool' erasure size 3 min_size 2 crush_rule 3 object_hash rjenkins pg_num 4 pgp_num 4 autoscale_mode on last_change 1410 flags hashpspool stripe_width 8192 target_size_bytes 100000000000 7). Check the pg_autoscale status, particularly to see a comparison of how much raw space is being consumed by the two pools: See that the RATE column for all of the replicated pools shows the value of 3.0, while the value for the bucket_pool \u2013 which is an EC pool \u2013 is 1.5. The EC pool, with a K+M of 2+1 consumes considerably less raw storage space. See the TARGET RATIO for the rbd_pool. Notice that the autoscaler has automatically adjusted the numbgr PGs assigned to rbd_pool from \u201c4\u201d to \u201c128\u201d because you told the cluster to have the pool use 50% of the capacity. See the TARGET SIZE for the bucket_pool, roughly 100GB. But the cluster may not have changed the PG_NUM value yet. The autoscaler will adjust the numbgr of PGs gradually, so as not to disrupt the performance too dramatically. While you\u2019re here, you might also notice the RAW CAPACITY column. All pools are expecting to divide the cluster space equally, even though you\u2019ve explicitly told the cluster that rbd_pool and bucket_pool will deviate from that even division. admin:~ # ceph osd pool autoscale-status POOL SIZE TARGET SIZE RATE RAW CAPACITY RATIO TARGET RATIO EFFECTIVE RATIO BIAS PG_NUM NEW PG_NUM AUTOSCALE iscsi-images 389 3.0 98256M 0.0000 1.0 32 on cephfs_data 0 3.0 98256M 0.0000 1.0 32 off cephfs_metadata 7412 3.0 98256M 0.0000 4.0 16 off .rgw.root 1245 3.0 98256M 0.0000 1.0 32 warn default.rgw.control 0 3.0 98256M 0.0000 1.0 32 warn default.rgw.meta 381 3.0 98256M 0.0000 1.0 32 warn default.rgw.log 35900 3.0 98256M 0.0000 1.0 32 warn rbd_pool 0 3.0 98256M 0.0000 0.5000 1.0 32 on bucket_pool 0 95367M 1.5 98256M 1.4559 1.0 4 on","title":"Task 3: Create two new pools, one replicated, one EC"},{"location":"linux/SES/linux_ses_demo/#task-4-assign-an-application-to-the-two-new-pools","text":"1). Assign the rbd application to the new rbd_pool that you created in the previous task: admin:~ # ceph osd pool application enable rbd_pool rbd enabled application 'rbd' on pool 'rbd_pool' 2). Instruct the cluster to prepare the new rbd_pool for storing block device images: admin:~ # rbd pool init rbd_pool 3). Assign the rgw application to the new bucket_pool that you created in the previous task: admin:~ # ceph osd pool application enable bucket_pool rgw enabled application 'rgw' on pool 'bucket_pool' 4). Display a list of all the pools again, this time noticing that the application attribute is set on the two new pools. admin:~ # ceph osd lspools 1 iscsi-images 2 cephfs_data 3 cephfs_metadata 4 .rgw.root 5 default.rgw.control 6 default.rgw.meta 7 default.rgw.log 8 rbd_pool 9 bucket_pool admin:~ # ceph osd pool ls detail pool 1 'iscsi-images' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 448 lfor 0/448/446 flags hashpspool stripe_width 0 application rbd pool 2 'cephfs_data' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 1395 lfor 0/1374/1372 flags hashpspool stripe_width 0 application cephfs pool 3 'cephfs_metadata' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 16 pgp_num 16 last_change 1385 lfor 0/975/973 flags hashpspool stripe_width 0 pg_autoscale_bias 4 pg_num_min 16 recovery_priority 5 application cephfs pool 4 '.rgw.root' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 31 flags hashpspool stripe_width 0 application rgw pool 5 'default.rgw.control' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 33 flags hashpspool stripe_width 0 application rgw pool 6 'default.rgw.meta' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 35 flags hashpspool stripe_width 0 application rgw pool 7 'default.rgw.log' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode warn last_change 37 flags hashpspool stripe_width 0 application rgw pool 8 'rbd_pool' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 autoscale_mode on last_change 1420 lfor 0/0/1413 flags hashpspool,selfmanaged_snaps stripe_width 0 target_size_ratio 0.5 application rbd removed_snaps [1~3] pool 9 'bucket_pool' erasure size 3 min_size 2 crush_rule 3 object_hash rjenkins pg_num 4 pgp_num 4 autoscale_mode on last_change 1422 flags hashpspool stripe_width 8192 target_size_bytes 100000000000 application rgw 5). Another way to display which application is assigned to a pool is: admin:~ # ceph osd pool application get bucket_pool { \"rgw\": {} } admin:~ # ceph osd pool application get rbd_pool { \"rbd\": {} }","title":"Task 4: Assign an application to the two new pools"},{"location":"linux/SES/linux_ses_demo/#task-5-manage-snapshots-of-the-new-rgw-bucket-pool","text":"1). Display a list of the snapshots that exist of the bucket_pool that you created in the previous task: The output show that there are \u201c0 snaps.\u201d Right, it is a little funny that you only list the snapshots with rados command; no such functionality exists with the ceph osd pool command. admin:~ # rados -p bucket_pool lssnap 0 snaps 2). Take (make) a snapshot of the rbd_pool: admin:~ # ceph osd pool mksnap bucket_pool brand_new_pool_snapshot created pool bucket_pool snap brand_new_pool_snapshot 3). Display the list of the snapshots again: admin:~ # rados -p bucket_pool lssnap 1 brand_new_pool_snapshot 2021.01.05 22:23:23 1 snaps 4). Remove the snapshot: admin:~ # ceph osd pool rmsnap bucket_pool brand_new_pool_snapshot removed pool bucket_pool snap brand_new_pool_snapshot 5). Display the list of the snapshots again: admin:~ # rados -p bucket_pool lssnap 0 snaps","title":"Task 5: Manage snapshots of the new RGW bucket pool"},{"location":"linux/SES/linux_ses_demo/#224-maintain-consistency-of-data-with-scrub-and-repair","text":"Scrubbing is like \u201cfsck,\u201d which ensures that OSDs have durable, consistent data. Most of the scrubbing of OSDs happens automatically on a periodic basis.","title":"2.2.4. Maintain consistency of data with Scrub and Repair"},{"location":"linux/SES/linux_ses_demo/#task-1-display-a-few-of-the-scrub-settings","text":"1). Show the possible configuration settings related to scrub: If you simply grep for \u201cscrub\u201d you\u2019ll get more than you really want; there are some mon_scrub settings that aren\u2019t related to this exercise. admin:~ # ceph config ls | grep osd_scrub osd_scrub_invalid_stats osd_scrub_during_recovery osd_scrub_begin_hour osd_scrub_end_hour osd_scrub_begin_week_day osd_scrub_end_week_day osd_scrub_load_threshold osd_scrub_min_interval osd_scrub_max_interval osd_scrub_interval_randomize_ratio osd_scrub_backoff_ratio osd_scrub_chunk_min osd_scrub_chunk_max osd_scrub_sleep osd_scrub_auto_repair osd_scrub_auto_repair_num_errors osd_scrub_max_preemptions osd_scrub_priority osd_scrub_cost admin:~ # ceph config ls | grep osd_deep_scrub osd_deep_scrub_interval osd_deep_scrub_randomize_ratio osd_deep_scrub_stride osd_deep_scrub_keys osd_deep_scrub_update_digest_min_age osd_deep_scrub_large_omap_object_key_threshold osd_deep_scrub_large_omap_object_value_sum_threshold admin:~ # ceph config ls | grep scrub mon_warn_pg_not_scrubbed_ratio mon_warn_pg_not_deep_scrubbed_ratio mon_scrub_interval mon_scrub_timeout mon_scrub_max_keys mon_scrub_inject_crc_mismatch mon_scrub_inject_missing_keys osd_op_queue_mclock_scrub_res osd_op_queue_mclock_scrub_wgt osd_op_queue_mclock_scrub_lim osd_scrub_invalid_stats osd_max_scrubs osd_scrub_during_recovery osd_scrub_begin_hour osd_scrub_end_hour osd_scrub_begin_week_day osd_scrub_end_week_day osd_scrub_load_threshold osd_scrub_min_interval osd_scrub_max_interval osd_scrub_interval_randomize_ratio osd_scrub_backoff_ratio osd_scrub_chunk_min osd_scrub_chunk_max osd_scrub_sleep osd_scrub_auto_repair osd_scrub_auto_repair_num_errors osd_scrub_max_preemptions osd_deep_scrub_interval osd_deep_scrub_randomize_ratio osd_deep_scrub_stride osd_deep_scrub_keys osd_deep_scrub_update_digest_min_age osd_deep_scrub_large_omap_object_key_threshold osd_deep_scrub_large_omap_object_value_sum_threshold osd_debug_deep_scrub_sleep osd_scrub_priority osd_scrub_cost osd_requested_scrub_priority mds_max_scrub_ops_in_progress 2). Get the value of a few of the different scrub schedule settings: Note that \u201c0\u201d and \u201c24\u201d are the same setting. admin:~ # ceph config get osd.* osd_scrub_begin_hour 0 admin:~ # ceph config get osd.* osd_scrub_end_hour 24 3). Get the value of the scrub and repair settings: The \u201cauto repair\u201d feature is turned off, and the maximum numbgr of errors that \u201cauto repair\u201d would automatically repair is 5. admin:~ # ceph config get osd.* osd_scrub_auto_repair false admin:~ # ceph config get osd.* osd_scrub_auto_repair_num_errors 5","title":"Task 1: Display a few of the Scrub settings"},{"location":"linux/SES/linux_ses_demo/#task-2-change-the-scrub-settings-in-cephconf","text":"1). Display the ceph.conf, and verify that the file doesn\u2019t have any settings defined yet that are related to scrub. The settings would be located in the [global] section of the file: # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.186, 10.58.121.187, 10.58.121.188 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] 2). Change to the Salt File Server directory that will have Salt control the master ceph.conf configuration file: admin:~ # cd /srv/salt/ceph/configuration/files/ceph.conf.d/ 3). List the content of the directory: The directory is empty. (Well, there is a README, but no other functional files.) admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ls -l -rw-r--r-- 1 root root 1989 May 14 2020 README 4). Create and edit a new file called global.conf. You don\u2019t have to use vi, but this step uses vi as one way of doing it: Be sure that you spell everything correctly, including the absence of \u201c_\u201d characters; there are spaces. Save the file and exit out of the editor. admin:/srv/salt/ceph/configuration/files/ceph.conf.d # vi global.conf Add the following content to the file: osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 5). Use DeepSea (Salt) to stage the file properly in Salt\u2019s File Server on the Salt Master (admin): admin:/srv/salt/ceph/configuration/files/ceph.conf.d # salt admin* state.apply ceph.configuration.create admin.sha.me.corp: Name: /var/cache/salt/minion/files/base/ceph/configuration - Function: file.absent - Result: Changed Started: - 22:42:34.900173 Duration: 20.891 ms Name: /srv/salt/ceph/configuration/cache/ceph.conf - Function: file.managed - Result: Changed Started: - 22:42:34.921454 Duration: 8576.516 ms Name: find /var/cache/salt/master/jobs -user root -exec chown salt:salt {} ';' - Function: cmd.run - Result: Changed Started: - 22:42:43.535022 Duration: 71.957 ms Summary for admin.sha.me.corp ------------ Succeeded: 3 (changed=3) Failed: 0 ------------ Total states run: 3 Total run time: 8.669 s 6). Using DeepSea (Salt), distribute the new ceph.conf configuration settings to all the nodes in the cluster: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # salt \\* state.apply ceph.configuration mon3.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:07.986661 Duration: 101.977 ms Summary for mon3.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 101.977 ms mon1.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.012479 Duration: 108.888 ms Summary for mon1.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 108.888 ms data3.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.052247 Duration: 98.681 ms Summary for data3.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 98.681 ms admin.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.072402 Duration: 97.231 ms Summary for admin.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 97.231 ms data1.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.076279 Duration: 104.169 ms Summary for data1.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 104.169 ms data4.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.081635 Duration: 105.13 ms Summary for data4.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 105.130 ms mon2.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.155758 Duration: 105.004 ms Summary for mon2.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 105.004 ms data2.sha.me.corp: Name: /etc/ceph/ceph.conf - Function: file.managed - Result: Changed Started: - 22:44:08.252200 Duration: 109.552 ms Summary for data2.sha.me.corp ------------ Succeeded: 1 (changed=1) Failed: 0 ------------ Total states run: 1 Total run time: 109.552 ms 7). Verify that the new ceph.conf settings have been put into place on the admin node: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # cat /etc/ceph/ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] 8). Also verify that other minions in the cluster have also received the updated configuration file, such as on the mon1 and data2 nodes: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ssh mon1 cat /etc/ceph/ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ssh data1 cat /etc/ceph/ceph.conf # DeepSea default configuration. Changes in this file will be overwritten on # package update. Include custom configuration fragments in # /srv/salt/ceph/configuration/files/ceph.conf.d/[global,osd,mon,mgr,mds,client].conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_initial_membgrs = mon1, mon2, mon3 mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx public_network = 10.58.120.0/23 cluster_network = 10.58.120.0/23 ms_bind_msgr2 = false # enable old ceph health format in the json output. This fixes the # ceph_exporter. This option will only stay until the prometheus plugin takes # over mon_health_preluminous_compat = true mon health preluminous compat warning = false rbd default features = 3 osd scrub begin hour = 23 osd scrub end hour = 5 osd scrub auto repair = True osd scrub auto repair num errors = 10 [client.rgw.mon3] rgw frontends = \"beast port=80\" rgw dns name = mon3.sha.me.corp rgw enable usage log = true [osd] [mon] [mgr] [mds] [client] 9). Apply the settings of the ceph.conf file to appropriate nodes in the cluster: admin:/srv/salt/ceph/configuration/files/ceph.conf.d # ceph config assimilate-conf -i /etc/ceph/ceph.conf [global] fsid = 343ee7d3-232f-4c71-8216-1edbc55ac6e0 mon_health_preluminous_compat = true mon_health_preluminous_compat_warning = false mon_host = 10.58.121.188, 10.58.121.187, 10.58.121.186 mon_initial_membgrs = mon1, mon2, mon3","title":"Task 2: Change the Scrub settings in ceph.conf"},{"location":"linux/SES/linux_ses_demo/#task-3-change-the-scrub-settings-directly-in-the-configuration-db","text":"1). Query the configuration database to see the value of \u201cosd_scrub_auto_repair_num_errors\u201d: You changed this value to \u201c10\u201d in the previous Task. admin:~ # ceph config get osd.* osd_scrub_auto_repair_num_errors 10 2). Change the value of \u201cosd_scrub_auto_repair_num_errors\u201d to \u201c8\u201d: admin:~ # ceph config set osd.* osd_scrub_auto_repair_num_errors 8 3). Show that the change has taken immediate effect by re-running the same command that was used in the first step: admin:~ # ceph config get osd.* osd_scrub_auto_repair_num_errors 8","title":"Task 3: Change the Scrub settings directly in the Configuration DB"},{"location":"linux/SES/linux_ses_demo/#task-4-manually-scrub-and-repair-an-osd-and-a-pg","text":"This won\u2019t do much in this demo environment, because the OSDs aren\u2019t storing very much data. But it\u2019s worth having some practice. 1). Start a scrubbing of one of the OSDs: admin:~ # ceph osd scrub osd.1 instructed osd(s) 1 to scrub 2). Scrub a Placement Group: admin:~ # ceph pg scrub 8.1 instructing pg 8.1 on osd.0 to scrub 3). Repair an OSD: admin:~ # ceph osd repair osd.1 instructed osd(s) 1 to repair 4). Repair a PG: admin:~ # ceph pg repair 8.1 instructing pg 8.1 on osd.0 to repair 5). Show what\u2019s currently happening to the OSD that you instructed to have scrubbed and repaired: admin:~ # ceph osd dump | grep osd.1 max_osd 12 osd.1 up in weight 1 up_from 10 up_thru 1415 down_at 0 last_clean_interval [0,0) v1:10.58.121.185:6800/11157 v1:10.58.121.185:6801/11157 exists,up 32c78078-1878-4fac-9738-00d8bf80deea osd.10 up in weight 1 up_from 18 up_thru 1413 down_at 0 last_clean_interval [0,0) v1:10.58.121.182:6808/11130 v1:10.58.121.182:6809/11130 exists,up 6cb26fdc-09b1-42de-8855-7203931a0101 osd.11 up in weight 1 up_from 18 up_thru 1415 down_at 0 last_clean_interval [0,0) v1:10.58.121.185:6808/11995 v1:10.58.121.185:6809/11995 exists,up cc22107d-0239-4874-8308-6c137c8a0931 6). Show what\u2019s currently happening to the PG that you instructed to have scrubbed and repaired: admin:~ # ceph pg dump | grep \"8\\.1\" dumped all 8.16 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.383909 0'0 1423:27 [6,4,5] 6 [6,4,5] 6 0'0 2021-01-05 20:53:47.314062 0'0 2021-01-05 20:53:47.314062 0 8.17 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:01.044252 0'0 1424:30 [1,6,8] 1 [1,6,8] 1 0'0 2021-01-05 22:57:01.044098 0'0 2021-01-05 22:57:01.044098 0 8.14 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:56:56.081480 0'0 1424:30 [1,2,4] 1 [1,2,4] 1 0'0 2021-01-05 22:56:56.081356 0'0 2021-01-05 22:56:56.081356 0 8.15 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.375386 0'0 1423:27 [3,5,0] 3 [3,5,0] 3 0'0 2021-01-05 20:53:53.231124 0'0 2021-01-05 20:48:05.301705 0 8.12 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.370121 0'0 1423:27 [11,2,8] 11 [11,2,8] 11 0'0 2021-01-05 20:53:48.149449 0'0 2021-01-05 20:48:05.301705 0 2.18 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 16:44:58.986205 0'0 1423:1630 [10,1,8] 10 [10,1,8] 10 0'0 2021-01-05 13:02:00.365382 0'0 2021-01-02 00:38:58.134100 0 8.13 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.387832 0'0 1423:27 [0,8,1] 0 [0,8,1] 0 0'0 2021-01-05 20:53:56.132358 0'0 2021-01-05 20:48:05.301705 0 8.10 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.368416 0'0 1423:27 [11,3,6] 11 [11,3,6] 11 0'0 2021-01-05 20:53:51.152790 0'0 2021-01-05 20:48:05.301705 0 8.11 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.377871 0'0 1423:24 [3,10,5] 3 [3,10,5] 3 0'0 2021-01-05 20:53:45.195257 0'0 2021-01-05 20:48:05.301705 0 8.1e 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.391754 0'0 1423:47 [0,11,8] 0 [0,11,8] 0 0'0 2021-01-05 20:53:55.081582 0'0 2021-01-05 20:48:05.301705 0 8.1 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:56:39.829397 0'0 1424:54 [0,7,10] 0 [0,7,10] 0 0'0 2021-01-05 22:56:39.829241 0'0 2021-01-05 22:56:39.829241 0 8.1f 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.392315 0'0 1423:27 [7,5,9] 7 [7,5,9] 7 0'0 2021-01-05 20:53:59.988252 0'0 2021-01-05 20:48:05.301705 0 5.4 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 18:21:28.179266 0'0 1423:1554 [7,9,6] 7 [7,9,6] 7 0'0 2021-01-05 18:21:28.179166 0'0 2021-01-05 18:21:28.179166 0 5.b 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 18:37:01.467457 0'0 1423:1547 [2,0,11] 2 [2,0,11] 2 0'0 2021-01-04 23:46:58.132824 0'0 2021-01-02 03:35:41.214192 0 8.19 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:06.059090 0'0 1424:30 [1,8,2] 1 [1,8,2] 1 0'0 2021-01-05 22:57:06.058935 0'0 2021-01-05 22:57:06.058935 0 8.18 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:05.097742 0'0 1424:30 [1,3,6] 1 [1,3,6] 1 0'0 2021-01-05 22:57:05.097670 0'0 2021-01-05 22:57:05.097670 0 1.11 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 00:30:18.193988 0'0 1423:1605 [0,8,6] 0 [0,8,6] 0 0'0 2021-01-05 00:30:18.193868 0'0 2020-12-29 06:30:58.897565 0 8.1b 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 22:57:13.146469 0'0 1424:30 [1,4,6] 1 [1,4,6] 1 0'0 2021-01-05 22:57:13.146390 0'0 2021-01-05 22:57:13.146390 0 8.1a 1 0 0 0 0 19 0 0 2 2 active+clean 2021-01-05 21:01:16.386166 1420'2 1423:29 [9,11,10] 9 [9,11,10] 9 0'0 2021-01-05 20:53:48.690239 0'0 2021-01-05 20:48:05.301705 0 8.1d 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.388079 0'0 1423:56 [0,2,3] 0 [0,2,3] 0 0'0 2021-01-05 20:53:54.121281 0'0 2021-01-05 20:48:05.301705 0 8.1c 0 0 0 0 0 0 0 0 0 0 active+clean 2021-01-05 21:01:16.385846 0'0 1423:27 [2,11,7] 2 [2,11,7] 2 0'0 2021-01-05 20:53:55.458714 0'0 2021-01-05 20:48:05.301705 0","title":"Task 4: Manually scrub and repair an OSD and a PG"},{"location":"linux/SES/linux_ses_demo/#225-manipulate-manager-modules","text":"","title":"2.2.5. Manipulate Manager Modules"},{"location":"linux/SES/linux_ses_demo/#task-1-display-the-list-of-enabled-manager-modules","text":"1). Run the following command to show the list of enabled manager modules: Note that several modules are already enabled, such as: dashboard, iostat, pg_autosclater, prometheus, and restful. Even though they are not listed, the crash module and the balancer module are already enabled by default. admin:~ # ceph mgr module ls | head { \"always_on_modules\": [ \"balancer\", \"crash\", \"devicehealth\", \"orchestrator_cli\", \"progress\", \"rbd_support\", \"status\", \"volumes\" 2). Demonstrate that the crash module is enabled by running its command with no arguments: A list of \u201c7 closest matches\u201d is displayed, representing possible additional arguments to be used with the crash command. The crash module is therefore available. admin:~ # ceph crash crash info crash ls crash ls-new crash post crash prune crash rm crash stat crash json_report crash archive crash archive-all admin:~ # ceph crash stat 0 crashes recorded Task 2: Use the iostat module to display statistics for the IO of the cluster The iostat module is really simple, but very helpful. Run the command: admin:~ # ceph iostat +-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+ | Read | Write | Total | Read IOPS | Write IOPS | Total IOPS | +-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+-----------------------------+ | 1024 B/s | 0 B/s | 1024 B/s | 1 | 0 | 1 | | 1024 B/s | 0 B/s | 1024 B/s | 1 | 0 | 1 | | 0 B/s | 0 B/s | 0 B/s | 0 | 0 | 0 | Task 3: Enable and configure the telemetry manager module 1). Enable the telemetry manager module: admin:~ # ceph mgr module enable telemetry 2). Show the various sub-commands that are associated with the telemetry command: A list of \u201c5 closest matches\u201d is displayed, showing various options. admin:~ # ceph telemetry telemetry status telemetry send {ceph|device [ceph|device...]} {} telemetry show { [...]} telemetry show-device telemetry on {} telemetry off 3). Show the status of the telemetry module: Notice that the output is returned as key/value pairs. Notice also that although the module has been enabled (which you accomplished in the first step of this task), the functionality is not enabled (enable=false). And for most of the keys, a null value is set. See that the url value is set to https://telemetry.ceph.com/report. That means that crash reports and other usage information about this cluster are going to be sent to the Ceph Community. admin:~ # ceph telemetry status { \"url\": \"https://telemetry.ceph.com/report\", \"device_url\": \"https://telemetry.ceph.com/device\", \"enabled\": false, \"last_opt_revision\": 1, \"leaderboard\": false, \"description\": null, \"contact\": null, \"organization\": null, \"proxy\": null, \"interval\": 24, \"channel_basic\": true, \"channel_ident\": false, \"channel_crash\": true, \"channel_device\": true, \"last_upload\": null } 4). Set the description, contact, and organization values: admin:~ # ceph config set mgr mgr/telemetry/contact 'JD ' admin:~ # ceph config set mgr mgr/telemetry/description 'Training Cluster' admin:~ # ceph config set mgr mgr/telemetry/organization 'SUSE Training' 5). Display the telemetry data that is collected to be sent: admin:~ # ceph telemetry show | less 6). With the contact information properly set, enable the telemetry functionality: This is a demo cluster with no connection to the internet, so no telemetry data will actually be sent. admin:~ # ceph telemetry on Error EPERM: Telemetry data is licensed under the Community Data License Agreement - Sharing - Version 1.0 (https://cdla.io/sharing-1-0/). To enable, add '--license sharing-1-0' to the 'ceph telemetry on' command. admin:~ # ceph telemetry on --license sharing-1-0 7). Disable the telemetry module: admin:~ # ceph mgr module disable telemetry admin:~ # ceph telemetry show | less Error ENOTSUP: Module 'telemetry' is not enabled (required by command 'telemetry show'): use `ceph mgr module enable telemetry` to enable it","title":"Task 1: Display the list of enabled Manager Modules"},{"location":"linux/SES/linux_ses_demo/#task-4-briefly-attempt-to-use-the-crash-manager-module","text":"1). Show (again) the various sub-commands that are associated with the crash command: admin:~ # ceph crash crash info crash ls crash ls-new crash post crash prune crash rm crash stat crash json_report crash archive crash archive-all 2). Show the current status of the crash database, including the numbgr of crash reports that have been collected so far: It\u2019s likely that the numbgr of crashes recorded in the demo environment is 0. admin:~ # ceph crash stat 0 crashes recorded","title":"Task 4: Briefly attempt to use the crash manager module"},{"location":"linux/SES/linux_ses_demo/#226-introduction-to-the-tell-command","text":"Tell is a very powerful command within Ceph to control the cluster. You don\u2019t use it everyday, but you need to know how to use it when the occasion to use it arises. It\u2019s mostly an Advanced Command, but exposure to it now reduces the stress of learning about it in a more advanced setting later. Run the tell command in a few different circumstances to control the behavior of various Ceph services.","title":"2.2.6. Introduction to the Tell command"},{"location":"linux/SES/linux_ses_demo/#task-1-run-a-benchmark-test-on-an-osd","text":"1). Run the following command to run and see the result of a benchmark test on osd.8: admin:~ # ceph tell osd.8 bench { \"bytes_written\": 1073741824, \"blocksize\": 4194304, \"elapsed_sec\": 3.7797023200000002, \"bytes_per_sec\": 284081055.35676152, \"iops\": 67.730201567831401 }","title":"Task 1: Run a benchmark test on an OSD"},{"location":"linux/SES/linux_ses_demo/#task-2-change-the-protection-setting-regarding-the-deletion-of-pools","text":"1). The default behavior in Ceph is that you can\u2019t delete pools. Try to delete a pool: The output says that you have to be VERY careful and provide more arguments in order to delete a pool admin:~ # ceph osd pool delete rbd_pool Error EPERM: WARNING: this will *PERMANENTLY DESTROY* all data stored in pool rbd_pool. If you are *ABSOLUTELY CERTAIN* that is what you want, pass the pool name *twice*, followed by --yes-i-really-really-mean-it. 2). Try deleting the pool again, this time with the extra arguments: Ceph still won\u2019t let you do it because the mon allow pool delete setting has the value of false. admin:~ # ceph osd pool delete rbd_pool rbd_pool --yes-i-really-really-mean-it Error EPERM: pool deletion is disabled; you must first set the mon_allow_pool_delete config option to true before you can destroy a pool 3). Show that the mon allow pool delete setting has the value of false: Indeed, the output shows that the value is false. admin:~ # ceph config get mon.mon\\* mon_allow_pool_delete false 4). Change to value of the setting using injectargs: Note that the \u201c-\u201d and \u201c_\u201d characters can be confusing. And note that the setting is preceded with the double \u201c--\u201d. The injected args must be enclosed in single quotes. You could have done this with ceph config set, but this is an alternative way to directly \u201ctell\u201d the cluster to change a setting. admin:~ # ceph tell mon.\\* injectargs '--mon-allow-pool-delete=true' mon.mon1: injectargs:mon_allow_pool_delete = 'true' mon.mon2: injectargs:mon_allow_pool_delete = 'true' mon.mon3: injectargs:mon_allow_pool_delete = 'true'","title":"Task 2: Change the protection setting regarding the deletion of pools"},{"location":"linux/SES/linux_ses_demo/#23-ceph-dashboard","text":"","title":"2.3. Ceph Dashboard"},{"location":"linux/SES/linux_ses_demo/#231-access-dashboard","text":"","title":"2.3.1. Access Dashboard"},{"location":"linux/SES/linux_ses_demo/#task-1-set-the-password-for-the-admin-user-of-the-ceph-dashboard","text":"1). In a Bash terminal as the root user, show that the Dashboard module is enabled: \u201cdashboard\u201d should be included in the list of \u201cenabled_modules\u201d at the top of the output. admin:~ # ceph mgr module ls | more \"enabled_modules\": [ \"dashboard\", \"iostat\", \"pg_autoscaler\", \"prometheus\", \"restful\" ], 2). Show the valid dashboard users that have already been created by DeepSea during initial deployment: It\u2019s possible that other users will be listed, but at least the \u201cadmin\u201d user should be displayed in the output. admin:~ # ceph dashboard ac-user-show [\"admin\"] 3). Show the \u201cadmin\u201d user\u2019s information as stored in the user database: You can see that the admin user has a password set, but it is stored as a hash. So you don\u2019t really know what the password is, and have no way of discovering it. admin:~ # ceph dashboard ac-user-show admin {\"username\": \"admin\", \"password\": , \"roles\": [\"administrator\"], \"name\": null, \"email\": null, \"lastUpdate\": 1601874928} 4). Change the \u201cadmin\u201d user\u2019s password for the dashboard: This sets the \u201cadmin\u201d user\u2019s password to the string: mypassword admin:~ # ceph dashboard ac-user-set-password admin mypassword {\"username\": \"admin\", \"password\": , \"roles\": [\"administrator\"], \"name\": null, \"email\": null, \"lastUpdate\": 1609860842} admin:~ #","title":"Task 1: Set the password for the admin user of the Ceph Dashboard"},{"location":"linux/SES/linux_ses_demo/#task-3-visit-the-ceph-dashboard-url","text":"admin:~ # salt-call grains.get dashboard_creds local: ---------- admin: admin:~ # ceph mgr services { \"dashboard\": \"https://mon1.sha.me.corp:8443/\", \"prometheus\": \"http://mon1.sha.me.corp:9283/\" } admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 25m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 5h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 9 pools, 244 pgs objects: 247 objects, 5.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 244 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr URL: https://mon1.sha.me.corp:8443/ https://10.58.121.186:8443","title":"Task 3: Visit the Ceph Dashboard URL"},{"location":"linux/SES/linux_ses_demo/#232-explore-the-dashboard-health-performance-status","text":"Dashboard Status Cluster Status Monitors OSDs Manager Daemons Hosts Object Gateway Metadata Service iSCSI Gateway Performance Client IOPS Client Throughput Client Read/Write Recovery Throughput Scrub Capacity Pools Raw Capacity Objects PGs per OSD PG Status [SUSE Enterprise Storage Portal Cluster\u2192Configuration Cluster\u2192Manager Modules Pools\u2192Create Pool","title":"2.3.2. Explore the Dashboard Health, Performance, Status"},{"location":"linux/SES/linux_ses_demo/#24-storage-data-access","text":"","title":"2.4. Storage Data Access"},{"location":"linux/SES/linux_ses_demo/#241-ensure-the-ses-cluster-is-healthy","text":"","title":"2.4.1. Ensure the SES Cluster is Healthy"},{"location":"linux/SES/linux_ses_demo/#task-1-check-the-clusters-health","text":"1). Run the following command to check the status (health) of the SES cluster: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 9w) mgr: mon1(active, since 18h) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 23h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 5.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr 2). Evaluate the output. The cluster in this demonstration environment often doesn\u2019t startup correctly due to the nature of a demo environment and it\u2019s less-predictable resources. Depending on whether any of the following tasks are necessary, followup accordingly to ensure that the cluster is healthy before proceeding with the course lectures or any further exercises. 3). Run the following series of commands to restart the Monitor daemons on each of the Monitor nodes: It\u2019s certainly not necessary to restart the monitor daemons on all of the monitor nodes if only one is down. If you prefer, you can take a different approach to starting the daemon on a single monitor node. admin:~ # for h in mon1 mon2 mon3; \\ do \\ ssh $h systemctl restart ceph-mon@$h; \\ done 4). After waiting a few moments for the daemons to restart, check the status again: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 15s) mgr: mon1(active, since 21h) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 26h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 5.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 767 B/s rd, 0 op/s rd, 0 op/s wr 5). Run the following series of commands to restart the Manager daemons on each of the Monitor nodes: admin:~ # for h in mon1 mon2 mon3; \\ do \\ ssh $h systemctl restart ceph-mgr@$h; \\ done 6). After waiting a few moments for the daemons to restart, check the status again: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 8m) mgr: mon1(active, since 18s) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 26h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.1 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr 7). Run the following command to restart the MDS daemon on the MDS node (mon1): admin:~ # ssh mon1 systemctl restart ceph-mds@mon1.service 8). After waiting a few moments for the mds daemon to restart, check the status again: Look for the mds service to be plain active rather than laggy or crashed admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 17m) mgr: mon1(active, since 8m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 26h), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.2 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr 9). Verify if the OSDs \u201cup\u201d and running properly. It is only necessary if the output of ceph -s shows that there are fewer than 9 OSDs shown as being \u201cup\u201d. It\u2019s most likely that a storage node is simply not quite fully booted yet, such that the OSD daemons haven\u2019t fully come up. But if you suspect that the solution requires something different than simply waiting a little longer, you should try the following steps. First, identify which server is hosting the down\u2019d OSDs. One way of doing that is with this command: admin:~ # ceph osd tree ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF -1 0.09357 root default -9 0.02339 host data1 2 hdd 0.00780 osd.2 up 1.00000 1.00000 6 hdd 0.00780 osd.6 up 1.00000 1.00000 10 hdd 0.00780 osd.10 up 1.00000 1.00000 -3 0.02339 host data2 0 hdd 0.00780 osd.0 up 1.00000 1.00000 4 hdd 0.00780 osd.4 up 1.00000 1.00000 9 hdd 0.00780 osd.9 up 1.00000 1.00000 -7 0.02339 host data3 3 hdd 0.00780 osd.3 up 1.00000 1.00000 7 hdd 0.00780 osd.7 up 1.00000 1.00000 8 hdd 0.00780 osd.8 up 1.00000 1.00000 -5 0.02339 host data4 1 hdd 0.00780 osd.1 up 1.00000 1.00000 5 hdd 0.00780 osd.5 up 1.00000 1.00000 11 hdd 0.00780 osd.11 up 1.00000 1.00000 Simply try restarting the storage daemon processes on the affected host, such as with this example: admin:~ # ssh data2 systemctl restart ceph-osd@9.service admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 32m) mgr: mon1(active, since 24m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 27s), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.2 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 852 B/s rd, 0 op/s rd, 0 op/s wr If the OSD daemon processes are being stubborn and uncooperative, you may choose to reboot the storage virtual machine entirely. This is one way to do that: admin:~ # ssh data1 systemctl reboot After waiting some time for the daemons to get started, verify that all the OSDs are \u201cup\u201d and that the cluster is healthy: admin:~ # ceph osd tree admin:~ # ceph status 10). Run the following command to restart the RADOS Gateway daemon on the node that is hosting the gateway (mon3): admin:~ # ssh mon3 systemctl restart ceph-radosgw@rgw.mon3.service admin:~ # ssh mon3 systemctl status ceph-radosgw@rgw.mon3.service \u25cf ceph-radosgw@rgw.mon3.service - Ceph rados gateway Loaded: loaded (/usr/lib/systemd/system/ceph-radosgw@.service; enabled; vendor preset: disabled) Active: active (running) since Wed 2021-01-06 21:37:53 CST; 23s ago Main PID: 781880 (radosgw) Tasks: 588 CGroup: /system.slice/system-ceph\\x2dradosgw.slice/ceph-radosgw@rgw.mon3.service \u2514\u2500781880 /usr/bin/radosgw -f --cluster ceph --name client.rgw.mon3 --setuser ceph --setgroup ceph Jan 06 21:37:53 mon3 systemd[1]: Started Ceph rados gateway. 11). After waiting a few moments for the daemon to restart, check the status again: admin:~ # ceph -s cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_WARN 1 subtrees have overcommitted pool target_size_bytes 1 pools have too few placement groups services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 39m) mgr: mon1(active, since 30m) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 6m), 12 in (since 3M) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 10 pools, 248 pgs objects: 247 objects, 6.2 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 248 active+clean io: client: 1.2 KiB/s rd, 1 op/s rd, 0 op/s wr","title":"Task 1: Check the Cluster\u2019s health"},{"location":"linux/SES/linux_ses_demo/#242-use-the-s3-api-to-interact-with-the-rados-gateway","text":"In this lab we used the s3cmd and radosgw-admin utilities to interact with the SUSE Enterprise Storage cluster. We created a new user, a new bucket, and a new file. We then uploaded the file to the cluster and verified that the object gateway stored it to the cluster.","title":"2.4.2. Use the S3 API to Interact with the RADOS Gateway"},{"location":"linux/SES/linux_ses_demo/#task-1-using-the-s3cmd-tool-and-create-an-s3-user","text":"1). As the root user (password is linux) in a shell or terminal, verify that the s3cmd is available on the admin node: You will likely see an error about configuration files missing, etc. This is enough information to validate the utility is installed. admin:~ # pip --version pip 10.0.1 from /usr/lib/python3.6/site-packages/pip (python 3.6) admin:~ # pip install s3cmd Collecting s3cmd Downloading https://files.pythonhosted.org/packages/26/44/19e08f69b2169003f7307565f19449d997895251c6a6566ce21d5d636435/s3cmd-2.1.0-py2.py3-none-any.whl (145kB) 100% | 153kB 2.7MB/s Collecting python-magic (from s3cmd) Downloading https://files.pythonhosted.org/packages/59/77/c76dc35249df428ce2c38a3196e2b2e8f9d2f847a8ca1d4d7a3973c28601/python_magic-0.4.18-py2.py3-none-any.whl Requirement already satisfied: python-dateutil in /usr/lib/python3.6/site-packages (from s3cmd) (2.7.3) Requirement already satisfied: six>=1.5 in /usr/lib/python3.6/site-packages (from python-dateutil->s3cmd) (1.11.0) Installing collected packages: python-magic, s3cmd Successfully installed python-magic-0.4.18 s3cmd-2.1.0 2). Create a new S3 user to be used: The output will include an access_key value and a secret_key value. You will need both of those values in later steps. admin:~ # radosgw-admin user create --uid=s3user --display-name=S3 User --email=s3user@example.net { \"user_id\": \"s3user\", \"display_name\": \"S3\", \"email\": \"s3user@example.net\", \"suspended\": 0, \"max_buckets\": 1000, \"subusers\": [], \"keys\": [ { \"user\": \"s3user\", \"access_key\": , \"secret_key\": } ], \"swift_keys\": [], \"caps\": [], \"op_mask\": \"read, write, delete\", \"default_placement\": \"\", \"default_storage_class\": \"\", \"placement_tags\": [], \"bucket_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"user_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"temp_url_keys\": [], \"type\": \"rgw\", \"mfa_ids\": [] } Retrieve above information admin:~ # radosgw-admin user info --uid=s3user","title":"Task 1: Using the s3cmd tool and create an S3 user"},{"location":"linux/SES/linux_ses_demo/#task-2-create-a-new-s3cmd-configuration-file-and-a-new-s3-bucket","text":"1). Generate a new s3cmd configuration file from a shell on the admin node: Fill in as listed below: admin:~ # cd ~ admin:~ # s3cmd --configure Enter new values or accept defaults in brackets with Enter. Refer to user manual for detailed description of all options. Access key and Secret key are your identifiers for Amazon S3. Leave them empty for using the env variables. Access Key: Secret Key: Default Region [US]: Use \"s3.amazonaws.com\" for S3 Endpoint and not modify it to the target Amazon S3. S3 Endpoint [s3.amazonaws.com]: mon3.sha.me.corp Use \"%(bucket)s.s3.amazonaws.com\" to the target Amazon S3. \"%(bucket)s\" and \"%(location)s\" vars can be used if the target S3 system supports dns based buckets. DNS-style bucket+hostname:port template for accessing a bucket [%(bucket)s.s3.amazonaws.com]: %(bucket)s.mon3.sha.me.corp Encryption password is used to protect your files from reading by unauthorized persons while in transfer to S3 Encryption password: Path to GPG program [/usr/bin/gpg]: When using secure HTTPS protocol all communication with Amazon S3 servers is protected from 3 rd party eavesdropping. This method is slower than plain HTTP, and can only be proxied with Python 2.7 or newer Use HTTPS protocol [Yes]: No On some networks all internet access must go through a HTTP proxy. Try setting it here if you can't connect to S3 directly HTTP Proxy server name: New settings: Access Key: Secret Key: Default Region: US S3 Endpoint: mon3.sha.me.corp DNS-style bucket+hostname:port template for accessing a bucket: %(bucket)s.mon3.sha.me.corp Encryption password: Path to GPG program: /usr/bin/gpg Use HTTPS protocol: False HTTP Proxy server name: HTTP Proxy server port: 0 Test access with supplied credentials? [Y/n] n Save settings? [y/N] y Configuration saved to '/root/.s3cfg' 2). Test the configuration by checking for existing files or directories: Since no buckets or files have been made available for the user, no items are listed and the command returns you to the prompt with no output. This is normal. If there is an error, your configuration may have a typo in it. The configuration file will have been saved as .s3cfg. Edit the file to match the configuration in step one. admin:~ # s3cmd ls 3). Create a new bucket for uploading files to using the s3cmd: You should see feedback that the bucket has been created. Although not technically required by the S3 API, the bucket name needs to be in all uppercase to avoid a bug with the s3cmd tool itself. admin:~ # s3cmd mb s3://S3CMDTEST Bucket 's3://S3CMDTEST/' created admin:~ # s3cmd ls 2021-01-06 14:04 s3://S3CMDTEST (it's GMT timezone)","title":"Task 2: Create a new s3cmd configuration file and a new S3 bucket"},{"location":"linux/SES/linux_ses_demo/#task3-create-and-upload-a-file-to-a-bucket-using-the-s3-api","text":"1). Create a file with a few words of text: admin:~ # echo \"The mountains are beautiful\" > newfile 2). Put the new file into your bucket using s3cmd: You should see the file being uploaded. admin:~ # s3cmd put newfile s3://S3CMDTEST upload: 'newfile' -> 's3://S3CMDTEST/newfile' [1 of 1] 28 of 28 100% in 3s 7.66 B/s done 3). Verify the file is now in your bucket, safely stored in you SES cluster: admin:~ # s3cmd ls s3://S3CMDTEST 2021-01-06 14:11 28 s3://S3CMDTEST/newfile","title":"Task3: Create and upload a file to a bucket using the S3 API"},{"location":"linux/SES/linux_ses_demo/#243-use-the-swift-api-to-interact-with-the-rados-gateway","text":"OpenStack packages for SUSE Install and configure the storage nodes for openSUSE and SUSE Linux Enterprise SUSE Package Hub: python-PasteDeploy Enable SUSE Package Hub extension admin:~ # SUSEConnect -p PackageHub/15.1/x86_64 Install python3-PasteDeploy, which is dependency of python-swift installation admin:~ # zypper in python3-PasteDeploy admin:~ # rpm -ivh python3-PyECLib-1.6.0-1.6.x86_64.rpm warning: python3-PyECLib-1.6.0-1.6.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID 3dbdc284: NOKEY error: Failed dependencies: python(abi) = 3.8 is needed by python3-PyECLib-1.6.0-1.6.x86_64 rpmlib(PayloadIsZstd) <= 5.4.18-1 is needed by python3-PyECLib-1.6.0-1.6.x86_64 Add OpenStack Swift Repository for SUSE admin:~ # zypper addrepo -f obs://Cloud:OpenStack:Train/SLE_15_SP1 Train admin:~ # zypper in openstack-swift openstack-swift-account openstack-swift-container openstack-swift-object","title":"2.4.3. Use the swift API to Interact with the RADOS Gateway"},{"location":"linux/SES/linux_ses_demo/#task-1-create-a-swift-subuser","text":"1). In a shell or terminal as the root user (password of linux) on the admin node, create a new subuser: The output will contain the access and secret keys for the s3user and a secret key for the new swift subuser.. admin:~ # radosgw-admin subuser create --uid=s3user --subuser=s3user:swift --access=full { \"user_id\": \"s3user\", \"display_name\": \"S3\", \"email\": \"s3user@example.net\", \"suspended\": 0, \"max_buckets\": 1000, \"subusers\": [ { \"id\": \"s3user:swift\", \"permissions\": \"full-control\" } ], \"keys\": [ { \"user\": \"s3user\", \"access_key\": , \"secret_key\": } ], \"swift_keys\": [ { \"user\": \"s3user:swift\", \"secret_key\": } ], \"caps\": [], \"op_mask\": \"read, write, delete\", \"default_placement\": \"\", \"default_storage_class\": \"\", \"placement_tags\": [], \"bucket_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"user_quota\": { \"enabled\": false, \"check_on_raw\": false, \"max_size\": -1, \"max_size_kb\": 0, \"max_objects\": -1 }, \"temp_url_keys\": [], \"type\": \"rgw\", \"mfa_ids\": [] } 2). Verify that the subuser has access to at least one bucket and list the buckets with a swift command: swift -A http://mon3.sha.me.corp/auth/1.0 -U s3user:swift -K '{SECRET_KEY_FROM_STEP_1}' list admin:~ # swift -A http://mon3.sha.me.corp/auth/1.0 -U s3user:swift -K '' list S3CMDTEST","title":"Task 1: Create a swift subuser"},{"location":"linux/SES/linux_ses_demo/#task-2-use-the-swift-command-to-access-a-file-created-with-the-s3cmd-tool","text":"1). Since the S3 API and the swift API are accessing the same SUSE Enterprise Storage cluster, and since the RADOS gateway is built to be inter-operable with both, you can use the swift API to retrieve the object which was uploaded to SES via the S3 API: swift -A http://mon3.example.net/auth/1.0 -U s3user:swift -K '{SECRET_KEY_FROM_STEP_1}' download -a An example of the command is listed here: admin:~ # swift -A http://mon3.sha.me.corp/auth/1.0 -U s3user:swift -K '' download -a Although we have taken a shortcut by using the -a option (meaning grab every object this user has access to), it illustrates the tool\u2019s capability. We\u2019ve uploaded the newfile with S3, we\u2019ve retrieved it with swift.","title":"Task 2: Use the swift command to access a file created with the S3cmd tool"},{"location":"linux/SES/linux_ses_demo/#244-create-snapshots-on-ses-using-rbd","text":"In this lab we worked with rbd images. We mapped an rbd image to a Linux device file, then created a filesystem and mounted it. Then we created snapshots to preserve the images data state at a particular time, and rolled it back to demonstrate functionality.","title":"2.4.4. Create Snapshots on SES using RBD"},{"location":"linux/SES/linux_ses_demo/#task-1-create-a-new-pool-for-rbd-images","text":"1). Access https://mon1.pvg.me.corp:8443 or https://10.58.121.186:8443 2). Log in with the following credentials: Username: admin Password: mypassword 3). Click on the Pools tab near the top of the page 4). Click the Create button and use the following in the available fields: Name: rbd-images Pool type: replicated Placement groups: 16 Crush ruleset: replicated_rule Replicted size: 2 Applications: rbd Compression Mode: none 5). Click Create Pool","title":"Task 1: Create a new pool for RBD images"},{"location":"linux/SES/linux_ses_demo/#task-2-create-a-new-rbd-image-in-the-rbd-images-pool","text":"6). Create a new RBD image using the rbd command: admin:~ # rbd create --size 1024 rbd-images/barfoo 7). Verify the new image has been created in the rbd-images pool: The new image named barfoo should be displayed. admin:~ # rbd ls -p rbd-images barfoo","title":"Task 2: Create a new RBD image in the rbd-images pool"},{"location":"linux/SES/linux_ses_demo/#task-3-mount-the-new-image-on-the-admin-node-and-create-a-filesystem","text":"1). As the root user in a shell or terminal on the admin node, map the new rbd image to a block device: admin:~ # rbd map rbd-images/barfoo /dev/rbd0 2). Create a filesystem on the newly mapped device: admin:~ # mkfs.ext4 /dev/rbd0 mke2fs 1.43.8 (1-Jan-2018) Discarding device blocks: done Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: 19da6b86-1989-4834-a365-2f654fcce6f6 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done 3). Mount the image to the /mnt directory: admin:~ # mount /dev/rbd0 /mnt admin:~ # l /mnt total 20 drwxr-xr-x 3 root root 4096 Jan 6 23:48 ./ drwxr-xr-x 1 root root 156 Oct 5 08:53 ../ drwx------ 2 root root 16384 Jan 6 23:48 lost+found/","title":"Task 3: Mount the new image on the admin node and create a filesystem"},{"location":"linux/SES/linux_ses_demo/#task-4-create-a-file-on-the-new-filesystem-and-snapshot-the-rbd-image-and-make-some-additional-changes","text":"1). Change to the /mnt directory and create a simple file: admin:~ # cd /mnt admin:/mnt # echo \"This is some sample text\" > start.txt 2). List the directories contents to see that the start.txt file has been created on the storage cluster. admin:/mnt # ls -l total 20 drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 3). Create a snapshot of what the rbd image contained: Wait for confirmation that the snapshot has been created. It should only take a few seconds. admin:/mnt # rbd snap create rbd-images/barfoo@begin 4). List the rbd snapshots for the rbd-images/barfoo image: You should see the new snap called begin listed. admin:/mnt # rbd snap ls rbd-images/barfoo SNAPID NAME SIZE PROTECTED TIMESTAMP 4 begin 1 GiB Wed Jan 6 23:51:12 2021 5). Add another file to the filesystem: admin:/mnt # echo \"Some more text\" > end.txt 6). List the contents of the /mnt to verify the existence of two files. admin:/mnt # ls -l total 24 -rw-r--r-- 1 root root 15 Jan 6 23:52 end.txt drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 7). Create a second snapshot of the rbd-images/barfoo image: admin:/mnt # rbd snap create rbd-images/barfoo@finish 8). List the rbd snapshots: There should be begin and finish snapshots. admin:/mnt # rbd snap ls rbd-images/barfoo SNAPID NAME SIZE PROTECTED TIMESTAMP 4 begin 1 GiB Wed Jan 6 23:51:12 2021 5 finish 1 GiB Wed Jan 6 23:53:15 2021 9). List the contents of the /mnt directory again and verify the two files. 10). Rollback the data to the begin snapshot: This process will be relatively quick because the size of the image is small and we have very little data on it. admin:/mnt # rbd snap rollback rbd-images/barfoo@begin Rolling back to snapshot: 100% complete...done. 11). Change to the root user\u2019s home directory, then remount the image in order to see that the rbd image has been rolled back: admin:/mnt # cd ~ admin:~ # umount /mnt admin:~ # mount /dev/rbd0 /mnt 12). List the contents of the /mnt directory to verify that only the start.txt file exists on the image. admin:/mnt # ls -l total 20 drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 13). Rollback the data to the finish snapshot: admin:/mnt # rbd snap rollback rbd-images/barfoo@finish Rolling back to snapshot: 100% complete...done. 14). Unmount and remount the image: admin:/mnt # cd ~ admin:~ # umount /mnt admin:~ # mount /dev/rbd0 /mnt 15). List the contents of the /mnt directory to show it has indeed been rolled back and contains the start.txt and end.txt files admin:/mnt # ls -l total 24 -rw-r--r-- 1 root root 15 Jan 6 23:52 end.txt drwx------ 2 root root 16384 Jan 6 23:48 lost+found -rw-r--r-- 1 root root 25 Jan 6 23:50 start.txt 16). Change to the root user\u2019s home directory and unmount the image: admin:/mnt # cd ~ admin:~ # umount /mnt","title":"Task 4: Create a file on the new filesystem and snapshot the rbd image and make some additional changes"},{"location":"linux/SES/linux_ses_demo/#245-create-and-manage-cow-clones-with-rbd","text":"In this lab you will created a new pool and block device image in the pool. You then mapped the block storage to a linux device and took a snapshot. Finally you protected the snapshot from modification. This would be done so the snapshot can be safely used as a parent cow image which can then be cloned to create new virtual machines.","title":"2.4.5. Create and manage COW Clones with rbd"},{"location":"linux/SES/linux_ses_demo/#task-1-create-a-new-pool","text":"1). View the current osds and pools: admin:~ # ceph osd ls 0 1 2 3 4 5 6 7 8 9 10 11 admin:~ # ceph osd pool ls iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log rbd_pool bucket_pool EC_RBD_Pool default.rgw.buckets.index default.rgw.buckets.data rbd-images 2). Create a new pool called cow-pool: admin:~ # ceph osd pool create cow-pool 128 pool 'cow-pool' created 3). List the available pools to view the new pool using either of the following commands: admin:~ # ceph osd pool ls iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log rbd_pool bucket_pool EC_RBD_Pool default.rgw.buckets.index default.rgw.buckets.data rbd-images cow-pool admin:~ # rados lspools iscsi-images cephfs_data cephfs_metadata .rgw.root default.rgw.control default.rgw.meta default.rgw.log rbd_pool bucket_pool EC_RBD_Pool default.rgw.buckets.index default.rgw.buckets.data rbd-images cow-pool Task 2: Create a block device image in a pool 1). Create a format 2 rbd image called cow-base in the cow-pool storage pool with a size of 1GB *Note that the \u2013image-format statement is optional as format 2 is default admin:~ # rbd create -p cow-pool cow-base --size 1024 --image-format 2 2). Check that the image has been created, that the format is 2 and that layering (COW Clones) is supported admin:~ # rbd -p cow-pool list cow-base admin:~ # rbd -p cow-pool info cow-base rbd image 'cow-base': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 269d5b817222aa block_name_prefix: rbd_data.269d5b817222aa format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:12:31 2021 access_timestamp: Thu Jan 7 10:12:31 2021 modify_timestamp: Thu Jan 7 10:12:31 2021 Task 3: Map the block storage image to a Linux host 1). In a shell or terminal as user root open a terminal window. Using the rbd map command, map an rbd device to the block-storage image created above. admin:~ # rbd map -p cow-pool --image cow-base /dev/rbd1 2). View the mapped block devices admin:~ # rbd showmapped id pool namespace image snap device 0 rbd-images barfoo - /dev/rbd0 1 cow-pool cow-base - /dev/rbd1 3). Note the rbd index numbgr (e.g. rbd0, rbd1) associated with the cow-base image: RBD ___1____ 4). View the devices in /dev. Note the device name(s) admin:~ # ls -l /dev/rbd* brw-rw---- 1 root disk 252, 0 Jan 6 23:49 /dev/rbd0 brw-rw---- 1 root disk 252, 16 Jan 7 10:14 /dev/rbd1 /dev/rbd: total 0 drwxr-xr-x 2 root root 60 Jan 7 10:14 cow-pool drwxr-xr-x 2 root root 60 Jan 6 23:48 rbd-images 5). View the block device:(use the device numbgr from step above) admin:~ # fdisk -l /dev/rbd1 Disk /dev/rbd1: 1 GiB, 1073741824 bytes, 2097152 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 4194304 bytes / 4194304 bytes 6). Format the device with an ext4 filesystem: admin:~ # mkfs.ext4 /dev/rbd1 mke2fs 1.43.8 (1-Jan-2018) Discarding device blocks: done Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: 64c9a973-cf31-4239-881f-ec5642bf34e3 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done 7). Mount the block device on the local filesystem: admin:~ # mkdir /mnt/cow-base admin:~ # mount /dev/rbd1 /mnt/cow-base 8). Test the storage access by creating a file: admin:~ # cd /mnt/cow-base admin:/mnt/cow-base # touch base-image-file admin:/mnt/cow-base # ls base-image-file lost+found","title":"Task 1: Create a new pool"},{"location":"linux/SES/linux_ses_demo/#task-4-snapshot-the-rbd-image-and-protect-the-snapshot","text":"1). List the snapshots in the cow-base image: admin:/mnt/cow-base # rbd snap ls cow-pool/cow-base 2). Create a snapshot of the cow-base rbd image which contains the base-image-file file admin:/mnt/cow-base # rbd snap create cow-pool/cow-base@base-snap 3). List the snapshot: admin:/mnt/cow-base # rbd snap ls cow-pool/cow-base SNAPID NAME SIZE PROTECTED TIMESTAMP 4 base-snap 1 GiB Thu Jan 7 10:37:13 2021 4). This snapshot will form the parent snapshot for COW clone images so you will now protected it from modification: admin:/mnt/cow-base # rbd snap protect cow-pool/cow-base@base-snap admin:/mnt/cow-base # rbd snap ls cow-pool/cow-base SNAPID NAME SIZE PROTECTED TIMESTAMP 4 base-snap 1 GiB yes Thu Jan 7 10:37:13 2021 Task 5: Create writable COW clones from the parent snapshot 1). Create a COW clone from the cow-base with the base-snap snapshot as the parent image admin:/mnt/cow-base # rbd clone cow-pool/cow-base@base-snap cow-pool/cow-image1 2). Check the information for the new image admin:/mnt/cow-base # rbd -p cow-pool --image cow-image1 info rbd image 'cow-image1': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a1209678cad4 block_name_prefix: rbd_data.26a1209678cad4 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:38:58 2021 access_timestamp: Thu Jan 7 10:38:58 2021 modify_timestamp: Thu Jan 7 10:38:58 2021 parent: cow-pool/cow-base@base-snap overlap: 1 GiB 3). Note that the image has details of the parent image and overlap 4). Repeat steps 2 & 3 for an additional image called cow-image2 admin:/mnt/cow-base # rbd clone cow-pool/cow-base@base-snap cow-pool/cow-image2 admin:/mnt/cow-base # rbd -p cow-pool --image cow-image2 info rbd image 'cow-image2': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a2fbcec7b8d9 block_name_prefix: rbd_data.26a2fbcec7b8d9 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:47:28 2021 access_timestamp: Thu Jan 7 10:47:28 2021 modify_timestamp: Thu Jan 7 10:47:28 2021 parent: cow-pool/cow-base@base-snap overlap: 1 GiB Task 6: Test that the COW clones are functional 1). Create a new directory and mount the COW clone called cow-image1 Note the rbd device name and use it to mount the file system admin:/mnt # mkdir /mnt/cow-image1 admin:/mnt # rbd map -p cow-pool --image cow-image1 /dev/rbd2 admin:/mnt # l total 4 drwxr-xr-x 1 root root 36 Jan 7 10:54 ./ drwxr-xr-x 1 root root 156 Oct 5 08:53 ../ drwxr-xr-x 3 root root 4096 Jan 7 10:19 cow-base/ drwxr-xr-x 1 root root 0 Jan 7 10:54 cow-image1/ admin:/mnt # ls -l /dev/rbd* brw-rw---- 1 root disk 252, 0 Jan 6 23:49 /dev/rbd0 brw-rw---- 1 root disk 252, 16 Jan 7 10:18 /dev/rbd1 brw-rw---- 1 root disk 252, 32 Jan 7 10:55 /dev/rbd2 /dev/rbd: total 0 drwxr-xr-x 2 root root 80 Jan 7 10:55 cow-pool drwxr-xr-x 2 root root 60 Jan 6 23:48 rbd-images admin:/mnt # mount /dev/rbd2 /mnt/cow-image1 2). Check that the base-image-file which was created in the parent snapshot is present admin:/mnt # cd /mnt/cow-image1 admin:/mnt/cow-image1 # ls base-image-file lost+found 3). Repeat steps 1 and 2 for cow-image2 admin:/mnt # mkdir /mnt/cow-image2 admin:/mnt # rbd map -p cow-pool --image cow-image2 /dev/rbd3 admin:/mnt # mount /dev/rbd3 /mnt/cow-image2 admin:/mnt # ls ./cow-image2/ base-image-file lost+found --> same file with image1 4). Create a new file in the directory where cow-image1 is mounted admin:/mnt # cd cow-image1 admin:/mnt/cow-image1 # touch additional-file admin:/mnt/cow-image1 # ls additional-file base-image-file lost+found 5). Look in the cow-image2 directory. Although they share the same parent snapshot, you can see that the files contained in each COW image are now different. admin:/mnt # ls ./cow-image2/ base-image-file lost+found","title":"Task 4: Snapshot the rbd image and protect the snapshot"},{"location":"linux/SES/linux_ses_demo/#task-7-flatten-a-cow-clone-and-remove-the-parent-image","text":"1). Convert the COW clone called cow-image1 to a standalone rbd image Wait while the flatten process completes. Unlike a clone process this is not instantaneous and can take considerable time. admin:/mnt # rbd flatten cow-pool/cow-image1 Image flatten: 100% complete...done. 2). Check to see that the flatten process has removed the link to the parent snapshot admin:/mnt # rbd -p cow-pool --image cow-image1 info rbd image 'cow-image1': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a1209678cad4 block_name_prefix: rbd_data.26a1209678cad4 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:38:58 2021 access_timestamp: Thu Jan 7 10:38:58 2021 modify_timestamp: Thu Jan 7 10:38:58 2021 admin:/mnt # rbd -p cow-pool --image cow-image2 info rbd image 'cow-image2': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 26a2fbcec7b8d9 block_name_prefix: rbd_data.26a2fbcec7b8d9 format: 2 features: layering op_features: flags: create_timestamp: Thu Jan 7 10:47:28 2021 access_timestamp: Thu Jan 7 10:47:28 2021 modify_timestamp: Thu Jan 7 10:47:28 2021 parent: cow-pool/cow-base@base-snap overlap: 1 GiB 3). Unmount the images admin:/mnt # umount /mnt/cow-image1 admin:/mnt # umount /mnt/cow-image2 admin:/mnt # umount /mnt/cow-base","title":"Task 7: Flatten a COW Clone and remove the parent image"},{"location":"linux/SES/linux_ses_demo/#246-configure-iscsi-on-ses","text":"In this lab an iSCSI Target was configured via the iSCSI gateway on our SUSE Enterprise Storage. An image was added to it. An iSCSI initiator then connected to the target, created a filesystem, and mounted it.","title":"2.4.6. Configure iSCSI on SES"},{"location":"linux/SES/linux_ses_demo/#task-1-create-a-new-rbd-image-in-the-iscsi-images-pool","text":"1). Create a new RBD image using the rbd command: admin:~ # rbd create --size 1024 iscsi-images/fooiscsi 2). Verify the new image has been created in the iscsi-images pool: The new image named fooiscsi should be displayed. admin:~ # rbd ls iscsi-images fooiscsi","title":"Task 1: Create a new RBD image in the iscsi-images pool"},{"location":"linux/SES/linux_ses_demo/#task-2-define-a-new-iscsi-target-with-the-ceph-dashboard","text":"1). Access the Ceph Dashboard and log in: https://mon1.pvg.me.corp:8443 or https://10.58.121.186:8443 Username: admin Password: mypassword 2). Once logged in, click on the Block drop-down item near the top. Select iSCSI. 3). With the Overview tab showing for iSCSI, click on the Targets tab near the top. Note: When clicking on the Targets tab, if you see an error that says something about \u201cUnsupported `ceph-iscsi` config version\u2026\u201d, perform the following steps: 1. Close the browser window where the error occurred 2. Restart the mon1 virtual machine. Do this with the following steps: from the Virtual Machine Manager on your lab machine (not in the admin virtual machine), restart the mon1 virtual machine by right-clicking on the mon1 virtual machine > Shut Down > Reboot 3. Wait at least 30 seconds, then from the admin node, open up the browser again and log in to the Ceph Dashboard: https://mon1.pvg.me.corp:8443 or https://10.58.121.186:8443 Username: admin Password: mypassword 4. Continue the lab as directed below by navigating to the Block > iSCSI section, clicking on the Targets tab, and completing the steps below 4). Click Add. Use the following values: Target IQN: Portals: mon2.example.net:172.17.6.132 Images: iscsi-images/fooiscsi ACL authentication: Click Create Target.","title":"Task 2: Define a new iSCSI target with the Ceph Dashboard"},{"location":"linux/SES/linux_ses_demo/#task-3-access-the-new-iscsi-target-from-the-admin-node","text":"1). On the admin node, launch YaST either the ncurses or GUI interface, and select the iSCSI Initiator module: YaST > Network Services > iSCSI Initiator 2). Select the Discovered Targets tab (alt-v) 3). Select Discovery at the bottom of the frame (alt-d) 4). Add the ip address of mon2: 10.58.121.187. Leave the port as the default of 3260. Select Next. 5). Once again on the Discovered Targets tab, the mon2 target should be listed. With the new target highlighted, select Connect (alt-e) at the bottom of the frame. 6). Leave the Startup (in YaST2) or On boot (in YaST) value as manual. Select Next. 7). Select OK to exit the iscsi client configuration module 8). To verify that the iscsi device is now connected, use the lsscsi command to list devices: You should see there is one disk of type RBD connected on a device file similar to the following: admin:~ # lsscsi [0:0:0:0] cd/dvd QEMU QEMU DVD-ROM 1.4. /dev/sr0 [2:0:0:0] disk SUSE RBD 4.0 /dev/sda 9). Create an ext4 filesystem on the connected device file: admin:~ # mkfs.ext4 /dev/sda mke2fs 1.43.8 (1-Jan-2018) Creating filesystem with 262144 4k blocks and 65536 inodes Filesystem UUID: e3896f7e-0664-4b14-85db-0f77cb234c43 Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Allocating group tables: done Writing inode tables: done Creating journal (8192 blocks): done Writing superblocks and filesystem accounting information: done 10). Mount the device to /mnt: admin:~ # mount /dev/sda /mnt 11). Use the mount command to list the connected device: admin:/mnt # mount | grep sda /dev/sda on /mnt type ext4 (rw,relatime,stripe=1024,data=ordered) 12).Change the root user\u2019s home directory and unmount the device: admin:/mnt # cd .. admin:/ # umount /mnt","title":"Task 3: Access the new iSCSI target from the admin node"},{"location":"linux/SES/linux_ses_demo/#247-mount-cephfs-provided-by-suse-enterprise-storage","text":"In this lab a ceph user was configured to mount the ceph filesystem provided by the SUSE Enterprise Cluster. A keyfile was generated, then used in the process.","title":"2.4.7. Mount CephFS Provided by SUSE Enterprise Storage"},{"location":"linux/SES/linux_ses_demo/#task-1-verify-cephfs-configuration-of-the-ses-cluster","text":"1). Cephfs requires two pools for operation: one for data, the other for metadata. Verify that the cluster has two pools for this purpose: admin:~ # ceph fs ls name: cephfs, metadata pool: cephfs_metadata, data pools: [cephfs_data ] Task 2: Create a secret key file for the admin user on the admin node 1). Because cephx authentication is enabled by default on SUSE Enterprise Storage, a secret key will need to be provided to allow access to mount the ceph filesystem. The admin user (identified \u2013 in this case \u2013 on the system as root) on the admin node has a key, but we will need to either provide it on the command line during the mount process (less secure), or put it in a permissions-restricted file and point to the file when mounting (more secure). If we do not specify the key or a file with the key, we will get an error. The following command will return an error: admin:~ # mount -t ceph mon1:6789:/ /mnt 2021-01-07 14:16:36.924 7f45108a9d80 -1 auth: unable to find a keyring on /etc/ceph/ceph.client.guest.keyring,/etc/ceph/ceph.keyring,/etc/ceph/keyring,/etc/ceph/keyring.bin,: (2) No such file or directory mount error 22 = Invalid argument 2). Take secret key value found in the /etc/ceph/ceph.client.admin.keyring file and put it in a new file: admin:~ # cat /etc/ceph/ceph.client.admin.keyring [client.admin] key = caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" 3). Create a new file and paste the secret key value into it: admin:~ # vi /etc/ceph/admin.secret Put the key value into the file and save it. 4). Change the permissions of the file to be read only by the user: admin:~ # ls -l /etc/ceph/admin.secret -r-------- 1 root root 41 Jan 5 20:05 /etc/ceph/admin.secret","title":"Task 1: Verify cephfs configuration of the SES cluster"},{"location":"linux/SES/linux_ses_demo/#task-3-mount-the-ceph-filesystem-on-the-admin-node","text":"1). Now that the keyfile is created, we can mount the filesystem: admin:~ # mount -t ceph mon1:6789:/ /mnt -o name=admin,secretfile=/etc/ceph/admin.secret admin:~ # ls -l /mnt total 0 2). Verify that the mount shows as expected: admin:~ # mount | grep ceph 10.58.121.186:6789:/ on /mnt type ceph (rw,relatime,name=admin,secret=,acl) 3). Change to the root user\u2019s home directory and unmount the filesystem: admin:~ # cd ~ admin:~ # umount /mnt","title":"Task 3: Mount the ceph filesystem on the admin node"},{"location":"linux/SES/linux_ses_demo/#248-export-an-nfs-share-from-ses-with-nfs-ganesha","text":"","title":"2.4.8. Export an NFS Share from SES with NFS Ganesha"},{"location":"linux/SES/linux_ses_demo/#task-0-install-and-configure-ganesha-ganesha-config-location-is-not-configured-please-set-the-ganesha_rados_pool_namespace-setting","text":"admin:~ # zypper in nfs-ganesha admin:/etc/ganesha # cat ganesha.conf NFSv4 { RecoveryBackend = 'rados_cluster'; #RecoveryBackend = 'rados_ng'; } RADOS_URLS { ceph_conf = '/etc/ceph/ceph.conf'; userid = \"admin\"; watch_url = \"rados://data/ganesha-export-index/conf-nfs1\"; } RADOS_KV { pool = \"metadata\"; namespace = \"ganesha-grace\"; nodeid = \"nfs1\"; } %url rados://data/ganesha-export-index/conf-nfs1 admin:/etc/ganesha # ganesha-rados-grace -p metadata -n ganesha-grace add nfs1 nfs2 nfs3 admin:/etc/ganesha # ganesha-rados-grace -p metadata -n ganesha-grace cur=1 rec=0 ====================================================== nfs1 E nfs2 E nfs3 E http://images.45drives.com/ceph/cephfs/nfs-ganesha-ceph.conf","title":"Task 0: Install and configure Ganesha (Ganesha config location is not configured. Please set the GANESHA_RADOS_POOL_NAMESPACE setting.)"},{"location":"linux/SES/linux_ses_demo/#task-1-create-an-nfs-export-using-the-ceph-dashboard","text":"1). In a browser, navigate to a monitor to access the Ceph Dashboard and log in: https://10.58.121.186:8443/ Username: admin Password: mypassword 2). Click on the NFS tab near the top of the page 3). Click on the green Add button 4). Click on the Add daemon button to the right and select mon1 5). Complete the configuration with the following values: Storage Backend: Object Gateway Object Storage User: s3user Path: S3CMDTEST NFS Protocol: NFSv3 and NFSv4 checked NFS Tag: Pseudo: /S3BKT Access Type: RW Squash: root_squash Transport Protocol: UDP and TCP checked Clients: Click Submit","title":"Task 1: Create an NFS export using the Ceph Dashboard"},{"location":"linux/SES/linux_ses_demo/#task-2-mount-the-nfs-export-on-the-admin-node","text":"1). As the root user on the admin node, query the NFS Ganesha gateway node to see what mounts are available: showmount -e mon1 You should see something similar to the following: Export list for mon1: S3CMDTEST (everyone) 2). Mount the available nfs share to the /mnt directory on the admin server: mount -t nfs mon1:/S3BKT /mnt 3). List the nfs mount: mount | grep mnt Note the type listed as nfs4 4). Change to the root user\u2019s home directory and unmount the export: cd umount /mnt","title":"Task 2: Mount the NFS export on the admin node"},{"location":"linux/SES/linux_ses_demo/#249-configure-and-mount-cifs","text":"In this lab the Samba gateway was configured. A keyring for the Samba gateway was created, the Samba service was modified, and a user created to allow CIFS access to the SES cluster.","title":"2.4.9. Configure and Mount CIFS"},{"location":"linux/SES/linux_ses_demo/#task-1-prepare-the-cephfs-share-for-cifs","text":"1). In order for CIFS to work in our SES environment, a valid CephFS share must be available. The CephFS lab previously done in this workbook is sufficient. Using the same configuration that we used previously, mount the CephFS share and give permissions to all users at the root of the share: admin:~ # mount -t ceph mon1:6789:/ /mnt -o name=admin,secretfile=/etc/ceph/admin.secret admin:~ # chmod 777 /mnt admin:~ # l /mnt total 0 drwxrwxrwx 2 root root 0 Oct 5 14:30 ./ drwxr-xr-x 1 root root 156 Oct 5 08:53 ../ admin:~ # umount /mnt","title":"Task 1: Prepare the CephFS share for CIFS"},{"location":"linux/SES/linux_ses_demo/#task-2-create-a-samba-gateway-specific-keyring-on-the-ceph-admin-node-and-copy-it-to-the-samba-gateway-node","text":"1). A new keyring will be needed for the Samba gateway to allow access to the Ceph cluster. As root, perform the following: admin:~ # ceph auth get-or-create client.samba.gw mon 'allow r' osd 'allow *' mds 'allow *' -o ceph.client.samba.gw.keyring 2). Copy the new keyring to the Samba gateway node: admin:~ # scp ceph.client.samba.gw.keyring mon1:/etc/ceph/ ceph.client.samba.gw.keyring admin:~ # ssh mon1 Last login: Thu Jan 7 14:35:58 2021 from 10.58.121.181 mon1:~ # ls -l /etc/ceph/ total 12 -rw-r--r-- 1 root root 66 Jan 7 15:15 ceph.client.samba.gw.keyring -rw-r--r-- 1 root root 1095 Jan 5 22:44 ceph.conf -rw-r--r-- 1 root root 92 Aug 24 22:03 rbdmap","title":"Task 2: Create a Samba gateway specific keyring on the Ceph admin node and copy it to the Samba gateway node"},{"location":"linux/SES/linux_ses_demo/#task-3-configure-samba-on-the-samba-gateway-node","text":"1). The /etc/samba/smb.conf file will need to be edited to allow CIFS access to the storage cluster. On the mon1 node, replace all of the contents of the file with the following: admin:~ # ssh mon1 mon1:~ # vi /etc/samba/smb.conf mon1:/etc/samba # cat smb.conf [global] netbios name = SAMBA-GW clustering = no idmap config * : backend = tdb2 passdb backend = tdbsam # disable print server load printers = no smbd: backgroundqueue = no [ceph-smb] path = / vfs objects = ceph ceph: config_file = /etc/ceph/ceph.conf ceph: user_id = samba.gw read only = no oplocks = no kernel share modes = no 2). Create a smb user on the mon1 node named joesmb with a password of mypassword: mon1:/etc/samba # useradd joesmb mon1:/etc/samba # passwd joesmb ---> 123 Add joesmb to the smb password database with a password of mypassword: mon1:/etc/samba # smbpasswd -a joesmb New SMB password: ---> 123 Retype new SMB password: ---> 123 Added user joesmb. 3). Start and enable the smb and nmb daemons on mon1: mon1:/etc/samba # systemctl start smb nmb mon1:/etc/samba # systemctl enable smb nmb Created symlink /etc/systemd/system/multi-user.target.wants/smb.service \u2192 /usr/lib/systemd/system/smb.service. Created symlink /etc/systemd/system/multi-user.target.wants/nmb.service \u2192 /usr/lib/systemd/system/nmb.service. 4). Unmount the filesystem: mon1:~ # umount /mnt umount: /mnt: not mounted.","title":"Task 3: Configure Samba on the Samba gateway node"},{"location":"linux/SES/linux_ses_demo/#task-4-connect-a-client-to-the-samba-gateway","text":"1). On the admin node, verify that the Samba gateway is sharing via CIFS. The password is 123 admin:~ # smbclient -U joesmb -L //mon1 Enter WORKGROUP\\joesmb's password: ---> 123 Sharename Type Comment --------- ---- ------- ceph-smb Disk IPC$ IPC IPC Service (Samba 4.9.5-git.373.26895a83dbf3.44.1-SUSE-oS15.0-x86_64) Reconnecting with SMB1 for workgroup listing. Server Comment --------- ------- Workgroup Master --------- ------- GLOBAL CNPVGVSYB900 WORKGROUP SAMBA-GW 2). Connect to the ceph-smb share as joesmb. The password is 123 admin:~ # smbclient -U joesmb //mon1/ceph-smb Enter WORKGROUP\\joesmb's password: ---> 123 tree connect failed: NT_STATUS_BAD_NETWORK_NAME You should see output similar to the following: Try \u201chelp\u201d to get a list of possible commands. smb: \\>","title":"Task 4: Connect a client to the Samba gateway"},{"location":"linux/SES/linux_ses_memo/","text":"SUSE Enterprise Storage Foundation \u00b6 Ceph\u2019s RADOS \u00b6 Everything in Ceph is stored in the RADOS cluster as Objects. Ceph\u2019s RADOS: Reliable Autonomous Distributed Object Store Ceph\u2019s RADOS is composed of storage devices represented as: Raw storage device with LVM (BlueStore) Standard filesystem (FileStore) The Object Storage Daemon (OSD) integrates each disk device as part of the RADOS cluster. Ceph architecture \u00b6 Ceph is made of two groups of core components The RADOS cluster Provides the clustered object storage Native Object Access methods Gateways Access to the object store via standard protocols librados Direct access to the object store using a native API Examples: iSCSI Gateway (block) -- IGW - iSCSI is a storage area network (SAN) protocol. Exports RADOS Block Device (--RBD) (images as iSCSI disks). iSCSI access to RDB images. lrbd is no longer used in SES6. RADOS Gateway (object) -- RGW Is an object storage interface built on top of librados CephFS (file) A MetaData Service (MDS) is required. Direct access to RADOS (no LIBRADOS layer) Traditional filesystem interface. NFS Ganesha (object, file) Provides NFS exports to: RGW buckets for access the object store The CephFS filesystem Client access the storage services of the cluster via Gateways and Librados The librados API allows interaction with the following daemons: The Ceph Monitor, which maintains a master copy of the cluster map The Ceph OSD Daemon (OSD), which stores data as objects on a storage node. Enhanced SES Architecture Diagram \u00b6 Object Storage \u00b6 The state of the art of distributed SDS storage Unstructured, to better accommodate large files and large quantities of files For large files and large quantities of files, it performs far better than other storage mechanisms Agile, scalable, extensible, and very customizable Invisible to the end-user, ideal for backends Perfect for systemic, application-based use cases. Not necessarily perfect for direct Human use Through associated metadata, ideal for computational analytics And CRUSH takes full advantage of this (CRUSH = Controllable Replication Under Scalable Hashing) Ceph Object Storage supports two interfaces: S3-compatible Swift-compatible Object-based storage has become the standard backend storage mechanism for nearly all modern Enterprise Storage Solutions. Ceph OSDs (Object Storage Daemon) \u00b6 A Ceph OSD (object storage daemon, ceph-osd) stores data, handles data replication, recovery, rebalancing, and provides some monitoring information to Ceph Monitors and Managers by checking other Ceph OSD Daemons for a heartbeat. The Ceph Storage Cluster receives data from Ceph Clients. Clients (dedicated access points, e.g., gateway) could be a Ceph Block Device, Ceph Object Storage, the Ceph Filesystem or a custom implementation using librados. The client requests the cluster status from a monitor node The client uses the status information to identify the location of objects in the cluster The client accesses the objects directly via the OSD node The OSD then stores the data as objects. Each object corresponds to a file in a filesystem which is stored on an OSD. The OSD Daemons take care of the reads and writes on the storage disks. When OSDs are deployed in SES5 the default is to use BlueStore which uses the raw disk and does not require a linux file system to be placed on the disk before it can be used. OSD Daemons store all data as objects in a flat namespace, i.e. no hierarchy of directories. At least 3 Ceph OSDs are normally required for redundancy and high availability. Ceph Mons (Monitor Servers) \u00b6 A Ceph Monitor (ceph-mon) maintains maps of the cluster state, including Monitor Map Manager Map OSD Map PG Map CRUSH Map Epoch These maps are critical cluster state required for Ceph daemons to coordinate with each other. Monitors are also responsible for managing authentication between daemons and clients. At least 3 monitors are normally required for redundancy and high availability. An odd number of MONs is required (Paxos requires). Typically 5 is sufficient for mid or large size cluster. Paxos is an algorithm used for cluster durability. Leader MON expects 50% quality to create quorum. Lowest IP address becomes leader. After new leader selected, all MONs polled for epoch. Leader Mon provides lease to non-leader MONs. MONs are NOT in the data path. They merely serve maps to clients so that the client can go directly to the appropriate OSD storage daemon. Monitor nodes MONs do not serve objects to clients Ceph MGRs (Manager Daemon) \u00b6 A Ceph Manager daemon (ceph-mgr) is responsible for keeping track of runtime metrics and the current state of the Ceph cluster, including storage utilization current performance metrics system load The Ceph Manager daemons also host python-based plugins to manage and expose Ceph cluster information, including a web-based dashboard and REST API. At least two managers are normally required for high availability. MON/MGR daemons are required to run on the same node in SES Ceph MDS (Metadata) \u00b6 A Ceph Metadata Server (MDS, ceph-mds) stores metadata on behalf of the Ceph Filesystem. Ceph Metadata Servers allow POSIX file system users to execute basic commands, for example ls -al without placing an large load on the Ceph Storage Cluster. Ceph Admin Node \u00b6 The Admin node fills the \u201cmaster\u201d and \u201cadmin\u201d roles for DeepSea. Salt is central to SES. SES\u2019s deployment and life-cycle management tool. The Admin node keeps master Ceph authentication keys. Prometheus and Grafana provide cluster monitoring and data graphs Ceph Dashboard \u00b6 Runs as a Ceph Manager module; runs via the MON/MGR node. Client Access \u00b6 Object Storage (RADOSGW or RGW) Block Storage (RDB). RBD is built on top of librados. CephFS iSCSI Gateway NFS Ganesha SMB/CIFS Native protocols via librados Objects in Ceph \u00b6 Everything stored in the Ceph cluster is an object. Default object size is 4MB. Each object has a unique ID. ID is unique across the entire cluster. Objects have associated metadata, in Key: Value pairs. In Ceph we use Storage Pools to organize or arrange our objects. Pools are logical partitions to manage objects Parameters to manage Pools Number of data replicas (Replica pools), or configuration of Erasure Code (size) (Erasure Code pools) Erasure Code is an alternative to Replication SIZE for Erasure Coding is K+M K = Data chunks, M = \u201cParity\u201d chunks EC reduces the hit to raw storage capacity EC incurs a greater hit to CPU on the OSDs as a tradeoff Placement Groups (PG) PG is used to manage objects within a pool. PGs are associated with OSDs for data placement PGs are a central feature of CRUSH that help to provide data durability by way of distribution No PG is owned by an OSD. (And an OSD is not owned by a PG.) PGs are just randomly assigned by CRUSH through all of the OSDs to spread the distribution of data Locating data among PGs is all handled economically, deterministically by way of CRUSH calculations PGs are subdivisions of pools Number of PGs = (Number of OSDs * 100) / Size (Size = either num of replicas, or K+M) The final PG number must be a power of 2 The default number of PGs for a new pool is 8 (it's too small for enterprise solution) In general, PG and PGP numbers should be the same pg_num is the number of placement groups for the pool (placement group, \u5b58\u50a8\u6c60\u7684\u76ee\u5f55\u4e2a\u6570 ) pgp_num is the number of placement groups that will be considered for placement (placement group for placement purpose, pg\u53ef\u7528\u7684osd\u6392\u5217\u7ec4\u5408\u6570\u91cf) \u4ec5\u589e\u5927pg_num\uff1a \u56e0\u4e3apgp_num\u6ca1\u53d8\uff0cpg\u7684osd\u7ec4\u5408\u4ecd\u53ea\u80fd\u4ece\u5f53\u524dpgp_num\u79cd\u7ec4\u5408\u91cc\u9762\u6311\u9009\uff0c\u5bfc\u81f4\u65b0\u589e\u7684pg\u548c\u65e7pg\u4f1a\u6709\u91cd\u590d\u7684osd\u7ec4\u5408\uff0c\u8be5\u73b0\u8c61\u79f0\u4e4b\u4e3a\u5206\u88c2\uff1b\u6b64\u65f6pg\u548cosd\u7684\u6620\u5c04\u6ca1\u6709\u53d8\uff1b \u7ee7\u7eed\u589e\u5927pgp_num\uff0c\u4f7f\u5176\u7b49\u4e8epg_num\uff1a \u65e7pg\u6ca1\u6709\u53d8\u5316\uff0c\u4f46\u65b0\u589epg\u7684osd\u7ec4\u5408\u53d1\u751f\u53d8\u5316\uff0c\u5373\u5f00\u59cb\u91cd\u65b0\u5206\u5e03 Placement Group (PG) \u5f52\u7f6e\u7ec4\u72b6\u6001 Creating \u521b\u5efa\u5b58\u50a8\u6c60\u65f6\uff0c\u5b83\u4f1a\u521b\u5efa\u6307\u5b9a\u6570\u91cf\u7684\u5f52\u7f6e\u7ec4\u3002 ceph \u5728\u521b\u5efa\u4e00\u6216\u591a\u4e2a\u5f52\u7f6e\u7ec4\u65f6\u4f1a\u663e\u793a creating\u3002 \u521b\u5efa\u5b8c\u540e\uff0c\u5728\u5176\u5f52\u7f6e\u7ec4\u7684 Acting Set \u91cc\u7684 OSD \u5c06\u5efa\u7acb\u4e92\u8054\u3002 \u4e00\u65e6\u4e92\u8054\u5b8c\u6210\uff0c\u5f52\u7f6e\u7ec4\u72b6\u6001\u5e94\u8be5\u53d8\u4e3a active+clean\uff0c\u610f\u601d\u662fceph \u5ba2\u6237\u7aef\u53ef\u4ee5\u5411\u5f52\u7f6e\u7ec4\u5199\u5165\u6570\u636e\u4e86\u3002 peering ceph \u4e3a\u5f52\u7f6e\u7ec4\u5efa\u7acb\u4e92\u8054\u65f6\uff0c\u4f1a\u8ba9\u5b58\u50a8\u5f52\u7f6e\u7ec4\u526f\u672c\u7684 OSD \u4e4b\u95f4\u5c31\u5176\u4e2d\u7684\u5bf9\u8c61\u548c\u5143\u6570\u636e\u72b6\u6001\u8fbe\u6210\u4e00\u81f4\u3002 ceph \u5b8c\u6210\u4e86\u4e92\u8054\uff0c\u4e5f\u5c31\u610f\u5473\u7740\u5b58\u50a8\u7740\u5f52\u7f6e\u7ec4\u7684 OSD \u5c31\u5176\u5f53\u524d\u72b6\u6001\u8fbe\u6210\u4e86\u4e00\u81f4\u3002 \u7136\u800c\uff0c\u4e92\u8054\u8fc7\u7a0b\u7684\u5b8c\u6210\u5e76\u4e0d\u80fd\u8868\u660e\u5404\u526f\u672c\u90fd\u6709\u4e86\u6570\u636e\u7684\u6700\u65b0\u7248\u672c\u3002 active ceph \u5b8c\u6210\u4e92\u8054\u8fdb\u7a0b\u540e,\u4e00\u5f52\u7f6e\u7ec4\u5c31\u53ef\u53d8\u4e3a active\u3002 active \u72b6\u6001\u901a\u5e38\u610f\u5473\u7740\u5728\u4e3b\u5f52\u7f6e\u7ec4\u548c\u526f\u672c\u4e2d\u7684\u6570\u636e\u90fd\u53ef\u4ee5\u8bfb\u5199\u3002 clean \u67d0\u4e00\u5f52\u7f6e\u7ec4\u5904\u4e8e clean \u72b6\u6001\u65f6\uff0c\u4e3b OSD \u548c\u526f\u672c OSD \u5df2\u6210\u529f\u4e92\u8054\uff0c\u5e76\u4e14\u6ca1\u6709\u504f\u79bb\u7684\u5f52\u7f6e\u7ec4\u3002 ceph \u5df2\u628a\u5f52\u7f6e\u7ec4\u4e2d\u7684\u5bf9\u8c61\u590d\u5236\u4e86\u89c4\u5b9a\u6b21\u6570\u3002 degraded \u5f53\u5ba2\u6237\u7aef\u5411\u4e3b OSD \u5199\u5165\u6570\u636e\u65f6\uff0c\u7531\u4e3b OSD \u8d1f\u8d23\u628a\u526f\u672c\u5199\u5165\u5176\u4f59\u590d\u5236 OSD\u3002 \u4e3b OSD \u628a\u5bf9\u8c61\u5199\u5165\u590d\u5236 OSD \u540e\uff0c\u5728\u6ca1\u6536\u5230\u6210\u529f\u5b8c\u6210\u7684\u786e\u8ba4\u524d\uff0c\u4e3b OSD \u4f1a\u4e00\u76f4\u505c\u7559\u5728 degraded \u72b6\u6001\u3002 \u5f52\u7f6e\u7ec4\u72b6\u6001\u53ef\u4ee5\u662f active+degraded \u72b6\u6001\uff0c\u539f\u56e0\u5728\u4e8e\u4e00 OSD \u5373\u4f7f\u6ca1\u6240\u6709\u5bf9\u8c61\u4e5f\u53ef\u4ee5\u5904\u4e8e active \u72b6\u6001\u3002 \u5982\u679c\u4e00OSD \u6302\u4e86\uff0cceph \u4f1a\u628a\u76f8\u5173\u7684\u5f52\u7f6e\u7ec4\u90fd\u6807\u8bb0\u4e3a degraded\u3002 \u90a3\u4e2a OSD \u91cd\u751f\u540e\uff0c\u5b83\u4eec\u5fc5\u987b\u91cd\u65b0\u4e92\u8054\u3002 \u7136\u800c\uff0c\u5982\u679c\u5f52\u7f6e\u7ec4\u4ecd\u5904\u4e8e active \u72b6\u6001\uff0c\u5373\u4fbf\u5b83\u5904\u4e8e degraded \u72b6\u6001\uff0c\u5ba2\u6237\u7aef\u8fd8\u53ef\u4ee5\u5411\u5176\u5199\u5165\u65b0\u5bf9\u8c61\u3002 \u5982\u679c\u4e00 OSD \u6302\u4e86\uff0c\u4e14 degraded \u72b6\u6001\u6301\u7eed\uff0cceph \u4f1a\u628a down \u7684 OSD \u6807\u8bb0\u4e3a\u5728\u96c6\u7fa4\u5916(out)\u3001\u5e76\u628a\u90a3\u4e9b down \u6389\u7684 OSD \u4e0a\u7684\u6570\u636e\u91cd\u6620\u5c04\u5230\u5176\u5b83 OSD\u3002 \u4ece\u6807\u8bb0\u4e3a down \u5230 out \u7684\u65f6\u95f4\u95f4\u9694\u7531 mon osd down out interval \u63a7\u5236,\u9ed8\u8ba4\u662f 300 \u79d2\u3002 \u5f52\u7f6e\u7ec4\u4e5f\u4f1a\u88ab\u964d\u7ea7(degraded)\uff0c\u56e0\u4e3a\u5f52\u7f6e\u7ec4\u627e\u4e0d\u5230\u672c\u5e94\u5b58\u5728\u4e8e\u5f52\u7f6e\u7ec4\u4e2d\u7684\u4e00\u6216\u591a\u4e2a\u5bf9\u8c61\uff0c\u8fd9\u65f6\uff0c\u4f60\u4e0d\u80fd\u8bfb\u6216\u5199\u627e\u4e0d\u5230\u7684\u5bf9\u8c61\uff0c\u4f46\u4ecd\u80fd\u8bbf\u95ee\u5176\u5b83\u4f4d\u4e8e\u964d\u7ea7\u5f52\u7f6e\u7ec4\u4e2d\u7684\u5bf9\u8c61\u3002 recovering ceph \u88ab\u8bbe\u8ba1\u4e3a\u53ef\u5bb9\u9519\uff0c\u53ef\u62b5\u5fa1\u4e00\u5b9a\u89c4\u6a21\u7684\u8f6f\u3001\u786c\u4ef6\u95ee\u9898\u3002 \u5f53\u67d0 OSD \u6302\u4e86(down)\u65f6\uff0c\u5176\u5185\u5bb9\u7248\u672c\u4f1a\u843d\u540e\u4e8e\u5f52\u7f6e\u7ec4\u5185\u7684\u5176\u5b83\u526f\u672c\u3002 \u5b83\u91cd\u751f(up)\u65f6\uff0c\u5f52\u7f6e\u7ec4\u5185\u5bb9\u5fc5\u987b\u66f4\u65b0\uff0c\u4ee5\u53cd\u6620\u5f53\u524d\u72b6\u6001\u3002 \u5728\u6b64\u671f\u95f4\uff0cOSD \u5728recovering \u72b6\u6001\u3002 \u4e00\u6b21\u786c\u4ef6\u5931\u8d25\u53ef\u80fd\u7275\u8fde\u591a\u4e2a OSD\u3002\u6bd4\u5982\u4e00\u4e2a\u673a\u67dc\u7684\u7f51\u7edc\u4ea4\u6362\u673a\u5931\u8d25\u4e86\uff0c\u8fd9\u4f1a\u5bfc\u81f4\u591a\u4e2a\u4e3b\u673a\u843d\u540e\u4e8e\u96c6\u7fa4\u7684\u5f53\u524d\u72b6\u6001\uff0c\u95ee\u9898\u89e3\u51b3\u540e\u6bcf\u4e00\u4e2a OSD \u90fd\u5fc5\u987b\u6062\u590d\u3002 ceph \u63d0\u4f9b\u4e86\u5f88\u591a\u9009\u9879\u6765\u5747\u8861\u8d44\u6e90\u7ade\u4e89\uff0c\u5982\u65b0\u670d\u52a1\u8bf7\u6c42\u3001\u6062\u590d\u6570\u636e\u5bf9\u8c61\u548c\u6062\u590d\u5f52\u7f6e\u7ec4\u5230\u5f53\u524d\u72b6\u6001\u3002 osd recovery delay start \u9009\u9879\u5141\u8bb8\u4e00 OSD \u5728\u5f00\u59cb\u6062\u590d\u8fdb\u7a0b\u524d\uff0c\u5148\u91cd\u542f\u3001\u91cd\u5efa\u4e92\u8054\u3001\u751a\u81f3\u5904\u7406\u4e00\u4e9b\u91cd\u653e\u8bf7\u6c42\u3002 osd recovery threads \u9009\u9879\u9650\u5236\u6062\u590d\u8fdb\u7a0b\u7684\u7ebf\u7a0b\u6570\uff0c\u9ed8\u8ba4\u4e3a 1 \u7ebf\u7a0b\u3002 osd recovery thread timeout \u8bbe\u7f6e\u7ebf\u7a0b\u8d85\u65f6\uff0c\u56e0\u4e3a\u591a\u4e2aOSD \u53ef\u80fd\u4ea4\u66ff\u5931\u8d25\u3001\u91cd\u542f\u548c\u91cd\u5efa\u4e92\u8054\u3002 osd recovery max active \u9009\u9879\u9650\u5236\u4e00 OSD \u6700\u591a\u540c\u65f6\u63a5\u53d7\u591a\u5c11\u8bf7\u6c42\uff0c\u4ee5\u9632\u5b83\u538b\u529b\u8fc7\u5927\u800c\u4e0d\u80fd\u6b63\u5e38\u670d\u52a1\u3002 osd recovery max chunk \u9009\u9879\u9650\u5236\u6062\u590d\u6570\u636e\u5757\u5c3a\u5bf8\uff0c\u4ee5\u9632\u7f51\u7edc\u62e5\u585e\u3002 back filling \u6709\u65b0 OSD \u52a0\u5165\u96c6\u7fa4\u65f6\uff0cCRUSH \u4f1a\u628a\u73b0\u6709\u96c6\u7fa4\u5185\u7684\u5f52\u7f6e\u7ec4\u91cd\u5206\u914d\u7ed9\u5b83\u3002 \u5f3a\u5236\u65b0 OSD \u7acb\u5373\u63a5\u53d7\u91cd\u5206\u914d\u7684\u5f52\u7f6e\u7ec4\u4f1a\u4f7f\u4e4b\u8fc7\u8f7d\uff0c\u7528\u5f52\u7f6e\u7ec4\u56de\u586b\u53ef\u4f7f\u8fd9\u4e2a\u8fc7\u7a0b\u5728\u540e\u53f0\u5f00\u59cb\u3002 \u56de\u586b\u5b8c\u6210\u540e\uff0c\u65b0 OSD \u51c6\u5907\u597d\u65f6\u5c31\u53ef\u4ee5\u5bf9\u5916\u670d\u52a1\u4e86\u3002 remapped \u67d0\u4e00\u5f52\u7f6e\u7ec4\u7684 Acting Set \u53d8\u66f4\u65f6\uff0c\u6570\u636e\u8981\u4ece\u65e7\u96c6\u5408\u8fc1\u79fb\u5230\u65b0\u7684\u3002 \u4e3b OSD \u8981\u82b1\u8d39\u4e00\u4e9b\u65f6\u95f4\u624d\u80fd\u63d0\u4f9b\u670d\u52a1\uff0c\u6240\u4ee5\u5b83\u53ef\u4ee5\u8ba9\u8001\u7684\u4e3b OSD \u6301\u7eed\u670d\u52a1\u3001\u76f4\u5230\u5f52\u7f6e\u7ec4\u8fc1\u79fb\u5b8c\u3002 \u6570\u636e\u8fc1\u79fb\u5b8c\u540e,\u4e3b OSD \u4f1a\u6620\u5c04\u5230\u65b0 acting set\u3002 stale \u867d\u7136 ceph \u7528\u5fc3\u8df3\u6765\u4fdd\u8bc1\u4e3b\u673a\u548c\u5b88\u62a4\u8fdb\u7a0b\u5728\u8fd0\u884c\uff0c\u4f46\u662f ceph-osd \u4ecd\u6709\u53ef\u80fd\u8fdb\u5165 stuck \u72b6\u6001\uff0c\u5b83\u4eec\u6ca1\u6709\u6309\u65f6\u62a5\u544a\u5176\u72b6\u6001(\u5982\u7f51\u7edc\u77ac\u65ad)\u3002 \u9ed8\u8ba4OSD \u5b88\u62a4\u8fdb\u7a0b\u6bcf\u534a\u79d2(0.5)\u4f1a\u4e00\u6b21\u62a5\u544a\u5176\u5f52\u7f6e\u7ec4\u3001\u51fa\u6d41\u91cf\u3001\u5f15\u5bfc\u548c\u5931\u8d25\u7edf\u8ba1\u72b6\u6001\uff0c\u6b64\u9891\u7387\u9ad8\u4e8e\u5fc3\u8df3\u9600\u503c\u3002 \u5982\u679c\u4e00\u5f52\u7f6e\u7ec4\u7684\u4e3b OSD \u6240\u5728\u7684 acting set \u6ca1\u80fd\u5411\u76d1\u89c6\u5668\u62a5\u544a\u3001\u6216\u8005\u5176\u5b83\u76d1\u89c6\u5668\u5df2\u7ecf\u62a5\u544a\u4e86\u90a3\u4e2a\u4e3b OSD \u5df2 down\uff0c\u76d1\u89c6\u5668\u4eec\u5c31\u4f1a\u628a\u6b64\u5f52\u7f6e\u7ec4\u6807\u8bb0\u4e3a stale\u3002 \u542f\u52a8\u96c6\u7fa4\u65f6\uff0c\u4f1a\u7ecf\u5e38\u770b\u5230 stale \u72b6\u6001\uff0c\u76f4\u5230\u4e92\u8054\u5b8c\u6210\u3002 \u96c6\u7fa4\u8fd0\u884c\u4e00\u9635\u540e\uff0c\u5982\u679c\u8fd8\u80fd\u770b\u5230\u6709\u5f52\u7f6e\u7ec4\u4f4d\u4e8e stale \u72b6\u6001\uff0c\u5c31\u8bf4\u660e\u90a3\u4e9b\u5f52\u7f6e\u7ec4\u7684\u4e3b OSD \u6302\u4e86(down)\u3001\u6216\u6ca1\u5728\u5411\u76d1\u89c6\u5668\u62a5\u544a\u7edf\u8ba1\u4fe1\u606f\u3002 Each pool has its own autoscaler settings The PG balancer optimizes the placement of PGs across OSD crush-compat mode It's default mode Uses the compat weight-set feature upmap mode. It's perfect mode, which an equal number of PGs on each OSD Use fine-grained control over the PG mapping Snapshots Rulesets to manage CRUSH placement Each pool has a defined CRUSH ruleset A CRUSH ruleset is a definition of how the OSDs organize data This allows configuration of data distribution to be managed per pool A single CRUSH ruleset can be reused by multiple pools A ruleset can take into account: \u9700\u8981\u8003\u8651\u7684\u70b9 physical layout of nodes in the cluster organization of network infrastructure selection of OSDs backed by SSDs versus HDDs, etc Each pool can use either Replication or Erasure Coding Replication is the original, default approach to resiliency Erasure Coded pools have an EC Profile assigned Different than CRUSH rulesets, but similar: define how OSDs organize data The profile defines K, M values; encoding method/plugin; etc CRUSH (Controllable Replication Under Scalable Hashing) \u00b6 CRUSH is a key piece of the Ceph storage solution With the CRUSH algorithm used by Ceph: Data is not centrally stored, it is distributed CRUSH calculates the storage location for each object dynamically No requirement to store a global index of object locations CRUSH Algorithm \u00b6 The CRUSH algorithm deterministically calculates the location of any object in the Ceph RADOS cluster Overhead is low and calculation is performed by each client As no metadata store is required, CRUSH removes the limitations of traditional metadata based management No direct control over the placement of your data in the cluster Higher CPU requirements CRUSH Maps and Rulesets \u00b6 CRUSH Rulesets are the named sets of rules: Combining all of the customizable CRUSH behavior settings Assigned to pool to govern how the pool\u2019s data is distributed in the cluster CRUSH Maps are central to how Ceph distributes data, and maintaining the durability of the data When the cluster is deployed, Ceph creates a simple default ruleset for replicated pools: replicated_rule CRUSH behavior depends on the behaviors and performance of storage devices CRUSH Maps should be crafted to take advantage of those behaviors Rulesets should be used to clearly identify how the devices in your environment should be employed Device Classes exist to indicate performance behavior: hdd, ssd, nvme Ceph OSDs will automatically set the Device Class of a storage device when the OSD is started Working with CRUSH Map Rulesets List the OSDs, which host each OSD belongs to: ceph osd tree ceph osd df tree ceph osd df tree -f json-pretty Find the host of a specific OSD: ceph osd find 8 Show the existing defined rulesets: ceph osd crush rule ls Examine the definition of an existing ruleset: ceph osd crush rule dump There are 3 options for creating a new ruleset: simple replicated erasure Creating new rulesets: ceph osd crush rule create-replicated ceph osd crush rule create-erasure Create a new ruleset using a Device Class: create-replicated Description : The name of the node under which data should be placed. Type : String Example : default (rarely would you need to make this different than \u201cdefault\u201d) or Description : The type of CRUSH node (bucket) across which replicas should be separated. Type : String Example : rack Description : The device class data should be placed on. Type : String Example : ssd CRUSH Weight \u00b6 You may need to move data around New nodes degraded nodes rebalancing View the current CRUSH weights ceph osd crush tree ceph osd df tree Change the weight for an OSD ceph osd crush reweight The important difference between ceph osd reweight and ceph osd crush reweight \"ceph osd crush reweight\" sets the CRUSH weight of the OSD. This weight is an arbitrary value (generally the size of the disk in TB or something) and controls how much data the system tries to allocate to the OSD. \"ceph osd reweight\" sets an override weight on the OSD. This value is in the range 0 to 1, and forces CRUSH to re-place (1-weight) of the data that would otherwise live on this drive. It does not change the weights assigned to the buckets above the OSD, and is a corrective measure in case the normal CRUSH distribution isn\u2019t working out quite right. \"ceph osd reweight\" is temporary. \"ceph osd crush reweight\" is sticky, permanent (until you change it again). Setting a weight of an OSD to 0 is effectively setting the OSD \"out\" - you don\u2019t want it to store data. The Monitor\u2019s Cluster Map contains \u00b6 Monitor Map Unique Cluster ID, details of each Mon node, current epoch, date/time of last change OSD Map Contains the cluster fsid, when the map was created and last modified, a list of pools, replica sizes, PG numbers, a list of OSDs and their status PG Map Contains the PG version, its time stamp, the last OSD map epoch, the full ratios, and details on each placement group such as the PG ID, the Up Set, the Acting Set, the state of the PG (e.g., active + clean), and data usage statistics for each pool MDS Map Contains the current MDS map epoch, references to pool(s) for storing metadata, list of MDS servers, and which metadata servers are up and in CRUSH Map Contains a list of storage devices, the failure domain hierarchy (e.g., device, host, rack, row, room, etc.), and rules for traversing the hierarchy when storing data CRUSH Hierarchy \u00b6 The CRUSH Map includes details of physical & network infrastructure The CRUSH Map hierarchy is defined by a storage architect The default hierarchical list of infrastructure elements: (Hierarchy of CRUSH buckets) OSD host chassis \u5200\u7247\u673a\u7bb1 rack \u673a\u67b6 row pdu \u7535\u6e90\u5206\u914d\u5355\u5143 pod \u6027\u80fd\u4f18\u5316\u7684\u6570\u636e\u4e2d\u5fc3(Performance Optimize Datacenter)\uff0c\u57fa\u4e8e\u6807\u51c6\u5316\u8bbe\u65bd\u7684\u6700\u4f73\u5b9e\u8df5\uff0c\u6bcf\u4e2aPOD\u5185IT\u90e8\u5206\u5305\u542b\u76845000\u53f0\u670d\u52a1\u5668\uff0c\u5206\u5c5e\u5230200\u4e2a\u673a\u67b6\uff0c\u5982\u679c\u4ee5\u6bcf\u53f0\u670d\u52a1\u5668400W\u529f\u7387\u8ba1\u7b97\u7684\u8bdd\uff0c\u6bcf\u4e2a\u673a\u67dc\u9700\u898110KW\u7684\u4f9b\u7535\uff0c\u5373\u6bcf\u4e2aPOD\u7684IT\u8d1f\u8f7d\u5bb9\u91cf\u662f2MW\u3002 room datacenter region root CRUSH is the algorithm and calculation for distributing data through the cluster. CRUSH Map obviously plays a part in how those CRUSH calculations work. CRUSH Map Sections (Six main sections) \u00b6 tunables: adjustments to legacy behavior devices: The list of OSDs (usually no customization needed) \u25cb \"device class\" is meaningful; useful in relation to creating/using CRUSH rulesets \u25cb Standard \"device class\" values are \"hdd.\", \"ssd.\", and \"nvme.\" \u25cb Example: device 7 osd.7 types: types of buckets (usually no customization needed) buckets: the most functional, customizable aspect of the Map \u25cb A bucket typically represents a physical location in the cluster, has a \u201ctype\u201d \u25cb Nodes (containers such as hosts) and leaves (storage devices such as OSDs) rules: define policies of how data should be distributed \u25cb The behind-the-scenes rules that CRUSH follows for data placement \u25cb IMPORTANT: this is NOT the same as the \"ruleset\". In fact, a ruleset is the combined set of all of these six Map sections. choose_args (optional): Rarely used exceptional settings to adjust weights From the documentation: \"choose_args are alternative weights associated with the hierarchy that have been adjusted to optimize data placement. A single choose_args map can be used for the entire cluster, or one can be created for each individual pool.\" Erasure Coding \u00b6 In information theory : an erasure code is a forward error correction (FEC, \u524d\u5411\u7ea0\u9519) code for the binary erasure channel, which transforms a message of k symbols into a longer message (code word) with n symbols such that the original message can be recovered from a subset of the n symbols. The fraction r = k/n is called the code rate The fraction k\u2019/k, where k\u2019 denotes the number of symbols required for recovery, is called reception efficiency Another (easier) way of describing EC: It\u2019s like RAID in Clustered Storage Erasure Coding in SES \u00b6 The default resilience strategy in SES is simple replication * SES Simple replication has overheads, size=3 means 3 times the storage requirements Simplistic EC details: k = number of \u201cdata\u201d chunks, split across \u201ck\u201d number of OSDs m = number of \u201cparity\u201d chunks, split across \u201cm\u201d number of OSDs Ceph calls these \u201ccoding chunks\u201d r (size) = k + m admin:~ # ceph osd crush rule ls replicated_rule Replication vs Erasure Code \u00b6 Replication (default): Use Case: active data Simple and fast Uses more disk space Erasure coding: Use Case: archive data, more static data Calculates recovery data (needs more CPU power) Definable redundancy level Example: K data chunks = 2 , M code chunks = 1 Similar to a replication size of 2 But with only 50% more raw storage consumed Example: for 1GB of effective storage replication pool of size of 2 needs 2GB raw storage erasure coded pool with k=2/m=1 only requires 1.5GB raw storage EC Overwrites \u00b6 Historically, EC only works properly with Objects EC only allowed appends; overwrites were not allowed Works perfectly for objects in buckets but doesn\u2019t work well with Block or CephFS With recent releases of SES, EC can work well with Block and CephFS Facilitated by \u201cEC Overwrites\u201d feature Store data in an EC Pool, and store object metadata in a Replicated Pool Requires a little extra work when defining pools, but worth it ceph osd pool set allow_ec_overwrites true EC Profiles \u00b6 Using Erasure Coding, each Pool is assigned an EC Profile Multiple pools can share a single Profile The profile is just a definition Each Profile has multiple settings The common required settings for all Profiles are K, M EC Profiles must be created before EC Pools can be created Created from the Dashboard or CLI Once an EC Profile is created, you can create a CRUSH Ruleset based on the EC profile Once a pool is created, its EC Profile properties cannot be changed Main profile parameters K: M: stripe_unit - allows you to adjust the size of the data chunk Default size is 4K stripe_unit : size of data striped across devices; default 4K This variable can also be set in the master configuration (osd_erasure_code_stripe_unit) EC plugins - choose your favorite EC algorithm via a plugin jerasure/gf-complete (default, free, open, and very fast) (www.jerasure.org) ISA (Intel library; optimized for modern Intel processors) (only runs on Intel processors) LRC (\u201cLocally Repairable Code\u201d; layers over existing plugins) SHEC (\u201cShingled EC\u201d; trades extra storage for recovery efficiency) CLAY (\u201cCoupled LAYer\u201d; good for reduced network traffic) Creating Erasure Code Profiles and Pools \u00b6 Syntax: ceph osd erasure-code-profile OPTIONS Option Description get - view details of an existing EC profile set - set a profile (create a profile), requires k and m values, with optional values such as ruleset, plugin. Once you create a profile, you can\u2019t change it. ceph osd erasure-code-profile set k= m= [plugin=] [stripe_unit=] ls - list profiles rm - Remove an EC profile ceph osd erasure-code-profile rm Common example (below) The default profile \u2012 2+1=3; data is written over 3 OSDs \u2012 Two data chunks \u2012 One code (parity) chunk \u2012 Uses jerasure plugin with standard Reed/Solomon (reed_sol_van) technique Setting a Custom EC Profile Option: \u2012 Profile name \u2012 K : number of stripes required \u2012 M : number of failed units Example: ceph osd erasure-code-profile set example-profile k=8 m=2 ruleset-failure-domain=host ruleset-failure-domain = crush bucket level for failure admin:/etc/ceph # ceph osd erasure-code-profile \\ set common_profile \\ k=4 \\ m=2 \\ plugin=jerasure \\ technique=reed_sol_van \\ stripe_unit=4K \\ crush-root=default \\ crush-failure-domain=rackcrush-device-class=ssd admin:/etc/ceph # ceph osd erasure-code-profile ls default admin:~ # ceph osd erasure-code-profile get default k=2 m=1 plugin=jerasure technique=reed_sol_van Pools Pools are at the heart of Storage Pools are tied to OSDs Display a list of existing pools: ceph osd pool ls or ceph osd lspools View the statistics and characteristics of pools: ceph osd pool stats ceph osd pool stats ceph osd pool get Show usage and related details of existing pools: rados df or ceph df or ceph df detail All storage revolves around Pools Each pool must be dedicated to a purpose: Object, Block, File Must specify # of Placement Groups and PG Placements Must specify whether using Replication or EC Must specify a CRUSH ruleset Create a Replicated Pool Syntax: ceph osd pool create replicated = number of placement groups for the pool = number of PGs for placement; routinely will be the same as pg_num Always a power of 2 Don\u2019t make the number too small; don\u2019t err on the high side, either Practices For a new pool, the pgp_num will generally (likley) just be the same as the pg_num When increasing the PGs in a pool, you may want to retain the smaller pgp_num to minimize rebalancing, and increase pgp_num later when rebalancing is more convenient If decreasing the PGs in a pool, the pgp_num is adjusted automatically Create an EC Pool (using an EC Profile) Syntax: ceph osd pool create erasure Example: ceph osd pool create EC-pool 128 128 erasure my-ec-profile Pools \u2013 Application Assignment Each Pool must have a stated purpose; application This defines which capabilities the Pool must support The applications are: Block (rbd), Object (rgw), and File (cephfs) There are subtypes of cephfs: i.e. cephfs:data, cephfs:metadata Application assignment happens after creating a pool It\u2019s effortless (and required) to assign an application on a new pool ceph osd pool application enable Changing application assignment after a pool is in use is \u201chard\u201d. Not recommended, only to be done as an expert Pools \u2013 Quotas One of the more desirable features of SDS is to set a maximum usage of a Pool - Quotas Prevent the over-use of a pool Set quotas based on number of objects or number of bytes ceph osd pool set-quota max_objects ceph osd pool set-quota max_bytes Show quota settings ceph osd pool get-quota To remove a quota, set the existing quota setting to 0 There are also application-level quotas For rgw and cephfs (not rbd; images are already limited in size) Pool Quotas vs. Application Quotas. When a pool quota nears its limit, the HEALTH mechanisms will display a \u201cPOOL_NEAR_FULL\u201d warning to the storage administrator. When the quota limit has been exceeded, the HEALTH mechanisms will display a \u201cPOOL_FULL\u201d warning to the storage administrator. Applications (clients) don\u2019t always handle the quotas cleanly. In most cases, once the Pool Quota is exceeded, the application will simply stop writing to the pool, and error messages and behavior at the application are inconsistent (if there are any messages at all). Pools \u2013 Snapshots Take (make) a snapshot of an existing pool ceph osd pool mksnap Remove a snapshot of a pool ceph osd pool rmsnap List pool snapshots rados -p lssnap Rollback the pool to an earlier snapshot rados -p rollback Images and cephfs have their own snapshot facilities. Object and Bucket snapshotting features related to rgw don\u2019t exist. Pools Snapshots versus App Snapshots The two different snapshot features cannot be used at the same time on a pool Either Pool Snapshots, or Application Snapshots; not both. (snap_mode = pool versus snap_mode = selfmanaged) Once you commit to pool snapshots for an RBD pool, you can\u2019t change to using RBD snapshots Pros and Cons of each, depending on your Use Case admin:~ # ceph osd pool ls detail -f json-pretty | grep snap_mode \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", BlueStore \u00b6 BlueStore is the default storage backend in SES Highlighted features: compressing, no double-writes, faster checksums Ceph FileStore Model It is not ideal for a specialized purpose like a highly scalable distributed storage system. Only recommend that XFS be used. Both btrfs and ext4 have known bugs. The FileStore model uses cache from the filesystem (XFS). Memory for cache is managed by filesystem kernel module. Ceph BlueStore Model BlueStore consumes raw block devices. Metadata management with RocksDB. BlueStore employs RocksDB\u2019s key/value database in order to manage internal metadata, such as the mapping from object names to block locations on disk. Full data and metadata checksumming. By default all data and metadata written to BlueStore is protected by one or more checksums. A small specialized filesystem called BlueFS. This provides just enough of a filesystem to allow RocksDB to store its \"key/value files\" to share metadata across all the raw device(s) No data or metadata will be read from disk or returned to the user without being verified. Multi-device metadata tiering. BlueStore allows its internal journal (write-ahead log) to be written to a separate, highspeed device (like an SSD, NVMe, or NVDIMM) to increased performance. Efficient copy-on-write. RBD and CephFS snapshots rely on a copy-on-write clone mechanism that is implemented efficiently in BlueStore. BlueStore is a userspace model that provides its own memory management and cache. No need to clear the storage device cache OSDs help facilitate the performance of caching Default: cache the reads, don\u2019t cache the writes RocksDB\uff1a rocksdb\u662ffacebook\u57fa\u4e8eleveldb\u5f00\u53d1\u7684\u4e00\u6b3ekv\u6570\u636e\u5e93\uff0cBlueStore\u5c06\u5143\u6570\u636e\u5168\u90e8\u5b58\u653e\u81f3RocksDB\u4e2d\uff0c\u8fd9\u4e9b\u5143\u6570\u636e\u5305\u62ec\u5b58\u50a8\u9884\u5199\u5f0f\u65e5\u5fd7\u3001\u6570\u636e\u5bf9\u8c61\u5143\u6570\u636e\u3001Ceph\u7684omap\u6570\u636e\u4fe1\u606f\u3001\u4ee5\u53ca\u5206\u914d\u5668\u7684\u5143\u6570\u636e \u3002 BlueRocksEnv\uff1a \u662fRocksDB\u4e0eBlueFS\u4ea4\u4e92\u7684\u63a5\u53e3\uff1bRocksDB\u63d0\u4f9b\u4e86\u6587\u4ef6\u64cd\u4f5c\u7684\u63a5\u53e3EnvWrapper\uff0c\u7528\u6237\u53ef\u4ee5\u901a\u8fc7\u7ee7\u627f\u5b9e\u73b0\u8be5\u63a5\u53e3\u6765\u81ea\u5b9a\u4e49\u5e95\u5c42\u7684\u8bfb\u5199\u64cd\u4f5c\uff0cBlueRocksEnv\u5c31\u662f\u7ee7\u627f\u81eaEnvWrapper\u5b9e\u73b0\u5bf9BlueFS\u7684\u8bfb\u5199\u3002 BlueFS\uff1a BlueFS\u662fBlueStore\u9488\u5bf9RocksDB\u5f00\u53d1\u7684\u8f7b\u91cf\u7ea7\u6587\u4ef6\u7cfb\u7edf\uff0c\u7528\u4e8e\u5b58\u653eRocksDB\u4ea7\u751f\u7684.sst\u548c.log\u7b49\u6587\u4ef6\u3002 BlockDecive\uff1a BlueStore\u629b\u5f03\u4e86\u4f20\u7edf\u7684ext4\u3001xfs\u6587\u4ef6\u7cfb\u7edf\uff0c\u4f7f\u7528\u76f4\u63a5\u7ba1\u7406\u88f8\u76d8\u7684\u65b9\u5f0f\uff1b BlueStore\u652f\u6301\u540c\u65f6\u4f7f\u7528\u591a\u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u8bbe\u5907\uff0c\u5728\u903b\u8f91\u4e0aBlueStore\u5c06\u5b58\u50a8\u7a7a\u95f4\u5212\u5206\u4e3a\u4e09\u5c42\uff1a\u6162\u901f\uff08Slow\uff09\u7a7a\u95f4\u3001\u9ad8\u901f\uff08DB\uff09\u7a7a\u95f4\u3001\u8d85\u9ad8\u901f\uff08WAL\uff09\u7a7a\u95f4\uff0c\u4e0d\u540c\u7684\u7a7a\u95f4\u53ef\u4ee5\u6307\u5b9a\u4f7f\u7528\u4e0d\u540c\u7684\u8bbe\u5907\u7c7b\u578b\uff0c\u5f53\u7136\u4e5f\u53ef\u4f7f\u7528\u540c\u4e00\u5757\u8bbe\u5907\u3002 Allocator\uff1a\u8d1f\u8d23\u88f8\u8bbe\u5907\u7684\u7a7a\u95f4\u7ba1\u7406\uff0c\u53ea\u5728\u5185\u5b58\u505a\u6807\u8bb0\uff0c\u76ee\u524d\u652f\u6301StupidAllocator\u548cBitmapAllocator\u4e24\u79cd\u5206\u914d\u5668,Stupid\u57fa\u4e8eextent\u7684\u65b9\u5f0f\u5b9e\u73b0 Ceph BlueStore with Mixed Devices BlueStore Cache Parameters \u00b6 Under most circumstances, autotune is best bluestore_cache_autotune Description: Automatically tune the ratios assigned to different bluestore caches while respecting minimum values Type: Boolean Required: Yes Default: True (enabled) Related settings: bluestore_cache_autotune_chunk_size, bluestore_cache_autotune_interval, and others bluestore_cache_size Description: The amount of memory BlueStore will use for its cache. If zero, bluestore_cache_size_hdd or bluestore_cache_size_ssd will be used instead. Type: Integer Required: Yes Default: 0 bluestore_cache_size_hdd Description: The default amount of memory BlueStore will use for its cache when backed by an HDD Type: Integer Required: Yes Default: 1 * 1024 * 1024 * 1024 (1 GB) bluestore_cache_size_ssd Description: The default amount of memory BlueStore will use for its cache when backed by an SSD. Type: Integer Required: Yes Default: 3 * 1024 * 1024 * 1024 (3 GB) bluestore_cache_meta_ratio Description: The ratio of cache devoted to metadata. Type: Floating point Default: .01 bluestore_cache_kv_ratio Description: The ratio of cache devoted to key/value data (rocksdb). Type : Floating point Default: .99 bluestore_cache_kv_max Description : The maximum amount of cache devoted to key/value data (rocksdb). Type : Unsigned Integer Default : 512 * 1024*1024 (512 MB) BlueStore Device Types \u00b6 BlueStore has three types of roles for devices: The DATA role: Required: main device (block symlink) stores all object data. If no other types: \u201cdata\u201d device serves all the other roles The DB role: Optional: DB device (block.db symlink) stores metadata in RocksDB Whatever doesn\u2019t fit will spill back onto the \u201cdata\u201d device The Write Ahead Log (WAL/Journal) role: Optional: WAL device (block.wal symlink) stores the internal journal Can combine all 3 roles into one physical device Or combine DB/WAL onto a single device with the DATA device separate Or all three on seperate devices BlueStore Configuration Recommendations \u00b6 Devote DB and WAL to SSD or NVMe Allocate 64 GB to the RocksDB Allocate 4-6 GB to the WAL Assign the \u201cdata\u201d role to the slower (HDD) devices If combining WAL/DB on one device, use a single partition for both You can use a single SSD/NVMe to store multiple journals Architecture Overview of Object, Block, Filesystem Access \u00b6 Object Storage \u00b6 The state of the art of distributed storage Object storage is the Cloud Storage mechanism of choice Unstructured, to better accommodate large files and large quantities of files Ideal for large media files, like streaming videos, audio Scales really well, large capacities Ceph provides access to the storage via all three major data access methods: Block, Object, and File. For the storage backend, Object Storage is ideal Block Storage \u00b6 Traditional Block Storage: Volumes as a collection of blocks Blocks can be of various sizes, but all the same within a volume Typically a filesystem is installed on top of the volume Hard Drives, CDs, USB sticks, etc The standard disk device mechanism for Unix, Linux, Windows, etc. Ceph presents RADOS as block device (RBD = RADOS Block Device) Ceph calls these block devices \u201cimages\u201d Provides clients with access like a \u201cdisk drive\u201d KVM/QEMU; libvirt; or remote Linux system A native Windows client that can access the Block storage of Ceph directly is in progress RADOS Block Device (RBD) \u00b6 RBD is the RADOS Block Device A specific RBD instance in the cluster is called an \u201cimage\u201d RBD images can be accessed by OSs other than linux librbd provides interface for gateways like iSCSI RBD allows the client to decide what to do with the storage Filesystem type; raw disk, such as for a DB; etc RBD images can accommodate 16Eb file system sizes No matter the size, the storage is distributed durably throughout the cluster Data is striped across the RADOS cluster in object sized chunks 4MB default Provides high performance and durability Notable Benefits Ability to mount with Linux or QEMU KVM clients Thinly provisioned Resizable images Image import/export Image copy or rename Read-only snapshots Revert to snapshots Copy on Write clones Useful for standing up lots of virtual machines with same base configuration High performance due to striping across cluster nodes RBD image definition: Defined storage area presented as a block device to a client RBD Storage File Storage \u00b6 POSIX Filesystem via CephFS File access is a significant use case Home directories Historical comfort with files and directories Ease of managing \u201csmall\u201d stuff broadly, in a distributed system A Use Case that\u2019s growing in popularity: HPC CephFS is fast, scalable, and flexible Fits into many existing paradigms, rather seamlessly In particular: NFS, Samba/CIFS But even better: extending Linux filesystems Requires Metadata Service (MDS) for POSIX capabilities SUSE does NOT support any FUSE clients. Ceph Users and Authentication \u00b6 Ceph Users are generally applications; applications that use the storage cluster The must common user is Admin A ceph admin user and credentials must exist Additional users and associated credentials are useful Each user must have credentials to access the storage cluster The most fundamental form of credentials in Ceph is keys Ceph Users and Keys The admin user has rights to all Ceph resources. Other users can be setup to have a subset of rights There are basically two types of Users (Actors): An individual (a person) An application (like a gateway, or some other kind of system) Most users are of the type client, and are represented as a dotted string, such as: client.admin, or client.steve, or client.swift The root linux user on the Admin node is effectively the Admin Ceph user, since the root user has all privileges to all filesystem objects on the Adminnode, including the ceph.client.admin.keyring. The root user on any of the nodes in the cluster can \u201cimpersonate\u201d all of the Ceph clients. Linux user accounts do not have any affect on the Ceph Users as managed in the dashboard. Take care to keep backups of the /etc/ceph/ directory structure, so that you don\u2019t lose these keys/keyrings. Each user must have a key/keyring, for example: /etc/ceph/ceph.client.admin.keyring on the Admin node /etc/ceph/ceph.client.storage.keyring on a storage node admin:/etc/ceph # cat ceph.client.admin.keyring [client.admin] key = AQD6pHpfAAAAABAAHJvkvLhOKZyQxm9lgnR5Qg== caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" data1:/etc/ceph # cat ceph.client.storage.keyring [client.storage] key = AQD8pHpfAAAAABAAHecCBgBsLIyPrJf+27eXUQ== caps mon = \"allow rw\" Ceph Keys and Keyrings A keyring contains one or more keys Each user can have its own keyring A keyring can contain multiple keys Different clients and users must have their own key, but multiple keys can be joined together in a single keyring Normally a key will be contained in a keyring Core Ceph will only recognize and use keys from keyrings Stand-alone keys are useful for other tools, like clients Ceph Authentication List The Admin node (and client.admin) can list all Users ceph auth list Create a Ceph User A typical user will have read rights to MONs, and read/write rights to a pool (osd) ceph auth get/add/get-or-create xxxxxx Create a User with ceph-authtool Create a keyring ceph-authtool -C /etc/ceph/ceph.client.richard.keyring Create a key, and place it on the keyring ceph-authtool --gen-key -n client.richard --cap osd 'allow rw pool=data' --cap mon 'allow r' /etc/ceph/ceph.client.richard.keyring Now officially tell the cluster about the key (add user to the key) ceph auth add client.richard -i /etc/ceph/ceph.client.richard.keyring Authentication with cephx The mechanism for passing keys around is cephx Authentication for users and daemons Does not provide data encryption, only authentication with keys cephx simply ensures the authenticity of actors So that no man-in-the-middle attacks can occur Other authentication mechanisms are theoretically possible Attempts to integrate LDAP and Kerberos have been made \u2026 but they have not come to full fruition yet Ceph Configuration \u00b6 Historically, the Ceph configuration was kept only in a file on the Admin node: /etc/ceph/ceph.conf, and sync'd to MONs and Storage Nodes SES DeepSea manages the ceph.conf file. Don\u2019t edit it directly; use Salt and DeepSea With Ceph Nautilus, most configuration held as objects in the Monitors using Dashboard or CLI for operation Ceph Configuration Stored in the MONs The MONs keep a configuration database Show all the configuration keys: admin:/etc/ceph # ceph config ls |less Show the configuration settings that have been customized. The dumped output also indicates an EXPERTISE LEVEL The keys also have a \u201cwho\u201d attribute. In below case, \"osd.*\" represents the \"who\", which is getting the general setting for all OSDs Ceph Configuration Settings Show configuration settings that have been customized: admin:/etc/ceph # ceph config dump WHO MASK LEVEL OPTION VALUE RO mgr advanced mgr/dashboard/GRAFANA_API_URL https://mon1.pvgl.sap.corp:3000 * mgr advanced mgr/dashboard/RGW_API_ACCESS_KEY M11I3JGQHAQM94CS910K * mgr advanced mgr/dashboard/RGW_API_HOST mon3.pvgl.sap.corp * mgr advanced mgr/dashboard/RGW_API_PORT 80 * mgr advanced mgr/dashboard/RGW_API_SECRET_KEY YWyRc3mayEPiOEUzQ2o76KePSKmVKN4fIWxgqTt6 * mgr advanced mgr/dashboard/RGW_API_USER_ID admin * mgr advanced mgr/dashboard/ssl_server_port 8443 admin:/etc/ceph # ceph config get osd.* osd_max_object_size 134217728 admin:/etc/ceph # ceph config show osd.0 \u2026\u2026 admin:/etc/ceph # ceph config show osd.11 (4 data nodes, 3 osds in each node) \u25cb Each of the configuration settings have default values ceph config show-with-defaults osd.2 | less \u25cb Ceph keeps a log of configuration changes admin:/etc/ceph # ceph config log --- 8 --- 2020-10-05 14:31:51.425902 --- + mgr/mgr/dashboard/RGW_API_USER_ID = admin --- 7 --- 2020-10-05 14:31:50.418622 --- + mgr/mgr/dashboard/RGW_API_HOST = mon3.pvgl.sap.corp --- 6 --- 2020-10-05 14:31:49.398448 --- + mgr/mgr/dashboard/RGW_API_PORT = 80 --- 5 --- 2020-10-05 14:31:48.403965 --- + mgr/mgr/dashboard/RGW_API_SECRET_KEY = YWyRc3mayEPiOEUzQ2o76KePSKmVKN4fIWxgqTt6 --- 4 --- 2020-10-05 14:31:46.905701 --- + mgr/mgr/dashboard/RGW_API_ACCESS_KEY = M11I3JGQHAQM94CS910K --- 3 --- 2020-10-05 13:15:29.530355 --- + mgr/mgr/dashboard/GRAFANA_API_URL = https://mon1.pvgl.sap.corp:3000 --- 2 --- 2020-10-05 13:15:14.349623 --- + mgr/mgr/dashboard/ssl_server_port = 8443 --- 1 --- 2020-10-05 13:13:55.637896 --- Health \u00b6 Show status admin:/etc/ceph # ceph status cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 6w) mgr: mon1(active, since 13d) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 9w), 12 in (since 9w) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 208 pgs objects: 246 objects, 4.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 208 active+clean io: client: 11 KiB/s rd, 0 B/s wr, 11 op/s rd, 6 op/s wr admin:/etc/ceph # ceph health HEALTH_OK admin:/etc/ceph # ceph health detail HEALTH_OK admin:/etc/ceph # ceph mon stat e1: 3 mons at {mon1=[v2:10.58.121.186:3300/0,v1:10.58.121.186:6789/0],mon2=[v2:10.58.121.187:3300/0,v1:10.58.121.187:6789/0],mon3=[v2:10.58.121.188:3300/0v1:10.58.121.188:6789/0]}, election epoch 22, leader 0 mon1, quorum 0,1,2 mon1,mon2,mon3 admin:/etc/ceph # ceph osd stat 12 osds: 12 up (since 9w), 12 in (since 9w); epoch: e1375 admin:/etc/ceph # ceph pg stat 208 pgs: 208 active+clean; 4.7 KiB data, 2.0 GiB used, 82 GiB / 96 GiB avail; 1.2 KiB/s rd, 1 op/s Watch status -w, --watch : Watch live cluster changes --watch-debug : Watch debug events --watch-info : Watch info events --watch-sec : Watch security events --watch-warn : Watch warning events --watch-error : Watch error Scrub and Deep-Scrub \u00b6 \"Scrub\" is the process of doing a data consistency check Basically like running fsck on the cluster In Replicas: compare object metadata among replicas In EC: verify \u201ccode\u201d chunks Manual scrubbing can be done per OSD or per PG. \"osd scrub\" is just a collaborative wrapper of \"pg scrub\". ceph osd scrub osd.11 ceph pg scrub 3.33 \"scrub\" is a light process, daily Checks object size and attributes \"deep-scrub\" is a more thorough process, weekly Reads all data and checks the checksums Scrub \u2013 Manual vs Automatic You can let Ceph just do the default Run scrub daily, run deep-scrub weekly Ceph pays attention to usage and backs off when necessary You can change the defaults for both scrub and deepscrub, examples: osd_scrub_begin_week_day=6 (Saturday) osd_scrub_end_week_day=7 (Sunday) You can manually run scrubbings at any time if you suspect it\u2019s wanted or needed Manual scrubbings are not common Adjustments to Scrub Settings For most circumstances the default behavior of Scrub is adequate See current Scrub configuration settings: ceph config ls | grep osd_scrub ceph config ls | grep osd_deep_scrub ceph config get osd.* osd_scrub_begin_hour Change the settings immediately in the MON DB ceph config set osd.* osd_scrub_begin_hour 23 ceph config set osd.* osd_scrub_end_hour 5 Adjust Settings in ceph.conf with DeepSea To permanently change settings in ceph.conf This is the \u201cold\u201d way, but is still valid Remember that ceph.conf is controlled by DeepSea Add changes to /srv/salt/ceph/configuration/files/ceph.conf.d/global.conf Run the following DeepSea (Salt) commands: salt admin* state.apply ceph.configuration.create salt \\* state.apply ceph.configuration Wait for services/servers to be restarted, or tell Ceph to assimilate the ceph.conf settings now ceph config assimilate-conf -i /etc/ceph/ceph.conf Repair \u00b6 Problems Found by Scrubbing * If data (in an OSD or PG) becomes inconsistent, it will need to be repaired. You can configure scrubbing to automatically repair errors * osd_scrub_auto_repair=True * osd_scrub_auto_repair_num_errors=5 * Manually repair when appropriate * ceph osd repair osd.11 * ceph pg repair 3.33 Ceph Manager Modules \u00b6 Manager Modules help to extend the capabilities of Ceph List of Modules Supported in SES Balancer (always on) rash (always on) Dashboard DeepSea iostat Orchestrator (always on) progress (always on, tech preview) Prometheus RESTful rbd_support (always on) status (always on) telemetry volume (always on) Zabbix (plugin only, not the required agent) Enabling Manager Modules Show a list of Manager Modules ceph mgr module ls | less The output is quite long; best to pipe it through less The top of the output shows those modules that have been enabled The exhaustive output also displays the \u201cAPI\u201d of each module Manager modules are quite easy to enable and disable ceph mgr module enable ceph mgr module disable Show list of services that are active from the Modules ceph mgr services Module Capabilities Each module has its own settings, configuration Once the module is enabled, the ceph command accepts commands for the module No need to run the command as ceph mgr ... Examples: ceph crash stat ceph telemetry show Setting parameters (key/value pairs) of Modules ceph config set mgr mgr/telemetry/contact 'JD ' ceph config set mgr mgr/telemetry/description 'Training Cluster' Ceph Tell \u00b6 Tell commands are actually directed to the target service by way of the MONs ceph tell is a tool to tell a ceph daemon to perform a task \u2026 change a setting \u2026 execute a subroutine The target of ceph tell can be a single daemon or a collection of daemons All MONs: ceph tell mon.* injectargs '--mon-pg-warn-max-per-osd 4096' A specific OSD: ceph tell osd.9 bench ceph tell is the most common way to change logging for troubleshooting ceph tell . injectargs '--debug- ' ceph tell osd.7 injectargs '--debug-osd 20' ceph tell osd.7 config set debug_osd 20 A \u201c/\u201d allows you to change both the file log and memory log settings simultaneously ceph tell mon.3 injectargs '--debug-mon 0/10' (The first is the file parameter, the second is the memory parameter) Since logging can fill space, important to restore settings after investigating ceph tell mon.3 injectargs '--debug-mon 1/5' ceph tell sends its instructions via the Monitors. So what if the MONs are having problems? To avoid running commands through the MONs, go directly to thenode running the daemon ssh storage1 ceph daemon osd.29 config show ceph daemon osd.29 config set debug_osd 0/20 Use with great care Ceph Dashboard \u00b6 What's Ceph Dashboard SES WEB-based Management Interface A Ceph MGR module, built-in to Ceph The open source \"port\" of openATTIC to Ceph. Technically it\u2019s not a port of openATTIC. SUSE and Ceph Community worked on implementing the openATTIC capabilities directly within Ceph Role-based and Multi-User Management of the SES cluster Create, manage, and monitor Pools, RBDs Manage users, access keys, quotas and buckets of RGW Manage NFS exports, iSCSI targets and portals, CephFS View cluster nodes/roles, monitor performance metrics Manage Ceph settings/configuration Reduces the need to understand complex Ceph commands The dashboard is stateless, it will reflect any changes to the Ceph cluster, Highlighted Enterprise Behavior via Ceph Dashboard Uses SSL/TLS By default will use a CA and certificate created by DeepSea or provide your own CA and certificate Can run without SSL/TLS (not recommended) Multi-User and Role Management Variety of mappings, i.e.: read, create, update, delete Single Sign-On, complying with SAML 2.0 Single Sign-On, complying with SAML 2.0 Auditing on the backend, to monitor specific user activity Internationalization (I18N), with a variety of language translations Ceph Dashboard Architecture Backend is based on CherryPy framework (CherryPy is a Minimalist Python Web Framework) Frontend WebUI is based on Angular/TypeScript A custom REST API Monitoring facilitated by Prometheus Visualization of data facilitated by Grafana Dependent upon DBUS, systemd, and systems\u2019 shell Dashboard as Manager Module Ceph Dashboard runs as a Manager module Runs on each MON/MGR node Really only actively available via the active MGR Runs on \u201cstandby\u201d on the standby MGR nodes Standby Dashboards will redirect to active MGR URL Dashboard automatically switches to active MGR node Helpful High Availability feature As a MGR module, enabled and configured by DeepSea Can be disabled if unwanted URL example: https://10.58.121.186:8443 Grafana and Prometheus Prometheus collects various data about the cluster Grafana represents the data as graphs Ceph Dashboard uses both to improve insight into SES Prometheus Open source event monitoring software \"Scrapes\" (collects) data from nodes/services in the cluster Real-time Time series Custom scrapers have been created for Ceph Stores scraped data in memory and on disk Presents data to other software for graphical representation Integrated nicely with Grafana Grafana The leading open source software for time series analytics \"Dashboards\" of panels, graphs, metrics, etc. \"Dashboard\" is a slightly conflicting term, but still meaningful Renders data in a graphical way collected from Prometheus Graphs are customized for use on the Ceph Dashboard Dashboard Users Always need an \u201cAdmin\u201d user for the Dashboard \u00a7 The admin keys of the root user on the \u201cAdmin\u201d node in the cluster Dashboard Users are accounts that relate only to using the Dashboard \u00a7 Not the same as Ceph CLI users and client keys; but could coincide Any person who wants to interact with the storage cluster via the Dashboard must have a user account Variety of Users established by the Admin User, and various permissions based on Admin-defined Roles User Authentication Dashboard Administrators can setup users with specific privileges The privileges and permissions are managed as \"roles\" User accounts can be created directly in the Dashboard Stored as objects in Ceph User accounts can also be tied to other authentication mechanisms: Single Sign-On Service; SAML 2.0 compliant protocol Dashboard accounts can be managed from the Dashboard or from the CLI Example: ceph dashboard ac-user-show [] The Admin Dashboard User (the term \u201cadmin\u201d is used differently in different places) The Dashboard Admin User is not the same as other admins The \u201cadmin\u201d node is obviously not directly tied to any admin user The Admin Dashboard User is created at Deployment time Given a random password by DeepSea You must use the CLI to establish the admin password ceph dashboard ac-user-show admin ceph dashboard ac-user-set-password admin \u25cb The SES Deployment Course has set the password to mypassword admin:~ # ceph dashboard ac-user-show [\"admin\"] admin:~ # ceph dashboard ac-user-show admin {\"username\": \"admin\", \"password\": \"$2b$12$4lC/AU7jc6midTZufj4P4.rBtVzRGf7Zy7fUbD6G9YfdfVEwkwuUy\", \"roles\": [\"administrator\"], \"name\": null \"email\":null\"lastUpdate\": 1601874928} Health from the Dashboard Cluster Status Monitors OSDs Manager Daemons Hosts Object Gateways Metadata Service iSCSI Gateways Cluster Performance from Dashboard Client IOPS Client Throughput Client Read/Write Recovery Throughput Scrub Performance Data Hosts: Overall Performance Monitors: Performance Counters OSDs: Relative Read/Write bar graphs, and Overall Performance Pools: Relative Read/Write bar graphs, and Overall Performance Block images: Overall Performance CephFS: Performance Details RGW: Overall Performance Cluster Capacity from Dashboard Capacity data: Number of Pools Raw Capacity Number of Objects (Ceph objects, not user objects from RGW) Placement Groups per OSD Placement Group Status Basic Troubleshooting \u00b6 Ceph Logs Logs normally stored in /var/log/ceph/ No real logs on the admin node Each service has its own log on the MON, Storage and Gateway nodes Logs handled routinely by logrotate Ceph has logs that are stored to files and in memory (triggered by event or manual request) There are 21 different levels of logging: 0-20 (0 is no logging; 20 is the most verbose logging) There are many subsystems that do their own logging, and can be configured independently Most common: mon, osd, mgr, rados, rbd, mds, rgw Others: asok, auth, client, filestore, journal, monc, ms, paxos, and more There are only 3 types of daemons: osd, mon, mds Using Tell to Change Log Levels 1) Check the Dashboard and Health. Common commands ceph status ceph osd status ceph osd df ceph osd utilization ceph osd pool stats ceph osd tree ceph pg stat 2) Network Troubleshooting Always be sure that the network (and related services) are working properly Ceph depends heavily on tightly synchronized time; make sure network time services are working on each node DNS hostnames are similarly essential 3) Check the Logs Go to the node of the component implicated in HEALTH 4: Raise the DEBUG Level. Follow this simple formula: Raise the debug level (a little each time until you see the problem) Check the logs Repeat as necessary Don\u2019t forget to restore the debug level back to its normal level 5) Check the Storage Device If the problem is with an OSD or a storage device, go straight to the device: hdparm smartctl And check out the details of the combination of OSD and storage device: lsblk /var/lib/ceph/osd/ 6) Scrub (or not) Sometimes simply scrubbing an OSD or PG can cause the checksum-ing process to reveal problems At least some problems can be made more clear with the result of scrub and/or deep-scrub Even doing a scrub can kick Ceph into fixing the problem itself And don\u2019t forget ceph osd repair On the other hand, sometimes Scrub can make things worse. If you suspect Scrub is part of the problem, turn it off: ceph osd set noscrub ceph osd unset noscrub 7) Placement Groups When Placement Groups cause problems: * ceph pg dump summary * ceph pg dump pools * ceph pg dump_jason * ceph pg dump | less Followed by a strategic \u201crepair\u201d of the PG * ceph pg repair 8) Running supportconfig YaST Support Module From CLI: supportconfig The collected data is stored in a file called /var/log/nts__.txz","title":"SUSE Enterprise Storage Foundation"},{"location":"linux/SES/linux_ses_memo/#suse-enterprise-storage-foundation","text":"","title":"SUSE Enterprise Storage Foundation"},{"location":"linux/SES/linux_ses_memo/#cephs-rados","text":"Everything in Ceph is stored in the RADOS cluster as Objects. Ceph\u2019s RADOS: Reliable Autonomous Distributed Object Store Ceph\u2019s RADOS is composed of storage devices represented as: Raw storage device with LVM (BlueStore) Standard filesystem (FileStore) The Object Storage Daemon (OSD) integrates each disk device as part of the RADOS cluster.","title":"Ceph\u2019s RADOS"},{"location":"linux/SES/linux_ses_memo/#ceph-architecture","text":"Ceph is made of two groups of core components The RADOS cluster Provides the clustered object storage Native Object Access methods Gateways Access to the object store via standard protocols librados Direct access to the object store using a native API Examples: iSCSI Gateway (block) -- IGW - iSCSI is a storage area network (SAN) protocol. Exports RADOS Block Device (--RBD) (images as iSCSI disks). iSCSI access to RDB images. lrbd is no longer used in SES6. RADOS Gateway (object) -- RGW Is an object storage interface built on top of librados CephFS (file) A MetaData Service (MDS) is required. Direct access to RADOS (no LIBRADOS layer) Traditional filesystem interface. NFS Ganesha (object, file) Provides NFS exports to: RGW buckets for access the object store The CephFS filesystem Client access the storage services of the cluster via Gateways and Librados The librados API allows interaction with the following daemons: The Ceph Monitor, which maintains a master copy of the cluster map The Ceph OSD Daemon (OSD), which stores data as objects on a storage node.","title":"Ceph architecture"},{"location":"linux/SES/linux_ses_memo/#enhanced-ses-architecture-diagram","text":"","title":"Enhanced SES Architecture Diagram"},{"location":"linux/SES/linux_ses_memo/#object-storage","text":"The state of the art of distributed SDS storage Unstructured, to better accommodate large files and large quantities of files For large files and large quantities of files, it performs far better than other storage mechanisms Agile, scalable, extensible, and very customizable Invisible to the end-user, ideal for backends Perfect for systemic, application-based use cases. Not necessarily perfect for direct Human use Through associated metadata, ideal for computational analytics And CRUSH takes full advantage of this (CRUSH = Controllable Replication Under Scalable Hashing) Ceph Object Storage supports two interfaces: S3-compatible Swift-compatible Object-based storage has become the standard backend storage mechanism for nearly all modern Enterprise Storage Solutions.","title":"Object Storage"},{"location":"linux/SES/linux_ses_memo/#ceph-osds-object-storage-daemon","text":"A Ceph OSD (object storage daemon, ceph-osd) stores data, handles data replication, recovery, rebalancing, and provides some monitoring information to Ceph Monitors and Managers by checking other Ceph OSD Daemons for a heartbeat. The Ceph Storage Cluster receives data from Ceph Clients. Clients (dedicated access points, e.g., gateway) could be a Ceph Block Device, Ceph Object Storage, the Ceph Filesystem or a custom implementation using librados. The client requests the cluster status from a monitor node The client uses the status information to identify the location of objects in the cluster The client accesses the objects directly via the OSD node The OSD then stores the data as objects. Each object corresponds to a file in a filesystem which is stored on an OSD. The OSD Daemons take care of the reads and writes on the storage disks. When OSDs are deployed in SES5 the default is to use BlueStore which uses the raw disk and does not require a linux file system to be placed on the disk before it can be used. OSD Daemons store all data as objects in a flat namespace, i.e. no hierarchy of directories. At least 3 Ceph OSDs are normally required for redundancy and high availability.","title":"Ceph OSDs (Object Storage Daemon)"},{"location":"linux/SES/linux_ses_memo/#ceph-mons-monitor-servers","text":"A Ceph Monitor (ceph-mon) maintains maps of the cluster state, including Monitor Map Manager Map OSD Map PG Map CRUSH Map Epoch These maps are critical cluster state required for Ceph daemons to coordinate with each other. Monitors are also responsible for managing authentication between daemons and clients. At least 3 monitors are normally required for redundancy and high availability. An odd number of MONs is required (Paxos requires). Typically 5 is sufficient for mid or large size cluster. Paxos is an algorithm used for cluster durability. Leader MON expects 50% quality to create quorum. Lowest IP address becomes leader. After new leader selected, all MONs polled for epoch. Leader Mon provides lease to non-leader MONs. MONs are NOT in the data path. They merely serve maps to clients so that the client can go directly to the appropriate OSD storage daemon. Monitor nodes MONs do not serve objects to clients","title":"Ceph Mons (Monitor Servers)"},{"location":"linux/SES/linux_ses_memo/#ceph-mgrs-manager-daemon","text":"A Ceph Manager daemon (ceph-mgr) is responsible for keeping track of runtime metrics and the current state of the Ceph cluster, including storage utilization current performance metrics system load The Ceph Manager daemons also host python-based plugins to manage and expose Ceph cluster information, including a web-based dashboard and REST API. At least two managers are normally required for high availability. MON/MGR daemons are required to run on the same node in SES","title":"Ceph MGRs (Manager Daemon)"},{"location":"linux/SES/linux_ses_memo/#ceph-mds-metadata","text":"A Ceph Metadata Server (MDS, ceph-mds) stores metadata on behalf of the Ceph Filesystem. Ceph Metadata Servers allow POSIX file system users to execute basic commands, for example ls -al without placing an large load on the Ceph Storage Cluster.","title":"Ceph MDS (Metadata)"},{"location":"linux/SES/linux_ses_memo/#ceph-admin-node","text":"The Admin node fills the \u201cmaster\u201d and \u201cadmin\u201d roles for DeepSea. Salt is central to SES. SES\u2019s deployment and life-cycle management tool. The Admin node keeps master Ceph authentication keys. Prometheus and Grafana provide cluster monitoring and data graphs","title":"Ceph Admin Node"},{"location":"linux/SES/linux_ses_memo/#ceph-dashboard","text":"Runs as a Ceph Manager module; runs via the MON/MGR node.","title":"Ceph Dashboard"},{"location":"linux/SES/linux_ses_memo/#client-access","text":"Object Storage (RADOSGW or RGW) Block Storage (RDB). RBD is built on top of librados. CephFS iSCSI Gateway NFS Ganesha SMB/CIFS Native protocols via librados","title":"Client Access"},{"location":"linux/SES/linux_ses_memo/#objects-in-ceph","text":"Everything stored in the Ceph cluster is an object. Default object size is 4MB. Each object has a unique ID. ID is unique across the entire cluster. Objects have associated metadata, in Key: Value pairs. In Ceph we use Storage Pools to organize or arrange our objects. Pools are logical partitions to manage objects Parameters to manage Pools Number of data replicas (Replica pools), or configuration of Erasure Code (size) (Erasure Code pools) Erasure Code is an alternative to Replication SIZE for Erasure Coding is K+M K = Data chunks, M = \u201cParity\u201d chunks EC reduces the hit to raw storage capacity EC incurs a greater hit to CPU on the OSDs as a tradeoff Placement Groups (PG) PG is used to manage objects within a pool. PGs are associated with OSDs for data placement PGs are a central feature of CRUSH that help to provide data durability by way of distribution No PG is owned by an OSD. (And an OSD is not owned by a PG.) PGs are just randomly assigned by CRUSH through all of the OSDs to spread the distribution of data Locating data among PGs is all handled economically, deterministically by way of CRUSH calculations PGs are subdivisions of pools Number of PGs = (Number of OSDs * 100) / Size (Size = either num of replicas, or K+M) The final PG number must be a power of 2 The default number of PGs for a new pool is 8 (it's too small for enterprise solution) In general, PG and PGP numbers should be the same pg_num is the number of placement groups for the pool (placement group, \u5b58\u50a8\u6c60\u7684\u76ee\u5f55\u4e2a\u6570 ) pgp_num is the number of placement groups that will be considered for placement (placement group for placement purpose, pg\u53ef\u7528\u7684osd\u6392\u5217\u7ec4\u5408\u6570\u91cf) \u4ec5\u589e\u5927pg_num\uff1a \u56e0\u4e3apgp_num\u6ca1\u53d8\uff0cpg\u7684osd\u7ec4\u5408\u4ecd\u53ea\u80fd\u4ece\u5f53\u524dpgp_num\u79cd\u7ec4\u5408\u91cc\u9762\u6311\u9009\uff0c\u5bfc\u81f4\u65b0\u589e\u7684pg\u548c\u65e7pg\u4f1a\u6709\u91cd\u590d\u7684osd\u7ec4\u5408\uff0c\u8be5\u73b0\u8c61\u79f0\u4e4b\u4e3a\u5206\u88c2\uff1b\u6b64\u65f6pg\u548cosd\u7684\u6620\u5c04\u6ca1\u6709\u53d8\uff1b \u7ee7\u7eed\u589e\u5927pgp_num\uff0c\u4f7f\u5176\u7b49\u4e8epg_num\uff1a \u65e7pg\u6ca1\u6709\u53d8\u5316\uff0c\u4f46\u65b0\u589epg\u7684osd\u7ec4\u5408\u53d1\u751f\u53d8\u5316\uff0c\u5373\u5f00\u59cb\u91cd\u65b0\u5206\u5e03 Placement Group (PG) \u5f52\u7f6e\u7ec4\u72b6\u6001 Creating \u521b\u5efa\u5b58\u50a8\u6c60\u65f6\uff0c\u5b83\u4f1a\u521b\u5efa\u6307\u5b9a\u6570\u91cf\u7684\u5f52\u7f6e\u7ec4\u3002 ceph \u5728\u521b\u5efa\u4e00\u6216\u591a\u4e2a\u5f52\u7f6e\u7ec4\u65f6\u4f1a\u663e\u793a creating\u3002 \u521b\u5efa\u5b8c\u540e\uff0c\u5728\u5176\u5f52\u7f6e\u7ec4\u7684 Acting Set \u91cc\u7684 OSD \u5c06\u5efa\u7acb\u4e92\u8054\u3002 \u4e00\u65e6\u4e92\u8054\u5b8c\u6210\uff0c\u5f52\u7f6e\u7ec4\u72b6\u6001\u5e94\u8be5\u53d8\u4e3a active+clean\uff0c\u610f\u601d\u662fceph \u5ba2\u6237\u7aef\u53ef\u4ee5\u5411\u5f52\u7f6e\u7ec4\u5199\u5165\u6570\u636e\u4e86\u3002 peering ceph \u4e3a\u5f52\u7f6e\u7ec4\u5efa\u7acb\u4e92\u8054\u65f6\uff0c\u4f1a\u8ba9\u5b58\u50a8\u5f52\u7f6e\u7ec4\u526f\u672c\u7684 OSD \u4e4b\u95f4\u5c31\u5176\u4e2d\u7684\u5bf9\u8c61\u548c\u5143\u6570\u636e\u72b6\u6001\u8fbe\u6210\u4e00\u81f4\u3002 ceph \u5b8c\u6210\u4e86\u4e92\u8054\uff0c\u4e5f\u5c31\u610f\u5473\u7740\u5b58\u50a8\u7740\u5f52\u7f6e\u7ec4\u7684 OSD \u5c31\u5176\u5f53\u524d\u72b6\u6001\u8fbe\u6210\u4e86\u4e00\u81f4\u3002 \u7136\u800c\uff0c\u4e92\u8054\u8fc7\u7a0b\u7684\u5b8c\u6210\u5e76\u4e0d\u80fd\u8868\u660e\u5404\u526f\u672c\u90fd\u6709\u4e86\u6570\u636e\u7684\u6700\u65b0\u7248\u672c\u3002 active ceph \u5b8c\u6210\u4e92\u8054\u8fdb\u7a0b\u540e,\u4e00\u5f52\u7f6e\u7ec4\u5c31\u53ef\u53d8\u4e3a active\u3002 active \u72b6\u6001\u901a\u5e38\u610f\u5473\u7740\u5728\u4e3b\u5f52\u7f6e\u7ec4\u548c\u526f\u672c\u4e2d\u7684\u6570\u636e\u90fd\u53ef\u4ee5\u8bfb\u5199\u3002 clean \u67d0\u4e00\u5f52\u7f6e\u7ec4\u5904\u4e8e clean \u72b6\u6001\u65f6\uff0c\u4e3b OSD \u548c\u526f\u672c OSD \u5df2\u6210\u529f\u4e92\u8054\uff0c\u5e76\u4e14\u6ca1\u6709\u504f\u79bb\u7684\u5f52\u7f6e\u7ec4\u3002 ceph \u5df2\u628a\u5f52\u7f6e\u7ec4\u4e2d\u7684\u5bf9\u8c61\u590d\u5236\u4e86\u89c4\u5b9a\u6b21\u6570\u3002 degraded \u5f53\u5ba2\u6237\u7aef\u5411\u4e3b OSD \u5199\u5165\u6570\u636e\u65f6\uff0c\u7531\u4e3b OSD \u8d1f\u8d23\u628a\u526f\u672c\u5199\u5165\u5176\u4f59\u590d\u5236 OSD\u3002 \u4e3b OSD \u628a\u5bf9\u8c61\u5199\u5165\u590d\u5236 OSD \u540e\uff0c\u5728\u6ca1\u6536\u5230\u6210\u529f\u5b8c\u6210\u7684\u786e\u8ba4\u524d\uff0c\u4e3b OSD \u4f1a\u4e00\u76f4\u505c\u7559\u5728 degraded \u72b6\u6001\u3002 \u5f52\u7f6e\u7ec4\u72b6\u6001\u53ef\u4ee5\u662f active+degraded \u72b6\u6001\uff0c\u539f\u56e0\u5728\u4e8e\u4e00 OSD \u5373\u4f7f\u6ca1\u6240\u6709\u5bf9\u8c61\u4e5f\u53ef\u4ee5\u5904\u4e8e active \u72b6\u6001\u3002 \u5982\u679c\u4e00OSD \u6302\u4e86\uff0cceph \u4f1a\u628a\u76f8\u5173\u7684\u5f52\u7f6e\u7ec4\u90fd\u6807\u8bb0\u4e3a degraded\u3002 \u90a3\u4e2a OSD \u91cd\u751f\u540e\uff0c\u5b83\u4eec\u5fc5\u987b\u91cd\u65b0\u4e92\u8054\u3002 \u7136\u800c\uff0c\u5982\u679c\u5f52\u7f6e\u7ec4\u4ecd\u5904\u4e8e active \u72b6\u6001\uff0c\u5373\u4fbf\u5b83\u5904\u4e8e degraded \u72b6\u6001\uff0c\u5ba2\u6237\u7aef\u8fd8\u53ef\u4ee5\u5411\u5176\u5199\u5165\u65b0\u5bf9\u8c61\u3002 \u5982\u679c\u4e00 OSD \u6302\u4e86\uff0c\u4e14 degraded \u72b6\u6001\u6301\u7eed\uff0cceph \u4f1a\u628a down \u7684 OSD \u6807\u8bb0\u4e3a\u5728\u96c6\u7fa4\u5916(out)\u3001\u5e76\u628a\u90a3\u4e9b down \u6389\u7684 OSD \u4e0a\u7684\u6570\u636e\u91cd\u6620\u5c04\u5230\u5176\u5b83 OSD\u3002 \u4ece\u6807\u8bb0\u4e3a down \u5230 out \u7684\u65f6\u95f4\u95f4\u9694\u7531 mon osd down out interval \u63a7\u5236,\u9ed8\u8ba4\u662f 300 \u79d2\u3002 \u5f52\u7f6e\u7ec4\u4e5f\u4f1a\u88ab\u964d\u7ea7(degraded)\uff0c\u56e0\u4e3a\u5f52\u7f6e\u7ec4\u627e\u4e0d\u5230\u672c\u5e94\u5b58\u5728\u4e8e\u5f52\u7f6e\u7ec4\u4e2d\u7684\u4e00\u6216\u591a\u4e2a\u5bf9\u8c61\uff0c\u8fd9\u65f6\uff0c\u4f60\u4e0d\u80fd\u8bfb\u6216\u5199\u627e\u4e0d\u5230\u7684\u5bf9\u8c61\uff0c\u4f46\u4ecd\u80fd\u8bbf\u95ee\u5176\u5b83\u4f4d\u4e8e\u964d\u7ea7\u5f52\u7f6e\u7ec4\u4e2d\u7684\u5bf9\u8c61\u3002 recovering ceph \u88ab\u8bbe\u8ba1\u4e3a\u53ef\u5bb9\u9519\uff0c\u53ef\u62b5\u5fa1\u4e00\u5b9a\u89c4\u6a21\u7684\u8f6f\u3001\u786c\u4ef6\u95ee\u9898\u3002 \u5f53\u67d0 OSD \u6302\u4e86(down)\u65f6\uff0c\u5176\u5185\u5bb9\u7248\u672c\u4f1a\u843d\u540e\u4e8e\u5f52\u7f6e\u7ec4\u5185\u7684\u5176\u5b83\u526f\u672c\u3002 \u5b83\u91cd\u751f(up)\u65f6\uff0c\u5f52\u7f6e\u7ec4\u5185\u5bb9\u5fc5\u987b\u66f4\u65b0\uff0c\u4ee5\u53cd\u6620\u5f53\u524d\u72b6\u6001\u3002 \u5728\u6b64\u671f\u95f4\uff0cOSD \u5728recovering \u72b6\u6001\u3002 \u4e00\u6b21\u786c\u4ef6\u5931\u8d25\u53ef\u80fd\u7275\u8fde\u591a\u4e2a OSD\u3002\u6bd4\u5982\u4e00\u4e2a\u673a\u67dc\u7684\u7f51\u7edc\u4ea4\u6362\u673a\u5931\u8d25\u4e86\uff0c\u8fd9\u4f1a\u5bfc\u81f4\u591a\u4e2a\u4e3b\u673a\u843d\u540e\u4e8e\u96c6\u7fa4\u7684\u5f53\u524d\u72b6\u6001\uff0c\u95ee\u9898\u89e3\u51b3\u540e\u6bcf\u4e00\u4e2a OSD \u90fd\u5fc5\u987b\u6062\u590d\u3002 ceph \u63d0\u4f9b\u4e86\u5f88\u591a\u9009\u9879\u6765\u5747\u8861\u8d44\u6e90\u7ade\u4e89\uff0c\u5982\u65b0\u670d\u52a1\u8bf7\u6c42\u3001\u6062\u590d\u6570\u636e\u5bf9\u8c61\u548c\u6062\u590d\u5f52\u7f6e\u7ec4\u5230\u5f53\u524d\u72b6\u6001\u3002 osd recovery delay start \u9009\u9879\u5141\u8bb8\u4e00 OSD \u5728\u5f00\u59cb\u6062\u590d\u8fdb\u7a0b\u524d\uff0c\u5148\u91cd\u542f\u3001\u91cd\u5efa\u4e92\u8054\u3001\u751a\u81f3\u5904\u7406\u4e00\u4e9b\u91cd\u653e\u8bf7\u6c42\u3002 osd recovery threads \u9009\u9879\u9650\u5236\u6062\u590d\u8fdb\u7a0b\u7684\u7ebf\u7a0b\u6570\uff0c\u9ed8\u8ba4\u4e3a 1 \u7ebf\u7a0b\u3002 osd recovery thread timeout \u8bbe\u7f6e\u7ebf\u7a0b\u8d85\u65f6\uff0c\u56e0\u4e3a\u591a\u4e2aOSD \u53ef\u80fd\u4ea4\u66ff\u5931\u8d25\u3001\u91cd\u542f\u548c\u91cd\u5efa\u4e92\u8054\u3002 osd recovery max active \u9009\u9879\u9650\u5236\u4e00 OSD \u6700\u591a\u540c\u65f6\u63a5\u53d7\u591a\u5c11\u8bf7\u6c42\uff0c\u4ee5\u9632\u5b83\u538b\u529b\u8fc7\u5927\u800c\u4e0d\u80fd\u6b63\u5e38\u670d\u52a1\u3002 osd recovery max chunk \u9009\u9879\u9650\u5236\u6062\u590d\u6570\u636e\u5757\u5c3a\u5bf8\uff0c\u4ee5\u9632\u7f51\u7edc\u62e5\u585e\u3002 back filling \u6709\u65b0 OSD \u52a0\u5165\u96c6\u7fa4\u65f6\uff0cCRUSH \u4f1a\u628a\u73b0\u6709\u96c6\u7fa4\u5185\u7684\u5f52\u7f6e\u7ec4\u91cd\u5206\u914d\u7ed9\u5b83\u3002 \u5f3a\u5236\u65b0 OSD \u7acb\u5373\u63a5\u53d7\u91cd\u5206\u914d\u7684\u5f52\u7f6e\u7ec4\u4f1a\u4f7f\u4e4b\u8fc7\u8f7d\uff0c\u7528\u5f52\u7f6e\u7ec4\u56de\u586b\u53ef\u4f7f\u8fd9\u4e2a\u8fc7\u7a0b\u5728\u540e\u53f0\u5f00\u59cb\u3002 \u56de\u586b\u5b8c\u6210\u540e\uff0c\u65b0 OSD \u51c6\u5907\u597d\u65f6\u5c31\u53ef\u4ee5\u5bf9\u5916\u670d\u52a1\u4e86\u3002 remapped \u67d0\u4e00\u5f52\u7f6e\u7ec4\u7684 Acting Set \u53d8\u66f4\u65f6\uff0c\u6570\u636e\u8981\u4ece\u65e7\u96c6\u5408\u8fc1\u79fb\u5230\u65b0\u7684\u3002 \u4e3b OSD \u8981\u82b1\u8d39\u4e00\u4e9b\u65f6\u95f4\u624d\u80fd\u63d0\u4f9b\u670d\u52a1\uff0c\u6240\u4ee5\u5b83\u53ef\u4ee5\u8ba9\u8001\u7684\u4e3b OSD \u6301\u7eed\u670d\u52a1\u3001\u76f4\u5230\u5f52\u7f6e\u7ec4\u8fc1\u79fb\u5b8c\u3002 \u6570\u636e\u8fc1\u79fb\u5b8c\u540e,\u4e3b OSD \u4f1a\u6620\u5c04\u5230\u65b0 acting set\u3002 stale \u867d\u7136 ceph \u7528\u5fc3\u8df3\u6765\u4fdd\u8bc1\u4e3b\u673a\u548c\u5b88\u62a4\u8fdb\u7a0b\u5728\u8fd0\u884c\uff0c\u4f46\u662f ceph-osd \u4ecd\u6709\u53ef\u80fd\u8fdb\u5165 stuck \u72b6\u6001\uff0c\u5b83\u4eec\u6ca1\u6709\u6309\u65f6\u62a5\u544a\u5176\u72b6\u6001(\u5982\u7f51\u7edc\u77ac\u65ad)\u3002 \u9ed8\u8ba4OSD \u5b88\u62a4\u8fdb\u7a0b\u6bcf\u534a\u79d2(0.5)\u4f1a\u4e00\u6b21\u62a5\u544a\u5176\u5f52\u7f6e\u7ec4\u3001\u51fa\u6d41\u91cf\u3001\u5f15\u5bfc\u548c\u5931\u8d25\u7edf\u8ba1\u72b6\u6001\uff0c\u6b64\u9891\u7387\u9ad8\u4e8e\u5fc3\u8df3\u9600\u503c\u3002 \u5982\u679c\u4e00\u5f52\u7f6e\u7ec4\u7684\u4e3b OSD \u6240\u5728\u7684 acting set \u6ca1\u80fd\u5411\u76d1\u89c6\u5668\u62a5\u544a\u3001\u6216\u8005\u5176\u5b83\u76d1\u89c6\u5668\u5df2\u7ecf\u62a5\u544a\u4e86\u90a3\u4e2a\u4e3b OSD \u5df2 down\uff0c\u76d1\u89c6\u5668\u4eec\u5c31\u4f1a\u628a\u6b64\u5f52\u7f6e\u7ec4\u6807\u8bb0\u4e3a stale\u3002 \u542f\u52a8\u96c6\u7fa4\u65f6\uff0c\u4f1a\u7ecf\u5e38\u770b\u5230 stale \u72b6\u6001\uff0c\u76f4\u5230\u4e92\u8054\u5b8c\u6210\u3002 \u96c6\u7fa4\u8fd0\u884c\u4e00\u9635\u540e\uff0c\u5982\u679c\u8fd8\u80fd\u770b\u5230\u6709\u5f52\u7f6e\u7ec4\u4f4d\u4e8e stale \u72b6\u6001\uff0c\u5c31\u8bf4\u660e\u90a3\u4e9b\u5f52\u7f6e\u7ec4\u7684\u4e3b OSD \u6302\u4e86(down)\u3001\u6216\u6ca1\u5728\u5411\u76d1\u89c6\u5668\u62a5\u544a\u7edf\u8ba1\u4fe1\u606f\u3002 Each pool has its own autoscaler settings The PG balancer optimizes the placement of PGs across OSD crush-compat mode It's default mode Uses the compat weight-set feature upmap mode. It's perfect mode, which an equal number of PGs on each OSD Use fine-grained control over the PG mapping Snapshots Rulesets to manage CRUSH placement Each pool has a defined CRUSH ruleset A CRUSH ruleset is a definition of how the OSDs organize data This allows configuration of data distribution to be managed per pool A single CRUSH ruleset can be reused by multiple pools A ruleset can take into account: \u9700\u8981\u8003\u8651\u7684\u70b9 physical layout of nodes in the cluster organization of network infrastructure selection of OSDs backed by SSDs versus HDDs, etc Each pool can use either Replication or Erasure Coding Replication is the original, default approach to resiliency Erasure Coded pools have an EC Profile assigned Different than CRUSH rulesets, but similar: define how OSDs organize data The profile defines K, M values; encoding method/plugin; etc","title":"Objects in Ceph"},{"location":"linux/SES/linux_ses_memo/#crush-controllable-replication-under-scalable-hashing","text":"CRUSH is a key piece of the Ceph storage solution With the CRUSH algorithm used by Ceph: Data is not centrally stored, it is distributed CRUSH calculates the storage location for each object dynamically No requirement to store a global index of object locations","title":"CRUSH (Controllable Replication Under Scalable Hashing)"},{"location":"linux/SES/linux_ses_memo/#crush-algorithm","text":"The CRUSH algorithm deterministically calculates the location of any object in the Ceph RADOS cluster Overhead is low and calculation is performed by each client As no metadata store is required, CRUSH removes the limitations of traditional metadata based management No direct control over the placement of your data in the cluster Higher CPU requirements","title":"CRUSH Algorithm"},{"location":"linux/SES/linux_ses_memo/#crush-maps-and-rulesets","text":"CRUSH Rulesets are the named sets of rules: Combining all of the customizable CRUSH behavior settings Assigned to pool to govern how the pool\u2019s data is distributed in the cluster CRUSH Maps are central to how Ceph distributes data, and maintaining the durability of the data When the cluster is deployed, Ceph creates a simple default ruleset for replicated pools: replicated_rule CRUSH behavior depends on the behaviors and performance of storage devices CRUSH Maps should be crafted to take advantage of those behaviors Rulesets should be used to clearly identify how the devices in your environment should be employed Device Classes exist to indicate performance behavior: hdd, ssd, nvme Ceph OSDs will automatically set the Device Class of a storage device when the OSD is started Working with CRUSH Map Rulesets List the OSDs, which host each OSD belongs to: ceph osd tree ceph osd df tree ceph osd df tree -f json-pretty Find the host of a specific OSD: ceph osd find 8 Show the existing defined rulesets: ceph osd crush rule ls Examine the definition of an existing ruleset: ceph osd crush rule dump There are 3 options for creating a new ruleset: simple replicated erasure Creating new rulesets: ceph osd crush rule create-replicated ceph osd crush rule create-erasure Create a new ruleset using a Device Class: create-replicated Description : The name of the node under which data should be placed. Type : String Example : default (rarely would you need to make this different than \u201cdefault\u201d) or Description : The type of CRUSH node (bucket) across which replicas should be separated. Type : String Example : rack Description : The device class data should be placed on. Type : String Example : ssd","title":"CRUSH Maps and Rulesets"},{"location":"linux/SES/linux_ses_memo/#crush-weight","text":"You may need to move data around New nodes degraded nodes rebalancing View the current CRUSH weights ceph osd crush tree ceph osd df tree Change the weight for an OSD ceph osd crush reweight The important difference between ceph osd reweight and ceph osd crush reweight \"ceph osd crush reweight\" sets the CRUSH weight of the OSD. This weight is an arbitrary value (generally the size of the disk in TB or something) and controls how much data the system tries to allocate to the OSD. \"ceph osd reweight\" sets an override weight on the OSD. This value is in the range 0 to 1, and forces CRUSH to re-place (1-weight) of the data that would otherwise live on this drive. It does not change the weights assigned to the buckets above the OSD, and is a corrective measure in case the normal CRUSH distribution isn\u2019t working out quite right. \"ceph osd reweight\" is temporary. \"ceph osd crush reweight\" is sticky, permanent (until you change it again). Setting a weight of an OSD to 0 is effectively setting the OSD \"out\" - you don\u2019t want it to store data.","title":"CRUSH Weight"},{"location":"linux/SES/linux_ses_memo/#the-monitors-cluster-map-contains","text":"Monitor Map Unique Cluster ID, details of each Mon node, current epoch, date/time of last change OSD Map Contains the cluster fsid, when the map was created and last modified, a list of pools, replica sizes, PG numbers, a list of OSDs and their status PG Map Contains the PG version, its time stamp, the last OSD map epoch, the full ratios, and details on each placement group such as the PG ID, the Up Set, the Acting Set, the state of the PG (e.g., active + clean), and data usage statistics for each pool MDS Map Contains the current MDS map epoch, references to pool(s) for storing metadata, list of MDS servers, and which metadata servers are up and in CRUSH Map Contains a list of storage devices, the failure domain hierarchy (e.g., device, host, rack, row, room, etc.), and rules for traversing the hierarchy when storing data","title":"The Monitor\u2019s Cluster Map contains"},{"location":"linux/SES/linux_ses_memo/#crush-hierarchy","text":"The CRUSH Map includes details of physical & network infrastructure The CRUSH Map hierarchy is defined by a storage architect The default hierarchical list of infrastructure elements: (Hierarchy of CRUSH buckets) OSD host chassis \u5200\u7247\u673a\u7bb1 rack \u673a\u67b6 row pdu \u7535\u6e90\u5206\u914d\u5355\u5143 pod \u6027\u80fd\u4f18\u5316\u7684\u6570\u636e\u4e2d\u5fc3(Performance Optimize Datacenter)\uff0c\u57fa\u4e8e\u6807\u51c6\u5316\u8bbe\u65bd\u7684\u6700\u4f73\u5b9e\u8df5\uff0c\u6bcf\u4e2aPOD\u5185IT\u90e8\u5206\u5305\u542b\u76845000\u53f0\u670d\u52a1\u5668\uff0c\u5206\u5c5e\u5230200\u4e2a\u673a\u67b6\uff0c\u5982\u679c\u4ee5\u6bcf\u53f0\u670d\u52a1\u5668400W\u529f\u7387\u8ba1\u7b97\u7684\u8bdd\uff0c\u6bcf\u4e2a\u673a\u67dc\u9700\u898110KW\u7684\u4f9b\u7535\uff0c\u5373\u6bcf\u4e2aPOD\u7684IT\u8d1f\u8f7d\u5bb9\u91cf\u662f2MW\u3002 room datacenter region root CRUSH is the algorithm and calculation for distributing data through the cluster. CRUSH Map obviously plays a part in how those CRUSH calculations work.","title":"CRUSH Hierarchy"},{"location":"linux/SES/linux_ses_memo/#crush-map-sections-six-main-sections","text":"tunables: adjustments to legacy behavior devices: The list of OSDs (usually no customization needed) \u25cb \"device class\" is meaningful; useful in relation to creating/using CRUSH rulesets \u25cb Standard \"device class\" values are \"hdd.\", \"ssd.\", and \"nvme.\" \u25cb Example: device 7 osd.7 types: types of buckets (usually no customization needed) buckets: the most functional, customizable aspect of the Map \u25cb A bucket typically represents a physical location in the cluster, has a \u201ctype\u201d \u25cb Nodes (containers such as hosts) and leaves (storage devices such as OSDs) rules: define policies of how data should be distributed \u25cb The behind-the-scenes rules that CRUSH follows for data placement \u25cb IMPORTANT: this is NOT the same as the \"ruleset\". In fact, a ruleset is the combined set of all of these six Map sections. choose_args (optional): Rarely used exceptional settings to adjust weights From the documentation: \"choose_args are alternative weights associated with the hierarchy that have been adjusted to optimize data placement. A single choose_args map can be used for the entire cluster, or one can be created for each individual pool.\"","title":"CRUSH Map Sections (Six main sections)"},{"location":"linux/SES/linux_ses_memo/#erasure-coding","text":"In information theory : an erasure code is a forward error correction (FEC, \u524d\u5411\u7ea0\u9519) code for the binary erasure channel, which transforms a message of k symbols into a longer message (code word) with n symbols such that the original message can be recovered from a subset of the n symbols. The fraction r = k/n is called the code rate The fraction k\u2019/k, where k\u2019 denotes the number of symbols required for recovery, is called reception efficiency Another (easier) way of describing EC: It\u2019s like RAID in Clustered Storage","title":"Erasure Coding"},{"location":"linux/SES/linux_ses_memo/#erasure-coding-in-ses","text":"The default resilience strategy in SES is simple replication * SES Simple replication has overheads, size=3 means 3 times the storage requirements Simplistic EC details: k = number of \u201cdata\u201d chunks, split across \u201ck\u201d number of OSDs m = number of \u201cparity\u201d chunks, split across \u201cm\u201d number of OSDs Ceph calls these \u201ccoding chunks\u201d r (size) = k + m admin:~ # ceph osd crush rule ls replicated_rule","title":"Erasure Coding in SES"},{"location":"linux/SES/linux_ses_memo/#replication-vs-erasure-code","text":"Replication (default): Use Case: active data Simple and fast Uses more disk space Erasure coding: Use Case: archive data, more static data Calculates recovery data (needs more CPU power) Definable redundancy level Example: K data chunks = 2 , M code chunks = 1 Similar to a replication size of 2 But with only 50% more raw storage consumed Example: for 1GB of effective storage replication pool of size of 2 needs 2GB raw storage erasure coded pool with k=2/m=1 only requires 1.5GB raw storage","title":"Replication vs Erasure Code"},{"location":"linux/SES/linux_ses_memo/#ec-overwrites","text":"Historically, EC only works properly with Objects EC only allowed appends; overwrites were not allowed Works perfectly for objects in buckets but doesn\u2019t work well with Block or CephFS With recent releases of SES, EC can work well with Block and CephFS Facilitated by \u201cEC Overwrites\u201d feature Store data in an EC Pool, and store object metadata in a Replicated Pool Requires a little extra work when defining pools, but worth it ceph osd pool set allow_ec_overwrites true","title":"EC Overwrites"},{"location":"linux/SES/linux_ses_memo/#ec-profiles","text":"Using Erasure Coding, each Pool is assigned an EC Profile Multiple pools can share a single Profile The profile is just a definition Each Profile has multiple settings The common required settings for all Profiles are K, M EC Profiles must be created before EC Pools can be created Created from the Dashboard or CLI Once an EC Profile is created, you can create a CRUSH Ruleset based on the EC profile Once a pool is created, its EC Profile properties cannot be changed Main profile parameters K: M: stripe_unit - allows you to adjust the size of the data chunk Default size is 4K stripe_unit : size of data striped across devices; default 4K This variable can also be set in the master configuration (osd_erasure_code_stripe_unit) EC plugins - choose your favorite EC algorithm via a plugin jerasure/gf-complete (default, free, open, and very fast) (www.jerasure.org) ISA (Intel library; optimized for modern Intel processors) (only runs on Intel processors) LRC (\u201cLocally Repairable Code\u201d; layers over existing plugins) SHEC (\u201cShingled EC\u201d; trades extra storage for recovery efficiency) CLAY (\u201cCoupled LAYer\u201d; good for reduced network traffic)","title":"EC Profiles"},{"location":"linux/SES/linux_ses_memo/#creating-erasure-code-profiles-and-pools","text":"Syntax: ceph osd erasure-code-profile OPTIONS Option Description get - view details of an existing EC profile set - set a profile (create a profile), requires k and m values, with optional values such as ruleset, plugin. Once you create a profile, you can\u2019t change it. ceph osd erasure-code-profile set k= m= [plugin=] [stripe_unit=] ls - list profiles rm - Remove an EC profile ceph osd erasure-code-profile rm Common example (below) The default profile \u2012 2+1=3; data is written over 3 OSDs \u2012 Two data chunks \u2012 One code (parity) chunk \u2012 Uses jerasure plugin with standard Reed/Solomon (reed_sol_van) technique Setting a Custom EC Profile Option: \u2012 Profile name \u2012 K : number of stripes required \u2012 M : number of failed units Example: ceph osd erasure-code-profile set example-profile k=8 m=2 ruleset-failure-domain=host ruleset-failure-domain = crush bucket level for failure admin:/etc/ceph # ceph osd erasure-code-profile \\ set common_profile \\ k=4 \\ m=2 \\ plugin=jerasure \\ technique=reed_sol_van \\ stripe_unit=4K \\ crush-root=default \\ crush-failure-domain=rackcrush-device-class=ssd admin:/etc/ceph # ceph osd erasure-code-profile ls default admin:~ # ceph osd erasure-code-profile get default k=2 m=1 plugin=jerasure technique=reed_sol_van Pools Pools are at the heart of Storage Pools are tied to OSDs Display a list of existing pools: ceph osd pool ls or ceph osd lspools View the statistics and characteristics of pools: ceph osd pool stats ceph osd pool stats ceph osd pool get Show usage and related details of existing pools: rados df or ceph df or ceph df detail All storage revolves around Pools Each pool must be dedicated to a purpose: Object, Block, File Must specify # of Placement Groups and PG Placements Must specify whether using Replication or EC Must specify a CRUSH ruleset Create a Replicated Pool Syntax: ceph osd pool create replicated = number of placement groups for the pool = number of PGs for placement; routinely will be the same as pg_num Always a power of 2 Don\u2019t make the number too small; don\u2019t err on the high side, either Practices For a new pool, the pgp_num will generally (likley) just be the same as the pg_num When increasing the PGs in a pool, you may want to retain the smaller pgp_num to minimize rebalancing, and increase pgp_num later when rebalancing is more convenient If decreasing the PGs in a pool, the pgp_num is adjusted automatically Create an EC Pool (using an EC Profile) Syntax: ceph osd pool create erasure Example: ceph osd pool create EC-pool 128 128 erasure my-ec-profile Pools \u2013 Application Assignment Each Pool must have a stated purpose; application This defines which capabilities the Pool must support The applications are: Block (rbd), Object (rgw), and File (cephfs) There are subtypes of cephfs: i.e. cephfs:data, cephfs:metadata Application assignment happens after creating a pool It\u2019s effortless (and required) to assign an application on a new pool ceph osd pool application enable Changing application assignment after a pool is in use is \u201chard\u201d. Not recommended, only to be done as an expert Pools \u2013 Quotas One of the more desirable features of SDS is to set a maximum usage of a Pool - Quotas Prevent the over-use of a pool Set quotas based on number of objects or number of bytes ceph osd pool set-quota max_objects ceph osd pool set-quota max_bytes Show quota settings ceph osd pool get-quota To remove a quota, set the existing quota setting to 0 There are also application-level quotas For rgw and cephfs (not rbd; images are already limited in size) Pool Quotas vs. Application Quotas. When a pool quota nears its limit, the HEALTH mechanisms will display a \u201cPOOL_NEAR_FULL\u201d warning to the storage administrator. When the quota limit has been exceeded, the HEALTH mechanisms will display a \u201cPOOL_FULL\u201d warning to the storage administrator. Applications (clients) don\u2019t always handle the quotas cleanly. In most cases, once the Pool Quota is exceeded, the application will simply stop writing to the pool, and error messages and behavior at the application are inconsistent (if there are any messages at all). Pools \u2013 Snapshots Take (make) a snapshot of an existing pool ceph osd pool mksnap Remove a snapshot of a pool ceph osd pool rmsnap List pool snapshots rados -p lssnap Rollback the pool to an earlier snapshot rados -p rollback Images and cephfs have their own snapshot facilities. Object and Bucket snapshotting features related to rgw don\u2019t exist. Pools Snapshots versus App Snapshots The two different snapshot features cannot be used at the same time on a pool Either Pool Snapshots, or Application Snapshots; not both. (snap_mode = pool versus snap_mode = selfmanaged) Once you commit to pool snapshots for an RBD pool, you can\u2019t change to using RBD snapshots Pros and Cons of each, depending on your Use Case admin:~ # ceph osd pool ls detail -f json-pretty | grep snap_mode \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\", \"snap_mode\": \"selfmanaged\",","title":"Creating Erasure Code Profiles and Pools"},{"location":"linux/SES/linux_ses_memo/#bluestore","text":"BlueStore is the default storage backend in SES Highlighted features: compressing, no double-writes, faster checksums Ceph FileStore Model It is not ideal for a specialized purpose like a highly scalable distributed storage system. Only recommend that XFS be used. Both btrfs and ext4 have known bugs. The FileStore model uses cache from the filesystem (XFS). Memory for cache is managed by filesystem kernel module. Ceph BlueStore Model BlueStore consumes raw block devices. Metadata management with RocksDB. BlueStore employs RocksDB\u2019s key/value database in order to manage internal metadata, such as the mapping from object names to block locations on disk. Full data and metadata checksumming. By default all data and metadata written to BlueStore is protected by one or more checksums. A small specialized filesystem called BlueFS. This provides just enough of a filesystem to allow RocksDB to store its \"key/value files\" to share metadata across all the raw device(s) No data or metadata will be read from disk or returned to the user without being verified. Multi-device metadata tiering. BlueStore allows its internal journal (write-ahead log) to be written to a separate, highspeed device (like an SSD, NVMe, or NVDIMM) to increased performance. Efficient copy-on-write. RBD and CephFS snapshots rely on a copy-on-write clone mechanism that is implemented efficiently in BlueStore. BlueStore is a userspace model that provides its own memory management and cache. No need to clear the storage device cache OSDs help facilitate the performance of caching Default: cache the reads, don\u2019t cache the writes RocksDB\uff1a rocksdb\u662ffacebook\u57fa\u4e8eleveldb\u5f00\u53d1\u7684\u4e00\u6b3ekv\u6570\u636e\u5e93\uff0cBlueStore\u5c06\u5143\u6570\u636e\u5168\u90e8\u5b58\u653e\u81f3RocksDB\u4e2d\uff0c\u8fd9\u4e9b\u5143\u6570\u636e\u5305\u62ec\u5b58\u50a8\u9884\u5199\u5f0f\u65e5\u5fd7\u3001\u6570\u636e\u5bf9\u8c61\u5143\u6570\u636e\u3001Ceph\u7684omap\u6570\u636e\u4fe1\u606f\u3001\u4ee5\u53ca\u5206\u914d\u5668\u7684\u5143\u6570\u636e \u3002 BlueRocksEnv\uff1a \u662fRocksDB\u4e0eBlueFS\u4ea4\u4e92\u7684\u63a5\u53e3\uff1bRocksDB\u63d0\u4f9b\u4e86\u6587\u4ef6\u64cd\u4f5c\u7684\u63a5\u53e3EnvWrapper\uff0c\u7528\u6237\u53ef\u4ee5\u901a\u8fc7\u7ee7\u627f\u5b9e\u73b0\u8be5\u63a5\u53e3\u6765\u81ea\u5b9a\u4e49\u5e95\u5c42\u7684\u8bfb\u5199\u64cd\u4f5c\uff0cBlueRocksEnv\u5c31\u662f\u7ee7\u627f\u81eaEnvWrapper\u5b9e\u73b0\u5bf9BlueFS\u7684\u8bfb\u5199\u3002 BlueFS\uff1a BlueFS\u662fBlueStore\u9488\u5bf9RocksDB\u5f00\u53d1\u7684\u8f7b\u91cf\u7ea7\u6587\u4ef6\u7cfb\u7edf\uff0c\u7528\u4e8e\u5b58\u653eRocksDB\u4ea7\u751f\u7684.sst\u548c.log\u7b49\u6587\u4ef6\u3002 BlockDecive\uff1a BlueStore\u629b\u5f03\u4e86\u4f20\u7edf\u7684ext4\u3001xfs\u6587\u4ef6\u7cfb\u7edf\uff0c\u4f7f\u7528\u76f4\u63a5\u7ba1\u7406\u88f8\u76d8\u7684\u65b9\u5f0f\uff1b BlueStore\u652f\u6301\u540c\u65f6\u4f7f\u7528\u591a\u79cd\u4e0d\u540c\u7c7b\u578b\u7684\u8bbe\u5907\uff0c\u5728\u903b\u8f91\u4e0aBlueStore\u5c06\u5b58\u50a8\u7a7a\u95f4\u5212\u5206\u4e3a\u4e09\u5c42\uff1a\u6162\u901f\uff08Slow\uff09\u7a7a\u95f4\u3001\u9ad8\u901f\uff08DB\uff09\u7a7a\u95f4\u3001\u8d85\u9ad8\u901f\uff08WAL\uff09\u7a7a\u95f4\uff0c\u4e0d\u540c\u7684\u7a7a\u95f4\u53ef\u4ee5\u6307\u5b9a\u4f7f\u7528\u4e0d\u540c\u7684\u8bbe\u5907\u7c7b\u578b\uff0c\u5f53\u7136\u4e5f\u53ef\u4f7f\u7528\u540c\u4e00\u5757\u8bbe\u5907\u3002 Allocator\uff1a\u8d1f\u8d23\u88f8\u8bbe\u5907\u7684\u7a7a\u95f4\u7ba1\u7406\uff0c\u53ea\u5728\u5185\u5b58\u505a\u6807\u8bb0\uff0c\u76ee\u524d\u652f\u6301StupidAllocator\u548cBitmapAllocator\u4e24\u79cd\u5206\u914d\u5668,Stupid\u57fa\u4e8eextent\u7684\u65b9\u5f0f\u5b9e\u73b0 Ceph BlueStore with Mixed Devices","title":"BlueStore"},{"location":"linux/SES/linux_ses_memo/#bluestore-cache-parameters","text":"Under most circumstances, autotune is best bluestore_cache_autotune Description: Automatically tune the ratios assigned to different bluestore caches while respecting minimum values Type: Boolean Required: Yes Default: True (enabled) Related settings: bluestore_cache_autotune_chunk_size, bluestore_cache_autotune_interval, and others bluestore_cache_size Description: The amount of memory BlueStore will use for its cache. If zero, bluestore_cache_size_hdd or bluestore_cache_size_ssd will be used instead. Type: Integer Required: Yes Default: 0 bluestore_cache_size_hdd Description: The default amount of memory BlueStore will use for its cache when backed by an HDD Type: Integer Required: Yes Default: 1 * 1024 * 1024 * 1024 (1 GB) bluestore_cache_size_ssd Description: The default amount of memory BlueStore will use for its cache when backed by an SSD. Type: Integer Required: Yes Default: 3 * 1024 * 1024 * 1024 (3 GB) bluestore_cache_meta_ratio Description: The ratio of cache devoted to metadata. Type: Floating point Default: .01 bluestore_cache_kv_ratio Description: The ratio of cache devoted to key/value data (rocksdb). Type : Floating point Default: .99 bluestore_cache_kv_max Description : The maximum amount of cache devoted to key/value data (rocksdb). Type : Unsigned Integer Default : 512 * 1024*1024 (512 MB)","title":"BlueStore Cache Parameters"},{"location":"linux/SES/linux_ses_memo/#bluestore-device-types","text":"BlueStore has three types of roles for devices: The DATA role: Required: main device (block symlink) stores all object data. If no other types: \u201cdata\u201d device serves all the other roles The DB role: Optional: DB device (block.db symlink) stores metadata in RocksDB Whatever doesn\u2019t fit will spill back onto the \u201cdata\u201d device The Write Ahead Log (WAL/Journal) role: Optional: WAL device (block.wal symlink) stores the internal journal Can combine all 3 roles into one physical device Or combine DB/WAL onto a single device with the DATA device separate Or all three on seperate devices","title":"BlueStore Device Types"},{"location":"linux/SES/linux_ses_memo/#bluestore-configuration-recommendations","text":"Devote DB and WAL to SSD or NVMe Allocate 64 GB to the RocksDB Allocate 4-6 GB to the WAL Assign the \u201cdata\u201d role to the slower (HDD) devices If combining WAL/DB on one device, use a single partition for both You can use a single SSD/NVMe to store multiple journals","title":"BlueStore Configuration Recommendations"},{"location":"linux/SES/linux_ses_memo/#architecture-overview-of-object-block-filesystem-access","text":"","title":"Architecture Overview of Object, Block, Filesystem Access"},{"location":"linux/SES/linux_ses_memo/#object-storage_1","text":"The state of the art of distributed storage Object storage is the Cloud Storage mechanism of choice Unstructured, to better accommodate large files and large quantities of files Ideal for large media files, like streaming videos, audio Scales really well, large capacities Ceph provides access to the storage via all three major data access methods: Block, Object, and File. For the storage backend, Object Storage is ideal","title":"Object Storage"},{"location":"linux/SES/linux_ses_memo/#block-storage","text":"Traditional Block Storage: Volumes as a collection of blocks Blocks can be of various sizes, but all the same within a volume Typically a filesystem is installed on top of the volume Hard Drives, CDs, USB sticks, etc The standard disk device mechanism for Unix, Linux, Windows, etc. Ceph presents RADOS as block device (RBD = RADOS Block Device) Ceph calls these block devices \u201cimages\u201d Provides clients with access like a \u201cdisk drive\u201d KVM/QEMU; libvirt; or remote Linux system A native Windows client that can access the Block storage of Ceph directly is in progress","title":"Block Storage"},{"location":"linux/SES/linux_ses_memo/#rados-block-device-rbd","text":"RBD is the RADOS Block Device A specific RBD instance in the cluster is called an \u201cimage\u201d RBD images can be accessed by OSs other than linux librbd provides interface for gateways like iSCSI RBD allows the client to decide what to do with the storage Filesystem type; raw disk, such as for a DB; etc RBD images can accommodate 16Eb file system sizes No matter the size, the storage is distributed durably throughout the cluster Data is striped across the RADOS cluster in object sized chunks 4MB default Provides high performance and durability Notable Benefits Ability to mount with Linux or QEMU KVM clients Thinly provisioned Resizable images Image import/export Image copy or rename Read-only snapshots Revert to snapshots Copy on Write clones Useful for standing up lots of virtual machines with same base configuration High performance due to striping across cluster nodes RBD image definition: Defined storage area presented as a block device to a client RBD Storage","title":"RADOS Block Device (RBD)"},{"location":"linux/SES/linux_ses_memo/#file-storage","text":"POSIX Filesystem via CephFS File access is a significant use case Home directories Historical comfort with files and directories Ease of managing \u201csmall\u201d stuff broadly, in a distributed system A Use Case that\u2019s growing in popularity: HPC CephFS is fast, scalable, and flexible Fits into many existing paradigms, rather seamlessly In particular: NFS, Samba/CIFS But even better: extending Linux filesystems Requires Metadata Service (MDS) for POSIX capabilities SUSE does NOT support any FUSE clients.","title":"File Storage"},{"location":"linux/SES/linux_ses_memo/#ceph-users-and-authentication","text":"Ceph Users are generally applications; applications that use the storage cluster The must common user is Admin A ceph admin user and credentials must exist Additional users and associated credentials are useful Each user must have credentials to access the storage cluster The most fundamental form of credentials in Ceph is keys Ceph Users and Keys The admin user has rights to all Ceph resources. Other users can be setup to have a subset of rights There are basically two types of Users (Actors): An individual (a person) An application (like a gateway, or some other kind of system) Most users are of the type client, and are represented as a dotted string, such as: client.admin, or client.steve, or client.swift The root linux user on the Admin node is effectively the Admin Ceph user, since the root user has all privileges to all filesystem objects on the Adminnode, including the ceph.client.admin.keyring. The root user on any of the nodes in the cluster can \u201cimpersonate\u201d all of the Ceph clients. Linux user accounts do not have any affect on the Ceph Users as managed in the dashboard. Take care to keep backups of the /etc/ceph/ directory structure, so that you don\u2019t lose these keys/keyrings. Each user must have a key/keyring, for example: /etc/ceph/ceph.client.admin.keyring on the Admin node /etc/ceph/ceph.client.storage.keyring on a storage node admin:/etc/ceph # cat ceph.client.admin.keyring [client.admin] key = AQD6pHpfAAAAABAAHJvkvLhOKZyQxm9lgnR5Qg== caps mds = \"allow *\" caps mon = \"allow *\" caps osd = \"allow *\" caps mgr = \"allow *\" data1:/etc/ceph # cat ceph.client.storage.keyring [client.storage] key = AQD8pHpfAAAAABAAHecCBgBsLIyPrJf+27eXUQ== caps mon = \"allow rw\" Ceph Keys and Keyrings A keyring contains one or more keys Each user can have its own keyring A keyring can contain multiple keys Different clients and users must have their own key, but multiple keys can be joined together in a single keyring Normally a key will be contained in a keyring Core Ceph will only recognize and use keys from keyrings Stand-alone keys are useful for other tools, like clients Ceph Authentication List The Admin node (and client.admin) can list all Users ceph auth list Create a Ceph User A typical user will have read rights to MONs, and read/write rights to a pool (osd) ceph auth get/add/get-or-create xxxxxx Create a User with ceph-authtool Create a keyring ceph-authtool -C /etc/ceph/ceph.client.richard.keyring Create a key, and place it on the keyring ceph-authtool --gen-key -n client.richard --cap osd 'allow rw pool=data' --cap mon 'allow r' /etc/ceph/ceph.client.richard.keyring Now officially tell the cluster about the key (add user to the key) ceph auth add client.richard -i /etc/ceph/ceph.client.richard.keyring Authentication with cephx The mechanism for passing keys around is cephx Authentication for users and daemons Does not provide data encryption, only authentication with keys cephx simply ensures the authenticity of actors So that no man-in-the-middle attacks can occur Other authentication mechanisms are theoretically possible Attempts to integrate LDAP and Kerberos have been made \u2026 but they have not come to full fruition yet","title":"Ceph Users and Authentication"},{"location":"linux/SES/linux_ses_memo/#ceph-configuration","text":"Historically, the Ceph configuration was kept only in a file on the Admin node: /etc/ceph/ceph.conf, and sync'd to MONs and Storage Nodes SES DeepSea manages the ceph.conf file. Don\u2019t edit it directly; use Salt and DeepSea With Ceph Nautilus, most configuration held as objects in the Monitors using Dashboard or CLI for operation Ceph Configuration Stored in the MONs The MONs keep a configuration database Show all the configuration keys: admin:/etc/ceph # ceph config ls |less Show the configuration settings that have been customized. The dumped output also indicates an EXPERTISE LEVEL The keys also have a \u201cwho\u201d attribute. In below case, \"osd.*\" represents the \"who\", which is getting the general setting for all OSDs Ceph Configuration Settings Show configuration settings that have been customized: admin:/etc/ceph # ceph config dump WHO MASK LEVEL OPTION VALUE RO mgr advanced mgr/dashboard/GRAFANA_API_URL https://mon1.pvgl.sap.corp:3000 * mgr advanced mgr/dashboard/RGW_API_ACCESS_KEY M11I3JGQHAQM94CS910K * mgr advanced mgr/dashboard/RGW_API_HOST mon3.pvgl.sap.corp * mgr advanced mgr/dashboard/RGW_API_PORT 80 * mgr advanced mgr/dashboard/RGW_API_SECRET_KEY YWyRc3mayEPiOEUzQ2o76KePSKmVKN4fIWxgqTt6 * mgr advanced mgr/dashboard/RGW_API_USER_ID admin * mgr advanced mgr/dashboard/ssl_server_port 8443 admin:/etc/ceph # ceph config get osd.* osd_max_object_size 134217728 admin:/etc/ceph # ceph config show osd.0 \u2026\u2026 admin:/etc/ceph # ceph config show osd.11 (4 data nodes, 3 osds in each node) \u25cb Each of the configuration settings have default values ceph config show-with-defaults osd.2 | less \u25cb Ceph keeps a log of configuration changes admin:/etc/ceph # ceph config log --- 8 --- 2020-10-05 14:31:51.425902 --- + mgr/mgr/dashboard/RGW_API_USER_ID = admin --- 7 --- 2020-10-05 14:31:50.418622 --- + mgr/mgr/dashboard/RGW_API_HOST = mon3.pvgl.sap.corp --- 6 --- 2020-10-05 14:31:49.398448 --- + mgr/mgr/dashboard/RGW_API_PORT = 80 --- 5 --- 2020-10-05 14:31:48.403965 --- + mgr/mgr/dashboard/RGW_API_SECRET_KEY = YWyRc3mayEPiOEUzQ2o76KePSKmVKN4fIWxgqTt6 --- 4 --- 2020-10-05 14:31:46.905701 --- + mgr/mgr/dashboard/RGW_API_ACCESS_KEY = M11I3JGQHAQM94CS910K --- 3 --- 2020-10-05 13:15:29.530355 --- + mgr/mgr/dashboard/GRAFANA_API_URL = https://mon1.pvgl.sap.corp:3000 --- 2 --- 2020-10-05 13:15:14.349623 --- + mgr/mgr/dashboard/ssl_server_port = 8443 --- 1 --- 2020-10-05 13:13:55.637896 ---","title":"Ceph Configuration"},{"location":"linux/SES/linux_ses_memo/#health","text":"Show status admin:/etc/ceph # ceph status cluster: id: 343ee7d3-232f-4c71-8216-1edbc55ac6e0 health: HEALTH_OK services: mon: 3 daemons, quorum mon1,mon2,mon3 (age 6w) mgr: mon1(active, since 13d) mds: cephfs:1 {0=mon3=up:active} 2 up:standby osd: 12 osds: 12 up (since 9w), 12 in (since 9w) rgw: 1 daemon active (mon3) task status: scrub status: mds.mon3: idle data: pools: 7 pools, 208 pgs objects: 246 objects, 4.7 KiB usage: 14 GiB used, 82 GiB / 96 GiB avail pgs: 208 active+clean io: client: 11 KiB/s rd, 0 B/s wr, 11 op/s rd, 6 op/s wr admin:/etc/ceph # ceph health HEALTH_OK admin:/etc/ceph # ceph health detail HEALTH_OK admin:/etc/ceph # ceph mon stat e1: 3 mons at {mon1=[v2:10.58.121.186:3300/0,v1:10.58.121.186:6789/0],mon2=[v2:10.58.121.187:3300/0,v1:10.58.121.187:6789/0],mon3=[v2:10.58.121.188:3300/0v1:10.58.121.188:6789/0]}, election epoch 22, leader 0 mon1, quorum 0,1,2 mon1,mon2,mon3 admin:/etc/ceph # ceph osd stat 12 osds: 12 up (since 9w), 12 in (since 9w); epoch: e1375 admin:/etc/ceph # ceph pg stat 208 pgs: 208 active+clean; 4.7 KiB data, 2.0 GiB used, 82 GiB / 96 GiB avail; 1.2 KiB/s rd, 1 op/s Watch status -w, --watch : Watch live cluster changes --watch-debug : Watch debug events --watch-info : Watch info events --watch-sec : Watch security events --watch-warn : Watch warning events --watch-error : Watch error","title":"Health"},{"location":"linux/SES/linux_ses_memo/#scrub-and-deep-scrub","text":"\"Scrub\" is the process of doing a data consistency check Basically like running fsck on the cluster In Replicas: compare object metadata among replicas In EC: verify \u201ccode\u201d chunks Manual scrubbing can be done per OSD or per PG. \"osd scrub\" is just a collaborative wrapper of \"pg scrub\". ceph osd scrub osd.11 ceph pg scrub 3.33 \"scrub\" is a light process, daily Checks object size and attributes \"deep-scrub\" is a more thorough process, weekly Reads all data and checks the checksums Scrub \u2013 Manual vs Automatic You can let Ceph just do the default Run scrub daily, run deep-scrub weekly Ceph pays attention to usage and backs off when necessary You can change the defaults for both scrub and deepscrub, examples: osd_scrub_begin_week_day=6 (Saturday) osd_scrub_end_week_day=7 (Sunday) You can manually run scrubbings at any time if you suspect it\u2019s wanted or needed Manual scrubbings are not common Adjustments to Scrub Settings For most circumstances the default behavior of Scrub is adequate See current Scrub configuration settings: ceph config ls | grep osd_scrub ceph config ls | grep osd_deep_scrub ceph config get osd.* osd_scrub_begin_hour Change the settings immediately in the MON DB ceph config set osd.* osd_scrub_begin_hour 23 ceph config set osd.* osd_scrub_end_hour 5 Adjust Settings in ceph.conf with DeepSea To permanently change settings in ceph.conf This is the \u201cold\u201d way, but is still valid Remember that ceph.conf is controlled by DeepSea Add changes to /srv/salt/ceph/configuration/files/ceph.conf.d/global.conf Run the following DeepSea (Salt) commands: salt admin* state.apply ceph.configuration.create salt \\* state.apply ceph.configuration Wait for services/servers to be restarted, or tell Ceph to assimilate the ceph.conf settings now ceph config assimilate-conf -i /etc/ceph/ceph.conf","title":"Scrub and Deep-Scrub"},{"location":"linux/SES/linux_ses_memo/#repair","text":"Problems Found by Scrubbing * If data (in an OSD or PG) becomes inconsistent, it will need to be repaired. You can configure scrubbing to automatically repair errors * osd_scrub_auto_repair=True * osd_scrub_auto_repair_num_errors=5 * Manually repair when appropriate * ceph osd repair osd.11 * ceph pg repair 3.33","title":"Repair"},{"location":"linux/SES/linux_ses_memo/#ceph-manager-modules","text":"Manager Modules help to extend the capabilities of Ceph List of Modules Supported in SES Balancer (always on) rash (always on) Dashboard DeepSea iostat Orchestrator (always on) progress (always on, tech preview) Prometheus RESTful rbd_support (always on) status (always on) telemetry volume (always on) Zabbix (plugin only, not the required agent) Enabling Manager Modules Show a list of Manager Modules ceph mgr module ls | less The output is quite long; best to pipe it through less The top of the output shows those modules that have been enabled The exhaustive output also displays the \u201cAPI\u201d of each module Manager modules are quite easy to enable and disable ceph mgr module enable ceph mgr module disable Show list of services that are active from the Modules ceph mgr services Module Capabilities Each module has its own settings, configuration Once the module is enabled, the ceph command accepts commands for the module No need to run the command as ceph mgr ... Examples: ceph crash stat ceph telemetry show Setting parameters (key/value pairs) of Modules ceph config set mgr mgr/telemetry/contact 'JD ' ceph config set mgr mgr/telemetry/description 'Training Cluster'","title":"Ceph Manager Modules"},{"location":"linux/SES/linux_ses_memo/#ceph-tell","text":"Tell commands are actually directed to the target service by way of the MONs ceph tell is a tool to tell a ceph daemon to perform a task \u2026 change a setting \u2026 execute a subroutine The target of ceph tell can be a single daemon or a collection of daemons All MONs: ceph tell mon.* injectargs '--mon-pg-warn-max-per-osd 4096' A specific OSD: ceph tell osd.9 bench ceph tell is the most common way to change logging for troubleshooting ceph tell . injectargs '--debug- ' ceph tell osd.7 injectargs '--debug-osd 20' ceph tell osd.7 config set debug_osd 20 A \u201c/\u201d allows you to change both the file log and memory log settings simultaneously ceph tell mon.3 injectargs '--debug-mon 0/10' (The first is the file parameter, the second is the memory parameter) Since logging can fill space, important to restore settings after investigating ceph tell mon.3 injectargs '--debug-mon 1/5' ceph tell sends its instructions via the Monitors. So what if the MONs are having problems? To avoid running commands through the MONs, go directly to thenode running the daemon ssh storage1 ceph daemon osd.29 config show ceph daemon osd.29 config set debug_osd 0/20 Use with great care","title":"Ceph Tell"},{"location":"linux/SES/linux_ses_memo/#ceph-dashboard_1","text":"What's Ceph Dashboard SES WEB-based Management Interface A Ceph MGR module, built-in to Ceph The open source \"port\" of openATTIC to Ceph. Technically it\u2019s not a port of openATTIC. SUSE and Ceph Community worked on implementing the openATTIC capabilities directly within Ceph Role-based and Multi-User Management of the SES cluster Create, manage, and monitor Pools, RBDs Manage users, access keys, quotas and buckets of RGW Manage NFS exports, iSCSI targets and portals, CephFS View cluster nodes/roles, monitor performance metrics Manage Ceph settings/configuration Reduces the need to understand complex Ceph commands The dashboard is stateless, it will reflect any changes to the Ceph cluster, Highlighted Enterprise Behavior via Ceph Dashboard Uses SSL/TLS By default will use a CA and certificate created by DeepSea or provide your own CA and certificate Can run without SSL/TLS (not recommended) Multi-User and Role Management Variety of mappings, i.e.: read, create, update, delete Single Sign-On, complying with SAML 2.0 Single Sign-On, complying with SAML 2.0 Auditing on the backend, to monitor specific user activity Internationalization (I18N), with a variety of language translations Ceph Dashboard Architecture Backend is based on CherryPy framework (CherryPy is a Minimalist Python Web Framework) Frontend WebUI is based on Angular/TypeScript A custom REST API Monitoring facilitated by Prometheus Visualization of data facilitated by Grafana Dependent upon DBUS, systemd, and systems\u2019 shell Dashboard as Manager Module Ceph Dashboard runs as a Manager module Runs on each MON/MGR node Really only actively available via the active MGR Runs on \u201cstandby\u201d on the standby MGR nodes Standby Dashboards will redirect to active MGR URL Dashboard automatically switches to active MGR node Helpful High Availability feature As a MGR module, enabled and configured by DeepSea Can be disabled if unwanted URL example: https://10.58.121.186:8443 Grafana and Prometheus Prometheus collects various data about the cluster Grafana represents the data as graphs Ceph Dashboard uses both to improve insight into SES Prometheus Open source event monitoring software \"Scrapes\" (collects) data from nodes/services in the cluster Real-time Time series Custom scrapers have been created for Ceph Stores scraped data in memory and on disk Presents data to other software for graphical representation Integrated nicely with Grafana Grafana The leading open source software for time series analytics \"Dashboards\" of panels, graphs, metrics, etc. \"Dashboard\" is a slightly conflicting term, but still meaningful Renders data in a graphical way collected from Prometheus Graphs are customized for use on the Ceph Dashboard Dashboard Users Always need an \u201cAdmin\u201d user for the Dashboard \u00a7 The admin keys of the root user on the \u201cAdmin\u201d node in the cluster Dashboard Users are accounts that relate only to using the Dashboard \u00a7 Not the same as Ceph CLI users and client keys; but could coincide Any person who wants to interact with the storage cluster via the Dashboard must have a user account Variety of Users established by the Admin User, and various permissions based on Admin-defined Roles User Authentication Dashboard Administrators can setup users with specific privileges The privileges and permissions are managed as \"roles\" User accounts can be created directly in the Dashboard Stored as objects in Ceph User accounts can also be tied to other authentication mechanisms: Single Sign-On Service; SAML 2.0 compliant protocol Dashboard accounts can be managed from the Dashboard or from the CLI Example: ceph dashboard ac-user-show [] The Admin Dashboard User (the term \u201cadmin\u201d is used differently in different places) The Dashboard Admin User is not the same as other admins The \u201cadmin\u201d node is obviously not directly tied to any admin user The Admin Dashboard User is created at Deployment time Given a random password by DeepSea You must use the CLI to establish the admin password ceph dashboard ac-user-show admin ceph dashboard ac-user-set-password admin \u25cb The SES Deployment Course has set the password to mypassword admin:~ # ceph dashboard ac-user-show [\"admin\"] admin:~ # ceph dashboard ac-user-show admin {\"username\": \"admin\", \"password\": \"$2b$12$4lC/AU7jc6midTZufj4P4.rBtVzRGf7Zy7fUbD6G9YfdfVEwkwuUy\", \"roles\": [\"administrator\"], \"name\": null \"email\":null\"lastUpdate\": 1601874928} Health from the Dashboard Cluster Status Monitors OSDs Manager Daemons Hosts Object Gateways Metadata Service iSCSI Gateways Cluster Performance from Dashboard Client IOPS Client Throughput Client Read/Write Recovery Throughput Scrub Performance Data Hosts: Overall Performance Monitors: Performance Counters OSDs: Relative Read/Write bar graphs, and Overall Performance Pools: Relative Read/Write bar graphs, and Overall Performance Block images: Overall Performance CephFS: Performance Details RGW: Overall Performance Cluster Capacity from Dashboard Capacity data: Number of Pools Raw Capacity Number of Objects (Ceph objects, not user objects from RGW) Placement Groups per OSD Placement Group Status","title":"Ceph Dashboard"},{"location":"linux/SES/linux_ses_memo/#basic-troubleshooting","text":"Ceph Logs Logs normally stored in /var/log/ceph/ No real logs on the admin node Each service has its own log on the MON, Storage and Gateway nodes Logs handled routinely by logrotate Ceph has logs that are stored to files and in memory (triggered by event or manual request) There are 21 different levels of logging: 0-20 (0 is no logging; 20 is the most verbose logging) There are many subsystems that do their own logging, and can be configured independently Most common: mon, osd, mgr, rados, rbd, mds, rgw Others: asok, auth, client, filestore, journal, monc, ms, paxos, and more There are only 3 types of daemons: osd, mon, mds Using Tell to Change Log Levels 1) Check the Dashboard and Health. Common commands ceph status ceph osd status ceph osd df ceph osd utilization ceph osd pool stats ceph osd tree ceph pg stat 2) Network Troubleshooting Always be sure that the network (and related services) are working properly Ceph depends heavily on tightly synchronized time; make sure network time services are working on each node DNS hostnames are similarly essential 3) Check the Logs Go to the node of the component implicated in HEALTH 4: Raise the DEBUG Level. Follow this simple formula: Raise the debug level (a little each time until you see the problem) Check the logs Repeat as necessary Don\u2019t forget to restore the debug level back to its normal level 5) Check the Storage Device If the problem is with an OSD or a storage device, go straight to the device: hdparm smartctl And check out the details of the combination of OSD and storage device: lsblk /var/lib/ceph/osd/ 6) Scrub (or not) Sometimes simply scrubbing an OSD or PG can cause the checksum-ing process to reveal problems At least some problems can be made more clear with the result of scrub and/or deep-scrub Even doing a scrub can kick Ceph into fixing the problem itself And don\u2019t forget ceph osd repair On the other hand, sometimes Scrub can make things worse. If you suspect Scrub is part of the problem, turn it off: ceph osd set noscrub ceph osd unset noscrub 7) Placement Groups When Placement Groups cause problems: * ceph pg dump summary * ceph pg dump pools * ceph pg dump_jason * ceph pg dump | less Followed by a strategic \u201crepair\u201d of the PG * ceph pg repair 8) Running supportconfig YaST Support Module From CLI: supportconfig The collected data is stored in a file called /var/log/nts__.txz","title":"Basic Troubleshooting"},{"location":"linux/SRE/01-fundamentals/","text":"\u7b2c\u4e00\u7ae0 Linux\u57fa\u7840 \u00b6 1.\u5b98\u65b9\u6587\u6863 \u00b6 Rocky Linux Instructional Books openSUSE Documentation Ubuntu Documentation 2.\u7cfb\u7edf\u73af\u5883 \u00b6 2.1.Rocky \u00b6 \u4f7f\u7528\u7248\u672c\uff1a Rocky 9.0 \u3002 \u4ece\u7f51\u7ad9\u4e0b\u8f7dRocky\u7cfb\u7edf ISO\u955c\u50cf \uff0c\u6216\u8005\u901a\u8fc7 wget \u547d\u4ee4\u4e0b\u8f7dRocky\u7cfb\u7edfISO\u955c\u50cf\u3002 wget https://download.rockylinux.org/pub/rocky/9.0/isos/x86_64/Rocky-9.0-x86_64-dvd.iso \u5b89\u88c5\u65f6\u6211\u9009\u62e9\u4e86\u6fc0\u6d3b root \u7528\u6237\uff0c\u9009\u62e9\u4e86Server\u6a21\u5f0f\u5b89\u88c5\uff08\u6ca1\u6709GUI\uff09\u3002 \u4ee5 root \u767b\u5f55\uff0c\u6267\u884c\u4e0b\u9762\u547d\u4ee4\u4fee\u6539 sudo \u6743\u9650\u3002 visudo \u5e76\u6fc0\u6d3b\u4e0b\u9762\u4e00\u884c\uff08\u4e0d\u8bbe\u5bc6\u7801\uff0c\u65b9\u4fbf\u7ec3\u4e60\uff09\uff1a %wheel ALL =( ALL ) NOPASSWD: ALL \u521b\u5efa\u7528\u6237 vagrant \uff0c\u5e76\u8bbe\u7f6e wheel \u4e3a\u4e3b\u8981\u7ec4\u548c\u4fee\u6539\u5bc6\u7801\u3002 adduser vagrant usermod -g wheel vagrant passwd vagrant \u8bbe\u5b9ahostname\uff08\u5305\u62ec\u522b\u540d\uff09\uff0c\u5e76\u67e5\u770b\u7ed3\u679c\u3002 hostnamectl set-hostname --static \"rocky9\" hostnamectl set-hostname --pretty \"rocky9\" hostnamectl cat /etc/hostname \u5c0f\u8d34\u58eb\uff1a \u7531systemd\u63a7\u5236\u7684\u4e3b\u673a\u540d\u7684\u670d\u52a1\u914d\u7f6e\u4fe1\u606f\uff1a /usr/lib/systemd/system/systemd-hostnamed.service Rocky\u7684\u8f6f\u4ef6\u6e90\u7684\u914d\u7f6e\u4fe1\u606f\u4fdd\u5b58\u5728\u76ee\u5f55 /etc/yum.repos.d/ \u4e0b\u3002\u5982\u679c\u8bbf\u95ee\u9ed8\u8ba4\u6e90\u6bd4\u8f83\u6162\uff0c\u53ef\u4ee5\u66f4\u65b0\u963f\u91cc\u6e90\u6216\u8005\u79d1\u5927\u6e90\u3002 \u66f4\u6362\u963f\u91cc\u6e90\u3002 sed -e 's|^mirrorlist=|#mirrorlist=|g' \\ -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \\ -i.bak \\ /etc/yum.repos.d/Rocky-*.repo \u66f4\u6362\u79d1\u5927\u6e90\u3002 sed -e 's|^mirrorlist=|#mirrorlist=|g' \\ -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.ustc.edu.cn/rocky|g' \\ -i.bak \\ /etc/yum.repos.d/rocky-extras.repo \\ /etc/yum.repos.d/rocky.repo \u5237\u65b0\u7f13\u5b58\u3002 dnf makecache 2.2.Ubuntu \u00b6 \u4f7f\u7528\u7248\u672c\uff1a Ubuntu 2204 \u3002 \u8bbe\u5b9aroot\u7528\u6237\u7684\u5bc6\u7801\u3002 sudo passwd root \u901a\u8fc7\u5b89\u88c5\u65f6\u5df2\u521b\u5efa\u7684\u7528\u6237 vagrant \u767b\u5f55\u3002\u6267\u884c\u4e0b\u9762\u547d\u4ee4\u4fee\u6539 sudo \u6743\u9650\u3002 sudo visudo \u6dfb\u52a0 vagrant \u5230\u7279\u6743\u7528\u6237\uff08Rocky\u548copenSUSE\u4e0d\u9700\u8981\u6dfb\u52a0\uff09\uff0c\u5e76\u6fc0\u6d3bsudo\u4e00\u884c\uff08\u4e0d\u8bbe\u5bc6\u7801\uff0c\u65b9\u4fbf\u7ec3\u4e60\uff09\uff1a # User privilege specification root ALL =( ALL:ALL ) ALL vagrant ALL =( ALL:ALL ) ALL # Allow members of group sudo to execute any command sudo ALL =( ALL:ALL ) NOPASSWD: ALL \u4fee\u6539\u7528\u6237 vagrant \u7684\u4e3b\u8981\u7ec4\u4e3a sudo \u3002 sudo usermod -g sudo vagrant \u4fee\u6539\u4e3b\u673a\u540d\u548c\u522b\u540d\u3002 sudo hostnamectl set-hostname ubuntu2204 sudo hostnamectl set-hostname ubuntu2204 --pretty \u5c0f\u8d34\u58eb\uff1a \u5982\u4f55\u5904\u7406 Username is not in the sudoers file. This incident will be reported \u95ee\u9898\u3002 \u5982\u679c\u6ca1\u6709\u521d\u59cb\u5316 root \u7528\u6237\u7684\u5bc6\u7801\uff0c\u4e14\u5f53\u524d\u7528\u6237\u4e5f\u65e0\u6cd5\u6267\u884c sudo \u547d\u4ee4\uff0c\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u6b65\u9aa4\u901a\u8fc7recovery\u6551\u63f4\u6a21\u5f0f\u8fdb\u884c\u6062\u590d\u3002 \u6309 shift \u952e\u5f00\u673a\uff0c\u8fdb\u5165grub\u542f\u52a8\u83dc\u5355\u3002\uff08VMWare\u4e5f\u9002\u7528\uff09 \u5411\u4e0b\u79fb\u52a8\u9ad8\u4eae\u6761\uff0c\u9009\u62e9\u83dc\u5355 Advanced options for Ubuntu \uff0c\u5e76\u786e\u8ba4\u56de\u8f66\u3002 \u9009\u62e9\u5e26\u6709 recovery mode \u7684\u5185\u6838\uff0c\u786e\u8ba4\u56de\u8f66\u3002 \u5411\u4e0b\u79fb\u52a8\u9ad8\u4eae\u6761\uff0c\u9009\u62e9\u83dc\u5355 root Drop to root shell prompt \uff0c\u5e76\u786e\u8ba4\u56de\u8f66\u3002 \u56de\u8f66\u786e\u8ba4 press Enter for maintenance \u3002 \u51fa\u73b0 root \u7684\u547d\u4ee4\u63d0\u793a\u7b26\u540e\uff0c\u6267\u884c\u547d\u4ee4 mount -o rw,remount / \u3002 \u6267\u884c\u547d\u4ee4 passwd \u7ed9 root \u8bbe\u5b9a\u5bc6\u7801\u3002 \u6267\u884c\u547d\u4ee4 adduser username sudo \u628a\u6307\u5b9a\u7528\u6237\u52a0\u5165 sudo \u7ec4\u3002 \u6267\u884c\u547d\u4ee4 visudo \u8fdb\u884c\u5fc5\u8981\u7684\u4fee\u6b63\u6216\u4fee\u6539\u3002 2.3.openSUSE \u00b6 \u4f7f\u7528\u7248\u672c\uff1a Leap 15.4 \u3002 \u9009\u62e9\u670d\u52a1\u5668\u6a21\u5f0f\u5b89\u88c5\uff0c\u65e0\u56fe\u5f62\u754c\u9762\u3002\u5b89\u88c5\u4e2d\u4e0d\u521b\u5efa\u7528\u6237\u3002 \u521b\u5efa\u7528\u6237 vagrant \uff0c\u5e76\u8bbe\u7f6e wheel \u4e3a\u4e3b\u8981\u7ec4\u3002 useradd -m -g wheel -G root -c \"vagrant\" vagrant passwd vagrant \u6267\u884c visudo \u547d\u4ee4\uff0c\u6fc0\u6d3b\u4e0b\u9762\u4e00\u884c\uff0c\u6dfb\u52a0 sudo \u6743\u9650\u3002 % wheel ALL =( ALL ) NOPASSWD: ALL \u4fee\u6539\u4e3b\u673a\u540d\u548c\u522b\u540d\u3002 sudo hostnamectl set-hostname lizard sudo hostnamectl set-hostname lizard --pretty 3.\u5e38\u7528\u547d\u4ee4 \u00b6 \u8bf4\u660e\uff1a \u9ed8\u8ba4\u5f53\u524d\u64cd\u4f5c\u7528\u6237\u4e3a vagrant \u3002 3.1.\u4fee\u6539\u63d0\u793a\u7b26\u98ce\u683c \u00b6 \u6267\u884c\u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u770b\u5230\u5f53\u524d\u7cfb\u7edf\u7684\u547d\u4ee4\u63d0\u793a\u7b26\u683c\u5f0f\u3002 echo $PS1 \u5404\u7cfb\u7edf\u9ed8\u8ba4\u8bbe\u7f6e\u662f\u6709\u5dee\u5f02\u7684\u3002 # Rocky [ \\u @ \\h \\W ] \\$ # Ubuntu \\[\\e ] 0 ; \\u @ \\h : \\w\\a\\] ${ debian_chroot :+( $debian_chroot ) } \\[\\0 33 [ 01 ; 32m \\]\\u @ \\h\\[\\0 33 [ 00m \\] : \\[\\0 33 [ 01 ; 34m \\]\\w\\[\\0 33 [ 00m \\]\\$ # openSUSE \\u @ \\h : \\w > \u5c0f\u8d34\u58eb\uff1a bash\u53ef\u8bc6\u522b\u7684\u8f6c\u4e49\u5e8f\u5217\u6709\u4e0b\u9762\u8fd9\u4e9b\uff1a \\u : \u5f53\u524d\u7528\u6237\u7684\u8d26\u53f7\u540d\u79f0 \\h : \u4e3b\u673a\u540d\u7b2c\u4e00\u90e8\u5206 \\H : \u5b8c\u6574\u7684\u4e3b\u673a\u540d\u79f0 \\w : \u5b8c\u6574\u7684\u5de5\u4f5c\u76ee\u5f55\u540d\u79f0\uff08\u5982 \"/home/username/mywork\"\uff09 \\W : \u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u7684\"\u57fa\u540d (basename)\"\uff08\u5982 \"mywork\") \\t : \u663e\u793a\u65f6\u95f4\u4e3a24\u5c0f\u65f6\u683c\u5f0f\uff0c\u5982\uff1aHH:MM:SS \\T : \u663e\u793a\u65f6\u95f4\u4e3a12\u5c0f\u65f6\u683c\u5f0f \\A : \u663e\u793a\u65f6\u95f4\u4e3a24\u5c0f\u65f6\u683c\u5f0f\uff1aHH:MM \\@ : \u5e26\u6709 am/pm \u7684 12 \u5c0f\u65f6\u5236\u65f6\u95f4 \\d : \u4ee3\u8868\u65e5\u671f\uff0c\u683c\u5f0f\u4e3aweekday month date\uff0c\u4f8b\u5982\uff1a\"Mon Aug 1\" \\s : shell \u7684\u540d\u79f0\uff08\u5982 \"bash\") \\v : bash\u7684\u7248\u672c\uff08\u5982 2.04\uff09 \\V : bash\u7684\u7248\u672c\uff08\u5305\u62ec\u8865\u4e01\u7ea7\u522b\uff09 \\n : \u6362\u884c\u7b26 \\r : \u56de\u8f66\u7b26 \\\\ : \u53cd\u659c\u6760 \\a : ASCII \u54cd\u94c3\u5b57\u7b26\uff08\u4e5f\u53ef\u4ee5\u952e\u5165 07 \uff09 \\e : ASCII \u8f6c\u4e49\u5b57\u7b26\uff08\u4e5f\u53ef\u4ee5\u952e\u5165 33 ) \\[ : \u8fd9\u4e2a\u5e8f\u5217\u5e94\u8be5\u51fa\u73b0\u5728\u4e0d\u79fb\u52a8\u5149\u6807\u7684\u5b57\u7b26\u5e8f\u5217\uff08\u5982\u989c\u8272\u8f6c\u4e49\u5e8f\u5217\uff09\u4e4b\u524d\u3002\u5b83\u4f7fbash\u80fd\u591f\u6b63\u786e\u8ba1\u7b97\u81ea\u52a8\u6362\u884c \\] : \u8fd9\u4e2a\u5e8f\u5217\u5e94\u8be5\u51fa\u73b0\u5728\u975e\u6253\u5370\u5b57\u7b26\u5e8f\u5217\u4e4b\u540e \\# : \u4e0b\u8fbe\u7684\u7b2c\u51e0\u4e2a\u547d\u4ee4 \\$ : \u63d0\u793a\u5b57\u7b26\uff0c\u5982\u679c\u662froot\u7528\u6237\uff0c\u63d0\u793a\u7b26\u4e3a # \uff0c\u666e\u901a\u7528\u6237\u5219\u4e3a $ \u5728PS1\u4e2d\u8bbe\u7f6e\u5b57\u7b26\u989c\u8272\u7684\u683c\u5f0f\u4e3a\uff1a [\\e[F;Bm]........[\\e[0m] \uff0c\u5176\u4e2d [\\e[0m] \u4f5c\u4e3a\u989c\u8272\u8bbe\u5b9a\u7684\u7ed3\u675f\u3002 \u5176\u4e2d\"F\"\u4e3a\u5b57\u4f53\u989c\u8272\uff0c\u7f16\u53f7\u4e3a30-37\uff0c\"B\"\u4e3a\u80cc\u666f\u989c\u8272\uff0c\u7f16\u53f7\u4e3a40-47\u3002 \u5c0f\u8d34\u58eb\uff1a \u989c\u8272\u5bf9\u7167\u8868: F:30 , B:40 : \u9ed1\u8272 F:31 , B:41 : \u7ea2\u8272 F:32 , B:42 : \u7eff\u8272 F:33 , B:43 : \u9ec4\u8272 F:34 , B:44 : \u84dd\u8272 F:35 , B:45 : \u7d2b\u7ea2\u8272 F:36 , B:46 : \u9752\u84dd\u8272 F:37 , B:47 : \u767d\u8272 \u4ee5\u4e0b\u9762\u7684PS1\u8bbe\u5b9a\u4e3a\u4f8b\u8bf4\u660e\u989c\u8272\u8bbe\u5b9a\u3002 PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[37;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" \u62c6\u89e3\u5206\u6790\uff1a PS1=\" \\[\\e[37;40m\\] # \u6574\u4e2a\u63d0\u793a\u7b26\u533a\u57df\u524d\u666f\u767d\u8272\uff0c\u80cc\u666f\u9ed1\u8272 [ # \u663e\u793a\u5b57\u7b26[ \\[\\e[32;40m\\] # \u4fee\u9970\u540e\u9762\u7684\\u\uff0c\u524d\u666f\u7eff\u8272\uff0c\u80cc\u666f\u9ed1\u8272 \\u # \u663e\u793a\u5f53\u524d\u7528\u6237\u7684\u8d26\u53f7\u540d\u79f0 \\[\\e[37;40m\\] # \u4fee\u9970\u540e\u9762\u7684\u5b57\u7b26@\u548c\u4e3b\u673a\u540d @ # \u663e\u793a\u5b57\u7b26@ \\h # \u663e\u793a\u4e3b\u673a\u540d : # \u663e\u793a\u5b57\u7b26: \\[\\e[36;40m\\] # \u4fee\u9970\u540e\u9762\u7684\\w\uff0c\u524d\u666f\u9752\u84dd\u8272\uff0c\u80cc\u666f\u9ed1\u8272 \\w # \u663e\u793a\u5b8c\u6574\u5de5\u4f5c\u76ee\u5f55 \\[\\e[0m\\] # \u7ed3\u675f\u989c\u8272\u8bbe\u5b9a ] # \u663e\u793a\u5b57\u7b26] \\$\" # \u5982\u679c\u662froot\u7528\u6237\uff0c\u63d0\u793a\u7b26\u4e3a# \uff0c\u666e\u901a\u7528\u6237\u5219\u4e3a$ \u5bf9\u4e0d\u540c\u4e3b\u673a\u505a\u4e0d\u540c\u8bbe\u7f6e\uff1a # Rocky PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[37;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" # Ubuntu PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[33;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" # openSUSE PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[35;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" \u5c06\u4e0a\u8ff0PS1\u7684\u8bbe\u5b9a\uff0c\u8ffd\u52a0\u5230\u5f53\u524d\u7528\u6237\u7684 ~/.bashrc \u6587\u4ef6\u672b\u5c3e\uff0c\u4ee5\u5b9e\u73b0\u5bf9\u5f53\u524d\u7528\u6237\u7684\u63d0\u793a\u7b26\u98ce\u683c\u505a\u6301\u4e45\u4fdd\u5b58\u3002 3.2.Linux\u7684\u5185\u5916\u90e8\u547d\u4ee4 \u00b6 \u5185\u90e8\u547d\u4ee4 (internal command)\u5b9e\u9645\u4e0a\u662fshell\u7a0b\u5e8f\u7684\u4e00\u90e8\u5206\uff0c\u5305\u542b\u7684\u662f\u4e00\u4e9b\u6bd4\u8f83\u7b80\u5355\u7684linux\u7cfb\u7edf\u547d\u4ee4\uff0c\u8fd9\u4e9b\u547d\u4ee4\u7531shell\u7a0b\u5e8f\u8bc6\u522b\u5e76\u5728shell\u7a0b\u5e8f\u5185\u90e8\u5b8c\u6210\u8fd0\u884c\uff0c\u901a\u5e38\u5728linux\u7cfb\u7edf\u52a0\u8f7d\u8fd0\u884c\u65f6shell\u5c31\u88ab\u52a0\u8f7d\u5e76\u9a7b\u7559\u5728\u7cfb\u7edf\u5185\u5b58\u4e2d\u3002 \u5916\u90e8\u547d\u4ee4 (external command)\u662flinux\u7cfb\u7edf\u4e2d\u7684\u5b9e\u7528\u7a0b\u5e8f\u90e8\u5206\uff0c\u7cfb\u7edf\u52a0\u8f7d\u65f6\u5e76\u4e0d\u968f\u7cfb\u7edf\u4e00\u8d77\u88ab\u52a0\u8f7d\u5230\u5185\u5b58\u4e2d\uff0c\u800c\u662f\u5728\u9700\u8981\u65f6\u624d\u5c06\u5176\u8c03\u7528\u5185\u5b58\u3002\u901a\u5e38\u5916\u90e8\u547d\u4ee4\u7684\u5b9e\u4f53\u5e76\u4e0d\u5305\u542b\u5728shell\u4e2d\uff0c\u4f46\u662f\u5176\u547d\u4ee4\u6267\u884c\u8fc7\u7a0b\u662f\u7531shell\u7a0b\u5e8f\u63a7\u5236\u7684\u3002 \u6bd4\u5982\uff1a \u6267\u884c\u547d\u4ee4 type -t cp \uff0c\u7cfb\u7edf\u8fd4\u56de\u7ed3\u679c\u662f file \uff0c\u5916\u90e8\u547d\u4ee4\u3002 \u6267\u884c\u547d\u4ee4 type -t cd \uff0c\u7cfb\u7edf\u8fd4\u56de\u7ed3\u679c builtin \uff0c\u5185\u90e8\u547d\u4ee4\u3002 \u6267\u884c\u547d\u4ee4 enable -a cp \uff0c\u7cfb\u7edf\u8fd4\u56de -bash: enable: cp: not a shell builtin \uff0c\u4e5f\u53ef\u4ee5\u5224\u65ad\u662f\u5426\u4e3a\u5185\u90e8\u547d\u4ee4\u3002 \u5bf9\u4e8e\u5185\u90e8\u547d\u4ee4\uff0c\u53ef\u4ee5\u901a\u8fc7enable\u547d\u4ee4\u6765\u542f\u7528\u6216\u8005\u7981\u7528\u3002 # \u7981\u7528cd\u547d\u4ee4 enable -n cd # \u67e5\u770b\u6240\u6709\u88ab\u7981\u7528\u7684\u547d\u4ee4 enable -n # \u542f\u7528cd\u547d\u4ee4 enable cd \u5bf9\u4e8e\u547d\u4ee4\uff0c\u53ef\u4ee5\u901a\u8fc7 whereis \u547d\u4ee4\u6765\u67e5\u770b\u8def\u5f84\u3002 whereis cp whereis cd 3.3.CPU\u4fe1\u606f \u00b6 lscpu cat /proc/cpuinfo 3.4.\u5185\u5b58\u4f7f\u7528\u72b6\u6001 \u00b6 free cat /proc/meminfo 3.5.\u786c\u76d8\u548c\u5206\u533a\u60c5\u51b5 \u00b6 lsblk openSUSE\u5728VMWare\u9ed8\u8ba4\u5b89\u88c5\u7684\u72b6\u6001\uff1a NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8 :0 0 200G 0 disk \u251c\u2500sda1 8 :1 0 8M 0 part \u251c\u2500sda2 8 :2 0 198G 0 part /home \u2502 /var \u2502 /opt \u2502 /usr/local \u2502 /root \u2502 /tmp \u2502 /srv \u2502 /boot/grub2/x86_64-efi \u2502 /boot/grub2/i386-pc \u2502 /.snapshots \u2502 / \u2514\u2500sda3 8 :3 0 2G 0 part [ SWAP ] sr0 11 :0 1 3 .8G 0 rom Ubuntu\u5728VMWare\u9ed8\u8ba4\u5b89\u88c5\u7684\u72b6\u6001\uff1a NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7 :0 0 61 .9M 1 loop /snap/core20/1405 loop1 7 :1 0 63 .2M 1 loop /snap/core20/1623 loop2 7 :2 0 79 .9M 1 loop /snap/lxd/22923 loop3 7 :3 0 48M 1 loop /snap/snapd/17029 loop4 7 :4 0 103M 1 loop /snap/lxd/23541 loop5 7 :5 0 48M 1 loop /snap/snapd/17336 sda 8 :0 0 50G 0 disk \u251c\u2500sda1 8 :1 0 1M 0 part \u251c\u2500sda2 8 :2 0 2G 0 part /boot \u2514\u2500sda3 8 :3 0 48G 0 part \u2514\u2500ubuntu--vg-ubuntu--lv 253 :0 0 24G 0 lvm / sr0 11 :0 1 1 .4G 0 rom Rocky\u5728VMWare\u9ed8\u8ba4\u5b89\u88c5\u7684\u72b6\u6001\uff1a NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8 :0 0 50G 0 disk \u251c\u2500sda1 8 :1 0 1G 0 part /boot \u2514\u2500sda2 8 :2 0 49G 0 part \u251c\u2500rl-root 253 :0 0 45 .1G 0 lvm / \u2514\u2500rl-swap 253 :1 0 3 .9G 0 lvm [ SWAP ] sr0 11 :0 1 7 .9G 0 rom 3.6.\u7cfb\u7edf\u67b6\u6784\u4fe1\u606f \u00b6 arch openSUSE\uff0cUbuntu\u548cRocky\u7684\u8fd4\u56de\u7ed3\u679c\u90fd\u662f x86_64 \u3002 3.7.\u5185\u6838\u7248\u672c \u00b6 uname -r \u4e09\u4e2a\u53d1\u884c\u7248\u8fd4\u56de\u7684\u7ed3\u679c\u4e0d\u5c3d\u76f8\u540c\uff1a # openSUSE 5 .14.21-150400.24.21-default # Ubuntu 5 .15.0-52-generic # Rocky 5 .14.0-70.17.1.el9_0.x86_64 3.8.\u64cd\u4f5c\u7cfb\u7edf\u7248\u672c \u00b6 cat /etc/os-release cat /etc/issue # Rocky 9 sudo cat /etc/redhat-release lsb-release -a lsb_release -cs lsb_release -is lsb_release -rs \u5728openSUSE\u4e2d\uff0c\u9700\u8981\u5b89\u88c5 lsb-release \u5305\u3002\u6267\u884c lsb-release -a \u548c lsb_release -a \u8fd4\u56de\u7684\u7ed3\u679c\u662f\u4e00\u6837\u7684\u3002 sudo zypper in lsb-release \u5728Ubuntu\u4e2d\uff0c\u9700\u8981\u5b89\u88c5 lsb-release \u5305\u3002\u53ea\u80fd\u6267\u884c lsb_release -a \u3002 sudo apt install lsb-release \u5728Rocky 9\u4e2d\uff0c\u627e\u4e0d\u5230 lsb-release \u76f8\u5173\u7684\u5305\u3002 3.9.\u65e5\u671f\u548c\u65f6\u95f4 \u00b6 \u663e\u793a\u9ed8\u8ba4\u683c\u5f0f\u7684\u5f53\u524d\u65e5\u671f\u3002 date \u4e09\u4e2a\u7cfb\u7edf\u7684\u9ed8\u8ba4\u65e5\u671f\u683c\u5f0f\u7565\u6709\u4e0d\u540c\u3002 # openSUSE Mon 24 Oct 2022 09 :28:06 AM CST # Ubuntu Mon Oct 24 01 :28:09 AM UTC 2022 # Rocky Mon Oct 24 09 :24:01 AM CST 2022 \u663e\u793a\u81ea1970-01-01 00:00:00 UTC\u5230\u5f53\u524d\u7684\u79d2\u6570\u3002 date +%s \u5c06\u4e0a\u4e00\u547d\u4ee4\u4e2d\u7684\u63cf\u8ff0\u8f6c\u6362\u4e3a\u7cfb\u7edf\u9ed8\u8ba4\u65e5\u671f\u683c\u5f0f\u3002 date -d @ ` date +%s ` date --date = @ '1666575347' \u663e\u793a\u786c\u4ef6\u65f6\u949f\u3002 hwclock \u4e5f\u88ab\u79f0\u4e3a Real Time Clock (RTC)\u3002 \u5728Rocky9\u4e2d\uff0c clock \u6709\u4e00\u4e2a\u8f6f\u8fde\u63a5\u6307\u5411 hwclock \uff1a /usr/sbin/clock -> hwclock \u3002\u5728openSUSE\u548cUbuntu\u4e2d\u53ea\u6709 hwclock \u3002 ll /usr/sbin/clock ll /usr/sbin/hwclock \u8bfb\u53d6RTC\u65f6\u95f4\u3002 sudo hwclock --get sudo hwclock -r \u6821\u51c6\u65f6\u95f4\uff1a -s, \u2013hctosys : \u4ee5RTC\u786c\u4ef6\u65f6\u95f4\u6765\u6821\u51c6\u7cfb\u7edf\u65f6\u95f4\u3002 -w, \u2013systohoc : \u4ee5\u7cfb\u7edf\u65f6\u95f4\u6765\u6821\u51c6RTC\u786c\u4ef6\u65f6\u95f4\u3002 \u663e\u793a\u5f53\u524d\u7cfb\u7edf\u65f6\u533a\u3002 ll /etc/localtime \u7cfb\u7edf\u53ef\u80fd\u4f1a\u8fd4\u56de\u4e0d\u540c\u7ed3\u679c\uff0c\u4f8b\u5982\uff1a /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai /etc/localtime -> /usr/share/zoneinfo/Etc/UTC \u663e\u793a\u5f53\u524d\u53ef\u4ee5\u65f6\u533a\u5217\u8868\u3002 timedatectl list-timezones timedatectl list-timezones | grep -i Asia \u4fee\u6539\u5f53\u524d\u7cfb\u7edf\u65f6\u533a\u3002 sudo timedatectl set-timezone Asia/Shanghai \u663e\u793a\u65e5\u5386\u3002 cal -y openSUSE\u548cRocky\u4e2d\uff0c\u4f7f\u7528 cal \u547d\u4ee4\u9700\u8981\u5b89\u88c5 util-linux \u5305\u3002 Ubuntu\u4e2d\uff0c\u4f7f\u7528 cal \u547d\u4ee4\u9700\u8981\u5b89\u88c5 ncal \u5305\u3002 sudo apt install ncal sudo zypper se util-linux sudo yum install util-linux 3.10.\u7528\u6237\u767b\u5f55\u4fe1\u606f \u00b6 whoami \uff1a\u5f53\u524d\u767b\u5f55\u7528\u6237 who \uff1a\u7cfb\u7edf\u5f53\u524d\u6240\u6709\u7684\u767b\u5f55\u4f1a\u8bdd w \uff1a\u7cfb\u7edf\u5f53\u524d\u6240\u6709\u7684\u767b\u5f55\u4f1a\u8bdd\u53ca\u6240\u4f5c\u7684\u64cd\u4f5c \u63d0\u793a\uff1a MOTD is the abbreviation of \"Message Of The Day\", and it is used to display a message when a remote user login to the Linux Operating system using SSH. Linux administrators often need to display different messages on the login of the user, like displaying custom information about the server or any necessary information. \u7f16\u8f91\u6587\u4ef6 /etc/motd \u53ef\u4ee5\u81ea\u5b9a\u4e49\"Message Of The Day\"\u7684\u4fe1\u606f\u3002 Ubuntu 2204\u65b0\u5b89\u88c5\u540e\u6ca1\u6709\u8fd9\u4e2a\u6587\u4ef6\uff0c\u9700\u8981\u81ea\u5df1\u521b\u5efa\u3002 openSUSE\u65b0\u5b89\u88c5\u540e\u6709\u9884\u5b9a\u4e49\u7684\u4fe1\u606f\u3002 Rocky9 \u65b0\u5b89\u88c5\u540e\u6709\u8be5\u6587\u4ef6\uff0c\u7a7a\u767d\u6587\u4ef6\u65e0\u5185\u5bb9\u3002 3.11.\u4f1a\u8bdd\u7ba1\u7406\u5de5\u5177 \u00b6 screen \u5de5\u5177 screen -S (Create new screen session) screen -ls (list current screen sessions) screen -x (Attach to existing screeen session, sync between both) screen -r (Reattach existing screen session) tmux \u5de5\u5177 tmux \u662f\u6307 Terminal Multiplexer . \u5b89\u88c5 tmux \u5de5\u5177\u3002 # Rocky sudo yum install tmux # Ubuntu sudo apt install tmux # openSUSE sudo zypper in tmux \u5e38\u7528\u65b9\u6cd5\uff1a tmux new -s (Create new session) tmux detach (Detach current session) tmux ls (list current sessions) tmux attach -t (Reattach existing session) tmux switch -t (Switch to another session) tmux kill-session -t (Kill existing session) tmux list-keys (List all short keys) tmux list-commands (List commands and parameters) tmux info (List all sessions info) tmux split-window (Split window) 3.12. echo \u547d\u4ee4 \u00b6 echo \u547d\u4ee4\u4e2d\u53ef\u4ee5\u8f93\u51fa\u53d8\u91cf\uff0c\u5982\u679c\u53d8\u91cf\u662f\u7528\u662f\u5355\u5f15\u53f7\u5f15\u8d77\u6765\uff0c\u8868\u793a\u8fd9\u4e2a\u53d8\u91cf\u4e0d\u7528IFS\u66ff\u6362\uff01\uff01 echo \"Home=$HOME\" \u7684\u8f93\u51fa\u7ed3\u679c\u662f Home=/home/vagrant echo 'Home=$HOME' \u7684\u8f93\u51fa\u7ed3\u679c\u662f Home=$HOME echo -e \u542f\u7528 \\ \u5b57\u7b26\u7684\u89e3\u91ca\u529f\u80fd\uff0c\u6bd4\u5982\uff1a echo -e \"a\\x0Ab\" \uff0c\u8f93\u51fa\u5b57\u7b26 a \u548c b \uff0c\u4e2d\u95f4 \\x0A \u4ee3\u8868\u5341\u516d\u8fdb\u5236 OA \uff08\u5373\u56de\u8f66\uff09 echo -e \"\\x4A \\x41 \\x4D \\x45 \\x53\" \uff0c\u8f93\u51fa\u7ed3\u679c\u662f J A M E S \u63d0\u793a\uff1a \u4ee5\u901a\u8fc7man 7 ascii\u6765\u67e5\u770b\u5404\u8fdb\u5236\u7684\u542b\u4e49\u3002 echo -e \u8f93\u51fa\u5e26\u989c\u8272\u5b57\u7b26\u3002 \u793a\u4f8b\uff1a echo -e \"\\e[35m \u7d2b\u8272 \\e[0m\" echo -e \"\\e[43m \u9ec4\u5e95 \\e[0m\" echo -e \"\\e[93m \u9ed1\u5e95\u9ec4\u5b57 \\e[0m\" \u53c2\u8003\u4fe1\u606f\uff1a \u5b57\u4f53\u989c\u8272\uff1a \\e[30m \uff1a \u9ed1\u8272 \\e[31m \uff1a \u7ea2\u8272 \\e[32m \uff1a \u7eff\u8272 \\e[33m \uff1a \u9ec4\u8272 \\e[34m \uff1a \u84dd\u8272 \\e[35m \uff1a \u7d2b\u8272 \\e[36m \uff1a \u9752\u8272 \\e[37m \uff1a \u767d\u8272 \\e[40m \uff1a \u9ed1\u5e95 \\e[41m \uff1a \u7ea2\u5e95 \\e[42m \uff1a \u7eff\u5e95 \\e[43m \uff1a \u9ec4\u5e95 \\e[44m \uff1a \u84dd\u5e95 \\e[45m \uff1a \u7d2b\u5e95 \\e[46m \uff1a \u9752\u5e95 \\e[47m \uff1a \u767d\u5e95 \u80cc\u666f\u989c\u8272\uff1a \\e[90m \uff1a \u9ed1\u5e95\u9ed1\u5b57 \\e[91m \uff1a \u9ed1\u5e95\u7ea2\u5b57 \\e[92m \uff1a \u9ed1\u5e95\u7eff\u5b57 \\e[93m \uff1a \u9ed1\u5e95\u9ec4\u5b57 \\e[94m \uff1a \u9ed1\u5e95\u84dd\u5b57 \\e[95m \uff1a \u9ed1\u5e95\u7d2b\u5b57 \\e[96m \uff1a \u9ed1\u5e95\u9752\u5b57 \\e[97m \uff1a \u9ed1\u5e95\u767d\u5b57 \u63a7\u5236\u5c5e\u6027\uff1a \\e[0m \u5173\u95ed\u6240\u6709\u5c5e\u6027 \\e[1m \u8bbe\u7f6e\u9ad8\u4eae\u5ea6 \\e[4m \u4e0b\u5212\u7ebf \\e[5m \u95ea\u70c1 \\e[7m \u53cd\u663e\uff0c\u649e\u8272\u663e\u793a\uff0c\u663e\u793a\u4e3a\u767d\u5b57\u9ed1\u5e95\uff0c\u6216\u8005\u663e\u793a\u4e3a\u9ed1\u5e95\u767d\u5b57 \\e[8m \u6d88\u5f71\uff0c\u5b57\u7b26\u989c\u8272\u5c06\u4f1a\u4e0e\u80cc\u666f\u989c\u8272\u76f8\u540c \\e[nA \u5149\u6807\u4e0a\u79fb n \u884c \\e[nB \u5149\u6807\u4e0b\u79fb n \u884c \\e[nC \u5149\u6807\u53f3\u79fb n \u884c \\e[nD \u5149\u6807\u5de6\u79fb n \u884c \\e[y;xH \u8bbe\u7f6e\u5149\u6807\u4f4d\u7f6e \\e[2J \u6e05\u5c4f \\e[K \u6e05\u9664\u4ece\u5149\u6807\u5230\u884c\u5c3e\u7684\u5185\u5bb9 \\e[s \u4fdd\u5b58\u5149\u6807\u4f4d\u7f6e \\e[u \u6062\u590d\u5149\u6807\u4f4d\u7f6e \\e[?25 \u9690\u85cf\u5149\u6807 \\e[?25h \u663e\u793a\u5149\u6807 3.13. man \u547d\u4ee4 \u00b6 \u5b89\u88c5\u5305\uff1a # openSUSE sudo zypper install man-pages man-pages-zh_CN man-pages-posix # Rocky sudo yum install man-pages # Ubuntu sudo apt install man-db manpages-posix manpages manpages-zh sudo apt install manpages-dev manpages-posix-dev \u66f4\u65b0mandb mandb \u67e5\u627e\u67d0\u4e2a\u547d\u4ee4\u7684man\u4fe1\u606f\uff0c\u4f8b\u5982\u67e5\u627e crontab \u547d\u4ee4\u7684\u4fe1\u606f\u3002 # \u7cbe\u786e\u67e5\u627e man -f crontab whatis crontab # \u6a21\u7cca\u67e5\u8be2 man -k crontab apropos crontab \u8f93\u51fa\u7ed3\u679c\u5982\u4e0b\uff1a crontab (5) - files used to schedule the execution of programs crontab (1) - maintains crontab files for individual users crontab (1p) - schedule periodic background work \u67e5\u627ecrontab\u7b2c5\u7ae0\u7684\u5185\u5bb9\uff0c\u5219\u53ef\u4ee5\u6267\u884c\uff1a man 5 crontab \u5e38\u7528\u5feb\u6377\u952e\u793a\u4f8bs\uff1a 1G : go to the 1 st line 10G : go to the 10 th line G : go to the end of the page /^SELinux : search the word SELinux /section OPTIONS : go to the section OPTIONS 3.14. tr \u547d\u4ee4 \u00b6 tr \u547d\u4ee4\u53ef\u4ee5\u5bf9\u6765\u81ea\u6807\u51c6\u8f93\u5165\u7684\u5b57\u7b26\u8fdb\u884c\u66ff\u6362\u3001\u538b\u7f29\u548c\u5220\u9664\u3002\u5b83\u53ef\u4ee5\u5c06\u4e00\u7ec4\u5b57\u7b26\u53d8\u6210\u53e6\u4e00\u7ec4\u5b57\u7b26\u3002 \u683c\u5f0f\uff1a tr [OPTION]... SET1 [SET2] \u4e3e\u4f8b\uff1a # \u5c06\u8f93\u5165\u5b57\u7b26\u7531\u5927\u5199\u8f6c\u6362\u4e3a\u5c0f\u5199 $ echo \"HELLO WORLD\" | tr 'A-Z' 'a-z' hello world # \u5220\u9664\u51fa\u73b0\u7684\u6570\u5b57 $ echo \"HELLO 1234 WORLD 4567\" | tr -d '0-9' HELLO WORLD # \u4ece\u8f93\u5165\u6587\u672c\u4e2d\u5c06\u4e0d\u5728\u8865\u96c6\u4e2d\u7684\u6240\u6709\u5b57\u7b26\u5220\u9664\uff08\u53ea\u4fdd\u7559\u6570\u5b571\uff0c2\uff0c3\uff0c4\uff0c5\uff09 $ echo \"HELLO 1234 WORLD 4567\" | tr -d -c '1-5' 123445 # \u5c06\u8fde\u7eed\u91cd\u590d\u7684\u5b57\u7b26\u4ee5\u5355\u72ec\u4e00\u4e2a\u5b57\u7b26\u8868\u793a $ echo \"HELLOOO 1222235555555554\" | tr -s 'O215' HELLO 12354 # \u5220\u9664\u7531\u4e8eWindows\u6587\u4ef6\u9020\u6210\u7684'^M'\u5b57\u7b26 $ cat file.txt | tr -s '\\r' '\\n' > new.txt $ cat file.txt | tr -d '\\r' > new.txt # \u5c06\u6362\u884c\u7b26\u66ff\u6362\u6210\u5236\u8868\u7b26 $ cat file.txt | tr '\\n' '\\t' > new.txt # \u5c06\u5927\u5199\u5b57\u6bcd\u8f6c\u6362\u4e3a\u5c0f\u5199\u5b57\u6bcd $ echo \"HELLO 1234 WORLD 4567\" | tr '[:upper:]' '[:lower:]' hello 1234 world 4567 3.15. tee \u547d\u4ee4 \u00b6 tee \u547d\u4ee4\u57fa\u4e8e\u6807\u51c6\u8f93\u5165\u8bfb\u53d6\u6570\u636e\uff0c\u6807\u51c6\u8f93\u51fa\u6216\u6587\u4ef6\u5199\u5165\u6570\u636e\u3002 \u4e3e\u4f8b\uff1a # ping\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u4e0d\u4ec5\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4e5f\u540c\u65f6\u5199\u5165\u6587\u4ef6output.txt\u4e2d\uff08\u8986\u76d6\u5f0f\u5199\u5165\uff09\u3002 $ ping www.baidu.com | tee output.txt # ping\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u4e0d\u4ec5\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4e5f\u540c\u65f6\u5199\u5165\u6587\u4ef6output.txt\u4e2d\uff08\u8ffd\u52a0\u5f0f\u5199\u5165\uff09\u3002 $ ping www.baidu.com | tee -a output.txt # ping\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u4e0d\u4ec5\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4e5f\u540c\u65f6\u5199\u5165\u591a\u4e2a\u6587\u4ef6\u4e2d\uff08\u8986\u76d6\u5f0f\u5199\u5165\uff09\u3002 $ ping www.baidu.com | tee output1.txt output2.txt output3.txt # ls\u547d\u4ee4\u7684\u8f93\u51fa\u5199\u5165\u6587\u4ef6output.txt\u4e2d\uff0c\u5e76\u4f5c\u4e3awc\u547d\u4ee4\u7684\u8f93\u5165\u3002 $ ls *.txt | tee output.txt | wc -l 4 # cat output.txt f1.txt f2.txt output.txt test.txt \u6280\u5de7\uff1a \u5728vi\u4f7f\u7528\u4e2d\uff0c\u901a\u8fc7 tee \u547d\u4ee4\u63d0\u5347\u6587\u4ef6\u5199\u5165\u6743\u9650\u3002 \u6bd4\u5982\u975eroot\u7528\u6237\u6267\u884c vi /etc/hosts \uff0c\u5728vi\u4e2d\u4f7f\u7528 :w !sudo tee % \u53ef\u4ee5\u63d0\u9ad8\u6743\u9650\u4fdd\u5b58\u8fd9\u4e2a\u6587\u4ef6\u3002 3.16.\u8bed\u8a00\u73af\u5883LANG \u00b6 \u5b89\u88c5\u8bed\u8a00\u5305\u3002 # Ubuntu sudo apt install locales-all # Rocky sudo yum install glibc-langpack-zh.x86_64 # openSUSE sudo zypper install glibc-locale glibc-locale-32bit glibc-locale-base \u67e5\u770b\u5f53\u524d\u8bed\u8a00\u8bbe\u7f6e\uff1a echo $LANG locale -a locale -k LC_TIME localectl status localectl list-locales \u5168\u5c40locale\u914d\u7f6e(Global locale settings)\u3002 # openSUSE & Rocky sudo cat /etc/locale.conf # Ubuntu sudo cat /etc/default/locale \u4e34\u65f6\u4fee\u6539\u5f53\u524dsession\u7684locale\u3002 LANG = \"zh_CN.utf8\" \u6c38\u4e45\u4fee\u6539locale\u8bbe\u7f6e\u3002 sudo localectl set-locale LANG = zh_CN.utf8 \u4fee\u6539\u56de\u539f\u8bbe\u7f6e\u3002 sudo localectl set-locale LANG = en_US.utf8 Tips: Mac OS ssh\u767b\u9646Linux\u662f\u7ec8\u7aef\u63d0\u793a /usr/bin/manpath: can't set the locale; make sure $LC_* and $LANG are correct \u89e3\u51b3\u65b9\u6cd5\uff1a\u5728\u672c\u5730mac\u7535\u8111\u4e0a\u4fee\u6539/etc/ssh/ssh_config\u6216\u8005/etc/ssh/ssh_config\u6587\u4ef6\uff0c\u5220\u9664\u6389\u6216\u8005\u6ce8\u91ca\u6389\u8fd9\u4e00\u884c\u914d\u7f6e\u5185\u5bb9 # SendEnv LANG LC_* \u3002 \u5982\u679c\u4f7f\u7528\u7684\u662f Iterm2 \uff0c\u53ef\u4ee5\u6253\u5f00 iterm2 \u7684 preferences -> Profiles -> Terminal \u83dc\u5355\u91cc\u5173\u95ed Set locale variables automatically \u9009\u9879\u3002 3.17.\u7b26\u53f7 $ \u7528\u6cd5 \u00b6 \u7b26\u53f7 $ \u7684\u7528\u6cd5\uff1a $ \uff0c\u83b7\u53d6\u53d8\u96f6\u503c\u3002 x = 1 echo $x echo \" $x \" \u5efa\u8bae\u4f7f\u7528\"$x\"\uff0c\u4ee5\u907f\u514dshell\u7f16\u7a0b\u4e2d\u4ea7\u751f\u6b67\u4e49\u3002\u5982\u4e0b\u4f8b\uff1a s = \"this is a string\" echo $s echo \"this is a string\" \u6267\u884c [ $s == \"this is a string\" ] \u4f1a\u62a5\u9519\uff0c\u8fd9\u662f\u5b9e\u9645\u751f\u6210\u7684\u6bd4\u8f83\u5f0f this is a string == \"this is a string\" \u3002 \u6211\u4eec\u9884\u671f\u7684\u662f \"this is a string\" == \"this is a string\" \uff0c\u6240\u4ee5\u9700\u8981\u6539\u6210 [ \"$s\" == \"this is a string\" ] \u3002 $0 , $1 , $n , $# \uff1a \u751f\u6210\u4e00\u4e2a\u6d4b\u8bd5\u811a\u672c\u3002 echo 'echo $0 $1 $2 $#' > test.sh chmod 755 test.sh \u9a8c\u8bc1\u5404\u4e2a\u53c2\u6570\u4f4d\u7f6e\u3002 ./test.sh a b c d e \u8f93\u51fa\u7ed3\u679c\uff1a ./test.sh a b 5 \u7ed3\u8bba\uff1a $0 \u8f93\u51fa\u811a\u672c\u6587\u4ef6\u540d\uff1b $1 \u8f93\u51fa\u7b2c\u4e00\u4e2a\u53c2\u6570\uff1b $2 \u8f93\u51fa\u7b2c\u4e8c\u4e2a\u53c2\u6570\uff1b $# \u8f93\u51fa\u53c2\u6570\u4e2a\u6570\u3002 ${} ${} \u7528\u4e8e\u533a\u5206\u53d8\u91cf\u7684\u8fb9\u754c\u3002 \u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c $abc \u65e0\u7ed3\u679c\u8f93\u51fa\uff0c ${a}bc \u8f93\u51fa\u7ed3\u679c stringbc \uff0c\u901a\u8fc7{}\u6307\u5b9a\u4e86\u67d0\u4e2a\u5b57\u7b26\u5c5e\u4e8e\u53d8\u91cf\u3002 a = \"string\" echo ${ a } bc echo $abc ${#} ${#} \u662f\u8fd4\u56de\u53d8\u91cf\u503c\u7684\u957f\u5ea6\u3002 s = 'this is a string' echo \" $s \" echo \" ${# s } \" \u547d\u4ee4 echo \"${#s}\" \u8f93\u51fa\u7ed3\u679c\u662f\u5b57\u4e32 this is a string \u7684\u957f\u5ea6 16 \u3002 $? $? \u662f\u8fd4\u56de\u4e0a\u4e00\u547d\u4ee4\u662f\u5426\u6210\u529f\u7684\u72b6\u6001\uff0c 0 \u4ee3\u8868\u6210\u529f\uff0c\u975e\u96f6\u4ee3\u8868\u5931\u8d25\u3002 ls \u662f\u4e00\u4e2a\u547d\u4ee4\uff0c\u6240\u4ee5\u8fd4\u56de\u503c\u662f 0 \u3002 tom \u662f\u4e00\u4e2a\u4e0d\u5b58\u5728\u7684\u547d\u4ee4\uff0c\u5219\u8fd4\u56de 127 \u3002 ls echo $? tom echo $? $() $() \u7b49\u540c\u4e8e\u53cd\u5f15\u53f7\u3002 echo $(ls) \u7b49\u540c\u4e8e\u6267\u884c ls \u547d\u4ee4\u3002 $() \u7684\u5f0a\u7aef\u662f\uff0c\u4e0d\u662f\u6240\u6709\u7684\u7c7bunix\u7cfb\u7edf\u90fd\u652f\u6301\uff0c\u53cd\u5f15\u53f7\u662f\u80af\u5b9a\u652f\u6301\u7684\u3002 $() \u7684\u4f18\u52bf\u662f\u76f4\u89c2\uff0c\u5728\u8f6c\u79fb\u5904\u7406\u65f6\uff0c\u6bd4\u53cd\u5f15\u53f7\u76f4\u89c2\u5bb9\u6613\u4e9b\u3002 echo $( ls ) # test.sh echo $( cat $( ls )) # echo $0 $1 $2 $# \u4e0a\u8ff0\u5d4c\u5957\u683c\u5f0f\u4e2d\uff0cls\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u662fcat\u547d\u4ee4\u7684\u8f93\u5165\uff0c\u53ef\u4ee5\u8fdb\u884c\u591a\u5c42\u5d4c\u5957\uff0c\u5185\u5c42\u547d\u4ee4\u7684\u8f93\u51fa\u662f\u5916\u5c42\u547d\u4ee4\u7684\u8f93\u5165\u3002 $[] $[] \u662f\u8868\u8fbe\u5f0f\u8ba1\u7b97\u3002 echo $ [ 3 + 2 ] $- $- \u663e\u793ashell\u5f53\u524d\u6240\u4f7f\u7528\u7684\u9009\u9879\u3002 \u6267\u884c echo $- \uff0c\u8f93\u51fa\u7ed3\u679c himBHs \u3002himBH\u6bcf\u4e00\u4e2a\u5b57\u7b26\u662f\u4e00\u4e2ashell\u7684\u9009\u9879\u3002 $! $! \u83b7\u53d6\u6700\u540e\u4e00\u4e2a\u8fd0\u884c\u7684\u540e\u53f0\u8fdb\u7a0b\u7684pid\u3002 \u6bd4\u5982\u6267\u884c cat test.sh & \uff0c\u7ed3\u679c\u4e2d\u4f1a\u5305\u542b\u4e00\u4e2apid\u53f7\uff0c\u9a6c\u4e0a\u7740\u6267\u884c echo $! \uff0c\u5982\u679c2\u4e2a\u547d\u4ee4\u95f4\u9694\u4e4b\u95f4\u6ca1\u6709\u5176\u4ed6\u540e\u53f0\u8fdb\u7a0b\u6267\u884c\uff0c\u5219\u53ef\u4ee5\u5f97\u5230\u548c\u524d\u9762\u4e00\u81f4\u7684pid\u53f7\u3002 !$ !$ \u8fd4\u56de\u4e0a\u4e00\u6761\u547d\u4ee4\u7684\u6700\u540e\u4e00\u4e2a\u53c2\u6570\u3002 \u6267\u884c ./test.sh a b c iamhere \uff0c\u5f97\u5230\u7ed3\u679c ./test.sh a b 4 \u3002 \u6267\u884c echo !$ \uff0c\u5f97\u52302\u4e2a\u7ed3\u679c\uff0c echo iamhere \u548c iamhere \u3002 !! !! \u8f93\u51fa\u4e0a\u4e00\u6761\u547d\u4ee4\uff0c\u5e76\u6267\u884c\u3002 !! \u4f1a\u5148\u8f93\u51fa\u4e0a\u4e00\u6761\u547d\u4ee4 cat test.sh \uff0c\u7136\u540e\u518d\u6267\u884c\u8fd9\u6761\u547d\u4ee4\uff0c\u7b2c\u4e8c\u884c\u5373\u6267\u884c\u7ed3\u679c\u3002 [ vagrant@lizard:~ ] $ cat test.sh echo $0 $1 $2 $# [ vagrant@lizard:~ ] $ !! cat test.sh echo $0 $1 $2 $# $$ $$ \u8f93\u51fa\u5f53\u524d\u8fdb\u7a0b\u7684pid\u3002 echo $$ $@ & $* $@ \u548c $* \u662f\u5bf9\u4f20\u5165\u53c2\u6570\u7684\u4e0d\u540c\u4f53\u73b0\uff0c $@ \u662f\u4ee5\u53d8\u91cf\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff0c $* \u662f\u4ee5\u6570\u7ec4\u7684\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\u3002 \u521b\u5efa\u4e00\u4e2a\u6587\u4ef6 script.sh \u5305\u542b\u4e0b\u9762\u7684\u811a\u672c\u3002\u5e76\u6dfb\u52a0\u6267\u884c\u6743\u9650 chmod 755 script.sh \u3002 echo '$@\u4ee5\u53d8\u91cf\u65b9\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a' for x in \" $@ \" do echo $x done echo '$*\u4ee5\u6570\u7ec4\u7684\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a' for x in \" $* \" do echo $x done \u8f93\u51fa\u7ed3\u679c\uff1a $@ \u4ee5\u53d8\u91cf\u65b9\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a a b 3 5 d $* \u4ee5\u6570\u7ec4\u7684\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a a b 3 5 d","title":"\u7b2c\u4e00\u7ae0 Linux\u57fa\u7840"},{"location":"linux/SRE/01-fundamentals/#linux","text":"","title":"\u7b2c\u4e00\u7ae0 Linux\u57fa\u7840"},{"location":"linux/SRE/01-fundamentals/#1","text":"Rocky Linux Instructional Books openSUSE Documentation Ubuntu Documentation","title":"1.\u5b98\u65b9\u6587\u6863"},{"location":"linux/SRE/01-fundamentals/#2","text":"","title":"2.\u7cfb\u7edf\u73af\u5883"},{"location":"linux/SRE/01-fundamentals/#21rocky","text":"\u4f7f\u7528\u7248\u672c\uff1a Rocky 9.0 \u3002 \u4ece\u7f51\u7ad9\u4e0b\u8f7dRocky\u7cfb\u7edf ISO\u955c\u50cf \uff0c\u6216\u8005\u901a\u8fc7 wget \u547d\u4ee4\u4e0b\u8f7dRocky\u7cfb\u7edfISO\u955c\u50cf\u3002 wget https://download.rockylinux.org/pub/rocky/9.0/isos/x86_64/Rocky-9.0-x86_64-dvd.iso \u5b89\u88c5\u65f6\u6211\u9009\u62e9\u4e86\u6fc0\u6d3b root \u7528\u6237\uff0c\u9009\u62e9\u4e86Server\u6a21\u5f0f\u5b89\u88c5\uff08\u6ca1\u6709GUI\uff09\u3002 \u4ee5 root \u767b\u5f55\uff0c\u6267\u884c\u4e0b\u9762\u547d\u4ee4\u4fee\u6539 sudo \u6743\u9650\u3002 visudo \u5e76\u6fc0\u6d3b\u4e0b\u9762\u4e00\u884c\uff08\u4e0d\u8bbe\u5bc6\u7801\uff0c\u65b9\u4fbf\u7ec3\u4e60\uff09\uff1a %wheel ALL =( ALL ) NOPASSWD: ALL \u521b\u5efa\u7528\u6237 vagrant \uff0c\u5e76\u8bbe\u7f6e wheel \u4e3a\u4e3b\u8981\u7ec4\u548c\u4fee\u6539\u5bc6\u7801\u3002 adduser vagrant usermod -g wheel vagrant passwd vagrant \u8bbe\u5b9ahostname\uff08\u5305\u62ec\u522b\u540d\uff09\uff0c\u5e76\u67e5\u770b\u7ed3\u679c\u3002 hostnamectl set-hostname --static \"rocky9\" hostnamectl set-hostname --pretty \"rocky9\" hostnamectl cat /etc/hostname \u5c0f\u8d34\u58eb\uff1a \u7531systemd\u63a7\u5236\u7684\u4e3b\u673a\u540d\u7684\u670d\u52a1\u914d\u7f6e\u4fe1\u606f\uff1a /usr/lib/systemd/system/systemd-hostnamed.service Rocky\u7684\u8f6f\u4ef6\u6e90\u7684\u914d\u7f6e\u4fe1\u606f\u4fdd\u5b58\u5728\u76ee\u5f55 /etc/yum.repos.d/ \u4e0b\u3002\u5982\u679c\u8bbf\u95ee\u9ed8\u8ba4\u6e90\u6bd4\u8f83\u6162\uff0c\u53ef\u4ee5\u66f4\u65b0\u963f\u91cc\u6e90\u6216\u8005\u79d1\u5927\u6e90\u3002 \u66f4\u6362\u963f\u91cc\u6e90\u3002 sed -e 's|^mirrorlist=|#mirrorlist=|g' \\ -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \\ -i.bak \\ /etc/yum.repos.d/Rocky-*.repo \u66f4\u6362\u79d1\u5927\u6e90\u3002 sed -e 's|^mirrorlist=|#mirrorlist=|g' \\ -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.ustc.edu.cn/rocky|g' \\ -i.bak \\ /etc/yum.repos.d/rocky-extras.repo \\ /etc/yum.repos.d/rocky.repo \u5237\u65b0\u7f13\u5b58\u3002 dnf makecache","title":"2.1.Rocky"},{"location":"linux/SRE/01-fundamentals/#22ubuntu","text":"\u4f7f\u7528\u7248\u672c\uff1a Ubuntu 2204 \u3002 \u8bbe\u5b9aroot\u7528\u6237\u7684\u5bc6\u7801\u3002 sudo passwd root \u901a\u8fc7\u5b89\u88c5\u65f6\u5df2\u521b\u5efa\u7684\u7528\u6237 vagrant \u767b\u5f55\u3002\u6267\u884c\u4e0b\u9762\u547d\u4ee4\u4fee\u6539 sudo \u6743\u9650\u3002 sudo visudo \u6dfb\u52a0 vagrant \u5230\u7279\u6743\u7528\u6237\uff08Rocky\u548copenSUSE\u4e0d\u9700\u8981\u6dfb\u52a0\uff09\uff0c\u5e76\u6fc0\u6d3bsudo\u4e00\u884c\uff08\u4e0d\u8bbe\u5bc6\u7801\uff0c\u65b9\u4fbf\u7ec3\u4e60\uff09\uff1a # User privilege specification root ALL =( ALL:ALL ) ALL vagrant ALL =( ALL:ALL ) ALL # Allow members of group sudo to execute any command sudo ALL =( ALL:ALL ) NOPASSWD: ALL \u4fee\u6539\u7528\u6237 vagrant \u7684\u4e3b\u8981\u7ec4\u4e3a sudo \u3002 sudo usermod -g sudo vagrant \u4fee\u6539\u4e3b\u673a\u540d\u548c\u522b\u540d\u3002 sudo hostnamectl set-hostname ubuntu2204 sudo hostnamectl set-hostname ubuntu2204 --pretty \u5c0f\u8d34\u58eb\uff1a \u5982\u4f55\u5904\u7406 Username is not in the sudoers file. This incident will be reported \u95ee\u9898\u3002 \u5982\u679c\u6ca1\u6709\u521d\u59cb\u5316 root \u7528\u6237\u7684\u5bc6\u7801\uff0c\u4e14\u5f53\u524d\u7528\u6237\u4e5f\u65e0\u6cd5\u6267\u884c sudo \u547d\u4ee4\uff0c\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u6b65\u9aa4\u901a\u8fc7recovery\u6551\u63f4\u6a21\u5f0f\u8fdb\u884c\u6062\u590d\u3002 \u6309 shift \u952e\u5f00\u673a\uff0c\u8fdb\u5165grub\u542f\u52a8\u83dc\u5355\u3002\uff08VMWare\u4e5f\u9002\u7528\uff09 \u5411\u4e0b\u79fb\u52a8\u9ad8\u4eae\u6761\uff0c\u9009\u62e9\u83dc\u5355 Advanced options for Ubuntu \uff0c\u5e76\u786e\u8ba4\u56de\u8f66\u3002 \u9009\u62e9\u5e26\u6709 recovery mode \u7684\u5185\u6838\uff0c\u786e\u8ba4\u56de\u8f66\u3002 \u5411\u4e0b\u79fb\u52a8\u9ad8\u4eae\u6761\uff0c\u9009\u62e9\u83dc\u5355 root Drop to root shell prompt \uff0c\u5e76\u786e\u8ba4\u56de\u8f66\u3002 \u56de\u8f66\u786e\u8ba4 press Enter for maintenance \u3002 \u51fa\u73b0 root \u7684\u547d\u4ee4\u63d0\u793a\u7b26\u540e\uff0c\u6267\u884c\u547d\u4ee4 mount -o rw,remount / \u3002 \u6267\u884c\u547d\u4ee4 passwd \u7ed9 root \u8bbe\u5b9a\u5bc6\u7801\u3002 \u6267\u884c\u547d\u4ee4 adduser username sudo \u628a\u6307\u5b9a\u7528\u6237\u52a0\u5165 sudo \u7ec4\u3002 \u6267\u884c\u547d\u4ee4 visudo \u8fdb\u884c\u5fc5\u8981\u7684\u4fee\u6b63\u6216\u4fee\u6539\u3002","title":"2.2.Ubuntu"},{"location":"linux/SRE/01-fundamentals/#23opensuse","text":"\u4f7f\u7528\u7248\u672c\uff1a Leap 15.4 \u3002 \u9009\u62e9\u670d\u52a1\u5668\u6a21\u5f0f\u5b89\u88c5\uff0c\u65e0\u56fe\u5f62\u754c\u9762\u3002\u5b89\u88c5\u4e2d\u4e0d\u521b\u5efa\u7528\u6237\u3002 \u521b\u5efa\u7528\u6237 vagrant \uff0c\u5e76\u8bbe\u7f6e wheel \u4e3a\u4e3b\u8981\u7ec4\u3002 useradd -m -g wheel -G root -c \"vagrant\" vagrant passwd vagrant \u6267\u884c visudo \u547d\u4ee4\uff0c\u6fc0\u6d3b\u4e0b\u9762\u4e00\u884c\uff0c\u6dfb\u52a0 sudo \u6743\u9650\u3002 % wheel ALL =( ALL ) NOPASSWD: ALL \u4fee\u6539\u4e3b\u673a\u540d\u548c\u522b\u540d\u3002 sudo hostnamectl set-hostname lizard sudo hostnamectl set-hostname lizard --pretty","title":"2.3.openSUSE"},{"location":"linux/SRE/01-fundamentals/#3","text":"\u8bf4\u660e\uff1a \u9ed8\u8ba4\u5f53\u524d\u64cd\u4f5c\u7528\u6237\u4e3a vagrant \u3002","title":"3.\u5e38\u7528\u547d\u4ee4"},{"location":"linux/SRE/01-fundamentals/#31","text":"\u6267\u884c\u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u770b\u5230\u5f53\u524d\u7cfb\u7edf\u7684\u547d\u4ee4\u63d0\u793a\u7b26\u683c\u5f0f\u3002 echo $PS1 \u5404\u7cfb\u7edf\u9ed8\u8ba4\u8bbe\u7f6e\u662f\u6709\u5dee\u5f02\u7684\u3002 # Rocky [ \\u @ \\h \\W ] \\$ # Ubuntu \\[\\e ] 0 ; \\u @ \\h : \\w\\a\\] ${ debian_chroot :+( $debian_chroot ) } \\[\\0 33 [ 01 ; 32m \\]\\u @ \\h\\[\\0 33 [ 00m \\] : \\[\\0 33 [ 01 ; 34m \\]\\w\\[\\0 33 [ 00m \\]\\$ # openSUSE \\u @ \\h : \\w > \u5c0f\u8d34\u58eb\uff1a bash\u53ef\u8bc6\u522b\u7684\u8f6c\u4e49\u5e8f\u5217\u6709\u4e0b\u9762\u8fd9\u4e9b\uff1a \\u : \u5f53\u524d\u7528\u6237\u7684\u8d26\u53f7\u540d\u79f0 \\h : \u4e3b\u673a\u540d\u7b2c\u4e00\u90e8\u5206 \\H : \u5b8c\u6574\u7684\u4e3b\u673a\u540d\u79f0 \\w : \u5b8c\u6574\u7684\u5de5\u4f5c\u76ee\u5f55\u540d\u79f0\uff08\u5982 \"/home/username/mywork\"\uff09 \\W : \u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u7684\"\u57fa\u540d (basename)\"\uff08\u5982 \"mywork\") \\t : \u663e\u793a\u65f6\u95f4\u4e3a24\u5c0f\u65f6\u683c\u5f0f\uff0c\u5982\uff1aHH:MM:SS \\T : \u663e\u793a\u65f6\u95f4\u4e3a12\u5c0f\u65f6\u683c\u5f0f \\A : \u663e\u793a\u65f6\u95f4\u4e3a24\u5c0f\u65f6\u683c\u5f0f\uff1aHH:MM \\@ : \u5e26\u6709 am/pm \u7684 12 \u5c0f\u65f6\u5236\u65f6\u95f4 \\d : \u4ee3\u8868\u65e5\u671f\uff0c\u683c\u5f0f\u4e3aweekday month date\uff0c\u4f8b\u5982\uff1a\"Mon Aug 1\" \\s : shell \u7684\u540d\u79f0\uff08\u5982 \"bash\") \\v : bash\u7684\u7248\u672c\uff08\u5982 2.04\uff09 \\V : bash\u7684\u7248\u672c\uff08\u5305\u62ec\u8865\u4e01\u7ea7\u522b\uff09 \\n : \u6362\u884c\u7b26 \\r : \u56de\u8f66\u7b26 \\\\ : \u53cd\u659c\u6760 \\a : ASCII \u54cd\u94c3\u5b57\u7b26\uff08\u4e5f\u53ef\u4ee5\u952e\u5165 07 \uff09 \\e : ASCII \u8f6c\u4e49\u5b57\u7b26\uff08\u4e5f\u53ef\u4ee5\u952e\u5165 33 ) \\[ : \u8fd9\u4e2a\u5e8f\u5217\u5e94\u8be5\u51fa\u73b0\u5728\u4e0d\u79fb\u52a8\u5149\u6807\u7684\u5b57\u7b26\u5e8f\u5217\uff08\u5982\u989c\u8272\u8f6c\u4e49\u5e8f\u5217\uff09\u4e4b\u524d\u3002\u5b83\u4f7fbash\u80fd\u591f\u6b63\u786e\u8ba1\u7b97\u81ea\u52a8\u6362\u884c \\] : \u8fd9\u4e2a\u5e8f\u5217\u5e94\u8be5\u51fa\u73b0\u5728\u975e\u6253\u5370\u5b57\u7b26\u5e8f\u5217\u4e4b\u540e \\# : \u4e0b\u8fbe\u7684\u7b2c\u51e0\u4e2a\u547d\u4ee4 \\$ : \u63d0\u793a\u5b57\u7b26\uff0c\u5982\u679c\u662froot\u7528\u6237\uff0c\u63d0\u793a\u7b26\u4e3a # \uff0c\u666e\u901a\u7528\u6237\u5219\u4e3a $ \u5728PS1\u4e2d\u8bbe\u7f6e\u5b57\u7b26\u989c\u8272\u7684\u683c\u5f0f\u4e3a\uff1a [\\e[F;Bm]........[\\e[0m] \uff0c\u5176\u4e2d [\\e[0m] \u4f5c\u4e3a\u989c\u8272\u8bbe\u5b9a\u7684\u7ed3\u675f\u3002 \u5176\u4e2d\"F\"\u4e3a\u5b57\u4f53\u989c\u8272\uff0c\u7f16\u53f7\u4e3a30-37\uff0c\"B\"\u4e3a\u80cc\u666f\u989c\u8272\uff0c\u7f16\u53f7\u4e3a40-47\u3002 \u5c0f\u8d34\u58eb\uff1a \u989c\u8272\u5bf9\u7167\u8868: F:30 , B:40 : \u9ed1\u8272 F:31 , B:41 : \u7ea2\u8272 F:32 , B:42 : \u7eff\u8272 F:33 , B:43 : \u9ec4\u8272 F:34 , B:44 : \u84dd\u8272 F:35 , B:45 : \u7d2b\u7ea2\u8272 F:36 , B:46 : \u9752\u84dd\u8272 F:37 , B:47 : \u767d\u8272 \u4ee5\u4e0b\u9762\u7684PS1\u8bbe\u5b9a\u4e3a\u4f8b\u8bf4\u660e\u989c\u8272\u8bbe\u5b9a\u3002 PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[37;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" \u62c6\u89e3\u5206\u6790\uff1a PS1=\" \\[\\e[37;40m\\] # \u6574\u4e2a\u63d0\u793a\u7b26\u533a\u57df\u524d\u666f\u767d\u8272\uff0c\u80cc\u666f\u9ed1\u8272 [ # \u663e\u793a\u5b57\u7b26[ \\[\\e[32;40m\\] # \u4fee\u9970\u540e\u9762\u7684\\u\uff0c\u524d\u666f\u7eff\u8272\uff0c\u80cc\u666f\u9ed1\u8272 \\u # \u663e\u793a\u5f53\u524d\u7528\u6237\u7684\u8d26\u53f7\u540d\u79f0 \\[\\e[37;40m\\] # \u4fee\u9970\u540e\u9762\u7684\u5b57\u7b26@\u548c\u4e3b\u673a\u540d @ # \u663e\u793a\u5b57\u7b26@ \\h # \u663e\u793a\u4e3b\u673a\u540d : # \u663e\u793a\u5b57\u7b26: \\[\\e[36;40m\\] # \u4fee\u9970\u540e\u9762\u7684\\w\uff0c\u524d\u666f\u9752\u84dd\u8272\uff0c\u80cc\u666f\u9ed1\u8272 \\w # \u663e\u793a\u5b8c\u6574\u5de5\u4f5c\u76ee\u5f55 \\[\\e[0m\\] # \u7ed3\u675f\u989c\u8272\u8bbe\u5b9a ] # \u663e\u793a\u5b57\u7b26] \\$\" # \u5982\u679c\u662froot\u7528\u6237\uff0c\u63d0\u793a\u7b26\u4e3a# \uff0c\u666e\u901a\u7528\u6237\u5219\u4e3a$ \u5bf9\u4e0d\u540c\u4e3b\u673a\u505a\u4e0d\u540c\u8bbe\u7f6e\uff1a # Rocky PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[37;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" # Ubuntu PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[33;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" # openSUSE PS1 = \"\\[\\e[37;40m\\][\\[\\e[32;40m\\]\\u\\[\\e[35;40m\\]@\\h:\\[\\e[36;40m\\]\\w\\[\\e[0m\\]]\\$ \" \u5c06\u4e0a\u8ff0PS1\u7684\u8bbe\u5b9a\uff0c\u8ffd\u52a0\u5230\u5f53\u524d\u7528\u6237\u7684 ~/.bashrc \u6587\u4ef6\u672b\u5c3e\uff0c\u4ee5\u5b9e\u73b0\u5bf9\u5f53\u524d\u7528\u6237\u7684\u63d0\u793a\u7b26\u98ce\u683c\u505a\u6301\u4e45\u4fdd\u5b58\u3002","title":"3.1.\u4fee\u6539\u63d0\u793a\u7b26\u98ce\u683c"},{"location":"linux/SRE/01-fundamentals/#32linux","text":"\u5185\u90e8\u547d\u4ee4 (internal command)\u5b9e\u9645\u4e0a\u662fshell\u7a0b\u5e8f\u7684\u4e00\u90e8\u5206\uff0c\u5305\u542b\u7684\u662f\u4e00\u4e9b\u6bd4\u8f83\u7b80\u5355\u7684linux\u7cfb\u7edf\u547d\u4ee4\uff0c\u8fd9\u4e9b\u547d\u4ee4\u7531shell\u7a0b\u5e8f\u8bc6\u522b\u5e76\u5728shell\u7a0b\u5e8f\u5185\u90e8\u5b8c\u6210\u8fd0\u884c\uff0c\u901a\u5e38\u5728linux\u7cfb\u7edf\u52a0\u8f7d\u8fd0\u884c\u65f6shell\u5c31\u88ab\u52a0\u8f7d\u5e76\u9a7b\u7559\u5728\u7cfb\u7edf\u5185\u5b58\u4e2d\u3002 \u5916\u90e8\u547d\u4ee4 (external command)\u662flinux\u7cfb\u7edf\u4e2d\u7684\u5b9e\u7528\u7a0b\u5e8f\u90e8\u5206\uff0c\u7cfb\u7edf\u52a0\u8f7d\u65f6\u5e76\u4e0d\u968f\u7cfb\u7edf\u4e00\u8d77\u88ab\u52a0\u8f7d\u5230\u5185\u5b58\u4e2d\uff0c\u800c\u662f\u5728\u9700\u8981\u65f6\u624d\u5c06\u5176\u8c03\u7528\u5185\u5b58\u3002\u901a\u5e38\u5916\u90e8\u547d\u4ee4\u7684\u5b9e\u4f53\u5e76\u4e0d\u5305\u542b\u5728shell\u4e2d\uff0c\u4f46\u662f\u5176\u547d\u4ee4\u6267\u884c\u8fc7\u7a0b\u662f\u7531shell\u7a0b\u5e8f\u63a7\u5236\u7684\u3002 \u6bd4\u5982\uff1a \u6267\u884c\u547d\u4ee4 type -t cp \uff0c\u7cfb\u7edf\u8fd4\u56de\u7ed3\u679c\u662f file \uff0c\u5916\u90e8\u547d\u4ee4\u3002 \u6267\u884c\u547d\u4ee4 type -t cd \uff0c\u7cfb\u7edf\u8fd4\u56de\u7ed3\u679c builtin \uff0c\u5185\u90e8\u547d\u4ee4\u3002 \u6267\u884c\u547d\u4ee4 enable -a cp \uff0c\u7cfb\u7edf\u8fd4\u56de -bash: enable: cp: not a shell builtin \uff0c\u4e5f\u53ef\u4ee5\u5224\u65ad\u662f\u5426\u4e3a\u5185\u90e8\u547d\u4ee4\u3002 \u5bf9\u4e8e\u5185\u90e8\u547d\u4ee4\uff0c\u53ef\u4ee5\u901a\u8fc7enable\u547d\u4ee4\u6765\u542f\u7528\u6216\u8005\u7981\u7528\u3002 # \u7981\u7528cd\u547d\u4ee4 enable -n cd # \u67e5\u770b\u6240\u6709\u88ab\u7981\u7528\u7684\u547d\u4ee4 enable -n # \u542f\u7528cd\u547d\u4ee4 enable cd \u5bf9\u4e8e\u547d\u4ee4\uff0c\u53ef\u4ee5\u901a\u8fc7 whereis \u547d\u4ee4\u6765\u67e5\u770b\u8def\u5f84\u3002 whereis cp whereis cd","title":"3.2.Linux\u7684\u5185\u5916\u90e8\u547d\u4ee4"},{"location":"linux/SRE/01-fundamentals/#33cpu","text":"lscpu cat /proc/cpuinfo","title":"3.3.CPU\u4fe1\u606f"},{"location":"linux/SRE/01-fundamentals/#34","text":"free cat /proc/meminfo","title":"3.4.\u5185\u5b58\u4f7f\u7528\u72b6\u6001"},{"location":"linux/SRE/01-fundamentals/#35","text":"lsblk openSUSE\u5728VMWare\u9ed8\u8ba4\u5b89\u88c5\u7684\u72b6\u6001\uff1a NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8 :0 0 200G 0 disk \u251c\u2500sda1 8 :1 0 8M 0 part \u251c\u2500sda2 8 :2 0 198G 0 part /home \u2502 /var \u2502 /opt \u2502 /usr/local \u2502 /root \u2502 /tmp \u2502 /srv \u2502 /boot/grub2/x86_64-efi \u2502 /boot/grub2/i386-pc \u2502 /.snapshots \u2502 / \u2514\u2500sda3 8 :3 0 2G 0 part [ SWAP ] sr0 11 :0 1 3 .8G 0 rom Ubuntu\u5728VMWare\u9ed8\u8ba4\u5b89\u88c5\u7684\u72b6\u6001\uff1a NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 7 :0 0 61 .9M 1 loop /snap/core20/1405 loop1 7 :1 0 63 .2M 1 loop /snap/core20/1623 loop2 7 :2 0 79 .9M 1 loop /snap/lxd/22923 loop3 7 :3 0 48M 1 loop /snap/snapd/17029 loop4 7 :4 0 103M 1 loop /snap/lxd/23541 loop5 7 :5 0 48M 1 loop /snap/snapd/17336 sda 8 :0 0 50G 0 disk \u251c\u2500sda1 8 :1 0 1M 0 part \u251c\u2500sda2 8 :2 0 2G 0 part /boot \u2514\u2500sda3 8 :3 0 48G 0 part \u2514\u2500ubuntu--vg-ubuntu--lv 253 :0 0 24G 0 lvm / sr0 11 :0 1 1 .4G 0 rom Rocky\u5728VMWare\u9ed8\u8ba4\u5b89\u88c5\u7684\u72b6\u6001\uff1a NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8 :0 0 50G 0 disk \u251c\u2500sda1 8 :1 0 1G 0 part /boot \u2514\u2500sda2 8 :2 0 49G 0 part \u251c\u2500rl-root 253 :0 0 45 .1G 0 lvm / \u2514\u2500rl-swap 253 :1 0 3 .9G 0 lvm [ SWAP ] sr0 11 :0 1 7 .9G 0 rom","title":"3.5.\u786c\u76d8\u548c\u5206\u533a\u60c5\u51b5"},{"location":"linux/SRE/01-fundamentals/#36","text":"arch openSUSE\uff0cUbuntu\u548cRocky\u7684\u8fd4\u56de\u7ed3\u679c\u90fd\u662f x86_64 \u3002","title":"3.6.\u7cfb\u7edf\u67b6\u6784\u4fe1\u606f"},{"location":"linux/SRE/01-fundamentals/#37","text":"uname -r \u4e09\u4e2a\u53d1\u884c\u7248\u8fd4\u56de\u7684\u7ed3\u679c\u4e0d\u5c3d\u76f8\u540c\uff1a # openSUSE 5 .14.21-150400.24.21-default # Ubuntu 5 .15.0-52-generic # Rocky 5 .14.0-70.17.1.el9_0.x86_64","title":"3.7.\u5185\u6838\u7248\u672c"},{"location":"linux/SRE/01-fundamentals/#38","text":"cat /etc/os-release cat /etc/issue # Rocky 9 sudo cat /etc/redhat-release lsb-release -a lsb_release -cs lsb_release -is lsb_release -rs \u5728openSUSE\u4e2d\uff0c\u9700\u8981\u5b89\u88c5 lsb-release \u5305\u3002\u6267\u884c lsb-release -a \u548c lsb_release -a \u8fd4\u56de\u7684\u7ed3\u679c\u662f\u4e00\u6837\u7684\u3002 sudo zypper in lsb-release \u5728Ubuntu\u4e2d\uff0c\u9700\u8981\u5b89\u88c5 lsb-release \u5305\u3002\u53ea\u80fd\u6267\u884c lsb_release -a \u3002 sudo apt install lsb-release \u5728Rocky 9\u4e2d\uff0c\u627e\u4e0d\u5230 lsb-release \u76f8\u5173\u7684\u5305\u3002","title":"3.8.\u64cd\u4f5c\u7cfb\u7edf\u7248\u672c"},{"location":"linux/SRE/01-fundamentals/#39","text":"\u663e\u793a\u9ed8\u8ba4\u683c\u5f0f\u7684\u5f53\u524d\u65e5\u671f\u3002 date \u4e09\u4e2a\u7cfb\u7edf\u7684\u9ed8\u8ba4\u65e5\u671f\u683c\u5f0f\u7565\u6709\u4e0d\u540c\u3002 # openSUSE Mon 24 Oct 2022 09 :28:06 AM CST # Ubuntu Mon Oct 24 01 :28:09 AM UTC 2022 # Rocky Mon Oct 24 09 :24:01 AM CST 2022 \u663e\u793a\u81ea1970-01-01 00:00:00 UTC\u5230\u5f53\u524d\u7684\u79d2\u6570\u3002 date +%s \u5c06\u4e0a\u4e00\u547d\u4ee4\u4e2d\u7684\u63cf\u8ff0\u8f6c\u6362\u4e3a\u7cfb\u7edf\u9ed8\u8ba4\u65e5\u671f\u683c\u5f0f\u3002 date -d @ ` date +%s ` date --date = @ '1666575347' \u663e\u793a\u786c\u4ef6\u65f6\u949f\u3002 hwclock \u4e5f\u88ab\u79f0\u4e3a Real Time Clock (RTC)\u3002 \u5728Rocky9\u4e2d\uff0c clock \u6709\u4e00\u4e2a\u8f6f\u8fde\u63a5\u6307\u5411 hwclock \uff1a /usr/sbin/clock -> hwclock \u3002\u5728openSUSE\u548cUbuntu\u4e2d\u53ea\u6709 hwclock \u3002 ll /usr/sbin/clock ll /usr/sbin/hwclock \u8bfb\u53d6RTC\u65f6\u95f4\u3002 sudo hwclock --get sudo hwclock -r \u6821\u51c6\u65f6\u95f4\uff1a -s, \u2013hctosys : \u4ee5RTC\u786c\u4ef6\u65f6\u95f4\u6765\u6821\u51c6\u7cfb\u7edf\u65f6\u95f4\u3002 -w, \u2013systohoc : \u4ee5\u7cfb\u7edf\u65f6\u95f4\u6765\u6821\u51c6RTC\u786c\u4ef6\u65f6\u95f4\u3002 \u663e\u793a\u5f53\u524d\u7cfb\u7edf\u65f6\u533a\u3002 ll /etc/localtime \u7cfb\u7edf\u53ef\u80fd\u4f1a\u8fd4\u56de\u4e0d\u540c\u7ed3\u679c\uff0c\u4f8b\u5982\uff1a /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai /etc/localtime -> /usr/share/zoneinfo/Etc/UTC \u663e\u793a\u5f53\u524d\u53ef\u4ee5\u65f6\u533a\u5217\u8868\u3002 timedatectl list-timezones timedatectl list-timezones | grep -i Asia \u4fee\u6539\u5f53\u524d\u7cfb\u7edf\u65f6\u533a\u3002 sudo timedatectl set-timezone Asia/Shanghai \u663e\u793a\u65e5\u5386\u3002 cal -y openSUSE\u548cRocky\u4e2d\uff0c\u4f7f\u7528 cal \u547d\u4ee4\u9700\u8981\u5b89\u88c5 util-linux \u5305\u3002 Ubuntu\u4e2d\uff0c\u4f7f\u7528 cal \u547d\u4ee4\u9700\u8981\u5b89\u88c5 ncal \u5305\u3002 sudo apt install ncal sudo zypper se util-linux sudo yum install util-linux","title":"3.9.\u65e5\u671f\u548c\u65f6\u95f4"},{"location":"linux/SRE/01-fundamentals/#310","text":"whoami \uff1a\u5f53\u524d\u767b\u5f55\u7528\u6237 who \uff1a\u7cfb\u7edf\u5f53\u524d\u6240\u6709\u7684\u767b\u5f55\u4f1a\u8bdd w \uff1a\u7cfb\u7edf\u5f53\u524d\u6240\u6709\u7684\u767b\u5f55\u4f1a\u8bdd\u53ca\u6240\u4f5c\u7684\u64cd\u4f5c \u63d0\u793a\uff1a MOTD is the abbreviation of \"Message Of The Day\", and it is used to display a message when a remote user login to the Linux Operating system using SSH. Linux administrators often need to display different messages on the login of the user, like displaying custom information about the server or any necessary information. \u7f16\u8f91\u6587\u4ef6 /etc/motd \u53ef\u4ee5\u81ea\u5b9a\u4e49\"Message Of The Day\"\u7684\u4fe1\u606f\u3002 Ubuntu 2204\u65b0\u5b89\u88c5\u540e\u6ca1\u6709\u8fd9\u4e2a\u6587\u4ef6\uff0c\u9700\u8981\u81ea\u5df1\u521b\u5efa\u3002 openSUSE\u65b0\u5b89\u88c5\u540e\u6709\u9884\u5b9a\u4e49\u7684\u4fe1\u606f\u3002 Rocky9 \u65b0\u5b89\u88c5\u540e\u6709\u8be5\u6587\u4ef6\uff0c\u7a7a\u767d\u6587\u4ef6\u65e0\u5185\u5bb9\u3002","title":"3.10.\u7528\u6237\u767b\u5f55\u4fe1\u606f"},{"location":"linux/SRE/01-fundamentals/#311","text":"screen \u5de5\u5177 screen -S (Create new screen session) screen -ls (list current screen sessions) screen -x (Attach to existing screeen session, sync between both) screen -r (Reattach existing screen session) tmux \u5de5\u5177 tmux \u662f\u6307 Terminal Multiplexer . \u5b89\u88c5 tmux \u5de5\u5177\u3002 # Rocky sudo yum install tmux # Ubuntu sudo apt install tmux # openSUSE sudo zypper in tmux \u5e38\u7528\u65b9\u6cd5\uff1a tmux new -s (Create new session) tmux detach (Detach current session) tmux ls (list current sessions) tmux attach -t (Reattach existing session) tmux switch -t (Switch to another session) tmux kill-session -t (Kill existing session) tmux list-keys (List all short keys) tmux list-commands (List commands and parameters) tmux info (List all sessions info) tmux split-window (Split window)","title":"3.11.\u4f1a\u8bdd\u7ba1\u7406\u5de5\u5177"},{"location":"linux/SRE/01-fundamentals/#312echo","text":"echo \u547d\u4ee4\u4e2d\u53ef\u4ee5\u8f93\u51fa\u53d8\u91cf\uff0c\u5982\u679c\u53d8\u91cf\u662f\u7528\u662f\u5355\u5f15\u53f7\u5f15\u8d77\u6765\uff0c\u8868\u793a\u8fd9\u4e2a\u53d8\u91cf\u4e0d\u7528IFS\u66ff\u6362\uff01\uff01 echo \"Home=$HOME\" \u7684\u8f93\u51fa\u7ed3\u679c\u662f Home=/home/vagrant echo 'Home=$HOME' \u7684\u8f93\u51fa\u7ed3\u679c\u662f Home=$HOME echo -e \u542f\u7528 \\ \u5b57\u7b26\u7684\u89e3\u91ca\u529f\u80fd\uff0c\u6bd4\u5982\uff1a echo -e \"a\\x0Ab\" \uff0c\u8f93\u51fa\u5b57\u7b26 a \u548c b \uff0c\u4e2d\u95f4 \\x0A \u4ee3\u8868\u5341\u516d\u8fdb\u5236 OA \uff08\u5373\u56de\u8f66\uff09 echo -e \"\\x4A \\x41 \\x4D \\x45 \\x53\" \uff0c\u8f93\u51fa\u7ed3\u679c\u662f J A M E S \u63d0\u793a\uff1a \u4ee5\u901a\u8fc7man 7 ascii\u6765\u67e5\u770b\u5404\u8fdb\u5236\u7684\u542b\u4e49\u3002 echo -e \u8f93\u51fa\u5e26\u989c\u8272\u5b57\u7b26\u3002 \u793a\u4f8b\uff1a echo -e \"\\e[35m \u7d2b\u8272 \\e[0m\" echo -e \"\\e[43m \u9ec4\u5e95 \\e[0m\" echo -e \"\\e[93m \u9ed1\u5e95\u9ec4\u5b57 \\e[0m\" \u53c2\u8003\u4fe1\u606f\uff1a \u5b57\u4f53\u989c\u8272\uff1a \\e[30m \uff1a \u9ed1\u8272 \\e[31m \uff1a \u7ea2\u8272 \\e[32m \uff1a \u7eff\u8272 \\e[33m \uff1a \u9ec4\u8272 \\e[34m \uff1a \u84dd\u8272 \\e[35m \uff1a \u7d2b\u8272 \\e[36m \uff1a \u9752\u8272 \\e[37m \uff1a \u767d\u8272 \\e[40m \uff1a \u9ed1\u5e95 \\e[41m \uff1a \u7ea2\u5e95 \\e[42m \uff1a \u7eff\u5e95 \\e[43m \uff1a \u9ec4\u5e95 \\e[44m \uff1a \u84dd\u5e95 \\e[45m \uff1a \u7d2b\u5e95 \\e[46m \uff1a \u9752\u5e95 \\e[47m \uff1a \u767d\u5e95 \u80cc\u666f\u989c\u8272\uff1a \\e[90m \uff1a \u9ed1\u5e95\u9ed1\u5b57 \\e[91m \uff1a \u9ed1\u5e95\u7ea2\u5b57 \\e[92m \uff1a \u9ed1\u5e95\u7eff\u5b57 \\e[93m \uff1a \u9ed1\u5e95\u9ec4\u5b57 \\e[94m \uff1a \u9ed1\u5e95\u84dd\u5b57 \\e[95m \uff1a \u9ed1\u5e95\u7d2b\u5b57 \\e[96m \uff1a \u9ed1\u5e95\u9752\u5b57 \\e[97m \uff1a \u9ed1\u5e95\u767d\u5b57 \u63a7\u5236\u5c5e\u6027\uff1a \\e[0m \u5173\u95ed\u6240\u6709\u5c5e\u6027 \\e[1m \u8bbe\u7f6e\u9ad8\u4eae\u5ea6 \\e[4m \u4e0b\u5212\u7ebf \\e[5m \u95ea\u70c1 \\e[7m \u53cd\u663e\uff0c\u649e\u8272\u663e\u793a\uff0c\u663e\u793a\u4e3a\u767d\u5b57\u9ed1\u5e95\uff0c\u6216\u8005\u663e\u793a\u4e3a\u9ed1\u5e95\u767d\u5b57 \\e[8m \u6d88\u5f71\uff0c\u5b57\u7b26\u989c\u8272\u5c06\u4f1a\u4e0e\u80cc\u666f\u989c\u8272\u76f8\u540c \\e[nA \u5149\u6807\u4e0a\u79fb n \u884c \\e[nB \u5149\u6807\u4e0b\u79fb n \u884c \\e[nC \u5149\u6807\u53f3\u79fb n \u884c \\e[nD \u5149\u6807\u5de6\u79fb n \u884c \\e[y;xH \u8bbe\u7f6e\u5149\u6807\u4f4d\u7f6e \\e[2J \u6e05\u5c4f \\e[K \u6e05\u9664\u4ece\u5149\u6807\u5230\u884c\u5c3e\u7684\u5185\u5bb9 \\e[s \u4fdd\u5b58\u5149\u6807\u4f4d\u7f6e \\e[u \u6062\u590d\u5149\u6807\u4f4d\u7f6e \\e[?25 \u9690\u85cf\u5149\u6807 \\e[?25h \u663e\u793a\u5149\u6807","title":"3.12.echo\u547d\u4ee4"},{"location":"linux/SRE/01-fundamentals/#313man","text":"\u5b89\u88c5\u5305\uff1a # openSUSE sudo zypper install man-pages man-pages-zh_CN man-pages-posix # Rocky sudo yum install man-pages # Ubuntu sudo apt install man-db manpages-posix manpages manpages-zh sudo apt install manpages-dev manpages-posix-dev \u66f4\u65b0mandb mandb \u67e5\u627e\u67d0\u4e2a\u547d\u4ee4\u7684man\u4fe1\u606f\uff0c\u4f8b\u5982\u67e5\u627e crontab \u547d\u4ee4\u7684\u4fe1\u606f\u3002 # \u7cbe\u786e\u67e5\u627e man -f crontab whatis crontab # \u6a21\u7cca\u67e5\u8be2 man -k crontab apropos crontab \u8f93\u51fa\u7ed3\u679c\u5982\u4e0b\uff1a crontab (5) - files used to schedule the execution of programs crontab (1) - maintains crontab files for individual users crontab (1p) - schedule periodic background work \u67e5\u627ecrontab\u7b2c5\u7ae0\u7684\u5185\u5bb9\uff0c\u5219\u53ef\u4ee5\u6267\u884c\uff1a man 5 crontab \u5e38\u7528\u5feb\u6377\u952e\u793a\u4f8bs\uff1a 1G : go to the 1 st line 10G : go to the 10 th line G : go to the end of the page /^SELinux : search the word SELinux /section OPTIONS : go to the section OPTIONS","title":"3.13.man\u547d\u4ee4"},{"location":"linux/SRE/01-fundamentals/#314tr","text":"tr \u547d\u4ee4\u53ef\u4ee5\u5bf9\u6765\u81ea\u6807\u51c6\u8f93\u5165\u7684\u5b57\u7b26\u8fdb\u884c\u66ff\u6362\u3001\u538b\u7f29\u548c\u5220\u9664\u3002\u5b83\u53ef\u4ee5\u5c06\u4e00\u7ec4\u5b57\u7b26\u53d8\u6210\u53e6\u4e00\u7ec4\u5b57\u7b26\u3002 \u683c\u5f0f\uff1a tr [OPTION]... SET1 [SET2] \u4e3e\u4f8b\uff1a # \u5c06\u8f93\u5165\u5b57\u7b26\u7531\u5927\u5199\u8f6c\u6362\u4e3a\u5c0f\u5199 $ echo \"HELLO WORLD\" | tr 'A-Z' 'a-z' hello world # \u5220\u9664\u51fa\u73b0\u7684\u6570\u5b57 $ echo \"HELLO 1234 WORLD 4567\" | tr -d '0-9' HELLO WORLD # \u4ece\u8f93\u5165\u6587\u672c\u4e2d\u5c06\u4e0d\u5728\u8865\u96c6\u4e2d\u7684\u6240\u6709\u5b57\u7b26\u5220\u9664\uff08\u53ea\u4fdd\u7559\u6570\u5b571\uff0c2\uff0c3\uff0c4\uff0c5\uff09 $ echo \"HELLO 1234 WORLD 4567\" | tr -d -c '1-5' 123445 # \u5c06\u8fde\u7eed\u91cd\u590d\u7684\u5b57\u7b26\u4ee5\u5355\u72ec\u4e00\u4e2a\u5b57\u7b26\u8868\u793a $ echo \"HELLOOO 1222235555555554\" | tr -s 'O215' HELLO 12354 # \u5220\u9664\u7531\u4e8eWindows\u6587\u4ef6\u9020\u6210\u7684'^M'\u5b57\u7b26 $ cat file.txt | tr -s '\\r' '\\n' > new.txt $ cat file.txt | tr -d '\\r' > new.txt # \u5c06\u6362\u884c\u7b26\u66ff\u6362\u6210\u5236\u8868\u7b26 $ cat file.txt | tr '\\n' '\\t' > new.txt # \u5c06\u5927\u5199\u5b57\u6bcd\u8f6c\u6362\u4e3a\u5c0f\u5199\u5b57\u6bcd $ echo \"HELLO 1234 WORLD 4567\" | tr '[:upper:]' '[:lower:]' hello 1234 world 4567","title":"3.14.tr\u547d\u4ee4"},{"location":"linux/SRE/01-fundamentals/#315tee","text":"tee \u547d\u4ee4\u57fa\u4e8e\u6807\u51c6\u8f93\u5165\u8bfb\u53d6\u6570\u636e\uff0c\u6807\u51c6\u8f93\u51fa\u6216\u6587\u4ef6\u5199\u5165\u6570\u636e\u3002 \u4e3e\u4f8b\uff1a # ping\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u4e0d\u4ec5\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4e5f\u540c\u65f6\u5199\u5165\u6587\u4ef6output.txt\u4e2d\uff08\u8986\u76d6\u5f0f\u5199\u5165\uff09\u3002 $ ping www.baidu.com | tee output.txt # ping\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u4e0d\u4ec5\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4e5f\u540c\u65f6\u5199\u5165\u6587\u4ef6output.txt\u4e2d\uff08\u8ffd\u52a0\u5f0f\u5199\u5165\uff09\u3002 $ ping www.baidu.com | tee -a output.txt # ping\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u4e0d\u4ec5\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4e5f\u540c\u65f6\u5199\u5165\u591a\u4e2a\u6587\u4ef6\u4e2d\uff08\u8986\u76d6\u5f0f\u5199\u5165\uff09\u3002 $ ping www.baidu.com | tee output1.txt output2.txt output3.txt # ls\u547d\u4ee4\u7684\u8f93\u51fa\u5199\u5165\u6587\u4ef6output.txt\u4e2d\uff0c\u5e76\u4f5c\u4e3awc\u547d\u4ee4\u7684\u8f93\u5165\u3002 $ ls *.txt | tee output.txt | wc -l 4 # cat output.txt f1.txt f2.txt output.txt test.txt \u6280\u5de7\uff1a \u5728vi\u4f7f\u7528\u4e2d\uff0c\u901a\u8fc7 tee \u547d\u4ee4\u63d0\u5347\u6587\u4ef6\u5199\u5165\u6743\u9650\u3002 \u6bd4\u5982\u975eroot\u7528\u6237\u6267\u884c vi /etc/hosts \uff0c\u5728vi\u4e2d\u4f7f\u7528 :w !sudo tee % \u53ef\u4ee5\u63d0\u9ad8\u6743\u9650\u4fdd\u5b58\u8fd9\u4e2a\u6587\u4ef6\u3002","title":"3.15.tee\u547d\u4ee4"},{"location":"linux/SRE/01-fundamentals/#316lang","text":"\u5b89\u88c5\u8bed\u8a00\u5305\u3002 # Ubuntu sudo apt install locales-all # Rocky sudo yum install glibc-langpack-zh.x86_64 # openSUSE sudo zypper install glibc-locale glibc-locale-32bit glibc-locale-base \u67e5\u770b\u5f53\u524d\u8bed\u8a00\u8bbe\u7f6e\uff1a echo $LANG locale -a locale -k LC_TIME localectl status localectl list-locales \u5168\u5c40locale\u914d\u7f6e(Global locale settings)\u3002 # openSUSE & Rocky sudo cat /etc/locale.conf # Ubuntu sudo cat /etc/default/locale \u4e34\u65f6\u4fee\u6539\u5f53\u524dsession\u7684locale\u3002 LANG = \"zh_CN.utf8\" \u6c38\u4e45\u4fee\u6539locale\u8bbe\u7f6e\u3002 sudo localectl set-locale LANG = zh_CN.utf8 \u4fee\u6539\u56de\u539f\u8bbe\u7f6e\u3002 sudo localectl set-locale LANG = en_US.utf8 Tips: Mac OS ssh\u767b\u9646Linux\u662f\u7ec8\u7aef\u63d0\u793a /usr/bin/manpath: can't set the locale; make sure $LC_* and $LANG are correct \u89e3\u51b3\u65b9\u6cd5\uff1a\u5728\u672c\u5730mac\u7535\u8111\u4e0a\u4fee\u6539/etc/ssh/ssh_config\u6216\u8005/etc/ssh/ssh_config\u6587\u4ef6\uff0c\u5220\u9664\u6389\u6216\u8005\u6ce8\u91ca\u6389\u8fd9\u4e00\u884c\u914d\u7f6e\u5185\u5bb9 # SendEnv LANG LC_* \u3002 \u5982\u679c\u4f7f\u7528\u7684\u662f Iterm2 \uff0c\u53ef\u4ee5\u6253\u5f00 iterm2 \u7684 preferences -> Profiles -> Terminal \u83dc\u5355\u91cc\u5173\u95ed Set locale variables automatically \u9009\u9879\u3002","title":"3.16.\u8bed\u8a00\u73af\u5883LANG"},{"location":"linux/SRE/01-fundamentals/#317","text":"\u7b26\u53f7 $ \u7684\u7528\u6cd5\uff1a $ \uff0c\u83b7\u53d6\u53d8\u96f6\u503c\u3002 x = 1 echo $x echo \" $x \" \u5efa\u8bae\u4f7f\u7528\"$x\"\uff0c\u4ee5\u907f\u514dshell\u7f16\u7a0b\u4e2d\u4ea7\u751f\u6b67\u4e49\u3002\u5982\u4e0b\u4f8b\uff1a s = \"this is a string\" echo $s echo \"this is a string\" \u6267\u884c [ $s == \"this is a string\" ] \u4f1a\u62a5\u9519\uff0c\u8fd9\u662f\u5b9e\u9645\u751f\u6210\u7684\u6bd4\u8f83\u5f0f this is a string == \"this is a string\" \u3002 \u6211\u4eec\u9884\u671f\u7684\u662f \"this is a string\" == \"this is a string\" \uff0c\u6240\u4ee5\u9700\u8981\u6539\u6210 [ \"$s\" == \"this is a string\" ] \u3002 $0 , $1 , $n , $# \uff1a \u751f\u6210\u4e00\u4e2a\u6d4b\u8bd5\u811a\u672c\u3002 echo 'echo $0 $1 $2 $#' > test.sh chmod 755 test.sh \u9a8c\u8bc1\u5404\u4e2a\u53c2\u6570\u4f4d\u7f6e\u3002 ./test.sh a b c d e \u8f93\u51fa\u7ed3\u679c\uff1a ./test.sh a b 5 \u7ed3\u8bba\uff1a $0 \u8f93\u51fa\u811a\u672c\u6587\u4ef6\u540d\uff1b $1 \u8f93\u51fa\u7b2c\u4e00\u4e2a\u53c2\u6570\uff1b $2 \u8f93\u51fa\u7b2c\u4e8c\u4e2a\u53c2\u6570\uff1b $# \u8f93\u51fa\u53c2\u6570\u4e2a\u6570\u3002 ${} ${} \u7528\u4e8e\u533a\u5206\u53d8\u91cf\u7684\u8fb9\u754c\u3002 \u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c $abc \u65e0\u7ed3\u679c\u8f93\u51fa\uff0c ${a}bc \u8f93\u51fa\u7ed3\u679c stringbc \uff0c\u901a\u8fc7{}\u6307\u5b9a\u4e86\u67d0\u4e2a\u5b57\u7b26\u5c5e\u4e8e\u53d8\u91cf\u3002 a = \"string\" echo ${ a } bc echo $abc ${#} ${#} \u662f\u8fd4\u56de\u53d8\u91cf\u503c\u7684\u957f\u5ea6\u3002 s = 'this is a string' echo \" $s \" echo \" ${# s } \" \u547d\u4ee4 echo \"${#s}\" \u8f93\u51fa\u7ed3\u679c\u662f\u5b57\u4e32 this is a string \u7684\u957f\u5ea6 16 \u3002 $? $? \u662f\u8fd4\u56de\u4e0a\u4e00\u547d\u4ee4\u662f\u5426\u6210\u529f\u7684\u72b6\u6001\uff0c 0 \u4ee3\u8868\u6210\u529f\uff0c\u975e\u96f6\u4ee3\u8868\u5931\u8d25\u3002 ls \u662f\u4e00\u4e2a\u547d\u4ee4\uff0c\u6240\u4ee5\u8fd4\u56de\u503c\u662f 0 \u3002 tom \u662f\u4e00\u4e2a\u4e0d\u5b58\u5728\u7684\u547d\u4ee4\uff0c\u5219\u8fd4\u56de 127 \u3002 ls echo $? tom echo $? $() $() \u7b49\u540c\u4e8e\u53cd\u5f15\u53f7\u3002 echo $(ls) \u7b49\u540c\u4e8e\u6267\u884c ls \u547d\u4ee4\u3002 $() \u7684\u5f0a\u7aef\u662f\uff0c\u4e0d\u662f\u6240\u6709\u7684\u7c7bunix\u7cfb\u7edf\u90fd\u652f\u6301\uff0c\u53cd\u5f15\u53f7\u662f\u80af\u5b9a\u652f\u6301\u7684\u3002 $() \u7684\u4f18\u52bf\u662f\u76f4\u89c2\uff0c\u5728\u8f6c\u79fb\u5904\u7406\u65f6\uff0c\u6bd4\u53cd\u5f15\u53f7\u76f4\u89c2\u5bb9\u6613\u4e9b\u3002 echo $( ls ) # test.sh echo $( cat $( ls )) # echo $0 $1 $2 $# \u4e0a\u8ff0\u5d4c\u5957\u683c\u5f0f\u4e2d\uff0cls\u547d\u4ee4\u7684\u8f93\u51fa\uff0c\u662fcat\u547d\u4ee4\u7684\u8f93\u5165\uff0c\u53ef\u4ee5\u8fdb\u884c\u591a\u5c42\u5d4c\u5957\uff0c\u5185\u5c42\u547d\u4ee4\u7684\u8f93\u51fa\u662f\u5916\u5c42\u547d\u4ee4\u7684\u8f93\u5165\u3002 $[] $[] \u662f\u8868\u8fbe\u5f0f\u8ba1\u7b97\u3002 echo $ [ 3 + 2 ] $- $- \u663e\u793ashell\u5f53\u524d\u6240\u4f7f\u7528\u7684\u9009\u9879\u3002 \u6267\u884c echo $- \uff0c\u8f93\u51fa\u7ed3\u679c himBHs \u3002himBH\u6bcf\u4e00\u4e2a\u5b57\u7b26\u662f\u4e00\u4e2ashell\u7684\u9009\u9879\u3002 $! $! \u83b7\u53d6\u6700\u540e\u4e00\u4e2a\u8fd0\u884c\u7684\u540e\u53f0\u8fdb\u7a0b\u7684pid\u3002 \u6bd4\u5982\u6267\u884c cat test.sh & \uff0c\u7ed3\u679c\u4e2d\u4f1a\u5305\u542b\u4e00\u4e2apid\u53f7\uff0c\u9a6c\u4e0a\u7740\u6267\u884c echo $! \uff0c\u5982\u679c2\u4e2a\u547d\u4ee4\u95f4\u9694\u4e4b\u95f4\u6ca1\u6709\u5176\u4ed6\u540e\u53f0\u8fdb\u7a0b\u6267\u884c\uff0c\u5219\u53ef\u4ee5\u5f97\u5230\u548c\u524d\u9762\u4e00\u81f4\u7684pid\u53f7\u3002 !$ !$ \u8fd4\u56de\u4e0a\u4e00\u6761\u547d\u4ee4\u7684\u6700\u540e\u4e00\u4e2a\u53c2\u6570\u3002 \u6267\u884c ./test.sh a b c iamhere \uff0c\u5f97\u5230\u7ed3\u679c ./test.sh a b 4 \u3002 \u6267\u884c echo !$ \uff0c\u5f97\u52302\u4e2a\u7ed3\u679c\uff0c echo iamhere \u548c iamhere \u3002 !! !! \u8f93\u51fa\u4e0a\u4e00\u6761\u547d\u4ee4\uff0c\u5e76\u6267\u884c\u3002 !! \u4f1a\u5148\u8f93\u51fa\u4e0a\u4e00\u6761\u547d\u4ee4 cat test.sh \uff0c\u7136\u540e\u518d\u6267\u884c\u8fd9\u6761\u547d\u4ee4\uff0c\u7b2c\u4e8c\u884c\u5373\u6267\u884c\u7ed3\u679c\u3002 [ vagrant@lizard:~ ] $ cat test.sh echo $0 $1 $2 $# [ vagrant@lizard:~ ] $ !! cat test.sh echo $0 $1 $2 $# $$ $$ \u8f93\u51fa\u5f53\u524d\u8fdb\u7a0b\u7684pid\u3002 echo $$ $@ & $* $@ \u548c $* \u662f\u5bf9\u4f20\u5165\u53c2\u6570\u7684\u4e0d\u540c\u4f53\u73b0\uff0c $@ \u662f\u4ee5\u53d8\u91cf\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff0c $* \u662f\u4ee5\u6570\u7ec4\u7684\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\u3002 \u521b\u5efa\u4e00\u4e2a\u6587\u4ef6 script.sh \u5305\u542b\u4e0b\u9762\u7684\u811a\u672c\u3002\u5e76\u6dfb\u52a0\u6267\u884c\u6743\u9650 chmod 755 script.sh \u3002 echo '$@\u4ee5\u53d8\u91cf\u65b9\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a' for x in \" $@ \" do echo $x done echo '$*\u4ee5\u6570\u7ec4\u7684\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a' for x in \" $* \" do echo $x done \u8f93\u51fa\u7ed3\u679c\uff1a $@ \u4ee5\u53d8\u91cf\u65b9\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a a b 3 5 d $* \u4ee5\u6570\u7ec4\u7684\u5f62\u5f0f\u5f15\u7528\u4f20\u5165\u53c2\u6570\uff1a a b 3 5 d","title":"3.17.\u7b26\u53f7$\u7528\u6cd5"},{"location":"linux/SRE/02-filesystem/","text":"\u7b2c\u4e8c\u7ae0 \u6587\u4ef6\u7cfb\u7edf \u00b6 \u6587\u4ef6\u7cfb\u7edf\u5c42\u6b21\u6807\u51c6\uff08Filesystem Hierarchy Standard, FHS\uff09\uff0c\u5b83\u662fLinux \u6807\u51c6\u5e93\uff08Linux Standards Base, LSB\uff09\u89c4\u8303\u7684\u4e00\u90e8\u5206\u3002 \u6839\u76ee\u5f55 / \u6307\u6587\u4ef6\u7cfb\u7edf\u6811\u7684\u6700\u9ad8\u5c42\u3002 \u6839\u5206\u533a\u5728\u7cfb\u7edf\u542f\u52a8\u65f6\u9996\u5148\u6302\u8f7d\u3002 \u7cfb\u7edf\u542f\u52a8\u65f6\u8fd0\u884c\u7684\u6240\u6709\u7a0b\u5e8f\u90fd\u5fc5\u987b\u5728\u6b64\u5206\u533a\u4e2d\u3002 1.\u4e3b\u8981\u76ee\u5f55 \u00b6 \u4ee5\u4e0b\u76ee\u5f55\u5fc5\u987b\u5728\u6839\u5206\u533a\u4e2d\uff1a /bin - \u7528\u6237\u57fa\u672c\u7a0b\u5e8f\u3002 \u5305\u542b\u672a\u6302\u8f7d\u5176\u4ed6\u6587\u4ef6\u7cfb\u7edf\u65f6\u6240\u9700\u7684\u53ef\u6267\u884c\u6587\u4ef6\u3002 \u4f8b\u5982\uff0c\u7cfb\u7edf\u542f\u52a8\u3001\u5904\u7406\u6587\u4ef6\u548c\u914d\u7f6e\u6240\u9700\u7684\u7a0b\u5e8f\u3002 \u4e0d\u80fd\u5173\u8054\u5230\u72ec\u7acb\u5206\u533a\uff0c\u64cd\u4f5c\u7cfb\u7edf\u542f\u52a8\u5373\u4f1a\u8c03\u7528\u7684\u7a0b\u5e8f\u3002 /bin/bash - bash \u811a\u672c\u5904\u7406 /bin/cat - \u663e\u793a\u6587\u4ef6\u5185\u5bb9 /bin/cp - \u62f7\u8d1d\u6587\u4ef6 /bin/dd - \u62f7\u8d1d\u6587\u4ef6\uff08\u57fa\u4e8e\u5b57\u8282byte\uff09 /bin/gzip - \u538b\u7f29\u6587\u4ef6 /bin/mount - \u6302\u8f7d\u6587\u4ef6\u7cfb\u7edf /bin/rm - \u5220\u9664\u6587\u4ef6 /bin/vi - \u6587\u4ef6\u7f16\u8f91 /sbin - \u7cfb\u7edf\u57fa\u672c\u7a0b\u5e8f\u3002 \u5305\u542b\u57fa\u672c\u7cfb\u7edf\u7ba1\u7406\u7684\u7a0b\u5e8f\u3002 \u9ed8\u8ba4\u662froot\u7528\u6237\u6709\u6743\u9650\u6267\u884c\uff0c\u56e0\u6b64\u5b83\u4e0d\u5728\u5e38\u89c4\u7528\u6237\u8def\u5f84\u4e2d\u3002 \u4e0d\u80fd\u5173\u8054\u5230\u72ec\u7acb\u5206\u533a\uff0c\u64cd\u4f5c\u7cfb\u7edf\u542f\u52a8\u5373\u4f1a\u8c03\u7528\u7684\u7a0b\u5e8f \u4e00\u4e9b\u91cd\u8981\u7ba1\u7406\u7a0b\u5e8f\uff1a /sbin/fdisk* - \u7ba1\u7406\u786c\u76d8\u5206\u533a /sbin/fsck* - \u6587\u4ef6\u7cfb\u7edf\u68c0\u67e5\u3002\u4e0d\u80fd\u5728\u8fd0\u884c\u7684\u7cfb\u7edf\u4e0a\u9762\u76f4\u63a5\u6267\u884c fsck \uff0c\u635f\u574f\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u6267\u884c\u524d\u9700\u8981 umount \u3002 /sbin/mkfs - \u521b\u5efa\u6587\u4ef6\u7cfb\u7edf /sbin/shutdown - \u5173\u95ed\u7cfb\u7edf /dev - \u8bbe\u5907\u6587\u4ef6 \u4ee5\u592a\u7f51\u5361\u662f\u5185\u6838\u6a21\u5757\uff0c\u5176\u4ed6\u786c\u4ef6\u90fd\u4ee5\u8bbe\u5907dev\u7684\u65b9\u5f0f\u5c55\u73b0\u3002 \u5e94\u7528\u7a0b\u5e8f\u8bfb\u53d6\u548c\u5199\u5165\u8fd9\u4e9b\u6587\u4ef6\u4ee5\u64cd\u4f5c\u4f7f\u7528\u786c\u4ef6\u7ec4\u4ef6\u3002 \u4e24\u79cd\u7c7b\u578b\u8bbe\u5907\u6587\u4ef6\uff1a \u5b57\u7b26\u8bbe\u5907\uff08Character-oriented\uff09\u2013 \u5e8f\u5217\u8bbe\u5907\uff08\u6253\u5370\u673a\uff0c\u78c1\u5e26\u673a\uff0c\u9f20\u6807\u7b49\uff09 \u5757\u8bbe\u5907\uff08Block-oriented\uff09\u2013 \u786c\u76d8\uff0cDVD\u7b49 \u4e0e\u8bbe\u5907\u9a71\u52a8\u7a0b\u5e8f\u7684\u8fde\u63a5\u901a\u8fc7\u5185\u6838\u4e2d\u79f0\u4e3a\u4e3b\u8bbe\u5907\u53f7\u7684\u901a\u9053\u5b9e\u73b0\u3002 \u8fc7\u53bb\uff0c\u8fd9\u4e9b\u6587\u4ef6\u662f\u4f7f\u7528 mknod \u547d\u4ee4\u624b\u52a8\u521b\u5efa\u7684\u3002 \u73b0\u5728\u5f53\u5185\u6838\u53d1\u73b0\u8bbe\u5907\u65f6\uff0c\u5b83\u4eec\u4f1a\u7531 udev \u81ea\u52a8\u521b\u5efa\u3002 \u4e00\u4e9b\u91cd\u8981\u7684\u8bbe\u5907\u6587\u4ef6\uff1a Null\u8bbe\u5907: - /dev/null Zero\u8bbe\u5907: - /dev/zero \u7cfb\u7edf\u7ec8\u7aef: - /dev/console \u865a\u62df\u7ec8\u7aef: - /dev/tty1 \u4e32\u884c\u7aef\u53e3 - /dev/ttyS0 \u5e76\u884c\u7aef\u53e3: - /dev/lp0 \u8f6f\u76d8\u9a71\u52a8\u5668: - /dev/fd0 \u786c\u76d8\u9a71\u52a8\u5668: - /dev/sda \u786c\u76d8\u5206\u533a: - /dev/sda1 CD-ROM\u9a71\u52a8\u5668: - /dev/scd0 /etc - \u914d\u7f6e\u6587\u4ef6 \u5b58\u653e\u7cfb\u7edf\u548c\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6\u3002 \u5927\u90e8\u5206\u90fd\u662fASCII\u6587\u4ef6 \u666e\u901a\u7528\u6237\u53ef\u4ee5\u9ed8\u8ba4\u8bfb\u53d6\u5176\u4e2d\u7684\u5927\u90e8\u5206\u5185\u5bb9\u3002 \u8fd9\u4f1a\u5e26\u6765\u4e00\u4e2a\u6f5c\u5728\u7684\u5168\u95ee\u9898\uff0c\u56e0\u4e3a\u5176\u4e2d\u4e00\u4e9b\u6587\u4ef6\u5305\u542b\u5bc6\u7801\uff0c\u56e0\u6b64\u91cd\u8981\u7684\u662f\u8981\u786e\u4fdd\u8fd9\u4e9b\u6587\u4ef6\u53ea\u80fd\u7531root\u7528\u6237\u8bfb\u53d6\u3002 \u6839\u636eFHS\u6807\u51c6\uff0c\u6b64\u5904\u4e0d\u80fd\u653e\u7f6e\u4efb\u4f55\u53ef\u6267\u884c\u6587\u4ef6\uff0c\u4f46\u5b50\u76ee\u5f55\u53ef\u80fd\u5305\u542bshell\u811a\u672c\u3002 \u51e0\u4e4e\u6bcf\u4e2a\u5df2\u5b89\u88c5\u7684\u670d\u52a1\u5728 /etc \u6216\u5176\u5b50\u76ee\u5f55\u4e2d\u81f3\u5c11\u6709\u4e00\u4e2a\u914d\u7f6e\u6587\u4ef6\u3002 \u4e00\u4e9b\u91cd\u8981\u7684\u914d\u7f6e\u6587\u4ef6: /etc/os-release - \u7cfb\u7edf\u7248\u672c\u4fe1\u606f /etc/DIR_COLORS - ls \u547d\u4ee4\u4e2d\u7684\u989c\u8272\u914d\u7f6e\u4fe1\u606f\uff08openSUSE\u548cRocky\uff09 /etc/fstab - \u914d\u7f6e\u8981\u6302\u8f7d\u7684\u6587\u4ef6\u7cfb\u7edf /etc/profile - Shell\u767b\u5f55\u811a\u672c /etc/passwd - \u7528\u6237\u4fe1\u606f\u96c6\u5408\uff08\u4e0d\u542b\u5bc6\u7801\uff09 /etc/shadow - \u5bc6\u7801\u548c\u76f8\u5173\u4fe1\u606f /etc/group - \u7528\u6237\u7ec4\u4fe1\u606f\u96c6\u5408 /etc/cups/* - \u7528\u4e8eCUPS\u6253\u5370\u7cfb\u7edf\uff08CUPS=Common UNIX Printing System\uff09 /etc/hosts - \u4e3b\u673a\u540d\u673a\u5668IP\u5730\u5740 /etc/motd - \u767b\u5f55\u540e\u663e\u793a\u7684\u6b22\u8fce\u4fe1\u606f /etc/issue - \u767b\u5f55\u524d\u663e\u793a\u7684\u6b22\u8fce\u4fe1\u606f /etc/sysconfig/* - \u7cfb\u7edf\u914d\u7f6e\u6587\u4ef6 /lib - \u5e93\uff08Libraries\uff09 \u8bb8\u591a\u7a0b\u5e8f\u90fd\u5177\u6709\u4e00\u4e9b\u901a\u7528\u529f\u80fd\u3002 \u8fd9\u4e9b\u901a\u7528\u529f\u80fd\u53ef\u4ee5\u4fdd\u5b58\u5728\u5171\u4eab\u5e93\u4e2d\u3002 \u5171\u4eab\u5e93\u4e2d\u6587\u4ef6\u7684\u6269\u5c55\u540d\u662f .so \u3002 \u76ee\u5f55 /lib \u5305\u542b\u7684\u5171\u4eab\u5e93\u6587\u4ef6\u4e3b\u8981\u662f\u88ab /bin \u548c /sbin \u76ee\u5f55\u5305\u542b\u7684\u7a0b\u5e8f\u6240\u8c03\u7528\u3002 \u76ee\u5f55 /lib \u7684\u5b50\u76ee\u5f55\u5305\u542b\u4e00\u4e9b\u989d\u5916\u9700\u8981\u7684\u5171\u4eab\u5e93\u3002 \u5185\u6838\u6a21\u5757\u5b58\u50a8\u5728\u76ee\u5f55 /lib/modules \u3002 /lib64 - 64\u4f4d\u5171\u4eab\u5e93\uff0864-Bit Libraries\uff09\uff0c\u7c7b\u4f3c\u76ee\u5f55 /lib \u3002 \u8fd9\u4e2a\u76ee\u5f55\u56e0\u7cfb\u7edf\u67b6\u6784\u4e0d\u540c\u800c\u4e0d\u540c\u3002 \u4e00\u4e9b\u7cfb\u7edf\u652f\u6301\u4e0d\u540c\u7684\u4e8c\u8fdb\u5236\u683c\u5f0f\u5e76\u4fdd\u7559\u540c\u4e00\u4e2a\u5171\u4eab\u5e93\u7684\u4e0d\u540c\u7248\u672c\u3002 /usr - \u5305\u542b\u5e94\u7528\u7a0b\u5e8f\u3001\u56fe\u5f62\u754c\u9762\u6587\u4ef6\u3001\u5e93\u3001\u672c\u5730\u7a0b\u5e8f\u3001\u6587\u6863\u7b49\u3002 /usr \u5373 Unix System Resources. \u4f8b\u5982\uff1a /usr/X11R6/ - X Window \u7cfb\u7edf\u6587\u4ef6 /usr/bin/ - \u51e0\u4e4e\u5305\u542b\u6240\u6709\u53ef\u6267\u884c\u6587\u4ef6 /usr/lib/ - \u5305\u542b\u5e93\u548c\u5e94\u7528\u7a0b\u5e8f /usr/lib64/ - \u5305\u542b64\u4f4d\u5e93\u548c\u5e94\u7528\u7a0b\u5e8f /usr/include/ - \u5305\u542bC\u7a0b\u5e8f\u7684\u5934\u6587\u4ef6\uff08head file\uff09 /usr/local/ - \u5305\u542b\u672c\u5730\u5b89\u88c5\u7a0b\u5e8f\u3002\u8fd9\u4e2a\u76ee\u5f55\u4e0b\u7684\u5185\u5bb9\u4e0d\u4f1a\u88ab\u7cfb\u7edf\u5347\u7ea7\u6240\u8986\u76d6\u3002\u4e0b\u97623\u4e2a\u76ee\u5f55\u5728\u521d\u59cb\u5b89\u88c5\u540e\u662f\u7a7a\u7684\u3002 /usr/local/bin - /usr/local/sbin - /usr/local/lib - /usr/sbin/ - \u7cfb\u7edf\u7ba1\u7406\u7a0b\u5e8f /usr/src/ - \u5185\u6838\u548c\u5e94\u7528\u7a0b\u5e8f\u7684\u6e90\u4ee3\u7801 /usr/src/linux - /usr/share/ - \u7ed3\u6784\u5316\u72ec\u7acb\u6570\u636e /usr/share/doc/ - \u6587\u6863 /usr/share/man/ - man \u547d\u4ee4\u4f7f\u7528\u7684\u5185\u5bb9 /opt - \u7b2c\u4e09\u65b9\u5e94\u7528\u7a0b\u5e8f\u76ee\u5f55 \u5404\u53d1\u884c\u7248\u5305\u542b\u7684\u5e94\u7528\u7a0b\u5e8f\u4e00\u822c\u5b58\u50a8\u5728\u76ee\u5f55 /usr/lib/ \u3002 \u5404\u53d1\u884c\u7248\u53ef\u9009\u7a0b\u5e8f\uff0c\u6216\u7b2c\u4e09\u65b9\u5e94\u7528\u7a0b\u5e8f\u5219\u5b58\u50a8\u5728\u76ee\u5f55 /opt \u3002 \u5728\u5b89\u88c5\u65f6\uff0c\u4f1a\u4e3a\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f\u7684\u6587\u4ef6\u521b\u5efa\u4e00\u4e2a\u76ee\u5f55\uff0c\u5176\u4e2d\u5305\u542b\u5e94\u7528\u7a0b\u5e8f\u7684\u540d\u79f0\u3002\u6bd4\u5982\uff1a /opt/novell - /boot - \u5f15\u5bfc\u76ee\u5f55 /boot/grub2 - \u5305\u542bGRUB2\u7684\u9759\u6001\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\u6587\u4ef6\uff08GRUB = Grand Unified Boot Loader\uff09\u3002 \u5305\u542b\u4ee5\u94fe\u63a5 vmlinuz \u548c initrd \u6807\u8bc6\u7684\u5185\u6838\u548c initrd \u6587\u4ef6\u3002 /root - \u7ba1\u7406\u5458\u7684\u4e3b\u76ee\u5f55\uff08home directory\uff09\u3002 root \u7528\u6237\u7684\u4e3b\u76ee\u5f55\u3002\u5176\u4ed6\u7528\u6237\u7684\u4e3b\u76ee\u5f55\u662f\u5728\u76ee\u5f55 /home \u4e0b\u3002 root \u7528\u6237\u7684\u767b\u5f55\u73af\u5883\u914d\u7f6e\u4fdd\u5b58\u81f3 /root \u5206\u533a\u4e2d\u3002 /home - \u7528\u6237\u4e3b\u76ee\u5f55 \u6bcf\u4e2a\u7cfb\u7edf\u7528\u6237\u90fd\u6709\u4e00\u4e2a\u5206\u914d\u7684\u6587\u4ef6\u533a\u57df\uff0c\u8be5\u6587\u4ef6\u533a\u57df\u5728\u767b\u5f55\u540e\u6210\u4e3a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b83\u4eec\u5b58\u5728\u4e8e /home \u4e2d\u3002 /home \u4e2d\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u53ef\u4ee5\u4f4d\u4e8e\u5355\u72ec\u7684\u5206\u533a\u4e2d\uff0c\u4e5f\u53ef\u4ee5\u4f4d\u4e8e\u7f51\u7edc\u4e0a\u7684\u53e6\u4e00\u53f0\u8ba1\u7b97\u673a\u4e0a\u3002 \u7528\u6237\u914d\u7f6e\u4fe1\u606f\u548c\u914d\u7f6e\u6587\u4ef6\uff08user profile and configuration files\uff09\u4e3b\u8981\u6709\uff1a .profile - \u7528\u6237\u79c1\u6709\u767b\u5f55\u811a\u672c .bashrc - bash \u7684\u914d\u7f6e\u6587\u4ef6 .bash_history - bash \u73af\u5883\u4e0b\u4fdd\u6301\u547d\u4ee4\u5386\u53f2\u8bb0\u5f55 run - \u5e94\u7528\u7a0b\u5e8f\u72b6\u6001\u6587\u4ef6 \u4e3a\u5e94\u7528\u7a0b\u5e8f\u63d0\u4f9b\u4e86\u4e00\u4e2a\u6807\u51c6\u4f4d\u7f6e\u6765\u5b58\u50a8\u5b83\u4eec\u9700\u8981\u7684\u4e34\u65f6\u6587\u4ef6\uff0c\u4f8b\u5982\u5957\u63a5\u5b57\u548c\u8fdb\u7a0bID\u3002 \u8fd9\u4e9b\u6587\u4ef6\u4e0d\u80fd\u5b58\u50a8\u5728 /tmp \u4e2d\uff0c\u56e0\u4e3a /tmp \u4e2d\u7684\u6587\u4ef6\u53ef\u80fd\u4f1a\u88ab\u5220\u9664\u3002 /run/media//* - \u53ef\u79fb\u52a8\u8bbe\u5907\u7684\u6302\u8f7d\u70b9\uff0c\u4f8b\u5982\uff1a /run/media/media_name/ /run/media/cdrom/ - /run/media/dvd/ - /run/media/usbdisk/ - /mnt - \u6587\u4ef6\u7cfb\u7edf\u4e34\u65f6\u6302\u8f7d\u70b9 \u7528\u4e8e\u6302\u8f7d\u4e34\u65f6\u4f7f\u7528\u7684\u6587\u4ef6\u7cfb\u7edf\u7684\u76ee\u5f55\u3002 \u6587\u4ef6\u7cfb\u7edf\u4f7f\u7528 mount \u547d\u4ee4\u6302\u8f7d\uff0c\u4f7f\u7528 umount \u547d\u4ee4\u5220\u9664\u3002 \u5b50\u76ee\u5f55\u9ed8\u8ba4\u4e0d\u5b58\u5728\uff0c\u4e5f\u4e0d\u4f1a\u81ea\u52a8\u521b\u5efa\u3002 /srv - \u670d\u52a1\u6570\u636e\u76ee\u5f55 \u5b58\u653e\u5404\u79cd\u670d\u52a1\u7684\u6570\u636e\uff0c\u6bd4\u5982\uff1a /srv/www - \u7528\u4e8e\u5b58\u653e Apache Web Server \u7684\u6570\u636e /srv/ftp - \u7528\u4e8e\u5b58\u653e FTP server \u7684\u6570\u636e /var - \u53ef\u53d8\u6587\u4ef6\uff08Variable Files\uff09 \u5728\u7cfb\u7edf\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u4f1a\u88ab\u4fee\u6539\u7684\u6587\u4ef6 Important subdirectories: /var/lib/ - \u53ef\u53d8\u5e93\u6587\u4ef6\uff0c\u5e94\u7528\u7a0b\u5e8f\u72b6\u6001\u4fe1\u606f\u6570\u636e /var/log/ - \u65e5\u5fd7\u6587\u4ef6 /var/run/ - \u8fd0\u884c\u4e2d\u7684\u8fdb\u7a0b\u7684\u4fe1\u606f /var/lock/ - \u591a\u7528\u6237\u8bbf\u95ee\u65f6\u7684\u9501\u6587\u4ef6 /var/cache - \u5e94\u7528\u7a0b\u5e8f\u7f13\u5b58\u6570\u636e\u76ee\u5f55 /var/opt - \u4e13\u4e3a /opt \u4e0b\u7684\u5e94\u7528\u7a0b\u5e8f\u5b58\u50a8\u53ef\u53d8\u6570\u636e /var/mail - /var/spool/ - \u5e94\u7528\u7a0b\u5e8f\u6570\u636e\u6c60\uff0c\u6bd4\u5982\uff1a\u6253\u5370\u673a\uff0c\u90ae\u4ef6 /var/spool/mail - /var/spool/cron - /tmp - \u4e34\u65f6\u6587\u4ef6 \u7a0b\u5e8f\u5728\u8fd0\u884c\u65f6\u521b\u5efa\u4e34\u65f6\u6587\u4ef6\u7684\u4f4d\u7f6e /proc - \u8fdb\u7a0b\u6587\u4ef6 \u865a\u62df\u6587\u4ef6\u7cfb\u7edf\uff0c\u4e0d\u5360\u7a7a\u95f4\uff0c\u5927\u5c0f\u59cb\u7ec8\u4e3a\u96f6\uff0c\u4fdd\u6301\u5f53\u524d\u8fdb\u7a0b\u7684\u72b6\u6001\u4fe1\u606f \u5305\u542b\u6709\u5173\u5404\u4e2a\u8fdb\u7a0b\u7684\u4fe1\u606f\u7684\u76ee\u5f55\uff0c\u6839\u636e\u8fdb\u7a0b\u7684 PID \u53f7\u547d\u540d \u6709\u4e9b\u503c\u53ef\u4ee5\u4e34\u65f6\u5728\u7ebf\u66f4\u6539\u751f\u6548\uff0c\u4f46\u91cd\u542f\u540e\u4e22\u5931 /proc/cpuinfo/ - Processor information /proc/dma/ - Use of DMA ports /proc/interrupts/ - Use of interrupts /proc/ioports/ - Use of I/O ports /proc/filesystems/ - File system formats the kernel knows /proc/modules/ - Active modules /proc/mounts/ - Mounted file systems /proc/net/* - Network information and statistics /proc/partitions/ - Existing partitions /proc/bus/pci/ - Connected PCI devices /proc/bus/scsi/ - Connected SCSI devices /proc/sys/* - System and kernel information /proc/version - Kernel version /sys - \u7cfb\u7edf\u4fe1\u606f\u76ee\u5f55 \u865a\u62df\u6587\u4ef6\u7cfb\u7edf\uff0c\u4ec5\u5b58\u5728\u4e8e\u5185\u5b58\u4e2d\uff0c\u6587\u4ef6\u5927\u5c0f\u4e3a\u96f6\u3002\u4e3b\u8981\u63d0\u4f9b\u5982\u4e0b\u4fe1\u606f\uff1a \u786c\u4ef6\u603b\u7ebf\uff08hardware buses\uff09 \u786c\u4ef6\u8bbe\u5907\uff08hardware devices\uff09 \u6709\u6e90\u8bbe\u5907\uff08active devices\uff09 \u9a71\u52a8\u7a0b\u5e8f\uff08drivers\uff09 2.\u6587\u4ef6\u64cd\u4f5c\u547d\u4ee4 \u00b6 2.1.\u663e\u793a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55 \u00b6 pwd\u547d\u4ee4\uff08print working directory\uff09: -L: \u663e\u793a\u94fe\u63a5\u8def\u5f84 -P\uff1a\u663e\u793a\u771f\u5b9e\u7269\u7406\u8def\u5f84 2.2.\u76f8\u5bf9\u548c\u7edd\u5bf9\u8def\u5f84 \u00b6 \u5bf9\u4e8e\u7edd\u5bf9\u8def\u5f84 /etc/firewalld/policies \uff0c\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u5f97\u5230\u8be5\u8def\u5f84\u7684\u57fa\u540d policies \u548c\u76ee\u5f55\u540d /etc/firewalld \u3002 basename /etc/firewalld/policies dirname /etc/firewalld/policies 2.3.\u66f4\u6539\u76ee\u5f55 \u00b6 . \u6307\u5f53\u524d\u76ee\u5f55\uff0c\u5373 pwd \u547d\u4ee4\u6240\u8fd4\u56de\u7684\u76ee\u5f55\u3002 .. \u6307\u5f53\u524d\u76ee\u5f55\u7684\u4e0a\u4e00\u7ea7\u76ee\u5f55\uff0c\u53ca\u5f53\u524d\u76ee\u5f55\u7684\u7236\u76ee\u5f55\u3002 \u5207\u6362\u81f3\u7236\u76ee\u5f55\uff1a cd .. \u5207\u6362\u81f3\u5f53\u524d\u7528\u6237\u4e3b\u76ee\u5f55\uff1a cd ~ \u5207\u6362\u81f3\u4e0a\u6b21\u5de5\u4f5c\u76ee\u5f55\uff1a cd - echo $PWD \uff1a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55 echo $OLDPWD \uff1a\u4e0a\u6b21\u5de5\u4f5c\u76ee\u5f55 2.4.\u5217\u51fa\u76ee\u5f55\u5185\u5bb9 \u00b6 ls \u547d\u4ee4\uff1a -a \u663e\u793a\u6240\u6709\u6587\u4ef6\u53ca\u76ee\u5f55 (. \u5f00\u5934\u7684\u9690\u85cf\u6587\u4ef6\u4e5f\u4f1a\u5217\u51fa) -A \u540c -a \uff0c\u4f46\u4e0d\u5217\u51fa . (\u76ee\u524d\u76ee\u5f55) \u53ca .. (\u7236\u76ee\u5f55) -l \u9664\u6587\u4ef6\u540d\u79f0\u5916\uff0c\u4ea6\u5c06\u6587\u4ef6\u578b\u6001\u3001\u6743\u9650\u3001\u62e5\u6709\u8005\u3001\u6587\u4ef6\u5927\u5c0f\u7b49\u8d44\u8baf\u8be6\u7ec6\u5217\u51fa -r \u5c06\u6587\u4ef6\u4ee5\u76f8\u53cd\u6b21\u5e8f\u663e\u793a(\u539f\u5b9a\u4f9d\u82f1\u6587\u5b57\u6bcd\u6b21\u5e8f) -t \u5c06\u6587\u4ef6\u4f9d\u5efa\u7acb\u65f6\u95f4\u4e4b\u5148\u540e\u6b21\u5e8f\u5217\u51fa -F \u5728\u5217\u51fa\u7684\u6587\u4ef6\u540d\u79f0\u540e\u52a0\u4e00\u7b26\u53f7\uff1b\u4f8b\u5982\u53ef\u6267\u884c\u6863\u5219\u52a0 \"*\", \u76ee\u5f55\u5219\u52a0 \"/\" -R \u9012\u5f52\u5217\u51fa\u5b50\u76ee\u5f55 -S \u6309\u6587\u4ef6\u5927\u5c0f\u6392\u5e8f\uff0c\u4ece\u5927\u5230\u5c0f -1 \u6309\u4e00\u4e2a\u6587\u4ef6\u4e00\u884c\u5217\u51fa -t \u6309\u6587\u4ef6\u65f6\u95f4\u6392\u5e8f\uff0c\u6700\u65b0\u7684\u5728\u524d -U \u4e0d\u6392\u5e8f\u8f93\u51fa\uff0c\u6309\u76ee\u5f55\u5b58\u653e\u987a\u5e8f\u5217\u51fa -u \u914d\u5408 -lt \uff0c\u6309\u8bbf\u95ee\u65f6\u95f4\u6392\u5e8f\u5e76\u663e\u793a\uff1b\u914d\u5408 -l \uff0c\u663e\u793a\u8bbf\u95ee\u65f6\u95f4\u5e76\u6309\u540d\u79f0\u6392\u5e8f\uff1b \u5426\u5219\u6309\u8bbf\u95ee\u65f6\u95f4\u6392\u5e8f\uff0c\u6700\u65b0\u7684\u5728\u524d -X \u6309\u6587\u4ef6\u6269\u5c55\u540d\u5b57\u6bcd\u987a\u5e8f\u6392\u5e8f\u8f93\u51fa -F \u5bf9\u4e0d\u540c\u7c7b\u578b\u6587\u4ef6\u663e\u793a\u65f6\u9644\u52a0\u4e0d\u540c\u7684\u7b26\u53f7\uff0c * / = > @ | \u4e4b\u4e00 ls \u547d\u4ee4\u67e5\u770b\u4e0d\u540c\u6587\u4ef6\u662f\u7684\u989c\u8272\uff0c\u7531 /etc/DIR_COLORS \u548c\u53d8\u91cf @LS_COLORS \u5b9a\u4e49\u3002 2.5.\u6587\u4ef6\u72b6\u6001stat \u00b6 \u6bcf\u4e2a\u6587\u4ef6\u6709\u4e09\u4e2a\u65f6\u95f4\u6233\uff1a \u8bbf\u95ee\u65f6\u95f4 Access Time atime : \u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u3002 \u4fee\u6539\u65f6\u95f4 Modify Time mtime : \u6539\u53d8\u6587\u4ef6\u5185\u5bb9\uff08\u6570\u636e\uff09\u3002 \u6539\u53d8\u65f6\u95f4 Change Time ctime : \u5143\u6570\u636e\u53d1\u751f\u6539\u53d8\u3002 \u8bfb\u53d6\u4e09\u4e2a\u65f6\u95f4\u6233\u7684\u547d\u4ee4 stat \uff1a stat /etc/fstab \u8f93\u51fa\u7ed3\u679c\uff1a File: /etc/fstab Size: 927 Blocks: 8 IO Block: 4096 regular file Device: 30h/48d Inode: 263 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2022-10-31 10:26:34.987466959 +0800 Modify: 2022-06-24 14:50:24.387992912 +0800 Change: 2022-06-24 14:50:24.387992912 +0800 Birth: 2022-06-24 14:50:23.755992937 +0800 2.6.\u786e\u5b9a\u6587\u4ef6\u7c7b\u578b \u00b6 \u547d\u4ee4 file \u68c0\u67e5\u6587\u4ef6\u7c7b\u578b\u3002 -b \uff1a\u5217\u51fa\u8fa8\u8bc6\u7ed3\u679c\u65f6\uff0c\u4e0d\u663e\u793a\u6587\u4ef6\u540d\u79f0\u3002 -c \uff1a\u8be6\u7ec6\u663e\u793a\u6307\u4ee4\u6267\u884c\u8fc7\u7a0b\uff0c\u4fbf\u4e8e\u6392\u9519\u6216\u5206\u6790\u7a0b\u5e8f\u6267\u884c\u7684\u60c5\u5f62\u3002 -f <\u540d\u79f0\u6587\u4ef6> \uff1a\u6307\u5b9a\u540d\u79f0\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u6587\u4ef6\u540d\u79f0\u65f6\uff0c\u8ba9file\u4f9d\u5e8f\u8fa8\u8bc6\u8fd9\u4e9b\u6587\u4ef6\uff0c\u683c\u5f0f\u4e3a\u6bcf\u5217\u4e00\u4e2a\u6587\u4ef6\u540d\u79f0\u3002 -L \uff1a \u76f4\u63a5\u663e\u793a\u7b26\u53f7\u8fde\u63a5\u6240\u6307\u5411\u7684\u6587\u4ef6\u7684\u7c7b\u522b\u3002 -v \uff1a \u663e\u793a\u7248\u672c\u4fe1\u606f\u3002 -z \uff1a \u5c1d\u8bd5\u53bb\u89e3\u8bfb\u538b\u7f29\u6587\u4ef6\u7684\u5185\u5bb9\u3002 \u7f16\u8f91\u6587\u4ef6 list.txt \u5305\u542b\u4e00\u4e0b\u5185\u5bb9\uff1a /etc/ /bin /etc/issue \u8fd0\u884c\u547d\u4ee4 file -f list.txt \uff0c\u7ed3\u679c\u5982\u4e0b\uff1a /etc/: directory /bin: directory /etc/issue: symbolic link to ../run/issue 2.7.\u6587\u4ef6\u7f16\u7801\u8f6c\u6362 \u00b6 iconv \u547d\u4ee4\u7528\u4e8e\u5c06\u4e00\u79cd\u7f16\u7801\u4e2d\u7684\u67d0\u4e9b\u6587\u672c\u8f6c\u6362\u4e3a\u53e6\u4e00\u79cd\u7f16\u7801\u3002 \u5982\u679c\u6ca1\u6709\u63d0\u4f9b\u8f93\u5165\u6587\u4ef6\uff0c\u5219\u5b83\u4ece\u6807\u51c6\u8f93\u5165\u4e2d\u8bfb\u53d6\u3002 \u540c\u6837\uff0c\u5982\u679c\u6ca1\u6709\u7ed9\u51fa\u8f93\u51fa\u6587\u4ef6\uff0c\u90a3\u4e48\u5b83\u4f1a\u5199\u5165\u6807\u51c6\u8f93\u51fa\u3002 \u5982\u679c\u6ca1\u6709\u63d0\u4f9b from-encoding \u6216 to-encoding \uff0c\u5219\u5b83\u4f7f\u7528\u5f53\u524d\u672c\u5730\u7684\u5b57\u7b26\u7f16\u7801\u3002 \u5c06\u6587\u672c\u4ece ISO 8859-15 \u5b57\u7b26\u7f16\u7801\u8f6c\u6362\u4e3a UTF-8\uff0c\u8bfb\u5165 input.txt \uff0c\u8f93\u51fa output.txt \u3002 iconv -f ISO-8859-15 -t UTF-8 < input.txt > output.txt \u4ece UTF-8 \u8f6c\u6362\u4e3a ASCII\uff0c\u5c3d\u53ef\u80fd\u8fdb\u884c\u97f3\u8bd1\uff08transliterating\uff09\uff1a echo abc \u00df \u03b1 \u20ac \u00e0\u1e03\u00e7 | iconv -f UTF-8 -t ASCII//TRANSLIT \u8fd0\u884c\u7ed3\u679c\uff1a abc ss ? EUR abc 2.8.\u901a\u914d\u7b26 \u00b6 \u901a\u914d\u7b26\uff0c\u6307\u5305\u542b\u8fd9\u4e9b\u5b57\u7b26\u7684\u5b57\u7b26\u4e32 ? \uff1a\u8868\u793a\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26 * \uff1a\u8868\u793a\u4efb\u610f\u957f\u5ea6\u7684\u4efb\u610f\u5b57\u7b26 [] \uff1a\u5339\u914d\u6307\u5b9a\u8303\u56f4\u5185\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26 [abcd] \uff1a\u5339\u914dabcd\u4e2d\u7684\u4efb\u4f55\u4e00\u4e2a\u5b57\u7b26 [a-z] \uff1a\u5339\u914d\u8303\u56f4a\u5230z\u5185\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26 [!abcd] \uff1a\u4e0d\u5339\u914d\u62ec\u53f7\u91cc\u9762\u4efb\u4f55\u4e00\u4e2a\u5b57\u7b26 {} \uff1a\u8868\u793a\u751f\u6210\u5e8f\u5217\uff0c\u4ee5\u9017\u53f7\u5206\u5272\uff0c\u4e0d\u80fd\u6709\u7a7a\u683c \u793a\u4f8b\uff1a $ touch file_ { a..z } .txt $ touch file_ { A..Z } .txt $ ls file_a.txt file_C.txt file_f.txt file_H.txt file_k.txt file_M.txt file_p.txt file_R.txt file_u.txt file_W.txt file_z.txt file_A.txt file_d.txt file_F.txt file_i.txt file_K.txt file_n.txt file_P.txt file_s.txt file_U.txt file_x.txt file_Z.txt file_b.txt file_D.txt file_g.txt file_I.txt file_l.txt file_N.txt file_q.txt file_S.txt file_v.txt file_X.txt file_B.txt file_e.txt file_G.txt file_j.txt file_L.txt file_o.txt file_Q.txt file_t.txt file_V.txt file_y.txt file_c.txt file_E.txt file_h.txt file_J.txt file_m.txt file_O.txt file_r.txt file_T.txt file_w.txt file_Y.txt $ ls file_ [ a..d ] .* file_a.txt file_d.txt $ ls file_ [ a...d ] .* file_a.txt file_d.txt $ ls file_ [ ad ] .* file_a.txt file_d.txt $ ls file_ [ a-c ] .* file_a.txt file_A.txt file_b.txt file_B.txt file_c.txt $ ls file_ [ a-C ] .* file_a.txt file_A.txt file_b.txt file_B.txt file_c.txt file_C.txt $ ls file_ [ !d-W ] .* file_a.txt file_b.txt file_c.txt file_x.txt file_y.txt file_z.txt file_A.txt file_B.txt file_C.txt file_X.txt file_Y.txt file_Z.txt \u6bd4\u8f83\u6709\u65e0 * \u7684\u533a\u522b\uff1a $ ls -a * file_a.txt file_D.txt file_h.txt file_K.txt file_o.txt file_R.txt file_v.txt file_Y.txt file_A.txt file_e.txt file_H.txt file_l.txt file_O.txt file_s.txt file_V.txt file_z.txt file_b.txt file_E.txt file_i.txt file_L.txt file_p.txt file_S.txt file_w.txt file_Z.txt file_B.txt file_f.txt file_I.txt file_m.txt file_P.txt file_t.txt file_W.txt file_c.txt file_F.txt file_j.txt file_M.txt file_q.txt file_T.txt file_x.txt file_C.txt file_g.txt file_J.txt file_n.txt file_Q.txt file_u.txt file_X.txt file_d.txt file_G.txt file_k.txt file_N.txt file_r.txt file_U.txt file_y.txt $ ls -a . file_C.txt file_g.txt file_J.txt file_n.txt file_Q.txt file_u.txt file_X.txt .. file_d.txt file_G.txt file_k.txt file_N.txt file_r.txt file_U.txt file_y.txt file_a.txt file_D.txt file_h.txt file_K.txt file_o.txt file_R.txt file_v.txt file_Y.txt file_A.txt file_e.txt file_H.txt file_l.txt file_O.txt file_s.txt file_V.txt file_z.txt file_b.txt file_E.txt file_i.txt file_L.txt file_p.txt file_S.txt file_w.txt file_Z.txt file_B.txt file_f.txt file_I.txt file_m.txt file_P.txt file_t.txt file_W.txt file_c.txt file_F.txt file_j.txt file_M.txt file_q.txt file_T.txt file_x.txt 2.9.\u5b57\u7b26\u96c6 \u00b6 [:alpha:] \uff1a\u8868\u793a\u6240\u6709\u7684\u5b57\u6bcd\uff08\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff09\uff0c\u6548\u679c\u540c [a-z] [:digit:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u6570\u5b57\uff0c\u6548\u679c\u540c [0-9] [:xdigit:] \uff1a\u8868\u793a\u5341\u516d\u8fdb\u5236\u6570\u5b57 [:lower:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5c0f\u5199\u5b57\u6bcd [:upper:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5927\u5199\u5b57\u6bcd [:alnum:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5b57\u6bcd\u6216\u6570\u5b57 [:blank:] \uff1a\u8868\u793a\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u548c\u5236\u8868\u7b26\uff09 [:space:] \uff1a\u8868\u793a\u5305\u62ec\u7a7a\u683c\u3001\u5236\u8868\u7b26\uff08\u6c34\u5e73\u548c\u5782\u76f4\uff09\u3001\u6362\u884c\u7b26\u3001\u56de\u8f66\u7b26\u7b49\u5404\u79cd\u7c7b\u578b\u7684\u7a7a\u767d\uff0c\u6bd4 [:blank:] \u8303\u56f4\u66f4\u5e7f [:cntrl:] \uff1a\u8868\u793a\u4e0d\u53ef\u6253\u5370\u7684\u63a7\u5236\u5b57\u7b26\uff08\u9000\u683c\u3001\u5220\u9664\u3001\u8b66\u94c3\u7b49\uff09 [:graph:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u7684\u975e\u7a7a\u767d\u5b57\u7b26 [:print:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u5b57\u7b26 [:punct:] \uff1a\u8868\u793a\u6807\u70b9\u7b26\u53f7 \u4e3e\u4f8b\uff1a ls -d [[:alpha:]] \u5373 ls -d [a-Z] \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u5355\u4e2a\u5b57\u6bcd\u7684\u76ee\u5f55\u548c\u6587\u4ef6 ls -d *[[:digit:]] \u5373 ls -d *[0-9] \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u4ee5\u6570\u5b57\u7ed3\u5c3e\u7684\u76ee\u5f55\u548c\u6587\u4ef6 ls [[:lower:]].txt \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u4ee5\u5355\u4e2a\u5c0f\u5199\u5b57\u6bcd\u4e3a\u540d\u7684.txt\u683c\u5f0f\u7684\u6587\u4ef6 ls -d [[:alnum:]] \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u5355\u4e2a\u5b57\u6bcd\uff08\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff09\u6216\u6570\u5b57\u4e3a\u540d\u7684\u76ee\u5f55\u6216\u6587\u4ef6 2.10.\u7279\u6b8a\u7b26\u53f7 \u00b6 | \uff1a\u7ba1\u9053\u7b26\uff0c\u6216\u8005\uff08\u6b63\u5219\uff09 > \uff1a\u8f93\u51fa\u91cd\u5b9a\u5411 >> \uff1a\u8f93\u51fa\u8ffd\u52a0\u91cd\u5b9a\u5411 < \uff1a\u8f93\u5165\u91cd\u5b9a\u5411 << \uff1a\u8ffd\u52a0\u8f93\u5165\u91cd\u5b9a\u5411 ~ \uff1a\u5f53\u524d\u7528\u6237\u5bb6\u76ee\u5f55 $() \uff1a\u5f15\u7528\u547d\u4ee4\u88ab\u6267\u884c\u540e\u7684\u7ed3\u679c $ \uff1a\u4ee5...\u7ed3\u5c3e\uff08\u6b63\u5219\uff09 ^ \uff1a\u4ee5...\u5f00\u5934\uff08\u6b63\u5219\uff09 * \uff1a\u5339\u914d\u5168\u90e8\u5b57\u7b26\uff0c\u901a\u914d\u7b26 ? \uff1a\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26\uff0c\u901a\u914d\u7b26 # \uff1a\u6ce8\u91ca & \uff1a\u8ba9\u7a0b\u5e8f\u6216\u811a\u672c\u5207\u6362\u5230\u540e\u53f0\u6267\u884c && \uff1a\u5e76\u4e14\uff0c\u540c\u65f6\u6210\u7acb [] \uff1a\u8868\u793a\u4e00\u4e2a\u8303\u56f4\uff08\u6b63\u5219\uff0c\u901a\u914d\u7b26\uff09 {} \uff1a\u4ea7\u751f\u4e00\u4e2a\u5e8f\u5217\uff08\u901a\u914d\u7b26\uff09 . \uff1a\u5f53\u524d\u76ee\u5f55\u7684\u786c\u94fe\u63a5 .. \uff1a\u4e0a\u7ea7\u76ee\u5f55\u7684\u786c\u94fe\u63a5 2.11.\u5237\u65b0\u6587\u4ef6\u65f6\u95f4 touch \u00b6 touch \u547d\u4ee4\u53ef\u4ee5\u521b\u5efa\u7a7a\u6587\u4ef6\uff0c\u4e5f\u53ef\u4ee5\u5237\u65b0\u6587\u4ef6\u65f6\u95f4\u3002\u53c2\u6570\u5982\u4e0b\uff1a -a \uff1a\u4ec5\u6539\u53d8 atime \u548c ctime -m \uff1a\u4ec5\u6539\u53d8 mtime \u548c ctime -t [[CC]YY]MMDDhhmm[.ss] \uff1a\u6307\u5b9a atime \u548c mtime -c \uff1a\u5982\u679c\u6587\u4ef6\u4e0d\u5b58\u5728\uff0c\u5219\u4e0d\u521b\u5efa $ touch file1 $ touch file2 $ ll -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 -rw-r--r--. 1 vagrant wheel 0 Nov 8 20 :28 file2 \u521b\u5efa\u6587\u4ef6file-non.log\uff0c\u5982\u679c\u4e0d\u5b58\u5728\u5219\u4e0d\u521b\u5efa\u3002 touch -c file-non.log \u66f4\u65b0 file1 \u7684\u65f6\u95f4\u548c file2 \u4e00\u81f4\u3002 $ touch -r file1 file2 $ ll -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 -rw-r--r--. 1 vagrant wheel 0 Nov 8 20 :49 file2 \u6307\u5b9a file2 \u7684\u65f6\u95f4\u3002 202210012135.25 \u4ee3\u8868 YYYYMMDDHHMM.SS \u3002 $ touch -t 202210012135 .25 file2 $ ll -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 -rw-r--r--. 1 vagrant wheel 0 Oct 1 21 :35 file2 $ stat file2 File: file2 Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: fd02h/64770d Inode: 140 Links: 1 Access: ( 0644 /-rw-r--r-- ) Uid: ( 1000 / vagrant ) Gid: ( 10 / wheel ) Context: unconfined_u:object_r:user_home_t:s0 Access: 2022 -10-01 21 :35:25.000000000 +0800 Modify: 2022 -10-01 21 :35:25.000000000 +0800 Change: 2022 -11-08 20 :56:18.306315887 +0800 Birth: 2022 -11-08 20 :28:37.809551441 +0800 2.12.\u590d\u5236\u6587\u4ef6\u548c\u76ee\u5f55 cp \u00b6 cp \u547d\u4ee4\uff1aCopy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY. \u5e38\u7528\u53c2\u6570\uff1a -a \uff1a\u5f52\u6863\uff0c\u76f8\u5f53\u4e8e -dR --preserv=all \u53c2\u6570\u7ec4\u5408\uff0c\u5e38\u7528\u4e8e\u5907\u4efd\u3002 -d \uff1a\u4e0d\u590d\u5236\u539f\u6587\u4ef6\uff0c\u53ea\u590d\u5236\u94fe\u63a5\u540d\u3002\u76f8\u5f53\u4e8e --no-dereference --preserve=links \u53c2\u6570\u7ec4\u5408\u3002 -f \uff1a\u8986\u76d6\u5df2\u7ecf\u5b58\u5728\u7684\u76ee\u6807\u6587\u4ef6\u3002 -i \uff1a\u8986\u76d6\u76ee\u6807\u6587\u4ef6\u4e4b\u524d\u7ed9\u51fa\u63d0\u793a\u3002 -p \uff1a\u9664\u590d\u5236\u6587\u4ef6\u7684\u5185\u5bb9\u5916\uff0c\u4e5f\u590d\u5236\u6587\u4ef6\u6743\u9650\uff0c\u65f6\u95f4\u6233\uff0c\u5c5e\u4e3b\u5c5e\u7ec4\u3002\u76f8\u5f53\u4e8e --preserve=mode,ownership,timestamps \u3002 -r, -R, --recursive \uff1a\u9012\u5f52\u590d\u5236\u76ee\u5f55\u6240\u5305\u542b\u7684\u5168\u90e8\u5185\u5bb9\u3002 -l \uff1a\u4e0d\u590d\u5236\u6587\u4ef6\uff0c\u53ea\u662f\u751f\u6210\u786c\u94fe\u63a5\u6587\u4ef6\u3002 \u53c2\u6570 --preserv \u53ef\u9009\u9879\uff1a mode\uff1a\u6743\u9650 ownership\uff1a\u5c5e\u4e3b\u5c5e\u7ec4 timestamp links xattr context all \u521b\u5efa\u6d4b\u8bd5\u76ee\u5f55\u3002 cd ~ mkdir test \u5bf9\u6bd4\u53c2\u6570 -p \u7684\u5dee\u522b\u3002 $ cp /etc/issue ~/test/issue1 $ cp -p /etc/issue ~/test/issue1 $ sudo cp /etc/issue ~/test/issue3 $ sudo cp -p /etc/issue ~/test/issue4 $ ll ~/test -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 issue1 -rw-r--r--. 1 vagrant wheel 23 Jul 21 01 :10 issue2 -rw-r--r--. 1 root root 23 Nov 8 22 :43 issue3 -rw-r--r--. 1 root root 23 Jul 21 01 :10 issue4 $ ll /etc/issue -rw-r--r--. 1 root root 23 Jul 21 01 :10 /etc/issue \u5bf9\u6bd4\u53c2\u6570 -r \u3002 $ sudo cp /etc/sysconfig/ ~/test cp: -r not specified ; omitting directory '/etc/sysconfig/' $ sudo cp -r /etc/sysconfig/ ~/test $ tree -L 2 ~/test /home/vagrant/test \u251c\u2500\u2500 issue1 \u251c\u2500\u2500 issue2 \u251c\u2500\u2500 issue3 \u251c\u2500\u2500 issue4 \u2514\u2500\u2500 sysconfig \u251c\u2500\u2500 anaconda \u251c\u2500\u2500 atd \u251c\u2500\u2500 chronyd \u251c\u2500\u2500 cpupower \u251c\u2500\u2500 crond \u251c\u2500\u2500 firewalld \u251c\u2500\u2500 irqbalance \u251c\u2500\u2500 kdump \u251c\u2500\u2500 kernel \u251c\u2500\u2500 man-db \u251c\u2500\u2500 network \u251c\u2500\u2500 network-scripts \u251c\u2500\u2500 nftables.conf \u251c\u2500\u2500 raid-check \u251c\u2500\u2500 rsyslog \u251c\u2500\u2500 run-parts \u251c\u2500\u2500 samba \u251c\u2500\u2500 selinux -> ../selinux/config \u251c\u2500\u2500 smartmontools \u2514\u2500\u2500 sshd \u53c2\u6570 -b \uff0c\u5982\u679c\u76ee\u6807\u6587\u4ef6\u5b58\u5728\uff0c\u590d\u5236\u524d\u5148\u5c06\u539f\u6587\u4ef6\u590d\u5236\u5e76\u4ee5 ~ \u7ed3\u5c3e\u3002 $ ll /etc/motd -rw-r--r--. 1 root root 0 Jun 23 2020 /etc/motd $ ll ~/test/issue1 -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 /home/vagrant/test/issue1 $ cp -b /etc/motd ~/test/issue $ cp -b /etc/motd ~/test/issue1 $ ll ~/test -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :00 issue -rw-r--r--. 1 vagrant wheel 0 Nov 8 22 :57 issue1 -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 issue1~ -rw-r--r--. 1 vagrant wheel 23 Jul 21 01 :10 issue2 -rw-r--r--. 1 root root 23 Nov 8 22 :43 issue3 -rw-r--r--. 1 root root 23 Jul 21 01 :10 issue4 drwxr-xr-x. 3 root root 4096 Nov 8 22 :49 sysconfig \u53c2\u6570 --backup=numbered \u4f1a\u5728\u590d\u5236\u539f\u6587\u4ef6\u65f6\u52a0\u4e0a\u6570\u5b57\u5e8f\u53f7\uff0c\u5e8f\u53f71\u4ee3\u8868\u539f\u59cb\u7684\u6587\u4ef6\u3002 $ cp --backup = numbered /etc/motd ~/test/issue2 $ cp --backup = numbered /etc/motd ~/test/issue2 $ cp --backup = numbered /etc/motd ~/test/issue2 $ ll ~/test -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :00 issue -rw-r--r--. 1 vagrant wheel 0 Nov 8 22 :57 issue1 -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 issue1~ -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :09 issue2 -rw-r--r--. 1 vagrant wheel 23 Jul 21 01 :10 issue2.~1~ -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :09 issue2.~2~ -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :09 issue2.~3~ -rw-r--r--. 1 root root 23 Nov 8 22 :43 issue3 -rw-r--r--. 1 root root 23 Jul 21 01 :10 issue4 drwxr-xr-x. 3 root root 4096 Nov 8 22 :49 sysconfig 2.13.\u79fb\u52a8\u6587\u4ef6\u548c\u76ee\u5f55 mv \u00b6 mv \u547d\u4ee4\u3002Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY. \u5e38\u7528\u53c2\u6570\uff1a -v \uff1a\u663e\u793a\u547d\u4ee4\u6267\u884c\u7684\u4fe1\u606f\u3002 -i \uff1a\u4ea4\u4e92\u5f0f\uff0c\u6bd4\u5982\uff0c\u91cd\u540d\u8986\u76d6\u65f6\u4f1a\u63d0\u5347\u662f\u5426\u786e\u8ba4\u3002 -b \uff1a\u8986\u76d6\u65f6\u521b\u5efa\u5907\u4efd\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u79fb\u52a8\u6587\u4ef6\u5c06\u4f1a\u8986\u76d6\u5df2\u5b58\u5728\u7684\u76ee\u6807\u6587\u4ef6\u3002 \u79fb\u52a8\u591a\u4e2a\u6587\u4ef6\u5230\u67d0\u4e2a\u76ee\u5f55\u3002 mv file1 file2 file3 ~/dest mv file* ~/dest \u79fb\u52a8\u76ee\u5f55\u3002 mv ~/test ~/dest/new/one/ \u91cd\u547d\u540d\u6587\u4ef6\u548c\u76ee\u5f55\u3002 mv file1 file2 mv ~/test ~/dest 2.14.\u91cd\u547d\u540d\u6587\u4ef6\u548c\u76ee\u5f55 rename \u00b6 rename \u547d\u4ee4\u3002\u5206\u4e3aperl\u7248\u672c\u548cC\u8bed\u8a00\u7248\u672c\u3002 \u533a\u5206\u65b9\u6cd5: rename --version \u3002\u5982\u679c\u8fd4\u56de\u7ed3\u679c\u4e2d\u5305\u542b util-linux \uff0c\u8bf4\u660e\u662fC\u8bed\u8a00\u7248\u672c, \u53cd\u4e4b\u662fPerl\u7248\u672c\u3002 openSUSE\u548cRocy\u662fC\u8bed\u8a00\u7248\u672c\uff0cUbuntu\u662fPerl\u7248\u672c\u3002 \u4e3e\u4f8b\uff1a\u4fee\u6539\u5f53\u524d\u76ee\u5f55\u6240\u6709\u6269\u5c55\u540d\u4e3a s \u7684\u6587\u4ef6\u6539\u4e3a\u6269\u5c55\u540d\u4e3a gz \u3002 $ touch file { 1 ..3 } .s $ rename -v '.s' '.gz' *.s $ rename -v \".s\" \".gz\" *.s ` file1.txt ' -> `file1.html' ` file2.txt ' -> `file2.html' ` file3.txt ' -> `file3.html' \u5728Ubuntu\u4e0a\u5b8c\u6210\u540c\u6837\u4efb\u52a1\uff0c\u5219\u9700\u8981\u4f7f\u7528\u6b63\u5219\u3002 rename -v \"s/s/gz/g\" *.s 2.15.\u5220\u9664\u6587\u4ef6 rm \u00b6 rm \u547d\u4ee4\u3002\u5efa\u8bae\u4f7f\u7528 mv \u547d\u4ee4\u4ee3\u66ff rm \u547d\u4ee4\u3002 2.16.\u76ee\u5f55\u64cd\u4f5c\u547d\u4ee4 \u00b6 \u521b\u5efa\u76ee\u5f55\uff1a mkdir \u5220\u9664\u7a7a\u76ee\u5f55\uff1a rmdir \u5220\u9664\u975e\u7a7a\u76ee\u5f55\uff1a rm -r \u663e\u793a\u76ee\u5f55\u6811\uff1a tree 2.17.\u7ec3\u4e60 \u00b6 \u663e\u793a /etc \u76ee\u5f55\u4e0b\u6240\u6709\u4ee5 l \u5f00\u5934\uff0c\u4ee5\u4e00\u4e2a\u5c0f\u5199\u5b57\u6bcd\u7ed3\u5c3e\uff0c\u4e14\u4e2d\u95f4\u51fa\u73b0\u81f3\u5c11\u4e00\u4f4d\u6570\u5b57\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls -d /etc/l* [ 0 -9 ] * [ a-z ] ls -d /etc/l* [[ :digit: ]] * [[ :lower: ]] \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/lam4you sudo mkdir /etc/lam5you \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/lam4you sudo rm -rf /etc/lam5you \u663e\u793a /etc \u76ee\u5f55\u4e0b\u4ee5\u4efb\u610f\u4e00\u4f4d\u6570\u5b57\u5f00\u5934\uff0c\u4e14\u4ee5\u975e\u6570\u5b57\u7ed3\u5c3e\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ 0 -9 ] * [ !0-9 ] ls /etc/ [[ :digit: ]] * [ ^ [ :digit: ]] \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/5am4yo. sudo mkdir /etc/5am5yo. \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/5am4yo. sudo rm -rf /etc/5am5yo. \u663e\u793a /etc \u76ee\u5f55\u4e0b\u4ee5\u975e\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u9762\u8ddf\u4e86\u4e00\u4e2a\u5b57\u6bcd\u53ca\u5176\u5b83\u4efb\u610f\u957f\u5ea6\u4efb\u610f\u5b57\u7b26\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ !a-zA-Z ][ a-zA-Z ] * ls /etc/ [ ^ [ :alpha: ]][[ :alpha: ]] * \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/5Ato3 sudo mkdir /etc/6dog6 \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/5Ato3 sudo rm -rf /etc/6dog6 \u663e\u793a /etc \u76ee\u5f55\u4e0b\uff0c\u6240\u6709\u4ee5 rc \u5f00\u5934\uff0c\u5e76\u540e\u9762\u662f0-6\u4e4b\u95f4\u7684\u6570\u5b57\uff0c\u5176\u5b83\u4e3a\u4efb\u610f\u5b57\u7b26\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/rc [ 0 -6 ] * \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/rc5come sudo mkdir /etc/rc0123 \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/rc5come sudo rm -rf /etc/rc0123 \u663e\u793a /etc \u76ee\u5f55\u4e0b\uff0c\u6240\u6709\u4ee5 .conf \u7ed3\u5c3e\uff0c\u4e14\u4ee5 m \u3001 n \u3001 r \u3001 p \u5f00\u5934\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ mnrp ] *.conf \u53ea\u663e\u793a /root \u4e0b\u7684\u9690\u85cf\u6587\u4ef6\u548c\u76ee\u5f55\u5217\u8868\u3002 ls .* \u53ea\u663e\u793a/etc\u4e0b\u975e\u9690\u85cf\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ ^. ] */ \u5c06 /etc \u76ee\u5f55\u4e0b\u6240\u6709\u6587\u4ef6\uff0c\u5907\u4efd\u5230 ~/test/ \u76ee\u5f55\u4e0b\uff0c\u5e76\u8981\u6c42\u5b50\u76ee\u5f55\u683c\u5f0f\u4e3a backupYYYY-mm-dd \uff0c\u5907\u4efd\u8fc7\u7a0b\u53ef\u89c1\u3002 sudo cp -av /etc/ ~/test/backup ` date +%F ` sudo cp -av /etc/ ~/test/backup ` date +%F_%H-%M-%S ` \u521b\u5efa\u76ee\u5f55 ~/testdir/dir1/x \uff0c ~/testdir/dir1/y \uff0c ~/testdir/dir1/x/a \uff0c ~/testdir/dir1/x/b \uff0c ~/testdir/dir1/y/a \uff0c ~/testdir/dir1/y/b \u3002 $ mkdir -p ~/testdir/dir1/ { x,y } / { a,b } $ tree ~/testdir/dir1/ /home/vagrant/testdir/dir1/ \u251c\u2500\u2500 x \u2502 \u251c\u2500\u2500 a \u2502 \u2514\u2500\u2500 b \u2514\u2500\u2500 y \u251c\u2500\u2500 a \u2514\u2500\u2500 b \u521b\u5efa\u76ee\u5f55 ~/testdir/dir2/x \uff0c ~/testdir/dir2/y \uff0c ~/testdir/dir2/x/a \uff0c ~/testdir/dir2/x/b \u3002 $ mkdir -p ~/testdir/dir2/ { x/ { a,b } ,y } $ tree ~/testdir/dir2/ /home/vagrant/testdir/dir2/ \u251c\u2500\u2500 x \u2502 \u251c\u2500\u2500 a \u2502 \u2514\u2500\u2500 b \u2514\u2500\u2500 y \u521b\u5efa\u76ee\u5f55 ~/testdir/dir3 \u3001 ~/testdir/dir4 \u3001 ~/testdir/dir5 \u3001 ~/testdir/dir5/dir6 \u3001 ~/testdir/dir5/dir7 \u3002 $ mkdir -p ~/testdir/dir { 3 ,4,5/dir { 6 ,7 }} $ tree ~/testdir /home/vagrant/testdir \u251c\u2500\u2500 dir1 \u2502 \u251c\u2500\u2500 x \u2502 \u2502 \u251c\u2500\u2500 a \u2502 \u2502 \u2514\u2500\u2500 b \u2502 \u2514\u2500\u2500 y \u2502 \u251c\u2500\u2500 a \u2502 \u2514\u2500\u2500 b \u251c\u2500\u2500 dir2 \u2502 \u251c\u2500\u2500 x \u2502 \u2502 \u251c\u2500\u2500 a \u2502 \u2502 \u2514\u2500\u2500 b \u2502 \u2514\u2500\u2500 y \u251c\u2500\u2500 dir3 \u251c\u2500\u2500 dir4 \u2514\u2500\u2500 dir5 \u251c\u2500\u2500 dir6 \u2514\u2500\u2500 dir7 3.\u4e03\u79cd\u6587\u4ef6\u7c7b\u578b \u00b6 \u666e\u901a\u6587\u4ef6\uff08Normal Files\uff09 ASCII \u6587\u672c\u6587\u4ef6 \u53ef\u6267\u884c\u6587\u4ef6 \u56fe\u5f62\u6587\u4ef6 \u76ee\u5f55\uff08Directories\uff09 \u7ec4\u7ec7\u89c4\u5212\u78c1\u76d8\u4e0a\u7684\u6587\u4ef6 \u5305\u542b\u6587\u4ef6\u548c\u5b50\u76ee\u5f55 \u5b9e\u73b0\u5206\u5c42\u6587\u4ef6\u7cfb\u7edf \u94fe\u63a5\uff08Links\uff09 \u786c\u94fe\u63a5\uff08Hard links\uff09 \u78c1\u76d8\u4e0a\u6587\u4ef6\u7684\u8f85\u52a9\u6587\u4ef6\u540d \u591a\u4e2a\u6587\u4ef6\u540d\u5f15\u7528\u5355\u4e2a inode \u5f15\u7528\u7684\u6587\u4ef6\u5fc5\u987b\u5b58\u5728\u4e8e\u540c\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u4e2d \u7b26\u53f7\u94fe\u63a5\uff08Symbolic links\uff09 \u5bf9\u78c1\u76d8\u4e0a\u5176\u4ed6\u6587\u4ef6\u7684\u5f15\u7528 inode \u5305\u542b\u5bf9\u53e6\u4e00\u4e2a\u6587\u4ef6\u540d\u7684\u5f15\u7528 \u88ab\u5f15\u7528\u7684\u6587\u4ef6\u53ef\u4ee5\u5b58\u5728\u4e8e\u540c\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u4e2d\uff0c\u4e5f\u53ef\u4ee5\u5b58\u5728\u4e8e\u5176\u4ed6\u6587\u4ef6\u7cfb\u7edf\u4e2d \u7b26\u53f7\u94fe\u63a5\u53ef\u4ee5\u5f15\u7528\u4e0d\u5b58\u5728\u7684\u6587\u4ef6\uff08\u65ad\u5f00\u7684\u94fe\u63a5\uff09 \u5957\u63a5\u5b57Sockets - \u7528\u4e8e\u8fdb\u7a0b\u4e4b\u95f4\u7684\u53cc\u5411\u901a\u4fe1\u3002 \u7ba1\u9053\uff08Pipes\uff09(FIFOs) - \u7528\u4e8e\u4ece\u4e00\u4e2a\u8fdb\u7a0b\u5230\u53e6\u4e00\u4e2a\u8fdb\u7a0b\u7684\u5355\u5411\u901a\u4fe1\u3002 \u5757\u8bbe\u5907\uff08Block Devices\uff09 \u5b57\u7b26\u8bbe\u5907\uff08Character Devices\uff09 3.1.inode\u7ed3\u6784 \u00b6 \u6587\u4ef6\u50a8\u5b58\u5728\u786c\u76d8\u4e0a\uff0c\u786c\u76d8\u7684\u6700\u5c0f\u5b58\u50a8\u5355\u4f4d\u53eb\u505a\u201c\u6247\u533a\u201d\uff08Sector\uff09\u3002\u6bcf\u4e2a\u6247\u533a\u50a8\u5b58512\u5b57\u8282\uff08\u76f8\u5f53\u4e8e0.5KB\uff09\u3002 \u64cd\u4f5c\u7cfb\u7edf\u8bfb\u53d6\u786c\u76d8\u7684\u65f6\u5019\uff0c\u4e0d\u662f\u4e00\u4e2a\u4e00\u4e2a\u6247\u533a\u8bfb\u53d6\uff0c\u800c\u662f\u4e00\u6b21\u6027\u8fde\u7eed\u8bfb\u53d6\u591a\u4e2a\u6247\u533a\uff0c\u6211\u4eec\u79f0\u4e3a\u8bfb\u53d6\u4e00\u4e2a\u201c\u5757\u201d\uff08block\uff09\u3002 \u5e38\u89c1\u7684block\u7684\u5927\u5c0f\u662f4KB\uff08\u8fde\u7eed\u516b\u4e2asector\u7ec4\u6210\u4e00\u4e2ablock\uff09\u3002 \u591a\u4e2a\u6247\u533a\u7ec4\u6210\u7684block\u662f\u6587\u4ef6\u5b58\u53d6\u7684*\u6700\u5c0f\u5355\u4f4d*\u3002 \u6587\u4ef6\u6570\u636e\u50a8\u5b58\u5728block\u4e2d\uff0c\u6587\u4ef6\u7684\u5143\u4fe1\u606f\uff0c\u6bd4\u5982\u6587\u4ef6\u7684\u521b\u5efa\u8005\u3001\u521b\u5efa\u65e5\u671f\u3001\u6587\u5927\u5c0f\u7b49\uff0c\u5b58\u50a8\u5728inode\uff0c\u5373\u201c\u7d22\u5f15\u8282\u70b9\u201d\u3002 \u6bcf\u4e00\u4e2a\u6587\u4ef6\u90fd\u6709\u5bf9\u5e94\u7684inode\uff0c\u91cc\u9762\u5305\u542b\u4e86\u4e0e\u8be5\u6587\u4ef6\u6709\u5173\u7684\u4e00\u4e9b\u4fe1\u606f\u3002\u6ce8\u610f\uff0c\u9664\u4e86\u6587\u4ef6\u540d\u4ee5\u5916\u7684\u5176\u5b83\u6587\u4ef6\u4fe1\u606f\uff0c\u90fd\u5b58\u5728inode\u4e4b\u4e2d\u3002 inode\u5305\u542b\u6587\u4ef6\u7684\u5143\u4fe1\u606f\u4e3b\u8981\u6709\uff1a \u6587\u4ef6\u7684\u5b57\u8282\u6570 \u6587\u4ef6\u62e5\u6709\u8005\u7684 User ID \u6587\u4ef6\u7684 Group ID \u6587\u4ef6\u7684\u8bfb\u3001\u5199\u3001\u6267\u884c\u6743\u9650 \u6587\u4ef6\u7684\u65f6\u95f4\u6233\uff0c\u5171\u6709\u4e09\u4e2a\uff1actime\u6307inode\u4e0a\u4e00\u6b21\u53d8\u52a8\u7684\u65f6\u95f4\uff0cmtime\u6307\u6587\u4ef6\u5185\u5bb9\u4e0a\u4e00\u6b21\u53d8\u52a8\u7684\u65f6\u95f4\uff0catime\u6307\u6587\u4ef6\u4e0a\u4e00\u6b21\u6253\u5f00\u7684\u65f6\u95f4\u3002 \u94fe\u63a5\u6570\uff0c\u5373\u6709\u591a\u5c11\u6587\u4ef6\u540d\u6307\u5411\u8fd9\u4e2ainode \u6587\u4ef6\u6570\u636eblock\u7684\u4f4d\u7f6e \u67e5\u770binode\u4fe1\u606f\u7684\u547d\u4ee4 stat \uff1a $ stat file1 File: file1 Size: 5 Blocks: 8 IO Block: 4096 regular file Device: fd02h/64770d Inode: 143 Links: 1 Access: ( 0644 /-rw-r--r-- ) Uid: ( 1000 / vagrant ) Gid: ( 10 / wheel ) Context: unconfined_u:object_r:user_home_t:s0 Access: 2022 -11-08 20 :49:26.019678244 +0800 Modify: 2022 -11-08 20 :49:26.019678244 +0800 Change: 2022 -11-08 20 :49:26.028678455 +0800 Birth: 2022 -11-08 20 :49:26.019678244 +0800 \u683c\u5f0f\u5316\u786c\u76d8\u65f6\uff0c\u64cd\u4f5c\u7cfb\u7edf\u4f1a\u81ea\u52a8\u5c06\u786c\u76d8\u5206\u6210\u4e24\u4e2a\u533a\u57df\u3002\u4e00\u4e2a\u662f\u6570\u636e\u533a\uff0c\u5b58\u653e\u6587\u4ef6\u6570\u636e\u3002\u53e6\u4e00\u4e2a\u662finode\u533a\uff08inode table\uff09\uff0c\u5b58\u653einode\u6240\u5305\u542b\u7684\u6587\u4ef6\u7684\u5143\u4fe1\u606f\u3002 \u6bcf\u4e2ainode\u8282\u70b9\u7684\u5927\u5c0f\uff0c\u4e00\u822c\u662f128\u5b57\u8282\u6216256\u5b57\u8282\u3002inode\u8282\u70b9\u7684\u603b\u6570\uff0c\u5728\u683c\u5f0f\u5316\u65f6\u5c31\u786e\u5b9a\u4e86\uff0c\u4e00\u822c\u662f\u6bcf1KB\u6216\u6bcf2KB\u5c31\u8bbe\u7f6e\u4e00\u4e2ainode\u3002 \u5047\u5b9a\u4e00\u57571GB\u7684\u786c\u76d8\uff0c\u5982\u679c\u6bcf\u4e2ainode\u8282\u70b9\u7684\u5927\u5c0f\u4e3a128\u5b57\u8282\uff0c\u4e14\u6bcf1KB\u5c31\u8bbe\u7f6e\u4e00\u4e2ainode\uff0c\u5219inode table\u7684\u5927\u5c0f\u5c31\u4f1a\u8fbe\u5230128MB\uff0c\u5360\u6574\u5757\u786c\u76d8\u768412.8%\u3002 \u901a\u8fc7 df \u547d\u4ee4\u67e5\u770b\u6bcf\u4e2a\u786c\u76d8\u5206\u533a\u7684inode\u603b\u6570\u548c\u5df2\u7ecf\u4f7f\u7528\u7684\u6570\u91cf\u3002 \u7531\u4e8e\u6bcf\u4e2a\u6587\u4ef6\u90fd\u5fc5\u987b\u6709\u4e00\u4e2ainode\uff0c\u56e0\u6b64\u6709\u53ef\u80fd\u53d1\u751finode\u5df2\u7ecf\u7528\u5149\uff0c\u4f46\u662f\u786c\u76d8\u8fd8\u672a\u5b58\u6ee1\u7684\u60c5\u51b5\uff0c\u4e5f\u5c31\u65e0\u6cd5\u5728\u786c\u76d8\u4e0a\u521b\u5efa\u65b0\u6587\u4ef6\u3002 $ df -i Filesystem Inodes IUsed IFree IUse% Mounted on tmpfs 497897 872 497025 1 % /run /dev/mapper/ubuntu--vg-ubuntu--lv 3211264 81473 3129791 3 % / tmpfs 497897 1 497896 1 % /dev/shm tmpfs 497897 3 497894 1 % /run/lock /dev/sda2 131072 316 130756 1 % /boot tmpfs 99579 25 99554 1 % /run/user/1000 \u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u67e5\u770b\u6bcf\u4e2ainode\u8282\u70b9\u7684\u5927\u5c0f\uff1a $ sudo dumpe2fs -h /dev/sda2 | grep \"Inode size\" dumpe2fs 1 .46.5 ( 30 -Dec-2021 ) Inode size: 256 \u6bcf\u4e2ainode\u90fd\u6709\u4e00\u4e2a\u53f7\u7801\uff0c\u64cd\u4f5c\u7cfb\u7edf\u7528inode\u53f7\u7801\u6765\u8bc6\u522b\u4e0d\u540c\u7684\u6587\u4ef6\uff0c\u6ce8\u610f\uff0c\u4e0d\u662f\u901a\u8fc7\u6587\u4ef6\u540d\u6765\u8bc6\u522b\u4e0d\u540c\u6587\u4ef6\u3002\u4ece\u64cd\u4f5c\u7cfb\u7edf\u89d2\u5ea6\u770b\uff0c\u6587\u4ef6\u540d\u53ea\u662finode\u53f7\u7801\u5bf9\u4e00\u4e2a\u522b\u540d\u3002 \u7528\u6237\u901a\u8fc7\u6587\u4ef6\u540d\uff0c\u6253\u5f00\u67d0\u4e2a\u6587\u4ef6\u7684\u8fc7\u7a0b\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5206\u6210\u4e09\u6b65\u5b8c\u6210\uff1a \u9996\u5148\uff0c\u7cfb\u7edf\u627e\u5230\u8fd9\u4e2a\u6587\u4ef6\u540d\u5bf9\u5e94\u7684inode\u53f7\u7801\u3002 \u5176\u6b21\uff0c\u901a\u8fc7inode\u53f7\uff0c\u83b7\u53d6inode\u4fe1\u606f\u3002 \u7b2c\u4e09\uff0c\u901a\u8fc7inode\u4fe1\u606f\uff0c\u627e\u5230\u6587\u4ef6\u6570\u636e\u6240\u5728\u7684block\uff0c\u8bfb\u51fa\u6570\u636e\u3002 \u901a\u8fc7 ls -i \u547d\u4ee4\uff0c\u53ef\u4ee5\u5f97\u5230\u6587\u4ef6\u5bf9\u5e94\u7684inode\u53f7\uff1a $ ls -i file1 143 file1 \u76ee\u5f55\uff08directory\uff09\u4e5f\u662f\u4e00\u79cd\u6587\u4ef6\u3002\u6253\u5f00\u76ee\u5f55\uff0c\u5b9e\u9645\u4e0a\u5c31\u662f\u6253\u5f00\u76ee\u5f55\u6587\u4ef6\u3002 \u76ee\u5f55\u6587\u4ef6\u7684\u7ed3\u6784\u662f\u7531\u4e00\u4e2a\u5305\u542b\u4e00\u7cfb\u5217\u76ee\u5f55\u9879\uff08dirent\uff09\u7684\u5217\u8868\u7ec4\u6210\u3002 \u6bcf\u4e2a\u76ee\u5f55\u9879\u7531\u4e24\u90e8\u5206\u7ec4\u6210\uff1a\u6240\u5305\u542b\u6587\u4ef6\u7684\u6587\u4ef6\u540d\uff0c\u4ee5\u53ca\u8be5\u6587\u4ef6\u540d\u5bf9\u5e94\u7684inode\u53f7\u3002 \u547d\u4ee4 ls -i \u5217\u51fa\u6574\u4e2a\u76ee\u5f55\u6587\u4ef6\uff0c\u5373\u6587\u4ef6\u540d\u548cinode\u53f7\uff1a $ ls -i 143 file1 140 file2 139 test $ ls -il 143 -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 140 -rw-r--r--. 1 vagrant wheel 0 Oct 1 21 :35 file2 139 drwxr-xr-x. 5 vagrant wheel 4096 Nov 9 22 :00 test 3.2.\u94fe\u63a5\u7c7b\u578b \u00b6 \u786c\u94fe\u63a5 \uff08Hard links\uff09\u786c\u94fe\u63a5\u662f\u5b58\u50a8\u5377\u4e0a\u6587\u4ef6\u7684\u76ee\u5f55\u5f15\u7528\u6216\u6307\u9488\u3002 \u6587\u4ef6\u540d\u662f\u5b58\u50a8\u5728\u76ee\u5f55\u7ed3\u6784\u4e2d\u7684\u6807\u7b7e\uff0c\u76ee\u5f55\u7ed3\u6784\u6307\u5411\u6587\u4ef6\u6570\u636e\u3002 \u56e0\u6b64\uff0c\u53ef\u4ee5\u5c06\u591a\u4e2a\u6587\u4ef6\u540d\u4e0e\u540c\u4e00\u6587\u4ef6\u5173\u8054\u3002 \u901a\u8fc7\u4e0d\u540c\u7684\u6587\u4ef6\u540d\u8bbf\u95ee\u65f6\uff0c\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u662f\u9488\u5bf9\u6e90\u6587\u4ef6\u6570\u636e\u3002 \u7b26\u53f7\u94fe\u63a5 \uff08Symbolic links\uff09: \u7b26\u53f7\u94fe\u63a5\u5305\u542b\u4e00\u4e2a\u6587\u672c\u5b57\u7b26\u4e32\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5c06\u5176\u89e3\u91ca\u4e3a\u53e6\u4e00\u4e2a\u6587\u4ef6\u6216\u76ee\u5f55\u3002 \u5b83\u672c\u8eab\u5c31\u662f\u4e00\u4e2a\u6587\u4ef6\uff0c\u53ef\u4ee5\u72ec\u7acb\u4e8e\u76ee\u6807\u800c\u5b58\u5728\u3002 \u5982\u679c\u5220\u9664\u4e86\u7b26\u53f7\u94fe\u63a5\uff0c\u5219\u5176\u76ee\u6807\u6587\u4ef6\u6216\u76ee\u5f55\u4e0d\u53d7\u5f71\u54cd\u3002 \u5982\u679c\u79fb\u52a8\uff0c\u91cd\u547d\u540d\u6216\u5220\u9664\u76ee\u6807\u6587\u4ef6\u6216\u76ee\u5f55\uff0c\u5219\u7528\u4e8e\u6307\u5411\u5b83\u7684\u4efb\u4f55\u7b26\u53f7\u94fe\u63a5\u5c06\u7ee7\u7eed\u5b58\u5728\uff0c\u4f46\u6307\u5411\u7684\u662f\u4e00\u4e2a\u4e0d\u5b58\u5728\u7684\u6587\u4ef6\u3002 \u4ec5\u5f53\u6587\u4ef6\u548c\u94fe\u63a5\u6587\u4ef6\u4f4d\u4e8e\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\uff08\u5728\u540c\u4e00\u5206\u533a\u4e0a\uff09\u65f6\uff0c\u624d\u80fd\u4f7f\u7528\u786c\u94fe\u63a5\uff0c\u56e0\u4e3ainode\u7f16\u53f7\u5728\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\u4e2d\u4ec5\u662f\u552f\u4e00\u7684\u3002 \u53ef\u4ee5\u4f7f\u7528 ln \u547d\u4ee4\u521b\u5efa\u786c\u94fe\u63a5\uff0c\u6307\u5411\u5df2\u5b58\u5728\u6587\u4ef6\u7684inode\uff0c\u53ef\u4ee5\u901a\u8fc7\u6587\u4ef6\u540d\u6216\u8005\u786c\u94fe\u63a5\u540d\u8bbf\u95ee\u6587\u4ef6\u3002 \u53ef\u4ee5\u4f7f\u7528 ln -s \u9009\u9879\u521b\u5efa\u7b26\u53f7\u94fe\u63a5\u3002 \u4e00\u4e2a\u7b26\u53f7\u94fe\u63a5\u4f1a\u88ab\u5206\u914d\u4e00\u4e2a\u5355\u72ec\u7684inode\uff0c\u5e76\u6307\u5411\u4e00\u4e2a\u6587\u4ef6\uff0c\u6240\u4ee5\u53ef\u4ee5\u660e\u663e\u533a\u5206\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\u548c\u5b9e\u9645\u6587\u4ef6\u3002 \u6587\u4ef6\u7cfb\u7edf\u672c\u8d28\u4e0a\u662f\u4e00\u4e2a\u7528\u4e8e\u8ddf\u8e2a\u5206\u533a\u5377\u4e2d\u7684\u6587\u4ef6\u7684\u6570\u636e\u5e93\u3002 \u5bf9\u4e8e\u666e\u901a\u6587\u4ef6\uff0c\u5206\u914d\u6570\u636e\u5757\u4ee5\u5b58\u50a8\u6587\u4ef6\u7684\u6570\u636e\uff0c\u5206\u914dinode\u4ee5\u6307\u5411\u6570\u636e\u5757\u4ee5\u53ca\u5b58\u50a8\u5173\u4e8e\u6587\u4ef6\u7684\u5143\u6570\u636e\uff0c\u7136\u540e\u5c06\u6587\u4ef6\u540d\u5206\u914d\u7ed9inode\u3002 \u786c\u94fe\u63a5\u662f\u4e0e\u73b0\u6709inode\u5173\u8054\u7684\u8f85\u52a9\u6587\u4ef6\u540d\u3002 \u5bf9\u4e8e\u7b26\u53f7\u94fe\u63a5\uff0c\u5c06\u4e3a\u65b0\u7684inode\u5206\u914d\u4e00\u4e2a\u4e0e\u4e4b\u5173\u8054\u7684\u65b0\u6587\u4ef6\u540d\uff0c\u4f46inode\u5f15\u7528\u53e6\u4e00\u4e2a\u6587\u4ef6\u540d\u800c\u4e0d\u662f\u5f15\u7528\u6570\u636e\u5757\u3002 \u67e5\u770b\u6587\u4ef6\u540d\u548cinode\u4e4b\u95f4\u5173\u7cfb\u7684\u4e00\u4e2a\u65b9\u6cd5\u662f\u4f7f\u7528 ls -il \u547d\u4ee4\u3002inode\u7684\u5178\u578b\u5927\u5c0f\u4e3a128\u4f4d\uff0c\u6570\u636e\u5757\u7684\u5927\u5c0f\u8303\u56f4\u53ef\u4ee5\u662f1k\uff0c2k\uff0c4k\u6216\u66f4\u5927\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u3002 \u8f6f\u8fde\u63a5\u53ef\u4ee5\u9488\u5bf9\u76ee\u5f55\uff0c\u786c\u8fde\u63a5\u53ea\u80fd\u9488\u5bf9\u6587\u4ef6\u3002 \u786c\u94fe\u63a5\u76f8\u5f53\u4e8e\u589e\u52a0\u4e86\u4e00\u4e2a\u767b\u8bb0\u9879\uff0c\u4f7f\u5f97\u539f\u6765\u7684\u6587\u4ef6\u591a\u4e86\u4e00\u4e2a\u540d\u5b57\uff0c\u81f3\u4e8einode\u90fd\u6ca1\u53d8\u3002\u6240\u8c13\u7684\u767b\u8bb0\u9879\u5176\u5b9e\u662f\u76ee\u5f55\u6587\u4ef6\u4e2d\u7684\u4e00\u4e2a\u6761\u76ee(\u76ee\u5f55\u9879)\uff0c\u4f7f\u7528hard link \u662f\u8ba9\u591a\u4e2a\u4e0d\u540c\u7684\u76ee\u5f55\u9879\u6307\u5411\u540c\u4e00\u4e2a\u6587\u4ef6\u7684inode\uff0c\u6ca1\u6709\u591a\u4f59\u7684\u5185\u5bb9\u9700\u8981\u5b58\u50a8\u5728\u78c1\u76d8\u6247\u533a\u4e2d\uff0c\u6240\u4ee5hardlink\u4e0d\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 \u7b26\u53f7\u94fe\u63a5\u6709\u5355\u72ec\u7684inode\uff0c\u5728inode\u4e2d\u5b58\u653e\u53e6\u4e00\u4e2a\u6587\u4ef6\u7684\u8def\u5f84\u800c\u4e0d\u662f\u6587\u4ef6\u6570\u636e\uff0c\u6240\u4ee5\u7b26\u53f7\u94fe\u63a5\u4f1a\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 \u7279\u5f81 \u786c\u94fe\u63a5 \u7b26\u53f7\u94fe\u63a5 \u672c\u8d28 \u540c\u4e00\u4e2a\u6587\u4ef6 \u4e0d\u662f\u540c\u4e00\u4e2a\u6587\u4ef6 \u8de8\u8bbe\u5907 \u4e0d\u652f\u6301 \u652f\u6301 inode \u76f8\u540c \u4e0d\u540c \u94fe\u63a5\u6570 \u521b\u5efa\u786c\u94fe\u63a5\uff0c\u94fe\u63a5\u6570\u4f1a\u589e\u52a0\uff0c\u5220\u9664\u5219\u51cf\u5c11 \u521b\u5efa\u6216\u5220\u9664\uff0c\u94fe\u63a5\u6570\u90fd\u4e0d\u53d8 \u6587\u4ef6\u5939 \u4e0d\u652f\u6301 \u652f\u6301 \u76f8\u5bf9\u8def\u5f84 \u539f\u59cb\u6587\u4ef6\u7684\u76f8\u5bf9\u8def\u5f84\u662f\u76f8\u5bf9\u4e8e\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55 \u539f\u59cb\u6587\u4ef6\u7684\u76f8\u5bf9\u8def\u5f84\u662f\u76f8\u5bf9\u4e8e\u94fe\u63a5\u6587\u4ef6\u7684\u76f8\u5bf9\u8def\u5f84 \u5220\u9664\u6e90\u6587\u4ef6 \u53ea\u662f\u94fe\u63a5\u6570\u51cf\u5c11\uff0c\u94fe\u63a5\u6587\u4ef6\u8bbf\u95ee\u4e0d\u53d7\u5f71\u54cd \u94fe\u63a5\u6587\u4ef6\u5c06\u65e0\u6cd5\u8bbf\u95ee \u6587\u4ef6\u7c7b\u578b \u548c\u6e90\u6587\u4ef6\u76f8\u540c \u94fe\u63a5\u6587\u4ef6\uff0c\u548c\u6e90\u6587\u4ef6\u65e0\u5173 \u6587\u4ef6\u5927\u5c0f \u548c\u6e90\u6587\u4ef6\u76f8\u540c \u6e90\u6587\u4ef6\u7684\u8def\u5f84\u7684\u957f\u5ea6 3.3.\u8bbe\u5907\u6587\u4ef6 \u00b6 \u8bbe\u5907\u6587\u4ef6 \uff08Device File\uff09\u8868\u793a\u786c\u4ef6\uff08\u7f51\u5361\u9664\u5916\uff09\u3002 \u6bcf\u4e2a\u786c\u4ef6\u90fd\u7531\u4e00\u4e2a\u8bbe\u5907\u6587\u4ef6\u8868\u793a\u3002 \u7f51\u5361\u662f\u63a5\u53e3\u3002 \u8bbe\u5907\u6587\u4ef6\u628a\u5185\u6838\u9a71\u52a8\u548c\u7269\u7406\u786c\u4ef6\u8bbe\u5907\u8fde\u63a5\u8d77\u6765\u3002 \u5185\u6838\u9a71\u52a8\u7a0b\u5e8f\u901a\u8fc7\u5bf9\u8bbe\u5907\u6587\u4ef6\u8fdb\u884c\u8bfb\u5199\uff08\u6b63\u786e\u7684\u683c\u5f0f\uff09\u6765\u5b9e\u73b0\u5bf9\u786c\u4ef6\u7684\u8bfb\u5199\u3002 \u7c7b\u578b\uff1a \u5757\u8bbe\u5907\uff08Block Devices\uff09\uff1a\u5757\u8bbe\u5907\uff08\u901a\u5e38\uff09\u5728512\u5b57\u8282\u7684\u5927\u5757\u4e2d\u8bfb\u53d6/\u5199\u5165\u4fe1\u606f\u3002 \u5b57\u7b26\u8bbe\u5907\uff08Character Devices\uff09\uff1a\u5b57\u7b26\u8bbe\u5907\u4ee5\u5b57\u7b26\u65b9\u5f0f\u8bfb\u53d6/\u5199\u5165\u4fe1\u606f\u3002 \u5b57\u7b26\u8bbe\u5907\u76f4\u63a5\u63d0\u4f9b\u5bf9\u786c\u4ef6\u8bbe\u5907\u7684\u65e0\u7f13\u51b2\u8bbf\u95ee\u3002 \u6709\u65f6\u79f0\u4e3a\u88f8\u8bbe\u5907\uff08raw devices\uff09\u3002\uff08\u6ce8\u610f\uff1a\u88f8\u8bbe\u5907\u88ab\u89c6\u4e3a\u5b57\u7b26\u8bbe\u5907\uff0c\u4e0d\u662f\u5757\u8bbe\u5907\uff09 \u901a\u8fc7\u8f85\u4ee5\u4e0d\u540c\u9009\u9879\uff0c\u53ef\u4ee5\u5e7f\u6cdb\u800c\u591a\u6837\u5730\u5e94\u7528\u548c\u4f7f\u7528\u5b57\u7b26\u8bbe\u5907\u3002 \u5f53\u5185\u6838\u53d1\u73b0\u8bbe\u5907\u65f6\u7531\u64cd\u4f5c\u7cfb\u7edf udev \u81ea\u52a8\u521b\u5efa\u3002 3.4.\u7ec3\u4e60 \u00b6 \u76ee\u6807\uff1a\u4ee5Rocky 9\u4e3a\u4f8b\u3002 \u67e5\u770b\u8f6f/\u786c\u94fe\u63a5\u6587\u4ef6\u7684\u7279\u5f81\u3002 \u67e5\u770b\u76ee\u5f55\u7ed3\u6784\u3002 \u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u5f97\u5230\u5f53\u524d\u7cfb\u7edf\u76842\u7ea7\u76ee\u5f55\u7684\u7ed3\u6784\u3002 tree -L 2 -d / \u521b\u5efa\u7ec3\u4e60\u76ee\u5f55\u3002 mkdir data mkdir -p data/typelink cd data \u521b\u5efa\u786c\u94fe\u63a5\u3002\u6ce8\u610f\uff1a file \u3001 hardlinkfile1 \u3001 hardlinkfile2 \u6587\u4ef6\u7684\u94fe\u63a5\u4f4d\u7f6e\u7684\u6570\u503c\u7684\u53d8\u5316) echo \"it's original file\" > file ln file hardlinkfile1 ln -s file symlinkfile1 ln -s file symlinkfile2 \u6267\u884c ls -l \u547d\u4ee4\u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u7ed3\u679c\uff1a -rw-r--r--. 2 vagrant wheel 19 Nov 1 10 :42 file -rw-r--r--. 2 vagrant wheel 19 Nov 1 10 :42 hardlinkfile1 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file \u521b\u5efa\u53e6\u5916\u4e00\u4e2a\u786c\u94fe\u63a5\u3002 ln file hardlinkfile2 \u6267\u884c ls -l \u547d\u4ee4\u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u7ed3\u679c\uff1a -rw-r--r--. 3 vagrant wheel 19 Nov 1 10 :42 file -rw-r--r--. 3 vagrant wheel 19 Nov 1 10 :42 hardlinkfile1 -rw-r--r--. 3 vagrant wheel 19 Nov 1 10 :42 hardlinkfile2 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file \u4fee\u6539 file \u6587\u4ef6\u7684\u5185\u5bb9\u3002 echo \"add oneline\" >> file \u901a\u8fc7\u547d\u4ee4 cat file \u67e5\u770b\u5f53\u524d file \u7684\u5185\u5bb9\u3002 it ' s original file add oneline \u901a\u8fc7\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u53ef\u4ee5\u770b\u5230\u6240\u4ee5\u8f6f/\u786c\u94fe\u63a5\u6587\u4ef6\u5185\u5bb9\u90fd\u66f4\u65b0\u4e86\uff0c\u548c file \u6587\u4ef6\u66f4\u65b0\u540e\u7684\u5185\u5bb9\u4fdd\u6301\u4e00\u81f4\u3002 cat hardlinkfile1 cat hardlinkfile2 cat symlinkfile1 cat symlinkfile2 \u5bf9\u6587\u4ef6 symlinkfile1 \u518d\u521b\u5efa\u65b0\u7684\u8f6f\u8fde\u63a5\u3002 ln -s symlinkfile1 symlinkfile1-1 \u901a\u8fc7\u547d\u4ee4 ls -il \u67e5\u770b\u73b0\u5728\u7684\u76ee\u5f55\u4fe1\u606f\u3002 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 file 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile1 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile2 67274681 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file 67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov 1 11 :20 symlinkfile1-1 -> symlinkfile1 67274682 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file \u8bfb\u53d6\u8f6f\u94fe\u63a5\u6587\u4ef6\u7684\u6e90\u6587\u4ef6\u4fe1\u606f readlink symlinkfile1 readlink symlinkfile2 \u6ce8\u610f\uff0c\u5bf9\u4e8e symlinkfile1-1 \u7684\u60c5\u51b5\u6709\u4e9b\u4e0d\u540c\u3002 readlink symlinkfile1-1 \u4e0a\u9762\u547d\u4ee4\u8fd4\u56de\u7ed3\u679c symlinkfile1 \u4ecd\u7136\u662f\u4e00\u4e2a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\u3002\u901a\u8fc7 readlink -f \u53ef\u4ee5\u76f4\u63a5\u5b9a\u4f4d\u771f\u6b63\u7684\u6e90\u6587\u4ef6\u3002 readlink -f symlinkfile1-1 \u4e0a\u9762\u7684\u8fd4\u56de\u7ed3\u679c /data/linktype/file \u662f symlinkfile1-1 \u771f\u6b63\u7684\u6e90\u6587\u4ef6\u3002 \u663e\u793a data \u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\uff1a cd ~ tree ./data \u8fd0\u884c\u7ed3\u679c\uff1a ./data \u251c\u2500\u2500 file \u251c\u2500\u2500 hardlinkfile1 \u251c\u2500\u2500 hardlinkfile2 \u251c\u2500\u2500 symlinkfile1 -> file \u251c\u2500\u2500 symlinkfile1-1 -> symlinkfile1 \u251c\u2500\u2500 symlinkfile2 -> file \u2514\u2500\u2500 typelink \u53ea\u663e\u793a data \u76ee\u5f55\u4e0b\u7684\u5b50\u76ee\u5f55\uff1a tree -d ./data \u8fd0\u884c\u7ed3\u679c\uff1a ./data \u2514\u2500\u2500 typelink \u663e\u793a data \u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\uff0c\u5305\u542b\u5168\u76ee\u5f55\uff1a tree -f ./data \u8fd0\u884c\u7ed3\u679c\uff1a ./data \u251c\u2500\u2500 ./data/file \u251c\u2500\u2500 ./data/hardlinkfile1 \u251c\u2500\u2500 ./data/hardlinkfile2 \u251c\u2500\u2500 ./data/symlinkfile1 -> file \u251c\u2500\u2500 ./data/symlinkfile1-1 -> symlinkfile1 \u251c\u2500\u2500 ./data/symlinkfile2 -> file \u2514\u2500\u2500 ./data/typelink 4.\u6587\u4ef6\u5c5e\u6027\u8bf4\u660e \u00b6 \u6267\u884c\u547d\u4ee4 ls -ihl \uff0c\u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\uff08Rocky 9\uff09\u3002 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 file 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile1 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile2 67274681 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file 67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov 1 11 :20 symlinkfile1-1 -> symlinkfile1 67274682 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file 33555262 drwxr-xr-x. 2 vagrant wheel 6 Nov 1 11 :30 typelink \u4ee5 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11:14 file \u4e3a\u4f8b\uff1a 67274680 : inode \u7d22\u5f15\u8282\u70b9\u7f16\u53f7\u3002 -rw-r--r-- \uff1a\u6587\u4ef6\u7c7b\u578b\u53ca\u6743\u9650 - \uff1a\u6587\u4ef6\u7c7b\u578b\uff0c\u4f8b\u5b50\u4e2d\u51fa\u73b0\u4e86\u4e09\u79cd\uff0c - \uff0c l \u548c d \u3002 - \uff1a\u666e\u901a\u6587\u4ef6 d \uff1a\u76ee\u5f55 l \uff1a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\uff08link\uff09 b \uff1a\u5757\u8bbe\u5907\uff08block\uff09 c \uff1a\u5b57\u7b26\u8bbe\u5907\uff08character\uff09 p \uff1a\u7ba1\u9053\u6587\u4ef6\uff08pipe\uff09 s \uff1a\u5957\u63a5\u5b57\u6587\u4ef6\uff08socket\uff09 rw-r--r-- \uff1a\u6587\u4ef6\u6743\u9650\uff0c\u4ece\u5de6\u5230\u53f3\u4f9d\u6b21\u4e3a\uff1a rw- \uff1a\u6587\u4ef6\u5c5e\u4e3b\u6743\u9650\uff0c\u4f8b\u5b50\u4e2d\u662f vagrant \u3002 r-- \uff1a\u6587\u4ef6\u5c5e\u7ec4\u7684\u6743\u9650\uff0c\u4f8b\u5b50\u4e2d\u662f wheel \u3002 r-- \uff1a\u5176\u4ed6\u7ec4\u7684\u6743\u9650\u3002 . \uff1a\u8fd9\u4e2a\u70b9\u8868\u793a\u6587\u4ef6\u5e26\u6709SELinux\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\uff08SELinux Contexts\uff09\u3002\u5173\u95edSELinux\uff0c\u65b0\u521b\u5efa\u7684\u6587\u4ef6\u5c31\u4e0d\u4f1a\u518d\u6709\u8fd9\u4e2a\u70b9\u4e86\u3002\u4f46\u662f\uff0c\u4ee5\u524d\u521b\u5efa\u7684\u6587\u4ef6\u672c\u6765\u6709\u8fd9\u4e2a\u70b9\u7684\u8fd8\u4f1a\u663e\u793a\u8fd9\u4e2a\u70b9\uff08\u867d\u7136SELinux\u4e0d\u8d77\u4f5c\u7528\u4e86\uff09\u3002 3 \uff1a\u786c\u94fe\u63a5\u6570\uff0c\u4f8b\u5b50\u4e2d file \u548c hardlinkfile1 \u548c hardlinkfile2 \u4e4b\u95f4\u662f\u786c\u94fe\u63a5\uff0c\u6240\u4ee5\u8fd9\u4e09\u4e2a\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u90fd\u662f 3 \u3002 vagrant \uff1a\u6587\u4ef6\u5c5e\u4e3b wheel \uff1a\u6587\u4ef6\u5c5e\u7ec4 31 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u5927\u5c0f Nov 1 11:14 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u521b\u5efa\u65e5\u671f\u548c\u65f6\u95f4 file \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u540d\u79f0 \u4e0b\u9762\u662f\u547d\u4ee4 ls -ihl \u5728openSUSE\u548cUbuntu\u4e0a\u7684\u663e\u793a\u7ed3\u679c\u3002 $ ls -ihl 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 file 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile1 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile2 233648 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile1 -> file 233650 lrwxrwxrwx 1 vagrant wheel 12 Nov 1 15 :52 symlinkfile1-1 -> symlinkfile1 233649 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile2 -> file 233646 drwxr-xr-x 1 vagrant wheel 0 Nov 1 15 :51 typelink 5.\u6807\u51c6\u8f93\u5165\u8f93\u51fa \u00b6 \u6807\u51c6\u8f93\u5165\u8f93\u51fa\uff0c\u5373I/O\uff0cI/O\u7684I\u662fInput\uff0cO\u662foutput\u3002 I\uff1a\u4ece\u5916\u90e8\u8bbe\u5907\u8f93\u5165\u5230\u5185\u5b58 O\uff1a\u4ece\u5185\u5b58\u8f93\u51fa\u5230\u5916\u90e8\u8bbe\u5907 \u6807\u51c6\u8f93\u5165\u548c\u6807\u51c6\u8f93\u51fa\u662f\u7528\u4e8eIO\u7684\uff0c\u5b83\u4eec\u5c5e\u4e8e\u5916\u90e8\u8bbe\u5907\uff08\u903b\u8f91\u4e0a\u7684\u5916\u90e8\u8bbe\u5907\uff09\uff0c\u4e0d\u662f\u5185\u5b58\u3002 linux\u4e2d\u4e00\u5207\u8bbe\u5907\u7686\u662f\u6587\u4ef6\uff01\u56e0\u6b64\u6807\u51c6\u8f93\u5165\u548c\u8f93\u51fa\u672c\u8d28\u5c31\u662f\u6587\u4ef6\uff0c\u5916\u90e8\u8bbe\u5907\u4ee5\u6587\u4ef6\u5f62\u5f0f\u8868\u73b0\u3002 \u5728Linux\u7cfb\u7edf\u4e2d\uff0c\u6807\u51c6\u8f93\u5165\u548c\u6807\u51c6\u8f93\u51fa\u5bf9\u5e94\u7684\u6587\u4ef6\u662f /dev/stdin \u548c /dev/stdout \u8fd9\u4e24\u4e2a\u6587\u4ef6\u3002 \u4ece\u6807\u51c6\u8f93\u5165\u8bfb\uff0c\u4ece\u903b\u8f91\u4e0a\u8bb2\uff0c\u5c31\u662f\u6253\u5f00 /dev/stdin \u8fd9\u4e2a\u6587\u4ef6\uff0c\u5e76\u8bfb\u5165\u6587\u4ef6\u5185\u5bb9\u3002 \u8f93\u51fa\u5230\u6807\u51c6\u8f93\u51fa\uff0c\u4ece\u903b\u8f91\u4e0a\u8bb2\uff0c\u5c31\u662f\u6253\u5f00 /dev/stdout \u8fd9\u4e2a\u6587\u4ef6\uff0c\u5e76\u628a\u5185\u5bb9\u8f93\u51fa\u5230\u8fd9\u4e2a\u6587\u4ef6\u91cc\u53bb\u3002 \u8fd9\u91cc\u5f3a\u8c03\u7684\u662f\u201c\u903b\u8f91\u4e0a\u201d\uff0c\u56e0\u4e3a /dev/stdin \u548c /dev/stdout \u8fd92\u4e2a\u6587\u4ef6\u672c\u8eab\u4e0d\u662f\u8bbe\u5907\u6587\u4ef6\u3002Linux\u4e2d\u8bbe\u5907\u662f\u6587\u4ef6\uff0c\u4f46\u662f\u6587\u4ef6\u4e0d\u4e00\u5b9a\u662f\u8bbe\u5907\u3002 \u56e0\u6b64\uff0c\u64cd\u4f5c /dev/stdin \u548c/dev/stdout`\u8fd92\u4e2a\u6587\u4ef6\uff0c\u5b9e\u9645\u4e0a\u662f\u64cd\u4f5c\u4e24\u4e2a\u6587\u4ef6\u5b58\u653e\u5730\u5740\u5bf9\u5e94\u7684\u8bbe\u5907\u6587\u4ef6\u3002 \u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u770b\u5230\u6807\u51c6\u8f93\u5165\u8f93\u51fa\u6587\u4ef6\u7684\u7279\u70b9\uff0c\u4ed6\u4eec\u867d\u7136\u5728 /dev \u76ee\u5f55\u4e0b\uff0c\u90fd\u662f\u4ee5 l \u5f00\u5934\u7684\u94fe\u63a5\u6587\u4ef6\uff0c\u6307\u5411\u7684\u662f\u53e6\u4e00\u4e2a\u6587\u4ef6\u7684\u5730\u5740\u3002 $ ls -l /dev/std* lrwxrwxrwx 1 root root 15 Nov 13 10 :39 /dev/stderr -> /proc/self/fd/2 lrwxrwxrwx 1 root root 15 Nov 13 10 :39 /dev/stdin -> /proc/self/fd/0 lrwxrwxrwx 1 root root 15 Nov 13 10 :39 /dev/stdout -> /proc/self/fd/1 # Rocky $ ll /proc/self/fd/ lrwx------. 1 vagrant wheel 64 Nov 13 22 :38 0 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 22 :38 1 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 22 :38 2 -> /dev/pts/0 lr-x------. 1 vagrant wheel 64 Nov 13 22 :38 3 -> /proc/1702/fd # Ubuntu $ ll /proc/self/fd/ lrwx------ 1 vagrant sudo 64 Nov 13 14 :38 0 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 14 :38 1 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 14 :38 2 -> /dev/pts/0 lr-x------ 1 vagrant sudo 64 Nov 13 14 :38 3 -> /proc/2062/fd/ # openSUSE $ ll /proc/self/fd/* ls: cannot access '/proc/self/fd/255' : No such file or directory ls: cannot access '/proc/self/fd/3' : No such file or directory lrwx------ 1 vagrant wheel 64 Nov 13 22 :37 /proc/self/fd/0 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 22 :37 /proc/self/fd/1 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 22 :37 /proc/self/fd/2 -> /dev/pts/0 Linux\u8fdb\u7a0b\u9ed8\u8ba4\u4f1a\u6253\u5f00\u7684\u4e09\u4e2a\u6587\u4ef6\uff1a \u6807\u51c6\u8f93\u5165 /dev/stdin \uff0c\u63cf\u8ff0\u7b26\u4e3a 0\uff0c\u9ed8\u8ba4\u662f\u952e\u76d8\u8f93\u5165\u3002 \u6807\u51c6\u8f93\u51fa /dev/stdout \uff0c\u63cf\u8ff0\u7b26\u4e3a 1\uff0c\u9ed8\u8ba4\u662f\u8f93\u51fa\u5230\u5c4f\u5e55\u3002 \u6807\u51c6\u8f93\u51fa /dev/stderr \uff0c\u63cf\u8ff0\u7b26\u4e3a 2\uff0c\u9ed8\u8ba4\u662f\u8f93\u51fa\u5230\u5c4f\u5e55\u3002 \u4ee5Rocky\u4e3a\u4f8b\uff0c\u521b\u5efa file.py \u6587\u4ef6\u3002 $ cat > file.py < test.txt \u8fd0\u884c file.py \u7a0b\u5e8f\u3002 python3 file.py \u6253\u5f00\u65b0\u7684\u7ec8\u7aef\u7a97\u53e3\uff0c\u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u5f97\u5230python3\u8fd9\u4e2a\u7a0b\u5e8f\u8fd0\u884c\u7684process ID\u3002\u5176\u4e2d\u53ef\u4ee5\u770b\u5230\u6709\u4e00\u4e2a\u6765\u81ea\u6587\u4ef6test.txt\u88ab\u7a0b\u5e8ffile.py\u6253\u5f00\uff08\u8f93\u5165\uff09\u3002 $ pidof python3 1739 788 $ sudo ls -l /proc/788/fd/ lr-x------. 1 root root 64 Nov 13 23 :00 0 -> /dev/null l-wx------. 1 root root 64 Nov 13 23 :00 1 -> /dev/null lrwx------. 1 root root 64 Nov 13 23 :00 10 -> 'socket:[24677]' lrwx------. 1 root root 64 Nov 13 23 :00 11 -> 'socket:[24678]' l-wx------. 1 root root 64 Nov 13 23 :00 2 -> /dev/null l-wx------. 1 root root 64 Nov 13 10 :41 3 -> /var/log/firewalld lrwx------. 1 root root 64 Nov 13 23 :00 4 -> 'socket:[23421]' lrwx------. 1 root root 64 Nov 13 23 :00 5 -> 'anon_inode:[eventfd]' lrwx------. 1 root root 64 Nov 13 23 :00 6 -> 'socket:[24586]' lr-x------. 1 root root 64 Nov 13 23 :00 7 -> anon_inode:inotify lrwx------. 1 root root 64 Nov 13 23 :00 8 -> 'anon_inode:[eventfd]' lrwx------. 1 root root 64 Nov 13 23 :00 9 -> '/memfd:libffi (deleted)' $ sudo ls -l /proc/1739/fd/ lrwx------. 1 vagrant wheel 64 Nov 13 23 :00 0 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 23 :00 1 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 23 :00 2 -> /dev/pts/0 lr-x------. 1 vagrant wheel 64 Nov 13 23 :00 3 -> /home/vagrant/test.txt \u5728Ubuntu\u4e2d\u8fd0\u884c file.py \u7a0b\u5e8f\uff0cpidof\u4f1a\u53d6\u5f973\u4e2aprocess IDs\u3002 $ pidof python3 2128 924 873 $ sudo ls -l /proc/2128/fd/ lrwx------ 1 vagrant sudo 64 Nov 13 15 :10 0 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 15 :10 1 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 15 :10 2 -> /dev/pts/0 lr-x------ 1 vagrant sudo 64 Nov 13 15 :10 3 -> /home/vagrant/test.txt $ sudo ls -l /proc/924/fd/ lr-x------ 1 root root 64 Nov 13 15 :11 0 -> /dev/null lrwx------ 1 root root 64 Nov 13 15 :11 1 -> 'socket:[31593]' lrwx------ 1 root root 64 Nov 13 15 :11 2 -> 'socket:[31593]' l-wx------ 1 root root 64 Nov 13 02 :40 3 -> /var/log/unattended-upgrades/unattended-upgrades-shutdown.log lrwx------ 1 root root 64 Nov 13 15 :11 4 -> 'socket:[31652]' lrwx------ 1 root root 64 Nov 13 15 :11 5 -> 'anon_inode:[eventfd]' lrwx------ 1 root root 64 Nov 13 15 :11 6 -> 'anon_inode:[eventfd]' lrwx------ 1 root root 64 Nov 13 15 :11 7 -> 'socket:[31657]' l-wx------ 1 root root 64 Nov 13 15 :11 8 -> /run/systemd/inhibit/1.ref lrwx------ 1 root root 64 Nov 13 15 :11 9 -> 'socket:[31658]' $ sudo ls -l /proc/873/fd/ lr-x------ 1 root root 64 Nov 13 15 :11 0 -> /dev/null lrwx------ 1 root root 64 Nov 13 15 :11 1 -> 'socket:[31412]' lrwx------ 1 root root 64 Nov 13 15 :11 2 -> 'socket:[31412]' lrwx------ 1 root root 64 Nov 13 02 :40 3 -> 'socket:[31650]' lrwx------ 1 root root 64 Nov 13 15 :11 4 -> 'anon_inode:[eventfd]' lrwx------ 1 root root 64 Nov 13 15 :11 5 -> 'socket:[31663]' lrwx------ 1 root root 64 Nov 13 15 :11 6 -> 'socket:[31664]' openSUSE\u9700\u8981\u5b89\u88c5\u5305 sysvinit-tools \u624d\u80fd\u4f7f\u7528 pidof \u547d\u4ee4\u3002 sudo zypper in sysvinit-tools \u7531\u4e8eopenSUSE\u4e2dpidof python3\u53ea\u8fd4\u56de\u4e00\u4e2aprocess ID\uff0c\u6240\u4ee5\u53ef\u4ee5\u7b80\u5316\u547d\u4ee4\u884c\u5f97\u5230process ID\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 $ sudo ls -l /proc/ ` pidof python3 ` /fd/ lrwx------ 1 vagrant wheel 64 Nov 13 23 :21 0 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 23 :21 1 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 23 :21 2 -> /dev/pts/0 lr-x------ 1 vagrant wheel 64 Nov 13 23 :21 3 -> /home/vagrant/test.txt \u53c2\u8003\uff1a \u5f53\u952e\u76d8\u548c\u9f20\u6807\u7b49\u8bbe\u5907\u901a\u8fc7\u4e32\u53e3\u76f4\u63a5\u8fde\u63a5\u5230\u8ba1\u7b97\u673a\u65f6\uff0c\u8fd9\u79cd\u8fde\u63a5\u79f0\u4e3aTTY\u3002 \u4f2a\u7ec8\u7aefpseudoterminal\uff08\u7f29\u5199\u4e3a\u201cpty\u201d\uff09\u662f\u4e00\u5bf9\u63d0\u4f9b\u53cc\u5411\u901a\u4fe1\u901a\u9053\u7684\u865a\u62df\u5b57\u7b26\u8bbe\u5907\u3002 \u901a\u9053\u7684\u4e00\u7aef\u79f0\u4e3a\u4e3b\u7aefmaster\uff1b \u53e6\u4e00\u7aef\u79f0\u4e3a\u4ece\u7aefslave\u3002 /dev/pts \u8868\u793a\u4e0e\u4f2a\u7ec8\u7aefpseudoterminal\u7684\u4e3b\u7aefmaster\u6216\u4ece\u7aefslave\u76f8\u5173\u7684master\u6587\u4ef6\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5c06\u5176\u4fdd\u5b58\u4e3a /dev/ptmx \u6587\u4ef6\u3002 telnet \u548c ssh \u7b49\u7a0b\u5e8f\u80fd\u591f\u4eff \u7aef\u7528\u6237> \u4e0e\u5b83\u4eec\u7684\u4ea4\u4e92\uff0c\u867d\u7136\u672c\u8d28\u4e0a\u662f\u4e0e\u6587\u4ef6 /dev/ptmx \u8fdb\u884c\u4ea4\u4e92\uff0c\u4f46\u5448\u73b0\u7ed9\u7528\u6237\u7684\u5374\u662f\u597d\u50cf\u8fd0\u884c\u5728\u771f\u6b63\u7684\u7ec8\u7aef\u7a97\u53e3\u4e00\u6837\uff0c\u4ece\u7aef\u7684\u6587\u4ef6\u662f\u4e3b\u7aef\u7684\u8f93\u5165\u3002 \u4f2a\u7ec8\u7aef\u8fdb\u7a0b\u5728Linux\u4e2d\u88ab\u5b58\u50a8\u5728 /dev/pts/ \u76ee\u5f55\u4e0b\u3002 /dev/pts/ \u76ee\u5f55\u4e0b\u7684\u5185\u5bb9\u662f\u4e00\u4e9b\u7279\u6b8a\u7684\u76ee\u5f55\uff0c\u7531Linux\u5185\u6838\u6240\u521b\u5efa\u3002 \u6bcf\u4e2a\u552f\u4e00\u7684\u7ec8\u7aef\u7a97\u53e3\u90fd\u4e0e /dev/pts \u7cfb\u7edf\u4e2d\u7684\u4e00\u4e2aLinux pts \u6761\u76ee\u76f8\u5173\u3002 \u4e0b\u9762\u8fd4\u56de\u7684\u7ed3\u679c\u8bf4\u660e\u67092\u4e2a\u8fdc\u7a0b\u7ec8\u7aef\u8fde\u63a5\u5230\u5f53\u524d\u7684\u673a\u5668\u3002 $ ll /dev/pts/ crw--w----. 1 vagrant tty 136 , 0 Nov 13 23 :18 0 crw--w----. 1 vagrant tty 136 , 1 Nov 13 23 :48 1 c---------. 1 root root 5 , 2 Nov 13 10 :41 ptmx \u4e5f\u53ef\u4ee5\u901a\u8fc7 w \u547d\u4ee4\u770b\u52302\u4e2a\u7ec8\u7aef\u8fdb\u7a0b\u3002 $ w 23 :55:05 up 13 :14, 2 users, load average: 0 .00, 0 .00, 0 .00 USER TTY LOGIN@ IDLE JCPU PCPU WHAT vagrant pts/0 10 :51 37 :03 0 .05s 0 .05s -bash vagrant pts/1 23 :48 0 .00s 0 .03s 0 .00s w \u5355\u4e2a\u4f2a\u7ec8\u7aefpseudoterminal\u53ef\u4ee5\u540c\u65f6\u63a5\u6536\u6765\u81ea\u4e0d\u540c\u7684\u7a0b\u5e8f\u7684\u8f93\u51fa\u3002 \u591a\u4e2a\u7a0b\u5e8f\u540c\u65f6\u5bf9\u4e00\u4e2a\u4f2a\u7ec8\u7aefpseudoterminal\u8fdb\u884c\u8bfb\u53d6\u4f1a\u5f15\u8d77\u6df7\u6dc6\u3002 \u5b58\u50a8\u5728 /dev/pts \u76ee\u5f55\u4e2d\u7684\u6587\u4ef6\u662f\u62bd\u8c61\u6587\u4ef6\u800c\u4e0d\u662f\u771f\u5b9e\u6587\u4ef6\uff0c\u662f\u4f2a\u7ec8\u7aef\u4e2d\u6267\u884c\u7a0b\u5e8f\u65f6\u4e34\u65f6\u5b58\u50a8\u7684\u6570\u636e\u3002 \u6253\u5f00 /dev/pts \u4e0b\u7684\u6587\u4ef6\u901a\u5e38\u6ca1\u6709\u4ec0\u4e48\u5b9e\u9645\u610f\u4e49\u3002 6.\u91cd\u5b9a\u5411\u548c\u7ba1\u9053 \u00b6 6.1.\u8f93\u5165\u91cd\u5b9a\u5411 \u00b6 \u5e38\u7528\u547d\u4ee4\u683c\u5f0f\uff1a command < file \uff1a\u5c06\u6307\u5b9a\u6587\u4ef6 file \u4f5c\u4e3a\u547d\u4ee4\u7684\u8f93\u5165\u8bbe\u5907\u3002 command << delimiter \uff1a\u8868\u793a\u4ece\u6807\u51c6\u8f93\u5165\u8bbe\u5907\uff08\u952e\u76d8\uff09\u4e2d\u8bfb\u5165\uff0c\u76f4\u5230\u9047\u5230\u5206\u754c\u7b26 delimiter \u505c\u6b62\uff08\u8bfb\u5165\u7684\u6570\u636e\u4e0d\u5305\u62ec\u5206\u754c\u7b26\uff09\uff0c\u8fd9\u91cc\u7684\u5206\u754c\u7b26\u53ef\u4ee5\u7406\u89e3\u4e3a\u81ea\u5b9a\u4e49\u7684\u5b57\u7b26\u4e32\u3002 command < file1 > file2 \uff1a\u5c06 file1 \u4f5c\u4e3a\u547d\u4ee4\u7684\u8f93\u5165\u8bbe\u5907\uff0c\u8be5\u547d\u4ee4\u7684\u6267\u884c\u7ed3\u679c\u8f93\u51fa\u5230 file2 \u4e2d\u3002 # \u8f93\u51fa\u6587\u4ef6file.py\u5185\u5bb9\uff08\u8f93\u5165\u8bbe\u5907\u662f\u952e\u76d8\uff09 $ cat file.py # \u8f93\u51fa\u6587\u4ef6file.py\u5185\u5bb9\uff08\u8f93\u5165\u8bbe\u5907\u662f\u6587\u4ef6file.py\uff09 $ cat < file.py # \u6307\u5b9a\u5206\u754c\u7b26\uff08\u8fd9\u91cc\u662fEOF\uff09\uff0c\u8bfb\u53d6\u952e\u76d8\u8f93\u5165\u5185\u5bb9\uff0c\u76f4\u5230\u9047\u5230\u6307\u5b9a\u5206\u754c\u7b26\u4e3a\u6b62\uff0c\u5c06\u6240\u8bfb\u53d6\u7684\u5185\u5bb9\u8f93\u51fa\u5230\u6587\u4ef6file.py\u3002 $ cat > file.py < new.py 6.2.\u8f93\u51fa\u91cd\u5b9a\u5411 \u00b6 \u8f93\u51fa\u91cd\u5b9a\u5411\u5206\u4e3a\u6807\u51c6\u8f93\u51fa\u91cd\u5b9a\u5411\u548c\u9519\u8bef\u8f93\u51fa\u91cd\u5b9a\u5411\u4e24\u79cd\u3002 \u5e38\u7528\u547d\u4ee4\u683c\u5f0f\uff1a command > file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u6807\u51c6\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u8f93\u51fa\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u5df2\u5305\u542b\u6570\u636e\uff0c\u4f1a\u6e05\u7a7a\u539f\u6709\u6570\u636e\uff0c\u518d\u5199\u5165\u65b0\u6570\u636e\u3002 command 2> file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u9519\u8bef\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u4e2d\u5df2\u5305\u542b\u6570\u636e\uff0c\u4f1a\u6e05\u7a7a\u539f\u6709\u6570\u636e\uff0c\u518d\u5199\u5165\u65b0\u6570\u636e\u3002 command >> file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u6807\u51c6\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u8f93\u51fa\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u5df2\u5305\u542b\u6570\u636e\uff0c\u65b0\u6570\u636e\u5c06\u8ffd\u52a0\u5199\u5165\u5230\u539f\u6709\u5185\u5bb9\u7684\u540e\u9762\u3002 command 2>> file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u9519\u8bef\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u4e2d\u5df2\u5305\u542b\u6570\u636e\uff0c\u65b0\u6570\u636e\u5c06\u8ffd\u52a0\u5199\u5165\u5230\u539f\u6709\u5185\u5bb9\u7684\u540e\u9762\u3002 command >> file 2>&1 \u6216\u8005 command &>> file \uff1a\u5c06\u6807\u51c6\u8f93\u51fa\u6216\u8005\u9519\u8bef\u8f93\u51fa\u5199\u5165\u5230\u6307\u5b9a\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u4e2d\u5df2\u5305\u542b\u6570\u636e\uff0c\u65b0\u6570\u636e\u5c06\u8ffd\u52a0\u5199\u5165\u5230\u539f\u6709\u5185\u5bb9\u7684\u540e\u9762\u3002 \u6ce8\u610f\uff1a\u4e0a\u9762\u7684 file \u53ef\u4ee5\u662f\u4e00\u4e2a\u666e\u901a\u6587\u4ef6\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u4e00\u4e2a\u7279\u6b8a\u7684\u6587\u4ef6 /dev/null \u3002 /dev/null \u5e76\u4e0d\u4fdd\u5b58\u6570\u636e\uff0c\u88ab\u5199\u5165 /dev/null \u7684\u6570\u636e\u6700\u7ec8\u90fd\u4f1a\u4e22\u5931\u3002 \u4e3e\u4f8b\uff1a2\u4e2apython\u6587\u4ef6\u5b58\u5728\uff0c\u5176\u4ed62\u4e2a\u65e0\u6269\u5c55\u540d\u7684\u6587\u4ef6\u4e0d\u5b58\u5728\u3002 ls file.py > out ls file 2 > out.err ls new.py >> out ls new 2 >> out.err \u53ef\u4ee5\u5f97\u5230\u9884\u671f\u7684\u7ed3\u679c\u3002\u4e24\u4e2a\u9519\u8bef\u8bb0\u5f55\u90fd\u88ab\u8ffd\u52a0\u5230 out.err \u6587\u4ef6\u4e2d\u3002\u4e24\u4e2a\u6210\u529f\u6267\u884c\u7684\u547d\u4ee4\u7684\u8fd4\u56de\u7ed3\u679c\u4e5f\u8f93\u51fa\u5230 out \u6587\u4ef6\u4e2d\u3002 $ccat out file.py new.py $ cat out.err ls: cannot access 'file' : No such file or directory ls: cannot access 'new' : No such file or directory \u4e0a\u4f8b\u547d\u4ee4\u4e5f\u53ef\u4ee5\u5408\u5e76\u3002 ls file.py > out 2 > out.err ls file >> out 2 >> out.err 2>&1 \u683c\u5f0f\u4e3e\u4f8b\uff1a $ ls file >> out.txt 2 > & 1 $ cat out.txt ls: cannot access 'file' : No such file or directory $ ls file.py & >> out.txt $ cat out.txt ls: cannot access 'file' : No such file or directory file.py 6.3.\u7279\u6b8a\u91cd\u5b9a\u5411 \u00b6 \u683c\u5f0f\uff1a command1 < <(command2) tr 'a-z' 'A-Z' < < ( echo \"Hello World\" ) \u5e94\u7528\uff1a\u4fee\u6539\u5bc6\u7801 \u5bc6\u7801\u4fdd\u5b58\u5728 passwd.txt \u6587\u4ef6\u4e2d\uff0c\u5e76\u4e25\u683c\u9650\u5236\u6539\u6587\u4ef6\u7684\u6743\u9650\u3002 \u901a\u8fc7\u53c2\u6570 --stdin \u5b9e\u73b0\u6a21\u62df\u952e\u76d8\u8f93\u5165\u64cd\u4f5c\u8f93\u5165\u7528\u6237\u540d\u3002 \u5728Rocky\u4e2d\u53ef\u4ee5\u4f7f\u7528 --stdin \u53c2\u6570\u3002 passwd --stdin vagrant < passwd.txt \u5728openSUSE\u548cUbuntu\u4e2d\uff0c --stdin \u53c2\u6570\u65e0\u6cd5\u8bc6\u522b\u3002\u53ef\u4ee5\u6539\u7528\u4e0b\u9762\u7684\u65b9\u6cd5\u3002 echo passwd.txt | chpasswd \u5176\u4e2dpasswd.txt\u7684\u683c\u5f0f\u4e3a username:password \u3002 \u53c2\u8003\uff1a Here-document(Here-doc)\uff1a\u8f93\u5165\u7684\u6587\u672c\u5757\u91cd\u5b9a\u5411\u81f3\u6807\u51c6\u8f93\u5165\u6d41\uff0c\u76f4\u81f3\u9047\u5230\u7279\u6b8a\u7684\u6587\u4ef6\u7ed3\u675f\u6807\u8bb0\u7b26\u4e3a\u6b62\uff08\u6587\u4ef6\u7ed3\u675f\u6807\u8bb0\u7b26\u53ef\u4ee5\u662f\u4efb\u610f\u7684\u552f\u4e00\u7684\u5b57\u7b26\u4e32\uff0c\u4f46\u5927\u90e8\u5206\u4eba\u90fd\u9ed8\u8ba4\u4f7f\u7528 EOF \uff09\u3002 cat < \u5c06\u547d\u4ee4\u4e0e\u6587\u4ef6\u8fde\u63a5\u8d77\u6765\uff0c\u7528\u6587\u4ef6\u6765\u63a5\u6536\u547d\u4ee4\u7684\u8f93\u51fa\uff1b\u800c\u7ba1\u9053\u7b26 | \u5c06\u547d\u4ee4\u4e0e\u547d\u4ee4\u8fde\u63a5\u8d77\u6765\uff0c\u7528\u53f3\u8fb9\u547d\u4ee4\u6765\u63a5\u6536\u5de6\u8fb9\u547d\u4ee4\u7684\u8f93\u51fa\u3002 $ ls | tr 'a-z' 'A-Z' BIN F1.TXT F2.TXT FILE.PY NEW.PY OUT OUT.ERR TEST.TXT","title":"\u7b2c\u4e8c\u7ae0 \u6587\u4ef6\u7cfb\u7edf"},{"location":"linux/SRE/02-filesystem/#_1","text":"\u6587\u4ef6\u7cfb\u7edf\u5c42\u6b21\u6807\u51c6\uff08Filesystem Hierarchy Standard, FHS\uff09\uff0c\u5b83\u662fLinux \u6807\u51c6\u5e93\uff08Linux Standards Base, LSB\uff09\u89c4\u8303\u7684\u4e00\u90e8\u5206\u3002 \u6839\u76ee\u5f55 / \u6307\u6587\u4ef6\u7cfb\u7edf\u6811\u7684\u6700\u9ad8\u5c42\u3002 \u6839\u5206\u533a\u5728\u7cfb\u7edf\u542f\u52a8\u65f6\u9996\u5148\u6302\u8f7d\u3002 \u7cfb\u7edf\u542f\u52a8\u65f6\u8fd0\u884c\u7684\u6240\u6709\u7a0b\u5e8f\u90fd\u5fc5\u987b\u5728\u6b64\u5206\u533a\u4e2d\u3002","title":"\u7b2c\u4e8c\u7ae0 \u6587\u4ef6\u7cfb\u7edf"},{"location":"linux/SRE/02-filesystem/#1","text":"\u4ee5\u4e0b\u76ee\u5f55\u5fc5\u987b\u5728\u6839\u5206\u533a\u4e2d\uff1a /bin - \u7528\u6237\u57fa\u672c\u7a0b\u5e8f\u3002 \u5305\u542b\u672a\u6302\u8f7d\u5176\u4ed6\u6587\u4ef6\u7cfb\u7edf\u65f6\u6240\u9700\u7684\u53ef\u6267\u884c\u6587\u4ef6\u3002 \u4f8b\u5982\uff0c\u7cfb\u7edf\u542f\u52a8\u3001\u5904\u7406\u6587\u4ef6\u548c\u914d\u7f6e\u6240\u9700\u7684\u7a0b\u5e8f\u3002 \u4e0d\u80fd\u5173\u8054\u5230\u72ec\u7acb\u5206\u533a\uff0c\u64cd\u4f5c\u7cfb\u7edf\u542f\u52a8\u5373\u4f1a\u8c03\u7528\u7684\u7a0b\u5e8f\u3002 /bin/bash - bash \u811a\u672c\u5904\u7406 /bin/cat - \u663e\u793a\u6587\u4ef6\u5185\u5bb9 /bin/cp - \u62f7\u8d1d\u6587\u4ef6 /bin/dd - \u62f7\u8d1d\u6587\u4ef6\uff08\u57fa\u4e8e\u5b57\u8282byte\uff09 /bin/gzip - \u538b\u7f29\u6587\u4ef6 /bin/mount - \u6302\u8f7d\u6587\u4ef6\u7cfb\u7edf /bin/rm - \u5220\u9664\u6587\u4ef6 /bin/vi - \u6587\u4ef6\u7f16\u8f91 /sbin - \u7cfb\u7edf\u57fa\u672c\u7a0b\u5e8f\u3002 \u5305\u542b\u57fa\u672c\u7cfb\u7edf\u7ba1\u7406\u7684\u7a0b\u5e8f\u3002 \u9ed8\u8ba4\u662froot\u7528\u6237\u6709\u6743\u9650\u6267\u884c\uff0c\u56e0\u6b64\u5b83\u4e0d\u5728\u5e38\u89c4\u7528\u6237\u8def\u5f84\u4e2d\u3002 \u4e0d\u80fd\u5173\u8054\u5230\u72ec\u7acb\u5206\u533a\uff0c\u64cd\u4f5c\u7cfb\u7edf\u542f\u52a8\u5373\u4f1a\u8c03\u7528\u7684\u7a0b\u5e8f \u4e00\u4e9b\u91cd\u8981\u7ba1\u7406\u7a0b\u5e8f\uff1a /sbin/fdisk* - \u7ba1\u7406\u786c\u76d8\u5206\u533a /sbin/fsck* - \u6587\u4ef6\u7cfb\u7edf\u68c0\u67e5\u3002\u4e0d\u80fd\u5728\u8fd0\u884c\u7684\u7cfb\u7edf\u4e0a\u9762\u76f4\u63a5\u6267\u884c fsck \uff0c\u635f\u574f\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u6267\u884c\u524d\u9700\u8981 umount \u3002 /sbin/mkfs - \u521b\u5efa\u6587\u4ef6\u7cfb\u7edf /sbin/shutdown - \u5173\u95ed\u7cfb\u7edf /dev - \u8bbe\u5907\u6587\u4ef6 \u4ee5\u592a\u7f51\u5361\u662f\u5185\u6838\u6a21\u5757\uff0c\u5176\u4ed6\u786c\u4ef6\u90fd\u4ee5\u8bbe\u5907dev\u7684\u65b9\u5f0f\u5c55\u73b0\u3002 \u5e94\u7528\u7a0b\u5e8f\u8bfb\u53d6\u548c\u5199\u5165\u8fd9\u4e9b\u6587\u4ef6\u4ee5\u64cd\u4f5c\u4f7f\u7528\u786c\u4ef6\u7ec4\u4ef6\u3002 \u4e24\u79cd\u7c7b\u578b\u8bbe\u5907\u6587\u4ef6\uff1a \u5b57\u7b26\u8bbe\u5907\uff08Character-oriented\uff09\u2013 \u5e8f\u5217\u8bbe\u5907\uff08\u6253\u5370\u673a\uff0c\u78c1\u5e26\u673a\uff0c\u9f20\u6807\u7b49\uff09 \u5757\u8bbe\u5907\uff08Block-oriented\uff09\u2013 \u786c\u76d8\uff0cDVD\u7b49 \u4e0e\u8bbe\u5907\u9a71\u52a8\u7a0b\u5e8f\u7684\u8fde\u63a5\u901a\u8fc7\u5185\u6838\u4e2d\u79f0\u4e3a\u4e3b\u8bbe\u5907\u53f7\u7684\u901a\u9053\u5b9e\u73b0\u3002 \u8fc7\u53bb\uff0c\u8fd9\u4e9b\u6587\u4ef6\u662f\u4f7f\u7528 mknod \u547d\u4ee4\u624b\u52a8\u521b\u5efa\u7684\u3002 \u73b0\u5728\u5f53\u5185\u6838\u53d1\u73b0\u8bbe\u5907\u65f6\uff0c\u5b83\u4eec\u4f1a\u7531 udev \u81ea\u52a8\u521b\u5efa\u3002 \u4e00\u4e9b\u91cd\u8981\u7684\u8bbe\u5907\u6587\u4ef6\uff1a Null\u8bbe\u5907: - /dev/null Zero\u8bbe\u5907: - /dev/zero \u7cfb\u7edf\u7ec8\u7aef: - /dev/console \u865a\u62df\u7ec8\u7aef: - /dev/tty1 \u4e32\u884c\u7aef\u53e3 - /dev/ttyS0 \u5e76\u884c\u7aef\u53e3: - /dev/lp0 \u8f6f\u76d8\u9a71\u52a8\u5668: - /dev/fd0 \u786c\u76d8\u9a71\u52a8\u5668: - /dev/sda \u786c\u76d8\u5206\u533a: - /dev/sda1 CD-ROM\u9a71\u52a8\u5668: - /dev/scd0 /etc - \u914d\u7f6e\u6587\u4ef6 \u5b58\u653e\u7cfb\u7edf\u548c\u670d\u52a1\u7684\u914d\u7f6e\u6587\u4ef6\u3002 \u5927\u90e8\u5206\u90fd\u662fASCII\u6587\u4ef6 \u666e\u901a\u7528\u6237\u53ef\u4ee5\u9ed8\u8ba4\u8bfb\u53d6\u5176\u4e2d\u7684\u5927\u90e8\u5206\u5185\u5bb9\u3002 \u8fd9\u4f1a\u5e26\u6765\u4e00\u4e2a\u6f5c\u5728\u7684\u5168\u95ee\u9898\uff0c\u56e0\u4e3a\u5176\u4e2d\u4e00\u4e9b\u6587\u4ef6\u5305\u542b\u5bc6\u7801\uff0c\u56e0\u6b64\u91cd\u8981\u7684\u662f\u8981\u786e\u4fdd\u8fd9\u4e9b\u6587\u4ef6\u53ea\u80fd\u7531root\u7528\u6237\u8bfb\u53d6\u3002 \u6839\u636eFHS\u6807\u51c6\uff0c\u6b64\u5904\u4e0d\u80fd\u653e\u7f6e\u4efb\u4f55\u53ef\u6267\u884c\u6587\u4ef6\uff0c\u4f46\u5b50\u76ee\u5f55\u53ef\u80fd\u5305\u542bshell\u811a\u672c\u3002 \u51e0\u4e4e\u6bcf\u4e2a\u5df2\u5b89\u88c5\u7684\u670d\u52a1\u5728 /etc \u6216\u5176\u5b50\u76ee\u5f55\u4e2d\u81f3\u5c11\u6709\u4e00\u4e2a\u914d\u7f6e\u6587\u4ef6\u3002 \u4e00\u4e9b\u91cd\u8981\u7684\u914d\u7f6e\u6587\u4ef6: /etc/os-release - \u7cfb\u7edf\u7248\u672c\u4fe1\u606f /etc/DIR_COLORS - ls \u547d\u4ee4\u4e2d\u7684\u989c\u8272\u914d\u7f6e\u4fe1\u606f\uff08openSUSE\u548cRocky\uff09 /etc/fstab - \u914d\u7f6e\u8981\u6302\u8f7d\u7684\u6587\u4ef6\u7cfb\u7edf /etc/profile - Shell\u767b\u5f55\u811a\u672c /etc/passwd - \u7528\u6237\u4fe1\u606f\u96c6\u5408\uff08\u4e0d\u542b\u5bc6\u7801\uff09 /etc/shadow - \u5bc6\u7801\u548c\u76f8\u5173\u4fe1\u606f /etc/group - \u7528\u6237\u7ec4\u4fe1\u606f\u96c6\u5408 /etc/cups/* - \u7528\u4e8eCUPS\u6253\u5370\u7cfb\u7edf\uff08CUPS=Common UNIX Printing System\uff09 /etc/hosts - \u4e3b\u673a\u540d\u673a\u5668IP\u5730\u5740 /etc/motd - \u767b\u5f55\u540e\u663e\u793a\u7684\u6b22\u8fce\u4fe1\u606f /etc/issue - \u767b\u5f55\u524d\u663e\u793a\u7684\u6b22\u8fce\u4fe1\u606f /etc/sysconfig/* - \u7cfb\u7edf\u914d\u7f6e\u6587\u4ef6 /lib - \u5e93\uff08Libraries\uff09 \u8bb8\u591a\u7a0b\u5e8f\u90fd\u5177\u6709\u4e00\u4e9b\u901a\u7528\u529f\u80fd\u3002 \u8fd9\u4e9b\u901a\u7528\u529f\u80fd\u53ef\u4ee5\u4fdd\u5b58\u5728\u5171\u4eab\u5e93\u4e2d\u3002 \u5171\u4eab\u5e93\u4e2d\u6587\u4ef6\u7684\u6269\u5c55\u540d\u662f .so \u3002 \u76ee\u5f55 /lib \u5305\u542b\u7684\u5171\u4eab\u5e93\u6587\u4ef6\u4e3b\u8981\u662f\u88ab /bin \u548c /sbin \u76ee\u5f55\u5305\u542b\u7684\u7a0b\u5e8f\u6240\u8c03\u7528\u3002 \u76ee\u5f55 /lib \u7684\u5b50\u76ee\u5f55\u5305\u542b\u4e00\u4e9b\u989d\u5916\u9700\u8981\u7684\u5171\u4eab\u5e93\u3002 \u5185\u6838\u6a21\u5757\u5b58\u50a8\u5728\u76ee\u5f55 /lib/modules \u3002 /lib64 - 64\u4f4d\u5171\u4eab\u5e93\uff0864-Bit Libraries\uff09\uff0c\u7c7b\u4f3c\u76ee\u5f55 /lib \u3002 \u8fd9\u4e2a\u76ee\u5f55\u56e0\u7cfb\u7edf\u67b6\u6784\u4e0d\u540c\u800c\u4e0d\u540c\u3002 \u4e00\u4e9b\u7cfb\u7edf\u652f\u6301\u4e0d\u540c\u7684\u4e8c\u8fdb\u5236\u683c\u5f0f\u5e76\u4fdd\u7559\u540c\u4e00\u4e2a\u5171\u4eab\u5e93\u7684\u4e0d\u540c\u7248\u672c\u3002 /usr - \u5305\u542b\u5e94\u7528\u7a0b\u5e8f\u3001\u56fe\u5f62\u754c\u9762\u6587\u4ef6\u3001\u5e93\u3001\u672c\u5730\u7a0b\u5e8f\u3001\u6587\u6863\u7b49\u3002 /usr \u5373 Unix System Resources. \u4f8b\u5982\uff1a /usr/X11R6/ - X Window \u7cfb\u7edf\u6587\u4ef6 /usr/bin/ - \u51e0\u4e4e\u5305\u542b\u6240\u6709\u53ef\u6267\u884c\u6587\u4ef6 /usr/lib/ - \u5305\u542b\u5e93\u548c\u5e94\u7528\u7a0b\u5e8f /usr/lib64/ - \u5305\u542b64\u4f4d\u5e93\u548c\u5e94\u7528\u7a0b\u5e8f /usr/include/ - \u5305\u542bC\u7a0b\u5e8f\u7684\u5934\u6587\u4ef6\uff08head file\uff09 /usr/local/ - \u5305\u542b\u672c\u5730\u5b89\u88c5\u7a0b\u5e8f\u3002\u8fd9\u4e2a\u76ee\u5f55\u4e0b\u7684\u5185\u5bb9\u4e0d\u4f1a\u88ab\u7cfb\u7edf\u5347\u7ea7\u6240\u8986\u76d6\u3002\u4e0b\u97623\u4e2a\u76ee\u5f55\u5728\u521d\u59cb\u5b89\u88c5\u540e\u662f\u7a7a\u7684\u3002 /usr/local/bin - /usr/local/sbin - /usr/local/lib - /usr/sbin/ - \u7cfb\u7edf\u7ba1\u7406\u7a0b\u5e8f /usr/src/ - \u5185\u6838\u548c\u5e94\u7528\u7a0b\u5e8f\u7684\u6e90\u4ee3\u7801 /usr/src/linux - /usr/share/ - \u7ed3\u6784\u5316\u72ec\u7acb\u6570\u636e /usr/share/doc/ - \u6587\u6863 /usr/share/man/ - man \u547d\u4ee4\u4f7f\u7528\u7684\u5185\u5bb9 /opt - \u7b2c\u4e09\u65b9\u5e94\u7528\u7a0b\u5e8f\u76ee\u5f55 \u5404\u53d1\u884c\u7248\u5305\u542b\u7684\u5e94\u7528\u7a0b\u5e8f\u4e00\u822c\u5b58\u50a8\u5728\u76ee\u5f55 /usr/lib/ \u3002 \u5404\u53d1\u884c\u7248\u53ef\u9009\u7a0b\u5e8f\uff0c\u6216\u7b2c\u4e09\u65b9\u5e94\u7528\u7a0b\u5e8f\u5219\u5b58\u50a8\u5728\u76ee\u5f55 /opt \u3002 \u5728\u5b89\u88c5\u65f6\uff0c\u4f1a\u4e3a\u6bcf\u4e2a\u5e94\u7528\u7a0b\u5e8f\u7684\u6587\u4ef6\u521b\u5efa\u4e00\u4e2a\u76ee\u5f55\uff0c\u5176\u4e2d\u5305\u542b\u5e94\u7528\u7a0b\u5e8f\u7684\u540d\u79f0\u3002\u6bd4\u5982\uff1a /opt/novell - /boot - \u5f15\u5bfc\u76ee\u5f55 /boot/grub2 - \u5305\u542bGRUB2\u7684\u9759\u6001\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\u6587\u4ef6\uff08GRUB = Grand Unified Boot Loader\uff09\u3002 \u5305\u542b\u4ee5\u94fe\u63a5 vmlinuz \u548c initrd \u6807\u8bc6\u7684\u5185\u6838\u548c initrd \u6587\u4ef6\u3002 /root - \u7ba1\u7406\u5458\u7684\u4e3b\u76ee\u5f55\uff08home directory\uff09\u3002 root \u7528\u6237\u7684\u4e3b\u76ee\u5f55\u3002\u5176\u4ed6\u7528\u6237\u7684\u4e3b\u76ee\u5f55\u662f\u5728\u76ee\u5f55 /home \u4e0b\u3002 root \u7528\u6237\u7684\u767b\u5f55\u73af\u5883\u914d\u7f6e\u4fdd\u5b58\u81f3 /root \u5206\u533a\u4e2d\u3002 /home - \u7528\u6237\u4e3b\u76ee\u5f55 \u6bcf\u4e2a\u7cfb\u7edf\u7528\u6237\u90fd\u6709\u4e00\u4e2a\u5206\u914d\u7684\u6587\u4ef6\u533a\u57df\uff0c\u8be5\u6587\u4ef6\u533a\u57df\u5728\u767b\u5f55\u540e\u6210\u4e3a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b83\u4eec\u5b58\u5728\u4e8e /home \u4e2d\u3002 /home \u4e2d\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u53ef\u4ee5\u4f4d\u4e8e\u5355\u72ec\u7684\u5206\u533a\u4e2d\uff0c\u4e5f\u53ef\u4ee5\u4f4d\u4e8e\u7f51\u7edc\u4e0a\u7684\u53e6\u4e00\u53f0\u8ba1\u7b97\u673a\u4e0a\u3002 \u7528\u6237\u914d\u7f6e\u4fe1\u606f\u548c\u914d\u7f6e\u6587\u4ef6\uff08user profile and configuration files\uff09\u4e3b\u8981\u6709\uff1a .profile - \u7528\u6237\u79c1\u6709\u767b\u5f55\u811a\u672c .bashrc - bash \u7684\u914d\u7f6e\u6587\u4ef6 .bash_history - bash \u73af\u5883\u4e0b\u4fdd\u6301\u547d\u4ee4\u5386\u53f2\u8bb0\u5f55 run - \u5e94\u7528\u7a0b\u5e8f\u72b6\u6001\u6587\u4ef6 \u4e3a\u5e94\u7528\u7a0b\u5e8f\u63d0\u4f9b\u4e86\u4e00\u4e2a\u6807\u51c6\u4f4d\u7f6e\u6765\u5b58\u50a8\u5b83\u4eec\u9700\u8981\u7684\u4e34\u65f6\u6587\u4ef6\uff0c\u4f8b\u5982\u5957\u63a5\u5b57\u548c\u8fdb\u7a0bID\u3002 \u8fd9\u4e9b\u6587\u4ef6\u4e0d\u80fd\u5b58\u50a8\u5728 /tmp \u4e2d\uff0c\u56e0\u4e3a /tmp \u4e2d\u7684\u6587\u4ef6\u53ef\u80fd\u4f1a\u88ab\u5220\u9664\u3002 /run/media//* - \u53ef\u79fb\u52a8\u8bbe\u5907\u7684\u6302\u8f7d\u70b9\uff0c\u4f8b\u5982\uff1a /run/media/media_name/ /run/media/cdrom/ - /run/media/dvd/ - /run/media/usbdisk/ - /mnt - \u6587\u4ef6\u7cfb\u7edf\u4e34\u65f6\u6302\u8f7d\u70b9 \u7528\u4e8e\u6302\u8f7d\u4e34\u65f6\u4f7f\u7528\u7684\u6587\u4ef6\u7cfb\u7edf\u7684\u76ee\u5f55\u3002 \u6587\u4ef6\u7cfb\u7edf\u4f7f\u7528 mount \u547d\u4ee4\u6302\u8f7d\uff0c\u4f7f\u7528 umount \u547d\u4ee4\u5220\u9664\u3002 \u5b50\u76ee\u5f55\u9ed8\u8ba4\u4e0d\u5b58\u5728\uff0c\u4e5f\u4e0d\u4f1a\u81ea\u52a8\u521b\u5efa\u3002 /srv - \u670d\u52a1\u6570\u636e\u76ee\u5f55 \u5b58\u653e\u5404\u79cd\u670d\u52a1\u7684\u6570\u636e\uff0c\u6bd4\u5982\uff1a /srv/www - \u7528\u4e8e\u5b58\u653e Apache Web Server \u7684\u6570\u636e /srv/ftp - \u7528\u4e8e\u5b58\u653e FTP server \u7684\u6570\u636e /var - \u53ef\u53d8\u6587\u4ef6\uff08Variable Files\uff09 \u5728\u7cfb\u7edf\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u4f1a\u88ab\u4fee\u6539\u7684\u6587\u4ef6 Important subdirectories: /var/lib/ - \u53ef\u53d8\u5e93\u6587\u4ef6\uff0c\u5e94\u7528\u7a0b\u5e8f\u72b6\u6001\u4fe1\u606f\u6570\u636e /var/log/ - \u65e5\u5fd7\u6587\u4ef6 /var/run/ - \u8fd0\u884c\u4e2d\u7684\u8fdb\u7a0b\u7684\u4fe1\u606f /var/lock/ - \u591a\u7528\u6237\u8bbf\u95ee\u65f6\u7684\u9501\u6587\u4ef6 /var/cache - \u5e94\u7528\u7a0b\u5e8f\u7f13\u5b58\u6570\u636e\u76ee\u5f55 /var/opt - \u4e13\u4e3a /opt \u4e0b\u7684\u5e94\u7528\u7a0b\u5e8f\u5b58\u50a8\u53ef\u53d8\u6570\u636e /var/mail - /var/spool/ - \u5e94\u7528\u7a0b\u5e8f\u6570\u636e\u6c60\uff0c\u6bd4\u5982\uff1a\u6253\u5370\u673a\uff0c\u90ae\u4ef6 /var/spool/mail - /var/spool/cron - /tmp - \u4e34\u65f6\u6587\u4ef6 \u7a0b\u5e8f\u5728\u8fd0\u884c\u65f6\u521b\u5efa\u4e34\u65f6\u6587\u4ef6\u7684\u4f4d\u7f6e /proc - \u8fdb\u7a0b\u6587\u4ef6 \u865a\u62df\u6587\u4ef6\u7cfb\u7edf\uff0c\u4e0d\u5360\u7a7a\u95f4\uff0c\u5927\u5c0f\u59cb\u7ec8\u4e3a\u96f6\uff0c\u4fdd\u6301\u5f53\u524d\u8fdb\u7a0b\u7684\u72b6\u6001\u4fe1\u606f \u5305\u542b\u6709\u5173\u5404\u4e2a\u8fdb\u7a0b\u7684\u4fe1\u606f\u7684\u76ee\u5f55\uff0c\u6839\u636e\u8fdb\u7a0b\u7684 PID \u53f7\u547d\u540d \u6709\u4e9b\u503c\u53ef\u4ee5\u4e34\u65f6\u5728\u7ebf\u66f4\u6539\u751f\u6548\uff0c\u4f46\u91cd\u542f\u540e\u4e22\u5931 /proc/cpuinfo/ - Processor information /proc/dma/ - Use of DMA ports /proc/interrupts/ - Use of interrupts /proc/ioports/ - Use of I/O ports /proc/filesystems/ - File system formats the kernel knows /proc/modules/ - Active modules /proc/mounts/ - Mounted file systems /proc/net/* - Network information and statistics /proc/partitions/ - Existing partitions /proc/bus/pci/ - Connected PCI devices /proc/bus/scsi/ - Connected SCSI devices /proc/sys/* - System and kernel information /proc/version - Kernel version /sys - \u7cfb\u7edf\u4fe1\u606f\u76ee\u5f55 \u865a\u62df\u6587\u4ef6\u7cfb\u7edf\uff0c\u4ec5\u5b58\u5728\u4e8e\u5185\u5b58\u4e2d\uff0c\u6587\u4ef6\u5927\u5c0f\u4e3a\u96f6\u3002\u4e3b\u8981\u63d0\u4f9b\u5982\u4e0b\u4fe1\u606f\uff1a \u786c\u4ef6\u603b\u7ebf\uff08hardware buses\uff09 \u786c\u4ef6\u8bbe\u5907\uff08hardware devices\uff09 \u6709\u6e90\u8bbe\u5907\uff08active devices\uff09 \u9a71\u52a8\u7a0b\u5e8f\uff08drivers\uff09","title":"1.\u4e3b\u8981\u76ee\u5f55"},{"location":"linux/SRE/02-filesystem/#2","text":"","title":"2.\u6587\u4ef6\u64cd\u4f5c\u547d\u4ee4"},{"location":"linux/SRE/02-filesystem/#21","text":"pwd\u547d\u4ee4\uff08print working directory\uff09: -L: \u663e\u793a\u94fe\u63a5\u8def\u5f84 -P\uff1a\u663e\u793a\u771f\u5b9e\u7269\u7406\u8def\u5f84","title":"2.1.\u663e\u793a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55"},{"location":"linux/SRE/02-filesystem/#22","text":"\u5bf9\u4e8e\u7edd\u5bf9\u8def\u5f84 /etc/firewalld/policies \uff0c\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u5f97\u5230\u8be5\u8def\u5f84\u7684\u57fa\u540d policies \u548c\u76ee\u5f55\u540d /etc/firewalld \u3002 basename /etc/firewalld/policies dirname /etc/firewalld/policies","title":"2.2.\u76f8\u5bf9\u548c\u7edd\u5bf9\u8def\u5f84"},{"location":"linux/SRE/02-filesystem/#23","text":". \u6307\u5f53\u524d\u76ee\u5f55\uff0c\u5373 pwd \u547d\u4ee4\u6240\u8fd4\u56de\u7684\u76ee\u5f55\u3002 .. \u6307\u5f53\u524d\u76ee\u5f55\u7684\u4e0a\u4e00\u7ea7\u76ee\u5f55\uff0c\u53ca\u5f53\u524d\u76ee\u5f55\u7684\u7236\u76ee\u5f55\u3002 \u5207\u6362\u81f3\u7236\u76ee\u5f55\uff1a cd .. \u5207\u6362\u81f3\u5f53\u524d\u7528\u6237\u4e3b\u76ee\u5f55\uff1a cd ~ \u5207\u6362\u81f3\u4e0a\u6b21\u5de5\u4f5c\u76ee\u5f55\uff1a cd - echo $PWD \uff1a\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55 echo $OLDPWD \uff1a\u4e0a\u6b21\u5de5\u4f5c\u76ee\u5f55","title":"2.3.\u66f4\u6539\u76ee\u5f55"},{"location":"linux/SRE/02-filesystem/#24","text":"ls \u547d\u4ee4\uff1a -a \u663e\u793a\u6240\u6709\u6587\u4ef6\u53ca\u76ee\u5f55 (. \u5f00\u5934\u7684\u9690\u85cf\u6587\u4ef6\u4e5f\u4f1a\u5217\u51fa) -A \u540c -a \uff0c\u4f46\u4e0d\u5217\u51fa . (\u76ee\u524d\u76ee\u5f55) \u53ca .. (\u7236\u76ee\u5f55) -l \u9664\u6587\u4ef6\u540d\u79f0\u5916\uff0c\u4ea6\u5c06\u6587\u4ef6\u578b\u6001\u3001\u6743\u9650\u3001\u62e5\u6709\u8005\u3001\u6587\u4ef6\u5927\u5c0f\u7b49\u8d44\u8baf\u8be6\u7ec6\u5217\u51fa -r \u5c06\u6587\u4ef6\u4ee5\u76f8\u53cd\u6b21\u5e8f\u663e\u793a(\u539f\u5b9a\u4f9d\u82f1\u6587\u5b57\u6bcd\u6b21\u5e8f) -t \u5c06\u6587\u4ef6\u4f9d\u5efa\u7acb\u65f6\u95f4\u4e4b\u5148\u540e\u6b21\u5e8f\u5217\u51fa -F \u5728\u5217\u51fa\u7684\u6587\u4ef6\u540d\u79f0\u540e\u52a0\u4e00\u7b26\u53f7\uff1b\u4f8b\u5982\u53ef\u6267\u884c\u6863\u5219\u52a0 \"*\", \u76ee\u5f55\u5219\u52a0 \"/\" -R \u9012\u5f52\u5217\u51fa\u5b50\u76ee\u5f55 -S \u6309\u6587\u4ef6\u5927\u5c0f\u6392\u5e8f\uff0c\u4ece\u5927\u5230\u5c0f -1 \u6309\u4e00\u4e2a\u6587\u4ef6\u4e00\u884c\u5217\u51fa -t \u6309\u6587\u4ef6\u65f6\u95f4\u6392\u5e8f\uff0c\u6700\u65b0\u7684\u5728\u524d -U \u4e0d\u6392\u5e8f\u8f93\u51fa\uff0c\u6309\u76ee\u5f55\u5b58\u653e\u987a\u5e8f\u5217\u51fa -u \u914d\u5408 -lt \uff0c\u6309\u8bbf\u95ee\u65f6\u95f4\u6392\u5e8f\u5e76\u663e\u793a\uff1b\u914d\u5408 -l \uff0c\u663e\u793a\u8bbf\u95ee\u65f6\u95f4\u5e76\u6309\u540d\u79f0\u6392\u5e8f\uff1b \u5426\u5219\u6309\u8bbf\u95ee\u65f6\u95f4\u6392\u5e8f\uff0c\u6700\u65b0\u7684\u5728\u524d -X \u6309\u6587\u4ef6\u6269\u5c55\u540d\u5b57\u6bcd\u987a\u5e8f\u6392\u5e8f\u8f93\u51fa -F \u5bf9\u4e0d\u540c\u7c7b\u578b\u6587\u4ef6\u663e\u793a\u65f6\u9644\u52a0\u4e0d\u540c\u7684\u7b26\u53f7\uff0c * / = > @ | \u4e4b\u4e00 ls \u547d\u4ee4\u67e5\u770b\u4e0d\u540c\u6587\u4ef6\u662f\u7684\u989c\u8272\uff0c\u7531 /etc/DIR_COLORS \u548c\u53d8\u91cf @LS_COLORS \u5b9a\u4e49\u3002","title":"2.4.\u5217\u51fa\u76ee\u5f55\u5185\u5bb9"},{"location":"linux/SRE/02-filesystem/#25stat","text":"\u6bcf\u4e2a\u6587\u4ef6\u6709\u4e09\u4e2a\u65f6\u95f4\u6233\uff1a \u8bbf\u95ee\u65f6\u95f4 Access Time atime : \u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u3002 \u4fee\u6539\u65f6\u95f4 Modify Time mtime : \u6539\u53d8\u6587\u4ef6\u5185\u5bb9\uff08\u6570\u636e\uff09\u3002 \u6539\u53d8\u65f6\u95f4 Change Time ctime : \u5143\u6570\u636e\u53d1\u751f\u6539\u53d8\u3002 \u8bfb\u53d6\u4e09\u4e2a\u65f6\u95f4\u6233\u7684\u547d\u4ee4 stat \uff1a stat /etc/fstab \u8f93\u51fa\u7ed3\u679c\uff1a File: /etc/fstab Size: 927 Blocks: 8 IO Block: 4096 regular file Device: 30h/48d Inode: 263 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2022-10-31 10:26:34.987466959 +0800 Modify: 2022-06-24 14:50:24.387992912 +0800 Change: 2022-06-24 14:50:24.387992912 +0800 Birth: 2022-06-24 14:50:23.755992937 +0800","title":"2.5.\u6587\u4ef6\u72b6\u6001stat"},{"location":"linux/SRE/02-filesystem/#26","text":"\u547d\u4ee4 file \u68c0\u67e5\u6587\u4ef6\u7c7b\u578b\u3002 -b \uff1a\u5217\u51fa\u8fa8\u8bc6\u7ed3\u679c\u65f6\uff0c\u4e0d\u663e\u793a\u6587\u4ef6\u540d\u79f0\u3002 -c \uff1a\u8be6\u7ec6\u663e\u793a\u6307\u4ee4\u6267\u884c\u8fc7\u7a0b\uff0c\u4fbf\u4e8e\u6392\u9519\u6216\u5206\u6790\u7a0b\u5e8f\u6267\u884c\u7684\u60c5\u5f62\u3002 -f <\u540d\u79f0\u6587\u4ef6> \uff1a\u6307\u5b9a\u540d\u79f0\u6587\u4ef6\uff0c\u5176\u5185\u5bb9\u6709\u4e00\u4e2a\u6216\u591a\u4e2a\u6587\u4ef6\u540d\u79f0\u65f6\uff0c\u8ba9file\u4f9d\u5e8f\u8fa8\u8bc6\u8fd9\u4e9b\u6587\u4ef6\uff0c\u683c\u5f0f\u4e3a\u6bcf\u5217\u4e00\u4e2a\u6587\u4ef6\u540d\u79f0\u3002 -L \uff1a \u76f4\u63a5\u663e\u793a\u7b26\u53f7\u8fde\u63a5\u6240\u6307\u5411\u7684\u6587\u4ef6\u7684\u7c7b\u522b\u3002 -v \uff1a \u663e\u793a\u7248\u672c\u4fe1\u606f\u3002 -z \uff1a \u5c1d\u8bd5\u53bb\u89e3\u8bfb\u538b\u7f29\u6587\u4ef6\u7684\u5185\u5bb9\u3002 \u7f16\u8f91\u6587\u4ef6 list.txt \u5305\u542b\u4e00\u4e0b\u5185\u5bb9\uff1a /etc/ /bin /etc/issue \u8fd0\u884c\u547d\u4ee4 file -f list.txt \uff0c\u7ed3\u679c\u5982\u4e0b\uff1a /etc/: directory /bin: directory /etc/issue: symbolic link to ../run/issue","title":"2.6.\u786e\u5b9a\u6587\u4ef6\u7c7b\u578b"},{"location":"linux/SRE/02-filesystem/#27","text":"iconv \u547d\u4ee4\u7528\u4e8e\u5c06\u4e00\u79cd\u7f16\u7801\u4e2d\u7684\u67d0\u4e9b\u6587\u672c\u8f6c\u6362\u4e3a\u53e6\u4e00\u79cd\u7f16\u7801\u3002 \u5982\u679c\u6ca1\u6709\u63d0\u4f9b\u8f93\u5165\u6587\u4ef6\uff0c\u5219\u5b83\u4ece\u6807\u51c6\u8f93\u5165\u4e2d\u8bfb\u53d6\u3002 \u540c\u6837\uff0c\u5982\u679c\u6ca1\u6709\u7ed9\u51fa\u8f93\u51fa\u6587\u4ef6\uff0c\u90a3\u4e48\u5b83\u4f1a\u5199\u5165\u6807\u51c6\u8f93\u51fa\u3002 \u5982\u679c\u6ca1\u6709\u63d0\u4f9b from-encoding \u6216 to-encoding \uff0c\u5219\u5b83\u4f7f\u7528\u5f53\u524d\u672c\u5730\u7684\u5b57\u7b26\u7f16\u7801\u3002 \u5c06\u6587\u672c\u4ece ISO 8859-15 \u5b57\u7b26\u7f16\u7801\u8f6c\u6362\u4e3a UTF-8\uff0c\u8bfb\u5165 input.txt \uff0c\u8f93\u51fa output.txt \u3002 iconv -f ISO-8859-15 -t UTF-8 < input.txt > output.txt \u4ece UTF-8 \u8f6c\u6362\u4e3a ASCII\uff0c\u5c3d\u53ef\u80fd\u8fdb\u884c\u97f3\u8bd1\uff08transliterating\uff09\uff1a echo abc \u00df \u03b1 \u20ac \u00e0\u1e03\u00e7 | iconv -f UTF-8 -t ASCII//TRANSLIT \u8fd0\u884c\u7ed3\u679c\uff1a abc ss ? EUR abc","title":"2.7.\u6587\u4ef6\u7f16\u7801\u8f6c\u6362"},{"location":"linux/SRE/02-filesystem/#28","text":"\u901a\u914d\u7b26\uff0c\u6307\u5305\u542b\u8fd9\u4e9b\u5b57\u7b26\u7684\u5b57\u7b26\u4e32 ? \uff1a\u8868\u793a\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26 * \uff1a\u8868\u793a\u4efb\u610f\u957f\u5ea6\u7684\u4efb\u610f\u5b57\u7b26 [] \uff1a\u5339\u914d\u6307\u5b9a\u8303\u56f4\u5185\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26 [abcd] \uff1a\u5339\u914dabcd\u4e2d\u7684\u4efb\u4f55\u4e00\u4e2a\u5b57\u7b26 [a-z] \uff1a\u5339\u914d\u8303\u56f4a\u5230z\u5185\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26 [!abcd] \uff1a\u4e0d\u5339\u914d\u62ec\u53f7\u91cc\u9762\u4efb\u4f55\u4e00\u4e2a\u5b57\u7b26 {} \uff1a\u8868\u793a\u751f\u6210\u5e8f\u5217\uff0c\u4ee5\u9017\u53f7\u5206\u5272\uff0c\u4e0d\u80fd\u6709\u7a7a\u683c \u793a\u4f8b\uff1a $ touch file_ { a..z } .txt $ touch file_ { A..Z } .txt $ ls file_a.txt file_C.txt file_f.txt file_H.txt file_k.txt file_M.txt file_p.txt file_R.txt file_u.txt file_W.txt file_z.txt file_A.txt file_d.txt file_F.txt file_i.txt file_K.txt file_n.txt file_P.txt file_s.txt file_U.txt file_x.txt file_Z.txt file_b.txt file_D.txt file_g.txt file_I.txt file_l.txt file_N.txt file_q.txt file_S.txt file_v.txt file_X.txt file_B.txt file_e.txt file_G.txt file_j.txt file_L.txt file_o.txt file_Q.txt file_t.txt file_V.txt file_y.txt file_c.txt file_E.txt file_h.txt file_J.txt file_m.txt file_O.txt file_r.txt file_T.txt file_w.txt file_Y.txt $ ls file_ [ a..d ] .* file_a.txt file_d.txt $ ls file_ [ a...d ] .* file_a.txt file_d.txt $ ls file_ [ ad ] .* file_a.txt file_d.txt $ ls file_ [ a-c ] .* file_a.txt file_A.txt file_b.txt file_B.txt file_c.txt $ ls file_ [ a-C ] .* file_a.txt file_A.txt file_b.txt file_B.txt file_c.txt file_C.txt $ ls file_ [ !d-W ] .* file_a.txt file_b.txt file_c.txt file_x.txt file_y.txt file_z.txt file_A.txt file_B.txt file_C.txt file_X.txt file_Y.txt file_Z.txt \u6bd4\u8f83\u6709\u65e0 * \u7684\u533a\u522b\uff1a $ ls -a * file_a.txt file_D.txt file_h.txt file_K.txt file_o.txt file_R.txt file_v.txt file_Y.txt file_A.txt file_e.txt file_H.txt file_l.txt file_O.txt file_s.txt file_V.txt file_z.txt file_b.txt file_E.txt file_i.txt file_L.txt file_p.txt file_S.txt file_w.txt file_Z.txt file_B.txt file_f.txt file_I.txt file_m.txt file_P.txt file_t.txt file_W.txt file_c.txt file_F.txt file_j.txt file_M.txt file_q.txt file_T.txt file_x.txt file_C.txt file_g.txt file_J.txt file_n.txt file_Q.txt file_u.txt file_X.txt file_d.txt file_G.txt file_k.txt file_N.txt file_r.txt file_U.txt file_y.txt $ ls -a . file_C.txt file_g.txt file_J.txt file_n.txt file_Q.txt file_u.txt file_X.txt .. file_d.txt file_G.txt file_k.txt file_N.txt file_r.txt file_U.txt file_y.txt file_a.txt file_D.txt file_h.txt file_K.txt file_o.txt file_R.txt file_v.txt file_Y.txt file_A.txt file_e.txt file_H.txt file_l.txt file_O.txt file_s.txt file_V.txt file_z.txt file_b.txt file_E.txt file_i.txt file_L.txt file_p.txt file_S.txt file_w.txt file_Z.txt file_B.txt file_f.txt file_I.txt file_m.txt file_P.txt file_t.txt file_W.txt file_c.txt file_F.txt file_j.txt file_M.txt file_q.txt file_T.txt file_x.txt","title":"2.8.\u901a\u914d\u7b26"},{"location":"linux/SRE/02-filesystem/#29","text":"[:alpha:] \uff1a\u8868\u793a\u6240\u6709\u7684\u5b57\u6bcd\uff08\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff09\uff0c\u6548\u679c\u540c [a-z] [:digit:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u6570\u5b57\uff0c\u6548\u679c\u540c [0-9] [:xdigit:] \uff1a\u8868\u793a\u5341\u516d\u8fdb\u5236\u6570\u5b57 [:lower:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5c0f\u5199\u5b57\u6bcd [:upper:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5927\u5199\u5b57\u6bcd [:alnum:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5b57\u6bcd\u6216\u6570\u5b57 [:blank:] \uff1a\u8868\u793a\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u548c\u5236\u8868\u7b26\uff09 [:space:] \uff1a\u8868\u793a\u5305\u62ec\u7a7a\u683c\u3001\u5236\u8868\u7b26\uff08\u6c34\u5e73\u548c\u5782\u76f4\uff09\u3001\u6362\u884c\u7b26\u3001\u56de\u8f66\u7b26\u7b49\u5404\u79cd\u7c7b\u578b\u7684\u7a7a\u767d\uff0c\u6bd4 [:blank:] \u8303\u56f4\u66f4\u5e7f [:cntrl:] \uff1a\u8868\u793a\u4e0d\u53ef\u6253\u5370\u7684\u63a7\u5236\u5b57\u7b26\uff08\u9000\u683c\u3001\u5220\u9664\u3001\u8b66\u94c3\u7b49\uff09 [:graph:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u7684\u975e\u7a7a\u767d\u5b57\u7b26 [:print:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u5b57\u7b26 [:punct:] \uff1a\u8868\u793a\u6807\u70b9\u7b26\u53f7 \u4e3e\u4f8b\uff1a ls -d [[:alpha:]] \u5373 ls -d [a-Z] \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u5355\u4e2a\u5b57\u6bcd\u7684\u76ee\u5f55\u548c\u6587\u4ef6 ls -d *[[:digit:]] \u5373 ls -d *[0-9] \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u4ee5\u6570\u5b57\u7ed3\u5c3e\u7684\u76ee\u5f55\u548c\u6587\u4ef6 ls [[:lower:]].txt \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u4ee5\u5355\u4e2a\u5c0f\u5199\u5b57\u6bcd\u4e3a\u540d\u7684.txt\u683c\u5f0f\u7684\u6587\u4ef6 ls -d [[:alnum:]] \uff1a\u663e\u793a\u5f53\u524d\u76ee\u5f55\u4e0b\u6240\u6709\u5355\u4e2a\u5b57\u6bcd\uff08\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff09\u6216\u6570\u5b57\u4e3a\u540d\u7684\u76ee\u5f55\u6216\u6587\u4ef6","title":"2.9.\u5b57\u7b26\u96c6"},{"location":"linux/SRE/02-filesystem/#210","text":"| \uff1a\u7ba1\u9053\u7b26\uff0c\u6216\u8005\uff08\u6b63\u5219\uff09 > \uff1a\u8f93\u51fa\u91cd\u5b9a\u5411 >> \uff1a\u8f93\u51fa\u8ffd\u52a0\u91cd\u5b9a\u5411 < \uff1a\u8f93\u5165\u91cd\u5b9a\u5411 << \uff1a\u8ffd\u52a0\u8f93\u5165\u91cd\u5b9a\u5411 ~ \uff1a\u5f53\u524d\u7528\u6237\u5bb6\u76ee\u5f55 $() \uff1a\u5f15\u7528\u547d\u4ee4\u88ab\u6267\u884c\u540e\u7684\u7ed3\u679c $ \uff1a\u4ee5...\u7ed3\u5c3e\uff08\u6b63\u5219\uff09 ^ \uff1a\u4ee5...\u5f00\u5934\uff08\u6b63\u5219\uff09 * \uff1a\u5339\u914d\u5168\u90e8\u5b57\u7b26\uff0c\u901a\u914d\u7b26 ? \uff1a\u4efb\u610f\u4e00\u4e2a\u5b57\u7b26\uff0c\u901a\u914d\u7b26 # \uff1a\u6ce8\u91ca & \uff1a\u8ba9\u7a0b\u5e8f\u6216\u811a\u672c\u5207\u6362\u5230\u540e\u53f0\u6267\u884c && \uff1a\u5e76\u4e14\uff0c\u540c\u65f6\u6210\u7acb [] \uff1a\u8868\u793a\u4e00\u4e2a\u8303\u56f4\uff08\u6b63\u5219\uff0c\u901a\u914d\u7b26\uff09 {} \uff1a\u4ea7\u751f\u4e00\u4e2a\u5e8f\u5217\uff08\u901a\u914d\u7b26\uff09 . \uff1a\u5f53\u524d\u76ee\u5f55\u7684\u786c\u94fe\u63a5 .. \uff1a\u4e0a\u7ea7\u76ee\u5f55\u7684\u786c\u94fe\u63a5","title":"2.10.\u7279\u6b8a\u7b26\u53f7"},{"location":"linux/SRE/02-filesystem/#211touch","text":"touch \u547d\u4ee4\u53ef\u4ee5\u521b\u5efa\u7a7a\u6587\u4ef6\uff0c\u4e5f\u53ef\u4ee5\u5237\u65b0\u6587\u4ef6\u65f6\u95f4\u3002\u53c2\u6570\u5982\u4e0b\uff1a -a \uff1a\u4ec5\u6539\u53d8 atime \u548c ctime -m \uff1a\u4ec5\u6539\u53d8 mtime \u548c ctime -t [[CC]YY]MMDDhhmm[.ss] \uff1a\u6307\u5b9a atime \u548c mtime -c \uff1a\u5982\u679c\u6587\u4ef6\u4e0d\u5b58\u5728\uff0c\u5219\u4e0d\u521b\u5efa $ touch file1 $ touch file2 $ ll -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 -rw-r--r--. 1 vagrant wheel 0 Nov 8 20 :28 file2 \u521b\u5efa\u6587\u4ef6file-non.log\uff0c\u5982\u679c\u4e0d\u5b58\u5728\u5219\u4e0d\u521b\u5efa\u3002 touch -c file-non.log \u66f4\u65b0 file1 \u7684\u65f6\u95f4\u548c file2 \u4e00\u81f4\u3002 $ touch -r file1 file2 $ ll -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 -rw-r--r--. 1 vagrant wheel 0 Nov 8 20 :49 file2 \u6307\u5b9a file2 \u7684\u65f6\u95f4\u3002 202210012135.25 \u4ee3\u8868 YYYYMMDDHHMM.SS \u3002 $ touch -t 202210012135 .25 file2 $ ll -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 -rw-r--r--. 1 vagrant wheel 0 Oct 1 21 :35 file2 $ stat file2 File: file2 Size: 0 Blocks: 0 IO Block: 4096 regular empty file Device: fd02h/64770d Inode: 140 Links: 1 Access: ( 0644 /-rw-r--r-- ) Uid: ( 1000 / vagrant ) Gid: ( 10 / wheel ) Context: unconfined_u:object_r:user_home_t:s0 Access: 2022 -10-01 21 :35:25.000000000 +0800 Modify: 2022 -10-01 21 :35:25.000000000 +0800 Change: 2022 -11-08 20 :56:18.306315887 +0800 Birth: 2022 -11-08 20 :28:37.809551441 +0800","title":"2.11.\u5237\u65b0\u6587\u4ef6\u65f6\u95f4touch"},{"location":"linux/SRE/02-filesystem/#212cp","text":"cp \u547d\u4ee4\uff1aCopy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY. \u5e38\u7528\u53c2\u6570\uff1a -a \uff1a\u5f52\u6863\uff0c\u76f8\u5f53\u4e8e -dR --preserv=all \u53c2\u6570\u7ec4\u5408\uff0c\u5e38\u7528\u4e8e\u5907\u4efd\u3002 -d \uff1a\u4e0d\u590d\u5236\u539f\u6587\u4ef6\uff0c\u53ea\u590d\u5236\u94fe\u63a5\u540d\u3002\u76f8\u5f53\u4e8e --no-dereference --preserve=links \u53c2\u6570\u7ec4\u5408\u3002 -f \uff1a\u8986\u76d6\u5df2\u7ecf\u5b58\u5728\u7684\u76ee\u6807\u6587\u4ef6\u3002 -i \uff1a\u8986\u76d6\u76ee\u6807\u6587\u4ef6\u4e4b\u524d\u7ed9\u51fa\u63d0\u793a\u3002 -p \uff1a\u9664\u590d\u5236\u6587\u4ef6\u7684\u5185\u5bb9\u5916\uff0c\u4e5f\u590d\u5236\u6587\u4ef6\u6743\u9650\uff0c\u65f6\u95f4\u6233\uff0c\u5c5e\u4e3b\u5c5e\u7ec4\u3002\u76f8\u5f53\u4e8e --preserve=mode,ownership,timestamps \u3002 -r, -R, --recursive \uff1a\u9012\u5f52\u590d\u5236\u76ee\u5f55\u6240\u5305\u542b\u7684\u5168\u90e8\u5185\u5bb9\u3002 -l \uff1a\u4e0d\u590d\u5236\u6587\u4ef6\uff0c\u53ea\u662f\u751f\u6210\u786c\u94fe\u63a5\u6587\u4ef6\u3002 \u53c2\u6570 --preserv \u53ef\u9009\u9879\uff1a mode\uff1a\u6743\u9650 ownership\uff1a\u5c5e\u4e3b\u5c5e\u7ec4 timestamp links xattr context all \u521b\u5efa\u6d4b\u8bd5\u76ee\u5f55\u3002 cd ~ mkdir test \u5bf9\u6bd4\u53c2\u6570 -p \u7684\u5dee\u522b\u3002 $ cp /etc/issue ~/test/issue1 $ cp -p /etc/issue ~/test/issue1 $ sudo cp /etc/issue ~/test/issue3 $ sudo cp -p /etc/issue ~/test/issue4 $ ll ~/test -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 issue1 -rw-r--r--. 1 vagrant wheel 23 Jul 21 01 :10 issue2 -rw-r--r--. 1 root root 23 Nov 8 22 :43 issue3 -rw-r--r--. 1 root root 23 Jul 21 01 :10 issue4 $ ll /etc/issue -rw-r--r--. 1 root root 23 Jul 21 01 :10 /etc/issue \u5bf9\u6bd4\u53c2\u6570 -r \u3002 $ sudo cp /etc/sysconfig/ ~/test cp: -r not specified ; omitting directory '/etc/sysconfig/' $ sudo cp -r /etc/sysconfig/ ~/test $ tree -L 2 ~/test /home/vagrant/test \u251c\u2500\u2500 issue1 \u251c\u2500\u2500 issue2 \u251c\u2500\u2500 issue3 \u251c\u2500\u2500 issue4 \u2514\u2500\u2500 sysconfig \u251c\u2500\u2500 anaconda \u251c\u2500\u2500 atd \u251c\u2500\u2500 chronyd \u251c\u2500\u2500 cpupower \u251c\u2500\u2500 crond \u251c\u2500\u2500 firewalld \u251c\u2500\u2500 irqbalance \u251c\u2500\u2500 kdump \u251c\u2500\u2500 kernel \u251c\u2500\u2500 man-db \u251c\u2500\u2500 network \u251c\u2500\u2500 network-scripts \u251c\u2500\u2500 nftables.conf \u251c\u2500\u2500 raid-check \u251c\u2500\u2500 rsyslog \u251c\u2500\u2500 run-parts \u251c\u2500\u2500 samba \u251c\u2500\u2500 selinux -> ../selinux/config \u251c\u2500\u2500 smartmontools \u2514\u2500\u2500 sshd \u53c2\u6570 -b \uff0c\u5982\u679c\u76ee\u6807\u6587\u4ef6\u5b58\u5728\uff0c\u590d\u5236\u524d\u5148\u5c06\u539f\u6587\u4ef6\u590d\u5236\u5e76\u4ee5 ~ \u7ed3\u5c3e\u3002 $ ll /etc/motd -rw-r--r--. 1 root root 0 Jun 23 2020 /etc/motd $ ll ~/test/issue1 -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 /home/vagrant/test/issue1 $ cp -b /etc/motd ~/test/issue $ cp -b /etc/motd ~/test/issue1 $ ll ~/test -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :00 issue -rw-r--r--. 1 vagrant wheel 0 Nov 8 22 :57 issue1 -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 issue1~ -rw-r--r--. 1 vagrant wheel 23 Jul 21 01 :10 issue2 -rw-r--r--. 1 root root 23 Nov 8 22 :43 issue3 -rw-r--r--. 1 root root 23 Jul 21 01 :10 issue4 drwxr-xr-x. 3 root root 4096 Nov 8 22 :49 sysconfig \u53c2\u6570 --backup=numbered \u4f1a\u5728\u590d\u5236\u539f\u6587\u4ef6\u65f6\u52a0\u4e0a\u6570\u5b57\u5e8f\u53f7\uff0c\u5e8f\u53f71\u4ee3\u8868\u539f\u59cb\u7684\u6587\u4ef6\u3002 $ cp --backup = numbered /etc/motd ~/test/issue2 $ cp --backup = numbered /etc/motd ~/test/issue2 $ cp --backup = numbered /etc/motd ~/test/issue2 $ ll ~/test -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :00 issue -rw-r--r--. 1 vagrant wheel 0 Nov 8 22 :57 issue1 -rw-r--r--. 1 vagrant wheel 23 Nov 8 22 :25 issue1~ -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :09 issue2 -rw-r--r--. 1 vagrant wheel 23 Jul 21 01 :10 issue2.~1~ -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :09 issue2.~2~ -rw-r--r--. 1 vagrant wheel 0 Nov 8 23 :09 issue2.~3~ -rw-r--r--. 1 root root 23 Nov 8 22 :43 issue3 -rw-r--r--. 1 root root 23 Jul 21 01 :10 issue4 drwxr-xr-x. 3 root root 4096 Nov 8 22 :49 sysconfig","title":"2.12.\u590d\u5236\u6587\u4ef6\u548c\u76ee\u5f55cp"},{"location":"linux/SRE/02-filesystem/#213mv","text":"mv \u547d\u4ee4\u3002Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY. \u5e38\u7528\u53c2\u6570\uff1a -v \uff1a\u663e\u793a\u547d\u4ee4\u6267\u884c\u7684\u4fe1\u606f\u3002 -i \uff1a\u4ea4\u4e92\u5f0f\uff0c\u6bd4\u5982\uff0c\u91cd\u540d\u8986\u76d6\u65f6\u4f1a\u63d0\u5347\u662f\u5426\u786e\u8ba4\u3002 -b \uff1a\u8986\u76d6\u65f6\u521b\u5efa\u5907\u4efd\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u79fb\u52a8\u6587\u4ef6\u5c06\u4f1a\u8986\u76d6\u5df2\u5b58\u5728\u7684\u76ee\u6807\u6587\u4ef6\u3002 \u79fb\u52a8\u591a\u4e2a\u6587\u4ef6\u5230\u67d0\u4e2a\u76ee\u5f55\u3002 mv file1 file2 file3 ~/dest mv file* ~/dest \u79fb\u52a8\u76ee\u5f55\u3002 mv ~/test ~/dest/new/one/ \u91cd\u547d\u540d\u6587\u4ef6\u548c\u76ee\u5f55\u3002 mv file1 file2 mv ~/test ~/dest","title":"2.13.\u79fb\u52a8\u6587\u4ef6\u548c\u76ee\u5f55mv"},{"location":"linux/SRE/02-filesystem/#214rename","text":"rename \u547d\u4ee4\u3002\u5206\u4e3aperl\u7248\u672c\u548cC\u8bed\u8a00\u7248\u672c\u3002 \u533a\u5206\u65b9\u6cd5: rename --version \u3002\u5982\u679c\u8fd4\u56de\u7ed3\u679c\u4e2d\u5305\u542b util-linux \uff0c\u8bf4\u660e\u662fC\u8bed\u8a00\u7248\u672c, \u53cd\u4e4b\u662fPerl\u7248\u672c\u3002 openSUSE\u548cRocy\u662fC\u8bed\u8a00\u7248\u672c\uff0cUbuntu\u662fPerl\u7248\u672c\u3002 \u4e3e\u4f8b\uff1a\u4fee\u6539\u5f53\u524d\u76ee\u5f55\u6240\u6709\u6269\u5c55\u540d\u4e3a s \u7684\u6587\u4ef6\u6539\u4e3a\u6269\u5c55\u540d\u4e3a gz \u3002 $ touch file { 1 ..3 } .s $ rename -v '.s' '.gz' *.s $ rename -v \".s\" \".gz\" *.s ` file1.txt ' -> `file1.html' ` file2.txt ' -> `file2.html' ` file3.txt ' -> `file3.html' \u5728Ubuntu\u4e0a\u5b8c\u6210\u540c\u6837\u4efb\u52a1\uff0c\u5219\u9700\u8981\u4f7f\u7528\u6b63\u5219\u3002 rename -v \"s/s/gz/g\" *.s","title":"2.14.\u91cd\u547d\u540d\u6587\u4ef6\u548c\u76ee\u5f55rename"},{"location":"linux/SRE/02-filesystem/#215rm","text":"rm \u547d\u4ee4\u3002\u5efa\u8bae\u4f7f\u7528 mv \u547d\u4ee4\u4ee3\u66ff rm \u547d\u4ee4\u3002","title":"2.15.\u5220\u9664\u6587\u4ef6rm"},{"location":"linux/SRE/02-filesystem/#216","text":"\u521b\u5efa\u76ee\u5f55\uff1a mkdir \u5220\u9664\u7a7a\u76ee\u5f55\uff1a rmdir \u5220\u9664\u975e\u7a7a\u76ee\u5f55\uff1a rm -r \u663e\u793a\u76ee\u5f55\u6811\uff1a tree","title":"2.16.\u76ee\u5f55\u64cd\u4f5c\u547d\u4ee4"},{"location":"linux/SRE/02-filesystem/#217","text":"\u663e\u793a /etc \u76ee\u5f55\u4e0b\u6240\u6709\u4ee5 l \u5f00\u5934\uff0c\u4ee5\u4e00\u4e2a\u5c0f\u5199\u5b57\u6bcd\u7ed3\u5c3e\uff0c\u4e14\u4e2d\u95f4\u51fa\u73b0\u81f3\u5c11\u4e00\u4f4d\u6570\u5b57\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls -d /etc/l* [ 0 -9 ] * [ a-z ] ls -d /etc/l* [[ :digit: ]] * [[ :lower: ]] \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/lam4you sudo mkdir /etc/lam5you \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/lam4you sudo rm -rf /etc/lam5you \u663e\u793a /etc \u76ee\u5f55\u4e0b\u4ee5\u4efb\u610f\u4e00\u4f4d\u6570\u5b57\u5f00\u5934\uff0c\u4e14\u4ee5\u975e\u6570\u5b57\u7ed3\u5c3e\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ 0 -9 ] * [ !0-9 ] ls /etc/ [[ :digit: ]] * [ ^ [ :digit: ]] \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/5am4yo. sudo mkdir /etc/5am5yo. \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/5am4yo. sudo rm -rf /etc/5am5yo. \u663e\u793a /etc \u76ee\u5f55\u4e0b\u4ee5\u975e\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u9762\u8ddf\u4e86\u4e00\u4e2a\u5b57\u6bcd\u53ca\u5176\u5b83\u4efb\u610f\u957f\u5ea6\u4efb\u610f\u5b57\u7b26\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ !a-zA-Z ][ a-zA-Z ] * ls /etc/ [ ^ [ :alpha: ]][[ :alpha: ]] * \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/5Ato3 sudo mkdir /etc/6dog6 \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/5Ato3 sudo rm -rf /etc/6dog6 \u663e\u793a /etc \u76ee\u5f55\u4e0b\uff0c\u6240\u6709\u4ee5 rc \u5f00\u5934\uff0c\u5e76\u540e\u9762\u662f0-6\u4e4b\u95f4\u7684\u6570\u5b57\uff0c\u5176\u5b83\u4e3a\u4efb\u610f\u5b57\u7b26\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/rc [ 0 -6 ] * \u5982\u679c\u65e0\u7b26\u5408\u6761\u4ef6\u7684\u8bb0\u5f55\u8fd4\u56de\uff0c\u53ef\u4ee5\u624b\u5de5\u521b\u5efa\u4e00\u4e2a\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u3002 sudo touch /etc/rc5come sudo mkdir /etc/rc0123 \u9a8c\u8bc1\u540e\u5220\u9664\u3002 sudo rm /etc/rc5come sudo rm -rf /etc/rc0123 \u663e\u793a /etc \u76ee\u5f55\u4e0b\uff0c\u6240\u6709\u4ee5 .conf \u7ed3\u5c3e\uff0c\u4e14\u4ee5 m \u3001 n \u3001 r \u3001 p \u5f00\u5934\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ mnrp ] *.conf \u53ea\u663e\u793a /root \u4e0b\u7684\u9690\u85cf\u6587\u4ef6\u548c\u76ee\u5f55\u5217\u8868\u3002 ls .* \u53ea\u663e\u793a/etc\u4e0b\u975e\u9690\u85cf\u76ee\u5f55\u5217\u8868\u3002 ls /etc/ [ ^. ] */ \u5c06 /etc \u76ee\u5f55\u4e0b\u6240\u6709\u6587\u4ef6\uff0c\u5907\u4efd\u5230 ~/test/ \u76ee\u5f55\u4e0b\uff0c\u5e76\u8981\u6c42\u5b50\u76ee\u5f55\u683c\u5f0f\u4e3a backupYYYY-mm-dd \uff0c\u5907\u4efd\u8fc7\u7a0b\u53ef\u89c1\u3002 sudo cp -av /etc/ ~/test/backup ` date +%F ` sudo cp -av /etc/ ~/test/backup ` date +%F_%H-%M-%S ` \u521b\u5efa\u76ee\u5f55 ~/testdir/dir1/x \uff0c ~/testdir/dir1/y \uff0c ~/testdir/dir1/x/a \uff0c ~/testdir/dir1/x/b \uff0c ~/testdir/dir1/y/a \uff0c ~/testdir/dir1/y/b \u3002 $ mkdir -p ~/testdir/dir1/ { x,y } / { a,b } $ tree ~/testdir/dir1/ /home/vagrant/testdir/dir1/ \u251c\u2500\u2500 x \u2502 \u251c\u2500\u2500 a \u2502 \u2514\u2500\u2500 b \u2514\u2500\u2500 y \u251c\u2500\u2500 a \u2514\u2500\u2500 b \u521b\u5efa\u76ee\u5f55 ~/testdir/dir2/x \uff0c ~/testdir/dir2/y \uff0c ~/testdir/dir2/x/a \uff0c ~/testdir/dir2/x/b \u3002 $ mkdir -p ~/testdir/dir2/ { x/ { a,b } ,y } $ tree ~/testdir/dir2/ /home/vagrant/testdir/dir2/ \u251c\u2500\u2500 x \u2502 \u251c\u2500\u2500 a \u2502 \u2514\u2500\u2500 b \u2514\u2500\u2500 y \u521b\u5efa\u76ee\u5f55 ~/testdir/dir3 \u3001 ~/testdir/dir4 \u3001 ~/testdir/dir5 \u3001 ~/testdir/dir5/dir6 \u3001 ~/testdir/dir5/dir7 \u3002 $ mkdir -p ~/testdir/dir { 3 ,4,5/dir { 6 ,7 }} $ tree ~/testdir /home/vagrant/testdir \u251c\u2500\u2500 dir1 \u2502 \u251c\u2500\u2500 x \u2502 \u2502 \u251c\u2500\u2500 a \u2502 \u2502 \u2514\u2500\u2500 b \u2502 \u2514\u2500\u2500 y \u2502 \u251c\u2500\u2500 a \u2502 \u2514\u2500\u2500 b \u251c\u2500\u2500 dir2 \u2502 \u251c\u2500\u2500 x \u2502 \u2502 \u251c\u2500\u2500 a \u2502 \u2502 \u2514\u2500\u2500 b \u2502 \u2514\u2500\u2500 y \u251c\u2500\u2500 dir3 \u251c\u2500\u2500 dir4 \u2514\u2500\u2500 dir5 \u251c\u2500\u2500 dir6 \u2514\u2500\u2500 dir7","title":"2.17.\u7ec3\u4e60"},{"location":"linux/SRE/02-filesystem/#3","text":"\u666e\u901a\u6587\u4ef6\uff08Normal Files\uff09 ASCII \u6587\u672c\u6587\u4ef6 \u53ef\u6267\u884c\u6587\u4ef6 \u56fe\u5f62\u6587\u4ef6 \u76ee\u5f55\uff08Directories\uff09 \u7ec4\u7ec7\u89c4\u5212\u78c1\u76d8\u4e0a\u7684\u6587\u4ef6 \u5305\u542b\u6587\u4ef6\u548c\u5b50\u76ee\u5f55 \u5b9e\u73b0\u5206\u5c42\u6587\u4ef6\u7cfb\u7edf \u94fe\u63a5\uff08Links\uff09 \u786c\u94fe\u63a5\uff08Hard links\uff09 \u78c1\u76d8\u4e0a\u6587\u4ef6\u7684\u8f85\u52a9\u6587\u4ef6\u540d \u591a\u4e2a\u6587\u4ef6\u540d\u5f15\u7528\u5355\u4e2a inode \u5f15\u7528\u7684\u6587\u4ef6\u5fc5\u987b\u5b58\u5728\u4e8e\u540c\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u4e2d \u7b26\u53f7\u94fe\u63a5\uff08Symbolic links\uff09 \u5bf9\u78c1\u76d8\u4e0a\u5176\u4ed6\u6587\u4ef6\u7684\u5f15\u7528 inode \u5305\u542b\u5bf9\u53e6\u4e00\u4e2a\u6587\u4ef6\u540d\u7684\u5f15\u7528 \u88ab\u5f15\u7528\u7684\u6587\u4ef6\u53ef\u4ee5\u5b58\u5728\u4e8e\u540c\u4e00\u4e2a\u6587\u4ef6\u7cfb\u7edf\u4e2d\uff0c\u4e5f\u53ef\u4ee5\u5b58\u5728\u4e8e\u5176\u4ed6\u6587\u4ef6\u7cfb\u7edf\u4e2d \u7b26\u53f7\u94fe\u63a5\u53ef\u4ee5\u5f15\u7528\u4e0d\u5b58\u5728\u7684\u6587\u4ef6\uff08\u65ad\u5f00\u7684\u94fe\u63a5\uff09 \u5957\u63a5\u5b57Sockets - \u7528\u4e8e\u8fdb\u7a0b\u4e4b\u95f4\u7684\u53cc\u5411\u901a\u4fe1\u3002 \u7ba1\u9053\uff08Pipes\uff09(FIFOs) - \u7528\u4e8e\u4ece\u4e00\u4e2a\u8fdb\u7a0b\u5230\u53e6\u4e00\u4e2a\u8fdb\u7a0b\u7684\u5355\u5411\u901a\u4fe1\u3002 \u5757\u8bbe\u5907\uff08Block Devices\uff09 \u5b57\u7b26\u8bbe\u5907\uff08Character Devices\uff09","title":"3.\u4e03\u79cd\u6587\u4ef6\u7c7b\u578b"},{"location":"linux/SRE/02-filesystem/#31inode","text":"\u6587\u4ef6\u50a8\u5b58\u5728\u786c\u76d8\u4e0a\uff0c\u786c\u76d8\u7684\u6700\u5c0f\u5b58\u50a8\u5355\u4f4d\u53eb\u505a\u201c\u6247\u533a\u201d\uff08Sector\uff09\u3002\u6bcf\u4e2a\u6247\u533a\u50a8\u5b58512\u5b57\u8282\uff08\u76f8\u5f53\u4e8e0.5KB\uff09\u3002 \u64cd\u4f5c\u7cfb\u7edf\u8bfb\u53d6\u786c\u76d8\u7684\u65f6\u5019\uff0c\u4e0d\u662f\u4e00\u4e2a\u4e00\u4e2a\u6247\u533a\u8bfb\u53d6\uff0c\u800c\u662f\u4e00\u6b21\u6027\u8fde\u7eed\u8bfb\u53d6\u591a\u4e2a\u6247\u533a\uff0c\u6211\u4eec\u79f0\u4e3a\u8bfb\u53d6\u4e00\u4e2a\u201c\u5757\u201d\uff08block\uff09\u3002 \u5e38\u89c1\u7684block\u7684\u5927\u5c0f\u662f4KB\uff08\u8fde\u7eed\u516b\u4e2asector\u7ec4\u6210\u4e00\u4e2ablock\uff09\u3002 \u591a\u4e2a\u6247\u533a\u7ec4\u6210\u7684block\u662f\u6587\u4ef6\u5b58\u53d6\u7684*\u6700\u5c0f\u5355\u4f4d*\u3002 \u6587\u4ef6\u6570\u636e\u50a8\u5b58\u5728block\u4e2d\uff0c\u6587\u4ef6\u7684\u5143\u4fe1\u606f\uff0c\u6bd4\u5982\u6587\u4ef6\u7684\u521b\u5efa\u8005\u3001\u521b\u5efa\u65e5\u671f\u3001\u6587\u5927\u5c0f\u7b49\uff0c\u5b58\u50a8\u5728inode\uff0c\u5373\u201c\u7d22\u5f15\u8282\u70b9\u201d\u3002 \u6bcf\u4e00\u4e2a\u6587\u4ef6\u90fd\u6709\u5bf9\u5e94\u7684inode\uff0c\u91cc\u9762\u5305\u542b\u4e86\u4e0e\u8be5\u6587\u4ef6\u6709\u5173\u7684\u4e00\u4e9b\u4fe1\u606f\u3002\u6ce8\u610f\uff0c\u9664\u4e86\u6587\u4ef6\u540d\u4ee5\u5916\u7684\u5176\u5b83\u6587\u4ef6\u4fe1\u606f\uff0c\u90fd\u5b58\u5728inode\u4e4b\u4e2d\u3002 inode\u5305\u542b\u6587\u4ef6\u7684\u5143\u4fe1\u606f\u4e3b\u8981\u6709\uff1a \u6587\u4ef6\u7684\u5b57\u8282\u6570 \u6587\u4ef6\u62e5\u6709\u8005\u7684 User ID \u6587\u4ef6\u7684 Group ID \u6587\u4ef6\u7684\u8bfb\u3001\u5199\u3001\u6267\u884c\u6743\u9650 \u6587\u4ef6\u7684\u65f6\u95f4\u6233\uff0c\u5171\u6709\u4e09\u4e2a\uff1actime\u6307inode\u4e0a\u4e00\u6b21\u53d8\u52a8\u7684\u65f6\u95f4\uff0cmtime\u6307\u6587\u4ef6\u5185\u5bb9\u4e0a\u4e00\u6b21\u53d8\u52a8\u7684\u65f6\u95f4\uff0catime\u6307\u6587\u4ef6\u4e0a\u4e00\u6b21\u6253\u5f00\u7684\u65f6\u95f4\u3002 \u94fe\u63a5\u6570\uff0c\u5373\u6709\u591a\u5c11\u6587\u4ef6\u540d\u6307\u5411\u8fd9\u4e2ainode \u6587\u4ef6\u6570\u636eblock\u7684\u4f4d\u7f6e \u67e5\u770binode\u4fe1\u606f\u7684\u547d\u4ee4 stat \uff1a $ stat file1 File: file1 Size: 5 Blocks: 8 IO Block: 4096 regular file Device: fd02h/64770d Inode: 143 Links: 1 Access: ( 0644 /-rw-r--r-- ) Uid: ( 1000 / vagrant ) Gid: ( 10 / wheel ) Context: unconfined_u:object_r:user_home_t:s0 Access: 2022 -11-08 20 :49:26.019678244 +0800 Modify: 2022 -11-08 20 :49:26.019678244 +0800 Change: 2022 -11-08 20 :49:26.028678455 +0800 Birth: 2022 -11-08 20 :49:26.019678244 +0800 \u683c\u5f0f\u5316\u786c\u76d8\u65f6\uff0c\u64cd\u4f5c\u7cfb\u7edf\u4f1a\u81ea\u52a8\u5c06\u786c\u76d8\u5206\u6210\u4e24\u4e2a\u533a\u57df\u3002\u4e00\u4e2a\u662f\u6570\u636e\u533a\uff0c\u5b58\u653e\u6587\u4ef6\u6570\u636e\u3002\u53e6\u4e00\u4e2a\u662finode\u533a\uff08inode table\uff09\uff0c\u5b58\u653einode\u6240\u5305\u542b\u7684\u6587\u4ef6\u7684\u5143\u4fe1\u606f\u3002 \u6bcf\u4e2ainode\u8282\u70b9\u7684\u5927\u5c0f\uff0c\u4e00\u822c\u662f128\u5b57\u8282\u6216256\u5b57\u8282\u3002inode\u8282\u70b9\u7684\u603b\u6570\uff0c\u5728\u683c\u5f0f\u5316\u65f6\u5c31\u786e\u5b9a\u4e86\uff0c\u4e00\u822c\u662f\u6bcf1KB\u6216\u6bcf2KB\u5c31\u8bbe\u7f6e\u4e00\u4e2ainode\u3002 \u5047\u5b9a\u4e00\u57571GB\u7684\u786c\u76d8\uff0c\u5982\u679c\u6bcf\u4e2ainode\u8282\u70b9\u7684\u5927\u5c0f\u4e3a128\u5b57\u8282\uff0c\u4e14\u6bcf1KB\u5c31\u8bbe\u7f6e\u4e00\u4e2ainode\uff0c\u5219inode table\u7684\u5927\u5c0f\u5c31\u4f1a\u8fbe\u5230128MB\uff0c\u5360\u6574\u5757\u786c\u76d8\u768412.8%\u3002 \u901a\u8fc7 df \u547d\u4ee4\u67e5\u770b\u6bcf\u4e2a\u786c\u76d8\u5206\u533a\u7684inode\u603b\u6570\u548c\u5df2\u7ecf\u4f7f\u7528\u7684\u6570\u91cf\u3002 \u7531\u4e8e\u6bcf\u4e2a\u6587\u4ef6\u90fd\u5fc5\u987b\u6709\u4e00\u4e2ainode\uff0c\u56e0\u6b64\u6709\u53ef\u80fd\u53d1\u751finode\u5df2\u7ecf\u7528\u5149\uff0c\u4f46\u662f\u786c\u76d8\u8fd8\u672a\u5b58\u6ee1\u7684\u60c5\u51b5\uff0c\u4e5f\u5c31\u65e0\u6cd5\u5728\u786c\u76d8\u4e0a\u521b\u5efa\u65b0\u6587\u4ef6\u3002 $ df -i Filesystem Inodes IUsed IFree IUse% Mounted on tmpfs 497897 872 497025 1 % /run /dev/mapper/ubuntu--vg-ubuntu--lv 3211264 81473 3129791 3 % / tmpfs 497897 1 497896 1 % /dev/shm tmpfs 497897 3 497894 1 % /run/lock /dev/sda2 131072 316 130756 1 % /boot tmpfs 99579 25 99554 1 % /run/user/1000 \u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u67e5\u770b\u6bcf\u4e2ainode\u8282\u70b9\u7684\u5927\u5c0f\uff1a $ sudo dumpe2fs -h /dev/sda2 | grep \"Inode size\" dumpe2fs 1 .46.5 ( 30 -Dec-2021 ) Inode size: 256 \u6bcf\u4e2ainode\u90fd\u6709\u4e00\u4e2a\u53f7\u7801\uff0c\u64cd\u4f5c\u7cfb\u7edf\u7528inode\u53f7\u7801\u6765\u8bc6\u522b\u4e0d\u540c\u7684\u6587\u4ef6\uff0c\u6ce8\u610f\uff0c\u4e0d\u662f\u901a\u8fc7\u6587\u4ef6\u540d\u6765\u8bc6\u522b\u4e0d\u540c\u6587\u4ef6\u3002\u4ece\u64cd\u4f5c\u7cfb\u7edf\u89d2\u5ea6\u770b\uff0c\u6587\u4ef6\u540d\u53ea\u662finode\u53f7\u7801\u5bf9\u4e00\u4e2a\u522b\u540d\u3002 \u7528\u6237\u901a\u8fc7\u6587\u4ef6\u540d\uff0c\u6253\u5f00\u67d0\u4e2a\u6587\u4ef6\u7684\u8fc7\u7a0b\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5206\u6210\u4e09\u6b65\u5b8c\u6210\uff1a \u9996\u5148\uff0c\u7cfb\u7edf\u627e\u5230\u8fd9\u4e2a\u6587\u4ef6\u540d\u5bf9\u5e94\u7684inode\u53f7\u7801\u3002 \u5176\u6b21\uff0c\u901a\u8fc7inode\u53f7\uff0c\u83b7\u53d6inode\u4fe1\u606f\u3002 \u7b2c\u4e09\uff0c\u901a\u8fc7inode\u4fe1\u606f\uff0c\u627e\u5230\u6587\u4ef6\u6570\u636e\u6240\u5728\u7684block\uff0c\u8bfb\u51fa\u6570\u636e\u3002 \u901a\u8fc7 ls -i \u547d\u4ee4\uff0c\u53ef\u4ee5\u5f97\u5230\u6587\u4ef6\u5bf9\u5e94\u7684inode\u53f7\uff1a $ ls -i file1 143 file1 \u76ee\u5f55\uff08directory\uff09\u4e5f\u662f\u4e00\u79cd\u6587\u4ef6\u3002\u6253\u5f00\u76ee\u5f55\uff0c\u5b9e\u9645\u4e0a\u5c31\u662f\u6253\u5f00\u76ee\u5f55\u6587\u4ef6\u3002 \u76ee\u5f55\u6587\u4ef6\u7684\u7ed3\u6784\u662f\u7531\u4e00\u4e2a\u5305\u542b\u4e00\u7cfb\u5217\u76ee\u5f55\u9879\uff08dirent\uff09\u7684\u5217\u8868\u7ec4\u6210\u3002 \u6bcf\u4e2a\u76ee\u5f55\u9879\u7531\u4e24\u90e8\u5206\u7ec4\u6210\uff1a\u6240\u5305\u542b\u6587\u4ef6\u7684\u6587\u4ef6\u540d\uff0c\u4ee5\u53ca\u8be5\u6587\u4ef6\u540d\u5bf9\u5e94\u7684inode\u53f7\u3002 \u547d\u4ee4 ls -i \u5217\u51fa\u6574\u4e2a\u76ee\u5f55\u6587\u4ef6\uff0c\u5373\u6587\u4ef6\u540d\u548cinode\u53f7\uff1a $ ls -i 143 file1 140 file2 139 test $ ls -il 143 -rw-r--r--. 1 vagrant wheel 5 Nov 8 20 :49 file1 140 -rw-r--r--. 1 vagrant wheel 0 Oct 1 21 :35 file2 139 drwxr-xr-x. 5 vagrant wheel 4096 Nov 9 22 :00 test","title":"3.1.inode\u7ed3\u6784"},{"location":"linux/SRE/02-filesystem/#32","text":"\u786c\u94fe\u63a5 \uff08Hard links\uff09\u786c\u94fe\u63a5\u662f\u5b58\u50a8\u5377\u4e0a\u6587\u4ef6\u7684\u76ee\u5f55\u5f15\u7528\u6216\u6307\u9488\u3002 \u6587\u4ef6\u540d\u662f\u5b58\u50a8\u5728\u76ee\u5f55\u7ed3\u6784\u4e2d\u7684\u6807\u7b7e\uff0c\u76ee\u5f55\u7ed3\u6784\u6307\u5411\u6587\u4ef6\u6570\u636e\u3002 \u56e0\u6b64\uff0c\u53ef\u4ee5\u5c06\u591a\u4e2a\u6587\u4ef6\u540d\u4e0e\u540c\u4e00\u6587\u4ef6\u5173\u8054\u3002 \u901a\u8fc7\u4e0d\u540c\u7684\u6587\u4ef6\u540d\u8bbf\u95ee\u65f6\uff0c\u6240\u505a\u7684\u4efb\u4f55\u66f4\u6539\u90fd\u662f\u9488\u5bf9\u6e90\u6587\u4ef6\u6570\u636e\u3002 \u7b26\u53f7\u94fe\u63a5 \uff08Symbolic links\uff09: \u7b26\u53f7\u94fe\u63a5\u5305\u542b\u4e00\u4e2a\u6587\u672c\u5b57\u7b26\u4e32\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5c06\u5176\u89e3\u91ca\u4e3a\u53e6\u4e00\u4e2a\u6587\u4ef6\u6216\u76ee\u5f55\u3002 \u5b83\u672c\u8eab\u5c31\u662f\u4e00\u4e2a\u6587\u4ef6\uff0c\u53ef\u4ee5\u72ec\u7acb\u4e8e\u76ee\u6807\u800c\u5b58\u5728\u3002 \u5982\u679c\u5220\u9664\u4e86\u7b26\u53f7\u94fe\u63a5\uff0c\u5219\u5176\u76ee\u6807\u6587\u4ef6\u6216\u76ee\u5f55\u4e0d\u53d7\u5f71\u54cd\u3002 \u5982\u679c\u79fb\u52a8\uff0c\u91cd\u547d\u540d\u6216\u5220\u9664\u76ee\u6807\u6587\u4ef6\u6216\u76ee\u5f55\uff0c\u5219\u7528\u4e8e\u6307\u5411\u5b83\u7684\u4efb\u4f55\u7b26\u53f7\u94fe\u63a5\u5c06\u7ee7\u7eed\u5b58\u5728\uff0c\u4f46\u6307\u5411\u7684\u662f\u4e00\u4e2a\u4e0d\u5b58\u5728\u7684\u6587\u4ef6\u3002 \u4ec5\u5f53\u6587\u4ef6\u548c\u94fe\u63a5\u6587\u4ef6\u4f4d\u4e8e\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\uff08\u5728\u540c\u4e00\u5206\u533a\u4e0a\uff09\u65f6\uff0c\u624d\u80fd\u4f7f\u7528\u786c\u94fe\u63a5\uff0c\u56e0\u4e3ainode\u7f16\u53f7\u5728\u540c\u4e00\u6587\u4ef6\u7cfb\u7edf\u4e2d\u4ec5\u662f\u552f\u4e00\u7684\u3002 \u53ef\u4ee5\u4f7f\u7528 ln \u547d\u4ee4\u521b\u5efa\u786c\u94fe\u63a5\uff0c\u6307\u5411\u5df2\u5b58\u5728\u6587\u4ef6\u7684inode\uff0c\u53ef\u4ee5\u901a\u8fc7\u6587\u4ef6\u540d\u6216\u8005\u786c\u94fe\u63a5\u540d\u8bbf\u95ee\u6587\u4ef6\u3002 \u53ef\u4ee5\u4f7f\u7528 ln -s \u9009\u9879\u521b\u5efa\u7b26\u53f7\u94fe\u63a5\u3002 \u4e00\u4e2a\u7b26\u53f7\u94fe\u63a5\u4f1a\u88ab\u5206\u914d\u4e00\u4e2a\u5355\u72ec\u7684inode\uff0c\u5e76\u6307\u5411\u4e00\u4e2a\u6587\u4ef6\uff0c\u6240\u4ee5\u53ef\u4ee5\u660e\u663e\u533a\u5206\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\u548c\u5b9e\u9645\u6587\u4ef6\u3002 \u6587\u4ef6\u7cfb\u7edf\u672c\u8d28\u4e0a\u662f\u4e00\u4e2a\u7528\u4e8e\u8ddf\u8e2a\u5206\u533a\u5377\u4e2d\u7684\u6587\u4ef6\u7684\u6570\u636e\u5e93\u3002 \u5bf9\u4e8e\u666e\u901a\u6587\u4ef6\uff0c\u5206\u914d\u6570\u636e\u5757\u4ee5\u5b58\u50a8\u6587\u4ef6\u7684\u6570\u636e\uff0c\u5206\u914dinode\u4ee5\u6307\u5411\u6570\u636e\u5757\u4ee5\u53ca\u5b58\u50a8\u5173\u4e8e\u6587\u4ef6\u7684\u5143\u6570\u636e\uff0c\u7136\u540e\u5c06\u6587\u4ef6\u540d\u5206\u914d\u7ed9inode\u3002 \u786c\u94fe\u63a5\u662f\u4e0e\u73b0\u6709inode\u5173\u8054\u7684\u8f85\u52a9\u6587\u4ef6\u540d\u3002 \u5bf9\u4e8e\u7b26\u53f7\u94fe\u63a5\uff0c\u5c06\u4e3a\u65b0\u7684inode\u5206\u914d\u4e00\u4e2a\u4e0e\u4e4b\u5173\u8054\u7684\u65b0\u6587\u4ef6\u540d\uff0c\u4f46inode\u5f15\u7528\u53e6\u4e00\u4e2a\u6587\u4ef6\u540d\u800c\u4e0d\u662f\u5f15\u7528\u6570\u636e\u5757\u3002 \u67e5\u770b\u6587\u4ef6\u540d\u548cinode\u4e4b\u95f4\u5173\u7cfb\u7684\u4e00\u4e2a\u65b9\u6cd5\u662f\u4f7f\u7528 ls -il \u547d\u4ee4\u3002inode\u7684\u5178\u578b\u5927\u5c0f\u4e3a128\u4f4d\uff0c\u6570\u636e\u5757\u7684\u5927\u5c0f\u8303\u56f4\u53ef\u4ee5\u662f1k\uff0c2k\uff0c4k\u6216\u66f4\u5927\uff0c\u5177\u4f53\u53d6\u51b3\u4e8e\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u3002 \u8f6f\u8fde\u63a5\u53ef\u4ee5\u9488\u5bf9\u76ee\u5f55\uff0c\u786c\u8fde\u63a5\u53ea\u80fd\u9488\u5bf9\u6587\u4ef6\u3002 \u786c\u94fe\u63a5\u76f8\u5f53\u4e8e\u589e\u52a0\u4e86\u4e00\u4e2a\u767b\u8bb0\u9879\uff0c\u4f7f\u5f97\u539f\u6765\u7684\u6587\u4ef6\u591a\u4e86\u4e00\u4e2a\u540d\u5b57\uff0c\u81f3\u4e8einode\u90fd\u6ca1\u53d8\u3002\u6240\u8c13\u7684\u767b\u8bb0\u9879\u5176\u5b9e\u662f\u76ee\u5f55\u6587\u4ef6\u4e2d\u7684\u4e00\u4e2a\u6761\u76ee(\u76ee\u5f55\u9879)\uff0c\u4f7f\u7528hard link \u662f\u8ba9\u591a\u4e2a\u4e0d\u540c\u7684\u76ee\u5f55\u9879\u6307\u5411\u540c\u4e00\u4e2a\u6587\u4ef6\u7684inode\uff0c\u6ca1\u6709\u591a\u4f59\u7684\u5185\u5bb9\u9700\u8981\u5b58\u50a8\u5728\u78c1\u76d8\u6247\u533a\u4e2d\uff0c\u6240\u4ee5hardlink\u4e0d\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 \u7b26\u53f7\u94fe\u63a5\u6709\u5355\u72ec\u7684inode\uff0c\u5728inode\u4e2d\u5b58\u653e\u53e6\u4e00\u4e2a\u6587\u4ef6\u7684\u8def\u5f84\u800c\u4e0d\u662f\u6587\u4ef6\u6570\u636e\uff0c\u6240\u4ee5\u7b26\u53f7\u94fe\u63a5\u4f1a\u5360\u7528\u989d\u5916\u7684\u7a7a\u95f4\u3002 \u7279\u5f81 \u786c\u94fe\u63a5 \u7b26\u53f7\u94fe\u63a5 \u672c\u8d28 \u540c\u4e00\u4e2a\u6587\u4ef6 \u4e0d\u662f\u540c\u4e00\u4e2a\u6587\u4ef6 \u8de8\u8bbe\u5907 \u4e0d\u652f\u6301 \u652f\u6301 inode \u76f8\u540c \u4e0d\u540c \u94fe\u63a5\u6570 \u521b\u5efa\u786c\u94fe\u63a5\uff0c\u94fe\u63a5\u6570\u4f1a\u589e\u52a0\uff0c\u5220\u9664\u5219\u51cf\u5c11 \u521b\u5efa\u6216\u5220\u9664\uff0c\u94fe\u63a5\u6570\u90fd\u4e0d\u53d8 \u6587\u4ef6\u5939 \u4e0d\u652f\u6301 \u652f\u6301 \u76f8\u5bf9\u8def\u5f84 \u539f\u59cb\u6587\u4ef6\u7684\u76f8\u5bf9\u8def\u5f84\u662f\u76f8\u5bf9\u4e8e\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55 \u539f\u59cb\u6587\u4ef6\u7684\u76f8\u5bf9\u8def\u5f84\u662f\u76f8\u5bf9\u4e8e\u94fe\u63a5\u6587\u4ef6\u7684\u76f8\u5bf9\u8def\u5f84 \u5220\u9664\u6e90\u6587\u4ef6 \u53ea\u662f\u94fe\u63a5\u6570\u51cf\u5c11\uff0c\u94fe\u63a5\u6587\u4ef6\u8bbf\u95ee\u4e0d\u53d7\u5f71\u54cd \u94fe\u63a5\u6587\u4ef6\u5c06\u65e0\u6cd5\u8bbf\u95ee \u6587\u4ef6\u7c7b\u578b \u548c\u6e90\u6587\u4ef6\u76f8\u540c \u94fe\u63a5\u6587\u4ef6\uff0c\u548c\u6e90\u6587\u4ef6\u65e0\u5173 \u6587\u4ef6\u5927\u5c0f \u548c\u6e90\u6587\u4ef6\u76f8\u540c \u6e90\u6587\u4ef6\u7684\u8def\u5f84\u7684\u957f\u5ea6","title":"3.2.\u94fe\u63a5\u7c7b\u578b"},{"location":"linux/SRE/02-filesystem/#33","text":"\u8bbe\u5907\u6587\u4ef6 \uff08Device File\uff09\u8868\u793a\u786c\u4ef6\uff08\u7f51\u5361\u9664\u5916\uff09\u3002 \u6bcf\u4e2a\u786c\u4ef6\u90fd\u7531\u4e00\u4e2a\u8bbe\u5907\u6587\u4ef6\u8868\u793a\u3002 \u7f51\u5361\u662f\u63a5\u53e3\u3002 \u8bbe\u5907\u6587\u4ef6\u628a\u5185\u6838\u9a71\u52a8\u548c\u7269\u7406\u786c\u4ef6\u8bbe\u5907\u8fde\u63a5\u8d77\u6765\u3002 \u5185\u6838\u9a71\u52a8\u7a0b\u5e8f\u901a\u8fc7\u5bf9\u8bbe\u5907\u6587\u4ef6\u8fdb\u884c\u8bfb\u5199\uff08\u6b63\u786e\u7684\u683c\u5f0f\uff09\u6765\u5b9e\u73b0\u5bf9\u786c\u4ef6\u7684\u8bfb\u5199\u3002 \u7c7b\u578b\uff1a \u5757\u8bbe\u5907\uff08Block Devices\uff09\uff1a\u5757\u8bbe\u5907\uff08\u901a\u5e38\uff09\u5728512\u5b57\u8282\u7684\u5927\u5757\u4e2d\u8bfb\u53d6/\u5199\u5165\u4fe1\u606f\u3002 \u5b57\u7b26\u8bbe\u5907\uff08Character Devices\uff09\uff1a\u5b57\u7b26\u8bbe\u5907\u4ee5\u5b57\u7b26\u65b9\u5f0f\u8bfb\u53d6/\u5199\u5165\u4fe1\u606f\u3002 \u5b57\u7b26\u8bbe\u5907\u76f4\u63a5\u63d0\u4f9b\u5bf9\u786c\u4ef6\u8bbe\u5907\u7684\u65e0\u7f13\u51b2\u8bbf\u95ee\u3002 \u6709\u65f6\u79f0\u4e3a\u88f8\u8bbe\u5907\uff08raw devices\uff09\u3002\uff08\u6ce8\u610f\uff1a\u88f8\u8bbe\u5907\u88ab\u89c6\u4e3a\u5b57\u7b26\u8bbe\u5907\uff0c\u4e0d\u662f\u5757\u8bbe\u5907\uff09 \u901a\u8fc7\u8f85\u4ee5\u4e0d\u540c\u9009\u9879\uff0c\u53ef\u4ee5\u5e7f\u6cdb\u800c\u591a\u6837\u5730\u5e94\u7528\u548c\u4f7f\u7528\u5b57\u7b26\u8bbe\u5907\u3002 \u5f53\u5185\u6838\u53d1\u73b0\u8bbe\u5907\u65f6\u7531\u64cd\u4f5c\u7cfb\u7edf udev \u81ea\u52a8\u521b\u5efa\u3002","title":"3.3.\u8bbe\u5907\u6587\u4ef6"},{"location":"linux/SRE/02-filesystem/#34","text":"\u76ee\u6807\uff1a\u4ee5Rocky 9\u4e3a\u4f8b\u3002 \u67e5\u770b\u8f6f/\u786c\u94fe\u63a5\u6587\u4ef6\u7684\u7279\u5f81\u3002 \u67e5\u770b\u76ee\u5f55\u7ed3\u6784\u3002 \u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u5f97\u5230\u5f53\u524d\u7cfb\u7edf\u76842\u7ea7\u76ee\u5f55\u7684\u7ed3\u6784\u3002 tree -L 2 -d / \u521b\u5efa\u7ec3\u4e60\u76ee\u5f55\u3002 mkdir data mkdir -p data/typelink cd data \u521b\u5efa\u786c\u94fe\u63a5\u3002\u6ce8\u610f\uff1a file \u3001 hardlinkfile1 \u3001 hardlinkfile2 \u6587\u4ef6\u7684\u94fe\u63a5\u4f4d\u7f6e\u7684\u6570\u503c\u7684\u53d8\u5316) echo \"it's original file\" > file ln file hardlinkfile1 ln -s file symlinkfile1 ln -s file symlinkfile2 \u6267\u884c ls -l \u547d\u4ee4\u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u7ed3\u679c\uff1a -rw-r--r--. 2 vagrant wheel 19 Nov 1 10 :42 file -rw-r--r--. 2 vagrant wheel 19 Nov 1 10 :42 hardlinkfile1 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file \u521b\u5efa\u53e6\u5916\u4e00\u4e2a\u786c\u94fe\u63a5\u3002 ln file hardlinkfile2 \u6267\u884c ls -l \u547d\u4ee4\u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u7ed3\u679c\uff1a -rw-r--r--. 3 vagrant wheel 19 Nov 1 10 :42 file -rw-r--r--. 3 vagrant wheel 19 Nov 1 10 :42 hardlinkfile1 -rw-r--r--. 3 vagrant wheel 19 Nov 1 10 :42 hardlinkfile2 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file \u4fee\u6539 file \u6587\u4ef6\u7684\u5185\u5bb9\u3002 echo \"add oneline\" >> file \u901a\u8fc7\u547d\u4ee4 cat file \u67e5\u770b\u5f53\u524d file \u7684\u5185\u5bb9\u3002 it ' s original file add oneline \u901a\u8fc7\u4e0b\u9762\u7684\u547d\u4ee4\uff0c\u53ef\u4ee5\u770b\u5230\u6240\u4ee5\u8f6f/\u786c\u94fe\u63a5\u6587\u4ef6\u5185\u5bb9\u90fd\u66f4\u65b0\u4e86\uff0c\u548c file \u6587\u4ef6\u66f4\u65b0\u540e\u7684\u5185\u5bb9\u4fdd\u6301\u4e00\u81f4\u3002 cat hardlinkfile1 cat hardlinkfile2 cat symlinkfile1 cat symlinkfile2 \u5bf9\u6587\u4ef6 symlinkfile1 \u518d\u521b\u5efa\u65b0\u7684\u8f6f\u8fde\u63a5\u3002 ln -s symlinkfile1 symlinkfile1-1 \u901a\u8fc7\u547d\u4ee4 ls -il \u67e5\u770b\u73b0\u5728\u7684\u76ee\u5f55\u4fe1\u606f\u3002 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 file 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile1 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile2 67274681 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file 67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov 1 11 :20 symlinkfile1-1 -> symlinkfile1 67274682 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file \u8bfb\u53d6\u8f6f\u94fe\u63a5\u6587\u4ef6\u7684\u6e90\u6587\u4ef6\u4fe1\u606f readlink symlinkfile1 readlink symlinkfile2 \u6ce8\u610f\uff0c\u5bf9\u4e8e symlinkfile1-1 \u7684\u60c5\u51b5\u6709\u4e9b\u4e0d\u540c\u3002 readlink symlinkfile1-1 \u4e0a\u9762\u547d\u4ee4\u8fd4\u56de\u7ed3\u679c symlinkfile1 \u4ecd\u7136\u662f\u4e00\u4e2a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\u3002\u901a\u8fc7 readlink -f \u53ef\u4ee5\u76f4\u63a5\u5b9a\u4f4d\u771f\u6b63\u7684\u6e90\u6587\u4ef6\u3002 readlink -f symlinkfile1-1 \u4e0a\u9762\u7684\u8fd4\u56de\u7ed3\u679c /data/linktype/file \u662f symlinkfile1-1 \u771f\u6b63\u7684\u6e90\u6587\u4ef6\u3002 \u663e\u793a data \u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\uff1a cd ~ tree ./data \u8fd0\u884c\u7ed3\u679c\uff1a ./data \u251c\u2500\u2500 file \u251c\u2500\u2500 hardlinkfile1 \u251c\u2500\u2500 hardlinkfile2 \u251c\u2500\u2500 symlinkfile1 -> file \u251c\u2500\u2500 symlinkfile1-1 -> symlinkfile1 \u251c\u2500\u2500 symlinkfile2 -> file \u2514\u2500\u2500 typelink \u53ea\u663e\u793a data \u76ee\u5f55\u4e0b\u7684\u5b50\u76ee\u5f55\uff1a tree -d ./data \u8fd0\u884c\u7ed3\u679c\uff1a ./data \u2514\u2500\u2500 typelink \u663e\u793a data \u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\uff0c\u5305\u542b\u5168\u76ee\u5f55\uff1a tree -f ./data \u8fd0\u884c\u7ed3\u679c\uff1a ./data \u251c\u2500\u2500 ./data/file \u251c\u2500\u2500 ./data/hardlinkfile1 \u251c\u2500\u2500 ./data/hardlinkfile2 \u251c\u2500\u2500 ./data/symlinkfile1 -> file \u251c\u2500\u2500 ./data/symlinkfile1-1 -> symlinkfile1 \u251c\u2500\u2500 ./data/symlinkfile2 -> file \u2514\u2500\u2500 ./data/typelink","title":"3.4.\u7ec3\u4e60"},{"location":"linux/SRE/02-filesystem/#4","text":"\u6267\u884c\u547d\u4ee4 ls -ihl \uff0c\u53ef\u4ee5\u5f97\u5230\u4e0b\u9762\u7684\u8f93\u51fa\u7ed3\u679c\uff08Rocky 9\uff09\u3002 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 file 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile1 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11 :14 hardlinkfile2 67274681 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile1 -> file 67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov 1 11 :20 symlinkfile1-1 -> symlinkfile1 67274682 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file 33555262 drwxr-xr-x. 2 vagrant wheel 6 Nov 1 11 :30 typelink \u4ee5 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11:14 file \u4e3a\u4f8b\uff1a 67274680 : inode \u7d22\u5f15\u8282\u70b9\u7f16\u53f7\u3002 -rw-r--r-- \uff1a\u6587\u4ef6\u7c7b\u578b\u53ca\u6743\u9650 - \uff1a\u6587\u4ef6\u7c7b\u578b\uff0c\u4f8b\u5b50\u4e2d\u51fa\u73b0\u4e86\u4e09\u79cd\uff0c - \uff0c l \u548c d \u3002 - \uff1a\u666e\u901a\u6587\u4ef6 d \uff1a\u76ee\u5f55 l \uff1a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\uff08link\uff09 b \uff1a\u5757\u8bbe\u5907\uff08block\uff09 c \uff1a\u5b57\u7b26\u8bbe\u5907\uff08character\uff09 p \uff1a\u7ba1\u9053\u6587\u4ef6\uff08pipe\uff09 s \uff1a\u5957\u63a5\u5b57\u6587\u4ef6\uff08socket\uff09 rw-r--r-- \uff1a\u6587\u4ef6\u6743\u9650\uff0c\u4ece\u5de6\u5230\u53f3\u4f9d\u6b21\u4e3a\uff1a rw- \uff1a\u6587\u4ef6\u5c5e\u4e3b\u6743\u9650\uff0c\u4f8b\u5b50\u4e2d\u662f vagrant \u3002 r-- \uff1a\u6587\u4ef6\u5c5e\u7ec4\u7684\u6743\u9650\uff0c\u4f8b\u5b50\u4e2d\u662f wheel \u3002 r-- \uff1a\u5176\u4ed6\u7ec4\u7684\u6743\u9650\u3002 . \uff1a\u8fd9\u4e2a\u70b9\u8868\u793a\u6587\u4ef6\u5e26\u6709SELinux\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\uff08SELinux Contexts\uff09\u3002\u5173\u95edSELinux\uff0c\u65b0\u521b\u5efa\u7684\u6587\u4ef6\u5c31\u4e0d\u4f1a\u518d\u6709\u8fd9\u4e2a\u70b9\u4e86\u3002\u4f46\u662f\uff0c\u4ee5\u524d\u521b\u5efa\u7684\u6587\u4ef6\u672c\u6765\u6709\u8fd9\u4e2a\u70b9\u7684\u8fd8\u4f1a\u663e\u793a\u8fd9\u4e2a\u70b9\uff08\u867d\u7136SELinux\u4e0d\u8d77\u4f5c\u7528\u4e86\uff09\u3002 3 \uff1a\u786c\u94fe\u63a5\u6570\uff0c\u4f8b\u5b50\u4e2d file \u548c hardlinkfile1 \u548c hardlinkfile2 \u4e4b\u95f4\u662f\u786c\u94fe\u63a5\uff0c\u6240\u4ee5\u8fd9\u4e09\u4e2a\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u90fd\u662f 3 \u3002 vagrant \uff1a\u6587\u4ef6\u5c5e\u4e3b wheel \uff1a\u6587\u4ef6\u5c5e\u7ec4 31 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u5927\u5c0f Nov 1 11:14 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u521b\u5efa\u65e5\u671f\u548c\u65f6\u95f4 file \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u540d\u79f0 \u4e0b\u9762\u662f\u547d\u4ee4 ls -ihl \u5728openSUSE\u548cUbuntu\u4e0a\u7684\u663e\u793a\u7ed3\u679c\u3002 $ ls -ihl 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 file 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile1 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile2 233648 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile1 -> file 233650 lrwxrwxrwx 1 vagrant wheel 12 Nov 1 15 :52 symlinkfile1-1 -> symlinkfile1 233649 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile2 -> file 233646 drwxr-xr-x 1 vagrant wheel 0 Nov 1 15 :51 typelink","title":"4.\u6587\u4ef6\u5c5e\u6027\u8bf4\u660e"},{"location":"linux/SRE/02-filesystem/#5","text":"\u6807\u51c6\u8f93\u5165\u8f93\u51fa\uff0c\u5373I/O\uff0cI/O\u7684I\u662fInput\uff0cO\u662foutput\u3002 I\uff1a\u4ece\u5916\u90e8\u8bbe\u5907\u8f93\u5165\u5230\u5185\u5b58 O\uff1a\u4ece\u5185\u5b58\u8f93\u51fa\u5230\u5916\u90e8\u8bbe\u5907 \u6807\u51c6\u8f93\u5165\u548c\u6807\u51c6\u8f93\u51fa\u662f\u7528\u4e8eIO\u7684\uff0c\u5b83\u4eec\u5c5e\u4e8e\u5916\u90e8\u8bbe\u5907\uff08\u903b\u8f91\u4e0a\u7684\u5916\u90e8\u8bbe\u5907\uff09\uff0c\u4e0d\u662f\u5185\u5b58\u3002 linux\u4e2d\u4e00\u5207\u8bbe\u5907\u7686\u662f\u6587\u4ef6\uff01\u56e0\u6b64\u6807\u51c6\u8f93\u5165\u548c\u8f93\u51fa\u672c\u8d28\u5c31\u662f\u6587\u4ef6\uff0c\u5916\u90e8\u8bbe\u5907\u4ee5\u6587\u4ef6\u5f62\u5f0f\u8868\u73b0\u3002 \u5728Linux\u7cfb\u7edf\u4e2d\uff0c\u6807\u51c6\u8f93\u5165\u548c\u6807\u51c6\u8f93\u51fa\u5bf9\u5e94\u7684\u6587\u4ef6\u662f /dev/stdin \u548c /dev/stdout \u8fd9\u4e24\u4e2a\u6587\u4ef6\u3002 \u4ece\u6807\u51c6\u8f93\u5165\u8bfb\uff0c\u4ece\u903b\u8f91\u4e0a\u8bb2\uff0c\u5c31\u662f\u6253\u5f00 /dev/stdin \u8fd9\u4e2a\u6587\u4ef6\uff0c\u5e76\u8bfb\u5165\u6587\u4ef6\u5185\u5bb9\u3002 \u8f93\u51fa\u5230\u6807\u51c6\u8f93\u51fa\uff0c\u4ece\u903b\u8f91\u4e0a\u8bb2\uff0c\u5c31\u662f\u6253\u5f00 /dev/stdout \u8fd9\u4e2a\u6587\u4ef6\uff0c\u5e76\u628a\u5185\u5bb9\u8f93\u51fa\u5230\u8fd9\u4e2a\u6587\u4ef6\u91cc\u53bb\u3002 \u8fd9\u91cc\u5f3a\u8c03\u7684\u662f\u201c\u903b\u8f91\u4e0a\u201d\uff0c\u56e0\u4e3a /dev/stdin \u548c /dev/stdout \u8fd92\u4e2a\u6587\u4ef6\u672c\u8eab\u4e0d\u662f\u8bbe\u5907\u6587\u4ef6\u3002Linux\u4e2d\u8bbe\u5907\u662f\u6587\u4ef6\uff0c\u4f46\u662f\u6587\u4ef6\u4e0d\u4e00\u5b9a\u662f\u8bbe\u5907\u3002 \u56e0\u6b64\uff0c\u64cd\u4f5c /dev/stdin \u548c/dev/stdout`\u8fd92\u4e2a\u6587\u4ef6\uff0c\u5b9e\u9645\u4e0a\u662f\u64cd\u4f5c\u4e24\u4e2a\u6587\u4ef6\u5b58\u653e\u5730\u5740\u5bf9\u5e94\u7684\u8bbe\u5907\u6587\u4ef6\u3002 \u901a\u8fc7\u4e0b\u9762\u547d\u4ee4\u53ef\u4ee5\u770b\u5230\u6807\u51c6\u8f93\u5165\u8f93\u51fa\u6587\u4ef6\u7684\u7279\u70b9\uff0c\u4ed6\u4eec\u867d\u7136\u5728 /dev \u76ee\u5f55\u4e0b\uff0c\u90fd\u662f\u4ee5 l \u5f00\u5934\u7684\u94fe\u63a5\u6587\u4ef6\uff0c\u6307\u5411\u7684\u662f\u53e6\u4e00\u4e2a\u6587\u4ef6\u7684\u5730\u5740\u3002 $ ls -l /dev/std* lrwxrwxrwx 1 root root 15 Nov 13 10 :39 /dev/stderr -> /proc/self/fd/2 lrwxrwxrwx 1 root root 15 Nov 13 10 :39 /dev/stdin -> /proc/self/fd/0 lrwxrwxrwx 1 root root 15 Nov 13 10 :39 /dev/stdout -> /proc/self/fd/1 # Rocky $ ll /proc/self/fd/ lrwx------. 1 vagrant wheel 64 Nov 13 22 :38 0 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 22 :38 1 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 22 :38 2 -> /dev/pts/0 lr-x------. 1 vagrant wheel 64 Nov 13 22 :38 3 -> /proc/1702/fd # Ubuntu $ ll /proc/self/fd/ lrwx------ 1 vagrant sudo 64 Nov 13 14 :38 0 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 14 :38 1 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 14 :38 2 -> /dev/pts/0 lr-x------ 1 vagrant sudo 64 Nov 13 14 :38 3 -> /proc/2062/fd/ # openSUSE $ ll /proc/self/fd/* ls: cannot access '/proc/self/fd/255' : No such file or directory ls: cannot access '/proc/self/fd/3' : No such file or directory lrwx------ 1 vagrant wheel 64 Nov 13 22 :37 /proc/self/fd/0 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 22 :37 /proc/self/fd/1 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 22 :37 /proc/self/fd/2 -> /dev/pts/0 Linux\u8fdb\u7a0b\u9ed8\u8ba4\u4f1a\u6253\u5f00\u7684\u4e09\u4e2a\u6587\u4ef6\uff1a \u6807\u51c6\u8f93\u5165 /dev/stdin \uff0c\u63cf\u8ff0\u7b26\u4e3a 0\uff0c\u9ed8\u8ba4\u662f\u952e\u76d8\u8f93\u5165\u3002 \u6807\u51c6\u8f93\u51fa /dev/stdout \uff0c\u63cf\u8ff0\u7b26\u4e3a 1\uff0c\u9ed8\u8ba4\u662f\u8f93\u51fa\u5230\u5c4f\u5e55\u3002 \u6807\u51c6\u8f93\u51fa /dev/stderr \uff0c\u63cf\u8ff0\u7b26\u4e3a 2\uff0c\u9ed8\u8ba4\u662f\u8f93\u51fa\u5230\u5c4f\u5e55\u3002 \u4ee5Rocky\u4e3a\u4f8b\uff0c\u521b\u5efa file.py \u6587\u4ef6\u3002 $ cat > file.py < test.txt \u8fd0\u884c file.py \u7a0b\u5e8f\u3002 python3 file.py \u6253\u5f00\u65b0\u7684\u7ec8\u7aef\u7a97\u53e3\uff0c\u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u5f97\u5230python3\u8fd9\u4e2a\u7a0b\u5e8f\u8fd0\u884c\u7684process ID\u3002\u5176\u4e2d\u53ef\u4ee5\u770b\u5230\u6709\u4e00\u4e2a\u6765\u81ea\u6587\u4ef6test.txt\u88ab\u7a0b\u5e8ffile.py\u6253\u5f00\uff08\u8f93\u5165\uff09\u3002 $ pidof python3 1739 788 $ sudo ls -l /proc/788/fd/ lr-x------. 1 root root 64 Nov 13 23 :00 0 -> /dev/null l-wx------. 1 root root 64 Nov 13 23 :00 1 -> /dev/null lrwx------. 1 root root 64 Nov 13 23 :00 10 -> 'socket:[24677]' lrwx------. 1 root root 64 Nov 13 23 :00 11 -> 'socket:[24678]' l-wx------. 1 root root 64 Nov 13 23 :00 2 -> /dev/null l-wx------. 1 root root 64 Nov 13 10 :41 3 -> /var/log/firewalld lrwx------. 1 root root 64 Nov 13 23 :00 4 -> 'socket:[23421]' lrwx------. 1 root root 64 Nov 13 23 :00 5 -> 'anon_inode:[eventfd]' lrwx------. 1 root root 64 Nov 13 23 :00 6 -> 'socket:[24586]' lr-x------. 1 root root 64 Nov 13 23 :00 7 -> anon_inode:inotify lrwx------. 1 root root 64 Nov 13 23 :00 8 -> 'anon_inode:[eventfd]' lrwx------. 1 root root 64 Nov 13 23 :00 9 -> '/memfd:libffi (deleted)' $ sudo ls -l /proc/1739/fd/ lrwx------. 1 vagrant wheel 64 Nov 13 23 :00 0 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 23 :00 1 -> /dev/pts/0 lrwx------. 1 vagrant wheel 64 Nov 13 23 :00 2 -> /dev/pts/0 lr-x------. 1 vagrant wheel 64 Nov 13 23 :00 3 -> /home/vagrant/test.txt \u5728Ubuntu\u4e2d\u8fd0\u884c file.py \u7a0b\u5e8f\uff0cpidof\u4f1a\u53d6\u5f973\u4e2aprocess IDs\u3002 $ pidof python3 2128 924 873 $ sudo ls -l /proc/2128/fd/ lrwx------ 1 vagrant sudo 64 Nov 13 15 :10 0 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 15 :10 1 -> /dev/pts/0 lrwx------ 1 vagrant sudo 64 Nov 13 15 :10 2 -> /dev/pts/0 lr-x------ 1 vagrant sudo 64 Nov 13 15 :10 3 -> /home/vagrant/test.txt $ sudo ls -l /proc/924/fd/ lr-x------ 1 root root 64 Nov 13 15 :11 0 -> /dev/null lrwx------ 1 root root 64 Nov 13 15 :11 1 -> 'socket:[31593]' lrwx------ 1 root root 64 Nov 13 15 :11 2 -> 'socket:[31593]' l-wx------ 1 root root 64 Nov 13 02 :40 3 -> /var/log/unattended-upgrades/unattended-upgrades-shutdown.log lrwx------ 1 root root 64 Nov 13 15 :11 4 -> 'socket:[31652]' lrwx------ 1 root root 64 Nov 13 15 :11 5 -> 'anon_inode:[eventfd]' lrwx------ 1 root root 64 Nov 13 15 :11 6 -> 'anon_inode:[eventfd]' lrwx------ 1 root root 64 Nov 13 15 :11 7 -> 'socket:[31657]' l-wx------ 1 root root 64 Nov 13 15 :11 8 -> /run/systemd/inhibit/1.ref lrwx------ 1 root root 64 Nov 13 15 :11 9 -> 'socket:[31658]' $ sudo ls -l /proc/873/fd/ lr-x------ 1 root root 64 Nov 13 15 :11 0 -> /dev/null lrwx------ 1 root root 64 Nov 13 15 :11 1 -> 'socket:[31412]' lrwx------ 1 root root 64 Nov 13 15 :11 2 -> 'socket:[31412]' lrwx------ 1 root root 64 Nov 13 02 :40 3 -> 'socket:[31650]' lrwx------ 1 root root 64 Nov 13 15 :11 4 -> 'anon_inode:[eventfd]' lrwx------ 1 root root 64 Nov 13 15 :11 5 -> 'socket:[31663]' lrwx------ 1 root root 64 Nov 13 15 :11 6 -> 'socket:[31664]' openSUSE\u9700\u8981\u5b89\u88c5\u5305 sysvinit-tools \u624d\u80fd\u4f7f\u7528 pidof \u547d\u4ee4\u3002 sudo zypper in sysvinit-tools \u7531\u4e8eopenSUSE\u4e2dpidof python3\u53ea\u8fd4\u56de\u4e00\u4e2aprocess ID\uff0c\u6240\u4ee5\u53ef\u4ee5\u7b80\u5316\u547d\u4ee4\u884c\u5f97\u5230process ID\u7684\u8be6\u7ec6\u4fe1\u606f\u3002 $ sudo ls -l /proc/ ` pidof python3 ` /fd/ lrwx------ 1 vagrant wheel 64 Nov 13 23 :21 0 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 23 :21 1 -> /dev/pts/0 lrwx------ 1 vagrant wheel 64 Nov 13 23 :21 2 -> /dev/pts/0 lr-x------ 1 vagrant wheel 64 Nov 13 23 :21 3 -> /home/vagrant/test.txt \u53c2\u8003\uff1a \u5f53\u952e\u76d8\u548c\u9f20\u6807\u7b49\u8bbe\u5907\u901a\u8fc7\u4e32\u53e3\u76f4\u63a5\u8fde\u63a5\u5230\u8ba1\u7b97\u673a\u65f6\uff0c\u8fd9\u79cd\u8fde\u63a5\u79f0\u4e3aTTY\u3002 \u4f2a\u7ec8\u7aefpseudoterminal\uff08\u7f29\u5199\u4e3a\u201cpty\u201d\uff09\u662f\u4e00\u5bf9\u63d0\u4f9b\u53cc\u5411\u901a\u4fe1\u901a\u9053\u7684\u865a\u62df\u5b57\u7b26\u8bbe\u5907\u3002 \u901a\u9053\u7684\u4e00\u7aef\u79f0\u4e3a\u4e3b\u7aefmaster\uff1b \u53e6\u4e00\u7aef\u79f0\u4e3a\u4ece\u7aefslave\u3002 /dev/pts \u8868\u793a\u4e0e\u4f2a\u7ec8\u7aefpseudoterminal\u7684\u4e3b\u7aefmaster\u6216\u4ece\u7aefslave\u76f8\u5173\u7684master\u6587\u4ef6\uff0c\u64cd\u4f5c\u7cfb\u7edf\u5c06\u5176\u4fdd\u5b58\u4e3a /dev/ptmx \u6587\u4ef6\u3002 telnet \u548c ssh \u7b49\u7a0b\u5e8f\u80fd\u591f\u4eff \u7aef\u7528\u6237> \u4e0e\u5b83\u4eec\u7684\u4ea4\u4e92\uff0c\u867d\u7136\u672c\u8d28\u4e0a\u662f\u4e0e\u6587\u4ef6 /dev/ptmx \u8fdb\u884c\u4ea4\u4e92\uff0c\u4f46\u5448\u73b0\u7ed9\u7528\u6237\u7684\u5374\u662f\u597d\u50cf\u8fd0\u884c\u5728\u771f\u6b63\u7684\u7ec8\u7aef\u7a97\u53e3\u4e00\u6837\uff0c\u4ece\u7aef\u7684\u6587\u4ef6\u662f\u4e3b\u7aef\u7684\u8f93\u5165\u3002 \u4f2a\u7ec8\u7aef\u8fdb\u7a0b\u5728Linux\u4e2d\u88ab\u5b58\u50a8\u5728 /dev/pts/ \u76ee\u5f55\u4e0b\u3002 /dev/pts/ \u76ee\u5f55\u4e0b\u7684\u5185\u5bb9\u662f\u4e00\u4e9b\u7279\u6b8a\u7684\u76ee\u5f55\uff0c\u7531Linux\u5185\u6838\u6240\u521b\u5efa\u3002 \u6bcf\u4e2a\u552f\u4e00\u7684\u7ec8\u7aef\u7a97\u53e3\u90fd\u4e0e /dev/pts \u7cfb\u7edf\u4e2d\u7684\u4e00\u4e2aLinux pts \u6761\u76ee\u76f8\u5173\u3002 \u4e0b\u9762\u8fd4\u56de\u7684\u7ed3\u679c\u8bf4\u660e\u67092\u4e2a\u8fdc\u7a0b\u7ec8\u7aef\u8fde\u63a5\u5230\u5f53\u524d\u7684\u673a\u5668\u3002 $ ll /dev/pts/ crw--w----. 1 vagrant tty 136 , 0 Nov 13 23 :18 0 crw--w----. 1 vagrant tty 136 , 1 Nov 13 23 :48 1 c---------. 1 root root 5 , 2 Nov 13 10 :41 ptmx \u4e5f\u53ef\u4ee5\u901a\u8fc7 w \u547d\u4ee4\u770b\u52302\u4e2a\u7ec8\u7aef\u8fdb\u7a0b\u3002 $ w 23 :55:05 up 13 :14, 2 users, load average: 0 .00, 0 .00, 0 .00 USER TTY LOGIN@ IDLE JCPU PCPU WHAT vagrant pts/0 10 :51 37 :03 0 .05s 0 .05s -bash vagrant pts/1 23 :48 0 .00s 0 .03s 0 .00s w \u5355\u4e2a\u4f2a\u7ec8\u7aefpseudoterminal\u53ef\u4ee5\u540c\u65f6\u63a5\u6536\u6765\u81ea\u4e0d\u540c\u7684\u7a0b\u5e8f\u7684\u8f93\u51fa\u3002 \u591a\u4e2a\u7a0b\u5e8f\u540c\u65f6\u5bf9\u4e00\u4e2a\u4f2a\u7ec8\u7aefpseudoterminal\u8fdb\u884c\u8bfb\u53d6\u4f1a\u5f15\u8d77\u6df7\u6dc6\u3002 \u5b58\u50a8\u5728 /dev/pts \u76ee\u5f55\u4e2d\u7684\u6587\u4ef6\u662f\u62bd\u8c61\u6587\u4ef6\u800c\u4e0d\u662f\u771f\u5b9e\u6587\u4ef6\uff0c\u662f\u4f2a\u7ec8\u7aef\u4e2d\u6267\u884c\u7a0b\u5e8f\u65f6\u4e34\u65f6\u5b58\u50a8\u7684\u6570\u636e\u3002 \u6253\u5f00 /dev/pts \u4e0b\u7684\u6587\u4ef6\u901a\u5e38\u6ca1\u6709\u4ec0\u4e48\u5b9e\u9645\u610f\u4e49\u3002","title":"5.\u6807\u51c6\u8f93\u5165\u8f93\u51fa"},{"location":"linux/SRE/02-filesystem/#6","text":"","title":"6.\u91cd\u5b9a\u5411\u548c\u7ba1\u9053"},{"location":"linux/SRE/02-filesystem/#61","text":"\u5e38\u7528\u547d\u4ee4\u683c\u5f0f\uff1a command < file \uff1a\u5c06\u6307\u5b9a\u6587\u4ef6 file \u4f5c\u4e3a\u547d\u4ee4\u7684\u8f93\u5165\u8bbe\u5907\u3002 command << delimiter \uff1a\u8868\u793a\u4ece\u6807\u51c6\u8f93\u5165\u8bbe\u5907\uff08\u952e\u76d8\uff09\u4e2d\u8bfb\u5165\uff0c\u76f4\u5230\u9047\u5230\u5206\u754c\u7b26 delimiter \u505c\u6b62\uff08\u8bfb\u5165\u7684\u6570\u636e\u4e0d\u5305\u62ec\u5206\u754c\u7b26\uff09\uff0c\u8fd9\u91cc\u7684\u5206\u754c\u7b26\u53ef\u4ee5\u7406\u89e3\u4e3a\u81ea\u5b9a\u4e49\u7684\u5b57\u7b26\u4e32\u3002 command < file1 > file2 \uff1a\u5c06 file1 \u4f5c\u4e3a\u547d\u4ee4\u7684\u8f93\u5165\u8bbe\u5907\uff0c\u8be5\u547d\u4ee4\u7684\u6267\u884c\u7ed3\u679c\u8f93\u51fa\u5230 file2 \u4e2d\u3002 # \u8f93\u51fa\u6587\u4ef6file.py\u5185\u5bb9\uff08\u8f93\u5165\u8bbe\u5907\u662f\u952e\u76d8\uff09 $ cat file.py # \u8f93\u51fa\u6587\u4ef6file.py\u5185\u5bb9\uff08\u8f93\u5165\u8bbe\u5907\u662f\u6587\u4ef6file.py\uff09 $ cat < file.py # \u6307\u5b9a\u5206\u754c\u7b26\uff08\u8fd9\u91cc\u662fEOF\uff09\uff0c\u8bfb\u53d6\u952e\u76d8\u8f93\u5165\u5185\u5bb9\uff0c\u76f4\u5230\u9047\u5230\u6307\u5b9a\u5206\u754c\u7b26\u4e3a\u6b62\uff0c\u5c06\u6240\u8bfb\u53d6\u7684\u5185\u5bb9\u8f93\u51fa\u5230\u6587\u4ef6file.py\u3002 $ cat > file.py < new.py","title":"6.1.\u8f93\u5165\u91cd\u5b9a\u5411"},{"location":"linux/SRE/02-filesystem/#62","text":"\u8f93\u51fa\u91cd\u5b9a\u5411\u5206\u4e3a\u6807\u51c6\u8f93\u51fa\u91cd\u5b9a\u5411\u548c\u9519\u8bef\u8f93\u51fa\u91cd\u5b9a\u5411\u4e24\u79cd\u3002 \u5e38\u7528\u547d\u4ee4\u683c\u5f0f\uff1a command > file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u6807\u51c6\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u8f93\u51fa\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u5df2\u5305\u542b\u6570\u636e\uff0c\u4f1a\u6e05\u7a7a\u539f\u6709\u6570\u636e\uff0c\u518d\u5199\u5165\u65b0\u6570\u636e\u3002 command 2> file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u9519\u8bef\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u4e2d\u5df2\u5305\u542b\u6570\u636e\uff0c\u4f1a\u6e05\u7a7a\u539f\u6709\u6570\u636e\uff0c\u518d\u5199\u5165\u65b0\u6570\u636e\u3002 command >> file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u6807\u51c6\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u8f93\u51fa\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u5df2\u5305\u542b\u6570\u636e\uff0c\u65b0\u6570\u636e\u5c06\u8ffd\u52a0\u5199\u5165\u5230\u539f\u6709\u5185\u5bb9\u7684\u540e\u9762\u3002 command 2>> file \uff1a\u5c06\u547d\u4ee4 command \u6267\u884c\u7684\u9519\u8bef\u8f93\u51fa\u7ed3\u679c\u91cd\u5b9a\u5411\u5230\u6307\u5b9a\u7684\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u4e2d\u5df2\u5305\u542b\u6570\u636e\uff0c\u65b0\u6570\u636e\u5c06\u8ffd\u52a0\u5199\u5165\u5230\u539f\u6709\u5185\u5bb9\u7684\u540e\u9762\u3002 command >> file 2>&1 \u6216\u8005 command &>> file \uff1a\u5c06\u6807\u51c6\u8f93\u51fa\u6216\u8005\u9519\u8bef\u8f93\u51fa\u5199\u5165\u5230\u6307\u5b9a\u6587\u4ef6 file \u4e2d\uff0c\u5982\u679c\u8be5\u6587\u4ef6\u4e2d\u5df2\u5305\u542b\u6570\u636e\uff0c\u65b0\u6570\u636e\u5c06\u8ffd\u52a0\u5199\u5165\u5230\u539f\u6709\u5185\u5bb9\u7684\u540e\u9762\u3002 \u6ce8\u610f\uff1a\u4e0a\u9762\u7684 file \u53ef\u4ee5\u662f\u4e00\u4e2a\u666e\u901a\u6587\u4ef6\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u4e00\u4e2a\u7279\u6b8a\u7684\u6587\u4ef6 /dev/null \u3002 /dev/null \u5e76\u4e0d\u4fdd\u5b58\u6570\u636e\uff0c\u88ab\u5199\u5165 /dev/null \u7684\u6570\u636e\u6700\u7ec8\u90fd\u4f1a\u4e22\u5931\u3002 \u4e3e\u4f8b\uff1a2\u4e2apython\u6587\u4ef6\u5b58\u5728\uff0c\u5176\u4ed62\u4e2a\u65e0\u6269\u5c55\u540d\u7684\u6587\u4ef6\u4e0d\u5b58\u5728\u3002 ls file.py > out ls file 2 > out.err ls new.py >> out ls new 2 >> out.err \u53ef\u4ee5\u5f97\u5230\u9884\u671f\u7684\u7ed3\u679c\u3002\u4e24\u4e2a\u9519\u8bef\u8bb0\u5f55\u90fd\u88ab\u8ffd\u52a0\u5230 out.err \u6587\u4ef6\u4e2d\u3002\u4e24\u4e2a\u6210\u529f\u6267\u884c\u7684\u547d\u4ee4\u7684\u8fd4\u56de\u7ed3\u679c\u4e5f\u8f93\u51fa\u5230 out \u6587\u4ef6\u4e2d\u3002 $ccat out file.py new.py $ cat out.err ls: cannot access 'file' : No such file or directory ls: cannot access 'new' : No such file or directory \u4e0a\u4f8b\u547d\u4ee4\u4e5f\u53ef\u4ee5\u5408\u5e76\u3002 ls file.py > out 2 > out.err ls file >> out 2 >> out.err 2>&1 \u683c\u5f0f\u4e3e\u4f8b\uff1a $ ls file >> out.txt 2 > & 1 $ cat out.txt ls: cannot access 'file' : No such file or directory $ ls file.py & >> out.txt $ cat out.txt ls: cannot access 'file' : No such file or directory file.py","title":"6.2.\u8f93\u51fa\u91cd\u5b9a\u5411"},{"location":"linux/SRE/02-filesystem/#63","text":"\u683c\u5f0f\uff1a command1 < <(command2) tr 'a-z' 'A-Z' < < ( echo \"Hello World\" ) \u5e94\u7528\uff1a\u4fee\u6539\u5bc6\u7801 \u5bc6\u7801\u4fdd\u5b58\u5728 passwd.txt \u6587\u4ef6\u4e2d\uff0c\u5e76\u4e25\u683c\u9650\u5236\u6539\u6587\u4ef6\u7684\u6743\u9650\u3002 \u901a\u8fc7\u53c2\u6570 --stdin \u5b9e\u73b0\u6a21\u62df\u952e\u76d8\u8f93\u5165\u64cd\u4f5c\u8f93\u5165\u7528\u6237\u540d\u3002 \u5728Rocky\u4e2d\u53ef\u4ee5\u4f7f\u7528 --stdin \u53c2\u6570\u3002 passwd --stdin vagrant < passwd.txt \u5728openSUSE\u548cUbuntu\u4e2d\uff0c --stdin \u53c2\u6570\u65e0\u6cd5\u8bc6\u522b\u3002\u53ef\u4ee5\u6539\u7528\u4e0b\u9762\u7684\u65b9\u6cd5\u3002 echo passwd.txt | chpasswd \u5176\u4e2dpasswd.txt\u7684\u683c\u5f0f\u4e3a username:password \u3002 \u53c2\u8003\uff1a Here-document(Here-doc)\uff1a\u8f93\u5165\u7684\u6587\u672c\u5757\u91cd\u5b9a\u5411\u81f3\u6807\u51c6\u8f93\u5165\u6d41\uff0c\u76f4\u81f3\u9047\u5230\u7279\u6b8a\u7684\u6587\u4ef6\u7ed3\u675f\u6807\u8bb0\u7b26\u4e3a\u6b62\uff08\u6587\u4ef6\u7ed3\u675f\u6807\u8bb0\u7b26\u53ef\u4ee5\u662f\u4efb\u610f\u7684\u552f\u4e00\u7684\u5b57\u7b26\u4e32\uff0c\u4f46\u5927\u90e8\u5206\u4eba\u90fd\u9ed8\u8ba4\u4f7f\u7528 EOF \uff09\u3002 cat < \u5c06\u547d\u4ee4\u4e0e\u6587\u4ef6\u8fde\u63a5\u8d77\u6765\uff0c\u7528\u6587\u4ef6\u6765\u63a5\u6536\u547d\u4ee4\u7684\u8f93\u51fa\uff1b\u800c\u7ba1\u9053\u7b26 | \u5c06\u547d\u4ee4\u4e0e\u547d\u4ee4\u8fde\u63a5\u8d77\u6765\uff0c\u7528\u53f3\u8fb9\u547d\u4ee4\u6765\u63a5\u6536\u5de6\u8fb9\u547d\u4ee4\u7684\u8f93\u51fa\u3002 $ ls | tr 'a-z' 'A-Z' BIN F1.TXT F2.TXT FILE.PY NEW.PY OUT OUT.ERR TEST.TXT","title":"7.\u7ba1\u9053"},{"location":"linux/SRE/03-identity-security/","text":"\u7b2c\u4e09\u7ae0 \u8eab\u4efd\u4e0e\u5b89\u5168 \u00b6 1.\u7528\u6237\u3001\u7ec4\u3001\u6743\u9650 \u00b6 \u7528\u6237\u548c\u7ec4 \u7528\u6237user\u548c\u7ec4group\u5728Linux\u7cfb\u7edf\u4e2d\u4ee5\u6570\u5b57\u5f62\u5f0f\u8fdb\u884c\u7ba1\u7406\u3002 \u7528\u6237\u88ab\u5206\u914d\u7684\u53f7\u7801\u79f0\u4e3a\u7528\u6237ID\uff08UID\uff09\u3002 \u6bcf\u4e2aLinux\u7cfb\u7edf\u90fd\u6709\u4e00\u4e2a\u7279\u6743\u7528\u6237\uff0c\u5373 root \u7528\u6237\u3002 root \u662f\u7cfb\u7edf\u7ba1\u7406\u5458\u3002 \u6b64\u7528\u6237\u7684UID\u59cb\u7ec8\u4e3a0\u3002 \u666e\u901a\u7528\u6237\u7684UID\u7f16\u53f7\uff08\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff09\u4e3a1000\u3002 \u6bcf\u4e2a\u7ec4\u4e5f\u5206\u914d\u4e86\u4e00\u4e2a\u79f0\u4e3a\u7ec4ID\uff08GID\uff09\u7684\u7f16\u53f7\u3002 \u6bcf\u4e2a\u7528\u6237\u6709\u4e00\u4e2a\u4e3b\u8981\u7ec4\uff08primary group\uff09\uff0c\u6709\u96f6\u4e2a\u6216\u8005\u4efb\u610f\u4e2a\u9644\u52a0\u7ec4\uff08supplementary group\uff09\u3002 \u4ee5openSUSE\u4e3a\u4f8b\uff1a UID 0: root 1 \u2013 99: System 100 \u2013 499: System accounts \u2265 1000: Normal (unprivileged) accounts GID 0: root 1 \u2013 99: System Groups 100 \u2013 499: Dynamically Allocated System Groups \u2265 1000: Normal Groups \u4e3e\u4f8b\uff1a $ id postfix uid = 51 ( postfix ) gid = 51 ( postfix ) groups = 482 ( mail ) ,59 ( maildrop ) ,51 ( postfix ) $ id vagrant uid = 1000 ( vagrant ) gid = 478 ( wheel ) groups = 0 ( root ) ,478 ( wheel ) \u63d0\u793a\uff1a UID\u548cGID\u7b49\u7f16\u53f7\u89c4\u5219\uff0c\u662f\u5728\u6587\u4ef6 /etc/login.defs \u4e2d\u7ea6\u5b9a\u7684\u3002 2.SELinux \u00b6 Security-Enhanced Linux (SELinux) \u662f\u4e00\u79cdLinux\u7cfb\u7edf\u7684\u5b89\u5168\u67b6\u6784\uff0c\u5b83\u5141\u8bb8\u7ba1\u7406\u5458\u66f4\u597d\u5730\u63a7\u5236\u8c01\u53ef\u4ee5\u8bbf\u95ee\u7cfb\u7edf\u3002 SELinux\u4e8e2000\u5e74\u5411\u5f00\u6e90\u793e\u533a\u53d1\u5e03\uff0c\u5e76\u4e8e2003\u5e74\u96c6\u6210\u5230\u4e0a\u6e38 Linux \u5185\u6838\u4e2d\u3002 SELinux\u4e3a\u7cfb\u7edf\u4e0a\u7684\u5e94\u7528\u7a0b\u5e8f\u3001\u8fdb\u7a0b\u548c\u6587\u4ef6\u5b9a\u4e49\u4e86\u8bbf\u95ee\u63a7\u5236\u3002 \u5b83\u4f7f\u7528\u5b89\u5168\u7b56\u7565\uff08\u4e00\u7ec4\u89c4\u5219\u544a\u8bc9SELinux\u4ec0\u4e48\u53ef\u4ee5\u8bbf\u95ee\u6216\u4e0d\u53ef\u4ee5\u8bbf\u95ee\uff09\u6765\u5f3a\u5236\u6267\u884c\u7b56\u7565\u5141\u8bb8\u7684\u8bbf\u95ee\u3002 \u5f53\u79f0\u4e3a\u4e3b\u4f53\uff08subject\uff09\u7684\u5e94\u7528\u7a0b\u5e8f\u6216\u8fdb\u7a0b\u8bf7\u6c42\u8bbf\u95ee\u5bf9\u8c61\uff08\u5982\u6587\u4ef6\uff09\u65f6\uff0cSELinux\u4f1a\u68c0\u67e5\u8bbf\u95ee\u5411\u91cf\u7f13\u5b58(AVC, Access Vector Cache)\uff0c\u5176\u4e2d\u7f13\u5b58\u4e86\u4e3b\u4f53\u548c\u5bf9\u8c61\u7684\u6743\u9650\u3002 \u5982\u679cSELinux\u65e0\u6cd5\u6839\u636e\u7f13\u5b58\u7684\u6743\u9650\u505a\u51fa\u8bbf\u95ee\u51b3\u5b9a\uff0c\u5b83\u4f1a\u5c06\u8bf7\u6c42\u53d1\u9001\u5230\u5b89\u5168\u670d\u52a1\u5668\u3002 \u5b89\u5168\u670d\u52a1\u5668\u68c0\u67e5\u5e94\u7528\u7a0b\u5e8f\u6216\u8fdb\u7a0b\u548c\u6587\u4ef6\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\u3002 \u4eceSELinux\u7b56\u7565\u6570\u636e\u5e93\u5e94\u7528\u5b89\u5168\u4e0a\u4e0b\u6587\uff08Security context\uff09\uff0c\u7136\u540e\u6388\u4e88\u6216\u62d2\u7edd\u8bb8\u53ef\u3002 \u5982\u679c\u6743\u9650\u88ab\u62d2\u7edd\uff0c avc: denied \u6d88\u606f\u5c06\u5728 /var/log.messages \u4e2d\u4f53\u73b0\u3002 \u4f20\u7edf\u4e0a\uff0cLinux\u548cUNIX\u7cfb\u7edf\u90fd\u4f7f\u7528DAC\uff08Discretionary Access Control\uff09\u3002 SELinux\u662fLinux\u7684MAC\uff08Mandatory Access Control\uff09\u7cfb\u7edf\u7684\u4e00\u4e2a\u793a\u4f8b\u3002 \u5728DAC\u65b9\u5f0f\u4e0b\uff0c\u6587\u4ef6\u548c\u8fdb\u7a0b\u6709\u81ea\u5df1\u7684\u5c5e\u4e3b\uff08\u6240\u6709\u8005\uff09\u3002 \u7528\u6237\u53ef\u4ee5\u62e5\u6709\u4e00\u4e2a\u6587\u4ef6\uff0c\u4e00\u4e2a\u7ec4\u4e5f\u53ef\u4ee5\u62e5\u6709\u4e00\u4e2a\u6587\u4ef6\uff0c\u6216\u8005\u5176\u4ed6\u4eba\u3002 \u7528\u6237\u53ef\u4ee5\u66f4\u6539\u81ea\u5df1\u6587\u4ef6\u7684\u6743\u9650\u3002 root \u7528\u6237\u5bf9DAC\u7cfb\u7edf\u5177\u6709\u5b8c\u5168\u8bbf\u95ee\u63a7\u5236\u6743\u3002 \u4f46\u662f\u5728\u50cfSELinux\u8fd9\u6837\u7684MAC\u7cfb\u7edf\u4e0a\uff0c\u5bf9\u4e8e\u8bbf\u95ee\u7684\u7ba1\u7406\u662f\u901a\u8fc7\u8bbe\u7f6e\u7b56\u7565\u6765\u5b9e\u73b0\u7684\u3002\u5373\u4f7f\u7528\u6237\u4e3b\u76ee\u5f55\u4e0a\u7684DAC\u8bbe\u7f6e\u53d1\u751f\u66f4\u6539\uff0c\u7528\u4e8e\u9632\u6b62\u5176\u4ed6\u7528\u6237\u6216\u8fdb\u7a0b\u8bbf\u95ee\u8be5\u76ee\u5f55\u7684SELinux\u7b56\u7565\u4e5f\u5c06\u7ee7\u7eed\u786e\u4fdd\u7cfb\u7edf\u5b89\u5168\u3002 MAC\u65b9\u5f0f\u662f\u63a7\u5236\u4e00\u4e2a\u8fdb\u7a0b\u5bf9\u5177\u4f53\u6587\u4ef6\u7cfb\u7edf\u4e0a\u9762\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u662f\u5426\u62e5\u6709\u8bbf\u95ee\u6743\u9650\u3002\u5224\u65ad\u8fdb\u7a0b\u662f\u5426\u53ef\u4ee5\u8bbf\u95ee\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u4f9d\u636e\uff0c\u53d6\u51b3\u4e8eSELinux\u4e2d\u8bbe\u5b9a\u7684\u5f88\u591a\u7b56\u7565\u89c4\u5219\u3002 \u8bbf\u95ee\u63a7\u5236\u5217\u8868 (ACL\uff0cAccess Control List) \u4e3a\u6587\u4ef6\u7cfb\u7edf\u63d0\u4f9b\u4e86\u4e00\u79cd\u989d\u5916\u7684\u3001\u66f4\u7075\u6d3b\u7684\u6743\u9650\u673a\u5236\u3002 \u5b83\u65e8\u5728\u534f\u52a9 UNIX \u6587\u4ef6\u6743\u9650\u3002ACL\u5141\u8bb8\u6388\u4e88\u4efb\u4f55\u7528\u6237\u6216\u7ec4\u5bf9\u4efb\u4f55\u78c1\u76d8\u8d44\u6e90\u7684\u6743\u9650\u3002ACL\u9002\u7528\u4e8e\u5728\u4e0d\u4f7f\u67d0\u4e2a\u7528\u6237\u6210\u4e3a\u7ec4\u6210\u5458\u7684\u60c5\u51b5\u4e0b\uff0c\u4ecd\u65e7\u6388\u4e88\u4e00\u4e9b\u8bfb\u6216\u5199\u8bbf\u95ee\u6743\u9650\u3002 \u4e0b\u9762\u793a\u4f8b\u5bf9\u6bd4\u8bf4\u660e\u4e86SELinux\u548cACL\u5728\u6587\u4ef6\u5c5e\u6027\u5c55\u73b0\u4e0a\u7684\u7279\u70b9\u3002 -rwxr-xr-- vagrant wheel \uff1a\u6ca1\u6709selinux\u4e0a\u4e0b\u6587\uff0c\u6ca1\u6709ACL -rwx--xr-x+ vagrant wheel \uff1a\u53ea\u6709ACL\uff0c\u6ca1\u6709selinux\u4e0a\u4e0b\u6587 -rw-r--r--. vagrant wheel \uff1a\u53ea\u6709selinux\u4e0a\u4e0b\u6587\uff0c\u6ca1\u6709ACL -rwxrwxr--+ vagrant wheel \uff1a\u6709selinux\u4e0a\u4e0b\u6587\uff0c\u6709ACL 2.1.SELinux\u4e3b\u8981\u6982\u5ff5 \u00b6 \u7528\u6237(Users)\uff1a SELinux\u7684\u7528\u6237\u4e0d\u7b49\u540c\u4e0eLinux\u7528\u6237\u3002 SELinux\u7528\u6237\u4ee5\u540e\u7f00 _u \u7ed3\u5c3e\u3002 \u89d2\u8272(Roles)\uff1a \u89d2\u8272Roles\u662f\u7531\u7b56\u7565Policies\u5b9a\u4e49\u7684\uff0c\u89d2\u8272\u51b3\u5b9a\u4e86\u4f7f\u7528\u54ea\u4e2a\u7b56\u7565\u3002 SELinux\u89d2\u8272\u4ee5\u540e\u7f00 _r \u7ed3\u5c3e\u3002 \u7c7b\u578b(Types)\uff1a SELinux\u662f\u7c7b\u578b\u5f3a\u5236\u7684\uff0c\u7c7b\u578bTypes\u51b3\u5b9a\u8fdb\u7a0b\u80fd\u5426\u8bbf\u95ee\u67d0\u4e2a\u6587\u4ef6\u3002 SELinux\u7c7b\u578b\u662f\u4ee5\u540e\u7f00 _t \u7ed3\u5c3e\u3002 \u4e0a\u4e0b\u6587(Contexts)\uff1a \u7528\u6765\u6807\u8bb0\u8fdb\u7a0b\u548c\u6587\u4ef6\u3002\u5206\u522b\u662f\u7528\u6237Users\uff0c\u89d2\u8272Roles\uff0c\u7c7b\u578bTypes\uff0c\u8303\u56f4Ranges\u3002 \u683c\u5f0f\uff1a user:role:type:range \u6587\u4ef6\u7c7b\u578b(Object Classes)\uff1a \u6bcf\u4e2a\u6587\u4ef6\u7c7b\u578bTypes\u90fd\u5bf9\u5e94\u4e00\u5957\u7b56\u7565Policies\u3002\u7b56\u7565Policies\u51b3\u5b9a\u4e86\u8fdb\u7a0b\u5bf9\u8fd9\u7c7b\u6587\u4ef6\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u8bbf\u95ee\u6743\u9650\u67094\u79cd\uff1a \u521b\u5efacreate \u8bfb\u53d6read \u5199\u5165write \u5220\u9664unlink\uff08\u6ce8\u610f\uff0c\u8fd9\u91cc\u4e0d\u662f\u94fe\u63a5\u7684\u610f\u601d\uff09 \u89c4\u5219(Rules) \u683c\u5f0f\uff1a allow user_t user_home_t:file {create read write unlink}; \u542b\u4e49\uff1a user_t \u7c7b\u578b\u5bf9 user_home_t \u7c7b\u578b\u6709\u521b\u5efacreate\uff0c\u8bfb\u53d6read\uff0c\u5199\u5165write\uff0c\u5220\u9664unlink\u6743\u9650\u3002 2.2.SELinux in openSUSE \u00b6 \u4f5c\u4e3aSELinux\u7684\u66ff\u4ee3\u54c1\uff0c2005\u5e74\u88abNovell\u6536\u8d2d\u7684Immunix\u516c\u53f8\u5f00\u53d1\u4e86AppArmor\u3002SUSE\u5728openSUSE Leap\u4e2d\u63d0\u4f9b\u5bf9SELinux\u6846\u67b6\u7684\u652f\u6301\u3002\u8fd9\u5e76\u4e0d\u610f\u5473\u7740openSUSE Leap\u7684\u9ed8\u8ba4\u5b89\u88c5\u4f1a\u5728\u4e0d\u4e45\u7684\u5c06\u6765\u4eceAppArmor\u5207\u6362\u5230SELinux\u3002 \u6dfb\u52a0SELinux\u7684\u6e90\u3002\u53ef\u4ee5\u4ece https://download.opensuse.org/repositories/security:/SELinux/ \u4e0b\u8f7d\u5bf9\u5e94\u7684\u7b56\u7565policy\u3002 sudo zypper ar -f https://download.opensuse.org/repositories/security:/SELinux/openSUSE_Factory/ Security-SELinux \u5b89\u88c5C++\u7b49\u57fa\u7840\u5f00\u53d1\u5305\uff1a # \u5217\u51fa\u5f53\u524d\u53ef\u5b89\u88c5\u7684Pattern sudo zypper pt # \u5b89\u88c5\u4e0b\u9762\u51e0\u4e2a\u5f00\u53d1\u76f8\u5173\u7684Pattern sudo zypper in -t pattern devel_C_C++ devel_basis devel_kernel \u5b89\u88c5SELinux packages\uff1a zypper se --search-descriptions selinux sudo zypper in restorecond policycoreutils setools-console sudo zypper in selinux-tools libselinux-devel \u5b89\u88c5SELinux policy\uff1a sudo zypper in selinux-policy-targeted selinux-policy-devel selinux-autorelabel \u66f4\u65b0GRUB2 bootloader\uff08GRUB2\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\uff09\uff1a \u7f16\u8f91\u6587\u4ef6 /etc/default/grub \uff0c\u6dfb\u52a0\u4e0b\u9762\u5185\u5bb9\u5230 GRUB_CMDLINE_LINUX_DEFAULT= \u8fd9\u4e00\u884c\uff1a security = selinux selinux = 1 \u8bb0\u5f55\u8fd9\u4e00\u884c\u7684\u539f\u59cb\u4fe1\u606f\uff1a GRUB_CMDLINE_LINUX_DEFAULT = \"splash=silent resume=/dev/disk/by-uuid/47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 preempt=full mitigations=auto quiet security=apparmor\" \u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u751f\u6210\u65b0\u7684GRUB2\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\u914d\u7f6e\u6587\u4ef6\u3002 sudo grub2-mkconfig -o /boot/grub2/grub.cfg \u7f16\u8f91\u6587\u4ef6 /etc/selinux/config \u5e76\u8bbe\u7f6e SELINUX=permissive \u6765\u542f\u7528SElinux\u3002\u8fd9\u4e0e\u524d\u9762GRUB2\u7684\u542f\u52a8\u914d\u7f6e\u662f\u4e00\u81f4\u7684\u3002 \u5982\u6587\u4ef6\u4e0d\u5b58\u5728\uff0c\u5219\u521b\u5efa\u3002 $ sudo cat /etc/selinux/config SELINUX = permissive SELINUXTYPE = targeted \u91cd\u542f\u7cfb\u7edf\u3002\u7cfb\u7edf\u542f\u52a8\u53ef\u80fd\u9700\u8981\u4e00\u4e9b\u65f6\u95f4\uff0cSELinux\u9700\u8981\u7ed9\u6574\u4e2a\u6587\u4ef6\u7cfb\u7edf\u91cd\u65b0\u8fdb\u884c\u6807\u7b7e\u5316\u3002 \u91cd\u542f\u540e\uff0c\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u6765\u67e5\u770bSELinux\u662f\u5426\u8fd0\u884c\u6b63\u5e38\u3002 $ sudo getenforce Permissive $ sudo sestatus -v SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted Current mode: permissive Mode from config file: permissive Policy MLS status: enabled Policy deny_unknown status: allowed Memory protection checking: requested ( insecure ) Max kernel policy version: 33 Process contexts: Current context: unconfined_u:unconfined_r:unconfined_t:s0 Init context: system_u:system_r:kernel_t:s0 /sbin/agetty system_u:system_r:kernel_t:s0 /usr/sbin/sshd system_u:system_r:kernel_t:s0 File contexts: Controlling terminal: unconfined_u:object_r:devpts_t:s0 /etc/passwd system_u:object_r:unlabeled_t:s0 /etc/shadow system_u:object_r:unlabeled_t:s0 /bin/bash system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /bin/login system_u:object_r:unlabeled_t:s0 /bin/sh system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /sbin/agetty system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /sbin/init system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /usr/sbin/sshd system_u:object_r:unlabeled_t:s0 \u53c2\u8003\uff1a GRUB2\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\u4e2d\u6dfb\u52a0\u7684\u4e09\u4e2a\u53c2\u6570\u7684\u89e3\u91ca\uff1a security=selinux : This option tells the kernel to use SELinux and not AppArmor. selinux=1 : This option switches on SELinux. enforcing=0 : This option puts SELinux in permissive mode. In this mode, SELinux is fully functional, but does not enforce any of the security settings in the policy. Use this mode for testing and configuring your system. To switch on SELinux protection, when the system is fully operational, change the option to enforcing=1 and add SELINUX=enforcing in /etc/selinux/config . \u5c0f\u8d34\u58eb\uff1a \u5728\u9996\u6b21\u542f\u7528SELinux\u540e\uff0c\u5982\u679c\u53ea\u5728grub2\u91cc\u9762\u6dfb\u52a0selinux=1\uff0c\u901a\u8fc7 getenforce \u547d\u4ee4\u770b\u7684SELinux\u4e00\u76f4\u5c31\u662fdisabled\u7684\u72b6\u6001\uff0c\u9700\u8981\u624b\u5de5\u521b\u5efa/etc/selinux/config\u6587\u4ef6\u6dfb\u52a0\u914d\u7f6e\u624d\u884c\u3002\u611f\u89c9grub2\u91cc\u9762\u65e0\u9700\u8bbe\u7f6e\uff0c\u76f4\u63a5\u914d\u7f6e/etc/selinux/config\u6587\u4ef6\u3002\u4e0d\u786e\u5b9a\u8fd9\u4e2a\u60f3\u6cd5\u662f\u5426\u6b63\u786e\u3002 \u5728grub2\u4e2d\u8bbe\u5b9aselinux=1\uff0c\u5728/etc/selinux/config\u6587\u4ef6\u4e2d\uff1a \u8bbe\u5b9aSELINUX=permissive\uff0c\u91cd\u542f\u540e\u901a\u8fc7 getenforce \u547d\u4ee4\u770b\u5230\u7684\u662fpermissive\u3002 \u8bbe\u5b9aSELINUX=disabled\uff0c\u5219\u91cd\u542f\u540e getenforce \u547d\u4ee4\u770b\u5230\u7684\u662fdisabled\u3002 \u8fd9\u8bf4\u660e\u914d\u7f6e\u6587\u4ef6\u540e\u542f\u52a8\uff0c\u8986\u76d6\u4e86\u5185\u6838\u8bbe\u7f6e\u3002 \u6ce8\u610f\uff0c\u5982\u679c\u4ec5\u4ec5\u5b8c\u6210\u4e86\u4e0a\u9762\u7684enable SELinux\uff0c\u7acb\u523b\u8bbe\u5b9aSELINUX=enforcing\uff0c\u4f1a\u5f15\u8d77ssh\u65e0\u6cd5\u767b\u5f55\uff0c\u9519\u8bef\u4fe1\u606f\u662f /bin/bash: Permission denied \u3002 \u914d\u7f6eSELinux\u3002 $ sudo semanage boolean -l Failed to use semanage \u6dfb\u52a0\u4e0b\u9762\u5185\u5bb9\u5230.bashrc\u6587\u4ef6\u3002 export PATH = /usr/local/bin:/home/ $USER /.local/bin: $PATH \u66f4\u65b0pip3. pip3 install --upgrade pip \u5b89\u88c5\u4e0b\u9762\u51e0\u4e2a\u5305 sudo zypper in libselinux libselinux-devel sudo zypper in python3-semanage sudo zypper in libsemanage-devel libsemanage-devel-static sudo zypper in policycoreutils-python-utils sudo zypper in cross-x86_64-linux-glibc-devel glibc-utils glibc-profile sudo zypper in policycoreutils-devel 2.3.SELinux in Ubuntu \u00b6 2.4.SELinux in Rocky \u00b6 3.\u7528\u6237\u548c\u7ec4\u7684\u914d\u7f6e\u6587\u4ef6 \u00b6 /etc/passwd \uff1a\u7528\u6237\u53ca\u5176\u5c5e\u6027\u4fe1\u606f\uff08\u7528\u6237\u540d\uff0cUID\uff0c\u4e3b\u7ec4ID\u7b49\uff09 /etc/shadow \uff1a\u7528\u6237\u5bc6\u7801\u673a\u5668\u5c5e\u6027 /etc/group \uff1a\u7ec4\u53ca\u5176\u5c5e\u6027 /etc/gshadow \uff1a\u7ec4\u5bc6\u7801\u53ca\u5176\u5c5e\u6027 3.1./etc/passwd \u00b6 \u683c\u5f0f\u8bf4\u660e\uff1a vagrant:x:1001:474:vagrant:/home/vagrant:/bin/bash [ ----- ] - [ -- ] [ - ] [ ----- ] [ ----------- ] [ ------- ] | | | | | | +--------> 7 . Login shell | | | | | +--------------------> 6 . Home directory | | | | +-------------------------------> 5 . GECOS or the full name of the user | | | +-------------------------------------> 4 . GID | | +------------------------------------------> 3 . UID | +---------------------------------------------> 2 . Password +--------------------------------------------------> 1 . Username 3.2./etc/shadow \u00b6 \u683c\u5f0f\u8bf4\u660e\uff1a vagrant: $6 $.n.:17736:0:99999:7::: [ ----- ] [ ---- ] [ --- ] - [ --- ] ---- | | | | | || | +-----------> 9 . Unused | | | | | || +------------> 8 . Expiration date since Jan 1 , 1970 | | | | | | +-------------> 7 . Inactivity period \u5bc6\u7801\u8fc7\u671f\u540e\u7684\u5bbd\u9650\u671f | | | | | +--------------> 6 . Warning period, default 7 days | | | | +------------------> 5 . Maximum password age | | | +----------------------> 4 . Minimum password age | | +--------------------------> 3 . Last password change since Jan 1 , 1970 | +---------------------------------> 2 . Encrypted Password +-------------------------------------------> 1 . Username 3.3./etc/group \u00b6 \u683c\u5f0f\u8bf4\u660e\uff1a audio:x:492:pulse [ --- ] - [ - ] [ --- ] | | | +----> 4 . username-list, who have this group as their supplementary | | +---------> 3 . GID | +------------> 2 . group-password. Real password is in /etc/gshadow +----------------> 1 . groupname 3.4./etc/gshadow \u00b6 \u683c\u5f0f\u8bf4\u660e\uff1a general:!!:shelley:juan,bob [ ----- ] -- [ ----- ] [ ------ ] | | | +-------> 4 . group members ( in a comma delimited list ) | | +---------------> 3 . group adminstrators ( in a comma delimited list ) | +---------------------> 2 . encrypted password. ` ! ` , ` !! ` , and null +---------------------------> 1 . group name Encrypted password ! \uff1ano user is allowed to access the group using the newgrp command. !! \uff1athe same as a value of ! \u2014 however, it also indicates that a password has never been set before. null\uff1aonly group members can log into the group. 3.5.\u751f\u6210\u968f\u673a\u5bc6\u7801 \u00b6 # \u901a\u8fc7`/dev/urandom`\u751f\u6210\u968f\u673a\u6570\uff0c\u901a\u8fc7`tr -dc`\u8fc7\u6ee4\u968f\u673a\u6570\uff0c\u53ea\u4fdd\u7559\u5b57\u6bcd\u548c\u6570\u5b57\uff0c\u901a\u8fc7`head -c`\u4fdd\u7559\u6307\u5b9a\u4f4d\u6570 $ tr -dc '[:alnum:]' < /dev/urandom | head -c 12 xFw7vfma54D8 $ openssl rand -base64 9 I5TZXJfpd3Pg 3.6.vipw/vigr/pwck/grpck\u547d\u4ee4 \u00b6 vipw \u548c vigr \u547d\u4ee4\u5206\u522b\u7f16\u8f91\u6587\u4ef6 /etc/passwd \u548c /etc/group \u3002 \u5982\u679c\u6307\u5b9a\u4e86 -s \u6807\u5fd7\uff0c\u8fd9\u4e9b\u547d\u4ee4\u5c06\u5206\u522b\u7f16\u8f91\u5176\u6587\u4ef6\u7684\u5f71\u5b50\uff08\u5b89\u5168\uff09\u7248\u672c\uff1a /etc/shadow \u548c /etc/gshadow \u3002 vipw \u548c vigr \u547d\u4ee4\u5728\u7f16\u8f91\u6587\u4ef6\u65f6\u4f1a\u8bbe\u7f6e\u9501\u4ee5\u9632\u6b62\u6587\u4ef6\u635f\u574f\u3002 vipw \u548c vigr \u547d\u4ee4\u4f1a\u9996\u5148\u5c1d\u8bd5\u73af\u5883\u53d8\u91cf $VISUAL \uff0c\u7136\u540e\u662f\u73af\u5883\u53d8\u91cf $EDITOR \uff0c\u6700\u540e\u662f\u9ed8\u8ba4\u7f16\u8f91\u5668 vi \u3002 sudo vipw sudo vipw -s sudo vigr sudo vigr -s pwck \u547d\u4ee4\u5b9e\u73b0\u9a8c\u8bc1\u7cfb\u7edf\u8ba4\u8bc1\u4fe1\u606f\u7684\u5b8c\u6574\u6027\u3002 \u68c0\u67e5 /etc/passwd \u548c /etc/shadow \u4e2d\u7684\u6240\u6709\u6761\u76ee\u6bcf\u4e2a\u5b57\u6bb5\u662f\u5426\u5177\u6709\u6b63\u786e\u7684\u683c\u5f0f\u548c\u6709\u6548\u6570\u636e\u3002 \u7cfb\u7edf\u4f1a\u63d0\u793a\u7528\u6237\u5220\u9664\u683c\u5f0f\u4e0d\u6b63\u786e\u6216\u5b58\u5728\u5176\u4ed6\u9519\u8bef\u7684\u6761\u76ee\u3002 pwck \u8fd4\u56de\u503c\uff1a 0 : success 1 : invalid command syntax 2 : one or more bad password entries 3 : can\u2019t open password files 4 : can\u2019t lock password files 5 : can\u2019t update password files grpck \u547d\u4ee4\u5b9e\u73b0\u9a8c\u8bc1\u7cfb\u7edf\u8ba4\u8bc1\u4fe1\u606f\u7684\u5b8c\u6574\u6027\u3002 \u68c0\u67e5 /etc/group \u548c /etc/gshadow \u4e2d\u7684\u6240\u6709\u6761\u76ee\u6bcf\u4e2a\u5b57\u6bb5\u662f\u5426\u5177\u6709\u6b63\u786e\u7684\u683c\u5f0f\u548c\u6709\u6548\u6570\u636e\u3002 \u7cfb\u7edf\u4f1a\u63d0\u793a\u7528\u6237\u5220\u9664\u683c\u5f0f\u4e0d\u6b63\u786e\u6216\u5b58\u5728\u5176\u4ed6\u9519\u8bef\u7684\u6761\u76ee\u3002 grpck \u8fd4\u56de\u503c\uff1a 0 : success 1 : invalid command syntax 2 : one or more bad group entries 3 : can\u2019t open group files 4 : can\u2019t lock group files 5 : can\u2019t update group files 4.\u7528\u6237\u7ba1\u7406 \u00b6 \u7528\u6237\u7ba1\u7406\u547d\u4ee4\uff1a useradd usermod userdel 4.1.\u521b\u5efa\u7528\u6237 useradd \u00b6 \u4e3e\u4f8b\uff1a # \u666e\u901a\u7528\u6237 $ useradd -m -g wheel -G root -c \"vagrant\" vagrant # \u975e\u4ea4\u4e92\u7528\u6237 $ useradd -r -u 48 -g apache -d /var/www -s /sbin/nologin -g postfix -c \"Apache\" apache 2 >/dev/null useradd \u547d\u4ee4\u7684\u9ed8\u8ba4\u503c\u662f\u5728 /etc/default/useradd \u6587\u4ef6\u4e2d\u8bbe\u5b9a\u3002 openSUSE\u7684 /etc/default/useradd \u6587\u4ef6\u5185\u5bb9\uff1a GROUP = 100 HOME = /home INACTIVE = -1 # \u5bf9\u5e94/etc/shadow\u6587\u4ef6\u7b2c7\u5217\uff0cInactivity period\uff0c\u5bc6\u7801\u8fc7\u671f\u540e\u7684\u5bbd\u9650\u671f\uff0c-1\u8868\u793a\u4e0d\u9650\u5236 EXPIRE = # \u5bf9\u5e94/etc/shadow\u6587\u4ef6\u7b2c8\u5217\uff0cExpiration date since Jan 1, 1970\uff0c\u5373\u8d26\u53f7\u6709\u6548\u671f SHELL = /bin/bash SKEL = /etc/skel # \u7528\u4e8e\u751f\u6210\u7528\u6237\u4e3b\u76ee\u5f55\u7684\u6a21\u7248\u6587\u4ef6 USRSKEL = /usr/etc/skel CREATE_MAIL_SPOOL = yes Rocky\u7684 /etc/default/useradd \u6587\u4ef6\u5185\u5bb9\uff1a GROUP = 100 HOME = /home INACTIVE = -1 EXPIRE = SHELL = /bin/bash SKEL = /etc/skel CREATE_MAIL_SPOOL = yes \u5728Ubuntu\u4e2d /etc/default/useradd \u6587\u4ef6\u53ea\u6709\u4e0b\u9762\u8fd9\u4e00\u884c\u3002 SHELL = /bin/sh 4.1.1.\u6279\u91cf\u521b\u5efa\u7528\u6237 newusers \u00b6 \u683c\u5f0f\uff1a newusers \u3002\u5176\u4e2d\u6587\u4ef6 \u7684\u683c\u5f0f\u5982\u4e0b\uff1a :::::: \u4e3e\u4f8b\uff0c\u521b\u5efa\u6587\u4ef6 users.txt \uff1a $ cat ~/users.txt tester1:123:600:1530: \"Test User1,testuser1@abc.com\" :/home/tester1:/bin/bash tester2:123:601:1529:::/bin/bash tester3:123::::: tester4:123::::/home/tester4:/bin/tsh \u770b\u7ed3\u679c\uff1a $ cat /etc/passwd | grep tester tester1:x:600:1530: \"Test User1,testuser1@abc.com\" :/home/tester1:/bin/bash tester2:x:601:1529:::/bin/bash tester3:x:1001:1001::: tester4:x:1002:1002::/home/tester4:/bin/tsh $ cat /etc/group | grep tester tester1:*:1530: tester2:*:1529: tester3:*:1001: tester4:*:1002: $ sudo cat /etc/shadow | grep tester tester1:!:19321:0:99999:7::: tester2:!:19321:0:99999:7::: tester3:!:19321:0:99999:7::: tester4:!:19321:0:99999:7::: $ ls -ld /home/tester* drwxr-xr-x. 1 tester1 tester1 0 Nov 26 00 :32 /home/tester1 drwxr-xr-x. 1 tester4 tester4 0 Nov 26 00 :32 /home/tester4 4.1.2.\u6279\u91cf\u4fee\u6539\u5bc6\u7801 chpasswd \u00b6 \u4e0d\u540c\u65b9\u6cd5\uff1a echo username:password | chpasswd chpasswd < file.txt # file.txt\u6bcf\u884c\u7684\u683c\u5f0f\u662fusername:password paste -d \":\" user.txt passwd.txt | chpasswd \u53c2\u6570 -e \uff1a\u53e3\u4ee4\u4ee5\u52a0\u5bc6\u7684\u65b9\u5f0f\u4f20\u9012\u3002\u5426\u5219\u53e3\u4ee4\u4ee5\u660e\u6587\u7684\u5f62\u5f0f\u4f20\u9012\u3002 \u6ce8\u610f\uff1a \u7528\u6237\u540dusername\u5fc5\u987b\u662f\u5df2\u5b58\u5728\u7684\u7528\u6237 \u666e\u901a\u7528\u6237\u6ca1\u6709\u4f7f\u7528\u8fd9\u4e2a\u6307\u4ee4\u7684\u6743\u9650 \u5982\u679c\u8f93\u5165\u6587\u4ef6\u662f\u6309\u975e\u52a0\u5bc6\u65b9\u5f0f\u4f20\u9012\u7684\u8bdd\uff0c\u8bf7\u5bf9\u8be5\u6587\u4ef6\u8fdb\u884c\u9002\u5f53\u7684\u52a0\u5bc6\u3002 \u6307\u4ee4\u6587\u4ef6\u4e0d\u80fd\u6709\u7a7a\u884c \u4e3e\u4f8b\uff1a echo tester1:112233 | sudo chpasswd $ cat chpasswd.txt tester1:112233 tester2:33445566 $ sudo chpasswd < chpasswd.txt 4.1.3.\u751f\u6210\u52a0\u5bc6\u5bc6\u7801 openssl passwd \u00b6 \u547d\u4ee4 openssl passwd \u683c\u5f0f\u53ef\u4ee5\u5982\u4e0b\u65b9\u6cd5\u83b7\u5f97\u3002 $ man -f passwd passwd ( 1 ) - change user password passwd ( 1ssl ) - compute password hashes passwd ( 5 ) - password file $ man passwd Man: find all matching manual pages ( set MAN_POSIXLY_CORRECT to avoid this ) * passwd ( 1 ) passwd ( 5 ) passwd ( 1ssl ) Man: What manual page do you want? Man: 1ssl \u4e3e\u4f8b\uff08\u8fd9\u91cc\u7528 \u4ee3\u66ff\u5b9e\u9645\u5bc6\u7801\uff09\uff1a # \u57fa\u4e8e\u7ed9\u5b9a\u5b57\u4e32newpasswd\u751f\u6210sha256\u52a0\u5bc6\u7801\uff0c $ openssl passwd -6 newpasswd # \u521b\u5efa\u65b0\u7528\u6237tester5\uff0c\u8d4b\u4e88\u52a0\u5bc6\u5bc6\u7801 $ useradd -p '' tester1 # \u8bfb\u53d6\u7528\u6237tester5\u7684\u5bc6\u7801\uff0c\u53ef\u4ee5\u9a8c\u8bc1\u662f\u5426\u548c\u4e4b\u524d\u7684\u4e00\u81f4 $ sudo getent shadow tester5 tester5::19321:0:99999:7::: 4.2.\u4fee\u6539\u7528\u6237\u5c5e\u6027 usermod \u00b6 \u6dfb\u52a0\u7528\u6237\u5230\u9644\u52a0\u7ec4 usermod -a -G GROUP USER usermod -a -G GROUP1,GROUP2,GROUP3 USER \u4fee\u6539\u7528\u6237\u4e3b\u7ec4 usermod -a -g GROUP USER \u4fee\u6539\u7528\u6237\u4fe1\u606f usermod -c \"GECOS Comments\" USER \u4fee\u6539\u7528\u6237\u4e3b\u76ee\u5f55\uff0c\u4f7f\u7528\u7edd\u5bf9\u8def\u5f84\uff0c -m \u53c2\u6570\u4f1a\u628a\u539f\u4e3b\u76ee\u5f55\u7684\u5185\u5bb9\u79fb\u52a8\u5230\u65b0\u4e3b\u76ee\u5f55\u3002 usermod -d NEW_HOME_DIR USER usermod -d NEW_HOME_DIR -m USER \u4fee\u6539\u7528\u6237shell usermod -s SHELL USER \u4fee\u6539\u7528\u6237UID usermod -u UID USER \u4fee\u6539\u7528\u6237\u540d\uff08\u4e0d\u5e38\u7528\uff09\uff0c\u540c\u65f6\u4e5f\u9700\u8981\u4fee\u6539\u7528\u6237\u4e3b\u76ee\u5f55\u3002 usermod -l NEW_USER USER \u4fee\u6539\u7528\u6237\u8fc7\u671f\u5c5e\u6027\uff0c\u65e5\u671f\u683c\u5f0f\u662f YYYY-MM-DD usermod -e DATE USER \u5982\u679c\u8bbe\u5b9a\u6c38\u4e0d\u8fc7\u671f\uff0c\u5219\u7f6e\u7a7a\u65e5\u671f\uff1a usermod -e \"\" USER \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684\u8fc7\u671f\u65e5\u671f $ sudo chage -l vagrant Last password change : Oct 30 , 2022 Password expires : never Password inactive : never Account expires : never Minimum number of days between password change : 0 Maximum number of days between password change : 99999 Number of days of warning before password expires : 7 \u9501\u5b9a\u7528\u6237\u3002 \u6b64\u547d\u4ee4\u5c06\u5728\u52a0\u5bc6\u5bc6\u7801\u524d\u63d2\u5165\u4e00\u4e2a\u611f\u53f9\u53f7 (!) \u6807\u8bb0\u3002 \u5f53 /etc/shadow \u6587\u4ef6\u4e2d\u7684\u5bc6\u7801\u5b57\u6bb5\u5305\u542b\u611f\u53f9\u53f7\u65f6\uff0c\u7528\u6237\u5c06\u65e0\u6cd5\u4f7f\u7528\u5bc6\u7801\u9a8c\u8bc1\u767b\u5f55\u7cfb\u7edf\u3002 \u5176\u4ed6\u767b\u5f55\u65b9\u6cd5\u4ecd\u7136\u5141\u8bb8\uff0c\u4f8b\u5982\u57fa\u4e8e\u5bc6\u94a5\u7684\u8eab\u4efd\u9a8c\u8bc1\u6216\u5207\u6362\u5230\u7528\u6237\u3002 \u5982\u679c\u8981\u9501\u5b9a\u8d26\u6237\u5e76\u7981\u7528\u6240\u6709\u767b\u5f55\u65b9\u5f0f\uff0c\u8fd8\u9700\u8981\u5c06\u5230\u671f\u65e5\u671f\u8bbe\u7f6e\u4e3a1\u3002 usermod -L USER usermod -L -e 1 USER \u89e3\u9501\u7528\u6237 usermod -U USER 4.3.\u5220\u9664\u7528\u6237 userdel \u00b6 userdel \u547d\u4ee4\u6267\u884c\u65f6\uff0c\u4f1a\u8bfb\u53d6 /etc/login.defs \u6587\u4ef6\u7684\u5185\u5bb9\u3002 \u6b64\u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u5c5e\u6027\u4f1a\u8986\u76d6 userdel \u7684\u9ed8\u8ba4\u884c\u4e3a\u3002 \u5982\u679c\u5728\u6b64\u6587\u4ef6\u4e2d\u5c06 USERGROUPS_ENAB \u8bbe\u7f6e\u4e3a yes \uff0c userdel \u5c06\u5220\u9664\u4e0e\u7528\u6237\u540c\u540d\u7684\u7ec4\uff0c\u524d\u63d0\u662f\u6ca1\u6709\u5176\u4ed6\u7528\u6237\u662f\u8be5\u7ec4\u7684\u6210\u5458\u3002 userdel \u547d\u4ee4\u4ece /etc/passwd \u548c /etc/shadow \u6587\u4ef6\u4e2d\u5220\u9664\u7528\u6237\u6761\u76ee\u3002 userdel \u547d\u4ee4\u5220\u9664\u7528\u6237\u5e10\u6237\u65f6\uff0c\u4e00\u822c\u4e0d\u4f1a\u5220\u9664\u7528\u6237\u4e3b\u76ee\u5f55\u548c\u90ae\u4ef6\u5047\u8131\u673amail spool\u76ee\u5f55\u3002 \u4f7f\u7528 -r \u9009\u9879\u5f3a\u5236\u5220\u9664\u7528\u6237\u7684\u4e3b\u76ee\u5f55\u548c\u90ae\u4ef6\u5047\u8131\u673a\u76ee\u5f55\u3002 \u5982\u679c\u8981\u5220\u9664\u7684\u7528\u6237\u4ecd\u7136\u5904\u4e8e\u767b\u5f55\u72b6\u6001\uff0c\u6216\u8005\u6709\u5c5e\u4e8e\u8be5\u7528\u6237\u7684\u6b63\u5728\u8fd0\u884c\u7684\u8fdb\u7a0b\uff0c\u5219 userdel \u547d\u4ee4\u4e0d\u5141\u8bb8\u5220\u9664\u8be5\u7528\u6237\u3002 \u4f7f\u7528 -f \u9009\u9879\u5f3a\u5236\u5220\u9664\u7528\u6237\u5e10\u6237\uff0c\u5373\u4f7f\u7528\u6237\u4ecd\u7136\u767b\u5f55\u6216\u6709\u5c5e\u4e8e\u8be5\u7528\u6237\u7684\u6b63\u5728\u8fd0\u884c\u7684\u8fdb\u7a0b\u4e5f\u662f\u5982\u6b64\u3002 userdel USER userdel -r USER 4.4.\u67e5\u770b\u7528\u6237\u4fe1\u606f id \u00b6 \u7c7bUnix\u64cd\u4f5c\u7cfb\u7edf\u4e2d\u7684\u6bcf\u4e2a\u7528\u6237\u90fd\u7531\u4e00\u4e2a\u4e0d\u540c\u7684\u6574\u6570\u6807\u8bc6\uff0c\u8fd9\u4e2a\u552f\u4e00\u7684\u6570\u5b57\u79f0\u4e3aUserID\u3002 \u4e3a\u8fdb\u7a0bprocess\u5b9a\u4e49\u4e86\u4e09\u79cd\u7c7b\u578b\u7684UID\uff0c\u53ef\u4ee5\u6839\u636e\u4efb\u52a1\u7684\u6743\u9650\u52a8\u6001\u66f4\u6539\u3002 \u5b9a\u4e49\u7684\u4e09\u79cd\u4e0d\u540c\u7c7b\u578b\u7684UID\u662f\uff1a \u771f\u5b9e\u7528\u6237ID\uff08Real UserId\uff09\uff1a\u5bf9\u4e8e\u4e00\u4e2a\u8fdb\u7a0b\uff0cReal UserId\u5c31\u662f\u542f\u52a8\u5b83\u7684\u7528\u6237\u7684 UserID\u3002 \u5b83\u5b9a\u4e49\u4e86\u8fd9\u4e2a\u8fdb\u7a0b\u53ef\u4ee5\u8bbf\u95ee\u54ea\u4e9b\u6587\u4ef6\u3002 \u6709\u6548\u7528\u6237\u540d\uff08Effective UserID\uff09\uff1a\u5b83\u901a\u5e38\u4e0e Real UserID \u76f8\u540c\uff0c\u4f46\u6709\u65f6\u4f1a\u66f4\u6539\u4e3a\u4f7f\u975e\u7279\u6743\u7528\u6237\u80fd\u591f\u8bbf\u95ee\u90a3\u4e9b\u53ea\u80fd\u7531\u7279\u6743\u7528\u6237\uff08\u5982 root \uff09\u8bbf\u95ee\u7684\u6587\u4ef6\u3002 \u4fdd\u5b58\u7684\u7528\u6237ID\uff08Saved UserID\uff09 \uff1a\u5f53\u4e00\u4e2a\u4ee5\u63d0\u5347\u7684\u6743\u9650\uff08\u901a\u5e38\u662f root \uff09\u8fd0\u884c\u7684\u8fdb\u7a0b\u9700\u8981\u505a\u4e00\u4e9b\u4f4e\u6743\u9650\u7684\u4efb\u52a1\u65f6\u4f7f\u7528\uff0c\u53ef\u4ee5\u901a\u8fc7\u4e34\u65f6\u5207\u6362\u5230\u975e\u7279\u6743\u5e10\u6237\u6765\u5b9e\u73b0\u3002\u5728\u6267\u884c\u4f4e\u6743\u9650\u4efb\u52a1\u65f6\uff0c\u6709\u6548\u7684 UID \u88ab\u66f4\u6539\u4e3a\u67d0\u4e2a\u8f83\u4f4e\u6743\u9650\u7684\u503c\uff0c\u5e76\u4e14 euid \u88ab\u4fdd\u5b58\u5230\u5df2\u4fdd\u5b58\u7684 userID (suid)\u4e2d\uff0c\u4ee5\u4fbf\u5728\u4efb\u52a1\u5b8c\u6210\u65f6\u7528\u4e8e\u5207\u6362\u56de\u7279\u6743\u5e10\u6237\u3002 \u5728\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u6682\u505c\u5728\u65b0\u5bc6\u7801\u8f93\u5165\u8fd9\u4e00\u6b65\u3002 $ ls -ltr /usr/bin/passwd -rwsr-xr-x. 1 root shadow 65208 May 8 2022 /usr/bin/passwd $ passwd Changing password for vagrant. Current password: New password: \u65b0\u5f00\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\u3002 $ ps -a | grep passwd 3040 pts/0 00 :00:00 passwd $ ps -eo pid,euid,ruid | grep 3040 3040 0 1000 \u4e0a\u9762\u8f93\u51fa\u53ef\u4ee5\u770b\u51fa\uff0c passwd \u8fd9\u4e2a\u8fdb\u7a0b\u7684Effective UserID\u662f 0 \u3002Real UserId\u662f 1000 . id \u547d\u4ee4\u67e5\u770b\u7528\u6237\u6709\u6548\u7684UID\u548cGID\u3002 \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684\u4fe1\u606f\uff1a $ id uid = 1000 ( vagrant ) gid = 478 ( wheel ) groups = 478 ( wheel ) ,0 ( root ) context = unconfined_u:unconfined_r:unconfined_t:s0 \u67e5\u770b\u6307\u5b9a\u7528\u6237\u7684\u4fe1\u606f\uff1a $ id vagrant uid = 1000 ( vagrant ) gid = 478 ( wheel ) groups = 0 ( root ) ,478 ( wheel ) \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684GID\uff1a $ id -g 478 \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684UID\uff1a $ id -u 1000 \u67e5\u770b\u5f53\u524d\u7528\u6237\u6240\u6709\u7ec4\u7684GID\uff1a $ id -G 478 0 \u67e5\u770b\u5f53\u524d\u7528\u6237\u540d\uff1a $ id -un vagrant \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684GID $ id -ur 1000 \u53ea\u6709SELinux\u6fc0\u6d3b\u540e\u624d\u6709 $ id -Z unconfined_u:unconfined_r:unconfined_t:s0 \u7c7b\u4f3c\u4e8e whoami \u547d\u4ee4 $ id -znG wheelroot 4.5.\u5207\u6362\u7528\u6237 su \u00b6 \u547d\u4ee4 su - username \u662f\u767b\u5f55\u5f0f\u5207\u6362\u7528\u6237\u3002\u4f1a\u8bfb\u53d6\u76ee\u6807\u7528\u6237\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5207\u6362\u81f3\u76ee\u6807\u7528\u6237\u7684\u4e3b\u76ee\u5f55\u3002 \u547d\u4ee4 su username \u662f\u975e\u767b\u5f55\u5f0f\u5207\u6362\u7528\u6237\u3002\u4e0d\u8bfb\u53d6\u76ee\u6807\u7528\u6237\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u4e0d\u6539\u53d8\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 \u5207\u6362\u6210root\u7528\u6237\uff0c\u5e76\u4f7f\u7528zsh shell\u3002 su -s /usr/bin/zsh su -s /usr/bin/zsh root \u5207\u6362\u6210tester1\u7528\u6237\uff0c\u4f7f\u7528bash shell su - tester1 -s /bin/bash su - -s /bin/bash tester1 \u4fdd\u7559\u5f53\u524d\u7528\u6237\u73af\u5883\u4e0d\u53d8\u3002 su -p root \u4e0d\u4ea4\u4e92\u5f0f\u5207\u6362\u7528\u6237\uff0c\u53ea\u7528\u76ee\u6807\u7528\u6237\u6267\u884c\u67d0\u4e9b\u547d\u4ee4\u3002 su -c ps su - root -c \"getent passwd\" su - root -s /bin/bash -c \"getent passwd\" root \u7528\u6237\u5207\u6362\u81f3\u5176\u4ed6\u7528\u6237\u4e0d\u9700\u8981\u5bc6\u7801\uff0c\u975e root \u7528\u6237\u5207\u6362\u5176\u4ed6\u7528\u6237\u9700\u8981\u5bc6\u7801\u3002 4.6.\u8bbe\u7f6e\u5bc6\u7801 \u00b6 4.6.1. passwd \u00b6 \u4fee\u6539\u5f53\u524d\u7528\u6237\u81ea\u5df1\u7684\u5bc6\u7801\uff1a passwd \u4fee\u6539\u5176\u4ed6\u7528\u6237\u7684\u5bc6\u7801\uff1a sudo passwd root \u67e5\u770b\u67d0\u4e2a\u7528\u6237\u5bc6\u7801\u72b6\u6001\uff1a $ sudo passwd -S root root P 10 /30/2022 -1 -1 -1 -1 $ sudo passwd -S vagrant vagrant P 10 /30/2022 0 99999 7 -1 \u68c0\u67e5\u5168\u90e8\u7528\u6237\u7684\u5bc6\u7801\u72b6\u6001\uff1a sudo passwd -Sa \u5bc6\u7801\u72b6\u6001\u8bf4\u660e\uff1a Username Status Date Last Changed Minimum Age Maximum Age Warning Period Inactivity Period vagrant P 10 /30/2022 0 99999 7 -1 root P 10 /30/2022 -1 -1 -1 -1 Status\u7684\u63cf\u8ff0\uff1a P : Usable password NP : No password L : Locked password Age\u7684\u4e00\u4e9b\u7279\u6b8a\u503c\uff1a 9999 : Never expires 0 : Can be changed at anytime -1 : Not active \u5f3a\u5236\u8981\u6c42\u7528\u6237\u4e0b\u6b21\u767b\u5f55\u65f6\u4fee\u6539\u5bc6\u7801\uff1a $ sudo passwd -e tester1 $ sudo passwd -S tester1 tester1 P 01 /01/1970 0 99999 7 -1 \u7528\u6237tester1\u7684\u5bc6\u7801\u65e5\u671f\u5df2\u7ecf\u88ab\u6539\u6210 01/01/1970 \u4e86\u3002\u8fd9\u4e2a\u65e5\u671f\u7b97\u662fUnix\u7684\u201c\u7eaa\u5143\uff08epoch\uff09\u201d\u65e5\u671f\uff0c\u610f\u5473\u7740Unix\u7684\u65e5\u671f\u8d77\u70b9\uff0c0\u5929\u3002 \u9501\u5b9a\u67d0\u4e2a\u7528\u6237\uff1a $ sudo passwd -l tester1 $ sudo passwd -S tester1 tester1 L 01 /01/1970 0 99999 7 -1 \u6b64\u65f6\u7528\u6237 tester1 \u7684\u72b6\u6001\u680f\u5df2\u7ecf\u53d8\u6210\u4e86 L \uff0c\u9501\u5b9a\u72b6\u6001\u3002 \u89e3\u9501\u67d0\u4e2a\u7528\u6237\uff1a $ sudo passwd -u tester1 $ sudo passwd -S tester1 tester1 P 01 /01/1970 0 99999 7 -1 \u6b64\u65f6\u7528\u6237 tester1 \u7684\u72b6\u6001\u680f\u5df2\u7ecf\u4ece L \u53d8\u56de\u4e86 P \uff0c\u89e3\u9664\u4e86\u9501\u5b9a\u72b6\u6001\u3002 \u5220\u9664\u7528\u6237\u5bc6\u7801\u3002\u8fd9\u4e2a\u64cd\u4f5c\u614e\u91cd\uff0c\u5bc6\u7801\u5220\u9664\u540e\u8be5\u7528\u6237\u53ef\u4ee5\u4e0d\u9700\u8981\u5bc6\u7801\u5c31\u80fd\u8bbf\u95ee\u7cfb\u7edf\u3002 $ sudo passwd -d tester1 $ sudo passwd -S tester1 tester1 NP 01 /01/1970 0 99999 7 -1 \u6b64\u65f6\u7528\u6237 tester1 \u7684\u72b6\u6001\u680f\u662f NP \u3002 4.6.2. pwgen \u00b6 \u5b89\u88c5\u5305\u3002 mkpasswd\u547d\u4ee4\u6709\u6b67\u4e49\uff0c2\u4e2a\u540c\u540d\u547d\u4ee4\u5b9e\u73b0\u4e0d\u540c\u529f\u80fd\uff0c\u751f\u6210\u968f\u673a\u5bc6\u7801\u5efa\u8bae\u4f7f\u7528 pwgen \u547d\u4ee4\u3002Rocky9\u6ca1\u6709\u627e\u5230pwgen\u5305\u3002 sudo zypper in pwgen sudo apt install pwgen \u968f\u673a\u751f\u6210\u957f\u5ea68\u4f4d\u5b89\u5168\u5bc6\u7801\u3002 pwgen -s -1 \u968f\u673a\u751f\u6210\u957f\u5ea614\u4f4d\u5b89\u5168\u5bc6\u7801\u3002 pwgen -s -1 14 \u968f\u673a\u751f\u62102\u4e2a\u957f\u5ea615\u4f4d\u5b89\u5168\u5bc6\u7801\u3002 pwgen -s -1 15 2 \u968f\u673a\u751f\u62105\u4e2a\u5bc6\u7801\uff0c\u957f\u5ea610\u4f4d\uff0c\u6bcf\u4e2a\u5bc6\u7801\u81f3\u5c11\u542b\u4e00\u4e2a\u7279\u6b8a\u5b57\u7b26\uff0c\u7ed3\u679c\u4ee5\u5217\u5f62\u5f0f\u8f93\u51fa\u3002 pwgen -s -1 -y 10 5 \u751f\u6210\u957f\u5ea68\uff0c\u542b\u6709\u6570\u5b57\uff0c\u542b\u6709\u5927\u5c0f\u5199\u5b57\u6bcd\u7684\u5bc6\u78014\u4e2a\uff0c\u5217\u6253\u5370 pwgen -s -n -c -C -1 8 4 \u751f\u6210\u957f\u5ea68\uff0c\u4e0d\u542b\u6570\u5b57\uff0c\u53ea\u542b\u5c0f\u5199\u5b57\u6bcd\uff0c\u5217\u6253\u5370 pwgen -s -c -A -0 -1 8 4 \u751f\u6210\u957f\u5ea616\uff0c\u542b\u6709\u6570\u5b57\uff0c\u542b\u6709\u5927\u5c0f\u5199\u5b57\u6bcd\uff0c\u542b\u6709\u7279\u6b8a\u5b57\u7b26\u7684\u5bc6\u78013\u4e2a\uff0c\u884c\u6253\u5370 pwgen -s -n -c -y -1 16 3 \u751f\u6210\u957f\u5ea680\uff0c\u4e0d\u542b\u5143\u97f3\u548c\u6570\u5b57\uff0c\u81f3\u5c11\u542b\u6709\u4e00\u4e2a\u5927\u5199\u5b57\u6bcd\uff0c\u884c\u6253\u5370 pwgen -s -v -c -0 80 1 4.6.3.\u975e\u4ea4\u4e92\u5f0f\u8bbe\u7f6e\u5bc6\u7801 \u00b6 \u65b9\u6cd51\uff1a $ echo -e '123456\\n123456' | sudo passwd tester1 New password: BAD PASSWORD: it is too simplistic/systematic BAD PASSWORD: is too simple Retype new password: passwd: password updated successfully \u65b9\u6cd52\uff1a Rocky\u4e2d\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u65b9\u6cd5\u3002 pwgen -ncy1 16 1 | tee passwd.txt | sudo passwd --stdin tester1 openSUSE\u548cUbuntu\u53ef\u4ee5\u7528\u4e0b\u9762\u65b9\u6cd5\u3002 echo \"tester1:\" ` pwgen -ncy1 16 1 ` | tee passwd.txt | sudo chpasswd \u65b9\u6cd53\uff1a\u6839\u636e\u9884\u5148\u7ed9\u5b9a\u7684\u7528\u6237\u5217\u8868\uff0c\u6279\u91cf\u751f\u6210\u5bc6\u7801\u3002 $ cat > user-list.txt < user.txt < file 67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov 1 11 :20 symlinkfile1-1 -> symlinkfile1 67274682 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file 33555262 drwxr-xr-x. 2 vagrant wheel 6 Nov 1 11 :30 typelink \u4ee5 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11:14 file \u4e3a\u4f8b\uff1a 67274680 : inode \u7d22\u5f15\u8282\u70b9\u7f16\u53f7\u3002 -rw-r--r-- \uff1a\u6587\u4ef6\u7c7b\u578b\u53ca\u6743\u9650 - \uff1a\u6587\u4ef6\u7c7b\u578b\uff0c\u4f8b\u5b50\u4e2d\u51fa\u73b0\u4e86\u4e09\u79cd\uff0c - \uff0c l \u548c d \u3002 - \uff1a\u666e\u901a\u6587\u4ef6 d \uff1a\u76ee\u5f55 l \uff1a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\uff08link\uff09 b \uff1a\u5757\u8bbe\u5907\uff08block\uff09 c \uff1a\u5b57\u7b26\u8bbe\u5907\uff08character\uff09 p \uff1a\u7ba1\u9053\u6587\u4ef6\uff08pipe\uff09 s \uff1a\u5957\u63a5\u5b57\u6587\u4ef6\uff08socket\uff09 rw-r--r-- \uff1a\u6587\u4ef6\u6743\u9650\uff0c\u4ece\u5de6\u5230\u53f3\u4f9d\u6b21\u4e3a\uff1a\uff08\u7528\u6237\u7684\u6700\u7ec8\u6743\u9650\uff0c\u662f\u4ece\u5de6\u5411\u53f3\u5339\u914d\uff0c\u4e00\u65e6\u5339\u914d\u5219\u6743\u9650\u7acb\u5373\u751f\u6548\uff0c\u4e0d\u518d\u5411\u53f3\u7ee7\u7eed\u5339\u914d\uff09 rw- \uff1a\u6587\u4ef6\u5c5e\u4e3b\u6743\u9650\uff08u\uff09\uff0c\u4f8b\u5b50\u4e2d\u662f vagrant \u3002 r-- \uff1a\u6587\u4ef6\u5c5e\u7ec4\u7684\u6743\u9650\uff08g\uff09\uff0c\u4f8b\u5b50\u4e2d\u662f wheel \u3002 r-- \uff1a\u5176\u4ed6\u7ec4\u7684\u6743\u9650\uff08o\uff09\u3002 . \uff1a\u8fd9\u4e2a\u70b9\u8868\u793a\u6587\u4ef6\u5e26\u6709SELinux\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\uff08SELinux Contexts\uff09\u3002\u5173\u95edSELinux\uff0c\u65b0\u521b\u5efa\u7684\u6587\u4ef6\u5c31\u4e0d\u4f1a\u518d\u6709\u8fd9\u4e2a\u70b9\u4e86\u3002\u4f46\u662f\uff0c\u4ee5\u524d\u521b\u5efa\u7684\u6587\u4ef6\u672c\u6765\u6709\u8fd9\u4e2a\u70b9\u7684\u8fd8\u4f1a\u663e\u793a\u8fd9\u4e2a\u70b9\uff08\u867d\u7136SELinux\u4e0d\u8d77\u4f5c\u7528\u4e86\uff09\u3002 3 \uff1a\u786c\u94fe\u63a5\u6570\uff0c\u4f8b\u5b50\u4e2d file \u548c hardlinkfile1 \u548c hardlinkfile2 \u4e4b\u95f4\u662f\u786c\u94fe\u63a5\uff0c\u6240\u4ee5\u8fd9\u4e09\u4e2a\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u90fd\u662f 3 \u3002 vagrant \uff1a\u6587\u4ef6\u5c5e\u4e3bowner wheel \uff1a\u6587\u4ef6\u5c5e\u7ec4group 31 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u5927\u5c0f Nov 1 11:14 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u521b\u5efa\u65e5\u671f\u548c\u65f6\u95f4 file \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u540d\u79f0 \u4e0b\u9762\u662f\u547d\u4ee4 ls -ihl \u5728openSUSE\u548cUbuntu\u4e0a\u7684\u663e\u793a\u7ed3\u679c\u3002 $ ls -ihl 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 file 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile1 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile2 233648 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile1 -> file 233650 lrwxrwxrwx 1 vagrant wheel 12 Nov 1 15 :52 symlinkfile1-1 -> symlinkfile1 233649 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile2 -> file 233646 drwxr-xr-x 1 vagrant wheel 0 Nov 1 15 :51 typelink 7.1.\u4fee\u6539\u5c5e\u4e3b chown \u00b6 chown \u547d\u4ee4\u4fee\u6539\u6587\u4ef6\u5c5e\u4e3b\uff08\u6240\u6709\u8005\uff0cowner\uff09\u3002 \u4fee\u6539\u6587\u4ef6\u5c5e\u4e3b\u4e3aroot\u3002 $ ll f1.txt -rw-r--r--. 1 vagrant wheel 41 Nov 14 22 :23 f1.txt $ sudo chown root f1.txt $ ll f1.txt -rw-r--r--. 1 root wheel 41 Nov 14 22 :23 f1.txt \u4fee\u6539\u6587\u4ef6\u7684\u5c5e\u7ec4\u4e3abin\u3002 $ sudo chown :bin f1.txt $ ll f1.txt -rw-r--r--. 1 root bin 41 Nov 14 22 :23 f1.txt \u540c\u65f6\u4fee\u6539\u6587\u4ef6\u7684\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u3002 $ sudo chown vagrant.wheel f1.txt $ ll f1.txt -rw-r--r--. 1 vagrant wheel 41 Nov 14 22 :23 f1.txt \u53c2\u7167\u67d0\u6587\u4ef6\u4fee\u6539\u53e6\u4e00\u6587\u4ef6\u7684\u5c5e\u6027\u3002 $ ll file.py -rw-r--r--. 1 vagrant wheel 56 Nov 13 22 :50 file.py $ ll user.txt -rw-r--r--. 1 root bin 21 Nov 27 23 :59 user.txt $ sudo chown root.bin user.txt $ sudo chown --reference = user.txt file.py $ ll file.py -rw-r--r--. 1 root bin 56 Nov 13 22 :50 file.py \u9012\u5f52\u4fee\u6539\u6240\u6709\u5b50\u76ee\u5f55\u53ca\u6587\u4ef6\u7684\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u3002 sudo chown -R vagrant.wheel ~ 7.2.\u4fee\u6539\u5c5e\u7ec4 chgrp \u00b6 \u4fee\u6539\u76ee\u5f55\u7684\u5c5e\u7ec4\u3002 sudo chgrp bin ~~ \u4fee\u6539\u76ee\u5f55\u53ca\u5b50\u76ee\u5f55\u53ca\u6587\u4ef6\u7684\u5c5e\u7ec4\u3002 sudo chgrp -R bin ~~ 7.3.\u6587\u4ef6\u548c\u76ee\u5f55\u6743\u9650 \u00b6 \u6587\u4ef6\uff1a r \uff1a\u53ef\u4ee5\u8bfb\u53d6\u8be5\u6587\u4ef6\u5185\u5bb9\uff0c\u6bd4\u5982\u901a\u8fc7 cat \u547d\u4ee4\u3002 w \uff1a\u53ef\u4ee5\u4fee\u6539\u8be5\u6587\u4ef6\u5185\u5bb9\uff0c\u53ef\u4ee5\u53ea\u6709 w \u800c\u6ca1\u6709 r \u3002 x \uff1a\u53ef\u4ee5\u628a\u8be5\u6587\u4ef6\u63d0\u8bf7\u5185\u6838\u542f\u52a8\u4e3a\u4e00\u4e2a\u8fdb\u7a0b\uff0c\u5373\u53ef\u4ee5\u6267\u884c\u8be5\u6587\u4ef6\uff08\u8be5\u6587\u4ef6\u7684\u5185\u5bb9\u5fc5\u987b\u662f\u53ef\u4ee5\u6267\u884c\uff09\u3002 \u76ee\u5f55\uff1a\uff08\u5bf9\u76ee\u5f55\u800c\u8a00\uff0c\u901a\u5e38\u9700\u8981\u7ed9 r \u548c x \u6743\u9650\uff09\uff08\u4ece\u76ee\u5f55\u89d2\u5ea6\u770b\uff0c\u76ee\u5f55\u5185\u6587\u4ef6\u5217\u8868\u7b49\u4e8e\u76ee\u5f55\u8282\u70b9\u7684\u5185\u5bb9\uff09 r \uff1a\u80fd\u770b\u6587\u4ef6\u5217\u8868\uff0c\u4f46\u4e0d\u80fd\u8bbf\u95ee\u6240\u542b\u6587\u4ef6\u7684\u5185\u5bb9\u53ca\u5176\u5c5e\u6027\u4fe1\u606f\uff0c\u5305\u62ecinode\u53f7\u3002 w \uff1a\u80fd\u5728\u8be5\u76ee\u5f55\u5185\u521b\u5efa\u548c\u5220\u9664\u6587\u4ef6\uff0c\u4e0d\u7531\u76ee\u5f55\u5185\u6587\u4ef6\u672c\u8eab\u7684\u6743\u9650\u51b3\u5b9a\u3002 x \uff1a\u80fdcd\u8fdb\u76ee\u5f55\uff0c\u80fd\u901a\u8fc7 ls -l file \u548c stat file \u67e5\u770b\u8be5\u76ee\u5f55\u4e2d\u5236\u5b9a\u6587\u4ef6\u7684\u5143\u6570\u636e\u3002 X \uff1a\u8868\u793a\u53ea\u6709\u5f53\u8be5\u6587\u4ef6\u662f\u4e2a\u5b50\u76ee\u5f55\u6216\u8005\u8be5\u6587\u4ef6\u5df2\u7ecf\u88ab\u8bbe\u5b9a\u8fc7\u4e3a\u53ef\u6267\u884c\u3002 \u6709\u53ea\u8bfb\u6743\u9650\u7684\u7528\u6237\u4e0d\u80fd\u7528cd\u8fdb\u5165\u8be5\u76ee\u5f55\uff0c\u8fd8\u5fc5\u987b\u6709\u6267\u884c\u6743\u9650\u624d\u80fd\u8fdb\u5165\u3002 \u6709\u6267\u884c\u6743\u9650\u7684\u7528\u6237\u53ea\u6709\u5728\u77e5\u9053\u6587\u4ef6\u540d\uff0c\u5e76\u62e5\u6709\u8bfb\u6743\u5229\u7684\u60c5\u51b5\u4e0b\u624d\u53ef\u4ee5\u8bbf\u95ee\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u3002 \u5fc5\u987b\u6709\u8bfb\u548c\u6267\u884c\u6743\u9650\u624d\u53ef\u4ee5ls\u5217\u51fa\u76ee\u5f55\u6e05\u5355\uff0c\u6216\u4f7f\u7528cd\u547d\u4ee4\u8fdb\u5165\u76ee\u5f55\u3002 \u6709\u76ee\u5f55\u7684\u5199\u6743\u9650\uff0c\u53ef\u4ee5\u521b\u5efa\u3001\u5220\u9664\u6216\u4fee\u6539\u76ee\u5f55\u4e0b\u7684\u4efb\u4f55\u6587\u4ef6\u6216\u5b50\u76ee\u5f55\uff0c\u5373\u4f7f\u4f7f\u8be5\u6587\u4ef6\u6216\u5b50\u76ee\u5f55\u5c5e\u4e8e\u5176\u4ed6\u7528\u6237\u4e5f\u662f\u5982\u6b64\u3002 \u5e38\u7528\u6743\u9650\u4f8b\u5b50\uff1a -rw------- ( 600 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\u548c\u5199\u7684\u6743\u9650 -rw-r--r-- ( 644 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\u548c\u5199\u7684\u6743\u9650\uff0c\u7ec4\u548c\u5176\u4ed6\u4eba\u53ea\u6709\u8bfb\u7684\u6743\u9650 -rwx------ ( 700 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\uff0c\u5199\uff0c\u6267\u884c\u7684\u6743\u9650 -rwxr-xr-x ( 755 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\uff0c\u5199\uff0c\u6267\u884c\u7684\u6743\u9650\uff0c\u7ec4\u548c\u5176\u4ed6\u4eba\u53ea\u6709\u8bfb\u548c\u6267\u884c\u7684\u6743\u9650 -rwx--x--x ( 711 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\uff0c\u5199\uff0c\u6267\u884c\u7684\u6743\u9650\uff0c\u7ec4\u548c\u5176\u4ed6\u4eba\u53ea\u6709\u6267\u884c\u7684\u6743\u9650 -rw-rw-rw- ( 666 ) \u6bcf\u4e2a\u4eba\u90fd\u6709\u8bfb\u5199\u7684\u6743\u9650 -rwxrwxrwx ( 777 ) \u6bcf\u4e2a\u4eba\u90fd\u6709\u8bfb\u5199\u548c\u6267\u884c\u7684\u6743\u9650 7.4.\u6743\u9650\u4fee\u6539 chmod \u00b6 \u547d\u4ee4\u683c\u5f0f\uff1a chmod [ -cfvR ] [ --help ] [ --version ] mode file mode \u5b57\u4e32\u683c\u5f0f\u4e3a\uff1a [ ugoa ][ +- =][ rwxXst ] who: u \u6587\u4ef6\u6240\u6709\u8005 g \u6587\u4ef6\u6240\u6709\u8005\u6240\u5728\u7ec4 o \u5176\u4ed6\u7528\u6237 a \u6240\u6709\u7528\u6237\uff0c\u76f8\u5f53\u4e8e ugo operator: + \u4e3a\u6307\u5b9a\u7684\u7528\u6237\u7c7b\u578b\u589e\u52a0\u6743\u9650 - \u53bb\u9664\u6307\u5b9a\u7528\u6237\u7c7b\u578b\u7684\u6743\u9650 = \u8bbe\u7f6e\u6307\u5b9a\u7528\u6237\u6743\u9650\u7684\u8bbe\u7f6e\uff0c\u5373\u5c06\u7528\u6237\u7c7b\u578b\u7684\u6240\u6709\u6743\u9650\u91cd\u65b0\u8bbe\u7f6e permission: r \u8bbe\u7f6e\u4e3a\u53ef\u8bfb\u6743\u9650 w \u8bbe\u7f6e\u4e3a\u53ef\u5199\u6743\u9650 x \u8bbe\u7f6e\u4e3a\u53ef\u6267\u884c\u6743\u9650 X \u7279\u6b8a\u6267\u884c\u6743\u9650\uff0c\u53ea\u6709\u5f53\u6587\u4ef6\u4e3a\u76ee\u5f55\u6587\u4ef6\uff0c\u6216\u8005\u5176\u4ed6\u7c7b\u578b\u7684\u7528\u6237\u6709\u53ef\u6267\u884c\u6743\u9650\u65f6\uff0c\u624d\u5c06\u6587\u4ef6\u6743\u9650\u8bbe\u7f6e\u53ef\u6267\u884c s \u5f53\u6587\u4ef6\u88ab\u6267\u884c\u65f6\uff0c\u6839\u636ewho\u53c2\u6570\u6307\u5b9a\u7684\u7528\u6237\u7c7b\u578b\u8bbe\u7f6e\u6587\u4ef6\u7684 setuid \u6216\u8005 setgid \u6743\u9650 t \u8bbe\u7f6e\u7c98\u8d34\u4f4d\uff0c\u53ea\u6709\u8d85\u7ea7\u7528\u6237\u53ef\u4ee5\u8bbe\u7f6e\u8be5\u4f4d\uff0c\u53ea\u6709\u6587\u4ef6\u6240\u6709\u8005u\u53ef\u4ee5\u4f7f\u7528\u8be5\u4f4d\u3002 \u793a\u4f8b\uff1a \u5c06\u6587\u4ef6 file1.txt \u8bbe\u4e3a\u6240\u6709\u4eba\u7686\u53ef\u8bfb\u53d6\u3002 chmod ugo+r file1.txt \u5c06\u6587\u4ef6 file1.txt \u8bbe\u4e3a\u6240\u6709\u4eba\u7686\u53ef\u8bfb\u53d6\u3002 chmod a+r file1.txt \u5c06\u6587\u4ef6 file1.txt \u4e0e file2.txt \u8bbe\u4e3a\u8be5\u6587\u4ef6\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u90fd\u53ef\u5199\u5165\uff0c\u4f46\u5176\u4ed6\u7528\u6237\u4e0d\u53ef\u5199\u5165\u3002 chmod ug+w,o-w file1.txt file2.txt \u4e3a ex1.py \u6587\u4ef6\u5c5e\u4e3b\u589e\u52a0\u53ef\u6267\u884c\u6743\u9650\u3002 chmod u+x ex1.py \u5c06\u76ee\u524d\u76ee\u5f55\u4e0b\u7684\u6240\u6709\u6587\u4ef6\u4e0e\u5b50\u76ee\u5f55\u7686\u8bbe\u4e3a\u4efb\u4f55\u4eba\u53ef\u8bfb\u53d6\u3002 chmod -R a+r * \u7ed9 file \u7684\u6240\u6709\u7528\u6237\u589e\u52a0\u8bfb\u6743\u9650 chmod a+r file \u5220\u9664 file \u7684\u6240\u6709\u7528\u6237\u7684\u6267\u884c\u6743\u9650 chmod a-x file \u7ed9 file \u7684\u6240\u6709\u7528\u6237\u589e\u52a0\u8bfb\u5199\u6743\u9650 chmod a+rw file \u7ed9 file \u7684\u6240\u6709\u7528\u6237\u589e\u52a0\u8bfb\u5199\u6267\u884c\u6743\u9650 chmod +rwx file \u5bf9 file \u7684\u5c5e\u4e3b\u8bbe\u7f6e\u8bfb\u5199\u6743\u9650\uff0c\u6e05\u7a7a\u5c5e\u7ec4\u548c\u5176\u4ed6\u7528\u6237\u5bf9 file \u7684\u6240\u6709\u6743\u9650\uff08\u7a7a\u683c\u4ee3\u8868\u65e0\u6743\u9650\uff09 chmod u = rw,go = file \u5bf9\u76ee\u5f55 docs \u548c\u5176\u5b50\u76ee\u5f55\u4e2d\u7684\u6240\u6709\u6587\u4ef6\u7ed9\u5c5e\u4e3b\u589e\u52a0\u8bfb\u6743\u9650\uff0c\u800c\u5bf9\u5c5e\u7ec4\u548c\u5176\u4ed6\u7528\u6237\u5220\u9664\u8bfb\u6743\u9650 chmod -R u+r,go-r docs \u5bf9 file \u7684\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u8bbe\u7f6e\u8bfb\u5199\u6743\u9650, \u4e3a\u5176\u4ed6\u7528\u6237\u8bbe\u7f6e\u8bfb\u6743\u9650 chmod 664 file \u5bf9 file \u7684\u5c5e\u4e3b\u8bbe\u7f6e\u8bfb\u5199\u6267\u884c\u6743\u9650\uff0c\u76f8\u5f53\u4e8e u=rwx (4+2+1)\uff0c\u8bbe\u7f6e\u5c5e\u7ec4\u8bfb\u548c\u6267\u884c\u6743\u9650\uff0c\u76f8\u5f53\u4e8e go=rx (4+1 & 4+1)\u3002 0 \u6ca1\u6709\u7279\u6b8a\u6a21\u5f0f chmod 0755 file 4 \u8bbe\u7f6e\u4e86\u8bbe\u7f6e\u7528\u6237ID\u4f4d\uff0c\u5269\u4e0b\u7684\u76f8\u5f53\u4e8e u=rwx (4+2+1)\u548c go=rx (4+1 & 4+1)\u3002 chmod 4755 file \u5220\u9664\u53ef\u6267\u884c\u6743\u9650\u5bf9 path/ \u4ee5\u53ca\u5176\u6240\u6709\u7684\u76ee\u5f55\uff08\u4e0d\u5305\u62ec\u6587\u4ef6\uff09\u7684\u6240\u6709\u7528\u6237\uff0c\u4f7f\u7528 -type f \u5339\u914d\u6587\u4ef6 find path/ -type d -exec chmod a-x {} \\; \u5141\u8bb8\u6240\u6709\u7528\u6237\u6d4f\u89c8\u6216\u901a\u8fc7\u76ee\u5f55 path/ find path/ -type d -exec chmod a+x {} \\; 7.5.\u9ed8\u8ba4\u6743\u9650 umask \u00b6 umask \u7684\u503c\uff0c\u5b9a\u4e49\u4e86\u6240\u6709\u65b0\u5efa\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u7684\u521d\u59cb\u6743\u9650\u7684\u3002 \u67e5\u770b\u5f53\u524d\u6743\u9650\u63a9\u7801\uff1a $ umask 0022 \u5728\u4e0d\u8003\u8651 umask \u7684\u60c5\u51b5\u4e0b\uff0c\u6587\u4ef6\u7684\u9ed8\u8ba4\u6743\u9650\u662f 666 (rw-rw-rw-)\uff0c\u76ee\u5f55\u7684\u9ed8\u8ba4\u6743\u9650\u662f 777 (rwxrwxrwx)\u3002 \u5728 umask \u7684\u503c\u4e3a 0022 \u7684\u60c5\u51b5\u4e0b\uff0c\u6587\u4ef6\u7684\u9ed8\u8ba4\u6743\u9650\u662f 644 (rw-r--r--)\uff0c\u76ee\u5f55\u7684\u9ed8\u8ba4\u6743\u9650\u662f 755 (rwxr-xr-x)\u3002 \u8ba1\u7b97\u65b9\u6cd5\uff1a Files: ( Default ) 6 6 6 ( umask ) 0 2 2 ---------------- ( Result ) 6 4 4 Directories: ( Default ) 7 7 7 ( umask ) 0 2 2 ---------------- ( Result ) 7 5 5 \u5982\u679c umask \u7684\u503c\u4e3a 0077 \u7684\u60c5\u51b5\u4e0b\uff0c\u6587\u4ef6\u7684\u9ed8\u8ba4\u6743\u9650\u662f 600 (rw-------)\uff0c\u76ee\u5f55\u7684\u9ed8\u8ba4\u6743\u9650\u662f 700 (rwx------)\u3002 \u8ba1\u7b97\u65b9\u6cd5\uff1a Files: ( Default ) 6 6 6 ( umask ) 0 7 7 ---------------- ( Result ) 6 0 0 Directories: ( Default ) 7 7 7 ( umask ) 0 7 7 ---------------- ( Result ) 7 0 0 \u4e3e\u4f8b\uff1a $ umask 022 $ touch file2 $ ll file2 -rw-r--r--. 1 vagrant wheel 0 Nov 28 23 :13 file2 $ umask 077 $ touch file1 $ ll file1 -rw-------. 1 vagrant wheel 0 Nov 28 23 :12 file1 $ umask 022 $ mkdir ./tmp1 $ umask 077 $ mkdir ./tmp2 $ ls -dl tmp* drwxr-xr-x. 1 vagrant wheel 0 Nov 28 23 :14 tmp1 drwx------. 1 vagrant wheel 0 Nov 28 23 :14 tmp2 7.6.\u7279\u6b8a\u6743\u9650 \u00b6 \u9664\u4e86\u4e09\u79cd\u5e38\u89c1\u7684\u6743\u9650rwx\uff0c\u8fd8\u6709\u4e09\u79cd\u7279\u6b8a\u6743\u9650\uff1aSUID\uff0cSGID\uff0cSticky\u3002 SUID\uff1a\u5c5e\u4e3bs\u6743\u9650\uff0c\u79f0\u4e3aSet UID \u524d\u63d0\uff1a\u8fdb\u7a0b\u6709\u5c5e\u4e3b\u548c\u5c5e\u7ec4\uff0c\u6587\u4ef6\u6709\u5c5e\u4e3b\u548c\u5c5e\u7ec4 \u4efb\u4f55\u53ef\u6267\u884c\u7a0b\u5e8f\u6587\u4ef6\u80fd\u4e0d\u80fd\u542f\u52a8\u4e3a\u8fdb\u7a0b\uff0c\u53d6\u51b3\u4e8e\u53d1\u8d77\u8005\u5bf9\u7a0b\u5e8f\u6587\u4ef6\u662f\u5426\u62e5\u6709\u6267\u884c\u6743\u9650\u3002 \u542f\u52a8\u4e3a\u8fdb\u7a0b\u4e4b\u540e\uff0c\u5176\u8fdb\u7a0b\u7684\u5c5e\u4e3b\u4e3a\u53d1\u8d77\u8005\u3002 \u8fdb\u7a0b\u8bbf\u95ee\u6587\u4ef6\u662f\u7684\u6743\u9650\uff0c\u53d6\u51b3\u4e8e\u8fdb\u7a0b\u7684\u53d1\u8d77\u8005\u3002 \u53ea\u5bf9\u4e8c\u8fdb\u5236\u53ef\u6267\u884c\u7a0b\u5e8f\u6587\u4ef6\u6709\u6548\u3002\u5f53\u6267\u884c\u8be5\u6587\u4ef6\u65f6\uff0c\u53d1\u8d77\u8005\u5c06\u81ea\u52a8\u5177\u6709\u8be5\u6587\u4ef6\u6240\u6709\u8005\u7684\u6743\u9650\u3002 \u5bf9\u76ee\u5f55\u65e0\u6548\u3002 $ ll file1 -rw-------. 1 vagrant wheel 0 Nov 28 23 :12 file1 $ sudo chmod u+s file1 $ ll file1 -rwS------. 1 vagrant wheel 0 Nov 28 23 :12 file1 \u5982\u679c\u5c5e\u4e3b\u7684 x \u4f4d\u4e0a\u662f-\uff0c\u5219\u5728\u5c5e\u4e3b\u7684 x \u4f4d\u4e0a\u6807\u8bb0\u5927\u5199 S \uff0c\u5426\u5219\u6807\u8bb0\u5c0f\u5199 s \u3002\u5982\u4e0b\uff1a $ chmod 777 file1 $ ll file1 -rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23 :12 file1 $ sudo chmod u+s file1 $ ll file1 -rwsrwxrwx. 1 vagrant wheel 0 Nov 28 23 :12 file1 \u4e0b\u97622\u7ec4\u547d\u4ee4\u5b9e\u73b0\u540c\u6837\u6548\u679c\u3002 sudo chmod 4xxx file1 chmod 777 file1 sudo chmod u+s file1 \u53d6\u6d88SUID\u3002 sudo chmod u-s file1 SGID\uff1a\u5c5e\u7ec4s\u6743\u9650\uff0c\u79f0\u4e3aSet GID \u5982\u679c\u4f5c\u7528\u4e8e\u4e8c\u8fdb\u5236\u53ef\u6267\u884c\u6587\u4ef6\u4e0a\uff0c\u5f53\u6267\u884c\u8be5\u6587\u4ef6\u4e3a\u8fdb\u7a0b\u4e4b\u540e\uff0c\u53d1\u8d77\u8005\u5c06\u81ea\u52a8\u5177\u6709\u8be5\u6587\u4ef6\u6240\u5c5e\u7ec4\u7684\u6743\u9650\uff0c\u8fdb\u7a0b\u7684\u5c5e\u7ec4\u4e3a\u53d1\u8d77\u8005\u7684\u5c5e\u7ec4\u3002 \u5982\u679c\u4f5c\u7528\u4e8e\u76ee\u5f55\u4e0a\uff0c\u5219\u8be5\u76ee\u5f55\u4e0b\u65b0\u5efa\u7acb\u7684\u76ee\u5f55\u548c\u6587\u4ef6\u90fd\u81ea\u52a8\u4ece\u6b64\u76ee\u5f55\u7ee7\u627f\u3002 $ sudo chmod g+s file2 $ ll file2 -rw-r-Sr--. 1 vagrant wheel 0 Nov 28 23 :13 file2 \u5982\u679c\u5c5e\u7ec4\u7684 x \u4f4d\u4e0a\u662f-\uff0c\u5219\u5728\u5c5e\u7ec4\u7684 x \u4f4d\u4e0a\u6807\u8bb0\u5927\u5199 S \uff0c\u5426\u5219\u6807\u8bb0\u5c0f\u5199 s \u3002\u5982\u4e0b\uff1a $ chmod 777 file2 $ ll file2 -rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23 :13 file2 $ sudo chmod g+s file2 $ ll file2 -rwxrwsrwx. 1 vagrant wheel 0 Nov 28 23 :13 file2 \u4e0b\u97622\u7ec4\u547d\u4ee4\u5b9e\u73b0\u540c\u6837\u6548\u679c\u3002 sudo chmod 2xxx file2 chmod 777 file2 sudo chmod g+s file2 \u53d6\u6d88SGID\u3002 sudo chmod g-s file2 \u5bf9\u4e8e\u76ee\u5f55\uff0c\u4e0b\u9762\u6f14\u793a\u53ef\u4ee5\u770b\u5230\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\u7684\u7ee7\u627f\u6027\u3002 $ ll -d data drwxr-xr-x. 1 vagrant bin 0 Nov 28 20 :55 data $ sudo chmod g+s .~ $ ll -d data drwxr-sr-x. 1 vagrant bin 0 Nov 28 20 :55 data $ cd data $ touch file2 $ ll file2 -rw-r--r--. 1 vagrant bin 0 Nov 29 21 :10 file2 $ mkdir tmp3 $ ll -d tmp3 drwxr-sr-x. 1 vagrant bin 0 Nov 29 21 :10 tmp3 Sticky Bit\uff1a\u7b80\u79f0\u4e3aSBIT\u6743\u9650 \u53ea\u9488\u5bf9\u76ee\u5f55\u6709\u6548\u3002\u5b83\u8868\u793a\u53ea\u80fd\u8ba9\u5176\u5c5e\u4e3b\u4ee5\u53caroot\u53ef\u4ee5\u5220\u9664\u3001\u91cd\u547d\u540d\u3001\u79fb\u52a8\u8be5\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u3002 Sticky\u8bbe\u7f6e\u5728\u6587\u4ef6\u4e0a\u65e0\u610f\u4e49\u3002 \u5982\u679c\u5176\u4ed6\u7684 x \u4f4d\u4e0a\u662f-\uff0c\u5219\u5728\u5176\u4ed6\u7684 x \u4f4d\u4e0a\u6807\u8bb0\u5927\u5199 T \uff0c\u5426\u5219\u6807\u8bb0\u5c0f\u5199 t \u3002 $ ll -d .~ drwxr-sr-x. 1 vagrant bin 18 Nov 29 21 :10 .~ $ sudo chmod o+t .~ $ ll -d .~ drwxr-sr-t. 1 vagrant bin 18 Nov 29 21 :10 .~ $ cd data $ touch file1 $ mkdir tmp1 $ ll file1 -rw-r--r--. 1 vagrant bin 0 Nov 29 21 :37 file1 $ ll -d tmp1 drwxr-sr-x. 1 vagrant bin 0 Nov 29 21 :37 tmp1 \u7279\u6b8a\u6743\u9650\u8bbe\u7f6e\u6570\u5b57\u6cd5\uff1a \u8bbe\u7f6eSUID User Group Others r w s r w s r w x r w S BIN 100 1 1 1 1 1 1 1 1 1 1 1 0 OCT 4 7 7 7 6 \u8bbe\u7f6eSGID User Group Others r w x r w s r w x r w S BIN 010 1 1 1 1 1 1 1 1 1 1 1 0 OCT 2 7 7 7 6 \u8bbe\u7f6eSticky Bit - SBIT User Group Others r w x r w x r w t r w T BIN 001 1 1 1 1 1 1 1 1 1 1 1 0 OCT 1 7 7 7 6 7.7.\u8bbe\u5b9a\u6587\u4ef6\u7279\u6b8a\u5c5e\u6027 chattr \u00b6 \u547d\u4ee4\u683c\u5f0f\uff1a chattr [ -RVf ] [ -v version ] [ mode ] files... \u5176\u4e2dmode\u7684\u5b57\u4e32\u683c\u5f0f\uff1a {+|-|=}[aAcCdDeijsStTu] \u5c5e\u6027 i \uff1a \u5982\u679c\u5bf9\u6587\u4ef6\u8bbe\u7f6e i \u5c5e\u6027\uff0c\u90a3\u4e48\u4e0d\u5141\u8bb8\u5bf9\u6587\u4ef6\u8fdb\u884c\u5220\u9664\u3001\u6539\u540d\uff0c\u4e5f\u4e0d\u80fd\u6dfb\u52a0\u548c\u4fee\u6539\u6570\u636e\uff1b \u5982\u679c\u5bf9\u76ee\u5f55\u8bbe\u7f6e i \u5c5e\u6027\uff0c\u90a3\u4e48\u53ea\u80fd\u4fee\u6539\u76ee\u5f55\u4e0b\u6587\u4ef6\u4e2d\u7684\u6570\u636e\uff0c\u4f46\u4e0d\u5141\u8bb8\u5efa\u7acb\u548c\u5220\u9664\u6587\u4ef6\uff1b \u5728openSUSE\u4e0b\u6267\u884c\uff0c\u5206\u533a\u6587\u4ef6\u7c7b\u578b\u662fbtrfs\u683c\u5f0f\u3002 $ touch filetest $ lsattr filetest ---------------------- filetest $ chattr +i filetest chattr: Operation not permitted while setting flags on filetest $ sudo chattr +i filetest $ lsattr filetest ----i----------------- filetest $ rm filetest rm: cannot remove 'filetest' : Operation not permitted $ sudo rm filetest rm: cannot remove 'filetest' : Operation not permitted $ echo \"test\" >> filetest -bash: filetest: Operation not permitted $ sudo echo \"test\" >> filetest -bash: filetest: Operation not permitted $ sudo chattr -i filetest \u5c5e\u6027 a \uff1a \u5982\u679c\u5bf9\u6587\u4ef6\u8bbe\u7f6e a \u5c5e\u6027\uff0c\u90a3\u4e48\u53ea\u80fd\u5728\u6587\u4ef6\u4e2d\u5897\u52a0\u6570\u636e\uff0c\u4f46\u662f\u4e0d\u80fd\u5220\u9664\u548c\u4fee\u6539\u6570\u636e\uff1b \u5982\u679c\u5bf9\u76ee\u5f55\u8bbe\u7f6e a \u5c5e\u6027\uff0c\u90a3\u4e48\u53ea\u5141\u8bb8\u5728\u76ee\u5f55\u4e2d\u5efa\u7acb\u548c\u4fee\u6539\u6587\u4ef6\uff0c\u4f46\u662f\u4e0d\u5141\u8bb8\u5220\u9664\u6587\u4ef6\uff1b \u5728openSUSE\u4e0b\u6267\u884c\uff0c\u5206\u533a\u6587\u4ef6\u7c7b\u578b\u662fbtrfs\u683c\u5f0f\u3002 lsattr filetest ---------------------- filetest $ chattr +a filetest chattr: Operation not permitted while setting flags on filetest $ sudo chattr +a filetest $ echo \"test\" >> filetest $ rm filetest rm: cannot remove 'filetest' : Operation not permitted $ sudo rm filetest rm: cannot remove 'filetest' : Operation not permitted $ sudo chattr -a filetest \u5c5e\u6027 u \uff1a \u8bbe\u7f6e\u6b64\u5c5e\u6027\u7684\u6587\u4ef6\u6216\u76ee\u5f55\uff0c\u5728\u5220\u9664\u65f6\uff0c\u5176\u5185\u5bb9\u4f1a\u88ab\u4fdd\u5b58\uff0c\u4ee5\u4fdd\u8bc1\u540e\u671f\u80fd\u591f\u6062\u590d\uff0c\u5e38\u7528\u6765\u9632\u6b62\u610f\u5916\u5220\u9664\u6587\u4ef6\u6216\u76ee\u5f55\u3002 \u5728Ubuntu\u4e0b\u6267\u884c\uff0c\u5206\u533a\u6587\u4ef6\u7c7b\u578b\u662fext4\u683c\u5f0f\u3002 $ touch filetest $ sudo chattr +u filetest $ lsattr filetest -u------------e------- filetest $ rm filetest \u5c5e\u6027 s \uff1a \u548c u \u76f8\u53cd\uff0c\u5220\u9664\u6587\u4ef6\u6216\u76ee\u5f55\u65f6\uff0c\u4f1a\u88ab\u5f7b\u5e95\u5220\u9664\uff08\u76f4\u63a5\u4ece\u786c\u76d8\u4e0a\u5220\u9664\uff0c\u7136\u540e\u75280\u586b\u5145\u6240\u5360\u7528\u7684\u533a\u57df\uff09\uff0c\u4e0d\u53ef\u6062\u590d\u3002 \u63d0\u793a\uff1a \u547d\u4ee4 chattr \u548c lsattr \u7684\u53ef\u64cd\u4f5c\u5c5e\u6027\u4f9d\u8d56\u4e8e\u6587\u4ef6\u6240\u5904\u5206\u533a\u7684\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\uff0c\u4f8b\u5982\uff0cext4\u548cxfs\u7684\u7ed3\u679c\u4f1a\u6709\u4e0d\u540c\u3002 \u5386\u53f2\uff1a\u547d\u4ee4 chattr \uff08\u7528\u4e8e\u64cd\u4f5c\u5c5e\u6027\uff09\u548c lsattr \uff08\u7528\u4e8e\u5217\u51fa\u5c5e\u6027\uff09\u6700\u521d\u4e13\u7528\u4e8e\u7b2c\u4e8c\u4e2a\u6269\u5c55\u6587\u4ef6\u7cfb\u7edf\u7cfb\u5217\uff08ext2\u3001ext3\u3001ext4\uff09\uff0c\u5e76\u4e14\u4f5c\u4e3a e2fsprogs \u5305\u7684\u4e00\u90e8\u5206\u63d0\u4f9b\u3002\u7136\u800c\uff0c\u6b64\u529f\u80fd\u5df2\u5168\u90e8\u6216\u90e8\u5206\u6269\u5c55\u5230\u8bb8\u591a\u5176\u4ed6\u7cfb\u7edf\uff0c\u5305\u62ec XFS\u3001ReiserFS\u3001JFS \u548c OCFS2\u3002 btrfs \u6587\u4ef6\u7cfb\u7edf\u5305\u62ec\u5c5e\u6027\u529f\u80fd\uff0c\u5305\u62ec C \u6807\u5fd7\uff0c\u7531\u4e8e\u4e0e CoW \u76f8\u5173\u7684\u6027\u80fd\u8f83\u6162\uff0c\u5b83\u5173\u95ed\u4e86btrfs\u7684\u5185\u7f6e\u5199\u65f6\u590d\u5236 (CoW) \u529f\u80fd\u3002 8.\u8bbf\u95ee\u63a7\u5236\u5217\u8868ACL \u00b6 8.1.ACL \u00b6 ACL\u7684\u5168\u79f0\u662fAccess Control List\u3002 \u4f20\u7edf\u7684POSIX\u6743\u9650\u6982\u5ff5\u4f7f\u7528\u4e09\u79cd\u7528\u6237\u7c7b\u578b\u6765\u5206\u914d\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6743\u9650\uff1a\u6240\u6709\u8005Owning Owner\uff0c\u6240\u6709\u8005\u7ec4Owning Group\u548c\u5176\u4ed6\u7528\u6237Other Users\u3002\u53ef\u4ee5\u4e3a\u6bcf\u4e2a\u7528\u6237\u7c7b\u578b\u8bbe\u7f6e\u4e09\u4e2a\u6743\u9650\u4f4d\uff0c\u8d4b\u4e88\u8bfb\uff08r\uff09\uff0c\u5199\uff08w\uff09\u548c\u6267\u884c\uff08x\uff09\u7684\u6743\u9650\u3002 \u6240\u6709\u8005Owning Owner\u6743\u9650\uff08\u5c5e\u4e3b\u6743\u9650\uff09 \u5c5e\u7ec4Owning Group\u6743\u9650 \u5176\u4ed6\uff08\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\uff09\u7528\u6237Other Users\u7684\u6743\u9650 \u4f20\u7edf\u7684\u4e09\u79cd\u6743\u9650\u9002\u7528\u4e8e\u5927\u591a\u6570\u5b9e\u9645\u6848\u4f8b\u3002\u4f46\u662f\uff0c\u5bf9\u4e8e\u66f4\u590d\u6742\u7684\u573a\u666f\u6216\u66f4\u9ad8\u7ea7\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u7cfb\u7edf\u7ba1\u7406\u5458\u5fc5\u987b\u4f7f\u7528\u8bb8\u591a\u6280\u5de7\u6765\u89c4\u907f\u4f20\u7edf\u6743\u9650\u7684\u9650\u5236\u3002 \u8bbf\u95ee\u63a7\u5236\u5217\u8868ACL\u63d0\u4f9b\u4e86\u5bf9\u4f20\u7edf\u6587\u4ef6\u6743\u9650\u6982\u5ff5\u7684\u6269\u5c55\u3002\u5b83\u4eec\u5141\u8bb8\u6211\u4eec\u4e3a\u5355\u4e2a\u7528\u6237\u6216\u7ec4\u5206\u914d\u6743\u9650\uff0c\u5373\u4f7f\u8fd9\u4e9b\u7528\u6237\u6216\u7ec4\u4e0e\u539f\u59cb\u6240\u6709\u8005\u6216\u5c5e\u7ec4\u4e0d\u5bf9\u5e94\u3002 ACL\u662fLinux\u5185\u6838\u7684\u4e00\u9879\u529f\u80fd\uff0c\u652f\u6301Ext\u2154/4\uff0cXFS\u548cBtrFS\u6587\u4ef6\u7cfb\u7edf\u4ee5\u53ca\u5176\u4ed6\u6587\u4ef6\u7cfb\u7edf\u3002 \u4f7f\u7528ACL\uff0c\u6211\u4eec\u53ef\u4ee5\u521b\u5efa\u590d\u6742\u7684\u65b9\u6848\uff0c\u800c\u65e0\u9700\u5728\u5e94\u7528\u7a0b\u5e8f\u7ea7\u522b\u4e0a\u53bb\u5b9e\u73b0\u590d\u6742\u7684\u6743\u9650\u6a21\u578b\u3002\u5728\u4f7f\u7528\u63d0\u4f9bSamba\u6587\u4ef6\u548c\u6253\u5370\u670d\u52a1\u7684Linux\u670d\u52a1\u5668\u66ff\u6362Windows\u670d\u52a1\u5668\u7684\u60c5\u51b5\u4e0b\uff0cACL\u7684\u4f18\u52bf\u975e\u5e38\u660e\u663e\u3002\u7531\u4e8eSamba\u652f\u6301ACL\uff0c\u56e0\u6b64\u53ef\u4ee5\u5728Linux\u670d\u52a1\u5668\u548cWindows\u4e2d\u914d\u7f6e\u7528\u6237\u6743\u9650\u3002 \u901a\u8fc7ACL\u6765\u5141\u8bb8\u5bf9\u6240\u6709\u8005\u7528\u6237\u4e4b\u5916\u7684\u5355\u4e2a\u7528\u6237\u8fdb\u884c\u6587\u4ef6\u5199\u6743\u9650\u662f\u4e00\u79cd\u7b80\u5355\u7684\u65b9\u6848\u3002\u4f7f\u7528\u4f20\u7edf\u65b9\u6cd5\uff0c\u6211\u4eec\u5fc5\u987b\u521b\u5efa\u4e00\u4e2a\u65b0\u7ec4\uff0c\u4f7f\u4e24\u4e2a\u7528\u6237\u6210\u4e3a\u8be5\u7ec4\u7684\u6210\u5458\uff0c\u5c06\u8be5\u6587\u4ef6\u7684\u6240\u6709\u7ec4\u66f4\u6539\u4e3a\u65b0\u7ec4\uff0c\u7136\u540e\u6388\u4e88\u8be5\u7ec4\u6587\u4ef6\u7684\u5199\u6743\u9650\u3002\u521b\u5efa\u7ec4\u5e76\u4f7f\u4e24\u4e2a\u7528\u6237\u6210\u4e3a\u8be5\u7ec4\u7684\u6210\u5458\u5219\u9700\u8981\u5229\u7528root\u6743\u9650\u6765\u5b9e\u73b0\u3002 \u4f7f\u7528ACL\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u4f7f\u6240\u6709\u8005\u548c\u6307\u5b9a\u7528\u6237\u5bf9\u6587\u4ef6\u5177\u6709\u5199\u6743\u9650\u6765\u5b9e\u73b0\u76f8\u540c\u7684\u7ed3\u679c\u3002 \u6b64\u65b9\u6cd5\u7684\u53e6\u4e00\u4e2a\u4f18\u70b9\u662f\u7cfb\u7edf\u7ba1\u7406\u5458\u65e0\u9700\u53c2\u4e0e\u521b\u5efa\u7ec4\u3002\u7528\u6237\u53ef\u4ee5\u81ea\u5df1\u51b3\u5b9a\u6388\u4e88\u8c01\u8bbf\u95ee\u5176\u6587\u4ef6\u7684\u6743\u9650\u3002 \u63d0\u793a\uff1a \u4f7f\u7528ACL\u65f6 ls \u7684\u8f93\u51fa\u7ed3\u679c\u4f1a\u53d1\u751f\u53d8\u5316\u3002\u6dfb\u52a0\u4e00\u4e2a\u52a0\u53f7+ \u6765\u8bf4\u660e\u5df2\u4e3a\u6b64\u6587\u4ef6\u5b9a\u4e49ACL\uff0c\u4e14\u5b9a\u4e49ACL\u540e\uff0c\u6240\u663e\u793a\u7684\u5c5e\u7ec4\u6743\u9650\u662fACL\u63a9\u7801\u7684\u503c\uff0c\u800c\u4e0d\u518d\u662f\u539f\u6765\u5c5e\u7ec4\u7684\u6743\u9650\u3002 8.2.ACL\u7684\u57fa\u672c\u7c7b\u578b \u00b6 Minimal ACLs\uff08\u6700\u5c0fACL\uff09\uff08\u5b9e\u9645\u7528\u9014\uff1a\u4e0ePOSIX\u6743\u9650\u76f8\u540c\uff09 \u4e0e\u6587\u4ef6\u6a21\u5f0f\u6743\u9650\u4f4d\u7b49\u6548\u7684ACL\u79f0\u4e3a\u6700\u5c0fACL \u5206\u4e09\u79cd\u7c7b\u578b\u7684ACL\u6761\u76ee\uff0c\u8fd9\u4e9b\u5bf9\u5e94\u4e8e\u6587\u4ef6\u548c\u76ee\u5f55\u7684\u4f20\u7edf\u6743\u9650\u4f4d Owning User \u6240\u6709\u8005 Owning Group \u6240\u6709\u8005\u7ec4 Others \u5176\u4ed6\u7ec4 Extended ACLs\uff08\u6269\u5c55ACL\uff09 \u5177\u6709\u591a\u4e8e\u4e0a\u8ff0\u4e09\u4e2aACL\u6761\u76ee\u7684ACL\u79f0\u4e3a\u6269\u5c55ACL \u6269\u5c55ACL\u8fd8\u5305\u542b\u63a9\u7801\u6761\u76ee\uff0c\u53ef\u4ee5\u5305\u542b\u4efb\u610f\u6570\u91cf\u7684\u6307\u5b9a\u7528\u6237\u548c\u6307\u5b9a\u7ec4\u6761\u76ee 8.3.ACL\u672f\u8bed \u00b6 \u7528\u6237\u7c7b\uff08User classes\uff09\u3002 \u4f20\u7edf\u7684POSIX\u6743\u9650\u6982\u5ff5\u4f7f\u7528\u4e09\u79cd\u7528\u6237\u7c7b\u6765\u5206\u914d\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6743\u9650\uff1a\u6240\u6709\u8005Owning Owner\uff0c\u6240\u6709\u8005\u7ec4Owning Group\u548c\u5176\u4ed6\u7528\u6237Other Users\u3002\u53ef\u4ee5\u4e3a\u6bcf\u4e2a\u7528\u6237\u7c7b\u578b\u8bbe\u7f6e\u4e09\u4e2a\u6743\u9650\u4f4d\uff0c\u8d4b\u4e88\u8bfb\uff08r\uff09\uff0c\u5199\uff08w\uff09\u548c\u6267\u884c\uff08x\uff09\u7684\u6743\u9650\u3002 Owner class \u6240\u6709\u8005\u7c7b Group class \u7ec4\u7c7b Other class \u5176\u4ed6\u7c7b ACL\u8bbf\u95ee\u6743\u9650\uff08Access ACL\uff09\uff1a\u786e\u5b9a\u5404\u79cd\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\uff08\u6587\u4ef6\u548c\u76ee\u5f55\uff09\u7684\u7528\u6237\u548c\u7ec4\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u9ed8\u8ba4ACL\uff08Default ACL\uff09\uff1a\u53ea\u80fd\u5e94\u7528\u4e8e\u76ee\u5f55\u3002 \u5b83\u4eec\u786e\u5b9a\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u5728\u521b\u5efa\u65f6\u4ece\u5176\u7236\u76ee\u5f55\u7ee7\u627f\u7684\u6743\u9650\u3002 ACL\u6761\u76ee\uff08ACL entry\uff09\uff1a \u6bcf\u4e2aACL\u7531\u4e00\u7ec4ACL\u6761\u76ee\u7ec4\u6210\u3002 ACL\u6761\u76ee\u5305\u542b\u7c7b\u578b\uff08type\uff09\uff0c\u6761\u76ee\u5f15\u7528\u7684\u7528\u6237\u6216\u7ec4\u7684\u9650\u5b9a\u7b26\uff08qualifier\uff09\uff0c\u4ee5\u53ca\u4e00\u7ec4\u6743\u9650\uff08permissions\uff09\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u6761\u76ee\u7c7b\u578b\uff0c\u672a\u5b9a\u4e49\u7ec4\u6216\u7528\u6237\u7684\u9650\u5b9a\u7b26\u3002 8.4.ACL\u6743\u9650\u5206\u7c7b \u00b6 Named user \u6307\u5b9a\u7528\u6237: Lets you assign permissions to individual users. \u5141\u8bb8\u6211\u4eec\u4e3a\u6307\u5b9a\u7528\u6237\u5206\u914d\u6743\u9650\u3002 Named group \u6307\u5b9a\u7ec4: Lets you assign permissions to individual groups. \u5141\u8bb8\u6211\u4eec\u4e3a\u5236\u5b9a\u7ec4\u5206\u914d\u6743\u9650\u3002 Mask \u63a9\u7801: Lets you limit the permissions granted to named users or groups. \u5141\u8bb8\u6211\u4eec\u9650\u5236\u7ed9\u4e88\u6307\u5b9a\u7528\u6237\u6216\u6307\u5b9a\u7ec4\u7684\u6743\u9650\u3002 \u6240\u4ee5\u53ef\u80fd\u7684ACL\u7c7b\u578b Type Text Form owner user::rwx named user user:name:rwx owning group group::rwx named group group:name:rwx mask mask::rwx other other::rwx \u4e0ePOSIX.1\u6743\u9650\u6a21\u578b\u4e0d\u540c\uff0c\u7ec4\u7c7bgroup class\u53ef\u4ee5\u5305\u542b\u5177\u6709\u4e0d\u540c\u6743\u9650\u96c6\u7684ACL\u6761\u76ee\uff0c\u56e0\u6b64\u5355\u72ec\u7684\u7ec4\u7c7b\u6743\u9650\u4e0d\u518d\u8db3\u4ee5\u8868\u793a\u5b83\u5305\u542b\u7684\u6240\u6709ACL\u6761\u76ee\u7684\u6240\u6709\u8be6\u7ec6\u6743\u9650\u3002 \u56e0\u6b64\uff0c\u7ec4\u7c7b\u578b\u6743\u9650\u7684\u542b\u4e49\u88ab\u91cd\u65b0\u5b9a\u4e49\u3002\u5728\u65b0\u8bed\u4e49\u4e0b\uff0c\u7ec4\u7c7b\u578b\u6743\u9650\u8868\u793a\u7ec4\u7c7b\u4e2d\u7684\u4efb\u4f55\u6761\u76ee\u5c06\u6388\u4e88\u7684\u6743\u9650\u7684**\u4e0a\u9650**\uff08upper bound\uff09\u3002 \u6b64\u4e0a\u9650\u5c5e\u6027\u53ef\u786e\u4fdd\u5728\u4f7f\u7528ACL\u63a7\u5236\u540e\uff0c\u5e94\u7528\u7a0b\u5e8f\u4e0d\u4f1a\u7a81\u7136\u6216\u8005\u610f\u5916\u5730\u6388\u4e88\u989d\u5916\u7684\u6743\u9650\u3002 \u5728\u6700\u5c0fACL\u4e2d\uff0c\u7ec4\u7c7b\u6743\u9650\u4e0e\u6240\u6709\u8005\u7ec4\u6743\u9650\u76f8\u540c\u3002\u5728\u6269\u5c55ACL\u4e2d\uff0c\u7ec4\u7c7b\u53ef\u4ee5\u5305\u542b\u5176\u4ed6\u7528\u6237\u6216\u7ec4\u7684\u6761\u76ee\u3002\u8fd9\u4f1a\u5bfc\u81f4\u4e00\u4e2a\u95ee\u9898\uff1a\u8fd9\u4e9b\u9644\u52a0\u6761\u76ee\u4e2d\u7684\u4e00\u4e9b\u53ef\u80fd\u62e5\u6709\u672a\u5305\u542b\u5728\u6240\u6709\u8005\u7ec4\u6761\u76ee\uff08owning group entry\uff09\u4e2d\u7684\u6743\u9650\uff0c\u56e0\u6b64\u6240\u6709\u8005\u7ec4\u6761\u76ee\u6743\u9650\u53ef\u80fd\u4e0e\u7ec4\u7c7b\u6743\u9650\uff08group class\uff09\u4e0d\u540c\u3002 \u901a\u8fc7\u63a9\u7801\uff08mask entry\uff09\u89e3\u51b3\u4e86\u8fd9\u4e2a\u95ee\u9898\u3002 \u4f7f\u7528\u6700\u5c0fACL\uff0c\u7ec4\u7c7b\u6743\u9650\u6620\u5c04\u5230\u6240\u6709\u8005\u7ec4\u6761\u76ee\u6743\u9650\u3002With minimal ACLs, the group class permissions map to the owning group entry permissions. \u4f7f\u7528\u6269\u5c55ACL\u65f6\uff0c\u7ec4\u7c7b\u6743\u9650\u6620\u5c04\u5230\u63a9\u7801\u6761\u76ee\u6743\u9650\uff0c\u800c\u6240\u6709\u8005\u7ec4\u6761\u76ee\u4ecd\u5b9a\u4e49\u62e5\u6709\u7ec4\u6743\u9650\u3002With extended ACLs, the group class permissions map to the mask entry permissions, whereas the owning group entry still defines the owning group permissions. 8.5.ACL\u64cd\u4f5c\u547d\u4ee4 \u00b6 \u8bbe\u5b9aACL\u6743\u9650\uff1a setfacl Syntax: setfacl [OPTIONS] [ACL-ENTRIES] Option Description -m : Add or modify an ACL entry -x : Remove an ACL entry -d : Set a default ACL -b : Remove all extended ACL entries -M : restore ACLs that have been written to a file \u6ce8\u610f\uff1a--set\u9009\u9879\u4f1a\u628a\u539f\u6709\u7684ACL\u9879\u90fd\u5220\u9664\uff0c\u7528\u65b0\u7684\u66ff\u4ee3\uff0c\u6240\u4ee5\u4e00\u5b9a\u8981\u5305\u542bUGO\u7684\u8bbe\u7f6e\uff0c\u4e0d\u80fd\u50cf-m\u533b\u9662\u53ea\u6dfb\u52a0ACL\u3002 setfacl --set u::rw,u:vagrant:rw,g::r,o::- file1 \u8bfb\u53d6ACL\u6743\u9650\uff1a getfacl Syntax: getfacl [OPTIONS] Option Description -a : Display the file access control list -d : Display the default access control list -R : List the ACLs of all files and directories recursively 8.6.ACL\u5b9e\u4f8b\u89e3\u6790 \u00b6 8.6.1.\u5b9e\u4f8b\u63cf\u8ff0 \u00b6 \u9879\u76ee\u76ee\u5f55 ~/project1 \u9879\u76ee\u7ecf\u7406 pm1 \u5bf9\u8fd9\u4e2a\u76ee\u5f55\u62e5\u6709\u8bbf\u95ee\u548c\u4fee\u6539\u6743\u9650 \u9879\u76ee\u6210\u5458 tm1 \u53ef\u4ee5\u8bbf\u95ee\u548c\u4fee\u6539\u8fd9\u4e2a\u76ee\u5f55 \u975e\u9879\u76ee\u6210\u5458 tm2 \u4e0d\u80fd\u8bbf\u95ee ~/project1 \u76ee\u5f55\u3002 \u9879\u76ee\u76ee\u5f55 ~/project1 \u7684\u6743\u9650\u89c4\u5212 \u9879\u76ee\u7ecf\u7406 pm1 \u662f\u8fd9\u4e2a\u76ee\u5f55\u7684\u5c5e\u4e3b\uff0c\u6743\u9650\u4e3a rwx \u9879\u76ee\u7ecf\u7406 pm1 \u5c5e\u4e8e project1 \u7ec4 \u9879\u76ee\u6210\u5458 tm1 \u4e0e pm1 \u5728\u540c\u4e00\u4e2a project1 \u7ec4\uff0c\u6743\u9650\u662f rw \u5176\u4ed6\u4eba\u7684\u6743\u9650\u8bbe\u5b9a\u4e3a 0 \u9879\u76ee\u4e34\u65f6\u6210\u5458tm2\u7684\u6743\u9650\u9700\u6c42 \u80fd\u8bbf\u95ee project1 \u76ee\u5f55\uff0c\u4f46\u53ea\u80fd\u5177\u6709 r \u548c x \u6743\u9650 \u89e3\u51b3\u65b9\u6cd5 \u5f53\u51fa\u73b0\u8fd9\u79cd\u60c5\u51b5\u65f6\uff0c\u666e\u901a\u6743\u9650\u4e2d\u7684\u4e09\u79cd\u8eab\u4efd\uff08owner\uff0cgroup\uff0cothers\uff09\u5c31\u4e0d\u80fd\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0c\u800cACL\u6743\u9650\u53ef\u4ee5\u3002 \u5728\u4f7f\u7528ACL\u6743\u9650\u7ed9\u7528\u6237 tm2 \u965a\u4e88\u6743\u9650\u65f6\uff0c tm2 \u65e2\u4e0d\u662f ~/project1 \u76ee\u5f55\u7684\u5c5e\u4e3b\uff0c\u4e5f\u4e0d\u662f\u5c5e\u7ec4\uff0c\u4ec5\u4ec5\u8d4b\u4e88\u7528\u6237 tm2 \u9488\u5bf9 ~/project1 \u76ee\u5f55\u7684r-x\u6743\u9650\uff0c \u5c5e\u4e8e\u5355\u72ec\u6307\u5b9a\u7528\u6237\u5e76\u5355\u72ec\u5206\u914d\u6743\u9650\uff0c\u89e3\u51b3\u4e86\u7528\u6237\u8eab\u4efd\u4e0d\u8db3\u7684\u95ee\u9898\u3002 \u62d3\u5c55\u95ee\u9898 \u7ed9 ~/project1 \u76ee\u5f55\u6dfb\u52a0\u5176\u4ed6\u7ec4 project2 \u7684\u8bbf\u95ee\u6743\u9650 \u901a\u8fc7 mask \u6765\u8c03\u6574\u7528\u6237 tm2 \u5b9e\u9645\u6709\u6548\u6743\u9650 \u9ed8\u8ba4ACL\u6743\u9650 \u9012\u5f52ACL\u6743\u9650 \u5220\u9664ACL\u6743\u9650 8.6.2.\u521d\u59cb\u5316\u73af\u5883 \u00b6 \u521b\u5efa\u6d4b\u8bd5\u7528\u6237 $ whoami vagrant $ sudo groupadd project1 $ sudo groupadd project2 $ sudo useradd -m -g project1 pm1 $ sudo useradd -m -g project1 tm1 $ sudo useradd -m -g project2 tm2 $ sudo passwd pm1 $ sudo passwd tm1 $ sudo passwd tm2 $ cat /etc/group ...... project1:x:1535: project2:x:1536: ...... $ cat /etc/passwd ...... pm1:x:2003:1535::/home/pm1:/bin/bash tm1:x:2004:1535::/home/tm1:/bin/bash tm2:x:2005:1536::/home/tm2:/bin/bash ...... \u521b\u5efa\u6d4b\u8bd5\u76ee\u5f55 project1 , \u6307\u5b9a project1 \u76ee\u5f55\u7684\u6743\u9650\uff0c\u521b\u5efa\u6d4b\u8bd5\u6587\u4ef6 file1 \u3002 $ su - pm1 $ cd ~ $ mkdir project1 $ ls -dl project1 drwxr-xr-x. 1 pm1 project1 0 Dec 4 06 :25 project1 $ chmod 770 project1/ $ ls -dl project1 drwxrwx---. 1 pm1 project1 0 Dec 4 06 :25 project1 $ echo \"hello from $USER \" > ./project1/file1 $ cat ./project1/file1 hello from pm1 \u76ee\u5f55 project1 \u5f53\u524d\u6743\u9650\u5feb\u7167 \u5c5e\u4e3b\uff1a pm1 \uff0c\u5bf9 ~/project1 \u76ee\u5f55\u6709 rwx \u6743\u9650 \u5c5e\u7ec4\uff1a project1 \uff0c\u5305\u542b\u7528\u6237 pm1 \u548c tm1 \uff0c\u5bf9 ~/project1 \u76ee\u5f55\u6709 rwx \u6743\u9650 \u5176\u4ed6\u7ec4\uff1a\u6ca1\u6709\u8bbf\u95ee\u6743\u9650 \u76ee\u5f55 ~/project1 \u5f53\u524d\u7684ACL\u5feb\u7167 $ getfacl ./project1/ # file: home/pm1/project1/ # owner: pm1 # group: project1 user::rwx group::rwx other::--- 8.6.3.\u6dfb\u52a0ACL\u6743\u9650 \u00b6 \u7ed9 ~/project1 \u76ee\u5f55\u6dfb\u52a0\u65b0\u7528\u6237 tm2 \uff0c\u6743\u9650\u4e3a rwx \u3002\u76ee\u5f55 ~/project1 \u7684\u66f4\u65b0\u540e\u7684\u6743\u9650\u4f4d\u53d8\u6210\u4e86 drwxrwx---+ \u3002 $ su - pm1 $ setfacl -m u:tm2:rx ./project1/ $ ls -dl ./project1 drwxrwx---+ 1 pm1 project1 0 Dec 4 06 :25 project1 $ getfacl ~/project1/ # file: project1 \uff08\u6587\u4ef6\u540d\uff09 # owner: pm1 \uff08Owner \u6587\u4ef6\u5c5e\u4e3b\uff09 # group: project1 \uff08Owing Group \u6587\u4ef6\u5c5e\u7ec4\uff09 user::rwx \uff08Ower\u6587\u4ef6\u5c5e\u4e3b\u7684\u6743\u9650\uff0c\u7528\u6237\u540d\u680f\u662f\u7a7a\u7684\uff0c\u8bf4\u660e\u662f\u5c5e\u4e3bOwner\u7684\u6743\u9650\uff09 user:tm2:r-x \uff08Named User \u6307\u5b9a\u7528\u6237\u7684\u6743\u9650\uff0c\u7528\u6237tm2\u7684\u6743\u9650\uff09 group::rwx \uff08Owing Group \u6587\u4ef6\u5c5e\u7ec4\u7684\u6743\u9650\uff0c\u7ec4\u540d\u680f\u662f\u7a7a\u7684\uff0c\u8bf4\u660e\u662f\u5c5e\u7ec4\u7684\u6743\u9650\uff09 \uff08Named Group \u6307\u5b9a\u7528\u6237\u7ec4\u7684\u6743\u9650\uff0c\u6b64\u65f6\u672a\u6307\u5b9a\uff09 mask::rwx \uff08mask\u6743\u9650\uff09 other::--- \uff08\u5176\u4ed6\u4ebaother\u7684\u6743\u9650\uff09 \u7ed9 ~/project1 \u76ee\u5f55\u6dfb\u52a0\u65b0\u7ec4 project2 \u7684\u6743\u9650 rwx $ su - pm1 $ setfacl -m g:project2:rwx ./project1/ $ ls -dl ./project1 drwxrwx---+ 1 pm1 project1 0 Dec 4 06 :46 ./project1 $ getfacl ./project1 # file: project1 # owner: pm1 # group: project1 user::rwx user:tm2:r-x ( \u7528\u6237tm2\u62e5\u6709\u4e86r-x\u6743\u9650\uff09 group::rwx group:project2:rwx ( \u7528\u6237\u7ec4project2\u62e5\u6709\u4e86rwx\u6743\u9650\uff09 mask::rwx other::--- \u6709\u6548\u6743\u9650\u7684\u8ba1\u7b97\uff1a \u5f53\u524d ~/project1 \u76ee\u5f55\u7684 mask \u662f rwx \uff0c tm2 \u7684\u6743\u9650\u662f r-x \uff0c\u4e8c\u8005\u8fdb\u884cAND\u64cd\u4f5c\uff0c tm2 \u7684\u5b9e\u9645\u6743\u9650\u662f r-x tm2: r - x ( 1 0 1 ) mask: r w x ( 1 1 1 ) --------------------- result: r - x ( 1 0 1 ) \u5bf9\u7167\u4e0b\u9762\u7684\u89c4\u5219\uff0c\u9a8c\u8bc1\u7528\u6237 tm2 \u5bf9 ~/project1 \u76ee\u5f55\u7684\u5b9e\u9645\u6743\u9650\u3002 su - tm2 \u80fd\u8fdb\u5165\u76ee\u5f55 project1 \uff0c\u8bf4\u660e\u5f53\u524d\u7528\u6237\u5177\u6709\u76ee\u5f55 project1 \u7684 r-x \u6743\u9650\u3002 $ whoami tm2 $ cd /home/pm1/project1/ \u80fd\u5217\u51fa\u76ee\u5f55 project1 \u4e0b\u6587\u4ef6\u5217\u8868\uff0c\u53ef\u4ee5\u67e5\u770b\u6587\u4ef6 file \u7684\u5185\u5bb9\uff0c\u8bf4\u660e\u5f53\u524d\u7528\u6237\u5177\u6709\u76ee\u5f55 project1 \u7684 r-x \u6743\u9650\u3002 $ pwd /home/pm1/project1 $ whoami tm2 $ ls -l -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 $ cat file1 hello from pm1 \u5bf9\u76ee\u5f55 project1 \u4e0d\u5177\u6709 w \u6743\u9650\uff0c\u6240\u4ee5\u65e0\u6cd5\u521b\u5efa\u3001\u5220\u9664\u6216\u4fee\u6539\u76ee\u5f55\u4e0b\u7684\u4efb\u4f55\u6587\u4ef6\u6216\u5b50\u76ee\u5f55\u3002 $ pwd /home/pm1/project1 $ whoami tm2 $ touch file2 touch: cannot touch 'file2' : Permission denied $ echo \"hello from $USER \" >> file1 -bash: file1: Permission denied 8.6.4.\u4fee\u6539mask\u6743\u9650 \u00b6 \u8c03\u6574 ~/project1 \u76ee\u5f55\u7684 mask \u4e3a r-- \uff0c\u5219 tm2 \u7684\u5b9e\u9645\u6743\u9650\u662f r-- $ su - pm1 $ cd ~ $ setfacl -m m::r ./project1/ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- (\u7528\u6237tm2\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u53d8\u4e3ar--) group::rwx #effective:r-- (\u5c5e\u7ec4project1\u7ec4\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u53d8\u4e3ar--) group:project2:rwx #effective:r-- (\u5176\u4ed6\u7ec4project2\u7ec4\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u53d8\u4e3ar--) mask::r-- ( mask\u53d8\u5316\uff0c\u5bfc\u81f4\u4e0a\u8ff0\u4e24\u4e2agroup\u7684\u6709\u6548\u6743\u9650\u90fd\u53d1\u751f\u4e86\u53d8\u5316 ) other::--- \u6709\u6548\u6743\u9650\u7684\u8ba1\u7b97\uff1a \u5f53\u524d ~/project1 \u76ee\u5f55\u7684 mask \u662f r-- \uff0c\u7528\u6237 tm2 \u3001\u7ec4 project2 \u7684\u5b9e\u9645\u6743\u9650\u662f r-- \u3002 tm2: r - w ( 1 0 1 ) mask: r - - ( 1 0 0 ) --------------------- result: r - - ( 1 0 0 ) \u63d0\u793a\uff1a \u7528\u6237\u548c\u7528\u6237\u7ec4\u6240\u8bbe\u5b9a\u7684\u6743\u9650\u5fc5\u987b\u5728mask\u6743\u9650\u8bbe\u5b9a\u7684\u8303\u56f4\u4e4b\u5185\u624d\u80fd\u751f\u6548\uff0cmask\u6743\u9650\u5c31\u662f\u6700\u5927\u6709\u6548\u6743\u9650\u3002 8.6.5.\u6709\u6548\u6743\u9650\u5206\u6790 \u00b6 \u5728POSIX\u6743\u9650\u6a21\u578b\u548cACL\u6743\u9650\u53e0\u52a0\u4f5c\u7528\u4e0b\uff0c\u7528\u6237\u7684\u5b9e\u9645\u6743\u9650\u5206\u6790\u3002 $ getfacl ./project1/ # file: project1/ # owner: pm1 <----Owner # group: project1 <----owning group user::rwx <----owner 's permissions user:tm2:r-x #effective:r-- <----named user' s permissions group::rwx #effective:r-- <----owning group's permissions group:project2:rwx #effective:r-- <----named group's permissions mask::r-- <----masks for named user and named group other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- \u6240\u6709\u8005ower\u548c\u5176\u4ed6\u7528\u6237other\u6761\u76ee\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\u603b\u662f\u6709\u6548\u7684\u3002\u4e0a\u4f8b\u4e2d\u7684user\u6761\u76ee\u548cother\u6761\u76ee\u3002 \u9664\u4e86\u63a9\u7801\u6761\u76ee\uff0c\u6240\u6709\u5176\u4ed6\u6761\u76ee\uff08\u6bd4\u5982\u6307\u5b9a\u7528\u6237named user\uff09\u53ef\u4ee5\u662f\u6709\u6548\u7684\u6216\u88ab\u5c4f\u853d\u7684\u3002 \u6307\u5b9a\u7528\u6237\uff08named user\uff09\uff0c\u6240\u6709\u8005\u7ec4\uff08owning group\uff09\u6216\u6307\u5b9a\u7ec4\uff08named group\uff09\u4ee5\u53ca\u63a9\u7801mask\u6761\u76ee\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\uff0c\u6709\u6548\u6743\u9650\u662f\u4ed6\u4eec\u6743\u9650\u8fdb\u884c\u903b\u8f91AND\u540e\u7684\u7ed3\u679c\uff0c\u800c\u4e0d\u662f\u5355\u72ec\u7684\u63a9\u7801\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\u6216\u8005\u5404\u81ea\u6761\u76ee\u4e2d\u5b9a\u4e49\u7684\u6743\u3002 \u6709\u6548\u6743\u9650\u8ba1\u7b97\u65b9\u6cd5\u5982\u4e0b\uff0c\u6ce8\u610f\uff0c ls \u547d\u4ee4\u4e2d\u663e\u793a\u51fa\u6765\u7684\u6743\u9650\uff0c\u4e0e\u5b9e\u9645\u7684ACL\u6743\u9650\u662f\u6709\u5dee\u522b\u7684\u3002 tm2: r - w ( 1 0 1 ) group: r w x ( 1 1 1 ) named group: r w x ( 1 1 1 ) mask: r - - ( 1 0 0 ) --------------------------- result: r - - ( 1 0 0 ) \u5c0f\u8d34\u58eb\uff1a \u4e0e\u6587\u4ef6\u6a21\u5f0f\u6743\u9650\u4f4d\u7b49\u6548\u7684ACL\u79f0\u4e3a\u6700\u5c0fACL\uff0c\u5373POSIX\u4f20\u7edf\u6743\u9650\u3002 \u542b\u63a9\u7801mask\u7b49\u5176\u4ed6\u6743\u9650\u6761\u76ee\u7684ACL\u79f0\u4e3a\u6269\u5c55ACL\u3002 \u5728\u6700\u5c0f\u548c\u6269\u5c55ACL\u60c5\u5f62\u4e0b\uff0c\u6240\u6709\u8005\u7c7b\u6743\u9650\uff08owner\uff09\u90fd\u662f\u6620\u5c04\u5230ACL\u7684\u6240\u6709\u8005\u6761\u76ee\u3002 \u5176\u4ed6\u7c7b\u6743\u9650\u6620\u5c04\u5230\u5176\u5404\u81ea\u7684ACL\u6761\u76ee\u3002 \u5728\u6269\u5c55ACL\u60c5\u5f62\u4e0b\uff0c\u7ec4\u7c7b\u6743\u9650\u7684\u6620\u5c04\u662f\u4e0d\u540c\u7684\u3002 \u5bf9\u4e8e\u6ca1\u6709\u63a9\u7801\u7684\u6700\u5c0fACL\uff0c\u7ec4\u7c7b\u6743\u9650\u5c06\u6620\u5c04\u5230ACL\u6240\u6709\u8005\u7ec4\u6761\u76ee\u3002 \u5bf9\u4e8e\u5e26\u6709\u63a9\u7801\u7684\u6269\u5c55ACL\uff0c\u7ec4\u7c7b\u6743\u9650\u5c06\u6620\u5c04\u5230\u63a9\u7801\u6761\u76ee\u3002 \u901a\u8fc7\u6743\u9650\u4f4d\u8fdb\u884c\u5206\u914d\u7684\u6743\u9650\u4ee3\u8868\u4e86\u901a\u8fc7ACL\u8fdb\u884c\u5206\u914d\u7684\u6743\u9650\u7684\u4e0a\u9650\u3002 \u6ca1\u6709\u5728\u8fd9\u91cc\u4f53\u73b0\u7684\u4efb\u4f55\u6743\u9650\uff0c\u8981\u4e48\u4e0d\u5728ACL\u4e2d\uff0c\u8981\u4e48\u65e0\u6548\u3002 \u5bf9\u6743\u9650\u4f4d\u6240\u505a\u7684\u66f4\u6539\u5c06\u7531ACL\u53cd\u6620\uff0c\u53cd\u4e4b\u4ea6\u7136\u3002 8.6.6.\u9ed8\u8ba4ACL\u6743\u9650 \u00b6 $ su - pm1 $ touch ./project1/file2 $ mkdir ./project1/cloud $ ll ./project1/ drwxr-xr-x. 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 $ ll -d project1/ drwxr-----+ 1 pm1 project1 30 Dec 4 08 :52 project1/ \u6587\u4ef6 file1 \u548c\u76ee\u5f55 cloud \u6ca1\u6709\u7ee7\u627f project1 \u76ee\u5f55\u7684ACL\u6743\u9650\u3002 \u63d0\u793a\uff1a \u9ed8\u8ba4 ACL\u9650\u53ea\u5bf9\u76ee\u5f55\u751f\u6548\u3002 \u9ed8\u8ba4ACL\u6743\u9650\u7684\u4f5c\u7528\u662f\uff1a\u5982\u679c\u7ed9\u7236\u76ee\u5f55\u8bbe\u5b9a\u4e86\u9ed8\u8ba4 ACL \u6743\u9650\uff0c\u90a3\u4e48\u7236\u76ee\u5f55\u4e2d\u6240\u6709\u65b0\u5efa\u7684\u5b50\u6587\u4ef6\u90fd\u4f1a\u7ee7\u627f\u7236\u76ee\u5f55\u7684ACL\u6743\u9650\u3002 \u4e0b\u9762\u589e\u52a0 ~/project1 \u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u6743\u9650\u3002 $ su - pm1 $ cd ~ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- group::rwx #effective:r-- group:project2:rwx #effective:r-- mask::r-- other::--- $ setfacl -m d:u:tm2:rx ./project1/ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- group::rwx #effective:r-- group:project2:rwx #effective:r-- mask::r-- other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- \u521b\u5efa\u65b0\u5b50\u76ee\u5f55 leonardo \uff0c\u5c31\u7ee7\u627f\u4e86 ~/project1 \u76ee\u5f55\u7684default ACL\u6743\u9650\u8bbe\u5b9a\u3002 \u6ce8\u610f\uff0c\u9ed8\u8ba4ACL\u6743\u9650\u662f\u9488\u5bf9\u65b0\u5efa\u7acb\u7684\u6587\u4ef6\u751f\u6548\u7684\uff0c\u76ee\u5f55cloud\u548c\u6587\u4ef6file1\u5e76\u6ca1\u6709\u56e0\u4e3a\u589e\u52a0\u4e86\u7236\u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u8bbe\u5b9a\u800c\u7ee7\u627f\u9ed8\u8ba4ACL\u6743\u9650\u8bbe\u5b9a. $ su - pm1 $ cd ~ $ mkdir ./project1/leonardo $ ll ./project1/ drwxr-xr-x. 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---+ 1 pm1 project1 0 Dec 4 09 :07 leonardo 8.6.7.\u9012\u5f52ACL\u6743\u9650 \u00b6 \u9012\u5f52 ACL \u6743\u9650\uff0c\u662f\u6307\u7236\u76ee\u5f55\u5728\u8bbe\u5b9aACL\u6743\u9650\u65f6\uff0c\u6240\u6709\u7684\u5b50\u76ee\u5f55\u4e5f\u4f1a\u62e5\u6709\u76f8\u540c\u7684ACL\u6743\u9650\u3002 $ su - pm1 $ cd ~ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- group::rwx #effective:r-- group:project2:rwx #effective:r-- mask::r-- other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- $ setfacl -m d:u:tm2:rx -R ./project1/ $ ll ./project1 drwxr-xr-x+ 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---+ 1 pm1 project1 0 Dec 4 09 :07 leonardo 8.6.8.\u5220\u9664ACL\u6743\u9650 \u00b6 \u5220\u9664\u7528\u6237 tm2 \u7684ACL\u6743\u9650\u3002 $ su - pm1 $ cd ~ $ setfacl -x u:tm2 ./project1/ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx group::rwx group:project2:rwx mask::rwx other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- \u5220\u9664\u6240\u6709\u7684ACL\u6743\u9650\u3002 $ setfacl -b ./project1 $ getfacl ./project1 # file: project1/ # owner: pm1 # group: project1 user::rwx group::rwx other::--- $ ll ./project1 drwxr-xr-x+ 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---+ 1 pm1 project1 0 Dec 4 09 :07 leonardo \u9012\u5f52\u5220\u9664\u5168\u90e8ACL\u6743\u9650\u3002 $ setfacl -b -R ./project1 $ ll ./project1/ total 4 drwxr-xr-x. 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---. 1 pm1 project1 0 Dec 4 09 :07 leonardo 8.7.ACL\u76ee\u5f55\u5b9e\u4f8b\u89e3\u6790 \u00b6 8.7.1.\u76ee\u5f55ACL \u00b6 \u5207\u6362\u5230pm1\u7528\u6237\uff0c\u5728\u5176\u4e3b\u76ee\u5f55\u4e2d\uff0c\u57fa\u4e8e\u4e0d\u540c\u7684\u63a9\u7801\u521b\u5efa2\u4e2a\u5b50\u76ee\u5f55\u3002 $ su - pm1 $ umask 0022 $ mkdir mydir1 $ umask 0027 $ mkdir mydir2 $ ll -d mydir* drwxr-xr-x. 1 pm1 project1 0 Dec 4 12 :30 mydir1 drwxr-x---. 1 pm1 project1 0 Dec 4 12 :31 mydir2 \u8fd92\u4e2a\u76ee\u5f55\u5f53\u524d\u7684ACL\u72b6\u6001\u5982\u4e0b\uff1a $ getfacl mydir1 # file: mydir1 # owner: pm1 # group: project1 user::rwx group::r-x other::r-x $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx group::r-x other::--- \u4fee\u6539\u76ee\u5f55 mydir2 \u7684ACL\u3002 $ setfacl -m u:tm2:rwx,g:project2:rwx mydir2 $ getfacl mydir2 getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx group::r-x group:project2:rwx mask::rwx other::--- $ ll -d mydir2 drwxrwx---+ 1 pm1 project1 0 Dec 4 12 :31 mydir2 \u73b0\u5728\uff0c\u7528\u6237 tm2 \u548c\u7ec4 project2 \u5bf9\u76ee\u5f55 mydir2 \u90fd\u5177\u6709rwx\u6743\u9650\uff0c\u4f20\u7edfPOSIX\u6743\u9650\u548cACL\u6743\u9650\u4e00\u81f4\u3002 \u73b0\u5728\u5bf9mydir2\u76ee\u5f55\u7ec4\u6743\u9650\u64a4\u9500w\u6743\u9650\u3002 \u7528\u6237 tm2 \u548c\u7ec4 project2 \u5bf9\u76ee\u5f55 mydir2 \u7684\u6709\u6548\u6743\u9650\u53d8\u6210\u4e86 r-x \u3002 mask\u4e5f\u53d7\u7ec4\u6743\u9650\u53d8\u5316\u5f71\u54cd\uff0c\u53d8\u6210\u4e86 r-x \u3002 $ chmod g-w mydir2 $ ll -d mydir2 drwxr-x---+ 1 pm1 project1 0 Dec 4 12 :31 mydir2 $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx #effective:r-x group::r-x group:project2:rwx #effective:r-x mask::r-x other::--- \u901a\u8fc7 chmod \u548c setfacl \u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u6cd5\u5bf9\u76ee\u5f55 mydir2 \u7684\u7ec4\u6743\u9650\u8fdb\u884c\u4fee\u6539\uff0c\u5728ls\u547d\u4ee4\u4e2d\u4f53\u73b0\u662f\u4e00\u6837\u7684\uff0c\u5bf9\u7ec4\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u7684\u5f71\u54cd\u4e5f\u662f\u4e00\u6837\u7684\u3002 chmod \u4fee\u6539\u7684\u662f mask \uff0c mask \u53ea\u5f71\u54cd\u9664\u6240\u6709\u8005\u548cother\u7684\u4e4b\u5916\u7684\u4eba\u548c\u7ec4\u7684\u6700\u5927\u6743\u9650\uff0c mask \u9700\u8981\u4e0e\u7528\u6237\u7684\u6743\u9650\u8fdb\u884c\u903b\u8f91\u4e0e\u8fd0\u7b97\u540e\uff0c\u624d\u80fd\u53d8\u6210\u6709\u6548\u6743\u9650\uff0c\u7528\u6237\u6216\u7ec4\u7684\u8bbe\u7f6e\u5fc5\u987b\u5728mask\u6743\u9650\u8bbe\u5b9a\u8303\u56f4\u5185\u624d\u4f1a\u751f\u6548\u3002 setfacl \u53ef\u4ee5\u4e0d\u4fee\u6539mask\u7684\u60c5\u51b5\u4e0b\u53ea\u4fee\u6539 owning group \u7684\u6743\u9650\uff0c\u4e0b\u9762\u7684\u4f8b\u5b50\u8bf4\u660e\u4e86\u8fd9\u4e00\u60c5\u51b5\u3002POSIX\u7ec4\u6743\u9650\u4ecd\u7136\u662f rwx \uff0c\u4f46ACL\u4e2d\u6240\u6709\u8005\u7ec4\u7684\u6743\u9650\u53d8\u6210\u4e86 r-- \u3002 $ setfacl -m g::r mydir2 $ ll -d mydir2 drwxrwx---+ 1 pm1 project1 0 Dec 4 12 :31 mydir2 $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx group::r-- group:project2:rwx mask::rwx other::--- 8.7.2.\u76ee\u5f55\u7684\u9ed8\u8ba4ACL \u00b6 \u76ee\u5f55\u53ef\u4ee5\u5177\u6709\u9ed8\u8ba4ACL\uff0c\u8fd9\u662f\u4e00\u79cd\u7279\u6b8a\u7684ACL\uff0c\u7528\u4e8e\u5b9a\u4e49\u76ee\u5f55\u4e0b\u7684\u5bf9\u8c61\u5728\u521b\u5efa\u65f6\u7ee7\u627f\u7684\u8bbf\u95ee\u6743\u9650\u3002\u9ed8\u8ba4ACL\u4f1a\u5f71\u54cd\u5b50\u76ee\u5f55\u548c\u6587\u4ef6\u3002 \u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u7684\u6743\u9650\u6709\u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u4f20\u9012\u7ed9\u5176\u4e2d\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\uff1a \u5b50\u76ee\u5f55\u7ee7\u627f\u7236\u76ee\u5f55\u7684\u9ed8\u8ba4ACL\uff0c\u65e2\u4f5c\u4e3a\u81ea\u5df1\u7684\u9ed8\u8ba4ACL\uff0c\u53c8\u4f5c\u4e3a\u81ea\u5df1\u7684\u8bbf\u95eeACL\u3002 \u6587\u4ef6\u7ee7\u627f\u76ee\u5f55\u9ed8\u8ba4ACL\u4f5c\u4e3a\u5176\u81ea\u5df1\u7684\u8bbf\u95eeACL\u3002 \u521b\u5efa\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u7684\u6240\u6709\u7cfb\u7edf\u51fd\u6570\u90fd\u4f7f\u7528mode\u53c2\u6570\uff0c\u8be5\u53c2\u6570\u5b9a\u4e49\u4e86\u65b0\u521b\u5efa\u7684\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u5982\u679c\u7236\u76ee\u5f55\u6ca1\u6709\u9ed8\u8ba4ACL\uff0c\u5219\u6839\u636eumask\u7684\u8bbe\u7f6e\u8bbe\u7f6e\u6743\u9650\u4f4d\u3002 \u5982\u679c\u7236\u76ee\u5f55\u5b58\u5728\u9ed8\u8ba4ACL\uff0c\u5219\u5206\u914d\u7ed9\u65b0\u5bf9\u8c61\u7684\u6743\u9650\u4f4d\u5219\u662fmode\u53c2\u6570\u6743\u9650\u4e0e\u9ed8\u8ba4ACL\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\u7684\u903b\u8f91\u4e0e\u7684\u7ed3\u679c\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5ffd\u7565umask\u547d\u4ee4\u3002 \u9ed8\u8ba4ACL\u4e0d\u4f1a\u7acb\u5373\u5f71\u54cd\u8bbf\u95ee\u6743\u9650\u3002\u5b83\u4eec\u4ec5\u5728\u521b\u5efa\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u65f6\u624d\u8d77\u4f5c\u7528\u3002\u8fd9\u4e9b\u65b0\u5bf9\u8c61\u4ec5\u4ece\u5176\u7236\u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u7ee7\u627f\u6743\u9650\u3002 \u547d\u4ee4 mkdir \u5728\u521b\u5efa\u76ee\u5f55\u65f6\u4f1a\u7ee7\u627f\u9ed8\u8ba4ACL\u3002 $ su - pm1 $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx group::r-- group:project2:rwx mask::rwx other::--- $ mkdir ./mydir2/sub1 $ ll ./mydir2 drwxr-x---. 1 pm1 project1 0 Dec 4 13 :23 sub1 $ setfacl -d -m g:project2:-w- mydir2 $ mkdir ./mydir2/sub2 $ ll ./mydir2 drwxr-x---. 1 pm1 project1 0 Dec 4 13 :23 sub1 drwxrw----+ 1 pm1 project1 0 Dec 4 13 :27 sub2 $ getfacl ./mydir2/sub2 # file: mydir2/sub2 # owner: pm1 # group: project1 user::rwx group::r-- group:project2:-w- mask::rw- other::--- default:user::rwx default:group::r-- default:group:project2:-w- default:mask::rw- default:other::--- \u5728\u5bf9 mydir2 \u76ee\u5f55\u6dfb\u52a0\u9ed8\u8ba4ACL\u524d\uff0c\u521b\u5efa\u5b50\u76ee\u5f55 sub1 \uff0c\u6dfb\u52a0\u540e\u521b\u5efa\u5b50\u76ee\u5f55 sub2 \u3002\u53ef\u4ee5\u89c2\u5bdf\u5230 sub2 \u5230\u7ee7\u627f\u4e86 mydir2 \u7684\u9ed8\u8ba4ACL\u3002 $ su - tm2 $ cd /home/pm1/mydir2/sub2 -bash: cd: /home/pm1/mydir2/sub2: Permission denied \u4e0a\u4f8b\u4e2d\uff0c\u9ed8\u8ba4ACL\u4e2d\u6307\u5b9a\u7ec4 project2 \u53ea\u5177\u6709w\u6743\u9650\uff0c\u6240\u4ee5\u65e0\u6cd5\u6267\u884c cd \u547d\u4ee4\u8fdb\u5165\u8be5\u76ee\u5f55\u3002 \u8fd9\u8bf4\u660e\u6a21\u5f0f\u503cmode\u4e2d\u7ed9\u4e88\u7684\u6743\u9650 r \u88ab\u5c4f\u853d\u4e86\uff0c\u53ea\u4fdd\u7559\u4e86ACL\u4e2d\u6700\u5c0f\u7684\u6743\u9650 w \u3002 8.8.ACL\u68c0\u67e5\u903b\u8f91 \u00b6 ACL\u68c0\u67e5\u987a\u5e8f\uff1a Owner Named user Owning group Named group Other If \u8fdb\u7a0b\u7684\u7528\u6237\u6807\u8bc6\u662fOwner\uff0c\u5219owner\u7684ACL\u6761\u76ee\u51b3\u5b9a\u8bbf\u95ee\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7528\u6237\u6807\u8bc6\u662fnamed user\uff0c\u5219name user\u7684ACL\u6761\u76ee\u7684\u6743\u9650\u51b3\u5b9a\u7533\u8bf7\u7684\u8bbf\u95ee\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7ec4\u5c5e\u4e8eowning group\uff0c\u4e14owning group\u7684ACL\u6761\u76ee\u5305\u542b\u6240\u8bf7\u6c42\u7684\u8bbf\u95ee\u6743\u9650\uff0c\u5219\u6388\u4e88\u6240\u8bf7\u6c42\u7684\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7ec4\u5c5e\u4e8enamed group\uff0c\u4e14named group\u7684ACL\u6761\u76ee\u5305\u542b\u6240\u8bf7\u6c42\u7684\u8bbf\u95ee\u6743\u9650\uff0c\u5219\u6388\u4e88\u6240\u8bf7\u6c42\u7684\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7ec4\u5c5e\u4e8eowning group\u6216\u8005named group\uff0c\u4f46owning group\u6216\u8005named group\u7684ACL\u6761\u76ee\u4e0d\u5305\u542b\u6240\u8bf7\u6c42\u7684\u8bbf\u95ee\u6743\u9650\uff0c\u5219\u62d2\u7edd\u6240\u8bf7\u6c42\u7684\u6743\u9650 else ACL\u4e2d\u7684other\u6761\u76ee\u5904\u7406\u7533\u8bf7\u7684\u6743\u9650 If \u5982\u679c\u8fdb\u7a0b\u5339\u914d\u5230owner\u6216\u8005other\u6761\u76ee\u4e2d\u5305\u542b\u6240\u7533\u8bf7\u7684\u6743\u9650\uff0c\u5219\u6388\u4e88\u6743\u9650 else if \u5982\u679c\u8fdb\u7a0b\u5339\u914d\u5230named user\uff0cowning group\uff0c\u6216\u8005named group\u6761\u76ee\u4e2d\u5305\u542b\u6240\u7533\u8bf7\u7684\u6743\u9650\uff0c\u4e14maks\u6761\u76ee\u4e5f\u5305\u542b\u6240\u7533\u8bf7\u7684\u6743\u9650\uff0c\u5219\u6388\u4e88\u6743\u9650 else \u62d2\u7edd\u6743\u9650\u7533\u8bf7 \u5b9e\u9645\u5e94\u7528\u4e3e\u4f8b\uff1a udev\u4f7f\u7528ACL\u7ed9\u4e88\u767b\u5f55\u5230\u56fe\u5f62\u754c\u9762\u7684\u7528\u6237\u8bbf\u95ee\u8bbe\u5907\u7684\u6743\u9650\uff0c\u4f8b\u5982DVD\u9a71\u52a8\u5668 \u67d0\u4e9b\u5e94\u7528\u7a0b\u5e8f\u4e0d\u652f\u6301ACL Star Archiver\u662f\u4e00\u4e2a\u5b8c\u5168\u4fdd\u7559ACL\u7684\u5907\u4efd\u5e94\u7528\u7a0b\u5e8f\uff0c\u5176\u4ed6\u4eba\u53ef\u80fd\u4f1a\u4e5f\u53ef\u80fd\u4e0d\u4f1a\u4fdd\u7559\u5b83 \u8bb8\u591a\u7f16\u8f91\u5668\u548c\u6587\u4ef6\u7ba1\u7406\u5668\u4e0d\u5141\u8bb8\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u67e5\u770b\u6216\u8bbe\u7f6eACL","title":"\u7b2c\u4e09\u7ae0 \u8eab\u4efd\u4e0e\u5b89\u5168"},{"location":"linux/SRE/03-identity-security/#_1","text":"","title":"\u7b2c\u4e09\u7ae0 \u8eab\u4efd\u4e0e\u5b89\u5168"},{"location":"linux/SRE/03-identity-security/#1","text":"\u7528\u6237\u548c\u7ec4 \u7528\u6237user\u548c\u7ec4group\u5728Linux\u7cfb\u7edf\u4e2d\u4ee5\u6570\u5b57\u5f62\u5f0f\u8fdb\u884c\u7ba1\u7406\u3002 \u7528\u6237\u88ab\u5206\u914d\u7684\u53f7\u7801\u79f0\u4e3a\u7528\u6237ID\uff08UID\uff09\u3002 \u6bcf\u4e2aLinux\u7cfb\u7edf\u90fd\u6709\u4e00\u4e2a\u7279\u6743\u7528\u6237\uff0c\u5373 root \u7528\u6237\u3002 root \u662f\u7cfb\u7edf\u7ba1\u7406\u5458\u3002 \u6b64\u7528\u6237\u7684UID\u59cb\u7ec8\u4e3a0\u3002 \u666e\u901a\u7528\u6237\u7684UID\u7f16\u53f7\uff08\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff09\u4e3a1000\u3002 \u6bcf\u4e2a\u7ec4\u4e5f\u5206\u914d\u4e86\u4e00\u4e2a\u79f0\u4e3a\u7ec4ID\uff08GID\uff09\u7684\u7f16\u53f7\u3002 \u6bcf\u4e2a\u7528\u6237\u6709\u4e00\u4e2a\u4e3b\u8981\u7ec4\uff08primary group\uff09\uff0c\u6709\u96f6\u4e2a\u6216\u8005\u4efb\u610f\u4e2a\u9644\u52a0\u7ec4\uff08supplementary group\uff09\u3002 \u4ee5openSUSE\u4e3a\u4f8b\uff1a UID 0: root 1 \u2013 99: System 100 \u2013 499: System accounts \u2265 1000: Normal (unprivileged) accounts GID 0: root 1 \u2013 99: System Groups 100 \u2013 499: Dynamically Allocated System Groups \u2265 1000: Normal Groups \u4e3e\u4f8b\uff1a $ id postfix uid = 51 ( postfix ) gid = 51 ( postfix ) groups = 482 ( mail ) ,59 ( maildrop ) ,51 ( postfix ) $ id vagrant uid = 1000 ( vagrant ) gid = 478 ( wheel ) groups = 0 ( root ) ,478 ( wheel ) \u63d0\u793a\uff1a UID\u548cGID\u7b49\u7f16\u53f7\u89c4\u5219\uff0c\u662f\u5728\u6587\u4ef6 /etc/login.defs \u4e2d\u7ea6\u5b9a\u7684\u3002","title":"1.\u7528\u6237\u3001\u7ec4\u3001\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#2selinux","text":"Security-Enhanced Linux (SELinux) \u662f\u4e00\u79cdLinux\u7cfb\u7edf\u7684\u5b89\u5168\u67b6\u6784\uff0c\u5b83\u5141\u8bb8\u7ba1\u7406\u5458\u66f4\u597d\u5730\u63a7\u5236\u8c01\u53ef\u4ee5\u8bbf\u95ee\u7cfb\u7edf\u3002 SELinux\u4e8e2000\u5e74\u5411\u5f00\u6e90\u793e\u533a\u53d1\u5e03\uff0c\u5e76\u4e8e2003\u5e74\u96c6\u6210\u5230\u4e0a\u6e38 Linux \u5185\u6838\u4e2d\u3002 SELinux\u4e3a\u7cfb\u7edf\u4e0a\u7684\u5e94\u7528\u7a0b\u5e8f\u3001\u8fdb\u7a0b\u548c\u6587\u4ef6\u5b9a\u4e49\u4e86\u8bbf\u95ee\u63a7\u5236\u3002 \u5b83\u4f7f\u7528\u5b89\u5168\u7b56\u7565\uff08\u4e00\u7ec4\u89c4\u5219\u544a\u8bc9SELinux\u4ec0\u4e48\u53ef\u4ee5\u8bbf\u95ee\u6216\u4e0d\u53ef\u4ee5\u8bbf\u95ee\uff09\u6765\u5f3a\u5236\u6267\u884c\u7b56\u7565\u5141\u8bb8\u7684\u8bbf\u95ee\u3002 \u5f53\u79f0\u4e3a\u4e3b\u4f53\uff08subject\uff09\u7684\u5e94\u7528\u7a0b\u5e8f\u6216\u8fdb\u7a0b\u8bf7\u6c42\u8bbf\u95ee\u5bf9\u8c61\uff08\u5982\u6587\u4ef6\uff09\u65f6\uff0cSELinux\u4f1a\u68c0\u67e5\u8bbf\u95ee\u5411\u91cf\u7f13\u5b58(AVC, Access Vector Cache)\uff0c\u5176\u4e2d\u7f13\u5b58\u4e86\u4e3b\u4f53\u548c\u5bf9\u8c61\u7684\u6743\u9650\u3002 \u5982\u679cSELinux\u65e0\u6cd5\u6839\u636e\u7f13\u5b58\u7684\u6743\u9650\u505a\u51fa\u8bbf\u95ee\u51b3\u5b9a\uff0c\u5b83\u4f1a\u5c06\u8bf7\u6c42\u53d1\u9001\u5230\u5b89\u5168\u670d\u52a1\u5668\u3002 \u5b89\u5168\u670d\u52a1\u5668\u68c0\u67e5\u5e94\u7528\u7a0b\u5e8f\u6216\u8fdb\u7a0b\u548c\u6587\u4ef6\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\u3002 \u4eceSELinux\u7b56\u7565\u6570\u636e\u5e93\u5e94\u7528\u5b89\u5168\u4e0a\u4e0b\u6587\uff08Security context\uff09\uff0c\u7136\u540e\u6388\u4e88\u6216\u62d2\u7edd\u8bb8\u53ef\u3002 \u5982\u679c\u6743\u9650\u88ab\u62d2\u7edd\uff0c avc: denied \u6d88\u606f\u5c06\u5728 /var/log.messages \u4e2d\u4f53\u73b0\u3002 \u4f20\u7edf\u4e0a\uff0cLinux\u548cUNIX\u7cfb\u7edf\u90fd\u4f7f\u7528DAC\uff08Discretionary Access Control\uff09\u3002 SELinux\u662fLinux\u7684MAC\uff08Mandatory Access Control\uff09\u7cfb\u7edf\u7684\u4e00\u4e2a\u793a\u4f8b\u3002 \u5728DAC\u65b9\u5f0f\u4e0b\uff0c\u6587\u4ef6\u548c\u8fdb\u7a0b\u6709\u81ea\u5df1\u7684\u5c5e\u4e3b\uff08\u6240\u6709\u8005\uff09\u3002 \u7528\u6237\u53ef\u4ee5\u62e5\u6709\u4e00\u4e2a\u6587\u4ef6\uff0c\u4e00\u4e2a\u7ec4\u4e5f\u53ef\u4ee5\u62e5\u6709\u4e00\u4e2a\u6587\u4ef6\uff0c\u6216\u8005\u5176\u4ed6\u4eba\u3002 \u7528\u6237\u53ef\u4ee5\u66f4\u6539\u81ea\u5df1\u6587\u4ef6\u7684\u6743\u9650\u3002 root \u7528\u6237\u5bf9DAC\u7cfb\u7edf\u5177\u6709\u5b8c\u5168\u8bbf\u95ee\u63a7\u5236\u6743\u3002 \u4f46\u662f\u5728\u50cfSELinux\u8fd9\u6837\u7684MAC\u7cfb\u7edf\u4e0a\uff0c\u5bf9\u4e8e\u8bbf\u95ee\u7684\u7ba1\u7406\u662f\u901a\u8fc7\u8bbe\u7f6e\u7b56\u7565\u6765\u5b9e\u73b0\u7684\u3002\u5373\u4f7f\u7528\u6237\u4e3b\u76ee\u5f55\u4e0a\u7684DAC\u8bbe\u7f6e\u53d1\u751f\u66f4\u6539\uff0c\u7528\u4e8e\u9632\u6b62\u5176\u4ed6\u7528\u6237\u6216\u8fdb\u7a0b\u8bbf\u95ee\u8be5\u76ee\u5f55\u7684SELinux\u7b56\u7565\u4e5f\u5c06\u7ee7\u7eed\u786e\u4fdd\u7cfb\u7edf\u5b89\u5168\u3002 MAC\u65b9\u5f0f\u662f\u63a7\u5236\u4e00\u4e2a\u8fdb\u7a0b\u5bf9\u5177\u4f53\u6587\u4ef6\u7cfb\u7edf\u4e0a\u9762\u7684\u6587\u4ef6\u6216\u76ee\u5f55\u662f\u5426\u62e5\u6709\u8bbf\u95ee\u6743\u9650\u3002\u5224\u65ad\u8fdb\u7a0b\u662f\u5426\u53ef\u4ee5\u8bbf\u95ee\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u4f9d\u636e\uff0c\u53d6\u51b3\u4e8eSELinux\u4e2d\u8bbe\u5b9a\u7684\u5f88\u591a\u7b56\u7565\u89c4\u5219\u3002 \u8bbf\u95ee\u63a7\u5236\u5217\u8868 (ACL\uff0cAccess Control List) \u4e3a\u6587\u4ef6\u7cfb\u7edf\u63d0\u4f9b\u4e86\u4e00\u79cd\u989d\u5916\u7684\u3001\u66f4\u7075\u6d3b\u7684\u6743\u9650\u673a\u5236\u3002 \u5b83\u65e8\u5728\u534f\u52a9 UNIX \u6587\u4ef6\u6743\u9650\u3002ACL\u5141\u8bb8\u6388\u4e88\u4efb\u4f55\u7528\u6237\u6216\u7ec4\u5bf9\u4efb\u4f55\u78c1\u76d8\u8d44\u6e90\u7684\u6743\u9650\u3002ACL\u9002\u7528\u4e8e\u5728\u4e0d\u4f7f\u67d0\u4e2a\u7528\u6237\u6210\u4e3a\u7ec4\u6210\u5458\u7684\u60c5\u51b5\u4e0b\uff0c\u4ecd\u65e7\u6388\u4e88\u4e00\u4e9b\u8bfb\u6216\u5199\u8bbf\u95ee\u6743\u9650\u3002 \u4e0b\u9762\u793a\u4f8b\u5bf9\u6bd4\u8bf4\u660e\u4e86SELinux\u548cACL\u5728\u6587\u4ef6\u5c5e\u6027\u5c55\u73b0\u4e0a\u7684\u7279\u70b9\u3002 -rwxr-xr-- vagrant wheel \uff1a\u6ca1\u6709selinux\u4e0a\u4e0b\u6587\uff0c\u6ca1\u6709ACL -rwx--xr-x+ vagrant wheel \uff1a\u53ea\u6709ACL\uff0c\u6ca1\u6709selinux\u4e0a\u4e0b\u6587 -rw-r--r--. vagrant wheel \uff1a\u53ea\u6709selinux\u4e0a\u4e0b\u6587\uff0c\u6ca1\u6709ACL -rwxrwxr--+ vagrant wheel \uff1a\u6709selinux\u4e0a\u4e0b\u6587\uff0c\u6709ACL","title":"2.SELinux"},{"location":"linux/SRE/03-identity-security/#21selinux","text":"\u7528\u6237(Users)\uff1a SELinux\u7684\u7528\u6237\u4e0d\u7b49\u540c\u4e0eLinux\u7528\u6237\u3002 SELinux\u7528\u6237\u4ee5\u540e\u7f00 _u \u7ed3\u5c3e\u3002 \u89d2\u8272(Roles)\uff1a \u89d2\u8272Roles\u662f\u7531\u7b56\u7565Policies\u5b9a\u4e49\u7684\uff0c\u89d2\u8272\u51b3\u5b9a\u4e86\u4f7f\u7528\u54ea\u4e2a\u7b56\u7565\u3002 SELinux\u89d2\u8272\u4ee5\u540e\u7f00 _r \u7ed3\u5c3e\u3002 \u7c7b\u578b(Types)\uff1a SELinux\u662f\u7c7b\u578b\u5f3a\u5236\u7684\uff0c\u7c7b\u578bTypes\u51b3\u5b9a\u8fdb\u7a0b\u80fd\u5426\u8bbf\u95ee\u67d0\u4e2a\u6587\u4ef6\u3002 SELinux\u7c7b\u578b\u662f\u4ee5\u540e\u7f00 _t \u7ed3\u5c3e\u3002 \u4e0a\u4e0b\u6587(Contexts)\uff1a \u7528\u6765\u6807\u8bb0\u8fdb\u7a0b\u548c\u6587\u4ef6\u3002\u5206\u522b\u662f\u7528\u6237Users\uff0c\u89d2\u8272Roles\uff0c\u7c7b\u578bTypes\uff0c\u8303\u56f4Ranges\u3002 \u683c\u5f0f\uff1a user:role:type:range \u6587\u4ef6\u7c7b\u578b(Object Classes)\uff1a \u6bcf\u4e2a\u6587\u4ef6\u7c7b\u578bTypes\u90fd\u5bf9\u5e94\u4e00\u5957\u7b56\u7565Policies\u3002\u7b56\u7565Policies\u51b3\u5b9a\u4e86\u8fdb\u7a0b\u5bf9\u8fd9\u7c7b\u6587\u4ef6\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u8bbf\u95ee\u6743\u9650\u67094\u79cd\uff1a \u521b\u5efacreate \u8bfb\u53d6read \u5199\u5165write \u5220\u9664unlink\uff08\u6ce8\u610f\uff0c\u8fd9\u91cc\u4e0d\u662f\u94fe\u63a5\u7684\u610f\u601d\uff09 \u89c4\u5219(Rules) \u683c\u5f0f\uff1a allow user_t user_home_t:file {create read write unlink}; \u542b\u4e49\uff1a user_t \u7c7b\u578b\u5bf9 user_home_t \u7c7b\u578b\u6709\u521b\u5efacreate\uff0c\u8bfb\u53d6read\uff0c\u5199\u5165write\uff0c\u5220\u9664unlink\u6743\u9650\u3002","title":"2.1.SELinux\u4e3b\u8981\u6982\u5ff5"},{"location":"linux/SRE/03-identity-security/#22selinux-in-opensuse","text":"\u4f5c\u4e3aSELinux\u7684\u66ff\u4ee3\u54c1\uff0c2005\u5e74\u88abNovell\u6536\u8d2d\u7684Immunix\u516c\u53f8\u5f00\u53d1\u4e86AppArmor\u3002SUSE\u5728openSUSE Leap\u4e2d\u63d0\u4f9b\u5bf9SELinux\u6846\u67b6\u7684\u652f\u6301\u3002\u8fd9\u5e76\u4e0d\u610f\u5473\u7740openSUSE Leap\u7684\u9ed8\u8ba4\u5b89\u88c5\u4f1a\u5728\u4e0d\u4e45\u7684\u5c06\u6765\u4eceAppArmor\u5207\u6362\u5230SELinux\u3002 \u6dfb\u52a0SELinux\u7684\u6e90\u3002\u53ef\u4ee5\u4ece https://download.opensuse.org/repositories/security:/SELinux/ \u4e0b\u8f7d\u5bf9\u5e94\u7684\u7b56\u7565policy\u3002 sudo zypper ar -f https://download.opensuse.org/repositories/security:/SELinux/openSUSE_Factory/ Security-SELinux \u5b89\u88c5C++\u7b49\u57fa\u7840\u5f00\u53d1\u5305\uff1a # \u5217\u51fa\u5f53\u524d\u53ef\u5b89\u88c5\u7684Pattern sudo zypper pt # \u5b89\u88c5\u4e0b\u9762\u51e0\u4e2a\u5f00\u53d1\u76f8\u5173\u7684Pattern sudo zypper in -t pattern devel_C_C++ devel_basis devel_kernel \u5b89\u88c5SELinux packages\uff1a zypper se --search-descriptions selinux sudo zypper in restorecond policycoreutils setools-console sudo zypper in selinux-tools libselinux-devel \u5b89\u88c5SELinux policy\uff1a sudo zypper in selinux-policy-targeted selinux-policy-devel selinux-autorelabel \u66f4\u65b0GRUB2 bootloader\uff08GRUB2\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\uff09\uff1a \u7f16\u8f91\u6587\u4ef6 /etc/default/grub \uff0c\u6dfb\u52a0\u4e0b\u9762\u5185\u5bb9\u5230 GRUB_CMDLINE_LINUX_DEFAULT= \u8fd9\u4e00\u884c\uff1a security = selinux selinux = 1 \u8bb0\u5f55\u8fd9\u4e00\u884c\u7684\u539f\u59cb\u4fe1\u606f\uff1a GRUB_CMDLINE_LINUX_DEFAULT = \"splash=silent resume=/dev/disk/by-uuid/47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 preempt=full mitigations=auto quiet security=apparmor\" \u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u751f\u6210\u65b0\u7684GRUB2\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\u914d\u7f6e\u6587\u4ef6\u3002 sudo grub2-mkconfig -o /boot/grub2/grub.cfg \u7f16\u8f91\u6587\u4ef6 /etc/selinux/config \u5e76\u8bbe\u7f6e SELINUX=permissive \u6765\u542f\u7528SElinux\u3002\u8fd9\u4e0e\u524d\u9762GRUB2\u7684\u542f\u52a8\u914d\u7f6e\u662f\u4e00\u81f4\u7684\u3002 \u5982\u6587\u4ef6\u4e0d\u5b58\u5728\uff0c\u5219\u521b\u5efa\u3002 $ sudo cat /etc/selinux/config SELINUX = permissive SELINUXTYPE = targeted \u91cd\u542f\u7cfb\u7edf\u3002\u7cfb\u7edf\u542f\u52a8\u53ef\u80fd\u9700\u8981\u4e00\u4e9b\u65f6\u95f4\uff0cSELinux\u9700\u8981\u7ed9\u6574\u4e2a\u6587\u4ef6\u7cfb\u7edf\u91cd\u65b0\u8fdb\u884c\u6807\u7b7e\u5316\u3002 \u91cd\u542f\u540e\uff0c\u8fd0\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u6765\u67e5\u770bSELinux\u662f\u5426\u8fd0\u884c\u6b63\u5e38\u3002 $ sudo getenforce Permissive $ sudo sestatus -v SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted Current mode: permissive Mode from config file: permissive Policy MLS status: enabled Policy deny_unknown status: allowed Memory protection checking: requested ( insecure ) Max kernel policy version: 33 Process contexts: Current context: unconfined_u:unconfined_r:unconfined_t:s0 Init context: system_u:system_r:kernel_t:s0 /sbin/agetty system_u:system_r:kernel_t:s0 /usr/sbin/sshd system_u:system_r:kernel_t:s0 File contexts: Controlling terminal: unconfined_u:object_r:devpts_t:s0 /etc/passwd system_u:object_r:unlabeled_t:s0 /etc/shadow system_u:object_r:unlabeled_t:s0 /bin/bash system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /bin/login system_u:object_r:unlabeled_t:s0 /bin/sh system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /sbin/agetty system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /sbin/init system_u:object_r:unlabeled_t:s0 -> system_u:object_r:unlabeled_t:s0 /usr/sbin/sshd system_u:object_r:unlabeled_t:s0 \u53c2\u8003\uff1a GRUB2\u5f15\u5bfc\u52a0\u8f7d\u7a0b\u5e8f\u4e2d\u6dfb\u52a0\u7684\u4e09\u4e2a\u53c2\u6570\u7684\u89e3\u91ca\uff1a security=selinux : This option tells the kernel to use SELinux and not AppArmor. selinux=1 : This option switches on SELinux. enforcing=0 : This option puts SELinux in permissive mode. In this mode, SELinux is fully functional, but does not enforce any of the security settings in the policy. Use this mode for testing and configuring your system. To switch on SELinux protection, when the system is fully operational, change the option to enforcing=1 and add SELINUX=enforcing in /etc/selinux/config . \u5c0f\u8d34\u58eb\uff1a \u5728\u9996\u6b21\u542f\u7528SELinux\u540e\uff0c\u5982\u679c\u53ea\u5728grub2\u91cc\u9762\u6dfb\u52a0selinux=1\uff0c\u901a\u8fc7 getenforce \u547d\u4ee4\u770b\u7684SELinux\u4e00\u76f4\u5c31\u662fdisabled\u7684\u72b6\u6001\uff0c\u9700\u8981\u624b\u5de5\u521b\u5efa/etc/selinux/config\u6587\u4ef6\u6dfb\u52a0\u914d\u7f6e\u624d\u884c\u3002\u611f\u89c9grub2\u91cc\u9762\u65e0\u9700\u8bbe\u7f6e\uff0c\u76f4\u63a5\u914d\u7f6e/etc/selinux/config\u6587\u4ef6\u3002\u4e0d\u786e\u5b9a\u8fd9\u4e2a\u60f3\u6cd5\u662f\u5426\u6b63\u786e\u3002 \u5728grub2\u4e2d\u8bbe\u5b9aselinux=1\uff0c\u5728/etc/selinux/config\u6587\u4ef6\u4e2d\uff1a \u8bbe\u5b9aSELINUX=permissive\uff0c\u91cd\u542f\u540e\u901a\u8fc7 getenforce \u547d\u4ee4\u770b\u5230\u7684\u662fpermissive\u3002 \u8bbe\u5b9aSELINUX=disabled\uff0c\u5219\u91cd\u542f\u540e getenforce \u547d\u4ee4\u770b\u5230\u7684\u662fdisabled\u3002 \u8fd9\u8bf4\u660e\u914d\u7f6e\u6587\u4ef6\u540e\u542f\u52a8\uff0c\u8986\u76d6\u4e86\u5185\u6838\u8bbe\u7f6e\u3002 \u6ce8\u610f\uff0c\u5982\u679c\u4ec5\u4ec5\u5b8c\u6210\u4e86\u4e0a\u9762\u7684enable SELinux\uff0c\u7acb\u523b\u8bbe\u5b9aSELINUX=enforcing\uff0c\u4f1a\u5f15\u8d77ssh\u65e0\u6cd5\u767b\u5f55\uff0c\u9519\u8bef\u4fe1\u606f\u662f /bin/bash: Permission denied \u3002 \u914d\u7f6eSELinux\u3002 $ sudo semanage boolean -l Failed to use semanage \u6dfb\u52a0\u4e0b\u9762\u5185\u5bb9\u5230.bashrc\u6587\u4ef6\u3002 export PATH = /usr/local/bin:/home/ $USER /.local/bin: $PATH \u66f4\u65b0pip3. pip3 install --upgrade pip \u5b89\u88c5\u4e0b\u9762\u51e0\u4e2a\u5305 sudo zypper in libselinux libselinux-devel sudo zypper in python3-semanage sudo zypper in libsemanage-devel libsemanage-devel-static sudo zypper in policycoreutils-python-utils sudo zypper in cross-x86_64-linux-glibc-devel glibc-utils glibc-profile sudo zypper in policycoreutils-devel","title":"2.2.SELinux in openSUSE"},{"location":"linux/SRE/03-identity-security/#23selinux-in-ubuntu","text":"","title":"2.3.SELinux in Ubuntu"},{"location":"linux/SRE/03-identity-security/#24selinux-in-rocky","text":"","title":"2.4.SELinux in Rocky"},{"location":"linux/SRE/03-identity-security/#3","text":"/etc/passwd \uff1a\u7528\u6237\u53ca\u5176\u5c5e\u6027\u4fe1\u606f\uff08\u7528\u6237\u540d\uff0cUID\uff0c\u4e3b\u7ec4ID\u7b49\uff09 /etc/shadow \uff1a\u7528\u6237\u5bc6\u7801\u673a\u5668\u5c5e\u6027 /etc/group \uff1a\u7ec4\u53ca\u5176\u5c5e\u6027 /etc/gshadow \uff1a\u7ec4\u5bc6\u7801\u53ca\u5176\u5c5e\u6027","title":"3.\u7528\u6237\u548c\u7ec4\u7684\u914d\u7f6e\u6587\u4ef6"},{"location":"linux/SRE/03-identity-security/#31etcpasswd","text":"\u683c\u5f0f\u8bf4\u660e\uff1a vagrant:x:1001:474:vagrant:/home/vagrant:/bin/bash [ ----- ] - [ -- ] [ - ] [ ----- ] [ ----------- ] [ ------- ] | | | | | | +--------> 7 . Login shell | | | | | +--------------------> 6 . Home directory | | | | +-------------------------------> 5 . GECOS or the full name of the user | | | +-------------------------------------> 4 . GID | | +------------------------------------------> 3 . UID | +---------------------------------------------> 2 . Password +--------------------------------------------------> 1 . Username","title":"3.1./etc/passwd"},{"location":"linux/SRE/03-identity-security/#32etcshadow","text":"\u683c\u5f0f\u8bf4\u660e\uff1a vagrant: $6 $.n.:17736:0:99999:7::: [ ----- ] [ ---- ] [ --- ] - [ --- ] ---- | | | | | || | +-----------> 9 . Unused | | | | | || +------------> 8 . Expiration date since Jan 1 , 1970 | | | | | | +-------------> 7 . Inactivity period \u5bc6\u7801\u8fc7\u671f\u540e\u7684\u5bbd\u9650\u671f | | | | | +--------------> 6 . Warning period, default 7 days | | | | +------------------> 5 . Maximum password age | | | +----------------------> 4 . Minimum password age | | +--------------------------> 3 . Last password change since Jan 1 , 1970 | +---------------------------------> 2 . Encrypted Password +-------------------------------------------> 1 . Username","title":"3.2./etc/shadow"},{"location":"linux/SRE/03-identity-security/#33etcgroup","text":"\u683c\u5f0f\u8bf4\u660e\uff1a audio:x:492:pulse [ --- ] - [ - ] [ --- ] | | | +----> 4 . username-list, who have this group as their supplementary | | +---------> 3 . GID | +------------> 2 . group-password. Real password is in /etc/gshadow +----------------> 1 . groupname","title":"3.3./etc/group"},{"location":"linux/SRE/03-identity-security/#34etcgshadow","text":"\u683c\u5f0f\u8bf4\u660e\uff1a general:!!:shelley:juan,bob [ ----- ] -- [ ----- ] [ ------ ] | | | +-------> 4 . group members ( in a comma delimited list ) | | +---------------> 3 . group adminstrators ( in a comma delimited list ) | +---------------------> 2 . encrypted password. ` ! ` , ` !! ` , and null +---------------------------> 1 . group name Encrypted password ! \uff1ano user is allowed to access the group using the newgrp command. !! \uff1athe same as a value of ! \u2014 however, it also indicates that a password has never been set before. null\uff1aonly group members can log into the group.","title":"3.4./etc/gshadow"},{"location":"linux/SRE/03-identity-security/#35","text":"# \u901a\u8fc7`/dev/urandom`\u751f\u6210\u968f\u673a\u6570\uff0c\u901a\u8fc7`tr -dc`\u8fc7\u6ee4\u968f\u673a\u6570\uff0c\u53ea\u4fdd\u7559\u5b57\u6bcd\u548c\u6570\u5b57\uff0c\u901a\u8fc7`head -c`\u4fdd\u7559\u6307\u5b9a\u4f4d\u6570 $ tr -dc '[:alnum:]' < /dev/urandom | head -c 12 xFw7vfma54D8 $ openssl rand -base64 9 I5TZXJfpd3Pg","title":"3.5.\u751f\u6210\u968f\u673a\u5bc6\u7801"},{"location":"linux/SRE/03-identity-security/#36vipwvigrpwckgrpck","text":"vipw \u548c vigr \u547d\u4ee4\u5206\u522b\u7f16\u8f91\u6587\u4ef6 /etc/passwd \u548c /etc/group \u3002 \u5982\u679c\u6307\u5b9a\u4e86 -s \u6807\u5fd7\uff0c\u8fd9\u4e9b\u547d\u4ee4\u5c06\u5206\u522b\u7f16\u8f91\u5176\u6587\u4ef6\u7684\u5f71\u5b50\uff08\u5b89\u5168\uff09\u7248\u672c\uff1a /etc/shadow \u548c /etc/gshadow \u3002 vipw \u548c vigr \u547d\u4ee4\u5728\u7f16\u8f91\u6587\u4ef6\u65f6\u4f1a\u8bbe\u7f6e\u9501\u4ee5\u9632\u6b62\u6587\u4ef6\u635f\u574f\u3002 vipw \u548c vigr \u547d\u4ee4\u4f1a\u9996\u5148\u5c1d\u8bd5\u73af\u5883\u53d8\u91cf $VISUAL \uff0c\u7136\u540e\u662f\u73af\u5883\u53d8\u91cf $EDITOR \uff0c\u6700\u540e\u662f\u9ed8\u8ba4\u7f16\u8f91\u5668 vi \u3002 sudo vipw sudo vipw -s sudo vigr sudo vigr -s pwck \u547d\u4ee4\u5b9e\u73b0\u9a8c\u8bc1\u7cfb\u7edf\u8ba4\u8bc1\u4fe1\u606f\u7684\u5b8c\u6574\u6027\u3002 \u68c0\u67e5 /etc/passwd \u548c /etc/shadow \u4e2d\u7684\u6240\u6709\u6761\u76ee\u6bcf\u4e2a\u5b57\u6bb5\u662f\u5426\u5177\u6709\u6b63\u786e\u7684\u683c\u5f0f\u548c\u6709\u6548\u6570\u636e\u3002 \u7cfb\u7edf\u4f1a\u63d0\u793a\u7528\u6237\u5220\u9664\u683c\u5f0f\u4e0d\u6b63\u786e\u6216\u5b58\u5728\u5176\u4ed6\u9519\u8bef\u7684\u6761\u76ee\u3002 pwck \u8fd4\u56de\u503c\uff1a 0 : success 1 : invalid command syntax 2 : one or more bad password entries 3 : can\u2019t open password files 4 : can\u2019t lock password files 5 : can\u2019t update password files grpck \u547d\u4ee4\u5b9e\u73b0\u9a8c\u8bc1\u7cfb\u7edf\u8ba4\u8bc1\u4fe1\u606f\u7684\u5b8c\u6574\u6027\u3002 \u68c0\u67e5 /etc/group \u548c /etc/gshadow \u4e2d\u7684\u6240\u6709\u6761\u76ee\u6bcf\u4e2a\u5b57\u6bb5\u662f\u5426\u5177\u6709\u6b63\u786e\u7684\u683c\u5f0f\u548c\u6709\u6548\u6570\u636e\u3002 \u7cfb\u7edf\u4f1a\u63d0\u793a\u7528\u6237\u5220\u9664\u683c\u5f0f\u4e0d\u6b63\u786e\u6216\u5b58\u5728\u5176\u4ed6\u9519\u8bef\u7684\u6761\u76ee\u3002 grpck \u8fd4\u56de\u503c\uff1a 0 : success 1 : invalid command syntax 2 : one or more bad group entries 3 : can\u2019t open group files 4 : can\u2019t lock group files 5 : can\u2019t update group files","title":"3.6.vipw/vigr/pwck/grpck\u547d\u4ee4"},{"location":"linux/SRE/03-identity-security/#4","text":"\u7528\u6237\u7ba1\u7406\u547d\u4ee4\uff1a useradd usermod userdel","title":"4.\u7528\u6237\u7ba1\u7406"},{"location":"linux/SRE/03-identity-security/#41useradd","text":"\u4e3e\u4f8b\uff1a # \u666e\u901a\u7528\u6237 $ useradd -m -g wheel -G root -c \"vagrant\" vagrant # \u975e\u4ea4\u4e92\u7528\u6237 $ useradd -r -u 48 -g apache -d /var/www -s /sbin/nologin -g postfix -c \"Apache\" apache 2 >/dev/null useradd \u547d\u4ee4\u7684\u9ed8\u8ba4\u503c\u662f\u5728 /etc/default/useradd \u6587\u4ef6\u4e2d\u8bbe\u5b9a\u3002 openSUSE\u7684 /etc/default/useradd \u6587\u4ef6\u5185\u5bb9\uff1a GROUP = 100 HOME = /home INACTIVE = -1 # \u5bf9\u5e94/etc/shadow\u6587\u4ef6\u7b2c7\u5217\uff0cInactivity period\uff0c\u5bc6\u7801\u8fc7\u671f\u540e\u7684\u5bbd\u9650\u671f\uff0c-1\u8868\u793a\u4e0d\u9650\u5236 EXPIRE = # \u5bf9\u5e94/etc/shadow\u6587\u4ef6\u7b2c8\u5217\uff0cExpiration date since Jan 1, 1970\uff0c\u5373\u8d26\u53f7\u6709\u6548\u671f SHELL = /bin/bash SKEL = /etc/skel # \u7528\u4e8e\u751f\u6210\u7528\u6237\u4e3b\u76ee\u5f55\u7684\u6a21\u7248\u6587\u4ef6 USRSKEL = /usr/etc/skel CREATE_MAIL_SPOOL = yes Rocky\u7684 /etc/default/useradd \u6587\u4ef6\u5185\u5bb9\uff1a GROUP = 100 HOME = /home INACTIVE = -1 EXPIRE = SHELL = /bin/bash SKEL = /etc/skel CREATE_MAIL_SPOOL = yes \u5728Ubuntu\u4e2d /etc/default/useradd \u6587\u4ef6\u53ea\u6709\u4e0b\u9762\u8fd9\u4e00\u884c\u3002 SHELL = /bin/sh","title":"4.1.\u521b\u5efa\u7528\u6237useradd"},{"location":"linux/SRE/03-identity-security/#411newusers","text":"\u683c\u5f0f\uff1a newusers \u3002\u5176\u4e2d\u6587\u4ef6 \u7684\u683c\u5f0f\u5982\u4e0b\uff1a :::::: \u4e3e\u4f8b\uff0c\u521b\u5efa\u6587\u4ef6 users.txt \uff1a $ cat ~/users.txt tester1:123:600:1530: \"Test User1,testuser1@abc.com\" :/home/tester1:/bin/bash tester2:123:601:1529:::/bin/bash tester3:123::::: tester4:123::::/home/tester4:/bin/tsh \u770b\u7ed3\u679c\uff1a $ cat /etc/passwd | grep tester tester1:x:600:1530: \"Test User1,testuser1@abc.com\" :/home/tester1:/bin/bash tester2:x:601:1529:::/bin/bash tester3:x:1001:1001::: tester4:x:1002:1002::/home/tester4:/bin/tsh $ cat /etc/group | grep tester tester1:*:1530: tester2:*:1529: tester3:*:1001: tester4:*:1002: $ sudo cat /etc/shadow | grep tester tester1:!:19321:0:99999:7::: tester2:!:19321:0:99999:7::: tester3:!:19321:0:99999:7::: tester4:!:19321:0:99999:7::: $ ls -ld /home/tester* drwxr-xr-x. 1 tester1 tester1 0 Nov 26 00 :32 /home/tester1 drwxr-xr-x. 1 tester4 tester4 0 Nov 26 00 :32 /home/tester4","title":"4.1.1.\u6279\u91cf\u521b\u5efa\u7528\u6237newusers"},{"location":"linux/SRE/03-identity-security/#412chpasswd","text":"\u4e0d\u540c\u65b9\u6cd5\uff1a echo username:password | chpasswd chpasswd < file.txt # file.txt\u6bcf\u884c\u7684\u683c\u5f0f\u662fusername:password paste -d \":\" user.txt passwd.txt | chpasswd \u53c2\u6570 -e \uff1a\u53e3\u4ee4\u4ee5\u52a0\u5bc6\u7684\u65b9\u5f0f\u4f20\u9012\u3002\u5426\u5219\u53e3\u4ee4\u4ee5\u660e\u6587\u7684\u5f62\u5f0f\u4f20\u9012\u3002 \u6ce8\u610f\uff1a \u7528\u6237\u540dusername\u5fc5\u987b\u662f\u5df2\u5b58\u5728\u7684\u7528\u6237 \u666e\u901a\u7528\u6237\u6ca1\u6709\u4f7f\u7528\u8fd9\u4e2a\u6307\u4ee4\u7684\u6743\u9650 \u5982\u679c\u8f93\u5165\u6587\u4ef6\u662f\u6309\u975e\u52a0\u5bc6\u65b9\u5f0f\u4f20\u9012\u7684\u8bdd\uff0c\u8bf7\u5bf9\u8be5\u6587\u4ef6\u8fdb\u884c\u9002\u5f53\u7684\u52a0\u5bc6\u3002 \u6307\u4ee4\u6587\u4ef6\u4e0d\u80fd\u6709\u7a7a\u884c \u4e3e\u4f8b\uff1a echo tester1:112233 | sudo chpasswd $ cat chpasswd.txt tester1:112233 tester2:33445566 $ sudo chpasswd < chpasswd.txt","title":"4.1.2.\u6279\u91cf\u4fee\u6539\u5bc6\u7801chpasswd"},{"location":"linux/SRE/03-identity-security/#413openssl-passwd","text":"\u547d\u4ee4 openssl passwd \u683c\u5f0f\u53ef\u4ee5\u5982\u4e0b\u65b9\u6cd5\u83b7\u5f97\u3002 $ man -f passwd passwd ( 1 ) - change user password passwd ( 1ssl ) - compute password hashes passwd ( 5 ) - password file $ man passwd Man: find all matching manual pages ( set MAN_POSIXLY_CORRECT to avoid this ) * passwd ( 1 ) passwd ( 5 ) passwd ( 1ssl ) Man: What manual page do you want? Man: 1ssl \u4e3e\u4f8b\uff08\u8fd9\u91cc\u7528 \u4ee3\u66ff\u5b9e\u9645\u5bc6\u7801\uff09\uff1a # \u57fa\u4e8e\u7ed9\u5b9a\u5b57\u4e32newpasswd\u751f\u6210sha256\u52a0\u5bc6\u7801\uff0c $ openssl passwd -6 newpasswd # \u521b\u5efa\u65b0\u7528\u6237tester5\uff0c\u8d4b\u4e88\u52a0\u5bc6\u5bc6\u7801 $ useradd -p '' tester1 # \u8bfb\u53d6\u7528\u6237tester5\u7684\u5bc6\u7801\uff0c\u53ef\u4ee5\u9a8c\u8bc1\u662f\u5426\u548c\u4e4b\u524d\u7684\u4e00\u81f4 $ sudo getent shadow tester5 tester5::19321:0:99999:7:::","title":"4.1.3.\u751f\u6210\u52a0\u5bc6\u5bc6\u7801openssl passwd"},{"location":"linux/SRE/03-identity-security/#42usermod","text":"\u6dfb\u52a0\u7528\u6237\u5230\u9644\u52a0\u7ec4 usermod -a -G GROUP USER usermod -a -G GROUP1,GROUP2,GROUP3 USER \u4fee\u6539\u7528\u6237\u4e3b\u7ec4 usermod -a -g GROUP USER \u4fee\u6539\u7528\u6237\u4fe1\u606f usermod -c \"GECOS Comments\" USER \u4fee\u6539\u7528\u6237\u4e3b\u76ee\u5f55\uff0c\u4f7f\u7528\u7edd\u5bf9\u8def\u5f84\uff0c -m \u53c2\u6570\u4f1a\u628a\u539f\u4e3b\u76ee\u5f55\u7684\u5185\u5bb9\u79fb\u52a8\u5230\u65b0\u4e3b\u76ee\u5f55\u3002 usermod -d NEW_HOME_DIR USER usermod -d NEW_HOME_DIR -m USER \u4fee\u6539\u7528\u6237shell usermod -s SHELL USER \u4fee\u6539\u7528\u6237UID usermod -u UID USER \u4fee\u6539\u7528\u6237\u540d\uff08\u4e0d\u5e38\u7528\uff09\uff0c\u540c\u65f6\u4e5f\u9700\u8981\u4fee\u6539\u7528\u6237\u4e3b\u76ee\u5f55\u3002 usermod -l NEW_USER USER \u4fee\u6539\u7528\u6237\u8fc7\u671f\u5c5e\u6027\uff0c\u65e5\u671f\u683c\u5f0f\u662f YYYY-MM-DD usermod -e DATE USER \u5982\u679c\u8bbe\u5b9a\u6c38\u4e0d\u8fc7\u671f\uff0c\u5219\u7f6e\u7a7a\u65e5\u671f\uff1a usermod -e \"\" USER \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684\u8fc7\u671f\u65e5\u671f $ sudo chage -l vagrant Last password change : Oct 30 , 2022 Password expires : never Password inactive : never Account expires : never Minimum number of days between password change : 0 Maximum number of days between password change : 99999 Number of days of warning before password expires : 7 \u9501\u5b9a\u7528\u6237\u3002 \u6b64\u547d\u4ee4\u5c06\u5728\u52a0\u5bc6\u5bc6\u7801\u524d\u63d2\u5165\u4e00\u4e2a\u611f\u53f9\u53f7 (!) \u6807\u8bb0\u3002 \u5f53 /etc/shadow \u6587\u4ef6\u4e2d\u7684\u5bc6\u7801\u5b57\u6bb5\u5305\u542b\u611f\u53f9\u53f7\u65f6\uff0c\u7528\u6237\u5c06\u65e0\u6cd5\u4f7f\u7528\u5bc6\u7801\u9a8c\u8bc1\u767b\u5f55\u7cfb\u7edf\u3002 \u5176\u4ed6\u767b\u5f55\u65b9\u6cd5\u4ecd\u7136\u5141\u8bb8\uff0c\u4f8b\u5982\u57fa\u4e8e\u5bc6\u94a5\u7684\u8eab\u4efd\u9a8c\u8bc1\u6216\u5207\u6362\u5230\u7528\u6237\u3002 \u5982\u679c\u8981\u9501\u5b9a\u8d26\u6237\u5e76\u7981\u7528\u6240\u6709\u767b\u5f55\u65b9\u5f0f\uff0c\u8fd8\u9700\u8981\u5c06\u5230\u671f\u65e5\u671f\u8bbe\u7f6e\u4e3a1\u3002 usermod -L USER usermod -L -e 1 USER \u89e3\u9501\u7528\u6237 usermod -U USER","title":"4.2.\u4fee\u6539\u7528\u6237\u5c5e\u6027usermod"},{"location":"linux/SRE/03-identity-security/#43userdel","text":"userdel \u547d\u4ee4\u6267\u884c\u65f6\uff0c\u4f1a\u8bfb\u53d6 /etc/login.defs \u6587\u4ef6\u7684\u5185\u5bb9\u3002 \u6b64\u6587\u4ef6\u4e2d\u5b9a\u4e49\u7684\u5c5e\u6027\u4f1a\u8986\u76d6 userdel \u7684\u9ed8\u8ba4\u884c\u4e3a\u3002 \u5982\u679c\u5728\u6b64\u6587\u4ef6\u4e2d\u5c06 USERGROUPS_ENAB \u8bbe\u7f6e\u4e3a yes \uff0c userdel \u5c06\u5220\u9664\u4e0e\u7528\u6237\u540c\u540d\u7684\u7ec4\uff0c\u524d\u63d0\u662f\u6ca1\u6709\u5176\u4ed6\u7528\u6237\u662f\u8be5\u7ec4\u7684\u6210\u5458\u3002 userdel \u547d\u4ee4\u4ece /etc/passwd \u548c /etc/shadow \u6587\u4ef6\u4e2d\u5220\u9664\u7528\u6237\u6761\u76ee\u3002 userdel \u547d\u4ee4\u5220\u9664\u7528\u6237\u5e10\u6237\u65f6\uff0c\u4e00\u822c\u4e0d\u4f1a\u5220\u9664\u7528\u6237\u4e3b\u76ee\u5f55\u548c\u90ae\u4ef6\u5047\u8131\u673amail spool\u76ee\u5f55\u3002 \u4f7f\u7528 -r \u9009\u9879\u5f3a\u5236\u5220\u9664\u7528\u6237\u7684\u4e3b\u76ee\u5f55\u548c\u90ae\u4ef6\u5047\u8131\u673a\u76ee\u5f55\u3002 \u5982\u679c\u8981\u5220\u9664\u7684\u7528\u6237\u4ecd\u7136\u5904\u4e8e\u767b\u5f55\u72b6\u6001\uff0c\u6216\u8005\u6709\u5c5e\u4e8e\u8be5\u7528\u6237\u7684\u6b63\u5728\u8fd0\u884c\u7684\u8fdb\u7a0b\uff0c\u5219 userdel \u547d\u4ee4\u4e0d\u5141\u8bb8\u5220\u9664\u8be5\u7528\u6237\u3002 \u4f7f\u7528 -f \u9009\u9879\u5f3a\u5236\u5220\u9664\u7528\u6237\u5e10\u6237\uff0c\u5373\u4f7f\u7528\u6237\u4ecd\u7136\u767b\u5f55\u6216\u6709\u5c5e\u4e8e\u8be5\u7528\u6237\u7684\u6b63\u5728\u8fd0\u884c\u7684\u8fdb\u7a0b\u4e5f\u662f\u5982\u6b64\u3002 userdel USER userdel -r USER","title":"4.3.\u5220\u9664\u7528\u6237userdel"},{"location":"linux/SRE/03-identity-security/#44id","text":"\u7c7bUnix\u64cd\u4f5c\u7cfb\u7edf\u4e2d\u7684\u6bcf\u4e2a\u7528\u6237\u90fd\u7531\u4e00\u4e2a\u4e0d\u540c\u7684\u6574\u6570\u6807\u8bc6\uff0c\u8fd9\u4e2a\u552f\u4e00\u7684\u6570\u5b57\u79f0\u4e3aUserID\u3002 \u4e3a\u8fdb\u7a0bprocess\u5b9a\u4e49\u4e86\u4e09\u79cd\u7c7b\u578b\u7684UID\uff0c\u53ef\u4ee5\u6839\u636e\u4efb\u52a1\u7684\u6743\u9650\u52a8\u6001\u66f4\u6539\u3002 \u5b9a\u4e49\u7684\u4e09\u79cd\u4e0d\u540c\u7c7b\u578b\u7684UID\u662f\uff1a \u771f\u5b9e\u7528\u6237ID\uff08Real UserId\uff09\uff1a\u5bf9\u4e8e\u4e00\u4e2a\u8fdb\u7a0b\uff0cReal UserId\u5c31\u662f\u542f\u52a8\u5b83\u7684\u7528\u6237\u7684 UserID\u3002 \u5b83\u5b9a\u4e49\u4e86\u8fd9\u4e2a\u8fdb\u7a0b\u53ef\u4ee5\u8bbf\u95ee\u54ea\u4e9b\u6587\u4ef6\u3002 \u6709\u6548\u7528\u6237\u540d\uff08Effective UserID\uff09\uff1a\u5b83\u901a\u5e38\u4e0e Real UserID \u76f8\u540c\uff0c\u4f46\u6709\u65f6\u4f1a\u66f4\u6539\u4e3a\u4f7f\u975e\u7279\u6743\u7528\u6237\u80fd\u591f\u8bbf\u95ee\u90a3\u4e9b\u53ea\u80fd\u7531\u7279\u6743\u7528\u6237\uff08\u5982 root \uff09\u8bbf\u95ee\u7684\u6587\u4ef6\u3002 \u4fdd\u5b58\u7684\u7528\u6237ID\uff08Saved UserID\uff09 \uff1a\u5f53\u4e00\u4e2a\u4ee5\u63d0\u5347\u7684\u6743\u9650\uff08\u901a\u5e38\u662f root \uff09\u8fd0\u884c\u7684\u8fdb\u7a0b\u9700\u8981\u505a\u4e00\u4e9b\u4f4e\u6743\u9650\u7684\u4efb\u52a1\u65f6\u4f7f\u7528\uff0c\u53ef\u4ee5\u901a\u8fc7\u4e34\u65f6\u5207\u6362\u5230\u975e\u7279\u6743\u5e10\u6237\u6765\u5b9e\u73b0\u3002\u5728\u6267\u884c\u4f4e\u6743\u9650\u4efb\u52a1\u65f6\uff0c\u6709\u6548\u7684 UID \u88ab\u66f4\u6539\u4e3a\u67d0\u4e2a\u8f83\u4f4e\u6743\u9650\u7684\u503c\uff0c\u5e76\u4e14 euid \u88ab\u4fdd\u5b58\u5230\u5df2\u4fdd\u5b58\u7684 userID (suid)\u4e2d\uff0c\u4ee5\u4fbf\u5728\u4efb\u52a1\u5b8c\u6210\u65f6\u7528\u4e8e\u5207\u6362\u56de\u7279\u6743\u5e10\u6237\u3002 \u5728\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u6682\u505c\u5728\u65b0\u5bc6\u7801\u8f93\u5165\u8fd9\u4e00\u6b65\u3002 $ ls -ltr /usr/bin/passwd -rwsr-xr-x. 1 root shadow 65208 May 8 2022 /usr/bin/passwd $ passwd Changing password for vagrant. Current password: New password: \u65b0\u5f00\u4e00\u4e2a\u7ec8\u7aef\u7a97\u53e3\u3002 $ ps -a | grep passwd 3040 pts/0 00 :00:00 passwd $ ps -eo pid,euid,ruid | grep 3040 3040 0 1000 \u4e0a\u9762\u8f93\u51fa\u53ef\u4ee5\u770b\u51fa\uff0c passwd \u8fd9\u4e2a\u8fdb\u7a0b\u7684Effective UserID\u662f 0 \u3002Real UserId\u662f 1000 . id \u547d\u4ee4\u67e5\u770b\u7528\u6237\u6709\u6548\u7684UID\u548cGID\u3002 \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684\u4fe1\u606f\uff1a $ id uid = 1000 ( vagrant ) gid = 478 ( wheel ) groups = 478 ( wheel ) ,0 ( root ) context = unconfined_u:unconfined_r:unconfined_t:s0 \u67e5\u770b\u6307\u5b9a\u7528\u6237\u7684\u4fe1\u606f\uff1a $ id vagrant uid = 1000 ( vagrant ) gid = 478 ( wheel ) groups = 0 ( root ) ,478 ( wheel ) \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684GID\uff1a $ id -g 478 \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684UID\uff1a $ id -u 1000 \u67e5\u770b\u5f53\u524d\u7528\u6237\u6240\u6709\u7ec4\u7684GID\uff1a $ id -G 478 0 \u67e5\u770b\u5f53\u524d\u7528\u6237\u540d\uff1a $ id -un vagrant \u67e5\u770b\u5f53\u524d\u7528\u6237\u7684GID $ id -ur 1000 \u53ea\u6709SELinux\u6fc0\u6d3b\u540e\u624d\u6709 $ id -Z unconfined_u:unconfined_r:unconfined_t:s0 \u7c7b\u4f3c\u4e8e whoami \u547d\u4ee4 $ id -znG wheelroot","title":"4.4.\u67e5\u770b\u7528\u6237\u4fe1\u606fid"},{"location":"linux/SRE/03-identity-security/#45su","text":"\u547d\u4ee4 su - username \u662f\u767b\u5f55\u5f0f\u5207\u6362\u7528\u6237\u3002\u4f1a\u8bfb\u53d6\u76ee\u6807\u7528\u6237\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u5207\u6362\u81f3\u76ee\u6807\u7528\u6237\u7684\u4e3b\u76ee\u5f55\u3002 \u547d\u4ee4 su username \u662f\u975e\u767b\u5f55\u5f0f\u5207\u6362\u7528\u6237\u3002\u4e0d\u8bfb\u53d6\u76ee\u6807\u7528\u6237\u7684\u914d\u7f6e\u6587\u4ef6\uff0c\u4e0d\u6539\u53d8\u5f53\u524d\u5de5\u4f5c\u76ee\u5f55\u3002 \u5207\u6362\u6210root\u7528\u6237\uff0c\u5e76\u4f7f\u7528zsh shell\u3002 su -s /usr/bin/zsh su -s /usr/bin/zsh root \u5207\u6362\u6210tester1\u7528\u6237\uff0c\u4f7f\u7528bash shell su - tester1 -s /bin/bash su - -s /bin/bash tester1 \u4fdd\u7559\u5f53\u524d\u7528\u6237\u73af\u5883\u4e0d\u53d8\u3002 su -p root \u4e0d\u4ea4\u4e92\u5f0f\u5207\u6362\u7528\u6237\uff0c\u53ea\u7528\u76ee\u6807\u7528\u6237\u6267\u884c\u67d0\u4e9b\u547d\u4ee4\u3002 su -c ps su - root -c \"getent passwd\" su - root -s /bin/bash -c \"getent passwd\" root \u7528\u6237\u5207\u6362\u81f3\u5176\u4ed6\u7528\u6237\u4e0d\u9700\u8981\u5bc6\u7801\uff0c\u975e root \u7528\u6237\u5207\u6362\u5176\u4ed6\u7528\u6237\u9700\u8981\u5bc6\u7801\u3002","title":"4.5.\u5207\u6362\u7528\u6237su"},{"location":"linux/SRE/03-identity-security/#46","text":"","title":"4.6.\u8bbe\u7f6e\u5bc6\u7801"},{"location":"linux/SRE/03-identity-security/#461passwd","text":"\u4fee\u6539\u5f53\u524d\u7528\u6237\u81ea\u5df1\u7684\u5bc6\u7801\uff1a passwd \u4fee\u6539\u5176\u4ed6\u7528\u6237\u7684\u5bc6\u7801\uff1a sudo passwd root \u67e5\u770b\u67d0\u4e2a\u7528\u6237\u5bc6\u7801\u72b6\u6001\uff1a $ sudo passwd -S root root P 10 /30/2022 -1 -1 -1 -1 $ sudo passwd -S vagrant vagrant P 10 /30/2022 0 99999 7 -1 \u68c0\u67e5\u5168\u90e8\u7528\u6237\u7684\u5bc6\u7801\u72b6\u6001\uff1a sudo passwd -Sa \u5bc6\u7801\u72b6\u6001\u8bf4\u660e\uff1a Username Status Date Last Changed Minimum Age Maximum Age Warning Period Inactivity Period vagrant P 10 /30/2022 0 99999 7 -1 root P 10 /30/2022 -1 -1 -1 -1 Status\u7684\u63cf\u8ff0\uff1a P : Usable password NP : No password L : Locked password Age\u7684\u4e00\u4e9b\u7279\u6b8a\u503c\uff1a 9999 : Never expires 0 : Can be changed at anytime -1 : Not active \u5f3a\u5236\u8981\u6c42\u7528\u6237\u4e0b\u6b21\u767b\u5f55\u65f6\u4fee\u6539\u5bc6\u7801\uff1a $ sudo passwd -e tester1 $ sudo passwd -S tester1 tester1 P 01 /01/1970 0 99999 7 -1 \u7528\u6237tester1\u7684\u5bc6\u7801\u65e5\u671f\u5df2\u7ecf\u88ab\u6539\u6210 01/01/1970 \u4e86\u3002\u8fd9\u4e2a\u65e5\u671f\u7b97\u662fUnix\u7684\u201c\u7eaa\u5143\uff08epoch\uff09\u201d\u65e5\u671f\uff0c\u610f\u5473\u7740Unix\u7684\u65e5\u671f\u8d77\u70b9\uff0c0\u5929\u3002 \u9501\u5b9a\u67d0\u4e2a\u7528\u6237\uff1a $ sudo passwd -l tester1 $ sudo passwd -S tester1 tester1 L 01 /01/1970 0 99999 7 -1 \u6b64\u65f6\u7528\u6237 tester1 \u7684\u72b6\u6001\u680f\u5df2\u7ecf\u53d8\u6210\u4e86 L \uff0c\u9501\u5b9a\u72b6\u6001\u3002 \u89e3\u9501\u67d0\u4e2a\u7528\u6237\uff1a $ sudo passwd -u tester1 $ sudo passwd -S tester1 tester1 P 01 /01/1970 0 99999 7 -1 \u6b64\u65f6\u7528\u6237 tester1 \u7684\u72b6\u6001\u680f\u5df2\u7ecf\u4ece L \u53d8\u56de\u4e86 P \uff0c\u89e3\u9664\u4e86\u9501\u5b9a\u72b6\u6001\u3002 \u5220\u9664\u7528\u6237\u5bc6\u7801\u3002\u8fd9\u4e2a\u64cd\u4f5c\u614e\u91cd\uff0c\u5bc6\u7801\u5220\u9664\u540e\u8be5\u7528\u6237\u53ef\u4ee5\u4e0d\u9700\u8981\u5bc6\u7801\u5c31\u80fd\u8bbf\u95ee\u7cfb\u7edf\u3002 $ sudo passwd -d tester1 $ sudo passwd -S tester1 tester1 NP 01 /01/1970 0 99999 7 -1 \u6b64\u65f6\u7528\u6237 tester1 \u7684\u72b6\u6001\u680f\u662f NP \u3002","title":"4.6.1.passwd"},{"location":"linux/SRE/03-identity-security/#462pwgen","text":"\u5b89\u88c5\u5305\u3002 mkpasswd\u547d\u4ee4\u6709\u6b67\u4e49\uff0c2\u4e2a\u540c\u540d\u547d\u4ee4\u5b9e\u73b0\u4e0d\u540c\u529f\u80fd\uff0c\u751f\u6210\u968f\u673a\u5bc6\u7801\u5efa\u8bae\u4f7f\u7528 pwgen \u547d\u4ee4\u3002Rocky9\u6ca1\u6709\u627e\u5230pwgen\u5305\u3002 sudo zypper in pwgen sudo apt install pwgen \u968f\u673a\u751f\u6210\u957f\u5ea68\u4f4d\u5b89\u5168\u5bc6\u7801\u3002 pwgen -s -1 \u968f\u673a\u751f\u6210\u957f\u5ea614\u4f4d\u5b89\u5168\u5bc6\u7801\u3002 pwgen -s -1 14 \u968f\u673a\u751f\u62102\u4e2a\u957f\u5ea615\u4f4d\u5b89\u5168\u5bc6\u7801\u3002 pwgen -s -1 15 2 \u968f\u673a\u751f\u62105\u4e2a\u5bc6\u7801\uff0c\u957f\u5ea610\u4f4d\uff0c\u6bcf\u4e2a\u5bc6\u7801\u81f3\u5c11\u542b\u4e00\u4e2a\u7279\u6b8a\u5b57\u7b26\uff0c\u7ed3\u679c\u4ee5\u5217\u5f62\u5f0f\u8f93\u51fa\u3002 pwgen -s -1 -y 10 5 \u751f\u6210\u957f\u5ea68\uff0c\u542b\u6709\u6570\u5b57\uff0c\u542b\u6709\u5927\u5c0f\u5199\u5b57\u6bcd\u7684\u5bc6\u78014\u4e2a\uff0c\u5217\u6253\u5370 pwgen -s -n -c -C -1 8 4 \u751f\u6210\u957f\u5ea68\uff0c\u4e0d\u542b\u6570\u5b57\uff0c\u53ea\u542b\u5c0f\u5199\u5b57\u6bcd\uff0c\u5217\u6253\u5370 pwgen -s -c -A -0 -1 8 4 \u751f\u6210\u957f\u5ea616\uff0c\u542b\u6709\u6570\u5b57\uff0c\u542b\u6709\u5927\u5c0f\u5199\u5b57\u6bcd\uff0c\u542b\u6709\u7279\u6b8a\u5b57\u7b26\u7684\u5bc6\u78013\u4e2a\uff0c\u884c\u6253\u5370 pwgen -s -n -c -y -1 16 3 \u751f\u6210\u957f\u5ea680\uff0c\u4e0d\u542b\u5143\u97f3\u548c\u6570\u5b57\uff0c\u81f3\u5c11\u542b\u6709\u4e00\u4e2a\u5927\u5199\u5b57\u6bcd\uff0c\u884c\u6253\u5370 pwgen -s -v -c -0 80 1","title":"4.6.2.pwgen"},{"location":"linux/SRE/03-identity-security/#463","text":"\u65b9\u6cd51\uff1a $ echo -e '123456\\n123456' | sudo passwd tester1 New password: BAD PASSWORD: it is too simplistic/systematic BAD PASSWORD: is too simple Retype new password: passwd: password updated successfully \u65b9\u6cd52\uff1a Rocky\u4e2d\u53ef\u4ee5\u4f7f\u7528\u4e0b\u9762\u65b9\u6cd5\u3002 pwgen -ncy1 16 1 | tee passwd.txt | sudo passwd --stdin tester1 openSUSE\u548cUbuntu\u53ef\u4ee5\u7528\u4e0b\u9762\u65b9\u6cd5\u3002 echo \"tester1:\" ` pwgen -ncy1 16 1 ` | tee passwd.txt | sudo chpasswd \u65b9\u6cd53\uff1a\u6839\u636e\u9884\u5148\u7ed9\u5b9a\u7684\u7528\u6237\u5217\u8868\uff0c\u6279\u91cf\u751f\u6210\u5bc6\u7801\u3002 $ cat > user-list.txt < user.txt < file 67274683 lrwxrwxrwx. 1 vagrant wheel 12 Nov 1 11 :20 symlinkfile1-1 -> symlinkfile1 67274682 lrwxrwxrwx. 1 vagrant wheel 4 Nov 1 10 :43 symlinkfile2 -> file 33555262 drwxr-xr-x. 2 vagrant wheel 6 Nov 1 11 :30 typelink \u4ee5 67274680 -rw-r--r--. 3 vagrant wheel 31 Nov 1 11:14 file \u4e3a\u4f8b\uff1a 67274680 : inode \u7d22\u5f15\u8282\u70b9\u7f16\u53f7\u3002 -rw-r--r-- \uff1a\u6587\u4ef6\u7c7b\u578b\u53ca\u6743\u9650 - \uff1a\u6587\u4ef6\u7c7b\u578b\uff0c\u4f8b\u5b50\u4e2d\u51fa\u73b0\u4e86\u4e09\u79cd\uff0c - \uff0c l \u548c d \u3002 - \uff1a\u666e\u901a\u6587\u4ef6 d \uff1a\u76ee\u5f55 l \uff1a\u7b26\u53f7\u94fe\u63a5\u6587\u4ef6\uff08link\uff09 b \uff1a\u5757\u8bbe\u5907\uff08block\uff09 c \uff1a\u5b57\u7b26\u8bbe\u5907\uff08character\uff09 p \uff1a\u7ba1\u9053\u6587\u4ef6\uff08pipe\uff09 s \uff1a\u5957\u63a5\u5b57\u6587\u4ef6\uff08socket\uff09 rw-r--r-- \uff1a\u6587\u4ef6\u6743\u9650\uff0c\u4ece\u5de6\u5230\u53f3\u4f9d\u6b21\u4e3a\uff1a\uff08\u7528\u6237\u7684\u6700\u7ec8\u6743\u9650\uff0c\u662f\u4ece\u5de6\u5411\u53f3\u5339\u914d\uff0c\u4e00\u65e6\u5339\u914d\u5219\u6743\u9650\u7acb\u5373\u751f\u6548\uff0c\u4e0d\u518d\u5411\u53f3\u7ee7\u7eed\u5339\u914d\uff09 rw- \uff1a\u6587\u4ef6\u5c5e\u4e3b\u6743\u9650\uff08u\uff09\uff0c\u4f8b\u5b50\u4e2d\u662f vagrant \u3002 r-- \uff1a\u6587\u4ef6\u5c5e\u7ec4\u7684\u6743\u9650\uff08g\uff09\uff0c\u4f8b\u5b50\u4e2d\u662f wheel \u3002 r-- \uff1a\u5176\u4ed6\u7ec4\u7684\u6743\u9650\uff08o\uff09\u3002 . \uff1a\u8fd9\u4e2a\u70b9\u8868\u793a\u6587\u4ef6\u5e26\u6709SELinux\u7684\u5b89\u5168\u4e0a\u4e0b\u6587\uff08SELinux Contexts\uff09\u3002\u5173\u95edSELinux\uff0c\u65b0\u521b\u5efa\u7684\u6587\u4ef6\u5c31\u4e0d\u4f1a\u518d\u6709\u8fd9\u4e2a\u70b9\u4e86\u3002\u4f46\u662f\uff0c\u4ee5\u524d\u521b\u5efa\u7684\u6587\u4ef6\u672c\u6765\u6709\u8fd9\u4e2a\u70b9\u7684\u8fd8\u4f1a\u663e\u793a\u8fd9\u4e2a\u70b9\uff08\u867d\u7136SELinux\u4e0d\u8d77\u4f5c\u7528\u4e86\uff09\u3002 3 \uff1a\u786c\u94fe\u63a5\u6570\uff0c\u4f8b\u5b50\u4e2d file \u548c hardlinkfile1 \u548c hardlinkfile2 \u4e4b\u95f4\u662f\u786c\u94fe\u63a5\uff0c\u6240\u4ee5\u8fd9\u4e09\u4e2a\u6587\u4ef6\u7684\u786c\u94fe\u63a5\u6570\u90fd\u662f 3 \u3002 vagrant \uff1a\u6587\u4ef6\u5c5e\u4e3bowner wheel \uff1a\u6587\u4ef6\u5c5e\u7ec4group 31 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u5927\u5c0f Nov 1 11:14 \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u7684\u521b\u5efa\u65e5\u671f\u548c\u65f6\u95f4 file \uff1a\u6587\u4ef6\u6216\u76ee\u5f55\u540d\u79f0 \u4e0b\u9762\u662f\u547d\u4ee4 ls -ihl \u5728openSUSE\u548cUbuntu\u4e0a\u7684\u663e\u793a\u7ed3\u679c\u3002 $ ls -ihl 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 file 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile1 233647 -rw-r--r-- 3 vagrant wheel 31 Nov 1 15 :52 hardlinkfile2 233648 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile1 -> file 233650 lrwxrwxrwx 1 vagrant wheel 12 Nov 1 15 :52 symlinkfile1-1 -> symlinkfile1 233649 lrwxrwxrwx 1 vagrant wheel 4 Nov 1 15 :52 symlinkfile2 -> file 233646 drwxr-xr-x 1 vagrant wheel 0 Nov 1 15 :51 typelink","title":"7.\u6743\u9650\u7ba1\u7406"},{"location":"linux/SRE/03-identity-security/#71chown","text":"chown \u547d\u4ee4\u4fee\u6539\u6587\u4ef6\u5c5e\u4e3b\uff08\u6240\u6709\u8005\uff0cowner\uff09\u3002 \u4fee\u6539\u6587\u4ef6\u5c5e\u4e3b\u4e3aroot\u3002 $ ll f1.txt -rw-r--r--. 1 vagrant wheel 41 Nov 14 22 :23 f1.txt $ sudo chown root f1.txt $ ll f1.txt -rw-r--r--. 1 root wheel 41 Nov 14 22 :23 f1.txt \u4fee\u6539\u6587\u4ef6\u7684\u5c5e\u7ec4\u4e3abin\u3002 $ sudo chown :bin f1.txt $ ll f1.txt -rw-r--r--. 1 root bin 41 Nov 14 22 :23 f1.txt \u540c\u65f6\u4fee\u6539\u6587\u4ef6\u7684\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u3002 $ sudo chown vagrant.wheel f1.txt $ ll f1.txt -rw-r--r--. 1 vagrant wheel 41 Nov 14 22 :23 f1.txt \u53c2\u7167\u67d0\u6587\u4ef6\u4fee\u6539\u53e6\u4e00\u6587\u4ef6\u7684\u5c5e\u6027\u3002 $ ll file.py -rw-r--r--. 1 vagrant wheel 56 Nov 13 22 :50 file.py $ ll user.txt -rw-r--r--. 1 root bin 21 Nov 27 23 :59 user.txt $ sudo chown root.bin user.txt $ sudo chown --reference = user.txt file.py $ ll file.py -rw-r--r--. 1 root bin 56 Nov 13 22 :50 file.py \u9012\u5f52\u4fee\u6539\u6240\u6709\u5b50\u76ee\u5f55\u53ca\u6587\u4ef6\u7684\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u3002 sudo chown -R vagrant.wheel ~","title":"7.1.\u4fee\u6539\u5c5e\u4e3bchown"},{"location":"linux/SRE/03-identity-security/#72chgrp","text":"\u4fee\u6539\u76ee\u5f55\u7684\u5c5e\u7ec4\u3002 sudo chgrp bin ~~ \u4fee\u6539\u76ee\u5f55\u53ca\u5b50\u76ee\u5f55\u53ca\u6587\u4ef6\u7684\u5c5e\u7ec4\u3002 sudo chgrp -R bin ~~","title":"7.2.\u4fee\u6539\u5c5e\u7ec4chgrp"},{"location":"linux/SRE/03-identity-security/#73","text":"\u6587\u4ef6\uff1a r \uff1a\u53ef\u4ee5\u8bfb\u53d6\u8be5\u6587\u4ef6\u5185\u5bb9\uff0c\u6bd4\u5982\u901a\u8fc7 cat \u547d\u4ee4\u3002 w \uff1a\u53ef\u4ee5\u4fee\u6539\u8be5\u6587\u4ef6\u5185\u5bb9\uff0c\u53ef\u4ee5\u53ea\u6709 w \u800c\u6ca1\u6709 r \u3002 x \uff1a\u53ef\u4ee5\u628a\u8be5\u6587\u4ef6\u63d0\u8bf7\u5185\u6838\u542f\u52a8\u4e3a\u4e00\u4e2a\u8fdb\u7a0b\uff0c\u5373\u53ef\u4ee5\u6267\u884c\u8be5\u6587\u4ef6\uff08\u8be5\u6587\u4ef6\u7684\u5185\u5bb9\u5fc5\u987b\u662f\u53ef\u4ee5\u6267\u884c\uff09\u3002 \u76ee\u5f55\uff1a\uff08\u5bf9\u76ee\u5f55\u800c\u8a00\uff0c\u901a\u5e38\u9700\u8981\u7ed9 r \u548c x \u6743\u9650\uff09\uff08\u4ece\u76ee\u5f55\u89d2\u5ea6\u770b\uff0c\u76ee\u5f55\u5185\u6587\u4ef6\u5217\u8868\u7b49\u4e8e\u76ee\u5f55\u8282\u70b9\u7684\u5185\u5bb9\uff09 r \uff1a\u80fd\u770b\u6587\u4ef6\u5217\u8868\uff0c\u4f46\u4e0d\u80fd\u8bbf\u95ee\u6240\u542b\u6587\u4ef6\u7684\u5185\u5bb9\u53ca\u5176\u5c5e\u6027\u4fe1\u606f\uff0c\u5305\u62ecinode\u53f7\u3002 w \uff1a\u80fd\u5728\u8be5\u76ee\u5f55\u5185\u521b\u5efa\u548c\u5220\u9664\u6587\u4ef6\uff0c\u4e0d\u7531\u76ee\u5f55\u5185\u6587\u4ef6\u672c\u8eab\u7684\u6743\u9650\u51b3\u5b9a\u3002 x \uff1a\u80fdcd\u8fdb\u76ee\u5f55\uff0c\u80fd\u901a\u8fc7 ls -l file \u548c stat file \u67e5\u770b\u8be5\u76ee\u5f55\u4e2d\u5236\u5b9a\u6587\u4ef6\u7684\u5143\u6570\u636e\u3002 X \uff1a\u8868\u793a\u53ea\u6709\u5f53\u8be5\u6587\u4ef6\u662f\u4e2a\u5b50\u76ee\u5f55\u6216\u8005\u8be5\u6587\u4ef6\u5df2\u7ecf\u88ab\u8bbe\u5b9a\u8fc7\u4e3a\u53ef\u6267\u884c\u3002 \u6709\u53ea\u8bfb\u6743\u9650\u7684\u7528\u6237\u4e0d\u80fd\u7528cd\u8fdb\u5165\u8be5\u76ee\u5f55\uff0c\u8fd8\u5fc5\u987b\u6709\u6267\u884c\u6743\u9650\u624d\u80fd\u8fdb\u5165\u3002 \u6709\u6267\u884c\u6743\u9650\u7684\u7528\u6237\u53ea\u6709\u5728\u77e5\u9053\u6587\u4ef6\u540d\uff0c\u5e76\u62e5\u6709\u8bfb\u6743\u5229\u7684\u60c5\u51b5\u4e0b\u624d\u53ef\u4ee5\u8bbf\u95ee\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u3002 \u5fc5\u987b\u6709\u8bfb\u548c\u6267\u884c\u6743\u9650\u624d\u53ef\u4ee5ls\u5217\u51fa\u76ee\u5f55\u6e05\u5355\uff0c\u6216\u4f7f\u7528cd\u547d\u4ee4\u8fdb\u5165\u76ee\u5f55\u3002 \u6709\u76ee\u5f55\u7684\u5199\u6743\u9650\uff0c\u53ef\u4ee5\u521b\u5efa\u3001\u5220\u9664\u6216\u4fee\u6539\u76ee\u5f55\u4e0b\u7684\u4efb\u4f55\u6587\u4ef6\u6216\u5b50\u76ee\u5f55\uff0c\u5373\u4f7f\u4f7f\u8be5\u6587\u4ef6\u6216\u5b50\u76ee\u5f55\u5c5e\u4e8e\u5176\u4ed6\u7528\u6237\u4e5f\u662f\u5982\u6b64\u3002 \u5e38\u7528\u6743\u9650\u4f8b\u5b50\uff1a -rw------- ( 600 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\u548c\u5199\u7684\u6743\u9650 -rw-r--r-- ( 644 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\u548c\u5199\u7684\u6743\u9650\uff0c\u7ec4\u548c\u5176\u4ed6\u4eba\u53ea\u6709\u8bfb\u7684\u6743\u9650 -rwx------ ( 700 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\uff0c\u5199\uff0c\u6267\u884c\u7684\u6743\u9650 -rwxr-xr-x ( 755 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\uff0c\u5199\uff0c\u6267\u884c\u7684\u6743\u9650\uff0c\u7ec4\u548c\u5176\u4ed6\u4eba\u53ea\u6709\u8bfb\u548c\u6267\u884c\u7684\u6743\u9650 -rwx--x--x ( 711 ) \u53ea\u6709\u6240\u6709\u8005\u624d\u6709\u8bfb\uff0c\u5199\uff0c\u6267\u884c\u7684\u6743\u9650\uff0c\u7ec4\u548c\u5176\u4ed6\u4eba\u53ea\u6709\u6267\u884c\u7684\u6743\u9650 -rw-rw-rw- ( 666 ) \u6bcf\u4e2a\u4eba\u90fd\u6709\u8bfb\u5199\u7684\u6743\u9650 -rwxrwxrwx ( 777 ) \u6bcf\u4e2a\u4eba\u90fd\u6709\u8bfb\u5199\u548c\u6267\u884c\u7684\u6743\u9650","title":"7.3.\u6587\u4ef6\u548c\u76ee\u5f55\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#74chmod","text":"\u547d\u4ee4\u683c\u5f0f\uff1a chmod [ -cfvR ] [ --help ] [ --version ] mode file mode \u5b57\u4e32\u683c\u5f0f\u4e3a\uff1a [ ugoa ][ +- =][ rwxXst ] who: u \u6587\u4ef6\u6240\u6709\u8005 g \u6587\u4ef6\u6240\u6709\u8005\u6240\u5728\u7ec4 o \u5176\u4ed6\u7528\u6237 a \u6240\u6709\u7528\u6237\uff0c\u76f8\u5f53\u4e8e ugo operator: + \u4e3a\u6307\u5b9a\u7684\u7528\u6237\u7c7b\u578b\u589e\u52a0\u6743\u9650 - \u53bb\u9664\u6307\u5b9a\u7528\u6237\u7c7b\u578b\u7684\u6743\u9650 = \u8bbe\u7f6e\u6307\u5b9a\u7528\u6237\u6743\u9650\u7684\u8bbe\u7f6e\uff0c\u5373\u5c06\u7528\u6237\u7c7b\u578b\u7684\u6240\u6709\u6743\u9650\u91cd\u65b0\u8bbe\u7f6e permission: r \u8bbe\u7f6e\u4e3a\u53ef\u8bfb\u6743\u9650 w \u8bbe\u7f6e\u4e3a\u53ef\u5199\u6743\u9650 x \u8bbe\u7f6e\u4e3a\u53ef\u6267\u884c\u6743\u9650 X \u7279\u6b8a\u6267\u884c\u6743\u9650\uff0c\u53ea\u6709\u5f53\u6587\u4ef6\u4e3a\u76ee\u5f55\u6587\u4ef6\uff0c\u6216\u8005\u5176\u4ed6\u7c7b\u578b\u7684\u7528\u6237\u6709\u53ef\u6267\u884c\u6743\u9650\u65f6\uff0c\u624d\u5c06\u6587\u4ef6\u6743\u9650\u8bbe\u7f6e\u53ef\u6267\u884c s \u5f53\u6587\u4ef6\u88ab\u6267\u884c\u65f6\uff0c\u6839\u636ewho\u53c2\u6570\u6307\u5b9a\u7684\u7528\u6237\u7c7b\u578b\u8bbe\u7f6e\u6587\u4ef6\u7684 setuid \u6216\u8005 setgid \u6743\u9650 t \u8bbe\u7f6e\u7c98\u8d34\u4f4d\uff0c\u53ea\u6709\u8d85\u7ea7\u7528\u6237\u53ef\u4ee5\u8bbe\u7f6e\u8be5\u4f4d\uff0c\u53ea\u6709\u6587\u4ef6\u6240\u6709\u8005u\u53ef\u4ee5\u4f7f\u7528\u8be5\u4f4d\u3002 \u793a\u4f8b\uff1a \u5c06\u6587\u4ef6 file1.txt \u8bbe\u4e3a\u6240\u6709\u4eba\u7686\u53ef\u8bfb\u53d6\u3002 chmod ugo+r file1.txt \u5c06\u6587\u4ef6 file1.txt \u8bbe\u4e3a\u6240\u6709\u4eba\u7686\u53ef\u8bfb\u53d6\u3002 chmod a+r file1.txt \u5c06\u6587\u4ef6 file1.txt \u4e0e file2.txt \u8bbe\u4e3a\u8be5\u6587\u4ef6\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u90fd\u53ef\u5199\u5165\uff0c\u4f46\u5176\u4ed6\u7528\u6237\u4e0d\u53ef\u5199\u5165\u3002 chmod ug+w,o-w file1.txt file2.txt \u4e3a ex1.py \u6587\u4ef6\u5c5e\u4e3b\u589e\u52a0\u53ef\u6267\u884c\u6743\u9650\u3002 chmod u+x ex1.py \u5c06\u76ee\u524d\u76ee\u5f55\u4e0b\u7684\u6240\u6709\u6587\u4ef6\u4e0e\u5b50\u76ee\u5f55\u7686\u8bbe\u4e3a\u4efb\u4f55\u4eba\u53ef\u8bfb\u53d6\u3002 chmod -R a+r * \u7ed9 file \u7684\u6240\u6709\u7528\u6237\u589e\u52a0\u8bfb\u6743\u9650 chmod a+r file \u5220\u9664 file \u7684\u6240\u6709\u7528\u6237\u7684\u6267\u884c\u6743\u9650 chmod a-x file \u7ed9 file \u7684\u6240\u6709\u7528\u6237\u589e\u52a0\u8bfb\u5199\u6743\u9650 chmod a+rw file \u7ed9 file \u7684\u6240\u6709\u7528\u6237\u589e\u52a0\u8bfb\u5199\u6267\u884c\u6743\u9650 chmod +rwx file \u5bf9 file \u7684\u5c5e\u4e3b\u8bbe\u7f6e\u8bfb\u5199\u6743\u9650\uff0c\u6e05\u7a7a\u5c5e\u7ec4\u548c\u5176\u4ed6\u7528\u6237\u5bf9 file \u7684\u6240\u6709\u6743\u9650\uff08\u7a7a\u683c\u4ee3\u8868\u65e0\u6743\u9650\uff09 chmod u = rw,go = file \u5bf9\u76ee\u5f55 docs \u548c\u5176\u5b50\u76ee\u5f55\u4e2d\u7684\u6240\u6709\u6587\u4ef6\u7ed9\u5c5e\u4e3b\u589e\u52a0\u8bfb\u6743\u9650\uff0c\u800c\u5bf9\u5c5e\u7ec4\u548c\u5176\u4ed6\u7528\u6237\u5220\u9664\u8bfb\u6743\u9650 chmod -R u+r,go-r docs \u5bf9 file \u7684\u5c5e\u4e3b\u548c\u5c5e\u7ec4\u8bbe\u7f6e\u8bfb\u5199\u6743\u9650, \u4e3a\u5176\u4ed6\u7528\u6237\u8bbe\u7f6e\u8bfb\u6743\u9650 chmod 664 file \u5bf9 file \u7684\u5c5e\u4e3b\u8bbe\u7f6e\u8bfb\u5199\u6267\u884c\u6743\u9650\uff0c\u76f8\u5f53\u4e8e u=rwx (4+2+1)\uff0c\u8bbe\u7f6e\u5c5e\u7ec4\u8bfb\u548c\u6267\u884c\u6743\u9650\uff0c\u76f8\u5f53\u4e8e go=rx (4+1 & 4+1)\u3002 0 \u6ca1\u6709\u7279\u6b8a\u6a21\u5f0f chmod 0755 file 4 \u8bbe\u7f6e\u4e86\u8bbe\u7f6e\u7528\u6237ID\u4f4d\uff0c\u5269\u4e0b\u7684\u76f8\u5f53\u4e8e u=rwx (4+2+1)\u548c go=rx (4+1 & 4+1)\u3002 chmod 4755 file \u5220\u9664\u53ef\u6267\u884c\u6743\u9650\u5bf9 path/ \u4ee5\u53ca\u5176\u6240\u6709\u7684\u76ee\u5f55\uff08\u4e0d\u5305\u62ec\u6587\u4ef6\uff09\u7684\u6240\u6709\u7528\u6237\uff0c\u4f7f\u7528 -type f \u5339\u914d\u6587\u4ef6 find path/ -type d -exec chmod a-x {} \\; \u5141\u8bb8\u6240\u6709\u7528\u6237\u6d4f\u89c8\u6216\u901a\u8fc7\u76ee\u5f55 path/ find path/ -type d -exec chmod a+x {} \\;","title":"7.4.\u6743\u9650\u4fee\u6539chmod"},{"location":"linux/SRE/03-identity-security/#75umask","text":"umask \u7684\u503c\uff0c\u5b9a\u4e49\u4e86\u6240\u6709\u65b0\u5efa\u7684\u6587\u4ef6\u548c\u76ee\u5f55\u7684\u521d\u59cb\u6743\u9650\u7684\u3002 \u67e5\u770b\u5f53\u524d\u6743\u9650\u63a9\u7801\uff1a $ umask 0022 \u5728\u4e0d\u8003\u8651 umask \u7684\u60c5\u51b5\u4e0b\uff0c\u6587\u4ef6\u7684\u9ed8\u8ba4\u6743\u9650\u662f 666 (rw-rw-rw-)\uff0c\u76ee\u5f55\u7684\u9ed8\u8ba4\u6743\u9650\u662f 777 (rwxrwxrwx)\u3002 \u5728 umask \u7684\u503c\u4e3a 0022 \u7684\u60c5\u51b5\u4e0b\uff0c\u6587\u4ef6\u7684\u9ed8\u8ba4\u6743\u9650\u662f 644 (rw-r--r--)\uff0c\u76ee\u5f55\u7684\u9ed8\u8ba4\u6743\u9650\u662f 755 (rwxr-xr-x)\u3002 \u8ba1\u7b97\u65b9\u6cd5\uff1a Files: ( Default ) 6 6 6 ( umask ) 0 2 2 ---------------- ( Result ) 6 4 4 Directories: ( Default ) 7 7 7 ( umask ) 0 2 2 ---------------- ( Result ) 7 5 5 \u5982\u679c umask \u7684\u503c\u4e3a 0077 \u7684\u60c5\u51b5\u4e0b\uff0c\u6587\u4ef6\u7684\u9ed8\u8ba4\u6743\u9650\u662f 600 (rw-------)\uff0c\u76ee\u5f55\u7684\u9ed8\u8ba4\u6743\u9650\u662f 700 (rwx------)\u3002 \u8ba1\u7b97\u65b9\u6cd5\uff1a Files: ( Default ) 6 6 6 ( umask ) 0 7 7 ---------------- ( Result ) 6 0 0 Directories: ( Default ) 7 7 7 ( umask ) 0 7 7 ---------------- ( Result ) 7 0 0 \u4e3e\u4f8b\uff1a $ umask 022 $ touch file2 $ ll file2 -rw-r--r--. 1 vagrant wheel 0 Nov 28 23 :13 file2 $ umask 077 $ touch file1 $ ll file1 -rw-------. 1 vagrant wheel 0 Nov 28 23 :12 file1 $ umask 022 $ mkdir ./tmp1 $ umask 077 $ mkdir ./tmp2 $ ls -dl tmp* drwxr-xr-x. 1 vagrant wheel 0 Nov 28 23 :14 tmp1 drwx------. 1 vagrant wheel 0 Nov 28 23 :14 tmp2","title":"7.5.\u9ed8\u8ba4\u6743\u9650umask"},{"location":"linux/SRE/03-identity-security/#76","text":"\u9664\u4e86\u4e09\u79cd\u5e38\u89c1\u7684\u6743\u9650rwx\uff0c\u8fd8\u6709\u4e09\u79cd\u7279\u6b8a\u6743\u9650\uff1aSUID\uff0cSGID\uff0cSticky\u3002 SUID\uff1a\u5c5e\u4e3bs\u6743\u9650\uff0c\u79f0\u4e3aSet UID \u524d\u63d0\uff1a\u8fdb\u7a0b\u6709\u5c5e\u4e3b\u548c\u5c5e\u7ec4\uff0c\u6587\u4ef6\u6709\u5c5e\u4e3b\u548c\u5c5e\u7ec4 \u4efb\u4f55\u53ef\u6267\u884c\u7a0b\u5e8f\u6587\u4ef6\u80fd\u4e0d\u80fd\u542f\u52a8\u4e3a\u8fdb\u7a0b\uff0c\u53d6\u51b3\u4e8e\u53d1\u8d77\u8005\u5bf9\u7a0b\u5e8f\u6587\u4ef6\u662f\u5426\u62e5\u6709\u6267\u884c\u6743\u9650\u3002 \u542f\u52a8\u4e3a\u8fdb\u7a0b\u4e4b\u540e\uff0c\u5176\u8fdb\u7a0b\u7684\u5c5e\u4e3b\u4e3a\u53d1\u8d77\u8005\u3002 \u8fdb\u7a0b\u8bbf\u95ee\u6587\u4ef6\u662f\u7684\u6743\u9650\uff0c\u53d6\u51b3\u4e8e\u8fdb\u7a0b\u7684\u53d1\u8d77\u8005\u3002 \u53ea\u5bf9\u4e8c\u8fdb\u5236\u53ef\u6267\u884c\u7a0b\u5e8f\u6587\u4ef6\u6709\u6548\u3002\u5f53\u6267\u884c\u8be5\u6587\u4ef6\u65f6\uff0c\u53d1\u8d77\u8005\u5c06\u81ea\u52a8\u5177\u6709\u8be5\u6587\u4ef6\u6240\u6709\u8005\u7684\u6743\u9650\u3002 \u5bf9\u76ee\u5f55\u65e0\u6548\u3002 $ ll file1 -rw-------. 1 vagrant wheel 0 Nov 28 23 :12 file1 $ sudo chmod u+s file1 $ ll file1 -rwS------. 1 vagrant wheel 0 Nov 28 23 :12 file1 \u5982\u679c\u5c5e\u4e3b\u7684 x \u4f4d\u4e0a\u662f-\uff0c\u5219\u5728\u5c5e\u4e3b\u7684 x \u4f4d\u4e0a\u6807\u8bb0\u5927\u5199 S \uff0c\u5426\u5219\u6807\u8bb0\u5c0f\u5199 s \u3002\u5982\u4e0b\uff1a $ chmod 777 file1 $ ll file1 -rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23 :12 file1 $ sudo chmod u+s file1 $ ll file1 -rwsrwxrwx. 1 vagrant wheel 0 Nov 28 23 :12 file1 \u4e0b\u97622\u7ec4\u547d\u4ee4\u5b9e\u73b0\u540c\u6837\u6548\u679c\u3002 sudo chmod 4xxx file1 chmod 777 file1 sudo chmod u+s file1 \u53d6\u6d88SUID\u3002 sudo chmod u-s file1 SGID\uff1a\u5c5e\u7ec4s\u6743\u9650\uff0c\u79f0\u4e3aSet GID \u5982\u679c\u4f5c\u7528\u4e8e\u4e8c\u8fdb\u5236\u53ef\u6267\u884c\u6587\u4ef6\u4e0a\uff0c\u5f53\u6267\u884c\u8be5\u6587\u4ef6\u4e3a\u8fdb\u7a0b\u4e4b\u540e\uff0c\u53d1\u8d77\u8005\u5c06\u81ea\u52a8\u5177\u6709\u8be5\u6587\u4ef6\u6240\u5c5e\u7ec4\u7684\u6743\u9650\uff0c\u8fdb\u7a0b\u7684\u5c5e\u7ec4\u4e3a\u53d1\u8d77\u8005\u7684\u5c5e\u7ec4\u3002 \u5982\u679c\u4f5c\u7528\u4e8e\u76ee\u5f55\u4e0a\uff0c\u5219\u8be5\u76ee\u5f55\u4e0b\u65b0\u5efa\u7acb\u7684\u76ee\u5f55\u548c\u6587\u4ef6\u90fd\u81ea\u52a8\u4ece\u6b64\u76ee\u5f55\u7ee7\u627f\u3002 $ sudo chmod g+s file2 $ ll file2 -rw-r-Sr--. 1 vagrant wheel 0 Nov 28 23 :13 file2 \u5982\u679c\u5c5e\u7ec4\u7684 x \u4f4d\u4e0a\u662f-\uff0c\u5219\u5728\u5c5e\u7ec4\u7684 x \u4f4d\u4e0a\u6807\u8bb0\u5927\u5199 S \uff0c\u5426\u5219\u6807\u8bb0\u5c0f\u5199 s \u3002\u5982\u4e0b\uff1a $ chmod 777 file2 $ ll file2 -rwxrwxrwx. 1 vagrant wheel 0 Nov 28 23 :13 file2 $ sudo chmod g+s file2 $ ll file2 -rwxrwsrwx. 1 vagrant wheel 0 Nov 28 23 :13 file2 \u4e0b\u97622\u7ec4\u547d\u4ee4\u5b9e\u73b0\u540c\u6837\u6548\u679c\u3002 sudo chmod 2xxx file2 chmod 777 file2 sudo chmod g+s file2 \u53d6\u6d88SGID\u3002 sudo chmod g-s file2 \u5bf9\u4e8e\u76ee\u5f55\uff0c\u4e0b\u9762\u6f14\u793a\u53ef\u4ee5\u770b\u5230\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\u7684\u7ee7\u627f\u6027\u3002 $ ll -d data drwxr-xr-x. 1 vagrant bin 0 Nov 28 20 :55 data $ sudo chmod g+s .~ $ ll -d data drwxr-sr-x. 1 vagrant bin 0 Nov 28 20 :55 data $ cd data $ touch file2 $ ll file2 -rw-r--r--. 1 vagrant bin 0 Nov 29 21 :10 file2 $ mkdir tmp3 $ ll -d tmp3 drwxr-sr-x. 1 vagrant bin 0 Nov 29 21 :10 tmp3 Sticky Bit\uff1a\u7b80\u79f0\u4e3aSBIT\u6743\u9650 \u53ea\u9488\u5bf9\u76ee\u5f55\u6709\u6548\u3002\u5b83\u8868\u793a\u53ea\u80fd\u8ba9\u5176\u5c5e\u4e3b\u4ee5\u53caroot\u53ef\u4ee5\u5220\u9664\u3001\u91cd\u547d\u540d\u3001\u79fb\u52a8\u8be5\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u3002 Sticky\u8bbe\u7f6e\u5728\u6587\u4ef6\u4e0a\u65e0\u610f\u4e49\u3002 \u5982\u679c\u5176\u4ed6\u7684 x \u4f4d\u4e0a\u662f-\uff0c\u5219\u5728\u5176\u4ed6\u7684 x \u4f4d\u4e0a\u6807\u8bb0\u5927\u5199 T \uff0c\u5426\u5219\u6807\u8bb0\u5c0f\u5199 t \u3002 $ ll -d .~ drwxr-sr-x. 1 vagrant bin 18 Nov 29 21 :10 .~ $ sudo chmod o+t .~ $ ll -d .~ drwxr-sr-t. 1 vagrant bin 18 Nov 29 21 :10 .~ $ cd data $ touch file1 $ mkdir tmp1 $ ll file1 -rw-r--r--. 1 vagrant bin 0 Nov 29 21 :37 file1 $ ll -d tmp1 drwxr-sr-x. 1 vagrant bin 0 Nov 29 21 :37 tmp1 \u7279\u6b8a\u6743\u9650\u8bbe\u7f6e\u6570\u5b57\u6cd5\uff1a \u8bbe\u7f6eSUID User Group Others r w s r w s r w x r w S BIN 100 1 1 1 1 1 1 1 1 1 1 1 0 OCT 4 7 7 7 6 \u8bbe\u7f6eSGID User Group Others r w x r w s r w x r w S BIN 010 1 1 1 1 1 1 1 1 1 1 1 0 OCT 2 7 7 7 6 \u8bbe\u7f6eSticky Bit - SBIT User Group Others r w x r w x r w t r w T BIN 001 1 1 1 1 1 1 1 1 1 1 1 0 OCT 1 7 7 7 6","title":"7.6.\u7279\u6b8a\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#77chattr","text":"\u547d\u4ee4\u683c\u5f0f\uff1a chattr [ -RVf ] [ -v version ] [ mode ] files... \u5176\u4e2dmode\u7684\u5b57\u4e32\u683c\u5f0f\uff1a {+|-|=}[aAcCdDeijsStTu] \u5c5e\u6027 i \uff1a \u5982\u679c\u5bf9\u6587\u4ef6\u8bbe\u7f6e i \u5c5e\u6027\uff0c\u90a3\u4e48\u4e0d\u5141\u8bb8\u5bf9\u6587\u4ef6\u8fdb\u884c\u5220\u9664\u3001\u6539\u540d\uff0c\u4e5f\u4e0d\u80fd\u6dfb\u52a0\u548c\u4fee\u6539\u6570\u636e\uff1b \u5982\u679c\u5bf9\u76ee\u5f55\u8bbe\u7f6e i \u5c5e\u6027\uff0c\u90a3\u4e48\u53ea\u80fd\u4fee\u6539\u76ee\u5f55\u4e0b\u6587\u4ef6\u4e2d\u7684\u6570\u636e\uff0c\u4f46\u4e0d\u5141\u8bb8\u5efa\u7acb\u548c\u5220\u9664\u6587\u4ef6\uff1b \u5728openSUSE\u4e0b\u6267\u884c\uff0c\u5206\u533a\u6587\u4ef6\u7c7b\u578b\u662fbtrfs\u683c\u5f0f\u3002 $ touch filetest $ lsattr filetest ---------------------- filetest $ chattr +i filetest chattr: Operation not permitted while setting flags on filetest $ sudo chattr +i filetest $ lsattr filetest ----i----------------- filetest $ rm filetest rm: cannot remove 'filetest' : Operation not permitted $ sudo rm filetest rm: cannot remove 'filetest' : Operation not permitted $ echo \"test\" >> filetest -bash: filetest: Operation not permitted $ sudo echo \"test\" >> filetest -bash: filetest: Operation not permitted $ sudo chattr -i filetest \u5c5e\u6027 a \uff1a \u5982\u679c\u5bf9\u6587\u4ef6\u8bbe\u7f6e a \u5c5e\u6027\uff0c\u90a3\u4e48\u53ea\u80fd\u5728\u6587\u4ef6\u4e2d\u5897\u52a0\u6570\u636e\uff0c\u4f46\u662f\u4e0d\u80fd\u5220\u9664\u548c\u4fee\u6539\u6570\u636e\uff1b \u5982\u679c\u5bf9\u76ee\u5f55\u8bbe\u7f6e a \u5c5e\u6027\uff0c\u90a3\u4e48\u53ea\u5141\u8bb8\u5728\u76ee\u5f55\u4e2d\u5efa\u7acb\u548c\u4fee\u6539\u6587\u4ef6\uff0c\u4f46\u662f\u4e0d\u5141\u8bb8\u5220\u9664\u6587\u4ef6\uff1b \u5728openSUSE\u4e0b\u6267\u884c\uff0c\u5206\u533a\u6587\u4ef6\u7c7b\u578b\u662fbtrfs\u683c\u5f0f\u3002 lsattr filetest ---------------------- filetest $ chattr +a filetest chattr: Operation not permitted while setting flags on filetest $ sudo chattr +a filetest $ echo \"test\" >> filetest $ rm filetest rm: cannot remove 'filetest' : Operation not permitted $ sudo rm filetest rm: cannot remove 'filetest' : Operation not permitted $ sudo chattr -a filetest \u5c5e\u6027 u \uff1a \u8bbe\u7f6e\u6b64\u5c5e\u6027\u7684\u6587\u4ef6\u6216\u76ee\u5f55\uff0c\u5728\u5220\u9664\u65f6\uff0c\u5176\u5185\u5bb9\u4f1a\u88ab\u4fdd\u5b58\uff0c\u4ee5\u4fdd\u8bc1\u540e\u671f\u80fd\u591f\u6062\u590d\uff0c\u5e38\u7528\u6765\u9632\u6b62\u610f\u5916\u5220\u9664\u6587\u4ef6\u6216\u76ee\u5f55\u3002 \u5728Ubuntu\u4e0b\u6267\u884c\uff0c\u5206\u533a\u6587\u4ef6\u7c7b\u578b\u662fext4\u683c\u5f0f\u3002 $ touch filetest $ sudo chattr +u filetest $ lsattr filetest -u------------e------- filetest $ rm filetest \u5c5e\u6027 s \uff1a \u548c u \u76f8\u53cd\uff0c\u5220\u9664\u6587\u4ef6\u6216\u76ee\u5f55\u65f6\uff0c\u4f1a\u88ab\u5f7b\u5e95\u5220\u9664\uff08\u76f4\u63a5\u4ece\u786c\u76d8\u4e0a\u5220\u9664\uff0c\u7136\u540e\u75280\u586b\u5145\u6240\u5360\u7528\u7684\u533a\u57df\uff09\uff0c\u4e0d\u53ef\u6062\u590d\u3002 \u63d0\u793a\uff1a \u547d\u4ee4 chattr \u548c lsattr \u7684\u53ef\u64cd\u4f5c\u5c5e\u6027\u4f9d\u8d56\u4e8e\u6587\u4ef6\u6240\u5904\u5206\u533a\u7684\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\uff0c\u4f8b\u5982\uff0cext4\u548cxfs\u7684\u7ed3\u679c\u4f1a\u6709\u4e0d\u540c\u3002 \u5386\u53f2\uff1a\u547d\u4ee4 chattr \uff08\u7528\u4e8e\u64cd\u4f5c\u5c5e\u6027\uff09\u548c lsattr \uff08\u7528\u4e8e\u5217\u51fa\u5c5e\u6027\uff09\u6700\u521d\u4e13\u7528\u4e8e\u7b2c\u4e8c\u4e2a\u6269\u5c55\u6587\u4ef6\u7cfb\u7edf\u7cfb\u5217\uff08ext2\u3001ext3\u3001ext4\uff09\uff0c\u5e76\u4e14\u4f5c\u4e3a e2fsprogs \u5305\u7684\u4e00\u90e8\u5206\u63d0\u4f9b\u3002\u7136\u800c\uff0c\u6b64\u529f\u80fd\u5df2\u5168\u90e8\u6216\u90e8\u5206\u6269\u5c55\u5230\u8bb8\u591a\u5176\u4ed6\u7cfb\u7edf\uff0c\u5305\u62ec XFS\u3001ReiserFS\u3001JFS \u548c OCFS2\u3002 btrfs \u6587\u4ef6\u7cfb\u7edf\u5305\u62ec\u5c5e\u6027\u529f\u80fd\uff0c\u5305\u62ec C \u6807\u5fd7\uff0c\u7531\u4e8e\u4e0e CoW \u76f8\u5173\u7684\u6027\u80fd\u8f83\u6162\uff0c\u5b83\u5173\u95ed\u4e86btrfs\u7684\u5185\u7f6e\u5199\u65f6\u590d\u5236 (CoW) \u529f\u80fd\u3002","title":"7.7.\u8bbe\u5b9a\u6587\u4ef6\u7279\u6b8a\u5c5e\u6027chattr"},{"location":"linux/SRE/03-identity-security/#8acl","text":"","title":"8.\u8bbf\u95ee\u63a7\u5236\u5217\u8868ACL"},{"location":"linux/SRE/03-identity-security/#81acl","text":"ACL\u7684\u5168\u79f0\u662fAccess Control List\u3002 \u4f20\u7edf\u7684POSIX\u6743\u9650\u6982\u5ff5\u4f7f\u7528\u4e09\u79cd\u7528\u6237\u7c7b\u578b\u6765\u5206\u914d\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6743\u9650\uff1a\u6240\u6709\u8005Owning Owner\uff0c\u6240\u6709\u8005\u7ec4Owning Group\u548c\u5176\u4ed6\u7528\u6237Other Users\u3002\u53ef\u4ee5\u4e3a\u6bcf\u4e2a\u7528\u6237\u7c7b\u578b\u8bbe\u7f6e\u4e09\u4e2a\u6743\u9650\u4f4d\uff0c\u8d4b\u4e88\u8bfb\uff08r\uff09\uff0c\u5199\uff08w\uff09\u548c\u6267\u884c\uff08x\uff09\u7684\u6743\u9650\u3002 \u6240\u6709\u8005Owning Owner\u6743\u9650\uff08\u5c5e\u4e3b\u6743\u9650\uff09 \u5c5e\u7ec4Owning Group\u6743\u9650 \u5176\u4ed6\uff08\u7ecf\u8fc7\u8eab\u4efd\u9a8c\u8bc1\u7684\uff09\u7528\u6237Other Users\u7684\u6743\u9650 \u4f20\u7edf\u7684\u4e09\u79cd\u6743\u9650\u9002\u7528\u4e8e\u5927\u591a\u6570\u5b9e\u9645\u6848\u4f8b\u3002\u4f46\u662f\uff0c\u5bf9\u4e8e\u66f4\u590d\u6742\u7684\u573a\u666f\u6216\u66f4\u9ad8\u7ea7\u7684\u5e94\u7528\u7a0b\u5e8f\uff0c\u7cfb\u7edf\u7ba1\u7406\u5458\u5fc5\u987b\u4f7f\u7528\u8bb8\u591a\u6280\u5de7\u6765\u89c4\u907f\u4f20\u7edf\u6743\u9650\u7684\u9650\u5236\u3002 \u8bbf\u95ee\u63a7\u5236\u5217\u8868ACL\u63d0\u4f9b\u4e86\u5bf9\u4f20\u7edf\u6587\u4ef6\u6743\u9650\u6982\u5ff5\u7684\u6269\u5c55\u3002\u5b83\u4eec\u5141\u8bb8\u6211\u4eec\u4e3a\u5355\u4e2a\u7528\u6237\u6216\u7ec4\u5206\u914d\u6743\u9650\uff0c\u5373\u4f7f\u8fd9\u4e9b\u7528\u6237\u6216\u7ec4\u4e0e\u539f\u59cb\u6240\u6709\u8005\u6216\u5c5e\u7ec4\u4e0d\u5bf9\u5e94\u3002 ACL\u662fLinux\u5185\u6838\u7684\u4e00\u9879\u529f\u80fd\uff0c\u652f\u6301Ext\u2154/4\uff0cXFS\u548cBtrFS\u6587\u4ef6\u7cfb\u7edf\u4ee5\u53ca\u5176\u4ed6\u6587\u4ef6\u7cfb\u7edf\u3002 \u4f7f\u7528ACL\uff0c\u6211\u4eec\u53ef\u4ee5\u521b\u5efa\u590d\u6742\u7684\u65b9\u6848\uff0c\u800c\u65e0\u9700\u5728\u5e94\u7528\u7a0b\u5e8f\u7ea7\u522b\u4e0a\u53bb\u5b9e\u73b0\u590d\u6742\u7684\u6743\u9650\u6a21\u578b\u3002\u5728\u4f7f\u7528\u63d0\u4f9bSamba\u6587\u4ef6\u548c\u6253\u5370\u670d\u52a1\u7684Linux\u670d\u52a1\u5668\u66ff\u6362Windows\u670d\u52a1\u5668\u7684\u60c5\u51b5\u4e0b\uff0cACL\u7684\u4f18\u52bf\u975e\u5e38\u660e\u663e\u3002\u7531\u4e8eSamba\u652f\u6301ACL\uff0c\u56e0\u6b64\u53ef\u4ee5\u5728Linux\u670d\u52a1\u5668\u548cWindows\u4e2d\u914d\u7f6e\u7528\u6237\u6743\u9650\u3002 \u901a\u8fc7ACL\u6765\u5141\u8bb8\u5bf9\u6240\u6709\u8005\u7528\u6237\u4e4b\u5916\u7684\u5355\u4e2a\u7528\u6237\u8fdb\u884c\u6587\u4ef6\u5199\u6743\u9650\u662f\u4e00\u79cd\u7b80\u5355\u7684\u65b9\u6848\u3002\u4f7f\u7528\u4f20\u7edf\u65b9\u6cd5\uff0c\u6211\u4eec\u5fc5\u987b\u521b\u5efa\u4e00\u4e2a\u65b0\u7ec4\uff0c\u4f7f\u4e24\u4e2a\u7528\u6237\u6210\u4e3a\u8be5\u7ec4\u7684\u6210\u5458\uff0c\u5c06\u8be5\u6587\u4ef6\u7684\u6240\u6709\u7ec4\u66f4\u6539\u4e3a\u65b0\u7ec4\uff0c\u7136\u540e\u6388\u4e88\u8be5\u7ec4\u6587\u4ef6\u7684\u5199\u6743\u9650\u3002\u521b\u5efa\u7ec4\u5e76\u4f7f\u4e24\u4e2a\u7528\u6237\u6210\u4e3a\u8be5\u7ec4\u7684\u6210\u5458\u5219\u9700\u8981\u5229\u7528root\u6743\u9650\u6765\u5b9e\u73b0\u3002 \u4f7f\u7528ACL\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u4f7f\u6240\u6709\u8005\u548c\u6307\u5b9a\u7528\u6237\u5bf9\u6587\u4ef6\u5177\u6709\u5199\u6743\u9650\u6765\u5b9e\u73b0\u76f8\u540c\u7684\u7ed3\u679c\u3002 \u6b64\u65b9\u6cd5\u7684\u53e6\u4e00\u4e2a\u4f18\u70b9\u662f\u7cfb\u7edf\u7ba1\u7406\u5458\u65e0\u9700\u53c2\u4e0e\u521b\u5efa\u7ec4\u3002\u7528\u6237\u53ef\u4ee5\u81ea\u5df1\u51b3\u5b9a\u6388\u4e88\u8c01\u8bbf\u95ee\u5176\u6587\u4ef6\u7684\u6743\u9650\u3002 \u63d0\u793a\uff1a \u4f7f\u7528ACL\u65f6 ls \u7684\u8f93\u51fa\u7ed3\u679c\u4f1a\u53d1\u751f\u53d8\u5316\u3002\u6dfb\u52a0\u4e00\u4e2a\u52a0\u53f7+ \u6765\u8bf4\u660e\u5df2\u4e3a\u6b64\u6587\u4ef6\u5b9a\u4e49ACL\uff0c\u4e14\u5b9a\u4e49ACL\u540e\uff0c\u6240\u663e\u793a\u7684\u5c5e\u7ec4\u6743\u9650\u662fACL\u63a9\u7801\u7684\u503c\uff0c\u800c\u4e0d\u518d\u662f\u539f\u6765\u5c5e\u7ec4\u7684\u6743\u9650\u3002","title":"8.1.ACL"},{"location":"linux/SRE/03-identity-security/#82acl","text":"Minimal ACLs\uff08\u6700\u5c0fACL\uff09\uff08\u5b9e\u9645\u7528\u9014\uff1a\u4e0ePOSIX\u6743\u9650\u76f8\u540c\uff09 \u4e0e\u6587\u4ef6\u6a21\u5f0f\u6743\u9650\u4f4d\u7b49\u6548\u7684ACL\u79f0\u4e3a\u6700\u5c0fACL \u5206\u4e09\u79cd\u7c7b\u578b\u7684ACL\u6761\u76ee\uff0c\u8fd9\u4e9b\u5bf9\u5e94\u4e8e\u6587\u4ef6\u548c\u76ee\u5f55\u7684\u4f20\u7edf\u6743\u9650\u4f4d Owning User \u6240\u6709\u8005 Owning Group \u6240\u6709\u8005\u7ec4 Others \u5176\u4ed6\u7ec4 Extended ACLs\uff08\u6269\u5c55ACL\uff09 \u5177\u6709\u591a\u4e8e\u4e0a\u8ff0\u4e09\u4e2aACL\u6761\u76ee\u7684ACL\u79f0\u4e3a\u6269\u5c55ACL \u6269\u5c55ACL\u8fd8\u5305\u542b\u63a9\u7801\u6761\u76ee\uff0c\u53ef\u4ee5\u5305\u542b\u4efb\u610f\u6570\u91cf\u7684\u6307\u5b9a\u7528\u6237\u548c\u6307\u5b9a\u7ec4\u6761\u76ee","title":"8.2.ACL\u7684\u57fa\u672c\u7c7b\u578b"},{"location":"linux/SRE/03-identity-security/#83acl","text":"\u7528\u6237\u7c7b\uff08User classes\uff09\u3002 \u4f20\u7edf\u7684POSIX\u6743\u9650\u6982\u5ff5\u4f7f\u7528\u4e09\u79cd\u7528\u6237\u7c7b\u6765\u5206\u914d\u6587\u4ef6\u7cfb\u7edf\u4e2d\u7684\u6743\u9650\uff1a\u6240\u6709\u8005Owning Owner\uff0c\u6240\u6709\u8005\u7ec4Owning Group\u548c\u5176\u4ed6\u7528\u6237Other Users\u3002\u53ef\u4ee5\u4e3a\u6bcf\u4e2a\u7528\u6237\u7c7b\u578b\u8bbe\u7f6e\u4e09\u4e2a\u6743\u9650\u4f4d\uff0c\u8d4b\u4e88\u8bfb\uff08r\uff09\uff0c\u5199\uff08w\uff09\u548c\u6267\u884c\uff08x\uff09\u7684\u6743\u9650\u3002 Owner class \u6240\u6709\u8005\u7c7b Group class \u7ec4\u7c7b Other class \u5176\u4ed6\u7c7b ACL\u8bbf\u95ee\u6743\u9650\uff08Access ACL\uff09\uff1a\u786e\u5b9a\u5404\u79cd\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\uff08\u6587\u4ef6\u548c\u76ee\u5f55\uff09\u7684\u7528\u6237\u548c\u7ec4\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u9ed8\u8ba4ACL\uff08Default ACL\uff09\uff1a\u53ea\u80fd\u5e94\u7528\u4e8e\u76ee\u5f55\u3002 \u5b83\u4eec\u786e\u5b9a\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u5728\u521b\u5efa\u65f6\u4ece\u5176\u7236\u76ee\u5f55\u7ee7\u627f\u7684\u6743\u9650\u3002 ACL\u6761\u76ee\uff08ACL entry\uff09\uff1a \u6bcf\u4e2aACL\u7531\u4e00\u7ec4ACL\u6761\u76ee\u7ec4\u6210\u3002 ACL\u6761\u76ee\u5305\u542b\u7c7b\u578b\uff08type\uff09\uff0c\u6761\u76ee\u5f15\u7528\u7684\u7528\u6237\u6216\u7ec4\u7684\u9650\u5b9a\u7b26\uff08qualifier\uff09\uff0c\u4ee5\u53ca\u4e00\u7ec4\u6743\u9650\uff08permissions\uff09\u3002 \u5bf9\u4e8e\u67d0\u4e9b\u6761\u76ee\u7c7b\u578b\uff0c\u672a\u5b9a\u4e49\u7ec4\u6216\u7528\u6237\u7684\u9650\u5b9a\u7b26\u3002","title":"8.3.ACL\u672f\u8bed"},{"location":"linux/SRE/03-identity-security/#84acl","text":"Named user \u6307\u5b9a\u7528\u6237: Lets you assign permissions to individual users. \u5141\u8bb8\u6211\u4eec\u4e3a\u6307\u5b9a\u7528\u6237\u5206\u914d\u6743\u9650\u3002 Named group \u6307\u5b9a\u7ec4: Lets you assign permissions to individual groups. \u5141\u8bb8\u6211\u4eec\u4e3a\u5236\u5b9a\u7ec4\u5206\u914d\u6743\u9650\u3002 Mask \u63a9\u7801: Lets you limit the permissions granted to named users or groups. \u5141\u8bb8\u6211\u4eec\u9650\u5236\u7ed9\u4e88\u6307\u5b9a\u7528\u6237\u6216\u6307\u5b9a\u7ec4\u7684\u6743\u9650\u3002 \u6240\u4ee5\u53ef\u80fd\u7684ACL\u7c7b\u578b Type Text Form owner user::rwx named user user:name:rwx owning group group::rwx named group group:name:rwx mask mask::rwx other other::rwx \u4e0ePOSIX.1\u6743\u9650\u6a21\u578b\u4e0d\u540c\uff0c\u7ec4\u7c7bgroup class\u53ef\u4ee5\u5305\u542b\u5177\u6709\u4e0d\u540c\u6743\u9650\u96c6\u7684ACL\u6761\u76ee\uff0c\u56e0\u6b64\u5355\u72ec\u7684\u7ec4\u7c7b\u6743\u9650\u4e0d\u518d\u8db3\u4ee5\u8868\u793a\u5b83\u5305\u542b\u7684\u6240\u6709ACL\u6761\u76ee\u7684\u6240\u6709\u8be6\u7ec6\u6743\u9650\u3002 \u56e0\u6b64\uff0c\u7ec4\u7c7b\u578b\u6743\u9650\u7684\u542b\u4e49\u88ab\u91cd\u65b0\u5b9a\u4e49\u3002\u5728\u65b0\u8bed\u4e49\u4e0b\uff0c\u7ec4\u7c7b\u578b\u6743\u9650\u8868\u793a\u7ec4\u7c7b\u4e2d\u7684\u4efb\u4f55\u6761\u76ee\u5c06\u6388\u4e88\u7684\u6743\u9650\u7684**\u4e0a\u9650**\uff08upper bound\uff09\u3002 \u6b64\u4e0a\u9650\u5c5e\u6027\u53ef\u786e\u4fdd\u5728\u4f7f\u7528ACL\u63a7\u5236\u540e\uff0c\u5e94\u7528\u7a0b\u5e8f\u4e0d\u4f1a\u7a81\u7136\u6216\u8005\u610f\u5916\u5730\u6388\u4e88\u989d\u5916\u7684\u6743\u9650\u3002 \u5728\u6700\u5c0fACL\u4e2d\uff0c\u7ec4\u7c7b\u6743\u9650\u4e0e\u6240\u6709\u8005\u7ec4\u6743\u9650\u76f8\u540c\u3002\u5728\u6269\u5c55ACL\u4e2d\uff0c\u7ec4\u7c7b\u53ef\u4ee5\u5305\u542b\u5176\u4ed6\u7528\u6237\u6216\u7ec4\u7684\u6761\u76ee\u3002\u8fd9\u4f1a\u5bfc\u81f4\u4e00\u4e2a\u95ee\u9898\uff1a\u8fd9\u4e9b\u9644\u52a0\u6761\u76ee\u4e2d\u7684\u4e00\u4e9b\u53ef\u80fd\u62e5\u6709\u672a\u5305\u542b\u5728\u6240\u6709\u8005\u7ec4\u6761\u76ee\uff08owning group entry\uff09\u4e2d\u7684\u6743\u9650\uff0c\u56e0\u6b64\u6240\u6709\u8005\u7ec4\u6761\u76ee\u6743\u9650\u53ef\u80fd\u4e0e\u7ec4\u7c7b\u6743\u9650\uff08group class\uff09\u4e0d\u540c\u3002 \u901a\u8fc7\u63a9\u7801\uff08mask entry\uff09\u89e3\u51b3\u4e86\u8fd9\u4e2a\u95ee\u9898\u3002 \u4f7f\u7528\u6700\u5c0fACL\uff0c\u7ec4\u7c7b\u6743\u9650\u6620\u5c04\u5230\u6240\u6709\u8005\u7ec4\u6761\u76ee\u6743\u9650\u3002With minimal ACLs, the group class permissions map to the owning group entry permissions. \u4f7f\u7528\u6269\u5c55ACL\u65f6\uff0c\u7ec4\u7c7b\u6743\u9650\u6620\u5c04\u5230\u63a9\u7801\u6761\u76ee\u6743\u9650\uff0c\u800c\u6240\u6709\u8005\u7ec4\u6761\u76ee\u4ecd\u5b9a\u4e49\u62e5\u6709\u7ec4\u6743\u9650\u3002With extended ACLs, the group class permissions map to the mask entry permissions, whereas the owning group entry still defines the owning group permissions.","title":"8.4.ACL\u6743\u9650\u5206\u7c7b"},{"location":"linux/SRE/03-identity-security/#85acl","text":"\u8bbe\u5b9aACL\u6743\u9650\uff1a setfacl Syntax: setfacl [OPTIONS] [ACL-ENTRIES] Option Description -m : Add or modify an ACL entry -x : Remove an ACL entry -d : Set a default ACL -b : Remove all extended ACL entries -M : restore ACLs that have been written to a file \u6ce8\u610f\uff1a--set\u9009\u9879\u4f1a\u628a\u539f\u6709\u7684ACL\u9879\u90fd\u5220\u9664\uff0c\u7528\u65b0\u7684\u66ff\u4ee3\uff0c\u6240\u4ee5\u4e00\u5b9a\u8981\u5305\u542bUGO\u7684\u8bbe\u7f6e\uff0c\u4e0d\u80fd\u50cf-m\u533b\u9662\u53ea\u6dfb\u52a0ACL\u3002 setfacl --set u::rw,u:vagrant:rw,g::r,o::- file1 \u8bfb\u53d6ACL\u6743\u9650\uff1a getfacl Syntax: getfacl [OPTIONS] Option Description -a : Display the file access control list -d : Display the default access control list -R : List the ACLs of all files and directories recursively","title":"8.5.ACL\u64cd\u4f5c\u547d\u4ee4"},{"location":"linux/SRE/03-identity-security/#86acl","text":"","title":"8.6.ACL\u5b9e\u4f8b\u89e3\u6790"},{"location":"linux/SRE/03-identity-security/#861","text":"\u9879\u76ee\u76ee\u5f55 ~/project1 \u9879\u76ee\u7ecf\u7406 pm1 \u5bf9\u8fd9\u4e2a\u76ee\u5f55\u62e5\u6709\u8bbf\u95ee\u548c\u4fee\u6539\u6743\u9650 \u9879\u76ee\u6210\u5458 tm1 \u53ef\u4ee5\u8bbf\u95ee\u548c\u4fee\u6539\u8fd9\u4e2a\u76ee\u5f55 \u975e\u9879\u76ee\u6210\u5458 tm2 \u4e0d\u80fd\u8bbf\u95ee ~/project1 \u76ee\u5f55\u3002 \u9879\u76ee\u76ee\u5f55 ~/project1 \u7684\u6743\u9650\u89c4\u5212 \u9879\u76ee\u7ecf\u7406 pm1 \u662f\u8fd9\u4e2a\u76ee\u5f55\u7684\u5c5e\u4e3b\uff0c\u6743\u9650\u4e3a rwx \u9879\u76ee\u7ecf\u7406 pm1 \u5c5e\u4e8e project1 \u7ec4 \u9879\u76ee\u6210\u5458 tm1 \u4e0e pm1 \u5728\u540c\u4e00\u4e2a project1 \u7ec4\uff0c\u6743\u9650\u662f rw \u5176\u4ed6\u4eba\u7684\u6743\u9650\u8bbe\u5b9a\u4e3a 0 \u9879\u76ee\u4e34\u65f6\u6210\u5458tm2\u7684\u6743\u9650\u9700\u6c42 \u80fd\u8bbf\u95ee project1 \u76ee\u5f55\uff0c\u4f46\u53ea\u80fd\u5177\u6709 r \u548c x \u6743\u9650 \u89e3\u51b3\u65b9\u6cd5 \u5f53\u51fa\u73b0\u8fd9\u79cd\u60c5\u51b5\u65f6\uff0c\u666e\u901a\u6743\u9650\u4e2d\u7684\u4e09\u79cd\u8eab\u4efd\uff08owner\uff0cgroup\uff0cothers\uff09\u5c31\u4e0d\u80fd\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0c\u800cACL\u6743\u9650\u53ef\u4ee5\u3002 \u5728\u4f7f\u7528ACL\u6743\u9650\u7ed9\u7528\u6237 tm2 \u965a\u4e88\u6743\u9650\u65f6\uff0c tm2 \u65e2\u4e0d\u662f ~/project1 \u76ee\u5f55\u7684\u5c5e\u4e3b\uff0c\u4e5f\u4e0d\u662f\u5c5e\u7ec4\uff0c\u4ec5\u4ec5\u8d4b\u4e88\u7528\u6237 tm2 \u9488\u5bf9 ~/project1 \u76ee\u5f55\u7684r-x\u6743\u9650\uff0c \u5c5e\u4e8e\u5355\u72ec\u6307\u5b9a\u7528\u6237\u5e76\u5355\u72ec\u5206\u914d\u6743\u9650\uff0c\u89e3\u51b3\u4e86\u7528\u6237\u8eab\u4efd\u4e0d\u8db3\u7684\u95ee\u9898\u3002 \u62d3\u5c55\u95ee\u9898 \u7ed9 ~/project1 \u76ee\u5f55\u6dfb\u52a0\u5176\u4ed6\u7ec4 project2 \u7684\u8bbf\u95ee\u6743\u9650 \u901a\u8fc7 mask \u6765\u8c03\u6574\u7528\u6237 tm2 \u5b9e\u9645\u6709\u6548\u6743\u9650 \u9ed8\u8ba4ACL\u6743\u9650 \u9012\u5f52ACL\u6743\u9650 \u5220\u9664ACL\u6743\u9650","title":"8.6.1.\u5b9e\u4f8b\u63cf\u8ff0"},{"location":"linux/SRE/03-identity-security/#862","text":"\u521b\u5efa\u6d4b\u8bd5\u7528\u6237 $ whoami vagrant $ sudo groupadd project1 $ sudo groupadd project2 $ sudo useradd -m -g project1 pm1 $ sudo useradd -m -g project1 tm1 $ sudo useradd -m -g project2 tm2 $ sudo passwd pm1 $ sudo passwd tm1 $ sudo passwd tm2 $ cat /etc/group ...... project1:x:1535: project2:x:1536: ...... $ cat /etc/passwd ...... pm1:x:2003:1535::/home/pm1:/bin/bash tm1:x:2004:1535::/home/tm1:/bin/bash tm2:x:2005:1536::/home/tm2:/bin/bash ...... \u521b\u5efa\u6d4b\u8bd5\u76ee\u5f55 project1 , \u6307\u5b9a project1 \u76ee\u5f55\u7684\u6743\u9650\uff0c\u521b\u5efa\u6d4b\u8bd5\u6587\u4ef6 file1 \u3002 $ su - pm1 $ cd ~ $ mkdir project1 $ ls -dl project1 drwxr-xr-x. 1 pm1 project1 0 Dec 4 06 :25 project1 $ chmod 770 project1/ $ ls -dl project1 drwxrwx---. 1 pm1 project1 0 Dec 4 06 :25 project1 $ echo \"hello from $USER \" > ./project1/file1 $ cat ./project1/file1 hello from pm1 \u76ee\u5f55 project1 \u5f53\u524d\u6743\u9650\u5feb\u7167 \u5c5e\u4e3b\uff1a pm1 \uff0c\u5bf9 ~/project1 \u76ee\u5f55\u6709 rwx \u6743\u9650 \u5c5e\u7ec4\uff1a project1 \uff0c\u5305\u542b\u7528\u6237 pm1 \u548c tm1 \uff0c\u5bf9 ~/project1 \u76ee\u5f55\u6709 rwx \u6743\u9650 \u5176\u4ed6\u7ec4\uff1a\u6ca1\u6709\u8bbf\u95ee\u6743\u9650 \u76ee\u5f55 ~/project1 \u5f53\u524d\u7684ACL\u5feb\u7167 $ getfacl ./project1/ # file: home/pm1/project1/ # owner: pm1 # group: project1 user::rwx group::rwx other::---","title":"8.6.2.\u521d\u59cb\u5316\u73af\u5883"},{"location":"linux/SRE/03-identity-security/#863acl","text":"\u7ed9 ~/project1 \u76ee\u5f55\u6dfb\u52a0\u65b0\u7528\u6237 tm2 \uff0c\u6743\u9650\u4e3a rwx \u3002\u76ee\u5f55 ~/project1 \u7684\u66f4\u65b0\u540e\u7684\u6743\u9650\u4f4d\u53d8\u6210\u4e86 drwxrwx---+ \u3002 $ su - pm1 $ setfacl -m u:tm2:rx ./project1/ $ ls -dl ./project1 drwxrwx---+ 1 pm1 project1 0 Dec 4 06 :25 project1 $ getfacl ~/project1/ # file: project1 \uff08\u6587\u4ef6\u540d\uff09 # owner: pm1 \uff08Owner \u6587\u4ef6\u5c5e\u4e3b\uff09 # group: project1 \uff08Owing Group \u6587\u4ef6\u5c5e\u7ec4\uff09 user::rwx \uff08Ower\u6587\u4ef6\u5c5e\u4e3b\u7684\u6743\u9650\uff0c\u7528\u6237\u540d\u680f\u662f\u7a7a\u7684\uff0c\u8bf4\u660e\u662f\u5c5e\u4e3bOwner\u7684\u6743\u9650\uff09 user:tm2:r-x \uff08Named User \u6307\u5b9a\u7528\u6237\u7684\u6743\u9650\uff0c\u7528\u6237tm2\u7684\u6743\u9650\uff09 group::rwx \uff08Owing Group \u6587\u4ef6\u5c5e\u7ec4\u7684\u6743\u9650\uff0c\u7ec4\u540d\u680f\u662f\u7a7a\u7684\uff0c\u8bf4\u660e\u662f\u5c5e\u7ec4\u7684\u6743\u9650\uff09 \uff08Named Group \u6307\u5b9a\u7528\u6237\u7ec4\u7684\u6743\u9650\uff0c\u6b64\u65f6\u672a\u6307\u5b9a\uff09 mask::rwx \uff08mask\u6743\u9650\uff09 other::--- \uff08\u5176\u4ed6\u4ebaother\u7684\u6743\u9650\uff09 \u7ed9 ~/project1 \u76ee\u5f55\u6dfb\u52a0\u65b0\u7ec4 project2 \u7684\u6743\u9650 rwx $ su - pm1 $ setfacl -m g:project2:rwx ./project1/ $ ls -dl ./project1 drwxrwx---+ 1 pm1 project1 0 Dec 4 06 :46 ./project1 $ getfacl ./project1 # file: project1 # owner: pm1 # group: project1 user::rwx user:tm2:r-x ( \u7528\u6237tm2\u62e5\u6709\u4e86r-x\u6743\u9650\uff09 group::rwx group:project2:rwx ( \u7528\u6237\u7ec4project2\u62e5\u6709\u4e86rwx\u6743\u9650\uff09 mask::rwx other::--- \u6709\u6548\u6743\u9650\u7684\u8ba1\u7b97\uff1a \u5f53\u524d ~/project1 \u76ee\u5f55\u7684 mask \u662f rwx \uff0c tm2 \u7684\u6743\u9650\u662f r-x \uff0c\u4e8c\u8005\u8fdb\u884cAND\u64cd\u4f5c\uff0c tm2 \u7684\u5b9e\u9645\u6743\u9650\u662f r-x tm2: r - x ( 1 0 1 ) mask: r w x ( 1 1 1 ) --------------------- result: r - x ( 1 0 1 ) \u5bf9\u7167\u4e0b\u9762\u7684\u89c4\u5219\uff0c\u9a8c\u8bc1\u7528\u6237 tm2 \u5bf9 ~/project1 \u76ee\u5f55\u7684\u5b9e\u9645\u6743\u9650\u3002 su - tm2 \u80fd\u8fdb\u5165\u76ee\u5f55 project1 \uff0c\u8bf4\u660e\u5f53\u524d\u7528\u6237\u5177\u6709\u76ee\u5f55 project1 \u7684 r-x \u6743\u9650\u3002 $ whoami tm2 $ cd /home/pm1/project1/ \u80fd\u5217\u51fa\u76ee\u5f55 project1 \u4e0b\u6587\u4ef6\u5217\u8868\uff0c\u53ef\u4ee5\u67e5\u770b\u6587\u4ef6 file \u7684\u5185\u5bb9\uff0c\u8bf4\u660e\u5f53\u524d\u7528\u6237\u5177\u6709\u76ee\u5f55 project1 \u7684 r-x \u6743\u9650\u3002 $ pwd /home/pm1/project1 $ whoami tm2 $ ls -l -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 $ cat file1 hello from pm1 \u5bf9\u76ee\u5f55 project1 \u4e0d\u5177\u6709 w \u6743\u9650\uff0c\u6240\u4ee5\u65e0\u6cd5\u521b\u5efa\u3001\u5220\u9664\u6216\u4fee\u6539\u76ee\u5f55\u4e0b\u7684\u4efb\u4f55\u6587\u4ef6\u6216\u5b50\u76ee\u5f55\u3002 $ pwd /home/pm1/project1 $ whoami tm2 $ touch file2 touch: cannot touch 'file2' : Permission denied $ echo \"hello from $USER \" >> file1 -bash: file1: Permission denied","title":"8.6.3.\u6dfb\u52a0ACL\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#864mask","text":"\u8c03\u6574 ~/project1 \u76ee\u5f55\u7684 mask \u4e3a r-- \uff0c\u5219 tm2 \u7684\u5b9e\u9645\u6743\u9650\u662f r-- $ su - pm1 $ cd ~ $ setfacl -m m::r ./project1/ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- (\u7528\u6237tm2\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u53d8\u4e3ar--) group::rwx #effective:r-- (\u5c5e\u7ec4project1\u7ec4\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u53d8\u4e3ar--) group:project2:rwx #effective:r-- (\u5176\u4ed6\u7ec4project2\u7ec4\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u53d8\u4e3ar--) mask::r-- ( mask\u53d8\u5316\uff0c\u5bfc\u81f4\u4e0a\u8ff0\u4e24\u4e2agroup\u7684\u6709\u6548\u6743\u9650\u90fd\u53d1\u751f\u4e86\u53d8\u5316 ) other::--- \u6709\u6548\u6743\u9650\u7684\u8ba1\u7b97\uff1a \u5f53\u524d ~/project1 \u76ee\u5f55\u7684 mask \u662f r-- \uff0c\u7528\u6237 tm2 \u3001\u7ec4 project2 \u7684\u5b9e\u9645\u6743\u9650\u662f r-- \u3002 tm2: r - w ( 1 0 1 ) mask: r - - ( 1 0 0 ) --------------------- result: r - - ( 1 0 0 ) \u63d0\u793a\uff1a \u7528\u6237\u548c\u7528\u6237\u7ec4\u6240\u8bbe\u5b9a\u7684\u6743\u9650\u5fc5\u987b\u5728mask\u6743\u9650\u8bbe\u5b9a\u7684\u8303\u56f4\u4e4b\u5185\u624d\u80fd\u751f\u6548\uff0cmask\u6743\u9650\u5c31\u662f\u6700\u5927\u6709\u6548\u6743\u9650\u3002","title":"8.6.4.\u4fee\u6539mask\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#865","text":"\u5728POSIX\u6743\u9650\u6a21\u578b\u548cACL\u6743\u9650\u53e0\u52a0\u4f5c\u7528\u4e0b\uff0c\u7528\u6237\u7684\u5b9e\u9645\u6743\u9650\u5206\u6790\u3002 $ getfacl ./project1/ # file: project1/ # owner: pm1 <----Owner # group: project1 <----owning group user::rwx <----owner 's permissions user:tm2:r-x #effective:r-- <----named user' s permissions group::rwx #effective:r-- <----owning group's permissions group:project2:rwx #effective:r-- <----named group's permissions mask::r-- <----masks for named user and named group other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- \u6240\u6709\u8005ower\u548c\u5176\u4ed6\u7528\u6237other\u6761\u76ee\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\u603b\u662f\u6709\u6548\u7684\u3002\u4e0a\u4f8b\u4e2d\u7684user\u6761\u76ee\u548cother\u6761\u76ee\u3002 \u9664\u4e86\u63a9\u7801\u6761\u76ee\uff0c\u6240\u6709\u5176\u4ed6\u6761\u76ee\uff08\u6bd4\u5982\u6307\u5b9a\u7528\u6237named user\uff09\u53ef\u4ee5\u662f\u6709\u6548\u7684\u6216\u88ab\u5c4f\u853d\u7684\u3002 \u6307\u5b9a\u7528\u6237\uff08named user\uff09\uff0c\u6240\u6709\u8005\u7ec4\uff08owning group\uff09\u6216\u6307\u5b9a\u7ec4\uff08named group\uff09\u4ee5\u53ca\u63a9\u7801mask\u6761\u76ee\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\uff0c\u6709\u6548\u6743\u9650\u662f\u4ed6\u4eec\u6743\u9650\u8fdb\u884c\u903b\u8f91AND\u540e\u7684\u7ed3\u679c\uff0c\u800c\u4e0d\u662f\u5355\u72ec\u7684\u63a9\u7801\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\u6216\u8005\u5404\u81ea\u6761\u76ee\u4e2d\u5b9a\u4e49\u7684\u6743\u3002 \u6709\u6548\u6743\u9650\u8ba1\u7b97\u65b9\u6cd5\u5982\u4e0b\uff0c\u6ce8\u610f\uff0c ls \u547d\u4ee4\u4e2d\u663e\u793a\u51fa\u6765\u7684\u6743\u9650\uff0c\u4e0e\u5b9e\u9645\u7684ACL\u6743\u9650\u662f\u6709\u5dee\u522b\u7684\u3002 tm2: r - w ( 1 0 1 ) group: r w x ( 1 1 1 ) named group: r w x ( 1 1 1 ) mask: r - - ( 1 0 0 ) --------------------------- result: r - - ( 1 0 0 ) \u5c0f\u8d34\u58eb\uff1a \u4e0e\u6587\u4ef6\u6a21\u5f0f\u6743\u9650\u4f4d\u7b49\u6548\u7684ACL\u79f0\u4e3a\u6700\u5c0fACL\uff0c\u5373POSIX\u4f20\u7edf\u6743\u9650\u3002 \u542b\u63a9\u7801mask\u7b49\u5176\u4ed6\u6743\u9650\u6761\u76ee\u7684ACL\u79f0\u4e3a\u6269\u5c55ACL\u3002 \u5728\u6700\u5c0f\u548c\u6269\u5c55ACL\u60c5\u5f62\u4e0b\uff0c\u6240\u6709\u8005\u7c7b\u6743\u9650\uff08owner\uff09\u90fd\u662f\u6620\u5c04\u5230ACL\u7684\u6240\u6709\u8005\u6761\u76ee\u3002 \u5176\u4ed6\u7c7b\u6743\u9650\u6620\u5c04\u5230\u5176\u5404\u81ea\u7684ACL\u6761\u76ee\u3002 \u5728\u6269\u5c55ACL\u60c5\u5f62\u4e0b\uff0c\u7ec4\u7c7b\u6743\u9650\u7684\u6620\u5c04\u662f\u4e0d\u540c\u7684\u3002 \u5bf9\u4e8e\u6ca1\u6709\u63a9\u7801\u7684\u6700\u5c0fACL\uff0c\u7ec4\u7c7b\u6743\u9650\u5c06\u6620\u5c04\u5230ACL\u6240\u6709\u8005\u7ec4\u6761\u76ee\u3002 \u5bf9\u4e8e\u5e26\u6709\u63a9\u7801\u7684\u6269\u5c55ACL\uff0c\u7ec4\u7c7b\u6743\u9650\u5c06\u6620\u5c04\u5230\u63a9\u7801\u6761\u76ee\u3002 \u901a\u8fc7\u6743\u9650\u4f4d\u8fdb\u884c\u5206\u914d\u7684\u6743\u9650\u4ee3\u8868\u4e86\u901a\u8fc7ACL\u8fdb\u884c\u5206\u914d\u7684\u6743\u9650\u7684\u4e0a\u9650\u3002 \u6ca1\u6709\u5728\u8fd9\u91cc\u4f53\u73b0\u7684\u4efb\u4f55\u6743\u9650\uff0c\u8981\u4e48\u4e0d\u5728ACL\u4e2d\uff0c\u8981\u4e48\u65e0\u6548\u3002 \u5bf9\u6743\u9650\u4f4d\u6240\u505a\u7684\u66f4\u6539\u5c06\u7531ACL\u53cd\u6620\uff0c\u53cd\u4e4b\u4ea6\u7136\u3002","title":"8.6.5.\u6709\u6548\u6743\u9650\u5206\u6790"},{"location":"linux/SRE/03-identity-security/#866acl","text":"$ su - pm1 $ touch ./project1/file2 $ mkdir ./project1/cloud $ ll ./project1/ drwxr-xr-x. 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 $ ll -d project1/ drwxr-----+ 1 pm1 project1 30 Dec 4 08 :52 project1/ \u6587\u4ef6 file1 \u548c\u76ee\u5f55 cloud \u6ca1\u6709\u7ee7\u627f project1 \u76ee\u5f55\u7684ACL\u6743\u9650\u3002 \u63d0\u793a\uff1a \u9ed8\u8ba4 ACL\u9650\u53ea\u5bf9\u76ee\u5f55\u751f\u6548\u3002 \u9ed8\u8ba4ACL\u6743\u9650\u7684\u4f5c\u7528\u662f\uff1a\u5982\u679c\u7ed9\u7236\u76ee\u5f55\u8bbe\u5b9a\u4e86\u9ed8\u8ba4 ACL \u6743\u9650\uff0c\u90a3\u4e48\u7236\u76ee\u5f55\u4e2d\u6240\u6709\u65b0\u5efa\u7684\u5b50\u6587\u4ef6\u90fd\u4f1a\u7ee7\u627f\u7236\u76ee\u5f55\u7684ACL\u6743\u9650\u3002 \u4e0b\u9762\u589e\u52a0 ~/project1 \u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u6743\u9650\u3002 $ su - pm1 $ cd ~ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- group::rwx #effective:r-- group:project2:rwx #effective:r-- mask::r-- other::--- $ setfacl -m d:u:tm2:rx ./project1/ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- group::rwx #effective:r-- group:project2:rwx #effective:r-- mask::r-- other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- \u521b\u5efa\u65b0\u5b50\u76ee\u5f55 leonardo \uff0c\u5c31\u7ee7\u627f\u4e86 ~/project1 \u76ee\u5f55\u7684default ACL\u6743\u9650\u8bbe\u5b9a\u3002 \u6ce8\u610f\uff0c\u9ed8\u8ba4ACL\u6743\u9650\u662f\u9488\u5bf9\u65b0\u5efa\u7acb\u7684\u6587\u4ef6\u751f\u6548\u7684\uff0c\u76ee\u5f55cloud\u548c\u6587\u4ef6file1\u5e76\u6ca1\u6709\u56e0\u4e3a\u589e\u52a0\u4e86\u7236\u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u8bbe\u5b9a\u800c\u7ee7\u627f\u9ed8\u8ba4ACL\u6743\u9650\u8bbe\u5b9a. $ su - pm1 $ cd ~ $ mkdir ./project1/leonardo $ ll ./project1/ drwxr-xr-x. 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---+ 1 pm1 project1 0 Dec 4 09 :07 leonardo","title":"8.6.6.\u9ed8\u8ba4ACL\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#867acl","text":"\u9012\u5f52 ACL \u6743\u9650\uff0c\u662f\u6307\u7236\u76ee\u5f55\u5728\u8bbe\u5b9aACL\u6743\u9650\u65f6\uff0c\u6240\u6709\u7684\u5b50\u76ee\u5f55\u4e5f\u4f1a\u62e5\u6709\u76f8\u540c\u7684ACL\u6743\u9650\u3002 $ su - pm1 $ cd ~ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx user:tm2:r-x #effective:r-- group::rwx #effective:r-- group:project2:rwx #effective:r-- mask::r-- other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- $ setfacl -m d:u:tm2:rx -R ./project1/ $ ll ./project1 drwxr-xr-x+ 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---+ 1 pm1 project1 0 Dec 4 09 :07 leonardo","title":"8.6.7.\u9012\u5f52ACL\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#868acl","text":"\u5220\u9664\u7528\u6237 tm2 \u7684ACL\u6743\u9650\u3002 $ su - pm1 $ cd ~ $ setfacl -x u:tm2 ./project1/ $ getfacl ./project1/ # file: project1/ # owner: pm1 # group: project1 user::rwx group::rwx group:project2:rwx mask::rwx other::--- default:user::rwx default:user:tm2:r-x default:group::rwx default:mask::rwx default:other::--- \u5220\u9664\u6240\u6709\u7684ACL\u6743\u9650\u3002 $ setfacl -b ./project1 $ getfacl ./project1 # file: project1/ # owner: pm1 # group: project1 user::rwx group::rwx other::--- $ ll ./project1 drwxr-xr-x+ 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---+ 1 pm1 project1 0 Dec 4 09 :07 leonardo \u9012\u5f52\u5220\u9664\u5168\u90e8ACL\u6743\u9650\u3002 $ setfacl -b -R ./project1 $ ll ./project1/ total 4 drwxr-xr-x. 1 pm1 project1 0 Dec 4 08 :52 cloud -rw-r--r--. 1 pm1 project1 15 Dec 4 07 :15 file1 -rw-r--r--. 1 pm1 project1 0 Dec 4 08 :52 file2 drwxrwx---. 1 pm1 project1 0 Dec 4 09 :07 leonardo","title":"8.6.8.\u5220\u9664ACL\u6743\u9650"},{"location":"linux/SRE/03-identity-security/#87acl","text":"","title":"8.7.ACL\u76ee\u5f55\u5b9e\u4f8b\u89e3\u6790"},{"location":"linux/SRE/03-identity-security/#871acl","text":"\u5207\u6362\u5230pm1\u7528\u6237\uff0c\u5728\u5176\u4e3b\u76ee\u5f55\u4e2d\uff0c\u57fa\u4e8e\u4e0d\u540c\u7684\u63a9\u7801\u521b\u5efa2\u4e2a\u5b50\u76ee\u5f55\u3002 $ su - pm1 $ umask 0022 $ mkdir mydir1 $ umask 0027 $ mkdir mydir2 $ ll -d mydir* drwxr-xr-x. 1 pm1 project1 0 Dec 4 12 :30 mydir1 drwxr-x---. 1 pm1 project1 0 Dec 4 12 :31 mydir2 \u8fd92\u4e2a\u76ee\u5f55\u5f53\u524d\u7684ACL\u72b6\u6001\u5982\u4e0b\uff1a $ getfacl mydir1 # file: mydir1 # owner: pm1 # group: project1 user::rwx group::r-x other::r-x $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx group::r-x other::--- \u4fee\u6539\u76ee\u5f55 mydir2 \u7684ACL\u3002 $ setfacl -m u:tm2:rwx,g:project2:rwx mydir2 $ getfacl mydir2 getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx group::r-x group:project2:rwx mask::rwx other::--- $ ll -d mydir2 drwxrwx---+ 1 pm1 project1 0 Dec 4 12 :31 mydir2 \u73b0\u5728\uff0c\u7528\u6237 tm2 \u548c\u7ec4 project2 \u5bf9\u76ee\u5f55 mydir2 \u90fd\u5177\u6709rwx\u6743\u9650\uff0c\u4f20\u7edfPOSIX\u6743\u9650\u548cACL\u6743\u9650\u4e00\u81f4\u3002 \u73b0\u5728\u5bf9mydir2\u76ee\u5f55\u7ec4\u6743\u9650\u64a4\u9500w\u6743\u9650\u3002 \u7528\u6237 tm2 \u548c\u7ec4 project2 \u5bf9\u76ee\u5f55 mydir2 \u7684\u6709\u6548\u6743\u9650\u53d8\u6210\u4e86 r-x \u3002 mask\u4e5f\u53d7\u7ec4\u6743\u9650\u53d8\u5316\u5f71\u54cd\uff0c\u53d8\u6210\u4e86 r-x \u3002 $ chmod g-w mydir2 $ ll -d mydir2 drwxr-x---+ 1 pm1 project1 0 Dec 4 12 :31 mydir2 $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx #effective:r-x group::r-x group:project2:rwx #effective:r-x mask::r-x other::--- \u901a\u8fc7 chmod \u548c setfacl \u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u6cd5\u5bf9\u76ee\u5f55 mydir2 \u7684\u7ec4\u6743\u9650\u8fdb\u884c\u4fee\u6539\uff0c\u5728ls\u547d\u4ee4\u4e2d\u4f53\u73b0\u662f\u4e00\u6837\u7684\uff0c\u5bf9\u7ec4\u7684\u5b9e\u9645\u6709\u6548\u6743\u9650\u7684\u5f71\u54cd\u4e5f\u662f\u4e00\u6837\u7684\u3002 chmod \u4fee\u6539\u7684\u662f mask \uff0c mask \u53ea\u5f71\u54cd\u9664\u6240\u6709\u8005\u548cother\u7684\u4e4b\u5916\u7684\u4eba\u548c\u7ec4\u7684\u6700\u5927\u6743\u9650\uff0c mask \u9700\u8981\u4e0e\u7528\u6237\u7684\u6743\u9650\u8fdb\u884c\u903b\u8f91\u4e0e\u8fd0\u7b97\u540e\uff0c\u624d\u80fd\u53d8\u6210\u6709\u6548\u6743\u9650\uff0c\u7528\u6237\u6216\u7ec4\u7684\u8bbe\u7f6e\u5fc5\u987b\u5728mask\u6743\u9650\u8bbe\u5b9a\u8303\u56f4\u5185\u624d\u4f1a\u751f\u6548\u3002 setfacl \u53ef\u4ee5\u4e0d\u4fee\u6539mask\u7684\u60c5\u51b5\u4e0b\u53ea\u4fee\u6539 owning group \u7684\u6743\u9650\uff0c\u4e0b\u9762\u7684\u4f8b\u5b50\u8bf4\u660e\u4e86\u8fd9\u4e00\u60c5\u51b5\u3002POSIX\u7ec4\u6743\u9650\u4ecd\u7136\u662f rwx \uff0c\u4f46ACL\u4e2d\u6240\u6709\u8005\u7ec4\u7684\u6743\u9650\u53d8\u6210\u4e86 r-- \u3002 $ setfacl -m g::r mydir2 $ ll -d mydir2 drwxrwx---+ 1 pm1 project1 0 Dec 4 12 :31 mydir2 $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx group::r-- group:project2:rwx mask::rwx other::---","title":"8.7.1.\u76ee\u5f55ACL"},{"location":"linux/SRE/03-identity-security/#872acl","text":"\u76ee\u5f55\u53ef\u4ee5\u5177\u6709\u9ed8\u8ba4ACL\uff0c\u8fd9\u662f\u4e00\u79cd\u7279\u6b8a\u7684ACL\uff0c\u7528\u4e8e\u5b9a\u4e49\u76ee\u5f55\u4e0b\u7684\u5bf9\u8c61\u5728\u521b\u5efa\u65f6\u7ee7\u627f\u7684\u8bbf\u95ee\u6743\u9650\u3002\u9ed8\u8ba4ACL\u4f1a\u5f71\u54cd\u5b50\u76ee\u5f55\u548c\u6587\u4ef6\u3002 \u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u7684\u6743\u9650\u6709\u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u4f20\u9012\u7ed9\u5176\u4e2d\u7684\u6587\u4ef6\u548c\u5b50\u76ee\u5f55\uff1a \u5b50\u76ee\u5f55\u7ee7\u627f\u7236\u76ee\u5f55\u7684\u9ed8\u8ba4ACL\uff0c\u65e2\u4f5c\u4e3a\u81ea\u5df1\u7684\u9ed8\u8ba4ACL\uff0c\u53c8\u4f5c\u4e3a\u81ea\u5df1\u7684\u8bbf\u95eeACL\u3002 \u6587\u4ef6\u7ee7\u627f\u76ee\u5f55\u9ed8\u8ba4ACL\u4f5c\u4e3a\u5176\u81ea\u5df1\u7684\u8bbf\u95eeACL\u3002 \u521b\u5efa\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u7684\u6240\u6709\u7cfb\u7edf\u51fd\u6570\u90fd\u4f7f\u7528mode\u53c2\u6570\uff0c\u8be5\u53c2\u6570\u5b9a\u4e49\u4e86\u65b0\u521b\u5efa\u7684\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u7684\u8bbf\u95ee\u6743\u9650\u3002 \u5982\u679c\u7236\u76ee\u5f55\u6ca1\u6709\u9ed8\u8ba4ACL\uff0c\u5219\u6839\u636eumask\u7684\u8bbe\u7f6e\u8bbe\u7f6e\u6743\u9650\u4f4d\u3002 \u5982\u679c\u7236\u76ee\u5f55\u5b58\u5728\u9ed8\u8ba4ACL\uff0c\u5219\u5206\u914d\u7ed9\u65b0\u5bf9\u8c61\u7684\u6743\u9650\u4f4d\u5219\u662fmode\u53c2\u6570\u6743\u9650\u4e0e\u9ed8\u8ba4ACL\u4e2d\u5b9a\u4e49\u7684\u6743\u9650\u7684\u903b\u8f91\u4e0e\u7684\u7ed3\u679c\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5ffd\u7565umask\u547d\u4ee4\u3002 \u9ed8\u8ba4ACL\u4e0d\u4f1a\u7acb\u5373\u5f71\u54cd\u8bbf\u95ee\u6743\u9650\u3002\u5b83\u4eec\u4ec5\u5728\u521b\u5efa\u6587\u4ef6\u7cfb\u7edf\u5bf9\u8c61\u65f6\u624d\u8d77\u4f5c\u7528\u3002\u8fd9\u4e9b\u65b0\u5bf9\u8c61\u4ec5\u4ece\u5176\u7236\u76ee\u5f55\u7684\u9ed8\u8ba4ACL\u7ee7\u627f\u6743\u9650\u3002 \u547d\u4ee4 mkdir \u5728\u521b\u5efa\u76ee\u5f55\u65f6\u4f1a\u7ee7\u627f\u9ed8\u8ba4ACL\u3002 $ su - pm1 $ getfacl mydir2 # file: mydir2 # owner: pm1 # group: project1 user::rwx user:tm2:rwx group::r-- group:project2:rwx mask::rwx other::--- $ mkdir ./mydir2/sub1 $ ll ./mydir2 drwxr-x---. 1 pm1 project1 0 Dec 4 13 :23 sub1 $ setfacl -d -m g:project2:-w- mydir2 $ mkdir ./mydir2/sub2 $ ll ./mydir2 drwxr-x---. 1 pm1 project1 0 Dec 4 13 :23 sub1 drwxrw----+ 1 pm1 project1 0 Dec 4 13 :27 sub2 $ getfacl ./mydir2/sub2 # file: mydir2/sub2 # owner: pm1 # group: project1 user::rwx group::r-- group:project2:-w- mask::rw- other::--- default:user::rwx default:group::r-- default:group:project2:-w- default:mask::rw- default:other::--- \u5728\u5bf9 mydir2 \u76ee\u5f55\u6dfb\u52a0\u9ed8\u8ba4ACL\u524d\uff0c\u521b\u5efa\u5b50\u76ee\u5f55 sub1 \uff0c\u6dfb\u52a0\u540e\u521b\u5efa\u5b50\u76ee\u5f55 sub2 \u3002\u53ef\u4ee5\u89c2\u5bdf\u5230 sub2 \u5230\u7ee7\u627f\u4e86 mydir2 \u7684\u9ed8\u8ba4ACL\u3002 $ su - tm2 $ cd /home/pm1/mydir2/sub2 -bash: cd: /home/pm1/mydir2/sub2: Permission denied \u4e0a\u4f8b\u4e2d\uff0c\u9ed8\u8ba4ACL\u4e2d\u6307\u5b9a\u7ec4 project2 \u53ea\u5177\u6709w\u6743\u9650\uff0c\u6240\u4ee5\u65e0\u6cd5\u6267\u884c cd \u547d\u4ee4\u8fdb\u5165\u8be5\u76ee\u5f55\u3002 \u8fd9\u8bf4\u660e\u6a21\u5f0f\u503cmode\u4e2d\u7ed9\u4e88\u7684\u6743\u9650 r \u88ab\u5c4f\u853d\u4e86\uff0c\u53ea\u4fdd\u7559\u4e86ACL\u4e2d\u6700\u5c0f\u7684\u6743\u9650 w \u3002","title":"8.7.2.\u76ee\u5f55\u7684\u9ed8\u8ba4ACL"},{"location":"linux/SRE/03-identity-security/#88acl","text":"ACL\u68c0\u67e5\u987a\u5e8f\uff1a Owner Named user Owning group Named group Other If \u8fdb\u7a0b\u7684\u7528\u6237\u6807\u8bc6\u662fOwner\uff0c\u5219owner\u7684ACL\u6761\u76ee\u51b3\u5b9a\u8bbf\u95ee\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7528\u6237\u6807\u8bc6\u662fnamed user\uff0c\u5219name user\u7684ACL\u6761\u76ee\u7684\u6743\u9650\u51b3\u5b9a\u7533\u8bf7\u7684\u8bbf\u95ee\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7ec4\u5c5e\u4e8eowning group\uff0c\u4e14owning group\u7684ACL\u6761\u76ee\u5305\u542b\u6240\u8bf7\u6c42\u7684\u8bbf\u95ee\u6743\u9650\uff0c\u5219\u6388\u4e88\u6240\u8bf7\u6c42\u7684\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7ec4\u5c5e\u4e8enamed group\uff0c\u4e14named group\u7684ACL\u6761\u76ee\u5305\u542b\u6240\u8bf7\u6c42\u7684\u8bbf\u95ee\u6743\u9650\uff0c\u5219\u6388\u4e88\u6240\u8bf7\u6c42\u7684\u6743\u9650 else if \u8fdb\u7a0b\u7684\u7ec4\u5c5e\u4e8eowning group\u6216\u8005named group\uff0c\u4f46owning group\u6216\u8005named group\u7684ACL\u6761\u76ee\u4e0d\u5305\u542b\u6240\u8bf7\u6c42\u7684\u8bbf\u95ee\u6743\u9650\uff0c\u5219\u62d2\u7edd\u6240\u8bf7\u6c42\u7684\u6743\u9650 else ACL\u4e2d\u7684other\u6761\u76ee\u5904\u7406\u7533\u8bf7\u7684\u6743\u9650 If \u5982\u679c\u8fdb\u7a0b\u5339\u914d\u5230owner\u6216\u8005other\u6761\u76ee\u4e2d\u5305\u542b\u6240\u7533\u8bf7\u7684\u6743\u9650\uff0c\u5219\u6388\u4e88\u6743\u9650 else if \u5982\u679c\u8fdb\u7a0b\u5339\u914d\u5230named user\uff0cowning group\uff0c\u6216\u8005named group\u6761\u76ee\u4e2d\u5305\u542b\u6240\u7533\u8bf7\u7684\u6743\u9650\uff0c\u4e14maks\u6761\u76ee\u4e5f\u5305\u542b\u6240\u7533\u8bf7\u7684\u6743\u9650\uff0c\u5219\u6388\u4e88\u6743\u9650 else \u62d2\u7edd\u6743\u9650\u7533\u8bf7 \u5b9e\u9645\u5e94\u7528\u4e3e\u4f8b\uff1a udev\u4f7f\u7528ACL\u7ed9\u4e88\u767b\u5f55\u5230\u56fe\u5f62\u754c\u9762\u7684\u7528\u6237\u8bbf\u95ee\u8bbe\u5907\u7684\u6743\u9650\uff0c\u4f8b\u5982DVD\u9a71\u52a8\u5668 \u67d0\u4e9b\u5e94\u7528\u7a0b\u5e8f\u4e0d\u652f\u6301ACL Star Archiver\u662f\u4e00\u4e2a\u5b8c\u5168\u4fdd\u7559ACL\u7684\u5907\u4efd\u5e94\u7528\u7a0b\u5e8f\uff0c\u5176\u4ed6\u4eba\u53ef\u80fd\u4f1a\u4e5f\u53ef\u80fd\u4e0d\u4f1a\u4fdd\u7559\u5b83 \u8bb8\u591a\u7f16\u8f91\u5668\u548c\u6587\u4ef6\u7ba1\u7406\u5668\u4e0d\u5141\u8bb8\u5728\u5e94\u7528\u7a0b\u5e8f\u4e2d\u67e5\u770b\u6216\u8bbe\u7f6eACL","title":"8.8.ACL\u68c0\u67e5\u903b\u8f91"},{"location":"linux/SRE/04-TextTools/","text":"\u7b2c\u56db\u7ae0 \u6587\u672c\u7f16\u8f91 \u00b6 1.\u6587\u672c\u7f16\u8f91\u5668 \u00b6 1.1.vim\u5de5\u5177 \u00b6 vim\u547d\u4ee4\u683c\u5f0f\uff1a +# file : \u6253\u5f00\u6587\u4ef6\u540e\uff0c\u8ba9\u5149\u6807\u5904\u4e8e\u7b2c#\u884c\u9996\uff0c+\u9ed8\u8ba4\u884c\u5c3e +/PATTERN file : \u6253\u5f00\u6587\u4ef6\u6709\uff0c\u8ba9\u5149\u6807\u5904\u4e8e\u7b2c\u4e00\u4e2a\u88abPATTERN\u5339\u914d\u5230\u7684\u884c\u9996 -b file : \u4e8c\u8fdb\u5236\u65b9\u5f0f\u6253\u5f00\u6587\u4ef6 -d file1 file2 ... : \u6bd4\u8f83\u591a\u4e2a\u6587\u4ef6\uff0c\u76f8\u5f53\u4e8e vimdiff -m file : \u53ea\u8bfb\u65b9\u5f0f\u6253\u5f00\u6587\u4ef6 -e file : \u8fdb\u5165ex\u6a21\u5f0f\uff0c\u76f8\u5f53\u4e8e ex file -y file : vim\u4e09\u79cd\u5e38\u89c1\u6a21\u5f0f\uff1a \u666e\u901a\u6a21\u5f0fNormal\u6216\u547d\u4ee4\u6a21\u5f0f \u63d2\u5165Insert\u6216\u7f16\u8f91\u6a21\u5f0f \u6269\u5c55\u547d\u4ee4\u6a21\u5f0fExtended Command \u4e09\u79cd\u6a21\u5f0f\u5207\u6362 \u547d\u4ee4\u6a21\u5f0f\u2192\u63d2\u5165\u6a21\u5f0f i\uff1ainsert\uff0c\u5728\u5149\u6807\u5904\u8f93\u5165 I\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u9996\u8f93\u5165 a\uff1aappend\uff0c\u5728\u5149\u6807\u5904\u540e\u9762\u8f93\u5165 A\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u5c3e\u8f93\u5165 o\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u7684\u4e0b\u65b9\u6253\u5f00\u4e00\u4e2a\u65b0\u884c O\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u7684\u4e0a\u65b9\u6253\u5f00\u4e00\u4e2a\u65b0\u884c \u63d2\u5165\u6a21\u5f0f\u2192 ESC \u2192 \u547d\u4ee4\u6a21\u5f0f \u547d\u4ee4\u6a21\u5f0f\u2192 : \u2192 \u6269\u5c55\u547d\u4ee4\u6a21\u5f0f \u6269\u5c55\u547d\u4ee4\u6a21\u5f0f\u2192 ESC, enter \u2192 \u547d\u4ee4\u6a21\u5f0f \u6269\u5c55\u547d\u4ee4\u6a21\u5f0f\u5e38\u7528\u547d\u4ee4\uff1a :wq : \u4fdd\u5b58\u6587\u4ef6\u5e76\u9000\u51fa :w : \u4fdd\u5b58\u6587\u4ef6 :w filename : \u5199\u5165\u6307\u5b9a\u6587\u4ef6\uff0c\u76f8\u5f53\u4e8e\u53e6\u5b58\u4e3a :q! : \u653e\u5f03\u4efb\u4f55\u4fee\u6539\u5e76\u9000\u51fa ZQ : \u65e0\u6761\u4ef6\u9000\u51fa :join : \u5408\u5e76\u591a\u884c J : \u5408\u5e76\u4e24\u884c \u8bbe\u7f6e\uff1a\uff08\u53ef\u4ee5\u5728 /etc/vimrc \u6587\u4ef6\u4e2d\u914d\u7f6e\uff09 :set textwidth : \u8bbe\u7f6e\u6587\u672c\u5bbd\u5ea6\uff08\u4ece\u5de6\u5411\u53f3\u8ba1\u6570\uff09 :set wrapmargin=# : \u8bbe\u7f6e\u884c\u8fb9\u8ddd\uff08\u4ece\u53f3\u5411\u5de6\u8ba1\u6570\uff09 :set endofline : \u8bbe\u7f6e\u6587\u4ef6\u7ed3\u675f\u7b26 :set noendofline : \u53d6\u6d88\u6587\u4ef6\u7ed3\u675f\u7b26 :set wrap : \u81ea\u52a8\u6362\u884c :set nowrap : \u53d6\u6d88\u81ea\u52a8\u6362\u884c :set number : \u663e\u793a\u884c\u53f7 :set nonumber : \u53d6\u6d88\u663e\u793a\u884c\u53f7 :set list : \u8fdb\u5165List Mode\uff0c\u663e\u793aTab ^I\uff0c\u6362\u884c\u7b26\uff0c\u548c$\u663e\u793a :set nolist : \u9000\u51faList Mode :set ignorecase : \u5ffd\u7565\u5b57\u7b26\u7684\u5927\u5c0f\u5199 :set noic : \u4e0d\u5ffd\u7565\u5b57\u7b26\u5927\u5c0f\u5199 :set autoindent : \u542f\u7528\u81ea\u52a8\u7f29\u8fdb :set noai : \u5173\u95ed\u81ea\u52a8\u7f29\u8fdb :set hlsearch : \u542f\u7528\u9ad8\u4eae\u641c\u7d22 :set nohlsearch : \u5173\u95ed\u9ad8\u4eae\u641c\u7d22 :set fileformat=dos : \u542f\u7528windows\u683c\u5f0f :set fileformat=unix : \u542f\u7528unix\u683c\u5f0f :set expandtab : \u542f\u7528\u7a7a\u683c\u4ee3\u66ffTAB\uff0c\u9ed8\u8ba48\u4e2a\u7a7a\u683c\u4ee3\u66ff\u4e00\u4e2aTAB :set noexpandtab : \u5173\u95ed\u7a7a\u683c\u4ee3\u66ffTAB :set tabstop=# : \u6307\u5b9a#\u4e2a\u7a7a\u683c\u4ee3\u66ff\u4e00\u4e2aTAB :set shiftwidth=# : \u8bbe\u7f6e#\u4e2a\u7f29\u8fdb\u5bbd\u5ea6 :set cursorline : \u8bbe\u7f6e\u5149\u6807\u6240\u5728\u884c\u7684\u8868\u793a\u7ebf :set cursorline : \u5173\u95ed\u5149\u6807\u6240\u5728\u884c\u7684\u8868\u793a\u7ebf :set key=PASSWORD : \u542f\u7528\u5bc6\u7801\u4fdd\u62a4 :set key= : \u5173\u95ed\u5bc6\u7801\u4fdd\u62a4 :help option-list : \u83b7\u53d6\u5e2e\u52a9 \u67e5\u627e /pattern : \u4ece\u5149\u6807\u5f00\u59cb\u5904\u5411\u6587\u4ef6\u5c3e\u641c\u7d22pattern ?pattern : \u4ece\u5149\u6807\u5f00\u59cb\u5904\u5411\u6587\u4ef6\u9996\u641c\u7d22pattern n : \u5728\u540c\u4e00\u65b9\u5411\u91cd\u590d\u4e0a\u4e00\u6b21\u641c\u7d22\u547d\u4ee4 N : \u5728\u53cd\u65b9\u5411\u4e0a\u91cd\u590d\u4e0a\u4e00\u6b21\u641c\u7d22\u547d\u4ee4 # : \u5411\u4e0a\u5b8c\u6574\u5339\u914d\u5149\u6807\u4e0b\u7684\u5355\u8bcd, \u76f8\u5f53\u4e8e\uff1fword * : \u5411\u4e0b\u5b8c\u6574\u5339\u914d\u5149\u6807\u4e0b\u7684\u5355\u8bcd, \u76f8\u5f53\u4e8e/word % : \u67e5\u627e\u5bf9\u5e94\u7684( [ {\u5339\u914d nfx : \u5728\u5f53\u524d\u884c\u67e5\u627e\u5149\u6807\u540e\u7b2cn\u4e2ax\uff08\u4e00\u822c\u76f4\u63a5fx\uff09 \u66ff\u6362 :%s/\\n//g : \u5220\u9664\u6362\u884c\u7b26 :s/p1/p2/g : \u5c06\u5f53\u524d\u884c\u4e2d\u6240\u6709p1\u5747\u7528p2\u66ff\u4ee3, \u65e0g\uff0c\u5219\u53ea\u66ff\u6362\u7b2c\u4e00\u4e2a :s/p1/p2/c : \u67e5\u627e\u66ff\u6362\u8981\u6c42\u786e\u8ba4 :n1,n2s/p1/p2/g : \u5c06\u7b2cn1\u81f3n2\u884c\u4e2d\u6240\u6709p1\u5747\u7528p2\u66ff\u4ee3 :%s/p1/p2/g : \u5168\u5c40\uff0c\u4f7f\u7528p2\u66ff\u6362p1 :%s/p1/p2/gc : \u66ff\u6362\u524d\u8be2\u95ee :n,$s/vivian/sky/ : \u66ff\u6362\u7b2cn\u884c\u5f00\u59cb\u5230\u6700\u540e\u4e00\u884c\u4e2d\u6bcf\u4e00\u884c\u7684\u7b2c\u4e00\u4e2avivian\u4e3asky\uff0cn\u4e3a\u6570\u5b57 :.,$s/vivian/sky/g : \u66ff\u6362\u5f53\u524d\u884c\u5f00\u59cb\u5230\u6700\u540e\u4e00\u884c\u4e2d\u6bcf\u4e00\u884c\u6240\u6709vivian\u4e3asky :s/vivian\\//sky\\// : \u66ff\u6362\u5f53\u524d\u884c\u7b2c\u4e00\u4e2avivian/\u4e3asky/\uff0c\u53ef\u4ee5\u4f7f\u7528\\\u4f5c\u4e3a\u8f6c\u4e49\u7b26 :1,$s/^/some string/ : \u5728\u6587\u4ef6\u7684\u7b2c\u4e00\u884c\u81f3\u6700\u540e\u4e00\u884c\u7684\u884c\u9996\u524d\u63d2\u5165some string :%s/$/some string/g : \u5728\u6574\u4e2a\u6587\u4ef6\u6bcf\u4e00\u884c\u7684\u884c\u5c3e\u6dfb\u52a0some string :%s/\\s\\+$// : \u53bb\u6389\u6240\u6709\u7684\u884c\u5c3e\u7a7a\u683c\uff0c\u201c\\s\u201d\u8868\u793a\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u548c\u5236\u8868\u7b26\uff09\uff0c\u201c+\u201d\u5bf9\u524d\u9762\u7684\u5b57\u7b26\u5339\u914d\u4e00\u6b21\u6216\u591a\u6b21\uff08\u8d8a\u591a\u8d8a\u597d\uff09\uff0c\u201c \\(\u201d\u5339\u914d\u884c\u5c3e\uff08\u4f7f\u7528\u201c\\$\u201d\u8868\u793a\u5355\u7eaf\u7684\u201c\\) \u201d\u5b57\u7b26\uff09 :%s/\\s\u2217\\n\\+/\\r/ : \u53bb\u6389\u6240\u6709\u7684\u7a7a\u767d\u884c\uff0c\u201c \\(\u201d\u548c\u201c\\) \u201d\u5bf9\u8868\u8fbe\u5f0f\u8fdb\u884c\u5206\u7ec4\uff0c\u4f7f\u5176\u88ab\u89c6\u4f5c\u4e00\u4e2a\u4e0d\u53ef\u5206\u5272\u7684\u6574\u4f53 :%s!\\s*//.*!! : \u53bb\u6389\u6240\u6709\u7684\u201c//\u201d\u6ce8\u91ca :%s!\\s*/\\*\\_.\\{-}\\*/\\s*!!g : \u53bb\u6389\u6240\u6709\u7684\u201c/**/\u201d\u6ce8\u91ca :%s= *$== : \u5c06\u6240\u6709\u884c\u5c3e\u591a\u4f59\u7684\u7a7a\u683c\u5220\u9664 :g/^\\s*$/d : \u5c06\u6240\u6709\u4e0d\u5305\u542b\u5b57\u7b26(\u7a7a\u683c\u4e5f\u4e0d\u5305\u542b)\u7684\u7a7a\u884c\u5220\u9664 r : \u66ff\u6362\u5f53\u524d\u5b57\u7b26 R : \u66ff\u6362\u5f53\u524d\u5b57\u7b26\u53ca\u5176\u540e\u7684\u5b57\u7b26\uff0c\u76f4\u81f3\u6309ESC\u952e \u7f16\u8f91 h : \u5149\u6807\u5de6\u79fb\u4e00\u4e2a\u5b57\u7b26[\u56de\u9000\u952eBackspace] l : \u5149\u6807\u53f3\u79fb\u4e00\u4e2a\u5b57\u7b26[\u7a7a\u683c\u952eSpace] K : \u5149\u6807\u4e0a\u79fb\u4e00\u884c j : \u5149\u6807\u4e0b\u79fb\u4e00\u884c w : \u5149\u6807\u8df3\u5230\u4e0b\u4e2aword\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd(\u5305\u62ec\u6807\u70b9\u7b26\u53f7) [\u5e38\u7528] W : \u79fb\u5230\u4e0b\u4e00\u4e2a\u5b57\u7684\u5f00\u5934\uff0c\u5ffd\u7565\u6807\u70b9\u7b26\u53f7 B : \u5149\u6807\u56de\u5230\u4e0a\u4e2aword\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd B : \u79fb\u5230\u524d\u4e00\u4e2a\u5b57\u7684\u5f00\u5934\uff0c\u5ffd\u7565\u6807\u70b9\u7b26\u53f7 BACK E : \u5149\u6807\u8df3\u5230\u4e0b\u4e2aword\u7684\u6700\u540e\u4e00\u4e2a\u5b57\u6bcd E : \u79fb\u5230\u4e0b\u4e00\u4e2a\u5b57\u7684\u7ed3\u5c3e\uff0c\u5ffd\u7565\u6807\u70b9\u7b26\u53f7 END 0 : \u79fb\u5230\u5f53\u524d\u4e00\u884c\u7684\u5f00\u59cb[Home] $ : \u79fb\u5230\u5f53\u524d\u4e00\u884c\u7684\u6700\u540e[End] ^ : \u547d\u4ee4\u5c06\u5149\u6807\u79fb\u52a8\u5230\u5f53\u524d\u884c\u7684\u7b2c\u4e00\u4e2a\u975e\u7a7a\u767d\u5b57\u7b26\u4e0a g_ : \u5230\u672c\u884c\u6700\u540e\u4e00\u4e2a\u4e0d\u662fblank\u5b57\u7b26\u7684\u4f4d\u7f6e Enter : \u5149\u6807\u4e0b\u79fb\u4e00\u884c n+ : \u5149\u6807\u4e0b\u79fbn\u884c\u3010\u6309\u4e0a\u6863\u952e \u6570\u5b57shift +\u3011 n- : \u5149\u6807\u4e0a\u79fbn\u884c G : \u79fb\u5230\u6587\u4ef6\u7684\u6700\u540e\u4e00\u884c nG \u6216\u8005 :n : \u79fb\u5230\u6587\u4ef6\u7684\u7b2cn\u884c\ue5e5\ue5e5\ue5e5 gg : \u79fb\u52a8\u5230\u6587\u6863\u7684\u5f00\u59cb [[ : \u6587\u4ef6\u5f00\u59cb\u4f4d\u7f6e\u2014\u2014\u5f00\u59cb\u884c ]] : \u6587\u4ef6\u7ed3\u675f\u4f4d\u7f6e\u2014\u2014\u672b\u5c3e\u884c H : \u5149\u6807\u79fb\u81f3\u5c4f\u5e55\u9876\u884cHEAD\u3002\u5149\u6807\u5b9a\u4f4d\u5728\u663e\u793a\u5c4f\u7684\u7b2c\u4e00\u884c M : \u79fb\u5230\u5c4f\u5e55\u7684\u4e2d\u95f4\u884c\u5f00\u5934 Middle\u3002\u5149\u6807\u5b9a\u4f4d\u5728\u663e\u793a\u5c4f\u7684\u4e2d\u95f4 L : \u79fb\u5230\u5c4f\u5e55\u7684\u6700\u540e\u4e00\u884cLAST\u3002\u5149\u6807\u5b9a\u4f4d\u5728\u663e\u793a\u5c4f\u7684\u6700\u540e\u4e00\u884c ( : \u5149\u6807\u79fb\u81f3\u53e5\u9996 ) : \u5149\u6807\u79fb\u81f3\u53e5\u5c3e { : \u79fb\u5230\u6bb5\u843d\u7684\u5f00\u5934 } : \u79fb\u5230\u4e0b\u4e00\u4e2a\u6bb5\u843d\u7684\u5f00\u5934 % : \u5339\u914d\u62ec\u53f7\u79fb\u52a8\uff0c\u5305\u62ec (, {, [.\uff08\u9700\u8981\u628a\u5149\u6807\u5148\u79fb\u5230\u62ec\u53f7\u4e0a\uff09\u8df3\u8f6c\u5230\u4e0e\u4e4b\u5339\u914d\u7684\u62ec\u53f7\u5904 * \u548c # : \u5339\u914d\u5149\u6807\u5f53\u524d\u6240\u5728\u7684\u5355\u8bcd\uff0c\u79fb\u52a8\u5149\u6807\u5230\u4e0b\u4e00\u4e2a\uff08\u6216\u4e0a\u4e00\u4e2a\uff09\u5339\u914d\u5355\u8bcd\uff08*\u662f\u4e0b\u4e00\u4e2a\uff0c#\u662f\u4e0a\u4e00\u4e2a\uff09 zf : \u6298\u53e0\uff08\u9700\u52a0\u65b9\u5411\u952e\uff09 zo : \u5c55\u5f00\uff08\u7a7a\u683c\u4e5f\u53ef\u4ee5\u5c55\u5f00\uff09 CTRL+u : \u5411\u6587\u4ef6\u9996\u7ffb\u534a\u5c4fup CTRL+d : \u5411\u6587\u4ef6\u5c3e\u7ffb\u534a\u5c4fdown CTRL+f : \u5411\u6587\u4ef6\u5c3e\u7ffb\u4e00\u5c4f forward (fact\u6574\u5c4f\u53bb\u4e24\u884c) CTRL+b : \u5411\u6587\u4ef6\u9996\u7ffb\u4e00\u5c4fback (fact\u6574\u5c4f\u53bb\u4e24\u884c) CTRL-] : \u8df3\u8f6c\u5230\u5f53\u524d\u5149\u6807\u6240\u5728\u5355\u8bcd\u5bf9\u5e94\u7684\u4e3b\u9898 CTRL-O : \u56de\u5230\u524d\u4e00\u4e2a\u4f4d\u7f6e SHIFT+V : \u9009\u62e9\u6574\u884c zz : \u547d\u4ee4\u4f1a\u628a\u5f53\u524d\u884c\u7f6e\u4e3a\u5c4f\u5e55\u6b63\u4e2d\u592e(z\u5b57\u53d6\u5176\u8c61\u5f62\u610f\u4e49\u6a21\u62df\u4e00\u5f20\u7eb8\u7684\u6298\u53e0\u53ca\u53d8\u5f62\u4f4d\u7f6e\u91cd\u7f6e) zt : \u547d\u4ee4\u4f1a\u628a\u5f53\u524d\u884c\u7f6e\u4e8e\u5c4f\u5e55\u9876\u7aef(top) zb : \u547d\u4ee4\u4f1a\u628a\u5f53\u524d\u884c\u7f6e\u4e8e\u5c4f\u5e55\u5e95\u7aef(bottom) 50% : \u5149\u6807\u5b9a\u4f4d\u5728\u6587\u4ef6\u7684\u4e2d\u95f4 ` : \u8df3\u8f6c\u5230\u6700\u8fd1\u5149\u6807\u5b9a\u4f4d\u7684\u4f4d\u7f6e\uff08\u53ea\u80fd\u8bb0\u5fc6\u6700\u8fd1\u4e24\u4e2a\u4f4d\u7f6e\uff09 \u53cd\u5f15\u53f7 I : \u5728\u5149\u6807\u524d\u5f00\u59cb\u63d2\u5165\u5b57\u7b26 insert I : \u5728\u5f53\u524d\u884c\u9996\u5f00\u59cb\u63d2\u5165\u5b57\u7b26 A : \u5728\u5149\u6807\u4f4d\u7f6e\u540e\u5f00\u59cb\u52a0\u5b57 append A : \u5728\u5149\u6807\u6240\u5728\u884c\u7684\u6700\u540e\u9762\u5f00\u59cb\u52a0\u5b57 O : \u5728\u5149\u6807\u4e0b\u52a0\u4e00\u7a7a\u767d\u884c\u5e76\u5f00\u59cb\u52a0\u5b57 open O : \u5728\u5149\u6807\u4e0a\u52a0\u4e00\u7a7a\u767d\u884c\u5e76\u5f00\u59cb\u52a0\u5b57 R : \u66ff\u6362\u5f53\u524d\u5b57\u7b26 R : \u66ff\u6362\u5f53\u524d\u5b57\u7b26\u53ca\u5176\u540e\u7684\u5b57\u7b26\u3010\u5f53\u524d\u53ca\u5176\u540e\u5b57\u7b26\u88ab\u8986\u76d6\u3011 S : \u9ed8\u8ba4\u5220\u9664\u5149\u6807\u6240\u5728\u5b57\u7b26\uff0c\u8f93\u5165\u5185\u5bb9\u63d2\u5165\u4e4b= xi S : \u9ed8\u8ba4\u5220\u9664\u5f53\u524d\u884c\u5185\u5bb9\uff0c\u8f93\u5165\u5185\u5bb9\u4f5c\u4e3a\u5f53\u524d\u884c\u65b0\u5185\u5bb9= dd+o nx : \u5220\u9664\u7531\u5149\u6807\u4f4d\u7f6e\u8d77\u59cb\u540e\u7684n\u4e2a\u5b57\u7b26\uff08\u542b\u5149\u6807\u4f4d\u7f6e\uff09x =dl(\u5220\u9664\u5f53\u524d\u5149\u6807\u4e0b\u7684\u5b57\u7b26) nX : \u5220\u9664\u7531\u5149\u6807\u4f4d\u7f6e\u8d77\u59cb\u524d\u7684n\u4e2a\u5b57\u7b26\uff08\u542b\u5149\u6807\u4f4d\u7f6e\uff09X =dh(\u5220\u9664\u5f53\u524d\u5149\u6807\u5de6\u8fb9\u7684\u5b57\u7b26) d0 : \u5220\u81f3\u884c\u9996 d$ : \u5220\u81f3\u884c\u5c3e dfa : \u8868\u793a\u5220\u9664\u4ece\u5f53\u524d\u5149\u6807\u5230\u5149\u6807\u540e\u9762\u7684\u7b2c\u4e00\u4e2aa\u5b57\u7b26\u4e4b\u95f4\u7684\u5185\u5bb9 D : \u4ee3\u8868d$(\u5220\u9664\u5230\u884c\u5c3e\u7684\u5185\u5bb9) C : \u4ee3\u8868c$(\u4fee\u6539\u5230\u884c\u5c3e\u7684\u5185\u5bb9) ndw : \u5220\u9664\u5149\u6807\u5904\u5f00\u59cb\u53ca\u5176\u540e\u7684n-1\u4e2a\u5b57 ndb : \u5220\u9664\u5149\u6807\u5904\u5f00\u59cb\u53ca\u5176\u524d\u7684n-1\u4e2a\u5b57 diw : \u5220\u9664\u5f53\u524d\u5149\u6807\u6240\u5728\u7684word(\u4e0d\u5305\u62ec\u7a7a\u767d\u5b57\u7b26)\uff0c\u610f\u4e3aDelete Inner Word \u4e24\u4e2a\u7b26\u53f7\u4e4b\u95f4\u7684\u5355\u8bcd daw : \u5220\u9664\u5f53\u524d\u5149\u6807\u6240\u5728\u7684word(\u5305\u62ec\u7a7a\u767d\u5b57\u7b26)\uff0c\u610f\u4e3aDelete A Word ndd : \u5220\u9664\u5f53\u524d\u884c\u53ca\u5176\u540en-1\u884c :n1,n2 d : \u5c06 n1\u884c\u5230n2\u884c\u4e4b\u95f4\u7684\u5185\u5bb9\u5220\u9664 dG : \u5220\u9664\u5f53\u524d\u884c\u81f3\u6587\u4ef6\u5c3e\u7684\u5185\u5bb9 Dgg : \u5220\u9664\u5f53\u524d\u884c\u81f3\u6587\u4ef6\u5934\u7684\u5185\u5bb9 d+enter : \u5220\u96642\u884c\u3010\u5305\u62ec\u5149\u6807\u4e00\u884c\u3011 cw : \u5220\u9664\u5f53\u524d\u5b57\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f\u3010\u5f88\u597d\u7528\uff0c\u5feb\u901f\u66f4\u6539\u4e00\u4e2a\u5355\u8bcd\u3011\u76f8\u5f53\u4e8edw+i ncw : \u5220\u9664\u5f53\u524d\u5b57\u53ca\u5176\u540e\u7684n-1\u4e2a\u5b57\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f\\\u4fee\u6539\u6307\u5b9a\u6570\u76ee\u7684\u5b57 cc : \u5220\u9664\u5f53\u524d\u884c\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f ncc : \u5220\u9664\u5f53\u524d\u884c\u53ca\u5176\u540e\u7684n-1\u884c\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f guw : \u5149\u6807\u4e0b\u7684\u5355\u8bcd\u53d8\u4e3a\u5c0f\u5199 gUw : \u5149\u6807\u4e0b\u7684\u5355\u8bcd\u53d8\u4e3a\u5927\u5199 xp : \u5de6\u53f3\u4ea4\u6362\u5149\u6807\u5904\u4e24\u5b57\u7b26\u7684\u4f4d\u7f6e ga : \u663e\u793a\u5149\u6807\u4e0b\u7684\u5b57\u7b26\u5728\u5f53\u524d\u4f7f\u7528\u7684encoding\u4e0b\u7684\u5185\u7801 nyl : \u590d\u5236n\u4e2a\u5b57\u7b26(\u4e5f\u53efnyh) yw : \u590d\u5236\u4e00\u4e2a\u5355\u8bcd y0 : \u8868\u793a\u62f7\u8d1d\u4ece\u5f53\u524d\u5149\u6807\u5230\u5149\u6807\u6240\u5728\u884c\u9996\u7684\u5185\u5bb9 y$ : \u590d\u5236\u4ece\u5f53\u524d\u4f4d\u7f6e\u5230\u884c\u5c3e yfa : \u8868\u793a\u62f7\u8d1d\u4ece\u5f53\u524d\u5149\u6807\u5230\u5149\u6807\u540e\u9762\u7684\u7b2c\u4e00\u4e2aa\u5b57\u7b26\u4e4b\u95f4\u7684\u5185\u5bb9 yG : \u590d\u5236\u4ece\u6240\u5728\u884c\u5230\u6700\u540e\u4e00\u884c nyy : \u5c06\u5149\u6807\u6240\u5728\u4f4d\u7f6e\u5f00\u59cb\u7684n\u884c\u6570\u636e\u590d\u5236\u6682\u5b58, \u590d\u5236\u4e00\u6574\u884c CTRL+v \u65b9\u5411y : \u5217\u9009\u62e9\u6a21\u5f0f\uff0c\u590d\u5236\u9009\u62e9\u7684\u5f88\u591a\u884c\uff1a\u5148\u4f7f\u7528V\u8fdb\u5165visual\u6a21\u5f0f\uff0c\u7136\u540ej\u5411\u4e0b\u79fb\u52a8\u5230\u4f60\u60f3\u590d\u5236\u7684\u884c\u4e3a\u6b62\uff0c\u7136\u540ey p : \u590d\u5236\u6682\u5b58\u6570\u636e\u5728\u5149\u6807\u7684\u4e0b\u4e00\u884c P : \u590d\u5236\u6682\u5b58\u6570\u636e\u5728\u5149\u6807\u7684\u4e0a\u4e00\u884c :n1,n2 co n3 : \u5c06n1\u884c\u5230n2\u884c\u4e4b\u95f4\u7684\u5185\u5bb9\u62f7\u8d1d\u5230\u7b2cn3+1\u884c\u3010n3\u884c\u7684\u4e0b\u4e00\u884c\u3011 :n1,n2 m n3 : \u5c06n1\u884c\u5230n2\u884c\u4e4b\u95f4\u7684\u5185\u5bb9\u79fb\u81f3\u5230\u7b2cn3\u884c\u4e0b J : \u628a\u4e0b\u4e00\u884c\u7684\u6570\u636e\u8fde\u63a5\u5230\u672c\u884c\u4e4b\u540e, \u591a\u4e00\u7a7a\u683c ~ : \u6539\u53d8\u5f53\u524d\u5149\u6807\u4e0b\u5b57\u7b26\u7684\u5927\u5c0f\u5199 \u5176\u4ed6 . : \u91cd\u590d\u524d\u4e00\u6307\u4ee4 u : \u53d6\u6d88\u524d\u4e00\u6307\u4ee4undo, :u\u4e5f\u884c\uff0c\u4e00\u822c\u4e0d\u7528\uff0c\u64cd\u4f5c\u592a\u591a Ctrl + r : \u6062\u590d\u3010\u53ea\u5bf9u\u6709\u6548\u3011redo Ctrl + l : \u5237\u65b0\u5c4f\u5e55\u663e\u793a Ctrl+v \u7136\u540e ctrl+A\u662f^A Ctrl+I\u662f\\t : \u8f93\u5165\u7279\u6b8a\u5b57\u7b26 Ctrl+v\u7136\u540e\u7528j\u3001k\u3001l\u3001h\u6216\u65b9\u5411\u952e\u4e0a\u4e0b\u9009\u4e2d\u591a\u5217\uff0c\u4e4b\u540e I I a A r x\u7b49\uff0c\u6700\u540e\u6309esc\uff0c\u751f\u6548 : Vim\u5217\u64cd\u4f5c 2.\u6587\u672c\u5904\u7406\u5de5\u5177 \u00b6 2.1.\u663e\u793a\u6587\u672c\u5185\u5bb9 cat \u00b6 \u547d\u4ee4 cat \u4e3b\u8981\u53c2\u6570\u8bf4\u660e\uff1a -E \uff1a\u663e\u793a\u884c\u7ed3\u675f\u7b26 $ -A \uff1a\u663e\u793a\u6240\u6709\u63a7\u5236\u7b26 -n \uff1a\u5bf9\u663e\u793a\u51fa\u7684\u6bcf\u4e00\u884c\u8fdb\u884c\u7f16\u53f7 -b \uff1a\u975e\u7a7a\u884c\u7f16\u53f7 -s \uff1a\u538b\u7f29\u8fde\u7eed\u7684\u7a7a\u884c\u6210\u4e00\u884c \u4e3e\u4f8b\uff1a cat -nA user-list.txt 1 user0$ 2 user1$ 3 user2$ 4 user3$ 5 user4$ 6 user5$ 7 user6$ 8 user7$ 9 user8$ 10 user9$ 2.2.\u663e\u793a\u6587\u672c\u884c\u53f7 nl \u00b6 \u76f8\u5f53\u4e8e\u547d\u4ee4 cat -b \u3002 \u547d\u4ee4 nl \u4e3b\u8981\u53c2\u6570\u8bf4\u660e\uff1a -b \uff1a\u6307\u5b9a\u884c\u53f7\u6307\u5b9a\u7684\u65b9\u5f0f\uff0c\u4e3b\u8981\u6709\u4e24\u79cd\uff1a -b a \uff1a\u8868\u793a\u4e0d\u8bba\u662f\u5426\u4e3a\u7a7a\u884c\uff0c\u4e5f\u540c\u6837\u5217\u51fa\u884c\u53f7\uff08\u7c7b\u4f3c cat -n\uff09\uff1b -b t \uff1a\u5982\u679c\u6709\u7a7a\u884c\uff0c\u7a7a\u7684\u90a3\u4e00\u884c\u4e0d\u8981\u5217\u51fa\u884c\u53f7\uff08\u9ed8\u8ba4\u503c\uff09\uff1b -n \uff1a\u5217\u51fa\u884c\u53f7\u8868\u793a\u7684\u65b9\u6cd5\uff0c\u4e3b\u8981\u6709\u4e09\u79cd\uff1a -n ln \uff1a\u884c\u53f7\u5728\u5c4f\u5e55\u7684\u6700\u5de6\u65b9\u663e\u793a\uff1b\u6ca1\u6709\u524d\u5bfc0\uff1b -n rn \uff1a\u884c\u53f7\u5728\u81ea\u5df1\u680f\u4f4d\u7684\u6700\u53f3\u65b9\u663e\u793a\uff0c\u6ca1\u6709\u524d\u5bfc0\uff1b -n rz \uff1a\u884c\u53f7\u5728\u81ea\u5df1\u680f\u4f4d\u7684\u6700\u53f3\u65b9\u663e\u793a\uff0c\u6709\u524d\u5bfc0\uff1b -w \uff1a\u884c\u53f7\u680f\u4f4d\u7684\u5360\u7528\u7684\u4f4d\u6570\u3002 -p \uff1a\u5728\u903b\u8f91\u5b9a\u754c\u7b26\u5904\u4e0d\u91cd\u65b0\u5f00\u59cb\u8ba1 \u4e3e\u4f8b\uff1a $ nl -b a -n rz user-list.txt 000001 user0 000002 user1 000003 user2 000004 user3 000005 user4 000006 user5 000007 user6 000008 user7 000009 user8 000010 user9 2.3.\u9006\u5411\u663e\u793a\u6587\u672c\u5185\u5bb9 tac \u00b6 \u547d\u4ee4 tac \u9006\u5411\u663e\u793a\u6587\u672c\u5185\u5bb9\u3002 \u4e3e\u4f8b\uff1a $ tac user-list.txt user9 user8 user7 user6 user5 user4 user3 user2 user1 user0 \u4e3e\u4f8b\uff1a $ seq 10 | tac 10 9 8 7 6 5 4 3 2 1 2.4.\u9006\u5411\u663e\u793a\u540c\u884c\u5185\u5bb9 rev \u00b6 \u547d\u4ee4 rev \u9006\u5411\u663e\u793a\u540c\u4e00\u884c\u7684\u5185\u5bb9\u3002 \u4e3e\u4f8b\uff1a $ rev user-list.txt 0resu 1resu 2resu 3resu 4resu 5resu 6resu 7resu 8resu 9resu \u4e3e\u4f8b\uff1a $ echo { 1 ..10 } | rev 01 9 8 7 6 5 4 3 2 1 2.5.\u663e\u793a\u975e\u6587\u672c\u6587\u4ef6\u5185\u5bb9 hexdump \u00b6 \u547d\u4ee4 hexdump \u547d\u4ee4\u4e00\u822c\u7528\u6765\u67e5\u770b\u201c\u4e8c\u8fdb\u5236\u201d\u6587\u4ef6\u7684\u5341\u516d\u8fdb\u5236\u7f16\u7801 \u4e3e\u4f8b\uff1a $ hexdump -C -n 32 cp 00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 | .ELF............ | 00000010 03 00 3e 00 01 00 00 00 e0 48 00 00 00 00 00 00 | ..>......H...... | 00000020 2.6.\u5206\u9875\u67e5\u770b\u6587\u4ef6\u5185\u5bb9 \u00b6 \u547d\u4ee4 more \u548c less \u53ef\u4ee5\u5b9e\u73b0\u5206\u9875\u67e5\u770b\u6587\u4ef6\u5185\u5bb9\u3002 \u547d\u4ee4 less \u914d\u5408\u7ba1\u9053\u7b26\u4f7f\u7528\u3002 tree -d /etc | less 2.7.\u663e\u793a\u6587\u4ef6\u5934\u90e8\u5185\u5bb9 head \u00b6 \u547d\u4ee4 head \u663e\u793a\u6587\u4ef6\u5934\u90e8\u5185\u5bb9\u3002 head -c 20 cp : \u663e\u793a\u6587\u4ef6\u524d20\u5b57\u8282\u5185\u5bb9 head -n 20 zdiff : \u663e\u793a\u6587\u4ef6\u524d20\u884c\u5185\u5bb9 head -20 zdiff : \u663e\u793a\u6587\u4ef6\u524d20\u884c\u5185\u5bb9 $ echo \"\u6211\u662f\u8c01\" | head -c3 \u6211 $ echo \"\u6211\u662f\u8c01\" | head -c6 \u6211\u662f cat /dev/urandom | tr -dc '[:alnum]' | head -c 10 | tee passwd.txt $ cat user-list.txt user0 user1 user2 user3 user4 user5 user6 user7 user8 user9 $ head -n -3 user-list.txt user0 user1 user2 user3 user4 user5 user6 2.8.\u663e\u793a\u6587\u4ef6\u5c3e\u90e8\u5185\u5bb9 tail \u00b6 \u547d\u4ee4 tail \u663e\u793a\u6587\u4ef6\u5934\u90e8\u5185\u5bb9\u3002 tail -c 200 cp : \u663e\u793a\u6587\u4ef6\u5c3e\u90e8200\u4e2a\u5b57\u8282\u7684\u5185\u5bb9 tail -n 3 user-list.txt : \u663e\u793a\u6587\u4ef6\u6700\u540e3\u884c tail -n -3 user-list.txt : \u663e\u793a\u4ece-3\u884c\u5230\u6587\u4ef6\u7ed3\u675f\uff08\u5373\u6700\u540e\u4e09\u884c\uff09 tail -3 user-list.txt : \u663e\u793a\u6587\u4ef6\u6700\u540e3\u884c tail -f /var/log/messages : \u8ddf\u8e2a\u663e\u793a\u6587\u4ef6redo.log\u6587\u4ef6\u5185\u5bb9\uff0c\u5f53\u6587\u4ef6\u5220\u9664\uff0c\u518d\u5efa\u540c\u540d\u6587\u4ef6\uff0c\u65e0\u6cd5\u7ee7\u7eed\u8ffd\u8e2a tail -F /var/log/messages : \u8ddf\u8e2a\u663e\u793a\u6587\u4ef6redo.log\u6587\u4ef6\u5185\u5bb9\uff0c\u5f53\u6587\u4ef6\u5220\u9664\uff0c\u518d\u5efa\u540c\u540d\u6587\u4ef6\uff0c\u7ee7\u7eed\u8ffd\u8e2a 2.9.\u6309\u5217\u62bd\u53d6\u6587\u672c cut \u00b6 \u547d\u4ee4 cut \u53ef\u4ee5\u63d0\u53d6\u6587\u672c\u6587\u4ef6\u6216\u8005stdin\u6570\u636e\u7684\u6307\u5b9a\u5217\u5185\u5bb9\u3002 \u9009\u9879\uff1a -f : \u901a\u8fc7\u6307\u5b9a\u54ea\u4e00\u4e2a\u5b57\u6bb5\u8fdb\u884c\u63d0\u53d6\u3002cut\u547d\u4ee4\u4f7f\u7528\u201cTAB\u201d\u4f5c\u4e3a\u9ed8\u8ba4\u7684\u5b57\u6bb5\u5206\u9694\u7b26 -d : \u201cTAB\u201d\u662f\u9ed8\u8ba4\u7684\u5206\u9694\u7b26\uff0c\u4f7f\u7528\u6b64\u9009\u9879\u53ef\u4ee5\u66f4\u6539\u4e3a\u5176\u4ed6\u7684\u5206\u9694\u7b26 --complement : \u6b64\u9009\u9879\u7528\u4e8e\u6392\u9664\u6240\u6307\u5b9a\u7684\u5b57\u6bb5 --output-delimiter=STRING : \u6307\u5b9a\u8f93\u51fa\u5185\u5bb9\u7684\u5206\u9694\u7b26 -c : \u6309\u5b57\u7b26\u5207\u5272 \u53d6/etc/passwd\u6587\u4ef6\u7b2c1\u5217\u5185\u5bb9\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff08\u53ea\u53d6\u524d\u4e09\u884c\uff09 $ cut -d ':' -f 1 /etc/passwd | head -3 root messagebus systemd-network \u53d6/etc/passwd\u6587\u4ef6\u7b2c1\u548c6\u5217\u5185\u5bb9\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff08\u53ea\u53d6\u524d\u4e09\u884c\uff09 cut -d ':' -f 1 ,6 /etc/passwd | head -3 root:/root messagebus:/run/dbus systemd-network:/ \u53d6/etc/passwd\u6587\u4ef6\u7b2c1\u52303\u5217\u4ee5\u53ca\u7b2c6\u5217\u5185\u5bb9\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff08\u53ea\u53d6\u524d\u4e09\u884c\uff09 $ cut -d ':' -f 1 -3,6 /etc/passwd | head -3 root:x:0:/root messagebus:x:499:/run/dbus systemd-network:x:497:/ \u4e0b\u9762\u4f7f\u7528 --output-delimiter \u9009\u9879\uff0c\u628a\u8f93\u51fa\u7ed3\u679c\u4e2d\u7684\u5206\u9694\u7b26 : \u5168\u90e8\u66ff\u6362\u6210 --- \u3002 $ cat /etc/passwd | sort | head -3 admin3:x:1020:100::/home/admin3:/bin/bash at:x:25:25:Batch jobs daemon:/var/spool/atjobs:/usr/sbin/nologin bin:x:1:1:bin:/bin:/usr/sbin/nologin $ cut -d \":\" -f 1 ,7 /etc/passwd | sort | head -3 admin3:/bin/bash at:/usr/sbin/nologin bin:/usr/sbin/nologin $ cut -d \":\" -f 1 ,7 --output-delimiter = \"---\" /etc/passwd | sort | head -3 admin3---/bin/bash at---/usr/sbin/nologin bin---/usr/sbin/nologin --output-delimiter \u9009\u9879\u4e5f\u53ef\u4ee5\u5229\u7528\u6765\u8fdb\u884c\u8ba1\u7b97\u3002 $ echo { 1 ..10 } | cut -d \" \" -f 1 -10 --output-delimiter = \"+\" | bc 55 \u4ece ifconfig \u547d\u4ee4\u4e2d\u622a\u53d6\u5f53\u524d\u4e3b\u673a\u7684ip\u5730\u5740\u3002\uff08openSUSE\u9700\u8981\u5b89\u88c5\u5305 net-tools-deprecated \uff09 $ ifconfig | head -2 | tail -1 inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig | head -2 | tail -1 | cut -d \" \" -f 10 192 .168.10.210 \u6216\u8005 $ ip addr list | grep eth0 | tail -1 | cut -d \" \" -f 6 192 .168.10.210/24 \u57fa\u4e8e\u4e0a\u9762\u7ed3\u679c\uff0c\u53ef\u4ee5\u5c1d\u8bd5\u901a\u8fc7 --complement \u53c2\u6570\uff0c\u4ee5 / \u4e3a\u5206\u9694\u7b26\uff0c\u6392\u9664\u7b2c\u4e8c\u5217 24 \uff0c\u53ea\u8f93\u51fa\u7b2c\u4e00\u5217IP\u5730\u5740\u3002 ip addr list | grep eth0 | tail -1 | cut -d \" \" -f 6 | cut -d \"/\" --complement -f 2 192 .168.10.210 \u663e\u793a df \u547d\u4ee4\u8f93\u51fa\u4e2d\u7684\u5206\u533a\u4f7f\u7528\u7387\u3002 $ df | tr -s ' ' | cut -d ' ' -f 5 | tr -d % Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0 \u65b9\u6cd52\uff1a\u5148\u628a\u7a7a\u683c\u5168\u90e8\u66ff\u6362\u6210%\uff0c\u518d\u53bb\u91cd\u3002 df | tr -s ' ' % | cut -d % -f 5 Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0 2.10.\u5408\u5e76\u591a\u4e2a\u6587\u4ef6 paste \u00b6 \u547d\u4ee4 paste \u5e38\u7528\u9009\u9879\uff1a -d \uff1a\u6307\u5b9a\u5206\u9694\u7b26\uff0c\u9ed8\u8ba4\u662fTAB -s \uff1a\u6240\u6709\u884c\u5408\u6210\u4e00\u884c\u663e\u793a \u751f\u6210 alpha.log \u548c seq.log \u3002 for i in { a..z } ; do echo $i >> alpha.log ; done seq 10 > seq.log \u7528 paste \u547d\u4ee4\u5408\u5e76\u8fd92\u4e2a\u6587\u4ef6\u3002 $ paste alpha.log seq.log a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k l m n o p q r s t u v w x y z $ paste -d \":\" alpha.log seq.log a:1 b:2 c:3 d:4 e:5 f:6 g:7 h:8 i:9 j:10 k: l: m: n: o: p: q: r: s: t: u: v: w: x: y: z: \u539f\u6587\u4ef6\u90fd\u662f\u5217\u8f93\u51fa\uff0c\u6539\u6210\u884c\u8f93\u51fa\u3002 $ paste -d \"-\" -s alpha.log a-b-c-d-e-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z $ paste -d \"-\" -s seq.log $ paste -d \":\" -s alpha.log seq.log a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z 1 :2:3:4:5:6:7:8:9:10 $ paste -d \":\" -s seq.log alpha.log 1 :2:3:4:5:6:7:8:9:10 a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z 2.11.\u6587\u672c\u7edf\u8ba1\u6570\u636e wc \u00b6 \u5e38\u7528\u9009\u9879\uff1a -l \uff1a\u53ea\u8ba1\u6570\u884c\u6570 -w \uff1a\u53ea\u8ba1\u6570\u5355\u8bcd\u603b\u6570 -c \uff1a\u53ea\u8ba1\u6570\u5b57\u8282\u603b\u6570 -m \uff1a\u53ea\u8ba1\u6570\u5b57\u7b26\u603b\u6570 -L \uff1a\u663e\u793a\u6587\u4ef6\u4e2d\u6700\u957f\u884c\u7684\u957f\u5ea6 $ cat text Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ wc text # \u884c\u6570 \u5355\u8bcd\u6570 \u5b57\u8282\u6570 3 9 57 text $ wc -l text 3 text $ wc -w text 9 text $ wc -c text 57 text $ wc -m text 57 text $ wc -L text 20 text \u5bf9\u6bd4\u4e24\u79cd\u4e0d\u540c\u5408\u5e76\u7684\u65b9\u6cd5\u3002 $ cat text1 text2 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou $ paste text1 text2 Tom, 20 , Shanghai Tom, 20 , Shanghai Jack, 30 , Beijing Jack, 30 , Beijing Smith, 40 , Guangzhou Leo, 40 , Guangzhou 2.12.\u6587\u672c\u6392\u5e8f sort \u00b6 \u547d\u4ee4 sort \u628a\u6574\u7406\u8fc7\u7684\u6587\u672c\u663e\u793a\u5728stdout\u4e0a\uff0c\u4e0d\u6539\u53d8\u539f\u6587\u4ef6\u3002 \u5e38\u7528\u9009\u9879\uff1a -r \uff1a\u6267\u884c\u53cd\u65b9\u5411\uff08\u4ece\u4e0a\u81f3\u4e0b\uff09\u6392\u5e8f -R \uff1a\u968f\u673a\u6392\u5e8f -n \uff1a\u6309\u6570\u5b57\u5927\u5c0f\u6392\u5e8f -h \uff1a\u4eba\u7c7b\u53ef\u8bfb\u6392\u5e8f\uff0c\u5982\uff1a2K\uff0c1G -f \uff1a\u6392\u5e8f\u65f6\u5c06\u5c0f\u5199\u5b57\u6bcd\u89c6\u4e3a\u5927\u5199\u5b57\u6bcd -u \uff1a\u6392\u5e8f\u65f6\u5408\u5e76\u91cd\u590d\u9879 -t c \uff1a\u4f7f\u7528c\u4f5c\u4e3a\u5b57\u6bb5\u5206\u9694\u7b26 -k # \uff1a\u6309\u7167\u4ee5c\u4e3a\u5206\u9694\u7b26\u7684\u7b2c#\u5217\u6765\u6392\u5e8f \u4e3e\u4f8b\uff1a\u4ee5 , \u4e3a\u5206\u9694\u7b26\uff0c\u8bfb\u53d6 text \u6587\u4ef6\u5185\u5bb9\u4e2d\u7b2c1\uff0c3\u5217\uff0c\u5bf9\u8f93\u51fa\u7ed3\u679c\u4ee5 , \u4e3a\u5206\u9694\u7b26\uff0c\u6309\u7b2c\u4e8c\u5217\u6392\u5e8f\uff08\u6b63\u5e8f\u548c\u53cd\u5e8f\uff09\u3002 $ cat text Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ cut -d \",\" -f 1 ,3 text | sort -t \",\" -k 1 Jack, Beijing Smith, Guangzhou Tom, Shanghai $ cut -d \",\" -f 1 ,3 text | sort -t \",\" -k 1 -r Tom, Shanghai Smith, Guangzhou Jack, Beijing \u628a\u6587\u4ef6text1\u548c\u6587\u4ef6text2\u5408\u5e76\u540e\u53bb\u91cd\u8f93\u51fa\u3002 $ cat text2 Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou $ cat text1 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ cat text1 text2 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou \u5e76\u96c6\uff0c\u91cd\u590d\u884c\u53ea\u4fdd\u7559\u4e00\u884c\u3002\u524d\u97622\u4e2a\u547d\u4ee4\u662f\u540c\u6837\u542b\u4e49\uff08\u76f8\u540c\u7684\u6392\u5e8f\u5217\uff09\uff0c\u7b2c\u4e09\u4e2a\u547d\u4ee4\u4e2d\u5bf9\u4e0d\u540c\u5217\u8fdb\u884c\u4e86\u6392\u5e8f\uff0c\u5bfc\u81f4\u53bb\u91cd\u7ed3\u679c\u4e0d\u540c\u3002 $ cat text1 text2 | sort -u Jack, 30 , Beijing Leo, 40 , Guangzhou Smith, 40 , Guangzhou Tom, 20 , Shanghai $ cat text1 text2 | sort -t \",\" -k 1 -u Jack, 30 , Beijing Leo, 40 , Guangzhou Smith, 40 , Guangzhou Tom, 20 , Shanghai $ cat text1 text2 | sort -t \",\" -k 2 -u Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou 2.13.\u53bb\u91cd uniq \u00b6 \u547d\u4ee4 uniq \u4ece\u8f93\u5165\u4e2d\u5220\u9664\u524d\u540e\u76f8\u90bb\u91cd\u590d\u7684\u884c\u3002\u7ecf\u5e38\u4e0e sort \u547d\u4ee4\u7ed3\u5408\u4f7f\u7528\u3002 \u4e3b\u8981\u53c2\u6570\uff1a -c \uff1a\u663e\u793a\u6bcf\u884c\u91cd\u590d\u51fa\u73b0\u7684\u6b21\u6570 -d \uff1a\u4ec5\u663e\u793a\u91cd\u590d\u7684\u884c -u \uff1a\u4ec5\u663e\u793a\u4e0d\u91cd\u590d\u7684\u884c \u4e3e\u4f8b\uff0c\u6ce8\u610f\u53ea\u6709\u5bf9\u76f8\u90bb\u884c\u8fdb\u884c\u53bb\u91cd\u3002 $ cat text3 test 30 Hello 95 Hello 95 Linux 85 Linux 85 Hello 95 test 30 $ uniq text3 test 30 Hello 95 Linux 85 Hello 95 test 30 \u628a\u6587\u4ef6text1\u548c\u6587\u4ef6text2\u5408\u5e76\u540e\uff0c\u8fdb\u884c\u4ea4\u96c6\u548c\u5e76\u96c6\uff0c\u5e76\u53bb\u91cd\u3002 $ cat text1 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ cat text2 Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou # \u5e76\u96c6\uff0c\u6309\u9996\u5217\u6392\u5e8f\u53bb\u91cd $ cat text1 text2 | sort | uniq Jack, 30 , Beijing Leo, 40 , Guangzhou Smith, 40 , Guangzhou Tom, 20 , Shanghai # \u4ea4\u96c6 $ cat text1 text2 | sort | uniq -d Jack, 30 , Beijing Tom, 20 , Shanghai # \u5dee\u96c6 $ cat text1 text2 | sort | uniq -u Leo, 40 , Guangzhou Smith, 40 , Guangzhou \u67e5\u770b\u5e76\u53d1\u8fde\u63a5\u6570\u6700\u591a\u7684\u8fdc\u7a0b\u4e3b\u673aIP\u3002 $ ss -nt State Recv-Q Send-Q Local Address:Port Peer Address:Port Process ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:41650 ESTAB 0 0 192 .168.10.210:22 192 .168.10.201:65330 ESTAB 0 64 192 .168.10.210:22 192 .168.10.201:63289 ESTAB 0 0 192 .168.10.210:41650 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:47992 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:60268 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.201:65327 ESTAB 0 0 192 .168.10.210:35758 192 .168.10.220:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:56818 ESTAB 0 0 192 .168.10.210:56818 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:48006 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:60268 ESTAB 0 0 192 .168.10.210:22 192 .168.10.220:33896 ESTAB 0 0 192 .168.10.210:22 192 .168.10.201:65324 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:47992 ESTAB 0 0 192 .168.10.210:59554 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:59554 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:48006 $ ss -nt | tr -s \" \" \":\" | cut -d \":\" -f 6 ,7 | sort | uniq -c | sort -nr | head -n 1 6 192 .168.10.210:22 2.14.\u6587\u672c\u6bd4\u8f83 \u00b6 2.14.1. diff \u00b6 \u547d\u4ee4 diff \u6bd4\u8f83\u4e24\u4e2a\u6587\u4ef6\u4e4b\u95f4\u7684\u533a\u522b\u3002 \u5e38\u7528\u9009\u9879\uff1a -u \uff1a\u4ee5\u7edf\u4e00\u7684\u65b9\u5f0f\u6765\u663e\u793a\u6587\u4ef6\u5185\u5bb9\u7684\u4e0d\u540c -y \uff1a\u4ee5\u5e76\u5217\u7684\u65b9\u5f0f\u663e\u793a\u6587\u4ef6\u7684\u5f02\u540c\u4e4b\u5904 -W \uff1a\u5728\u4f7f\u7528-y\u53c2\u6570\u65f6\uff0c\u6307\u5b9a\u680f\u5bbd -c \uff1a\u663e\u793a\u5168\u90e8\u5185\u6587\uff0c\u5e76\u6807\u51fa\u4e0d\u540c\u4e4b\u5904 -N \uff1a\u7f3a\u5931\u6587\u4ef6\u4ee5\u7a7a\u6587\u4ef6\u5904\u7406 \u4e3e\u4f8b\uff1a $ cat text5 # \u6587\u4ef6\u5c3e\u90e8\u6ca1\u6709\u7a7a\u884c 1001 1002 1003 $ cat text6 # \u6587\u4ef6\u5c3e\u90e8\u6ca1\u6709\u7a7a\u884c 1001 1002 1003a 1004 \u663e\u793a\u4e0d\u540c\u3002 3c3,4 \u4ee3\u8868\u4e24\u4e2a\u6587\u4ef6\u5728\u7b2c3\uff0c4\u884c\u6709\u4e0d\u540c\u3002 $ diff text5 text6 3c3,4 < 1003 --- > 1003a > 1004 \u4ee5\u7edf\u4e00\u683c\u5f0f\u8f93\u51fa\u6bd4\u8f83\u7ed3\u679c\u3002 \u524d2\u884c\u662f\u6587\u4ef6\u4fe1\u606f\u3002\u5176\u4e2d --- \u8868\u793a\u53d8\u52a8\u524d\u7684\u6587\u4ef6\uff0c +++ \u8868\u793a\u53d8\u52a8\u540e\u7684\u6587\u4ef6\u3002 \u53d8\u52a8\u7684\u4f4d\u7f6e\u7528\u4e24\u4e2a@\u4f5c\u4e3a\u8d77\u9996\u548c\u7ed3\u675f\uff0c @@ -1,3 +1,4 @@ \u3002 -1,3 \u4e2d\uff0c - \u8868\u793a\u7b2c\u4e00\u4e2a\u6587\u4ef6\uff0c\u5373 text5 \u3002\u7b2c\u4e00\u4e2a\u6587\u4ef6\u4ece\u7b2c1\u884c\u5f00\u59cb\u8fde\u7eed3\u884c\u3002 +1,4 \u4e2d\uff0c + \u8868\u793a\u7b2c\u4e8c\u4e2a\u6587\u4ef6\uff0c\u5373 text6 \u3002\u5373\uff0c\u7b2c\u4e8c\u4e2a\u6587\u4ef6\u4ece\u7b2c1\u884c\u5f00\u59cb\u8fde\u7eed4\u884c\u3002 $ diff -u text5 text6 --- text5 2022 -12-07 08 :07:05.927805722 +0800 +++ text6 2022 -12-07 08 :07:24.692234585 +0800 @@ -1,3 +1,4 @@ 1001 1002 -1003 +1003a +1004 \u4ee5\u4e0a\u4e0b\u6587\u65b9\u5f0f\u8f93\u51fa\u6bd4\u8f83\u7ed3\u679c\u3002\u6807\u6709 ! \u4ee3\u8868\u5dee\u5f02\u884c\u3002 $ diff -c text5 text6 *** text5 2022 -12-07 08 :24:08.867168414 +0800 --- text6 2022 -12-07 08 :24:13.939284243 +0800 *************** *** 1 ,3 **** 1001 1002 ! 1003 --- 1 ,4 ---- 1001 1002 ! 1003a ! 1004 \u5e76\u6392\u683c\u5f0f\u8f93\u51fa\u6bd4\u8f83\u7ed3\u679c\u3002 | \u8868\u793a\u524d\u540e2\u4e2a\u6587\u4ef6\u5185\u5bb9\u6709\u4e0d\u540c < \u8868\u793a\u540e\u9762\u6587\u4ef6\u6bd4\u524d\u9762\u6587\u4ef6\u5c11\u4e861\u884c\u5185\u5bb9 > \u8868\u793a\u540e\u9762\u6587\u4ef6\u6bd4\u524d\u9762\u6587\u4ef6\u591a\u4e861\u884c\u5185\u5bb9 $ diff -y -W 50 text5 text6 1001 1001 1002 1002 1003 | 1003a > 1004 \u6bd4\u8f83\u6587\u4ef6\u5939\u5185\u5bb9\u3002\u6ce8\u610f\uff0c\u53ea\u6bd4\u8f83\u5185\u5bb9\uff0c\u4e0d\u6bd4\u8f83\u65f6\u95f4\u6233\u3002 $ mkdir dir1 $ mkdir dir2 $ cd dir1 $ touch file1 $ touch file2 $ cp file1 file2 ../dir2/ $ echo \"hello\" > file3 $ cd ../dir2 $ touch file3 $ touch file4 $ diff dir1 dir2 1d0 < hello Only in dir2: file4 2.14.2. patch \u00b6 \u547d\u4ee4 patch \u590d\u5236\u5176\u4ed6\u6587\u4ef6\u4e2d\u7684\u5185\u5bb9\u3002\u547d\u4ee4\u683c\u5f0f\uff1a patch -p [ num ] < patchfile patch [ options ] originalfile patchfile \u5f53\u7279\u5b9a\u8f6f\u4ef6\u6709\u53ef\u7528\u7684\u5b89\u5168\u4fee\u590d\u7a0b\u5e8f\u65f6\uff0c\u6211\u4eec\u901a\u5e38\u4f1a\u4f7f\u7528 yum \u6216 apt-get \u6216 zypper \u7b49\u5305\u7ba1\u7406\u5de5\u5177\u8fdb\u884c\u4e8c\u8fdb\u5236\u5347\u7ea7\u3002 \u4f46\u5982\u679c\u6211\u4eec\u662f\u901a\u8fc7\u4ece\u6e90\u4ee3\u7801\u7f16\u8bd1\u5b89\u88c5\u8f6f\u4ef6\u7684\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u9700\u8981\u4e0b\u8f7d\u5b89\u5168\u8865\u4e01\u5e76\u5c06\u5176\u5e94\u7528\u4e8e\u539f\u59cb\u6e90\u4ee3\u7801\u5e76\u91cd\u65b0\u7f16\u8bd1\u8f6f\u4ef6\u3002 \u8fd9\u5c31\u662f\u6211\u4eec\u4f7f\u7528 diff \u521b\u5efa\u8865\u4e01\u6587\u4ef6\uff08patch file\uff09\uff0c\u5e76\u4f7f\u7528 patch \u547d\u4ee4\u5e94\u7528\u5b83\u3002 \u8865\u4e01\u6587\u4ef6\u662f\u4e00\u4e2a\u6587\u672c\u6587\u4ef6\uff0c\u5176\u4e2d\u5305\u542b\u540c\u4e00\u6587\u4ef6\uff08\u6216\u540c\u4e00\u6e90\u4ee3\u7801\u6811\uff09\u7684\u4e24\u4e2a\u7248\u672c\u4e4b\u95f4\u7684\u5dee\u5f02\u3002 \u8865\u4e01\u6587\u4ef6\u662f\u4f7f\u7528 diff \u547d\u4ee4\u521b\u5efa\u7684\u3002 \u7ee7\u7eed\u4e0a\u4f8b\u3002 \u5c06\u6587\u4ef6 text5 \u7684\u5185\u5bb9\u540c\u6b65\u5230\u6587\u4ef6 text6 \uff0c\u7136\u540e\u64a4\u9500\u8865\u4e01\u3002\u6ce8\u610f\u533a\u5206\u6e90\u6587\u4ef6\u548c\u76ee\u6807\u6587\u4ef6\u3002 $ cat text5 1001 1002 1003 $ cat text6 1001 1002 1003a 1004 # \u751f\u6210\u8865\u4e01\u6587\u4ef6 $ diff -ruN text5 text6 > patchfile $ cat patchfile --- text5 2022 -12-07 08 :24:08.867168414 +0800 +++ text6 2022 -12-07 08 :24:13.939284243 +0800 @@ -1,3 +1,4 @@ 1001 1002 -1003 +1003a +1004 # \u4e0d\u6307\u660e\u76ee\u6807\u6587\u4ef6\uff0c\u5219\u9ed8\u8ba4\u7ed9diff\u547d\u4ee4\u4e2d\u7684\u6e90\u6587\u4ef6\u8fdb\u884c\u6253\u8865\u4e01 $ patch < patchfile patching file text5 $ cat text5 1001 1002 1003a 1004 $ cat text6 1001 1002 1003a 1004 # \u64a4\u9500\u8865\u4e01 patch -R < patchfile patching file text5 # cat text5 1001 1002 1003 # \u7ed9text6\u6587\u4ef6\u6253\u8865\u4e01\uff08\u7528text5\u7684\u6587\u4ef6\u5185\u5bb9\u8986\u76d6text6\u7684\u5185\u5bb9\uff09 $ patch text6 patchfile patching file text6 Reversed ( or previously applied ) patch detected! Assume -R? [ n ] y $ cat text6 1001 1002 1003 # \u64a4\u9500\u7ed9text6\u6587\u4ef6\u6253\u7684\u8865\u4e01\uff08\u6062\u590dtext6\u6587\u4ef6\u8865\u4e01\u524d\u7684\u5185\u5bb9\uff09 $ patch -R text6 patchfile patching file text6 Unreversed patch detected! Ignore -R? [ n ] y $ cat text6 1001 1002 1003a 1004 \u4f7f\u7528 -b \u53c2\u6570\uff0c\u5728patch\u524d\u5148\u5907\u4efd\u6e90\u6587\u4ef6\u3002 $ patch -b < patchfile patching file text5 $ cat text5 1001 1002 1003a 1004 $ cat text5.orig 1001 1002 1003 $ cat text6.orig 1001 1002 1003 $ patch -R < patchfile patching file text5 \u5728-b\u53c2\u6570\u4e2d\u52a0\u5165-V\u53c2\u6570\uff0c\u6307\u5b9a\u5907\u4efd\u6587\u4ef6\u540d\u7684\u683c\u5f0f\uff0c\u5982\u4e0b\uff0c\u4f1a\u5f97\u5230\u6587\u4ef6 text5.~1~ \u3002 $patch -b -V numbered < patchfile patching file text5 $ cat text5 1001 1002 1003a 1004 $ cat text5.~1~ 1001 1002 1003 \u8bd5\u8fd0\u884c\uff0c\u4e0d\u505a\u5b9e\u9645\u66f4\u6539\u3002 patch --dry-run < patchfile \u5bf9\u76ee\u5f55\u6253\u8865\u4e01\u3002 \u6267\u884c diff \u548c patch \u547d\u4ee4\u662f\u5728\u5f53\u524d\u7528\u6237 vagrant \u7684\u4e3b\u76ee\u5f55\u4e0b\uff0c\u7edd\u5bf9\u8def\u5f84\u662f /home/vagrant \u3002 diff \u547d\u4ee4\u4e2d\uff0c\u6e90\u76ee\u5f55\u662f /home/vagrant/dir1 \u3002\u76ee\u6807\u76ee\u5f55\u662f /home/vagrant/dir2 \u3002 -p3 \u662f\u544a\u8bc9 patch \u547d\u4ee4\u5ffd\u7565\u4e0a\u9762\u7edd\u5bf9\u8def\u5f84\u4e2d\u524d\u4e09\u4e2a\u659c\u6760 / \u3002 patch \u547d\u4ee4\u4e2d\u7528 diff \u7684\u76ee\u6807\u76ee\u5f55\u53bb\u8986\u76d6\u6e90\u76ee\u5f55\u3002\u4e92\u6362\u4f1a\u62a5\u9519\u3002 -R \uff1a\u64a4\u9500\u8865\u4e01\u3002 # file3\u548cfile4\u6709\u5185\u5bb9 $ tree ./dir1 ./dir1 \u251c\u2500\u2500 file1 \u251c\u2500\u2500 file2 \u251c\u2500\u2500 file3 \u2514\u2500\u2500 subdir1 \u2514\u2500\u2500 file4 \u90fd\u662f\u7a7a\u6587\u4ef6 $ tree ./dir2 ./dir2 \u251c\u2500\u2500 file1 \u251c\u2500\u2500 file2 \u251c\u2500\u2500 file3 \u2514\u2500\u2500 subdir1 \u2514\u2500\u2500 file4 $ diff -ruN /home/vagrant/dir1 /home/vagrant/dir2 > patchdir $ cat patchdir diff -ruN /home/vagrant/dir1/file3 /home/vagrant/dir2/file3 --- /home/vagrant/dir1/file3 2022 -12-07 08 :42:33.108418336 +0800 +++ /home/vagrant/dir2/file3 2022 -12-07 21 :25:48.156056360 +0800 @@ -1 +0,0 @@ -hello diff -ruN /home/vagrant/dir1/subdir1/file4 /home/vagrant/dir2/subdir1/file4 --- /home/vagrant/dir1/subdir1/file4 2022 -12-07 21 :15:09.689912160 +0800 +++ /home/vagrant/dir2/subdir1/file4 2022 -12-07 21 :26:55.405546177 +0800 @@ -1 +0,0 @@ -/home/vagrant/dir1/subdir1 # \u7528dir2\u7684\u5185\u5bb9\u8986\u76d6dir1\u7684\u5185\u5bb9 $ patch -p3 < patchdir patching file dir1/file3 patching file dir1/subdir1/file4 # \u73b0\u5728dir1\u76ee\u5f55\u4e0b\u7684\u5185\u5bb9\u5df2\u7ecf\u88abdir2\u76ee\u5f55\u8986\u76d6\u4e86\u3002file3\u548cfile4\u90fd\u662f\u7a7a\u6587\u4ef6 $ ll ./dir1 total 0 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :34 file1 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :35 file2 -rw-r--r--. 1 vagrant wheel 0 Dec 7 21 :40 file3 drwxr-xr-x. 1 vagrant wheel 10 Dec 7 21 :40 subdir1 $ ll ./dir1/subdir1 total 0 -rw-r--r--. 1 vagrant wheel 0 Dec 7 21 :40 file4 # \u64a4\u9500\u8865\u4e01\uff0cfile3\u548cfile4\u5df2\u7ecf\u6062\u590d\u4e3a\u539f\u6587\u4ef6 $ patch -R -p3 < patchdir patching file dir1/file3 patching file dir1/subdir1/file4 $ ll ./dir1 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :34 file1 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :35 file2 -rw-r--r--. 1 vagrant wheel 6 Dec 7 21 :45 file3 drwxr-xr-x. 1 vagrant wheel 10 Dec 7 21 :45 subdir1 $ ll ./dir1/subdir1 -rw-r--r--. 1 vagrant wheel 27 Dec 7 21 :45 file4 # \u7528dir1\u7684\u5185\u5bb9\u8986\u76d6dir2\u7684\u5185\u5bb9\uff0c\u7cfb\u7edf\u62d2\u7edd\u3002 patch dir2 -p3 < patchdir File dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file dir2.rej File dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file dir2.rej $ patch /home/vagrant/dir2 -p3 < patchdir File /home/vagrant/dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file /home/vagrant/dir2.rej File /home/vagrant/dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file /home/vagrant/dir2.rej 2.14.3. vimdiff \u00b6 \u547d\u4ee4 vimdiff \u76f8\u5f53\u4e8e vim -d \u3002 \u4e3e\u4f8b\uff1a vimdiff text1 text2 2.14.4. cmp \u00b6 \u547d\u4ee4 cmp \u67e5\u770b\u4e8c\u8fdb\u5236\u6587\u4ef6\u7684\u4e0d\u540c\u3002 $ cmp cp grep cp grep differ: byte 25 , line 1 $ cmp /usr/bin/ls /usr/bin/dir /usr/bin/ls /usr/bin/dir differ: byte 613 , line 1 # \u8df3\u8fc7\u524d735\u4e2a\u5b57\u8282\uff0c\u8f93\u51fa\u540e\u976230\u4e2a\u5b57\u8282\u5185\u5bb9 $ hexdump -s 735 -Cn 30 /usr/bin/ls 000002df 00 00 00 00 00 5d 00 00 00 50 00 00 00 68 00 00 | ..... ] ...P...h.. | 000002ef 00 6a 00 00 00 4f 00 00 00 00 00 00 00 1d | .j...O........ | 000002fd $ hexdump -s 735 -Cn 30 /usr/bin/dir 000002df 00 00 00 00 00 5d 00 00 00 50 00 00 00 68 00 00 | ..... ] ...P...h.. | 000002ef 00 6a 00 00 00 4f 00 00 00 00 00 00 00 1d | .j...O........ | 000002fd","title":"\u7b2c\u56db\u7ae0 \u6587\u672c\u7f16\u8f91"},{"location":"linux/SRE/04-TextTools/#_1","text":"","title":"\u7b2c\u56db\u7ae0 \u6587\u672c\u7f16\u8f91"},{"location":"linux/SRE/04-TextTools/#1","text":"","title":"1.\u6587\u672c\u7f16\u8f91\u5668"},{"location":"linux/SRE/04-TextTools/#11vim","text":"vim\u547d\u4ee4\u683c\u5f0f\uff1a +# file : \u6253\u5f00\u6587\u4ef6\u540e\uff0c\u8ba9\u5149\u6807\u5904\u4e8e\u7b2c#\u884c\u9996\uff0c+\u9ed8\u8ba4\u884c\u5c3e +/PATTERN file : \u6253\u5f00\u6587\u4ef6\u6709\uff0c\u8ba9\u5149\u6807\u5904\u4e8e\u7b2c\u4e00\u4e2a\u88abPATTERN\u5339\u914d\u5230\u7684\u884c\u9996 -b file : \u4e8c\u8fdb\u5236\u65b9\u5f0f\u6253\u5f00\u6587\u4ef6 -d file1 file2 ... : \u6bd4\u8f83\u591a\u4e2a\u6587\u4ef6\uff0c\u76f8\u5f53\u4e8e vimdiff -m file : \u53ea\u8bfb\u65b9\u5f0f\u6253\u5f00\u6587\u4ef6 -e file : \u8fdb\u5165ex\u6a21\u5f0f\uff0c\u76f8\u5f53\u4e8e ex file -y file : vim\u4e09\u79cd\u5e38\u89c1\u6a21\u5f0f\uff1a \u666e\u901a\u6a21\u5f0fNormal\u6216\u547d\u4ee4\u6a21\u5f0f \u63d2\u5165Insert\u6216\u7f16\u8f91\u6a21\u5f0f \u6269\u5c55\u547d\u4ee4\u6a21\u5f0fExtended Command \u4e09\u79cd\u6a21\u5f0f\u5207\u6362 \u547d\u4ee4\u6a21\u5f0f\u2192\u63d2\u5165\u6a21\u5f0f i\uff1ainsert\uff0c\u5728\u5149\u6807\u5904\u8f93\u5165 I\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u9996\u8f93\u5165 a\uff1aappend\uff0c\u5728\u5149\u6807\u5904\u540e\u9762\u8f93\u5165 A\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u5c3e\u8f93\u5165 o\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u7684\u4e0b\u65b9\u6253\u5f00\u4e00\u4e2a\u65b0\u884c O\uff1a\u5728\u5149\u6807\u6240\u5728\u884c\u7684\u4e0a\u65b9\u6253\u5f00\u4e00\u4e2a\u65b0\u884c \u63d2\u5165\u6a21\u5f0f\u2192 ESC \u2192 \u547d\u4ee4\u6a21\u5f0f \u547d\u4ee4\u6a21\u5f0f\u2192 : \u2192 \u6269\u5c55\u547d\u4ee4\u6a21\u5f0f \u6269\u5c55\u547d\u4ee4\u6a21\u5f0f\u2192 ESC, enter \u2192 \u547d\u4ee4\u6a21\u5f0f \u6269\u5c55\u547d\u4ee4\u6a21\u5f0f\u5e38\u7528\u547d\u4ee4\uff1a :wq : \u4fdd\u5b58\u6587\u4ef6\u5e76\u9000\u51fa :w : \u4fdd\u5b58\u6587\u4ef6 :w filename : \u5199\u5165\u6307\u5b9a\u6587\u4ef6\uff0c\u76f8\u5f53\u4e8e\u53e6\u5b58\u4e3a :q! : \u653e\u5f03\u4efb\u4f55\u4fee\u6539\u5e76\u9000\u51fa ZQ : \u65e0\u6761\u4ef6\u9000\u51fa :join : \u5408\u5e76\u591a\u884c J : \u5408\u5e76\u4e24\u884c \u8bbe\u7f6e\uff1a\uff08\u53ef\u4ee5\u5728 /etc/vimrc \u6587\u4ef6\u4e2d\u914d\u7f6e\uff09 :set textwidth : \u8bbe\u7f6e\u6587\u672c\u5bbd\u5ea6\uff08\u4ece\u5de6\u5411\u53f3\u8ba1\u6570\uff09 :set wrapmargin=# : \u8bbe\u7f6e\u884c\u8fb9\u8ddd\uff08\u4ece\u53f3\u5411\u5de6\u8ba1\u6570\uff09 :set endofline : \u8bbe\u7f6e\u6587\u4ef6\u7ed3\u675f\u7b26 :set noendofline : \u53d6\u6d88\u6587\u4ef6\u7ed3\u675f\u7b26 :set wrap : \u81ea\u52a8\u6362\u884c :set nowrap : \u53d6\u6d88\u81ea\u52a8\u6362\u884c :set number : \u663e\u793a\u884c\u53f7 :set nonumber : \u53d6\u6d88\u663e\u793a\u884c\u53f7 :set list : \u8fdb\u5165List Mode\uff0c\u663e\u793aTab ^I\uff0c\u6362\u884c\u7b26\uff0c\u548c$\u663e\u793a :set nolist : \u9000\u51faList Mode :set ignorecase : \u5ffd\u7565\u5b57\u7b26\u7684\u5927\u5c0f\u5199 :set noic : \u4e0d\u5ffd\u7565\u5b57\u7b26\u5927\u5c0f\u5199 :set autoindent : \u542f\u7528\u81ea\u52a8\u7f29\u8fdb :set noai : \u5173\u95ed\u81ea\u52a8\u7f29\u8fdb :set hlsearch : \u542f\u7528\u9ad8\u4eae\u641c\u7d22 :set nohlsearch : \u5173\u95ed\u9ad8\u4eae\u641c\u7d22 :set fileformat=dos : \u542f\u7528windows\u683c\u5f0f :set fileformat=unix : \u542f\u7528unix\u683c\u5f0f :set expandtab : \u542f\u7528\u7a7a\u683c\u4ee3\u66ffTAB\uff0c\u9ed8\u8ba48\u4e2a\u7a7a\u683c\u4ee3\u66ff\u4e00\u4e2aTAB :set noexpandtab : \u5173\u95ed\u7a7a\u683c\u4ee3\u66ffTAB :set tabstop=# : \u6307\u5b9a#\u4e2a\u7a7a\u683c\u4ee3\u66ff\u4e00\u4e2aTAB :set shiftwidth=# : \u8bbe\u7f6e#\u4e2a\u7f29\u8fdb\u5bbd\u5ea6 :set cursorline : \u8bbe\u7f6e\u5149\u6807\u6240\u5728\u884c\u7684\u8868\u793a\u7ebf :set cursorline : \u5173\u95ed\u5149\u6807\u6240\u5728\u884c\u7684\u8868\u793a\u7ebf :set key=PASSWORD : \u542f\u7528\u5bc6\u7801\u4fdd\u62a4 :set key= : \u5173\u95ed\u5bc6\u7801\u4fdd\u62a4 :help option-list : \u83b7\u53d6\u5e2e\u52a9 \u67e5\u627e /pattern : \u4ece\u5149\u6807\u5f00\u59cb\u5904\u5411\u6587\u4ef6\u5c3e\u641c\u7d22pattern ?pattern : \u4ece\u5149\u6807\u5f00\u59cb\u5904\u5411\u6587\u4ef6\u9996\u641c\u7d22pattern n : \u5728\u540c\u4e00\u65b9\u5411\u91cd\u590d\u4e0a\u4e00\u6b21\u641c\u7d22\u547d\u4ee4 N : \u5728\u53cd\u65b9\u5411\u4e0a\u91cd\u590d\u4e0a\u4e00\u6b21\u641c\u7d22\u547d\u4ee4 # : \u5411\u4e0a\u5b8c\u6574\u5339\u914d\u5149\u6807\u4e0b\u7684\u5355\u8bcd, \u76f8\u5f53\u4e8e\uff1fword * : \u5411\u4e0b\u5b8c\u6574\u5339\u914d\u5149\u6807\u4e0b\u7684\u5355\u8bcd, \u76f8\u5f53\u4e8e/word % : \u67e5\u627e\u5bf9\u5e94\u7684( [ {\u5339\u914d nfx : \u5728\u5f53\u524d\u884c\u67e5\u627e\u5149\u6807\u540e\u7b2cn\u4e2ax\uff08\u4e00\u822c\u76f4\u63a5fx\uff09 \u66ff\u6362 :%s/\\n//g : \u5220\u9664\u6362\u884c\u7b26 :s/p1/p2/g : \u5c06\u5f53\u524d\u884c\u4e2d\u6240\u6709p1\u5747\u7528p2\u66ff\u4ee3, \u65e0g\uff0c\u5219\u53ea\u66ff\u6362\u7b2c\u4e00\u4e2a :s/p1/p2/c : \u67e5\u627e\u66ff\u6362\u8981\u6c42\u786e\u8ba4 :n1,n2s/p1/p2/g : \u5c06\u7b2cn1\u81f3n2\u884c\u4e2d\u6240\u6709p1\u5747\u7528p2\u66ff\u4ee3 :%s/p1/p2/g : \u5168\u5c40\uff0c\u4f7f\u7528p2\u66ff\u6362p1 :%s/p1/p2/gc : \u66ff\u6362\u524d\u8be2\u95ee :n,$s/vivian/sky/ : \u66ff\u6362\u7b2cn\u884c\u5f00\u59cb\u5230\u6700\u540e\u4e00\u884c\u4e2d\u6bcf\u4e00\u884c\u7684\u7b2c\u4e00\u4e2avivian\u4e3asky\uff0cn\u4e3a\u6570\u5b57 :.,$s/vivian/sky/g : \u66ff\u6362\u5f53\u524d\u884c\u5f00\u59cb\u5230\u6700\u540e\u4e00\u884c\u4e2d\u6bcf\u4e00\u884c\u6240\u6709vivian\u4e3asky :s/vivian\\//sky\\// : \u66ff\u6362\u5f53\u524d\u884c\u7b2c\u4e00\u4e2avivian/\u4e3asky/\uff0c\u53ef\u4ee5\u4f7f\u7528\\\u4f5c\u4e3a\u8f6c\u4e49\u7b26 :1,$s/^/some string/ : \u5728\u6587\u4ef6\u7684\u7b2c\u4e00\u884c\u81f3\u6700\u540e\u4e00\u884c\u7684\u884c\u9996\u524d\u63d2\u5165some string :%s/$/some string/g : \u5728\u6574\u4e2a\u6587\u4ef6\u6bcf\u4e00\u884c\u7684\u884c\u5c3e\u6dfb\u52a0some string :%s/\\s\\+$// : \u53bb\u6389\u6240\u6709\u7684\u884c\u5c3e\u7a7a\u683c\uff0c\u201c\\s\u201d\u8868\u793a\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u548c\u5236\u8868\u7b26\uff09\uff0c\u201c+\u201d\u5bf9\u524d\u9762\u7684\u5b57\u7b26\u5339\u914d\u4e00\u6b21\u6216\u591a\u6b21\uff08\u8d8a\u591a\u8d8a\u597d\uff09\uff0c\u201c \\(\u201d\u5339\u914d\u884c\u5c3e\uff08\u4f7f\u7528\u201c\\$\u201d\u8868\u793a\u5355\u7eaf\u7684\u201c\\) \u201d\u5b57\u7b26\uff09 :%s/\\s\u2217\\n\\+/\\r/ : \u53bb\u6389\u6240\u6709\u7684\u7a7a\u767d\u884c\uff0c\u201c \\(\u201d\u548c\u201c\\) \u201d\u5bf9\u8868\u8fbe\u5f0f\u8fdb\u884c\u5206\u7ec4\uff0c\u4f7f\u5176\u88ab\u89c6\u4f5c\u4e00\u4e2a\u4e0d\u53ef\u5206\u5272\u7684\u6574\u4f53 :%s!\\s*//.*!! : \u53bb\u6389\u6240\u6709\u7684\u201c//\u201d\u6ce8\u91ca :%s!\\s*/\\*\\_.\\{-}\\*/\\s*!!g : \u53bb\u6389\u6240\u6709\u7684\u201c/**/\u201d\u6ce8\u91ca :%s= *$== : \u5c06\u6240\u6709\u884c\u5c3e\u591a\u4f59\u7684\u7a7a\u683c\u5220\u9664 :g/^\\s*$/d : \u5c06\u6240\u6709\u4e0d\u5305\u542b\u5b57\u7b26(\u7a7a\u683c\u4e5f\u4e0d\u5305\u542b)\u7684\u7a7a\u884c\u5220\u9664 r : \u66ff\u6362\u5f53\u524d\u5b57\u7b26 R : \u66ff\u6362\u5f53\u524d\u5b57\u7b26\u53ca\u5176\u540e\u7684\u5b57\u7b26\uff0c\u76f4\u81f3\u6309ESC\u952e \u7f16\u8f91 h : \u5149\u6807\u5de6\u79fb\u4e00\u4e2a\u5b57\u7b26[\u56de\u9000\u952eBackspace] l : \u5149\u6807\u53f3\u79fb\u4e00\u4e2a\u5b57\u7b26[\u7a7a\u683c\u952eSpace] K : \u5149\u6807\u4e0a\u79fb\u4e00\u884c j : \u5149\u6807\u4e0b\u79fb\u4e00\u884c w : \u5149\u6807\u8df3\u5230\u4e0b\u4e2aword\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd(\u5305\u62ec\u6807\u70b9\u7b26\u53f7) [\u5e38\u7528] W : \u79fb\u5230\u4e0b\u4e00\u4e2a\u5b57\u7684\u5f00\u5934\uff0c\u5ffd\u7565\u6807\u70b9\u7b26\u53f7 B : \u5149\u6807\u56de\u5230\u4e0a\u4e2aword\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd B : \u79fb\u5230\u524d\u4e00\u4e2a\u5b57\u7684\u5f00\u5934\uff0c\u5ffd\u7565\u6807\u70b9\u7b26\u53f7 BACK E : \u5149\u6807\u8df3\u5230\u4e0b\u4e2aword\u7684\u6700\u540e\u4e00\u4e2a\u5b57\u6bcd E : \u79fb\u5230\u4e0b\u4e00\u4e2a\u5b57\u7684\u7ed3\u5c3e\uff0c\u5ffd\u7565\u6807\u70b9\u7b26\u53f7 END 0 : \u79fb\u5230\u5f53\u524d\u4e00\u884c\u7684\u5f00\u59cb[Home] $ : \u79fb\u5230\u5f53\u524d\u4e00\u884c\u7684\u6700\u540e[End] ^ : \u547d\u4ee4\u5c06\u5149\u6807\u79fb\u52a8\u5230\u5f53\u524d\u884c\u7684\u7b2c\u4e00\u4e2a\u975e\u7a7a\u767d\u5b57\u7b26\u4e0a g_ : \u5230\u672c\u884c\u6700\u540e\u4e00\u4e2a\u4e0d\u662fblank\u5b57\u7b26\u7684\u4f4d\u7f6e Enter : \u5149\u6807\u4e0b\u79fb\u4e00\u884c n+ : \u5149\u6807\u4e0b\u79fbn\u884c\u3010\u6309\u4e0a\u6863\u952e \u6570\u5b57shift +\u3011 n- : \u5149\u6807\u4e0a\u79fbn\u884c G : \u79fb\u5230\u6587\u4ef6\u7684\u6700\u540e\u4e00\u884c nG \u6216\u8005 :n : \u79fb\u5230\u6587\u4ef6\u7684\u7b2cn\u884c\ue5e5\ue5e5\ue5e5 gg : \u79fb\u52a8\u5230\u6587\u6863\u7684\u5f00\u59cb [[ : \u6587\u4ef6\u5f00\u59cb\u4f4d\u7f6e\u2014\u2014\u5f00\u59cb\u884c ]] : \u6587\u4ef6\u7ed3\u675f\u4f4d\u7f6e\u2014\u2014\u672b\u5c3e\u884c H : \u5149\u6807\u79fb\u81f3\u5c4f\u5e55\u9876\u884cHEAD\u3002\u5149\u6807\u5b9a\u4f4d\u5728\u663e\u793a\u5c4f\u7684\u7b2c\u4e00\u884c M : \u79fb\u5230\u5c4f\u5e55\u7684\u4e2d\u95f4\u884c\u5f00\u5934 Middle\u3002\u5149\u6807\u5b9a\u4f4d\u5728\u663e\u793a\u5c4f\u7684\u4e2d\u95f4 L : \u79fb\u5230\u5c4f\u5e55\u7684\u6700\u540e\u4e00\u884cLAST\u3002\u5149\u6807\u5b9a\u4f4d\u5728\u663e\u793a\u5c4f\u7684\u6700\u540e\u4e00\u884c ( : \u5149\u6807\u79fb\u81f3\u53e5\u9996 ) : \u5149\u6807\u79fb\u81f3\u53e5\u5c3e { : \u79fb\u5230\u6bb5\u843d\u7684\u5f00\u5934 } : \u79fb\u5230\u4e0b\u4e00\u4e2a\u6bb5\u843d\u7684\u5f00\u5934 % : \u5339\u914d\u62ec\u53f7\u79fb\u52a8\uff0c\u5305\u62ec (, {, [.\uff08\u9700\u8981\u628a\u5149\u6807\u5148\u79fb\u5230\u62ec\u53f7\u4e0a\uff09\u8df3\u8f6c\u5230\u4e0e\u4e4b\u5339\u914d\u7684\u62ec\u53f7\u5904 * \u548c # : \u5339\u914d\u5149\u6807\u5f53\u524d\u6240\u5728\u7684\u5355\u8bcd\uff0c\u79fb\u52a8\u5149\u6807\u5230\u4e0b\u4e00\u4e2a\uff08\u6216\u4e0a\u4e00\u4e2a\uff09\u5339\u914d\u5355\u8bcd\uff08*\u662f\u4e0b\u4e00\u4e2a\uff0c#\u662f\u4e0a\u4e00\u4e2a\uff09 zf : \u6298\u53e0\uff08\u9700\u52a0\u65b9\u5411\u952e\uff09 zo : \u5c55\u5f00\uff08\u7a7a\u683c\u4e5f\u53ef\u4ee5\u5c55\u5f00\uff09 CTRL+u : \u5411\u6587\u4ef6\u9996\u7ffb\u534a\u5c4fup CTRL+d : \u5411\u6587\u4ef6\u5c3e\u7ffb\u534a\u5c4fdown CTRL+f : \u5411\u6587\u4ef6\u5c3e\u7ffb\u4e00\u5c4f forward (fact\u6574\u5c4f\u53bb\u4e24\u884c) CTRL+b : \u5411\u6587\u4ef6\u9996\u7ffb\u4e00\u5c4fback (fact\u6574\u5c4f\u53bb\u4e24\u884c) CTRL-] : \u8df3\u8f6c\u5230\u5f53\u524d\u5149\u6807\u6240\u5728\u5355\u8bcd\u5bf9\u5e94\u7684\u4e3b\u9898 CTRL-O : \u56de\u5230\u524d\u4e00\u4e2a\u4f4d\u7f6e SHIFT+V : \u9009\u62e9\u6574\u884c zz : \u547d\u4ee4\u4f1a\u628a\u5f53\u524d\u884c\u7f6e\u4e3a\u5c4f\u5e55\u6b63\u4e2d\u592e(z\u5b57\u53d6\u5176\u8c61\u5f62\u610f\u4e49\u6a21\u62df\u4e00\u5f20\u7eb8\u7684\u6298\u53e0\u53ca\u53d8\u5f62\u4f4d\u7f6e\u91cd\u7f6e) zt : \u547d\u4ee4\u4f1a\u628a\u5f53\u524d\u884c\u7f6e\u4e8e\u5c4f\u5e55\u9876\u7aef(top) zb : \u547d\u4ee4\u4f1a\u628a\u5f53\u524d\u884c\u7f6e\u4e8e\u5c4f\u5e55\u5e95\u7aef(bottom) 50% : \u5149\u6807\u5b9a\u4f4d\u5728\u6587\u4ef6\u7684\u4e2d\u95f4 ` : \u8df3\u8f6c\u5230\u6700\u8fd1\u5149\u6807\u5b9a\u4f4d\u7684\u4f4d\u7f6e\uff08\u53ea\u80fd\u8bb0\u5fc6\u6700\u8fd1\u4e24\u4e2a\u4f4d\u7f6e\uff09 \u53cd\u5f15\u53f7 I : \u5728\u5149\u6807\u524d\u5f00\u59cb\u63d2\u5165\u5b57\u7b26 insert I : \u5728\u5f53\u524d\u884c\u9996\u5f00\u59cb\u63d2\u5165\u5b57\u7b26 A : \u5728\u5149\u6807\u4f4d\u7f6e\u540e\u5f00\u59cb\u52a0\u5b57 append A : \u5728\u5149\u6807\u6240\u5728\u884c\u7684\u6700\u540e\u9762\u5f00\u59cb\u52a0\u5b57 O : \u5728\u5149\u6807\u4e0b\u52a0\u4e00\u7a7a\u767d\u884c\u5e76\u5f00\u59cb\u52a0\u5b57 open O : \u5728\u5149\u6807\u4e0a\u52a0\u4e00\u7a7a\u767d\u884c\u5e76\u5f00\u59cb\u52a0\u5b57 R : \u66ff\u6362\u5f53\u524d\u5b57\u7b26 R : \u66ff\u6362\u5f53\u524d\u5b57\u7b26\u53ca\u5176\u540e\u7684\u5b57\u7b26\u3010\u5f53\u524d\u53ca\u5176\u540e\u5b57\u7b26\u88ab\u8986\u76d6\u3011 S : \u9ed8\u8ba4\u5220\u9664\u5149\u6807\u6240\u5728\u5b57\u7b26\uff0c\u8f93\u5165\u5185\u5bb9\u63d2\u5165\u4e4b= xi S : \u9ed8\u8ba4\u5220\u9664\u5f53\u524d\u884c\u5185\u5bb9\uff0c\u8f93\u5165\u5185\u5bb9\u4f5c\u4e3a\u5f53\u524d\u884c\u65b0\u5185\u5bb9= dd+o nx : \u5220\u9664\u7531\u5149\u6807\u4f4d\u7f6e\u8d77\u59cb\u540e\u7684n\u4e2a\u5b57\u7b26\uff08\u542b\u5149\u6807\u4f4d\u7f6e\uff09x =dl(\u5220\u9664\u5f53\u524d\u5149\u6807\u4e0b\u7684\u5b57\u7b26) nX : \u5220\u9664\u7531\u5149\u6807\u4f4d\u7f6e\u8d77\u59cb\u524d\u7684n\u4e2a\u5b57\u7b26\uff08\u542b\u5149\u6807\u4f4d\u7f6e\uff09X =dh(\u5220\u9664\u5f53\u524d\u5149\u6807\u5de6\u8fb9\u7684\u5b57\u7b26) d0 : \u5220\u81f3\u884c\u9996 d$ : \u5220\u81f3\u884c\u5c3e dfa : \u8868\u793a\u5220\u9664\u4ece\u5f53\u524d\u5149\u6807\u5230\u5149\u6807\u540e\u9762\u7684\u7b2c\u4e00\u4e2aa\u5b57\u7b26\u4e4b\u95f4\u7684\u5185\u5bb9 D : \u4ee3\u8868d$(\u5220\u9664\u5230\u884c\u5c3e\u7684\u5185\u5bb9) C : \u4ee3\u8868c$(\u4fee\u6539\u5230\u884c\u5c3e\u7684\u5185\u5bb9) ndw : \u5220\u9664\u5149\u6807\u5904\u5f00\u59cb\u53ca\u5176\u540e\u7684n-1\u4e2a\u5b57 ndb : \u5220\u9664\u5149\u6807\u5904\u5f00\u59cb\u53ca\u5176\u524d\u7684n-1\u4e2a\u5b57 diw : \u5220\u9664\u5f53\u524d\u5149\u6807\u6240\u5728\u7684word(\u4e0d\u5305\u62ec\u7a7a\u767d\u5b57\u7b26)\uff0c\u610f\u4e3aDelete Inner Word \u4e24\u4e2a\u7b26\u53f7\u4e4b\u95f4\u7684\u5355\u8bcd daw : \u5220\u9664\u5f53\u524d\u5149\u6807\u6240\u5728\u7684word(\u5305\u62ec\u7a7a\u767d\u5b57\u7b26)\uff0c\u610f\u4e3aDelete A Word ndd : \u5220\u9664\u5f53\u524d\u884c\u53ca\u5176\u540en-1\u884c :n1,n2 d : \u5c06 n1\u884c\u5230n2\u884c\u4e4b\u95f4\u7684\u5185\u5bb9\u5220\u9664 dG : \u5220\u9664\u5f53\u524d\u884c\u81f3\u6587\u4ef6\u5c3e\u7684\u5185\u5bb9 Dgg : \u5220\u9664\u5f53\u524d\u884c\u81f3\u6587\u4ef6\u5934\u7684\u5185\u5bb9 d+enter : \u5220\u96642\u884c\u3010\u5305\u62ec\u5149\u6807\u4e00\u884c\u3011 cw : \u5220\u9664\u5f53\u524d\u5b57\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f\u3010\u5f88\u597d\u7528\uff0c\u5feb\u901f\u66f4\u6539\u4e00\u4e2a\u5355\u8bcd\u3011\u76f8\u5f53\u4e8edw+i ncw : \u5220\u9664\u5f53\u524d\u5b57\u53ca\u5176\u540e\u7684n-1\u4e2a\u5b57\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f\\\u4fee\u6539\u6307\u5b9a\u6570\u76ee\u7684\u5b57 cc : \u5220\u9664\u5f53\u524d\u884c\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f ncc : \u5220\u9664\u5f53\u524d\u884c\u53ca\u5176\u540e\u7684n-1\u884c\uff0c\u5e76\u8fdb\u5165\u8f93\u5165\u6a21\u5f0f guw : \u5149\u6807\u4e0b\u7684\u5355\u8bcd\u53d8\u4e3a\u5c0f\u5199 gUw : \u5149\u6807\u4e0b\u7684\u5355\u8bcd\u53d8\u4e3a\u5927\u5199 xp : \u5de6\u53f3\u4ea4\u6362\u5149\u6807\u5904\u4e24\u5b57\u7b26\u7684\u4f4d\u7f6e ga : \u663e\u793a\u5149\u6807\u4e0b\u7684\u5b57\u7b26\u5728\u5f53\u524d\u4f7f\u7528\u7684encoding\u4e0b\u7684\u5185\u7801 nyl : \u590d\u5236n\u4e2a\u5b57\u7b26(\u4e5f\u53efnyh) yw : \u590d\u5236\u4e00\u4e2a\u5355\u8bcd y0 : \u8868\u793a\u62f7\u8d1d\u4ece\u5f53\u524d\u5149\u6807\u5230\u5149\u6807\u6240\u5728\u884c\u9996\u7684\u5185\u5bb9 y$ : \u590d\u5236\u4ece\u5f53\u524d\u4f4d\u7f6e\u5230\u884c\u5c3e yfa : \u8868\u793a\u62f7\u8d1d\u4ece\u5f53\u524d\u5149\u6807\u5230\u5149\u6807\u540e\u9762\u7684\u7b2c\u4e00\u4e2aa\u5b57\u7b26\u4e4b\u95f4\u7684\u5185\u5bb9 yG : \u590d\u5236\u4ece\u6240\u5728\u884c\u5230\u6700\u540e\u4e00\u884c nyy : \u5c06\u5149\u6807\u6240\u5728\u4f4d\u7f6e\u5f00\u59cb\u7684n\u884c\u6570\u636e\u590d\u5236\u6682\u5b58, \u590d\u5236\u4e00\u6574\u884c CTRL+v \u65b9\u5411y : \u5217\u9009\u62e9\u6a21\u5f0f\uff0c\u590d\u5236\u9009\u62e9\u7684\u5f88\u591a\u884c\uff1a\u5148\u4f7f\u7528V\u8fdb\u5165visual\u6a21\u5f0f\uff0c\u7136\u540ej\u5411\u4e0b\u79fb\u52a8\u5230\u4f60\u60f3\u590d\u5236\u7684\u884c\u4e3a\u6b62\uff0c\u7136\u540ey p : \u590d\u5236\u6682\u5b58\u6570\u636e\u5728\u5149\u6807\u7684\u4e0b\u4e00\u884c P : \u590d\u5236\u6682\u5b58\u6570\u636e\u5728\u5149\u6807\u7684\u4e0a\u4e00\u884c :n1,n2 co n3 : \u5c06n1\u884c\u5230n2\u884c\u4e4b\u95f4\u7684\u5185\u5bb9\u62f7\u8d1d\u5230\u7b2cn3+1\u884c\u3010n3\u884c\u7684\u4e0b\u4e00\u884c\u3011 :n1,n2 m n3 : \u5c06n1\u884c\u5230n2\u884c\u4e4b\u95f4\u7684\u5185\u5bb9\u79fb\u81f3\u5230\u7b2cn3\u884c\u4e0b J : \u628a\u4e0b\u4e00\u884c\u7684\u6570\u636e\u8fde\u63a5\u5230\u672c\u884c\u4e4b\u540e, \u591a\u4e00\u7a7a\u683c ~ : \u6539\u53d8\u5f53\u524d\u5149\u6807\u4e0b\u5b57\u7b26\u7684\u5927\u5c0f\u5199 \u5176\u4ed6 . : \u91cd\u590d\u524d\u4e00\u6307\u4ee4 u : \u53d6\u6d88\u524d\u4e00\u6307\u4ee4undo, :u\u4e5f\u884c\uff0c\u4e00\u822c\u4e0d\u7528\uff0c\u64cd\u4f5c\u592a\u591a Ctrl + r : \u6062\u590d\u3010\u53ea\u5bf9u\u6709\u6548\u3011redo Ctrl + l : \u5237\u65b0\u5c4f\u5e55\u663e\u793a Ctrl+v \u7136\u540e ctrl+A\u662f^A Ctrl+I\u662f\\t : \u8f93\u5165\u7279\u6b8a\u5b57\u7b26 Ctrl+v\u7136\u540e\u7528j\u3001k\u3001l\u3001h\u6216\u65b9\u5411\u952e\u4e0a\u4e0b\u9009\u4e2d\u591a\u5217\uff0c\u4e4b\u540e I I a A r x\u7b49\uff0c\u6700\u540e\u6309esc\uff0c\u751f\u6548 : Vim\u5217\u64cd\u4f5c","title":"1.1.vim\u5de5\u5177"},{"location":"linux/SRE/04-TextTools/#2","text":"","title":"2.\u6587\u672c\u5904\u7406\u5de5\u5177"},{"location":"linux/SRE/04-TextTools/#21cat","text":"\u547d\u4ee4 cat \u4e3b\u8981\u53c2\u6570\u8bf4\u660e\uff1a -E \uff1a\u663e\u793a\u884c\u7ed3\u675f\u7b26 $ -A \uff1a\u663e\u793a\u6240\u6709\u63a7\u5236\u7b26 -n \uff1a\u5bf9\u663e\u793a\u51fa\u7684\u6bcf\u4e00\u884c\u8fdb\u884c\u7f16\u53f7 -b \uff1a\u975e\u7a7a\u884c\u7f16\u53f7 -s \uff1a\u538b\u7f29\u8fde\u7eed\u7684\u7a7a\u884c\u6210\u4e00\u884c \u4e3e\u4f8b\uff1a cat -nA user-list.txt 1 user0$ 2 user1$ 3 user2$ 4 user3$ 5 user4$ 6 user5$ 7 user6$ 8 user7$ 9 user8$ 10 user9$","title":"2.1.\u663e\u793a\u6587\u672c\u5185\u5bb9cat"},{"location":"linux/SRE/04-TextTools/#22nl","text":"\u76f8\u5f53\u4e8e\u547d\u4ee4 cat -b \u3002 \u547d\u4ee4 nl \u4e3b\u8981\u53c2\u6570\u8bf4\u660e\uff1a -b \uff1a\u6307\u5b9a\u884c\u53f7\u6307\u5b9a\u7684\u65b9\u5f0f\uff0c\u4e3b\u8981\u6709\u4e24\u79cd\uff1a -b a \uff1a\u8868\u793a\u4e0d\u8bba\u662f\u5426\u4e3a\u7a7a\u884c\uff0c\u4e5f\u540c\u6837\u5217\u51fa\u884c\u53f7\uff08\u7c7b\u4f3c cat -n\uff09\uff1b -b t \uff1a\u5982\u679c\u6709\u7a7a\u884c\uff0c\u7a7a\u7684\u90a3\u4e00\u884c\u4e0d\u8981\u5217\u51fa\u884c\u53f7\uff08\u9ed8\u8ba4\u503c\uff09\uff1b -n \uff1a\u5217\u51fa\u884c\u53f7\u8868\u793a\u7684\u65b9\u6cd5\uff0c\u4e3b\u8981\u6709\u4e09\u79cd\uff1a -n ln \uff1a\u884c\u53f7\u5728\u5c4f\u5e55\u7684\u6700\u5de6\u65b9\u663e\u793a\uff1b\u6ca1\u6709\u524d\u5bfc0\uff1b -n rn \uff1a\u884c\u53f7\u5728\u81ea\u5df1\u680f\u4f4d\u7684\u6700\u53f3\u65b9\u663e\u793a\uff0c\u6ca1\u6709\u524d\u5bfc0\uff1b -n rz \uff1a\u884c\u53f7\u5728\u81ea\u5df1\u680f\u4f4d\u7684\u6700\u53f3\u65b9\u663e\u793a\uff0c\u6709\u524d\u5bfc0\uff1b -w \uff1a\u884c\u53f7\u680f\u4f4d\u7684\u5360\u7528\u7684\u4f4d\u6570\u3002 -p \uff1a\u5728\u903b\u8f91\u5b9a\u754c\u7b26\u5904\u4e0d\u91cd\u65b0\u5f00\u59cb\u8ba1 \u4e3e\u4f8b\uff1a $ nl -b a -n rz user-list.txt 000001 user0 000002 user1 000003 user2 000004 user3 000005 user4 000006 user5 000007 user6 000008 user7 000009 user8 000010 user9","title":"2.2.\u663e\u793a\u6587\u672c\u884c\u53f7nl"},{"location":"linux/SRE/04-TextTools/#23tac","text":"\u547d\u4ee4 tac \u9006\u5411\u663e\u793a\u6587\u672c\u5185\u5bb9\u3002 \u4e3e\u4f8b\uff1a $ tac user-list.txt user9 user8 user7 user6 user5 user4 user3 user2 user1 user0 \u4e3e\u4f8b\uff1a $ seq 10 | tac 10 9 8 7 6 5 4 3 2 1","title":"2.3.\u9006\u5411\u663e\u793a\u6587\u672c\u5185\u5bb9tac"},{"location":"linux/SRE/04-TextTools/#24rev","text":"\u547d\u4ee4 rev \u9006\u5411\u663e\u793a\u540c\u4e00\u884c\u7684\u5185\u5bb9\u3002 \u4e3e\u4f8b\uff1a $ rev user-list.txt 0resu 1resu 2resu 3resu 4resu 5resu 6resu 7resu 8resu 9resu \u4e3e\u4f8b\uff1a $ echo { 1 ..10 } | rev 01 9 8 7 6 5 4 3 2 1","title":"2.4.\u9006\u5411\u663e\u793a\u540c\u884c\u5185\u5bb9rev"},{"location":"linux/SRE/04-TextTools/#25hexdump","text":"\u547d\u4ee4 hexdump \u547d\u4ee4\u4e00\u822c\u7528\u6765\u67e5\u770b\u201c\u4e8c\u8fdb\u5236\u201d\u6587\u4ef6\u7684\u5341\u516d\u8fdb\u5236\u7f16\u7801 \u4e3e\u4f8b\uff1a $ hexdump -C -n 32 cp 00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 | .ELF............ | 00000010 03 00 3e 00 01 00 00 00 e0 48 00 00 00 00 00 00 | ..>......H...... | 00000020","title":"2.5.\u663e\u793a\u975e\u6587\u672c\u6587\u4ef6\u5185\u5bb9hexdump"},{"location":"linux/SRE/04-TextTools/#26","text":"\u547d\u4ee4 more \u548c less \u53ef\u4ee5\u5b9e\u73b0\u5206\u9875\u67e5\u770b\u6587\u4ef6\u5185\u5bb9\u3002 \u547d\u4ee4 less \u914d\u5408\u7ba1\u9053\u7b26\u4f7f\u7528\u3002 tree -d /etc | less","title":"2.6.\u5206\u9875\u67e5\u770b\u6587\u4ef6\u5185\u5bb9"},{"location":"linux/SRE/04-TextTools/#27head","text":"\u547d\u4ee4 head \u663e\u793a\u6587\u4ef6\u5934\u90e8\u5185\u5bb9\u3002 head -c 20 cp : \u663e\u793a\u6587\u4ef6\u524d20\u5b57\u8282\u5185\u5bb9 head -n 20 zdiff : \u663e\u793a\u6587\u4ef6\u524d20\u884c\u5185\u5bb9 head -20 zdiff : \u663e\u793a\u6587\u4ef6\u524d20\u884c\u5185\u5bb9 $ echo \"\u6211\u662f\u8c01\" | head -c3 \u6211 $ echo \"\u6211\u662f\u8c01\" | head -c6 \u6211\u662f cat /dev/urandom | tr -dc '[:alnum]' | head -c 10 | tee passwd.txt $ cat user-list.txt user0 user1 user2 user3 user4 user5 user6 user7 user8 user9 $ head -n -3 user-list.txt user0 user1 user2 user3 user4 user5 user6","title":"2.7.\u663e\u793a\u6587\u4ef6\u5934\u90e8\u5185\u5bb9head"},{"location":"linux/SRE/04-TextTools/#28tail","text":"\u547d\u4ee4 tail \u663e\u793a\u6587\u4ef6\u5934\u90e8\u5185\u5bb9\u3002 tail -c 200 cp : \u663e\u793a\u6587\u4ef6\u5c3e\u90e8200\u4e2a\u5b57\u8282\u7684\u5185\u5bb9 tail -n 3 user-list.txt : \u663e\u793a\u6587\u4ef6\u6700\u540e3\u884c tail -n -3 user-list.txt : \u663e\u793a\u4ece-3\u884c\u5230\u6587\u4ef6\u7ed3\u675f\uff08\u5373\u6700\u540e\u4e09\u884c\uff09 tail -3 user-list.txt : \u663e\u793a\u6587\u4ef6\u6700\u540e3\u884c tail -f /var/log/messages : \u8ddf\u8e2a\u663e\u793a\u6587\u4ef6redo.log\u6587\u4ef6\u5185\u5bb9\uff0c\u5f53\u6587\u4ef6\u5220\u9664\uff0c\u518d\u5efa\u540c\u540d\u6587\u4ef6\uff0c\u65e0\u6cd5\u7ee7\u7eed\u8ffd\u8e2a tail -F /var/log/messages : \u8ddf\u8e2a\u663e\u793a\u6587\u4ef6redo.log\u6587\u4ef6\u5185\u5bb9\uff0c\u5f53\u6587\u4ef6\u5220\u9664\uff0c\u518d\u5efa\u540c\u540d\u6587\u4ef6\uff0c\u7ee7\u7eed\u8ffd\u8e2a","title":"2.8.\u663e\u793a\u6587\u4ef6\u5c3e\u90e8\u5185\u5bb9tail"},{"location":"linux/SRE/04-TextTools/#29cut","text":"\u547d\u4ee4 cut \u53ef\u4ee5\u63d0\u53d6\u6587\u672c\u6587\u4ef6\u6216\u8005stdin\u6570\u636e\u7684\u6307\u5b9a\u5217\u5185\u5bb9\u3002 \u9009\u9879\uff1a -f : \u901a\u8fc7\u6307\u5b9a\u54ea\u4e00\u4e2a\u5b57\u6bb5\u8fdb\u884c\u63d0\u53d6\u3002cut\u547d\u4ee4\u4f7f\u7528\u201cTAB\u201d\u4f5c\u4e3a\u9ed8\u8ba4\u7684\u5b57\u6bb5\u5206\u9694\u7b26 -d : \u201cTAB\u201d\u662f\u9ed8\u8ba4\u7684\u5206\u9694\u7b26\uff0c\u4f7f\u7528\u6b64\u9009\u9879\u53ef\u4ee5\u66f4\u6539\u4e3a\u5176\u4ed6\u7684\u5206\u9694\u7b26 --complement : \u6b64\u9009\u9879\u7528\u4e8e\u6392\u9664\u6240\u6307\u5b9a\u7684\u5b57\u6bb5 --output-delimiter=STRING : \u6307\u5b9a\u8f93\u51fa\u5185\u5bb9\u7684\u5206\u9694\u7b26 -c : \u6309\u5b57\u7b26\u5207\u5272 \u53d6/etc/passwd\u6587\u4ef6\u7b2c1\u5217\u5185\u5bb9\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff08\u53ea\u53d6\u524d\u4e09\u884c\uff09 $ cut -d ':' -f 1 /etc/passwd | head -3 root messagebus systemd-network \u53d6/etc/passwd\u6587\u4ef6\u7b2c1\u548c6\u5217\u5185\u5bb9\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff08\u53ea\u53d6\u524d\u4e09\u884c\uff09 cut -d ':' -f 1 ,6 /etc/passwd | head -3 root:/root messagebus:/run/dbus systemd-network:/ \u53d6/etc/passwd\u6587\u4ef6\u7b2c1\u52303\u5217\u4ee5\u53ca\u7b2c6\u5217\u5185\u5bb9\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff08\u53ea\u53d6\u524d\u4e09\u884c\uff09 $ cut -d ':' -f 1 -3,6 /etc/passwd | head -3 root:x:0:/root messagebus:x:499:/run/dbus systemd-network:x:497:/ \u4e0b\u9762\u4f7f\u7528 --output-delimiter \u9009\u9879\uff0c\u628a\u8f93\u51fa\u7ed3\u679c\u4e2d\u7684\u5206\u9694\u7b26 : \u5168\u90e8\u66ff\u6362\u6210 --- \u3002 $ cat /etc/passwd | sort | head -3 admin3:x:1020:100::/home/admin3:/bin/bash at:x:25:25:Batch jobs daemon:/var/spool/atjobs:/usr/sbin/nologin bin:x:1:1:bin:/bin:/usr/sbin/nologin $ cut -d \":\" -f 1 ,7 /etc/passwd | sort | head -3 admin3:/bin/bash at:/usr/sbin/nologin bin:/usr/sbin/nologin $ cut -d \":\" -f 1 ,7 --output-delimiter = \"---\" /etc/passwd | sort | head -3 admin3---/bin/bash at---/usr/sbin/nologin bin---/usr/sbin/nologin --output-delimiter \u9009\u9879\u4e5f\u53ef\u4ee5\u5229\u7528\u6765\u8fdb\u884c\u8ba1\u7b97\u3002 $ echo { 1 ..10 } | cut -d \" \" -f 1 -10 --output-delimiter = \"+\" | bc 55 \u4ece ifconfig \u547d\u4ee4\u4e2d\u622a\u53d6\u5f53\u524d\u4e3b\u673a\u7684ip\u5730\u5740\u3002\uff08openSUSE\u9700\u8981\u5b89\u88c5\u5305 net-tools-deprecated \uff09 $ ifconfig | head -2 | tail -1 inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig | head -2 | tail -1 | cut -d \" \" -f 10 192 .168.10.210 \u6216\u8005 $ ip addr list | grep eth0 | tail -1 | cut -d \" \" -f 6 192 .168.10.210/24 \u57fa\u4e8e\u4e0a\u9762\u7ed3\u679c\uff0c\u53ef\u4ee5\u5c1d\u8bd5\u901a\u8fc7 --complement \u53c2\u6570\uff0c\u4ee5 / \u4e3a\u5206\u9694\u7b26\uff0c\u6392\u9664\u7b2c\u4e8c\u5217 24 \uff0c\u53ea\u8f93\u51fa\u7b2c\u4e00\u5217IP\u5730\u5740\u3002 ip addr list | grep eth0 | tail -1 | cut -d \" \" -f 6 | cut -d \"/\" --complement -f 2 192 .168.10.210 \u663e\u793a df \u547d\u4ee4\u8f93\u51fa\u4e2d\u7684\u5206\u533a\u4f7f\u7528\u7387\u3002 $ df | tr -s ' ' | cut -d ' ' -f 5 | tr -d % Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0 \u65b9\u6cd52\uff1a\u5148\u628a\u7a7a\u683c\u5168\u90e8\u66ff\u6362\u6210%\uff0c\u518d\u53bb\u91cd\u3002 df | tr -s ' ' % | cut -d % -f 5 Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0","title":"2.9.\u6309\u5217\u62bd\u53d6\u6587\u672ccut"},{"location":"linux/SRE/04-TextTools/#210paste","text":"\u547d\u4ee4 paste \u5e38\u7528\u9009\u9879\uff1a -d \uff1a\u6307\u5b9a\u5206\u9694\u7b26\uff0c\u9ed8\u8ba4\u662fTAB -s \uff1a\u6240\u6709\u884c\u5408\u6210\u4e00\u884c\u663e\u793a \u751f\u6210 alpha.log \u548c seq.log \u3002 for i in { a..z } ; do echo $i >> alpha.log ; done seq 10 > seq.log \u7528 paste \u547d\u4ee4\u5408\u5e76\u8fd92\u4e2a\u6587\u4ef6\u3002 $ paste alpha.log seq.log a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 k l m n o p q r s t u v w x y z $ paste -d \":\" alpha.log seq.log a:1 b:2 c:3 d:4 e:5 f:6 g:7 h:8 i:9 j:10 k: l: m: n: o: p: q: r: s: t: u: v: w: x: y: z: \u539f\u6587\u4ef6\u90fd\u662f\u5217\u8f93\u51fa\uff0c\u6539\u6210\u884c\u8f93\u51fa\u3002 $ paste -d \"-\" -s alpha.log a-b-c-d-e-f-g-h-i-j-k-l-m-n-o-p-q-r-s-t-u-v-w-x-y-z $ paste -d \"-\" -s seq.log $ paste -d \":\" -s alpha.log seq.log a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z 1 :2:3:4:5:6:7:8:9:10 $ paste -d \":\" -s seq.log alpha.log 1 :2:3:4:5:6:7:8:9:10 a:b:c:d:e:f:g:h:i:j:k:l:m:n:o:p:q:r:s:t:u:v:w:x:y:z","title":"2.10.\u5408\u5e76\u591a\u4e2a\u6587\u4ef6paste"},{"location":"linux/SRE/04-TextTools/#211wc","text":"\u5e38\u7528\u9009\u9879\uff1a -l \uff1a\u53ea\u8ba1\u6570\u884c\u6570 -w \uff1a\u53ea\u8ba1\u6570\u5355\u8bcd\u603b\u6570 -c \uff1a\u53ea\u8ba1\u6570\u5b57\u8282\u603b\u6570 -m \uff1a\u53ea\u8ba1\u6570\u5b57\u7b26\u603b\u6570 -L \uff1a\u663e\u793a\u6587\u4ef6\u4e2d\u6700\u957f\u884c\u7684\u957f\u5ea6 $ cat text Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ wc text # \u884c\u6570 \u5355\u8bcd\u6570 \u5b57\u8282\u6570 3 9 57 text $ wc -l text 3 text $ wc -w text 9 text $ wc -c text 57 text $ wc -m text 57 text $ wc -L text 20 text \u5bf9\u6bd4\u4e24\u79cd\u4e0d\u540c\u5408\u5e76\u7684\u65b9\u6cd5\u3002 $ cat text1 text2 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou $ paste text1 text2 Tom, 20 , Shanghai Tom, 20 , Shanghai Jack, 30 , Beijing Jack, 30 , Beijing Smith, 40 , Guangzhou Leo, 40 , Guangzhou","title":"2.11.\u6587\u672c\u7edf\u8ba1\u6570\u636ewc"},{"location":"linux/SRE/04-TextTools/#212sort","text":"\u547d\u4ee4 sort \u628a\u6574\u7406\u8fc7\u7684\u6587\u672c\u663e\u793a\u5728stdout\u4e0a\uff0c\u4e0d\u6539\u53d8\u539f\u6587\u4ef6\u3002 \u5e38\u7528\u9009\u9879\uff1a -r \uff1a\u6267\u884c\u53cd\u65b9\u5411\uff08\u4ece\u4e0a\u81f3\u4e0b\uff09\u6392\u5e8f -R \uff1a\u968f\u673a\u6392\u5e8f -n \uff1a\u6309\u6570\u5b57\u5927\u5c0f\u6392\u5e8f -h \uff1a\u4eba\u7c7b\u53ef\u8bfb\u6392\u5e8f\uff0c\u5982\uff1a2K\uff0c1G -f \uff1a\u6392\u5e8f\u65f6\u5c06\u5c0f\u5199\u5b57\u6bcd\u89c6\u4e3a\u5927\u5199\u5b57\u6bcd -u \uff1a\u6392\u5e8f\u65f6\u5408\u5e76\u91cd\u590d\u9879 -t c \uff1a\u4f7f\u7528c\u4f5c\u4e3a\u5b57\u6bb5\u5206\u9694\u7b26 -k # \uff1a\u6309\u7167\u4ee5c\u4e3a\u5206\u9694\u7b26\u7684\u7b2c#\u5217\u6765\u6392\u5e8f \u4e3e\u4f8b\uff1a\u4ee5 , \u4e3a\u5206\u9694\u7b26\uff0c\u8bfb\u53d6 text \u6587\u4ef6\u5185\u5bb9\u4e2d\u7b2c1\uff0c3\u5217\uff0c\u5bf9\u8f93\u51fa\u7ed3\u679c\u4ee5 , \u4e3a\u5206\u9694\u7b26\uff0c\u6309\u7b2c\u4e8c\u5217\u6392\u5e8f\uff08\u6b63\u5e8f\u548c\u53cd\u5e8f\uff09\u3002 $ cat text Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ cut -d \",\" -f 1 ,3 text | sort -t \",\" -k 1 Jack, Beijing Smith, Guangzhou Tom, Shanghai $ cut -d \",\" -f 1 ,3 text | sort -t \",\" -k 1 -r Tom, Shanghai Smith, Guangzhou Jack, Beijing \u628a\u6587\u4ef6text1\u548c\u6587\u4ef6text2\u5408\u5e76\u540e\u53bb\u91cd\u8f93\u51fa\u3002 $ cat text2 Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou $ cat text1 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ cat text1 text2 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou \u5e76\u96c6\uff0c\u91cd\u590d\u884c\u53ea\u4fdd\u7559\u4e00\u884c\u3002\u524d\u97622\u4e2a\u547d\u4ee4\u662f\u540c\u6837\u542b\u4e49\uff08\u76f8\u540c\u7684\u6392\u5e8f\u5217\uff09\uff0c\u7b2c\u4e09\u4e2a\u547d\u4ee4\u4e2d\u5bf9\u4e0d\u540c\u5217\u8fdb\u884c\u4e86\u6392\u5e8f\uff0c\u5bfc\u81f4\u53bb\u91cd\u7ed3\u679c\u4e0d\u540c\u3002 $ cat text1 text2 | sort -u Jack, 30 , Beijing Leo, 40 , Guangzhou Smith, 40 , Guangzhou Tom, 20 , Shanghai $ cat text1 text2 | sort -t \",\" -k 1 -u Jack, 30 , Beijing Leo, 40 , Guangzhou Smith, 40 , Guangzhou Tom, 20 , Shanghai $ cat text1 text2 | sort -t \",\" -k 2 -u Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou","title":"2.12.\u6587\u672c\u6392\u5e8fsort"},{"location":"linux/SRE/04-TextTools/#213uniq","text":"\u547d\u4ee4 uniq \u4ece\u8f93\u5165\u4e2d\u5220\u9664\u524d\u540e\u76f8\u90bb\u91cd\u590d\u7684\u884c\u3002\u7ecf\u5e38\u4e0e sort \u547d\u4ee4\u7ed3\u5408\u4f7f\u7528\u3002 \u4e3b\u8981\u53c2\u6570\uff1a -c \uff1a\u663e\u793a\u6bcf\u884c\u91cd\u590d\u51fa\u73b0\u7684\u6b21\u6570 -d \uff1a\u4ec5\u663e\u793a\u91cd\u590d\u7684\u884c -u \uff1a\u4ec5\u663e\u793a\u4e0d\u91cd\u590d\u7684\u884c \u4e3e\u4f8b\uff0c\u6ce8\u610f\u53ea\u6709\u5bf9\u76f8\u90bb\u884c\u8fdb\u884c\u53bb\u91cd\u3002 $ cat text3 test 30 Hello 95 Hello 95 Linux 85 Linux 85 Hello 95 test 30 $ uniq text3 test 30 Hello 95 Linux 85 Hello 95 test 30 \u628a\u6587\u4ef6text1\u548c\u6587\u4ef6text2\u5408\u5e76\u540e\uff0c\u8fdb\u884c\u4ea4\u96c6\u548c\u5e76\u96c6\uff0c\u5e76\u53bb\u91cd\u3002 $ cat text1 Tom, 20 , Shanghai Jack, 30 , Beijing Smith, 40 , Guangzhou $ cat text2 Tom, 20 , Shanghai Jack, 30 , Beijing Leo, 40 , Guangzhou # \u5e76\u96c6\uff0c\u6309\u9996\u5217\u6392\u5e8f\u53bb\u91cd $ cat text1 text2 | sort | uniq Jack, 30 , Beijing Leo, 40 , Guangzhou Smith, 40 , Guangzhou Tom, 20 , Shanghai # \u4ea4\u96c6 $ cat text1 text2 | sort | uniq -d Jack, 30 , Beijing Tom, 20 , Shanghai # \u5dee\u96c6 $ cat text1 text2 | sort | uniq -u Leo, 40 , Guangzhou Smith, 40 , Guangzhou \u67e5\u770b\u5e76\u53d1\u8fde\u63a5\u6570\u6700\u591a\u7684\u8fdc\u7a0b\u4e3b\u673aIP\u3002 $ ss -nt State Recv-Q Send-Q Local Address:Port Peer Address:Port Process ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:41650 ESTAB 0 0 192 .168.10.210:22 192 .168.10.201:65330 ESTAB 0 64 192 .168.10.210:22 192 .168.10.201:63289 ESTAB 0 0 192 .168.10.210:41650 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:47992 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:60268 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.201:65327 ESTAB 0 0 192 .168.10.210:35758 192 .168.10.220:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:56818 ESTAB 0 0 192 .168.10.210:56818 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:48006 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:60268 ESTAB 0 0 192 .168.10.210:22 192 .168.10.220:33896 ESTAB 0 0 192 .168.10.210:22 192 .168.10.201:65324 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:47992 ESTAB 0 0 192 .168.10.210:59554 192 .168.10.210:22 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:59554 ESTAB 0 0 192 .168.10.210:22 192 .168.10.210:48006 $ ss -nt | tr -s \" \" \":\" | cut -d \":\" -f 6 ,7 | sort | uniq -c | sort -nr | head -n 1 6 192 .168.10.210:22","title":"2.13.\u53bb\u91cduniq"},{"location":"linux/SRE/04-TextTools/#214","text":"","title":"2.14.\u6587\u672c\u6bd4\u8f83"},{"location":"linux/SRE/04-TextTools/#2141diff","text":"\u547d\u4ee4 diff \u6bd4\u8f83\u4e24\u4e2a\u6587\u4ef6\u4e4b\u95f4\u7684\u533a\u522b\u3002 \u5e38\u7528\u9009\u9879\uff1a -u \uff1a\u4ee5\u7edf\u4e00\u7684\u65b9\u5f0f\u6765\u663e\u793a\u6587\u4ef6\u5185\u5bb9\u7684\u4e0d\u540c -y \uff1a\u4ee5\u5e76\u5217\u7684\u65b9\u5f0f\u663e\u793a\u6587\u4ef6\u7684\u5f02\u540c\u4e4b\u5904 -W \uff1a\u5728\u4f7f\u7528-y\u53c2\u6570\u65f6\uff0c\u6307\u5b9a\u680f\u5bbd -c \uff1a\u663e\u793a\u5168\u90e8\u5185\u6587\uff0c\u5e76\u6807\u51fa\u4e0d\u540c\u4e4b\u5904 -N \uff1a\u7f3a\u5931\u6587\u4ef6\u4ee5\u7a7a\u6587\u4ef6\u5904\u7406 \u4e3e\u4f8b\uff1a $ cat text5 # \u6587\u4ef6\u5c3e\u90e8\u6ca1\u6709\u7a7a\u884c 1001 1002 1003 $ cat text6 # \u6587\u4ef6\u5c3e\u90e8\u6ca1\u6709\u7a7a\u884c 1001 1002 1003a 1004 \u663e\u793a\u4e0d\u540c\u3002 3c3,4 \u4ee3\u8868\u4e24\u4e2a\u6587\u4ef6\u5728\u7b2c3\uff0c4\u884c\u6709\u4e0d\u540c\u3002 $ diff text5 text6 3c3,4 < 1003 --- > 1003a > 1004 \u4ee5\u7edf\u4e00\u683c\u5f0f\u8f93\u51fa\u6bd4\u8f83\u7ed3\u679c\u3002 \u524d2\u884c\u662f\u6587\u4ef6\u4fe1\u606f\u3002\u5176\u4e2d --- \u8868\u793a\u53d8\u52a8\u524d\u7684\u6587\u4ef6\uff0c +++ \u8868\u793a\u53d8\u52a8\u540e\u7684\u6587\u4ef6\u3002 \u53d8\u52a8\u7684\u4f4d\u7f6e\u7528\u4e24\u4e2a@\u4f5c\u4e3a\u8d77\u9996\u548c\u7ed3\u675f\uff0c @@ -1,3 +1,4 @@ \u3002 -1,3 \u4e2d\uff0c - \u8868\u793a\u7b2c\u4e00\u4e2a\u6587\u4ef6\uff0c\u5373 text5 \u3002\u7b2c\u4e00\u4e2a\u6587\u4ef6\u4ece\u7b2c1\u884c\u5f00\u59cb\u8fde\u7eed3\u884c\u3002 +1,4 \u4e2d\uff0c + \u8868\u793a\u7b2c\u4e8c\u4e2a\u6587\u4ef6\uff0c\u5373 text6 \u3002\u5373\uff0c\u7b2c\u4e8c\u4e2a\u6587\u4ef6\u4ece\u7b2c1\u884c\u5f00\u59cb\u8fde\u7eed4\u884c\u3002 $ diff -u text5 text6 --- text5 2022 -12-07 08 :07:05.927805722 +0800 +++ text6 2022 -12-07 08 :07:24.692234585 +0800 @@ -1,3 +1,4 @@ 1001 1002 -1003 +1003a +1004 \u4ee5\u4e0a\u4e0b\u6587\u65b9\u5f0f\u8f93\u51fa\u6bd4\u8f83\u7ed3\u679c\u3002\u6807\u6709 ! \u4ee3\u8868\u5dee\u5f02\u884c\u3002 $ diff -c text5 text6 *** text5 2022 -12-07 08 :24:08.867168414 +0800 --- text6 2022 -12-07 08 :24:13.939284243 +0800 *************** *** 1 ,3 **** 1001 1002 ! 1003 --- 1 ,4 ---- 1001 1002 ! 1003a ! 1004 \u5e76\u6392\u683c\u5f0f\u8f93\u51fa\u6bd4\u8f83\u7ed3\u679c\u3002 | \u8868\u793a\u524d\u540e2\u4e2a\u6587\u4ef6\u5185\u5bb9\u6709\u4e0d\u540c < \u8868\u793a\u540e\u9762\u6587\u4ef6\u6bd4\u524d\u9762\u6587\u4ef6\u5c11\u4e861\u884c\u5185\u5bb9 > \u8868\u793a\u540e\u9762\u6587\u4ef6\u6bd4\u524d\u9762\u6587\u4ef6\u591a\u4e861\u884c\u5185\u5bb9 $ diff -y -W 50 text5 text6 1001 1001 1002 1002 1003 | 1003a > 1004 \u6bd4\u8f83\u6587\u4ef6\u5939\u5185\u5bb9\u3002\u6ce8\u610f\uff0c\u53ea\u6bd4\u8f83\u5185\u5bb9\uff0c\u4e0d\u6bd4\u8f83\u65f6\u95f4\u6233\u3002 $ mkdir dir1 $ mkdir dir2 $ cd dir1 $ touch file1 $ touch file2 $ cp file1 file2 ../dir2/ $ echo \"hello\" > file3 $ cd ../dir2 $ touch file3 $ touch file4 $ diff dir1 dir2 1d0 < hello Only in dir2: file4","title":"2.14.1.diff"},{"location":"linux/SRE/04-TextTools/#2142patch","text":"\u547d\u4ee4 patch \u590d\u5236\u5176\u4ed6\u6587\u4ef6\u4e2d\u7684\u5185\u5bb9\u3002\u547d\u4ee4\u683c\u5f0f\uff1a patch -p [ num ] < patchfile patch [ options ] originalfile patchfile \u5f53\u7279\u5b9a\u8f6f\u4ef6\u6709\u53ef\u7528\u7684\u5b89\u5168\u4fee\u590d\u7a0b\u5e8f\u65f6\uff0c\u6211\u4eec\u901a\u5e38\u4f1a\u4f7f\u7528 yum \u6216 apt-get \u6216 zypper \u7b49\u5305\u7ba1\u7406\u5de5\u5177\u8fdb\u884c\u4e8c\u8fdb\u5236\u5347\u7ea7\u3002 \u4f46\u5982\u679c\u6211\u4eec\u662f\u901a\u8fc7\u4ece\u6e90\u4ee3\u7801\u7f16\u8bd1\u5b89\u88c5\u8f6f\u4ef6\u7684\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u9700\u8981\u4e0b\u8f7d\u5b89\u5168\u8865\u4e01\u5e76\u5c06\u5176\u5e94\u7528\u4e8e\u539f\u59cb\u6e90\u4ee3\u7801\u5e76\u91cd\u65b0\u7f16\u8bd1\u8f6f\u4ef6\u3002 \u8fd9\u5c31\u662f\u6211\u4eec\u4f7f\u7528 diff \u521b\u5efa\u8865\u4e01\u6587\u4ef6\uff08patch file\uff09\uff0c\u5e76\u4f7f\u7528 patch \u547d\u4ee4\u5e94\u7528\u5b83\u3002 \u8865\u4e01\u6587\u4ef6\u662f\u4e00\u4e2a\u6587\u672c\u6587\u4ef6\uff0c\u5176\u4e2d\u5305\u542b\u540c\u4e00\u6587\u4ef6\uff08\u6216\u540c\u4e00\u6e90\u4ee3\u7801\u6811\uff09\u7684\u4e24\u4e2a\u7248\u672c\u4e4b\u95f4\u7684\u5dee\u5f02\u3002 \u8865\u4e01\u6587\u4ef6\u662f\u4f7f\u7528 diff \u547d\u4ee4\u521b\u5efa\u7684\u3002 \u7ee7\u7eed\u4e0a\u4f8b\u3002 \u5c06\u6587\u4ef6 text5 \u7684\u5185\u5bb9\u540c\u6b65\u5230\u6587\u4ef6 text6 \uff0c\u7136\u540e\u64a4\u9500\u8865\u4e01\u3002\u6ce8\u610f\u533a\u5206\u6e90\u6587\u4ef6\u548c\u76ee\u6807\u6587\u4ef6\u3002 $ cat text5 1001 1002 1003 $ cat text6 1001 1002 1003a 1004 # \u751f\u6210\u8865\u4e01\u6587\u4ef6 $ diff -ruN text5 text6 > patchfile $ cat patchfile --- text5 2022 -12-07 08 :24:08.867168414 +0800 +++ text6 2022 -12-07 08 :24:13.939284243 +0800 @@ -1,3 +1,4 @@ 1001 1002 -1003 +1003a +1004 # \u4e0d\u6307\u660e\u76ee\u6807\u6587\u4ef6\uff0c\u5219\u9ed8\u8ba4\u7ed9diff\u547d\u4ee4\u4e2d\u7684\u6e90\u6587\u4ef6\u8fdb\u884c\u6253\u8865\u4e01 $ patch < patchfile patching file text5 $ cat text5 1001 1002 1003a 1004 $ cat text6 1001 1002 1003a 1004 # \u64a4\u9500\u8865\u4e01 patch -R < patchfile patching file text5 # cat text5 1001 1002 1003 # \u7ed9text6\u6587\u4ef6\u6253\u8865\u4e01\uff08\u7528text5\u7684\u6587\u4ef6\u5185\u5bb9\u8986\u76d6text6\u7684\u5185\u5bb9\uff09 $ patch text6 patchfile patching file text6 Reversed ( or previously applied ) patch detected! Assume -R? [ n ] y $ cat text6 1001 1002 1003 # \u64a4\u9500\u7ed9text6\u6587\u4ef6\u6253\u7684\u8865\u4e01\uff08\u6062\u590dtext6\u6587\u4ef6\u8865\u4e01\u524d\u7684\u5185\u5bb9\uff09 $ patch -R text6 patchfile patching file text6 Unreversed patch detected! Ignore -R? [ n ] y $ cat text6 1001 1002 1003a 1004 \u4f7f\u7528 -b \u53c2\u6570\uff0c\u5728patch\u524d\u5148\u5907\u4efd\u6e90\u6587\u4ef6\u3002 $ patch -b < patchfile patching file text5 $ cat text5 1001 1002 1003a 1004 $ cat text5.orig 1001 1002 1003 $ cat text6.orig 1001 1002 1003 $ patch -R < patchfile patching file text5 \u5728-b\u53c2\u6570\u4e2d\u52a0\u5165-V\u53c2\u6570\uff0c\u6307\u5b9a\u5907\u4efd\u6587\u4ef6\u540d\u7684\u683c\u5f0f\uff0c\u5982\u4e0b\uff0c\u4f1a\u5f97\u5230\u6587\u4ef6 text5.~1~ \u3002 $patch -b -V numbered < patchfile patching file text5 $ cat text5 1001 1002 1003a 1004 $ cat text5.~1~ 1001 1002 1003 \u8bd5\u8fd0\u884c\uff0c\u4e0d\u505a\u5b9e\u9645\u66f4\u6539\u3002 patch --dry-run < patchfile \u5bf9\u76ee\u5f55\u6253\u8865\u4e01\u3002 \u6267\u884c diff \u548c patch \u547d\u4ee4\u662f\u5728\u5f53\u524d\u7528\u6237 vagrant \u7684\u4e3b\u76ee\u5f55\u4e0b\uff0c\u7edd\u5bf9\u8def\u5f84\u662f /home/vagrant \u3002 diff \u547d\u4ee4\u4e2d\uff0c\u6e90\u76ee\u5f55\u662f /home/vagrant/dir1 \u3002\u76ee\u6807\u76ee\u5f55\u662f /home/vagrant/dir2 \u3002 -p3 \u662f\u544a\u8bc9 patch \u547d\u4ee4\u5ffd\u7565\u4e0a\u9762\u7edd\u5bf9\u8def\u5f84\u4e2d\u524d\u4e09\u4e2a\u659c\u6760 / \u3002 patch \u547d\u4ee4\u4e2d\u7528 diff \u7684\u76ee\u6807\u76ee\u5f55\u53bb\u8986\u76d6\u6e90\u76ee\u5f55\u3002\u4e92\u6362\u4f1a\u62a5\u9519\u3002 -R \uff1a\u64a4\u9500\u8865\u4e01\u3002 # file3\u548cfile4\u6709\u5185\u5bb9 $ tree ./dir1 ./dir1 \u251c\u2500\u2500 file1 \u251c\u2500\u2500 file2 \u251c\u2500\u2500 file3 \u2514\u2500\u2500 subdir1 \u2514\u2500\u2500 file4 \u90fd\u662f\u7a7a\u6587\u4ef6 $ tree ./dir2 ./dir2 \u251c\u2500\u2500 file1 \u251c\u2500\u2500 file2 \u251c\u2500\u2500 file3 \u2514\u2500\u2500 subdir1 \u2514\u2500\u2500 file4 $ diff -ruN /home/vagrant/dir1 /home/vagrant/dir2 > patchdir $ cat patchdir diff -ruN /home/vagrant/dir1/file3 /home/vagrant/dir2/file3 --- /home/vagrant/dir1/file3 2022 -12-07 08 :42:33.108418336 +0800 +++ /home/vagrant/dir2/file3 2022 -12-07 21 :25:48.156056360 +0800 @@ -1 +0,0 @@ -hello diff -ruN /home/vagrant/dir1/subdir1/file4 /home/vagrant/dir2/subdir1/file4 --- /home/vagrant/dir1/subdir1/file4 2022 -12-07 21 :15:09.689912160 +0800 +++ /home/vagrant/dir2/subdir1/file4 2022 -12-07 21 :26:55.405546177 +0800 @@ -1 +0,0 @@ -/home/vagrant/dir1/subdir1 # \u7528dir2\u7684\u5185\u5bb9\u8986\u76d6dir1\u7684\u5185\u5bb9 $ patch -p3 < patchdir patching file dir1/file3 patching file dir1/subdir1/file4 # \u73b0\u5728dir1\u76ee\u5f55\u4e0b\u7684\u5185\u5bb9\u5df2\u7ecf\u88abdir2\u76ee\u5f55\u8986\u76d6\u4e86\u3002file3\u548cfile4\u90fd\u662f\u7a7a\u6587\u4ef6 $ ll ./dir1 total 0 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :34 file1 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :35 file2 -rw-r--r--. 1 vagrant wheel 0 Dec 7 21 :40 file3 drwxr-xr-x. 1 vagrant wheel 10 Dec 7 21 :40 subdir1 $ ll ./dir1/subdir1 total 0 -rw-r--r--. 1 vagrant wheel 0 Dec 7 21 :40 file4 # \u64a4\u9500\u8865\u4e01\uff0cfile3\u548cfile4\u5df2\u7ecf\u6062\u590d\u4e3a\u539f\u6587\u4ef6 $ patch -R -p3 < patchdir patching file dir1/file3 patching file dir1/subdir1/file4 $ ll ./dir1 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :34 file1 -rw-r--r--. 1 vagrant wheel 0 Dec 7 08 :35 file2 -rw-r--r--. 1 vagrant wheel 6 Dec 7 21 :45 file3 drwxr-xr-x. 1 vagrant wheel 10 Dec 7 21 :45 subdir1 $ ll ./dir1/subdir1 -rw-r--r--. 1 vagrant wheel 27 Dec 7 21 :45 file4 # \u7528dir1\u7684\u5185\u5bb9\u8986\u76d6dir2\u7684\u5185\u5bb9\uff0c\u7cfb\u7edf\u62d2\u7edd\u3002 patch dir2 -p3 < patchdir File dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file dir2.rej File dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file dir2.rej $ patch /home/vagrant/dir2 -p3 < patchdir File /home/vagrant/dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file /home/vagrant/dir2.rej File /home/vagrant/dir2 is not a regular file -- refusing to patch 1 out of 1 hunk ignored -- saving rejects to file /home/vagrant/dir2.rej","title":"2.14.2.patch"},{"location":"linux/SRE/04-TextTools/#2143vimdiff","text":"\u547d\u4ee4 vimdiff \u76f8\u5f53\u4e8e vim -d \u3002 \u4e3e\u4f8b\uff1a vimdiff text1 text2","title":"2.14.3.vimdiff"},{"location":"linux/SRE/04-TextTools/#2144cmp","text":"\u547d\u4ee4 cmp \u67e5\u770b\u4e8c\u8fdb\u5236\u6587\u4ef6\u7684\u4e0d\u540c\u3002 $ cmp cp grep cp grep differ: byte 25 , line 1 $ cmp /usr/bin/ls /usr/bin/dir /usr/bin/ls /usr/bin/dir differ: byte 613 , line 1 # \u8df3\u8fc7\u524d735\u4e2a\u5b57\u8282\uff0c\u8f93\u51fa\u540e\u976230\u4e2a\u5b57\u8282\u5185\u5bb9 $ hexdump -s 735 -Cn 30 /usr/bin/ls 000002df 00 00 00 00 00 5d 00 00 00 50 00 00 00 68 00 00 | ..... ] ...P...h.. | 000002ef 00 6a 00 00 00 4f 00 00 00 00 00 00 00 1d | .j...O........ | 000002fd $ hexdump -s 735 -Cn 30 /usr/bin/dir 000002df 00 00 00 00 00 5d 00 00 00 50 00 00 00 68 00 00 | ..... ] ...P...h.. | 000002ef 00 6a 00 00 00 4f 00 00 00 00 00 00 00 1d | .j...O........ | 000002fd","title":"2.14.4.cmp"},{"location":"linux/SRE/05-RegExpress/","text":"\u7b2c\u4e94\u7ae0 \u6b63\u5219\u8868\u8fbe\u5f0f \u00b6 \u6b63\u5219\u8868\u8fbe\u5f0f\u5206\u4e24\u7c7b\uff1a \u57fa\u672c\u6b63\u5219\u8868\u8fbe\u5f0f\uff08Basic Regular Expression\uff0c \u53c8\u53ebBasic RegEx\uff0c\u7b80\u79f0BREs\uff09 \u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\uff08Extended Regular Expression\uff0c \u53c8\u53ebExtended RegEx\uff0c\u7b80\u79f0EREs\uff09 Perl\u6b63\u5219\u8868\u8fbe\u5f0f\uff08Perl Regular Expression\uff0c \u53c8\u53ebPerl RegEx \u7b80\u79f0PREs \u57fa\u672c\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u548c\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u533a\u522b\u5c31\u662f\u5143\u5b57\u7b26\u7684\u4e0d\u540c\u3002 5.1.\u57fa\u672c\u6b63\u5219\u8868\u8fbe\u5f0f\u7b26\u53f7 \u00b6 ^ \uff1a\u8868\u793a\u4ee5\u67d0\u4e2a\u5b57\u7b26\u5f00\u59cb $ \uff1a\u8868\u793a\u4ee5\u67d0\u4e2a\u5b57\u7b26\u7ed3\u5c3e . \uff1a\u8868\u793a\u5339\u914d\u4e00\u4e2a\u4e14\u53ea\u5339\u914d\u4e00\u4e2a\u5b57\u7b26 * \uff1a\u8868\u793a\u5339\u914d\u524d\u8fb9\u4e00\u4e2a\u5b57\u7b26\u51fa\u73b00\u6b21\u6216\u8005\u591a\u6b21 [] \uff1a\u8868\u793a\u5339\u914d\u62ec\u53f7\u5185\u7684\u591a\u4e2a\u5b57\u7b26\u4fe1\u606f,\u4e00\u4e2a\u4e00\u4e2a\u5339\u914d .* \uff1a\u8868\u793a\u5339\u914d\u6240\u6709\uff0c\u7a7a\u884c\u4e5f\u4f1a\u8fdb\u884c\u5339\u914d [^] \uff1a\u8868\u793a\u4e0d\u5339\u914d\u62ec\u53f7\u5185\u7684\u6bcf\u4e00\u4e2a\u5b57\u7b26 ^$ \uff1a\u8868\u793a\u5339\u914d\u7a7a\u884c\u4fe1\u606f \\ \uff1a\u5c06\u6709\u7279\u6b8a\u542b\u4e49\u7684\u5b57\u7b26\u8f6c\u4e49\u4e3a\u901a\u914d\u7b26 5.2.\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\u7b26\u53f7 \u00b6 + \uff1a\u8868\u793a\u524d\u4e00\u4e2a\u5b57\u7b26\u51fa\u73b0\u4e00\u6b21\u6216\u4e00\u6b21\u4ee5\u4e0a ? \uff1a\u8868\u793a\u524d\u4e00\u4e2a\u5b57\u7b26\u51fa\u73b00\u6b21\u6216\u8005\u4e00\u6b21\u4ee5\u4e0a | \uff1a\u8868\u793a\u6216\u8005\u7684\u5173\u7cfb,\u5339\u914d\u591a\u4e2a\u4fe1\u606f () \uff1a\u5339\u914d\u4e00\u4e2a\u6574\u4f53\u4fe1\u606f\uff0c\u4e5f\u53ef\u4ee5\u63a5\u540e\u9879\u5f15\u7528 {} \uff1a\u5b9a\u4e49\u524d\u8fb9\u5b57\u7b26\u51fa\u73b0\u51e0\u6b21 \u63d0\u793a\uff1a grep -E \u6216\u8005 egrep \u53ea\u662f\u8868\u793a\u6269\u5c55\u6b63\u5219\uff0c\u4e0d\u4ee3\u8868\u52a0\u4e86e\u5c31\u8868\u793a\u8f6c\u4e49\u4e86\u3002 \u5f53 grep \u4f7f\u7528\u6269\u5c55\u6b63\u5219\u7684\u7b26\u53f7\u65f6\u5019\u9700\u8981\u7528 \\ \u8f6c\u4e49\u4e3a\u901a\u914d\u7b26\u624d\u80fd\u4f7f\u7528\u3002 5.3.\u5b57\u7b26\u5339\u914d \u00b6 [:alpha:] \uff1a\u8868\u793a\u6240\u6709\u7684\u5b57\u6bcd\uff08\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff09\uff0c\u6548\u679c\u540c [a-z] [:digit:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u6570\u5b57\uff0c\u6548\u679c\u540c [0-9] [:xdigit:] \uff1a\u8868\u793a\u5341\u516d\u8fdb\u5236\u6570\u5b57 [:lower:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5c0f\u5199\u5b57\u6bcd [:upper:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5927\u5199\u5b57\u6bcd [:alnum:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5b57\u6bcd\u6216\u6570\u5b57 [:blank:] \uff1a\u8868\u793a\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u548c\u5236\u8868\u7b26\uff09 [:space:] \uff1a\u8868\u793a\u5305\u62ec\u7a7a\u683c\u3001\u5236\u8868\u7b26\uff08\u6c34\u5e73\u548c\u5782\u76f4\uff09\u3001\u6362\u884c\u7b26\u3001\u56de\u8f66\u7b26\u7b49\u5404\u79cd\u7c7b\u578b\u7684\u7a7a\u767d\uff0c\u6bd4 [:blank:] \u8303\u56f4\u66f4\u5e7f [:cntrl:] \uff1a\u8868\u793a\u4e0d\u53ef\u6253\u5370\u7684\u63a7\u5236\u5b57\u7b26\uff08\u9000\u683c\u3001\u5220\u9664\u3001\u8b66\u94c3\u7b49\uff09 [:graph:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u7684\u975e\u7a7a\u767d\u5b57\u7b26 [:print:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u5b57\u7b26 [:punct:] \uff1a\u8868\u793a\u6807\u70b9\u7b26\u53f7 5.4.\u4f4d\u7f6e\u6807\u8bb0 \u00b6 \u4f4d\u7f6e\u6807\u8bb0\u951a\u70b9\uff08position marker anchor\uff09\u662f\u6807\u8bc6\u5b57\u7b26\u4e32\u4f4d\u7f6e\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6b63\u5219\u8868\u8fbe\u5f0f\u6240\u5339\u914d\u7684\u5b57\u7b26\u53ef\u4ee5\u51fa\u73b0\u5728\u5b57\u7b26\u4e32\u4e2d\u4efb\u4f55\u4f4d\u7f6e\u3002 ^ \uff1a\u884c\u9996\u951a\u5b9a\uff0c\u6307\u5b9a\u4e86\u5339\u914d\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u6587\u672c\u5fc5\u987b\u8d77\u59cb\u4e8e\u5b57\u7b26\u4e32\u7684\u9996\u90e8\u3002 \u4f8b\u5982\uff1a ^tux \u80fd\u591f\u5339\u914d\u4ee5 tux \u8d77\u59cb\u7684\u884c $ \uff1a\u884c\u5c3e\u951a\u5b9a\uff0c\u6307\u5b9a\u4e86\u5339\u914d\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u6587\u672c\u5fc5\u987b\u7ed3\u675f\u4e8e\u76ee\u6807\u5b57\u7b26\u4e32\u7684\u5c3e\u90e8\u3002 \\< \u6216 \\b \uff1a\u8bcd\u9996\u951a\u5b9a\uff0c\u7528\u4e8e\u5355\u8bcd\u6a21\u5f0f\u5339\u914d\u5de6\u4fa7\u3002\uff08\u5355\u8bcd\u662f\u6709\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u4e0b\u5212\u7ebf\u7ec4\u6210\uff09 \\> \u6216 \\b \uff1a\u8bcd\u5c3e\u951a\u5b9a\uff0c\u7528\u4e8e\u5355\u8bcd\u6a21\u5f0f\u5339\u914d\u53f3\u4fa7\u3002\uff08\u5355\u8bcd\u662f\u6709\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u4e0b\u5212\u7ebf\u7ec4\u6210\uff09 ^PATTERN$ \uff1a\u7528\u6a21\u5f0fPATTERN\u5339\u914d\u6574\u884c\u3002 ^$ \uff1a\u5339\u914d\u7a7a\u884c\u3002 ^[[:space:]]*$ \uff1a\u5339\u914d\u7a7a\u767d\u884c\uff08\u6574\u884c\uff09\u3002 \\ \uff1a\u5339\u914d\u6574\u4e2a\u5355\u8bcd\u3002\uff08\u5355\u8bcd\u662f\u6709\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u4e0b\u5212\u7ebf\u7ec4\u6210\uff09 \u5173\u4e8e\u884c\u9996\u951a\u5b9a\u548c\u8bcd\u9996\u951a\u5b9a\uff0c\u5bf9\u6bd4\u4e0b\u9762\u4f8b\u5b50\u3002\u8bcd\u5c3e\u951a\u5b9a\u4e5f\u662f\u7c7b\u4f3c\u60c5\u51b5\u3002 ; \u548c - \u90fd\u88ab\u8ba4\u5b9a\u4e3a\u5355\u8bcd\u5206\u9694\u7b26\u3002 # \u7b26\u5408\u8bcd\u9996\u5339\u914d $ echo \"tux_01-tux02\" | grep '\\ mtu 1500 inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 inet6 fe80::20c:29ff:fea4:e17a prefixlen 64 scopeid 0x20 ether 00 :0c:29:a4:e1:7a txqueuelen 1000 ( Ethernet ) RX packets 7654 bytes 635932 ( 621 .0 KiB ) RX errors 0 dropped 1 overruns 0 frame 0 TX packets 1934 bytes 279649 ( 273 .0 KiB ) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 $ ifconfig eth0 | grep netmask | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' 192 .168.10.210 255 .255.255.0 192 .168.10.255 $ ifconfig eth0 | grep netmask | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' | head -n 1 192 .168.10.210 $ ifconfig eth0 | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' 192 .168.10.210 255 .255.255.0 192 .168.10.255 ifconfig eth0 | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' | head -n 1 192 .168.10.210 \u5339\u914d\u7a7a\u884c\u548c\u975e\u7a7a\u884c\uff1a grep '^$' /etc/profile grep -v '^$' /etc/profile \u5339\u914d\u975e\u7a7a\u884c\u548c\u975e#\u5f00\u5934\u7684\u884c\uff1a\uff08\u4e09\u79cd\u65b9\u6cd5\uff09 grep -v '^$' /etc/profile | grep -v '^#' grep -v '^$\\|#' /etc/profile grep '^[^$#]' /etc/profile \u6ce8\u610f\uff0c\u5982\u679c\u5199\u6210\u4e0b\u9762\u8fd9\u6837\uff0c\u5219\u4e0d\u4f1a\u8fc7\u6ee4\u6389\u7a7a\u884c\uff0c [$] \u4f1a\u88ab\u89c6\u4e3a $ \u7b26\u53f7\u3002 \u6240\u4ee5\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u5143\u5b57\u7b26\u653e\u5728\u4e2d\u62ec\u53f7 [] \u5185\u5c31\u88ab\u89c6\u4e3a\u666e\u901a\u5b57\u7b26\u3002 grep -v '^[$#]' /etc/profile 5.8.\u4e09\u5251\u5ba2 grep \u547d\u4ee4 \u00b6 \u683c\u5f0f\uff1a grep [OPTIONS] PATTERN [FILE...] grep [OPTIONS] -e PATTERN ... [FILE...] grep [OPTIONS] -f FILE ... [FILE...] \u53c2\u6570\uff1a -n \uff1a\u663e\u793a\u8fc7\u6ee4\u51fa\u6765\u7684\u6587\u4ef6\u5728\u6587\u4ef6\u5f53\u4e2d\u7684\u884c\u53f7 -c \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u884c\u6570 -o \uff1a\u53ea\u663e\u793a\u5339\u914d\u5230\u7684\u5185\u5bb9 -q \uff1a\u9759\u9ed8\u8f93\u51fa\uff08\u4e00\u822c\u7528\u5728shell\u811a\u672c\u5f53\u4e2d\uff0c\u901a\u8fc7 echo $? \u67e5\u770b\u547d\u4ee4\u6267\u884c\u7ed3\u679c\uff0c0\u8868\u793a\u6210\u529f\uff0c\u975e0\u8868\u793a\u5931\u8d25\uff09\uff09 -i \uff1a\u5ffd\u7565\u5927\u5c0f\u5199 -v \uff1a\u53cd\u5411\u67e5\u627e -w \uff1a\u5339\u914d\u67d0\u4e2a\u8bcd\u8bcd\uff1a\u5728Linux\u4e2d\uff0c\u8bcd\u4e3a\u4e00\u8fde\u4e32\u5b57\u6bcd\u3001\u6570\u5b57\u548c\u4e0b\u5212\u7ebf\u7ec4\u6210\u7684\u5b57\u7b26\u4e32 -E \uff1a\u4f7f\u7528\u6269\u5c55\u6b63\u5219 -R \uff1a\u9012\u5f52\u67e5\u8be2 -l \uff1a\u53ea\u6253\u5370\u6587\u4ef6\u8def\u5f84 \u6269\u5c55\u53c2\u6570\uff1a -A \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u6570\u636e\u7684\u540e\u51e0n\u884c -B \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u6570\u636e\u7684\u524d\u51e0n\u884c -C \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u6570\u636e\u7684\u524d\u540e\u5404\u51e0n\u884c \u793a\u4f8b\uff1a \u5339\u914d\u7528\u6237\uff1a grep root /etc/passwd root:x:0:0:root:/root:/bin/bash $ grep \"USER\" /etc/passwd $ grep \" $USER \" /etc/passwd vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash $ grep '$USER' /etc/passwd \u5339\u914d\u5173\u952e\u5b57\uff1a $ grep processor /proc/cpuinfo processor : 0 processor : 1 $ grep -o processor /proc/cpuinfo processor processor $ grep \"cpu family\" /proc/cpuinfo cpu family : 6 cpu family : 6 $ grep -o \"cpu family\" /proc/cpuinfo cpu family cpu family \u901a\u8fc7grep\u8fdb\u884c\u6587\u4ef6\u6bd4\u8f83\u3002 # \u6700\u540e\u4e00\u884c\u662f\u7a7a\u884c $ cat f1 a b 1 c # \u6700\u540e\u4e00\u884c\u662f\u7a7a\u884c $ cat f2 b e f c 1 2 # \u9ad8\u4eae\u663e\u793a\u76f8\u540c\u5185\u5bb9\u7684\u884c\uff0c\u5305\u542b\u6700\u540e\u4e00\u884c\u7a7a\u884c $ grep -f f1 f2 b e f c 1 2 # \u53ea\u663e\u793a\u76f8\u540c\u5185\u5bb9\u7684\u884c\uff0c\u5305\u542b\u6700\u540e\u4e00\u884c\u7a7a\u884c $ grep -wf f1 f2 b c 1 # \u53ea\u663e\u793a\u4e0d\u540c\u5185\u5bb9\u7684\u884c $ grep -wvf f1 f2 e f 2 \u63d0\u793a\uff1a grep -wvf f1 f2 \u6216\u8005 grep -w -v -f f1 f2 \u4e2d\uff0c -f \u53ea\u80fd\u4f5c\u4e3a\u6700\u540e\u4e00\u4e2a\u53c2\u6570\uff0c\u5426\u5219\u4f1a\u62a5\u9519\u3002 \u4f53\u4f1a\u57fa\u672c\u6b63\u5219\u548c\u6269\u5c55\u6b63\u5219\u7684\u5dee\u5f02\u3002 \u4f8b1\uff1a\u8f6c\u4e49\u3002 # \u4e0b\u9762\u51e0\u4e2a\u547d\u4ee4\u8fd4\u56de\u7684\u7ed3\u679c\u662f\u4e00\u6837\u7684\u3002 $ grep \"root\\|bash\" /etc/passwd $ grep -E \"root|bash\" /etc/passwd $ grep -e \"root\" -e \"bash\" /etc/passwd # \u4e0b\u9762\u7684\u547d\u4ee4\u6ca1\u6709\u5339\u914d\u7ed3\u679c\u8fd4\u56de\u3002 $ grep \"root|bash\" /etc/passwd \u4f8b2\uff1a\u4e0b\u97624\u4e2a\u547d\u4ee4\u8fd4\u56de\u540c\u6837\u7684\u7ed3\u679c\u3002 grep \"root\" /etc/passwd grep -E \"root\" /etc/passwd grep \"\\\" /etc/passwd grep -E \"\\\" /etc/passwd \u4f8b3\uff1a\u884c\u9996\u884c\u5c3e\u951a\u5b9a\u3002 $ grep \"^\\(.*\\)\\>.*\\<\\1 $ \" /etc/passwd $ grep -E \"^(.*)\\>.*\\<\\1 $ \" /etc/passwd $ egrep \"^(.*)\\>.*\\<\\1 $ \" /etc/passwd sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt \u4f8b4\uff1a\u4e09\u79cd\u65b9\u6cd5\u6c42\u548c\u8ba1\u7b97\uff0c\u8fd0\u7528 grep \uff0c cut \uff0c bc \u548c paste \u547d\u4ee4\u3002 $cat age Jason = 20 Tom = 30 Jack = 40 # \u65b9\u6cd51 $ cat age | cut -d \"=\" -f 2 | tr \"\\n\" + | grep -Eo \".*[0-9]\" | bc 90 # \u65b9\u6cd52 $ grep -Eo \"[0-9]+\" age | tr \"\\n\" + | grep -Eo \".*[0-9]\" | bc 90 # \u65b9\u6cd53 $ grep -Eo \"[0-9]+\" age | paste -s -d \"+\" | bc 90 5.9.\u4e09\u5251\u5ba2 sed \u547d\u4ee4 \u00b6 sed \u662fstream editor\u7684\u7f29\u5199\uff0c\u4e2d\u6587\u79f0\u4e4b\u4e3a\u201c\u6d41\u7f16\u8f91\u5668\u201d\u3002 sed \u547d\u4ee4\u662f\u4e00\u4e2a\u9762\u5411\u884c\u5904\u7406\u7684\u5de5\u5177\uff0c\u5b83\u4ee5\u201c\u884c\u201d\u4e3a\u5904\u7406\u5355\u4f4d\uff0c\u9488\u5bf9\u6bcf\u4e00\u884c\u8fdb\u884c\u5904\u7406\uff0c\u5904\u7406\u540e\u7684\u7ed3\u679c\u4f1a\u8f93\u51fa\u5230\u6807\u51c6\u8f93\u51fa STDOUT \uff0c\u4e0d\u4f1a\u5bf9\u8bfb\u53d6\u7684\u6587\u4ef6\u505a\u4efb\u4f55\u4fee\u6539\u3002 sed \u7684\u5de5\u4f5c\u539f\u7406\uff1a sed \u547d\u4ee4\u662f\u9762\u5411\u201c\u884c\u201d\u8fdb\u884c\u5904\u7406\u7684\uff0c\u6bcf\u4e00\u6b21\u5904\u7406\u4e00\u884c\u5185\u5bb9\u3002 \u5904\u7406\u65f6\uff0c sed \u4f1a\u628a\u8981\u5904\u7406\u7684\u884c\u5b58\u50a8\u5728\u7f13\u51b2\u533a\u4e2d\uff0c\u63a5\u7740\u7528 sed \u547d\u4ee4\u5904\u7406\u7f13\u51b2\u533a\u4e2d\u7684\u5185\u5bb9\uff0c\u5904\u7406\u5b8c\u6210\u540e\uff0c\u628a\u7f13\u51b2\u533a\u7684\u5185\u5bb9\u9001\u5f80\u5c4f\u5e55\u3002\u63a5\u7740\u5904\u7406\u4e0b\u4e00\u884c\uff0c\u8fd9\u6837\u4e0d\u65ad\u91cd\u590d\uff0c\u76f4\u5230\u6587\u4ef6\u672b\u5c3e\u3002\u8fd9\u4e2a\u7f13\u51b2\u533a\u88ab\u79f0\u4e3a\u201c \u6a21\u5f0f\u7a7a\u95f4 \u201d\uff08pattern space\uff09\u3002 \u4fdd\u6301\u7a7a\u95f4(hold space) sed \u7684\u4fdd\u6301\u7a7a\u95f4\u50cf\u4e00\u4e2a\u957f\u671f\u50a8\u5b58\uff0c \u53ef\u4ee5\u628a\u83b7\u53d6\u7684\u4fe1\u606f\u50a8\u5b58\u5230\u5176\u4e2d\uff0c\u5f85\u540e\u7eed\u8c03\u7528\u3002\u4e0d\u80fd\u76f4\u63a5\u5bf9\u4fdd\u6301\u7a7a\u95f4\u8fdb\u884c\u64cd\u4f5c\uff0c \u800c\u662f\u5c06\u4fdd\u6301\u7a7a\u95f4\u7684\u5185\u5bb9\u590d\u5236\u6216\u8005\u6dfb\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u8fdb\u884c\u64cd\u4f5c\u3002 \u975e\u4ea4\u4e92\u5f0f\u6279\u91cf\u4fee\u6539\u6587\u4ef6\u3002 sed \u547d\u4ee4\u683c\u5f0f\uff1a sed [ option ] command file option \u5e38\u7528\u9009\u9879\uff1a -n \uff1a\u4e0d\u8f93\u51fa\u6a21\u5f0fpattern\u7684\u5185\u5bb9\u5230\u5c4f\u5e55\uff08\u5373\u4e0d\u81ea\u52a8\u6253\u5370\uff09 -e \uff1a\u591a\u70b9\u7f16\u8f91 -f filename \uff1a\u4ece\u6307\u5b9a\u6587\u4ef6\u8bfb\u53d6\u7f16\u8f91\u811a\u672c -r \uff0c -E \uff1a\u4f7f\u7528\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f -i .bak \uff1a\u5907\u4efd\u6587\u4ef6\u5e76\u539f\u5904\u7f16\u8f91 -s \uff1a\u5c06\u591a\u4e2a\u6587\u4ef6\u89c6\u4e3a\u72ec\u7acb\u6587\u4ef6\uff0c\u800c\u4e0d\u662f\u5355\u4e2a\u8fde\u7eed\u7684\u957f\u6587\u4ef6\u6d41 -ir \uff1a \u4e0d\u652f\u6301 -i -r \uff1a \u652f\u6301 -ri \uff1a \u652f\u6301 -ni \uff1a \u5371\u9669\u9009\u9879\uff0c\u4f1a\u6e05\u7a7a\u6587\u4ef6 command \u90e8\u5206\u53ef\u4ee5\u5206\u4e3a\u4e24\u90e8\u5206\uff1a \u8303\u56f4\u8bbe\u5b9a\uff0c\u53ef\u4ee5\u91c7\u7528\u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u6765\u8868\u8fbe\uff1a \u6307\u5b9a\u884c\u6570\uff1a\u5982\uff1a 3,5 \u8868\u793a\u7b2c3\u30014\u30015\u884c 5,$ \u8868\u793a\u7b2c5\u884c\u81f3\u6587\u4ef6\u6700\u540e\u4e00\u884c \u6a21\u5f0f\u5339\u914d\uff1a\u5982\uff1a /^[^dD]/ \u8868\u793a\u5339\u914d\u884c\u9996\u4e0d\u662f\u4ee5 d \u6216 D \u5f00\u5934\u7684\u884c \u52a8\u4f5c\u5904\u7406\uff0c\u4e0b\u9762\u662f\u5e38\u7528\u7684\u52a8\u4f5c\uff1a a \uff1a\u65b0\u589e\uff0c a \u540e\u9762\u7684\u5b57\u4e32\u4f1a\u5728\u65b0\u7684\u4e00\u884c\u51fa\u73b0\uff08\u5f53\u524d\u884c\u7684\u4e0b\u4e00\u884c\uff09 i \uff1a\u63d2\u5165\uff0c i \u540e\u9762\u7684\u5b57\u4e32\u4f1a\u5728\u65b0\u7684\u4e00\u884c\u51fa\u73b0\uff08\u5f53\u524d\u884c\u7684\u4e0a\u4e00\u884c\uff09 r filename \uff1a\u8bfb\u53d6\u6307\u5b9a\u6587\u4ef6 fllename \u7684\u5185\u5bb9\uff0c\u8ffd\u52a0\u5230\u5f53\u524d\u884c\u7684\u4e0b\u4e00\u884c R filename \uff1a\u8bfb\u53d6\u6307\u5b9a\u6587\u4ef6 fllename \u7684\u4e00\u884c\uff0c\u8ffd\u52a0\u5230\u5f53\u524d\u884c\u7684\u4e0b\u4e00\u884c d \uff1a\u5220\u9664\u8be5\u884c p \uff1a\u6253\u5370\u8be5\u884c Ip \uff1a\u5ffd\u7565\u5927\u5c0f\u5199\u8f93\u51fa w filename \uff1a\u5199\u5165\u5230\u6307\u5b9a\u6587\u4ef6filename\u4e2d\u3002 s/regexp/replacement/ \uff1a\u53d6\u4ee3\uff0c\u7528replacement\u53d6\u4ee3\u6b63\u5219regexp\u5339\u914d\u5230\u7684\u5185\u5bb9 = \uff1a\u4e3a\u6a21\u5f0fpattern\u4e2d\u7684\u5339\u914d\u884c\u6253\u5370\u884c\u53f7 ! \uff1a\u4e3a\u6a21\u5f0fpattern\u4e2d\u7684\u5339\u914d\u884c\u53d6\u53cd\u64cd\u4f5c q \uff1a\u7ed3\u675f\u6216\u9000\u51fased \u521b\u5efa\u4e00\u4e2a testfile \u6587\u4ef6\u3002 $ cat < testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob Tesetfile Wiki EOF \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u7b2c\u4e8c\u884c\uff0c\u5e76\u8f93\u51fa\uff08\u5305\u542b\u5339\u914d\u7b2c\u4e8c\u884c\u548c\u8f93\u51fa\u7b2c\u4e8c\u884c\uff09\u3002 # nl testfile | sed '2p' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u7b2c\u4e8c\u884c\uff0c\u4e0d\u8f93\u51fa\u3002 # nl testfile | sed -n '2p' 2 Linux is a free unix-type opterating system. \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u6700\u540e\u4e00\u884c\u3002 $ nl testfile | sed -n '$p' 9 Wiki \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u5012\u6570\u7b2c\u4e8c\u884c\u3002 # sed -n \"$(echo $[`cat testfile | wc -l`-1])p\" testfile Tesetfile \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u7b2c2\uff5e3\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\u3002 $ nl testfile | sed -n '2,3p' 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! \u5c06 testfile \u7684\u5185\u5bb9\u4ece\u7b2c2\u884c\u5f00\u59cb\uff0c\u5411\u540e\u8f93\u51fa\u989d\u5916\u76843\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\u3002 $ nl testfile | sed -n '2,+3p' 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test 5 Google \u5c06 testfile \u7684\u5185\u5bb9\u4ece\u7b2c2\u884c\u5f00\u59cb\uff0c\u5411\u540e\u4ee52\u4e3a\u6b65\u8fdb\u5355\u4f4d\u8f93\u51fa\u6240\u6709\u5339\u914d\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff08\u5373\uff0c\u4ece\u7b2c2\u884c\u5f00\u59cb\u8f93\u51fa\u5076\u6570\u884c\uff09\u3002 nl testfile | sed -n '2~2p' 2 Linux is a free unix-type opterating system. 4 Linux test 6 Taobao 8 Tesetfile \u5c06 testfile \u7684\u5185\u5bb9\u4ece\u7b2c2\u884c\u5f00\u59cb\uff0c\u5411\u540e\u4ee52\u4e3a\u6b65\u8fdb\u5355\u4f4d\u5220\u9664\u6240\u6709\u5339\u914d\u884c\uff0c\u8f93\u51fa\u5269\u4f59\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff08\u5373\uff0c\u4ece\u7b2c2\u884c\u5f00\u59cb\u5220\u9664\u5076\u6570\u884c\uff0c\u8f93\u51fa\u5947\u6570\u884c\uff09\u3002 $ nl testfile | sed '2~2d' 1 HELLO LINUX! 3 This is a linux testfile! 5 Google 7 Banbooob 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u8f93\u51fa\uff0c\u5220\u9664\u7b2c2\u884c\u548c\u7b2c5\u884c\uff0c\u5e76\u6253\u5370\u884c\u53f7\u3002 $ nl testfile | sed -e '2d' -e '5d' $ nl testfile | sed -e '2d;5d' $ nl testfile | sed '2d;5d' 1 HELLO LINUX! 3 This is a linux testfile! 4 Linux test 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u8f93\u51fa\uff0c\u8f93\u51fa\u533a\u95f4\u662f\u4ece\u884c\u9996 L \u7684\u884c\u5230\u884c\u9996 G \u7684\u884c\u7ed3\u675f\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 \u5982\u679c\u884c\u9996\u5339\u914d\u4e0d\u5230\uff0c\u5219\u65e0\u7ed3\u679c\u8f93\u51fa\uff1b\u5982\u679c\u884c\u5c3e\u5339\u914d\u4e0d\u5230\uff0c\u5219\u8f93\u51fa\u5230\u6587\u4ef6\u7ed3\u675f\u3002 $ sed -n '/^L/,/^G/p' testfile Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google \u5c06 testfile \u7684\u5185\u5bb9\u8f93\u51fa\uff0c\u4e14\u5728\u7b2c6\u884c\u540e\u52a0\u4e0a I love Linux \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -e '6a I love Linux' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao I love Linux Banbooob Tesetfile Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5728\u7b2c6\u884c\u540e\u6dfb\u52a0 I love Linux \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '6a I love Linux' $ nl testfile | sed '6a\\I love Linux' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao I love Linux 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5728\u7b2c3\u884c\u524d\u6dfb\u52a0 I am a journer learner \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '3i\\I am a journer learner' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. I am a journer learner 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5728\u7b2c3\u884c\u524d\u6dfb\u52a0\u4e09\u884c\u5185\u5bb9 Add line 1 \uff0c Add line 2 \uff0c Add line 3 \u3002\u7528\u7b26\u5408 \\ \u8fdb\u884c\u6362\u884c\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '3i\\Add line 1 \\ Add line 2 \\ Add line 3' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. Add line 1 Add line 2 Add line 3 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5c06\u7b2c2-5\u884c\u7684\u5185\u5bb9\u53d6\u4ee3\u6210\u4e3a replaced \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '2,5c\\replaced' $ nl testfile | sed '2,5c replaced' $ nl testfile | sed '2,5creplaced' 1 HELLO LINUX! replaced 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5220\u9664\u7b2c2~5\u884c\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '2,5d' 1 HELLO LINUX! 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5220\u9664\u7b2c5\u884c\u5230\u6700\u540e\u4e00\u884c\u3002 $ nl testfile | sed '5,$d' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u4e2d\u5305\u542b\u5173\u952e\u5b57 linux \u7684\u884c\u3002 $ sed -n '/linux/p' testfile This is a linux testfile! \u5339\u914d\u5b9a\u4f4d\u547d\u4ee4 df \u8f93\u51fa\u4e2d\u4ee5 /dev/sd \u5173\u952e\u5b57\u5f00\u5934\u7684\u884c\u3002\uff08\u9700\u8981\u8f6c\u4e49\u7b26 \\ \uff09 $ df | sed -n '/^\\/dev\\/sd/p' /dev/sda2 102750208 7077280 92055312 8 % / /dev/sda2 102750208 7077280 92055312 8 % /.snapshots /dev/sda2 102750208 7077280 92055312 8 % /home /dev/sda2 102750208 7077280 92055312 8 % /opt /dev/sda2 102750208 7077280 92055312 8 % /root /dev/sda2 102750208 7077280 92055312 8 % /boot/grub2/x86_64-efi /dev/sda2 102750208 7077280 92055312 8 % /boot/grub2/i386-pc /dev/sda2 102750208 7077280 92055312 8 % /srv /dev/sda2 102750208 7077280 92055312 8 % /tmp /dev/sda2 102750208 7077280 92055312 8 % /usr/local /dev/sda2 102750208 7077280 92055312 8 % /var \u5339\u914d\u5b9a\u4f4d\u547d\u4ee4 df \u8f93\u51fa\u4e2d\u4e0d\u4ee5 /dev/sd \u5173\u952e\u5b57\u5f00\u5934\u7684\u884c\u3002\u901a\u8fc7 !p \u8fdb\u884c\u6c42\u53cd\u8f93\u51fa\u3002 $ df | sed -n '/^\\/dev\\/sd/!p' Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 4096 0 4096 0 % /dev tmpfs 1971208 0 1971208 0 % /dev/shm tmpfs 788484 9612 778872 2 % /run tmpfs 4096 0 4096 0 % /sys/fs/cgroup tmpfs 394240 0 394240 0 % /run/user/1000 \u5339\u914d\u5b9a\u4f4d\u547d\u4ee4 df \u8f93\u51fa\u4e2d\u4e0d\u4ee5 /dev/sd \u548c tmp \u5173\u952e\u5b57\u5f00\u5934\u7684\u884c\u3002 $ df | sed '/^\\/dev\\/sd/d;/^tmp/d' Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 4096 0 4096 0 % /dev $ df | grep -Ev '^\\/dev\\/sd|^tmp' Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 4096 0 4096 0 % /dev \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b oo \u5173\u952e\u5b57\u7684\u884c\u5e76\u5339\u914d\u8f93\u51fa\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -n '/ooo/p' testfile Banbooob $ sed -n '/oo/p' testfile Google Banbooob \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b oo \u5173\u952e\u5b57\u7684\u884c\u5e76\u5220\u9664\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed '/oo/d' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Taobao Tesetfile Wiki \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b oo \u7684\u884c\uff0c\u628a oo \u66ff\u6362\u4e3a kk \uff0c\u518d\u8f93\u51fa\u8fd9\u884c\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -n '/oo/{s/oo/kk/;p;q}' testfile $ sed -ne '/oo/{s/oo/kk/;p;q}' testfile Gkkgle \u5c06 testfile \u7684\u6bcf\u884c\u4e2d\u7b2c\u4e00\u6b21\u51fa\u73b0 ao \u7684\u66ff\u6362\u6210 HH \u3002 $ sed 's/ao/HH/' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbao Banbooob Tesetfile Wiki \u4e0b\u9762\u662f\u628a testfile \u7684\u5339\u914d\u5230 ao \u7684\u884c\u66ff\u6362\u6210 HH \u3002 sed '/ao/cHH' testfile HELLO LINUX! SUSE This is a linux testfile! SUSE Google Taobao Banbooob Tesetfile Wiki \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b ao \u7684\u5168\u90e8\u66ff\u6362\u6210 HH \u3002 g \u8868\u793a\u5168\u5c40\u5339\u914d\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -e 's/ao/HH/g' testfile $ sed 's/ao/HH/g' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbHH Banbooob Tesetfile Wiki \u5728\u6587\u4ef6 /etc/passwd \u4e2d\u67e5\u627e\u5339\u914d\u6240\u6709\u7b26\u5408 r \u5f00\u5934 t \u7ed3\u5c3e\u4e14\u4e2d\u95f4\u542b\u4efb\u610f\u4e24\u4e2a\u5b57\u7b26\u7684\u884c\uff0c\u5e76\u5728 t \u5b57\u6bcd\u540e\u6dfb\u52a0 er \u3002 $ sed -nr 's/r..t/&er/gp' /etc/passwd rooter:x:0:0:rooter:/rooter:/bin/bash lp:x:493:487:Printering daemon:/var/spool/lpd:/usr/sbin/nologin tftp:x:487:474:TFTP account:/srv/terftpboot:/bin/false vagranter:x:1000:478:vagranter:/home/vagranter:/bin/bash tester1:x:600:1530: \"Test User1,terestuser1@abc.com\" :/home/tester1:/bin/bash \u5c06\u4e0a\u8ff0\u7ed3\u679c\u548c\u539f\u59cb\u5185\u5bb9\u8fdb\u884c\u5bf9\u6bd4\uff0c\u80fd\u66f4\u597d\u7684\u7406\u89e3 s/r..t/&er \u7684\u64cd\u4f5c\u3002 rooter:x:0:0:rooter:/rooter:/bin/bash root:x:0:0:root:/root:/bin/bash lp:x:493:487:Printering daemon:/var/spool/lpd:/usr/sbin/nologin lp:x:493:487:Printing daemon:/var/spool/lpd:/usr/sbin/nologin tftp:x:487:474:TFTP account:/srv/terftpboot:/bin/false tftp:x:487:474:TFTP account:/srv/tftpboot:/bin/false vagranter:x:1000:478:vagranter:/home/vagranter:/bin/bash vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash tester1:x:600:1530: \"Test User1,terestuser1@abc.com\" :/home/tester1:/bin/bash tester1:x:600:1530: \"Test User1,testuser1@abc.com\" :/home/tester1:/bin/bash \u4f53\u4f1a & \u7684\u4f4d\u7f6e\u4e0d\u540c\u7684\u4e0d\u540c\u542b\u4e49\u3002 # \u9644\u52a0\u5728root\u5355\u8bcd\u540e $ sed -n 's/root/&superman/p' /etc/passwd rootsuperman:x:0:0:root:/root:/bin/bash # \u9644\u52a0\u5728root\u5355\u8bcd\u524d $ sed -n 's/root/superman&/p' /etc/passwd supermanroot:x:0:0:root:/root:/bin/bash \u4f7f\u7528\u53c2\u6570 -i \u8fdb\u884c\u6e90\u6587\u4ef6\u4fee\u6539\u3002 $ sed -i 's/ao/HH/' testfile $ cat testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbao Banbooob Tesetfile Wiki \u6e90\u6587\u4ef6\u4fee\u6539\u524d\uff0c\u5907\u4efd\u5728\u65b0\u6587\u4ef6 testfile.new \u3002 $ sed -i.new 's/ao/HH/' testfile $ cat testfile.new HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob Tesetfile Wiki $ cat testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbao Banbooob Tesetfile Wiki \u8303\u4f8b\uff1a\u9664\u6307\u5b9a\u6587\u4ef6\u5916\uff0c\u5176\u4f59\u90fd\u5220\u9664\u3002 $ touch { 1 ..9 } file.txt $ ls 1file.txt 2file.txt 3file.txt 4file.txt 5file.txt 6file.txt 7file.txt 8file.txt 9file.txt $ ls | grep -E '(3|5|7)file\\.txt' 3file.txt 5file.txt 7file.txt $ ls | grep -Ev '(3|5|7)file\\.txt' 1file.txt 2file.txt 4file.txt 6file.txt 8file.txt 9file.txt \u4e0b\u9762\u56db\u79cd\u65b9\u6cd5\u5b9e\u73b0\u540c\u6837\u7684\u529f\u80fd $ rm ` ls | grep -Ev '(3|5|7)file\\.txt' ` $ ls | sed -n '/^[357]file.txt/!p' | xargs rm $ ls | grep -Ev '(3|5|7)file\\.txt' | sed -n 's/.*/rm &/p' | bash $ ls | grep -Ev '(3|5|7)file\\.txt' | sed -En 's/(.*)/rm &/p' | bash $ ls | grep -Ev '(3|5|7)file\\.txt' | sed -En 's/(.*)/rm \\1/p' | bash $ ls 3file.txt 5file.txt 7file.txt \u540e\u5411\u5f15\u7528 \\0 \\1 \\2 \u7b49\u3002 $ $echo 123456789 | sed -nE 's/(123)(456)(789)/\\1/p' 123 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\2/p' 456 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\3/p' 789 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\3\\1\\2/p' 789123456 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\1xyz\\2/p' 123xyz456 \u8303\u4f8b\uff1a\u83b7\u53d6\u5206\u533a\u5229\u7528\u7387 $ df | sed -En '/^\\/dev\\/sd/p' /dev/sda2 102750208 7079236 92053692 8 % / /dev/sda2 102750208 7079236 92053692 8 % /.snapshots /dev/sda2 102750208 7079236 92053692 8 % /boot/grub2/i386-pc /dev/sda2 102750208 7079236 92053692 8 % /boot/grub2/x86_64-efi /dev/sda2 102750208 7079236 92053692 8 % /home /dev/sda2 102750208 7079236 92053692 8 % /opt /dev/sda2 102750208 7079236 92053692 8 % /root /dev/sda2 102750208 7079236 92053692 8 % /srv /dev/sda2 102750208 7079236 92053692 8 % /usr/local /dev/sda2 102750208 7079236 92053692 8 % /tmp /dev/sda2 102750208 7079236 92053692 8 % /var $ df | sed -En '/^\\/dev\\/sd/s@.*([0-9]+)%.*@\\1@p' $ df | sed -En '/^\\/dev\\/sd/s#.*([0-9]+)%.*#\\1#p' # df | sed -En '/^\\/dev\\/sd/s/.*([0-9]+)%.*/\\1/p' 8 8 8 8 8 8 8 8 8 8 8 \u4f53\u4f1a\u4e0b\u9762\u7a7a\u683c\u548c\u62ec\u5f27\u5e26\u6765\u7684\u4e0d\u540c\u3002 $ df | sed -En '/^\\/dev\\/sd/s# .*([0-9]+)%.*# \\1#p' /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 $ df | sed -En '/^\\/dev\\/sd/s#( .*)([0-9]+)%.*# \\1#p' /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 $ df | sed -En '/^\\/dev\\/sd/s#( .*)([0-9]+)%.*# \\2#p' /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 \u8303\u4f8b\uff1a\u53d6\u5f97\u5f53\u524dIP\u5730\u5740\u3002 $ ifconfig eth0 eth0: flags = 4163 mtu 1500 inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 inet6 fe80::20c:29ff:fea4:e17a prefixlen 64 scopeid 0x20 ether 00 :0c:29:a4:e1:7a txqueuelen 1000 ( Ethernet ) RX packets 22923 bytes 1658298 ( 1 .5 MiB ) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3763 bytes 442641 ( 432 .2 KiB ) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 $ ip addr show eth0 2 : eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00 :0c:29:a4:e1:7a brd ff:ff:ff:ff:ff:ff altname enp2s1 altname ens33 inet 192 .168.10.210/24 brd 192 .168.10.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::20c:29ff:fea4:e17a/64 scope link valid_lft forever preferred_lft forever $ ifconfig eth0 | sed -En '2s/[^0-9]+([0-9.]+).*/\\1/p' $ ifconfig eth0 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*/\\1/p' $ ifconfig eth0 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*$/\\1/p' $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.*//p' $ ifconfig eth0 | sed -n '2s/^.*inet //;s/ netmask.*//p' $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\2/p' 192 .168.10.210 192 .168.10.210 192 .168.10.210 \u4f7f\u7528 \\0 \u8f93\u51fa\u5168\u90e8\u53d8\u91cf\u3002 $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\0/p' inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\1/p' inet $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\2/p' 192 .168.10.210 $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\3/p' netmask 255 .255.255.0 broadcast 192 .168.10.255 \u5bf9\u6bd4\u4e0b\u9762\u4e24\u4e2a\u6307\u4ee4\u7684\u5339\u914d\u5dee\u5f02\u3002 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/ netmask.*//p' 192 .168.10.210 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.* //p' 192 .168.10.210 192 .168.10.255 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask .*//p' 192 .168.10.210 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.*//p' 192 .168.10.210 \u8303\u4f8b\uff1a\u53d6\u57fa\u540d\u548c\u76ee\u5f55\u540d\u3002 \uff08 /etc/sysconfig/network-scripts/ \u76ee\u5f55\u5728Rocky9\u4e2d\u9ed8\u8ba4\u5df2\u521b\u5efa\uff0c\u5728openSUSE\u548cUbuntu\u4e2d\u6ca1\u6709\uff09 # \u53d6\u76ee\u5f55\u540d $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's#(^/.*/)([^/]+/?)#\\1#' $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\1/' /etc/sysconfig/ # \u53d6\u57fa\u540d $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's#(^/.*/)([^/]+/?)#\\2#' $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\2/' network-scripts/ # \u53d6\u76ee\u5f55\u540d $ echo \"/etc/sysconfig/network-scripts/dummyfile\" | sed -E 's#(^/.*/)([^/]+/?)#\\1#' $ echo \"/etc/sysconfig/network-scripts/dummyfille\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\1/' /etc/sysconfig/network-scripts/ # \u53d6\u57fa\u540d $ echo \"/etc/sysconfig/network-scripts/dummyfile\" | sed -E 's#(^/.*/)([^/]+/?)#\\2#' $ echo \"/etc/sysconfig/network-scripts/dummyfille\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\2/' dummyfille \u8303\u4f8b\uff1a\u53d6\u6587\u4ef6\u540d\u548c\u6587\u4ef6\u6269\u5c55\u540d $ echo 1_.file.tar.gz | sed -En 's/(.*)\\.([^.]+)$/\\1/p' $ echo 1_.file.tar.gz | sed -En 's@(.*)\\.([^.]+)$@\\1@p' 1_.file.tar $ echo 1_.file.tar.gz | sed -En 's/(.*)\\.([^.]+)$/\\2/p' $ echo 1_.file.tar.gz | sed -En 's@(.*)\\.([^.]+)$@\\2@p' gz $ echo 1_.file.tar.gz | grep -Eo '.*\\.' 1_.file.tar. $ echo 1_.file.tar.gz | grep -Eo '[^.]+$' gz \u8303\u4f8b\uff1a\u5c06\u975e # \u5f00\u5934\u7684\u884c\u6dfb\u52a0 # $ cat < testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob #Tesetfile #Wiki EOF $ sed -En 's/^[^#]/#&/p' testfile $ sed -En 's/^[^#](.*)/#\\1/p' testfile #HELLO LINUX! #Linux is a free unix-type opterating system. #This is a linux testfile! #Linux test #Google #Taobao #Banbooob \u8303\u4f8b\uff1a\u5c06 # \u5f00\u5934\u7684\u884c\u5220\u9664 # $ cat < testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob #Tesetfile #Wiki EOF $ sed -Ei.bak '/^#/s/^#//' testfile $ cat testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob Tesetfile Wiki sed \u4fdd\u6301\u7a7a\u95f4\uff08hold space\uff09\u7684\u4f8b\u5b50\uff1a d \uff1a\u5220\u9664pattern space\u7684\u5185\u5bb9\uff0c\u5f00\u59cb\u4e0b\u4e00\u4e2a\u5faa\u73af\u3002 D \uff1a\u5982\u679c\u6a21\u5f0f\u7a7a\u95f4\u4fdd\u62a4\u6362\u884c\u7b26\uff0c\u5219\u5220\u9664\u76f4\u5230\u7b2c\u4e00\u4e2a\u6362\u884c\u7b26\u5230\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u7684\u6587\u672c\uff0c\u5e76\u4e0d\u8bfb\u53d6\u65b0\u7684\u8f93\u5165\u884c\uff0c\u800c\u4f7f\u7528\u5408\u6210\u7684\u6a21\u5f0f\u7a7a\u95f4\u91cd\u65b0\u542f\u52a8\u5faa\u73af\u3002\u5982\u679c\u6a21\u5f0f\u7a7a\u95f4\u4e0d\u5305\u542b\u6362\u884c\u7b26\uff0c\u5219\u7c7b\u4f3c d \u547d\u4ee4\u542f\u52a8\u6b63\u5e38\u7684\u65b0\u5faa\u73af\u3002 h \u3001 H \uff1a\u590d\u5236/\u8ffd\u52a0\u6a21\u5f0f\u7a7a\u95f4\u7684\u5185\u5bb9\u5230\u4fdd\u6301\u7a7a\u95f4\u3002 g \u3001 G \uff1a\u590d\u5236/\u8ffd\u52a0\u4fdd\u6301\u7a7a\u95f4\u7684\u5185\u5bb9\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002 n \u3001 N \uff1a\u590d\u5236/\u8ffd\u52a0\u5339\u914d\u5230\u7684\u4e0b\u4e00\u884c\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002 p\uff1a\u6253\u5370\u5f53\u524d\u6a21\u5f0f\u7a7a\u95f4\u5185\u5bb9\u3002 P\uff1a\u6253\u5370\u6a21\u5f0f\u7a7a\u95f4\u5f00\u5934\u81f3 \\n \u7684\u5185\u5bb9\uff0c\u5e76\u8ffd\u52a0\u5230\u9ed8\u8ba4\u8f93\u51fa\u4e4b\u524d\u3002 x \uff1a\u4ea4\u6362\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u7684\u5185\u5bb9. \u4e3e\u4f8b\u89e3\u8bfb1\uff1a seq 10 \u547d\u4ee4\u8f93\u51fa1\uff5e10\u4e2a\u6570\u5b57\uff0c\u6bcf\u4e2a\u6570\u5b57\u4e00\u884c\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e00\u884c 1 \u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u56e0\u4e3a\u53c2\u6570 -n \uff0c\u6240\u4ee5\u8bfb\u53d6\u5230\u7684 1 \u4e0d\u6253\u5370\u5230\u5c4f\u5e55\u3002 \u6267\u884c n \u547d\u4ee4\uff0c\u5373\u8bfb\u53d6\u5339\u914d\u5230\u7684\u4e0b\u4e00\u884c\u5230\u6a21\u5f0f\u7a7a\u95f4\uff0c\u5373\u628a\u7b2c\u4e8c\u884c\u7684 2 \u8bfb\u53d6\u5e76\u8986\u76d6\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002 \u6267\u884c p \u547d\u4ee4\uff0c\u628a 2 \u8f93\u51fa\u5230\u5c4f\u5e55\u3002 \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8bfb\u53d6\u7b2c\u4e09\u884c\u7684 3 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff0c\u6267\u884c n \u547d\u4ee4\uff0c\u5c06\u7b2c\u56db\u884c\u7684 4 \u8bfb\u53d6\u5e76\u8986\u76d6\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u6267\u884c p \u547d\u4ee4\uff0c\u8f93\u51fa 4 \u5230\u5c4f\u5e55\u3002 \u4ee5\u6b64\u7c7b\u63a8\u3002 $ seq 10 | sed -n 'n;p' 2 4 6 8 10 seq 10 | sed 'n;p' 1 2 2 3 4 4 5 6 6 7 8 8 9 10 10 \u4e3e\u4f8b\u89e3\u8bfb2\uff1a seq 10 \u547d\u4ee4\u8f93\u51fa1\uff5e10\u4e2a\u6570\u5b57\uff0c\u6bcf\u4e2a\u6570\u5b57\u4e00\u884c\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e00\u884c\u5230 1 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c\u547d\u4ee4 N \uff0c\u5373\u8bfb\u53d6\u4e0b\u4e00\u884c\uff0c\u5373\u7b2c\u4e8c\u884c\u7684 2 \uff0c\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u6240\u4ee5\u5f53\u524d\u6a21\u5f0f\u7a7a\u95f4\u6709 1 \u548c 2 \u8fd92\u884c\u8bb0\u5f55\u3002 \u6267\u884c s/\\n// \uff0c\u628a\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u7684\u7b2c\u4e00\u884c\u7684 1 \u540e\u9762\u7684 \\n \u66ff\u6362\u4e3a\u7a7a\uff0c\u5373\uff0c\u539f\u6765\u6a21\u5f0f\u7a7a\u95f4\u7684\u4e24\u884c 1 \u548c 2 \u73b0\u5728\u5408\u5e76\u4e3a\u4e00\u884c\uff0c\u5373 12 \u3002 \u8bfb\u53d6\u7b2c\u4e09\u884c\u7684 3 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c\u547d\u4ee4 N \uff0c\u5373\u8bfb\u53d6\u4e0b\u4e00\u884c\uff0c\u5373\u7b2c\u56db\u884c\u7684 4 \uff0c\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u6240\u4ee5\u5f53\u524d\u6a21\u5f0f\u7a7a\u95f4\u6709 3 \u548c 4 \u8fd92\u884c\u8bb0\u5f55\u3002 \u6267\u884c s/\\n// \uff0c\u628a\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u7684\u7b2c\u4e00\u884c 3 \u540e\u9762\u7684 \\n \u66ff\u6362\u4e3a\u7a7a\uff0c\u5373\uff0c\u539f\u6765\u6a21\u5f0f\u7a7a\u95f4\u7684\u4e24\u884c 3 \u548c 4 \u73b0\u5728\u5408\u5e76\u4e3a\u4e00\u884c\uff0c\u5373 34 \u3002 \u4ee5\u6b64\u7c7b\u63a8\u3002 $ seq 10 | sed 'N;s/\\n//' 12 34 56 78 910 \u4e3e\u4f8b\u89e3\u8bfb3\uff1a seq 10 \u547d\u4ee4\u8f93\u51fa1\uff5e10\u4e2a\u6570\u5b57\uff0c\u6bcf\u4e2a\u6570\u5b57\u4e00\u884c\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e00\u884c\u5230 1 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c !G \uff0c\u5373\u5bf9\u7b2c\u4e00\u884c\u7684 1 \u4e0d\u6267\u884c G \u547d\u4ee4\u3002 \u6267\u884c h \u547d\u4ee4\uff0c\u5373\u628a 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u8986\u76d6\u81f3\u4fdd\u6301\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u90fd\u5b58\u6709 1 \u3002 \u6267\u884c $!d \uff0c\u5373\u4e0d\u662f\u6700\u540e\u4e00\u884c\u5c31\u4ece\u6a21\u5f0f\u7a7a\u95f4\u5220\u9664\uff0c\u6240\u4ee5\u628a 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u5220\u9664\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e8c\u884c\u5230 2 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c !G \uff0c\u5373\u5bf9\u7b2c\u4e8c\u884c\u7684 2 \u6267\u884c G \u547d\u4ee4\uff0c\u628a 1 \u4ece\u4fdd\u6301\u7a7a\u95f4\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u5b58\u6709 1 \uff0c\u6a21\u5f0f\u7a7a\u95f4\u5b58\u6709 2 \u548c 1 \u3002 \u6267\u884c h \u547d\u4ee4\uff0c\u5373\u628a 2 \u548c 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u8986\u76d6\u81f3\u4fdd\u6301\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u90fd\u5b58\u6709 2 \u548c 1 \u3002 \u6267\u884c $!d \uff0c\u5373\u4e0d\u662f\u6700\u540e\u4e00\u884c\u5c31\u4ece\u6a21\u5f0f\u7a7a\u95f4\u5220\u9664\uff0c\u6240\u4ee5\u628a 2 \u548c 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u5220\u9664\u3002 \u4ee5\u6b64\u7c7b\u63a8\uff0c\u76f4\u81f3\u8bfb\u53d6\u6700\u540e\u4e00\u884c10\u3002\u6b64\u65f6\uff0c\u6a21\u5f0f\u7a7a\u95f4\u662f 10 \uff0c\u4fdd\u6301\u7a7a\u95f4\u5b58\u6709 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002 \u6267\u884c !G \uff0c\u5373\u5bf9\u6700\u540e\u4e00\u884c\u7684 10 \u6267\u884c G \u547d\u4ee4\uff0c\u628a 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u4ece\u4fdd\u6301\u7a7a\u95f4\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u5b58\u6709 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002\uff0c\u6a21\u5f0f\u7a7a\u95f4\u5b58\u6709 10 \u3001 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002 \u6267\u884c h \u547d\u4ee4\uff0c\u5373\u628a 10 \u3001 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u8986\u76d6\u81f3\u4fdd\u6301\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u90fd\u5b58\u6709 10 \u3001 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002 \u6267\u884c $!d \uff0c\u5f53\u524d\u662f\u6700\u540e\u4e00\u884c\uff0c\u6240\u4ee5\u4e0d\u4ece\u6a21\u5f0f\u7a7a\u95f4\u5220\u9664\u5f53\u524d\u5185\u5bb9\u3002 \u8f93\u51fa\u6a21\u5f0f\u7a7a\u95f4\u5185\u5bb9\u81f3\u5c4f\u5e55\u3002\u537310\uff5e1\u3002 $ seq 10 | sed '1!G;h;$!d' 10 9 8 7 6 5 4 3 2 1 \u5176\u4ed6\u4e00\u4e9b\u4f8b\u5b50\uff1a $ seq 10 | sed -n '/3/{g;1!p;};h' 2 $ seq 10 | sed -nr '/3/{n;p}' 4 $ seq 10 | sed 'N;D' 10 $ seq 10 | sed '3h;9G;9!d' 9 3 $ seq 10 | sed '$!N;$!D' 9 10 $ seq 10 | sed '$!d' 10 $ seq 10 | sed 'G' 1 2 3 4 5 6 7 8 9 10 $ seq 10 | sed 'g' $ seq 10 | sed '/^$/d;G' 1 2 3 4 5 6 7 8 9 10 $ seq 10 | sed 'n;d' 1 3 5 7 9 $ seq 10 | sed -n '1!G;h;$p' 10 9 8 7 6 5 4 3 2 1 5.10.\u4e09\u5251\u5ba2 awk \u547d\u4ee4 \u00b6 awk \u662f\u4e00\u4e2a\u6587\u672c\u5206\u6790\u5de5\u5177\u3002 grep \u64c5\u957f\u67e5\u627e\uff0c sed \u64c5\u957f\u7f16\u8f91\uff0c awk \u64c5\u957f\u6570\u636e\u5206\u6790\u5e76\u751f\u6210\u62a5\u544a\u3002 awk \u7684\u540d\u79f0\u5f97\u81ea\u4e8e\u5b83\u7684\u521b\u59cb\u4ebaAlfred Aho \u3001Peter Weinberger \u548c Brian Kernighan \u59d3\u6c0f\u7684\u9996\u4e2a\u5b57\u6bcd\u3002 awk \u67093\u4e2a\u4e0d\u540c\u7248\u672c: awk \u3001 nawk \u548c gawk \u3002\u6211\u4eec\u8bf4\u7684 awk \u4e00\u822c\u6307 gawk \u3002 gawk \u662f awk \u7684GNU\u7248\u672c\u3002 awk \u628a\u6587\u4ef6\u9010\u884c\u8bfb\u5165\uff0c\u4ee5\u7a7a\u683c\u4e3a\u9ed8\u8ba4\u5206\u9694\u7b26\u5c06\u6bcf\u884c\u5207\u7247\uff0c\u518d\u5bf9\u5207\u7247\u8fdb\u884c\u5206\u6790\u5904\u7406\u3002 5.10.1.\u547d\u4ee4\u683c\u5f0f \u00b6 awk 'pattern{action statements;...}' {filenames} pattern \u8868\u793a awk \u5728\u6570\u636e\u4e2d\u67e5\u627e\u7684\u5185\u5bb9\u3002\u662f\u8981\u8868\u793a\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\uff0c\u7528\u659c\u6760\u62ec\u8d77\u6765\u3002 action \u662f\u5728\u627e\u5230\u5339\u914d\u5185\u5bb9\u65f6\u6240\u6267\u884c\u7684\u4e00\u7cfb\u5217\u547d\u4ee4\u3002 -F \uff1a\u6307\u5b9a\u5206\u9694\u7b26\uff0c\u540e\u9762\u7d27\u8ddf\u5355\u5f15\u53f7\uff0c\u5355\u5f15\u53f7\u5185\u662f\u5206\u9694\u7b26\u3002\u5982\u4e0d\u52a0 -F \u9009\u9879\uff0c\u5219\u4ee5\u7a7a\u683c\u6216\u8005tab\u4f5c\u4e3a\u5206\u9694\u7b26\u3002 -v \uff1avar=value\uff0c\u53d8\u91cf\u8d4b\u503c\u3002 \u63d0\u793a\uff1a -F \"\" \u6307\u5b9a\u7a7a\u5b57\u7b26\u4e32\u4f5c\u4e3a\u5b57\u6bb5\u5206\u9694\u7b26\uff0c\u4ece\u800c\u5c06\u8f93\u5165\u5b57\u7b26\u4e32\u4e2d\u7684\u6bcf\u4e2a\u5b57\u7b26\u4f5c\u4e3a\u4e00\u4e2a\u72ec\u7acb\u7684\u5b57\u6bb5\u8fdb\u884c\u5904\u7406\u3002\u7136\u540e\uff0c\u4f7f\u7528\u5faa\u73af\u904d\u5386\u6bcf\u4e2a\u5b57\u6bb5\uff0c\u5982\u679c\u5b57\u6bb5\u4e2d\u5305\u542b\u6570\u5b57\uff0c\u5219\u5c06\u5176\u6dfb\u52a0\u5230str1\u53d8\u91cf\u4e2d\u3002\u6700\u540e\uff0c\u6253\u5370str1\u7684\u503c\u3002 -F '' \u4e2d\u7684\u4e24\u4e2a\u5355\u5f15\u53f7\u4e4b\u95f4\u6ca1\u6709\u63d0\u4f9b\u6709\u6548\u7684\u5b57\u6bb5\u5206\u9694\u7b26\u3002\u5728awk\u4e2d\uff0c\u5b57\u6bb5\u5206\u9694\u7b26\u5fc5\u987b\u662f\u4e00\u4e2a\u975e\u7a7a\u5b57\u7b26\u4e32\u3002 \u793a\u4f8b\uff1a\u7b2c\u4e00\u4e2a\u548c\u7b2c\u4e09\u4e2a\u547d\u4ee4\u662f\u6b63\u786e\u7684\u3002 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F \"\" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F \"\" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 5.10.2.\u5de5\u4f5c\u8fc7\u7a0b \u00b6 \u6267\u884cBEGIN{action;...}\u8bed\u53e5\u5757\u4e2d\u7684\u8bed\u53e5\u3002 BEGIN\u8bed\u53e5\u5757\u518dawk\u8bfb\u5165\u8f93\u5165\u6d41\u4e4b\u524d\u88ab\u6267\u884c\u3002 \u662f\u53ef\u9009\u8bed\u53e5\u5757\u3002 \u5305\u542b\u521d\u59cb\u5316\u53d8\u91cf\uff0c\u6253\u5370\u8f93\u51fa\u8868\u683c\u7684\u8868\u5934\u7b49\u8bed\u53e5\u3002 \u4ece\u6587\u4ef6\u6216\u8005\u6807\u51c6\u8f93\u5165stdin\u8bfb\u53d6\u4e00\u884c\uff0c\u7136\u540e\u6267\u884cpattern{action;...}\u8bed\u53e5\u5757\u3002\u4ece\u7b2c\u4e00\u884c\u5f00\u59cb\u5230\u6700\u540e\u4e00\u884c\uff0c\u9010\u884c\u626b\u63cf\u6587\u4ef6\uff0c\u91cd\u590d\u8fd9\u4e2a\u52a8\u4f5c\uff0c\u76f4\u5230\u6587\u4ef6\u6216\u8005\u8f93\u5165\u6d41\u5168\u90e8\u88ab\u8bfb\u53d6\u5b8c\u6bd5\u3002 \u53ef\u9009\u8bed\u53e5\u5757\u3002 \u5982\u679c\u6ca1\u6709\u63d0\u4f9bpattern\u8bed\u53e5\u5757\uff0c\u5219\u9ed8\u8ba4\u6267\u884c{print}\u3002 \u5f53\u8bfb\u81f3\u6587\u4ef6\u6216\u8005\u8f93\u5165\u6d41\u672b\u5c3e\u65f6\uff0c\u6267\u884cEND{action;...}\u8bed\u53e5\u5757\uff0c\u6bd4\u5982\u6253\u5370\u6240\u6709\u884c\u7684\u5206\u6790\u7ed3\u679c\u8fd9\u7c7b\u6c47\u603b\u4fe1\u606f\u3002\u4e5f\u662f\u4e00\u4e2a\u53ef\u9009\u8bed\u53e5\u5757\u3002 5.10.3.\u5206\u9694\u7b26\u3001\u57df\u548c\u8bb0\u5f55 \u00b6 \u6709\u5206\u9694\u7b26\u5206\u9694\u7684\u5b57\u6bb5\uff08\u5217column\uff0c\u57dffield\uff09\uff0c\u6807\u8bb0 $1 \u3001 $2 \u3001 $3 \u3001...\u3001 $n \u79f0\u4e3a\u57df\u6807\u8bc6\uff0c $0 \u4e3a\u6240\u6709\u57df\u3002\u6ce8\u610f\uff0c\u548cshell\u53d8\u91cf\u4e2d\u7684 $ \u4e0d\u540c\u3002 \u6bcf\u4e00\u884c\u6210\u4e3a\u8bb0\u5f55\uff08record\uff09\u3002 \u5982\u679c\u7701\u7565action\uff0c\u5219\u9ed8\u8ba4\u6267\u884c print $0 \u64cd\u4f5c\u3002 5.10.4.\u5e38\u7528action\u5206\u7c7b \u00b6 Output statements: print , printf Expressions: \u7b97\u672f\u3001\u6bd4\u8f83\u8868\u8fbe\u5f0f Compund statements: \u7ec4\u5408\u8bed\u53e5 Control statements: if , while \u8bed\u53e5 Input statements: \u52a8\u4f5c print \u683c\u5f0f\uff1a print item1, item2, ... \u8bf4\u660e\uff1a \u9017\u53f7\u5206\u9694\u7b26 \u8f93\u51faitem\u53ef\u4ee5\u662f\u5b57\u7b26\u4e32\uff0c\u4e5f\u53ef\u4ee5\u662f\u6570\u503c\uff0c\u662f\u5f53\u524d\u8bb0\u5f55\u7684\u5b57\u6bb5\u3001\u53d8\u91cf\u6216 awk \u8868\u8fbe\u5f0f\u3002 \u5982\u679c\u7701\u7565item\uff0c\u76f8\u5f53\u4e8e print $0 \u56fa\u5b9a\u5b57\u7b26\u9700\u8981\u7528\u53cc\u5f15\u53f7\uff0c\u800c\u53d8\u91cf\u548c\u6570\u5b57\u4e0d\u9700\u8981\u3002 \u793a\u4f8b\uff1a $ seq 5 | awk '{print \"hello awk\"}' hello awk hello awk hello awk hello awk hello awk $ seq 5 | awk '{print 3*5}' 15 15 15 15 15 $ awk -F ':' '{print \"hello\"}' /etc/passwd | head -5 hello hello hello hello hello $ awk -F ':' '{print}' /etc/passwd | head -5 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin systemd-timesync:x:496:496:systemd Time Synchronization:/:/usr/sbin/nologin nobody:x:65534:65534:nobody:/var/lib/nobody:/bin/bash $ awk -F ':' '{print $0}' /etc/passwd | head -5 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin systemd-timesync:x:496:496:systemd Time Synchronization:/:/usr/sbin/nologin nobody:x:65534:65534:nobody:/var/lib/nobody:/bin/bash $ awk -F ':' '{print $1,$3}' /etc/passwd | head -5 root 0 messagebus 499 systemd-network 497 systemd-timesync 496 nobody 65534 $ awk -F ':' '{print $1\"\\t\"$3}' /etc/passwd | head -5 root 0 messagebus 499 systemd-network 497 systemd-timesync 496 nobody 65534 $ grep \"^UUID\" /etc/fstab | awk '{print $2,$3}' / btrfs /var btrfs /usr/local btrfs /tmp btrfs /srv btrfs /root btrfs /opt btrfs /home btrfs /boot/grub2/x86_64-efi btrfs /boot/grub2/i386-pc btrfs /.snapshots btrfs swap swap \u793a\u4f8b\uff1a\u8bfb\u53d6\u5206\u533a\u5229\u7528\u7387\u3002 \u5206\u9694\u7b26\u4e2d\u7684\u5b9a\u4e49 [[:space:]]+|% \u7684\u542b\u4e49\uff0c\u4e00\u4e2a\u6216\u591a\u4e2a\u7a7a\u683c\u6216\u8005 % \u4f5c\u4e3a\u5206\u9694\u7b26\u3002 $ df | awk '{print $1,$5}' Filesystem Use% devtmpfs 0 % tmpfs 0 % tmpfs 2 % tmpfs 0 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % tmpfs 0 % $ df | grep '^/dev/sd' | awk -F '[[:space:]]+|%' '{print $1,$5}' $ df | grep '^/dev/sd' | awk -F ' +|%' '{print $1,$5}' /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 \u793a\u4f8b\uff1a\u8bfb\u53d6ifconfig\u8f93\u51fa\u7ed3\u679c\u4e2d\u7684ip\u5730\u5740\u3002 $ ifconfig eth0 | sed -n '2p' | awk '/netmask/{print $2}' 192 .168.10.210 $ ifconfig eth0 | sed -n '2p' | awk '{print $2}' 192 .168.10.210 5.10.5.\u6a21\u5f0fPattern \u00b6 \u6839\u636epattern\u6761\u4ef6\uff0c\u8fc7\u6ee4\u5339\u914d\u7684\u884c\uff0c\u518d\u505a\u5904\u7406\u3002 \u5982\u679c\u672a\u6307\u5b9a\uff0c\u5373\u7a7a\u6a21\u5f0f\uff0c\u5219\u5339\u914d\u6bcf\u4e00\u884c\u3002 /regular expression/ \uff0c\u4ec5\u5904\u7406\u80fd\u591f\u6a21\u5f0f\u5339\u914d\u5230\u7684\u884c\uff08\u5373\u7ed3\u679c\u4e3a\u771f\uff09\uff0c\u9700\u8981\u7528 / \u8fdb\u884c\u62ec\u8d77\u6765\u3002 \u7ed3\u679c\u4e3a\u771f\uff0c\u5373\u975e0\u503c\u3001\u975e\u7a7a\u5b57\u7b26\u4e32 \u7ed3\u679c\u4e3a\u5047\uff0c\u53730\u503c\u3001\u7a7a\u5b57\u7b26\u4e32 \u793a\u4f8b\uff1a\u7a7a\u6a21\u5f0f awk -F \":\" '{print $1, $3}' /etc/passwd | head -n5 root 0 messagebus 499 systemd-network 497 systemd-timesync 496 nobody 65534 \u793a\u4f8b\uff1a\u975e\u7a7a\u6a21\u5f0f $ seq 5 | awk '0' $ seq 5 | awk '1' 1 2 3 4 5 $ seq 5 | awk '2' 1 2 3 4 5 $ seq 5 | awk '\"true\"' 1 2 3 4 5 $ seq 5 | awk '\"false\"' 1 2 3 4 5 $ seq 5 | awk 'true' $ seq 5 | awk 'false' $ seq 5 | awk '' $ seq 5 | awk '\"\"' $ seq 5 | awk '\"0\"' 1 2 3 4 5 \u4f53\u4f1a\u4e0b\u9762\u53d8\u91cf\u7684\u503c\u548c\u6b63\u786e\u4f7f\u7528\u53d8\u91cf\uff08\u5b57\u7b26\u4e32\u8fd8\u662f\u53d8\u91cf\uff1f\uff09 $ seq 5 | awk '\"test\"' 1 2 3 4 5 $ seq 5 | awk 'test' $ seq 5 | awk -v test = 0 '\"test\"' $ seq 5 | awk -v test = 0 'test' $ seq 5 | awk -v test = \"0\" 'test' $ seq 5 | awk -v test = \"0\" '\"test\"' 1 2 3 4 5 $ seq 5 | awk -v test = 1 'test' 1 2 3 4 5 \u4f53\u4f1a\u4e0b\u9762\u7684\u4e0e\u975e\u5224\u65ad\u3002 $ awk '1' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin $ awk '0' /etc/passwd | head -n3 $ awk '!1' /etc/passwd | head -n3 $ awk '!0' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin # i\u6ca1\u6709\u8d4b\u503c\uff0c\u4e3a\u5047\uff0c\u6ca1\u6709\u8f93\u51fa $ seq 5 | awk 'i' # i\u8d4b\u503c\u4e3a0\uff0c\u4e3a\u5047\uff0c\u6ca1\u6709\u8f93\u51fa $ seq 5 | awk 'i=0' # i\u8d4b\u503c\u4e3a1\uff0c\u4e3a\u771f\uff0c\u8f93\u51fa\u7b2c\u4e00\u884c\u7ed3\u679c\uff0c\u4ee5\u6b64\u7c7b\u63a8\uff0c\u6bcf\u884c\u90fd\u4e3a\u771f\uff0c\u8f93\u51fa\u5168\u90e8seq\u7684\u7ed3\u679c $ seq 5 | awk 'i=1' 1 2 3 4 5 # \u7b2c\u4e00\u6b21\u521d\u59cbi\u672a\u8d4b\u503c\uff0c\u4e3a\u5047\uff0c!i\u5219\u4e3a\u771f\uff0c\u8d4b\u503c\u7ed9i\uff0c\u6240\u4ee5i\u4e3a\u771f,\u8f93\u51faseq\u7b2c1\u884c\u7ed3\u679c # \u7b2c\u4e8c\u6b21\u521d\u59cbi\u4e3a\u771f\uff0c!i\u5219\u4e3a\u5047\uff0c\u8d4b\u503c\u7ed9i\uff0c\u6240\u4ee5i\u4e3a\u5047\uff0c\u4e0d\u8f93\u51faseq\u7b2c2\u884c\u7ed3\u679c # \u7b2c\u4e09\u6b21\u521d\u59cbi\u4e3a\u5047\uff0c!i\u5219\u4e3a\u771f\uff0c\u8d4b\u503c\u7ed9i\uff0c\u6240\u4ee5i\u4e3a\u771f\uff0c\u8f93\u51faseq\u7b2c3\u884c\u7ed3\u679c # \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8f93\u51faseq\u7ed3\u679c\u7684\u5947\u6570\u884c $ seq 5 | awk 'i=!i' 1 3 5 # \u4e0e\u4e0a\u4f8b\u7684\u533a\u522b\u5728\u4e8ei\u521d\u59cb\u503c\u672a\u771f\uff0c\u7b2c\u4e00\u6b21\u7684i\u503c\u4e3a\u5047\uff0c\u4e0d\u8f93\u51faseq\u7b2c1\u884c\u7ed3\u679c # \u7b2c\u4e8c\u6b21i\u7684\u521d\u59cb\u503c\u4e3a\u5047\uff0c\u901a\u8fc7i=!i\u53d8\u4e3a\u771f\uff0c\u6240\u4ee5\u8f93\u51faseq\u7684\u7b2c2\u884c\u7ed3\u679c # \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8f93\u51faseq\u7ed3\u679c\u7684\u5076\u6570\u884c $ seq 5 | awk -v i = 1 'i=!i' 2 4 # \u8f93\u51fa\u8ba1\u6570\u884c $ seq 5 | awk -v i = 0 'i=!i' 1 3 5 # \u53ea\u8f93\u51fai\u7684\u503c\uff0c\u4e0d\u8f93\u51faseq\u7684\u503c $ seq 5 | awk '{i=!i;print i}' 1 0 1 0 1 $ seq 5 | awk '{i=!i}' $ seq 5 | awk '(i=!i)' 1 3 5 $ seq 5 | awk '!(i=!i)' 2 4 5.10.6.\u622a\u53d6\u7247\u6bb5 \u00b6 \u793a\u4f8b\uff1a $ head -n2 /etc/passwd | awk -F ':' '{print $0}' root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false $ head -n2 /etc/passwd | awk -F ':' '{print $2}' x x $ head -n2 /etc/passwd | awk -F ':' '{print $1}' root messagebus $ head -n2 /etc/passwd | awk -F ':' '{print $1\"#\"$2\"#\"$3\"#\"$4}' root#x#0#0 messagebus#x#499#499 5.10.7.\u64cd\u4f5c\u7b26 \u00b6 5.10.7.1.\u7b97\u6570\u64cd\u4f5c\u7b26 \u00b6 x+y \uff0c x-y \uff0c x*y \uff0c x/y \uff0c x^y \uff0c x%y \u3002 -x \uff1a\u8f6c\u6362\u4e3a\u8d1f\u6570 +x \uff1a\u5c06\u5b57\u7b26\u4e32\u8f6c\u6362\u4e3a\u6570\u503c \u5217\u503c\u4e4b\u95f4\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97\u3002 $ awk -F ':' '{$7=$3+$4;print $1,$3,$4,$7}' /etc/passwd | head -n5 root 0 0 0 messagebus 499 499 998 systemd-network 497 497 994 systemd-timesync 496 496 992 nobody 65534 65534 131068 \u8ba1\u7b97\u67d0\u4e2a\u5217\u7684\u603b\u548c\u3002 END \u8868\u793a\u6240\u6709\u7684\u884c\u90fd\u5df2\u7ecf\u6267\u884c\u3002 $ awk -F ':' '{(total=total+$3)}; END {print total}' /etc/passwd 103011 5.10.7.2.\u5b57\u7b26\u4e32\u64cd\u4f5c\u7b26 \u00b6 \u6ca1\u6709\u64cd\u4f5c\u7b26\u53f7\uff0c\u5b57\u7b26\u4e32\u8fde\u63a5\u3002 5.10.7.3.\u8d4b\u503c\u64cd\u4f5c\u7b26 \u00b6 = \uff0c += \uff0c -= \uff0c *= \uff0c /= \uff0c %= \uff0c ^= \uff0c ++ \uff0c -- \u3002 \u793a\u4f8b\uff1a $ awk 'BEGIN{print i}' $ awk 'BEGIN{print i++}' #\u4ece0\u5f00\u59cb 0 $ awk 'BEGIN{print ++i}' 1 $ awk 'BEGIN{print i++, i}' 0 1 $ awk 'BEGIN{i=0;print i++, i}' 0 1 $ awk 'BEGIN{print ++i, i}' 1 1 $ awk 'BEGIN{i=0;print ++i, i}' 1 1 $ awk 'BEGIN{i=0;print i, i++}' 0 0 $ awk 'BEGIN{i=0;print i, ++i}' 0 1 $ seq 10 1 2 3 4 5 6 7 8 9 10 # n\u4ece0\u5f00\u59cb\u8ba1\u6570\uff0c\u8f93\u51fa\u7684\u662fn\u503c\uff0c\u4e0d\u662fseq\u7684\u8f93\u51fa\u7ed3\u679c $ seq 10 | awk '{print n++}' 0 1 2 3 4 5 6 7 8 9 # seq=1\u65f6\uff0c\u521d\u59cbn\u672a\u8d4b\u503c\uff0c\u4e3a\u5047\uff0c\u4e0d\u8f93\u51faseq\u7ed3\u679c\uff0cn++\u4e3a\u771f # seq=2\u65f6\uff0cn\u4e3a\u771f\uff0c\u8f93\u51faseq\u7ed3\u679c\uff0cn++\u4e3a\u771f # \u540e\u7eedn++\u90fd\u4e3a\u771f\uff0c\u6240\u4ee5seq\u7684\u7ed3\u679c\u51fa\u4e86\u7b2c\u4e00\u884c\u7531\u4e8en\u4e3a\u5047\u6ca1\u6709\u8f93\u51fa\uff0c\u5176\u4ed6\u884c\u90fd\u8f93\u51fa $ seq 10 | awk 'n++' 2 3 4 5 6 7 8 9 10 # \u53c2\u8003\u4e0a\u4f8b\uff0cn\u521d\u59cb\u672a\u8d4b\u503c\uff0c\u4f46\u6267\u884c++n\u540e\u4e3a\u771f\uff0c\u6240\u4ee5\u8f93\u51fa\u7b2c\u4e00\u884c\uff0c\u540e\u7eed\u884c\u90fd\u8f93\u51fa\u56e0\u4e3an\u4e00\u76f4\u4e3a\u771f $ seq 10 | awk '++n' 1 2 3 4 5 6 7 8 9 10 # n=0\u65f6++n=1\uff0c!++n=0\uff0c\u8f93\u51fa\u7b2c0\u884c $ awk -v n = 0 '!++n' /etc/passwd # n=0\u65f6n++=1\uff0c!n++=1\uff0c\u8f93\u51fa\u7b2c1\u884c $ awk -v n = 0 '!n++' /etc/passwd root:x:0:0:root:/root:/bin/bash $ awk -v n = 0 '!n++{print n}' /etc/passwd 1 # \u65e0\u7ed3\u679c\u8f93\u51fa $ awk -v n = 0 '!++n{print n}' /etc/passwd $ awk -v n = 1 '!n++{print n}' /etc/passwd $ awk -v n = 0 '!n++' /etc/passwd root:x:0:0:root:/root:/bin/bash # \u65e0\u7ed3\u679c\u8f93\u51fa $ awk -v n = 1 '!n++' /etc/passwd $ awk -v n = 2 '!n++' /etc/passwd 5.10.7.4.\u6bd4\u8f83\u64cd\u4f5c\u7b26 \u00b6 \u4f7f\u7528 == \u4ee3\u8868\u7b49\u4e8e\uff0c\u5373\u7cbe\u786e\u5339\u914d\u3002\u7c7b\u4f3c\u8fd8\u6709 > \u3001 >= \u3001 < \u3001 <= \u3001 != \u7b26\u53f7\u3002 \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e09\u5217\u7684\u503c\u4e3a 1000 \u7684\u884c\u3002 $ awk -F ':' '$3==\"100\"' /etc/passwd vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash \u5728\u548c\u6570\u5b57\u6bd4\u8f83\u65f6\uff0c\u82e5\u628a\u8981\u6bd4\u8f83\u7684\u6570\u5b57\u7528\u53cc\u5f15\u53f7\u5f15\u8d77\u6765\uff0c awk \u4f1a\u6309\u5b57\u7b26\u5904\u7406\uff0c\u4e0d\u52a0\u53cc\u5f15\u53f7\uff0c\u5219\u4f1a\u6309\u6570\u5b57\u5904\u7406\u3002 $ awk -F ':' '$3<=\"100\"' /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/usr/sbin/nologin $ awk -F ':' '$3<=100' /etc/passwd root:x:0:0:root:/root:/bin/bash postfix:x:51:51:Postfix Daemon:/var/spool/postfix:/usr/sbin/nologin man:x:13:62:Manual pages viewer:/var/lib/empty:/usr/sbin/nologin daemon:x:2:2:Daemon:/sbin:/usr/sbin/nologin at:x:25:25:Batch jobs daemon:/var/spool/atjobs:/usr/sbin/nologin bin:x:1:1:bin:/bin:/usr/sbin/nologin awk -F ':' '{if ($1==\"root\") {print $0}}' /etc/passwd awk -F ':' '$7!=\"/bin/false\"' /etc/passwd awk -F ':' '$3<$2' /etc/passwd 5.10.7.5.\u903b\u8f91\u64cd\u4f5c\u7b26 \u00b6 && \u8868\u793a\u201c\u5e76\u4e14\u201d || \u8868\u793a\u201c\u6216\u8005\u201d ! \u8868\u793a\u201c\u975e\u201d\uff08\u53d6\u53cd\uff09 awk -F ':' '$3>10 && $3<100' /etc/passwd awk -F ':' '$3>10 || $3<100' /etc/passwd awk -F ':' '($3==0)' /etc/passwd awk -F ':' '!($3==0)' /etc/passwd \u6ce8\u610f\u4e0b\u9762\u5bf9\u5b57\u7b26\u548c\u6570\u503c\u8fdb\u884c\u53d6\u53cd\u64cd\u4f5c\u7684\u7ed3\u679c\u3002 $ awk 'BEGIN{print i}' $ awk 'BEGIN{print !i}' 1 $ awk -v i = 10 'BEGIN{print i}' 10 $ awk -v i = 10 'BEGIN{print !i}' 0 $ awk -v i = -5 'BEGIN{print i}' -5 $ awk -v i = -5 'BEGIN{print !i}' 0 $ awk -v i = \"abc\" 'BEGIN{print i}' abc $ awk -v i = \"abc\" 'BEGIN{print !i}' 0 $ awk -v i = abc 'BEGIN{print i}' abc $ awk -v i = abc 'BEGIN{print !i}' 0 $ awk -v i = \"\" 'BEGIN{print i}' $ awk -v i = \"\" 'BEGIN{print !i}' 1 \u5728\u5206\u9694\u7b26\u5b9a\u4e49\u4e2d\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u3002 $ df | awk -F \" +|%\" '{print $5}' Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0 $ df | awk -F \"[[:space:]]+|%\" '{print $5}' Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0 5.10.7.6.\u4e09\u76ee\u6761\u4ef6\u8868\u8fbe\u5f0f \u00b6 \u683c\u5f0f\uff1a selector?if-true-expression:if-false-expression $ awk -F ':' '{$3>1000?usertype=\"Common User\":usertype=\"Superuser\";printf\"%-20s:%12s\\n\", $1, usertype}' /etc/passwd | head -n5 root : Superuser messagebus : Superuser systemd-network : Superuser systemd-timesync : Superuser nobody : Common User 5.10.7.8.\u6a21\u5f0f\u5339\u914d\u7b26 \u00b6 ~ \uff1a\u5de6\u53f3\u662f\u5426\u5339\u914d !~ \uff1a\u5de6\u53f3\u662f\u5426\u4e0d\u5339\u914d \u793a\u4f8b\uff1a \u5339\u914d\u6587\u4ef6\u4e2d\u6307\u5b9a\u5b57\u7b26\u4e32 root \u7684\u6240\u6709\u884c\uff0c\u7c7b\u4f3cgrep\u547d\u4ee4\uff0c\u4f46\u6ca1\u6709\u9ad8\u4eae\u663e\u793a\u3002 $ awk '/root/' /etc/passwd root:x:0:0:root:/root:/bin/bash \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e00\u5217 $1 \u4e2d\u5305\u542b\u6307\u5b9a\u5b57\u7b26\u4e32 oo \u7684\u884c\u3002 ~ \u662f\u4ee3\u8868\u5de6\u53f3\u5339\u914d\u3002 $ awk -F ':' '$1 ~/oo/' /etc/passwd root:x:0:0:root:/root:/bin/bash gentoo:x:1014:100:Gentoo Distribution:/home/gentoo:/bin/csh \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u5217 $0 \uff08\u6574\u884c\uff09\u4e2d\u5305\u542b root \u884c\u7684\u7b2c\u4e00\u5217 $1 \u3002 $ awk -F: '$0 ~/root/{print $1}' /etc/passwd $ awk -F: '$0 ~\"root\"{print $1}' /etc/passwd root daemon _cvmsroot \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u5217 $0 \uff08\u6574\u884c\uff09\u4e2d\u4ee5 root \u5f00\u5934\u884c\u7684\u7b2c\u4e00\u5217 $1 \u3002 $ awk -F: '$0 ~\"^root\"{print $1}' /etc/passwd $ awk -F: '$0 ~/^root/{print $1}' /etc/passwd root \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u5217 $0 \uff08\u6574\u884c\uff09\u4e2d\u4e0d\u4ee5 root \u5f00\u5934\u884c\u7684\u7b2c\u4e00\u5217 $1 \u3002 awk -F: '$0 !~/^root/{print $1}' /etc/passwd awk -F: '$0 ~/^[^root]/{print $1}' /etc/passwd \u591a\u6761\u4ef6\u5339\u914d\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u542b\u6709 root \u6216 ftp \u7684\u884c\uff0c\u5e76\u6253\u5370\u7b2c1\u30013\u5217\u3002 awk -F ':' '/root/ {print $1,$3} /bin/ {print $1,$3}' /etc/passwd \u591a\u6761\u4ef6\u5339\u914d\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e00\u5217\u4e2d\u542b\u6709 root \u6216 bin \u7684\u884c\uff0c\u5e76\u6253\u5370\u7b2c1\u30013\u5217\u3002 $ awk -F ':' '$1 ~/root/ {print $1,$3} $1 ~/bin/ {print $1,$3}' /etc/passwd root 0 bin 1 \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e09\u5217 $3 \u4e2d\u503c\u4e3a 0 \u7684\u884c\u3002 $ awk -F \":\" '$3==0' /etc/passwd root:x:0:0:root:/root:/bin/bash \u4ee5\u81f3\u5c11\u4e00\u4e2a\u7a7a\u683c\u6216%\u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u4ee5 /dev/sd \u5f00\u5934\u7684\u884c\uff0c\u6253\u5370\u7b2c\u4e94\u5217\u3002 $ df | awk -F \"[[:space:]]+|%\" '$0 ~ /^\\/dev\\/sd/{print $5}' 8 8 8 8 8 8 8 8 8 8 8 \u8bfb\u53d6 ifconfig eth0 \u8f93\u51fa\u7ed3\u679c\u7684\u7b2c\u4e8c\u884c NR==2 \u7684\u7b2c\u4e8c\u5217 $2 \u3002 $ ifconfig eth0 | awk 'NR==2{print $2}' 192 .168.10.210 5.10.8.\u53d8\u91cf \u00b6 5.10.8.1.\u5185\u7f6e\u53d8\u91cf \u00b6 awk \u5e38\u7528\u7684\u53d8\u91cf\u6709 FS \u3001 OFS \u3001 NF \u548c NR \u3002 FS \u7528\u6765\u5b9a\u4e49\u8f93\u5165\u5b57\u6bb5\u5206\u9694\u7b26\uff0c\u9ed8\u8ba4\u4e3a\u7a7a\u767d\u5b57\u7b26\u3002\u4e0e -F \u9009\u9879\u529f\u80fd\u7c7b\u4f3c\uff0c\u540c\u65f6\u4f7f\u7528\u4f1a\u62a5\u9519\u3002 OFS \u7528\u6765\u5b9a\u4e49\u8f93\u51fa\u5b57\u6bb5\u5206\u9694\u7b26\uff0c\u9ed8\u8ba4\u4e3a\u7a7a\u767d\u5b57\u7b26\u3002 RS \u6307\u5b9a\u8f93\u5165\u65f6\u7684\u6362\u884c\u7b26\u3002 ORS \u6307\u5b9a\u7b26\u53f7\u5728\u8f93\u51fa\u65f6\u66ff\u6362\u6362\u884c\u7b26\u3002 NF \u8868\u793a\u7528\u5206\u9694\u7b26\u5206\u9694\u540e\u4e00\u5171\u6709\u591a\u5c11\u5217\u3002 NR \u8868\u793a\u884c\u53f7\u3002 FNR \u8868\u793a\u4e2a\u6587\u4ef6\u5206\u522b\u8ba1\u6570\u5404\u81ea\u8bb0\u5f55\u7684\u7f16\u53f7\u3002 FILENAME \u8868\u793a\u5f53\u524d\u6587\u4ef6\u540d\u3002 ARGC \u8868\u793a\u547d\u4ee4\u884c\u53c2\u6570\u7684\u4e2a\u6570\u3002 ARVC \u4ee5\u6570\u7ec4\u5f62\u5f0f\u4fdd\u5b58\u547d\u4ee4\u884c\u6240\u7ed9\u5b9a\u7684\u5404\u53c2\u6570\uff0c\u6bcf\u4e2a\u53c2\u6570\uff1a ARGV[0] \uff0c......\u3002 FS \u7684\u7528\u6cd5\uff1a $ awk -v FS = ':' '{print $1, FS, $3}' /etc/passwd | head -n5 root : 0 messagebus : 499 systemd-network : 497 $ awk -F: '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 $ S = : ; awk -v FS = $S '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 systemd-timesync:496 nobody:65534 $ S = : ; awk -F $S '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 FS \u548c -F \u9009\u9879\u529f\u540c\u65f6\u4f7f\u7528\u4f1a\u51b2\u7a81\uff0c -F \u7684\u4f18\u5148\u7ea7\u66f4\u9ad8\u3002 $ awk -v FS = ':' -F ';' '{print $1FS$3}' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash ; messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false ; systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin ; $ awk -v FS = ';' -F ':' '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 OFS \u7684\u7528\u6cd5\uff1a \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u7b2c1\u30013\u30014\u5217\u7b2c\u5185\u5bb9\uff0c\u5e76\u4ee5 # \u4e3a\u5206\u9694\u7b26\u3002 $ awk -F ':' '{OFS=\"#\"} {print $1,$3,$4}' /etc/passwd | head -n5 root#0#0 messagebus#499#499 systemd-network#497#497 systemd-timesync#496#496 nobody#65534#65534 $ awk -v FS = ':' -v OFS = '#' '{print $1,$3,$4}' /etc/passwd | head -n5 root#0#0 messagebus#499#499 systemd-network#497#497 systemd-timesync#496#496 nobody#65534#65534 \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5f53\u7b2c\u4e09\u5217\u5927\u4e8e\u7b49\u4e8e5000\u65f6\uff0c\u6253\u5370\u7b2c1\u30012\u30013\u30014\u5217\u7b2c\u5185\u5bb9\uff0c\u5e76\u4ee5 # \u4e3a\u5206\u9694\u7b26\u3002 $ awk -F ':' '{OFS=\"#\"} {if ($3>=5000) {print $1,$2,$3,$4}}' /etc/passwd nobody#x#65534#65534 RS \u7684\u7528\u6cd5\uff1a # \u4ee5\u7a7a\u683c\u4e3a\u6362\u884c\u6807\u5fd7 $ awk -v RS = ' ' '{print $0}' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for # \u4ee5\u5192\u53f7\u4e3a\u6362\u884c\u6807\u5fd7 $ awk -v RS = ':' '{print $0}' /etc/passwd | head -n3 root x 0 ORS \u7684\u7528\u6cd5\uff1a # \u4ee5\u5192\u53f7\u4e3a\u6362\u884c\u6807\u5fd7\uff0c\u66ff\u6362\u6210### $ awk -v RS = ':' -v ORS = '###' '{print $0}' /etc/passwd | head -n3 root###x###0###0###root###/root###/bin/bash messagebus###x###499###499###User for D-Bus###/run/dbus###/usr/bin/false systemd-network###x###497###497###systemd Network Management###/###/usr/sbin/nologin NF \u7684\u7528\u6cd5\uff1a \u5176\u4e2d NF \u662f\u591a\u5c11\u5217\uff0c $NF \u662f\u6700\u540e\u4e00\u5217\u7684\u503c\u3002 \u4e0b\u4f8b\u4e2d\u4ee5 : \u4e3a\u5206\u9694\u7b26\u4e00\u5171\u5206\u4e3a7\u5217\uff0c\u6700\u540e\u4e00\u5217\u7684\u503c\u662f $NF \u3002 $ awk -F ':' '{print $NF}' /etc/passwd | head -n2 /bin/bash /usr/bin/false $ awk -F ':' '{print NF}' /etc/passwd | head -n2 7 7 $ ss -nt | grep \"^ESTAB\" | awk -F \"[[:space:]]+|:\" '{print $(NF-2)}' 192 .168.10.103 $ ss -nt | awk -F \"[[:space:]]+|:\" '/^ESTAB/{print $(NF-2)}' 192 .168.10.103 NR \u7684\u7528\u6cd5\uff1a \u901a\u8fc7 NR \u8f93\u51fa\u884c\u53f7\u3002\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u524d\u4e09\u884c\u7684\u884c\u53f7\u3002 $ awk -F ':' '{print NR}' /etc/passwd | head -n3 1 2 3 \u53d6\u5947\u3001\u5076\u6570\u884c\u3002 $ seq 10 | awk 'NR%2==0' 2 4 6 8 10 $ seq 10 | awk 'NR%2==1' 1 3 5 7 9 \u901a\u8fc7 NR \u8bbe\u5b9a\u884c\u53f7\u6761\u4ef6\u3002\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u7b2c40\u884c\u4ee5\u540e\u7684\u884c\u5185\u5bb9\u3002 $ awk 'NR>45' /etc/passwd admin3:x:1020:100::/home/admin3:/bin/bash smith:x:2002:0:,,,:/home/admin2:/bin/bash pm1:x:2003:1535::/home/pm1:/bin/bash tm1:x:2004:1535::/home/tm1:/bin/bash tm2:x:2005:1536::/home/tm2:/bin/bash $ awk -F ':' 'NR>45' /etc/passwd admin3:x:1020:100::/home/admin3:/bin/bash smith:x:2002:0:,,,:/home/admin2:/bin/bash pm1:x:2003:1535::/home/pm1:/bin/bash tm1:x:2004:1535::/home/tm1:/bin/bash tm2:x:2005:1536::/home/tm2:/bin/bash $ awk -F ':' 'NR>45 {print NR,$1,$3}' /etc/passwd 46 admin3 1020 47 smith 2002 48 pm1 2003 49 tm1 2004 50 tm2 2005 $ awk -F ':' 'BEGIN{print NR}' /etc/passwd 0 $ awk -F ':' 'END{print NR}' /etc/passwd 50 $ ifconfig eth0 | awk '/netmask/{print $0}' inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig eth0 | awk '/netmask/{print $1}' inet $ ifconfig eth0 | awk '/netmask/{print $2}' 192 .168.10.210 $ ifconfig eth0 | awk 'NR==2{print $0}' inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig eth0 | awk 'NR==2{print $1}' inet $ ifconfig eth0 | awk 'NR==2{print $2}' 192 .168.10.210 \u901a\u8fc7 NR \u4e0e\u5217\u5339\u914d\u4e00\u8d77\u4f7f\u7528\u3002 $ awk -F ':' 'NR<5 && $1 ~/roo/' /etc/passwd root:x:0:0:root:/root:/bin/bash FNR \u7684\u7528\u6cd5\uff1a $ awk '{print FNR}' /etc/fstab /etc/networks 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 $ awk '{print NR, $0}' /etc/fstab /etc/networks 1 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af / btrfs defaults 0 0 2 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /var btrfs subvol = /@/var 0 0 3 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /usr/local btrfs subvol = /@/usr/local 0 0 4 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /tmp btrfs subvol = /@/tmp 0 0 5 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /srv btrfs subvol = /@/srv 0 0 6 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /root btrfs subvol = /@/root 0 0 7 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /opt btrfs subvol = /@/opt 0 0 8 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /home btrfs subvol = /@/home 0 0 9 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/x86_64-efi btrfs subvol = /@/boot/grub2/x86_64-efi 0 0 10 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/i386-pc btrfs subvol = /@/boot/grub2/i386-pc 0 0 11 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /.snapshots btrfs subvol = /@/.snapshots 0 0 12 UUID = 47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 swap swap defaults 0 0 13 # 14 # networks This file describes a number of netname-to-address 15 # mappings for the TCP/IP subsystem. It is mostly 16 # used at boot time, when no name servers are running. 17 # 18 19 loopback 127 .0.0.0 20 link-local 169 .254.0.0 21 22 # End. $ awk '{print FNR, $0}' /etc/fstab /etc/networks 1 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af / btrfs defaults 0 0 2 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /var btrfs subvol = /@/var 0 0 3 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /usr/local btrfs subvol = /@/usr/local 0 0 4 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /tmp btrfs subvol = /@/tmp 0 0 5 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /srv btrfs subvol = /@/srv 0 0 6 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /root btrfs subvol = /@/root 0 0 7 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /opt btrfs subvol = /@/opt 0 0 8 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /home btrfs subvol = /@/home 0 0 9 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/x86_64-efi btrfs subvol = /@/boot/grub2/x86_64-efi 0 0 10 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/i386-pc btrfs subvol = /@/boot/grub2/i386-pc 0 0 11 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /.snapshots btrfs subvol = /@/.snapshots 0 0 12 UUID = 47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 swap swap defaults 0 0 1 # 2 # networks This file describes a number of netname-to-address 3 # mappings for the TCP/IP subsystem. It is mostly 4 # used at boot time, when no name servers are running. 5 # 6 7 loopback 127 .0.0.0 8 link-local 169 .254.0.0 9 10 # End. FILENAME \u7684\u7528\u6cd5\uff1a $ awk '{print FILENAME}' /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab $ awk '{print FNR, FILENAME, $0}' /etc/fstab /etc/networks 1 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af / btrfs defaults 0 0 2 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /var btrfs subvol = /@/var 0 0 3 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /usr/local btrfs subvol = /@/usr/local 0 0 4 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /tmp btrfs subvol = /@/tmp 0 0 5 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /srv btrfs subvol = /@/srv 0 0 6 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /root btrfs subvol = /@/root 0 0 7 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /opt btrfs subvol = /@/opt 0 0 8 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /home btrfs subvol = /@/home 0 0 9 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/x86_64-efi btrfs subvol = /@/boot/grub2/x86_64-efi 0 0 10 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/i386-pc btrfs subvol = /@/boot/grub2/i386-pc 0 0 11 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /.snapshots btrfs subvol = /@/.snapshots 0 0 12 /etc/fstab UUID = 47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 swap swap defaults 0 0 1 /etc/networks # 2 /etc/networks # networks This file describes a number of netname-to-address 3 /etc/networks # mappings for the TCP/IP subsystem. It is mostly 4 /etc/networks # used at boot time, when no name servers are running. 5 /etc/networks # 6 /etc/networks 7 /etc/networks loopback 127 .0.0.0 8 /etc/networks link-local 169 .254.0.0 9 /etc/networks 10 /etc/networks # End. ARGC \u7684\u7528\u6cd5\uff1a \u6bcf\u4e2a\u53d8\u91cf\u7684\u540d\u5b57\u901a\u8fc7 ARGV \u83b7\u53d6\u3002 $ awk '{print ARGC}' /etc/fstab /etc/issue 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 $ awk 'BEGIN{print ARGC}' /etc/fstab /etc/issue 3 ARGV \u7684\u7528\u6cd5\uff1a $ awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/issue awk $ awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/issue /etc/fstab $ awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/issue /etc/issue $ awk 'BEGIN{print ARGV[3]}' /etc/fstab /etc/issue 5.10.8.2.\u81ea\u5b9a\u4e49\u53d8\u91cf \u00b6 \u81ea\u5b9a\u4e49\u53d8\u91cf\u662f\u533a\u5206\u5b57\u7b26\u5927\u5c0f\u5199\u7684\uff0c\u4f7f\u7528\u4e0b\u9762\u7684\u65b9\u5f0f\u8fdb\u884c\u8d4b\u503c\u3002 -v var=value \u5728program\u4e2d\u76f4\u63a5\u5b9a\u4e49 \u4e3e\u4f8b\uff1a $ awk -v t1 = t2 = \"hello awk\" 'BEGIN{print t1, t2}' t2 = hello awk $ awk -v t1 = t2 = \"hello awk\" 'BEGIN{t1=t2=\"gawk\"; print t1, t2}' gawk gawk $ awk 'BEGIN{t1=t2=\"hello awk\"; print t1, t2}' hello awk hello awk $ awk -v t1 = \"hello awk\" '{print t1}' /etc/issue hello awk hello awk hello awk hello awk hello awk $ awk -v t1 = \"hello awk\" 'BEGIN{print t1}' /etc/issue hello awk $ awk -v t1 = \"hello awk\" 'BEGIN{print t1}' hello awk $ awk -F: '{sex=\"male\"; print $1, sex, age; age=28}' /etc/passwd | head -n3 root male messagebus male 28 systemd-network male 28 $ cat < awkscript {print script,$1,$2} EOF $ awk -F: -f awkscript script = \"awk\" /etc/passwd | head -n2 awk root x awk messagebus x \u52a8\u4f5c printf \u3002 \u52a8\u4f5cprintf\u53ef\u4ee5\u5b9e\u73b0\u683c\u5f0f\u5316\u8f93\u51fa\u3002 \u683c\u5f0f\uff1a printf \"FORMAT\", item1, item2, ...... \u8bf4\u660e\uff1a \u5fc5\u987b\u6307\u5b9aFORMAT \u4e0d\u4f1a\u81ea\u52a8\u6362\u884c\uff0c\u9700\u8981\u663e\u5f0f\u7ed9\u51fa\u6362\u884c\u63a7\u5236\u7b26 \\n \u3002 FORMAT\u4e2d\u9700\u8981\u5206\u522b\u4e3a\u540e\u9762\u6bcf\u4e2aitem\u6307\u5b9a\u683c\u5f0f\u7b26\u3002 \u683c\u5f0f\u7b26\uff1a\u4e0eitem\u662f\u4e00\u4e00\u5bf9\u5e94\u7684 %s \uff1a\u663e\u793a\u5b57\u7b26\u4e32 %d , %i \uff1a\u663e\u793a\u5341\u8fdb\u5236\u6574\u6570 %f \uff1a\u663e\u793a\u4e3a\u6d6e\u70b9\u6570 %e , %E \uff1a\u663e\u793a\u79d1\u5b66\u8ba1\u6570\u6cd5\u6570\u503c %c \uff1a\u663e\u793a\u5b57\u7b26\u7684ASCII\u7801 %g , %G \uff1a\u4ee5\u79d1\u5b66\u8ba1\u6570\u6cd5\u6216\u6d6e\u70b9\u5f62\u5f0f\u663e\u793a\u6570\u503c %u \uff1a\u65e0\u7b26\u53f7\u6574\u6570 %% \uff1a\u663e\u793a % \u81ea\u8eab \u4fee\u9970\u7b26\uff1a #[.#] \uff1a\u7b2c\u4e00\u4e2a\u6570\u5b57\u63a7\u5236\u663e\u793a\u7684\u5bbd\u5ea6\uff0c\u7b2c\u4e8c\u4e2a#\u8868\u793a\u5c0f\u6570\u70b9\u540e\u7cbe\u5ea6\uff0c\u5982 %3.1f - \uff1a\u5de6\u5bf9\u9f50\uff08\u9ed8\u8ba4\u53f3\u5bf9\u9f50\uff09\uff0c\u5982 %-15s + \uff1a\u663e\u793a\u6570\u503c\u7684\u6b63\u8d1f\u7b26\u53f7\uff0c\u5982 %+d \u793a\u4f8b\uff1a $ awk -F: '{printf \"%s\", $1}' /etc/passwd | head -n3 rootmessagebussystemd-networksystemd-timesyncnobodymailchronypostfixmanlpgamesftpdaemonrpcnscdpolkitdattftpftpsecurebinstatdsshdvagrantpesignsvntester1tester2tester3tester4tester5user0user1user2user3user4user5user6user7user8user9gentoonginxvarnishmysqlwebuseradmin3smithpm1tm1tm2 $ awk -F: '{printf \"%s\\n\", $1}' /etc/passwd | head -n3 root messagebus systemd-network $ awk -F: '{printf \"%20s\\n\", $1}' /etc/passwd | head -n3 root messagebus systemd-network $ awk -F: '{printf \"%-20s\\n\", $1}' /etc/passwd | head -n3 root messagebus systemd-network $ awk -F: '{printf \"%-20s %10d\\n\", $1, $3}' /etc/passwd | head -n3 root 0 messagebus 499 systemd-network 497 $ awk -F: '{printf \"Username: %s\\n\", $1}' /etc/passwd | head -n3 Username: root Username: messagebus Username: systemd-network $ awk -F: '{printf \"Username: %s UID:%d\\n\", $1, $3}' /etc/passwd | head -n3 Username: root UID:0 Username: messagebus UID:499 Username: systemd-network UID:497 $ awk -F: '{printf \"Username: %25s UID:%d\\n\", $1, $3}' /etc/passwd | head -n3 Username: root UID:0 Username: messagebus UID:499 Username: systemd-network UID:497 $ awk -F: '{printf \"Username: %-25s UID:%d\\n\", $1, $3}' /etc/passwd | head -n3 Username: root UID:0 Username: messagebus UID:499 Username: systemd-network UID:497 5.10.9.BEGIN/END \u00b6 \u793a\u4f8b\uff1a awk -F \":\" 'BEGIN{printf \"--------------------------------\\n%-20s|%10s|\\n--------------------------------\\n\", \"Username\", \"UID\"}{printf \"%-20s|%-10d|\\n--------------------------------\\n\", $1, $3}END{print \"end\"}' /etc/passwd -------------------------------- Username | UID | -------------------------------- root | 0 | -------------------------------- daemon | 1 | -------------------------------- bin | 2 | ------------------------------- ... ... -------------------------------- mfe | 997 | -------------------------------- end 5.10.10.\u5e38\u7528\u63a7\u5236\u8bed\u53e5 \u00b6 {statements;...} \u7ec4\u5408\u8bed\u53e5 if(condition){statements;...} if(condition){statements;...} else(statements;...) switch(expression){case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2;......;default: statementn} while(condition){statements;...} do(statements;...) while{condition} for(expr1;expr2;expr3) {statements;...} break continue exit if-else\u793a\u4f8b\uff1a $ cat < score.txt Name Score Tom 100 Jack 91 Bill 81 Jim 51 EOF $ awk 'NR!=1{score=$2;if($2>=80){print $1, \"Good\"}else if($2>=60){print $1, \"Pass\"}else{print $1, \"failed\"}}' score.txt Tom Good Jack Good Bill Good Jim failed switch\u793a\u4f8b\uff1a $ awk 'NR!=1{switch($2){case 100:print $1,\"good\"; case 60:print $1,\"Pass\"; default:print $1,\"others\"}}' score.txt Tom good Tom Pass Tom others Jack others Bill others Jim others while\u793a\u4f8b\uff1a $ awk 'BEGIN{i=0;sum=0;while(i<=100){sum+=i;i++};print sum}' 5050 do-while\u793a\u4f8b\uff1a $ awk 'BEGIN{i=0;sum=0;do{sum+=i;i++}while(i<101);print sum}' 5050 for\u793a\u4f8b\uff1a $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){sum+=i};print sum}' 5050 \u547d\u4ee4\u6548\u7387\u6bd4\u8f83\uff1a $ time ( awk 'BEGIN{i=0;sum=0;while(i<=100000){sum+=i;i++};print sum}' ) 5000050000 real 0m0.028s user 0m0.027s sys 0m0.001s $ time ( seq -s+ 1000000 | bc ) 500000500000 real 0m0.329s user 0m0.240s sys 0m0.094s $ time ( awk 'BEGIN{i=0;sum=0;for(i=1;i<=1000000;i++){sum+=i};print sum}' ) 500000500000 real 0m0.050s user 0m0.046s sys 0m0.004s contine\u793a\u4f8b\uff1a\u4e2d\u65ad\u5f53\u524d\u5faa\u73af\uff0c\u8fdb\u5165\u4e0b\u4e00\u6b21\u5faa\u73af\u3002 $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){if(i==50)continue;sum+=i};print sum}' 5000 contine\u793a\u4f8b\uff1a\u4e2d\u65ad\u6574\u4e2a\u5faa\u73af\u3002 $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){if(i==50)break;sum+=i};print sum}' 1225 next\u793a\u4f8b\uff1a\u63d0\u524d\u7ed3\u675f\u5bf9\u672c\u884c\u5904\u7406\uff0c\u76f4\u63a5\u8fdb\u5165\u4e0b\u4e00\u884c\u5904\u7406\uff08\u6ce8\uff0cawk\u81ea\u5faa\u73af\uff0c\u5e76\u975e\u524d\u9762\u7684for\u6216while\u5faa\u73af\uff09 $ awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd # \u5947\u6570\u884c\u6253\u5370 root 0 systemd-timesync 496 nobody 65534 chrony 494 games 492 daemon 2 rpc 490 polkitd 488 ftpsecure 486 sshd 484 vagrant 1000 svn 482 tester1 600 tester4 1002 user0 1004 user2 1006 user4 1008 user6 1010 user8 1012 gentoo 1014 varnish 1016 webuser 666 admin3 1020 smith 2002 tm1 2004 $ awk -F: '{if($3%2==0)next;print $1,$3}' /etc/passwd # \u5076\u6570\u884c\u6253\u5370 messagebus 499 systemd-network 497 mail 495 postfix 51 man 13 lp 493 ftp 491 nscd 489 at 25 tftp 487 bin 1 statd 485 pesign 483 tester2 601 tester3 1001 tester5 1003 user1 1005 user3 1007 user5 1009 user7 1011 user9 1013 nginx 1015 mysql 1017 pm1 2003 tm2 2005 5.10.11.\u6570\u7ec4 \u00b6 \u5173\u8054\u6570\u7ec4\u662f\u4e00\u79cd\u6570\u636e\u7ed3\u6784\uff0c\u4e5f\u79f0\u4e3a\u5b57\u5178\u6216\u6620\u5c04\u3002\u4e0e\u4f20\u7edf\u7684\u6570\u7ec4\u4e0d\u540c\uff0c\u5173\u8054\u6570\u7ec4\u7684\u7d22\u5f15\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\u7684\u6570\u636e\uff0c\u4f8b\u5982\u5b57\u7b26\u4e32\u6216\u5bf9\u8c61\uff0c\u800c\u4e0d\u4ec5\u4ec5\u662f\u6574\u6570\u3002 \u63d0\u793a\uff1a \u5728\u8ba1\u7b97\u673a\u7f16\u7a0b\u4e2d\uff0c\u9664\u4e86\u5173\u8054\u6570\u7ec4\uff0c\u8fd8\u6709\u5176\u4ed6\u51e0\u79cd\u5e38\u89c1\u7684\u6570\u7ec4\u7c7b\u578b\uff0c\u5305\u62ec\uff1a \u7ebf\u6027\u6570\u7ec4\uff08\u6216\u79f0\u4e3a\u7d22\u5f15\u6570\u7ec4\uff09\uff1a\u8fd9\u662f\u6700\u5e38\u89c1\u7684\u6570\u7ec4\u7c7b\u578b\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e00\u4e2a\u6570\u5b57\u7d22\u5f15\uff0c\u53ef\u4ee5\u7528\u6765\u5feb\u901f\u8bbf\u95ee\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u3002\u4f8b\u5982\uff0c\u5728C\u8bed\u8a00\u4e2d\uff0c\u6570\u7ec4\u7684\u6bcf\u4e2a\u5143\u7d20\u90fd\u53ef\u4ee5\u901a\u8fc7\u6570\u7ec4\u4e0b\u6807\u6765\u8bbf\u95ee\u3002 \u591a\u7ef4\u6570\u7ec4\uff1a\u591a\u7ef4\u6570\u7ec4\u662f\u4e00\u79cd\u6570\u7ec4\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u4e5f\u662f\u4e00\u4e2a\u6570\u7ec4\u3002\u5728\u4e8c\u7ef4\u6570\u7ec4\u4e2d\uff0c\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e24\u4e2a\u7d22\u5f15\uff08\u4f8b\u5982\uff0c\u884c\u548c\u5217\uff09\uff0c\u53ef\u4ee5\u7528\u4e8e\u8bbf\u95ee\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u3002\u5728\u9ad8\u7ef4\u6570\u7ec4\u4e2d\uff0c\u6bcf\u4e2a\u5143\u7d20\u90fd\u5177\u6709\u66f4\u591a\u7684\u7d22\u5f15\u3002 \u52a8\u6001\u6570\u7ec4\uff1a\u52a8\u6001\u6570\u7ec4\u662f\u4e00\u79cd\u53ef\u4ee5\u52a8\u6001\u8c03\u6574\u5927\u5c0f\u7684\u6570\u7ec4\u3002\u5728\u8bb8\u591a\u7f16\u7a0b\u8bed\u8a00\u4e2d\uff0c\u52a8\u6001\u6570\u7ec4\u53ef\u4ee5\u52a8\u6001\u5206\u914d\u5185\u5b58\uff0c\u4ee5\u4fbf\u5728\u7a0b\u5e8f\u8fd0\u884c\u65f6\u6839\u636e\u9700\u8981\u8c03\u6574\u6570\u7ec4\u7684\u5927\u5c0f\u3002 \u5411\u91cf\uff1a\u5411\u91cf\u662f\u4e00\u79cd\u6570\u7ec4\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u90fd\u662f\u76f8\u540c\u7684\u6570\u636e\u7c7b\u578b\u3002\u5411\u91cf\u901a\u5e38\u7528\u4e8e\u6267\u884c\u6570\u5b66\u8fd0\u7b97\u6216\u5904\u7406\u5927\u91cf\u6570\u5b57\u6570\u636e\u3002 \u5728 awk \u4e2d\u4f7f\u7528\u6570\u7ec4\u65f6\uff0c\u901a\u5e38\u4f1a\u5c06\u67d0\u4e9b\u503c\u4e0e\u4e00\u4e2a\u5b57\u7b26\u4e32\u76f8\u5173\u8054\uff0c\u4ee5\u4fbf\u5728\u9700\u8981\u65f6\u53ef\u4ee5\u901a\u8fc7\u8be5\u5b57\u7b26\u4e32\u5feb\u901f\u5730\u68c0\u7d22\u8be5\u503c\u3002 awk \u7684\u6570\u7ec4\u662f\u4e00\u4e2a\u5173\u8054\u6570\u7ec4\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u90fd\u7531\u4e00\u4e2a\u552f\u4e00\u7684\u952e\u503c\u548c\u4e00\u4e2a\u5bf9\u5e94\u7684\u503c\u7ec4\u6210\u3002\u952e\u503c\uff08\u6216\u79f0\u4e3a\u7d22\u5f15\uff09\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\u7684\u5b57\u7b26\u4e32\u3002 \u6570\u7ec4\u53ef\u4ee5\u901a\u8fc7\u4ee5\u4e0b\u8bed\u6cd5\u8fdb\u884c\u58f0\u660e\uff1a array_name [ index ] = value \u5176\u4e2d\uff0c array_name \u662f\u6570\u7ec4\u7684\u540d\u79f0\uff0c index \u662f\u5143\u7d20\u7684\u7d22\u5f15\u503c\uff0c value \u662f\u5143\u7d20\u7684\u503c\u3002 \u4f8b\u5982\uff0c\u4ee5\u4e0b\u662f\u4e00\u4e2a\u5305\u542b\u4e09\u4e2a\u5143\u7d20\u7684\u5173\u8054\u6570\u7ec4\u7684\u793a\u4f8b\uff1a array [ \"apple\" ] = 1 array [ \"banana\" ] = 2 array [ \"orange\" ] = 3 \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c array \u662f\u4e00\u4e2a\u5173\u8054\u6570\u7ec4\uff0c\u5176\u7d22\u5f15\u4e3a\u5b57\u7b26\u4e32\u7c7b\u578b\uff0c\u800c\u503c\u4e3a\u6574\u6570\u7c7b\u578b\u3002\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u7684\u65b9\u5f0f\u8bbf\u95ee\u8be5\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\uff1a value = array [ \"apple\" ] \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c value \u7684\u503c\u5c06\u4e3a 1 \uff0c\u56e0\u4e3a array[\"apple\"] \u7684\u503c\u4e3a 1 \u3002 \u4ee5\u4e0b\u662f\u7528 awk \u547d\u4ee4\u6765\u521b\u5efa\u4e0a\u9762\u90a3\u4e2a\u5305\u542b\u4e09\u4e2a\u5143\u7d20\u7684\u5173\u8054\u6570\u7ec4\uff0c\u904d\u5386\u5e76\u8f93\u51fa\u6570\u7ec4\u503c\uff1a awk 'BEGIN { array[\"apple\"]=1; array[\"banana\"]=2; array[\"orange\"]=3; for(i in array){print array[i]}}' 3 1 2 \u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u4e92\u6362\u4e86\u6570\u7ec4\u7684\u952e\u548c\u503c\u3002 $ awk 'BEGIN {arr[1]=\"apple\";arr[2]=\"banana\";arr[3]=\"orange\";for(i in arr){print arr[i]}}' apple banana orange \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c i \u662f\u6570\u7ec4 arr \u7684\u7d22\u5f15\u503c\uff0c arr[i] \u662f\u6570\u7ec4\u4e2d\u5bf9\u5e94\u7684\u5143\u7d20\u503c\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\u53ef\u4ee5\u5faa\u73af\u904d\u5386\u6574\u4e2a\u6570\u7ec4\uff0c\u5e76\u8f93\u51fa\u5176\u4e2d\u7684\u5143\u7d20\u3002 \u9664\u4e86\u4f7f\u7528\u5faa\u73af\u904d\u5386\u6570\u7ec4\u4e4b\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f7f\u7528 length \u51fd\u6570\u83b7\u53d6\u6570\u7ec4\u4e2d\u5143\u7d20\u7684\u6570\u91cf\u3002\u4f8b\u5982\uff1a $ awk 'BEGIN { arr[1]=\"apple\"; arr[2]=\"banana\"; arr[3]=\"orange\"; print length(arr) }' 3 \u4e0a\u9762\u7684\u793a\u4f8b\u5c06\u8f93\u51fa\u6570\u5b573\uff0c\u8868\u793a\u6570\u7ec4 arr \u4e2d\u5305\u542b\u4e09\u4e2a\u5143\u7d20\u3002 \u4e3e\u4f8b\uff1a\u53bb\u91cd\u590d\u8bb0\u5f55\u3002 line \u662f\u6570\u7ec4\u540d\uff0c $0 \u662f awk \u8bfb\u53d6\u7684\u5f53\u524d\u884c\u7684\u5185\u5bb9\u3002 line[$0] \u7b49\u4ef7\u4e8e line[\"a\"] \uff0c line[\"b\"] \uff0c......\u3002 \u6211\u4eec\u770b\u6267\u884c\u8fc7\u7a0b\uff1a awk\u8bfb\u5165\u7b2c1\u884c\uff1b \u6267\u884c line[\"a\"] \uff0c\u503c\u4e3a\u7a7a\uff1b \u6c42\u53cd\uff0c\u5219\u7b2c\u4e00\u884c\u7684\u503c\u53d8\u4e3a true \uff0c\u5373 !line[\"a\"]=true \uff1b \u5f53 !line[\"a\"] \u4e3a true \uff0c\u5219\u6253\u5370\u5f53\u524d\u884c\uff0c\u5373\u8f93\u51fa a \u5230\u5c4f\u5e55\uff1b \u6267\u884c line[\"a\"]++ \uff0c\u6ce8\u610f\u7b2c2\u6b65\u4e2d line[\"a\"] \u7684\u503c\u662f\u7a7a\uff0c\u6267\u884c ++ \u540e\u503c\u53d8\u4e3a 1 \u3002 \u540c\u7406\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u7b2c2\uff0c3\uff0c4\u884c\u90fd\u8f93\u51fa\u4e86\u3002 \u5f53\u8bfb\u5165\u7b2c5\u884c\u65f6\uff08\u7b2c\u4e8c\u4e2a a \uff09\uff0c\u6267\u884c line[\"a\"] \uff0c\u503c\u4e3a 1 \uff1b !line[\"a\"]=0 \uff0c\u5373false\uff1b\u5219\u4e0d\u6253\u5370\u5f53\u524d\u884c\uff0c\u5373\u4e0d\u8f93\u51fa a \u5230\u5c4f\u5e55\uff1b\u6267\u884c ++ \u540e\u503c\u53d8\u4e3a 2 \u5f53\u8bfb\u5165\u7b2c8\u884c\u65f6\uff08\u7b2c\u4e09\u4e2a a \uff09\uff0c\u6267\u884c line[\"a\"] \uff0c\u503c\u4e3a 2 \uff1b !line[\"a\"]=0 \uff0c\u5373false\uff1b\u5219\u4e0d\u6253\u5370\u5f53\u524d\u884c\uff0c\u5373\u4e0d\u8f93\u51fa a \u5230\u5c4f\u5e55\uff1b\u6267\u884c ++ \u540e\u503c\u53d8\u4e3a 3 \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8bfb\u5165\u7b2c\u4e8c\u4e2a b \uff0c c \uff0c d \uff0c e \uff0c\u90fd\u4e0d\u4f1a\u518d\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4ece\u800c\u5b9e\u73b0\u53bb\u91cd\u8f93\u51fa\u5230\u529f\u80fd\u3002 $ cat > test << EOF a b c d a c d a b b e EOF $ awk '!line[$0]++' test a b c d e \u4e3e\u4f8b\uff1a\u5224\u65ad\u6570\u7ec4\u7d22\u5f15\u662f\u5426\u5b58\u5728\u3002 \u65b9\u6cd5\uff1a in array \uff0c 0 \u8868\u793a\u4e0d\u5b58\u5728\uff0c 1 \u8868\u793a\u5b58\u5728\u3002 $ awk 'BEGIN{array[\"i\"]=\"x\";array[\"j\"]=\"j\";print \"i\" in array, \"y\" in array}' 1 0 $ awk 'BEGIN{array[\"i\"]=\"x\";array[\"j\"]=\"j\";if(\"i\" in array){print \"exits!\"}else{print \"not exists!\"}}' exits! $ awk 'BEGIN{array[\"i\"]=\"x\";array[\"j\"]=\"j\";if(\"abc\" in array){print \"exits!\"}else{print \"not exists!\"}}' not exists! \u4e3e\u4f8b\uff1a\u904d\u5386\u6570\u7ec4\u4e2d\u6bcf\u4e2a\u5143\u7d20\u3002 \u65b9\u6cd5\uff1a for(your_var in array){your_for_body} \uff0c\u6ce8\u610f\uff0cyour_var\u4f1a\u904d\u5386\u6bcf\u4e2a\u7d22\u5f15\u3002 $ awk 'BEGIN{weekday[\"mon\"]=\"Monday\";weekday[\"tue\"]=\"Tuesday\";for(i in weekday){print i,weekday[i]}}' tue Tuesday mon Monday $ awk 'BEGIN{weekday[\"mon\"]=\"Monday\";weekday[\"tue\"]=\"Tuesday\";for(i in weekday){print i\": \"weekday[i]}}' tue: Tuesday mon: Monday \u6ce8\u610f\u4e0b\u9762\u7684\u6362\u884c\u5199\u6cd5\uff0c\u4e0d\u9700\u8981\u53cd\u659c\u6760 \\ \u3002 $ awk 'BEGIN{ arr[\"x\"]=\"welcome\" arr[\"y\"]=\"to\" arr[\"z\"]=\"Shanghai\" for (i in arr) { print i, arr[i] } }' x welcome y to z Shanghai \u793a\u4f8b\uff1a\u683c\u5f0f\u5316\u8f93\u51fa\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002 $ awk -F: '{user[$1]=$3}END{for (i in user){print \"Username: \" i, \"UID: \" user[i]}}' /etc/passwd Username: sshd UID: 476 Username: rpc UID: 482 Username: tftp UID: 488 Username: usbmux UID: 480 Username: srvGeoClue UID: 487 ...... \u793a\u4f8b\uff1a\u663e\u793a\u4e3b\u673a\u8fde\u63a5\u72b6\u6001\u51fa\u73b0\u7684\u6b21\u6570\u3002 # \u4f20\u7edf\u65b9\u6cd5 $ ss -ant | awk 'NR>=2{print $1}' | sort | uniq -c $ ss -ant | awk 'NR!=1{print $1}' | sort | uniq -c 1 ESTAB 6 LISTEN # \u4f7f\u7528awk\u6570\u7ec4 $ ss -ant | awk 'NR>=2{state[$1]++}END{for(i in state){print state[i], i}}' $ ss -ant | awk 'NR!=1{state[$1]++}END{for(i in state){print state[i], i}}' 6 LISTEN 1 ESTAB 5.10.12.awk\u51fd\u6570 \u00b6 \u53c2\u8003\uff1a awk \u51fd\u6570\u5b98\u7f51 5.10.12.1.\u5185\u7f6e\u51fd\u6570 \u00b6 \u5728 awk \u4e2d\uff0c\u51fd\u6570\u662f\u4e00\u79cd\u7528\u4e8e\u6267\u884c\u7279\u5b9a\u4efb\u52a1\u6216\u8ba1\u7b97\u7279\u5b9a\u503c\u7684\u53ef\u91cd\u7528\u4ee3\u7801\u5757\u3002 awk \u63d0\u4f9b\u4e86\u8bb8\u591a\u5185\u7f6e\u51fd\u6570\uff0c\u53ef\u4ee5\u7528\u4e8e\u5904\u7406\u6587\u672c\u6570\u636e\u3001\u6267\u884c\u6570\u5b66\u8fd0\u7b97\u3001\u64cd\u4f5c\u5b57\u7b26\u4e32\u7b49\u3002 \u4ee5\u4e0b\u662f\u4e00\u4e9b\u5e38\u7528\u7684awk\u51fd\u6570\u793a\u4f8b\uff1a length(string) \uff1a\u8fd4\u56de\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u3002 $ awk 'BEGIN { str = \"Hello World\"; len = length(str); print len }' 11 $ cut -d: -f1 /etc/passwd | awk '{print length($1)}' | head -3 4 10 15 substr(string, start, length) \uff1a\u4ece\u6307\u5b9a\u4f4d\u7f6e\u5f00\u59cb\u63d0\u53d6\u5b57\u7b26\u4e32\u7684\u5b50\u4e32\u3002 $ awk 'BEGIN { str = \"Hello World\"; substring = substr(str, 7, 5); print substring }' World sub(regexp, replacement [, target]) \uff1a\u4ece\u5b57\u7b26\u4e32target\u4e2d\u641c\u7d22\u5339\u914dregexp\u7684\u5185\u5bb9\uff0c\u5e76\u628a\u7b2c\u4e00\u4e2a\u5339\u914d\u7684\u5185\u5bb9\u66ff\u6362\u4e3areplacement\u3002\u61d2\u60f0\u6a21\u5f0f\u3002 \u6ce8\u610f\uff1a sub() \u51fd\u6570\u5728\u539f\u59cb\u5b57\u7b26\u4e32\u4e0a\u8fdb\u884c\u66ff\u6362\u64cd\u4f5c\uff0c\u5e76\u8fd4\u56de\u66ff\u6362\u7684\u6b21\u6570\u3002 # \u5728\u539f\u59cb\u5b57\u7b26\u4e32\u4e2d\uff0c\u7b2c\u4e00\u4e2a\u5339\u914d\u5230\u7684\"at\"\u88ab\u66ff\u6362\u4e3a\"ith\"\uff0c\u56e0\u6b64\u8f93\u51fa\u7ed3\u679c\u4e2d\u7684\"at\"\u53d8\u4e3a\"ith\"\uff0c\u5176\u4ed6\u5730\u65b9\u7684\"at\"\u4fdd\u6301\u4e0d\u53d8 $ awk 'BEGIN { str = \"water, water, everywhere\"; sub(/at/, \"ith\", str); print str }' wither, water, everywhere # \u8fd4\u56de\u5339\u914d\u6b21\u6570 $ awk 'BEGIN { str = \"water, water, everywhere\"; str_new = sub(/at/, \"ith\", str); print str_new }' 1 $ echo \"2023:15:35 08:15:26\" | awk 'sub(/:/, \"-\", $0)' 2023 -15:35 08 :15:26 $ echo \"2023:15:35 08:15:26\" | awk 'sub(/:/, \"-\", $1)' 2023 -15:35 08 :15:26 $ echo \"2023:15:35 08:15:26\" | awk 'sub(/:/, \"-\", $2)' 2023 :15:35 08 -15:26 gsub(regexp, replacement [, target])\uff1a\u4ece\u5b57\u7b26\u4e32target\u4e2d\u641c\u7d22\u5339\u914dregexp\u7684\u5185\u5bb9\uff0c\u5e76\u628a\u5168\u90e8\u5339\u914d\u7684\u5185\u5bb9\u66ff\u6362\u4e3areplacement\u3002\u8d2a\u5a6a\u6a21\u5f0f\u3002 # \u5728\u539f\u59cb\u5b57\u7b26\u4e32\u4e2d\uff0c\u5c06\u6240\u6709\u5339\u914d\u5230\u7684\"at\"\u88ab\u66ff\u6362\u4e3a\"ith\" $ awk 'BEGIN { str = \"water, water, everywhere\"; gsub(/at/, \"ith\", str); print str }' wither, wither, everywhere # \u8fd4\u56de\u5339\u914d\u6b21\u6570 $ awk 'BEGIN { str = \"water, water, everywhere\"; str_new = gsub(/at/, \"ith\", str); print str_new }' 2 $ echo \"2023:15:35 08:15:26\" | awk 'gsub(/:/, \"-\", $0)' 2023 -15-35 08 -15-26 $ echo \"2023:15:35 08:15:26\" | awk 'gsub(/:/, \"-\", $1)' 2023 -15-35 08 :15:26 $ echo \"2023:15:35 08:15:26\" | awk 'gsub(/:/, \"-\", $2)' 2023 :15:35 08 -15-26 split(string, array, delimiter) \uff1a\u5c06\u5b57\u7b26\u4e32string\u6309\u6307\u5b9a\u5206\u9694\u7b26delimiter\u62c6\u5206\u6210\u6570\u7ec4array\u7684\u5143\u7d20\u3002 \u6ce8\u610f\uff1a\u7b2c\u4e00\u4e2a\u7d22\u5f15\u503c\u4e3a 1 \uff0c\u7b2c\u4e8c\u4e2a\u7d22\u5f15\u503c\u4e3a 2 . $ awk 'BEGIN { str = \"apple,banana,orange\"; split(str, fruits, \",\"); print fruits[2] }' banana $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[1]}' messagebus $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[2]}' x $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[3]}' 499 $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[7]}' /usr/bin/false index(string, search) \uff1a\u5728\u5b57\u7b26\u4e32\u4e2d\u67e5\u627e\u6307\u5b9a\u5b50\u4e32\u7684\u4f4d\u7f6e\u3002 $ awk 'BEGIN { str = \"Hello World\"; pos = index(str, \"World\"); print pos }' 7 sprintf(format, expression) \uff1a\u6839\u636e\u6307\u5b9a\u7684\u683c\u5f0f\u5c06\u8868\u8fbe\u5f0f\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\u3002 $ awk 'BEGIN { num = 3.14159; str = sprintf(\"%.2f\", num); print str }' 3 .14 rand() \uff1a\u8fd4\u56de\u4e00\u4e2a\u968f\u673a\u6570\uff0c\u503c\u5728 0 \u548c 1 \u4e4b\u95f4\u5747\u5300\u5206\u5e03\u3002\u8fd9\u4e2a\u503c\u53ef\u4ee5\u662f 0 \uff0c\u4f46\u4e0d\u4f1a\u662f 1 \u3002\u4ece\u4e0b\u9762\u7684\u4f8b\u5b50\u53ef\u4ee5\u770b\u51fa\uff0c\u8fd0\u884c\u7ed3\u679c\u90fd\u662f\u4e00\u6837\u7684\uff0c\u6240\u4ee5\u4ea7\u751f\u968f\u673a\u6570\u7684\u79cd\u5b50\u662f\u4e00\u6837\u7684\u3002 $ awk 'BEGIN{print rand()}' 0 .924046 $ awk 'BEGIN{print rand()}' 0 .924046 $ awk 'BEGIN{print rand()}' 0 .924046 srand() \uff1a\u914d\u5408 rand() \u51fd\u6570\uff0c\u751f\u6210\u968f\u673a\u6570\u79cd\u5b50\u3002 $ awk 'BEGIN{srand();print rand()}' 0 .112006 $ awk 'BEGIN{srand();print rand()}' 0 .663431 $ awk 'BEGIN{srand();print rand()}' 0 .541305 int() \uff1a\u8fd4\u56de\u6574\u6570\u3002 $ awk 'BEGIN{srand();print int(rand()*100)}' 84 $ awk 'BEGIN{srand();print int(rand()*100)}' 66 $ awk 'BEGIN{srand();print int(rand()*100)}' 8 system(command) \uff1a\u6267\u884ccommand\u547d\u4ee4\uff08\u53ef\u4ee5\u662f\u4efb\u4f55\u6709\u6548\u7684Shell\u547d\u4ee4\uff09\u5e76\u8fd4\u56de\u547d\u4ee4\u7684\u9000\u51fa\u72b6\u6001\u7801\u3002\u5141\u8bb8\u5728 awk \u811a\u672c\u4e2d\u6267\u884c\u5916\u90e8\u547d\u4ee4\uff0c\u5e76\u83b7\u53d6\u547d\u4ee4\u6267\u884c\u7684\u7ed3\u679c\u3002 # \u6267\u884cls -l\u547d\u4ee4\uff0c\u5e76\u5c06\u547d\u4ee4\u7684\u9000\u51fa\u72b6\u6001\u7801\u5b58\u50a8\u5728status\u53d8\u91cf\u4e2d\uff0c\u5e76\u6253\u5370status\u53d8\u91cf\u7684\u503c $ awk 'BEGIN { status = system(\"ls -l\"); print \"Exit status:\", status }' total 0 drwxr-xr-x 1 vagrant users 70 Jan 2 15 :54 Desktop drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Documents drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Downloads drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Music drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Pictures drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Public drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Templates drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Videos drwxr-xr-x 1 vagrant users 0 Mar 15 2022 bin Exit status: 0 $ awk 'BEGIN{score=100; system(\"echo your score is \" score)}' your score is 100 systime() \uff1a\u5f53\u524d\u65f6\u95f4\u52301970\u5e741\u67081\u65e5\u5230\u79d2\u6570 $ awk 'BEGIN{print systime()}' 1684158395 strftime(format, timestamp) \uff1a\u5c06\u65f6\u95f4\u6233timestamp\u8f6c\u6362\u4e3a\u6307\u5b9a\u683c\u5f0fformat\u7684\u65e5\u671f\u548c\u65f6\u95f4\u5b57\u7b26\u4e32\u3002timestamp\u901a\u5e38\u662f\u4e00\u4e2a\u4ee5\u79d2\u4e3a\u5355\u4f4d\u8868\u793a\u7684\u6574\u6570\u3002 \u5e38\u89c1\u7684\u683c\u5f0f\u5316\u5b57\u7b26\u4e32\u9009\u9879\uff1a %Y \uff1a\u56db\u4f4d\u6570\u7684\u5e74\u4efd\uff08\u4f8b\u5982\uff1a2023\uff09 %m \uff1a\u4e24\u4f4d\u6570\u7684\u6708\u4efd\uff0801-12\uff09 %d \uff1a\u4e24\u4f4d\u6570\u7684\u65e5\u671f\uff0801-31\uff09 %H \uff1a\u4e24\u4f4d\u6570\u7684\u5c0f\u65f6\uff0800-23\uff09 %M \uff1a\u4e24\u4f4d\u6570\u7684\u5206\u949f\uff0800-59\uff09 %S \uff1a\u4e24\u4f4d\u6570\u7684\u79d2\uff0800-60\uff09 %Z \uff1a\u65f6\u533a\u540d\u79f0\uff08\u4f8b\u5982\uff1aGMT\uff09 # \u5c06\u5f53\u524d\u65f6\u95f4\u6233\u8f6c\u6362\u4e3a\u683c\u5f0f\u4e3a\"YYYY-MM-DD HH:MM:SS\"\u7684\u65e5\u671f\u548c\u65f6\u95f4\u5b57\u7b26\u4e32 $ awk 'BEGIN { timestamp = systime(); str = strftime(\"%Y-%m-%d %H:%M:%S\", timestamp); print str }' 2023 -05-15 22 :01:35 # \u5c06\u5f53\u524d\u65f6\u95f4\u6233\u7684\u524d\u4e00\u5c0f\u65f6\uff083600\u79d2\uff09\u8f6c\u6362\u4e3a\u683c\u5f0f\u4e3a\"YYYY-MM-DD HH:MM:SS\"\u7684\u65e5\u671f\u548c\u65f6\u95f4\u5b57\u7b26\u4e32 $ awk 'BEGIN { timestamp = systime()-3600; str = strftime(\"%Y-%m-%d %H:%M:%S\", timestamp); print str }' 2023 -05-15 21 :01:43 5.10.12.2.\u81ea\u5b9a\u4e49\u51fd\u6570 \u00b6 \u4e3e\u4f8b\uff1a $ cat > func.awk << EOF function max(x,y){ x>y?var=x:var=y return var } BEGIN{print max(a,b)} EOF $ awk -v a = 30 -v b = 20 -f func.awk 30 \u4e3e\u4f8b\uff1a \u5728\u4e0b\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u5b9a\u4e49\u4e86\u4e00\u4e2a\u540d\u4e3a square() \u7684\u81ea\u5b9a\u4e49\u51fd\u6570\uff0c\u5b83\u63a5\u53d7\u4e00\u4e2a\u53c2\u6570 x \uff0c\u5e76\u8fd4\u56de x \u7684\u5e73\u65b9\u3002\u7136\u540e\uff0c\u5728\u4e3b\u4ee3\u7801\u5757\u4e2d\uff0c\u6211\u4eec\u58f0\u660e\u4e86\u4e00\u4e2a\u53d8\u91cf num \u5e76\u8d4b\u503c\u4e3a 5 \u3002\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u8c03\u7528\u4e86\u81ea\u5b9a\u4e49\u51fd\u6570 square() \uff0c\u4f20\u9012 num \u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u5c06\u8fd4\u56de\u503c\u5b58\u50a8\u5728\u53d8\u91cf result \u4e2d\u3002\u6700\u540e\uff0c\u6211\u4eec\u6253\u5370\u51fa result \u7684\u503c\u3002 $ cat > func.awk << EOF # \u81ea\u5b9a\u4e49\u51fd\u6570\uff1a\u8ba1\u7b97\u5e73\u65b9 function square(x) { return x * x; } # \u4f7f\u7528\u81ea\u5b9a\u4e49\u51fd\u6570 { num = 5; result = square(num); print \"\u5e73\u65b9\u7ed3\u679c\uff1a\" result; } EOF $ awk -f func.awk \u5e73\u65b9\u7ed3\u679c\uff1a25 \u4e3e\u4f8b\uff1a $ cat > func.awk << EOF # \u81ea\u5b9a\u4e49\u51fd\u6570\uff1a\u8ba1\u7b97\u6570\u7ec4\u5e73\u5747\u503c function calculateAverage(arr, size) { sum = 0; for (i = 1; i <= size; i++) { sum += arr[i]; } return sum / size; } # \u4f7f\u7528\u81ea\u5b9a\u4e49\u51fd\u6570 { # \u5b9a\u4e49\u6570\u7ec4 numbers[1] = 10; numbers[2] = 20; numbers[3] = 30; numbers[4] = 40; numbers[5] = 50; # \u8ba1\u7b97\u6570\u7ec4\u7684\u5e73\u5747\u503c size = 5; average = calculateAverage(numbers, size); print \"\u6570\u7ec4\u7684\u5e73\u5747\u503c\uff1a\" average; } EOF $ awk -f func.awk \u6570\u7ec4\u7684\u5e73\u5747\u503c\uff1a30 5.10.12.3.awk\u811a\u672c \u00b6 \u4e3e\u4f8b\uff1a # \u6ce8\u610f\u8f6c\u4e49 $ cat > passwd.awk << EOF {if(\\$3>=1000)print \\$1,\\$3} EOF $ awk -F: -f passwd.awk /etc/passwd nobody 65534 vagrant 1000 \u4e0a\u9762\u4f8b\u5b50\u4e5f\u53ef\u4ee5\u5199\u6210\u5982\u4e0b\u811a\u6b65\u683c\u5f0f\u3002 $ cat > test.awk << EOF #!/bin/awk -f # This is an awk script {if(\\$3>=1000)print \\$1,\\$3} EOF $ chmod +x test.awk $ ./test.awk -F: /etc/passwd nobody 65534 vagrant 1000 \u5411awk\u811a\u672c\u4f20\u9012\u53c2\u6570\uff1a \u683c\u5f0f\uff1a awkfile var=value var2=value2 ... inputfile \u8bf4\u660e\uff1a \u4e0a\u9762\u683c\u5f0f\u53d8\u91cf\u5728 BEGIN \u8fc7\u7a0b\u4e2d\u4e0d\u53ef\u7528\uff0c\u76f4\u5230\u9996\u884c\u8f93\u5165\u5b8c\u6210\u4ee5\u540e\uff0c\u53d8\u91cf\u624d\u53ef\u7528\u3002 \u53ef\u4ee5\u901a\u8fc7 -v \u53c2\u6570\uff0c\u8ba9 awk \u5728\u6267\u884c BEGIN \u4e4b\u524d\u5f97\u5230\u53d8\u91cf\u3002 \u547d\u4ee4\u884c\u4e2d\u6bcf\u4e00\u4e2a\u6307\u5b9a\u7684\u53d8\u91cf\u90fd\u9700\u8981\u4e00\u4e2a -v \u53c2\u6570\u3002 \u4e3e\u4f8b\uff1a # x=100\u5728BEGIN{print x}\u533a\u6bb5\u53ef\u7528 $ awk -v x = 100 'BEGIN{print x}{print x+100}' /etc/hosts 100 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 # \u4e0d\u52a0-v\u5219x=100\u5728BEGIN{print x}\u533a\u6bb5\u4e0d\u53ef\u7528 $ awk x = 100 'BEGIN{print x}{print x+100}' /etc/hosts awk: fatal: cannot open file ` BEGIN { print x }{ print x+100 } ' for reading (No such file or directory) # \u4fee\u6b63\u4e0a\u9762\u7684\u9519\u8bef\uff0c\u5c06x=100\u653e\u5728\u540e\u9762\uff0c\u56e0\u4e3a\u6ca1\u6709-v\uff0c\u6240\u4ee5x=100\u5728BEGIN{print x}\u533a\u6bb5\u4e0d\u53ef\u7528\uff0c\u7b2c\u4e00\u884c\u8f93\u51fa\u7a7a\u767d $ awk ' BEGIN { print x }{ print x+100 } ' x = 100 /etc/hosts 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 5.11.\u5c0f\u7ec3\u4e60 \u00b6 \u663e\u793a /proc/meminfo \u6587\u4ef6\u4e2d\u4ee5\u5927\u5c0fs\u5f00\u5934\u7684\u884c\uff0c\u8981\u6c42\u4f7f\u7528\u4e24\u79cd\u65b9\u6cd5\u3002 cat /proc/meminfo | grep -i \"^s\" cat /proc/meminfo | grep \"^[sS]\" \u663e\u793a /etc/passwd \u6587\u4ef6\u4e2d\u4e0d\u4ee5 /bin/bash \u7ed3\u5c3e\u7684\u884c\u3002 grep -v \"/bin/bash $ \" /etc/passwd \u663e\u793a\u7528\u6237 rpc \u9ed8\u8ba4\u7684shell\u7a0b\u5e8f\u3002 $ grep \"rpc\" /etc/passwd | cut -d \":\" -f 7 /sbin/nologin \u627e\u51fa /etc/passwd \u4e2d\u7684\u4e24\u4f4d\u6216\u4e09\u4f4d\u6570\u3002 grep -Eo \"[:digit:]{2,3}\" /etc/passwd grep -Eo \"[0-9]{2,3}\" /etc/passwd \u8fd9\u91cc\u7528\u5230\u4e86 {} \uff0c\u5c5e\u4e8e\u6269\u5c55\u6b63\u5219\u7b26\u53f7\uff0c\u6240\u4ee5\u8981\u7528 -E \u3002 \u663e\u793aRocky 9\u7684 /etc/grub2.cfg \u6587\u4ef6\u4e2d\uff0c\u81f3\u5c11\u4ee5\u4e00\u4e2a\u7a7a\u767d\u5b57\u7b26\u5f00\u5934\u7684\u4e14\u540e\u9762\u6709\u975e\u7a7a\u767d\u5b57\u7b26\u7684\u884c\u3002\uff08\u6ce8\uff1a /etc/grub2.cfg \u5728openSUSE\u548cUbuntu\u4e2d\u6ca1\u6709\uff09 # \u4e0d\u542b\u9996\u5b57\u7b26\u4e3atab $ sudo grep \"^ \" /etc/grub2.cfg # \u5305\u542b\u9996\u5b57\u7b26\u4e3atab $ sudo grep \"^[[:space:]]\" /etc/grub2.cfg \u627e\u51fa netstat -tan \u547d\u4ee4\u7ed3\u679c\u4e2d\u4ee5 LISTEN \u540e\u8ddf\u4efb\u610f\u591a\u4e2a\u7a7a\u767d\u5b57\u7b26\u7ed3\u5c3e\u7684\u884c\u3002 netstat -tan | grep -E \"LISTEN[[:space:]]+\" \u663e\u793aRocky 9\u4e0a\u6240\u6709UID\u5c0f\u4e8e1000\u4ee5\u5185\u7684\u7528\u6237\u540d\u548cUID\u3002 cat /etc/passwd | cut -d \":\" -f 1 ,3 | grep -E \"\\:[0-9]{1,3} $ \" grep -E \"\\:[0-9]{1,3}\\:[0-9]{1,}\" /etc/passwd | cut -d \":\" -f 1 ,3 \u5728Rocky 9\u4e0a\u663e\u793a\u6587\u4ef6 /etc/passwd \u7528\u6237\u540d\u548cshell\u540c\u540d\u7684\u884c\u3002 $ grep -E \"^([[:alnum:]]+\\b).*\\1 $ \" /etc/passwd sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt \u5229\u7528 df \u548c grep \uff0c\u53d6\u51fa\u78c1\u76d8\u5404\u5206\u533a\u5229\u7528\u7387,\u5e76\u4ece\u5927\u5230\u5c0f\u6392\u5e8f\u3002 $ df | tr -s \" \" | cut -d \" \" -f 1 ,5 | sort -n -t \" \" -k 2 devtmpfs 0 % Filesystem Use% tmpfs 0 % tmpfs 0 % /dev/mapper/rl-home 1 % tmpfs 2 % /dev/mapper/rl-root 5 % /dev/nvme0n1p1 23 % \u663e\u793a\u4e09\u4e2a\u7528\u6237 root \uff0c sync \uff0c bin \u7684UID\u548c\u9ed8\u8ba4shell\u3002 $ grep \"^root:\\|^sync:\\|^bin:\" /etc/passwd | cut -d \":\" -f 1 ,7 root:/bin/bash bin:/usr/sbin/nologin \u4f7f\u7528 egrep \u53d6\u51fa /etc/default-1/text_2/local.3/grub \u4e2d\u5176\u57fa\u540d\u548c\u76ee\u5f55\u540d\u3002 # \u57fa\u540d $ echo \"/etc/default-1/text_2/local.3/grub\" | egrep -io \"[[:alpha:]]+ $ \" grub # \u76ee\u5f55\u540d $ echo \"/etc/default-1/text_2/local.3/grub\" | egrep -io \"/([[:alpha:]]+.|_?[[:alpha:]]|[[:alnum:]]+/){7}\" /etc/default-1/text_2/local.3/ \u7edf\u8ba1 last \u547d\u4ee4\u4e2d\u4ee5 vagrant \u767b\u5f55\u7684\u6bcf\u4e2a\u4e3b\u673aIP\u5730\u5740\u767b\u5f55\u6b21\u6570\u3002 $ last | grep vagrant | tr -s \" \" | cut -d \" \" -f 3 | grep -E \"([0-9]{1,3}\\.){1,3}[0-9]{1,3}\" | sort -n | uniq -c 24 192 .168.10.107 38 192 .168.10.109 17 192 .168.10.201 6 192 .168.10.210 2 192 .168.10.220 \u5229\u7528\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\u5206\u522b\u8868\u793a0-9\u300110-99\u3001100-199\u3001200-249\u3001250-255\u3002 [ 0 -9 ] | [ 0 -9 ]{ 2 } | 1 [ 0 -9 ]{ 2 } | 2 [ 0 -4 ][ 0 -9 ] | 25 [ 0 -5 ] \u663e\u793a ifconfig \u547d\u4ee4\u7ed3\u679c\u4e2d\u6240\u6709IPv4\u5730\u5740\u3002 $ ifconfig | grep -Eo \"([0-9]{1,3}\\.){3}[0-9]{1,3}\" | grep -v \"^255\" 192 .168.10.210 192 .168.10.255 127 .0.0.1 \u663e\u793a ip addr \u547d\u4ee4\u7ed3\u679c\u4e2d\u6240\u6709IPv4\u5730\u5740\u3002 $ ip addr show eth0 | grep inet | grep eth0 | tr -s \" \" | cut -d \" \" -f 3 | cut -d \"/\" -f 1 192 .168.10.210 $ ip addr show | grep -Eo \"([0-9]{1,3}\\.){3}[0-9]{1,3}\" | grep -v \"^255\" 127 .0.0.1 192 .168.10.210 192 .168.10.255 \u5c06\u6b64\u5b57\u7b26\u4e32Welcome to the linux world\u4e2d\u7684\u6bcf\u4e2a\u5b57\u7b26\u53bb\u91cd\u5e76\u6392\u5e8f\uff0c\u91cd\u590d\u6b21\u6570\u591a\u7684\u6392\u5230\u524d\u9762\u3002 $ echo \"Welcome to the linux world\" | grep -o [[ :alpha: ]] | sort | uniq -c | sort -nr 3 o 3 l 3 e 2 t 1 x 1 W 1 w 1 u 1 r 1 n 1 m 1 i 1 h 1 d 1 c \u5220\u9664 /etc/default/grub \u6587\u4ef6\u4e2d\u6240\u6709\u4ee5\u7a7a\u767d\u5f00\u5934\u7684\u884c\u884c\u9996\u7684\u7a7a\u767d\u5b57\u7b26\u3002 sed '/^$/d' /etc/default/grub \u5220\u9664 /etc/default/grub \u6587\u4ef6\u4e2d\u6240\u6709\u4ee5 # \u5f00\u5934\uff0c\u540e\u9762\u81f3\u5c11\u8ddf\u4e00\u4e2a\u7a7a\u767d\u5b57\u7b26\u7684\u884c\u7684\u884c\u9996\u7684 # \u548c\u7a7a\u767d\u5b57\u7b26\u3002 sed -r '/#[[:space:]]+/d;/#/d' /etc/default/grub \u4e0a\u9762\u8f93\u51fa\u7ed3\u679c\u4e2d\u5305\u542b\u7a7a\u767d\u884c\u3002 \u82e5\u8f93\u51fa\u4e2d\u5220\u9664\u7a7a\u767d\u884c\uff0c\u5219\uff1a sed -r '/#[[:space:]]+/d;/#/d;/^$/d' /etc/default/grub \u5728 /etc/fstab \u6bcf\u4e00\u884c\u884c\u9996\u589e\u52a0 # \u53f7\u3002 sed -r 's/(.*)/#&/' /etc/fstab \u5728 /etc/fstab \u6587\u4ef6\u4e2d\u4e0d\u4ee5 # \u5f00\u5934\u7684\u884c\u7684\u884c\u9996\u589e\u52a0 # \u53f7\uff08\u5305\u62ec\u7a7a\u884c\uff09\u3002 sed -r 's/^[^#].*/#&/' -r 's/^$/#/' /etc/default/grub \u901a\u8fc7\u547d\u4ee4 rpm -qa --last |awk -F ' ' '{print $1}' \u5f97\u5230\u6700\u65b0\u5b89\u88c5\u7684\u5305\u5217\u8868\u3002\u7edf\u8ba1\u6240\u6709 x86_64 \u7ed3\u5c3e\u7684\u5b89\u88c5\u5305\u540d\u4ee5 . \u5206\u9694\u5012\u6570\u7b2c\u4e8c\u4e2a\u5b57\u6bb5\u7684\u91cd\u590d\u6b21\u6570\u3002 $ rpm -qa --last | awk -F ' ' '{print $1}' | sed -nr '/x86_64$/s@.*\\.(.*)\\.x86_64@\\1@p' | sort -r | uniq -c 75 el9_0 563 el9 3 7 1 5 2 4 2 3 10 2 29 1 \u5728openSUSE\u4e2d\u7edf\u8ba1 /etc/rc.status \u6587\u4ef6\u4e2d\u6bcf\u4e2a\u5355\u8bcd\u7684\u51fa\u73b0\u6b21\u6570\uff0c\u5e76\u6392\u5e8f\uff08\u7528grep\u548csed\u4e24\u79cd\u65b9\u6cd5\u5206\u522b\u5b9e\u73b0\uff09\u3002 grep -Eo \"[a-zA-Z]+\" /etc/rc.status | sort | uniq -c cat /etc/rc.status | sed -r 's/[^[:alpha:]]+/\\n/g' | sed '/^$/d' | sort | uniq -c | sort -nr \u5c06\u6587\u672c\u6587\u4ef6\u7684n\u548cn+1\u884c\u5408\u5e76\u4e3a\u4e00\u884c\uff0cn\u4e3a\u5947\u6570\u884c\u3002 $ cat < sed.txt 1aa 2bb 3cc 4dd 5ee 6ff 7gg EOF $ sed -n 'N;s/\\n//p' sed.txt 1aa2bb 3cc4dd 5ee6ff $ sed 'N;s/\\n//' sed.txt 1aa2bb 3cc4dd 5ee6ff 7gg \u5bf9\u4e00\u4e32\u6570\u5b57\u8fdb\u884c\u6c42\u548c\u3002 $ cat < number.txt 1 2 3 4 5 6 EOF $ tr ' ' + < number.txt | bc 21 $ sum = 0 ; for i in ` cat number.txt ` ; do let sum += i ; done ; echo $sum 21 $ awk '{sum=0;for(i=1;i<=NF;i++){sum+=i};print sum}' number.txt 21 \u53d6\u51fa\u5b57\u7b26\u4e32\u4e2d\u7684\u6570\u5b57\u3002 $ echo 'kdajl;3k8jd33la5kj23f90ld02sakjflakjdslf' | awk -F \"\" ' { for(i=1;i<=NF;i++) { if($i ~ /[0-9]/) { str=(str $i) } }; print str }' 38335239002 host.log \u6587\u4ef6\u5185\u5bb9\u5982\u4e0b\uff0c\u63d0\u53d6 .edu.cn \u524d\u9762\u7684\u4e3b\u673a\u540d\uff0c\u5e76\u56de\u5199\u5230\u8be5\u6587\u4ef6\u4e2d\u3002 $ cat > host.log << EOF 1 www.edu.cn 2 blog.edu.cn 3 learning.edu.cn 4 java.edu.cn 5 nodejs.edu.cn 6 k8s.eud.cn 7 linux.edu.cn 8 python.edu.cn 9 learning.edu.cn 10 java.edu.cn 11 nodejs.edu.cn 12 www.edu.cn EOF # \u5bf9\u6bd4 $ awk -F '[ .]' '{print $1}' host.log 1 2 3 4 5 6 7 8 9 10 11 12 $ awk -F '[ .]' '{print $2}' host.log www blog learning java nodejs k8s linux python learning java nodejs www # \u4ee5\u7a7a\u683c\u6216\u8005.\u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u7b2c\u4e8c\u5217\uff08\u4e3b\u673a\u540d\uff09\uff0c\u8ffd\u52a0\u5199\u5165\u539f\u6587\u4ef6 $ awk -F '[ .]' '{print $2}' host.log >> host.log $ cat host.log 1 www.edu.cn 2 blog.edu.cn 3 learning.edu.cn 4 java.edu.cn 5 nodejs.edu.cn 6 k8s.eud.cn 7 linux.edu.cn 8 python.edu.cn 9 learning.edu.cn 10 java.edu.cn 11 nodejs.edu.cn 12 www.edu.cn www blog learning java nodejs k8s linux python learning java nodejs www \u7edf\u8ba1\u6587\u4ef6 /etc/fstab \u4e2d\u6bcf\u4e2a\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u51fa\u73b0\u7684\u6b21\u6570\u3002 # \u4ee5UUID\u5f00\u5934\uff0c\u4e00\u4e2a\u6216\u591a\u4e2a\u7a7a\u683c\u4e3a\u5206\u9694\u7b26\uff0c\u8bfb\u53d6\u7b2c\u4e09\u5217\uff08\u5373\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\uff09\u5e76\u8ba1\u6570\u3002 $ awk -F ' +' '/^UUID/{fs[$3]++}END{for(i in fs){print i, fs[i]}}' /etc/fstab swap 1 btrfs 10 vfat 1 # \u65b9\u6cd52 $ awk -F ' +' '/^UUID/{print $3}' /etc/fstab | uniq -c 10 btrfs 1 swap 1 vfat \u7edf\u8ba1\u6587\u4ef6 /etc/fstab \u4e2d\u6bcf\u4e2a\u5355\u8bcd\u51fa\u73b0\u7684\u6b21\u6570\u3002 $ awk -F \"[^[:alpha:]]\" '{for(i=1;i<=NF;i++)word[$i]++}END{for(a in word)if(a!=\"\")print a,word[a]}' /etc/fstab swap 2 B 1 srv 2 btrfs 10 snapshots 2 vfat 1 opt 2 cbaef 10 UUID 12 E 1 ecf 1 CD 1 cf 1 arm 2 a 11 c 2 tmp 2 usr 2 var 2 afa 20 home 2 d 10 utf 1 e 2 efi 3 grub 2 boot 3 subvol 9 root 2 local 2 defaults 2 f 10 \u63d0\u53d6\u5b57\u7b26\u4e32 Yd$@C#M05MD9&8923+Vip3wZ!33*44&55 \u4e2d\u6240\u6709\u7684\u6570\u5b57\u3002 # \u5bf9\u6bd4\u5355\u5f15\u53f7\u548c\u53cc\u5f15\u53f7\u7684\u533a\u522b\u3002 $ echo \"Yd $@ C#M05MD9&8923+Vip3wZ!33*44&55\" echo \"Yd $@ C#M05MD9&8923+Vip3wZcgcreate -g cpu:mygroup44&55\" YdC#M05MD9 & 8923 +Vip3wZcgcreate -g cpu:mygroup44 & 55 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' Yd $@ C#M05MD9 & 8923 +Vip3wZ!33*44 & 55 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk '{gsub(/[^0-9]/,\"\");print $0}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '[^0-9]' '{for(i=1;i<=NF;i++){printf \"%s\", $i}}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F \"\" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' # \u6ce8\u610f\uff0c\u5982\u679c\u5199\u6210\u5982\u4e0b\u683c\u5f0f\uff0c\u5219\u62a5\u9519\u3002 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' # \u6ce8\u610f\uff0c\u5982\u679c\u5199\u6210\u5982\u4e0b\u683c\u5f0f\uff0c\u5219\u8f93\u51fa\u539f\u5b57\u7b26\u4e32\u3002 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F ' ' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' \u751f\u6210500\u4e2a\u968f\u673a\u6570\uff0c\u4fdd\u5b58\u5230\u6587\u4ef6random.txt\u4e2d\uff0c\u683c\u5f0f\u4e3a 100,20,61,98... \uff0c\u53d6\u51fa\u5176\u4e2d\u6700\u5927\u6574\u6570\u548c\u6700\u5c0f\u6574\u6570\u3002 $ str = \"\" ; for (( i = 1 ; i< = 500 ; i++ )) ; do if [ $i -ne 500 ] ; then str += \" $RANDOM ,\" ; else str += \" $RANDOM \" ; fi ; done ; echo \" $str \" > random.txt $ cat random.txt 11308 ,8764,2075,9411,...... $ awk -F, '{max=$1;min=$1;for(i=1;i<=NF;i++){if($i>max){max=$i}else{if($i200){system(\"iptables -A INPUT -s \" i \" -j REJECT;\")}}}' \u5c06\u4e0b\u9762\u5185\u5bb9\u4e2dFQDN\u53d6\u51fa\uff0c\u5e76\u6839\u636e\u5176\u8fdb\u884c\u8ba1\u6570\uff0c\u4ece\u9ad8\u5230\u4f4e\u6392\u5e8f\u3002 $ cat > fqdn.txt << EOF http://mail.edu.com/index.html http://www.edu.com/test.html http://study.edu.com/index.html http://blog.edu.com/index.html http://www.edu.com/images/logo.jpg http://blog.edu.com/20080102.html EOF $ awk -F \"/\" '{url[$3]++}END{for(i in url){print url[i], i}}' fqdn.txt | sort -nr 2 www.edu.com 2 blog.edu.com 1 study.edu.com 1 mail.edu.com \u5c06\u4ee5\u4e0b\u2f42\u672c\u4ee5inode\u4e3a\u6807\u8bb0\uff0c\u5bf9inode\u76f8\u540c\u7684counts\u8fdb\u2f8f\u7d2f\u52a0\uff0c\u5e76\u4e14\u7edf\u8ba1\u51fa\u540c\u4e00inode\u4e2d\uff0cbeginnumber\u7684\u6700\u5c0f\u503c\u548cendnumber\u7684\u6700\u5927\u503c\u3002 inode | beginnumber | endnumber | counts | 106 | 3363120000 | 3363129999 | 10000 | 106 | 3368560000 | 3368579999 | 20000 | 310 | 3337000000 | 3337000100 | 101 | 310 | 3342950000 | 3342959999 | 10000 | 310 | 3362120960 | 3362120961 | 2 | 311 | 3313460102 | 3313469999 | 9898 | 311 | 3313470000 | 3313499999 | 30000 | 311 | 3362120962 | 3362120963 | 2 | \u8f93\u51fa\u7684\u7ed3\u679c\u683c\u5f0f\u4e3a\uff1a 310 | 3337000000 | 3362120961 | 10103 | 311 | 3313460102 | 3362120963 | 39900 | 106 | 3363120000 | 3368579999 | 30000 | $ cat > inode.text << EOF inode|beginnumber|endnumber|counts| 106|3363120000|3363129999|10000| 106|3368560000|3368579999|20000| 310|3337000000|3337000100|101| 310|3342950000|3342959999|10000| 310|3362120960|3362120961|2| 311|3313460102|3313469999|9898| 311|3313470000|3313499999|30000| 311|3362120962|3362120963|2| EOF $ awk -F '|' -v OFS = '|' '/^[0-9]/{inode[$1]++; if(!bn[$1]){bn[$1]=$2}else if(bn[$1]>$2) {bn[$1]=$2}; if(en[$1]<$3)en[$1]=$3;cnt[$1]+=$(NF-1)} END{for(i in inode)print i,bn[i],en[i],cnt[i]}' inode.text 106 | 3363120000 | 3368579999 | 30000 310 | 3337000000 | 3362120961 | 10103 311 | 3313460102 | 3362120963 | 39900","title":"\u7b2c\u4e94\u7ae0 \u6b63\u5219\u8868\u8fbe\u5f0f"},{"location":"linux/SRE/05-RegExpress/#_1","text":"\u6b63\u5219\u8868\u8fbe\u5f0f\u5206\u4e24\u7c7b\uff1a \u57fa\u672c\u6b63\u5219\u8868\u8fbe\u5f0f\uff08Basic Regular Expression\uff0c \u53c8\u53ebBasic RegEx\uff0c\u7b80\u79f0BREs\uff09 \u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\uff08Extended Regular Expression\uff0c \u53c8\u53ebExtended RegEx\uff0c\u7b80\u79f0EREs\uff09 Perl\u6b63\u5219\u8868\u8fbe\u5f0f\uff08Perl Regular Expression\uff0c \u53c8\u53ebPerl RegEx \u7b80\u79f0PREs \u57fa\u672c\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u548c\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u533a\u522b\u5c31\u662f\u5143\u5b57\u7b26\u7684\u4e0d\u540c\u3002","title":"\u7b2c\u4e94\u7ae0 \u6b63\u5219\u8868\u8fbe\u5f0f"},{"location":"linux/SRE/05-RegExpress/#51","text":"^ \uff1a\u8868\u793a\u4ee5\u67d0\u4e2a\u5b57\u7b26\u5f00\u59cb $ \uff1a\u8868\u793a\u4ee5\u67d0\u4e2a\u5b57\u7b26\u7ed3\u5c3e . \uff1a\u8868\u793a\u5339\u914d\u4e00\u4e2a\u4e14\u53ea\u5339\u914d\u4e00\u4e2a\u5b57\u7b26 * \uff1a\u8868\u793a\u5339\u914d\u524d\u8fb9\u4e00\u4e2a\u5b57\u7b26\u51fa\u73b00\u6b21\u6216\u8005\u591a\u6b21 [] \uff1a\u8868\u793a\u5339\u914d\u62ec\u53f7\u5185\u7684\u591a\u4e2a\u5b57\u7b26\u4fe1\u606f,\u4e00\u4e2a\u4e00\u4e2a\u5339\u914d .* \uff1a\u8868\u793a\u5339\u914d\u6240\u6709\uff0c\u7a7a\u884c\u4e5f\u4f1a\u8fdb\u884c\u5339\u914d [^] \uff1a\u8868\u793a\u4e0d\u5339\u914d\u62ec\u53f7\u5185\u7684\u6bcf\u4e00\u4e2a\u5b57\u7b26 ^$ \uff1a\u8868\u793a\u5339\u914d\u7a7a\u884c\u4fe1\u606f \\ \uff1a\u5c06\u6709\u7279\u6b8a\u542b\u4e49\u7684\u5b57\u7b26\u8f6c\u4e49\u4e3a\u901a\u914d\u7b26","title":"5.1.\u57fa\u672c\u6b63\u5219\u8868\u8fbe\u5f0f\u7b26\u53f7"},{"location":"linux/SRE/05-RegExpress/#52","text":"+ \uff1a\u8868\u793a\u524d\u4e00\u4e2a\u5b57\u7b26\u51fa\u73b0\u4e00\u6b21\u6216\u4e00\u6b21\u4ee5\u4e0a ? \uff1a\u8868\u793a\u524d\u4e00\u4e2a\u5b57\u7b26\u51fa\u73b00\u6b21\u6216\u8005\u4e00\u6b21\u4ee5\u4e0a | \uff1a\u8868\u793a\u6216\u8005\u7684\u5173\u7cfb,\u5339\u914d\u591a\u4e2a\u4fe1\u606f () \uff1a\u5339\u914d\u4e00\u4e2a\u6574\u4f53\u4fe1\u606f\uff0c\u4e5f\u53ef\u4ee5\u63a5\u540e\u9879\u5f15\u7528 {} \uff1a\u5b9a\u4e49\u524d\u8fb9\u5b57\u7b26\u51fa\u73b0\u51e0\u6b21 \u63d0\u793a\uff1a grep -E \u6216\u8005 egrep \u53ea\u662f\u8868\u793a\u6269\u5c55\u6b63\u5219\uff0c\u4e0d\u4ee3\u8868\u52a0\u4e86e\u5c31\u8868\u793a\u8f6c\u4e49\u4e86\u3002 \u5f53 grep \u4f7f\u7528\u6269\u5c55\u6b63\u5219\u7684\u7b26\u53f7\u65f6\u5019\u9700\u8981\u7528 \\ \u8f6c\u4e49\u4e3a\u901a\u914d\u7b26\u624d\u80fd\u4f7f\u7528\u3002","title":"5.2.\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\u7b26\u53f7"},{"location":"linux/SRE/05-RegExpress/#53","text":"[:alpha:] \uff1a\u8868\u793a\u6240\u6709\u7684\u5b57\u6bcd\uff08\u4e0d\u533a\u5206\u5927\u5c0f\u5199\uff09\uff0c\u6548\u679c\u540c [a-z] [:digit:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u6570\u5b57\uff0c\u6548\u679c\u540c [0-9] [:xdigit:] \uff1a\u8868\u793a\u5341\u516d\u8fdb\u5236\u6570\u5b57 [:lower:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5c0f\u5199\u5b57\u6bcd [:upper:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5927\u5199\u5b57\u6bcd [:alnum:] \uff1a\u8868\u793a\u4efb\u610f\u5355\u4e2a\u5b57\u6bcd\u6216\u6570\u5b57 [:blank:] \uff1a\u8868\u793a\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u548c\u5236\u8868\u7b26\uff09 [:space:] \uff1a\u8868\u793a\u5305\u62ec\u7a7a\u683c\u3001\u5236\u8868\u7b26\uff08\u6c34\u5e73\u548c\u5782\u76f4\uff09\u3001\u6362\u884c\u7b26\u3001\u56de\u8f66\u7b26\u7b49\u5404\u79cd\u7c7b\u578b\u7684\u7a7a\u767d\uff0c\u6bd4 [:blank:] \u8303\u56f4\u66f4\u5e7f [:cntrl:] \uff1a\u8868\u793a\u4e0d\u53ef\u6253\u5370\u7684\u63a7\u5236\u5b57\u7b26\uff08\u9000\u683c\u3001\u5220\u9664\u3001\u8b66\u94c3\u7b49\uff09 [:graph:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u7684\u975e\u7a7a\u767d\u5b57\u7b26 [:print:] \uff1a\u8868\u793a\u53ef\u6253\u5370\u5b57\u7b26 [:punct:] \uff1a\u8868\u793a\u6807\u70b9\u7b26\u53f7","title":"5.3.\u5b57\u7b26\u5339\u914d"},{"location":"linux/SRE/05-RegExpress/#54","text":"\u4f4d\u7f6e\u6807\u8bb0\u951a\u70b9\uff08position marker anchor\uff09\u662f\u6807\u8bc6\u5b57\u7b26\u4e32\u4f4d\u7f6e\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6b63\u5219\u8868\u8fbe\u5f0f\u6240\u5339\u914d\u7684\u5b57\u7b26\u53ef\u4ee5\u51fa\u73b0\u5728\u5b57\u7b26\u4e32\u4e2d\u4efb\u4f55\u4f4d\u7f6e\u3002 ^ \uff1a\u884c\u9996\u951a\u5b9a\uff0c\u6307\u5b9a\u4e86\u5339\u914d\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u6587\u672c\u5fc5\u987b\u8d77\u59cb\u4e8e\u5b57\u7b26\u4e32\u7684\u9996\u90e8\u3002 \u4f8b\u5982\uff1a ^tux \u80fd\u591f\u5339\u914d\u4ee5 tux \u8d77\u59cb\u7684\u884c $ \uff1a\u884c\u5c3e\u951a\u5b9a\uff0c\u6307\u5b9a\u4e86\u5339\u914d\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u6587\u672c\u5fc5\u987b\u7ed3\u675f\u4e8e\u76ee\u6807\u5b57\u7b26\u4e32\u7684\u5c3e\u90e8\u3002 \\< \u6216 \\b \uff1a\u8bcd\u9996\u951a\u5b9a\uff0c\u7528\u4e8e\u5355\u8bcd\u6a21\u5f0f\u5339\u914d\u5de6\u4fa7\u3002\uff08\u5355\u8bcd\u662f\u6709\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u4e0b\u5212\u7ebf\u7ec4\u6210\uff09 \\> \u6216 \\b \uff1a\u8bcd\u5c3e\u951a\u5b9a\uff0c\u7528\u4e8e\u5355\u8bcd\u6a21\u5f0f\u5339\u914d\u53f3\u4fa7\u3002\uff08\u5355\u8bcd\u662f\u6709\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u4e0b\u5212\u7ebf\u7ec4\u6210\uff09 ^PATTERN$ \uff1a\u7528\u6a21\u5f0fPATTERN\u5339\u914d\u6574\u884c\u3002 ^$ \uff1a\u5339\u914d\u7a7a\u884c\u3002 ^[[:space:]]*$ \uff1a\u5339\u914d\u7a7a\u767d\u884c\uff08\u6574\u884c\uff09\u3002 \\ \uff1a\u5339\u914d\u6574\u4e2a\u5355\u8bcd\u3002\uff08\u5355\u8bcd\u662f\u6709\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u4e0b\u5212\u7ebf\u7ec4\u6210\uff09 \u5173\u4e8e\u884c\u9996\u951a\u5b9a\u548c\u8bcd\u9996\u951a\u5b9a\uff0c\u5bf9\u6bd4\u4e0b\u9762\u4f8b\u5b50\u3002\u8bcd\u5c3e\u951a\u5b9a\u4e5f\u662f\u7c7b\u4f3c\u60c5\u51b5\u3002 ; \u548c - \u90fd\u88ab\u8ba4\u5b9a\u4e3a\u5355\u8bcd\u5206\u9694\u7b26\u3002 # \u7b26\u5408\u8bcd\u9996\u5339\u914d $ echo \"tux_01-tux02\" | grep '\\ mtu 1500 inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 inet6 fe80::20c:29ff:fea4:e17a prefixlen 64 scopeid 0x20 ether 00 :0c:29:a4:e1:7a txqueuelen 1000 ( Ethernet ) RX packets 7654 bytes 635932 ( 621 .0 KiB ) RX errors 0 dropped 1 overruns 0 frame 0 TX packets 1934 bytes 279649 ( 273 .0 KiB ) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 $ ifconfig eth0 | grep netmask | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' 192 .168.10.210 255 .255.255.0 192 .168.10.255 $ ifconfig eth0 | grep netmask | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' | head -n 1 192 .168.10.210 $ ifconfig eth0 | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' 192 .168.10.210 255 .255.255.0 192 .168.10.255 ifconfig eth0 | grep -o '[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}\\.[0-9]\\{1,3\\}' | head -n 1 192 .168.10.210 \u5339\u914d\u7a7a\u884c\u548c\u975e\u7a7a\u884c\uff1a grep '^$' /etc/profile grep -v '^$' /etc/profile \u5339\u914d\u975e\u7a7a\u884c\u548c\u975e#\u5f00\u5934\u7684\u884c\uff1a\uff08\u4e09\u79cd\u65b9\u6cd5\uff09 grep -v '^$' /etc/profile | grep -v '^#' grep -v '^$\\|#' /etc/profile grep '^[^$#]' /etc/profile \u6ce8\u610f\uff0c\u5982\u679c\u5199\u6210\u4e0b\u9762\u8fd9\u6837\uff0c\u5219\u4e0d\u4f1a\u8fc7\u6ee4\u6389\u7a7a\u884c\uff0c [$] \u4f1a\u88ab\u89c6\u4e3a $ \u7b26\u53f7\u3002 \u6240\u4ee5\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u5143\u5b57\u7b26\u653e\u5728\u4e2d\u62ec\u53f7 [] \u5185\u5c31\u88ab\u89c6\u4e3a\u666e\u901a\u5b57\u7b26\u3002 grep -v '^[$#]' /etc/profile","title":"5.7.\u5206\u7ec4"},{"location":"linux/SRE/05-RegExpress/#58grep","text":"\u683c\u5f0f\uff1a grep [OPTIONS] PATTERN [FILE...] grep [OPTIONS] -e PATTERN ... [FILE...] grep [OPTIONS] -f FILE ... [FILE...] \u53c2\u6570\uff1a -n \uff1a\u663e\u793a\u8fc7\u6ee4\u51fa\u6765\u7684\u6587\u4ef6\u5728\u6587\u4ef6\u5f53\u4e2d\u7684\u884c\u53f7 -c \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u884c\u6570 -o \uff1a\u53ea\u663e\u793a\u5339\u914d\u5230\u7684\u5185\u5bb9 -q \uff1a\u9759\u9ed8\u8f93\u51fa\uff08\u4e00\u822c\u7528\u5728shell\u811a\u672c\u5f53\u4e2d\uff0c\u901a\u8fc7 echo $? \u67e5\u770b\u547d\u4ee4\u6267\u884c\u7ed3\u679c\uff0c0\u8868\u793a\u6210\u529f\uff0c\u975e0\u8868\u793a\u5931\u8d25\uff09\uff09 -i \uff1a\u5ffd\u7565\u5927\u5c0f\u5199 -v \uff1a\u53cd\u5411\u67e5\u627e -w \uff1a\u5339\u914d\u67d0\u4e2a\u8bcd\u8bcd\uff1a\u5728Linux\u4e2d\uff0c\u8bcd\u4e3a\u4e00\u8fde\u4e32\u5b57\u6bcd\u3001\u6570\u5b57\u548c\u4e0b\u5212\u7ebf\u7ec4\u6210\u7684\u5b57\u7b26\u4e32 -E \uff1a\u4f7f\u7528\u6269\u5c55\u6b63\u5219 -R \uff1a\u9012\u5f52\u67e5\u8be2 -l \uff1a\u53ea\u6253\u5370\u6587\u4ef6\u8def\u5f84 \u6269\u5c55\u53c2\u6570\uff1a -A \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u6570\u636e\u7684\u540e\u51e0n\u884c -B \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u6570\u636e\u7684\u524d\u51e0n\u884c -C \uff1a\u663e\u793a\u5339\u914d\u5230\u7684\u6570\u636e\u7684\u524d\u540e\u5404\u51e0n\u884c \u793a\u4f8b\uff1a \u5339\u914d\u7528\u6237\uff1a grep root /etc/passwd root:x:0:0:root:/root:/bin/bash $ grep \"USER\" /etc/passwd $ grep \" $USER \" /etc/passwd vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash $ grep '$USER' /etc/passwd \u5339\u914d\u5173\u952e\u5b57\uff1a $ grep processor /proc/cpuinfo processor : 0 processor : 1 $ grep -o processor /proc/cpuinfo processor processor $ grep \"cpu family\" /proc/cpuinfo cpu family : 6 cpu family : 6 $ grep -o \"cpu family\" /proc/cpuinfo cpu family cpu family \u901a\u8fc7grep\u8fdb\u884c\u6587\u4ef6\u6bd4\u8f83\u3002 # \u6700\u540e\u4e00\u884c\u662f\u7a7a\u884c $ cat f1 a b 1 c # \u6700\u540e\u4e00\u884c\u662f\u7a7a\u884c $ cat f2 b e f c 1 2 # \u9ad8\u4eae\u663e\u793a\u76f8\u540c\u5185\u5bb9\u7684\u884c\uff0c\u5305\u542b\u6700\u540e\u4e00\u884c\u7a7a\u884c $ grep -f f1 f2 b e f c 1 2 # \u53ea\u663e\u793a\u76f8\u540c\u5185\u5bb9\u7684\u884c\uff0c\u5305\u542b\u6700\u540e\u4e00\u884c\u7a7a\u884c $ grep -wf f1 f2 b c 1 # \u53ea\u663e\u793a\u4e0d\u540c\u5185\u5bb9\u7684\u884c $ grep -wvf f1 f2 e f 2 \u63d0\u793a\uff1a grep -wvf f1 f2 \u6216\u8005 grep -w -v -f f1 f2 \u4e2d\uff0c -f \u53ea\u80fd\u4f5c\u4e3a\u6700\u540e\u4e00\u4e2a\u53c2\u6570\uff0c\u5426\u5219\u4f1a\u62a5\u9519\u3002 \u4f53\u4f1a\u57fa\u672c\u6b63\u5219\u548c\u6269\u5c55\u6b63\u5219\u7684\u5dee\u5f02\u3002 \u4f8b1\uff1a\u8f6c\u4e49\u3002 # \u4e0b\u9762\u51e0\u4e2a\u547d\u4ee4\u8fd4\u56de\u7684\u7ed3\u679c\u662f\u4e00\u6837\u7684\u3002 $ grep \"root\\|bash\" /etc/passwd $ grep -E \"root|bash\" /etc/passwd $ grep -e \"root\" -e \"bash\" /etc/passwd # \u4e0b\u9762\u7684\u547d\u4ee4\u6ca1\u6709\u5339\u914d\u7ed3\u679c\u8fd4\u56de\u3002 $ grep \"root|bash\" /etc/passwd \u4f8b2\uff1a\u4e0b\u97624\u4e2a\u547d\u4ee4\u8fd4\u56de\u540c\u6837\u7684\u7ed3\u679c\u3002 grep \"root\" /etc/passwd grep -E \"root\" /etc/passwd grep \"\\\" /etc/passwd grep -E \"\\\" /etc/passwd \u4f8b3\uff1a\u884c\u9996\u884c\u5c3e\u951a\u5b9a\u3002 $ grep \"^\\(.*\\)\\>.*\\<\\1 $ \" /etc/passwd $ grep -E \"^(.*)\\>.*\\<\\1 $ \" /etc/passwd $ egrep \"^(.*)\\>.*\\<\\1 $ \" /etc/passwd sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt \u4f8b4\uff1a\u4e09\u79cd\u65b9\u6cd5\u6c42\u548c\u8ba1\u7b97\uff0c\u8fd0\u7528 grep \uff0c cut \uff0c bc \u548c paste \u547d\u4ee4\u3002 $cat age Jason = 20 Tom = 30 Jack = 40 # \u65b9\u6cd51 $ cat age | cut -d \"=\" -f 2 | tr \"\\n\" + | grep -Eo \".*[0-9]\" | bc 90 # \u65b9\u6cd52 $ grep -Eo \"[0-9]+\" age | tr \"\\n\" + | grep -Eo \".*[0-9]\" | bc 90 # \u65b9\u6cd53 $ grep -Eo \"[0-9]+\" age | paste -s -d \"+\" | bc 90","title":"5.8.\u4e09\u5251\u5ba2grep\u547d\u4ee4"},{"location":"linux/SRE/05-RegExpress/#59sed","text":"sed \u662fstream editor\u7684\u7f29\u5199\uff0c\u4e2d\u6587\u79f0\u4e4b\u4e3a\u201c\u6d41\u7f16\u8f91\u5668\u201d\u3002 sed \u547d\u4ee4\u662f\u4e00\u4e2a\u9762\u5411\u884c\u5904\u7406\u7684\u5de5\u5177\uff0c\u5b83\u4ee5\u201c\u884c\u201d\u4e3a\u5904\u7406\u5355\u4f4d\uff0c\u9488\u5bf9\u6bcf\u4e00\u884c\u8fdb\u884c\u5904\u7406\uff0c\u5904\u7406\u540e\u7684\u7ed3\u679c\u4f1a\u8f93\u51fa\u5230\u6807\u51c6\u8f93\u51fa STDOUT \uff0c\u4e0d\u4f1a\u5bf9\u8bfb\u53d6\u7684\u6587\u4ef6\u505a\u4efb\u4f55\u4fee\u6539\u3002 sed \u7684\u5de5\u4f5c\u539f\u7406\uff1a sed \u547d\u4ee4\u662f\u9762\u5411\u201c\u884c\u201d\u8fdb\u884c\u5904\u7406\u7684\uff0c\u6bcf\u4e00\u6b21\u5904\u7406\u4e00\u884c\u5185\u5bb9\u3002 \u5904\u7406\u65f6\uff0c sed \u4f1a\u628a\u8981\u5904\u7406\u7684\u884c\u5b58\u50a8\u5728\u7f13\u51b2\u533a\u4e2d\uff0c\u63a5\u7740\u7528 sed \u547d\u4ee4\u5904\u7406\u7f13\u51b2\u533a\u4e2d\u7684\u5185\u5bb9\uff0c\u5904\u7406\u5b8c\u6210\u540e\uff0c\u628a\u7f13\u51b2\u533a\u7684\u5185\u5bb9\u9001\u5f80\u5c4f\u5e55\u3002\u63a5\u7740\u5904\u7406\u4e0b\u4e00\u884c\uff0c\u8fd9\u6837\u4e0d\u65ad\u91cd\u590d\uff0c\u76f4\u5230\u6587\u4ef6\u672b\u5c3e\u3002\u8fd9\u4e2a\u7f13\u51b2\u533a\u88ab\u79f0\u4e3a\u201c \u6a21\u5f0f\u7a7a\u95f4 \u201d\uff08pattern space\uff09\u3002 \u4fdd\u6301\u7a7a\u95f4(hold space) sed \u7684\u4fdd\u6301\u7a7a\u95f4\u50cf\u4e00\u4e2a\u957f\u671f\u50a8\u5b58\uff0c \u53ef\u4ee5\u628a\u83b7\u53d6\u7684\u4fe1\u606f\u50a8\u5b58\u5230\u5176\u4e2d\uff0c\u5f85\u540e\u7eed\u8c03\u7528\u3002\u4e0d\u80fd\u76f4\u63a5\u5bf9\u4fdd\u6301\u7a7a\u95f4\u8fdb\u884c\u64cd\u4f5c\uff0c \u800c\u662f\u5c06\u4fdd\u6301\u7a7a\u95f4\u7684\u5185\u5bb9\u590d\u5236\u6216\u8005\u6dfb\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u8fdb\u884c\u64cd\u4f5c\u3002 \u975e\u4ea4\u4e92\u5f0f\u6279\u91cf\u4fee\u6539\u6587\u4ef6\u3002 sed \u547d\u4ee4\u683c\u5f0f\uff1a sed [ option ] command file option \u5e38\u7528\u9009\u9879\uff1a -n \uff1a\u4e0d\u8f93\u51fa\u6a21\u5f0fpattern\u7684\u5185\u5bb9\u5230\u5c4f\u5e55\uff08\u5373\u4e0d\u81ea\u52a8\u6253\u5370\uff09 -e \uff1a\u591a\u70b9\u7f16\u8f91 -f filename \uff1a\u4ece\u6307\u5b9a\u6587\u4ef6\u8bfb\u53d6\u7f16\u8f91\u811a\u672c -r \uff0c -E \uff1a\u4f7f\u7528\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f -i .bak \uff1a\u5907\u4efd\u6587\u4ef6\u5e76\u539f\u5904\u7f16\u8f91 -s \uff1a\u5c06\u591a\u4e2a\u6587\u4ef6\u89c6\u4e3a\u72ec\u7acb\u6587\u4ef6\uff0c\u800c\u4e0d\u662f\u5355\u4e2a\u8fde\u7eed\u7684\u957f\u6587\u4ef6\u6d41 -ir \uff1a \u4e0d\u652f\u6301 -i -r \uff1a \u652f\u6301 -ri \uff1a \u652f\u6301 -ni \uff1a \u5371\u9669\u9009\u9879\uff0c\u4f1a\u6e05\u7a7a\u6587\u4ef6 command \u90e8\u5206\u53ef\u4ee5\u5206\u4e3a\u4e24\u90e8\u5206\uff1a \u8303\u56f4\u8bbe\u5b9a\uff0c\u53ef\u4ee5\u91c7\u7528\u4e24\u79cd\u4e0d\u540c\u7684\u65b9\u5f0f\u6765\u8868\u8fbe\uff1a \u6307\u5b9a\u884c\u6570\uff1a\u5982\uff1a 3,5 \u8868\u793a\u7b2c3\u30014\u30015\u884c 5,$ \u8868\u793a\u7b2c5\u884c\u81f3\u6587\u4ef6\u6700\u540e\u4e00\u884c \u6a21\u5f0f\u5339\u914d\uff1a\u5982\uff1a /^[^dD]/ \u8868\u793a\u5339\u914d\u884c\u9996\u4e0d\u662f\u4ee5 d \u6216 D \u5f00\u5934\u7684\u884c \u52a8\u4f5c\u5904\u7406\uff0c\u4e0b\u9762\u662f\u5e38\u7528\u7684\u52a8\u4f5c\uff1a a \uff1a\u65b0\u589e\uff0c a \u540e\u9762\u7684\u5b57\u4e32\u4f1a\u5728\u65b0\u7684\u4e00\u884c\u51fa\u73b0\uff08\u5f53\u524d\u884c\u7684\u4e0b\u4e00\u884c\uff09 i \uff1a\u63d2\u5165\uff0c i \u540e\u9762\u7684\u5b57\u4e32\u4f1a\u5728\u65b0\u7684\u4e00\u884c\u51fa\u73b0\uff08\u5f53\u524d\u884c\u7684\u4e0a\u4e00\u884c\uff09 r filename \uff1a\u8bfb\u53d6\u6307\u5b9a\u6587\u4ef6 fllename \u7684\u5185\u5bb9\uff0c\u8ffd\u52a0\u5230\u5f53\u524d\u884c\u7684\u4e0b\u4e00\u884c R filename \uff1a\u8bfb\u53d6\u6307\u5b9a\u6587\u4ef6 fllename \u7684\u4e00\u884c\uff0c\u8ffd\u52a0\u5230\u5f53\u524d\u884c\u7684\u4e0b\u4e00\u884c d \uff1a\u5220\u9664\u8be5\u884c p \uff1a\u6253\u5370\u8be5\u884c Ip \uff1a\u5ffd\u7565\u5927\u5c0f\u5199\u8f93\u51fa w filename \uff1a\u5199\u5165\u5230\u6307\u5b9a\u6587\u4ef6filename\u4e2d\u3002 s/regexp/replacement/ \uff1a\u53d6\u4ee3\uff0c\u7528replacement\u53d6\u4ee3\u6b63\u5219regexp\u5339\u914d\u5230\u7684\u5185\u5bb9 = \uff1a\u4e3a\u6a21\u5f0fpattern\u4e2d\u7684\u5339\u914d\u884c\u6253\u5370\u884c\u53f7 ! \uff1a\u4e3a\u6a21\u5f0fpattern\u4e2d\u7684\u5339\u914d\u884c\u53d6\u53cd\u64cd\u4f5c q \uff1a\u7ed3\u675f\u6216\u9000\u51fased \u521b\u5efa\u4e00\u4e2a testfile \u6587\u4ef6\u3002 $ cat < testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob Tesetfile Wiki EOF \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u7b2c\u4e8c\u884c\uff0c\u5e76\u8f93\u51fa\uff08\u5305\u542b\u5339\u914d\u7b2c\u4e8c\u884c\u548c\u8f93\u51fa\u7b2c\u4e8c\u884c\uff09\u3002 # nl testfile | sed '2p' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u7b2c\u4e8c\u884c\uff0c\u4e0d\u8f93\u51fa\u3002 # nl testfile | sed -n '2p' 2 Linux is a free unix-type opterating system. \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u6700\u540e\u4e00\u884c\u3002 $ nl testfile | sed -n '$p' 9 Wiki \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u5012\u6570\u7b2c\u4e8c\u884c\u3002 # sed -n \"$(echo $[`cat testfile | wc -l`-1])p\" testfile Tesetfile \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u7b2c2\uff5e3\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\u3002 $ nl testfile | sed -n '2,3p' 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! \u5c06 testfile \u7684\u5185\u5bb9\u4ece\u7b2c2\u884c\u5f00\u59cb\uff0c\u5411\u540e\u8f93\u51fa\u989d\u5916\u76843\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\u3002 $ nl testfile | sed -n '2,+3p' 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test 5 Google \u5c06 testfile \u7684\u5185\u5bb9\u4ece\u7b2c2\u884c\u5f00\u59cb\uff0c\u5411\u540e\u4ee52\u4e3a\u6b65\u8fdb\u5355\u4f4d\u8f93\u51fa\u6240\u6709\u5339\u914d\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff08\u5373\uff0c\u4ece\u7b2c2\u884c\u5f00\u59cb\u8f93\u51fa\u5076\u6570\u884c\uff09\u3002 nl testfile | sed -n '2~2p' 2 Linux is a free unix-type opterating system. 4 Linux test 6 Taobao 8 Tesetfile \u5c06 testfile \u7684\u5185\u5bb9\u4ece\u7b2c2\u884c\u5f00\u59cb\uff0c\u5411\u540e\u4ee52\u4e3a\u6b65\u8fdb\u5355\u4f4d\u5220\u9664\u6240\u6709\u5339\u914d\u884c\uff0c\u8f93\u51fa\u5269\u4f59\u884c\uff0c\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff08\u5373\uff0c\u4ece\u7b2c2\u884c\u5f00\u59cb\u5220\u9664\u5076\u6570\u884c\uff0c\u8f93\u51fa\u5947\u6570\u884c\uff09\u3002 $ nl testfile | sed '2~2d' 1 HELLO LINUX! 3 This is a linux testfile! 5 Google 7 Banbooob 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u8f93\u51fa\uff0c\u5220\u9664\u7b2c2\u884c\u548c\u7b2c5\u884c\uff0c\u5e76\u6253\u5370\u884c\u53f7\u3002 $ nl testfile | sed -e '2d' -e '5d' $ nl testfile | sed -e '2d;5d' $ nl testfile | sed '2d;5d' 1 HELLO LINUX! 3 This is a linux testfile! 4 Linux test 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u8f93\u51fa\uff0c\u8f93\u51fa\u533a\u95f4\u662f\u4ece\u884c\u9996 L \u7684\u884c\u5230\u884c\u9996 G \u7684\u884c\u7ed3\u675f\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 \u5982\u679c\u884c\u9996\u5339\u914d\u4e0d\u5230\uff0c\u5219\u65e0\u7ed3\u679c\u8f93\u51fa\uff1b\u5982\u679c\u884c\u5c3e\u5339\u914d\u4e0d\u5230\uff0c\u5219\u8f93\u51fa\u5230\u6587\u4ef6\u7ed3\u675f\u3002 $ sed -n '/^L/,/^G/p' testfile Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google \u5c06 testfile \u7684\u5185\u5bb9\u8f93\u51fa\uff0c\u4e14\u5728\u7b2c6\u884c\u540e\u52a0\u4e0a I love Linux \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -e '6a I love Linux' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao I love Linux Banbooob Tesetfile Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5728\u7b2c6\u884c\u540e\u6dfb\u52a0 I love Linux \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '6a I love Linux' $ nl testfile | sed '6a\\I love Linux' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao I love Linux 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5728\u7b2c3\u884c\u524d\u6dfb\u52a0 I am a journer learner \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '3i\\I am a journer learner' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. I am a journer learner 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5728\u7b2c3\u884c\u524d\u6dfb\u52a0\u4e09\u884c\u5185\u5bb9 Add line 1 \uff0c Add line 2 \uff0c Add line 3 \u3002\u7528\u7b26\u5408 \\ \u8fdb\u884c\u6362\u884c\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '3i\\Add line 1 \\ Add line 2 \\ Add line 3' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. Add line 1 Add line 2 Add line 3 3 This is a linux testfile! 4 Linux test 5 Google 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5c06\u7b2c2-5\u884c\u7684\u5185\u5bb9\u53d6\u4ee3\u6210\u4e3a replaced \u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '2,5c\\replaced' $ nl testfile | sed '2,5c replaced' $ nl testfile | sed '2,5creplaced' 1 HELLO LINUX! replaced 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5220\u9664\u7b2c2~5\u884c\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ nl testfile | sed '2,5d' 1 HELLO LINUX! 6 Taobao 7 Banbooob 8 Tesetfile 9 Wiki \u5c06 testfile \u7684\u5185\u5bb9\u5217\u51fa\u5e76\u4e14\u6253\u5370\u884c\u53f7\uff0c\u4e14\u5220\u9664\u7b2c5\u884c\u5230\u6700\u540e\u4e00\u884c\u3002 $ nl testfile | sed '5,$d' 1 HELLO LINUX! 2 Linux is a free unix-type opterating system. 3 This is a linux testfile! 4 Linux test \u5339\u914d\u5b9a\u4f4d\u6587\u4ef6 testfile \u4e2d\u5305\u542b\u5173\u952e\u5b57 linux \u7684\u884c\u3002 $ sed -n '/linux/p' testfile This is a linux testfile! \u5339\u914d\u5b9a\u4f4d\u547d\u4ee4 df \u8f93\u51fa\u4e2d\u4ee5 /dev/sd \u5173\u952e\u5b57\u5f00\u5934\u7684\u884c\u3002\uff08\u9700\u8981\u8f6c\u4e49\u7b26 \\ \uff09 $ df | sed -n '/^\\/dev\\/sd/p' /dev/sda2 102750208 7077280 92055312 8 % / /dev/sda2 102750208 7077280 92055312 8 % /.snapshots /dev/sda2 102750208 7077280 92055312 8 % /home /dev/sda2 102750208 7077280 92055312 8 % /opt /dev/sda2 102750208 7077280 92055312 8 % /root /dev/sda2 102750208 7077280 92055312 8 % /boot/grub2/x86_64-efi /dev/sda2 102750208 7077280 92055312 8 % /boot/grub2/i386-pc /dev/sda2 102750208 7077280 92055312 8 % /srv /dev/sda2 102750208 7077280 92055312 8 % /tmp /dev/sda2 102750208 7077280 92055312 8 % /usr/local /dev/sda2 102750208 7077280 92055312 8 % /var \u5339\u914d\u5b9a\u4f4d\u547d\u4ee4 df \u8f93\u51fa\u4e2d\u4e0d\u4ee5 /dev/sd \u5173\u952e\u5b57\u5f00\u5934\u7684\u884c\u3002\u901a\u8fc7 !p \u8fdb\u884c\u6c42\u53cd\u8f93\u51fa\u3002 $ df | sed -n '/^\\/dev\\/sd/!p' Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 4096 0 4096 0 % /dev tmpfs 1971208 0 1971208 0 % /dev/shm tmpfs 788484 9612 778872 2 % /run tmpfs 4096 0 4096 0 % /sys/fs/cgroup tmpfs 394240 0 394240 0 % /run/user/1000 \u5339\u914d\u5b9a\u4f4d\u547d\u4ee4 df \u8f93\u51fa\u4e2d\u4e0d\u4ee5 /dev/sd \u548c tmp \u5173\u952e\u5b57\u5f00\u5934\u7684\u884c\u3002 $ df | sed '/^\\/dev\\/sd/d;/^tmp/d' Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 4096 0 4096 0 % /dev $ df | grep -Ev '^\\/dev\\/sd|^tmp' Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 4096 0 4096 0 % /dev \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b oo \u5173\u952e\u5b57\u7684\u884c\u5e76\u5339\u914d\u8f93\u51fa\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -n '/ooo/p' testfile Banbooob $ sed -n '/oo/p' testfile Google Banbooob \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b oo \u5173\u952e\u5b57\u7684\u884c\u5e76\u5220\u9664\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed '/oo/d' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Taobao Tesetfile Wiki \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b oo \u7684\u884c\uff0c\u628a oo \u66ff\u6362\u4e3a kk \uff0c\u518d\u8f93\u51fa\u8fd9\u884c\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -n '/oo/{s/oo/kk/;p;q}' testfile $ sed -ne '/oo/{s/oo/kk/;p;q}' testfile Gkkgle \u5c06 testfile \u7684\u6bcf\u884c\u4e2d\u7b2c\u4e00\u6b21\u51fa\u73b0 ao \u7684\u66ff\u6362\u6210 HH \u3002 $ sed 's/ao/HH/' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbao Banbooob Tesetfile Wiki \u4e0b\u9762\u662f\u628a testfile \u7684\u5339\u914d\u5230 ao \u7684\u884c\u66ff\u6362\u6210 HH \u3002 sed '/ao/cHH' testfile HELLO LINUX! SUSE This is a linux testfile! SUSE Google Taobao Banbooob Tesetfile Wiki \u641c\u7d22\u6587\u4ef6 testfile \u6240\u6709\u5305\u542b ao \u7684\u5168\u90e8\u66ff\u6362\u6210 HH \u3002 g \u8868\u793a\u5168\u5c40\u5339\u914d\u3002\u4e0d\u4fee\u6539\u539f\u6587\u4ef6\u3002 $ sed -e 's/ao/HH/g' testfile $ sed 's/ao/HH/g' testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbHH Banbooob Tesetfile Wiki \u5728\u6587\u4ef6 /etc/passwd \u4e2d\u67e5\u627e\u5339\u914d\u6240\u6709\u7b26\u5408 r \u5f00\u5934 t \u7ed3\u5c3e\u4e14\u4e2d\u95f4\u542b\u4efb\u610f\u4e24\u4e2a\u5b57\u7b26\u7684\u884c\uff0c\u5e76\u5728 t \u5b57\u6bcd\u540e\u6dfb\u52a0 er \u3002 $ sed -nr 's/r..t/&er/gp' /etc/passwd rooter:x:0:0:rooter:/rooter:/bin/bash lp:x:493:487:Printering daemon:/var/spool/lpd:/usr/sbin/nologin tftp:x:487:474:TFTP account:/srv/terftpboot:/bin/false vagranter:x:1000:478:vagranter:/home/vagranter:/bin/bash tester1:x:600:1530: \"Test User1,terestuser1@abc.com\" :/home/tester1:/bin/bash \u5c06\u4e0a\u8ff0\u7ed3\u679c\u548c\u539f\u59cb\u5185\u5bb9\u8fdb\u884c\u5bf9\u6bd4\uff0c\u80fd\u66f4\u597d\u7684\u7406\u89e3 s/r..t/&er \u7684\u64cd\u4f5c\u3002 rooter:x:0:0:rooter:/rooter:/bin/bash root:x:0:0:root:/root:/bin/bash lp:x:493:487:Printering daemon:/var/spool/lpd:/usr/sbin/nologin lp:x:493:487:Printing daemon:/var/spool/lpd:/usr/sbin/nologin tftp:x:487:474:TFTP account:/srv/terftpboot:/bin/false tftp:x:487:474:TFTP account:/srv/tftpboot:/bin/false vagranter:x:1000:478:vagranter:/home/vagranter:/bin/bash vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash tester1:x:600:1530: \"Test User1,terestuser1@abc.com\" :/home/tester1:/bin/bash tester1:x:600:1530: \"Test User1,testuser1@abc.com\" :/home/tester1:/bin/bash \u4f53\u4f1a & \u7684\u4f4d\u7f6e\u4e0d\u540c\u7684\u4e0d\u540c\u542b\u4e49\u3002 # \u9644\u52a0\u5728root\u5355\u8bcd\u540e $ sed -n 's/root/&superman/p' /etc/passwd rootsuperman:x:0:0:root:/root:/bin/bash # \u9644\u52a0\u5728root\u5355\u8bcd\u524d $ sed -n 's/root/superman&/p' /etc/passwd supermanroot:x:0:0:root:/root:/bin/bash \u4f7f\u7528\u53c2\u6570 -i \u8fdb\u884c\u6e90\u6587\u4ef6\u4fee\u6539\u3002 $ sed -i 's/ao/HH/' testfile $ cat testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbao Banbooob Tesetfile Wiki \u6e90\u6587\u4ef6\u4fee\u6539\u524d\uff0c\u5907\u4efd\u5728\u65b0\u6587\u4ef6 testfile.new \u3002 $ sed -i.new 's/ao/HH/' testfile $ cat testfile.new HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob Tesetfile Wiki $ cat testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google THHbao Banbooob Tesetfile Wiki \u8303\u4f8b\uff1a\u9664\u6307\u5b9a\u6587\u4ef6\u5916\uff0c\u5176\u4f59\u90fd\u5220\u9664\u3002 $ touch { 1 ..9 } file.txt $ ls 1file.txt 2file.txt 3file.txt 4file.txt 5file.txt 6file.txt 7file.txt 8file.txt 9file.txt $ ls | grep -E '(3|5|7)file\\.txt' 3file.txt 5file.txt 7file.txt $ ls | grep -Ev '(3|5|7)file\\.txt' 1file.txt 2file.txt 4file.txt 6file.txt 8file.txt 9file.txt \u4e0b\u9762\u56db\u79cd\u65b9\u6cd5\u5b9e\u73b0\u540c\u6837\u7684\u529f\u80fd $ rm ` ls | grep -Ev '(3|5|7)file\\.txt' ` $ ls | sed -n '/^[357]file.txt/!p' | xargs rm $ ls | grep -Ev '(3|5|7)file\\.txt' | sed -n 's/.*/rm &/p' | bash $ ls | grep -Ev '(3|5|7)file\\.txt' | sed -En 's/(.*)/rm &/p' | bash $ ls | grep -Ev '(3|5|7)file\\.txt' | sed -En 's/(.*)/rm \\1/p' | bash $ ls 3file.txt 5file.txt 7file.txt \u540e\u5411\u5f15\u7528 \\0 \\1 \\2 \u7b49\u3002 $ $echo 123456789 | sed -nE 's/(123)(456)(789)/\\1/p' 123 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\2/p' 456 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\3/p' 789 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\3\\1\\2/p' 789123456 $ echo 123456789 | sed -nE 's/(123)(456)(789)/\\1xyz\\2/p' 123xyz456 \u8303\u4f8b\uff1a\u83b7\u53d6\u5206\u533a\u5229\u7528\u7387 $ df | sed -En '/^\\/dev\\/sd/p' /dev/sda2 102750208 7079236 92053692 8 % / /dev/sda2 102750208 7079236 92053692 8 % /.snapshots /dev/sda2 102750208 7079236 92053692 8 % /boot/grub2/i386-pc /dev/sda2 102750208 7079236 92053692 8 % /boot/grub2/x86_64-efi /dev/sda2 102750208 7079236 92053692 8 % /home /dev/sda2 102750208 7079236 92053692 8 % /opt /dev/sda2 102750208 7079236 92053692 8 % /root /dev/sda2 102750208 7079236 92053692 8 % /srv /dev/sda2 102750208 7079236 92053692 8 % /usr/local /dev/sda2 102750208 7079236 92053692 8 % /tmp /dev/sda2 102750208 7079236 92053692 8 % /var $ df | sed -En '/^\\/dev\\/sd/s@.*([0-9]+)%.*@\\1@p' $ df | sed -En '/^\\/dev\\/sd/s#.*([0-9]+)%.*#\\1#p' # df | sed -En '/^\\/dev\\/sd/s/.*([0-9]+)%.*/\\1/p' 8 8 8 8 8 8 8 8 8 8 8 \u4f53\u4f1a\u4e0b\u9762\u7a7a\u683c\u548c\u62ec\u5f27\u5e26\u6765\u7684\u4e0d\u540c\u3002 $ df | sed -En '/^\\/dev\\/sd/s# .*([0-9]+)%.*# \\1#p' /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 $ df | sed -En '/^\\/dev\\/sd/s#( .*)([0-9]+)%.*# \\1#p' /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 /dev/sda2 102750208 7079804 92053156 $ df | sed -En '/^\\/dev\\/sd/s#( .*)([0-9]+)%.*# \\2#p' /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 \u8303\u4f8b\uff1a\u53d6\u5f97\u5f53\u524dIP\u5730\u5740\u3002 $ ifconfig eth0 eth0: flags = 4163 mtu 1500 inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 inet6 fe80::20c:29ff:fea4:e17a prefixlen 64 scopeid 0x20 ether 00 :0c:29:a4:e1:7a txqueuelen 1000 ( Ethernet ) RX packets 22923 bytes 1658298 ( 1 .5 MiB ) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 3763 bytes 442641 ( 432 .2 KiB ) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 $ ip addr show eth0 2 : eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00 :0c:29:a4:e1:7a brd ff:ff:ff:ff:ff:ff altname enp2s1 altname ens33 inet 192 .168.10.210/24 brd 192 .168.10.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::20c:29ff:fea4:e17a/64 scope link valid_lft forever preferred_lft forever $ ifconfig eth0 | sed -En '2s/[^0-9]+([0-9.]+).*/\\1/p' $ ifconfig eth0 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*/\\1/p' $ ifconfig eth0 | sed -En '2s/^[^0-9]+([0-9.]{7,15}).*$/\\1/p' $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.*//p' $ ifconfig eth0 | sed -n '2s/^.*inet //;s/ netmask.*//p' $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\2/p' 192 .168.10.210 192 .168.10.210 192 .168.10.210 \u4f7f\u7528 \\0 \u8f93\u51fa\u5168\u90e8\u53d8\u91cf\u3002 $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\0/p' inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\1/p' inet $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\2/p' 192 .168.10.210 $ ifconfig eth0 | sed -En '2s/(.*inet )([0-9].*)(netmask.*)/\\3/p' netmask 255 .255.255.0 broadcast 192 .168.10.255 \u5bf9\u6bd4\u4e0b\u9762\u4e24\u4e2a\u6307\u4ee4\u7684\u5339\u914d\u5dee\u5f02\u3002 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/ netmask.*//p' 192 .168.10.210 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.* //p' 192 .168.10.210 192 .168.10.255 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask .*//p' 192 .168.10.210 $ ifconfig eth0 | sed -n '2s/^.*inet //p' | sed -n 's/netmask.*//p' 192 .168.10.210 \u8303\u4f8b\uff1a\u53d6\u57fa\u540d\u548c\u76ee\u5f55\u540d\u3002 \uff08 /etc/sysconfig/network-scripts/ \u76ee\u5f55\u5728Rocky9\u4e2d\u9ed8\u8ba4\u5df2\u521b\u5efa\uff0c\u5728openSUSE\u548cUbuntu\u4e2d\u6ca1\u6709\uff09 # \u53d6\u76ee\u5f55\u540d $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's#(^/.*/)([^/]+/?)#\\1#' $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\1/' /etc/sysconfig/ # \u53d6\u57fa\u540d $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's#(^/.*/)([^/]+/?)#\\2#' $ echo \"/etc/sysconfig/network-scripts/\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\2/' network-scripts/ # \u53d6\u76ee\u5f55\u540d $ echo \"/etc/sysconfig/network-scripts/dummyfile\" | sed -E 's#(^/.*/)([^/]+/?)#\\1#' $ echo \"/etc/sysconfig/network-scripts/dummyfille\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\1/' /etc/sysconfig/network-scripts/ # \u53d6\u57fa\u540d $ echo \"/etc/sysconfig/network-scripts/dummyfile\" | sed -E 's#(^/.*/)([^/]+/?)#\\2#' $ echo \"/etc/sysconfig/network-scripts/dummyfille\" | sed -E 's/(^\\/.*\\/)([^\\/]+\\/?)/\\2/' dummyfille \u8303\u4f8b\uff1a\u53d6\u6587\u4ef6\u540d\u548c\u6587\u4ef6\u6269\u5c55\u540d $ echo 1_.file.tar.gz | sed -En 's/(.*)\\.([^.]+)$/\\1/p' $ echo 1_.file.tar.gz | sed -En 's@(.*)\\.([^.]+)$@\\1@p' 1_.file.tar $ echo 1_.file.tar.gz | sed -En 's/(.*)\\.([^.]+)$/\\2/p' $ echo 1_.file.tar.gz | sed -En 's@(.*)\\.([^.]+)$@\\2@p' gz $ echo 1_.file.tar.gz | grep -Eo '.*\\.' 1_.file.tar. $ echo 1_.file.tar.gz | grep -Eo '[^.]+$' gz \u8303\u4f8b\uff1a\u5c06\u975e # \u5f00\u5934\u7684\u884c\u6dfb\u52a0 # $ cat < testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob #Tesetfile #Wiki EOF $ sed -En 's/^[^#]/#&/p' testfile $ sed -En 's/^[^#](.*)/#\\1/p' testfile #HELLO LINUX! #Linux is a free unix-type opterating system. #This is a linux testfile! #Linux test #Google #Taobao #Banbooob \u8303\u4f8b\uff1a\u5c06 # \u5f00\u5934\u7684\u884c\u5220\u9664 # $ cat < testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob #Tesetfile #Wiki EOF $ sed -Ei.bak '/^#/s/^#//' testfile $ cat testfile HELLO LINUX! Linux is a free unix-type opterating system. This is a linux testfile! Linux test Google Taobao Banbooob Tesetfile Wiki sed \u4fdd\u6301\u7a7a\u95f4\uff08hold space\uff09\u7684\u4f8b\u5b50\uff1a d \uff1a\u5220\u9664pattern space\u7684\u5185\u5bb9\uff0c\u5f00\u59cb\u4e0b\u4e00\u4e2a\u5faa\u73af\u3002 D \uff1a\u5982\u679c\u6a21\u5f0f\u7a7a\u95f4\u4fdd\u62a4\u6362\u884c\u7b26\uff0c\u5219\u5220\u9664\u76f4\u5230\u7b2c\u4e00\u4e2a\u6362\u884c\u7b26\u5230\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u7684\u6587\u672c\uff0c\u5e76\u4e0d\u8bfb\u53d6\u65b0\u7684\u8f93\u5165\u884c\uff0c\u800c\u4f7f\u7528\u5408\u6210\u7684\u6a21\u5f0f\u7a7a\u95f4\u91cd\u65b0\u542f\u52a8\u5faa\u73af\u3002\u5982\u679c\u6a21\u5f0f\u7a7a\u95f4\u4e0d\u5305\u542b\u6362\u884c\u7b26\uff0c\u5219\u7c7b\u4f3c d \u547d\u4ee4\u542f\u52a8\u6b63\u5e38\u7684\u65b0\u5faa\u73af\u3002 h \u3001 H \uff1a\u590d\u5236/\u8ffd\u52a0\u6a21\u5f0f\u7a7a\u95f4\u7684\u5185\u5bb9\u5230\u4fdd\u6301\u7a7a\u95f4\u3002 g \u3001 G \uff1a\u590d\u5236/\u8ffd\u52a0\u4fdd\u6301\u7a7a\u95f4\u7684\u5185\u5bb9\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002 n \u3001 N \uff1a\u590d\u5236/\u8ffd\u52a0\u5339\u914d\u5230\u7684\u4e0b\u4e00\u884c\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002 p\uff1a\u6253\u5370\u5f53\u524d\u6a21\u5f0f\u7a7a\u95f4\u5185\u5bb9\u3002 P\uff1a\u6253\u5370\u6a21\u5f0f\u7a7a\u95f4\u5f00\u5934\u81f3 \\n \u7684\u5185\u5bb9\uff0c\u5e76\u8ffd\u52a0\u5230\u9ed8\u8ba4\u8f93\u51fa\u4e4b\u524d\u3002 x \uff1a\u4ea4\u6362\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u7684\u5185\u5bb9. \u4e3e\u4f8b\u89e3\u8bfb1\uff1a seq 10 \u547d\u4ee4\u8f93\u51fa1\uff5e10\u4e2a\u6570\u5b57\uff0c\u6bcf\u4e2a\u6570\u5b57\u4e00\u884c\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e00\u884c 1 \u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u56e0\u4e3a\u53c2\u6570 -n \uff0c\u6240\u4ee5\u8bfb\u53d6\u5230\u7684 1 \u4e0d\u6253\u5370\u5230\u5c4f\u5e55\u3002 \u6267\u884c n \u547d\u4ee4\uff0c\u5373\u8bfb\u53d6\u5339\u914d\u5230\u7684\u4e0b\u4e00\u884c\u5230\u6a21\u5f0f\u7a7a\u95f4\uff0c\u5373\u628a\u7b2c\u4e8c\u884c\u7684 2 \u8bfb\u53d6\u5e76\u8986\u76d6\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002 \u6267\u884c p \u547d\u4ee4\uff0c\u628a 2 \u8f93\u51fa\u5230\u5c4f\u5e55\u3002 \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8bfb\u53d6\u7b2c\u4e09\u884c\u7684 3 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff0c\u6267\u884c n \u547d\u4ee4\uff0c\u5c06\u7b2c\u56db\u884c\u7684 4 \u8bfb\u53d6\u5e76\u8986\u76d6\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u6267\u884c p \u547d\u4ee4\uff0c\u8f93\u51fa 4 \u5230\u5c4f\u5e55\u3002 \u4ee5\u6b64\u7c7b\u63a8\u3002 $ seq 10 | sed -n 'n;p' 2 4 6 8 10 seq 10 | sed 'n;p' 1 2 2 3 4 4 5 6 6 7 8 8 9 10 10 \u4e3e\u4f8b\u89e3\u8bfb2\uff1a seq 10 \u547d\u4ee4\u8f93\u51fa1\uff5e10\u4e2a\u6570\u5b57\uff0c\u6bcf\u4e2a\u6570\u5b57\u4e00\u884c\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e00\u884c\u5230 1 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c\u547d\u4ee4 N \uff0c\u5373\u8bfb\u53d6\u4e0b\u4e00\u884c\uff0c\u5373\u7b2c\u4e8c\u884c\u7684 2 \uff0c\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u6240\u4ee5\u5f53\u524d\u6a21\u5f0f\u7a7a\u95f4\u6709 1 \u548c 2 \u8fd92\u884c\u8bb0\u5f55\u3002 \u6267\u884c s/\\n// \uff0c\u628a\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u7684\u7b2c\u4e00\u884c\u7684 1 \u540e\u9762\u7684 \\n \u66ff\u6362\u4e3a\u7a7a\uff0c\u5373\uff0c\u539f\u6765\u6a21\u5f0f\u7a7a\u95f4\u7684\u4e24\u884c 1 \u548c 2 \u73b0\u5728\u5408\u5e76\u4e3a\u4e00\u884c\uff0c\u5373 12 \u3002 \u8bfb\u53d6\u7b2c\u4e09\u884c\u7684 3 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c\u547d\u4ee4 N \uff0c\u5373\u8bfb\u53d6\u4e0b\u4e00\u884c\uff0c\u5373\u7b2c\u56db\u884c\u7684 4 \uff0c\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u6240\u4ee5\u5f53\u524d\u6a21\u5f0f\u7a7a\u95f4\u6709 3 \u548c 4 \u8fd92\u884c\u8bb0\u5f55\u3002 \u6267\u884c s/\\n// \uff0c\u628a\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u7684\u7b2c\u4e00\u884c 3 \u540e\u9762\u7684 \\n \u66ff\u6362\u4e3a\u7a7a\uff0c\u5373\uff0c\u539f\u6765\u6a21\u5f0f\u7a7a\u95f4\u7684\u4e24\u884c 3 \u548c 4 \u73b0\u5728\u5408\u5e76\u4e3a\u4e00\u884c\uff0c\u5373 34 \u3002 \u4ee5\u6b64\u7c7b\u63a8\u3002 $ seq 10 | sed 'N;s/\\n//' 12 34 56 78 910 \u4e3e\u4f8b\u89e3\u8bfb3\uff1a seq 10 \u547d\u4ee4\u8f93\u51fa1\uff5e10\u4e2a\u6570\u5b57\uff0c\u6bcf\u4e2a\u6570\u5b57\u4e00\u884c\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e00\u884c\u5230 1 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c !G \uff0c\u5373\u5bf9\u7b2c\u4e00\u884c\u7684 1 \u4e0d\u6267\u884c G \u547d\u4ee4\u3002 \u6267\u884c h \u547d\u4ee4\uff0c\u5373\u628a 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u8986\u76d6\u81f3\u4fdd\u6301\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u90fd\u5b58\u6709 1 \u3002 \u6267\u884c $!d \uff0c\u5373\u4e0d\u662f\u6700\u540e\u4e00\u884c\u5c31\u4ece\u6a21\u5f0f\u7a7a\u95f4\u5220\u9664\uff0c\u6240\u4ee5\u628a 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u5220\u9664\u3002 sed \u547d\u4ee4\u8bfb\u53d6\u7b2c\u4e8c\u884c\u5230 2 \u5230\u6a21\u5f0f\u7a7a\u95f4\uff08\u8986\u76d6\uff09\u3002 \u6267\u884c !G \uff0c\u5373\u5bf9\u7b2c\u4e8c\u884c\u7684 2 \u6267\u884c G \u547d\u4ee4\uff0c\u628a 1 \u4ece\u4fdd\u6301\u7a7a\u95f4\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u5b58\u6709 1 \uff0c\u6a21\u5f0f\u7a7a\u95f4\u5b58\u6709 2 \u548c 1 \u3002 \u6267\u884c h \u547d\u4ee4\uff0c\u5373\u628a 2 \u548c 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u8986\u76d6\u81f3\u4fdd\u6301\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u90fd\u5b58\u6709 2 \u548c 1 \u3002 \u6267\u884c $!d \uff0c\u5373\u4e0d\u662f\u6700\u540e\u4e00\u884c\u5c31\u4ece\u6a21\u5f0f\u7a7a\u95f4\u5220\u9664\uff0c\u6240\u4ee5\u628a 2 \u548c 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u4e2d\u5220\u9664\u3002 \u4ee5\u6b64\u7c7b\u63a8\uff0c\u76f4\u81f3\u8bfb\u53d6\u6700\u540e\u4e00\u884c10\u3002\u6b64\u65f6\uff0c\u6a21\u5f0f\u7a7a\u95f4\u662f 10 \uff0c\u4fdd\u6301\u7a7a\u95f4\u5b58\u6709 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002 \u6267\u884c !G \uff0c\u5373\u5bf9\u6700\u540e\u4e00\u884c\u7684 10 \u6267\u884c G \u547d\u4ee4\uff0c\u628a 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u4ece\u4fdd\u6301\u7a7a\u95f4\u8ffd\u52a0\u5230\u6a21\u5f0f\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u5b58\u6709 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002\uff0c\u6a21\u5f0f\u7a7a\u95f4\u5b58\u6709 10 \u3001 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002 \u6267\u884c h \u547d\u4ee4\uff0c\u5373\u628a 10 \u3001 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u4ece\u6a21\u5f0f\u7a7a\u95f4\u8986\u76d6\u81f3\u4fdd\u6301\u7a7a\u95f4\u3002\u81f3\u6b64\uff0c\u4fdd\u6301\u7a7a\u95f4\u548c\u6a21\u5f0f\u7a7a\u95f4\u90fd\u5b58\u6709 10 \u3001 9 \u3001 8 \u3001 7 \u3001 6 \u3001 5 \u3001 4 \u3001 3 \u3001 2 \u3001 1 \u3002 \u6267\u884c $!d \uff0c\u5f53\u524d\u662f\u6700\u540e\u4e00\u884c\uff0c\u6240\u4ee5\u4e0d\u4ece\u6a21\u5f0f\u7a7a\u95f4\u5220\u9664\u5f53\u524d\u5185\u5bb9\u3002 \u8f93\u51fa\u6a21\u5f0f\u7a7a\u95f4\u5185\u5bb9\u81f3\u5c4f\u5e55\u3002\u537310\uff5e1\u3002 $ seq 10 | sed '1!G;h;$!d' 10 9 8 7 6 5 4 3 2 1 \u5176\u4ed6\u4e00\u4e9b\u4f8b\u5b50\uff1a $ seq 10 | sed -n '/3/{g;1!p;};h' 2 $ seq 10 | sed -nr '/3/{n;p}' 4 $ seq 10 | sed 'N;D' 10 $ seq 10 | sed '3h;9G;9!d' 9 3 $ seq 10 | sed '$!N;$!D' 9 10 $ seq 10 | sed '$!d' 10 $ seq 10 | sed 'G' 1 2 3 4 5 6 7 8 9 10 $ seq 10 | sed 'g' $ seq 10 | sed '/^$/d;G' 1 2 3 4 5 6 7 8 9 10 $ seq 10 | sed 'n;d' 1 3 5 7 9 $ seq 10 | sed -n '1!G;h;$p' 10 9 8 7 6 5 4 3 2 1","title":"5.9.\u4e09\u5251\u5ba2sed\u547d\u4ee4"},{"location":"linux/SRE/05-RegExpress/#510awk","text":"awk \u662f\u4e00\u4e2a\u6587\u672c\u5206\u6790\u5de5\u5177\u3002 grep \u64c5\u957f\u67e5\u627e\uff0c sed \u64c5\u957f\u7f16\u8f91\uff0c awk \u64c5\u957f\u6570\u636e\u5206\u6790\u5e76\u751f\u6210\u62a5\u544a\u3002 awk \u7684\u540d\u79f0\u5f97\u81ea\u4e8e\u5b83\u7684\u521b\u59cb\u4ebaAlfred Aho \u3001Peter Weinberger \u548c Brian Kernighan \u59d3\u6c0f\u7684\u9996\u4e2a\u5b57\u6bcd\u3002 awk \u67093\u4e2a\u4e0d\u540c\u7248\u672c: awk \u3001 nawk \u548c gawk \u3002\u6211\u4eec\u8bf4\u7684 awk \u4e00\u822c\u6307 gawk \u3002 gawk \u662f awk \u7684GNU\u7248\u672c\u3002 awk \u628a\u6587\u4ef6\u9010\u884c\u8bfb\u5165\uff0c\u4ee5\u7a7a\u683c\u4e3a\u9ed8\u8ba4\u5206\u9694\u7b26\u5c06\u6bcf\u884c\u5207\u7247\uff0c\u518d\u5bf9\u5207\u7247\u8fdb\u884c\u5206\u6790\u5904\u7406\u3002","title":"5.10.\u4e09\u5251\u5ba2awk\u547d\u4ee4"},{"location":"linux/SRE/05-RegExpress/#5101","text":"awk 'pattern{action statements;...}' {filenames} pattern \u8868\u793a awk \u5728\u6570\u636e\u4e2d\u67e5\u627e\u7684\u5185\u5bb9\u3002\u662f\u8981\u8868\u793a\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\uff0c\u7528\u659c\u6760\u62ec\u8d77\u6765\u3002 action \u662f\u5728\u627e\u5230\u5339\u914d\u5185\u5bb9\u65f6\u6240\u6267\u884c\u7684\u4e00\u7cfb\u5217\u547d\u4ee4\u3002 -F \uff1a\u6307\u5b9a\u5206\u9694\u7b26\uff0c\u540e\u9762\u7d27\u8ddf\u5355\u5f15\u53f7\uff0c\u5355\u5f15\u53f7\u5185\u662f\u5206\u9694\u7b26\u3002\u5982\u4e0d\u52a0 -F \u9009\u9879\uff0c\u5219\u4ee5\u7a7a\u683c\u6216\u8005tab\u4f5c\u4e3a\u5206\u9694\u7b26\u3002 -v \uff1avar=value\uff0c\u53d8\u91cf\u8d4b\u503c\u3002 \u63d0\u793a\uff1a -F \"\" \u6307\u5b9a\u7a7a\u5b57\u7b26\u4e32\u4f5c\u4e3a\u5b57\u6bb5\u5206\u9694\u7b26\uff0c\u4ece\u800c\u5c06\u8f93\u5165\u5b57\u7b26\u4e32\u4e2d\u7684\u6bcf\u4e2a\u5b57\u7b26\u4f5c\u4e3a\u4e00\u4e2a\u72ec\u7acb\u7684\u5b57\u6bb5\u8fdb\u884c\u5904\u7406\u3002\u7136\u540e\uff0c\u4f7f\u7528\u5faa\u73af\u904d\u5386\u6bcf\u4e2a\u5b57\u6bb5\uff0c\u5982\u679c\u5b57\u6bb5\u4e2d\u5305\u542b\u6570\u5b57\uff0c\u5219\u5c06\u5176\u6dfb\u52a0\u5230str1\u53d8\u91cf\u4e2d\u3002\u6700\u540e\uff0c\u6253\u5370str1\u7684\u503c\u3002 -F '' \u4e2d\u7684\u4e24\u4e2a\u5355\u5f15\u53f7\u4e4b\u95f4\u6ca1\u6709\u63d0\u4f9b\u6709\u6548\u7684\u5b57\u6bb5\u5206\u9694\u7b26\u3002\u5728awk\u4e2d\uff0c\u5b57\u6bb5\u5206\u9694\u7b26\u5fc5\u987b\u662f\u4e00\u4e2a\u975e\u7a7a\u5b57\u7b26\u4e32\u3002 \u793a\u4f8b\uff1a\u7b2c\u4e00\u4e2a\u548c\u7b2c\u4e09\u4e2a\u547d\u4ee4\u662f\u6b63\u786e\u7684\u3002 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F \"\" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F \"\" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}'","title":"5.10.1.\u547d\u4ee4\u683c\u5f0f"},{"location":"linux/SRE/05-RegExpress/#5102","text":"\u6267\u884cBEGIN{action;...}\u8bed\u53e5\u5757\u4e2d\u7684\u8bed\u53e5\u3002 BEGIN\u8bed\u53e5\u5757\u518dawk\u8bfb\u5165\u8f93\u5165\u6d41\u4e4b\u524d\u88ab\u6267\u884c\u3002 \u662f\u53ef\u9009\u8bed\u53e5\u5757\u3002 \u5305\u542b\u521d\u59cb\u5316\u53d8\u91cf\uff0c\u6253\u5370\u8f93\u51fa\u8868\u683c\u7684\u8868\u5934\u7b49\u8bed\u53e5\u3002 \u4ece\u6587\u4ef6\u6216\u8005\u6807\u51c6\u8f93\u5165stdin\u8bfb\u53d6\u4e00\u884c\uff0c\u7136\u540e\u6267\u884cpattern{action;...}\u8bed\u53e5\u5757\u3002\u4ece\u7b2c\u4e00\u884c\u5f00\u59cb\u5230\u6700\u540e\u4e00\u884c\uff0c\u9010\u884c\u626b\u63cf\u6587\u4ef6\uff0c\u91cd\u590d\u8fd9\u4e2a\u52a8\u4f5c\uff0c\u76f4\u5230\u6587\u4ef6\u6216\u8005\u8f93\u5165\u6d41\u5168\u90e8\u88ab\u8bfb\u53d6\u5b8c\u6bd5\u3002 \u53ef\u9009\u8bed\u53e5\u5757\u3002 \u5982\u679c\u6ca1\u6709\u63d0\u4f9bpattern\u8bed\u53e5\u5757\uff0c\u5219\u9ed8\u8ba4\u6267\u884c{print}\u3002 \u5f53\u8bfb\u81f3\u6587\u4ef6\u6216\u8005\u8f93\u5165\u6d41\u672b\u5c3e\u65f6\uff0c\u6267\u884cEND{action;...}\u8bed\u53e5\u5757\uff0c\u6bd4\u5982\u6253\u5370\u6240\u6709\u884c\u7684\u5206\u6790\u7ed3\u679c\u8fd9\u7c7b\u6c47\u603b\u4fe1\u606f\u3002\u4e5f\u662f\u4e00\u4e2a\u53ef\u9009\u8bed\u53e5\u5757\u3002","title":"5.10.2.\u5de5\u4f5c\u8fc7\u7a0b"},{"location":"linux/SRE/05-RegExpress/#5103","text":"\u6709\u5206\u9694\u7b26\u5206\u9694\u7684\u5b57\u6bb5\uff08\u5217column\uff0c\u57dffield\uff09\uff0c\u6807\u8bb0 $1 \u3001 $2 \u3001 $3 \u3001...\u3001 $n \u79f0\u4e3a\u57df\u6807\u8bc6\uff0c $0 \u4e3a\u6240\u6709\u57df\u3002\u6ce8\u610f\uff0c\u548cshell\u53d8\u91cf\u4e2d\u7684 $ \u4e0d\u540c\u3002 \u6bcf\u4e00\u884c\u6210\u4e3a\u8bb0\u5f55\uff08record\uff09\u3002 \u5982\u679c\u7701\u7565action\uff0c\u5219\u9ed8\u8ba4\u6267\u884c print $0 \u64cd\u4f5c\u3002","title":"5.10.3.\u5206\u9694\u7b26\u3001\u57df\u548c\u8bb0\u5f55"},{"location":"linux/SRE/05-RegExpress/#5104action","text":"Output statements: print , printf Expressions: \u7b97\u672f\u3001\u6bd4\u8f83\u8868\u8fbe\u5f0f Compund statements: \u7ec4\u5408\u8bed\u53e5 Control statements: if , while \u8bed\u53e5 Input statements: \u52a8\u4f5c print \u683c\u5f0f\uff1a print item1, item2, ... \u8bf4\u660e\uff1a \u9017\u53f7\u5206\u9694\u7b26 \u8f93\u51faitem\u53ef\u4ee5\u662f\u5b57\u7b26\u4e32\uff0c\u4e5f\u53ef\u4ee5\u662f\u6570\u503c\uff0c\u662f\u5f53\u524d\u8bb0\u5f55\u7684\u5b57\u6bb5\u3001\u53d8\u91cf\u6216 awk \u8868\u8fbe\u5f0f\u3002 \u5982\u679c\u7701\u7565item\uff0c\u76f8\u5f53\u4e8e print $0 \u56fa\u5b9a\u5b57\u7b26\u9700\u8981\u7528\u53cc\u5f15\u53f7\uff0c\u800c\u53d8\u91cf\u548c\u6570\u5b57\u4e0d\u9700\u8981\u3002 \u793a\u4f8b\uff1a $ seq 5 | awk '{print \"hello awk\"}' hello awk hello awk hello awk hello awk hello awk $ seq 5 | awk '{print 3*5}' 15 15 15 15 15 $ awk -F ':' '{print \"hello\"}' /etc/passwd | head -5 hello hello hello hello hello $ awk -F ':' '{print}' /etc/passwd | head -5 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin systemd-timesync:x:496:496:systemd Time Synchronization:/:/usr/sbin/nologin nobody:x:65534:65534:nobody:/var/lib/nobody:/bin/bash $ awk -F ':' '{print $0}' /etc/passwd | head -5 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin systemd-timesync:x:496:496:systemd Time Synchronization:/:/usr/sbin/nologin nobody:x:65534:65534:nobody:/var/lib/nobody:/bin/bash $ awk -F ':' '{print $1,$3}' /etc/passwd | head -5 root 0 messagebus 499 systemd-network 497 systemd-timesync 496 nobody 65534 $ awk -F ':' '{print $1\"\\t\"$3}' /etc/passwd | head -5 root 0 messagebus 499 systemd-network 497 systemd-timesync 496 nobody 65534 $ grep \"^UUID\" /etc/fstab | awk '{print $2,$3}' / btrfs /var btrfs /usr/local btrfs /tmp btrfs /srv btrfs /root btrfs /opt btrfs /home btrfs /boot/grub2/x86_64-efi btrfs /boot/grub2/i386-pc btrfs /.snapshots btrfs swap swap \u793a\u4f8b\uff1a\u8bfb\u53d6\u5206\u533a\u5229\u7528\u7387\u3002 \u5206\u9694\u7b26\u4e2d\u7684\u5b9a\u4e49 [[:space:]]+|% \u7684\u542b\u4e49\uff0c\u4e00\u4e2a\u6216\u591a\u4e2a\u7a7a\u683c\u6216\u8005 % \u4f5c\u4e3a\u5206\u9694\u7b26\u3002 $ df | awk '{print $1,$5}' Filesystem Use% devtmpfs 0 % tmpfs 0 % tmpfs 2 % tmpfs 0 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % /dev/sda2 8 % tmpfs 0 % $ df | grep '^/dev/sd' | awk -F '[[:space:]]+|%' '{print $1,$5}' $ df | grep '^/dev/sd' | awk -F ' +|%' '{print $1,$5}' /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 /dev/sda2 8 \u793a\u4f8b\uff1a\u8bfb\u53d6ifconfig\u8f93\u51fa\u7ed3\u679c\u4e2d\u7684ip\u5730\u5740\u3002 $ ifconfig eth0 | sed -n '2p' | awk '/netmask/{print $2}' 192 .168.10.210 $ ifconfig eth0 | sed -n '2p' | awk '{print $2}' 192 .168.10.210","title":"5.10.4.\u5e38\u7528action\u5206\u7c7b"},{"location":"linux/SRE/05-RegExpress/#5105pattern","text":"\u6839\u636epattern\u6761\u4ef6\uff0c\u8fc7\u6ee4\u5339\u914d\u7684\u884c\uff0c\u518d\u505a\u5904\u7406\u3002 \u5982\u679c\u672a\u6307\u5b9a\uff0c\u5373\u7a7a\u6a21\u5f0f\uff0c\u5219\u5339\u914d\u6bcf\u4e00\u884c\u3002 /regular expression/ \uff0c\u4ec5\u5904\u7406\u80fd\u591f\u6a21\u5f0f\u5339\u914d\u5230\u7684\u884c\uff08\u5373\u7ed3\u679c\u4e3a\u771f\uff09\uff0c\u9700\u8981\u7528 / \u8fdb\u884c\u62ec\u8d77\u6765\u3002 \u7ed3\u679c\u4e3a\u771f\uff0c\u5373\u975e0\u503c\u3001\u975e\u7a7a\u5b57\u7b26\u4e32 \u7ed3\u679c\u4e3a\u5047\uff0c\u53730\u503c\u3001\u7a7a\u5b57\u7b26\u4e32 \u793a\u4f8b\uff1a\u7a7a\u6a21\u5f0f awk -F \":\" '{print $1, $3}' /etc/passwd | head -n5 root 0 messagebus 499 systemd-network 497 systemd-timesync 496 nobody 65534 \u793a\u4f8b\uff1a\u975e\u7a7a\u6a21\u5f0f $ seq 5 | awk '0' $ seq 5 | awk '1' 1 2 3 4 5 $ seq 5 | awk '2' 1 2 3 4 5 $ seq 5 | awk '\"true\"' 1 2 3 4 5 $ seq 5 | awk '\"false\"' 1 2 3 4 5 $ seq 5 | awk 'true' $ seq 5 | awk 'false' $ seq 5 | awk '' $ seq 5 | awk '\"\"' $ seq 5 | awk '\"0\"' 1 2 3 4 5 \u4f53\u4f1a\u4e0b\u9762\u53d8\u91cf\u7684\u503c\u548c\u6b63\u786e\u4f7f\u7528\u53d8\u91cf\uff08\u5b57\u7b26\u4e32\u8fd8\u662f\u53d8\u91cf\uff1f\uff09 $ seq 5 | awk '\"test\"' 1 2 3 4 5 $ seq 5 | awk 'test' $ seq 5 | awk -v test = 0 '\"test\"' $ seq 5 | awk -v test = 0 'test' $ seq 5 | awk -v test = \"0\" 'test' $ seq 5 | awk -v test = \"0\" '\"test\"' 1 2 3 4 5 $ seq 5 | awk -v test = 1 'test' 1 2 3 4 5 \u4f53\u4f1a\u4e0b\u9762\u7684\u4e0e\u975e\u5224\u65ad\u3002 $ awk '1' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin $ awk '0' /etc/passwd | head -n3 $ awk '!1' /etc/passwd | head -n3 $ awk '!0' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin # i\u6ca1\u6709\u8d4b\u503c\uff0c\u4e3a\u5047\uff0c\u6ca1\u6709\u8f93\u51fa $ seq 5 | awk 'i' # i\u8d4b\u503c\u4e3a0\uff0c\u4e3a\u5047\uff0c\u6ca1\u6709\u8f93\u51fa $ seq 5 | awk 'i=0' # i\u8d4b\u503c\u4e3a1\uff0c\u4e3a\u771f\uff0c\u8f93\u51fa\u7b2c\u4e00\u884c\u7ed3\u679c\uff0c\u4ee5\u6b64\u7c7b\u63a8\uff0c\u6bcf\u884c\u90fd\u4e3a\u771f\uff0c\u8f93\u51fa\u5168\u90e8seq\u7684\u7ed3\u679c $ seq 5 | awk 'i=1' 1 2 3 4 5 # \u7b2c\u4e00\u6b21\u521d\u59cbi\u672a\u8d4b\u503c\uff0c\u4e3a\u5047\uff0c!i\u5219\u4e3a\u771f\uff0c\u8d4b\u503c\u7ed9i\uff0c\u6240\u4ee5i\u4e3a\u771f,\u8f93\u51faseq\u7b2c1\u884c\u7ed3\u679c # \u7b2c\u4e8c\u6b21\u521d\u59cbi\u4e3a\u771f\uff0c!i\u5219\u4e3a\u5047\uff0c\u8d4b\u503c\u7ed9i\uff0c\u6240\u4ee5i\u4e3a\u5047\uff0c\u4e0d\u8f93\u51faseq\u7b2c2\u884c\u7ed3\u679c # \u7b2c\u4e09\u6b21\u521d\u59cbi\u4e3a\u5047\uff0c!i\u5219\u4e3a\u771f\uff0c\u8d4b\u503c\u7ed9i\uff0c\u6240\u4ee5i\u4e3a\u771f\uff0c\u8f93\u51faseq\u7b2c3\u884c\u7ed3\u679c # \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8f93\u51faseq\u7ed3\u679c\u7684\u5947\u6570\u884c $ seq 5 | awk 'i=!i' 1 3 5 # \u4e0e\u4e0a\u4f8b\u7684\u533a\u522b\u5728\u4e8ei\u521d\u59cb\u503c\u672a\u771f\uff0c\u7b2c\u4e00\u6b21\u7684i\u503c\u4e3a\u5047\uff0c\u4e0d\u8f93\u51faseq\u7b2c1\u884c\u7ed3\u679c # \u7b2c\u4e8c\u6b21i\u7684\u521d\u59cb\u503c\u4e3a\u5047\uff0c\u901a\u8fc7i=!i\u53d8\u4e3a\u771f\uff0c\u6240\u4ee5\u8f93\u51faseq\u7684\u7b2c2\u884c\u7ed3\u679c # \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8f93\u51faseq\u7ed3\u679c\u7684\u5076\u6570\u884c $ seq 5 | awk -v i = 1 'i=!i' 2 4 # \u8f93\u51fa\u8ba1\u6570\u884c $ seq 5 | awk -v i = 0 'i=!i' 1 3 5 # \u53ea\u8f93\u51fai\u7684\u503c\uff0c\u4e0d\u8f93\u51faseq\u7684\u503c $ seq 5 | awk '{i=!i;print i}' 1 0 1 0 1 $ seq 5 | awk '{i=!i}' $ seq 5 | awk '(i=!i)' 1 3 5 $ seq 5 | awk '!(i=!i)' 2 4","title":"5.10.5.\u6a21\u5f0fPattern"},{"location":"linux/SRE/05-RegExpress/#5106","text":"\u793a\u4f8b\uff1a $ head -n2 /etc/passwd | awk -F ':' '{print $0}' root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false $ head -n2 /etc/passwd | awk -F ':' '{print $2}' x x $ head -n2 /etc/passwd | awk -F ':' '{print $1}' root messagebus $ head -n2 /etc/passwd | awk -F ':' '{print $1\"#\"$2\"#\"$3\"#\"$4}' root#x#0#0 messagebus#x#499#499","title":"5.10.6.\u622a\u53d6\u7247\u6bb5"},{"location":"linux/SRE/05-RegExpress/#5107","text":"","title":"5.10.7.\u64cd\u4f5c\u7b26"},{"location":"linux/SRE/05-RegExpress/#51071","text":"x+y \uff0c x-y \uff0c x*y \uff0c x/y \uff0c x^y \uff0c x%y \u3002 -x \uff1a\u8f6c\u6362\u4e3a\u8d1f\u6570 +x \uff1a\u5c06\u5b57\u7b26\u4e32\u8f6c\u6362\u4e3a\u6570\u503c \u5217\u503c\u4e4b\u95f4\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97\u3002 $ awk -F ':' '{$7=$3+$4;print $1,$3,$4,$7}' /etc/passwd | head -n5 root 0 0 0 messagebus 499 499 998 systemd-network 497 497 994 systemd-timesync 496 496 992 nobody 65534 65534 131068 \u8ba1\u7b97\u67d0\u4e2a\u5217\u7684\u603b\u548c\u3002 END \u8868\u793a\u6240\u6709\u7684\u884c\u90fd\u5df2\u7ecf\u6267\u884c\u3002 $ awk -F ':' '{(total=total+$3)}; END {print total}' /etc/passwd 103011","title":"5.10.7.1.\u7b97\u6570\u64cd\u4f5c\u7b26"},{"location":"linux/SRE/05-RegExpress/#51072","text":"\u6ca1\u6709\u64cd\u4f5c\u7b26\u53f7\uff0c\u5b57\u7b26\u4e32\u8fde\u63a5\u3002","title":"5.10.7.2.\u5b57\u7b26\u4e32\u64cd\u4f5c\u7b26"},{"location":"linux/SRE/05-RegExpress/#51073","text":"= \uff0c += \uff0c -= \uff0c *= \uff0c /= \uff0c %= \uff0c ^= \uff0c ++ \uff0c -- \u3002 \u793a\u4f8b\uff1a $ awk 'BEGIN{print i}' $ awk 'BEGIN{print i++}' #\u4ece0\u5f00\u59cb 0 $ awk 'BEGIN{print ++i}' 1 $ awk 'BEGIN{print i++, i}' 0 1 $ awk 'BEGIN{i=0;print i++, i}' 0 1 $ awk 'BEGIN{print ++i, i}' 1 1 $ awk 'BEGIN{i=0;print ++i, i}' 1 1 $ awk 'BEGIN{i=0;print i, i++}' 0 0 $ awk 'BEGIN{i=0;print i, ++i}' 0 1 $ seq 10 1 2 3 4 5 6 7 8 9 10 # n\u4ece0\u5f00\u59cb\u8ba1\u6570\uff0c\u8f93\u51fa\u7684\u662fn\u503c\uff0c\u4e0d\u662fseq\u7684\u8f93\u51fa\u7ed3\u679c $ seq 10 | awk '{print n++}' 0 1 2 3 4 5 6 7 8 9 # seq=1\u65f6\uff0c\u521d\u59cbn\u672a\u8d4b\u503c\uff0c\u4e3a\u5047\uff0c\u4e0d\u8f93\u51faseq\u7ed3\u679c\uff0cn++\u4e3a\u771f # seq=2\u65f6\uff0cn\u4e3a\u771f\uff0c\u8f93\u51faseq\u7ed3\u679c\uff0cn++\u4e3a\u771f # \u540e\u7eedn++\u90fd\u4e3a\u771f\uff0c\u6240\u4ee5seq\u7684\u7ed3\u679c\u51fa\u4e86\u7b2c\u4e00\u884c\u7531\u4e8en\u4e3a\u5047\u6ca1\u6709\u8f93\u51fa\uff0c\u5176\u4ed6\u884c\u90fd\u8f93\u51fa $ seq 10 | awk 'n++' 2 3 4 5 6 7 8 9 10 # \u53c2\u8003\u4e0a\u4f8b\uff0cn\u521d\u59cb\u672a\u8d4b\u503c\uff0c\u4f46\u6267\u884c++n\u540e\u4e3a\u771f\uff0c\u6240\u4ee5\u8f93\u51fa\u7b2c\u4e00\u884c\uff0c\u540e\u7eed\u884c\u90fd\u8f93\u51fa\u56e0\u4e3an\u4e00\u76f4\u4e3a\u771f $ seq 10 | awk '++n' 1 2 3 4 5 6 7 8 9 10 # n=0\u65f6++n=1\uff0c!++n=0\uff0c\u8f93\u51fa\u7b2c0\u884c $ awk -v n = 0 '!++n' /etc/passwd # n=0\u65f6n++=1\uff0c!n++=1\uff0c\u8f93\u51fa\u7b2c1\u884c $ awk -v n = 0 '!n++' /etc/passwd root:x:0:0:root:/root:/bin/bash $ awk -v n = 0 '!n++{print n}' /etc/passwd 1 # \u65e0\u7ed3\u679c\u8f93\u51fa $ awk -v n = 0 '!++n{print n}' /etc/passwd $ awk -v n = 1 '!n++{print n}' /etc/passwd $ awk -v n = 0 '!n++' /etc/passwd root:x:0:0:root:/root:/bin/bash # \u65e0\u7ed3\u679c\u8f93\u51fa $ awk -v n = 1 '!n++' /etc/passwd $ awk -v n = 2 '!n++' /etc/passwd","title":"5.10.7.3.\u8d4b\u503c\u64cd\u4f5c\u7b26"},{"location":"linux/SRE/05-RegExpress/#51074","text":"\u4f7f\u7528 == \u4ee3\u8868\u7b49\u4e8e\uff0c\u5373\u7cbe\u786e\u5339\u914d\u3002\u7c7b\u4f3c\u8fd8\u6709 > \u3001 >= \u3001 < \u3001 <= \u3001 != \u7b26\u53f7\u3002 \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e09\u5217\u7684\u503c\u4e3a 1000 \u7684\u884c\u3002 $ awk -F ':' '$3==\"100\"' /etc/passwd vagrant:x:1000:478:vagrant:/home/vagrant:/bin/bash \u5728\u548c\u6570\u5b57\u6bd4\u8f83\u65f6\uff0c\u82e5\u628a\u8981\u6bd4\u8f83\u7684\u6570\u5b57\u7528\u53cc\u5f15\u53f7\u5f15\u8d77\u6765\uff0c awk \u4f1a\u6309\u5b57\u7b26\u5904\u7406\uff0c\u4e0d\u52a0\u53cc\u5f15\u53f7\uff0c\u5219\u4f1a\u6309\u6570\u5b57\u5904\u7406\u3002 $ awk -F ':' '$3<=\"100\"' /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/usr/sbin/nologin $ awk -F ':' '$3<=100' /etc/passwd root:x:0:0:root:/root:/bin/bash postfix:x:51:51:Postfix Daemon:/var/spool/postfix:/usr/sbin/nologin man:x:13:62:Manual pages viewer:/var/lib/empty:/usr/sbin/nologin daemon:x:2:2:Daemon:/sbin:/usr/sbin/nologin at:x:25:25:Batch jobs daemon:/var/spool/atjobs:/usr/sbin/nologin bin:x:1:1:bin:/bin:/usr/sbin/nologin awk -F ':' '{if ($1==\"root\") {print $0}}' /etc/passwd awk -F ':' '$7!=\"/bin/false\"' /etc/passwd awk -F ':' '$3<$2' /etc/passwd","title":"5.10.7.4.\u6bd4\u8f83\u64cd\u4f5c\u7b26"},{"location":"linux/SRE/05-RegExpress/#51075","text":"&& \u8868\u793a\u201c\u5e76\u4e14\u201d || \u8868\u793a\u201c\u6216\u8005\u201d ! \u8868\u793a\u201c\u975e\u201d\uff08\u53d6\u53cd\uff09 awk -F ':' '$3>10 && $3<100' /etc/passwd awk -F ':' '$3>10 || $3<100' /etc/passwd awk -F ':' '($3==0)' /etc/passwd awk -F ':' '!($3==0)' /etc/passwd \u6ce8\u610f\u4e0b\u9762\u5bf9\u5b57\u7b26\u548c\u6570\u503c\u8fdb\u884c\u53d6\u53cd\u64cd\u4f5c\u7684\u7ed3\u679c\u3002 $ awk 'BEGIN{print i}' $ awk 'BEGIN{print !i}' 1 $ awk -v i = 10 'BEGIN{print i}' 10 $ awk -v i = 10 'BEGIN{print !i}' 0 $ awk -v i = -5 'BEGIN{print i}' -5 $ awk -v i = -5 'BEGIN{print !i}' 0 $ awk -v i = \"abc\" 'BEGIN{print i}' abc $ awk -v i = \"abc\" 'BEGIN{print !i}' 0 $ awk -v i = abc 'BEGIN{print i}' abc $ awk -v i = abc 'BEGIN{print !i}' 0 $ awk -v i = \"\" 'BEGIN{print i}' $ awk -v i = \"\" 'BEGIN{print !i}' 1 \u5728\u5206\u9694\u7b26\u5b9a\u4e49\u4e2d\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u3002 $ df | awk -F \" +|%\" '{print $5}' Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0 $ df | awk -F \"[[:space:]]+|%\" '{print $5}' Use 0 0 2 0 8 8 8 8 8 8 8 8 8 8 8 0","title":"5.10.7.5.\u903b\u8f91\u64cd\u4f5c\u7b26"},{"location":"linux/SRE/05-RegExpress/#51076","text":"\u683c\u5f0f\uff1a selector?if-true-expression:if-false-expression $ awk -F ':' '{$3>1000?usertype=\"Common User\":usertype=\"Superuser\";printf\"%-20s:%12s\\n\", $1, usertype}' /etc/passwd | head -n5 root : Superuser messagebus : Superuser systemd-network : Superuser systemd-timesync : Superuser nobody : Common User","title":"5.10.7.6.\u4e09\u76ee\u6761\u4ef6\u8868\u8fbe\u5f0f"},{"location":"linux/SRE/05-RegExpress/#51078","text":"~ \uff1a\u5de6\u53f3\u662f\u5426\u5339\u914d !~ \uff1a\u5de6\u53f3\u662f\u5426\u4e0d\u5339\u914d \u793a\u4f8b\uff1a \u5339\u914d\u6587\u4ef6\u4e2d\u6307\u5b9a\u5b57\u7b26\u4e32 root \u7684\u6240\u6709\u884c\uff0c\u7c7b\u4f3cgrep\u547d\u4ee4\uff0c\u4f46\u6ca1\u6709\u9ad8\u4eae\u663e\u793a\u3002 $ awk '/root/' /etc/passwd root:x:0:0:root:/root:/bin/bash \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e00\u5217 $1 \u4e2d\u5305\u542b\u6307\u5b9a\u5b57\u7b26\u4e32 oo \u7684\u884c\u3002 ~ \u662f\u4ee3\u8868\u5de6\u53f3\u5339\u914d\u3002 $ awk -F ':' '$1 ~/oo/' /etc/passwd root:x:0:0:root:/root:/bin/bash gentoo:x:1014:100:Gentoo Distribution:/home/gentoo:/bin/csh \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u5217 $0 \uff08\u6574\u884c\uff09\u4e2d\u5305\u542b root \u884c\u7684\u7b2c\u4e00\u5217 $1 \u3002 $ awk -F: '$0 ~/root/{print $1}' /etc/passwd $ awk -F: '$0 ~\"root\"{print $1}' /etc/passwd root daemon _cvmsroot \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u5217 $0 \uff08\u6574\u884c\uff09\u4e2d\u4ee5 root \u5f00\u5934\u884c\u7684\u7b2c\u4e00\u5217 $1 \u3002 $ awk -F: '$0 ~\"^root\"{print $1}' /etc/passwd $ awk -F: '$0 ~/^root/{print $1}' /etc/passwd root \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u5217 $0 \uff08\u6574\u884c\uff09\u4e2d\u4e0d\u4ee5 root \u5f00\u5934\u884c\u7684\u7b2c\u4e00\u5217 $1 \u3002 awk -F: '$0 !~/^root/{print $1}' /etc/passwd awk -F: '$0 ~/^[^root]/{print $1}' /etc/passwd \u591a\u6761\u4ef6\u5339\u914d\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u6240\u6709\u542b\u6709 root \u6216 ftp \u7684\u884c\uff0c\u5e76\u6253\u5370\u7b2c1\u30013\u5217\u3002 awk -F ':' '/root/ {print $1,$3} /bin/ {print $1,$3}' /etc/passwd \u591a\u6761\u4ef6\u5339\u914d\uff0c\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e00\u5217\u4e2d\u542b\u6709 root \u6216 bin \u7684\u884c\uff0c\u5e76\u6253\u5370\u7b2c1\u30013\u5217\u3002 $ awk -F ':' '$1 ~/root/ {print $1,$3} $1 ~/bin/ {print $1,$3}' /etc/passwd root 0 bin 1 \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u7b2c\u4e09\u5217 $3 \u4e2d\u503c\u4e3a 0 \u7684\u884c\u3002 $ awk -F \":\" '$3==0' /etc/passwd root:x:0:0:root:/root:/bin/bash \u4ee5\u81f3\u5c11\u4e00\u4e2a\u7a7a\u683c\u6216%\u4e3a\u5206\u9694\u7b26\uff0c\u5339\u914d\u4ee5 /dev/sd \u5f00\u5934\u7684\u884c\uff0c\u6253\u5370\u7b2c\u4e94\u5217\u3002 $ df | awk -F \"[[:space:]]+|%\" '$0 ~ /^\\/dev\\/sd/{print $5}' 8 8 8 8 8 8 8 8 8 8 8 \u8bfb\u53d6 ifconfig eth0 \u8f93\u51fa\u7ed3\u679c\u7684\u7b2c\u4e8c\u884c NR==2 \u7684\u7b2c\u4e8c\u5217 $2 \u3002 $ ifconfig eth0 | awk 'NR==2{print $2}' 192 .168.10.210","title":"5.10.7.8.\u6a21\u5f0f\u5339\u914d\u7b26"},{"location":"linux/SRE/05-RegExpress/#5108","text":"","title":"5.10.8.\u53d8\u91cf"},{"location":"linux/SRE/05-RegExpress/#51081","text":"awk \u5e38\u7528\u7684\u53d8\u91cf\u6709 FS \u3001 OFS \u3001 NF \u548c NR \u3002 FS \u7528\u6765\u5b9a\u4e49\u8f93\u5165\u5b57\u6bb5\u5206\u9694\u7b26\uff0c\u9ed8\u8ba4\u4e3a\u7a7a\u767d\u5b57\u7b26\u3002\u4e0e -F \u9009\u9879\u529f\u80fd\u7c7b\u4f3c\uff0c\u540c\u65f6\u4f7f\u7528\u4f1a\u62a5\u9519\u3002 OFS \u7528\u6765\u5b9a\u4e49\u8f93\u51fa\u5b57\u6bb5\u5206\u9694\u7b26\uff0c\u9ed8\u8ba4\u4e3a\u7a7a\u767d\u5b57\u7b26\u3002 RS \u6307\u5b9a\u8f93\u5165\u65f6\u7684\u6362\u884c\u7b26\u3002 ORS \u6307\u5b9a\u7b26\u53f7\u5728\u8f93\u51fa\u65f6\u66ff\u6362\u6362\u884c\u7b26\u3002 NF \u8868\u793a\u7528\u5206\u9694\u7b26\u5206\u9694\u540e\u4e00\u5171\u6709\u591a\u5c11\u5217\u3002 NR \u8868\u793a\u884c\u53f7\u3002 FNR \u8868\u793a\u4e2a\u6587\u4ef6\u5206\u522b\u8ba1\u6570\u5404\u81ea\u8bb0\u5f55\u7684\u7f16\u53f7\u3002 FILENAME \u8868\u793a\u5f53\u524d\u6587\u4ef6\u540d\u3002 ARGC \u8868\u793a\u547d\u4ee4\u884c\u53c2\u6570\u7684\u4e2a\u6570\u3002 ARVC \u4ee5\u6570\u7ec4\u5f62\u5f0f\u4fdd\u5b58\u547d\u4ee4\u884c\u6240\u7ed9\u5b9a\u7684\u5404\u53c2\u6570\uff0c\u6bcf\u4e2a\u53c2\u6570\uff1a ARGV[0] \uff0c......\u3002 FS \u7684\u7528\u6cd5\uff1a $ awk -v FS = ':' '{print $1, FS, $3}' /etc/passwd | head -n5 root : 0 messagebus : 499 systemd-network : 497 $ awk -F: '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 $ S = : ; awk -v FS = $S '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 systemd-timesync:496 nobody:65534 $ S = : ; awk -F $S '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 FS \u548c -F \u9009\u9879\u529f\u540c\u65f6\u4f7f\u7528\u4f1a\u51b2\u7a81\uff0c -F \u7684\u4f18\u5148\u7ea7\u66f4\u9ad8\u3002 $ awk -v FS = ':' -F ';' '{print $1FS$3}' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash ; messagebus:x:499:499:User for D-Bus:/run/dbus:/usr/bin/false ; systemd-network:x:497:497:systemd Network Management:/:/usr/sbin/nologin ; $ awk -v FS = ';' -F ':' '{print $1FS$3}' /etc/passwd | head -n3 root:0 messagebus:499 systemd-network:497 OFS \u7684\u7528\u6cd5\uff1a \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u7b2c1\u30013\u30014\u5217\u7b2c\u5185\u5bb9\uff0c\u5e76\u4ee5 # \u4e3a\u5206\u9694\u7b26\u3002 $ awk -F ':' '{OFS=\"#\"} {print $1,$3,$4}' /etc/passwd | head -n5 root#0#0 messagebus#499#499 systemd-network#497#497 systemd-timesync#496#496 nobody#65534#65534 $ awk -v FS = ':' -v OFS = '#' '{print $1,$3,$4}' /etc/passwd | head -n5 root#0#0 messagebus#499#499 systemd-network#497#497 systemd-timesync#496#496 nobody#65534#65534 \u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u5f53\u7b2c\u4e09\u5217\u5927\u4e8e\u7b49\u4e8e5000\u65f6\uff0c\u6253\u5370\u7b2c1\u30012\u30013\u30014\u5217\u7b2c\u5185\u5bb9\uff0c\u5e76\u4ee5 # \u4e3a\u5206\u9694\u7b26\u3002 $ awk -F ':' '{OFS=\"#\"} {if ($3>=5000) {print $1,$2,$3,$4}}' /etc/passwd nobody#x#65534#65534 RS \u7684\u7528\u6cd5\uff1a # \u4ee5\u7a7a\u683c\u4e3a\u6362\u884c\u6807\u5fd7 $ awk -v RS = ' ' '{print $0}' /etc/passwd | head -n3 root:x:0:0:root:/root:/bin/bash messagebus:x:499:499:User for # \u4ee5\u5192\u53f7\u4e3a\u6362\u884c\u6807\u5fd7 $ awk -v RS = ':' '{print $0}' /etc/passwd | head -n3 root x 0 ORS \u7684\u7528\u6cd5\uff1a # \u4ee5\u5192\u53f7\u4e3a\u6362\u884c\u6807\u5fd7\uff0c\u66ff\u6362\u6210### $ awk -v RS = ':' -v ORS = '###' '{print $0}' /etc/passwd | head -n3 root###x###0###0###root###/root###/bin/bash messagebus###x###499###499###User for D-Bus###/run/dbus###/usr/bin/false systemd-network###x###497###497###systemd Network Management###/###/usr/sbin/nologin NF \u7684\u7528\u6cd5\uff1a \u5176\u4e2d NF \u662f\u591a\u5c11\u5217\uff0c $NF \u662f\u6700\u540e\u4e00\u5217\u7684\u503c\u3002 \u4e0b\u4f8b\u4e2d\u4ee5 : \u4e3a\u5206\u9694\u7b26\u4e00\u5171\u5206\u4e3a7\u5217\uff0c\u6700\u540e\u4e00\u5217\u7684\u503c\u662f $NF \u3002 $ awk -F ':' '{print $NF}' /etc/passwd | head -n2 /bin/bash /usr/bin/false $ awk -F ':' '{print NF}' /etc/passwd | head -n2 7 7 $ ss -nt | grep \"^ESTAB\" | awk -F \"[[:space:]]+|:\" '{print $(NF-2)}' 192 .168.10.103 $ ss -nt | awk -F \"[[:space:]]+|:\" '/^ESTAB/{print $(NF-2)}' 192 .168.10.103 NR \u7684\u7528\u6cd5\uff1a \u901a\u8fc7 NR \u8f93\u51fa\u884c\u53f7\u3002\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u524d\u4e09\u884c\u7684\u884c\u53f7\u3002 $ awk -F ':' '{print NR}' /etc/passwd | head -n3 1 2 3 \u53d6\u5947\u3001\u5076\u6570\u884c\u3002 $ seq 10 | awk 'NR%2==0' 2 4 6 8 10 $ seq 10 | awk 'NR%2==1' 1 3 5 7 9 \u901a\u8fc7 NR \u8bbe\u5b9a\u884c\u53f7\u6761\u4ef6\u3002\u4ee5 : \u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u7b2c40\u884c\u4ee5\u540e\u7684\u884c\u5185\u5bb9\u3002 $ awk 'NR>45' /etc/passwd admin3:x:1020:100::/home/admin3:/bin/bash smith:x:2002:0:,,,:/home/admin2:/bin/bash pm1:x:2003:1535::/home/pm1:/bin/bash tm1:x:2004:1535::/home/tm1:/bin/bash tm2:x:2005:1536::/home/tm2:/bin/bash $ awk -F ':' 'NR>45' /etc/passwd admin3:x:1020:100::/home/admin3:/bin/bash smith:x:2002:0:,,,:/home/admin2:/bin/bash pm1:x:2003:1535::/home/pm1:/bin/bash tm1:x:2004:1535::/home/tm1:/bin/bash tm2:x:2005:1536::/home/tm2:/bin/bash $ awk -F ':' 'NR>45 {print NR,$1,$3}' /etc/passwd 46 admin3 1020 47 smith 2002 48 pm1 2003 49 tm1 2004 50 tm2 2005 $ awk -F ':' 'BEGIN{print NR}' /etc/passwd 0 $ awk -F ':' 'END{print NR}' /etc/passwd 50 $ ifconfig eth0 | awk '/netmask/{print $0}' inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig eth0 | awk '/netmask/{print $1}' inet $ ifconfig eth0 | awk '/netmask/{print $2}' 192 .168.10.210 $ ifconfig eth0 | awk 'NR==2{print $0}' inet 192 .168.10.210 netmask 255 .255.255.0 broadcast 192 .168.10.255 $ ifconfig eth0 | awk 'NR==2{print $1}' inet $ ifconfig eth0 | awk 'NR==2{print $2}' 192 .168.10.210 \u901a\u8fc7 NR \u4e0e\u5217\u5339\u914d\u4e00\u8d77\u4f7f\u7528\u3002 $ awk -F ':' 'NR<5 && $1 ~/roo/' /etc/passwd root:x:0:0:root:/root:/bin/bash FNR \u7684\u7528\u6cd5\uff1a $ awk '{print FNR}' /etc/fstab /etc/networks 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 $ awk '{print NR, $0}' /etc/fstab /etc/networks 1 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af / btrfs defaults 0 0 2 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /var btrfs subvol = /@/var 0 0 3 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /usr/local btrfs subvol = /@/usr/local 0 0 4 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /tmp btrfs subvol = /@/tmp 0 0 5 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /srv btrfs subvol = /@/srv 0 0 6 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /root btrfs subvol = /@/root 0 0 7 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /opt btrfs subvol = /@/opt 0 0 8 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /home btrfs subvol = /@/home 0 0 9 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/x86_64-efi btrfs subvol = /@/boot/grub2/x86_64-efi 0 0 10 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/i386-pc btrfs subvol = /@/boot/grub2/i386-pc 0 0 11 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /.snapshots btrfs subvol = /@/.snapshots 0 0 12 UUID = 47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 swap swap defaults 0 0 13 # 14 # networks This file describes a number of netname-to-address 15 # mappings for the TCP/IP subsystem. It is mostly 16 # used at boot time, when no name servers are running. 17 # 18 19 loopback 127 .0.0.0 20 link-local 169 .254.0.0 21 22 # End. $ awk '{print FNR, $0}' /etc/fstab /etc/networks 1 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af / btrfs defaults 0 0 2 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /var btrfs subvol = /@/var 0 0 3 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /usr/local btrfs subvol = /@/usr/local 0 0 4 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /tmp btrfs subvol = /@/tmp 0 0 5 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /srv btrfs subvol = /@/srv 0 0 6 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /root btrfs subvol = /@/root 0 0 7 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /opt btrfs subvol = /@/opt 0 0 8 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /home btrfs subvol = /@/home 0 0 9 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/x86_64-efi btrfs subvol = /@/boot/grub2/x86_64-efi 0 0 10 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/i386-pc btrfs subvol = /@/boot/grub2/i386-pc 0 0 11 UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /.snapshots btrfs subvol = /@/.snapshots 0 0 12 UUID = 47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 swap swap defaults 0 0 1 # 2 # networks This file describes a number of netname-to-address 3 # mappings for the TCP/IP subsystem. It is mostly 4 # used at boot time, when no name servers are running. 5 # 6 7 loopback 127 .0.0.0 8 link-local 169 .254.0.0 9 10 # End. FILENAME \u7684\u7528\u6cd5\uff1a $ awk '{print FILENAME}' /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab /etc/fstab $ awk '{print FNR, FILENAME, $0}' /etc/fstab /etc/networks 1 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af / btrfs defaults 0 0 2 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /var btrfs subvol = /@/var 0 0 3 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /usr/local btrfs subvol = /@/usr/local 0 0 4 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /tmp btrfs subvol = /@/tmp 0 0 5 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /srv btrfs subvol = /@/srv 0 0 6 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /root btrfs subvol = /@/root 0 0 7 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /opt btrfs subvol = /@/opt 0 0 8 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /home btrfs subvol = /@/home 0 0 9 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/x86_64-efi btrfs subvol = /@/boot/grub2/x86_64-efi 0 0 10 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /boot/grub2/i386-pc btrfs subvol = /@/boot/grub2/i386-pc 0 0 11 /etc/fstab UUID = 5ffa8dbd-473e-4308-804a-0033c3b5f7af /.snapshots btrfs subvol = /@/.snapshots 0 0 12 /etc/fstab UUID = 47c36ad7-f49f-4ecd-9b72-4801c5bb3a04 swap swap defaults 0 0 1 /etc/networks # 2 /etc/networks # networks This file describes a number of netname-to-address 3 /etc/networks # mappings for the TCP/IP subsystem. It is mostly 4 /etc/networks # used at boot time, when no name servers are running. 5 /etc/networks # 6 /etc/networks 7 /etc/networks loopback 127 .0.0.0 8 /etc/networks link-local 169 .254.0.0 9 /etc/networks 10 /etc/networks # End. ARGC \u7684\u7528\u6cd5\uff1a \u6bcf\u4e2a\u53d8\u91cf\u7684\u540d\u5b57\u901a\u8fc7 ARGV \u83b7\u53d6\u3002 $ awk '{print ARGC}' /etc/fstab /etc/issue 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 $ awk 'BEGIN{print ARGC}' /etc/fstab /etc/issue 3 ARGV \u7684\u7528\u6cd5\uff1a $ awk 'BEGIN{print ARGV[0]}' /etc/fstab /etc/issue awk $ awk 'BEGIN{print ARGV[1]}' /etc/fstab /etc/issue /etc/fstab $ awk 'BEGIN{print ARGV[2]}' /etc/fstab /etc/issue /etc/issue $ awk 'BEGIN{print ARGV[3]}' /etc/fstab /etc/issue","title":"5.10.8.1.\u5185\u7f6e\u53d8\u91cf"},{"location":"linux/SRE/05-RegExpress/#51082","text":"\u81ea\u5b9a\u4e49\u53d8\u91cf\u662f\u533a\u5206\u5b57\u7b26\u5927\u5c0f\u5199\u7684\uff0c\u4f7f\u7528\u4e0b\u9762\u7684\u65b9\u5f0f\u8fdb\u884c\u8d4b\u503c\u3002 -v var=value \u5728program\u4e2d\u76f4\u63a5\u5b9a\u4e49 \u4e3e\u4f8b\uff1a $ awk -v t1 = t2 = \"hello awk\" 'BEGIN{print t1, t2}' t2 = hello awk $ awk -v t1 = t2 = \"hello awk\" 'BEGIN{t1=t2=\"gawk\"; print t1, t2}' gawk gawk $ awk 'BEGIN{t1=t2=\"hello awk\"; print t1, t2}' hello awk hello awk $ awk -v t1 = \"hello awk\" '{print t1}' /etc/issue hello awk hello awk hello awk hello awk hello awk $ awk -v t1 = \"hello awk\" 'BEGIN{print t1}' /etc/issue hello awk $ awk -v t1 = \"hello awk\" 'BEGIN{print t1}' hello awk $ awk -F: '{sex=\"male\"; print $1, sex, age; age=28}' /etc/passwd | head -n3 root male messagebus male 28 systemd-network male 28 $ cat < awkscript {print script,$1,$2} EOF $ awk -F: -f awkscript script = \"awk\" /etc/passwd | head -n2 awk root x awk messagebus x \u52a8\u4f5c printf \u3002 \u52a8\u4f5cprintf\u53ef\u4ee5\u5b9e\u73b0\u683c\u5f0f\u5316\u8f93\u51fa\u3002 \u683c\u5f0f\uff1a printf \"FORMAT\", item1, item2, ...... \u8bf4\u660e\uff1a \u5fc5\u987b\u6307\u5b9aFORMAT \u4e0d\u4f1a\u81ea\u52a8\u6362\u884c\uff0c\u9700\u8981\u663e\u5f0f\u7ed9\u51fa\u6362\u884c\u63a7\u5236\u7b26 \\n \u3002 FORMAT\u4e2d\u9700\u8981\u5206\u522b\u4e3a\u540e\u9762\u6bcf\u4e2aitem\u6307\u5b9a\u683c\u5f0f\u7b26\u3002 \u683c\u5f0f\u7b26\uff1a\u4e0eitem\u662f\u4e00\u4e00\u5bf9\u5e94\u7684 %s \uff1a\u663e\u793a\u5b57\u7b26\u4e32 %d , %i \uff1a\u663e\u793a\u5341\u8fdb\u5236\u6574\u6570 %f \uff1a\u663e\u793a\u4e3a\u6d6e\u70b9\u6570 %e , %E \uff1a\u663e\u793a\u79d1\u5b66\u8ba1\u6570\u6cd5\u6570\u503c %c \uff1a\u663e\u793a\u5b57\u7b26\u7684ASCII\u7801 %g , %G \uff1a\u4ee5\u79d1\u5b66\u8ba1\u6570\u6cd5\u6216\u6d6e\u70b9\u5f62\u5f0f\u663e\u793a\u6570\u503c %u \uff1a\u65e0\u7b26\u53f7\u6574\u6570 %% \uff1a\u663e\u793a % \u81ea\u8eab \u4fee\u9970\u7b26\uff1a #[.#] \uff1a\u7b2c\u4e00\u4e2a\u6570\u5b57\u63a7\u5236\u663e\u793a\u7684\u5bbd\u5ea6\uff0c\u7b2c\u4e8c\u4e2a#\u8868\u793a\u5c0f\u6570\u70b9\u540e\u7cbe\u5ea6\uff0c\u5982 %3.1f - \uff1a\u5de6\u5bf9\u9f50\uff08\u9ed8\u8ba4\u53f3\u5bf9\u9f50\uff09\uff0c\u5982 %-15s + \uff1a\u663e\u793a\u6570\u503c\u7684\u6b63\u8d1f\u7b26\u53f7\uff0c\u5982 %+d \u793a\u4f8b\uff1a $ awk -F: '{printf \"%s\", $1}' /etc/passwd | head -n3 rootmessagebussystemd-networksystemd-timesyncnobodymailchronypostfixmanlpgamesftpdaemonrpcnscdpolkitdattftpftpsecurebinstatdsshdvagrantpesignsvntester1tester2tester3tester4tester5user0user1user2user3user4user5user6user7user8user9gentoonginxvarnishmysqlwebuseradmin3smithpm1tm1tm2 $ awk -F: '{printf \"%s\\n\", $1}' /etc/passwd | head -n3 root messagebus systemd-network $ awk -F: '{printf \"%20s\\n\", $1}' /etc/passwd | head -n3 root messagebus systemd-network $ awk -F: '{printf \"%-20s\\n\", $1}' /etc/passwd | head -n3 root messagebus systemd-network $ awk -F: '{printf \"%-20s %10d\\n\", $1, $3}' /etc/passwd | head -n3 root 0 messagebus 499 systemd-network 497 $ awk -F: '{printf \"Username: %s\\n\", $1}' /etc/passwd | head -n3 Username: root Username: messagebus Username: systemd-network $ awk -F: '{printf \"Username: %s UID:%d\\n\", $1, $3}' /etc/passwd | head -n3 Username: root UID:0 Username: messagebus UID:499 Username: systemd-network UID:497 $ awk -F: '{printf \"Username: %25s UID:%d\\n\", $1, $3}' /etc/passwd | head -n3 Username: root UID:0 Username: messagebus UID:499 Username: systemd-network UID:497 $ awk -F: '{printf \"Username: %-25s UID:%d\\n\", $1, $3}' /etc/passwd | head -n3 Username: root UID:0 Username: messagebus UID:499 Username: systemd-network UID:497","title":"5.10.8.2.\u81ea\u5b9a\u4e49\u53d8\u91cf"},{"location":"linux/SRE/05-RegExpress/#5109beginend","text":"\u793a\u4f8b\uff1a awk -F \":\" 'BEGIN{printf \"--------------------------------\\n%-20s|%10s|\\n--------------------------------\\n\", \"Username\", \"UID\"}{printf \"%-20s|%-10d|\\n--------------------------------\\n\", $1, $3}END{print \"end\"}' /etc/passwd -------------------------------- Username | UID | -------------------------------- root | 0 | -------------------------------- daemon | 1 | -------------------------------- bin | 2 | ------------------------------- ... ... -------------------------------- mfe | 997 | -------------------------------- end","title":"5.10.9.BEGIN/END"},{"location":"linux/SRE/05-RegExpress/#51010","text":"{statements;...} \u7ec4\u5408\u8bed\u53e5 if(condition){statements;...} if(condition){statements;...} else(statements;...) switch(expression){case VALUE1 or /REGEXP/: statement1; case VALUE2 or /REGEXP2/: statement2;......;default: statementn} while(condition){statements;...} do(statements;...) while{condition} for(expr1;expr2;expr3) {statements;...} break continue exit if-else\u793a\u4f8b\uff1a $ cat < score.txt Name Score Tom 100 Jack 91 Bill 81 Jim 51 EOF $ awk 'NR!=1{score=$2;if($2>=80){print $1, \"Good\"}else if($2>=60){print $1, \"Pass\"}else{print $1, \"failed\"}}' score.txt Tom Good Jack Good Bill Good Jim failed switch\u793a\u4f8b\uff1a $ awk 'NR!=1{switch($2){case 100:print $1,\"good\"; case 60:print $1,\"Pass\"; default:print $1,\"others\"}}' score.txt Tom good Tom Pass Tom others Jack others Bill others Jim others while\u793a\u4f8b\uff1a $ awk 'BEGIN{i=0;sum=0;while(i<=100){sum+=i;i++};print sum}' 5050 do-while\u793a\u4f8b\uff1a $ awk 'BEGIN{i=0;sum=0;do{sum+=i;i++}while(i<101);print sum}' 5050 for\u793a\u4f8b\uff1a $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){sum+=i};print sum}' 5050 \u547d\u4ee4\u6548\u7387\u6bd4\u8f83\uff1a $ time ( awk 'BEGIN{i=0;sum=0;while(i<=100000){sum+=i;i++};print sum}' ) 5000050000 real 0m0.028s user 0m0.027s sys 0m0.001s $ time ( seq -s+ 1000000 | bc ) 500000500000 real 0m0.329s user 0m0.240s sys 0m0.094s $ time ( awk 'BEGIN{i=0;sum=0;for(i=1;i<=1000000;i++){sum+=i};print sum}' ) 500000500000 real 0m0.050s user 0m0.046s sys 0m0.004s contine\u793a\u4f8b\uff1a\u4e2d\u65ad\u5f53\u524d\u5faa\u73af\uff0c\u8fdb\u5165\u4e0b\u4e00\u6b21\u5faa\u73af\u3002 $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){if(i==50)continue;sum+=i};print sum}' 5000 contine\u793a\u4f8b\uff1a\u4e2d\u65ad\u6574\u4e2a\u5faa\u73af\u3002 $ awk 'BEGIN{i=0;sum=0;for(i=1;i<=100;i++){if(i==50)break;sum+=i};print sum}' 1225 next\u793a\u4f8b\uff1a\u63d0\u524d\u7ed3\u675f\u5bf9\u672c\u884c\u5904\u7406\uff0c\u76f4\u63a5\u8fdb\u5165\u4e0b\u4e00\u884c\u5904\u7406\uff08\u6ce8\uff0cawk\u81ea\u5faa\u73af\uff0c\u5e76\u975e\u524d\u9762\u7684for\u6216while\u5faa\u73af\uff09 $ awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd # \u5947\u6570\u884c\u6253\u5370 root 0 systemd-timesync 496 nobody 65534 chrony 494 games 492 daemon 2 rpc 490 polkitd 488 ftpsecure 486 sshd 484 vagrant 1000 svn 482 tester1 600 tester4 1002 user0 1004 user2 1006 user4 1008 user6 1010 user8 1012 gentoo 1014 varnish 1016 webuser 666 admin3 1020 smith 2002 tm1 2004 $ awk -F: '{if($3%2==0)next;print $1,$3}' /etc/passwd # \u5076\u6570\u884c\u6253\u5370 messagebus 499 systemd-network 497 mail 495 postfix 51 man 13 lp 493 ftp 491 nscd 489 at 25 tftp 487 bin 1 statd 485 pesign 483 tester2 601 tester3 1001 tester5 1003 user1 1005 user3 1007 user5 1009 user7 1011 user9 1013 nginx 1015 mysql 1017 pm1 2003 tm2 2005","title":"5.10.10.\u5e38\u7528\u63a7\u5236\u8bed\u53e5"},{"location":"linux/SRE/05-RegExpress/#51011","text":"\u5173\u8054\u6570\u7ec4\u662f\u4e00\u79cd\u6570\u636e\u7ed3\u6784\uff0c\u4e5f\u79f0\u4e3a\u5b57\u5178\u6216\u6620\u5c04\u3002\u4e0e\u4f20\u7edf\u7684\u6570\u7ec4\u4e0d\u540c\uff0c\u5173\u8054\u6570\u7ec4\u7684\u7d22\u5f15\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\u7684\u6570\u636e\uff0c\u4f8b\u5982\u5b57\u7b26\u4e32\u6216\u5bf9\u8c61\uff0c\u800c\u4e0d\u4ec5\u4ec5\u662f\u6574\u6570\u3002 \u63d0\u793a\uff1a \u5728\u8ba1\u7b97\u673a\u7f16\u7a0b\u4e2d\uff0c\u9664\u4e86\u5173\u8054\u6570\u7ec4\uff0c\u8fd8\u6709\u5176\u4ed6\u51e0\u79cd\u5e38\u89c1\u7684\u6570\u7ec4\u7c7b\u578b\uff0c\u5305\u62ec\uff1a \u7ebf\u6027\u6570\u7ec4\uff08\u6216\u79f0\u4e3a\u7d22\u5f15\u6570\u7ec4\uff09\uff1a\u8fd9\u662f\u6700\u5e38\u89c1\u7684\u6570\u7ec4\u7c7b\u578b\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e00\u4e2a\u6570\u5b57\u7d22\u5f15\uff0c\u53ef\u4ee5\u7528\u6765\u5feb\u901f\u8bbf\u95ee\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u3002\u4f8b\u5982\uff0c\u5728C\u8bed\u8a00\u4e2d\uff0c\u6570\u7ec4\u7684\u6bcf\u4e2a\u5143\u7d20\u90fd\u53ef\u4ee5\u901a\u8fc7\u6570\u7ec4\u4e0b\u6807\u6765\u8bbf\u95ee\u3002 \u591a\u7ef4\u6570\u7ec4\uff1a\u591a\u7ef4\u6570\u7ec4\u662f\u4e00\u79cd\u6570\u7ec4\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u4e5f\u662f\u4e00\u4e2a\u6570\u7ec4\u3002\u5728\u4e8c\u7ef4\u6570\u7ec4\u4e2d\uff0c\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e24\u4e2a\u7d22\u5f15\uff08\u4f8b\u5982\uff0c\u884c\u548c\u5217\uff09\uff0c\u53ef\u4ee5\u7528\u4e8e\u8bbf\u95ee\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u3002\u5728\u9ad8\u7ef4\u6570\u7ec4\u4e2d\uff0c\u6bcf\u4e2a\u5143\u7d20\u90fd\u5177\u6709\u66f4\u591a\u7684\u7d22\u5f15\u3002 \u52a8\u6001\u6570\u7ec4\uff1a\u52a8\u6001\u6570\u7ec4\u662f\u4e00\u79cd\u53ef\u4ee5\u52a8\u6001\u8c03\u6574\u5927\u5c0f\u7684\u6570\u7ec4\u3002\u5728\u8bb8\u591a\u7f16\u7a0b\u8bed\u8a00\u4e2d\uff0c\u52a8\u6001\u6570\u7ec4\u53ef\u4ee5\u52a8\u6001\u5206\u914d\u5185\u5b58\uff0c\u4ee5\u4fbf\u5728\u7a0b\u5e8f\u8fd0\u884c\u65f6\u6839\u636e\u9700\u8981\u8c03\u6574\u6570\u7ec4\u7684\u5927\u5c0f\u3002 \u5411\u91cf\uff1a\u5411\u91cf\u662f\u4e00\u79cd\u6570\u7ec4\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u90fd\u662f\u76f8\u540c\u7684\u6570\u636e\u7c7b\u578b\u3002\u5411\u91cf\u901a\u5e38\u7528\u4e8e\u6267\u884c\u6570\u5b66\u8fd0\u7b97\u6216\u5904\u7406\u5927\u91cf\u6570\u5b57\u6570\u636e\u3002 \u5728 awk \u4e2d\u4f7f\u7528\u6570\u7ec4\u65f6\uff0c\u901a\u5e38\u4f1a\u5c06\u67d0\u4e9b\u503c\u4e0e\u4e00\u4e2a\u5b57\u7b26\u4e32\u76f8\u5173\u8054\uff0c\u4ee5\u4fbf\u5728\u9700\u8981\u65f6\u53ef\u4ee5\u901a\u8fc7\u8be5\u5b57\u7b26\u4e32\u5feb\u901f\u5730\u68c0\u7d22\u8be5\u503c\u3002 awk \u7684\u6570\u7ec4\u662f\u4e00\u4e2a\u5173\u8054\u6570\u7ec4\uff0c\u5176\u4e2d\u6bcf\u4e2a\u5143\u7d20\u90fd\u7531\u4e00\u4e2a\u552f\u4e00\u7684\u952e\u503c\u548c\u4e00\u4e2a\u5bf9\u5e94\u7684\u503c\u7ec4\u6210\u3002\u952e\u503c\uff08\u6216\u79f0\u4e3a\u7d22\u5f15\uff09\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\u7684\u5b57\u7b26\u4e32\u3002 \u6570\u7ec4\u53ef\u4ee5\u901a\u8fc7\u4ee5\u4e0b\u8bed\u6cd5\u8fdb\u884c\u58f0\u660e\uff1a array_name [ index ] = value \u5176\u4e2d\uff0c array_name \u662f\u6570\u7ec4\u7684\u540d\u79f0\uff0c index \u662f\u5143\u7d20\u7684\u7d22\u5f15\u503c\uff0c value \u662f\u5143\u7d20\u7684\u503c\u3002 \u4f8b\u5982\uff0c\u4ee5\u4e0b\u662f\u4e00\u4e2a\u5305\u542b\u4e09\u4e2a\u5143\u7d20\u7684\u5173\u8054\u6570\u7ec4\u7684\u793a\u4f8b\uff1a array [ \"apple\" ] = 1 array [ \"banana\" ] = 2 array [ \"orange\" ] = 3 \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c array \u662f\u4e00\u4e2a\u5173\u8054\u6570\u7ec4\uff0c\u5176\u7d22\u5f15\u4e3a\u5b57\u7b26\u4e32\u7c7b\u578b\uff0c\u800c\u503c\u4e3a\u6574\u6570\u7c7b\u578b\u3002\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u7684\u65b9\u5f0f\u8bbf\u95ee\u8be5\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\uff1a value = array [ \"apple\" ] \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c value \u7684\u503c\u5c06\u4e3a 1 \uff0c\u56e0\u4e3a array[\"apple\"] \u7684\u503c\u4e3a 1 \u3002 \u4ee5\u4e0b\u662f\u7528 awk \u547d\u4ee4\u6765\u521b\u5efa\u4e0a\u9762\u90a3\u4e2a\u5305\u542b\u4e09\u4e2a\u5143\u7d20\u7684\u5173\u8054\u6570\u7ec4\uff0c\u904d\u5386\u5e76\u8f93\u51fa\u6570\u7ec4\u503c\uff1a awk 'BEGIN { array[\"apple\"]=1; array[\"banana\"]=2; array[\"orange\"]=3; for(i in array){print array[i]}}' 3 1 2 \u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u4e92\u6362\u4e86\u6570\u7ec4\u7684\u952e\u548c\u503c\u3002 $ awk 'BEGIN {arr[1]=\"apple\";arr[2]=\"banana\";arr[3]=\"orange\";for(i in arr){print arr[i]}}' apple banana orange \u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c i \u662f\u6570\u7ec4 arr \u7684\u7d22\u5f15\u503c\uff0c arr[i] \u662f\u6570\u7ec4\u4e2d\u5bf9\u5e94\u7684\u5143\u7d20\u503c\u3002\u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\u53ef\u4ee5\u5faa\u73af\u904d\u5386\u6574\u4e2a\u6570\u7ec4\uff0c\u5e76\u8f93\u51fa\u5176\u4e2d\u7684\u5143\u7d20\u3002 \u9664\u4e86\u4f7f\u7528\u5faa\u73af\u904d\u5386\u6570\u7ec4\u4e4b\u5916\uff0c\u8fd8\u53ef\u4ee5\u4f7f\u7528 length \u51fd\u6570\u83b7\u53d6\u6570\u7ec4\u4e2d\u5143\u7d20\u7684\u6570\u91cf\u3002\u4f8b\u5982\uff1a $ awk 'BEGIN { arr[1]=\"apple\"; arr[2]=\"banana\"; arr[3]=\"orange\"; print length(arr) }' 3 \u4e0a\u9762\u7684\u793a\u4f8b\u5c06\u8f93\u51fa\u6570\u5b573\uff0c\u8868\u793a\u6570\u7ec4 arr \u4e2d\u5305\u542b\u4e09\u4e2a\u5143\u7d20\u3002 \u4e3e\u4f8b\uff1a\u53bb\u91cd\u590d\u8bb0\u5f55\u3002 line \u662f\u6570\u7ec4\u540d\uff0c $0 \u662f awk \u8bfb\u53d6\u7684\u5f53\u524d\u884c\u7684\u5185\u5bb9\u3002 line[$0] \u7b49\u4ef7\u4e8e line[\"a\"] \uff0c line[\"b\"] \uff0c......\u3002 \u6211\u4eec\u770b\u6267\u884c\u8fc7\u7a0b\uff1a awk\u8bfb\u5165\u7b2c1\u884c\uff1b \u6267\u884c line[\"a\"] \uff0c\u503c\u4e3a\u7a7a\uff1b \u6c42\u53cd\uff0c\u5219\u7b2c\u4e00\u884c\u7684\u503c\u53d8\u4e3a true \uff0c\u5373 !line[\"a\"]=true \uff1b \u5f53 !line[\"a\"] \u4e3a true \uff0c\u5219\u6253\u5370\u5f53\u524d\u884c\uff0c\u5373\u8f93\u51fa a \u5230\u5c4f\u5e55\uff1b \u6267\u884c line[\"a\"]++ \uff0c\u6ce8\u610f\u7b2c2\u6b65\u4e2d line[\"a\"] \u7684\u503c\u662f\u7a7a\uff0c\u6267\u884c ++ \u540e\u503c\u53d8\u4e3a 1 \u3002 \u540c\u7406\uff0c\u6211\u4eec\u53ef\u4ee5\u770b\u5230\u7b2c2\uff0c3\uff0c4\u884c\u90fd\u8f93\u51fa\u4e86\u3002 \u5f53\u8bfb\u5165\u7b2c5\u884c\u65f6\uff08\u7b2c\u4e8c\u4e2a a \uff09\uff0c\u6267\u884c line[\"a\"] \uff0c\u503c\u4e3a 1 \uff1b !line[\"a\"]=0 \uff0c\u5373false\uff1b\u5219\u4e0d\u6253\u5370\u5f53\u524d\u884c\uff0c\u5373\u4e0d\u8f93\u51fa a \u5230\u5c4f\u5e55\uff1b\u6267\u884c ++ \u540e\u503c\u53d8\u4e3a 2 \u5f53\u8bfb\u5165\u7b2c8\u884c\u65f6\uff08\u7b2c\u4e09\u4e2a a \uff09\uff0c\u6267\u884c line[\"a\"] \uff0c\u503c\u4e3a 2 \uff1b !line[\"a\"]=0 \uff0c\u5373false\uff1b\u5219\u4e0d\u6253\u5370\u5f53\u524d\u884c\uff0c\u5373\u4e0d\u8f93\u51fa a \u5230\u5c4f\u5e55\uff1b\u6267\u884c ++ \u540e\u503c\u53d8\u4e3a 3 \u4ee5\u6b64\u7c7b\u63a8\uff0c\u8bfb\u5165\u7b2c\u4e8c\u4e2a b \uff0c c \uff0c d \uff0c e \uff0c\u90fd\u4e0d\u4f1a\u518d\u8f93\u51fa\u5230\u5c4f\u5e55\uff0c\u4ece\u800c\u5b9e\u73b0\u53bb\u91cd\u8f93\u51fa\u5230\u529f\u80fd\u3002 $ cat > test << EOF a b c d a c d a b b e EOF $ awk '!line[$0]++' test a b c d e \u4e3e\u4f8b\uff1a\u5224\u65ad\u6570\u7ec4\u7d22\u5f15\u662f\u5426\u5b58\u5728\u3002 \u65b9\u6cd5\uff1a in array \uff0c 0 \u8868\u793a\u4e0d\u5b58\u5728\uff0c 1 \u8868\u793a\u5b58\u5728\u3002 $ awk 'BEGIN{array[\"i\"]=\"x\";array[\"j\"]=\"j\";print \"i\" in array, \"y\" in array}' 1 0 $ awk 'BEGIN{array[\"i\"]=\"x\";array[\"j\"]=\"j\";if(\"i\" in array){print \"exits!\"}else{print \"not exists!\"}}' exits! $ awk 'BEGIN{array[\"i\"]=\"x\";array[\"j\"]=\"j\";if(\"abc\" in array){print \"exits!\"}else{print \"not exists!\"}}' not exists! \u4e3e\u4f8b\uff1a\u904d\u5386\u6570\u7ec4\u4e2d\u6bcf\u4e2a\u5143\u7d20\u3002 \u65b9\u6cd5\uff1a for(your_var in array){your_for_body} \uff0c\u6ce8\u610f\uff0cyour_var\u4f1a\u904d\u5386\u6bcf\u4e2a\u7d22\u5f15\u3002 $ awk 'BEGIN{weekday[\"mon\"]=\"Monday\";weekday[\"tue\"]=\"Tuesday\";for(i in weekday){print i,weekday[i]}}' tue Tuesday mon Monday $ awk 'BEGIN{weekday[\"mon\"]=\"Monday\";weekday[\"tue\"]=\"Tuesday\";for(i in weekday){print i\": \"weekday[i]}}' tue: Tuesday mon: Monday \u6ce8\u610f\u4e0b\u9762\u7684\u6362\u884c\u5199\u6cd5\uff0c\u4e0d\u9700\u8981\u53cd\u659c\u6760 \\ \u3002 $ awk 'BEGIN{ arr[\"x\"]=\"welcome\" arr[\"y\"]=\"to\" arr[\"z\"]=\"Shanghai\" for (i in arr) { print i, arr[i] } }' x welcome y to z Shanghai \u793a\u4f8b\uff1a\u683c\u5f0f\u5316\u8f93\u51fa\u7528\u6237\u540d\u548c\u5bc6\u7801\u3002 $ awk -F: '{user[$1]=$3}END{for (i in user){print \"Username: \" i, \"UID: \" user[i]}}' /etc/passwd Username: sshd UID: 476 Username: rpc UID: 482 Username: tftp UID: 488 Username: usbmux UID: 480 Username: srvGeoClue UID: 487 ...... \u793a\u4f8b\uff1a\u663e\u793a\u4e3b\u673a\u8fde\u63a5\u72b6\u6001\u51fa\u73b0\u7684\u6b21\u6570\u3002 # \u4f20\u7edf\u65b9\u6cd5 $ ss -ant | awk 'NR>=2{print $1}' | sort | uniq -c $ ss -ant | awk 'NR!=1{print $1}' | sort | uniq -c 1 ESTAB 6 LISTEN # \u4f7f\u7528awk\u6570\u7ec4 $ ss -ant | awk 'NR>=2{state[$1]++}END{for(i in state){print state[i], i}}' $ ss -ant | awk 'NR!=1{state[$1]++}END{for(i in state){print state[i], i}}' 6 LISTEN 1 ESTAB","title":"5.10.11.\u6570\u7ec4"},{"location":"linux/SRE/05-RegExpress/#51012awk","text":"\u53c2\u8003\uff1a awk \u51fd\u6570\u5b98\u7f51","title":"5.10.12.awk\u51fd\u6570"},{"location":"linux/SRE/05-RegExpress/#510121","text":"\u5728 awk \u4e2d\uff0c\u51fd\u6570\u662f\u4e00\u79cd\u7528\u4e8e\u6267\u884c\u7279\u5b9a\u4efb\u52a1\u6216\u8ba1\u7b97\u7279\u5b9a\u503c\u7684\u53ef\u91cd\u7528\u4ee3\u7801\u5757\u3002 awk \u63d0\u4f9b\u4e86\u8bb8\u591a\u5185\u7f6e\u51fd\u6570\uff0c\u53ef\u4ee5\u7528\u4e8e\u5904\u7406\u6587\u672c\u6570\u636e\u3001\u6267\u884c\u6570\u5b66\u8fd0\u7b97\u3001\u64cd\u4f5c\u5b57\u7b26\u4e32\u7b49\u3002 \u4ee5\u4e0b\u662f\u4e00\u4e9b\u5e38\u7528\u7684awk\u51fd\u6570\u793a\u4f8b\uff1a length(string) \uff1a\u8fd4\u56de\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u3002 $ awk 'BEGIN { str = \"Hello World\"; len = length(str); print len }' 11 $ cut -d: -f1 /etc/passwd | awk '{print length($1)}' | head -3 4 10 15 substr(string, start, length) \uff1a\u4ece\u6307\u5b9a\u4f4d\u7f6e\u5f00\u59cb\u63d0\u53d6\u5b57\u7b26\u4e32\u7684\u5b50\u4e32\u3002 $ awk 'BEGIN { str = \"Hello World\"; substring = substr(str, 7, 5); print substring }' World sub(regexp, replacement [, target]) \uff1a\u4ece\u5b57\u7b26\u4e32target\u4e2d\u641c\u7d22\u5339\u914dregexp\u7684\u5185\u5bb9\uff0c\u5e76\u628a\u7b2c\u4e00\u4e2a\u5339\u914d\u7684\u5185\u5bb9\u66ff\u6362\u4e3areplacement\u3002\u61d2\u60f0\u6a21\u5f0f\u3002 \u6ce8\u610f\uff1a sub() \u51fd\u6570\u5728\u539f\u59cb\u5b57\u7b26\u4e32\u4e0a\u8fdb\u884c\u66ff\u6362\u64cd\u4f5c\uff0c\u5e76\u8fd4\u56de\u66ff\u6362\u7684\u6b21\u6570\u3002 # \u5728\u539f\u59cb\u5b57\u7b26\u4e32\u4e2d\uff0c\u7b2c\u4e00\u4e2a\u5339\u914d\u5230\u7684\"at\"\u88ab\u66ff\u6362\u4e3a\"ith\"\uff0c\u56e0\u6b64\u8f93\u51fa\u7ed3\u679c\u4e2d\u7684\"at\"\u53d8\u4e3a\"ith\"\uff0c\u5176\u4ed6\u5730\u65b9\u7684\"at\"\u4fdd\u6301\u4e0d\u53d8 $ awk 'BEGIN { str = \"water, water, everywhere\"; sub(/at/, \"ith\", str); print str }' wither, water, everywhere # \u8fd4\u56de\u5339\u914d\u6b21\u6570 $ awk 'BEGIN { str = \"water, water, everywhere\"; str_new = sub(/at/, \"ith\", str); print str_new }' 1 $ echo \"2023:15:35 08:15:26\" | awk 'sub(/:/, \"-\", $0)' 2023 -15:35 08 :15:26 $ echo \"2023:15:35 08:15:26\" | awk 'sub(/:/, \"-\", $1)' 2023 -15:35 08 :15:26 $ echo \"2023:15:35 08:15:26\" | awk 'sub(/:/, \"-\", $2)' 2023 :15:35 08 -15:26 gsub(regexp, replacement [, target])\uff1a\u4ece\u5b57\u7b26\u4e32target\u4e2d\u641c\u7d22\u5339\u914dregexp\u7684\u5185\u5bb9\uff0c\u5e76\u628a\u5168\u90e8\u5339\u914d\u7684\u5185\u5bb9\u66ff\u6362\u4e3areplacement\u3002\u8d2a\u5a6a\u6a21\u5f0f\u3002 # \u5728\u539f\u59cb\u5b57\u7b26\u4e32\u4e2d\uff0c\u5c06\u6240\u6709\u5339\u914d\u5230\u7684\"at\"\u88ab\u66ff\u6362\u4e3a\"ith\" $ awk 'BEGIN { str = \"water, water, everywhere\"; gsub(/at/, \"ith\", str); print str }' wither, wither, everywhere # \u8fd4\u56de\u5339\u914d\u6b21\u6570 $ awk 'BEGIN { str = \"water, water, everywhere\"; str_new = gsub(/at/, \"ith\", str); print str_new }' 2 $ echo \"2023:15:35 08:15:26\" | awk 'gsub(/:/, \"-\", $0)' 2023 -15-35 08 -15-26 $ echo \"2023:15:35 08:15:26\" | awk 'gsub(/:/, \"-\", $1)' 2023 -15-35 08 :15:26 $ echo \"2023:15:35 08:15:26\" | awk 'gsub(/:/, \"-\", $2)' 2023 :15:35 08 -15-26 split(string, array, delimiter) \uff1a\u5c06\u5b57\u7b26\u4e32string\u6309\u6307\u5b9a\u5206\u9694\u7b26delimiter\u62c6\u5206\u6210\u6570\u7ec4array\u7684\u5143\u7d20\u3002 \u6ce8\u610f\uff1a\u7b2c\u4e00\u4e2a\u7d22\u5f15\u503c\u4e3a 1 \uff0c\u7b2c\u4e8c\u4e2a\u7d22\u5f15\u503c\u4e3a 2 . $ awk 'BEGIN { str = \"apple,banana,orange\"; split(str, fruits, \",\"); print fruits[2] }' banana $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[1]}' messagebus $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[2]}' x $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[3]}' 499 $ head -n2 /etc/passwd | awk '{split($0, array, \":\")}END{print array[7]}' /usr/bin/false index(string, search) \uff1a\u5728\u5b57\u7b26\u4e32\u4e2d\u67e5\u627e\u6307\u5b9a\u5b50\u4e32\u7684\u4f4d\u7f6e\u3002 $ awk 'BEGIN { str = \"Hello World\"; pos = index(str, \"World\"); print pos }' 7 sprintf(format, expression) \uff1a\u6839\u636e\u6307\u5b9a\u7684\u683c\u5f0f\u5c06\u8868\u8fbe\u5f0f\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\u3002 $ awk 'BEGIN { num = 3.14159; str = sprintf(\"%.2f\", num); print str }' 3 .14 rand() \uff1a\u8fd4\u56de\u4e00\u4e2a\u968f\u673a\u6570\uff0c\u503c\u5728 0 \u548c 1 \u4e4b\u95f4\u5747\u5300\u5206\u5e03\u3002\u8fd9\u4e2a\u503c\u53ef\u4ee5\u662f 0 \uff0c\u4f46\u4e0d\u4f1a\u662f 1 \u3002\u4ece\u4e0b\u9762\u7684\u4f8b\u5b50\u53ef\u4ee5\u770b\u51fa\uff0c\u8fd0\u884c\u7ed3\u679c\u90fd\u662f\u4e00\u6837\u7684\uff0c\u6240\u4ee5\u4ea7\u751f\u968f\u673a\u6570\u7684\u79cd\u5b50\u662f\u4e00\u6837\u7684\u3002 $ awk 'BEGIN{print rand()}' 0 .924046 $ awk 'BEGIN{print rand()}' 0 .924046 $ awk 'BEGIN{print rand()}' 0 .924046 srand() \uff1a\u914d\u5408 rand() \u51fd\u6570\uff0c\u751f\u6210\u968f\u673a\u6570\u79cd\u5b50\u3002 $ awk 'BEGIN{srand();print rand()}' 0 .112006 $ awk 'BEGIN{srand();print rand()}' 0 .663431 $ awk 'BEGIN{srand();print rand()}' 0 .541305 int() \uff1a\u8fd4\u56de\u6574\u6570\u3002 $ awk 'BEGIN{srand();print int(rand()*100)}' 84 $ awk 'BEGIN{srand();print int(rand()*100)}' 66 $ awk 'BEGIN{srand();print int(rand()*100)}' 8 system(command) \uff1a\u6267\u884ccommand\u547d\u4ee4\uff08\u53ef\u4ee5\u662f\u4efb\u4f55\u6709\u6548\u7684Shell\u547d\u4ee4\uff09\u5e76\u8fd4\u56de\u547d\u4ee4\u7684\u9000\u51fa\u72b6\u6001\u7801\u3002\u5141\u8bb8\u5728 awk \u811a\u672c\u4e2d\u6267\u884c\u5916\u90e8\u547d\u4ee4\uff0c\u5e76\u83b7\u53d6\u547d\u4ee4\u6267\u884c\u7684\u7ed3\u679c\u3002 # \u6267\u884cls -l\u547d\u4ee4\uff0c\u5e76\u5c06\u547d\u4ee4\u7684\u9000\u51fa\u72b6\u6001\u7801\u5b58\u50a8\u5728status\u53d8\u91cf\u4e2d\uff0c\u5e76\u6253\u5370status\u53d8\u91cf\u7684\u503c $ awk 'BEGIN { status = system(\"ls -l\"); print \"Exit status:\", status }' total 0 drwxr-xr-x 1 vagrant users 70 Jan 2 15 :54 Desktop drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Documents drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Downloads drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Music drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Pictures drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Public drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Templates drwxr-xr-x 1 vagrant users 0 Jan 2 15 :54 Videos drwxr-xr-x 1 vagrant users 0 Mar 15 2022 bin Exit status: 0 $ awk 'BEGIN{score=100; system(\"echo your score is \" score)}' your score is 100 systime() \uff1a\u5f53\u524d\u65f6\u95f4\u52301970\u5e741\u67081\u65e5\u5230\u79d2\u6570 $ awk 'BEGIN{print systime()}' 1684158395 strftime(format, timestamp) \uff1a\u5c06\u65f6\u95f4\u6233timestamp\u8f6c\u6362\u4e3a\u6307\u5b9a\u683c\u5f0fformat\u7684\u65e5\u671f\u548c\u65f6\u95f4\u5b57\u7b26\u4e32\u3002timestamp\u901a\u5e38\u662f\u4e00\u4e2a\u4ee5\u79d2\u4e3a\u5355\u4f4d\u8868\u793a\u7684\u6574\u6570\u3002 \u5e38\u89c1\u7684\u683c\u5f0f\u5316\u5b57\u7b26\u4e32\u9009\u9879\uff1a %Y \uff1a\u56db\u4f4d\u6570\u7684\u5e74\u4efd\uff08\u4f8b\u5982\uff1a2023\uff09 %m \uff1a\u4e24\u4f4d\u6570\u7684\u6708\u4efd\uff0801-12\uff09 %d \uff1a\u4e24\u4f4d\u6570\u7684\u65e5\u671f\uff0801-31\uff09 %H \uff1a\u4e24\u4f4d\u6570\u7684\u5c0f\u65f6\uff0800-23\uff09 %M \uff1a\u4e24\u4f4d\u6570\u7684\u5206\u949f\uff0800-59\uff09 %S \uff1a\u4e24\u4f4d\u6570\u7684\u79d2\uff0800-60\uff09 %Z \uff1a\u65f6\u533a\u540d\u79f0\uff08\u4f8b\u5982\uff1aGMT\uff09 # \u5c06\u5f53\u524d\u65f6\u95f4\u6233\u8f6c\u6362\u4e3a\u683c\u5f0f\u4e3a\"YYYY-MM-DD HH:MM:SS\"\u7684\u65e5\u671f\u548c\u65f6\u95f4\u5b57\u7b26\u4e32 $ awk 'BEGIN { timestamp = systime(); str = strftime(\"%Y-%m-%d %H:%M:%S\", timestamp); print str }' 2023 -05-15 22 :01:35 # \u5c06\u5f53\u524d\u65f6\u95f4\u6233\u7684\u524d\u4e00\u5c0f\u65f6\uff083600\u79d2\uff09\u8f6c\u6362\u4e3a\u683c\u5f0f\u4e3a\"YYYY-MM-DD HH:MM:SS\"\u7684\u65e5\u671f\u548c\u65f6\u95f4\u5b57\u7b26\u4e32 $ awk 'BEGIN { timestamp = systime()-3600; str = strftime(\"%Y-%m-%d %H:%M:%S\", timestamp); print str }' 2023 -05-15 21 :01:43","title":"5.10.12.1.\u5185\u7f6e\u51fd\u6570"},{"location":"linux/SRE/05-RegExpress/#510122","text":"\u4e3e\u4f8b\uff1a $ cat > func.awk << EOF function max(x,y){ x>y?var=x:var=y return var } BEGIN{print max(a,b)} EOF $ awk -v a = 30 -v b = 20 -f func.awk 30 \u4e3e\u4f8b\uff1a \u5728\u4e0b\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u5b9a\u4e49\u4e86\u4e00\u4e2a\u540d\u4e3a square() \u7684\u81ea\u5b9a\u4e49\u51fd\u6570\uff0c\u5b83\u63a5\u53d7\u4e00\u4e2a\u53c2\u6570 x \uff0c\u5e76\u8fd4\u56de x \u7684\u5e73\u65b9\u3002\u7136\u540e\uff0c\u5728\u4e3b\u4ee3\u7801\u5757\u4e2d\uff0c\u6211\u4eec\u58f0\u660e\u4e86\u4e00\u4e2a\u53d8\u91cf num \u5e76\u8d4b\u503c\u4e3a 5 \u3002\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u8c03\u7528\u4e86\u81ea\u5b9a\u4e49\u51fd\u6570 square() \uff0c\u4f20\u9012 num \u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u5c06\u8fd4\u56de\u503c\u5b58\u50a8\u5728\u53d8\u91cf result \u4e2d\u3002\u6700\u540e\uff0c\u6211\u4eec\u6253\u5370\u51fa result \u7684\u503c\u3002 $ cat > func.awk << EOF # \u81ea\u5b9a\u4e49\u51fd\u6570\uff1a\u8ba1\u7b97\u5e73\u65b9 function square(x) { return x * x; } # \u4f7f\u7528\u81ea\u5b9a\u4e49\u51fd\u6570 { num = 5; result = square(num); print \"\u5e73\u65b9\u7ed3\u679c\uff1a\" result; } EOF $ awk -f func.awk \u5e73\u65b9\u7ed3\u679c\uff1a25 \u4e3e\u4f8b\uff1a $ cat > func.awk << EOF # \u81ea\u5b9a\u4e49\u51fd\u6570\uff1a\u8ba1\u7b97\u6570\u7ec4\u5e73\u5747\u503c function calculateAverage(arr, size) { sum = 0; for (i = 1; i <= size; i++) { sum += arr[i]; } return sum / size; } # \u4f7f\u7528\u81ea\u5b9a\u4e49\u51fd\u6570 { # \u5b9a\u4e49\u6570\u7ec4 numbers[1] = 10; numbers[2] = 20; numbers[3] = 30; numbers[4] = 40; numbers[5] = 50; # \u8ba1\u7b97\u6570\u7ec4\u7684\u5e73\u5747\u503c size = 5; average = calculateAverage(numbers, size); print \"\u6570\u7ec4\u7684\u5e73\u5747\u503c\uff1a\" average; } EOF $ awk -f func.awk \u6570\u7ec4\u7684\u5e73\u5747\u503c\uff1a30","title":"5.10.12.2.\u81ea\u5b9a\u4e49\u51fd\u6570"},{"location":"linux/SRE/05-RegExpress/#510123awk","text":"\u4e3e\u4f8b\uff1a # \u6ce8\u610f\u8f6c\u4e49 $ cat > passwd.awk << EOF {if(\\$3>=1000)print \\$1,\\$3} EOF $ awk -F: -f passwd.awk /etc/passwd nobody 65534 vagrant 1000 \u4e0a\u9762\u4f8b\u5b50\u4e5f\u53ef\u4ee5\u5199\u6210\u5982\u4e0b\u811a\u6b65\u683c\u5f0f\u3002 $ cat > test.awk << EOF #!/bin/awk -f # This is an awk script {if(\\$3>=1000)print \\$1,\\$3} EOF $ chmod +x test.awk $ ./test.awk -F: /etc/passwd nobody 65534 vagrant 1000 \u5411awk\u811a\u672c\u4f20\u9012\u53c2\u6570\uff1a \u683c\u5f0f\uff1a awkfile var=value var2=value2 ... inputfile \u8bf4\u660e\uff1a \u4e0a\u9762\u683c\u5f0f\u53d8\u91cf\u5728 BEGIN \u8fc7\u7a0b\u4e2d\u4e0d\u53ef\u7528\uff0c\u76f4\u5230\u9996\u884c\u8f93\u5165\u5b8c\u6210\u4ee5\u540e\uff0c\u53d8\u91cf\u624d\u53ef\u7528\u3002 \u53ef\u4ee5\u901a\u8fc7 -v \u53c2\u6570\uff0c\u8ba9 awk \u5728\u6267\u884c BEGIN \u4e4b\u524d\u5f97\u5230\u53d8\u91cf\u3002 \u547d\u4ee4\u884c\u4e2d\u6bcf\u4e00\u4e2a\u6307\u5b9a\u7684\u53d8\u91cf\u90fd\u9700\u8981\u4e00\u4e2a -v \u53c2\u6570\u3002 \u4e3e\u4f8b\uff1a # x=100\u5728BEGIN{print x}\u533a\u6bb5\u53ef\u7528 $ awk -v x = 100 'BEGIN{print x}{print x+100}' /etc/hosts 100 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 # \u4e0d\u52a0-v\u5219x=100\u5728BEGIN{print x}\u533a\u6bb5\u4e0d\u53ef\u7528 $ awk x = 100 'BEGIN{print x}{print x+100}' /etc/hosts awk: fatal: cannot open file ` BEGIN { print x }{ print x+100 } ' for reading (No such file or directory) # \u4fee\u6b63\u4e0a\u9762\u7684\u9519\u8bef\uff0c\u5c06x=100\u653e\u5728\u540e\u9762\uff0c\u56e0\u4e3a\u6ca1\u6709-v\uff0c\u6240\u4ee5x=100\u5728BEGIN{print x}\u533a\u6bb5\u4e0d\u53ef\u7528\uff0c\u7b2c\u4e00\u884c\u8f93\u51fa\u7a7a\u767d $ awk ' BEGIN { print x }{ print x+100 } ' x = 100 /etc/hosts 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200 200","title":"5.10.12.3.awk\u811a\u672c"},{"location":"linux/SRE/05-RegExpress/#511","text":"\u663e\u793a /proc/meminfo \u6587\u4ef6\u4e2d\u4ee5\u5927\u5c0fs\u5f00\u5934\u7684\u884c\uff0c\u8981\u6c42\u4f7f\u7528\u4e24\u79cd\u65b9\u6cd5\u3002 cat /proc/meminfo | grep -i \"^s\" cat /proc/meminfo | grep \"^[sS]\" \u663e\u793a /etc/passwd \u6587\u4ef6\u4e2d\u4e0d\u4ee5 /bin/bash \u7ed3\u5c3e\u7684\u884c\u3002 grep -v \"/bin/bash $ \" /etc/passwd \u663e\u793a\u7528\u6237 rpc \u9ed8\u8ba4\u7684shell\u7a0b\u5e8f\u3002 $ grep \"rpc\" /etc/passwd | cut -d \":\" -f 7 /sbin/nologin \u627e\u51fa /etc/passwd \u4e2d\u7684\u4e24\u4f4d\u6216\u4e09\u4f4d\u6570\u3002 grep -Eo \"[:digit:]{2,3}\" /etc/passwd grep -Eo \"[0-9]{2,3}\" /etc/passwd \u8fd9\u91cc\u7528\u5230\u4e86 {} \uff0c\u5c5e\u4e8e\u6269\u5c55\u6b63\u5219\u7b26\u53f7\uff0c\u6240\u4ee5\u8981\u7528 -E \u3002 \u663e\u793aRocky 9\u7684 /etc/grub2.cfg \u6587\u4ef6\u4e2d\uff0c\u81f3\u5c11\u4ee5\u4e00\u4e2a\u7a7a\u767d\u5b57\u7b26\u5f00\u5934\u7684\u4e14\u540e\u9762\u6709\u975e\u7a7a\u767d\u5b57\u7b26\u7684\u884c\u3002\uff08\u6ce8\uff1a /etc/grub2.cfg \u5728openSUSE\u548cUbuntu\u4e2d\u6ca1\u6709\uff09 # \u4e0d\u542b\u9996\u5b57\u7b26\u4e3atab $ sudo grep \"^ \" /etc/grub2.cfg # \u5305\u542b\u9996\u5b57\u7b26\u4e3atab $ sudo grep \"^[[:space:]]\" /etc/grub2.cfg \u627e\u51fa netstat -tan \u547d\u4ee4\u7ed3\u679c\u4e2d\u4ee5 LISTEN \u540e\u8ddf\u4efb\u610f\u591a\u4e2a\u7a7a\u767d\u5b57\u7b26\u7ed3\u5c3e\u7684\u884c\u3002 netstat -tan | grep -E \"LISTEN[[:space:]]+\" \u663e\u793aRocky 9\u4e0a\u6240\u6709UID\u5c0f\u4e8e1000\u4ee5\u5185\u7684\u7528\u6237\u540d\u548cUID\u3002 cat /etc/passwd | cut -d \":\" -f 1 ,3 | grep -E \"\\:[0-9]{1,3} $ \" grep -E \"\\:[0-9]{1,3}\\:[0-9]{1,}\" /etc/passwd | cut -d \":\" -f 1 ,3 \u5728Rocky 9\u4e0a\u663e\u793a\u6587\u4ef6 /etc/passwd \u7528\u6237\u540d\u548cshell\u540c\u540d\u7684\u884c\u3002 $ grep -E \"^([[:alnum:]]+\\b).*\\1 $ \" /etc/passwd sync:x:5:0:sync:/sbin:/bin/sync shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown halt:x:7:0:halt:/sbin:/sbin/halt \u5229\u7528 df \u548c grep \uff0c\u53d6\u51fa\u78c1\u76d8\u5404\u5206\u533a\u5229\u7528\u7387,\u5e76\u4ece\u5927\u5230\u5c0f\u6392\u5e8f\u3002 $ df | tr -s \" \" | cut -d \" \" -f 1 ,5 | sort -n -t \" \" -k 2 devtmpfs 0 % Filesystem Use% tmpfs 0 % tmpfs 0 % /dev/mapper/rl-home 1 % tmpfs 2 % /dev/mapper/rl-root 5 % /dev/nvme0n1p1 23 % \u663e\u793a\u4e09\u4e2a\u7528\u6237 root \uff0c sync \uff0c bin \u7684UID\u548c\u9ed8\u8ba4shell\u3002 $ grep \"^root:\\|^sync:\\|^bin:\" /etc/passwd | cut -d \":\" -f 1 ,7 root:/bin/bash bin:/usr/sbin/nologin \u4f7f\u7528 egrep \u53d6\u51fa /etc/default-1/text_2/local.3/grub \u4e2d\u5176\u57fa\u540d\u548c\u76ee\u5f55\u540d\u3002 # \u57fa\u540d $ echo \"/etc/default-1/text_2/local.3/grub\" | egrep -io \"[[:alpha:]]+ $ \" grub # \u76ee\u5f55\u540d $ echo \"/etc/default-1/text_2/local.3/grub\" | egrep -io \"/([[:alpha:]]+.|_?[[:alpha:]]|[[:alnum:]]+/){7}\" /etc/default-1/text_2/local.3/ \u7edf\u8ba1 last \u547d\u4ee4\u4e2d\u4ee5 vagrant \u767b\u5f55\u7684\u6bcf\u4e2a\u4e3b\u673aIP\u5730\u5740\u767b\u5f55\u6b21\u6570\u3002 $ last | grep vagrant | tr -s \" \" | cut -d \" \" -f 3 | grep -E \"([0-9]{1,3}\\.){1,3}[0-9]{1,3}\" | sort -n | uniq -c 24 192 .168.10.107 38 192 .168.10.109 17 192 .168.10.201 6 192 .168.10.210 2 192 .168.10.220 \u5229\u7528\u6269\u5c55\u6b63\u5219\u8868\u8fbe\u5f0f\u5206\u522b\u8868\u793a0-9\u300110-99\u3001100-199\u3001200-249\u3001250-255\u3002 [ 0 -9 ] | [ 0 -9 ]{ 2 } | 1 [ 0 -9 ]{ 2 } | 2 [ 0 -4 ][ 0 -9 ] | 25 [ 0 -5 ] \u663e\u793a ifconfig \u547d\u4ee4\u7ed3\u679c\u4e2d\u6240\u6709IPv4\u5730\u5740\u3002 $ ifconfig | grep -Eo \"([0-9]{1,3}\\.){3}[0-9]{1,3}\" | grep -v \"^255\" 192 .168.10.210 192 .168.10.255 127 .0.0.1 \u663e\u793a ip addr \u547d\u4ee4\u7ed3\u679c\u4e2d\u6240\u6709IPv4\u5730\u5740\u3002 $ ip addr show eth0 | grep inet | grep eth0 | tr -s \" \" | cut -d \" \" -f 3 | cut -d \"/\" -f 1 192 .168.10.210 $ ip addr show | grep -Eo \"([0-9]{1,3}\\.){3}[0-9]{1,3}\" | grep -v \"^255\" 127 .0.0.1 192 .168.10.210 192 .168.10.255 \u5c06\u6b64\u5b57\u7b26\u4e32Welcome to the linux world\u4e2d\u7684\u6bcf\u4e2a\u5b57\u7b26\u53bb\u91cd\u5e76\u6392\u5e8f\uff0c\u91cd\u590d\u6b21\u6570\u591a\u7684\u6392\u5230\u524d\u9762\u3002 $ echo \"Welcome to the linux world\" | grep -o [[ :alpha: ]] | sort | uniq -c | sort -nr 3 o 3 l 3 e 2 t 1 x 1 W 1 w 1 u 1 r 1 n 1 m 1 i 1 h 1 d 1 c \u5220\u9664 /etc/default/grub \u6587\u4ef6\u4e2d\u6240\u6709\u4ee5\u7a7a\u767d\u5f00\u5934\u7684\u884c\u884c\u9996\u7684\u7a7a\u767d\u5b57\u7b26\u3002 sed '/^$/d' /etc/default/grub \u5220\u9664 /etc/default/grub \u6587\u4ef6\u4e2d\u6240\u6709\u4ee5 # \u5f00\u5934\uff0c\u540e\u9762\u81f3\u5c11\u8ddf\u4e00\u4e2a\u7a7a\u767d\u5b57\u7b26\u7684\u884c\u7684\u884c\u9996\u7684 # \u548c\u7a7a\u767d\u5b57\u7b26\u3002 sed -r '/#[[:space:]]+/d;/#/d' /etc/default/grub \u4e0a\u9762\u8f93\u51fa\u7ed3\u679c\u4e2d\u5305\u542b\u7a7a\u767d\u884c\u3002 \u82e5\u8f93\u51fa\u4e2d\u5220\u9664\u7a7a\u767d\u884c\uff0c\u5219\uff1a sed -r '/#[[:space:]]+/d;/#/d;/^$/d' /etc/default/grub \u5728 /etc/fstab \u6bcf\u4e00\u884c\u884c\u9996\u589e\u52a0 # \u53f7\u3002 sed -r 's/(.*)/#&/' /etc/fstab \u5728 /etc/fstab \u6587\u4ef6\u4e2d\u4e0d\u4ee5 # \u5f00\u5934\u7684\u884c\u7684\u884c\u9996\u589e\u52a0 # \u53f7\uff08\u5305\u62ec\u7a7a\u884c\uff09\u3002 sed -r 's/^[^#].*/#&/' -r 's/^$/#/' /etc/default/grub \u901a\u8fc7\u547d\u4ee4 rpm -qa --last |awk -F ' ' '{print $1}' \u5f97\u5230\u6700\u65b0\u5b89\u88c5\u7684\u5305\u5217\u8868\u3002\u7edf\u8ba1\u6240\u6709 x86_64 \u7ed3\u5c3e\u7684\u5b89\u88c5\u5305\u540d\u4ee5 . \u5206\u9694\u5012\u6570\u7b2c\u4e8c\u4e2a\u5b57\u6bb5\u7684\u91cd\u590d\u6b21\u6570\u3002 $ rpm -qa --last | awk -F ' ' '{print $1}' | sed -nr '/x86_64$/s@.*\\.(.*)\\.x86_64@\\1@p' | sort -r | uniq -c 75 el9_0 563 el9 3 7 1 5 2 4 2 3 10 2 29 1 \u5728openSUSE\u4e2d\u7edf\u8ba1 /etc/rc.status \u6587\u4ef6\u4e2d\u6bcf\u4e2a\u5355\u8bcd\u7684\u51fa\u73b0\u6b21\u6570\uff0c\u5e76\u6392\u5e8f\uff08\u7528grep\u548csed\u4e24\u79cd\u65b9\u6cd5\u5206\u522b\u5b9e\u73b0\uff09\u3002 grep -Eo \"[a-zA-Z]+\" /etc/rc.status | sort | uniq -c cat /etc/rc.status | sed -r 's/[^[:alpha:]]+/\\n/g' | sed '/^$/d' | sort | uniq -c | sort -nr \u5c06\u6587\u672c\u6587\u4ef6\u7684n\u548cn+1\u884c\u5408\u5e76\u4e3a\u4e00\u884c\uff0cn\u4e3a\u5947\u6570\u884c\u3002 $ cat < sed.txt 1aa 2bb 3cc 4dd 5ee 6ff 7gg EOF $ sed -n 'N;s/\\n//p' sed.txt 1aa2bb 3cc4dd 5ee6ff $ sed 'N;s/\\n//' sed.txt 1aa2bb 3cc4dd 5ee6ff 7gg \u5bf9\u4e00\u4e32\u6570\u5b57\u8fdb\u884c\u6c42\u548c\u3002 $ cat < number.txt 1 2 3 4 5 6 EOF $ tr ' ' + < number.txt | bc 21 $ sum = 0 ; for i in ` cat number.txt ` ; do let sum += i ; done ; echo $sum 21 $ awk '{sum=0;for(i=1;i<=NF;i++){sum+=i};print sum}' number.txt 21 \u53d6\u51fa\u5b57\u7b26\u4e32\u4e2d\u7684\u6570\u5b57\u3002 $ echo 'kdajl;3k8jd33la5kj23f90ld02sakjflakjdslf' | awk -F \"\" ' { for(i=1;i<=NF;i++) { if($i ~ /[0-9]/) { str=(str $i) } }; print str }' 38335239002 host.log \u6587\u4ef6\u5185\u5bb9\u5982\u4e0b\uff0c\u63d0\u53d6 .edu.cn \u524d\u9762\u7684\u4e3b\u673a\u540d\uff0c\u5e76\u56de\u5199\u5230\u8be5\u6587\u4ef6\u4e2d\u3002 $ cat > host.log << EOF 1 www.edu.cn 2 blog.edu.cn 3 learning.edu.cn 4 java.edu.cn 5 nodejs.edu.cn 6 k8s.eud.cn 7 linux.edu.cn 8 python.edu.cn 9 learning.edu.cn 10 java.edu.cn 11 nodejs.edu.cn 12 www.edu.cn EOF # \u5bf9\u6bd4 $ awk -F '[ .]' '{print $1}' host.log 1 2 3 4 5 6 7 8 9 10 11 12 $ awk -F '[ .]' '{print $2}' host.log www blog learning java nodejs k8s linux python learning java nodejs www # \u4ee5\u7a7a\u683c\u6216\u8005.\u4e3a\u5206\u9694\u7b26\uff0c\u6253\u5370\u7b2c\u4e8c\u5217\uff08\u4e3b\u673a\u540d\uff09\uff0c\u8ffd\u52a0\u5199\u5165\u539f\u6587\u4ef6 $ awk -F '[ .]' '{print $2}' host.log >> host.log $ cat host.log 1 www.edu.cn 2 blog.edu.cn 3 learning.edu.cn 4 java.edu.cn 5 nodejs.edu.cn 6 k8s.eud.cn 7 linux.edu.cn 8 python.edu.cn 9 learning.edu.cn 10 java.edu.cn 11 nodejs.edu.cn 12 www.edu.cn www blog learning java nodejs k8s linux python learning java nodejs www \u7edf\u8ba1\u6587\u4ef6 /etc/fstab \u4e2d\u6bcf\u4e2a\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\u51fa\u73b0\u7684\u6b21\u6570\u3002 # \u4ee5UUID\u5f00\u5934\uff0c\u4e00\u4e2a\u6216\u591a\u4e2a\u7a7a\u683c\u4e3a\u5206\u9694\u7b26\uff0c\u8bfb\u53d6\u7b2c\u4e09\u5217\uff08\u5373\u6587\u4ef6\u7cfb\u7edf\u7c7b\u578b\uff09\u5e76\u8ba1\u6570\u3002 $ awk -F ' +' '/^UUID/{fs[$3]++}END{for(i in fs){print i, fs[i]}}' /etc/fstab swap 1 btrfs 10 vfat 1 # \u65b9\u6cd52 $ awk -F ' +' '/^UUID/{print $3}' /etc/fstab | uniq -c 10 btrfs 1 swap 1 vfat \u7edf\u8ba1\u6587\u4ef6 /etc/fstab \u4e2d\u6bcf\u4e2a\u5355\u8bcd\u51fa\u73b0\u7684\u6b21\u6570\u3002 $ awk -F \"[^[:alpha:]]\" '{for(i=1;i<=NF;i++)word[$i]++}END{for(a in word)if(a!=\"\")print a,word[a]}' /etc/fstab swap 2 B 1 srv 2 btrfs 10 snapshots 2 vfat 1 opt 2 cbaef 10 UUID 12 E 1 ecf 1 CD 1 cf 1 arm 2 a 11 c 2 tmp 2 usr 2 var 2 afa 20 home 2 d 10 utf 1 e 2 efi 3 grub 2 boot 3 subvol 9 root 2 local 2 defaults 2 f 10 \u63d0\u53d6\u5b57\u7b26\u4e32 Yd$@C#M05MD9&8923+Vip3wZ!33*44&55 \u4e2d\u6240\u6709\u7684\u6570\u5b57\u3002 # \u5bf9\u6bd4\u5355\u5f15\u53f7\u548c\u53cc\u5f15\u53f7\u7684\u533a\u522b\u3002 $ echo \"Yd $@ C#M05MD9&8923+Vip3wZ!33*44&55\" echo \"Yd $@ C#M05MD9&8923+Vip3wZcgcreate -g cpu:mygroup44&55\" YdC#M05MD9 & 8923 +Vip3wZcgcreate -g cpu:mygroup44 & 55 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' Yd $@ C#M05MD9 & 8923 +Vip3wZ!33*44 & 55 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk '{gsub(/[^0-9]/,\"\");print $0}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '[^0-9]' '{for(i=1;i<=NF;i++){printf \"%s\", $i}}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F \"\" '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' 05989233334455 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' # \u6ce8\u610f\uff0c\u5982\u679c\u5199\u6210\u5982\u4e0b\u683c\u5f0f\uff0c\u5219\u62a5\u9519\u3002 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F '' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' # \u6ce8\u610f\uff0c\u5982\u679c\u5199\u6210\u5982\u4e0b\u683c\u5f0f\uff0c\u5219\u8f93\u51fa\u539f\u5b57\u7b26\u4e32\u3002 $ echo 'Yd$@C#M05MD9&8923+Vip3wZ!33*44&55' | awk -F ' ' '{for(i=1;i<=NF;i++){if($i ~ /[[:digit:]]/){str=$i;str1=(str1 str)}};print str1}' \u751f\u6210500\u4e2a\u968f\u673a\u6570\uff0c\u4fdd\u5b58\u5230\u6587\u4ef6random.txt\u4e2d\uff0c\u683c\u5f0f\u4e3a 100,20,61,98... \uff0c\u53d6\u51fa\u5176\u4e2d\u6700\u5927\u6574\u6570\u548c\u6700\u5c0f\u6574\u6570\u3002 $ str = \"\" ; for (( i = 1 ; i< = 500 ; i++ )) ; do if [ $i -ne 500 ] ; then str += \" $RANDOM ,\" ; else str += \" $RANDOM \" ; fi ; done ; echo \" $str \" > random.txt $ cat random.txt 11308 ,8764,2075,9411,...... $ awk -F, '{max=$1;min=$1;for(i=1;i<=NF;i++){if($i>max){max=$i}else{if($i200){system(\"iptables -A INPUT -s \" i \" -j REJECT;\")}}}' \u5c06\u4e0b\u9762\u5185\u5bb9\u4e2dFQDN\u53d6\u51fa\uff0c\u5e76\u6839\u636e\u5176\u8fdb\u884c\u8ba1\u6570\uff0c\u4ece\u9ad8\u5230\u4f4e\u6392\u5e8f\u3002 $ cat > fqdn.txt << EOF http://mail.edu.com/index.html http://www.edu.com/test.html http://study.edu.com/index.html http://blog.edu.com/index.html http://www.edu.com/images/logo.jpg http://blog.edu.com/20080102.html EOF $ awk -F \"/\" '{url[$3]++}END{for(i in url){print url[i], i}}' fqdn.txt | sort -nr 2 www.edu.com 2 blog.edu.com 1 study.edu.com 1 mail.edu.com \u5c06\u4ee5\u4e0b\u2f42\u672c\u4ee5inode\u4e3a\u6807\u8bb0\uff0c\u5bf9inode\u76f8\u540c\u7684counts\u8fdb\u2f8f\u7d2f\u52a0\uff0c\u5e76\u4e14\u7edf\u8ba1\u51fa\u540c\u4e00inode\u4e2d\uff0cbeginnumber\u7684\u6700\u5c0f\u503c\u548cendnumber\u7684\u6700\u5927\u503c\u3002 inode | beginnumber | endnumber | counts | 106 | 3363120000 | 3363129999 | 10000 | 106 | 3368560000 | 3368579999 | 20000 | 310 | 3337000000 | 3337000100 | 101 | 310 | 3342950000 | 3342959999 | 10000 | 310 | 3362120960 | 3362120961 | 2 | 311 | 3313460102 | 3313469999 | 9898 | 311 | 3313470000 | 3313499999 | 30000 | 311 | 3362120962 | 3362120963 | 2 | \u8f93\u51fa\u7684\u7ed3\u679c\u683c\u5f0f\u4e3a\uff1a 310 | 3337000000 | 3362120961 | 10103 | 311 | 3313460102 | 3362120963 | 39900 | 106 | 3363120000 | 3368579999 | 30000 | $ cat > inode.text << EOF inode|beginnumber|endnumber|counts| 106|3363120000|3363129999|10000| 106|3368560000|3368579999|20000| 310|3337000000|3337000100|101| 310|3342950000|3342959999|10000| 310|3362120960|3362120961|2| 311|3313460102|3313469999|9898| 311|3313470000|3313499999|30000| 311|3362120962|3362120963|2| EOF $ awk -F '|' -v OFS = '|' '/^[0-9]/{inode[$1]++; if(!bn[$1]){bn[$1]=$2}else if(bn[$1]>$2) {bn[$1]=$2}; if(en[$1]<$3)en[$1]=$3;cnt[$1]+=$(NF-1)} END{for(i in inode)print i,bn[i],en[i],cnt[i]}' inode.text 106 | 3363120000 | 3368579999 | 30000 310 | 3337000000 | 3362120961 | 10103 311 | 3313460102 | 3362120963 | 39900","title":"5.11.\u5c0f\u7ec3\u4e60"},{"location":"linux/SRE/06-FileLookup/","text":"\u7b2c\u516d\u7ae0 \u6587\u4ef6\u67e5\u627e \u00b6 \u5e38\u7528\u6587\u4ef6\u67e5\u627e\u547d\u4ee4\uff1a locate\u547d\u4ee4 \u00b6 locate \u662f\u4e00\u4e2a\u5728 Linux \u7cfb\u7edf\u4e0a\u7528\u4e8e\u5feb\u901f\u641c\u7d22\u6587\u4ef6\u548c\u76ee\u5f55\u7684\u547d\u4ee4\u3002\u5b83\u4f7f\u7528\u9884\u5148\u6784\u5efa\u7684\u6587\u4ef6\u6570\u636e\u5e93 /var/lib/mlocate/mlocate.db \u8fdb\u884c\u641c\u7d22\uff0c\u56e0\u6b64\u6bd4\u76f4\u63a5\u5728\u6587\u4ef6\u7cfb\u7edf\u4e0a\u641c\u7d22\u8981\u5feb\u5f97\u591a\u3002 \u4f7f\u7528 updatedb \u547d\u4ee4\u624b\u52a8\u66f4\u65b0\u6587\u4ef6\u6570\u636e\u5e93 /var/lib/mlocate/mlocate.db \uff0c\u7d22\u5f15\u6784\u5efa\u8fc7\u7a0b\u9700\u8981\u904d\u5386\u6574\u4e2a\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u5f88\u6d88\u8017\u8d44\u6e90\u3002 \u6ce8\u610f\uff0c\u7531\u4e8e locate \u4f7f\u7528\u9884\u5148\u6784\u5efa\u7684\u6587\u4ef6\u6570\u636e\u5e93\uff0c\u56e0\u6b64\u5728\u66f4\u65b0\u6587\u4ef6\u6570\u636e\u5e93\u4e4b\u524d\uff0c\u65b0\u521b\u5efa\u6216\u79fb\u52a8\u7684\u6587\u4ef6\u53ef\u80fd\u4e0d\u4f1a\u7acb\u5373\u51fa\u73b0\u5728\u641c\u7d22\u7ed3\u679c\u4e2d\u3002 \u5728openSUSE 15\u4e2d\u9ed8\u8ba4\u6ca1\u6709\u5b89\u88c5\uff0c\u9700\u8981\u624b\u52a8\u5b89\u88c5\u4e0b\u9762\u7684\u8f6f\u4ef6\u5305\u3002 sudo zypper ref sudo zypper in mlocate sudo updatedb locate \u547d\u4ee4\u7684\u7279\u70b9\uff1a \u67e5\u627e\u901f\u5ea6\u5feb \u6a21\u7cca\u67e5\u627e \u975e\u5b9e\u65f6\u67e5\u627e \u641c\u7d22\u7684\u662f\u6587\u4ef6\u7684\u5168\u8def\u5f84\uff0c\u4e0d\u4ec5\u4ec5\u662f\u6587\u4ef6\u540d \u53ef\u80fd\u53ea\u641c\u7d22\u5f53\u524d\u7528\u6237\u5177\u5907\u8bfb\u53d6 r \u548c\u6267\u884c x \u6743\u9650\u7684\u76ee\u5f55 locate \u547d\u4ee4\u7684\u683c\u5f0f\uff1a locate [OPTIONS] PATTERN \u5e38\u7528\u9009\u9879\uff1a -i \uff1a\u5ffd\u7565\u5927\u5c0f\u5199\u3002 -r \uff1a\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u8fdb\u884c\u6a21\u5f0f\u5339\u914d\u3002 -l \uff1a\u4ec5\u663e\u793a\u6587\u4ef6\u8def\u5f84\uff0c\u800c\u4e0d\u663e\u793a\u6587\u4ef6\u540d\u3002 -c \uff1a\u4ec5\u663e\u793a\u5339\u914d\u7ed3\u679c\u7684\u8ba1\u6570\u3002 -b \uff1a\u53ea\u5339\u914d\u57fa\u672c\u540d\u79f0\u800c\u4e0d\u662f\u5168\u8def\u5f84\u540d\u3002 -n N \uff1a\u53ea\u5217\u4e3e\u524dN\u4e2a\u5339\u914d\u9879\u76ee\u3002 -q \uff1a\u5b89\u9759\u6a21\u5f0f\uff0c\u4e0d\u663e\u793a\u4efb\u4f55\u9519\u8bef\u4fe1\u606f\u3002 man locate \u83b7\u53d6\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\u548c\u9009\u9879\u8bf4\u660e\u3002 \u4e3e\u4f8b\uff1a\u641c\u7d22\u540d\u4e3a bashrc \u7684\u6587\u4ef6\uff0c\u6ce8\u610f\uff0c\u8fd9\u91cc\u662f\u641c\u7d22\u6587\u4ef6\u540d\u6216\u8def\u5f84\u540d\u4e2d\u5305\u542b bashrc \u7684\u6587\u4ef6 $ locate bashrc /etc/bash.bashrc /etc/skel/.bashrc /home/vagrant/.bashrc \u8981\u641c\u7d22\u4ee5 \"image\" \u5f00\u5934\u7684\u6587\u4ef6\uff0c\u5ffd\u7565\u5927\u5c0f\u5199\uff1a locate -i '^image' \u4e3e\u4f8b\uff1a\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u641c\u7d22\u4ee5 .conf \u4e3a\u6269\u5c55\u540d\u7684\u6587\u4ef6\uff1a locate -r '\\.conf$' find\u547d\u4ee4 \u00b6 find \u547d\u4ee4\u662f\u5b9e\u65f6\u67e5\u627e\u5de5\u5177\uff0c\u901a\u8fc7\u904d\u5386\u6307\u5b9a\u8def\u5f84\u5b8c\u6210\u6587\u4ef6\u67e5\u627e\u3002 \u7279\u70b9\uff1a \u67e5\u627e\u901f\u5ea6\u7565\u6162 \u7cbe\u786e\u67e5\u627e \u5b9e\u65f6\u67e5\u627e \u67e5\u627e\u6761\u4ef6\u4e30\u5bcc \u53ef\u80fd\u53ea\u641c\u7d22\u5f53\u524d\u7528\u6237\u5177\u5907\u8bfb\u53d6 r \u548c\u6267\u884c x \u6743\u9650\u7684\u76ee\u5f55 find \u547d\u4ee4\u7684\u683c\u5f0f\uff1a find [OPTIONS] [PATH] [CONDITIONS] [ACTIONS] [PATH]\uff1a\u6307\u5b9a\u5177\u4f53\u76ee\u6807\u8def\u5f84\uff0c\u9ed8\u8ba4\u4e3a\u5f53\u524d\u76ee\u5f55\u3002 [CONDITIONS]\uff1a\u6307\u5b9a\u67e5\u627e\u6807\u51c6\uff0c\u53ef\u4ee5\u662f\u6587\u4ef6\u540d\u3001\u6587\u4ef6\u5927\u5c0f\u3001\u6587\u4ef6\u7c7b\u578b\u3001\u6743\u9650\u7b49\uff0c\u9ed8\u8ba4\u4e3a\u627e\u51fa\u6307\u5b9a\u8def\u5f84\u4e0b\u6240\u6709\u6587\u4ef6\u3002 [ACTIONS]\uff1a\u5bf9\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u6267\u884c\u7684\u64cd\u4f5c\uff0c\u9ed8\u8ba4\u8f93\u51fa\u5230\u5c4f\u5e55\u3002 -maxdepth level \uff1a\u6700\u5927\u641c\u7d22\u76ee\u5f55\u6df1\u5ea6\uff0c\u6307\u5b9a\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u4e3a\u7b2c\u4e00\u7ea7\u3002 -mindepth level \uff1a\u6700\u5c0f\u641c\u7d22\u76ee\u5f55\u6df1\u5ea6\u3002 \u4e3e\u4f8b\uff1a\u53ea\u641c\u7d22 /etc \u76ee\u5f55\u7b2c\u4e8c\u7ea7\u3002 find /etc -maxdepth 2 -mindepth 2 find \u547d\u4ee4\u9ed8\u8ba4\u662f\u5148\u5904\u7406\u76ee\u5f55\uff0c\u518d\u5904\u7406\u76ee\u5f55\u5185\u90e8\u7684\u6587\u4ef6\u3002\u9009\u9879 -depth \u4f1a\u4fee\u6539 find \u547d\u4ee4\u5904\u7406\u4f18\u5148\u987a\u5e8f\uff0c\u5148\u5904\u7406\u76ee\u5f55\u5185\u90e8\u7684\u6587\u4ef6\uff0c\u518d\u5904\u7406\u76ee\u5f55\u3002 \u6839\u636e\u6587\u4ef6\u540d\u548cinode\u67e5\u627e\uff1a -name \"FILENAME\" \uff1a\u652f\u6301\u4f7f\u7528\u901a\u914d\u7b26\uff0c\u5982 * \uff0c \uff1f \uff0c [] \uff0c [^] \uff0c\u6ce8\u610f\uff0c\u901a\u914d\u7b26\u8981\u7528\u53cc\u5f15\u53f7\u3002 -iname \"FILENAME\" \uff1a\u4e0d\u533a\u5206\u5b57\u6bcd\u5927\u5c0f\u5199\u3002 -inum N \uff1a\u6309inode\u53f7\u67e5\u627e\u3002 -samefile NAME \uff1a\u67e5\u627e\u76f8\u540cinode\u53f7\u7684\u6587\u4ef6\u3002 -links N \uff1a\u94fe\u63a5\u6570\u4e3a N \u7684\u6587\u4ef6\u3002 -regex \"PATTERN\" \uff1a\u4ee5PATTERN\u5339\u914d\u6574\u4e2a\u6587\u4ef6\u8def\u5f84\uff0c\u800c\u975e\u6587\u4ef6\u540d\u79f0\u3002 xargs\u547d\u4ee4 \u00b6","title":"\u7b2c\u516d\u7ae0 \u6587\u4ef6\u67e5\u627e"},{"location":"linux/SRE/06-FileLookup/#_1","text":"\u5e38\u7528\u6587\u4ef6\u67e5\u627e\u547d\u4ee4\uff1a","title":"\u7b2c\u516d\u7ae0 \u6587\u4ef6\u67e5\u627e"},{"location":"linux/SRE/06-FileLookup/#locate","text":"locate \u662f\u4e00\u4e2a\u5728 Linux \u7cfb\u7edf\u4e0a\u7528\u4e8e\u5feb\u901f\u641c\u7d22\u6587\u4ef6\u548c\u76ee\u5f55\u7684\u547d\u4ee4\u3002\u5b83\u4f7f\u7528\u9884\u5148\u6784\u5efa\u7684\u6587\u4ef6\u6570\u636e\u5e93 /var/lib/mlocate/mlocate.db \u8fdb\u884c\u641c\u7d22\uff0c\u56e0\u6b64\u6bd4\u76f4\u63a5\u5728\u6587\u4ef6\u7cfb\u7edf\u4e0a\u641c\u7d22\u8981\u5feb\u5f97\u591a\u3002 \u4f7f\u7528 updatedb \u547d\u4ee4\u624b\u52a8\u66f4\u65b0\u6587\u4ef6\u6570\u636e\u5e93 /var/lib/mlocate/mlocate.db \uff0c\u7d22\u5f15\u6784\u5efa\u8fc7\u7a0b\u9700\u8981\u904d\u5386\u6574\u4e2a\u6839\u6587\u4ef6\u7cfb\u7edf\uff0c\u5f88\u6d88\u8017\u8d44\u6e90\u3002 \u6ce8\u610f\uff0c\u7531\u4e8e locate \u4f7f\u7528\u9884\u5148\u6784\u5efa\u7684\u6587\u4ef6\u6570\u636e\u5e93\uff0c\u56e0\u6b64\u5728\u66f4\u65b0\u6587\u4ef6\u6570\u636e\u5e93\u4e4b\u524d\uff0c\u65b0\u521b\u5efa\u6216\u79fb\u52a8\u7684\u6587\u4ef6\u53ef\u80fd\u4e0d\u4f1a\u7acb\u5373\u51fa\u73b0\u5728\u641c\u7d22\u7ed3\u679c\u4e2d\u3002 \u5728openSUSE 15\u4e2d\u9ed8\u8ba4\u6ca1\u6709\u5b89\u88c5\uff0c\u9700\u8981\u624b\u52a8\u5b89\u88c5\u4e0b\u9762\u7684\u8f6f\u4ef6\u5305\u3002 sudo zypper ref sudo zypper in mlocate sudo updatedb locate \u547d\u4ee4\u7684\u7279\u70b9\uff1a \u67e5\u627e\u901f\u5ea6\u5feb \u6a21\u7cca\u67e5\u627e \u975e\u5b9e\u65f6\u67e5\u627e \u641c\u7d22\u7684\u662f\u6587\u4ef6\u7684\u5168\u8def\u5f84\uff0c\u4e0d\u4ec5\u4ec5\u662f\u6587\u4ef6\u540d \u53ef\u80fd\u53ea\u641c\u7d22\u5f53\u524d\u7528\u6237\u5177\u5907\u8bfb\u53d6 r \u548c\u6267\u884c x \u6743\u9650\u7684\u76ee\u5f55 locate \u547d\u4ee4\u7684\u683c\u5f0f\uff1a locate [OPTIONS] PATTERN \u5e38\u7528\u9009\u9879\uff1a -i \uff1a\u5ffd\u7565\u5927\u5c0f\u5199\u3002 -r \uff1a\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u8fdb\u884c\u6a21\u5f0f\u5339\u914d\u3002 -l \uff1a\u4ec5\u663e\u793a\u6587\u4ef6\u8def\u5f84\uff0c\u800c\u4e0d\u663e\u793a\u6587\u4ef6\u540d\u3002 -c \uff1a\u4ec5\u663e\u793a\u5339\u914d\u7ed3\u679c\u7684\u8ba1\u6570\u3002 -b \uff1a\u53ea\u5339\u914d\u57fa\u672c\u540d\u79f0\u800c\u4e0d\u662f\u5168\u8def\u5f84\u540d\u3002 -n N \uff1a\u53ea\u5217\u4e3e\u524dN\u4e2a\u5339\u914d\u9879\u76ee\u3002 -q \uff1a\u5b89\u9759\u6a21\u5f0f\uff0c\u4e0d\u663e\u793a\u4efb\u4f55\u9519\u8bef\u4fe1\u606f\u3002 man locate \u83b7\u53d6\u66f4\u591a\u8be6\u7ec6\u4fe1\u606f\u548c\u9009\u9879\u8bf4\u660e\u3002 \u4e3e\u4f8b\uff1a\u641c\u7d22\u540d\u4e3a bashrc \u7684\u6587\u4ef6\uff0c\u6ce8\u610f\uff0c\u8fd9\u91cc\u662f\u641c\u7d22\u6587\u4ef6\u540d\u6216\u8def\u5f84\u540d\u4e2d\u5305\u542b bashrc \u7684\u6587\u4ef6 $ locate bashrc /etc/bash.bashrc /etc/skel/.bashrc /home/vagrant/.bashrc \u8981\u641c\u7d22\u4ee5 \"image\" \u5f00\u5934\u7684\u6587\u4ef6\uff0c\u5ffd\u7565\u5927\u5c0f\u5199\uff1a locate -i '^image' \u4e3e\u4f8b\uff1a\u4f7f\u7528\u6b63\u5219\u8868\u8fbe\u5f0f\u641c\u7d22\u4ee5 .conf \u4e3a\u6269\u5c55\u540d\u7684\u6587\u4ef6\uff1a locate -r '\\.conf$'","title":"locate\u547d\u4ee4"},{"location":"linux/SRE/06-FileLookup/#find","text":"find \u547d\u4ee4\u662f\u5b9e\u65f6\u67e5\u627e\u5de5\u5177\uff0c\u901a\u8fc7\u904d\u5386\u6307\u5b9a\u8def\u5f84\u5b8c\u6210\u6587\u4ef6\u67e5\u627e\u3002 \u7279\u70b9\uff1a \u67e5\u627e\u901f\u5ea6\u7565\u6162 \u7cbe\u786e\u67e5\u627e \u5b9e\u65f6\u67e5\u627e \u67e5\u627e\u6761\u4ef6\u4e30\u5bcc \u53ef\u80fd\u53ea\u641c\u7d22\u5f53\u524d\u7528\u6237\u5177\u5907\u8bfb\u53d6 r \u548c\u6267\u884c x \u6743\u9650\u7684\u76ee\u5f55 find \u547d\u4ee4\u7684\u683c\u5f0f\uff1a find [OPTIONS] [PATH] [CONDITIONS] [ACTIONS] [PATH]\uff1a\u6307\u5b9a\u5177\u4f53\u76ee\u6807\u8def\u5f84\uff0c\u9ed8\u8ba4\u4e3a\u5f53\u524d\u76ee\u5f55\u3002 [CONDITIONS]\uff1a\u6307\u5b9a\u67e5\u627e\u6807\u51c6\uff0c\u53ef\u4ee5\u662f\u6587\u4ef6\u540d\u3001\u6587\u4ef6\u5927\u5c0f\u3001\u6587\u4ef6\u7c7b\u578b\u3001\u6743\u9650\u7b49\uff0c\u9ed8\u8ba4\u4e3a\u627e\u51fa\u6307\u5b9a\u8def\u5f84\u4e0b\u6240\u6709\u6587\u4ef6\u3002 [ACTIONS]\uff1a\u5bf9\u7b26\u5408\u6761\u4ef6\u7684\u6587\u4ef6\u6267\u884c\u7684\u64cd\u4f5c\uff0c\u9ed8\u8ba4\u8f93\u51fa\u5230\u5c4f\u5e55\u3002 -maxdepth level \uff1a\u6700\u5927\u641c\u7d22\u76ee\u5f55\u6df1\u5ea6\uff0c\u6307\u5b9a\u76ee\u5f55\u4e0b\u7684\u6587\u4ef6\u4e3a\u7b2c\u4e00\u7ea7\u3002 -mindepth level \uff1a\u6700\u5c0f\u641c\u7d22\u76ee\u5f55\u6df1\u5ea6\u3002 \u4e3e\u4f8b\uff1a\u53ea\u641c\u7d22 /etc \u76ee\u5f55\u7b2c\u4e8c\u7ea7\u3002 find /etc -maxdepth 2 -mindepth 2 find \u547d\u4ee4\u9ed8\u8ba4\u662f\u5148\u5904\u7406\u76ee\u5f55\uff0c\u518d\u5904\u7406\u76ee\u5f55\u5185\u90e8\u7684\u6587\u4ef6\u3002\u9009\u9879 -depth \u4f1a\u4fee\u6539 find \u547d\u4ee4\u5904\u7406\u4f18\u5148\u987a\u5e8f\uff0c\u5148\u5904\u7406\u76ee\u5f55\u5185\u90e8\u7684\u6587\u4ef6\uff0c\u518d\u5904\u7406\u76ee\u5f55\u3002 \u6839\u636e\u6587\u4ef6\u540d\u548cinode\u67e5\u627e\uff1a -name \"FILENAME\" \uff1a\u652f\u6301\u4f7f\u7528\u901a\u914d\u7b26\uff0c\u5982 * \uff0c \uff1f \uff0c [] \uff0c [^] \uff0c\u6ce8\u610f\uff0c\u901a\u914d\u7b26\u8981\u7528\u53cc\u5f15\u53f7\u3002 -iname \"FILENAME\" \uff1a\u4e0d\u533a\u5206\u5b57\u6bcd\u5927\u5c0f\u5199\u3002 -inum N \uff1a\u6309inode\u53f7\u67e5\u627e\u3002 -samefile NAME \uff1a\u67e5\u627e\u76f8\u540cinode\u53f7\u7684\u6587\u4ef6\u3002 -links N \uff1a\u94fe\u63a5\u6570\u4e3a N \u7684\u6587\u4ef6\u3002 -regex \"PATTERN\" \uff1a\u4ee5PATTERN\u5339\u914d\u6574\u4e2a\u6587\u4ef6\u8def\u5f84\uff0c\u800c\u975e\u6587\u4ef6\u540d\u79f0\u3002","title":"find\u547d\u4ee4"},{"location":"linux/SRE/06-FileLookup/#xargs","text":"","title":"xargs\u547d\u4ee4"},{"location":"linux/SRE/07-FilePacking/","text":"\u7b2c\u4e03\u7ae0 \u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305 \u00b6 \u5e38\u7528\u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305\u547d\u4ee4\uff1a compress\u548cuncompress gzip\u548cgunzip bzip2\u548cbunzip2 xz\u548cunxz zip\u548cunzip tar","title":"\u7b2c\u4e03\u7ae0 \u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305"},{"location":"linux/SRE/07-FilePacking/#_1","text":"\u5e38\u7528\u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305\u547d\u4ee4\uff1a compress\u548cuncompress gzip\u548cgunzip bzip2\u548cbunzip2 xz\u548cunxz zip\u548cunzip tar","title":"\u7b2c\u4e03\u7ae0 \u6587\u4ef6\u6253\u5305\u548c\u89e3\u5305"},{"location":"python/","text":"Content \u00b6 Memo Python\u5b66\u4e60\u7684\u7b14\u8bb0\u3002 Python\u57fa\u7840\u77e5\u8bc6\uff0c\u6765\u6e90\u4e8e\u53c2\u52a0\u7684\u5404\u79cd\u5728\u7ebf\u57fa\u7840\u8bfe\u7a0b\u6c47\u96c6\u800c\u6210\u3002 \u300a\u5229\u7528Python\u8fdb\u884c\u6570\u636e\u5206\u6790\uff08\u539f\u4e66\u7b2c2\u7248\uff09\u300b\uff08Python for Data Analysis, 2rd Edition\uff09\u5b66\u4e60\u7b14\u8bb0\uff0c\u4f5c\u8005\u7684github\u94fe\u63a5 Python For Data Analysis \u300a\u6570\u636e\u7ed3\u6784\uff08Python\u8bed\u8a00\u63cf\u8ff0\uff09\uff08\u7b2c2\u7248\uff09\u300b\uff08Fundamentals of Python: Data Structures 2 nd Edition\uff09\u5b66\u4e60\u7b14\u8bb0\u3002 \u5c0f\u7a0b\u5e8f\u6f14\u793a\uff0c\u6765\u6e90\u4e8e\u53c2\u52a0\u7684\u5404\u79cd\u5728\u7ebf\u57fa\u7840\u8bfe\u7a0b\u3002","title":"Index"},{"location":"python/#content","text":"Memo Python\u5b66\u4e60\u7684\u7b14\u8bb0\u3002 Python\u57fa\u7840\u77e5\u8bc6\uff0c\u6765\u6e90\u4e8e\u53c2\u52a0\u7684\u5404\u79cd\u5728\u7ebf\u57fa\u7840\u8bfe\u7a0b\u6c47\u96c6\u800c\u6210\u3002 \u300a\u5229\u7528Python\u8fdb\u884c\u6570\u636e\u5206\u6790\uff08\u539f\u4e66\u7b2c2\u7248\uff09\u300b\uff08Python for Data Analysis, 2rd Edition\uff09\u5b66\u4e60\u7b14\u8bb0\uff0c\u4f5c\u8005\u7684github\u94fe\u63a5 Python For Data Analysis \u300a\u6570\u636e\u7ed3\u6784\uff08Python\u8bed\u8a00\u63cf\u8ff0\uff09\uff08\u7b2c2\u7248\uff09\u300b\uff08Fundamentals of Python: Data Structures 2 nd Edition\uff09\u5b66\u4e60\u7b14\u8bb0\u3002 \u5c0f\u7a0b\u5e8f\u6f14\u793a\uff0c\u6765\u6e90\u4e8e\u53c2\u52a0\u7684\u5404\u79cd\u5728\u7ebf\u57fa\u7840\u8bfe\u7a0b\u3002","title":"Content"},{"location":"python/DataAnalysis/ch01/","text":"NumPy\u57fa\u7840 \u00b6 \u5305\u542b\u4ee5\u4e0b\u5185\u5bb9\uff1a \u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61 \u901a\u7528\u51fd\u6570 \u9762\u5411\u6570\u7ec4\u7f16\u7a0b \u4f7f\u7528\u6570\u7ec4\u8fdb\u884c\u6587\u4ef6\u8f93\u5165\u548c\u8f93\u51fa \u7ebf\u6027\u4ee3\u6570 \u4f2a\u968f\u673a\u6570\u751f\u6210 \u793a\u4f8b\uff1a\u968f\u673a\u6f2b\u6b65 \u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61ndarry \u00b6 \u522b\u540d\u7ea6\u5b9a \u00b6 import numpy as np import pandas as pd import matplotlib.pyplot as plt \u5b89\u88c5matplotlib\u4e2d\u6587\u5b57\u4f53 \u00b6 \u67e5\u770b\u5b57\u4f53\u8def\u5f84 >>> import matplotlib >>> print(matplotlib.matplotlib_fname()) /home/james/.local/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc \u4e0b\u8f7d\u4e2d\u6587\u5b57\u4f53\u3002\u7f51\u5740 https://www.fontpalace.com/font-download/SimHei/,\u5e76\u62f7\u8d1d\u5230\u4e0b\u9762\u7684\u8def\u5f84\u4e0b james@lizard:~/Downloads> cp SimHei.ttf /home/james/.local/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf/ \u67e5\u770bmatplotlib\u7684\u5b57\u4f53\u7f13\u5b58\u76ee\u5f55\u3002 >>> import matplotlib >>> print(matplotlib.get_cachedir()) /home/james/.cache/matplotlib \u5220\u9664\u8fd9\u4e2a\u76ee\u5f55 james@lizard:~> rm -rf /home/james/.cache/matplotlib \u7f16\u8f91matplotlibrc\u6587\u4ef6 /home/james/.local/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc \uff0c\u505a\u5982\u4e0b\u4fee\u6539\u3002 \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # font.family: sans-serif \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # \uff0c\u5e76\u6dfb\u52a0 SimHei \uff0c\u4fee\u6539\u540e\u4e3a font.serif: SimHei, DejaVu Serif, Bitstream Vera Serif, Computer Modern Roman, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # \uff0c\u5e76\u6dfb\u52a0 SimHei \uff0c\u4fee\u6539\u540e\u4e3a font.sans-serif: SimHei, DejaVu Sans, Bitstream Vera Sans, Computer Modern Sans Serif, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # \uff0c\u5e76\u628a True \u6539\u4e3a False \uff0c\u4fee\u6539\u540e\u4e3a axes.unicode_minus: False \u8bbe\u7f6ematplotlib\u540e\u7aef\u6e32\u67d3\u5668 \u00b6 \u5728\u4f7f\u7528matplotlib\u8f93\u51fa\u56fe\u50cf\u65f6\uff0c\u5982\u679c\u9047\u5230\u65e0\u6cd5\u663e\u793a\u56fe\u50cf\u7684\u9519\u8bef UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure\u3002 \uff0c\u53ef\u4ee5\u5c1d\u8bd5\u4e0b\u9762\u7684\u6b65\u9aa4\u89e3\u51b3\u3002 \u5b89\u88c5 python3-tk \u5305 james@lizard:~> sudo zypper in python3-tk \u6216\u8005\u901a\u8fc7 pip \u5b89\u88c5 tk \u5305 james@lizard:~> pip3 install tk Defaulting to user installation because normal site-packages is not writeable Collecting tk Downloading tk-0.1.0-py3-none-any.whl (3.9 kB) Installing collected packages: tk Successfully installed tk-0.1.0 \u4e00\u822c\u5b8c\u6210\u4e0a\u9762\u5b89\u88c5\u540e\uff0c\u7a0b\u5e8f\u5c31\u80fd\u81ea\u52a8\u663e\u793a\u56fe\u4e86\uff0c\u5982\u679c\u8fd8\u662f\u4e0d\u80fd\u663e\u793a\uff0c\u518d\u5c1d\u8bd5\u91cd\u65b0\u5b89\u88c5 matplotlib \u3002 pip3 ininstall matplotlib pip3 install matplotlib ndarray: N-\u7ef4\u6570\u7ec4\u5bf9\u8c61 \u00b6 \u4e00\u4e2andarray\u662f\u4e00\u4e2a\u901a\u7528\u7684\u591a\u7ef4\u540c\u7c7b\u6570\u636e\u5bb9\u5668\uff0c\u4e5f\u5c31\u662f\u8bf4\uff0c\u5b83\u5305\u542b\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u5747\u4e3a**\u76f8\u540c\u7c7b\u578b**\uff1b \u6bcf\u4e00\u4e2a\u6570\u7ec4\u90fd\u6709\u4e00\u4e2ashape\u5c5e\u6027\uff0c\u7528\u6765\u8868\u5f81\u6570\u7ec4\u6bcf\u4e00\u7ef4\u5ea6\u7684\u6570\u91cf\uff1b \u6bcf\u4e00\u4e2a\u6570\u7ec4\u90fd\u6709\u4e00\u4e2adtype\u5c5e\u6027\uff0c\u7528\u6765\u63cf\u8ff0\u6570\u7ec4\u7684\u6570\u636e\u7c7b\u578b\uff1b \u4e0b\u9762\u662f\u6807\u51c6\u6570\u7ec4\u7684\u751f\u6210\u51fd\u6570 array: \u5c06\u8f93\u5165\u6570\u636e\uff08\u5217\u8868\u3001\u5143\u7ec4\u3001\u6570\u7ec4\uff0c\u5176\u4ed6\u5e8f\u5217\uff09\u8f6c\u6362\u4e3andarray\uff0c\u5982\u679c\u4e0d\u663e\u5f0f\u6307\u660e\u6570\u636e\u7c7b\u578b\uff0c\u5c06\u81ea\u52a8\u63a8\u65ad\uff1b\u9ed8\u8ba4\u590d\u5236\u6240\u6709\u7684\u8f93\u5165\u6570\u636e\u3002 asarray\uff1a\u5c06\u8f93\u5165\u8f6c\u6362\u4e3andarray\uff0c\u4f46\u5982\u679c\u8f93\u5165\u5df2\u7ecf\u662fndarray\u5219\u4e0d\u518d\u590d\u5236\u3002 arange\uff1aPython\u5185\u7f6e\u51fd\u6570range\u7684\u6570\u7ec4\u7248\uff0c\u8fd4\u56de\u4e00\u4e2a\u6570\u7ec4\u3002 \u4e0b\u9762\u662f\u7528 Numpy.random() \u4e00\u4e2a\u751f\u6210\u4e00\u4e2a\u968f\u673a\u6570\u7ec4\u7684\u4f8b\u5b50\uff0c\u6ce8\u610f data01 \u7684\u7c7b\u578b\u662f'numpy.ndarray'\u3002\u53ef\u4ee5\u5728ndarray\u7c7b\u578b\u6570\u7ec4\u4e0a\u53e0\u52a0\u4e00\u4e0b\u6570\u5b66\u64cd\u4f5c\u3002 data01 = np.random.randn(2, 3) print(type(data01)) # print(data01) # [[ 0.12047302 -1.13499045 -0.39311368] # [ 1.54046881 0.01254838 -3.65090952]] print(data01 * 10) # \u7ed9data\u52a0\u4e0a\u4e00\u4e2a\u6570\u5b66\u64cd\u4f5c, \u6240\u6709\u7684\u5143\u7d20\u90fd\u540c\u65f6\u4e58\u4ee5\u4e8610 # [[ 1.20473022 -11.3499045 -3.93113676] # [ 15.40468806 0.12548383 -36.50909515]] print(data01 + data01) # \u7ed9data\u52a0\u4e0a\u4e00\u4e2a\u6570\u5b66\u64cd\u4f5c, \u6570\u7ec4\u4e2d\u7684\u5bf9\u5e94\u5143\u7d20\u8fdb\u884c\u4e86\u76f8\u52a0 # [[ 0.24094604 -2.2699809 -0.78622735] # [ 3.08093761 0.02509677 -7.30181903]] print(data01.shape) # (2, 3) print(data01.dtype) # float64 \u5f53\u8868\u8fbe\u201c\u6570\u7ec4\u201d\u3001\u201cNumPy\u6570\u7ec4\u201d\u6216\u201cndarray\u201d\u65f6\uff0c\u90fd\u8868\u793a\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1andarray\u5bf9\u8c61\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a data01 \u662f\u4e00\u4e2a\u5217\u8868\uff08list\uff09\u7c7b\u578b\uff0c\u901a\u8fc7 Numpy.array \u8f6c\u6362\u6210Numpy\u7684 ndarray \u7c7b\u578b\u3002 \u5728 np.array \u4e2d\uff0c\u9664\u975e\u663e\u5f0f\u5730\u6307\u5b9a\uff0c\u5982 np.array(data01, dtype=np.int8) \uff0c\u5426\u5219np.array\u4f1a\u81ea\u52a8\u63a8\u65ad\u751f\u6210\u6570\u7ec4\u7684\u6570\u636e\u7c7b\u578b array01.dtype \u3002 \u4f7f\u7528 astype() \u65b9\u6cd5\u663e\u5f0f\u5730\u8f6c\u6362\u6570\u7ec4\u7684\u6570\u636e\u7c7b\u578b\u3002\u4f7f\u7528 astype() \u65f6\u603b\u662f\u751f\u6210\u4e00\u4e2a*\u65b0\u7684\u6570\u7ec4*\uff0c\u5373\u4f7f\u4f60\u4f20\u5165\u7684dtype\u4e0e\u4e4b\u524d\u4e00\u6837\u3002 data02 \u662f\u4e00\u4e2a\u5d4c\u5957\u5217\u8868 [[1, 2, 3, 4], [5, 6, 7, 8]] \uff0c\u901a\u8fc7np.array()\u65b9\u6cd5\u8f6c\u6362\u6210\u591a\u7ef4\u6570\u7ec4\uff0c\u524d\u63d0\u662f\u6bcf\u4e2a\u5b50\u5217\u8868\u7684\u957f\u5ea6\u8981\u4e00\u81f4\u3002 data01 = [6, 7.5, 8, 0, 1] print(data01) # [6, 7.5, 8, 0, 1] print(type(data01)) # array01 = np.array(data01) print(\"\u77e9\u9635\u7c7b\u578b\", type(array01)) # \u77e9\u9635\u7c7b\u578b print(\"\u6837\u672c\u77e9\u9635\", array01) # \u6837\u672c\u77e9\u9635 [6. 7.5 8. 0. 1. ] print(\"\u6570\u7ec4\u7ef4\u5ea6\", array01.ndim) # \u6570\u7ec4\u7ef4\u5ea6 1 print(\"\u77e9\u9635\u5f62\u72b6\", array01.shape) # \u77e9\u9635\u5f62\u72b6 (5,) \u4e00\u884c\u4e94\u5217 print(\"\u77e9\u9635\u6570\u636e\u7c7b\u578b\", array01.dtype) # float64 data02 = [[1, 2, 3, 4], [5, 6, 7, 8]] array02 = np.array(data02) print(\"\u6837\u672c\u77e9\u9635\\n\", array02) # \u6837\u672c\u77e9\u9635 # [[1 2 3 4] # [5 6 7 8]] print(\"\u6570\u7ec4\u7ef4\u5ea6\", array02.ndim) # \u6570\u7ec4\u7ef4\u5ea6 2 print(\"\u77e9\u9635\u5f62\u72b6\", array02.shape) # \u77e9\u9635\u5f62\u72b6 (2, 4) print(\"\u77e9\u9635\u6570\u636e\u7c7b\u578b\", array02.dtype) # \u77e9\u9635\u6570\u636e\u7c7b\u578b int64 print(\"\u77e9\u96350\u8f74\u5411\u6c42\u548c\", array02.sum(axis=0)) # \u77e9\u96350\u8f74\u5411\u6c42\u548c [ 6 8 10 12] print(\"\u77e9\u96351\u8f74\u5411\u6c42\u548c\", array02.sum(axis=1)) # \u77e9\u96351\u8f74\u5411\u6c42\u548c [10 26] array03 = array02.astype(np.float64) print(array03.dtype) # float64 print(array03) # [[1. 2. 3. 4.] # [5. 6. 7. 8.]] zeros() \u65b9\u6cd5\u53ef\u4ee5\u4e00\u6b21\u6027\u521b\u9020\u51680\u6570\u7ec4\u3002 print(np.zeros(10)) # [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] ones() \u65b9\u6cd5\u53ef\u4ee5\u4e00\u6b21\u6027\u521b\u9020\u51681\u6570\u7ec4\u3002\u6ce8\u610f\uff0c\u4f20\u53c2shape\u662f\u4e00\u4e2a\u5143\u7ec4 (3, 5) \u3002 print(np.ones((3, 5))) # [[1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.]] empty() \u65b9\u6cd5\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u6ca1\u6709\u521d\u59cb\u5316\u6570\u503c\u7684\u6570\u7ec4\u3002\u4f46\u662f\uff0c\u4f7f\u7528np.empty\u6765\u751f\u6210\u4e00\u4e2a\u51680\u6570\u7ec4\uff0c\u5e76\u4e0d\u53ef\u9760\uff0c\u6709\u4e9b\u65f6\u5019\u5b83\u53ef\u80fd\u4f1a\u8fd4\u56de\u672a\u521d\u59cb\u5316\u7684\u5783\u573e\u6570\u503c print(np.empty((2, 3, 2))) # [[[2.30116964e-316 0.00000000e+000] # [2.10077583e-312 6.79038654e-313] # [2.22809558e-312 2.14321575e-312]] # # [[2.35541533e-312 6.79038654e-313] # [2.22809558e-312 2.14321575e-312] # [2.46151512e-312 2.41907520e-312]]] NumPy\u8f74 \u00b6 \u4e00\u53e5\u8bdd\u603b\u7ed3\uff1a\u5c06NumPy\u8f74\u89c6\u4e3a\u6211\u4eec\u53ef\u4ee5\u6267\u884c\u64cd\u4f5c\u7684\u65b9\u5411\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a arr_1 = np.array([[1, 1, 1], [1, 1, 1]]) arr_2 = np.array([[9, 9, 9], [9, 9, 9]]) print(arr_1) # [[1 1 1] # [1 1 1]] print(arr_2) # [[9 9 9] # [9 9 9]] \u6cbf0\u8f74\u5408\u5e76\u7684\u601d\u8def\u662f\uff0c\u4e24\u4e2a\u6570\u7ec4\u6cbf0\u8f74\u65b9\u5411\uff0c\u54110\u8f74\u201c\u584c\u7f29\u201d\uff08collapse\uff09\u3002 result = np.concatenate([arr_1, arr_2], axis=0) print(result) # [[1 1 1] # [1 1 1] # [9 9 9] # [9 9 9]] \u6cbf1\u8f74\u5408\u5e76\u7684\u601d\u8def\u662f\uff0c\u4e24\u4e2a\u6570\u7ec4\u6cbf1\u8f74\u65b9\u5411\uff0c\u54111\u8f74\u201c\u584c\u7f29\u201d result = np.concatenate([arr_1, arr_2], axis=1) print(result) # [[1 1 1 9 9 9] # [1 1 1 9 9 9]] \u6211\u4eec\u6765\u770bNumPy\u7684\u4e09\u7ef4\u6570\u7ec4\u3002 array1 = np.arange(36).reshape((3, 3, 4)) print(array1) # [[[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] # # [[12 13 14 15] # [16 17 18 19] # [20 21 22 23]] # # [[24 25 26 27] # [28 29 30 31] # [32 33 34 35]]] \u8fd9\u6837\u770b\u4f1a\u5bb9\u6613\u7406\u89e3\u4e00\u4e9b\uff0c0\u8f74\u67093\u884c\uff0c1\u8f74\u67093\u5217\uff0c2\u8f74\u67094\u4e2a\u5143\u7d20\uff1a [[[ 0 1 2 3], [ 4 5 6 7], [ 8 9 10 11]] [[12 13 14 15], [16 17 18 19], [20 21 22 23]] [[24 25 26 27], [28 29 30 31], [32 33 34 35]]] \u8f93\u51fa\uff1a\u8f740\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f741\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f742\u7d22\u5f15\u53f7\uff1a\u5168\u90e8 print(array1[0, 0, :]) # [0 1 2 3] \u8f93\u51fa\uff1a\u8f740\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f741\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f742\u7d22\u5f15\u53f7\uff1a1 print(array1[0, 0, 1]) # 1 NumPy\u6570\u7ec4\u7b97\u672f \u00b6 \u4e00\u4e2a**\u6807\u91cf**\u5c31\u662f\u4e00\u4e2a\u5355\u72ec\u7684\u6570\u3002\u4e00\u4e2a\u5411\u91cf\u5c31\u662f\u4e00\u5217\u6570\uff0c\u8fd9\u4e9b\u6570\u662f\u6709\u5e8f\u6392\u5217\u7684\u3002 \u77e9\u9635\u662f\u4e8c\u7ef4\u6570\u7ec4\uff0c\u5176\u4e2d\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u88ab\u4e24\u4e2a\u7d22\u5f15\u800c\u975e\u4e00\u4e2a\u6240\u786e\u5b9a\u3002 \u51e0\u4f55\u4ee3\u6570\u4e2d\u5b9a\u4e49\u7684**\u5f20\u91cf**\u662f\u57fa\u4e8e\u5411\u91cf\u548c\u77e9\u9635\u7684\u63a8\u5e7f\uff0c\u6211\u4eec\u53ef\u4ee5**\u5c06\u6807\u91cf\u89c6\u4e3a\u96f6\u9636\u5f20\u91cf**\uff0c \u77e2\u91cf**\u89c6\u4e3a\u4e00\u9636\u5f20\u91cf\uff0c\u90a3\u4e48**\u77e9\u9635\u5c31\u662f\u4e8c\u9636\u5f20\u91cf \u3002 \u5e26\u6709\u6807\u91cf\u8ba1\u7b97\u7684\u7b97\u672f\u64cd\u4f5c\uff0c\u4f1a\u628a\u8ba1\u7b97\u53c2\u6570\u4f20\u9012\u7ed9\u6570\u7ec4\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u3002 \u540c\u5c3a\u5bf8\u6570\u7ec4\u4e4b\u95f4\u7684\u6bd4\u8f83 array04 == array04 \uff0c\u4f1a\u4ea7\u751f\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4 \u4e0d\u540c\u5c3a\u5bf8\u7684\u6570\u7ec4\u95f4\u7684\u64cd\u4f5c\uff0c\u5c06\u4f1a\u7528\u5230 \u5e7f\u64ad\u7279\u6027\uff08broadcasting\uff09 \u3002 array04 = np.array([ [1, 2, 3, 4, 5], [3, 4, 5, 6, 7], [5, 6, 7, 8, 9] ], dtype=int) print(array04 + array04) # [[ 2 4 6 8 10] # [ 6 8 10 12 14] # [10 12 14 16 18]] print(array04 - array04) # [[0 0 0 0 0] # [0 0 0 0 0] # [0 0 0 0 0]] print(array04 * array04) # [[ 1 4 9 16 25] # [ 9 16 25 36 49] # [25 36 49 64 81]] print(array04 / array04) # [[1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.]] print(1 / array04) # [[1. 0.5 0.33333333 0.25 0.2 ] # [0.33333333 0.25 0.2 0.16666667 0.14285714] # [0.2 0.16666667 0.14285714 0.125 0.11111111]] print(array04 == array04) # [[ True True True True True] # [ True True True True True] # [ True True True True True]] \u57fa\u7840\u7d22\u5f15\u4e0e\u5207\u7247 \u00b6 ndarray\u5bf9\u8c61\u7684\u5185\u5bb9\u53ef\u4ee5\u901a\u8fc7\u7d22\u5f15\uff08indexing\uff09\u6216\u5207\u7247\uff08slicing\uff09\u6765\u8bbf\u95ee\u548c\u4fee\u6539\uff0cndarray\u5bf9\u8c61\u4e2d\u7684\u5143\u7d20\u7d22\u5f15\u4ece\u96f6\u5f00\u59cb\u3002 \u6709\u4e09\u79cd\u53ef\u7528\u7684\u7d22\u5f15\u65b9\u6cd5\uff1a\u5b57\u6bb5\u8bbf\u95ee\uff0c\u57fa\u672c\u5207\u7247\u548c\u9ad8\u7ea7\u7d22\u5f15\u3002 \u7d22\u5f15\uff08indexing\uff09\uff1a\u83b7\u53d6\u6570\u7ec4\u4e2d\u7279\u5b9a\u4f4d\u7f6e\u5143\u7d20\u7684\u8fc7\u7a0b\u3002 \u5207\u7247\uff08slicing\uff09\uff1a\u83b7\u53d6\u6570\u7ec4\u5143\u7d20\u5b50\u96c6\u7684\u8fc7\u7a0b\u3002\u6570\u7ec4\u7684\u5207\u7247\u662f\u539f\u6570\u7ec4\u7684\u89c6\u56fe\u3002\u8fd9\u610f\u5473\u7740\u4efb\u4f55**\u5bf9\u4e8e\u89c6\u56fe\u7684\u4fee\u6539\u90fd\u4f1a\u53cd\u6620\u5230\u539f\u6570\u7ec4\u4e0a**\u3002\u6570\u7ec4\u7684\u5207\u7247, \u8fd4\u56de\u7684\u5bf9\u8c61\u662f\u964d\u4f4e\u4e00\u4e2a\u7ef4\u5ea6\u7684\u6570\u7ec4\u3002 \u4e00\u7ef4\u6570\u7ec4\u7684\u7d22\u5f15\u548c\u5207\u7247\uff1a\u4e0ePython\u7684\u5217\u8868\u7c7b\u4f3c\uff1a a[n] \uff1a\u8fd4\u56de\u7b2c n+1 \u4e2a\u5143\u7d20\u3002\u5982\u679c n \u4e3a\u8d1f\u6570\uff0c\u5219\u8fd4\u56de\u5012\u6570\u7b2c n \u4e2a\u5143\u7d20\u3002 a[n:m:k] \uff1a\u8d77\u59cb\u7f16\u53f7 n \uff0c\u7ec8\u6b62\u7f16\u53f7 m \uff0c\u6b65\u957f k \uff0c\u7528\u5192\u53f7\u5206\u5272\u3002 \u9075\u5faa\u5de6\u95ed\u53f3\u5f00\u7684\u539f\u5219 \uff0c\u5373 [n, m) \u3002\u5982\u679c n \u4e3a\u7a7a\uff0c\u5373 n = 0 \uff1b\u5982\u679c m \u4e3a\u7a7a\uff0c\u5373 m = len(a) \u3002 \u591a\u7ef4\u6570\u7ec4\u7684\u7d22\u5f15\u548c\u5207\u7247\uff1a a[n,m,k,...] \uff1a\u6bcf\u4e2a\u7ef4\u5ea6\u4e00\u4e2a\u7d22\u5f15\u503c\uff0c\u6700\u5916\u5c42\u5217\u8868\uff08list\uff09\u4e2d\u7b2c n \u4e2a\u5143\u7d20\uff0c\u6b21\u5916\u5c42\u5217\u8868\uff08list\uff09\u4e2d\u7b2c m \u4e2a\u5143\u7d20\uff0c\u4ee5\u6b64\u7c7b\u63a8\u3002\u5982\u679c n \u4e3a\u8d1f\u6570\uff0c\u5219\u8fd4\u56de\u5012\u6570\u7b2c n \u4e2a\u5143\u7d20\u3002 a[n1:m1:k1,n2:m2:k2,n3:m3:k3,...] \uff1a\u6bcf\u4e2a\u7ef4\u5ea6\u7684\u5207\u7247\u65b9\u6cd5\u4e0e\u4e00\u7ef4\u6570\u7ec4\u76f8\u540c\u3002\u987a\u5e8f\u4e3a\u4ece\u5916\u5230\u5185\u3002 array05 = np.arange(10) print(array05) # [0 1 2 3 4 5 6 7 8 9] # \u4ece\u7d22\u5f15\u503c5\u5f00\u59cb\u5230\u7d22\u5f15\u503c7\u7684\u4e00\u4e2a\u5207\u7247\u3002 print(array05[5:8]) # [5 6 7] array06 = array05[5:8] # \u4f20\u5165\u4e00\u4e2a\u6570\u503c\u7ed9\u6570\u7ec4\u7684\u5207\u7247\uff0c\u6570\u503c\u88ab\u4f20\u9012\u7ed9\u4e86\u6574\u4e2a\u5207\u7247\u3002\u4e0d\u5199\u5207\u7247\u503c\u7684[:]\u5c06\u4f1a\u5f15\u7528\u6570\u7ec4\u7684\u6240\u6709\u503c array06[:] = 12 print(array06) # [12 12 12] # \u5207\u7247\u7684\u4fee\u6539\u4f1a\u53cd\u6620\u5230\u539f\u6570\u7ec4\u4e0a print(array05) # [ 0 1 2 3 4 12 12 12 8 9] # \u8f93\u51fa3\u7ef4\u77e9\u9635\uff0c3\u884c3\u5217\uff0c\u51719\u4e2a\u5143\u7d20\uff0c\u6bcf\u4e2a\u5143\u7d20\u662f\u4e00\u4e2a\u542b3\u4e2a\u5143\u7d20\u7684\u5217\u8868 array07 = np.array([ [[0, 1, 2], [3, 4, 5], [6, 7, 8]], [[9, 0, 1], [2, 3, 4], [5, 6, 7]], [[8, 9, 0], [1, 2, 3], [4, 5, 6]], ]) # \u8f93\u51fa3\u7ef4\u77e9\u9635\uff0c\u663e\u793a\u539f\u77e9\u9635\u7684\u7b2c1\uff0c2\u884c\u76842\uff0c3\u5217\u5143\u7d20\uff0c\u4e0d\u8981\u628a\u7d22\u5f15\u53f7\u548c\u8fd9\u91cc\u7684\u8868\u8ff0\u884c\u53f7\u6df7\u6dc6\u3002 print(array07[:2, 1:]) # [[[3 4 5] [6 7 8]] # [[2 3 4] [5 6 7]]] print(array07[:2, 1:].shape) # (2, 2, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c3\u884c print(array07[2]) # [[8 9 0] [1 2 3] [4 5 6]] print(array07[2].shape) # (3, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c3\u884c print(array07[2, :]) # [[8 9 0] [1 2 3] [4 5 6]] print(array07[2, :].shape) # (3, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c3\u884c\uff08\u53ea\u6709\u4e09\u884c\uff0c\u6240\u4ee5[2:, :]\u7b49\u540c\u4e8e[2, :]\uff09 print(array07[2:, :]) # [[[8 9 0] [1 2 3] [4 5 6]]] print(array07[2:, :].shape) # (1, 3, 3) # \u8f93\u51fa\u539f\u77e9\u9635\u76841\uff0c2\u5217 print(array07[:, :2]) # [[[0 1 2] [3 4 5]] # [[9 0 1] [2 3 4]] # [[8 9 0] [1 2 3]]] print(array07[:, :2].shape) # (3, 2, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u524d2\u4e2a\u5143\u7d20 print(array07[1, :2]) # [[9 0 1] [2 3 4]] print(array07[1, :2].shape) # (2, 3) # \u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u524d2\u4e2a\u5143\u7d20 print(array07[1:2, :2]) # [[[9 0 1] [2 3 4]]] print(array07[1:2, :2].shape) # (1, 2, 3) # \u5c06\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u8d4b\u503c\u7ed9\u53d8\u91cf old_value = array07[2].copy() print(old_value) # [[8 9 0] [1 2 3] [4 5 6]] # \u4fee\u6539\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u7684\u503c\uff0c\u6807\u91cf\u548c\u6570\u7ec4\u90fd\u53ef\u4ee5\u4f20\u9012\u7ed9 array07[2] array07[2] = 25 print(array07) # [[[ 0 1 2] [ 3 4 5] [ 6 7 8]] # [[ 9 0 1] [ 2 3 4] [ 5 6 7]] # [[25 25 25] [25 25 25] [25 25 25]]] # \u5c06\u53d8\u91cf\u503c\u8d4b\u503c\u7ed9\u539f\u77e9\u9635\u7684\u7b2c2\u884c array07[2] = old_value print(array07) # [[[0 1 2] [3 4 5] [6 7 8]] # [[9 0 1] [2 3 4] [5 6 7]] # [[8 9 0] [1 2 3] [4 5 6]]] \u5e03\u5c14\u7d22\u5f15 \u00b6 \u5e03\u5c14\u503c\u7d22\u5f15\uff08Boolean indexing\uff09\u662f\u901a\u8fc7\u4e00\u4e2a\u5e03\u5c14\u6570\u7ec4\u6765\u7d22\u5f15\u76ee\u6807\u6570\u7ec4\uff0c\u4ee5\u6b64\u627e\u51fa\u4e0e\u5e03\u5c14\u6570\u7ec4\u4e2d\u503c\u4e3aTrue\u7684\u5bf9\u5e94\u7684\u76ee\u6807\u6570\u7ec4\u4e2d\u7684\u6570\u636e\u3002\u5e03\u5c14\u6570\u7ec4\u7684\u957f\u5ea6\u5fc5\u987b\u4e0e\u76ee\u6807\u6570\u7ec4\u5bf9\u5e94\u7684\u8f74\u7684\u957f\u5ea6\u4e00\u81f4\u3002 \u4f7f\u7528\u5e03\u5c14\u503c\u7d22\u5f15\uff08Boolean indexing\uff09\u9009\u62e9\u6570\u636e\u65f6\uff0c\u603b\u662f\u751f\u6210\u6570\u636e\u7684\u62f7\u8d1d\uff0c\u5373\u4f7f\u8fd4\u56de\u7684\u6570\u7ec4\u5e76\u6ca1\u6709\u4efb\u4f55\u53d8\u5316\u3002 \u5047\u8bbe\u6211\u4eec\u7684\u6570\u636e\u90fd\u5728\u6570\u7ec4\u4e2d\uff0c\u5e76\u4e14\u6570\u7ec4\u4e2d\u7684\u6570\u636e\u662f\u4e00\u4e9b\u5b58\u5728\u91cd\u590d\u7684\u4eba\u540d\u3002\u7528randn\u51fd\u6570\u751f\u6210\u4e00\u4e9b\u6807\u51c6\u6b63\u6001(standard normal)\u5206\u5e03\u7684\u6570\u636e\u3002\u5047\u8bbe\u6bcf\u4e2a\u4eba\u540d\u90fd\u548cdata\u6570\u7ec4\u4e2d\u7684\u4e00\u884c\u76f8\u5bf9\u5e94\uff0c\u5e76\u4e14\u6211\u4eec\u60f3\u8981\u9009\u4e2d\u6240\u6709\u2019Bob\u2019\u5bf9\u5e94\u7684\u884c\u3002 names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype=' # \u56fe\u50cf\u6807\u9898 plt.title(\"$\\sqrt{x^2 + y^2}$ \u8ba1\u7b97\u503c\u7684\u7f51\u683c\u56fe\") # \u8f93\u51fa\u56fe\u50cf plt.show() \u8f93\u51fa\u56fe\u50cf\u4e3a\uff1a \u901a\u8fc7\u6761\u4ef6\u903b\u8f91\u64cd\u4f5c\u6570\u7ec4 \u00b6 numpy.where \u51fd\u6570\u662f\u4e09\u5143\u8868\u8fbe\u5f0f x if condition else y \u7684\u5411\u91cf\u5316\u7248\u672c\u3002 np.where \u7684\u7b2c\u4e8c\u4e2a\u548c\u7b2c\u4e09\u4e2a\u53c2\u6570\u5e76\u4e0d\u9700\u8981\u662f\u6570\u7ec4\uff0c\u5b83\u4eec\u53ef\u4ee5\u662f\u6807\u91cf\u3002 np.where \u5728\u6570\u636e\u5206\u6790\u4e2d\u7684\u4e00\u4e2a\u5178\u578b\u7528\u6cd5\u662f\u6839\u636e\u4e00\u4e2a\u6570\u7ec4\u6765\u751f\u6210\u4e00\u4e2a\u65b0\u7684\u6570\u7ec4\u3002 \u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4\u548c\u4e24\u4e2a\u6570\u503c\u6570\u7ec4\u3002\u5047\u8bbe cond \u4e2d\u7684\u5143\u7d20\u4e3a True \u65f6\uff0c\u6211\u4eec\u53d6 xarr \u4e2d\u7684\u5bf9\u5e94\u5143\u7d20\u503c\uff0c\u5426\u5219\u53d6 yarr \u4e2d\u7684\u5143\u7d20\u3002 xarray = np.array([1.1, 1.2, 1.3, 1.4, 1.5]) yarray = np.array([2.1, 2.2, 2.3, 2.4, 2.5]) cond = np.array([True, False, True, True, False]) \u901a\u8fc7\u5217\u8868\u63a8\u5bfc\u5f0f\u6765\u5b9e\u73b0\u4e0a\u8ff0\u9700\u6c42\u3002 \u7f3a\u70b9: \u9996\u5148\uff0c\u5982\u679c\u6570\u7ec4\u5f88\u5927\u7684\u8bdd\uff0c\u901f\u5ea6\u4f1a\u5f88\u6162\uff08\u56e0\u4e3a\u6240\u6709\u7684\u5de5\u4f5c\u90fd\u662f\u901a\u8fc7\u89e3\u91ca\u5668\u6765\u89e3\u91caPython\u4ee3\u7801\u5b8c\u6210\uff09\u3002 \u5176\u6b21\uff0c\u5f53\u6570\u7ec4\u662f\u591a\u7ef4\u65f6\uff0c\u5c31\u65e0\u6cd5\u51d1\u6548\u4e86\u3002 # \u901a\u8fc7\u5217\u8868\u63a8\u5bfc\u5f0f\u6765\u5b9e\u73b0 result = [(x if c else y) for x, y, c in zip(xarray, yarray, cond)] print(result) # [1.1, 2.2, 1.3, 1.4, 2.5] \u901a\u8fc7 np.where \u6765\u5b9e\u73b0\u4e0a\u8ff0\u9700\u6c42\u3002 result = np.where(cond, xarray, yarray) print(result) # [1.1 2.2 1.3 1.4 2.5] \u5047\u8bbe\u6709\u4e00\u4e2a\u968f\u673a\u751f\u6210\u7684\u77e9\u9635\u6570\u636e\uff0c\u4e0b\u9762\u4f7f\u7528np.where\u5b9e\u73b0\u66ff\u6362\u3002 array = np.random.randn(4, 4) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) print(\"\u77e9\u9635\u5143\u7d20\u662f\u5426\u5927\u4e8e0 \\n\", array > 0) # \u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2\uff0c\u5c06\u6240\u6709\u7684\u8d1f\u503c\u66ff\u6362\u4e3a-2 result03 = np.where(array > 0, 2, -2) print(\"\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2\uff0c\u5c06\u6240\u6709\u7684\u8d1f\u503c\u66ff\u6362\u4e3a-2 \\n\", result03) # \u4ec5\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2 result04 = np.where(array > 0, 2, array) print(\"\u4ec5\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2 \\n\", result04) # \u6837\u672c\u77e9\u9635 # [[-0.57177422 -0.34917512 2.20268075 1.99959296] # [ 0.67966599 2.67915099 -0.40528454 -0.80339907] # [-0.74406888 2.33802717 -0.74582936 0.59347128] # [ 0.68624473 0.65953112 -0.40871415 -0.68698878]] # \u77e9\u9635\u5143\u7d20\u662f\u5426\u5927\u4e8e0 # [[False False True True] # [ True True False False] # [False True False True] # [ True True False False]] # \u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2\uff0c\u5c06\u6240\u6709\u7684\u8d1f\u503c\u66ff\u6362\u4e3a-2 # [[-2 -2 2 2] # [ 2 2 -2 -2] # [-2 2 -2 2] # [ 2 2 -2 -2]] # \u4ec5\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2 # [[-0.57177422 -0.34917512 2. 2. ] # [ 2. 2. -0.40528454 -0.80339907] # [-0.74406888 2. -0.74582936 2. ] # [ 2. 2. -0.40871415 -0.68698878]] \u6570\u5b66\u548c\u7edf\u8ba1\u65b9\u6cd5 \u00b6 NumPy\u6709\u4e00\u4e9b\u4e13\u95e8\u7684\u6570\u5b66\u51fd\u6570\uff0c\u7528\u6765\u8ba1\u7b97\u6574\u4e2a\u6570\u7ec4\u7edf\u8ba1\u503c\u6216\u8f74\u5411\u6570\u636e\u7684\u8ba1\u7b97\u3002\u4f8b\u5982\uff0c\u805a\u5408\u51fd\u6570\uff08\u901a\u5e38\u4e5f\u53eb\u7f29\u51cf\u51fd\u6570\uff09\uff0c\u5982sum\u3001mean\u548cstd\uff08\u6807\u51c6\u5dee\uff09\u3002 \u65e2\u53ef\u4ee5\u76f4\u63a5\u8c03\u7528\u6570\u7ec4\u5b9e\u4f8b\u7684\u65b9\u6cd5\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u9876\u5c42\u7684NumPy\u51fd\u6570\u3002 \u4e3e\u4f8b\uff1a\u751f\u6210\u4e00\u4e9b\u6b63\u6001\u5206\u5e03\u7684\u968f\u673a\u6570\uff0c\u8ba1\u7b97\u90e8\u5206\u805a\u5408\u7edf\u8ba1\u6570\u636e\u3002 \u8fd9\u91cc\u518d\u5bf9\u8f74\u5411\u505a\u4e2a\u89e3\u91ca\uff0c np.random.randn(5, 4) \u4ea7\u751f\u7684\u4e8c\u7ef4\u6570\u7ec4\u662f\uff1a0\u8f74\u54115\u4e2a\u5143\u7d20, 1\u8f74\u54114\u4e2a\u5143\u7d20\u3002 # \u751f\u62102\u8f74\u6570\u7ec4 array = np.random.randn(5, 4) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) print(\"\u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c\", array.mean()) print(\"\u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c\", np.mean(array)) print(\"\u77e9\u9635\u5143\u7d20\u548c\", array.sum()) print(\"\u77e9\u9635\u5143\u7d20\u548c\", np.sum(array)) print(\"0\u8f74\u5411\u7684\u7d2f\u548c\", array.sum(axis=0)) print(\"1\u8f74\u5411\u7684\u7d2f\u548c\", array.sum(axis=1)) print(\"1\u8f74\u5411\u7684\u5e73\u5747\u503c\", array.mean(axis=1)) # \u6837\u672c\u77e9\u9635 shape=(5, 4) 0\u8f74\u54115\u4e2a\u5143\u7d20, 1\u8f74\u54114\u4e2a\u5143\u7d20 # [[ 0.32532911 -0.00177984 -1.59432632 1.58375133] # [ 1.48921763 0.25202456 0.44076148 -1.02277289] # [-0.73490219 0.19197171 -0.22374362 0.52610852] # [-1.03531076 1.0595528 -0.11566501 0.34063544] # [-0.2122241 -0.81348187 1.70989712 -0.00732696]] # \u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c 0.10788580775057008 # \u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c 0.10788580775057008 # \u77e9\u9635\u5143\u7d20\u548c 2.1577161550114017 # \u77e9\u9635\u5143\u7d20\u548c 2.1577161550114017 # 0\u8f74\u5411\u7684\u7d2f\u548c [-0.16789031 0.68828737 0.21692365 1.42039545] # 1\u8f74\u5411\u7684\u7d2f\u548c [ 0.31297429 1.15923078 -0.24056558 0.24921247 0.67686419] # 1\u8f74\u5411\u7684\u5e73\u5747\u503c [ 0.07824357 0.28980769 -0.06014139 0.06230312 0.16921605] \u4e0b\u9762\u5217\u4e3e\u4e86\u5e38\u7528\u7684\u57fa\u7840\u6570\u7ec4\u7edf\u8ba1\u65b9\u6cd5\u3002 array = np.array([ [1, 2, 3, 4, 5], [3, 4, 5, 6, 7], [5, 6, 7, 8, 9] ], dtype=int) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) print(\"\u8f74\u5411\u6c42\u548c\", array.sum()) print(\"\u8f74\u5411\u6c42\u548c\", array.sum(axis=0)) print(\"\u6570\u5b66\u5e73\u5747\", array.mean()) print(\"\u8f74\u5411\u6570\u5b66\u5e73\u5747\", array.mean(axis=0)) print(\"\u6807\u51c6\u5dee\", array.std(), \"\u65b9\u5dee\", array.var()) print(\"\u8f74\u5411\u6807\u51c6\u5dee\", array.std(axis=0), \"\u8f74\u5411\u65b9\u5dee\", array.var(axis=0)) print(\"\u6700\u5c0f\u503c\", array.min(), \"\u6700\u5927\u503c\", array.max()) print(\"\u8f74\u5411\u6700\u5c0f\u503c\", array.min(axis=0), \"\u8f74\u5411\u6700\u5927\u503c\", array.max(axis=0)) print(\"\u6700\u5c0f\u503c\u4f4d\u7f6e\", array.argmin(), \"\u6700\u5927\u503c\u4f4d\u7f6e\", array.argmax()) print(\"\u8f74\u5411\u6700\u5c0f\u503c\u4f4d\u7f6e\", array.argmin(axis=0), \"\u8f74\u5411\u6700\u5927\u503c\u4f4d\u7f6e\", array.argmax(axis=0)) print(\"\u7d2f\u79ef\u548c \\n\", array.cumsum()) print(\"\u8f74\u5411\u7d2f\u79ef\u548c \\n\", array.cumsum(axis=1)) print(\"\u7d2f\u79ef\u4e58\u79ef \\n\", array.cumprod()) print(\"\u8f74\u5411\u7d2f\u79ef\u4e58\u79ef \\n\", array.cumprod(axis=1)) # \u6837\u672c\u77e9\u9635 # [[1 2 3 4 5] # [3 4 5 6 7] # [5 6 7 8 9]] # \u8f74\u5411\u6c42\u548c 75 # \u8f74\u5411\u6c42\u548c [ 9 12 15 18 21] # \u6570\u5b66\u5e73\u5747 5.0 # \u8f74\u5411\u6570\u5b66\u5e73\u5747 [3. 4. 5. 6. 7.] # \u6807\u51c6\u5dee 2.160246899469287 \u65b9\u5dee 4.666666666666667 # \u8f74\u5411\u6807\u51c6\u5dee [1.63299316 1.63299316 1.63299316 1.63299316 1.63299316] \u8f74\u5411\u65b9\u5dee [2.66666667 2.66666667 2.66666667 2.66666667 2.66666667] # \u6700\u5c0f\u503c 1 \u6700\u5927\u503c 9 # \u8f74\u5411\u6700\u5c0f\u503c [1 2 3 4 5] \u8f74\u5411\u6700\u5927\u503c [5 6 7 8 9] # \u6700\u5c0f\u503c\u4f4d\u7f6e 0 \u6700\u5927\u503c\u4f4d\u7f6e 14 # \u8f74\u5411\u6700\u5c0f\u503c\u4f4d\u7f6e [0 0 0 0 0] \u8f74\u5411\u6700\u5927\u503c\u4f4d\u7f6e [2 2 2 2 2] # \u7d2f\u79ef\u548c # [ 1 3 6 10 15 18 22 27 33 40 45 51 58 66 75] # \u8f74\u5411\u7d2f\u79ef\u548c # [[ 1 3 6 10 15] # [ 3 7 12 18 25] # [ 5 11 18 26 35]] # \u7d2f\u79ef\u4e58\u79ef # [ 1 2 6 24 120 360 # 1440 7200 43200 302400 1512000 9072000 # 63504000 508032000 4572288000] # \u8f74\u5411\u7d2f\u79ef\u4e58\u79ef # [[ 1 2 6 24 120] # [ 3 12 60 360 2520] # [ 5 30 210 1680 15120]] \u5e03\u5c14\u503c\u6570\u7ec4(Boolean Array)\u7684\u65b9\u6cd5 \u00b6 \u5e03\u5c14\u503c\u6570\u7ec4\uff0c\u6709\u4e24\u4e2a\u975e\u5e38\u6709\u7528\u7684\u65b9\u6cd5any\u548call\u3002 * any\u68c0\u67e5\u6570\u7ec4\u4e2d\u662f\u5426\u81f3\u5c11\u6709\u4e00\u4e2aTrue\uff0c * all\u68c0\u67e5\u662f\u5426\u6bcf\u4e2a\u503c\u90fd\u662fTrue bools = np.array([False, False, True, False]) print(bools.any()) # True print(bools.all()) # False \u4e0b\u9762\u662f\u4e00\u4e2a\u8fd0\u7528\u5e03\u5c14\u503c\u6570\u7ec4\uff08Boolean Array\uff09\u8fdb\u884c\u6c42\u548c\u7684\u4e00\u4e2a\u4f8b\u5b50\uff0c\u5176\u4e2d (array > 0) \u672c\u8eab\u662f\u4e00\u4e2a\u5e03\u5c14\u578b\u7684\u6570\u7ec4\u3002 array = np.random.randn(100) result = (array > 0).sum() # \u8ba1\u7b97\u6b63\u503c\u7684\u4e2a\u6570 print(result) # 59 \u4e0b\u9762\u662f\u8fd0\u7528\u5e03\u5c14\u503c\u6570\u7ec4\u7684\u751f\u6210\u65b0\u6570\u7ec4\u7684\u4f8b\u5b50\u3002 arr = [[8, 9, 10, 11], [0, 1, 2, 3], [4, 5, 6, 7]] arr = np.array(arr) print(arr.shape) # (3, 4) print(arr) # [[ 8 9 10 11] # [ 0 1 2 3] # [ 4 5 6 7]] idx = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]] idx = np.array(idx) print(idx.shape) # (3, 4) print(idx) # [[1 0 0 0] # [0 1 0 0] # [0 0 1 0]] result = arr[idx] # print(result.shape) # (3, 4, 4) print(result) # [[[ 0 1 2 3] # [ 8 9 10 11] # [ 8 9 10 11] # [ 8 9 10 11]] # [[ 8 9 10 11] # [ 0 1 2 3] # [ 8 9 10 11] # [ 8 9 10 11]] # [[ 8 9 10 11] # [ 8 9 10 11] # [ 0 1 2 3] # [ 8 9 10 11]]] result = arr[idx == 1] print(result.shape) print(result) # [8 1 6] \u6392\u5e8f \u00b6 \u548cPython\u7684\u5185\u5efa\u5217\u8868\u7c7b\u578b\u76f8\u4f3c\uff0cNumPy\u6570\u7ec4\u53ef\u4ee5\u4f7f\u7528sort\u65b9\u6cd5\u6309\u4f4d\u7f6e\u6392\u5e8f\u3002 \u9876\u5c42\u7684np.sort\u65b9\u6cd5\u8fd4\u56de\u7684\u662f\u5df2\u7ecf\u6392\u5e8f\u597d\u7684\u6570\u7ec4*\u62f7\u8d1d*\uff0c\u800c\u4e0d\u662f\u5bf9\u539f\u6570\u7ec4\u6309\u4f4d\u7f6e\u6392\u5e8f\u3002 array = np.random.randn(6) print(\"\u6837\u672c\u77e9\u9635\", array) array.sort() print(\"\u6392\u5e8f\u540e\u77e9\u9635\", array) # \u6837\u672c\u77e9\u9635 [-0.03119521 0.01839556 0.79238537 -2.46622775 0.62522211 0.22430846] # \u6392\u5e8f\u540e\u77e9\u9635 [-2.46622775 -0.03119521 0.01839556 0.22430846 0.62522211 0.79238537] \u591a\u7ef4\u6570\u7ec4\u4e2d\u6839\u636e\u4f20\u9012\u7684axis\u503c\uff0c\u6cbf\u7740\u8f74\u5411\u5bf9\u6bcf\u4e2a\u4e00\u7ef4\u6570\u636e\u6bb5\u8fdb\u884c\u6392\u5e8f\u3002 array = np.random.randn(5, 3) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) array.sort(1) print(\"\u5bf91\u8f74\u6392\u5e8f\u540e\u77e9\u9635 \\n\", array) # \u6837\u672c\u77e9\u9635 # [[-0.88057833 0.30160954 -2.08788148] # [ 0.27969618 0.62923028 -0.58157581] # [-1.87194465 -1.1102104 1.09589605] # [ 0.1467938 -1.01558304 -0.25905165] # [-0.17294279 0.62369511 0.17947059]] # \u5bf91\u8f74\u6392\u5e8f\u540e\u77e9\u9635 # [[-2.08788148 -0.88057833 0.30160954] # [-0.58157581 0.27969618 0.62923028] # [-1.87194465 -1.1102104 1.09589605] # [-1.01558304 -0.25905165 0.1467938 ] # [-0.17294279 0.17947059 0.62369511]] \u552f\u4e00\u503c\u4e0e\u5176\u4ed6\u96c6\u5408\u903b\u8f91 \u00b6 NumPy\u5305\u542b\u4e00\u4e9b\u9488\u5bf9\u4e00\u7ef4 ndarray \u6570\u7ec4\u7684\u57fa\u7840\u96c6\u5408\u64cd\u4f5c\u3002 np.unique(x, y) \u8ba1\u7b97x\u7684\u552f\u4e00\u503c\uff0c\u5e76\u6392\u5e8f\u3002 names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe']) result = np.unique(names) # NumPy\u5b9e\u73b0 print(result) # ['Bob' 'Joe' 'Will'] result = sorted(set(names)) # \u7eafPython\u5b9e\u73b0 print(result) # ['Bob' 'Joe' 'Will'] inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) result = np.unique(inits) print(result) # [1 2 3 5] np.in1d(x, y) \u8ba1\u7b97x\u4e2d\u7684\u5143\u7d20\u662f\u5426\u5305\u542b\u5728y\u4e2d\uff0c\u5e76\u8fd4\u56de\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.in1d(inits, [3, 4, 5])) # [ True True True False False False False True True] np.intersect1d(x, y) \uff0c\u8ba1\u7b97x\u548cy\u7684\u4ea4\u96c6\uff0c\u5e76\u6392\u5e8f\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.intersect1d(inits, [3, 4, 5])) # [3 5] np.union1d(x, y) \u8ba1\u7b97x\u548cy\u7684\u5e76\u96c6\uff0c\u5e76\u6392\u5e8f\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.union1d(inits, [3, 4, 5])) # [1 2 3 4 5] np.setdiff1d(x, y) \u5dee\u96c6\uff0c\u5728x\u4e2d\u4f46\u4e0d\u5728y\u4e2d\u7684\u5143\u7d20\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.setdiff1d(inits, [3, 4, 5])) # [1 2] np.setxor1d(x, y) \u5f02\u6216\u96c6\uff0c\u5728x\u6216\u8005y\u4e2d\uff0c\u4f46\u4e0d\u5c5e\u4e8ex\uff0cy\u4ea4\u96c6\u7684\u5143\u7d20\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.setxor1d(inits, [3, 4, 5])) # [1 2 4] \u4f7f\u7528\u6570\u7ec4\u8fdb\u884c\u6587\u4ef6\u8f93\u5165\u548c\u8f93\u51fa \u00b6 NumPy\u53ef\u4ee5\u5728\u786c\u76d8\u4e2d\u5c06\u6570\u636e\u4ee5\u6587\u672c\u6216\u4e8c\u8fdb\u5236\u6587\u4ef6\u7684\u5f62\u5f0f\u8fdb\u884c\u5b58\u5165\u786c\u76d8\u6216\u7531\u786c\u76d8\u8f7d\u5165\u3002 \u5f53\u524d\u53ea\u5173\u6ce8NumPy\u7684\u5185\u5efa\u4e8c\u8fdb\u5236\u683c\u5f0f\uff0c\u56e0\u4e3a\u5927\u90e8\u5206\u7528\u6237\u66f4\u503e\u5411\u4e8e\u4f7f\u7528pandas\u6216\u5176\u4ed6\u5de5\u5177\u6765\u8f7d\u5165\u6587\u672c\u6216\u8868\u683c\u578b\u6570\u636e\u3002 np.save \u548c np.load \u662f\u9ad8\u6548\u5b58\u53d6\u786c\u76d8\u6570\u636e\u7684\u4e24\u5927\u5de5\u5177\u51fd\u6570\u3002\u6570\u7ec4\u5728\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u662f\u4ee5*\u672a\u538b\u7f29*\u7684\u683c\u5f0f\u8fdb\u884c\u5b58\u50a8\u7684\uff0c\u540e\u7f00\u540d\u662f.npy\u3002 import numpy as np array1 = np.arange(10) array2 = np.arange(15).reshape(3, 5) array3 = np.arange(30).reshape(3, 2, 5) print(array1) # [0 1 2 3 4 5 6 7 8 9] print(array2) # [[ 0 1 2 3 4] # [ 5 6 7 8 9] # [10 11 12 13 14]] print(array3) # [[[ 0 1 2 3 4] # [ 5 6 7 8 9]] # [[10 11 12 13 14] # [15 16 17 18 19]] # [[20 21 22 23 24] # [25 26 27 28 29]]] # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os.getcwd() # '/opt/myProject/mySite' # \u66f4\u6539\u9ed8\u8ba4\u8def\u5f84 os.chdir('/opt/myProject/mySite/docs/python/datasets/examples') # \u4fdd\u5b58\u5230\u9ed8\u8ba4\u8def\u5f84\u3002npy\u540e\u7f00\u540d\u4f1a\u88ab\u81ea\u52a8\u52a0\u4e0a np.save('some_array', array1) # \u8bfb\u53d6\u6240\u4fdd\u5b58\u7684\u6587\u4ef6 result = np.load('some_array.npy') # \u5bf9\u6bd4\u7ed3\u679c\u4e00\u81f4\u3002 print(result) # [0 1 2 3 4 5 6 7 8 9] # \u5c06\u591a\u4e2a\u6570\u7ec4\u4fdd\u5b58\u5230\u672a\u538b\u7f29\u7684\u5355\u4e2a\u6587\u4ef6\u4e2d\uff0c.npz\u683c\u5f0f np.savez('some_array_archive.npz', a=array2, b=array3) result = np.load('some_array_archive.npz') # reslt\u662f\u4e00\u4e2a\u5b57\u5178\u578b\u7684\u5bf9\u8c61 print(result['b']) # \u8f7d\u5165\u5355\u4e2a\u6570\u7ec4b # [[[ 0 1 2 3 4] # [ 5 6 7 8 9]] # [[10 11 12 13 14] # [15 16 17 18 19]] # [[20 21 22 23 24] # [25 26 27 28 29]]] \u7ebf\u6027\u4ee3\u6570 \u00b6 \u53c2\u8003\u94fe\u63a5\uff1a https://www.numpy.org.cn/reference/routines/linalg.html https://github.com/teadocs/numpy-cn \u5e0c\u814a\u5b57\u6bcd: \u0391 \u03b1 /'\u00e6lf\u0259/ alpha \u0392 \u03b2 /'bi:t\u0259/ beta \u0393 \u03b3 /'g\u00e6m\u0259/ gamma \u0394 \u03b4 /'delt\u0259/ delta \u0395 \u03b5 /'eps\u026al\u0252n/ epsilon \u0396 \u03b6 /'zi:t\u0259/ zeta \u0397 \u03b7 /'i:t\u0259/ eta \u0398 \u03b8 /'\u03b8i:t\u0259/ theta \u0399 \u03b9 /'a\u026a\u0259\u028at\u0259/ iota \u039a \u03ba /'k\u00e6p\u0259/ kappa \u2227 \u03bb /'l\u00e6md\u0259/ lambda \u039c \u03bc /mju:/ mu \u039d \u03bd /nju:/ nu \u039e \u03be /ksi/ xi \u039f \u03bf /\u0259u\u02c8maikr\u0259n/ omicron \u220f \u03c0 /pa\u026a/ pi \u03a1 \u03c1 /r\u0259\u028a/ rho \u2211 \u03c3 /'s\u026a\u0261m\u0259/ sigma \u03a4 \u03c4 /t\u0254:/ tau \u03a5 \u03c5 /\u02c8ips\u026alon/ upsilon \u03a6 \u03c6 /fa\u026a/ phi \u03a7 \u03c7 /ka\u026a/ chi \u03a8 \u03c8 /psa\u026a/ psi \u03a9 \u03c9 /'\u0259\u028am\u026a\u0261\u0259/ omega numpy.linalg \u6a21\u5757\u5305\u542b\u7ebf\u6027\u4ee3\u6570\u7684\u51fd\u6570\u3002\u4f7f\u7528\u8fd9\u4e2a\u6a21\u5757\uff0c\u53ef\u4ee5\u8ba1\u7b97\u9006\u77e9\u9635\u3001\u6c42\u7279\u5f81\u503c\u3001\u89e3\u7ebf\u6027\u65b9\u7a0b\u7ec4\u4ee5\u53ca\u6c42\u89e3\u884c\u5217\u5f0f\u7b49\u3002 import numpy as np from numpy import linalg as LA from numpy import * from numpy.linalg import inv import matplotlib.pyplot as plt diag \u00b6 np.diag \u5c06\u4e00\u4e2a\u65b9\u9635\u7684\u5bf9\u89d2\uff08\u6216\u975e\u5bf9\u89d2\uff09\u5143\u7d20\u4f5c\u4e3a\u4e00\u7ef4\u6570\u7ec4\u8fd4\u56de\uff0c\u6216\u8005\u5c06\u4e00\u7ef4\u6570\u7ec4\u8f6c\u6362\u6210\u4e00\u4e2a\u65b9\u9635\uff0c\u5e76\u4e14\u5728\u975e\u5bf9\u89d2\u7ebf\u4e0a\u6709\u96f6\u70b9\u3002 a1 = np.arange(9, dtype=float).reshape((3, 3)) r1 = np.diag(a1) r2 = np.diag(a1, k=1) r3 = np.diag(a1, k=-1) r4 = np.diag(np.diag(a1)) # \u5bf9\u89d2\u77e9\u9635 print(\"\u6837\u672c\u77e9\u9635 \\n\", a1) print(\"\u77e9\u9635\u5bf9\u89d2\u7ebf\", r1) print(\"\u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0a\u504f\u79fb\", r2) print(\"\u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0b\u504f\u79fb\", r3) print(\"\u5bf9\u89d2\u77e9\u9635 \\n\", r4) # \u6837\u672c\u77e9\u9635 # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]] # \u77e9\u9635\u5bf9\u89d2\u7ebf [0. 4. 8.] # \u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0a\u504f\u79fb [1. 5.] # \u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0b\u504f\u79fb [3. 7.] # \u5bf9\u89d2\u77e9\u9635 # [[0. 0. 0.] # [0. 4. 0.] # [0. 0. 8.]] dot \u00b6 np.dot \u5c06\u5411\u91cf\u4e2d\u5bf9\u5e94\u5143\u7d20\u76f8\u4e58\uff0c\u518d\u76f8\u52a0\u6240\u5f97\u3002\u5373\u666e\u901a\u7684\u5411\u91cf\u4e58\u6cd5\u8fd0\u7b97\uff0c\u6216**\u77e9\u9635\u70b9\u4e58**\u3002 a1 = np.dot(3, 4) print(a1) # 12 a2 = np.arange(9, dtype=float).reshape((3, 3)) r2 = np.dot(a2, a2) print(a2) # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]] print(r2) # [[ 15. 18. 21.] # [ 42. 54. 66.] # [ 69. 90. 111.]] r3 = np.dot([2j, 3j], [2j, 3j]) print(r3) # (-13+0j) trace \u00b6 np.trace \u8ba1\u7b97\u5bf9\u89d2\u5143\u7d20\u548c\u3002 a1 = np.arange(9, dtype=float).reshape((3, 3)) print(\"\u6837\u672c\u77e9\u9635 \\n\", a1) r1 = np.trace(a1) print(\"\u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c\", r1) a2 = np.arange(24, dtype=float).reshape((2, 3, 4)) r2 = np.trace(a2) print(\"\u6837\u672c\u77e9\u9635 \\n\", a2) print(\"\u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c\", r2) # \u6837\u672c\u77e9\u9635 # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]] # \u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c 12.0 # \u6837\u672c\u77e9\u9635 # [[[ 0. 1. 2. 3.] # [ 4. 5. 6. 7.] # [ 8. 9. 10. 11.]] # # [[12. 13. 14. 15.] # [16. 17. 18. 19.] # [20. 21. 22. 23.]]] # \u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c [16. 18. 20. 22.] det \u00b6 np.det \u8ba1\u7b97\u77e9\u9635\u7684\u884c\u5217\u5f0f\uff08\u65b9\u9635\uff09\u3002 \u4e8c\u9636\u884c\u5217\u5f0f[[a, b], [c, d]]\u7684\u503c\u662fad - bc \u4e09\u9636\u884c\u5217\u5f0f [[a, b, c], [d, e, f], [g, h, i]]\u7684\u503c\u662f aei + bfd + cdh - ceg - bdi - afh \u4e09\u9636\u884c\u5217\u5f0f\u7684\u6027\u8d28 \u6027\u8d281\uff1a\u884c\u5217\u5f0f\u4e0e\u5b83\u7684\u8f6c\u7f6e\u884c\u5217\u5f0f\u76f8\u7b49\u3002 \u6027\u8d282\uff1a\u4e92\u6362\u884c\u5217\u5f0f\u7684\u4e24\u884c(\u5217)\uff0c\u884c\u5217\u5f0f\u53d8\u53f7\u3002 \u63a8\u8bba\uff1a\u5982\u679c\u884c\u5217\u5f0f\u6709\u4e24\u884c(\u5217)\u5b8c\u5168\u76f8\u540c\uff0c\u5219\u6b64\u884c\u5217\u5f0f\u4e3a\u96f6\u3002 \u6027\u8d283\uff1a\u884c\u5217\u5f0f\u7684\u67d0\u4e00\u884c(\u5217)\u4e2d\u6240\u6709\u7684\u5143\u7d20\u90fd\u4e58\u4ee5\u540c\u4e00\u6570k\uff0c\u7b49\u4e8e\u7528\u6570k\u4e58\u6b64\u884c\u5217\u5f0f\u3002 \u63a8\u8bba\uff1a\u884c\u5217\u5f0f\u4e2d\u67d0\u4e00\u884c(\u5217)\u7684\u6240\u6709\u5143\u7d20\u7684\u516c\u56e0\u5b50\u53ef\u4ee5\u63d0\u5230\u884c\u5217\u5f0f\u7b26\u53f7\u7684\u5916\u9762\u3002 \u6027\u8d284\uff1a\u884c\u5217\u5f0f\u4e2d\u5982\u679c\u6709\u4e24\u884c(\u5217)\u5143\u7d20\u6210\u6bd4\u4f8b\uff0c\u5219\u6b64\u884c\u5217\u5f0f\u7b49\u4e8e\u96f6\u3002 \u6027\u8d285\uff1a\u628a\u884c\u5217\u5f0f\u7684\u67d0\u4e00\u5217(\u884c)\u7684\u5404\u5143\u7d20\u4e58\u4ee5\u540c\u4e00\u6570\u7136\u540e\u52a0\u5230\u53e6\u4e00\u5217(\u884c)\u5bf9\u5e94\u7684\u5143\u7d20\u4e0a\u53bb\uff0c\u884c\u5217\u5f0f\u4e0d\u53d8\u3002 a1 = np.array([[1, 2], [3, 4]]) r1 = np.linalg.det(a1) print(\"\u4e8c\u9636\u65b9\u9635 \\n\", a1) print(\"\u4e8c\u9636\u884c\u5217\u5f0f\u7684\u503c\", r1) # \u4e8c\u9636\u65b9\u9635 # [[1 2] # [3 4]] # \u4e8c\u9636\u884c\u5217\u5f0f\u7684\u503c -2.0000000000000004 # \u5e0c\u814a\u5b57\u6bcd # \u03b1, \u03b2, \u03b3,\u03b4, \u03b5, \u03b6, \u03b7, \u03b8, \u03b9, \u03ba, \u03bb, \u03bc, \u03bd, # \u03be, \u03bf, \u03c0, \u03c1, \u03c2, \u03c3, \u03c4, \u03c5, \u03c6, \u03c7, \u03c8, \u03c9, a2 = np.arange(9).reshape(3, 3) r2 = np.linalg.det(a2) print(\"\u4e09\u9636\u65b9\u9635 \\n\", a2) print(\"\u4e09\u9636\u884c\u5217\u5f0f\u7684\u503c\", r2) # \u4e09\u9636\u65b9\u9635 # [[0 1 2] # [3 4 5] # [6 7 8]] # \u4e09\u9636\u884c\u5217\u5f0f\u7684\u503c 0.0 a3 = np.arange(16).reshape(4, 4) r3 = np.linalg.det(a3) print(\"\u56db\u9636\u65b9\u9635 \\n\", a3) print(\"\u56db\u9636\u884c\u5217\u5f0f\u7684\u503c\", r3) # \u56db\u9636\u65b9\u9635 # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]# \u5e0c\u814a\u5b57\u6bcd # \u03b1, \u03b2, \u03b3,\u03b4, \u03b5, \u03b6, \u03b7, \u03b8, \u03b9, \u03ba, \u03bb, \u03bc, \u03bd, # \u03be, \u03bf, \u03c0, \u03c1, \u03c2, \u03c3, \u03c4, \u03c5, \u03c6, \u03c7, \u03c8, \u03c9, # [12 13 14 15]] # \u56db\u9636\u884c\u5217\u5f0f\u7684\u503c 0.0 eig \u00b6 np.eig \u8ba1\u7b97\u65b9\u9635\u7684\u7279\u5f81\u503c\u548c\u7279\u5f81\u5411\u91cf\u3002 \u7279\u5f81\u503c\u4e0e\u7279\u5f81\u5411\u91cf\u7684\u5b9a\u4e49\uff1a\u8bbeA\u662fn\u9636\u65b9\u9635\uff0c\u82e5\u6570\u03bb\u548cn\u7ef4\u975e\u96f6\u5217\u5411\u91cfx\uff0c\u4f7f\u5f97Ax = \u03bbx\u6210\u7acb\uff0c\u5219\u79f0\u03bb\u662f\u65b9\u9635A\u7684\u4e00\u4e2a\u7279\u5f81\u503c\uff0cx\u4e3a\u65b9\u9635A\u7684\u5bf9\u5e94\u4e8e\u7279\u5f81\u503c\u03bb\u7684\u4e00\u4e2a\u7279\u5f81\u5411\u91cf\u3002 A\u662f\u65b9\u9635\u3002\uff08\u5bf9\u4e8e\u975e\u65b9\u9635\uff0c\u662f\u6ca1\u6709\u7279\u5f81\u503c\u7684\uff0c\u4f46\u4f1a\u6709\u6761\u4ef6\u6570\u3002\uff09\u7279\u5f81\u5411\u91cfx\u4e3a\u975e\u96f6\u5217\u5411\u91cf\u3002 v_eigenvectors, v_eigenvalues = LA.eig(np.diag((1, 2, 3))) print(\"\u7279\u5f81\u5411\u91cf\", v_eigenvectors) print(\"\u7279\u5f81\u503c \\n\", v_eigenvalues) # \u7279\u5f81\u5411\u91cf [1. 2. 3.] # \u7279\u5f81\u503c # [[1. 0. 0.] # [0. 1. 0.] # [0. 0. 1.]] v_eigenvectors, v_eigenvalues = LA.eig(np.array([[1, -1], [1, 1]])) print(\"\u7279\u5f81\u5411\u91cf\", v_eigenvectors) print(\"\u7279\u5f81\u503c \\n\", v_eigenvalues) # \u7279\u5f81\u5411\u91cf [1.+1.j 1.-1.j] # \u7279\u5f81\u503c # [[0.70710678+0.j 0.70710678-0.j ] # [0. -0.70710678j 0. +0.70710678j]] inv \u00b6 np.inv \u8ba1\u7b97\u65b9\u9635\u7684\u9006\u77e9\u9635\u3002 a1 = np.array([[1, 2], [3, 4]]) r1 = inv(a1) r2 = inv(np.matrix(a1)) print(\"\u539f\u77e9\u9635 \\n\", a1) print(\"\u9006\u77e9\u9635 \\n\", r1) print(\"\u9006\u77e9\u9635 \\n\", r2) # \u539f\u77e9\u9635 # [[1 2] # [3 4]] # \u9006\u77e9\u9635 # [[-2. 1. ] # [ 1.5 -0.5]] # \u9006\u77e9\u9635 # [[-2. 1. ] # [ 1.5 -0.5]] pinv \u00b6 np.pinv \u8ba1\u7b97\u77e9\u9635\u7684Moore-Penrose\u4f2a\u9006(\u6469\u5c14\uff0d\u5f6d\u82e5\u65af\u5e7f\u4e49\u9006)\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u68c0\u9a8c a * a+ * a == a \u548c a+ * a * a+ == a+ a = np.random.randn(9, 6) B = np.linalg.pinv(a) r1 = np.allclose(a, np.dot(a, np.dot(B, a))) r2 = np.allclose(B, np.dot(B, np.dot(a, B))) print(a) print(B) print(r1) # True print(r2) # True # a: # [[-2.30316101 -0.63217332 1.24134743 -0.72492307 0.12456801 -0.14192548] # [ 1.37573495 0.07626697 -0.71870843 1.26824984 -0.79485727 -0.24630455] # [ 0.29003175 -1.23931665 -0.50864107 -0.31140718 0.45467649 -2.44973999] # [-0.70748664 -1.2995059 0.85126149 -1.10918804 -2.10042342 0.75942293] # [ 1.91765238 1.23892103 1.58516486 -1.65520154 0.11894439 0.84536298] # [ 1.03220791 0.1715148 0.85595408 0.58569706 1.34066384 -1.5782386 ] # [-0.54432889 -0.0114189 1.55403934 0.89852512 1.15586365 -0.30733805] # [-0.80874673 0.14602121 1.04680044 1.98722514 0.39766383 0.75178788] # [ 0.01664663 0.06243353 -0.50725334 -0.37707204 -1.76701091 -0.33866559]] # B: # [[-0.25055838 0.13963115 0.08990923 0.16280282 0.12997291 0.05088469 -0.01541299 -0.01656133 -0.21731387] # [ 0.22862622 -0.05108109 -0.2639602 -0.47835978 0.11776862 0.09324694 0.00436756 -0.00609393 0.61995597] # [ 0.10422554 0.03985857 0.00198025 0.15139023 0.17165026 0.15697725 0.17360246 0.13150089 0.08378135] # [-0.07021378 0.17665487 -0.04109252 0.0015022 -0.11998477 0.0543575 0.08649033 0.21190785 0.04065729] # [-0.08110336 -0.15274536 0.05601496 -0.07967802 -0.02454705 -0.04152356 0.00071268 -0.05981012 -0.43996066] # [-0.17998537 -0.03160871 -0.12587707 0.16856246 0.00565094 -0.21038026 -0.06060039 0.04322126 -0.42038066]] qr \u00b6 np.qr \u8ba1\u7b97QR\u5206\u89e3\u3002QR\uff08\u6b63\u4ea4\u4e09\u89d2\uff09\u5206\u89e3\u6cd5\u662f\u6c42\u4e00\u822c\u77e9\u9635\u5168\u90e8\u7279\u5f81\u503c\u7684\u6700\u6709\u6548\u5e76\u5e7f\u6cdb\u5e94\u7528\u7684\u65b9\u6cd5\u3002 \u4e00\u822c\u77e9\u9635\u5148\u7ecf\u8fc7\u6b63\u4ea4\u76f8\u4f3c\u53d8\u5316\u6210\u4e3aHessenberg\u77e9\u9635\uff0c\u7136\u540e\u518d\u5e94\u7528QR\u65b9\u6cd5\u6c42\u7279\u5f81\u503c\u548c\u7279\u5f81\u5411\u91cf\u3002QR\u5206\u89e3\u6cd5\u662f\u5c06\u77e9\u9635\u5206\u89e3\u6210\u4e00\u4e2a\u6b63\u89c4\u6b63\u4ea4\u77e9\u9635Q\u4e0e\u4e0a\u4e09\u89d2\u5f62\u77e9\u9635R\uff0c\u6240\u4ee5\u79f0\u4e3aQR\u5206\u89e3\u6cd5\u3002 a = np.arange(9).reshape(3, 3) q, r = np.linalg.qr(a) print(\"\u539f\u77e9\u9635 \\n\", a) print(\"\u6b63\u4ea4\u77e9\u9635 \\n\", q) print(\"\u4e0a\u4e09\u89d2\u77e9\u9635 \\n\", r) # \u539f\u77e9\u9635 # [[0 1 2] # [3 4 5] # [6 7 8]] # \u6b63\u4ea4\u77e9\u9635 # [[ 0. 0.91287093 0.40824829] # [-0.4472136 0.36514837 -0.81649658] # [-0.89442719 -0.18257419 0.40824829]] # \u4e0a\u4e09\u89d2\u77e9\u9635 # [[-6.70820393e+00 -8.04984472e+00 -9.39148551e+00] # [ 0.00000000e+00 1.09544512e+00 2.19089023e+00] # [ 0.00000000e+00 0.00000000e+00 -8.88178420e-16]] svd \u00b6 np.svd \u8ba1\u7b97\u5947\u5f02\u503c\u5206\u89e3\uff08SVD\uff09\u3002 \u51e0\u4f55\u610f\u4e49\uff1aSVD\u5206\u89e3\u7684\u51e0\u4f55\u610f\u4e49\u662f\u4efb\u4f55\u4e00\u4e2a\u77e9\u9635A\u5728\u4e00\u7cfb\u5217\u65cb\u8f6c\u548c\u5e73\u79fb\u4e0b\u90fd\u80fd\u8f6c\u5316\u6210\u4e00\u4e2a\u5bf9\u89d2\u77e9\u9635\u2211 , \u5176\u4e2d\u9149\u9635U, V\u7684\u51e0\u4f55\u610f\u4e49\u5c31\u662f\u4e00\u7cfb\u5217\u65cb\u8f6c\u548c\u5e73\u79fb\u7684\u53e0\u52a0\u3002 a = mat([[1, 2, 3],[4, 5, 6]]) U, sigma, V = np.linalg.svd(a) print(\"\u539f\u77e9\u9635 \\n\", a) print(\"\u5de6\u5947\u5f02\u503cU \\n\", U) print(\"\u5947\u5f02\u503cSigma \\n\", sigma) print(\"\u53f3\u5947\u5f02\u503cV \\n\", V) # \u539f\u77e9\u9635 # [[1 2 3] # [4 5 6]] # \u5de6\u5947\u5f02\u503cU # [[-0.3863177 -0.92236578] # [-0.92236578 0.3863177 ]] # \u5947\u5f02\u503cSigma # [9.508032 0.77286964] # \u53f3\u5947\u5f02\u503cV # [[-0.42866713 -0.56630692 -0.7039467 ] # [ 0.80596391 0.11238241 -0.58119908] # [ 0.40824829 -0.81649658 0.40824829]] solve \u00b6 np.solve \u6c42\u89e3x\u7684\u7ebf\u6027\u7cfb\u7edfAx = b\uff0c\u5176\u4e2dA\u662f\u65b9\u9635\u3002 \u89e3\u65b9\u7a0b\u7ec4\uff1a x + 2y = 1 3x + 5y = 2 a = np.array([[1, 2], [3, 5]]) b = np.array([1, 2]) x = np.linalg.solve(a, b) print(x) # [-1. 1.] lstsq \u00b6 np.lstsq \u8ba1\u7b97Ax = b\u7684\u6700\u5c0f\u4e8c\u4e58\u89e3\u3002 \u7528\u6700\u5c0f\u4e8c\u4e58\u6cd5\u62df\u5408\u6570\u636e\u5f97\u5230\u4e00\u4e2a\u5f62\u5982y = mx + c\u7684\u7ebf\u6027\u65b9\u7a0b\uff08Return the least-squares solution to a linear matrix equation\uff09\u3002 x = np.array([0, 1, 2, 3]) # \u539f\u59cb\u6570\u636e\u70b9\u7684\u6a2a\u5750\u6807 y = np.array([-1, 0.2, 0.9, 2.1]) # \u539f\u59cb\u6570\u636e\u70b9\u7684\u7eb5\u5750\u6807 print(x) # [0 1 2 3] print(y) # [-1. 0.2 0.9 2.1] A = np.vstack([x, np.ones(len(x))]).T # \u6784\u9020\u7cfb\u6570\u77e9\u9635 print(A) # [[0. 1.] # [1. 1.] # [2. 1.] # [3. 1.]] m, c = np.linalg.lstsq(A, y, rcond=None)[0] # \u89e3\u51fa\u659c\u7387a\u548c\u7eb5\u622a\u8dddc plt.plot(x, y, 'o', label='Original data', markersize=10) # \u505a\u51fa\u539f\u59cb\u6570\u636e\u6563\u70b9\u56fe plt.plot(x, m*x + c, 'r', label='Fitted line') # \u7528\u4e0a\u9762\u89e3\u51fa\u7684\u53c2\u6570\u505a\u51fa\u62df\u5408\u66f2\u7ebfy=mx+c plt.legend() plt.show() \u4f2a\u968f\u673a\u6570\u751f\u6210 \u00b6 numpy.random \u6a21\u5757\u586b\u8865\u4e86Python\u5185\u5efa\u7684 random \u6a21\u5757\u7684\u4e0d\u8db3\uff0c\u53ef\u4ee5\u9ad8\u6548\u5730\u751f\u6210\u591a\u79cd\u6982\u7387\u5206\u5e03\u4e0b\u7684\u5b8c\u6574\u6837\u672c\u503c\u6570\u7ec4\u3002 numpy.random \u4e2d\u7684\u6570\u636e\u751f\u6210\u51fd\u6570\u516c\u7528\u4e86\u4e00\u4e2a\u5168\u5c40\u7684\u968f\u673a\u6570\u79cd\u5b50\u3002 \u4f7f\u7528 numpy.random.RandomState \u751f\u6210\u4e00\u4e2a\u968f\u673a\u6570\u751f\u6210\u5668\uff0c\u4f7f\u6570\u636e\u72ec\u7acb\u4e8e\u5176\u4ed6\u7684\u968f\u673a\u6570\u72b6\u6001\u3002 \u901a\u8fc7 np.random.seed \u66f4\u6539NumPy\u7684\u968f\u673a\u6570\u79cd\u5b50\u3002 numpy.random \u4e2d\u7684\u90e8\u5206\u51fd\u6570\u5217\u8868 seed: \u5411\u968f\u673a\u6570\u751f\u6210\u5668\u4f20\u9012\u968f\u673a\u72b6\u6001\u79cd\u5b50 permutation: \u8fd4\u56de\u4e00\u4e2a\u5e8f\u5217\u7684\u968f\u673a\u6392\u5217\uff0c\u6216\u8005\u8fd4\u56de\u4e00\u4e2a\u4e71\u5e8f\u7684\u6574\u6570\u8303\u56f4\u5e8f\u5217 shuffle: \u968f\u673a\u6392\u5217\u4e00\u4e2a\u5e8f\u5217 rand: \u4ece\u5747\u5300\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c randint: \u6839\u636e\u7ed9\u5b9a\u7684\u7531\u4f4e\u5230\u9ad8\u7684\u8303\u56f4\u62bd\u53d6\u968f\u673a\u6574\u6570 randn: \u4ece\u5747\u503c0\u65b9\u5dee1\u7684\u6b63\u6001\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c(MATLAB\u578b\u63a5\u53e3\uff09 binomial: \u4ece\u4e8c\u9879\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c normal: \u4ece\u6b63\u6001\uff08\u9ad8\u65af\uff09\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c beta\u4ecebeta: \u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c chisquare: \u4ece\u5361\u65b9\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c \u4f8b\u5982\uff0c\u4f7f\u7528normal\u6765\u83b7\u5f97\u4e00\u4e2a4\u00d74\u7684\u6b63\u6001\u5206\u5e03\u6837\u672c\u6570\u7ec4\uff0c\u79f0\u4e3a\u4f2a\u968f\u673a\u6570\u3002 import numpy as np samples = np.random.normal(size=(4, 4)) print(samples) # [[ 0.78583658 -0.27462104 -0.53027675 -0.62675004] # [ 0.39054781 1.20503691 -0.0057432 0.17243182] # [-0.41516669 -0.93335854 0.01996088 -0.12707275] # [ 0.42952379 2.56998319 0.14848737 -0.42871493]] \u793a\u4f8b\uff1a\u968f\u673a\u6f2b\u6b65 \u00b6 import matplotlib.pyplot as plt import numpy as np position = 0 walk = [position] nwalks = 5000 nsteps = 1000 draws = np.random.randint(0, 2, size=(nwalks, nsteps)) steps = np.where(draws > 0, 1, -1) walks = steps.cumsum() plt.plot(walks[:500000000000000000000000000]) plt.show() \u8f93\u51fa\u56fe\u50cf\uff1a","title":"NumPy\u57fa\u7840"},{"location":"python/DataAnalysis/ch01/#numpy","text":"\u5305\u542b\u4ee5\u4e0b\u5185\u5bb9\uff1a \u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61 \u901a\u7528\u51fd\u6570 \u9762\u5411\u6570\u7ec4\u7f16\u7a0b \u4f7f\u7528\u6570\u7ec4\u8fdb\u884c\u6587\u4ef6\u8f93\u5165\u548c\u8f93\u51fa \u7ebf\u6027\u4ee3\u6570 \u4f2a\u968f\u673a\u6570\u751f\u6210 \u793a\u4f8b\uff1a\u968f\u673a\u6f2b\u6b65","title":"NumPy\u57fa\u7840"},{"location":"python/DataAnalysis/ch01/#ndarry","text":"","title":"\u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61ndarry"},{"location":"python/DataAnalysis/ch01/#_1","text":"import numpy as np import pandas as pd import matplotlib.pyplot as plt","title":"\u522b\u540d\u7ea6\u5b9a"},{"location":"python/DataAnalysis/ch01/#matplotlib","text":"\u67e5\u770b\u5b57\u4f53\u8def\u5f84 >>> import matplotlib >>> print(matplotlib.matplotlib_fname()) /home/james/.local/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc \u4e0b\u8f7d\u4e2d\u6587\u5b57\u4f53\u3002\u7f51\u5740 https://www.fontpalace.com/font-download/SimHei/,\u5e76\u62f7\u8d1d\u5230\u4e0b\u9762\u7684\u8def\u5f84\u4e0b james@lizard:~/Downloads> cp SimHei.ttf /home/james/.local/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf/ \u67e5\u770bmatplotlib\u7684\u5b57\u4f53\u7f13\u5b58\u76ee\u5f55\u3002 >>> import matplotlib >>> print(matplotlib.get_cachedir()) /home/james/.cache/matplotlib \u5220\u9664\u8fd9\u4e2a\u76ee\u5f55 james@lizard:~> rm -rf /home/james/.cache/matplotlib \u7f16\u8f91matplotlibrc\u6587\u4ef6 /home/james/.local/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc \uff0c\u505a\u5982\u4e0b\u4fee\u6539\u3002 \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # font.family: sans-serif \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # \uff0c\u5e76\u6dfb\u52a0 SimHei \uff0c\u4fee\u6539\u540e\u4e3a font.serif: SimHei, DejaVu Serif, Bitstream Vera Serif, Computer Modern Roman, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # \uff0c\u5e76\u6dfb\u52a0 SimHei \uff0c\u4fee\u6539\u540e\u4e3a font.sans-serif: SimHei, DejaVu Sans, Bitstream Vera Sans, Computer Modern Sans Serif, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif \u5b9a\u4f4d\u8fd9\u4e00\u884c\uff0c\u53bb\u6389\u6ce8\u91ca\u7b26 # \uff0c\u5e76\u628a True \u6539\u4e3a False \uff0c\u4fee\u6539\u540e\u4e3a axes.unicode_minus: False","title":"\u5b89\u88c5matplotlib\u4e2d\u6587\u5b57\u4f53"},{"location":"python/DataAnalysis/ch01/#matplotlib_1","text":"\u5728\u4f7f\u7528matplotlib\u8f93\u51fa\u56fe\u50cf\u65f6\uff0c\u5982\u679c\u9047\u5230\u65e0\u6cd5\u663e\u793a\u56fe\u50cf\u7684\u9519\u8bef UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure\u3002 \uff0c\u53ef\u4ee5\u5c1d\u8bd5\u4e0b\u9762\u7684\u6b65\u9aa4\u89e3\u51b3\u3002 \u5b89\u88c5 python3-tk \u5305 james@lizard:~> sudo zypper in python3-tk \u6216\u8005\u901a\u8fc7 pip \u5b89\u88c5 tk \u5305 james@lizard:~> pip3 install tk Defaulting to user installation because normal site-packages is not writeable Collecting tk Downloading tk-0.1.0-py3-none-any.whl (3.9 kB) Installing collected packages: tk Successfully installed tk-0.1.0 \u4e00\u822c\u5b8c\u6210\u4e0a\u9762\u5b89\u88c5\u540e\uff0c\u7a0b\u5e8f\u5c31\u80fd\u81ea\u52a8\u663e\u793a\u56fe\u4e86\uff0c\u5982\u679c\u8fd8\u662f\u4e0d\u80fd\u663e\u793a\uff0c\u518d\u5c1d\u8bd5\u91cd\u65b0\u5b89\u88c5 matplotlib \u3002 pip3 ininstall matplotlib pip3 install matplotlib","title":"\u8bbe\u7f6ematplotlib\u540e\u7aef\u6e32\u67d3\u5668"},{"location":"python/DataAnalysis/ch01/#ndarray-n-","text":"\u4e00\u4e2andarray\u662f\u4e00\u4e2a\u901a\u7528\u7684\u591a\u7ef4\u540c\u7c7b\u6570\u636e\u5bb9\u5668\uff0c\u4e5f\u5c31\u662f\u8bf4\uff0c\u5b83\u5305\u542b\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u5747\u4e3a**\u76f8\u540c\u7c7b\u578b**\uff1b \u6bcf\u4e00\u4e2a\u6570\u7ec4\u90fd\u6709\u4e00\u4e2ashape\u5c5e\u6027\uff0c\u7528\u6765\u8868\u5f81\u6570\u7ec4\u6bcf\u4e00\u7ef4\u5ea6\u7684\u6570\u91cf\uff1b \u6bcf\u4e00\u4e2a\u6570\u7ec4\u90fd\u6709\u4e00\u4e2adtype\u5c5e\u6027\uff0c\u7528\u6765\u63cf\u8ff0\u6570\u7ec4\u7684\u6570\u636e\u7c7b\u578b\uff1b \u4e0b\u9762\u662f\u6807\u51c6\u6570\u7ec4\u7684\u751f\u6210\u51fd\u6570 array: \u5c06\u8f93\u5165\u6570\u636e\uff08\u5217\u8868\u3001\u5143\u7ec4\u3001\u6570\u7ec4\uff0c\u5176\u4ed6\u5e8f\u5217\uff09\u8f6c\u6362\u4e3andarray\uff0c\u5982\u679c\u4e0d\u663e\u5f0f\u6307\u660e\u6570\u636e\u7c7b\u578b\uff0c\u5c06\u81ea\u52a8\u63a8\u65ad\uff1b\u9ed8\u8ba4\u590d\u5236\u6240\u6709\u7684\u8f93\u5165\u6570\u636e\u3002 asarray\uff1a\u5c06\u8f93\u5165\u8f6c\u6362\u4e3andarray\uff0c\u4f46\u5982\u679c\u8f93\u5165\u5df2\u7ecf\u662fndarray\u5219\u4e0d\u518d\u590d\u5236\u3002 arange\uff1aPython\u5185\u7f6e\u51fd\u6570range\u7684\u6570\u7ec4\u7248\uff0c\u8fd4\u56de\u4e00\u4e2a\u6570\u7ec4\u3002 \u4e0b\u9762\u662f\u7528 Numpy.random() \u4e00\u4e2a\u751f\u6210\u4e00\u4e2a\u968f\u673a\u6570\u7ec4\u7684\u4f8b\u5b50\uff0c\u6ce8\u610f data01 \u7684\u7c7b\u578b\u662f'numpy.ndarray'\u3002\u53ef\u4ee5\u5728ndarray\u7c7b\u578b\u6570\u7ec4\u4e0a\u53e0\u52a0\u4e00\u4e0b\u6570\u5b66\u64cd\u4f5c\u3002 data01 = np.random.randn(2, 3) print(type(data01)) # print(data01) # [[ 0.12047302 -1.13499045 -0.39311368] # [ 1.54046881 0.01254838 -3.65090952]] print(data01 * 10) # \u7ed9data\u52a0\u4e0a\u4e00\u4e2a\u6570\u5b66\u64cd\u4f5c, \u6240\u6709\u7684\u5143\u7d20\u90fd\u540c\u65f6\u4e58\u4ee5\u4e8610 # [[ 1.20473022 -11.3499045 -3.93113676] # [ 15.40468806 0.12548383 -36.50909515]] print(data01 + data01) # \u7ed9data\u52a0\u4e0a\u4e00\u4e2a\u6570\u5b66\u64cd\u4f5c, \u6570\u7ec4\u4e2d\u7684\u5bf9\u5e94\u5143\u7d20\u8fdb\u884c\u4e86\u76f8\u52a0 # [[ 0.24094604 -2.2699809 -0.78622735] # [ 3.08093761 0.02509677 -7.30181903]] print(data01.shape) # (2, 3) print(data01.dtype) # float64 \u5f53\u8868\u8fbe\u201c\u6570\u7ec4\u201d\u3001\u201cNumPy\u6570\u7ec4\u201d\u6216\u201cndarray\u201d\u65f6\uff0c\u90fd\u8868\u793a\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1andarray\u5bf9\u8c61\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a data01 \u662f\u4e00\u4e2a\u5217\u8868\uff08list\uff09\u7c7b\u578b\uff0c\u901a\u8fc7 Numpy.array \u8f6c\u6362\u6210Numpy\u7684 ndarray \u7c7b\u578b\u3002 \u5728 np.array \u4e2d\uff0c\u9664\u975e\u663e\u5f0f\u5730\u6307\u5b9a\uff0c\u5982 np.array(data01, dtype=np.int8) \uff0c\u5426\u5219np.array\u4f1a\u81ea\u52a8\u63a8\u65ad\u751f\u6210\u6570\u7ec4\u7684\u6570\u636e\u7c7b\u578b array01.dtype \u3002 \u4f7f\u7528 astype() \u65b9\u6cd5\u663e\u5f0f\u5730\u8f6c\u6362\u6570\u7ec4\u7684\u6570\u636e\u7c7b\u578b\u3002\u4f7f\u7528 astype() \u65f6\u603b\u662f\u751f\u6210\u4e00\u4e2a*\u65b0\u7684\u6570\u7ec4*\uff0c\u5373\u4f7f\u4f60\u4f20\u5165\u7684dtype\u4e0e\u4e4b\u524d\u4e00\u6837\u3002 data02 \u662f\u4e00\u4e2a\u5d4c\u5957\u5217\u8868 [[1, 2, 3, 4], [5, 6, 7, 8]] \uff0c\u901a\u8fc7np.array()\u65b9\u6cd5\u8f6c\u6362\u6210\u591a\u7ef4\u6570\u7ec4\uff0c\u524d\u63d0\u662f\u6bcf\u4e2a\u5b50\u5217\u8868\u7684\u957f\u5ea6\u8981\u4e00\u81f4\u3002 data01 = [6, 7.5, 8, 0, 1] print(data01) # [6, 7.5, 8, 0, 1] print(type(data01)) # array01 = np.array(data01) print(\"\u77e9\u9635\u7c7b\u578b\", type(array01)) # \u77e9\u9635\u7c7b\u578b print(\"\u6837\u672c\u77e9\u9635\", array01) # \u6837\u672c\u77e9\u9635 [6. 7.5 8. 0. 1. ] print(\"\u6570\u7ec4\u7ef4\u5ea6\", array01.ndim) # \u6570\u7ec4\u7ef4\u5ea6 1 print(\"\u77e9\u9635\u5f62\u72b6\", array01.shape) # \u77e9\u9635\u5f62\u72b6 (5,) \u4e00\u884c\u4e94\u5217 print(\"\u77e9\u9635\u6570\u636e\u7c7b\u578b\", array01.dtype) # float64 data02 = [[1, 2, 3, 4], [5, 6, 7, 8]] array02 = np.array(data02) print(\"\u6837\u672c\u77e9\u9635\\n\", array02) # \u6837\u672c\u77e9\u9635 # [[1 2 3 4] # [5 6 7 8]] print(\"\u6570\u7ec4\u7ef4\u5ea6\", array02.ndim) # \u6570\u7ec4\u7ef4\u5ea6 2 print(\"\u77e9\u9635\u5f62\u72b6\", array02.shape) # \u77e9\u9635\u5f62\u72b6 (2, 4) print(\"\u77e9\u9635\u6570\u636e\u7c7b\u578b\", array02.dtype) # \u77e9\u9635\u6570\u636e\u7c7b\u578b int64 print(\"\u77e9\u96350\u8f74\u5411\u6c42\u548c\", array02.sum(axis=0)) # \u77e9\u96350\u8f74\u5411\u6c42\u548c [ 6 8 10 12] print(\"\u77e9\u96351\u8f74\u5411\u6c42\u548c\", array02.sum(axis=1)) # \u77e9\u96351\u8f74\u5411\u6c42\u548c [10 26] array03 = array02.astype(np.float64) print(array03.dtype) # float64 print(array03) # [[1. 2. 3. 4.] # [5. 6. 7. 8.]] zeros() \u65b9\u6cd5\u53ef\u4ee5\u4e00\u6b21\u6027\u521b\u9020\u51680\u6570\u7ec4\u3002 print(np.zeros(10)) # [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] ones() \u65b9\u6cd5\u53ef\u4ee5\u4e00\u6b21\u6027\u521b\u9020\u51681\u6570\u7ec4\u3002\u6ce8\u610f\uff0c\u4f20\u53c2shape\u662f\u4e00\u4e2a\u5143\u7ec4 (3, 5) \u3002 print(np.ones((3, 5))) # [[1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.]] empty() \u65b9\u6cd5\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u6ca1\u6709\u521d\u59cb\u5316\u6570\u503c\u7684\u6570\u7ec4\u3002\u4f46\u662f\uff0c\u4f7f\u7528np.empty\u6765\u751f\u6210\u4e00\u4e2a\u51680\u6570\u7ec4\uff0c\u5e76\u4e0d\u53ef\u9760\uff0c\u6709\u4e9b\u65f6\u5019\u5b83\u53ef\u80fd\u4f1a\u8fd4\u56de\u672a\u521d\u59cb\u5316\u7684\u5783\u573e\u6570\u503c print(np.empty((2, 3, 2))) # [[[2.30116964e-316 0.00000000e+000] # [2.10077583e-312 6.79038654e-313] # [2.22809558e-312 2.14321575e-312]] # # [[2.35541533e-312 6.79038654e-313] # [2.22809558e-312 2.14321575e-312] # [2.46151512e-312 2.41907520e-312]]]","title":"ndarray: N-\u7ef4\u6570\u7ec4\u5bf9\u8c61"},{"location":"python/DataAnalysis/ch01/#numpy_1","text":"\u4e00\u53e5\u8bdd\u603b\u7ed3\uff1a\u5c06NumPy\u8f74\u89c6\u4e3a\u6211\u4eec\u53ef\u4ee5\u6267\u884c\u64cd\u4f5c\u7684\u65b9\u5411\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a arr_1 = np.array([[1, 1, 1], [1, 1, 1]]) arr_2 = np.array([[9, 9, 9], [9, 9, 9]]) print(arr_1) # [[1 1 1] # [1 1 1]] print(arr_2) # [[9 9 9] # [9 9 9]] \u6cbf0\u8f74\u5408\u5e76\u7684\u601d\u8def\u662f\uff0c\u4e24\u4e2a\u6570\u7ec4\u6cbf0\u8f74\u65b9\u5411\uff0c\u54110\u8f74\u201c\u584c\u7f29\u201d\uff08collapse\uff09\u3002 result = np.concatenate([arr_1, arr_2], axis=0) print(result) # [[1 1 1] # [1 1 1] # [9 9 9] # [9 9 9]] \u6cbf1\u8f74\u5408\u5e76\u7684\u601d\u8def\u662f\uff0c\u4e24\u4e2a\u6570\u7ec4\u6cbf1\u8f74\u65b9\u5411\uff0c\u54111\u8f74\u201c\u584c\u7f29\u201d result = np.concatenate([arr_1, arr_2], axis=1) print(result) # [[1 1 1 9 9 9] # [1 1 1 9 9 9]] \u6211\u4eec\u6765\u770bNumPy\u7684\u4e09\u7ef4\u6570\u7ec4\u3002 array1 = np.arange(36).reshape((3, 3, 4)) print(array1) # [[[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] # # [[12 13 14 15] # [16 17 18 19] # [20 21 22 23]] # # [[24 25 26 27] # [28 29 30 31] # [32 33 34 35]]] \u8fd9\u6837\u770b\u4f1a\u5bb9\u6613\u7406\u89e3\u4e00\u4e9b\uff0c0\u8f74\u67093\u884c\uff0c1\u8f74\u67093\u5217\uff0c2\u8f74\u67094\u4e2a\u5143\u7d20\uff1a [[[ 0 1 2 3], [ 4 5 6 7], [ 8 9 10 11]] [[12 13 14 15], [16 17 18 19], [20 21 22 23]] [[24 25 26 27], [28 29 30 31], [32 33 34 35]]] \u8f93\u51fa\uff1a\u8f740\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f741\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f742\u7d22\u5f15\u53f7\uff1a\u5168\u90e8 print(array1[0, 0, :]) # [0 1 2 3] \u8f93\u51fa\uff1a\u8f740\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f741\u7d22\u5f15\u53f7\uff1a0\uff1b\u8f742\u7d22\u5f15\u53f7\uff1a1 print(array1[0, 0, 1]) # 1","title":"NumPy\u8f74"},{"location":"python/DataAnalysis/ch01/#numpy_2","text":"\u4e00\u4e2a**\u6807\u91cf**\u5c31\u662f\u4e00\u4e2a\u5355\u72ec\u7684\u6570\u3002\u4e00\u4e2a\u5411\u91cf\u5c31\u662f\u4e00\u5217\u6570\uff0c\u8fd9\u4e9b\u6570\u662f\u6709\u5e8f\u6392\u5217\u7684\u3002 \u77e9\u9635\u662f\u4e8c\u7ef4\u6570\u7ec4\uff0c\u5176\u4e2d\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u88ab\u4e24\u4e2a\u7d22\u5f15\u800c\u975e\u4e00\u4e2a\u6240\u786e\u5b9a\u3002 \u51e0\u4f55\u4ee3\u6570\u4e2d\u5b9a\u4e49\u7684**\u5f20\u91cf**\u662f\u57fa\u4e8e\u5411\u91cf\u548c\u77e9\u9635\u7684\u63a8\u5e7f\uff0c\u6211\u4eec\u53ef\u4ee5**\u5c06\u6807\u91cf\u89c6\u4e3a\u96f6\u9636\u5f20\u91cf**\uff0c \u77e2\u91cf**\u89c6\u4e3a\u4e00\u9636\u5f20\u91cf\uff0c\u90a3\u4e48**\u77e9\u9635\u5c31\u662f\u4e8c\u9636\u5f20\u91cf \u3002 \u5e26\u6709\u6807\u91cf\u8ba1\u7b97\u7684\u7b97\u672f\u64cd\u4f5c\uff0c\u4f1a\u628a\u8ba1\u7b97\u53c2\u6570\u4f20\u9012\u7ed9\u6570\u7ec4\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u3002 \u540c\u5c3a\u5bf8\u6570\u7ec4\u4e4b\u95f4\u7684\u6bd4\u8f83 array04 == array04 \uff0c\u4f1a\u4ea7\u751f\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4 \u4e0d\u540c\u5c3a\u5bf8\u7684\u6570\u7ec4\u95f4\u7684\u64cd\u4f5c\uff0c\u5c06\u4f1a\u7528\u5230 \u5e7f\u64ad\u7279\u6027\uff08broadcasting\uff09 \u3002 array04 = np.array([ [1, 2, 3, 4, 5], [3, 4, 5, 6, 7], [5, 6, 7, 8, 9] ], dtype=int) print(array04 + array04) # [[ 2 4 6 8 10] # [ 6 8 10 12 14] # [10 12 14 16 18]] print(array04 - array04) # [[0 0 0 0 0] # [0 0 0 0 0] # [0 0 0 0 0]] print(array04 * array04) # [[ 1 4 9 16 25] # [ 9 16 25 36 49] # [25 36 49 64 81]] print(array04 / array04) # [[1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.] # [1. 1. 1. 1. 1.]] print(1 / array04) # [[1. 0.5 0.33333333 0.25 0.2 ] # [0.33333333 0.25 0.2 0.16666667 0.14285714] # [0.2 0.16666667 0.14285714 0.125 0.11111111]] print(array04 == array04) # [[ True True True True True] # [ True True True True True] # [ True True True True True]]","title":"NumPy\u6570\u7ec4\u7b97\u672f"},{"location":"python/DataAnalysis/ch01/#_2","text":"ndarray\u5bf9\u8c61\u7684\u5185\u5bb9\u53ef\u4ee5\u901a\u8fc7\u7d22\u5f15\uff08indexing\uff09\u6216\u5207\u7247\uff08slicing\uff09\u6765\u8bbf\u95ee\u548c\u4fee\u6539\uff0cndarray\u5bf9\u8c61\u4e2d\u7684\u5143\u7d20\u7d22\u5f15\u4ece\u96f6\u5f00\u59cb\u3002 \u6709\u4e09\u79cd\u53ef\u7528\u7684\u7d22\u5f15\u65b9\u6cd5\uff1a\u5b57\u6bb5\u8bbf\u95ee\uff0c\u57fa\u672c\u5207\u7247\u548c\u9ad8\u7ea7\u7d22\u5f15\u3002 \u7d22\u5f15\uff08indexing\uff09\uff1a\u83b7\u53d6\u6570\u7ec4\u4e2d\u7279\u5b9a\u4f4d\u7f6e\u5143\u7d20\u7684\u8fc7\u7a0b\u3002 \u5207\u7247\uff08slicing\uff09\uff1a\u83b7\u53d6\u6570\u7ec4\u5143\u7d20\u5b50\u96c6\u7684\u8fc7\u7a0b\u3002\u6570\u7ec4\u7684\u5207\u7247\u662f\u539f\u6570\u7ec4\u7684\u89c6\u56fe\u3002\u8fd9\u610f\u5473\u7740\u4efb\u4f55**\u5bf9\u4e8e\u89c6\u56fe\u7684\u4fee\u6539\u90fd\u4f1a\u53cd\u6620\u5230\u539f\u6570\u7ec4\u4e0a**\u3002\u6570\u7ec4\u7684\u5207\u7247, \u8fd4\u56de\u7684\u5bf9\u8c61\u662f\u964d\u4f4e\u4e00\u4e2a\u7ef4\u5ea6\u7684\u6570\u7ec4\u3002 \u4e00\u7ef4\u6570\u7ec4\u7684\u7d22\u5f15\u548c\u5207\u7247\uff1a\u4e0ePython\u7684\u5217\u8868\u7c7b\u4f3c\uff1a a[n] \uff1a\u8fd4\u56de\u7b2c n+1 \u4e2a\u5143\u7d20\u3002\u5982\u679c n \u4e3a\u8d1f\u6570\uff0c\u5219\u8fd4\u56de\u5012\u6570\u7b2c n \u4e2a\u5143\u7d20\u3002 a[n:m:k] \uff1a\u8d77\u59cb\u7f16\u53f7 n \uff0c\u7ec8\u6b62\u7f16\u53f7 m \uff0c\u6b65\u957f k \uff0c\u7528\u5192\u53f7\u5206\u5272\u3002 \u9075\u5faa\u5de6\u95ed\u53f3\u5f00\u7684\u539f\u5219 \uff0c\u5373 [n, m) \u3002\u5982\u679c n \u4e3a\u7a7a\uff0c\u5373 n = 0 \uff1b\u5982\u679c m \u4e3a\u7a7a\uff0c\u5373 m = len(a) \u3002 \u591a\u7ef4\u6570\u7ec4\u7684\u7d22\u5f15\u548c\u5207\u7247\uff1a a[n,m,k,...] \uff1a\u6bcf\u4e2a\u7ef4\u5ea6\u4e00\u4e2a\u7d22\u5f15\u503c\uff0c\u6700\u5916\u5c42\u5217\u8868\uff08list\uff09\u4e2d\u7b2c n \u4e2a\u5143\u7d20\uff0c\u6b21\u5916\u5c42\u5217\u8868\uff08list\uff09\u4e2d\u7b2c m \u4e2a\u5143\u7d20\uff0c\u4ee5\u6b64\u7c7b\u63a8\u3002\u5982\u679c n \u4e3a\u8d1f\u6570\uff0c\u5219\u8fd4\u56de\u5012\u6570\u7b2c n \u4e2a\u5143\u7d20\u3002 a[n1:m1:k1,n2:m2:k2,n3:m3:k3,...] \uff1a\u6bcf\u4e2a\u7ef4\u5ea6\u7684\u5207\u7247\u65b9\u6cd5\u4e0e\u4e00\u7ef4\u6570\u7ec4\u76f8\u540c\u3002\u987a\u5e8f\u4e3a\u4ece\u5916\u5230\u5185\u3002 array05 = np.arange(10) print(array05) # [0 1 2 3 4 5 6 7 8 9] # \u4ece\u7d22\u5f15\u503c5\u5f00\u59cb\u5230\u7d22\u5f15\u503c7\u7684\u4e00\u4e2a\u5207\u7247\u3002 print(array05[5:8]) # [5 6 7] array06 = array05[5:8] # \u4f20\u5165\u4e00\u4e2a\u6570\u503c\u7ed9\u6570\u7ec4\u7684\u5207\u7247\uff0c\u6570\u503c\u88ab\u4f20\u9012\u7ed9\u4e86\u6574\u4e2a\u5207\u7247\u3002\u4e0d\u5199\u5207\u7247\u503c\u7684[:]\u5c06\u4f1a\u5f15\u7528\u6570\u7ec4\u7684\u6240\u6709\u503c array06[:] = 12 print(array06) # [12 12 12] # \u5207\u7247\u7684\u4fee\u6539\u4f1a\u53cd\u6620\u5230\u539f\u6570\u7ec4\u4e0a print(array05) # [ 0 1 2 3 4 12 12 12 8 9] # \u8f93\u51fa3\u7ef4\u77e9\u9635\uff0c3\u884c3\u5217\uff0c\u51719\u4e2a\u5143\u7d20\uff0c\u6bcf\u4e2a\u5143\u7d20\u662f\u4e00\u4e2a\u542b3\u4e2a\u5143\u7d20\u7684\u5217\u8868 array07 = np.array([ [[0, 1, 2], [3, 4, 5], [6, 7, 8]], [[9, 0, 1], [2, 3, 4], [5, 6, 7]], [[8, 9, 0], [1, 2, 3], [4, 5, 6]], ]) # \u8f93\u51fa3\u7ef4\u77e9\u9635\uff0c\u663e\u793a\u539f\u77e9\u9635\u7684\u7b2c1\uff0c2\u884c\u76842\uff0c3\u5217\u5143\u7d20\uff0c\u4e0d\u8981\u628a\u7d22\u5f15\u53f7\u548c\u8fd9\u91cc\u7684\u8868\u8ff0\u884c\u53f7\u6df7\u6dc6\u3002 print(array07[:2, 1:]) # [[[3 4 5] [6 7 8]] # [[2 3 4] [5 6 7]]] print(array07[:2, 1:].shape) # (2, 2, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c3\u884c print(array07[2]) # [[8 9 0] [1 2 3] [4 5 6]] print(array07[2].shape) # (3, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c3\u884c print(array07[2, :]) # [[8 9 0] [1 2 3] [4 5 6]] print(array07[2, :].shape) # (3, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c3\u884c\uff08\u53ea\u6709\u4e09\u884c\uff0c\u6240\u4ee5[2:, :]\u7b49\u540c\u4e8e[2, :]\uff09 print(array07[2:, :]) # [[[8 9 0] [1 2 3] [4 5 6]]] print(array07[2:, :].shape) # (1, 3, 3) # \u8f93\u51fa\u539f\u77e9\u9635\u76841\uff0c2\u5217 print(array07[:, :2]) # [[[0 1 2] [3 4 5]] # [[9 0 1] [2 3 4]] # [[8 9 0] [1 2 3]]] print(array07[:, :2].shape) # (3, 2, 3) # \u964d\u7ef4\uff0c\u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u524d2\u4e2a\u5143\u7d20 print(array07[1, :2]) # [[9 0 1] [2 3 4]] print(array07[1, :2].shape) # (2, 3) # \u8f93\u51fa\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u524d2\u4e2a\u5143\u7d20 print(array07[1:2, :2]) # [[[9 0 1] [2 3 4]]] print(array07[1:2, :2].shape) # (1, 2, 3) # \u5c06\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u8d4b\u503c\u7ed9\u53d8\u91cf old_value = array07[2].copy() print(old_value) # [[8 9 0] [1 2 3] [4 5 6]] # \u4fee\u6539\u539f\u77e9\u9635\u7684\u7b2c2\u884c\u7684\u503c\uff0c\u6807\u91cf\u548c\u6570\u7ec4\u90fd\u53ef\u4ee5\u4f20\u9012\u7ed9 array07[2] array07[2] = 25 print(array07) # [[[ 0 1 2] [ 3 4 5] [ 6 7 8]] # [[ 9 0 1] [ 2 3 4] [ 5 6 7]] # [[25 25 25] [25 25 25] [25 25 25]]] # \u5c06\u53d8\u91cf\u503c\u8d4b\u503c\u7ed9\u539f\u77e9\u9635\u7684\u7b2c2\u884c array07[2] = old_value print(array07) # [[[0 1 2] [3 4 5] [6 7 8]] # [[9 0 1] [2 3 4] [5 6 7]] # [[8 9 0] [1 2 3] [4 5 6]]]","title":"\u57fa\u7840\u7d22\u5f15\u4e0e\u5207\u7247"},{"location":"python/DataAnalysis/ch01/#_3","text":"\u5e03\u5c14\u503c\u7d22\u5f15\uff08Boolean indexing\uff09\u662f\u901a\u8fc7\u4e00\u4e2a\u5e03\u5c14\u6570\u7ec4\u6765\u7d22\u5f15\u76ee\u6807\u6570\u7ec4\uff0c\u4ee5\u6b64\u627e\u51fa\u4e0e\u5e03\u5c14\u6570\u7ec4\u4e2d\u503c\u4e3aTrue\u7684\u5bf9\u5e94\u7684\u76ee\u6807\u6570\u7ec4\u4e2d\u7684\u6570\u636e\u3002\u5e03\u5c14\u6570\u7ec4\u7684\u957f\u5ea6\u5fc5\u987b\u4e0e\u76ee\u6807\u6570\u7ec4\u5bf9\u5e94\u7684\u8f74\u7684\u957f\u5ea6\u4e00\u81f4\u3002 \u4f7f\u7528\u5e03\u5c14\u503c\u7d22\u5f15\uff08Boolean indexing\uff09\u9009\u62e9\u6570\u636e\u65f6\uff0c\u603b\u662f\u751f\u6210\u6570\u636e\u7684\u62f7\u8d1d\uff0c\u5373\u4f7f\u8fd4\u56de\u7684\u6570\u7ec4\u5e76\u6ca1\u6709\u4efb\u4f55\u53d8\u5316\u3002 \u5047\u8bbe\u6211\u4eec\u7684\u6570\u636e\u90fd\u5728\u6570\u7ec4\u4e2d\uff0c\u5e76\u4e14\u6570\u7ec4\u4e2d\u7684\u6570\u636e\u662f\u4e00\u4e9b\u5b58\u5728\u91cd\u590d\u7684\u4eba\u540d\u3002\u7528randn\u51fd\u6570\u751f\u6210\u4e00\u4e9b\u6807\u51c6\u6b63\u6001(standard normal)\u5206\u5e03\u7684\u6570\u636e\u3002\u5047\u8bbe\u6bcf\u4e2a\u4eba\u540d\u90fd\u548cdata\u6570\u7ec4\u4e2d\u7684\u4e00\u884c\u76f8\u5bf9\u5e94\uff0c\u5e76\u4e14\u6211\u4eec\u60f3\u8981\u9009\u4e2d\u6240\u6709\u2019Bob\u2019\u5bf9\u5e94\u7684\u884c\u3002 names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'], dtype=' # \u56fe\u50cf\u6807\u9898 plt.title(\"$\\sqrt{x^2 + y^2}$ \u8ba1\u7b97\u503c\u7684\u7f51\u683c\u56fe\") # \u8f93\u51fa\u56fe\u50cf plt.show() \u8f93\u51fa\u56fe\u50cf\u4e3a\uff1a","title":"\u9762\u5411\u6570\u7ec4\u7f16\u7a0b"},{"location":"python/DataAnalysis/ch01/#_8","text":"numpy.where \u51fd\u6570\u662f\u4e09\u5143\u8868\u8fbe\u5f0f x if condition else y \u7684\u5411\u91cf\u5316\u7248\u672c\u3002 np.where \u7684\u7b2c\u4e8c\u4e2a\u548c\u7b2c\u4e09\u4e2a\u53c2\u6570\u5e76\u4e0d\u9700\u8981\u662f\u6570\u7ec4\uff0c\u5b83\u4eec\u53ef\u4ee5\u662f\u6807\u91cf\u3002 np.where \u5728\u6570\u636e\u5206\u6790\u4e2d\u7684\u4e00\u4e2a\u5178\u578b\u7528\u6cd5\u662f\u6839\u636e\u4e00\u4e2a\u6570\u7ec4\u6765\u751f\u6210\u4e00\u4e2a\u65b0\u7684\u6570\u7ec4\u3002 \u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4\u548c\u4e24\u4e2a\u6570\u503c\u6570\u7ec4\u3002\u5047\u8bbe cond \u4e2d\u7684\u5143\u7d20\u4e3a True \u65f6\uff0c\u6211\u4eec\u53d6 xarr \u4e2d\u7684\u5bf9\u5e94\u5143\u7d20\u503c\uff0c\u5426\u5219\u53d6 yarr \u4e2d\u7684\u5143\u7d20\u3002 xarray = np.array([1.1, 1.2, 1.3, 1.4, 1.5]) yarray = np.array([2.1, 2.2, 2.3, 2.4, 2.5]) cond = np.array([True, False, True, True, False]) \u901a\u8fc7\u5217\u8868\u63a8\u5bfc\u5f0f\u6765\u5b9e\u73b0\u4e0a\u8ff0\u9700\u6c42\u3002 \u7f3a\u70b9: \u9996\u5148\uff0c\u5982\u679c\u6570\u7ec4\u5f88\u5927\u7684\u8bdd\uff0c\u901f\u5ea6\u4f1a\u5f88\u6162\uff08\u56e0\u4e3a\u6240\u6709\u7684\u5de5\u4f5c\u90fd\u662f\u901a\u8fc7\u89e3\u91ca\u5668\u6765\u89e3\u91caPython\u4ee3\u7801\u5b8c\u6210\uff09\u3002 \u5176\u6b21\uff0c\u5f53\u6570\u7ec4\u662f\u591a\u7ef4\u65f6\uff0c\u5c31\u65e0\u6cd5\u51d1\u6548\u4e86\u3002 # \u901a\u8fc7\u5217\u8868\u63a8\u5bfc\u5f0f\u6765\u5b9e\u73b0 result = [(x if c else y) for x, y, c in zip(xarray, yarray, cond)] print(result) # [1.1, 2.2, 1.3, 1.4, 2.5] \u901a\u8fc7 np.where \u6765\u5b9e\u73b0\u4e0a\u8ff0\u9700\u6c42\u3002 result = np.where(cond, xarray, yarray) print(result) # [1.1 2.2 1.3 1.4 2.5] \u5047\u8bbe\u6709\u4e00\u4e2a\u968f\u673a\u751f\u6210\u7684\u77e9\u9635\u6570\u636e\uff0c\u4e0b\u9762\u4f7f\u7528np.where\u5b9e\u73b0\u66ff\u6362\u3002 array = np.random.randn(4, 4) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) print(\"\u77e9\u9635\u5143\u7d20\u662f\u5426\u5927\u4e8e0 \\n\", array > 0) # \u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2\uff0c\u5c06\u6240\u6709\u7684\u8d1f\u503c\u66ff\u6362\u4e3a-2 result03 = np.where(array > 0, 2, -2) print(\"\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2\uff0c\u5c06\u6240\u6709\u7684\u8d1f\u503c\u66ff\u6362\u4e3a-2 \\n\", result03) # \u4ec5\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2 result04 = np.where(array > 0, 2, array) print(\"\u4ec5\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2 \\n\", result04) # \u6837\u672c\u77e9\u9635 # [[-0.57177422 -0.34917512 2.20268075 1.99959296] # [ 0.67966599 2.67915099 -0.40528454 -0.80339907] # [-0.74406888 2.33802717 -0.74582936 0.59347128] # [ 0.68624473 0.65953112 -0.40871415 -0.68698878]] # \u77e9\u9635\u5143\u7d20\u662f\u5426\u5927\u4e8e0 # [[False False True True] # [ True True False False] # [False True False True] # [ True True False False]] # \u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2\uff0c\u5c06\u6240\u6709\u7684\u8d1f\u503c\u66ff\u6362\u4e3a-2 # [[-2 -2 2 2] # [ 2 2 -2 -2] # [-2 2 -2 2] # [ 2 2 -2 -2]] # \u4ec5\u5c06\u5176\u4e2d\u7684\u6b63\u503c\u90fd\u66ff\u6362\u4e3a2 # [[-0.57177422 -0.34917512 2. 2. ] # [ 2. 2. -0.40528454 -0.80339907] # [-0.74406888 2. -0.74582936 2. ] # [ 2. 2. -0.40871415 -0.68698878]]","title":"\u901a\u8fc7\u6761\u4ef6\u903b\u8f91\u64cd\u4f5c\u6570\u7ec4"},{"location":"python/DataAnalysis/ch01/#_9","text":"NumPy\u6709\u4e00\u4e9b\u4e13\u95e8\u7684\u6570\u5b66\u51fd\u6570\uff0c\u7528\u6765\u8ba1\u7b97\u6574\u4e2a\u6570\u7ec4\u7edf\u8ba1\u503c\u6216\u8f74\u5411\u6570\u636e\u7684\u8ba1\u7b97\u3002\u4f8b\u5982\uff0c\u805a\u5408\u51fd\u6570\uff08\u901a\u5e38\u4e5f\u53eb\u7f29\u51cf\u51fd\u6570\uff09\uff0c\u5982sum\u3001mean\u548cstd\uff08\u6807\u51c6\u5dee\uff09\u3002 \u65e2\u53ef\u4ee5\u76f4\u63a5\u8c03\u7528\u6570\u7ec4\u5b9e\u4f8b\u7684\u65b9\u6cd5\uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u9876\u5c42\u7684NumPy\u51fd\u6570\u3002 \u4e3e\u4f8b\uff1a\u751f\u6210\u4e00\u4e9b\u6b63\u6001\u5206\u5e03\u7684\u968f\u673a\u6570\uff0c\u8ba1\u7b97\u90e8\u5206\u805a\u5408\u7edf\u8ba1\u6570\u636e\u3002 \u8fd9\u91cc\u518d\u5bf9\u8f74\u5411\u505a\u4e2a\u89e3\u91ca\uff0c np.random.randn(5, 4) \u4ea7\u751f\u7684\u4e8c\u7ef4\u6570\u7ec4\u662f\uff1a0\u8f74\u54115\u4e2a\u5143\u7d20, 1\u8f74\u54114\u4e2a\u5143\u7d20\u3002 # \u751f\u62102\u8f74\u6570\u7ec4 array = np.random.randn(5, 4) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) print(\"\u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c\", array.mean()) print(\"\u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c\", np.mean(array)) print(\"\u77e9\u9635\u5143\u7d20\u548c\", array.sum()) print(\"\u77e9\u9635\u5143\u7d20\u548c\", np.sum(array)) print(\"0\u8f74\u5411\u7684\u7d2f\u548c\", array.sum(axis=0)) print(\"1\u8f74\u5411\u7684\u7d2f\u548c\", array.sum(axis=1)) print(\"1\u8f74\u5411\u7684\u5e73\u5747\u503c\", array.mean(axis=1)) # \u6837\u672c\u77e9\u9635 shape=(5, 4) 0\u8f74\u54115\u4e2a\u5143\u7d20, 1\u8f74\u54114\u4e2a\u5143\u7d20 # [[ 0.32532911 -0.00177984 -1.59432632 1.58375133] # [ 1.48921763 0.25202456 0.44076148 -1.02277289] # [-0.73490219 0.19197171 -0.22374362 0.52610852] # [-1.03531076 1.0595528 -0.11566501 0.34063544] # [-0.2122241 -0.81348187 1.70989712 -0.00732696]] # \u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c 0.10788580775057008 # \u77e9\u9635\u5143\u7d20\u5e73\u5747\u503c 0.10788580775057008 # \u77e9\u9635\u5143\u7d20\u548c 2.1577161550114017 # \u77e9\u9635\u5143\u7d20\u548c 2.1577161550114017 # 0\u8f74\u5411\u7684\u7d2f\u548c [-0.16789031 0.68828737 0.21692365 1.42039545] # 1\u8f74\u5411\u7684\u7d2f\u548c [ 0.31297429 1.15923078 -0.24056558 0.24921247 0.67686419] # 1\u8f74\u5411\u7684\u5e73\u5747\u503c [ 0.07824357 0.28980769 -0.06014139 0.06230312 0.16921605] \u4e0b\u9762\u5217\u4e3e\u4e86\u5e38\u7528\u7684\u57fa\u7840\u6570\u7ec4\u7edf\u8ba1\u65b9\u6cd5\u3002 array = np.array([ [1, 2, 3, 4, 5], [3, 4, 5, 6, 7], [5, 6, 7, 8, 9] ], dtype=int) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) print(\"\u8f74\u5411\u6c42\u548c\", array.sum()) print(\"\u8f74\u5411\u6c42\u548c\", array.sum(axis=0)) print(\"\u6570\u5b66\u5e73\u5747\", array.mean()) print(\"\u8f74\u5411\u6570\u5b66\u5e73\u5747\", array.mean(axis=0)) print(\"\u6807\u51c6\u5dee\", array.std(), \"\u65b9\u5dee\", array.var()) print(\"\u8f74\u5411\u6807\u51c6\u5dee\", array.std(axis=0), \"\u8f74\u5411\u65b9\u5dee\", array.var(axis=0)) print(\"\u6700\u5c0f\u503c\", array.min(), \"\u6700\u5927\u503c\", array.max()) print(\"\u8f74\u5411\u6700\u5c0f\u503c\", array.min(axis=0), \"\u8f74\u5411\u6700\u5927\u503c\", array.max(axis=0)) print(\"\u6700\u5c0f\u503c\u4f4d\u7f6e\", array.argmin(), \"\u6700\u5927\u503c\u4f4d\u7f6e\", array.argmax()) print(\"\u8f74\u5411\u6700\u5c0f\u503c\u4f4d\u7f6e\", array.argmin(axis=0), \"\u8f74\u5411\u6700\u5927\u503c\u4f4d\u7f6e\", array.argmax(axis=0)) print(\"\u7d2f\u79ef\u548c \\n\", array.cumsum()) print(\"\u8f74\u5411\u7d2f\u79ef\u548c \\n\", array.cumsum(axis=1)) print(\"\u7d2f\u79ef\u4e58\u79ef \\n\", array.cumprod()) print(\"\u8f74\u5411\u7d2f\u79ef\u4e58\u79ef \\n\", array.cumprod(axis=1)) # \u6837\u672c\u77e9\u9635 # [[1 2 3 4 5] # [3 4 5 6 7] # [5 6 7 8 9]] # \u8f74\u5411\u6c42\u548c 75 # \u8f74\u5411\u6c42\u548c [ 9 12 15 18 21] # \u6570\u5b66\u5e73\u5747 5.0 # \u8f74\u5411\u6570\u5b66\u5e73\u5747 [3. 4. 5. 6. 7.] # \u6807\u51c6\u5dee 2.160246899469287 \u65b9\u5dee 4.666666666666667 # \u8f74\u5411\u6807\u51c6\u5dee [1.63299316 1.63299316 1.63299316 1.63299316 1.63299316] \u8f74\u5411\u65b9\u5dee [2.66666667 2.66666667 2.66666667 2.66666667 2.66666667] # \u6700\u5c0f\u503c 1 \u6700\u5927\u503c 9 # \u8f74\u5411\u6700\u5c0f\u503c [1 2 3 4 5] \u8f74\u5411\u6700\u5927\u503c [5 6 7 8 9] # \u6700\u5c0f\u503c\u4f4d\u7f6e 0 \u6700\u5927\u503c\u4f4d\u7f6e 14 # \u8f74\u5411\u6700\u5c0f\u503c\u4f4d\u7f6e [0 0 0 0 0] \u8f74\u5411\u6700\u5927\u503c\u4f4d\u7f6e [2 2 2 2 2] # \u7d2f\u79ef\u548c # [ 1 3 6 10 15 18 22 27 33 40 45 51 58 66 75] # \u8f74\u5411\u7d2f\u79ef\u548c # [[ 1 3 6 10 15] # [ 3 7 12 18 25] # [ 5 11 18 26 35]] # \u7d2f\u79ef\u4e58\u79ef # [ 1 2 6 24 120 360 # 1440 7200 43200 302400 1512000 9072000 # 63504000 508032000 4572288000] # \u8f74\u5411\u7d2f\u79ef\u4e58\u79ef # [[ 1 2 6 24 120] # [ 3 12 60 360 2520] # [ 5 30 210 1680 15120]]","title":"\u6570\u5b66\u548c\u7edf\u8ba1\u65b9\u6cd5"},{"location":"python/DataAnalysis/ch01/#boolean-array","text":"\u5e03\u5c14\u503c\u6570\u7ec4\uff0c\u6709\u4e24\u4e2a\u975e\u5e38\u6709\u7528\u7684\u65b9\u6cd5any\u548call\u3002 * any\u68c0\u67e5\u6570\u7ec4\u4e2d\u662f\u5426\u81f3\u5c11\u6709\u4e00\u4e2aTrue\uff0c * all\u68c0\u67e5\u662f\u5426\u6bcf\u4e2a\u503c\u90fd\u662fTrue bools = np.array([False, False, True, False]) print(bools.any()) # True print(bools.all()) # False \u4e0b\u9762\u662f\u4e00\u4e2a\u8fd0\u7528\u5e03\u5c14\u503c\u6570\u7ec4\uff08Boolean Array\uff09\u8fdb\u884c\u6c42\u548c\u7684\u4e00\u4e2a\u4f8b\u5b50\uff0c\u5176\u4e2d (array > 0) \u672c\u8eab\u662f\u4e00\u4e2a\u5e03\u5c14\u578b\u7684\u6570\u7ec4\u3002 array = np.random.randn(100) result = (array > 0).sum() # \u8ba1\u7b97\u6b63\u503c\u7684\u4e2a\u6570 print(result) # 59 \u4e0b\u9762\u662f\u8fd0\u7528\u5e03\u5c14\u503c\u6570\u7ec4\u7684\u751f\u6210\u65b0\u6570\u7ec4\u7684\u4f8b\u5b50\u3002 arr = [[8, 9, 10, 11], [0, 1, 2, 3], [4, 5, 6, 7]] arr = np.array(arr) print(arr.shape) # (3, 4) print(arr) # [[ 8 9 10 11] # [ 0 1 2 3] # [ 4 5 6 7]] idx = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]] idx = np.array(idx) print(idx.shape) # (3, 4) print(idx) # [[1 0 0 0] # [0 1 0 0] # [0 0 1 0]] result = arr[idx] # print(result.shape) # (3, 4, 4) print(result) # [[[ 0 1 2 3] # [ 8 9 10 11] # [ 8 9 10 11] # [ 8 9 10 11]] # [[ 8 9 10 11] # [ 0 1 2 3] # [ 8 9 10 11] # [ 8 9 10 11]] # [[ 8 9 10 11] # [ 8 9 10 11] # [ 0 1 2 3] # [ 8 9 10 11]]] result = arr[idx == 1] print(result.shape) print(result) # [8 1 6]","title":"\u5e03\u5c14\u503c\u6570\u7ec4(Boolean Array)\u7684\u65b9\u6cd5"},{"location":"python/DataAnalysis/ch01/#_10","text":"\u548cPython\u7684\u5185\u5efa\u5217\u8868\u7c7b\u578b\u76f8\u4f3c\uff0cNumPy\u6570\u7ec4\u53ef\u4ee5\u4f7f\u7528sort\u65b9\u6cd5\u6309\u4f4d\u7f6e\u6392\u5e8f\u3002 \u9876\u5c42\u7684np.sort\u65b9\u6cd5\u8fd4\u56de\u7684\u662f\u5df2\u7ecf\u6392\u5e8f\u597d\u7684\u6570\u7ec4*\u62f7\u8d1d*\uff0c\u800c\u4e0d\u662f\u5bf9\u539f\u6570\u7ec4\u6309\u4f4d\u7f6e\u6392\u5e8f\u3002 array = np.random.randn(6) print(\"\u6837\u672c\u77e9\u9635\", array) array.sort() print(\"\u6392\u5e8f\u540e\u77e9\u9635\", array) # \u6837\u672c\u77e9\u9635 [-0.03119521 0.01839556 0.79238537 -2.46622775 0.62522211 0.22430846] # \u6392\u5e8f\u540e\u77e9\u9635 [-2.46622775 -0.03119521 0.01839556 0.22430846 0.62522211 0.79238537] \u591a\u7ef4\u6570\u7ec4\u4e2d\u6839\u636e\u4f20\u9012\u7684axis\u503c\uff0c\u6cbf\u7740\u8f74\u5411\u5bf9\u6bcf\u4e2a\u4e00\u7ef4\u6570\u636e\u6bb5\u8fdb\u884c\u6392\u5e8f\u3002 array = np.random.randn(5, 3) print(\"\u6837\u672c\u77e9\u9635 \\n\", array) array.sort(1) print(\"\u5bf91\u8f74\u6392\u5e8f\u540e\u77e9\u9635 \\n\", array) # \u6837\u672c\u77e9\u9635 # [[-0.88057833 0.30160954 -2.08788148] # [ 0.27969618 0.62923028 -0.58157581] # [-1.87194465 -1.1102104 1.09589605] # [ 0.1467938 -1.01558304 -0.25905165] # [-0.17294279 0.62369511 0.17947059]] # \u5bf91\u8f74\u6392\u5e8f\u540e\u77e9\u9635 # [[-2.08788148 -0.88057833 0.30160954] # [-0.58157581 0.27969618 0.62923028] # [-1.87194465 -1.1102104 1.09589605] # [-1.01558304 -0.25905165 0.1467938 ] # [-0.17294279 0.17947059 0.62369511]]","title":"\u6392\u5e8f"},{"location":"python/DataAnalysis/ch01/#_11","text":"NumPy\u5305\u542b\u4e00\u4e9b\u9488\u5bf9\u4e00\u7ef4 ndarray \u6570\u7ec4\u7684\u57fa\u7840\u96c6\u5408\u64cd\u4f5c\u3002 np.unique(x, y) \u8ba1\u7b97x\u7684\u552f\u4e00\u503c\uff0c\u5e76\u6392\u5e8f\u3002 names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe']) result = np.unique(names) # NumPy\u5b9e\u73b0 print(result) # ['Bob' 'Joe' 'Will'] result = sorted(set(names)) # \u7eafPython\u5b9e\u73b0 print(result) # ['Bob' 'Joe' 'Will'] inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) result = np.unique(inits) print(result) # [1 2 3 5] np.in1d(x, y) \u8ba1\u7b97x\u4e2d\u7684\u5143\u7d20\u662f\u5426\u5305\u542b\u5728y\u4e2d\uff0c\u5e76\u8fd4\u56de\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.in1d(inits, [3, 4, 5])) # [ True True True False False False False True True] np.intersect1d(x, y) \uff0c\u8ba1\u7b97x\u548cy\u7684\u4ea4\u96c6\uff0c\u5e76\u6392\u5e8f\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.intersect1d(inits, [3, 4, 5])) # [3 5] np.union1d(x, y) \u8ba1\u7b97x\u548cy\u7684\u5e76\u96c6\uff0c\u5e76\u6392\u5e8f\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.union1d(inits, [3, 4, 5])) # [1 2 3 4 5] np.setdiff1d(x, y) \u5dee\u96c6\uff0c\u5728x\u4e2d\u4f46\u4e0d\u5728y\u4e2d\u7684\u5143\u7d20\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.setdiff1d(inits, [3, 4, 5])) # [1 2] np.setxor1d(x, y) \u5f02\u6216\u96c6\uff0c\u5728x\u6216\u8005y\u4e2d\uff0c\u4f46\u4e0d\u5c5e\u4e8ex\uff0cy\u4ea4\u96c6\u7684\u5143\u7d20\u3002 inits = np.array([3, 3, 3, 2, 2, 1, 1, 5, 5]) print(np.setxor1d(inits, [3, 4, 5])) # [1 2 4]","title":"\u552f\u4e00\u503c\u4e0e\u5176\u4ed6\u96c6\u5408\u903b\u8f91"},{"location":"python/DataAnalysis/ch01/#_12","text":"NumPy\u53ef\u4ee5\u5728\u786c\u76d8\u4e2d\u5c06\u6570\u636e\u4ee5\u6587\u672c\u6216\u4e8c\u8fdb\u5236\u6587\u4ef6\u7684\u5f62\u5f0f\u8fdb\u884c\u5b58\u5165\u786c\u76d8\u6216\u7531\u786c\u76d8\u8f7d\u5165\u3002 \u5f53\u524d\u53ea\u5173\u6ce8NumPy\u7684\u5185\u5efa\u4e8c\u8fdb\u5236\u683c\u5f0f\uff0c\u56e0\u4e3a\u5927\u90e8\u5206\u7528\u6237\u66f4\u503e\u5411\u4e8e\u4f7f\u7528pandas\u6216\u5176\u4ed6\u5de5\u5177\u6765\u8f7d\u5165\u6587\u672c\u6216\u8868\u683c\u578b\u6570\u636e\u3002 np.save \u548c np.load \u662f\u9ad8\u6548\u5b58\u53d6\u786c\u76d8\u6570\u636e\u7684\u4e24\u5927\u5de5\u5177\u51fd\u6570\u3002\u6570\u7ec4\u5728\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u662f\u4ee5*\u672a\u538b\u7f29*\u7684\u683c\u5f0f\u8fdb\u884c\u5b58\u50a8\u7684\uff0c\u540e\u7f00\u540d\u662f.npy\u3002 import numpy as np array1 = np.arange(10) array2 = np.arange(15).reshape(3, 5) array3 = np.arange(30).reshape(3, 2, 5) print(array1) # [0 1 2 3 4 5 6 7 8 9] print(array2) # [[ 0 1 2 3 4] # [ 5 6 7 8 9] # [10 11 12 13 14]] print(array3) # [[[ 0 1 2 3 4] # [ 5 6 7 8 9]] # [[10 11 12 13 14] # [15 16 17 18 19]] # [[20 21 22 23 24] # [25 26 27 28 29]]] # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os.getcwd() # '/opt/myProject/mySite' # \u66f4\u6539\u9ed8\u8ba4\u8def\u5f84 os.chdir('/opt/myProject/mySite/docs/python/datasets/examples') # \u4fdd\u5b58\u5230\u9ed8\u8ba4\u8def\u5f84\u3002npy\u540e\u7f00\u540d\u4f1a\u88ab\u81ea\u52a8\u52a0\u4e0a np.save('some_array', array1) # \u8bfb\u53d6\u6240\u4fdd\u5b58\u7684\u6587\u4ef6 result = np.load('some_array.npy') # \u5bf9\u6bd4\u7ed3\u679c\u4e00\u81f4\u3002 print(result) # [0 1 2 3 4 5 6 7 8 9] # \u5c06\u591a\u4e2a\u6570\u7ec4\u4fdd\u5b58\u5230\u672a\u538b\u7f29\u7684\u5355\u4e2a\u6587\u4ef6\u4e2d\uff0c.npz\u683c\u5f0f np.savez('some_array_archive.npz', a=array2, b=array3) result = np.load('some_array_archive.npz') # reslt\u662f\u4e00\u4e2a\u5b57\u5178\u578b\u7684\u5bf9\u8c61 print(result['b']) # \u8f7d\u5165\u5355\u4e2a\u6570\u7ec4b # [[[ 0 1 2 3 4] # [ 5 6 7 8 9]] # [[10 11 12 13 14] # [15 16 17 18 19]] # [[20 21 22 23 24] # [25 26 27 28 29]]]","title":"\u4f7f\u7528\u6570\u7ec4\u8fdb\u884c\u6587\u4ef6\u8f93\u5165\u548c\u8f93\u51fa"},{"location":"python/DataAnalysis/ch01/#_13","text":"\u53c2\u8003\u94fe\u63a5\uff1a https://www.numpy.org.cn/reference/routines/linalg.html https://github.com/teadocs/numpy-cn \u5e0c\u814a\u5b57\u6bcd: \u0391 \u03b1 /'\u00e6lf\u0259/ alpha \u0392 \u03b2 /'bi:t\u0259/ beta \u0393 \u03b3 /'g\u00e6m\u0259/ gamma \u0394 \u03b4 /'delt\u0259/ delta \u0395 \u03b5 /'eps\u026al\u0252n/ epsilon \u0396 \u03b6 /'zi:t\u0259/ zeta \u0397 \u03b7 /'i:t\u0259/ eta \u0398 \u03b8 /'\u03b8i:t\u0259/ theta \u0399 \u03b9 /'a\u026a\u0259\u028at\u0259/ iota \u039a \u03ba /'k\u00e6p\u0259/ kappa \u2227 \u03bb /'l\u00e6md\u0259/ lambda \u039c \u03bc /mju:/ mu \u039d \u03bd /nju:/ nu \u039e \u03be /ksi/ xi \u039f \u03bf /\u0259u\u02c8maikr\u0259n/ omicron \u220f \u03c0 /pa\u026a/ pi \u03a1 \u03c1 /r\u0259\u028a/ rho \u2211 \u03c3 /'s\u026a\u0261m\u0259/ sigma \u03a4 \u03c4 /t\u0254:/ tau \u03a5 \u03c5 /\u02c8ips\u026alon/ upsilon \u03a6 \u03c6 /fa\u026a/ phi \u03a7 \u03c7 /ka\u026a/ chi \u03a8 \u03c8 /psa\u026a/ psi \u03a9 \u03c9 /'\u0259\u028am\u026a\u0261\u0259/ omega numpy.linalg \u6a21\u5757\u5305\u542b\u7ebf\u6027\u4ee3\u6570\u7684\u51fd\u6570\u3002\u4f7f\u7528\u8fd9\u4e2a\u6a21\u5757\uff0c\u53ef\u4ee5\u8ba1\u7b97\u9006\u77e9\u9635\u3001\u6c42\u7279\u5f81\u503c\u3001\u89e3\u7ebf\u6027\u65b9\u7a0b\u7ec4\u4ee5\u53ca\u6c42\u89e3\u884c\u5217\u5f0f\u7b49\u3002 import numpy as np from numpy import linalg as LA from numpy import * from numpy.linalg import inv import matplotlib.pyplot as plt","title":"\u7ebf\u6027\u4ee3\u6570"},{"location":"python/DataAnalysis/ch01/#diag","text":"np.diag \u5c06\u4e00\u4e2a\u65b9\u9635\u7684\u5bf9\u89d2\uff08\u6216\u975e\u5bf9\u89d2\uff09\u5143\u7d20\u4f5c\u4e3a\u4e00\u7ef4\u6570\u7ec4\u8fd4\u56de\uff0c\u6216\u8005\u5c06\u4e00\u7ef4\u6570\u7ec4\u8f6c\u6362\u6210\u4e00\u4e2a\u65b9\u9635\uff0c\u5e76\u4e14\u5728\u975e\u5bf9\u89d2\u7ebf\u4e0a\u6709\u96f6\u70b9\u3002 a1 = np.arange(9, dtype=float).reshape((3, 3)) r1 = np.diag(a1) r2 = np.diag(a1, k=1) r3 = np.diag(a1, k=-1) r4 = np.diag(np.diag(a1)) # \u5bf9\u89d2\u77e9\u9635 print(\"\u6837\u672c\u77e9\u9635 \\n\", a1) print(\"\u77e9\u9635\u5bf9\u89d2\u7ebf\", r1) print(\"\u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0a\u504f\u79fb\", r2) print(\"\u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0b\u504f\u79fb\", r3) print(\"\u5bf9\u89d2\u77e9\u9635 \\n\", r4) # \u6837\u672c\u77e9\u9635 # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]] # \u77e9\u9635\u5bf9\u89d2\u7ebf [0. 4. 8.] # \u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0a\u504f\u79fb [1. 5.] # \u77e9\u9635\u5bf9\u89d2\u7ebf\u5411\u4e0b\u504f\u79fb [3. 7.] # \u5bf9\u89d2\u77e9\u9635 # [[0. 0. 0.] # [0. 4. 0.] # [0. 0. 8.]]","title":"diag"},{"location":"python/DataAnalysis/ch01/#dot","text":"np.dot \u5c06\u5411\u91cf\u4e2d\u5bf9\u5e94\u5143\u7d20\u76f8\u4e58\uff0c\u518d\u76f8\u52a0\u6240\u5f97\u3002\u5373\u666e\u901a\u7684\u5411\u91cf\u4e58\u6cd5\u8fd0\u7b97\uff0c\u6216**\u77e9\u9635\u70b9\u4e58**\u3002 a1 = np.dot(3, 4) print(a1) # 12 a2 = np.arange(9, dtype=float).reshape((3, 3)) r2 = np.dot(a2, a2) print(a2) # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]] print(r2) # [[ 15. 18. 21.] # [ 42. 54. 66.] # [ 69. 90. 111.]] r3 = np.dot([2j, 3j], [2j, 3j]) print(r3) # (-13+0j)","title":"dot"},{"location":"python/DataAnalysis/ch01/#trace","text":"np.trace \u8ba1\u7b97\u5bf9\u89d2\u5143\u7d20\u548c\u3002 a1 = np.arange(9, dtype=float).reshape((3, 3)) print(\"\u6837\u672c\u77e9\u9635 \\n\", a1) r1 = np.trace(a1) print(\"\u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c\", r1) a2 = np.arange(24, dtype=float).reshape((2, 3, 4)) r2 = np.trace(a2) print(\"\u6837\u672c\u77e9\u9635 \\n\", a2) print(\"\u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c\", r2) # \u6837\u672c\u77e9\u9635 # [[0. 1. 2.] # [3. 4. 5.] # [6. 7. 8.]] # \u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c 12.0 # \u6837\u672c\u77e9\u9635 # [[[ 0. 1. 2. 3.] # [ 4. 5. 6. 7.] # [ 8. 9. 10. 11.]] # # [[12. 13. 14. 15.] # [16. 17. 18. 19.] # [20. 21. 22. 23.]]] # \u5bf9\u89d2\u7ebf\u5143\u7d20\u6c42\u548c [16. 18. 20. 22.]","title":"trace"},{"location":"python/DataAnalysis/ch01/#det","text":"np.det \u8ba1\u7b97\u77e9\u9635\u7684\u884c\u5217\u5f0f\uff08\u65b9\u9635\uff09\u3002 \u4e8c\u9636\u884c\u5217\u5f0f[[a, b], [c, d]]\u7684\u503c\u662fad - bc \u4e09\u9636\u884c\u5217\u5f0f [[a, b, c], [d, e, f], [g, h, i]]\u7684\u503c\u662f aei + bfd + cdh - ceg - bdi - afh \u4e09\u9636\u884c\u5217\u5f0f\u7684\u6027\u8d28 \u6027\u8d281\uff1a\u884c\u5217\u5f0f\u4e0e\u5b83\u7684\u8f6c\u7f6e\u884c\u5217\u5f0f\u76f8\u7b49\u3002 \u6027\u8d282\uff1a\u4e92\u6362\u884c\u5217\u5f0f\u7684\u4e24\u884c(\u5217)\uff0c\u884c\u5217\u5f0f\u53d8\u53f7\u3002 \u63a8\u8bba\uff1a\u5982\u679c\u884c\u5217\u5f0f\u6709\u4e24\u884c(\u5217)\u5b8c\u5168\u76f8\u540c\uff0c\u5219\u6b64\u884c\u5217\u5f0f\u4e3a\u96f6\u3002 \u6027\u8d283\uff1a\u884c\u5217\u5f0f\u7684\u67d0\u4e00\u884c(\u5217)\u4e2d\u6240\u6709\u7684\u5143\u7d20\u90fd\u4e58\u4ee5\u540c\u4e00\u6570k\uff0c\u7b49\u4e8e\u7528\u6570k\u4e58\u6b64\u884c\u5217\u5f0f\u3002 \u63a8\u8bba\uff1a\u884c\u5217\u5f0f\u4e2d\u67d0\u4e00\u884c(\u5217)\u7684\u6240\u6709\u5143\u7d20\u7684\u516c\u56e0\u5b50\u53ef\u4ee5\u63d0\u5230\u884c\u5217\u5f0f\u7b26\u53f7\u7684\u5916\u9762\u3002 \u6027\u8d284\uff1a\u884c\u5217\u5f0f\u4e2d\u5982\u679c\u6709\u4e24\u884c(\u5217)\u5143\u7d20\u6210\u6bd4\u4f8b\uff0c\u5219\u6b64\u884c\u5217\u5f0f\u7b49\u4e8e\u96f6\u3002 \u6027\u8d285\uff1a\u628a\u884c\u5217\u5f0f\u7684\u67d0\u4e00\u5217(\u884c)\u7684\u5404\u5143\u7d20\u4e58\u4ee5\u540c\u4e00\u6570\u7136\u540e\u52a0\u5230\u53e6\u4e00\u5217(\u884c)\u5bf9\u5e94\u7684\u5143\u7d20\u4e0a\u53bb\uff0c\u884c\u5217\u5f0f\u4e0d\u53d8\u3002 a1 = np.array([[1, 2], [3, 4]]) r1 = np.linalg.det(a1) print(\"\u4e8c\u9636\u65b9\u9635 \\n\", a1) print(\"\u4e8c\u9636\u884c\u5217\u5f0f\u7684\u503c\", r1) # \u4e8c\u9636\u65b9\u9635 # [[1 2] # [3 4]] # \u4e8c\u9636\u884c\u5217\u5f0f\u7684\u503c -2.0000000000000004 # \u5e0c\u814a\u5b57\u6bcd # \u03b1, \u03b2, \u03b3,\u03b4, \u03b5, \u03b6, \u03b7, \u03b8, \u03b9, \u03ba, \u03bb, \u03bc, \u03bd, # \u03be, \u03bf, \u03c0, \u03c1, \u03c2, \u03c3, \u03c4, \u03c5, \u03c6, \u03c7, \u03c8, \u03c9, a2 = np.arange(9).reshape(3, 3) r2 = np.linalg.det(a2) print(\"\u4e09\u9636\u65b9\u9635 \\n\", a2) print(\"\u4e09\u9636\u884c\u5217\u5f0f\u7684\u503c\", r2) # \u4e09\u9636\u65b9\u9635 # [[0 1 2] # [3 4 5] # [6 7 8]] # \u4e09\u9636\u884c\u5217\u5f0f\u7684\u503c 0.0 a3 = np.arange(16).reshape(4, 4) r3 = np.linalg.det(a3) print(\"\u56db\u9636\u65b9\u9635 \\n\", a3) print(\"\u56db\u9636\u884c\u5217\u5f0f\u7684\u503c\", r3) # \u56db\u9636\u65b9\u9635 # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]# \u5e0c\u814a\u5b57\u6bcd # \u03b1, \u03b2, \u03b3,\u03b4, \u03b5, \u03b6, \u03b7, \u03b8, \u03b9, \u03ba, \u03bb, \u03bc, \u03bd, # \u03be, \u03bf, \u03c0, \u03c1, \u03c2, \u03c3, \u03c4, \u03c5, \u03c6, \u03c7, \u03c8, \u03c9, # [12 13 14 15]] # \u56db\u9636\u884c\u5217\u5f0f\u7684\u503c 0.0","title":"det"},{"location":"python/DataAnalysis/ch01/#eig","text":"np.eig \u8ba1\u7b97\u65b9\u9635\u7684\u7279\u5f81\u503c\u548c\u7279\u5f81\u5411\u91cf\u3002 \u7279\u5f81\u503c\u4e0e\u7279\u5f81\u5411\u91cf\u7684\u5b9a\u4e49\uff1a\u8bbeA\u662fn\u9636\u65b9\u9635\uff0c\u82e5\u6570\u03bb\u548cn\u7ef4\u975e\u96f6\u5217\u5411\u91cfx\uff0c\u4f7f\u5f97Ax = \u03bbx\u6210\u7acb\uff0c\u5219\u79f0\u03bb\u662f\u65b9\u9635A\u7684\u4e00\u4e2a\u7279\u5f81\u503c\uff0cx\u4e3a\u65b9\u9635A\u7684\u5bf9\u5e94\u4e8e\u7279\u5f81\u503c\u03bb\u7684\u4e00\u4e2a\u7279\u5f81\u5411\u91cf\u3002 A\u662f\u65b9\u9635\u3002\uff08\u5bf9\u4e8e\u975e\u65b9\u9635\uff0c\u662f\u6ca1\u6709\u7279\u5f81\u503c\u7684\uff0c\u4f46\u4f1a\u6709\u6761\u4ef6\u6570\u3002\uff09\u7279\u5f81\u5411\u91cfx\u4e3a\u975e\u96f6\u5217\u5411\u91cf\u3002 v_eigenvectors, v_eigenvalues = LA.eig(np.diag((1, 2, 3))) print(\"\u7279\u5f81\u5411\u91cf\", v_eigenvectors) print(\"\u7279\u5f81\u503c \\n\", v_eigenvalues) # \u7279\u5f81\u5411\u91cf [1. 2. 3.] # \u7279\u5f81\u503c # [[1. 0. 0.] # [0. 1. 0.] # [0. 0. 1.]] v_eigenvectors, v_eigenvalues = LA.eig(np.array([[1, -1], [1, 1]])) print(\"\u7279\u5f81\u5411\u91cf\", v_eigenvectors) print(\"\u7279\u5f81\u503c \\n\", v_eigenvalues) # \u7279\u5f81\u5411\u91cf [1.+1.j 1.-1.j] # \u7279\u5f81\u503c # [[0.70710678+0.j 0.70710678-0.j ] # [0. -0.70710678j 0. +0.70710678j]]","title":"eig"},{"location":"python/DataAnalysis/ch01/#inv","text":"np.inv \u8ba1\u7b97\u65b9\u9635\u7684\u9006\u77e9\u9635\u3002 a1 = np.array([[1, 2], [3, 4]]) r1 = inv(a1) r2 = inv(np.matrix(a1)) print(\"\u539f\u77e9\u9635 \\n\", a1) print(\"\u9006\u77e9\u9635 \\n\", r1) print(\"\u9006\u77e9\u9635 \\n\", r2) # \u539f\u77e9\u9635 # [[1 2] # [3 4]] # \u9006\u77e9\u9635 # [[-2. 1. ] # [ 1.5 -0.5]] # \u9006\u77e9\u9635 # [[-2. 1. ] # [ 1.5 -0.5]]","title":"inv"},{"location":"python/DataAnalysis/ch01/#pinv","text":"np.pinv \u8ba1\u7b97\u77e9\u9635\u7684Moore-Penrose\u4f2a\u9006(\u6469\u5c14\uff0d\u5f6d\u82e5\u65af\u5e7f\u4e49\u9006)\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u68c0\u9a8c a * a+ * a == a \u548c a+ * a * a+ == a+ a = np.random.randn(9, 6) B = np.linalg.pinv(a) r1 = np.allclose(a, np.dot(a, np.dot(B, a))) r2 = np.allclose(B, np.dot(B, np.dot(a, B))) print(a) print(B) print(r1) # True print(r2) # True # a: # [[-2.30316101 -0.63217332 1.24134743 -0.72492307 0.12456801 -0.14192548] # [ 1.37573495 0.07626697 -0.71870843 1.26824984 -0.79485727 -0.24630455] # [ 0.29003175 -1.23931665 -0.50864107 -0.31140718 0.45467649 -2.44973999] # [-0.70748664 -1.2995059 0.85126149 -1.10918804 -2.10042342 0.75942293] # [ 1.91765238 1.23892103 1.58516486 -1.65520154 0.11894439 0.84536298] # [ 1.03220791 0.1715148 0.85595408 0.58569706 1.34066384 -1.5782386 ] # [-0.54432889 -0.0114189 1.55403934 0.89852512 1.15586365 -0.30733805] # [-0.80874673 0.14602121 1.04680044 1.98722514 0.39766383 0.75178788] # [ 0.01664663 0.06243353 -0.50725334 -0.37707204 -1.76701091 -0.33866559]] # B: # [[-0.25055838 0.13963115 0.08990923 0.16280282 0.12997291 0.05088469 -0.01541299 -0.01656133 -0.21731387] # [ 0.22862622 -0.05108109 -0.2639602 -0.47835978 0.11776862 0.09324694 0.00436756 -0.00609393 0.61995597] # [ 0.10422554 0.03985857 0.00198025 0.15139023 0.17165026 0.15697725 0.17360246 0.13150089 0.08378135] # [-0.07021378 0.17665487 -0.04109252 0.0015022 -0.11998477 0.0543575 0.08649033 0.21190785 0.04065729] # [-0.08110336 -0.15274536 0.05601496 -0.07967802 -0.02454705 -0.04152356 0.00071268 -0.05981012 -0.43996066] # [-0.17998537 -0.03160871 -0.12587707 0.16856246 0.00565094 -0.21038026 -0.06060039 0.04322126 -0.42038066]]","title":"pinv"},{"location":"python/DataAnalysis/ch01/#qr","text":"np.qr \u8ba1\u7b97QR\u5206\u89e3\u3002QR\uff08\u6b63\u4ea4\u4e09\u89d2\uff09\u5206\u89e3\u6cd5\u662f\u6c42\u4e00\u822c\u77e9\u9635\u5168\u90e8\u7279\u5f81\u503c\u7684\u6700\u6709\u6548\u5e76\u5e7f\u6cdb\u5e94\u7528\u7684\u65b9\u6cd5\u3002 \u4e00\u822c\u77e9\u9635\u5148\u7ecf\u8fc7\u6b63\u4ea4\u76f8\u4f3c\u53d8\u5316\u6210\u4e3aHessenberg\u77e9\u9635\uff0c\u7136\u540e\u518d\u5e94\u7528QR\u65b9\u6cd5\u6c42\u7279\u5f81\u503c\u548c\u7279\u5f81\u5411\u91cf\u3002QR\u5206\u89e3\u6cd5\u662f\u5c06\u77e9\u9635\u5206\u89e3\u6210\u4e00\u4e2a\u6b63\u89c4\u6b63\u4ea4\u77e9\u9635Q\u4e0e\u4e0a\u4e09\u89d2\u5f62\u77e9\u9635R\uff0c\u6240\u4ee5\u79f0\u4e3aQR\u5206\u89e3\u6cd5\u3002 a = np.arange(9).reshape(3, 3) q, r = np.linalg.qr(a) print(\"\u539f\u77e9\u9635 \\n\", a) print(\"\u6b63\u4ea4\u77e9\u9635 \\n\", q) print(\"\u4e0a\u4e09\u89d2\u77e9\u9635 \\n\", r) # \u539f\u77e9\u9635 # [[0 1 2] # [3 4 5] # [6 7 8]] # \u6b63\u4ea4\u77e9\u9635 # [[ 0. 0.91287093 0.40824829] # [-0.4472136 0.36514837 -0.81649658] # [-0.89442719 -0.18257419 0.40824829]] # \u4e0a\u4e09\u89d2\u77e9\u9635 # [[-6.70820393e+00 -8.04984472e+00 -9.39148551e+00] # [ 0.00000000e+00 1.09544512e+00 2.19089023e+00] # [ 0.00000000e+00 0.00000000e+00 -8.88178420e-16]]","title":"qr"},{"location":"python/DataAnalysis/ch01/#svd","text":"np.svd \u8ba1\u7b97\u5947\u5f02\u503c\u5206\u89e3\uff08SVD\uff09\u3002 \u51e0\u4f55\u610f\u4e49\uff1aSVD\u5206\u89e3\u7684\u51e0\u4f55\u610f\u4e49\u662f\u4efb\u4f55\u4e00\u4e2a\u77e9\u9635A\u5728\u4e00\u7cfb\u5217\u65cb\u8f6c\u548c\u5e73\u79fb\u4e0b\u90fd\u80fd\u8f6c\u5316\u6210\u4e00\u4e2a\u5bf9\u89d2\u77e9\u9635\u2211 , \u5176\u4e2d\u9149\u9635U, V\u7684\u51e0\u4f55\u610f\u4e49\u5c31\u662f\u4e00\u7cfb\u5217\u65cb\u8f6c\u548c\u5e73\u79fb\u7684\u53e0\u52a0\u3002 a = mat([[1, 2, 3],[4, 5, 6]]) U, sigma, V = np.linalg.svd(a) print(\"\u539f\u77e9\u9635 \\n\", a) print(\"\u5de6\u5947\u5f02\u503cU \\n\", U) print(\"\u5947\u5f02\u503cSigma \\n\", sigma) print(\"\u53f3\u5947\u5f02\u503cV \\n\", V) # \u539f\u77e9\u9635 # [[1 2 3] # [4 5 6]] # \u5de6\u5947\u5f02\u503cU # [[-0.3863177 -0.92236578] # [-0.92236578 0.3863177 ]] # \u5947\u5f02\u503cSigma # [9.508032 0.77286964] # \u53f3\u5947\u5f02\u503cV # [[-0.42866713 -0.56630692 -0.7039467 ] # [ 0.80596391 0.11238241 -0.58119908] # [ 0.40824829 -0.81649658 0.40824829]]","title":"svd"},{"location":"python/DataAnalysis/ch01/#solve","text":"np.solve \u6c42\u89e3x\u7684\u7ebf\u6027\u7cfb\u7edfAx = b\uff0c\u5176\u4e2dA\u662f\u65b9\u9635\u3002 \u89e3\u65b9\u7a0b\u7ec4\uff1a x + 2y = 1 3x + 5y = 2 a = np.array([[1, 2], [3, 5]]) b = np.array([1, 2]) x = np.linalg.solve(a, b) print(x) # [-1. 1.]","title":"solve"},{"location":"python/DataAnalysis/ch01/#lstsq","text":"np.lstsq \u8ba1\u7b97Ax = b\u7684\u6700\u5c0f\u4e8c\u4e58\u89e3\u3002 \u7528\u6700\u5c0f\u4e8c\u4e58\u6cd5\u62df\u5408\u6570\u636e\u5f97\u5230\u4e00\u4e2a\u5f62\u5982y = mx + c\u7684\u7ebf\u6027\u65b9\u7a0b\uff08Return the least-squares solution to a linear matrix equation\uff09\u3002 x = np.array([0, 1, 2, 3]) # \u539f\u59cb\u6570\u636e\u70b9\u7684\u6a2a\u5750\u6807 y = np.array([-1, 0.2, 0.9, 2.1]) # \u539f\u59cb\u6570\u636e\u70b9\u7684\u7eb5\u5750\u6807 print(x) # [0 1 2 3] print(y) # [-1. 0.2 0.9 2.1] A = np.vstack([x, np.ones(len(x))]).T # \u6784\u9020\u7cfb\u6570\u77e9\u9635 print(A) # [[0. 1.] # [1. 1.] # [2. 1.] # [3. 1.]] m, c = np.linalg.lstsq(A, y, rcond=None)[0] # \u89e3\u51fa\u659c\u7387a\u548c\u7eb5\u622a\u8dddc plt.plot(x, y, 'o', label='Original data', markersize=10) # \u505a\u51fa\u539f\u59cb\u6570\u636e\u6563\u70b9\u56fe plt.plot(x, m*x + c, 'r', label='Fitted line') # \u7528\u4e0a\u9762\u89e3\u51fa\u7684\u53c2\u6570\u505a\u51fa\u62df\u5408\u66f2\u7ebfy=mx+c plt.legend() plt.show()","title":"lstsq"},{"location":"python/DataAnalysis/ch01/#_14","text":"numpy.random \u6a21\u5757\u586b\u8865\u4e86Python\u5185\u5efa\u7684 random \u6a21\u5757\u7684\u4e0d\u8db3\uff0c\u53ef\u4ee5\u9ad8\u6548\u5730\u751f\u6210\u591a\u79cd\u6982\u7387\u5206\u5e03\u4e0b\u7684\u5b8c\u6574\u6837\u672c\u503c\u6570\u7ec4\u3002 numpy.random \u4e2d\u7684\u6570\u636e\u751f\u6210\u51fd\u6570\u516c\u7528\u4e86\u4e00\u4e2a\u5168\u5c40\u7684\u968f\u673a\u6570\u79cd\u5b50\u3002 \u4f7f\u7528 numpy.random.RandomState \u751f\u6210\u4e00\u4e2a\u968f\u673a\u6570\u751f\u6210\u5668\uff0c\u4f7f\u6570\u636e\u72ec\u7acb\u4e8e\u5176\u4ed6\u7684\u968f\u673a\u6570\u72b6\u6001\u3002 \u901a\u8fc7 np.random.seed \u66f4\u6539NumPy\u7684\u968f\u673a\u6570\u79cd\u5b50\u3002 numpy.random \u4e2d\u7684\u90e8\u5206\u51fd\u6570\u5217\u8868 seed: \u5411\u968f\u673a\u6570\u751f\u6210\u5668\u4f20\u9012\u968f\u673a\u72b6\u6001\u79cd\u5b50 permutation: \u8fd4\u56de\u4e00\u4e2a\u5e8f\u5217\u7684\u968f\u673a\u6392\u5217\uff0c\u6216\u8005\u8fd4\u56de\u4e00\u4e2a\u4e71\u5e8f\u7684\u6574\u6570\u8303\u56f4\u5e8f\u5217 shuffle: \u968f\u673a\u6392\u5217\u4e00\u4e2a\u5e8f\u5217 rand: \u4ece\u5747\u5300\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c randint: \u6839\u636e\u7ed9\u5b9a\u7684\u7531\u4f4e\u5230\u9ad8\u7684\u8303\u56f4\u62bd\u53d6\u968f\u673a\u6574\u6570 randn: \u4ece\u5747\u503c0\u65b9\u5dee1\u7684\u6b63\u6001\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c(MATLAB\u578b\u63a5\u53e3\uff09 binomial: \u4ece\u4e8c\u9879\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c normal: \u4ece\u6b63\u6001\uff08\u9ad8\u65af\uff09\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c beta\u4ecebeta: \u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c chisquare: \u4ece\u5361\u65b9\u5206\u5e03\u4e2d\u62bd\u53d6\u6837\u672c \u4f8b\u5982\uff0c\u4f7f\u7528normal\u6765\u83b7\u5f97\u4e00\u4e2a4\u00d74\u7684\u6b63\u6001\u5206\u5e03\u6837\u672c\u6570\u7ec4\uff0c\u79f0\u4e3a\u4f2a\u968f\u673a\u6570\u3002 import numpy as np samples = np.random.normal(size=(4, 4)) print(samples) # [[ 0.78583658 -0.27462104 -0.53027675 -0.62675004] # [ 0.39054781 1.20503691 -0.0057432 0.17243182] # [-0.41516669 -0.93335854 0.01996088 -0.12707275] # [ 0.42952379 2.56998319 0.14848737 -0.42871493]]","title":"\u4f2a\u968f\u673a\u6570\u751f\u6210"},{"location":"python/DataAnalysis/ch01/#_15","text":"import matplotlib.pyplot as plt import numpy as np position = 0 walk = [position] nwalks = 5000 nsteps = 1000 draws = np.random.randint(0, 2, size=(nwalks, nsteps)) steps = np.where(draws > 0, 1, -1) walks = steps.cumsum() plt.plot(walks[:500000000000000000000000000]) plt.show() \u8f93\u51fa\u56fe\u50cf\uff1a","title":"\u793a\u4f8b\uff1a\u968f\u673a\u6f2b\u6b65"},{"location":"python/DataAnalysis/ch02/","text":"Pandas\u5165\u95e8 \u00b6 \u7ea6\u5b9a\uff1a import numpy as np import pandas as pd from pandas import Series, DataFrame import pandas_datareader as web pandas\u6570\u636e\u7ed3\u6784\u4ecb\u7ecd \u00b6 Series \u00b6 Series\u662f\u4e00\u79cd\u4e00\u7ef4\u7684\u6570\u7ec4\u578b\u5bf9\u8c61\uff0c\u5b83\u5305\u542b\u4e86\u4e00\u4e2a\u503c\u5e8f\u5217\uff08\u4e0eNumPy\u4e2d\u7684\u7c7b\u578b\u76f8\u4f3c\uff09\uff0c\u5e76\u4e14\u5305\u542b\u4e86\u6570\u636e\u6807\u7b7e\uff0c\u79f0\u4e3a**\u7d22\u5f15\uff08index\uff09 \u3002 \u4ece\u53e6\u4e00\u4e2a\u89d2\u5ea6\u8003\u8651Series\uff0c\u53ef\u4ee5\u8ba4\u4e3a\u5b83\u662f\u4e00\u4e2a**\u957f\u5ea6\u56fa\u5b9a\u4e14\u6709\u5e8f\u7684\u5b57\u5178 \uff0c\u56e0\u4e3a\u5b83\u5c06\u7d22\u5f15\u503c\u548c\u6570\u636e\u503c\u6309\u4f4d\u7f6e\u914d\u5bf9\u3002\u7d22\u5f15\u5728\u5de6\u8fb9\uff0c\u503c\u5728\u53f3\u8fb9\u3002 obj = pd.Series([4, 7, -5, 3]) print(obj) # 0 4 # 1 7 # 2 -5 # 3 3 # dtype: int64 print(obj.values) # [ 4 7 -5 3 print(obj.index) # RangeIndex(start=0, stop=4, step=1) \u81ea\u5b9a\u4e49index obj = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c']) print(obj) # d 4 # b 7 # a -5 # c 3 # dtype: int64 print(obj.values) # [ 4 7 -5 3] print(obj.index) # Index(['d', 'b', 'a', 'c'], dtype='object') # \u8f93\u51fa\u7d22\u5f15\u503c\u4e3a'a'\u7684Series\u503c print(obj['a']) # -5 # \u4f7f\u7528\u5e03\u5c14\u503c\u6570\u7ec4\u8fdb\u884c\u8fc7\u6ee4Series\u503c print(obj[obj > 3]) # d 4 # b 7 # dtype: int64 # \u5bf9Series\u503c\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97 print(obj * 2) # d 8 # b 14 # a -10 # c 6 # dtype: int64 # \u5bf9Series\u503c\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97 print(np.exp(obj)) # d 54.598150 # b 1096.633158 # a 0.006738 # c 20.085537 # dtype: float64 # \u66f4\u65b0Series\u6570\u7ec4\u503c obj['a'] = 9 # \u8f93\u51fa\u6307\u5b9a\u7d22\u5f15\u503c\u7684Series\u503c\uff0c\u6ce8\u610f\uff0c\u7d22\u5f15\u6761\u4ef6\u662f\u5217\u8868 print(obj[['a', 'b', 'c']]) # a 9 # b 7 # c 3 # dtype: int64 # \u6ce8\u610f\uff0c\u4e0b\u9762\u7684\u5224\u65ad\u662f\u7d22\u5f15\u503c\uff0c\u975eSeries\u503c print(obj) print(7 in obj) # False print('a' in obj) # True \u901a\u8fc7\u5b57\u5178\u751f\u6210\u4e00\u4e2aSeries\u3002 NaN \uff08not a number\uff09\uff0c\u8fd9\u662fpandas\u4e2d\u6807\u8bb0\u7f3a\u5931\u503c\u6216NA\u503c\u7684\u65b9\u5f0f\u3002 \u5f53\u628a\u5b57\u5178\u4f20\u9012\u7ed9Series\u6784\u9020\u51fd\u6570\u65f6\uff0c\u4ea7\u751f\u7684Series\u7684\u7d22\u5f15\u5c06\u662f\u6392\u5e8f\u597d\u7684\u5b57\u5178\u952e\u3002\u53ef\u4ee5\u5c06\u5b57\u5178\u952e\u6309\u7167\u4f60\u6240\u60f3\u8981\u7684\u987a\u5e8f\u4f20\u9012\u7ed9\u6784\u9020\u51fd\u6570\uff0c\u4ece\u800c\u4f7f\u751f\u6210\u7684Series\u7684\u7d22\u5f15\u987a\u5e8f\u7b26\u5408\u9884\u671f\u3002 \u770b\u4e0b\u4f8b\uff0c\u901a\u8fc7\u5b57\u5178sdata\u751f\u6210Series\u3002 sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000} obj3 = pd.Series(sdata) print(sdata) # {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000} print(obj3) # Ohio 35000 # Texas 71000 # Oregon 16000 # Utah 5000 # dtype: int64 \u901a\u8fc7\u6307\u5b9a\u7d22\u5f15states\u53bb\u5339\u914d\u5b57\u5178sdata\u751f\u6210\u57fa\u4e8e\u65b0\u7d22\u5f15states\u7684Series\u3002 states = ['California', 'Ohio', 'Oregon', 'Texas'] obj4 = pd.Series(sdata, index=states) print(obj4) # California NaN # Ohio 35000.0 # Oregon 16000.0 # Texas 71000.0 # dtype: float64 \u5bf9Series\u8fdb\u884c\u5e03\u5c14\u503c\u5224\u65ad\u3002 print(pd.isnull(obj4)) # California True # Ohio False # Oregon False # Texas False # dtype: bool print(pd.notnull(obj4)) # California False # Ohio True # Oregon True # Texas True # dtype: bool \u5bf9Series\u8fdb\u884c\u5e03\u5c14\u503c\u5224\u65ad\u3002 print(obj4.isnull) # print(obj4.notnull) # Series\u7684\u81ea\u52a8\u5bf9\u9f50\u7d22\u5f15\uff0c\u4e0e\u6570\u636e\u5e93\u7684join\u64cd\u4f5c\u662f\u975e\u5e38\u76f8\u4f3c\u3002 print(\"obj3 \\n\", obj3) # obj3 # Ohio 35000 # Texas 71000 # Oregon 16000 # Utah 5000 # dtype: int64 print(\"obj4 \\n\", obj4) # obj4 # California NaN # Ohio 35000.0 # Oregon 16000.0 # Texas 71000.0 # dtype: float64 print(\"obj3+obj4 \\n\", obj3 + obj4) # obj3+obj4 # California NaN # Ohio 70000.0 # Oregon 32000.0 # Texas 142000.0 # Utah NaN # dtype: float64 # \u4e0b\u9762\u662fobj3\u548cobj4\u7684\u503c\uff0c\u5e2e\u52a9\u7406\u89e3\u4e0a\u9762obj3 + obj4\u7684\u64cd\u4f5c\u3002 # obj3 obj4 # Ohio 35000 California NaN # Texas 71000 Ohio 35000.0 # Oregon 16000 Oregon 16000.0 # Utah 5000 Texas 71000.0 # dtype: int64 dtype: float64 Series\u5bf9\u8c61\u81ea\u8eab\u548c\u5176\u7d22\u5f15\u90fd\u6709name\u5c5e\u6027\u3002 obj4.name = 'population' obj4.index.name = 'state' print(obj4) # state # California NaN # Ohio 35000.0 # Oregon 16000.0 # Texas 71000.0 # Name: population, dtype: float64 \u66ff\u6362Series\u7684\u7d22\u5f15\u540d\u3002 obj = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c']) print(obj) obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan'] print(obj) # Bob 4 # Steve 7 # Jeff -5 # Ryan 3 # dtype: int64 DataFrame \u00b6 DataFrame\u8868\u793a\u7684\u662f\u77e9\u9635\u7684\u6570\u636e\u8868\uff0c\u5b83\u5305\u542b\u5df2\u6392\u5e8f\u7684\u5217\u96c6\u5408\uff0c\u6bcf\u4e00\u5217\u53ef\u4ee5\u662f\u4e0d\u540c\u7684\u503c\u7c7b\u578b\uff08\u6570\u503c\u3001\u5b57\u7b26\u4e32\u3001\u5e03\u5c14\u503c\u7b49\uff09\u3002 DataFrame\u65e2\u6709\u884c\u7d22\u5f15\u4e5f\u6709\u5217\u7d22\u5f15\uff0c\u5b83\u53ef\u4ee5\u88ab\u89c6\u4e3a\u4e00\u4e2a\u5171\u4eab\u76f8\u540c\u7d22\u5f15\u7684Series\u7684\u5b57\u5178\uff0c\u6bd4\u5982\u6240\u6709\u5217\u5171\u4eab\u540c\u4e00\u4e2a\u5217\u7d22\u5f15\u3002 \u5728DataFrame\u4e2d\uff0c\u6570\u636e\u88ab\u5b58\u50a8\u4e3a\u4e00\u4e2a\u4ee5\u4e0a\u7684\u4e8c\u7ef4\u5757\uff0c\u800c\u4e0d\u662f\u5217\u8868\u3001\u5b57\u5178\u6216\u5176\u4ed6\u4e00\u7ef4\u6570\u7ec4\u7684\u96c6\u5408\u3002 DataFrame\u662f\u4e8c\u7ef4\u7684\uff0c\u4f46\u53ef\u4ee5\u5229\u7528**\u5206\u5c42\u7d22\u5f15**\u5728DataFrame\u4e2d\u5c55\u73b0\u66f4\u9ad8\u7ef4\u5ea6\u7684\u6570\u636e\u3002 \u4eceDataFrame\u4e2d\u9009\u53d6\u7684\u5217\u662f\u6570\u636e\u7684\u89c6\u56fe\uff0c\u800c\u4e0d\u662f\u62f7\u8d1d \u3002\u56e0\u6b64\uff0c\u5bf9Series\u7684\u4fee\u6539\u4f1a\u6620\u5c04\u5230DataFrame\u4e2d\u3002\u5982\u679c\u9700\u8981\u590d\u5236\uff0c\u5219\u5e94\u5f53\u663e\u5f0f\u5730\u4f7f\u7528Series\u7684copy\u65b9\u6cd5\u3002 \u7531\u5b57\u5178\u6784\u6210DataFrame \u00b6 \u57fa\u4e8e\u5b57\u5178 data \u4ea7\u751f\u7684DataFrame\u4f1a\u81ea\u52a8\u4e3aSereies\u5206\u914d\u7d22\u5f15\uff0c\u5e76\u4e14\u5217\u4f1a\u6309\u7167\u6392\u5e8f\u7684\u987a\u5e8f\u6392\u5217\u3002 data = { 'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], 'year': [2000, 2001, 2002, 2001, 2002, 2003], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2] } frame = pd.DataFrame(data) print(frame) # state year pop # 0 Ohio 2000 1.5 # 1 Ohio 2001 1.7 # 2 Ohio 2002 3.6 # 3 Nevada 2001 2.4 # 4 Nevada 2002 2.9 # 5 Nevada 2003 3.2 # \u5bf9\u4e8e\u5927\u578bDataFrame, head\u65b9\u6cd5\u5c06\u4f1a\u53ea\u9009\u51fa\u5934\u90e8\u7684\u82e5\u5e72\u884c, \u9ed8\u8ba4\u662f\u524d\u4e94\u884c\u3002 print(frame.head(3)) # state year pop # 0 Ohio 2000 1.5 # 1 Ohio 2001 1.7 # 2 Ohio 2002 3.6 \u5982\u679c\u6307\u5b9a\u4e86\u5217\u7684\u987a\u5e8f\uff0cDataFrame\u7684\u5217\u5c06\u4f1a\u6309\u7167\u6307\u5b9a\u987a\u5e8f\u6392\u5217\u3002 frame = pd.DataFrame(data, columns=['year', 'state', 'pop']) print(frame) # year state pop # 0 2000 Ohio 1.5 # 1 2001 Ohio 1.7 # 2 2002 Ohio 3.6 # 3 2001 Nevada 2.4 # 4 2002 Nevada 2.9 # 5 2003 Nevada 3.2 \u5982\u679c\u4f20\u7684\u5217\uff08 debt \uff09\u4e0d\u5305\u542b\u5728\u5b57\u5178\uff08 data \uff09\u4e2d\uff0c\u5c06\u4f1a\u5728\u7ed3\u679c\u4e2d\u51fa\u73b0\u7f3a\u5931\u503c\u3002 frame2 = pd.DataFrame( data, columns=['year', 'state', 'pop', 'debt'], index=['one', 'two', 'three', 'four', 'five', 'six'] ) print(frame2) # year state pop debt # one 2000 Ohio 1.5 NaN # two 2001 Ohio 1.7 NaN # three 2002 Ohio 3.6 NaN # four 2001 Nevada 2.4 NaN # five 2002 Nevada 2.9 NaN # six 2003 Nevada 3.2 NaN \u9009\u53d6\u884c, \u53ef\u4ee5\u901a\u8fc7\u4f4d\u7f6e\u6216\u884c\u7d22\u5f15\u6807\u7b7e loc \u8fdb\u884c\u9009\u53d6\u3002 print(frame2.loc['three']) # year 2002 # state Ohio # pop 3.6 # debt NaN # Name: three, dtype: object DataFrame\u4e2d\u7684\u4e00\u5217\uff0c\u53ef\u4ee5\u6309\u5b57\u5178\u578b\u6807\u8bb0\u6216\u5c5e\u6027\u90a3\u6837\u68c0\u7d22\u4e3aSeries\u3002 frame2[colunm] \u5bf9\u4e8e\u4efb\u610f\u5217\u540d\u5747\u6709\u6548\uff0c\u4f46\u662f frame2.column \u53ea\u5728\u5217\u540d\u662f\u6709\u6548\u7684Python\u53d8\u91cf\u540d\u65f6\u6709\u6548\u3002 \u8fd4\u56de\u7684Series\u4e0e\u539fDataFrame\u6709\u76f8\u540c\u7684\u7d22\u5f15\uff0c\u4e14Series\u7684 name \u5c5e\u6027\u4e5f\u4f1a\u88ab\u5408\u7406\u5730\u8bbe\u7f6e\u3002 print(frame2['state']) # one Ohio # two Ohio # three Ohio # four Nevada # five Nevada # six Nevada # Name: state, dtype: object print(frame2.state) # \u5c5e\u6027\u578b\u8fde\u63a5 # one Ohio # two Ohio # three Ohio # four Nevada # five Nevada # six Nevada # Name: state, dtype: object \u5217\u7684\u5f15\u7528\u662f\u53ef\u4ee5\u4fee\u6539\u7684\u3002\u503c\u7684\u957f\u5ea6\u5fc5\u987b\u548cDataFrame\u7684\u957f\u5ea6\u76f8\u5339\u914d,\u6bd4\u5982\uff0c\u4e0b\u4f8b\u4e2d np.arange(6.) \u548c frame2['debt'] \u7684\u957f\u5ea6\u90fd\u662f6\u3002 frame2['debt'] = 16.5 print(frame2) # Name: state, dtype: object # year state pop debt # one 2000 Ohio 1.5 16.5 # two 2001 Ohio 1.7 16.5 # three 2002 Ohio 3.6 16.5 # four 2001 Nevada 2.4 16.5 # five 2002 Nevada 2.9 16.5 # six 2003 Nevada 3.2 16.5 frame2['debt'] = np.arange(6.) print(frame2) # year state pop debt # one 2000 Ohio 1.5 0.0 # two 2001 Ohio 1.7 1.0 # three 2002 Ohio 3.6 2.0 # four 2001 Nevada 2.4 3.0 # five 2002 Nevada 2.9 4.0 # six 2003 Nevada 3.2 5.0 \u5982\u679c\u5c06Series\u8d4b\u503c\u7ed9\u4e00\u5217\u65f6\uff0cSeries\u7684\u7d22\u5f15\u5c06\u4f1a\u6309\u7167DataFrame\u7684\u7d22\u5f15\u91cd\u65b0\u6392\u5217\uff0c\u5e76\u5728\u7a7a\u7f3a\u7684\u5730\u65b9\u586b\u5145\u7f3a\u5931\u503c val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five']) frame2['debt'] = val print(frame2) # year state pop debt # one 2000 Ohio 1.5 NaN # two 2001 Ohio 1.7 -1.2 # three 2002 Ohio 3.6 NaN # four 2001 Nevada 2.4 -1.5 # five 2002 Nevada 2.9 -1.7 # six 2003 Nevada 3.2 NaN \u5982\u679c\u88ab\u8d4b\u503c\u7684\u5217( eastern \u5217)\u5e76\u4e0d\u5b58\u5728\uff0c\u5219\u4f1a\u751f\u6210\u4e00\u4e2a\u65b0\u7684\u5217\u3002 frame2.state == 'Ohio' \u8fd4\u56de\u7684\u662f\u5e03\u5c14\u503c\uff0c\u8d4b\u503c\u7ed9 eastern \u3002 frame2['eastern'] = frame2.state == 'Ohio' print(frame2) # year state pop debt eastern # one 2000 Ohio 1.5 NaN True # two 2001 Ohio 1.7 -1.2 True # three 2002 Ohio 3.6 NaN True # four 2001 Nevada 2.4 -1.5 False # five 2002 Nevada 2.9 -1.7 False # six 2003 Nevada 3.2 NaN False print(frame2.eastern) # one True # two True # three True # four False # five False # six False # Name: eastern, dtype: bool del \u5173\u952e\u5b57\u53ef\u4ee5\u50cf\u5728\u5b57\u5178\u4e2d\u90a3\u6837\u5bf9DataFrame\u5220\u9664\u5217\u3002 del frame2['eastern'] print(frame2.columns) # Index(['year', 'state', 'pop', 'debt'], dtype='object') \u4f7f\u7528\u5d4c\u5957\u5b57\u5178\u6784\u5efaDataFrame \u00b6 pandas\u4f1a\u5c06\u5b57\u5178\u7684\u952e\u4f5c\u4e3a\u5217('Nevada', etc.)\uff0c\u5c06\u5185\u90e8\u5b57\u5178\u7684\u952e\u4f5c\u4e3a\u884c\u7d22\u5f15(2001, etc.) pop = { 'Nevada': { 2001: 2.4, 2002: 2.9 }, 'Ohio': { 2000: 1.5, 2001: 1.7, 2002: 3.6 } } # \u4e0d\u6307\u5b9a\u7d22\u5f15\uff0c\u9ed8\u8ba4\u4f7f\u7528\u5b57\u5178\u7d22\u5f15 frame3 = pd.DataFrame(pop) print(frame3) # Nevada Ohio # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 # \u6307\u5b9a\u5b57\u5178\u67d0\u5217\u4f5c\u4e3a\u7d22\u5f15 print(pd.DataFrame(pop, index=[2001, 2002, 2003])) # Nevada Ohio # 2001 2.4 1.7 # 2002 2.9 3.6 # 2003 NaN NaN # \u6307\u5b9a\u4e0d\u76f8\u5e72\u7d22\u5f15 print(pd.DataFrame(pop, index=['a', 'b', 'c'])) # Nevada Ohio # a NaN NaN # b NaN NaN # c NaN NaN \u8f6c\u7f6e\u64cd\u4f5c\uff08\u8c03\u6362\u884c\u548c\u5217\uff09 print(frame3.T) # 2001 2002 2000 # Nevada 2.4 2.9 NaN # Ohio 1.7 3.6 1.5 \u4f7f\u7528\u542bSeries\u7684\u5b57\u5178\u6784\u9020DataFrame \u00b6 frame3['Ohio'][:-1] \u662f\u503c\u4e3a Ohio \u7684Series\u76840~\u5012\u6570\u7b2c\u4e00\u4e2a\u5143\u7d20\uff08\u4e0d\u542b\uff09\uff0c\u4e00\u51713\u4e2a\u3002 frame3['Nevada'][:2] \u662f\u503c\u4e3a Nevada \u7684Series\u7684\u524d2\u4e2a\u5143\u7d20\u3002 pdata = { 'Ohio': frame3['Ohio'][:-1], 'Nevada': frame3['Nevada'][:2] } print(pd.DataFrame(pdata)) # Ohio Nevada # 2001 1.7 2.4 # 2002 3.6 2.9 \u6307\u5b9aDataframe frame3 \u7684\u5217\u540d\u3002 frame3.index.name = 'year' frame3.columns.name = 'state' print(frame3) # state Nevada Ohio # year # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 \u53ea\u8f93\u51faDataframe\u7684\u503c frame3.values \uff0c\u662f\u4e00\u4e2a\u4e8c\u7ef4\u6570\u7ec4\u3002 print(frame3.values) # [[2.4 1.7] # [2.9 3.6] # [nan 1.5]] \u53ea\u8f93\u51faDataframe\u7684\u503c frame2.values \uff0c\u662f\u4e00\u4e2a\u4e8c\u7ef4\u6570\u7ec4\u3002 print(frame2) # year state pop debt # one 2000 Ohio 1.5 NaN # two 2001 Ohio 1.7 -1.2 # three 2002 Ohio 3.6 NaN # four 2001 Nevada 2.4 -1.5 # five 2002 Nevada 2.9 -1.7 # six 2003 Nevada 3.2 NaN print(frame2.values) # [[2000 'Ohio' 1.5 nan] # [2001 'Ohio' 1.7 -1.2] # [2002 'Ohio' 3.6 nan] # [2001 'Nevada' 2.4 -1.5] # [2002 'Nevada' 2.9 -1.7] # [2003 'Nevada' 3.2 nan]] \u7d22\u5f15\u5bf9\u8c61 \u00b6 pandas\u4e2d\u7684**\u7d22\u5f15\u5bf9\u8c61**\u662f\u7528\u4e8e\u5b58\u50a8\u8f74\u6807\u7b7e\u548c\u5176\u4ed6\u5143\u6570\u636e\u7684\uff08\u4f8b\u5982\u8f74\u540d\u79f0\u6216\u6807\u7b7e\uff09\u3002 \u5728\u6784\u9020Series\u6216DataFrame\u65f6\uff0c\u4f60\u6240\u4f7f\u7528\u7684\u4efb\u610f\u6570\u7ec4\u6216\u6807\u7b7e\u5e8f\u5217\u90fd\u53ef\u4ee5\u5728\u5185\u90e8\u8f6c\u6362\u4e3a\u7d22\u5f15\u5bf9\u8c61\u3002 \u7d22\u5f15\u5bf9\u8c61\u662f\u4e0d\u53ef\u53d8\u7684\u3002 \u9664\u4e86\u7c7b\u4f3c\u6570\u7ec4\uff0c\u7d22\u5f15\u5bf9\u8c61\u4e5f\u50cf\u4e00\u4e2a\u56fa\u5b9a\u5927\u5c0f\u7684\u96c6\u5408\u3002\u4e0ePython\u96c6\u5408\u4e0d\u540c\uff0c pandas\u7d22\u5f15\u5bf9\u8c61\u53ef\u4ee5\u5305\u542b\u91cd\u590d\u6807\u7b7e \u3002 \u56e0\u4e3a\u4e00\u4e9b\u64cd\u4f5c\u4f1a\u4ea7\u751f\u5305\u542b\u7d22\u5f15\u5316\u6570\u636e\u7684\u7ed3\u679c\uff0c\u7406\u89e3\u7d22\u5f15\u5982\u4f55\u5de5\u4f5c\u8fd8\u662f\u5f88\u91cd\u8981\u7684\u3002 \u4e0b\u4f8b\u6f14\u793a\u4e86\u5982\u4f55\u8bfb\u53d6Dataframe\u7684\u7d22\u5f15\u503c\u3002 obj = pd.Series(range(3), index=['a', 'b', 'c']) index = obj.index print(obj) # a 0 # b 1 # c 2 # dtype: int64 print(index) # Index(['a', 'b', 'c'], dtype='object') print(index[1:]) # Index(['b', 'c'], dtype='object') \u4e0b\u4f8b\u6f14\u793a\u4e86\u901a\u8fc7\u4e00\u4e2a\u6307\u5b9a\u7684Dataframe\u7d22\u5f15 labels \u6765\u751f\u6210Dataframe obj2 \u3002 labels = pd.Index(np.arange(3)) print(labels) # Int64Index([0, 1, 2], dtype='int64') obj2 = pd.Series([1.5, -2.5, 0], index=labels) print(obj2) # 0 1.5 # 1 -2.5 # 2 0.0 # dtype: float64 print(obj2.index is labels) # True \u4e0b\u4f8b\u6f14\u793a\u4e86\u4e0d\u6307\u5b9a\u7d22\u5f15\uff0c\u9ed8\u8ba4\u4f7f\u7528\u5b57\u5178\u7d22\u5f15\u6765\u521b\u5efaDataframe\u3002 pop = { 'Nevada': { 2001: 2.4, 2002: 2.9 }, 'Ohio': { 2000: 1.5, 2001: 1.7, 2002: 3.6 } } frame3 = pd.DataFrame(pop) print(frame3) # Nevada Ohio # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 print(frame3) # state Nevada Ohio # year # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 print(frame3.columns) # Index(['Nevada', 'Ohio'], dtype='object', name='state') print(frame3.index) # Int64Index([2001, 2002, 2000], dtype='int64', name='year') print('Ohio' in frame3.columns) # True print(2003 in frame3.index) # False pandas\u7d22\u5f15\u5bf9\u8c61\u5141\u8bb8\u5305\u542b\u91cd\u590d\u6807\u7b7e\u3002\u6839\u636e\u91cd\u590d\u6807\u7b7e\u8fdb\u884c\u7b5b\u9009\uff0c\u4f1a\u9009\u53d6\u6240\u6709\u91cd\u590d\u6807\u7b7e\u5bf9\u5e94\u7684\u6570\u636e\u3002 dup_labels = pd.Index(['foo', 'foo', 'bar', 'bar']) print(dup_labels) # Index(['foo', 'foo', 'bar', 'bar'], dtype='object') \u4e00\u4e9b\u5e38\u7528\u7d22\u5f15\u5bf9\u8c61\u7684\u65b9\u6cd5\u548c\u5c5e\u6027\u3002 obj1 = pd.Series(range(3), index=['a', 'b', 'c']) index1 = obj1.index obj2 = pd.Series(range(3), index=['c', 'f', 'g']) index2 = obj2.index print(index1) # Index(['a', 'b', 'c'], dtype='object') print(index2) # Index(['c', 'f', 'g'], dtype='object') append \u65b9\u6cd5\uff1a\u5c06\u5916\u90e8\u7684\u7d22\u5f15\u5bf9\u8c61\u7c98\u8d34\u5230\u539f\u7d22\u5f15\u540e\uff0c\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684\u7d22\u5f15\u3002 \u63a5\u4e0a\u4f8b\uff0c\u628a index2 \u5bf9\u8c61\u8ffd\u52a0\u5230 index1 \u5bf9\u8c61\u3002 print(index1.append(index2)) # Index(['a', 'b', 'c', 'c', 'f', 'g'], dtype='object') difference \u65b9\u6cd5: \u8ba1\u7b972\u4e2a\u7d22\u5f15\u7684\u5dee\u96c6\u3002 print(index1.difference(index2)) # Index(['a', 'b'], dtype='object') intersection \u65b9\u6cd5: \u8ba1\u7b972\u4e2a\u7d22\u5f15\u7684\u4ea4\u96c6\u3002 print(index1.intersection(index2)) # Index(['c'], dtype='object') union \u65b9\u6cd5: \u8ba1\u7b972\u4e2a\u7d22\u5f15\u7684\u5e76\u96c6\uff08\u53bb\u91cd\uff09\u3002 print(index1.union(index2)) # Index(['a', 'b', 'c', 'f', 'g'], dtype='object') isin \u65b9\u6cd5: \u8ba1\u7b97\u8868\u793a\u6bcf\u4e00\u4e2a\u503c\u662f\u5426\u5728\u4f20\u503c\u5bb9\u5668\u4e2d\uff0c\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u5e03\u5c14\u6570\u7ec4\u3002 print(index1.isin(index2)) # [False False True] delete \u65b9\u6cd5: \u5c06\u4f4d\u7f6ei\uff08\u4ece0\u5f00\u59cb\u7f16\u53f7\uff09\u7684\u5143\u7d20\u5220\u9664\uff0c\u5e76\u4ea7\u751f\u65b0\u7684\u7d22\u5f15\u3002 print(index1.delete('b')) # IndexError: arrays used as indices must be of integer (or boolean) type print(index1.delete(1)) # Index(['a', 'c'], dtype='object') print(index1) # Index(['a', 'b', 'c'], dtype='object') drop \u65b9\u6cd5: \u6839\u636e\u4f20\u53c2\u5220\u9664\u6307\u5b9a\u7d22\u5f15\u503c\uff0c\u5e76\u4ea7\u751f\u65b0\u7684\u7d22\u5f15, \u5bf9\u6bd4\u548cdelete\u7684\u533a\u522b\uff0c delete \u65b9\u6cd5\u662f\u8f93\u5165\u4f4d\u7f6e\uff0c drop \u65b9\u6cd5\u662f\u8f93\u5165\u7d22\u5f15\u540d\u79f0\u3002 print(index2.drop(1)) # KeyError: '[1] not found in axis' print(index2.drop('f')) # Index(['c', 'g'], dtype='object') print(index2) # Index(['c', 'f', 'g'], dtype='object') insert \u65b9\u6cd5: \u5728\u4f4d\u7f6e i \u63d2\u5165\u5143\u7d20\uff0c\u5e76\u4ea7\u751f\u65b0\u7684\u7d22\u5f15\u3002 print(index1.insert(1, 'e')) # Index(['a', 'e', 'b', 'c'], dtype='object') print(index1) # Index(['a', 'b', 'c'], dtype='object') is_monotonic \u65b9\u6cd5: \u5982\u679c\u7d22\u5f15\u5e8f\u5217\u9012\u589e\uff0c\u5219\u8fd4\u56de True \u3002 print(index1.is_monotonic) # True print(index1.insert(1, 'e').is_monotonic) # False is_unique \u65b9\u6cd5: \u5982\u679c\u7d22\u5f15\u5e8f\u5217\u552f\u4e00\u5219\u8fd4\u56de True \u3002 print(index1.is_unique) # True print(index1.append(index2).is_unique) # False unique \u65b9\u6cd5: \u8ba1\u7b97\u7d22\u5f15\u7684\u552f\u4e00\u503c\u5e8f\u5217\uff08\u5bf9\u6bd4Union\uff09\u3002 print(index1.unique()) # Index(['a', 'b', 'c'], dtype='object') print(index1.append(index2).unique()) # Index(['a', 'b', 'c', 'f', 'g'], dtype='object') pandas\u57fa\u672c\u529f\u80fd \u00b6 \u91cd\u5efa\u7d22\u5f15 \u00b6 Series\u8c03\u7528 reindex \u65b9\u6cd5\u65f6\uff0c\u4f1a\u5c06\u6570\u636e\u6309\u7167\u65b0\u7684\u7d22\u5f15\u8fdb\u884c\u6392\u5217\uff0c\u5982\u679c\u67d0\u4e2a\u7d22\u5f15\u503c\u4e4b\u524d\u5e76\u4e0d\u5b58\u5728\uff0c\u5219\u4f1a\u5f15\u5165\u7f3a\u5931\u503c\u3002 \u4e0b\u4f8b\u4e2d\uff0c\u5bf9 obj1 \u505a reindex \uff0c reindex \u65b9\u6cd5\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7d22\u5f15\u5bf9\u8c61 obj2 \uff0c\u7d22\u5f15\u503c e \u4e4b\u524d\u5e76\u4e0d\u5b58\u5728\uff0c\u6240\u4ee5\u586b\u5165\u7f3a\u5931\u503c\u3002 \u5982\u679c\u5bf9obj1\u505a reindex \u65f6\u6307\u5b9a method='ffill' \uff0c\u4f1a\u62a5\u9519 index must be monotonic increasing or decreasing \u3002 obj1 = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c']) print(obj1) # d 4.5 # b 7.2 # a -5.3 # c 3.6 # dtype: float64 obj2 = obj1.reindex(['a', 'b', 'c', 'd', 'e']) print(obj2) # a -5.3 # b 7.2 # c 3.6 # d 4.5 # e NaN # dtype: float64 obj2 = obj1.reindex(['a', 'b', 'c', 'd', 'e'], method='ffill') # ValueError: index must be monotonic increasing or decreasing \u5bf9\u4e8e\u987a\u5e8f\u6570\u636e\uff0c\u6bd4\u5982\u65f6\u95f4\u5e8f\u5217\uff0c\u5728\u91cd\u5efa\u7d22\u5f15\u65f6\u53ef\u80fd\u4f1a\u9700\u8981\u8fdb\u884c\u63d2\u503c\u6216\u586b\u503c\u3002 ffill \u65b9\u6cd5\u5728\u91cd\u5efa\u7d22\u5f15\u65f6\u63d2\u503c\uff0c\u5c06\u503c\u524d\u5411\u586b\u5145\u3002 obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4]) print(obj3.reindex(range(6), method='ffill')) # 0 blue # 1 blue # 2 purple # 3 purple # 4 yellow # 5 yellow # dtype: object \u5728DataFrame\u4e2d\uff0c reindex \u53ef\u4ee5\u6539\u53d8\u884c\u7d22\u5f15\u3001\u5217\u7d22\u5f15\uff0c\u4e5f\u53ef\u4ee5\u540c\u65f6\u6539\u53d8\u4e8c\u8005\u3002\u5f53\u4ec5\u4f20\u5165\u4e00\u4e2a\u5e8f\u5217\u65f6\uff0c\u4f1a\u91cd\u5efa\u884c\u7d22\u5f15\u3002 \u4e0b\u4f8b\u4e2d\uff0c\u901a\u8fc7 indexes \u521b\u5efaDataframe frame \u3002 \u901a\u8fc7 frame.reindex(['a', 'b', 'c', 'd'])\u91cd\u5efa\u884c\u7d22\u5f15 \u3002 \u901a\u8fc7 frame2.reindex(columns=['Ohio', 'Uta', 'California']) \u91cd\u5efa\u5217\u7d22\u5f15\u3002 \u7f3a\u5931\u7684\u7d22\u5f15\u5217\u586b\u5165\u7f3a\u5931\u503c\u3002 indexes = index = ['a', 'b', 'c'] states = ['Ohio', 'Texas', 'California'] frame = pd.DataFrame( np.arange(9).reshape(3, 3), index=indexes, columns=states ) print(frame) # Ohio Texas California # a 0 1 2 # b 3 4 5 # c 6 7 8 frame2 = frame.reindex(['a', 'b', 'c', 'd']) # \u91cd\u5efa\u884c\u7d22\u5f15 print(frame2) # Ohio Texas California # a 0.0 1.0 2.0 # b 3.0 4.0 5.0 # c 6.0 7.0 8.0 # d NaN NaN NaN frame3 = frame2.reindex(columns=['Ohio', 'Uta', 'California']) # \u91cd\u5efa\u5217\u7d22\u5f15 print(frame3) # Ohio Uta California # a 0.0 NaN 2.0 # b 3.0 NaN 5.0 # c 6.0 NaN 8.0 # d NaN NaN NaN \u4f7f\u7528 loc \u8fdb\u884c\u66f4\u4e3a\u7b80\u6d01\u7684\u884c\u3001\u5217\u6807\u7b7e\u7d22\u5f15\u3002\u4e0b\u4f8b\u901a\u8fc7\u7b5b\u9009\u884c\u7d22\u5f15\u548c\u5217\u7d22\u5f15\u4ea7\u751f\u65b0\u7684Dataframe\u3002 frame4 = frame.loc[['a', 'b'], states] print(frame4) # Ohio Texas California # a 0 1 2 # b 3 4 5 \u8f74\u5411\u7d22\u5f15\u5220\u9664\u6761\u76ee \u00b6 set_index() , dropna() , fillna() , reset_index() , drop() , replace() \u8fd9\u4e9b\u65b9\u6cd5\u7684 inplace \u5c5e\u6027\u8bbe\u4e3a True \u65f6\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u4f1a\u4fee\u6539Series\u6216DataFrame\u7684\u5c3a\u5bf8\u6216\u5f62\u72b6\uff0c*\u76f4\u63a5*\u64cd\u4f5c\u539f\u5bf9\u8c61\u800c\u4e0d\u8fd4\u56de\u65b0\u5bf9\u8c61\u3002 obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e']) print(obj) # a 0 # b 1 # c 2 # d 3 # e 4 # dtype: int64 obj1 = obj.drop('c') print(obj1) # a 0 # b 1 # d 3 # e 4 # dtype: int64 print(obj1.drop(['d', 'e'])) # a 0 # b 1 # dtype: int64 \u5bf9\u6bd4 inplace=True \u548c False \u7684\u533a\u522b\u3002 inplace=False \u65f6\uff0c obj \u7684\u503c\u6ca1\u6709\u53d8\u5316\u3002 obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e']) print(obj.drop('c', inplace=False)) # \u8bf4\u660e\u751f\u6210\u4e86\u65b0\u5bf9\u8c61 # a 0 # b 1 # d 3 # e 4 # dtype: int64 print(obj) # a 0 # b 1 # c 2 # d 3 # e 4 # dtype: int64 obj.drop('c', inplace=True) \u8f93\u51fa\u662f None \uff0c\u8bf4\u660e\u6ca1\u6709\u751f\u6210\u65b0\u5bf9\u8c61\uff0c\u53d8\u5316\u76f4\u63a5\u4f5c\u7528\u5230 obj \u4e0a\u3002 obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e']) print(obj) print(obj.drop('c', inplace=True)) # \u8bf4\u660e\u6ca1\u6709\u751f\u6210\u65b0\u5bf9\u8c61 # None print(obj) # a 0 # b 1 # d 3 # e 4 # dtype: int64 \u4e0b\u4f8b\u6f14\u793a\u4e86\u8f74\u5411\u7684\u6548\u679c\u3002 \u5982\u679c\u4e0d\u6307\u5b9a\u8f74\u5411axis\uff0c drop() \u4f1a\u9ed8\u8ba4\u6cbf axis=0 \u8fdb\u884c\uff0c\u6240\u4ee5\uff0c\u57280\u8f74\u4e0a\u6267\u884c data.drop(['one', 'two']) \u4f1a\u62a5\u9519\u3002 axis='columns \u4e0e\u6307\u5b9a axis=1 \u540c\u6837\u6548\u679c\u3002 data = pd.DataFrame( np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['one', 'two', 'three', 'four'] ) print(data) # one two three four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 # \u6cbf0\u8f74\u64cd\u4f5c\uff0c\u5220\u9664\u7b26\u5408\u6761\u4ef6\u7684\u884c\u8bb0\u5f55 print(data.drop(['Ohio', 'Colorado'])) # one two three four # Utah 8 9 10 11 # New York 12 13 14 15 print(data.drop(['one', 'two'])) # KeyError: \"['one' 'two'] not found in axis\" # \u6cbf1\u8f74\u64cd\u4f5c\uff0c\u5220\u9664\u7b26\u5408\u6761\u4ef6\u7684\u5217\u8bb0\u5f55 print(data.drop(['one', 'two'], axis=1)) # three four # Ohio 2 3 # Colorado 6 7 # Utah 10 11 # New York 14 15 print(data.drop(['one', 'two'], axis='columns')) # three four # Ohio 2 3 # Colorado 6 7 # Utah 10 11 # New York 14 15 \u518d\u901a\u8fc7\u4e0b\u4f8b\u4f53\u4f1a\u4e00\u4e0b inplace \u53c2\u6570\u7684\u4e0d\u540c\u6548\u679c\u3002 data = pd.DataFrame( { 'Name': ['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], 'class': [11, 12, 10, 9], 'Age': [18, 20, 21, 17] } ) print(data) # Name class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 print(data.rename(columns={'Name': 'FirstName'}, inplace=False)) # FirstName class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 print(data) # Name class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 print(data.rename(columns={'Name': 'FirstName'}, inplace=True)) # \u6ca1\u6709\u751f\u6210\u65b0\u5bf9\u8c61 # None print(data) # FirstName class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 \u7d22\u5f15\u3001\u9009\u62e9\u4e0e\u8fc7\u6ee4 \u00b6 Series\u7684\u7d22\u5f15 obj[...] \u4e0eNumPy\u6570\u7ec4\u7d22\u5f15\u7684\u529f\u80fd\u7c7b\u4f3c\uff0c\u53ea\u4e0d\u8fc7Series\u7684\u7d22\u5f15\u503c\u53ef\u4ee5\u4e0d\u4ec5\u4ec5\u662f\u6574\u6570\u3002 \u4e0b\u4f8b\u4e2d\uff1a obj[1] \u901a\u8fc7\u7d22\u5f15\u4f4d 1 \u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c\u3002 obj[1] \u901a\u8fc7\u7d22\u5f15\u4f4d [1] \u68c0\u7d22\uff0c\u8f93\u51faSeries\u3002 obj['b'] \u901a\u8fc7\u7d22\u5f15\u503c 'b' \u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c\u3002 obj[['b']] \u901a\u8fc7\u7d22\u5f15\u503c ['b'] \u68c0\u7d22\uff0c\u8f93\u51faSeries\u3002 obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd']) print(obj) # a Shobhit # b vaibhav # c vimal # d Sourabh # dtype: object print(obj[1]) # \u901a\u8fc7\u7d22\u5f15\u4f4d\u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c # vaibhav print(obj[[1]]) # b vaibhav # dtype: object print(obj['b']) # \u901a\u8fc7\u7d22\u5f15\u503c\u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c # vaibhav print(obj[['b']]) # \u901a\u8fc7\u7d22\u5f15\u503c\u68c0\u7d22\uff0c\u8f93\u51faSeries # b vaibhav # dtype: object \u4e0b\u9762\u4e00\u7ec4\u7684\u8f93\u51fa\u4e2d\uff0c\u6ce8\u610f\u5bf9\u6bd4\u666e\u901aPython\u5207\u7247\u4e0eSeries\u7684\u5207\u7247\u7684\u5dee\u5f02\u3002 obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd']) print(obj[1]) # vaibhav print(obj[[1]]) # b vaibhav # dtype: object print(obj[1:3]) # b vaibhav # c vimal # dtype: object print(obj['b':'d']) # b vaibhav # c vimal # d Sourabh # dtype: object Series\u7684\u5207\u7247\u7684\u503c\u66f4\u65b0\u3002 obj['b': 'c'] = 5 \u662f\u901a\u8fc7\u7d22\u5f15\u503c\u8fdb\u884c\u66f4\u65b0\uff0c\u76f4\u63a5\u4f5c\u7528\u5728 obj \u3002 obj[1: 3] = 6 \u662f\u901a\u8fc7\u7d22\u5f15\u4f4d\u7f6e\u6765\u66f4\u65b0 obj \u3002 obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd']) obj['b': 'c'] = 5 print(obj) # a Shobhit # b 5 # c 5 # d Sourabh # dtype: object obj[1: 3] = 6 print(obj) # a Shobhit # b 6 # c 6 # d Sourabh # dtype: object DataFrame\u7684\u7d22\u5f15\u4e0e\u5207\u7247\u3002 data[['Three', 'Two']] \u9009\u53d6\u6307\u5b9a\u5217\uff0c\u6ce8\u610f\u8f93\u5165\u5217\u6761\u4ef6\u662f\u5217\u8868 ['Three', 'Two'] \u3002 data = pd.DataFrame( np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['One', 'Two', 'Three', 'Four'] ) print(data) # One Two Three Four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 print(data['Two']) # Ohio 1 # Colorado 5 # Utah 9 # New York 13 # Name: Two, dtype: int64 print(data[['Three', 'Two']]) # Three Two # Ohio 2 1 # Colorado 6 5 # Utah 10 9 # New York 14 13 print(data[:2]) # One Two Three Four # Ohio 0 1 2 3 # Colorado 4 5 6 7 \u5d4c\u5957\uff1a\u6839\u636e\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4\u5207\u7247\u6216\u9009\u62e9\u6570\u636e\u3002 data['Three'] > 5 \u662f\u4e00\u4e2a\u5e03\u5c14\u503c\u5e8f\u5217\u3002 data[data['Three'] > 5] \u8f93\u51fa\u6761\u4ef6\u4e3aTrue\u7684\u7ed3\u679c\u96c6\u3002 print(data['Three'] > 5) # Ohio False # Colorado True # Utah True # New York True # Name: Three, dtype: bool print(data[data['Three'] > 5]) # One Two Three Four # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 \u4f7f\u7528\u5e03\u5c14\u503cDataFrame\u8fdb\u884c\u7d22\u5f15\uff0c\u5df2\u7ecf\u66f4\u65b0\u3002 \u5728\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u8fd9\u79cd\u7d22\u5f15\u65b9\u5f0f\u4f7f\u5f97DataFrame\u5728\u8bed\u6cd5\u4e0a\u66f4\u50cf\u662fNumPy\u4e8c\u7ef4\u6570\u7ec4\u3002 print(data < 5) # One Two Three Four # Ohio True True True True # Colorado True False False False # Utah False False False False # New York False False False False data[data < 5] = 0 print(data) # One Two Three Four # Ohio 0 0 0 0 # Colorado 0 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 \u4f7f\u7528loc\u548ciloc\u9009\u62e9\u6570\u636e\u3002 \u4f7f\u7528\u6807\u7b7e\u540d loc \u6216\u6807\u7b7e\u4f4d\u7f6e iloc \u4ee5NumPy\u98ce\u683c\u7684\u8bed\u6cd5\u4eceDataFrame\u4e2d\u9009\u51faDataframe\u7684\u884c\u548c\u5217\u7684\u5b50\u96c6\u3002 data = pd.DataFrame( np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['One', 'Two', 'Three', 'Four'] ) print(data) # One Two Three Four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 \u4e0b\u4f8b\u901a\u8fc7loc\u5bf9\u6807\u7b7e\u540d\u7b5b\u9009\u884c\u6216\u5217\u6570\u636e\u3002\u4f8b\u5982\uff0c\u8f93\u51fa Colorado \u884c\u6807\u7b7e\u7684 Two \u548c Three \u8fd9\u4e24\u5217\u7684\u503c\uff0c\u4ee5\u884c\u8bb0\u5f55\u7684\u65b9\u5f0f\u5c55\u73b0\u3002 print(data.loc['Colorado', ['Two', 'Three']]) # \u5207\u7247: # Two 5 # Three 6 # Name: Colorado, dtype: int64 print(data.loc[:'Ohio', :'Two']) # \u5207\u7247: 0\u884c\uff0c0,1\u5217 # One Two # Ohio 0 1 \u4e0b\u4f8b\u901a\u8fc7\u6807\u7b7e\u4f4d\u7f6e iloc \u8fdb\u884c\u7c7b\u4f3c\u7684\u6570\u636e\u9009\u62e9\u3002 data.iloc[:3, :2][data > 4] \u6309\u6307\u5b9a\u6761\u4ef6\u8fdb\u884c\u884c\u3001\u5217\u7b5b\u9009\uff0c\u7b26\u5408\u6761\u4ef6 [data > 4] \u7684\u8f93\u51faDataframe\u503c\uff0c\u4e0d\u7b26\u5408\u6761\u4ef6\u7684\u8f93\u51faNaN\u3002 print(data.iloc[[0]]) # 0\u884c # One Two Three Four # Ohio 0 1 2 3 print(data.iloc[[0], [1]]) # \u5207\u7247: 0\u884c\uff0c1\u5217 # Two # Ohio 1 print(data.iloc[1:2, 1:2]) # \u5207\u7247: 1\u884c\uff0c2\u5217 # Two # Ohio 1 print(data.iloc[2, [3, 0, 1]]) # \u5207\u7247: 2\u884c\uff0c\u4f9d\u6b21\u53d63\uff0c0\uff0c1\u5217 # Four 11 # One 8 # Two 9 # Name: Utah, dtype: int64 print(data.iloc[:3, :2][data > 4]) # One Two # Ohio NaN NaN # Colorado NaN 5.0 # Utah 8.0 9.0 \u6574\u6570\u7d22\u5f15 \u00b6 Pandas\u7684Series\u7684\u7d22\u5f15\u503c\u662f\u6574\u6570\u7d22\u5f15\u3002 data = np.arange(3.) ser = pd.Series(data) print(ser) # 0 0.0 # 1 1.0 # 2 2.0 # dtype: float64 print(ser[:1]) # 0 0.0 # dtype: float64 print(ser.loc[:1]) # loc\u7528\u4e8e\u6807\u7b7e\u540d # 0 0.0 # 1 1.0 # dtype: float64 print(ser.iloc[:1]) # iloc\u7528\u4e8e\u6807\u7b7e\u4f4d\u7f6e # 0 0.0 # dtype: float64 data = ['1', 'b', 'e', 3] ser = pd.Series(data) print(ser) # 0 1 # 1 b # 2 e # 3 3 # dtype: object print(ser[:1]) # 0 1 # dtype: object print(ser.loc[:1]) # 0 1 # 1 b # dtype: object print(ser.iloc[:1]) # 0 1 # dtype: object \u5bf9DataFrame\u7684\u66f4\u65b0\u3002 df1 = pd.DataFrame(np.arange(4).reshape((2, 2)), columns=list('ab')) print(df1) # a b # 0 0 1 # 1 2 3 # \u6309\u6807\u7b7e\u540d\u66f4\u65b0 df1.loc[1, :'b'] = np.nan print(df1) # a b # 0 0.0 1.0 # 1 NaN NaN \u7b97\u672f\u548c\u6570\u636e\u5bf9\u9f50 \u00b6 Pandas\u652f\u6301\u5728Series\u6216\u8005DataFrame\u5bf9\u8c61\u4e4b\u95f4\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97\u3002 \u4f8b\uff1a\u4e24\u4e2aSeries\u505a\u7b97\u672f\u52a0\u6cd5\u3002 \u8fd4\u56de\u7684\u7ed3\u679c\u4e5f\u662f\u4e00\u4e2aSeries\u3002 \u8fd4\u56de\u7ed3\u679c\u7684\u7d22\u5f15\u662f\u6bcf\u4e2aSeries\u7684\u7d22\u5f15\u7684\u5e76\u96c6\u3002 \u51e1\u662f\u6ca1\u6709\u5728\u4e24\u4e2aSeries\u90fd\u51fa\u73b0\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0c\u5185\u90e8\u6570\u636e\u5bf9\u9f50\u4f1a\u586b\u5145\u7f3a\u5931\u503cNaN\u3002\u7f3a\u5931\u503c\u4f1a\u5728\u540e\u7eed\u7684\u5176\u5b83\u7b97\u672f\u64cd\u4f5c\u4e0a\u4ea7\u751f\u5f71\u54cd\u3002 \u540c\u65f6\u51fa\u73b0\u5728\u4e24\u4e2aSeries\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0cSeries\u7684\u503c\u505a\u7b97\u672f\u76f8\u52a0\u3002 s1 = pd.Series( [7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'] ) s2 = pd.Series( [-2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'] ) print(s1) # a 7.3 # c -2.5 # d 3.4 # e 1.5 # dtype: float64 print(s2) # a -2.1 # c 3.6 # e -1.5 # f 4.0 # g 3.1 # dtype: float64 print(s1 + s2) # a 5.2 # c 1.1 # d NaN # e 0.0 # f NaN # g NaN # dtype: float64 \u4f8b\uff1a\u4e24\u4e2aDataframe\u505a\u7b97\u672f\u52a0\u6cd5 \u8fd4\u56de\u7ed3\u679c\u4e5f\u662f\u4e00\u4e2aDataframe\u3002 \u8fd4\u56de\u7ed3\u679c\u7684\u884c\u5217\u7d22\u5f15\u662f\u6bcf\u4e2aDataFrame\u7684\u884c\u5217\u7d22\u5f15\u7684\u5e76\u96c6\u3002 \u51e1\u662f\u6ca1\u6709\u5728\u4e24\u4e2aDataFrame\u90fd\u51fa\u73b0\u7684\u4f4d\u7f6e\u5c31\u4f1a\u88ab\u7f6e\u4e3aNaN\u3002 \u4e24\u4e2aDataFrame\u90fd\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5bf9Dataframe\u7684\u503c\u505a\u7b97\u672f\u52a0\u6cd5\u3002 df1 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'] ) df2 = pd.DataFrame( np.arange(12).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'] ) print(df1) # b c d # Ohio 0 1 2 # Texas 3 4 5 # Colorado 6 7 8 print(df2) # b d e # Utah 0 1 2 # Ohio 3 4 5 # Texas 6 7 8 # Oregon 9 10 11 print(df1 + df2) # b c d e # Colorado NaN NaN NaN NaN # Ohio 3.0 NaN 6.0 NaN # Oregon NaN NaN NaN NaN # Texas 9.0 NaN 12.0 NaN # Utah NaN NaN NaN NaN \u5728Series\u6216\u8005DataFrame\u5bf9\u8c61\u4e4b\u95f4\u8fdb\u884c\u7b97\u672f\u64cd\u4f5c\u65f6\uff0c\u6709\u65f6\u9700\u8981\u5bf9\u7f3a\u5931\u503c\u6307\u5b9a\u586b\u5145\u503c\uff0c\u6bd4\u5982\u5f53\u8f74\u6807\u7b7e\u5728\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u5b58\u5728\uff0c\u5728\u53e6\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u4e0d\u5b58\u5728\u65f6\uff0c\u5c06\u7f3a\u5931\u503c\u586b\u5145\u4e3a0\u3002\u4e5f\u5c31\u662f\u8bf4\uff0c\u5982\u679c\u5728\u4e24\u4e2aDataFrame\u90fd\u7f3a\u5931\uff0c\u90a3\u4e48\u4f9d\u7136\u8fd8\u4f1a\u662fNaN\u3002 \u4e0b\u4f8b\u4e2da2\u662f\u5728 df1 \u548c df2 \u90fd\u7f3a\u5931\u7684\u4f4d\u7f6e\uff0c\u6240\u4ee5\u5373\u4f7f fill_value=0 \uff0ca2\u4ecd\u7136\u662fNaN\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('bcd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # b c d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 # \u5bf9df1\u548cdf2\u5c31\u7b97\u672f\u548c\uff0c\u5bf9\u5e94\u6ca1\u6709\u884c\u5217\u5171\u540c\u7684\u4ea4\u96c6\u7684\u5730\u65b9\u586b\u5145\u7a7a\u503cNaN\uff0c\u6709\u4ea4\u96c6\u7684\u5730\u65b9\u6c42\u7b97\u672f\u548c\u3002 print(df1.add(df2)) # a b c d # 0 NaN 1.0 NaN NaN # 1 NaN 6.0 NaN NaN # 2 NaN NaN NaN NaN # \u5bf9df1\u548cdf2\u5c31\u7b97\u672f\u548c\uff0c\u5bf9\u5e94\u6ca1\u6709\u884c\u5217\u5171\u540c\u7684\u4ea4\u96c6\u7684\u5730\u65b9\u586b\u5145\u7a7a\u503c0\uff0c\u6709\u4ea4\u96c6\u7684\u5730\u65b9\u6c42\u7b97\u672f\u548c\u3002 print(df1.add(df2, fill_value=0)) # df2.add(df1, fill_value=0) \u8fd4\u56de\u540c\u6837\u7684\u7ed3\u679c # a b c d # 0 0.0 1.0 1.0 2.0 # 1 2.0 6.0 4.0 5.0 # 2 NaN 6.0 7.0 8.0 \u4e0b\u4f8b\u4e2db2\u662f\u5728 df1 \u548c df2 \u90fd\u7f3a\u5931\u7684\u4f4d\u7f6e\uff0c\u6240\u4ee5\u5373\u4f7f fill_value=0 \uff0cb2\u4ecd\u7136\u662fNaN\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('acd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # a c d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 print(df1.add(df2, fill_value=0)) # a b c d # 0 0.0 1.0 1.0 2.0 # 1 5.0 3.0 4.0 5.0 # 2 6.0 NaN 7.0 8.0 \u4e0b\u4f8b\u4e2d\u6ca1\u6709\u4e24\u4e2aDataFrame\u5171\u540c\u7f3a\u5931\u7684\u60c5\u51b5\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('abd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # a b d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 print(df1.add(df2, fill_value=0)) # a b d # 0 0.0 2.0 2.0 # 1 5.0 7.0 5.0 # 2 6.0 7.0 8.0 \u4e0b\u9762\u662fSeries\u548cDataFrame\u7684\u7b97\u672f\u65b9\u6cd5\u3002 add\uff0cradd\uff1a\u52a0\u6cd5(+) sub\uff0crsub\uff1a\u51cf\u6cd5(-) div\uff0crdiv\uff1a\u9664\u6cd5(/) floordiv\uff0crfloordiv\uff1a\u6574\u9664(//) mul\uff0crmul\uff1a\u4e58\u6cd5(*) pow\uff0crpow\uff1a\u5e42\u6b21\u65b9(**) \u4e0a\u8ff0\u6bcf\u4e2a\u65b9\u6cd5\u90fd\u6709\u4e00\u4e2a\u4ee5r\u5f00\u5934\u7684\u526f\u672c\uff0c\u8fd9\u4e9b\u526f\u672c\u65b9\u6cd5\u7684\u53c2\u6570\u662f\u7ffb\u8f6c\u7684\u3002\u6bd4\u5982\uff0c\u6c42DataFrame\u5f53\u4e2d\u6240\u6709\u5143\u7d20\u7684\u5012\u6570 1/df \uff0c\u53ef\u4ee5\u5199\u6210df.rdiv(1)\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('abd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # a b d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 print(df1.radd(df2, fill_value=0)) # a b d # 0 0.0 2.0 2.0 # 1 5.0 7.0 5.0 # 2 6.0 7.0 8.0 print(df1.sub(df2, fill_value=0)) # a b d # 0 0.0 0.0 -2.0 # 1 -1.0 -1.0 -5.0 # 2 -6.0 -7.0 -8.0 print(df1.div(df2, fill_value=0)) # a b d # 0 NaN 1.00 0.0 # 1 0.666667 0.75 0.0 # 2 0.000000 0.00 0.0 print(df1.floordiv(df2, fill_value=0)) # a b d # 0 NaN 1.0 0.0 # 1 0.0 0.0 0.0 # 2 0.0 0.0 0.0 print(df1.mul(df2, fill_value=0)) # a b d # 0 0.0 1.0 0.0 # 1 6.0 12.0 0.0 # 2 0.0 0.0 0.0 print(df1.pow(df2, fill_value=0)) # a b d # 0 1.0 1.0 0.0 # 1 8.0 81.0 0.0 # 2 0.0 0.0 0.0 DataFrame\u548cSeries\u95f4\u7684\u7b97\u672f\u64cd\u4f5c \u00b6 DataFrame\u548cSeries\u95f4\u7684\u7b97\u672f\u64cd\u4f5c\u4e0eNumPy\u4e2d\u4e0d\u540c\u7ef4\u5ea6\u6570\u7ec4\u95f4\u7684\u64cd\u4f5c\u7c7b\u4f3c\u3002 \u4e0d\u540c\u7ef4\u5ea6NumPy\u6570\u7ec4\u95f4\u7684\u7b97\u672f\u64cd\u4f5c \u00b6 \u4ecearr\u4e2d\u51cf\u53bbarr[0]\u65f6\uff0c\u51cf\u6cd5\u6cbf0\u8f74\u5728\u6bcf\u4e00\u884c\u90fd\u8fdb\u884c\u4e86\u64cd\u4f5c\u3002\u8fd9\u5c31\u662f\u6240\u8c13\u7684\u5e7f\u64ad\u673a\u5236\u3002 arr = np.arange(12).reshape((3, 4)) print(arr) # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] print(arr[0]) # [0 1 2 3] print(arr - arr[0]) # [[0 0 0 0] # [4 4 4 4] # [8 8 8 8]] DataFrame\u548cSeries\u95f4\u7684\u7b97\u672f\u64cd\u4f5c \u00b6 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cDataFrame\u548cSeries\u7684\u6570\u5b66\u64cd\u4f5c\u4e2d\u4f1a\u5c06Series\u7684\u7d22\u5f15\u548cDataFrame\u7684*\u5217*\u8fdb\u884c\u5339\u914d\uff0c\u5e76*\u5e7f\u64ad\u5230\u5404\u884c*. \u5982\u679c\u4e00\u4e2a\u7d22\u5f15\u503c\u4e0d\u5728DataFrame\u7684\u5217\u4e2d\uff0c\u4e5f\u4e0d\u5728Series\u7684\u7d22\u5f15\u4e2d\uff0c\u5219\u65b0\u5bf9\u8c61\u4f1a\u6784\u5efa\u5e76\u96c6\u7d22\u5f15\u3002 frame = pd.DataFrame( np.arange(12).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'] ) print(frame) # b d e # Utah 0 1 2 # Ohio 3 4 5 # Texas 6 7 8 # Oregon 9 10 11 # \u622a\u53d6frame\u7684\u7b2c0\u884c\uff0c\u5217\u6807\u7b7e\u53d8\u6210\u65b0Serise\u7684\u7d22\u5f15\u3002 series = frame.iloc[0] print(series) # b 0 # d 1 # e 2 # Name: Utah, dtype: int64 series2 = pd.Series( range(3), index=list('bef') ) print(series2) # b 0 # e 1 # f 2 # dtype: int64 # \u622a\u53d6frame\u7684d\u5217\uff0c\u884c\u6807\u7b7e\u53d8\u6210\u65b0Serise\u7684\u7d22\u5f15\u3002 series3 = frame['d'] print(series3) # Utah 1 # Ohio 4 # Texas 7 # Oregon 10 # Name: d, dtype: int64 # \u5c06Series\u7684\u7d22\u5f15\u548cDataFrame\u7684\u5217\u6807\u7b7e\u8fdb\u884c\u5339\u914d\uff0cSeries\u7684\u503c\u6cbfDataFrame\u76840\u8f74\u5e7f\u64ad\u5230\u5404\u4e2a\u884c\u3002 print(frame - series) # frame: series Result: # b d e # b 0 # b d e # Utah 0 1 2 # d 1 # Utah 0 0 0 # Ohio 3 4 5 # e 2 # Ohio 3 3 3 # Texas 6 7 8 # Name: Utah, dtype: int64 # Texas 6 6 6 # Oregon 9 10 11 # Oregon 9 9 9 # \u5c06Series\u7684\u7d22\u5f15\u548cDataFrame\u7684\u5217\u6807\u7b7e\u8fdb\u884c\u5339\u914d\uff0cSeries\u7684\u503c\u6cbfDataFrame\u76840\u8f74\u5e7f\u64ad\u5230\u5404\u4e2a\u884c\uff0c\u7f3a\u5931\u4f4d\u7f6e\u586b\u5145\u7a7a\u503cNaN\u3002 print(frame - series2) # frame: series2 Result: # b d e # b 0 # b d e f # Utah 0 1 2 # e 1 # Utah 0.0 NaN 1.0 NaN # Ohio 3 4 5 # f 2 # Ohio 3.0 NaN 4.0 NaN # Texas 6 7 8 # dtype: int64 # Texas 6.0 NaN 7.0 NaN # Oregon 9 10 11 # Oregon 9.0 NaN 10.0 NaN # \u6539\u4e3a\u5728\u5217\u4e0a\u8fdb\u884c\u5e7f\u64ad\uff0c\u5728\u884c\u4e0a\u5339\u914d\uff0c\u5fc5\u987b\u4f5c\u7528\u5728\u67d0\u79cd\u7b97\u672f\u65b9\u6cd5\u4e0a\u3002\u4e0b\u4f8b\u4e2dSeries\u7684\u503c\u6cbfDataFrame\u76840\u8f74\u5e7f\u64ad\u5230\u5404\u4e2a\u884c\uff08\u6309index\u5339\u914d\u8fdb\u884c\u884c\u64cd\u4f5c\uff09\u3002 print(frame.sub(series3, axis='index')) # \u6216axis=0 # frame: series3 Result: # b d e # Utah 1 # b d e # Utah 0 1 2 # Ohio 4 # Utah -1 0 1 # Ohio 3 4 5 # Texas 7 # Ohio -1 0 1 # Texas 6 7 8 # Oregon 10 # Texas -1 0 1 # Oregon 9 10 11 # Name: d, dtype: int64 # Oregon -1 0 1 \u51fd\u6570\u5e94\u7528\u548c\u6620\u5c04 \u00b6 NumPy\u7684\u901a\u7528\u51fd\u6570\uff08\u9010\u5143\u7d20\u6570\u7ec4\u65b9\u6cd5\uff09\u5bf9pandas\u5bf9\u8c61\uff08DataFrame\u548cSeries\uff09\u4e5f\u6709\u6548\u3002 frame = pd.DataFrame( np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'] ) print(frame) # b d e # Utah 2.737734 -0.379977 0.758933 # Ohio 0.847497 0.839583 -2.192021 # Texas -0.907544 -0.457436 -1.907396 # Oregon 0.389362 0.250170 1.065889 # \u5bf9DataFrame\u5bf9\u8c61\u8ba1\u7b97\u7edd\u5bf9\u503c\u3002 print(np.abs(frame)) # b d e # Utah 2.737734 0.379977 0.758933 # Ohio 0.847497 0.839583 2.192021 # Texas 0.907544 0.457436 1.907396 # Oregon 0.389362 0.250170 1.065889 # f\u8fd4\u56de\u4e00\u4e2a\u6807\u91cf\u503c f = lambda x: x.max() - x.min() # \u6cbf0\u8f74\u5e94\u7528f\uff08\u5bf9\u6bcf\u5217\u7684\u6240\u6709\u884c\u5143\u7d20\u8fdb\u884cf\u8ba1\u7b97\uff09, \u9ed8\u8ba4axis=0 print(frame.apply(f)) # b 3.645278 # d 1.297019 # e 3.257911 # dtype: float64 # \u6cbf1\u8f74\u5e94\u7528f\uff08\u5bf9\u6bcf\u884c\u7684\u6240\u6709\u5217\u5143\u7d20\u8fdb\u884cf\u8ba1\u7b97\uff09 print(frame.apply(f, axis=1)) # Utah 3.117711 # Ohio 3.039518 # Texas 1.449961 # Oregon 0.815720 # dtype: float64 # \u5b9a\u4e49\u51fd\u6570f\uff0c\u8fd4\u56de\u5e26\u6709\u591a\u4e2a\u503c\u7684Series\u3002 def f(x): return pd.Series( [x.min(), x.max()], index=['min', 'max'] ) print(frame.apply(f)) # b d e # min -0.907544 -0.457436 -2.192021 # max 2.737734 0.839583 1.065889 # \u5b9a\u4e49\u51fd\u6570f\uff0c\u4f7f\u7528applymap\u65b9\u6cd5\u683c\u5f0f\u5316\u5b57\u7b26\uff0c\u5c06\u4e00\u4e2a\u9010\u5143\u7d20\u7684\u51fd\u6570\u5e94\u7528\u5230Series\u4e0a\u3002 f = lambda x: '%.2f' % x print(frame.applymap(f)) # # b d e # Utah 2.74 -0.38 0.76 # Ohio 0.85 0.84 -2.19 # Texas -0.91 -0.46 -1.91 # Oregon 0.39 0.25 1.07 print(frame['e'].map(f)) # Utah 0.76 # Ohio -2.19 # Texas -1.91 # Oregon 1.07 # Name: e, dtype: object \u6392\u5e8f\u548c\u6392\u540d \u00b6 \u4f7f\u7528sort_index\u65b9\u6cd5\uff0c\u6309\u884c\u6216\u5217\u7d22\u5f15\u8fdb\u884c\u5b57\u5178\u578b\u6392\u5e8f\uff0c\u8fd4\u56de\u4e00\u4e2a\u65b0\u7684\u6392\u5e8f\u597d\u7684Pandas\u5bf9\u8c61\u3002 Series\u6392\u5e8f \u00b6 \u5bf9Series\u8fdb\u884c\u7d22\u5f15\u6392\u5e8f\u548c\u503c\u6392\u5e8f\u3002 obj = pd.Series( range(4), index=list('dabc') ) print(obj) # d 0 # a 1 # b 2 # c 3 # dtype: int64 print(obj.sort_index()) # a 1 # b 2 # c 3 # d 0 # dtype: int64 # print(obj.sort_values()) # d 0 # a 1 # b 2 # c 3 # dtype: int64 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6240\u6709\u7684\u7f3a\u5931\u503c\u90fd\u4f1a\u88ab\u6392\u5e8f\u81f3Series\u7684\u5c3e\u90e8\u3002 obj = pd.Series([4, np.nan, 7, np.nan, -3, 2]) print(obj) # 0 4.0 # 1 NaN # 2 7.0 # 3 NaN # 4 -3.0 # 5 2.0 # dtype: float64 print(obj.sort_values()) # 4 -3.0 # 5 2.0 # 0 4.0 # 2 7.0 # 1 NaN # 3 NaN # dtype: float64 DataFrame\u6392\u5e8f \u00b6 frame = pd.DataFrame( [[0, 1, 10, 3], [4, 5, 6, 21], [8, 9, 2, 21]], index=['three', 'one', 'five'], columns=list('dabc') ) print(frame) # d a b c # three 0 1 10 3 # one 4 5 6 21 # five 8 9 2 21 print(frame.index) # Index(['three', 'one', 'five'], dtype='object') # \u9ed8\u8ba40\u8f74\uff0c\u6240\u6709\u884c\u8fdb\u884c\u7d22\u5f15\u9996\u5b57\u6bcd\u5347\u5e8f print(frame.sort_index()) # d a b c # five 8 9 2 21 # one 4 5 6 21 # three 0 1 10 3 # \u6307\u5b9a0\u8f74\uff0c\u6240\u6709\u884c\u8fdb\u884c\u7d22\u5f15\u9996\u5b57\u6bcd\u5347\u5e8f print(frame.sort_index(axis=0)) # d a b c # five 8 9 2 21 # one 4 5 6 21 # three 0 1 10 3 # \u6307\u5b9a0\u8f74\uff0c\u6240\u6709\u884c\u8fdb\u884c\u7d22\u5f15\u9996\u5b57\u6bcd\u964d\u5e8f print(frame.sort_index(axis=0, ascending=False)) # d a b c # three 0 1 10 3 # one 4 5 6 21 # five 8 9 2 21 # \u6307\u5b9a1\u8f74\uff0c\u6240\u6709\u5217\u8fdb\u5217\u7d22\u5f15\u9996\u5b57\u6bcd\u5347\u5e8f print(frame.sort_index(axis=1)) # a b c d # three 1 10 3 0 # one 5 6 21 4 # five 9 2 21 8 # \u6307\u5b9a1\u8f74\uff0c\u6240\u6709\u5217\u8fdb\u5217\u7d22\u5f15\u9996\u5b57\u6bcd\u964d\u5e8f print(frame.sort_index(axis=1, ascending=False)) # d c b a # three 0 3 10 1 # one 4 21 6 5 # five 8 21 2 9 # \u6309\u6307\u5b9a\u5355\u5217\u8fdb\u884c\u503c\u6392\u5e8f\uff08\u964d\u5e8f\uff09 print(frame.sort_values(by=['c'], ascending=False)) # d a b c # one 4 5 6 21 # five 8 9 2 21 # three 0 1 10 3 # \u6309\u6307\u5b9a\u591a\u5217\u8fdb\u884c\u503c\u6392\u5e8f\uff08\u964d\u5e8f\uff09\uff0c\u5148\u5bf9b\u964d\u5e8f\uff0c\u518d\u5bf9d\u964d\u5e8f print(frame.sort_values(by=['c', 'd'], ascending=False)) # d a b c # five 8 9 2 21 # one 4 5 6 21 # three 0 1 10 3 \u6392\u540d \u00b6 **\u6392\u540d**\u662f\u6307\u5bf9\u6570\u7ec4\u4ece1\u5230\u6709\u6548\u6570\u636e\u70b9\u603b\u6570\u5206\u914d\u540d\u6b21\u7684\u64cd\u4f5c\u3002 Series\u548cDataFrame\u7684 rank \u65b9\u6cd5\u662f\u5b9e\u73b0\u6392\u540d\u7684\u65b9\u6cd5\uff0c df.rank(ascending=False, method='max') \u3002 ascending \uff1a\u6392\u540d\u65b9\u5f0f\uff0c\u9ed8\u8ba4\u4ece\u4f4e\u5230\u9ad8\uff0c ascending=False \u8868\u793a\u4ece\u9ad8\u5230\u4f4e\uff1b method \uff1a\u6392\u540d\u65b9\u5f0f\uff0c\u5305\u62ec\uff1a average:\u9ed8\u8ba4\uff0c\u5728\u76f8\u7b49\u5206\u7ec4\u4e2d\uff0c\u4e3a\u5404\u4e2a\u503c\u5206\u914d\u5e73\u5747\u6392\u540d\uff0c\u5373\u76f8\u540c\u503c\u7684\u548c\u9664\u4ee5\u8be5\u503c\u7684\u4e2a\u6570\uff0c\u5373\u4e3a\u8be5\u503c\u7684\u540d\u6b21\u3002 min:\u4f7f\u7528\u6574\u4e2a\u5206\u7ec4\u7684\u6700\u5c0f\u6392\u540d\uff0c\u5373\uff0c\u5bf9\u5e94\u76f8\u540c\u503c\uff0c\u53d6\u5728\u987a\u5e8f\u6392\u540d\u4e2d\u6700\u5c0f\u7684\u90a3\u4e2a\u6392\u540d\u4f5c\u4e3a\u6240\u6709\u8be5\u503c\u7684\u6392\u540d\u3002 max:\u4f7f\u7528\u6574\u4e2a\u5206\u7ec4\u7684\u6700\u5927\u6392\u540d\uff0c\u5373\uff0c\u5bf9\u5e94\u76f8\u540c\u503c\uff0c\u53d6\u5728\u987a\u5e8f\u6392\u540d\u4e2d\u6700\u5927\u7684\u90a3\u4e2a\u6392\u540d\u4f5c\u4e3a\u6240\u6709\u8be5\u503c\u7684\u6392\u540d\u3002 first:\u6309\u503c\u518d\u539f\u59cb\u6570\u636e\u4e2d\u51fa\u73b0\u987a\u5e8f\u5206\u914d\u6392\u540d\uff0c\u8c01\u51fa\u73b0\u7684\u4f4d\u7f6e\u9760\u524d\uff0c\u8c01\u7684\u6392\u540d\u9760\u524d\u3002 dense:\u7c7b\u4f3cmin\u65b9\u6cd5\uff0c\u4f46\u6392\u540d\u603b\u662f\u5728\u7ec4\u95f4\u589e\u52a01\uff0c\u800c\u4e0d\u662f\u7ec4\u4e2d\u76f8\u540c\u7684\u5143\u7d20\u6570\uff0c\u5373\u76f8\u540c\u503c\u7684\u6392\u540d\u76f8\u540c\uff0c\u5176\u4ed6\u4f9d\u6b21\u52a01\u5373\u53ef\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0crank\u662f\u901a\u8fc7\u201c\u4e3a\u5404\u7ec4\u5206\u914d\u4e00\u4e2a\u5e73\u5747\u6392\u540d\u201d\u7684\u65b9\u5f0f\u7834\u574f\u5e73\u7ea7\u5173\u7cfb # \u6309\u7167\u6bcf\u4e2a\u5143\u7d20\u7684\u5927\u5c0f\u987a\u5e8f\u7ed9\u51fa\u4e00\u4e2a\u5e73\u5747\u6392\u540d obj = pd.Series([7, -5, 7, 4, 2, 0, 4]) print(obj) # 0 7 # 1 -5 # 2 7 # 3 4 # 4 2 # 5 0 # 6 4 # dtype: int64 print(obj.rank()) # 0 6.5 # 1 1.0 # 2 6.5 # 3 4.5 # 4 3.0 # 5 2.0 # 6 4.5 # dtype: float64 # index value rank # 2 -5 1 # 6 0 2 # 5 2 3 # 4 4 4.5 # 7 4 4.5 # 1 7 6.5 # 3 7 6.5 # \u6839\u636e\u5143\u7d20\u7684\u89c2\u5bdf\u987a\u5e8f\u8fdb\u884c\u5206\u914d\u3002\u5143\u7d200\u548c2\u6ca1\u6709\u4f7f\u7528\u5e73\u5747\u6392\u540d6.5\uff0c\u5b83\u4eec\u88ab\u8bbe\u6210\u4e866\u548c7\uff0c\u56e0\u4e3a\u6570\u636e\u4e2d\u6807\u7b7e0\u4f4d\u4e8e\u6807\u7b7e2\u7684\u524d\u9762\u3002 print(obj.rank(method='first')) # 0 6.0 # 1 1.0 # 2 7.0 # 3 4.0 # 4 3.0 # 5 2.0 # 6 5.0 # dtype: float64 # \u6309\u7167max\u8fdb\u884c\u5347\u5e8f\u548c\u964d\u5e8f print(obj.rank(ascending=False, method='max')) print(obj.rank(ascending=True, method='max')) # Original Series Max with inc Max with dec # 0 7 # 0 2.0 (\u6700\u5c0f) # 0 7.0 (\u6700\u5927) # 1 -5 # 1 7.0 (\u6700\u5927) # 1 1.0 (\u6700\u5c0f) # 2 7 # 2 2.0 (\u6700\u5c0f) # 2 7.0 (\u6700\u5927) # 3 4 # 3 4.0 # 3 5.0 # 4 2 # 4 5.0 # 4 3.0 # 5 0 # 5 6.0 # 5 2.0 # 6 4 # 6 4.0 # 6 5.0 # dtype: float64 # dtype: float64 # dtype: float64 frame = pd.DataFrame( {'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1], 'c': [-2, 5, 8, -2]} ) print(frame) # b a c # 0 4.3 0 -2 # 1 7.0 1 5 # 2 -3.0 0 8 # 3 2.0 1 -2 # \u6cbf1\u8f74\u5bf9DataFrame\u8fdb\u884crank\u64cd\u4f5c\uff0c\u5373\uff0c\u6bcf\u4e00\u884c\u5404\u5143\u7d20\u8fdb\u884crank\u3002 print(frame.rank(axis='columns')) # axis=1 # b a c # 0 3.0 2.0 1.0 # 1 3.0 1.0 2.0 # 2 1.0 2.0 3.0 # 3 3.0 2.0 1.0 \u542b\u6709\u91cd\u590d\u6807\u7b7e\u7684\u8f74\u7d22\u5f15 \u00b6 \u5c3d\u7ba1\u5f88\u591apandas\u51fd\u6570\uff08\u6bd4\u5982reindex\uff09\u9700\u8981\u6807\u7b7e\u662f\u552f\u4e00\u7684\uff0c\u4f46\u8fd9\u4e2a\u5e76\u4e0d\u662f\u5f3a\u5236\u6027\u7684\u3002 \u7d22\u5f15\u7684is_unique\u5c5e\u6027\u53ef\u4ee5\u68c0\u67e5\u6807\u7b7e\u662f\u5426\u552f\u4e00\u3002 \u5e26\u6709\u91cd\u590d\u7d22\u5f15\u7684\u60c5\u51b5\u4e0b\uff0c\u4e00\u4e2a\u7d22\u5f15\u6807\u7b7e\u4f1a\u4ee5\u5e8f\u5217\u65b9\u5f0f\u8fd4\u56de\u591a\u4e2a\u6761\u76ee\u3002\u4e0d\u91cd\u590d\u7684\u7d22\u5f15\u5219\u4f1a\u4ee5\u6807\u91cf\u503c\u7684\u5f62\u5f0f\u8fd4\u56de\u5355\u4e2a\u6761\u76ee\uff0c\u8fd9\u53ef\u80fd\u4f1a\u4f7f\u4ee3\u7801\u66f4\u590d\u6742\u3002 obj = pd.Series(range(5), index=['a', 'b', 'a', 'c', 'b']) print(obj) # a 0 # b 1 # a 2 # c 3 # b 4 # dtype: int64 print(obj.is_unique) # True print(obj.index.is_unique) # False # \u8fd4\u56de\u91cd\u590d\u7d22\u5f15\u5bf9\u5e94\u503c\u7684\u5e8f\u5217\u3002 print(obj['a']) # a 0 # a 2 # dtype: int64 df = pd.DataFrame(np.random.randn(4, 3), index=['a', 'a', 'b', 'b']) print(df) # 0 1 2 # a -0.726164 0.531540 -0.521611 # a -1.539807 -0.710880 -0.992789 # b -0.975970 -0.470725 0.121958 # b -0.301495 1.072322 -1.542296 print(df.index.is_unique) # False print(df.loc['b']) # 0 1 2 # b -0.520008 0.052574 0.638529 # b -1.928705 -1.099534 -1.605296 \u63cf\u8ff0\u6027\u7edf\u8ba1\u6982\u8ff0\u4e0e\u8ba1\u7b97 \u00b6 pandas\u5305\u542b\u4e86\u4e00\u4e9b\u5e38\u7528\u6570\u5b66\u3001\u7edf\u8ba1\u5b66\u65b9\u6cd5\u3002\u5176\u4e2d\u5927\u90e8\u5206\u5c5e\u4e8e\u5f52\u7ea6\u6216\u6c47\u603b\u7edf\u8ba1\u7684\u7c7b\u522b\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u4eceDataFrame\u7684\u884c\u6216\u5217\u4e2d\u62bd\u53d6\u4e00\u4e2aSeries\u6216\u4e00\u7cfb\u5217\u503c\uff08\u5982\u603b\u548c\u6216\u5e73\u5747\u503c\uff09\u3002 \u4e0eNumPy\u6570\u7ec4\u4e2d\u7684\u7c7b\u4f3c\u65b9\u6cd5\u76f8\u6bd4\uff0cpandas\u5185\u5efa\u4e86\u5904\u7406\u7f3a\u5931\u503c\u7684\u529f\u80fd\u3002 \u5f52\u7ea6\u65b9\u6cd5: sum() \u79ef\u7d2f\u578b\u65b9\u6cd5: cumsun() \u65e2\u4e0d\u662f\u5f52\u7ea6\u578b\u65b9\u6cd5\u4e5f\u4e0d\u662f\u79ef\u7d2f\u578b\u65b9\u6cd5: describe() df = pd.DataFrame( [[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=list('abcd'), columns=['one', 'two'] ) print(df) # one two # a 1.40 NaN # b 7.10 -4.5 # c NaN NaN # d 0.75 -1.3 # axis=0, \u8fd4\u56de\u4e00\u4e2a\u6bcf\u5217\u7b97\u672f\u548c\u7684Series print(df.sum()) # one 9.25 # two -5.80 # dtype: float64 # axis=1\u4e14skipna=True, \u8fd4\u56de\u4e00\u4e2a\u6bcf\u884c\u548c\u7684Series, \u5ffd\u7565NA\u503c, \u586b0\u3002 print(df.sum(axis=1)) # a 1.40 # b 2.60 # c 0.00 # d -0.55 # dtype: float64 # \u4e0d\u5ffd\u7565NA\u503c\uff0c\u586bNaN\u3002 print(df.sum(axis=1, skipna=False)) # a NaN # b 2.60 # c NaN # d -0.55 # dtype: float64 # \u53ea\u67091\u7ea7\u7d22\u5f15\uff0c\u6240\u4ee5level=0\u548c\u539f\u7d22\u5f15\u6ca1\u6709\u533a\u522b\uff0cNaN\u586b\u51450\u3002 print(df.groupby(level=0).sum()) # one two # a 1.40 0.0 # b 7.10 -4.5 # c 0.00 0.0 # d 0.75 -1.3 # \u5217one\u7684\u6700\u5927\u503c\u662f\u5728\u7d22\u5f15b, \u5217two\u7684\u6700\u5927\u503c\u662f\u5728\u7d22\u5f15d print(df.idxmax()) # one b # two d # dtype: object print(df.idxmin()) # one d # two b # dtype: object # cumsun\u7684\u610f\u601d\u662f\u7b2cn\u6b21\u7684\u548c\u662fn-1\u6b21\u7684\u548c\u4e0en\u7684\u548c\uff0cone\u5217d\u884c\u7684\u548c\u5c31\u662fone\u5217a\u3001b\u3001c\u3001d\u503c\u7684\u603b\u548c\u3002 print(df.cumsum()) # one two # a 1.40 NaN # b 8.50 -4.5 # c NaN NaN # d 9.25 -5.8 \u901a\u8fc7describe\u4ea7\u751f\u7edf\u8ba1\u4fe1\u606f\uff0c\u6ce8\u610f\uff0c\u6570\u503c\u578b\u548c\u975e\u6570\u503c\u578b\u7684describe\u7684\u4fe1\u606f\u662f\u4e0d\u540c\u7684\u3002 # \u4e00\u6b21\u6027\u4ea7\u751f\u591a\u4e2a\u6c47\u603b\u7edf\u8ba1 print(df.describe()) # one two # count 3.000000 2.000000 # mean 3.083333 -2.900000 # std 3.493685 2.262742 # min 0.750000 -4.500000 # 25% 1.075000 -3.700000 # 50% 1.400000 -2.900000 # 75% 4.250000 -2.100000 # max 7.100000 -1.300000 obj = pd.Series(['a', 'a', 'b', 'c'] * 4) print(obj) # 0 a # 1 a # 2 b # 3 c # 4 a # 5 a # 6 b # 7 c # 8 a # 9 a # 10 b # 11 c # 12 a # 13 a # 14 b # 15 c # dtype: object # \u9488\u5bf9\u975e\u6570\u503c\u578b\u6570\u636e\uff0cdescribe\u4ea7\u751f\u53e6\u4e00\u79cd\u6c47\u603b\u7edf\u8ba1 print(obj.describe()) # count 16 # unique 3 # top a # freq 8 # dtype: object \u76f8\u5173\u6027\u548c\u534f\u65b9\u5dee \u00b6 \u534f\u65b9\u5dee\u4e0e\u76f8\u5173\u7cfb\u6570\u4e5f\u662f\u5728\u65f6\u57df\u5206\u6790\u65f6\u5e38\u89c1\u7684\u4e24\u4e2a\u6982\u5ff5\uff0c\u4ed6\u4eec\u90fd\u662f\u7528\u6765\u63cf\u8ff0\u6570\u636e\u201c\u50cf\u4e0d\u50cf\u201d\u7684\u3002 \u534f\u65b9\u5dee\u7684\u901a\u4fd7\u7406\u89e3\uff1a \u4e24\u4e2a\u53d8\u91cf\u5728\u53d8\u5316\u8fc7\u7a0b\u4e2d\u662f\u540c\u65b9\u5411\u53d8\u5316\u8fd8\u662f\u53cd\u65b9\u5411\u53d8\u5316\uff1f\u76f8\u540c\u6216\u8005\u76f8\u53cd\u7a0b\u5ea6\u5982\u4f55\uff1f \u4f60\u53d8\u5927\uff0c\u540c\u65f6\u6211\u53d8\u5927\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u662f\u540c\u5411\u53d8\u5316\uff0c\u8fd9\u65f6\u534f\u65b9\u5dee\u5c31\u662f\u6b63\u7684\u3002 \u4f60\u53d8\u5927\uff0c\u540c\u65f6\u6211\u53d8\u5c0f\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u662f\u53cd\u5411\u53d8\u5316\uff0c\u8fd9\u65f6\u534f\u65b9\u5dee\u5c31\u662f\u8d1f\u7684\u3002 \u4ece\u6570\u503c\u770b\uff0c\u534f\u65b9\u5dee\u7684\u6570\u503c\u8d8a\u5927\uff0c\u4e24\u4e2a\u53d8\u91cf\u540c\u5411\u7a0b\u5ea6\u4e5f\u5c31\u8d8a\u5927\u3002\u53cd\u4e4b\u4ea6\u7136\u3002 \u76f8\u5173\u7cfb\u6570\u7684\u901a\u4fd7\u7406\u89e3\uff1a \u7528X\uff0cY\u7684\u534f\u65b9\u5dee\u9664\u4ee5X\u7684\u6807\u51c6\u5dee\u548cY\u7684\u6807\u51c6\u5dee\u3002\u76f8\u5173\u7cfb\u6570\u4e5f\u53ef\u4ee5\u770b\u6210\u534f\u65b9\u5dee\uff0c\u4e00\u79cd\u63d0\u51fa\u4e86\u4e24\u4e2a\u53d8\u91cf\u91cf\u7eb2\u5f71\u54cd\u3001\u6807\u51c6\u5316\u540e\u7684\u7279\u6b8a\u534f\u65b9\u5dee\u3002\u6240\u4ee5\uff1a\u4e5f\u53ef\u4ee5\u53cd\u6620\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u65f6\u662f\u540c\u5411\u8fd8\u662f\u53cd\u5411\uff0c\u5982\u679c\u540c\u5411\u53d8\u5316\u5c31\u4e3a\u6b63\uff0c\u53cd\u5411\u53d8\u5316\u5c31\u4e3a\u8d1f\u3002 \u7531\u4e8e\u662f\u6807\u51c6\u7248\u540e\u7684\u534f\u65b9\u5dee\uff0c\u76f8\u5173\u7cfb\u6570\u6d88\u9664\u4e86\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u5e45\u5ea6\u7684\u5f71\u54cd\uff0c\u800c\u53ea\u662f\u5355\u7eaf\u53cd\u5e94\u4e24\u4e2a\u53d8\u91cf\u6bcf\u5355\u4f4d\u53d8\u5316\u65f6\u7684\u76f8\u4f3c\u7a0b\u5ea6\u3002 \u603b\u7ed3\uff1a \u5bf9\u4e8e\u4e24\u4e2a\u53d8\u91cfX\u3001Y\uff0c \u5f53\u4ed6\u4eec\u7684\u76f8\u5173\u7cfb\u6570\u4e3a1\u65f6\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u65f6\u7684\u6b63\u5411\u76f8\u4f3c\u5ea6\u6700\u5927\u3002 \u5f53\u4ed6\u4eec\u7684\u76f8\u5173\u7cfb\u6570\u4e3a\uff0d1\u65f6\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u7684\u53cd\u5411\u76f8\u4f3c\u5ea6\u6700\u5927\u3002 \u968f\u7740\u4ed6\u4eec\u76f8\u5173\u7cfb\u6570\u51cf\u5c0f\uff0c\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u65f6\u7684\u76f8\u4f3c\u5ea6\u4e5f\u53d8\u5c0f\uff0c\u5f53\u76f8\u5173\u7cfb\u6570\u4e3a0\u65f6\uff0c\u4e24\u4e2a\u53d8\u91cf\u7684\u53d8\u5316\u8fc7\u7a0b\u6ca1\u6709\u4efb\u4f55\u76f8\u4f3c\u5ea6\uff0c\u4e5f\u5373\u4e24\u4e2a\u53d8\u91cf\u65e0\u5173\u3002 \u5f53\u76f8\u5173\u7cfb\u6570\u7ee7\u7eed\u53d8\u5c0f\uff0c\u5c0f\u4e8e0\u65f6\uff0c\u4e24\u4e2a\u53d8\u91cf\u5f00\u59cb\u51fa\u73b0\u53cd\u5411\u7684\u76f8\u4f3c\u5ea6\uff0c\u968f\u7740\u76f8\u5173\u7cfb\u6570\u7ee7\u7eed\u53d8\u5c0f\uff0c\u53cd\u5411\u76f8\u4f3c\u5ea6\u4f1a\u9010\u6e10\u53d8\u5927\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u4f7f\u7528 pandas-datareader\uff1a https://pypi.org/project/pandas-datareader/ https://pydata.github.io/pandas-datareader/) \u5728\u6240\u6709\u4f8b\u5b50\u4e2d\uff0c\u5728\u8ba1\u7b97\u76f8\u5173\u6027\u4e4b\u524d\uff0c\u6570\u636e\u70b9\u5df2\u7ecf\u6309\u6807\u7b7e\u8fdb\u884c\u4e86\u5bf9\u9f50\u3002 \u4e0b\u4f8b\u9700\u8981\u901a\u8fc7pandas-datareader\u5e93\u4eceYahoo! Finance\u4e0a\u83b7\u53d6\u7684\u5305\u542b\u80a1\u4ef7\u548c\u4ea4\u6613\u91cf\u7684DataFrame\u3002 import pandas_datareader.data as web all_data = { ticker: web.get_data_yahoo(ticker) for ticker in ['AAPL', 'IBM', 'MSFT', 'GOOG'] } price = pd.DataFrame( { ticker: data['Adj Close'] for ticker, data in all_data.items() } ) volume = pd.DataFrame( { ticker: data['Volume'] for ticker, data in all_data.items() } ) returns = price.pct_change() print(returns.tail()) # AAPL IBM MSFT GOOG # Date # 2021-08-09 -0.000342 -0.008424 -0.003904 0.007049 # 2021-08-10 -0.003354 0.000920 -0.006555 0.000685 # 2021-08-11 0.001786 0.005305 0.001781 -0.002947 # 2021-08-12 0.020773 0.006614 0.009967 0.005084 # 2021-08-13 0.001410 0.000769 0.010490 0.000119 Series\u7684corr\u65b9\u6cd5\u8ba1\u7b97\u7684\u662f\u4e24\u4e2aSeries\u4e2d\u91cd\u53e0\u7684\u3001\u975eNA\u7684\u3001\u6309\u7d22\u5f15\u5bf9\u9f50\u7684\u503c\u7684\u76f8\u5173\u6027\u3002\u76f8\u5e94\u5730\uff0ccov\u8ba1\u7b97\u7684\u662f\u534f\u65b9\u5dee print(returns['MSFT']) # Date # 2016-08-15 NaN # 2016-08-16 -0.005540 # 2016-08-17 0.002089 # 2016-08-18 0.000695 # 2016-08-19 0.000347 # ... # 2021-08-09 -0.003904 # 2021-08-10 -0.006555 # 2021-08-11 0.001781 # 2021-08-12 0.009967 # 2021-08-13 0.010490 # Name: MSFT, Length: 1259, dtype: float64 # Series\u7684corr\u65b9\u6cd5\u8ba1\u7b97\u7684\u662f\u4e24\u4e2aSeries\u4e2d\u91cd\u53e0\u7684\u3001\u975eNA\u7684\u3001\u6309\u7d22\u5f15\u5bf9\u9f50\u7684\u503c\u7684\u76f8\u5173\u6027\u3002 print(returns['MSFT'].corr(returns['IBM'])) # 0.5175237180581937 # \u7b49\u540c\u5199\u6cd5\uff0cMSFT\u662f\u4e00\u4e2a\u6709\u6548\u7684Python\u5c5e\u6027 print(returns.MSFT.corr(returns.IBM)) # 0.5175237180581937 # Series\u7684cov\u65b9\u6cd5\u8ba1\u7b97\u7684\u662f\u4e24\u4e2aSeries\u4e2d\u503c\u7684\u534f\u65b9\u5dee\u3002 print(returns['MSFT'].cov(returns['IBM'])) # 0.0001452224236764915 DataFrame\u7684corr\u548ccov\u65b9\u6cd5\u4f1a\u5206\u522b\u4ee5DataFrame\u7684\u5f62\u5f0f\u8fd4\u56de\u76f8\u5173\u6027\u548c\u534f\u65b9\u5dee\u77e9\u9635\u3002 print(returns.corr()) # AAPL IBM MSFT GOOG # AAPL 1.000000 0.441111 0.735539 0.661961 # IBM 0.441111 1.000000 0.517524 0.484230 # MSFT 0.735539 0.517524 1.000000 0.775756 # GOOG 0.661961 0.484230 0.775756 1.000000 # \u7ed9corrwith\u65b9\u6cd5\uff0c\u4f20\u5165\u4e00\u4e2aSeries\u65f6\uff0c\u4f1a\u8fd4\u56de\u4e00\u4e2a\u542b\u6709\u4e3a\u6bcf\u5217\u8ba1\u7b97\u76f8\u5173\u6027\u503c\u7684Series print(returns.corrwith(returns['IBM'])) # AAPL 0.441111 # IBM 1.000000 # MSFT 0.517524 # GOOG 0.484230 # dtype: float64 # \u7ed9corrwith\u65b9\u6cd5\uff0c\u4f20\u5165\u4e00\u4e2aDataFrame\u65f6\uff0c\u4f1a\u8ba1\u7b97\u5339\u914d\u5230\u5217\u540d\u7684\u76f8\u5173\u6027\u6570\u503c\u3002\u4e0b\u9762\u662f\u8ba1\u7b97\u4ea4\u6613\u91cf\u767e\u5206\u6bd4\u53d8\u5316\u7684\u76f8\u5173\u6027 print(returns.corrwith(volume)) # AAPL -0.063111 # IBM -0.103721 # MSFT -0.056842 # GOOG -0.119026 # dtype: float64 print(returns.cov()) # AAPL IBM MSFT GOOG # AAPL 0.000361 0.000137 0.000240 0.000211 # IBM 0.000137 0.000268 0.000145 0.000133 # MSFT 0.000240 0.000145 0.000294 0.000224 # GOOG 0.000211 0.000133 0.000224 0.000282 \u552f\u4e00\u503c\u3001\u8ba1\u6570\u548c\u6210\u5458\u5c5e\u6027 \u00b6 obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c']) print(obj) # 0 c # 1 a # 2 d # 3 a # 4 a # 5 a # 6 b # 7 b # 8 c # 9 c # dtype: object \u51fd\u6570 unique \u7ed9\u51faSeries\u4e2d\u7684\u552f\u4e00\u503c\u3002 print(obj.unique()) # ['c' 'a' 'd' 'b'] print(obj.sort_values().unique()) # ['a' 'b' 'c' 'd'] # value_counts\u8ba1\u7b97Series\u5305\u542b\u7684\u503c\u7684\u4e2a\u6570 print(obj.value_counts()) # a 4 # c 3 # b 2 # d 1 # dtype: int64 # \u8fd9\u91ccvalue_counts\u4e0d\u662fSeries\u7684\u65b9\u6cd5\uff0c\u662fpandas\u9876\u5c42\u65b9\u6cd5 print(pd.value_counts(obj.values, sort=True)) # a 4 # c 3 # b 2 # d 1 # dtype: int64 print(obj.isin(['b', 'c'])) # 0 True # 1 False # 2 False # 3 False # 4 False # 5 False # 6 True # 7 True # 8 True # 9 True # dtype: bool # \u5c06\u4e0a\u9762\u7684\u7ed3\u679c\u4f5c\u4e3a\u5217\u8868\u8f93\u5165\u7684\u6761\u4ef6\uff0c\u8f93\u51fa\u4e3aTrue\u7684\u7ed3\u679c print(obj[obj.isin(['b', 'c'])]) # 0 c # 6 b # 7 b # 8 c # 9 c # dtype: object \u53c2\u8003: pandas.Index.get_indexer obj1 = pd.Series(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c']) obj2 = pd.Series(['c', 'a', 'b']) print(pd.Index(obj1)) # Index(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c'], dtype='object') print(pd.Index(obj2)) # Index(['c', 'a', 'b'], dtype='object') # \u8fd9\u91cc0\u5bf9\u5e94obj2\u91cc\u9762\u7684c\u5728job1\u7684\u4f4d\u7f6e\uff0c\u4ee5\u6b64\u7c7b\u63a8\uff0c\u751f\u6210\u65b0\u7684\u7d22\u5f15\u5217\u8868 print(pd.Index(obj2).get_indexer(obj1)) # [ 0 1 -1 1 1 1 2 2 0 0] \u8ba1\u7b97DataFrame\u591a\u4e2a\u76f8\u5173\u5217\u7684\u76f4\u65b9\u56fe\u3002 data = pd.DataFrame( { 'Que1': [1, 3, 4, 3, 4], 'Que2': [2, 3, 1, 2, 3], 'Que3': [1, 5, 2, 4, 4], } ) print(data) # Que1 Que2 Que3 # 0 1 2 1 # 1 3 3 5 # 2 4 1 2 # 3 3 2 4 # 4 4 3 4 result = data.apply(pd.value_counts).fillna(0) # \u4e0b\u9762\u7ed3\u679c\u4e2d\u7684\u884c\u6807\u7b7e\u662f\u6240\u6709\u5217\u4e2d\u51fa\u73b0\u7684\u4e0d\u540c\u503c\uff0c\u6570\u503c\u5219\u662f\u8fd9\u4e9b\u4e0d\u540c\u503c\u5728\u6bcf\u4e2a\u5217\u4e2d\u51fa\u73b0\u7684\u6b21\u6570\uff0c\u4f8b\u5982\uff1a\u6570\u5b575\u53ea\u5728Que3\u91cc\u9762\u51fa\u73b0\u4e86\u4e00\u6b21 print(result) # Que1 Que2 Que3 # 1 1.0 1.0 1.0 # 2 0.0 2.0 1.0 # 3 2.0 2.0 0.0 # 4 2.0 0.0 2.0 # 5 0.0 0.0 1.0","title":"Pandas\u5165\u95e8"},{"location":"python/DataAnalysis/ch02/#pandas","text":"\u7ea6\u5b9a\uff1a import numpy as np import pandas as pd from pandas import Series, DataFrame import pandas_datareader as web","title":"Pandas\u5165\u95e8"},{"location":"python/DataAnalysis/ch02/#pandas_1","text":"","title":"pandas\u6570\u636e\u7ed3\u6784\u4ecb\u7ecd"},{"location":"python/DataAnalysis/ch02/#series","text":"Series\u662f\u4e00\u79cd\u4e00\u7ef4\u7684\u6570\u7ec4\u578b\u5bf9\u8c61\uff0c\u5b83\u5305\u542b\u4e86\u4e00\u4e2a\u503c\u5e8f\u5217\uff08\u4e0eNumPy\u4e2d\u7684\u7c7b\u578b\u76f8\u4f3c\uff09\uff0c\u5e76\u4e14\u5305\u542b\u4e86\u6570\u636e\u6807\u7b7e\uff0c\u79f0\u4e3a**\u7d22\u5f15\uff08index\uff09 \u3002 \u4ece\u53e6\u4e00\u4e2a\u89d2\u5ea6\u8003\u8651Series\uff0c\u53ef\u4ee5\u8ba4\u4e3a\u5b83\u662f\u4e00\u4e2a**\u957f\u5ea6\u56fa\u5b9a\u4e14\u6709\u5e8f\u7684\u5b57\u5178 \uff0c\u56e0\u4e3a\u5b83\u5c06\u7d22\u5f15\u503c\u548c\u6570\u636e\u503c\u6309\u4f4d\u7f6e\u914d\u5bf9\u3002\u7d22\u5f15\u5728\u5de6\u8fb9\uff0c\u503c\u5728\u53f3\u8fb9\u3002 obj = pd.Series([4, 7, -5, 3]) print(obj) # 0 4 # 1 7 # 2 -5 # 3 3 # dtype: int64 print(obj.values) # [ 4 7 -5 3 print(obj.index) # RangeIndex(start=0, stop=4, step=1) \u81ea\u5b9a\u4e49index obj = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c']) print(obj) # d 4 # b 7 # a -5 # c 3 # dtype: int64 print(obj.values) # [ 4 7 -5 3] print(obj.index) # Index(['d', 'b', 'a', 'c'], dtype='object') # \u8f93\u51fa\u7d22\u5f15\u503c\u4e3a'a'\u7684Series\u503c print(obj['a']) # -5 # \u4f7f\u7528\u5e03\u5c14\u503c\u6570\u7ec4\u8fdb\u884c\u8fc7\u6ee4Series\u503c print(obj[obj > 3]) # d 4 # b 7 # dtype: int64 # \u5bf9Series\u503c\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97 print(obj * 2) # d 8 # b 14 # a -10 # c 6 # dtype: int64 # \u5bf9Series\u503c\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97 print(np.exp(obj)) # d 54.598150 # b 1096.633158 # a 0.006738 # c 20.085537 # dtype: float64 # \u66f4\u65b0Series\u6570\u7ec4\u503c obj['a'] = 9 # \u8f93\u51fa\u6307\u5b9a\u7d22\u5f15\u503c\u7684Series\u503c\uff0c\u6ce8\u610f\uff0c\u7d22\u5f15\u6761\u4ef6\u662f\u5217\u8868 print(obj[['a', 'b', 'c']]) # a 9 # b 7 # c 3 # dtype: int64 # \u6ce8\u610f\uff0c\u4e0b\u9762\u7684\u5224\u65ad\u662f\u7d22\u5f15\u503c\uff0c\u975eSeries\u503c print(obj) print(7 in obj) # False print('a' in obj) # True \u901a\u8fc7\u5b57\u5178\u751f\u6210\u4e00\u4e2aSeries\u3002 NaN \uff08not a number\uff09\uff0c\u8fd9\u662fpandas\u4e2d\u6807\u8bb0\u7f3a\u5931\u503c\u6216NA\u503c\u7684\u65b9\u5f0f\u3002 \u5f53\u628a\u5b57\u5178\u4f20\u9012\u7ed9Series\u6784\u9020\u51fd\u6570\u65f6\uff0c\u4ea7\u751f\u7684Series\u7684\u7d22\u5f15\u5c06\u662f\u6392\u5e8f\u597d\u7684\u5b57\u5178\u952e\u3002\u53ef\u4ee5\u5c06\u5b57\u5178\u952e\u6309\u7167\u4f60\u6240\u60f3\u8981\u7684\u987a\u5e8f\u4f20\u9012\u7ed9\u6784\u9020\u51fd\u6570\uff0c\u4ece\u800c\u4f7f\u751f\u6210\u7684Series\u7684\u7d22\u5f15\u987a\u5e8f\u7b26\u5408\u9884\u671f\u3002 \u770b\u4e0b\u4f8b\uff0c\u901a\u8fc7\u5b57\u5178sdata\u751f\u6210Series\u3002 sdata = {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000} obj3 = pd.Series(sdata) print(sdata) # {'Ohio': 35000, 'Texas': 71000, 'Oregon': 16000, 'Utah': 5000} print(obj3) # Ohio 35000 # Texas 71000 # Oregon 16000 # Utah 5000 # dtype: int64 \u901a\u8fc7\u6307\u5b9a\u7d22\u5f15states\u53bb\u5339\u914d\u5b57\u5178sdata\u751f\u6210\u57fa\u4e8e\u65b0\u7d22\u5f15states\u7684Series\u3002 states = ['California', 'Ohio', 'Oregon', 'Texas'] obj4 = pd.Series(sdata, index=states) print(obj4) # California NaN # Ohio 35000.0 # Oregon 16000.0 # Texas 71000.0 # dtype: float64 \u5bf9Series\u8fdb\u884c\u5e03\u5c14\u503c\u5224\u65ad\u3002 print(pd.isnull(obj4)) # California True # Ohio False # Oregon False # Texas False # dtype: bool print(pd.notnull(obj4)) # California False # Ohio True # Oregon True # Texas True # dtype: bool \u5bf9Series\u8fdb\u884c\u5e03\u5c14\u503c\u5224\u65ad\u3002 print(obj4.isnull) # print(obj4.notnull) # Series\u7684\u81ea\u52a8\u5bf9\u9f50\u7d22\u5f15\uff0c\u4e0e\u6570\u636e\u5e93\u7684join\u64cd\u4f5c\u662f\u975e\u5e38\u76f8\u4f3c\u3002 print(\"obj3 \\n\", obj3) # obj3 # Ohio 35000 # Texas 71000 # Oregon 16000 # Utah 5000 # dtype: int64 print(\"obj4 \\n\", obj4) # obj4 # California NaN # Ohio 35000.0 # Oregon 16000.0 # Texas 71000.0 # dtype: float64 print(\"obj3+obj4 \\n\", obj3 + obj4) # obj3+obj4 # California NaN # Ohio 70000.0 # Oregon 32000.0 # Texas 142000.0 # Utah NaN # dtype: float64 # \u4e0b\u9762\u662fobj3\u548cobj4\u7684\u503c\uff0c\u5e2e\u52a9\u7406\u89e3\u4e0a\u9762obj3 + obj4\u7684\u64cd\u4f5c\u3002 # obj3 obj4 # Ohio 35000 California NaN # Texas 71000 Ohio 35000.0 # Oregon 16000 Oregon 16000.0 # Utah 5000 Texas 71000.0 # dtype: int64 dtype: float64 Series\u5bf9\u8c61\u81ea\u8eab\u548c\u5176\u7d22\u5f15\u90fd\u6709name\u5c5e\u6027\u3002 obj4.name = 'population' obj4.index.name = 'state' print(obj4) # state # California NaN # Ohio 35000.0 # Oregon 16000.0 # Texas 71000.0 # Name: population, dtype: float64 \u66ff\u6362Series\u7684\u7d22\u5f15\u540d\u3002 obj = pd.Series([4, 7, -5, 3], index=['d', 'b', 'a', 'c']) print(obj) obj.index = ['Bob', 'Steve', 'Jeff', 'Ryan'] print(obj) # Bob 4 # Steve 7 # Jeff -5 # Ryan 3 # dtype: int64","title":"Series"},{"location":"python/DataAnalysis/ch02/#dataframe","text":"DataFrame\u8868\u793a\u7684\u662f\u77e9\u9635\u7684\u6570\u636e\u8868\uff0c\u5b83\u5305\u542b\u5df2\u6392\u5e8f\u7684\u5217\u96c6\u5408\uff0c\u6bcf\u4e00\u5217\u53ef\u4ee5\u662f\u4e0d\u540c\u7684\u503c\u7c7b\u578b\uff08\u6570\u503c\u3001\u5b57\u7b26\u4e32\u3001\u5e03\u5c14\u503c\u7b49\uff09\u3002 DataFrame\u65e2\u6709\u884c\u7d22\u5f15\u4e5f\u6709\u5217\u7d22\u5f15\uff0c\u5b83\u53ef\u4ee5\u88ab\u89c6\u4e3a\u4e00\u4e2a\u5171\u4eab\u76f8\u540c\u7d22\u5f15\u7684Series\u7684\u5b57\u5178\uff0c\u6bd4\u5982\u6240\u6709\u5217\u5171\u4eab\u540c\u4e00\u4e2a\u5217\u7d22\u5f15\u3002 \u5728DataFrame\u4e2d\uff0c\u6570\u636e\u88ab\u5b58\u50a8\u4e3a\u4e00\u4e2a\u4ee5\u4e0a\u7684\u4e8c\u7ef4\u5757\uff0c\u800c\u4e0d\u662f\u5217\u8868\u3001\u5b57\u5178\u6216\u5176\u4ed6\u4e00\u7ef4\u6570\u7ec4\u7684\u96c6\u5408\u3002 DataFrame\u662f\u4e8c\u7ef4\u7684\uff0c\u4f46\u53ef\u4ee5\u5229\u7528**\u5206\u5c42\u7d22\u5f15**\u5728DataFrame\u4e2d\u5c55\u73b0\u66f4\u9ad8\u7ef4\u5ea6\u7684\u6570\u636e\u3002 \u4eceDataFrame\u4e2d\u9009\u53d6\u7684\u5217\u662f\u6570\u636e\u7684\u89c6\u56fe\uff0c\u800c\u4e0d\u662f\u62f7\u8d1d \u3002\u56e0\u6b64\uff0c\u5bf9Series\u7684\u4fee\u6539\u4f1a\u6620\u5c04\u5230DataFrame\u4e2d\u3002\u5982\u679c\u9700\u8981\u590d\u5236\uff0c\u5219\u5e94\u5f53\u663e\u5f0f\u5730\u4f7f\u7528Series\u7684copy\u65b9\u6cd5\u3002","title":"DataFrame"},{"location":"python/DataAnalysis/ch02/#dataframe_1","text":"\u57fa\u4e8e\u5b57\u5178 data \u4ea7\u751f\u7684DataFrame\u4f1a\u81ea\u52a8\u4e3aSereies\u5206\u914d\u7d22\u5f15\uff0c\u5e76\u4e14\u5217\u4f1a\u6309\u7167\u6392\u5e8f\u7684\u987a\u5e8f\u6392\u5217\u3002 data = { 'state': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], 'year': [2000, 2001, 2002, 2001, 2002, 2003], 'pop': [1.5, 1.7, 3.6, 2.4, 2.9, 3.2] } frame = pd.DataFrame(data) print(frame) # state year pop # 0 Ohio 2000 1.5 # 1 Ohio 2001 1.7 # 2 Ohio 2002 3.6 # 3 Nevada 2001 2.4 # 4 Nevada 2002 2.9 # 5 Nevada 2003 3.2 # \u5bf9\u4e8e\u5927\u578bDataFrame, head\u65b9\u6cd5\u5c06\u4f1a\u53ea\u9009\u51fa\u5934\u90e8\u7684\u82e5\u5e72\u884c, \u9ed8\u8ba4\u662f\u524d\u4e94\u884c\u3002 print(frame.head(3)) # state year pop # 0 Ohio 2000 1.5 # 1 Ohio 2001 1.7 # 2 Ohio 2002 3.6 \u5982\u679c\u6307\u5b9a\u4e86\u5217\u7684\u987a\u5e8f\uff0cDataFrame\u7684\u5217\u5c06\u4f1a\u6309\u7167\u6307\u5b9a\u987a\u5e8f\u6392\u5217\u3002 frame = pd.DataFrame(data, columns=['year', 'state', 'pop']) print(frame) # year state pop # 0 2000 Ohio 1.5 # 1 2001 Ohio 1.7 # 2 2002 Ohio 3.6 # 3 2001 Nevada 2.4 # 4 2002 Nevada 2.9 # 5 2003 Nevada 3.2 \u5982\u679c\u4f20\u7684\u5217\uff08 debt \uff09\u4e0d\u5305\u542b\u5728\u5b57\u5178\uff08 data \uff09\u4e2d\uff0c\u5c06\u4f1a\u5728\u7ed3\u679c\u4e2d\u51fa\u73b0\u7f3a\u5931\u503c\u3002 frame2 = pd.DataFrame( data, columns=['year', 'state', 'pop', 'debt'], index=['one', 'two', 'three', 'four', 'five', 'six'] ) print(frame2) # year state pop debt # one 2000 Ohio 1.5 NaN # two 2001 Ohio 1.7 NaN # three 2002 Ohio 3.6 NaN # four 2001 Nevada 2.4 NaN # five 2002 Nevada 2.9 NaN # six 2003 Nevada 3.2 NaN \u9009\u53d6\u884c, \u53ef\u4ee5\u901a\u8fc7\u4f4d\u7f6e\u6216\u884c\u7d22\u5f15\u6807\u7b7e loc \u8fdb\u884c\u9009\u53d6\u3002 print(frame2.loc['three']) # year 2002 # state Ohio # pop 3.6 # debt NaN # Name: three, dtype: object DataFrame\u4e2d\u7684\u4e00\u5217\uff0c\u53ef\u4ee5\u6309\u5b57\u5178\u578b\u6807\u8bb0\u6216\u5c5e\u6027\u90a3\u6837\u68c0\u7d22\u4e3aSeries\u3002 frame2[colunm] \u5bf9\u4e8e\u4efb\u610f\u5217\u540d\u5747\u6709\u6548\uff0c\u4f46\u662f frame2.column \u53ea\u5728\u5217\u540d\u662f\u6709\u6548\u7684Python\u53d8\u91cf\u540d\u65f6\u6709\u6548\u3002 \u8fd4\u56de\u7684Series\u4e0e\u539fDataFrame\u6709\u76f8\u540c\u7684\u7d22\u5f15\uff0c\u4e14Series\u7684 name \u5c5e\u6027\u4e5f\u4f1a\u88ab\u5408\u7406\u5730\u8bbe\u7f6e\u3002 print(frame2['state']) # one Ohio # two Ohio # three Ohio # four Nevada # five Nevada # six Nevada # Name: state, dtype: object print(frame2.state) # \u5c5e\u6027\u578b\u8fde\u63a5 # one Ohio # two Ohio # three Ohio # four Nevada # five Nevada # six Nevada # Name: state, dtype: object \u5217\u7684\u5f15\u7528\u662f\u53ef\u4ee5\u4fee\u6539\u7684\u3002\u503c\u7684\u957f\u5ea6\u5fc5\u987b\u548cDataFrame\u7684\u957f\u5ea6\u76f8\u5339\u914d,\u6bd4\u5982\uff0c\u4e0b\u4f8b\u4e2d np.arange(6.) \u548c frame2['debt'] \u7684\u957f\u5ea6\u90fd\u662f6\u3002 frame2['debt'] = 16.5 print(frame2) # Name: state, dtype: object # year state pop debt # one 2000 Ohio 1.5 16.5 # two 2001 Ohio 1.7 16.5 # three 2002 Ohio 3.6 16.5 # four 2001 Nevada 2.4 16.5 # five 2002 Nevada 2.9 16.5 # six 2003 Nevada 3.2 16.5 frame2['debt'] = np.arange(6.) print(frame2) # year state pop debt # one 2000 Ohio 1.5 0.0 # two 2001 Ohio 1.7 1.0 # three 2002 Ohio 3.6 2.0 # four 2001 Nevada 2.4 3.0 # five 2002 Nevada 2.9 4.0 # six 2003 Nevada 3.2 5.0 \u5982\u679c\u5c06Series\u8d4b\u503c\u7ed9\u4e00\u5217\u65f6\uff0cSeries\u7684\u7d22\u5f15\u5c06\u4f1a\u6309\u7167DataFrame\u7684\u7d22\u5f15\u91cd\u65b0\u6392\u5217\uff0c\u5e76\u5728\u7a7a\u7f3a\u7684\u5730\u65b9\u586b\u5145\u7f3a\u5931\u503c val = pd.Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five']) frame2['debt'] = val print(frame2) # year state pop debt # one 2000 Ohio 1.5 NaN # two 2001 Ohio 1.7 -1.2 # three 2002 Ohio 3.6 NaN # four 2001 Nevada 2.4 -1.5 # five 2002 Nevada 2.9 -1.7 # six 2003 Nevada 3.2 NaN \u5982\u679c\u88ab\u8d4b\u503c\u7684\u5217( eastern \u5217)\u5e76\u4e0d\u5b58\u5728\uff0c\u5219\u4f1a\u751f\u6210\u4e00\u4e2a\u65b0\u7684\u5217\u3002 frame2.state == 'Ohio' \u8fd4\u56de\u7684\u662f\u5e03\u5c14\u503c\uff0c\u8d4b\u503c\u7ed9 eastern \u3002 frame2['eastern'] = frame2.state == 'Ohio' print(frame2) # year state pop debt eastern # one 2000 Ohio 1.5 NaN True # two 2001 Ohio 1.7 -1.2 True # three 2002 Ohio 3.6 NaN True # four 2001 Nevada 2.4 -1.5 False # five 2002 Nevada 2.9 -1.7 False # six 2003 Nevada 3.2 NaN False print(frame2.eastern) # one True # two True # three True # four False # five False # six False # Name: eastern, dtype: bool del \u5173\u952e\u5b57\u53ef\u4ee5\u50cf\u5728\u5b57\u5178\u4e2d\u90a3\u6837\u5bf9DataFrame\u5220\u9664\u5217\u3002 del frame2['eastern'] print(frame2.columns) # Index(['year', 'state', 'pop', 'debt'], dtype='object')","title":"\u7531\u5b57\u5178\u6784\u6210DataFrame"},{"location":"python/DataAnalysis/ch02/#dataframe_2","text":"pandas\u4f1a\u5c06\u5b57\u5178\u7684\u952e\u4f5c\u4e3a\u5217('Nevada', etc.)\uff0c\u5c06\u5185\u90e8\u5b57\u5178\u7684\u952e\u4f5c\u4e3a\u884c\u7d22\u5f15(2001, etc.) pop = { 'Nevada': { 2001: 2.4, 2002: 2.9 }, 'Ohio': { 2000: 1.5, 2001: 1.7, 2002: 3.6 } } # \u4e0d\u6307\u5b9a\u7d22\u5f15\uff0c\u9ed8\u8ba4\u4f7f\u7528\u5b57\u5178\u7d22\u5f15 frame3 = pd.DataFrame(pop) print(frame3) # Nevada Ohio # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 # \u6307\u5b9a\u5b57\u5178\u67d0\u5217\u4f5c\u4e3a\u7d22\u5f15 print(pd.DataFrame(pop, index=[2001, 2002, 2003])) # Nevada Ohio # 2001 2.4 1.7 # 2002 2.9 3.6 # 2003 NaN NaN # \u6307\u5b9a\u4e0d\u76f8\u5e72\u7d22\u5f15 print(pd.DataFrame(pop, index=['a', 'b', 'c'])) # Nevada Ohio # a NaN NaN # b NaN NaN # c NaN NaN \u8f6c\u7f6e\u64cd\u4f5c\uff08\u8c03\u6362\u884c\u548c\u5217\uff09 print(frame3.T) # 2001 2002 2000 # Nevada 2.4 2.9 NaN # Ohio 1.7 3.6 1.5","title":"\u4f7f\u7528\u5d4c\u5957\u5b57\u5178\u6784\u5efaDataFrame"},{"location":"python/DataAnalysis/ch02/#seriesdataframe","text":"frame3['Ohio'][:-1] \u662f\u503c\u4e3a Ohio \u7684Series\u76840~\u5012\u6570\u7b2c\u4e00\u4e2a\u5143\u7d20\uff08\u4e0d\u542b\uff09\uff0c\u4e00\u51713\u4e2a\u3002 frame3['Nevada'][:2] \u662f\u503c\u4e3a Nevada \u7684Series\u7684\u524d2\u4e2a\u5143\u7d20\u3002 pdata = { 'Ohio': frame3['Ohio'][:-1], 'Nevada': frame3['Nevada'][:2] } print(pd.DataFrame(pdata)) # Ohio Nevada # 2001 1.7 2.4 # 2002 3.6 2.9 \u6307\u5b9aDataframe frame3 \u7684\u5217\u540d\u3002 frame3.index.name = 'year' frame3.columns.name = 'state' print(frame3) # state Nevada Ohio # year # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 \u53ea\u8f93\u51faDataframe\u7684\u503c frame3.values \uff0c\u662f\u4e00\u4e2a\u4e8c\u7ef4\u6570\u7ec4\u3002 print(frame3.values) # [[2.4 1.7] # [2.9 3.6] # [nan 1.5]] \u53ea\u8f93\u51faDataframe\u7684\u503c frame2.values \uff0c\u662f\u4e00\u4e2a\u4e8c\u7ef4\u6570\u7ec4\u3002 print(frame2) # year state pop debt # one 2000 Ohio 1.5 NaN # two 2001 Ohio 1.7 -1.2 # three 2002 Ohio 3.6 NaN # four 2001 Nevada 2.4 -1.5 # five 2002 Nevada 2.9 -1.7 # six 2003 Nevada 3.2 NaN print(frame2.values) # [[2000 'Ohio' 1.5 nan] # [2001 'Ohio' 1.7 -1.2] # [2002 'Ohio' 3.6 nan] # [2001 'Nevada' 2.4 -1.5] # [2002 'Nevada' 2.9 -1.7] # [2003 'Nevada' 3.2 nan]]","title":"\u4f7f\u7528\u542bSeries\u7684\u5b57\u5178\u6784\u9020DataFrame"},{"location":"python/DataAnalysis/ch02/#_1","text":"pandas\u4e2d\u7684**\u7d22\u5f15\u5bf9\u8c61**\u662f\u7528\u4e8e\u5b58\u50a8\u8f74\u6807\u7b7e\u548c\u5176\u4ed6\u5143\u6570\u636e\u7684\uff08\u4f8b\u5982\u8f74\u540d\u79f0\u6216\u6807\u7b7e\uff09\u3002 \u5728\u6784\u9020Series\u6216DataFrame\u65f6\uff0c\u4f60\u6240\u4f7f\u7528\u7684\u4efb\u610f\u6570\u7ec4\u6216\u6807\u7b7e\u5e8f\u5217\u90fd\u53ef\u4ee5\u5728\u5185\u90e8\u8f6c\u6362\u4e3a\u7d22\u5f15\u5bf9\u8c61\u3002 \u7d22\u5f15\u5bf9\u8c61\u662f\u4e0d\u53ef\u53d8\u7684\u3002 \u9664\u4e86\u7c7b\u4f3c\u6570\u7ec4\uff0c\u7d22\u5f15\u5bf9\u8c61\u4e5f\u50cf\u4e00\u4e2a\u56fa\u5b9a\u5927\u5c0f\u7684\u96c6\u5408\u3002\u4e0ePython\u96c6\u5408\u4e0d\u540c\uff0c pandas\u7d22\u5f15\u5bf9\u8c61\u53ef\u4ee5\u5305\u542b\u91cd\u590d\u6807\u7b7e \u3002 \u56e0\u4e3a\u4e00\u4e9b\u64cd\u4f5c\u4f1a\u4ea7\u751f\u5305\u542b\u7d22\u5f15\u5316\u6570\u636e\u7684\u7ed3\u679c\uff0c\u7406\u89e3\u7d22\u5f15\u5982\u4f55\u5de5\u4f5c\u8fd8\u662f\u5f88\u91cd\u8981\u7684\u3002 \u4e0b\u4f8b\u6f14\u793a\u4e86\u5982\u4f55\u8bfb\u53d6Dataframe\u7684\u7d22\u5f15\u503c\u3002 obj = pd.Series(range(3), index=['a', 'b', 'c']) index = obj.index print(obj) # a 0 # b 1 # c 2 # dtype: int64 print(index) # Index(['a', 'b', 'c'], dtype='object') print(index[1:]) # Index(['b', 'c'], dtype='object') \u4e0b\u4f8b\u6f14\u793a\u4e86\u901a\u8fc7\u4e00\u4e2a\u6307\u5b9a\u7684Dataframe\u7d22\u5f15 labels \u6765\u751f\u6210Dataframe obj2 \u3002 labels = pd.Index(np.arange(3)) print(labels) # Int64Index([0, 1, 2], dtype='int64') obj2 = pd.Series([1.5, -2.5, 0], index=labels) print(obj2) # 0 1.5 # 1 -2.5 # 2 0.0 # dtype: float64 print(obj2.index is labels) # True \u4e0b\u4f8b\u6f14\u793a\u4e86\u4e0d\u6307\u5b9a\u7d22\u5f15\uff0c\u9ed8\u8ba4\u4f7f\u7528\u5b57\u5178\u7d22\u5f15\u6765\u521b\u5efaDataframe\u3002 pop = { 'Nevada': { 2001: 2.4, 2002: 2.9 }, 'Ohio': { 2000: 1.5, 2001: 1.7, 2002: 3.6 } } frame3 = pd.DataFrame(pop) print(frame3) # Nevada Ohio # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 print(frame3) # state Nevada Ohio # year # 2001 2.4 1.7 # 2002 2.9 3.6 # 2000 NaN 1.5 print(frame3.columns) # Index(['Nevada', 'Ohio'], dtype='object', name='state') print(frame3.index) # Int64Index([2001, 2002, 2000], dtype='int64', name='year') print('Ohio' in frame3.columns) # True print(2003 in frame3.index) # False pandas\u7d22\u5f15\u5bf9\u8c61\u5141\u8bb8\u5305\u542b\u91cd\u590d\u6807\u7b7e\u3002\u6839\u636e\u91cd\u590d\u6807\u7b7e\u8fdb\u884c\u7b5b\u9009\uff0c\u4f1a\u9009\u53d6\u6240\u6709\u91cd\u590d\u6807\u7b7e\u5bf9\u5e94\u7684\u6570\u636e\u3002 dup_labels = pd.Index(['foo', 'foo', 'bar', 'bar']) print(dup_labels) # Index(['foo', 'foo', 'bar', 'bar'], dtype='object') \u4e00\u4e9b\u5e38\u7528\u7d22\u5f15\u5bf9\u8c61\u7684\u65b9\u6cd5\u548c\u5c5e\u6027\u3002 obj1 = pd.Series(range(3), index=['a', 'b', 'c']) index1 = obj1.index obj2 = pd.Series(range(3), index=['c', 'f', 'g']) index2 = obj2.index print(index1) # Index(['a', 'b', 'c'], dtype='object') print(index2) # Index(['c', 'f', 'g'], dtype='object') append \u65b9\u6cd5\uff1a\u5c06\u5916\u90e8\u7684\u7d22\u5f15\u5bf9\u8c61\u7c98\u8d34\u5230\u539f\u7d22\u5f15\u540e\uff0c\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684\u7d22\u5f15\u3002 \u63a5\u4e0a\u4f8b\uff0c\u628a index2 \u5bf9\u8c61\u8ffd\u52a0\u5230 index1 \u5bf9\u8c61\u3002 print(index1.append(index2)) # Index(['a', 'b', 'c', 'c', 'f', 'g'], dtype='object') difference \u65b9\u6cd5: \u8ba1\u7b972\u4e2a\u7d22\u5f15\u7684\u5dee\u96c6\u3002 print(index1.difference(index2)) # Index(['a', 'b'], dtype='object') intersection \u65b9\u6cd5: \u8ba1\u7b972\u4e2a\u7d22\u5f15\u7684\u4ea4\u96c6\u3002 print(index1.intersection(index2)) # Index(['c'], dtype='object') union \u65b9\u6cd5: \u8ba1\u7b972\u4e2a\u7d22\u5f15\u7684\u5e76\u96c6\uff08\u53bb\u91cd\uff09\u3002 print(index1.union(index2)) # Index(['a', 'b', 'c', 'f', 'g'], dtype='object') isin \u65b9\u6cd5: \u8ba1\u7b97\u8868\u793a\u6bcf\u4e00\u4e2a\u503c\u662f\u5426\u5728\u4f20\u503c\u5bb9\u5668\u4e2d\uff0c\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u5e03\u5c14\u6570\u7ec4\u3002 print(index1.isin(index2)) # [False False True] delete \u65b9\u6cd5: \u5c06\u4f4d\u7f6ei\uff08\u4ece0\u5f00\u59cb\u7f16\u53f7\uff09\u7684\u5143\u7d20\u5220\u9664\uff0c\u5e76\u4ea7\u751f\u65b0\u7684\u7d22\u5f15\u3002 print(index1.delete('b')) # IndexError: arrays used as indices must be of integer (or boolean) type print(index1.delete(1)) # Index(['a', 'c'], dtype='object') print(index1) # Index(['a', 'b', 'c'], dtype='object') drop \u65b9\u6cd5: \u6839\u636e\u4f20\u53c2\u5220\u9664\u6307\u5b9a\u7d22\u5f15\u503c\uff0c\u5e76\u4ea7\u751f\u65b0\u7684\u7d22\u5f15, \u5bf9\u6bd4\u548cdelete\u7684\u533a\u522b\uff0c delete \u65b9\u6cd5\u662f\u8f93\u5165\u4f4d\u7f6e\uff0c drop \u65b9\u6cd5\u662f\u8f93\u5165\u7d22\u5f15\u540d\u79f0\u3002 print(index2.drop(1)) # KeyError: '[1] not found in axis' print(index2.drop('f')) # Index(['c', 'g'], dtype='object') print(index2) # Index(['c', 'f', 'g'], dtype='object') insert \u65b9\u6cd5: \u5728\u4f4d\u7f6e i \u63d2\u5165\u5143\u7d20\uff0c\u5e76\u4ea7\u751f\u65b0\u7684\u7d22\u5f15\u3002 print(index1.insert(1, 'e')) # Index(['a', 'e', 'b', 'c'], dtype='object') print(index1) # Index(['a', 'b', 'c'], dtype='object') is_monotonic \u65b9\u6cd5: \u5982\u679c\u7d22\u5f15\u5e8f\u5217\u9012\u589e\uff0c\u5219\u8fd4\u56de True \u3002 print(index1.is_monotonic) # True print(index1.insert(1, 'e').is_monotonic) # False is_unique \u65b9\u6cd5: \u5982\u679c\u7d22\u5f15\u5e8f\u5217\u552f\u4e00\u5219\u8fd4\u56de True \u3002 print(index1.is_unique) # True print(index1.append(index2).is_unique) # False unique \u65b9\u6cd5: \u8ba1\u7b97\u7d22\u5f15\u7684\u552f\u4e00\u503c\u5e8f\u5217\uff08\u5bf9\u6bd4Union\uff09\u3002 print(index1.unique()) # Index(['a', 'b', 'c'], dtype='object') print(index1.append(index2).unique()) # Index(['a', 'b', 'c', 'f', 'g'], dtype='object')","title":"\u7d22\u5f15\u5bf9\u8c61"},{"location":"python/DataAnalysis/ch02/#pandas_2","text":"","title":"pandas\u57fa\u672c\u529f\u80fd"},{"location":"python/DataAnalysis/ch02/#_2","text":"Series\u8c03\u7528 reindex \u65b9\u6cd5\u65f6\uff0c\u4f1a\u5c06\u6570\u636e\u6309\u7167\u65b0\u7684\u7d22\u5f15\u8fdb\u884c\u6392\u5217\uff0c\u5982\u679c\u67d0\u4e2a\u7d22\u5f15\u503c\u4e4b\u524d\u5e76\u4e0d\u5b58\u5728\uff0c\u5219\u4f1a\u5f15\u5165\u7f3a\u5931\u503c\u3002 \u4e0b\u4f8b\u4e2d\uff0c\u5bf9 obj1 \u505a reindex \uff0c reindex \u65b9\u6cd5\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7d22\u5f15\u5bf9\u8c61 obj2 \uff0c\u7d22\u5f15\u503c e \u4e4b\u524d\u5e76\u4e0d\u5b58\u5728\uff0c\u6240\u4ee5\u586b\u5165\u7f3a\u5931\u503c\u3002 \u5982\u679c\u5bf9obj1\u505a reindex \u65f6\u6307\u5b9a method='ffill' \uff0c\u4f1a\u62a5\u9519 index must be monotonic increasing or decreasing \u3002 obj1 = pd.Series([4.5, 7.2, -5.3, 3.6], index=['d', 'b', 'a', 'c']) print(obj1) # d 4.5 # b 7.2 # a -5.3 # c 3.6 # dtype: float64 obj2 = obj1.reindex(['a', 'b', 'c', 'd', 'e']) print(obj2) # a -5.3 # b 7.2 # c 3.6 # d 4.5 # e NaN # dtype: float64 obj2 = obj1.reindex(['a', 'b', 'c', 'd', 'e'], method='ffill') # ValueError: index must be monotonic increasing or decreasing \u5bf9\u4e8e\u987a\u5e8f\u6570\u636e\uff0c\u6bd4\u5982\u65f6\u95f4\u5e8f\u5217\uff0c\u5728\u91cd\u5efa\u7d22\u5f15\u65f6\u53ef\u80fd\u4f1a\u9700\u8981\u8fdb\u884c\u63d2\u503c\u6216\u586b\u503c\u3002 ffill \u65b9\u6cd5\u5728\u91cd\u5efa\u7d22\u5f15\u65f6\u63d2\u503c\uff0c\u5c06\u503c\u524d\u5411\u586b\u5145\u3002 obj3 = pd.Series(['blue', 'purple', 'yellow'], index=[0, 2, 4]) print(obj3.reindex(range(6), method='ffill')) # 0 blue # 1 blue # 2 purple # 3 purple # 4 yellow # 5 yellow # dtype: object \u5728DataFrame\u4e2d\uff0c reindex \u53ef\u4ee5\u6539\u53d8\u884c\u7d22\u5f15\u3001\u5217\u7d22\u5f15\uff0c\u4e5f\u53ef\u4ee5\u540c\u65f6\u6539\u53d8\u4e8c\u8005\u3002\u5f53\u4ec5\u4f20\u5165\u4e00\u4e2a\u5e8f\u5217\u65f6\uff0c\u4f1a\u91cd\u5efa\u884c\u7d22\u5f15\u3002 \u4e0b\u4f8b\u4e2d\uff0c\u901a\u8fc7 indexes \u521b\u5efaDataframe frame \u3002 \u901a\u8fc7 frame.reindex(['a', 'b', 'c', 'd'])\u91cd\u5efa\u884c\u7d22\u5f15 \u3002 \u901a\u8fc7 frame2.reindex(columns=['Ohio', 'Uta', 'California']) \u91cd\u5efa\u5217\u7d22\u5f15\u3002 \u7f3a\u5931\u7684\u7d22\u5f15\u5217\u586b\u5165\u7f3a\u5931\u503c\u3002 indexes = index = ['a', 'b', 'c'] states = ['Ohio', 'Texas', 'California'] frame = pd.DataFrame( np.arange(9).reshape(3, 3), index=indexes, columns=states ) print(frame) # Ohio Texas California # a 0 1 2 # b 3 4 5 # c 6 7 8 frame2 = frame.reindex(['a', 'b', 'c', 'd']) # \u91cd\u5efa\u884c\u7d22\u5f15 print(frame2) # Ohio Texas California # a 0.0 1.0 2.0 # b 3.0 4.0 5.0 # c 6.0 7.0 8.0 # d NaN NaN NaN frame3 = frame2.reindex(columns=['Ohio', 'Uta', 'California']) # \u91cd\u5efa\u5217\u7d22\u5f15 print(frame3) # Ohio Uta California # a 0.0 NaN 2.0 # b 3.0 NaN 5.0 # c 6.0 NaN 8.0 # d NaN NaN NaN \u4f7f\u7528 loc \u8fdb\u884c\u66f4\u4e3a\u7b80\u6d01\u7684\u884c\u3001\u5217\u6807\u7b7e\u7d22\u5f15\u3002\u4e0b\u4f8b\u901a\u8fc7\u7b5b\u9009\u884c\u7d22\u5f15\u548c\u5217\u7d22\u5f15\u4ea7\u751f\u65b0\u7684Dataframe\u3002 frame4 = frame.loc[['a', 'b'], states] print(frame4) # Ohio Texas California # a 0 1 2 # b 3 4 5","title":"\u91cd\u5efa\u7d22\u5f15"},{"location":"python/DataAnalysis/ch02/#_3","text":"set_index() , dropna() , fillna() , reset_index() , drop() , replace() \u8fd9\u4e9b\u65b9\u6cd5\u7684 inplace \u5c5e\u6027\u8bbe\u4e3a True \u65f6\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u4f1a\u4fee\u6539Series\u6216DataFrame\u7684\u5c3a\u5bf8\u6216\u5f62\u72b6\uff0c*\u76f4\u63a5*\u64cd\u4f5c\u539f\u5bf9\u8c61\u800c\u4e0d\u8fd4\u56de\u65b0\u5bf9\u8c61\u3002 obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e']) print(obj) # a 0 # b 1 # c 2 # d 3 # e 4 # dtype: int64 obj1 = obj.drop('c') print(obj1) # a 0 # b 1 # d 3 # e 4 # dtype: int64 print(obj1.drop(['d', 'e'])) # a 0 # b 1 # dtype: int64 \u5bf9\u6bd4 inplace=True \u548c False \u7684\u533a\u522b\u3002 inplace=False \u65f6\uff0c obj \u7684\u503c\u6ca1\u6709\u53d8\u5316\u3002 obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e']) print(obj.drop('c', inplace=False)) # \u8bf4\u660e\u751f\u6210\u4e86\u65b0\u5bf9\u8c61 # a 0 # b 1 # d 3 # e 4 # dtype: int64 print(obj) # a 0 # b 1 # c 2 # d 3 # e 4 # dtype: int64 obj.drop('c', inplace=True) \u8f93\u51fa\u662f None \uff0c\u8bf4\u660e\u6ca1\u6709\u751f\u6210\u65b0\u5bf9\u8c61\uff0c\u53d8\u5316\u76f4\u63a5\u4f5c\u7528\u5230 obj \u4e0a\u3002 obj = pd.Series(np.arange(5), index=['a', 'b', 'c', 'd', 'e']) print(obj) print(obj.drop('c', inplace=True)) # \u8bf4\u660e\u6ca1\u6709\u751f\u6210\u65b0\u5bf9\u8c61 # None print(obj) # a 0 # b 1 # d 3 # e 4 # dtype: int64 \u4e0b\u4f8b\u6f14\u793a\u4e86\u8f74\u5411\u7684\u6548\u679c\u3002 \u5982\u679c\u4e0d\u6307\u5b9a\u8f74\u5411axis\uff0c drop() \u4f1a\u9ed8\u8ba4\u6cbf axis=0 \u8fdb\u884c\uff0c\u6240\u4ee5\uff0c\u57280\u8f74\u4e0a\u6267\u884c data.drop(['one', 'two']) \u4f1a\u62a5\u9519\u3002 axis='columns \u4e0e\u6307\u5b9a axis=1 \u540c\u6837\u6548\u679c\u3002 data = pd.DataFrame( np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['one', 'two', 'three', 'four'] ) print(data) # one two three four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 # \u6cbf0\u8f74\u64cd\u4f5c\uff0c\u5220\u9664\u7b26\u5408\u6761\u4ef6\u7684\u884c\u8bb0\u5f55 print(data.drop(['Ohio', 'Colorado'])) # one two three four # Utah 8 9 10 11 # New York 12 13 14 15 print(data.drop(['one', 'two'])) # KeyError: \"['one' 'two'] not found in axis\" # \u6cbf1\u8f74\u64cd\u4f5c\uff0c\u5220\u9664\u7b26\u5408\u6761\u4ef6\u7684\u5217\u8bb0\u5f55 print(data.drop(['one', 'two'], axis=1)) # three four # Ohio 2 3 # Colorado 6 7 # Utah 10 11 # New York 14 15 print(data.drop(['one', 'two'], axis='columns')) # three four # Ohio 2 3 # Colorado 6 7 # Utah 10 11 # New York 14 15 \u518d\u901a\u8fc7\u4e0b\u4f8b\u4f53\u4f1a\u4e00\u4e0b inplace \u53c2\u6570\u7684\u4e0d\u540c\u6548\u679c\u3002 data = pd.DataFrame( { 'Name': ['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], 'class': [11, 12, 10, 9], 'Age': [18, 20, 21, 17] } ) print(data) # Name class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 print(data.rename(columns={'Name': 'FirstName'}, inplace=False)) # FirstName class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 print(data) # Name class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17 print(data.rename(columns={'Name': 'FirstName'}, inplace=True)) # \u6ca1\u6709\u751f\u6210\u65b0\u5bf9\u8c61 # None print(data) # FirstName class Age # 0 Shobhit 11 18 # 1 vaibhav 12 20 # 2 vimal 10 21 # 3 Sourabh 9 17","title":"\u8f74\u5411\u7d22\u5f15\u5220\u9664\u6761\u76ee"},{"location":"python/DataAnalysis/ch02/#_4","text":"Series\u7684\u7d22\u5f15 obj[...] \u4e0eNumPy\u6570\u7ec4\u7d22\u5f15\u7684\u529f\u80fd\u7c7b\u4f3c\uff0c\u53ea\u4e0d\u8fc7Series\u7684\u7d22\u5f15\u503c\u53ef\u4ee5\u4e0d\u4ec5\u4ec5\u662f\u6574\u6570\u3002 \u4e0b\u4f8b\u4e2d\uff1a obj[1] \u901a\u8fc7\u7d22\u5f15\u4f4d 1 \u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c\u3002 obj[1] \u901a\u8fc7\u7d22\u5f15\u4f4d [1] \u68c0\u7d22\uff0c\u8f93\u51faSeries\u3002 obj['b'] \u901a\u8fc7\u7d22\u5f15\u503c 'b' \u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c\u3002 obj[['b']] \u901a\u8fc7\u7d22\u5f15\u503c ['b'] \u68c0\u7d22\uff0c\u8f93\u51faSeries\u3002 obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd']) print(obj) # a Shobhit # b vaibhav # c vimal # d Sourabh # dtype: object print(obj[1]) # \u901a\u8fc7\u7d22\u5f15\u4f4d\u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c # vaibhav print(obj[[1]]) # b vaibhav # dtype: object print(obj['b']) # \u901a\u8fc7\u7d22\u5f15\u503c\u68c0\u7d22\uff0c\u8f93\u51fa\u5bf9\u5e94Series\u7684\u503c # vaibhav print(obj[['b']]) # \u901a\u8fc7\u7d22\u5f15\u503c\u68c0\u7d22\uff0c\u8f93\u51faSeries # b vaibhav # dtype: object \u4e0b\u9762\u4e00\u7ec4\u7684\u8f93\u51fa\u4e2d\uff0c\u6ce8\u610f\u5bf9\u6bd4\u666e\u901aPython\u5207\u7247\u4e0eSeries\u7684\u5207\u7247\u7684\u5dee\u5f02\u3002 obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd']) print(obj[1]) # vaibhav print(obj[[1]]) # b vaibhav # dtype: object print(obj[1:3]) # b vaibhav # c vimal # dtype: object print(obj['b':'d']) # b vaibhav # c vimal # d Sourabh # dtype: object Series\u7684\u5207\u7247\u7684\u503c\u66f4\u65b0\u3002 obj['b': 'c'] = 5 \u662f\u901a\u8fc7\u7d22\u5f15\u503c\u8fdb\u884c\u66f4\u65b0\uff0c\u76f4\u63a5\u4f5c\u7528\u5728 obj \u3002 obj[1: 3] = 6 \u662f\u901a\u8fc7\u7d22\u5f15\u4f4d\u7f6e\u6765\u66f4\u65b0 obj \u3002 obj = pd.Series(['Shobhit', 'vaibhav', 'vimal', 'Sourabh'], index=['a', 'b', 'c', 'd']) obj['b': 'c'] = 5 print(obj) # a Shobhit # b 5 # c 5 # d Sourabh # dtype: object obj[1: 3] = 6 print(obj) # a Shobhit # b 6 # c 6 # d Sourabh # dtype: object DataFrame\u7684\u7d22\u5f15\u4e0e\u5207\u7247\u3002 data[['Three', 'Two']] \u9009\u53d6\u6307\u5b9a\u5217\uff0c\u6ce8\u610f\u8f93\u5165\u5217\u6761\u4ef6\u662f\u5217\u8868 ['Three', 'Two'] \u3002 data = pd.DataFrame( np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['One', 'Two', 'Three', 'Four'] ) print(data) # One Two Three Four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 print(data['Two']) # Ohio 1 # Colorado 5 # Utah 9 # New York 13 # Name: Two, dtype: int64 print(data[['Three', 'Two']]) # Three Two # Ohio 2 1 # Colorado 6 5 # Utah 10 9 # New York 14 13 print(data[:2]) # One Two Three Four # Ohio 0 1 2 3 # Colorado 4 5 6 7 \u5d4c\u5957\uff1a\u6839\u636e\u4e00\u4e2a\u5e03\u5c14\u503c\u6570\u7ec4\u5207\u7247\u6216\u9009\u62e9\u6570\u636e\u3002 data['Three'] > 5 \u662f\u4e00\u4e2a\u5e03\u5c14\u503c\u5e8f\u5217\u3002 data[data['Three'] > 5] \u8f93\u51fa\u6761\u4ef6\u4e3aTrue\u7684\u7ed3\u679c\u96c6\u3002 print(data['Three'] > 5) # Ohio False # Colorado True # Utah True # New York True # Name: Three, dtype: bool print(data[data['Three'] > 5]) # One Two Three Four # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 \u4f7f\u7528\u5e03\u5c14\u503cDataFrame\u8fdb\u884c\u7d22\u5f15\uff0c\u5df2\u7ecf\u66f4\u65b0\u3002 \u5728\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u8fd9\u79cd\u7d22\u5f15\u65b9\u5f0f\u4f7f\u5f97DataFrame\u5728\u8bed\u6cd5\u4e0a\u66f4\u50cf\u662fNumPy\u4e8c\u7ef4\u6570\u7ec4\u3002 print(data < 5) # One Two Three Four # Ohio True True True True # Colorado True False False False # Utah False False False False # New York False False False False data[data < 5] = 0 print(data) # One Two Three Four # Ohio 0 0 0 0 # Colorado 0 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 \u4f7f\u7528loc\u548ciloc\u9009\u62e9\u6570\u636e\u3002 \u4f7f\u7528\u6807\u7b7e\u540d loc \u6216\u6807\u7b7e\u4f4d\u7f6e iloc \u4ee5NumPy\u98ce\u683c\u7684\u8bed\u6cd5\u4eceDataFrame\u4e2d\u9009\u51faDataframe\u7684\u884c\u548c\u5217\u7684\u5b50\u96c6\u3002 data = pd.DataFrame( np.arange(16).reshape(4, 4), index=['Ohio', 'Colorado', 'Utah', 'New York'], columns=['One', 'Two', 'Three', 'Four'] ) print(data) # One Two Three Four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # Utah 8 9 10 11 # New York 12 13 14 15 \u4e0b\u4f8b\u901a\u8fc7loc\u5bf9\u6807\u7b7e\u540d\u7b5b\u9009\u884c\u6216\u5217\u6570\u636e\u3002\u4f8b\u5982\uff0c\u8f93\u51fa Colorado \u884c\u6807\u7b7e\u7684 Two \u548c Three \u8fd9\u4e24\u5217\u7684\u503c\uff0c\u4ee5\u884c\u8bb0\u5f55\u7684\u65b9\u5f0f\u5c55\u73b0\u3002 print(data.loc['Colorado', ['Two', 'Three']]) # \u5207\u7247: # Two 5 # Three 6 # Name: Colorado, dtype: int64 print(data.loc[:'Ohio', :'Two']) # \u5207\u7247: 0\u884c\uff0c0,1\u5217 # One Two # Ohio 0 1 \u4e0b\u4f8b\u901a\u8fc7\u6807\u7b7e\u4f4d\u7f6e iloc \u8fdb\u884c\u7c7b\u4f3c\u7684\u6570\u636e\u9009\u62e9\u3002 data.iloc[:3, :2][data > 4] \u6309\u6307\u5b9a\u6761\u4ef6\u8fdb\u884c\u884c\u3001\u5217\u7b5b\u9009\uff0c\u7b26\u5408\u6761\u4ef6 [data > 4] \u7684\u8f93\u51faDataframe\u503c\uff0c\u4e0d\u7b26\u5408\u6761\u4ef6\u7684\u8f93\u51faNaN\u3002 print(data.iloc[[0]]) # 0\u884c # One Two Three Four # Ohio 0 1 2 3 print(data.iloc[[0], [1]]) # \u5207\u7247: 0\u884c\uff0c1\u5217 # Two # Ohio 1 print(data.iloc[1:2, 1:2]) # \u5207\u7247: 1\u884c\uff0c2\u5217 # Two # Ohio 1 print(data.iloc[2, [3, 0, 1]]) # \u5207\u7247: 2\u884c\uff0c\u4f9d\u6b21\u53d63\uff0c0\uff0c1\u5217 # Four 11 # One 8 # Two 9 # Name: Utah, dtype: int64 print(data.iloc[:3, :2][data > 4]) # One Two # Ohio NaN NaN # Colorado NaN 5.0 # Utah 8.0 9.0","title":"\u7d22\u5f15\u3001\u9009\u62e9\u4e0e\u8fc7\u6ee4"},{"location":"python/DataAnalysis/ch02/#_5","text":"Pandas\u7684Series\u7684\u7d22\u5f15\u503c\u662f\u6574\u6570\u7d22\u5f15\u3002 data = np.arange(3.) ser = pd.Series(data) print(ser) # 0 0.0 # 1 1.0 # 2 2.0 # dtype: float64 print(ser[:1]) # 0 0.0 # dtype: float64 print(ser.loc[:1]) # loc\u7528\u4e8e\u6807\u7b7e\u540d # 0 0.0 # 1 1.0 # dtype: float64 print(ser.iloc[:1]) # iloc\u7528\u4e8e\u6807\u7b7e\u4f4d\u7f6e # 0 0.0 # dtype: float64 data = ['1', 'b', 'e', 3] ser = pd.Series(data) print(ser) # 0 1 # 1 b # 2 e # 3 3 # dtype: object print(ser[:1]) # 0 1 # dtype: object print(ser.loc[:1]) # 0 1 # 1 b # dtype: object print(ser.iloc[:1]) # 0 1 # dtype: object \u5bf9DataFrame\u7684\u66f4\u65b0\u3002 df1 = pd.DataFrame(np.arange(4).reshape((2, 2)), columns=list('ab')) print(df1) # a b # 0 0 1 # 1 2 3 # \u6309\u6807\u7b7e\u540d\u66f4\u65b0 df1.loc[1, :'b'] = np.nan print(df1) # a b # 0 0.0 1.0 # 1 NaN NaN","title":"\u6574\u6570\u7d22\u5f15"},{"location":"python/DataAnalysis/ch02/#_6","text":"Pandas\u652f\u6301\u5728Series\u6216\u8005DataFrame\u5bf9\u8c61\u4e4b\u95f4\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97\u3002 \u4f8b\uff1a\u4e24\u4e2aSeries\u505a\u7b97\u672f\u52a0\u6cd5\u3002 \u8fd4\u56de\u7684\u7ed3\u679c\u4e5f\u662f\u4e00\u4e2aSeries\u3002 \u8fd4\u56de\u7ed3\u679c\u7684\u7d22\u5f15\u662f\u6bcf\u4e2aSeries\u7684\u7d22\u5f15\u7684\u5e76\u96c6\u3002 \u51e1\u662f\u6ca1\u6709\u5728\u4e24\u4e2aSeries\u90fd\u51fa\u73b0\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0c\u5185\u90e8\u6570\u636e\u5bf9\u9f50\u4f1a\u586b\u5145\u7f3a\u5931\u503cNaN\u3002\u7f3a\u5931\u503c\u4f1a\u5728\u540e\u7eed\u7684\u5176\u5b83\u7b97\u672f\u64cd\u4f5c\u4e0a\u4ea7\u751f\u5f71\u54cd\u3002 \u540c\u65f6\u51fa\u73b0\u5728\u4e24\u4e2aSeries\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0cSeries\u7684\u503c\u505a\u7b97\u672f\u76f8\u52a0\u3002 s1 = pd.Series( [7.3, -2.5, 3.4, 1.5], index=['a', 'c', 'd', 'e'] ) s2 = pd.Series( [-2.1, 3.6, -1.5, 4, 3.1], index=['a', 'c', 'e', 'f', 'g'] ) print(s1) # a 7.3 # c -2.5 # d 3.4 # e 1.5 # dtype: float64 print(s2) # a -2.1 # c 3.6 # e -1.5 # f 4.0 # g 3.1 # dtype: float64 print(s1 + s2) # a 5.2 # c 1.1 # d NaN # e 0.0 # f NaN # g NaN # dtype: float64 \u4f8b\uff1a\u4e24\u4e2aDataframe\u505a\u7b97\u672f\u52a0\u6cd5 \u8fd4\u56de\u7ed3\u679c\u4e5f\u662f\u4e00\u4e2aDataframe\u3002 \u8fd4\u56de\u7ed3\u679c\u7684\u884c\u5217\u7d22\u5f15\u662f\u6bcf\u4e2aDataFrame\u7684\u884c\u5217\u7d22\u5f15\u7684\u5e76\u96c6\u3002 \u51e1\u662f\u6ca1\u6709\u5728\u4e24\u4e2aDataFrame\u90fd\u51fa\u73b0\u7684\u4f4d\u7f6e\u5c31\u4f1a\u88ab\u7f6e\u4e3aNaN\u3002 \u4e24\u4e2aDataFrame\u90fd\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5bf9Dataframe\u7684\u503c\u505a\u7b97\u672f\u52a0\u6cd5\u3002 df1 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('bcd'), index=['Ohio', 'Texas', 'Colorado'] ) df2 = pd.DataFrame( np.arange(12).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'] ) print(df1) # b c d # Ohio 0 1 2 # Texas 3 4 5 # Colorado 6 7 8 print(df2) # b d e # Utah 0 1 2 # Ohio 3 4 5 # Texas 6 7 8 # Oregon 9 10 11 print(df1 + df2) # b c d e # Colorado NaN NaN NaN NaN # Ohio 3.0 NaN 6.0 NaN # Oregon NaN NaN NaN NaN # Texas 9.0 NaN 12.0 NaN # Utah NaN NaN NaN NaN \u5728Series\u6216\u8005DataFrame\u5bf9\u8c61\u4e4b\u95f4\u8fdb\u884c\u7b97\u672f\u64cd\u4f5c\u65f6\uff0c\u6709\u65f6\u9700\u8981\u5bf9\u7f3a\u5931\u503c\u6307\u5b9a\u586b\u5145\u503c\uff0c\u6bd4\u5982\u5f53\u8f74\u6807\u7b7e\u5728\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u5b58\u5728\uff0c\u5728\u53e6\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u4e0d\u5b58\u5728\u65f6\uff0c\u5c06\u7f3a\u5931\u503c\u586b\u5145\u4e3a0\u3002\u4e5f\u5c31\u662f\u8bf4\uff0c\u5982\u679c\u5728\u4e24\u4e2aDataFrame\u90fd\u7f3a\u5931\uff0c\u90a3\u4e48\u4f9d\u7136\u8fd8\u4f1a\u662fNaN\u3002 \u4e0b\u4f8b\u4e2da2\u662f\u5728 df1 \u548c df2 \u90fd\u7f3a\u5931\u7684\u4f4d\u7f6e\uff0c\u6240\u4ee5\u5373\u4f7f fill_value=0 \uff0ca2\u4ecd\u7136\u662fNaN\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('bcd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # b c d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 # \u5bf9df1\u548cdf2\u5c31\u7b97\u672f\u548c\uff0c\u5bf9\u5e94\u6ca1\u6709\u884c\u5217\u5171\u540c\u7684\u4ea4\u96c6\u7684\u5730\u65b9\u586b\u5145\u7a7a\u503cNaN\uff0c\u6709\u4ea4\u96c6\u7684\u5730\u65b9\u6c42\u7b97\u672f\u548c\u3002 print(df1.add(df2)) # a b c d # 0 NaN 1.0 NaN NaN # 1 NaN 6.0 NaN NaN # 2 NaN NaN NaN NaN # \u5bf9df1\u548cdf2\u5c31\u7b97\u672f\u548c\uff0c\u5bf9\u5e94\u6ca1\u6709\u884c\u5217\u5171\u540c\u7684\u4ea4\u96c6\u7684\u5730\u65b9\u586b\u5145\u7a7a\u503c0\uff0c\u6709\u4ea4\u96c6\u7684\u5730\u65b9\u6c42\u7b97\u672f\u548c\u3002 print(df1.add(df2, fill_value=0)) # df2.add(df1, fill_value=0) \u8fd4\u56de\u540c\u6837\u7684\u7ed3\u679c # a b c d # 0 0.0 1.0 1.0 2.0 # 1 2.0 6.0 4.0 5.0 # 2 NaN 6.0 7.0 8.0 \u4e0b\u4f8b\u4e2db2\u662f\u5728 df1 \u548c df2 \u90fd\u7f3a\u5931\u7684\u4f4d\u7f6e\uff0c\u6240\u4ee5\u5373\u4f7f fill_value=0 \uff0cb2\u4ecd\u7136\u662fNaN\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('acd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # a c d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 print(df1.add(df2, fill_value=0)) # a b c d # 0 0.0 1.0 1.0 2.0 # 1 5.0 3.0 4.0 5.0 # 2 6.0 NaN 7.0 8.0 \u4e0b\u4f8b\u4e2d\u6ca1\u6709\u4e24\u4e2aDataFrame\u5171\u540c\u7f3a\u5931\u7684\u60c5\u51b5\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('abd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # a b d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 print(df1.add(df2, fill_value=0)) # a b d # 0 0.0 2.0 2.0 # 1 5.0 7.0 5.0 # 2 6.0 7.0 8.0 \u4e0b\u9762\u662fSeries\u548cDataFrame\u7684\u7b97\u672f\u65b9\u6cd5\u3002 add\uff0cradd\uff1a\u52a0\u6cd5(+) sub\uff0crsub\uff1a\u51cf\u6cd5(-) div\uff0crdiv\uff1a\u9664\u6cd5(/) floordiv\uff0crfloordiv\uff1a\u6574\u9664(//) mul\uff0crmul\uff1a\u4e58\u6cd5(*) pow\uff0crpow\uff1a\u5e42\u6b21\u65b9(**) \u4e0a\u8ff0\u6bcf\u4e2a\u65b9\u6cd5\u90fd\u6709\u4e00\u4e2a\u4ee5r\u5f00\u5934\u7684\u526f\u672c\uff0c\u8fd9\u4e9b\u526f\u672c\u65b9\u6cd5\u7684\u53c2\u6570\u662f\u7ffb\u8f6c\u7684\u3002\u6bd4\u5982\uff0c\u6c42DataFrame\u5f53\u4e2d\u6240\u6709\u5143\u7d20\u7684\u5012\u6570 1/df \uff0c\u53ef\u4ee5\u5199\u6210df.rdiv(1)\u3002 df1 = pd.DataFrame( np.arange(4).reshape((2, 2)), columns=list('ab') ) df2 = pd.DataFrame( np.arange(9).reshape((3, 3)), columns=list('abd') ) print(df1) # a b # 0 0 1 # 1 2 3 print(df2) # a b d # 0 0 1 2 # 1 3 4 5 # 2 6 7 8 print(df1.radd(df2, fill_value=0)) # a b d # 0 0.0 2.0 2.0 # 1 5.0 7.0 5.0 # 2 6.0 7.0 8.0 print(df1.sub(df2, fill_value=0)) # a b d # 0 0.0 0.0 -2.0 # 1 -1.0 -1.0 -5.0 # 2 -6.0 -7.0 -8.0 print(df1.div(df2, fill_value=0)) # a b d # 0 NaN 1.00 0.0 # 1 0.666667 0.75 0.0 # 2 0.000000 0.00 0.0 print(df1.floordiv(df2, fill_value=0)) # a b d # 0 NaN 1.0 0.0 # 1 0.0 0.0 0.0 # 2 0.0 0.0 0.0 print(df1.mul(df2, fill_value=0)) # a b d # 0 0.0 1.0 0.0 # 1 6.0 12.0 0.0 # 2 0.0 0.0 0.0 print(df1.pow(df2, fill_value=0)) # a b d # 0 1.0 1.0 0.0 # 1 8.0 81.0 0.0 # 2 0.0 0.0 0.0","title":"\u7b97\u672f\u548c\u6570\u636e\u5bf9\u9f50"},{"location":"python/DataAnalysis/ch02/#dataframeseries","text":"DataFrame\u548cSeries\u95f4\u7684\u7b97\u672f\u64cd\u4f5c\u4e0eNumPy\u4e2d\u4e0d\u540c\u7ef4\u5ea6\u6570\u7ec4\u95f4\u7684\u64cd\u4f5c\u7c7b\u4f3c\u3002","title":"DataFrame\u548cSeries\u95f4\u7684\u7b97\u672f\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch02/#numpy","text":"\u4ecearr\u4e2d\u51cf\u53bbarr[0]\u65f6\uff0c\u51cf\u6cd5\u6cbf0\u8f74\u5728\u6bcf\u4e00\u884c\u90fd\u8fdb\u884c\u4e86\u64cd\u4f5c\u3002\u8fd9\u5c31\u662f\u6240\u8c13\u7684\u5e7f\u64ad\u673a\u5236\u3002 arr = np.arange(12).reshape((3, 4)) print(arr) # [[ 0 1 2 3] # [ 4 5 6 7] # [ 8 9 10 11]] print(arr[0]) # [0 1 2 3] print(arr - arr[0]) # [[0 0 0 0] # [4 4 4 4] # [8 8 8 8]]","title":"\u4e0d\u540c\u7ef4\u5ea6NumPy\u6570\u7ec4\u95f4\u7684\u7b97\u672f\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch02/#dataframeseries_1","text":"\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cDataFrame\u548cSeries\u7684\u6570\u5b66\u64cd\u4f5c\u4e2d\u4f1a\u5c06Series\u7684\u7d22\u5f15\u548cDataFrame\u7684*\u5217*\u8fdb\u884c\u5339\u914d\uff0c\u5e76*\u5e7f\u64ad\u5230\u5404\u884c*. \u5982\u679c\u4e00\u4e2a\u7d22\u5f15\u503c\u4e0d\u5728DataFrame\u7684\u5217\u4e2d\uff0c\u4e5f\u4e0d\u5728Series\u7684\u7d22\u5f15\u4e2d\uff0c\u5219\u65b0\u5bf9\u8c61\u4f1a\u6784\u5efa\u5e76\u96c6\u7d22\u5f15\u3002 frame = pd.DataFrame( np.arange(12).reshape((4, 3)), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'] ) print(frame) # b d e # Utah 0 1 2 # Ohio 3 4 5 # Texas 6 7 8 # Oregon 9 10 11 # \u622a\u53d6frame\u7684\u7b2c0\u884c\uff0c\u5217\u6807\u7b7e\u53d8\u6210\u65b0Serise\u7684\u7d22\u5f15\u3002 series = frame.iloc[0] print(series) # b 0 # d 1 # e 2 # Name: Utah, dtype: int64 series2 = pd.Series( range(3), index=list('bef') ) print(series2) # b 0 # e 1 # f 2 # dtype: int64 # \u622a\u53d6frame\u7684d\u5217\uff0c\u884c\u6807\u7b7e\u53d8\u6210\u65b0Serise\u7684\u7d22\u5f15\u3002 series3 = frame['d'] print(series3) # Utah 1 # Ohio 4 # Texas 7 # Oregon 10 # Name: d, dtype: int64 # \u5c06Series\u7684\u7d22\u5f15\u548cDataFrame\u7684\u5217\u6807\u7b7e\u8fdb\u884c\u5339\u914d\uff0cSeries\u7684\u503c\u6cbfDataFrame\u76840\u8f74\u5e7f\u64ad\u5230\u5404\u4e2a\u884c\u3002 print(frame - series) # frame: series Result: # b d e # b 0 # b d e # Utah 0 1 2 # d 1 # Utah 0 0 0 # Ohio 3 4 5 # e 2 # Ohio 3 3 3 # Texas 6 7 8 # Name: Utah, dtype: int64 # Texas 6 6 6 # Oregon 9 10 11 # Oregon 9 9 9 # \u5c06Series\u7684\u7d22\u5f15\u548cDataFrame\u7684\u5217\u6807\u7b7e\u8fdb\u884c\u5339\u914d\uff0cSeries\u7684\u503c\u6cbfDataFrame\u76840\u8f74\u5e7f\u64ad\u5230\u5404\u4e2a\u884c\uff0c\u7f3a\u5931\u4f4d\u7f6e\u586b\u5145\u7a7a\u503cNaN\u3002 print(frame - series2) # frame: series2 Result: # b d e # b 0 # b d e f # Utah 0 1 2 # e 1 # Utah 0.0 NaN 1.0 NaN # Ohio 3 4 5 # f 2 # Ohio 3.0 NaN 4.0 NaN # Texas 6 7 8 # dtype: int64 # Texas 6.0 NaN 7.0 NaN # Oregon 9 10 11 # Oregon 9.0 NaN 10.0 NaN # \u6539\u4e3a\u5728\u5217\u4e0a\u8fdb\u884c\u5e7f\u64ad\uff0c\u5728\u884c\u4e0a\u5339\u914d\uff0c\u5fc5\u987b\u4f5c\u7528\u5728\u67d0\u79cd\u7b97\u672f\u65b9\u6cd5\u4e0a\u3002\u4e0b\u4f8b\u4e2dSeries\u7684\u503c\u6cbfDataFrame\u76840\u8f74\u5e7f\u64ad\u5230\u5404\u4e2a\u884c\uff08\u6309index\u5339\u914d\u8fdb\u884c\u884c\u64cd\u4f5c\uff09\u3002 print(frame.sub(series3, axis='index')) # \u6216axis=0 # frame: series3 Result: # b d e # Utah 1 # b d e # Utah 0 1 2 # Ohio 4 # Utah -1 0 1 # Ohio 3 4 5 # Texas 7 # Ohio -1 0 1 # Texas 6 7 8 # Oregon 10 # Texas -1 0 1 # Oregon 9 10 11 # Name: d, dtype: int64 # Oregon -1 0 1","title":"DataFrame\u548cSeries\u95f4\u7684\u7b97\u672f\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch02/#_7","text":"NumPy\u7684\u901a\u7528\u51fd\u6570\uff08\u9010\u5143\u7d20\u6570\u7ec4\u65b9\u6cd5\uff09\u5bf9pandas\u5bf9\u8c61\uff08DataFrame\u548cSeries\uff09\u4e5f\u6709\u6548\u3002 frame = pd.DataFrame( np.random.randn(4, 3), columns=list('bde'), index=['Utah', 'Ohio', 'Texas', 'Oregon'] ) print(frame) # b d e # Utah 2.737734 -0.379977 0.758933 # Ohio 0.847497 0.839583 -2.192021 # Texas -0.907544 -0.457436 -1.907396 # Oregon 0.389362 0.250170 1.065889 # \u5bf9DataFrame\u5bf9\u8c61\u8ba1\u7b97\u7edd\u5bf9\u503c\u3002 print(np.abs(frame)) # b d e # Utah 2.737734 0.379977 0.758933 # Ohio 0.847497 0.839583 2.192021 # Texas 0.907544 0.457436 1.907396 # Oregon 0.389362 0.250170 1.065889 # f\u8fd4\u56de\u4e00\u4e2a\u6807\u91cf\u503c f = lambda x: x.max() - x.min() # \u6cbf0\u8f74\u5e94\u7528f\uff08\u5bf9\u6bcf\u5217\u7684\u6240\u6709\u884c\u5143\u7d20\u8fdb\u884cf\u8ba1\u7b97\uff09, \u9ed8\u8ba4axis=0 print(frame.apply(f)) # b 3.645278 # d 1.297019 # e 3.257911 # dtype: float64 # \u6cbf1\u8f74\u5e94\u7528f\uff08\u5bf9\u6bcf\u884c\u7684\u6240\u6709\u5217\u5143\u7d20\u8fdb\u884cf\u8ba1\u7b97\uff09 print(frame.apply(f, axis=1)) # Utah 3.117711 # Ohio 3.039518 # Texas 1.449961 # Oregon 0.815720 # dtype: float64 # \u5b9a\u4e49\u51fd\u6570f\uff0c\u8fd4\u56de\u5e26\u6709\u591a\u4e2a\u503c\u7684Series\u3002 def f(x): return pd.Series( [x.min(), x.max()], index=['min', 'max'] ) print(frame.apply(f)) # b d e # min -0.907544 -0.457436 -2.192021 # max 2.737734 0.839583 1.065889 # \u5b9a\u4e49\u51fd\u6570f\uff0c\u4f7f\u7528applymap\u65b9\u6cd5\u683c\u5f0f\u5316\u5b57\u7b26\uff0c\u5c06\u4e00\u4e2a\u9010\u5143\u7d20\u7684\u51fd\u6570\u5e94\u7528\u5230Series\u4e0a\u3002 f = lambda x: '%.2f' % x print(frame.applymap(f)) # # b d e # Utah 2.74 -0.38 0.76 # Ohio 0.85 0.84 -2.19 # Texas -0.91 -0.46 -1.91 # Oregon 0.39 0.25 1.07 print(frame['e'].map(f)) # Utah 0.76 # Ohio -2.19 # Texas -1.91 # Oregon 1.07 # Name: e, dtype: object","title":"\u51fd\u6570\u5e94\u7528\u548c\u6620\u5c04"},{"location":"python/DataAnalysis/ch02/#_8","text":"\u4f7f\u7528sort_index\u65b9\u6cd5\uff0c\u6309\u884c\u6216\u5217\u7d22\u5f15\u8fdb\u884c\u5b57\u5178\u578b\u6392\u5e8f\uff0c\u8fd4\u56de\u4e00\u4e2a\u65b0\u7684\u6392\u5e8f\u597d\u7684Pandas\u5bf9\u8c61\u3002","title":"\u6392\u5e8f\u548c\u6392\u540d"},{"location":"python/DataAnalysis/ch02/#series_1","text":"\u5bf9Series\u8fdb\u884c\u7d22\u5f15\u6392\u5e8f\u548c\u503c\u6392\u5e8f\u3002 obj = pd.Series( range(4), index=list('dabc') ) print(obj) # d 0 # a 1 # b 2 # c 3 # dtype: int64 print(obj.sort_index()) # a 1 # b 2 # c 3 # d 0 # dtype: int64 # print(obj.sort_values()) # d 0 # a 1 # b 2 # c 3 # dtype: int64 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6240\u6709\u7684\u7f3a\u5931\u503c\u90fd\u4f1a\u88ab\u6392\u5e8f\u81f3Series\u7684\u5c3e\u90e8\u3002 obj = pd.Series([4, np.nan, 7, np.nan, -3, 2]) print(obj) # 0 4.0 # 1 NaN # 2 7.0 # 3 NaN # 4 -3.0 # 5 2.0 # dtype: float64 print(obj.sort_values()) # 4 -3.0 # 5 2.0 # 0 4.0 # 2 7.0 # 1 NaN # 3 NaN # dtype: float64","title":"Series\u6392\u5e8f"},{"location":"python/DataAnalysis/ch02/#dataframe_3","text":"frame = pd.DataFrame( [[0, 1, 10, 3], [4, 5, 6, 21], [8, 9, 2, 21]], index=['three', 'one', 'five'], columns=list('dabc') ) print(frame) # d a b c # three 0 1 10 3 # one 4 5 6 21 # five 8 9 2 21 print(frame.index) # Index(['three', 'one', 'five'], dtype='object') # \u9ed8\u8ba40\u8f74\uff0c\u6240\u6709\u884c\u8fdb\u884c\u7d22\u5f15\u9996\u5b57\u6bcd\u5347\u5e8f print(frame.sort_index()) # d a b c # five 8 9 2 21 # one 4 5 6 21 # three 0 1 10 3 # \u6307\u5b9a0\u8f74\uff0c\u6240\u6709\u884c\u8fdb\u884c\u7d22\u5f15\u9996\u5b57\u6bcd\u5347\u5e8f print(frame.sort_index(axis=0)) # d a b c # five 8 9 2 21 # one 4 5 6 21 # three 0 1 10 3 # \u6307\u5b9a0\u8f74\uff0c\u6240\u6709\u884c\u8fdb\u884c\u7d22\u5f15\u9996\u5b57\u6bcd\u964d\u5e8f print(frame.sort_index(axis=0, ascending=False)) # d a b c # three 0 1 10 3 # one 4 5 6 21 # five 8 9 2 21 # \u6307\u5b9a1\u8f74\uff0c\u6240\u6709\u5217\u8fdb\u5217\u7d22\u5f15\u9996\u5b57\u6bcd\u5347\u5e8f print(frame.sort_index(axis=1)) # a b c d # three 1 10 3 0 # one 5 6 21 4 # five 9 2 21 8 # \u6307\u5b9a1\u8f74\uff0c\u6240\u6709\u5217\u8fdb\u5217\u7d22\u5f15\u9996\u5b57\u6bcd\u964d\u5e8f print(frame.sort_index(axis=1, ascending=False)) # d c b a # three 0 3 10 1 # one 4 21 6 5 # five 8 21 2 9 # \u6309\u6307\u5b9a\u5355\u5217\u8fdb\u884c\u503c\u6392\u5e8f\uff08\u964d\u5e8f\uff09 print(frame.sort_values(by=['c'], ascending=False)) # d a b c # one 4 5 6 21 # five 8 9 2 21 # three 0 1 10 3 # \u6309\u6307\u5b9a\u591a\u5217\u8fdb\u884c\u503c\u6392\u5e8f\uff08\u964d\u5e8f\uff09\uff0c\u5148\u5bf9b\u964d\u5e8f\uff0c\u518d\u5bf9d\u964d\u5e8f print(frame.sort_values(by=['c', 'd'], ascending=False)) # d a b c # five 8 9 2 21 # one 4 5 6 21 # three 0 1 10 3","title":"DataFrame\u6392\u5e8f"},{"location":"python/DataAnalysis/ch02/#_9","text":"**\u6392\u540d**\u662f\u6307\u5bf9\u6570\u7ec4\u4ece1\u5230\u6709\u6548\u6570\u636e\u70b9\u603b\u6570\u5206\u914d\u540d\u6b21\u7684\u64cd\u4f5c\u3002 Series\u548cDataFrame\u7684 rank \u65b9\u6cd5\u662f\u5b9e\u73b0\u6392\u540d\u7684\u65b9\u6cd5\uff0c df.rank(ascending=False, method='max') \u3002 ascending \uff1a\u6392\u540d\u65b9\u5f0f\uff0c\u9ed8\u8ba4\u4ece\u4f4e\u5230\u9ad8\uff0c ascending=False \u8868\u793a\u4ece\u9ad8\u5230\u4f4e\uff1b method \uff1a\u6392\u540d\u65b9\u5f0f\uff0c\u5305\u62ec\uff1a average:\u9ed8\u8ba4\uff0c\u5728\u76f8\u7b49\u5206\u7ec4\u4e2d\uff0c\u4e3a\u5404\u4e2a\u503c\u5206\u914d\u5e73\u5747\u6392\u540d\uff0c\u5373\u76f8\u540c\u503c\u7684\u548c\u9664\u4ee5\u8be5\u503c\u7684\u4e2a\u6570\uff0c\u5373\u4e3a\u8be5\u503c\u7684\u540d\u6b21\u3002 min:\u4f7f\u7528\u6574\u4e2a\u5206\u7ec4\u7684\u6700\u5c0f\u6392\u540d\uff0c\u5373\uff0c\u5bf9\u5e94\u76f8\u540c\u503c\uff0c\u53d6\u5728\u987a\u5e8f\u6392\u540d\u4e2d\u6700\u5c0f\u7684\u90a3\u4e2a\u6392\u540d\u4f5c\u4e3a\u6240\u6709\u8be5\u503c\u7684\u6392\u540d\u3002 max:\u4f7f\u7528\u6574\u4e2a\u5206\u7ec4\u7684\u6700\u5927\u6392\u540d\uff0c\u5373\uff0c\u5bf9\u5e94\u76f8\u540c\u503c\uff0c\u53d6\u5728\u987a\u5e8f\u6392\u540d\u4e2d\u6700\u5927\u7684\u90a3\u4e2a\u6392\u540d\u4f5c\u4e3a\u6240\u6709\u8be5\u503c\u7684\u6392\u540d\u3002 first:\u6309\u503c\u518d\u539f\u59cb\u6570\u636e\u4e2d\u51fa\u73b0\u987a\u5e8f\u5206\u914d\u6392\u540d\uff0c\u8c01\u51fa\u73b0\u7684\u4f4d\u7f6e\u9760\u524d\uff0c\u8c01\u7684\u6392\u540d\u9760\u524d\u3002 dense:\u7c7b\u4f3cmin\u65b9\u6cd5\uff0c\u4f46\u6392\u540d\u603b\u662f\u5728\u7ec4\u95f4\u589e\u52a01\uff0c\u800c\u4e0d\u662f\u7ec4\u4e2d\u76f8\u540c\u7684\u5143\u7d20\u6570\uff0c\u5373\u76f8\u540c\u503c\u7684\u6392\u540d\u76f8\u540c\uff0c\u5176\u4ed6\u4f9d\u6b21\u52a01\u5373\u53ef\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0crank\u662f\u901a\u8fc7\u201c\u4e3a\u5404\u7ec4\u5206\u914d\u4e00\u4e2a\u5e73\u5747\u6392\u540d\u201d\u7684\u65b9\u5f0f\u7834\u574f\u5e73\u7ea7\u5173\u7cfb # \u6309\u7167\u6bcf\u4e2a\u5143\u7d20\u7684\u5927\u5c0f\u987a\u5e8f\u7ed9\u51fa\u4e00\u4e2a\u5e73\u5747\u6392\u540d obj = pd.Series([7, -5, 7, 4, 2, 0, 4]) print(obj) # 0 7 # 1 -5 # 2 7 # 3 4 # 4 2 # 5 0 # 6 4 # dtype: int64 print(obj.rank()) # 0 6.5 # 1 1.0 # 2 6.5 # 3 4.5 # 4 3.0 # 5 2.0 # 6 4.5 # dtype: float64 # index value rank # 2 -5 1 # 6 0 2 # 5 2 3 # 4 4 4.5 # 7 4 4.5 # 1 7 6.5 # 3 7 6.5 # \u6839\u636e\u5143\u7d20\u7684\u89c2\u5bdf\u987a\u5e8f\u8fdb\u884c\u5206\u914d\u3002\u5143\u7d200\u548c2\u6ca1\u6709\u4f7f\u7528\u5e73\u5747\u6392\u540d6.5\uff0c\u5b83\u4eec\u88ab\u8bbe\u6210\u4e866\u548c7\uff0c\u56e0\u4e3a\u6570\u636e\u4e2d\u6807\u7b7e0\u4f4d\u4e8e\u6807\u7b7e2\u7684\u524d\u9762\u3002 print(obj.rank(method='first')) # 0 6.0 # 1 1.0 # 2 7.0 # 3 4.0 # 4 3.0 # 5 2.0 # 6 5.0 # dtype: float64 # \u6309\u7167max\u8fdb\u884c\u5347\u5e8f\u548c\u964d\u5e8f print(obj.rank(ascending=False, method='max')) print(obj.rank(ascending=True, method='max')) # Original Series Max with inc Max with dec # 0 7 # 0 2.0 (\u6700\u5c0f) # 0 7.0 (\u6700\u5927) # 1 -5 # 1 7.0 (\u6700\u5927) # 1 1.0 (\u6700\u5c0f) # 2 7 # 2 2.0 (\u6700\u5c0f) # 2 7.0 (\u6700\u5927) # 3 4 # 3 4.0 # 3 5.0 # 4 2 # 4 5.0 # 4 3.0 # 5 0 # 5 6.0 # 5 2.0 # 6 4 # 6 4.0 # 6 5.0 # dtype: float64 # dtype: float64 # dtype: float64 frame = pd.DataFrame( {'b': [4.3, 7, -3, 2], 'a': [0, 1, 0, 1], 'c': [-2, 5, 8, -2]} ) print(frame) # b a c # 0 4.3 0 -2 # 1 7.0 1 5 # 2 -3.0 0 8 # 3 2.0 1 -2 # \u6cbf1\u8f74\u5bf9DataFrame\u8fdb\u884crank\u64cd\u4f5c\uff0c\u5373\uff0c\u6bcf\u4e00\u884c\u5404\u5143\u7d20\u8fdb\u884crank\u3002 print(frame.rank(axis='columns')) # axis=1 # b a c # 0 3.0 2.0 1.0 # 1 3.0 1.0 2.0 # 2 1.0 2.0 3.0 # 3 3.0 2.0 1.0","title":"\u6392\u540d"},{"location":"python/DataAnalysis/ch02/#_10","text":"\u5c3d\u7ba1\u5f88\u591apandas\u51fd\u6570\uff08\u6bd4\u5982reindex\uff09\u9700\u8981\u6807\u7b7e\u662f\u552f\u4e00\u7684\uff0c\u4f46\u8fd9\u4e2a\u5e76\u4e0d\u662f\u5f3a\u5236\u6027\u7684\u3002 \u7d22\u5f15\u7684is_unique\u5c5e\u6027\u53ef\u4ee5\u68c0\u67e5\u6807\u7b7e\u662f\u5426\u552f\u4e00\u3002 \u5e26\u6709\u91cd\u590d\u7d22\u5f15\u7684\u60c5\u51b5\u4e0b\uff0c\u4e00\u4e2a\u7d22\u5f15\u6807\u7b7e\u4f1a\u4ee5\u5e8f\u5217\u65b9\u5f0f\u8fd4\u56de\u591a\u4e2a\u6761\u76ee\u3002\u4e0d\u91cd\u590d\u7684\u7d22\u5f15\u5219\u4f1a\u4ee5\u6807\u91cf\u503c\u7684\u5f62\u5f0f\u8fd4\u56de\u5355\u4e2a\u6761\u76ee\uff0c\u8fd9\u53ef\u80fd\u4f1a\u4f7f\u4ee3\u7801\u66f4\u590d\u6742\u3002 obj = pd.Series(range(5), index=['a', 'b', 'a', 'c', 'b']) print(obj) # a 0 # b 1 # a 2 # c 3 # b 4 # dtype: int64 print(obj.is_unique) # True print(obj.index.is_unique) # False # \u8fd4\u56de\u91cd\u590d\u7d22\u5f15\u5bf9\u5e94\u503c\u7684\u5e8f\u5217\u3002 print(obj['a']) # a 0 # a 2 # dtype: int64 df = pd.DataFrame(np.random.randn(4, 3), index=['a', 'a', 'b', 'b']) print(df) # 0 1 2 # a -0.726164 0.531540 -0.521611 # a -1.539807 -0.710880 -0.992789 # b -0.975970 -0.470725 0.121958 # b -0.301495 1.072322 -1.542296 print(df.index.is_unique) # False print(df.loc['b']) # 0 1 2 # b -0.520008 0.052574 0.638529 # b -1.928705 -1.099534 -1.605296","title":"\u542b\u6709\u91cd\u590d\u6807\u7b7e\u7684\u8f74\u7d22\u5f15"},{"location":"python/DataAnalysis/ch02/#_11","text":"pandas\u5305\u542b\u4e86\u4e00\u4e9b\u5e38\u7528\u6570\u5b66\u3001\u7edf\u8ba1\u5b66\u65b9\u6cd5\u3002\u5176\u4e2d\u5927\u90e8\u5206\u5c5e\u4e8e\u5f52\u7ea6\u6216\u6c47\u603b\u7edf\u8ba1\u7684\u7c7b\u522b\uff0c\u8fd9\u4e9b\u65b9\u6cd5\u4eceDataFrame\u7684\u884c\u6216\u5217\u4e2d\u62bd\u53d6\u4e00\u4e2aSeries\u6216\u4e00\u7cfb\u5217\u503c\uff08\u5982\u603b\u548c\u6216\u5e73\u5747\u503c\uff09\u3002 \u4e0eNumPy\u6570\u7ec4\u4e2d\u7684\u7c7b\u4f3c\u65b9\u6cd5\u76f8\u6bd4\uff0cpandas\u5185\u5efa\u4e86\u5904\u7406\u7f3a\u5931\u503c\u7684\u529f\u80fd\u3002 \u5f52\u7ea6\u65b9\u6cd5: sum() \u79ef\u7d2f\u578b\u65b9\u6cd5: cumsun() \u65e2\u4e0d\u662f\u5f52\u7ea6\u578b\u65b9\u6cd5\u4e5f\u4e0d\u662f\u79ef\u7d2f\u578b\u65b9\u6cd5: describe() df = pd.DataFrame( [[1.4, np.nan], [7.1, -4.5], [np.nan, np.nan], [0.75, -1.3]], index=list('abcd'), columns=['one', 'two'] ) print(df) # one two # a 1.40 NaN # b 7.10 -4.5 # c NaN NaN # d 0.75 -1.3 # axis=0, \u8fd4\u56de\u4e00\u4e2a\u6bcf\u5217\u7b97\u672f\u548c\u7684Series print(df.sum()) # one 9.25 # two -5.80 # dtype: float64 # axis=1\u4e14skipna=True, \u8fd4\u56de\u4e00\u4e2a\u6bcf\u884c\u548c\u7684Series, \u5ffd\u7565NA\u503c, \u586b0\u3002 print(df.sum(axis=1)) # a 1.40 # b 2.60 # c 0.00 # d -0.55 # dtype: float64 # \u4e0d\u5ffd\u7565NA\u503c\uff0c\u586bNaN\u3002 print(df.sum(axis=1, skipna=False)) # a NaN # b 2.60 # c NaN # d -0.55 # dtype: float64 # \u53ea\u67091\u7ea7\u7d22\u5f15\uff0c\u6240\u4ee5level=0\u548c\u539f\u7d22\u5f15\u6ca1\u6709\u533a\u522b\uff0cNaN\u586b\u51450\u3002 print(df.groupby(level=0).sum()) # one two # a 1.40 0.0 # b 7.10 -4.5 # c 0.00 0.0 # d 0.75 -1.3 # \u5217one\u7684\u6700\u5927\u503c\u662f\u5728\u7d22\u5f15b, \u5217two\u7684\u6700\u5927\u503c\u662f\u5728\u7d22\u5f15d print(df.idxmax()) # one b # two d # dtype: object print(df.idxmin()) # one d # two b # dtype: object # cumsun\u7684\u610f\u601d\u662f\u7b2cn\u6b21\u7684\u548c\u662fn-1\u6b21\u7684\u548c\u4e0en\u7684\u548c\uff0cone\u5217d\u884c\u7684\u548c\u5c31\u662fone\u5217a\u3001b\u3001c\u3001d\u503c\u7684\u603b\u548c\u3002 print(df.cumsum()) # one two # a 1.40 NaN # b 8.50 -4.5 # c NaN NaN # d 9.25 -5.8 \u901a\u8fc7describe\u4ea7\u751f\u7edf\u8ba1\u4fe1\u606f\uff0c\u6ce8\u610f\uff0c\u6570\u503c\u578b\u548c\u975e\u6570\u503c\u578b\u7684describe\u7684\u4fe1\u606f\u662f\u4e0d\u540c\u7684\u3002 # \u4e00\u6b21\u6027\u4ea7\u751f\u591a\u4e2a\u6c47\u603b\u7edf\u8ba1 print(df.describe()) # one two # count 3.000000 2.000000 # mean 3.083333 -2.900000 # std 3.493685 2.262742 # min 0.750000 -4.500000 # 25% 1.075000 -3.700000 # 50% 1.400000 -2.900000 # 75% 4.250000 -2.100000 # max 7.100000 -1.300000 obj = pd.Series(['a', 'a', 'b', 'c'] * 4) print(obj) # 0 a # 1 a # 2 b # 3 c # 4 a # 5 a # 6 b # 7 c # 8 a # 9 a # 10 b # 11 c # 12 a # 13 a # 14 b # 15 c # dtype: object # \u9488\u5bf9\u975e\u6570\u503c\u578b\u6570\u636e\uff0cdescribe\u4ea7\u751f\u53e6\u4e00\u79cd\u6c47\u603b\u7edf\u8ba1 print(obj.describe()) # count 16 # unique 3 # top a # freq 8 # dtype: object","title":"\u63cf\u8ff0\u6027\u7edf\u8ba1\u6982\u8ff0\u4e0e\u8ba1\u7b97"},{"location":"python/DataAnalysis/ch02/#_12","text":"\u534f\u65b9\u5dee\u4e0e\u76f8\u5173\u7cfb\u6570\u4e5f\u662f\u5728\u65f6\u57df\u5206\u6790\u65f6\u5e38\u89c1\u7684\u4e24\u4e2a\u6982\u5ff5\uff0c\u4ed6\u4eec\u90fd\u662f\u7528\u6765\u63cf\u8ff0\u6570\u636e\u201c\u50cf\u4e0d\u50cf\u201d\u7684\u3002 \u534f\u65b9\u5dee\u7684\u901a\u4fd7\u7406\u89e3\uff1a \u4e24\u4e2a\u53d8\u91cf\u5728\u53d8\u5316\u8fc7\u7a0b\u4e2d\u662f\u540c\u65b9\u5411\u53d8\u5316\u8fd8\u662f\u53cd\u65b9\u5411\u53d8\u5316\uff1f\u76f8\u540c\u6216\u8005\u76f8\u53cd\u7a0b\u5ea6\u5982\u4f55\uff1f \u4f60\u53d8\u5927\uff0c\u540c\u65f6\u6211\u53d8\u5927\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u662f\u540c\u5411\u53d8\u5316\uff0c\u8fd9\u65f6\u534f\u65b9\u5dee\u5c31\u662f\u6b63\u7684\u3002 \u4f60\u53d8\u5927\uff0c\u540c\u65f6\u6211\u53d8\u5c0f\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u662f\u53cd\u5411\u53d8\u5316\uff0c\u8fd9\u65f6\u534f\u65b9\u5dee\u5c31\u662f\u8d1f\u7684\u3002 \u4ece\u6570\u503c\u770b\uff0c\u534f\u65b9\u5dee\u7684\u6570\u503c\u8d8a\u5927\uff0c\u4e24\u4e2a\u53d8\u91cf\u540c\u5411\u7a0b\u5ea6\u4e5f\u5c31\u8d8a\u5927\u3002\u53cd\u4e4b\u4ea6\u7136\u3002 \u76f8\u5173\u7cfb\u6570\u7684\u901a\u4fd7\u7406\u89e3\uff1a \u7528X\uff0cY\u7684\u534f\u65b9\u5dee\u9664\u4ee5X\u7684\u6807\u51c6\u5dee\u548cY\u7684\u6807\u51c6\u5dee\u3002\u76f8\u5173\u7cfb\u6570\u4e5f\u53ef\u4ee5\u770b\u6210\u534f\u65b9\u5dee\uff0c\u4e00\u79cd\u63d0\u51fa\u4e86\u4e24\u4e2a\u53d8\u91cf\u91cf\u7eb2\u5f71\u54cd\u3001\u6807\u51c6\u5316\u540e\u7684\u7279\u6b8a\u534f\u65b9\u5dee\u3002\u6240\u4ee5\uff1a\u4e5f\u53ef\u4ee5\u53cd\u6620\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u65f6\u662f\u540c\u5411\u8fd8\u662f\u53cd\u5411\uff0c\u5982\u679c\u540c\u5411\u53d8\u5316\u5c31\u4e3a\u6b63\uff0c\u53cd\u5411\u53d8\u5316\u5c31\u4e3a\u8d1f\u3002 \u7531\u4e8e\u662f\u6807\u51c6\u7248\u540e\u7684\u534f\u65b9\u5dee\uff0c\u76f8\u5173\u7cfb\u6570\u6d88\u9664\u4e86\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u5e45\u5ea6\u7684\u5f71\u54cd\uff0c\u800c\u53ea\u662f\u5355\u7eaf\u53cd\u5e94\u4e24\u4e2a\u53d8\u91cf\u6bcf\u5355\u4f4d\u53d8\u5316\u65f6\u7684\u76f8\u4f3c\u7a0b\u5ea6\u3002 \u603b\u7ed3\uff1a \u5bf9\u4e8e\u4e24\u4e2a\u53d8\u91cfX\u3001Y\uff0c \u5f53\u4ed6\u4eec\u7684\u76f8\u5173\u7cfb\u6570\u4e3a1\u65f6\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u65f6\u7684\u6b63\u5411\u76f8\u4f3c\u5ea6\u6700\u5927\u3002 \u5f53\u4ed6\u4eec\u7684\u76f8\u5173\u7cfb\u6570\u4e3a\uff0d1\u65f6\uff0c\u8bf4\u660e\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u7684\u53cd\u5411\u76f8\u4f3c\u5ea6\u6700\u5927\u3002 \u968f\u7740\u4ed6\u4eec\u76f8\u5173\u7cfb\u6570\u51cf\u5c0f\uff0c\u4e24\u4e2a\u53d8\u91cf\u53d8\u5316\u65f6\u7684\u76f8\u4f3c\u5ea6\u4e5f\u53d8\u5c0f\uff0c\u5f53\u76f8\u5173\u7cfb\u6570\u4e3a0\u65f6\uff0c\u4e24\u4e2a\u53d8\u91cf\u7684\u53d8\u5316\u8fc7\u7a0b\u6ca1\u6709\u4efb\u4f55\u76f8\u4f3c\u5ea6\uff0c\u4e5f\u5373\u4e24\u4e2a\u53d8\u91cf\u65e0\u5173\u3002 \u5f53\u76f8\u5173\u7cfb\u6570\u7ee7\u7eed\u53d8\u5c0f\uff0c\u5c0f\u4e8e0\u65f6\uff0c\u4e24\u4e2a\u53d8\u91cf\u5f00\u59cb\u51fa\u73b0\u53cd\u5411\u7684\u76f8\u4f3c\u5ea6\uff0c\u968f\u7740\u76f8\u5173\u7cfb\u6570\u7ee7\u7eed\u53d8\u5c0f\uff0c\u53cd\u5411\u76f8\u4f3c\u5ea6\u4f1a\u9010\u6e10\u53d8\u5927\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u4f7f\u7528 pandas-datareader\uff1a https://pypi.org/project/pandas-datareader/ https://pydata.github.io/pandas-datareader/) \u5728\u6240\u6709\u4f8b\u5b50\u4e2d\uff0c\u5728\u8ba1\u7b97\u76f8\u5173\u6027\u4e4b\u524d\uff0c\u6570\u636e\u70b9\u5df2\u7ecf\u6309\u6807\u7b7e\u8fdb\u884c\u4e86\u5bf9\u9f50\u3002 \u4e0b\u4f8b\u9700\u8981\u901a\u8fc7pandas-datareader\u5e93\u4eceYahoo! Finance\u4e0a\u83b7\u53d6\u7684\u5305\u542b\u80a1\u4ef7\u548c\u4ea4\u6613\u91cf\u7684DataFrame\u3002 import pandas_datareader.data as web all_data = { ticker: web.get_data_yahoo(ticker) for ticker in ['AAPL', 'IBM', 'MSFT', 'GOOG'] } price = pd.DataFrame( { ticker: data['Adj Close'] for ticker, data in all_data.items() } ) volume = pd.DataFrame( { ticker: data['Volume'] for ticker, data in all_data.items() } ) returns = price.pct_change() print(returns.tail()) # AAPL IBM MSFT GOOG # Date # 2021-08-09 -0.000342 -0.008424 -0.003904 0.007049 # 2021-08-10 -0.003354 0.000920 -0.006555 0.000685 # 2021-08-11 0.001786 0.005305 0.001781 -0.002947 # 2021-08-12 0.020773 0.006614 0.009967 0.005084 # 2021-08-13 0.001410 0.000769 0.010490 0.000119 Series\u7684corr\u65b9\u6cd5\u8ba1\u7b97\u7684\u662f\u4e24\u4e2aSeries\u4e2d\u91cd\u53e0\u7684\u3001\u975eNA\u7684\u3001\u6309\u7d22\u5f15\u5bf9\u9f50\u7684\u503c\u7684\u76f8\u5173\u6027\u3002\u76f8\u5e94\u5730\uff0ccov\u8ba1\u7b97\u7684\u662f\u534f\u65b9\u5dee print(returns['MSFT']) # Date # 2016-08-15 NaN # 2016-08-16 -0.005540 # 2016-08-17 0.002089 # 2016-08-18 0.000695 # 2016-08-19 0.000347 # ... # 2021-08-09 -0.003904 # 2021-08-10 -0.006555 # 2021-08-11 0.001781 # 2021-08-12 0.009967 # 2021-08-13 0.010490 # Name: MSFT, Length: 1259, dtype: float64 # Series\u7684corr\u65b9\u6cd5\u8ba1\u7b97\u7684\u662f\u4e24\u4e2aSeries\u4e2d\u91cd\u53e0\u7684\u3001\u975eNA\u7684\u3001\u6309\u7d22\u5f15\u5bf9\u9f50\u7684\u503c\u7684\u76f8\u5173\u6027\u3002 print(returns['MSFT'].corr(returns['IBM'])) # 0.5175237180581937 # \u7b49\u540c\u5199\u6cd5\uff0cMSFT\u662f\u4e00\u4e2a\u6709\u6548\u7684Python\u5c5e\u6027 print(returns.MSFT.corr(returns.IBM)) # 0.5175237180581937 # Series\u7684cov\u65b9\u6cd5\u8ba1\u7b97\u7684\u662f\u4e24\u4e2aSeries\u4e2d\u503c\u7684\u534f\u65b9\u5dee\u3002 print(returns['MSFT'].cov(returns['IBM'])) # 0.0001452224236764915 DataFrame\u7684corr\u548ccov\u65b9\u6cd5\u4f1a\u5206\u522b\u4ee5DataFrame\u7684\u5f62\u5f0f\u8fd4\u56de\u76f8\u5173\u6027\u548c\u534f\u65b9\u5dee\u77e9\u9635\u3002 print(returns.corr()) # AAPL IBM MSFT GOOG # AAPL 1.000000 0.441111 0.735539 0.661961 # IBM 0.441111 1.000000 0.517524 0.484230 # MSFT 0.735539 0.517524 1.000000 0.775756 # GOOG 0.661961 0.484230 0.775756 1.000000 # \u7ed9corrwith\u65b9\u6cd5\uff0c\u4f20\u5165\u4e00\u4e2aSeries\u65f6\uff0c\u4f1a\u8fd4\u56de\u4e00\u4e2a\u542b\u6709\u4e3a\u6bcf\u5217\u8ba1\u7b97\u76f8\u5173\u6027\u503c\u7684Series print(returns.corrwith(returns['IBM'])) # AAPL 0.441111 # IBM 1.000000 # MSFT 0.517524 # GOOG 0.484230 # dtype: float64 # \u7ed9corrwith\u65b9\u6cd5\uff0c\u4f20\u5165\u4e00\u4e2aDataFrame\u65f6\uff0c\u4f1a\u8ba1\u7b97\u5339\u914d\u5230\u5217\u540d\u7684\u76f8\u5173\u6027\u6570\u503c\u3002\u4e0b\u9762\u662f\u8ba1\u7b97\u4ea4\u6613\u91cf\u767e\u5206\u6bd4\u53d8\u5316\u7684\u76f8\u5173\u6027 print(returns.corrwith(volume)) # AAPL -0.063111 # IBM -0.103721 # MSFT -0.056842 # GOOG -0.119026 # dtype: float64 print(returns.cov()) # AAPL IBM MSFT GOOG # AAPL 0.000361 0.000137 0.000240 0.000211 # IBM 0.000137 0.000268 0.000145 0.000133 # MSFT 0.000240 0.000145 0.000294 0.000224 # GOOG 0.000211 0.000133 0.000224 0.000282","title":"\u76f8\u5173\u6027\u548c\u534f\u65b9\u5dee"},{"location":"python/DataAnalysis/ch02/#_13","text":"obj = pd.Series(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c']) print(obj) # 0 c # 1 a # 2 d # 3 a # 4 a # 5 a # 6 b # 7 b # 8 c # 9 c # dtype: object \u51fd\u6570 unique \u7ed9\u51faSeries\u4e2d\u7684\u552f\u4e00\u503c\u3002 print(obj.unique()) # ['c' 'a' 'd' 'b'] print(obj.sort_values().unique()) # ['a' 'b' 'c' 'd'] # value_counts\u8ba1\u7b97Series\u5305\u542b\u7684\u503c\u7684\u4e2a\u6570 print(obj.value_counts()) # a 4 # c 3 # b 2 # d 1 # dtype: int64 # \u8fd9\u91ccvalue_counts\u4e0d\u662fSeries\u7684\u65b9\u6cd5\uff0c\u662fpandas\u9876\u5c42\u65b9\u6cd5 print(pd.value_counts(obj.values, sort=True)) # a 4 # c 3 # b 2 # d 1 # dtype: int64 print(obj.isin(['b', 'c'])) # 0 True # 1 False # 2 False # 3 False # 4 False # 5 False # 6 True # 7 True # 8 True # 9 True # dtype: bool # \u5c06\u4e0a\u9762\u7684\u7ed3\u679c\u4f5c\u4e3a\u5217\u8868\u8f93\u5165\u7684\u6761\u4ef6\uff0c\u8f93\u51fa\u4e3aTrue\u7684\u7ed3\u679c print(obj[obj.isin(['b', 'c'])]) # 0 c # 6 b # 7 b # 8 c # 9 c # dtype: object \u53c2\u8003: pandas.Index.get_indexer obj1 = pd.Series(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c']) obj2 = pd.Series(['c', 'a', 'b']) print(pd.Index(obj1)) # Index(['c', 'a', 'd', 'a', 'a', 'a', 'b', 'b', 'c', 'c'], dtype='object') print(pd.Index(obj2)) # Index(['c', 'a', 'b'], dtype='object') # \u8fd9\u91cc0\u5bf9\u5e94obj2\u91cc\u9762\u7684c\u5728job1\u7684\u4f4d\u7f6e\uff0c\u4ee5\u6b64\u7c7b\u63a8\uff0c\u751f\u6210\u65b0\u7684\u7d22\u5f15\u5217\u8868 print(pd.Index(obj2).get_indexer(obj1)) # [ 0 1 -1 1 1 1 2 2 0 0] \u8ba1\u7b97DataFrame\u591a\u4e2a\u76f8\u5173\u5217\u7684\u76f4\u65b9\u56fe\u3002 data = pd.DataFrame( { 'Que1': [1, 3, 4, 3, 4], 'Que2': [2, 3, 1, 2, 3], 'Que3': [1, 5, 2, 4, 4], } ) print(data) # Que1 Que2 Que3 # 0 1 2 1 # 1 3 3 5 # 2 4 1 2 # 3 3 2 4 # 4 4 3 4 result = data.apply(pd.value_counts).fillna(0) # \u4e0b\u9762\u7ed3\u679c\u4e2d\u7684\u884c\u6807\u7b7e\u662f\u6240\u6709\u5217\u4e2d\u51fa\u73b0\u7684\u4e0d\u540c\u503c\uff0c\u6570\u503c\u5219\u662f\u8fd9\u4e9b\u4e0d\u540c\u503c\u5728\u6bcf\u4e2a\u5217\u4e2d\u51fa\u73b0\u7684\u6b21\u6570\uff0c\u4f8b\u5982\uff1a\u6570\u5b575\u53ea\u5728Que3\u91cc\u9762\u51fa\u73b0\u4e86\u4e00\u6b21 print(result) # Que1 Que2 Que3 # 1 1.0 1.0 1.0 # 2 0.0 2.0 1.0 # 3 2.0 2.0 0.0 # 4 2.0 0.0 2.0 # 5 0.0 0.0 1.0","title":"\u552f\u4e00\u503c\u3001\u8ba1\u6570\u548c\u6210\u5458\u5c5e\u6027"},{"location":"python/DataAnalysis/ch03/","text":"\u6570\u636e\u8f7d\u5165\u3001\u5b58\u50a8\u53ca\u6587\u4ef6\u683c\u5f0f \u00b6 \u6587\u672c\u683c\u5f0f\u6570\u636e\u7684\u8bfb\u5199 \u00b6 import numpy as np import pandas as pd import sys import csv import json \u5c06\u8868\u683c\u578b\u6570\u636e\u8bfb\u53d6\u4e3aDataFrame\u5bf9\u8c61\u662fpandas\u7684\u91cd\u8981\u7279\u6027\u3002 \u4e0b\u9762\u662f\u90e8\u5206\u5b9e\u73b0\u6587\u4ef6\u8bfb\u53d6\u529f\u80fd\u7684\u51fd\u6570\uff0cread_csv\u548cread_table\u53ef\u80fd\u662f\u540e\u671f\u6211\u4eec\u4f7f\u7528\u6700\u591a\u7684\u51fd\u6570\u3002 \u8fd9\u4e9b\u51fd\u6570\u7684\u53ef\u9009\u53c2\u6570\u4e3b\u8981\u6709\u4ee5\u4e0b\u51e0\u79cd\u7c7b\u578b\uff1a \u7d22\u5f15\uff1a\u53ef\u4ee5\u5c06\u4e00\u5217\u6216\u591a\u4e2a\u5217\u4f5c\u4e3a\u8fd4\u56de\u7684DataFrame\uff0c\u4ece\u6587\u4ef6\u6216\u7528\u6237\u5904\u83b7\u5f97\u5217\u540d\uff0c\u6216\u8005\u6ca1\u6709\u5217\u540d\u3002 \u7c7b\u578b\u63a8\u65ad\u548c\u6570\u636e\u8f6c\u6362\uff1a\u5305\u62ec\u7528\u6237\u81ea\u5b9a\u4e49\u7684\u503c\u8f6c\u6362\u548c\u81ea\u5b9a\u4e49\u7684\u7f3a\u5931\u503c\u7b26\u53f7\u5217\u8868\u3002 \u65e5\u671f\u65f6\u95f4\u89e3\u6790\uff1a\u5305\u62ec\u7ec4\u5408\u529f\u80fd\uff0c\u4e5f\u5305\u62ec\u5c06\u5206\u6563\u5728\u591a\u4e2a\u5217\u4e0a\u7684\u65e5\u671f\u548c\u65f6\u95f4\u4fe1\u606f\u7ec4\u5408\u6210\u7ed3\u679c\u4e2d\u7684\u5355\u4e2a\u5217\u3002 \u8fed\u4ee3\uff1a\u652f\u6301\u5bf9\u5927\u578b\u6587\u4ef6\u7684\u5206\u5757\u8fed\u4ee3\u3002 \u672a\u6e05\u6d17\u6570\u636e\u95ee\u9898\uff1a\u8df3\u8fc7\u884c\u3001\u9875\u811a\u3001\u6ce8\u91ca\u4ee5\u53ca\u5176\u4ed6\u6b21\u8981\u6570\u636e\uff0c\u6bd4\u5982\u4f7f\u7528\u9017\u53f7\u5206\u9694\u5343\u4f4d\u7684\u6570\u5b57\u3002 file01 = '../examples/ex1.csv' # \u4f7f\u7528read_csv\u5c06\u6587\u4ef6\u8bfb\u5165\u4e00\u4e2aDataFrame df = pd.read_csv(file01) print(df) # 1 2 3 4 hello # 0 5 6 7 8 world # 1 9 10 11 12 foo df = pd.read_csv(file01, header=None) # \u4f7f\u7528pandas\u81ea\u52a8\u5206\u914d\u9ed8\u8ba4\u5217\u540d print(df) # 0 1 2 3 4 # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo df = pd.read_csv(file01, names=['aa', 'bb', 'cc', 'dd', 'message']) # \u81ea\u5df1\u6307\u5b9a\u5217\u540d print(df) # aa bb cc dd ee # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo # \u4f7f\u7528read_table\uff0c\u5e76\u6307\u5b9a\u5206\u9694\u7b26\uff0c\u5c06\u6587\u4ef6\u8bfb\u5165\u4e00\u4e2aDataFrame df = pd.read_table(file01, sep=',') print(df) # a b c d message # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo \u4ece\u591a\u4e2a\u5217\u4e2d\u5f62\u6210\u4e00\u4e2a\u5206\u5c42\u7d22\u5f15 parased = pd.read_csv('../examples/csv_mindex.csv', index_col=['key1', 'key2']) print(parased) # value1 value2 # key1 key2 # one a 1 2 # b 3 4 # c 5 6 # d 7 8 # two a 9 10 # b 11 12 # c 13 14 # d 15 16 \u4e0b\u4f8b\u4e2d\uff0c\u7531\u4e8e\u5217\u540d\u7684\u6570\u91cf\u6bd4\u6570\u636e\u7684\u5217\u6570\u5c11\u4e00\u4e2a\uff0c\u56e0\u6b64read_table\u63a8\u65ad\u7b2c\u4e00\u5217\u5e94\u5f53\u4f5c\u4e3aDataFrame\u7684\u7d22\u5f15\u3002 ex3.txt\u539f\u59cb\u6587\u4ef6\u5185\u5bb9 A B C aaa -0.264438 -1.026059 -0.619500 bbb 0.927272 0.302904 -0.032399 ccc -0.264273 -0.386314 -0.217601 ddd -0.871858 -0.348382 1.100491 result = pd.read_table('../examples/ex3.txt') # \u76f4\u63a5\u8bfb\u53d6 print(result) # A B C # aaa -0.264438 -1.026059 -0.619500 # bbb 0.927272 0.302904 -0.032399 NaN # ccc -0.264273 -0.386314 -0.217601 # ddd -0.871858 -0.348382 1.100491 result = pd.read_table('../examples/ex3.txt', sep='\\s+') # \u5411read_table\u6b63\u5219\u8868\u8fbe\u5f0f\u4e3a\\s+\u6765\u683c\u5f0f\u5316\u6587\u4ef6 print(result) # A B C # aaa -0.264438 -1.026059 -0.619500 # bbb 0.927272 0.302904 -0.032399 # ccc -0.264273 -0.386314 -0.217601 # ddd -0.871858 -0.348382 1.100491 \u4e0b\u4f8b\u4e2dex4.csv\u539f\u59cb\u6587\u4ef6\u5185\u5bb9 # hey! a,b,c,d,message # just wanted to make things more difficult for you # who reads CSV files with computers, anyway? 1,2,3,4,hello 5,6,7,8,world 9,10,11,12,foo result = pd.read_csv('../examples/ex4.csv', skiprows=[0, 2, 3]) # \u4f7f\u7528skiprows\u6765\u8df3\u8fc7\u7b2c\u4e00\u884c\u3001\u7b2c\u4e09\u884c\u548c\u7b2c\u56db\u884c print(result) # a b c d message # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo \u7f3a\u5931\u503c\u5904\u7406 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cpandas\u4f7f\u7528\u4e00\u4e9b\u5e38\u89c1\u7684\u6807\u8bc6\uff0c\u4f8b\u5982 NA \u548c NULL \u4e0b\u4f8b\u4e2dex5.csv\u539f\u59cb\u6587\u4ef6\u5185\u5bb9 something,a,b,c,d,message one,1,2,3,4,NA two,5,6,,8,world three,9,10,11,12,foo result = pd.read_csv('../examples/ex5.csv') print(result) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 two 5 6 NaN 8 world # 2 three 9 10 11.0 12 foo print(pd.isnull(result)) # something a b c d message # 0 False False False False False True # 1 False False False True False False # 2 False False False False False False result = pd.read_csv('../examples/ex5.csv', na_values=['NULL']) print(result) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 two 5 6 NaN 8 world # 2 three 9 10 11.0 12 foo \u5b9a\u4e49\u66ff\u6362\u89c4\u5219 sentinels = { 'message': ['foo', 'NA'], 'something': ['two'] } result = pd.read_csv('../examples/ex5.csv', na_values=sentinels) \u628amessage\u5217\u6240\u6709\u503c\u4e3afoo\u6216NA\u7684\u66ff\u6362\u4e3aNull \u628asomething\u5217\u6240\u6709\u503c\u4e3atwo\u7684\u66ff\u6362\u4e3aNull print(result) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 NaN 5 6 NaN 8 world # 2 three 9 10 11.0 12 NaN \u5206\u5757\u8bfb\u5165\u6587\u672c\u6587\u4ef6 \u00b6 pd.options.display.max_rows = 10 result = pd.read_csv('../examples/ex6.csv') # \u8bfb\u53d6\u5168\u90e8\u8bb0\u5f55 print(result) result = pd.read_csv('../examples/ex6.csv', nrows=5) # \u8bfb\u53d6\u524d5\u884c\u8bb0\u5f55 print(result) # [10000 rows x 5 columns] # one two three four key # 0 0.467976 -0.038649 -0.295344 -1.824726 L # 1 -0.358893 1.404453 0.704965 -0.200638 B # 2 -0.501840 0.659254 -0.421691 -0.057688 G # 3 0.204886 1.074134 1.388361 -0.982404 R # 4 0.354628 -0.133116 0.283763 -0.837063 Q result = pd.read_csv('../examples/ex6.csv', chunksize=1000) # \u5206\u5757\u8bfb\u5165\u6587\u4ef6\uff0c\u6bcf\u57571000\u884c print(result) # \u8fd4\u56de\u7684\u662f\u4e00\u4e2aTextParser\u5bf9\u8c61, \u5141\u8bb8\u4f60\u6839\u636echunksize\u904d\u5386\u6587\u4ef6\u3002 # \u53ef\u4ee5\u904d\u5386 ex6.csv \uff0c\u5e76\u5bf9 key \u5217\u805a\u5408\u83b7\u5f97\u8ba1\u6570\u503c tot = pd.Series([], dtype=float) # \u8fd9\u91cc\u9700\u8981\u663e\u5f0f\u6307\u5b9adtype\uff0c\u540e\u7eedPython\u4f1a\u5c06\u9ed8\u8ba4\u503c\u4ecefloat64\u53d8\u6210object\uff0c\u76ee\u524d\u9ed8\u8ba4\u662ffloat64 for piece in result: tot = tot.add(piece['key'].value_counts(), fill_value=0) tot = tot.sort_values(ascending=False) print(tot[:10]) # E 368.0 # X 364.0 # L 346.0 # O 343.0 # Q 340.0 # M 338.0 # J 337.0 # F 335.0 # K 334.0 # H 330.0 # dtype: float64 \u5c06\u6570\u636e\u5199\u5165\u6587\u672c\u683c\u5f0f \u00b6 data = pd.read_csv('../examples/ex5.csv') print(data) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 two 5 6 NaN 8 world # 2 three 9 10 11.0 12 foo \u4f7f\u7528DataFrame\u7684 to_csv \u65b9\u6cd5\uff0c\u5c06\u6570\u636e\u5bfc\u51fa\u4e3a\u9017\u53f7\u5206\u9694\u7684\u6587\u4ef6 data.to_csv('../examples/out.csv') # \u8f93\u51faout.csv\u7684\u5185\u5bb9 # ,something,a,b,c,d,message # 0,one,1,2,3.0,4, # 1,two,5,6,,8,world # 2,three,9,10,11.0,12,foo \u4f7f\u7528DataFrame\u7684 to_csv \u65b9\u6cd5\uff0c\u5c06\u6570\u636e\u5bfc\u51fa\u4e3a\u5176\u4ed6\u7684\u5206\u9694\u7b26\u7684\u6587\u4ef6 data.to_csv(sys.stdout, sep='|') # |something|a|b|c|d|message # 0|one|1|2|3.0|4| # 1|two|5|6||8|world # 2|three|9|10|11.0|12|foo data.to_csv(sys.stdout, sep=',') # ,something,a,b,c,d,message # 0,one,1,2,3.0,4, # 1,two,5,6,,8,world # 2,three,9,10,11.0,12,foo data.to_csv(sys.stdout, sep=',', na_rep='NULL') # \u8bbe\u5b9a\u7f3a\u5931\u503c\u5728\u8f93\u51fa\u65f6\u4ee5\u7a7a\u5b57\u7b26\u4e32\u51fa\u73b0 # ,something,a,b,c,d,message # 0,one,1,2,3.0,4,NULL # 1,two,5,6,NULL,8,world # 2,three,9,10,11.0,12,foo data.to_csv(sys.stdout, sep=',', na_rep='NULL', index=False, header=False) # \u4e0d\u8f93\u51fa\u884c\u548c\u5217\u7684\u6807\u7b7e\uff08index\uff0cheader\uff09 # one,1,2,3.0,4,NULL # two,5,6,NULL,8,world # three,9,10,11.0,12,foo data.to_csv(sys.stdout, sep=',', na_rep='NULL', index=False, header=False, columns=['a', 'b', 'c']) # \u6309\u7167\u81ea\u5b9a\u7684\u987a\u5e8f\u8f93\u51fa\u5b50\u96c6 # 1,2,3.0 # 5,6,NULL # 9,10,11.0 Series\u4e5f\u6709 to_csv \u65b9\u6cd5 dates = pd.date_range('1/1/2000', periods=7) ts = pd.Series(np.arange(7), index=dates) ts.to_csv('../examples/tseries.csv', header=False) # \u8f93\u51fatseries.csv\u6587\u4ef6\u5185\u5bb9 # 2000-01-01,0 # 2000-01-02,1 # 2000-01-03,2 # 2000-01-04,3 # 2000-01-05,4 # 2000-01-06,5 # 2000-01-07,6 \u4f7f\u7528\u5206\u9694\u683c\u5f0f \u00b6 \u7edd\u5927\u591a\u6570\u7684\u8868\u578b\u6570\u636e\u90fd\u53ef\u4ee5\u4f7f\u7528\u51fd\u6570 pandas.read_table \u4ece\u786c\u76d8\u4e2d\u8bfb\u53d6\u3002 \u7136\u800c\uff0c\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u63a5\u6536\u4e00\u4e2a\u5e26\u6709\u4e00\u884c\u6216\u591a\u884c\u9519\u8bef\u7684\u6587\u4ef6\u5e76\u4e0d\u5c11\u89c1\uff0c read_table \u4e5f\u65e0\u6cd5\u89e3\u51b3\u8fd9\u79cd\u60c5\u51b5\u3002 ex7.csv \u6587\u4ef6\u5185\u5bb9 \"a\",\"b\",\"c\" \"1\",\"2\",\"3\" \"1\",\"2\",\"3\" f = open('../examples/ex7.csv') # \u4f7f\u7528Python\u7684\u5185\u5efacsv\u6a21\u5757 reader = csv.reader(f) # \u5c06\u4efb\u4e00\u6253\u5f00\u7684\u6587\u4ef6\u6216\u6587\u4ef6\u578b\u5bf9\u8c61\u4f20\u7ed9csv.reader for line in reader: # # \u904d\u5386reader\uff0c\u4ea7\u751f\u5143\u7ec4\uff0c\u5143\u7ec4\u7684\u503c\u4e3a\u5220\u9664\u4e86\u5f15\u53f7\u7684\u5b57\u7b26 print(line) f.close() # ['a', 'b', 'c'] # ['1', '2', '3'] # ['1', '2', '3'] with open('../examples/ex7.csv') as f: lines = list(csv.reader(f)) # \u9996\u5148\uff0c\u5c06\u6587\u4ef6\u8bfb\u53d6\u4e3a\u884c\u7684\u5217\u8868 header, values = lines[0], lines[1:] # \u5176\u6b21\uff0c\u5c06\u6570\u636e\u62c6\u5206\u4e3a\u5217\u540d\u884c\u548c\u6570\u636e\u884c data_dict = { h: v for h, v in zip(header, zip(*values)) # \u518d\u7136\u540e\uff0c\u4f7f\u7528\u5b57\u5178\u63a8\u5bfc\u5f0f\u548c\u8868\u8fbe\u5f0fzip(*values)\u751f\u6210\u4e00\u4e2a\u5305\u542b\u6570\u636e\u5217\u7684\u5b57\u5178\uff0c\u5b57\u5178\u4e2d\u884c\u8f6c\u7f6e\u6210\u5217 } print(data_dict) # \u8f93\u51fa\u7ed3\u679c # {'a': ('1', '1'), 'b': ('2', '2'), 'c': ('3', '3')} \u5982\u679c\u9700\u6839\u636e\u4e0d\u540c\u7684\u5206\u9694\u7b26\u3001\u5b57\u7b26\u4e32\u5f15\u7528\u7ea6\u5b9a\u6216\u884c\u7ec8\u6b62\u7b26\u5b9a\u4e49\u4e00\u79cd\u65b0\u7684\u683c\u5f0f\u65f6\uff0c\u53ef\u4ee5: \u65b9\u6cd51\uff1a\u4f7f\u7528csv.Dialect\u5b9a\u4e49\u4e00\u4e2a\u7b80\u5355\u7684\u5b50\u7c7b class my_dialect(csv.Dialect): lineterminator = '\\n' delimiter = ';' # \u8fd9\u91cc\u53ea\u80fd\u662f\u4e00\u4e2a\u5b57\u7b26 quotechar = '\"' quoting = csv.QUOTE_MINIMAL f = open('../examples/ex7.csv') reader = csv.reader(f, dialect=my_dialect) for line in reader: # \u904d\u5386reader\uff0c\u4ea7\u751f\u5143\u7ec4\uff0c\u5143\u7ec4\u7684\u503c\u4e3a\u5220\u9664\u4e86\u5f15\u53f7\u7684\u5b57\u7b26 print(line) f.close() # ['a,\"b\",\"c\"'] # ['1,\"2\",\"3\"'] # ['1,\"2\",\"3\"'] \u65b9\u6cd52\uff1a\u76f4\u63a5\u5c06CSV\u65b9\u8a00\u53c2\u6570(dialect)\u4f20\u5165csv.reader\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 \u6bd4\u8f83\u8be6\u7ec6\u7684 \u4ecb\u7ecd\u65b9\u8a00\u548c\u5206\u9694\u7b26 f = open('../examples/ex7.csv') reader = csv.reader(f, delimiter='|') for line in reader: # \u904d\u5386reader\uff0c\u4ea7\u751f\u5143\u7ec4\uff0c\u5143\u7ec4\u7684\u503c\u4e3a\u5220\u9664\u4e86\u5f15\u53f7\u7684\u5b57\u7b26 print(line) f.close() # ['a,\"b\",\"c\"'] # ['1,\"2\",\"3\"'] # ['1,\"2\",\"3\"'] \u5bf9\u4e8e\u5177\u6709\u66f4\u590d\u6742\u6216\u56fa\u5b9a\u7684\u591a\u5b57\u7b26\u5206\u9694\u7b26\u7684\u6587\u4ef6\uff0c\u5c06\u65e0\u6cd5\u4f7f\u7528csv\u6a21\u5757\u3002 \u5728\u6b64\u7c7b\u60c5\u51b5\u4e0b\uff0c\u5c06\u4f7f\u7528\u5b57\u7b26\u4e32\u7684split\u65b9\u6cd5\u6216\u6b63\u5219\u8868\u8fbe\u5f0f\u65b9\u6cd5re.split\u8fdb\u884c\u884c\u62c6\u5206\u548c\u5176\u4ed6\u6e05\u7406\u5de5\u4f5c\u3002 \u9700\u8981\u624b\u52a8\u5199\u5165\u88ab\u5206\u9694\u7684\u6587\u4ef6\u65f6\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528csv.writer\u3002 \u8fd9\u4e2a\u51fd\u6570\u63a5\u6536\u4e00\u4e2a\u5df2\u7ecf\u6253\u5f00\u7684\u53ef\u5199\u5165\u6587\u4ef6\u5bf9\u8c61\u4ee5\u53ca\u548ccsv.reader\u76f8\u540c\u7684CSV\u65b9\u8a00\u3001\u683c\u5f0f\u9009\u9879. with open('../examples/mydata.csv', 'w') as f: writer = csv.writer(f, dialect=my_dialect) writer.writerow(('1', '2', '3')) writer.writerow(('4', '5', '6')) writer.writerow(('7', '8', '9')) writer.writerow(('10', '11', '12')) # mydata.csv \u6587\u4ef6\u5185\u5bb9 # 1;2;3 # 4;5;6 # 7;8;9 # 10;11;12 JSON\u6570\u636e \u00b6 obj = \"\"\" { \"name\": \"Wes\", \"places_lived\": [\"United States\", \"Spain\", \"Germany\"], \"pet\": null, \"siblings\": [ { \"name\": \"Scott\", \"age\": 30, \"pets\": [\"Zeus\", \"Zuko\"] }, { \"name\": \"Katie\", \"age\": 38, \"pets\": [\"Sixes\", \"Stache\", \"Cisco\"] } ] } \"\"\" \u5c06JSON\u5b57\u7b26\u4e32\u8f6c\u6362\u4e3aPython\u5f62\u5f0f\u65f6\uff0c\u4f7f\u7528json.loads\u65b9\u6cd5 result = json.loads(obj) print(result) # {'name': 'Wes', 'places_lived': ['United States', 'Spain', 'Germany'], 'pet': None, 'siblings': [{'name': 'Scott', 'age': 30, 'pets': ['Zeus', 'Zuko']}, {'name': 'Katie', 'age': 38, 'pets': ['Sixes', 'Stache', 'Cisco']}]} \u53e6\u4e00\u65b9\u9762\uff0cjson.dumps\u53ef\u4ee5\u5c06Python\u5bf9\u8c61\u8f6c\u6362\u56deJSON asjson = json.dumps(result) print(asjson) # {\"name\": \"Wes\", \"places_lived\": [\"United States\", \"Spain\", \"Germany\"], \"pet\": null, \"siblings\": [{\"name\": \"Scott\", \"age\": 30, \"pets\": [\"Zeus\", \"Zuko\"]}, {\"name\": \"Katie\", \"age\": 38, \"pets\": [\"Sixes\", \"Stache\", \"Cisco\"]}]} \u5c06JSON\u5bf9\u8c61\u6216\u5bf9\u8c61\u5217\u8868\u8f6c\u6362\u4e3aDataFrame\u6216\u5176\u4ed6\u6570\u636e\u7ed3\u6784\u3002 \u6bd4\u8f83\u65b9\u4fbf\u7684\u65b9\u5f0f\u662f\u5c06\u5b57\u5178\u6784\u6210\u7684\u5217\u8868\uff08\u4e4b\u524d\u662fJSON\u5bf9\u8c61\uff09\u4f20\u5165DataFrame\u6784\u9020\u51fd\u6570\uff0c\u5e76\u9009\u51fa\u6570\u636e\u5b57\u6bb5\u7684\u5b50\u96c6\u3002 siblings = pd.DataFrame(result['siblings'], columns=['name', 'age']) print(siblings) # name age # 0 Scott 30 # 1 Katie 38 pandas.read_json\u53ef\u4ee5\u81ea\u52a8\u5c06JSON\u6570\u636e\u96c6\u6309\u7167\u6307\u5b9a\u6b21\u5e8f\u8f6c\u6362\u4e3aSeries\u6216DataFrame\u3002 pandas.read_json\u7684\u9ed8\u8ba4\u9009\u9879\u662f\u5047\u8bbeJSON\u6570\u7ec4\u4e2d\u7684\u6bcf\u4e2a\u5bf9\u8c61\u662f\u8868\u91cc\u7684\u4e00\u884c\u3002 \u4f8b\u5982\u8bfb\u53d6 data = pd.read_json('../examples/example_new.json') data = pd.read_json('../examples/example.json') print(data) # a b c # 0 1 2 3 # 1 4 5 6 # 2 7 8 9 print(data.to_json()) # {\"a\":{\"0\":1,\"1\":4,\"2\":7},\"b\":{\"0\":2,\"1\":5,\"2\":8},\"c\":{\"0\":3,\"1\":6,\"2\":9}} print(data.to_json(orient='records')) # [{\"a\":1,\"b\":2,\"c\":3},{\"a\":4,\"b\":5,\"c\":6},{\"a\":7,\"b\":8,\"c\":9}] XML\u548cHTML\uff1a\u7f51\u7edc\u6293\u53d6 \u00b6 pandas\u7684\u5185\u5efa\u51fd\u6570read_html\u53ef\u4ee5\u4f7f\u7528lxml\u548cBeautiful Soup\u7b49\u5e93\u5c06HTML\u4e2d\u7684\u8868\u81ea\u52a8\u89e3\u6790\u4e3aDataFrame\u5bf9\u8c61\u3002 tables = pd.read_html('../examples/fdic_failed_bank_list.html') print(len(tables)) # 1 failures = tables[0] # //*[@id=\"table\"] print(failures.head()) # \u8bfb\u53d6\u524d5\u884c\u8bb0\u5f55 # Bank Name ... Updated Date # 0 Allied Bank ... November 17, 2016 # 1 The Woodbury Banking Company ... November 17, 2016 # 2 First CornerStone Bank ... September 6, 2016 # 3 Trust Company Bank ... September 6, 2016 # 4 North Milwaukee State Bank ... June 16, 2016 # # [5 rows x 7 columns] close_timestamps = pd.to_datetime(failures['Closing Date']) # \u8ba1\u7b97\u6bcf\u5e74\u94f6\u884c\u5012\u95ed\u7684\u6570\u91cf print(close_timestamps.dt.year.value_counts()) # 2010 157 # 2009 140 # 2011 92 # 2012 51 # 2008 25 # ... # 2004 4 # 2001 4 # 2007 3 # 2003 3 # 2000 2 # Name: Closing Date, Length: 15, dtype: int64 \u4e8c\u8fdb\u5236\u683c\u5f0f \u00b6 \u4e0eWeb API\u4ea4\u4e92 \u00b6 \u4e0e\u6570\u636e\u5e93\u4ea4\u4e92 \u00b6","title":"\u6570\u636e\u8f7d\u5165\u3001\u5b58\u50a8\u53ca\u6587\u4ef6\u683c\u5f0f"},{"location":"python/DataAnalysis/ch03/#_1","text":"","title":"\u6570\u636e\u8f7d\u5165\u3001\u5b58\u50a8\u53ca\u6587\u4ef6\u683c\u5f0f"},{"location":"python/DataAnalysis/ch03/#_2","text":"import numpy as np import pandas as pd import sys import csv import json \u5c06\u8868\u683c\u578b\u6570\u636e\u8bfb\u53d6\u4e3aDataFrame\u5bf9\u8c61\u662fpandas\u7684\u91cd\u8981\u7279\u6027\u3002 \u4e0b\u9762\u662f\u90e8\u5206\u5b9e\u73b0\u6587\u4ef6\u8bfb\u53d6\u529f\u80fd\u7684\u51fd\u6570\uff0cread_csv\u548cread_table\u53ef\u80fd\u662f\u540e\u671f\u6211\u4eec\u4f7f\u7528\u6700\u591a\u7684\u51fd\u6570\u3002 \u8fd9\u4e9b\u51fd\u6570\u7684\u53ef\u9009\u53c2\u6570\u4e3b\u8981\u6709\u4ee5\u4e0b\u51e0\u79cd\u7c7b\u578b\uff1a \u7d22\u5f15\uff1a\u53ef\u4ee5\u5c06\u4e00\u5217\u6216\u591a\u4e2a\u5217\u4f5c\u4e3a\u8fd4\u56de\u7684DataFrame\uff0c\u4ece\u6587\u4ef6\u6216\u7528\u6237\u5904\u83b7\u5f97\u5217\u540d\uff0c\u6216\u8005\u6ca1\u6709\u5217\u540d\u3002 \u7c7b\u578b\u63a8\u65ad\u548c\u6570\u636e\u8f6c\u6362\uff1a\u5305\u62ec\u7528\u6237\u81ea\u5b9a\u4e49\u7684\u503c\u8f6c\u6362\u548c\u81ea\u5b9a\u4e49\u7684\u7f3a\u5931\u503c\u7b26\u53f7\u5217\u8868\u3002 \u65e5\u671f\u65f6\u95f4\u89e3\u6790\uff1a\u5305\u62ec\u7ec4\u5408\u529f\u80fd\uff0c\u4e5f\u5305\u62ec\u5c06\u5206\u6563\u5728\u591a\u4e2a\u5217\u4e0a\u7684\u65e5\u671f\u548c\u65f6\u95f4\u4fe1\u606f\u7ec4\u5408\u6210\u7ed3\u679c\u4e2d\u7684\u5355\u4e2a\u5217\u3002 \u8fed\u4ee3\uff1a\u652f\u6301\u5bf9\u5927\u578b\u6587\u4ef6\u7684\u5206\u5757\u8fed\u4ee3\u3002 \u672a\u6e05\u6d17\u6570\u636e\u95ee\u9898\uff1a\u8df3\u8fc7\u884c\u3001\u9875\u811a\u3001\u6ce8\u91ca\u4ee5\u53ca\u5176\u4ed6\u6b21\u8981\u6570\u636e\uff0c\u6bd4\u5982\u4f7f\u7528\u9017\u53f7\u5206\u9694\u5343\u4f4d\u7684\u6570\u5b57\u3002 file01 = '../examples/ex1.csv' # \u4f7f\u7528read_csv\u5c06\u6587\u4ef6\u8bfb\u5165\u4e00\u4e2aDataFrame df = pd.read_csv(file01) print(df) # 1 2 3 4 hello # 0 5 6 7 8 world # 1 9 10 11 12 foo df = pd.read_csv(file01, header=None) # \u4f7f\u7528pandas\u81ea\u52a8\u5206\u914d\u9ed8\u8ba4\u5217\u540d print(df) # 0 1 2 3 4 # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo df = pd.read_csv(file01, names=['aa', 'bb', 'cc', 'dd', 'message']) # \u81ea\u5df1\u6307\u5b9a\u5217\u540d print(df) # aa bb cc dd ee # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo # \u4f7f\u7528read_table\uff0c\u5e76\u6307\u5b9a\u5206\u9694\u7b26\uff0c\u5c06\u6587\u4ef6\u8bfb\u5165\u4e00\u4e2aDataFrame df = pd.read_table(file01, sep=',') print(df) # a b c d message # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo \u4ece\u591a\u4e2a\u5217\u4e2d\u5f62\u6210\u4e00\u4e2a\u5206\u5c42\u7d22\u5f15 parased = pd.read_csv('../examples/csv_mindex.csv', index_col=['key1', 'key2']) print(parased) # value1 value2 # key1 key2 # one a 1 2 # b 3 4 # c 5 6 # d 7 8 # two a 9 10 # b 11 12 # c 13 14 # d 15 16 \u4e0b\u4f8b\u4e2d\uff0c\u7531\u4e8e\u5217\u540d\u7684\u6570\u91cf\u6bd4\u6570\u636e\u7684\u5217\u6570\u5c11\u4e00\u4e2a\uff0c\u56e0\u6b64read_table\u63a8\u65ad\u7b2c\u4e00\u5217\u5e94\u5f53\u4f5c\u4e3aDataFrame\u7684\u7d22\u5f15\u3002 ex3.txt\u539f\u59cb\u6587\u4ef6\u5185\u5bb9 A B C aaa -0.264438 -1.026059 -0.619500 bbb 0.927272 0.302904 -0.032399 ccc -0.264273 -0.386314 -0.217601 ddd -0.871858 -0.348382 1.100491 result = pd.read_table('../examples/ex3.txt') # \u76f4\u63a5\u8bfb\u53d6 print(result) # A B C # aaa -0.264438 -1.026059 -0.619500 # bbb 0.927272 0.302904 -0.032399 NaN # ccc -0.264273 -0.386314 -0.217601 # ddd -0.871858 -0.348382 1.100491 result = pd.read_table('../examples/ex3.txt', sep='\\s+') # \u5411read_table\u6b63\u5219\u8868\u8fbe\u5f0f\u4e3a\\s+\u6765\u683c\u5f0f\u5316\u6587\u4ef6 print(result) # A B C # aaa -0.264438 -1.026059 -0.619500 # bbb 0.927272 0.302904 -0.032399 # ccc -0.264273 -0.386314 -0.217601 # ddd -0.871858 -0.348382 1.100491 \u4e0b\u4f8b\u4e2dex4.csv\u539f\u59cb\u6587\u4ef6\u5185\u5bb9 # hey! a,b,c,d,message # just wanted to make things more difficult for you # who reads CSV files with computers, anyway? 1,2,3,4,hello 5,6,7,8,world 9,10,11,12,foo result = pd.read_csv('../examples/ex4.csv', skiprows=[0, 2, 3]) # \u4f7f\u7528skiprows\u6765\u8df3\u8fc7\u7b2c\u4e00\u884c\u3001\u7b2c\u4e09\u884c\u548c\u7b2c\u56db\u884c print(result) # a b c d message # 0 1 2 3 4 hello # 1 5 6 7 8 world # 2 9 10 11 12 foo \u7f3a\u5931\u503c\u5904\u7406 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cpandas\u4f7f\u7528\u4e00\u4e9b\u5e38\u89c1\u7684\u6807\u8bc6\uff0c\u4f8b\u5982 NA \u548c NULL \u4e0b\u4f8b\u4e2dex5.csv\u539f\u59cb\u6587\u4ef6\u5185\u5bb9 something,a,b,c,d,message one,1,2,3,4,NA two,5,6,,8,world three,9,10,11,12,foo result = pd.read_csv('../examples/ex5.csv') print(result) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 two 5 6 NaN 8 world # 2 three 9 10 11.0 12 foo print(pd.isnull(result)) # something a b c d message # 0 False False False False False True # 1 False False False True False False # 2 False False False False False False result = pd.read_csv('../examples/ex5.csv', na_values=['NULL']) print(result) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 two 5 6 NaN 8 world # 2 three 9 10 11.0 12 foo \u5b9a\u4e49\u66ff\u6362\u89c4\u5219 sentinels = { 'message': ['foo', 'NA'], 'something': ['two'] } result = pd.read_csv('../examples/ex5.csv', na_values=sentinels) \u628amessage\u5217\u6240\u6709\u503c\u4e3afoo\u6216NA\u7684\u66ff\u6362\u4e3aNull \u628asomething\u5217\u6240\u6709\u503c\u4e3atwo\u7684\u66ff\u6362\u4e3aNull print(result) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 NaN 5 6 NaN 8 world # 2 three 9 10 11.0 12 NaN","title":"\u6587\u672c\u683c\u5f0f\u6570\u636e\u7684\u8bfb\u5199"},{"location":"python/DataAnalysis/ch03/#_3","text":"pd.options.display.max_rows = 10 result = pd.read_csv('../examples/ex6.csv') # \u8bfb\u53d6\u5168\u90e8\u8bb0\u5f55 print(result) result = pd.read_csv('../examples/ex6.csv', nrows=5) # \u8bfb\u53d6\u524d5\u884c\u8bb0\u5f55 print(result) # [10000 rows x 5 columns] # one two three four key # 0 0.467976 -0.038649 -0.295344 -1.824726 L # 1 -0.358893 1.404453 0.704965 -0.200638 B # 2 -0.501840 0.659254 -0.421691 -0.057688 G # 3 0.204886 1.074134 1.388361 -0.982404 R # 4 0.354628 -0.133116 0.283763 -0.837063 Q result = pd.read_csv('../examples/ex6.csv', chunksize=1000) # \u5206\u5757\u8bfb\u5165\u6587\u4ef6\uff0c\u6bcf\u57571000\u884c print(result) # \u8fd4\u56de\u7684\u662f\u4e00\u4e2aTextParser\u5bf9\u8c61, \u5141\u8bb8\u4f60\u6839\u636echunksize\u904d\u5386\u6587\u4ef6\u3002 # \u53ef\u4ee5\u904d\u5386 ex6.csv \uff0c\u5e76\u5bf9 key \u5217\u805a\u5408\u83b7\u5f97\u8ba1\u6570\u503c tot = pd.Series([], dtype=float) # \u8fd9\u91cc\u9700\u8981\u663e\u5f0f\u6307\u5b9adtype\uff0c\u540e\u7eedPython\u4f1a\u5c06\u9ed8\u8ba4\u503c\u4ecefloat64\u53d8\u6210object\uff0c\u76ee\u524d\u9ed8\u8ba4\u662ffloat64 for piece in result: tot = tot.add(piece['key'].value_counts(), fill_value=0) tot = tot.sort_values(ascending=False) print(tot[:10]) # E 368.0 # X 364.0 # L 346.0 # O 343.0 # Q 340.0 # M 338.0 # J 337.0 # F 335.0 # K 334.0 # H 330.0 # dtype: float64","title":"\u5206\u5757\u8bfb\u5165\u6587\u672c\u6587\u4ef6"},{"location":"python/DataAnalysis/ch03/#_4","text":"data = pd.read_csv('../examples/ex5.csv') print(data) # something a b c d message # 0 one 1 2 3.0 4 NaN # 1 two 5 6 NaN 8 world # 2 three 9 10 11.0 12 foo \u4f7f\u7528DataFrame\u7684 to_csv \u65b9\u6cd5\uff0c\u5c06\u6570\u636e\u5bfc\u51fa\u4e3a\u9017\u53f7\u5206\u9694\u7684\u6587\u4ef6 data.to_csv('../examples/out.csv') # \u8f93\u51faout.csv\u7684\u5185\u5bb9 # ,something,a,b,c,d,message # 0,one,1,2,3.0,4, # 1,two,5,6,,8,world # 2,three,9,10,11.0,12,foo \u4f7f\u7528DataFrame\u7684 to_csv \u65b9\u6cd5\uff0c\u5c06\u6570\u636e\u5bfc\u51fa\u4e3a\u5176\u4ed6\u7684\u5206\u9694\u7b26\u7684\u6587\u4ef6 data.to_csv(sys.stdout, sep='|') # |something|a|b|c|d|message # 0|one|1|2|3.0|4| # 1|two|5|6||8|world # 2|three|9|10|11.0|12|foo data.to_csv(sys.stdout, sep=',') # ,something,a,b,c,d,message # 0,one,1,2,3.0,4, # 1,two,5,6,,8,world # 2,three,9,10,11.0,12,foo data.to_csv(sys.stdout, sep=',', na_rep='NULL') # \u8bbe\u5b9a\u7f3a\u5931\u503c\u5728\u8f93\u51fa\u65f6\u4ee5\u7a7a\u5b57\u7b26\u4e32\u51fa\u73b0 # ,something,a,b,c,d,message # 0,one,1,2,3.0,4,NULL # 1,two,5,6,NULL,8,world # 2,three,9,10,11.0,12,foo data.to_csv(sys.stdout, sep=',', na_rep='NULL', index=False, header=False) # \u4e0d\u8f93\u51fa\u884c\u548c\u5217\u7684\u6807\u7b7e\uff08index\uff0cheader\uff09 # one,1,2,3.0,4,NULL # two,5,6,NULL,8,world # three,9,10,11.0,12,foo data.to_csv(sys.stdout, sep=',', na_rep='NULL', index=False, header=False, columns=['a', 'b', 'c']) # \u6309\u7167\u81ea\u5b9a\u7684\u987a\u5e8f\u8f93\u51fa\u5b50\u96c6 # 1,2,3.0 # 5,6,NULL # 9,10,11.0 Series\u4e5f\u6709 to_csv \u65b9\u6cd5 dates = pd.date_range('1/1/2000', periods=7) ts = pd.Series(np.arange(7), index=dates) ts.to_csv('../examples/tseries.csv', header=False) # \u8f93\u51fatseries.csv\u6587\u4ef6\u5185\u5bb9 # 2000-01-01,0 # 2000-01-02,1 # 2000-01-03,2 # 2000-01-04,3 # 2000-01-05,4 # 2000-01-06,5 # 2000-01-07,6","title":"\u5c06\u6570\u636e\u5199\u5165\u6587\u672c\u683c\u5f0f"},{"location":"python/DataAnalysis/ch03/#_5","text":"\u7edd\u5927\u591a\u6570\u7684\u8868\u578b\u6570\u636e\u90fd\u53ef\u4ee5\u4f7f\u7528\u51fd\u6570 pandas.read_table \u4ece\u786c\u76d8\u4e2d\u8bfb\u53d6\u3002 \u7136\u800c\uff0c\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u63a5\u6536\u4e00\u4e2a\u5e26\u6709\u4e00\u884c\u6216\u591a\u884c\u9519\u8bef\u7684\u6587\u4ef6\u5e76\u4e0d\u5c11\u89c1\uff0c read_table \u4e5f\u65e0\u6cd5\u89e3\u51b3\u8fd9\u79cd\u60c5\u51b5\u3002 ex7.csv \u6587\u4ef6\u5185\u5bb9 \"a\",\"b\",\"c\" \"1\",\"2\",\"3\" \"1\",\"2\",\"3\" f = open('../examples/ex7.csv') # \u4f7f\u7528Python\u7684\u5185\u5efacsv\u6a21\u5757 reader = csv.reader(f) # \u5c06\u4efb\u4e00\u6253\u5f00\u7684\u6587\u4ef6\u6216\u6587\u4ef6\u578b\u5bf9\u8c61\u4f20\u7ed9csv.reader for line in reader: # # \u904d\u5386reader\uff0c\u4ea7\u751f\u5143\u7ec4\uff0c\u5143\u7ec4\u7684\u503c\u4e3a\u5220\u9664\u4e86\u5f15\u53f7\u7684\u5b57\u7b26 print(line) f.close() # ['a', 'b', 'c'] # ['1', '2', '3'] # ['1', '2', '3'] with open('../examples/ex7.csv') as f: lines = list(csv.reader(f)) # \u9996\u5148\uff0c\u5c06\u6587\u4ef6\u8bfb\u53d6\u4e3a\u884c\u7684\u5217\u8868 header, values = lines[0], lines[1:] # \u5176\u6b21\uff0c\u5c06\u6570\u636e\u62c6\u5206\u4e3a\u5217\u540d\u884c\u548c\u6570\u636e\u884c data_dict = { h: v for h, v in zip(header, zip(*values)) # \u518d\u7136\u540e\uff0c\u4f7f\u7528\u5b57\u5178\u63a8\u5bfc\u5f0f\u548c\u8868\u8fbe\u5f0fzip(*values)\u751f\u6210\u4e00\u4e2a\u5305\u542b\u6570\u636e\u5217\u7684\u5b57\u5178\uff0c\u5b57\u5178\u4e2d\u884c\u8f6c\u7f6e\u6210\u5217 } print(data_dict) # \u8f93\u51fa\u7ed3\u679c # {'a': ('1', '1'), 'b': ('2', '2'), 'c': ('3', '3')} \u5982\u679c\u9700\u6839\u636e\u4e0d\u540c\u7684\u5206\u9694\u7b26\u3001\u5b57\u7b26\u4e32\u5f15\u7528\u7ea6\u5b9a\u6216\u884c\u7ec8\u6b62\u7b26\u5b9a\u4e49\u4e00\u79cd\u65b0\u7684\u683c\u5f0f\u65f6\uff0c\u53ef\u4ee5: \u65b9\u6cd51\uff1a\u4f7f\u7528csv.Dialect\u5b9a\u4e49\u4e00\u4e2a\u7b80\u5355\u7684\u5b50\u7c7b class my_dialect(csv.Dialect): lineterminator = '\\n' delimiter = ';' # \u8fd9\u91cc\u53ea\u80fd\u662f\u4e00\u4e2a\u5b57\u7b26 quotechar = '\"' quoting = csv.QUOTE_MINIMAL f = open('../examples/ex7.csv') reader = csv.reader(f, dialect=my_dialect) for line in reader: # \u904d\u5386reader\uff0c\u4ea7\u751f\u5143\u7ec4\uff0c\u5143\u7ec4\u7684\u503c\u4e3a\u5220\u9664\u4e86\u5f15\u53f7\u7684\u5b57\u7b26 print(line) f.close() # ['a,\"b\",\"c\"'] # ['1,\"2\",\"3\"'] # ['1,\"2\",\"3\"'] \u65b9\u6cd52\uff1a\u76f4\u63a5\u5c06CSV\u65b9\u8a00\u53c2\u6570(dialect)\u4f20\u5165csv.reader\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 \u6bd4\u8f83\u8be6\u7ec6\u7684 \u4ecb\u7ecd\u65b9\u8a00\u548c\u5206\u9694\u7b26 f = open('../examples/ex7.csv') reader = csv.reader(f, delimiter='|') for line in reader: # \u904d\u5386reader\uff0c\u4ea7\u751f\u5143\u7ec4\uff0c\u5143\u7ec4\u7684\u503c\u4e3a\u5220\u9664\u4e86\u5f15\u53f7\u7684\u5b57\u7b26 print(line) f.close() # ['a,\"b\",\"c\"'] # ['1,\"2\",\"3\"'] # ['1,\"2\",\"3\"'] \u5bf9\u4e8e\u5177\u6709\u66f4\u590d\u6742\u6216\u56fa\u5b9a\u7684\u591a\u5b57\u7b26\u5206\u9694\u7b26\u7684\u6587\u4ef6\uff0c\u5c06\u65e0\u6cd5\u4f7f\u7528csv\u6a21\u5757\u3002 \u5728\u6b64\u7c7b\u60c5\u51b5\u4e0b\uff0c\u5c06\u4f7f\u7528\u5b57\u7b26\u4e32\u7684split\u65b9\u6cd5\u6216\u6b63\u5219\u8868\u8fbe\u5f0f\u65b9\u6cd5re.split\u8fdb\u884c\u884c\u62c6\u5206\u548c\u5176\u4ed6\u6e05\u7406\u5de5\u4f5c\u3002 \u9700\u8981\u624b\u52a8\u5199\u5165\u88ab\u5206\u9694\u7684\u6587\u4ef6\u65f6\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528csv.writer\u3002 \u8fd9\u4e2a\u51fd\u6570\u63a5\u6536\u4e00\u4e2a\u5df2\u7ecf\u6253\u5f00\u7684\u53ef\u5199\u5165\u6587\u4ef6\u5bf9\u8c61\u4ee5\u53ca\u548ccsv.reader\u76f8\u540c\u7684CSV\u65b9\u8a00\u3001\u683c\u5f0f\u9009\u9879. with open('../examples/mydata.csv', 'w') as f: writer = csv.writer(f, dialect=my_dialect) writer.writerow(('1', '2', '3')) writer.writerow(('4', '5', '6')) writer.writerow(('7', '8', '9')) writer.writerow(('10', '11', '12')) # mydata.csv \u6587\u4ef6\u5185\u5bb9 # 1;2;3 # 4;5;6 # 7;8;9 # 10;11;12","title":"\u4f7f\u7528\u5206\u9694\u683c\u5f0f"},{"location":"python/DataAnalysis/ch03/#json","text":"obj = \"\"\" { \"name\": \"Wes\", \"places_lived\": [\"United States\", \"Spain\", \"Germany\"], \"pet\": null, \"siblings\": [ { \"name\": \"Scott\", \"age\": 30, \"pets\": [\"Zeus\", \"Zuko\"] }, { \"name\": \"Katie\", \"age\": 38, \"pets\": [\"Sixes\", \"Stache\", \"Cisco\"] } ] } \"\"\" \u5c06JSON\u5b57\u7b26\u4e32\u8f6c\u6362\u4e3aPython\u5f62\u5f0f\u65f6\uff0c\u4f7f\u7528json.loads\u65b9\u6cd5 result = json.loads(obj) print(result) # {'name': 'Wes', 'places_lived': ['United States', 'Spain', 'Germany'], 'pet': None, 'siblings': [{'name': 'Scott', 'age': 30, 'pets': ['Zeus', 'Zuko']}, {'name': 'Katie', 'age': 38, 'pets': ['Sixes', 'Stache', 'Cisco']}]} \u53e6\u4e00\u65b9\u9762\uff0cjson.dumps\u53ef\u4ee5\u5c06Python\u5bf9\u8c61\u8f6c\u6362\u56deJSON asjson = json.dumps(result) print(asjson) # {\"name\": \"Wes\", \"places_lived\": [\"United States\", \"Spain\", \"Germany\"], \"pet\": null, \"siblings\": [{\"name\": \"Scott\", \"age\": 30, \"pets\": [\"Zeus\", \"Zuko\"]}, {\"name\": \"Katie\", \"age\": 38, \"pets\": [\"Sixes\", \"Stache\", \"Cisco\"]}]} \u5c06JSON\u5bf9\u8c61\u6216\u5bf9\u8c61\u5217\u8868\u8f6c\u6362\u4e3aDataFrame\u6216\u5176\u4ed6\u6570\u636e\u7ed3\u6784\u3002 \u6bd4\u8f83\u65b9\u4fbf\u7684\u65b9\u5f0f\u662f\u5c06\u5b57\u5178\u6784\u6210\u7684\u5217\u8868\uff08\u4e4b\u524d\u662fJSON\u5bf9\u8c61\uff09\u4f20\u5165DataFrame\u6784\u9020\u51fd\u6570\uff0c\u5e76\u9009\u51fa\u6570\u636e\u5b57\u6bb5\u7684\u5b50\u96c6\u3002 siblings = pd.DataFrame(result['siblings'], columns=['name', 'age']) print(siblings) # name age # 0 Scott 30 # 1 Katie 38 pandas.read_json\u53ef\u4ee5\u81ea\u52a8\u5c06JSON\u6570\u636e\u96c6\u6309\u7167\u6307\u5b9a\u6b21\u5e8f\u8f6c\u6362\u4e3aSeries\u6216DataFrame\u3002 pandas.read_json\u7684\u9ed8\u8ba4\u9009\u9879\u662f\u5047\u8bbeJSON\u6570\u7ec4\u4e2d\u7684\u6bcf\u4e2a\u5bf9\u8c61\u662f\u8868\u91cc\u7684\u4e00\u884c\u3002 \u4f8b\u5982\u8bfb\u53d6 data = pd.read_json('../examples/example_new.json') data = pd.read_json('../examples/example.json') print(data) # a b c # 0 1 2 3 # 1 4 5 6 # 2 7 8 9 print(data.to_json()) # {\"a\":{\"0\":1,\"1\":4,\"2\":7},\"b\":{\"0\":2,\"1\":5,\"2\":8},\"c\":{\"0\":3,\"1\":6,\"2\":9}} print(data.to_json(orient='records')) # [{\"a\":1,\"b\":2,\"c\":3},{\"a\":4,\"b\":5,\"c\":6},{\"a\":7,\"b\":8,\"c\":9}]","title":"JSON\u6570\u636e"},{"location":"python/DataAnalysis/ch03/#xmlhtml","text":"pandas\u7684\u5185\u5efa\u51fd\u6570read_html\u53ef\u4ee5\u4f7f\u7528lxml\u548cBeautiful Soup\u7b49\u5e93\u5c06HTML\u4e2d\u7684\u8868\u81ea\u52a8\u89e3\u6790\u4e3aDataFrame\u5bf9\u8c61\u3002 tables = pd.read_html('../examples/fdic_failed_bank_list.html') print(len(tables)) # 1 failures = tables[0] # //*[@id=\"table\"] print(failures.head()) # \u8bfb\u53d6\u524d5\u884c\u8bb0\u5f55 # Bank Name ... Updated Date # 0 Allied Bank ... November 17, 2016 # 1 The Woodbury Banking Company ... November 17, 2016 # 2 First CornerStone Bank ... September 6, 2016 # 3 Trust Company Bank ... September 6, 2016 # 4 North Milwaukee State Bank ... June 16, 2016 # # [5 rows x 7 columns] close_timestamps = pd.to_datetime(failures['Closing Date']) # \u8ba1\u7b97\u6bcf\u5e74\u94f6\u884c\u5012\u95ed\u7684\u6570\u91cf print(close_timestamps.dt.year.value_counts()) # 2010 157 # 2009 140 # 2011 92 # 2012 51 # 2008 25 # ... # 2004 4 # 2001 4 # 2007 3 # 2003 3 # 2000 2 # Name: Closing Date, Length: 15, dtype: int64","title":"XML\u548cHTML\uff1a\u7f51\u7edc\u6293\u53d6"},{"location":"python/DataAnalysis/ch03/#_6","text":"","title":"\u4e8c\u8fdb\u5236\u683c\u5f0f"},{"location":"python/DataAnalysis/ch03/#web-api","text":"","title":"\u4e0eWeb API\u4ea4\u4e92"},{"location":"python/DataAnalysis/ch03/#_7","text":"","title":"\u4e0e\u6570\u636e\u5e93\u4ea4\u4e92"},{"location":"python/DataAnalysis/ch04/","text":"\u6570\u636e\u6e05\u6d17\u4e0e\u51c6\u5907 \u00b6 \u5904\u7406\u7f3a\u5931\u503c \u00b6 import pandas as pd import numpy as np from numpy import nan as NA \u5bf9\u4e8e\u6570\u503c\u578b\u6570\u636e\uff0cpandas\u4f7f\u7528\u6d6e\u70b9\u503c NaN \uff08Not a Number\u6765\u8868\u793a\u7f3a\u5931\u503c\uff09\u3002 \u5728pandas\u4e2d\uff0c\u91c7\u7528\u4e86R\u8bed\u8a00\u4e2d\u7684\u7f16\u7a0b\u60ef\u4f8b\uff0c\u5c06\u7f3a\u5931\u503c\u6210\u4e3a NA \uff0c\u610f\u601d\u662fnotavailable\uff08\u4e0d\u53ef\u7528\uff09\u3002 Python\u5185\u5efa\u7684 None \u503c\u5728\u5bf9\u8c61\u6570\u7ec4\u4e2d\u4e5f\u88ab\u5f53\u4f5c NA \u5904\u7406\u3002 NA\u5904\u7406\u65b9\u6cd5\uff1a dropna :\u6839\u636e\u6bcf\u4e2a\u6807\u7b7e\u7684\u503c\u662f\u5426\u662f\u786e\u5b9e\u6570\u636e\u6765\u7b5b\u9009\u8f74\u6807\u7b7e\uff0c\u5e76\u6839\u636e\u5141\u8bb8\u4e22\u5931\u7684\u6570\u636e\u91cf\u6765\u786e\u5b9a\u9608\u503c fillna :\u7528\u67d0\u4e9b\u503c\u586b\u5145\u786e\u5b9e\u7684\u6570\u636e\u6216\u4f7f\u7528\u63d2\u503c\u65b9\u6cd5\uff0c\u5982 ffill \u6216 bfill isnull :\u8fd4\u56de\u8868\u660e\u54ea\u4e9b\u503c\u662f\u7f3a\u5931\u503c\u7684\u5e03\u5c14\u503c notnull :\u662f isnull \u7684\u53cd\u51fd\u6570 string_data = pd.Series(['aardvark', 'artichoke', np.nan, 'avocado']) print(string_data) # 0 aardvark # 1 artichoke # 2 NaN # 3 avocado # dtype: object print(string_data.isnull()) # 0 False # 1 False # 2 True # 3 False # dtype: bool string_data[0] = None print(string_data.isnull()) # 0 True # 1 False # 2 True # 3 False # dtype: bool \u8fc7\u6ee4\u7f3a\u5931\u503c \u00b6 \u5904\u7406Series \u00b6 \u5728Series\u4e0a\u4f7f\u7528 dropna \uff0c\u5b83\u4f1a\u8fd4\u56deSeries\u4e2d\u6240\u6709\u7684\u975e\u7a7a\u6570\u636e\u53ca\u5176\u7d22\u5f15\u503c\u3002 data = pd.Series([1, NA, 3.5, NA, 7]) print(data.dropna()) # 0 1.0 # 2 3.5 # 4 7.0 # dtype: float64 print(data[data.notnull()]) # \u4e0e\u4e0a\u9762\u7b49\u4ef7 # 0 1.0 # 2 3.5 # 4 7.0 # dtype: float64 \u5904\u7406DataFrame \u00b6 data = pd.DataFrame( [[1., 6.5, 3.], [1., NA, NA], [NA, NA, NA], [NA, 6.5, 3.]] ) print(data) # 0 1 2 # 0 1.0 6.5 3.0 # 1 1.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 6.5 3.0 cleaned = data.dropna() # dropna\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u4f1a\u5220\u9664\u5305\u542b\u7f3a\u5931\u503c\u7684\u884c print(cleaned) # 0 1 2 # 0 1.0 6.5 3.0 cleaned = data.dropna(how='all') # \u4f20\u5165how='all\u2019\u65f6\uff0c\u5c06\u5220\u9664\u6240\u6709\u503c\u5747\u4e3aNA\u7684\u884c print(cleaned) # 0 1 2 # 0 1.0 6.5 3.0 # 1 1.0 NaN NaN # 3 NaN 6.5 3.0 data[4] = NA print(data) # 0 1 2 4 # 0 1.0 6.5 3.0 NaN # 1 1.0 NaN NaN NaN # 2 NaN NaN NaN NaN # 3 NaN 6.5 3.0 NaN cleaned = data.dropna(axis=1, how='all') # \u5220\u9664\u5168NA\u7684\u5217 print(cleaned) # 0 1 2 # 0 1.0 6.5 3.0 # 1 1.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 6.5 3.0 df = pd.DataFrame(np.random.randn(7, 3)) print(df) # 0 1 2 # 0 -1.069771 -0.777921 0.181956 # 1 -0.399504 -0.641737 -0.946327 # 2 -1.013920 -0.247588 -0.760146 # 3 1.076946 -1.263203 0.494077 # 4 0.460985 -1.241870 0.283006 # 5 1.168149 1.033752 0.900095 # 6 -1.208514 -1.049546 -0.783680 df.iloc[:4, 1] = NA # \u6807\u7b7e1\uff0c\u524d4\u4e2a\u5143\u7d20 df.iloc[:2, 2] = NA # \u6807\u7b7e2\uff0c\u524d2\u4e2a\u5143\u7d20 print(df) # 0 1 2 # 0 -1.069771 NaN NaN # 1 -0.399504 NaN NaN # 2 -1.013920 NaN -0.760146 # 3 1.076946 NaN 0.494077 # 4 0.460985 -1.241870 0.283006 # 5 1.168149 1.033752 0.900095 # 6 -1.208514 -1.049546 -0.783680 cleaned = df.dropna() print(cleaned) # 0 1 2 # 4 0.033663 0.291886 0.736448 # 5 -0.433380 0.397104 1.252005 # 6 -1.999018 0.303866 1.430109 cleaned = df.dropna(thresh=2) # \u4fdd\u75592\u884c\u542bNA\u7684\u89c2\u5bdf\u503c print(cleaned) # 0 1 2 # 2 -1.413976 NaN 0.222274 # 3 -0.644266 NaN 0.324180 # 4 -0.122160 -2.244880 -0.406562 # 5 -0.140326 0.101133 -0.764048 # 6 -1.809141 0.139091 -0.819175 \u8865\u5168\u7f3a\u5931\u503c \u00b6 fillna \u51fd\u6570\u53c2\u6570\uff1a value\uff1a\u6807\u91cf\u503c\u6216\u5b57\u5178\u578b\u5bf9\u8c61\u7528\u4e8e\u586b\u5145\u7f3a\u5931\u503c method\uff1a\u63d2\u503c\u65b9\u6cd5\uff0c\u5982\u679c\u6ca1\u6709\u5176\u4ed6\u53c2\u6570\uff0c\u9ed8\u8ba4\u662f'ffill' axis\uff1a\u9700\u8981\u586b\u5145\u7684\u8f74\uff0c\u9ed8\u8ba4axis=0 inplace\uff1a\u4fee\u6539\u88ab\u8c03\u7528\u5bf9\u8c61\uff0c\u800c\u4e0d\u662f\u751f\u6210\u4e00\u4e2a\u5907\u4efd limit\uff1a\u7528\u4e8e\u524d\u5411\u6216\u540e\u5411\u586b\u5145\u65f6\u6700\u5927\u7684\u586b\u5145\u8303\u56f4 df = pd.DataFrame(np.random.randn(7, 3)) df.iloc[:4, 1] = NA # \u6807\u7b7e1\uff0c\u524d4\u4e2a\u5143\u7d20 df.iloc[:2, 2] = NA # \u6807\u7b7e2\uff0c\u524d2\u4e2a\u5143\u7d20 print(df) # 0 1 2 # 0 -0.181196 NaN NaN # 1 -1.657668 NaN NaN # 2 -0.053454 NaN 0.391461 # 3 -0.539307 NaN -0.668400 # 4 -0.433439 0.839713 -0.295273 # 5 0.749930 1.661641 -0.495165 # 6 0.591810 1.017372 0.932367 result = df.fillna(0) # \u8c03\u7528fillna\u65f6\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e00\u4e2a\u5e38\u6570\u6765\u66ff\u4ee3\u7f3a\u5931\u503c print(result) # 0 1 2 # 0 -0.430926 0.000000 0.000000 # 1 0.448061 0.000000 0.000000 # 2 -0.059910 0.000000 -1.532646 # 3 -0.315793 0.000000 -0.196546 # 4 -0.546106 0.135108 -0.332309 # 5 1.083075 0.346070 -0.773104 # 6 -0.186511 1.055337 -1.168303 result = df.fillna({1: 0.5, 2: 0}) # \u8c03\u7528fillna\u65f6\u4f7f\u7528\u5b57\u5178\uff0c\u53ef\u4ee5\u4e3a\u4e0d\u540c\u5217\u8bbe\u5b9a\u4e0d\u540c\u7684\u586b\u5145\u503c print(result) # 0 1 2 # 0 -0.794344 0.500000 0.000000 # 1 -0.960917 0.500000 0.000000 # 2 1.494351 0.500000 0.100878 # 3 -0.554765 0.500000 1.118801 # 4 -0.866117 0.523615 1.217478 # 5 -0.706966 -0.681776 0.797690 # 6 -1.456366 1.205518 -0.402432 fillna \u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u65b0\u7684\u5bf9\u8c61\uff0c\u4f46\u4e5f\u53ef\u4ee5\u4fee\u6539\u5df2\u7ecf\u5b58\u5728\u7684\u5bf9\u8c61 _ = df.fillna(0, inplace=True) # inplace=True\u6307\u5b9a\u5728\u5df2\u6709\u5bf9\u8c61\u4e0a\u76f4\u63a5\u4fee\u6539 print(df) # 0 1 2 # 0 -1.176124 0.000000 0.000000 # 1 0.120458 0.000000 0.000000 # 2 -1.206408 0.000000 0.551693 # 3 0.224563 0.000000 1.145156 # 4 -0.557836 0.081135 -0.075282 # 5 2.378837 -0.876145 1.430386 # 6 -0.152662 1.278364 0.479686 df = pd.DataFrame(np.random.randn(6, 3)) df.iloc[2:, 1] = NA # \u6807\u7b7e1\uff0c\u524d4\u4e2a\u5143\u7d20 df.iloc[4:, 2] = NA # \u6807\u7b7e2\uff0c\u524d2\u4e2a\u5143\u7d20 print(df) # 0 1 2 # 0 1.154788 0.033949 -0.122807 # 1 0.258684 -0.580244 1.636514 # 2 1.503756 NaN -1.224203 # 3 0.824049 NaN -0.364345 # 4 -1.247609 NaN NaN # 5 -1.019980 NaN NaN result = df.fillna(method='ffill') # \u5411\u540e\u586b\u5145 print(result) # 0 1 2 # 0 2.082449 0.398874 0.359772 # 1 0.233129 0.385347 1.953533 # 2 0.396555 0.385347 0.592784 # 3 -0.957249 0.385347 0.169815 # 4 0.854452 0.385347 0.169815 # 5 -0.105982 0.385347 0.169815 result = df.fillna(method='ffill', limit=3) # \u6bcf\u5217\u6700\u591a\u586b3\u4e2a print(result) result = df.fillna(df[0].max()) # \u75280\u5217\u7684\u6700\u5927\u503c\u586b\u5145\u6240\u6709\u7684NA print(result) # 0 1 2 # 0 -0.377697 -0.852891 -0.705489 # 1 -0.611759 -0.013237 -0.295764 # 2 -0.389974 1.057881 1.041957 # 3 -0.016845 1.057881 -1.149954 # 4 1.057881 1.057881 1.057881 # 5 -0.463471 1.057881 1.057881 \u6570\u636e\u8f6c\u6362 \u00b6 import pandas as pd import numpy as np from numpy import nan as NA \u5220\u9664\u91cd\u590d\u503c \u00b6 data = pd.DataFrame( { 'k1': ['one', 'two'] * 3 + ['two'], 'k2': [1, 1, 2, 3, 4, 4, 4] } ) print(data) # \u91cd\u590d\u51fa\u73b02\u6b21\u7684\u8bb0\u5f55\uff1atwo 4 # k1 k2 # 0 one 1 # 1 two 1 # 2 one 2 # 3 two 3 # 4 one 4 # 5 two 4 # 6 two 4 DataFrame\u7684 duplicated \u65b9\u6cd5\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u5e03\u5c14\u503cSeries\uff0c\u8fd9\u4e2aSeries\u53cd\u6620\u7684\u662f\u6bcf\u4e00\u884c\u662f\u5426\u5b58\u5728\u91cd\u590d\uff08\u4e0e\u4e4b\u524d\u51fa\u73b0\u8fc7\u7684\u884c\u76f8\u540c\uff09\u60c5\u51b5\uff0c\u9ed8\u8ba4\u662f\u5bf9\u5217\u8fdb\u884c\u64cd\u4f5c\u3002 print(data.duplicated()) # 0 False # 1 False # 2 False # 3 False # 4 False # 5 False # 6 True # dtype: bool drop_duplicates \u8fd4\u56de\u7684\u662fDataFrame\uff0c\u5185\u5bb9\u662f duplicated \u8fd4\u56de\u6570\u7ec4\u4e2d\u4e3a False \u7684\u90e8\u5206\u3002\u9ed8\u8ba4\u662f\u5bf9\u5217\u8fdb\u884c\u64cd\u4f5c\u3002 print(data.drop_duplicates()) # k1 k2 # 0 one 1 # 1 two 1 # 2 one 2 # 3 two 3 # 4 one 4 # 5 two 4 \u53ef\u4ee5\u6307\u5b9a\u6570\u636e\u7684\u4efb\u4f55\u5b50\u96c6\u6765\u68c0\u6d4b\u662f\u5426\u6709\u91cd\u590d\u3002\u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u989d\u5916\u7684\u5217\uff0c\u5e76\u60f3\u57fa\u4e8e\u2019k1\u2019\u5217\u53bb\u9664\u91cd\u590d\u503c\u3002 data['v1'] = range(7) print(data) # k1 k2 v1 # 0 one 1 0 # 1 two 1 1 # 2 one 2 2 # 3 two 3 3 # 4 one 4 4 # 5 two 4 5 # 6 two 4 6 print(data.drop_duplicates(['k1'])) # \u4fdd\u7559\u7b2c\u4e00\u4e2a\u89c2\u6d4b\u5230\u7684one\u548ctwo\uff0c\u5176\u4f59\u4e22\u5f03 # k1 k2 v1 # 0 one 1 0 # 1 two 1 1 duplicated \u548c drop_duplicates \u9ed8\u8ba4\u90fd\u662f\u4fdd\u7559\u7b2c\u4e00\u4e2a\u89c2\u6d4b\u5230\u7684\u503c\u3002\u4f20\u5165\u53c2\u6570keep='last\u2019\u5c06\u4f1a\u8fd4\u56de\u6700\u540e\u4e00\u4e2a\u3002 print(data.drop_duplicates(['k1'], keep='last')) # \u4fdd\u7559\u6700\u540e\u4e00\u4e2a\u89c2\u6d4b\u5230\u7684one\u548ctwo # k1 k2 v1 # 4 one 4 4 # 6 two 4 6 \u4f7f\u7528\u51fd\u6570\u6216\u6620\u5c04\u8fdb\u884c\u6570\u636e\u8f6c\u6362 \u00b6 \u4f7f\u7528 map \u662f\u4e00\u79cd\u53ef\u4ee5\u4fbf\u6377\u6267\u884c\u6309\u5143\u7d20\u8f6c\u6362\u53ca\u5176\u4ed6\u6e05\u6d17\u76f8\u5173\u64cd\u4f5c\u7684\u65b9\u6cd5\u3002 data = pd.DataFrame( { 'food': ['bacon', 'pulled pork', 'bacon', 'Pastrami', 'corned beef', 'Bacon', 'pastrami', 'honey ham', 'nova lox'], 'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6] } ) print(data) # food ounces # 0 bacon 4.0 # 1 pulled pork 3.0 # 2 bacon 12.0 # 3 Pastrami 6.0 # 4 corned beef 7.5 # 5 Bacon 8.0 # 6 pastrami 3.0 # 7 honey ham 5.0 # 8 nova lox 6.0 \u6dfb\u52a0\u4e00\u5217\u7528\u4e8e\u8868\u660e\u6bcf\u79cd\u98df\u7269\u7684\u52a8\u7269\u8089\u7c7b\u578b\u3002 \u5148\u521b\u5efa\u4e00\u4e2a\u98df\u7269\u548c\u8089\u7c7b\u7684\u6620\u5c04\u3002 meat_to_animal = { 'bacon': 'pig', 'pulled pork': 'pig', 'pastrami': 'cow', 'corned beef': 'cow', 'honey ham': 'pig', 'nova lox': 'salmon' } lowercased = data['food'].str.lower() # \u4f7f\u7528Series\u7684str.lower\u65b9\u6cd5\u5c06food\u7684\u6bcf\u4e2a\u503c\u90fd\u8f6c\u6362\u4e3a\u5c0f\u5199 print(lowercased) # 0 bacon # 1 pulled pork # 2 bacon # 3 pastrami # 4 corned beef # 5 bacon # 6 pastrami # 7 honey ham # 8 nova lox # Name: food, dtype: object data['animal'] = lowercased.map(meat_to_animal) print(data) # food ounces animal # 0 bacon 4.0 pig # 1 pulled pork 3.0 pig # 2 bacon 12.0 pig # 3 Pastrami 6.0 cow # 4 corned beef 7.5 cow # 5 Bacon 8.0 pig # 6 pastrami 3.0 cow # 7 honey ham 5.0 pig # 8 nova lox 6.0 salmon \u4e5f\u53ef\u4ee5\u4f20\u5165\u4e00\u4e2a\u51fd\u6570\uff0c\u5b8c\u6210\u4e0a\u9762\u6240\u6709\u529f\u80fd\u3002 data = pd.DataFrame( { 'food': ['bacon', 'pulled pork', 'bacon', 'Pastrami', 'corned beef', 'Bacon', 'pastrami', 'honey ham', 'nova lox'], 'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6] } ) result = data['food'].map(lambda x: meat_to_animal[x.lower()]) print(result) # 0 pig # 1 pig # 2 pig # 3 cow # 4 cow # 5 pig # 6 cow # 7 pig # 8 salmon # Name: food, dtype: object \u66ff\u4ee3\u503c \u00b6 \u4f7f\u7528 fillna \u586b\u5145\u7f3a\u5931\u503c\u662f\u901a\u7528\u503c\u66ff\u6362\u7684\u7279\u6b8a\u6848\u4f8b\u3002 map \u53ef\u4ee5\u7528\u6765\u4fee\u6539\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u7684\u5b50\u96c6\u7684\u503c\uff0c\u4f46\u662f replace \u63d0\u4f9b\u4e86\u66f4\u4e3a\u7b80\u5355\u7075\u6d3b\u7684\u5b9e\u73b0\u3002 data.replace \u65b9\u6cd5\u4e0e data.str.replace \u65b9\u6cd5\u662f\u4e0d\u540c\u7684\uff0c data.str.replace \u662f\u5bf9\u5b57\u7b26\u4e32\u8fdb\u884c\u6309\u5143\u7d20\u66ff\u4ee3\u7684\u3002 \u4e0b\u9762\u7684Series\uff0c -999 \u53ef\u80fd\u662f\u7f3a\u5931\u503c\u7684\u6807\u8bc6\u3002\u5982\u679c\u8981\u4f7f\u7528 NA \u6765\u66ff\u4ee3\u8fd9\u4e9b\u503c\uff0c\u53ef\u4ee5\u4f7f\u7528 replace \u65b9\u6cd5\u751f\u6210\u65b0\u7684Series\uff08\u9664\u975e\u4f20\u5165\u4e86 inplace=True \uff09 data = pd.Series([1., -999., 2., -999., -1000., 3.]) print(data) # 0 1.0 # 1 -999.0 # 2 2.0 # 3 -999.0 # 4 -1000.0 # 5 3.0 # dtype: float64 result = data.replace(-999, np.nan) print(result) # 0 1.0 # 1 NaN # 2 2.0 # 3 NaN # 4 -1000.0 # 5 3.0 # dtype: float64 \u8981\u5c06\u4e0d\u540c\u7684\u503c\u66ff\u6362\u4e3a\u4e0d\u540c\u7684\u503c\uff0c\u53ef\u4ee5\u4f20\u5165\u66ff\u4ee3\u503c\u7684\u5217\u8868 result = data.replace([-999, -1000], [np.nan, 0]) print(result) # 0 1.0 # 1 NaN # 2 2.0 # 3 NaN # 4 0.0 # 5 3.0 # dtype: float64 \u4e5f\u53ef\u4ee5\u4f20\u5165\u66ff\u4ee3\u503c\u7684\u5b57\u5178 result = data.replace({-999: np.nan, -1000: 0}) print(result) # 0 1.0 # 1 NaN # 2 2.0 # 3 NaN # 4 0.0 # 5 3.0 # dtype: float64 \u91cd\u547d\u540d\u8f74\u7d22\u5f15 \u00b6 \u548cSeries\u4e2d\u503c\u66ff\u6362\u7c7b\u4f3c\uff0c\u53ef\u4ee5\u901a\u8fc7\u51fd\u6570\u6216\u6620\u5c04\u5bf9\u8f74\u6807\u7b7e\u8fdb\u884c\u7c7b\u4f3c\u7684\u8f6c\u6362\uff0c\u751f\u6210\u65b0\u7684\u4e14\u5e26\u6709\u4e0d\u540c\u6807\u7b7e\u7684\u5bf9\u8c61\u3002 data = pd.DataFrame( np.arange(12).reshape((3, 4)), index=['Ohio', 'Colorado', 'New York'], columns=['one', 'two', 'three', 'four'] ) print(data) # one two three four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # New York 8 9 10 11 \u4e0eSeries\u7c7b\u4f3c\uff0c\u8f74\u7d22\u5f15\u4e5f\u6709\u4e00\u4e2a map \u65b9\u6cd5\u3002 transform = lambda x: x[:4].upper() # \u622a\u53d6index\u7684\u524d\u56db\u4f4d\u5e76\u8f6c\u5316\u4e3a\u5927\u5199\u683c\u5f0f result = data.index.map(transform) print(result) # Index(['OHIO', 'COLO', 'NEW '], dtype='object') \u8d4b\u503c\u7ed9 index \uff0c\u4fee\u6539DataFrame\u3002 data.index = data.index.map(transform) print(data) # one two three four # OHIO 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 \u521b\u5efa\u6570\u636e\u96c6\u8f6c\u6362\u540e\u7684\u7248\u672c\uff0c\u5e76\u4e14\u4e0d\u4fee\u6539\u539f\u6709\u7684\u6570\u636e\u96c6\uff0c\u4e00\u4e2a\u6709\u7528\u7684\u65b9\u6cd5\u662f rename \u3002 result = data.rename(index=str.title, columns=str.upper) print(result) # ONE TWO THREE FOUR # Ohio 0 1 2 3 # Colo 4 5 6 7 # New 8 9 10 11 print(data) # \u539f\u6709\u7684\u6570\u636e\u96c6\u672a\u88ab\u4fee\u6539 # one two three four # OHIO 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 rename \u53ef\u4ee5\u7ed3\u5408\u5b57\u5178\u578b\u5bf9\u8c61\u4f7f\u7528\uff0c\u4e3a\u8f74\u6807\u7b7e\u7684\u5b50\u96c6\u63d0\u4f9b\u65b0\u7684\u503c\u3002 result = data.rename(index={'OHIO': 'INDIANA'}, columns={'three': 'peekaboo'}) print(result) # one two peekaboo four # INDIANA 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 \u5982\u679c\u8981\u4fee\u6539\u539f\u6709\u7684\u6570\u636e\u96c6\uff0c\u4f20\u5165 inplace=True \u3002 data.rename(index={'OHIO': 'INDIANA'}, columns={'three': 'peekaboo'}, inplace=True) print(data) # one two peekaboo four # INDIANA 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 \u79bb\u6563\u5316\u548c\u5206\u7bb1 \u00b6 \u8fde\u7eed\u503c\u7ecf\u5e38\u9700\u8981\u79bb\u6563\u5316\uff0c\u6216\u8005\u5206\u79bb\u6210\u201d\u7bb1\u5b50\u201c\u8fdb\u884c\u5206\u6790\u3002 \u5047\u8bbe\u6709\u4e00\u7ec4\u4eba\u7fa4\u7684\u6570\u636e\uff0c\u60f3\u5c06\u4ed6\u4eec\u8fdb\u884c\u5206\u7ec4\uff0c\u653e\u5165\u79bb\u6563\u7684\u5e74\u9f84\u6846\u4e2d\u3002 ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32] \u5c06\u8fd9\u4e9b\u5e74\u9f84\u5206\u4e3a18\uff5e25\u300126\uff5e35\u300136\uff5e60\u4ee5\u53ca61\u53ca\u4ee5\u4e0a\u7b49\u82e5\u5e72\u7ec4\uff0c\u4f7f\u7528pandas\u4e2d\u7684 cut \u3002 bins = [18, 25, 35, 60, 100] cats = pd.cut(ages, bins) print(cats) # [(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]] # Length: 12 # Categories (4, interval[int64, right]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]] pandas\u8fd4\u56de\u7684\u5bf9\u8c61\u662f\u4e00\u4e2a\u7279\u6b8a\u7684 Categorical \u5bf9\u8c61\u3002 \u4f60\u770b\u5230\u7684\u8f93\u51fa\u63cf\u8ff0\u4e86\u7531 pandas.cut \u8ba1\u7b97\u51fa\u7684\u7bb1\u3002 \u4f60\u53ef\u4ee5\u5c06\u5b83\u5f53\u4f5c\u4e00\u4e2a\u8868\u793a\u7bb1\u540d\u7684\u5b57\u7b26\u4e32\u6570\u7ec4\uff1b\u5b83\u5728\u5185\u90e8\u5305\u542b\u4e00\u4e2a categories \uff08\u7c7b\u522b\uff09\u6570\u7ec4\uff0c\u5b83\u6307\u5b9a\u4e86\u4e0d\u540c\u7684\u7c7b\u522b\u540d\u79f0\u4ee5\u53ca codes \u5c5e\u6027\u4e2d\u7684 ages \uff08\u5e74\u9f84\uff09\u6570\u636e\u6807\u7b7e\u3002 print(cats.categories) # \u56db\u4e2a\u533a\u95f4\u7ec4 # IntervalIndex([(18, 25], (25, 35], (35, 60], (60, 100]], dtype='interval[int64, right]') print(cats.codes) # 61\u5c81\u843d\u5728\u7b2c3\u7ec4\uff08\u7ec4\u7f16\u53f7\u4ece0\u5f00\u59cb\uff09 # [0 0 0 1 0 0 2 1 3 2 2 1] \u6ce8\u610f\uff0c pd.value_counts(cats) \u662f\u5bf9 pandas.cut \u7684\u7ed3\u679c\u4e2d\u7684\u7bb1\u6570\u91cf\u7684\u8ba1\u6570\u3002 result = pd.value_counts(cats) print(result) # (18, 25] 5 # (25, 35] 3 # (35, 60] 3 # (60, 100] 1 # dtype: int64 \u4e0e\u533a\u95f4\u7684\u6570\u5b66\u7b26\u53f7\u4e00\u81f4\uff0c\u5c0f\u62ec\u53f7\u8868\u793a\u8fb9\u662f\u5f00\u653e\u7684\uff0c\u4e2d\u62ec\u53f7\u8868\u793a\u5b83\u662f\u5c01\u95ed\u7684\uff08\u5305\u62ec\u8fb9\uff09\u3002\u53ef\u4ee5\u901a\u8fc7\u4f20\u9012 right=False \u6765\u6539\u53d8\u54ea\u4e00\u8fb9\u662f\u5c01\u95ed\u7684\u3002\u9ed8\u8ba4 right=True \u3002 result = pd.cut(ages, [18, 26, 36, 61, 100], right=False) print(result) # [[18, 26), [18, 26), [18, 26), [26, 36), [18, 26), ..., [26, 36), [61, 100), [36, 61), [36, 61), [26, 36)] # Length: 12 # Categories (4, interval[int64, left]): [[18, 26) < [26, 36) < [36, 61) < [61, 100)] \u901a\u8fc7\u5411 labels \u9009\u9879\u4f20\u9012\u4e00\u4e2a\u5217\u8868\u6216\u6570\u7ec4\u6765\u4f20\u5165\u81ea\u5b9a\u4e49\u7684\u7bb1\u540d\u3002 group_name = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior'] result = pd.cut(ages, bins, labels=group_name) print(result) # ['Youth', 'Youth', 'Youth', 'YoungAdult', 'Youth', ..., 'YoungAdult', 'Senior', 'MiddleAged', 'MiddleAged', 'YoungAdult'] # Length: 12 # Categories (4, object): ['Youth' < 'YoungAdult' < 'MiddleAged' < 'Senior'] result = pd.value_counts(pd.cut(ages, bins, labels=group_name)) # \u6807\u7b7e\u8f93\u51fa print(result) # Youth 5 # YoungAdult 3 # MiddleAged 3 # Senior 1 # dtype: int64 result = pd.value_counts(pd.cut(ages, bins)) # \u533a\u95f4\u8f93\u51fa print(result) # (18, 25] 5 # (25, 35] 3 # (35, 60] 3 # (60, 100] 1 # dtype: int64 \u5982\u679c\u4f20\u7ed9 cut \u6574\u6570\u4e2a\u7684\u7bb1\u6765\u4ee3\u66ff\u663e\u5f0f\u7684\u7bb1\u8fb9\uff0cpandas\u5c06\u6839\u636e\u6570\u636e\u4e2d\u7684\u6700\u5c0f\u503c\u548c\u6700\u5927\u503c\u8ba1\u7b97\u51fa\u7b49\u957f\u7684\u7bb1\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u8003\u8651\u4e00\u4e9b\u5747\u5300\u5206\u5e03\u7684\u6570\u636e\u88ab\u5207\u6210\u56db\u4efd\u7684\u60c5\u51b5\u3002 data = np.random.rand(20) result = pd.cut(data, 4, precision=2) # precision=2\u7684\u9009\u9879\u5c06\u5341\u8fdb\u5236\u7cbe\u5ea6\u9650\u5236\u5728\u4e24\u4f4d\u3002 print(result) # [(0.44, 0.66], (0.0063, 0.23], (0.23, 0.44], (0.0063, 0.23], (0.23, 0.44], ..., (0.23, 0.44], (0.0063, 0.23], (0.23, 0.44], (0.66, 0.88], (0.23, 0.44]] # Length: 20 # Categories (4, interval[float64, right]): [(0.0063, 0.23] < (0.23, 0.44] < (0.44, 0.66] < (0.66, 0.88]] qcut \u662f\u4e00\u4e2a\u4e0e\u5206\u7bb1\u5bc6\u5207\u76f8\u5173\u7684\u51fd\u6570\uff0c\u5b83\u57fa\u4e8e\u6837\u672c\u5206\u4f4d\u6570\u8fdb\u884c\u5206\u7bb1\u3002 \u53d6\u51b3\u4e8e\u6570\u636e\u7684\u5206\u5e03\uff0c\u4f7f\u7528 cut \u901a\u5e38\u4e0d\u4f1a\u4f7f\u6bcf\u4e2a\u7bb1\u5177\u6709\u76f8\u540c\u6570\u636e\u91cf\u7684\u6570\u636e\u70b9\u3002 \u7531\u4e8eqcut\u4f7f\u7528\u6837\u672c\u7684\u5206\u4f4d\u6570\uff0c\u4f60\u53ef\u4ee5\u901a\u8fc7qcut\u83b7\u5f97\u7b49\u957f\u7684\u7bb1\u3002 data = np.random.randn(1000) # \u6b63\u6001\u5206\u5e03 cats = pd.qcut(data, 4) # \u5207\u62104\u4efd print(cats) # [(-0.00329, 0.644], (-0.00329, 0.644], (-0.659, -0.00329], (-0.659, -0.00329], (0.644, 3.468], ..., (0.644, 3.468], (-3.9619999999999997, -0.659], (-3.9619999999999997, -0.659], (-0.00329, 0.644], (-0.00329, 0.644]] # Length: 1000 # Categories (4, interval[float64, right]): [(-3.9619999999999997, -0.659] < (-0.659, -0.00329] < (-0.00329, 0.644] < (0.644, 3.468]] result = pd.value_counts(cats) print(result) # (-3.9619999999999997, -0.659] 250 # (-0.659, -0.00329] 250 # (-0.00329, 0.644] 250 # (0.644, 3.468] 250 # dtype: int64 \u4e0e cut \u7c7b\u4f3c\uff0c\u53ef\u4ee5\u4f20\u5165\u81ea\u5b9a\u4e49\u7684\u5206\u4f4d\u6570\uff080\u548c1\u4e4b\u95f4\u7684\u6570\u636e\uff0c\u5305\u62ec\u8fb9\uff09\u3002 result = pd.qcut(data, [0, 0.1, 0.5, 0.9, 1.]) print(result) # [(-0.00329, 1.234], (-0.00329, 1.234], (-1.321, -0.00329], (-1.321, -0.00329], (-0.00329, 1.234], ..., (-0.00329, 1.234], (-1.321, -0.00329], (-1.321, -0.00329], (-0.00329, 1.234], (-0.00329, 1.234]] # Length: 1000 # Categories (4, interval[float64, right]): [(-3.9619999999999997, -1.321] < (-1.321, -0.00329] < (-0.00329, 1.234] < (1.234, 3.468]] \u68c0\u6d4b\u548c\u8fc7\u6ee4\u5f02\u5e38\u503c \u00b6 \u8fc7\u6ee4\u6216\u8f6c\u6362\u5f02\u5e38\u503c\u5728\u5f88\u5927\u7a0b\u5ea6\u4e0a\u662f\u5e94\u7528\u6570\u7ec4\u64cd\u4f5c\u7684\u4e8b\u60c5\u3002 \u8003\u8651\u4e00\u4e2a\u5177\u6709\u6b63\u6001\u5206\u5e03\u6570\u636e\u7684DataFrame\u3002 data = pd.DataFrame(np.random.randn(1000, 4)) print(data.describe()) # 0 1 2 3 # count 1000.000000 1000.000000 1000.000000 1000.000000 # mean 0.008124 -0.008050 -0.013403 -0.008261 # std 0.979236 0.992982 0.998819 1.038760 # min -3.231914 -3.441270 -3.345210 -4.320565 # 25% -0.634801 -0.599852 -0.656481 -0.677611 # 50% -0.033252 0.000060 -0.040634 -0.015463 # 75% 0.649340 0.644312 0.678101 0.683849 # max 3.292099 2.758754 2.911447 3.371729 \u627e\u51fa\u4e00\u5217\u4e2d\u7edd\u5bf9\u503c\u5927\u4e8e\u4e09\u7684\u503c\u3002 col = data[2] result = col[np.abs(col) > 3] print(result) # 519 -3.035355 # 536 -3.345210 # Name: 2, dtype: float64 \u9009\u51fa\u6240\u6709\u503c\u5927\u4e8e3\u6216\u5c0f\u4e8e-3\u7684\u884c\uff0c\u53ef\u4ee5\u5bf9\u5e03\u5c14\u503cDataFrame\u4f7f\u7528 any \u65b9\u6cd5\u3002 result = data[(np.abs(data) > 3).any(1)] print(result) # 0 1 2 3 # 116 -0.080907 -3.441270 -0.163263 0.392800 # 139 -1.294440 1.828397 1.178897 -3.469466 # 241 -0.486292 0.150443 0.264172 -3.013440 # 295 3.292099 -0.339284 0.732829 -0.475202 # 355 0.307577 -3.053322 0.967497 0.896363 # 359 3.264981 -1.172096 0.207622 -0.281803 # 519 -0.448987 1.623843 -3.035355 -0.436833 # 533 -1.022616 -0.212597 1.030969 3.371729 # 536 1.067598 -1.306839 -3.345210 0.620834 # 541 -0.952760 -2.157970 -0.403199 -4.320565 # 690 0.006821 -3.104117 0.484881 -0.132613 # 750 -3.231914 1.017712 0.070430 0.631447 # 771 -3.007622 0.257960 -0.118179 -1.283365 # 976 1.684760 -0.003295 -0.249843 3.169371 \u6839\u636e\u8fd9\u4e9b\u6807\u51c6\u6765\u8bbe\u7f6e\u6765\u9650\u5b9a\u503c\uff0c\u4e0b\u9762\u4ee3\u7801\u9650\u5236\u4e86-3\u52303\u4e4b\u95f4\u7684\u6570\u503c\u3002 \u8bed\u53e5 np.sign(data) \u6839\u636e\u6570\u636e\u4e2d\u7684\u503c\u7684\u6b63\u8d1f\u5206\u522b\u751f\u62101\u548c-1\u7684\u6570\u503c\u3002 result = data[(np.abs(data) > 3)] = np.sign(data) * 3 print(result.describe()) # 0 1 2 3 # count 1000.000000 1000.000000 1000.000000 1000.000000 # mean -0.036000 0.000000 -0.084000 -0.048000 # std 3.001285 3.001501 3.000324 3.001117 # min -3.000000 -3.000000 -3.000000 -3.000000 # 25% -3.000000 -3.000000 -3.000000 -3.000000 # 50% -3.000000 0.000000 -3.000000 -3.000000 # 75% 3.000000 3.000000 3.000000 3.000000 # max 3.000000 3.000000 3.000000 3.000000 print(result.head()) # 0 1 2 3 # 0 -3.0 3.0 -3.0 -3.0 # 1 -3.0 -3.0 -3.0 -3.0 # 2 3.0 3.0 -3.0 3.0 # 3 3.0 -3.0 3.0 -3.0 # 4 3.0 -3.0 -3.0 -3.0 \u7f6e\u6362\u548c\u968f\u673a\u62bd\u6837 \u00b6 \u4f7f\u7528 numpy.random.permutation \u5bf9DataFrame\u4e2d\u7684Series\u6216\u884c\u8fdb\u884c\u7f6e\u6362\uff08\u968f\u673a\u91cd\u6392\u5e8f\uff09\u3002 \u5728\u8c03\u7528 permutation \u65f6\u6839\u636e\u4f60\u60f3\u8981\u7684\u8f74\u957f\u5ea6\u53ef\u4ee5\u4ea7\u751f\u4e00\u4e2a\u8868\u793a\u65b0\u987a\u5e8f\u7684\u6574\u6570\u6570\u7ec4\u3002 df = pd.DataFrame(np.arange(5 * 4).reshape((5, 4))) sampler = np.random.permutation(5) print(sampler) # \u8fd4\u56dearray # [1 4 3 0 2] print(df) # 0 1 2 3 # 0 0 1 2 3 # 1 4 5 6 7 # 2 8 9 10 11 # 3 12 13 14 15 # 4 16 17 18 19 \u4e0a\u9762\u8fd4\u56de\u7684 sampler \u6574\u6570\u6570\u7ec4 [1 4 3 0 2] \u7528\u5728\u57fa\u4e8e iloc \u7684\u7d22\u5f15\u6216\u7b49\u4ef7\u7684 take \u51fd\u6570\u4e2d\uff0c\u91cd\u65b0\u6392\u5217\u884c\u987a\u5e8f\u3002 print(df.take(sampler)) # 0 1 2 3 # 1 4 5 6 7 # 4 16 17 18 19 # 3 12 13 14 15 # 0 0 1 2 3 # 2 8 9 10 11 \u9009\u51fa\u4e00\u4e2a\u4e0d\u542b\u6709\u66ff\u4ee3\u503c\u7684\u968f\u673a\u5b50\u96c6\uff0c\u53ef\u4ee5\u4f7f\u7528Series\u548cDataFrame\u7684 sample \u65b9\u6cd5\u3002 result = df.sample(n=3) print(result) # 0 1 2 3 # 0 0 1 2 3 # 2 8 9 10 11 # 1 4 5 6 7 \u8981\u751f\u6210\u4e00\u4e2a\u5e26\u6709\u66ff\u4ee3\u503c\u7684\u6837\u672c\uff08\u5141\u8bb8\u6709\u91cd\u590d\u9009\u62e9\uff09\uff0c\u5c06 replace=True \u4f20\u5165 sample \u65b9\u6cd5\u3002 choice = pd.Series([5, 7, -1, 6, 4]) draws = choice.sample(n=10, replace=True) print(choice) # 0 5 # 1 7 # 2 -1 # 3 6 # 4 4 # dtype: int64 print(draws) # 4 4 # 0 5 # 0 5 # 3 6 # 4 4 # 0 5 # 1 7 # 3 6 # 2 -1 # 0 5 # dtype: int64 \u8ba1\u7b97\u6307\u6807/\u865a\u62df\u53d8\u91cf \u00b6 \u5c06\u5206\u7c7b\u53d8\u91cf\u8f6c\u6362\u4e3a\u201c\u865a\u62df\u201d\u6216\u201c\u6307\u6807\u201d\u77e9\u9635\u662f\u53e6\u4e00\u79cd\u7528\u4e8e\u7edf\u8ba1\u5efa\u6a21\u6216\u673a\u5668\u5b66\u4e60\u7684\u8f6c\u6362\u64cd\u4f5c\u3002 \u5982\u679cDataFrame\u4e2d\u7684\u4e00\u5217\u6709 k \u4e2a\u4e0d\u540c\u7684\u503c\uff0c\u5219\u53ef\u4ee5\u884d\u751f\u4e00\u4e2a k \u5217\u7684\u503c\u4e3a 1 \u548c 0 \u7684\u77e9\u9635\u6216DataFrame\u3002 pandas\u6709\u4e00\u4e2aget_dummies\u51fd\u6570\u7528\u4e8e\u5b9e\u73b0\u8be5\u529f\u80fd\u3002 df = pd.DataFrame( { 'key': ['b', 'b', 'a', 'c', 'a', 'b'], 'data1': range(6) } ) print(df) # key data1 # 0 b 0 # 1 b 1 # 2 a 2 # 3 c 3 # 4 a 4 # 5 b 5 \u5728\u6307\u6807DataFrame\u7684\u5217\u4e0a\u52a0\u5165\u524d\u7f00\uff0c\u7136\u540e\u4e0e\u5176\u4ed6\u6570\u636e\u5408\u5e76\u3002\u5728 get_dummies \u65b9\u6cd5\u4e2d\u6709\u4e00\u4e2a\u524d\u7f00\u53c2\u6570\u7528\u4e8e\u5b9e\u73b0\u8be5\u529f\u80fd\u3002 \u901a\u8fc7 get_dummies \u65b9\u6cd5\uff0c\u628a\u4e0a\u9762 df \u6570\u636e\u6309\u7167 key \u8fdb\u884c\u4e86\u5206\u7ec4\uff0c\u5e76\u901a\u8fc7\u4e0d\u540c\u5217\u6765\u5c55\u73b0\u5206\u7ec4\u540e\u7684\u5bf9\u5e94\u5173\u7cfb\u3002\u4f8b\u5982\uff0c key \u5217\u7684 a \uff0c\u5bf9\u5e94\u503c 2 \u548c 4 \u3002 dummies = pd.get_dummies(df['key'], prefix='key') print(dummies) # key_a key_b key_c # 0 0 1 0 # 1 0 1 0 # 2 1 0 0 # 3 0 0 1 # 4 1 0 0 # 5 0 1 0 df_with_dummy = df[['data1']].join(dummies) print(df_with_dummy) # data1 key_a key_b key_c # 0 0 0 1 0 # 1 1 0 1 0 # 2 2 1 0 0 # 3 3 0 0 1 # 4 4 1 0 0 # 5 5 0 1 0 \u66f4\u4e3a\u590d\u6742\u7684\u60c5\u51b5\uff0cDataFrame\u4e2d\u7684\u4e00\u884c\u5c5e\u4e8e\u591a\u4e2a\u7c7b\u522b\u3002 \u4ee5MovieLens\u76841M\u6570\u636e\u96c6\u4e3a\u4f8b\u3002\u589e\u52a0\u53c2\u6570 encoding='unicode_escape' \u907f\u514d\u51fa\u73b0\u4e0b\u9762\u7684\u9519\u8bef\uff1a UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 3114: invalid continuation byte \u589e\u52a0\u53c2\u6570 engine='python' \u907f\u514d\u51fa\u73b0\u4e0b\u9762\u7684\u9519\u8bef\uff1a ParserWarning: Falling back to the 'python' engine because the 'c' engine does not support regex separators (separators > 1 char and different from '\\s+' are interpreted as regex); you can avoid this warning by specifying engine='python'. mnames = ['movie_id', 'title', 'genres'] movies = pd.read_table( '../datasets/movielens/movies.dat', sep='::', header=None, names=mnames, encoding='unicode_escape', engine='python' ) print(movies[:10]) # movie_id title genres # 0 1 Toy Story (1995) Animation|Children's|Comedy # 1 2 Jumanji (1995) Adventure|Children's|Fantasy # 2 3 Grumpier Old Men (1995) Comedy|Romance # 3 4 Waiting to Exhale (1995) Comedy|Drama # 4 5 Father of the Bride Part II (1995) Comedy # 5 6 Heat (1995) Action|Crime|Thriller # 6 7 Sabrina (1995) Comedy|Romance # 7 8 Tom and Huck (1995) Adventure|Children's # 8 9 Sudden Death (1995) Action # 9 10 GoldenEye (1995) Action|Adventure|Thriller \u4e3a\u6bcf\u4e2a\u7535\u5f71\u6d41\u6d3e\u6dfb\u52a0\u6307\u6807\u53d8\u91cf\u9700\u8981\u8fdb\u884c\u4e00\u4e9b\u6570\u636e\u5904\u7406\u3002 \u9996\u5148\uff0c\u6211\u4eec\u4ece\u6570\u636e\u96c6\u4e2d\u63d0\u53d6\u51fa\u6240\u6709\u4e0d\u540c\u7684\u6d41\u6d3e\u7684\u5217\u8868\u3002 all_genres = [] for x in movies.genres: all_genres.extend(x.split('|')) genres = pd.unique(all_genres) print(genres) # ['Animation' \"Children's\" 'Comedy' 'Adventure' 'Fantasy' 'Romance' 'Drama' # 'Action' 'Crime' 'Thriller' 'Horror' 'Sci-Fi' 'Documentary' 'War' # 'Musical' 'Mystery' 'Film-Noir' 'Western'] \u4f7f\u7528\u51680\u7684DataFrame\u662f\u6784\u5efa\u6307\u6807DataFrame\u7684\u4e00\u79cd\u65b9\u5f0f\u3002 zero_matrix = np.zeros((len(movies), len(genres))) dummies = pd.DataFrame(zero_matrix, columns=genres) print(zero_matrix) # [[0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.] # ... # [0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.]] print(dummies.head(n=10)) # Animation Children's Comedy ... Mystery Film-Noir Western # 0 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 1 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 2 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 3 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 4 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 5 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 6 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 7 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 8 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 9 0.0 0.0 0.0 ... 0.0 0.0 0.0 # # [10 rows x 18 columns] \u904d\u5386\u6bcf\u4e00\u90e8\u7535\u5f71\uff0c\u5c06 dummies \u6bcf\u4e00\u884c\u7684\u6761\u76ee\u8bbe\u7f6e\u4e3a 1 \u3002\u4f7f\u7528 dummies.columns \u6765\u8ba1\u7b97\u6bcf\u4e00\u4e2a\u6d41\u6d3e\u7684\u5217\u6307\u6807\u3002 gen = movies.genres[0] print(gen.split('|')) # ['Animation', \"Children's\", 'Comedy'] result = dummies.columns.get_indexer(gen.split('|')) print(result) # [0 1 2] \u4f7f\u7528 .loc \u6839\u636e\u8fd9\u4e9b\u6307\u6807\u6765\u8bbe\u7f6e\u503c\u3002 for i, gen in enumerate(movies.genres): indices = dummies.columns.get_indexer(gen.split('|')) dummies.iloc[i, indices] = 1 \u5c06\u7ed3\u679c\u4e0e movies \u8fdb\u884c\u5408\u5e76\u3002 movies_windic = movies.join(dummies.add_prefix('Genre_')) print(movies_windic.iloc[0]) # movie_id 1 # title Toy Story (1995) # genres Animation|Children's|Comedy # Genre_Animation 1.0 # Genre_Children's 1.0 # Genre_Comedy 1.0 # Genre_Adventure 0.0 # Genre_Fantasy 0.0 # Genre_Romance 0.0 # Genre_Drama 0.0 # Genre_Action 0.0 # Genre_Crime 0.0 # Genre_Thriller 0.0 # Genre_Horror 0.0 # Genre_Sci-Fi 0.0 # Genre_Documentary 0.0 # Genre_War 0.0 # Genre_Musical 0.0 # Genre_Mystery 0.0 # Genre_Film-Noir 0.0 # Genre_Western 0.0 # Name: 0, dtype: object \u5bf9\u4e8e\u66f4\u5927\u7684\u6570\u636e\uff0c\u4e0a\u9762\u8fd9\u79cd\u4f7f\u7528\u591a\u6210\u5458\u6784\u5efa\u6307\u6807\u53d8\u91cf\u5e76\u4e0d\u662f\u7279\u522b\u5feb\u901f\u3002 \u66f4\u597d\u7684\u65b9\u6cd5\u662f\u5199\u4e00\u4e2a\u76f4\u63a5\u5c06\u6570\u636e\u5199\u4e3aNumPy\u6570\u7ec4\u7684\u5e95\u5c42\u51fd\u6570\uff0c\u7136\u540e\u5c06\u7ed3\u679c\u5c01\u88c5\u8fdbDataFrame\u3002 \u5c06 get_dummies \u4e0e cut \u7b49\u79bb\u6563\u5316\u51fd\u6570\u7ed3\u5408\u4f7f\u7528\u662f\u7edf\u8ba1\u5e94\u7528\u7684\u4e00\u4e2a\u6709\u7528\u65b9\u6cd5\u3002 np.random.seed(12345) # \u4f7f\u7528numpy.random.seed\u6765\u8bbe\u7f6e\u968f\u673a\u79cd\u5b50\u4ee5\u786e\u4fdd\u793a\u4f8b\u7684\u786e\u5b9a\u6027 values = np.random.rand(10) print(values) # [0.92961609 0.31637555 0.18391881 0.20456028 0.56772503 0.5955447 # 0.96451452 0.6531771 0.74890664 0.65356987] bins = [0, 0.2, 0.4, 0.6, 0.8, 1] result = pd.get_dummies(pd.cut(values, bins)) print(result) # (0.0, 0.2] (0.2, 0.4] (0.4, 0.6] (0.6, 0.8] (0.8, 1.0] # 0 0 0 0 0 1 # 1 0 1 0 0 0 # 2 1 0 0 0 0 # 3 0 1 0 0 0 # 4 0 0 1 0 0 # 5 0 0 1 0 0 # 6 0 0 0 0 1 # 7 0 0 0 1 0 # 8 0 0 0 1 0 # 9 0 0 0 1 0 \u5b57\u7b26\u4e32\u64cd\u4f5c \u00b6 import re pandas\u5141\u8bb8\u5c06\u5b57\u7b26\u4e32\u548c\u6b63\u5219\u8868\u8fbe\u5f0f\u7b80\u6d01\u5730\u5e94\u7528\u5230\u6574\u4e2a\u6570\u636e\u6570\u7ec4\u4e0a\uff0c\u6b64\u5916\u8fd8\u80fd\u5904\u7406\u6570\u636e\u7f3a\u5931\u3002 \u5b57\u7b26\u4e32\u5bf9\u8c61\u65b9\u6cd5 \u00b6 \u5b57\u4e32\u62c6\u5206\u5408\u5e76\u65b9\u6cd5\u3002\u5728\u5f88\u591a\u5b57\u7b26\u4e32\u5904\u7406\u548c\u811a\u672c\u5e94\u7528\u4e2d\uff0c\u5185\u5efa\u7684\u5b57\u7b26\u4e32\u65b9\u6cd5\u662f\u8db3\u591f\u7684\u3002 \u4f8b\u5982\uff0c\u4e00\u4e2a\u9017\u53f7\u5206\u9694\u7684\u5b57\u7b26\u4e32\u53ef\u4ee5\u4f7f\u7528split\u65b9\u6cd5\u62c6\u5206\u6210\u591a\u5757\u3002 import numpy as np import pandas as pd val = 'a, b, guido' result = val.split(',') print(result) # ['a', ' b', ' guido'] count \uff1a\u8fd4\u56de\u5b50\u5b57\u7b26\u4e32\u5728\u5b57\u7b26\u4e32\u4e2d\u7684\u975e\u91cd\u53e0\u51fa\u73b0\u6b21\u6570\u3002 result = val.count(',') print(result) # 2 endswith \uff1a\u5982\u679c\u5b57\u7b26\u4e32\u4ee5\u540e\u7f00\u7ed3\u5c3e\u5219\u8fd4\u56de True \u3002 startswith \uff1a\u5982\u679c\u5b57\u7b26\u4e32\u4ee5\u540e\u7f00\u7ed3\u5c3e\u5219\u8fd4\u56de True \u3002 result = val.endswith('b') print(result) # False result = val.endswith('o') print(result) # True result = val.startswith('a') print(result) # True split \u5e38\u548c strip \u4e00\u8d77\u4f7f\u7528\uff0c\u7528\u4e8e\u6e05\u9664\u7a7a\u683c\uff08\u5305\u62ec\u6362\u884c\uff09\u3002 split \uff1a\u4f7f\u7528\u5206\u9694\u7b26\u8bb2\u5b57\u7b26\u4e32\u62c6\u5206\u6210\u5b50\u5b57\u7b26\u4e32\u7684\u5217\u8868\u3002 strip \uff0c rstrip \uff0c lstrip \uff1a\u4fee\u526a\u7a7a\u767d\uff0c\u5305\u62ec\u6362\u884c\u7b26\uff1b\u76f8\u5f53\u4e8e\u5bf9\u6bcf\u4e2a\u5143\u7d20\u8fdb\u884c x.strip() (\u4ee5\u53ca rstrip \uff0c lstrip )\u3002 pieces = [x.strip() for x in val.split(',')] print(pieces) # ['a', 'b', 'guido'] \u8fd9\u4e9b\u5b50\u5b57\u7b26\u4e32\u53ef\u4ee5\u4f7f\u7528\u52a0\u6cd5\u4e0e\u4e24\u4e2a\u5192\u53f7\u5206\u9694\u7b26\u8fde\u63a5\u5728\u4e00\u8d77\u3002 first, second, third = pieces result = first + '::' + second + '::' + third print(result) # a::b::guido \u4f46\u662f\u8fd9\u5e76\u4e0d\u662f\u4e00\u4e2a\u5b9e\u7528\u7684\u901a\u7528\u65b9\u6cd5\u3002 \u5728\u5b57\u7b26\u4e32 ': :' \u7684 join \u65b9\u6cd5\u4e2d\u4f20\u5165\u4e00\u4e2a\u5217\u8868\u6216\u5143\u7ec4\u662f\u4e00\u79cd\u66f4\u5feb\u4e14\u66f4\u52a0Pythonic\uff08Python\u98ce\u683c\u5316\uff09\u7684\u65b9\u6cd5\u3002 join : \u4f7f\u7528\u5b57\u7b26\u4e32\u5ea7\u4f4d\u95f4\u9694\u7b26\uff0c\u7528\u4e8e\u7c98\u5408\u5176\u4ed6\u5b57\u7b26\u4e32\u7684\u5e8f\u5217\u3002 result = '::'.join(pieces) print(result) # a::b::guido \u5b9a\u4f4d\u5b50\u5b57\u7b26\u4e32\u7684\u65b9\u6cd5\u3002 \u4f7f\u7528Python\u7684 in \u5173\u952e\u5b57\u662f\u68c0\u6d4b\u5b50\u5b57\u7b26\u4e32\u7684\u6700\u4f73\u65b9\u6cd5\uff0c\u5c3d\u7ba1 index \u548c find \u4e5f\u80fd\u5b9e\u73b0\u540c\u6837\u7684\u529f\u80fd\u3002 result = 'guido' in val print(result) # True index \uff1a\u5982\u679c\u5728\u5b57\u7b26\u4e32\u4e2d\u627e\u5230\uff0c\u5219\u8fd4\u56de\u5b50\u5b57\u7b26\u4e32\u4e2d\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u627e\u4e0d\u5230\u5219\u89e6\u53d1\u4e00\u4e2a ValueError \u3002 find \uff1a\u8fd4\u56de\u5b57\u7b26\u4e32\u4e2d\u7b2c\u4e00\u4e2a\u51fa\u73b0\u5b50\u5b57\u7b26\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u4f4d\u7f6e\uff0c\u7c7b\u4f3c index \uff0c\u5982\u679c\u6ca1\u6709\u627e\u5230\uff0c\u5219\u8fd4\u56de -1 \u3002 rfind \uff1a\u8fd4\u56de\u5b57\u7b26\u4e32\u4e2d\u5b50\u5b57\u7b26\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u65f6\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u627e\u5230\uff0c\u5219\u8fd4\u56de -1 \u3002 result = val.index(',') print(result) # 1 result = val.find(',') print(result) # 1 # result = val.index(':') print(result) # ValueError: substring not found result = val.find(':') print(result) # -1 result = val.rfind(',') print(result) # 4 replace \u5c06\u7528\u4e00\u79cd\u6a21\u5f0f\u66ff\u4ee3\u53e6\u4e00\u79cd\u6a21\u5f0f\u3002\u5b83\u4e5f\u7528\u4e8e\u4f20\u5165\u7a7a\u5b57\u7b26\u4e32\u6765\u5220\u9664\u67d0\u4e2a\u6a21\u5f0f\u3002 result = val.replace(',', '::') print(result) # a:: b:: guido result = val.replace(', ', '') print(result) # abguido result = val.replace(',', '') print(result) # a b guido lower \uff1a\u5c06\u5927\u5199\u5b57\u6bcd\u8f6c\u6362\u4e3a\u5c0f\u5199\u5b57\u6bcd\u3002 upper \uff1a\u5c06\u5c0f\u5199\u5b57\u6bcd\u8f6c\u6362\u4e3a\u5927\u5199\u5b57\u6bcd\u3002 uppers = val.upper() print(uppers) # A, B, GUIDO casefold \uff1a\u548c lower \u7c7b\u4f3c\uff0c\u5c06\u5b57\u7b26\u4e32\u4e2d\u7684\u5143\u7d20\u53d8\u6210\u5c0f\u5199\uff0c lower \u51fd\u6570\u53ea\u652f\u6301 ascill \u8868\u4e2d\u7684\u5b57\u7b26\uff0c casefold \u652f\u6301\u5f88\u591a\u4e0d\u540c\u79cd\u7c7b\u7684\u8bed\u8a00\u3002 str1 = \"Jan Wei\u03b2@cN\u4e0a\u6d77\" result = str1.casefold() print(result) # jan wei\u03b2@cn\u4e0a\u6d77 result = str1.lower() print(result) # jan wei\u03b2@cn\u4e0a\u6d77 ljust \uff0c rjust \uff1a\u5de6\u5bf9\u9f50\u6216\u8005\u53f3\u5bf9\u9f50\uff1b\u7528\u7a7a\u683c\u6216\u8005\u5176\u5b83\u4e00\u4e9b\u5b57\u7b26\u586b\u5145\u5b57\u7b26\u4e32\u7684\u76f8\u53cd\u4fa7\uff0c\u4ee5\u8fd4\u56de\u5177\u6709\u6700\u5c0f\u5bbd\u5ea6\u7684\u5b57\u7b26\u4e32 str1 = 'https://docs.python.org/3/' str2 = 'https://packagehub.suse.com/package-categories/python/' print(str1.ljust(60, '*')) print(str2.ljust(60, '*')) # https://docs.python.org/3/********************************** # https://packagehub.suse.com/package-categories/python/****** print(str1.rjust(60, '*')) print(str2.rjust(60, '*')) # **********************************https://docs.python.org/3/ # ******https://packagehub.suse.com/package-categories/python/ print(str1.rjust(60)) print(str2.rjust(60)) \u6b63\u5219\u8868\u8fbe\u5f0f \u00b6 Python\u5185\u5efa\u7684 re \u6a21\u5757\u662f\u7528\u4e8e\u5c06\u6b63\u5219\u8868\u8fbe\u5f0f\u5e94\u7528\u5230\u5b57\u7b26\u4e32\u4e0a\u7684\u5e93\u3002 re \u6a21\u5757\u4e3b\u8981\u6709\u4e09\u4e2a\u4e3b\u9898\uff1a\u6a21\u5f0f\u5339\u914d\u3001\u66ff\u4ee3\u3001\u62c6\u5206\u3002 \u770b\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\uff1a\u5047\u8bbe\u6211\u4eec\u60f3\u5c06\u542b\u6709\u591a\u79cd\u7a7a\u767d\u5b57\u7b26\uff08\u5236\u8868\u7b26\u3001\u7a7a\u683c\u3001\u6362\u884c\u7b26\uff09\u7684\u5b57\u7b26\u4e32\u62c6\u5206\u5f00\u3002 \u63cf\u8ff0\u4e00\u4e2a\u6216\u591a\u4e2a\u7a7a\u767d\u5b57\u7b26\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u662f \\s+ \u3002 \u5f53\u8c03\u7528 re.split('\\s+', text) \uff0c\u6b63\u5219\u8868\u8fbe\u5f0f\u9996\u5148\u4f1a\u88ab\u7f16\u8bd1\uff0c\u7136\u540e\u6b63\u5219\u8868\u8fbe\u5f0f\u7684 split \u65b9\u6cd5\u5728\u4f20\u5165\u6587\u672c\u4e0a\u88ab\u8c03\u7528\u3002 text = \"foo bar\\t baz \\tqux\" result = re.split('\\s+', text) print(result) # ['foo', 'bar', 'baz', 'qux'] \u53ef\u4ee5\u4f7f\u7528 re.compile \u81ea\u884c\u7f16\u8bd1\uff0c\u5f62\u6210\u4e00\u4e2a\u53ef\u590d\u7528\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u5bf9\u8c61\u3002 regex = re.compile('\\s+') result = regex.split(text) print(result) # ['foo', 'bar', 'baz', 'qux'] \u5982\u679c\u60f3\u83b7\u5f97\u7684\u662f\u4e00\u4e2a\u6240\u6709\u5339\u914d\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u6a21\u5f0f\u7684\u5217\u8868\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 findall \u65b9\u6cd5\u3002 result = regex.findall(text) print(result) # [' ', '\\t ', ' \\t'] \u4e3a\u4e86\u5728\u6b63\u5219\u8868\u8fbe\u5f0f\u4e2d\u907f\u514d\u8f6c\u4e49\u7b26 \\ \u7684\u5f71\u54cd\uff0c\u53ef\u4ee5\u4f7f\u7528\u539f\u751f\u5b57\u7b26\u4e32\u8bed\u6cd5\uff0c\u6bd4\u5982 r'C:\\x' \u6216\u8005\u7528\u7b49\u4ef7\u7684 'C:\\\\x'\\ \u3002 \u5982\u679c\u9700\u8981\u5c06\u76f8\u540c\u7684\u8868\u8fbe\u5f0f\u5e94\u7528\u5230\u591a\u4e2a\u5b57\u7b26\u4e32\u4e0a\uff0c\u63a8\u8350\u4f7f\u7528 re.compile \u521b\u5efa\u4e00\u4e2a\u6b63\u5219\u8868\u8fbe\u5f0f\u5bf9\u8c61\uff0c\u8fd9\u6837\u505a\u6709\u5229\u4e8e\u8282\u7ea6CPU\u5468\u671f\u3002 match \u548c search \u4e0e findall \u76f8\u5173\u6027\u5f88\u5927\u3002 findall \u8fd4\u56de\u7684\u662f\u5b57\u7b26\u4e32\u4e2d\u6240\u6709\u7684\u5339\u914d\u9879\uff0c\u800c search \u8fd4\u56de\u7684\u4ec5\u4ec5\u662f\u7b2c\u4e00\u4e2a\u5339\u914d\u9879\u3002 match \u66f4\u4e3a\u4e25\u683c\uff0c\u5b83\u53ea\u5728\u5b57\u7b26\u4e32\u7684\u8d77\u59cb\u4f4d\u7f6e\u8fdb\u884c\u5339\u914d\u3002 text = \"\"\"Dave dave@google.com Steve steve@gmail.com Rob rob@gmail.com Ryan ryan@yahoo.com \"\"\" pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}' regex = re.compile(pattern, flags=re.IGNORECASE) # flags=re.IGNORECASE \u4f7f\u6b63\u5219\u8868\u8fbe\u5f0f\u4e0d\u533a\u5206\u5927\u5c0f\u5199 m = regex.findall(text) # findall\u4f1a\u751f\u6210\u4e00\u4e2a\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u7684\u5217\u8868 print(m) # ['dave@google.com', 'steve@gmail.com', 'rob@gmail.com', 'ryan@yahoo.com'] search \u8fd4\u56de\u7684\u662f\u6587\u672c\u4e2d\u7b2c\u4e00\u4e2a\u5339\u914d\u5230\u7684\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u3002 \u5bf9\u4e8e\u524d\u9762\u63d0\u5230\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\uff0c\u5339\u914d\u5bf9\u8c61\u53ea\u80fd\u544a\u8bc9\u6211\u4eec\u6a21\u5f0f\u5728\u5b57\u7b26\u4e32\u4e2d\u8d77\u59cb\u548c\u7ed3\u675f\u7684\u4f4d\u7f6e\u3002 m = regex.search(text) print(m) # print(text[m.start():m.end()]) # dave@google.com regex.match \u53ea\u5728\u6a21\u5f0f\u51fa\u73b0\u4e8e\u5b57\u7b26\u4e32\u8d77\u59cb\u4f4d\u7f6e\u65f6\u8fdb\u884c\u5339\u914d\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u5230\uff0c\u8fd4\u56de None \u3002 m = regex.match(text) print(m) # None m = regex.match('rob@gmail.com') print(m) # print(m.group()) # rob@gmail.com print(m.groups()) # () regex.sub \u4f1a\u8fd4\u56de\u4e00\u4e2a\u65b0\u7684\u5b57\u7b26\u4e32\uff0c\u539f\u5b57\u7b26\u4e32\u4e2d\u7684\u6a21\u5f0f\u4f1a\u88ab\u4e00\u4e2a\u65b0\u7684\u5b57\u7b26\u4e32\u66ff\u4ee3\u3002 m = regex.sub('REDACTED', text) print(m) # Dave REDACTED # Steve REDACTED # Rob REDACTED # Ryan REDACTED \u67e5\u627e\u7535\u5b50\u90ae\u4ef6\u5730\u5740\uff0c\u5e76\u5c06\u6bcf\u4e2a\u5730\u5740\u5206\u4e3a\u4e09\u4e2a\u90e8\u5206\uff1a\u7528\u6237\u540d\uff0c\u57df\u540d\u548c\u57df\u540d\u540e\u7f00\u3002\u8981\u5b9e\u73b0\u8fd9\u4e00\u70b9\uff0c\u53ef\u4ee5\u7528\u62ec\u53f7\u5c06 pattern \u5305\u8d77\u6765\u3002 \u4fee\u6539\u540e\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u4ea7\u751f\u7684\u5339\u914d\u5bf9\u8c61\u7684 groups \u65b9\u6cd5\uff0c\u8fd4\u56de\u7684\u662f\u6a21\u5f0f\u7ec4\u4ef6\u7684\u5143\u7ec4\u3002 text = \"\"\"Dave dave@google.com Steve steve@gmail.com Rob rob@gmail.com Ryan ryan@yahoo.com \"\"\" pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\\.([A-Z]{2,4})' regex = re.compile(pattern, flags=re.IGNORECASE) m = regex.findall(text) # \u5f53pattern\u53ef\u4ee5\u5206\u7ec4\u65f6\uff0cfindall\u8fd4\u56de\u7684\u662f\u5305\u542b\u5143\u7ec4\u7684\u5217\u8868 print(m) # [('dave', 'google', 'com'), ('steve', 'gmail', 'com'), ('rob', 'gmail', 'com'), ('ryan', 'yahoo', 'com')] m = regex.search(text) print(m) # print(text[m.start():m.end()]) # dave@google.com m = regex.match('rob@gmail.com') print(m) # print(m.group()) # rob@gmail.com print(m.groups()) # ('rob', 'gmail', 'com') m = regex.sub('REDACTED', text) print(m) # Dave REDACTED # Steve REDACTED # Rob REDACTED # Ryan REDACTED m = regex.sub(r'Username: \\1, Domain: \\2, Suffix: \\3', text) print(m) # Dave Username: dave, Domain: google, Suffix: com # Steve Username: steve, Domain: gmail, Suffix: com # Rob Username: rob, Domain: gmail, Suffix: com # Ryan Username: ryan, Domain: yahoo, Suffix: com pandas\u4e2d\u7684\u5411\u91cf\u5316\u5b57\u7b26\u4e32\u51fd\u6570 \u00b6 \u6e05\u7406\u6742\u4e71\u7684\u6570\u636e\u96c6\u7528\u4e8e\u5206\u6790\u901a\u5e38\u9700\u8981\u5927\u91cf\u7684\u5b57\u7b26\u4e32\u5904\u7406\u548c\u6b63\u5219\u5316\u3002 data = { 'Dave': 'dave@gmail.com', 'Steve': 'steve@gmail.com', 'Rob': 'rob@gmail.com', 'Wes': np.nan } data = pd.Series(data) print(data) # Dave dave@gmail.com # Steve steve@gmail.com # Rob rob@gmail.com # Wes NaN # dtype: object print(data.isnull()) # Dave False # Steve False # Rob False # Wes True # dtype: bool \u53ef\u4ee5\u4f7f\u7528 data.map \u5c06\u5b57\u7b26\u4e32\u548c\u6709\u6548\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u65b9\u6cd5\uff08\u4ee5 lambda \u6216\u5176\u4ed6\u51fd\u6570\u7684\u65b9\u5f0f\u4f20\u9012\uff09\u5e94\u7528\u5230\u6bcf\u4e2a\u503c\u4e0a\uff0c\u4f46\u662f\u5728 NA \uff08 null \uff09\u503c\u4e0a\u4f1a\u5931\u8d25\u3002 \u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0cSeries\u6709\u9762\u5411\u6570\u7ec4\u7684\u65b9\u6cd5\u7528\u4e8e\u8df3\u8fc7 NA \u503c\u7684\u5b57\u7b26\u4e32\u64cd\u4f5c\u3002\u8fd9\u4e9b\u65b9\u6cd5\u901a\u8fc7Series\u7684 str \u5c5e\u6027\u8fdb\u884c\u8c03\u7528\u3002 \u4f8b\u5982\uff0c\u53ef\u4ee5\u901a\u8fc7 str.contains \u6765\u68c0\u67e5\u6bcf\u4e2a\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u662f\u5426\u542b\u6709 'gmail' \u3002 m = data.str.contains('gmail') print(m) # Dave True # Steve True # Rob True # Wes NaN # dtype: object \u6b63\u5219\u8868\u8fbe\u5f0f\u4e5f\u53ef\u4ee5\u7ed3\u5408\u4efb\u610f\u7684 re \u6a21\u5757\u9009\u9879\u4f7f\u7528\uff0c\u4f8b\u5982 IGNORECASE \u3002 print(pattern) # ([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\\.([A-Z]{2,4}) m = data.str.findall(pattern, flags=re.IGNORECASE) print(m) # Dave [(dave, gmail, com)] # Steve [(steve, gmail, com)] # Rob [(rob, gmail, com)] # Wes NaN # dtype: object \u4f7f\u7528 str.get \u6216\u5728 str \u5c5e\u6027\u5185\u90e8\u7d22\u5f15\uff0c\u8fdb\u884c\u5411\u91cf\u5316\u7684\u5143\u7d20\u68c0\u7d22\u3002 m = data.str.match(pattern, flags=re.IGNORECASE) print(m) # Dave True # Steve True # Rob True # Wes NaN # dtype: object m = data.str.findall(pattern, flags=re.IGNORECASE) print(m.str.get(1)) # Dave NaN # Steve NaN # Rob NaN # Wes NaN # dtype: float64 print(m.str[0]) # Dave (dave, gmail, com) # Steve (steve, gmail, com) # Rob (rob, gmail, com) # Wes NaN # dtype: object \u4f7f\u7528\u5b57\u7b26\u4e32\u5207\u7247\u7684\u7c7b\u4f3c\u8bed\u6cd5\u8fdb\u884c\u5411\u91cf\u5316\u5207\u7247\u3002 print(data.str[:]) # Dave dave@gmail.com # Steve steve@gmail.com # Rob rob@gmail.com # Wes NaN # dtype: object print(data.str[:5]) # Dave dave@ # Steve steve # Rob rob@g # Wes NaN # dtype: object","title":"\u6570\u636e\u6e05\u6d17\u4e0e\u51c6\u5907"},{"location":"python/DataAnalysis/ch04/#_1","text":"","title":"\u6570\u636e\u6e05\u6d17\u4e0e\u51c6\u5907"},{"location":"python/DataAnalysis/ch04/#_2","text":"import pandas as pd import numpy as np from numpy import nan as NA \u5bf9\u4e8e\u6570\u503c\u578b\u6570\u636e\uff0cpandas\u4f7f\u7528\u6d6e\u70b9\u503c NaN \uff08Not a Number\u6765\u8868\u793a\u7f3a\u5931\u503c\uff09\u3002 \u5728pandas\u4e2d\uff0c\u91c7\u7528\u4e86R\u8bed\u8a00\u4e2d\u7684\u7f16\u7a0b\u60ef\u4f8b\uff0c\u5c06\u7f3a\u5931\u503c\u6210\u4e3a NA \uff0c\u610f\u601d\u662fnotavailable\uff08\u4e0d\u53ef\u7528\uff09\u3002 Python\u5185\u5efa\u7684 None \u503c\u5728\u5bf9\u8c61\u6570\u7ec4\u4e2d\u4e5f\u88ab\u5f53\u4f5c NA \u5904\u7406\u3002 NA\u5904\u7406\u65b9\u6cd5\uff1a dropna :\u6839\u636e\u6bcf\u4e2a\u6807\u7b7e\u7684\u503c\u662f\u5426\u662f\u786e\u5b9e\u6570\u636e\u6765\u7b5b\u9009\u8f74\u6807\u7b7e\uff0c\u5e76\u6839\u636e\u5141\u8bb8\u4e22\u5931\u7684\u6570\u636e\u91cf\u6765\u786e\u5b9a\u9608\u503c fillna :\u7528\u67d0\u4e9b\u503c\u586b\u5145\u786e\u5b9e\u7684\u6570\u636e\u6216\u4f7f\u7528\u63d2\u503c\u65b9\u6cd5\uff0c\u5982 ffill \u6216 bfill isnull :\u8fd4\u56de\u8868\u660e\u54ea\u4e9b\u503c\u662f\u7f3a\u5931\u503c\u7684\u5e03\u5c14\u503c notnull :\u662f isnull \u7684\u53cd\u51fd\u6570 string_data = pd.Series(['aardvark', 'artichoke', np.nan, 'avocado']) print(string_data) # 0 aardvark # 1 artichoke # 2 NaN # 3 avocado # dtype: object print(string_data.isnull()) # 0 False # 1 False # 2 True # 3 False # dtype: bool string_data[0] = None print(string_data.isnull()) # 0 True # 1 False # 2 True # 3 False # dtype: bool","title":"\u5904\u7406\u7f3a\u5931\u503c"},{"location":"python/DataAnalysis/ch04/#_3","text":"","title":"\u8fc7\u6ee4\u7f3a\u5931\u503c"},{"location":"python/DataAnalysis/ch04/#series","text":"\u5728Series\u4e0a\u4f7f\u7528 dropna \uff0c\u5b83\u4f1a\u8fd4\u56deSeries\u4e2d\u6240\u6709\u7684\u975e\u7a7a\u6570\u636e\u53ca\u5176\u7d22\u5f15\u503c\u3002 data = pd.Series([1, NA, 3.5, NA, 7]) print(data.dropna()) # 0 1.0 # 2 3.5 # 4 7.0 # dtype: float64 print(data[data.notnull()]) # \u4e0e\u4e0a\u9762\u7b49\u4ef7 # 0 1.0 # 2 3.5 # 4 7.0 # dtype: float64","title":"\u5904\u7406Series"},{"location":"python/DataAnalysis/ch04/#dataframe","text":"data = pd.DataFrame( [[1., 6.5, 3.], [1., NA, NA], [NA, NA, NA], [NA, 6.5, 3.]] ) print(data) # 0 1 2 # 0 1.0 6.5 3.0 # 1 1.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 6.5 3.0 cleaned = data.dropna() # dropna\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u4f1a\u5220\u9664\u5305\u542b\u7f3a\u5931\u503c\u7684\u884c print(cleaned) # 0 1 2 # 0 1.0 6.5 3.0 cleaned = data.dropna(how='all') # \u4f20\u5165how='all\u2019\u65f6\uff0c\u5c06\u5220\u9664\u6240\u6709\u503c\u5747\u4e3aNA\u7684\u884c print(cleaned) # 0 1 2 # 0 1.0 6.5 3.0 # 1 1.0 NaN NaN # 3 NaN 6.5 3.0 data[4] = NA print(data) # 0 1 2 4 # 0 1.0 6.5 3.0 NaN # 1 1.0 NaN NaN NaN # 2 NaN NaN NaN NaN # 3 NaN 6.5 3.0 NaN cleaned = data.dropna(axis=1, how='all') # \u5220\u9664\u5168NA\u7684\u5217 print(cleaned) # 0 1 2 # 0 1.0 6.5 3.0 # 1 1.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 6.5 3.0 df = pd.DataFrame(np.random.randn(7, 3)) print(df) # 0 1 2 # 0 -1.069771 -0.777921 0.181956 # 1 -0.399504 -0.641737 -0.946327 # 2 -1.013920 -0.247588 -0.760146 # 3 1.076946 -1.263203 0.494077 # 4 0.460985 -1.241870 0.283006 # 5 1.168149 1.033752 0.900095 # 6 -1.208514 -1.049546 -0.783680 df.iloc[:4, 1] = NA # \u6807\u7b7e1\uff0c\u524d4\u4e2a\u5143\u7d20 df.iloc[:2, 2] = NA # \u6807\u7b7e2\uff0c\u524d2\u4e2a\u5143\u7d20 print(df) # 0 1 2 # 0 -1.069771 NaN NaN # 1 -0.399504 NaN NaN # 2 -1.013920 NaN -0.760146 # 3 1.076946 NaN 0.494077 # 4 0.460985 -1.241870 0.283006 # 5 1.168149 1.033752 0.900095 # 6 -1.208514 -1.049546 -0.783680 cleaned = df.dropna() print(cleaned) # 0 1 2 # 4 0.033663 0.291886 0.736448 # 5 -0.433380 0.397104 1.252005 # 6 -1.999018 0.303866 1.430109 cleaned = df.dropna(thresh=2) # \u4fdd\u75592\u884c\u542bNA\u7684\u89c2\u5bdf\u503c print(cleaned) # 0 1 2 # 2 -1.413976 NaN 0.222274 # 3 -0.644266 NaN 0.324180 # 4 -0.122160 -2.244880 -0.406562 # 5 -0.140326 0.101133 -0.764048 # 6 -1.809141 0.139091 -0.819175","title":"\u5904\u7406DataFrame"},{"location":"python/DataAnalysis/ch04/#_4","text":"fillna \u51fd\u6570\u53c2\u6570\uff1a value\uff1a\u6807\u91cf\u503c\u6216\u5b57\u5178\u578b\u5bf9\u8c61\u7528\u4e8e\u586b\u5145\u7f3a\u5931\u503c method\uff1a\u63d2\u503c\u65b9\u6cd5\uff0c\u5982\u679c\u6ca1\u6709\u5176\u4ed6\u53c2\u6570\uff0c\u9ed8\u8ba4\u662f'ffill' axis\uff1a\u9700\u8981\u586b\u5145\u7684\u8f74\uff0c\u9ed8\u8ba4axis=0 inplace\uff1a\u4fee\u6539\u88ab\u8c03\u7528\u5bf9\u8c61\uff0c\u800c\u4e0d\u662f\u751f\u6210\u4e00\u4e2a\u5907\u4efd limit\uff1a\u7528\u4e8e\u524d\u5411\u6216\u540e\u5411\u586b\u5145\u65f6\u6700\u5927\u7684\u586b\u5145\u8303\u56f4 df = pd.DataFrame(np.random.randn(7, 3)) df.iloc[:4, 1] = NA # \u6807\u7b7e1\uff0c\u524d4\u4e2a\u5143\u7d20 df.iloc[:2, 2] = NA # \u6807\u7b7e2\uff0c\u524d2\u4e2a\u5143\u7d20 print(df) # 0 1 2 # 0 -0.181196 NaN NaN # 1 -1.657668 NaN NaN # 2 -0.053454 NaN 0.391461 # 3 -0.539307 NaN -0.668400 # 4 -0.433439 0.839713 -0.295273 # 5 0.749930 1.661641 -0.495165 # 6 0.591810 1.017372 0.932367 result = df.fillna(0) # \u8c03\u7528fillna\u65f6\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e00\u4e2a\u5e38\u6570\u6765\u66ff\u4ee3\u7f3a\u5931\u503c print(result) # 0 1 2 # 0 -0.430926 0.000000 0.000000 # 1 0.448061 0.000000 0.000000 # 2 -0.059910 0.000000 -1.532646 # 3 -0.315793 0.000000 -0.196546 # 4 -0.546106 0.135108 -0.332309 # 5 1.083075 0.346070 -0.773104 # 6 -0.186511 1.055337 -1.168303 result = df.fillna({1: 0.5, 2: 0}) # \u8c03\u7528fillna\u65f6\u4f7f\u7528\u5b57\u5178\uff0c\u53ef\u4ee5\u4e3a\u4e0d\u540c\u5217\u8bbe\u5b9a\u4e0d\u540c\u7684\u586b\u5145\u503c print(result) # 0 1 2 # 0 -0.794344 0.500000 0.000000 # 1 -0.960917 0.500000 0.000000 # 2 1.494351 0.500000 0.100878 # 3 -0.554765 0.500000 1.118801 # 4 -0.866117 0.523615 1.217478 # 5 -0.706966 -0.681776 0.797690 # 6 -1.456366 1.205518 -0.402432 fillna \u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u65b0\u7684\u5bf9\u8c61\uff0c\u4f46\u4e5f\u53ef\u4ee5\u4fee\u6539\u5df2\u7ecf\u5b58\u5728\u7684\u5bf9\u8c61 _ = df.fillna(0, inplace=True) # inplace=True\u6307\u5b9a\u5728\u5df2\u6709\u5bf9\u8c61\u4e0a\u76f4\u63a5\u4fee\u6539 print(df) # 0 1 2 # 0 -1.176124 0.000000 0.000000 # 1 0.120458 0.000000 0.000000 # 2 -1.206408 0.000000 0.551693 # 3 0.224563 0.000000 1.145156 # 4 -0.557836 0.081135 -0.075282 # 5 2.378837 -0.876145 1.430386 # 6 -0.152662 1.278364 0.479686 df = pd.DataFrame(np.random.randn(6, 3)) df.iloc[2:, 1] = NA # \u6807\u7b7e1\uff0c\u524d4\u4e2a\u5143\u7d20 df.iloc[4:, 2] = NA # \u6807\u7b7e2\uff0c\u524d2\u4e2a\u5143\u7d20 print(df) # 0 1 2 # 0 1.154788 0.033949 -0.122807 # 1 0.258684 -0.580244 1.636514 # 2 1.503756 NaN -1.224203 # 3 0.824049 NaN -0.364345 # 4 -1.247609 NaN NaN # 5 -1.019980 NaN NaN result = df.fillna(method='ffill') # \u5411\u540e\u586b\u5145 print(result) # 0 1 2 # 0 2.082449 0.398874 0.359772 # 1 0.233129 0.385347 1.953533 # 2 0.396555 0.385347 0.592784 # 3 -0.957249 0.385347 0.169815 # 4 0.854452 0.385347 0.169815 # 5 -0.105982 0.385347 0.169815 result = df.fillna(method='ffill', limit=3) # \u6bcf\u5217\u6700\u591a\u586b3\u4e2a print(result) result = df.fillna(df[0].max()) # \u75280\u5217\u7684\u6700\u5927\u503c\u586b\u5145\u6240\u6709\u7684NA print(result) # 0 1 2 # 0 -0.377697 -0.852891 -0.705489 # 1 -0.611759 -0.013237 -0.295764 # 2 -0.389974 1.057881 1.041957 # 3 -0.016845 1.057881 -1.149954 # 4 1.057881 1.057881 1.057881 # 5 -0.463471 1.057881 1.057881","title":"\u8865\u5168\u7f3a\u5931\u503c"},{"location":"python/DataAnalysis/ch04/#_5","text":"import pandas as pd import numpy as np from numpy import nan as NA","title":"\u6570\u636e\u8f6c\u6362"},{"location":"python/DataAnalysis/ch04/#_6","text":"data = pd.DataFrame( { 'k1': ['one', 'two'] * 3 + ['two'], 'k2': [1, 1, 2, 3, 4, 4, 4] } ) print(data) # \u91cd\u590d\u51fa\u73b02\u6b21\u7684\u8bb0\u5f55\uff1atwo 4 # k1 k2 # 0 one 1 # 1 two 1 # 2 one 2 # 3 two 3 # 4 one 4 # 5 two 4 # 6 two 4 DataFrame\u7684 duplicated \u65b9\u6cd5\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u5e03\u5c14\u503cSeries\uff0c\u8fd9\u4e2aSeries\u53cd\u6620\u7684\u662f\u6bcf\u4e00\u884c\u662f\u5426\u5b58\u5728\u91cd\u590d\uff08\u4e0e\u4e4b\u524d\u51fa\u73b0\u8fc7\u7684\u884c\u76f8\u540c\uff09\u60c5\u51b5\uff0c\u9ed8\u8ba4\u662f\u5bf9\u5217\u8fdb\u884c\u64cd\u4f5c\u3002 print(data.duplicated()) # 0 False # 1 False # 2 False # 3 False # 4 False # 5 False # 6 True # dtype: bool drop_duplicates \u8fd4\u56de\u7684\u662fDataFrame\uff0c\u5185\u5bb9\u662f duplicated \u8fd4\u56de\u6570\u7ec4\u4e2d\u4e3a False \u7684\u90e8\u5206\u3002\u9ed8\u8ba4\u662f\u5bf9\u5217\u8fdb\u884c\u64cd\u4f5c\u3002 print(data.drop_duplicates()) # k1 k2 # 0 one 1 # 1 two 1 # 2 one 2 # 3 two 3 # 4 one 4 # 5 two 4 \u53ef\u4ee5\u6307\u5b9a\u6570\u636e\u7684\u4efb\u4f55\u5b50\u96c6\u6765\u68c0\u6d4b\u662f\u5426\u6709\u91cd\u590d\u3002\u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u989d\u5916\u7684\u5217\uff0c\u5e76\u60f3\u57fa\u4e8e\u2019k1\u2019\u5217\u53bb\u9664\u91cd\u590d\u503c\u3002 data['v1'] = range(7) print(data) # k1 k2 v1 # 0 one 1 0 # 1 two 1 1 # 2 one 2 2 # 3 two 3 3 # 4 one 4 4 # 5 two 4 5 # 6 two 4 6 print(data.drop_duplicates(['k1'])) # \u4fdd\u7559\u7b2c\u4e00\u4e2a\u89c2\u6d4b\u5230\u7684one\u548ctwo\uff0c\u5176\u4f59\u4e22\u5f03 # k1 k2 v1 # 0 one 1 0 # 1 two 1 1 duplicated \u548c drop_duplicates \u9ed8\u8ba4\u90fd\u662f\u4fdd\u7559\u7b2c\u4e00\u4e2a\u89c2\u6d4b\u5230\u7684\u503c\u3002\u4f20\u5165\u53c2\u6570keep='last\u2019\u5c06\u4f1a\u8fd4\u56de\u6700\u540e\u4e00\u4e2a\u3002 print(data.drop_duplicates(['k1'], keep='last')) # \u4fdd\u7559\u6700\u540e\u4e00\u4e2a\u89c2\u6d4b\u5230\u7684one\u548ctwo # k1 k2 v1 # 4 one 4 4 # 6 two 4 6","title":"\u5220\u9664\u91cd\u590d\u503c"},{"location":"python/DataAnalysis/ch04/#_7","text":"\u4f7f\u7528 map \u662f\u4e00\u79cd\u53ef\u4ee5\u4fbf\u6377\u6267\u884c\u6309\u5143\u7d20\u8f6c\u6362\u53ca\u5176\u4ed6\u6e05\u6d17\u76f8\u5173\u64cd\u4f5c\u7684\u65b9\u6cd5\u3002 data = pd.DataFrame( { 'food': ['bacon', 'pulled pork', 'bacon', 'Pastrami', 'corned beef', 'Bacon', 'pastrami', 'honey ham', 'nova lox'], 'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6] } ) print(data) # food ounces # 0 bacon 4.0 # 1 pulled pork 3.0 # 2 bacon 12.0 # 3 Pastrami 6.0 # 4 corned beef 7.5 # 5 Bacon 8.0 # 6 pastrami 3.0 # 7 honey ham 5.0 # 8 nova lox 6.0 \u6dfb\u52a0\u4e00\u5217\u7528\u4e8e\u8868\u660e\u6bcf\u79cd\u98df\u7269\u7684\u52a8\u7269\u8089\u7c7b\u578b\u3002 \u5148\u521b\u5efa\u4e00\u4e2a\u98df\u7269\u548c\u8089\u7c7b\u7684\u6620\u5c04\u3002 meat_to_animal = { 'bacon': 'pig', 'pulled pork': 'pig', 'pastrami': 'cow', 'corned beef': 'cow', 'honey ham': 'pig', 'nova lox': 'salmon' } lowercased = data['food'].str.lower() # \u4f7f\u7528Series\u7684str.lower\u65b9\u6cd5\u5c06food\u7684\u6bcf\u4e2a\u503c\u90fd\u8f6c\u6362\u4e3a\u5c0f\u5199 print(lowercased) # 0 bacon # 1 pulled pork # 2 bacon # 3 pastrami # 4 corned beef # 5 bacon # 6 pastrami # 7 honey ham # 8 nova lox # Name: food, dtype: object data['animal'] = lowercased.map(meat_to_animal) print(data) # food ounces animal # 0 bacon 4.0 pig # 1 pulled pork 3.0 pig # 2 bacon 12.0 pig # 3 Pastrami 6.0 cow # 4 corned beef 7.5 cow # 5 Bacon 8.0 pig # 6 pastrami 3.0 cow # 7 honey ham 5.0 pig # 8 nova lox 6.0 salmon \u4e5f\u53ef\u4ee5\u4f20\u5165\u4e00\u4e2a\u51fd\u6570\uff0c\u5b8c\u6210\u4e0a\u9762\u6240\u6709\u529f\u80fd\u3002 data = pd.DataFrame( { 'food': ['bacon', 'pulled pork', 'bacon', 'Pastrami', 'corned beef', 'Bacon', 'pastrami', 'honey ham', 'nova lox'], 'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6] } ) result = data['food'].map(lambda x: meat_to_animal[x.lower()]) print(result) # 0 pig # 1 pig # 2 pig # 3 cow # 4 cow # 5 pig # 6 cow # 7 pig # 8 salmon # Name: food, dtype: object","title":"\u4f7f\u7528\u51fd\u6570\u6216\u6620\u5c04\u8fdb\u884c\u6570\u636e\u8f6c\u6362"},{"location":"python/DataAnalysis/ch04/#_8","text":"\u4f7f\u7528 fillna \u586b\u5145\u7f3a\u5931\u503c\u662f\u901a\u7528\u503c\u66ff\u6362\u7684\u7279\u6b8a\u6848\u4f8b\u3002 map \u53ef\u4ee5\u7528\u6765\u4fee\u6539\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u7684\u5b50\u96c6\u7684\u503c\uff0c\u4f46\u662f replace \u63d0\u4f9b\u4e86\u66f4\u4e3a\u7b80\u5355\u7075\u6d3b\u7684\u5b9e\u73b0\u3002 data.replace \u65b9\u6cd5\u4e0e data.str.replace \u65b9\u6cd5\u662f\u4e0d\u540c\u7684\uff0c data.str.replace \u662f\u5bf9\u5b57\u7b26\u4e32\u8fdb\u884c\u6309\u5143\u7d20\u66ff\u4ee3\u7684\u3002 \u4e0b\u9762\u7684Series\uff0c -999 \u53ef\u80fd\u662f\u7f3a\u5931\u503c\u7684\u6807\u8bc6\u3002\u5982\u679c\u8981\u4f7f\u7528 NA \u6765\u66ff\u4ee3\u8fd9\u4e9b\u503c\uff0c\u53ef\u4ee5\u4f7f\u7528 replace \u65b9\u6cd5\u751f\u6210\u65b0\u7684Series\uff08\u9664\u975e\u4f20\u5165\u4e86 inplace=True \uff09 data = pd.Series([1., -999., 2., -999., -1000., 3.]) print(data) # 0 1.0 # 1 -999.0 # 2 2.0 # 3 -999.0 # 4 -1000.0 # 5 3.0 # dtype: float64 result = data.replace(-999, np.nan) print(result) # 0 1.0 # 1 NaN # 2 2.0 # 3 NaN # 4 -1000.0 # 5 3.0 # dtype: float64 \u8981\u5c06\u4e0d\u540c\u7684\u503c\u66ff\u6362\u4e3a\u4e0d\u540c\u7684\u503c\uff0c\u53ef\u4ee5\u4f20\u5165\u66ff\u4ee3\u503c\u7684\u5217\u8868 result = data.replace([-999, -1000], [np.nan, 0]) print(result) # 0 1.0 # 1 NaN # 2 2.0 # 3 NaN # 4 0.0 # 5 3.0 # dtype: float64 \u4e5f\u53ef\u4ee5\u4f20\u5165\u66ff\u4ee3\u503c\u7684\u5b57\u5178 result = data.replace({-999: np.nan, -1000: 0}) print(result) # 0 1.0 # 1 NaN # 2 2.0 # 3 NaN # 4 0.0 # 5 3.0 # dtype: float64","title":"\u66ff\u4ee3\u503c"},{"location":"python/DataAnalysis/ch04/#_9","text":"\u548cSeries\u4e2d\u503c\u66ff\u6362\u7c7b\u4f3c\uff0c\u53ef\u4ee5\u901a\u8fc7\u51fd\u6570\u6216\u6620\u5c04\u5bf9\u8f74\u6807\u7b7e\u8fdb\u884c\u7c7b\u4f3c\u7684\u8f6c\u6362\uff0c\u751f\u6210\u65b0\u7684\u4e14\u5e26\u6709\u4e0d\u540c\u6807\u7b7e\u7684\u5bf9\u8c61\u3002 data = pd.DataFrame( np.arange(12).reshape((3, 4)), index=['Ohio', 'Colorado', 'New York'], columns=['one', 'two', 'three', 'four'] ) print(data) # one two three four # Ohio 0 1 2 3 # Colorado 4 5 6 7 # New York 8 9 10 11 \u4e0eSeries\u7c7b\u4f3c\uff0c\u8f74\u7d22\u5f15\u4e5f\u6709\u4e00\u4e2a map \u65b9\u6cd5\u3002 transform = lambda x: x[:4].upper() # \u622a\u53d6index\u7684\u524d\u56db\u4f4d\u5e76\u8f6c\u5316\u4e3a\u5927\u5199\u683c\u5f0f result = data.index.map(transform) print(result) # Index(['OHIO', 'COLO', 'NEW '], dtype='object') \u8d4b\u503c\u7ed9 index \uff0c\u4fee\u6539DataFrame\u3002 data.index = data.index.map(transform) print(data) # one two three four # OHIO 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 \u521b\u5efa\u6570\u636e\u96c6\u8f6c\u6362\u540e\u7684\u7248\u672c\uff0c\u5e76\u4e14\u4e0d\u4fee\u6539\u539f\u6709\u7684\u6570\u636e\u96c6\uff0c\u4e00\u4e2a\u6709\u7528\u7684\u65b9\u6cd5\u662f rename \u3002 result = data.rename(index=str.title, columns=str.upper) print(result) # ONE TWO THREE FOUR # Ohio 0 1 2 3 # Colo 4 5 6 7 # New 8 9 10 11 print(data) # \u539f\u6709\u7684\u6570\u636e\u96c6\u672a\u88ab\u4fee\u6539 # one two three four # OHIO 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 rename \u53ef\u4ee5\u7ed3\u5408\u5b57\u5178\u578b\u5bf9\u8c61\u4f7f\u7528\uff0c\u4e3a\u8f74\u6807\u7b7e\u7684\u5b50\u96c6\u63d0\u4f9b\u65b0\u7684\u503c\u3002 result = data.rename(index={'OHIO': 'INDIANA'}, columns={'three': 'peekaboo'}) print(result) # one two peekaboo four # INDIANA 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11 \u5982\u679c\u8981\u4fee\u6539\u539f\u6709\u7684\u6570\u636e\u96c6\uff0c\u4f20\u5165 inplace=True \u3002 data.rename(index={'OHIO': 'INDIANA'}, columns={'three': 'peekaboo'}, inplace=True) print(data) # one two peekaboo four # INDIANA 0 1 2 3 # COLO 4 5 6 7 # NEW 8 9 10 11","title":"\u91cd\u547d\u540d\u8f74\u7d22\u5f15"},{"location":"python/DataAnalysis/ch04/#_10","text":"\u8fde\u7eed\u503c\u7ecf\u5e38\u9700\u8981\u79bb\u6563\u5316\uff0c\u6216\u8005\u5206\u79bb\u6210\u201d\u7bb1\u5b50\u201c\u8fdb\u884c\u5206\u6790\u3002 \u5047\u8bbe\u6709\u4e00\u7ec4\u4eba\u7fa4\u7684\u6570\u636e\uff0c\u60f3\u5c06\u4ed6\u4eec\u8fdb\u884c\u5206\u7ec4\uff0c\u653e\u5165\u79bb\u6563\u7684\u5e74\u9f84\u6846\u4e2d\u3002 ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32] \u5c06\u8fd9\u4e9b\u5e74\u9f84\u5206\u4e3a18\uff5e25\u300126\uff5e35\u300136\uff5e60\u4ee5\u53ca61\u53ca\u4ee5\u4e0a\u7b49\u82e5\u5e72\u7ec4\uff0c\u4f7f\u7528pandas\u4e2d\u7684 cut \u3002 bins = [18, 25, 35, 60, 100] cats = pd.cut(ages, bins) print(cats) # [(18, 25], (18, 25], (18, 25], (25, 35], (18, 25], ..., (25, 35], (60, 100], (35, 60], (35, 60], (25, 35]] # Length: 12 # Categories (4, interval[int64, right]): [(18, 25] < (25, 35] < (35, 60] < (60, 100]] pandas\u8fd4\u56de\u7684\u5bf9\u8c61\u662f\u4e00\u4e2a\u7279\u6b8a\u7684 Categorical \u5bf9\u8c61\u3002 \u4f60\u770b\u5230\u7684\u8f93\u51fa\u63cf\u8ff0\u4e86\u7531 pandas.cut \u8ba1\u7b97\u51fa\u7684\u7bb1\u3002 \u4f60\u53ef\u4ee5\u5c06\u5b83\u5f53\u4f5c\u4e00\u4e2a\u8868\u793a\u7bb1\u540d\u7684\u5b57\u7b26\u4e32\u6570\u7ec4\uff1b\u5b83\u5728\u5185\u90e8\u5305\u542b\u4e00\u4e2a categories \uff08\u7c7b\u522b\uff09\u6570\u7ec4\uff0c\u5b83\u6307\u5b9a\u4e86\u4e0d\u540c\u7684\u7c7b\u522b\u540d\u79f0\u4ee5\u53ca codes \u5c5e\u6027\u4e2d\u7684 ages \uff08\u5e74\u9f84\uff09\u6570\u636e\u6807\u7b7e\u3002 print(cats.categories) # \u56db\u4e2a\u533a\u95f4\u7ec4 # IntervalIndex([(18, 25], (25, 35], (35, 60], (60, 100]], dtype='interval[int64, right]') print(cats.codes) # 61\u5c81\u843d\u5728\u7b2c3\u7ec4\uff08\u7ec4\u7f16\u53f7\u4ece0\u5f00\u59cb\uff09 # [0 0 0 1 0 0 2 1 3 2 2 1] \u6ce8\u610f\uff0c pd.value_counts(cats) \u662f\u5bf9 pandas.cut \u7684\u7ed3\u679c\u4e2d\u7684\u7bb1\u6570\u91cf\u7684\u8ba1\u6570\u3002 result = pd.value_counts(cats) print(result) # (18, 25] 5 # (25, 35] 3 # (35, 60] 3 # (60, 100] 1 # dtype: int64 \u4e0e\u533a\u95f4\u7684\u6570\u5b66\u7b26\u53f7\u4e00\u81f4\uff0c\u5c0f\u62ec\u53f7\u8868\u793a\u8fb9\u662f\u5f00\u653e\u7684\uff0c\u4e2d\u62ec\u53f7\u8868\u793a\u5b83\u662f\u5c01\u95ed\u7684\uff08\u5305\u62ec\u8fb9\uff09\u3002\u53ef\u4ee5\u901a\u8fc7\u4f20\u9012 right=False \u6765\u6539\u53d8\u54ea\u4e00\u8fb9\u662f\u5c01\u95ed\u7684\u3002\u9ed8\u8ba4 right=True \u3002 result = pd.cut(ages, [18, 26, 36, 61, 100], right=False) print(result) # [[18, 26), [18, 26), [18, 26), [26, 36), [18, 26), ..., [26, 36), [61, 100), [36, 61), [36, 61), [26, 36)] # Length: 12 # Categories (4, interval[int64, left]): [[18, 26) < [26, 36) < [36, 61) < [61, 100)] \u901a\u8fc7\u5411 labels \u9009\u9879\u4f20\u9012\u4e00\u4e2a\u5217\u8868\u6216\u6570\u7ec4\u6765\u4f20\u5165\u81ea\u5b9a\u4e49\u7684\u7bb1\u540d\u3002 group_name = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior'] result = pd.cut(ages, bins, labels=group_name) print(result) # ['Youth', 'Youth', 'Youth', 'YoungAdult', 'Youth', ..., 'YoungAdult', 'Senior', 'MiddleAged', 'MiddleAged', 'YoungAdult'] # Length: 12 # Categories (4, object): ['Youth' < 'YoungAdult' < 'MiddleAged' < 'Senior'] result = pd.value_counts(pd.cut(ages, bins, labels=group_name)) # \u6807\u7b7e\u8f93\u51fa print(result) # Youth 5 # YoungAdult 3 # MiddleAged 3 # Senior 1 # dtype: int64 result = pd.value_counts(pd.cut(ages, bins)) # \u533a\u95f4\u8f93\u51fa print(result) # (18, 25] 5 # (25, 35] 3 # (35, 60] 3 # (60, 100] 1 # dtype: int64 \u5982\u679c\u4f20\u7ed9 cut \u6574\u6570\u4e2a\u7684\u7bb1\u6765\u4ee3\u66ff\u663e\u5f0f\u7684\u7bb1\u8fb9\uff0cpandas\u5c06\u6839\u636e\u6570\u636e\u4e2d\u7684\u6700\u5c0f\u503c\u548c\u6700\u5927\u503c\u8ba1\u7b97\u51fa\u7b49\u957f\u7684\u7bb1\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u8003\u8651\u4e00\u4e9b\u5747\u5300\u5206\u5e03\u7684\u6570\u636e\u88ab\u5207\u6210\u56db\u4efd\u7684\u60c5\u51b5\u3002 data = np.random.rand(20) result = pd.cut(data, 4, precision=2) # precision=2\u7684\u9009\u9879\u5c06\u5341\u8fdb\u5236\u7cbe\u5ea6\u9650\u5236\u5728\u4e24\u4f4d\u3002 print(result) # [(0.44, 0.66], (0.0063, 0.23], (0.23, 0.44], (0.0063, 0.23], (0.23, 0.44], ..., (0.23, 0.44], (0.0063, 0.23], (0.23, 0.44], (0.66, 0.88], (0.23, 0.44]] # Length: 20 # Categories (4, interval[float64, right]): [(0.0063, 0.23] < (0.23, 0.44] < (0.44, 0.66] < (0.66, 0.88]] qcut \u662f\u4e00\u4e2a\u4e0e\u5206\u7bb1\u5bc6\u5207\u76f8\u5173\u7684\u51fd\u6570\uff0c\u5b83\u57fa\u4e8e\u6837\u672c\u5206\u4f4d\u6570\u8fdb\u884c\u5206\u7bb1\u3002 \u53d6\u51b3\u4e8e\u6570\u636e\u7684\u5206\u5e03\uff0c\u4f7f\u7528 cut \u901a\u5e38\u4e0d\u4f1a\u4f7f\u6bcf\u4e2a\u7bb1\u5177\u6709\u76f8\u540c\u6570\u636e\u91cf\u7684\u6570\u636e\u70b9\u3002 \u7531\u4e8eqcut\u4f7f\u7528\u6837\u672c\u7684\u5206\u4f4d\u6570\uff0c\u4f60\u53ef\u4ee5\u901a\u8fc7qcut\u83b7\u5f97\u7b49\u957f\u7684\u7bb1\u3002 data = np.random.randn(1000) # \u6b63\u6001\u5206\u5e03 cats = pd.qcut(data, 4) # \u5207\u62104\u4efd print(cats) # [(-0.00329, 0.644], (-0.00329, 0.644], (-0.659, -0.00329], (-0.659, -0.00329], (0.644, 3.468], ..., (0.644, 3.468], (-3.9619999999999997, -0.659], (-3.9619999999999997, -0.659], (-0.00329, 0.644], (-0.00329, 0.644]] # Length: 1000 # Categories (4, interval[float64, right]): [(-3.9619999999999997, -0.659] < (-0.659, -0.00329] < (-0.00329, 0.644] < (0.644, 3.468]] result = pd.value_counts(cats) print(result) # (-3.9619999999999997, -0.659] 250 # (-0.659, -0.00329] 250 # (-0.00329, 0.644] 250 # (0.644, 3.468] 250 # dtype: int64 \u4e0e cut \u7c7b\u4f3c\uff0c\u53ef\u4ee5\u4f20\u5165\u81ea\u5b9a\u4e49\u7684\u5206\u4f4d\u6570\uff080\u548c1\u4e4b\u95f4\u7684\u6570\u636e\uff0c\u5305\u62ec\u8fb9\uff09\u3002 result = pd.qcut(data, [0, 0.1, 0.5, 0.9, 1.]) print(result) # [(-0.00329, 1.234], (-0.00329, 1.234], (-1.321, -0.00329], (-1.321, -0.00329], (-0.00329, 1.234], ..., (-0.00329, 1.234], (-1.321, -0.00329], (-1.321, -0.00329], (-0.00329, 1.234], (-0.00329, 1.234]] # Length: 1000 # Categories (4, interval[float64, right]): [(-3.9619999999999997, -1.321] < (-1.321, -0.00329] < (-0.00329, 1.234] < (1.234, 3.468]]","title":"\u79bb\u6563\u5316\u548c\u5206\u7bb1"},{"location":"python/DataAnalysis/ch04/#_11","text":"\u8fc7\u6ee4\u6216\u8f6c\u6362\u5f02\u5e38\u503c\u5728\u5f88\u5927\u7a0b\u5ea6\u4e0a\u662f\u5e94\u7528\u6570\u7ec4\u64cd\u4f5c\u7684\u4e8b\u60c5\u3002 \u8003\u8651\u4e00\u4e2a\u5177\u6709\u6b63\u6001\u5206\u5e03\u6570\u636e\u7684DataFrame\u3002 data = pd.DataFrame(np.random.randn(1000, 4)) print(data.describe()) # 0 1 2 3 # count 1000.000000 1000.000000 1000.000000 1000.000000 # mean 0.008124 -0.008050 -0.013403 -0.008261 # std 0.979236 0.992982 0.998819 1.038760 # min -3.231914 -3.441270 -3.345210 -4.320565 # 25% -0.634801 -0.599852 -0.656481 -0.677611 # 50% -0.033252 0.000060 -0.040634 -0.015463 # 75% 0.649340 0.644312 0.678101 0.683849 # max 3.292099 2.758754 2.911447 3.371729 \u627e\u51fa\u4e00\u5217\u4e2d\u7edd\u5bf9\u503c\u5927\u4e8e\u4e09\u7684\u503c\u3002 col = data[2] result = col[np.abs(col) > 3] print(result) # 519 -3.035355 # 536 -3.345210 # Name: 2, dtype: float64 \u9009\u51fa\u6240\u6709\u503c\u5927\u4e8e3\u6216\u5c0f\u4e8e-3\u7684\u884c\uff0c\u53ef\u4ee5\u5bf9\u5e03\u5c14\u503cDataFrame\u4f7f\u7528 any \u65b9\u6cd5\u3002 result = data[(np.abs(data) > 3).any(1)] print(result) # 0 1 2 3 # 116 -0.080907 -3.441270 -0.163263 0.392800 # 139 -1.294440 1.828397 1.178897 -3.469466 # 241 -0.486292 0.150443 0.264172 -3.013440 # 295 3.292099 -0.339284 0.732829 -0.475202 # 355 0.307577 -3.053322 0.967497 0.896363 # 359 3.264981 -1.172096 0.207622 -0.281803 # 519 -0.448987 1.623843 -3.035355 -0.436833 # 533 -1.022616 -0.212597 1.030969 3.371729 # 536 1.067598 -1.306839 -3.345210 0.620834 # 541 -0.952760 -2.157970 -0.403199 -4.320565 # 690 0.006821 -3.104117 0.484881 -0.132613 # 750 -3.231914 1.017712 0.070430 0.631447 # 771 -3.007622 0.257960 -0.118179 -1.283365 # 976 1.684760 -0.003295 -0.249843 3.169371 \u6839\u636e\u8fd9\u4e9b\u6807\u51c6\u6765\u8bbe\u7f6e\u6765\u9650\u5b9a\u503c\uff0c\u4e0b\u9762\u4ee3\u7801\u9650\u5236\u4e86-3\u52303\u4e4b\u95f4\u7684\u6570\u503c\u3002 \u8bed\u53e5 np.sign(data) \u6839\u636e\u6570\u636e\u4e2d\u7684\u503c\u7684\u6b63\u8d1f\u5206\u522b\u751f\u62101\u548c-1\u7684\u6570\u503c\u3002 result = data[(np.abs(data) > 3)] = np.sign(data) * 3 print(result.describe()) # 0 1 2 3 # count 1000.000000 1000.000000 1000.000000 1000.000000 # mean -0.036000 0.000000 -0.084000 -0.048000 # std 3.001285 3.001501 3.000324 3.001117 # min -3.000000 -3.000000 -3.000000 -3.000000 # 25% -3.000000 -3.000000 -3.000000 -3.000000 # 50% -3.000000 0.000000 -3.000000 -3.000000 # 75% 3.000000 3.000000 3.000000 3.000000 # max 3.000000 3.000000 3.000000 3.000000 print(result.head()) # 0 1 2 3 # 0 -3.0 3.0 -3.0 -3.0 # 1 -3.0 -3.0 -3.0 -3.0 # 2 3.0 3.0 -3.0 3.0 # 3 3.0 -3.0 3.0 -3.0 # 4 3.0 -3.0 -3.0 -3.0","title":"\u68c0\u6d4b\u548c\u8fc7\u6ee4\u5f02\u5e38\u503c"},{"location":"python/DataAnalysis/ch04/#_12","text":"\u4f7f\u7528 numpy.random.permutation \u5bf9DataFrame\u4e2d\u7684Series\u6216\u884c\u8fdb\u884c\u7f6e\u6362\uff08\u968f\u673a\u91cd\u6392\u5e8f\uff09\u3002 \u5728\u8c03\u7528 permutation \u65f6\u6839\u636e\u4f60\u60f3\u8981\u7684\u8f74\u957f\u5ea6\u53ef\u4ee5\u4ea7\u751f\u4e00\u4e2a\u8868\u793a\u65b0\u987a\u5e8f\u7684\u6574\u6570\u6570\u7ec4\u3002 df = pd.DataFrame(np.arange(5 * 4).reshape((5, 4))) sampler = np.random.permutation(5) print(sampler) # \u8fd4\u56dearray # [1 4 3 0 2] print(df) # 0 1 2 3 # 0 0 1 2 3 # 1 4 5 6 7 # 2 8 9 10 11 # 3 12 13 14 15 # 4 16 17 18 19 \u4e0a\u9762\u8fd4\u56de\u7684 sampler \u6574\u6570\u6570\u7ec4 [1 4 3 0 2] \u7528\u5728\u57fa\u4e8e iloc \u7684\u7d22\u5f15\u6216\u7b49\u4ef7\u7684 take \u51fd\u6570\u4e2d\uff0c\u91cd\u65b0\u6392\u5217\u884c\u987a\u5e8f\u3002 print(df.take(sampler)) # 0 1 2 3 # 1 4 5 6 7 # 4 16 17 18 19 # 3 12 13 14 15 # 0 0 1 2 3 # 2 8 9 10 11 \u9009\u51fa\u4e00\u4e2a\u4e0d\u542b\u6709\u66ff\u4ee3\u503c\u7684\u968f\u673a\u5b50\u96c6\uff0c\u53ef\u4ee5\u4f7f\u7528Series\u548cDataFrame\u7684 sample \u65b9\u6cd5\u3002 result = df.sample(n=3) print(result) # 0 1 2 3 # 0 0 1 2 3 # 2 8 9 10 11 # 1 4 5 6 7 \u8981\u751f\u6210\u4e00\u4e2a\u5e26\u6709\u66ff\u4ee3\u503c\u7684\u6837\u672c\uff08\u5141\u8bb8\u6709\u91cd\u590d\u9009\u62e9\uff09\uff0c\u5c06 replace=True \u4f20\u5165 sample \u65b9\u6cd5\u3002 choice = pd.Series([5, 7, -1, 6, 4]) draws = choice.sample(n=10, replace=True) print(choice) # 0 5 # 1 7 # 2 -1 # 3 6 # 4 4 # dtype: int64 print(draws) # 4 4 # 0 5 # 0 5 # 3 6 # 4 4 # 0 5 # 1 7 # 3 6 # 2 -1 # 0 5 # dtype: int64","title":"\u7f6e\u6362\u548c\u968f\u673a\u62bd\u6837"},{"location":"python/DataAnalysis/ch04/#_13","text":"\u5c06\u5206\u7c7b\u53d8\u91cf\u8f6c\u6362\u4e3a\u201c\u865a\u62df\u201d\u6216\u201c\u6307\u6807\u201d\u77e9\u9635\u662f\u53e6\u4e00\u79cd\u7528\u4e8e\u7edf\u8ba1\u5efa\u6a21\u6216\u673a\u5668\u5b66\u4e60\u7684\u8f6c\u6362\u64cd\u4f5c\u3002 \u5982\u679cDataFrame\u4e2d\u7684\u4e00\u5217\u6709 k \u4e2a\u4e0d\u540c\u7684\u503c\uff0c\u5219\u53ef\u4ee5\u884d\u751f\u4e00\u4e2a k \u5217\u7684\u503c\u4e3a 1 \u548c 0 \u7684\u77e9\u9635\u6216DataFrame\u3002 pandas\u6709\u4e00\u4e2aget_dummies\u51fd\u6570\u7528\u4e8e\u5b9e\u73b0\u8be5\u529f\u80fd\u3002 df = pd.DataFrame( { 'key': ['b', 'b', 'a', 'c', 'a', 'b'], 'data1': range(6) } ) print(df) # key data1 # 0 b 0 # 1 b 1 # 2 a 2 # 3 c 3 # 4 a 4 # 5 b 5 \u5728\u6307\u6807DataFrame\u7684\u5217\u4e0a\u52a0\u5165\u524d\u7f00\uff0c\u7136\u540e\u4e0e\u5176\u4ed6\u6570\u636e\u5408\u5e76\u3002\u5728 get_dummies \u65b9\u6cd5\u4e2d\u6709\u4e00\u4e2a\u524d\u7f00\u53c2\u6570\u7528\u4e8e\u5b9e\u73b0\u8be5\u529f\u80fd\u3002 \u901a\u8fc7 get_dummies \u65b9\u6cd5\uff0c\u628a\u4e0a\u9762 df \u6570\u636e\u6309\u7167 key \u8fdb\u884c\u4e86\u5206\u7ec4\uff0c\u5e76\u901a\u8fc7\u4e0d\u540c\u5217\u6765\u5c55\u73b0\u5206\u7ec4\u540e\u7684\u5bf9\u5e94\u5173\u7cfb\u3002\u4f8b\u5982\uff0c key \u5217\u7684 a \uff0c\u5bf9\u5e94\u503c 2 \u548c 4 \u3002 dummies = pd.get_dummies(df['key'], prefix='key') print(dummies) # key_a key_b key_c # 0 0 1 0 # 1 0 1 0 # 2 1 0 0 # 3 0 0 1 # 4 1 0 0 # 5 0 1 0 df_with_dummy = df[['data1']].join(dummies) print(df_with_dummy) # data1 key_a key_b key_c # 0 0 0 1 0 # 1 1 0 1 0 # 2 2 1 0 0 # 3 3 0 0 1 # 4 4 1 0 0 # 5 5 0 1 0 \u66f4\u4e3a\u590d\u6742\u7684\u60c5\u51b5\uff0cDataFrame\u4e2d\u7684\u4e00\u884c\u5c5e\u4e8e\u591a\u4e2a\u7c7b\u522b\u3002 \u4ee5MovieLens\u76841M\u6570\u636e\u96c6\u4e3a\u4f8b\u3002\u589e\u52a0\u53c2\u6570 encoding='unicode_escape' \u907f\u514d\u51fa\u73b0\u4e0b\u9762\u7684\u9519\u8bef\uff1a UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 3114: invalid continuation byte \u589e\u52a0\u53c2\u6570 engine='python' \u907f\u514d\u51fa\u73b0\u4e0b\u9762\u7684\u9519\u8bef\uff1a ParserWarning: Falling back to the 'python' engine because the 'c' engine does not support regex separators (separators > 1 char and different from '\\s+' are interpreted as regex); you can avoid this warning by specifying engine='python'. mnames = ['movie_id', 'title', 'genres'] movies = pd.read_table( '../datasets/movielens/movies.dat', sep='::', header=None, names=mnames, encoding='unicode_escape', engine='python' ) print(movies[:10]) # movie_id title genres # 0 1 Toy Story (1995) Animation|Children's|Comedy # 1 2 Jumanji (1995) Adventure|Children's|Fantasy # 2 3 Grumpier Old Men (1995) Comedy|Romance # 3 4 Waiting to Exhale (1995) Comedy|Drama # 4 5 Father of the Bride Part II (1995) Comedy # 5 6 Heat (1995) Action|Crime|Thriller # 6 7 Sabrina (1995) Comedy|Romance # 7 8 Tom and Huck (1995) Adventure|Children's # 8 9 Sudden Death (1995) Action # 9 10 GoldenEye (1995) Action|Adventure|Thriller \u4e3a\u6bcf\u4e2a\u7535\u5f71\u6d41\u6d3e\u6dfb\u52a0\u6307\u6807\u53d8\u91cf\u9700\u8981\u8fdb\u884c\u4e00\u4e9b\u6570\u636e\u5904\u7406\u3002 \u9996\u5148\uff0c\u6211\u4eec\u4ece\u6570\u636e\u96c6\u4e2d\u63d0\u53d6\u51fa\u6240\u6709\u4e0d\u540c\u7684\u6d41\u6d3e\u7684\u5217\u8868\u3002 all_genres = [] for x in movies.genres: all_genres.extend(x.split('|')) genres = pd.unique(all_genres) print(genres) # ['Animation' \"Children's\" 'Comedy' 'Adventure' 'Fantasy' 'Romance' 'Drama' # 'Action' 'Crime' 'Thriller' 'Horror' 'Sci-Fi' 'Documentary' 'War' # 'Musical' 'Mystery' 'Film-Noir' 'Western'] \u4f7f\u7528\u51680\u7684DataFrame\u662f\u6784\u5efa\u6307\u6807DataFrame\u7684\u4e00\u79cd\u65b9\u5f0f\u3002 zero_matrix = np.zeros((len(movies), len(genres))) dummies = pd.DataFrame(zero_matrix, columns=genres) print(zero_matrix) # [[0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.] # ... # [0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.] # [0. 0. 0. ... 0. 0. 0.]] print(dummies.head(n=10)) # Animation Children's Comedy ... Mystery Film-Noir Western # 0 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 1 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 2 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 3 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 4 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 5 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 6 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 7 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 8 0.0 0.0 0.0 ... 0.0 0.0 0.0 # 9 0.0 0.0 0.0 ... 0.0 0.0 0.0 # # [10 rows x 18 columns] \u904d\u5386\u6bcf\u4e00\u90e8\u7535\u5f71\uff0c\u5c06 dummies \u6bcf\u4e00\u884c\u7684\u6761\u76ee\u8bbe\u7f6e\u4e3a 1 \u3002\u4f7f\u7528 dummies.columns \u6765\u8ba1\u7b97\u6bcf\u4e00\u4e2a\u6d41\u6d3e\u7684\u5217\u6307\u6807\u3002 gen = movies.genres[0] print(gen.split('|')) # ['Animation', \"Children's\", 'Comedy'] result = dummies.columns.get_indexer(gen.split('|')) print(result) # [0 1 2] \u4f7f\u7528 .loc \u6839\u636e\u8fd9\u4e9b\u6307\u6807\u6765\u8bbe\u7f6e\u503c\u3002 for i, gen in enumerate(movies.genres): indices = dummies.columns.get_indexer(gen.split('|')) dummies.iloc[i, indices] = 1 \u5c06\u7ed3\u679c\u4e0e movies \u8fdb\u884c\u5408\u5e76\u3002 movies_windic = movies.join(dummies.add_prefix('Genre_')) print(movies_windic.iloc[0]) # movie_id 1 # title Toy Story (1995) # genres Animation|Children's|Comedy # Genre_Animation 1.0 # Genre_Children's 1.0 # Genre_Comedy 1.0 # Genre_Adventure 0.0 # Genre_Fantasy 0.0 # Genre_Romance 0.0 # Genre_Drama 0.0 # Genre_Action 0.0 # Genre_Crime 0.0 # Genre_Thriller 0.0 # Genre_Horror 0.0 # Genre_Sci-Fi 0.0 # Genre_Documentary 0.0 # Genre_War 0.0 # Genre_Musical 0.0 # Genre_Mystery 0.0 # Genre_Film-Noir 0.0 # Genre_Western 0.0 # Name: 0, dtype: object \u5bf9\u4e8e\u66f4\u5927\u7684\u6570\u636e\uff0c\u4e0a\u9762\u8fd9\u79cd\u4f7f\u7528\u591a\u6210\u5458\u6784\u5efa\u6307\u6807\u53d8\u91cf\u5e76\u4e0d\u662f\u7279\u522b\u5feb\u901f\u3002 \u66f4\u597d\u7684\u65b9\u6cd5\u662f\u5199\u4e00\u4e2a\u76f4\u63a5\u5c06\u6570\u636e\u5199\u4e3aNumPy\u6570\u7ec4\u7684\u5e95\u5c42\u51fd\u6570\uff0c\u7136\u540e\u5c06\u7ed3\u679c\u5c01\u88c5\u8fdbDataFrame\u3002 \u5c06 get_dummies \u4e0e cut \u7b49\u79bb\u6563\u5316\u51fd\u6570\u7ed3\u5408\u4f7f\u7528\u662f\u7edf\u8ba1\u5e94\u7528\u7684\u4e00\u4e2a\u6709\u7528\u65b9\u6cd5\u3002 np.random.seed(12345) # \u4f7f\u7528numpy.random.seed\u6765\u8bbe\u7f6e\u968f\u673a\u79cd\u5b50\u4ee5\u786e\u4fdd\u793a\u4f8b\u7684\u786e\u5b9a\u6027 values = np.random.rand(10) print(values) # [0.92961609 0.31637555 0.18391881 0.20456028 0.56772503 0.5955447 # 0.96451452 0.6531771 0.74890664 0.65356987] bins = [0, 0.2, 0.4, 0.6, 0.8, 1] result = pd.get_dummies(pd.cut(values, bins)) print(result) # (0.0, 0.2] (0.2, 0.4] (0.4, 0.6] (0.6, 0.8] (0.8, 1.0] # 0 0 0 0 0 1 # 1 0 1 0 0 0 # 2 1 0 0 0 0 # 3 0 1 0 0 0 # 4 0 0 1 0 0 # 5 0 0 1 0 0 # 6 0 0 0 0 1 # 7 0 0 0 1 0 # 8 0 0 0 1 0 # 9 0 0 0 1 0","title":"\u8ba1\u7b97\u6307\u6807/\u865a\u62df\u53d8\u91cf"},{"location":"python/DataAnalysis/ch04/#_14","text":"import re pandas\u5141\u8bb8\u5c06\u5b57\u7b26\u4e32\u548c\u6b63\u5219\u8868\u8fbe\u5f0f\u7b80\u6d01\u5730\u5e94\u7528\u5230\u6574\u4e2a\u6570\u636e\u6570\u7ec4\u4e0a\uff0c\u6b64\u5916\u8fd8\u80fd\u5904\u7406\u6570\u636e\u7f3a\u5931\u3002","title":"\u5b57\u7b26\u4e32\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch04/#_15","text":"\u5b57\u4e32\u62c6\u5206\u5408\u5e76\u65b9\u6cd5\u3002\u5728\u5f88\u591a\u5b57\u7b26\u4e32\u5904\u7406\u548c\u811a\u672c\u5e94\u7528\u4e2d\uff0c\u5185\u5efa\u7684\u5b57\u7b26\u4e32\u65b9\u6cd5\u662f\u8db3\u591f\u7684\u3002 \u4f8b\u5982\uff0c\u4e00\u4e2a\u9017\u53f7\u5206\u9694\u7684\u5b57\u7b26\u4e32\u53ef\u4ee5\u4f7f\u7528split\u65b9\u6cd5\u62c6\u5206\u6210\u591a\u5757\u3002 import numpy as np import pandas as pd val = 'a, b, guido' result = val.split(',') print(result) # ['a', ' b', ' guido'] count \uff1a\u8fd4\u56de\u5b50\u5b57\u7b26\u4e32\u5728\u5b57\u7b26\u4e32\u4e2d\u7684\u975e\u91cd\u53e0\u51fa\u73b0\u6b21\u6570\u3002 result = val.count(',') print(result) # 2 endswith \uff1a\u5982\u679c\u5b57\u7b26\u4e32\u4ee5\u540e\u7f00\u7ed3\u5c3e\u5219\u8fd4\u56de True \u3002 startswith \uff1a\u5982\u679c\u5b57\u7b26\u4e32\u4ee5\u540e\u7f00\u7ed3\u5c3e\u5219\u8fd4\u56de True \u3002 result = val.endswith('b') print(result) # False result = val.endswith('o') print(result) # True result = val.startswith('a') print(result) # True split \u5e38\u548c strip \u4e00\u8d77\u4f7f\u7528\uff0c\u7528\u4e8e\u6e05\u9664\u7a7a\u683c\uff08\u5305\u62ec\u6362\u884c\uff09\u3002 split \uff1a\u4f7f\u7528\u5206\u9694\u7b26\u8bb2\u5b57\u7b26\u4e32\u62c6\u5206\u6210\u5b50\u5b57\u7b26\u4e32\u7684\u5217\u8868\u3002 strip \uff0c rstrip \uff0c lstrip \uff1a\u4fee\u526a\u7a7a\u767d\uff0c\u5305\u62ec\u6362\u884c\u7b26\uff1b\u76f8\u5f53\u4e8e\u5bf9\u6bcf\u4e2a\u5143\u7d20\u8fdb\u884c x.strip() (\u4ee5\u53ca rstrip \uff0c lstrip )\u3002 pieces = [x.strip() for x in val.split(',')] print(pieces) # ['a', 'b', 'guido'] \u8fd9\u4e9b\u5b50\u5b57\u7b26\u4e32\u53ef\u4ee5\u4f7f\u7528\u52a0\u6cd5\u4e0e\u4e24\u4e2a\u5192\u53f7\u5206\u9694\u7b26\u8fde\u63a5\u5728\u4e00\u8d77\u3002 first, second, third = pieces result = first + '::' + second + '::' + third print(result) # a::b::guido \u4f46\u662f\u8fd9\u5e76\u4e0d\u662f\u4e00\u4e2a\u5b9e\u7528\u7684\u901a\u7528\u65b9\u6cd5\u3002 \u5728\u5b57\u7b26\u4e32 ': :' \u7684 join \u65b9\u6cd5\u4e2d\u4f20\u5165\u4e00\u4e2a\u5217\u8868\u6216\u5143\u7ec4\u662f\u4e00\u79cd\u66f4\u5feb\u4e14\u66f4\u52a0Pythonic\uff08Python\u98ce\u683c\u5316\uff09\u7684\u65b9\u6cd5\u3002 join : \u4f7f\u7528\u5b57\u7b26\u4e32\u5ea7\u4f4d\u95f4\u9694\u7b26\uff0c\u7528\u4e8e\u7c98\u5408\u5176\u4ed6\u5b57\u7b26\u4e32\u7684\u5e8f\u5217\u3002 result = '::'.join(pieces) print(result) # a::b::guido \u5b9a\u4f4d\u5b50\u5b57\u7b26\u4e32\u7684\u65b9\u6cd5\u3002 \u4f7f\u7528Python\u7684 in \u5173\u952e\u5b57\u662f\u68c0\u6d4b\u5b50\u5b57\u7b26\u4e32\u7684\u6700\u4f73\u65b9\u6cd5\uff0c\u5c3d\u7ba1 index \u548c find \u4e5f\u80fd\u5b9e\u73b0\u540c\u6837\u7684\u529f\u80fd\u3002 result = 'guido' in val print(result) # True index \uff1a\u5982\u679c\u5728\u5b57\u7b26\u4e32\u4e2d\u627e\u5230\uff0c\u5219\u8fd4\u56de\u5b50\u5b57\u7b26\u4e32\u4e2d\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u627e\u4e0d\u5230\u5219\u89e6\u53d1\u4e00\u4e2a ValueError \u3002 find \uff1a\u8fd4\u56de\u5b57\u7b26\u4e32\u4e2d\u7b2c\u4e00\u4e2a\u51fa\u73b0\u5b50\u5b57\u7b26\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u4f4d\u7f6e\uff0c\u7c7b\u4f3c index \uff0c\u5982\u679c\u6ca1\u6709\u627e\u5230\uff0c\u5219\u8fd4\u56de -1 \u3002 rfind \uff1a\u8fd4\u56de\u5b57\u7b26\u4e32\u4e2d\u5b50\u5b57\u7b26\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u65f6\u7b2c\u4e00\u4e2a\u5b57\u7b26\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u627e\u5230\uff0c\u5219\u8fd4\u56de -1 \u3002 result = val.index(',') print(result) # 1 result = val.find(',') print(result) # 1 # result = val.index(':') print(result) # ValueError: substring not found result = val.find(':') print(result) # -1 result = val.rfind(',') print(result) # 4 replace \u5c06\u7528\u4e00\u79cd\u6a21\u5f0f\u66ff\u4ee3\u53e6\u4e00\u79cd\u6a21\u5f0f\u3002\u5b83\u4e5f\u7528\u4e8e\u4f20\u5165\u7a7a\u5b57\u7b26\u4e32\u6765\u5220\u9664\u67d0\u4e2a\u6a21\u5f0f\u3002 result = val.replace(',', '::') print(result) # a:: b:: guido result = val.replace(', ', '') print(result) # abguido result = val.replace(',', '') print(result) # a b guido lower \uff1a\u5c06\u5927\u5199\u5b57\u6bcd\u8f6c\u6362\u4e3a\u5c0f\u5199\u5b57\u6bcd\u3002 upper \uff1a\u5c06\u5c0f\u5199\u5b57\u6bcd\u8f6c\u6362\u4e3a\u5927\u5199\u5b57\u6bcd\u3002 uppers = val.upper() print(uppers) # A, B, GUIDO casefold \uff1a\u548c lower \u7c7b\u4f3c\uff0c\u5c06\u5b57\u7b26\u4e32\u4e2d\u7684\u5143\u7d20\u53d8\u6210\u5c0f\u5199\uff0c lower \u51fd\u6570\u53ea\u652f\u6301 ascill \u8868\u4e2d\u7684\u5b57\u7b26\uff0c casefold \u652f\u6301\u5f88\u591a\u4e0d\u540c\u79cd\u7c7b\u7684\u8bed\u8a00\u3002 str1 = \"Jan Wei\u03b2@cN\u4e0a\u6d77\" result = str1.casefold() print(result) # jan wei\u03b2@cn\u4e0a\u6d77 result = str1.lower() print(result) # jan wei\u03b2@cn\u4e0a\u6d77 ljust \uff0c rjust \uff1a\u5de6\u5bf9\u9f50\u6216\u8005\u53f3\u5bf9\u9f50\uff1b\u7528\u7a7a\u683c\u6216\u8005\u5176\u5b83\u4e00\u4e9b\u5b57\u7b26\u586b\u5145\u5b57\u7b26\u4e32\u7684\u76f8\u53cd\u4fa7\uff0c\u4ee5\u8fd4\u56de\u5177\u6709\u6700\u5c0f\u5bbd\u5ea6\u7684\u5b57\u7b26\u4e32 str1 = 'https://docs.python.org/3/' str2 = 'https://packagehub.suse.com/package-categories/python/' print(str1.ljust(60, '*')) print(str2.ljust(60, '*')) # https://docs.python.org/3/********************************** # https://packagehub.suse.com/package-categories/python/****** print(str1.rjust(60, '*')) print(str2.rjust(60, '*')) # **********************************https://docs.python.org/3/ # ******https://packagehub.suse.com/package-categories/python/ print(str1.rjust(60)) print(str2.rjust(60))","title":"\u5b57\u7b26\u4e32\u5bf9\u8c61\u65b9\u6cd5"},{"location":"python/DataAnalysis/ch04/#_16","text":"Python\u5185\u5efa\u7684 re \u6a21\u5757\u662f\u7528\u4e8e\u5c06\u6b63\u5219\u8868\u8fbe\u5f0f\u5e94\u7528\u5230\u5b57\u7b26\u4e32\u4e0a\u7684\u5e93\u3002 re \u6a21\u5757\u4e3b\u8981\u6709\u4e09\u4e2a\u4e3b\u9898\uff1a\u6a21\u5f0f\u5339\u914d\u3001\u66ff\u4ee3\u3001\u62c6\u5206\u3002 \u770b\u4e00\u4e2a\u7b80\u5355\u7684\u793a\u4f8b\uff1a\u5047\u8bbe\u6211\u4eec\u60f3\u5c06\u542b\u6709\u591a\u79cd\u7a7a\u767d\u5b57\u7b26\uff08\u5236\u8868\u7b26\u3001\u7a7a\u683c\u3001\u6362\u884c\u7b26\uff09\u7684\u5b57\u7b26\u4e32\u62c6\u5206\u5f00\u3002 \u63cf\u8ff0\u4e00\u4e2a\u6216\u591a\u4e2a\u7a7a\u767d\u5b57\u7b26\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u662f \\s+ \u3002 \u5f53\u8c03\u7528 re.split('\\s+', text) \uff0c\u6b63\u5219\u8868\u8fbe\u5f0f\u9996\u5148\u4f1a\u88ab\u7f16\u8bd1\uff0c\u7136\u540e\u6b63\u5219\u8868\u8fbe\u5f0f\u7684 split \u65b9\u6cd5\u5728\u4f20\u5165\u6587\u672c\u4e0a\u88ab\u8c03\u7528\u3002 text = \"foo bar\\t baz \\tqux\" result = re.split('\\s+', text) print(result) # ['foo', 'bar', 'baz', 'qux'] \u53ef\u4ee5\u4f7f\u7528 re.compile \u81ea\u884c\u7f16\u8bd1\uff0c\u5f62\u6210\u4e00\u4e2a\u53ef\u590d\u7528\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u5bf9\u8c61\u3002 regex = re.compile('\\s+') result = regex.split(text) print(result) # ['foo', 'bar', 'baz', 'qux'] \u5982\u679c\u60f3\u83b7\u5f97\u7684\u662f\u4e00\u4e2a\u6240\u6709\u5339\u914d\u6b63\u5219\u8868\u8fbe\u5f0f\u7684\u6a21\u5f0f\u7684\u5217\u8868\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 findall \u65b9\u6cd5\u3002 result = regex.findall(text) print(result) # [' ', '\\t ', ' \\t'] \u4e3a\u4e86\u5728\u6b63\u5219\u8868\u8fbe\u5f0f\u4e2d\u907f\u514d\u8f6c\u4e49\u7b26 \\ \u7684\u5f71\u54cd\uff0c\u53ef\u4ee5\u4f7f\u7528\u539f\u751f\u5b57\u7b26\u4e32\u8bed\u6cd5\uff0c\u6bd4\u5982 r'C:\\x' \u6216\u8005\u7528\u7b49\u4ef7\u7684 'C:\\\\x'\\ \u3002 \u5982\u679c\u9700\u8981\u5c06\u76f8\u540c\u7684\u8868\u8fbe\u5f0f\u5e94\u7528\u5230\u591a\u4e2a\u5b57\u7b26\u4e32\u4e0a\uff0c\u63a8\u8350\u4f7f\u7528 re.compile \u521b\u5efa\u4e00\u4e2a\u6b63\u5219\u8868\u8fbe\u5f0f\u5bf9\u8c61\uff0c\u8fd9\u6837\u505a\u6709\u5229\u4e8e\u8282\u7ea6CPU\u5468\u671f\u3002 match \u548c search \u4e0e findall \u76f8\u5173\u6027\u5f88\u5927\u3002 findall \u8fd4\u56de\u7684\u662f\u5b57\u7b26\u4e32\u4e2d\u6240\u6709\u7684\u5339\u914d\u9879\uff0c\u800c search \u8fd4\u56de\u7684\u4ec5\u4ec5\u662f\u7b2c\u4e00\u4e2a\u5339\u914d\u9879\u3002 match \u66f4\u4e3a\u4e25\u683c\uff0c\u5b83\u53ea\u5728\u5b57\u7b26\u4e32\u7684\u8d77\u59cb\u4f4d\u7f6e\u8fdb\u884c\u5339\u914d\u3002 text = \"\"\"Dave dave@google.com Steve steve@gmail.com Rob rob@gmail.com Ryan ryan@yahoo.com \"\"\" pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}' regex = re.compile(pattern, flags=re.IGNORECASE) # flags=re.IGNORECASE \u4f7f\u6b63\u5219\u8868\u8fbe\u5f0f\u4e0d\u533a\u5206\u5927\u5c0f\u5199 m = regex.findall(text) # findall\u4f1a\u751f\u6210\u4e00\u4e2a\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u7684\u5217\u8868 print(m) # ['dave@google.com', 'steve@gmail.com', 'rob@gmail.com', 'ryan@yahoo.com'] search \u8fd4\u56de\u7684\u662f\u6587\u672c\u4e2d\u7b2c\u4e00\u4e2a\u5339\u914d\u5230\u7684\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u3002 \u5bf9\u4e8e\u524d\u9762\u63d0\u5230\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\uff0c\u5339\u914d\u5bf9\u8c61\u53ea\u80fd\u544a\u8bc9\u6211\u4eec\u6a21\u5f0f\u5728\u5b57\u7b26\u4e32\u4e2d\u8d77\u59cb\u548c\u7ed3\u675f\u7684\u4f4d\u7f6e\u3002 m = regex.search(text) print(m) # print(text[m.start():m.end()]) # dave@google.com regex.match \u53ea\u5728\u6a21\u5f0f\u51fa\u73b0\u4e8e\u5b57\u7b26\u4e32\u8d77\u59cb\u4f4d\u7f6e\u65f6\u8fdb\u884c\u5339\u914d\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u5230\uff0c\u8fd4\u56de None \u3002 m = regex.match(text) print(m) # None m = regex.match('rob@gmail.com') print(m) # print(m.group()) # rob@gmail.com print(m.groups()) # () regex.sub \u4f1a\u8fd4\u56de\u4e00\u4e2a\u65b0\u7684\u5b57\u7b26\u4e32\uff0c\u539f\u5b57\u7b26\u4e32\u4e2d\u7684\u6a21\u5f0f\u4f1a\u88ab\u4e00\u4e2a\u65b0\u7684\u5b57\u7b26\u4e32\u66ff\u4ee3\u3002 m = regex.sub('REDACTED', text) print(m) # Dave REDACTED # Steve REDACTED # Rob REDACTED # Ryan REDACTED \u67e5\u627e\u7535\u5b50\u90ae\u4ef6\u5730\u5740\uff0c\u5e76\u5c06\u6bcf\u4e2a\u5730\u5740\u5206\u4e3a\u4e09\u4e2a\u90e8\u5206\uff1a\u7528\u6237\u540d\uff0c\u57df\u540d\u548c\u57df\u540d\u540e\u7f00\u3002\u8981\u5b9e\u73b0\u8fd9\u4e00\u70b9\uff0c\u53ef\u4ee5\u7528\u62ec\u53f7\u5c06 pattern \u5305\u8d77\u6765\u3002 \u4fee\u6539\u540e\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u4ea7\u751f\u7684\u5339\u914d\u5bf9\u8c61\u7684 groups \u65b9\u6cd5\uff0c\u8fd4\u56de\u7684\u662f\u6a21\u5f0f\u7ec4\u4ef6\u7684\u5143\u7ec4\u3002 text = \"\"\"Dave dave@google.com Steve steve@gmail.com Rob rob@gmail.com Ryan ryan@yahoo.com \"\"\" pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\\.([A-Z]{2,4})' regex = re.compile(pattern, flags=re.IGNORECASE) m = regex.findall(text) # \u5f53pattern\u53ef\u4ee5\u5206\u7ec4\u65f6\uff0cfindall\u8fd4\u56de\u7684\u662f\u5305\u542b\u5143\u7ec4\u7684\u5217\u8868 print(m) # [('dave', 'google', 'com'), ('steve', 'gmail', 'com'), ('rob', 'gmail', 'com'), ('ryan', 'yahoo', 'com')] m = regex.search(text) print(m) # print(text[m.start():m.end()]) # dave@google.com m = regex.match('rob@gmail.com') print(m) # print(m.group()) # rob@gmail.com print(m.groups()) # ('rob', 'gmail', 'com') m = regex.sub('REDACTED', text) print(m) # Dave REDACTED # Steve REDACTED # Rob REDACTED # Ryan REDACTED m = regex.sub(r'Username: \\1, Domain: \\2, Suffix: \\3', text) print(m) # Dave Username: dave, Domain: google, Suffix: com # Steve Username: steve, Domain: gmail, Suffix: com # Rob Username: rob, Domain: gmail, Suffix: com # Ryan Username: ryan, Domain: yahoo, Suffix: com","title":"\u6b63\u5219\u8868\u8fbe\u5f0f"},{"location":"python/DataAnalysis/ch04/#pandas","text":"\u6e05\u7406\u6742\u4e71\u7684\u6570\u636e\u96c6\u7528\u4e8e\u5206\u6790\u901a\u5e38\u9700\u8981\u5927\u91cf\u7684\u5b57\u7b26\u4e32\u5904\u7406\u548c\u6b63\u5219\u5316\u3002 data = { 'Dave': 'dave@gmail.com', 'Steve': 'steve@gmail.com', 'Rob': 'rob@gmail.com', 'Wes': np.nan } data = pd.Series(data) print(data) # Dave dave@gmail.com # Steve steve@gmail.com # Rob rob@gmail.com # Wes NaN # dtype: object print(data.isnull()) # Dave False # Steve False # Rob False # Wes True # dtype: bool \u53ef\u4ee5\u4f7f\u7528 data.map \u5c06\u5b57\u7b26\u4e32\u548c\u6709\u6548\u7684\u6b63\u5219\u8868\u8fbe\u5f0f\u65b9\u6cd5\uff08\u4ee5 lambda \u6216\u5176\u4ed6\u51fd\u6570\u7684\u65b9\u5f0f\u4f20\u9012\uff09\u5e94\u7528\u5230\u6bcf\u4e2a\u503c\u4e0a\uff0c\u4f46\u662f\u5728 NA \uff08 null \uff09\u503c\u4e0a\u4f1a\u5931\u8d25\u3002 \u4e3a\u4e86\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\uff0cSeries\u6709\u9762\u5411\u6570\u7ec4\u7684\u65b9\u6cd5\u7528\u4e8e\u8df3\u8fc7 NA \u503c\u7684\u5b57\u7b26\u4e32\u64cd\u4f5c\u3002\u8fd9\u4e9b\u65b9\u6cd5\u901a\u8fc7Series\u7684 str \u5c5e\u6027\u8fdb\u884c\u8c03\u7528\u3002 \u4f8b\u5982\uff0c\u53ef\u4ee5\u901a\u8fc7 str.contains \u6765\u68c0\u67e5\u6bcf\u4e2a\u7535\u5b50\u90ae\u4ef6\u5730\u5740\u662f\u5426\u542b\u6709 'gmail' \u3002 m = data.str.contains('gmail') print(m) # Dave True # Steve True # Rob True # Wes NaN # dtype: object \u6b63\u5219\u8868\u8fbe\u5f0f\u4e5f\u53ef\u4ee5\u7ed3\u5408\u4efb\u610f\u7684 re \u6a21\u5757\u9009\u9879\u4f7f\u7528\uff0c\u4f8b\u5982 IGNORECASE \u3002 print(pattern) # ([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\\.([A-Z]{2,4}) m = data.str.findall(pattern, flags=re.IGNORECASE) print(m) # Dave [(dave, gmail, com)] # Steve [(steve, gmail, com)] # Rob [(rob, gmail, com)] # Wes NaN # dtype: object \u4f7f\u7528 str.get \u6216\u5728 str \u5c5e\u6027\u5185\u90e8\u7d22\u5f15\uff0c\u8fdb\u884c\u5411\u91cf\u5316\u7684\u5143\u7d20\u68c0\u7d22\u3002 m = data.str.match(pattern, flags=re.IGNORECASE) print(m) # Dave True # Steve True # Rob True # Wes NaN # dtype: object m = data.str.findall(pattern, flags=re.IGNORECASE) print(m.str.get(1)) # Dave NaN # Steve NaN # Rob NaN # Wes NaN # dtype: float64 print(m.str[0]) # Dave (dave, gmail, com) # Steve (steve, gmail, com) # Rob (rob, gmail, com) # Wes NaN # dtype: object \u4f7f\u7528\u5b57\u7b26\u4e32\u5207\u7247\u7684\u7c7b\u4f3c\u8bed\u6cd5\u8fdb\u884c\u5411\u91cf\u5316\u5207\u7247\u3002 print(data.str[:]) # Dave dave@gmail.com # Steve steve@gmail.com # Rob rob@gmail.com # Wes NaN # dtype: object print(data.str[:5]) # Dave dave@ # Steve steve # Rob rob@g # Wes NaN # dtype: object","title":"pandas\u4e2d\u7684\u5411\u91cf\u5316\u5b57\u7b26\u4e32\u51fd\u6570"},{"location":"python/DataAnalysis/ch05/","text":"\u6570\u636e\u89c4\u6574\uff1a\u8fde\u63a5\u3001\u8054\u5408\u4e0e\u91cd\u5851 \u00b6 \u5206\u5c42\u7d22\u5f15 \u00b6 import pandas as pd import numpy as np import re \u5206\u5c42\u7d22\u5f15\u662fpandas\u7684\u91cd\u8981\u7279\u6027\uff0c\u5141\u8bb8\u4f60\u5728\u4e00\u4e2a\u8f74\u5411\u4e0a\u62e5\u6709\u591a\u4e2a\uff08\u4e24\u4e2a\u6216\u4e24\u4e2a\u4ee5\u4e0a\uff09\u7d22\u5f15\u5c42\u7ea7\u3002 \u5206\u5c42\u7d22 import re \u5f15\u63d0\u4f9b\u4e86\u4e00\u79cd\u5728\u66f4\u4f4e\u7ef4\u5ea6\u7684\u5f62\u5f0f\u4e2d\u5904\u7406\u66f4\u9ad8\u7ef4\u5ea6\u6570\u636e\u7684\u65b9\u5f0f\u3002 Series\u7d22\u5f15\u5206\u5c42 \u00b6 data = pd.Series( np.random.randn(9), index=[['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'], [1, 2, 3, 1, 3, 1, 2, 2, 3]] ) \u8f93\u51fa\u662f\u4e00\u4e2a\u4ee5 MultiIndex \u4f5c\u4e3a\u7d22\u5f15\u7684Series\u7684\u7f8e\u5316\u89c6\u56fe\u3002 \u7d22\u5f15\u4e2d\u7684\"\u95f4\u9699\"\u8868\u793a\"\u76f4\u63a5\u4f7f\u7528\u4e0a\u9762\u7684\u6807\u7b7e\"\u3002 print(data) # a 1 0.163468 # 2 -1.525926 # 3 -0.210247 # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # d 2 0.034305 # 3 -0.896078 # dtype: float64 print(data.index) # MultiIndex([('a', 1), # ('a', 2), # ('a', 3), # ('b', 1), # ('b', 3), # ('c', 1), # ('c', 2), # ('d', 2), # ('d', 3)], # ) \u901a\u8fc7\u5206\u5c42\u7d22\u5f15\u5bf9\u8c61\uff0c\u4e5f\u53ef\u4ee5\u79f0\u4e3a\u90e8\u5206\u7d22\u5f15\uff0c\u53ef\u4ee5\u7b80\u6d01\u5730\u9009\u62e9\u51fa\u6570\u636e\u7684\u5b50\u96c6\u3002 m = data['b'] print(m) # 1 -0.956063 # 3 -1.839111 # dtype: float64 m = data['b': 'c'] print(m) # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # dtype: float64 m = data.loc[['b', 'c']] print(m) # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # dtype: float64 m = data.loc[:, 2] print(m) # a -1.525926 # c 0.595279 # d 0.034305 # dtype: float64 \u5206\u5c42\u7d22\u5f15\u5728\u91cd\u5851\u6570\u636e\u548c\u6570\u7ec4\u900f\u89c6\u8868\u7b49\u5206\u7ec4\u64cd\u4f5c\u4e2d\u626e\u6f14\u4e86\u91cd\u8981\u89d2\u8272\u3002 \u4f8b\u5982\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 unstack \u65b9\u6cd5\u5c06\u6570\u636e\u5728DataFrame\u4e2d\u91cd\u65b0\u6392\u5217\u3002 m = data.unstack() print(m) # 1 2 3 # a 0.163468 -1.525926 -0.210247 # b -0.956063 NaN -1.839111 # c -0.398905 0.595279 NaN # d NaN 0.034305 -0.896078 n = m.stack() print(n) # \u6216\u8005 print(data.unstack().stack()) # a 1 0.163468 # 2 -1.525926 # 3 -0.210247 # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # d 2 0.034305 # 3 -0.896078 # dtype: float64 DataFrame\u7d22\u5f15\u5206\u5c42 \u00b6 \u5728DataFrame\u4e2d\uff0c\u6bcf\u4e2a\u8f74\u90fd\u53ef\u4ee5\u62e5\u6709\u5206\u5c42\u7d22\u5f15\u3002 \u53c2\u8003 \u65b9\u6cd51\uff1a\u76f4\u63a5\u521b\u5efa \u00b6 \u76f4\u63a5\u901a\u8fc7\u7ed9 index \uff08columns\uff09\u53c2\u6570\u4f20\u9012\u591a\u7ef4\u6570\u7ec4\uff0c\u8fdb\u800c\u6784\u5efa\u591a\u7ef4\u7d22\u5f15\u3002 \u6570\u7ec4\u4e2d\u6bcf\u4e2a\u7ef4\u5ea6\u5bf9\u5e94\u4f4d\u7f6e\u7684\u5143\u7d20\uff0c\u7ec4\u6210\u6bcf\u4e2a\u7d22\u5f15\u503c\u3002 frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]], columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) print(frame) # Ohio Colorado # Green Red Green # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 \u4e0a\u9762\u8f93\u51fa\u4e2d\u76842\u4e2a\u5c42\u7ea7\u662f\u6ca1\u6709\u540d\u5b57\u3002 \u5206\u5c42\u7684\u5c42\u7ea7\u53ef\u4ee5\u6709\u540d\u79f0\uff08\u53ef\u4ee5\u662f\u5b57\u7b26\u4e32\u6216Python\u5bf9\u8c61\uff09\u3002 \u5982\u679c\u5c42\u7ea7\u6709\u540d\u79f0\uff0c\u8fd9\u4e9b\u540d\u79f0\u4f1a\u5728\u63a7\u5236\u53f0\u8f93\u51fa\u4e2d\u663e\u793a\u3002 print(frame.index.names) # [None, None] print(frame.columns.names) # [None, None] \u7ed9\u5c42\u7ea7\u8d4b\u4e88\u540d\u79f0\u3002\u6ce8\u610f\u533a\u5206\u884c\u6807\u7b7e\u4e2d\u7684\u7d22\u5f15\u540d\u79f0 state \u548c color \u3002 frame.index.names = ['key1', 'key2'] frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 print(frame['Ohio']) # color Green Red # key1 key2 # a 1 0 1 # 2 3 4 # b 1 6 7 # 2 9 10 print(frame.index) # MultiIndex([('a', 1), # ('a', 2), # ('b', 1), # ('b', 2)], # names=['key1', 'key2']) \u901a\u8fc7 MultiIndex \u7c7b\u7684\u76f8\u5173\u65b9\u6cd5\uff0c\u9884\u5148\u521b\u5efa\u4e00\u4e2a MultiIndex \u5bf9\u8c61\uff0c\u7136\u540e\u4f5c\u4e3aSeries\u4e0eDataFrame\u4e2d\u7684 index \uff08\u6216columns\uff09\u53c2\u6570\u503c\u3002\u540c\u65f6\uff0c\u53ef\u4ee5\u901a\u8fc7 names \u53c2\u6570\u6307\u5b9a\u591a\u5c42\u7d22\u5f15\u7684\u540d\u79f0\u3002 \u65b9\u6cd52\uff1afrom_arrays \u00b6 from_arrays \uff1a\u63a5\u6536\u4e00\u4e2a\u591a\u7ef4\u6570\u7ec4\u53c2\u6570\uff0c\u9ad8\u7ef4\u6307\u5b9a\u9ad8\u5c42\u7d22\u5f15\uff0c\u4f4e\u7ef4\u6307\u5b9a\u5e95\u5c42\u7d22\u5f15\u3002 mindex = pd.MultiIndex.from_arrays( [['a', 'a', 'b', 'b'], [1, 2, 1, 2]], names=['key1', 'key2'] ) frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=mindex, columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 \u65b9\u6cd53\uff1afrom_tuples \u00b6 from_tuples \uff1a\u63a5\u6536\u4e00\u4e2a\u5143\u7ec4\u7684\u5217\u8868\uff0c\u6bcf\u4e2a\u5143\u7ec4\u6307\u5b9a\u6bcf\u4e2a\u7d22\u5f15\uff08\u9ad8\u7ef4\u7d22\u5f15\uff0c\u4f4e\u7ef4\u7d22\u5f15\uff09\u3002 mindex = pd.MultiIndex.from_tuples( [('a', 1), ('a', 2), ('b', 1), ('b', 2)] ) frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=mindex, columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) frame.index.names = ['key1', 'key2'] frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 \u65b9\u6cd54\uff1afrom_product \u00b6 from_product \uff1a\u63a5\u6536\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u7684\u5217\u8868\uff0c\u6839\u636e\u591a\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u5143\u7d20\u7684\u7b1b\u5361\u5c14\u79ef\u8fdb\u884c\u521b\u5efa\u7d22\u5f15\u3002 \u4f7f\u7528\u7b1b\u5361\u5c14\u79ef\u7684\u65b9\u5f0f\u6765\u521b\u5efa\u591a\u5c42\u7d22\u5f15\u3002\u53c2\u6570\u4e3a\u5d4c\u5957\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002\u7ed3\u679c\u4e3a\u4f7f\u7528\u6bcf\u4e2a\u4e00\u7ef4\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u4e0e\u5176\u4ed6\u4e00\u7ef4\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u6765\u751f\u6210\u3002 \u7b1b\u5361\u5c14\u79ef\u7684\u65b9\u5f0f\u7684\u5c40\u9650\uff1a\u4e24\u4e24\u7ec4\u5408\u5fc5\u987b\u90fd\u5b58\u5728\uff0c\u5426\u5219\uff0c\u5c31\u4e0d\u80fd\u4f7f\u7528\u8fd9\u79cd\u65b9\u5f0f\u3002 mindex = pd.MultiIndex.from_product( [['a', 'b'], ['1', '2']], names=['key1', 'key2'] ) frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=mindex, columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 \u91cd\u6392\u5e8f\u548c\u5c42\u7ea7\u6392\u5e8f \u00b6 \u5982\u679c\u9700\u8981\u91cd\u65b0\u6392\u5217\u8f74\u4e0a\u7684\u5c42\u7ea7\u987a\u5e8f\uff0c\u6216\u8005\u6309\u7167\u7279\u5b9a\u5c42\u7ea7\u7684\u503c\u5bf9\u6570\u636e\u8fdb\u884c\u6392\u5e8f\uff0c \u53ef\u4ee5\u901a\u8fc7swaplevel\u63a5\u6536\u4e24\u4e2a\u5c42\u7ea7\u5e8f\u53f7\u6216\u5c42\u7ea7\u540d\u79f0\uff0c\u8fd4\u56de\u4e00\u4e2a\u8fdb\u884c\u4e86\u5c42\u7ea7\u53d8\u66f4\u7684\u65b0\u5bf9\u8c61\uff08\u4f46\u662f\u6570\u636e\u662f\u4e0d\u53d8\u7684\uff09\u3002 print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 m = frame.swaplevel('key1', 'key2') print(m) # state Ohio Colorado # color Green Red Green # key2 key1 # 1 a 0 1 2 # 2 a 3 4 5 # 1 b 6 7 8 # 2 b 9 10 11 sort_index \u53ea\u80fd\u5728\u5355\u4e00\u5c42\u7ea7\u4e0a\u5bf9\u6570\u636e\u8fdb\u884c\u6392\u5e8f\u3002 \u5728\u8fdb\u884c\u5c42\u7ea7\u53d8\u6362\u65f6\uff0c\u4f7f\u7528 sort_index \u4ee5\u4f7f\u5f97\u7ed3\u679c\u6309\u7167\u5c42\u7ea7\u8fdb\u884c\u5b57\u5178\u6392\u5e8f\u3002 m = frame.sort_index(level=1) # \u5bf9key2\u6392\u5e8f\uff0c\u5e95\u5c42\u7d22\u5f15 print(m) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # b 1 6 7 8 # a 2 3 4 5 # b 2 9 10 11 m = frame.sort_index(level=0) # \u5bf9key1\u6392\u5e8f\uff0c\u9ad8\u5c42\u7d22\u5f15 print(m) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 m = frame.swaplevel(0, 1).sort_index(level=1) # swaplevel(0, 1)\u7b49\u540c\u4e8eswaplevel(key1, key2)\uff0c\u4ea4\u6362\u540ekey1\u53d8\u6210\u4e86\u5e95\u5c42\u7d22\u5f15 print(m) # state Ohio Colorado # color Green Red Green # key2 key1 # 1 a 0 1 2 # 2 a 3 4 5 # 1 b 6 7 8 # 2 b 9 10 11 \u6309\u5c42\u7ea7\u8fdb\u884c\u6c47\u603b\u7edf\u8ba1 \u00b6 DataFrame\u548cSeries\u4e2d\u5f88\u591a\u63cf\u8ff0\u6027\u548c\u6c47\u603b\u6027\u7edf\u8ba1\u6709\u4e00\u4e2a level \u9009\u9879\uff0c\u901a\u8fc7 level \u9009\u9879\u4f60\u53ef\u4ee5\u6307\u5b9a\u4f60\u60f3\u8981\u5728\u67d0\u4e2a\u7279\u5b9a\u7684\u8f74\u4e0a\u8fdb\u884c\u805a\u5408\u3002 print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 m = frame.groupby(level='key2').sum() print(m) # state Ohio Colorado # color Green Red Green # key2 # 1 6 8 10 # 2 12 14 16 m = frame.groupby(level='color', axis=1).sum() print(m) # color Green Red # key1 key2 # a 1 2 1 # 2 8 4 # b 1 14 7 # 2 20 10 \u4f7f\u7528DataFrame\u7684\u5217\u8fdb\u884c\u7d22\u5f15 \u00b6 \u901a\u5e38\u6211\u4eec\u4e0d\u4f1a\u4f7f\u7528DataFrame\u4e2d\u4e00\u4e2a\u6216\u591a\u4e2a\u5217\u4f5c\u4e3a\u884c\u7d22\u5f15\uff1b\u53cd\u800c\u4f60\u53ef\u80fd\u60f3\u8981\u5c06\u884c\u7d22\u5f15\u79fb\u52a8\u5230DataFrame\u7684\u5217\u4e2d\u3002 frame = pd.DataFrame( {'a': range(7), 'b': range(7, 0, -1), 'c': ['one', 'one', 'one', 'two', 'two', 'two', 'two'], 'd': [0, 1, 2, 0, 1, 2, 3] } ) print(frame) # a b c d # 0 0 7 one 0 # 1 1 6 one 1 # 2 2 5 one 2 # 3 3 4 two 0 # 4 4 3 two 1 # 5 5 2 two 2 # 6 6 1 two 3 DataFrame\u7684 set_index \u51fd\u6570\u4f1a\u751f\u6210\u4e00\u4e2a\u65b0\u7684DataFrame\uff0c\u65b0\u7684DataFrame\u4f7f\u7528\u4e00\u4e2a\u6216\u591a\u4e2a\u5217\u4f5c\u4e3a\u7d22\u5f15\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\u8fd9\u4e9b\u7d22\u5f15\u5217\u4f1a\u4eceDataFrame\u4e2d\u79fb\u9664\uff0c\u4e5f\u53ef\u4ee5\u5c06\u5b83\u4eec\u7559\u5728DataFrame\u4e2d\u3002 frame2 = frame.set_index(['c', 'd'], drop=False) print(frame2) # a b c d # c d # one 0 0 7 one 0 # 1 1 6 one 1 # 2 2 5 one 2 # two 0 3 4 two 0 # 1 4 3 two 1 # 2 5 2 two 2 # 3 6 1 two 3 frame2 = frame.set_index(['c', 'd']) print(frame2) # a b # c d # one 0 0 7 # 1 1 6 # 2 2 5 # two 0 3 4 # 1 4 3 # 2 5 2 # 3 6 1 reset_index \u662f set_index \u7684\u53cd\u64cd\u4f5c\uff0c\u5206\u5c42\u7d22\u5f15\u7684\u7d22\u5f15\u5c42\u7ea7\u4f1a\u88ab\u79fb\u52a8\u5230\u5217\u4e2d\u3002 \u6ce8\u610f\uff1a\u5982\u679c\u5728 set_index \u65f6\u4f7f\u7528\u4e86 drop=False \uff0c\u5728\u4f7f\u7528 reset_index \u4f1a\u62a5\u9519\u3002 m = frame2.reset_index() print(m) # c d a b # 0 one 0 0 7 # 1 one 1 1 6 # 2 one 2 2 5 # 3 two 0 3 4 # 4 two 1 4 3 # 5 two 2 5 2 # 6 two 3 6 1 \u8054\u5408\u4e0e\u5408\u5e76\u6570\u636e\u96c6 \u00b6 \u5305\u542b\u5728pandas\u5bf9\u8c61\u7684\u6570\u636e\u53ef\u4ee5\u901a\u8fc7\u591a\u79cd\u65b9\u5f0f\u8054\u5408\u5728\u4e00\u8d77\uff1a pandas.merge \u6839\u636e\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u5c06\u884c\u8fdb\u884c\u8fde\u63a5\u3002\u5bf9\u4e8eSQL\u6216\u5176\u4ed6\u5173\u7cfb\u578b\u6570\u636e\u5e93\u7684\u7528\u6237\u6765\u8bf4\uff0c\u8fd9\u79cd\u65b9\u5f0f\u6bd4\u8f83\u719f\u6089\uff0c\u5b83\u5b9e\u73b0\u7684\u662f\u6570\u636e\u5e93\u7684\u8fde\u63a5\u64cd\u4f5c\u3002 pandas.concat \u4f7f\u5bf9\u8c61\u5728\u8f74\u5411\u4e0a\u8fdb\u884c\u9ecf\u5408\u6216\u201c\u5806\u53e0\u201d\u3002 combine_first \u5b9e\u4f8b\u65b9\u6cd5\u5141\u8bb8\u5c06\u91cd\u53e0\u7684\u6570\u636e\u62fc\u63a5\u5728\u4e00\u8d77\uff0c\u4ee5\u4f7f\u7528\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u7684\u503c\u586b\u5145\u53e6\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u7684\u7f3a\u5931\u503c\u3002 \u6570\u636e\u5e93\u98ce\u683c\u7684DataFrame\u8fde\u63a5 \u00b6 \u5408\u5e76\u6216\u8fde\u63a5\u64cd\u4f5c\u901a\u8fc7\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u8fde\u63a5\u884c\u6765\u8054\u5408\u6570\u636e\u96c6\u3002 \u8fd9\u4e9b\u64cd\u4f5c\u662f\u5173\u7cfb\u578b\u6570\u636e\u5e93\u7684\u6838\u5fc3\u5185\u5bb9\uff08\u4f8b\u5982\u57fa\u4e8eSQL\u7684\u6570\u636e\u5e93\uff09\u3002 pandas\u4e2d\u7684 merge \u51fd\u6570\u4e3b\u8981\u7528\u4e8e\u5c06\u5404\u79cd join \u64cd\u4f5c\u7b97\u6cd5\u8fd0\u7528\u5728\u6570\u636e\u4e0a\u3002 \u5728\u8fdb\u884c\u5217-\u5217\u8fde\u63a5\u65f6\uff0c\u4f20\u9012\u7684DataFrame\u7d22\u5f15\u5bf9\u8c61\u4f1a\u88ab\u4e22\u5f03\u3002 \u5408\u5e76\u64cd\u4f5c\u4e5f\u8981\u8003\u8651\u5982\u4f55\u5904\u7406\u91cd\u53e0\u7684\u5217\u540d( suffixes \u540e\u7f00\u9009\u9879)\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u591a\u5bf9\u4e00\u8fde\u63a5\u7684\u4f8b\u5b50\u3002 df1 \u7684\u6570\u636e\u6709\u591a\u4e2a\u884c\u7684\u6807\u7b7e\u4e3a a \u548c b \uff0c\u800c df2 \u5728 key \u5217\u4e2d\u6bcf\u4e2a\u503c\u4ec5\u6709\u4e00\u884c\u3002 df1 = pd.DataFrame( { 'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7) } ) df2 = pd.DataFrame( { 'key': ['a', 'b', 'd'], 'data1': range(3) } ) print(df1) # key data1 # 0 b 0 # 1 b 1 # 2 a 2 # 3 c 3 # 4 a 4 # 5 a 5 # 6 b 6 print(df2) # key data1 # 0 a 0 # 1 b 1 # 2 d 2 \u8c03\u7528 merge \u5904\u7406\uff0c\u63a8\u8350\u663e\u5f0f\u5730\u6307\u5b9a\u8fde\u63a5\u952e\u3002 result = pd.merge(df1, df2) print(result) # key data1 # 0 b 1 result = pd.merge(df1, df2, on=['key', 'data1']) print(result) # key data1 # 0 b 1 result = pd.merge(df1, df2, on='key') print(result) # key data1_x data1_y # 0 b 0 1 # 1 b 1 1 # 2 b 6 1 # 3 a 2 0 # 4 a 4 0 # 5 a 5 0 \u5982\u679c\u6bcf\u4e2a\u5bf9\u8c61\u7684\u5217\u540d\u662f\u4e0d\u540c\u7684\uff0c\u53ef\u4ee5\u5206\u522b\u4e3a\u5b83\u4eec\u6307\u5b9a\u5217\u540d\u3002 df3 = pd.DataFrame( { 'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7) } ) df4 = pd.DataFrame( { 'rkey': ['a', 'b', 'd'], 'data2': range(3) } ) print(df3) # lkey data1 # 0 b 0 # 1 b 1 # 2 a 2 # 3 c 3 # 4 a 4 # 5 a 5 # 6 b 6 print(df4) # rkey data2 # 0 a 0 # 1 b 1 # 2 d 2 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c merge \u505a\u7684\u662f\u5185\u8fde\u63a5\uff08'inner' join\uff09\uff0c\u7ed3\u679c\u4e2d\u7684\u952e\u662f\u4e24\u5f20\u8868\u7684\u4ea4\u96c6\u3002 result = pd.merge(df3, df4, left_on='lkey', right_on='rkey') # df4\u7684[a,0]\u5bf9\u5e94df3\u7684\u6240\u6709[a,?]\u8bb0\u5f55\uff08\u901a\u8fc7\u91cd\u590d\u6765\u586b\u5145\u4e0d\u8db3\uff09 print(result) # lkey data1 rkey data2 # 0 b 0 b 1 # 1 b 1 b 1 # 2 b 6 b 1 # 3 a 2 a 0 # 4 a 4 a 0 # 5 a 5 a 0 \u5916\u8fde\u63a5\uff08outer join\uff09\u662f\u952e\u7684\u5e76\u96c6\uff0c\u8054\u5408\u4e86\u5de6\u8fde\u63a5\u548c\u53f3\u8fde\u63a5\u7684\u6548\u679c\u3002 \u591a\u5bf9\u591a\u8fde\u63a5\u662f\u884c\u7684\u7b1b\u5361\u5c14\u79ef\u3002 df1 = pd.DataFrame( { 'key': ['b', 'b', 'a', 'c', 'a', 'b'], 'data1': range(6) } ) df2 = pd.DataFrame( { 'key': ['a', 'b', 'a', 'b', 'd'], 'data2': range(5) } ) print(df1.sort_values(by='key')) # key data1 # 2 a 2 # 4 a 4 # 0 b 0 # 1 b 1 # 5 b 5 # 3 c 3 print(df2.sort_values(by='key')) # key data2 # 0 a 0 # 2 a 2 # 1 b 1 # 3 b 3 # 4 d 4 result = pd.merge(df1, df2, on='key', how='left') print(result.sort_values(by='key')) # key data1 data2 # 4 a 2 0.0 # 5 a 2 2.0 # 7 a 4 0.0 # 8 a 4 2.0 # 0 b 0 1.0 # 1 b 0 3.0 # 2 b 1 1.0 # 3 b 1 3.0 # 9 b 5 1.0 # 10 b 5 3.0 # 6 c 3 NaN result = pd.merge(df1, df2, on='key', how='outer') # \u591a\u5bf9\u591a\u8fde\u63a5 print(result.sort_values(by='key')) # key data1 data2 # 6 a 2.0 0.0 # 7 a 2.0 2.0 # 8 a 4.0 0.0 # 9 a 4.0 2.0 # 0 b 0.0 1.0 # 1 b 0.0 3.0 # 2 b 1.0 1.0 # 3 b 1.0 3.0 # 4 b 5.0 1.0 # 5 b 5.0 3.0 # 10 c 3.0 NaN # 11 d NaN 4.0 \u591a\u952e\u5408\u5e76\u3002 df1 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar'], 'key2': ['one', 'two', 'one'], 'lval': [1, 2, 3] } ) df2 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar', 'bar'], 'key2': ['one', 'one', 'one', 'two'], 'rval': [4, 5, 6, 7] } ) print(df1.sort_values(by=['key1', 'key2'])) # key1 key2 lval # 2 bar one 3 # 0 foo one 1 # 1 foo two 2 print(df2.sort_values(by=['key1', 'key2'])) # key1 key2 rval # 2 bar one 6 # 3 bar two 7 # 0 foo one 4 # 1 foo one 5 result = pd.merge(df1, df2, on=['key1', 'key2'], how='outer') print(result.sort_values(by=['key1', 'key2'])) # key1 key2 lval rval # 3 bar one 3.0 6.0 # 4 bar two NaN 7.0 # 0 foo one 1.0 4.0 # \u91cd\u590d\u586b\u5145 # 1 foo one 1.0 5.0 # \u91cd\u590d\u586b\u5145 # 2 foo two 2.0 NaN \u5904\u7406\u91cd\u53e0\u5217\u540d\u3002 result = pd.merge(df1, df2, on='key1') print(result.sort_values(by='key1')) # key1 key2_x lval key2_y rval # 4 bar one 3 one 6 # 5 bar one 3 two 7 # 0 foo one 1 one 4 # 1 foo one 1 one 5 # 2 foo two 2 one 4 # 3 foo two 2 one 5 result = pd.merge(df1, df2, on='key1', suffixes=('_left', '_right')) print(result.sort_values(by='key1')) # key1 key2_left lval key2_right rval # 4 bar one 3 one 6 # 5 bar one 3 two 7 # 0 foo one 1 one 4 # 1 foo one 1 one 5 # 2 foo two 2 one 4 # 3 foo two 2 one 5 \u6839\u636e\u7d22\u5f15\u5408\u5e76 \u00b6 \u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0cDataFrame\u4e2d\u7528\u4e8e\u5408\u5e76\u7684\u952e\u662f\u5b83\u7684\u7d22\u5f15\u3002\u53ef\u4ee5\u4f20\u9012 left_index=True \u6216 right_index=True \uff08\u6216\u8005\u90fd\u4f20\uff09\u6765\u8868\u793a\u7d22\u5f15\u9700\u8981\u7528\u6765\u4f5c\u4e3a\u5408\u5e76\u7684\u952e\u3002 df1 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar'], 'key2': ['one', 'two', 'one'], 'lval': [1, 2, 3] } ) df2 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar', 'bar'], 'key2': ['one', 'one', 'one', 'two'], 'rval': [4, 5, 6, 7] }, index=['foo', 'foo', 'bar', 'bar'] ) print(df1) # key1 key2 lval # 0 foo one 1 # 1 foo two 2 # 2 bar one 3 print(df2) # key1 key2 rval # foo foo one 4 # foo foo one 5 # bar bar one 6 # bar bar two 7 result = pd.merge(df1, df2, left_on='key1', right_index=True, suffixes=('_left', '_right')) print(result.sort_index()) # key1 key1_left key2_left lval key1_right key2_right rval # 0 foo foo one 1 foo one 4 # 0 foo foo one 1 foo one 5 # 1 foo foo two 2 foo one 4 # 1 foo foo two 2 foo one 5 # 2 bar bar one 3 bar one 6 # 2 bar bar one 3 bar two 7 result = pd.merge(df1, df2, left_on='key1', right_index=True, how='outer', suffixes=('_left', '_right')) # \u548c\u4e0a\u8ff0\u7ed3\u679c\u4e00\u6837 print(result.sort_index()) # key1 key1_left key2_left lval key1_right key2_right rval # 0 foo foo one 1 foo one 4 # 0 foo foo one 1 foo one 5 # 1 foo foo two 2 foo one 4 # 1 foo foo two 2 foo one 5 # 2 bar bar one 3 bar one 6 # 2 bar bar one 3 bar two 7 \u5728\u66f4\u590d\u6742\u591a\u5c42\u7d22\u5f15\u6570\u636e\u7684\u591a\u952e\u5408\u5e76\uff0c\u5728\u7d22\u5f15\u4e0a\u8fde\u63a5\u662f\u4e00\u4e2a\u9690\u5f0f\u7684\u591a\u952e\u5408\u5e76\u3002 \u5fc5\u987b\u4ee5\u5217\u8868\u7684\u65b9\u5f0f\u6307\u660e\u5408\u5e76\u6240\u9700\u591a\u4e2a\u5217\uff08\u6ce8\u610f\u4f7f\u7528 how='outer' \u5904\u7406\u91cd\u590d\u7684\u7d22\u5f15\u503c\uff09\u3002 df1 = pd.DataFrame( { 'key1': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'], 'key2': [2000, 2001, 2002, 2001, 2002], 'data': np.arange(5.) } ) df2 = pd.DataFrame( np.arange(12).reshape((6, 2)), index=[ ['Nevada', 'Nevada', 'Ohio', 'Ohio', 'Ohio', 'Ohio'], [2001, 2000, 2000, 2000, 2001, 2002] ], columns=['event1', 'event2'] ) print(df1) # key1 key2 data # 0 Ohio 2000 0.0 # 1 Ohio 2001 1.0 # 2 Ohio 2002 2.0 # 3 Nevada 2001 3.0 # 4 Nevada 2002 4.0 print(df2) # event1 event2 # Nevada 2001 0 1 # 2000 2 3 # Ohio 2000 4 5 # 2000 6 7 # 2001 8 9 # 2002 10 11 result = pd.merge(df1, df2, left_on=['key1', 'key2'], right_index=True) print(result) # key1 key2 data event1 event2 # 0 Ohio 2000 0.0 4 5 # 0 Ohio 2000 0.0 6 7 # 1 Ohio 2001 1.0 8 9 # 2 Ohio 2002 2.0 10 11 # 3 Nevada 2001 3.0 0 1 result = pd.merge(df1, df2, left_on=['key1', 'key2'], right_index=True, how='outer') print(result) # key1 key2 data event1 event2 # 0 Ohio 2000 0.0 4.0 5.0 # 0 Ohio 2000 0.0 6.0 7.0 # 1 Ohio 2001 1.0 8.0 9.0 # 2 Ohio 2002 2.0 10.0 11.0 # 3 Nevada 2001 3.0 0.0 1.0 # 4 Nevada 2002 4.0 NaN NaN # 4 Nevada 2000 NaN 2.0 3.0 \u4f7f\u7528\u4e24\u8fb9\u7684\u7d22\u5f15\u8fdb\u884c\u5408\u5e76\u4e5f\u662f\u53ef\u4ee5\u7684\uff0c\u524d\u63d0\u662f\u7528\u4e24\u8fb9\u7528\u6765\u5408\u5e76\u7684\u7d22\u5f15\u6709\u4ea4\u96c6\uff08\u516c\u5171\u90e8\u5206\uff09\u3002 \u5728\u4f7f\u7528 merge \u65f6\uff0c\u53c2\u6570 on=['key1', 'key2'] \u4e0d\u80fd\u548c left_index=True , right_index=True \u540c\u65f6\u5b58\u5728\u3002 \u5bf9\u4e8e\u91cd\u590d\u7d22\u5f15\uff0c\u5982\u679c\u503c\u4e0d\u540c\uff0c\u5219\u591a\u884c\u663e\u793a\uff0c\u548c\u6570\u636e\u5e93SQL\u7684 full join \u7c7b\u4f3c\u6982\u5ff5\u3002 \u5982\u679c\u51fa\u73b0\u76f8\u540c\u5217\u540d\uff0c\u5219\u4f1a\u81ea\u52a8\u6dfb\u52a0\u540e\u7f00\u5b57\u7b26\u4ee5\u793a\u533a\u522b\u3002 df1 = pd.DataFrame( [[1, 2], [3, 4], [5, 6]], index=['a', 'c', 'e'], columns=['Ohio', 'Nevada'] ) print(df1) # Ohio Nevada # a 1 2 # c 3 4 # e 5 6 df2 = pd.DataFrame( [[7, 8], [9, 10], [11, 12], [13, 14]], index=['b', 'c', 'c', 'e'], columns=['Missouri', 'Alabama'] ) print(df2) # Missouri Alabama # b 7 8 # c 9 10 # c 11 12 # e 13 14 df3 = pd.DataFrame( [[7, 8], [9, 10], [11, 12], [13, 14]], index=['a', 'c', 'e', 'f'], columns=['Nevada', 'Alabama'] ) print(df3) # Nevada Alabama # a 7 8 # c 9 10 # e 11 12 # f 13 14 result = pd.merge(df1, df2, left_index=True, right_index=True, how='outer') print(result) # Ohio Nevada Missouri Alabama # a 1.0 2.0 NaN NaN # b NaN NaN 7.0 8.0 # c 3.0 4.0 9.0 10.0 # c 3.0 4.0 11.0 12.0 # e 5.0 6.0 13.0 14.0 result = pd.merge(df1, df3, left_index=True, right_index=True, how='outer') print(result) # Ohio Nevada_x Nevada_y Alabama # a 1.0 2.0 7 8 # c 3.0 4.0 9 10 # e 5.0 6.0 11 12 # f NaN NaN 13 14 \u53e6\u4e00\u79cd\u5199\u6cd5\uff1a result = df1.join(df2, how='outer') print(result) # Ohio Nevada Missouri Alabama # a 1.0 2.0 NaN NaN # b NaN NaN 7.0 8.0 # c 3.0 4.0 9.0 10.0 # c 3.0 4.0 11.0 12.0 # e 5.0 6.0 13.0 14.0 \u4e5f\u53ef\u4ee5\u5411 join \u65b9\u6cd5\u4f20\u5165\u4e00\u4e2aDataFrame\u5217\u8868\uff0c\u7c7b\u4f3c\u4e8e\u5bf9\u4e09\u4e2a\u6570\u636e\u96c6\u8fdb\u884c join \u64cd\u4f5c\u3002 result = df1.join([df2, df3]) print(result) # Ohio Nevada_x Missouri Alabama_x Nevada_y Alabama_y # a 1 2 NaN NaN 7 8 # c 3 4 9.0 10.0 9 10 # c 3 4 11.0 12.0 9 10 # e 5 6 13.0 14.0 11 12 \u6cbf\u8f74\u5411\u8fde\u63a5 \u00b6 \u53e6\u4e00\u79cd\u6570\u636e\u7ec4\u5408\u64cd\u4f5c\u53ef\u79f0\u4e3a\u62fc\u63a5\u3001\u7ed1\u5b9a\u6216\u5806\u53e0\u3002NumPy\u7684 concatenate \u51fd\u6570\u53ef\u4ee5\u5728NumPy\u6570\u7ec4\u4e0a\u5b9e\u73b0\u8be5\u529f\u80fd\u3002 \u57fa\u4e8eSeries\u7684pandas\u7684 concat \u51fd\u6570\u7684\u5de5\u4f5c\u673a\u5236\u5206\u6790\u3002 \u4e0b\u9762\u4e09\u4e2a\u7d22\u5f15\u4e0d\u91cd\u53e0\u7684Series\u3002 s1 = pd.Series([0, 1], index=['a', 'b']) s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e']) s3 = pd.Series([5, 6], index=['f', 'g']) \u7528\u5217\u8868\u4e2d\u7684\u8fd9\u4e9b\u5bf9\u8c61\u8c03\u7528 concat \u65b9\u6cd5\u4f1a\u5c06\u503c\u548c\u7d22\u5f15\u7c98\u5728\u4e00\u8d77\uff1a \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c concat \u65b9\u6cd5\u662f\u6cbf\u7740 axis=0 \u7684\u8f74\u5411\u751f\u6548\u7684\uff0c\u751f\u6210\u53e6\u4e00\u4e2aSeries\u3002 \u5982\u679c\u4f20\u9012 axis=1 \uff0c\u8fd4\u56de\u7684\u7ed3\u679c\u5219\u662f\u4e00\u4e2aDataFrame\uff08 axis=1 \u65f6\u662f\u5217\uff09\u3002 result = pd.concat([s1, s2, s3]) print(result) # a 0 # b 1 # c 2 # d 3 # e 4 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s2, s3], keys=['one', 'two', 'three']) # \u901a\u8fc7keys\u53c2\u6570\uff0c\u5728\u8fde\u63a5\u8f74\u5411\u4e0a\u521b\u5efa\u4e00\u4e2a\u591a\u5c42\u7d22\u5f15\uff0c\u4ee5\u4fbf\u5728\u7ed3\u679c\u4e2d\u533a\u5206\u5404\u90e8\u5206 print(result) # one a 0 # b 1 # two c 2 # d 3 # e 4 # three f 5 # g 6 # dtype: int64 print(result.unstack()) # \u628a\u539f\u7d22\u5f15\u4f5c\u4e3a\u5217\u6807\u7b7e\u5c55\u5f00 # a b c d e f g # one 0.0 1.0 NaN NaN NaN NaN NaN # two NaN NaN 2.0 3.0 4.0 NaN NaN # three NaN NaN NaN NaN NaN 5.0 6.0 result = pd.concat([s1, s2, s3], axis=1) # \u5728\u8fd9\u4e2a\u6848\u4f8b\u4e2daxis=1\u8f74\u5411\u4e0a\u5e76\u6ca1\u6709\u91cd\u53e0 print(result) # 0 1 2 # a 0.0 NaN NaN # b 1.0 NaN NaN # c NaN 2.0 NaN # d NaN 3.0 NaN # e NaN 4.0 NaN # f NaN NaN 5.0 # g NaN NaN 6.0 result = pd.concat([s1, s2, s3], axis=1, keys=['one', 'two', 'three']) # \u5728\u8fd9\u4e2a\u6848\u4f8b\u4e2daxis=1\u8f74\u5411\u4e0a\u5e76\u6ca1\u6709\u91cd\u53e0 print(result) # one two three # a 0.0 NaN NaN # b 1.0 NaN NaN # c NaN 2.0 NaN # d NaN 3.0 NaN # e NaN 4.0 NaN # f NaN NaN 5.0 # g NaN NaN 6.0 print(result.unstack()) # \u5bf9\u6bd4axis=0\u7684\u591a\u5c42\u7d22\u5f15\uff0c\u5f53axis=1\u65f6\u5bf9\u8f93\u51fa\u5404index\u7684\u5e76\u96c6\u505a\u4e86\u5206\u7ec4\u3002 # one a 0.0 # b 1.0 # c NaN # d NaN # e NaN # f NaN # g NaN # two a NaN # b NaN # c 2.0 # d 3.0 # e 4.0 # f NaN # g NaN # three a NaN # b NaN # c NaN # d NaN # e NaN # f 5.0 # g 6.0 # dtype: float64 s4 = pd.concat([s1, s3]) print(s4) # a 0 # b 1 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s4]) print(result) # a 0 # b 1 # a 0 # b 1 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s4], axis=1) # \u73b0\u5728\u5728\u4e2daxis=1\u8f74\u5411\u4e0a\u6709\u91cd\u53e0 print(result) # 0 1 # a 0.0 0 # b 1.0 1 # f NaN 5 # g NaN 6 result = pd.concat([s1, s4], axis=1, keys=['one', 'two', 'three']) print(result) # one two # a 0.0 0 # b 1.0 1 # f NaN 5 # g NaN 6 result = pd.concat([s1, s4], axis=0, keys=['one', 'two', 'three']) # \u901a\u8fc7keys\u53c2\u6570\uff0c\u5728\u8fde\u63a5\u8f74\u5411\u4e0a\u521b\u5efa\u4e00\u4e2a\u591a\u5c42\u7d22\u5f15 print(result) # one a 0 # b 1 # two a 0 # b 1 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s4], axis=1, join='inner') # \u5185\u8fde\u63a5\u65b9\u5f0f\u5408\u5e76\u7d22\u5f15\uff08\u7d22\u5f15\u4ea4\u96c6\uff09 print(result) # 0 1 # a 0 0 # b 1 1 result = pd.concat([s1, s4], axis=1).reindex(['a', 'c', 'b', 'e']) # \u4f7f\u7528join_axes(\u5df2\u88ab\u66ff\u6362\u6210reindex)\u6765\u6307\u5b9a\u7528\u4e8e\u8fde\u63a5\u5176\u4ed6\u8f74\u5411\u7684\u8f74 print(result) # 0 1 # a 0.0 0.0 # c NaN NaN # b 1.0 1.0 # e NaN NaN \u57fa\u4e8eDataFrame\u7684pandas\u7684 concat \u51fd\u6570\u7684\u5de5\u4f5c\u673a\u5236\u5206\u6790\u3002 df1 = pd.DataFrame( np.arange(12).reshape((6, 2)), index=[ ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], [2000, 2001, 2002, 2000, 2001, 2002] ], columns=['event1', 'event2'] ) df2 = pd.DataFrame( np.arange(12).reshape((6, 2)), index=[ ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], [2000, 2001, 2002, 2000, 2001, 2002] ], columns=['event3', 'event4'] ) print(df1) # event1 event2 # Ohio 2000 0 1 # 2001 2 3 # 2002 4 5 # Nevada 2000 6 7 # 2001 8 9 # 2002 10 11 print(df2) # event3 event4 # Ohio 2000 0 1 # 2001 2 3 # 2002 4 5 # Nevada 2000 6 7 # 2001 8 9 # 2002 10 11 result = np.concatenate([df1, df2], axis=0) # \u6cbf0\u8f74\u62fc\u63a5 print(result) # [[ 0 1] # [ 2 3] # [ 4 5] # [ 6 7] # [ 8 9] # [10 11] # [ 0 1] # [ 2 3] # [ 4 5] # [ 6 7] # [ 8 9] # [10 11]] result = np.concatenate([df1, df2], axis=1) # \u6cbf1\u8f74\u62fc\u63a5 print(result) # [[ 0 1 0 1] # [ 2 3 2 3] # [ 4 5 4 5] # [ 6 7 6 7] # [ 8 9 8 9] # [10 11 10 11]] result = np.concatenate([df1, df2], axis=None) # \u5c06\u6570\u7ec4\u5c55\u5e73 print(result) # [ 0 1 2 3 4 5 6 7 8 9 10 11 0 1 2 3 4 5 6 7 8 9 10 11] \u8054\u5408\u91cd\u53e0\u6570\u636e \u00b6 \u53e6\u4e00\u4e2a\u6570\u636e\u8054\u5408\u573a\u666f\uff0c\u65e2\u4e0d\u662f\u5408\u5e76\u64cd\u4f5c\uff0c\u4e5f\u4e0d\u662f\u8fde\u63a5\u64cd\u4f5c\u3002 \u5047\u5982\u6709\u4e24\u4e2a\u6570\u636e\u96c6\uff0c\u8fd9\u4e24\u4e2a\u6570\u636e\u96c6\u7684\u7d22\u5f15\u5168\u90e8\u6216\u90e8\u5206\u91cd\u53e0\uff0c\u901a\u8fc7NumPy\u7684 where \u51fd\u6570\u53ef\u4ee5\u8fdb\u884c\u9762\u5411\u6570\u7ec4\u7684if-else\u7b49\u4ef7\u64cd\u4f5c\u3002 s1 = pd.Series( [np.nan, 2.5, 0.0, 3.5, 4.5, np.nan], index=['f', 'e', 'd', 'c', 'b', 'a'] ) s2 = pd.Series( [0.0, np.nan, 2.0, np.nan, np.nan, 5.0], index=['a', 'b', 'c', 'd', 'e', 'f'] ) print(s1) # f NaN # e 2.5 # d 0.0 # c 3.5 # b 4.5 # a NaN # dtype: float64 print(s2) # a 0.0 # b NaN # c 2.0 # d NaN # e NaN # f 5.0 # dtype: float64 \u65b9\u6cd51\uff0c\u901a\u8fc7Numpy\u7684 where \u51fd\u6570\u3002 result = np.where(pd.isnull(s1), s2, s1) # An array with elements from 'x'(s2) where 'condition'(isnull(s1)) is True, and elements from 'y'(s1) elsewhere. print(result) # [0. 2.5 0. 3.5 4.5 5. ] # s1 # s2 # result # f NaN # a 0.0 0. \u6761\u4ef6\u4e2ds1\u8be5\u5143\u7d20\u4e3anull\uff0c\u6240\u4ee5where\u51fd\u6570\u53d6\u5bf9\u5e94x(s2)\u7684\u5143\u7d20\uff08\u6ce8\u610f\uff0c\u4e0e\u7d22\u5f15\u987a\u5e8f\u65e0\u5173\uff09 # e 2.5 # b NaN 2.5 \u6761\u4ef6\u4e2ds1\u8be5\u5143\u7d20\u4e0d\u4e3anull\uff0c\u6240\u4ee5where\u51fd\u6570\u53d6\u5bf9\u5e94y(s1)\u7684\u5143\u7d20 # d 0.0 # c 2.0 0. # c 3.5 # d NaN 3.5 # b 4.5 # e NaN 4.5 # a NaN # f 5.0 5.0 \u6761\u4ef6\u4e2ds1\u8be5\u5143\u7d20\u4e3anull\uff0c\u6240\u4ee5where\u51fd\u6570\u53d6\u5bf9\u5e94x(s2)\u7684\u5143\u7d20 result = np.where(pd.isnull(s2), s1, s2) print(result) # [0. 2.5 2. 3.5 4.5 5. ] \u65b9\u6cd52\uff0c\u901a\u8fc7Series\u7684 combine_first \u65b9\u6cd5\u3002 result = s2.combine_first(s1) # \u6ce8\u610f\uff0ccombine_first\u662f\u6309\u7167s2\u7684\u7d22\u5f15\u987a\u5e8f\u68c0\u7d22\u7684\uff0c\u76f8\u540c\u7d22\u5f15\u7684s1\u7684\u503c\u4f1a\u586b\u5145\u5bf9\u5e94s2\u7684null print(result) # a 0.0 # b 4.5 # c 2.0 # d 0.0 # e 2.5 # f 5.0 # dtype: float64 \u65b9\u6cd53\uff1aPandas\u7684 combine_first \u65b9\u6cd5\u3002 df1 = pd.DataFrame( { 'a': [1.0, np.nan, 5.0, np.nan], 'b': [np.nan, 2.0, np.nan, 6.0], 'c': [2.0, 6.0, 10.0, 15.0] } ) df2 = pd.DataFrame( { 'a': [5.0, 4.0, np.nan, 3.0, 7.0], 'b': [np.nan, 3.0, 4.0, 6.0, 8.0] } ) print(df1) # a b c # 0 1.0 NaN 2.0 # 1 NaN 2.0 6.0 # 2 5.0 NaN 10.0 # 3 NaN 6.0 15.0 print(df2) # a b # 0 5.0 NaN # 1 4.0 3.0 # 2 NaN 4.0 # 3 3.0 6.0 # 4 7.0 8.0 result = df2.combine_first(df1) # \u7528df1\u7684\u503c\u53bb\u586b\u5145df2\u5bf9\u5e94\u7d22\u5f15\u4f4d\u7f6e\u7684null\u503c print(result) # a b c # 0 5.0 NaN 2.0 # 1 4.0 3.0 6.0 # 2 5.0 4.0 10.0 # 3 3.0 6.0 15.0 # 4 7.0 8.0 NaN \u91cd\u5851\u548c\u900f\u89c6 \u00b6 \u91cd\u65b0\u6392\u5217\u8868\u683c\u578b\u6570\u636e\u6709\u591a\u79cd\u57fa\u7840\u64cd\u4f5c\u3002\u8fd9\u4e9b\u64cd\u4f5c\u88ab\u79f0\u4e3a\u91cd\u5851\u6216\u900f\u89c6\u3002 import numpy as np import pandas as pd \u4f7f\u7528\u591a\u5c42\u7d22\u5f15\u8fdb\u884c\u91cd\u5851 \u00b6 \u591a\u5c42\u7d22\u5f15\u5728DataFrame\u4e2d\u63d0\u4f9b\u4e86\u4e00\u79cd\u4e00\u81f4\u6027\u65b9\u5f0f\u7528\u4e8e\u91cd\u6392\u5217\u6570\u636e\u3002\u4ee5\u4e0b\u662f\u4e24\u4e2a\u57fa\u7840\u64cd\u4f5c\uff1a statck\uff08\u5806\u53e0\uff09\u8be5\u64cd\u4f5c\u4f1a\u201c\u65cb\u8f6c\u201d\u6216\u5c06\u5217\u4e2d\u7684\u6570\u636e\u900f\u89c6\u5230\u884c\u3002 unstack\uff08\u62c6\u5806\uff09\u8be5\u64cd\u4f5c\u4f1a\u5c06\u884c\u4e2d\u7684\u6570\u636e\u900f\u89c6\u5230\u5217\u3002 df = pd.DataFrame( np.arange(6).reshape((2, 3)), index=pd.Index(['Ohio', 'Colorado'], name='state'), columns=pd.Index(['one', 'two', 'three'], name='number') ) print(df) # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 \u5728\u8fd9\u4efd\u6570\u636e\u4e0a\u4f7f\u7528stack\u65b9\u6cd5\u4f1a\u5c06\u5217\u900f\u89c6\u5230\u884c\uff0c\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684Series\uff1a result = df.stack() print(result) # state number # Ohio one 0 # two 1 # three 2 # Colorado one 3 # two 4 # three 5 # dtype: int64 \u4ece\u4e00\u4e2a\u591a\u5c42\u7d22\u5f15\u5e8f\u5217\u4e2d\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 unstack \u65b9\u6cd5\u5c06\u6570\u636e\u91cd\u6392\u5217\u540e\u653e\u5165\u4e00\u4e2aDataFrame\u4e2d\uff1a print(result.unstack()) # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 print(result.unstack(0)) # \u53ef\u4ee5\u4f20\u5165\u4e00\u4e2a\u5c42\u7ea7\u5e8f\u53f7\u6216\u540d\u79f0\u6765\u62c6\u5206\u4e00\u4e2a\u4e0d\u540c\u7684\u5c42\u7ea7 # state Ohio Colorado # number # one 0 3 # two 1 4 # three 2 5 print(result.unstack(1)) # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 print(result.unstack('state')) # \u8f93\u51fa\u7ed3\u679c\u548c\u4f20\u5165\u5c42\u7ea70\u4e00\u6837 # state Ohio Colorado # number # one 0 3 # two 1 4 # three 2 5 print(result.unstack('number')) # \u8f93\u51fa\u7ed3\u679c\u548c\u4f20\u5165\u5c42\u7ea71\u4e00\u6837 # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 \u5982\u679c\u5c42\u7ea7\u4e2d\u7684\u6240\u6709\u503c\u5e76\u672a\u5305\u542b\u4e8e\u6bcf\u4e2a\u5b50\u5206\u7ec4\u4e2d\u65f6\uff0c\u62c6\u5206\u53ef\u80fd\u4f1a\u5f15\u5165\u7f3a\u5931\u503c\uff1a s1 = pd.Series([0, 1, 2, 3], index=['a', 'b', 'c', 'd']) s2 = pd.Series([4, 5, 6], index=['c', 'd', 'e']) s3 = pd.concat([s1, s2], keys=['one', 'two']) print(s3) # one a 0 # b 1 # c 2 # d 3 # two c 4 # d 5 # e 6 # dtype: int64 print(s3.unstack(0)) # one two # a 0.0 NaN # b 1.0 NaN # c 2.0 4.0 # d 3.0 5.0 # e NaN 6.0 print(s3.unstack(1)) print(s3.unstack()) # a b c d e # one 0.0 1.0 2.0 3.0 NaN # two NaN NaN 4.0 5.0 6.0 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5806\u53e0\u4f1a\u8fc7\u6ee4\u51fa\u7f3a\u5931\u503c\uff0c\u56e0\u6b64\u5806\u53e0\u62c6\u5806\u7684\u64cd\u4f5c\u662f\u53ef\u9006\u7684\u3002 print(s3.unstack().stack()) # one a 0.0 # b 1.0 # c 2.0 # d 3.0 # two c 4.0 # d 5.0 # e 6.0 # dtype: float64 print(s3.unstack().stack(dropna=False)) # one a 0.0 # b 1.0 # c 2.0 # d 3.0 # e NaN # two a NaN # b NaN # c 4.0 # d 5.0 # e 6.0 # dtype: float64 \u5728DataFrame\u4e2d\u62c6\u5806\u65f6\uff0c\u88ab\u62c6\u5806\u7684\u5c42\u7ea7\u4f1a\u53d8\u4e3a\u7ed3\u679c\u4e2d\u6700\u4f4e\u7684\u5c42\u7ea7\u3002 \u5728\u8c03\u7528 stack \u65b9\u6cd5\u65f6\uff0c\u6211\u4eec\u53ef\u4ee5\u6307\u660e\u9700\u8981\u5806\u53e0\u7684\u8f74\u5411\u540d\u79f0\u3002 df = pd.DataFrame( {'left': result, 'right': result + 5}, columns=pd.Index(['left', 'right'], name='side') ) print(df) # side left right # state number # Ohio one 0 5 # two 1 6 # three 2 7 # Colorado one 3 8 # two 4 9 # three 5 10 print(df.unstack()) # side left right # number one two three one two three # state # Ohio 0 1 2 5 6 7 # Colorado 3 4 5 8 9 10 print(df.unstack('state')) # \u88ab\u62c6\u5806\u7684\u5c42\u7ea7(state)\u4f1a\u53d8\u4e3a\u7ed3\u679c\u4e2d\u6700\u4f4e\u7684\u5c42\u7ea7 # side left right # state Ohio Colorado Ohio Colorado # number # one 0 3 5 8 # two 1 4 6 9 # three 2 5 7 10 \u5728\u8c03\u7528 stack \u65b9\u6cd5\u65f6\uff0c\u53ef\u4ee5\u6307\u660e\u9700\u8981\u5806\u53e0\u7684\u8f74\u5411\u540d\u79f0\uff1a print(df.unstack('state').stack('side')) # state Colorado Ohio # number side # one left 3 0 # right 8 5 # two left 4 1 # right 9 6 # three left 5 2 # right 10 7 \u5c06\u201c\u957f\u201d\u900f\u89c6\u4e3a\u201c\u5bbd\u201d \u00b6 \u5728\u6570\u636e\u5e93\u548cCSV\u4e2d\u5b58\u50a8\u591a\u65f6\u95f4\u5e8f\u5217\u7684\u65b9\u5f0f\u5c31\u662f\u6240\u8c13\u7684\u957f\u683c\u5f0f\u6216\u5806\u53e0\u683c\u5f0f\u3002 data = pd.read_csv('../examples/macrodata.csv') print(data.head(3)) # year quarter realgdp realcons ... unemp pop infl realint # 0 1959.0 1.0 2710.349 1707.4 ... 5.8 177.146 0.00 0.00 # 1 1959.0 2.0 2778.801 1733.7 ... 5.1 177.830 2.34 0.74 # 2 1959.0 3.0 2775.488 1751.8 ... 5.3 178.657 2.74 1.09 # ...... # [3 rows x 14 columns] # PeriodIndex\u5c06year\u548cquarter\u7b49\u5217\u8fdb\u884c\u8054\u5408\u5e76\u751f\u6210\u4e86\u4e00\u79cd\u65f6\u95f4\u95f4\u9694\u7c7b\u578b periods = pd.PeriodIndex( year=data.year, quarter=data.quarter, name='date' ) columns = pd.Index( ['realgdp', 'infl', 'unemp'], name='item' ) data = data.reindex(columns=columns) print(data) # item realgdp infl unemp # 0 2710.349 0.00 5.8 # 1 2778.801 2.34 5.1 # 2 2775.488 2.74 5.3 # ...... # [203 rows x 3 columns] data.index = periods.to_timestamp('D', 'end') print(data.index) # DatetimeIndex(['1959-03-31 23:59:59.999999999', # '1959-06-30 23:59:59.999999999', # ... # '2009-06-30 23:59:59.999999999', # '2009-09-30 23:59:59.999999999'], # dtype='datetime64[ns]', name='date', length=203, freq=None) \u4e0b\u9762\u662fldata\u7684\u6570\u636e\u6837\u672c\u3002 \u8fd9\u79cd\u6570\u636e\u5373\u6240\u8c13\u7684\u591a\u65f6\u95f4\u5e8f\u5217\u7684\u957f\u683c\u5f0f\uff0c\u6216\u79f0\u4e3a\u5177\u6709\u4e24\u4e2a\u6216\u66f4\u591a\u4e2a\u952e\u7684\u5176\u4ed6\u89c2\u6d4b\u6570\u636e\uff08\u8fd9\u91cc\uff0c\u6211\u4eec\u7684\u952e\u662fdate\u548citem\uff09\u3002 \u8868\u4e2d\u7684\u6bcf\u4e00\u884c\u8868\u793a\u4e00\u4e2a\u65f6\u95f4\u70b9\u4e0a\u7684\u5355\u4e2a\u89c2\u6d4b\u503c\u3002 ldata = data.stack().reset_index().rename(columns={0: 'value'}) print(ldata) # date item value # 0 1959-03-31 23:59:59.999999999 realgdp 2710.349 # 1 1959-03-31 23:59:59.999999999 infl 0.000 # 2 1959-03-31 23:59:59.999999999 unemp 5.800 # 3 1959-06-30 23:59:59.999999999 realgdp 2778.801 # 4 1959-06-30 23:59:59.999999999 infl 2.340 # .. ... ... ... # 604 2009-06-30 23:59:59.999999999 infl 3.370 # 605 2009-06-30 23:59:59.999999999 unemp 9.200 # 606 2009-09-30 23:59:59.999999999 realgdp 12990.341 # 607 2009-09-30 23:59:59.999999999 infl 3.560 # 608 2009-09-30 23:59:59.999999999 unemp 9.600 # [609 rows x 3 columns] \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff1a \u6570\u636e\u901a\u5e38\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u5b58\u50a8\u5728\u5173\u7cfb\u578b\u6570\u636e\u5e93\u4e2d\uff0c\u6bd4\u5982MySQL\uff0c\u56e0\u4e3a\u56fa\u5b9a\u6a21\u5f0f\uff08\u5217\u540d\u79f0\u548c\u6570\u636e\u7c7b\u578b\uff09\u5141\u8bb8 item \u5217\u4e2d\u4e0d\u540c\u503c\u7684\u6570\u91cf\u968f\u7740\u6570\u636e\u88ab\u6dfb\u52a0\u5230\u8868\u4e2d\u800c\u6539\u53d8\u3002 date \u548c item \u901a\u5e38\u662f\u4e3b\u952e\uff08\u4f7f\u7528\u5173\u7cfb\u578b\u6570\u636e\u5e93\u7684\u8bf4\u6cd5\uff09\uff0c\u63d0\u4f9b\u4e86\u5173\u7cfb\u5b8c\u6574\u6027\u548c\u66f4\u7b80\u5355\u7684\u8fde\u63a5\u3002 \u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u5904\u7406\u8fd9\u79cd\u683c\u5f0f\u7684\u6570\u636e\u66f4\u4e3a\u56f0\u96be\u3002\u53ef\u80fd\u66f4\u503e\u5411\u4e8e\u83b7\u53d6\u4e00\u4e2a\u6309 date \u5217\u65f6\u95f4\u6233\u7d22\u5f15\u7684\u4e14\u6bcf\u4e2a\u4e0d\u540c\u7684 item \u72ec\u7acb\u4e00\u5217\u7684DataFrame\u3002 DataFrame\u7684pivot\u65b9\u6cd5\u5c31\u662f\u8fdb\u884c\u8fd9\u79cd\u8f6c\u6362\u7684\uff1a \u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c\u4f20\u9012\u7684\u524d\u4e24\u4e2a\u503c\u662f\u5206\u522b\u7528\u4f5c\u884c\u548c\u5217\u7d22\u5f15\u7684\u5217\uff0c\u7136\u540e\u662f\u53ef\u9009\u7684\u6570\u503c\u5217\u4ee5\u586b\u5145DataFrame\u3002 \u6ce8\u610f\uff0c pivot \u65b9\u6cd5\u7b49\u4ef7\u4e8e\u4f7f\u7528 set_index \u521b\u5efa\u5206\u5c42\u7d22\u5f15\uff0c\u7136\u540e\u8c03\u7528unstack\u3002 pivoted = ldata.pivot('date', 'item', 'value') print(pivoted) # item infl realgdp unemp # date # 1959-03-31 23:59:59.999999999 0.00 2710.349 5.8 # 1959-06-30 23:59:59.999999999 2.34 2778.801 5.1 # ... ... ... ... # 2009-06-30 23:59:59.999999999 3.37 12901.504 9.2 # 2009-09-30 23:59:59.999999999 3.56 12990.341 9.6 # [203 rows x 3 columns] ldata['value2'] = np.random.randn(len(ldata)) print(ldata[:5]) # date item value value2 # 0 1959-03-31 23:59:59.999999999 realgdp 2710.349 -1.268405 # 1 1959-03-31 23:59:59.999999999 infl 0.000 0.377691 # 2 1959-03-31 23:59:59.999999999 unemp 5.800 -0.342492 # 3 1959-06-30 23:59:59.999999999 realgdp 2778.801 0.132797 # 4 1959-06-30 23:59:59.999999999 infl 2.340 0.180290 \u6b64\u65f6 ldata \u5df2\u7ecf\u6dfb\u52a0\u4e86\u4e00\u5217\u3002\u5982\u679c\u9057\u6f0f\u6700\u540e\u4e00\u4e2a\u53c2\u6570\uff0c\u4f1a\u5f97\u5230\u4e00\u4e2a\u542b\u6709\u591a\u5c42\u5217\u7684DataFrame\uff0c\u5982\u4e0b\uff1a pivoted = ldata.pivot('date', 'item') print(pivoted) # value ... value2 # item infl realgdp ... realgdp unemp # date ... # 1959-03-31 23:59:59.999999999 0.00 2710.349 ... 0.157467 -0.222464 # 1959-06-30 23:59:59.999999999 2.34 2778.801 ... 0.861501 0.368855 # ... ... ... ... ... ... # 2009-06-30 23:59:59.999999999 3.37 12901.504 ... 0.279988 0.934972 # 2009-09-30 23:59:59.999999999 3.56 12990.341 ... 0.547914 1.842967 # [203 rows x 6 columns] \u6ce8\u610f\uff0c pivot \u65b9\u6cd5\u7b49\u4ef7\u4e8e\u4f7f\u7528 set_index \u521b\u5efa\u5206\u5c42\u7d22\u5f15\uff0c\u7136\u540e\u8c03\u7528 unstack \u3002 unstacked = ldata.set_index(['date', 'item']).unstack('item') print(unstacked[:5]) # value ... value2 # item infl realgdp ... realgdp unemp # date ... # 1959-03-31 23:59:59.999999999 0.00 2710.349 ... 0.213120 -0.248004 # 1959-06-30 23:59:59.999999999 2.34 2778.801 ... 0.697763 0.112388 # 1959-09-30 23:59:59.999999999 2.74 2775.488 ... 1.291884 -1.046142 # 1959-12-31 23:59:59.999999999 0.27 2785.204 ... 0.363339 -0.307364 # 1960-03-31 23:59:59.999999999 2.31 2847.699 ... 0.377330 2.272980 # [5 rows x 6 columns] \u5c06\u201c\u5bbd\u201d\u900f\u89c6\u4e3a\u201c\u957f\u201d \u00b6 \u5728DataFrame\u4e2d\uff0cpivot\u65b9\u6cd5\u7684\u53cd\u64cd\u4f5c\u662f pandas.melt \u3002 \u4e0e\u5c06\u4e00\u5217\u53d8\u6362\u4e3a\u65b0\u7684DataFrame\u4e2d\u7684\u591a\u5217\u4e0d\u540c\uff0c\u5b83\u5c06\u591a\u5217\u5408\u5e76\u6210\u4e00\u5217\uff0c\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684DataFrame\uff0c\u5176\u957f\u5ea6\u6bd4\u8f93\u5165\u66f4\u957f\u3002 df = pd.DataFrame( { 'key': ['foo', 'bar', 'baz'], 'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9] } ) print(df) # key A B C # 0 foo 1 4 7 # 1 bar 2 5 8 # 2 baz 3 6 9 key \u5217\u53ef\u4ee5\u4f5c\u4e3a\u5206\u7ec4\u6307\u6807\uff0c\u5176\u4ed6\u5217\u5747\u4e3a\u6570\u636e\u503c\u3002 \u5f53\u4f7f\u7528 pandas.melt \u65f6\uff0c\u6211\u4eec\u5fc5\u987b\u6307\u660e\u54ea\u4e9b\u5217\u662f\u5206\u7ec4\u6307\u6807\uff08\u5982\u679c\u6709\u7684\u8bdd\uff09\u3002 \u6b64\u5904\uff0c\u8ba9\u6211\u4eec\u4f7f\u7528 key \u4f5c\u4e3a\u552f\u4e00\u7684\u5206\u7ec4\u6307\u6807\uff1a melted = pd.melt(df, ['key']) print(melted) # key variable value # 0 foo A 1 # 1 bar A 2 # 2 baz A 3 # 3 foo B 4 # 4 bar B 5 # 5 baz B 6 # 6 foo C 7 # 7 bar C 8 # 8 baz C 9 \u4f7f\u7528 pivot \u65b9\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u6570\u636e\u91cd\u5851\u56de\u539f\u5148\u7684\u5e03\u5c40\u3002 reshaped = melted.pivot('key', 'variable', 'value') print(reshaped) # variable A B C # key # bar 2 5 8 # baz 3 6 9 # foo 1 4 7 \u7531\u4e8e pivot \u7684\u7ed3\u679c\u6839\u636e\u4f5c\u4e3a\u884c\u6807\u7b7e\u7684\u5217\u751f\u6210\u4e86\u7d22\u5f15\uff0c\u53ef\u4f7f\u7528 reset_index \u6765\u5c06\u6570\u636e\u56de\u79fb\u4e00\u5217\uff1a print(reshaped.reset_index()) # variable key A B C # 0 bar 2 5 8 # 1 baz 3 6 9 # 2 foo 1 4 7 pandas.melt \u7684\u4f7f\u7528\u4e5f\u53ef\u4ee5\u65e0\u987b\u4efb\u4f55\u5206\u7ec4\u6307\u6807\u3002 result = pd.melt(df, value_vars=['A', 'B', 'C']) print(result) # variable value # 0 A 1 # 1 A 2 # 2 A 3 # 3 B 4 # 4 B 5 # 5 B 6 # 6 C 7 # 7 C 8 # 8 C 9 result = pd.melt(df, value_vars=['key', 'B', 'C']) print(result) # variable value # 0 key foo # 1 key bar # 2 key baz # 3 B 4 # 4 B 5 # 5 B 6 # 6 C 7 # 7 C 8 # 8 C 9","title":"\u6570\u636e\u89c4\u6574\uff1a\u8fde\u63a5\u3001\u8054\u5408\u4e0e\u91cd\u5851"},{"location":"python/DataAnalysis/ch05/#_1","text":"","title":"\u6570\u636e\u89c4\u6574\uff1a\u8fde\u63a5\u3001\u8054\u5408\u4e0e\u91cd\u5851"},{"location":"python/DataAnalysis/ch05/#_2","text":"import pandas as pd import numpy as np import re \u5206\u5c42\u7d22\u5f15\u662fpandas\u7684\u91cd\u8981\u7279\u6027\uff0c\u5141\u8bb8\u4f60\u5728\u4e00\u4e2a\u8f74\u5411\u4e0a\u62e5\u6709\u591a\u4e2a\uff08\u4e24\u4e2a\u6216\u4e24\u4e2a\u4ee5\u4e0a\uff09\u7d22\u5f15\u5c42\u7ea7\u3002 \u5206\u5c42\u7d22 import re \u5f15\u63d0\u4f9b\u4e86\u4e00\u79cd\u5728\u66f4\u4f4e\u7ef4\u5ea6\u7684\u5f62\u5f0f\u4e2d\u5904\u7406\u66f4\u9ad8\u7ef4\u5ea6\u6570\u636e\u7684\u65b9\u5f0f\u3002","title":"\u5206\u5c42\u7d22\u5f15"},{"location":"python/DataAnalysis/ch05/#series","text":"data = pd.Series( np.random.randn(9), index=[['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'], [1, 2, 3, 1, 3, 1, 2, 2, 3]] ) \u8f93\u51fa\u662f\u4e00\u4e2a\u4ee5 MultiIndex \u4f5c\u4e3a\u7d22\u5f15\u7684Series\u7684\u7f8e\u5316\u89c6\u56fe\u3002 \u7d22\u5f15\u4e2d\u7684\"\u95f4\u9699\"\u8868\u793a\"\u76f4\u63a5\u4f7f\u7528\u4e0a\u9762\u7684\u6807\u7b7e\"\u3002 print(data) # a 1 0.163468 # 2 -1.525926 # 3 -0.210247 # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # d 2 0.034305 # 3 -0.896078 # dtype: float64 print(data.index) # MultiIndex([('a', 1), # ('a', 2), # ('a', 3), # ('b', 1), # ('b', 3), # ('c', 1), # ('c', 2), # ('d', 2), # ('d', 3)], # ) \u901a\u8fc7\u5206\u5c42\u7d22\u5f15\u5bf9\u8c61\uff0c\u4e5f\u53ef\u4ee5\u79f0\u4e3a\u90e8\u5206\u7d22\u5f15\uff0c\u53ef\u4ee5\u7b80\u6d01\u5730\u9009\u62e9\u51fa\u6570\u636e\u7684\u5b50\u96c6\u3002 m = data['b'] print(m) # 1 -0.956063 # 3 -1.839111 # dtype: float64 m = data['b': 'c'] print(m) # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # dtype: float64 m = data.loc[['b', 'c']] print(m) # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # dtype: float64 m = data.loc[:, 2] print(m) # a -1.525926 # c 0.595279 # d 0.034305 # dtype: float64 \u5206\u5c42\u7d22\u5f15\u5728\u91cd\u5851\u6570\u636e\u548c\u6570\u7ec4\u900f\u89c6\u8868\u7b49\u5206\u7ec4\u64cd\u4f5c\u4e2d\u626e\u6f14\u4e86\u91cd\u8981\u89d2\u8272\u3002 \u4f8b\u5982\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 unstack \u65b9\u6cd5\u5c06\u6570\u636e\u5728DataFrame\u4e2d\u91cd\u65b0\u6392\u5217\u3002 m = data.unstack() print(m) # 1 2 3 # a 0.163468 -1.525926 -0.210247 # b -0.956063 NaN -1.839111 # c -0.398905 0.595279 NaN # d NaN 0.034305 -0.896078 n = m.stack() print(n) # \u6216\u8005 print(data.unstack().stack()) # a 1 0.163468 # 2 -1.525926 # 3 -0.210247 # b 1 -0.956063 # 3 -1.839111 # c 1 -0.398905 # 2 0.595279 # d 2 0.034305 # 3 -0.896078 # dtype: float64","title":"Series\u7d22\u5f15\u5206\u5c42"},{"location":"python/DataAnalysis/ch05/#dataframe","text":"\u5728DataFrame\u4e2d\uff0c\u6bcf\u4e2a\u8f74\u90fd\u53ef\u4ee5\u62e5\u6709\u5206\u5c42\u7d22\u5f15\u3002 \u53c2\u8003","title":"DataFrame\u7d22\u5f15\u5206\u5c42"},{"location":"python/DataAnalysis/ch05/#1","text":"\u76f4\u63a5\u901a\u8fc7\u7ed9 index \uff08columns\uff09\u53c2\u6570\u4f20\u9012\u591a\u7ef4\u6570\u7ec4\uff0c\u8fdb\u800c\u6784\u5efa\u591a\u7ef4\u7d22\u5f15\u3002 \u6570\u7ec4\u4e2d\u6bcf\u4e2a\u7ef4\u5ea6\u5bf9\u5e94\u4f4d\u7f6e\u7684\u5143\u7d20\uff0c\u7ec4\u6210\u6bcf\u4e2a\u7d22\u5f15\u503c\u3002 frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=[['a', 'a', 'b', 'b'], [1, 2, 1, 2]], columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) print(frame) # Ohio Colorado # Green Red Green # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 \u4e0a\u9762\u8f93\u51fa\u4e2d\u76842\u4e2a\u5c42\u7ea7\u662f\u6ca1\u6709\u540d\u5b57\u3002 \u5206\u5c42\u7684\u5c42\u7ea7\u53ef\u4ee5\u6709\u540d\u79f0\uff08\u53ef\u4ee5\u662f\u5b57\u7b26\u4e32\u6216Python\u5bf9\u8c61\uff09\u3002 \u5982\u679c\u5c42\u7ea7\u6709\u540d\u79f0\uff0c\u8fd9\u4e9b\u540d\u79f0\u4f1a\u5728\u63a7\u5236\u53f0\u8f93\u51fa\u4e2d\u663e\u793a\u3002 print(frame.index.names) # [None, None] print(frame.columns.names) # [None, None] \u7ed9\u5c42\u7ea7\u8d4b\u4e88\u540d\u79f0\u3002\u6ce8\u610f\u533a\u5206\u884c\u6807\u7b7e\u4e2d\u7684\u7d22\u5f15\u540d\u79f0 state \u548c color \u3002 frame.index.names = ['key1', 'key2'] frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 print(frame['Ohio']) # color Green Red # key1 key2 # a 1 0 1 # 2 3 4 # b 1 6 7 # 2 9 10 print(frame.index) # MultiIndex([('a', 1), # ('a', 2), # ('b', 1), # ('b', 2)], # names=['key1', 'key2']) \u901a\u8fc7 MultiIndex \u7c7b\u7684\u76f8\u5173\u65b9\u6cd5\uff0c\u9884\u5148\u521b\u5efa\u4e00\u4e2a MultiIndex \u5bf9\u8c61\uff0c\u7136\u540e\u4f5c\u4e3aSeries\u4e0eDataFrame\u4e2d\u7684 index \uff08\u6216columns\uff09\u53c2\u6570\u503c\u3002\u540c\u65f6\uff0c\u53ef\u4ee5\u901a\u8fc7 names \u53c2\u6570\u6307\u5b9a\u591a\u5c42\u7d22\u5f15\u7684\u540d\u79f0\u3002","title":"\u65b9\u6cd51\uff1a\u76f4\u63a5\u521b\u5efa"},{"location":"python/DataAnalysis/ch05/#2from_arrays","text":"from_arrays \uff1a\u63a5\u6536\u4e00\u4e2a\u591a\u7ef4\u6570\u7ec4\u53c2\u6570\uff0c\u9ad8\u7ef4\u6307\u5b9a\u9ad8\u5c42\u7d22\u5f15\uff0c\u4f4e\u7ef4\u6307\u5b9a\u5e95\u5c42\u7d22\u5f15\u3002 mindex = pd.MultiIndex.from_arrays( [['a', 'a', 'b', 'b'], [1, 2, 1, 2]], names=['key1', 'key2'] ) frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=mindex, columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11","title":"\u65b9\u6cd52\uff1afrom_arrays"},{"location":"python/DataAnalysis/ch05/#3from_tuples","text":"from_tuples \uff1a\u63a5\u6536\u4e00\u4e2a\u5143\u7ec4\u7684\u5217\u8868\uff0c\u6bcf\u4e2a\u5143\u7ec4\u6307\u5b9a\u6bcf\u4e2a\u7d22\u5f15\uff08\u9ad8\u7ef4\u7d22\u5f15\uff0c\u4f4e\u7ef4\u7d22\u5f15\uff09\u3002 mindex = pd.MultiIndex.from_tuples( [('a', 1), ('a', 2), ('b', 1), ('b', 2)] ) frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=mindex, columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) frame.index.names = ['key1', 'key2'] frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11","title":"\u65b9\u6cd53\uff1afrom_tuples"},{"location":"python/DataAnalysis/ch05/#4from_product","text":"from_product \uff1a\u63a5\u6536\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u7684\u5217\u8868\uff0c\u6839\u636e\u591a\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u5143\u7d20\u7684\u7b1b\u5361\u5c14\u79ef\u8fdb\u884c\u521b\u5efa\u7d22\u5f15\u3002 \u4f7f\u7528\u7b1b\u5361\u5c14\u79ef\u7684\u65b9\u5f0f\u6765\u521b\u5efa\u591a\u5c42\u7d22\u5f15\u3002\u53c2\u6570\u4e3a\u5d4c\u5957\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002\u7ed3\u679c\u4e3a\u4f7f\u7528\u6bcf\u4e2a\u4e00\u7ef4\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u4e0e\u5176\u4ed6\u4e00\u7ef4\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u6765\u751f\u6210\u3002 \u7b1b\u5361\u5c14\u79ef\u7684\u65b9\u5f0f\u7684\u5c40\u9650\uff1a\u4e24\u4e24\u7ec4\u5408\u5fc5\u987b\u90fd\u5b58\u5728\uff0c\u5426\u5219\uff0c\u5c31\u4e0d\u80fd\u4f7f\u7528\u8fd9\u79cd\u65b9\u5f0f\u3002 mindex = pd.MultiIndex.from_product( [['a', 'b'], ['1', '2']], names=['key1', 'key2'] ) frame = pd.DataFrame( np.arange(12).reshape((4, 3)), index=mindex, columns=[['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']] ) frame.columns.names = ['state', 'color'] print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11","title":"\u65b9\u6cd54\uff1afrom_product"},{"location":"python/DataAnalysis/ch05/#_3","text":"\u5982\u679c\u9700\u8981\u91cd\u65b0\u6392\u5217\u8f74\u4e0a\u7684\u5c42\u7ea7\u987a\u5e8f\uff0c\u6216\u8005\u6309\u7167\u7279\u5b9a\u5c42\u7ea7\u7684\u503c\u5bf9\u6570\u636e\u8fdb\u884c\u6392\u5e8f\uff0c \u53ef\u4ee5\u901a\u8fc7swaplevel\u63a5\u6536\u4e24\u4e2a\u5c42\u7ea7\u5e8f\u53f7\u6216\u5c42\u7ea7\u540d\u79f0\uff0c\u8fd4\u56de\u4e00\u4e2a\u8fdb\u884c\u4e86\u5c42\u7ea7\u53d8\u66f4\u7684\u65b0\u5bf9\u8c61\uff08\u4f46\u662f\u6570\u636e\u662f\u4e0d\u53d8\u7684\uff09\u3002 print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 m = frame.swaplevel('key1', 'key2') print(m) # state Ohio Colorado # color Green Red Green # key2 key1 # 1 a 0 1 2 # 2 a 3 4 5 # 1 b 6 7 8 # 2 b 9 10 11 sort_index \u53ea\u80fd\u5728\u5355\u4e00\u5c42\u7ea7\u4e0a\u5bf9\u6570\u636e\u8fdb\u884c\u6392\u5e8f\u3002 \u5728\u8fdb\u884c\u5c42\u7ea7\u53d8\u6362\u65f6\uff0c\u4f7f\u7528 sort_index \u4ee5\u4f7f\u5f97\u7ed3\u679c\u6309\u7167\u5c42\u7ea7\u8fdb\u884c\u5b57\u5178\u6392\u5e8f\u3002 m = frame.sort_index(level=1) # \u5bf9key2\u6392\u5e8f\uff0c\u5e95\u5c42\u7d22\u5f15 print(m) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # b 1 6 7 8 # a 2 3 4 5 # b 2 9 10 11 m = frame.sort_index(level=0) # \u5bf9key1\u6392\u5e8f\uff0c\u9ad8\u5c42\u7d22\u5f15 print(m) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 m = frame.swaplevel(0, 1).sort_index(level=1) # swaplevel(0, 1)\u7b49\u540c\u4e8eswaplevel(key1, key2)\uff0c\u4ea4\u6362\u540ekey1\u53d8\u6210\u4e86\u5e95\u5c42\u7d22\u5f15 print(m) # state Ohio Colorado # color Green Red Green # key2 key1 # 1 a 0 1 2 # 2 a 3 4 5 # 1 b 6 7 8 # 2 b 9 10 11","title":"\u91cd\u6392\u5e8f\u548c\u5c42\u7ea7\u6392\u5e8f"},{"location":"python/DataAnalysis/ch05/#_4","text":"DataFrame\u548cSeries\u4e2d\u5f88\u591a\u63cf\u8ff0\u6027\u548c\u6c47\u603b\u6027\u7edf\u8ba1\u6709\u4e00\u4e2a level \u9009\u9879\uff0c\u901a\u8fc7 level \u9009\u9879\u4f60\u53ef\u4ee5\u6307\u5b9a\u4f60\u60f3\u8981\u5728\u67d0\u4e2a\u7279\u5b9a\u7684\u8f74\u4e0a\u8fdb\u884c\u805a\u5408\u3002 print(frame) # state Ohio Colorado # color Green Red Green # key1 key2 # a 1 0 1 2 # 2 3 4 5 # b 1 6 7 8 # 2 9 10 11 m = frame.groupby(level='key2').sum() print(m) # state Ohio Colorado # color Green Red Green # key2 # 1 6 8 10 # 2 12 14 16 m = frame.groupby(level='color', axis=1).sum() print(m) # color Green Red # key1 key2 # a 1 2 1 # 2 8 4 # b 1 14 7 # 2 20 10","title":"\u6309\u5c42\u7ea7\u8fdb\u884c\u6c47\u603b\u7edf\u8ba1"},{"location":"python/DataAnalysis/ch05/#dataframe_1","text":"\u901a\u5e38\u6211\u4eec\u4e0d\u4f1a\u4f7f\u7528DataFrame\u4e2d\u4e00\u4e2a\u6216\u591a\u4e2a\u5217\u4f5c\u4e3a\u884c\u7d22\u5f15\uff1b\u53cd\u800c\u4f60\u53ef\u80fd\u60f3\u8981\u5c06\u884c\u7d22\u5f15\u79fb\u52a8\u5230DataFrame\u7684\u5217\u4e2d\u3002 frame = pd.DataFrame( {'a': range(7), 'b': range(7, 0, -1), 'c': ['one', 'one', 'one', 'two', 'two', 'two', 'two'], 'd': [0, 1, 2, 0, 1, 2, 3] } ) print(frame) # a b c d # 0 0 7 one 0 # 1 1 6 one 1 # 2 2 5 one 2 # 3 3 4 two 0 # 4 4 3 two 1 # 5 5 2 two 2 # 6 6 1 two 3 DataFrame\u7684 set_index \u51fd\u6570\u4f1a\u751f\u6210\u4e00\u4e2a\u65b0\u7684DataFrame\uff0c\u65b0\u7684DataFrame\u4f7f\u7528\u4e00\u4e2a\u6216\u591a\u4e2a\u5217\u4f5c\u4e3a\u7d22\u5f15\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\u8fd9\u4e9b\u7d22\u5f15\u5217\u4f1a\u4eceDataFrame\u4e2d\u79fb\u9664\uff0c\u4e5f\u53ef\u4ee5\u5c06\u5b83\u4eec\u7559\u5728DataFrame\u4e2d\u3002 frame2 = frame.set_index(['c', 'd'], drop=False) print(frame2) # a b c d # c d # one 0 0 7 one 0 # 1 1 6 one 1 # 2 2 5 one 2 # two 0 3 4 two 0 # 1 4 3 two 1 # 2 5 2 two 2 # 3 6 1 two 3 frame2 = frame.set_index(['c', 'd']) print(frame2) # a b # c d # one 0 0 7 # 1 1 6 # 2 2 5 # two 0 3 4 # 1 4 3 # 2 5 2 # 3 6 1 reset_index \u662f set_index \u7684\u53cd\u64cd\u4f5c\uff0c\u5206\u5c42\u7d22\u5f15\u7684\u7d22\u5f15\u5c42\u7ea7\u4f1a\u88ab\u79fb\u52a8\u5230\u5217\u4e2d\u3002 \u6ce8\u610f\uff1a\u5982\u679c\u5728 set_index \u65f6\u4f7f\u7528\u4e86 drop=False \uff0c\u5728\u4f7f\u7528 reset_index \u4f1a\u62a5\u9519\u3002 m = frame2.reset_index() print(m) # c d a b # 0 one 0 0 7 # 1 one 1 1 6 # 2 one 2 2 5 # 3 two 0 3 4 # 4 two 1 4 3 # 5 two 2 5 2 # 6 two 3 6 1","title":"\u4f7f\u7528DataFrame\u7684\u5217\u8fdb\u884c\u7d22\u5f15"},{"location":"python/DataAnalysis/ch05/#_5","text":"\u5305\u542b\u5728pandas\u5bf9\u8c61\u7684\u6570\u636e\u53ef\u4ee5\u901a\u8fc7\u591a\u79cd\u65b9\u5f0f\u8054\u5408\u5728\u4e00\u8d77\uff1a pandas.merge \u6839\u636e\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u5c06\u884c\u8fdb\u884c\u8fde\u63a5\u3002\u5bf9\u4e8eSQL\u6216\u5176\u4ed6\u5173\u7cfb\u578b\u6570\u636e\u5e93\u7684\u7528\u6237\u6765\u8bf4\uff0c\u8fd9\u79cd\u65b9\u5f0f\u6bd4\u8f83\u719f\u6089\uff0c\u5b83\u5b9e\u73b0\u7684\u662f\u6570\u636e\u5e93\u7684\u8fde\u63a5\u64cd\u4f5c\u3002 pandas.concat \u4f7f\u5bf9\u8c61\u5728\u8f74\u5411\u4e0a\u8fdb\u884c\u9ecf\u5408\u6216\u201c\u5806\u53e0\u201d\u3002 combine_first \u5b9e\u4f8b\u65b9\u6cd5\u5141\u8bb8\u5c06\u91cd\u53e0\u7684\u6570\u636e\u62fc\u63a5\u5728\u4e00\u8d77\uff0c\u4ee5\u4f7f\u7528\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u7684\u503c\u586b\u5145\u53e6\u4e00\u4e2a\u5bf9\u8c61\u4e2d\u7684\u7f3a\u5931\u503c\u3002","title":"\u8054\u5408\u4e0e\u5408\u5e76\u6570\u636e\u96c6"},{"location":"python/DataAnalysis/ch05/#dataframe_2","text":"\u5408\u5e76\u6216\u8fde\u63a5\u64cd\u4f5c\u901a\u8fc7\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u8fde\u63a5\u884c\u6765\u8054\u5408\u6570\u636e\u96c6\u3002 \u8fd9\u4e9b\u64cd\u4f5c\u662f\u5173\u7cfb\u578b\u6570\u636e\u5e93\u7684\u6838\u5fc3\u5185\u5bb9\uff08\u4f8b\u5982\u57fa\u4e8eSQL\u7684\u6570\u636e\u5e93\uff09\u3002 pandas\u4e2d\u7684 merge \u51fd\u6570\u4e3b\u8981\u7528\u4e8e\u5c06\u5404\u79cd join \u64cd\u4f5c\u7b97\u6cd5\u8fd0\u7528\u5728\u6570\u636e\u4e0a\u3002 \u5728\u8fdb\u884c\u5217-\u5217\u8fde\u63a5\u65f6\uff0c\u4f20\u9012\u7684DataFrame\u7d22\u5f15\u5bf9\u8c61\u4f1a\u88ab\u4e22\u5f03\u3002 \u5408\u5e76\u64cd\u4f5c\u4e5f\u8981\u8003\u8651\u5982\u4f55\u5904\u7406\u91cd\u53e0\u7684\u5217\u540d( suffixes \u540e\u7f00\u9009\u9879)\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u591a\u5bf9\u4e00\u8fde\u63a5\u7684\u4f8b\u5b50\u3002 df1 \u7684\u6570\u636e\u6709\u591a\u4e2a\u884c\u7684\u6807\u7b7e\u4e3a a \u548c b \uff0c\u800c df2 \u5728 key \u5217\u4e2d\u6bcf\u4e2a\u503c\u4ec5\u6709\u4e00\u884c\u3002 df1 = pd.DataFrame( { 'key': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7) } ) df2 = pd.DataFrame( { 'key': ['a', 'b', 'd'], 'data1': range(3) } ) print(df1) # key data1 # 0 b 0 # 1 b 1 # 2 a 2 # 3 c 3 # 4 a 4 # 5 a 5 # 6 b 6 print(df2) # key data1 # 0 a 0 # 1 b 1 # 2 d 2 \u8c03\u7528 merge \u5904\u7406\uff0c\u63a8\u8350\u663e\u5f0f\u5730\u6307\u5b9a\u8fde\u63a5\u952e\u3002 result = pd.merge(df1, df2) print(result) # key data1 # 0 b 1 result = pd.merge(df1, df2, on=['key', 'data1']) print(result) # key data1 # 0 b 1 result = pd.merge(df1, df2, on='key') print(result) # key data1_x data1_y # 0 b 0 1 # 1 b 1 1 # 2 b 6 1 # 3 a 2 0 # 4 a 4 0 # 5 a 5 0 \u5982\u679c\u6bcf\u4e2a\u5bf9\u8c61\u7684\u5217\u540d\u662f\u4e0d\u540c\u7684\uff0c\u53ef\u4ee5\u5206\u522b\u4e3a\u5b83\u4eec\u6307\u5b9a\u5217\u540d\u3002 df3 = pd.DataFrame( { 'lkey': ['b', 'b', 'a', 'c', 'a', 'a', 'b'], 'data1': range(7) } ) df4 = pd.DataFrame( { 'rkey': ['a', 'b', 'd'], 'data2': range(3) } ) print(df3) # lkey data1 # 0 b 0 # 1 b 1 # 2 a 2 # 3 c 3 # 4 a 4 # 5 a 5 # 6 b 6 print(df4) # rkey data2 # 0 a 0 # 1 b 1 # 2 d 2 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c merge \u505a\u7684\u662f\u5185\u8fde\u63a5\uff08'inner' join\uff09\uff0c\u7ed3\u679c\u4e2d\u7684\u952e\u662f\u4e24\u5f20\u8868\u7684\u4ea4\u96c6\u3002 result = pd.merge(df3, df4, left_on='lkey', right_on='rkey') # df4\u7684[a,0]\u5bf9\u5e94df3\u7684\u6240\u6709[a,?]\u8bb0\u5f55\uff08\u901a\u8fc7\u91cd\u590d\u6765\u586b\u5145\u4e0d\u8db3\uff09 print(result) # lkey data1 rkey data2 # 0 b 0 b 1 # 1 b 1 b 1 # 2 b 6 b 1 # 3 a 2 a 0 # 4 a 4 a 0 # 5 a 5 a 0 \u5916\u8fde\u63a5\uff08outer join\uff09\u662f\u952e\u7684\u5e76\u96c6\uff0c\u8054\u5408\u4e86\u5de6\u8fde\u63a5\u548c\u53f3\u8fde\u63a5\u7684\u6548\u679c\u3002 \u591a\u5bf9\u591a\u8fde\u63a5\u662f\u884c\u7684\u7b1b\u5361\u5c14\u79ef\u3002 df1 = pd.DataFrame( { 'key': ['b', 'b', 'a', 'c', 'a', 'b'], 'data1': range(6) } ) df2 = pd.DataFrame( { 'key': ['a', 'b', 'a', 'b', 'd'], 'data2': range(5) } ) print(df1.sort_values(by='key')) # key data1 # 2 a 2 # 4 a 4 # 0 b 0 # 1 b 1 # 5 b 5 # 3 c 3 print(df2.sort_values(by='key')) # key data2 # 0 a 0 # 2 a 2 # 1 b 1 # 3 b 3 # 4 d 4 result = pd.merge(df1, df2, on='key', how='left') print(result.sort_values(by='key')) # key data1 data2 # 4 a 2 0.0 # 5 a 2 2.0 # 7 a 4 0.0 # 8 a 4 2.0 # 0 b 0 1.0 # 1 b 0 3.0 # 2 b 1 1.0 # 3 b 1 3.0 # 9 b 5 1.0 # 10 b 5 3.0 # 6 c 3 NaN result = pd.merge(df1, df2, on='key', how='outer') # \u591a\u5bf9\u591a\u8fde\u63a5 print(result.sort_values(by='key')) # key data1 data2 # 6 a 2.0 0.0 # 7 a 2.0 2.0 # 8 a 4.0 0.0 # 9 a 4.0 2.0 # 0 b 0.0 1.0 # 1 b 0.0 3.0 # 2 b 1.0 1.0 # 3 b 1.0 3.0 # 4 b 5.0 1.0 # 5 b 5.0 3.0 # 10 c 3.0 NaN # 11 d NaN 4.0 \u591a\u952e\u5408\u5e76\u3002 df1 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar'], 'key2': ['one', 'two', 'one'], 'lval': [1, 2, 3] } ) df2 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar', 'bar'], 'key2': ['one', 'one', 'one', 'two'], 'rval': [4, 5, 6, 7] } ) print(df1.sort_values(by=['key1', 'key2'])) # key1 key2 lval # 2 bar one 3 # 0 foo one 1 # 1 foo two 2 print(df2.sort_values(by=['key1', 'key2'])) # key1 key2 rval # 2 bar one 6 # 3 bar two 7 # 0 foo one 4 # 1 foo one 5 result = pd.merge(df1, df2, on=['key1', 'key2'], how='outer') print(result.sort_values(by=['key1', 'key2'])) # key1 key2 lval rval # 3 bar one 3.0 6.0 # 4 bar two NaN 7.0 # 0 foo one 1.0 4.0 # \u91cd\u590d\u586b\u5145 # 1 foo one 1.0 5.0 # \u91cd\u590d\u586b\u5145 # 2 foo two 2.0 NaN \u5904\u7406\u91cd\u53e0\u5217\u540d\u3002 result = pd.merge(df1, df2, on='key1') print(result.sort_values(by='key1')) # key1 key2_x lval key2_y rval # 4 bar one 3 one 6 # 5 bar one 3 two 7 # 0 foo one 1 one 4 # 1 foo one 1 one 5 # 2 foo two 2 one 4 # 3 foo two 2 one 5 result = pd.merge(df1, df2, on='key1', suffixes=('_left', '_right')) print(result.sort_values(by='key1')) # key1 key2_left lval key2_right rval # 4 bar one 3 one 6 # 5 bar one 3 two 7 # 0 foo one 1 one 4 # 1 foo one 1 one 5 # 2 foo two 2 one 4 # 3 foo two 2 one 5","title":"\u6570\u636e\u5e93\u98ce\u683c\u7684DataFrame\u8fde\u63a5"},{"location":"python/DataAnalysis/ch05/#_6","text":"\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0cDataFrame\u4e2d\u7528\u4e8e\u5408\u5e76\u7684\u952e\u662f\u5b83\u7684\u7d22\u5f15\u3002\u53ef\u4ee5\u4f20\u9012 left_index=True \u6216 right_index=True \uff08\u6216\u8005\u90fd\u4f20\uff09\u6765\u8868\u793a\u7d22\u5f15\u9700\u8981\u7528\u6765\u4f5c\u4e3a\u5408\u5e76\u7684\u952e\u3002 df1 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar'], 'key2': ['one', 'two', 'one'], 'lval': [1, 2, 3] } ) df2 = pd.DataFrame( { 'key1': ['foo', 'foo', 'bar', 'bar'], 'key2': ['one', 'one', 'one', 'two'], 'rval': [4, 5, 6, 7] }, index=['foo', 'foo', 'bar', 'bar'] ) print(df1) # key1 key2 lval # 0 foo one 1 # 1 foo two 2 # 2 bar one 3 print(df2) # key1 key2 rval # foo foo one 4 # foo foo one 5 # bar bar one 6 # bar bar two 7 result = pd.merge(df1, df2, left_on='key1', right_index=True, suffixes=('_left', '_right')) print(result.sort_index()) # key1 key1_left key2_left lval key1_right key2_right rval # 0 foo foo one 1 foo one 4 # 0 foo foo one 1 foo one 5 # 1 foo foo two 2 foo one 4 # 1 foo foo two 2 foo one 5 # 2 bar bar one 3 bar one 6 # 2 bar bar one 3 bar two 7 result = pd.merge(df1, df2, left_on='key1', right_index=True, how='outer', suffixes=('_left', '_right')) # \u548c\u4e0a\u8ff0\u7ed3\u679c\u4e00\u6837 print(result.sort_index()) # key1 key1_left key2_left lval key1_right key2_right rval # 0 foo foo one 1 foo one 4 # 0 foo foo one 1 foo one 5 # 1 foo foo two 2 foo one 4 # 1 foo foo two 2 foo one 5 # 2 bar bar one 3 bar one 6 # 2 bar bar one 3 bar two 7 \u5728\u66f4\u590d\u6742\u591a\u5c42\u7d22\u5f15\u6570\u636e\u7684\u591a\u952e\u5408\u5e76\uff0c\u5728\u7d22\u5f15\u4e0a\u8fde\u63a5\u662f\u4e00\u4e2a\u9690\u5f0f\u7684\u591a\u952e\u5408\u5e76\u3002 \u5fc5\u987b\u4ee5\u5217\u8868\u7684\u65b9\u5f0f\u6307\u660e\u5408\u5e76\u6240\u9700\u591a\u4e2a\u5217\uff08\u6ce8\u610f\u4f7f\u7528 how='outer' \u5904\u7406\u91cd\u590d\u7684\u7d22\u5f15\u503c\uff09\u3002 df1 = pd.DataFrame( { 'key1': ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'], 'key2': [2000, 2001, 2002, 2001, 2002], 'data': np.arange(5.) } ) df2 = pd.DataFrame( np.arange(12).reshape((6, 2)), index=[ ['Nevada', 'Nevada', 'Ohio', 'Ohio', 'Ohio', 'Ohio'], [2001, 2000, 2000, 2000, 2001, 2002] ], columns=['event1', 'event2'] ) print(df1) # key1 key2 data # 0 Ohio 2000 0.0 # 1 Ohio 2001 1.0 # 2 Ohio 2002 2.0 # 3 Nevada 2001 3.0 # 4 Nevada 2002 4.0 print(df2) # event1 event2 # Nevada 2001 0 1 # 2000 2 3 # Ohio 2000 4 5 # 2000 6 7 # 2001 8 9 # 2002 10 11 result = pd.merge(df1, df2, left_on=['key1', 'key2'], right_index=True) print(result) # key1 key2 data event1 event2 # 0 Ohio 2000 0.0 4 5 # 0 Ohio 2000 0.0 6 7 # 1 Ohio 2001 1.0 8 9 # 2 Ohio 2002 2.0 10 11 # 3 Nevada 2001 3.0 0 1 result = pd.merge(df1, df2, left_on=['key1', 'key2'], right_index=True, how='outer') print(result) # key1 key2 data event1 event2 # 0 Ohio 2000 0.0 4.0 5.0 # 0 Ohio 2000 0.0 6.0 7.0 # 1 Ohio 2001 1.0 8.0 9.0 # 2 Ohio 2002 2.0 10.0 11.0 # 3 Nevada 2001 3.0 0.0 1.0 # 4 Nevada 2002 4.0 NaN NaN # 4 Nevada 2000 NaN 2.0 3.0 \u4f7f\u7528\u4e24\u8fb9\u7684\u7d22\u5f15\u8fdb\u884c\u5408\u5e76\u4e5f\u662f\u53ef\u4ee5\u7684\uff0c\u524d\u63d0\u662f\u7528\u4e24\u8fb9\u7528\u6765\u5408\u5e76\u7684\u7d22\u5f15\u6709\u4ea4\u96c6\uff08\u516c\u5171\u90e8\u5206\uff09\u3002 \u5728\u4f7f\u7528 merge \u65f6\uff0c\u53c2\u6570 on=['key1', 'key2'] \u4e0d\u80fd\u548c left_index=True , right_index=True \u540c\u65f6\u5b58\u5728\u3002 \u5bf9\u4e8e\u91cd\u590d\u7d22\u5f15\uff0c\u5982\u679c\u503c\u4e0d\u540c\uff0c\u5219\u591a\u884c\u663e\u793a\uff0c\u548c\u6570\u636e\u5e93SQL\u7684 full join \u7c7b\u4f3c\u6982\u5ff5\u3002 \u5982\u679c\u51fa\u73b0\u76f8\u540c\u5217\u540d\uff0c\u5219\u4f1a\u81ea\u52a8\u6dfb\u52a0\u540e\u7f00\u5b57\u7b26\u4ee5\u793a\u533a\u522b\u3002 df1 = pd.DataFrame( [[1, 2], [3, 4], [5, 6]], index=['a', 'c', 'e'], columns=['Ohio', 'Nevada'] ) print(df1) # Ohio Nevada # a 1 2 # c 3 4 # e 5 6 df2 = pd.DataFrame( [[7, 8], [9, 10], [11, 12], [13, 14]], index=['b', 'c', 'c', 'e'], columns=['Missouri', 'Alabama'] ) print(df2) # Missouri Alabama # b 7 8 # c 9 10 # c 11 12 # e 13 14 df3 = pd.DataFrame( [[7, 8], [9, 10], [11, 12], [13, 14]], index=['a', 'c', 'e', 'f'], columns=['Nevada', 'Alabama'] ) print(df3) # Nevada Alabama # a 7 8 # c 9 10 # e 11 12 # f 13 14 result = pd.merge(df1, df2, left_index=True, right_index=True, how='outer') print(result) # Ohio Nevada Missouri Alabama # a 1.0 2.0 NaN NaN # b NaN NaN 7.0 8.0 # c 3.0 4.0 9.0 10.0 # c 3.0 4.0 11.0 12.0 # e 5.0 6.0 13.0 14.0 result = pd.merge(df1, df3, left_index=True, right_index=True, how='outer') print(result) # Ohio Nevada_x Nevada_y Alabama # a 1.0 2.0 7 8 # c 3.0 4.0 9 10 # e 5.0 6.0 11 12 # f NaN NaN 13 14 \u53e6\u4e00\u79cd\u5199\u6cd5\uff1a result = df1.join(df2, how='outer') print(result) # Ohio Nevada Missouri Alabama # a 1.0 2.0 NaN NaN # b NaN NaN 7.0 8.0 # c 3.0 4.0 9.0 10.0 # c 3.0 4.0 11.0 12.0 # e 5.0 6.0 13.0 14.0 \u4e5f\u53ef\u4ee5\u5411 join \u65b9\u6cd5\u4f20\u5165\u4e00\u4e2aDataFrame\u5217\u8868\uff0c\u7c7b\u4f3c\u4e8e\u5bf9\u4e09\u4e2a\u6570\u636e\u96c6\u8fdb\u884c join \u64cd\u4f5c\u3002 result = df1.join([df2, df3]) print(result) # Ohio Nevada_x Missouri Alabama_x Nevada_y Alabama_y # a 1 2 NaN NaN 7 8 # c 3 4 9.0 10.0 9 10 # c 3 4 11.0 12.0 9 10 # e 5 6 13.0 14.0 11 12","title":"\u6839\u636e\u7d22\u5f15\u5408\u5e76"},{"location":"python/DataAnalysis/ch05/#_7","text":"\u53e6\u4e00\u79cd\u6570\u636e\u7ec4\u5408\u64cd\u4f5c\u53ef\u79f0\u4e3a\u62fc\u63a5\u3001\u7ed1\u5b9a\u6216\u5806\u53e0\u3002NumPy\u7684 concatenate \u51fd\u6570\u53ef\u4ee5\u5728NumPy\u6570\u7ec4\u4e0a\u5b9e\u73b0\u8be5\u529f\u80fd\u3002 \u57fa\u4e8eSeries\u7684pandas\u7684 concat \u51fd\u6570\u7684\u5de5\u4f5c\u673a\u5236\u5206\u6790\u3002 \u4e0b\u9762\u4e09\u4e2a\u7d22\u5f15\u4e0d\u91cd\u53e0\u7684Series\u3002 s1 = pd.Series([0, 1], index=['a', 'b']) s2 = pd.Series([2, 3, 4], index=['c', 'd', 'e']) s3 = pd.Series([5, 6], index=['f', 'g']) \u7528\u5217\u8868\u4e2d\u7684\u8fd9\u4e9b\u5bf9\u8c61\u8c03\u7528 concat \u65b9\u6cd5\u4f1a\u5c06\u503c\u548c\u7d22\u5f15\u7c98\u5728\u4e00\u8d77\uff1a \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c concat \u65b9\u6cd5\u662f\u6cbf\u7740 axis=0 \u7684\u8f74\u5411\u751f\u6548\u7684\uff0c\u751f\u6210\u53e6\u4e00\u4e2aSeries\u3002 \u5982\u679c\u4f20\u9012 axis=1 \uff0c\u8fd4\u56de\u7684\u7ed3\u679c\u5219\u662f\u4e00\u4e2aDataFrame\uff08 axis=1 \u65f6\u662f\u5217\uff09\u3002 result = pd.concat([s1, s2, s3]) print(result) # a 0 # b 1 # c 2 # d 3 # e 4 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s2, s3], keys=['one', 'two', 'three']) # \u901a\u8fc7keys\u53c2\u6570\uff0c\u5728\u8fde\u63a5\u8f74\u5411\u4e0a\u521b\u5efa\u4e00\u4e2a\u591a\u5c42\u7d22\u5f15\uff0c\u4ee5\u4fbf\u5728\u7ed3\u679c\u4e2d\u533a\u5206\u5404\u90e8\u5206 print(result) # one a 0 # b 1 # two c 2 # d 3 # e 4 # three f 5 # g 6 # dtype: int64 print(result.unstack()) # \u628a\u539f\u7d22\u5f15\u4f5c\u4e3a\u5217\u6807\u7b7e\u5c55\u5f00 # a b c d e f g # one 0.0 1.0 NaN NaN NaN NaN NaN # two NaN NaN 2.0 3.0 4.0 NaN NaN # three NaN NaN NaN NaN NaN 5.0 6.0 result = pd.concat([s1, s2, s3], axis=1) # \u5728\u8fd9\u4e2a\u6848\u4f8b\u4e2daxis=1\u8f74\u5411\u4e0a\u5e76\u6ca1\u6709\u91cd\u53e0 print(result) # 0 1 2 # a 0.0 NaN NaN # b 1.0 NaN NaN # c NaN 2.0 NaN # d NaN 3.0 NaN # e NaN 4.0 NaN # f NaN NaN 5.0 # g NaN NaN 6.0 result = pd.concat([s1, s2, s3], axis=1, keys=['one', 'two', 'three']) # \u5728\u8fd9\u4e2a\u6848\u4f8b\u4e2daxis=1\u8f74\u5411\u4e0a\u5e76\u6ca1\u6709\u91cd\u53e0 print(result) # one two three # a 0.0 NaN NaN # b 1.0 NaN NaN # c NaN 2.0 NaN # d NaN 3.0 NaN # e NaN 4.0 NaN # f NaN NaN 5.0 # g NaN NaN 6.0 print(result.unstack()) # \u5bf9\u6bd4axis=0\u7684\u591a\u5c42\u7d22\u5f15\uff0c\u5f53axis=1\u65f6\u5bf9\u8f93\u51fa\u5404index\u7684\u5e76\u96c6\u505a\u4e86\u5206\u7ec4\u3002 # one a 0.0 # b 1.0 # c NaN # d NaN # e NaN # f NaN # g NaN # two a NaN # b NaN # c 2.0 # d 3.0 # e 4.0 # f NaN # g NaN # three a NaN # b NaN # c NaN # d NaN # e NaN # f 5.0 # g 6.0 # dtype: float64 s4 = pd.concat([s1, s3]) print(s4) # a 0 # b 1 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s4]) print(result) # a 0 # b 1 # a 0 # b 1 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s4], axis=1) # \u73b0\u5728\u5728\u4e2daxis=1\u8f74\u5411\u4e0a\u6709\u91cd\u53e0 print(result) # 0 1 # a 0.0 0 # b 1.0 1 # f NaN 5 # g NaN 6 result = pd.concat([s1, s4], axis=1, keys=['one', 'two', 'three']) print(result) # one two # a 0.0 0 # b 1.0 1 # f NaN 5 # g NaN 6 result = pd.concat([s1, s4], axis=0, keys=['one', 'two', 'three']) # \u901a\u8fc7keys\u53c2\u6570\uff0c\u5728\u8fde\u63a5\u8f74\u5411\u4e0a\u521b\u5efa\u4e00\u4e2a\u591a\u5c42\u7d22\u5f15 print(result) # one a 0 # b 1 # two a 0 # b 1 # f 5 # g 6 # dtype: int64 result = pd.concat([s1, s4], axis=1, join='inner') # \u5185\u8fde\u63a5\u65b9\u5f0f\u5408\u5e76\u7d22\u5f15\uff08\u7d22\u5f15\u4ea4\u96c6\uff09 print(result) # 0 1 # a 0 0 # b 1 1 result = pd.concat([s1, s4], axis=1).reindex(['a', 'c', 'b', 'e']) # \u4f7f\u7528join_axes(\u5df2\u88ab\u66ff\u6362\u6210reindex)\u6765\u6307\u5b9a\u7528\u4e8e\u8fde\u63a5\u5176\u4ed6\u8f74\u5411\u7684\u8f74 print(result) # 0 1 # a 0.0 0.0 # c NaN NaN # b 1.0 1.0 # e NaN NaN \u57fa\u4e8eDataFrame\u7684pandas\u7684 concat \u51fd\u6570\u7684\u5de5\u4f5c\u673a\u5236\u5206\u6790\u3002 df1 = pd.DataFrame( np.arange(12).reshape((6, 2)), index=[ ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], [2000, 2001, 2002, 2000, 2001, 2002] ], columns=['event1', 'event2'] ) df2 = pd.DataFrame( np.arange(12).reshape((6, 2)), index=[ ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada', 'Nevada'], [2000, 2001, 2002, 2000, 2001, 2002] ], columns=['event3', 'event4'] ) print(df1) # event1 event2 # Ohio 2000 0 1 # 2001 2 3 # 2002 4 5 # Nevada 2000 6 7 # 2001 8 9 # 2002 10 11 print(df2) # event3 event4 # Ohio 2000 0 1 # 2001 2 3 # 2002 4 5 # Nevada 2000 6 7 # 2001 8 9 # 2002 10 11 result = np.concatenate([df1, df2], axis=0) # \u6cbf0\u8f74\u62fc\u63a5 print(result) # [[ 0 1] # [ 2 3] # [ 4 5] # [ 6 7] # [ 8 9] # [10 11] # [ 0 1] # [ 2 3] # [ 4 5] # [ 6 7] # [ 8 9] # [10 11]] result = np.concatenate([df1, df2], axis=1) # \u6cbf1\u8f74\u62fc\u63a5 print(result) # [[ 0 1 0 1] # [ 2 3 2 3] # [ 4 5 4 5] # [ 6 7 6 7] # [ 8 9 8 9] # [10 11 10 11]] result = np.concatenate([df1, df2], axis=None) # \u5c06\u6570\u7ec4\u5c55\u5e73 print(result) # [ 0 1 2 3 4 5 6 7 8 9 10 11 0 1 2 3 4 5 6 7 8 9 10 11]","title":"\u6cbf\u8f74\u5411\u8fde\u63a5"},{"location":"python/DataAnalysis/ch05/#_8","text":"\u53e6\u4e00\u4e2a\u6570\u636e\u8054\u5408\u573a\u666f\uff0c\u65e2\u4e0d\u662f\u5408\u5e76\u64cd\u4f5c\uff0c\u4e5f\u4e0d\u662f\u8fde\u63a5\u64cd\u4f5c\u3002 \u5047\u5982\u6709\u4e24\u4e2a\u6570\u636e\u96c6\uff0c\u8fd9\u4e24\u4e2a\u6570\u636e\u96c6\u7684\u7d22\u5f15\u5168\u90e8\u6216\u90e8\u5206\u91cd\u53e0\uff0c\u901a\u8fc7NumPy\u7684 where \u51fd\u6570\u53ef\u4ee5\u8fdb\u884c\u9762\u5411\u6570\u7ec4\u7684if-else\u7b49\u4ef7\u64cd\u4f5c\u3002 s1 = pd.Series( [np.nan, 2.5, 0.0, 3.5, 4.5, np.nan], index=['f', 'e', 'd', 'c', 'b', 'a'] ) s2 = pd.Series( [0.0, np.nan, 2.0, np.nan, np.nan, 5.0], index=['a', 'b', 'c', 'd', 'e', 'f'] ) print(s1) # f NaN # e 2.5 # d 0.0 # c 3.5 # b 4.5 # a NaN # dtype: float64 print(s2) # a 0.0 # b NaN # c 2.0 # d NaN # e NaN # f 5.0 # dtype: float64 \u65b9\u6cd51\uff0c\u901a\u8fc7Numpy\u7684 where \u51fd\u6570\u3002 result = np.where(pd.isnull(s1), s2, s1) # An array with elements from 'x'(s2) where 'condition'(isnull(s1)) is True, and elements from 'y'(s1) elsewhere. print(result) # [0. 2.5 0. 3.5 4.5 5. ] # s1 # s2 # result # f NaN # a 0.0 0. \u6761\u4ef6\u4e2ds1\u8be5\u5143\u7d20\u4e3anull\uff0c\u6240\u4ee5where\u51fd\u6570\u53d6\u5bf9\u5e94x(s2)\u7684\u5143\u7d20\uff08\u6ce8\u610f\uff0c\u4e0e\u7d22\u5f15\u987a\u5e8f\u65e0\u5173\uff09 # e 2.5 # b NaN 2.5 \u6761\u4ef6\u4e2ds1\u8be5\u5143\u7d20\u4e0d\u4e3anull\uff0c\u6240\u4ee5where\u51fd\u6570\u53d6\u5bf9\u5e94y(s1)\u7684\u5143\u7d20 # d 0.0 # c 2.0 0. # c 3.5 # d NaN 3.5 # b 4.5 # e NaN 4.5 # a NaN # f 5.0 5.0 \u6761\u4ef6\u4e2ds1\u8be5\u5143\u7d20\u4e3anull\uff0c\u6240\u4ee5where\u51fd\u6570\u53d6\u5bf9\u5e94x(s2)\u7684\u5143\u7d20 result = np.where(pd.isnull(s2), s1, s2) print(result) # [0. 2.5 2. 3.5 4.5 5. ] \u65b9\u6cd52\uff0c\u901a\u8fc7Series\u7684 combine_first \u65b9\u6cd5\u3002 result = s2.combine_first(s1) # \u6ce8\u610f\uff0ccombine_first\u662f\u6309\u7167s2\u7684\u7d22\u5f15\u987a\u5e8f\u68c0\u7d22\u7684\uff0c\u76f8\u540c\u7d22\u5f15\u7684s1\u7684\u503c\u4f1a\u586b\u5145\u5bf9\u5e94s2\u7684null print(result) # a 0.0 # b 4.5 # c 2.0 # d 0.0 # e 2.5 # f 5.0 # dtype: float64 \u65b9\u6cd53\uff1aPandas\u7684 combine_first \u65b9\u6cd5\u3002 df1 = pd.DataFrame( { 'a': [1.0, np.nan, 5.0, np.nan], 'b': [np.nan, 2.0, np.nan, 6.0], 'c': [2.0, 6.0, 10.0, 15.0] } ) df2 = pd.DataFrame( { 'a': [5.0, 4.0, np.nan, 3.0, 7.0], 'b': [np.nan, 3.0, 4.0, 6.0, 8.0] } ) print(df1) # a b c # 0 1.0 NaN 2.0 # 1 NaN 2.0 6.0 # 2 5.0 NaN 10.0 # 3 NaN 6.0 15.0 print(df2) # a b # 0 5.0 NaN # 1 4.0 3.0 # 2 NaN 4.0 # 3 3.0 6.0 # 4 7.0 8.0 result = df2.combine_first(df1) # \u7528df1\u7684\u503c\u53bb\u586b\u5145df2\u5bf9\u5e94\u7d22\u5f15\u4f4d\u7f6e\u7684null\u503c print(result) # a b c # 0 5.0 NaN 2.0 # 1 4.0 3.0 6.0 # 2 5.0 4.0 10.0 # 3 3.0 6.0 15.0 # 4 7.0 8.0 NaN","title":"\u8054\u5408\u91cd\u53e0\u6570\u636e"},{"location":"python/DataAnalysis/ch05/#_9","text":"\u91cd\u65b0\u6392\u5217\u8868\u683c\u578b\u6570\u636e\u6709\u591a\u79cd\u57fa\u7840\u64cd\u4f5c\u3002\u8fd9\u4e9b\u64cd\u4f5c\u88ab\u79f0\u4e3a\u91cd\u5851\u6216\u900f\u89c6\u3002 import numpy as np import pandas as pd","title":"\u91cd\u5851\u548c\u900f\u89c6"},{"location":"python/DataAnalysis/ch05/#_10","text":"\u591a\u5c42\u7d22\u5f15\u5728DataFrame\u4e2d\u63d0\u4f9b\u4e86\u4e00\u79cd\u4e00\u81f4\u6027\u65b9\u5f0f\u7528\u4e8e\u91cd\u6392\u5217\u6570\u636e\u3002\u4ee5\u4e0b\u662f\u4e24\u4e2a\u57fa\u7840\u64cd\u4f5c\uff1a statck\uff08\u5806\u53e0\uff09\u8be5\u64cd\u4f5c\u4f1a\u201c\u65cb\u8f6c\u201d\u6216\u5c06\u5217\u4e2d\u7684\u6570\u636e\u900f\u89c6\u5230\u884c\u3002 unstack\uff08\u62c6\u5806\uff09\u8be5\u64cd\u4f5c\u4f1a\u5c06\u884c\u4e2d\u7684\u6570\u636e\u900f\u89c6\u5230\u5217\u3002 df = pd.DataFrame( np.arange(6).reshape((2, 3)), index=pd.Index(['Ohio', 'Colorado'], name='state'), columns=pd.Index(['one', 'two', 'three'], name='number') ) print(df) # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 \u5728\u8fd9\u4efd\u6570\u636e\u4e0a\u4f7f\u7528stack\u65b9\u6cd5\u4f1a\u5c06\u5217\u900f\u89c6\u5230\u884c\uff0c\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684Series\uff1a result = df.stack() print(result) # state number # Ohio one 0 # two 1 # three 2 # Colorado one 3 # two 4 # three 5 # dtype: int64 \u4ece\u4e00\u4e2a\u591a\u5c42\u7d22\u5f15\u5e8f\u5217\u4e2d\uff0c\u4f60\u53ef\u4ee5\u4f7f\u7528 unstack \u65b9\u6cd5\u5c06\u6570\u636e\u91cd\u6392\u5217\u540e\u653e\u5165\u4e00\u4e2aDataFrame\u4e2d\uff1a print(result.unstack()) # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 print(result.unstack(0)) # \u53ef\u4ee5\u4f20\u5165\u4e00\u4e2a\u5c42\u7ea7\u5e8f\u53f7\u6216\u540d\u79f0\u6765\u62c6\u5206\u4e00\u4e2a\u4e0d\u540c\u7684\u5c42\u7ea7 # state Ohio Colorado # number # one 0 3 # two 1 4 # three 2 5 print(result.unstack(1)) # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 print(result.unstack('state')) # \u8f93\u51fa\u7ed3\u679c\u548c\u4f20\u5165\u5c42\u7ea70\u4e00\u6837 # state Ohio Colorado # number # one 0 3 # two 1 4 # three 2 5 print(result.unstack('number')) # \u8f93\u51fa\u7ed3\u679c\u548c\u4f20\u5165\u5c42\u7ea71\u4e00\u6837 # number one two three # state # Ohio 0 1 2 # Colorado 3 4 5 \u5982\u679c\u5c42\u7ea7\u4e2d\u7684\u6240\u6709\u503c\u5e76\u672a\u5305\u542b\u4e8e\u6bcf\u4e2a\u5b50\u5206\u7ec4\u4e2d\u65f6\uff0c\u62c6\u5206\u53ef\u80fd\u4f1a\u5f15\u5165\u7f3a\u5931\u503c\uff1a s1 = pd.Series([0, 1, 2, 3], index=['a', 'b', 'c', 'd']) s2 = pd.Series([4, 5, 6], index=['c', 'd', 'e']) s3 = pd.concat([s1, s2], keys=['one', 'two']) print(s3) # one a 0 # b 1 # c 2 # d 3 # two c 4 # d 5 # e 6 # dtype: int64 print(s3.unstack(0)) # one two # a 0.0 NaN # b 1.0 NaN # c 2.0 4.0 # d 3.0 5.0 # e NaN 6.0 print(s3.unstack(1)) print(s3.unstack()) # a b c d e # one 0.0 1.0 2.0 3.0 NaN # two NaN NaN 4.0 5.0 6.0 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5806\u53e0\u4f1a\u8fc7\u6ee4\u51fa\u7f3a\u5931\u503c\uff0c\u56e0\u6b64\u5806\u53e0\u62c6\u5806\u7684\u64cd\u4f5c\u662f\u53ef\u9006\u7684\u3002 print(s3.unstack().stack()) # one a 0.0 # b 1.0 # c 2.0 # d 3.0 # two c 4.0 # d 5.0 # e 6.0 # dtype: float64 print(s3.unstack().stack(dropna=False)) # one a 0.0 # b 1.0 # c 2.0 # d 3.0 # e NaN # two a NaN # b NaN # c 4.0 # d 5.0 # e 6.0 # dtype: float64 \u5728DataFrame\u4e2d\u62c6\u5806\u65f6\uff0c\u88ab\u62c6\u5806\u7684\u5c42\u7ea7\u4f1a\u53d8\u4e3a\u7ed3\u679c\u4e2d\u6700\u4f4e\u7684\u5c42\u7ea7\u3002 \u5728\u8c03\u7528 stack \u65b9\u6cd5\u65f6\uff0c\u6211\u4eec\u53ef\u4ee5\u6307\u660e\u9700\u8981\u5806\u53e0\u7684\u8f74\u5411\u540d\u79f0\u3002 df = pd.DataFrame( {'left': result, 'right': result + 5}, columns=pd.Index(['left', 'right'], name='side') ) print(df) # side left right # state number # Ohio one 0 5 # two 1 6 # three 2 7 # Colorado one 3 8 # two 4 9 # three 5 10 print(df.unstack()) # side left right # number one two three one two three # state # Ohio 0 1 2 5 6 7 # Colorado 3 4 5 8 9 10 print(df.unstack('state')) # \u88ab\u62c6\u5806\u7684\u5c42\u7ea7(state)\u4f1a\u53d8\u4e3a\u7ed3\u679c\u4e2d\u6700\u4f4e\u7684\u5c42\u7ea7 # side left right # state Ohio Colorado Ohio Colorado # number # one 0 3 5 8 # two 1 4 6 9 # three 2 5 7 10 \u5728\u8c03\u7528 stack \u65b9\u6cd5\u65f6\uff0c\u53ef\u4ee5\u6307\u660e\u9700\u8981\u5806\u53e0\u7684\u8f74\u5411\u540d\u79f0\uff1a print(df.unstack('state').stack('side')) # state Colorado Ohio # number side # one left 3 0 # right 8 5 # two left 4 1 # right 9 6 # three left 5 2 # right 10 7","title":"\u4f7f\u7528\u591a\u5c42\u7d22\u5f15\u8fdb\u884c\u91cd\u5851"},{"location":"python/DataAnalysis/ch05/#_11","text":"\u5728\u6570\u636e\u5e93\u548cCSV\u4e2d\u5b58\u50a8\u591a\u65f6\u95f4\u5e8f\u5217\u7684\u65b9\u5f0f\u5c31\u662f\u6240\u8c13\u7684\u957f\u683c\u5f0f\u6216\u5806\u53e0\u683c\u5f0f\u3002 data = pd.read_csv('../examples/macrodata.csv') print(data.head(3)) # year quarter realgdp realcons ... unemp pop infl realint # 0 1959.0 1.0 2710.349 1707.4 ... 5.8 177.146 0.00 0.00 # 1 1959.0 2.0 2778.801 1733.7 ... 5.1 177.830 2.34 0.74 # 2 1959.0 3.0 2775.488 1751.8 ... 5.3 178.657 2.74 1.09 # ...... # [3 rows x 14 columns] # PeriodIndex\u5c06year\u548cquarter\u7b49\u5217\u8fdb\u884c\u8054\u5408\u5e76\u751f\u6210\u4e86\u4e00\u79cd\u65f6\u95f4\u95f4\u9694\u7c7b\u578b periods = pd.PeriodIndex( year=data.year, quarter=data.quarter, name='date' ) columns = pd.Index( ['realgdp', 'infl', 'unemp'], name='item' ) data = data.reindex(columns=columns) print(data) # item realgdp infl unemp # 0 2710.349 0.00 5.8 # 1 2778.801 2.34 5.1 # 2 2775.488 2.74 5.3 # ...... # [203 rows x 3 columns] data.index = periods.to_timestamp('D', 'end') print(data.index) # DatetimeIndex(['1959-03-31 23:59:59.999999999', # '1959-06-30 23:59:59.999999999', # ... # '2009-06-30 23:59:59.999999999', # '2009-09-30 23:59:59.999999999'], # dtype='datetime64[ns]', name='date', length=203, freq=None) \u4e0b\u9762\u662fldata\u7684\u6570\u636e\u6837\u672c\u3002 \u8fd9\u79cd\u6570\u636e\u5373\u6240\u8c13\u7684\u591a\u65f6\u95f4\u5e8f\u5217\u7684\u957f\u683c\u5f0f\uff0c\u6216\u79f0\u4e3a\u5177\u6709\u4e24\u4e2a\u6216\u66f4\u591a\u4e2a\u952e\u7684\u5176\u4ed6\u89c2\u6d4b\u6570\u636e\uff08\u8fd9\u91cc\uff0c\u6211\u4eec\u7684\u952e\u662fdate\u548citem\uff09\u3002 \u8868\u4e2d\u7684\u6bcf\u4e00\u884c\u8868\u793a\u4e00\u4e2a\u65f6\u95f4\u70b9\u4e0a\u7684\u5355\u4e2a\u89c2\u6d4b\u503c\u3002 ldata = data.stack().reset_index().rename(columns={0: 'value'}) print(ldata) # date item value # 0 1959-03-31 23:59:59.999999999 realgdp 2710.349 # 1 1959-03-31 23:59:59.999999999 infl 0.000 # 2 1959-03-31 23:59:59.999999999 unemp 5.800 # 3 1959-06-30 23:59:59.999999999 realgdp 2778.801 # 4 1959-06-30 23:59:59.999999999 infl 2.340 # .. ... ... ... # 604 2009-06-30 23:59:59.999999999 infl 3.370 # 605 2009-06-30 23:59:59.999999999 unemp 9.200 # 606 2009-09-30 23:59:59.999999999 realgdp 12990.341 # 607 2009-09-30 23:59:59.999999999 infl 3.560 # 608 2009-09-30 23:59:59.999999999 unemp 9.600 # [609 rows x 3 columns] \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff1a \u6570\u636e\u901a\u5e38\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u5b58\u50a8\u5728\u5173\u7cfb\u578b\u6570\u636e\u5e93\u4e2d\uff0c\u6bd4\u5982MySQL\uff0c\u56e0\u4e3a\u56fa\u5b9a\u6a21\u5f0f\uff08\u5217\u540d\u79f0\u548c\u6570\u636e\u7c7b\u578b\uff09\u5141\u8bb8 item \u5217\u4e2d\u4e0d\u540c\u503c\u7684\u6570\u91cf\u968f\u7740\u6570\u636e\u88ab\u6dfb\u52a0\u5230\u8868\u4e2d\u800c\u6539\u53d8\u3002 date \u548c item \u901a\u5e38\u662f\u4e3b\u952e\uff08\u4f7f\u7528\u5173\u7cfb\u578b\u6570\u636e\u5e93\u7684\u8bf4\u6cd5\uff09\uff0c\u63d0\u4f9b\u4e86\u5173\u7cfb\u5b8c\u6574\u6027\u548c\u66f4\u7b80\u5355\u7684\u8fde\u63a5\u3002 \u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\uff0c\u5904\u7406\u8fd9\u79cd\u683c\u5f0f\u7684\u6570\u636e\u66f4\u4e3a\u56f0\u96be\u3002\u53ef\u80fd\u66f4\u503e\u5411\u4e8e\u83b7\u53d6\u4e00\u4e2a\u6309 date \u5217\u65f6\u95f4\u6233\u7d22\u5f15\u7684\u4e14\u6bcf\u4e2a\u4e0d\u540c\u7684 item \u72ec\u7acb\u4e00\u5217\u7684DataFrame\u3002 DataFrame\u7684pivot\u65b9\u6cd5\u5c31\u662f\u8fdb\u884c\u8fd9\u79cd\u8f6c\u6362\u7684\uff1a \u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c\u4f20\u9012\u7684\u524d\u4e24\u4e2a\u503c\u662f\u5206\u522b\u7528\u4f5c\u884c\u548c\u5217\u7d22\u5f15\u7684\u5217\uff0c\u7136\u540e\u662f\u53ef\u9009\u7684\u6570\u503c\u5217\u4ee5\u586b\u5145DataFrame\u3002 \u6ce8\u610f\uff0c pivot \u65b9\u6cd5\u7b49\u4ef7\u4e8e\u4f7f\u7528 set_index \u521b\u5efa\u5206\u5c42\u7d22\u5f15\uff0c\u7136\u540e\u8c03\u7528unstack\u3002 pivoted = ldata.pivot('date', 'item', 'value') print(pivoted) # item infl realgdp unemp # date # 1959-03-31 23:59:59.999999999 0.00 2710.349 5.8 # 1959-06-30 23:59:59.999999999 2.34 2778.801 5.1 # ... ... ... ... # 2009-06-30 23:59:59.999999999 3.37 12901.504 9.2 # 2009-09-30 23:59:59.999999999 3.56 12990.341 9.6 # [203 rows x 3 columns] ldata['value2'] = np.random.randn(len(ldata)) print(ldata[:5]) # date item value value2 # 0 1959-03-31 23:59:59.999999999 realgdp 2710.349 -1.268405 # 1 1959-03-31 23:59:59.999999999 infl 0.000 0.377691 # 2 1959-03-31 23:59:59.999999999 unemp 5.800 -0.342492 # 3 1959-06-30 23:59:59.999999999 realgdp 2778.801 0.132797 # 4 1959-06-30 23:59:59.999999999 infl 2.340 0.180290 \u6b64\u65f6 ldata \u5df2\u7ecf\u6dfb\u52a0\u4e86\u4e00\u5217\u3002\u5982\u679c\u9057\u6f0f\u6700\u540e\u4e00\u4e2a\u53c2\u6570\uff0c\u4f1a\u5f97\u5230\u4e00\u4e2a\u542b\u6709\u591a\u5c42\u5217\u7684DataFrame\uff0c\u5982\u4e0b\uff1a pivoted = ldata.pivot('date', 'item') print(pivoted) # value ... value2 # item infl realgdp ... realgdp unemp # date ... # 1959-03-31 23:59:59.999999999 0.00 2710.349 ... 0.157467 -0.222464 # 1959-06-30 23:59:59.999999999 2.34 2778.801 ... 0.861501 0.368855 # ... ... ... ... ... ... # 2009-06-30 23:59:59.999999999 3.37 12901.504 ... 0.279988 0.934972 # 2009-09-30 23:59:59.999999999 3.56 12990.341 ... 0.547914 1.842967 # [203 rows x 6 columns] \u6ce8\u610f\uff0c pivot \u65b9\u6cd5\u7b49\u4ef7\u4e8e\u4f7f\u7528 set_index \u521b\u5efa\u5206\u5c42\u7d22\u5f15\uff0c\u7136\u540e\u8c03\u7528 unstack \u3002 unstacked = ldata.set_index(['date', 'item']).unstack('item') print(unstacked[:5]) # value ... value2 # item infl realgdp ... realgdp unemp # date ... # 1959-03-31 23:59:59.999999999 0.00 2710.349 ... 0.213120 -0.248004 # 1959-06-30 23:59:59.999999999 2.34 2778.801 ... 0.697763 0.112388 # 1959-09-30 23:59:59.999999999 2.74 2775.488 ... 1.291884 -1.046142 # 1959-12-31 23:59:59.999999999 0.27 2785.204 ... 0.363339 -0.307364 # 1960-03-31 23:59:59.999999999 2.31 2847.699 ... 0.377330 2.272980 # [5 rows x 6 columns]","title":"\u5c06\u201c\u957f\u201d\u900f\u89c6\u4e3a\u201c\u5bbd\u201d"},{"location":"python/DataAnalysis/ch05/#_12","text":"\u5728DataFrame\u4e2d\uff0cpivot\u65b9\u6cd5\u7684\u53cd\u64cd\u4f5c\u662f pandas.melt \u3002 \u4e0e\u5c06\u4e00\u5217\u53d8\u6362\u4e3a\u65b0\u7684DataFrame\u4e2d\u7684\u591a\u5217\u4e0d\u540c\uff0c\u5b83\u5c06\u591a\u5217\u5408\u5e76\u6210\u4e00\u5217\uff0c\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684DataFrame\uff0c\u5176\u957f\u5ea6\u6bd4\u8f93\u5165\u66f4\u957f\u3002 df = pd.DataFrame( { 'key': ['foo', 'bar', 'baz'], 'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9] } ) print(df) # key A B C # 0 foo 1 4 7 # 1 bar 2 5 8 # 2 baz 3 6 9 key \u5217\u53ef\u4ee5\u4f5c\u4e3a\u5206\u7ec4\u6307\u6807\uff0c\u5176\u4ed6\u5217\u5747\u4e3a\u6570\u636e\u503c\u3002 \u5f53\u4f7f\u7528 pandas.melt \u65f6\uff0c\u6211\u4eec\u5fc5\u987b\u6307\u660e\u54ea\u4e9b\u5217\u662f\u5206\u7ec4\u6307\u6807\uff08\u5982\u679c\u6709\u7684\u8bdd\uff09\u3002 \u6b64\u5904\uff0c\u8ba9\u6211\u4eec\u4f7f\u7528 key \u4f5c\u4e3a\u552f\u4e00\u7684\u5206\u7ec4\u6307\u6807\uff1a melted = pd.melt(df, ['key']) print(melted) # key variable value # 0 foo A 1 # 1 bar A 2 # 2 baz A 3 # 3 foo B 4 # 4 bar B 5 # 5 baz B 6 # 6 foo C 7 # 7 bar C 8 # 8 baz C 9 \u4f7f\u7528 pivot \u65b9\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u5c06\u6570\u636e\u91cd\u5851\u56de\u539f\u5148\u7684\u5e03\u5c40\u3002 reshaped = melted.pivot('key', 'variable', 'value') print(reshaped) # variable A B C # key # bar 2 5 8 # baz 3 6 9 # foo 1 4 7 \u7531\u4e8e pivot \u7684\u7ed3\u679c\u6839\u636e\u4f5c\u4e3a\u884c\u6807\u7b7e\u7684\u5217\u751f\u6210\u4e86\u7d22\u5f15\uff0c\u53ef\u4f7f\u7528 reset_index \u6765\u5c06\u6570\u636e\u56de\u79fb\u4e00\u5217\uff1a print(reshaped.reset_index()) # variable key A B C # 0 bar 2 5 8 # 1 baz 3 6 9 # 2 foo 1 4 7 pandas.melt \u7684\u4f7f\u7528\u4e5f\u53ef\u4ee5\u65e0\u987b\u4efb\u4f55\u5206\u7ec4\u6307\u6807\u3002 result = pd.melt(df, value_vars=['A', 'B', 'C']) print(result) # variable value # 0 A 1 # 1 A 2 # 2 A 3 # 3 B 4 # 4 B 5 # 5 B 6 # 6 C 7 # 7 C 8 # 8 C 9 result = pd.melt(df, value_vars=['key', 'B', 'C']) print(result) # variable value # 0 key foo # 1 key bar # 2 key baz # 3 B 4 # 4 B 5 # 5 B 6 # 6 C 7 # 7 C 8 # 8 C 9","title":"\u5c06\u201c\u5bbd\u201d\u900f\u89c6\u4e3a\u201c\u957f\u201d"},{"location":"python/DataAnalysis/ch06/","text":"\u7ed8\u56fe\u4e0e\u53ef\u89c6\u5316 \u00b6 \u7b80\u660ematplotlib API\u5165\u95e8 \u00b6 import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np import pandas as pd from io import BytesIO \u6267\u884c plt.show() \u65f6\u62a5\u9519\uff1a UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure. \u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u5f97\u5230 plt \u7684 backend \u662f\u7528 agg \u3002 plt.get_backend() \u4f8b\u5982\uff1a\u4e0b\u9762\u4e24\u79cd\u8868\u8fbe\u65b9\u5f0f\u6548\u679c\u4e00\u6837\u3002 ax.plot(x, y, 'g--') ax.plot(x, y, linestyle='--', color='g') Out[6]: 'agg' \u5b89\u88c5\u4e0b\u9762\u51e0\u4e2a\u5305\uff1a sudo zypper in python-tk python3-tk sudo zypper in plplot-tcltk-devel plplot-tcltk-libs pip install tk \u6dfb\u52a0\u4e0b\u9762\u5230python\u4ee3\u7801\u4e2d\u3002 import matplotlib.pyplot as plt mpl.use('TkAgg') \u6267\u884c\u540e\u62a5\u4e0b\u9762\u9519\u8bef\uff1a your Python may not be configured for Tk \u8fdb\u5165python\u6e90\u7801\u76ee\u5f55\uff0c\u91cd\u65b0\u7f16\u8bd1\u4f8b\u5982\uff1a\u4e0b\u9762\u4e24\u79cd\u8868\u8fbe\u65b9\u5f0f\u6548\u679c\u4e00\u6837\u3002 ax.plot(x, y, 'g--') ax.plot(x, y, linestyle='--', color='g') james@lizard:/opt/Python-3.9.6> sudo make james@lizard:/opt/Python-3.9.6> sudo make install \u95ee\u9898\u89e3\u51b3\uff0c\u5373\u4f7f\u4e0d\u52a0\u5165 mpl.use('TkAgg') \uff0c\u6267\u884c plt.show() \u4e5f\u662f\u53ef\u4ee5\u8f93\u51fa\u56fe\u50cf\u3002 \u56fe\u7247\u4e0e\u5b50\u56fe \u00b6 matplotlib \u6240\u7ed8\u5236\u7684\u56fe\u4f4d\u4e8e\u56fe\u7247\uff08Figure\uff09\u5bf9\u8c61\u4e2d\u3002\u53ef\u4ee5\u4f7f\u7528 plt.figure \u751f\u6210\u4e00\u4e2a\u65b0\u7684\u56fe\u7247\u3002 \u4f7f\u7528 add_subplot \u521b\u5efa\u4e00\u4e2a\u6216\u591a\u4e2a\u5b50\u56fe\uff08subplot\uff09\u3002 plt \u4e0e ax \u7ed8\u56fe\u3002 fig = plt.figure() # plt: \u5148\u751f\u6210\u4e86\u4e00\u4e2a\u753b\u5e03\uff0c\u7136\u540e\u5728\u8fd9\u4e2a\u753b\u5e03\u4e0a\u9690\u5f0f\u7684\u751f\u6210\u4e00\u4e2a\u753b\u56fe\u533a\u57df\u6765\u8fdb\u884c\u753b\u56fe # plt.plot([1, 2, 3, 4]) # plt.show() # ax: \u5148\u751f\u6210\u4e00\u4e2a\u753b\u5e03\uff082\u00d72\u7684\u533a\u57df\uff0c\u6700\u591a\u653e\u56db\u4e2a\u56fe\u5f62\uff09\uff0c\u7136\u540e\u5728\u6b64\u753b\u5e03\u4e0a\uff0c\u9009\u5b9a\u4e00\u4e2a\u5b50\u533a\u57df\u753b\u4e86\u4e00\u4e2a\u5b50\u56fe\uff08\u5e8f\u53f71\u4ee3\u8868\u7b2c\u4e00\u4e2a\u533a\u57df\uff09 ax1 = fig.add_subplot(2, 2, 1) # \u4e5f\u53ef\u4ee5\u5199\u6210fig.add_subplot(221) ax1.plot([1, 2, 3, 4], [1, 4, 3, 2]) # \u8f93\u51fa\u56fe\u7247\u5230\u7b2c\u4e00\u4e2a\u533a\u57df\u3002 # \u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u6570\u636e\u96c6\u91cc\u5404\u4e2a\u6570\u636e\u70b9\u7684X\u503c\u7684\u96c6\u5408 # \u7b2c\u4e8c\u4e2a\u53c2\u6570\u6570\u636e\u96c6\u91cc\u5404\u4e2a\u6570\u636e\u70b9\u7684Y\u503c\u7684\u96c6\u5408\u3002 # \u4e0d\u662f\u6570\u5b66\u4e0a\u5e38\u89c1\u7684\u6210\u5bf9\u5750\u6807\u70b9\u5982(x1,y1)\u3001(x2,y2)\u3001...\u3001(xn,yn)\u7684\u683c\u5f0f\uff0c\u800c\u662f (x1,x2,...,xn)\u548c(y1,y2,...,yn) \u3002 plt.show() \u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u589e\u52a0\u5b50\u56fe\u540e\u7684\u6570\u636e\u53ef\u89c6\u5316\u6548\u679c\u3002 fig = plt.figure() ax1 = fig.add_subplot(2, 2, 1) ax2 = fig.add_subplot(2, 2, 2) ax3 = fig.add_subplot(2, 2, 3) ax1.plot(np.random.randn(50).cumsum(), 'k--') # \u5728\u7b2c\u4e09\u4e2a\u533a\u57df\u8f93\u51fa\u56fe\u50cf\u3002'k--\u2019\u662f\u7528\u4e8e\u7ed8\u5236\u9ed1\u8272\u5206\u6bb5\u7ebf\u7684style\u9009\u9879\u3002 ax2.hist(np.random.randn(100), bins=20, color='k', alpha=0.3) ax3.scatter(np.arange(30), np.arange(30) + 3 * np.random.randn(30)) plt.show() plt.subplots \u901a\u8fc7 matplotlib \u7684 subplots \u65b9\u6cd5\uff0c\u4f7f\u7528\u5b50\u56fe\u7f51\u683c\u521b\u5efa\u56fe\u7247\uff0c\u7136\u540e\u8fd4\u56de\u5305\u542b\u4e86\u5df2\u751f\u6210\u5b50\u56fe\u5bf9\u8c61\u7684NumPy\u6570\u7ec4\u3002 \u6570\u7ec4 axes \u53ef\u4ee5\u50cf\u4e8c\u7ef4\u6570\u7ec4\u90a3\u6837\u65b9\u4fbf\u5730\u8fdb\u884c\u7d22\u5f15\uff0c\u4f8b\u5982\uff0c axes[0, 1] \u3002 plt.subplots \u53c2\u6570\u9009\u9879\uff1a nrows\uff1a\u53ef\u9009\u7684\uff0c\u6574\u578b\uff0c\u9ed8\u8ba4\u4e3a1\u3002\u5b50\u56fe\u7f51\u683c\u7684\u884c\u6570\u3002 ncols\uff1a\u53ef\u9009\u7684\uff0c\u6574\u578b\uff0c\u9ed8\u8ba4\u4e3a1\u3002\u5b50\u56fe\u7f51\u683c\u7684\u5217\u6570\u3002 sharex\uff1a\u53ef\u9009\u7684\uff0c\u9ed8\u8ba4\u4e3aFalse\u3002\u53ef\u9009\u503c\u5982\u4e0b\uff1a True\u6216all\uff0c\u6240\u6709\u5b50\u56fe\u5171\u4eabx\u8f74 False\u6216none\uff0c\u6bcf\u4e2a\u5b50\u56fe\u7684x\u8f74\u90fd\u662f\u72ec\u7acb\u7684 row\uff0c\u6bcf\u884c\u5b50\u56fe\u5171\u4eab\u4e00\u4e2ax\u8f74 col\uff0c\u6bcf\u5217\u5b50\u56fe\u5171\u4eab\u4e00\u4e2ax\u8f74 sharey\uff1a\u7c7b\u4f3c\u4e8esharex\uff0c\u8bbe\u7f6ey\u8f74\u7684\u5171\u4eab\u65b9\u5f0f\u3002\u5f53\u67d0\u5217\u5171\u4eab\u4e00\u4e2ax\u8f74\u65f6\uff0c\u53ea\u6709\u5e95\u90e8\u7684\u5b50\u56fe\u4f1a\u521b\u5efax\u8f74\u6807\u8bb0\u3002\u540c\u6837\u7684\uff0c\u5982\u679c\u67d0\u884c\u5171\u4eab\u4e00\u4e2ay\u8f74\u65f6\uff0c\u53ea\u6709\u884c\u7684\u7b2c\u4e00\u5217\u5b50\u56fe\u4f1a\u521b\u5efay\u8f74\u6807\u8bb0\u3002 squeeze \uff1a\u53ef\u9009\u7684\uff0c\u5e03\u5c14\u578b\uff0c\u9ed8\u8ba4\u4e3aTrue\u3002\u662f\u5426\u538b\u7f29\u8fd4\u56de\u7684Axes\u6570\u7ec4\u3002\u5982\u679c\u4e3aTrue\uff0c\u5f53\u53ea\u6709\u4e00\u4e2a\u5b50\u56fe\uff0c\u5373nrows\u548cncols\u5747\u4e3a1\u65f6\uff0c\u8fd4\u56de\u4e00\u4e2a\u5355\u72ec\u7684Axes\u5bf9\u8c61\uff0c\u5f53\u6709N*1\u548c1*M\u4e2a\u5b50\u56fe\u65f6\uff0c\u8fd4\u56de\u4e00\u4e2a\u4e00\u7ef4Axes\u5bf9\u8c61\u6570\u7ec4\u3002\u5f53\u6709N*M\u4e2a\u5b50\u56fe\uff08N>1\uff0cM>1\uff09\u65f6\uff0c\u8fd4\u56de\u4e8c\u7ef4\u6570\u7ec4\u3002\u5982\u679c\u4e3aFalse\uff0c\u5219\u603b\u662f\u8fd4\u56de\u4e8c\u7ef4\u6570\u7ec4\u3002 num\uff1a\u53ef\u9009\u7684\uff0c\u6574\u578b\u6216\u5b57\u7b26\u4e32\uff0c\u9ed8\u8ba4\u4e3aNone\u3002\u662fmatplotlib.pyplot.figure\u7684\u5173\u952e\u5b57\uff0c\u7528\u4e8e\u8bbe\u7f6e\u56fe\u50cf\u6570\u5b57\u6216\u6807\u7b7e\u3002\u5982\u679c\u672a\u8bbe\u7f6e\u6b64\u53c2\u6570\uff0c\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u56fe\u50cf\uff0c\u5e76\u9012\u589e\u56fe\u50cf\u7f16\u53f7\uff0cfigure\u5bf9\u8c61\u4f1a\u5c06\u7f16\u53f7\u4fdd\u5b58\u5728number\u5c5e\u6027\u4e2d\u3002\u5982\u679c\u8bbe\u7f6e\u4e86\u6b64\u53c2\u6570\uff0c\u5e76\u4e14\u5b58\u5728\u53c2\u6570\u6307\u5b9a\u7684\u56fe\u50cf\uff0c\u5219\u4f1a\u8fd4\u56de\u6b64\u56fe\u50cf\u7684\u5f15\u7528\uff0c\u5982\u679c\u4e0d\u5b58\u5728\u5219\u4f1a\u521b\u5efa\u65b0\u7684\u56fe\u50cf\u5e76\u8fd4\u56de\u5b83\u7684\u5f15\u7528\u3002\u5982\u679c\u662f\u5b57\u7b26\u4e32\uff0c\u5219\u7a97\u53e3\u6807\u9898\u4f1a\u88ab\u8bbe\u7f6e\u4e3a\u6b64\u5b57\u7b26\u4e32\u7684\u503c\u3002 subplot_kw\uff1a\u53ef\u9009\u7684\uff0c\u5b57\u5178\u7c7b\u578b\u3002\u5305\u542b\u4f20\u9012\u7ed9\u7528\u4e8e\u521b\u5efa\u5b50\u56fe\u7684\u8c03\u7528add_subplot\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 gridspec_kw\uff1a\u53ef\u9009\u7684\uff0c\u5b57\u5178\u7c7b\u578b\u3002\u5305\u542b\u4f20\u9012\u7ed9\u7528\u4e8e\u521b\u5efa\u5b50\u56fe\u7f51\u683c\u7684GridSpec\u6784\u9020\u51fd\u6570\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 fig, axes = plt.subplots(2, 3) print(axes) # \u5c06\u751f\u6210\u7684axes\u5bf9\u8c61\u653e\u5165NumPy\u6570\u7ec4\u3002 # [[ ] # [ ]] \u8c03\u6574\u5b50\u56fe\u5468\u56f4\u7684\u95f4\u8ddd\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c matplotlib \u4f1a\u5728\u5b50\u56fe\u7684\u5916\u90e8\u548c\u5b50\u56fe\u4e4b\u95f4\u7559\u51fa\u4e00\u5b9a\u7684\u95f4\u8ddd\u3002 \u8fd9\u4e2a\u95f4\u8ddd\u90fd\u662f\u76f8\u5bf9\u4e8e\u56fe\u7684\u9ad8\u5ea6\u548c\u5bbd\u5ea6\u6765\u6307\u5b9a\u7684\uff0c\u624b\u52a8\u8c03\u6574\u56fe\u7684\u5927\u5c0f\uff0c\u90a3\u4e48\u95f4\u8ddd\u4f1a\u81ea\u52a8\u8c03\u6574\u3002 \u4e5f\u53ef\u4ee5\u4f7f\u7528\u56fe\u5bf9\u8c61\u4e0a\u7684 subplots_adjust \u65b9\u6cd5\u66f4\u6539\u95f4\u8ddd\uff0c\u4e5f\u53ef\u4ee5\u7528\u4f5c\u9876\u5c42\u51fd\u6570\u3002 fig, axes = plt.subplots(2, 2, sharex=True, sharey=True) for i in range(2): for j in range(2): axes[i, j].hist(np.random.randn(500), bins=50, color='k', alpha=0.5) plt.subplots_adjust(wspace=0, hspace=0) plt.show() \u4e0a\u9762\u8f93\u51fa\u56fe\u50cf\u7684\u8f74\u6807\u7b7e\u662f\u5b58\u5728\u91cd\u53e0\u7684\u3002 matplotlib \u5e76\u4e0d\u68c0\u67e5\u6807\u7b7e\u662f\u5426\u91cd\u53e0\uff0c\u56e0\u6b64\u5728\u7c7b\u4f3c\u60c5\u51b5\u4e0b\u4f60\u9700\u8981\u901a\u8fc7\u663e\u5f0f\u6307\u5b9a\u523b\u5ea6\u4f4d\u7f6e\u548c\u523b\u5ea6\u6807\u7b7e\u7684\u65b9\u6cd5\u6765\u4fee\u590d\u8f74\u6807\u7b7e\u3002 \u989c\u8272\u3001\u6807\u8bb0\u548c\u7ebf\u7c7b\u578b \u00b6 matplotlib \u7684\u4e3b\u51fd\u6570 plot \u63a5\u6536\u5e26\u6709 x \u548c y \u8f74\u7684\u6570\u7ec4\u4ee5\u53ca\u4e00\u4e9b\u53ef\u9009\u7684\u5b57\u7b26\u4e32\u7f29\u5199\u53c2\u6570\u6765\u6307\u660e\u989c\u8272\u548c\u7ebf\u7c7b\u578b\u3002 \u4f8b\u5982\uff1a\u4e0b\u9762\u4e24\u79cd\u8868\u8fbe\u65b9\u5f0f\u6548\u679c\u4e00\u6837\u3002 ax.plot(x, y, 'g--') ax.plot(x, y, linestyle='--', color='g') data = np.random.randn(30).cumsum() plt.plot(data, 'ko--') plt.show() # \u4e0a\u9762\u7684\u4ee3\u7801\u53ef\u4ee5\u5199\u5f97\u66f4\u4e3a\u663e\u5f0f\uff1a plt.plot(data, color='k', linestyle='dashed', marker='o') plt.show() plt.plot(data, color='k', linestyle='dashed', marker='o', label='Default') plt.show() plt.plot(data, color='k', linestyle='dashed', marker='o', label='steps-post', drawstyle='steps-post') plt.show() \u523b\u5ea6\u3001\u6807\u7b7e\u548c\u56fe\u4f8b \u00b6 \u5bf9\u4e8e\u5927\u591a\u6570\u56fe\u8868\u4fee\u9970\u5de5\u4f5c\uff0c\u6709\u4e24\u79cd\u4e3b\u8981\u7684\u65b9\u5f0f\uff1a\u4f7f\u7528\u7a0b\u5e8f\u6027\u7684pyplot\u63a5\u53e3\uff08\u5373matplotlib.pyplot\uff09\u548c\u66f4\u591a\u9762\u5411\u5bf9\u8c61\u7684\u539f\u751fmatplotlib API\u3002 pyplot \u63a5\u53e3\u8bbe\u8ba1\u4e3a\u4ea4\u4e92\u5f0f\u4f7f\u7528\uff0c\u5305\u542b\u4e86\u50cf xlim \u3001 xticks \u548c xticklabels \u7b49\u65b9\u6cd5\u3002\u8fd9\u4e9b\u65b9\u6cd5\u5206\u522b\u63a7\u5236\u4e86\u7ed8\u56fe\u8303\u56f4\u3001\u523b\u5ea6\u4f4d\u7f6e\u4ee5\u53ca\u523b\u5ea6\u6807\u7b7e\u3002 \u5728\u6ca1\u6709\u51fd\u6570\u53c2\u6570\u7684\u60c5\u51b5\u4e0b\u8c03\u7528\uff0c\u8fd4\u56de\u5f53\u524d\u7684\u53c2\u6570\u503c\uff08\u4f8b\u5982 plt.xlim() \u8fd4\u56de\u5f53\u524d\u7684x\u8f74\u7ed8\u56fe\u8303\u56f4\uff09\u3002 \u4f20\u5165\u53c2\u6570\u7684\u60c5\u51b5\u4e0b\u8c03\u7528\uff0c\u5e76\u8bbe\u7f6e\u53c2\u6570\u503c\uff08\u4f8b\u5982 plt.xlim\uff08[0, 10]\uff09 \u4f1a\u5c06 x \u8f74\u7684\u8303\u56f4\u8bbe\u7f6e\u4e3a0\u523010\uff09\u3002 \u6240\u6709\u7684\u8fd9\u4e9b\u65b9\u6cd5\u90fd\u4f1a\u5728\u5f53\u524d\u6d3b\u52a8\u7684\u6216\u6700\u8fd1\u521b\u5efa\u7684 AxesSubplot \u4e0a\u751f\u6548\u3002 \u8fd9\u4e9b\u65b9\u6cd5\u4e2d\u7684\u6bcf\u4e00\u4e2a\u5bf9\u5e94\u4e8e\u5b50\u56fe\u81ea\u8eab\u7684\u4e24\u4e2a\u65b9\u6cd5\u3002\u6bd4\u5982 xlim \u5bf9\u5e94\u4e8e ax.get_lim \u548c ax.set_lim \u3002 \u63a8\u8350\u4f7f\u7528 subplot \u7684\u5b9e\u4f8b\u65b9\u6cd5\uff0c\u56e0\u4e3a\u8fd9\u6837\u66f4\u4e3a\u663e\u5f0f\uff08\u5c24\u5176\u662f\u5728\u5904\u7406\u591a\u4e2a\u5b50\u56fe\u65f6\uff09\u3002 data = np.random.randn(1000).cumsum() fig = plt.figure() # \u8bbe\u5b9a\u5b50\u56fe ax = fig.add_subplot(1, 1, 1) # \u8bbe\u5b9ax\u8f74\u5bf9\u5e94\u53c2\u6570\uff1a # \u8bbe\u5b9ax\u8f74\u523b\u5ea6 ax.set_xticks([0, 250, 500, 750, 1000]) # \u8bbe\u5b9ax\u8f74\u6807\u7b7e ax.set_xticklabels(['one(0)', 'two(250)', 'three(500)', 'four(750)', 'five(1000)'], rotation=30, fontsize='small') # \u7ed9x\u8f74\u4e00\u4e2a\u540d\u79f0 ax.set_xlabel('Stages') # \u8bbe\u5b9ay\u8f74\u5bf9\u5e94\u53c2\u6570\uff1a # \u672a\u6307\u5b9a\u7684\u53c2\u6570\u7531\u7cfb\u7edf\u9ed8\u8ba4\u4ea7\u751f\u3002 ax.set_ylabel('Steps') # \u7ed9\u5b50\u56fe\u6dfb\u52a0\u4e00\u4e2a\u6807\u9898 ax.set_title('My first matplotlib plot') # \u7ed9\u5b50\u56fe\u6dfb\u52a0\u4e00\u4e2a\u56fe\u4f8b\uff08\u5982\uff1a\u7ed9\u5b50\u56fe\u5185\u4e00\u4e2a\u56fe\u5f62\u66f2\u7ebf\u6dfb\u52a0\u4e00\u4e2alabel\uff09 ax.plot(data, 'k--', label='Label One') # loc\u53c2\u6570\u544a\u8bc9matplotlib\u5728\u54ea\u91cc\u653e\u7f6e\u56fe\u8868\u3002legend\u65b9\u6cd5\u6709\u591a\u4e2a\u5176\u4ed6\u7684\u4f4d\u7f6e\u53c2\u6570loc\u3002 ax.legend(loc='best') # \u6216\u8005plt.legend(loc='best') \u3002 # \u5728\u56fe\u5f62\u5750\u6807\u4e3a(0, 0)\u7684\u4f4d\u7f6e\u6dfb\u52a0\u4e00\u4e2alable ax.text(0, 0, 'Hello World1', family='monospace', fontsize=10) # \u7ed9\u5b50\u56fe\u6dfb\u52a0annotate\u3002\u7528\u4e00\u4e2a\u7bad\u5934\u6307\u5411\u8981\u6ce8\u91ca\u7684\u5730\u65b9\uff0c\u518d\u5199\u4e0a\u4e00\u6bb5\u8bdd\u7684\u884c\u4e3a\uff0c\u53eb\u505aannotate\u3002 # * s: \u6ce8\u91ca\u7684\u5185\u5bb9\uff0c\u4e00\u6bb5\u6587\u5b57\uff1b # * xytext: \u8fd9\u6bb5\u6587\u5b57\u6240\u5904\u7684\u4f4d\u7f6e; # * xy: \u7bad\u5934\u6307\u5411\u7684\u4f4d\u7f6e\uff1b # * arrowprops: \u901a\u8fc7arrowstyle\u8868\u660e\u7bad\u5934\u7684\u98ce\u683c\u6216\u79cd\u7c7b\u3002 ax.annotate('Zero is here!', xytext=(20, 20), xy=(1, 1), arrowprops=dict(arrowstyle='->')) # \u7ed9\u5b50\u56fe\u6dfb\u52a0\u4e00\u4e9b\u56fe\u5f62 # matplotlib\u542b\u6709\u8868\u793a\u591a\u79cd\u5e38\u89c1\u56fe\u5f62\u7684\u5bf9\u8c61\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u7684\u5f15\u7528\u662fpatches\u3002 # \u4e00\u4e9b\u56fe\u5f62\uff0c\u6bd4\u5982Rectangle\uff08\u77e9\u5f62\uff09\u548cCircle\uff08\u5706\u5f62\uff09\uff0c\u53ef\u4ee5\u5728matplotlib.pyplot\u4e2d\u627e\u5230\uff0c\u4f46\u56fe\u5f62\u7684\u5168\u96c6\u4f4d\u4e8ematplotlib.patches\u3002 rect = plt.Rectangle((10, 5), 100, 15, color='k', alpha=0.3) circ = plt.Circle((200, 9), 95, color='b', alpha=0.3) pgon = plt.Polygon([[500, 5], [600, -5], [700, 30]], color='g', alpha=0.5) ax.add_patch(rect) ax.add_patch(circ) ax.add_patch(pgon) # \u5c06\u56fe\u7247\u4fdd\u5b58\u5230\u6587\u4ef6 # \u6587\u4ef6\u7c7b\u578b\u662f\u4ece\u6587\u4ef6\u6269\u5c55\u540d\u4e2d\u63a8\u65ad\u51fa\u6765\u7684\u3002\u6240\u4ee5\u5982\u679c\u4f60\u4f7f\u7528\uff0epdf\uff0c\u5219\u4f1a\u5f97\u5230\u4e00\u4e2aPDF\u3002 # \u51e0\u4e2a\u91cd\u8981\u7684\u9009\u9879\uff1adpi\uff0c\u5b83\u63a7\u5236\u6bcf\u82f1\u5bf8\u70b9\u6570\u7684\u5206\u8fa8\u7387\uff1bbbox_inches\uff0c\u53ef\u4ee5\u4fee\u526a\u5b9e\u9645\u56fe\u5f62\u7684\u7a7a\u767d\u3002 plt.savefig('../examples/figpath.png', dpi=400, bbox_inches='tight') # saveifg\u5e76\u975e\u4e00\u5b9a\u662f\u5199\u5230\u786c\u76d8\u7684\uff0c\u5b83\u53ef\u4ee5\u5c06\u56fe\u7247\u5199\u5165\u5230\u6240\u6709\u7684\u6587\u4ef6\u578b\u5bf9\u8c61\u4e2d\uff0c\u4f8b\u5982BytesIO buffer = BytesIO() plt.savefig(buffer) plot_data = buffer.getvalue() plt.show() matplotlib\u8bbe\u7f6e \u00b6 matplotlib \u914d\u7f6e\u4e86\u914d\u8272\u65b9\u6848\u548c\u9ed8\u8ba4\u8bbe\u7f6e\uff0c\u901a\u8fc7\u5168\u5c40\u53c2\u6570\u6765\u5b9a\u5236\uff0c\u5305\u62ec\u56fe\u5f62\u5927\u5c0f\u3001\u5b50\u56fe\u95f4\u8ddd\u3001\u989c\u8272\u3001\u5b57\u4f53\u5927\u5c0f\u548c\u7f51\u683c\u6837\u5f0f\u7b49\u7b49\u3002 \u4f7f\u7528 rc \u65b9\u6cd5\u662f\u4f7f\u7528Python\u7f16\u7a0b\u4fee\u6539\u914d\u7f6e\u7684\u4e00\u79cd\u65b9\u5f0f\u3002 rc \u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u4f60\u60f3\u8981\u81ea\u5b9a\u4e49\u7684\u7ec4\u4ef6\uff0c\u6bd4\u5982 'figure'\u3001'axes'\u3001'xtick'\u3001'ytick'\u3001'grid'\u3001'legend' \u7b49\u7b49\u3002 \u4e4b\u540e\uff0c\u53ef\u4ee5\u6309\u7167\u5173\u952e\u5b57\u53c2\u6570\u7684\u5e8f\u5217\u6307\u5b9a\u65b0\u53c2\u6570\u3002 \u5b57\u5178\u662f\u4e00\u79cd\u5728\u7a0b\u5e8f\u4e2d\u8bbe\u7f6e\u9009\u9879\u7684\u7b80\u5355\u65b9\u5f0f\u3002\u6bd4\u5982\uff1a plt.rc('figure', figsize=(10, 10)) font_options = { 'family': 'monospace', 'weight': 'bold', 'size': 'small' } plt.rc('font', **font_options) \u4f7f\u7528pandas\u548cseaborn\u7ed8\u56fe \u00b6 pandas\u81ea\u8eab\u6709\u5f88\u591a\u5185\u5efa\u65b9\u6cd5\u53ef\u4ee5\u7b80\u5316\u4eceDataFrame\u548cSeries\u5bf9\u8c61\u751f\u6210\u53ef\u89c6\u5316\u7684\u8fc7\u7a0b\u3002 \u53e6\u4e00\u4e2a\u5e93\u662f seaborn \u3002 seaborn \u7b80\u5316\u4e86\u5f88\u591a\u5e38\u7528\u53ef\u89c6\u5316\u7c7b\u578b\u7684\u751f\u6210\u3002 \u5bfc\u5165 seaborn \u4f1a\u4fee\u6539\u9ed8\u8ba4\u7684matplotlib\u914d\u8272\u65b9\u6848\u548c\u7ed8\u56fe\u6837\u5f0f\uff0c\u8fd9\u4f1a\u63d0\u9ad8\u56fe\u8868\u7684\u53ef\u8bfb\u6027\u548c\u7f8e\u89c2\u6027\u3002 \u5373\u4f7f\u4e0d\u4f7f\u7528seaborn\u7684API\uff0c\u4e5f\u53ef\u4ee5\u5bfc\u5165seaborn\u6765\u4e3a\u901a\u7528matplotlib\u56fe\u8868\u63d0\u4f9b\u66f4\u597d\u7684\u89c6\u89c9\u7f8e\u89c2\u5ea6\u3002 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns \u6298\u7ebf\u56fe \u00b6 Series\u548cDataFrame\u90fd\u6709\u4e00\u4e2a plot \u5c5e\u6027\uff0c\u7528\u4e8e\u7ed8\u5236\u57fa\u672c\u7684\u56fe\u5f62\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c plot() \u7ed8\u5236\u7684\u662f\u6298\u7ebf\u56fe\u3002 Series\u7684 plot \u53c2\u6570\uff1a ax: matplotlib\u5b50\u56fe\u5bf9\u8c61axes\uff0c\u5982\u679c\u6ca1\u6709\u4f20\u503c\uff0c\u5219\u4f7f\u7528\u5f53\u524d\u6d3b\u52a8\u7684\u5b50\u56fe\u9ed8\u8ba4\u4f7f\u7528gca() alpha: \u56fe\u7247\u4e0d\u900f\u660e\u5ea6\uff080\u52301\uff09 data: \u6570\u636e\u5e8f\u5217Series figsize: \u56fe\u50cf\u5c3a\u5bf8\uff0ctuple(\u5bbd\u5ea6\uff0c\u9ad8\u5ea6)\uff0c\u6ce8\u610f\u8fd9\u91cc\u7684\u5355\u4f4d\u662f\u82f1\u5bf8 fontsize: \u8bbe\u7f6e\u523b\u5ea6\u6807\u7b7e\uff08xticks, yticks\uff09\u7684\u5927\u5c0f grid: \u7f51\u683c\u7ebf\uff08\u9ed8\u8ba4\u662f\u6253\u5f00\u7684\uff09 kind: \u56fe\u7c7b\u578b\uff1a\u6298\u7ebf\u56fe\uff0c\u67f1\u5f62\u56fe\uff0c\u6a2a\u5411\u67f1\u5f62\u56fe\uff0c\u76f4\u65b9\u56fe\uff0c\u7bb1\u7ebf\u56fe\uff0c\u5bc6\u5ea6\u56fe\uff0c\u9762\u79ef\u56fe\uff0c\u997c\u56fe label: \u5217\u7684\u522b\u540d\uff0c\u4f5c\u7528\u5728\u56fe\u4f8b\u4e0a legend: \u56fe\u4f8b loglog: x,y\u8f74\u90fd\u4f7f\u7528\u5bf9\u6570\u523b\u5ea6 logx: x\u8f74\u4f7f\u7528\u5bf9\u6570\u523b\u5ea6 logy: y\u8f74\u4f7f\u7528\u5bf9\u6570\u523b\u5ea6 mark_right: \u53cc y \u8f74\u65f6\uff0c\u5728\u56fe\u4f8b\u4e2d\u7684\u5217\u6807\u7b7e\u65c1\u589e\u52a0\u663e\u793a (right) \u6807\u8bc6 position: \u67f1\u5f62\u56fe\u7684\u67f1\u5b50\u7684\u4f4d\u7f6e\u8bbe\u7f6e rot: \u6539\u53d8\u523b\u5ea6\u6807\u7b7e\uff08xticks, yticks\uff09\u7684\u65cb\u8f6c\u5ea6\uff080\u5230360\uff09 secondary_y: \u53cc y \u8f74\uff0c\u5728\u53f3\u8fb9\u7684\u7b2c\u4e8c\u4e2a y \u8f74 style: \u7ebf\u7684\u6837\u5f0f\uff0c\u6bd4\u5982'ko--' table: \u5c06\u6570\u636e\u4ee5\u8868\u683c\u7684\u5f62\u5f0f\u5c55\u793a\u51fa\u6765 title: \u6807\u9898 use_index: \u662f\u5426\u4f7f\u7528\u7d22\u5f15\u4f5c\u4e3ax\u523b\u5ea6\u6807\u7b7e xerr: \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe xlim: \u6a2a\u8f74\u5750\u6807\u523b\u5ea6\u7684\u53d6\u503c\u8303\u56f4 xticks: x\u8f74\u523b\u5ea6\u6807\u7b7e yerr: \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe ylim: \u7eb5\u8f74\u5750\u6807\u523b\u5ea6\u7684\u53d6\u503c\u8303\u56f4 yticks: y\u8f74\u523b\u5ea6\u6807\u7b7e **kwds: matplotlib plot\u65b9\u6cd5\u7684\u5176\u4ed6\u53c2\u6570 DataFrame\u7684 plot \u53c2\u6570\uff1a x : \u6307\u6570\u636e\u6846\u5217\u7684\u6807\u7b7e\u6216\u4f4d\u7f6e\u53c2\u6570 y : \u6307\u6570\u636e\u6846\u5217\u7684\u6807\u7b7e\u6216\u4f4d\u7f6e\u53c2\u6570 kind : 'line' : \u6298\u7ebf\u56fe 'bar' : \u6761\u5f62\u56fe 'barh' : \u6a2a\u5411\u6761\u5f62\u56fe 'hist' : \u67f1\u72b6\u56fe 'box' : \u7bb1\u7ebf\u56fe 'kde' : Kernel\u7684\u5bc6\u5ea6\u4f30\u8ba1\u56fe\uff0c\u4e3b\u8981\u5bf9\u67f1\u72b6\u56fe\u6dfb\u52a0Kernel \u6982\u7387\u5bc6\u5ea6\u7ebf 'density' : 'kde' 'area' : area plot 'pie' : \u997c\u56fe 'scatter' : \u6563\u70b9\u56fe \u9700\u8981\u4f20\u5165columns\u65b9\u5411\u7684\u7d22\u5f15 'hexbin' : hexbin plot ax : \u5b50\u56fe(axes, \u4e5f\u53ef\u4ee5\u7406\u89e3\u6210\u5750\u6807\u8f74) \u8981\u5728\u5176\u4e0a\u8fdb\u884c\u7ed8\u5236\u7684matplotlib subplot\u5bf9\u8c61\u3002\u5982\u679c\u6ca1\u6709\u8bbe\u7f6e\uff0c\u5219\u4f7f\u7528\u5f53\u524dmatplotlib subplot\u3002\u5176\u4e2d\uff0c\u53d8\u91cf\u548c\u51fd\u6570\u901a\u8fc7\u6539\u53d8figure\u548caxes\u4e2d\u7684\u5143\u7d20\uff08\u4f8b\u5982\uff1atitle,label,\u70b9\u548c\u7ebf\u7b49\u7b49\uff09\u4e00\u8d77\u63cf\u8ff0figure\u548caxes\uff0c\u4e5f\u5c31\u662f\u5728\u753b\u5e03\u4e0a\u7ed8\u56fe\u3002 subplots : \u5224\u65ad\u56fe\u7247\u4e2d\u662f\u5426\u6709\u5b50\u56fe sharex : \u5982\u679c\u6709\u5b50\u56fe\uff0c\u5b50\u56fe\u5171x\u8f74\u523b\u5ea6\uff0c\u6807\u7b7e sharey : \u5982\u679c\u6709\u5b50\u56fe\uff0c\u5b50\u56fe\u5171y\u8f74\u523b\u5ea6\uff0c\u6807\u7b7e layout : \u5b50\u56fe\u7684\u884c\u5217\u5e03\u5c40 figsize : \u56fe\u7247\u5c3a\u5bf8\u5927\u5c0f use_index : \u9ed8\u8ba4\u7528\u7d22\u5f15\u505ax\u8f74 title : \u56fe\u7247\u7684\u6807\u9898\u7528\u5b57\u7b26\u4e32 grid : \u56fe\u7247\u662f\u5426\u6709\u7f51\u683c legend : \u5b50\u56fe\u7684\u56fe\u4f8b\uff0c\u6dfb\u52a0\u4e00\u4e2asubplot\u56fe\u4f8b(\u9ed8\u8ba4\u4e3aTrue) style : \u5bf9\u6bcf\u5217\u6298\u7ebf\u56fe\u8bbe\u7f6e\u7ebf\u7684\u7c7b\u578b logx : \u8bbe\u7f6ex\u8f74\u523b\u5ea6\u662f\u5426\u53d6\u5bf9\u6570 logy : \u8bbe\u7f6ey\u8f74\u523b\u5ea6\u662f\u5426\u53d6\u5bf9\u6570 loglog : \u540c\u65f6\u8bbe\u7f6ex\uff0cy\u8f74\u523b\u5ea6\u662f\u5426\u53d6\u5bf9\u6570 xticks : \u8bbe\u7f6ex\u8f74\u523b\u5ea6\u503c\uff0c\u5e8f\u5217\u5f62\u5f0f\uff08\u6bd4\u5982\u5217\u8868\uff09 yticks : \u8bbe\u7f6ey\u8f74\u523b\u5ea6\uff0c\u5e8f\u5217\u5f62\u5f0f\uff08\u6bd4\u5982\u5217\u8868\uff09 xlim : \u8bbe\u7f6e\u5750\u6807\u8f74x\u7684\u8303\u56f4\uff0c\u5217\u8868\u6216\u5143\u7ec4\u5f62\u5f0f ylim : \u8bbe\u7f6e\u5750\u6807\u8f74y\u7684\u8303\u56f4\uff0c\u5217\u8868\u6216\u5143\u7ec4\u5f62\u5f0f rot : \u8bbe\u7f6e\u8f74\u6807\u7b7e\uff08\u8f74\u523b\u5ea6\uff09\u7684\u663e\u793a\u65cb\u8f6c\u5ea6\u6570 fontsize : \u8bbe\u7f6e\u8f74\u523b\u5ea6\u7684\u5b57\u4f53\u5927\u5c0f colormap : \u8bbe\u7f6e\u56fe\u7684\u533a\u57df\u989c\u8272 colorbar : \u56fe\u7247\u67f1\u5b50 position : Specify relative alignments for bar plot layout. From 0 (left/bottom-end) to 1 (right/top-end). Default is 0.5 (center) layout : \u5e03\u5c40(rows, columns) for the layout of the plot table : \u5982\u679c\u4e3a\u6b63\uff0c\u5219\u9009\u62e9DataFrame\u7c7b\u578b\u7684\u6570\u636e\u5e76\u4e14\u8f6c\u6362\u5339\u914dmatplotlib\u7684\u5e03\u5c40 yerr : \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe xerr : \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe stacked : \u751f\u6210\u5806\u79ef\u67f1\u72b6\u56fe sort_columns : \u4ee5\u5b57\u6bcd\u8868\u987a\u5e8f\u7ed8\u5236\u5404\u5217\uff0c\u9ed8\u8ba4\u4f7f\u7528\u524d\u5217\u987a\u5e8f secondary_y : \u8bbe\u7f6e\u7b2c\u4e8c\u4e2ay\u8f74\uff08\u53f3y\u8f74\uff09 mark_right : When using a secondary_y axis, automatically mark the column labels with \u201c(right)\u201d in the legend kwds : Options to pass to matplotlib plotting method Series data1 = np.random.randn(10).cumsum(0) s1 = pd.Series( data1, index=np.arange(0, 100, 10), ) print(s1) fig, axes = plt.subplots(3, 1) # 3\u4e2a\u5b50\u56fe s1.plot.bar(ax=axes[0], color='k', alpha=0.7) # \u6761\u5f62\u56fe(\u5b50\u56fe0)\uff0ccolor='k\u2019(\u67f1\u5b50\u7684\u989c\u8272\u8bbe\u7f6e\u4e3a\u9ed1\u8272)\uff0calpha=0.7(\u56fe\u50cf\u7684\u586b\u5145\u8272\u8bbe\u7f6e\u4e3a\u90e8\u5206\u900f\u660e) s1.plot.barh(ax=axes[1], color='k', alpha=0.7) # \u6a2a\u5411\u6761\u5f62\u56fe(\u5b50\u56fe1) s1.value_counts().plot.pie(ax=axes[2]) # \u901a\u8fc7value_counts()\u5bf9Series\u503c\u9891\u7387\u8fdb\u884c\u53ef\u89c6\u5316 plt.show() DataFrame data2 = np.random.randn(10, 4).cumsum(0) df1 = pd.DataFrame( data2, columns=pd.Index(['A', 'B', 'C', 'D'], name='Genus'), index=np.arange(0, 100, 10) ) print(df1) fig, axes = plt.subplots(2, 1) # 2\u4e2a\u5b50\u56fe df1.plot.kde(ax=axes[0], alpha=0.7, grid='True', title='KDE Figure', sharex=True) df1.plot.bar(ax=axes[1], grid='True', title='Line Figure', sharex=True, use_index=False, stacked=True) # \u56e0\u4e3a\u5171\u4eabx\u8f74\uff0c\u6240\u4ee5\u5728KDE\u5b50\u56fe\u4e2d\u6307\u5b9ause_index=False\u770b\u4e0d\u51fa\u6548\u679c\u3002 # DataFrame\u7684\u5217\u540d\u79f0\"Genus\"\u88ab\u7528\u4f5c\u4e86\u56fe\u4f8b\u6807\u9898 # stacked=True\u6765\u751f\u6210\u5806\u79ef\u67f1\u72b6\u56fe plt.show() \u5b9e\u4f8b\uff1a\u7ed8\u5236\u4e00\u4e2a\u5806\u79ef\u67f1\u72b6\u56fe\uff0c\u7528\u4e8e\u5c55\u793a\u6bcf\u4e2a\u6d3e\u5bf9\u5728\u6bcf\u5929\u7684\u6570\u636e\u70b9\u5360\u6bd4\u3002 \u4ea4\u53c9\u8868 \u662f\u4e00\u79cd\u5e38\u7528\u7684\u5206\u7c7b\u6c47\u603b\u8868\u683c\uff0c\u7528\u4e8e\u9891\u6570\u5206\u5e03\u7edf\u8ba1\uff0c\u4e3b\u8981\u4ef7\u503c\u5728\u4e8e\u63cf\u8ff0\u4e86\u53d8\u91cf\u95f4\u5173\u7cfb\u7684\u6df1\u523b\u542b\u4e49\u3002 \u867d\u7136\u4e24\u4e2a\uff08\u6216\u4ee5\u4e0a\uff09\u53d8\u91cf\u53ef\u4ee5\u662f\u5206\u7c7b\u7684\u6216\u6570\u91cf\u7684\uff0c\u4f46\u662f\u4ee5\u90fd\u662f\u5206\u7c7b\u7684\u60c5\u5f62\u6700\u4e3a\u5e38\u89c1\u3002 Pandas\u7684 crosstab() \u65b9\u6cd5\u80fd\u591f\u5feb\u901f\u6784\u5efa\u4ea4\u53c9\u8868\uff0c\u5e76\u53ef\u4ee5\u901a\u8fc7\u53c2\u6570\u52a0\u4ee5\u4e2a\u6027\u5316\u7684\u8bbe\u7f6e\u3002\u5176\u4e2d\uff0c\u7b2c\u4e00\u4e2a\u53c2\u6570\u5c06\u6784\u6210\u4ea4\u53c9\u8868\u7684\u884c\uff0c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u5c06\u6784\u6210\u4ea4\u53c9\u8868\u7684\u5217\u3002 tips = pd.read_csv('../examples/tips.csv') print(tips) # total_bill tip smoker day time size # 0 16.99 1.01 No Sun Dinner 2 # 1 10.34 1.66 No Sun Dinner 3 # 2 21.01 3.50 No Sun Dinner 3 # 3 23.68 3.31 No Sun Dinner 2 # 4 24.59 3.61 No Sun Dinner 4 # .. ... ... ... ... ... ... # 239 29.03 5.92 No Sat Dinner 3 # 240 27.18 2.00 Yes Sat Dinner 2 # 241 22.67 2.00 Yes Sat Dinner 2 # 242 17.82 1.75 No Sat Dinner 2 # 243 18.78 3.00 No Thur Dinner 2 # [244 rows x 6 columns] party_counts = pd.crosstab(tips['day'], tips['size']) # \u5bf9\u539f\u59cb\u6570\u636e\u7684day\u548csize\u8fdb\u884c\u805a\u5408\uff0c\u5e76\u6784\u5efa\u4ea4\u53c9\u8868\uff0cday\u4f5c\u4e3a\u884c\uff0csize\u4f5c\u4e3a\u5217\u3002 print(party_counts) # size 1 2 3 4 5 6 # day # Fri 1 16 1 1 0 0 # Sat 2 53 18 13 1 0 # Sun 0 39 15 18 3 1 # Thur 1 48 4 5 1 3 # \u6ca1\u6709\u592a\u591a\u76841\u4eba\u548c6\u4eba\u6d3e\u5bf9\uff0c\u820d\u5f03\u8fd9\u4e9b\u6570\u636e party_counts = party_counts.loc[:, 2:5] print(party_counts) # size 2 3 4 5 # day # Fri 16 1 1 0 # Sat 53 18 13 1 # Sun 39 15 18 3 # Thur 48 4 5 1 # \u6807\u51c6\u5316\u81f3\u548c\u4e3a1\uff1a\u6cbf0\u8f74\uff08\u884c\uff09\u5bf9\u6bcf\u5217\u6c42\u548c\uff0c\u6bcf\u884c\u5404\u503c\u9664\u4ee5\u548c\uff0c\u4ee5\u786e\u4fdd\u6bcf\u4e00\u884c\u7684\u503c\u548c\u4e3a1\uff0c\u7136\u540e\u8fdb\u884c\u7ed8\u56fe party_pcts = party_counts.div(party_counts.sum(1), axis=0) print(party_pcts) # size 2 3 4 5 # day # Fri 0.888889 0.055556 0.055556 0.000000 # Sat 0.623529 0.211765 0.152941 0.011765 # Sun 0.520000 0.200000 0.240000 0.040000 # Thur 0.827586 0.068966 0.086207 0.017241 party_counts.plot.bar() plt.show() \u53ef\u4ee5\u770b\u5230\u672c\u6570\u636e\u96c6\u4e2d\u7684\u6d3e\u5bf9\u6570\u91cf\u5728\u5468\u672b\u4f1a\u589e\u52a0\u3002 \u5b9e\u4f8b\uff1a\u4f7f\u7528seaborn\u8fdb\u884c\u6309\u661f\u671f\u65e5\u671f\u8ba1\u7b97\u5c0f\u8d39\u767e\u5206\u6bd4\u3002 Seaborn\u8981\u6c42\u6570\u636e\u7684\u8f93\u5165\u7c7b\u578b\u4e3apandas\u7684Dataframe\u6216Numpy\u6570\u7ec4\u3002 tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) print(tips) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 # .. ... ... ... ... ... ... ... # 239 29.03 5.92 No Sat Dinner 3 0.256166 # 240 27.18 2.00 Yes Sat Dinner 2 0.079428 # 241 22.67 2.00 Yes Sat Dinner 2 0.096759 # 242 17.82 1.75 No Sat Dinner 2 0.108899 # 243 18.78 3.00 No Thur Dinner 2 0.190114 # [244 rows x 7 columns] # barplot: \u5c06\u70b9\u4f30\u8ba1\u548c\u7f6e\u4fe1\u533a\u95f4\u663e\u793a\u4e3a\u77e9\u5f62\u6761\u3002\u6761\u5f62\u56fe\u8868\u793a\u5177\u6709\u6bcf\u4e2a\u77e9\u5f62\u7684\u9ad8\u5ea6\u7684\u6570\u503c\u53d8\u91cf\u7684\u96c6\u4e2d\u8d8b\u52bf\u7684\u4f30\u8ba1\uff0c\u5e76\u4e14\u4f7f\u7528\u8bef\u5dee\u6761\u63d0\u4f9b\u56f4\u7ed5\u8be5\u4f30\u8ba1\u7684\u4e0d\u786e\u5b9a\u6027\u7684\u4e00\u4e9b\u6307\u793a # \u67f1\u5b50\u7684\u503c\u662ftip_pct\u7684\u5e73\u5747\u503c # \u67f1\u5b50\u4e0a\u753b\u51fa\u7684\u9ed1\u7ebf\u4ee3\u8868\u7684\u662f95%\u7684\u7f6e\u4fe1\u533a\u95f4\uff08\u7f6e\u4fe1\u533a\u95f4\u53ef\u4ee5\u901a\u8fc7\u53ef\u9009\u53c2\u6570\u8fdb\u884c\u8bbe\u7f6e\uff09 # hue\u9009\u9879\uff0c\u5141\u8bb8\u6211\u4eec\u901a\u8fc7\u4e00\u4e2a\u989d\u5916\u7684\u5206\u7c7b\u503c\u5c06\u6570\u636e\u5206\u79bb # \u5e26\u53c2\u6570hue='time'\u65f6\uff0c\u56db\u4e2a\u4e0d\u540c\u989c\u8272\u7684\u67f1\u5b50\uff0c\u6bcf\u4e2a\u67f1\u5b50\u4e0a\u6709\u7f6e\u4fe1\u533a\u95f4\u7684\u9ed1\u7ebf\uff0c\u523b\u5ea60.00~0.30\uff0c\u6b65\u957f0.05 # \u4e0d\u5e26\u53c2\u6570hue='time'\u65f6\uff0c\u4e24\u4e2a\u4e0d\u540c\u989c\u8272\u7684\u67f1\u5b50\uff0c\u5206\u522b\u4ee3\u8868Dinner\u548cLunch\uff0c\u4e0d\u662f\u6bcf\u4e2a\u67f1\u5b50\u4e0a\u90fd\u6709\u7f6e\u4fe1\u533a\u95f4\u7684\u9ed1\u7ebf\uff0c\u523b\u5ea60.00~0.30\uff0c\u6b65\u957f0.05 sns.barplot(x='tip_pct', y='day', data=tips, hue='time', orient='h') # \u6839\u636e\u661f\u671f\u65e5\u671f\u548c\u65f6\u95f4\u8ba1\u7b97\u7684\u5c0f\u8d39\u767e\u5206\u6bd4 # sns.barplot(x='tip_pct', y='day', data=tips, orient='h') sns.set(style=\"darkgrid\", palette=\"deep\") # style=\"whitegrid\" plt.show() \u76f4\u65b9\u56fe\u548c\u5bc6\u5ea6\u56fe \u00b6 \u76f4\u65b9\u56fe\u662f\u4e00\u79cd\u6761\u5f62\u56fe\uff0c\u7528\u4e8e\u7ed9\u51fa\u503c\u9891\u7387\u7684\u79bb\u6563\u663e\u793a\u3002\u6570\u636e\u70b9\u88ab\u5206\u6210\u79bb\u6563\u7684\uff0c\u5747\u5300\u95f4\u9694\u7684\u7bb1\uff0c\u5e76\u4e14\u7ed8\u5236\u6bcf\u4e2a\u7bb1\u4e2d\u6570\u636e\u70b9\u7684\u6570\u91cf\u3002 tips['tip_pct'].plot.hist(bins=50) # \u5c0f\u8d39\u767e\u5206\u6bd4\u7684\u76f4\u65b9\u56fe plt.show() \u5bc6\u5ea6\u56fe\u662f\u4e00\u79cd\u4e0e\u76f4\u65b9\u56fe\u76f8\u5173\u7684\u56fe\u8868\u7c7b\u578b\uff0c\u5b83\u901a\u8fc7\u8ba1\u7b97\u53ef\u80fd\u4ea7\u751f\u89c2\u6d4b\u6570\u636e\u7684\u8fde\u7eed\u6982\u7387\u5206\u5e03\u4f30\u8ba1\u800c\u4ea7\u751f\u3002 \u901a\u5e38\u7684\u505a\u6cd5\u662f\u5c06\u8fd9\u79cd\u5206\u5e03\u8fd1\u4f3c\u4e3a\u201c\u5185\u6838\u201d\u7684\u6df7\u5408\uff0c\u4e5f\u5c31\u662f\u50cf\u6b63\u6001\u5206\u5e03\u90a3\u6837\u7b80\u5355\u7684\u5206\u5e03\u3002 \u56e0\u6b64\uff0c\u5bc6\u5ea6\u56fe\u4e5f\u88ab\u79f0\u4e3a\u5185\u6838\u5bc6\u5ea6\u4f30\u8ba1\u56fe\uff08KDE\uff09\u3002 tips['tip_pct'].plot.density() # \u5c0f\u8d39\u767e\u5206\u6bd4\u5bc6\u5ea6\u56fe plt.show() \u7ed8\u5236\u76f4\u65b9\u56fe\u548c\u8fde\u7eed\u5bc6\u5ea6\u4f30\u8ba1 sns.displot() \u3002 sns.distplot(tips['tip_pct'], bins=100, color='k') plt.show() # FutureWarning: `distplot` is a deprecated function and will be removed in a future version. # Please adapt your code to use either `displot` (a figure-level function with similar flexibility) # or `histplot` (an axes-level function for histograms). \u6563\u70b9\u56fe\u6216\u70b9\u56fe \u00b6 \u70b9\u56fe\u6216\u6563\u70b9\u56fe\u53ef\u4ee5\u7528\u4e8e\u68c0\u9a8c\u4e24\u4e2a\u4e00\u7ef4\u6570\u636e\u5e8f\u5217\u4e4b\u95f4\u7684\u5173\u7cfb\u3002 \u5b9e\u4f8b\uff1a\u4ece statsmodels \u9879\u76ee\u4e2d\u8f7d\u5165\u4e86macrodata\u6570\u636e\u96c6\uff0c\u5e76\u9009\u62e9\u4e86\u4e00\u4e9b\u53d8\u91cf\uff0c\u4e4b\u540e\u8ba1\u7b97\u5bf9\u6570\u5dee\u3002 macro = pd.read_csv('../examples/macrodata.csv') print(macro.head(5)) # year quarter realgdp realcons ... unemp pop infl realint # 0 1959.0 1.0 2710.349 1707.4 ... 5.8 177.146 0.00 0.00 # 1 1959.0 2.0 2778.801 1733.7 ... 5.1 177.830 2.34 0.74 # 2 1959.0 3.0 2775.488 1751.8 ... 5.3 178.657 2.74 1.09 # 3 1959.0 4.0 2785.204 1753.7 ... 5.6 179.386 0.27 4.06 # 4 1960.0 1.0 2847.699 1770.5 ... 5.2 180.007 2.31 1.19 # [5 rows x 14 columns] data = macro[['cpi', 'm1', 'tbilrate', 'unemp']] print(data.head(5)) # cpi m1 tbilrate unemp # 0 28.98 139.7 2.82 5.8 # 1 29.15 141.7 3.08 5.1 # 2 29.35 140.5 3.82 5.3 # 3 29.37 140.0 4.33 5.6 # 4 29.54 139.6 3.50 5.2 trans_data = np.log(data).diff().dropna() print(trans_data[-5:]) # cpi m1 tbilrate unemp # 198 -0.007904 0.045361 -0.396881 0.105361 # 199 -0.021979 0.066753 -2.277267 0.139762 # 200 0.002340 0.010286 0.606136 0.160343 # 201 0.008419 0.037461 -0.200671 0.127339 # 202 0.008894 0.012202 -0.405465 0.042560 \u7528 seaborn \u7684 regplot \u65b9\u6cd5\u7ed8\u5236\u6563\u70b9\u56fe\uff0c\u5e76\u62df\u5408\u51fa\u4e00\u4e2a\u6761\u7ebf\u6027\u56de\u5f52\u7ebf\u3002( seaborn\u6587\u6863 ) sns.regplot('m1', 'unemp', data=trans_data) plt.title('Changes in log %s versus log %s ' % ('m1', 'unemp')) plt.show() \u5728\u63a2\u7d22\u6027\u6570\u636e\u5206\u6790\u4e2d\uff0c\u80fd\u591f\u67e5\u770b\u4e00\u7ec4\u53d8\u91cf\u4e2d\u7684\u6240\u6709\u6563\u70b9\u56fe\u662f\u6709\u5e2e\u52a9\u7684\uff0c\u8fd9\u88ab\u79f0\u4e3a\u6210\u5bf9\u56fe\u6216\u6563\u70b9\u56fe\u77e9\u9635\u3002 Seaborn\u6709\u4e00\u4e2a\u65b9\u4fbf\u7684 pairplot \u51fd\u6570\uff0c\u5b83\u652f\u6301\u5728\u5bf9\u89d2\u7ebf\u4e0a\u653e\u7f6e\u6bcf\u4e2a\u53d8\u91cf\u7684\u76f4\u65b9\u56fe\u6216\u5bc6\u5ea6\u4f30\u8ba1\u503c\u3002 plot_ksw \u53c2\u6570\u80fd\u591f\u5c06\u914d\u7f6e\u9009\u9879\u4f20\u9012\u7ed9\u975e\u5bf9\u89d2\u5143\u7d20\u4e0a\u7684\u5404\u4e2a\u7ed8\u56fe\u8c03\u7528\u3002 sns.pairplot(trans_data, diag_kind='kde', plot_kws={'alpha': 0.2}) plt.show() \u5206\u9762\u7f51\u683c\u548c\u5206\u7c7b\u6570\u636e \u00b6 \u5982\u679c\u6570\u636e\u96c6\u6709\u989d\u5916\u7684\u5206\u7ec4\u7ef4\u5ea6\u600e\u4e48\u529e\uff1f\u4f7f\u7528\u5206\u9762\u7f51\u683c\u662f\u5229\u7528\u591a\u79cd\u5206\u7ec4\u53d8\u91cf\u5bf9\u6570\u636e\u8fdb\u884c\u53ef\u89c6\u5316\u7684\u65b9\u5f0f\u3002 seaborn\u62e5\u6709\u4e00\u4e2a\u6709\u6548\u7684\u5185\u5efa\u51fd\u6570 factorplot \uff0c\u5b83\u53ef\u4ee5\u7b80\u5316\u591a\u79cd\u5206\u9762\u7ed8\u56fe\u3002 sns.factorplot(x='day', y='tip_pct', hue='time', col='smoker', kind='bar', data=tips[tips.tip_pct < 1]) plt.show() # UserWarning: The `factorplot` function has been renamed to `catplot`. # The original name will be removed in a future release. Please update your code. # Note that the default `kind` in `factorplot` (`'point'`) has changed `'strip'` in `catplot`. sns.catplot(x='day', y='tip_pct', hue='time', col='smoker', kind='box', data=tips[tips.tip_pct < 0.5]) plt.show() \u5176\u4ed6Python\u53ef\u89c6\u5316\u5de5\u5177 \u00b6 \u81ea2010\u5e74\u4ee5\u6765\uff0c\u5f88\u591a\u5f00\u53d1\u5de5\u4f5c\u90fd\u96c6\u4e2d\u5728\u521b\u5efaweb\u4ea4\u4e92\u5f0f\u56fe\u5f62\u4e0a\u3002 \u501f\u52a9\u50cf Bokeh \u548c Plotly \u8fd9\u6837\u7684\u5de5\u5177\uff0c\u5728web\u6d4f\u89c8\u5668\u4e2d\u521b\u5efa\u52a8\u6001\u7684\u3001\u4ea4\u4e92\u5f0f\u56fe\u50cf\u7684\u5de5\u4f5c\u73b0\u5728\u5df2\u7ecf\u53ef\u4ee5\u5b9e\u73b0\u3002 \u53ef\u89c6\u5316\u662f\u4e00\u4e2a\u6d3b\u8dc3\u7684\u7814\u7a76\u9886\u57df\u3002","title":"\u7ed8\u56fe\u4e0e\u53ef\u89c6\u5316"},{"location":"python/DataAnalysis/ch06/#_1","text":"","title":"\u7ed8\u56fe\u4e0e\u53ef\u89c6\u5316"},{"location":"python/DataAnalysis/ch06/#matplotlib-api","text":"import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np import pandas as pd from io import BytesIO \u6267\u884c plt.show() \u65f6\u62a5\u9519\uff1a UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure. \u6267\u884c\u4e0b\u9762\u547d\u4ee4\uff0c\u5f97\u5230 plt \u7684 backend \u662f\u7528 agg \u3002 plt.get_backend() \u4f8b\u5982\uff1a\u4e0b\u9762\u4e24\u79cd\u8868\u8fbe\u65b9\u5f0f\u6548\u679c\u4e00\u6837\u3002 ax.plot(x, y, 'g--') ax.plot(x, y, linestyle='--', color='g') Out[6]: 'agg' \u5b89\u88c5\u4e0b\u9762\u51e0\u4e2a\u5305\uff1a sudo zypper in python-tk python3-tk sudo zypper in plplot-tcltk-devel plplot-tcltk-libs pip install tk \u6dfb\u52a0\u4e0b\u9762\u5230python\u4ee3\u7801\u4e2d\u3002 import matplotlib.pyplot as plt mpl.use('TkAgg') \u6267\u884c\u540e\u62a5\u4e0b\u9762\u9519\u8bef\uff1a your Python may not be configured for Tk \u8fdb\u5165python\u6e90\u7801\u76ee\u5f55\uff0c\u91cd\u65b0\u7f16\u8bd1\u4f8b\u5982\uff1a\u4e0b\u9762\u4e24\u79cd\u8868\u8fbe\u65b9\u5f0f\u6548\u679c\u4e00\u6837\u3002 ax.plot(x, y, 'g--') ax.plot(x, y, linestyle='--', color='g') james@lizard:/opt/Python-3.9.6> sudo make james@lizard:/opt/Python-3.9.6> sudo make install \u95ee\u9898\u89e3\u51b3\uff0c\u5373\u4f7f\u4e0d\u52a0\u5165 mpl.use('TkAgg') \uff0c\u6267\u884c plt.show() \u4e5f\u662f\u53ef\u4ee5\u8f93\u51fa\u56fe\u50cf\u3002","title":"\u7b80\u660ematplotlib API\u5165\u95e8"},{"location":"python/DataAnalysis/ch06/#_2","text":"matplotlib \u6240\u7ed8\u5236\u7684\u56fe\u4f4d\u4e8e\u56fe\u7247\uff08Figure\uff09\u5bf9\u8c61\u4e2d\u3002\u53ef\u4ee5\u4f7f\u7528 plt.figure \u751f\u6210\u4e00\u4e2a\u65b0\u7684\u56fe\u7247\u3002 \u4f7f\u7528 add_subplot \u521b\u5efa\u4e00\u4e2a\u6216\u591a\u4e2a\u5b50\u56fe\uff08subplot\uff09\u3002 plt \u4e0e ax \u7ed8\u56fe\u3002 fig = plt.figure() # plt: \u5148\u751f\u6210\u4e86\u4e00\u4e2a\u753b\u5e03\uff0c\u7136\u540e\u5728\u8fd9\u4e2a\u753b\u5e03\u4e0a\u9690\u5f0f\u7684\u751f\u6210\u4e00\u4e2a\u753b\u56fe\u533a\u57df\u6765\u8fdb\u884c\u753b\u56fe # plt.plot([1, 2, 3, 4]) # plt.show() # ax: \u5148\u751f\u6210\u4e00\u4e2a\u753b\u5e03\uff082\u00d72\u7684\u533a\u57df\uff0c\u6700\u591a\u653e\u56db\u4e2a\u56fe\u5f62\uff09\uff0c\u7136\u540e\u5728\u6b64\u753b\u5e03\u4e0a\uff0c\u9009\u5b9a\u4e00\u4e2a\u5b50\u533a\u57df\u753b\u4e86\u4e00\u4e2a\u5b50\u56fe\uff08\u5e8f\u53f71\u4ee3\u8868\u7b2c\u4e00\u4e2a\u533a\u57df\uff09 ax1 = fig.add_subplot(2, 2, 1) # \u4e5f\u53ef\u4ee5\u5199\u6210fig.add_subplot(221) ax1.plot([1, 2, 3, 4], [1, 4, 3, 2]) # \u8f93\u51fa\u56fe\u7247\u5230\u7b2c\u4e00\u4e2a\u533a\u57df\u3002 # \u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u6570\u636e\u96c6\u91cc\u5404\u4e2a\u6570\u636e\u70b9\u7684X\u503c\u7684\u96c6\u5408 # \u7b2c\u4e8c\u4e2a\u53c2\u6570\u6570\u636e\u96c6\u91cc\u5404\u4e2a\u6570\u636e\u70b9\u7684Y\u503c\u7684\u96c6\u5408\u3002 # \u4e0d\u662f\u6570\u5b66\u4e0a\u5e38\u89c1\u7684\u6210\u5bf9\u5750\u6807\u70b9\u5982(x1,y1)\u3001(x2,y2)\u3001...\u3001(xn,yn)\u7684\u683c\u5f0f\uff0c\u800c\u662f (x1,x2,...,xn)\u548c(y1,y2,...,yn) \u3002 plt.show() \u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u589e\u52a0\u5b50\u56fe\u540e\u7684\u6570\u636e\u53ef\u89c6\u5316\u6548\u679c\u3002 fig = plt.figure() ax1 = fig.add_subplot(2, 2, 1) ax2 = fig.add_subplot(2, 2, 2) ax3 = fig.add_subplot(2, 2, 3) ax1.plot(np.random.randn(50).cumsum(), 'k--') # \u5728\u7b2c\u4e09\u4e2a\u533a\u57df\u8f93\u51fa\u56fe\u50cf\u3002'k--\u2019\u662f\u7528\u4e8e\u7ed8\u5236\u9ed1\u8272\u5206\u6bb5\u7ebf\u7684style\u9009\u9879\u3002 ax2.hist(np.random.randn(100), bins=20, color='k', alpha=0.3) ax3.scatter(np.arange(30), np.arange(30) + 3 * np.random.randn(30)) plt.show() plt.subplots \u901a\u8fc7 matplotlib \u7684 subplots \u65b9\u6cd5\uff0c\u4f7f\u7528\u5b50\u56fe\u7f51\u683c\u521b\u5efa\u56fe\u7247\uff0c\u7136\u540e\u8fd4\u56de\u5305\u542b\u4e86\u5df2\u751f\u6210\u5b50\u56fe\u5bf9\u8c61\u7684NumPy\u6570\u7ec4\u3002 \u6570\u7ec4 axes \u53ef\u4ee5\u50cf\u4e8c\u7ef4\u6570\u7ec4\u90a3\u6837\u65b9\u4fbf\u5730\u8fdb\u884c\u7d22\u5f15\uff0c\u4f8b\u5982\uff0c axes[0, 1] \u3002 plt.subplots \u53c2\u6570\u9009\u9879\uff1a nrows\uff1a\u53ef\u9009\u7684\uff0c\u6574\u578b\uff0c\u9ed8\u8ba4\u4e3a1\u3002\u5b50\u56fe\u7f51\u683c\u7684\u884c\u6570\u3002 ncols\uff1a\u53ef\u9009\u7684\uff0c\u6574\u578b\uff0c\u9ed8\u8ba4\u4e3a1\u3002\u5b50\u56fe\u7f51\u683c\u7684\u5217\u6570\u3002 sharex\uff1a\u53ef\u9009\u7684\uff0c\u9ed8\u8ba4\u4e3aFalse\u3002\u53ef\u9009\u503c\u5982\u4e0b\uff1a True\u6216all\uff0c\u6240\u6709\u5b50\u56fe\u5171\u4eabx\u8f74 False\u6216none\uff0c\u6bcf\u4e2a\u5b50\u56fe\u7684x\u8f74\u90fd\u662f\u72ec\u7acb\u7684 row\uff0c\u6bcf\u884c\u5b50\u56fe\u5171\u4eab\u4e00\u4e2ax\u8f74 col\uff0c\u6bcf\u5217\u5b50\u56fe\u5171\u4eab\u4e00\u4e2ax\u8f74 sharey\uff1a\u7c7b\u4f3c\u4e8esharex\uff0c\u8bbe\u7f6ey\u8f74\u7684\u5171\u4eab\u65b9\u5f0f\u3002\u5f53\u67d0\u5217\u5171\u4eab\u4e00\u4e2ax\u8f74\u65f6\uff0c\u53ea\u6709\u5e95\u90e8\u7684\u5b50\u56fe\u4f1a\u521b\u5efax\u8f74\u6807\u8bb0\u3002\u540c\u6837\u7684\uff0c\u5982\u679c\u67d0\u884c\u5171\u4eab\u4e00\u4e2ay\u8f74\u65f6\uff0c\u53ea\u6709\u884c\u7684\u7b2c\u4e00\u5217\u5b50\u56fe\u4f1a\u521b\u5efay\u8f74\u6807\u8bb0\u3002 squeeze \uff1a\u53ef\u9009\u7684\uff0c\u5e03\u5c14\u578b\uff0c\u9ed8\u8ba4\u4e3aTrue\u3002\u662f\u5426\u538b\u7f29\u8fd4\u56de\u7684Axes\u6570\u7ec4\u3002\u5982\u679c\u4e3aTrue\uff0c\u5f53\u53ea\u6709\u4e00\u4e2a\u5b50\u56fe\uff0c\u5373nrows\u548cncols\u5747\u4e3a1\u65f6\uff0c\u8fd4\u56de\u4e00\u4e2a\u5355\u72ec\u7684Axes\u5bf9\u8c61\uff0c\u5f53\u6709N*1\u548c1*M\u4e2a\u5b50\u56fe\u65f6\uff0c\u8fd4\u56de\u4e00\u4e2a\u4e00\u7ef4Axes\u5bf9\u8c61\u6570\u7ec4\u3002\u5f53\u6709N*M\u4e2a\u5b50\u56fe\uff08N>1\uff0cM>1\uff09\u65f6\uff0c\u8fd4\u56de\u4e8c\u7ef4\u6570\u7ec4\u3002\u5982\u679c\u4e3aFalse\uff0c\u5219\u603b\u662f\u8fd4\u56de\u4e8c\u7ef4\u6570\u7ec4\u3002 num\uff1a\u53ef\u9009\u7684\uff0c\u6574\u578b\u6216\u5b57\u7b26\u4e32\uff0c\u9ed8\u8ba4\u4e3aNone\u3002\u662fmatplotlib.pyplot.figure\u7684\u5173\u952e\u5b57\uff0c\u7528\u4e8e\u8bbe\u7f6e\u56fe\u50cf\u6570\u5b57\u6216\u6807\u7b7e\u3002\u5982\u679c\u672a\u8bbe\u7f6e\u6b64\u53c2\u6570\uff0c\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u56fe\u50cf\uff0c\u5e76\u9012\u589e\u56fe\u50cf\u7f16\u53f7\uff0cfigure\u5bf9\u8c61\u4f1a\u5c06\u7f16\u53f7\u4fdd\u5b58\u5728number\u5c5e\u6027\u4e2d\u3002\u5982\u679c\u8bbe\u7f6e\u4e86\u6b64\u53c2\u6570\uff0c\u5e76\u4e14\u5b58\u5728\u53c2\u6570\u6307\u5b9a\u7684\u56fe\u50cf\uff0c\u5219\u4f1a\u8fd4\u56de\u6b64\u56fe\u50cf\u7684\u5f15\u7528\uff0c\u5982\u679c\u4e0d\u5b58\u5728\u5219\u4f1a\u521b\u5efa\u65b0\u7684\u56fe\u50cf\u5e76\u8fd4\u56de\u5b83\u7684\u5f15\u7528\u3002\u5982\u679c\u662f\u5b57\u7b26\u4e32\uff0c\u5219\u7a97\u53e3\u6807\u9898\u4f1a\u88ab\u8bbe\u7f6e\u4e3a\u6b64\u5b57\u7b26\u4e32\u7684\u503c\u3002 subplot_kw\uff1a\u53ef\u9009\u7684\uff0c\u5b57\u5178\u7c7b\u578b\u3002\u5305\u542b\u4f20\u9012\u7ed9\u7528\u4e8e\u521b\u5efa\u5b50\u56fe\u7684\u8c03\u7528add_subplot\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 gridspec_kw\uff1a\u53ef\u9009\u7684\uff0c\u5b57\u5178\u7c7b\u578b\u3002\u5305\u542b\u4f20\u9012\u7ed9\u7528\u4e8e\u521b\u5efa\u5b50\u56fe\u7f51\u683c\u7684GridSpec\u6784\u9020\u51fd\u6570\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 fig, axes = plt.subplots(2, 3) print(axes) # \u5c06\u751f\u6210\u7684axes\u5bf9\u8c61\u653e\u5165NumPy\u6570\u7ec4\u3002 # [[ ] # [ ]] \u8c03\u6574\u5b50\u56fe\u5468\u56f4\u7684\u95f4\u8ddd\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c matplotlib \u4f1a\u5728\u5b50\u56fe\u7684\u5916\u90e8\u548c\u5b50\u56fe\u4e4b\u95f4\u7559\u51fa\u4e00\u5b9a\u7684\u95f4\u8ddd\u3002 \u8fd9\u4e2a\u95f4\u8ddd\u90fd\u662f\u76f8\u5bf9\u4e8e\u56fe\u7684\u9ad8\u5ea6\u548c\u5bbd\u5ea6\u6765\u6307\u5b9a\u7684\uff0c\u624b\u52a8\u8c03\u6574\u56fe\u7684\u5927\u5c0f\uff0c\u90a3\u4e48\u95f4\u8ddd\u4f1a\u81ea\u52a8\u8c03\u6574\u3002 \u4e5f\u53ef\u4ee5\u4f7f\u7528\u56fe\u5bf9\u8c61\u4e0a\u7684 subplots_adjust \u65b9\u6cd5\u66f4\u6539\u95f4\u8ddd\uff0c\u4e5f\u53ef\u4ee5\u7528\u4f5c\u9876\u5c42\u51fd\u6570\u3002 fig, axes = plt.subplots(2, 2, sharex=True, sharey=True) for i in range(2): for j in range(2): axes[i, j].hist(np.random.randn(500), bins=50, color='k', alpha=0.5) plt.subplots_adjust(wspace=0, hspace=0) plt.show() \u4e0a\u9762\u8f93\u51fa\u56fe\u50cf\u7684\u8f74\u6807\u7b7e\u662f\u5b58\u5728\u91cd\u53e0\u7684\u3002 matplotlib \u5e76\u4e0d\u68c0\u67e5\u6807\u7b7e\u662f\u5426\u91cd\u53e0\uff0c\u56e0\u6b64\u5728\u7c7b\u4f3c\u60c5\u51b5\u4e0b\u4f60\u9700\u8981\u901a\u8fc7\u663e\u5f0f\u6307\u5b9a\u523b\u5ea6\u4f4d\u7f6e\u548c\u523b\u5ea6\u6807\u7b7e\u7684\u65b9\u6cd5\u6765\u4fee\u590d\u8f74\u6807\u7b7e\u3002","title":"\u56fe\u7247\u4e0e\u5b50\u56fe"},{"location":"python/DataAnalysis/ch06/#_3","text":"matplotlib \u7684\u4e3b\u51fd\u6570 plot \u63a5\u6536\u5e26\u6709 x \u548c y \u8f74\u7684\u6570\u7ec4\u4ee5\u53ca\u4e00\u4e9b\u53ef\u9009\u7684\u5b57\u7b26\u4e32\u7f29\u5199\u53c2\u6570\u6765\u6307\u660e\u989c\u8272\u548c\u7ebf\u7c7b\u578b\u3002 \u4f8b\u5982\uff1a\u4e0b\u9762\u4e24\u79cd\u8868\u8fbe\u65b9\u5f0f\u6548\u679c\u4e00\u6837\u3002 ax.plot(x, y, 'g--') ax.plot(x, y, linestyle='--', color='g') data = np.random.randn(30).cumsum() plt.plot(data, 'ko--') plt.show() # \u4e0a\u9762\u7684\u4ee3\u7801\u53ef\u4ee5\u5199\u5f97\u66f4\u4e3a\u663e\u5f0f\uff1a plt.plot(data, color='k', linestyle='dashed', marker='o') plt.show() plt.plot(data, color='k', linestyle='dashed', marker='o', label='Default') plt.show() plt.plot(data, color='k', linestyle='dashed', marker='o', label='steps-post', drawstyle='steps-post') plt.show()","title":"\u989c\u8272\u3001\u6807\u8bb0\u548c\u7ebf\u7c7b\u578b"},{"location":"python/DataAnalysis/ch06/#_4","text":"\u5bf9\u4e8e\u5927\u591a\u6570\u56fe\u8868\u4fee\u9970\u5de5\u4f5c\uff0c\u6709\u4e24\u79cd\u4e3b\u8981\u7684\u65b9\u5f0f\uff1a\u4f7f\u7528\u7a0b\u5e8f\u6027\u7684pyplot\u63a5\u53e3\uff08\u5373matplotlib.pyplot\uff09\u548c\u66f4\u591a\u9762\u5411\u5bf9\u8c61\u7684\u539f\u751fmatplotlib API\u3002 pyplot \u63a5\u53e3\u8bbe\u8ba1\u4e3a\u4ea4\u4e92\u5f0f\u4f7f\u7528\uff0c\u5305\u542b\u4e86\u50cf xlim \u3001 xticks \u548c xticklabels \u7b49\u65b9\u6cd5\u3002\u8fd9\u4e9b\u65b9\u6cd5\u5206\u522b\u63a7\u5236\u4e86\u7ed8\u56fe\u8303\u56f4\u3001\u523b\u5ea6\u4f4d\u7f6e\u4ee5\u53ca\u523b\u5ea6\u6807\u7b7e\u3002 \u5728\u6ca1\u6709\u51fd\u6570\u53c2\u6570\u7684\u60c5\u51b5\u4e0b\u8c03\u7528\uff0c\u8fd4\u56de\u5f53\u524d\u7684\u53c2\u6570\u503c\uff08\u4f8b\u5982 plt.xlim() \u8fd4\u56de\u5f53\u524d\u7684x\u8f74\u7ed8\u56fe\u8303\u56f4\uff09\u3002 \u4f20\u5165\u53c2\u6570\u7684\u60c5\u51b5\u4e0b\u8c03\u7528\uff0c\u5e76\u8bbe\u7f6e\u53c2\u6570\u503c\uff08\u4f8b\u5982 plt.xlim\uff08[0, 10]\uff09 \u4f1a\u5c06 x \u8f74\u7684\u8303\u56f4\u8bbe\u7f6e\u4e3a0\u523010\uff09\u3002 \u6240\u6709\u7684\u8fd9\u4e9b\u65b9\u6cd5\u90fd\u4f1a\u5728\u5f53\u524d\u6d3b\u52a8\u7684\u6216\u6700\u8fd1\u521b\u5efa\u7684 AxesSubplot \u4e0a\u751f\u6548\u3002 \u8fd9\u4e9b\u65b9\u6cd5\u4e2d\u7684\u6bcf\u4e00\u4e2a\u5bf9\u5e94\u4e8e\u5b50\u56fe\u81ea\u8eab\u7684\u4e24\u4e2a\u65b9\u6cd5\u3002\u6bd4\u5982 xlim \u5bf9\u5e94\u4e8e ax.get_lim \u548c ax.set_lim \u3002 \u63a8\u8350\u4f7f\u7528 subplot \u7684\u5b9e\u4f8b\u65b9\u6cd5\uff0c\u56e0\u4e3a\u8fd9\u6837\u66f4\u4e3a\u663e\u5f0f\uff08\u5c24\u5176\u662f\u5728\u5904\u7406\u591a\u4e2a\u5b50\u56fe\u65f6\uff09\u3002 data = np.random.randn(1000).cumsum() fig = plt.figure() # \u8bbe\u5b9a\u5b50\u56fe ax = fig.add_subplot(1, 1, 1) # \u8bbe\u5b9ax\u8f74\u5bf9\u5e94\u53c2\u6570\uff1a # \u8bbe\u5b9ax\u8f74\u523b\u5ea6 ax.set_xticks([0, 250, 500, 750, 1000]) # \u8bbe\u5b9ax\u8f74\u6807\u7b7e ax.set_xticklabels(['one(0)', 'two(250)', 'three(500)', 'four(750)', 'five(1000)'], rotation=30, fontsize='small') # \u7ed9x\u8f74\u4e00\u4e2a\u540d\u79f0 ax.set_xlabel('Stages') # \u8bbe\u5b9ay\u8f74\u5bf9\u5e94\u53c2\u6570\uff1a # \u672a\u6307\u5b9a\u7684\u53c2\u6570\u7531\u7cfb\u7edf\u9ed8\u8ba4\u4ea7\u751f\u3002 ax.set_ylabel('Steps') # \u7ed9\u5b50\u56fe\u6dfb\u52a0\u4e00\u4e2a\u6807\u9898 ax.set_title('My first matplotlib plot') # \u7ed9\u5b50\u56fe\u6dfb\u52a0\u4e00\u4e2a\u56fe\u4f8b\uff08\u5982\uff1a\u7ed9\u5b50\u56fe\u5185\u4e00\u4e2a\u56fe\u5f62\u66f2\u7ebf\u6dfb\u52a0\u4e00\u4e2alabel\uff09 ax.plot(data, 'k--', label='Label One') # loc\u53c2\u6570\u544a\u8bc9matplotlib\u5728\u54ea\u91cc\u653e\u7f6e\u56fe\u8868\u3002legend\u65b9\u6cd5\u6709\u591a\u4e2a\u5176\u4ed6\u7684\u4f4d\u7f6e\u53c2\u6570loc\u3002 ax.legend(loc='best') # \u6216\u8005plt.legend(loc='best') \u3002 # \u5728\u56fe\u5f62\u5750\u6807\u4e3a(0, 0)\u7684\u4f4d\u7f6e\u6dfb\u52a0\u4e00\u4e2alable ax.text(0, 0, 'Hello World1', family='monospace', fontsize=10) # \u7ed9\u5b50\u56fe\u6dfb\u52a0annotate\u3002\u7528\u4e00\u4e2a\u7bad\u5934\u6307\u5411\u8981\u6ce8\u91ca\u7684\u5730\u65b9\uff0c\u518d\u5199\u4e0a\u4e00\u6bb5\u8bdd\u7684\u884c\u4e3a\uff0c\u53eb\u505aannotate\u3002 # * s: \u6ce8\u91ca\u7684\u5185\u5bb9\uff0c\u4e00\u6bb5\u6587\u5b57\uff1b # * xytext: \u8fd9\u6bb5\u6587\u5b57\u6240\u5904\u7684\u4f4d\u7f6e; # * xy: \u7bad\u5934\u6307\u5411\u7684\u4f4d\u7f6e\uff1b # * arrowprops: \u901a\u8fc7arrowstyle\u8868\u660e\u7bad\u5934\u7684\u98ce\u683c\u6216\u79cd\u7c7b\u3002 ax.annotate('Zero is here!', xytext=(20, 20), xy=(1, 1), arrowprops=dict(arrowstyle='->')) # \u7ed9\u5b50\u56fe\u6dfb\u52a0\u4e00\u4e9b\u56fe\u5f62 # matplotlib\u542b\u6709\u8868\u793a\u591a\u79cd\u5e38\u89c1\u56fe\u5f62\u7684\u5bf9\u8c61\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u7684\u5f15\u7528\u662fpatches\u3002 # \u4e00\u4e9b\u56fe\u5f62\uff0c\u6bd4\u5982Rectangle\uff08\u77e9\u5f62\uff09\u548cCircle\uff08\u5706\u5f62\uff09\uff0c\u53ef\u4ee5\u5728matplotlib.pyplot\u4e2d\u627e\u5230\uff0c\u4f46\u56fe\u5f62\u7684\u5168\u96c6\u4f4d\u4e8ematplotlib.patches\u3002 rect = plt.Rectangle((10, 5), 100, 15, color='k', alpha=0.3) circ = plt.Circle((200, 9), 95, color='b', alpha=0.3) pgon = plt.Polygon([[500, 5], [600, -5], [700, 30]], color='g', alpha=0.5) ax.add_patch(rect) ax.add_patch(circ) ax.add_patch(pgon) # \u5c06\u56fe\u7247\u4fdd\u5b58\u5230\u6587\u4ef6 # \u6587\u4ef6\u7c7b\u578b\u662f\u4ece\u6587\u4ef6\u6269\u5c55\u540d\u4e2d\u63a8\u65ad\u51fa\u6765\u7684\u3002\u6240\u4ee5\u5982\u679c\u4f60\u4f7f\u7528\uff0epdf\uff0c\u5219\u4f1a\u5f97\u5230\u4e00\u4e2aPDF\u3002 # \u51e0\u4e2a\u91cd\u8981\u7684\u9009\u9879\uff1adpi\uff0c\u5b83\u63a7\u5236\u6bcf\u82f1\u5bf8\u70b9\u6570\u7684\u5206\u8fa8\u7387\uff1bbbox_inches\uff0c\u53ef\u4ee5\u4fee\u526a\u5b9e\u9645\u56fe\u5f62\u7684\u7a7a\u767d\u3002 plt.savefig('../examples/figpath.png', dpi=400, bbox_inches='tight') # saveifg\u5e76\u975e\u4e00\u5b9a\u662f\u5199\u5230\u786c\u76d8\u7684\uff0c\u5b83\u53ef\u4ee5\u5c06\u56fe\u7247\u5199\u5165\u5230\u6240\u6709\u7684\u6587\u4ef6\u578b\u5bf9\u8c61\u4e2d\uff0c\u4f8b\u5982BytesIO buffer = BytesIO() plt.savefig(buffer) plot_data = buffer.getvalue() plt.show()","title":"\u523b\u5ea6\u3001\u6807\u7b7e\u548c\u56fe\u4f8b"},{"location":"python/DataAnalysis/ch06/#matplotlib","text":"matplotlib \u914d\u7f6e\u4e86\u914d\u8272\u65b9\u6848\u548c\u9ed8\u8ba4\u8bbe\u7f6e\uff0c\u901a\u8fc7\u5168\u5c40\u53c2\u6570\u6765\u5b9a\u5236\uff0c\u5305\u62ec\u56fe\u5f62\u5927\u5c0f\u3001\u5b50\u56fe\u95f4\u8ddd\u3001\u989c\u8272\u3001\u5b57\u4f53\u5927\u5c0f\u548c\u7f51\u683c\u6837\u5f0f\u7b49\u7b49\u3002 \u4f7f\u7528 rc \u65b9\u6cd5\u662f\u4f7f\u7528Python\u7f16\u7a0b\u4fee\u6539\u914d\u7f6e\u7684\u4e00\u79cd\u65b9\u5f0f\u3002 rc \u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u4f60\u60f3\u8981\u81ea\u5b9a\u4e49\u7684\u7ec4\u4ef6\uff0c\u6bd4\u5982 'figure'\u3001'axes'\u3001'xtick'\u3001'ytick'\u3001'grid'\u3001'legend' \u7b49\u7b49\u3002 \u4e4b\u540e\uff0c\u53ef\u4ee5\u6309\u7167\u5173\u952e\u5b57\u53c2\u6570\u7684\u5e8f\u5217\u6307\u5b9a\u65b0\u53c2\u6570\u3002 \u5b57\u5178\u662f\u4e00\u79cd\u5728\u7a0b\u5e8f\u4e2d\u8bbe\u7f6e\u9009\u9879\u7684\u7b80\u5355\u65b9\u5f0f\u3002\u6bd4\u5982\uff1a plt.rc('figure', figsize=(10, 10)) font_options = { 'family': 'monospace', 'weight': 'bold', 'size': 'small' } plt.rc('font', **font_options)","title":"matplotlib\u8bbe\u7f6e"},{"location":"python/DataAnalysis/ch06/#pandasseaborn","text":"pandas\u81ea\u8eab\u6709\u5f88\u591a\u5185\u5efa\u65b9\u6cd5\u53ef\u4ee5\u7b80\u5316\u4eceDataFrame\u548cSeries\u5bf9\u8c61\u751f\u6210\u53ef\u89c6\u5316\u7684\u8fc7\u7a0b\u3002 \u53e6\u4e00\u4e2a\u5e93\u662f seaborn \u3002 seaborn \u7b80\u5316\u4e86\u5f88\u591a\u5e38\u7528\u53ef\u89c6\u5316\u7c7b\u578b\u7684\u751f\u6210\u3002 \u5bfc\u5165 seaborn \u4f1a\u4fee\u6539\u9ed8\u8ba4\u7684matplotlib\u914d\u8272\u65b9\u6848\u548c\u7ed8\u56fe\u6837\u5f0f\uff0c\u8fd9\u4f1a\u63d0\u9ad8\u56fe\u8868\u7684\u53ef\u8bfb\u6027\u548c\u7f8e\u89c2\u6027\u3002 \u5373\u4f7f\u4e0d\u4f7f\u7528seaborn\u7684API\uff0c\u4e5f\u53ef\u4ee5\u5bfc\u5165seaborn\u6765\u4e3a\u901a\u7528matplotlib\u56fe\u8868\u63d0\u4f9b\u66f4\u597d\u7684\u89c6\u89c9\u7f8e\u89c2\u5ea6\u3002 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns","title":"\u4f7f\u7528pandas\u548cseaborn\u7ed8\u56fe"},{"location":"python/DataAnalysis/ch06/#_5","text":"Series\u548cDataFrame\u90fd\u6709\u4e00\u4e2a plot \u5c5e\u6027\uff0c\u7528\u4e8e\u7ed8\u5236\u57fa\u672c\u7684\u56fe\u5f62\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c plot() \u7ed8\u5236\u7684\u662f\u6298\u7ebf\u56fe\u3002 Series\u7684 plot \u53c2\u6570\uff1a ax: matplotlib\u5b50\u56fe\u5bf9\u8c61axes\uff0c\u5982\u679c\u6ca1\u6709\u4f20\u503c\uff0c\u5219\u4f7f\u7528\u5f53\u524d\u6d3b\u52a8\u7684\u5b50\u56fe\u9ed8\u8ba4\u4f7f\u7528gca() alpha: \u56fe\u7247\u4e0d\u900f\u660e\u5ea6\uff080\u52301\uff09 data: \u6570\u636e\u5e8f\u5217Series figsize: \u56fe\u50cf\u5c3a\u5bf8\uff0ctuple(\u5bbd\u5ea6\uff0c\u9ad8\u5ea6)\uff0c\u6ce8\u610f\u8fd9\u91cc\u7684\u5355\u4f4d\u662f\u82f1\u5bf8 fontsize: \u8bbe\u7f6e\u523b\u5ea6\u6807\u7b7e\uff08xticks, yticks\uff09\u7684\u5927\u5c0f grid: \u7f51\u683c\u7ebf\uff08\u9ed8\u8ba4\u662f\u6253\u5f00\u7684\uff09 kind: \u56fe\u7c7b\u578b\uff1a\u6298\u7ebf\u56fe\uff0c\u67f1\u5f62\u56fe\uff0c\u6a2a\u5411\u67f1\u5f62\u56fe\uff0c\u76f4\u65b9\u56fe\uff0c\u7bb1\u7ebf\u56fe\uff0c\u5bc6\u5ea6\u56fe\uff0c\u9762\u79ef\u56fe\uff0c\u997c\u56fe label: \u5217\u7684\u522b\u540d\uff0c\u4f5c\u7528\u5728\u56fe\u4f8b\u4e0a legend: \u56fe\u4f8b loglog: x,y\u8f74\u90fd\u4f7f\u7528\u5bf9\u6570\u523b\u5ea6 logx: x\u8f74\u4f7f\u7528\u5bf9\u6570\u523b\u5ea6 logy: y\u8f74\u4f7f\u7528\u5bf9\u6570\u523b\u5ea6 mark_right: \u53cc y \u8f74\u65f6\uff0c\u5728\u56fe\u4f8b\u4e2d\u7684\u5217\u6807\u7b7e\u65c1\u589e\u52a0\u663e\u793a (right) \u6807\u8bc6 position: \u67f1\u5f62\u56fe\u7684\u67f1\u5b50\u7684\u4f4d\u7f6e\u8bbe\u7f6e rot: \u6539\u53d8\u523b\u5ea6\u6807\u7b7e\uff08xticks, yticks\uff09\u7684\u65cb\u8f6c\u5ea6\uff080\u5230360\uff09 secondary_y: \u53cc y \u8f74\uff0c\u5728\u53f3\u8fb9\u7684\u7b2c\u4e8c\u4e2a y \u8f74 style: \u7ebf\u7684\u6837\u5f0f\uff0c\u6bd4\u5982'ko--' table: \u5c06\u6570\u636e\u4ee5\u8868\u683c\u7684\u5f62\u5f0f\u5c55\u793a\u51fa\u6765 title: \u6807\u9898 use_index: \u662f\u5426\u4f7f\u7528\u7d22\u5f15\u4f5c\u4e3ax\u523b\u5ea6\u6807\u7b7e xerr: \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe xlim: \u6a2a\u8f74\u5750\u6807\u523b\u5ea6\u7684\u53d6\u503c\u8303\u56f4 xticks: x\u8f74\u523b\u5ea6\u6807\u7b7e yerr: \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe ylim: \u7eb5\u8f74\u5750\u6807\u523b\u5ea6\u7684\u53d6\u503c\u8303\u56f4 yticks: y\u8f74\u523b\u5ea6\u6807\u7b7e **kwds: matplotlib plot\u65b9\u6cd5\u7684\u5176\u4ed6\u53c2\u6570 DataFrame\u7684 plot \u53c2\u6570\uff1a x : \u6307\u6570\u636e\u6846\u5217\u7684\u6807\u7b7e\u6216\u4f4d\u7f6e\u53c2\u6570 y : \u6307\u6570\u636e\u6846\u5217\u7684\u6807\u7b7e\u6216\u4f4d\u7f6e\u53c2\u6570 kind : 'line' : \u6298\u7ebf\u56fe 'bar' : \u6761\u5f62\u56fe 'barh' : \u6a2a\u5411\u6761\u5f62\u56fe 'hist' : \u67f1\u72b6\u56fe 'box' : \u7bb1\u7ebf\u56fe 'kde' : Kernel\u7684\u5bc6\u5ea6\u4f30\u8ba1\u56fe\uff0c\u4e3b\u8981\u5bf9\u67f1\u72b6\u56fe\u6dfb\u52a0Kernel \u6982\u7387\u5bc6\u5ea6\u7ebf 'density' : 'kde' 'area' : area plot 'pie' : \u997c\u56fe 'scatter' : \u6563\u70b9\u56fe \u9700\u8981\u4f20\u5165columns\u65b9\u5411\u7684\u7d22\u5f15 'hexbin' : hexbin plot ax : \u5b50\u56fe(axes, \u4e5f\u53ef\u4ee5\u7406\u89e3\u6210\u5750\u6807\u8f74) \u8981\u5728\u5176\u4e0a\u8fdb\u884c\u7ed8\u5236\u7684matplotlib subplot\u5bf9\u8c61\u3002\u5982\u679c\u6ca1\u6709\u8bbe\u7f6e\uff0c\u5219\u4f7f\u7528\u5f53\u524dmatplotlib subplot\u3002\u5176\u4e2d\uff0c\u53d8\u91cf\u548c\u51fd\u6570\u901a\u8fc7\u6539\u53d8figure\u548caxes\u4e2d\u7684\u5143\u7d20\uff08\u4f8b\u5982\uff1atitle,label,\u70b9\u548c\u7ebf\u7b49\u7b49\uff09\u4e00\u8d77\u63cf\u8ff0figure\u548caxes\uff0c\u4e5f\u5c31\u662f\u5728\u753b\u5e03\u4e0a\u7ed8\u56fe\u3002 subplots : \u5224\u65ad\u56fe\u7247\u4e2d\u662f\u5426\u6709\u5b50\u56fe sharex : \u5982\u679c\u6709\u5b50\u56fe\uff0c\u5b50\u56fe\u5171x\u8f74\u523b\u5ea6\uff0c\u6807\u7b7e sharey : \u5982\u679c\u6709\u5b50\u56fe\uff0c\u5b50\u56fe\u5171y\u8f74\u523b\u5ea6\uff0c\u6807\u7b7e layout : \u5b50\u56fe\u7684\u884c\u5217\u5e03\u5c40 figsize : \u56fe\u7247\u5c3a\u5bf8\u5927\u5c0f use_index : \u9ed8\u8ba4\u7528\u7d22\u5f15\u505ax\u8f74 title : \u56fe\u7247\u7684\u6807\u9898\u7528\u5b57\u7b26\u4e32 grid : \u56fe\u7247\u662f\u5426\u6709\u7f51\u683c legend : \u5b50\u56fe\u7684\u56fe\u4f8b\uff0c\u6dfb\u52a0\u4e00\u4e2asubplot\u56fe\u4f8b(\u9ed8\u8ba4\u4e3aTrue) style : \u5bf9\u6bcf\u5217\u6298\u7ebf\u56fe\u8bbe\u7f6e\u7ebf\u7684\u7c7b\u578b logx : \u8bbe\u7f6ex\u8f74\u523b\u5ea6\u662f\u5426\u53d6\u5bf9\u6570 logy : \u8bbe\u7f6ey\u8f74\u523b\u5ea6\u662f\u5426\u53d6\u5bf9\u6570 loglog : \u540c\u65f6\u8bbe\u7f6ex\uff0cy\u8f74\u523b\u5ea6\u662f\u5426\u53d6\u5bf9\u6570 xticks : \u8bbe\u7f6ex\u8f74\u523b\u5ea6\u503c\uff0c\u5e8f\u5217\u5f62\u5f0f\uff08\u6bd4\u5982\u5217\u8868\uff09 yticks : \u8bbe\u7f6ey\u8f74\u523b\u5ea6\uff0c\u5e8f\u5217\u5f62\u5f0f\uff08\u6bd4\u5982\u5217\u8868\uff09 xlim : \u8bbe\u7f6e\u5750\u6807\u8f74x\u7684\u8303\u56f4\uff0c\u5217\u8868\u6216\u5143\u7ec4\u5f62\u5f0f ylim : \u8bbe\u7f6e\u5750\u6807\u8f74y\u7684\u8303\u56f4\uff0c\u5217\u8868\u6216\u5143\u7ec4\u5f62\u5f0f rot : \u8bbe\u7f6e\u8f74\u6807\u7b7e\uff08\u8f74\u523b\u5ea6\uff09\u7684\u663e\u793a\u65cb\u8f6c\u5ea6\u6570 fontsize : \u8bbe\u7f6e\u8f74\u523b\u5ea6\u7684\u5b57\u4f53\u5927\u5c0f colormap : \u8bbe\u7f6e\u56fe\u7684\u533a\u57df\u989c\u8272 colorbar : \u56fe\u7247\u67f1\u5b50 position : Specify relative alignments for bar plot layout. From 0 (left/bottom-end) to 1 (right/top-end). Default is 0.5 (center) layout : \u5e03\u5c40(rows, columns) for the layout of the plot table : \u5982\u679c\u4e3a\u6b63\uff0c\u5219\u9009\u62e9DataFrame\u7c7b\u578b\u7684\u6570\u636e\u5e76\u4e14\u8f6c\u6362\u5339\u914dmatplotlib\u7684\u5e03\u5c40 yerr : \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe xerr : \u5e26\u8bef\u5dee\u7ebf\u7684\u67f1\u5f62\u56fe stacked : \u751f\u6210\u5806\u79ef\u67f1\u72b6\u56fe sort_columns : \u4ee5\u5b57\u6bcd\u8868\u987a\u5e8f\u7ed8\u5236\u5404\u5217\uff0c\u9ed8\u8ba4\u4f7f\u7528\u524d\u5217\u987a\u5e8f secondary_y : \u8bbe\u7f6e\u7b2c\u4e8c\u4e2ay\u8f74\uff08\u53f3y\u8f74\uff09 mark_right : When using a secondary_y axis, automatically mark the column labels with \u201c(right)\u201d in the legend kwds : Options to pass to matplotlib plotting method Series data1 = np.random.randn(10).cumsum(0) s1 = pd.Series( data1, index=np.arange(0, 100, 10), ) print(s1) fig, axes = plt.subplots(3, 1) # 3\u4e2a\u5b50\u56fe s1.plot.bar(ax=axes[0], color='k', alpha=0.7) # \u6761\u5f62\u56fe(\u5b50\u56fe0)\uff0ccolor='k\u2019(\u67f1\u5b50\u7684\u989c\u8272\u8bbe\u7f6e\u4e3a\u9ed1\u8272)\uff0calpha=0.7(\u56fe\u50cf\u7684\u586b\u5145\u8272\u8bbe\u7f6e\u4e3a\u90e8\u5206\u900f\u660e) s1.plot.barh(ax=axes[1], color='k', alpha=0.7) # \u6a2a\u5411\u6761\u5f62\u56fe(\u5b50\u56fe1) s1.value_counts().plot.pie(ax=axes[2]) # \u901a\u8fc7value_counts()\u5bf9Series\u503c\u9891\u7387\u8fdb\u884c\u53ef\u89c6\u5316 plt.show() DataFrame data2 = np.random.randn(10, 4).cumsum(0) df1 = pd.DataFrame( data2, columns=pd.Index(['A', 'B', 'C', 'D'], name='Genus'), index=np.arange(0, 100, 10) ) print(df1) fig, axes = plt.subplots(2, 1) # 2\u4e2a\u5b50\u56fe df1.plot.kde(ax=axes[0], alpha=0.7, grid='True', title='KDE Figure', sharex=True) df1.plot.bar(ax=axes[1], grid='True', title='Line Figure', sharex=True, use_index=False, stacked=True) # \u56e0\u4e3a\u5171\u4eabx\u8f74\uff0c\u6240\u4ee5\u5728KDE\u5b50\u56fe\u4e2d\u6307\u5b9ause_index=False\u770b\u4e0d\u51fa\u6548\u679c\u3002 # DataFrame\u7684\u5217\u540d\u79f0\"Genus\"\u88ab\u7528\u4f5c\u4e86\u56fe\u4f8b\u6807\u9898 # stacked=True\u6765\u751f\u6210\u5806\u79ef\u67f1\u72b6\u56fe plt.show() \u5b9e\u4f8b\uff1a\u7ed8\u5236\u4e00\u4e2a\u5806\u79ef\u67f1\u72b6\u56fe\uff0c\u7528\u4e8e\u5c55\u793a\u6bcf\u4e2a\u6d3e\u5bf9\u5728\u6bcf\u5929\u7684\u6570\u636e\u70b9\u5360\u6bd4\u3002 \u4ea4\u53c9\u8868 \u662f\u4e00\u79cd\u5e38\u7528\u7684\u5206\u7c7b\u6c47\u603b\u8868\u683c\uff0c\u7528\u4e8e\u9891\u6570\u5206\u5e03\u7edf\u8ba1\uff0c\u4e3b\u8981\u4ef7\u503c\u5728\u4e8e\u63cf\u8ff0\u4e86\u53d8\u91cf\u95f4\u5173\u7cfb\u7684\u6df1\u523b\u542b\u4e49\u3002 \u867d\u7136\u4e24\u4e2a\uff08\u6216\u4ee5\u4e0a\uff09\u53d8\u91cf\u53ef\u4ee5\u662f\u5206\u7c7b\u7684\u6216\u6570\u91cf\u7684\uff0c\u4f46\u662f\u4ee5\u90fd\u662f\u5206\u7c7b\u7684\u60c5\u5f62\u6700\u4e3a\u5e38\u89c1\u3002 Pandas\u7684 crosstab() \u65b9\u6cd5\u80fd\u591f\u5feb\u901f\u6784\u5efa\u4ea4\u53c9\u8868\uff0c\u5e76\u53ef\u4ee5\u901a\u8fc7\u53c2\u6570\u52a0\u4ee5\u4e2a\u6027\u5316\u7684\u8bbe\u7f6e\u3002\u5176\u4e2d\uff0c\u7b2c\u4e00\u4e2a\u53c2\u6570\u5c06\u6784\u6210\u4ea4\u53c9\u8868\u7684\u884c\uff0c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u5c06\u6784\u6210\u4ea4\u53c9\u8868\u7684\u5217\u3002 tips = pd.read_csv('../examples/tips.csv') print(tips) # total_bill tip smoker day time size # 0 16.99 1.01 No Sun Dinner 2 # 1 10.34 1.66 No Sun Dinner 3 # 2 21.01 3.50 No Sun Dinner 3 # 3 23.68 3.31 No Sun Dinner 2 # 4 24.59 3.61 No Sun Dinner 4 # .. ... ... ... ... ... ... # 239 29.03 5.92 No Sat Dinner 3 # 240 27.18 2.00 Yes Sat Dinner 2 # 241 22.67 2.00 Yes Sat Dinner 2 # 242 17.82 1.75 No Sat Dinner 2 # 243 18.78 3.00 No Thur Dinner 2 # [244 rows x 6 columns] party_counts = pd.crosstab(tips['day'], tips['size']) # \u5bf9\u539f\u59cb\u6570\u636e\u7684day\u548csize\u8fdb\u884c\u805a\u5408\uff0c\u5e76\u6784\u5efa\u4ea4\u53c9\u8868\uff0cday\u4f5c\u4e3a\u884c\uff0csize\u4f5c\u4e3a\u5217\u3002 print(party_counts) # size 1 2 3 4 5 6 # day # Fri 1 16 1 1 0 0 # Sat 2 53 18 13 1 0 # Sun 0 39 15 18 3 1 # Thur 1 48 4 5 1 3 # \u6ca1\u6709\u592a\u591a\u76841\u4eba\u548c6\u4eba\u6d3e\u5bf9\uff0c\u820d\u5f03\u8fd9\u4e9b\u6570\u636e party_counts = party_counts.loc[:, 2:5] print(party_counts) # size 2 3 4 5 # day # Fri 16 1 1 0 # Sat 53 18 13 1 # Sun 39 15 18 3 # Thur 48 4 5 1 # \u6807\u51c6\u5316\u81f3\u548c\u4e3a1\uff1a\u6cbf0\u8f74\uff08\u884c\uff09\u5bf9\u6bcf\u5217\u6c42\u548c\uff0c\u6bcf\u884c\u5404\u503c\u9664\u4ee5\u548c\uff0c\u4ee5\u786e\u4fdd\u6bcf\u4e00\u884c\u7684\u503c\u548c\u4e3a1\uff0c\u7136\u540e\u8fdb\u884c\u7ed8\u56fe party_pcts = party_counts.div(party_counts.sum(1), axis=0) print(party_pcts) # size 2 3 4 5 # day # Fri 0.888889 0.055556 0.055556 0.000000 # Sat 0.623529 0.211765 0.152941 0.011765 # Sun 0.520000 0.200000 0.240000 0.040000 # Thur 0.827586 0.068966 0.086207 0.017241 party_counts.plot.bar() plt.show() \u53ef\u4ee5\u770b\u5230\u672c\u6570\u636e\u96c6\u4e2d\u7684\u6d3e\u5bf9\u6570\u91cf\u5728\u5468\u672b\u4f1a\u589e\u52a0\u3002 \u5b9e\u4f8b\uff1a\u4f7f\u7528seaborn\u8fdb\u884c\u6309\u661f\u671f\u65e5\u671f\u8ba1\u7b97\u5c0f\u8d39\u767e\u5206\u6bd4\u3002 Seaborn\u8981\u6c42\u6570\u636e\u7684\u8f93\u5165\u7c7b\u578b\u4e3apandas\u7684Dataframe\u6216Numpy\u6570\u7ec4\u3002 tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) print(tips) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 # .. ... ... ... ... ... ... ... # 239 29.03 5.92 No Sat Dinner 3 0.256166 # 240 27.18 2.00 Yes Sat Dinner 2 0.079428 # 241 22.67 2.00 Yes Sat Dinner 2 0.096759 # 242 17.82 1.75 No Sat Dinner 2 0.108899 # 243 18.78 3.00 No Thur Dinner 2 0.190114 # [244 rows x 7 columns] # barplot: \u5c06\u70b9\u4f30\u8ba1\u548c\u7f6e\u4fe1\u533a\u95f4\u663e\u793a\u4e3a\u77e9\u5f62\u6761\u3002\u6761\u5f62\u56fe\u8868\u793a\u5177\u6709\u6bcf\u4e2a\u77e9\u5f62\u7684\u9ad8\u5ea6\u7684\u6570\u503c\u53d8\u91cf\u7684\u96c6\u4e2d\u8d8b\u52bf\u7684\u4f30\u8ba1\uff0c\u5e76\u4e14\u4f7f\u7528\u8bef\u5dee\u6761\u63d0\u4f9b\u56f4\u7ed5\u8be5\u4f30\u8ba1\u7684\u4e0d\u786e\u5b9a\u6027\u7684\u4e00\u4e9b\u6307\u793a # \u67f1\u5b50\u7684\u503c\u662ftip_pct\u7684\u5e73\u5747\u503c # \u67f1\u5b50\u4e0a\u753b\u51fa\u7684\u9ed1\u7ebf\u4ee3\u8868\u7684\u662f95%\u7684\u7f6e\u4fe1\u533a\u95f4\uff08\u7f6e\u4fe1\u533a\u95f4\u53ef\u4ee5\u901a\u8fc7\u53ef\u9009\u53c2\u6570\u8fdb\u884c\u8bbe\u7f6e\uff09 # hue\u9009\u9879\uff0c\u5141\u8bb8\u6211\u4eec\u901a\u8fc7\u4e00\u4e2a\u989d\u5916\u7684\u5206\u7c7b\u503c\u5c06\u6570\u636e\u5206\u79bb # \u5e26\u53c2\u6570hue='time'\u65f6\uff0c\u56db\u4e2a\u4e0d\u540c\u989c\u8272\u7684\u67f1\u5b50\uff0c\u6bcf\u4e2a\u67f1\u5b50\u4e0a\u6709\u7f6e\u4fe1\u533a\u95f4\u7684\u9ed1\u7ebf\uff0c\u523b\u5ea60.00~0.30\uff0c\u6b65\u957f0.05 # \u4e0d\u5e26\u53c2\u6570hue='time'\u65f6\uff0c\u4e24\u4e2a\u4e0d\u540c\u989c\u8272\u7684\u67f1\u5b50\uff0c\u5206\u522b\u4ee3\u8868Dinner\u548cLunch\uff0c\u4e0d\u662f\u6bcf\u4e2a\u67f1\u5b50\u4e0a\u90fd\u6709\u7f6e\u4fe1\u533a\u95f4\u7684\u9ed1\u7ebf\uff0c\u523b\u5ea60.00~0.30\uff0c\u6b65\u957f0.05 sns.barplot(x='tip_pct', y='day', data=tips, hue='time', orient='h') # \u6839\u636e\u661f\u671f\u65e5\u671f\u548c\u65f6\u95f4\u8ba1\u7b97\u7684\u5c0f\u8d39\u767e\u5206\u6bd4 # sns.barplot(x='tip_pct', y='day', data=tips, orient='h') sns.set(style=\"darkgrid\", palette=\"deep\") # style=\"whitegrid\" plt.show()","title":"\u6298\u7ebf\u56fe"},{"location":"python/DataAnalysis/ch06/#_6","text":"\u76f4\u65b9\u56fe\u662f\u4e00\u79cd\u6761\u5f62\u56fe\uff0c\u7528\u4e8e\u7ed9\u51fa\u503c\u9891\u7387\u7684\u79bb\u6563\u663e\u793a\u3002\u6570\u636e\u70b9\u88ab\u5206\u6210\u79bb\u6563\u7684\uff0c\u5747\u5300\u95f4\u9694\u7684\u7bb1\uff0c\u5e76\u4e14\u7ed8\u5236\u6bcf\u4e2a\u7bb1\u4e2d\u6570\u636e\u70b9\u7684\u6570\u91cf\u3002 tips['tip_pct'].plot.hist(bins=50) # \u5c0f\u8d39\u767e\u5206\u6bd4\u7684\u76f4\u65b9\u56fe plt.show() \u5bc6\u5ea6\u56fe\u662f\u4e00\u79cd\u4e0e\u76f4\u65b9\u56fe\u76f8\u5173\u7684\u56fe\u8868\u7c7b\u578b\uff0c\u5b83\u901a\u8fc7\u8ba1\u7b97\u53ef\u80fd\u4ea7\u751f\u89c2\u6d4b\u6570\u636e\u7684\u8fde\u7eed\u6982\u7387\u5206\u5e03\u4f30\u8ba1\u800c\u4ea7\u751f\u3002 \u901a\u5e38\u7684\u505a\u6cd5\u662f\u5c06\u8fd9\u79cd\u5206\u5e03\u8fd1\u4f3c\u4e3a\u201c\u5185\u6838\u201d\u7684\u6df7\u5408\uff0c\u4e5f\u5c31\u662f\u50cf\u6b63\u6001\u5206\u5e03\u90a3\u6837\u7b80\u5355\u7684\u5206\u5e03\u3002 \u56e0\u6b64\uff0c\u5bc6\u5ea6\u56fe\u4e5f\u88ab\u79f0\u4e3a\u5185\u6838\u5bc6\u5ea6\u4f30\u8ba1\u56fe\uff08KDE\uff09\u3002 tips['tip_pct'].plot.density() # \u5c0f\u8d39\u767e\u5206\u6bd4\u5bc6\u5ea6\u56fe plt.show() \u7ed8\u5236\u76f4\u65b9\u56fe\u548c\u8fde\u7eed\u5bc6\u5ea6\u4f30\u8ba1 sns.displot() \u3002 sns.distplot(tips['tip_pct'], bins=100, color='k') plt.show() # FutureWarning: `distplot` is a deprecated function and will be removed in a future version. # Please adapt your code to use either `displot` (a figure-level function with similar flexibility) # or `histplot` (an axes-level function for histograms).","title":"\u76f4\u65b9\u56fe\u548c\u5bc6\u5ea6\u56fe"},{"location":"python/DataAnalysis/ch06/#_7","text":"\u70b9\u56fe\u6216\u6563\u70b9\u56fe\u53ef\u4ee5\u7528\u4e8e\u68c0\u9a8c\u4e24\u4e2a\u4e00\u7ef4\u6570\u636e\u5e8f\u5217\u4e4b\u95f4\u7684\u5173\u7cfb\u3002 \u5b9e\u4f8b\uff1a\u4ece statsmodels \u9879\u76ee\u4e2d\u8f7d\u5165\u4e86macrodata\u6570\u636e\u96c6\uff0c\u5e76\u9009\u62e9\u4e86\u4e00\u4e9b\u53d8\u91cf\uff0c\u4e4b\u540e\u8ba1\u7b97\u5bf9\u6570\u5dee\u3002 macro = pd.read_csv('../examples/macrodata.csv') print(macro.head(5)) # year quarter realgdp realcons ... unemp pop infl realint # 0 1959.0 1.0 2710.349 1707.4 ... 5.8 177.146 0.00 0.00 # 1 1959.0 2.0 2778.801 1733.7 ... 5.1 177.830 2.34 0.74 # 2 1959.0 3.0 2775.488 1751.8 ... 5.3 178.657 2.74 1.09 # 3 1959.0 4.0 2785.204 1753.7 ... 5.6 179.386 0.27 4.06 # 4 1960.0 1.0 2847.699 1770.5 ... 5.2 180.007 2.31 1.19 # [5 rows x 14 columns] data = macro[['cpi', 'm1', 'tbilrate', 'unemp']] print(data.head(5)) # cpi m1 tbilrate unemp # 0 28.98 139.7 2.82 5.8 # 1 29.15 141.7 3.08 5.1 # 2 29.35 140.5 3.82 5.3 # 3 29.37 140.0 4.33 5.6 # 4 29.54 139.6 3.50 5.2 trans_data = np.log(data).diff().dropna() print(trans_data[-5:]) # cpi m1 tbilrate unemp # 198 -0.007904 0.045361 -0.396881 0.105361 # 199 -0.021979 0.066753 -2.277267 0.139762 # 200 0.002340 0.010286 0.606136 0.160343 # 201 0.008419 0.037461 -0.200671 0.127339 # 202 0.008894 0.012202 -0.405465 0.042560 \u7528 seaborn \u7684 regplot \u65b9\u6cd5\u7ed8\u5236\u6563\u70b9\u56fe\uff0c\u5e76\u62df\u5408\u51fa\u4e00\u4e2a\u6761\u7ebf\u6027\u56de\u5f52\u7ebf\u3002( seaborn\u6587\u6863 ) sns.regplot('m1', 'unemp', data=trans_data) plt.title('Changes in log %s versus log %s ' % ('m1', 'unemp')) plt.show() \u5728\u63a2\u7d22\u6027\u6570\u636e\u5206\u6790\u4e2d\uff0c\u80fd\u591f\u67e5\u770b\u4e00\u7ec4\u53d8\u91cf\u4e2d\u7684\u6240\u6709\u6563\u70b9\u56fe\u662f\u6709\u5e2e\u52a9\u7684\uff0c\u8fd9\u88ab\u79f0\u4e3a\u6210\u5bf9\u56fe\u6216\u6563\u70b9\u56fe\u77e9\u9635\u3002 Seaborn\u6709\u4e00\u4e2a\u65b9\u4fbf\u7684 pairplot \u51fd\u6570\uff0c\u5b83\u652f\u6301\u5728\u5bf9\u89d2\u7ebf\u4e0a\u653e\u7f6e\u6bcf\u4e2a\u53d8\u91cf\u7684\u76f4\u65b9\u56fe\u6216\u5bc6\u5ea6\u4f30\u8ba1\u503c\u3002 plot_ksw \u53c2\u6570\u80fd\u591f\u5c06\u914d\u7f6e\u9009\u9879\u4f20\u9012\u7ed9\u975e\u5bf9\u89d2\u5143\u7d20\u4e0a\u7684\u5404\u4e2a\u7ed8\u56fe\u8c03\u7528\u3002 sns.pairplot(trans_data, diag_kind='kde', plot_kws={'alpha': 0.2}) plt.show()","title":"\u6563\u70b9\u56fe\u6216\u70b9\u56fe"},{"location":"python/DataAnalysis/ch06/#_8","text":"\u5982\u679c\u6570\u636e\u96c6\u6709\u989d\u5916\u7684\u5206\u7ec4\u7ef4\u5ea6\u600e\u4e48\u529e\uff1f\u4f7f\u7528\u5206\u9762\u7f51\u683c\u662f\u5229\u7528\u591a\u79cd\u5206\u7ec4\u53d8\u91cf\u5bf9\u6570\u636e\u8fdb\u884c\u53ef\u89c6\u5316\u7684\u65b9\u5f0f\u3002 seaborn\u62e5\u6709\u4e00\u4e2a\u6709\u6548\u7684\u5185\u5efa\u51fd\u6570 factorplot \uff0c\u5b83\u53ef\u4ee5\u7b80\u5316\u591a\u79cd\u5206\u9762\u7ed8\u56fe\u3002 sns.factorplot(x='day', y='tip_pct', hue='time', col='smoker', kind='bar', data=tips[tips.tip_pct < 1]) plt.show() # UserWarning: The `factorplot` function has been renamed to `catplot`. # The original name will be removed in a future release. Please update your code. # Note that the default `kind` in `factorplot` (`'point'`) has changed `'strip'` in `catplot`. sns.catplot(x='day', y='tip_pct', hue='time', col='smoker', kind='box', data=tips[tips.tip_pct < 0.5]) plt.show()","title":"\u5206\u9762\u7f51\u683c\u548c\u5206\u7c7b\u6570\u636e"},{"location":"python/DataAnalysis/ch06/#python","text":"\u81ea2010\u5e74\u4ee5\u6765\uff0c\u5f88\u591a\u5f00\u53d1\u5de5\u4f5c\u90fd\u96c6\u4e2d\u5728\u521b\u5efaweb\u4ea4\u4e92\u5f0f\u56fe\u5f62\u4e0a\u3002 \u501f\u52a9\u50cf Bokeh \u548c Plotly \u8fd9\u6837\u7684\u5de5\u5177\uff0c\u5728web\u6d4f\u89c8\u5668\u4e2d\u521b\u5efa\u52a8\u6001\u7684\u3001\u4ea4\u4e92\u5f0f\u56fe\u50cf\u7684\u5de5\u4f5c\u73b0\u5728\u5df2\u7ecf\u53ef\u4ee5\u5b9e\u73b0\u3002 \u53ef\u89c6\u5316\u662f\u4e00\u4e2a\u6d3b\u8dc3\u7684\u7814\u7a76\u9886\u57df\u3002","title":"\u5176\u4ed6Python\u53ef\u89c6\u5316\u5de5\u5177"},{"location":"python/DataAnalysis/ch07/","text":"\u6570\u636e\u805a\u5408\u4e0e\u5206\u7ec4\u64cd\u4f5c \u00b6 GroupBy\u673a\u5236 \u00b6 import pandas as pd import numpy as np \u5206\u7ec4\u673a\u5236 \u00b6 \u5206\u7ec4\u64cd\u4f5c\u7b2c\u4e00\u6b65\uff0c\u6570\u636e\u5305\u542b\u5728pandas\u5bf9\u8c61\u4e2d\uff0c\u53ef\u4ee5\u662fSeries\u3001DataFrame\u6216\u5176\u4ed6\u6570\u636e\u7ed3\u6784\u3002\u4e4b\u540e\u6839\u636e\u63d0\u4f9b\u7684\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u5206\u79bb\u5230\u5404\u4e2a\u7ec4\u4e2d\u3002 \u5206\u7ec4\u952e\u53ef\u662f\u591a\u79cd\u5f62\u5f0f\u7684\uff0c\u5e76\u4e14\u952e\u4e0d\u4e00\u5b9a\u662f\u5b8c\u5168\u76f8\u540c\u7684\u7c7b\u578b(\u6ce8\u610f\u540e\u9762\u4ecb\u7ecd\u7684\u4e09\u4e2a\u65b9\u6cd5\u662f\u53ef\u4ee5\u4ea7\u751f\u7528\u4e8e\u5206\u9694\u5bf9\u8c61\u7684\u503c\u6570\u7ec4\u7684\u5feb\u6377\u65b9\u5f0f)\uff1a \u4e0e\u9700\u8981\u5206\u7ec4\u7684\u8f74\u5411\u957f\u5ea6\u4e00\u81f4\u7684\u503c\u5217\u8868\u6216\u503c\u6570\u7ec4\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cgroupby\u5728axis=0\u7684\u8f74\u5411\u4e0a\u5206\u7ec4\u3002 DataFrame\u7684\u5217\u540d\u7684\u503c\u3002 \u53ef\u4ee5\u5c06\u5206\u7ec4\u8f74\u5411\u4e0a\u7684\u503c\u548c\u5206\u7ec4\u540d\u79f0\u76f8\u5339\u914d\u7684\u5b57\u5178\u6216Series\u3002 \u53ef\u4ee5\u5728\u8f74\u7d22\u5f15\u6216\u7d22\u5f15\u4e2d\u7684\u5355\u4e2a\u6807\u7b7e\u4e0a\u8c03\u7528\u7684\u51fd\u6570\u3002 \u8bf7\u6ce8\u610f\uff0c\u5206\u7ec4\u952e\u4e2d\u7684\u4efb\u4f55\u7f3a\u5931\u503c\u5c06\u88ab\u6392\u9664\u5728\u7ed3\u679c\u4e4b\u5916\u3002 \u5206\u79bb\u64cd\u4f5c\u662f\u5728\u6570\u636e\u5bf9\u8c61\u7684\u7279\u5b9a\u8f74\u5411\u4e0a\u8fdb\u884c\u7684\u3002\u4f8b\u5982\uff0cDataFrame\u53ef\u4ee5\u5728\u5b83\u7684\u884c\u65b9\u5411\uff08axis=0\uff09\u6216\u5217\u65b9\u5411\uff08axis=1\uff09\u8fdb\u884c\u5206\u7ec4\u3002 \u5206\u7ec4\u64cd\u4f5c\u540e\uff0c\u4e00\u4e2a\u51fd\u6570\u5c31\u53ef\u4ee5\u5e94\u7528\u5230\u5404\u4e2a\u7ec4\u4e2d\uff0c\u4ea7\u751f\u65b0\u7684\u503c\u3002\u6700\u7ec8\uff0c\u6240\u6709\u51fd\u6570\u7684\u5e94\u7528\u7ed3\u679c\u4f1a\u8054\u5408\u4e3a\u4e00\u4e2a\u7ed3\u679c\u5bf9\u8c61\u3002 df = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a'], 'key2': ['one', 'two', 'one', 'two', 'one'], 'data1': [1, 3, 5, 7, 9], 'data2': [2, 4, 6, 8, 10] } ) \u6839\u636ekey1\u6807\u7b7e\u8ba1\u7b97data1\u5217\u7684\u5747\u503c\uff0c\u65b9\u6cd5\u4e00\uff0c\u8bbf\u95ee data1 \u5e76\u4f7f\u7528 key1 \u5217\uff08\u5b83\u662f\u4e00\u4e2aSeries\uff09\u8c03\u7528 groupby \u65b9\u6cd5\uff1a grouped = df['data1'].groupby(df['key1']) print(grouped) # grouped \u53d8\u91cf\u73b0\u5728\u662f\u4e00\u4e2a GroupBy \u5bf9\u8c61\uff0c\u5b83\u5b9e\u9645\u4e0a\u8fd8\u6ca1\u6709\u8fdb\u884c\u4efb\u4f55\u8ba1\u7b97\uff0c\u62e5\u6709\u4e00\u4e9b\u5173\u4e8e\u5206\u7ec4\u952edf['key1']\u7684\u4e00\u4e9b\u4e2d\u95f4\u6570\u636e\u7684\u4fe1\u606f\u3002 \u4e0b\u9762\u5bf9 grouped \u5bf9\u8c61\u505a\u4e00\u4e9b\u64cd\u4f5c\uff1a result = grouped.mean() # \u8ba1\u7b97\u5e73\u5747\u503c print(result) # key1 # a 4.333333 # b 6.000000 # Name: data1, dtype: float64 grouped_means = df['data1'].groupby([df['key1'], df['key2']]).mean() print(grouped_means) # key1 key2 # a one 5.0 # two 3.0 # b one 5.0 # two 7.0 # Name: data1, dtype: float64 \u4e0a\u9762\u4f8b\u5b50\u4f7f\u7528\u4e86\u4e24\u4e2a\u952e\u5bf9\u6570\u636e\u8fdb\u884c\u5206\u7ec4\uff0c\u5e76\u4e14\u7ed3\u679cSeries\u73b0\u5728\u62e5\u6709\u4e00\u4e2a\u5305\u542b\u552f\u4e00\u952e\u5bf9\u7684\u591a\u5c42\u7d22\u5f15\u3002 \u4e0b\u9762\u5bf9\u8ba1\u7b97\u7684\u5e73\u5747\u503c\uff08mean\uff09\u8fdb\u884c\u91cd\u5851\uff08unstack\uff09\u3002 print(grouped_means.unstack()) # key2 one two # key1 # a 5.0 3.0 # b 5.0 7.0 \u5206\u7ec4\u4fe1\u606f\u901a\u5e38\u5305\u542b\u5728\u540c\u4e00\u4e2aDataFrame\u4e2d\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u53ef\u4ee5\u4f20\u9012\u5217\u540d\uff08\u65e0\u8bba\u90a3\u4e9b\u5217\u540d\u662f\u5b57\u7b26\u4e32\u3001\u6570\u5b57\u6216\u5176\u4ed6Python\u5bf9\u8c61\uff09\u4f5c\u4e3a\u5206\u7ec4\u952e\uff1a \u4e0b\u9762\u4f8b\u5b50\u4e2d df.groupby('key1').mean() \u7684\u7ed3\u679c\u91cc\u5e76\u6ca1\u6709 key2 \u5217\u3002\u8fd9\u662f\u56e0\u4e3a df['key2'] \u5e76\u4e0d\u662f\u6570\u503c\u6570\u636e\uff0c\u5373 df['key2'] \u662f\u4e00\u4e2a\u5197\u4f59\u5217\uff0c\u56e0\u6b64\u88ab\u6392\u9664\u5728\u7ed3\u679c\u4e4b\u5916\u3002 result = df.groupby('key1').mean() print(result) # data1 data2 # key1 # a 4.333333 5.333333 # b 6.000000 7.000000 result = df.groupby(['key1', 'key2']).mean() print(result) # data1 data2 # key1 key2 # a one 5.0 6.0 # two 3.0 4.0 # b one 5.0 6.0 # two 7.0 8.0 result = df.groupby(['key1', 'key2']).size() print(result) # key1 key # a one 2 # two 1 # b one 1 # two 1 # dtype: int64 \u904d\u5386\u5404\u5206\u7ec4 \u00b6 GroupBy \u5bf9\u8c61\u652f\u6301\u8fed\u4ee3\uff0c\u4f1a\u751f\u6210\u4e00\u4e2a\u5305\u542b\u7ec4\u540d\u548c\u6570\u636e\u5757\u76842\u7ef4\u5143\u7ec4\u5e8f\u5217\u3002 df = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a'], 'key2': ['one', 'two', 'one', 'two', 'one'], 'data1': [1, 3, 5, 7, 9], 'data2': [2, 4, 6, 8, 10] } ) \u5355\u4e2a\u5206\u7ec4\u952e\u7684\u60c5\u51b5: for name, group in df.groupby('key1'): print(name) print(group) # a # key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10 # b # key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 \u591a\u4e2a\u5206\u7ec4\u952e\u7684\u60c5\u51b5: \u5143\u7ec4\u4e2d\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u662f\u952e\u503c\u7684\u5143\u7ec4\u3002 for (k1, k2), group in df.groupby(['key1', 'key2']): print((k1, k2)) print(group) # ('a', 'one') # key1 key2 data1 data2 # 0 a one 1 2 # 4 a one 9 10 # ('a', 'two') # key1 key2 data1 data2 # 1 a two 3 4 # ('b', 'one') # key1 key2 data1 data2 # 2 b one 5 6 # ('b', 'two') # key1 key2 data1 data2 # 3 b two 7 8 result = dict(list(df.groupby('key1'))) print(result) # df.groupby('key1')\u7684\u7ed3\u679c\u662f\u4e00\u4e2a\u5bf9\u8c61 # # list(df.groupby('key1'))\u7684\u7ed3\u679c\u662f\u5305\u542bFrameData\u7684\u7ed3\u6784\u7684\u5217\u8868list: # [ # ('a', key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10), # ('b', key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8) # ] # dict(list(df.groupby('key1')))\u7684\u7ed3\u679c\u662f\u5305\u542bFrameData\u7684\u7ed3\u6784\u7684\u5b57\u5178dict # { # 'a': key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10, # 'b': key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 # } print(result['b']) # key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c groupby \u5728 axis=0 \u7684\u8f74\u5411\u4e0a\u5206\u7ec4\uff0c\u4e5f\u53ef\u4ee5\u5728\u5176\u4ed6\u4efb\u610f\u8f74\u5411\u4e0a\u8fdb\u884c\u5206\u7ec4\u3002 print(df.dtypes) # key1 object # key2 object # data1 int64 # data2 int64 # dtype: object grouped = df.groupby(df.dtypes, axis=1) print(grouped) # print(list(grouped)) # [ # (dtype('int64'), data1 data2 # 0 1 2 # 1 3 4 # 2 5 6 # 3 7 8 # 4 9 10), # (dtype('O'), key1 key2 # 0 a one # 1 a two # 2 b one # 3 b two # 4 a one) # ] \u6253\u5370\u5404\u5206\u7ec4\u5982\u4e0b\uff1a for dtype, group in grouped: print(dtype) print(group) # int64 # data1 data2 # 0 1 2 # 1 3 4 # 2 5 6 # 3 7 8 # 4 9 10 # object # key1 key2 # 0 a one # 1 a two # 2 b one # 3 b two # 4 a one \u9009\u62e9\u4e00\u5217\u6216\u6240\u6709\u5217\u7684\u5b50\u96c6 \u00b6 \u5bf9\u4e8e\u4eceDataFrame\u521b\u5efa\u7684 GroupBy \u5bf9\u8c61\uff0c\u7528\u5217\u540d\u79f0\u6216\u5217\u540d\u79f0\u6570\u7ec4\u8fdb\u884c\u7d22\u5f15\u65f6\uff0c\u4f1a\u4ea7\u751f\u7528\u4e8e\u805a\u5408\u7684\u5217\u5b50\u96c6\u7684\u6548\u679c\u3002 \u5982\u679c\u4f20\u9012\u7684\u662f\u5217\u8868\u6216\u6570\u7ec4\uff0c\u5219\u6b64\u7d22\u5f15\u64cd\u4f5c\u8fd4\u56de\u7684\u5bf9\u8c61\u662f\u5206\u7ec4\u7684DataFrame\uff1b\u5982\u679c\u53ea\u6709\u5355\u4e2a\u5217\u540d\u4f5c\u4e3a\u6807\u91cf\u4f20\u9012\uff0c\u5219\u4e3a\u5206\u7ec4\u7684Series\uff1b \u5bf9\u6bd4\u4e0b\u97624\u53e5\uff1a result = df.groupby('key1')['data1'] # \u5355\u4e2a\u5217\u540d print(result) # for key, data in result: print(key) print(data) result = df['data1'].groupby(df['key1']) # \u5355\u4e2a\u5217\u540d print(result) # for key, data in result: print(key) print(data) # a # 0 1 # 1 3 # 4 9 # Name: data1, dtype: int64 # b # 2 5 # 3 7 # Name: data1, dtype: int64 result = df.groupby('key1')[['data1']] # \u5217\u8868\u6216\u6570\u7ec4 print(result) # for key, data in result: print(key) print(data) # a # key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10 # b # key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 result = df[['data1']].groupby(df['key1']) # \u5217\u8868\u6216\u6570\u7ec4 print(result) # for key, data in result: print(key) print(data) # a # data1 # 0 1 # 1 3 # 4 9 # b # data1 # 2 5 # 3 7 \u4f7f\u7528\u5b57\u5178\u548cSeries\u5206\u7ec4 \u00b6 \u5206\u7ec4\u4fe1\u606f\u53ef\u80fd\u4f1a\u4ee5\u975e\u6570\u7ec4\u5f62\u5f0f\u5b58\u5728\u3002 \u751f\u6210\u4e00\u4e2a\u793a\u4f8bDataFrame\u3002 people = pd.DataFrame( [[1, 3, 5, 7, 9], [0, 2, 4, 6, 8], [0, 2, 4, 6, 8], [1, 3, 5, 7, 9], [1, 2, 3, 4, 5]], columns=['a', 'b', 'c', 'd', 'e'], index=['Joe', 'Steve', 'Wes', 'Jim', 'Travis'] ) \u6dfb\u52a0\u4e00\u4e9bNA\u503c\u3002 people.iloc[2:3, [1, 2]] = np.nan print(people) # a b c d e # Joe 1 3.0 5.0 7 9 # Steve 0 2.0 4.0 6 8 # Wes 0 NaN NaN 6 8 # Jim 1 3.0 5.0 7 9 # Travis 1 2.0 3.0 4 5 \u5047\u8bbe\u6709\u5982\u4e0b\u5404\u5217\u7684\u5206\u7ec4\u5bf9\u5e94\u5173\u7cfb\uff0c\u5e76\u4e14\u60f3\u628a\u5404\u5217\u6309\u7ec4\u7d2f\u52a0\u3002 mapping = { 'a': 'red', 'b': 'red', 'c': 'blue', 'd': 'blue', 'e': 'red', 'f': 'orange' # \u6ce8\u610f\uff1a\u5065f\u867d\u7136\u6ca1\u6709\u88ab\u7528\u5230\uff0c\u4f46\u4e0d\u5f71\u54cd\u5728\u8fd9\u91cc\u5b9a\u4e49\u3002 } \u628a mapping \u8fd9\u4e2a\u5b57\u5178\u4f20\u7ed9 groupby() \u3002 by_column = people.groupby(mapping, axis=1) print(by_column.sum()) # blue red # Joe 12.0 13.0 # Steve 10.0 10.0 # Wes 6.0 8.0 # Jim 12.0 13.0 # Travis 7.0 8.0 Series\u4e5f\u6709\u76f8\u540c\u7684\u529f\u80fd\uff0c\u53ef\u4ee5\u89c6\u4e3a\u56fa\u5b9a\u5927\u5c0f\u7684\u6620\u5c04\u3002 map_services = pd.Series(mapping) print(map_services) # a red # b red # c blue # d blue # e red # f orange # dtype: object result = people.groupby(map_services, axis=1).count() print(result) # blue red # Joe 2 3 # Steve 2 3 # Wes 1 2 # Jim 2 3 # Travis 2 3 \u4f7f\u7528\u51fd\u6570\u5206\u7ec4 \u00b6 \u4e0e\u4f7f\u7528\u5b57\u5178\u6216Series\u5206\u7ec4\u76f8\u6bd4\uff0c\u4f7f\u7528Python\u51fd\u6570\u662f\u5b9a\u4e49\u5206\u7ec4\u5173\u7cfb\u7684\u4e00\u79cd\u66f4\u4e3a\u901a\u7528\u7684\u65b9\u5f0f\u3002 \u4f5c\u4e3a\u5206\u7ec4\u952e\u4f20\u9012\u7684\u51fd\u6570\u5c06\u4f1a\u6309\u7167\u6bcf\u4e2a\u7d22\u5f15\u503c\u8c03\u7528\u4e00\u6b21\uff0c\u540c\u65f6\u8fd4\u56de\u503c\u4f1a\u88ab\u7528\u4f5c\u5206\u7ec4\u540d\u79f0\u3002\u6ce8\u610f\uff1a\u51fd\u6570\u662f\u4f5c\u7528\u5728\u7d22\u5f15\u4e0a\u3002 result = people.groupby(len).sum() # \u4eba\u7684\u540d\u5b57\u662f\u7d22\u5f15\u503c\uff0c\u6839\u636e\u540d\u5b57\u7684\u957f\u5ea6\u6765\u8fdb\u884c\u5206\u7ec4 print(result) # a b c d e # 3 2 6.0 10.0 20 26 # 5 0 2.0 4.0 6 8 # 6 1 2.0 3.0 4 5 \u53ef\u4ee5\u5c06\u51fd\u6570\u4e0e\u6570\u7ec4\u3001\u5b57\u5178\u6216Series\u8fdb\u884c\u6df7\u5408\uff0c\u6240\u6709\u7684\u5bf9\u8c61\u90fd\u4f1a\u5728\u5185\u90e8\u8f6c\u6362\u4e3a\u6570\u7ec4\u3002 key_list = ['one', 'one', 'one', 'two', 'two'] result = people.groupby([len, key_list]).min() print(result) # a b c d e # 3 one 0 3.0 5.0 6 8 # two 1 3.0 5.0 7 9 # 5 one 0 2.0 4.0 6 8 # 6 two 1 2.0 3.0 4 5 \u6839\u636e\u7d22\u5f15\u5c42\u7ea7\u5206\u7ec4 \u00b6 \u6839\u636e\u5c42\u7ea7\u5206\u7ec4\u65f6\uff0c\u5c06\u5c42\u7ea7\u6570\u503c\u6216\u5c42\u7ea7\u540d\u79f0\u4f20\u9012\u7ed9 level \u5173\u952e\u5b57\u3002 columns = pd.MultiIndex.from_arrays( [['US', 'US', 'US', 'JP', 'JP'], [1, 3, 5, 1, 3]], names=['cty', 'tenor'] ) hier_df = pd.DataFrame( [[1, 3, 5, 7, 9], [0, 2, 4, 6, 8], [1, 3, 5, 7, 9], [1, 2, 3, 4, 5]], columns=columns ) print(hier_df) # cty US JP # tenor 1 3 5 1 3 # 0 1 3 5 7 9 # 1 0 2 4 6 8 # 2 1 3 5 7 9 # 3 1 2 3 4 5 result = hier_df.groupby(level='cty', axis=1).count() print(result) # cty JP US # 0 2 3 # 1 2 3 # 2 2 3 # 3 2 3 \u6570\u636e\u805a\u5408 \u00b6 \u805a\u5408\u662f\u6307\u6240\u6709\u6839\u636e\u6570\u7ec4\u4ea7\u751f\u6807\u91cf\u503c\u7684\u6570\u636e\u8f6c\u6362\u8fc7\u7a0b\uff0c\u6bd4\u5982\uff1a mean \u3001 count \u3001 min \u548c sum \u7b49\u4e00\u4e9b\u805a\u5408\u64cd\u4f5c\u3002 import pandas as pd import numpy as np \u9884\u5907\u77e5\u8bc6\uff1a \u5206\u4f4d\u6570\uff08Quantile\uff09\uff0c\u4e5f\u79f0\u5206\u4f4d\u70b9\uff0c\u662f\u6307\u5c06\u4e00\u4e2a\u968f\u673a\u53d8\u91cf\u7684\u6982\u7387\u5206\u5e03\u8303\u56f4\u5206\u4e3a\u51e0\u4e2a\u7b49\u4efd\u7684\u6570\u503c\u70b9\uff0c\u5206\u6790\u5176\u6570\u636e\u53d8\u91cf\u7684\u8d8b\u52bf\u3002 \u5e38\u7528\u7684\u5206\u4f4d\u6570\u6709 \u4e2d\u4f4d\u6570\u3001\u56db\u5206\u4f4d\u6570\u3001\u767e\u5206\u4f4d\u6570\u7b49\u3002 \u4e2d\u4f4d\u6570\uff08Medians\uff09\u662f\u4e00\u4e2a\u7edf\u8ba1\u5b66\u7684\u4e13\u6709\u540d\u8bcd\uff0c\u4ee3\u8868\u4e00\u4e2a\u6837\u672c\u3001\u79cd\u7fa4\u6216\u6982\u7387\u5206\u5e03\u4e2d\u7684\u4e00\u4e2a\u6570\u503c\uff0c\u53ef\u4ee5\u5c06\u6570\u503c\u96c6\u5408\u5212\u5206\u4e3a\u76f8\u7b49\u7684\u4e24\u90e8\u5206\u3002 \u5229\u7528pandas\u5e93\u8ba1\u7b97 data = [6, 47, 49, 15, 42, 41, 7, 39, 43, 40, 36] \u7684\u5206\u4f4d\u6570\u3002 \u786e\u5b9a p \u5206\u4f4d\u6570\u4f4d\u7f6e\u7684\u4e24\u79cd\u65b9\u6cd5( n \u4e3a\u6570\u636e\u7684\u603b\u4e2a\u6570\uff0c p \u4e3a 0-1 \u4e4b\u95f4\u7684\u503c)\u3002\u5728python\u4e2d\u8ba1\u7b97\u5206\u4f4d\u6570\u4f4d\u7f6e\u7684\u65b9\u6848\u91c7\u7528 position=1+(n-1)*p \uff1a position = (n+1)*p position = 1 + (n-1)*p \u6848\u4f8b1 data = pd.Series(np.array([6, 47, 49, 15, 42, 41, 7, 39, 43, 40, 36])) print(\"\u6570\u636e\u683c\u5f0f\uff1a\") print(np.sort(data)) # \u5fc5\u987b\u8981\u6392\u5e8f print('Q1:', data.quantile(.25)) print('Q2:', data.quantile(.5)) print('Q3:', data.quantile(.75)) # \u6570\u636e\u683c\u5f0f\uff1a # [ 6 7 15 36 39 40 41 42 43 47 49] # Q1: 25.5 # Q2: 40.0 # Q3: 42.5 # \u624b\u7b97\u8ba1\u7b97\u7ed3\u679c\uff1a # Q1\u7684p\u5206\u4f4d\u6570(0.25)\u4f4d\u7f6eposition = 1+(11-1)*0.25 = 3.5(\u53d6\u7b2c3\u4f4d) (p=0.25) Q1=15+(36-15)*0.5=25.5 (\u7b2c3\u30014\u4f4d\u7684\u5dee\u4e58\u4ee5\u4f59\u65700.5) # Q2\u7684p\u5206\u4f4d\u6570(0.5)\u4f4d\u7f6eposition = 1+(11-1)*0.5 = 6 (p=0.5) Q2=40 # Q3\u7684p\u5206\u4f4d\u6570(0.75)\u4f4d\u7f6eposition = 1+(11-1)*0.75 = 9 (p=0.75) Q3=42+(43-42)*0.5=42.5 # IQR = Q3 - Q1 = 17 \u6848\u4f8b2 df = pd.DataFrame(np.array([[1, 1], [2, 10], [3, 100], [4, 100]]), columns=['a', 'b']) print(\"\u6570\u636e\u539f\u59cb\u683c\u5f0f\uff1a\") print(df) print(\"\u8ba1\u7b97p=0.1\u65f6\uff0ca\u5217\u548cb\u5217\u7684\u5206\u4f4d\u6570\") print(df.quantile(.1)) # \u6570\u636e\u539f\u59cb\u683c\u5f0f\uff1a # a b # 0 1 1 # 1 2 10 # 2 3 100 # 3 4 100 # \u8ba1\u7b97p=0.1\u65f6\uff0ca\u5217\u548cb\u5217\u7684\u5206\u4f4d\u6570 # a 1.3 # b 3.7 # Name: 0.1, dtype: float64 # \u624b\u7b97\u8ba1\u7b97\u7ed3\u679c\uff1a # \u8ba1\u7b97a\u5217 # position=1+(4-1)*0.1=1.3 (\u53d6\u7b2c1\u4f4d) # Q1=1+(2-1)*0.3=1.3 (\u7b2c1\u30012\u4f4d\u7684\u5dee\u4e58\u4ee5\u4f59\u65700.3) # \u8ba1\u7b97b\u5217 # position=1+(4-1)*0.1=1.3 (\u53d6\u7b2c1\u4f4d) # Q1=1+(10-1)*0.3=3.7 (\u7b2c1\u30012\u4f4d\u7684\u5dee\u4e58\u4ee5\u4f59\u65700.3) \u4f18\u5316\u7684 groupby \u65b9\u6cd5\uff1a count: \u5206\u7ec4\u4e2d\u975eNA\u503c\u7684\u6570\u91cf sum: \u975eNA\u503c\u7684\u7d2f\u52a0\u548c mean: \u975eNA\u503c\u7684\u5e73\u5747\u503c median: \u975eNA\u503c\u7684\u7b97\u672f\u4e2d\u4f4d\u6570 std, var: \u65e0\u504f\u7684(n-1\u5206\u6bcd)\u6807\u51c6\u5dee\u548c\u65b9\u5dee min, max: \u975eNA\u503c\u7684\u6700\u5c0f\u503c\u3001\u6700\u5927\u503c prod: \u975eNA\u503c\u7684\u4e58\u79ef first, last: \u975eNA\u503c\u7684\u7b2c\u4e00\u4e2a\u3001\u6700\u540e\u4e00\u4e2a\u503c df = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a'], 'key2': ['one', 'two', 'one', 'two', 'one'], 'data1': [1, 3, 5, 7, 9], 'data2': [2, 4, 6, 8, 10] } ) print(df) # key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 2 b one 5 6 # 3 b two 7 8 # 4 a one 9 10 grouped = df.groupby('key1') result = grouped['data1'] for i in result: print(i) # ('a', 0 1 # 1 3 # 4 9 # Name: data1, dtype: int64) # ('b', 2 5 # 3 7 # Name: data1, dtype: int64) result = grouped['data1'].quantile(0.9) # quantile\u5206\u4f4d\u6570 print(result) # key1 # a 7.8 # b 6.8 # Name: data1, dtype: float64 # \u624b\u7b97\u8ba1\u7b97\u7ed3\u679c\uff1a # \u8ba1\u7b97a\u5217 # position=1+(3-1)*0.9=2.8 # Q1=3+(9-3)*0.8=7.8 # \u8ba1\u7b97b\u5217 # position=1+(2-1)*0.9=1.9 # Q1=5+(7-5)*0.9=6.8 \u4f7f\u7528\u81ea\u884c\u5236\u5b9a\u7684\u805a\u5408\uff0c\u5e76\u518d\u8c03\u7528\u5df2\u7ecf\u5728\u5206\u7ec4\u5bf9\u8c61\u4e0a\u5b9a\u4e49\u597d\u7684\u65b9\u6cd5\u3002 def peak_to_peak(arr): return arr.max() - arr.min() result = grouped.agg(peak_to_peak) print(result) # data1 data2 # key1 # a 8 8 # b 2 2 result = grouped.describe() print(result) # data1 ... data2 # count mean std min 25% ... min 25% 50% 75% max # key1 ... # a 3.0 4.333333 4.163332 1.0 2.0 ... 2.0 3.0 4.0 7.0 10.0 # b 2.0 6.000000 1.414214 5.0 5.5 ... 6.0 6.5 7.0 7.5 8.0 \u9010\u5217\u53ca\u591a\u51fd\u6570\u5e94\u7528 \u00b6 tips = pd.read_csv('../examples/tips.csv') tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) print(tips.head(5)) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 \u6839\u636e\u5404\u5217\u540c\u65f6\u4f7f\u7528\u591a\u4e2a\u51fd\u6570\u8fdb\u884c\u805a\u5408 grouped = tips.groupby(['day', 'smoker']) # for i in grouped: # print(i) # (('Fri', 'No'), total_bill tip smoker day time size tip_pct # 91 22.49 3.50 No Fri Dinner 2 0.184308 # ...... # 223 15.98 3.00 No Fri Lunch 3 0.231125) # (('Fri', 'Yes'), total_bill tip smoker day time size tip_pct # 90 28.97 3.00 Yes Fri Dinner 2 0.115518 # ...... # 226 10.09 2.00 Yes Fri Lunch 2 0.247219) # ...... grouped_pct = grouped['tip_pct'] for i in grouped_pct: print(i) # (('Fri', 'No'), 91 0.184308 # 94 0.166667 # ...... # Name: tip_pct, dtype: float64) # (('Fri', 'Yes'), 90 0.115518 # 92 0.210526 # ...... # Name: tip_pct, dtype: float64) # ...... \u5c06\u51fd\u6570\u540d\u4ee5\u5b57\u7b26\u4e32\u5f62\u5f0f\u4f20\u9012\u3002 result = grouped_pct.agg('mean') print(result) # day smoker # Fri No 0.179740 # Yes 0.216293 # Sat No 0.190412 # Yes 0.179833 # Sun No 0.193617 # Yes 0.322021 # Thur No 0.193424 # Yes 0.198508 # Name: tip_pct, dtype: float64 \u5982\u679c\u4f20\u9012\u7684\u662f\u51fd\u6570\u6216\u8005\u51fd\u6570\u540d\u7684\u5217\u8868\uff0c\u4f1a\u5f97\u5230\u4e00\u4e2a\u5217\u540d\u662f\u8fd9\u4e9b\u51fd\u6570\u540d\u7684DataFrame\u3002 \u4e0b\u9762\u4f20\u9012\u4e86\u805a\u5408\u51fd\u6570\u7684\u5217\u8868\u7ed9agg\u65b9\u6cd5\uff0c\u8fd9\u4e9b\u51fd\u6570\u4f1a\u5404\u81ea\u8fd0\u7528\u4e8e\u6570\u636e\u5206\u7ec4\u3002 result = grouped_pct.agg(['mean', 'std', peak_to_peak]) print(result) # mean std peak_to_peak # day smoker # Fri No 0.179740 0.039458 0.094263 # Yes 0.216293 0.077530 0.242219 # Sat No 0.190412 0.058626 0.352192 # Yes 0.179833 0.089496 0.446137 # Sun No 0.193617 0.060302 0.274897 # Yes 0.322021 0.538061 2.382107 # Thur No 0.193424 0.056065 0.284273 # Yes 0.198508 0.057170 0.219047 \u5982\u679c\u4f20\u9012\u7684\u662f (name, function) \u5143\u7ec4\u7684\u5217\u8868\uff0c\u6bcf\u4e2a\u5143\u7ec4\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5c06\u4f5c\u4e3aDataFrame\u7684\u5217\u540d\uff08\u53ef\u4ee5\u8ba4\u4e3a\u4e8c\u5143\u5143\u7ec4\u7684\u5217\u8868\u662f\u4e00\u79cd\u6709\u5e8f\u7684\u5bf9\u5e94\u5173\u7cfb\uff09\uff1a result = grouped_pct.agg([('foo', 'mean'), ('bar', np.std)]) # foo\u662fmean\u503c\u7684\u5217\u540d print(result) # foo bar # day smoker # Fri No 0.179740 0.039458 # Yes 0.216293 0.077530 # Sat No 0.190412 0.058626 # Yes 0.179833 0.089496 # Sun No 0.193617 0.060302 # Yes 0.322021 0.538061 # Thur No 0.193424 0.056065 # Yes 0.198508 0.057170 \u53ef\u4ee5\u6307\u5b9a\u5e94\u7528\u5230\u6240\u6709\u5217\u4e0a\u7684\u51fd\u6570\u5217\u8868\u6216\u6bcf\u4e00\u5217\u4e0a\u8981\u5e94\u7528\u7684\u4e0d\u540c\u51fd\u6570\u3002 \u4e0b\u9762\u4ea7\u751f\u7684DataFrame\u62e5\u6709\u5206\u5c42\u5217\uff0c\u4e0e\u5206\u522b\u805a\u5408\u6bcf\u4e00\u5217\uff0c\u518d\u4ee5\u5217\u540d\u4f5c\u4e3a keys \u53c2\u6570\u4f7f\u7528 concat \u5c06\u7ed3\u679c\u62fc\u63a5\u5728\u4e00\u8d77\u7684\u7ed3\u679c\u76f8\u540c\u3002 functions = ['count', 'mean', 'max'] result = grouped[['tip_pct', 'total_bill']].agg(functions) print(result) # tip_pct total_bill # count mean max count mean max # day smoker # Fri No 4 0.179740 0.231125 4 18.420000 22.75 # Yes 15 0.216293 0.357737 15 16.813333 40.17 # Sat No 45 0.190412 0.412409 45 19.661778 48.33 # Yes 42 0.179833 0.483092 42 21.276667 50.81 # Sun No 57 0.193617 0.338101 57 20.506667 48.17 # Yes 19 0.322021 2.452381 19 24.120000 45.35 # Thur No 45 0.193424 0.362976 45 17.113111 41.19 # Yes 17 0.198508 0.317965 17 19.190588 43.11 # \u628a['tip_pct', 'total_bill']\u6539\u6210[['tip_pct', 'total_bill']]\uff0c\u5c31\u53ef\u4ee5\u907f\u514d\u62a5\u9519 # FutureWarning: Indexing with multiple keys (implicitly converted to a tuple of keys) will be deprecated, use a list instead. # result = grouped['tip_pct', 'total_bill'].agg(functions) print(result['tip_pct']) # count mean max # day smoker # Fri No 4 0.179740 0.231125 # Yes 15 0.216293 0.357737 # Sat No 45 0.190412 0.412409 # Yes 42 0.179833 0.483092 # Sun No 57 0.193617 0.338101 # Yes 19 0.322021 2.452381 # Thur No 45 0.193424 0.362976 # Yes 17 0.198508 0.317965 \u4e5f\u540c\u6837\u53ef\u4ee5\u4f20\u9012\u5177\u6709\u81ea\u5b9a\u4e49\u540d\u79f0\u7684\u5143\u7ec4\u5217\u8868\uff1a ftuples = [('Durchschnitt', 'mean'), ('Abweichung', np.var)] result = grouped[['tip_pct', 'total_bill']].agg(ftuples) print(result) # tip_pct total_bill # Durchschnitt Abweichung Durchschnitt Abweichung # day smoker # Fri No 0.179740 0.001557 18.420000 25.596333 # Yes 0.216293 0.006011 16.813333 82.562438 # Sat No 0.190412 0.003437 19.661778 79.908965 # Yes 0.179833 0.008010 21.276667 101.387535 # Sun No 0.193617 0.003636 20.506667 66.099980 # Yes 0.322021 0.289509 24.120000 109.046044 # Thur No 0.193424 0.003143 17.113111 59.625081 # Yes 0.198508 0.003268 19.190588 69.808518 \u8981\u5c06\u4e0d\u540c\u7684\u51fd\u6570\u5e94\u7528\u5230\u4e00\u4e2a\u6216\u591a\u4e2a\u5217\u4e0a\uff0c\u9700\u8981\u5c06\u542b\u6709\u5217\u540d\u4e0e\u51fd\u6570\u5bf9\u5e94\u5173\u7cfb\u7684\u5b57\u5178\u4f20\u9012\u7ed9 agg \uff1a result = grouped.agg({'tip': np.max, 'size': 'sum'}) print(result) # tip size # day smoker # Fri No 3.50 9 # Yes 4.73 31 # Sat No 9.00 115 # Yes 10.00 104 # Sun No 6.00 167 # Yes 6.50 49 # Thur No 6.70 112 # Yes 5.00 40 result = grouped.agg({'tip_pct': ['min', 'max', 'mean', 'std']}) print(result) # tip_pct # min max mean std # day smoker # Fri No 0.136861 0.231125 0.179740 0.039458 # Yes 0.115518 0.357737 0.216293 0.077530 # Sat No 0.060217 0.412409 0.190412 0.058626 # Yes 0.036955 0.483092 0.179833 0.089496 # Sun No 0.063204 0.338101 0.193617 0.060302 # Yes 0.070274 2.452381 0.322021 0.538061 # Thur No 0.078704 0.362976 0.193424 0.056065 # Yes 0.098918 0.317965 0.198508 0.057170 \u53ea\u6709\u591a\u4e2a\u51fd\u6570\u5e94\u7528\u4e8e\u81f3\u5c11\u4e00\u4e2a\u5217\u65f6\uff0cDataFrame\u624d\u5177\u6709\u5206\u5c42\u5217\u3002 \u8fd4\u56de\u4e0d\u542b\u884c\u7d22\u5f15\u7684\u805a\u5408\u6570\u636e \u00b6 \u5728\u524d\u9762\u6240\u6709\u7684\u4f8b\u5b50\u4e2d\uff0c\u805a\u5408\u6570\u636e\u8fd4\u56de\u65f6\u90fd\u662f\u5e26\u6709\u7d22\u5f15\u7684\uff0c\u6709\u65f6\u7d22\u5f15\u662f\u5206\u5c42\u7684\uff0c\u7531\u552f\u4e00\u7684\u5206\u7ec4\u952e\u8054\u5408\u5f62\u6210\u3002 \u56e0\u4e3a\u4e0d\u662f\u6240\u6709\u7684\u60c5\u51b5\u4e0b\u90fd\u9700\u8981\u7d22\u5f15\uff0c\u6240\u4ee5\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\u53ef\u4ee5\u901a\u8fc7\u5411groupby\u4f20\u9012as_index=False\u6765\u7981\u7528\u5206\u7ec4\u952e\u4f5c\u4e3a\u7d22\u5f15\u7684\u884c\u4e3a\uff1a result = tips.groupby(['day', 'smoker'], as_index=False).mean() print(result) # day smoker total_bill tip size tip_pct # 0 Fri No 18.420000 2.812500 2.250000 0.179740 # 1 Fri Yes 16.813333 2.714000 2.066667 0.216293 # 2 Sat No 19.661778 3.102889 2.555556 0.190412 # 3 Sat Yes 21.276667 2.875476 2.476190 0.179833 # 4 Sun No 20.506667 3.167895 2.929825 0.193617 # 5 Sun Yes 24.120000 3.516842 2.578947 0.322021 # 6 Thur No 17.113111 2.673778 2.488889 0.193424 # 7 Thur Yes 19.190588 3.030000 2.352941 0.198508 \u901a\u8fc7\u5728\u7ed3\u679c\u4e0a\u8c03\u7528reset_index\u4e5f\u53ef\u4ee5\u83b7\u5f97\u540c\u6837\u7684\u7ed3\u679c\u3002\u4f7f\u7528as_index=False\u53ef\u4ee5\u907f\u514d\u4e00\u4e9b\u4e0d\u5fc5\u8981\u7684\u8ba1\u7b97\u3002 result = tips.groupby(['day', 'smoker']).mean() print(result.reset_index()) # day smoker total_bill tip size tip_pct # 0 Fri No 18.420000 2.812500 2.250000 0.179740 # 1 Fri Yes 16.813333 2.714000 2.066667 0.216293 # 2 Sat No 19.661778 3.102889 2.555556 0.190412 # 3 Sat Yes 21.276667 2.875476 2.476190 0.179833 # 4 Sun No 20.506667 3.167895 2.929825 0.193617 # 5 Sun Yes 24.120000 3.516842 2.578947 0.322021 # 6 Thur No 17.113111 2.673778 2.488889 0.193424 # 7 Thur Yes 19.190588 3.030000 2.352941 0.198508 print(result) # total_bill tip size tip_pct # day smoker # Fri No 18.420000 2.812500 2.250000 0.179740 # Yes 16.813333 2.714000 2.066667 0.216293 # Sat No 19.661778 3.102889 2.555556 0.190412 # Yes 21.276667 2.875476 2.476190 0.179833 # Sun No 20.506667 3.167895 2.929825 0.193617 # Yes 24.120000 3.516842 2.578947 0.322021 # Thur No 17.113111 2.673778 2.488889 0.193424 # Yes 19.190588 3.030000 2.352941 0.198508 \u5e94\u7528\uff1a\u901a\u7528\u62c6\u5206-\u5e94\u7528-\u8054\u5408 \u00b6 import pandas as pd import numpy as np import statsmodels.api as sm GroupBy \u65b9\u6cd5\u6700\u5e38\u89c1\u7684\u76ee\u7684\u662f apply \uff08\u5e94\u7528\uff09\u3002 apply \u5c06\u5bf9\u8c61\u62c6\u5206\u6210\u591a\u5757\uff0c\u7136\u540e\u5728\u6bcf\u4e00\u5757\u4e0a\u8c03\u7528\u4f20\u9012\u7684\u51fd\u6570\uff0c\u4e4b\u540e\u5c1d\u8bd5\u5c06\u6bcf\u4e00\u5757\u62fc\u63a5\u5230\u4e00\u8d77\u3002 \u6839\u636e\u4e0b\u9762\u7684\u5c0f\u8d39\u6570\u636e\u96c6\uff0c\u6309\u7ec4\u9009\u51fa\u5c0f\u8d39\u767e\u5206\u6bd4\uff08tip-pct\uff09\u6700\u9ad8\u7684\u4e94\u7ec4\u3002 tips = pd.read_csv('../examples/tips.csv') tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) \u6837\u672c\u6570\u636e print(tips.head(5)) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 \u9996\u5148\uff0c\u5199\u4e00\u4e2a\u53ef\u4ee5\u5728\u7279\u5b9a\u5217\u4e2d\u9009\u51fa\u6700\u5927\u503c\u6240\u5728\u884c\u7684\u51fd\u6570\uff1a \u6dfb\u52a0\u4e86\u5347\u5e8f\uff0c\u7ed3\u679c\u8f93\u51fa\u6700\u540e5\u884c\uff08\u6700\u540e\u76845\u884c\u4e5f\u662f\u6700\u5927\u76845\u4e2a tip_tcp \u8bb0\u5f55\uff09\u3002 def top(df, n=5, column='tip_pct'): return df.sort_values(by=column, ascending=True)[-n:] result = top(tips, n=6) print(result) # \u7b49\u4ef7\u65b9\u5f0f\uff1a # result = tips.sort_values('tip_pct')[-6:] # print(result) # total_bill tip smoker day time size tip_pct # 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 \u5982\u679c\u6309\u7167 smoker \u8fdb\u884c\u5206\u7ec4\uff0c\u4e4b\u540e\u8c03\u7528 apply \uff0c\u4f1a\u5f97\u5230\u4ee5\u4e0b\u7ed3\u679c\uff1a top \u51fd\u6570\u5728DataFrame\u7684\u6bcf\u4e00\u884c\u5206\u7ec4\u4e0a\u88ab\u8c03\u7528\uff0c\u4e4b\u540e\u4f7f\u7528 pandas.concat \u5c06\u51fd\u6570\u7ed3\u679c\u7c98\u8d34\u5728\u4e00\u8d77\uff0c\u5e76\u4f7f\u7528\u5206\u7ec4\u540d\u4f5c\u4e3a\u5404\u7ec4\u7684\u6807\u7b7e\u3002 \u56e0\u6b64\u7ed3\u679c\u5305\u542b\u4e00\u4e2a\u5206\u5c42\u7d22\u5f15\uff0c\u8be5\u5206\u5c42\u7d22\u5f15\u7684\u5185\u90e8\u5c42\u7ea7\u5305\u542b\u539fDataFrame\u7684\u7d22\u5f15\u503c\u3002 result = tips.groupby('smoker').apply(top) print(result) # total_bill tip smoker day time size tip_pct # smoker # No 88 24.71 5.85 No Thur Lunch 2 0.310180 # 185 20.69 5.00 No Sun Dinner 5 0.318674 # 51 10.29 2.60 No Sun Dinner 2 0.338101 # 149 7.51 2.00 No Thur Lunch 2 0.362976 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # Yes 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 \u5982\u679c\u9664\u4e86\u5411 apply \u4f20\u9012\u51fd\u6570\uff0c\u8fd8\u4f20\u9012\u5176\u4ed6\u53c2\u6570\u6216\u5173\u952e\u5b57\u7684\u8bdd\uff0c\u4f60\u53ef\u4ee5\u628a\u8fd9\u4e9b\u653e\u5728\u51fd\u6570\u540e\u8fdb\u884c\u4f20\u9012\u3002 result = tips.groupby('smoker').apply(top, n=1, column='total_bill') print(result) # \u8fd92\u884c\u90fd\u662fsmoker\u662fyes\u548cno\u65f6\u6700\u5927total_bill\u503c\u6240\u5728\u884c\u3002 # total_bill tip smoker day time size tip_pct # smoker # No 212 48.33 9.0 No Sat Dinner 4 0.228833 # Yes 170 50.81 10.0 Yes Sat Dinner 3 0.245038 \u5728 GroupBy \u5bf9\u8c61\u4e0a\u8c03\u7528 describe \u65b9\u6cd5\u3002 result = tips.groupby('smoker')['tip_pct'].describe() print(result) # count mean std ... 50% 75% max # smoker ... # No 151.0 0.192237 0.057665 ... 0.184308 0.227015 0.412409 # Yes 93.0 0.218176 0.254295 ... 0.181818 0.242326 2.452381 # [2 rows x 8 columns] print(result.unstack('smoker')) # \u7c7b\u4f3c\u4e8e\u8f6c\u7f6e # smoker # count No 151.000000 # Yes 93.000000 # mean No 0.192237 # Yes 0.218176 # std No 0.057665 # Yes 0.254295 # min No 0.060217 # Yes 0.036955 # 25% No 0.158622 # Yes 0.119534 # 50% No 0.184308 # Yes 0.181818 # 75% No 0.227015 # Yes 0.242326 # max No 0.412409 # Yes 2.452381 # dtype: float64 \u5728 GroupBy \u5bf9\u8c61\u7684\u5185\u90e8\uff0c\u5f53\u8c03\u7528\u50cf describe \u8fd9\u6837\u7684\u65b9\u6cd5\u65f6\uff0c\u5b9e\u9645\u4e0a\u662f\u4ee5\u4e0b\u4ee3\u7801\u7684\u7b80\u5199\uff1a grouped = tips.groupby(['smoker']) f = lambda x: x.describe() result = grouped.apply(f) print(result) # total_bill tip size tip_pct # smoker # No count 151.000000 151.000000 151.000000 151.000000 # mean 19.188278 2.991854 2.668874 0.192237 # std 8.255582 1.377190 1.017984 0.057665 # min 7.250000 1.000000 1.000000 0.060217 # 25% 13.325000 2.000000 2.000000 0.158622 # 50% 17.590000 2.740000 2.000000 0.184308 # 75% 22.755000 3.505000 3.000000 0.227015 # max 48.330000 9.000000 6.000000 0.412409 # Yes count 93.000000 93.000000 93.000000 93.000000 # mean 20.756344 3.008710 2.408602 0.218176 # std 9.832154 1.401468 0.810751 0.254295 # min 3.070000 1.000000 1.000000 0.036955 # 25% 13.420000 2.000000 2.000000 0.119534 # 50% 17.920000 3.000000 2.000000 0.181818 # 75% 26.860000 3.680000 3.000000 0.242326 # max 50.810000 10.000000 5.000000 2.452381 \u538b\u7f29\u5206\u7ec4\u952e \u00b6 \u5728\u524d\u9762\u7684\u4f8b\u5b50\u4e2d\u6240\u5f97\u5230\u7684\u5bf9\u8c61\uff0c\u90fd\u5177\u6709\u5206\u7ec4\u952e\u6240\u5f62\u6210\u7684\u5206\u5c42\u7d22\u5f15\u4ee5\u53ca\u6bcf\u4e2a\u539f\u59cb\u5bf9\u8c61\u7684\u7d22\u5f15\u3002 \u4e5f\u53ef\u4ee5\u901a\u8fc7\u5411 groupby \u4f20\u9012 group_keys=False \u6765\u7981\u7528\u8fd9\u4e2a\u529f\u80fd\u3002 result = tips.groupby('smoker', group_keys=True).apply(top) print(result) # total_bill tip smoker day time size tip_pct # smoker # No 88 24.71 5.85 No Thur Lunch 2 0.310180 # 185 20.69 5.00 No Sun Dinner 5 0.318674 # 51 10.29 2.60 No Sun Dinner 2 0.338101 # 149 7.51 2.00 No Thur Lunch 2 0.362976 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # Yes 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 result = tips.groupby('smoker', group_keys=False).apply(top) print(result) # total_bill tip smoker day time size tip_pct # 88 24.71 5.85 No Thur Lunch 2 0.310180 # 185 20.69 5.00 No Sun Dinner 5 0.318674 # 51 10.29 2.60 No Sun Dinner 2 0.338101 # 149 7.51 2.00 No Thur Lunch 2 0.362976 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 \u5206\u4f4d\u6570\u4e0e\u6876\u5206\u6790 \u00b6 \u7b2c8\u7ae0\u4e2d\uff0cpandas\u6709\u4e00\u4e9b\u5de5\u5177\uff0c\u5c24\u5176\u662f cut \u548c qcut \uff0c\u7528\u4e8e\u5c06\u6570\u636e\u6309\u7167\u4f60\u9009\u62e9\u7684\u7bb1\u4f4d\u6216\u6837\u672c\u5206\u4f4d\u6570\u8fdb\u884c\u5206\u6876\u3002 \u4e0e groupby \u65b9\u6cd5\u4e00\u8d77\u4f7f\u7528\u8fd9\u4e9b\u51fd\u6570\u53ef\u4ee5\u5bf9\u6570\u636e\u96c6\u66f4\u65b9\u4fbf\u5730\u8fdb\u884c\u5206\u6876\u6216\u5206\u4f4d\u5206\u6790\u3002 \u590d\u4e60\uff1a\u673a\u68b0\u5b66\u4e60\u4e2d\u7684\u5206\u7bb1\u5904\u7406\u3002 \u5728\u673a\u68b0\u5b66\u4e60\u4e2d\u7ecf\u5e38\u4f1a\u5bf9\u6570\u636e\u8fdb\u884c\u5206\u7bb1\u5904\u7406\u7684\u64cd\u4f5c\uff0c \u4e5f\u5c31\u662f\u628a\u4e00\u6bb5\u8fde\u7eed\u7684\u503c\u5207\u5206\u6210\u82e5\u5e72\u6bb5\uff0c\u6bcf\u4e00\u6bb5\u7684\u503c\u770b\u6210\u4e00\u4e2a\u5206\u7c7b\u3002\u8fd9\u4e2a\u628a\u8fde\u7eed\u503c\u8f6c\u6362\u6210\u79bb\u6563\u503c\u7684\u8fc7\u7a0b\uff0c\u6211\u4eec\u53eb\u505a\u5206\u7bb1\u5904\u7406\u3002 \u6bd4\u5982\uff0c\u628a\u5e74\u9f84\u630915\u5c81\u5212\u5206\u6210\u4e00\u7ec4\uff0c0-15\u5c81\u53eb\u505a\u5c11\u5e74\uff0c16-30\u5c81\u53eb\u505a\u9752\u5e74\uff0c31-45\u5c81\u53eb\u505a\u58ee\u5e74\u3002\u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e2d\uff0c\u6211\u4eec\u628a\u8fde\u7eed\u7684\u5e74\u9f84\u5206\u6210\u4e86\u4e09\u4e2a\u7c7b\u522b\uff0c\u201c\u5c11\u5e74\u201d\uff0c\u201c\u9752\u5e74\u201d\u548c\u201c\u58ee\u5e74\u201d\u5c31\u662f\u5404\u4e2a\u7c7b\u522b\u7684\u540d\u79f0\uff0c\u6216\u8005\u53eb\u505a\u6807\u7b7e\u3002 \u5728pandas\u4e2d\uff0c cut \u548c qcut \u51fd\u6570\u90fd\u53ef\u4ee5\u8fdb\u884c\u5206\u7bb1\u5904\u7406\u64cd\u4f5c\u3002 cut() \u6309\u7167\u53d8\u91cf\u7684\u503c\u5bf9\u53d8\u91cf\u8fdb\u884c\u5206\u5272\uff0c\u6bcf\u4e2a\u5206\u7ec4\u91cc\u6570\u636e\u7684\u4e2a\u6570\u5e76\u4e0d\u4e00\u6837\u3002 qcut() \u662f\u6309\u53d8\u91cf\u7684\u6570\u91cf\u6765\u5bf9\u53d8\u91cf\u8fdb\u884c\u5206\u5272\uff0c\u5e76\u4e14\u5c3d\u91cf\u4fdd\u8bc1\u6bcf\u4e2a\u5206\u7ec4\u91cc\u53d8\u91cf\u7684\u4e2a\u6570\u76f8\u540c\u3002 \u8003\u8651\u4e0b\u9762\u4e00\u4e2a\u7b80\u5355\u7684\u968f\u673a\u6570\u636e\u96c6\u548c\u4e00\u4e2a\u4f7f\u7528 cut \u7684\u7b49\u957f\u6876\u5206\u7c7b\uff1a df = pd.DataFrame( { 'data1': np.random.randn(1000), 'data2': np.random.randn(1000) } ) quartiles = pd.cut(df.data1, 4) # \u6309\u7167data1\u503c\u7531\u5c0f\u5230\u5927\u7684\u987a\u5e8f\u5c06\u6570\u636e\u5206\u62104\u4efd\uff0c\u5e76\u4e14\u4f7f\u6bcf\u7ec4\u503c\u7684\u8303\u56f4\u5927\u81f4\u76f8\u7b49\u3002 print(quartiles[:10]) # 0 (-0.0743, 1.729] # 1 (-0.0743, 1.729] # 2 (-0.0743, 1.729] # 3 (-0.0743, 1.729] # 4 (-1.877, -0.0743] # 5 (-0.0743, 1.729] # 6 (-0.0743, 1.729] # 7 (-0.0743, 1.729] # 8 (-1.877, -0.0743] # 9 (-0.0743, 1.729] # Name: data1, dtype: category # Categories ( # 4, # interval[float64, right]): [ # (-3.687, -1.877] < (-1.877, -0.0743] < (-0.0743, 1.729] < (1.729, 3.531] # ] \u4e0a\u9762 cut \u8fd4\u56de\u7684 Categorical \u5bf9\u8c61\u53ef\u4ee5\u76f4\u63a5\u4f20\u9012\u7ed9 groupby \u3002\u5229\u7528\u5b83\u8ba1\u7b97\u51fa data2 \u5217\u7684\u4e00\u4e2a\u7edf\u8ba1\u503c\u96c6\u5408\uff0c\u5982\u4e0b\uff1a def get_stats(group): return { 'min': group.min(), 'max': group.max(), 'count': group.count(), 'mean': group.mean() } grouped = df.data2.groupby(quartiles) for i in grouped: print(i) result = grouped.apply(get_stats).unstack() print(result) # min max count mean # data1 # (-3.145, -1.424] -1.759377 2.484321 77.0 -0.127900 # (-1.424, 0.29] -3.142344 2.830654 524.0 -0.081931 # (0.29, 2.005] -3.557136 3.261635 376.0 0.015715 # (2.005, 3.719] -2.829458 1.766352 23.0 -0.198780 \u4f7f\u7528 qcut \uff0c\u6839\u636e\u6837\u672c\u5206\u4f4d\u6570\u8ba1\u7b97\u51fa\u7b49\u5927\u5c0f\u7684\u6876\uff0c\u5c31\u662f\u7b49\u957f\u6876\u3002\u901a\u8fc7\u4f20\u9012 labels=False \u6765\u83b7\u5f97\u5206\u4f4d\u6570\u6570\u503c\u3002 grouping = pd.qcut(df.data1, 10, labels=False) grouped = df.data2.groupby(grouping) result = grouped.apply(get_stats).unstack() print(result) # min max count mean # data1 # 0 -3.678934 3.022862 100.0 0.029658 # 1 -2.319813 2.646502 100.0 0.094035 # 2 -2.873727 2.470840 100.0 0.023866 # 3 -2.196701 2.042251 100.0 0.021232 # 4 -2.154161 2.020809 100.0 0.110834 # 5 -2.723061 2.415626 100.0 0.057365 # 6 -2.291470 2.536159 100.0 0.020866 # 7 -2.064083 1.799356 100.0 -0.081025 # 8 -3.405679 1.792581 100.0 -0.009705 # 9 -2.469285 2.600849 100.0 -0.061721 \u793a\u4f8b\uff1a\u4f7f\u7528\u6307\u5b9a\u5206\u7ec4\u503c\u586b\u5145\u7f3a\u5931\u503c \u00b6 \u5728\u6e05\u9664\u7f3a\u5931\u503c\u65f6\uff0c\u6709\u65f6\u4f1a\u4f7f\u7528 dropna \u6765\u53bb\u9664\u7f3a\u5931\u503c\uff0c\u6709\u65f6\u4f7f\u7528\u4fee\u6b63\u503c\u6216\u6765\u81ea\u4e8e\u5176\u4ed6\u6570\u636e\u7684\u503c\u6765\u8f93\u5165\uff08\u586b\u5145\uff09\u5230 null \u503c\uff08 NA \uff09\u3002 fillna \u662f\u4e00\u4e2a\u53ef\u4ee5\u4f7f\u7528\u7684\u6b63\u786e\u5de5\u5177\u3002 \u4f8b\u5982\u4e0b\u9762\u4f8b\u5b50\u4e2d\u4f7f\u7528\u4f7f\u7528\u5e73\u5747\u503c\u6765\u586b\u5145NA\u503c\uff1a data = (100, 110, 120, 130, 140, 150) s = pd.Series(data) print(s) # 0 100 # 1 110 # 2 120 # 3 130 # 4 140 # 5 150 # dtype: float64 \u5c06\u6570\u636e\u4e2d\u7684\u4e00\u4e9b\u503c\u8bbe\u7f6e\u4e3a\u7f3a\u5931\u503c\uff1a s[::2] = np.nan print(s) # 0 NaN # 1 110.0 # 2 NaN # 3 130.0 # 4 NaN # 5 150.0 # dtype: float64 result = s.fillna(s.mean()) # 110, 130, 150\u7684\u5e73\u5747\u503c\u662f130 print(result) # 0 130.0 # 1 110.0 # 2 130.0 # 3 130.0 # 4 130.0 # 5 150.0 # dtype: float64 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u6309\u7ec4\u586b\u5145NA\u503c\uff1a \u65b9\u6cd51,\u5bf9\u6570\u636e\u5206\u7ec4\u540e\u4f7f\u7528 apply \u3002 \u65b9\u6cd52,\u5728\u6bcf\u4e2a\u6570\u636e\u5757\u4e0a\u90fd\u8c03\u7528 fillna \u7684\u51fd\u6570\u3002 data = (100, 110, 120, 130, 140, 150, 160, 170) states = ['Ohio', 'New York', 'Vermont', 'Florida', 'Oregon', 'Nevada', 'California', 'Idaho'] group_key = ['East'] * 4 + ['West'] * 4 # 4\u4e2aEast\u548c4\u4e2aWest\u62fc\u63a5\u7684\u5217\u8868list s = pd.Series(data, index=states) print(s) # Ohio 100 # New York 110 # Vermont 120 # Florida 130 # Oregon 140 # Nevada 150 # California 160 # Idaho 170 # dtype: int64 \u5c06\u6570\u636e\u4e2d\u7684\u4e00\u4e9b\u503c\u8bbe\u7f6e\u4e3a\u7f3a\u5931\u503c\uff1a s[['Vermont', 'Nevada', 'Idaho']] = np.nan print(s) # Ohio 100.0 # New York 110.0 # Vermont NaN # Florida 130.0 # Oregon 140.0 # Nevada NaN # California 160.0 # Idaho NaN # dtype: float64 result = s.groupby(group_key).mean() print(result) # East 113.333333 # West 150.000000 # dtype: float64 \u7528\u4e0a\u9762\u5f97\u51fa\u7684\u5206\u7ec4\u5e73\u5747\u503c\u6765\u586b\u5145NA\u3002 fill_mean = lambda g: g.fillna(g.mean()) result = s.groupby(group_key).apply(fill_mean) print(result) # Ohio 100.000000 # New York 110.000000 # Vermont 113.333333 # Florida 130.000000 # Oregon 140.000000 # Nevada 150.000000 # California 160.000000 # Idaho 150.000000 # dtype: float64 \u5982\u679c\u5df2\u7ecf\u5728\u4ee3\u7801\u4e2d\u4e3a\u6bcf\u4e2a\u5206\u7ec4\u9884\u5b9a\u4e49\u4e86\u586b\u5145\u503c\uff0c\u53ef\u4ee5\u5229\u7528\u6bcf\u4e2a\u5206\u7ec4\u90fd\u6709\u7684\u5185\u7f6e\u7684 name \u5c5e\u6027\uff0c\u5b9e\u73b0\u586b\u5145 NA \u3002 fill_value = {'East': 0.5, 'West': -1} fill_func = lambda g: g.fillna(fill_value[g.name]) result = s.groupby(group_key).apply(fill_func) print(result) # Ohio 100.0 # New York 110.0 # Vermont 0.5 # Florida 130.0 # Oregon 140.0 # Nevada -1.0 # California 160.0 # Idaho -1.0 # dtype: float64 \u793a\u4f8b\uff1a\u968f\u673a\u91c7\u6837\u4e0e\u6392\u5217 \u00b6 \u5047\u8bbe\u60f3\u4ece\u5927\u6570\u636e\u96c6\u4e2d\u62bd\u53d6\u968f\u673a\u6837\u672c\uff08\u6709\u6216\u6ca1\u6709\u66ff\u6362\uff09\u4ee5\u7528\u4e8e\u8499\u7279\u5361\u7f57\u6a21\u62df\u76ee\u7684\u6216\u67d0\u4e9b\u5176\u4ed6\u5e94\u7528\u7a0b\u5e8f\u3002 \u6709\u5f88\u591a\u65b9\u6cd5\u6765\u6267\u884c\u201c\u62bd\u53d6\u201d\uff0c\u8fd9\u91cc\u4f7f\u7528Series\u7684sample\u65b9\u6cd5\u3002 \u4e3a\u4e86\u6f14\u793a\uff0c\u8fd9\u91cc\u4ecb\u7ecd\u4e00\u79cd\u6784\u9020\u4e00\u526f\u82f1\u5f0f\u6251\u514b\u724c\u7684\u65b9\u6cd5\uff1a # \u6885\u82b1clubs\u3001\u65b9\u5757diamonds\u3001\u7ea2\u6843hearts\u3001\u9ed1\u6843spades\u3002 suits = ['H', 'S', 'C', 'D'] card_val = (list(range(1, 11)) + [10] * 3) * 4 # card_val [ # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10 # ] base_names = ['A'] + list(range(2, 11)) + ['J', 'K', 'Q'] # base_names\uff1a ['A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'K', 'Q'] \u751f\u6210\u4e86\u4e00\u4e2a\u957f\u5ea6\u4e3a 52 \u7684Series, Series\u7684\u7d22\u5f15\u5305\u542b\u4e86\u724c\u540d\uff0cSeries\u7684\u503c\u53ef\u4ee5\u7528\u6e38\u620f\uff08\u4e3a\u4e86\u4fdd\u6301\u7b80\u5355\uff0c\u8ba9\u2019A\u2019\u4e3a1 \uff09\uff1a cards = [] for suit in ['H', 'S', 'C', 'D']: cards.extend(str(num) + suit for num in base_names) deck = pd.Series(card_val, index=cards) print(deck) # AH 1 # 2H 2 # 3H 3 # 4H 4 # 5H 5 # 6H 6 # 7H 7 # 8H 8 # 9H 9 # 10H 10 # JH 10 # KH 10 # QH 10 # AS 1 # 2S 2 # 3S 3 # 4S 4 # 5S 5 # 6S 6 # 7S 7 # 8S 8 # 9S 9 # 10S 10 # JS 10 # KS 10 # QS 10 # AC 1 # 2C 2 # 3C 3 # 4C 4 # 5C 5 # 6C 6 # 7C 7 # 8C 8 # 9C 9 # 10C 10 # JC 10 # KC 10 # QC 10 # AD 1 # 2D 2 # 3D 3 # 4D 4 # 5D 5 # 6D 6 # 7D 7 # 8D 8 # 9D 9 # 10D 10 # JD 10 # KD 10 # QD 10 # dtype: int64 \u4ece\u8fd9\u526f\u724c\u4e2d\u62ff\u51fa\u4e94\u5f20\u724c\u53ef\u4ee5\u5199\u6210\uff1a def draw(_deck, n=5): return _deck.sample(n) print(draw(deck)) # KD 10 # 2S 2 # 5C 5 # 6C 6 # QD 10 # dtype: int64 \u5047\u8bbe\u8981\u4ece\u6bcf\u4e2a\u82b1\u8272\u4e2d\u968f\u673a\u62bd\u53d6\u4e24\u5f20\u724c\u3002\u7531\u4e8e\u82b1\u8272\u662f\u724c\u540d\u7684\u6700\u540e\u4e24\u4e2a\u5b57\u7b26\uff0c\u53ef\u4ee5\u57fa\u4e8e\u8fd9\u70b9\u8fdb\u884c\u5206\u7ec4\uff0c\u5e76\u4f7f\u7528 apply \uff1a get_suit = lambda card: card[-1] # \u6700\u540e\u4e00\u4e2a\u5b57\u6bcd\u662f\u82b1\u8272 result = deck.groupby(get_suit).apply(draw, n=2) print(result) # C 10C 10 # 3C 3 # D KD 10 # AD 1 # H 5H 5 # 7H 7 # S 3S 3 # 5S 5 # dtype: int64 \u6216\u8005\u4e5f\u53ef\u4ee5\u5199\u6210\uff1a result = deck.groupby(get_suit, group_keys=False).apply(draw, n=2) print(result) # JC 10 # 8C 8 # QD 10 # 4D 4 # 10H 10 # 6H 6 # 7S 7 # KS 10 # dtype: int64 \u793a\u4f8b\uff1a\u5206\u7ec4\u52a0\u6743\u5e73\u5747\u548c\u76f8\u5173\u6027 \u00b6 \u5728 groupby \u7684\u62c6\u5206-\u5e94\u7528-\u8054\u5408\u7684\u8303\u5f0f\u4e0b\uff0cDataFrame\u7684\u5217\u95f4\u64cd\u4f5c\u6216\u4e24\u4e2aSeriese\u4e4b\u95f4\u7684\u64cd\u4f5c\uff0c\u4f8b\u5982\u5b9e\u73b0\u5206\u7ec4\u52a0\u6743\u5e73\u5747\u3002 \u4e0b\u9762\u4f8b\u5b50\uff0c\u4f7f\u7528\u4e00\u4e2a\u5305\u542b\u5206\u7ec4\u952e\u548c\u6743\u91cd\u503c\u7684\u6570\u636e\u96c6\uff1a dt = np.random.randn(8) wt = np.random.randn(8) df = pd.DataFrame( { 'category': ['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b'], 'data': dt, 'weight': wt } ) print(df) # category data weight # 0 a -0.250764 -0.085285 # 1 a 0.167155 -1.361254 # 2 a 0.399306 1.755542 # 3 a -0.514477 0.270124 # 4 b -0.005558 0.886514 # 5 b 0.607596 -1.384315 # 6 b -1.029627 -0.845340 # 7 b -0.294204 1.253965 \u901a\u8fc7 category \u8fdb\u884c\u5206\u7ec4\u52a0\u6743\u5e73\u5747\u5982\u4e0b\uff1a grouped = df.groupby('category') get_wavg = lambda g: np.average(g['data'], weights=g['weight']) result = grouped.apply(get_wavg) print(result) # category # a 0.614499 # b 3.863947 # dtype: float64 \u53e6\u4e00\u4e2a\u4f8b\u5b50\uff0c\u4e00\u4e2a\u4ece\u96c5\u864e\u8d22\u7ecf\u4e0a\u83b7\u5f97\u7684\u6570\u636e\u96c6\uff0c\u8be5\u6570\u636e\u96c6\u5305\u542b\u4e00\u4e9b\u6807\u666e500 \uff08SPX\u7b26\u53f7\uff09\u548c\u80a1\u7968\u7684\u6536\u76d8\u4ef7\uff1a close_px = pd.read_csv('../examples/stock_px_2.csv', parse_dates=True, index_col=0) print(close_px.info()) # # DatetimeIndex: 2214 entries, 2003-01-02 to 2011-10-14 # Data columns (total 4 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 AAPL 2214 non-null float64 # 1 MSFT 2214 non-null float64 # 2 XOM 2214 non-null float64 # 3 SPX 2214 non-null float64 # dtypes: float64(4) # memory usage: 86.5 KB # None print(close_px[-4:]) # AAPL MSFT XOM SPX # 2011-10-11 400.29 27.00 76.27 1195.54 # 2011-10-12 402.19 26.96 77.16 1207.25 # 2011-10-13 408.43 27.18 76.37 1203.66 # 2011-10-14 422.00 27.27 78.11 1224.58 \u76ee\u6807\u4efb\u52a1\uff1a\u8ba1\u7b97\u4e00\u4e2aDataFrame\uff0c\u5b83\u5305\u542b\u6807\u666e\u6307\u6570\uff08SPX\uff09\u6bcf\u65e5\u6536\u76ca\u7684\u5e74\u5ea6\u76f8\u5173\u6027\uff08\u901a\u8fc7\u767e\u5206\u6bd4\u53d8\u5316\u8ba1\u7b97\uff09\u3002 \u9996\u5148\u521b\u5efa\u4e00\u4e2a\u8ba1\u7b97\u6bcf\u5217\u4e0e\u2019SPX\u2019\u5217\u6210\u5bf9\u5173\u8054\u7684\u51fd\u6570\uff1a spx_corr = lambda x: x.corrwith(x['SPX']) \u4e4b\u540e\uff0c\u4f7f\u7528 pct_change \u8ba1\u7b97 close-px \u767e\u5206\u6bd4\u7684\u53d8\u5316\uff1a rets = close_px.pct_change().dropna() # Percentage change between the current and a prior element. print(rets) # AAPL MSFT XOM SPX # 2003-01-03 0.006757 0.001421 0.000684 -0.000484 # 2003-01-06 0.000000 0.017975 0.024624 0.022474 # ... ... ... ... ... # 2011-10-14 0.033225 0.003311 0.022784 0.017380 # [2213 rows x 4 columns] \u6700\u540e\uff0c\u6309\u5e74\u5bf9\u767e\u5206\u6bd4\u53d8\u5316\u8fdb\u884c\u5206\u7ec4\uff0c\u53ef\u4ee5\u4f7f\u7528\u5355\u884c\u51fd\u6570\u4ece\u6bcf\u4e2a\u884c\u6807\u7b7e\u4e2d\u63d0\u53d6\u6bcf\u4e2a datetime \u6807\u7b7e\u7684 year \u5c5e\u6027\uff1a get_year = lambda x: x.year by_year = rets.groupby(get_year) result = by_year.apply(spx_corr) print(result) # AAPL MSFT XOM SPX # 2003 0.541124 0.745174 0.661265 1.0 # 2004 0.374283 0.588531 0.557742 1.0 # 2005 0.467540 0.562374 0.631010 1.0 # 2006 0.428267 0.406126 0.518514 1.0 # 2007 0.508118 0.658770 0.786264 1.0 # 2008 0.681434 0.804626 0.828303 1.0 # 2009 0.707103 0.654902 0.797921 1.0 # 2010 0.710105 0.730118 0.839057 1.0 # 2011 0.691931 0.800996 0.859975 1.0 \u53ef\u4ee5\u8ba1\u7b97\u5185\u90e8\u5217\u76f8\u5173\u6027\u3002\u8fd9\u91cc\u8ba1\u7b97\u4e86\u82f9\u679c\u548c\u5fae\u8f6f\u7684\u5e74\u5ea6\u76f8\u5173\u6027\uff1a result = by_year.apply(lambda g: g['AAPL'].corr(g['MSFT'])) print(result) # 2003 0.480868 # 2004 0.259024 # 2005 0.300093 # 2006 0.161735 # 2007 0.417738 # 2008 0.611901 # 2009 0.432738 # 2010 0.571946 # 2011 0.581987 # dtype: float64 \u793a\u4f8b\uff1a\u9010\u7ec4\u7ebf\u6027\u56de\u5f52 \u00b6 \u5b9a\u4e49\u4ee5\u4e0b regress \uff08\u56de\u5f52\uff09\u51fd\u6570\uff08\u4f7f\u7528 statsmodels \u8ba1\u91cf\u7ecf\u6d4e\u5b66\u5e93\uff09\uff0c\u8be5\u51fd\u6570\u5bf9\u6bcf\u4e2a\u6570\u636e\u5757\u6267\u884c\u666e\u901a\u6700\u5c0f\u4e8c\u4e58\uff08OLS\uff09\u56de\u5f52\uff1a def regress(data, yvar, xvars): Y = data[yvar] X = data[xvars] X['intercept'] = 1. result = sm.OLS(Y, X).fit() return result.params \u73b0\u5728\u8981\u8ba1\u7b97AAPL\u5728SPX\u56de\u62a5\u4e0a\u7684\u5e74\u5ea6\u7ebf\u6027\u56de\u5f52\uff1a result = by_year.apply(regress, 'AAPL', ['SPX']) print(result) # SPX intercept # 2003 1.195406 0.000710 # 2004 1.363463 0.004201 # 2005 1.766415 0.003246 # 2006 1.645496 0.000080 # 2007 1.198761 0.003438 # 2008 0.968016 -0.001110 # 2009 0.879103 0.002954 # 2010 1.052608 0.001261 # 2011 0.806605 0.001514 \u6570\u636e\u900f\u89c6\u8868\u4e0e\u4ea4\u53c9\u8868 \u00b6 \u6570\u636e\u900f\u89c6\u8868 \u00b6 \u6570\u636e\u900f\u89c6\u8868\u662f\u7535\u5b50\u8868\u683c\u7a0b\u5e8f\u548c\u5176\u4ed6\u6570\u636e\u5206\u6790\u8f6f\u4ef6\u4e2d\u5e38\u89c1\u7684\u6570\u636e\u6c47\u603b\u5de5\u5177\u3002 \u5b83\u6839\u636e\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u805a\u5408\u4e00\u5f20\u8868\u7684\u6570\u636e\uff0c\u5c06\u6570\u636e\u5728\u77e9\u5f62\u683c\u5f0f\u4e2d\u6392\u5217\uff0c\u5176\u4e2d\u4e00\u4e9b\u5206\u7ec4\u952e\u662f\u6cbf\u7740\u884c\u7684\uff0c\u53e6\u4e00\u4e9b\u662f\u6cbf\u7740\u5217\u7684\u3002 Python\u4e2d\u7684pandas\u900f\u89c6\u8868\u662f\u901a\u8fc7\u8fd9\u91cc\u6240\u4ecb\u7ecd\u7684groupby\u5de5\u5177\u4ee5\u53ca\u4f7f\u7528\u5206\u5c42\u7d22\u5f15\u7684\u91cd\u5851\u64cd\u4f5c\u5b9e\u73b0\u7684\u3002 DataFrame\u62e5\u6709\u4e00\u4e2a pivot_table \u65b9\u6cd5\uff0c\u5e76\u4e14\u8fd8\u6709\u8fd8\u4e00\u4e2a\u9876\u5c42\u7684 pandas.pivot_table \u51fd\u6570\u3002 \u9664\u4e86\u4e3a groupby \u63d0\u4f9b\u4e00\u4e2a\u65b9\u4fbf\u63a5\u53e3\uff0c pivot_table \u8fd8\u53ef\u4ee5\u6dfb\u52a0\u90e8\u5206\u603b\u8ba1\uff0c\u4e5f\u79f0\u4f5c\u8fb9\u8ddd\u3002 import pandas as pd import numpy as np \u6839\u636e\u4e0b\u9762\u7684\u5c0f\u8d39\u6570\u636e\u96c6\uff0c\u8ba1\u7b97\u4e00\u5f20\u5728\u884c\u65b9\u5411\u4e0a\u6309 day \u548c smoker \u6392\u5217\u7684\u5206\u7ec4\u5e73\u5747\u503c\uff08\u9ed8\u8ba4\u7684 pivot_table \u805a\u5408\u7c7b\u578b\uff09\u7684\u8868\u3002 pivot_table \u9009\u9879\uff1a values: \u9700\u8981\u805a\u5408\u7684\u5217\u540d\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u805a\u5408\u6240\u6709\u6570\u503c\u578b\u7684\u5217\u3002 index: \u5728\u7ed3\u679c\u900f\u89c6\u8868\u7684\u884c\u4e0a\u8fdb\u884c\u5206\u7ec4\u7684\u5217\u540d\u6216\u8005\u5176\u4ed6\u5206\u7ec4\u952e\u3002 tips = pd.read_csv('../examples/tips.csv') tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) \u6837\u672c\u6570\u636e\u3002 print(tips.head(5)) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 \u8ba1\u7b97\u5728\u884c\u65b9\u5411\u4e0a\u6309 day \u548c smoker \u6392\u5217\u7684\u5206\u7ec4\u5e73\u5747\u503c\u3002\u4e5f\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528 groupby \u5b9e\u73b0\u3002 result = tips.pivot_table(index=['day', 'smoker']) print(result) # size tip tip_pct total_bill # day smoker # Fri No 2.250000 2.812500 0.179740 18.420000 # Yes 2.066667 2.714000 0.216293 16.813333 # Sat No 2.555556 3.102889 0.190412 19.661778 # Yes 2.476190 2.875476 0.179833 21.276667 # Sun No 2.929825 3.167895 0.193617 20.506667 # Yes 2.578947 3.516842 0.322021 24.120000 # Thur No 2.488889 2.673778 0.193424 17.113111 # Yes 2.352941 3.030000 0.198508 19.190588 \u5728 tip_pct \u548c size \u4e0a\u8fdb\u884c\u805a\u5408\uff0c\u5e76\u6839\u636e time \u5206\u7ec4\u3002\u5c06\u628a smoker \u653e\u5165\u8868\u7684\u5217\uff0c\u800c\u5c06 day \u653e\u5165\u8868\u7684\u884c\uff1a result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker' ) print(result) # size tip_pct # smoker No Yes No Yes # time day # Dinner Fri 2.000000 2.222222 0.162612 0.202545 # Sat 2.555556 2.476190 0.190412 0.179833 # Sun 2.929825 2.578947 0.193617 0.322021 # Thur 2.000000 NaN 0.190114 NaN # Lunch Fri 3.000000 1.833333 0.231125 0.236915 # Thur 2.500000 2.352941 0.193499 0.198508 \u901a\u8fc7\u4f20\u9012 margins=True \u6765\u6269\u5145\u8fd9\u4e2a\u8868\u6765\u5305\u542b\u90e8\u5206\u603b\u8ba1\u3002\u8fd9\u4f1a\u6dfb\u52a0 All \u884c\u548c\u5217\u6807\u7b7e\uff0c\u5176\u4e2d\u76f8\u5e94\u7684\u503c\u662f\u5355\u5c42\u4e2d\u6240\u6709\u6570\u636e\u7684\u5206\u7ec4\u7edf\u8ba1\u503c\u3002 \u8fd9\u91cc All \u7684\u503c\u662f\u5747\u503c\uff0c\u4e14\u8be5\u5747\u503c\u662f\u4e0d\u8003\u8651\u5438\u70df\u8005\u4e0e\u975e\u5438\u70df\u8005\uff08 All \u5217\uff09\u6216\u884c\u5206\u7ec4\u4e2d\u4efb\u4f55\u4e24\u7ea7\u7684\uff08 All \u884c\uff09\u3002 result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker', margins=True ) print(result) # size tip_pct # smoker No Yes All No Yes All # time day # Dinner Fri 2.000000 2.222222 2.166667 0.162612 0.202545 0.192562 # Sat 2.555556 2.476190 2.517241 0.190412 0.179833 0.185305 # Sun 2.929825 2.578947 2.842105 0.193617 0.322021 0.225718 # Thur 2.000000 NaN 2.000000 0.190114 NaN 0.190114 # Lunch Fri 3.000000 1.833333 2.000000 0.231125 0.236915 0.236088 # Thur 2.500000 2.352941 2.459016 0.193499 0.198508 0.194895 # All 2.668874 2.408602 2.569672 0.192237 0.218176 0.202123 \u8981\u4f7f\u7528\u4e0d\u540c\u7684\u805a\u5408\u51fd\u6570\u65f6\uff0c\u5c06\u51fd\u6570\u4f20\u9012\u7ed9 aggfunc \u3002\u4f8b\u5982\uff0c count \u6216\u8005 len \u5c06\u7ed9\u51fa\u4e00\u5f20\u5206\u7ec4\u5927\u5c0f\u7684\u4ea4\u53c9\u8868\uff08\u8ba1\u6570\u6216\u51fa\u73b0\u9891\u7387\uff09\uff1a result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker', aggfunc=len, margins=True ) print(result) # size tip_pct # smoker No Yes All No Yes All # time day # Dinner Fri 3.0 9.0 12 3.0 9.0 12 # Sat 45.0 42.0 87 45.0 42.0 87 # Sun 57.0 19.0 76 57.0 19.0 76 # Thur 1.0 NaN 1 1.0 NaN 1 # Lunch Fri 1.0 6.0 7 1.0 6.0 7 # Thur 44.0 17.0 61 44.0 17.0 61 # All 151.0 93.0 244 151.0 93.0 244 \u5bf9\u4e8e\u7a7a\u503c NA \uff0c\u4f20\u9012\u4e00\u4e2a fill_value \u3002 result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker', aggfunc='mean', fill_value=0, margins=True ) print(result) # size tip_pct # smoker No Yes All No Yes All # time day # Dinner Fri 2.000000 2.222222 2.166667 0.162612 0.202545 0.192562 # Sat 2.555556 2.476190 2.517241 0.190412 0.179833 0.185305 # Sun 2.929825 2.578947 2.842105 0.193617 0.322021 0.225718 # Thur 2.000000 0.000000 2.000000 0.190114 0.000000 0.190114 # Lunch Fri 3.000000 1.833333 2.000000 0.231125 0.236915 0.236088 # Thur 2.500000 2.352941 2.459016 0.193499 0.198508 0.194895 # All 2.668874 2.408602 2.569672 0.192237 0.218176 0.202123 \u4ea4\u53c9\u8868\uff1acrosstab \u00b6 \u4ea4\u53c9\u8868\uff08\u7b80\u5199\u4e3acrosstab\uff09\u662f\u6570\u636e\u900f\u89c6\u8868\u7684\u4e00\u4e2a\u7279\u6b8a\u60c5\u51b5\uff0c\u8ba1\u7b97\u7684\u662f\u5206\u7ec4\u4e2d\u7684\u9891\u7387\u3002 crosstab \u7684\u524d\u4e24\u4e2a\u53c2\u6570\u53ef\u662f\u6570\u7ec4\u3001Series\u6216\u6570\u7ec4\u7684\u5217\u8868\u3002 sample = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] nationality = ['USA', 'Japan', 'USA', 'Japan', 'Japan', 'Japan', 'USA', 'USA', 'Japan', 'USA'] handedness = ['Right-handed', 'Left-handed', 'Right-handed', 'Right-handed', 'Left-handed', 'Right-handed', 'Right-handed', 'Left-handed', 'Right-handed', 'Right-handed'] df = pd.DataFrame( { 'sample': sample, 'nationality': nationality, 'handedness': handedness } ) print(df) # sample nationality handedness # 0 1 USA Right-handed # 1 2 Japan Left-handed # 2 3 USA Right-handed # 3 4 Japan Right-handed # 4 5 Japan Left-handed # 5 6 Japan Right-handed # 6 7 USA Right-handed # 7 8 USA Left-handed # 8 9 Japan Right-handed # 9 10 USA Right-handed \u6309\u7167\u56fd\u7c4d\u548c\u60ef\u7528\u6027\u6765\u603b\u7ed3\u8fd9\u4e9b\u6570\u636e\uff0c\u53ef\u4ee5\u4f7f\u7528 pivot_table \u6765\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\uff0c\u4f46\u662f pandas.crosstable \u51fd\u6570\u66f4\u4e3a\u65b9\u4fbf\uff1a result = pd.crosstab(df.nationality, df.handedness, margins=True) print(result) # handedness Left-handed Right-handed All # nationality # Japan 2 3 5 # USA 1 4 5 # All 3 7 10 \u5728\u5c0f\u8d39\u6570\u636e\u4e2d\u53ef\u4ee5\u8fd9\u4e48\u505a\uff1a result = pd.crosstab(['tips.time', tips.day], tips.smoker, margins=True) print(result) # smoker No Yes All # row_0 day # tips.time Fri 4 15 19 # Sat 45 42 87 # Sun 57 19 76 # Thur 45 17 62 # All 151 93 244","title":"\u6570\u636e\u805a\u5408\u4e0e\u5206\u7ec4\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch07/#_1","text":"","title":"\u6570\u636e\u805a\u5408\u4e0e\u5206\u7ec4\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch07/#groupby","text":"import pandas as pd import numpy as np","title":"GroupBy\u673a\u5236"},{"location":"python/DataAnalysis/ch07/#_2","text":"\u5206\u7ec4\u64cd\u4f5c\u7b2c\u4e00\u6b65\uff0c\u6570\u636e\u5305\u542b\u5728pandas\u5bf9\u8c61\u4e2d\uff0c\u53ef\u4ee5\u662fSeries\u3001DataFrame\u6216\u5176\u4ed6\u6570\u636e\u7ed3\u6784\u3002\u4e4b\u540e\u6839\u636e\u63d0\u4f9b\u7684\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u5206\u79bb\u5230\u5404\u4e2a\u7ec4\u4e2d\u3002 \u5206\u7ec4\u952e\u53ef\u662f\u591a\u79cd\u5f62\u5f0f\u7684\uff0c\u5e76\u4e14\u952e\u4e0d\u4e00\u5b9a\u662f\u5b8c\u5168\u76f8\u540c\u7684\u7c7b\u578b(\u6ce8\u610f\u540e\u9762\u4ecb\u7ecd\u7684\u4e09\u4e2a\u65b9\u6cd5\u662f\u53ef\u4ee5\u4ea7\u751f\u7528\u4e8e\u5206\u9694\u5bf9\u8c61\u7684\u503c\u6570\u7ec4\u7684\u5feb\u6377\u65b9\u5f0f)\uff1a \u4e0e\u9700\u8981\u5206\u7ec4\u7684\u8f74\u5411\u957f\u5ea6\u4e00\u81f4\u7684\u503c\u5217\u8868\u6216\u503c\u6570\u7ec4\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cgroupby\u5728axis=0\u7684\u8f74\u5411\u4e0a\u5206\u7ec4\u3002 DataFrame\u7684\u5217\u540d\u7684\u503c\u3002 \u53ef\u4ee5\u5c06\u5206\u7ec4\u8f74\u5411\u4e0a\u7684\u503c\u548c\u5206\u7ec4\u540d\u79f0\u76f8\u5339\u914d\u7684\u5b57\u5178\u6216Series\u3002 \u53ef\u4ee5\u5728\u8f74\u7d22\u5f15\u6216\u7d22\u5f15\u4e2d\u7684\u5355\u4e2a\u6807\u7b7e\u4e0a\u8c03\u7528\u7684\u51fd\u6570\u3002 \u8bf7\u6ce8\u610f\uff0c\u5206\u7ec4\u952e\u4e2d\u7684\u4efb\u4f55\u7f3a\u5931\u503c\u5c06\u88ab\u6392\u9664\u5728\u7ed3\u679c\u4e4b\u5916\u3002 \u5206\u79bb\u64cd\u4f5c\u662f\u5728\u6570\u636e\u5bf9\u8c61\u7684\u7279\u5b9a\u8f74\u5411\u4e0a\u8fdb\u884c\u7684\u3002\u4f8b\u5982\uff0cDataFrame\u53ef\u4ee5\u5728\u5b83\u7684\u884c\u65b9\u5411\uff08axis=0\uff09\u6216\u5217\u65b9\u5411\uff08axis=1\uff09\u8fdb\u884c\u5206\u7ec4\u3002 \u5206\u7ec4\u64cd\u4f5c\u540e\uff0c\u4e00\u4e2a\u51fd\u6570\u5c31\u53ef\u4ee5\u5e94\u7528\u5230\u5404\u4e2a\u7ec4\u4e2d\uff0c\u4ea7\u751f\u65b0\u7684\u503c\u3002\u6700\u7ec8\uff0c\u6240\u6709\u51fd\u6570\u7684\u5e94\u7528\u7ed3\u679c\u4f1a\u8054\u5408\u4e3a\u4e00\u4e2a\u7ed3\u679c\u5bf9\u8c61\u3002 df = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a'], 'key2': ['one', 'two', 'one', 'two', 'one'], 'data1': [1, 3, 5, 7, 9], 'data2': [2, 4, 6, 8, 10] } ) \u6839\u636ekey1\u6807\u7b7e\u8ba1\u7b97data1\u5217\u7684\u5747\u503c\uff0c\u65b9\u6cd5\u4e00\uff0c\u8bbf\u95ee data1 \u5e76\u4f7f\u7528 key1 \u5217\uff08\u5b83\u662f\u4e00\u4e2aSeries\uff09\u8c03\u7528 groupby \u65b9\u6cd5\uff1a grouped = df['data1'].groupby(df['key1']) print(grouped) # grouped \u53d8\u91cf\u73b0\u5728\u662f\u4e00\u4e2a GroupBy \u5bf9\u8c61\uff0c\u5b83\u5b9e\u9645\u4e0a\u8fd8\u6ca1\u6709\u8fdb\u884c\u4efb\u4f55\u8ba1\u7b97\uff0c\u62e5\u6709\u4e00\u4e9b\u5173\u4e8e\u5206\u7ec4\u952edf['key1']\u7684\u4e00\u4e9b\u4e2d\u95f4\u6570\u636e\u7684\u4fe1\u606f\u3002 \u4e0b\u9762\u5bf9 grouped \u5bf9\u8c61\u505a\u4e00\u4e9b\u64cd\u4f5c\uff1a result = grouped.mean() # \u8ba1\u7b97\u5e73\u5747\u503c print(result) # key1 # a 4.333333 # b 6.000000 # Name: data1, dtype: float64 grouped_means = df['data1'].groupby([df['key1'], df['key2']]).mean() print(grouped_means) # key1 key2 # a one 5.0 # two 3.0 # b one 5.0 # two 7.0 # Name: data1, dtype: float64 \u4e0a\u9762\u4f8b\u5b50\u4f7f\u7528\u4e86\u4e24\u4e2a\u952e\u5bf9\u6570\u636e\u8fdb\u884c\u5206\u7ec4\uff0c\u5e76\u4e14\u7ed3\u679cSeries\u73b0\u5728\u62e5\u6709\u4e00\u4e2a\u5305\u542b\u552f\u4e00\u952e\u5bf9\u7684\u591a\u5c42\u7d22\u5f15\u3002 \u4e0b\u9762\u5bf9\u8ba1\u7b97\u7684\u5e73\u5747\u503c\uff08mean\uff09\u8fdb\u884c\u91cd\u5851\uff08unstack\uff09\u3002 print(grouped_means.unstack()) # key2 one two # key1 # a 5.0 3.0 # b 5.0 7.0 \u5206\u7ec4\u4fe1\u606f\u901a\u5e38\u5305\u542b\u5728\u540c\u4e00\u4e2aDataFrame\u4e2d\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u53ef\u4ee5\u4f20\u9012\u5217\u540d\uff08\u65e0\u8bba\u90a3\u4e9b\u5217\u540d\u662f\u5b57\u7b26\u4e32\u3001\u6570\u5b57\u6216\u5176\u4ed6Python\u5bf9\u8c61\uff09\u4f5c\u4e3a\u5206\u7ec4\u952e\uff1a \u4e0b\u9762\u4f8b\u5b50\u4e2d df.groupby('key1').mean() \u7684\u7ed3\u679c\u91cc\u5e76\u6ca1\u6709 key2 \u5217\u3002\u8fd9\u662f\u56e0\u4e3a df['key2'] \u5e76\u4e0d\u662f\u6570\u503c\u6570\u636e\uff0c\u5373 df['key2'] \u662f\u4e00\u4e2a\u5197\u4f59\u5217\uff0c\u56e0\u6b64\u88ab\u6392\u9664\u5728\u7ed3\u679c\u4e4b\u5916\u3002 result = df.groupby('key1').mean() print(result) # data1 data2 # key1 # a 4.333333 5.333333 # b 6.000000 7.000000 result = df.groupby(['key1', 'key2']).mean() print(result) # data1 data2 # key1 key2 # a one 5.0 6.0 # two 3.0 4.0 # b one 5.0 6.0 # two 7.0 8.0 result = df.groupby(['key1', 'key2']).size() print(result) # key1 key # a one 2 # two 1 # b one 1 # two 1 # dtype: int64","title":"\u5206\u7ec4\u673a\u5236"},{"location":"python/DataAnalysis/ch07/#_3","text":"GroupBy \u5bf9\u8c61\u652f\u6301\u8fed\u4ee3\uff0c\u4f1a\u751f\u6210\u4e00\u4e2a\u5305\u542b\u7ec4\u540d\u548c\u6570\u636e\u5757\u76842\u7ef4\u5143\u7ec4\u5e8f\u5217\u3002 df = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a'], 'key2': ['one', 'two', 'one', 'two', 'one'], 'data1': [1, 3, 5, 7, 9], 'data2': [2, 4, 6, 8, 10] } ) \u5355\u4e2a\u5206\u7ec4\u952e\u7684\u60c5\u51b5: for name, group in df.groupby('key1'): print(name) print(group) # a # key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10 # b # key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 \u591a\u4e2a\u5206\u7ec4\u952e\u7684\u60c5\u51b5: \u5143\u7ec4\u4e2d\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u662f\u952e\u503c\u7684\u5143\u7ec4\u3002 for (k1, k2), group in df.groupby(['key1', 'key2']): print((k1, k2)) print(group) # ('a', 'one') # key1 key2 data1 data2 # 0 a one 1 2 # 4 a one 9 10 # ('a', 'two') # key1 key2 data1 data2 # 1 a two 3 4 # ('b', 'one') # key1 key2 data1 data2 # 2 b one 5 6 # ('b', 'two') # key1 key2 data1 data2 # 3 b two 7 8 result = dict(list(df.groupby('key1'))) print(result) # df.groupby('key1')\u7684\u7ed3\u679c\u662f\u4e00\u4e2a\u5bf9\u8c61 # # list(df.groupby('key1'))\u7684\u7ed3\u679c\u662f\u5305\u542bFrameData\u7684\u7ed3\u6784\u7684\u5217\u8868list: # [ # ('a', key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10), # ('b', key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8) # ] # dict(list(df.groupby('key1')))\u7684\u7ed3\u679c\u662f\u5305\u542bFrameData\u7684\u7ed3\u6784\u7684\u5b57\u5178dict # { # 'a': key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10, # 'b': key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 # } print(result['b']) # key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c groupby \u5728 axis=0 \u7684\u8f74\u5411\u4e0a\u5206\u7ec4\uff0c\u4e5f\u53ef\u4ee5\u5728\u5176\u4ed6\u4efb\u610f\u8f74\u5411\u4e0a\u8fdb\u884c\u5206\u7ec4\u3002 print(df.dtypes) # key1 object # key2 object # data1 int64 # data2 int64 # dtype: object grouped = df.groupby(df.dtypes, axis=1) print(grouped) # print(list(grouped)) # [ # (dtype('int64'), data1 data2 # 0 1 2 # 1 3 4 # 2 5 6 # 3 7 8 # 4 9 10), # (dtype('O'), key1 key2 # 0 a one # 1 a two # 2 b one # 3 b two # 4 a one) # ] \u6253\u5370\u5404\u5206\u7ec4\u5982\u4e0b\uff1a for dtype, group in grouped: print(dtype) print(group) # int64 # data1 data2 # 0 1 2 # 1 3 4 # 2 5 6 # 3 7 8 # 4 9 10 # object # key1 key2 # 0 a one # 1 a two # 2 b one # 3 b two # 4 a one","title":"\u904d\u5386\u5404\u5206\u7ec4"},{"location":"python/DataAnalysis/ch07/#_4","text":"\u5bf9\u4e8e\u4eceDataFrame\u521b\u5efa\u7684 GroupBy \u5bf9\u8c61\uff0c\u7528\u5217\u540d\u79f0\u6216\u5217\u540d\u79f0\u6570\u7ec4\u8fdb\u884c\u7d22\u5f15\u65f6\uff0c\u4f1a\u4ea7\u751f\u7528\u4e8e\u805a\u5408\u7684\u5217\u5b50\u96c6\u7684\u6548\u679c\u3002 \u5982\u679c\u4f20\u9012\u7684\u662f\u5217\u8868\u6216\u6570\u7ec4\uff0c\u5219\u6b64\u7d22\u5f15\u64cd\u4f5c\u8fd4\u56de\u7684\u5bf9\u8c61\u662f\u5206\u7ec4\u7684DataFrame\uff1b\u5982\u679c\u53ea\u6709\u5355\u4e2a\u5217\u540d\u4f5c\u4e3a\u6807\u91cf\u4f20\u9012\uff0c\u5219\u4e3a\u5206\u7ec4\u7684Series\uff1b \u5bf9\u6bd4\u4e0b\u97624\u53e5\uff1a result = df.groupby('key1')['data1'] # \u5355\u4e2a\u5217\u540d print(result) # for key, data in result: print(key) print(data) result = df['data1'].groupby(df['key1']) # \u5355\u4e2a\u5217\u540d print(result) # for key, data in result: print(key) print(data) # a # 0 1 # 1 3 # 4 9 # Name: data1, dtype: int64 # b # 2 5 # 3 7 # Name: data1, dtype: int64 result = df.groupby('key1')[['data1']] # \u5217\u8868\u6216\u6570\u7ec4 print(result) # for key, data in result: print(key) print(data) # a # key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 4 a one 9 10 # b # key1 key2 data1 data2 # 2 b one 5 6 # 3 b two 7 8 result = df[['data1']].groupby(df['key1']) # \u5217\u8868\u6216\u6570\u7ec4 print(result) # for key, data in result: print(key) print(data) # a # data1 # 0 1 # 1 3 # 4 9 # b # data1 # 2 5 # 3 7","title":"\u9009\u62e9\u4e00\u5217\u6216\u6240\u6709\u5217\u7684\u5b50\u96c6"},{"location":"python/DataAnalysis/ch07/#series","text":"\u5206\u7ec4\u4fe1\u606f\u53ef\u80fd\u4f1a\u4ee5\u975e\u6570\u7ec4\u5f62\u5f0f\u5b58\u5728\u3002 \u751f\u6210\u4e00\u4e2a\u793a\u4f8bDataFrame\u3002 people = pd.DataFrame( [[1, 3, 5, 7, 9], [0, 2, 4, 6, 8], [0, 2, 4, 6, 8], [1, 3, 5, 7, 9], [1, 2, 3, 4, 5]], columns=['a', 'b', 'c', 'd', 'e'], index=['Joe', 'Steve', 'Wes', 'Jim', 'Travis'] ) \u6dfb\u52a0\u4e00\u4e9bNA\u503c\u3002 people.iloc[2:3, [1, 2]] = np.nan print(people) # a b c d e # Joe 1 3.0 5.0 7 9 # Steve 0 2.0 4.0 6 8 # Wes 0 NaN NaN 6 8 # Jim 1 3.0 5.0 7 9 # Travis 1 2.0 3.0 4 5 \u5047\u8bbe\u6709\u5982\u4e0b\u5404\u5217\u7684\u5206\u7ec4\u5bf9\u5e94\u5173\u7cfb\uff0c\u5e76\u4e14\u60f3\u628a\u5404\u5217\u6309\u7ec4\u7d2f\u52a0\u3002 mapping = { 'a': 'red', 'b': 'red', 'c': 'blue', 'd': 'blue', 'e': 'red', 'f': 'orange' # \u6ce8\u610f\uff1a\u5065f\u867d\u7136\u6ca1\u6709\u88ab\u7528\u5230\uff0c\u4f46\u4e0d\u5f71\u54cd\u5728\u8fd9\u91cc\u5b9a\u4e49\u3002 } \u628a mapping \u8fd9\u4e2a\u5b57\u5178\u4f20\u7ed9 groupby() \u3002 by_column = people.groupby(mapping, axis=1) print(by_column.sum()) # blue red # Joe 12.0 13.0 # Steve 10.0 10.0 # Wes 6.0 8.0 # Jim 12.0 13.0 # Travis 7.0 8.0 Series\u4e5f\u6709\u76f8\u540c\u7684\u529f\u80fd\uff0c\u53ef\u4ee5\u89c6\u4e3a\u56fa\u5b9a\u5927\u5c0f\u7684\u6620\u5c04\u3002 map_services = pd.Series(mapping) print(map_services) # a red # b red # c blue # d blue # e red # f orange # dtype: object result = people.groupby(map_services, axis=1).count() print(result) # blue red # Joe 2 3 # Steve 2 3 # Wes 1 2 # Jim 2 3 # Travis 2 3","title":"\u4f7f\u7528\u5b57\u5178\u548cSeries\u5206\u7ec4"},{"location":"python/DataAnalysis/ch07/#_5","text":"\u4e0e\u4f7f\u7528\u5b57\u5178\u6216Series\u5206\u7ec4\u76f8\u6bd4\uff0c\u4f7f\u7528Python\u51fd\u6570\u662f\u5b9a\u4e49\u5206\u7ec4\u5173\u7cfb\u7684\u4e00\u79cd\u66f4\u4e3a\u901a\u7528\u7684\u65b9\u5f0f\u3002 \u4f5c\u4e3a\u5206\u7ec4\u952e\u4f20\u9012\u7684\u51fd\u6570\u5c06\u4f1a\u6309\u7167\u6bcf\u4e2a\u7d22\u5f15\u503c\u8c03\u7528\u4e00\u6b21\uff0c\u540c\u65f6\u8fd4\u56de\u503c\u4f1a\u88ab\u7528\u4f5c\u5206\u7ec4\u540d\u79f0\u3002\u6ce8\u610f\uff1a\u51fd\u6570\u662f\u4f5c\u7528\u5728\u7d22\u5f15\u4e0a\u3002 result = people.groupby(len).sum() # \u4eba\u7684\u540d\u5b57\u662f\u7d22\u5f15\u503c\uff0c\u6839\u636e\u540d\u5b57\u7684\u957f\u5ea6\u6765\u8fdb\u884c\u5206\u7ec4 print(result) # a b c d e # 3 2 6.0 10.0 20 26 # 5 0 2.0 4.0 6 8 # 6 1 2.0 3.0 4 5 \u53ef\u4ee5\u5c06\u51fd\u6570\u4e0e\u6570\u7ec4\u3001\u5b57\u5178\u6216Series\u8fdb\u884c\u6df7\u5408\uff0c\u6240\u6709\u7684\u5bf9\u8c61\u90fd\u4f1a\u5728\u5185\u90e8\u8f6c\u6362\u4e3a\u6570\u7ec4\u3002 key_list = ['one', 'one', 'one', 'two', 'two'] result = people.groupby([len, key_list]).min() print(result) # a b c d e # 3 one 0 3.0 5.0 6 8 # two 1 3.0 5.0 7 9 # 5 one 0 2.0 4.0 6 8 # 6 two 1 2.0 3.0 4 5","title":"\u4f7f\u7528\u51fd\u6570\u5206\u7ec4"},{"location":"python/DataAnalysis/ch07/#_6","text":"\u6839\u636e\u5c42\u7ea7\u5206\u7ec4\u65f6\uff0c\u5c06\u5c42\u7ea7\u6570\u503c\u6216\u5c42\u7ea7\u540d\u79f0\u4f20\u9012\u7ed9 level \u5173\u952e\u5b57\u3002 columns = pd.MultiIndex.from_arrays( [['US', 'US', 'US', 'JP', 'JP'], [1, 3, 5, 1, 3]], names=['cty', 'tenor'] ) hier_df = pd.DataFrame( [[1, 3, 5, 7, 9], [0, 2, 4, 6, 8], [1, 3, 5, 7, 9], [1, 2, 3, 4, 5]], columns=columns ) print(hier_df) # cty US JP # tenor 1 3 5 1 3 # 0 1 3 5 7 9 # 1 0 2 4 6 8 # 2 1 3 5 7 9 # 3 1 2 3 4 5 result = hier_df.groupby(level='cty', axis=1).count() print(result) # cty JP US # 0 2 3 # 1 2 3 # 2 2 3 # 3 2 3","title":"\u6839\u636e\u7d22\u5f15\u5c42\u7ea7\u5206\u7ec4"},{"location":"python/DataAnalysis/ch07/#_7","text":"\u805a\u5408\u662f\u6307\u6240\u6709\u6839\u636e\u6570\u7ec4\u4ea7\u751f\u6807\u91cf\u503c\u7684\u6570\u636e\u8f6c\u6362\u8fc7\u7a0b\uff0c\u6bd4\u5982\uff1a mean \u3001 count \u3001 min \u548c sum \u7b49\u4e00\u4e9b\u805a\u5408\u64cd\u4f5c\u3002 import pandas as pd import numpy as np \u9884\u5907\u77e5\u8bc6\uff1a \u5206\u4f4d\u6570\uff08Quantile\uff09\uff0c\u4e5f\u79f0\u5206\u4f4d\u70b9\uff0c\u662f\u6307\u5c06\u4e00\u4e2a\u968f\u673a\u53d8\u91cf\u7684\u6982\u7387\u5206\u5e03\u8303\u56f4\u5206\u4e3a\u51e0\u4e2a\u7b49\u4efd\u7684\u6570\u503c\u70b9\uff0c\u5206\u6790\u5176\u6570\u636e\u53d8\u91cf\u7684\u8d8b\u52bf\u3002 \u5e38\u7528\u7684\u5206\u4f4d\u6570\u6709 \u4e2d\u4f4d\u6570\u3001\u56db\u5206\u4f4d\u6570\u3001\u767e\u5206\u4f4d\u6570\u7b49\u3002 \u4e2d\u4f4d\u6570\uff08Medians\uff09\u662f\u4e00\u4e2a\u7edf\u8ba1\u5b66\u7684\u4e13\u6709\u540d\u8bcd\uff0c\u4ee3\u8868\u4e00\u4e2a\u6837\u672c\u3001\u79cd\u7fa4\u6216\u6982\u7387\u5206\u5e03\u4e2d\u7684\u4e00\u4e2a\u6570\u503c\uff0c\u53ef\u4ee5\u5c06\u6570\u503c\u96c6\u5408\u5212\u5206\u4e3a\u76f8\u7b49\u7684\u4e24\u90e8\u5206\u3002 \u5229\u7528pandas\u5e93\u8ba1\u7b97 data = [6, 47, 49, 15, 42, 41, 7, 39, 43, 40, 36] \u7684\u5206\u4f4d\u6570\u3002 \u786e\u5b9a p \u5206\u4f4d\u6570\u4f4d\u7f6e\u7684\u4e24\u79cd\u65b9\u6cd5( n \u4e3a\u6570\u636e\u7684\u603b\u4e2a\u6570\uff0c p \u4e3a 0-1 \u4e4b\u95f4\u7684\u503c)\u3002\u5728python\u4e2d\u8ba1\u7b97\u5206\u4f4d\u6570\u4f4d\u7f6e\u7684\u65b9\u6848\u91c7\u7528 position=1+(n-1)*p \uff1a position = (n+1)*p position = 1 + (n-1)*p \u6848\u4f8b1 data = pd.Series(np.array([6, 47, 49, 15, 42, 41, 7, 39, 43, 40, 36])) print(\"\u6570\u636e\u683c\u5f0f\uff1a\") print(np.sort(data)) # \u5fc5\u987b\u8981\u6392\u5e8f print('Q1:', data.quantile(.25)) print('Q2:', data.quantile(.5)) print('Q3:', data.quantile(.75)) # \u6570\u636e\u683c\u5f0f\uff1a # [ 6 7 15 36 39 40 41 42 43 47 49] # Q1: 25.5 # Q2: 40.0 # Q3: 42.5 # \u624b\u7b97\u8ba1\u7b97\u7ed3\u679c\uff1a # Q1\u7684p\u5206\u4f4d\u6570(0.25)\u4f4d\u7f6eposition = 1+(11-1)*0.25 = 3.5(\u53d6\u7b2c3\u4f4d) (p=0.25) Q1=15+(36-15)*0.5=25.5 (\u7b2c3\u30014\u4f4d\u7684\u5dee\u4e58\u4ee5\u4f59\u65700.5) # Q2\u7684p\u5206\u4f4d\u6570(0.5)\u4f4d\u7f6eposition = 1+(11-1)*0.5 = 6 (p=0.5) Q2=40 # Q3\u7684p\u5206\u4f4d\u6570(0.75)\u4f4d\u7f6eposition = 1+(11-1)*0.75 = 9 (p=0.75) Q3=42+(43-42)*0.5=42.5 # IQR = Q3 - Q1 = 17 \u6848\u4f8b2 df = pd.DataFrame(np.array([[1, 1], [2, 10], [3, 100], [4, 100]]), columns=['a', 'b']) print(\"\u6570\u636e\u539f\u59cb\u683c\u5f0f\uff1a\") print(df) print(\"\u8ba1\u7b97p=0.1\u65f6\uff0ca\u5217\u548cb\u5217\u7684\u5206\u4f4d\u6570\") print(df.quantile(.1)) # \u6570\u636e\u539f\u59cb\u683c\u5f0f\uff1a # a b # 0 1 1 # 1 2 10 # 2 3 100 # 3 4 100 # \u8ba1\u7b97p=0.1\u65f6\uff0ca\u5217\u548cb\u5217\u7684\u5206\u4f4d\u6570 # a 1.3 # b 3.7 # Name: 0.1, dtype: float64 # \u624b\u7b97\u8ba1\u7b97\u7ed3\u679c\uff1a # \u8ba1\u7b97a\u5217 # position=1+(4-1)*0.1=1.3 (\u53d6\u7b2c1\u4f4d) # Q1=1+(2-1)*0.3=1.3 (\u7b2c1\u30012\u4f4d\u7684\u5dee\u4e58\u4ee5\u4f59\u65700.3) # \u8ba1\u7b97b\u5217 # position=1+(4-1)*0.1=1.3 (\u53d6\u7b2c1\u4f4d) # Q1=1+(10-1)*0.3=3.7 (\u7b2c1\u30012\u4f4d\u7684\u5dee\u4e58\u4ee5\u4f59\u65700.3) \u4f18\u5316\u7684 groupby \u65b9\u6cd5\uff1a count: \u5206\u7ec4\u4e2d\u975eNA\u503c\u7684\u6570\u91cf sum: \u975eNA\u503c\u7684\u7d2f\u52a0\u548c mean: \u975eNA\u503c\u7684\u5e73\u5747\u503c median: \u975eNA\u503c\u7684\u7b97\u672f\u4e2d\u4f4d\u6570 std, var: \u65e0\u504f\u7684(n-1\u5206\u6bcd)\u6807\u51c6\u5dee\u548c\u65b9\u5dee min, max: \u975eNA\u503c\u7684\u6700\u5c0f\u503c\u3001\u6700\u5927\u503c prod: \u975eNA\u503c\u7684\u4e58\u79ef first, last: \u975eNA\u503c\u7684\u7b2c\u4e00\u4e2a\u3001\u6700\u540e\u4e00\u4e2a\u503c df = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a'], 'key2': ['one', 'two', 'one', 'two', 'one'], 'data1': [1, 3, 5, 7, 9], 'data2': [2, 4, 6, 8, 10] } ) print(df) # key1 key2 data1 data2 # 0 a one 1 2 # 1 a two 3 4 # 2 b one 5 6 # 3 b two 7 8 # 4 a one 9 10 grouped = df.groupby('key1') result = grouped['data1'] for i in result: print(i) # ('a', 0 1 # 1 3 # 4 9 # Name: data1, dtype: int64) # ('b', 2 5 # 3 7 # Name: data1, dtype: int64) result = grouped['data1'].quantile(0.9) # quantile\u5206\u4f4d\u6570 print(result) # key1 # a 7.8 # b 6.8 # Name: data1, dtype: float64 # \u624b\u7b97\u8ba1\u7b97\u7ed3\u679c\uff1a # \u8ba1\u7b97a\u5217 # position=1+(3-1)*0.9=2.8 # Q1=3+(9-3)*0.8=7.8 # \u8ba1\u7b97b\u5217 # position=1+(2-1)*0.9=1.9 # Q1=5+(7-5)*0.9=6.8 \u4f7f\u7528\u81ea\u884c\u5236\u5b9a\u7684\u805a\u5408\uff0c\u5e76\u518d\u8c03\u7528\u5df2\u7ecf\u5728\u5206\u7ec4\u5bf9\u8c61\u4e0a\u5b9a\u4e49\u597d\u7684\u65b9\u6cd5\u3002 def peak_to_peak(arr): return arr.max() - arr.min() result = grouped.agg(peak_to_peak) print(result) # data1 data2 # key1 # a 8 8 # b 2 2 result = grouped.describe() print(result) # data1 ... data2 # count mean std min 25% ... min 25% 50% 75% max # key1 ... # a 3.0 4.333333 4.163332 1.0 2.0 ... 2.0 3.0 4.0 7.0 10.0 # b 2.0 6.000000 1.414214 5.0 5.5 ... 6.0 6.5 7.0 7.5 8.0","title":"\u6570\u636e\u805a\u5408"},{"location":"python/DataAnalysis/ch07/#_8","text":"tips = pd.read_csv('../examples/tips.csv') tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) print(tips.head(5)) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 \u6839\u636e\u5404\u5217\u540c\u65f6\u4f7f\u7528\u591a\u4e2a\u51fd\u6570\u8fdb\u884c\u805a\u5408 grouped = tips.groupby(['day', 'smoker']) # for i in grouped: # print(i) # (('Fri', 'No'), total_bill tip smoker day time size tip_pct # 91 22.49 3.50 No Fri Dinner 2 0.184308 # ...... # 223 15.98 3.00 No Fri Lunch 3 0.231125) # (('Fri', 'Yes'), total_bill tip smoker day time size tip_pct # 90 28.97 3.00 Yes Fri Dinner 2 0.115518 # ...... # 226 10.09 2.00 Yes Fri Lunch 2 0.247219) # ...... grouped_pct = grouped['tip_pct'] for i in grouped_pct: print(i) # (('Fri', 'No'), 91 0.184308 # 94 0.166667 # ...... # Name: tip_pct, dtype: float64) # (('Fri', 'Yes'), 90 0.115518 # 92 0.210526 # ...... # Name: tip_pct, dtype: float64) # ...... \u5c06\u51fd\u6570\u540d\u4ee5\u5b57\u7b26\u4e32\u5f62\u5f0f\u4f20\u9012\u3002 result = grouped_pct.agg('mean') print(result) # day smoker # Fri No 0.179740 # Yes 0.216293 # Sat No 0.190412 # Yes 0.179833 # Sun No 0.193617 # Yes 0.322021 # Thur No 0.193424 # Yes 0.198508 # Name: tip_pct, dtype: float64 \u5982\u679c\u4f20\u9012\u7684\u662f\u51fd\u6570\u6216\u8005\u51fd\u6570\u540d\u7684\u5217\u8868\uff0c\u4f1a\u5f97\u5230\u4e00\u4e2a\u5217\u540d\u662f\u8fd9\u4e9b\u51fd\u6570\u540d\u7684DataFrame\u3002 \u4e0b\u9762\u4f20\u9012\u4e86\u805a\u5408\u51fd\u6570\u7684\u5217\u8868\u7ed9agg\u65b9\u6cd5\uff0c\u8fd9\u4e9b\u51fd\u6570\u4f1a\u5404\u81ea\u8fd0\u7528\u4e8e\u6570\u636e\u5206\u7ec4\u3002 result = grouped_pct.agg(['mean', 'std', peak_to_peak]) print(result) # mean std peak_to_peak # day smoker # Fri No 0.179740 0.039458 0.094263 # Yes 0.216293 0.077530 0.242219 # Sat No 0.190412 0.058626 0.352192 # Yes 0.179833 0.089496 0.446137 # Sun No 0.193617 0.060302 0.274897 # Yes 0.322021 0.538061 2.382107 # Thur No 0.193424 0.056065 0.284273 # Yes 0.198508 0.057170 0.219047 \u5982\u679c\u4f20\u9012\u7684\u662f (name, function) \u5143\u7ec4\u7684\u5217\u8868\uff0c\u6bcf\u4e2a\u5143\u7ec4\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5c06\u4f5c\u4e3aDataFrame\u7684\u5217\u540d\uff08\u53ef\u4ee5\u8ba4\u4e3a\u4e8c\u5143\u5143\u7ec4\u7684\u5217\u8868\u662f\u4e00\u79cd\u6709\u5e8f\u7684\u5bf9\u5e94\u5173\u7cfb\uff09\uff1a result = grouped_pct.agg([('foo', 'mean'), ('bar', np.std)]) # foo\u662fmean\u503c\u7684\u5217\u540d print(result) # foo bar # day smoker # Fri No 0.179740 0.039458 # Yes 0.216293 0.077530 # Sat No 0.190412 0.058626 # Yes 0.179833 0.089496 # Sun No 0.193617 0.060302 # Yes 0.322021 0.538061 # Thur No 0.193424 0.056065 # Yes 0.198508 0.057170 \u53ef\u4ee5\u6307\u5b9a\u5e94\u7528\u5230\u6240\u6709\u5217\u4e0a\u7684\u51fd\u6570\u5217\u8868\u6216\u6bcf\u4e00\u5217\u4e0a\u8981\u5e94\u7528\u7684\u4e0d\u540c\u51fd\u6570\u3002 \u4e0b\u9762\u4ea7\u751f\u7684DataFrame\u62e5\u6709\u5206\u5c42\u5217\uff0c\u4e0e\u5206\u522b\u805a\u5408\u6bcf\u4e00\u5217\uff0c\u518d\u4ee5\u5217\u540d\u4f5c\u4e3a keys \u53c2\u6570\u4f7f\u7528 concat \u5c06\u7ed3\u679c\u62fc\u63a5\u5728\u4e00\u8d77\u7684\u7ed3\u679c\u76f8\u540c\u3002 functions = ['count', 'mean', 'max'] result = grouped[['tip_pct', 'total_bill']].agg(functions) print(result) # tip_pct total_bill # count mean max count mean max # day smoker # Fri No 4 0.179740 0.231125 4 18.420000 22.75 # Yes 15 0.216293 0.357737 15 16.813333 40.17 # Sat No 45 0.190412 0.412409 45 19.661778 48.33 # Yes 42 0.179833 0.483092 42 21.276667 50.81 # Sun No 57 0.193617 0.338101 57 20.506667 48.17 # Yes 19 0.322021 2.452381 19 24.120000 45.35 # Thur No 45 0.193424 0.362976 45 17.113111 41.19 # Yes 17 0.198508 0.317965 17 19.190588 43.11 # \u628a['tip_pct', 'total_bill']\u6539\u6210[['tip_pct', 'total_bill']]\uff0c\u5c31\u53ef\u4ee5\u907f\u514d\u62a5\u9519 # FutureWarning: Indexing with multiple keys (implicitly converted to a tuple of keys) will be deprecated, use a list instead. # result = grouped['tip_pct', 'total_bill'].agg(functions) print(result['tip_pct']) # count mean max # day smoker # Fri No 4 0.179740 0.231125 # Yes 15 0.216293 0.357737 # Sat No 45 0.190412 0.412409 # Yes 42 0.179833 0.483092 # Sun No 57 0.193617 0.338101 # Yes 19 0.322021 2.452381 # Thur No 45 0.193424 0.362976 # Yes 17 0.198508 0.317965 \u4e5f\u540c\u6837\u53ef\u4ee5\u4f20\u9012\u5177\u6709\u81ea\u5b9a\u4e49\u540d\u79f0\u7684\u5143\u7ec4\u5217\u8868\uff1a ftuples = [('Durchschnitt', 'mean'), ('Abweichung', np.var)] result = grouped[['tip_pct', 'total_bill']].agg(ftuples) print(result) # tip_pct total_bill # Durchschnitt Abweichung Durchschnitt Abweichung # day smoker # Fri No 0.179740 0.001557 18.420000 25.596333 # Yes 0.216293 0.006011 16.813333 82.562438 # Sat No 0.190412 0.003437 19.661778 79.908965 # Yes 0.179833 0.008010 21.276667 101.387535 # Sun No 0.193617 0.003636 20.506667 66.099980 # Yes 0.322021 0.289509 24.120000 109.046044 # Thur No 0.193424 0.003143 17.113111 59.625081 # Yes 0.198508 0.003268 19.190588 69.808518 \u8981\u5c06\u4e0d\u540c\u7684\u51fd\u6570\u5e94\u7528\u5230\u4e00\u4e2a\u6216\u591a\u4e2a\u5217\u4e0a\uff0c\u9700\u8981\u5c06\u542b\u6709\u5217\u540d\u4e0e\u51fd\u6570\u5bf9\u5e94\u5173\u7cfb\u7684\u5b57\u5178\u4f20\u9012\u7ed9 agg \uff1a result = grouped.agg({'tip': np.max, 'size': 'sum'}) print(result) # tip size # day smoker # Fri No 3.50 9 # Yes 4.73 31 # Sat No 9.00 115 # Yes 10.00 104 # Sun No 6.00 167 # Yes 6.50 49 # Thur No 6.70 112 # Yes 5.00 40 result = grouped.agg({'tip_pct': ['min', 'max', 'mean', 'std']}) print(result) # tip_pct # min max mean std # day smoker # Fri No 0.136861 0.231125 0.179740 0.039458 # Yes 0.115518 0.357737 0.216293 0.077530 # Sat No 0.060217 0.412409 0.190412 0.058626 # Yes 0.036955 0.483092 0.179833 0.089496 # Sun No 0.063204 0.338101 0.193617 0.060302 # Yes 0.070274 2.452381 0.322021 0.538061 # Thur No 0.078704 0.362976 0.193424 0.056065 # Yes 0.098918 0.317965 0.198508 0.057170 \u53ea\u6709\u591a\u4e2a\u51fd\u6570\u5e94\u7528\u4e8e\u81f3\u5c11\u4e00\u4e2a\u5217\u65f6\uff0cDataFrame\u624d\u5177\u6709\u5206\u5c42\u5217\u3002","title":"\u9010\u5217\u53ca\u591a\u51fd\u6570\u5e94\u7528"},{"location":"python/DataAnalysis/ch07/#_9","text":"\u5728\u524d\u9762\u6240\u6709\u7684\u4f8b\u5b50\u4e2d\uff0c\u805a\u5408\u6570\u636e\u8fd4\u56de\u65f6\u90fd\u662f\u5e26\u6709\u7d22\u5f15\u7684\uff0c\u6709\u65f6\u7d22\u5f15\u662f\u5206\u5c42\u7684\uff0c\u7531\u552f\u4e00\u7684\u5206\u7ec4\u952e\u8054\u5408\u5f62\u6210\u3002 \u56e0\u4e3a\u4e0d\u662f\u6240\u6709\u7684\u60c5\u51b5\u4e0b\u90fd\u9700\u8981\u7d22\u5f15\uff0c\u6240\u4ee5\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\u53ef\u4ee5\u901a\u8fc7\u5411groupby\u4f20\u9012as_index=False\u6765\u7981\u7528\u5206\u7ec4\u952e\u4f5c\u4e3a\u7d22\u5f15\u7684\u884c\u4e3a\uff1a result = tips.groupby(['day', 'smoker'], as_index=False).mean() print(result) # day smoker total_bill tip size tip_pct # 0 Fri No 18.420000 2.812500 2.250000 0.179740 # 1 Fri Yes 16.813333 2.714000 2.066667 0.216293 # 2 Sat No 19.661778 3.102889 2.555556 0.190412 # 3 Sat Yes 21.276667 2.875476 2.476190 0.179833 # 4 Sun No 20.506667 3.167895 2.929825 0.193617 # 5 Sun Yes 24.120000 3.516842 2.578947 0.322021 # 6 Thur No 17.113111 2.673778 2.488889 0.193424 # 7 Thur Yes 19.190588 3.030000 2.352941 0.198508 \u901a\u8fc7\u5728\u7ed3\u679c\u4e0a\u8c03\u7528reset_index\u4e5f\u53ef\u4ee5\u83b7\u5f97\u540c\u6837\u7684\u7ed3\u679c\u3002\u4f7f\u7528as_index=False\u53ef\u4ee5\u907f\u514d\u4e00\u4e9b\u4e0d\u5fc5\u8981\u7684\u8ba1\u7b97\u3002 result = tips.groupby(['day', 'smoker']).mean() print(result.reset_index()) # day smoker total_bill tip size tip_pct # 0 Fri No 18.420000 2.812500 2.250000 0.179740 # 1 Fri Yes 16.813333 2.714000 2.066667 0.216293 # 2 Sat No 19.661778 3.102889 2.555556 0.190412 # 3 Sat Yes 21.276667 2.875476 2.476190 0.179833 # 4 Sun No 20.506667 3.167895 2.929825 0.193617 # 5 Sun Yes 24.120000 3.516842 2.578947 0.322021 # 6 Thur No 17.113111 2.673778 2.488889 0.193424 # 7 Thur Yes 19.190588 3.030000 2.352941 0.198508 print(result) # total_bill tip size tip_pct # day smoker # Fri No 18.420000 2.812500 2.250000 0.179740 # Yes 16.813333 2.714000 2.066667 0.216293 # Sat No 19.661778 3.102889 2.555556 0.190412 # Yes 21.276667 2.875476 2.476190 0.179833 # Sun No 20.506667 3.167895 2.929825 0.193617 # Yes 24.120000 3.516842 2.578947 0.322021 # Thur No 17.113111 2.673778 2.488889 0.193424 # Yes 19.190588 3.030000 2.352941 0.198508","title":"\u8fd4\u56de\u4e0d\u542b\u884c\u7d22\u5f15\u7684\u805a\u5408\u6570\u636e"},{"location":"python/DataAnalysis/ch07/#-","text":"import pandas as pd import numpy as np import statsmodels.api as sm GroupBy \u65b9\u6cd5\u6700\u5e38\u89c1\u7684\u76ee\u7684\u662f apply \uff08\u5e94\u7528\uff09\u3002 apply \u5c06\u5bf9\u8c61\u62c6\u5206\u6210\u591a\u5757\uff0c\u7136\u540e\u5728\u6bcf\u4e00\u5757\u4e0a\u8c03\u7528\u4f20\u9012\u7684\u51fd\u6570\uff0c\u4e4b\u540e\u5c1d\u8bd5\u5c06\u6bcf\u4e00\u5757\u62fc\u63a5\u5230\u4e00\u8d77\u3002 \u6839\u636e\u4e0b\u9762\u7684\u5c0f\u8d39\u6570\u636e\u96c6\uff0c\u6309\u7ec4\u9009\u51fa\u5c0f\u8d39\u767e\u5206\u6bd4\uff08tip-pct\uff09\u6700\u9ad8\u7684\u4e94\u7ec4\u3002 tips = pd.read_csv('../examples/tips.csv') tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) \u6837\u672c\u6570\u636e print(tips.head(5)) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 \u9996\u5148\uff0c\u5199\u4e00\u4e2a\u53ef\u4ee5\u5728\u7279\u5b9a\u5217\u4e2d\u9009\u51fa\u6700\u5927\u503c\u6240\u5728\u884c\u7684\u51fd\u6570\uff1a \u6dfb\u52a0\u4e86\u5347\u5e8f\uff0c\u7ed3\u679c\u8f93\u51fa\u6700\u540e5\u884c\uff08\u6700\u540e\u76845\u884c\u4e5f\u662f\u6700\u5927\u76845\u4e2a tip_tcp \u8bb0\u5f55\uff09\u3002 def top(df, n=5, column='tip_pct'): return df.sort_values(by=column, ascending=True)[-n:] result = top(tips, n=6) print(result) # \u7b49\u4ef7\u65b9\u5f0f\uff1a # result = tips.sort_values('tip_pct')[-6:] # print(result) # total_bill tip smoker day time size tip_pct # 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 \u5982\u679c\u6309\u7167 smoker \u8fdb\u884c\u5206\u7ec4\uff0c\u4e4b\u540e\u8c03\u7528 apply \uff0c\u4f1a\u5f97\u5230\u4ee5\u4e0b\u7ed3\u679c\uff1a top \u51fd\u6570\u5728DataFrame\u7684\u6bcf\u4e00\u884c\u5206\u7ec4\u4e0a\u88ab\u8c03\u7528\uff0c\u4e4b\u540e\u4f7f\u7528 pandas.concat \u5c06\u51fd\u6570\u7ed3\u679c\u7c98\u8d34\u5728\u4e00\u8d77\uff0c\u5e76\u4f7f\u7528\u5206\u7ec4\u540d\u4f5c\u4e3a\u5404\u7ec4\u7684\u6807\u7b7e\u3002 \u56e0\u6b64\u7ed3\u679c\u5305\u542b\u4e00\u4e2a\u5206\u5c42\u7d22\u5f15\uff0c\u8be5\u5206\u5c42\u7d22\u5f15\u7684\u5185\u90e8\u5c42\u7ea7\u5305\u542b\u539fDataFrame\u7684\u7d22\u5f15\u503c\u3002 result = tips.groupby('smoker').apply(top) print(result) # total_bill tip smoker day time size tip_pct # smoker # No 88 24.71 5.85 No Thur Lunch 2 0.310180 # 185 20.69 5.00 No Sun Dinner 5 0.318674 # 51 10.29 2.60 No Sun Dinner 2 0.338101 # 149 7.51 2.00 No Thur Lunch 2 0.362976 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # Yes 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 \u5982\u679c\u9664\u4e86\u5411 apply \u4f20\u9012\u51fd\u6570\uff0c\u8fd8\u4f20\u9012\u5176\u4ed6\u53c2\u6570\u6216\u5173\u952e\u5b57\u7684\u8bdd\uff0c\u4f60\u53ef\u4ee5\u628a\u8fd9\u4e9b\u653e\u5728\u51fd\u6570\u540e\u8fdb\u884c\u4f20\u9012\u3002 result = tips.groupby('smoker').apply(top, n=1, column='total_bill') print(result) # \u8fd92\u884c\u90fd\u662fsmoker\u662fyes\u548cno\u65f6\u6700\u5927total_bill\u503c\u6240\u5728\u884c\u3002 # total_bill tip smoker day time size tip_pct # smoker # No 212 48.33 9.0 No Sat Dinner 4 0.228833 # Yes 170 50.81 10.0 Yes Sat Dinner 3 0.245038 \u5728 GroupBy \u5bf9\u8c61\u4e0a\u8c03\u7528 describe \u65b9\u6cd5\u3002 result = tips.groupby('smoker')['tip_pct'].describe() print(result) # count mean std ... 50% 75% max # smoker ... # No 151.0 0.192237 0.057665 ... 0.184308 0.227015 0.412409 # Yes 93.0 0.218176 0.254295 ... 0.181818 0.242326 2.452381 # [2 rows x 8 columns] print(result.unstack('smoker')) # \u7c7b\u4f3c\u4e8e\u8f6c\u7f6e # smoker # count No 151.000000 # Yes 93.000000 # mean No 0.192237 # Yes 0.218176 # std No 0.057665 # Yes 0.254295 # min No 0.060217 # Yes 0.036955 # 25% No 0.158622 # Yes 0.119534 # 50% No 0.184308 # Yes 0.181818 # 75% No 0.227015 # Yes 0.242326 # max No 0.412409 # Yes 2.452381 # dtype: float64 \u5728 GroupBy \u5bf9\u8c61\u7684\u5185\u90e8\uff0c\u5f53\u8c03\u7528\u50cf describe \u8fd9\u6837\u7684\u65b9\u6cd5\u65f6\uff0c\u5b9e\u9645\u4e0a\u662f\u4ee5\u4e0b\u4ee3\u7801\u7684\u7b80\u5199\uff1a grouped = tips.groupby(['smoker']) f = lambda x: x.describe() result = grouped.apply(f) print(result) # total_bill tip size tip_pct # smoker # No count 151.000000 151.000000 151.000000 151.000000 # mean 19.188278 2.991854 2.668874 0.192237 # std 8.255582 1.377190 1.017984 0.057665 # min 7.250000 1.000000 1.000000 0.060217 # 25% 13.325000 2.000000 2.000000 0.158622 # 50% 17.590000 2.740000 2.000000 0.184308 # 75% 22.755000 3.505000 3.000000 0.227015 # max 48.330000 9.000000 6.000000 0.412409 # Yes count 93.000000 93.000000 93.000000 93.000000 # mean 20.756344 3.008710 2.408602 0.218176 # std 9.832154 1.401468 0.810751 0.254295 # min 3.070000 1.000000 1.000000 0.036955 # 25% 13.420000 2.000000 2.000000 0.119534 # 50% 17.920000 3.000000 2.000000 0.181818 # 75% 26.860000 3.680000 3.000000 0.242326 # max 50.810000 10.000000 5.000000 2.452381","title":"\u5e94\u7528\uff1a\u901a\u7528\u62c6\u5206-\u5e94\u7528-\u8054\u5408"},{"location":"python/DataAnalysis/ch07/#_10","text":"\u5728\u524d\u9762\u7684\u4f8b\u5b50\u4e2d\u6240\u5f97\u5230\u7684\u5bf9\u8c61\uff0c\u90fd\u5177\u6709\u5206\u7ec4\u952e\u6240\u5f62\u6210\u7684\u5206\u5c42\u7d22\u5f15\u4ee5\u53ca\u6bcf\u4e2a\u539f\u59cb\u5bf9\u8c61\u7684\u7d22\u5f15\u3002 \u4e5f\u53ef\u4ee5\u901a\u8fc7\u5411 groupby \u4f20\u9012 group_keys=False \u6765\u7981\u7528\u8fd9\u4e2a\u529f\u80fd\u3002 result = tips.groupby('smoker', group_keys=True).apply(top) print(result) # total_bill tip smoker day time size tip_pct # smoker # No 88 24.71 5.85 No Thur Lunch 2 0.310180 # 185 20.69 5.00 No Sun Dinner 5 0.318674 # 51 10.29 2.60 No Sun Dinner 2 0.338101 # 149 7.51 2.00 No Thur Lunch 2 0.362976 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # Yes 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381 result = tips.groupby('smoker', group_keys=False).apply(top) print(result) # total_bill tip smoker day time size tip_pct # 88 24.71 5.85 No Thur Lunch 2 0.310180 # 185 20.69 5.00 No Sun Dinner 5 0.318674 # 51 10.29 2.60 No Sun Dinner 2 0.338101 # 149 7.51 2.00 No Thur Lunch 2 0.362976 # 232 11.61 3.39 No Sat Dinner 2 0.412409 # 109 14.31 4.00 Yes Sat Dinner 2 0.387973 # 183 23.17 6.50 Yes Sun Dinner 4 0.389922 # 67 3.07 1.00 Yes Sat Dinner 1 0.483092 # 178 9.60 4.00 Yes Sun Dinner 2 0.714286 # 172 7.25 5.15 Yes Sun Dinner 2 2.452381","title":"\u538b\u7f29\u5206\u7ec4\u952e"},{"location":"python/DataAnalysis/ch07/#_11","text":"\u7b2c8\u7ae0\u4e2d\uff0cpandas\u6709\u4e00\u4e9b\u5de5\u5177\uff0c\u5c24\u5176\u662f cut \u548c qcut \uff0c\u7528\u4e8e\u5c06\u6570\u636e\u6309\u7167\u4f60\u9009\u62e9\u7684\u7bb1\u4f4d\u6216\u6837\u672c\u5206\u4f4d\u6570\u8fdb\u884c\u5206\u6876\u3002 \u4e0e groupby \u65b9\u6cd5\u4e00\u8d77\u4f7f\u7528\u8fd9\u4e9b\u51fd\u6570\u53ef\u4ee5\u5bf9\u6570\u636e\u96c6\u66f4\u65b9\u4fbf\u5730\u8fdb\u884c\u5206\u6876\u6216\u5206\u4f4d\u5206\u6790\u3002 \u590d\u4e60\uff1a\u673a\u68b0\u5b66\u4e60\u4e2d\u7684\u5206\u7bb1\u5904\u7406\u3002 \u5728\u673a\u68b0\u5b66\u4e60\u4e2d\u7ecf\u5e38\u4f1a\u5bf9\u6570\u636e\u8fdb\u884c\u5206\u7bb1\u5904\u7406\u7684\u64cd\u4f5c\uff0c \u4e5f\u5c31\u662f\u628a\u4e00\u6bb5\u8fde\u7eed\u7684\u503c\u5207\u5206\u6210\u82e5\u5e72\u6bb5\uff0c\u6bcf\u4e00\u6bb5\u7684\u503c\u770b\u6210\u4e00\u4e2a\u5206\u7c7b\u3002\u8fd9\u4e2a\u628a\u8fde\u7eed\u503c\u8f6c\u6362\u6210\u79bb\u6563\u503c\u7684\u8fc7\u7a0b\uff0c\u6211\u4eec\u53eb\u505a\u5206\u7bb1\u5904\u7406\u3002 \u6bd4\u5982\uff0c\u628a\u5e74\u9f84\u630915\u5c81\u5212\u5206\u6210\u4e00\u7ec4\uff0c0-15\u5c81\u53eb\u505a\u5c11\u5e74\uff0c16-30\u5c81\u53eb\u505a\u9752\u5e74\uff0c31-45\u5c81\u53eb\u505a\u58ee\u5e74\u3002\u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e2d\uff0c\u6211\u4eec\u628a\u8fde\u7eed\u7684\u5e74\u9f84\u5206\u6210\u4e86\u4e09\u4e2a\u7c7b\u522b\uff0c\u201c\u5c11\u5e74\u201d\uff0c\u201c\u9752\u5e74\u201d\u548c\u201c\u58ee\u5e74\u201d\u5c31\u662f\u5404\u4e2a\u7c7b\u522b\u7684\u540d\u79f0\uff0c\u6216\u8005\u53eb\u505a\u6807\u7b7e\u3002 \u5728pandas\u4e2d\uff0c cut \u548c qcut \u51fd\u6570\u90fd\u53ef\u4ee5\u8fdb\u884c\u5206\u7bb1\u5904\u7406\u64cd\u4f5c\u3002 cut() \u6309\u7167\u53d8\u91cf\u7684\u503c\u5bf9\u53d8\u91cf\u8fdb\u884c\u5206\u5272\uff0c\u6bcf\u4e2a\u5206\u7ec4\u91cc\u6570\u636e\u7684\u4e2a\u6570\u5e76\u4e0d\u4e00\u6837\u3002 qcut() \u662f\u6309\u53d8\u91cf\u7684\u6570\u91cf\u6765\u5bf9\u53d8\u91cf\u8fdb\u884c\u5206\u5272\uff0c\u5e76\u4e14\u5c3d\u91cf\u4fdd\u8bc1\u6bcf\u4e2a\u5206\u7ec4\u91cc\u53d8\u91cf\u7684\u4e2a\u6570\u76f8\u540c\u3002 \u8003\u8651\u4e0b\u9762\u4e00\u4e2a\u7b80\u5355\u7684\u968f\u673a\u6570\u636e\u96c6\u548c\u4e00\u4e2a\u4f7f\u7528 cut \u7684\u7b49\u957f\u6876\u5206\u7c7b\uff1a df = pd.DataFrame( { 'data1': np.random.randn(1000), 'data2': np.random.randn(1000) } ) quartiles = pd.cut(df.data1, 4) # \u6309\u7167data1\u503c\u7531\u5c0f\u5230\u5927\u7684\u987a\u5e8f\u5c06\u6570\u636e\u5206\u62104\u4efd\uff0c\u5e76\u4e14\u4f7f\u6bcf\u7ec4\u503c\u7684\u8303\u56f4\u5927\u81f4\u76f8\u7b49\u3002 print(quartiles[:10]) # 0 (-0.0743, 1.729] # 1 (-0.0743, 1.729] # 2 (-0.0743, 1.729] # 3 (-0.0743, 1.729] # 4 (-1.877, -0.0743] # 5 (-0.0743, 1.729] # 6 (-0.0743, 1.729] # 7 (-0.0743, 1.729] # 8 (-1.877, -0.0743] # 9 (-0.0743, 1.729] # Name: data1, dtype: category # Categories ( # 4, # interval[float64, right]): [ # (-3.687, -1.877] < (-1.877, -0.0743] < (-0.0743, 1.729] < (1.729, 3.531] # ] \u4e0a\u9762 cut \u8fd4\u56de\u7684 Categorical \u5bf9\u8c61\u53ef\u4ee5\u76f4\u63a5\u4f20\u9012\u7ed9 groupby \u3002\u5229\u7528\u5b83\u8ba1\u7b97\u51fa data2 \u5217\u7684\u4e00\u4e2a\u7edf\u8ba1\u503c\u96c6\u5408\uff0c\u5982\u4e0b\uff1a def get_stats(group): return { 'min': group.min(), 'max': group.max(), 'count': group.count(), 'mean': group.mean() } grouped = df.data2.groupby(quartiles) for i in grouped: print(i) result = grouped.apply(get_stats).unstack() print(result) # min max count mean # data1 # (-3.145, -1.424] -1.759377 2.484321 77.0 -0.127900 # (-1.424, 0.29] -3.142344 2.830654 524.0 -0.081931 # (0.29, 2.005] -3.557136 3.261635 376.0 0.015715 # (2.005, 3.719] -2.829458 1.766352 23.0 -0.198780 \u4f7f\u7528 qcut \uff0c\u6839\u636e\u6837\u672c\u5206\u4f4d\u6570\u8ba1\u7b97\u51fa\u7b49\u5927\u5c0f\u7684\u6876\uff0c\u5c31\u662f\u7b49\u957f\u6876\u3002\u901a\u8fc7\u4f20\u9012 labels=False \u6765\u83b7\u5f97\u5206\u4f4d\u6570\u6570\u503c\u3002 grouping = pd.qcut(df.data1, 10, labels=False) grouped = df.data2.groupby(grouping) result = grouped.apply(get_stats).unstack() print(result) # min max count mean # data1 # 0 -3.678934 3.022862 100.0 0.029658 # 1 -2.319813 2.646502 100.0 0.094035 # 2 -2.873727 2.470840 100.0 0.023866 # 3 -2.196701 2.042251 100.0 0.021232 # 4 -2.154161 2.020809 100.0 0.110834 # 5 -2.723061 2.415626 100.0 0.057365 # 6 -2.291470 2.536159 100.0 0.020866 # 7 -2.064083 1.799356 100.0 -0.081025 # 8 -3.405679 1.792581 100.0 -0.009705 # 9 -2.469285 2.600849 100.0 -0.061721","title":"\u5206\u4f4d\u6570\u4e0e\u6876\u5206\u6790"},{"location":"python/DataAnalysis/ch07/#_12","text":"\u5728\u6e05\u9664\u7f3a\u5931\u503c\u65f6\uff0c\u6709\u65f6\u4f1a\u4f7f\u7528 dropna \u6765\u53bb\u9664\u7f3a\u5931\u503c\uff0c\u6709\u65f6\u4f7f\u7528\u4fee\u6b63\u503c\u6216\u6765\u81ea\u4e8e\u5176\u4ed6\u6570\u636e\u7684\u503c\u6765\u8f93\u5165\uff08\u586b\u5145\uff09\u5230 null \u503c\uff08 NA \uff09\u3002 fillna \u662f\u4e00\u4e2a\u53ef\u4ee5\u4f7f\u7528\u7684\u6b63\u786e\u5de5\u5177\u3002 \u4f8b\u5982\u4e0b\u9762\u4f8b\u5b50\u4e2d\u4f7f\u7528\u4f7f\u7528\u5e73\u5747\u503c\u6765\u586b\u5145NA\u503c\uff1a data = (100, 110, 120, 130, 140, 150) s = pd.Series(data) print(s) # 0 100 # 1 110 # 2 120 # 3 130 # 4 140 # 5 150 # dtype: float64 \u5c06\u6570\u636e\u4e2d\u7684\u4e00\u4e9b\u503c\u8bbe\u7f6e\u4e3a\u7f3a\u5931\u503c\uff1a s[::2] = np.nan print(s) # 0 NaN # 1 110.0 # 2 NaN # 3 130.0 # 4 NaN # 5 150.0 # dtype: float64 result = s.fillna(s.mean()) # 110, 130, 150\u7684\u5e73\u5747\u503c\u662f130 print(result) # 0 130.0 # 1 110.0 # 2 130.0 # 3 130.0 # 4 130.0 # 5 150.0 # dtype: float64 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u6309\u7ec4\u586b\u5145NA\u503c\uff1a \u65b9\u6cd51,\u5bf9\u6570\u636e\u5206\u7ec4\u540e\u4f7f\u7528 apply \u3002 \u65b9\u6cd52,\u5728\u6bcf\u4e2a\u6570\u636e\u5757\u4e0a\u90fd\u8c03\u7528 fillna \u7684\u51fd\u6570\u3002 data = (100, 110, 120, 130, 140, 150, 160, 170) states = ['Ohio', 'New York', 'Vermont', 'Florida', 'Oregon', 'Nevada', 'California', 'Idaho'] group_key = ['East'] * 4 + ['West'] * 4 # 4\u4e2aEast\u548c4\u4e2aWest\u62fc\u63a5\u7684\u5217\u8868list s = pd.Series(data, index=states) print(s) # Ohio 100 # New York 110 # Vermont 120 # Florida 130 # Oregon 140 # Nevada 150 # California 160 # Idaho 170 # dtype: int64 \u5c06\u6570\u636e\u4e2d\u7684\u4e00\u4e9b\u503c\u8bbe\u7f6e\u4e3a\u7f3a\u5931\u503c\uff1a s[['Vermont', 'Nevada', 'Idaho']] = np.nan print(s) # Ohio 100.0 # New York 110.0 # Vermont NaN # Florida 130.0 # Oregon 140.0 # Nevada NaN # California 160.0 # Idaho NaN # dtype: float64 result = s.groupby(group_key).mean() print(result) # East 113.333333 # West 150.000000 # dtype: float64 \u7528\u4e0a\u9762\u5f97\u51fa\u7684\u5206\u7ec4\u5e73\u5747\u503c\u6765\u586b\u5145NA\u3002 fill_mean = lambda g: g.fillna(g.mean()) result = s.groupby(group_key).apply(fill_mean) print(result) # Ohio 100.000000 # New York 110.000000 # Vermont 113.333333 # Florida 130.000000 # Oregon 140.000000 # Nevada 150.000000 # California 160.000000 # Idaho 150.000000 # dtype: float64 \u5982\u679c\u5df2\u7ecf\u5728\u4ee3\u7801\u4e2d\u4e3a\u6bcf\u4e2a\u5206\u7ec4\u9884\u5b9a\u4e49\u4e86\u586b\u5145\u503c\uff0c\u53ef\u4ee5\u5229\u7528\u6bcf\u4e2a\u5206\u7ec4\u90fd\u6709\u7684\u5185\u7f6e\u7684 name \u5c5e\u6027\uff0c\u5b9e\u73b0\u586b\u5145 NA \u3002 fill_value = {'East': 0.5, 'West': -1} fill_func = lambda g: g.fillna(fill_value[g.name]) result = s.groupby(group_key).apply(fill_func) print(result) # Ohio 100.0 # New York 110.0 # Vermont 0.5 # Florida 130.0 # Oregon 140.0 # Nevada -1.0 # California 160.0 # Idaho -1.0 # dtype: float64","title":"\u793a\u4f8b\uff1a\u4f7f\u7528\u6307\u5b9a\u5206\u7ec4\u503c\u586b\u5145\u7f3a\u5931\u503c"},{"location":"python/DataAnalysis/ch07/#_13","text":"\u5047\u8bbe\u60f3\u4ece\u5927\u6570\u636e\u96c6\u4e2d\u62bd\u53d6\u968f\u673a\u6837\u672c\uff08\u6709\u6216\u6ca1\u6709\u66ff\u6362\uff09\u4ee5\u7528\u4e8e\u8499\u7279\u5361\u7f57\u6a21\u62df\u76ee\u7684\u6216\u67d0\u4e9b\u5176\u4ed6\u5e94\u7528\u7a0b\u5e8f\u3002 \u6709\u5f88\u591a\u65b9\u6cd5\u6765\u6267\u884c\u201c\u62bd\u53d6\u201d\uff0c\u8fd9\u91cc\u4f7f\u7528Series\u7684sample\u65b9\u6cd5\u3002 \u4e3a\u4e86\u6f14\u793a\uff0c\u8fd9\u91cc\u4ecb\u7ecd\u4e00\u79cd\u6784\u9020\u4e00\u526f\u82f1\u5f0f\u6251\u514b\u724c\u7684\u65b9\u6cd5\uff1a # \u6885\u82b1clubs\u3001\u65b9\u5757diamonds\u3001\u7ea2\u6843hearts\u3001\u9ed1\u6843spades\u3002 suits = ['H', 'S', 'C', 'D'] card_val = (list(range(1, 11)) + [10] * 3) * 4 # card_val [ # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10 # ] base_names = ['A'] + list(range(2, 11)) + ['J', 'K', 'Q'] # base_names\uff1a ['A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'K', 'Q'] \u751f\u6210\u4e86\u4e00\u4e2a\u957f\u5ea6\u4e3a 52 \u7684Series, Series\u7684\u7d22\u5f15\u5305\u542b\u4e86\u724c\u540d\uff0cSeries\u7684\u503c\u53ef\u4ee5\u7528\u6e38\u620f\uff08\u4e3a\u4e86\u4fdd\u6301\u7b80\u5355\uff0c\u8ba9\u2019A\u2019\u4e3a1 \uff09\uff1a cards = [] for suit in ['H', 'S', 'C', 'D']: cards.extend(str(num) + suit for num in base_names) deck = pd.Series(card_val, index=cards) print(deck) # AH 1 # 2H 2 # 3H 3 # 4H 4 # 5H 5 # 6H 6 # 7H 7 # 8H 8 # 9H 9 # 10H 10 # JH 10 # KH 10 # QH 10 # AS 1 # 2S 2 # 3S 3 # 4S 4 # 5S 5 # 6S 6 # 7S 7 # 8S 8 # 9S 9 # 10S 10 # JS 10 # KS 10 # QS 10 # AC 1 # 2C 2 # 3C 3 # 4C 4 # 5C 5 # 6C 6 # 7C 7 # 8C 8 # 9C 9 # 10C 10 # JC 10 # KC 10 # QC 10 # AD 1 # 2D 2 # 3D 3 # 4D 4 # 5D 5 # 6D 6 # 7D 7 # 8D 8 # 9D 9 # 10D 10 # JD 10 # KD 10 # QD 10 # dtype: int64 \u4ece\u8fd9\u526f\u724c\u4e2d\u62ff\u51fa\u4e94\u5f20\u724c\u53ef\u4ee5\u5199\u6210\uff1a def draw(_deck, n=5): return _deck.sample(n) print(draw(deck)) # KD 10 # 2S 2 # 5C 5 # 6C 6 # QD 10 # dtype: int64 \u5047\u8bbe\u8981\u4ece\u6bcf\u4e2a\u82b1\u8272\u4e2d\u968f\u673a\u62bd\u53d6\u4e24\u5f20\u724c\u3002\u7531\u4e8e\u82b1\u8272\u662f\u724c\u540d\u7684\u6700\u540e\u4e24\u4e2a\u5b57\u7b26\uff0c\u53ef\u4ee5\u57fa\u4e8e\u8fd9\u70b9\u8fdb\u884c\u5206\u7ec4\uff0c\u5e76\u4f7f\u7528 apply \uff1a get_suit = lambda card: card[-1] # \u6700\u540e\u4e00\u4e2a\u5b57\u6bcd\u662f\u82b1\u8272 result = deck.groupby(get_suit).apply(draw, n=2) print(result) # C 10C 10 # 3C 3 # D KD 10 # AD 1 # H 5H 5 # 7H 7 # S 3S 3 # 5S 5 # dtype: int64 \u6216\u8005\u4e5f\u53ef\u4ee5\u5199\u6210\uff1a result = deck.groupby(get_suit, group_keys=False).apply(draw, n=2) print(result) # JC 10 # 8C 8 # QD 10 # 4D 4 # 10H 10 # 6H 6 # 7S 7 # KS 10 # dtype: int64","title":"\u793a\u4f8b\uff1a\u968f\u673a\u91c7\u6837\u4e0e\u6392\u5217"},{"location":"python/DataAnalysis/ch07/#_14","text":"\u5728 groupby \u7684\u62c6\u5206-\u5e94\u7528-\u8054\u5408\u7684\u8303\u5f0f\u4e0b\uff0cDataFrame\u7684\u5217\u95f4\u64cd\u4f5c\u6216\u4e24\u4e2aSeriese\u4e4b\u95f4\u7684\u64cd\u4f5c\uff0c\u4f8b\u5982\u5b9e\u73b0\u5206\u7ec4\u52a0\u6743\u5e73\u5747\u3002 \u4e0b\u9762\u4f8b\u5b50\uff0c\u4f7f\u7528\u4e00\u4e2a\u5305\u542b\u5206\u7ec4\u952e\u548c\u6743\u91cd\u503c\u7684\u6570\u636e\u96c6\uff1a dt = np.random.randn(8) wt = np.random.randn(8) df = pd.DataFrame( { 'category': ['a', 'a', 'a', 'a', 'b', 'b', 'b', 'b'], 'data': dt, 'weight': wt } ) print(df) # category data weight # 0 a -0.250764 -0.085285 # 1 a 0.167155 -1.361254 # 2 a 0.399306 1.755542 # 3 a -0.514477 0.270124 # 4 b -0.005558 0.886514 # 5 b 0.607596 -1.384315 # 6 b -1.029627 -0.845340 # 7 b -0.294204 1.253965 \u901a\u8fc7 category \u8fdb\u884c\u5206\u7ec4\u52a0\u6743\u5e73\u5747\u5982\u4e0b\uff1a grouped = df.groupby('category') get_wavg = lambda g: np.average(g['data'], weights=g['weight']) result = grouped.apply(get_wavg) print(result) # category # a 0.614499 # b 3.863947 # dtype: float64 \u53e6\u4e00\u4e2a\u4f8b\u5b50\uff0c\u4e00\u4e2a\u4ece\u96c5\u864e\u8d22\u7ecf\u4e0a\u83b7\u5f97\u7684\u6570\u636e\u96c6\uff0c\u8be5\u6570\u636e\u96c6\u5305\u542b\u4e00\u4e9b\u6807\u666e500 \uff08SPX\u7b26\u53f7\uff09\u548c\u80a1\u7968\u7684\u6536\u76d8\u4ef7\uff1a close_px = pd.read_csv('../examples/stock_px_2.csv', parse_dates=True, index_col=0) print(close_px.info()) # # DatetimeIndex: 2214 entries, 2003-01-02 to 2011-10-14 # Data columns (total 4 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 AAPL 2214 non-null float64 # 1 MSFT 2214 non-null float64 # 2 XOM 2214 non-null float64 # 3 SPX 2214 non-null float64 # dtypes: float64(4) # memory usage: 86.5 KB # None print(close_px[-4:]) # AAPL MSFT XOM SPX # 2011-10-11 400.29 27.00 76.27 1195.54 # 2011-10-12 402.19 26.96 77.16 1207.25 # 2011-10-13 408.43 27.18 76.37 1203.66 # 2011-10-14 422.00 27.27 78.11 1224.58 \u76ee\u6807\u4efb\u52a1\uff1a\u8ba1\u7b97\u4e00\u4e2aDataFrame\uff0c\u5b83\u5305\u542b\u6807\u666e\u6307\u6570\uff08SPX\uff09\u6bcf\u65e5\u6536\u76ca\u7684\u5e74\u5ea6\u76f8\u5173\u6027\uff08\u901a\u8fc7\u767e\u5206\u6bd4\u53d8\u5316\u8ba1\u7b97\uff09\u3002 \u9996\u5148\u521b\u5efa\u4e00\u4e2a\u8ba1\u7b97\u6bcf\u5217\u4e0e\u2019SPX\u2019\u5217\u6210\u5bf9\u5173\u8054\u7684\u51fd\u6570\uff1a spx_corr = lambda x: x.corrwith(x['SPX']) \u4e4b\u540e\uff0c\u4f7f\u7528 pct_change \u8ba1\u7b97 close-px \u767e\u5206\u6bd4\u7684\u53d8\u5316\uff1a rets = close_px.pct_change().dropna() # Percentage change between the current and a prior element. print(rets) # AAPL MSFT XOM SPX # 2003-01-03 0.006757 0.001421 0.000684 -0.000484 # 2003-01-06 0.000000 0.017975 0.024624 0.022474 # ... ... ... ... ... # 2011-10-14 0.033225 0.003311 0.022784 0.017380 # [2213 rows x 4 columns] \u6700\u540e\uff0c\u6309\u5e74\u5bf9\u767e\u5206\u6bd4\u53d8\u5316\u8fdb\u884c\u5206\u7ec4\uff0c\u53ef\u4ee5\u4f7f\u7528\u5355\u884c\u51fd\u6570\u4ece\u6bcf\u4e2a\u884c\u6807\u7b7e\u4e2d\u63d0\u53d6\u6bcf\u4e2a datetime \u6807\u7b7e\u7684 year \u5c5e\u6027\uff1a get_year = lambda x: x.year by_year = rets.groupby(get_year) result = by_year.apply(spx_corr) print(result) # AAPL MSFT XOM SPX # 2003 0.541124 0.745174 0.661265 1.0 # 2004 0.374283 0.588531 0.557742 1.0 # 2005 0.467540 0.562374 0.631010 1.0 # 2006 0.428267 0.406126 0.518514 1.0 # 2007 0.508118 0.658770 0.786264 1.0 # 2008 0.681434 0.804626 0.828303 1.0 # 2009 0.707103 0.654902 0.797921 1.0 # 2010 0.710105 0.730118 0.839057 1.0 # 2011 0.691931 0.800996 0.859975 1.0 \u53ef\u4ee5\u8ba1\u7b97\u5185\u90e8\u5217\u76f8\u5173\u6027\u3002\u8fd9\u91cc\u8ba1\u7b97\u4e86\u82f9\u679c\u548c\u5fae\u8f6f\u7684\u5e74\u5ea6\u76f8\u5173\u6027\uff1a result = by_year.apply(lambda g: g['AAPL'].corr(g['MSFT'])) print(result) # 2003 0.480868 # 2004 0.259024 # 2005 0.300093 # 2006 0.161735 # 2007 0.417738 # 2008 0.611901 # 2009 0.432738 # 2010 0.571946 # 2011 0.581987 # dtype: float64","title":"\u793a\u4f8b\uff1a\u5206\u7ec4\u52a0\u6743\u5e73\u5747\u548c\u76f8\u5173\u6027"},{"location":"python/DataAnalysis/ch07/#_15","text":"\u5b9a\u4e49\u4ee5\u4e0b regress \uff08\u56de\u5f52\uff09\u51fd\u6570\uff08\u4f7f\u7528 statsmodels \u8ba1\u91cf\u7ecf\u6d4e\u5b66\u5e93\uff09\uff0c\u8be5\u51fd\u6570\u5bf9\u6bcf\u4e2a\u6570\u636e\u5757\u6267\u884c\u666e\u901a\u6700\u5c0f\u4e8c\u4e58\uff08OLS\uff09\u56de\u5f52\uff1a def regress(data, yvar, xvars): Y = data[yvar] X = data[xvars] X['intercept'] = 1. result = sm.OLS(Y, X).fit() return result.params \u73b0\u5728\u8981\u8ba1\u7b97AAPL\u5728SPX\u56de\u62a5\u4e0a\u7684\u5e74\u5ea6\u7ebf\u6027\u56de\u5f52\uff1a result = by_year.apply(regress, 'AAPL', ['SPX']) print(result) # SPX intercept # 2003 1.195406 0.000710 # 2004 1.363463 0.004201 # 2005 1.766415 0.003246 # 2006 1.645496 0.000080 # 2007 1.198761 0.003438 # 2008 0.968016 -0.001110 # 2009 0.879103 0.002954 # 2010 1.052608 0.001261 # 2011 0.806605 0.001514","title":"\u793a\u4f8b\uff1a\u9010\u7ec4\u7ebf\u6027\u56de\u5f52"},{"location":"python/DataAnalysis/ch07/#_16","text":"","title":"\u6570\u636e\u900f\u89c6\u8868\u4e0e\u4ea4\u53c9\u8868"},{"location":"python/DataAnalysis/ch07/#_17","text":"\u6570\u636e\u900f\u89c6\u8868\u662f\u7535\u5b50\u8868\u683c\u7a0b\u5e8f\u548c\u5176\u4ed6\u6570\u636e\u5206\u6790\u8f6f\u4ef6\u4e2d\u5e38\u89c1\u7684\u6570\u636e\u6c47\u603b\u5de5\u5177\u3002 \u5b83\u6839\u636e\u4e00\u4e2a\u6216\u591a\u4e2a\u952e\u805a\u5408\u4e00\u5f20\u8868\u7684\u6570\u636e\uff0c\u5c06\u6570\u636e\u5728\u77e9\u5f62\u683c\u5f0f\u4e2d\u6392\u5217\uff0c\u5176\u4e2d\u4e00\u4e9b\u5206\u7ec4\u952e\u662f\u6cbf\u7740\u884c\u7684\uff0c\u53e6\u4e00\u4e9b\u662f\u6cbf\u7740\u5217\u7684\u3002 Python\u4e2d\u7684pandas\u900f\u89c6\u8868\u662f\u901a\u8fc7\u8fd9\u91cc\u6240\u4ecb\u7ecd\u7684groupby\u5de5\u5177\u4ee5\u53ca\u4f7f\u7528\u5206\u5c42\u7d22\u5f15\u7684\u91cd\u5851\u64cd\u4f5c\u5b9e\u73b0\u7684\u3002 DataFrame\u62e5\u6709\u4e00\u4e2a pivot_table \u65b9\u6cd5\uff0c\u5e76\u4e14\u8fd8\u6709\u8fd8\u4e00\u4e2a\u9876\u5c42\u7684 pandas.pivot_table \u51fd\u6570\u3002 \u9664\u4e86\u4e3a groupby \u63d0\u4f9b\u4e00\u4e2a\u65b9\u4fbf\u63a5\u53e3\uff0c pivot_table \u8fd8\u53ef\u4ee5\u6dfb\u52a0\u90e8\u5206\u603b\u8ba1\uff0c\u4e5f\u79f0\u4f5c\u8fb9\u8ddd\u3002 import pandas as pd import numpy as np \u6839\u636e\u4e0b\u9762\u7684\u5c0f\u8d39\u6570\u636e\u96c6\uff0c\u8ba1\u7b97\u4e00\u5f20\u5728\u884c\u65b9\u5411\u4e0a\u6309 day \u548c smoker \u6392\u5217\u7684\u5206\u7ec4\u5e73\u5747\u503c\uff08\u9ed8\u8ba4\u7684 pivot_table \u805a\u5408\u7c7b\u578b\uff09\u7684\u8868\u3002 pivot_table \u9009\u9879\uff1a values: \u9700\u8981\u805a\u5408\u7684\u5217\u540d\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u805a\u5408\u6240\u6709\u6570\u503c\u578b\u7684\u5217\u3002 index: \u5728\u7ed3\u679c\u900f\u89c6\u8868\u7684\u884c\u4e0a\u8fdb\u884c\u5206\u7ec4\u7684\u5217\u540d\u6216\u8005\u5176\u4ed6\u5206\u7ec4\u952e\u3002 tips = pd.read_csv('../examples/tips.csv') tips['tip_pct'] = tips['tip'] / (tips['total_bill'] - tips['tip']) \u6837\u672c\u6570\u636e\u3002 print(tips.head(5)) # total_bill tip smoker day time size tip_pct # 0 16.99 1.01 No Sun Dinner 2 0.063204 # 1 10.34 1.66 No Sun Dinner 3 0.191244 # 2 21.01 3.50 No Sun Dinner 3 0.199886 # 3 23.68 3.31 No Sun Dinner 2 0.162494 # 4 24.59 3.61 No Sun Dinner 4 0.172069 \u8ba1\u7b97\u5728\u884c\u65b9\u5411\u4e0a\u6309 day \u548c smoker \u6392\u5217\u7684\u5206\u7ec4\u5e73\u5747\u503c\u3002\u4e5f\u53ef\u4ee5\u76f4\u63a5\u4f7f\u7528 groupby \u5b9e\u73b0\u3002 result = tips.pivot_table(index=['day', 'smoker']) print(result) # size tip tip_pct total_bill # day smoker # Fri No 2.250000 2.812500 0.179740 18.420000 # Yes 2.066667 2.714000 0.216293 16.813333 # Sat No 2.555556 3.102889 0.190412 19.661778 # Yes 2.476190 2.875476 0.179833 21.276667 # Sun No 2.929825 3.167895 0.193617 20.506667 # Yes 2.578947 3.516842 0.322021 24.120000 # Thur No 2.488889 2.673778 0.193424 17.113111 # Yes 2.352941 3.030000 0.198508 19.190588 \u5728 tip_pct \u548c size \u4e0a\u8fdb\u884c\u805a\u5408\uff0c\u5e76\u6839\u636e time \u5206\u7ec4\u3002\u5c06\u628a smoker \u653e\u5165\u8868\u7684\u5217\uff0c\u800c\u5c06 day \u653e\u5165\u8868\u7684\u884c\uff1a result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker' ) print(result) # size tip_pct # smoker No Yes No Yes # time day # Dinner Fri 2.000000 2.222222 0.162612 0.202545 # Sat 2.555556 2.476190 0.190412 0.179833 # Sun 2.929825 2.578947 0.193617 0.322021 # Thur 2.000000 NaN 0.190114 NaN # Lunch Fri 3.000000 1.833333 0.231125 0.236915 # Thur 2.500000 2.352941 0.193499 0.198508 \u901a\u8fc7\u4f20\u9012 margins=True \u6765\u6269\u5145\u8fd9\u4e2a\u8868\u6765\u5305\u542b\u90e8\u5206\u603b\u8ba1\u3002\u8fd9\u4f1a\u6dfb\u52a0 All \u884c\u548c\u5217\u6807\u7b7e\uff0c\u5176\u4e2d\u76f8\u5e94\u7684\u503c\u662f\u5355\u5c42\u4e2d\u6240\u6709\u6570\u636e\u7684\u5206\u7ec4\u7edf\u8ba1\u503c\u3002 \u8fd9\u91cc All \u7684\u503c\u662f\u5747\u503c\uff0c\u4e14\u8be5\u5747\u503c\u662f\u4e0d\u8003\u8651\u5438\u70df\u8005\u4e0e\u975e\u5438\u70df\u8005\uff08 All \u5217\uff09\u6216\u884c\u5206\u7ec4\u4e2d\u4efb\u4f55\u4e24\u7ea7\u7684\uff08 All \u884c\uff09\u3002 result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker', margins=True ) print(result) # size tip_pct # smoker No Yes All No Yes All # time day # Dinner Fri 2.000000 2.222222 2.166667 0.162612 0.202545 0.192562 # Sat 2.555556 2.476190 2.517241 0.190412 0.179833 0.185305 # Sun 2.929825 2.578947 2.842105 0.193617 0.322021 0.225718 # Thur 2.000000 NaN 2.000000 0.190114 NaN 0.190114 # Lunch Fri 3.000000 1.833333 2.000000 0.231125 0.236915 0.236088 # Thur 2.500000 2.352941 2.459016 0.193499 0.198508 0.194895 # All 2.668874 2.408602 2.569672 0.192237 0.218176 0.202123 \u8981\u4f7f\u7528\u4e0d\u540c\u7684\u805a\u5408\u51fd\u6570\u65f6\uff0c\u5c06\u51fd\u6570\u4f20\u9012\u7ed9 aggfunc \u3002\u4f8b\u5982\uff0c count \u6216\u8005 len \u5c06\u7ed9\u51fa\u4e00\u5f20\u5206\u7ec4\u5927\u5c0f\u7684\u4ea4\u53c9\u8868\uff08\u8ba1\u6570\u6216\u51fa\u73b0\u9891\u7387\uff09\uff1a result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker', aggfunc=len, margins=True ) print(result) # size tip_pct # smoker No Yes All No Yes All # time day # Dinner Fri 3.0 9.0 12 3.0 9.0 12 # Sat 45.0 42.0 87 45.0 42.0 87 # Sun 57.0 19.0 76 57.0 19.0 76 # Thur 1.0 NaN 1 1.0 NaN 1 # Lunch Fri 1.0 6.0 7 1.0 6.0 7 # Thur 44.0 17.0 61 44.0 17.0 61 # All 151.0 93.0 244 151.0 93.0 244 \u5bf9\u4e8e\u7a7a\u503c NA \uff0c\u4f20\u9012\u4e00\u4e2a fill_value \u3002 result = tips.pivot_table( ['tip_pct', 'size'], index=['time', 'day'], columns='smoker', aggfunc='mean', fill_value=0, margins=True ) print(result) # size tip_pct # smoker No Yes All No Yes All # time day # Dinner Fri 2.000000 2.222222 2.166667 0.162612 0.202545 0.192562 # Sat 2.555556 2.476190 2.517241 0.190412 0.179833 0.185305 # Sun 2.929825 2.578947 2.842105 0.193617 0.322021 0.225718 # Thur 2.000000 0.000000 2.000000 0.190114 0.000000 0.190114 # Lunch Fri 3.000000 1.833333 2.000000 0.231125 0.236915 0.236088 # Thur 2.500000 2.352941 2.459016 0.193499 0.198508 0.194895 # All 2.668874 2.408602 2.569672 0.192237 0.218176 0.202123","title":"\u6570\u636e\u900f\u89c6\u8868"},{"location":"python/DataAnalysis/ch07/#crosstab","text":"\u4ea4\u53c9\u8868\uff08\u7b80\u5199\u4e3acrosstab\uff09\u662f\u6570\u636e\u900f\u89c6\u8868\u7684\u4e00\u4e2a\u7279\u6b8a\u60c5\u51b5\uff0c\u8ba1\u7b97\u7684\u662f\u5206\u7ec4\u4e2d\u7684\u9891\u7387\u3002 crosstab \u7684\u524d\u4e24\u4e2a\u53c2\u6570\u53ef\u662f\u6570\u7ec4\u3001Series\u6216\u6570\u7ec4\u7684\u5217\u8868\u3002 sample = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] nationality = ['USA', 'Japan', 'USA', 'Japan', 'Japan', 'Japan', 'USA', 'USA', 'Japan', 'USA'] handedness = ['Right-handed', 'Left-handed', 'Right-handed', 'Right-handed', 'Left-handed', 'Right-handed', 'Right-handed', 'Left-handed', 'Right-handed', 'Right-handed'] df = pd.DataFrame( { 'sample': sample, 'nationality': nationality, 'handedness': handedness } ) print(df) # sample nationality handedness # 0 1 USA Right-handed # 1 2 Japan Left-handed # 2 3 USA Right-handed # 3 4 Japan Right-handed # 4 5 Japan Left-handed # 5 6 Japan Right-handed # 6 7 USA Right-handed # 7 8 USA Left-handed # 8 9 Japan Right-handed # 9 10 USA Right-handed \u6309\u7167\u56fd\u7c4d\u548c\u60ef\u7528\u6027\u6765\u603b\u7ed3\u8fd9\u4e9b\u6570\u636e\uff0c\u53ef\u4ee5\u4f7f\u7528 pivot_table \u6765\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\uff0c\u4f46\u662f pandas.crosstable \u51fd\u6570\u66f4\u4e3a\u65b9\u4fbf\uff1a result = pd.crosstab(df.nationality, df.handedness, margins=True) print(result) # handedness Left-handed Right-handed All # nationality # Japan 2 3 5 # USA 1 4 5 # All 3 7 10 \u5728\u5c0f\u8d39\u6570\u636e\u4e2d\u53ef\u4ee5\u8fd9\u4e48\u505a\uff1a result = pd.crosstab(['tips.time', tips.day], tips.smoker, margins=True) print(result) # smoker No Yes All # row_0 day # tips.time Fri 4 15 19 # Sat 45 42 87 # Sun 57 19 76 # Thur 45 17 62 # All 151 93 244","title":"\u4ea4\u53c9\u8868\uff1acrosstab"},{"location":"python/DataAnalysis/ch08/","text":"\u65f6\u95f4\u5e8f\u5217 \u00b6 \u65e5\u671f\u548c\u65f6\u95f4\u6570\u636e\u7684\u7c7b\u578b\u53ca\u5de5\u5177 \u00b6 \u65f6\u95f4\u5e8f\u5217\u6570\u636e\u5728\u5f88\u591a\u9886\u57df\u90fd\u662f\u91cd\u8981\u7684\u7ed3\u6784\u5316\u6570\u636e\u5f62\u5f0f\u3002\u5728\u591a\u4e2a\u65f6\u95f4\u70b9\u89c2\u6d4b\u6216\u6d4b\u91cf\u7684\u6570\u636e\u5f62\u6210\u4e86\u65f6\u95f4\u5e8f\u5217\u3002 \u8bb8\u591a\u65f6\u95f4\u5e8f\u5217\u662f\u56fa\u5b9a\u9891\u7387\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\u6570\u636e\u662f\u6839\u636e\u76f8\u540c\u7684\u89c4\u5219\u5b9a\u671f\u51fa\u73b0\u7684\uff0c\u4f8b\u5982\u6bcf15\u79d2\u3001\u6bcf5\u5206\u949f\u6216\u6bcf\u67081\u6b21\u3002 \u65f6\u95f4\u5e8f\u5217\u4e5f\u53ef\u4ee5\u662f\u4e0d\u89c4\u5219\u7684\uff0c\u6ca1\u6709\u56fa\u5b9a\u7684\u65f6\u95f4\u5355\u4f4d\u6216\u5355\u4f4d\u95f4\u7684\u504f\u79fb\u91cf\u3002 \u5982\u4f55\u6807\u8bb0\u548c\u5f15\u7528\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u53d6\u51b3\u4e8e\u5e94\u7528\u7a0b\u5e8f\uff0c\u65f6\u95f4\u5e8f\u5217\u5305\u62ec\uff1a \u65f6\u95f4\u6233\uff0c\u5177\u4f53\u7684\u65f6\u523b\u3002 \u56fa\u5b9a\u7684\u65f6\u95f4\u533a\u95f4\uff0c\u4f8b\u59822007\u76841\u6708\u6216\u6574\u4e2a2010\u5e74\u3002 \u65f6\u95f4\u95f4\u9694\uff0c\u7531\u5f00\u59cb\u548c\u7ed3\u675f\u65f6\u95f4\u6233\u8868\u793a\u3002\u65f6\u95f4\u533a\u95f4\u53ef\u4ee5\u88ab\u8ba4\u4e3a\u662f\u95f4\u9694\u7684\u7279\u6b8a\u60c5\u51b5\u3002 \u5b9e\u9a8c\u65f6\u95f4\u6216\u6d88\u8017\u65f6\u95f4\u3002\u6bcf\u4e2a\u65f6\u95f4\u6233\u662f\u76f8\u5bf9\u4e8e\u7279\u5b9a\u5f00\u59cb\u65f6\u95f4\u7684\u65f6\u95f4\u7684\u91cf\u5ea6\uff08\u4f8b\u5982\uff0c\u81ea\u4ece\u88ab\u653e\u7f6e\u5728\u70e4\u7bb1\u4e2d\u6bcf\u79d2\u70d8\u70e4\u7684\u997c\u5e72\u7684\u76f4\u5f84\uff09\u3002 \u76ee\u524d\u4e3b\u8981\u5173\u6ce8\u524d\u4e09\u7c7b\u4e2d\u7684\u65f6\u95f4\u5e8f\u5217\u3002 from datetime import datetime, timedelta import datetime as dt from dateutil.parser import parse import pandas as pd datetime \u00b6 datetime\u683c\u5f0f\u7b26\uff1a %a \u661f\u671f\u7684\u82f1\u6587\u5355\u8bcd\u7684\u7f29\u5199\uff1a\u5982\u661f\u671f\u4e00\uff0c \u5219\u8fd4\u56de Mon %A \u661f\u671f\u7684\u82f1\u6587\u5355\u8bcd\u7684\u5168\u62fc\uff1a\u5982\u661f\u671f\u4e00\uff0c\u8fd4\u56de Monday %b \u6708\u4efd\u7684\u82f1\u6587\u5355\u8bcd\u7684\u7f29\u5199\uff1a\u5982\u4e00\u6708\uff0c \u5219\u8fd4\u56de Jan %B \u6708\u4efd\u7684\u5f15\u6587\u5355\u8bcd\u7684\u7f29\u5199\uff1a\u5982\u4e00\u6708\uff0c \u5219\u8fd4\u56de January %c \u8fd4\u56dedatetime\u7684\u5b57\u7b26\u4e32\u8868\u793a\uff0c\u598203/08/15 23:01:26 %d \u8fd4\u56de\u7684\u662f\u5f53\u524d\u65f6\u95f4\u662f\u5f53\u524d\u6708\u7684\u7b2c\u51e0\u5929 %f \u5fae\u79d2\u7684\u8868\u793a\uff1a \u8303\u56f4: [0,999999] %H \u4ee524\u5c0f\u65f6\u5236\u8868\u793a\u5f53\u524d\u5c0f\u65f6 %I \u4ee512\u5c0f\u65f6\u5236\u8868\u793a\u5f53\u524d\u5c0f\u65f6 %m \u8fd4\u56de\u6708\u4efd \u8303\u56f4[0,12] %M \u8fd4\u56de\u5206\u949f\u6570 \u8303\u56f4 [0,59] %P \u8fd4\u56de\u662f\u4e0a\u5348\u8fd8\u662f\u4e0b\u5348\u2013AM or PM %S \u8fd4\u56de\u79d2\u6570 \u8303\u56f4 [0,61]\u3002\u3002\u3002\u624b\u518c\u8bf4\u660e\u7684 %U \u8fd4\u56de\u5f53\u5468\u662f\u5f53\u5e74\u7684\u7b2c\u51e0\u5468 \u4ee5\u5468\u65e5\u4e3a\u7b2c\u4e00\u5929 %W \u8fd4\u56de\u5f53\u5468\u662f\u5f53\u5e74\u7684\u7b2c\u51e0\u5468 \u4ee5\u5468\u4e00\u4e3a\u7b2c\u4e00\u5929 %w \u5f53\u5929\u5728\u5f53\u5468\u7684\u5929\u6570\uff0c\u8303\u56f4\u4e3a[0, 6]\uff0c6\u8868\u793a\u661f\u671f\u5929 %x \u65e5\u671f\u7684\u5b57\u7b26\u4e32\u8868\u793a \uff1a03/08/15 %X \u65f6\u95f4\u7684\u5b57\u7b26\u4e32\u8868\u793a \uff1a23:22:08 %y \u4e24\u4e2a\u6570\u5b57\u8868\u793a\u7684\u5e74\u4efd 15 %Y \u56db\u4e2a\u6570\u5b57\u8868\u793a\u7684\u5e74\u4efd 2015 %z \u4e0eutc\u65f6\u95f4\u7684\u95f4\u9694 \uff08\u5982\u679c\u662f\u672c\u5730\u65f6\u95f4\uff0c\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\uff09 %Z \u65f6\u533a\u540d\u79f0\uff08\u5982\u679c\u662f\u672c\u5730\u65f6\u95f4\uff0c\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\uff09 datestrs = ['2020/5/6', '2021/10/1'] # \u6ce8\u610f\u533a\u5206datetime\u6a21\u5757\u548cdatetime\u7c7b\uff0c\u540d\u5b57\u76f8\u540c\uff0c\u5bb9\u6613\u5f15\u8d77\u9519\u8bef\u3002 # \u6bd4\u5982datetime.datetime\u5c31\u62a5\u9519type object 'datetime.datetime' has no attribute 'datetime' print(datetime) # print(dt) # Python\u6807\u51c6\u5e93\u5305\u542b\u4e86\u65e5\u671f\u548c\u65f6\u95f4\u6570\u636e\u7684\u7c7b\u578b\u3002 datetime \u3001 time \u548c calendar \u6a21\u5757\u662f\u5f00\u59cb\u5904\u7406\u65f6\u95f4\u6570\u636e\u7684\u4e3b\u8981\u5185\u5bb9\u3002 datetime.datetime \u7c7b\u578b\uff0c\u6216\u7b80\u5199\u4e3a datetime \uff0c\u662f\u5e7f\u6cdb\u4f7f\u7528\u7684\u3002 now = datetime.now() print(now) # 2021-10-07 20:24:43.834293 result = dt.datetime(2021, 10, 7, 20, 26, 00, 72973) print(result) # 2021-10-07 20:26:00.072973 datetime \u65e2\u5b58\u50a8\u4e86\u65e5\u671f\uff0c\u4e5f\u5b58\u50a8\u4e86\u7ec6\u5316\u5230\u5fae\u79d2\u7684\u65f6\u95f4\u3002 timedelta \u8868\u793a\u4e24\u4e2a datetime \u5bf9\u8c61\u7684\u65f6\u95f4\u5dee\u3002 delta = datetime(2021, 10, 7) - datetime(2021, 9, 7) print(delta) # 30 days, 0:00:00 print(delta.days) # 30 print(delta.seconds) # 0 result = dt.timedelta(926, 56700) print(result) # 926 days, 15:45:00 \u53ef\u4ee5\u4e3a\u4e00\u4e2a datetime \u5bf9\u8c61\u52a0\u4e0a\uff08\u6216\u51cf\u53bb\uff09\u4e00\u4e2a timedelta \u6216\u5176\u6574\u6570\u500d\u6765\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684 datetime \u5bf9\u8c61\u3002 start = datetime(2021, 10, 7) result = start + timedelta(12) print(result) # 2021-10-19 00:00:00 result = start - 2 * timedelta(5) print(result) # 2021-09-27 00:00:00 \u5b57\u7b26\u4e32\u4e0edatetime\u4e92\u76f8\u8f6c\u6362 \u00b6 \u4f7f\u7528 str \u65b9\u6cd5\u6216\u4f20\u9012\u4e00\u4e2a\u6307\u5b9a\u7684\u683c\u5f0f\u7ed9 strftime \u65b9\u6cd5\u6765\u5bf9 datetime \u5bf9\u8c61\u548cpandas\u7684 Timestamp \u5bf9\u8c61\u8fdb\u884c\u683c\u5f0f\u5316\u3002 stamp = datetime(2021, 10, 7) result = str(stamp) print(result) # 2021-10-07 00:00:00 \u4f7f\u7528 datetime.srtptime \u548c datetime \u683c\u5f0f\u7b26\uff0c\u628a\u5b57\u7b26\u4e32\u8f6c\u6362\u65e5\u671f\u3002 datetime.strptime \u662f\u5728\u5df2\u77e5\u683c\u5f0f\u7684\u60c5\u51b5\u4e0b\u8f6c\u6362\u65e5\u671f\u7684\u597d\u65b9\u5f0f\u3002 value = '2021-10-7' result = datetime.strptime(value, '%Y-%m-%d') print(result) # 2021-10-07 00:00:00 datestrs = ['2020/5/6', '2021/10/1'] result = [datetime.strptime(x, '%Y/%m/%d') for x in datestrs] print(result) # [datetime.datetime(2020, 5, 6, 0, 0), datetime.datetime(2021, 10, 1, 0, 0)] dateutil \u89e3\u6790\u901a\u7528\u65e5\u671f\u683c\u5f0f\uff1a print(parse('2020/5/6')) # 2020-05-06 00:00:00 print(parse('Jan 31, 2021 10:25 AM')) # 2021-01-31 10:25:00 print(parse('5/6/2021', dayfirst=True)) # \u65e5\u671f\u51fa\u73b0\u5728\u6708\u4efd\u4e4b\u524d # 2021-06-05 00:00:00 pandas\u4e3b\u8981\u662f\u9762\u5411\u5904\u7406\u65e5\u671f\u6570\u7ec4\u7684\uff0c\u65e0\u8bba\u662f\u7528\u4f5c\u8f74\u7d22\u5f15\u8fd8\u662f\u7528\u4f5cDataFrame\u4e2d\u7684\u5217\u3002 to_datetime \u65b9\u6cd5\u53ef\u4ee5\u8f6c\u6362\u5f88\u591a\u4e0d\u540c\u7684\u65e5\u671f\u8868\u793a\u683c\u5f0f\u3002 to_datetime \u65b9\u6cd5\u8fd8\u53ef\u4ee5\u5904\u7406\u90a3\u4e9b\u88ab\u8ba4\u4e3a\u662f\u7f3a\u5931\u503c\u7684\u503c\uff08None\u3001\u7a7a\u5b57\u7b26\u4e32\u7b49\uff09\u3002 NaT \uff08Not a time\uff09\u662fpandas\u4e2d\u65f6\u95f4\u6233\u6570\u636e\u7684\u662fnull\u503c\u3002 datestrs = ['2020/5/6 12:00:00', '2021/10/1 09:00:00'] result = pd.to_datetime(datestrs) print(result) # DatetimeIndex(['2020-05-06 12:00:00', '2021-10-01 09:00:00'], dtype='datetime64[ns]', freq=None) idx = pd.to_datetime(datestrs + [None]) print(idx) # DatetimeIndex(['2020-05-06 12:00:00', '2021-10-01 09:00:00', 'NaT'], dtype='datetime64[ns]', freq=None) print(idx[2]) # NaT print(pd.isnull(idx)) # [False False True] \u65f6\u95f4\u5e8f\u5217\u57fa\u7840 \u00b6 from datetime import datetime import pandas as pd import numpy as np DatetimeIndex \u00b6 pandas\u4e2d\u7684\u57fa\u7840\u65f6\u95f4\u5e8f\u5217\u79cd\u7c7b\u662f\u7531\u65f6\u95f4\u6233\u7d22\u5f15\u7684Series\uff0c\u5728pandas\u5916\u90e8\u5219\u901a\u5e38\u8868\u793a\u4e3aPython\u5b57\u7b26\u4e32\u6216 datetime \u5bf9\u8c61\u3002 \u6240\u6709\u4f7f\u7528 datetime \u5bf9\u8c61\u7684\u5730\u65b9\u90fd\u53ef\u4ee5\u7528 Timestamp \u3002 dates = [ datetime(2021, 10, 1), datetime(2021, 10, 3), datetime(2021, 10, 5), datetime(2021, 10, 7), datetime(2021, 10, 9), datetime(2021, 10, 11) ] data = np.random.rand(6) ts = pd.Series(data, index=dates) print(ts) # 2021-10-01 0.678297 # 2021-10-03 0.538631 # 2021-10-05 0.934413 # 2021-10-07 0.018534 # 2021-10-09 0.938441 # 2021-10-11 0.173329 # dtype: float64 \u8fd9\u4e9b datetime \u5bf9\u8c61\u88ab\u653e\u5165 DatetimeIndex \u4e2d\u3002 print(ts.index) # DatetimeIndex(['2021-10-01', '2021-10-03', '2021-10-05', '2021-10-07', # '2021-10-09', '2021-10-11'], # dtype='datetime64[ns]', freq=None) DatetimeIndex \u4e2d\u7684\u6807\u91cf\u503c\u662f pandas \u7684 Timestamp \u5bf9\u8c61\uff1a stamp = ts.index[0] print(stamp) # 2021-10-01 00:00:00 \u548c\u5176\u4ed6Series\u7c7b\u4f3c\uff0c\u4e0d\u540c\u7d22\u5f15\u7684\u65f6\u95f4\u5e8f\u5217\u4e4b\u95f4\u7684\u7b97\u672f\u8fd0\u7b97\u5728\u65e5\u671f\u4e0a\u81ea\u52a8\u5bf9\u9f50\uff1a print(ts + ts[::2]) # ts[::2]\u4f1a\u5c06ts\u4e2d\u6bcf\u9694\u4e00\u4e2a\u7684\u5143\u7d20\u9009\u62e9\u51fa # 2021-10-01 1.356595 # 2021-10-03 NaN # 2021-10-05 1.868825 # 2021-10-07 NaN # 2021-10-09 1.876883 # 2021-10-11 NaN # dtype: float64 pandas\u4f7f\u7528NumPy\u7684 datetime64 \u6570\u636e\u7c7b\u578b\u5728\u7eb3\u79d2\u7ea7\u7684\u5206\u8fa8\u7387\u4e0b\u5b58\u50a8\u65f6\u95f4\u6233 print(ts.index.dtype) # datetime64[ns] \u7d22\u5f15\u3001\u9009\u62e9\u3001\u5b50\u96c6 \u00b6 \u5f53\u57fa\u4e8e\u6807\u7b7e\u8fdb\u884c\u7d22\u5f15\u548c\u9009\u62e9\u65f6\uff0c\u65f6\u95f4\u5e8f\u5217\u7684\u884c\u4e3a\u548c\u5176\u4ed6\u7684pandas.Series\u7c7b\u4f3c\uff1a stamp = ts.index[2] print(ts[stamp]) # 0.9344125159374457 \u5bf9\u5e942021-10-05 \u4e5f\u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u80fd\u89e3\u91ca\u4e3a\u65e5\u671f\u7684\u5b57\u7b26\u4e32\uff1a print(ts['10/9/2021']) print(ts['20211003']) \u5bf9\u4e00\u4e2a\u957f\u7684\u65f6\u95f4\u5e8f\u5217\uff0c\u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u5e74\u4efd\u6216\u4e00\u4e2a\u5e74\u4efd\u548c\u6708\u4efd\u6765\u9009\u62e9\u6570\u636e\u5207\u7247\uff1a data = np.random.randn(1000) longer_ts = pd.Series( data, index=pd.date_range('1/1/2021', periods=1000) ) print(longer_ts) # 2021-01-01 -0.009192 # 2021-01-02 -1.079068 # 2021-01-03 -1.851176 # 2021-01-04 1.347109 # 2021-01-05 -0.236394 # ... # 2023-09-23 -1.317943 # 2023-09-24 0.201741 # 2023-09-25 0.442282 # 2023-09-26 0.176137 # 2023-09-27 1.146437 # Freq: D, Length: 1000, dtype: float64 \u5b57\u7b26\u4e32\u20192001\u2019\u88ab\u89e3\u91ca\u4e3a\u4e00\u4e2a\u5e74\u4efd\uff0c\u5e76\u9009\u62e9\u4e86\u76f8\u5e94\u7684\u65f6\u95f4\u533a\u95f4\u3002 print(longer_ts['2021']) # 2021-01-01 2.170411 # 2021-01-02 1.186933 # 2021-01-03 0.399262 # 2021-01-04 -1.042606 # 2021-01-05 2.082112 # ... # 2021-12-27 -0.988282 # 2021-12-28 0.598683 # 2021-12-29 2.770580 # 2021-12-30 -1.463262 # 2021-12-31 -1.642846 # Freq: D, Length: 365, dtype: float64 \u6307\u5b9a\u4e86\u5e74\u4efd\u548c\u6708\u4efd\u4e5f\u662f\u6709\u6548\u7684\u3002 print(longer_ts['2021-10']) # 2021-10-01 0.712265 # 2021-10-02 1.195221 # 2021-10-03 -1.930220 # 2021-10-04 -0.720816 # 2021-10-05 0.081777 # 2021-10-06 -0.037466 # 2021-10-07 3.737303 # 2021-10-08 1.620383 # 2021-10-09 0.990797 # 2021-10-10 0.507850 # 2021-10-11 0.846935 # 2021-10-12 0.996947 # 2021-10-13 -1.078558 # 2021-10-14 0.871832 # 2021-10-15 -0.591698 # 2021-10-16 -0.805463 # 2021-10-17 0.160528 # 2021-10-18 -0.028474 # 2021-10-19 2.305579 # 2021-10-20 -1.132288 # 2021-10-21 0.649980 # 2021-10-22 0.615327 # 2021-10-23 0.185108 # 2021-10-24 0.857199 # 2021-10-25 -1.473752 # 2021-10-26 -0.895161 # 2021-10-27 -0.432717 # 2021-10-28 0.734504 # 2021-10-29 1.892493 # 2021-10-30 0.456619 # 2021-10-31 -0.255288 # Freq: D, dtype: float64 \u4f7f\u7528 datetime \u5bf9\u8c61\u8fdb\u884c\u5207\u7247\u4e5f\u662f\u53ef\u4ee5\u7684\uff1a print(longer_ts[datetime(2023, 1, 6):]) # 2023-01-06 0.952591 # 2023-01-07 -0.900259 # 2023-01-08 0.925332 # 2023-01-09 0.173215 # 2023-01-10 -0.507791 # ... # 2023-09-23 -0.319989 # 2023-09-24 -1.105417 # 2023-09-25 -2.118769 # 2023-09-26 0.009420 # 2023-09-27 -0.310281 # Freq: D, Length: 265, dtype: float64 \u56e0\u4e3a\u5927\u90e8\u5206\u7684\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u662f\u6309\u65f6\u95f4\u987a\u5e8f\u6392\u5e8f\u7684\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e0d\u5305\u542b\u5728\u65f6\u95f4\u5e8f\u5217\u4e2d\u7684\u65f6\u95f4\u6233\u8fdb\u884c\u5207\u7247\uff0c\u4ee5\u6267\u884c\u8303\u56f4\u67e5\u8be2\uff1a print(longer_ts['2021/10/1':'2021/10/5']) # 2021-10-01 -0.591853 # 2021-10-02 -1.554564 # 2021-10-03 -0.712585 # 2021-10-04 -0.326657 # 2021-10-05 1.044887 # Freq: D, dtype: float64 \u4f7f\u7528 truncate \u5728\u4e24\u4e2a\u65e5\u671f\u95f4\u5bf9Series\u8fdb\u884c\u5207\u7247\uff1a print(longer_ts.truncate(after='2021/10/1')) # 2021-01-01 -0.906685 # 2021-01-02 -0.470732 # 2021-01-03 -0.041316 # 2021-01-04 -0.287356 # 2021-01-05 0.104268 # ... # 2021-09-27 -0.669198 # 2021-09-28 -2.222169 # 2021-09-29 -0.653814 # 2021-09-30 -0.625868 # 2021-10-01 0.872684 # Freq: D, Length: 274, dtype: float64 \u4e0a\u9762\u8fd9\u4e9b\u64cd\u4f5c\u4e5f\u90fd\u9002\u7528\u4e8eDataFrame\uff0c\u5e76\u5728\u5176\u884c\u4e0a\u8fdb\u884c\u7d22\u5f15\uff1a dates = pd.date_range('10/1/2020', periods=100, freq='W-WED') data = np.random.randn(100, 4) long_df = pd.DataFrame( data, index=dates, columns=['Colorado', 'Texas', 'New York', 'Ohio'] ) print(long_df) # Colorado Texas New York Ohio # 2020-10-07 -1.186789 2.020634 0.300076 -0.955234 # 2020-10-14 1.502838 0.965368 -0.797539 -0.292833 # ... ... ... ... ... # 2022-08-24 -0.253116 -0.263307 0.602425 0.370599 # 2022-08-31 0.907918 0.091939 0.789694 2.781535 # [100 rows x 4 columns] print(long_df.loc['10-2020']) # Colorado Texas New York Ohio # 2020-10-07 1.031616 -1.812038 -0.446577 0.395656 # 2020-10-14 -0.673167 0.198804 -0.439141 0.086004 # 2020-10-21 -1.139786 0.716820 0.006516 -0.284335 # 2020-10-28 -0.637939 1.647810 -0.750786 0.140637 \u542b\u6709\u91cd\u590d\u7d22\u5f15\u7684\u65f6\u95f4\u5e8f\u5217 \u00b6 \u5728\u67d0\u4e9b\u5e94\u7528\u4e2d\uff0c\u53ef\u80fd\u4f1a\u6709\u591a\u4e2a\u6570\u636e\u89c2\u5bdf\u503c\u843d\u5728\u7279\u5b9a\u7684\u65f6\u95f4\u6233\u4e0a\u3002\u4e0b\u9762\u662f\u4e2a\u4f8b\u5b50\uff1a dates = pd.DatetimeIndex( ['2021/1/1', '2021/1/2', '2021/1/2', '2021/1/2', '2021/1/3'] ) dup_ts = pd.Series( np.arange(5), index=dates ) print(dup_ts) # 2021-01-01 0 # 2021-01-02 1 # 2021-01-02 2 # 2021-01-02 3 # 2021-01-03 4 # dtype: int64 \u901a\u8fc7\u68c0\u67e5\u7d22\u5f15\u7684 is_unique \u5c5e\u6027\uff0c\u53ef\u4ee5\u770b\u51fa\u7d22\u5f15\u5e76\u4e0d\u662f\u552f\u4e00\u7684\uff1a print(dup_ts.index.is_unique) # False \u5bf9\u4e0a\u9762\u7684Series\u8fdb\u884c\u7d22\u5f15\uff0c\u7ed3\u679c\u662f\u6807\u91cf\u503c\u8fd8\u662fSeries\u5207\u7247\u53d6\u51b3\u4e8e\u662f\u5426\u6709\u65f6\u95f4\u6233\u662f\u91cd\u590d\u7684\uff1a result = dup_ts['2021/1/3'] print(result) # 4 result = dup_ts['2021/1/2'] print(result) # 2021-01-02 1 # 2021-01-02 2 # 2021-01-02 3 # dtype: int64 \u5047\u8bbe\u60f3\u8981\u805a\u5408\u542b\u6709\u975e\u552f\u4e00\u65f6\u95f4\u6233\u7684\u6570\u636e\u3002\u4e00\u79cd\u65b9\u5f0f\u5c31\u662f\u4f7f\u7528 groupby \u5e76\u4f20\u9012 level=0 \uff1a grouped = dup_ts.groupby(level=0) result = grouped.mean() print(result) # 2021-01-01 0.0 # 2021-01-02 2.0 # 2021-01-03 4.0 # dtype: float64 result = grouped.count() print(result) # 2021-01-01 1 # 2021-01-02 3 # 2021-01-03 1 # dtype: int64 \u65e5\u671f\u8303\u56f4\u3001\u9891\u7387\u548c\u79fb\u4f4d \u00b6 from datetime import datetime, timedelta import pandas as pd import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd pandas\u7684\u901a\u7528\u65f6\u95f4\u5e8f\u5217\u662f\u4e0d\u89c4\u5219\u7684\uff0c\u5373\u65f6\u95f4\u5e8f\u5217\u7684\u9891\u7387\u4e0d\u662f\u56fa\u5b9a\u7684\u3002 \u4f46\u6709\u65f6\u9700\u8981\u5904\u7406\u56fa\u5b9a\u9891\u7387\u7684\u573a\u666f\uff0c\u4f8b\u5982\u6bcf\u65e5\u7684\u3001\u6bcf\u6708\u7684\u6216\u6bcf15\u5206\u949f\u7684\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u3002 \u53ef\u4ee5\u901a\u8fc7\u8c03\u7528resample\u65b9\u6cd5\u5c06\u6837\u672c\u65f6\u95f4\u5e8f\u5217\u8f6c\u6362\u4e3a\u56fa\u5b9a\u7684\u6bcf\u65e5\u9891\u7387\u6570\u636e\u3002 \u5728\u9891\u7387\u95f4\u8f6c\u6362\uff0c\u53c8\u79f0\u4e3a\u91cd\u65b0\u91c7\u6837\u3002 dates = [ datetime(2021, 10, 1), datetime(2021, 10, 3), datetime(2021, 10, 5), datetime(2021, 10, 7), datetime(2021, 10, 9), datetime(2021, 10, 11) ] data = np.random.rand(6) ts = pd.Series(data, index=dates) print(ts) # 2021-10-01 0.956685 # 2021-10-03 0.817168 # 2021-10-05 0.275543 # 2021-10-07 0.614226 # 2021-10-09 0.061377 # 2021-10-11 0.357080 # dtype: float64 resampler = ts.resample('D') # \u5b57\u7b26\u4e32\u2019D\u2019\u88ab\u89e3\u91ca\u4e3a\u6bcf\u65e5\u9891\u7387 print(resampler) # DatetimeIndexResampler [freq=, axis=0, closed=left, label=left, convention=start, origin=start_day] \u751f\u6210\u65e5\u671f\u8303\u56f4 \u00b6 pandas.date_range \u662f\u7528\u4e8e\u6839\u636e\u7279\u5b9a\u9891\u7387\u751f\u6210\u6307\u5b9a\u957f\u5ea6\u7684 DatetimeIndex \u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c date_range \u751f\u6210\u7684\u662f\u6bcf\u65e5\u7684\u65f6\u95f4\u6233\u3002\u5982\u679c\u53ea\u4f20\u9012\u4e00\u4e2a\u8d77\u59cb\u6216\u7ed3\u5c3e\u65e5\u671f\uff0c\u4f60\u5fc5\u987b\u4f20\u9012\u4e00\u4e2a\u7528\u4e8e\u751f\u6210\u8303\u56f4\u7684\u6570\u5b57\u3002 \u5f00\u59cb\u65e5\u671f\u548c\u7ed3\u675f\u65e5\u671f\u4e25\u683c\u5b9a\u4e49\u4e86\u751f\u6210\u65e5\u671f\u7d22\u5f15\u7684\u8fb9\u754c\u3002 index = pd.date_range('2021/1/1', '2021/1/30') print(index) index = pd.date_range(start='2021/1/1', periods=30) print(index) index = pd.date_range(end='2021/1/30', periods=30) print(index) # DatetimeIndex(['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', # '2021-01-05', '2021-01-06', '2021-01-07', '2021-01-08', # '2021-01-09', '2021-01-10', '2021-01-11', '2021-01-12', # '2021-01-13', '2021-01-14', '2021-01-15', '2021-01-16', # '2021-01-17', '2021-01-18', '2021-01-19', '2021-01-20', # '2021-01-21', '2021-01-22', '2021-01-23', '2021-01-24', # '2021-01-25', '2021-01-26', '2021-01-27', '2021-01-28', # '2021-01-29', '2021-01-30'], # dtype='datetime64[ns]', freq='D') \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c date_range \u4fdd\u7559\u5f00\u59cb\u6216\u7ed3\u675f\u65f6\u95f4\u6233\u7684\u65f6\u95f4\uff08\u5982\u679c\u6709\u7684\u8bdd\uff09\u3002 normalize \u9009\u9879\u53ef\u4ee5\u5b9e\u73b0\u751f\u6210\u7684\u662f\u6807\u51c6\u5316\u4e3a\u96f6\u70b9\u7684\u65f6\u95f4\u6233\u3002 index = pd.date_range('2021/1/1 12:56:30', periods=5) print(index) # DatetimeIndex(['2021-01-01 12:56:30', '2021-01-02 12:56:30', # '2021-01-03 12:56:30', '2021-01-04 12:56:30', # '2021-01-05 12:56:30'], # dtype='datetime64[ns]', freq='D') index = pd.date_range('2021/1/1 12:56:30', periods=5, normalize=True) print(index) # DatetimeIndex(['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', # '2021-01-05'], # dtype='datetime64[ns]', freq='D') Pandas\u65f6\u95f4\u5e8f\u5217\uff1a\u9891\u7387\u548c\u65e5\u671f\u504f\u79fb\u91cf\u3002 pandas\u4e2d\u7684\u9891\u7387\u662f\u7531\u4e00\u4e2a\u57fa\u7840\u9891\u7387(\u4f8b\u5982\u201c\u65e5\u201d\u3001\u201c\u6708\u201d)\u548c\u4e00\u4e2a\u4e58\u6570\u7ec4\u6210\u3002 \u57fa\u7840\u9891\u7387\u901a\u5e38\u4ee5\u4e00\u4e2a\u5b57\u7b26\u4e32\u522b\u540d\u8868\u793a\uff0c\u6bd4\u5982\u201cD\u201d\u8868\u793a\u65e5\uff0c\u201cM\u201d\u8868\u793a\u6708\u3002 \u5bf9\u4e8e\u6bcf\u4e2a\u57fa\u7840\u9891\u7387\uff0c\u90fd\u6709\u4e00\u4e2a\u88ab\u79f0\u4e3a\u65e5\u671f\u504f\u79fb\u91cf(dateoffset)\u7684\u5bf9\u8c61\u4e0e\u4e4b\u5bf9\u5e94\uff0c\u6bd4\u5982\u65e5\u671f\u504f\u79fb\u91cf Hour \u5bf9\u5e94\u7684\u9891\u7387\u662f H \u3002 \u5e38\u7528\u9891\u7387\u4e0e\u65e5\u671f\u504f\u79fb\u91cf\u3002 \u9891\u7387 \u65e5\u671f\u504f\u79fb\u91cf \u8bf4\u660e D Day \u65e5\u5386\u65e5 B BusinessDay \u5de5\u4f5c\u65e5 H Hour \u5c0f\u65f6 T/min Minute \u5206 S Second \u79d2 L/ms Milli \u6beb\u79d2 U Micro \u5fae\u79d2 M MonthEnd \u6bcf\u6708\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5 BM BusinessMonthEnd \u6bcf\u6708\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5 MS MonthBegin \u6bcf\u6708\u7b2c\u4e00\u4e2a\u65e5\u5386\u65e5 BMS BussinessMonthBegin \u6bcf\u6708\u7b2c\u4e00\u4e2a\u5de5\u4f5c\u65e5 W-MON, W-TUE, ... Week \u6307\u5b9a\u661f\u671f\u51e0(MON,TUE,WED,THU,FRI,SAT,SUN) WOM-1MON,WOM-2MON, ... WeekOfMonth \u4ea7\u751f\u6bcf\u6708\u7b2c\u4e00,\u7b2c\u4e8c,\u7b2c\u4e09\u6216\u7b2c\u56db\u5468\u7684\u661f\u671f\u51e0\u3002\u4f8b\u5982WOM-3FRI\u8868\u793a\u6bcf\u6708\u7b2c3\u4e2a\u661f\u671f\u4e94 Q-JAN,Q-FEB, ... QuarterEnd \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5 BQ-JAN,BQ-FEB, ... BusinessQuarterEnd \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5 QS-JAN,QS-FEB, ... QuarterBegin \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u7b2c\u4e00\u4e2a\u65e5\u5386\u65e5 BQS-JAN,BQS-FEB, ... BusinessQuarterBegin \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u7b2c\u4e00\u4e2a\u5de5\u4f5c\u65e5 A-JAN,A-FEB, ... YearEnd \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5 BA-JAN,BA-FEB, ... BusinessYearEnd \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5 AS-JAN,AS-FEB, ... YearBegin \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u7b2c\u4e00\u4e2a\u65e5\u5386\u65e5 BAS-JAN,BAS-FEB, ... BusinessYearBegin \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u7b2c\u4e00\u4e2a\u5de5\u4f5c\u65e5 \u9891\u7387\u548c\u65e5\u671f\u504f\u7f6e \u00b6 pandas\u4e2d\u7684\u9891\u7387\u662f\u7531\u57fa\u7840\u9891\u7387\u548c\u500d\u6570\u7ec4\u6210\u7684\u3002 \u57fa\u7840\u9891\u7387\u901a\u5e38\u4f1a\u6709\u5b57\u7b26\u4e32\u522b\u540d\uff0c\u4f8b\u5982 M \u4ee3\u8868\u6bcf\u6708\uff0c H \u4ee3\u8868\u6bcf\u5c0f\u65f6\u3002 \u5bf9\u4e8e\u6bcf\u4e2a\u57fa\u7840\u9891\u7387\uff0c\u90fd\u6709\u4e00\u4e2a\u5bf9\u8c61\u53ef\u4ee5\u88ab\u7528\u4e8e\u5b9a\u4e49\u65e5\u671f\u504f\u7f6e\u3002 \u4f8b\u5982\uff0c\u6bcf\u5c0f\u65f6\u7684\u9891\u7387\u53ef\u4ee5\u4f7f\u7528 Hour \u7c7b\u6765\u8868\u793a\uff1a ```hour = Hour() print(hour) \u00b6 \u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u6574\u6570\u6765\u5b9a\u4e49\u504f\u7f6e\u91cf\u7684\u500d\u6570\uff1a four_hours = Hour(4) print(four_hours) <4 * Hours> \u00b6 \u5728\u5927\u591a\u6570\u5e94\u7528\u4e2d\uff0c\u4e0d\u9700\u8981\u663e\u5f0f\u5730\u521b\u5efa\u8fd9\u4e9b\u5bf9\u8c61\uff0c\u800c\u662f\u4f7f\u7528\u5b57\u7b26\u4e32\u522b\u540d\uff0c\u5982`H`\u6216`4H`\u3002\u5728\u57fa\u7840\u9891\u7387\u524d\u653e\u4e00\u4e2a\u6574\u6570\u5c31\u53ef\u4ee5\u751f\u6210\u500d\u6570\uff1a ts = pd.date_range('2021/1/1', '2021/\u00bd 23:59', freq='4h') print(ts) DatetimeIndex(['2021-01-01 00:00:00', '2021-01-01 04:00:00', \u00b6 '2021-01-01 08:00:00', '2021-01-01 12:00:00', \u00b6 '2021-01-01 16:00:00', '2021-01-01 20:00:00', \u00b6 '2021-01-02 00:00:00', '2021-01-02 04:00:00', \u00b6 '2021-01-02 08:00:00', '2021-01-02 12:00:00', \u00b6 '2021-01-02 16:00:00', '2021-01-02 20:00:00'], \u00b6 dtype='datetime64[ns]', freq='4H') \u00b6 \u591a\u4e2a\u504f\u7f6e\u53ef\u4ee5\u901a\u8fc7\u52a0\u6cd5\u8fdb\u884c\u8054\u5408\uff1a print(Hour(2) + Minute(30)) <150 * Minutes> \u00b6 \u7c7b\u4f3c\u5730\uff0c\u53ef\u4ee5\u4f20\u9012\u9891\u7387\u5b57\u7b26\u4e32\uff1a ts = pd.date_range('2021/1/1', '2021/1/1 23:59', freq='4h30min') print(ts) DatetimeIndex(['2021-01-01 00:00:00', '2021-01-01 04:30:00', \u00b6 '2021-01-01 09:00:00', '2021-01-01 13:30:00', \u00b6 '2021-01-01 18:00:00', '2021-01-01 22:30:00'], \u00b6 dtype='datetime64[ns]', freq='270T') \u00b6 \u6709\u4e9b\u9891\u7387\u63cf\u8ff0\u70b9\u7684\u65f6\u95f4\u5e76\u4e0d\u662f\u5747\u5300\u5206\u9694\u7684\u3002\u4f8b\u5982\uff0c`M`\uff08\u65e5\u5386\u6708\u672b\uff09\u548c`BM`\uff08\u6708\u5185\u6700\u540e\u5de5\u4f5c\u65e5\uff09\u53d6\u51b3\u4e8e\u5f53\u6708\u5929\u6570\uff0c\u6708\u672b\u662f\u5426\u662f\u5468\u672b\u3002\u6211\u4eec\u5c06\u8fd9\u4e9b\u65e5\u671f\u79f0\u4e3a\u951a\u5b9a\u504f\u7f6e\u91cf\u3002 #### \u6708\u4e2d\u67d0\u661f\u671f\u7684\u65e5\u671f \"\u6708\u4e2d\u67d0\u661f\u671f\"\uff08week of month \uff09\u7684\u65e5\u671f\u662f\u4e00\u4e2a\u6709\u7528\u7684\u9891\u7387\u7c7b\uff0c\u4ee5`WOM`\u5f00\u59cb\u3002 rng = pd.date_range('2021-1-1', '2021-9-1', freq='WOM-3FRI') # \u6bcf\u6708\u7b2c\u4e09\u4e2a\u661f\u671f\u4e94 print(rng) DatetimeIndex(['2021-01-15', '2021-02-19', '2021-03-19', '2021-04-16', \u00b6 '2021-05-21', '2021-06-18', '2021-07-16', '2021-08-20'], \u00b6 dtype='datetime64[ns]', freq='WOM-3FRI') \u00b6 ### \u79fb\u4f4d\uff08\u524d\u5411\u548c\u540e\u5411\uff09\u65e5\u671f \"\u79fb\u4f4d\"\u662f\u6307\u5c06\u65e5\u671f\u6309\u65f6\u95f4\u5411\u524d\u79fb\u52a8\u6216\u5411\u540e\u79fb\u52a8\u3002 Series\u548cDataFrame\u90fd\u6709\u4e00\u4e2a`shift`\u65b9\u6cd5\u7528\u4e8e\u8fdb\u884c\u7b80\u5355\u7684\u524d\u5411\u6216\u540e\u5411\u79fb\u4f4d\uff0c\u800c\u4e0d\u6539\u53d8\u7d22\u5f15\u3002 \u8fdb\u884c\u79fb\u4f4d\u65f6\uff0c\u4f1a\u5728\u65f6\u95f4\u5e8f\u5217\u7684\u8d77\u59cb\u4f4d\u6216\u7ed3\u675f\u4f4d\u5f15\u5165\u7f3a\u5931\u503c\u3002 data = [0.882972, 1.363282, -0.687750, -0.048117] ts = pd.Series(data, index=pd.date_range('2021-1-1', periods=4, freq='M')) print(ts) 2021-01-31 0.882972 \u00b6 2021-02-28 1.363282 \u00b6 2021-03-31 -0.687750 \u00b6 2021-04-30 -0.048117 \u00b6 Freq: M, dtype: float64 \u00b6 print(ts.shift(2)) 2021-01-31 NaN \u00b6 2021-02-28 NaN \u00b6 2021-03-31 0.882972 \u00b6 2021-04-30 1.363282 \u00b6 Freq: M, dtype: float64 \u00b6 print(ts.shift(-2)) 2021-01-31 -0.687750 \u00b6 2021-02-28 -0.048117 \u00b6 2021-03-31 NaN \u00b6 2021-04-30 NaN \u00b6 Freq: M, dtype: float64 \u00b6 `shift`\u5e38\u7528\u4e8e\u8ba1\u7b97\u65f6\u95f4\u5e8f\u5217\u6216DataFrame\u591a\u5217\u65f6\u95f4\u5e8f\u5217\u7684\u767e\u5206\u6bd4\u53d8\u5316\uff1a print(ts/ts.shift(1)) 2021-01-31 NaN \u00b6 2021-02-28 1.543970 \u00b6 2021-03-31 -0.504481 \u00b6 2021-04-30 0.069963 \u00b6 Freq: M, dtype: float64 \u00b6 print(ts/ts.shift(1) - 1) 2021-01-31 NaN \u00b6 2021-02-28 0.543970 \u00b6 2021-03-31 -1.504481 \u00b6 2021-04-30 -0.930037 \u00b6 Freq: M, dtype: float64 \u00b6 \u5982\u679c\u9891\u7387\u662f\u5df2\u77e5\u7684\uff0c\u5219\u53ef\u4ee5\u5c06\u9891\u7387\u4f20\u9012\u7ed9`shift`\u6765\u63a8\u79fb\u65f6\u95f4\u6233\uff1a print(ts.shift(2, freq='M')) # \u539f\u59cb\u6570\u636e\u7684\u201c\u6708\u201c\u589e\u52a0\u4e86\u504f\u79fb\u503c 2021-03-31 0.882972 \u00b6 2022021-10-31 00:00:001-04-30 1.363282 \u00b6 2021-05-31 -0.687750 \u00b6 2021-06-30 -0.048117 \u00b6 Freq: M, dtype: float64 \u00b6 print(ts.shift(2, freq='D')) # \u539f\u59cb\u6570\u636e\u7684\u201c\u65e5\u201c\u589e\u52a0\u4e86\u504f\u79fb\u503c 2021-02-02 0.882972 \u00b6 2021-03-02 1.363282 \u00b6 2021-04-02 -0.687750 \u00b6 2021-05-02 -0.048117 \u00b6 dtype: float64 \u00b6 print(ts.shift(2, freq='90T')) # \u539f\u59cb\u6570\u636e\u7684\u201c\u5c0f\u65f6\u201c\u589e\u52a0\u4e86\u504f\u79fb\u503c 2021-01-31 03:00:00 0.882972 \u00b6 2021-02-28 03:00:00 1.363282 \u00b6 2021-03-31 03:00:00 -0.687750 \u00b6 2021-04-30 03:00:00 -0.048117 \u00b6 dtype: float64 \u00b6 #### \u4f7f\u7528\u504f\u7f6e\u8fdb\u884c\u79fb\u4f4d\u65e5\u671f pandas\u65e5\u671f\u504f\u7f6e\u4e5f\u53ef\u4ee5\u4f7f\u7528`datetime`\u6216`Timestamp`\u5bf9\u8c61\u5b8c\u6210\uff1a now = datetime(2021, 10, 9) print(now) 2021-10-09 00:00:00 \u00b6 print(now + 3 * Day()) 2021-10-12 00:00:00 \u00b6 \u951a\u5b9a\u504f\u7f6e\u53ef\u4ee5\u4f7f\u7528`rollforward`\u548c`rollback`\u5206\u522b\u663e\u5f0f\u5730\u5c06\u65e5\u671f\u5411\u524d\u6216\u5411\u540e\"\u6eda\u52a8\"\u3002 \u5982\u679c\u6dfb\u52a0\u4e86\u4e00\u4e2a\u951a\u5b9a\u504f\u7f6e\u91cf\uff0c\u6bd4\u5982`MonthEnd`\uff0c\u6839\u636e\u9891\u7387\u89c4\u5219\uff0c\u7b2c\u4e00\u4e2a\u589e\u91cf\u4f1a\u5c06\u65e5\u671f\u201c\u524d\u6eda\u201d\u5230\u4e0b\u4e00\u4e2a\u65e5\u671f\uff1a print(now + MonthEnd()) # \u201c\u524d\u6eda\u201d\u5230\u5f53\u524d\u6708\u7684\u6708\u5e95 2021-10-31 00:00:00 \u00b6 print(now + MonthEnd(2)) # \u6ce8\u610f\u8fd9\u91cc\u7684\u5e8f\u5217\u53f7\uff0c\u5f53\u524d\u6708\u662f1,\u4e0b\u4e2a\u6708\u662f2 2021-11-30 00:00:00 \u00b6 offset = MonthEnd() print(offset.rollback(now)) 2021-09-30 00:00:00 \u00b6 print(offset.rollforward(now)) 2021-10-31 00:00:00 \u00b6 \u5c06\u79fb\u4f4d\u65b9\u6cd5\u4e0e`groupby`\u4e00\u8d77\u4f7f\u7528\u662f\u65e5\u671f\u504f\u7f6e\u7684\u4e00\u79cd\u521b\u9020\u6027\u7528\u6cd5\uff1a ts = pd.Series( np.random.randn(20), index=pd.date_range('2021/1/1', periods=20, freq='4d') ) print(ts) 2021-01-01 0.674348 \u00b6 2021-01-05 -1.437803 \u00b6 2021-01-09 -0.079218 \u00b6 2021-01-13 -1.444890 \u00b6 2021-01-17 0.643279 \u00b6 2021-01-21 1.089965 \u00b6 2021-01-25 0.021876 \u00b6 2021-01-29 0.692138 \u00b6 2021-02-02 0.833496 \u00b6 2021-02-06 1.082616 \u00b6 2021-02-10 -0.729415 \u00b6 2021-02-14 0.271186 \u00b6 2021-02-18 -1.416218 \u00b6 2021-02-22 -0.780402 \u00b6 2021-02-26 -0.113773 \u00b6 2021-03-02 2.095338 \u00b6 2021-03-06 -0.302612 \u00b6 2021-03-10 1.113632 \u00b6 2021-03-14 -1.314581 \u00b6 2021-03-18 0.947746 \u00b6 Freq: 4D, dtype: float64 \u00b6 print(ts.groupby(offset.rollforward).mean()) # \u524d\u6eda\u81f3\u5f53\u6708\u6708\u5e95\uff0c\u8ba1\u7b97\u5f53\u6708\u5e73\u5747\u503c 2021-01-31 0.019962 \u00b6 2021-02-28 -0.121787 \u00b6 2021-03-31 0.507905 \u00b6 dtype: float64 \u00b6 \u4f7f\u7528resample\u662f\u66f4\u7b80\u5355\u66f4\u5feb\u6377\u7684\u65b9\u6cd5 \u00b6 print(ts.resample('M').mean()) 2021-01-31 0.019962 \u00b6 2021-02-28 -0.121787 \u00b6 2021-03-31 0.507905 \u00b6 Freq: M, dtype: float64 \u00b6 ## \u65f6\u533a\u5904\u7406 \u65f6\u533a\u901a\u5e38\u88ab\u8868\u793a\u4e3aUTC\u7684\u504f\u7f6e\u3002 \u5728Python\u8bed\u8a00\u4e2d\uff0c\u65f6\u533a\u4fe1\u606f\u6765\u6e90\u4e8e\u7b2c\u4e09\u65b9\u5e93pytz\uff08\u53ef\u4ee5\u4f7f\u7528pip\u6216conda\u5b89\u88c5\uff09\uff0c\u5176\u4e2d\u516c\u5f00\u4e86Olson\u6570\u636e\u5e93\uff0c\u8fd9\u662f\u4e16\u754c\u65f6\u533a\u4fe1\u606f\u7684\u6c47\u7f16\u3002 pandas\u5c01\u88c5\u4e86pytz\u7684\u529f\u80fd\u3002 from datetime import datetime, timedelta import pandas as pd import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd import pytz #### common_timezones tz = pytz.common_timezones[-5:] # \u8bfb\u53d6common_timezones\u8fd9\u4e2a\u5217\u8868\u7684\u6700\u540e5\u4e2a\u5143\u7d20 print(tz) ['US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC'] \u00b6 \u8981\u83b7\u5f97pytz\u7684\u65f6\u533a\u5bf9\u8c61\uff0c\u53ef\u4f7f\u7528pytz.timezone\uff1a tz = pytz.timezone('Asia/Shanghai') print(tz) #### \u65f6\u533a\u7684\u672c\u5730\u5316\u548c\u8f6c\u6362 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cpandas\u4e2d\u7684\u65f6\u95f4\u5e8f\u5217\u662f\u65f6\u533a\u7b80\u5355\u578b\u7684\u3002 rng = pd.date_range('2021/1/1 9:30', periods=6, freq='D') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(rng) DatetimeIndex(['2021-01-01 09:30:00', '2021-01-02 09:30:00', \u00b6 '2021-01-03 09:30:00', '2021-01-04 09:30:00', \u00b6 '2021-01-05 09:30:00', '2021-01-06 09:30:00'], \u00b6 dtype='datetime64[ns]', freq='D') \u00b6 print(ts) 2021-01-01 09:30:00 0.339822 \u00b6 2021-01-02 09:30:00 1.356382 \u00b6 2021-01-03 09:30:00 0.475429 \u00b6 2021-01-04 09:30:00 1.826654 \u00b6 2021-01-05 09:30:00 -0.245510 \u00b6 2021-01-06 09:30:00 0.705274 \u00b6 Freq: D, dtype: float64 \u00b6 print(ts.index.tz) # \u7d22\u5f15\u7684tz\u5c5e\u6027\u662fNone None \u00b6 \u65e5\u671f\u8303\u56f4\u53ef\u4ee5\u901a\u8fc7\u65f6\u533a\u96c6\u5408\u6765\u751f\u6210\uff1a rng = pd.date_range('2021/3/1', periods=10, freq='D', tz='UTC') print(rng) DatetimeIndex(['2021-03-01 00:00:00+00:00', '2021-03-02 00:00:00+00:00', \u00b6 '2021-03-03 00:00:00+00:00', '2021-03-04 00:00:00+00:00', \u00b6 '2021-03-05 00:00:00+00:00', '2021-03-06 00:00:00+00:00', \u00b6 '2021-03-07 00:00:00+00:00', '2021-03-08 00:00:00+00:00', \u00b6 '2021-03-09 00:00:00+00:00', '2021-03-10 00:00:00+00:00'], \u00b6 dtype='datetime64[ns, UTC]', freq='D') \u00b6 \u4f7f\u7528`tz_localize`\u65b9\u6cd5\u53ef\u4ee5\u4ece\u7b80\u5355\u65f6\u533a\u8f6c\u6362\u5230\u672c\u5730\u5316\u65f6\u533a\uff1a print(ts) 2021-01-01 09:30:00 0.294647 \u00b6 2021-01-02 09:30:00 0.958414 \u00b6 2021-01-03 09:30:00 0.424235 \u00b6 2021-01-04 09:30:00 -1.714333 \u00b6 2021-01-05 09:30:00 -0.030319 \u00b6 2021-01-06 09:30:00 -0.744940 \u00b6 Freq: D, dtype: float64 \u00b6 print(ts.tz_localize('UTC')) 2021-01-01 09:30:00+00:00 0.294647 \u00b6 2021-01-02 09:30:00+00:00 0.958414 \u00b6 2021-01-03 09:30:00+00:00 0.424235 \u00b6 2021-01-04 09:30:00+00:00 -1.714333 \u00b6 2021-01-05 09:30:00+00:00 -0.030319 \u00b6 2021-01-06 09:30:00+00:00 -0.744940 \u00b6 Freq: D, dtype: float64 \u00b6 print(ts.tz_localize('Asia/Shanghai')) 2021-01-01 09:30:00+08:00 0.052521 \u00b6 2021-01-02 09:30:00+08:00 -0.305417 \u00b6 2021-01-03 09:30:00+08:00 0.150215 \u00b6 2021-01-04 09:30:00+08:00 -0.953715 \u00b6 2021-01-05 09:30:00+08:00 0.543622 \u00b6 2021-01-06 09:30:00+08:00 0.222422 \u00b6 dtype: float64 \u00b6 print(ts.tz_localize('Asia/Shanghai').index) DatetimeIndex(['2021-01-01 09:30:00+08:00', '2021-01-02 09:30:00+08:00', \u00b6 '2021-01-03 09:30:00+08:00', '2021-01-04 09:30:00+08:00', \u00b6 '2021-01-05 09:30:00+08:00', '2021-01-06 09:30:00+08:00'], \u00b6 dtype='datetime64[ns, Asia/Shanghai]', freq=None) \u00b6 \u4e00\u65e6\u65f6\u95f4\u5e8f\u5217\u88ab\u672c\u5730\u5316\u4e3a\u67d0\u4e2a\u7279\u5b9a\u7684\u65f6\u533a\uff0c\u5219\u53ef\u4ee5\u901a\u8fc7`tz_convert`\u5c06\u5176\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u65f6\u533a\uff1a tz_sha = ts.tz_localize('Asia/Shanghai') tz_utc = tz_sha.tz_convert('UTC') print(tz_sha) 2021-01-01 09:30:00+08:00 0.095689 \u00b6 2021-01-02 09:30:00+08:00 -0.392730 \u00b6 2021-01-03 09:30:00+08:00 0.151468 \u00b6 2021-01-04 09:30:00+08:00 0.027467 \u00b6 2021-01-05 09:30:00+08:00 0.393709 \u00b6 2021-01-06 09:30:00+08:00 0.872914 \u00b6 dtype: float64 \u00b6 print(tz_utc) 2021-01-01 01:30:00+00:00 0.095689 \u00b6 2021-01-02 01:30:00+00:00 -0.392730 \u00b6 2021-01-03 01:30:00+00:00 0.151468 \u00b6 2021-01-04 01:30:00+00:00 0.027467 \u00b6 2021-01-05 01:30:00+00:00 0.393709 \u00b6 2021-01-06 01:30:00+00:00 0.872914 \u00b6 dtype: float64 \u00b6 tz_localize\u548ctz_convert\u4e5f\u662fDatetimeIndex\u7684\u5b9e\u4f8b\u65b9\u6cd5\uff1a \u00b6 print(ts.index.tz_localize('Asia/Shanghai')) DatetimeIndex(['2021-01-01 09:30:00+08:00', '2021-01-02 09:30:00+08:00', \u00b6 '2021-01-03 09:30:00+08:00', '2021-01-04 09:30:00+08:00', \u00b6 '2021-01-05 09:30:00+08:00', '2021-01-06 09:30:00+08:00'], \u00b6 dtype='datetime64[ns, Asia/Shanghai]', freq=None) \u00b6 ### \u65f6\u533a\u611f\u77e5\u65f6\u95f4\u6233\u5bf9\u8c61\u7684\u64cd\u4f5c \u4e0e\u65f6\u95f4\u5e8f\u5217\u548c\u65e5\u671f\u8303\u56f4\u7c7b\u4f3c\uff0c\u5355\u72ec\u7684`Timestamp`\u5bf9\u8c61\u4e5f\u53ef\u4ee5\u4ece\u7b80\u5355\u65f6\u95f4\u6233\u672c\u5730\u5316\u4e3a\u65f6\u533a\u611f\u77e5\u65f6\u95f4\u6233\uff0c\u5e76\u4ece\u4e00\u4e2a\u65f6\u533a\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u65f6\u533a\uff1a stamp = pd.Timestamp('2021-5-1 05:30') print(stamp) 2021-05-01 05:30:00 \u00b6 stamp_utc = stamp.tz_localize('utc') print(stamp_utc) 2021-05-01 05:30:00+00:00 \u00b6 stamp_sha = stamp_utc.tz_convert('Asia/Shanghai') print(stamp_sha) 2021-05-01 13:30:00+08:00 \u00b6 \u4e5f\u53ef\u4ee5\u5728\u521b\u5efa`Timestamp`\u7684\u65f6\u5019\u4f20\u9012\u4e00\u4e2a\u65f6\u533a\uff1a stamp_sha = pd.Timestamp('2021-5-1 05:30', tz='Asia/Shanghai') print(stamp_sha) 2021-05-01 05:30:00+08:00 \u00b6 `Timestamp`\u5bf9\u8c61\u5185\u90e8\u5b58\u50a8\u4e86\u4e00\u4e2aUnix\u7eaa\u5143(1970\u5e741\u67081\u65e5)\u81f3\u4eca\u7684\u7eb3\u79d2\u6570\u91cfUTC\u65f6\u95f4\u6233\u6570\u503c\uff0c\u8be5\u6570\u503c\u5728\u65f6\u533a\u8f6c\u6362\u4e2d\u662f\u4e0d\u53d8\u7684\uff1a print(stamp_utc.value) 1619847000000000000 \u00b6 print(stamp_utc.tz_convert('Asia/Shanghai').value) 1619847000000000000 \u00b6 \u5728\u4f7f\u7528pandas\u7684`DateOffset`\u8fdb\u884c\u65f6\u95f4\u7b97\u672f\u65f6\uff0cpandas\u5c3d\u53ef\u80fd\u9075\u4ece\u590f\u65f6\u5236\u3002 \u9996\u5148\uff0c\u6784\u9020\u8f6c\u6362\u5230DST\u4e4b\u524d\u768430\u5206\u949f\u7684\u65f6\u95f4\uff1a stamp = pd.Timestamp('2012-3-12 1:30', tz='US/Eastern') print(stamp) 2012-03-12 01:30:00-04:00 \u00b6 print(stamp + Hour()) 2012-03-12 02:30:00-04:00 \u00b6 \u4e4b\u540e\uff0c\u6784\u5efa\u4eceDST\u8fdb\u884c\u8f6c\u6362\u524d\u768490\u5206\u949f\uff1a stamp = pd.Timestamp('2012-11-04 0:30-04:00', tz='US/Eastern') print(stamp) 2012-11-04 00:30:00-04:00 \u00b6 print(stamp + 2 * Hour()) # \u53ea\u589e\u52a0\u4e86\u4e00\u5c0f\u65f6 2012-11-04 01:30:00-05:00 \u00b6 ### \u4e0d\u540c\u65f6\u533a\u95f4\u7684\u64cd\u4f5c \u5982\u679c\u4e24\u4e2a\u65f6\u533a\u4e0d\u540c\u7684\u65f6\u95f4\u5e8f\u5217\u9700\u8981\u8054\u5408\uff0c\u90a3\u4e48\u7ed3\u679c\u5c06\u662fUTC\u65f6\u95f4\u7684\uff0c\u56e0\u4e3a\u65f6\u95f4\u6233\u4ee5UTC\u683c\u5f0f\u5b58\u50a8\u3002 rng = pd.date_range('2021/1/1 9:30', periods=9, freq='B') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(ts) 2021-01-01 09:30:00 0.715681 \u00b6 2021-01-04 09:30:00 0.524563 \u00b6 2021-01-05 09:30:00 -0.482199 \u00b6 2021-01-06 09:30:00 -0.661303 \u00b6 2021-01-07 09:30:00 1.750010 \u00b6 2021-01-08 09:30:00 0.251478 \u00b6 2021-01-11 09:30:00 -1.487268 \u00b6 2021-01-12 09:30:00 -0.224024 \u00b6 2021-01-13 09:30:00 -1.621853 \u00b6 Freq: B, dtype: float64 \u00b6 ts1 = ts[:7].tz_localize('Europe/London') ts2 = ts1[2:].tz_convert('Europe/Moscow') result = ts1 + ts2 print(ts1) 2021-01-01 09:30:00+00:00 -1.393445 \u00b6 2021-01-04 09:30:00+00:00 -1.179614 \u00b6 2021-01-05 09:30:00+00:00 0.716669 \u00b6 2021-01-06 09:30:00+00:00 -0.485656 \u00b6 2021-01-07 09:30:00+00:00 0.433000 \u00b6 2021-01-08 09:30:00+00:00 1.540745 \u00b6 2021-01-11 09:30:00+00:00 0.343751 \u00b6 dtype: float64 \u00b6 print(ts2) 2021-01-05 12:30:00+03:00 0.716669 \u00b6 2021-01-06 12:30:00+03:00 -0.485656 \u00b6 2021-01-07 12:30:00+03:00 0.433000 \u00b6 2021-01-08 12:30:00+03:00 1.540745 \u00b6 2021-01-11 12:30:00+03:00 0.343751 \u00b6 dtype: float64 \u00b6 print(result) 2021-01-01 09:30:00+00:00 NaN \u00b6 2021-01-04 09:30:00+00:00 NaN \u00b6 2021-01-05 09:30:00+00:00 1.433337 \u00b6 2021-01-06 09:30:00+00:00 -0.971312 \u00b6 2021-01-07 09:30:00+00:00 0.866000 \u00b6 2021-01-08 09:30:00+00:00 3.081489 \u00b6 2021-01-11 09:30:00+00:00 0.687502 \u00b6 dtype: float64 \u00b6 ## \u65f6\u95f4\u533a\u95f4\u548c\u533a\u95f4\u7b97\u672f from datetime import datetime, timedelta import pandas as pd import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd import pytz \u65f6\u95f4\u533a\u95f4\u8868\u793a\u7684\u662f\u65f6\u95f4\u8303\u56f4\u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628a`year`\u548c`quarter`\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f15\uff0c\u6bd4\u5982\u4e00\u4e9b\u5929\u3001\u4e00\u4e9b\u6708\u3001\u4e00\u4e9b\u5b63\u5ea6\u6216\u8005\u662f\u4e00\u4e9b\u5e74\u3002 `Period`\u7c7b\u8868\u793a\u7684\u6b63\u662f\u8fd9\u79cd\u6570\u636e\u7c7b\u578b\uff0c\u9700\u8981\u4e00\u4e2a\u5b57\u7b26\u4e32\u6216\u6570\u5b57\u4ee5\u53ca\u9891\u7387\u3002 \u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c`Period`\u5bf9\u8c61\u8868\u793a\u7684\u662f\u4ece2007\u5e741\u67081\u65e5\u52302007\u5e7412\u670831\u65e5\uff08\u5305\u542b\u5728\u5185\uff09\u7684\u65f6\u95f4\u6bb5\u3002 \u5728\u65f6\u95f4\u6bb5\u4e0a\u589e\u52a0\u6216\u51cf\u53bb\u6574\u6570\u53ef\u4ee5\u65b9\u4fbf\u5730\u6839\u636e\u5b83\u4eec\u7684\u9891\u7387\u8fdb\u884c\u79fb\u4f4d\u3002 p = pd.Period(2020, freq='A-DEC') print(p) 2020 \u00b6 print(p + 5) 2025 \u00b6 print(p - 5) 2015 \u00b6 \u5982\u679c\u4e24\u4e2a\u533a\u95f4\u62e5\u6709\u76f8\u540c\u7684\u9891\u7387\uff0c\u5219\u5b83\u4eec\u7684\u5dee\u662f\u5b83\u4eec\u4e4b\u95f4\u7684\u5355\u4f4d\u6570\u3002 p1 = pd.Period(2020, freq='A-DEC') p2 = pd.Period(2010, freq='A-DEC') print(p1 - p2) <10 * YearEnds: month=12> \u00b6 p1 = pd.Period(2020, freq='Q-DEC') p2 = pd.Period(2010, freq='Q-DEC') print(p1 - p2) <40 * QuarterEnds: startingMonth=12> \u00b6 \u4f7f\u7528`period_range`\u51fd\u6570\u53ef\u4ee5\u6784\u9020\u89c4\u5219\u533a\u95f4\u5e8f\u5217\u3002`PeriodIndex`\u7c7b\u5b58\u50a8\u7684\u662f\u533a\u95f4\u7684\u5e8f\u5217\uff0c\u53ef\u4ee5\u4f5c\u4e3a\u4efb\u610fpandas\u6570\u636e\u7ed3\u6784\u7684\u8f74\u7d22\u5f15\u3002 data = np.random.randn(6) strings = ['2021Q1', '2021Q2', '2021Q3', '2021Q4', '2022Q1', '2022Q2'] rng = pd.period_range('2001-1-1', '2001-6-30', freq='M') ts = pd.Series(data, index=rng) print(ts) 2001-01 -0.481408 \u00b6 2001-02 -0.297590 \u00b6 2001-03 -0.860354 \u00b6 2001-04 1.281540 \u00b6 2001-05 1.036551 \u00b6 2001-06 -0.522592 \u00b6 Freq: M, dtype: float64 \u00b6 rng = pd.PeriodIndex(strings, freq='Q-DEC') # \u5b57\u7b26\u4e32\u6570\u7ec4\u4e5f\u53ef\u4ee5\u4f7f\u7528PeriodIndex\u7c7b ts = pd.Series(data, index=rng) print(ts) 2021Q1 -2.077200 \u00b6 2021Q2 -0.948796 \u00b6 2021Q3 -1.104737 \u00b6 2021Q4 0.090281 \u00b6 2022Q1 0.431517 \u00b6 2022Q2 1.537045 \u00b6 Freq: Q-DEC, dtype: float64 \u00b6 ### \u533a\u95f4\u9891\u7387\u8f6c\u6362 \u4f7f\u7528`asfreq`\u53ef\u4ee5\u5c06\u533a\u95f4\u548c`PeriodIndex`\u5bf9\u8c61\u8f6c\u6362\u4e3a\u5176\u4ed6\u7684\u9891\u7387\u3002 \u4f8b\u5982\uff0c\u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u5e74\u5ea6\u533a\u95f4\uff0c\u5e76\u4e14\u60f3\u8981\u5728\u4e00\u5e74\u7684\u5f00\u59cb\u6216\u7ed3\u675f\u65f6\u5c06\u5176\u8f6c\u6362\u4e3a\u6708\u5ea6\u533a\u95f4\u3002 \u53ef\u4ee5\u5c06`Period('2020', 'A-DEC')`\u770b\u4f5c\u4e00\u6bb5\u65f6\u95f4\u4e2d\u7684\u4e00\u79cd\u6e38\u6807\uff0c\u5c06\u65f6\u95f4\u6309\u6708\u4efd\u5212\u5206\u3002 p = pd.Period(2020, freq='A-DEC') print(p.asfreq('M', how='start')) 2020-01 \u00b6 print(p.asfreq('M', how='end')) 2020-12 \u00b6 \u5982\u679c\u8d22\u5e74\u7ed3\u675f\u4e0d\u572812\u6708\uff0c\u5219\u6bcf\u6708\u5206\u671f\u4f1a\u81ea\u52a8\u8c03\u6574\u3002 \u6309\u5f53\u5e74\u8d22\u5e74\u7ed3\u675f\u8ba1\u7b97\uff0c\u8d77\u59cb\u5e74\u4efd\u5c31\u662f\u4e0a\u4e00\u5e74\u4e86\u3002 p = pd.Period(2020, freq='A-JUN') print(p.asfreq('M', how='start')) 2019-07 \u00b6 print(p.asfreq('M', how='end')) 2020-06 \u00b6 \u5f53\u4ece\u9ad8\u9891\u7387\u5411\u4f4e\u9891\u7387\u8f6c\u6362\u65f6\uff0cpandas\u6839\u636e\u5b50\u533a\u95f4\u7684\"\u6240\u5c5e\"\u6765\u51b3\u5b9a\u7236\u533a\u95f4\u3002 \u4f8b\u5982\uff0c\u5728A-JUN\u9891\u7387\u4e2d\uff0cAug-2020\u662f2020\u533a\u95f4\u7684\u4e00\u90e8\u5206\uff1a print(p.asfreq('A-JUN')) 2020\u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628a`year`\u548c`quarter`\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f15\u3002 \u5b8c\u6574\u7684`PeriodIndex`\u5bf9\u8c61\u6216\u65f6\u95f4\u5e8f\u5217\u53ef\u4ee5\u6309\u7167\u76f8\u540c\u7684\u8bed\u4e49\u8fdb\u884c\u8f6c\u6362\uff1a rng = pd.period_range('2018', '2021', freq='A-DEC') data = np.random.randn(len(rng)) ts = pd.Series(data, index=rng) print(ts) 2018 0.221634 \u00b6 2019 -0.392724 \u00b6 2020 -0.355022 \u00b6 2021 0.114000 \u00b6 Freq: A-DEC, dtype: float64 \u00b6 \u4e0b\u9762\u5e74\u5ea6\u533a\u95f4\u5c06\u901a\u8fc7`asfreq`\u88ab\u66ff\u6362\u4e3a\u5bf9\u5e94\u4e8e\u6bcf\u4e2a\u5e74\u5ea6\u533a\u95f4\u5185\u7684\u7b2c\u4e00\u4e2a\u6708\u7684\u6708\u5ea6\u533a\u95f4\u3002 print(ts.asfreq('M', how='start')) 2018-01 0.681874 \u00b6 2019-01 -1.006585 \u00b6 2020-01 -0.619142 \u00b6 2021-01 1.445820 \u00b6 Freq: M, dtype: float64 \u00b6 \u5982\u679c\u6211\u4eec\u60f3\u8981\u6bcf\u5e74\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528`B`\u9891\u7387\u6765\u8868\u793a\u6211\u4eec\u60f3\u8981\u7684\u662f\u533a\u95f4\u7684\u672b\u7aef\u3002 print(ts.asfreq('B', how='end')) 2018-12-31 -1.520316 \u00b6 2019-12-31 -0.425544 \u00b6 2020-12-31 -0.658073 \u00b6 2021-12-31 1.206881 \u00b6 Freq: B, dtype: float64 \u00b6 ### \u5b63\u5ea6\u533a\u95f4\u9891\u7387 \u5b63\u5ea6\u6570\u636e\u662f\u4f1a\u8ba1\u3001\u91d1\u878d\u548c\u5176\u4ed6\u9886\u57df\u7684\u6807\u51c6\u3002 \u5f88\u591a\u5b63\u5ea6\u6570\u636e\u662f\u5728\u8d22\u5e74\u7ed3\u5c3e\u62a5\u544a\u7684\uff0c\u901a\u5e38\u662f\u4e00\u5e7412\u4e2a\u6708\u4e2d\u7684\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5\u6216\u5de5\u4f5c\u65e5\u3002 pandas\u652f\u6301\u6240\u6709\u7684\u53ef\u80fd\u768412\u4e2a\u5b63\u5ea6\u9891\u7387\u4eceQ-JAN\u5230Q-DEC\uff1a \u4e0b\u4f8b\u4e2d\uff0c\u8d22\u5e74\u7ed3\u675f\u4e8e1\u6708\uff0c2020Q4\u884c\u65f6\u95f4\u4e3a\u4e0a\u4e00\u5e7411\u6708\u81f3\u5f53\u5e741\u6708\u3002\u53ef\u4ee5\u901a\u8fc7\u8f6c\u6362\u4e3a\u6bcf\u65e5\u9891\u7387\uff08asfreq\uff09\u8fdb\u884c\u68c0\u67e5\u3002 p = pd.Period('2020Q4', freq='Q-JAN') print(p) 2020Q4 \u00b6 print(p.asfreq('D', 'start')) 2019-11-01 \u00b6 print(p.asfreq('D', 'end')) 2020-01-31 \u00b6 \u5047\u5982\u8d22\u5e74\u7ed3\u675f\u4e8e2\u6708\uff0c2020Q4\u884c\u65f6\u95f4\u4e3a\u4e0a\u4e00\u5e7412\u6708\u81f3\u5f53\u5e742\u6708\u3002 p = pd.Period('2020Q4', freq='Q-FEB') print(p) 2020Q4 \u00b6 print(p.asfreq('D', 'start')) 2019-11-01 \u00b6 print(p.asfreq('D', 'end')) 2020-01-31 \u00b6 \u5047\u5982\u8d22\u5e74\u7ed3\u675f\u4e8e4\u6708\uff0c2020Q4\u884c\u65f6\u95f4\u4e3a\u4e0a\u4e00\u5e7412\u6708\u81f3\u5f53\u5e742\u6708\u3002 p = pd.Period('2020Q4', freq='Q-APR') print(p) 2020Q4 \u00b6 print(p.asfreq('D', 'start')) 2020-02-01 \u00b6 print(p.asfreq('D', 'end')) 2020-04-30 \u00b6 \u53ef\u4ee5\u5bf9\u533a\u95f4\u6570\u636e\u505a\u7b97\u672f\u64cd\u4f5c\u3002\u4f8b\u5982\uff0c\u8981\u83b7\u53d6\u5728\u5b63\u5ea6\u5012\u6570\u7b2c\u4e8c\u4e2a\u5de5\u4f5c\u65e5\u4e0b\u53484\u70b9\u7684\u65f6\u95f4\u6233\uff0c\u53ef\u4ee5\u8fd9\u4e48\u505a\uff1a(\u7591\u95ee\uff1a\u8fd9\u91cc\u7684\u53c2\u6570e\u4ee3\u8868\u4ec0\u4e48 ???) p4pm = (p.asfreq('B', 'e') - 1).asfreq('T', 's') + 16 * 60 print(p4pm) 2020-04-29 16:00 \u00b6 print(p4pm.to_timestamp()) 2020-04-29 16:00:00 \u00b6 \u53ef\u4ee5\u4f7f\u7528`peroid_range`\u751f\u6210\u5b63\u5ea6\u5e8f\u5217\u3002\u5b83\u7684\u7b97\u672f\u4e5f\u662f\u4e00\u6837\u7684\uff1a rng = pd.period_range('2000Q3', '2001Q4', freq='Q-JAN') ts = pd.Series(np.arange(len(rng)), index=rng) print(ts) 2000Q3 0 \u00b6 2000Q4 1 \u00b6 2001Q1 2 \u00b6 2001Q2 3 \u00b6 2001Q3 4 \u00b6 2001Q4 5 \u00b6 Freq: Q-JAN, dtype: int64 \u00b6 new_rng = (rng.asfreq('B', 'e') - 1).asfreq('T', 's') + 16 * 60 ts.index = new_rng.to_timestamp() print(ts) 1999-10-28 16:00:00 0 \u00b6 2000-01-28 16:00:00 1 \u00b6 2000-04-27 16:00:00 2 \u00b6 2000-07-28 16:00:00 3 \u00b6 2000-10-30 16:00:00 4 \u00b6 2001-01-30 16:00:00 5 \u00b6 dtype: int64 \u00b6 ### \u5c06\u65f6\u95f4\u6233\u8f6c\u6362\u4e3a\u533a\u95f4\uff08\u4ee5\u53ca\u9006\u8f6c\u6362\uff09 \u901a\u8fc7\u65f6\u95f4\u6233\u7d22\u5f15\u7684Series\u548cDataFrame\u53ef\u4ee5\u88ab`to_period`\u65b9\u6cd5\u8f6c\u6362\u4e3a\u533a\u95f4\uff1a rng = pd.date_range('2020-01-01', periods=3, freq='M') ts = pd.Series(np.random.randn(3), index=rng) print(ts) 2020-01-31 -0.567097 \u00b6 2020-02-29 0.63452\u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628ayear\u548cquarter\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f152 \u00b6 2020-03-31 0.297777 \u00b6 Freq: M, dtype: float64 \u00b6 pts = ts.to_period() print(pts) 2020-01 -0.567097 \u00b6 2020-02 0.634522 \u00b6 2020-03 0.297777 \u00b6 Freq: M, dtype: float64 \u00b6 \u7531\u4e8e\u533a\u95f4\u662f\u975e\u91cd\u53e0\u65f6\u95f4\u8303\u56f4\uff0c\u4e00\u4e2a\u65f6\u95f4\u6233\u53ea\u80fd\u5c5e\u4e8e\u7ed9\u5b9a\u9891\u7387\u7684\u5355\u4e2a\u533a\u95f4\u3002 \u5c3d\u7ba1\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u6839\u636e\u65f6\u95f4\u6233\u63a8\u65ad\u51fa\u65b0`PeriodIndex`\u7684\u9891\u7387\uff0c\u4f46\u53ef\u4ee5\u6307\u5b9a\u4efb\u4f55\u60f3\u8981\u7684\u9891\u7387\u3002 \u5728\u7ed3\u679c\u4e2d\u5305\u542b\u91cd\u590d\u7684\u533a\u95f4\u4e5f\u662f\u6ca1\u6709\u95ee\u9898\u7684\u3002 rng = pd.date_range('2020-01-01', periods=6, freq='D') ts = pd.Series(np.random.randn(6), index=rng) print(ts) 2020-01-01 -0.111287 \u00b6 2020-01-02 1.442234 \u00b6 2020-01-03 -0.767553 \u00b6 2020-01-04 -0.265064 \u00b6 2020-01-05 1.200312 \u00b6 2020-01-06 -1.782557 \u00b6 Freq: D, dtype: float64 \u00b6 ts_m = ts.to_period('M') # \u6307\u5b9aperiod\u7684\u9891\u7387\uff08M\uff09,\u8f93\u51fa\u7ed3\u679c\u5305\u542b\u91cd\u590dperiod print(ts_m) 2020-01 -0.111287 \u00b6 2020-01 1.442234 \u00b6 2020-01 -0.767553 \u00b6 2020-01 -0.265064 \u00b6 2020-01 1.200312 \u00b6 2020-01 -1.782557 \u00b6 Freq: M, dtype: float64 \u00b6 \u4f7f\u7528`to_timestamp`\u53ef\u4ee5\u5c06\u533a\u95f4\u518d\u8f6c\u6362\u4e3a\u65f6\u95f4\u6233\uff1a print(ts_m.to_timestamp(how='end')) 2020-01-31 23:59:59.999999999 -0.111287 \u00b6 2020-01-31 23:59:59.999999999 1.442234 \u00b6 2020-01-31 23:59:59.999999999 -0.767553 \u00b6 2020-01-31 23:59:59.999999999 -0.265064 \u00b6 2020-01-31 23:59:59.999999999 1.200312 \u00b6 2020-01-31 23:59:59.999999999 -1.782557 \u00b6 dtype: float64 \u00b6 print(ts_m.to_timestamp(how='start')) 2020-01-01 -0.111287 \u00b6 2020-01-01 1.442234 \u00b6 2020-01-01 -0.767553 \u00b6 2020-01-01 -0.265064 \u00b6 2020-01-01 1.200312 \u00b6 2020-01-01 -1.782557 \u00b6 dtype: float64 \u00b6 ### \u4ece\u6570\u7ec4\u751f\u6210PeriodIndex \u56fa\u5b9a\u9891\u7387\u6570\u636e\u96c6\u6709\u65f6\u5b58\u50a8\u5728\u8de8\u8d8a\u591a\u5217\u7684\u65f6\u95f4\u8303\u56f4\u4fe1\u606f\u4e2d\u3002\u4f8b\u5982\uff0c\u5728\u8fd9\u4e2a\u5b8f\u89c2\u7ecf\u6d4e\u6570\u636e\u96c6\u4e2d\uff0c\u5e74\u4efd\u548c\u5b63\u5ea6\u5728\u4e0d\u540c\u5217\u4e2d\uff1a data = pd.read_csv('../examples/macrodata.csv') print(data.head(5)) year quarter realgdp realcons ... unemp pop infl realint \u00b6 0 1959.0 1.0 2710.349 1707.4 ... 5.8 177.146 0.00 0.00 \u00b6 1 1959.0 2.0 2778.801 1733.7 ... 5.1 177.830 2.34 0.74 \u00b6 2 1959.0 3.0 2775.488 1751.8 ... 5.3 178.657 2.74 1.09 \u00b6 3 1959.0 4.0 2785.204 1753.7 ... 5.6 179.386 0.27 4.06 \u00b6 4 1960.0 1.0 2847.699 1770.5 ... 5.2 180.007 2.31 1.19 \u00b6 print(data.year) 0 1959.0 \u00b6 1 1959.0 \u00b6 2 1959.0 \u00b6 3 1959.0 \u00b6 4 1960.0 \u00b6 ... \u00b6 198 2008.0 \u00b6 199 2008.0 \u00b6 200 2009.0 \u00b6 201 2009.0 \u00b6 202 2009.0 \u00b6 Name: year, Length: 203, dtype: float64 \u00b6 print(data.quarter) 0 1.0 \u00b6 1 2.0 \u00b6 2 3.0 \u00b6 3 4.0 \u00b6 4 1.0 \u00b6 ... \u00b6 198 3.0 \u00b6 199 4.0 \u00b6 200 1.0 \u00b6 201 2.0 \u00b6 202 3.0 \u00b6 Name: quarter, Length: 203, dtype: float64 \u00b6 \u901a\u8fc7\u5c06\u8fd9\u4e9b\u6570\u7ec4\u548c\u9891\u7387\u4f20\u9012\u7ed9`PeriodIndex`\uff0c\u53ef\u4ee5\u8054\u5408\u5f62\u6210DataFrame\u7684\u7d22\u5f15 index = pd.PeriodIndex(year=data.year, quarter=data.quarter, freq='Q-DEC') print(index) PeriodIndex(['1959Q1', '1959Q2', '1959Q3', '1959Q4', '1960Q1', '1960Q2', \u00b6 '1960Q3', '1960Q4', '1961Q1', '1961Q2', \u00b6 ... \u00b6 '2007Q2', '2007Q3', '2007Q4', '2008Q1', '2008Q2', '2008Q3', \u00b6 '2008Q4', '2009Q1', '2009Q2', '2009Q3'], \u00b6 dtype='period[Q-DEC]', length=203) \u00b6 data.index = index # \u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628ayear\u548cquarter\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f15 print(data.infl) 1959Q1 0.00 \u00b6 1959Q2 2.34 \u00b6 1959Q3 2.74 \u00b6 1959Q4 0.27 \u00b6 1960Q1 2.31 \u00b6 ... \u00b6 2008Q3 -3.16 \u00b6 2008Q4 -8.79 \u00b6 2009Q1 0.94 \u00b6 2009Q2 3.37 \u00b6 2009Q3 3.56 \u00b6 Freq: Q-DEC, Name: infl, Length: 203, dtype: float64 \u00b6 ## \u91cd\u65b0\u91c7\u6837\u9891\u7387\u8f6c\u6362 import pandas as pd import numpy as np from pandas.tseries.frequencies import to_offset \u91cd\u65b0\u91c7\u6837\u662f\u6307\u5c06\u65f6\u95f4\u5e8f\u5217\u4ece\u4e00\u4e2a\u9891\u7387\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u9891\u7387\u7684\u8fc7\u7a0b\u3002 \u5c06\u66f4\u9ad8\u9891\u7387\u7684\u6570\u636e\u805a\u5408\u5230\u4f4e\u9891\u7387\u88ab\u79f0\u4e3a\u5411\u4e0b\u91c7\u6837\uff0c\u800c\u4ece\u4f4e\u9891\u7387\u8f6c\u6362\u5230\u9ad8\u9891\u7387\u79f0\u4e3a\u5411\u4e0a\u91c7\u6837\u3002 \u5e76\u4e0d\u662f\u6240\u6709\u7684\u91cd\u65b0\u91c7\u6837\u90fd\u5c5e\u4e8e\u4e0a\u9762\u8bf4\u7684\u4e24\u7c7b\u3002\u4f8b\u5982\uff0c\u5c06W-WED\uff08weekly on Wednesday\uff0c\u6bcf\u5468\u4e09\uff09\u8f6c\u6362\u5230W-FRI\uff08\u6bcf\u5468\u4e94\uff09\u65e2\u4e0d\u662f\u5411\u4e0a\u91c7\u6837\u4e5f\u4e0d\u662f\u5411\u4e0b\u91c7\u6837\u3002 pandas\u5bf9\u8c61\u90fd\u914d\u6709`resample`\u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u662f\u6240\u6709\u9891\u7387\u8f6c\u6362\u7684\u5de5\u5177\u51fd\u6570\u3002`resample`\u62e5\u6709\u7c7b\u4f3c\u4e8e`groupby`\u7684API\uff1b\u8c03\u7528`resample`\u5bf9\u6570\u636e\u5206\u7ec4\uff0c\u4e4b\u540e\u518d\u8c03\u7528\u805a\u5408\u51fd\u6570\uff1a ### resample\u65b9\u6cd5\u53c2\u6570 \u53c2\u6570 * freq: \u8868\u793a\u91cd\u91c7\u6837\u9891\u7387\uff0c\u4f8b\u5982\u2018M'\u3001\u20185min'\uff0cSecond(15) * how='mean': \u7528\u4e8e\u4ea7\u751f\u805a\u5408\u503c\u7684\u51fd\u6570\u540d\u6216\u6570\u7ec4\u51fd\u6570\uff0c\u4f8b\u5982\u2018mean'\u3001\u2018ohlc'\u3001np.max\u7b49\uff0c\u9ed8\u8ba4\u662f\u2018mean'\uff0c\u5176\u4ed6\u5e38\u7528\u7684\u503c\u7531\uff1a\u2018first'\u3001\u2018last'\u3001\u2018median'\u3001\u2018max'\u3001\u2018min' * axis=0: \u9ed8\u8ba4\u662f\u7eb5\u8f74\uff0c\u6a2a\u8f74\u8bbe\u7f6eaxis=1 * fill_method = None: \u5347\u91c7\u6837\u65f6\u5982\u4f55\u63d2\u503c\uff0c\u6bd4\u5982\u2018ffill'\u3001\u2018bfill'\u7b49 * closed = \u2018right': \u5728\u964d\u91c7\u6837\u65f6\uff0c\u5404\u65f6\u95f4\u6bb5\u7684\u54ea\u4e00\u6bb5\u662f\u95ed\u5408\u7684\uff0c\u2018right'\u6216\u2018left'\uff0c\u9ed8\u8ba4\u2018right' * label= \u2018right': \u5728\u964d\u91c7\u6837\u65f6\uff0c\u5982\u4f55\u8bbe\u7f6e\u805a\u5408\u503c\u7684\u6807\u7b7e\uff0c\u4f8b\u5982\uff0c9\uff1a30-9\uff1a35\u4f1a\u88ab\u6807\u8bb0\u62109\uff1a30\u8fd8\u662f9\uff1a35,\u9ed8\u8ba49\uff1a35 * loffset = None: \u9762\u5143\u6807\u7b7e\u7684\u65f6\u95f4\u6821\u6b63\u503c\uff0c\u6bd4\u5982\u2018-1s'\u6216Second(-1)\u7528\u4e8e\u5c06\u805a\u5408\u6807\u7b7e\u8c03\u65e91\u79d2 * limit=None: \u5728\u5411\u524d\u6216\u5411\u540e\u586b\u5145\u65f6\uff0c\u5141\u8bb8\u586b\u5145\u7684\u6700\u5927\u65f6\u671f\u6570 * kind = None: \u805a\u5408\u5230\u65f6\u671f\uff08\u2018period'\uff09\u6216\u65f6\u95f4\u6233\uff08\u2018timestamp'\uff09\uff0c\u9ed8\u8ba4\u805a\u5408\u5230\u65f6\u95f4\u5e8f\u5217\u7684\u7d22\u5f15\u7c7b\u578b * convention = None: \u5f53\u91cd\u91c7\u6837\u65f6\u671f\u65f6\uff0c\u5c06\u4f4e\u9891\u7387\u8f6c\u6362\u5230\u9ad8\u9891\u7387\u6240\u91c7\u7528\u7684\u7ea6\u5b9a\uff08start\u6216end\uff09\u3002\u9ed8\u8ba4\u2018end' rng = pd.date_range('2020-1-1', periods=100, freq='D') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(ts) 2020-01-01 0.802409 \u00b6 2020-01-02 -1.147130 \u00b6 2020-01-03 -1.076115 \u00b6 2020-01-04 -2.097443 \u00b6 2020-01-05 0.577671 \u00b6 ... \u00b6 2020-04-05 -0.110747 \u00b6 2020-04-06 0.132867 \u00b6 2020-04-07 -0.294061 \u00b6 2020-04-08 -0.246155 \u00b6 2020-04-09 0.927194 \u00b6 Freq: D, Length: 100, dtype: float64 \u00b6 print(ts.resample('M')) DatetimeIndexResampler [freq= , axis=0, closed=right, label=right, convention=start, origin=start_day] \u00b6 print(ts.resample('M').mean()) # \u628a100\u5929\u7684\u6570\u636e\u6309\u6708groupby\uff0c\u5e76\u8f93\u51fa\u6708\u672b\u6700\u540e\u4e00\u5929\uff0c\u8ba1\u7b97\u5e73\u5747\u503c 2020-01-31 -0.311714 \u00b6 2020-02-29 0.121526 \u00b6 2020-03-31 -0.051131 \u00b6 2020-04-30 -0.273113 \u00b6 Freq: M, dtype: float64 \u00b6 print(ts.resample('M', kind='period').mean()) # # \u628a100\u5929\u7684\u6570\u636e\u6309\u6708groupby\uff0c\u5e76\u8f93\u51fa\u6708\u4efd\uff08\u53c2\u6570period\uff09\uff0c\u8ba1\u7b97\u5e73\u5747\u503c 2020-01 -0.311714 \u00b6 2020-02 0.121526 \u00b6 2020-03 -0.051131 \u00b6 2020-04 -0.273113 \u00b6 Freq: M, dtype: float64 \u00b6 ### \u5411\u4e0b\u91c7\u6837 \u5c06\u6570\u636e\u805a\u5408\u5230\u4e00\u4e2a\u89c4\u5219\u7684\u4f4e\u9891\u7387\u4e0a\u662f\u4e00\u4e2a\u5e38\u89c1\u7684\u65f6\u95f4\u5e8f\u5217\u4efb\u52a1\u3002 \u8981\u805a\u5408\u7684\u6570\u636e\u4e0d\u5fc5\u662f\u56fa\u5b9a\u9891\u7387\u7684\u3002 \u671f\u671b\u7684\u9891\u7387\u5b9a\u4e49\u4e86\u7528\u4e8e\u5bf9\u65f6\u95f4\u5e8f\u5217\u5207\u7247\u4ee5\u805a\u5408\u7684\u7bb1\u4f53\u8fb9\u754c\u3002\u4f8b\u5982\uff0c\u8981\u5c06\u65f6\u95f4\u8f6c\u6362\u4e3a\u6bcf\u6708\uff0c`M`\u6216`BM`\uff0c\u5219\u9700\u8981\u5c06\u6570\u636e\u5206\u6210\u4e00\u4e2a\u6708\u7684\u65f6\u95f4\u95f4\u9694\u3002 \u6bcf\u4e2a\u95f4\u9694\u662f\u534a\u95ed\u5408\u7684\uff0c\u4e00\u4e2a\u6570\u636e\u70b9\u53ea\u80fd\u5c5e\u4e8e\u4e00\u4e2a\u65f6\u95f4\u95f4\u9694\uff0c\u65f6\u95f4\u95f4\u9694\u7684\u5e76\u96c6\u5fc5\u987b\u662f\u6574\u4e2a\u65f6\u95f4\u5e27\u3002 \u5728\u4f7f\u7528resample\u8fdb\u884c\u5411\u4e0b\u91c7\u6837\u6570\u636e\u65f6\u6709\u4e9b\u4e8b\u60c5\u9700\u8981\u8003\u8651\uff1a * \u6bcf\u6bb5\u95f4\u9694\u7684\u54ea\u4e00\u8fb9\u662f\u95ed\u5408\u7684\u3002 * \u5982\u4f55\u5728\u95f4\u9694\u7684\u8d77\u59cb\u6216\u7ed3\u675f\u4f4d\u7f6e\u6807\u8bb0\u6bcf\u4e2a\u5df2\u805a\u5408\u7684\u7bb1\u4f53\u3002 rng = pd.date_range('2020-1-1', periods=12, freq='T') ts = pd.Series(np.arange(12), index=rng) print(ts) 2020-01-01 00:00:00 0 \u00b6 2020-01-01 00:01:00 1 \u00b6 2020-01-01 00:02:00 2 \u00b6 2020-01-01 00:03:00 3 \u00b6 2020-01-01 00:04:00 4 \u00b6 2020-01-01 00:05:00 5 \u00b6 2020-01-01 00:06:00 6 \u00b6 2020-01-01 00:07:00 7 \u00b6 2020-01-01 00:08:00 8 \u00b6 2020-01-01 00:09:00 9 \u00b6 2020-01-01 00:10:00 10 \u00b6 2020-01-01 00:11:00 11 \u00b6 Freq: T, dtype: int64 \u00b6 \u6309\u4e94\u5206\u949f\u9891\u7387\u805a\u5408\u5206\u7ec4\uff0c\u8ba1\u7b97\u6bcf\u4e00\u7ec4\u7684\u52a0\u548c\u3002\u9891\u7387\u6309\u4e94\u5206\u949f\u7684\u589e\u91cf\u5b9a\u4e49\u4e86\u7bb1\u4f53\u8fb9\u754c\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5de6\u7bb1\u4f53\u8fb9\u754c\u662f\u5305\u542b\u7684\uff0c\u56e0\u6b6400:00\u7684\u503c\u662f\u5305\u542b\u572800:00\u523000:05\u95f4\u9694\u5185\u7684\u3002 \u4f20\u9012`closed='right'`\u5c06\u95f4\u9694\u7684\u95ed\u5408\u7aef\u6539\u4e3a\u4e86\u53f3\u8fb9\u3002 \u5206\u7ec4\uff1a * left: [00:00,00:01,00:02,00:03,00:04],[00:05,00:06,00:07,00:08,00:09],[00:10,00:11] * right:[00:00],[00:01,00:02,00:03,00:04,00:05],[00:06,00:07,00:08,00:09,00:10],[00:11] result = ts.resample('5min', closed='right').sum() print(result) 2019-12-31 23:55:00 0 \u00b6 2020-01-01 00:00:00 15 \u00b6 2020-01-01 00:05:00 40 \u00b6 2020-01-01 00:10:00 11 \u00b6 Freq: 5T, dtype: int64 \u00b6 result = ts.resample('5min', closed='left').sum() print(result) 2020-01-01 00:00:00 10 \u00b6 2020-01-01 00:05:00 35 \u00b6 2020-01-01 00:10:00 21 \u00b6 Freq: 5T, dtype: int64 \u00b6 \u6700\u540e\uff0c\u5c06\u7ed3\u679c\u7d22\u5f15\u79fb\u52a8\u4e00\u5b9a\u7684\u6570\u91cf\uff0c\u4f8b\u5982\u4ece\u53f3\u8fb9\u7f18\u51cf\u53bb\u4e00\u79d2\uff0c\u4ee5\u4f7f\u5176\u66f4\u6e05\u695a\u5730\u8868\u660e\u65f6\u95f4\u6233\u6240\u6307\u7684\u95f4\u9694\u3002 \u8981\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\uff0c\u5411`loffset`\u4f20\u9012\u5b57\u7b26\u4e32\u6216\u65e5\u671f\u504f\u7f6e\uff1a result = ts.resample('5min', closed='right', label='right', loffset='-1s').sum() print(result) 2019-12-31 23:59:59 0 \u00b6 2020-01-01 00:04:59 15 \u00b6 2020-01-01 00:09:59 40 \u00b6 2020-01-01 00:14:59 11 \u00b6 Freq: 5T, dtype: int64 \u00b6 FutureWarning: 'loffset' in .resample() and in Grouper() is deprecated. \u00b6 >>> df.resample(freq=\"3s\", loffset=\"8H\") \u00b6 becomes: \u00b6 >>> from pandas.tseries.frequencies import to_offset \u00b6 >>> df = df.resample(freq=\"3s\").mean() \u00b6 >>> df.index = df.index.to_timestamp() + to_offset(\"8H\") \u00b6 #### \u5f00\u7aef-\u5cf0\u503c-\u8c37\u503c-\u7ed3\u675f\uff08OHLC\uff09\u91cd\u65b0\u91c7\u6837 \u5728\u91d1\u878d\u4e2d\uff0c\u4e3a\u6bcf\u4e2a\u6570\u636e\u6876\u8ba1\u7b97\u56db\u4e2a\u503c\u662f\u4e00\u79cd\u6d41\u884c\u7684\u65f6\u95f4\u5e8f\u5217\u805a\u5408\u65b9\u6cd5\uff1a\u7b2c\u4e00\u4e2a\u503c\uff08\u5f00\u7aef\uff09\u3001\u6700\u540e\u4e00\u4e2a\u503c\uff08\u7ed3\u675f\uff09\u3001\u6700\u5927\u503c\uff08\u5cf0\u503c\uff09\u548c\u6700\u5c0f\u503c\uff08\u8c37\u503c\uff09\u3002 \u901a\u8fc7\u4f7f\u7528`ohlc`\u805a\u5408\u51fd\u6570\u53d6\u5f97\u5305\u542b\u56db\u79cd\u805a\u5408\u503c\u5217\u7684DataFrame\uff0c\u8fd9\u4e9b\u503c\u5728\u6570\u636e\u7684\u5355\u6b21\u626b\u63cf\u4e2d\u88ab\u9ad8\u6548\u8ba1\u7b97\uff1a result = ts.resample('5min').ohlc() print(result) open high low close \u00b6 2020-01-01 00:00:00 0 4 0 4 \u00b6 2020-01-01 00:05:00 5 9 5 9 \u00b6 2020-01-01 00:10:00 10 11 10 11 \u00b6 ### \u5411\u4e0a\u91c7\u6837\u4e0e\u63d2\u503c \u5f53\u4ece\u4f4e\u9891\u7387\u8f6c\u6362\u4e3a\u9ad8\u9891\u7387\u65f6\uff0c\u5e76\u4e0d\u9700\u8981\u4efb\u4f55\u805a\u5408\u3002 df = pd.DataFrame( np.random.randn(2, 4), index=pd.date_range('2020/1/1', periods=2, freq='W-WED'), columns=['Colorado', 'Texas', 'New York', 'Ohio'] ) print(df) Colorado Texas New York Ohio \u00b6 2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-08 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 df_daily = df.resample('W-WED').sum() print(df_daily) Colorado Texas New York Ohio \u00b6 2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-08 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 df_daily = df.resample('D').sum() print(df_daily) Colorado Texas New York Ohio \u00b6 2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-02 0.000000 0.000000 0.000000 0.000000 \u00b6 2020-01-03 0.000000 0.000000 0.000000 0.000000 \u00b6 2020-01-04 0.000000 0.000000 0.000000 0.000000 \u00b6 2020-01-05 0.000000 0.000000 0.000000 0.000000 \u00b6 2020-01-06 0.000000 0.000000 0.000000 0.000000 \u00b6 2020-01-07 0.000000 0.000000 0.000000 0.000000 \u00b6 2020-01-08 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 \u5f53\u5bf9\u8fd9\u4e9b\u6570\u636e\u4f7f\u7528\u805a\u5408\u51fd\u6570\u65f6\uff0c\u6bcf\u4e00\u7ec4\u53ea\u6709\u4e00\u4e2a\u503c\uff0c\u5e76\u4e14\u4f1a\u5728\u95f4\u9699\u4e2d\u4ea7\u751f\u7f3a\u5931\u503c\u3002 \u4f7f\u7528`asfreq`\u65b9\u6cd5\u5728\u4e0d\u805a\u5408\u7684\u60c5\u51b5\u4e0b\u8f6c\u6362\u5230\u9ad8\u9891\u7387\uff1a df_daily = df.resample('D').asfreq() print(df_daily) Colorado Texas New York Ohio \u00b6 2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-02 NaN NaN NaN NaN \u00b6 2020-01-03 NaN NaN NaN NaN \u00b6 2020-01-04 NaN NaN NaN NaN \u00b6 2020-01-05 NaN NaN NaN NaN \u00b6 2020-01-06 NaN NaN NaN NaN \u00b6 2020-01-07 NaN NaN NaN NaN \u00b6 2020-01-08 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 \u5728\u975e\u661f\u671f\u4e09\u7684\u65e5\u671f\u4e0a\u5411\u524d\u586b\u5145\u6bcf\u5468\u6570\u503c\u3002`fillna`\u548c`reindex`\u65b9\u6cd5\u4e2d\u53ef\u7528\u7684\u586b\u5145\u6216\u63d2\u503c\u65b9\u6cd5\u53ef\u7528\u4e8e\u91cd\u91c7\u6837\uff1a df_daily = df.resample('D').ffill() print(df_daily) Colorado Texas New York Ohio \u00b6 2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-02 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-03 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-04 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-05 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-06 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-07 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-08 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 \u53ef\u4ee5\u540c\u6837\u9009\u62e9\u4ec5\u5411\u524d\u586b\u5145\u4e00\u5b9a\u6570\u91cf\u7684\u533a\u95f4\uff0c\u4ee5\u9650\u5236\u7ee7\u7eed\u4f7f\u7528\u89c2\u6d4b\u503c\u7684\u65f6\u8ddd\uff1a df_daily = df.resample('D').ffill(limit=2) print(df_daily) Colorado Texas New York Ohio \u00b6 2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-02 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-03 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-04 NaN NaN NaN NaN \u00b6 2020-01-05 NaN NaN NaN NaN \u00b6 2020-01-06 NaN NaN NaN NaN \u00b6 2020-01-07 NaN NaN NaN NaN \u00b6 2020-01-08 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 \u6ce8\u610f\uff0c\u65b0\u7684\u65e5\u671f\u7d22\u5f15\u4e0d\u9700\u8981\u4e0e\u65e7\u7684\u7d22\u5f15\u91cd\u53e0\uff0c\u548c\u539f\u6765`df`\u7684\u503c\u4e00\u6837\uff0c\u53ea\u662f\u65e5\u671f\u7d22\u5f15\u53d8\u4e86\u3002 df_new = df.resample('W-THU').ffill() print(df_new) Colorado Texas New York Ohio \u00b6 2020-01-02 -0.228758 -0.758718 -0.025410 -1.001819 \u00b6 2020-01-09 -0.704541 -0.261414 -0.863335 0.267101 \u00b6 ### \u4f7f\u7528\u533a\u95f4\u8fdb\u884c\u91cd\u65b0\u91c7\u6837 \u5bf9\u4ee5\u533a\u95f4\u4e3a\u7d22\u5f15\u7684\u6570\u636e\u8fdb\u884c\u91c7\u6837\u4e0e\u65f6\u95f4\u6233\u7684\u60c5\u51b5\u7c7b\u4f3c\uff1a df = pd.DataFrame( np.random.randn(24, 4), index=pd.period_range('2020-1', periods=24, freq='M'), columns=['Colorado', 'Texas', 'New York', 'Ohio'] ) print(df) 2020-01 0.721395 -1.492674 0.707410 1.641890 \u00b6 2020-02 -0.894880 0.032823 -0.676158 0.029203 \u00b6 2020-03 2.147365 -0.176796 0.562695 -0.747656 \u00b6 2020-04 1.496037 -0.797119 -0.495601 0.774147 \u00b6 2020-05 -0.309839 0.502563 0.237244 0.910624 \u00b6 2020-06 1.231869 -0.105227 1.315759 0.217701 \u00b6 2020-07 1.447419 0.263876 -0.342045 -0.768907 \u00b6 2020-08 -2.567162 -1.008827 0.391085 1.259560 \u00b6 2020-09 -0.772501 1.183532 0.450374 0.450714 \u00b6 2020-10 0.228974 0.461224 1.393178 0.175243 \u00b6 2020-11 -0.725193 -1.544131 1.372029 -0.659224 \u00b6 2020-12 0.718195 0.862024 -0.166460 -0.940191 \u00b6 2021-01 -0.617054 -0.887312 0.338451 -1.392838 \u00b6 2021-02 -0.081140 0.634730 -0.868051 -1.277167 \u00b6 2021-03 -0.999642 -1.959715 -0.930662 0.748687 \u00b6 2021-04 1.851453 1.561669 -0.688822 -0.371255 \u00b6 2021-05 -0.540777 -0.890403 -1.204188 0.243480 \u00b6 2021-06 1.318905 1.247457 0.518969 0.799793 \u00b6 2021-07 0.223238 0.747177 -0.410889 0.904593 \u00b6 2021-08 -0.652551 -0.254351 -0.464604 -0.676923 \u00b6 2021-09 0.562312 0.182099 0.018617 0.573331 \u00b6 2021-10 0.429490 -0.045959 -0.356292 -0.295776 \u00b6 2021-11 2.552155 0.801299 1.378421 1.232792 \u00b6 2021-12 1.102288 0.850280 -0.767015 -0.519840 \u00b6 df_annual = df.resample('A-DEC').mean() print(df_annual) Colorado Texas New York Ohio \u00b6 2020 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021 0.429056 0.165581 -0.286339 -0.002594 \u00b6 \u5411\u4e0a\u91c7\u6837\u66f4\u4e3a\u7ec6\u81f4\uff0c\u56e0\u4e3a\u5fc5\u987b\u5728\u91cd\u65b0\u91c7\u6837\u524d\u51b3\u5b9a\u65b0\u9891\u7387\u4e2d\u5728\u65f6\u95f4\u6bb5\u7684\u54ea\u4e00\u7aef\u653e\u7f6e\u6570\u503c\uff0c\u5c31\u50cfasfreq\u65b9\u6cd5\u4e00\u6837\u3002 `convention`\u53c2\u6570\u9ed8\u8ba4\u503c\u662f`start`\uff0c\u4f46\u4e5f\u53ef\u4ee5\u662f`end`\uff1a result = df_annual.resample('Q-DEC').ffill() print(result) Colorado Texas New York Ohio \u00b6 2020Q1 0.226807 -0.151561 0.395793 0.195259 \u00b6 2020Q2 0.226807 -0.151561 0.395793 0.195259 \u00b6 2020Q3 0.226807 -0.151561 0.395793 0.195259 \u00b6 2020Q4 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q1 0.429056 0.165581 -0.286339 -0.002594 \u00b6 2021Q2 0.429056 0.165581 -0.286339 -0.002594 \u00b6 2021Q3 0.429056 0.165581 -0.286339 -0.002594 \u00b6 2021Q4 0.429056 0.165581 -0.286339 -0.002594 \u00b6 result = df_annual.resample('Q-DEC', convention='end').ffill() print(result) Colorado Texas New York Ohio \u00b6 2020Q4 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q1 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q2 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q3 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q4 0.429056 0.165581 -0.286339 -0.002594 \u00b6 \u7531\u4e8e\u533a\u95f4\u6d89\u53ca\u65f6\u95f4\u8303\u56f4\uff0c\u5411\u4e0a\u91c7\u6837\u548c\u5411\u4e0b\u91c7\u6837\u5c31\u66f4\u4e3a\u4e25\u683c\uff1a * \u5728\u5411\u4e0b\u91c7\u6837\u4e2d\uff0c\u76ee\u6807\u9891\u7387\u5fc5\u987b\u662f\u539f\u9891\u7387\u7684\u5b50\u533a\u95f4\u3002 * \u5728\u5411\u4e0a\u91c7\u6837\u4e2d\uff0c\u76ee\u6807\u9891\u7387\u5fc5\u987b\u662f\u539f\u9891\u7387\u7684\u7236\u533a\u95f4\u3002 \u5982\u679c\u4e0d\u6ee1\u8db3\u8fd9\u4e9b\u89c4\u5219\uff0c\u5c06\u4f1a\u5f15\u8d77\u5f02\u5e38\u3002\u8fd9\u4e3b\u8981\u4f1a\u5f71\u54cd\u6bcf\u5b63\u5ea6\u3001\u6bcf\u5e74\u548c\u6bcf\u5468\u7684\u9891\u7387\u3002 \u4f8b\u5982\uff0c\u6839\u636eQ-MAR\u5b9a\u4e49\u7684\u65f6\u95f4\u8303\u56f4\u5c06\u53ea\u548cA-MAR\u3001A-JUN\u3001A-SEP\u548cA-DEC\u4fdd\u6301\u4e00\u81f4\uff1a result = df_annual.resample('Q-MAR').ffill() print(result) Colorado Texas New York Ohio \u00b6 2020Q4 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q1 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q2 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q3 0.226807 -0.151561 0.395793 0.195259 \u00b6 2021Q4 0.429056 0.165581 -0.286339 -0.002594 \u00b6 2022Q1 0.429056 0.165581 -0.286339 -0.002594 \u00b6 2022Q2 0.429056 0.165581 -0.286339 -0.002594 \u00b6 2022Q3 0.429056 0.165581 -0.286339 -0.002594 \u00b6 ## \u79fb\u52a8\u7a97\u53e3\u51fd\u6570 \u7edf\u8ba1\u90a3\u4e9b\u901a\u8fc7\u79fb\u52a8\u7a97\u53e3\u6216\u6307\u6570\u8870\u51cf\u800c\u8fd0\u884c\u7684\u51fd\u6570\uff0c\u662f\u7528\u4e8e\u65f6\u95f4\u5e8f\u5217\u64cd\u4f5c\u7684\u6570\u7ec4\u53d8\u6362\u7684\u4e00\u4e2a\u91cd\u8981\u7c7b\u522b\u3002 \u8fd9\u5bf9\u5e73\u6ed1\u566a\u58f0\u6216\u7c97\u7cd9\u7684\u6570\u636e\u975e\u5e38\u6709\u7528\u3002\u79f0\u8fd9\u4e9b\u51fd\u6570\u4e3a\u79fb\u52a8\u7a97\u53e3\u51fd\u6570\uff0c\u5c3d\u7ba1\u5b83\u4e5f\u5305\u542b\u4e86\u4e00\u4e9b\u6ca1\u6709\u56fa\u5b9a\u957f\u5ea6\u7a97\u53e3\u7684\u51fd\u6570\uff0c\u6bd4\u5982\u6307\u6570\u52a0\u6743\u79fb\u52a8\u5e73\u5747\u3002 \u4e0e\u5176\u4ed6\u7684\u7edf\u8ba1\u51fd\u6570\u7c7b\u4f3c\uff0c\u8fd9\u4e9b\u51fd\u6570\u4f1a\u81ea\u52a8\u6392\u9664\u7f3a\u5931\u6570\u636e\u3002 import matplotlib.pyplot as plt import pandas as pd from scipy.stats import percentileofscore import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd import pytz \u5728\u6df1\u5165\u4e86\u89e3\u4e4b\u524d\uff0c\u6211\u4eec\u53ef\u4ee5\u5148\u8f7d\u5165\u4e00\u4e9b\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u5e76\u6309\u7167\u5de5\u4f5c\u65e5\u9891\u7387\u8fdb\u884c\u91cd\u65b0\u91c7\u6837\uff1a close_px_all = pd.read_csv( '../examples/stock_px_2.csv', parse_dates = True, index_col=0 ) print(close_px_all.head(5)) AAPL MSFT XOM SPX \u00b6 2003-01-02 7.40 21.11 29.22 909.03 \u00b6 2003-01-03 7.45 21.14 29.24 908.59 \u00b6 2003-01-06 7.45 21.52 29.96 929.01 \u00b6 2003-01-07 7.43 21.93 28.95 922.93 \u00b6 2003-01-08 7.28 21.31 28.83 909.93 \u00b6 close_px = close_px_all[ ['AAPL', 'MSFT', 'XOM'] ] close_px = close_px.resample('B').ffill() print(close_px) AAPL MSFT XOM \u00b6 2003-01-02 7.40 21.11 29.22 \u00b6 2003-01-03 7.45 21.14 29.24 \u00b6 ... ... ... ... \u00b6 2011-10-13 408.43 27.18 76.37 \u00b6 2011-10-14 422.00 27.27 78.11 \u00b6 [2292 rows x 3 columns] \u00b6 `rolling`\u7b97\u5b50\uff0c\u5b83\u7684\u884c\u4e3a\u4e0e`resample`\u548c`groupby`\u7c7b\u4f3c\u3002 `rolling`\u53ef\u4ee5\u5728Series\u6216DataFrame\u4e0a\u901a\u8fc7\u4e00\u4e2awindow\uff08\u4ee5\u4e00\u4e2a\u533a\u95f4\u7684\u6570\u5b57\u6765\u8868\u793a\uff09\u8fdb\u884c\u8c03\u7528\u3002 close_px.AAPL.plot() \u8868\u8fbe\u5f0f`rolling(250)`\u4e0e`groupby`\u7684\u884c\u4e3a\u7c7b\u4f3c\uff0c\u4f46\u662f\u5b83\u521b\u5efa\u7684\u5bf9\u8c61\u662f\u6839\u636e250\u65e5\u6ed1\u52a8\u7a97\u53e3\u5206\u7ec4\u7684\u800c\u4e0d\u662f\u76f4\u63a5\u5206\u7ec4\u3002 \u56e0\u6b64\u8fd9\u91cc\u6211\u4eec\u83b7\u5f97\u4e86\u82f9\u679c\u516c\u53f8\u80a1\u7968\u4ef7\u683c\u7684250\u65e5\u79fb\u52a8\u7a97\u53e3\u5e73\u5747\u503c\u3002 close_px.AAPL.rolling(250).mean().plot() plt.show() \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6eda\u52a8\u51fd\u6570\u9700\u8981\u7a97\u53e3\u4e2d\u6240\u6709\u7684\u503c\u5fc5\u987b\u662f\u975e`NA`\u503c\u3002 \u7531\u4e8e\u5b58\u5728\u7f3a\u5931\u503c\u8fd9\u79cd\u884c\u4e3a\u4f1a\u53d1\u751f\u6539\u53d8\uff0c\u5c24\u5176\u662f\u5728\u65f6\u95f4\u5e8f\u5217\u7684\u8d77\u59cb\u4f4d\u7f6e\u4f60\u62e5\u6709\u7684\u6570\u636e\u662f\u5c11\u4e8e\u7a97\u53e3\u533a\u95f4\u7684 apple_std250 = close_px.AAPL.rolling(250, min_periods=10).std() # \u82f9\u679c\u516c\u53f8250\u65e5\u6bcf\u65e5\u8fd4\u56de\u6807\u51c6\u5dee print(apple_std250[5:12]) 2003-01-09 NaN \u00b6 2003-01-10 NaN \u00b6 2003-01-13 NaN \u00b6 2003-01-14 NaN \u00b6 2003-01-15 0.077496 \u00b6 2003-01-16 0.074760 \u00b6 2003-01-17 0.112368 \u00b6 Freq: B, Name: AAPL, dtype: float64 \u00b6 apple_std250.plot() plt.show() expanding_mean = apple_std250.expanding().mean() print(expanding_mean[5:12]) 2003-01-09 NaN \u00b6 2003-01-10 NaN \u00b6 2003-01-13 NaN \u00b6 2003-01-14 NaN \u00b6 2003-01-15 0.077496 \u00b6 2003-01-16 0.076128 \u00b6 2003-01-17 0.088208 \u00b6 Freq: B, Name: AAPL, dtype: float64 \u00b6 expanding_mean.plot() plt.show() \u5728DataFrame\u4e0a\u8c03\u7528\u4e00\u4e2a\u79fb\u52a8\u7a97\u53e3\u51fd\u6570\u4f1a\u5c06\u53d8\u6362\u5e94\u7528\u5230\u6bcf\u4e00\u5217\u4e0a: close_px.rolling(60).mean().plot(logy=True) # \u80a1\u7968\u4ef7\u683c60\u65e5MA\uff08Y\u8f74\u53d6\u5bf9\u6570\uff09 plt.show() `rolling`\u51fd\u6570\u4e5f\u63a5\u6536\u8868\u793a\u56fa\u5b9a\u5927\u5c0f\u7684\u65f6\u95f4\u504f\u7f6e\u5b57\u7b26\u4e32\uff0c\u800c\u4e0d\u53ea\u662f\u4e00\u4e2a\u533a\u95f4\u7684\u96c6\u5408\u6570\u5b57\u3002 \u5bf9\u4e0d\u89c4\u5219\u65f6\u95f4\u5e8f\u5217\u4f7f\u7528\u6ce8\u91ca\u975e\u5e38\u6709\u7528\u3002\u8fd9\u4e9b\u5b57\u7b26\u4e32\u53ef\u4ee5\u4f20\u9012\u7ed9`resample`\u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u50cf\u8fd9\u6837\u8ba1\u7b9720\u5929\u7684\u6eda\u52a8\u5e73\u5747\u503c\uff1a result = close_px.rolling('20D').mean() print(result) AAPL MSFT XOM \u00b6 2003-01-02 7.400000 21.110000 29.220000 \u00b6 ... ... ... ... \u00b6 2011-10-14 391.038000 26.048667 74.185333 \u00b6 [2292 rows x 3 columns] \u00b6 result.plot() plt.show() ### \u6307\u6570\u52a0\u6743\u51fd\u6570 \u6307\u5b9a\u4e00\u4e2a\u5e38\u6570\u8870\u51cf\u56e0\u5b50\u4ee5\u5411\u66f4\u591a\u8fd1\u671f\u89c2\u6d4b\u503c\u63d0\u4f9b\u66f4\u591a\u6743\u91cd\uff0c\u53ef\u4ee5\u66ff\u4ee3\u4f7f\u7528\u5177\u6709\u76f8\u7b49\u52a0\u6743\u89c2\u5bdf\u503c\u7684\u9759\u6001\u7a97\u53e3\u5c3a\u5bf8\u7684\u65b9\u6cd5\u3002 \u6709\u591a\u79cd\u65b9\u5f0f\u53ef\u4ee5\u6307\u5b9a\u8870\u51cf\u56e0\u5b50\u3002\u5176\u4e2d\u4e00\u79cd\u6d41\u884c\u7684\u65b9\u5f0f\u662f\u4f7f\u7528\u4e00\u4e2aspan\uff08\u8de8\u5ea6\uff09\uff0c\u8fd9\u4f7f\u5f97\u7ed3\u679c\u4e0e\u7a97\u53e3\u5927\u5c0f\u7b49\u4e8e\u8de8\u5ea6\u7684\u7b80\u5355\u79fb\u52a8\u7a97\u53e3\u51fd\u6570\u3002 \u7531\u4e8e\u6307\u6570\u52a0\u6743\u7edf\u8ba1\u503c\u7ed9\u66f4\u8fd1\u671f\u7684\u89c2\u6d4b\u503c\u4ee5\u66f4\u591a\u7684\u6743\u91cd\uff0c\u4e0e\u7b49\u6743\u91cd\u7684\u7248\u672c\u76f8\u6bd4\uff0c\u5b83\u5bf9\u53d8\u5316\u201c\u9002\u5e94\u201d\u5f97\u66f4\u5feb\u3002 pandas\u62e5\u6709`ewm`\u7b97\u5b50\uff0c\u540c`rolling`\u3001`expanding`\u7b97\u5b50\u4e00\u8d77\u4f7f\u7528\u3002 \u4ee5\u4e0b\u662f\u5c06\u82f9\u679c\u516c\u53f8\u80a1\u7968\u4ef7\u683c\u768460\u65e5\u5747\u7ebf\u4e0e`span=60`\u7684EW\u79fb\u52a8\u5e73\u5747\u7ebf\u8fdb\u884c\u6bd4\u8f83\u7684\u4f8b\u5b50\uff1a aapl_ex = close_px.AAPL['2006':'2007'] ma60 = aapl_ex.rolling(30, min_periods=20).mean() ewma60 = aapl_ex.ewm(span=30).mean() ma60.plot(style='k--', label='Simple MA') ewma60.plot(style='k-', label='EWMA') plt.legend() plt.show() ### \u4e8c\u5143\u79fb\u52a8\u7a97\u53e3\u51fd\u6570 \u4e00\u4e9b\u7edf\u8ba1\u7b97\u5b50\uff0c\u4f8b\u5982\u76f8\u5173\u5ea6\u548c\u534f\u65b9\u5dee\uff0c\u9700\u8981\u64cd\u4f5c\u4e24\u4e2a\u65f6\u95f4\u5e8f\u5217\u3002 \u4f8b\u5982\uff0c\u91d1\u878d\u5206\u6790\u5e08\u7ecf\u5e38\u5bf9\u80a1\u7968\u4e0e\u57fa\u51c6\u6307\u6570\uff08\u5982\u6807\u666e500\uff09\u7684\u5173\u8054\u6027\u611f\u5174\u8da3\u3002 \u6211\u4eec\u9996\u5148\u8ba1\u7b97\u6240\u6709\u6211\u4eec\u611f\u5174\u8da3\u7684\u65f6\u95f4\u5e8f\u5217\u7684\u767e\u5206\u6bd4\u53d8\u5316\uff1a spx_px = close_px_all['SPX'] spx_rets = spx_px.pct_change() returns = close_px.pct_change() \u5728\u8c03\u7528rolling\u540e\uff0ccorr\u805a\u5408\u51fd\u6570\u53ef\u4ee5\u6839\u636espx_rets\u8ba1\u7b97\u6eda\u52a8\u76f8\u5173\u6027\uff1a \u00b6 corr = returns.AAPL.rolling(125, min_periods=100).corr(spx_rets) # \u82f9\u679c\u516c\u53f8\u4e0e\u6807\u666e500\u7684\u516d\u4e2a\u6708\u7684\u6536\u76ca\u76f8\u5173\u6027 corr.plot() plt.show() corr = returns.rolling(125, min_periods=100).corr(spx_rets) # \u591a\u53ea\u80a1\u7968\u4e0e\u6807\u666e500\u7684\u516d\u4e2a\u6708\u6536\u76ca\u76f8\u5173\u6027 corr.plot() plt.show() ### \u7528\u6237\u81ea\u5b9a\u4e49\u7684\u79fb\u52a8\u7a97\u53e3\u51fd\u6570 \u5728`rolling`\u53ca\u5176\u76f8\u5173\u65b9\u6cd5\u4e0a\u4f7f\u7528apply\u65b9\u6cd5\u63d0\u4f9b\u4e86\u4e00\u79cd\u5728\u79fb\u52a8\u7a97\u53e3\u4e2d\u5e94\u7528\u4f60\u81ea\u5df1\u8bbe\u8ba1\u7684\u6570\u7ec4\u51fd\u6570\u7684\u65b9\u6cd5\u3002 \u552f\u4e00\u7684\u8981\u6c42\u662f\u8be5\u51fd\u6570\u4ece\u6bcf\u4e2a\u6570\u7ec4\u4e2d\u4ea7\u751f\u4e00\u4e2a\u5355\u503c\uff08\u7f29\u805a\uff09\u3002 \u4f8b\u5982\uff0c\u5c3d\u7ba1\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528`rolling(...).quantile(q)`\u8ba1\u7b97\u6837\u672c\u7684\u5206\u4f4d\u6570\uff0c\u4f46\u6211\u4eec\u53ef\u80fd\u4f1a\u5bf9\u6837\u672c\u4e2d\u7279\u5b9a\u503c\u7684\u767e\u5206\u4f4d\u6570\u611f\u5174\u8da3\u3002 `scipy.stats.percentileofscore`\u51fd\u6570\u5c31\u662f\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\u7684\uff1a score_at_2percent = lambda x: percentileofscore(x, 0.02) result = returns.AAPL.rolling(250).apply(score_at_2percent) # \u4e00\u5e74\u7a97\u53e3\u4e0b\u82f9\u679c\u516c\u53f8\u80a1\u4ef72%\u6536\u76ca\u7684\u767e\u5206\u4f4d\u7b49\u7ea7 result.plot() plt.show() result = returns.rolling(250).apply(score_at_2percent) # \u4e00\u5e74\u7a97\u53e3\u4e0b\u6240\u6709\u516c\u53f8\u80a1\u4ef72%\u6536\u76ca\u7684\u767e\u5206\u4f4d\u7b49\u7ea7 result.plot() plt.show() ```","title":"\u65f6\u95f4\u5e8f\u5217"},{"location":"python/DataAnalysis/ch08/#_1","text":"","title":"\u65f6\u95f4\u5e8f\u5217"},{"location":"python/DataAnalysis/ch08/#_2","text":"\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u5728\u5f88\u591a\u9886\u57df\u90fd\u662f\u91cd\u8981\u7684\u7ed3\u6784\u5316\u6570\u636e\u5f62\u5f0f\u3002\u5728\u591a\u4e2a\u65f6\u95f4\u70b9\u89c2\u6d4b\u6216\u6d4b\u91cf\u7684\u6570\u636e\u5f62\u6210\u4e86\u65f6\u95f4\u5e8f\u5217\u3002 \u8bb8\u591a\u65f6\u95f4\u5e8f\u5217\u662f\u56fa\u5b9a\u9891\u7387\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\u6570\u636e\u662f\u6839\u636e\u76f8\u540c\u7684\u89c4\u5219\u5b9a\u671f\u51fa\u73b0\u7684\uff0c\u4f8b\u5982\u6bcf15\u79d2\u3001\u6bcf5\u5206\u949f\u6216\u6bcf\u67081\u6b21\u3002 \u65f6\u95f4\u5e8f\u5217\u4e5f\u53ef\u4ee5\u662f\u4e0d\u89c4\u5219\u7684\uff0c\u6ca1\u6709\u56fa\u5b9a\u7684\u65f6\u95f4\u5355\u4f4d\u6216\u5355\u4f4d\u95f4\u7684\u504f\u79fb\u91cf\u3002 \u5982\u4f55\u6807\u8bb0\u548c\u5f15\u7528\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u53d6\u51b3\u4e8e\u5e94\u7528\u7a0b\u5e8f\uff0c\u65f6\u95f4\u5e8f\u5217\u5305\u62ec\uff1a \u65f6\u95f4\u6233\uff0c\u5177\u4f53\u7684\u65f6\u523b\u3002 \u56fa\u5b9a\u7684\u65f6\u95f4\u533a\u95f4\uff0c\u4f8b\u59822007\u76841\u6708\u6216\u6574\u4e2a2010\u5e74\u3002 \u65f6\u95f4\u95f4\u9694\uff0c\u7531\u5f00\u59cb\u548c\u7ed3\u675f\u65f6\u95f4\u6233\u8868\u793a\u3002\u65f6\u95f4\u533a\u95f4\u53ef\u4ee5\u88ab\u8ba4\u4e3a\u662f\u95f4\u9694\u7684\u7279\u6b8a\u60c5\u51b5\u3002 \u5b9e\u9a8c\u65f6\u95f4\u6216\u6d88\u8017\u65f6\u95f4\u3002\u6bcf\u4e2a\u65f6\u95f4\u6233\u662f\u76f8\u5bf9\u4e8e\u7279\u5b9a\u5f00\u59cb\u65f6\u95f4\u7684\u65f6\u95f4\u7684\u91cf\u5ea6\uff08\u4f8b\u5982\uff0c\u81ea\u4ece\u88ab\u653e\u7f6e\u5728\u70e4\u7bb1\u4e2d\u6bcf\u79d2\u70d8\u70e4\u7684\u997c\u5e72\u7684\u76f4\u5f84\uff09\u3002 \u76ee\u524d\u4e3b\u8981\u5173\u6ce8\u524d\u4e09\u7c7b\u4e2d\u7684\u65f6\u95f4\u5e8f\u5217\u3002 from datetime import datetime, timedelta import datetime as dt from dateutil.parser import parse import pandas as pd","title":"\u65e5\u671f\u548c\u65f6\u95f4\u6570\u636e\u7684\u7c7b\u578b\u53ca\u5de5\u5177"},{"location":"python/DataAnalysis/ch08/#datetime","text":"datetime\u683c\u5f0f\u7b26\uff1a %a \u661f\u671f\u7684\u82f1\u6587\u5355\u8bcd\u7684\u7f29\u5199\uff1a\u5982\u661f\u671f\u4e00\uff0c \u5219\u8fd4\u56de Mon %A \u661f\u671f\u7684\u82f1\u6587\u5355\u8bcd\u7684\u5168\u62fc\uff1a\u5982\u661f\u671f\u4e00\uff0c\u8fd4\u56de Monday %b \u6708\u4efd\u7684\u82f1\u6587\u5355\u8bcd\u7684\u7f29\u5199\uff1a\u5982\u4e00\u6708\uff0c \u5219\u8fd4\u56de Jan %B \u6708\u4efd\u7684\u5f15\u6587\u5355\u8bcd\u7684\u7f29\u5199\uff1a\u5982\u4e00\u6708\uff0c \u5219\u8fd4\u56de January %c \u8fd4\u56dedatetime\u7684\u5b57\u7b26\u4e32\u8868\u793a\uff0c\u598203/08/15 23:01:26 %d \u8fd4\u56de\u7684\u662f\u5f53\u524d\u65f6\u95f4\u662f\u5f53\u524d\u6708\u7684\u7b2c\u51e0\u5929 %f \u5fae\u79d2\u7684\u8868\u793a\uff1a \u8303\u56f4: [0,999999] %H \u4ee524\u5c0f\u65f6\u5236\u8868\u793a\u5f53\u524d\u5c0f\u65f6 %I \u4ee512\u5c0f\u65f6\u5236\u8868\u793a\u5f53\u524d\u5c0f\u65f6 %m \u8fd4\u56de\u6708\u4efd \u8303\u56f4[0,12] %M \u8fd4\u56de\u5206\u949f\u6570 \u8303\u56f4 [0,59] %P \u8fd4\u56de\u662f\u4e0a\u5348\u8fd8\u662f\u4e0b\u5348\u2013AM or PM %S \u8fd4\u56de\u79d2\u6570 \u8303\u56f4 [0,61]\u3002\u3002\u3002\u624b\u518c\u8bf4\u660e\u7684 %U \u8fd4\u56de\u5f53\u5468\u662f\u5f53\u5e74\u7684\u7b2c\u51e0\u5468 \u4ee5\u5468\u65e5\u4e3a\u7b2c\u4e00\u5929 %W \u8fd4\u56de\u5f53\u5468\u662f\u5f53\u5e74\u7684\u7b2c\u51e0\u5468 \u4ee5\u5468\u4e00\u4e3a\u7b2c\u4e00\u5929 %w \u5f53\u5929\u5728\u5f53\u5468\u7684\u5929\u6570\uff0c\u8303\u56f4\u4e3a[0, 6]\uff0c6\u8868\u793a\u661f\u671f\u5929 %x \u65e5\u671f\u7684\u5b57\u7b26\u4e32\u8868\u793a \uff1a03/08/15 %X \u65f6\u95f4\u7684\u5b57\u7b26\u4e32\u8868\u793a \uff1a23:22:08 %y \u4e24\u4e2a\u6570\u5b57\u8868\u793a\u7684\u5e74\u4efd 15 %Y \u56db\u4e2a\u6570\u5b57\u8868\u793a\u7684\u5e74\u4efd 2015 %z \u4e0eutc\u65f6\u95f4\u7684\u95f4\u9694 \uff08\u5982\u679c\u662f\u672c\u5730\u65f6\u95f4\uff0c\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\uff09 %Z \u65f6\u533a\u540d\u79f0\uff08\u5982\u679c\u662f\u672c\u5730\u65f6\u95f4\uff0c\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\uff09 datestrs = ['2020/5/6', '2021/10/1'] # \u6ce8\u610f\u533a\u5206datetime\u6a21\u5757\u548cdatetime\u7c7b\uff0c\u540d\u5b57\u76f8\u540c\uff0c\u5bb9\u6613\u5f15\u8d77\u9519\u8bef\u3002 # \u6bd4\u5982datetime.datetime\u5c31\u62a5\u9519type object 'datetime.datetime' has no attribute 'datetime' print(datetime) # print(dt) # Python\u6807\u51c6\u5e93\u5305\u542b\u4e86\u65e5\u671f\u548c\u65f6\u95f4\u6570\u636e\u7684\u7c7b\u578b\u3002 datetime \u3001 time \u548c calendar \u6a21\u5757\u662f\u5f00\u59cb\u5904\u7406\u65f6\u95f4\u6570\u636e\u7684\u4e3b\u8981\u5185\u5bb9\u3002 datetime.datetime \u7c7b\u578b\uff0c\u6216\u7b80\u5199\u4e3a datetime \uff0c\u662f\u5e7f\u6cdb\u4f7f\u7528\u7684\u3002 now = datetime.now() print(now) # 2021-10-07 20:24:43.834293 result = dt.datetime(2021, 10, 7, 20, 26, 00, 72973) print(result) # 2021-10-07 20:26:00.072973 datetime \u65e2\u5b58\u50a8\u4e86\u65e5\u671f\uff0c\u4e5f\u5b58\u50a8\u4e86\u7ec6\u5316\u5230\u5fae\u79d2\u7684\u65f6\u95f4\u3002 timedelta \u8868\u793a\u4e24\u4e2a datetime \u5bf9\u8c61\u7684\u65f6\u95f4\u5dee\u3002 delta = datetime(2021, 10, 7) - datetime(2021, 9, 7) print(delta) # 30 days, 0:00:00 print(delta.days) # 30 print(delta.seconds) # 0 result = dt.timedelta(926, 56700) print(result) # 926 days, 15:45:00 \u53ef\u4ee5\u4e3a\u4e00\u4e2a datetime \u5bf9\u8c61\u52a0\u4e0a\uff08\u6216\u51cf\u53bb\uff09\u4e00\u4e2a timedelta \u6216\u5176\u6574\u6570\u500d\u6765\u4ea7\u751f\u4e00\u4e2a\u65b0\u7684 datetime \u5bf9\u8c61\u3002 start = datetime(2021, 10, 7) result = start + timedelta(12) print(result) # 2021-10-19 00:00:00 result = start - 2 * timedelta(5) print(result) # 2021-09-27 00:00:00","title":"datetime"},{"location":"python/DataAnalysis/ch08/#datetime_1","text":"\u4f7f\u7528 str \u65b9\u6cd5\u6216\u4f20\u9012\u4e00\u4e2a\u6307\u5b9a\u7684\u683c\u5f0f\u7ed9 strftime \u65b9\u6cd5\u6765\u5bf9 datetime \u5bf9\u8c61\u548cpandas\u7684 Timestamp \u5bf9\u8c61\u8fdb\u884c\u683c\u5f0f\u5316\u3002 stamp = datetime(2021, 10, 7) result = str(stamp) print(result) # 2021-10-07 00:00:00 \u4f7f\u7528 datetime.srtptime \u548c datetime \u683c\u5f0f\u7b26\uff0c\u628a\u5b57\u7b26\u4e32\u8f6c\u6362\u65e5\u671f\u3002 datetime.strptime \u662f\u5728\u5df2\u77e5\u683c\u5f0f\u7684\u60c5\u51b5\u4e0b\u8f6c\u6362\u65e5\u671f\u7684\u597d\u65b9\u5f0f\u3002 value = '2021-10-7' result = datetime.strptime(value, '%Y-%m-%d') print(result) # 2021-10-07 00:00:00 datestrs = ['2020/5/6', '2021/10/1'] result = [datetime.strptime(x, '%Y/%m/%d') for x in datestrs] print(result) # [datetime.datetime(2020, 5, 6, 0, 0), datetime.datetime(2021, 10, 1, 0, 0)] dateutil \u89e3\u6790\u901a\u7528\u65e5\u671f\u683c\u5f0f\uff1a print(parse('2020/5/6')) # 2020-05-06 00:00:00 print(parse('Jan 31, 2021 10:25 AM')) # 2021-01-31 10:25:00 print(parse('5/6/2021', dayfirst=True)) # \u65e5\u671f\u51fa\u73b0\u5728\u6708\u4efd\u4e4b\u524d # 2021-06-05 00:00:00 pandas\u4e3b\u8981\u662f\u9762\u5411\u5904\u7406\u65e5\u671f\u6570\u7ec4\u7684\uff0c\u65e0\u8bba\u662f\u7528\u4f5c\u8f74\u7d22\u5f15\u8fd8\u662f\u7528\u4f5cDataFrame\u4e2d\u7684\u5217\u3002 to_datetime \u65b9\u6cd5\u53ef\u4ee5\u8f6c\u6362\u5f88\u591a\u4e0d\u540c\u7684\u65e5\u671f\u8868\u793a\u683c\u5f0f\u3002 to_datetime \u65b9\u6cd5\u8fd8\u53ef\u4ee5\u5904\u7406\u90a3\u4e9b\u88ab\u8ba4\u4e3a\u662f\u7f3a\u5931\u503c\u7684\u503c\uff08None\u3001\u7a7a\u5b57\u7b26\u4e32\u7b49\uff09\u3002 NaT \uff08Not a time\uff09\u662fpandas\u4e2d\u65f6\u95f4\u6233\u6570\u636e\u7684\u662fnull\u503c\u3002 datestrs = ['2020/5/6 12:00:00', '2021/10/1 09:00:00'] result = pd.to_datetime(datestrs) print(result) # DatetimeIndex(['2020-05-06 12:00:00', '2021-10-01 09:00:00'], dtype='datetime64[ns]', freq=None) idx = pd.to_datetime(datestrs + [None]) print(idx) # DatetimeIndex(['2020-05-06 12:00:00', '2021-10-01 09:00:00', 'NaT'], dtype='datetime64[ns]', freq=None) print(idx[2]) # NaT print(pd.isnull(idx)) # [False False True]","title":"\u5b57\u7b26\u4e32\u4e0edatetime\u4e92\u76f8\u8f6c\u6362"},{"location":"python/DataAnalysis/ch08/#_3","text":"from datetime import datetime import pandas as pd import numpy as np","title":"\u65f6\u95f4\u5e8f\u5217\u57fa\u7840"},{"location":"python/DataAnalysis/ch08/#datetimeindex","text":"pandas\u4e2d\u7684\u57fa\u7840\u65f6\u95f4\u5e8f\u5217\u79cd\u7c7b\u662f\u7531\u65f6\u95f4\u6233\u7d22\u5f15\u7684Series\uff0c\u5728pandas\u5916\u90e8\u5219\u901a\u5e38\u8868\u793a\u4e3aPython\u5b57\u7b26\u4e32\u6216 datetime \u5bf9\u8c61\u3002 \u6240\u6709\u4f7f\u7528 datetime \u5bf9\u8c61\u7684\u5730\u65b9\u90fd\u53ef\u4ee5\u7528 Timestamp \u3002 dates = [ datetime(2021, 10, 1), datetime(2021, 10, 3), datetime(2021, 10, 5), datetime(2021, 10, 7), datetime(2021, 10, 9), datetime(2021, 10, 11) ] data = np.random.rand(6) ts = pd.Series(data, index=dates) print(ts) # 2021-10-01 0.678297 # 2021-10-03 0.538631 # 2021-10-05 0.934413 # 2021-10-07 0.018534 # 2021-10-09 0.938441 # 2021-10-11 0.173329 # dtype: float64 \u8fd9\u4e9b datetime \u5bf9\u8c61\u88ab\u653e\u5165 DatetimeIndex \u4e2d\u3002 print(ts.index) # DatetimeIndex(['2021-10-01', '2021-10-03', '2021-10-05', '2021-10-07', # '2021-10-09', '2021-10-11'], # dtype='datetime64[ns]', freq=None) DatetimeIndex \u4e2d\u7684\u6807\u91cf\u503c\u662f pandas \u7684 Timestamp \u5bf9\u8c61\uff1a stamp = ts.index[0] print(stamp) # 2021-10-01 00:00:00 \u548c\u5176\u4ed6Series\u7c7b\u4f3c\uff0c\u4e0d\u540c\u7d22\u5f15\u7684\u65f6\u95f4\u5e8f\u5217\u4e4b\u95f4\u7684\u7b97\u672f\u8fd0\u7b97\u5728\u65e5\u671f\u4e0a\u81ea\u52a8\u5bf9\u9f50\uff1a print(ts + ts[::2]) # ts[::2]\u4f1a\u5c06ts\u4e2d\u6bcf\u9694\u4e00\u4e2a\u7684\u5143\u7d20\u9009\u62e9\u51fa # 2021-10-01 1.356595 # 2021-10-03 NaN # 2021-10-05 1.868825 # 2021-10-07 NaN # 2021-10-09 1.876883 # 2021-10-11 NaN # dtype: float64 pandas\u4f7f\u7528NumPy\u7684 datetime64 \u6570\u636e\u7c7b\u578b\u5728\u7eb3\u79d2\u7ea7\u7684\u5206\u8fa8\u7387\u4e0b\u5b58\u50a8\u65f6\u95f4\u6233 print(ts.index.dtype) # datetime64[ns]","title":"DatetimeIndex"},{"location":"python/DataAnalysis/ch08/#_4","text":"\u5f53\u57fa\u4e8e\u6807\u7b7e\u8fdb\u884c\u7d22\u5f15\u548c\u9009\u62e9\u65f6\uff0c\u65f6\u95f4\u5e8f\u5217\u7684\u884c\u4e3a\u548c\u5176\u4ed6\u7684pandas.Series\u7c7b\u4f3c\uff1a stamp = ts.index[2] print(ts[stamp]) # 0.9344125159374457 \u5bf9\u5e942021-10-05 \u4e5f\u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u80fd\u89e3\u91ca\u4e3a\u65e5\u671f\u7684\u5b57\u7b26\u4e32\uff1a print(ts['10/9/2021']) print(ts['20211003']) \u5bf9\u4e00\u4e2a\u957f\u7684\u65f6\u95f4\u5e8f\u5217\uff0c\u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u5e74\u4efd\u6216\u4e00\u4e2a\u5e74\u4efd\u548c\u6708\u4efd\u6765\u9009\u62e9\u6570\u636e\u5207\u7247\uff1a data = np.random.randn(1000) longer_ts = pd.Series( data, index=pd.date_range('1/1/2021', periods=1000) ) print(longer_ts) # 2021-01-01 -0.009192 # 2021-01-02 -1.079068 # 2021-01-03 -1.851176 # 2021-01-04 1.347109 # 2021-01-05 -0.236394 # ... # 2023-09-23 -1.317943 # 2023-09-24 0.201741 # 2023-09-25 0.442282 # 2023-09-26 0.176137 # 2023-09-27 1.146437 # Freq: D, Length: 1000, dtype: float64 \u5b57\u7b26\u4e32\u20192001\u2019\u88ab\u89e3\u91ca\u4e3a\u4e00\u4e2a\u5e74\u4efd\uff0c\u5e76\u9009\u62e9\u4e86\u76f8\u5e94\u7684\u65f6\u95f4\u533a\u95f4\u3002 print(longer_ts['2021']) # 2021-01-01 2.170411 # 2021-01-02 1.186933 # 2021-01-03 0.399262 # 2021-01-04 -1.042606 # 2021-01-05 2.082112 # ... # 2021-12-27 -0.988282 # 2021-12-28 0.598683 # 2021-12-29 2.770580 # 2021-12-30 -1.463262 # 2021-12-31 -1.642846 # Freq: D, Length: 365, dtype: float64 \u6307\u5b9a\u4e86\u5e74\u4efd\u548c\u6708\u4efd\u4e5f\u662f\u6709\u6548\u7684\u3002 print(longer_ts['2021-10']) # 2021-10-01 0.712265 # 2021-10-02 1.195221 # 2021-10-03 -1.930220 # 2021-10-04 -0.720816 # 2021-10-05 0.081777 # 2021-10-06 -0.037466 # 2021-10-07 3.737303 # 2021-10-08 1.620383 # 2021-10-09 0.990797 # 2021-10-10 0.507850 # 2021-10-11 0.846935 # 2021-10-12 0.996947 # 2021-10-13 -1.078558 # 2021-10-14 0.871832 # 2021-10-15 -0.591698 # 2021-10-16 -0.805463 # 2021-10-17 0.160528 # 2021-10-18 -0.028474 # 2021-10-19 2.305579 # 2021-10-20 -1.132288 # 2021-10-21 0.649980 # 2021-10-22 0.615327 # 2021-10-23 0.185108 # 2021-10-24 0.857199 # 2021-10-25 -1.473752 # 2021-10-26 -0.895161 # 2021-10-27 -0.432717 # 2021-10-28 0.734504 # 2021-10-29 1.892493 # 2021-10-30 0.456619 # 2021-10-31 -0.255288 # Freq: D, dtype: float64 \u4f7f\u7528 datetime \u5bf9\u8c61\u8fdb\u884c\u5207\u7247\u4e5f\u662f\u53ef\u4ee5\u7684\uff1a print(longer_ts[datetime(2023, 1, 6):]) # 2023-01-06 0.952591 # 2023-01-07 -0.900259 # 2023-01-08 0.925332 # 2023-01-09 0.173215 # 2023-01-10 -0.507791 # ... # 2023-09-23 -0.319989 # 2023-09-24 -1.105417 # 2023-09-25 -2.118769 # 2023-09-26 0.009420 # 2023-09-27 -0.310281 # Freq: D, Length: 265, dtype: float64 \u56e0\u4e3a\u5927\u90e8\u5206\u7684\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u662f\u6309\u65f6\u95f4\u987a\u5e8f\u6392\u5e8f\u7684\uff0c\u53ef\u4ee5\u4f7f\u7528\u4e0d\u5305\u542b\u5728\u65f6\u95f4\u5e8f\u5217\u4e2d\u7684\u65f6\u95f4\u6233\u8fdb\u884c\u5207\u7247\uff0c\u4ee5\u6267\u884c\u8303\u56f4\u67e5\u8be2\uff1a print(longer_ts['2021/10/1':'2021/10/5']) # 2021-10-01 -0.591853 # 2021-10-02 -1.554564 # 2021-10-03 -0.712585 # 2021-10-04 -0.326657 # 2021-10-05 1.044887 # Freq: D, dtype: float64 \u4f7f\u7528 truncate \u5728\u4e24\u4e2a\u65e5\u671f\u95f4\u5bf9Series\u8fdb\u884c\u5207\u7247\uff1a print(longer_ts.truncate(after='2021/10/1')) # 2021-01-01 -0.906685 # 2021-01-02 -0.470732 # 2021-01-03 -0.041316 # 2021-01-04 -0.287356 # 2021-01-05 0.104268 # ... # 2021-09-27 -0.669198 # 2021-09-28 -2.222169 # 2021-09-29 -0.653814 # 2021-09-30 -0.625868 # 2021-10-01 0.872684 # Freq: D, Length: 274, dtype: float64 \u4e0a\u9762\u8fd9\u4e9b\u64cd\u4f5c\u4e5f\u90fd\u9002\u7528\u4e8eDataFrame\uff0c\u5e76\u5728\u5176\u884c\u4e0a\u8fdb\u884c\u7d22\u5f15\uff1a dates = pd.date_range('10/1/2020', periods=100, freq='W-WED') data = np.random.randn(100, 4) long_df = pd.DataFrame( data, index=dates, columns=['Colorado', 'Texas', 'New York', 'Ohio'] ) print(long_df) # Colorado Texas New York Ohio # 2020-10-07 -1.186789 2.020634 0.300076 -0.955234 # 2020-10-14 1.502838 0.965368 -0.797539 -0.292833 # ... ... ... ... ... # 2022-08-24 -0.253116 -0.263307 0.602425 0.370599 # 2022-08-31 0.907918 0.091939 0.789694 2.781535 # [100 rows x 4 columns] print(long_df.loc['10-2020']) # Colorado Texas New York Ohio # 2020-10-07 1.031616 -1.812038 -0.446577 0.395656 # 2020-10-14 -0.673167 0.198804 -0.439141 0.086004 # 2020-10-21 -1.139786 0.716820 0.006516 -0.284335 # 2020-10-28 -0.637939 1.647810 -0.750786 0.140637","title":"\u7d22\u5f15\u3001\u9009\u62e9\u3001\u5b50\u96c6"},{"location":"python/DataAnalysis/ch08/#_5","text":"\u5728\u67d0\u4e9b\u5e94\u7528\u4e2d\uff0c\u53ef\u80fd\u4f1a\u6709\u591a\u4e2a\u6570\u636e\u89c2\u5bdf\u503c\u843d\u5728\u7279\u5b9a\u7684\u65f6\u95f4\u6233\u4e0a\u3002\u4e0b\u9762\u662f\u4e2a\u4f8b\u5b50\uff1a dates = pd.DatetimeIndex( ['2021/1/1', '2021/1/2', '2021/1/2', '2021/1/2', '2021/1/3'] ) dup_ts = pd.Series( np.arange(5), index=dates ) print(dup_ts) # 2021-01-01 0 # 2021-01-02 1 # 2021-01-02 2 # 2021-01-02 3 # 2021-01-03 4 # dtype: int64 \u901a\u8fc7\u68c0\u67e5\u7d22\u5f15\u7684 is_unique \u5c5e\u6027\uff0c\u53ef\u4ee5\u770b\u51fa\u7d22\u5f15\u5e76\u4e0d\u662f\u552f\u4e00\u7684\uff1a print(dup_ts.index.is_unique) # False \u5bf9\u4e0a\u9762\u7684Series\u8fdb\u884c\u7d22\u5f15\uff0c\u7ed3\u679c\u662f\u6807\u91cf\u503c\u8fd8\u662fSeries\u5207\u7247\u53d6\u51b3\u4e8e\u662f\u5426\u6709\u65f6\u95f4\u6233\u662f\u91cd\u590d\u7684\uff1a result = dup_ts['2021/1/3'] print(result) # 4 result = dup_ts['2021/1/2'] print(result) # 2021-01-02 1 # 2021-01-02 2 # 2021-01-02 3 # dtype: int64 \u5047\u8bbe\u60f3\u8981\u805a\u5408\u542b\u6709\u975e\u552f\u4e00\u65f6\u95f4\u6233\u7684\u6570\u636e\u3002\u4e00\u79cd\u65b9\u5f0f\u5c31\u662f\u4f7f\u7528 groupby \u5e76\u4f20\u9012 level=0 \uff1a grouped = dup_ts.groupby(level=0) result = grouped.mean() print(result) # 2021-01-01 0.0 # 2021-01-02 2.0 # 2021-01-03 4.0 # dtype: float64 result = grouped.count() print(result) # 2021-01-01 1 # 2021-01-02 3 # 2021-01-03 1 # dtype: int64","title":"\u542b\u6709\u91cd\u590d\u7d22\u5f15\u7684\u65f6\u95f4\u5e8f\u5217"},{"location":"python/DataAnalysis/ch08/#_6","text":"from datetime import datetime, timedelta import pandas as pd import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd pandas\u7684\u901a\u7528\u65f6\u95f4\u5e8f\u5217\u662f\u4e0d\u89c4\u5219\u7684\uff0c\u5373\u65f6\u95f4\u5e8f\u5217\u7684\u9891\u7387\u4e0d\u662f\u56fa\u5b9a\u7684\u3002 \u4f46\u6709\u65f6\u9700\u8981\u5904\u7406\u56fa\u5b9a\u9891\u7387\u7684\u573a\u666f\uff0c\u4f8b\u5982\u6bcf\u65e5\u7684\u3001\u6bcf\u6708\u7684\u6216\u6bcf15\u5206\u949f\u7684\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u3002 \u53ef\u4ee5\u901a\u8fc7\u8c03\u7528resample\u65b9\u6cd5\u5c06\u6837\u672c\u65f6\u95f4\u5e8f\u5217\u8f6c\u6362\u4e3a\u56fa\u5b9a\u7684\u6bcf\u65e5\u9891\u7387\u6570\u636e\u3002 \u5728\u9891\u7387\u95f4\u8f6c\u6362\uff0c\u53c8\u79f0\u4e3a\u91cd\u65b0\u91c7\u6837\u3002 dates = [ datetime(2021, 10, 1), datetime(2021, 10, 3), datetime(2021, 10, 5), datetime(2021, 10, 7), datetime(2021, 10, 9), datetime(2021, 10, 11) ] data = np.random.rand(6) ts = pd.Series(data, index=dates) print(ts) # 2021-10-01 0.956685 # 2021-10-03 0.817168 # 2021-10-05 0.275543 # 2021-10-07 0.614226 # 2021-10-09 0.061377 # 2021-10-11 0.357080 # dtype: float64 resampler = ts.resample('D') # \u5b57\u7b26\u4e32\u2019D\u2019\u88ab\u89e3\u91ca\u4e3a\u6bcf\u65e5\u9891\u7387 print(resampler) # DatetimeIndexResampler [freq=, axis=0, closed=left, label=left, convention=start, origin=start_day]","title":"\u65e5\u671f\u8303\u56f4\u3001\u9891\u7387\u548c\u79fb\u4f4d"},{"location":"python/DataAnalysis/ch08/#_7","text":"pandas.date_range \u662f\u7528\u4e8e\u6839\u636e\u7279\u5b9a\u9891\u7387\u751f\u6210\u6307\u5b9a\u957f\u5ea6\u7684 DatetimeIndex \u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c date_range \u751f\u6210\u7684\u662f\u6bcf\u65e5\u7684\u65f6\u95f4\u6233\u3002\u5982\u679c\u53ea\u4f20\u9012\u4e00\u4e2a\u8d77\u59cb\u6216\u7ed3\u5c3e\u65e5\u671f\uff0c\u4f60\u5fc5\u987b\u4f20\u9012\u4e00\u4e2a\u7528\u4e8e\u751f\u6210\u8303\u56f4\u7684\u6570\u5b57\u3002 \u5f00\u59cb\u65e5\u671f\u548c\u7ed3\u675f\u65e5\u671f\u4e25\u683c\u5b9a\u4e49\u4e86\u751f\u6210\u65e5\u671f\u7d22\u5f15\u7684\u8fb9\u754c\u3002 index = pd.date_range('2021/1/1', '2021/1/30') print(index) index = pd.date_range(start='2021/1/1', periods=30) print(index) index = pd.date_range(end='2021/1/30', periods=30) print(index) # DatetimeIndex(['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', # '2021-01-05', '2021-01-06', '2021-01-07', '2021-01-08', # '2021-01-09', '2021-01-10', '2021-01-11', '2021-01-12', # '2021-01-13', '2021-01-14', '2021-01-15', '2021-01-16', # '2021-01-17', '2021-01-18', '2021-01-19', '2021-01-20', # '2021-01-21', '2021-01-22', '2021-01-23', '2021-01-24', # '2021-01-25', '2021-01-26', '2021-01-27', '2021-01-28', # '2021-01-29', '2021-01-30'], # dtype='datetime64[ns]', freq='D') \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c date_range \u4fdd\u7559\u5f00\u59cb\u6216\u7ed3\u675f\u65f6\u95f4\u6233\u7684\u65f6\u95f4\uff08\u5982\u679c\u6709\u7684\u8bdd\uff09\u3002 normalize \u9009\u9879\u53ef\u4ee5\u5b9e\u73b0\u751f\u6210\u7684\u662f\u6807\u51c6\u5316\u4e3a\u96f6\u70b9\u7684\u65f6\u95f4\u6233\u3002 index = pd.date_range('2021/1/1 12:56:30', periods=5) print(index) # DatetimeIndex(['2021-01-01 12:56:30', '2021-01-02 12:56:30', # '2021-01-03 12:56:30', '2021-01-04 12:56:30', # '2021-01-05 12:56:30'], # dtype='datetime64[ns]', freq='D') index = pd.date_range('2021/1/1 12:56:30', periods=5, normalize=True) print(index) # DatetimeIndex(['2021-01-01', '2021-01-02', '2021-01-03', '2021-01-04', # '2021-01-05'], # dtype='datetime64[ns]', freq='D') Pandas\u65f6\u95f4\u5e8f\u5217\uff1a\u9891\u7387\u548c\u65e5\u671f\u504f\u79fb\u91cf\u3002 pandas\u4e2d\u7684\u9891\u7387\u662f\u7531\u4e00\u4e2a\u57fa\u7840\u9891\u7387(\u4f8b\u5982\u201c\u65e5\u201d\u3001\u201c\u6708\u201d)\u548c\u4e00\u4e2a\u4e58\u6570\u7ec4\u6210\u3002 \u57fa\u7840\u9891\u7387\u901a\u5e38\u4ee5\u4e00\u4e2a\u5b57\u7b26\u4e32\u522b\u540d\u8868\u793a\uff0c\u6bd4\u5982\u201cD\u201d\u8868\u793a\u65e5\uff0c\u201cM\u201d\u8868\u793a\u6708\u3002 \u5bf9\u4e8e\u6bcf\u4e2a\u57fa\u7840\u9891\u7387\uff0c\u90fd\u6709\u4e00\u4e2a\u88ab\u79f0\u4e3a\u65e5\u671f\u504f\u79fb\u91cf(dateoffset)\u7684\u5bf9\u8c61\u4e0e\u4e4b\u5bf9\u5e94\uff0c\u6bd4\u5982\u65e5\u671f\u504f\u79fb\u91cf Hour \u5bf9\u5e94\u7684\u9891\u7387\u662f H \u3002 \u5e38\u7528\u9891\u7387\u4e0e\u65e5\u671f\u504f\u79fb\u91cf\u3002 \u9891\u7387 \u65e5\u671f\u504f\u79fb\u91cf \u8bf4\u660e D Day \u65e5\u5386\u65e5 B BusinessDay \u5de5\u4f5c\u65e5 H Hour \u5c0f\u65f6 T/min Minute \u5206 S Second \u79d2 L/ms Milli \u6beb\u79d2 U Micro \u5fae\u79d2 M MonthEnd \u6bcf\u6708\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5 BM BusinessMonthEnd \u6bcf\u6708\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5 MS MonthBegin \u6bcf\u6708\u7b2c\u4e00\u4e2a\u65e5\u5386\u65e5 BMS BussinessMonthBegin \u6bcf\u6708\u7b2c\u4e00\u4e2a\u5de5\u4f5c\u65e5 W-MON, W-TUE, ... Week \u6307\u5b9a\u661f\u671f\u51e0(MON,TUE,WED,THU,FRI,SAT,SUN) WOM-1MON,WOM-2MON, ... WeekOfMonth \u4ea7\u751f\u6bcf\u6708\u7b2c\u4e00,\u7b2c\u4e8c,\u7b2c\u4e09\u6216\u7b2c\u56db\u5468\u7684\u661f\u671f\u51e0\u3002\u4f8b\u5982WOM-3FRI\u8868\u793a\u6bcf\u6708\u7b2c3\u4e2a\u661f\u671f\u4e94 Q-JAN,Q-FEB, ... QuarterEnd \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5 BQ-JAN,BQ-FEB, ... BusinessQuarterEnd \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5 QS-JAN,QS-FEB, ... QuarterBegin \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u7b2c\u4e00\u4e2a\u65e5\u5386\u65e5 BQS-JAN,BQS-FEB, ... BusinessQuarterBegin \u4ee5\u6307\u5b9a\u6708\u4efd\u7ed3\u675f\u7684\u5e74\u5ea6\uff0c\u6bcf\u5b63\u5ea6\u6700\u540e\u4e00\u4e2a\u6708\u7684\u7b2c\u4e00\u4e2a\u5de5\u4f5c\u65e5 A-JAN,A-FEB, ... YearEnd \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5 BA-JAN,BA-FEB, ... BusinessYearEnd \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5 AS-JAN,AS-FEB, ... YearBegin \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u7b2c\u4e00\u4e2a\u65e5\u5386\u65e5 BAS-JAN,BAS-FEB, ... BusinessYearBegin \u6bcf\u5e74\u6307\u5b9a\u6708\u4efd\u7684\u7b2c\u4e00\u4e2a\u5de5\u4f5c\u65e5","title":"\u751f\u6210\u65e5\u671f\u8303\u56f4"},{"location":"python/DataAnalysis/ch08/#_8","text":"pandas\u4e2d\u7684\u9891\u7387\u662f\u7531\u57fa\u7840\u9891\u7387\u548c\u500d\u6570\u7ec4\u6210\u7684\u3002 \u57fa\u7840\u9891\u7387\u901a\u5e38\u4f1a\u6709\u5b57\u7b26\u4e32\u522b\u540d\uff0c\u4f8b\u5982 M \u4ee3\u8868\u6bcf\u6708\uff0c H \u4ee3\u8868\u6bcf\u5c0f\u65f6\u3002 \u5bf9\u4e8e\u6bcf\u4e2a\u57fa\u7840\u9891\u7387\uff0c\u90fd\u6709\u4e00\u4e2a\u5bf9\u8c61\u53ef\u4ee5\u88ab\u7528\u4e8e\u5b9a\u4e49\u65e5\u671f\u504f\u7f6e\u3002 \u4f8b\u5982\uff0c\u6bcf\u5c0f\u65f6\u7684\u9891\u7387\u53ef\u4ee5\u4f7f\u7528 Hour \u7c7b\u6765\u8868\u793a\uff1a ```hour = Hour() print(hour)","title":"\u9891\u7387\u548c\u65e5\u671f\u504f\u7f6e"},{"location":"python/DataAnalysis/ch08/#_9","text":"\u53ef\u4ee5\u4f20\u9012\u4e00\u4e2a\u6574\u6570\u6765\u5b9a\u4e49\u504f\u7f6e\u91cf\u7684\u500d\u6570\uff1a four_hours = Hour(4) print(four_hours)","title":""},{"location":"python/DataAnalysis/ch08/#4-hours","text":"\u5728\u5927\u591a\u6570\u5e94\u7528\u4e2d\uff0c\u4e0d\u9700\u8981\u663e\u5f0f\u5730\u521b\u5efa\u8fd9\u4e9b\u5bf9\u8c61\uff0c\u800c\u662f\u4f7f\u7528\u5b57\u7b26\u4e32\u522b\u540d\uff0c\u5982`H`\u6216`4H`\u3002\u5728\u57fa\u7840\u9891\u7387\u524d\u653e\u4e00\u4e2a\u6574\u6570\u5c31\u53ef\u4ee5\u751f\u6210\u500d\u6570\uff1a ts = pd.date_range('2021/1/1', '2021/\u00bd 23:59', freq='4h') print(ts)","title":"<4 * Hours>"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-01-01-000000-2021-01-01-040000","text":"","title":"DatetimeIndex(['2021-01-01 00:00:00', '2021-01-01 04:00:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-01-080000-2021-01-01-120000","text":"","title":"'2021-01-01 08:00:00', '2021-01-01 12:00:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-01-160000-2021-01-01-200000","text":"","title":"'2021-01-01 16:00:00', '2021-01-01 20:00:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-02-000000-2021-01-02-040000","text":"","title":"'2021-01-02 00:00:00', '2021-01-02 04:00:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-02-080000-2021-01-02-120000","text":"","title":"'2021-01-02 08:00:00', '2021-01-02 12:00:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-02-160000-2021-01-02-200000","text":"","title":"'2021-01-02 16:00:00', '2021-01-02 20:00:00'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-freq4h","text":"\u591a\u4e2a\u504f\u7f6e\u53ef\u4ee5\u901a\u8fc7\u52a0\u6cd5\u8fdb\u884c\u8054\u5408\uff1a print(Hour(2) + Minute(30))","title":"dtype='datetime64[ns]', freq='4H')"},{"location":"python/DataAnalysis/ch08/#150-minutes","text":"\u7c7b\u4f3c\u5730\uff0c\u53ef\u4ee5\u4f20\u9012\u9891\u7387\u5b57\u7b26\u4e32\uff1a ts = pd.date_range('2021/1/1', '2021/1/1 23:59', freq='4h30min') print(ts)","title":"<150 * Minutes>"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-01-01-000000-2021-01-01-043000","text":"","title":"DatetimeIndex(['2021-01-01 00:00:00', '2021-01-01 04:30:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-01-090000-2021-01-01-133000","text":"","title":"'2021-01-01 09:00:00', '2021-01-01 13:30:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-01-180000-2021-01-01-223000","text":"","title":"'2021-01-01 18:00:00', '2021-01-01 22:30:00'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-freq270t","text":"\u6709\u4e9b\u9891\u7387\u63cf\u8ff0\u70b9\u7684\u65f6\u95f4\u5e76\u4e0d\u662f\u5747\u5300\u5206\u9694\u7684\u3002\u4f8b\u5982\uff0c`M`\uff08\u65e5\u5386\u6708\u672b\uff09\u548c`BM`\uff08\u6708\u5185\u6700\u540e\u5de5\u4f5c\u65e5\uff09\u53d6\u51b3\u4e8e\u5f53\u6708\u5929\u6570\uff0c\u6708\u672b\u662f\u5426\u662f\u5468\u672b\u3002\u6211\u4eec\u5c06\u8fd9\u4e9b\u65e5\u671f\u79f0\u4e3a\u951a\u5b9a\u504f\u7f6e\u91cf\u3002 #### \u6708\u4e2d\u67d0\u661f\u671f\u7684\u65e5\u671f \"\u6708\u4e2d\u67d0\u661f\u671f\"\uff08week of month \uff09\u7684\u65e5\u671f\u662f\u4e00\u4e2a\u6709\u7528\u7684\u9891\u7387\u7c7b\uff0c\u4ee5`WOM`\u5f00\u59cb\u3002 rng = pd.date_range('2021-1-1', '2021-9-1', freq='WOM-3FRI') # \u6bcf\u6708\u7b2c\u4e09\u4e2a\u661f\u671f\u4e94 print(rng)","title":"dtype='datetime64[ns]', freq='270T')"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-01-15-2021-02-19-2021-03-19-2021-04-16","text":"","title":"DatetimeIndex(['2021-01-15', '2021-02-19', '2021-03-19', '2021-04-16',"},{"location":"python/DataAnalysis/ch08/#2021-05-21-2021-06-18-2021-07-16-2021-08-20","text":"","title":"'2021-05-21', '2021-06-18', '2021-07-16', '2021-08-20'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-freqwom-3fri","text":"### \u79fb\u4f4d\uff08\u524d\u5411\u548c\u540e\u5411\uff09\u65e5\u671f \"\u79fb\u4f4d\"\u662f\u6307\u5c06\u65e5\u671f\u6309\u65f6\u95f4\u5411\u524d\u79fb\u52a8\u6216\u5411\u540e\u79fb\u52a8\u3002 Series\u548cDataFrame\u90fd\u6709\u4e00\u4e2a`shift`\u65b9\u6cd5\u7528\u4e8e\u8fdb\u884c\u7b80\u5355\u7684\u524d\u5411\u6216\u540e\u5411\u79fb\u4f4d\uff0c\u800c\u4e0d\u6539\u53d8\u7d22\u5f15\u3002 \u8fdb\u884c\u79fb\u4f4d\u65f6\uff0c\u4f1a\u5728\u65f6\u95f4\u5e8f\u5217\u7684\u8d77\u59cb\u4f4d\u6216\u7ed3\u675f\u4f4d\u5f15\u5165\u7f3a\u5931\u503c\u3002 data = [0.882972, 1.363282, -0.687750, -0.048117] ts = pd.Series(data, index=pd.date_range('2021-1-1', periods=4, freq='M')) print(ts)","title":"dtype='datetime64[ns]', freq='WOM-3FRI')"},{"location":"python/DataAnalysis/ch08/#2021-01-31-0882972","text":"","title":"2021-01-31 0.882972"},{"location":"python/DataAnalysis/ch08/#2021-02-28-1363282","text":"","title":"2021-02-28 1.363282"},{"location":"python/DataAnalysis/ch08/#2021-03-31-0687750","text":"","title":"2021-03-31 -0.687750"},{"location":"python/DataAnalysis/ch08/#2021-04-30-0048117","text":"","title":"2021-04-30 -0.048117"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64","text":"print(ts.shift(2))","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-31-nan","text":"","title":"2021-01-31 NaN"},{"location":"python/DataAnalysis/ch08/#2021-02-28-nan","text":"","title":"2021-02-28 NaN"},{"location":"python/DataAnalysis/ch08/#2021-03-31-0882972","text":"","title":"2021-03-31 0.882972"},{"location":"python/DataAnalysis/ch08/#2021-04-30-1363282","text":"","title":"2021-04-30 1.363282"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_1","text":"print(ts.shift(-2))","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-31-0687750","text":"","title":"2021-01-31 -0.687750"},{"location":"python/DataAnalysis/ch08/#2021-02-28-0048117","text":"","title":"2021-02-28 -0.048117"},{"location":"python/DataAnalysis/ch08/#2021-03-31-nan","text":"","title":"2021-03-31 NaN"},{"location":"python/DataAnalysis/ch08/#2021-04-30-nan","text":"","title":"2021-04-30 NaN"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_2","text":"`shift`\u5e38\u7528\u4e8e\u8ba1\u7b97\u65f6\u95f4\u5e8f\u5217\u6216DataFrame\u591a\u5217\u65f6\u95f4\u5e8f\u5217\u7684\u767e\u5206\u6bd4\u53d8\u5316\uff1a print(ts/ts.shift(1))","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-31-nan_1","text":"","title":"2021-01-31 NaN"},{"location":"python/DataAnalysis/ch08/#2021-02-28-1543970","text":"","title":"2021-02-28 1.543970"},{"location":"python/DataAnalysis/ch08/#2021-03-31-0504481","text":"","title":"2021-03-31 -0.504481"},{"location":"python/DataAnalysis/ch08/#2021-04-30-0069963","text":"","title":"2021-04-30 0.069963"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_3","text":"print(ts/ts.shift(1) - 1)","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-31-nan_2","text":"","title":"2021-01-31 NaN"},{"location":"python/DataAnalysis/ch08/#2021-02-28-0543970","text":"","title":"2021-02-28 0.543970"},{"location":"python/DataAnalysis/ch08/#2021-03-31-1504481","text":"","title":"2021-03-31 -1.504481"},{"location":"python/DataAnalysis/ch08/#2021-04-30-0930037","text":"","title":"2021-04-30 -0.930037"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_4","text":"\u5982\u679c\u9891\u7387\u662f\u5df2\u77e5\u7684\uff0c\u5219\u53ef\u4ee5\u5c06\u9891\u7387\u4f20\u9012\u7ed9`shift`\u6765\u63a8\u79fb\u65f6\u95f4\u6233\uff1a print(ts.shift(2, freq='M')) # \u539f\u59cb\u6570\u636e\u7684\u201c\u6708\u201c\u589e\u52a0\u4e86\u504f\u79fb\u503c","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-03-31-0882972_1","text":"","title":"2021-03-31 0.882972"},{"location":"python/DataAnalysis/ch08/#2022021-10-31-0000001-04-30-1363282","text":"","title":"2022021-10-31 00:00:001-04-30 1.363282"},{"location":"python/DataAnalysis/ch08/#2021-05-31-0687750","text":"","title":"2021-05-31 -0.687750"},{"location":"python/DataAnalysis/ch08/#2021-06-30-0048117","text":"","title":"2021-06-30 -0.048117"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_5","text":"print(ts.shift(2, freq='D')) # \u539f\u59cb\u6570\u636e\u7684\u201c\u65e5\u201c\u589e\u52a0\u4e86\u504f\u79fb\u503c","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-02-02-0882972","text":"","title":"2021-02-02 0.882972"},{"location":"python/DataAnalysis/ch08/#2021-03-02-1363282","text":"","title":"2021-03-02 1.363282"},{"location":"python/DataAnalysis/ch08/#2021-04-02-0687750","text":"","title":"2021-04-02 -0.687750"},{"location":"python/DataAnalysis/ch08/#2021-05-02-0048117","text":"","title":"2021-05-02 -0.048117"},{"location":"python/DataAnalysis/ch08/#dtype-float64","text":"print(ts.shift(2, freq='90T')) # \u539f\u59cb\u6570\u636e\u7684\u201c\u5c0f\u65f6\u201c\u589e\u52a0\u4e86\u504f\u79fb\u503c","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-31-030000-0882972","text":"","title":"2021-01-31 03:00:00 0.882972"},{"location":"python/DataAnalysis/ch08/#2021-02-28-030000-1363282","text":"","title":"2021-02-28 03:00:00 1.363282"},{"location":"python/DataAnalysis/ch08/#2021-03-31-030000-0687750","text":"","title":"2021-03-31 03:00:00 -0.687750"},{"location":"python/DataAnalysis/ch08/#2021-04-30-030000-0048117","text":"","title":"2021-04-30 03:00:00 -0.048117"},{"location":"python/DataAnalysis/ch08/#dtype-float64_1","text":"#### \u4f7f\u7528\u504f\u7f6e\u8fdb\u884c\u79fb\u4f4d\u65e5\u671f pandas\u65e5\u671f\u504f\u7f6e\u4e5f\u53ef\u4ee5\u4f7f\u7528`datetime`\u6216`Timestamp`\u5bf9\u8c61\u5b8c\u6210\uff1a now = datetime(2021, 10, 9) print(now)","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-10-09-000000","text":"print(now + 3 * Day())","title":"2021-10-09 00:00:00"},{"location":"python/DataAnalysis/ch08/#2021-10-12-000000","text":"\u951a\u5b9a\u504f\u7f6e\u53ef\u4ee5\u4f7f\u7528`rollforward`\u548c`rollback`\u5206\u522b\u663e\u5f0f\u5730\u5c06\u65e5\u671f\u5411\u524d\u6216\u5411\u540e\"\u6eda\u52a8\"\u3002 \u5982\u679c\u6dfb\u52a0\u4e86\u4e00\u4e2a\u951a\u5b9a\u504f\u7f6e\u91cf\uff0c\u6bd4\u5982`MonthEnd`\uff0c\u6839\u636e\u9891\u7387\u89c4\u5219\uff0c\u7b2c\u4e00\u4e2a\u589e\u91cf\u4f1a\u5c06\u65e5\u671f\u201c\u524d\u6eda\u201d\u5230\u4e0b\u4e00\u4e2a\u65e5\u671f\uff1a print(now + MonthEnd()) # \u201c\u524d\u6eda\u201d\u5230\u5f53\u524d\u6708\u7684\u6708\u5e95","title":"2021-10-12 00:00:00"},{"location":"python/DataAnalysis/ch08/#2021-10-31-000000","text":"print(now + MonthEnd(2)) # \u6ce8\u610f\u8fd9\u91cc\u7684\u5e8f\u5217\u53f7\uff0c\u5f53\u524d\u6708\u662f1,\u4e0b\u4e2a\u6708\u662f2","title":"2021-10-31 00:00:00"},{"location":"python/DataAnalysis/ch08/#2021-11-30-000000","text":"offset = MonthEnd() print(offset.rollback(now))","title":"2021-11-30 00:00:00"},{"location":"python/DataAnalysis/ch08/#2021-09-30-000000","text":"print(offset.rollforward(now))","title":"2021-09-30 00:00:00"},{"location":"python/DataAnalysis/ch08/#2021-10-31-000000_1","text":"\u5c06\u79fb\u4f4d\u65b9\u6cd5\u4e0e`groupby`\u4e00\u8d77\u4f7f\u7528\u662f\u65e5\u671f\u504f\u7f6e\u7684\u4e00\u79cd\u521b\u9020\u6027\u7528\u6cd5\uff1a ts = pd.Series( np.random.randn(20), index=pd.date_range('2021/1/1', periods=20, freq='4d') ) print(ts)","title":"2021-10-31 00:00:00"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0674348","text":"","title":"2021-01-01 0.674348"},{"location":"python/DataAnalysis/ch08/#2021-01-05-1437803","text":"","title":"2021-01-05 -1.437803"},{"location":"python/DataAnalysis/ch08/#2021-01-09-0079218","text":"","title":"2021-01-09 -0.079218"},{"location":"python/DataAnalysis/ch08/#2021-01-13-1444890","text":"","title":"2021-01-13 -1.444890"},{"location":"python/DataAnalysis/ch08/#2021-01-17-0643279","text":"","title":"2021-01-17 0.643279"},{"location":"python/DataAnalysis/ch08/#2021-01-21-1089965","text":"","title":"2021-01-21 1.089965"},{"location":"python/DataAnalysis/ch08/#2021-01-25-0021876","text":"","title":"2021-01-25 0.021876"},{"location":"python/DataAnalysis/ch08/#2021-01-29-0692138","text":"","title":"2021-01-29 0.692138"},{"location":"python/DataAnalysis/ch08/#2021-02-02-0833496","text":"","title":"2021-02-02 0.833496"},{"location":"python/DataAnalysis/ch08/#2021-02-06-1082616","text":"","title":"2021-02-06 1.082616"},{"location":"python/DataAnalysis/ch08/#2021-02-10-0729415","text":"","title":"2021-02-10 -0.729415"},{"location":"python/DataAnalysis/ch08/#2021-02-14-0271186","text":"","title":"2021-02-14 0.271186"},{"location":"python/DataAnalysis/ch08/#2021-02-18-1416218","text":"","title":"2021-02-18 -1.416218"},{"location":"python/DataAnalysis/ch08/#2021-02-22-0780402","text":"","title":"2021-02-22 -0.780402"},{"location":"python/DataAnalysis/ch08/#2021-02-26-0113773","text":"","title":"2021-02-26 -0.113773"},{"location":"python/DataAnalysis/ch08/#2021-03-02-2095338","text":"","title":"2021-03-02 2.095338"},{"location":"python/DataAnalysis/ch08/#2021-03-06-0302612","text":"","title":"2021-03-06 -0.302612"},{"location":"python/DataAnalysis/ch08/#2021-03-10-1113632","text":"","title":"2021-03-10 1.113632"},{"location":"python/DataAnalysis/ch08/#2021-03-14-1314581","text":"","title":"2021-03-14 -1.314581"},{"location":"python/DataAnalysis/ch08/#2021-03-18-0947746","text":"","title":"2021-03-18 0.947746"},{"location":"python/DataAnalysis/ch08/#freq-4d-dtype-float64","text":"print(ts.groupby(offset.rollforward).mean()) # \u524d\u6eda\u81f3\u5f53\u6708\u6708\u5e95\uff0c\u8ba1\u7b97\u5f53\u6708\u5e73\u5747\u503c","title":"Freq: 4D, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-31-0019962","text":"","title":"2021-01-31 0.019962"},{"location":"python/DataAnalysis/ch08/#2021-02-28-0121787","text":"","title":"2021-02-28 -0.121787"},{"location":"python/DataAnalysis/ch08/#2021-03-31-0507905","text":"","title":"2021-03-31 0.507905"},{"location":"python/DataAnalysis/ch08/#dtype-float64_2","text":"","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#resample","text":"print(ts.resample('M').mean())","title":"\u4f7f\u7528resample\u662f\u66f4\u7b80\u5355\u66f4\u5feb\u6377\u7684\u65b9\u6cd5"},{"location":"python/DataAnalysis/ch08/#2021-01-31-0019962_1","text":"","title":"2021-01-31 0.019962"},{"location":"python/DataAnalysis/ch08/#2021-02-28-0121787_1","text":"","title":"2021-02-28 -0.121787"},{"location":"python/DataAnalysis/ch08/#2021-03-31-0507905_1","text":"","title":"2021-03-31 0.507905"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_6","text":"## \u65f6\u533a\u5904\u7406 \u65f6\u533a\u901a\u5e38\u88ab\u8868\u793a\u4e3aUTC\u7684\u504f\u7f6e\u3002 \u5728Python\u8bed\u8a00\u4e2d\uff0c\u65f6\u533a\u4fe1\u606f\u6765\u6e90\u4e8e\u7b2c\u4e09\u65b9\u5e93pytz\uff08\u53ef\u4ee5\u4f7f\u7528pip\u6216conda\u5b89\u88c5\uff09\uff0c\u5176\u4e2d\u516c\u5f00\u4e86Olson\u6570\u636e\u5e93\uff0c\u8fd9\u662f\u4e16\u754c\u65f6\u533a\u4fe1\u606f\u7684\u6c47\u7f16\u3002 pandas\u5c01\u88c5\u4e86pytz\u7684\u529f\u80fd\u3002 from datetime import datetime, timedelta import pandas as pd import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd import pytz #### common_timezones tz = pytz.common_timezones[-5:] # \u8bfb\u53d6common_timezones\u8fd9\u4e2a\u5217\u8868\u7684\u6700\u540e5\u4e2a\u5143\u7d20 print(tz)","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#useastern-ushawaii-usmountain-uspacific-utc","text":"\u8981\u83b7\u5f97pytz\u7684\u65f6\u533a\u5bf9\u8c61\uff0c\u53ef\u4f7f\u7528pytz.timezone\uff1a tz = pytz.timezone('Asia/Shanghai') print(tz) #### \u65f6\u533a\u7684\u672c\u5730\u5316\u548c\u8f6c\u6362 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cpandas\u4e2d\u7684\u65f6\u95f4\u5e8f\u5217\u662f\u65f6\u533a\u7b80\u5355\u578b\u7684\u3002 rng = pd.date_range('2021/1/1 9:30', periods=6, freq='D') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(rng)","title":"['US/Eastern', 'US/Hawaii', 'US/Mountain', 'US/Pacific', 'UTC']"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-01-01-093000-2021-01-02-093000","text":"","title":"DatetimeIndex(['2021-01-01 09:30:00', '2021-01-02 09:30:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-03-093000-2021-01-04-093000","text":"","title":"'2021-01-03 09:30:00', '2021-01-04 09:30:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-05-093000-2021-01-06-093000","text":"","title":"'2021-01-05 09:30:00', '2021-01-06 09:30:00'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-freqd","text":"print(ts)","title":"dtype='datetime64[ns]', freq='D')"},{"location":"python/DataAnalysis/ch08/#2021-01-01-093000-0339822","text":"","title":"2021-01-01 09:30:00 0.339822"},{"location":"python/DataAnalysis/ch08/#2021-01-02-093000-1356382","text":"","title":"2021-01-02 09:30:00 1.356382"},{"location":"python/DataAnalysis/ch08/#2021-01-03-093000-0475429","text":"","title":"2021-01-03 09:30:00 0.475429"},{"location":"python/DataAnalysis/ch08/#2021-01-04-093000-1826654","text":"","title":"2021-01-04 09:30:00 1.826654"},{"location":"python/DataAnalysis/ch08/#2021-01-05-093000-0245510","text":"","title":"2021-01-05 09:30:00 -0.245510"},{"location":"python/DataAnalysis/ch08/#2021-01-06-093000-0705274","text":"","title":"2021-01-06 09:30:00 0.705274"},{"location":"python/DataAnalysis/ch08/#freq-d-dtype-float64","text":"print(ts.index.tz) # \u7d22\u5f15\u7684tz\u5c5e\u6027\u662fNone","title":"Freq: D, dtype: float64"},{"location":"python/DataAnalysis/ch08/#none","text":"\u65e5\u671f\u8303\u56f4\u53ef\u4ee5\u901a\u8fc7\u65f6\u533a\u96c6\u5408\u6765\u751f\u6210\uff1a rng = pd.date_range('2021/3/1', periods=10, freq='D', tz='UTC') print(rng)","title":"None"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-03-01-0000000000-2021-03-02-0000000000","text":"","title":"DatetimeIndex(['2021-03-01 00:00:00+00:00', '2021-03-02 00:00:00+00:00',"},{"location":"python/DataAnalysis/ch08/#2021-03-03-0000000000-2021-03-04-0000000000","text":"","title":"'2021-03-03 00:00:00+00:00', '2021-03-04 00:00:00+00:00',"},{"location":"python/DataAnalysis/ch08/#2021-03-05-0000000000-2021-03-06-0000000000","text":"","title":"'2021-03-05 00:00:00+00:00', '2021-03-06 00:00:00+00:00',"},{"location":"python/DataAnalysis/ch08/#2021-03-07-0000000000-2021-03-08-0000000000","text":"","title":"'2021-03-07 00:00:00+00:00', '2021-03-08 00:00:00+00:00',"},{"location":"python/DataAnalysis/ch08/#2021-03-09-0000000000-2021-03-10-0000000000","text":"","title":"'2021-03-09 00:00:00+00:00', '2021-03-10 00:00:00+00:00'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-utc-freqd","text":"\u4f7f\u7528`tz_localize`\u65b9\u6cd5\u53ef\u4ee5\u4ece\u7b80\u5355\u65f6\u533a\u8f6c\u6362\u5230\u672c\u5730\u5316\u65f6\u533a\uff1a print(ts)","title":"dtype='datetime64[ns, UTC]', freq='D')"},{"location":"python/DataAnalysis/ch08/#2021-01-01-093000-0294647","text":"","title":"2021-01-01 09:30:00 0.294647"},{"location":"python/DataAnalysis/ch08/#2021-01-02-093000-0958414","text":"","title":"2021-01-02 09:30:00 0.958414"},{"location":"python/DataAnalysis/ch08/#2021-01-03-093000-0424235","text":"","title":"2021-01-03 09:30:00 0.424235"},{"location":"python/DataAnalysis/ch08/#2021-01-04-093000-1714333","text":"","title":"2021-01-04 09:30:00 -1.714333"},{"location":"python/DataAnalysis/ch08/#2021-01-05-093000-0030319","text":"","title":"2021-01-05 09:30:00 -0.030319"},{"location":"python/DataAnalysis/ch08/#2021-01-06-093000-0744940","text":"","title":"2021-01-06 09:30:00 -0.744940"},{"location":"python/DataAnalysis/ch08/#freq-d-dtype-float64_1","text":"print(ts.tz_localize('UTC'))","title":"Freq: D, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0930000000-0294647","text":"","title":"2021-01-01 09:30:00+00:00 0.294647"},{"location":"python/DataAnalysis/ch08/#2021-01-02-0930000000-0958414","text":"","title":"2021-01-02 09:30:00+00:00 0.958414"},{"location":"python/DataAnalysis/ch08/#2021-01-03-0930000000-0424235","text":"","title":"2021-01-03 09:30:00+00:00 0.424235"},{"location":"python/DataAnalysis/ch08/#2021-01-04-0930000000-1714333","text":"","title":"2021-01-04 09:30:00+00:00 -1.714333"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000000-0030319","text":"","title":"2021-01-05 09:30:00+00:00 -0.030319"},{"location":"python/DataAnalysis/ch08/#2021-01-06-0930000000-0744940","text":"","title":"2021-01-06 09:30:00+00:00 -0.744940"},{"location":"python/DataAnalysis/ch08/#freq-d-dtype-float64_2","text":"print(ts.tz_localize('Asia/Shanghai'))","title":"Freq: D, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0930000800-0052521","text":"","title":"2021-01-01 09:30:00+08:00 0.052521"},{"location":"python/DataAnalysis/ch08/#2021-01-02-0930000800-0305417","text":"","title":"2021-01-02 09:30:00+08:00 -0.305417"},{"location":"python/DataAnalysis/ch08/#2021-01-03-0930000800-0150215","text":"","title":"2021-01-03 09:30:00+08:00 0.150215"},{"location":"python/DataAnalysis/ch08/#2021-01-04-0930000800-0953715","text":"","title":"2021-01-04 09:30:00+08:00 -0.953715"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000800-0543622","text":"","title":"2021-01-05 09:30:00+08:00 0.543622"},{"location":"python/DataAnalysis/ch08/#2021-01-06-0930000800-0222422","text":"","title":"2021-01-06 09:30:00+08:00 0.222422"},{"location":"python/DataAnalysis/ch08/#dtype-float64_3","text":"print(ts.tz_localize('Asia/Shanghai').index)","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-01-01-0930000800-2021-01-02-0930000800","text":"","title":"DatetimeIndex(['2021-01-01 09:30:00+08:00', '2021-01-02 09:30:00+08:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-03-0930000800-2021-01-04-0930000800","text":"","title":"'2021-01-03 09:30:00+08:00', '2021-01-04 09:30:00+08:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000800-2021-01-06-0930000800","text":"","title":"'2021-01-05 09:30:00+08:00', '2021-01-06 09:30:00+08:00'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-asiashanghai-freqnone","text":"\u4e00\u65e6\u65f6\u95f4\u5e8f\u5217\u88ab\u672c\u5730\u5316\u4e3a\u67d0\u4e2a\u7279\u5b9a\u7684\u65f6\u533a\uff0c\u5219\u53ef\u4ee5\u901a\u8fc7`tz_convert`\u5c06\u5176\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u65f6\u533a\uff1a tz_sha = ts.tz_localize('Asia/Shanghai') tz_utc = tz_sha.tz_convert('UTC') print(tz_sha)","title":"dtype='datetime64[ns, Asia/Shanghai]', freq=None)"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0930000800-0095689","text":"","title":"2021-01-01 09:30:00+08:00 0.095689"},{"location":"python/DataAnalysis/ch08/#2021-01-02-0930000800-0392730","text":"","title":"2021-01-02 09:30:00+08:00 -0.392730"},{"location":"python/DataAnalysis/ch08/#2021-01-03-0930000800-0151468","text":"","title":"2021-01-03 09:30:00+08:00 0.151468"},{"location":"python/DataAnalysis/ch08/#2021-01-04-0930000800-0027467","text":"","title":"2021-01-04 09:30:00+08:00 0.027467"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000800-0393709","text":"","title":"2021-01-05 09:30:00+08:00 0.393709"},{"location":"python/DataAnalysis/ch08/#2021-01-06-0930000800-0872914","text":"","title":"2021-01-06 09:30:00+08:00 0.872914"},{"location":"python/DataAnalysis/ch08/#dtype-float64_4","text":"print(tz_utc)","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0130000000-0095689","text":"","title":"2021-01-01 01:30:00+00:00 0.095689"},{"location":"python/DataAnalysis/ch08/#2021-01-02-0130000000-0392730","text":"","title":"2021-01-02 01:30:00+00:00 -0.392730"},{"location":"python/DataAnalysis/ch08/#2021-01-03-0130000000-0151468","text":"","title":"2021-01-03 01:30:00+00:00 0.151468"},{"location":"python/DataAnalysis/ch08/#2021-01-04-0130000000-0027467","text":"","title":"2021-01-04 01:30:00+00:00 0.027467"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0130000000-0393709","text":"","title":"2021-01-05 01:30:00+00:00 0.393709"},{"location":"python/DataAnalysis/ch08/#2021-01-06-0130000000-0872914","text":"","title":"2021-01-06 01:30:00+00:00 0.872914"},{"location":"python/DataAnalysis/ch08/#dtype-float64_5","text":"","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#tz_localizetz_convertdatetimeindex","text":"print(ts.index.tz_localize('Asia/Shanghai'))","title":"tz_localize\u548ctz_convert\u4e5f\u662fDatetimeIndex\u7684\u5b9e\u4f8b\u65b9\u6cd5\uff1a"},{"location":"python/DataAnalysis/ch08/#datetimeindex2021-01-01-0930000800-2021-01-02-0930000800_1","text":"","title":"DatetimeIndex(['2021-01-01 09:30:00+08:00', '2021-01-02 09:30:00+08:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-03-0930000800-2021-01-04-0930000800_1","text":"","title":"'2021-01-03 09:30:00+08:00', '2021-01-04 09:30:00+08:00',"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000800-2021-01-06-0930000800_1","text":"","title":"'2021-01-05 09:30:00+08:00', '2021-01-06 09:30:00+08:00'],"},{"location":"python/DataAnalysis/ch08/#dtypedatetime64ns-asiashanghai-freqnone_1","text":"### \u65f6\u533a\u611f\u77e5\u65f6\u95f4\u6233\u5bf9\u8c61\u7684\u64cd\u4f5c \u4e0e\u65f6\u95f4\u5e8f\u5217\u548c\u65e5\u671f\u8303\u56f4\u7c7b\u4f3c\uff0c\u5355\u72ec\u7684`Timestamp`\u5bf9\u8c61\u4e5f\u53ef\u4ee5\u4ece\u7b80\u5355\u65f6\u95f4\u6233\u672c\u5730\u5316\u4e3a\u65f6\u533a\u611f\u77e5\u65f6\u95f4\u6233\uff0c\u5e76\u4ece\u4e00\u4e2a\u65f6\u533a\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u65f6\u533a\uff1a stamp = pd.Timestamp('2021-5-1 05:30') print(stamp)","title":"dtype='datetime64[ns, Asia/Shanghai]', freq=None)"},{"location":"python/DataAnalysis/ch08/#2021-05-01-053000","text":"stamp_utc = stamp.tz_localize('utc') print(stamp_utc)","title":"2021-05-01 05:30:00"},{"location":"python/DataAnalysis/ch08/#2021-05-01-0530000000","text":"stamp_sha = stamp_utc.tz_convert('Asia/Shanghai') print(stamp_sha)","title":"2021-05-01 05:30:00+00:00"},{"location":"python/DataAnalysis/ch08/#2021-05-01-1330000800","text":"\u4e5f\u53ef\u4ee5\u5728\u521b\u5efa`Timestamp`\u7684\u65f6\u5019\u4f20\u9012\u4e00\u4e2a\u65f6\u533a\uff1a stamp_sha = pd.Timestamp('2021-5-1 05:30', tz='Asia/Shanghai') print(stamp_sha)","title":"2021-05-01 13:30:00+08:00"},{"location":"python/DataAnalysis/ch08/#2021-05-01-0530000800","text":"`Timestamp`\u5bf9\u8c61\u5185\u90e8\u5b58\u50a8\u4e86\u4e00\u4e2aUnix\u7eaa\u5143(1970\u5e741\u67081\u65e5)\u81f3\u4eca\u7684\u7eb3\u79d2\u6570\u91cfUTC\u65f6\u95f4\u6233\u6570\u503c\uff0c\u8be5\u6570\u503c\u5728\u65f6\u533a\u8f6c\u6362\u4e2d\u662f\u4e0d\u53d8\u7684\uff1a print(stamp_utc.value)","title":"2021-05-01 05:30:00+08:00"},{"location":"python/DataAnalysis/ch08/#1619847000000000000","text":"print(stamp_utc.tz_convert('Asia/Shanghai').value)","title":"1619847000000000000"},{"location":"python/DataAnalysis/ch08/#1619847000000000000_1","text":"\u5728\u4f7f\u7528pandas\u7684`DateOffset`\u8fdb\u884c\u65f6\u95f4\u7b97\u672f\u65f6\uff0cpandas\u5c3d\u53ef\u80fd\u9075\u4ece\u590f\u65f6\u5236\u3002 \u9996\u5148\uff0c\u6784\u9020\u8f6c\u6362\u5230DST\u4e4b\u524d\u768430\u5206\u949f\u7684\u65f6\u95f4\uff1a stamp = pd.Timestamp('2012-3-12 1:30', tz='US/Eastern') print(stamp)","title":"1619847000000000000"},{"location":"python/DataAnalysis/ch08/#2012-03-12-013000-0400","text":"print(stamp + Hour())","title":"2012-03-12 01:30:00-04:00"},{"location":"python/DataAnalysis/ch08/#2012-03-12-023000-0400","text":"\u4e4b\u540e\uff0c\u6784\u5efa\u4eceDST\u8fdb\u884c\u8f6c\u6362\u524d\u768490\u5206\u949f\uff1a stamp = pd.Timestamp('2012-11-04 0:30-04:00', tz='US/Eastern') print(stamp)","title":"2012-03-12 02:30:00-04:00"},{"location":"python/DataAnalysis/ch08/#2012-11-04-003000-0400","text":"print(stamp + 2 * Hour()) # \u53ea\u589e\u52a0\u4e86\u4e00\u5c0f\u65f6","title":"2012-11-04 00:30:00-04:00"},{"location":"python/DataAnalysis/ch08/#2012-11-04-013000-0500","text":"### \u4e0d\u540c\u65f6\u533a\u95f4\u7684\u64cd\u4f5c \u5982\u679c\u4e24\u4e2a\u65f6\u533a\u4e0d\u540c\u7684\u65f6\u95f4\u5e8f\u5217\u9700\u8981\u8054\u5408\uff0c\u90a3\u4e48\u7ed3\u679c\u5c06\u662fUTC\u65f6\u95f4\u7684\uff0c\u56e0\u4e3a\u65f6\u95f4\u6233\u4ee5UTC\u683c\u5f0f\u5b58\u50a8\u3002 rng = pd.date_range('2021/1/1 9:30', periods=9, freq='B') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(ts)","title":"2012-11-04 01:30:00-05:00"},{"location":"python/DataAnalysis/ch08/#2021-01-01-093000-0715681","text":"","title":"2021-01-01 09:30:00 0.715681"},{"location":"python/DataAnalysis/ch08/#2021-01-04-093000-0524563","text":"","title":"2021-01-04 09:30:00 0.524563"},{"location":"python/DataAnalysis/ch08/#2021-01-05-093000-0482199","text":"","title":"2021-01-05 09:30:00 -0.482199"},{"location":"python/DataAnalysis/ch08/#2021-01-06-093000-0661303","text":"","title":"2021-01-06 09:30:00 -0.661303"},{"location":"python/DataAnalysis/ch08/#2021-01-07-093000-1750010","text":"","title":"2021-01-07 09:30:00 1.750010"},{"location":"python/DataAnalysis/ch08/#2021-01-08-093000-0251478","text":"","title":"2021-01-08 09:30:00 0.251478"},{"location":"python/DataAnalysis/ch08/#2021-01-11-093000-1487268","text":"","title":"2021-01-11 09:30:00 -1.487268"},{"location":"python/DataAnalysis/ch08/#2021-01-12-093000-0224024","text":"","title":"2021-01-12 09:30:00 -0.224024"},{"location":"python/DataAnalysis/ch08/#2021-01-13-093000-1621853","text":"","title":"2021-01-13 09:30:00 -1.621853"},{"location":"python/DataAnalysis/ch08/#freq-b-dtype-float64","text":"ts1 = ts[:7].tz_localize('Europe/London') ts2 = ts1[2:].tz_convert('Europe/Moscow') result = ts1 + ts2 print(ts1)","title":"Freq: B, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0930000000-1393445","text":"","title":"2021-01-01 09:30:00+00:00 -1.393445"},{"location":"python/DataAnalysis/ch08/#2021-01-04-0930000000-1179614","text":"","title":"2021-01-04 09:30:00+00:00 -1.179614"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000000-0716669","text":"","title":"2021-01-05 09:30:00+00:00 0.716669"},{"location":"python/DataAnalysis/ch08/#2021-01-06-0930000000-0485656","text":"","title":"2021-01-06 09:30:00+00:00 -0.485656"},{"location":"python/DataAnalysis/ch08/#2021-01-07-0930000000-0433000","text":"","title":"2021-01-07 09:30:00+00:00 0.433000"},{"location":"python/DataAnalysis/ch08/#2021-01-08-0930000000-1540745","text":"","title":"2021-01-08 09:30:00+00:00 1.540745"},{"location":"python/DataAnalysis/ch08/#2021-01-11-0930000000-0343751","text":"","title":"2021-01-11 09:30:00+00:00 0.343751"},{"location":"python/DataAnalysis/ch08/#dtype-float64_6","text":"print(ts2)","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-05-1230000300-0716669","text":"","title":"2021-01-05 12:30:00+03:00 0.716669"},{"location":"python/DataAnalysis/ch08/#2021-01-06-1230000300-0485656","text":"","title":"2021-01-06 12:30:00+03:00 -0.485656"},{"location":"python/DataAnalysis/ch08/#2021-01-07-1230000300-0433000","text":"","title":"2021-01-07 12:30:00+03:00 0.433000"},{"location":"python/DataAnalysis/ch08/#2021-01-08-1230000300-1540745","text":"","title":"2021-01-08 12:30:00+03:00 1.540745"},{"location":"python/DataAnalysis/ch08/#2021-01-11-1230000300-0343751","text":"","title":"2021-01-11 12:30:00+03:00 0.343751"},{"location":"python/DataAnalysis/ch08/#dtype-float64_7","text":"print(result)","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021-01-01-0930000000-nan","text":"","title":"2021-01-01 09:30:00+00:00 NaN"},{"location":"python/DataAnalysis/ch08/#2021-01-04-0930000000-nan","text":"","title":"2021-01-04 09:30:00+00:00 NaN"},{"location":"python/DataAnalysis/ch08/#2021-01-05-0930000000-1433337","text":"","title":"2021-01-05 09:30:00+00:00 1.433337"},{"location":"python/DataAnalysis/ch08/#2021-01-06-0930000000-0971312","text":"","title":"2021-01-06 09:30:00+00:00 -0.971312"},{"location":"python/DataAnalysis/ch08/#2021-01-07-0930000000-0866000","text":"","title":"2021-01-07 09:30:00+00:00 0.866000"},{"location":"python/DataAnalysis/ch08/#2021-01-08-0930000000-3081489","text":"","title":"2021-01-08 09:30:00+00:00 3.081489"},{"location":"python/DataAnalysis/ch08/#2021-01-11-0930000000-0687502","text":"","title":"2021-01-11 09:30:00+00:00 0.687502"},{"location":"python/DataAnalysis/ch08/#dtype-float64_8","text":"## \u65f6\u95f4\u533a\u95f4\u548c\u533a\u95f4\u7b97\u672f from datetime import datetime, timedelta import pandas as pd import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd import pytz \u65f6\u95f4\u533a\u95f4\u8868\u793a\u7684\u662f\u65f6\u95f4\u8303\u56f4\u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628a`year`\u548c`quarter`\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f15\uff0c\u6bd4\u5982\u4e00\u4e9b\u5929\u3001\u4e00\u4e9b\u6708\u3001\u4e00\u4e9b\u5b63\u5ea6\u6216\u8005\u662f\u4e00\u4e9b\u5e74\u3002 `Period`\u7c7b\u8868\u793a\u7684\u6b63\u662f\u8fd9\u79cd\u6570\u636e\u7c7b\u578b\uff0c\u9700\u8981\u4e00\u4e2a\u5b57\u7b26\u4e32\u6216\u6570\u5b57\u4ee5\u53ca\u9891\u7387\u3002 \u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c`Period`\u5bf9\u8c61\u8868\u793a\u7684\u662f\u4ece2007\u5e741\u67081\u65e5\u52302007\u5e7412\u670831\u65e5\uff08\u5305\u542b\u5728\u5185\uff09\u7684\u65f6\u95f4\u6bb5\u3002 \u5728\u65f6\u95f4\u6bb5\u4e0a\u589e\u52a0\u6216\u51cf\u53bb\u6574\u6570\u53ef\u4ee5\u65b9\u4fbf\u5730\u6839\u636e\u5b83\u4eec\u7684\u9891\u7387\u8fdb\u884c\u79fb\u4f4d\u3002 p = pd.Period(2020, freq='A-DEC') print(p)","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020","text":"print(p + 5)","title":"2020"},{"location":"python/DataAnalysis/ch08/#2025","text":"print(p - 5)","title":"2025"},{"location":"python/DataAnalysis/ch08/#2015","text":"\u5982\u679c\u4e24\u4e2a\u533a\u95f4\u62e5\u6709\u76f8\u540c\u7684\u9891\u7387\uff0c\u5219\u5b83\u4eec\u7684\u5dee\u662f\u5b83\u4eec\u4e4b\u95f4\u7684\u5355\u4f4d\u6570\u3002 p1 = pd.Period(2020, freq='A-DEC') p2 = pd.Period(2010, freq='A-DEC') print(p1 - p2)","title":"2015"},{"location":"python/DataAnalysis/ch08/#10-yearends-month12","text":"p1 = pd.Period(2020, freq='Q-DEC') p2 = pd.Period(2010, freq='Q-DEC') print(p1 - p2)","title":"<10 * YearEnds: month=12>"},{"location":"python/DataAnalysis/ch08/#40-quarterends-startingmonth12","text":"\u4f7f\u7528`period_range`\u51fd\u6570\u53ef\u4ee5\u6784\u9020\u89c4\u5219\u533a\u95f4\u5e8f\u5217\u3002`PeriodIndex`\u7c7b\u5b58\u50a8\u7684\u662f\u533a\u95f4\u7684\u5e8f\u5217\uff0c\u53ef\u4ee5\u4f5c\u4e3a\u4efb\u610fpandas\u6570\u636e\u7ed3\u6784\u7684\u8f74\u7d22\u5f15\u3002 data = np.random.randn(6) strings = ['2021Q1', '2021Q2', '2021Q3', '2021Q4', '2022Q1', '2022Q2'] rng = pd.period_range('2001-1-1', '2001-6-30', freq='M') ts = pd.Series(data, index=rng) print(ts)","title":"<40 * QuarterEnds: startingMonth=12>"},{"location":"python/DataAnalysis/ch08/#2001-01-0481408","text":"","title":"2001-01 -0.481408"},{"location":"python/DataAnalysis/ch08/#2001-02-0297590","text":"","title":"2001-02 -0.297590"},{"location":"python/DataAnalysis/ch08/#2001-03-0860354","text":"","title":"2001-03 -0.860354"},{"location":"python/DataAnalysis/ch08/#2001-04-1281540","text":"","title":"2001-04 1.281540"},{"location":"python/DataAnalysis/ch08/#2001-05-1036551","text":"","title":"2001-05 1.036551"},{"location":"python/DataAnalysis/ch08/#2001-06-0522592","text":"","title":"2001-06 -0.522592"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_7","text":"rng = pd.PeriodIndex(strings, freq='Q-DEC') # \u5b57\u7b26\u4e32\u6570\u7ec4\u4e5f\u53ef\u4ee5\u4f7f\u7528PeriodIndex\u7c7b ts = pd.Series(data, index=rng) print(ts)","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2021q1-2077200","text":"","title":"2021Q1 -2.077200"},{"location":"python/DataAnalysis/ch08/#2021q2-0948796","text":"","title":"2021Q2 -0.948796"},{"location":"python/DataAnalysis/ch08/#2021q3-1104737","text":"","title":"2021Q3 -1.104737"},{"location":"python/DataAnalysis/ch08/#2021q4-0090281","text":"","title":"2021Q4 0.090281"},{"location":"python/DataAnalysis/ch08/#2022q1-0431517","text":"","title":"2022Q1 0.431517"},{"location":"python/DataAnalysis/ch08/#2022q2-1537045","text":"","title":"2022Q2 1.537045"},{"location":"python/DataAnalysis/ch08/#freq-q-dec-dtype-float64","text":"### \u533a\u95f4\u9891\u7387\u8f6c\u6362 \u4f7f\u7528`asfreq`\u53ef\u4ee5\u5c06\u533a\u95f4\u548c`PeriodIndex`\u5bf9\u8c61\u8f6c\u6362\u4e3a\u5176\u4ed6\u7684\u9891\u7387\u3002 \u4f8b\u5982\uff0c\u5047\u8bbe\u6211\u4eec\u6709\u4e00\u4e2a\u5e74\u5ea6\u533a\u95f4\uff0c\u5e76\u4e14\u60f3\u8981\u5728\u4e00\u5e74\u7684\u5f00\u59cb\u6216\u7ed3\u675f\u65f6\u5c06\u5176\u8f6c\u6362\u4e3a\u6708\u5ea6\u533a\u95f4\u3002 \u53ef\u4ee5\u5c06`Period('2020', 'A-DEC')`\u770b\u4f5c\u4e00\u6bb5\u65f6\u95f4\u4e2d\u7684\u4e00\u79cd\u6e38\u6807\uff0c\u5c06\u65f6\u95f4\u6309\u6708\u4efd\u5212\u5206\u3002 p = pd.Period(2020, freq='A-DEC') print(p.asfreq('M', how='start'))","title":"Freq: Q-DEC, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01","text":"print(p.asfreq('M', how='end'))","title":"2020-01"},{"location":"python/DataAnalysis/ch08/#2020-12","text":"\u5982\u679c\u8d22\u5e74\u7ed3\u675f\u4e0d\u572812\u6708\uff0c\u5219\u6bcf\u6708\u5206\u671f\u4f1a\u81ea\u52a8\u8c03\u6574\u3002 \u6309\u5f53\u5e74\u8d22\u5e74\u7ed3\u675f\u8ba1\u7b97\uff0c\u8d77\u59cb\u5e74\u4efd\u5c31\u662f\u4e0a\u4e00\u5e74\u4e86\u3002 p = pd.Period(2020, freq='A-JUN') print(p.asfreq('M', how='start'))","title":"2020-12"},{"location":"python/DataAnalysis/ch08/#2019-07","text":"print(p.asfreq('M', how='end'))","title":"2019-07"},{"location":"python/DataAnalysis/ch08/#2020-06","text":"\u5f53\u4ece\u9ad8\u9891\u7387\u5411\u4f4e\u9891\u7387\u8f6c\u6362\u65f6\uff0cpandas\u6839\u636e\u5b50\u533a\u95f4\u7684\"\u6240\u5c5e\"\u6765\u51b3\u5b9a\u7236\u533a\u95f4\u3002 \u4f8b\u5982\uff0c\u5728A-JUN\u9891\u7387\u4e2d\uff0cAug-2020\u662f2020\u533a\u95f4\u7684\u4e00\u90e8\u5206\uff1a print(p.asfreq('A-JUN')) 2020\u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628a`year`\u548c`quarter`\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f15\u3002 \u5b8c\u6574\u7684`PeriodIndex`\u5bf9\u8c61\u6216\u65f6\u95f4\u5e8f\u5217\u53ef\u4ee5\u6309\u7167\u76f8\u540c\u7684\u8bed\u4e49\u8fdb\u884c\u8f6c\u6362\uff1a rng = pd.period_range('2018', '2021', freq='A-DEC') data = np.random.randn(len(rng)) ts = pd.Series(data, index=rng) print(ts)","title":"2020-06"},{"location":"python/DataAnalysis/ch08/#2018-0221634","text":"","title":"2018 0.221634"},{"location":"python/DataAnalysis/ch08/#2019-0392724","text":"","title":"2019 -0.392724"},{"location":"python/DataAnalysis/ch08/#2020-0355022","text":"","title":"2020 -0.355022"},{"location":"python/DataAnalysis/ch08/#2021-0114000","text":"","title":"2021 0.114000"},{"location":"python/DataAnalysis/ch08/#freq-a-dec-dtype-float64","text":"\u4e0b\u9762\u5e74\u5ea6\u533a\u95f4\u5c06\u901a\u8fc7`asfreq`\u88ab\u66ff\u6362\u4e3a\u5bf9\u5e94\u4e8e\u6bcf\u4e2a\u5e74\u5ea6\u533a\u95f4\u5185\u7684\u7b2c\u4e00\u4e2a\u6708\u7684\u6708\u5ea6\u533a\u95f4\u3002 print(ts.asfreq('M', how='start'))","title":"Freq: A-DEC, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2018-01-0681874","text":"","title":"2018-01 0.681874"},{"location":"python/DataAnalysis/ch08/#2019-01-1006585","text":"","title":"2019-01 -1.006585"},{"location":"python/DataAnalysis/ch08/#2020-01-0619142","text":"","title":"2020-01 -0.619142"},{"location":"python/DataAnalysis/ch08/#2021-01-1445820","text":"","title":"2021-01 1.445820"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_8","text":"\u5982\u679c\u6211\u4eec\u60f3\u8981\u6bcf\u5e74\u6700\u540e\u4e00\u4e2a\u5de5\u4f5c\u65e5\uff0c\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528`B`\u9891\u7387\u6765\u8868\u793a\u6211\u4eec\u60f3\u8981\u7684\u662f\u533a\u95f4\u7684\u672b\u7aef\u3002 print(ts.asfreq('B', how='end'))","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2018-12-31-1520316","text":"","title":"2018-12-31 -1.520316"},{"location":"python/DataAnalysis/ch08/#2019-12-31-0425544","text":"","title":"2019-12-31 -0.425544"},{"location":"python/DataAnalysis/ch08/#2020-12-31-0658073","text":"","title":"2020-12-31 -0.658073"},{"location":"python/DataAnalysis/ch08/#2021-12-31-1206881","text":"","title":"2021-12-31 1.206881"},{"location":"python/DataAnalysis/ch08/#freq-b-dtype-float64_1","text":"### \u5b63\u5ea6\u533a\u95f4\u9891\u7387 \u5b63\u5ea6\u6570\u636e\u662f\u4f1a\u8ba1\u3001\u91d1\u878d\u548c\u5176\u4ed6\u9886\u57df\u7684\u6807\u51c6\u3002 \u5f88\u591a\u5b63\u5ea6\u6570\u636e\u662f\u5728\u8d22\u5e74\u7ed3\u5c3e\u62a5\u544a\u7684\uff0c\u901a\u5e38\u662f\u4e00\u5e7412\u4e2a\u6708\u4e2d\u7684\u6700\u540e\u4e00\u4e2a\u65e5\u5386\u65e5\u6216\u5de5\u4f5c\u65e5\u3002 pandas\u652f\u6301\u6240\u6709\u7684\u53ef\u80fd\u768412\u4e2a\u5b63\u5ea6\u9891\u7387\u4eceQ-JAN\u5230Q-DEC\uff1a \u4e0b\u4f8b\u4e2d\uff0c\u8d22\u5e74\u7ed3\u675f\u4e8e1\u6708\uff0c2020Q4\u884c\u65f6\u95f4\u4e3a\u4e0a\u4e00\u5e7411\u6708\u81f3\u5f53\u5e741\u6708\u3002\u53ef\u4ee5\u901a\u8fc7\u8f6c\u6362\u4e3a\u6bcf\u65e5\u9891\u7387\uff08asfreq\uff09\u8fdb\u884c\u68c0\u67e5\u3002 p = pd.Period('2020Q4', freq='Q-JAN') print(p)","title":"Freq: B, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020q4","text":"print(p.asfreq('D', 'start'))","title":"2020Q4"},{"location":"python/DataAnalysis/ch08/#2019-11-01","text":"print(p.asfreq('D', 'end'))","title":"2019-11-01"},{"location":"python/DataAnalysis/ch08/#2020-01-31","text":"\u5047\u5982\u8d22\u5e74\u7ed3\u675f\u4e8e2\u6708\uff0c2020Q4\u884c\u65f6\u95f4\u4e3a\u4e0a\u4e00\u5e7412\u6708\u81f3\u5f53\u5e742\u6708\u3002 p = pd.Period('2020Q4', freq='Q-FEB') print(p)","title":"2020-01-31"},{"location":"python/DataAnalysis/ch08/#2020q4_1","text":"print(p.asfreq('D', 'start'))","title":"2020Q4"},{"location":"python/DataAnalysis/ch08/#2019-11-01_1","text":"print(p.asfreq('D', 'end'))","title":"2019-11-01"},{"location":"python/DataAnalysis/ch08/#2020-01-31_1","text":"\u5047\u5982\u8d22\u5e74\u7ed3\u675f\u4e8e4\u6708\uff0c2020Q4\u884c\u65f6\u95f4\u4e3a\u4e0a\u4e00\u5e7412\u6708\u81f3\u5f53\u5e742\u6708\u3002 p = pd.Period('2020Q4', freq='Q-APR') print(p)","title":"2020-01-31"},{"location":"python/DataAnalysis/ch08/#2020q4_2","text":"print(p.asfreq('D', 'start'))","title":"2020Q4"},{"location":"python/DataAnalysis/ch08/#2020-02-01","text":"print(p.asfreq('D', 'end'))","title":"2020-02-01"},{"location":"python/DataAnalysis/ch08/#2020-04-30","text":"\u53ef\u4ee5\u5bf9\u533a\u95f4\u6570\u636e\u505a\u7b97\u672f\u64cd\u4f5c\u3002\u4f8b\u5982\uff0c\u8981\u83b7\u53d6\u5728\u5b63\u5ea6\u5012\u6570\u7b2c\u4e8c\u4e2a\u5de5\u4f5c\u65e5\u4e0b\u53484\u70b9\u7684\u65f6\u95f4\u6233\uff0c\u53ef\u4ee5\u8fd9\u4e48\u505a\uff1a(\u7591\u95ee\uff1a\u8fd9\u91cc\u7684\u53c2\u6570e\u4ee3\u8868\u4ec0\u4e48 ???) p4pm = (p.asfreq('B', 'e') - 1).asfreq('T', 's') + 16 * 60 print(p4pm)","title":"2020-04-30"},{"location":"python/DataAnalysis/ch08/#2020-04-29-1600","text":"print(p4pm.to_timestamp())","title":"2020-04-29 16:00"},{"location":"python/DataAnalysis/ch08/#2020-04-29-160000","text":"\u53ef\u4ee5\u4f7f\u7528`peroid_range`\u751f\u6210\u5b63\u5ea6\u5e8f\u5217\u3002\u5b83\u7684\u7b97\u672f\u4e5f\u662f\u4e00\u6837\u7684\uff1a rng = pd.period_range('2000Q3', '2001Q4', freq='Q-JAN') ts = pd.Series(np.arange(len(rng)), index=rng) print(ts)","title":"2020-04-29 16:00:00"},{"location":"python/DataAnalysis/ch08/#2000q3-0","text":"","title":"2000Q3 0"},{"location":"python/DataAnalysis/ch08/#2000q4-1","text":"","title":"2000Q4 1"},{"location":"python/DataAnalysis/ch08/#2001q1-2","text":"","title":"2001Q1 2"},{"location":"python/DataAnalysis/ch08/#2001q2-3","text":"","title":"2001Q2 3"},{"location":"python/DataAnalysis/ch08/#2001q3-4","text":"","title":"2001Q3 4"},{"location":"python/DataAnalysis/ch08/#2001q4-5","text":"","title":"2001Q4 5"},{"location":"python/DataAnalysis/ch08/#freq-q-jan-dtype-int64","text":"new_rng = (rng.asfreq('B', 'e') - 1).asfreq('T', 's') + 16 * 60 ts.index = new_rng.to_timestamp() print(ts)","title":"Freq: Q-JAN, dtype: int64"},{"location":"python/DataAnalysis/ch08/#1999-10-28-160000-0","text":"","title":"1999-10-28 16:00:00 0"},{"location":"python/DataAnalysis/ch08/#2000-01-28-160000-1","text":"","title":"2000-01-28 16:00:00 1"},{"location":"python/DataAnalysis/ch08/#2000-04-27-160000-2","text":"","title":"2000-04-27 16:00:00 2"},{"location":"python/DataAnalysis/ch08/#2000-07-28-160000-3","text":"","title":"2000-07-28 16:00:00 3"},{"location":"python/DataAnalysis/ch08/#2000-10-30-160000-4","text":"","title":"2000-10-30 16:00:00 4"},{"location":"python/DataAnalysis/ch08/#2001-01-30-160000-5","text":"","title":"2001-01-30 16:00:00 5"},{"location":"python/DataAnalysis/ch08/#dtype-int64","text":"### \u5c06\u65f6\u95f4\u6233\u8f6c\u6362\u4e3a\u533a\u95f4\uff08\u4ee5\u53ca\u9006\u8f6c\u6362\uff09 \u901a\u8fc7\u65f6\u95f4\u6233\u7d22\u5f15\u7684Series\u548cDataFrame\u53ef\u4ee5\u88ab`to_period`\u65b9\u6cd5\u8f6c\u6362\u4e3a\u533a\u95f4\uff1a rng = pd.date_range('2020-01-01', periods=3, freq='M') ts = pd.Series(np.random.randn(3), index=rng) print(ts)","title":"dtype: int64"},{"location":"python/DataAnalysis/ch08/#2020-01-31-0567097","text":"","title":"2020-01-31 -0.567097"},{"location":"python/DataAnalysis/ch08/#2020-02-29-0634521202yearquarter2","text":"","title":"2020-02-29 0.63452\u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628ayear\u548cquarter\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f152"},{"location":"python/DataAnalysis/ch08/#2020-03-31-0297777","text":"","title":"2020-03-31 0.297777"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_9","text":"pts = ts.to_period() print(pts)","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-0567097","text":"","title":"2020-01 -0.567097"},{"location":"python/DataAnalysis/ch08/#2020-02-0634522","text":"","title":"2020-02 0.634522"},{"location":"python/DataAnalysis/ch08/#2020-03-0297777","text":"","title":"2020-03 0.297777"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_10","text":"\u7531\u4e8e\u533a\u95f4\u662f\u975e\u91cd\u53e0\u65f6\u95f4\u8303\u56f4\uff0c\u4e00\u4e2a\u65f6\u95f4\u6233\u53ea\u80fd\u5c5e\u4e8e\u7ed9\u5b9a\u9891\u7387\u7684\u5355\u4e2a\u533a\u95f4\u3002 \u5c3d\u7ba1\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u6839\u636e\u65f6\u95f4\u6233\u63a8\u65ad\u51fa\u65b0`PeriodIndex`\u7684\u9891\u7387\uff0c\u4f46\u53ef\u4ee5\u6307\u5b9a\u4efb\u4f55\u60f3\u8981\u7684\u9891\u7387\u3002 \u5728\u7ed3\u679c\u4e2d\u5305\u542b\u91cd\u590d\u7684\u533a\u95f4\u4e5f\u662f\u6ca1\u6709\u95ee\u9898\u7684\u3002 rng = pd.date_range('2020-01-01', periods=6, freq='D') ts = pd.Series(np.random.randn(6), index=rng) print(ts)","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0111287","text":"","title":"2020-01-01 -0.111287"},{"location":"python/DataAnalysis/ch08/#2020-01-02-1442234","text":"","title":"2020-01-02 1.442234"},{"location":"python/DataAnalysis/ch08/#2020-01-03-0767553","text":"","title":"2020-01-03 -0.767553"},{"location":"python/DataAnalysis/ch08/#2020-01-04-0265064","text":"","title":"2020-01-04 -0.265064"},{"location":"python/DataAnalysis/ch08/#2020-01-05-1200312","text":"","title":"2020-01-05 1.200312"},{"location":"python/DataAnalysis/ch08/#2020-01-06-1782557","text":"","title":"2020-01-06 -1.782557"},{"location":"python/DataAnalysis/ch08/#freq-d-dtype-float64_3","text":"ts_m = ts.to_period('M') # \u6307\u5b9aperiod\u7684\u9891\u7387\uff08M\uff09,\u8f93\u51fa\u7ed3\u679c\u5305\u542b\u91cd\u590dperiod print(ts_m)","title":"Freq: D, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-0111287","text":"","title":"2020-01 -0.111287"},{"location":"python/DataAnalysis/ch08/#2020-01-1442234","text":"","title":"2020-01 1.442234"},{"location":"python/DataAnalysis/ch08/#2020-01-0767553","text":"","title":"2020-01 -0.767553"},{"location":"python/DataAnalysis/ch08/#2020-01-0265064","text":"","title":"2020-01 -0.265064"},{"location":"python/DataAnalysis/ch08/#2020-01-1200312","text":"","title":"2020-01 1.200312"},{"location":"python/DataAnalysis/ch08/#2020-01-1782557","text":"","title":"2020-01 -1.782557"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_11","text":"\u4f7f\u7528`to_timestamp`\u53ef\u4ee5\u5c06\u533a\u95f4\u518d\u8f6c\u6362\u4e3a\u65f6\u95f4\u6233\uff1a print(ts_m.to_timestamp(how='end'))","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-31-235959999999999-0111287","text":"","title":"2020-01-31 23:59:59.999999999 -0.111287"},{"location":"python/DataAnalysis/ch08/#2020-01-31-235959999999999-1442234","text":"","title":"2020-01-31 23:59:59.999999999 1.442234"},{"location":"python/DataAnalysis/ch08/#2020-01-31-235959999999999-0767553","text":"","title":"2020-01-31 23:59:59.999999999 -0.767553"},{"location":"python/DataAnalysis/ch08/#2020-01-31-235959999999999-0265064","text":"","title":"2020-01-31 23:59:59.999999999 -0.265064"},{"location":"python/DataAnalysis/ch08/#2020-01-31-235959999999999-1200312","text":"","title":"2020-01-31 23:59:59.999999999 1.200312"},{"location":"python/DataAnalysis/ch08/#2020-01-31-235959999999999-1782557","text":"","title":"2020-01-31 23:59:59.999999999 -1.782557"},{"location":"python/DataAnalysis/ch08/#dtype-float64_9","text":"print(ts_m.to_timestamp(how='start'))","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0111287_1","text":"","title":"2020-01-01 -0.111287"},{"location":"python/DataAnalysis/ch08/#2020-01-01-1442234","text":"","title":"2020-01-01 1.442234"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0767553","text":"","title":"2020-01-01 -0.767553"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0265064","text":"","title":"2020-01-01 -0.265064"},{"location":"python/DataAnalysis/ch08/#2020-01-01-1200312","text":"","title":"2020-01-01 1.200312"},{"location":"python/DataAnalysis/ch08/#2020-01-01-1782557","text":"","title":"2020-01-01 -1.782557"},{"location":"python/DataAnalysis/ch08/#dtype-float64_10","text":"### \u4ece\u6570\u7ec4\u751f\u6210PeriodIndex \u56fa\u5b9a\u9891\u7387\u6570\u636e\u96c6\u6709\u65f6\u5b58\u50a8\u5728\u8de8\u8d8a\u591a\u5217\u7684\u65f6\u95f4\u8303\u56f4\u4fe1\u606f\u4e2d\u3002\u4f8b\u5982\uff0c\u5728\u8fd9\u4e2a\u5b8f\u89c2\u7ecf\u6d4e\u6570\u636e\u96c6\u4e2d\uff0c\u5e74\u4efd\u548c\u5b63\u5ea6\u5728\u4e0d\u540c\u5217\u4e2d\uff1a data = pd.read_csv('../examples/macrodata.csv') print(data.head(5))","title":"dtype: float64"},{"location":"python/DataAnalysis/ch08/#year-quarter-realgdp-realcons-unemp-pop-infl-realint","text":"","title":"year quarter realgdp realcons ... unemp pop infl realint"},{"location":"python/DataAnalysis/ch08/#0-19590-10-2710349-17074-58-177146-000-000","text":"","title":"0 1959.0 1.0 2710.349 1707.4 ... 5.8 177.146 0.00 0.00"},{"location":"python/DataAnalysis/ch08/#1-19590-20-2778801-17337-51-177830-234-074","text":"","title":"1 1959.0 2.0 2778.801 1733.7 ... 5.1 177.830 2.34 0.74"},{"location":"python/DataAnalysis/ch08/#2-19590-30-2775488-17518-53-178657-274-109","text":"","title":"2 1959.0 3.0 2775.488 1751.8 ... 5.3 178.657 2.74 1.09"},{"location":"python/DataAnalysis/ch08/#3-19590-40-2785204-17537-56-179386-027-406","text":"","title":"3 1959.0 4.0 2785.204 1753.7 ... 5.6 179.386 0.27 4.06"},{"location":"python/DataAnalysis/ch08/#4-19600-10-2847699-17705-52-180007-231-119","text":"print(data.year)","title":"4 1960.0 1.0 2847.699 1770.5 ... 5.2 180.007 2.31 1.19"},{"location":"python/DataAnalysis/ch08/#0-19590","text":"","title":"0 1959.0"},{"location":"python/DataAnalysis/ch08/#1-19590","text":"","title":"1 1959.0"},{"location":"python/DataAnalysis/ch08/#2-19590","text":"","title":"2 1959.0"},{"location":"python/DataAnalysis/ch08/#3-19590","text":"","title":"3 1959.0"},{"location":"python/DataAnalysis/ch08/#4-19600","text":"","title":"4 1960.0"},{"location":"python/DataAnalysis/ch08/#_10","text":"","title":"..."},{"location":"python/DataAnalysis/ch08/#198-20080","text":"","title":"198 2008.0"},{"location":"python/DataAnalysis/ch08/#199-20080","text":"","title":"199 2008.0"},{"location":"python/DataAnalysis/ch08/#200-20090","text":"","title":"200 2009.0"},{"location":"python/DataAnalysis/ch08/#201-20090","text":"","title":"201 2009.0"},{"location":"python/DataAnalysis/ch08/#202-20090","text":"","title":"202 2009.0"},{"location":"python/DataAnalysis/ch08/#name-year-length-203-dtype-float64","text":"print(data.quarter)","title":"Name: year, Length: 203, dtype: float64"},{"location":"python/DataAnalysis/ch08/#0-10","text":"","title":"0 1.0"},{"location":"python/DataAnalysis/ch08/#1-20","text":"","title":"1 2.0"},{"location":"python/DataAnalysis/ch08/#2-30","text":"","title":"2 3.0"},{"location":"python/DataAnalysis/ch08/#3-40","text":"","title":"3 4.0"},{"location":"python/DataAnalysis/ch08/#4-10","text":"","title":"4 1.0"},{"location":"python/DataAnalysis/ch08/#_11","text":"","title":"..."},{"location":"python/DataAnalysis/ch08/#198-30","text":"","title":"198 3.0"},{"location":"python/DataAnalysis/ch08/#199-40","text":"","title":"199 4.0"},{"location":"python/DataAnalysis/ch08/#200-10","text":"","title":"200 1.0"},{"location":"python/DataAnalysis/ch08/#201-20","text":"","title":"201 2.0"},{"location":"python/DataAnalysis/ch08/#202-30","text":"","title":"202 3.0"},{"location":"python/DataAnalysis/ch08/#name-quarter-length-203-dtype-float64","text":"\u901a\u8fc7\u5c06\u8fd9\u4e9b\u6570\u7ec4\u548c\u9891\u7387\u4f20\u9012\u7ed9`PeriodIndex`\uff0c\u53ef\u4ee5\u8054\u5408\u5f62\u6210DataFrame\u7684\u7d22\u5f15 index = pd.PeriodIndex(year=data.year, quarter=data.quarter, freq='Q-DEC') print(index)","title":"Name: quarter, Length: 203, dtype: float64"},{"location":"python/DataAnalysis/ch08/#periodindex1959q1-1959q2-1959q3-1959q4-1960q1-1960q2","text":"","title":"PeriodIndex(['1959Q1', '1959Q2', '1959Q3', '1959Q4', '1960Q1', '1960Q2',"},{"location":"python/DataAnalysis/ch08/#1960q3-1960q4-1961q1-1961q2","text":"","title":"'1960Q3', '1960Q4', '1961Q1', '1961Q2',"},{"location":"python/DataAnalysis/ch08/#_12","text":"","title":"..."},{"location":"python/DataAnalysis/ch08/#2007q2-2007q3-2007q4-2008q1-2008q2-2008q3","text":"","title":"'2007Q2', '2007Q3', '2007Q4', '2008Q1', '2008Q2', '2008Q3',"},{"location":"python/DataAnalysis/ch08/#2008q4-2009q1-2009q2-2009q3","text":"","title":"'2008Q4', '2009Q1', '2009Q2', '2009Q3'],"},{"location":"python/DataAnalysis/ch08/#dtypeperiodq-dec-length203","text":"data.index = index # \u901a\u8fc7\u539f\u7d22\u5f151~202\uff0c\u628ayear\u548cquarter\u8054\u5408\u8d77\u6765\uff0c\u751f\u6210\u65b0\u7d22\u5f15\uff0c\u5e76\u66ff\u6362\u539f\u7d22\u5f15 print(data.infl)","title":"dtype='period[Q-DEC]', length=203)"},{"location":"python/DataAnalysis/ch08/#1959q1-000","text":"","title":"1959Q1 0.00"},{"location":"python/DataAnalysis/ch08/#1959q2-234","text":"","title":"1959Q2 2.34"},{"location":"python/DataAnalysis/ch08/#1959q3-274","text":"","title":"1959Q3 2.74"},{"location":"python/DataAnalysis/ch08/#1959q4-027","text":"","title":"1959Q4 0.27"},{"location":"python/DataAnalysis/ch08/#1960q1-231","text":"","title":"1960Q1 2.31"},{"location":"python/DataAnalysis/ch08/#_13","text":"","title":"..."},{"location":"python/DataAnalysis/ch08/#2008q3-316","text":"","title":"2008Q3 -3.16"},{"location":"python/DataAnalysis/ch08/#2008q4-879","text":"","title":"2008Q4 -8.79"},{"location":"python/DataAnalysis/ch08/#2009q1-094","text":"","title":"2009Q1 0.94"},{"location":"python/DataAnalysis/ch08/#2009q2-337","text":"","title":"2009Q2 3.37"},{"location":"python/DataAnalysis/ch08/#2009q3-356","text":"","title":"2009Q3 3.56"},{"location":"python/DataAnalysis/ch08/#freq-q-dec-name-infl-length-203-dtype-float64","text":"## \u91cd\u65b0\u91c7\u6837\u9891\u7387\u8f6c\u6362 import pandas as pd import numpy as np from pandas.tseries.frequencies import to_offset \u91cd\u65b0\u91c7\u6837\u662f\u6307\u5c06\u65f6\u95f4\u5e8f\u5217\u4ece\u4e00\u4e2a\u9891\u7387\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u9891\u7387\u7684\u8fc7\u7a0b\u3002 \u5c06\u66f4\u9ad8\u9891\u7387\u7684\u6570\u636e\u805a\u5408\u5230\u4f4e\u9891\u7387\u88ab\u79f0\u4e3a\u5411\u4e0b\u91c7\u6837\uff0c\u800c\u4ece\u4f4e\u9891\u7387\u8f6c\u6362\u5230\u9ad8\u9891\u7387\u79f0\u4e3a\u5411\u4e0a\u91c7\u6837\u3002 \u5e76\u4e0d\u662f\u6240\u6709\u7684\u91cd\u65b0\u91c7\u6837\u90fd\u5c5e\u4e8e\u4e0a\u9762\u8bf4\u7684\u4e24\u7c7b\u3002\u4f8b\u5982\uff0c\u5c06W-WED\uff08weekly on Wednesday\uff0c\u6bcf\u5468\u4e09\uff09\u8f6c\u6362\u5230W-FRI\uff08\u6bcf\u5468\u4e94\uff09\u65e2\u4e0d\u662f\u5411\u4e0a\u91c7\u6837\u4e5f\u4e0d\u662f\u5411\u4e0b\u91c7\u6837\u3002 pandas\u5bf9\u8c61\u90fd\u914d\u6709`resample`\u65b9\u6cd5\uff0c\u8be5\u65b9\u6cd5\u662f\u6240\u6709\u9891\u7387\u8f6c\u6362\u7684\u5de5\u5177\u51fd\u6570\u3002`resample`\u62e5\u6709\u7c7b\u4f3c\u4e8e`groupby`\u7684API\uff1b\u8c03\u7528`resample`\u5bf9\u6570\u636e\u5206\u7ec4\uff0c\u4e4b\u540e\u518d\u8c03\u7528\u805a\u5408\u51fd\u6570\uff1a ### resample\u65b9\u6cd5\u53c2\u6570 \u53c2\u6570 * freq: \u8868\u793a\u91cd\u91c7\u6837\u9891\u7387\uff0c\u4f8b\u5982\u2018M'\u3001\u20185min'\uff0cSecond(15) * how='mean': \u7528\u4e8e\u4ea7\u751f\u805a\u5408\u503c\u7684\u51fd\u6570\u540d\u6216\u6570\u7ec4\u51fd\u6570\uff0c\u4f8b\u5982\u2018mean'\u3001\u2018ohlc'\u3001np.max\u7b49\uff0c\u9ed8\u8ba4\u662f\u2018mean'\uff0c\u5176\u4ed6\u5e38\u7528\u7684\u503c\u7531\uff1a\u2018first'\u3001\u2018last'\u3001\u2018median'\u3001\u2018max'\u3001\u2018min' * axis=0: \u9ed8\u8ba4\u662f\u7eb5\u8f74\uff0c\u6a2a\u8f74\u8bbe\u7f6eaxis=1 * fill_method = None: \u5347\u91c7\u6837\u65f6\u5982\u4f55\u63d2\u503c\uff0c\u6bd4\u5982\u2018ffill'\u3001\u2018bfill'\u7b49 * closed = \u2018right': \u5728\u964d\u91c7\u6837\u65f6\uff0c\u5404\u65f6\u95f4\u6bb5\u7684\u54ea\u4e00\u6bb5\u662f\u95ed\u5408\u7684\uff0c\u2018right'\u6216\u2018left'\uff0c\u9ed8\u8ba4\u2018right' * label= \u2018right': \u5728\u964d\u91c7\u6837\u65f6\uff0c\u5982\u4f55\u8bbe\u7f6e\u805a\u5408\u503c\u7684\u6807\u7b7e\uff0c\u4f8b\u5982\uff0c9\uff1a30-9\uff1a35\u4f1a\u88ab\u6807\u8bb0\u62109\uff1a30\u8fd8\u662f9\uff1a35,\u9ed8\u8ba49\uff1a35 * loffset = None: \u9762\u5143\u6807\u7b7e\u7684\u65f6\u95f4\u6821\u6b63\u503c\uff0c\u6bd4\u5982\u2018-1s'\u6216Second(-1)\u7528\u4e8e\u5c06\u805a\u5408\u6807\u7b7e\u8c03\u65e91\u79d2 * limit=None: \u5728\u5411\u524d\u6216\u5411\u540e\u586b\u5145\u65f6\uff0c\u5141\u8bb8\u586b\u5145\u7684\u6700\u5927\u65f6\u671f\u6570 * kind = None: \u805a\u5408\u5230\u65f6\u671f\uff08\u2018period'\uff09\u6216\u65f6\u95f4\u6233\uff08\u2018timestamp'\uff09\uff0c\u9ed8\u8ba4\u805a\u5408\u5230\u65f6\u95f4\u5e8f\u5217\u7684\u7d22\u5f15\u7c7b\u578b * convention = None: \u5f53\u91cd\u91c7\u6837\u65f6\u671f\u65f6\uff0c\u5c06\u4f4e\u9891\u7387\u8f6c\u6362\u5230\u9ad8\u9891\u7387\u6240\u91c7\u7528\u7684\u7ea6\u5b9a\uff08start\u6216end\uff09\u3002\u9ed8\u8ba4\u2018end' rng = pd.date_range('2020-1-1', periods=100, freq='D') ts = pd.Series(np.random.randn(len(rng)), index=rng) print(ts)","title":"Freq: Q-DEC, Name: infl, Length: 203, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0802409","text":"","title":"2020-01-01 0.802409"},{"location":"python/DataAnalysis/ch08/#2020-01-02-1147130","text":"","title":"2020-01-02 -1.147130"},{"location":"python/DataAnalysis/ch08/#2020-01-03-1076115","text":"","title":"2020-01-03 -1.076115"},{"location":"python/DataAnalysis/ch08/#2020-01-04-2097443","text":"","title":"2020-01-04 -2.097443"},{"location":"python/DataAnalysis/ch08/#2020-01-05-0577671","text":"","title":"2020-01-05 0.577671"},{"location":"python/DataAnalysis/ch08/#_14","text":"","title":"..."},{"location":"python/DataAnalysis/ch08/#2020-04-05-0110747","text":"","title":"2020-04-05 -0.110747"},{"location":"python/DataAnalysis/ch08/#2020-04-06-0132867","text":"","title":"2020-04-06 0.132867"},{"location":"python/DataAnalysis/ch08/#2020-04-07-0294061","text":"","title":"2020-04-07 -0.294061"},{"location":"python/DataAnalysis/ch08/#2020-04-08-0246155","text":"","title":"2020-04-08 -0.246155"},{"location":"python/DataAnalysis/ch08/#2020-04-09-0927194","text":"","title":"2020-04-09 0.927194"},{"location":"python/DataAnalysis/ch08/#freq-d-length-100-dtype-float64","text":"print(ts.resample('M'))","title":"Freq: D, Length: 100, dtype: float64"},{"location":"python/DataAnalysis/ch08/#datetimeindexresampler-freq-axis0-closedright-labelright-conventionstart-originstart_day","text":"print(ts.resample('M').mean()) # \u628a100\u5929\u7684\u6570\u636e\u6309\u6708groupby\uff0c\u5e76\u8f93\u51fa\u6708\u672b\u6700\u540e\u4e00\u5929\uff0c\u8ba1\u7b97\u5e73\u5747\u503c","title":"DatetimeIndexResampler [freq=, axis=0, closed=right, label=right, convention=start, origin=start_day]"},{"location":"python/DataAnalysis/ch08/#2020-01-31-0311714","text":"","title":"2020-01-31 -0.311714"},{"location":"python/DataAnalysis/ch08/#2020-02-29-0121526","text":"","title":"2020-02-29 0.121526"},{"location":"python/DataAnalysis/ch08/#2020-03-31-0051131","text":"","title":"2020-03-31 -0.051131"},{"location":"python/DataAnalysis/ch08/#2020-04-30-0273113","text":"","title":"2020-04-30 -0.273113"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_12","text":"print(ts.resample('M', kind='period').mean()) # # \u628a100\u5929\u7684\u6570\u636e\u6309\u6708groupby\uff0c\u5e76\u8f93\u51fa\u6708\u4efd\uff08\u53c2\u6570period\uff09\uff0c\u8ba1\u7b97\u5e73\u5747\u503c","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-0311714","text":"","title":"2020-01 -0.311714"},{"location":"python/DataAnalysis/ch08/#2020-02-0121526","text":"","title":"2020-02 0.121526"},{"location":"python/DataAnalysis/ch08/#2020-03-0051131","text":"","title":"2020-03 -0.051131"},{"location":"python/DataAnalysis/ch08/#2020-04-0273113","text":"","title":"2020-04 -0.273113"},{"location":"python/DataAnalysis/ch08/#freq-m-dtype-float64_13","text":"### \u5411\u4e0b\u91c7\u6837 \u5c06\u6570\u636e\u805a\u5408\u5230\u4e00\u4e2a\u89c4\u5219\u7684\u4f4e\u9891\u7387\u4e0a\u662f\u4e00\u4e2a\u5e38\u89c1\u7684\u65f6\u95f4\u5e8f\u5217\u4efb\u52a1\u3002 \u8981\u805a\u5408\u7684\u6570\u636e\u4e0d\u5fc5\u662f\u56fa\u5b9a\u9891\u7387\u7684\u3002 \u671f\u671b\u7684\u9891\u7387\u5b9a\u4e49\u4e86\u7528\u4e8e\u5bf9\u65f6\u95f4\u5e8f\u5217\u5207\u7247\u4ee5\u805a\u5408\u7684\u7bb1\u4f53\u8fb9\u754c\u3002\u4f8b\u5982\uff0c\u8981\u5c06\u65f6\u95f4\u8f6c\u6362\u4e3a\u6bcf\u6708\uff0c`M`\u6216`BM`\uff0c\u5219\u9700\u8981\u5c06\u6570\u636e\u5206\u6210\u4e00\u4e2a\u6708\u7684\u65f6\u95f4\u95f4\u9694\u3002 \u6bcf\u4e2a\u95f4\u9694\u662f\u534a\u95ed\u5408\u7684\uff0c\u4e00\u4e2a\u6570\u636e\u70b9\u53ea\u80fd\u5c5e\u4e8e\u4e00\u4e2a\u65f6\u95f4\u95f4\u9694\uff0c\u65f6\u95f4\u95f4\u9694\u7684\u5e76\u96c6\u5fc5\u987b\u662f\u6574\u4e2a\u65f6\u95f4\u5e27\u3002 \u5728\u4f7f\u7528resample\u8fdb\u884c\u5411\u4e0b\u91c7\u6837\u6570\u636e\u65f6\u6709\u4e9b\u4e8b\u60c5\u9700\u8981\u8003\u8651\uff1a * \u6bcf\u6bb5\u95f4\u9694\u7684\u54ea\u4e00\u8fb9\u662f\u95ed\u5408\u7684\u3002 * \u5982\u4f55\u5728\u95f4\u9694\u7684\u8d77\u59cb\u6216\u7ed3\u675f\u4f4d\u7f6e\u6807\u8bb0\u6bcf\u4e2a\u5df2\u805a\u5408\u7684\u7bb1\u4f53\u3002 rng = pd.date_range('2020-1-1', periods=12, freq='T') ts = pd.Series(np.arange(12), index=rng) print(ts)","title":"Freq: M, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000000-0","text":"","title":"2020-01-01 00:00:00 0"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000100-1","text":"","title":"2020-01-01 00:01:00 1"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000200-2","text":"","title":"2020-01-01 00:02:00 2"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000300-3","text":"","title":"2020-01-01 00:03:00 3"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000400-4","text":"","title":"2020-01-01 00:04:00 4"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000500-5","text":"","title":"2020-01-01 00:05:00 5"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000600-6","text":"","title":"2020-01-01 00:06:00 6"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000700-7","text":"","title":"2020-01-01 00:07:00 7"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000800-8","text":"","title":"2020-01-01 00:08:00 8"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000900-9","text":"","title":"2020-01-01 00:09:00 9"},{"location":"python/DataAnalysis/ch08/#2020-01-01-001000-10","text":"","title":"2020-01-01 00:10:00 10"},{"location":"python/DataAnalysis/ch08/#2020-01-01-001100-11","text":"","title":"2020-01-01 00:11:00 11"},{"location":"python/DataAnalysis/ch08/#freq-t-dtype-int64","text":"\u6309\u4e94\u5206\u949f\u9891\u7387\u805a\u5408\u5206\u7ec4\uff0c\u8ba1\u7b97\u6bcf\u4e00\u7ec4\u7684\u52a0\u548c\u3002\u9891\u7387\u6309\u4e94\u5206\u949f\u7684\u589e\u91cf\u5b9a\u4e49\u4e86\u7bb1\u4f53\u8fb9\u754c\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5de6\u7bb1\u4f53\u8fb9\u754c\u662f\u5305\u542b\u7684\uff0c\u56e0\u6b6400:00\u7684\u503c\u662f\u5305\u542b\u572800:00\u523000:05\u95f4\u9694\u5185\u7684\u3002 \u4f20\u9012`closed='right'`\u5c06\u95f4\u9694\u7684\u95ed\u5408\u7aef\u6539\u4e3a\u4e86\u53f3\u8fb9\u3002 \u5206\u7ec4\uff1a * left: [00:00,00:01,00:02,00:03,00:04],[00:05,00:06,00:07,00:08,00:09],[00:10,00:11] * right:[00:00],[00:01,00:02,00:03,00:04,00:05],[00:06,00:07,00:08,00:09,00:10],[00:11] result = ts.resample('5min', closed='right').sum() print(result)","title":"Freq: T, dtype: int64"},{"location":"python/DataAnalysis/ch08/#2019-12-31-235500-0","text":"","title":"2019-12-31 23:55:00 0"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000000-15","text":"","title":"2020-01-01 00:00:00 15"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000500-40","text":"","title":"2020-01-01 00:05:00 40"},{"location":"python/DataAnalysis/ch08/#2020-01-01-001000-11","text":"","title":"2020-01-01 00:10:00 11"},{"location":"python/DataAnalysis/ch08/#freq-5t-dtype-int64","text":"result = ts.resample('5min', closed='left').sum() print(result)","title":"Freq: 5T, dtype: int64"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000000-10","text":"","title":"2020-01-01 00:00:00 10"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000500-35","text":"","title":"2020-01-01 00:05:00 35"},{"location":"python/DataAnalysis/ch08/#2020-01-01-001000-21","text":"","title":"2020-01-01 00:10:00 21"},{"location":"python/DataAnalysis/ch08/#freq-5t-dtype-int64_1","text":"\u6700\u540e\uff0c\u5c06\u7ed3\u679c\u7d22\u5f15\u79fb\u52a8\u4e00\u5b9a\u7684\u6570\u91cf\uff0c\u4f8b\u5982\u4ece\u53f3\u8fb9\u7f18\u51cf\u53bb\u4e00\u79d2\uff0c\u4ee5\u4f7f\u5176\u66f4\u6e05\u695a\u5730\u8868\u660e\u65f6\u95f4\u6233\u6240\u6307\u7684\u95f4\u9694\u3002 \u8981\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\uff0c\u5411`loffset`\u4f20\u9012\u5b57\u7b26\u4e32\u6216\u65e5\u671f\u504f\u7f6e\uff1a result = ts.resample('5min', closed='right', label='right', loffset='-1s').sum() print(result)","title":"Freq: 5T, dtype: int64"},{"location":"python/DataAnalysis/ch08/#2019-12-31-235959-0","text":"","title":"2019-12-31 23:59:59 0"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000459-15","text":"","title":"2020-01-01 00:04:59 15"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000959-40","text":"","title":"2020-01-01 00:09:59 40"},{"location":"python/DataAnalysis/ch08/#2020-01-01-001459-11","text":"","title":"2020-01-01 00:14:59 11"},{"location":"python/DataAnalysis/ch08/#freq-5t-dtype-int64_2","text":"","title":"Freq: 5T, dtype: int64"},{"location":"python/DataAnalysis/ch08/#futurewarning-loffset-in-resample-and-in-grouper-is-deprecated","text":"","title":"FutureWarning: 'loffset' in .resample() and in Grouper() is deprecated."},{"location":"python/DataAnalysis/ch08/#dfresamplefreq3s-loffset8h","text":"","title":">>> df.resample(freq=\"3s\", loffset=\"8H\")"},{"location":"python/DataAnalysis/ch08/#becomes","text":"","title":"becomes:"},{"location":"python/DataAnalysis/ch08/#from-pandastseriesfrequencies-import-to_offset","text":"","title":">>> from pandas.tseries.frequencies import to_offset"},{"location":"python/DataAnalysis/ch08/#df-dfresamplefreq3smean","text":"","title":">>> df = df.resample(freq=\"3s\").mean()"},{"location":"python/DataAnalysis/ch08/#dfindex-dfindexto_timestamp-to_offset8h","text":"#### \u5f00\u7aef-\u5cf0\u503c-\u8c37\u503c-\u7ed3\u675f\uff08OHLC\uff09\u91cd\u65b0\u91c7\u6837 \u5728\u91d1\u878d\u4e2d\uff0c\u4e3a\u6bcf\u4e2a\u6570\u636e\u6876\u8ba1\u7b97\u56db\u4e2a\u503c\u662f\u4e00\u79cd\u6d41\u884c\u7684\u65f6\u95f4\u5e8f\u5217\u805a\u5408\u65b9\u6cd5\uff1a\u7b2c\u4e00\u4e2a\u503c\uff08\u5f00\u7aef\uff09\u3001\u6700\u540e\u4e00\u4e2a\u503c\uff08\u7ed3\u675f\uff09\u3001\u6700\u5927\u503c\uff08\u5cf0\u503c\uff09\u548c\u6700\u5c0f\u503c\uff08\u8c37\u503c\uff09\u3002 \u901a\u8fc7\u4f7f\u7528`ohlc`\u805a\u5408\u51fd\u6570\u53d6\u5f97\u5305\u542b\u56db\u79cd\u805a\u5408\u503c\u5217\u7684DataFrame\uff0c\u8fd9\u4e9b\u503c\u5728\u6570\u636e\u7684\u5355\u6b21\u626b\u63cf\u4e2d\u88ab\u9ad8\u6548\u8ba1\u7b97\uff1a result = ts.resample('5min').ohlc() print(result)","title":">>> df.index = df.index.to_timestamp() + to_offset(\"8H\")"},{"location":"python/DataAnalysis/ch08/#open-high-low-close","text":"","title":"open high low close"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000000-0-4-0-4","text":"","title":"2020-01-01 00:00:00 0 4 0 4"},{"location":"python/DataAnalysis/ch08/#2020-01-01-000500-5-9-5-9","text":"","title":"2020-01-01 00:05:00 5 9 5 9"},{"location":"python/DataAnalysis/ch08/#2020-01-01-001000-10-11-10-11","text":"### \u5411\u4e0a\u91c7\u6837\u4e0e\u63d2\u503c \u5f53\u4ece\u4f4e\u9891\u7387\u8f6c\u6362\u4e3a\u9ad8\u9891\u7387\u65f6\uff0c\u5e76\u4e0d\u9700\u8981\u4efb\u4f55\u805a\u5408\u3002 df = pd.DataFrame( np.random.randn(2, 4), index=pd.date_range('2020/1/1', periods=2, freq='W-WED'), columns=['Colorado', 'Texas', 'New York', 'Ohio'] ) print(df)","title":"2020-01-01 00:10:00 10 11 10 11"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0228758-0758718-0025410-1001819","text":"","title":"2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-08-0704541-0261414-0863335-0267101","text":"df_daily = df.resample('W-WED').sum() print(df_daily)","title":"2020-01-08 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_1","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0228758-0758718-0025410-1001819_1","text":"","title":"2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-08-0704541-0261414-0863335-0267101_1","text":"df_daily = df.resample('D').sum() print(df_daily)","title":"2020-01-08 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_2","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0228758-0758718-0025410-1001819_2","text":"","title":"2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-02-0000000-0000000-0000000-0000000","text":"","title":"2020-01-02 0.000000 0.000000 0.000000 0.000000"},{"location":"python/DataAnalysis/ch08/#2020-01-03-0000000-0000000-0000000-0000000","text":"","title":"2020-01-03 0.000000 0.000000 0.000000 0.000000"},{"location":"python/DataAnalysis/ch08/#2020-01-04-0000000-0000000-0000000-0000000","text":"","title":"2020-01-04 0.000000 0.000000 0.000000 0.000000"},{"location":"python/DataAnalysis/ch08/#2020-01-05-0000000-0000000-0000000-0000000","text":"","title":"2020-01-05 0.000000 0.000000 0.000000 0.000000"},{"location":"python/DataAnalysis/ch08/#2020-01-06-0000000-0000000-0000000-0000000","text":"","title":"2020-01-06 0.000000 0.000000 0.000000 0.000000"},{"location":"python/DataAnalysis/ch08/#2020-01-07-0000000-0000000-0000000-0000000","text":"","title":"2020-01-07 0.000000 0.000000 0.000000 0.000000"},{"location":"python/DataAnalysis/ch08/#2020-01-08-0704541-0261414-0863335-0267101_2","text":"\u5f53\u5bf9\u8fd9\u4e9b\u6570\u636e\u4f7f\u7528\u805a\u5408\u51fd\u6570\u65f6\uff0c\u6bcf\u4e00\u7ec4\u53ea\u6709\u4e00\u4e2a\u503c\uff0c\u5e76\u4e14\u4f1a\u5728\u95f4\u9699\u4e2d\u4ea7\u751f\u7f3a\u5931\u503c\u3002 \u4f7f\u7528`asfreq`\u65b9\u6cd5\u5728\u4e0d\u805a\u5408\u7684\u60c5\u51b5\u4e0b\u8f6c\u6362\u5230\u9ad8\u9891\u7387\uff1a df_daily = df.resample('D').asfreq() print(df_daily)","title":"2020-01-08 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_3","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0228758-0758718-0025410-1001819_3","text":"","title":"2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-02-nan-nan-nan-nan","text":"","title":"2020-01-02 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-03-nan-nan-nan-nan","text":"","title":"2020-01-03 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-04-nan-nan-nan-nan","text":"","title":"2020-01-04 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-05-nan-nan-nan-nan","text":"","title":"2020-01-05 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-06-nan-nan-nan-nan","text":"","title":"2020-01-06 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-07-nan-nan-nan-nan","text":"","title":"2020-01-07 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-08-0704541-0261414-0863335-0267101_3","text":"\u5728\u975e\u661f\u671f\u4e09\u7684\u65e5\u671f\u4e0a\u5411\u524d\u586b\u5145\u6bcf\u5468\u6570\u503c\u3002`fillna`\u548c`reindex`\u65b9\u6cd5\u4e2d\u53ef\u7528\u7684\u586b\u5145\u6216\u63d2\u503c\u65b9\u6cd5\u53ef\u7528\u4e8e\u91cd\u91c7\u6837\uff1a df_daily = df.resample('D').ffill() print(df_daily)","title":"2020-01-08 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_4","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0228758-0758718-0025410-1001819_4","text":"","title":"2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-02-0228758-0758718-0025410-1001819","text":"","title":"2020-01-02 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-03-0228758-0758718-0025410-1001819","text":"","title":"2020-01-03 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-04-0228758-0758718-0025410-1001819","text":"","title":"2020-01-04 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-05-0228758-0758718-0025410-1001819","text":"","title":"2020-01-05 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-06-0228758-0758718-0025410-1001819","text":"","title":"2020-01-06 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-07-0228758-0758718-0025410-1001819","text":"","title":"2020-01-07 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-08-0704541-0261414-0863335-0267101_4","text":"\u53ef\u4ee5\u540c\u6837\u9009\u62e9\u4ec5\u5411\u524d\u586b\u5145\u4e00\u5b9a\u6570\u91cf\u7684\u533a\u95f4\uff0c\u4ee5\u9650\u5236\u7ee7\u7eed\u4f7f\u7528\u89c2\u6d4b\u503c\u7684\u65f6\u8ddd\uff1a df_daily = df.resample('D').ffill(limit=2) print(df_daily)","title":"2020-01-08 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_5","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-01-0228758-0758718-0025410-1001819_5","text":"","title":"2020-01-01 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-02-0228758-0758718-0025410-1001819_1","text":"","title":"2020-01-02 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-03-0228758-0758718-0025410-1001819_1","text":"","title":"2020-01-03 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-04-nan-nan-nan-nan_1","text":"","title":"2020-01-04 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-05-nan-nan-nan-nan_1","text":"","title":"2020-01-05 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-06-nan-nan-nan-nan_1","text":"","title":"2020-01-06 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-07-nan-nan-nan-nan_1","text":"","title":"2020-01-07 NaN NaN NaN NaN"},{"location":"python/DataAnalysis/ch08/#2020-01-08-0704541-0261414-0863335-0267101_5","text":"\u6ce8\u610f\uff0c\u65b0\u7684\u65e5\u671f\u7d22\u5f15\u4e0d\u9700\u8981\u4e0e\u65e7\u7684\u7d22\u5f15\u91cd\u53e0\uff0c\u548c\u539f\u6765`df`\u7684\u503c\u4e00\u6837\uff0c\u53ea\u662f\u65e5\u671f\u7d22\u5f15\u53d8\u4e86\u3002 df_new = df.resample('W-THU').ffill() print(df_new)","title":"2020-01-08 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_6","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-01-02-0228758-0758718-0025410-1001819_2","text":"","title":"2020-01-02 -0.228758 -0.758718 -0.025410 -1.001819"},{"location":"python/DataAnalysis/ch08/#2020-01-09-0704541-0261414-0863335-0267101","text":"### \u4f7f\u7528\u533a\u95f4\u8fdb\u884c\u91cd\u65b0\u91c7\u6837 \u5bf9\u4ee5\u533a\u95f4\u4e3a\u7d22\u5f15\u7684\u6570\u636e\u8fdb\u884c\u91c7\u6837\u4e0e\u65f6\u95f4\u6233\u7684\u60c5\u51b5\u7c7b\u4f3c\uff1a df = pd.DataFrame( np.random.randn(24, 4), index=pd.period_range('2020-1', periods=24, freq='M'), columns=['Colorado', 'Texas', 'New York', 'Ohio'] ) print(df)","title":"2020-01-09 -0.704541 -0.261414 -0.863335 0.267101"},{"location":"python/DataAnalysis/ch08/#2020-01-0721395-1492674-0707410-1641890","text":"","title":"2020-01 0.721395 -1.492674 0.707410 1.641890"},{"location":"python/DataAnalysis/ch08/#2020-02-0894880-0032823-0676158-0029203","text":"","title":"2020-02 -0.894880 0.032823 -0.676158 0.029203"},{"location":"python/DataAnalysis/ch08/#2020-03-2147365-0176796-0562695-0747656","text":"","title":"2020-03 2.147365 -0.176796 0.562695 -0.747656"},{"location":"python/DataAnalysis/ch08/#2020-04-1496037-0797119-0495601-0774147","text":"","title":"2020-04 1.496037 -0.797119 -0.495601 0.774147"},{"location":"python/DataAnalysis/ch08/#2020-05-0309839-0502563-0237244-0910624","text":"","title":"2020-05 -0.309839 0.502563 0.237244 0.910624"},{"location":"python/DataAnalysis/ch08/#2020-06-1231869-0105227-1315759-0217701","text":"","title":"2020-06 1.231869 -0.105227 1.315759 0.217701"},{"location":"python/DataAnalysis/ch08/#2020-07-1447419-0263876-0342045-0768907","text":"","title":"2020-07 1.447419 0.263876 -0.342045 -0.768907"},{"location":"python/DataAnalysis/ch08/#2020-08-2567162-1008827-0391085-1259560","text":"","title":"2020-08 -2.567162 -1.008827 0.391085 1.259560"},{"location":"python/DataAnalysis/ch08/#2020-09-0772501-1183532-0450374-0450714","text":"","title":"2020-09 -0.772501 1.183532 0.450374 0.450714"},{"location":"python/DataAnalysis/ch08/#2020-10-0228974-0461224-1393178-0175243","text":"","title":"2020-10 0.228974 0.461224 1.393178 0.175243"},{"location":"python/DataAnalysis/ch08/#2020-11-0725193-1544131-1372029-0659224","text":"","title":"2020-11 -0.725193 -1.544131 1.372029 -0.659224"},{"location":"python/DataAnalysis/ch08/#2020-12-0718195-0862024-0166460-0940191","text":"","title":"2020-12 0.718195 0.862024 -0.166460 -0.940191"},{"location":"python/DataAnalysis/ch08/#2021-01-0617054-0887312-0338451-1392838","text":"","title":"2021-01 -0.617054 -0.887312 0.338451 -1.392838"},{"location":"python/DataAnalysis/ch08/#2021-02-0081140-0634730-0868051-1277167","text":"","title":"2021-02 -0.081140 0.634730 -0.868051 -1.277167"},{"location":"python/DataAnalysis/ch08/#2021-03-0999642-1959715-0930662-0748687","text":"","title":"2021-03 -0.999642 -1.959715 -0.930662 0.748687"},{"location":"python/DataAnalysis/ch08/#2021-04-1851453-1561669-0688822-0371255","text":"","title":"2021-04 1.851453 1.561669 -0.688822 -0.371255"},{"location":"python/DataAnalysis/ch08/#2021-05-0540777-0890403-1204188-0243480","text":"","title":"2021-05 -0.540777 -0.890403 -1.204188 0.243480"},{"location":"python/DataAnalysis/ch08/#2021-06-1318905-1247457-0518969-0799793","text":"","title":"2021-06 1.318905 1.247457 0.518969 0.799793"},{"location":"python/DataAnalysis/ch08/#2021-07-0223238-0747177-0410889-0904593","text":"","title":"2021-07 0.223238 0.747177 -0.410889 0.904593"},{"location":"python/DataAnalysis/ch08/#2021-08-0652551-0254351-0464604-0676923","text":"","title":"2021-08 -0.652551 -0.254351 -0.464604 -0.676923"},{"location":"python/DataAnalysis/ch08/#2021-09-0562312-0182099-0018617-0573331","text":"","title":"2021-09 0.562312 0.182099 0.018617 0.573331"},{"location":"python/DataAnalysis/ch08/#2021-10-0429490-0045959-0356292-0295776","text":"","title":"2021-10 0.429490 -0.045959 -0.356292 -0.295776"},{"location":"python/DataAnalysis/ch08/#2021-11-2552155-0801299-1378421-1232792","text":"","title":"2021-11 2.552155 0.801299 1.378421 1.232792"},{"location":"python/DataAnalysis/ch08/#2021-12-1102288-0850280-0767015-0519840","text":"df_annual = df.resample('A-DEC').mean() print(df_annual)","title":"2021-12 1.102288 0.850280 -0.767015 -0.519840"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_7","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020-0226807-0151561-0395793-0195259","text":"","title":"2020 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021-0429056-0165581-0286339-0002594","text":"\u5411\u4e0a\u91c7\u6837\u66f4\u4e3a\u7ec6\u81f4\uff0c\u56e0\u4e3a\u5fc5\u987b\u5728\u91cd\u65b0\u91c7\u6837\u524d\u51b3\u5b9a\u65b0\u9891\u7387\u4e2d\u5728\u65f6\u95f4\u6bb5\u7684\u54ea\u4e00\u7aef\u653e\u7f6e\u6570\u503c\uff0c\u5c31\u50cfasfreq\u65b9\u6cd5\u4e00\u6837\u3002 `convention`\u53c2\u6570\u9ed8\u8ba4\u503c\u662f`start`\uff0c\u4f46\u4e5f\u53ef\u4ee5\u662f`end`\uff1a result = df_annual.resample('Q-DEC').ffill() print(result)","title":"2021 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_8","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020q1-0226807-0151561-0395793-0195259","text":"","title":"2020Q1 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2020q2-0226807-0151561-0395793-0195259","text":"","title":"2020Q2 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2020q3-0226807-0151561-0395793-0195259","text":"","title":"2020Q3 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2020q4-0226807-0151561-0395793-0195259","text":"","title":"2020Q4 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q1-0429056-0165581-0286339-0002594","text":"","title":"2021Q1 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#2021q2-0429056-0165581-0286339-0002594","text":"","title":"2021Q2 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#2021q3-0429056-0165581-0286339-0002594","text":"","title":"2021Q3 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#2021q4-0429056-0165581-0286339-0002594","text":"result = df_annual.resample('Q-DEC', convention='end').ffill() print(result)","title":"2021Q4 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_9","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020q4-0226807-0151561-0395793-0195259_1","text":"","title":"2020Q4 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q1-0226807-0151561-0395793-0195259","text":"","title":"2021Q1 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q2-0226807-0151561-0395793-0195259","text":"","title":"2021Q2 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q3-0226807-0151561-0395793-0195259","text":"","title":"2021Q3 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q4-0429056-0165581-0286339-0002594_1","text":"\u7531\u4e8e\u533a\u95f4\u6d89\u53ca\u65f6\u95f4\u8303\u56f4\uff0c\u5411\u4e0a\u91c7\u6837\u548c\u5411\u4e0b\u91c7\u6837\u5c31\u66f4\u4e3a\u4e25\u683c\uff1a * \u5728\u5411\u4e0b\u91c7\u6837\u4e2d\uff0c\u76ee\u6807\u9891\u7387\u5fc5\u987b\u662f\u539f\u9891\u7387\u7684\u5b50\u533a\u95f4\u3002 * \u5728\u5411\u4e0a\u91c7\u6837\u4e2d\uff0c\u76ee\u6807\u9891\u7387\u5fc5\u987b\u662f\u539f\u9891\u7387\u7684\u7236\u533a\u95f4\u3002 \u5982\u679c\u4e0d\u6ee1\u8db3\u8fd9\u4e9b\u89c4\u5219\uff0c\u5c06\u4f1a\u5f15\u8d77\u5f02\u5e38\u3002\u8fd9\u4e3b\u8981\u4f1a\u5f71\u54cd\u6bcf\u5b63\u5ea6\u3001\u6bcf\u5e74\u548c\u6bcf\u5468\u7684\u9891\u7387\u3002 \u4f8b\u5982\uff0c\u6839\u636eQ-MAR\u5b9a\u4e49\u7684\u65f6\u95f4\u8303\u56f4\u5c06\u53ea\u548cA-MAR\u3001A-JUN\u3001A-SEP\u548cA-DEC\u4fdd\u6301\u4e00\u81f4\uff1a result = df_annual.resample('Q-MAR').ffill() print(result)","title":"2021Q4 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#colorado-texas-new-york-ohio_10","text":"","title":"Colorado Texas New York Ohio"},{"location":"python/DataAnalysis/ch08/#2020q4-0226807-0151561-0395793-0195259_2","text":"","title":"2020Q4 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q1-0226807-0151561-0395793-0195259_1","text":"","title":"2021Q1 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q2-0226807-0151561-0395793-0195259_1","text":"","title":"2021Q2 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q3-0226807-0151561-0395793-0195259_1","text":"","title":"2021Q3 0.226807 -0.151561 0.395793 0.195259"},{"location":"python/DataAnalysis/ch08/#2021q4-0429056-0165581-0286339-0002594_2","text":"","title":"2021Q4 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#2022q1-0429056-0165581-0286339-0002594","text":"","title":"2022Q1 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#2022q2-0429056-0165581-0286339-0002594","text":"","title":"2022Q2 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#2022q3-0429056-0165581-0286339-0002594","text":"## \u79fb\u52a8\u7a97\u53e3\u51fd\u6570 \u7edf\u8ba1\u90a3\u4e9b\u901a\u8fc7\u79fb\u52a8\u7a97\u53e3\u6216\u6307\u6570\u8870\u51cf\u800c\u8fd0\u884c\u7684\u51fd\u6570\uff0c\u662f\u7528\u4e8e\u65f6\u95f4\u5e8f\u5217\u64cd\u4f5c\u7684\u6570\u7ec4\u53d8\u6362\u7684\u4e00\u4e2a\u91cd\u8981\u7c7b\u522b\u3002 \u8fd9\u5bf9\u5e73\u6ed1\u566a\u58f0\u6216\u7c97\u7cd9\u7684\u6570\u636e\u975e\u5e38\u6709\u7528\u3002\u79f0\u8fd9\u4e9b\u51fd\u6570\u4e3a\u79fb\u52a8\u7a97\u53e3\u51fd\u6570\uff0c\u5c3d\u7ba1\u5b83\u4e5f\u5305\u542b\u4e86\u4e00\u4e9b\u6ca1\u6709\u56fa\u5b9a\u957f\u5ea6\u7a97\u53e3\u7684\u51fd\u6570\uff0c\u6bd4\u5982\u6307\u6570\u52a0\u6743\u79fb\u52a8\u5e73\u5747\u3002 \u4e0e\u5176\u4ed6\u7684\u7edf\u8ba1\u51fd\u6570\u7c7b\u4f3c\uff0c\u8fd9\u4e9b\u51fd\u6570\u4f1a\u81ea\u52a8\u6392\u9664\u7f3a\u5931\u6570\u636e\u3002 import matplotlib.pyplot as plt import pandas as pd from scipy.stats import percentileofscore import numpy as np from pandas.tseries.offsets import Hour, Minute, Day, MonthEnd import pytz \u5728\u6df1\u5165\u4e86\u89e3\u4e4b\u524d\uff0c\u6211\u4eec\u53ef\u4ee5\u5148\u8f7d\u5165\u4e00\u4e9b\u65f6\u95f4\u5e8f\u5217\u6570\u636e\u5e76\u6309\u7167\u5de5\u4f5c\u65e5\u9891\u7387\u8fdb\u884c\u91cd\u65b0\u91c7\u6837\uff1a close_px_all = pd.read_csv( '../examples/stock_px_2.csv', parse_dates = True, index_col=0 ) print(close_px_all.head(5))","title":"2022Q3 0.429056 0.165581 -0.286339 -0.002594"},{"location":"python/DataAnalysis/ch08/#aapl-msft-xom-spx","text":"","title":"AAPL MSFT XOM SPX"},{"location":"python/DataAnalysis/ch08/#2003-01-02-740-2111-2922-90903","text":"","title":"2003-01-02 7.40 21.11 29.22 909.03"},{"location":"python/DataAnalysis/ch08/#2003-01-03-745-2114-2924-90859","text":"","title":"2003-01-03 7.45 21.14 29.24 908.59"},{"location":"python/DataAnalysis/ch08/#2003-01-06-745-2152-2996-92901","text":"","title":"2003-01-06 7.45 21.52 29.96 929.01"},{"location":"python/DataAnalysis/ch08/#2003-01-07-743-2193-2895-92293","text":"","title":"2003-01-07 7.43 21.93 28.95 922.93"},{"location":"python/DataAnalysis/ch08/#2003-01-08-728-2131-2883-90993","text":"close_px = close_px_all[ ['AAPL', 'MSFT', 'XOM'] ] close_px = close_px.resample('B').ffill() print(close_px)","title":"2003-01-08 7.28 21.31 28.83 909.93"},{"location":"python/DataAnalysis/ch08/#aapl-msft-xom","text":"","title":"AAPL MSFT XOM"},{"location":"python/DataAnalysis/ch08/#2003-01-02-740-2111-2922","text":"","title":"2003-01-02 7.40 21.11 29.22"},{"location":"python/DataAnalysis/ch08/#2003-01-03-745-2114-2924","text":"","title":"2003-01-03 7.45 21.14 29.24"},{"location":"python/DataAnalysis/ch08/#_15","text":"","title":"... ... ... ..."},{"location":"python/DataAnalysis/ch08/#2011-10-13-40843-2718-7637","text":"","title":"2011-10-13 408.43 27.18 76.37"},{"location":"python/DataAnalysis/ch08/#2011-10-14-42200-2727-7811","text":"","title":"2011-10-14 422.00 27.27 78.11"},{"location":"python/DataAnalysis/ch08/#2292-rows-x-3-columns","text":"`rolling`\u7b97\u5b50\uff0c\u5b83\u7684\u884c\u4e3a\u4e0e`resample`\u548c`groupby`\u7c7b\u4f3c\u3002 `rolling`\u53ef\u4ee5\u5728Series\u6216DataFrame\u4e0a\u901a\u8fc7\u4e00\u4e2awindow\uff08\u4ee5\u4e00\u4e2a\u533a\u95f4\u7684\u6570\u5b57\u6765\u8868\u793a\uff09\u8fdb\u884c\u8c03\u7528\u3002 close_px.AAPL.plot() \u8868\u8fbe\u5f0f`rolling(250)`\u4e0e`groupby`\u7684\u884c\u4e3a\u7c7b\u4f3c\uff0c\u4f46\u662f\u5b83\u521b\u5efa\u7684\u5bf9\u8c61\u662f\u6839\u636e250\u65e5\u6ed1\u52a8\u7a97\u53e3\u5206\u7ec4\u7684\u800c\u4e0d\u662f\u76f4\u63a5\u5206\u7ec4\u3002 \u56e0\u6b64\u8fd9\u91cc\u6211\u4eec\u83b7\u5f97\u4e86\u82f9\u679c\u516c\u53f8\u80a1\u7968\u4ef7\u683c\u7684250\u65e5\u79fb\u52a8\u7a97\u53e3\u5e73\u5747\u503c\u3002 close_px.AAPL.rolling(250).mean().plot() plt.show() \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u6eda\u52a8\u51fd\u6570\u9700\u8981\u7a97\u53e3\u4e2d\u6240\u6709\u7684\u503c\u5fc5\u987b\u662f\u975e`NA`\u503c\u3002 \u7531\u4e8e\u5b58\u5728\u7f3a\u5931\u503c\u8fd9\u79cd\u884c\u4e3a\u4f1a\u53d1\u751f\u6539\u53d8\uff0c\u5c24\u5176\u662f\u5728\u65f6\u95f4\u5e8f\u5217\u7684\u8d77\u59cb\u4f4d\u7f6e\u4f60\u62e5\u6709\u7684\u6570\u636e\u662f\u5c11\u4e8e\u7a97\u53e3\u533a\u95f4\u7684 apple_std250 = close_px.AAPL.rolling(250, min_periods=10).std() # \u82f9\u679c\u516c\u53f8250\u65e5\u6bcf\u65e5\u8fd4\u56de\u6807\u51c6\u5dee print(apple_std250[5:12])","title":"[2292 rows x 3 columns]"},{"location":"python/DataAnalysis/ch08/#2003-01-09-nan","text":"","title":"2003-01-09 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-10-nan","text":"","title":"2003-01-10 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-13-nan","text":"","title":"2003-01-13 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-14-nan","text":"","title":"2003-01-14 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-15-0077496","text":"","title":"2003-01-15 0.077496"},{"location":"python/DataAnalysis/ch08/#2003-01-16-0074760","text":"","title":"2003-01-16 0.074760"},{"location":"python/DataAnalysis/ch08/#2003-01-17-0112368","text":"","title":"2003-01-17 0.112368"},{"location":"python/DataAnalysis/ch08/#freq-b-name-aapl-dtype-float64","text":"apple_std250.plot() plt.show() expanding_mean = apple_std250.expanding().mean() print(expanding_mean[5:12])","title":"Freq: B, Name: AAPL, dtype: float64"},{"location":"python/DataAnalysis/ch08/#2003-01-09-nan_1","text":"","title":"2003-01-09 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-10-nan_1","text":"","title":"2003-01-10 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-13-nan_1","text":"","title":"2003-01-13 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-14-nan_1","text":"","title":"2003-01-14 NaN"},{"location":"python/DataAnalysis/ch08/#2003-01-15-0077496_1","text":"","title":"2003-01-15 0.077496"},{"location":"python/DataAnalysis/ch08/#2003-01-16-0076128","text":"","title":"2003-01-16 0.076128"},{"location":"python/DataAnalysis/ch08/#2003-01-17-0088208","text":"","title":"2003-01-17 0.088208"},{"location":"python/DataAnalysis/ch08/#freq-b-name-aapl-dtype-float64_1","text":"expanding_mean.plot() plt.show() \u5728DataFrame\u4e0a\u8c03\u7528\u4e00\u4e2a\u79fb\u52a8\u7a97\u53e3\u51fd\u6570\u4f1a\u5c06\u53d8\u6362\u5e94\u7528\u5230\u6bcf\u4e00\u5217\u4e0a: close_px.rolling(60).mean().plot(logy=True) # \u80a1\u7968\u4ef7\u683c60\u65e5MA\uff08Y\u8f74\u53d6\u5bf9\u6570\uff09 plt.show() `rolling`\u51fd\u6570\u4e5f\u63a5\u6536\u8868\u793a\u56fa\u5b9a\u5927\u5c0f\u7684\u65f6\u95f4\u504f\u7f6e\u5b57\u7b26\u4e32\uff0c\u800c\u4e0d\u53ea\u662f\u4e00\u4e2a\u533a\u95f4\u7684\u96c6\u5408\u6570\u5b57\u3002 \u5bf9\u4e0d\u89c4\u5219\u65f6\u95f4\u5e8f\u5217\u4f7f\u7528\u6ce8\u91ca\u975e\u5e38\u6709\u7528\u3002\u8fd9\u4e9b\u5b57\u7b26\u4e32\u53ef\u4ee5\u4f20\u9012\u7ed9`resample`\u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u50cf\u8fd9\u6837\u8ba1\u7b9720\u5929\u7684\u6eda\u52a8\u5e73\u5747\u503c\uff1a result = close_px.rolling('20D').mean() print(result)","title":"Freq: B, Name: AAPL, dtype: float64"},{"location":"python/DataAnalysis/ch08/#aapl-msft-xom_1","text":"","title":"AAPL MSFT XOM"},{"location":"python/DataAnalysis/ch08/#2003-01-02-7400000-21110000-29220000","text":"","title":"2003-01-02 7.400000 21.110000 29.220000"},{"location":"python/DataAnalysis/ch08/#_16","text":"","title":"... ... ... ..."},{"location":"python/DataAnalysis/ch08/#2011-10-14-391038000-26048667-74185333","text":"","title":"2011-10-14 391.038000 26.048667 74.185333"},{"location":"python/DataAnalysis/ch08/#2292-rows-x-3-columns_1","text":"result.plot() plt.show() ### \u6307\u6570\u52a0\u6743\u51fd\u6570 \u6307\u5b9a\u4e00\u4e2a\u5e38\u6570\u8870\u51cf\u56e0\u5b50\u4ee5\u5411\u66f4\u591a\u8fd1\u671f\u89c2\u6d4b\u503c\u63d0\u4f9b\u66f4\u591a\u6743\u91cd\uff0c\u53ef\u4ee5\u66ff\u4ee3\u4f7f\u7528\u5177\u6709\u76f8\u7b49\u52a0\u6743\u89c2\u5bdf\u503c\u7684\u9759\u6001\u7a97\u53e3\u5c3a\u5bf8\u7684\u65b9\u6cd5\u3002 \u6709\u591a\u79cd\u65b9\u5f0f\u53ef\u4ee5\u6307\u5b9a\u8870\u51cf\u56e0\u5b50\u3002\u5176\u4e2d\u4e00\u79cd\u6d41\u884c\u7684\u65b9\u5f0f\u662f\u4f7f\u7528\u4e00\u4e2aspan\uff08\u8de8\u5ea6\uff09\uff0c\u8fd9\u4f7f\u5f97\u7ed3\u679c\u4e0e\u7a97\u53e3\u5927\u5c0f\u7b49\u4e8e\u8de8\u5ea6\u7684\u7b80\u5355\u79fb\u52a8\u7a97\u53e3\u51fd\u6570\u3002 \u7531\u4e8e\u6307\u6570\u52a0\u6743\u7edf\u8ba1\u503c\u7ed9\u66f4\u8fd1\u671f\u7684\u89c2\u6d4b\u503c\u4ee5\u66f4\u591a\u7684\u6743\u91cd\uff0c\u4e0e\u7b49\u6743\u91cd\u7684\u7248\u672c\u76f8\u6bd4\uff0c\u5b83\u5bf9\u53d8\u5316\u201c\u9002\u5e94\u201d\u5f97\u66f4\u5feb\u3002 pandas\u62e5\u6709`ewm`\u7b97\u5b50\uff0c\u540c`rolling`\u3001`expanding`\u7b97\u5b50\u4e00\u8d77\u4f7f\u7528\u3002 \u4ee5\u4e0b\u662f\u5c06\u82f9\u679c\u516c\u53f8\u80a1\u7968\u4ef7\u683c\u768460\u65e5\u5747\u7ebf\u4e0e`span=60`\u7684EW\u79fb\u52a8\u5e73\u5747\u7ebf\u8fdb\u884c\u6bd4\u8f83\u7684\u4f8b\u5b50\uff1a aapl_ex = close_px.AAPL['2006':'2007'] ma60 = aapl_ex.rolling(30, min_periods=20).mean() ewma60 = aapl_ex.ewm(span=30).mean() ma60.plot(style='k--', label='Simple MA') ewma60.plot(style='k-', label='EWMA') plt.legend() plt.show() ### \u4e8c\u5143\u79fb\u52a8\u7a97\u53e3\u51fd\u6570 \u4e00\u4e9b\u7edf\u8ba1\u7b97\u5b50\uff0c\u4f8b\u5982\u76f8\u5173\u5ea6\u548c\u534f\u65b9\u5dee\uff0c\u9700\u8981\u64cd\u4f5c\u4e24\u4e2a\u65f6\u95f4\u5e8f\u5217\u3002 \u4f8b\u5982\uff0c\u91d1\u878d\u5206\u6790\u5e08\u7ecf\u5e38\u5bf9\u80a1\u7968\u4e0e\u57fa\u51c6\u6307\u6570\uff08\u5982\u6807\u666e500\uff09\u7684\u5173\u8054\u6027\u611f\u5174\u8da3\u3002 \u6211\u4eec\u9996\u5148\u8ba1\u7b97\u6240\u6709\u6211\u4eec\u611f\u5174\u8da3\u7684\u65f6\u95f4\u5e8f\u5217\u7684\u767e\u5206\u6bd4\u53d8\u5316\uff1a spx_px = close_px_all['SPX'] spx_rets = spx_px.pct_change() returns = close_px.pct_change()","title":"[2292 rows x 3 columns]"},{"location":"python/DataAnalysis/ch08/#rollingcorrspx_rets","text":"corr = returns.AAPL.rolling(125, min_periods=100).corr(spx_rets) # \u82f9\u679c\u516c\u53f8\u4e0e\u6807\u666e500\u7684\u516d\u4e2a\u6708\u7684\u6536\u76ca\u76f8\u5173\u6027 corr.plot() plt.show() corr = returns.rolling(125, min_periods=100).corr(spx_rets) # \u591a\u53ea\u80a1\u7968\u4e0e\u6807\u666e500\u7684\u516d\u4e2a\u6708\u6536\u76ca\u76f8\u5173\u6027 corr.plot() plt.show() ### \u7528\u6237\u81ea\u5b9a\u4e49\u7684\u79fb\u52a8\u7a97\u53e3\u51fd\u6570 \u5728`rolling`\u53ca\u5176\u76f8\u5173\u65b9\u6cd5\u4e0a\u4f7f\u7528apply\u65b9\u6cd5\u63d0\u4f9b\u4e86\u4e00\u79cd\u5728\u79fb\u52a8\u7a97\u53e3\u4e2d\u5e94\u7528\u4f60\u81ea\u5df1\u8bbe\u8ba1\u7684\u6570\u7ec4\u51fd\u6570\u7684\u65b9\u6cd5\u3002 \u552f\u4e00\u7684\u8981\u6c42\u662f\u8be5\u51fd\u6570\u4ece\u6bcf\u4e2a\u6570\u7ec4\u4e2d\u4ea7\u751f\u4e00\u4e2a\u5355\u503c\uff08\u7f29\u805a\uff09\u3002 \u4f8b\u5982\uff0c\u5c3d\u7ba1\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528`rolling(...).quantile(q)`\u8ba1\u7b97\u6837\u672c\u7684\u5206\u4f4d\u6570\uff0c\u4f46\u6211\u4eec\u53ef\u80fd\u4f1a\u5bf9\u6837\u672c\u4e2d\u7279\u5b9a\u503c\u7684\u767e\u5206\u4f4d\u6570\u611f\u5174\u8da3\u3002 `scipy.stats.percentileofscore`\u51fd\u6570\u5c31\u662f\u5b9e\u73b0\u8fd9\u4e2a\u529f\u80fd\u7684\uff1a score_at_2percent = lambda x: percentileofscore(x, 0.02) result = returns.AAPL.rolling(250).apply(score_at_2percent) # \u4e00\u5e74\u7a97\u53e3\u4e0b\u82f9\u679c\u516c\u53f8\u80a1\u4ef72%\u6536\u76ca\u7684\u767e\u5206\u4f4d\u7b49\u7ea7 result.plot() plt.show() result = returns.rolling(250).apply(score_at_2percent) # \u4e00\u5e74\u7a97\u53e3\u4e0b\u6240\u6709\u516c\u53f8\u80a1\u4ef72%\u6536\u76ca\u7684\u767e\u5206\u4f4d\u7b49\u7ea7 result.plot() plt.show() ```","title":"\u5728\u8c03\u7528rolling\u540e\uff0ccorr\u805a\u5408\u51fd\u6570\u53ef\u4ee5\u6839\u636espx_rets\u8ba1\u7b97\u6eda\u52a8\u76f8\u5173\u6027\uff1a"},{"location":"python/DataAnalysis/ch09/","text":"\u9ad8\u9636pandas \u00b6 \u5206\u7c7b\u6570\u636e \u00b6 import numpy as np import pandas as pd \u80cc\u666f\u548c\u76ee\u6807 \u00b6 \u4e00\u4e2a\u5217\u7ecf\u5e38\u4f1a\u5305\u542b\u91cd\u590d\u503c\uff0c\u8fd9\u4e9b\u91cd\u590d\u503c\u662f\u4e00\u4e2a\u5c0f\u578b\u7684\u4e0d\u540c\u503c\u7684\u96c6\u5408\u3002 unique \u548c value_counts \u8fd9\u6837\u7684\u51fd\u6570\u5141\u8bb8\u6211\u4eec\u4ece\u4e00\u4e2a\u6570\u7ec4\u4e2d\u63d0\u53d6\u4e0d\u540c\u503c\u5e76\u5206\u522b\u8ba1\u7b97\u8fd9\u4e9b\u4e0d\u540c\u503c\u7684\u9891\u7387\uff1a values = pd.Series(['apple', 'orange', 'apple', 'apple'] * 2) print(values) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # dtype: object print(pd.unique(values)) # ['apple' 'orange'] print(pd.value_counts(values)) # apple 6 # orange 2 # dtype: int64 \u5728\u6570\u636e\u5165\u5e93\u7684\u64cd\u4f5c\u4e2d\uff0c\u4f7f\u7528\u7ef4\u5ea6\u8868\u662f\u4e00\u79cd\u6700\u4f73\u5b9e\u8df5\uff0c\u7ef4\u5ea6\u8868\u5305\u542b\u4e86\u4e0d\u540c\u503c\uff0c\u5e76\u5c06\u4e3b\u8981\u89c2\u6d4b\u503c\u5b58\u50a8\u4e3a\u5f15\u7528\u7ef4\u5ea6\u8868\u7684\u6574\u6570\u952e\uff1a values = pd.Series([0, 1, 0, 0] * 2) dim = pd.Series(['apple', 'oragne']) \u4f7f\u7528 take \u65b9\u6cd5\u6765\u6062\u590d\u539f\u6765\u7684\u5b57\u7b26\u4e32Series\u3002\uff080\u5bf9\u5e94\u5230apple)\u3002 \u8fd9\u79cd\u6309\u7167\u6574\u6570\u5c55\u73b0\u7684\u65b9\u5f0f\u88ab\u79f0\u4e3a\u5206\u7c7b\u6216\u5b57\u5178\u7f16\u7801\u5c55\u73b0\u3002\u4e0d\u540c\u503c\u7684\u6570\u7ec4\u53ef\u4ee5\u88ab\u79f0\u4e3a\u6570\u636e\u7684\u7c7b\u522b\u3001\u5b57\u5178\u6216\u5c42\u7ea7\u3002 print(dim.take(values)) # 0 apple # 1 oragne # 0 apple # 0 apple # 0 apple # 1 oragne # 0 apple # 0 apple # dtype: object \u5728\u505a\u6570\u636e\u5206\u6790\u65f6\uff0c\u5206\u7c7b\u5c55\u793a\u4f1a\u4ea7\u751f\u663e\u8457\u7684\u6027\u80fd\u63d0\u5347\u3002\u53ef\u4ee5\u5728\u7c7b\u522b\u4e0a\u8fdb\u884c\u8f6c\u6362\u540c\u65f6\u4e0d\u6539\u53d8\u4ee3\u7801\u3002 \u4ee5\u4e0b\u662f\u4e00\u4e9b\u76f8\u5bf9\u4f4e\u5f00\u9500\u7684\u8f6c\u6362\u793a\u4f8b\uff1a \u91cd\u547d\u540d\u7c7b\u522b \u5728\u4e0d\u6539\u53d8\u5df2\u6709\u7684\u7c7b\u522b\u987a\u5e8f\u7684\u60c5\u51b5\u4e0b\u6dfb\u52a0\u4e00\u4e2a\u65b0\u7684\u7c7b\u522b pandas\u4e2d\u7684Categorical\u7c7b\u578b \u00b6 pandas\u62e5\u6709\u7279\u6b8a\u7684 Categorical \u7c7b\u578b\uff0c\u7528\u4e8e\u627f\u8f7d\u57fa\u4e8e\u6574\u6570\u7684\u7c7b\u522b\u5c55\u793a\u6216\u7f16\u7801\u7684\u6570\u636e\u3002 fruits = ['apple', 'orange', 'apple', 'apple'] * 2 N = len(fruits) df = pd.DataFrame( { 'fruit': fruits, 'basket_id': np.arange(N), 'count': np.random.randint(3, 15, size=N), 'weight': np.random.uniform(0, 4, size=N) }, columns=['basket_id', 'fruit', 'count', 'weight'] ) print(df) # basket_id fruit count weight # 0 0 apple 8 1.288867 # 1 1 orange 4 3.414430 # 2 2 apple 7 3.222160 # 3 3 apple 14 2.724804 # 4 4 apple 8 3.548828 # 5 5 orange 10 0.918739 # 6 6 apple 4 0.784816 # 7 7 apple 10 3.140607 df['fruit'] \u662f\u4e00\u4e2aPython\u5b57\u7b26\u4e32\u5bf9\u8c61\u7ec4\u6210\u7684\u6570\u7ec4\u3002\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528\u51fd\u6570\u5c06\u5b83\u8f6c\u6362\u4e3a Categorical \u5bf9\u8c61\uff1a fruit_cat = df['fruit'].astype('category') print(fruit_cat) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # Name: fruit, dtype: category # Categories (2, object): ['apple', 'orange'] fruit_cat \u7684\u503c\u5e76\u4e0d\u662fNumPy\u6570\u7ec4\uff0c\u800c\u662f pandas.Categorical \u7684\u5b9e\u4f8b\uff1a c = fruit_cat.values print(type(c)) # print(c) # ['apple', 'orange', 'apple', 'apple', 'apple', 'orange', 'apple', 'apple'] # Categories (2, object): ['apple', 'orange'] Categorical \u5bf9\u8c61\u62e5\u6709 categories \u548c codes \u5c5e\u6027\uff1a print(c.categories) # Index(['apple', 'orange'], dtype='object') print(c.codes) # [0 1 0 0 0 1 0 0] \u901a\u8fc7\u5206\u914d\u5df2\u8f6c\u6362\u7684\u7ed3\u679c\u5c06DataFrame\u7684\u4e00\u5217\u8f6c\u6362\u4e3a Categorical \u5bf9\u8c61\uff1a print(df['fruit']) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # Name: fruit, dtype: object df['fruit'] = df['fruit'].astype('category') print(df['fruit']) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # Name: fruit, dtype: category # Categories (2, object): ['apple', 'orange'] \u4e5f\u53ef\u4ee5\u4ece\u5176\u4ed6Python\u5e8f\u5217\u7c7b\u578b\u76f4\u63a5\u751f\u6210 pandas.Categorical \uff1a my_categories = pd.Categorical(['foo', 'bar', 'baz', 'foo', 'bar']) print(my_categories) # ['foo', 'bar', 'baz', 'foo', 'bar'] # Categories (3, object): ['bar', 'baz', 'foo'] \u4e5f\u53ef\u4ee5\u4f7f\u7528 from_codes \u6784\u9020\u51fd\u6570\u6765\u8f6c\u6362\u5176\u4ed6\u6570\u636e\u6e90\u7684\u5206\u7c7b\u7f16\u7801\u6570\u636e\uff1a categories = ['foo', 'bar', 'baz'] codes = [0, 1, 2, 0, 0, 1] my_cats_2 = pd.Categorical.from_codes(codes, categories) print(my_cats_2) # ['foo', 'bar', 'baz', 'foo', 'foo', 'bar'] # Categories (3, object): ['foo', 'bar', 'baz'] \u8fd9\u4e2a\u672a\u6392\u5e8f\u7684\u5206\u7c7b\u5b9e\u4f8b\u53ef\u4ee5\u4f7f\u7528 as_ordered \u8fdb\u884c\u6392\u5e8f\uff1a print(my_cats_2.as_ordered()) # ['foo', 'bar', 'baz', 'foo', 'foo', 'bar'] # Categories (3, object): ['foo' < 'bar' < 'baz'] \u9664\u975e\u663e\u5f0f\u5730\u6307\u5b9a\uff0c\u5206\u7c7b\u8f6c\u6362\u662f\u4e0d\u4f1a\u6307\u5b9a\u7c7b\u522b\u7684\u987a\u5e8f\u7684\u3002\u56e0\u6b64 categories \u6570\u7ec4\u53ef\u80fd\u4f1a\u4e0e\u8f93\u5165\u6570\u636e\u7684\u987a\u5e8f\u4e0d\u540c\u3002 \u5f53\u4f7f\u7528 from_codes \u6216\u5176\u4ed6\u4efb\u610f\u6784\u9020\u51fd\u6570\u65f6\uff0c\u53ef\u4ee5\u4e3a\u7c7b\u522b\u6307\u5b9a\u4e00\u4e2a\u6709\u610f\u4e49\u7684\u987a\u5e8f\uff1a\u8f93\u51fa\u7684 [foo df.pipe(len) # \u4f20\u9012\u7684\u662flen\u5b9e\u4f8b # 4 def fun(df): return df * 2 fun(df) # 0 1 2 # 0 2.0 4.0 6.0 # 1 2.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 4.0 6.0 df.pipe(fun) # \u4f20\u9012\u7684\u662ffun\u51fd\u6570 # 0 1 2 # 0 2.0 4.0 6.0 # 1 2.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 4.0 6.0 def fun2(x, df): # \u6570\u636e\u662f\u7b2c\u4e8c\u4e2a\u53c2\u6570 return df * 3 df.pipe((fun2, 'df'), 2) # \u6ce8\u610f\u4f20\u503c # 0 1 2 # 0 3.0 6.0 9.0 # 1 3.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 6.0 9.0 Series \u793a\u4f8b\uff1a \u00b6 s = pd.Series([1, 2, 3, 4, 5]) s.pipe(type) # s.pipe(len) # 5 def fun3(x, ss): return ss * 3 s.pipe((fun3, 'ss'), 2) # 0 3 # 1 6 # 2 9 # 3 12 # 4 15 # dtype: int64 GroupBy \u793a\u4f8b\uff1a \u00b6 df = pd.DataFrame({'A': 'a b a b'.split(), 'B': [1, 2, 3, 4]}) print(df) # A B # 0 a 1 # 1 b 2 # 2 a 3 # 3 b 4 \u6c42\u6bcf\u7ec4\u6700\u5927\u503c\u548c\u6700\u5c0f\u503c\u4e4b\u95f4\u7684\u5dee\u5f02\u3002 df.groupby('A').pipe(lambda x: x.max() - x.min()) # B # A # a 2 # b 2 def mean1(groupby): return groupby.mean() df.groupby(['A']).pipe(mean1) # B # A # a 2.0 # b 3.0","title":"\u9ad8\u9636pandas"},{"location":"python/DataAnalysis/ch09/#pandas","text":"","title":"\u9ad8\u9636pandas"},{"location":"python/DataAnalysis/ch09/#_1","text":"import numpy as np import pandas as pd","title":"\u5206\u7c7b\u6570\u636e"},{"location":"python/DataAnalysis/ch09/#_2","text":"\u4e00\u4e2a\u5217\u7ecf\u5e38\u4f1a\u5305\u542b\u91cd\u590d\u503c\uff0c\u8fd9\u4e9b\u91cd\u590d\u503c\u662f\u4e00\u4e2a\u5c0f\u578b\u7684\u4e0d\u540c\u503c\u7684\u96c6\u5408\u3002 unique \u548c value_counts \u8fd9\u6837\u7684\u51fd\u6570\u5141\u8bb8\u6211\u4eec\u4ece\u4e00\u4e2a\u6570\u7ec4\u4e2d\u63d0\u53d6\u4e0d\u540c\u503c\u5e76\u5206\u522b\u8ba1\u7b97\u8fd9\u4e9b\u4e0d\u540c\u503c\u7684\u9891\u7387\uff1a values = pd.Series(['apple', 'orange', 'apple', 'apple'] * 2) print(values) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # dtype: object print(pd.unique(values)) # ['apple' 'orange'] print(pd.value_counts(values)) # apple 6 # orange 2 # dtype: int64 \u5728\u6570\u636e\u5165\u5e93\u7684\u64cd\u4f5c\u4e2d\uff0c\u4f7f\u7528\u7ef4\u5ea6\u8868\u662f\u4e00\u79cd\u6700\u4f73\u5b9e\u8df5\uff0c\u7ef4\u5ea6\u8868\u5305\u542b\u4e86\u4e0d\u540c\u503c\uff0c\u5e76\u5c06\u4e3b\u8981\u89c2\u6d4b\u503c\u5b58\u50a8\u4e3a\u5f15\u7528\u7ef4\u5ea6\u8868\u7684\u6574\u6570\u952e\uff1a values = pd.Series([0, 1, 0, 0] * 2) dim = pd.Series(['apple', 'oragne']) \u4f7f\u7528 take \u65b9\u6cd5\u6765\u6062\u590d\u539f\u6765\u7684\u5b57\u7b26\u4e32Series\u3002\uff080\u5bf9\u5e94\u5230apple)\u3002 \u8fd9\u79cd\u6309\u7167\u6574\u6570\u5c55\u73b0\u7684\u65b9\u5f0f\u88ab\u79f0\u4e3a\u5206\u7c7b\u6216\u5b57\u5178\u7f16\u7801\u5c55\u73b0\u3002\u4e0d\u540c\u503c\u7684\u6570\u7ec4\u53ef\u4ee5\u88ab\u79f0\u4e3a\u6570\u636e\u7684\u7c7b\u522b\u3001\u5b57\u5178\u6216\u5c42\u7ea7\u3002 print(dim.take(values)) # 0 apple # 1 oragne # 0 apple # 0 apple # 0 apple # 1 oragne # 0 apple # 0 apple # dtype: object \u5728\u505a\u6570\u636e\u5206\u6790\u65f6\uff0c\u5206\u7c7b\u5c55\u793a\u4f1a\u4ea7\u751f\u663e\u8457\u7684\u6027\u80fd\u63d0\u5347\u3002\u53ef\u4ee5\u5728\u7c7b\u522b\u4e0a\u8fdb\u884c\u8f6c\u6362\u540c\u65f6\u4e0d\u6539\u53d8\u4ee3\u7801\u3002 \u4ee5\u4e0b\u662f\u4e00\u4e9b\u76f8\u5bf9\u4f4e\u5f00\u9500\u7684\u8f6c\u6362\u793a\u4f8b\uff1a \u91cd\u547d\u540d\u7c7b\u522b \u5728\u4e0d\u6539\u53d8\u5df2\u6709\u7684\u7c7b\u522b\u987a\u5e8f\u7684\u60c5\u51b5\u4e0b\u6dfb\u52a0\u4e00\u4e2a\u65b0\u7684\u7c7b\u522b","title":"\u80cc\u666f\u548c\u76ee\u6807"},{"location":"python/DataAnalysis/ch09/#pandascategorical","text":"pandas\u62e5\u6709\u7279\u6b8a\u7684 Categorical \u7c7b\u578b\uff0c\u7528\u4e8e\u627f\u8f7d\u57fa\u4e8e\u6574\u6570\u7684\u7c7b\u522b\u5c55\u793a\u6216\u7f16\u7801\u7684\u6570\u636e\u3002 fruits = ['apple', 'orange', 'apple', 'apple'] * 2 N = len(fruits) df = pd.DataFrame( { 'fruit': fruits, 'basket_id': np.arange(N), 'count': np.random.randint(3, 15, size=N), 'weight': np.random.uniform(0, 4, size=N) }, columns=['basket_id', 'fruit', 'count', 'weight'] ) print(df) # basket_id fruit count weight # 0 0 apple 8 1.288867 # 1 1 orange 4 3.414430 # 2 2 apple 7 3.222160 # 3 3 apple 14 2.724804 # 4 4 apple 8 3.548828 # 5 5 orange 10 0.918739 # 6 6 apple 4 0.784816 # 7 7 apple 10 3.140607 df['fruit'] \u662f\u4e00\u4e2aPython\u5b57\u7b26\u4e32\u5bf9\u8c61\u7ec4\u6210\u7684\u6570\u7ec4\u3002\u53ef\u4ee5\u901a\u8fc7\u8c03\u7528\u51fd\u6570\u5c06\u5b83\u8f6c\u6362\u4e3a Categorical \u5bf9\u8c61\uff1a fruit_cat = df['fruit'].astype('category') print(fruit_cat) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # Name: fruit, dtype: category # Categories (2, object): ['apple', 'orange'] fruit_cat \u7684\u503c\u5e76\u4e0d\u662fNumPy\u6570\u7ec4\uff0c\u800c\u662f pandas.Categorical \u7684\u5b9e\u4f8b\uff1a c = fruit_cat.values print(type(c)) # print(c) # ['apple', 'orange', 'apple', 'apple', 'apple', 'orange', 'apple', 'apple'] # Categories (2, object): ['apple', 'orange'] Categorical \u5bf9\u8c61\u62e5\u6709 categories \u548c codes \u5c5e\u6027\uff1a print(c.categories) # Index(['apple', 'orange'], dtype='object') print(c.codes) # [0 1 0 0 0 1 0 0] \u901a\u8fc7\u5206\u914d\u5df2\u8f6c\u6362\u7684\u7ed3\u679c\u5c06DataFrame\u7684\u4e00\u5217\u8f6c\u6362\u4e3a Categorical \u5bf9\u8c61\uff1a print(df['fruit']) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # Name: fruit, dtype: object df['fruit'] = df['fruit'].astype('category') print(df['fruit']) # 0 apple # 1 orange # 2 apple # 3 apple # 4 apple # 5 orange # 6 apple # 7 apple # Name: fruit, dtype: category # Categories (2, object): ['apple', 'orange'] \u4e5f\u53ef\u4ee5\u4ece\u5176\u4ed6Python\u5e8f\u5217\u7c7b\u578b\u76f4\u63a5\u751f\u6210 pandas.Categorical \uff1a my_categories = pd.Categorical(['foo', 'bar', 'baz', 'foo', 'bar']) print(my_categories) # ['foo', 'bar', 'baz', 'foo', 'bar'] # Categories (3, object): ['bar', 'baz', 'foo'] \u4e5f\u53ef\u4ee5\u4f7f\u7528 from_codes \u6784\u9020\u51fd\u6570\u6765\u8f6c\u6362\u5176\u4ed6\u6570\u636e\u6e90\u7684\u5206\u7c7b\u7f16\u7801\u6570\u636e\uff1a categories = ['foo', 'bar', 'baz'] codes = [0, 1, 2, 0, 0, 1] my_cats_2 = pd.Categorical.from_codes(codes, categories) print(my_cats_2) # ['foo', 'bar', 'baz', 'foo', 'foo', 'bar'] # Categories (3, object): ['foo', 'bar', 'baz'] \u8fd9\u4e2a\u672a\u6392\u5e8f\u7684\u5206\u7c7b\u5b9e\u4f8b\u53ef\u4ee5\u4f7f\u7528 as_ordered \u8fdb\u884c\u6392\u5e8f\uff1a print(my_cats_2.as_ordered()) # ['foo', 'bar', 'baz', 'foo', 'foo', 'bar'] # Categories (3, object): ['foo' < 'bar' < 'baz'] \u9664\u975e\u663e\u5f0f\u5730\u6307\u5b9a\uff0c\u5206\u7c7b\u8f6c\u6362\u662f\u4e0d\u4f1a\u6307\u5b9a\u7c7b\u522b\u7684\u987a\u5e8f\u7684\u3002\u56e0\u6b64 categories \u6570\u7ec4\u53ef\u80fd\u4f1a\u4e0e\u8f93\u5165\u6570\u636e\u7684\u987a\u5e8f\u4e0d\u540c\u3002 \u5f53\u4f7f\u7528 from_codes \u6216\u5176\u4ed6\u4efb\u610f\u6784\u9020\u51fd\u6570\u65f6\uff0c\u53ef\u4ee5\u4e3a\u7c7b\u522b\u6307\u5b9a\u4e00\u4e2a\u6709\u610f\u4e49\u7684\u987a\u5e8f\uff1a\u8f93\u51fa\u7684 [foo df.pipe(len) # \u4f20\u9012\u7684\u662flen\u5b9e\u4f8b # 4 def fun(df): return df * 2 fun(df) # 0 1 2 # 0 2.0 4.0 6.0 # 1 2.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 4.0 6.0 df.pipe(fun) # \u4f20\u9012\u7684\u662ffun\u51fd\u6570 # 0 1 2 # 0 2.0 4.0 6.0 # 1 2.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 4.0 6.0 def fun2(x, df): # \u6570\u636e\u662f\u7b2c\u4e8c\u4e2a\u53c2\u6570 return df * 3 df.pipe((fun2, 'df'), 2) # \u6ce8\u610f\u4f20\u503c # 0 1 2 # 0 3.0 6.0 9.0 # 1 3.0 NaN NaN # 2 NaN NaN NaN # 3 NaN 6.0 9.0","title":"DataFrame\u793a\u4f8b\uff1a"},{"location":"python/DataAnalysis/ch09/#series","text":"s = pd.Series([1, 2, 3, 4, 5]) s.pipe(type) # s.pipe(len) # 5 def fun3(x, ss): return ss * 3 s.pipe((fun3, 'ss'), 2) # 0 3 # 1 6 # 2 9 # 3 12 # 4 15 # dtype: int64","title":"Series \u793a\u4f8b\uff1a"},{"location":"python/DataAnalysis/ch09/#groupby_2","text":"df = pd.DataFrame({'A': 'a b a b'.split(), 'B': [1, 2, 3, 4]}) print(df) # A B # 0 a 1 # 1 b 2 # 2 a 3 # 3 b 4 \u6c42\u6bcf\u7ec4\u6700\u5927\u503c\u548c\u6700\u5c0f\u503c\u4e4b\u95f4\u7684\u5dee\u5f02\u3002 df.groupby('A').pipe(lambda x: x.max() - x.min()) # B # A # a 2 # b 2 def mean1(groupby): return groupby.mean() df.groupby(['A']).pipe(mean1) # B # A # a 2.0 # b 3.0","title":"GroupBy \u793a\u4f8b\uff1a"},{"location":"python/DataAnalysis/ch10/","text":"NumPy\u8fdb\u9636 \u00b6 \u5305\u542b\u4ee5\u4e0b\u5185\u5bb9\uff1a ndarray\u5bf9\u8c61\u7684\u5185\u90e8\u673a\u7406 \u9ad8\u7ea7\u6570\u7ec4\u64cd\u4f5c \u91cd\u5851\u6570\u7ec4 C\u987a\u5e8f\u548cF\u987a\u5e8f \u8fde\u63a5\u548c\u5206\u9694\u6570\u7ec4 \u5806\u53e0\u52a9\u624b\uff1ar \u548cc \u91cd\u590d\u5143\u7d20\uff1atile\u548crepeat \u795e\u5947\u7d22\u5f15\u7684\u7b49\u4ef7\u65b9\u6cd5\uff1atake\u548cput \u5e7f\u64ad ufunc\u9ad8\u7ea7\u5e94\u7528 \u7ed3\u6784\u5316\u548c\u8bb0\u5f55\u5f0f\u6570\u7ec4 ndarray\u5bf9\u8c61\u7684\u5185\u90e8\u673a\u7406 \u00b6 NumPy\u7684 ndarray \u63d0\u4f9b\u4e86\u4e00\u79cd\u5c06\u540c\u8d28\u6570\u636e\u5757\uff08\u53ef\u4ee5\u662f\u8fde\u7eed\u6216\u8de8\u8d8a\uff09\u89e3\u91ca\u4e3a\u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61\u7684\u65b9\u5f0f\u3002 ndarray \u7684\u6570\u636e\u7c7b\u578b dtype \u51b3\u5b9a\u4e86\u6570\u636e\u7684\u89e3\u91ca\u65b9\u5f0f\uff0c\u6bd4\u5982\u6d6e\u70b9\u6570\u3001\u6574\u6570\u3001\u5e03\u5c14\u503c\u7b49\u3002 ndarray \u7684\u6240\u6709\u6570\u7ec4\u5bf9\u8c61\u90fd\u662f\u6570\u636e\u5757\u7684\u4e00\u4e2a\u8de8\u5ea6\u89c6\u56fe\uff08strided view\uff09\u3002 \u6570\u7ec4\u89c6\u56fe arr[::2,::-1] \u4e0d\u590d\u5236\u4efb\u4f55\u6570\u636e\u7684\u539f\u56e0\u662f\u4ec0\u4e48\uff1f \u7b80\u5355\u5730\u8bf4\uff0c ndarray \u4e0d\u53ea\u662f\u4e00\u5757\u5185\u5b58\u548c\u4e00\u4e2a dtype \uff0c\u5b83\u8fd8\u6709\u8de8\u5ea6\u4fe1\u606f\uff0c\u8fd9\u4f7f\u5f97\u6570\u7ec4\u80fd\u4ee5\u5404\u79cd\u6b65\u5e45\uff08step size\uff09\u5728\u5185\u5b58\u4e2d\u79fb\u52a8\u3002 \u66f4\u51c6\u786e\u5730\u8bb2\uff0c ndarray \u5185\u90e8\u7531\u4ee5\u4e0b\u5185\u5bb9\u7ec4\u6210\uff1a \u4e00\u4e2a\u6307\u5411\u6570\u636e\uff08\u5185\u5b58\u6216\u5185\u5b58\u6620\u5c04\u6587\u4ef6\u4e2d\u7684\u4e00\u5757\u6570\u636e\uff09\u7684\u6307\u9488\u3002 \u6570\u636e\u7c7b\u578b\u6216 dtype \uff0c\u63cf\u8ff0\u5728\u6570\u7ec4\u4e2d\u7684\u56fa\u5b9a\u5927\u5c0f\u503c\u7684\u683c\u5b50\u3002 \u4e00\u4e2a\u8868\u793a\u6570\u7ec4\u5f62\u72b6\uff08shape\uff09\u7684\u5143\u7ec4\u3002 \u4e00\u4e2a\u8de8\u5ea6\u5143\u7ec4\uff08stride\uff09\uff0c\u5176\u4e2d\u7684\u6574\u6570\u6307\u7684\u662f\u4e3a\u4e86\u524d\u8fdb\u5230\u5f53\u524d\u7ef4\u5ea6\u4e0b\u4e00\u4e2a\u5143\u7d20\u9700\u8981\u201c\u8de8\u8fc7\u201d\u7684\u5b57\u8282\u6570\u3002 \u4f8b\u5982\uff0c\u4e00\u4e2a10\u00d75\u7684\u6570\u7ec4\uff0c\u5176shape\u4e3a(10, 5)\uff1a s = np.ones((10, 5)).shape print(s) # (10, 5) \u4e00\u4e2a\u5178\u578b\u7684\uff08C\u9636\uff093\u00d74\u00d75 float64\u503c\uff088\u5b57\u8282\uff09\u7684\u6570\u7ec4\u5177\u6709\u8de8\u5ea6\uff08160,40,8\uff09\uff08\u901a\u5e38\u7279\u5b9a\u8f74\u4e0a\u7684\u8de8\u5ea6\u8d8a\u5927\uff0c\u6cbf\u7740\u8be5\u8f74\u6267\u884c\u8ba1\u7b97\u7684\u4ee3\u4ef7\u8d8a\u9ad8\uff09\uff1a s = np.ones((3, 4, 5), dtype=np.float64).strides print(s) # (160, 40, 8) \u6570\u7ec4\u8de8\u5ea6\uff08strides\uff09\u662f\u6784\u5efa\u201c\u96f6\u590d\u5236\u201d\u6570\u7ec4\u89c6\u56fe\u7684\u5173\u952e\u56e0\u7d20\u3002 \u6570\u7ec4\u8de8\u5ea6\u751a\u81f3\u53ef\u4ee5\u662f\u8d1f\u7684\uff0c\u8fd9\u4f7f\u5f97\u6570\u7ec4\u80fd\u591f\u7a7f\u8fc7\u5185\u5b58\u201c\u5411\u540e\u201d\u79fb\u52a8\uff08\u4f8b\u5982\uff0c\u5728\u8bf8\u5982obj[::-1]\u6216obj[:, ::-1]\u7684\u5207\u7247\u4e2d\u5c31\u662f\u8fd9\u79cd\u60c5\u51b5\uff09\u3002 NumPy dtype\u5c42\u6b21\u7ed3\u6784 \u00b6 \u6709\u65f6\u5019\u9700\u8981\u901a\u8fc7\u4e00\u4e9b\u4ee3\u7801\u6765\u68c0\u67e5\u6570\u7ec4\u662f\u5426\u5305\u542b\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u5b57\u7b26\u4e32\u6216Python\u5bf9\u8c61\u3002 \u7531\u4e8e\u6d6e\u70b9\u6570\u6709\u591a\u79cd\u7c7b\u578b\uff08float16\u5230float128\uff09\uff0c\u56e0\u6b64\u68c0\u67e5dtype\u662f\u5426\u5728\u7c7b\u578b\u5217\u8868\u4e2d\u4f1a\u975e\u5e38\u9ebb\u70e6\u3002 dtype\u6709\u8d85\u7c7b\uff0c\u5982np.integer\u548cnp.floating\uff0c\u5b83\u4eec\u53ef\u4ee5\u548cnp.issubdtype\u51fd\u6570\u4e00\u8d77\u4f7f\u7528\uff1a ints = np.ones(10, dtype=np.uint16) floats = np.ones(10, dtype=np.float32) \u53ef\u4ee5\u901a\u8fc7\u8c03\u7528\u7c7b\u578b\u7684mro\u65b9\u6cd5\u6765\u67e5\u770b\u7279\u5b9adtype\u7684\u6240\u6709\u7236\u7c7b\uff1a print(np.float64.mro()) # [, # , # , # , # , # , # ] print(np.issubdtype(ints.dtype, np.integer)) # True print(np.issubdtype(floats.dtype, np.floating)) # True print(np.issubdtype(floats.dtype, np.number)) # True print(np.issubdtype(floats.dtype, np.generic)) # True \u9ad8\u7ea7\u6570\u7ec4\u64cd\u4f5c \u00b6 \u91cd\u5851\u6570\u7ec4 \u00b6 \u901a\u5e38\uff0c\u901a\u8fc7 reshape \u5c06\u6570\u7ec4\u4ece\u4e00\u4e2a\u5f62\u72b6\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u5f62\u72b6\uff0c\u5e76\u4e14\u4e0d\u590d\u5236\u4efb\u4f55\u6570\u636e\u3002 reshape \u91cc\u9762\u6709\u4e24\u79cd\u91cd\u5851\u987a\u5e8f\uff0c\u6309C\u987a\u5e8f\uff08\u884c\u65b9\u5411\uff09\u7684\u91cd\u5851\u548c\u6309Fortran\u987a\u5e8f\uff08\u5217\u65b9\u5411\uff09\u7684\u91cd\u5851\u3002 \u9996\u5148\u662f\u53d6\u6570\uff0c\u7136\u540e\u662f\u653e\u6570\uff0c\u53d6\u6570\u6309\u4ec0\u4e48\u987a\u5e8f\uff0c\u653e\u6570\u5c31\u6309\u4ec0\u4e48\u987a\u5e8f\u3002 \u4e0b\u9762\u662f\u5b98\u7f51\u7684\u89e3\u91ca\uff1a \u2018C\u2019 means to read / write the elements using C-like index order, with the last axis index changing fastest, back to the first axis index changing slowest. \u2018F\u2019 means to read / write the elements using Fortran-like index order, with the first index changing fastest, and the last index changing slowest. Note that the \u2018C\u2019 and \u2018F\u2019 options take no account of the memory layout of the underlying array, and only refer to the order of indexing. \u2018A\u2019 means to read / write the elements in Fortran-like index order if a is Fortran contiguous in memory, C-like order otherwise. \u4e00\u7ef4\u6570\u7ec4\u91cd\u5851\uff1a arr = np.arange(8) print(arr) # [0 1 2 3 4 5 6 7] a = arr.reshape((4, 2), order='C') print(a) # [[0 1] # [2 3] # [4 5] # [6 7]] a = arr.reshape((4, 2), order='F') print(a) # [[0 4] # [1 5] # [2 6] # [3 7]] \u591a\u7ef4\u6570\u7ec4\u91cd\u5851\uff1a\u4f20\u9012\u7684\u5f62\u72b6\u7ef4\u5ea6\u53ef\u4ee5\u6709\u4e00\u4e2a\u503c\u662f-1\uff0c\u8868\u793a\u7ef4\u5ea6\u901a\u8fc7\u6570\u636e\u8fdb\u884c\u63a8\u65ad\uff1a a = arr.reshape((4, 2)).reshape((2, 4)) print(a) # [[0 1 2 3] # [4 5 6 7]] arr = np.arange(15) a = arr.reshape((5, -1)) # 15 / 5 = 3\u5217 print(a) # [[ 0 1 2] # [ 3 4 5] # [ 6 7 8] # [ 9 10 11] # [12 13 14]] print(a.shape) # (5, 3) \u6570\u7ec4\u7684 shape \u5c5e\u6027\u662f\u4e00\u4e2a**\u5143\u7ec4**\uff0c\u5b83\u4e5f\u53ef\u4ee5\u88ab\u4f20\u9012\u7ed9 reshape \uff0c\u63a5\u4e0a\u4f8b\uff1a other_arr = np.ones((3, 5)) print(other_arr.shape) # (3, 5) a = arr.reshape(other_arr.shape) print(a.shape) # (3, 5) reshape \u7684\u53cd\u64cd\u4f5c\u53ef\u4ee5\u5c06\u66f4\u9ad8\u7ef4\u5ea6\u7684\u6570\u7ec4\u8f6c\u6362\u4e3a\u4e00\u7ef4\u6570\u7ec4\uff0c\u8fd9\u79cd\u64cd\u4f5c\u901a\u5e38\u88ab\u6210\u4e3a\u6241\u5e73\u5316\uff08flattening\uff09\u6216\u5206\u6563\u5316\uff08raveling\uff09\u3002 \u5982\u679c\u7ed3\u679c\u4e2d\u7684\u503c\u5728\u539f\u59cb\u6570\u7ec4\u4e2d\u662f\u8fde\u7eed\u7684\uff0c\u5219 ravel \u4e0d\u4f1a\u751f\u6210\u5e95\u5c42\u6570\u503c\u7684\u526f\u672c\u3002 flatten \u65b9\u6cd5\u7684\u884c\u4e3a\u7c7b\u4f3c\u4e8e ravel \uff0c\u4f46\u5b83\u603b\u662f\u751f\u6210\u6570\u636e\u7684\u526f\u672c\u3002 arr = np.arange(15).reshape((5, 3)) print(arr) # [[ 0 1 2] # [ 3 4 5] # [ 6 7 8] # [ 9 10 11] # [12 13 14]] a = arr.ravel() print(a) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] a = arr.flatten() print(a) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] C\u987a\u5e8f\u548cF\u987a\u5e8f \u00b6 \u6570\u636e\u53ef\u4ee5\u6309\u7167\u4e0d\u540c\u7684\u987a\u5e8f\u8fdb\u884c\u91cd\u5851\u6216\u6241\u5e73\u5316\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cNumPy\u6570\u7ec4\u662f\u6309\u884c\u65b9\u5411\u987a\u5e8f\u521b\u5efa\u7684\u3002 \u5bf9\u4e8e\u4e00\u4e2a\u4e8c\u7ef4\u7684\u6570\u636e\u6570\u7ec4\uff0c**C\u987a\u5e8f**\u8bf4\u660e\u6570\u7ec4\u6bcf\u884c\u4e2d\u7684\u5143\u7d20\u5b58\u50a8\u5728\u76f8\u90bb\u7684\u5b58\u50a8\u5355\u5143\u4e2d\u3002**F\u987a\u5e8f**\u610f\u5473\u7740\u6bcf\u5217\u6570\u636e\u4e2d\u7684\u503c\u90fd\u5b58\u50a8\u5728\u76f8\u90bb\u7684\u5185\u5b58\u4f4d\u7f6e\u4e2d\u3002 \u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e reshape \u548c ravel \u51fd\u6570\u7684 order \u53c2\u6570\u6765\u8868\u793a\u6570\u636e\u5728\u6570\u7ec4\u4e2d\u4f7f\u7528\u54ea\u79cd\u987a\u5e8f\u3002 arr = np.arange(15).reshape((5, 3)) print(arr) # [[ 0 1 2] # [ 3 4 5] # [ 6 7 8] # [ 9 10 11] # [12 13 14]] print(arr.ravel()) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] print(arr.ravel('F')) # [ 0 3 6 9 12 1 4 7 10 13 2 5 8 11 14] C\u987a\u5e8f\u548cFortran\u987a\u5e8f\u7684\u6838\u5fc3\u533a\u522b\u5c31\u662f\u5728\u7ef4\u5ea6\u65b9\u5411\u4e0a\u904d\u5386\u7684\u65b9\u5f0f\u3002 C\u987a\u5e8f/\u884c\u65b9\u5411\u987a\u5e8f\u9996\u5148\u904d\u5386\u66f4\u9ad8\u7684\u7ef4\u5ea6\uff08\u4f8b\u5982\uff0c\u5728\u8f740\u4e0a\u884c\u8fdb\u4e4b\u524d\u5148\u5728\u8f741\u4e0a\u884c\u8fdb\uff09\u3002 Fortran\u987a\u5e8f/\u5217\u65b9\u5411\u987a\u5e8f\u6700\u540e\u904d\u5386\u66f4\u9ad8\u7684\u7ef4\u5ea6\uff08\u4f8b\u5982\uff0c\u5728\u8f741\u4e0a\u884c\u8fdb\u4e4b\u524d\u5148\u5728\u8f740\u4e0a\u884c\u8fdb\uff09\u3002 \u6570\u7ec4\u8fde\u63a5\u548c\u5206\u9694 \u00b6 numpy.concatenate \u53ef\u4ee5\u83b7\u53d6\u6570\u7ec4\u7684\u5e8f\u5217\uff08\u5143\u7ec4\u3001\u5217\u8868\u7b49\uff09\uff0c\u5e76\u6cbf\u7740\u8f93\u5165\u8f74\u5c06\u5b83\u4eec\u6309\u987a\u5e8f\u8fde\u63a5\u5728\u4e00\u8d77\uff1a arr1 = np.array( [ [1, 2, 3], [4, 5, 6] ] ) arr2 = np.array( [ [7, 8, 9], [10, 11, 12] ] ) a = np.concatenate([arr1, arr2], axis=0) print(a) # [[ 1 2 3] # [ 4 5 6] # [ 7 8 9] # [10 11 12]] a = np.concatenate([arr1, arr2], axis=1) print(a) # [[ 1 2 3 7 8 9] # [ 4 5 6 10 11 12]] \u5176\u4ed6\u7c7b\u4f3c concatenate \u7684\u51fd\u6570\u3002 vstack \u7c7b\u4f3c concatenate \u6cbf axis=0 \u64cd\u4f5c\uff0c hstack \u7c7b\u4f3c concatenate \u6cbf axis=1 \u64cd\u4f5c\u3002 a = np.vstack((arr1, arr2)) print(a) # [[ 1 2 3] # [ 4 5 6] # [ 7 8 9] # [10 11 12]] a = np.hstack((arr1, arr2)) print(a) # [[ 1 2 3 7 8 9] # [ 4 5 6 10 11 12]] split \u53ef\u4ee5\u5c06\u4e00\u4e2a\u6570\u7ec4\u6cbf\u8f74\u5411\u5207\u7247\u6210\u591a\u4e2a\u6570\u7ec4\u3002\u5148\u770b\u4e00\u7ef4\u6570\u7ec4\u3002 np.split(arr, 3) \u8868\u793a\u5c06\u6570\u7ec4\u62c6\u5206\u65f6\u7684**\u7d22\u5f15\u4f4d\u7f6e** arr = np.array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']) print(arr) # ['a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k'] print(np.split(arr, 3)) print(np.split(arr, [3])) # \u4ece\u7d22\u5f15\u4f4d\u7f6e\u4e3a3\u8fdb\u884c\u62c6\u5206 # [array(['a', 'b', 'c'], dtype=', # , # , # , # , # , # ] print(np.issubdtype(ints.dtype, np.integer)) # True print(np.issubdtype(floats.dtype, np.floating)) # True print(np.issubdtype(floats.dtype, np.number)) # True print(np.issubdtype(floats.dtype, np.generic)) # True","title":"NumPy dtype\u5c42\u6b21\u7ed3\u6784"},{"location":"python/DataAnalysis/ch10/#_1","text":"","title":"\u9ad8\u7ea7\u6570\u7ec4\u64cd\u4f5c"},{"location":"python/DataAnalysis/ch10/#_2","text":"\u901a\u5e38\uff0c\u901a\u8fc7 reshape \u5c06\u6570\u7ec4\u4ece\u4e00\u4e2a\u5f62\u72b6\u8f6c\u6362\u4e3a\u53e6\u4e00\u4e2a\u5f62\u72b6\uff0c\u5e76\u4e14\u4e0d\u590d\u5236\u4efb\u4f55\u6570\u636e\u3002 reshape \u91cc\u9762\u6709\u4e24\u79cd\u91cd\u5851\u987a\u5e8f\uff0c\u6309C\u987a\u5e8f\uff08\u884c\u65b9\u5411\uff09\u7684\u91cd\u5851\u548c\u6309Fortran\u987a\u5e8f\uff08\u5217\u65b9\u5411\uff09\u7684\u91cd\u5851\u3002 \u9996\u5148\u662f\u53d6\u6570\uff0c\u7136\u540e\u662f\u653e\u6570\uff0c\u53d6\u6570\u6309\u4ec0\u4e48\u987a\u5e8f\uff0c\u653e\u6570\u5c31\u6309\u4ec0\u4e48\u987a\u5e8f\u3002 \u4e0b\u9762\u662f\u5b98\u7f51\u7684\u89e3\u91ca\uff1a \u2018C\u2019 means to read / write the elements using C-like index order, with the last axis index changing fastest, back to the first axis index changing slowest. \u2018F\u2019 means to read / write the elements using Fortran-like index order, with the first index changing fastest, and the last index changing slowest. Note that the \u2018C\u2019 and \u2018F\u2019 options take no account of the memory layout of the underlying array, and only refer to the order of indexing. \u2018A\u2019 means to read / write the elements in Fortran-like index order if a is Fortran contiguous in memory, C-like order otherwise. \u4e00\u7ef4\u6570\u7ec4\u91cd\u5851\uff1a arr = np.arange(8) print(arr) # [0 1 2 3 4 5 6 7] a = arr.reshape((4, 2), order='C') print(a) # [[0 1] # [2 3] # [4 5] # [6 7]] a = arr.reshape((4, 2), order='F') print(a) # [[0 4] # [1 5] # [2 6] # [3 7]] \u591a\u7ef4\u6570\u7ec4\u91cd\u5851\uff1a\u4f20\u9012\u7684\u5f62\u72b6\u7ef4\u5ea6\u53ef\u4ee5\u6709\u4e00\u4e2a\u503c\u662f-1\uff0c\u8868\u793a\u7ef4\u5ea6\u901a\u8fc7\u6570\u636e\u8fdb\u884c\u63a8\u65ad\uff1a a = arr.reshape((4, 2)).reshape((2, 4)) print(a) # [[0 1 2 3] # [4 5 6 7]] arr = np.arange(15) a = arr.reshape((5, -1)) # 15 / 5 = 3\u5217 print(a) # [[ 0 1 2] # [ 3 4 5] # [ 6 7 8] # [ 9 10 11] # [12 13 14]] print(a.shape) # (5, 3) \u6570\u7ec4\u7684 shape \u5c5e\u6027\u662f\u4e00\u4e2a**\u5143\u7ec4**\uff0c\u5b83\u4e5f\u53ef\u4ee5\u88ab\u4f20\u9012\u7ed9 reshape \uff0c\u63a5\u4e0a\u4f8b\uff1a other_arr = np.ones((3, 5)) print(other_arr.shape) # (3, 5) a = arr.reshape(other_arr.shape) print(a.shape) # (3, 5) reshape \u7684\u53cd\u64cd\u4f5c\u53ef\u4ee5\u5c06\u66f4\u9ad8\u7ef4\u5ea6\u7684\u6570\u7ec4\u8f6c\u6362\u4e3a\u4e00\u7ef4\u6570\u7ec4\uff0c\u8fd9\u79cd\u64cd\u4f5c\u901a\u5e38\u88ab\u6210\u4e3a\u6241\u5e73\u5316\uff08flattening\uff09\u6216\u5206\u6563\u5316\uff08raveling\uff09\u3002 \u5982\u679c\u7ed3\u679c\u4e2d\u7684\u503c\u5728\u539f\u59cb\u6570\u7ec4\u4e2d\u662f\u8fde\u7eed\u7684\uff0c\u5219 ravel \u4e0d\u4f1a\u751f\u6210\u5e95\u5c42\u6570\u503c\u7684\u526f\u672c\u3002 flatten \u65b9\u6cd5\u7684\u884c\u4e3a\u7c7b\u4f3c\u4e8e ravel \uff0c\u4f46\u5b83\u603b\u662f\u751f\u6210\u6570\u636e\u7684\u526f\u672c\u3002 arr = np.arange(15).reshape((5, 3)) print(arr) # [[ 0 1 2] # [ 3 4 5] # [ 6 7 8] # [ 9 10 11] # [12 13 14]] a = arr.ravel() print(a) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] a = arr.flatten() print(a) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]","title":"\u91cd\u5851\u6570\u7ec4"},{"location":"python/DataAnalysis/ch10/#cf","text":"\u6570\u636e\u53ef\u4ee5\u6309\u7167\u4e0d\u540c\u7684\u987a\u5e8f\u8fdb\u884c\u91cd\u5851\u6216\u6241\u5e73\u5316\u3002\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cNumPy\u6570\u7ec4\u662f\u6309\u884c\u65b9\u5411\u987a\u5e8f\u521b\u5efa\u7684\u3002 \u5bf9\u4e8e\u4e00\u4e2a\u4e8c\u7ef4\u7684\u6570\u636e\u6570\u7ec4\uff0c**C\u987a\u5e8f**\u8bf4\u660e\u6570\u7ec4\u6bcf\u884c\u4e2d\u7684\u5143\u7d20\u5b58\u50a8\u5728\u76f8\u90bb\u7684\u5b58\u50a8\u5355\u5143\u4e2d\u3002**F\u987a\u5e8f**\u610f\u5473\u7740\u6bcf\u5217\u6570\u636e\u4e2d\u7684\u503c\u90fd\u5b58\u50a8\u5728\u76f8\u90bb\u7684\u5185\u5b58\u4f4d\u7f6e\u4e2d\u3002 \u53ef\u4ee5\u901a\u8fc7\u8bbe\u7f6e reshape \u548c ravel \u51fd\u6570\u7684 order \u53c2\u6570\u6765\u8868\u793a\u6570\u636e\u5728\u6570\u7ec4\u4e2d\u4f7f\u7528\u54ea\u79cd\u987a\u5e8f\u3002 arr = np.arange(15).reshape((5, 3)) print(arr) # [[ 0 1 2] # [ 3 4 5] # [ 6 7 8] # [ 9 10 11] # [12 13 14]] print(arr.ravel()) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14] print(arr.ravel('F')) # [ 0 3 6 9 12 1 4 7 10 13 2 5 8 11 14] C\u987a\u5e8f\u548cFortran\u987a\u5e8f\u7684\u6838\u5fc3\u533a\u522b\u5c31\u662f\u5728\u7ef4\u5ea6\u65b9\u5411\u4e0a\u904d\u5386\u7684\u65b9\u5f0f\u3002 C\u987a\u5e8f/\u884c\u65b9\u5411\u987a\u5e8f\u9996\u5148\u904d\u5386\u66f4\u9ad8\u7684\u7ef4\u5ea6\uff08\u4f8b\u5982\uff0c\u5728\u8f740\u4e0a\u884c\u8fdb\u4e4b\u524d\u5148\u5728\u8f741\u4e0a\u884c\u8fdb\uff09\u3002 Fortran\u987a\u5e8f/\u5217\u65b9\u5411\u987a\u5e8f\u6700\u540e\u904d\u5386\u66f4\u9ad8\u7684\u7ef4\u5ea6\uff08\u4f8b\u5982\uff0c\u5728\u8f741\u4e0a\u884c\u8fdb\u4e4b\u524d\u5148\u5728\u8f740\u4e0a\u884c\u8fdb\uff09\u3002","title":"C\u987a\u5e8f\u548cF\u987a\u5e8f"},{"location":"python/DataAnalysis/ch10/#_3","text":"numpy.concatenate \u53ef\u4ee5\u83b7\u53d6\u6570\u7ec4\u7684\u5e8f\u5217\uff08\u5143\u7ec4\u3001\u5217\u8868\u7b49\uff09\uff0c\u5e76\u6cbf\u7740\u8f93\u5165\u8f74\u5c06\u5b83\u4eec\u6309\u987a\u5e8f\u8fde\u63a5\u5728\u4e00\u8d77\uff1a arr1 = np.array( [ [1, 2, 3], [4, 5, 6] ] ) arr2 = np.array( [ [7, 8, 9], [10, 11, 12] ] ) a = np.concatenate([arr1, arr2], axis=0) print(a) # [[ 1 2 3] # [ 4 5 6] # [ 7 8 9] # [10 11 12]] a = np.concatenate([arr1, arr2], axis=1) print(a) # [[ 1 2 3 7 8 9] # [ 4 5 6 10 11 12]] \u5176\u4ed6\u7c7b\u4f3c concatenate \u7684\u51fd\u6570\u3002 vstack \u7c7b\u4f3c concatenate \u6cbf axis=0 \u64cd\u4f5c\uff0c hstack \u7c7b\u4f3c concatenate \u6cbf axis=1 \u64cd\u4f5c\u3002 a = np.vstack((arr1, arr2)) print(a) # [[ 1 2 3] # [ 4 5 6] # [ 7 8 9] # [10 11 12]] a = np.hstack((arr1, arr2)) print(a) # [[ 1 2 3 7 8 9] # [ 4 5 6 10 11 12]] split \u53ef\u4ee5\u5c06\u4e00\u4e2a\u6570\u7ec4\u6cbf\u8f74\u5411\u5207\u7247\u6210\u591a\u4e2a\u6570\u7ec4\u3002\u5148\u770b\u4e00\u7ef4\u6570\u7ec4\u3002 np.split(arr, 3) \u8868\u793a\u5c06\u6570\u7ec4\u62c6\u5206\u65f6\u7684**\u7d22\u5f15\u4f4d\u7f6e** arr = np.array(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k']) print(arr) # ['a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k'] print(np.split(arr, 3)) print(np.split(arr, [3])) # \u4ece\u7d22\u5f15\u4f4d\u7f6e\u4e3a3\u8fdb\u884c\u62c6\u5206 # [array(['a', 'b', 'c'], dtype='|t| [0.025 0.975] # ------------------------------------------------------------------------------ # x1 0.1783 0.053 3.364 0.001 0.073 0.283 # x2 0.2230 0.046 4.818 0.000 0.131 0.315 # x3 0.5010 0.080 6.237 0.000 0.342 0.660 # ============================================================================== # Omnibus: 4.662 Durbin-Watson: 0 -0.002327 # Prob(Omnibus): 0.097 Jarque-Bera (JB): 4.098 # Skew: 0.481 Prob(JB): 0.129 # Kurtosis: 3.243 Cond. No. 1.74 # ============================================================================== # # Notes: # [1] R\u00b2 is computed without centering (uncentered) since the model does not contain a constant. # [2] Standard Errors assume that the covariance matrix of the errors is correctly specified. \u5047\u8bbe\u6240\u6709\u6a21\u578b\u53c2\u6570\u90fd\u5728DataFrame\u4e2d\uff1a data = pd.DataFrame(X, columns=['col0', 'col1', 'col2']) data['y'] = y print(data[:5]) # col0 col1 col2 y # 0 -0.129468 -1.212753 0.504225 0.427863 # 1 0.302910 -0.435742 -0.254180 -0.673480 # 2 -0.328522 -0.025302 0.138351 -0.090878 # 3 -0.351475 -0.719605 -0.258215 -0.489494 # 4 1.243269 -0.373799 -0.522629 -0.128941 \u73b0\u5728\u53ef\u4ee5\u4f7f\u7528 statsmodels \u516c\u5f0fAPI\u548cPatsy\u516c\u5f0f\u5b57\u7b26\u4e32\u3002\u89c2\u5bdf statsmodels \u5982\u4f55\u5c06\u7ed3\u679c\u4f5c\u4e3a\u5e26\u6709DataFrame\u5217\u540d\u79f0\u7684Series\u8fd4\u56de\u3002 results = smf.ols('y ~ col0 + col1 + col2', data=data).fit() print(results.params) # Intercept 0.033559 # col0 0.176149 # col1 0.224826 # col2 0.514808 # dtype: float64 \u7ed9\u5b9a\u65b0\u7684\u6837\u672c\u5916\u6570\u636e\u540e\uff0c\u53ef\u4ee5\u6839\u636e\u4f30\u8ba1\u7684\u6a21\u578b\u53c2\u6570\u8ba1\u7b97\u9884\u6d4b\u503c\uff1a print(results.predict(data[:5])) # 0 -0.002327 # 1 -0.141904 # 2 0.041226 # 3 -0.323070 # 4 -0.100535 # dtype: float64 \u8bc4\u4f30\u65f6\u95f4\u5e8f\u5217\u5904\u7406 \u00b6 statsmodels\u4e2d\u7684\u53e6\u4e00\u7c7b\u6a21\u578b\u7528\u4e8e\u65f6\u95f4\u5e8f\u5217\u5206\u6790\u3002\u5176\u4e2d\u5305\u62ec\u81ea\u56de\u5f52\u8fc7\u7a0b\uff0c\u5361\u5c14\u66fc\u6ee4\u6ce2\u548c\u5176\u4ed6\u72b6\u6001\u7a7a\u95f4\u6a21\u578b\uff0c\u4ee5\u53ca\u591a\u53d8\u91cf\u81ea\u56de\u5f52\u6a21\u578b\u3002 \u4e0b\u4f8b\u6a21\u62df\u4e00\u4e9b\u5177\u6709\u81ea\u56de\u5f52\u7ed3\u6784\u548c\u566a\u58f0\u7684\u65f6\u95f4\u5e8f\u5217\u6570\u636e\uff0c\u8be5\u6570\u636e\u5177\u6709\u53c2\u6570\u4e3a0.8\u548c-0.4\u7684AR\uff082\uff09\u7ed3\u6784\uff08\u4e24\u4e2a\u6ede\u540e\uff09\u3002 init_x = 4 values = [init_x, init_x] N = 1000 b0 = 0.8 b1 = -0.4 noise = dnorm(0, 0.1, N) for i in range(N): new_x = values[-1] * b0 + values[-2] * b1 + noise[i] values.append(new_x) \u5f53\u62df\u5408\u4e00\u4e2aAR\u6a21\u578b\u65f6\uff0c\u4f60\u53ef\u80fd\u4e0d\u77e5\u9053\u5305\u542b\u7684\u6ede\u540e\u9879\u7684\u6570\u91cf\uff0c\u6240\u4ee5\u53ef\u4ee5\u7528\u66f4\u5927\u7684\u6ede\u540e\u6570\u6765\u62df\u5408\u8be5\u6a21\u578b\uff1a MAXLAGS = 5 model = sm.tsa.AR(values) results = model.fit(MAXLAGS) print(results.params) # NotImplementedError: AR has been removed from statsmodels and replaced with statsmodels.tsa.ar_model.AutoReg. sikit-learn\u4ecb\u7ecd \u00b6 scikit-learn\uff08http://scikit-learn.org\uff09\u662f\u4f7f\u7528\u6700\u5e7f\u6cdb\u4e14\u6700\u53d7\u4fe1\u4efb\u7684\u901a\u7528Python\u673a\u5668\u5b66\u4e60\u5e93\u3002\\ \u5b83\u5305\u542b\u5e7f\u6cdb\u7684\u6807\u51c6\u76d1\u7763\u7684\u548c\u65e0\u76d1\u7763\u7684\u673a\u5668\u5b66\u4e60\u65b9\u6cd5\uff0c\u5305\u62ec\u7528\u4e8e\u6a21\u578b\u9009\u62e9\u548c\u8bc4\u4f30\u3001\u6570\u636e\u8f6c\u6362\u3001\u6570\u636e\u52a0\u8f7d\u548c\u6a21\u578b\u6301\u4e45\u5316\u7684\u5de5\u5177\u3002\\ \u8fd9\u4e9b\u6a21\u578b\u53ef\u7528\u4e8e\u5206\u7c7b\u3001\u805a\u7c7b\u3001\u9884\u6d4b\u548c\u5176\u4ed6\u5e38\u89c1\u4efb\u52a1\u3002\\ pandas\u975e\u5e38\u9002\u5408\u5728\u6a21\u578b\u62df\u5408\u524d\u5904\u7406\u6570\u636e\u96c6\u3002 \u4e3e\u4e2a\u4f8b\u5b50\uff0c\u7528\u4e00\u4e2aKaggle\u7ade\u8d5b\u7684\u7ecf\u5178\u6570\u636e\u96c6\uff0c\u5173\u4e8e\u6cf0\u5766\u5c3c\u514b\u53f7\u4e58\u5ba2\u7684\u751f\u8fd8\u7387\u3002\u6211\u4eec\u7528pandas\u52a0\u8f7d\u6d4b\u8bd5\u548c\u8bad\u7ec3\u6570\u636e\u96c6\uff1a import pandas as pd from sklearn.linear_model import LogisticRegression from sklearn.linear_model import LogisticRegressionCV from sklearn.model_selection import cross_val_score train = pd.read_csv('../datasets/titanic/train.csv') test = pd.read_csv('../datasets/titanic/test.csv') print(train[:4]) # PassengerId Survived Pclass ... Fare Cabin Embarked # 0 1 0 3 ... 7.2500 NaN S # 1 2 1 1 ... 71.2833 C85 C # 2 3 1 3 ... 7.9250 NaN S # 3 4 1 1 ... 53.1000 C123 S \u50cfstatsmodels\u548cscikit-learn\u901a\u5e38\u4e0d\u80fd\u63d0\u4f9b\u7f3a\u5931\u6570\u636e\uff0c\u56e0\u6b64\u6211\u4eec\u8981\u68c0\u67e5\u5404\u5217\uff0c\u770b\u770b\u662f\u5426\u6709\u5305\u542b\u7f3a\u5931\u6570\u636e\uff1a print(train.isnull().sum()) # PassengerId 0 # Survived 0 # Pclass 0 # Name 0 # Sex 0 # Age 177 # SibSp 0 # Parch 0 # Ticket 0 # Fare 0 # Cabin 687 # Embarked 2 # dtype: int64 print(test.isnull().sum()) # PassengerId 0 # Pclass 0 # Name 0 # Sex 0 # Age 86 # SibSp 0 # Parch 0 # Ticket 0 # Fare 1 # Cabin 327 # Embarked 0 # dtype: int64 \u5728\u50cf\u8fd9\u6837\u7684\u7edf\u8ba1\u548c\u673a\u5668\u5b66\u4e60\u7684\u4f8b\u5b50\u4e2d\uff0c\u4e00\u4e2a\u5178\u578b\u7684\u4efb\u52a1\u662f\u6839\u636e\u6570\u636e\u4e2d\u7684\u7279\u5f81\u6765\u9884\u6d4b\u4e58\u5ba2\u662f\u5426\u80fd\u5e78\u5b58\u4e0b\u6765\u3002\\ \u5c06\u6a21\u578b\u62df\u5408\u5230\u8bad\u7ec3\u6570\u636e\u96c6\u4e0a\uff0c\u7136\u540e\u5728\u6837\u672c\u5916\u6d4b\u8bd5\u6570\u636e\u96c6\u4e0a\u8fdb\u884c\u8bc4\u4f30\u3002\\ \u5982\u679c\u7528Age\u4f5c\u4e3a\u9884\u6d4b\uff0c\u4f46\u5b83\u7f3a\u5c11\u6570\u636e\u3002\u9700\u8981\u8fdb\u884c\u7f3a\u5931\u6570\u636e\u63d2\u8865\uff08imputation\uff09\uff0c\u5e76\u4f7f\u7528\u8bad\u7ec3\u6570\u636e\u96c6\u7684\u4e2d\u95f4\u503c\u586b\u5145\u4e24\u4e2a\u8868\u4e2d\u7684\u7a7a\u503c\uff1a impute_value = train['Age'].median() train['Age'] = train['Age'].fillna(impute_value) test['Age'] = test['Age'].fillna(impute_value) \u73b0\u5728\u5efa\u7acb\u6a21\u578b\u3002\\ \u6dfb\u52a0\u4e00\u5217IsFemale\u4f5c\u4e3a\u2019Sex\u2019\u5217\u7684\u7f16\u7801\u7248\u672c\uff1a train['IsFemale'] = (train['Sex'] == 'female').astype(int) test['IsFemale'] = (test['Sex'] == 'female').astype(int) \u786e\u5b9a\u4e00\u4e9b\u6a21\u578b\u53d8\u91cf\u5e76\u521b\u5efaNumPy\u6570\u7ec4\uff1a predictors = ['Pclass', 'IsFemale', 'Age'] X_train = train[predictors].values X_test = test[predictors].values y_train = train['Survived'].values print(X_train[:5]) # [[ 3. 0. 22.] # [ 1. 1. 38.] # [ 3. 1. 26.] # [ 1. 1. 35.] # [ 3. 0. 35.]] print(y_train[:5]) # [0 1 1 1 0] \u4f7f\u7528scikit-learn\u7684LogisticRegression\u6a21\u578b\u521b\u5efa\u4e00\u4e2a\u6a21\u578b\u5b9e\u4f8b\uff1a model = LogisticRegression() \u4e0estatsmodels\u7c7b\u4f3c\uff0c\u4f7f\u7528\u6a21\u578b\u7684fit\u65b9\u6cd5\u5728\u8bad\u7ec3\u6570\u636e\u4e0a\u62df\u5408\u6a21\u578b\uff1a result = model.fit(X_train, y_train) print(result) # LogisticRegression() \u4f7f\u7528model.predict\u4e3a\u6d4b\u8bd5\u6570\u636e\u96c6\u5f62\u6210\u9884\u6d4b\uff1a y_predict = model.predict(X_test) print(y_predict[:10]) # [0 0 0 0 1 0 1 0 1 0] \u5b9e\u9645\u4e0a\uff0c\u6a21\u578b\u8bad\u7ec3\u4e2d\u7ecf\u5e38\u5b58\u5728\u8bb8\u591a\u9644\u52a0\u7684\u590d\u6742\u5c42\u6b21\u3002\\ \u8bb8\u591a\u6a21\u578b\u5177\u6709\u53ef\u4ee5\u8c03\u6574\u7684\u53c2\u6570\uff0c\u5e76\u4e14\u5b58\u5728\u53ef\u7528\u4e8e\u53c2\u6570\u8c03\u6574\u7684\u4ea4\u53c9\u9a8c\u8bc1\u7b49\u6280\u672f\u4ee5\u907f\u514d\u8fc7\u5ea6\u62df\u5408\u8bad\u7ec3\u6570\u636e\u3002\\ \u8fd9\u901a\u5e38\u53ef\u4ee5\u5728\u65b0\u6570\u636e\u4e0a\u4ea7\u751f\u66f4\u597d\u7684\u9884\u6d4b\u6027\u80fd\u6216\u7a33\u5065\u6027\u3002\u4ea4\u53c9\u9a8c\u8bc1\u901a\u8fc7\u5206\u5272\u8bad\u7ec3\u6570\u636e\u6765\u6a21\u62df\u6837\u672c\u5916\u9884\u6d4b\u3002\\ \u57fa\u4e8e\u50cf\u5747\u65b9\u8bef\u5dee\u4e4b\u7c7b\u7684\u6a21\u578b\u51c6\u786e\u5ea6\u5206\u6570\uff0c\u53ef\u4ee5\u5bf9\u6a21\u578b\u53c2\u6570\u6267\u884c\u7f51\u683c\u641c\u7d22\u3002\\ \u4e00\u4e9b\u6a21\u578b\uff0c\u5982\u903b\u8f91\u56de\u5f52\uff0c\u5177\u6709\u5185\u7f6e\u4ea4\u53c9\u9a8c\u8bc1\u7684\u4f30\u8ba1\u7c7b\u3002\\ \u4f8b\u5982\uff0cLogisticRegressionCV\u7c7b\u53ef\u4ee5\u4e0e\u4e00\u4e2a\u53c2\u6570\u4e00\u8d77\u4f7f\u7528\uff0c\u8be5\u53c2\u6570\u8868\u793a\u7f51\u683c\u641c\u7d22\u5728\u6a21\u578b\u6b63\u5219\u5316\u53c2\u6570C\u4e0a\u7684\u7ec6\u81f4\u5ea6\uff1a model_cv = LogisticRegressionCV() result = model_cv.fit(X_train, y_train) print(result) # LogisticRegressionCV() \u8981\u624b\u52a8\u8fdb\u884c\u4ea4\u53c9\u9a8c\u8bc1\uff0c\u53ef\u4ee5\u4f7f\u7528cross_val_score\u51fd\u6570\uff0c\u8be5\u51fd\u6570\u5904\u7406\u6570\u636e\u62c6\u5206\u8fc7\u7a0b\u3002\\ \u4f8b\u5982\uff0c\u4e3a\u4e86\u7528\u6211\u4eec\u7684\u6a21\u578b\u4e0e\u8bad\u7ec3\u6570\u636e\u7684\u56db\u4e2a\u975e\u91cd\u53e0\u5206\u5272\u8fdb\u884c\u4ea4\u53c9\u9a8c\u8bc1\uff0c\u53ef\u4ee5\u8fd9\u6837\u505a\uff1a model = LogisticRegression(C=10) scores = cross_val_score(model, X_train, y_train, cv=4) print(scores) # [0.77578475 0.79820628 0.77578475 0.78828829] \u9ed8\u8ba4\u8bc4\u5206\u6307\u6807\u662f\u4f9d\u8d56\u4e8e\u6a21\u578b\u7684\uff0c\u4f46\u53ef\u4ee5\u9009\u62e9\u660e\u786e\u7684\u8bc4\u5206\u51fd\u6570\u3002\u7ecf\u8fc7\u4ea4\u53c9\u9a8c\u8bc1\u7684\u6a21\u578b\u9700\u8981\u66f4\u957f\u65f6\u95f4\u7684\u8bad\u7ec3\uff0c\u4f46\u901a\u5e38\u53ef\u4ee5\u4ea7\u751f\u66f4\u597d\u7684\u6a21\u578b\u6027\u80fd\u3002","title":"Python\u5efa\u6a21\u5e93\u4ecb\u7ecd"},{"location":"python/DataAnalysis/ch11/#python","text":"","title":"Python\u5efa\u6a21\u5e93\u4ecb\u7ecd"},{"location":"python/DataAnalysis/ch11/#pandas","text":"\u4ecb\u7ecd\u4e24\u4e2a\u6d41\u884c\u7684\u5efa\u6a21\u5de5\u5177\u5305\uff1a [statsmodels]http://statsmodels.org\uff09 [scikit-learn]http://scikit-learn.org\uff09 import pandas as pd import numpy as np \u4f7f\u7528pandas\u7528\u4e8e\u6570\u636e\u8f7d\u5165\u548c\u6570\u636e\u6e05\u6d17\uff0c\u4e4b\u540e\u5207\u6362\u5230\u6a21\u578b\u5e93\u53bb\u5efa\u7acb\u6a21\u578b\u662f\u4e00\u4e2a\u5e38\u89c1\u7684\u6a21\u578b\u5f00\u53d1\u5de5\u4f5c\u6d41\u3002 \u5728\u673a\u5668\u5b66\u4e60\u4e2d\uff0c\u7279\u5f81\u5de5\u7a0b\u662f\u6a21\u578b\u5f00\u53d1\u7684\u91cd\u8981\u90e8\u5206\u4e4b\u4e00\u3002 \u7279\u5f81\u5de5\u7a0b\u662f\u6307\u4ece\u539f\u751f\u6570\u636e\u96c6\u4e2d\u63d0\u53d6\u53ef\u7528\u4e8e\u6a21\u578b\u4e0a\u4e0b\u6587\u7684\u6709\u6548\u4fe1\u606f\u7684\u6570\u636e\u8f6c\u6362\u8fc7\u7a0b\u6216\u5206\u6790\u3002 pandas\u548c\u5176\u4ed6\u5206\u6790\u5e93\u7684\u7ed3\u5408\u70b9\u901a\u5e38\u662fNumPy\u6570\u7ec4\u3002 \u8981\u5c06DataFrame\u8f6c\u6362\u4e3aNumPy\u6570\u7ec4\uff0c\u4f7f\u7528 .values \u5c5e\u6027\uff1a df = pd.DataFrame( { 'x0': [1, 2, 3, 4, 5], 'x1': [0.01, -0.01, 0.25, -4.1, 0.], 'y': [-1.5, 0., 3.6, 1.3, -2.] } ) print(df) # x0 x1 y # 0 1 0.01 -1.5 # 1 2 -0.01 0.0 # 2 3 0.25 3.6 # 3 4 -4.10 1.3 # 4 5 0.00 -2.0 print(df.columns) # Index(['x0', 'x1', 'y'], dtype='object') print(df.values) # [[ 1. 0.01 -1.5 ] # [ 2. -0.01 0. ] # [ 3. 0.25 3.6 ] # [ 4. -4.1 1.3 ] # [ 5. 0. -2. ]] \u5c06\u6570\u7ec4\u518d\u8f6c\u6362\u4e3aDataFrame\uff1a df2 = pd.DataFrame(df.values, columns=['one', 'two', 'three']) # \u9012\u4e00\u4e2a\u542b\u6709\u5217\u540d\u7684\u4e8c\u7ef4ndarray print(df2) # one two three # 0 1.0 0.01 -1.5 # 1 2.0 -0.01 0.0 # 2 3.0 0.25 3.6 # 3 4.0 -4.10 1.3 # 4 5.0 0.00 -2.0 .values \u5c5e\u6027\u4e00\u822c\u5728\u6570\u636e\u662f\u540c\u6784\u5316\u7684\u65f6\u5019\u4f7f\u7528\u2014\u2014\u4f8b\u5982\uff0c\u90fd\u662f\u6570\u5b57\u7c7b\u578b\u7684\u65f6\u5019\u3002\u5982\u679c\u6570\u636e\u662f\u5f02\u6784\u5316\u7684\uff0c\u7ed3\u679c\u5c06\u662fPython\u5bf9\u8c61\u7684 ndarray \uff1a \u6dfb\u52a0\u4e00\u4e2a\u975e\u6570\u5b57\u7c7b\u578b\u7684\u5217\u3002 df3 = df.copy() df3['category'] = pd.Categorical(['a', 'b', 'a', 'a', 'b'], categories=['a', 'b']) print(df3) # x0 x1 y category # 0 1 0.01 -1.5 a # 1 2 -0.01 0.0 b # 2 3 0.25 3.6 a # 3 4 -4.10 1.3 a # 4 5 0.00 -2.0 b print(df3.values) # [[1 0.01 -1.5 'a'] # [2 -0.01 0.0 'b'] # [3 0.25 3.6 'a'] # [4 -4.1 1.3 'a'] # [5 0.0 -2.0 'b']] \u901a\u8fc7 loc \u7d22\u5f15\u548c values \u4f7f\u7528\u4e00\u90e8\u5206\u5217\u6570\u636e\u3002 model_cols = ['x0', 'x1'] result = df.loc[:, model_cols].values print(result) # [[ 1. 0.01] # [ 2. -0.01] # [ 3. 0.25] # [ 4. -4.1 ] # [ 5. 0. ]] \u5982\u679c\u6211\u4f7f\u7528\u865a\u62df\u53d8\u91cf\u66ff\u4ee3 df3 \u7684 category \u5217\uff0c\u5148\u521b\u5efa\u865a\u62df\u53d8\u91cf\uff0c\u4e4b\u540e\u5220\u9664 categroy \u5217\uff0c\u7136\u540e\u8fde\u63a5\u7ed3\u679c\uff1a dummies = pd.get_dummies(df3.category, prefix='category') print(dummies) # category_a category_b # 0 1 0 # 1 0 1 # 2 1 0 # 3 1 0 # 4 0 1 data_with_dummies = df3.drop('category', axis=1).join(dummies) print(data_with_dummies) # x0 x1 y category_a category_b # 0 1 0.01 -1.5 1 0 # 1 2 -0.01 0.0 0 1 # 2 3 0.25 3.6 1 0 # 3 4 -4.10 1.3 1 0 # 4 5 0.00 -2.0 0 1","title":"pandas\u4e0e\u5efa\u6a21\u4ee3\u7801\u7684\u7ed3\u5408"},{"location":"python/DataAnalysis/ch11/#patsy","text":"\u6837\u672c\u7684\u8868\u793a\u5f62\u5f0f\uff1a \u5728\u6570\u636e\u6316\u6398\u8fc7\u7a0b\u4e2d\uff0c\u6837\u672c\u4ee5\u7279\u5f81\u503c\u77e9\u9635X\u548c\u76ee\u6807\u503c\u5411\u91cfY\u7684\u5f62\u5f0f\u8868\u793a\u3002 \u5bb9\u91cf\u4e3a n \uff0c\u6709 m \u4e2a\u7279\u5f81\u7684\u6837\u672c\uff0c\u5176\u7279\u5f81\u503c\u77e9\u9635X\u7531 n \u4e2a\u7ef4\u5ea6\u4e3a m \u7684\u5217\u5411\u91cf\u7ec4\u6210\uff0c\u7b2c j \u4e2a\u5217\u5411\u91cf\u4e3a\u6837\u672c\u4e2d\u7b2c j \u4e2a\u4e2a\u4f53\u7684\u7279\u5f81\u503c\u5411\u91cf\uff1b \u76ee\u6807\u503c\u5411\u91cfY\u7684\u7b2c j \u4e2a\u5206\u91cf\u4e3a\u6837\u672c\u4e2d\u7b2c j \u4e2a\u4e2a\u4f53\u7684\u76ee\u6807\u503c\u3002 \u53c2\u8003\uff1a How formulas work [Patsy](https://patsy.readthedocs.io/\uff09\u662f\u4e00\u4e2a\u7528\u4e8e\u63cf\u8ff0\u7edf\u8ba1\u6a21\u578b\uff08\u5c24\u5176\u662f\u7ebf\u6027\u6a21\u578b\uff09\u7684Python\u5e93\u3002 \u5b83\u4f7f\u7528\u4e00\u79cd\u5c0f\u578b\u57fa\u4e8e\u5b57\u7b26\u4e32\u7684\"\u516c\u5f0f\u8bed\u6cd5\"\u3002 Patsy\u80fd\u591f\u5f88\u597d\u5730\u652f\u6301 statsmodels \u4e2d\u7279\u5b9a\u7684\u7ebf\u6027\u6a21\u578b\u3002 \u50cf y ~ x0 + x1 \u8fd9\u79cd a + b \u7684\u8bed\u6cd5\u5e76\u4e0d\u4ee3\u8868\u5c06 a \u548c b \u76f8\u52a0\uff0c\u800c\u662f\u4ee3\u8868\u4e3a\u6a21\u578b\u521b\u5efa\u7684\u8bbe\u8ba1\u77e9\u9635\u7684\u672f\u8bed\uff08terms in the design matrix\uff09\u3002 patsy.dmatrices \u51fd\u6570\uff0c\u53d6\u4e00\u4e2a\u516c\u5f0f\u5b57\u7b26\u4e32\u548c\u4e00\u4e2a\u6570\u636e\u96c6\uff08\u53ef\u4ee5\u4f7fDataFrame\u6216dict\uff09\uff0c\u7136\u540e\u4e3a\u7ebf\u6027\u6a21\u578b\u4ea7\u751f\u8bbe\u8ba1\u77e9\u9635\uff1a import pandas as pd import numpy as np import patsy from patsy import dmatrices, dmatrix, demo_data df = pd.DataFrame( { 'x0': [1, 2, 3, 4, 5], 'x1': [0.01, -0.01, 0.25, -4.1, 0.], 'y': [-1.5, 0., 3.6, 1.3, -2.] } ) print(df) # x0 x1 y # 0 1 0.01 -1.5 # 1 2 -0.01 0.0 # 2 3 0.25 3.6 # 3 4 -4.10 1.3 # 4 5 0.00 -2.0 y, X = patsy.dmatrices('y ~ x0 + x1', df) print(y) # [[-1.5] # [ 0. ] # [ 3.6] # [ 1.3] # [-2. ]] print(X) # [[ 1. 1. 0.01] # [ 1. 2. -0.01] # [ 1. 3. 0.25] # [ 1. 4. -4.1 ] # [ 1. 5. 0. ]] print(np.asarray(y)) # Patsy\u7684DesignMatrix\u5b9e\u4f8b\uff0c\u542b\u6709\u9644\u52a0\u5143\u6570\u636e\u7684NumPy.ndarray # [[-1.5] # [ 0. ] # [ 3.6] # [ 1.3] # [-2. ]] print(np.asarray(X)) # Patsy\u7684DesignMatrix\u5b9e\u4f8b\uff0c\u542b\u6709\u9644\u52a0\u5143\u6570\u636e\u7684NumPy.ndarray # [[ 1. 1. 0.01] # [ 1. 2. -0.01] # [ 1. 3. 0.25] # [ 1. 4. -4.1 ] # [ 1. 5. 0. ]] \u4e0a\u9762X\u8f93\u51fa\u4e2d\u7684Intercept(\u6700\u5de6\u8fb9\u4e00\u5217)\u662f\u4ece\u54ea\u91cc\u6765\u7684\u3002 \u8fd9\u5176\u5b9e\u662f\u7ebf\u6027\u6a21\u578b\u7684\u4e00\u4e2a\u60ef\u4f8b\uff0c\u6bd4\u5982\u666e\u901a\u6700\u5c0f\u4e8c\u4e58\u56de\u5f52\u6cd5\uff08ordinary least squares regression\uff09\u3002 \u53ef\u4ee5\u53bb\u6389\u8fd9\u4e2a\u622a\u8ddd\uff08intercept\uff09\uff0c\u901a\u8fc7 y ~ x0 + x1 + 0 \u7ed9\u6a21\u578b\u3002 y, X = patsy.dmatrices('y ~ x0 + x1 + 0', df) print(X) # [[ 1. 0.01] # [ 2. -0.01] # [ 3. 0.25] # [ 4. -4.1 ] # [ 5. 0. ]] \u8fd9\u79cdPatsy\u5bf9\u8c61\u53ef\u4ee5\u76f4\u63a5\u4f20\u5165\u4e00\u4e2a\u7b97\u6cd5\uff0c\u6bd4\u5982 numpy.linalg.lstsq \uff0c\u6765\u8fdb\u884c\u666e\u901a\u6700\u5c0f\u4e8c\u4e58\u56de\u5f52\u7684\u8ba1\u7b97 coef, resid, _, _ =np.linalg.lstsq(X, y, rcond=1) # \u6700\u5c0f\u4e8c\u4e58\u6cd5 print(coef) # [[ 0.00925424] # [-0.25485421]] print(resid) # [19.72552896] coef = pd.Series(coef.squeeze(), index=X.design_info.column_names) print(coef) # x0 0.009254 # x1 -0.254854 # dtype: float64","title":"\u4f7f\u7528Patsy\u521b\u5efa\u6a21\u578b\u63cf\u8ff0"},{"location":"python/DataAnalysis/ch11/#patsy_1","text":"\u53ef\u4ee5\u5c06Python\u4ee3\u7801\u6df7\u5408\u5230\u4f60\u7684Patsy\u516c\u5f0f\u4e2d\uff0c\u5728\u6267\u884c\u516c\u5f0f\u65f6\uff0cPatsy\u5e93\u5c06\u5c1d\u8bd5\u5728\u5c01\u95ed\u4f5c\u7528\u57df\u4e2d\u5bfb\u627e\u4f60\u4f7f\u7528\u7684\u51fd\u6570\uff1a y, X = patsy.dmatrices('y ~ x0 + np.log(np.abs(x1) +1)', df) print(X) # [[1. 1. 0.00995033] # [1. 2. 0.00995033] # [1. 3. 0.22314355] # [1. 4. 1.62924054] # [1. 5. 0. ]] \u4e00\u4e9b\u5e38\u7528\u7684\u53d8\u91cf\u53d8\u6362\uff0c\u5305\u62ec\u6807\u51c6\u5316\uff08standardizing (\u5e73\u5747\u503c0\uff0c\u65b9\u5dee1\uff09\u548c\u4e2d\u5fc3\u5316\uff08\u51cf\u53bb\u5e73\u5747\u503c\uff09\u3002Patsy\u6709\u5185\u5efa\u7684\u51fd\u6570\u53ef\u4ee5\u505a\u5230\u8fd9\u4e9b\u3002 y, X = patsy.dmatrices('y ~ standardize(x0) + center(x1)', df) print(X) # [[ 1. -1.41421356 0.78 ] # [ 1. -0.70710678 0.76 ] # [ 1. 0. 1.02 ] # [ 1. 0.70710678 -3.33 ] # [ 1. 1.41421356 0.77 ]] \u4f5c\u4e3a\u5efa\u6a21\u7684\u4e00\u90e8\u5206\uff0c\u6211\u4eec\u53ef\u80fd\u4f1a\u5728\u4e00\u4e2a\u6570\u636e\u53ca\u4e0a\u8bad\u7ec3\u6a21\u578b\uff0c\u7136\u540e\u5728\u53e6\u4e00\u4e2a\u6570\u636e\u53ca\u4e0a\u8bc4\u4ef7\u6a21\u578b\u3002 \u5f53\u4f7f\u7528\u4e2d\u5fc3\u5316\u6216\u6807\u51c6\u5316\u8fd9\u6837\u7684\u8f6c\u6362\u65f6\uff0c\u6211\u4eec\u5fc5\u987b\u6ce8\u610f\uff0c\u5fc5\u987b\u7528\u6a21\u578b\u5728\u65b0\u6570\u636e\u96c6\u4e0a\u505a\u9884\u6d4b\u3002 \u8fd9\u53eb\u505a\u72b6\u6001\u53d8\u6362\uff08stateful transformations\uff09\u3002 \u56e0\u4e3a\u6211\u4eec\u5fc5\u987b\u7528\u539f\u672c\u5728\u8bad\u7ec3\u96c6\u4e0a\u5f97\u5230\u7684\u5e73\u5747\u503c\u548c\u6807\u51c6\u5dee\uff0c\u7528\u5728\u65b0\u7684\u6570\u636e\u96c6\u4e0a\u3002 new_df = pd.DataFrame( { 'x0': [6, 7, 8, 9], 'x1': [3.1, -0.5, 0, 2.3], 'y': [1, 2, 3, 4] } ) new_X = patsy.build_design_matrices([X.design_info], new_df) print(new_X) # [DesignMatrix with shape (4, 3) # Intercept standardize(x0) center(x1) # 1 2.12132 3.87 # 1 2.82843 0.27 # 1 3.53553 0.77 # 1 4.24264 3.07 # Terms: # 'Intercept' (column 0), 'standardize(x0)' (column 1), 'center(x1)' (column 2)] \u56e0\u4e3a\u52a0\u53f7\uff08+\uff09\u5728Patsy\u516c\u5f0f\u7684\u4e0a\u4e0b\u6587\u4e2d\u5e76\u4e0d\u662f\u52a0\u6cd5\u7684\u610f\u601d\uff0c\u5f53\u60f3\u8981\u5bf9\u6570\u636e\u96c6\u4e2d\u4e24\u5217\u6309\u5217\u540d\u76f8\u52a0\u65f6\uff0c\u5fc5\u987b\u5c06\u5217\u540d\u5c01\u88c5\u5230\u7279\u6b8a\u7684I\u51fd\u6570\u4e2d\uff1a y, X = patsy.dmatrices('y ~ I(x0 + x1)', df) print(X) # [[ 1. 1.01] # [ 1. 1.99] # [ 1. 3.25] # [ 1. -0.1 ] # [ 1. 5. ]]","title":"Patsy\u516c\u5f0f\u4e2d\u7684\u6570\u636e\u8f6c\u6362"},{"location":"python/DataAnalysis/ch11/#categoricalpatsy","text":"\u975e\u6570\u503c\u578b\u6570\u636e\u53ef\u4ee5\u901a\u8fc7\u5f88\u591a\u79cd\u65b9\u5f0f\u53d8\u4e3a\u4e00\u4e2a\u6a21\u578b\u8bbe\u8ba1\u77e9\u9635\u3002 \u5f53\u6211\u4eec\u5728Patsy\u516c\u5f0f\u4e2d\u4f7f\u7528\u975e\u6570\u503c\u672f\u8bed\u65f6\uff0c\u8fd9\u4e9b\u7c7b\u578b\u6570\u636e\u9ed8\u8ba4\u4f1a\u88ab\u8f6c\u6362\u4e3a\u54d1\u53d8\u91cf\u3002\u5982\u679c\u6709\u622a\u8ddd\uff0c\u4e00\u4e2a\u5c42\u7ea7\u4e0a\u7684\u622a\u8ddd\u4f1a\u88ab\u820d\u5f03\uff0c\u9632\u6b62\u51fa\u73b0\u5171\u7ebf\u6027\u3002 data = pd.DataFrame( { 'key1': ['a', 'a', 'b', 'b', 'a', 'b', 'a', 'b'], 'key2': [0, 1, 0, 1, 0, 1, 0, 0], 'v1': [1, 2, 3, 4, 5, 6, 7, 8], 'v2': [-1, 0, 2.5, -0.5, 4., -1.2, 0.2, -1.7] } ) y, X = patsy.dmatrices('v2 ~ key1', data) print(y) # [[-1. ] # [ 0. ] # [ 2.5] # [-0.5] # [ 4. ] # [-1.2] # [ 0.2] # [-1.7]] print(X) # [[1. 0.] # [1. 0.] # [1. 1.] # [1. 1.] # [1. 0.] # [1. 1.] # [1. 0.] # [1. 1.]] \u5982\u679c\u4ece\u6a21\u578b\u4e2d\u820d\u5f03\u622a\u8ddd\uff0c\u6bcf\u4e2a\u7c7b\u578b\u7684\u5217\u4f1a\u88ab\u5305\u542b\u5728\u6a21\u578b\u8bbe\u8ba1\u77e9\u9635\u4e2d\u3002 y, X = patsy.dmatrices('v2 ~ key1 + 0', data) print(X) # [[1. 0.] # [1. 0.] # [0. 1.] # [0. 1.] # [1. 0.] # [0. 1.] # [1. 0.] # [0. 1.]] \u6570\u503c\u578b\u5217\u53ef\u4ee5\u901a\u8fc7C\u51fd\u6570\uff0c\u53d8\u4e3a\u7c7b\u578b\u5217\uff1a y, X = patsy.dmatrices('v2 ~ C(key2)', data) print(X) # [[1. 0.] # [1. 1.] # [1. 0.] # [1. 1.] # [1. 0.] # [1. 1.] # [1. 0.] # [1. 0.]] \u5f53\u6211\u4eec\u5728\u4e00\u4e2a\u6a21\u578b\u4e2d\u4f7f\u7528\u591a\u4e2a\u7c7b\u578b\u672f\u8bed\u65f6\uff0c\u4f1a\u53d8\u5f97\u66f4\u590d\u6742\u4e00\u4e9b\uff0c\u4e4b\u524d\u7528key1:key2\u7684\u5f62\u5f0f\u6765\u5305\u542b\u6709\u4ea4\u96c6\u7684\u672f\u8bed\uff0c \u8fd9\u79cd\u65b9\u6cd5\u53ef\u4ee5\u7528\u4e8e\u4f7f\u7528\u591a\u4e2a\u672f\u8bed\uff0c\u4f8b\u5982\uff0c\u4e00\u4e2a\u65b9\u6cd5\u5206\u6790\u6a21\u578b\uff08analysis of variance (ANOVA) models\uff09\uff1a data['key2'] = data['key2'].map({0: 'zero', 1: 'one'}) print(data) # key1 key2 v1 v2 # 0 a zero 1 -1.0 # 1 a one 2 0.0 # 2 b zero 3 2.5 # 3 b one 4 -0.5 # 4 a zero 5 4.0 # 5 b one 6 -1.2 # 6 a zero 7 0.2 # 7 b zero 8 -1.7 y, X = patsy.dmatrices('v2 ~ key1 + key2', data) print(X) # [[1. 0. 1.] # [1. 0. 0.] # [1. 1. 1.] # [1. 1. 0.] # [1. 0. 1.] # [1. 1. 0.] # [1. 0. 1.] # [1. 1. 1.]] y, X = patsy.dmatrices('v2 ~ key1 + key2 + key1:key2', data) print(X) # [[1. 0. 1. 0.] # [1. 0. 0. 0.] # [1. 1. 1. 1.] # [1. 1. 0. 0.] # [1. 0. 1. 0.] # [1. 1. 0. 0.] # [1. 0. 1. 0.] # [1. 1. 1. 1.]]","title":"\u5206\u7c7b\u6570\u636eCategorical\u548cPatsy"},{"location":"python/DataAnalysis/ch11/#statsmodels","text":"statsmodels \u662f\u4e00\u4e2aPython\u5e93\uff0c\u7528\u4e8e\u62df\u5408\u591a\u79cd\u7edf\u8ba1\u6a21\u578b\uff0c\u6267\u884c\u7edf\u8ba1\u6d4b\u8bd5\u4ee5\u53ca\u6570\u636e\u63a2\u7d22\u548c\u53ef\u89c6\u5316\u3002 statsmodels \u5305\u542b\u66f4\u591a\u7684\u201c\u7ecf\u5178\u201d\u9891\u7387\u5b66\u6d3e\u7edf\u8ba1\u65b9\u6cd5\uff0c\u800c\u8d1d\u53f6\u65af\u65b9\u6cd5\u548c\u673a\u5668\u5b66\u4e60\u6a21\u578b\u53ef\u5728\u5176\u4ed6\u5e93\u4e2d\u627e\u5230\u3002 \u5305\u542b\u5728statsmodels\u4e2d\u7684\u4e00\u4e9b\u6a21\u578b\uff1a \u7ebf\u6027\u6a21\u578b\uff0c\u5e7f\u4e49\u7ebf\u6027\u6a21\u578b\u548c\u9c81\u68d2\u7ebf\u6027\u6a21\u578b \u7ebf\u6027\u6df7\u5408\u6548\u5e94\u6a21\u578b \u65b9\u5dee\u5206\u6790\uff08ANOVA\uff09\u65b9\u6cd5 \u65f6\u95f4\u5e8f\u5217\u8fc7\u7a0b\u548c\u72b6\u6001\u7a7a\u95f4\u6a21\u578b \u5e7f\u4e49\u7684\u77e9\u91cf\u6cd5 import pandas as pd import statsmodels.api as sm import statsmodels.formula.api as smf import numpy as np import random","title":"statsmodels\u4ecb\u7ecd"},{"location":"python/DataAnalysis/ch11/#_1","text":"\u7edf\u8ba1\u6a21\u578b\u4e2d\u6709\u51e0\u79cd\u7ebf\u6027\u56de\u5f52\u6a21\u578b\uff0c\u4ece\u8f83\u57fa\u672c\u7684\uff08\u4f8b\u5982\uff0c\u666e\u901a\u6700\u5c0f\u4e8c\u4e58\uff09\u5230\u66f4\u590d\u6742\u7684\uff08\u4f8b\u5982\uff0c\u8fed\u4ee3\u91cd\u65b0\u52a0\u6743\u7684\u6700\u5c0f\u4e8c\u4e58\uff09\u3002 tatsmodels \u4e2d\u7684\u7ebf\u6027\u6a21\u578b\u6709\u4e24\u4e2a\u4e0d\u540c\u7684\u4e3b\u8981\u63a5\u53e3\uff0c\u8fd9\u4e9b\u63a5\u53e3\u901a\u8fc7\u8fd9\u4e9bAPI\u6a21\u5757\u5bfc\u5165\u6765\u8bbf\u95ee\uff1a \u57fa\u4e8e\u6570\u7ec4 \u57fa\u4e8e\u516c\u5f0f \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u8c03\u7528\u5df2\u77e5\u53c2\u6570beta\u7684\u6a21\u578b\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c dnorm \u662f\u7528\u4e8e\u751f\u6210\u5177\u6709\u7279\u5b9a\u5747\u503c\u548c\u65b9\u5dee\u7684\u6b63\u6001\u5206\u5e03\u6570\u636e\u7684\u8f85\u52a9\u51fd\u6570\u3002 def dnorm (mean, variance, size=1): if isinstance(size, int): size = size, return mean + np.sqrt(variance) * np.random.randn(*size) np.random.seed(12345) N = 100 X = np.c_[ dnorm(0, 0.4, size=N), dnorm(0, 0.6, size=N), dnorm(0, 0.2, size=N) ] eps = dnorm(0, 0.1, size=N) beta = [0.1, 0.3, 0.5] y = np.dot(X, beta) + eps print(X[:5]) # [[-0.12946849 -1.21275292 0.50422488] # [ 0.30291036 -0.43574176 -0.25417986] # [-0.32852189 -0.02530153 0.13835097] # [-0.35147471 -0.71960511 -0.25821463] # [ 1.2432688 -0.37379916 -0.52262905]] print(y[:5]) # [ 0.42786349 -0.67348041 -0.09087764 -0.48949442 -0.12894109] \u7ebf\u6027\u6a21\u578b\u901a\u5e38\u4e0e\u6211\u4eec\u5728Patsy\u4e2d\u770b\u5230\u7684\u622a\u8ddd\u9879\u76f8\u5339\u914d\u3002 sm.add_constant \u51fd\u6570\u53ef\u4ee5\u5c06\u622a\u8ddd\u5217\u6dfb\u52a0\u5230\u73b0\u6709\u77e9\u9635\uff1a X_model = sm.add_constant(X) print(X_model[:5]) # [[ 1. -0.12946849 -1.21275292 0.50422488] # [ 1. 0.30291036 -0.43574176 -0.25417986] # [ 1. -0.32852189 -0.02530153 0.13835097] # [ 1. -0.35147471 -0.71960511 -0.25821463] # [ 1. 1.2432688 -0.37379916 -0.52262905]] sm.OLS \u7c7b\u53ef\u4ee5\u62df\u5408\u4e00\u4e2a\u6700\u5c0f\u4e8c\u4e58\u7ebf\u6027\u56de\u5f52\uff1a model = sm.OLS(y, X) \u6a21\u578b\u7684 fit \u65b9\u6cd5\u8fd4\u56de\u4e00\u4e2a\u56de\u5f52\u7ed3\u679c\u5bf9\u8c61\uff0c\u8be5\u5bf9\u8c61\u5305\u542b\u4e86\u4f30\u8ba1\u7684\u6a21\u578b\u53c2\u6570\u548c\u5176\u4ed6\u7684\u8bca\u65ad\uff1a results = model.fit() print(results.params) # [0.17826108 0.22303962 0.50095093] \u8c03\u7528 summary \u65b9\u6cd5\u53ef\u4ee5\u6253\u5370\u51fa\u4e00\u4e2a\u6a21\u578b\u7684\u8bca\u65ad\u7ec6\u8282\uff0c\u6b64\u5904\u7684\u53c2\u6570\u540d\u79f0\u5df2\u88ab\u8d4b\u4e88\u901a\u7528\u540d\u79f0 x1 \u3001 x2 \u7b49\uff1a print(results.summary()) # OLS Regression Results # ======================================================================================= # Dep. Variable: y R-squared (uncentered): 0.430 # Model: OLS Adj. R-squared (uncentered): 0.413 # Method: Least Squares F-statistic: 24.42 # Date: Sat, 16 Oct 2021 Prob (F-statistic): 7.44e-12 # Time: 14:21:45 Log-Likelihood: -34.305 # No. Observations: 100 AIC: 74.61 # Df Residuals: 97 BIC: 82.42 # Df Model: 3 # Covariance Type: nonrobust # ============================================================================== # coef std err t P>|t| [0.025 0.975] # ------------------------------------------------------------------------------ # x1 0.1783 0.053 3.364 0.001 0.073 0.283 # x2 0.2230 0.046 4.818 0.000 0.131 0.315 # x3 0.5010 0.080 6.237 0.000 0.342 0.660 # ============================================================================== # Omnibus: 4.662 Durbin-Watson: 0 -0.002327 # Prob(Omnibus): 0.097 Jarque-Bera (JB): 4.098 # Skew: 0.481 Prob(JB): 0.129 # Kurtosis: 3.243 Cond. No. 1.74 # ============================================================================== # # Notes: # [1] R\u00b2 is computed without centering (uncentered) since the model does not contain a constant. # [2] Standard Errors assume that the covariance matrix of the errors is correctly specified. \u5047\u8bbe\u6240\u6709\u6a21\u578b\u53c2\u6570\u90fd\u5728DataFrame\u4e2d\uff1a data = pd.DataFrame(X, columns=['col0', 'col1', 'col2']) data['y'] = y print(data[:5]) # col0 col1 col2 y # 0 -0.129468 -1.212753 0.504225 0.427863 # 1 0.302910 -0.435742 -0.254180 -0.673480 # 2 -0.328522 -0.025302 0.138351 -0.090878 # 3 -0.351475 -0.719605 -0.258215 -0.489494 # 4 1.243269 -0.373799 -0.522629 -0.128941 \u73b0\u5728\u53ef\u4ee5\u4f7f\u7528 statsmodels \u516c\u5f0fAPI\u548cPatsy\u516c\u5f0f\u5b57\u7b26\u4e32\u3002\u89c2\u5bdf statsmodels \u5982\u4f55\u5c06\u7ed3\u679c\u4f5c\u4e3a\u5e26\u6709DataFrame\u5217\u540d\u79f0\u7684Series\u8fd4\u56de\u3002 results = smf.ols('y ~ col0 + col1 + col2', data=data).fit() print(results.params) # Intercept 0.033559 # col0 0.176149 # col1 0.224826 # col2 0.514808 # dtype: float64 \u7ed9\u5b9a\u65b0\u7684\u6837\u672c\u5916\u6570\u636e\u540e\uff0c\u53ef\u4ee5\u6839\u636e\u4f30\u8ba1\u7684\u6a21\u578b\u53c2\u6570\u8ba1\u7b97\u9884\u6d4b\u503c\uff1a print(results.predict(data[:5])) # 0 -0.002327 # 1 -0.141904 # 2 0.041226 # 3 -0.323070 # 4 -0.100535 # dtype: float64","title":"\u8bc4\u4f30\u7ebf\u6027\u6a21\u578b"},{"location":"python/DataAnalysis/ch11/#_2","text":"statsmodels\u4e2d\u7684\u53e6\u4e00\u7c7b\u6a21\u578b\u7528\u4e8e\u65f6\u95f4\u5e8f\u5217\u5206\u6790\u3002\u5176\u4e2d\u5305\u62ec\u81ea\u56de\u5f52\u8fc7\u7a0b\uff0c\u5361\u5c14\u66fc\u6ee4\u6ce2\u548c\u5176\u4ed6\u72b6\u6001\u7a7a\u95f4\u6a21\u578b\uff0c\u4ee5\u53ca\u591a\u53d8\u91cf\u81ea\u56de\u5f52\u6a21\u578b\u3002 \u4e0b\u4f8b\u6a21\u62df\u4e00\u4e9b\u5177\u6709\u81ea\u56de\u5f52\u7ed3\u6784\u548c\u566a\u58f0\u7684\u65f6\u95f4\u5e8f\u5217\u6570\u636e\uff0c\u8be5\u6570\u636e\u5177\u6709\u53c2\u6570\u4e3a0.8\u548c-0.4\u7684AR\uff082\uff09\u7ed3\u6784\uff08\u4e24\u4e2a\u6ede\u540e\uff09\u3002 init_x = 4 values = [init_x, init_x] N = 1000 b0 = 0.8 b1 = -0.4 noise = dnorm(0, 0.1, N) for i in range(N): new_x = values[-1] * b0 + values[-2] * b1 + noise[i] values.append(new_x) \u5f53\u62df\u5408\u4e00\u4e2aAR\u6a21\u578b\u65f6\uff0c\u4f60\u53ef\u80fd\u4e0d\u77e5\u9053\u5305\u542b\u7684\u6ede\u540e\u9879\u7684\u6570\u91cf\uff0c\u6240\u4ee5\u53ef\u4ee5\u7528\u66f4\u5927\u7684\u6ede\u540e\u6570\u6765\u62df\u5408\u8be5\u6a21\u578b\uff1a MAXLAGS = 5 model = sm.tsa.AR(values) results = model.fit(MAXLAGS) print(results.params) # NotImplementedError: AR has been removed from statsmodels and replaced with statsmodels.tsa.ar_model.AutoReg.","title":"\u8bc4\u4f30\u65f6\u95f4\u5e8f\u5217\u5904\u7406"},{"location":"python/DataAnalysis/ch11/#sikit-learn","text":"scikit-learn\uff08http://scikit-learn.org\uff09\u662f\u4f7f\u7528\u6700\u5e7f\u6cdb\u4e14\u6700\u53d7\u4fe1\u4efb\u7684\u901a\u7528Python\u673a\u5668\u5b66\u4e60\u5e93\u3002\\ \u5b83\u5305\u542b\u5e7f\u6cdb\u7684\u6807\u51c6\u76d1\u7763\u7684\u548c\u65e0\u76d1\u7763\u7684\u673a\u5668\u5b66\u4e60\u65b9\u6cd5\uff0c\u5305\u62ec\u7528\u4e8e\u6a21\u578b\u9009\u62e9\u548c\u8bc4\u4f30\u3001\u6570\u636e\u8f6c\u6362\u3001\u6570\u636e\u52a0\u8f7d\u548c\u6a21\u578b\u6301\u4e45\u5316\u7684\u5de5\u5177\u3002\\ \u8fd9\u4e9b\u6a21\u578b\u53ef\u7528\u4e8e\u5206\u7c7b\u3001\u805a\u7c7b\u3001\u9884\u6d4b\u548c\u5176\u4ed6\u5e38\u89c1\u4efb\u52a1\u3002\\ pandas\u975e\u5e38\u9002\u5408\u5728\u6a21\u578b\u62df\u5408\u524d\u5904\u7406\u6570\u636e\u96c6\u3002 \u4e3e\u4e2a\u4f8b\u5b50\uff0c\u7528\u4e00\u4e2aKaggle\u7ade\u8d5b\u7684\u7ecf\u5178\u6570\u636e\u96c6\uff0c\u5173\u4e8e\u6cf0\u5766\u5c3c\u514b\u53f7\u4e58\u5ba2\u7684\u751f\u8fd8\u7387\u3002\u6211\u4eec\u7528pandas\u52a0\u8f7d\u6d4b\u8bd5\u548c\u8bad\u7ec3\u6570\u636e\u96c6\uff1a import pandas as pd from sklearn.linear_model import LogisticRegression from sklearn.linear_model import LogisticRegressionCV from sklearn.model_selection import cross_val_score train = pd.read_csv('../datasets/titanic/train.csv') test = pd.read_csv('../datasets/titanic/test.csv') print(train[:4]) # PassengerId Survived Pclass ... Fare Cabin Embarked # 0 1 0 3 ... 7.2500 NaN S # 1 2 1 1 ... 71.2833 C85 C # 2 3 1 3 ... 7.9250 NaN S # 3 4 1 1 ... 53.1000 C123 S \u50cfstatsmodels\u548cscikit-learn\u901a\u5e38\u4e0d\u80fd\u63d0\u4f9b\u7f3a\u5931\u6570\u636e\uff0c\u56e0\u6b64\u6211\u4eec\u8981\u68c0\u67e5\u5404\u5217\uff0c\u770b\u770b\u662f\u5426\u6709\u5305\u542b\u7f3a\u5931\u6570\u636e\uff1a print(train.isnull().sum()) # PassengerId 0 # Survived 0 # Pclass 0 # Name 0 # Sex 0 # Age 177 # SibSp 0 # Parch 0 # Ticket 0 # Fare 0 # Cabin 687 # Embarked 2 # dtype: int64 print(test.isnull().sum()) # PassengerId 0 # Pclass 0 # Name 0 # Sex 0 # Age 86 # SibSp 0 # Parch 0 # Ticket 0 # Fare 1 # Cabin 327 # Embarked 0 # dtype: int64 \u5728\u50cf\u8fd9\u6837\u7684\u7edf\u8ba1\u548c\u673a\u5668\u5b66\u4e60\u7684\u4f8b\u5b50\u4e2d\uff0c\u4e00\u4e2a\u5178\u578b\u7684\u4efb\u52a1\u662f\u6839\u636e\u6570\u636e\u4e2d\u7684\u7279\u5f81\u6765\u9884\u6d4b\u4e58\u5ba2\u662f\u5426\u80fd\u5e78\u5b58\u4e0b\u6765\u3002\\ \u5c06\u6a21\u578b\u62df\u5408\u5230\u8bad\u7ec3\u6570\u636e\u96c6\u4e0a\uff0c\u7136\u540e\u5728\u6837\u672c\u5916\u6d4b\u8bd5\u6570\u636e\u96c6\u4e0a\u8fdb\u884c\u8bc4\u4f30\u3002\\ \u5982\u679c\u7528Age\u4f5c\u4e3a\u9884\u6d4b\uff0c\u4f46\u5b83\u7f3a\u5c11\u6570\u636e\u3002\u9700\u8981\u8fdb\u884c\u7f3a\u5931\u6570\u636e\u63d2\u8865\uff08imputation\uff09\uff0c\u5e76\u4f7f\u7528\u8bad\u7ec3\u6570\u636e\u96c6\u7684\u4e2d\u95f4\u503c\u586b\u5145\u4e24\u4e2a\u8868\u4e2d\u7684\u7a7a\u503c\uff1a impute_value = train['Age'].median() train['Age'] = train['Age'].fillna(impute_value) test['Age'] = test['Age'].fillna(impute_value) \u73b0\u5728\u5efa\u7acb\u6a21\u578b\u3002\\ \u6dfb\u52a0\u4e00\u5217IsFemale\u4f5c\u4e3a\u2019Sex\u2019\u5217\u7684\u7f16\u7801\u7248\u672c\uff1a train['IsFemale'] = (train['Sex'] == 'female').astype(int) test['IsFemale'] = (test['Sex'] == 'female').astype(int) \u786e\u5b9a\u4e00\u4e9b\u6a21\u578b\u53d8\u91cf\u5e76\u521b\u5efaNumPy\u6570\u7ec4\uff1a predictors = ['Pclass', 'IsFemale', 'Age'] X_train = train[predictors].values X_test = test[predictors].values y_train = train['Survived'].values print(X_train[:5]) # [[ 3. 0. 22.] # [ 1. 1. 38.] # [ 3. 1. 26.] # [ 1. 1. 35.] # [ 3. 0. 35.]] print(y_train[:5]) # [0 1 1 1 0] \u4f7f\u7528scikit-learn\u7684LogisticRegression\u6a21\u578b\u521b\u5efa\u4e00\u4e2a\u6a21\u578b\u5b9e\u4f8b\uff1a model = LogisticRegression() \u4e0estatsmodels\u7c7b\u4f3c\uff0c\u4f7f\u7528\u6a21\u578b\u7684fit\u65b9\u6cd5\u5728\u8bad\u7ec3\u6570\u636e\u4e0a\u62df\u5408\u6a21\u578b\uff1a result = model.fit(X_train, y_train) print(result) # LogisticRegression() \u4f7f\u7528model.predict\u4e3a\u6d4b\u8bd5\u6570\u636e\u96c6\u5f62\u6210\u9884\u6d4b\uff1a y_predict = model.predict(X_test) print(y_predict[:10]) # [0 0 0 0 1 0 1 0 1 0] \u5b9e\u9645\u4e0a\uff0c\u6a21\u578b\u8bad\u7ec3\u4e2d\u7ecf\u5e38\u5b58\u5728\u8bb8\u591a\u9644\u52a0\u7684\u590d\u6742\u5c42\u6b21\u3002\\ \u8bb8\u591a\u6a21\u578b\u5177\u6709\u53ef\u4ee5\u8c03\u6574\u7684\u53c2\u6570\uff0c\u5e76\u4e14\u5b58\u5728\u53ef\u7528\u4e8e\u53c2\u6570\u8c03\u6574\u7684\u4ea4\u53c9\u9a8c\u8bc1\u7b49\u6280\u672f\u4ee5\u907f\u514d\u8fc7\u5ea6\u62df\u5408\u8bad\u7ec3\u6570\u636e\u3002\\ \u8fd9\u901a\u5e38\u53ef\u4ee5\u5728\u65b0\u6570\u636e\u4e0a\u4ea7\u751f\u66f4\u597d\u7684\u9884\u6d4b\u6027\u80fd\u6216\u7a33\u5065\u6027\u3002\u4ea4\u53c9\u9a8c\u8bc1\u901a\u8fc7\u5206\u5272\u8bad\u7ec3\u6570\u636e\u6765\u6a21\u62df\u6837\u672c\u5916\u9884\u6d4b\u3002\\ \u57fa\u4e8e\u50cf\u5747\u65b9\u8bef\u5dee\u4e4b\u7c7b\u7684\u6a21\u578b\u51c6\u786e\u5ea6\u5206\u6570\uff0c\u53ef\u4ee5\u5bf9\u6a21\u578b\u53c2\u6570\u6267\u884c\u7f51\u683c\u641c\u7d22\u3002\\ \u4e00\u4e9b\u6a21\u578b\uff0c\u5982\u903b\u8f91\u56de\u5f52\uff0c\u5177\u6709\u5185\u7f6e\u4ea4\u53c9\u9a8c\u8bc1\u7684\u4f30\u8ba1\u7c7b\u3002\\ \u4f8b\u5982\uff0cLogisticRegressionCV\u7c7b\u53ef\u4ee5\u4e0e\u4e00\u4e2a\u53c2\u6570\u4e00\u8d77\u4f7f\u7528\uff0c\u8be5\u53c2\u6570\u8868\u793a\u7f51\u683c\u641c\u7d22\u5728\u6a21\u578b\u6b63\u5219\u5316\u53c2\u6570C\u4e0a\u7684\u7ec6\u81f4\u5ea6\uff1a model_cv = LogisticRegressionCV() result = model_cv.fit(X_train, y_train) print(result) # LogisticRegressionCV() \u8981\u624b\u52a8\u8fdb\u884c\u4ea4\u53c9\u9a8c\u8bc1\uff0c\u53ef\u4ee5\u4f7f\u7528cross_val_score\u51fd\u6570\uff0c\u8be5\u51fd\u6570\u5904\u7406\u6570\u636e\u62c6\u5206\u8fc7\u7a0b\u3002\\ \u4f8b\u5982\uff0c\u4e3a\u4e86\u7528\u6211\u4eec\u7684\u6a21\u578b\u4e0e\u8bad\u7ec3\u6570\u636e\u7684\u56db\u4e2a\u975e\u91cd\u53e0\u5206\u5272\u8fdb\u884c\u4ea4\u53c9\u9a8c\u8bc1\uff0c\u53ef\u4ee5\u8fd9\u6837\u505a\uff1a model = LogisticRegression(C=10) scores = cross_val_score(model, X_train, y_train, cv=4) print(scores) # [0.77578475 0.79820628 0.77578475 0.78828829] \u9ed8\u8ba4\u8bc4\u5206\u6307\u6807\u662f\u4f9d\u8d56\u4e8e\u6a21\u578b\u7684\uff0c\u4f46\u53ef\u4ee5\u9009\u62e9\u660e\u786e\u7684\u8bc4\u5206\u51fd\u6570\u3002\u7ecf\u8fc7\u4ea4\u53c9\u9a8c\u8bc1\u7684\u6a21\u578b\u9700\u8981\u66f4\u957f\u65f6\u95f4\u7684\u8bad\u7ec3\uff0c\u4f46\u901a\u5e38\u53ef\u4ee5\u4ea7\u751f\u66f4\u597d\u7684\u6a21\u578b\u6027\u80fd\u3002","title":"sikit-learn\u4ecb\u7ecd"},{"location":"python/DataStructure/01_PythonFundmantal/","text":"1.\u57fa\u7840\u77e5\u8bc6\u56de\u987e \u00b6 1.1.\u57fa\u672c\u7a0b\u5e8f\u8981\u7d20 \u00b6 \u793a\u4f8b\u4ee3\u7801 numberguess.py \u3002 import random def main (): smaller = int ( input ( \"\u8f93\u5165\u6700\u5c0f\u503c: \" )) larger = int ( input ( \"\u8f93\u5165\u6700\u5927\u503c: \" )) myNumber = random . randint ( smaller , larger ) count = 0 while True : count += 1 userNumber = int ( input ( \"\u8f93\u5165\u4f60\u731c\u7684\u503c: \" )) if userNumber < myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5c0f\uff01\" ) elif userNumber > myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5927\uff01\" ) else : print ( \"\u606d\u559c\uff0c\u4f60\u5728\u7b2c\" , count , \"\u6b21\u731c\u5bf9\u4e86!\" ) break if __name__ == \"__main__\" : main () \u8fd0\u884c\u4ee3\u7801\uff1a $ python3 numberguess.py Enter the smaller number: 10 Enter the larger number: 60 Enter your guess: 50 Too large Enter your guess: 40 Too large Enter your guess: 30 Too large Enter your guess: 20 Too large Enter your guess: 10 Too small Enter your guess: 15 You\u2019ve got it in 6 tries! 1.1.1.\u62fc\u5199\u548c\u547d\u540d\u60ef\u4f8b \u00b6 \u53d8\u91cf\uff1asalary\uff0choursWorked\uff0cisAbsent \u5e38\u6570\uff1aABSOLUTE_ZERO\uff0cINTEREST_RATE \u51fd\u6570\u6216\u65b9\u6cd5\uff1aprintResults\uff0ccubeRoot\uff0cinput \u7c7b\uff1aBankAccount\uff0cSortedSet \u901a\u5e38\u7ea6\u5b9a\uff1a\u53d8\u91cf\u540d\u662f\u540d\u8bcd\u3001\u5f62\u5bb9\u8bcd\uff08\u5e03\u5c14\u503c\uff09\uff0c\u51fd\u6570\u548c\u65b9\u6cd5\u662f\u52a8\u8bcd\uff08\u8868\u793a\u52a8\u4f5c\uff09\u3001\u540d\u8bcd\u3001\u6216\u5f62\u5bb9\u8bcd\uff08\u8868\u793a\u8fd4\u56de\u7684\u503c\uff09\u3002 \u8bed\u6cd5\u5143\u7d20\uff1a Python\u4f7f\u7528\u7a7a\u767d\u7b26\uff08\u7a7a\u683c\u3001\u5236\u8868\u7b26\u3001\u6216\u6362\u884c\u7b26\uff09\u6765\u8868\u793a\u4e0d\u540c\u7c7b\u578b\u7684\u8bed\u53e5\u7684\u8bed\u6cd5\u3002 \u901a\u5e38\u7ea6\u5b9a\u4f7f\u75284\u4e2a\u7a7a\u683c\u4f5c\u4e3a\u9501\u8fdb\u5bbd\u5ea6\u3002 1.1.2.\u5b57\u7b26\u4e32 \u00b6 \u5355\u5f15\u53f7 \u53cc\u5f15\u53f7 \u6210\u5bf9\u7684\u4e09\u4e2a\u53cc\u5f15\u53f7\uff08\u591a\u884c\u6587\u672c\uff09 \u6210\u5bf9\u7684\u4e09\u4e2a\u5355\u5f15\u53f7\uff08\u591a\u884c\u6587\u672c\uff09 \u8f6c\u4e49\u5b57\u7b26 \\ \uff08\u53cd\u659c\u6760\uff09 1.1.3.\u8fd0\u7b97\u7b26\u548c\u8868\u8fbe\u5f0f \u00b6 \u6807\u51c6\u8fd0\u7b97\u7b26\uff1a + \u3001 - \u3001 * \u3001 / \u3001 % \u7b97\u672f\u8868\u8fbe\u5f0f\u662f\u7528\u6807\u51c6\u8fd0\u7b97\u7b26\u548c\u4e2d\u7f00\u8868\u793a\u6cd5 \u6bd4\u8f83\u8fd0\u7b97\u7b26\uff1a < \u3001 <= \u3001 > \u3001 >= \u3001 == \u3001 != \uff0c\u7528\u4e8e\u6bd4\u8f83\u6570\u5b57\u6216\u5b57\u7b26\u4e32\uff0c\u8fd4\u56deTrue\u6216False \u8fd0\u7b97\u7b26 == \u7528\u4e8e\u6bd4\u8f83\u6570\u636e\u7ed3\u6784\u91cc\u7684\u5185\u5bb9\uff0c\u8fd0\u7b97\u7b26 is \u7528\u4e8e\u6bd4\u8f83\u4e24\u4e2a\u5bf9\u8c61\u7684\u6807\u8bc6\u662f\u5426\u4e00\u81f4 \u903b\u8f91\u8fd0\u7b97\u7b26\uff1a and \u3001 or \u3001 not \u3002\u628a0\u3001None\u3001\u7a7a\u5b57\u7b26\u4e32\u3001\u7a7a\u5217\u8868\u7b49\u89c6\u4e3aFalse\uff0c\u5927\u591a\u6570\u5176\u4ed6\u503c\u662f\u4e3aTrue \u4e0b\u6807\u8fd0\u7b97\u7b26\uff1a [] \uff0c\u4e0e\u591a\u9879\u96c6collection\u5bf9\u8c61\u4e00\u8d77\u4f7f\u7528 \u9009\u62e9\u5668\u8fd0\u7b97\u7b26\uff1a . \uff0c\u7528\u4e8e\u5f15\u7528\u4e00\u4e2a\u6a21\u5757\u3001\u7c7b\u6216\u5bf9\u8c61\u4e2d\u7684\u4e00\u4e2a\u5177\u540d\u7684\u9879 \u8fd0\u7b97\u7b26\u4f18\u5148\u7ea7\uff0c\u4f9d\u6b21\u662f\u9009\u62e9\u8fd0\u7b97\u7b26\u3001\u51fd\u6570\u8c03\u7528\u8fd0\u7b97\u7b26\u3001\u4e0b\u6807\u8fd0\u7b97\u7b26\u3001\u7b97\u672f\u8fd0\u7b97\u7b26\u3001\u6bd4\u8f83\u8fd0\u7b97\u7b26\u3001\u903b\u8f91\u8fd0\u7b97\u7b26\u3001\u8d4b\u503c\u8fd0\u7b97\u7b26\u3002\u62ec\u53f7\u7528\u4e8e\u8ba9\u5b50\u8868\u8fbe\u5f0f\u4f18\u5148\u8fd0\u884c\u3002 1.1.4.\u51fd\u6570\u8c03\u7528 \u00b6 \u51fd\u6570\u540d\u79f0\u540e\u9762\u8ddf\u7740\u7528\u62ec\u53f7\u62ec\u8d77\u6765\u7684\u53c2\u6570\u5217\u8868\uff0c\u4f8b\u5982\uff1a min(5,2) \u6807\u51c6\u51fd\u6570 \u5176\u4ed6\u6a21\u5757\u5bfc\u5165\u51fd\u6570 1.1.5.print\u51fd\u6570 \u00b6 \u81ea\u52a8\u4e3a\u6bcf\u4e2a\u53c2\u6570\u8fd0\u884c str \u51fd\u6570\uff0c\u4ee5\u5f97\u5230\u5176\u5b57\u7b26\u4e32\u8868\u793a \u5728\u8f93\u51fa\u4e4b\u524d\u4f1a\u7528\u7a7a\u683c\u5427\u6bcf\u4e2a\u5b57\u7b26\u4e32\u9694\u5f00 \u9ed8\u8ba4\u4ee5\u6362\u884c\u7b26\u4f5c\u4e3a\u7ed3\u675f 1.1.6.input\u51fd\u6570 \u00b6 \u6807\u51c6\u8f93\u5165\u51fd\u6570input\u4f1a\u4e00\u76f4\u7b49\u5f85\u7528\u6237\u901a\u8fc7\u952e\u76d8\u8f93\u5165\u6587\u672c \u63a5\u53d7\u4e00\u4e2a\u53ef\u9009\u7684\u5b57\u7b26\u4e32\u4f5c\u4e3a\u5176\u53c2\u6570 1.1.7.\u7c7b\u578b\u8f6c\u6362\u51fd\u6570\u548c\u6df7\u5408\u6a21\u5f0f\u64cd\u4f5c \u00b6 Python\u5141\u8bb8\u7b97\u672f\u8868\u8fbe\u5f0f\u4e2d\u7684\u64cd\u4f5c\u6570\u5177\u6709\u4e0d\u540c\u7684\u6570\u503c\u7c7b\u578b\u3002\u4f8b\u5982\uff0c\u628aint\u7c7b\u578b\u7684\u64cd\u4f5c\u6570\u548cfloat\u7c7b\u578b\u7684\u64cd\u4f5c\u6570\u76f8\u52a0\uff0c\u4f1a\u5f97\u5230float\u7c7b\u578b\u7684\u6570\u3002 # \u8f93\u5165\u534a\u5f84\u6c42\u5706\u9762\u79ef radius = float ( input ( \"Radius: \" )) print ( \"The area is\" , 3.14 * radius ** 2 ) 1.1.8.\u53ef\u9009\u548c\u5173\u952e\u5b57\u51fd\u6570\u53c2\u6570 \u00b6 \u5fc5\u9009\u53c2\u6570\u662f\u6ca1\u6709\u9ed8\u8ba4\u503c\u7684\uff1b\u53ef\u9009\u53c2\u6570\u6709\u9ed8\u8ba4\u503c\uff1b \u5728\u8c03\u7528\u51fd\u6570\u65f6\uff0c\u4f20\u9012\u7ed9\u5b83\u7684\u53c2\u6570\u6570\u91cf\u5fc5\u987b\u81f3\u5c11\u548c\u5fc5\u9009\u53c2\u6570\u7684\u6570\u91cf\u76f8\u540c\u3002 \u6807\u51c6\u51fd\u6570\u548cPython\u7684\u5e93\u51fd\u6570\u5728\u8c03\u7528\u65f6\u90fd\u4f1a\u5bf9\u4f20\u5165\u7684\u53c2\u6570\u8fdb\u884c\u7c7b\u578b\u68c0\u67e5 1.1.9.\u53d8\u91cf\u548c\u8d4b\u503c\u8bed\u53e5 \u00b6 \u7b80\u5355\u7684\u8d4b\u503c\u8bed\u53e5 PI = 3.1416 \u591a\u53d8\u91cf\u8d4b\u503c minValue, maxValue = 1, 100 \u53d8\u91cf\u4ea4\u6362 a, b = b, a \u8d4b\u503c\u8bed\u53e5\u5fc5\u987b\u5199\u5728\u4e00\u884c\u4ee3\u7801\u91cc\uff0c\u4f46\u662f\u53ef\u4ee5\u5728\u9017\u53f7\u3001\u5706\u62ec\u53f7\u3001\u82b1\u62ec\u53f7\u6216\u65b9\u62ec\u53f7\u4e4b\u540e\u6362\u884c\uff0c\u6216\u8005\u7528\u8f6c\u4e49\u7b26 \\ \u8fdb\u884c\u6362\u884c\u3002 \u6362\u884c\u793a\u4f8b\uff1a minValue = min ( 100 , 200 ) product = max ( 100 , 200 ) \\ * 30 1.1.10.\u6570\u636e\u7c7b\u578b \u00b6 \u53d8\u91cf\u90fd\u53ef\u4ee5\u88ab\u6307\u5b9a\u4e3a\u4efb\u4f55\u7c7b\u578b\u7684\u503c\u3002\u8fd9\u4e9b\u53d8\u91cf\u5e76\u4e0d\u50cf\u5176\u4ed6\u8bed\u8a00\u90a3\u6837\u88ab\u58f0\u660e\u4e3a\u7279\u5b9a\u7684\u7c7b\u578b\uff0c\u800c\u53ea\u662f\u88ab\u8d4b\u4e86\u4e00\u4e2a\u503c \u503c\u548c\u5bf9\u8c61\u90fd\u662f\u6709\u7c7b\u578b\u7684\uff0c\u4f1a\u5728\u8fd0\u884c\u65f6\u8fdb\u884c\u6570\u636e\u7c7b\u578b\u68c0\u67e5 1.1.11. import \u8bed\u53e5 \u00b6 import \u8bed\u53e5\u4f7f\u5f97\u4e00\u4e2a\u6a21\u5757\u4e2d\u7684\u6807\u8bc6\u7b26\u53ef\u4ee5\u88ab\u53e6\u4e00\u4e2a\u7a0b\u5e8f\u6240\u89c1\u5230\u3002\u6807\u8bc6\u7b26\u53ef\u4ee5\u662f\u5bf9\u8c61\u540d\u3001\u51fd\u6570\u540d\u6216\u7c7b\u540d \u5bfc\u5165\u6a21\u5757\u540d\u79f0\uff0c\u4f8b\u5982 import math \u5bfc\u5165\u6a21\u5757\u4e2d\u7684\u6807\u8bc6\u7b26\uff0c\u4f8b\u5982\uff1a from math import sqrt \uff0c\u6216\u8005 from math import pi, sqrt \u4e5f\u53ef\u4ee5\u4f7f\u7528\u7b26\u53f7 * \u5bfc\u5165\u4e00\u4e2a\u6a21\u5757\u4e2d\u7684\u6240\u6709\u540d\u79f0\uff0c\u4f46\u4e0d\u63a8\u8350 1.2.\u63a7\u5236\u8bed\u53e5 \u00b6 1.2.1.\u6761\u4ef6\u8bed\u53e5 \u00b6 \u5355\u5411if\u8bed\u53e5\u7684\u8bed\u6cd5 if < Boolean expression > : < sequence of statements > \u53cc\u5411if\u8bed\u53e5\u7684\u8bed\u6cd5 if < Boolean expression > : < sequence of statements > else : < sequence of statements > \u591a\u5411if\u8bed\u53e5\u7684\u8bed\u6cd5 if < Boolean expression > : < sequence of statements > elif < Boolean expression > : < sequence of statements > ... else : < sequence of statements > 1.2.2.\u4f7f\u7528if name == \" main \" \u00b6 \u793a\u4f8b\u4ee3\u7801 numberguess.py \u3002 import random def main (): smaller = int ( input ( \"\u8f93\u5165\u6700\u5c0f\u503c: \" )) larger = int ( input ( \"\u8f93\u5165\u6700\u5927\u503c: \" )) myNumber = random . randint ( smaller , larger ) count = 0 while True : count += 1 userNumber = int ( input ( \"\u8f93\u5165\u4f60\u731c\u7684\u503c: \" )) if userNumber < myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5c0f\uff01\" ) elif userNumber > myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5927\uff01\" ) else : print ( \"\u606d\u559c\uff0c\u4f60\u5728\u7b2c\" , count , \"\u6b21\u731c\u5bf9\u4e86!\" ) break if __name__ == \"__main__\" : main () \u4e0a\u9762\u7684if\u8bed\u53e5\u7684\u4f5c\u7528\u662f\uff0c \u8981\u4e48\u5c06\u6a21\u5757\u5f53\u4f5c\u4e00\u4e2a\u72ec\u7acb\u7684\u7a0b\u5e8f\u8fd0\u884c\uff0c\u8be5\u6a21\u5757\u7684 _name_ \u53d8\u91cf\u4f1a\u8bbe\u7f6e\u4e3a\u5b57\u7b26\u4e32 _main_ \uff0c\u624d\u4f1a\u6267\u884c main() \u51fd\u6570 \u8981\u4e48\u4ece\u53e6\u4e00\u4e2a\u6a21\u5757\u4e2d\u5bfc\u5165\uff0c\u8be5\u6a21\u5757\u7684 _name_ \u53d8\u91cf\u4f1a\u8bbe\u7f6e\u8be5\u6a21\u5757\u7684\u540d\u79f0\uff0c\u4e0a\u4f8b\u4e2d\u5373 numberguess 1.2.3.\u5faa\u73af\u8bed\u53e5 \u00b6 \u901a\u5e38\uff1a \u4e00\u822c\u4f1a\u4f7f\u7528for\u5faa\u73af\u6765\u8fed\u4ee3\u786e\u5b9a\u8303\u56f4\u7684\u503c\u6216\u503c\u7684\u5e8f\u5217 \u5982\u679c\u7ee7\u7eed\u5faa\u73af\u7684\u6761\u4ef6\u662f\u67d0\u4e2a\u5e03\u5c14\u8868\u8fbe\u5f0f\uff0c\u4e00\u822c\u4f1a\u4f7f\u7528while\u5faa\u73af while \u8bed\u6cd5\u683c\u5f0f\uff1a while < Boolean expression > : < sequence of statements > \u793a\u4f8b\uff1a # \u8ba1\u7b97\u4ece1\u523010\u7684\u4e58\u79ef\u5e76\u8f93\u51fa\u7ed3\u679c result = 1 value = 1 while value <= 10 : result *= value value += 1 print ( result , value ) # \u8fd0\u884c\u7ed3\u679c # 3628800 11 for \u8bed\u6cd5\u683c\u5f0f\uff1a for < variable > in < iterable object > : < sequence of statements > \u793a\u4f8b\uff1a # \u8ba1\u7b97\u4ece1\u523010\u7684\u4e58\u79ef\u5e76\u8f93\u51fa\u7ed3\u679c result = 1 value = 1 for value in range ( 1 , 11 ): result *= value value += 1 print ( result , value ) # \u8fd0\u884c\u7ed3\u679c # 3628800 11 1.3.\u5b57\u7b26\u4e32\u53ca\u5176\u8fd0\u7b97 \u00b6 Python\u4e2d\u7684\u5b57\u7b26\u4e32\u4e5f\u662f\u4e00\u4e2a\u590d\u5408\u5bf9\u8c61 Python\u7684\u5b57\u7b26\u4e32\u7c7b\u578b\u540d\u4e3a str \u7ea6\u5b9a\uff1a \u628a\u5355\u5b57\u7b26\u7684\u5b57\u7b26\u4e32\u7528\u5355\u5f15\u53f7\u62ec\u8d77\u6765 \u628a\u591a\u5b57\u7b26\u7684\u5b57\u7b26\u4e32\u7528\u53cc\u5f15\u53f7\u62ec\u8d77\u6765 1.3.1.\u8fd0\u7b97\u7b26 \u00b6 \u6bd4\u8f83\u8fd0\u7b97\u7b26\uff0c\u662f\u6309\u7167ASCII\u7801\u7684\u987a\u5e8f\u6bd4\u8f83\u4e24\u4e2a\u5b57\u7b26\u4e32\u4e2d\u6bcf\u4e2a\u4f4d\u7f6e\u7684\u5b57\u7b26\u5bf9 \u793a\u4f8b\uff1a print ( 'A' > 'a' ) # \u8fd0\u884c\u7ed3\u679c False print ( 'A' < 'a' ) # \u8fd0\u884c\u7ed3\u679c True + \u8fd0\u7b97\u7b26\u751f\u6210\u5e76\u8fd4\u56de\u4e00\u4e2a\u5305\u542b\u4e24\u4e2a\u64cd\u4f5c\u6570\u7684\u65b0\u5b57\u7b26\u4e32 \u793a\u4f8b\uff1a print ( \"Hello\" + \"Python\" ) # \u8fd0\u884c\u7ed3\u679c HelloPython \u4e0b\u6807\u8fd0\u7b97\u7b26\uff0c\u8303\u56f4\u662f\u4ece0\u5230\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u51cf\u53bb1\u7684\u4e00\u4e2a\u6574\u6570\u3002 \u8fd0\u7b97\u7b26\u8fd4\u56de\u5728\u5b57\u7b26\u4e32\u4e2d\u8be5\u4f4d\u7f6e\u7684\u5b57\u7b26\u3002 \u793a\u4f8b\uff1a print ( \"Greater\" [ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1ar \u5f53\u7d22\u5f15\u4e3a\u8d1f\u503c\u65f6\uff0cPython\u4f1a\u628a\u8fd9\u4e2a\u503c\u548c\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u76f8\u52a0\uff0c\u4ee5\u786e\u5b9a\u8981\u8fd4\u56de\u7684\u5b57\u7b26\u7684\u4f4d\u7f6e\u3002\u8d1f\u7d22\u5f15\u503c\u4e0d\u5f97\u5c0f\u4e8e\u5b57\u7b26\u4e32\u957f\u5ea6\u7684\u8d1f\u503c\u3002 print ( \"Greater\" [ - 3 ]) # \u8fd0\u884c\u7ed3\u679c\uff1at print ( \"Greater\" [ - 9 ]) # \u8fd0\u884c\u7ed3\u679c\uff1aIndexError: string index out of range \u5207\u7247\u8fd0\u7b97\u7b26\uff08slice operator\uff09\uff0c\u4e0b\u6807\u8fd0\u7b97\u7b26\u7684\u4e00\u79cd\u53d8\u4f53\u3002 \u8bed\u6cd5\u683c\u5f0f\uff1a [:] \uff1a\u8303\u56f4\u662f\u4ece0\u5230\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u51cf\u53bb1\u7684\u6574\u6570 \uff1a\u8303\u56f4\u662f\u4ece0\u5230\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u7684\u6574\u6570 \u5207\u7247\u68c0\u7d22\u89c4\u5219\uff1a \u8fd4\u56de\u8fd9\u6837\u4e00\u4e2a\u5b50\u5b57\u7b26\u4e32\uff1a\u8fd9\u4e2a\u5b50\u5b57\u7b26\u4e32\u4f1a\u4ece \u7d22\u5f15\u5904\u7684\u5b57\u7b26\u5f00\u59cb\uff0c\u5230 \u7d22\u5f15\u51cf1\u7684\u4f4d\u7f6e\u4f5c\u4e3a\u7ed3\u675f\u3002 \u5982\u679c\u7701\u7565 \u7d22\u5f15\uff0c\u90a3\u4e48\u5207\u7247\u8fd0\u7b97\u7b26\u5c06\u8fd4\u56de\u4e00\u4e2a\u4ee5\u5f53\u524d\u5b57\u7b26\u4e32\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\u4f5c\u4e3a\u5f00\u5934\u7684\u5b50\u5b57\u7b26\u4e32\u3002 \u5982\u679c\u7701\u7565 \u7d22\u5f15\uff0c\u90a3\u4e48\u5207\u7247\u8fd0\u7b97\u7b26\u5c06\u8fd4\u56de\u4e00\u4e2a\u4ee5\u5f53\u524d\u5b57\u7b26\u4e32\u7684\u6700\u540e\u4e00\u4e2a\u5b57\u7b26\u4f5c\u4e3a\u7ed3\u5c3e\u7684\u5b50\u5b57\u7b26\u4e32\u3002 \u5982\u679c\u7701\u7565\u8fd9\u4e24\u4e2a\u503c\uff0c\u90a3\u4e48\u5207\u7247\u8fd0\u7b97\u7b26\u4f1a\u8fd4\u56de\u6574\u4e2a\u5b57\u7b26\u4e32\u3002 \u793a\u4f8b\uff1a print ( \"Greater\" [:]) # \u8fd4\u56de\u5b57\u4e32 Greater print ( \"Greater\" [ 2 :]) # \u8fd4\u56de\u5b57\u4e32 eater print ( \"Greater\" [: 2 ]) # \u8fd4\u56de\u5b57\u4e32 Gr print ( \"Greater\" [ 2 : 5 ]) # \u8fd4\u56de\u5b57\u4e32 eat 1.3.2.\u5b57\u7b26\u4e32\u683c\u5f0f\u5316 \u00b6 \u683c\u5f0f\u5316\u5b57\u7b26\u4e32\u91cc\u7684\u6570\u636e\u5b57\u7b26\u4ee5\u53ca\u6ee1\u8db3\u7ed9\u5b9a\u57fa\u51c6\u7ebf\u7684\u9644\u52a0\u7a7a\u683c\u7684\u603b\u6570\u79f0\u4e3a\u5b83\u7684\u5b57\u6bb5\u5bbd\u5ea6\uff08field width\uff09\u3002 print \u51fd\u6570\u4f1a\u5728\u9047\u5230\u7b2c\u4e00\u5217\u65f6\u81ea\u52a8\u5f00\u59cb\u6253\u5370\u8f93\u51fa\u57fa\u51c6\u7ebf\u3002 \u793a\u4f8b\uff0c\u901a\u8fc7print\u8bed\u53e5\u8f93\u51fa2\u5217\u3002 for i in range ( 7 , 11 ): print ( i , 10 * i ) # \u8fd0\u884c\u7ed3\u679c # 7 70 # 8 80 # 9 90 # 10 100 Python\u7684\u901a\u7528\u683c\u5f0f\u5316\u673a\u5236 \u8bed\u6cd5\u683c\u5f0f % \u548c % (, \u2026, ) \u3002 \u683c\u5f0f\u5316\u5b57\u7b26\u4e32\u65f6\uff0c \u4f7f\u7528 %s \u8868\u793a\u6cd5\u3002\u5f53\u5b57\u6bb5\u5bbd\u5ea6\u4e3a\u6b63\u65f6\uff0c\u6570\u636e\u662f\u53f3\u5bf9\u9f50\u7684\uff1b\u5f53\u5b57\u6bb5\u5bbd\u5ea6\u4e3a\u8d1f\u65f6\uff0c\u6570\u636e\u662f\u5de6\u5bf9\u9f50\u7684\u3002 \u683c\u5f0f\u6574\u6570\u65f6\uff0c \u4f7f\u7528 %d \u8868\u793a\u6cd5\u3002 \u683c\u5f0f\u6d6e\u70b9\u6570\u65f6\uff0c \u4f7f\u7528 %.f \u8868\u793a\u6cd5\uff0c\u5176\u4e2d . \u8fd9\u4e00\u90e8\u5206\u662f\u53ef\u9009\u7684\u3002 \u793a\u4f8b\uff1a print ( \" %6s \" % \"four\" ) print ( \" %-6s \" % \"four\" ) # four # four for i in range ( 7 , 11 ): print ( \" %-3d%5d \" % ( i , 10 * i )) # 7 70 # 8 80 # 9 90 # 10 100 for i in range ( 7 , 11 ): print ( \" %-3d%5.3f \" % ( i , i / 3 )) # 7 2.333 # 8 2.667 # 9 3.000 # 10 3.333 \u4e0b\u4f8b\u5bf9\u6bd4\u4e86\u6d6e\u70b9\u6570\u5728\u4f7f\u7528\u4e86\u683c\u5f0f\u5b57\u7b26\u4e32\u548c\u6ca1\u6709\u4f7f\u7528\u683c\u5f0f\u5b57\u7b26\u4e32\u8fd9\u4e24\u79cd\u60c5\u51b5\u4e0b\u7684\u8f93\u51fa\u5dee\u5f02\u3002 salary = 100.00 print ( \"Salary: $\" + str ( salary )) # Salary: $100.0 print ( \"Salary: $ %0.2f \" % salary ) # Salary: $100.00 \u6ce8\u610f\uff0c\u4e0b\u4f8b\u4e2dPython\u7ed9\u6570\u5b57\u6dfb\u52a0\u4e86\u4e00\u4e2a\u7cbe\u5ea6\u4f4d\u6570\uff0c\u5e76\u4e14\u5176\u5de6\u4fa7\u586b\u5145\u7a7a\u683c\uff0c\u4ece\u800c\u5b9e\u73b0\u4e86\u5b57\u6bb5\u5bbd\u5ea6\u4e3a6\u3001\u7cbe\u5ea6\u4e3a3\u7684\u8bbe\u7f6e\u3002\u8fd9\u4e2a\u5bbd\u5ea6\u5305\u542b\u5c0f\u6570\u70b9\u540e\u6240\u5360\u636e\u7684\u4f4d\u7f6e\u3002 print ( \" %6.3f \" % 3.14 ) # \u5de6\u4fa7\u586b\u5145\u4e86\u7a7a\u683c # 3.140 print ( \" %-6.3f \" % 3.14 ) # 3.140 1.3.3.\u5bf9\u8c61\u548c\u65b9\u6cd5\u8c03\u7528 \u00b6 \u8bed\u6cd5\u683c\u5f0f\uff1a .() \u793a\u4f8b\uff1a print ( \"greater\" . isupper ()) # \u8fd0\u884c\u7ed3\u679c # False print ( \"greater\" . upper ()) # \u8fd0\u884c\u7ed3\u679c # GREATER print ( \"greater\" . startswith ( \"great\" )) # \u8fd0\u884c\u7ed3\u679c # True print ( len ( \"greater\" )) print ( \"greater\" . __len__ ()) # \u8fd0\u884c\u7ed3\u679c # 7 print ( \"great\" + \"er\" ) print ( \"great\" . __add__ ( \"er\" )) # \u8fd0\u884c\u7ed3\u679c # greater print ( \"e\" in \"great\" ) print ( \"great\" . __contains__ ( \"e\" )) # \u8fd0\u884c\u7ed3\u679c # True \u63d0\u793a\uff1a dir() \u65b9\u6cd5\u4f1a\u8fd4\u56de\u6240\u4f20\u9012\u7684\u5bf9\u8c61\u7684\u6709\u6548\u5c5e\u6027\uff0c\u8bed\u6cd5\u683c\u5f0f\uff1a dir(object) help() \u51fd\u6570\u67e5\u770b\u51fd\u6570\u6216\u6a21\u5757\u7528\u9014\u7684\u8be6\u7ec6\u8bf4\u660e\uff0c\u8bed\u6cd5\u683c\u5f0f\uff1a help(object) dir ( str ) help ( str . __contains__ ) 1.4.\u5185\u7f6e\u591a\u9879\u96c6\u53ca\u5176\u64cd\u4f5c \u00b6 Python\u4e2d\u7684\u591a\u9879\u96c6\uff08collections\uff09\u6307\u80fd\u591f\u5305\u542b\u5143\u7d20\u7684\u6570\u636e\u7ed3\u6784\u3002\u591a\u9879\u96c6\u6a21\u5757\u63d0\u4f9b\u4e86\u4e0d\u540c\u7c7b\u578b\u7684\u5bb9\u5668\u3002\u5bb9\u5668\u662f\u7528\u4e8e\u5b58\u50a8\u4e0d\u540c\u5bf9\u8c61\u5e76\u63d0\u4f9b\u8bbf\u95ee\u6240\u5305\u542b\u5bf9\u8c61\u4ee5\u53ca\u5bf9\u5b83\u4eec\u8fdb\u884c\u8fed\u4ee3\u7684\u65b9\u5f0f\u7684\u5bf9\u8c61\u3002\u4e00\u4e9b\u5185\u7f6e\u7684\u5bb9\u5668\u6709\u5143\u7ec4\uff08Tuple\uff09\u3001\u5217\u8868\uff08List\uff09\u3001\u5b57\u5178\uff08Dictionary\uff09\u7b49\u3002 \u4ee5\u4e0b\u662f\u7531collections\u6a21\u5757\u63d0\u4f9b\u7684\u4e0d\u540c\u5bb9\u5668\u7684\u5217\u8868\uff1a \u8ba1\u6570\u5668\uff08Counters\uff09 \u6709\u5e8f\u5b57\u5178\uff08OrderedDict\uff09 \u9ed8\u8ba4\u5b57\u5178\uff08DefaultDict\uff09 \u94fe\u6620\u5c04\uff08ChainMap\uff09 \u547d\u540d\u5143\u7ec4\uff08NamedTuple\uff09 \u53cc\u5411\u961f\u5217\uff08DeQue\uff09 \u7528\u6237\u5b57\u5178\uff08UserDict\uff09 \u7528\u6237\u5217\u8868\uff08UserList\uff09 \u7528\u6237\u5b57\u7b26\u4e32\uff08UserString\uff09 1.4.1.\u5217\u8868 \u00b6 \u5217\u8868\uff08list\uff09\u662f\u96f6\u4e2a\u6216\u591a\u4e2aPython\u5bf9\u8c61\u7684\u4e00\u4e2a\u5e8f\u5217\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u901a\u5e38\u79f0\u4e3a\u9879\uff08item\uff09\u3002 \u5217\u8868\u7684\u8868\u73b0\u5f62\u5f0f\u662f\uff1a\u7528\u65b9\u62ec\u53f7\u62ec\u8d77\u6574\u4e2a\u5217\u8868\uff0c\u5e76\u7528\u9017\u53f7\u5206\u9694\u5143\u7d20\u3002 \u793a\u4f8b\uff1a [] # \u7a7a\u5217\u8868 [ \"greater\" , \"less\" , 10 ] # \u542b\u4e0d\u540c\u7c7b\u578b\u7684\u5217\u8868 [ \"greater\" , [ \"less\" , 10 ]] # \u542b\u5185\u5d4c\u5217\u8868\u7684\u5217\u8868 \u5217\u8868\u7684\u5207\u7247\u64cd\u4f5c\uff1a \u548c\u5b57\u7b26\u4e32\u7c7b\u4f3c\uff0c\u53ef\u4ee5\u901a\u8fc7\u6807\u51c6\u8fd0\u7b97\u7b26\u6267\u884c\u5207\u7247\u6216\u8fde\u63a5\u64cd\u4f5c\uff0c\u8fd4\u56de\u7ed3\u679c\u4e5f\u662f\u5217\u8868\u3002 \u548c\u5b57\u7b26\u4e32\u4e0d\u540c\uff0c\u5217\u8868\u662f\u53ef\u53d8\u7684\uff0c\u5373\uff0c\u53ef\u4ee5\u66ff\u6362\u3001\u63d2\u5165\u6216\u5220\u9664\u5217\u8868\u4e2d\u6240\u5305\u542b\u7684\u9879\u3002 \u5207\u7247\u548c\u8fde\u63a5\u8fd0\u7b97\u7b26\u6240\u8fd4\u56de\u7684\u5217\u8868\u662f\u65b0\u7684\u5217\u8868\uff0c\u800c\u4e0d\u662f\u6700\u521d\u5217\u8868\u7684\u4e00\u90e8\u5206\uff1b \u5217\u8868\u7c7b\u578b\u5305\u542b\u4e86\u51e0\u4e2a\u53eb\u4f5c\u53d8\u5f02\u5668\uff08mutator\uff09\u7684\u65b9\u6cd5\uff0c\u7528\u4e8e\u4fee\u6539\u5217\u8868\u7684\u7ed3\u6784\u3002 \u53ef\u4ee5\u901a\u8fc7 dir(list) \u6765\u67e5\u770b\u65b9\u6cd5\uff0c\u5305\u62ec\u53d8\u5f02\u5668\uff08mutator\uff09\u7684\u65b9\u6cd5\u3002 dir ( list ) # \u8fd0\u884c\u7ed3\u679c # ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] \u6700\u5e38\u7528\u7684\u5217\u8868\u53d8\u5f02\u5668\u65b9\u6cd5\u662f append \u3001 insert \u3001 pop \u3001 remove \u548c sort \u3002 \u793a\u4f8b\uff1a myList = [] # myList\u5f53\u524d\u4e3a[] myList . append ( 34 ) # myList\u5f53\u524d\u4e3a[34]\uff0c\u9ed8\u8ba4\u5c3e\u90e8\u63d2\u5165 myList . append ( 22 ) # myList\u5f53\u524d\u4e3a[34, 22]\uff0c\u9ed8\u8ba4\u5c3e\u90e8\u63d2\u5165 myList . sort () # myList\u5f53\u524d\u4e3a[22, 34] myList . pop () # \u9ed8\u8ba4\u4ece\u7d22\u5f15\u4f4d[0]\u5220\u9664\uff0c\u8fd4\u56de\u7ed3\u679c22\uff1bmyList\u5f53\u524d\u4e3a[34] myList . insert ( 0 , 22 ) # \u5728\u6307\u5b9a\u7d22\u5f15\u4f4d[0]\u63d2\u5165\uff1bmyList\u5f53\u524d\u4e3a[22, 34] myList . insert ( 1 , 55 ) # \u5728\u6307\u5b9a\u7d22\u5f15\u4f4d[1]\u63d2\u5165\uff1bmyList\u5f53\u524d\u4e3a[22, 55, 34] myList . pop ( 1 ) # \u6307\u5b9a\u7d22\u5f15\u4f4d[1]\u5220\u9664\uff0c\u8fd4\u56de\u7ed3\u679c55\uff1bmyList\u5f53\u524d\u4e3a[22, 34] myList . remove ( 22 ) # \u5220\u9664\u9996\u4e2a\u5339\u914d\u9879\u7684\u5143\u7d20[22]\uff1bmyList\u5f53\u524d\u4e3a[34] myList . remove ( 55 ) # \u62a5ValueError\u9519\uff0clist.remove(x): x not in list \u5bf9\u4e8e\u5b57\u7b26\u4e32\uff0csplit\u65b9\u6cd5\u4f1a\u4ece\u5b57\u7b26\u4e32\u91cc\u5206\u79bb\u51fa\u4e00\u4e2a\u5355\u8bcd\u5217\u8868\uff0c\u800cjoin\u65b9\u6cd5\u4f1a\u628a\u5355\u8bcd\u5217\u8868\u8fde\u5728\u4e00\u8d77\u4ece\u800c\u5f62\u6210\u5b57\u7b26\u4e32\u3002\u4f8b\u5982\uff1a print ( \"Python is cool\" . split ()) # \u8fd0\u884c\u7ed3\u679c\uff1a # ['Python', 'is', 'cool'] print ( \" \" . join ([ \"Python\" , \"is\" , \"cool\" ])) # \u8fd0\u884c\u7ed3\u679c\uff1a # Python is cool \u5bf9\u4e8e\u5217\u8868\u7279\u6027\u548c\u64cd\u4f5c\u7684\u8be6\u7ec6\u7ec3\u4e60\uff0c\u53c2\u8003 Python\u8bed\u8a00\u57fa\u7840@github \u6216\u8005 Python\u8bed\u8a00\u57fa\u7840@web \u4e2d\u201c1.3 \u5217\u8868\uff08list\uff09\u201d\u7684\u5185\u5bb9\u3002 1.4.2.\u5143\u7ec4 \u00b6 \u5143\u7ec4\uff08tuple\uff09\u662f\u4e00\u4e2a\u4e0d\u53ef\u53d8\u7684\u5143\u7d20\u5e8f\u5217\u3002 \u5143\u7ec4\uff08tuple\uff09\u5f62\u5f0f\u662f\u7528\u5706\u62ec\u53f7\u5c06\u5404\u9879\u62ec\u8d77\u6765\uff0c\u5e76\u4e14\u5fc5\u987b\u81f3\u5c11\u5305\u542b\u4e24\u4e2a\u9879\u3002 \u5143\u7ec4\u5b9e\u9645\u4e0a\u5c31\u50cf\u5217\u8868\u4e00\u6837\uff0c\u53ea\u4e0d\u8fc7\u5b83\u6ca1\u6709\u53d8\u5f02\u5668\u65b9\u6cd5\u3002 \u5982\u679c\u8981\u4f7f\u5143\u7ec4\u53ea\u5305\u542b\u4e00\u4e2a\u5143\u7d20\uff0c\u5219\u5fc5\u987b\u5728\u5143\u7ec4\u91cc\u5305\u542b\u9017\u53f7\u3002 \u5bf9\u6bd4\u4e0b\u9762\u7684\u533a\u522b\uff1a print (( 21 )) # (21)\u88ab\u89c6\u4e3a\u6574\u6570 # \u8fd0\u884c\u7ed3\u679c\uff1a # 21 print (( 21 ,)) # (21,)\u88ab\u89c6\u4e3a\u5143\u7ec4 # \u8fd0\u884c\u7ed3\u679c\uff1a # (21,) \u5bf9\u4e8e\u5217\u8868\u7279\u6027\u548c\u64cd\u4f5c\u7684\u8be6\u7ec6\u7ec3\u4e60\uff0c\u53c2\u8003 Python\u8bed\u8a00\u57fa\u7840@github \u6216\u8005 Python\u8bed\u8a00\u57fa\u7840@web \u4e2d\u201c1.6 \u5143\u7ec4\uff08tuple\uff09\u201d\u7684\u5185\u5bb9\u3002 1.4.3.\u5e8f\u5217\u904d\u5386 \u00b6 for \u5faa\u73af\u53ef\u4ee5\u7528\u6765\u904d\u5386\u5e8f\u5217\uff08\u5982\u5b57\u7b26\u4e32\u3001\u5217\u8868\u6216\u5143\u7ec4\uff09\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002 \u904d\u5386\u5217\u8868\uff1a myList = [ 67 , 100 , 'Monday' , \"It's good\" ] for item in myList : print ( item ) myList = [ 67 , 100 , 'Monday' , \"It's good\" ] for idx in range ( len ( myList )): print ( myList [ idx ]) \u904d\u5386\u5143\u7ec4\uff1a myString = \"I love Python\" myList = myString . split () myTuple = tuple ( myList ) for i in myTuple : print ( i ) \u904d\u5386\u5b57\u7b26\u4e32\uff1a(\u6ce8\u610f\uff0c\u662f\u904d\u5386\u5b57\u7b26\uff0c\u4e0d\u662f\u5355\u8bcd) myString = \"I love Python\" for i in myString : print ( i ) myString = \"I love Python\" for i in range ( len ( myString )): print ( myString [ i ]) myString = \"I love Python\" for i in enumerate ( myString ): print ( i ) myString = \"I love Python\" for i , j in enumerate ( myString ): print ( i , j ) myString = \"I love Python\" for i in iter ( myString ): print ( i ) \u5982\u679c\u6309\u7167\u5355\u8bcd\u904d\u5386\u5b57\u7b26\u4e32\uff0c\u5219\u9700\u8981\u5148\u628a\u5b57\u4e32\u6309\u5355\u8bcd\u62c6\u89e3\u4e3a\u5217\u8868\u3002 myString = \"I love Python\" myList = \"I love Python\" . split () for i in myList : print ( i ) \u5bf9\u4e8e\u5217\u8868\u548c\u5143\u7ec4\u904d\u5386\u7684\u66f4\u591a\u4f8b\u5b50\uff0c\u5305\u62ec\u62c6\u5305\u904d\u5386\uff0c\u53c2\u8003 Python\u8bed\u8a00\u57fa\u7840@github \u6216\u8005 Python\u8bed\u8a00\u57fa\u7840@web \u7684\u5185\u5bb9\u3002 1.4.4.\u5b57\u5178 \u00b6 \u5b57\u5178\uff08dictionary\uff09\u5305\u542b\u96f6\u4e2a\u6216\u591a\u4e2a\u6761\u76ee\u3002 \u6bcf\u4e2a\u6761\u76ee\uff08entry\uff09\u90fd\u6709\u552f\u4e00\u7684\u952e\u548c\u5b83\u6240\u5bf9\u5e94\u7684\u503c\u76f8\u5173\u8054\u3002 \u952e\u901a\u5e38\u662f\u5b57\u7b26\u4e32\u6216\u6574\u6570\uff0c\u800c\u503c\u662f\u4efb\u610f\u7684Python\u5bf9\u8c61\u3002 \u4e0b\u6807\u8fd0\u7b97\u7b26\u53ef\u4ee5\u7528\u4e8e\u8bbf\u95ee\u4e00\u4e2a\u7ed9\u5b9a\u952e\u7684\u503c\uff0c\u7ed9\u4e00\u4e2a\u65b0\u952e\u6dfb\u52a0\u4e00\u4e2a\u503c\uff0c\u4ee5\u53ca\u66ff\u6362\u7ed9\u5b9a\u952e\u7684\u503c\u3002 pop \u65b9\u6cd5\u4f1a\u5220\u9664\u4e00\u4e2a\u6761\u76ee\u5e76\u8fd4\u56de\u7ed9\u5b9a\u952e\u6240\u5bf9\u5e94\u7684\u503c\u3002 keys \u65b9\u6cd5\u4f1a\u628a\u6240\u6709\u952e\u8fd4\u56de\u6210\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 values \u65b9\u6cd5\u4f1a\u628a\u6240\u6709\u503c\u8fd4\u56de\u6210\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 \u793a\u4f8b\uff1a {} # \u7a7a\u5b57\u5178 { \"name\" : \"Ken\" } # \u542b\u4e00\u4e2a\u6761\u76ee { \"name\" : \"Ken\" , \"age\" : 67 } # \u542b\u4e8c\u4e2a\u6761\u76ee { \"hobbies\" :[ \"reading\" , \"running\" ]} # \u542b\u4e00\u4e2a\u6761\u76ee\uff0c\u5176\u4e2d\u503c\u662f\u4e00\u4e2a\u5217\u8868 \u5b57\u5178\u672c\u8eab\u4e5f\u662f\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002\u53ef\u4ee5\u901a\u8fc7for\u8bed\u53e5\u8fdb\u884c\u904d\u5386\u952e\u6216/\u548c\u503c\u3002 myDict = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } for keys in myDict : print ( keys , myDict [ keys ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # name Ming # id 1001 # age 35 1.4.5.\u503c\u68c0\u7d22 \u00b6 \u53ef\u4ee5\u5728\u5b57\u7b26\u4e32\u5217\u8868\u3001\u5143\u7ec4\u6216\u5b57\u5178\u91cc\u901a\u8fc7 in \u8fd0\u7b97\u7b26\u6765\u5bf9\u503c\u6216\u591a\u9879\u96c6\u8fdb\u884c\u641c\u7d22\uff0c\u8fd4\u56de True \u6216 False \u3002\u5bf9\u4e8e\u5b57\u5178\u6765\u8bf4\uff0c\u641c\u7d22\u7684\u76ee\u6807\u503c\u5e94\u8be5\u662f\u4e00\u4e2a\u952e\u3002 \u5982\u679c\u5df2\u77e5\u7ed9\u5b9a\u503c\u5b58\u5728\u4e8e\u5e8f\u5217\uff08\u5b57\u7b26\u4e32\u3001\u5217\u8868\u6216\u5143\u7ec4\uff09\u91cc\uff0c\u90a3\u4e48 index \u65b9\u6cd5\u5c06\u8fd4\u56de\u8fd9\u4e2a\u503c\u6240\u51fa\u73b0\u7684\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3002 \u5217\u8868\u68c0\u7d22\uff1a myString = \"I love Python\" myList = myString . split () print ( myList ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ['I', 'love', 'Python'] print ( myList . index ( 'love' )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 1 \u5143\u7ec4\u68c0\u7d22\uff1a myString = \"I love Python\" myList = myString . split () myTuple = tuple ( myList ) print ( myTuple ) print ( myTuple . index ( 'love' )) \u5b57\u5178\u68c0\u7d22\uff1a myDict = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } print ( myDict ) for keys in myDict : print ( keys , myDict [ keys ]) myDict . pop ( 'city' ) # \u62a5\u9519\uff0cKeyError: 'city' myDict . pop ( 'id' ) print ( myDict ) # \u8fd0\u884c\u7ed3\u679c\uff1a{'name': 'Ming', 'age': 35} 1.4.6.\u6a21\u5f0f\u5339\u914d\u8bbf\u95ee\u591a\u9879\u96c6 \u00b6 \u4e0b\u6807\u8fd0\u7b97\u7b26\u53ef\u4ee5\u7528\u6765\u8bbf\u95ee\u5217\u8868\u3001\u5143\u7ec4\u548c\u5b57\u5178\u91cc\u7684\u5143\u7d20\u3002 \u901a\u8fc7\u6a21\u5f0f\u5339\u914d\u53ef\u4ee5\u4e00\u6b21\u8bbf\u95ee\u591a\u4e2a\u5143\u7d20\u3002 \u793a\u4f8b\uff1a myTuple \u662f\u4e00\u4e2a\u542b\u5185\u5d4c\u5143\u7ec4\u7684\u5143\u7ec4\u3002 myTuple = (( 'r' , 'g' , 'b' ), 'hexString' ) print ( myTuple ) # \u8fd0\u884c\u7ed3\u679c\uff1a # (('r', 'g', 'b'), 'hexString') print ( myTuple [ 0 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # ('r', 'g', 'b') print ( myTuple [ 0 ][ 0 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # r print ( myTuple [ 0 ][ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # g print ( myTuple [ 0 ][ 2 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # b print ( myTuple [ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # hexString \u901a\u8fc7\u4e0a\u9762\u7684\u62c6\u89e3\uff0c\u6211\u4eec\u6e05\u695a\u4e86\u5185\u5d4c\u5143\u7ec4\u7684\u7ed3\u6784\u8be6\u7ec6\u60c5\u51b5\u3002 \u4e0b\u9762\uff0c\u6211\u4eec\u901a\u8fc7\u6a21\u5f0f\u5339\u914d\uff0c\u628a\u4e00\u4e2a\u7ed3\u6784\u5206\u914d\u7ed9\u5f62\u5f0f\u5b8c\u5168\u76f8\u540c\u7684\u53e6\u4e00\u4e2a\u7ed3\u6784\u3002\u8fd9\u91cc\u76ee\u6807\u7ed3\u6784 newTuple \u6240\u5305\u542b\u7684\u53d8\u91cf\u4ece\u6e90\u7ed3\u6784 (('r', 'g', 'b'), 'hexString') \u91cc\u7684\u76f8\u5e94\u4f4d\u7f6e\u5904\u83b7\u5f97\u5bf9\u5e94\u7684\u503c\u3002 newTuple = (( 'r' , 'g' , 'b' ), 'hexString' ) print ( newTuple [ 0 ]) # ('r', 'g', 'b') print ( newTuple [ 0 ][ 0 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # r print ( newTuple [ 0 ][ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # g print ( newTuple [ 0 ][ 2 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # b print ( newTuple [ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # hexString 1.5.\u521b\u5efa\u51fd\u6570 \u00b6 Python\u652f\u6301\u5b8c\u5168\u51fd\u6570\u5f0f\u7f16\u7a0b\u8bbe\u8ba1\u3002 Python\u5305\u542b\u5f88\u591a\u5185\u7f6e\u51fd\u6570\u3002 Python\u4e5f\u8fd0\u884c\u521b\u5efa\u65b0\u51fd\u6570\uff0c\u53ef\u4ee5\u4f7f\u7528\u9012\u5f52\uff0c\u628a\u51fd\u6570\u4f5c\u4e3a\u6570\u636e\u8fdb\u884c\u4f20\u9012\u548c\u8fd4\u56de\u3002 1.5.1.\u51fd\u6570\u5b9a\u4e49 \u00b6 \u51fd\u6570\u5b9a\u4e49\u8bed\u6cd5\uff1a \u547d\u540d\u51fd\u6570\u540d\u79f0\u548c\u53c2\u6570\u540d\u79f0\u7684\u89c4\u5219\u4e0e\u60ef\u4f8b\u4e0e\u547d\u540d\u53d8\u91cf\u7684\u662f\u76f8\u540c\u7684\u3002 \u5fc5\u9009\u53c2\u6570\u7684\u5217\u8868\u53ef\u4ee5\u4e3a\u7a7a\uff0c\u4e5f\u53ef\u4ee5\u5305\u542b\u7528\u9017\u53f7\u9694\u5f00\u7684\u540d\u79f0\u3002 \u4e0e\u5176\u4ed6\u7f16\u7a0b\u8bed\u8a00\u4e0d\u540c\u7684\u662f\uff0c\u53c2\u6570\u540d\u79f0\u6216\u51fd\u6570\u540d\u79f0\u672c\u8eab\u5e76\u4e0d\u4f1a\u548c\u6570\u636e\u7c7b\u578b\u8fdb\u884c\u5173\u8054\u3002 def < function name > ( < list of parameters > ): < sequence of statements > \u793a\u4f8b\uff1a \u5728\u51fd\u6570\u7684\u6807\u9898\u4e0b\u6709\u4e00\u884c\u7528\u4e09\u5f15\u53f7\u62ec\u8d77\u6765\u7684\u5b57\u7b26\u4e32 \u8fd4\u56den\u7684\u5e73\u65b9\u6570 \uff0c\u8fd9\u662f\u4e00\u4e2a\u6587\u6863\u5b57\u7b26\u4e32\uff08docstring\uff09\u3002 \u5728shell\u91cc\u9762\u8f93\u5165help(square)\u65f6\uff0c\u4f1a\u663e\u793a\u8fd9\u4e2a\u5b57\u7b26\u4e32\u3002 \u5b9a\u4e49\u7684\u6bcf\u4e00\u4e2a\u51fd\u6570\u90fd\u5e94\u8be5\u6709\u6587\u6863\u5b57\u7b26\u4e32\uff0c\u6765\u8bf4\u660e\u8be5\u51fd\u6570\u7684\u529f\u80fd\uff0c\u5e76\u63d0\u4f9b\u76f8\u5173\u7684\u6240\u6709\u53c2\u6570\u4ee5\u53ca\u8fd4\u56de\u503c\u7684\u4fe1\u606f\u3002 \u51fd\u6570\u7684\u53c2\u6570\u548c\u4e34\u65f6\u53d8\u91cf\u53ea\u4f1a\u5728\u51fd\u6570\u8c03\u7528\u7684\u751f\u5b58\u5468\u671f\u5185\u5b58\u5728\uff0c\u5e76\u4e14\u5bf9\u5176\u4ed6\u51fd\u6570\u53ca\u5176\u5916\u56f4\u7a0b\u5e8f\u90fd\u662f\u4e0d\u53ef\u89c1\u7684\u3002 n \u662f\u53c2\u6570\u3002 result \u662f\u4e34\u65f6\u53d8\u91cf\u3002 \u5982\u679c\u51fd\u6570\u4e0d\u5305\u542b return \u8bed\u53e5\u65f6\uff0c\u5b83\u5c06\u5728\u6700\u540e\u4e00\u6761\u8bed\u53e5\u6267\u884c\u4e4b\u540e\u81ea\u52a8\u8fd4\u56de None \u503c\u3002 \u7528 = \u628a\u53c2\u6570\u6307\u5b9a\u4e3a\u6709\u9ed8\u8ba4\u503c\u7684\u53ef\u9009\u53c2\u6570\u3002 \u5728\u53c2\u6570\u5217\u8868\u4e2d\uff0c\u5fc5\u9009\u53c2\u6570\uff08\u6ca1\u6709\u9ed8\u8ba4\u503c\u7684\u53c2\u6570\uff09\u5fc5\u987b\u4f4d\u4e8e\u53ef\u9009\u53c2\u6570\u4e4b\u524d\u3002 def square ( n ): \"\"\"\u8fd4\u56den\u7684\u5e73\u65b9\u6570\"\"\" result = n ** 2 return result print ( square ( 5 )) 1.5.2.\u51fd\u6570\u9012\u5f52 \u00b6 \u9012\u5f52\u51fd\u6570\uff08recursive function\uff09\u662f\u6307\u4f1a\u8c03\u7528\u81ea\u8eab\u7684\u51fd\u6570\u3002 \u4e3a\u4e86\u9632\u6b62\u51fd\u6570\u65e0\u9650\u5730\u91cd\u590d\u8c03\u7528\u81ea\u8eab\uff0c\u4ee3\u7801\u4e2d\u5fc5\u987b\u81f3\u5c11\u6709\u4e00\u6761\u7528\u6765\u67e5\u9a8c\u6761\u4ef6\u7684\u9009\u62e9\u8bed\u53e5\uff0c\u7528\u4e8e\u786e\u5b9a\u63a5\u4e0b\u6765\u8981\u7ee7\u7eed\u9012\u5f52\u8fd8\u662f\u505c\u6b62\u9012\u5f52\u3002\u8fd9\u4e2a\u68c0\u67e5\u6761\u4ef6\u8bed\u53e5\u79f0\u4e3a\u57fa\u672c\u60c5\u51b5\uff08base case\uff09\u3002 \u793a\u4f8b\uff1a\u4e0b\u9762\u662f\u901a\u8fc7\u5faa\u73af\u5b9e\u73b0\u8f93\u51fa\u4ece\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u548c\u3002 def mySum ( lower , upper ): \"\"\"\u5bf9\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u6c42\u548c; lower:\u6700\u5c0f\u503c; upper:\u6700\u5927\u503c;\"\"\" result = 0 while ( lower <= upper ): result = result + lower lower += 1 return result print ( mySum ( 1 , 10 )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 55 \u7528\u9012\u5f52\u51fd\u6570\u6539\u5199\u4e0a\u8ff0\u51fd\u6570\u3002 def mySum ( lower , upper ): \"\"\"\u5bf9\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u6c42\u548c; lower:\u6700\u5c0f\u503c; upper:\u6700\u5927\u503c;\"\"\" if lower <= upper : return lower + mySum ( lower + 1 , upper ) else : return 0 print ( mySum ( 1 , 10 )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 55 \u901a\u5e38\u6765\u8bf4\uff0c\u9012\u5f52\u51fd\u6570\u81f3\u5c11\u6709\u4e00\u4e2a\u53c2\u6570\u3002 \u8fd9\u4e2a\u53c2\u6570\u7684\u503c\u4f1a\u88ab\u7528\u6765\u5bf9\u9012\u5f52\u8fc7\u7a0b\u7684\u57fa\u672c\u60c5\u51b5\u8fdb\u884c\u5224\u5b9a\uff0c\u4ece\u800c\u51b3\u5b9a\u662f\u5426\u8981\u7ed3\u675f\u6574\u4e2a\u8c03\u7528\u3002 \u5728\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u4e4b\u524d\uff0c\u8fd9\u4e2a\u503c\u4e5f\u4f1a\u88ab\u8fdb\u884c\u67d0\u79cd\u65b9\u5f0f\u7684\u4fee\u6539\u3002 \u6bcf\u6b21\u5bf9\u8fd9\u4e2a\u503c\u7684\u4fee\u6539\uff0c\u90fd\u5e94\u8be5\u4ea7\u751f\u4e00\u4e2a\u65b0\u6570\u636e\u503c\uff0c\u53ef\u4ee5\u8ba9\u51fd\u6570\u6700\u7ec8\u8fbe\u5230\u57fa\u672c\u60c5\u51b5\u3002 \u4e3a\u4e86\u5bf9 mySum \u51fd\u6570\u7684\u9012\u5f52\u8fdb\u884c\u8ddf\u8e2a\uff0c\u53ef\u4ee5\u5c1d\u8bd5\u6dfb\u52a0\u4e00\u4e2a\u4ee3\u8868\u7f29\u8fdb\u8fb9\u8ddd\u7684\u53c2\u6570\u5e76\u4e14\u6dfb\u52a0\u4e00\u4e9bprint\u8bed\u53e5\u3002\u8fd9\u6837\u5728\u6bcf\u6b21\u8c03\u7528\u65f6\uff0c\u51fd\u6570\u7684\u7b2c\u4e00\u6761\u8bed\u53e5\u4f1a\u8ba1\u7b97\u7f29\u8fdb\u6570\u91cf\uff0c\u7136\u540e\u518d\u6253\u5370\u4e24\u4e2a\u53c2\u6570\u7684\u503c\uff0c\u6bcf\u6b21\u8fd4\u56de\u8c03\u7528\u4e4b\u524d\u7684\u8fd4\u56de\u503c\u65f6\u90fd\u4f7f\u7528\u76f8\u540c\u7684\u7f29\u8fdb\uff0c\u5c31\u53ef\u4ee5\u5b9e\u73b0\u5bf9\u4e24\u4e2a\u53c2\u6570\u7684\u503c\u4ee5\u53ca\u6bcf\u6b21\u8c03\u7528\u7684\u8fd4\u56de\u503c\u8fdb\u884c\u8ddf\u8e2a\u3002 def mySum ( lower , upper , margin = 0 ): \"\"\"\u5bf9\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u6c42\u548c\uff0c\u901a\u8fc7\u9636\u68af\u65b9\u5f0f\u8f93\u51fa; lower:\u6700\u5c0f\u503c; upper:\u6700\u5927\u503c;\"\"\" blanks = \" \" * margin print ( blanks , lower , upper ) if lower <= upper : result = lower + mySum ( lower + 1 , upper , margin + 4 ) print ( blanks , result ) return result else : print ( blanks , 0 ) return 0 print ( mySum ( 1 , 5 )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 1 5 # 2 5 # 3 5 # 4 5 # 5 5 # 6 5 # 0 # 5 # 9 # 12 # 14 # 15 # 15 1.5.3.\u51fd\u6570\u5d4c\u5957 \u00b6 \u5d4c\u5957\u51fd\u6570\u7c7b\u4f3c\u4e8e\u5d4c\u5957\u5faa\u73af\uff0c\u5c31\u662f\u51fd\u6570\u5185\u53c8\u5d4c\u5957\u7740\u51fd\u6570\u3002\u5373\uff0c\u51fd\u6570\u7684\u5b9a\u4e49\u5d4c\u5957\u5728\u4e00\u4e2a\u51fd\u6570\u7684\u8bed\u53e5\u5e8f\u5217\u91cc\u3002 \u5148\u770b\u4e00\u4e2a\u666e\u901a\u4f8b\u5b50\uff1a # \u5b9a\u4e49inner\u51fd\u6570 def inner (): print ( '\u6211\u662finner' ) # \u5b9a\u4e49outer\u51fd\u6570\uff0couter\u51fd\u6570\u8c03\u7528inner\u51fd\u6570 def outer (): print ( '\u6211\u662fouter' ) inner () outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter # \u6211\u662finner \u6539\u5199\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u628a inner \u51fd\u6570\u5199\u5728 outer \u51fd\u6570\u91cc\u9762\u3002 # \u5b9a\u4e49outer\u51fd\u6570\uff0couter\u51fd\u6570\u5185\u5d4cinner\u51fd\u6570\uff0c\u5e76\u8c03\u7528inner\u51fd\u6570 def outer (): print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): print ( '\u6211\u662finner' ) inner () outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter # \u6211\u662finner \u4e0a\u9762\u7684\u5916\u5c42 outer \u51fd\u6570\u548c\u5185\u5c42 inner \u51fd\u6570\u90fd\u6ca1\u6709\u53d8\u91cf\u548c\u53c2\u6570\u3002 \u73b0\u5728\u4fee\u6539\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u6211\u4eec\u4f20\u5165\u53c2\u6570\u548c\u53d8\u91cf\uff0c\u7136\u540e\u628a\u5916\u5c42\u51fd\u6570\u8fd4\u56de\u503c\u6307\u5411\u5185\u5c42\u51fd\u6570\u540d\u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) # \u8fd4\u56de\u5185\u5c42inner\u51fd\u6570\u540d return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662finner # inner\u6253\u5370: 1 \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff1a f = outer() \u8c03\u7528\u5916\u5c42 outer \u51fd\u6570\uff0c\u5e76\u628a\u7ed3\u679c\u8d4b\u503c\u7ed9 f \u3002\u6ce8\u610f\uff0cinner\u51fd\u6570\u5e76\u6ca1\u6709\u88ab\u6267\u884c\u3002 f \u5176\u5b9e\u5c31\u662f inner \uff0c\u6307\u5411 inner \u7684\u5185\u5b58\u7a7a\u95f4\u3002\u901a\u8fc7 f() \u9a8c\u8bc1\u4e86\u8fd9\u4e00\u70b9\uff0c outer \u51fd\u6570\u4e2d\u7684\u53d8\u91cf a \u88ab\u6253\u5370\u51fa\u6765\u4e86\u3002 \u4e0a\u9762\u4f8b\u5b50\u4e2d outer \u5c31\u662f\u95ed\u5305\u51fd\u6570\uff0c\u5916\u5c42\u51fd\u6570\u7684\u53d8\u91cf\u53ef\u4ee5\u88ab\u5185\u5c42\u51fd\u6570\u8c03\u7528\uff0c\u7c7b\u4f3c\u4e8e\u5c01\u88c5\u7684\u6548\u679c\u3002\u5185\u5c42\u51fd\u6570\u4e0d\u4f1a\u7acb\u523b\u88ab\u6267\u884c\uff0c\u5f53\u518d\u6b21\u8c03\u7528\u65f6\uff0c\u5185\u5c42\u51fd\u6570\u624d\u4f1a\u6267\u884c\u3002 \u95ed\u5305\u51fd\u6570\u9700\u8981\u6709\u4e09\u4e2a\u6761\u4ef6\uff1a \u5fc5\u987b\u6709\u4e00\u4e2a\u5185\u5d4c\u51fd\u6570\uff0c\u4f8b\u5982\u51fd\u6570 inner \uff1b \u5185\u90e8\u51fd\u6570\u5f15\u7528\u5916\u90e8\u51fd\u6570\u53d8\u91cf\uff0c\u4f8b\u5982\u53d8\u91cf a \uff1b \u5916\u90e8\u51fd\u6570\u5fc5\u987b\u8fd4\u56de\u5185\u5d4c\u51fd\u6570\uff0c\u4f8b\u5982 outer \u51fd\u6570\u4e2d\u7684 return inner \uff1b \u5bf9\u4e0a\u9762\u7684\u4ee3\u7801\u518d\u8fdb\u884c\u4fee\u6539\uff0c\u5728 inner \u51fd\u6570\u4e2d\u518d\u6dfb\u52a0\u4e00\u4e2a\u540c\u540d\u7684\u53d8\u91cfa\u3002\u4ece\u7ed3\u679c\u53ef\u4ee5\u5f97\u51fa\u7ed3\u8bba\uff0c inner \u51fd\u6570\u4f18\u5148\u5728\u5185\u90e8\u67e5\u627e\u53d8\u91cf a=5 \u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): a = 5 print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662finner # inner\u6253\u5370: 5 \u7ed3\u8bba\uff1a\u5185\u5c42\u51fd\u6570\u4e2d\u8c03\u7528\u7684\u53d8\u91cf\uff1a \u9996\u5148\u4f1a\u4ece\u5185\u5c42\u51fd\u6570\u4e2d\u627e\uff0c \u627e\u4e0d\u5230\u5c31\u53bb\u5916\u5c42\u51fd\u6570\u4e2d\u627e\uff0c \u518d\u627e\u4e0d\u5230\u5c31\u5230\u51fd\u6570\u5916\u4e2d\u627e\uff0c \u518d\u627e\u4e0d\u5230\u5c31\u5230\u5185\u7f6e\u7684\u6a21\u5757\u4e2d\u627e\uff0c \u518d\u627e\u4e0d\u5230\uff0c\u5c31\u62a5\u9519\u3002 \u8fd9\u5c31\u662f\u4f5c\u7528\u57df\u7684\u6982\u5ff5\u3002 \u7ee7\u7eed\u4fee\u6539\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u5728 inner \u51fd\u6570\u4e2d\u4fee\u6539 outer \u51fd\u6570\u4e2d\u53d8\u91cf a \u7684\u503c\uff0c\u8fd0\u884c\u7ed3\u679c\u62a5\u9519\u3002\u7ed3\u8bba\uff1a\u5185\u5c42\u51fd\u6570\u4e0d\u80fd\u4fee\u6539\u5916\u5c42\u51fd\u6570\u7684\u53d8\u91cf\u503c\u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): a += 5 print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # UnboundLocalError: local variable 'a' referenced before assignment \u4fee\u6b63\u4e0a\u9762\u7684\u4ee3\u7801\u3002\u5728 inner \u51fd\u6570\u4e2d\u5bf9\u53d8\u91cfa\u6dfb\u52a0\u4e00\u4e2a nonlocal \u7684\u58f0\u660e\uff0c\u5c31\u53ef\u4ee5\u5728 inner \u51fd\u6570\u4e2d\u4fee\u6539\u5916\u5c42outer\u51fd\u6570\u7684\u53d8\u91cf a \u7684\u503c\u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): nonlocal a a += 5 print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662finner # inner\u6253\u5370: 6 \u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u662f\u9636\u4e58\uff08factorial\uff09\u9012\u5f52\u51fd\u6570\u7684\u4e24\u4e2a\u4e0d\u540c\u7684\u5b9a\u4e49\u3002 \u7b2c\u4e00\u4e2a\u5b9a\u4e49\u4f7f\u7528\u4e86\u5d4c\u5957\u7684\u8f85\u52a9\u51fd\u6570 recurse \u6765\u5bf9\u6240\u9700\u8981\u7684\u53c2\u6570\u8fdb\u884c\u9012\u5f52\uff1b\u8fd9\u91cc\u7684 factorial \u51fd\u6570\u5c31\u662f\u95ed\u5305\u51fd\u6570\u3002 \u7b2c\u4e00\u6b65\uff1a\u7b2c\u4e00\u6b21\u8c03\u7528 factorial() \u51fd\u6570\uff0c\u5373 n=5 \uff1b \u7b2c\u4e8c\u6b65\uff1a\u7b2c\u4e00\u6b21\u8c03\u7528\u5185\u5c42\u51fd\u6570 recurse() \uff0c\u4f46\u4e0d\u4f1a\u7acb\u523b\u88ab\u6267\u884c\uff1b \u7b2c\u4e09\u6b65\uff0c\u6267\u884c return recurse(5, 1) \uff0c\u5bf9\u53c2\u6570 product \u521d\u59cb\u5316\u8d4b\u503c 1 \u7b2c\u56db\u6b65\uff1a\u6267\u884c return recurse(5, 5 * 1) \uff0c\u6b64\u65f6 n=5 \uff0c product=1 \u3002 \u7b2c\u4e94\u6b65\uff1a\u6267\u884c return recurse(4, 4 * 5) \uff0c\u6b64\u65f6 n=4 \uff0c product=5 \u3002 \u7b2c\u516d\u6b65\uff1a\u6267\u884c return recurse(3, 3 * 20) \uff0c\u6b64\u65f6 n=3 \uff0c product=20 \u3002 \u7b2c\u4e03\u6b65\uff1a\u6267\u884c return recurse(2, 2 * 60) \uff0c\u6b64\u65f6 n=2 \uff0c product=60 \u3002 \u7b2c\u516b\u6b65\uff1a\u6267\u884c return recurse(1, 1 * 120) \uff0c\u6b64\u65f6 n=1 \uff0c product=120 \u3002 \u7b2c\u4e5d\u6b65\uff1a\u6b64\u65f6 n=1 \uff0c\u6267\u884c return product \uff0c\u5373 return 120 \uff0c\u7ed3\u675f\u3002 \u7b2c\u4e8c\u4e2a\u5b9a\u4e49\u5219\u662f\u4e3a\u7b2c\u4e8c\u4e2a\u53c2\u6570\u63d0\u4f9b\u4e86\u9ed8\u8ba4\u503c\uff0c\u4ece\u800c\u7b80\u5316\u4e86\u8bbe\u8ba1\u3002 # \u7b2c\u4e00\u4e2a\u5b9a\u4e49 def factorial ( n ): \"\"\"\u8fd4\u56de n \u7684\u9636\u4e58\"\"\" def recurse ( n , product ): \"\"\"\u8ba1\u7b97\u9636\u4e58\u7684\u5e2e\u52a9\u5668\"\"\" print ( n , product ) # \u63d2\u5165\u8fd9\u4e00\u53e5\u662f\u4e3a\u4e86\u80fd\u770b\u6e05\u695a\u6bcf\u4e00\u6b21\u9012\u5f52\u8c03\u7528\u7684n\u548cproduct\u53d8\u5316 if n == 1 : return product else : return recurse ( n - 1 , n * product ) return recurse ( n , 1 ) f = factorial ( 5 ) # \u8fd0\u884c\u7ed3\u679c 5 1 4 5 3 20 2 60 1 120 # \u7b2c\u4e8c\u4e2a\u5b9a\u4e49 def factorial ( n , product = 1 ): \"\"\"\u8fd4\u56de n \u7684\u9636\u4e58\"\"\" if n == 1 : return product else : return factorial ( n - 1 , n * product ) print ( factorial ( 5 )) # \u8fd0\u884c\u7ed3\u679c # 120 1.5.4.\u9ad8\u9636\u51fd\u6570 \u00b6 \u51fd\u6570\u672c\u8eab\u4e5f\u662f\u4e00\u79cd\u72ec\u7279\u7684\u6570\u636e\u5bf9\u8c61\u3002\u53ef\u4ee5\u628a\u5b83\u4eec\u8d4b\u7ed9\u53d8\u91cf\u3001\u5b58\u50a8\u5728\u6570\u636e\u7ed3\u6784\u91cc\u3001\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7ed9\u5176\u4ed6\u51fd\u6570\u4ee5\u53ca\u4f5c\u4e3a\u5176\u4ed6\u51fd\u6570\u7684\u503c\u8fd4\u56de\u3002 \u9ad8\u9636\u51fd\u6570\uff08higher-order function\uff09\uff1a\u5b83\u63a5\u6536\u53e6\u4e00\u4e2a\u51fd\u6570\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u4e14\u4ee5\u67d0\u79cd\u65b9\u5f0f\u5e94\u7528\u8be5\u51fd\u6570\u3002 Python\u6709\u4e24\u4e2a\u5185\u7f6e\u7684\u9ad8\u9636\u51fd\u6570\uff0c\u5206\u522b\u662f map \u548c filter \uff0c\u5b83\u4eec\u53ef\u4ee5\u7528\u4e8e\u5904\u7406\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 map \u51fd\u6570\u4f1a\u63a5\u6536\u53e6\u4e00\u4e2a\u51fd\u6570\u548c\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\uff0c\u8fd4\u56de\u53e6\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002\u8fd9\u4e2a\u51fd\u6570\u4f1a\u628a\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7684\u51fd\u6570\u5e94\u7528\u5728\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\u7684\u6bcf\u4e2a\u5143\u7d20\u4e0a\u3002\u7b80\u5355\u6765\u8bf4\uff0c map \u51fd\u6570\u4f1a\u5bf9\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\u7684\u6bcf\u4e2a\u5143\u7d20\u8fdb\u884c\u8f6c\u6362\u3002 filter \u4f1a\u63a5\u53d7\u4e00\u4e2a\u5e03\u5c14\u51fd\u6570\u548c\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\uff0c\u8fd4\u56de\u8fd9\u6837\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff0c\u5b83\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u90fd\u4f1a\u88ab\u4f20\u9012\u7ed9\u5e03\u5c14\u51fd\u6570\uff0c\u5982\u679c\u8fd9\u4e2a\u51fd\u6570\u8fd4\u56deTrue\uff0c\u90a3\u4e48\u8fd9\u4e2a\u5143\u7d20\u5c06\u88ab\u4fdd\u7559\u5728\u8fd4\u56de\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\uff1b\u5426\u5219\uff0c\u8fd9\u4e2a\u5143\u7d20\u5c06\u88ab\u5220\u9664\u3002\u7b80\u5355\u8bf4\uff0c filter \u51fd\u6570\u4f1a\u628a\u6240\u6709\u80fd\u591f\u901a\u8fc7\u68c0\u9a8c\u7684\u5143\u7d20\u4fdd\u7559\u5728\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\u3002 functools.reduce \u901a\u8fc7\u628a\u63a5\u6536\u4e24\u4e2a\u53c2\u6570\u7684\u51fd\u6570\u7684\u7ed3\u679c\u4ee5\u53ca\u8fed\u4ee3\u5bf9\u8c61\u7684\u4e0b\u4e00\u4e2a\u5143\u7d20\u518d\u6b21\u5e94\u7528\u4e8e\u8fd9\u4e2a\u63a5\u6536\u4e24\u4e2a\u53c2\u6570\u7684\u51fd\u6570\uff0c\u6765\u628a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u8ba1\u7b97\u6210\u5355\u4e00\u7684\u503c\u3002 \u793a\u4f8b\uff1a\u628a\u4e00\u4e2a\u6574\u6570\u5217\u8868\u8f6c\u6362\u6210\u53e6\u4e00\u4e2a\u5305\u542b\u8fd9\u4e9b\u6574\u6570\u7684\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\u5217\u8868\u3002 \u4f20\u7edf\u65b9\u6cd5\u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] for i in oldList : newList . append ( str ( i )) print ( newList ) # ['0', '1', '3', '5', '7', '9'] \u7528 map \u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] newList = list ( map ( str , oldList )) print ( newList ) # ['0', '1', '3', '5', '7', '9'] \u62d3\u5c55\uff1a\u628a\u4e00\u4e2a\u6574\u6570\u5217\u8868\u4e2d\u7684\u6b63\u6574\u6570\u8f6c\u6362\u6210\u53e6\u4e00\u4e2a\u5305\u542b\u8fd9\u4e9b\u6574\u6570\u7684\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\u5217\u8868\u3002 \u4f20\u7edf\u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] for i in oldList : if i > 0 : newList . append (( str ( i ))) print ( newList ) # ['1', '3', '5', '7', '9'] \u4f7f\u7528 filter \u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] def isPositive ( n ): if n > 0 : return True # \u521b\u5efa\u4e00\u4e2a\u4e0d\u5305\u542b\u4efb\u4f55\u96f6\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61 newList = list ( filter ( isPositive , oldList )) print ( newList ) # [1, 3, 5, 7, 9] \u793a\u4f8b\uff1a\u8ba1\u7b97\u4ece1\u523010\u7684\u4e58\u79ef\u5e76\u8f93\u51fa\u7ed3\u679c\u3002 \u901a\u8fc7 for \u5faa\u73af\u5b9e\u73b0\uff1a result = 1 value = 1 for value in range ( 1 , 11 ): result *= value value += 1 print ( result ) # \u8fd0\u884c\u7ed3\u679c # 3628800 \u901a\u8fc7 functools.reduce \u5faa\u73af\u5b9e\u73b0\uff1a import functools result = functools . reduce ( lambda x , y : x * y , range ( 1 , 11 )) print ( result ) # 3628800 1.5.5.lambda\u4e0e\u533f\u540d\u51fd\u6570 \u00b6 \u8bed\u6cd5\u683c\u5f0f\uff1a lambda < argument list > : < expression > lambda\u8868\u8fbe\u5f0f\u4e0d\u80fd\u50cf\u5176\u4ed6Python\u51fd\u6570\u90a3\u6837\u5305\u542b\u4e00\u6574\u4e2a\u8bed\u53e5\u5e8f\u5217\u3002 \u62d3\u5c55\uff1a\u7528lambda\u5b9e\u73b0\u628a\u4e00\u4e2a\u6574\u6570\u5217\u8868\u4e2d\u7684\u6b63\u6574\u6570\u8f6c\u6362\u6210\u53e6\u4e00\u4e2a\u5305\u542b\u8fd9\u4e9b\u6574\u6570\u7684\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\u5217\u8868\uff0c\u5b9e\u9645\u5c31\u662f\u901a\u8fc7\u4f7f\u7528\u533f\u540d\u7684\u5e03\u5c14\u51fd\u6570\u6765\u4ece\u6574\u6570\u5217\u8868\u91cc\u5254\u9664\u6240\u6709\u4e3a\u96f6\u7684\u5143\u7d20\u3002 oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] newList = list ( filter ( lambda i : i > 0 , oldList )) print ( newList ) # [1, 3, 5, 7, 9] 1.6.\u6355\u83b7\u5f02\u5e38 \u00b6 \u8003\u8651\u4e24\u79cd\u5f02\u5e38\u60c5\u51b5\uff1a Python\u865a\u62df\u673a\u5728\u7a0b\u5e8f\u6267\u884c\u671f\u95f4\u9047\u5230\u4e86\u8bed\u4e49\u9519\u8bef\uff0c\u5219\u4f1a\u5f97\u5230\u76f8\u5e94\u7684\u9519\u8bef\u6d88\u606f\uff0c\u4ece\u800c\u5f15\u53d1\u4e00\u4e2a\u5f02\u5e38\u5e76\u4e14\u6682\u505c\u7a0b\u5e8f\u3002\u8bed\u4e49\u9519\u8bef\u5305\u62ec\u4f8b\u5982\u672a\u5b9a\u4e49\u7684\u53d8\u91cf\u540d\u3001\u9664\u4ee50\u4ee5\u53ca\u8d85\u51fa\u5217\u8868\u8303\u56f4\u7684\u7d22\u5f15\u7b49\u3002 \u7528\u6237\u5f15\u8d77\u7684\u67d0\u4e9b\u9519\u8bef\uff0c\u4f8b\u5982\uff0c\u671f\u671b\u8f93\u5165\u6570\u5b57\u7684\u65f6\u5019\u8f93\u5165\u4e86\u5176\u4ed6\u5b57\u7b26\u3002\u5bf9\u4e8e\u5728\u8fd9\u4e9b\u60c5\u51b5\u4e0b\u4ea7\u751f\u7684\u5f02\u5e38\uff0c\u7a0b\u5e8f\u4e0d\u5e94\u8be5\u505c\u6b62\u6267\u884c\uff0c\u800c\u5e94\u8be5\u5bf9\u8fd9\u4e9b\u5f02\u5e38\u8fdb\u884c\u6355\u83b7\uff0c\u5e76\u4e14\u5141\u8bb8\u7528\u6237\u4fee\u6b63\u9519\u8bef\u3002 Python\u63d0\u4f9b\u4e86try-except\u8bed\u53e5\uff0c\u53ef\u4ee5\u8ba9\u7a0b\u5e8f\u6355\u83b7\u5f02\u5e38\u5e76\u6267\u884c\u76f8\u5e94\u7684\u6062\u590d\u64cd\u4f5c\u3002 try \u5b50\u53e5\u4e2d\u7684\u8bed\u53e5\u5c06\u5148\u88ab\u6267\u884c\u3002\u5982\u679c\u8fd9\u4e9b\u8bed\u53e5\u4e2d\u7684\u4e00\u6761\u5f15\u53d1\u4e86\u5f02\u5e38\uff0c\u90a3\u4e48\u63a7\u5236\u6743\u4f1a\u7acb\u5373\u8f6c\u79fb\u5230 except \u5b50\u53e5\u53bb\u3002 \u5982\u679c\u5f15\u53d1\u7684\u5f02\u5e38\u7c7b\u578b\u548c\u8fd9\u4e2a\u5b50\u53e5\u91cc\u7684\u7c7b\u578b\u4e00\u81f4\uff0c\u90a3\u4e48\u4f1a\u6267\u884c\u5b83\u91cc\u9762\u7684\u8bed\u53e5\uff1b \u5426\u5219\uff0c\u5c06\u8f6c\u79fb\u5230try-except\u8bed\u53e5\u7684\u8c03\u7528\u8005\uff0c\u5e76\u57fa\u4e8e\u8c03\u7528\u94fe\u5411\u4e0a\u4f20\u9012\uff0c\u76f4\u5230\u8fd9\u4e2a\u5f02\u5e38\u88ab\u6210\u529f\u6355\u83b7\uff0c\u6216\u8005\u662f\u7a0b\u5e8f\u56e0\u9519\u8bef\u6d88\u606f\u800c\u505c\u6b62\u6267\u884c\u3002 \u5982\u679c try \u5b50\u53e5\u91cc\u7684\u8bed\u53e5\u6ca1\u6709\u5f15\u53d1\u4efb\u4f55\u5f02\u5e38\uff0c\u90a3\u4e48\u4f1a\u8df3\u8fc7 except \u5b50\u53e5\u5e76\u7ee7\u7eed\u6267\u884c\uff0c\u76f4\u5230try-except\u8bed\u53e5\u7684\u672b\u5c3e\u3002 try : < statements > except < exception type > : < statements > \u901a\u5e38\u6765\u8bf4\uff0c \u5bf9\u4e8e\u5df2\u77e5\u53ef\u80fd\u4f1a\u53d1\u751f\u7684\u5f02\u5e38\u7c7b\u578b\uff0c\u5e94\u8be5\u5c3d\u53ef\u80fd\u5730\u5305\u62ec\u5728\u5728 except \u8bed\u53e5\u91cc\u3002 \u5982\u679c\u4e0d\u77e5\u9053\u5f02\u5e38\u7684\u7c7b\u578b\uff0c\u53ef\u4ee5\u5728 except \u4e2d\u7528\u66f4\u901a\u7528\u7684Exception\u7c7b\u578b\u5339\u914d\u53ef\u80fd\u4f1a\u5f15\u53d1\u7684\u4efb\u4f55\u5f02\u5e38\u3002 \u793a\u4f8b\uff1a def getYourAge ( prompt ): \"\"\"\u63d0\u793a\u7528\u6237\u8f93\u5165\u4e00\u4e2a\u6574\u6570\uff0c\u5426\u5219\u7ed9\u51fa\u9519\u8bef\u63d0\u793a\uff0c\u5e76\u7ee7\u7eed\u63d0\u793a\u7528\u6237\u8f93\u5165\u3002\"\"\" inputStr = input ( prompt ) try : number = int ( inputStr ) return number except ValueError : print ( \"Error in number format:\" , inputStr ) return getYourAge ( prompt ) if __name__ == \"__main__\" : age = getYourAge ( \"Enter your age: \" ) print ( \"Your age is\" , age ) # \u8fd0\u884c\u7ed3\u679c # Enter your age: 3a # Error in number format: 3a # Enter your age: 3.5 # Error in number format: 3.5 # Enter your age: 20 # Your age is 20 1.7.\u6587\u4ef6\u53ca\u5176\u64cd\u4f5c \u00b6 1.7.1.\u6587\u672c\u6587\u4ef6\u8bfb\u53d6 \u00b6 \u53ef\u4ee5\u628a\u6587\u672c\u6587\u4ef6\u91cc\u7684\u6570\u636e\u770b\u4f5c\u5b57\u7b26\u3001\u5355\u8bcd\u3001\u6570\u5b57\u6216\u8005\u82e5\u5e72\u884c\u6587\u672c\u3002 \u5982\u679c\u628a\u6587\u672c\u6587\u4ef6\u91cc\u7684\u6570\u636e\u5f53\u4f5c\u6574\u6570\u6216\u6d6e\u70b9\u6570\uff0c\u5c31\u5fc5\u987b\u7528\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u3001\u5236\u8868\u7b26\u548c\u6362\u884c\u7b26\uff09\u5c06\u5176\u5206\u9694\u5f00\u3002\u8f93\u51fa\u6216\u8f93\u5165\u5230\u6587\u672c\u6587\u4ef6\u7684\u6240\u6709\u6570\u636e\u5fc5\u987b\u662f\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\uff0c\u6240\u4ee5\u5728\u8f93\u5165/\u8f93\u51fa\u65f6\u9700\u8981\u505a\u76f8\u5e94\u7684\u7c7b\u578b\u8f6c\u6362\u3002 \u5982\u4e0b\u4f8b\uff1a 34.6 22.33 66.75 77.12 21.44 99.01 Python\u7684open\u51fd\u6570\u63a5\u6536\u4e0b\u9762\u4e24\u4e2a\u4e3b\u8981\u53c2\u6570\uff0c\u6253\u5f00\u4e00\u4e2a\u4e0e\u78c1\u76d8\u6587\u4ef6\u7684\u8fde\u63a5\u5e76\u4e14\u8fd4\u56de\u76f8\u5e94\u7684\u6587\u4ef6\u5bf9\u8c61\u3002 \u6587\u4ef6\u8def\u5f84\uff1b \u6253\u5f00\u6a21\u5f0f\uff1a \u6253\u5f00\u6a21\u5f0f\uff1a r \u8868\u793a\u6587\u4ef6\u53ea\u80fd\u8bfb\u53d6\uff1b w \u8868\u793a\u6587\u4ef6\u53ea\u80fd\u5199\u5165\uff1b a \u8868\u793a\u6253\u5f00\u6587\u4ef6\uff0c\u5728\u539f\u6709\u5185\u5bb9\u7684\u57fa\u7840\u4e0a\u8ffd\u52a0\u5185\u5bb9\uff0c\u5728\u672b\u5c3e\u5199\u5165\uff1b w+ \u8868\u793a\u53ef\u4ee5\u5bf9\u6587\u4ef6\u8fdb\u884c\u8bfb\u5199\u53cc\u91cd\u64cd\u4f5c\uff1b rb \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u53ea\u8bfb\uff1b wb \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u53ea\u5199\uff1b ab \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u8ffd\u52a0\uff1b wb+ \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u8bfb\u5199\uff1b \u793a\u4f8b\uff1a \u4e3a myfile.txt \u6587\u4ef6\u6253\u5f00\u4e00\u4e2a\u7528\u6765\u8f93\u51fa\u7684\u6587\u4ef6\u5bf9\u8c61\u3002 \u5b57\u7b26\u4e32\u6570\u636e\u901a\u8fc7 write \u65b9\u6cd5\u548c\u6587\u4ef6\u5bf9\u8c61\u5199\u5165\uff08\u6216\u8f93\u51fa\uff09\u5230\u6587\u4ef6\u91cc\u3002 \u8f6c\u4e49\u7b26 \\n \u5b9e\u73b0\u6362\u884c\u3002 \u4f7f\u7528 close \u65b9\u6cd5\u5173\u95ed\u6587\u4ef6\u3002\u5982\u679c\u6ca1\u6709\u5173\u95ed\u8f93\u51fa\u6587\u4ef6\uff0c\u5219\u53ef\u80fd\u5bfc\u81f4\u6570\u636e\u4e22\u5931\u3002 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) f . write ( \"First line. \\n Second line. \\n \" ) f . close () \u6587\u4ef6myfile.txt\u7684\u5185\u5bb9\uff1a First line. Second line. 1.7.2.\u6587\u672c\u6587\u4ef6\u5199\u5165 \u00b6 \u6587\u4ef6\u7684 write \u65b9\u6cd5\u63a5\u6536\u4e00\u4e2a\u5b57\u7b26\u4e32\u4f5c\u4e3a\u53c2\u6570\u3002\u56e0\u6b64\uff0c\u5176\u4ed6\u7c7b\u578b\u7684\u6570\u636e\uff08\u5982\u6574\u6570\u6216\u6d6e\u70b9\u6570\uff09\u5728\u5199\u5165\u8f93\u51fa\u6587\u4ef6\u4e4b\u524d\uff0c\u90fd\u5fc5\u987b\u5148\u88ab\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\u3002 \u5728Python\u91cc\uff0c\u53ef\u4ee5\u4f7f\u7528 str \u51fd\u6570\u628a\u7edd\u5927\u591a\u6570\u7684\u6570\u636e\u7c7b\u578b\u7684\u503c\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\uff0c\u4ee5\u7a7a\u683c\u6216\u6362\u884c\u7b26\u4f5c\u4e3a\u5206\u9694\u7b26\uff0c\u5c06\u5176\u5199\u5165\u6587\u4ef6\u91cc\u3002 \u793a\u4f8b\uff1a\u751f\u6210500\u4e2a\u4ecb\u4e8e1\u548c500\u4e4b\u95f4\u7684\u968f\u673a\u6570\uff0c\u5e76\u8f93\u51fa\u5230\u6587\u672c\u6587\u4ef6\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) for count in range ( 500 ): number = random . randint ( 1 , 500 ) f . write ( str ( number ) + \" \\n \" ) f . close () 1.7.3.\u4ece\u6587\u672c\u6587\u4ef6\u8bfb\u53d6\u6570\u636e \u00b6 \u793a\u4f8b\uff1a\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) f . write ( \"First line. \\n Second line. \\n \" ) # \u521d\u59cb\u5316\u6587\u4ef6\u5185\u5bb9 f . close () # \u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) text1 = f . read () # \u628a\u6587\u4ef6\u7684\u5168\u90e8\u5185\u5bb9\u8f93\u5165\u5355\u4e2a\u5b57\u7b26\u4e32\u4e2d print ( text1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # First line. # Second line text2 = f . read () # \u518d\u6b21read\uff0c\u5f97\u5230\u4e00\u4e2a\u7a7a\u5b57\u4e32\uff0c\u8868\u8ff0\u5df2\u7ecf\u5230\u8fbe\u6587\u4ef6\u672b\u5c3e\u3002\u8981\u518d\u6b21\u8bfb\u53d6\u9700\u8981\u91cd\u65b0\u6253\u5f00\u6587\u4ef6 print ( \"======\" ) print ( text2 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ====== # f . close () # \u91cd\u65b0\u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) for line in f : # \u9010\u884c\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9 print ( \"======\" ) print ( line ) # \u6bcf\u884c\u90fd\u6709\u4e00\u4e2a\u6362\u884c\u7b26\uff0c\u8fd9\u662fprint\u51fd\u6570\u9ed8\u8ba4\u884c\u4e3a # \u8fd0\u884c\u7ed3\u679c\uff1a # ====== # First line. # ====== # Second line. # f . close () # \u91cd\u65b0\u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) while True : line = f . readline () # readline\u65b9\u6cd5\u4f1a\u4ece\u8f93\u5165\u7684\u6587\u672c\u91cc\u53ea\u83b7\u53d6\u4e00\u884c\u6570\u636e\uff0c\u5e76\u4e14\u8fd4\u56de\u8fd9\u4e2a\u5305\u542b\u6362\u884c\u7b26\u7684\u5b57\u7b26\u4e32\u3002\u5982\u679creadline\u9047\u5230\u4e86\u6587\u4ef6\u672b\u5c3e\uff0c\u90a3\u4e48\u4f1a\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\u3002 if line == \"\" : break print ( \"******\" ) print ( line ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ****** # First line. # ****** # Second line. # f . close () # \u91cd\u65b0\u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) line = f . readlines () # readlines\u65b9\u6cd5\u5219\u662f\u8bfb\u53d6\u6240\u6709\u884c\uff0c\u8fd4\u56de\u7684\u662f\u6240\u6709\u884c\u7ec4\u6210\u7684\u5217\u8868\u3002 print ( line ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ['First line.\\n', 'Second line.\\n'] f . close () 1.7.4.\u4ece\u5176\u5b83\u6587\u4ef6\u8bfb\u53d6\u6570\u636e \u00b6 \u793a\u4f8b\uff1a\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6574\u6570\uff0c\u6bcf\u884c\u53ea\u6709\u4e00\u4e2a\u6574\u6570\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) # \u751f\u62100~9\u6574\u6570\uff0c\u5e76\u5199\u5165\u6587\u4ef6 for count in range ( 10 ): f . write ( str ( count ) + \" \\n \" ) f . close () # \u6253\u5f00\u6587\u4ef6 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) # \u4f9d\u6b21\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6570\u5b57\uff0c\u5e76\u6c42\u548c theSum = 0 for line in f : line = line . strip () number = int ( line ) theSum += number print ( \"The sum is : \" , theSum ) # \u8fd0\u884c\u7ed3\u679c\uff1a # The sum is : 45 f . close () \u793a\u4f8b\uff1a\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6574\u6570\uff0c\u6bcf\u884c\u6709\u591a\u4e2a\u6574\u6570\u3002\u9700\u8981\u4e8b\u5148\u628a\u4e0b\u9762\u7684\u5185\u5bb9\u5199\u5165 myfile.txt \u6587\u4ef6\u4e2d\u3002 \u6587\u4ef6 myfile.txt \u7684\u5185\u5bb9\u3002 1 3 5 7 9 2 4 6 8 10 31 200 3000 50000 import random # \u6253\u5f00\u6587\u4ef6 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) # \u4f9d\u6b21\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6570\u5b57\uff0c\u5e76\u6c42\u548c theSum = 0 for line in f : lines = line . split () # split\u65b9\u6cd5\u4f1a\u81ea\u52a8\u5904\u7406\u6362\u884c\u7b26 for word in lines : number = int ( word ) theSum += number print ( \"The sum is : \" , theSum ) # \u8fd0\u884c\u7ed3\u679c\uff1a # The sum is : 53286 f . close () \u7b80\u5199\u4e0a\u9762\u7684\u4ee3\u7801\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) print ( \"The sum is: \" , sum ( map ( int , f . read () . split ()))) # \u8fd0\u884c\u7ed3\u679c\uff1a # The sum is : 53286 f . close () 1.7.5.\u4f7f\u7528pickle\u8bfb\u5199\u5bf9\u8c61 \u00b6 \u5728\u628a\u4efb\u4f55\u5bf9\u8c61\u4fdd\u5b58\u5230\u6587\u4ef6\u4e4b\u524d\uff0c\u6211\u4eec\u53ef\u4ee5\u5bf9\u5b83\u8fdb\u884c\u201c\u814c\u5236\u201d\uff1b\u5728\u628a\u5bf9\u8c61\u4ece\u6587\u4ef6\u52a0\u8f7d\u5230\u7a0b\u5e8f\u4e2d\u65f6\uff0c\u4e5f\u53ef\u4ee5\u5bf9\u5b83\u8fdb\u884c\u201c\u53cd\u814c\u5236\u201d\u3002 \u793a\u4f8b\uff1a \u4f7f\u7528pickle\u6a21\u5757\u7684 pickle.dump \u628a\u540d\u4e3alyst\u7684\u5217\u8868\u91cc\u7684\u6240\u6709\u5bf9\u8c61\u4fdd\u5b58\u5230\u540d\u4e3aitems.dat\u7684\u6587\u4ef6\u91cc\uff08\u201c\u814c\u5236\u201d\uff09\u3002\u6211\u4eec\u4e0d\u9700\u8981\u77e5\u9053\u5217\u8868\u91cc\u6709\u54ea\u4e9b\u7c7b\u578b\u7684\u5bf9\u8c61\uff0c\u4e5f\u4e0d\u9700\u8981\u77e5\u9053\u6709\u591a\u5c11\u4e2a\u5bf9\u8c61\u3002 import pickle myList = [ 60 , \"A string object\" , 1977 ] fObj = open ( \"./docs/python/DataStructure/code/items.dat\" , \"wb\" ) for item in myList : pickle . dump ( item , fObj ) fObj . close () \u4f7f\u7528pickle\u6a21\u5757\u7684 pickle.load \u628aitems.dat\u7684\u6587\u4ef6\u5185\u5bb9\u52a0\u8f7d\u56de\u7a0b\u5e8f\uff08\u201c\u53cd\u814c\u5236\u201d\uff09\u3002 import pickle lyst = list () fileObj = open ( \"./docs/python/DataStructure/code/items.dat\" , \"rb\" ) while True : try : item = pickle . load ( fileObj ) lyst . append ( item ) except EOFError : # \u68c0\u6d4b\u5df2\u7ecf\u5230\u8fbe\u6587\u4ef6\u672b\u5c3e fileObj . close () break print ( lyst ) # \u8fd0\u884c\u7ed3\u679c\uff1a # [60, 'A string object', 1977] 1.8.\u521b\u5efa\u7c7b \u00b6 \u7c7b\uff08class\uff09\u7528\u6765\u63cf\u8ff0\u4e0e\u4e00\u7ec4\u5bf9\u8c61\u6709\u5173\u7684\u6570\u636e\u548c\u65b9\u6cd5\u3002\u5b83\u63d0\u4f9b\u4e86\u7528\u6765\u521b\u5efa\u5bf9\u8c61\u7684\u84dd\u56fe\uff0c\u4ee5\u53ca\u5728\u5bf9\u8c61\u4e0a\u8c03\u7528\u65b9\u6cd5\u65f6\u6240\u9700\u8981\u6267\u884c\u7684\u4ee3\u7801\u3002 Python\u91cc\u7684\u6570\u636e\u7c7b\u578b\u90fd\u662f\u7c7b\uff1b \u7c7b\u540d\u6309\u7167\u60ef\u4f8b\u9996\u5b57\u6bcd\u5e94\u4e3a\u5927\u5199\u6837\u5f0f\uff1b \u5b9a\u4e49\u7c7b\u7684\u4ee3\u7801\u901a\u5e38\u4f1a\u88ab\u5b58\u653e\u5728\u9996\u5b57\u6bcd\u5c0f\u5199\u7684\u7c7b\u540d\u7684\u6a21\u5757\u6587\u4ef6\u91cc\u3002 \u76f8\u5173\u7684\u7c7b\u4e5f\u53ef\u80fd\u4f1a\u51fa\u73b0\u5728\u540c\u4e00\u4e2a\u6a21\u5757\u91cc\u3002 \u7c7b\u7684\u8bed\u6cd5\uff1a def < class name > ( < parent class name > )[ 2 ]: < class variable assignments > < instance method definitions > \u7236\u7c7b\uff08parent class\uff09\u7684\u540d\u79f0\u662f\u53ef\u9009\u7684\uff0c\u5728\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b83\u4f1a\u662fobject\u3002 \u6240\u6709Python\u7c7b\u5c5e\u4e8e\u4e00\u4e2a\u4ee5 object \u4f5c\u4e3a\u6839\u8282\u70b9\u7684\u5c42\u6b21\u7ed3\u6784\u3002 \u5728 object \u91cc\uff0cPython\u5b9a\u4e49\u4e86\u51e0\u79cd\u65b9\u6cd5\uff1a __str__ \u548c __eq__ \uff0c\u56e0\u6b64\u6240\u6709\u5b50\u7c7b\u4f1a\u81ea\u52a8\u7ee7\u627f\u8fd9\u4e9b\u65b9\u6cd5\u3002 \u5b9e\u4f8b\u65b9\u6cd5\uff08instance method\uff09\u662f\u5728\u7c7b\u7684\u5bf9\u8c61\u4e0a\u8fd0\u884c\u7684\u3002\u5b83\u4eec\u5305\u542b\u7528\u6765\u8bbf\u95ee\u6216\u4fee\u6539\u5b9e\u4f8b\u53d8\u91cf\u7684\u4ee3\u7801\u3002 \u5b9e\u4f8b\u53d8\u91cf\uff08instance variable\uff09\u662f\u6307\u7531\u5355\u4e2a\u5bf9\u8c61\u6240\u62e5\u6709\u7684\u5b58\u50a8\u4fe1\u606f\u3002 \u7c7b\u53d8\u91cf\uff08class variable\uff09\u662f\u6307\u7531\u7c7b\u7684\u6240\u6709\u5bf9\u8c61\u5b58\u50a8\u6240\u6709\u7684\u4fe1\u606f\u3002 \u793a\u4f8b\uff1a\u89e3\u8bfbCounter\u7c7b\u3002 Counter \u7c7b\u662f object \u7684\u5b50\u7c7b\uff1b instances \u662f\u7c7b\u53d8\u91cf\uff0c\u8ddf\u8e2a\u5df2\u521b\u5efa\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u7684\u6570\u91cf\uff1b \u5b9e\u4f8b\u65b9\u6cd5 __init__ \u4e5f\u79f0\u4e3a\u6784\u9020\u51fd\u6570\uff1b\u8fd9\u4e2a\u65b9\u6cd5\u7528\u6765\u521d\u59cb\u5316\u5b9e\u4f8b\u53d8\u91cf\uff0c\u5e76\u4e14\u5bf9\u7c7b\u53d8\u91cf\u8fdb\u884c\u66f4\u65b0\uff1b self \u662f\u6307\u5728\u8fd0\u884c\u65f6\u8fd9\u4e2a\u65b9\u6cd5\u7684\u5bf9\u8c61\u672c\u8eab\uff1b \u4f7f\u7528\u5b9e\u4f8b\u53d8\u91cf\u90fd\u4f1a\u52a0\u4e0a\u524d\u7f00 self \uff1b\u548c\u53c2\u6570\u6216\u4e34\u65f6\u53d8\u91cf\u4e0d\u540c\u7684\u5730\u65b9\u662f\uff0c\u5b9e\u4f8b\u53d8\u91cf\u5728\u7c7b\u7684\u4efb\u4f55\u65b9\u6cd5\u91cc\u662f\u53ef\u89c1\u7684\uff1b \u5176\u4ed6\u5b9e\u4f8b\u65b9\u6cd5\u53ef\u4ee5\u5206\u4e3a\u4e24\u79cd\uff1a\u53d8\u5f02\u5668\uff08mutator\uff09\u548c\u8bbf\u95ee\u5668\uff08accessor\uff09\u3002\u53d8\u5f02\u5668\u4f1a\u901a\u8fc7\u4fee\u6539\u5bf9\u8c61\u7684\u5b9e\u4f8b\u53d8\u91cf\u5bf9\u5176\u5185\u90e8\u72b6\u6001\u8fdb\u884c\u4fee\u6539\u6216\u66f4\u6539\u3002\u8bbf\u95ee\u5668\u5219\u53ea\u4f1a\u67e5\u770b\u6216\u4f7f\u7528\u5bf9\u8c61\u7684\u5b9e\u4f8b\u53d8\u91cf\u7684\u503c\uff0c\u800c\u4e0d\u4f1a\u53bb\u4fee\u6539\u5b83\u4eec\uff1b __str__ \u65b9\u6cd5\u5c06\u8986\u76d6object\u7c7b\u91cc\u7684\u8fd9\u4e2a\u65b9\u6cd5\uff1b \u5f53Python\u7684 print \u51fd\u6570\u63a5\u6536\u5230\u4e00\u4e2a\u53c2\u6570\u65f6\uff0c\u8fd9\u4e2a\u53c2\u6570\u7684 __str__ \u65b9\u6cd5\u5c06\u81ea\u52a8\u8fd0\u884c\uff0c\u4ece\u800c\u5f97\u5230\u5b83\u7684\u5b57\u7b26\u4e32\u8868\u8fbe\u5f0f\uff0c\u4ee5\u4fbf\u7528\u6765\u8f93\u51fa\uff1b \u5f53\u770b\u5230 == \u8fd0\u7b97\u7b26\u65f6\uff0cPython\u5c06\u8fd0\u884c __eq__ \u65b9\u6cd5\uff1b\u5728 object \u7c7b\u91cc\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u7684\u9ed8\u8ba4\u5b9a\u4e49\u662f\u8fd0\u884c is \u8fd0\u7b97\u7b26\u3002 class Counter ( object ): # Counter\u7c7b\u662fobject\u7684\u5b50\u7c7b \"\"\"Models a counter.\"\"\" # Class variable \u7c7b\u53d8\u91cf instances = 0 # \u8ddf\u8e2a\u5df2\u521b\u5efa\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u7684\u6570\u91cf # Constructor \u6784\u9020\u5668 # \u5b9e\u4f8b\u65b9\u6cd5__init__\u4e5f\u79f0\u4e3a\u6784\u9020\u51fd\u6570\uff1b\u8fd9\u4e2a\u65b9\u6cd5\u7528\u6765\u521d\u59cb\u5316\u5b9e\u4f8b\u53d8\u91cf\uff0c\u5e76\u4e14\u5bf9\u7c7b\u53d8\u91cf\u8fdb\u884c\u66f4\u65b0\uff1b def __init__ ( self ): # self\u662f\u6307\u5728\u8fd0\u884c\u65f6\u8fd9\u4e2a\u65b9\u6cd5\u7684\u5bf9\u8c61\u672c\u8eab \"\"\"Sets up the counter.\"\"\" Counter . instances += 1 self . reset () # Mutator methods def reset ( self ): \"\"\"Sets the counter to 0.\"\"\" self . value = 0 def increment ( self , amount = 1 ): \"\"\"Adds amount to the counter.\"\"\" self . value += amount def decrement ( self , amount = 1 ): \"\"\"Subtracts amount from the counter.\"\"\" self . value -= amount # Accessor methods def getValue ( self ): \"\"\"Returns the counter's value.\"\"\" return self . value def __str__ ( self ): \"\"\"Returns the string representation of the counter.\"\"\" return str ( self . value ) def __eq__ ( self , other ): \"\"\"Returns True if self equals other or False otherwise.\"\"\" if self is other : return True if type ( self ) != type ( other ): return False return self . value == other . value c1 = Counter () print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 0 c1 . getValue () str ( c1 ) c1 . increment () print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 1 c1 . increment ( 5 ) print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 6 c1 . reset () print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 0 c2 = Counter () print ( Counter . instances ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 2 print ( c1 == c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # True print ( c1 == 0 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # False print ( c1 == c2 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # True c2 . increment () print ( c1 == c2 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # False 1.9.\u7f16\u7a0b\u7ec3\u4e60 \u00b6 1\uff0e\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u4f7f\u4e4b\u80fd\u591f\u63a5\u6536\u7403\u4f53\u7684\u534a\u5f84\uff08\u6d6e\u70b9\u6570\uff09\uff0c\u5e76\u4e14\u53ef\u4ee5\u8f93\u51fa\u7403\u4f53\u7684\u76f4\u5f84\u3001\u5468\u957f\u3001\u8868\u9762\u79ef\u4ee5\u53ca\u4f53\u79ef\u3002 \u89e3\u7b54\uff1a PAI = 3.14 radius = float ( input ( \"\u8f93\u5165\u7403\u534a\u5f84\uff1a\" )) diameter = radius * 2 circumference = 2 * PAI * radius surfaceArea = 4 * PAI * radius ** 2 sphereVolume = 4 * ( PAI * radius ** 3 ) / 3 print ( \"\u7403\u534a\u5f84\uff1a\" , radius , \"\u7403\u76f4\u5f84\uff1a\" , diameter , \"\u7403\u8868\u9762\u79ef\uff1a\" , surfaceArea , \"\u7403\u4f53\u79ef\uff1a\" , sphereVolume ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u7403\u534a\u5f84\uff1a3.5 # \u7403\u534a\u5f84\uff1a 3.5 \u7403\u76f4\u5f84\uff1a 7.0 \u7403\u8868\u9762\u79ef\uff1a 153.86 \u7403\u4f53\u79ef\uff1a 179.50333333333333 import math def main (): try : radius = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u534a\u5f84\uff1a\" )) if radius <= 0 : print ( \"\u534a\u5f84\u5fc5\u987b\u4e3a\u6b63\u6570\uff01\" ) return diameter = 2 * radius circumference = 2 * math . pi * radius surfaceArea = 4 * math . pi * radius ** 2 volume = ( 4 / 3 ) * math . pi * radius ** 3 print ( f \"\u7403\u4f53\u7684\u76f4\u5f84\uff1a { diameter : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u5468\u957f\uff1a { circumference : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a { surfaceArea : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u4f53\u79ef\uff1a { volume : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u7403\u534a\u5f84\uff1a3.5 # \u7403\u4f53\u7684\u76f4\u5f84\uff1a7.00 # \u7403\u4f53\u7684\u5468\u957f\uff1a21.99 # \u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a153.94 # \u7403\u4f53\u7684\u4f53\u79ef\uff1a179.59 import math class Sphere : def __init__ ( self , radius ): self . radius = radius def diameter ( self ): return 2 * self . radius def circumference ( self ): return 2 * math . pi * self . radius def surfaceArea ( self ): return 4 * math . pi * self . radius ** 2 def volume ( self ): return ( 4 / 3 ) * math . pi * self . radius ** 3 def main (): try : radius = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u4f53\u7684\u534a\u5f84\uff1a\" )) if radius <= 0 : print ( \"\u534a\u5f84\u5fc5\u987b\u4e3a\u6b63\u6570\uff01\" ) return sphere = Sphere ( radius ) print ( f \"\u7403\u4f53\u7684\u76f4\u5f84\uff1a { sphere . diameter () : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u5468\u957f\uff1a { sphere . circumference () : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a { sphere . surfaceArea () : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u4f53\u79ef\uff1a { sphere . volume () : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u7403\u4f53\u7684\u534a\u5f84\uff1a3.5 # \u7403\u4f53\u7684\u76f4\u5f84\uff1a7.00 # \u7403\u4f53\u7684\u5468\u957f\uff1a21.99 # \u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a153.94 # \u7403\u4f53\u7684\u4f53\u79ef\uff1a179.59 2\uff0e\u5458\u5de5\u7684\u5468\u5de5\u8d44\u7b49\u4e8e\u5c0f\u65f6\u5de5\u8d44\u4e58\u4ee5\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\u518d\u52a0\u4e0a\u52a0\u73ed\u5de5\u8d44\u3002\u52a0\u73ed\u5de5\u8d44\u7b49\u4e8e\u603b\u52a0\u73ed\u65f6\u95f4\u4e58\u4ee5\u5c0f\u65f6\u5de5\u8d44\u76841.5\u500d\u3002\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\u3001\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\u4ee5\u53ca\u52a0\u73ed\u603b\u65f6\u95f4\uff0c\u7136\u540e\u663e\u793a\u51fa\u5458\u5de5\u7684\u5468\u5de5\u8d44\u3002 \u89e3\u7b54\uff1a hourSalary = float ( input ( \"\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff08\u5143\uff09\uff1a\" )) totalWorkingHours = float ( input ( \"\u8f93\u5165\u672c\u5468\u6b63\u5e38\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) totalOvertimeHours = float ( input ( \"\u8f93\u5165\u672c\u5468\u603b\u52a0\u73ed\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) weeklySalary = hourSalary * totalWorkingHours + hourSalary * totalOvertimeHours * 1.5 print ( \"\u5458\u5de5\u7684\u5468\u5de5\u8d44\uff08\u5143\uff09\u662f\uff1a\" , weeklySalary ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff08\u5143\uff09\uff1a20 # \u8f93\u5165\u672c\u5468\u6b63\u5e38\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a40 # \u8f93\u5165\u672c\u5468\u603b\u52a0\u73ed\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a10 # \u5458\u5de5\u7684\u5468\u5de5\u8d44\uff08\u5143\uff09\u662f\uff1a 1100.0 def calculate_weekly_salary ( hourly_wage , normal_hours , overtime_hours ): overtime_pay = overtime_hours * hourly_wage * 1.5 normal_pay = normal_hours * hourly_wage weekly_salary = normal_pay + overtime_pay return weekly_salary def main (): try : hourly_wage = float ( input ( \"\u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a\" )) normal_hours = float ( input ( \"\u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) overtime_hours = float ( input ( \"\u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) weekly_salary = calculate_weekly_salary ( hourly_wage , normal_hours , overtime_hours ) print ( f \"\u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a { weekly_salary : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a20 # \u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a40 # \u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a10 # \u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a1100.00 class Employee : def __init__ ( self , hourly_wage , normal_hours , overtime_hours ): self . hourly_wage = hourly_wage self . normal_hours = normal_hours self . overtime_hours = overtime_hours def calculate_weekly_salary ( self ): overtime_pay = self . overtime_hours * self . hourly_wage * 1.5 normal_pay = self . normal_hours * self . hourly_wage weekly_salary = normal_pay + overtime_pay return weekly_salary def main (): try : hourly_wage = float ( input ( \"\u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a\" )) normal_hours = float ( input ( \"\u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) overtime_hours = float ( input ( \"\u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) employee = Employee ( hourly_wage , normal_hours , overtime_hours ) weekly_salary = employee . calculate_weekly_salary () print ( f \"\u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a { weekly_salary : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a20 # \u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a40 # \u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a10 # \u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a1100.00 3\uff0e\u6709\u4e00\u4e2a\u6807\u51c6\u7684\u79d1\u5b66\u5b9e\u9a8c\uff1a\u6254\u4e00\u4e2a\u7403\uff0c\u770b\u770b\u5b83\u80fd\u53cd\u5f39\u591a\u9ad8\u3002\u4e00\u65e6\u786e\u5b9a\u4e86\u7403\u7684\u201c\u53cd\u5f39\u9ad8\u5ea6\u201d\uff0c\u8fd9\u4e2a\u6bd4\u503c\u5c31\u7ed9\u51fa\u4e86\u76f8\u5e94\u7684\u53cd\u5f39\u5ea6\u6307\u6570\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4ece10ft\uff081ft=0.3048m\uff09\u9ad8\u5904\u6389\u843d\u7684\u7403\u53ef\u4ee5\u53cd\u5f39\u52306 ft\u9ad8\uff0c\u90a3\u4e48\u76f8\u5e94\u7684\u53cd\u5f39\u5ea6\u6307\u6570\u5c31\u662f0.6\uff1b\u5728\u4e00\u6b21\u53cd\u5f39\u4e4b\u540e\uff0c\u7403\u7684\u603b\u884c\u8fdb\u8ddd\u79bb\u662f16 ft\u3002\u63a5\u4e0b\u6765\uff0c\u7403\u7ee7\u7eed\u5f39\u8df3\uff0c\u90a3\u4e48\u4e24\u6b21\u5f39\u8df3\u540e\u7684\u603b\u8ddd\u79bb\u5e94\u8be5\u662f\uff1a10 ft + 6 ft + 6 ft + 3.6 ft = 25.6 ft\u3002\u53ef\u4ee5\u770b\u5230\uff0c\u6bcf\u6b21\u8fde\u7eed\u5f39\u8df3\u6240\u7ecf\u8fc7\u7684\u8ddd\u79bb\u662f\uff1a\u7403\u5230\u5730\u9762\u7684\u8ddd\u79bb\uff0c\u52a0\u4e0a\u8fd9\u4e2a\u8ddd\u79bb\u4e58\u4ee5 0.6\uff0c\u8fd9\u65f6\u7403\u53c8\u5f39\u56de\u6765\u4e86\u3002\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u53ef\u4ee5\u8ba9\u7528\u6237\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\u548c\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff0c\u5e76\u8f93\u51fa\u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u3002 \u89e3\u7b54\uff1a height = float ( input ( \"\u8f93\u5165\u5c0f\u7403\u521d\u59cb\u9ad8\u5ea6\uff08ft\uff09\uff1a\" )) times = float ( input ( \"\u8f93\u5165\u5141\u8bb8\u5c0f\u7403\u5f39\u8df3\u6b21\u6570\uff1a\" )) distance = 0 traceDistance = 0 while times : distance = height + 0.6 * height traceDistance += distance height = 0.6 * height times -= 1 print ( \"\u5c0f\u7403\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\uff08ft\uff09\uff1a\" , traceDistance ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u5c0f\u7403\u521d\u59cb\u9ad8\u5ea6\uff08ft\uff09\uff1a50 # \u8f93\u5165\u5141\u8bb8\u5c0f\u7403\u5f39\u8df3\u6b21\u6570\uff1a5 # \u5c0f\u7403\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\uff08ft\uff09\uff1a 184.448 # \u8f93\u5165\u5c0f\u7403\u521d\u59cb\u9ad8\u5ea6\uff08ft\uff09\uff1a100 # \u8f93\u5165\u5141\u8bb8\u5c0f\u7403\u5f39\u8df3\u6b21\u6570\uff1a10 # \u5c0f\u7403\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\uff08ft\uff09\uff1a 397.58135296000006 def calculate_total_distance ( initial_height , num_bounces ): rebound_factor = 0.6 total_distance = 0 height = initial_height for _ in range ( num_bounces + 1 ): total_distance += height height *= rebound_factor return total_distance def main (): try : initial_height = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a\" )) num_bounces = int ( input ( \"\u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a\" )) total_distance = calculate_total_distance ( initial_height , num_bounces ) print ( f \"\u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a { total_distance : .2f } ft\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a50 # \u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a5 # \u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a119.17 ft # \u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a100 # \u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a10 # \u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a249.09 ft class BouncingBall : def __init__ ( self , initial_height , num_bounces ): self . initial_height = initial_height self . num_bounces = num_bounces self . rebound_factor = 0.6 def calculate_total_distance ( self ): total_distance = 0 height = self . initial_height for _ in range ( self . num_bounces + 1 ): total_distance += height height *= self . rebound_factor return total_distance def main (): try : initial_height = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a\" )) num_bounces = int ( input ( \"\u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a\" )) bouncing_ball = BouncingBall ( initial_height , num_bounces ) total_distance = bouncing_ball . calculate_total_distance () print ( f \"\u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a { total_distance : .2f } ft\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () 4\uff0e\u5fb7\u56fd\u6570\u5b66\u5bb6Gottfried Leibniz\u53d1\u660e\u4e86\u4e0b\u9762\u8fd9\u4e2a\u7528\u6765\u6c42\u03c0\u7684\u8fd1\u4f3c\u503c\u7684\u65b9\u6cd5\uff1a \u03c0/4 = 1 - 1/3 + 1/5 - 1/7 + ...... \uff0c\u8bf7\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u6307\u5b9a\u8fd9\u4e2a\u8fd1\u4f3c\u503c\u6240\u4f7f\u7528\u7684\u8fed\u4ee3\u6b21\u6570\uff0c\u5e76\u4e14\u663e\u793a\u51fa\u7ed3\u679c\u3002 \u89e3\u7b54\uff1a n = int ( input ( \"\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a\" )) mySum = 0 while n : mySum += 1 / ( 2 * n - 1 ) * (( - 1 ) ** ( n + 1 )) n -= 1 print ( \"\u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a\" , mySum * 4 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a5 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.33968253968254 # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.0418396189294024 # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a20 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.0916238066678385 # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10000000 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.1415925535897933 def calculate_pi_approximation ( iterations ): approximation = 0 sign = 1 for i in range ( 1 , iterations * 2 , 2 ): approximation += sign * ( 1 / i ) sign *= - 1 return approximation * 4 def main (): try : iterations = int ( input ( \"\u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a\" )) if iterations <= 0 : print ( \"\u8fed\u4ee3\u6b21\u6570\u5fc5\u987b\u4e3a\u6b63\u6574\u6570\uff01\" ) return pi_approximation = calculate_pi_approximation ( iterations ) print ( f \"\u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a { pi_approximation : .10f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6574\u6570\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a5 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.3396825397 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0418396189 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a20 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0916238067 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10000000 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.1415925536 class PiApproximation : @classmethod def calculate_pi_approximation ( cls , iterations ): approximation = 0 sign = 1 for i in range ( 1 , iterations * 2 , 2 ): approximation += sign * ( 1 / i ) sign *= - 1 return approximation * 4 def main (): try : iterations = int ( input ( \"\u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a\" )) if iterations <= 0 : print ( \"\u8fed\u4ee3\u6b21\u6570\u5fc5\u987b\u4e3a\u6b63\u6574\u6570\uff01\" ) return pi_approximation = PiApproximation . calculate_pi_approximation ( iterations ) print ( f \"\u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a { pi_approximation : .10f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6574\u6570\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a5 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.3396825397 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0418396189 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a20 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0916238067 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10000000 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.1415925536 5\uff0e\u67d0\u8ba1\u7b97\u673a\u5546\u5e97\u6709\u8d2d\u4e70\u8ba1\u7b97\u673a\u7684\u4fe1\u8d37\u8ba1\u5212\uff1a\u9996\u4ed810%\uff0c\u5e74\u5229\u7387\u4e3a12%\uff0c\u6bcf\u6708\u6240\u4ed8\u6b3e\u4e3a\u8d2d\u4e70\u4ef7\u683c\u51cf\u53bb\u9996\u4ed8\u4e4b\u540e\u76845%\u3002\u7f16\u5199\u4e00\u4e2a\u4ee5\u8d2d\u4e70\u4ef7\u683c\u4e3a\u8f93\u5165\u7684\u7a0b\u5e8f\uff0c\u53ef\u4ee5\u8f93\u51fa\u4e00\u4e2a\u6709\u9002\u5f53\u6807\u9898\u7684\u8868\u683c\uff0c\u663e\u793a\u8d37\u6b3e\u671f\u9650\u5185\u7684\u4ed8\u6b3e\u8ba1\u5212\u3002\u8868\u7684\u6bcf\u4e00\u884c\u90fd\u5e94\u5305\u542b\u4e0b\u9762\u5404\u9879\uff1a \u6708\u6570\uff08\u4ee51\u5f00\u5934\uff09\uff1b \u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d\uff1b \u5f53\u6708\u6240\u6b20\u7684\u5229\u606f\uff1b \u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1\uff1b \u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d\uff1b \u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d\u3002 \u4e00\u4e2a\u6708\u7684\u5229\u606f\u7b49\u4e8e\u4f59\u989d \u00d7 \u5229\u7387/12\uff1b\u4e00\u4e2a\u6708\u6240\u6b20\u7684\u672c\u91d1\u7b49\u4e8e\u5f53\u6708\u8fd8\u6b3e\u989d\u51cf\u53bb\u6240\u6b20\u7684\u5229\u606f\u3002 \u89e3\u7b54\uff1a def calculate_payment_schedule ( purchase_price ): down_payment = purchase_price * 0.1 loan_balance = purchase_price - down_payment annual_interest_rate = 0.12 monthly_interest_rate = annual_interest_rate / 12 monthly_payment = ( purchase_price - down_payment ) * 0.05 payment_schedule = [] for month in range ( 1 , 13 ): interest = loan_balance * monthly_interest_rate principal = monthly_payment - interest loan_balance -= principal payment_schedule . append (( month , loan_balance , interest , principal , monthly_payment , loan_balance + monthly_payment )) return payment_schedule def main (): try : purchase_price = float ( input ( \"\u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a\" )) payment_schedule = calculate_payment_schedule ( purchase_price ) print ( \" {:<10} {:<15} {:<15} {:<15} {:<15} {:<15} \" . format ( \"\u6708\u6570\" , \"\u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d\" , \"\u5f53\u6708\u6240\u6b20\u7684\u5229\u606f\" , \"\u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1\" , \"\u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d\" , \"\u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d\" )) for payment in payment_schedule : month , balance , interest , principal , monthly_payment , new_balance = payment print ( \" {:<10} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} \" . format ( month , balance , interest , principal , monthly_payment , new_balance )) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a5000 # \u6708\u6570 \u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d \u5f53\u6708\u6240\u6b20\u7684\u5229\u606f \u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1 \u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d \u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d # 1 4320.00 45.00 180.00 225.00 4545.00 # 2 4138.20 43.20 181.80 225.00 4363.20 # 3 3954.58 41.38 183.62 225.00 4179.58 # 4 3769.13 39.55 185.45 225.00 3994.13 # 5 3581.82 37.69 187.31 225.00 3806.82 # 6 3392.64 35.82 189.18 225.00 3617.64 # 7 3201.56 33.93 191.07 225.00 3426.56 # 8 3008.58 32.02 192.98 225.00 3233.58 # 9 2813.67 30.09 194.91 225.00 3038.67 # 10 2616.80 28.14 196.86 225.00 2841.80 # 11 2417.97 26.17 198.83 225.00 2642.97 # 12 2217.15 24.18 200.82 225.00 2442.15 class PaymentSchedule : def __init__ ( self , purchase_price ): self . purchase_price = purchase_price self . down_payment = purchase_price * 0.1 self . loan_balance = purchase_price - self . down_payment self . annual_interest_rate = 0.12 self . monthly_interest_rate = self . annual_interest_rate / 12 self . monthly_payment = ( purchase_price - self . down_payment ) * 0.05 def calculate_schedule ( self ): payment_schedule = [] for month in range ( 1 , 13 ): interest = self . loan_balance * self . monthly_interest_rate principal = self . monthly_payment - interest self . loan_balance -= principal payment_schedule . append (( month , self . loan_balance , interest , principal , self . monthly_payment , self . loan_balance + self . monthly_payment )) return payment_schedule def print_schedule_table ( self ): payment_schedule = self . calculate_schedule () print ( \" {:<10} {:<15} {:<15} {:<15} {:<15} {:<15} \" . format ( \"\u6708\u6570\" , \"\u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d\" , \"\u5f53\u6708\u6240\u6b20\u7684\u5229\u606f\" , \"\u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1\" , \"\u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d\" , \"\u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d\" )) for payment in payment_schedule : month , balance , interest , principal , monthly_payment , new_balance = payment print ( \" {:<10} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} \" . format ( month , balance , interest , principal , monthly_payment , new_balance )) def main (): try : purchase_price = float ( input ( \"\u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a\" )) payment_schedule = PaymentSchedule ( purchase_price ) payment_schedule . print_schedule_table () except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # \u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a5000 # \u6708\u6570 \u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d \u5f53\u6708\u6240\u6b20\u7684\u5229\u606f \u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1 \u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d \u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d # 1 4320.00 45.00 180.00 225.00 4545.00 # 2 4138.20 43.20 181.80 225.00 4363.20 # 3 3954.58 41.38 183.62 225.00 4179.58 # 4 3769.13 39.55 185.45 225.00 3994.13 # 5 3581.82 37.69 187.31 225.00 3806.82 # 6 3392.64 35.82 189.18 225.00 3617.64 # 7 3201.56 33.93 191.07 225.00 3426.56 # 8 3008.58 32.02 192.98 225.00 3233.58 # 9 2813.67 30.09 194.91 225.00 3038.67 # 10 2616.80 28.14 196.86 225.00 2841.80 # 11 2417.97 26.17 198.83 225.00 2642.97 # 12 2217.15 24.18 200.82 225.00 2442.15 6\uff0e\u8d22\u52a1\u90e8\u95e8\u5728\u6587\u672c\u6587\u4ef6\u91cc\u4fdd\u5b58\u4e86\u6240\u6709\u5458\u5de5\u5728\u6bcf\u4e2a\u5de5\u8d44\u5468\u671f\u91cc\u7684\u4fe1\u606f\u5217\u8868\u3002\u6587\u4ef6\u4e2d\u6bcf\u4e00\u884c\u7684\u683c\u5f0f\u4e3a \u3002\u8bf7\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u8f93\u5165\u6587\u4ef6\u7684\u540d\u79f0\uff0c\u5e76\u5728\u7ec8\u7aef\u4e0a\u6253\u5370\u51fa\u7ed9\u5b9a\u65f6\u95f4\u5185\u652f\u4ed8\u7ed9\u6bcf\u4e2a\u5458\u5de5\u7684\u5de5\u8d44\u62a5\u544a\u3002\u8fd9\u4e2a\u62a5\u544a\u662f\u4e00\u4e2a\u6709\u5408\u9002\u6807\u9898\u7684\u8868\uff0c\u5176\u4e2d\u6bcf\u884c\u90fd\u5e94\u8be5\u5305\u542b\u5458\u5de5\u7684\u59d3\u540d\u3001\u5de5\u4f5c\u65f6\u957f\u4ee5\u53ca\u7ed9\u5b9a\u65f6\u95f4\u5185\u6240\u652f\u4ed8\u7684\u5de5\u8d44\u3002 \u89e3\u7b54\uff1a # \u7a0b\u5e8f\u4f1a\u63d0\u793a\u7528\u6237\u8f93\u5165\u6587\u4ef6\u540d\uff0c\u7136\u540e\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u5458\u5de5\u4fe1\u606f\uff0c\u8ba1\u7b97\u5de5\u8d44\u62a5\u544a\uff0c\u5e76\u6253\u5370\u51fa\u5458\u5de5\u7684\u59d3\u540d\u3001\u5de5\u4f5c\u65f6\u957f\u548c\u652f\u4ed8\u5de5\u8d44\u3002\u6ce8\u610f\uff0c\u7a0b\u5e8f\u4f1a\u68c0\u67e5\u6587\u4ef6\u662f\u5426\u5b58\u5728\uff0c\u5e76\u4f1a\u5bf9\u6587\u4ef6\u4e2d\u7684\u6bcf\u884c\u6570\u636e\u8fdb\u884c\u5904\u7406\u4ee5\u786e\u4fdd\u6b63\u786e\u89e3\u6790\u3002 class Employee : def __init__ ( self , last_name , hourly_wage , hours_worked ): self . last_name = last_name self . hourly_wage = float ( hourly_wage ) self . hours_worked = float ( hours_worked ) def calculate_salary ( self ): return self . hourly_wage * self . hours_worked def main (): try : filename = input ( \"\u8bf7\u8f93\u5165\u6587\u4ef6\u540d\uff1a\" ) with open ( filename , 'r' ) as file : employees = [] for line in file : parts = line . strip () . split () if len ( parts ) == 3 : last_name , hourly_wage , hours_worked = parts employee = Employee ( last_name , hourly_wage , hours_worked ) employees . append ( employee ) print ( \" {:<20} {:<15} {:<15} \" . format ( \"\u5458\u5de5\u59d3\u540d\" , \"\u5de5\u4f5c\u65f6\u957f\" , \"\u652f\u4ed8\u5de5\u8d44\" )) print ( \"=\" * 50 ) total_salary = 0 for employee in employees : salary = employee . calculate_salary () total_salary += salary print ( \" {:<20} {:<15.2f} {:<15.2f} \" . format ( employee . last_name , employee . hours_worked , salary )) print ( \"=\" * 50 ) print ( f \"\u603b\u652f\u4ed8\u5de5\u8d44\uff1a { total_salary : .2f } \" ) except FileNotFoundError : print ( \"\u6587\u4ef6\u4e0d\u5b58\u5728\uff01\" ) if __name__ == \"__main__\" : main () 7\uff0e\u7edf\u8ba1\u5b66\u5bb6\u5e0c\u671b\u4f7f\u7528\u4e00\u7ec4\u51fd\u6570\u8ba1\u7b97\u6570\u5b57\u5217\u8868\u7684\u4e2d\u4f4d\u6570\uff08median\uff09\u548c\u4f17\u6570\uff08mode\uff09\u3002\u4e2d\u4f4d\u6570\u662f\u6307\u5982\u679c\u5bf9\u5217\u8868\u8fdb\u884c\u6392\u5e8f\u5c06\u4f1a\u51fa\u73b0\u5728\u5217\u8868\u4e2d\u70b9\u7684\u6570\u5b57\uff0c\u4f17\u6570\u662f\u6307\u5217\u8868\u4e2d\u6700\u5e38\u51fa\u73b0\u7684\u6570\u5b57\u3002\u628a\u8fd9\u4e9b\u529f\u80fd\u5b9a\u4e49\u5728\u540d\u53ebstats.py\u7684\u6a21\u5757\u4e2d\u3002\u9664\u6b64\u4e4b\u5916\uff0c\u6a21\u5757\u8fd8\u5e94\u8be5\u5305\u542b\u4e00\u4e2a\u540d\u53ebmean\u7684\u51fd\u6570\uff0c\u7528\u6765\u8ba1\u7b97\u4e00\u7ec4\u6570\u5b57\u7684\u5e73\u5747\u503c\u3002\u6bcf\u4e2a\u51fd\u6570\u90fd\u4f1a\u63a5\u6536\u4e00\u4e2a\u6570\u5b57\u5217\u8868\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u8fd4\u56de\u4e00\u4e2a\u6570\u5b57\u3002 \u89e3\u7b54\uff1a def median ( numbers ): sorted_numbers = sorted ( numbers ) length = len ( sorted_numbers ) if length % 2 == 1 : return sorted_numbers [ length // 2 ] else : mid1 = sorted_numbers [ length // 2 - 1 ] mid2 = sorted_numbers [ length // 2 ] return ( mid1 + mid2 ) / 2 def mode ( numbers ): from collections import Counter counter = Counter ( numbers ) mode_list = counter . most_common () max_count = mode_list [ 0 ][ 1 ] modes = [ num for num , count in mode_list if count == max_count ] return modes def mean ( numbers ): total = sum ( numbers ) count = len ( numbers ) return total / count if __name__ == \"__main__\" : test_numbers = [ 4 , 2 , 7 , 2 , 1 , 9 , 4 , 7 ] print ( \"\u4e2d\u4f4d\u6570:\" , median ( test_numbers )) print ( \"\u4f17\u6570:\" , mode ( test_numbers )) print ( \"\u5e73\u5747\u503c:\" , mean ( test_numbers )) class Stats : @staticmethod def median ( numbers ): sorted_numbers = sorted ( numbers ) length = len ( sorted_numbers ) if length % 2 == 1 : return sorted_numbers [ length // 2 ] else : mid1 = sorted_numbers [ length // 2 - 1 ] mid2 = sorted_numbers [ length // 2 ] return ( mid1 + mid2 ) / 2 @staticmethod def mode ( numbers ): from collections import Counter counter = Counter ( numbers ) mode_list = counter . most_common () max_count = mode_list [ 0 ][ 1 ] modes = [ num for num , count in mode_list if count == max_count ] return modes @staticmethod def mean ( numbers ): total = sum ( numbers ) count = len ( numbers ) return total / count if __name__ == \"__main__\" : test_numbers = [ 4 , 2 , 7 , 2 , 1 , 9 , 4 , 7 ] print ( \"\u4e2d\u4f4d\u6570:\" , Stats . median ( test_numbers )) print ( \"\u4f17\u6570:\" , Stats . mode ( test_numbers )) print ( \"\u5e73\u5747\u503c:\" , Stats . mean ( test_numbers )) 8\uff0e\u7f16\u5199\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u6d4f\u89c8\u6587\u4ef6\u91cc\u7684\u6587\u672c\u884c\u3002\u8fd9\u4e2a\u7a0b\u5e8f\u4f1a\u63d0\u793a\u7528\u6237\u8f93\u5165\u6587\u4ef6\u540d\uff0c\u7136\u540e\u628a\u6587\u672c\u884c\u90fd\u8f93\u5165\u5217\u8868\u3002\u63a5\u4e0b\u6765\uff0c\u8fd9\u4e2a\u7a0b\u5e8f\u4f1a\u8fdb\u5165\u4e00\u4e2a\u5faa\u73af\uff0c\u5728\u8fd9\u4e2a\u5faa\u73af\u91cc\u6253\u5370\u51fa\u6587\u4ef6\u7684\u603b\u884c\u6570\uff0c\u5e76\u63d0\u793a\u7528\u6237\u8f93\u5165\u884c\u53f7\u3002\u8fd9\u4e2a\u884c\u53f7\u7684\u8303\u56f4\u5e94\u5f53\u662f1\u5230\u6587\u4ef6\u7684\u603b\u884c\u6570\u3002\u5982\u679c\u8f93\u5165\u662f0\uff0c\u90a3\u4e48\u7a0b\u5e8f\u9000\u51fa\uff1b\u5426\u5219\uff0c\u7a0b\u5e8f\u5c06\u6253\u5370\u51fa\u884c\u53f7\u6240\u5bf9\u5e94\u7684\u6587\u672c\u884c\u3002 def read_file_lines ( filename ): try : with open ( filename , 'r' ) as file : lines = file . readlines () return lines except FileNotFoundError : print ( \"\u6587\u4ef6\u4e0d\u5b58\u5728\uff01\" ) return [] def main (): filename = input ( \"\u8bf7\u8f93\u5165\u6587\u4ef6\u540d\uff1a\" ) lines = read_file_lines ( filename ) if not lines : return total_lines = len ( lines ) while True : print ( f \"\u6587\u4ef6\u603b\u884c\u6570\uff1a { total_lines } \" ) try : line_number = int ( input ( \"\u8bf7\u8f93\u5165\u884c\u53f7\uff08\u8f93\u51650\u9000\u51fa\uff09\uff1a\" )) if line_number == 0 : break elif 1 <= line_number <= total_lines : print ( f \"\u884c\u53f7 { line_number } : { lines [ line_number - 1 ] . strip () } \" ) else : print ( \"\u65e0\u6548\u7684\u884c\u53f7\uff0c\u8bf7\u8f93\u5165\u6b63\u786e\u8303\u56f4\u5185\u7684\u884c\u53f7\uff01\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () class TextFileBrowser : @classmethod def read_file_lines ( cls , filename ): try : with open ( filename , 'r' ) as file : lines = file . readlines () return lines except FileNotFoundError : print ( \"\u6587\u4ef6\u4e0d\u5b58\u5728\uff01\" ) return [] @classmethod def browse_file ( cls , filename ): lines = cls . read_file_lines ( filename ) if not lines : return total_lines = len ( lines ) while True : print ( f \"\u6587\u4ef6\u603b\u884c\u6570\uff1a { total_lines } \" ) try : line_number = int ( input ( \"\u8bf7\u8f93\u5165\u884c\u53f7\uff08\u8f93\u51650\u9000\u51fa\uff09\uff1a\" )) if line_number == 0 : break elif 1 <= line_number <= total_lines : print ( f \"\u884c\u53f7 { line_number } : { lines [ line_number - 1 ] . strip () } \" ) else : print ( \"\u65e0\u6548\u7684\u884c\u53f7\uff0c\u8bf7\u8f93\u5165\u6b63\u786e\u8303\u56f4\u5185\u7684\u884c\u53f7\uff01\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) def main (): filename = input ( \"\u8bf7\u8f93\u5165\u6587\u4ef6\u540d\uff1a\" ) TextFileBrowser . browse_file ( filename ) if __name__ == \"__main__\" : main () 9\uff0e\u5728\u672c\u7ae0\u8ba8\u8bba\u7684numberguess\u7a0b\u5e8f\u91cc\uff0c\u8ba1\u7b97\u673a\u4f1a\u201c\u6784\u601d\u201d\u4e00\u4e2a\u6570\u5b57\uff0c\u800c\u7528\u6237\u5219\u8f93\u5165\u731c\u6d4b\u7684\u503c\uff0c\u76f4\u5230\u731c\u5bf9\u4e3a\u6b62\u3002\u7f16\u5199\u8fd9\u6837\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u4f7f\u5176\u53ef\u4ee5\u8c03\u6362\u8fd9\u4e24\u4e2a\u89d2\u8272\uff0c\u4e5f\u5c31\u662f\uff1a\u7528\u6237\u53bb\u201c\u6784\u601d\u201d\u4e00\u4e2a\u6570\u5b57\uff0c\u7136\u540e\u8ba1\u7b97\u673a\u53bb\u8ba1\u7b97\u5e76\u8f93\u51fa\u731c\u6d4b\u7684\u503c\u3002\u548c\u524d\u9762\u90a3\u4e2a\u6e38\u620f\u7248\u672c\u4e00\u6837\uff0c\u5f53\u8ba1\u7b97\u673a\u731c\u9519\u65f6\uff0c\u7528\u6237\u5fc5\u987b\u7ed9\u51fa\u76f8\u5e94\u7684\u63d0\u793a\uff0c\u4f8b\u5982\u201c<\u201d\u548c\u201c>\u201d\uff08\u5206\u522b\u4ee3\u8868\u201c\u6211\u7684\u6570\u5b57\u66f4\u5c0f\u201d\u548c\u201c\u6211\u7684\u6570\u5b57\u66f4\u5927\u201d\uff09\u3002\u5f53\u8ba1\u7b97\u673a\u731c\u5bf9\u65f6\uff0c\u7528\u6237\u5e94\u8be5\u8f93\u5165\u201c=\u201d\u3002\u7528\u6237\u9700\u8981\u5728\u7a0b\u5e8f\u542f\u52a8\u7684\u65f6\u5019\u8f93\u5165\u6570\u5b57\u7684\u4e0b\u9650\u548c\u4e0a\u9650\u3002\u8ba1\u7b97\u673a\u5e94\u8be5\u5728\u6700\u591a [log2(high\u2212low)+1] \u6b21\u731c\u6d4b\u91cc\u627e\u5230\u6b63\u786e\u7684\u6570\u5b57\u3002\u7a0b\u5e8f\u5e94\u8be5\u80fd\u591f\u8ddf\u8e2a\u731c\u6d4b\u6b21\u6570\uff0c\u5982\u679c\u731c\u6d4b\u9519\u8bef\u7684\u6b21\u6570\u5230\u4e86\u5141\u8bb8\u731c\u6d4b\u7684\u6700\u5927\u503c\u4f46\u8fd8\u6ca1\u6709\u731c\u5bf9\uff0c\u5c31\u8f93\u51fa\u6d88\u606f\u201cYou're cheating\uff01\u201d\u3002\u4e0b\u9762\u662f\u548c\u8fd9\u4e2a\u7a0b\u5e8f\u8fdb\u884c\u4ea4\u4e92\u7684\u793a\u4f8b\uff1a Enter the smaller number : 1 Enter the larger number : 100 Your number is 50 Enter = , < , or > : > Your number is 75 Enter = , < , or > : < Your number is 62 Enter = , < , or > : < Your number is 56 Enter = , < , or > : = Hooray , I 've got it in 4 tries! import math class ComputerGuesser : def __init__ ( self , lower_limit , upper_limit ): self . lower_limit = lower_limit self . upper_limit = upper_limit self . max_attempts = math . floor ( math . log2 ( upper_limit - lower_limit + 1 )) + 1 self . attempts = 0 def guess ( self ): return ( self . lower_limit + self . upper_limit ) // 2 def play ( self ): print ( f \"\u8bf7\u4f60\u9009\u62e9\u4e00\u4e2a\u5728 { self . lower_limit } \u5230 { self . upper_limit } \u4e4b\u95f4\u7684\u6570\u5b57\u3002\" ) while self . attempts < self . max_attempts : guess = self . guess () print ( f \"\u6211\u7684\u731c\u6d4b\u662f\uff1a { guess } \" ) response = input ( \"\u8bf7\u8f93\u5165 =, <, \u6216 > \u6765\u6307\u793a\u662f\u5426\u731c\u5bf9\uff1a\" ) self . attempts += 1 if response == '=' : print ( f \"\u6211\u5728\u7b2c { self . attempts } \u6b21\u731c\u5bf9\u4e86\uff01\" ) break elif response == '<' : self . upper_limit = guess - 1 elif response == '>' : self . lower_limit = guess + 1 else : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u64cd\u4f5c\u7b26\uff1a=, <, \u6216 >\" ) if self . attempts >= self . max_attempts : print ( \"\u4f60\u5728\u6b3a\u9a97\u6211\uff01\" ) def main (): lower_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5c0f\u7684\u6570\u5b57\uff1a\" )) upper_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5927\u7684\u6570\u5b57\uff1a\" )) guesser = ComputerGuesser ( lower_limit , upper_limit ) guesser . play () if __name__ == \"__main__\" : main () import math class ComputerGuesser : def __init__ ( self , lower_limit , upper_limit ): self . lower_limit = lower_limit self . upper_limit = upper_limit self . max_attempts = math . floor ( math . log2 ( upper_limit - lower_limit + 1 )) + 1 self . attempts = 0 @classmethod def guess ( cls , lower_limit , upper_limit ): return ( lower_limit + upper_limit ) // 2 @classmethod def play ( cls , lower_limit , upper_limit ): print ( f \"\u8bf7\u4f60\u9009\u62e9\u4e00\u4e2a\u5728 { lower_limit } \u5230 { upper_limit } \u4e4b\u95f4\u7684\u6570\u5b57\u3002\" ) attempts = 0 while attempts < cls . max_attempts : guess = cls . guess ( lower_limit , upper_limit ) print ( f \"\u6211\u7684\u731c\u6d4b\u662f\uff1a { guess } \" ) response = input ( \"\u8bf7\u8f93\u5165 =, <, \u6216 > \u6765\u6307\u793a\u662f\u5426\u731c\u5bf9\uff1a\" ) attempts += 1 if response == '=' : print ( f \"\u6211\u5728\u7b2c { attempts } \u6b21\u731c\u5bf9\u4e86\uff01\" ) break elif response == '<' : upper_limit = guess - 1 elif response == '>' : lower_limit = guess + 1 else : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u64cd\u4f5c\u7b26\uff1a=, <, \u6216 >\" ) if attempts >= cls . max_attempts : print ( \"\u4f60\u5728\u6b3a\u9a97\u6211\uff01\" ) def main (): lower_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5c0f\u7684\u6570\u5b57\uff1a\" )) upper_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5927\u7684\u6570\u5b57\uff1a\" )) ComputerGuesser . play ( lower_limit , upper_limit ) if __name__ == \"__main__\" : main () 10\uff0e\u6709\u4e00\u4e2a\u7b80\u5355\u7684\u8bfe\u7a0b\u7ba1\u7406\u7cfb\u7edf\uff0c\u5b83\u901a\u8fc7\u4f7f\u7528\u540d\u5b57\u548c\u4e00\u7ec4\u8003\u8bd5\u5206\u6570\u6765\u6a21\u62df\u5b66\u751f\u7684\u4fe1\u606f\u3002\u8fd9\u4e2a\u7cfb\u7edf\u5e94\u8be5\u80fd\u591f\u521b\u5efa\u4e00\u4e2a\u5177\u6709\u7ed9\u5b9a\u540d\u5b57\u548c\u5206\u6570\uff08\u8d77\u521d\u5747\u4e3a0\uff09\u7684\u5b66\u751f\u5bf9\u8c61\u3002\u7cfb\u7edf\u5e94\u8be5\u80fd\u591f\u8bbf\u95ee\u548c\u66ff\u6362\u6307\u5b9a\u4f4d\u7f6e\u5904\u7684\u5206\u6570\uff08\u4ece0\u5f00\u59cb\u8ba1\u6570\uff09\u3001\u5f97\u5230\u5b66\u751f\u6709\u591a\u5c11\u6b21\u8003\u8bd5\u3001\u5f97\u5230\u7684\u6700\u9ad8\u5206\u3001\u5f97\u5230\u7684\u5e73\u5747\u5206\u4ee5\u53ca\u5b66\u751f\u7684\u59d3\u540d\u3002\u9664\u6b64\u4e4b\u5916\uff0c\u5728\u6253\u5370\u5b66\u751f\u5bf9\u8c61\u7684\u65f6\u5019\uff0c\u5e94\u8be5\u50cf\u4e0b\u9762\u8fd9\u6837\u663e\u793a\u5b66\u751f\u7684\u59d3\u540d\u548c\u5206\u6570\uff1a Name : Ken Lambert Score 1 : 88 Score 2 : 77 Score 3 : 100 \u8bf7\u5b9a\u4e49\u4e00\u4e2a\u652f\u6301\u8fd9\u4e9b\u529f\u80fd\u548c\u884c\u4e3a\u7684Student\u7c7b\uff0c\u5e76\u4e14\u7f16\u5199\u4e00\u4e2a\u521b\u5efaStudent\u5bf9\u8c61\u5e76\u8fd0\u884c\u5176\u65b9\u6cd5\u7684\u7b80\u77ed\u7684\u6d4b\u8bd5\u51fd\u6570\u3002 class Student : def __init__ ( self , name ): self . name = name self . scores = [] def add_score ( self , score ): self . scores . append ( score ) def replace_score ( self , index , score ): if 0 <= index < len ( self . scores ): self . scores [ index ] = score else : print ( \"\u65e0\u6548\u7684\u5206\u6570\u7d22\u5f15\" ) def num_scores ( self ): return len ( self . scores ) def highest_score ( self ): if self . scores : return max ( self . scores ) else : return None def average_score ( self ): if self . scores : return sum ( self . scores ) / len ( self . scores ) else : return None def display ( self ): print ( f \"Name: { self . name } \" ) for i , score in enumerate ( self . scores , start = 1 ): print ( f \"Score { i } : { score } \" ) def test_student_class (): student = Student ( \"Ken Lambert\" ) student . add_score ( 88 ) student . add_score ( 77 ) student . add_score ( 100 ) student . display () print ( f \"Total Scores: { student . num_scores () } \" ) print ( f \"Highest Score: { student . highest_score () } \" ) print ( f \"Average Score: { student . average_score () } \" ) if __name__ == \"__main__\" : test_student_class ()","title":"\u57fa\u7840\u77e5\u8bc6\u56de\u987e"},{"location":"python/DataStructure/01_PythonFundmantal/#1","text":"","title":"1.\u57fa\u7840\u77e5\u8bc6\u56de\u987e"},{"location":"python/DataStructure/01_PythonFundmantal/#11","text":"\u793a\u4f8b\u4ee3\u7801 numberguess.py \u3002 import random def main (): smaller = int ( input ( \"\u8f93\u5165\u6700\u5c0f\u503c: \" )) larger = int ( input ( \"\u8f93\u5165\u6700\u5927\u503c: \" )) myNumber = random . randint ( smaller , larger ) count = 0 while True : count += 1 userNumber = int ( input ( \"\u8f93\u5165\u4f60\u731c\u7684\u503c: \" )) if userNumber < myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5c0f\uff01\" ) elif userNumber > myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5927\uff01\" ) else : print ( \"\u606d\u559c\uff0c\u4f60\u5728\u7b2c\" , count , \"\u6b21\u731c\u5bf9\u4e86!\" ) break if __name__ == \"__main__\" : main () \u8fd0\u884c\u4ee3\u7801\uff1a $ python3 numberguess.py Enter the smaller number: 10 Enter the larger number: 60 Enter your guess: 50 Too large Enter your guess: 40 Too large Enter your guess: 30 Too large Enter your guess: 20 Too large Enter your guess: 10 Too small Enter your guess: 15 You\u2019ve got it in 6 tries!","title":"1.1.\u57fa\u672c\u7a0b\u5e8f\u8981\u7d20"},{"location":"python/DataStructure/01_PythonFundmantal/#111","text":"\u53d8\u91cf\uff1asalary\uff0choursWorked\uff0cisAbsent \u5e38\u6570\uff1aABSOLUTE_ZERO\uff0cINTEREST_RATE \u51fd\u6570\u6216\u65b9\u6cd5\uff1aprintResults\uff0ccubeRoot\uff0cinput \u7c7b\uff1aBankAccount\uff0cSortedSet \u901a\u5e38\u7ea6\u5b9a\uff1a\u53d8\u91cf\u540d\u662f\u540d\u8bcd\u3001\u5f62\u5bb9\u8bcd\uff08\u5e03\u5c14\u503c\uff09\uff0c\u51fd\u6570\u548c\u65b9\u6cd5\u662f\u52a8\u8bcd\uff08\u8868\u793a\u52a8\u4f5c\uff09\u3001\u540d\u8bcd\u3001\u6216\u5f62\u5bb9\u8bcd\uff08\u8868\u793a\u8fd4\u56de\u7684\u503c\uff09\u3002 \u8bed\u6cd5\u5143\u7d20\uff1a Python\u4f7f\u7528\u7a7a\u767d\u7b26\uff08\u7a7a\u683c\u3001\u5236\u8868\u7b26\u3001\u6216\u6362\u884c\u7b26\uff09\u6765\u8868\u793a\u4e0d\u540c\u7c7b\u578b\u7684\u8bed\u53e5\u7684\u8bed\u6cd5\u3002 \u901a\u5e38\u7ea6\u5b9a\u4f7f\u75284\u4e2a\u7a7a\u683c\u4f5c\u4e3a\u9501\u8fdb\u5bbd\u5ea6\u3002","title":"1.1.1.\u62fc\u5199\u548c\u547d\u540d\u60ef\u4f8b"},{"location":"python/DataStructure/01_PythonFundmantal/#112","text":"\u5355\u5f15\u53f7 \u53cc\u5f15\u53f7 \u6210\u5bf9\u7684\u4e09\u4e2a\u53cc\u5f15\u53f7\uff08\u591a\u884c\u6587\u672c\uff09 \u6210\u5bf9\u7684\u4e09\u4e2a\u5355\u5f15\u53f7\uff08\u591a\u884c\u6587\u672c\uff09 \u8f6c\u4e49\u5b57\u7b26 \\ \uff08\u53cd\u659c\u6760\uff09","title":"1.1.2.\u5b57\u7b26\u4e32"},{"location":"python/DataStructure/01_PythonFundmantal/#113","text":"\u6807\u51c6\u8fd0\u7b97\u7b26\uff1a + \u3001 - \u3001 * \u3001 / \u3001 % \u7b97\u672f\u8868\u8fbe\u5f0f\u662f\u7528\u6807\u51c6\u8fd0\u7b97\u7b26\u548c\u4e2d\u7f00\u8868\u793a\u6cd5 \u6bd4\u8f83\u8fd0\u7b97\u7b26\uff1a < \u3001 <= \u3001 > \u3001 >= \u3001 == \u3001 != \uff0c\u7528\u4e8e\u6bd4\u8f83\u6570\u5b57\u6216\u5b57\u7b26\u4e32\uff0c\u8fd4\u56deTrue\u6216False \u8fd0\u7b97\u7b26 == \u7528\u4e8e\u6bd4\u8f83\u6570\u636e\u7ed3\u6784\u91cc\u7684\u5185\u5bb9\uff0c\u8fd0\u7b97\u7b26 is \u7528\u4e8e\u6bd4\u8f83\u4e24\u4e2a\u5bf9\u8c61\u7684\u6807\u8bc6\u662f\u5426\u4e00\u81f4 \u903b\u8f91\u8fd0\u7b97\u7b26\uff1a and \u3001 or \u3001 not \u3002\u628a0\u3001None\u3001\u7a7a\u5b57\u7b26\u4e32\u3001\u7a7a\u5217\u8868\u7b49\u89c6\u4e3aFalse\uff0c\u5927\u591a\u6570\u5176\u4ed6\u503c\u662f\u4e3aTrue \u4e0b\u6807\u8fd0\u7b97\u7b26\uff1a [] \uff0c\u4e0e\u591a\u9879\u96c6collection\u5bf9\u8c61\u4e00\u8d77\u4f7f\u7528 \u9009\u62e9\u5668\u8fd0\u7b97\u7b26\uff1a . \uff0c\u7528\u4e8e\u5f15\u7528\u4e00\u4e2a\u6a21\u5757\u3001\u7c7b\u6216\u5bf9\u8c61\u4e2d\u7684\u4e00\u4e2a\u5177\u540d\u7684\u9879 \u8fd0\u7b97\u7b26\u4f18\u5148\u7ea7\uff0c\u4f9d\u6b21\u662f\u9009\u62e9\u8fd0\u7b97\u7b26\u3001\u51fd\u6570\u8c03\u7528\u8fd0\u7b97\u7b26\u3001\u4e0b\u6807\u8fd0\u7b97\u7b26\u3001\u7b97\u672f\u8fd0\u7b97\u7b26\u3001\u6bd4\u8f83\u8fd0\u7b97\u7b26\u3001\u903b\u8f91\u8fd0\u7b97\u7b26\u3001\u8d4b\u503c\u8fd0\u7b97\u7b26\u3002\u62ec\u53f7\u7528\u4e8e\u8ba9\u5b50\u8868\u8fbe\u5f0f\u4f18\u5148\u8fd0\u884c\u3002","title":"1.1.3.\u8fd0\u7b97\u7b26\u548c\u8868\u8fbe\u5f0f"},{"location":"python/DataStructure/01_PythonFundmantal/#114","text":"\u51fd\u6570\u540d\u79f0\u540e\u9762\u8ddf\u7740\u7528\u62ec\u53f7\u62ec\u8d77\u6765\u7684\u53c2\u6570\u5217\u8868\uff0c\u4f8b\u5982\uff1a min(5,2) \u6807\u51c6\u51fd\u6570 \u5176\u4ed6\u6a21\u5757\u5bfc\u5165\u51fd\u6570","title":"1.1.4.\u51fd\u6570\u8c03\u7528"},{"location":"python/DataStructure/01_PythonFundmantal/#115print","text":"\u81ea\u52a8\u4e3a\u6bcf\u4e2a\u53c2\u6570\u8fd0\u884c str \u51fd\u6570\uff0c\u4ee5\u5f97\u5230\u5176\u5b57\u7b26\u4e32\u8868\u793a \u5728\u8f93\u51fa\u4e4b\u524d\u4f1a\u7528\u7a7a\u683c\u5427\u6bcf\u4e2a\u5b57\u7b26\u4e32\u9694\u5f00 \u9ed8\u8ba4\u4ee5\u6362\u884c\u7b26\u4f5c\u4e3a\u7ed3\u675f","title":"1.1.5.print\u51fd\u6570"},{"location":"python/DataStructure/01_PythonFundmantal/#116input","text":"\u6807\u51c6\u8f93\u5165\u51fd\u6570input\u4f1a\u4e00\u76f4\u7b49\u5f85\u7528\u6237\u901a\u8fc7\u952e\u76d8\u8f93\u5165\u6587\u672c \u63a5\u53d7\u4e00\u4e2a\u53ef\u9009\u7684\u5b57\u7b26\u4e32\u4f5c\u4e3a\u5176\u53c2\u6570","title":"1.1.6.input\u51fd\u6570"},{"location":"python/DataStructure/01_PythonFundmantal/#117","text":"Python\u5141\u8bb8\u7b97\u672f\u8868\u8fbe\u5f0f\u4e2d\u7684\u64cd\u4f5c\u6570\u5177\u6709\u4e0d\u540c\u7684\u6570\u503c\u7c7b\u578b\u3002\u4f8b\u5982\uff0c\u628aint\u7c7b\u578b\u7684\u64cd\u4f5c\u6570\u548cfloat\u7c7b\u578b\u7684\u64cd\u4f5c\u6570\u76f8\u52a0\uff0c\u4f1a\u5f97\u5230float\u7c7b\u578b\u7684\u6570\u3002 # \u8f93\u5165\u534a\u5f84\u6c42\u5706\u9762\u79ef radius = float ( input ( \"Radius: \" )) print ( \"The area is\" , 3.14 * radius ** 2 )","title":"1.1.7.\u7c7b\u578b\u8f6c\u6362\u51fd\u6570\u548c\u6df7\u5408\u6a21\u5f0f\u64cd\u4f5c"},{"location":"python/DataStructure/01_PythonFundmantal/#118","text":"\u5fc5\u9009\u53c2\u6570\u662f\u6ca1\u6709\u9ed8\u8ba4\u503c\u7684\uff1b\u53ef\u9009\u53c2\u6570\u6709\u9ed8\u8ba4\u503c\uff1b \u5728\u8c03\u7528\u51fd\u6570\u65f6\uff0c\u4f20\u9012\u7ed9\u5b83\u7684\u53c2\u6570\u6570\u91cf\u5fc5\u987b\u81f3\u5c11\u548c\u5fc5\u9009\u53c2\u6570\u7684\u6570\u91cf\u76f8\u540c\u3002 \u6807\u51c6\u51fd\u6570\u548cPython\u7684\u5e93\u51fd\u6570\u5728\u8c03\u7528\u65f6\u90fd\u4f1a\u5bf9\u4f20\u5165\u7684\u53c2\u6570\u8fdb\u884c\u7c7b\u578b\u68c0\u67e5","title":"1.1.8.\u53ef\u9009\u548c\u5173\u952e\u5b57\u51fd\u6570\u53c2\u6570"},{"location":"python/DataStructure/01_PythonFundmantal/#119","text":"\u7b80\u5355\u7684\u8d4b\u503c\u8bed\u53e5 PI = 3.1416 \u591a\u53d8\u91cf\u8d4b\u503c minValue, maxValue = 1, 100 \u53d8\u91cf\u4ea4\u6362 a, b = b, a \u8d4b\u503c\u8bed\u53e5\u5fc5\u987b\u5199\u5728\u4e00\u884c\u4ee3\u7801\u91cc\uff0c\u4f46\u662f\u53ef\u4ee5\u5728\u9017\u53f7\u3001\u5706\u62ec\u53f7\u3001\u82b1\u62ec\u53f7\u6216\u65b9\u62ec\u53f7\u4e4b\u540e\u6362\u884c\uff0c\u6216\u8005\u7528\u8f6c\u4e49\u7b26 \\ \u8fdb\u884c\u6362\u884c\u3002 \u6362\u884c\u793a\u4f8b\uff1a minValue = min ( 100 , 200 ) product = max ( 100 , 200 ) \\ * 30","title":"1.1.9.\u53d8\u91cf\u548c\u8d4b\u503c\u8bed\u53e5"},{"location":"python/DataStructure/01_PythonFundmantal/#1110","text":"\u53d8\u91cf\u90fd\u53ef\u4ee5\u88ab\u6307\u5b9a\u4e3a\u4efb\u4f55\u7c7b\u578b\u7684\u503c\u3002\u8fd9\u4e9b\u53d8\u91cf\u5e76\u4e0d\u50cf\u5176\u4ed6\u8bed\u8a00\u90a3\u6837\u88ab\u58f0\u660e\u4e3a\u7279\u5b9a\u7684\u7c7b\u578b\uff0c\u800c\u53ea\u662f\u88ab\u8d4b\u4e86\u4e00\u4e2a\u503c \u503c\u548c\u5bf9\u8c61\u90fd\u662f\u6709\u7c7b\u578b\u7684\uff0c\u4f1a\u5728\u8fd0\u884c\u65f6\u8fdb\u884c\u6570\u636e\u7c7b\u578b\u68c0\u67e5","title":"1.1.10.\u6570\u636e\u7c7b\u578b"},{"location":"python/DataStructure/01_PythonFundmantal/#1111import","text":"import \u8bed\u53e5\u4f7f\u5f97\u4e00\u4e2a\u6a21\u5757\u4e2d\u7684\u6807\u8bc6\u7b26\u53ef\u4ee5\u88ab\u53e6\u4e00\u4e2a\u7a0b\u5e8f\u6240\u89c1\u5230\u3002\u6807\u8bc6\u7b26\u53ef\u4ee5\u662f\u5bf9\u8c61\u540d\u3001\u51fd\u6570\u540d\u6216\u7c7b\u540d \u5bfc\u5165\u6a21\u5757\u540d\u79f0\uff0c\u4f8b\u5982 import math \u5bfc\u5165\u6a21\u5757\u4e2d\u7684\u6807\u8bc6\u7b26\uff0c\u4f8b\u5982\uff1a from math import sqrt \uff0c\u6216\u8005 from math import pi, sqrt \u4e5f\u53ef\u4ee5\u4f7f\u7528\u7b26\u53f7 * \u5bfc\u5165\u4e00\u4e2a\u6a21\u5757\u4e2d\u7684\u6240\u6709\u540d\u79f0\uff0c\u4f46\u4e0d\u63a8\u8350","title":"1.1.11.import\u8bed\u53e5"},{"location":"python/DataStructure/01_PythonFundmantal/#12","text":"","title":"1.2.\u63a7\u5236\u8bed\u53e5"},{"location":"python/DataStructure/01_PythonFundmantal/#121","text":"\u5355\u5411if\u8bed\u53e5\u7684\u8bed\u6cd5 if < Boolean expression > : < sequence of statements > \u53cc\u5411if\u8bed\u53e5\u7684\u8bed\u6cd5 if < Boolean expression > : < sequence of statements > else : < sequence of statements > \u591a\u5411if\u8bed\u53e5\u7684\u8bed\u6cd5 if < Boolean expression > : < sequence of statements > elif < Boolean expression > : < sequence of statements > ... else : < sequence of statements >","title":"1.2.1.\u6761\u4ef6\u8bed\u53e5"},{"location":"python/DataStructure/01_PythonFundmantal/#122if-name-main","text":"\u793a\u4f8b\u4ee3\u7801 numberguess.py \u3002 import random def main (): smaller = int ( input ( \"\u8f93\u5165\u6700\u5c0f\u503c: \" )) larger = int ( input ( \"\u8f93\u5165\u6700\u5927\u503c: \" )) myNumber = random . randint ( smaller , larger ) count = 0 while True : count += 1 userNumber = int ( input ( \"\u8f93\u5165\u4f60\u731c\u7684\u503c: \" )) if userNumber < myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5c0f\uff01\" ) elif userNumber > myNumber : print ( \"\u4f60\u731c\u7684\u592a\u5927\uff01\" ) else : print ( \"\u606d\u559c\uff0c\u4f60\u5728\u7b2c\" , count , \"\u6b21\u731c\u5bf9\u4e86!\" ) break if __name__ == \"__main__\" : main () \u4e0a\u9762\u7684if\u8bed\u53e5\u7684\u4f5c\u7528\u662f\uff0c \u8981\u4e48\u5c06\u6a21\u5757\u5f53\u4f5c\u4e00\u4e2a\u72ec\u7acb\u7684\u7a0b\u5e8f\u8fd0\u884c\uff0c\u8be5\u6a21\u5757\u7684 _name_ \u53d8\u91cf\u4f1a\u8bbe\u7f6e\u4e3a\u5b57\u7b26\u4e32 _main_ \uff0c\u624d\u4f1a\u6267\u884c main() \u51fd\u6570 \u8981\u4e48\u4ece\u53e6\u4e00\u4e2a\u6a21\u5757\u4e2d\u5bfc\u5165\uff0c\u8be5\u6a21\u5757\u7684 _name_ \u53d8\u91cf\u4f1a\u8bbe\u7f6e\u8be5\u6a21\u5757\u7684\u540d\u79f0\uff0c\u4e0a\u4f8b\u4e2d\u5373 numberguess","title":"1.2.2.\u4f7f\u7528if name == \"main\""},{"location":"python/DataStructure/01_PythonFundmantal/#123","text":"\u901a\u5e38\uff1a \u4e00\u822c\u4f1a\u4f7f\u7528for\u5faa\u73af\u6765\u8fed\u4ee3\u786e\u5b9a\u8303\u56f4\u7684\u503c\u6216\u503c\u7684\u5e8f\u5217 \u5982\u679c\u7ee7\u7eed\u5faa\u73af\u7684\u6761\u4ef6\u662f\u67d0\u4e2a\u5e03\u5c14\u8868\u8fbe\u5f0f\uff0c\u4e00\u822c\u4f1a\u4f7f\u7528while\u5faa\u73af while \u8bed\u6cd5\u683c\u5f0f\uff1a while < Boolean expression > : < sequence of statements > \u793a\u4f8b\uff1a # \u8ba1\u7b97\u4ece1\u523010\u7684\u4e58\u79ef\u5e76\u8f93\u51fa\u7ed3\u679c result = 1 value = 1 while value <= 10 : result *= value value += 1 print ( result , value ) # \u8fd0\u884c\u7ed3\u679c # 3628800 11 for \u8bed\u6cd5\u683c\u5f0f\uff1a for < variable > in < iterable object > : < sequence of statements > \u793a\u4f8b\uff1a # \u8ba1\u7b97\u4ece1\u523010\u7684\u4e58\u79ef\u5e76\u8f93\u51fa\u7ed3\u679c result = 1 value = 1 for value in range ( 1 , 11 ): result *= value value += 1 print ( result , value ) # \u8fd0\u884c\u7ed3\u679c # 3628800 11","title":"1.2.3.\u5faa\u73af\u8bed\u53e5"},{"location":"python/DataStructure/01_PythonFundmantal/#13","text":"Python\u4e2d\u7684\u5b57\u7b26\u4e32\u4e5f\u662f\u4e00\u4e2a\u590d\u5408\u5bf9\u8c61 Python\u7684\u5b57\u7b26\u4e32\u7c7b\u578b\u540d\u4e3a str \u7ea6\u5b9a\uff1a \u628a\u5355\u5b57\u7b26\u7684\u5b57\u7b26\u4e32\u7528\u5355\u5f15\u53f7\u62ec\u8d77\u6765 \u628a\u591a\u5b57\u7b26\u7684\u5b57\u7b26\u4e32\u7528\u53cc\u5f15\u53f7\u62ec\u8d77\u6765","title":"1.3.\u5b57\u7b26\u4e32\u53ca\u5176\u8fd0\u7b97"},{"location":"python/DataStructure/01_PythonFundmantal/#131","text":"\u6bd4\u8f83\u8fd0\u7b97\u7b26\uff0c\u662f\u6309\u7167ASCII\u7801\u7684\u987a\u5e8f\u6bd4\u8f83\u4e24\u4e2a\u5b57\u7b26\u4e32\u4e2d\u6bcf\u4e2a\u4f4d\u7f6e\u7684\u5b57\u7b26\u5bf9 \u793a\u4f8b\uff1a print ( 'A' > 'a' ) # \u8fd0\u884c\u7ed3\u679c False print ( 'A' < 'a' ) # \u8fd0\u884c\u7ed3\u679c True + \u8fd0\u7b97\u7b26\u751f\u6210\u5e76\u8fd4\u56de\u4e00\u4e2a\u5305\u542b\u4e24\u4e2a\u64cd\u4f5c\u6570\u7684\u65b0\u5b57\u7b26\u4e32 \u793a\u4f8b\uff1a print ( \"Hello\" + \"Python\" ) # \u8fd0\u884c\u7ed3\u679c HelloPython \u4e0b\u6807\u8fd0\u7b97\u7b26\uff0c\u8303\u56f4\u662f\u4ece0\u5230\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u51cf\u53bb1\u7684\u4e00\u4e2a\u6574\u6570\u3002 \u8fd0\u7b97\u7b26\u8fd4\u56de\u5728\u5b57\u7b26\u4e32\u4e2d\u8be5\u4f4d\u7f6e\u7684\u5b57\u7b26\u3002 \u793a\u4f8b\uff1a print ( \"Greater\" [ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1ar \u5f53\u7d22\u5f15\u4e3a\u8d1f\u503c\u65f6\uff0cPython\u4f1a\u628a\u8fd9\u4e2a\u503c\u548c\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u76f8\u52a0\uff0c\u4ee5\u786e\u5b9a\u8981\u8fd4\u56de\u7684\u5b57\u7b26\u7684\u4f4d\u7f6e\u3002\u8d1f\u7d22\u5f15\u503c\u4e0d\u5f97\u5c0f\u4e8e\u5b57\u7b26\u4e32\u957f\u5ea6\u7684\u8d1f\u503c\u3002 print ( \"Greater\" [ - 3 ]) # \u8fd0\u884c\u7ed3\u679c\uff1at print ( \"Greater\" [ - 9 ]) # \u8fd0\u884c\u7ed3\u679c\uff1aIndexError: string index out of range \u5207\u7247\u8fd0\u7b97\u7b26\uff08slice operator\uff09\uff0c\u4e0b\u6807\u8fd0\u7b97\u7b26\u7684\u4e00\u79cd\u53d8\u4f53\u3002 \u8bed\u6cd5\u683c\u5f0f\uff1a [:] \uff1a\u8303\u56f4\u662f\u4ece0\u5230\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u51cf\u53bb1\u7684\u6574\u6570 \uff1a\u8303\u56f4\u662f\u4ece0\u5230\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u7684\u6574\u6570 \u5207\u7247\u68c0\u7d22\u89c4\u5219\uff1a \u8fd4\u56de\u8fd9\u6837\u4e00\u4e2a\u5b50\u5b57\u7b26\u4e32\uff1a\u8fd9\u4e2a\u5b50\u5b57\u7b26\u4e32\u4f1a\u4ece \u7d22\u5f15\u5904\u7684\u5b57\u7b26\u5f00\u59cb\uff0c\u5230 \u7d22\u5f15\u51cf1\u7684\u4f4d\u7f6e\u4f5c\u4e3a\u7ed3\u675f\u3002 \u5982\u679c\u7701\u7565 \u7d22\u5f15\uff0c\u90a3\u4e48\u5207\u7247\u8fd0\u7b97\u7b26\u5c06\u8fd4\u56de\u4e00\u4e2a\u4ee5\u5f53\u524d\u5b57\u7b26\u4e32\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\u4f5c\u4e3a\u5f00\u5934\u7684\u5b50\u5b57\u7b26\u4e32\u3002 \u5982\u679c\u7701\u7565 \u7d22\u5f15\uff0c\u90a3\u4e48\u5207\u7247\u8fd0\u7b97\u7b26\u5c06\u8fd4\u56de\u4e00\u4e2a\u4ee5\u5f53\u524d\u5b57\u7b26\u4e32\u7684\u6700\u540e\u4e00\u4e2a\u5b57\u7b26\u4f5c\u4e3a\u7ed3\u5c3e\u7684\u5b50\u5b57\u7b26\u4e32\u3002 \u5982\u679c\u7701\u7565\u8fd9\u4e24\u4e2a\u503c\uff0c\u90a3\u4e48\u5207\u7247\u8fd0\u7b97\u7b26\u4f1a\u8fd4\u56de\u6574\u4e2a\u5b57\u7b26\u4e32\u3002 \u793a\u4f8b\uff1a print ( \"Greater\" [:]) # \u8fd4\u56de\u5b57\u4e32 Greater print ( \"Greater\" [ 2 :]) # \u8fd4\u56de\u5b57\u4e32 eater print ( \"Greater\" [: 2 ]) # \u8fd4\u56de\u5b57\u4e32 Gr print ( \"Greater\" [ 2 : 5 ]) # \u8fd4\u56de\u5b57\u4e32 eat","title":"1.3.1.\u8fd0\u7b97\u7b26"},{"location":"python/DataStructure/01_PythonFundmantal/#132","text":"\u683c\u5f0f\u5316\u5b57\u7b26\u4e32\u91cc\u7684\u6570\u636e\u5b57\u7b26\u4ee5\u53ca\u6ee1\u8db3\u7ed9\u5b9a\u57fa\u51c6\u7ebf\u7684\u9644\u52a0\u7a7a\u683c\u7684\u603b\u6570\u79f0\u4e3a\u5b83\u7684\u5b57\u6bb5\u5bbd\u5ea6\uff08field width\uff09\u3002 print \u51fd\u6570\u4f1a\u5728\u9047\u5230\u7b2c\u4e00\u5217\u65f6\u81ea\u52a8\u5f00\u59cb\u6253\u5370\u8f93\u51fa\u57fa\u51c6\u7ebf\u3002 \u793a\u4f8b\uff0c\u901a\u8fc7print\u8bed\u53e5\u8f93\u51fa2\u5217\u3002 for i in range ( 7 , 11 ): print ( i , 10 * i ) # \u8fd0\u884c\u7ed3\u679c # 7 70 # 8 80 # 9 90 # 10 100 Python\u7684\u901a\u7528\u683c\u5f0f\u5316\u673a\u5236 \u8bed\u6cd5\u683c\u5f0f % \u548c % (, \u2026, ) \u3002 \u683c\u5f0f\u5316\u5b57\u7b26\u4e32\u65f6\uff0c \u4f7f\u7528 %s \u8868\u793a\u6cd5\u3002\u5f53\u5b57\u6bb5\u5bbd\u5ea6\u4e3a\u6b63\u65f6\uff0c\u6570\u636e\u662f\u53f3\u5bf9\u9f50\u7684\uff1b\u5f53\u5b57\u6bb5\u5bbd\u5ea6\u4e3a\u8d1f\u65f6\uff0c\u6570\u636e\u662f\u5de6\u5bf9\u9f50\u7684\u3002 \u683c\u5f0f\u6574\u6570\u65f6\uff0c \u4f7f\u7528 %d \u8868\u793a\u6cd5\u3002 \u683c\u5f0f\u6d6e\u70b9\u6570\u65f6\uff0c \u4f7f\u7528 %.f \u8868\u793a\u6cd5\uff0c\u5176\u4e2d . \u8fd9\u4e00\u90e8\u5206\u662f\u53ef\u9009\u7684\u3002 \u793a\u4f8b\uff1a print ( \" %6s \" % \"four\" ) print ( \" %-6s \" % \"four\" ) # four # four for i in range ( 7 , 11 ): print ( \" %-3d%5d \" % ( i , 10 * i )) # 7 70 # 8 80 # 9 90 # 10 100 for i in range ( 7 , 11 ): print ( \" %-3d%5.3f \" % ( i , i / 3 )) # 7 2.333 # 8 2.667 # 9 3.000 # 10 3.333 \u4e0b\u4f8b\u5bf9\u6bd4\u4e86\u6d6e\u70b9\u6570\u5728\u4f7f\u7528\u4e86\u683c\u5f0f\u5b57\u7b26\u4e32\u548c\u6ca1\u6709\u4f7f\u7528\u683c\u5f0f\u5b57\u7b26\u4e32\u8fd9\u4e24\u79cd\u60c5\u51b5\u4e0b\u7684\u8f93\u51fa\u5dee\u5f02\u3002 salary = 100.00 print ( \"Salary: $\" + str ( salary )) # Salary: $100.0 print ( \"Salary: $ %0.2f \" % salary ) # Salary: $100.00 \u6ce8\u610f\uff0c\u4e0b\u4f8b\u4e2dPython\u7ed9\u6570\u5b57\u6dfb\u52a0\u4e86\u4e00\u4e2a\u7cbe\u5ea6\u4f4d\u6570\uff0c\u5e76\u4e14\u5176\u5de6\u4fa7\u586b\u5145\u7a7a\u683c\uff0c\u4ece\u800c\u5b9e\u73b0\u4e86\u5b57\u6bb5\u5bbd\u5ea6\u4e3a6\u3001\u7cbe\u5ea6\u4e3a3\u7684\u8bbe\u7f6e\u3002\u8fd9\u4e2a\u5bbd\u5ea6\u5305\u542b\u5c0f\u6570\u70b9\u540e\u6240\u5360\u636e\u7684\u4f4d\u7f6e\u3002 print ( \" %6.3f \" % 3.14 ) # \u5de6\u4fa7\u586b\u5145\u4e86\u7a7a\u683c # 3.140 print ( \" %-6.3f \" % 3.14 ) # 3.140","title":"1.3.2.\u5b57\u7b26\u4e32\u683c\u5f0f\u5316"},{"location":"python/DataStructure/01_PythonFundmantal/#133","text":"\u8bed\u6cd5\u683c\u5f0f\uff1a .() \u793a\u4f8b\uff1a print ( \"greater\" . isupper ()) # \u8fd0\u884c\u7ed3\u679c # False print ( \"greater\" . upper ()) # \u8fd0\u884c\u7ed3\u679c # GREATER print ( \"greater\" . startswith ( \"great\" )) # \u8fd0\u884c\u7ed3\u679c # True print ( len ( \"greater\" )) print ( \"greater\" . __len__ ()) # \u8fd0\u884c\u7ed3\u679c # 7 print ( \"great\" + \"er\" ) print ( \"great\" . __add__ ( \"er\" )) # \u8fd0\u884c\u7ed3\u679c # greater print ( \"e\" in \"great\" ) print ( \"great\" . __contains__ ( \"e\" )) # \u8fd0\u884c\u7ed3\u679c # True \u63d0\u793a\uff1a dir() \u65b9\u6cd5\u4f1a\u8fd4\u56de\u6240\u4f20\u9012\u7684\u5bf9\u8c61\u7684\u6709\u6548\u5c5e\u6027\uff0c\u8bed\u6cd5\u683c\u5f0f\uff1a dir(object) help() \u51fd\u6570\u67e5\u770b\u51fd\u6570\u6216\u6a21\u5757\u7528\u9014\u7684\u8be6\u7ec6\u8bf4\u660e\uff0c\u8bed\u6cd5\u683c\u5f0f\uff1a help(object) dir ( str ) help ( str . __contains__ )","title":"1.3.3.\u5bf9\u8c61\u548c\u65b9\u6cd5\u8c03\u7528"},{"location":"python/DataStructure/01_PythonFundmantal/#14","text":"Python\u4e2d\u7684\u591a\u9879\u96c6\uff08collections\uff09\u6307\u80fd\u591f\u5305\u542b\u5143\u7d20\u7684\u6570\u636e\u7ed3\u6784\u3002\u591a\u9879\u96c6\u6a21\u5757\u63d0\u4f9b\u4e86\u4e0d\u540c\u7c7b\u578b\u7684\u5bb9\u5668\u3002\u5bb9\u5668\u662f\u7528\u4e8e\u5b58\u50a8\u4e0d\u540c\u5bf9\u8c61\u5e76\u63d0\u4f9b\u8bbf\u95ee\u6240\u5305\u542b\u5bf9\u8c61\u4ee5\u53ca\u5bf9\u5b83\u4eec\u8fdb\u884c\u8fed\u4ee3\u7684\u65b9\u5f0f\u7684\u5bf9\u8c61\u3002\u4e00\u4e9b\u5185\u7f6e\u7684\u5bb9\u5668\u6709\u5143\u7ec4\uff08Tuple\uff09\u3001\u5217\u8868\uff08List\uff09\u3001\u5b57\u5178\uff08Dictionary\uff09\u7b49\u3002 \u4ee5\u4e0b\u662f\u7531collections\u6a21\u5757\u63d0\u4f9b\u7684\u4e0d\u540c\u5bb9\u5668\u7684\u5217\u8868\uff1a \u8ba1\u6570\u5668\uff08Counters\uff09 \u6709\u5e8f\u5b57\u5178\uff08OrderedDict\uff09 \u9ed8\u8ba4\u5b57\u5178\uff08DefaultDict\uff09 \u94fe\u6620\u5c04\uff08ChainMap\uff09 \u547d\u540d\u5143\u7ec4\uff08NamedTuple\uff09 \u53cc\u5411\u961f\u5217\uff08DeQue\uff09 \u7528\u6237\u5b57\u5178\uff08UserDict\uff09 \u7528\u6237\u5217\u8868\uff08UserList\uff09 \u7528\u6237\u5b57\u7b26\u4e32\uff08UserString\uff09","title":"1.4.\u5185\u7f6e\u591a\u9879\u96c6\u53ca\u5176\u64cd\u4f5c"},{"location":"python/DataStructure/01_PythonFundmantal/#141","text":"\u5217\u8868\uff08list\uff09\u662f\u96f6\u4e2a\u6216\u591a\u4e2aPython\u5bf9\u8c61\u7684\u4e00\u4e2a\u5e8f\u5217\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u901a\u5e38\u79f0\u4e3a\u9879\uff08item\uff09\u3002 \u5217\u8868\u7684\u8868\u73b0\u5f62\u5f0f\u662f\uff1a\u7528\u65b9\u62ec\u53f7\u62ec\u8d77\u6574\u4e2a\u5217\u8868\uff0c\u5e76\u7528\u9017\u53f7\u5206\u9694\u5143\u7d20\u3002 \u793a\u4f8b\uff1a [] # \u7a7a\u5217\u8868 [ \"greater\" , \"less\" , 10 ] # \u542b\u4e0d\u540c\u7c7b\u578b\u7684\u5217\u8868 [ \"greater\" , [ \"less\" , 10 ]] # \u542b\u5185\u5d4c\u5217\u8868\u7684\u5217\u8868 \u5217\u8868\u7684\u5207\u7247\u64cd\u4f5c\uff1a \u548c\u5b57\u7b26\u4e32\u7c7b\u4f3c\uff0c\u53ef\u4ee5\u901a\u8fc7\u6807\u51c6\u8fd0\u7b97\u7b26\u6267\u884c\u5207\u7247\u6216\u8fde\u63a5\u64cd\u4f5c\uff0c\u8fd4\u56de\u7ed3\u679c\u4e5f\u662f\u5217\u8868\u3002 \u548c\u5b57\u7b26\u4e32\u4e0d\u540c\uff0c\u5217\u8868\u662f\u53ef\u53d8\u7684\uff0c\u5373\uff0c\u53ef\u4ee5\u66ff\u6362\u3001\u63d2\u5165\u6216\u5220\u9664\u5217\u8868\u4e2d\u6240\u5305\u542b\u7684\u9879\u3002 \u5207\u7247\u548c\u8fde\u63a5\u8fd0\u7b97\u7b26\u6240\u8fd4\u56de\u7684\u5217\u8868\u662f\u65b0\u7684\u5217\u8868\uff0c\u800c\u4e0d\u662f\u6700\u521d\u5217\u8868\u7684\u4e00\u90e8\u5206\uff1b \u5217\u8868\u7c7b\u578b\u5305\u542b\u4e86\u51e0\u4e2a\u53eb\u4f5c\u53d8\u5f02\u5668\uff08mutator\uff09\u7684\u65b9\u6cd5\uff0c\u7528\u4e8e\u4fee\u6539\u5217\u8868\u7684\u7ed3\u6784\u3002 \u53ef\u4ee5\u901a\u8fc7 dir(list) \u6765\u67e5\u770b\u65b9\u6cd5\uff0c\u5305\u62ec\u53d8\u5f02\u5668\uff08mutator\uff09\u7684\u65b9\u6cd5\u3002 dir ( list ) # \u8fd0\u884c\u7ed3\u679c # ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] \u6700\u5e38\u7528\u7684\u5217\u8868\u53d8\u5f02\u5668\u65b9\u6cd5\u662f append \u3001 insert \u3001 pop \u3001 remove \u548c sort \u3002 \u793a\u4f8b\uff1a myList = [] # myList\u5f53\u524d\u4e3a[] myList . append ( 34 ) # myList\u5f53\u524d\u4e3a[34]\uff0c\u9ed8\u8ba4\u5c3e\u90e8\u63d2\u5165 myList . append ( 22 ) # myList\u5f53\u524d\u4e3a[34, 22]\uff0c\u9ed8\u8ba4\u5c3e\u90e8\u63d2\u5165 myList . sort () # myList\u5f53\u524d\u4e3a[22, 34] myList . pop () # \u9ed8\u8ba4\u4ece\u7d22\u5f15\u4f4d[0]\u5220\u9664\uff0c\u8fd4\u56de\u7ed3\u679c22\uff1bmyList\u5f53\u524d\u4e3a[34] myList . insert ( 0 , 22 ) # \u5728\u6307\u5b9a\u7d22\u5f15\u4f4d[0]\u63d2\u5165\uff1bmyList\u5f53\u524d\u4e3a[22, 34] myList . insert ( 1 , 55 ) # \u5728\u6307\u5b9a\u7d22\u5f15\u4f4d[1]\u63d2\u5165\uff1bmyList\u5f53\u524d\u4e3a[22, 55, 34] myList . pop ( 1 ) # \u6307\u5b9a\u7d22\u5f15\u4f4d[1]\u5220\u9664\uff0c\u8fd4\u56de\u7ed3\u679c55\uff1bmyList\u5f53\u524d\u4e3a[22, 34] myList . remove ( 22 ) # \u5220\u9664\u9996\u4e2a\u5339\u914d\u9879\u7684\u5143\u7d20[22]\uff1bmyList\u5f53\u524d\u4e3a[34] myList . remove ( 55 ) # \u62a5ValueError\u9519\uff0clist.remove(x): x not in list \u5bf9\u4e8e\u5b57\u7b26\u4e32\uff0csplit\u65b9\u6cd5\u4f1a\u4ece\u5b57\u7b26\u4e32\u91cc\u5206\u79bb\u51fa\u4e00\u4e2a\u5355\u8bcd\u5217\u8868\uff0c\u800cjoin\u65b9\u6cd5\u4f1a\u628a\u5355\u8bcd\u5217\u8868\u8fde\u5728\u4e00\u8d77\u4ece\u800c\u5f62\u6210\u5b57\u7b26\u4e32\u3002\u4f8b\u5982\uff1a print ( \"Python is cool\" . split ()) # \u8fd0\u884c\u7ed3\u679c\uff1a # ['Python', 'is', 'cool'] print ( \" \" . join ([ \"Python\" , \"is\" , \"cool\" ])) # \u8fd0\u884c\u7ed3\u679c\uff1a # Python is cool \u5bf9\u4e8e\u5217\u8868\u7279\u6027\u548c\u64cd\u4f5c\u7684\u8be6\u7ec6\u7ec3\u4e60\uff0c\u53c2\u8003 Python\u8bed\u8a00\u57fa\u7840@github \u6216\u8005 Python\u8bed\u8a00\u57fa\u7840@web \u4e2d\u201c1.3 \u5217\u8868\uff08list\uff09\u201d\u7684\u5185\u5bb9\u3002","title":"1.4.1.\u5217\u8868"},{"location":"python/DataStructure/01_PythonFundmantal/#142","text":"\u5143\u7ec4\uff08tuple\uff09\u662f\u4e00\u4e2a\u4e0d\u53ef\u53d8\u7684\u5143\u7d20\u5e8f\u5217\u3002 \u5143\u7ec4\uff08tuple\uff09\u5f62\u5f0f\u662f\u7528\u5706\u62ec\u53f7\u5c06\u5404\u9879\u62ec\u8d77\u6765\uff0c\u5e76\u4e14\u5fc5\u987b\u81f3\u5c11\u5305\u542b\u4e24\u4e2a\u9879\u3002 \u5143\u7ec4\u5b9e\u9645\u4e0a\u5c31\u50cf\u5217\u8868\u4e00\u6837\uff0c\u53ea\u4e0d\u8fc7\u5b83\u6ca1\u6709\u53d8\u5f02\u5668\u65b9\u6cd5\u3002 \u5982\u679c\u8981\u4f7f\u5143\u7ec4\u53ea\u5305\u542b\u4e00\u4e2a\u5143\u7d20\uff0c\u5219\u5fc5\u987b\u5728\u5143\u7ec4\u91cc\u5305\u542b\u9017\u53f7\u3002 \u5bf9\u6bd4\u4e0b\u9762\u7684\u533a\u522b\uff1a print (( 21 )) # (21)\u88ab\u89c6\u4e3a\u6574\u6570 # \u8fd0\u884c\u7ed3\u679c\uff1a # 21 print (( 21 ,)) # (21,)\u88ab\u89c6\u4e3a\u5143\u7ec4 # \u8fd0\u884c\u7ed3\u679c\uff1a # (21,) \u5bf9\u4e8e\u5217\u8868\u7279\u6027\u548c\u64cd\u4f5c\u7684\u8be6\u7ec6\u7ec3\u4e60\uff0c\u53c2\u8003 Python\u8bed\u8a00\u57fa\u7840@github \u6216\u8005 Python\u8bed\u8a00\u57fa\u7840@web \u4e2d\u201c1.6 \u5143\u7ec4\uff08tuple\uff09\u201d\u7684\u5185\u5bb9\u3002","title":"1.4.2.\u5143\u7ec4"},{"location":"python/DataStructure/01_PythonFundmantal/#143","text":"for \u5faa\u73af\u53ef\u4ee5\u7528\u6765\u904d\u5386\u5e8f\u5217\uff08\u5982\u5b57\u7b26\u4e32\u3001\u5217\u8868\u6216\u5143\u7ec4\uff09\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002 \u904d\u5386\u5217\u8868\uff1a myList = [ 67 , 100 , 'Monday' , \"It's good\" ] for item in myList : print ( item ) myList = [ 67 , 100 , 'Monday' , \"It's good\" ] for idx in range ( len ( myList )): print ( myList [ idx ]) \u904d\u5386\u5143\u7ec4\uff1a myString = \"I love Python\" myList = myString . split () myTuple = tuple ( myList ) for i in myTuple : print ( i ) \u904d\u5386\u5b57\u7b26\u4e32\uff1a(\u6ce8\u610f\uff0c\u662f\u904d\u5386\u5b57\u7b26\uff0c\u4e0d\u662f\u5355\u8bcd) myString = \"I love Python\" for i in myString : print ( i ) myString = \"I love Python\" for i in range ( len ( myString )): print ( myString [ i ]) myString = \"I love Python\" for i in enumerate ( myString ): print ( i ) myString = \"I love Python\" for i , j in enumerate ( myString ): print ( i , j ) myString = \"I love Python\" for i in iter ( myString ): print ( i ) \u5982\u679c\u6309\u7167\u5355\u8bcd\u904d\u5386\u5b57\u7b26\u4e32\uff0c\u5219\u9700\u8981\u5148\u628a\u5b57\u4e32\u6309\u5355\u8bcd\u62c6\u89e3\u4e3a\u5217\u8868\u3002 myString = \"I love Python\" myList = \"I love Python\" . split () for i in myList : print ( i ) \u5bf9\u4e8e\u5217\u8868\u548c\u5143\u7ec4\u904d\u5386\u7684\u66f4\u591a\u4f8b\u5b50\uff0c\u5305\u62ec\u62c6\u5305\u904d\u5386\uff0c\u53c2\u8003 Python\u8bed\u8a00\u57fa\u7840@github \u6216\u8005 Python\u8bed\u8a00\u57fa\u7840@web \u7684\u5185\u5bb9\u3002","title":"1.4.3.\u5e8f\u5217\u904d\u5386"},{"location":"python/DataStructure/01_PythonFundmantal/#144","text":"\u5b57\u5178\uff08dictionary\uff09\u5305\u542b\u96f6\u4e2a\u6216\u591a\u4e2a\u6761\u76ee\u3002 \u6bcf\u4e2a\u6761\u76ee\uff08entry\uff09\u90fd\u6709\u552f\u4e00\u7684\u952e\u548c\u5b83\u6240\u5bf9\u5e94\u7684\u503c\u76f8\u5173\u8054\u3002 \u952e\u901a\u5e38\u662f\u5b57\u7b26\u4e32\u6216\u6574\u6570\uff0c\u800c\u503c\u662f\u4efb\u610f\u7684Python\u5bf9\u8c61\u3002 \u4e0b\u6807\u8fd0\u7b97\u7b26\u53ef\u4ee5\u7528\u4e8e\u8bbf\u95ee\u4e00\u4e2a\u7ed9\u5b9a\u952e\u7684\u503c\uff0c\u7ed9\u4e00\u4e2a\u65b0\u952e\u6dfb\u52a0\u4e00\u4e2a\u503c\uff0c\u4ee5\u53ca\u66ff\u6362\u7ed9\u5b9a\u952e\u7684\u503c\u3002 pop \u65b9\u6cd5\u4f1a\u5220\u9664\u4e00\u4e2a\u6761\u76ee\u5e76\u8fd4\u56de\u7ed9\u5b9a\u952e\u6240\u5bf9\u5e94\u7684\u503c\u3002 keys \u65b9\u6cd5\u4f1a\u628a\u6240\u6709\u952e\u8fd4\u56de\u6210\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 values \u65b9\u6cd5\u4f1a\u628a\u6240\u6709\u503c\u8fd4\u56de\u6210\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 \u793a\u4f8b\uff1a {} # \u7a7a\u5b57\u5178 { \"name\" : \"Ken\" } # \u542b\u4e00\u4e2a\u6761\u76ee { \"name\" : \"Ken\" , \"age\" : 67 } # \u542b\u4e8c\u4e2a\u6761\u76ee { \"hobbies\" :[ \"reading\" , \"running\" ]} # \u542b\u4e00\u4e2a\u6761\u76ee\uff0c\u5176\u4e2d\u503c\u662f\u4e00\u4e2a\u5217\u8868 \u5b57\u5178\u672c\u8eab\u4e5f\u662f\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002\u53ef\u4ee5\u901a\u8fc7for\u8bed\u53e5\u8fdb\u884c\u904d\u5386\u952e\u6216/\u548c\u503c\u3002 myDict = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } for keys in myDict : print ( keys , myDict [ keys ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # name Ming # id 1001 # age 35","title":"1.4.4.\u5b57\u5178"},{"location":"python/DataStructure/01_PythonFundmantal/#145","text":"\u53ef\u4ee5\u5728\u5b57\u7b26\u4e32\u5217\u8868\u3001\u5143\u7ec4\u6216\u5b57\u5178\u91cc\u901a\u8fc7 in \u8fd0\u7b97\u7b26\u6765\u5bf9\u503c\u6216\u591a\u9879\u96c6\u8fdb\u884c\u641c\u7d22\uff0c\u8fd4\u56de True \u6216 False \u3002\u5bf9\u4e8e\u5b57\u5178\u6765\u8bf4\uff0c\u641c\u7d22\u7684\u76ee\u6807\u503c\u5e94\u8be5\u662f\u4e00\u4e2a\u952e\u3002 \u5982\u679c\u5df2\u77e5\u7ed9\u5b9a\u503c\u5b58\u5728\u4e8e\u5e8f\u5217\uff08\u5b57\u7b26\u4e32\u3001\u5217\u8868\u6216\u5143\u7ec4\uff09\u91cc\uff0c\u90a3\u4e48 index \u65b9\u6cd5\u5c06\u8fd4\u56de\u8fd9\u4e2a\u503c\u6240\u51fa\u73b0\u7684\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3002 \u5217\u8868\u68c0\u7d22\uff1a myString = \"I love Python\" myList = myString . split () print ( myList ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ['I', 'love', 'Python'] print ( myList . index ( 'love' )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 1 \u5143\u7ec4\u68c0\u7d22\uff1a myString = \"I love Python\" myList = myString . split () myTuple = tuple ( myList ) print ( myTuple ) print ( myTuple . index ( 'love' )) \u5b57\u5178\u68c0\u7d22\uff1a myDict = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } print ( myDict ) for keys in myDict : print ( keys , myDict [ keys ]) myDict . pop ( 'city' ) # \u62a5\u9519\uff0cKeyError: 'city' myDict . pop ( 'id' ) print ( myDict ) # \u8fd0\u884c\u7ed3\u679c\uff1a{'name': 'Ming', 'age': 35}","title":"1.4.5.\u503c\u68c0\u7d22"},{"location":"python/DataStructure/01_PythonFundmantal/#146","text":"\u4e0b\u6807\u8fd0\u7b97\u7b26\u53ef\u4ee5\u7528\u6765\u8bbf\u95ee\u5217\u8868\u3001\u5143\u7ec4\u548c\u5b57\u5178\u91cc\u7684\u5143\u7d20\u3002 \u901a\u8fc7\u6a21\u5f0f\u5339\u914d\u53ef\u4ee5\u4e00\u6b21\u8bbf\u95ee\u591a\u4e2a\u5143\u7d20\u3002 \u793a\u4f8b\uff1a myTuple \u662f\u4e00\u4e2a\u542b\u5185\u5d4c\u5143\u7ec4\u7684\u5143\u7ec4\u3002 myTuple = (( 'r' , 'g' , 'b' ), 'hexString' ) print ( myTuple ) # \u8fd0\u884c\u7ed3\u679c\uff1a # (('r', 'g', 'b'), 'hexString') print ( myTuple [ 0 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # ('r', 'g', 'b') print ( myTuple [ 0 ][ 0 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # r print ( myTuple [ 0 ][ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # g print ( myTuple [ 0 ][ 2 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # b print ( myTuple [ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # hexString \u901a\u8fc7\u4e0a\u9762\u7684\u62c6\u89e3\uff0c\u6211\u4eec\u6e05\u695a\u4e86\u5185\u5d4c\u5143\u7ec4\u7684\u7ed3\u6784\u8be6\u7ec6\u60c5\u51b5\u3002 \u4e0b\u9762\uff0c\u6211\u4eec\u901a\u8fc7\u6a21\u5f0f\u5339\u914d\uff0c\u628a\u4e00\u4e2a\u7ed3\u6784\u5206\u914d\u7ed9\u5f62\u5f0f\u5b8c\u5168\u76f8\u540c\u7684\u53e6\u4e00\u4e2a\u7ed3\u6784\u3002\u8fd9\u91cc\u76ee\u6807\u7ed3\u6784 newTuple \u6240\u5305\u542b\u7684\u53d8\u91cf\u4ece\u6e90\u7ed3\u6784 (('r', 'g', 'b'), 'hexString') \u91cc\u7684\u76f8\u5e94\u4f4d\u7f6e\u5904\u83b7\u5f97\u5bf9\u5e94\u7684\u503c\u3002 newTuple = (( 'r' , 'g' , 'b' ), 'hexString' ) print ( newTuple [ 0 ]) # ('r', 'g', 'b') print ( newTuple [ 0 ][ 0 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # r print ( newTuple [ 0 ][ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # g print ( newTuple [ 0 ][ 2 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # b print ( newTuple [ 1 ]) # \u8fd0\u884c\u7ed3\u679c\uff1a # hexString","title":"1.4.6.\u6a21\u5f0f\u5339\u914d\u8bbf\u95ee\u591a\u9879\u96c6"},{"location":"python/DataStructure/01_PythonFundmantal/#15","text":"Python\u652f\u6301\u5b8c\u5168\u51fd\u6570\u5f0f\u7f16\u7a0b\u8bbe\u8ba1\u3002 Python\u5305\u542b\u5f88\u591a\u5185\u7f6e\u51fd\u6570\u3002 Python\u4e5f\u8fd0\u884c\u521b\u5efa\u65b0\u51fd\u6570\uff0c\u53ef\u4ee5\u4f7f\u7528\u9012\u5f52\uff0c\u628a\u51fd\u6570\u4f5c\u4e3a\u6570\u636e\u8fdb\u884c\u4f20\u9012\u548c\u8fd4\u56de\u3002","title":"1.5.\u521b\u5efa\u51fd\u6570"},{"location":"python/DataStructure/01_PythonFundmantal/#151","text":"\u51fd\u6570\u5b9a\u4e49\u8bed\u6cd5\uff1a \u547d\u540d\u51fd\u6570\u540d\u79f0\u548c\u53c2\u6570\u540d\u79f0\u7684\u89c4\u5219\u4e0e\u60ef\u4f8b\u4e0e\u547d\u540d\u53d8\u91cf\u7684\u662f\u76f8\u540c\u7684\u3002 \u5fc5\u9009\u53c2\u6570\u7684\u5217\u8868\u53ef\u4ee5\u4e3a\u7a7a\uff0c\u4e5f\u53ef\u4ee5\u5305\u542b\u7528\u9017\u53f7\u9694\u5f00\u7684\u540d\u79f0\u3002 \u4e0e\u5176\u4ed6\u7f16\u7a0b\u8bed\u8a00\u4e0d\u540c\u7684\u662f\uff0c\u53c2\u6570\u540d\u79f0\u6216\u51fd\u6570\u540d\u79f0\u672c\u8eab\u5e76\u4e0d\u4f1a\u548c\u6570\u636e\u7c7b\u578b\u8fdb\u884c\u5173\u8054\u3002 def < function name > ( < list of parameters > ): < sequence of statements > \u793a\u4f8b\uff1a \u5728\u51fd\u6570\u7684\u6807\u9898\u4e0b\u6709\u4e00\u884c\u7528\u4e09\u5f15\u53f7\u62ec\u8d77\u6765\u7684\u5b57\u7b26\u4e32 \u8fd4\u56den\u7684\u5e73\u65b9\u6570 \uff0c\u8fd9\u662f\u4e00\u4e2a\u6587\u6863\u5b57\u7b26\u4e32\uff08docstring\uff09\u3002 \u5728shell\u91cc\u9762\u8f93\u5165help(square)\u65f6\uff0c\u4f1a\u663e\u793a\u8fd9\u4e2a\u5b57\u7b26\u4e32\u3002 \u5b9a\u4e49\u7684\u6bcf\u4e00\u4e2a\u51fd\u6570\u90fd\u5e94\u8be5\u6709\u6587\u6863\u5b57\u7b26\u4e32\uff0c\u6765\u8bf4\u660e\u8be5\u51fd\u6570\u7684\u529f\u80fd\uff0c\u5e76\u63d0\u4f9b\u76f8\u5173\u7684\u6240\u6709\u53c2\u6570\u4ee5\u53ca\u8fd4\u56de\u503c\u7684\u4fe1\u606f\u3002 \u51fd\u6570\u7684\u53c2\u6570\u548c\u4e34\u65f6\u53d8\u91cf\u53ea\u4f1a\u5728\u51fd\u6570\u8c03\u7528\u7684\u751f\u5b58\u5468\u671f\u5185\u5b58\u5728\uff0c\u5e76\u4e14\u5bf9\u5176\u4ed6\u51fd\u6570\u53ca\u5176\u5916\u56f4\u7a0b\u5e8f\u90fd\u662f\u4e0d\u53ef\u89c1\u7684\u3002 n \u662f\u53c2\u6570\u3002 result \u662f\u4e34\u65f6\u53d8\u91cf\u3002 \u5982\u679c\u51fd\u6570\u4e0d\u5305\u542b return \u8bed\u53e5\u65f6\uff0c\u5b83\u5c06\u5728\u6700\u540e\u4e00\u6761\u8bed\u53e5\u6267\u884c\u4e4b\u540e\u81ea\u52a8\u8fd4\u56de None \u503c\u3002 \u7528 = \u628a\u53c2\u6570\u6307\u5b9a\u4e3a\u6709\u9ed8\u8ba4\u503c\u7684\u53ef\u9009\u53c2\u6570\u3002 \u5728\u53c2\u6570\u5217\u8868\u4e2d\uff0c\u5fc5\u9009\u53c2\u6570\uff08\u6ca1\u6709\u9ed8\u8ba4\u503c\u7684\u53c2\u6570\uff09\u5fc5\u987b\u4f4d\u4e8e\u53ef\u9009\u53c2\u6570\u4e4b\u524d\u3002 def square ( n ): \"\"\"\u8fd4\u56den\u7684\u5e73\u65b9\u6570\"\"\" result = n ** 2 return result print ( square ( 5 ))","title":"1.5.1.\u51fd\u6570\u5b9a\u4e49"},{"location":"python/DataStructure/01_PythonFundmantal/#152","text":"\u9012\u5f52\u51fd\u6570\uff08recursive function\uff09\u662f\u6307\u4f1a\u8c03\u7528\u81ea\u8eab\u7684\u51fd\u6570\u3002 \u4e3a\u4e86\u9632\u6b62\u51fd\u6570\u65e0\u9650\u5730\u91cd\u590d\u8c03\u7528\u81ea\u8eab\uff0c\u4ee3\u7801\u4e2d\u5fc5\u987b\u81f3\u5c11\u6709\u4e00\u6761\u7528\u6765\u67e5\u9a8c\u6761\u4ef6\u7684\u9009\u62e9\u8bed\u53e5\uff0c\u7528\u4e8e\u786e\u5b9a\u63a5\u4e0b\u6765\u8981\u7ee7\u7eed\u9012\u5f52\u8fd8\u662f\u505c\u6b62\u9012\u5f52\u3002\u8fd9\u4e2a\u68c0\u67e5\u6761\u4ef6\u8bed\u53e5\u79f0\u4e3a\u57fa\u672c\u60c5\u51b5\uff08base case\uff09\u3002 \u793a\u4f8b\uff1a\u4e0b\u9762\u662f\u901a\u8fc7\u5faa\u73af\u5b9e\u73b0\u8f93\u51fa\u4ece\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u548c\u3002 def mySum ( lower , upper ): \"\"\"\u5bf9\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u6c42\u548c; lower:\u6700\u5c0f\u503c; upper:\u6700\u5927\u503c;\"\"\" result = 0 while ( lower <= upper ): result = result + lower lower += 1 return result print ( mySum ( 1 , 10 )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 55 \u7528\u9012\u5f52\u51fd\u6570\u6539\u5199\u4e0a\u8ff0\u51fd\u6570\u3002 def mySum ( lower , upper ): \"\"\"\u5bf9\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u6c42\u548c; lower:\u6700\u5c0f\u503c; upper:\u6700\u5927\u503c;\"\"\" if lower <= upper : return lower + mySum ( lower + 1 , upper ) else : return 0 print ( mySum ( 1 , 10 )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 55 \u901a\u5e38\u6765\u8bf4\uff0c\u9012\u5f52\u51fd\u6570\u81f3\u5c11\u6709\u4e00\u4e2a\u53c2\u6570\u3002 \u8fd9\u4e2a\u53c2\u6570\u7684\u503c\u4f1a\u88ab\u7528\u6765\u5bf9\u9012\u5f52\u8fc7\u7a0b\u7684\u57fa\u672c\u60c5\u51b5\u8fdb\u884c\u5224\u5b9a\uff0c\u4ece\u800c\u51b3\u5b9a\u662f\u5426\u8981\u7ed3\u675f\u6574\u4e2a\u8c03\u7528\u3002 \u5728\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u4e4b\u524d\uff0c\u8fd9\u4e2a\u503c\u4e5f\u4f1a\u88ab\u8fdb\u884c\u67d0\u79cd\u65b9\u5f0f\u7684\u4fee\u6539\u3002 \u6bcf\u6b21\u5bf9\u8fd9\u4e2a\u503c\u7684\u4fee\u6539\uff0c\u90fd\u5e94\u8be5\u4ea7\u751f\u4e00\u4e2a\u65b0\u6570\u636e\u503c\uff0c\u53ef\u4ee5\u8ba9\u51fd\u6570\u6700\u7ec8\u8fbe\u5230\u57fa\u672c\u60c5\u51b5\u3002 \u4e3a\u4e86\u5bf9 mySum \u51fd\u6570\u7684\u9012\u5f52\u8fdb\u884c\u8ddf\u8e2a\uff0c\u53ef\u4ee5\u5c1d\u8bd5\u6dfb\u52a0\u4e00\u4e2a\u4ee3\u8868\u7f29\u8fdb\u8fb9\u8ddd\u7684\u53c2\u6570\u5e76\u4e14\u6dfb\u52a0\u4e00\u4e9bprint\u8bed\u53e5\u3002\u8fd9\u6837\u5728\u6bcf\u6b21\u8c03\u7528\u65f6\uff0c\u51fd\u6570\u7684\u7b2c\u4e00\u6761\u8bed\u53e5\u4f1a\u8ba1\u7b97\u7f29\u8fdb\u6570\u91cf\uff0c\u7136\u540e\u518d\u6253\u5370\u4e24\u4e2a\u53c2\u6570\u7684\u503c\uff0c\u6bcf\u6b21\u8fd4\u56de\u8c03\u7528\u4e4b\u524d\u7684\u8fd4\u56de\u503c\u65f6\u90fd\u4f7f\u7528\u76f8\u540c\u7684\u7f29\u8fdb\uff0c\u5c31\u53ef\u4ee5\u5b9e\u73b0\u5bf9\u4e24\u4e2a\u53c2\u6570\u7684\u503c\u4ee5\u53ca\u6bcf\u6b21\u8c03\u7528\u7684\u8fd4\u56de\u503c\u8fdb\u884c\u8ddf\u8e2a\u3002 def mySum ( lower , upper , margin = 0 ): \"\"\"\u5bf9\u7ed9\u5b9a\u7684\u6700\u5c0f\u503c\u5230\u6700\u5927\u503c\u4e4b\u95f4\u7684\u6574\u6570\u6c42\u548c\uff0c\u901a\u8fc7\u9636\u68af\u65b9\u5f0f\u8f93\u51fa; lower:\u6700\u5c0f\u503c; upper:\u6700\u5927\u503c;\"\"\" blanks = \" \" * margin print ( blanks , lower , upper ) if lower <= upper : result = lower + mySum ( lower + 1 , upper , margin + 4 ) print ( blanks , result ) return result else : print ( blanks , 0 ) return 0 print ( mySum ( 1 , 5 )) # \u8fd0\u884c\u7ed3\u679c\uff1a # 1 5 # 2 5 # 3 5 # 4 5 # 5 5 # 6 5 # 0 # 5 # 9 # 12 # 14 # 15 # 15","title":"1.5.2.\u51fd\u6570\u9012\u5f52"},{"location":"python/DataStructure/01_PythonFundmantal/#153","text":"\u5d4c\u5957\u51fd\u6570\u7c7b\u4f3c\u4e8e\u5d4c\u5957\u5faa\u73af\uff0c\u5c31\u662f\u51fd\u6570\u5185\u53c8\u5d4c\u5957\u7740\u51fd\u6570\u3002\u5373\uff0c\u51fd\u6570\u7684\u5b9a\u4e49\u5d4c\u5957\u5728\u4e00\u4e2a\u51fd\u6570\u7684\u8bed\u53e5\u5e8f\u5217\u91cc\u3002 \u5148\u770b\u4e00\u4e2a\u666e\u901a\u4f8b\u5b50\uff1a # \u5b9a\u4e49inner\u51fd\u6570 def inner (): print ( '\u6211\u662finner' ) # \u5b9a\u4e49outer\u51fd\u6570\uff0couter\u51fd\u6570\u8c03\u7528inner\u51fd\u6570 def outer (): print ( '\u6211\u662fouter' ) inner () outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter # \u6211\u662finner \u6539\u5199\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u628a inner \u51fd\u6570\u5199\u5728 outer \u51fd\u6570\u91cc\u9762\u3002 # \u5b9a\u4e49outer\u51fd\u6570\uff0couter\u51fd\u6570\u5185\u5d4cinner\u51fd\u6570\uff0c\u5e76\u8c03\u7528inner\u51fd\u6570 def outer (): print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): print ( '\u6211\u662finner' ) inner () outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter # \u6211\u662finner \u4e0a\u9762\u7684\u5916\u5c42 outer \u51fd\u6570\u548c\u5185\u5c42 inner \u51fd\u6570\u90fd\u6ca1\u6709\u53d8\u91cf\u548c\u53c2\u6570\u3002 \u73b0\u5728\u4fee\u6539\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u6211\u4eec\u4f20\u5165\u53c2\u6570\u548c\u53d8\u91cf\uff0c\u7136\u540e\u628a\u5916\u5c42\u51fd\u6570\u8fd4\u56de\u503c\u6307\u5411\u5185\u5c42\u51fd\u6570\u540d\u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) # \u8fd4\u56de\u5185\u5c42inner\u51fd\u6570\u540d return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662finner # inner\u6253\u5370: 1 \u5728\u4e0a\u9762\u7684\u4f8b\u5b50\u4e2d\uff1a f = outer() \u8c03\u7528\u5916\u5c42 outer \u51fd\u6570\uff0c\u5e76\u628a\u7ed3\u679c\u8d4b\u503c\u7ed9 f \u3002\u6ce8\u610f\uff0cinner\u51fd\u6570\u5e76\u6ca1\u6709\u88ab\u6267\u884c\u3002 f \u5176\u5b9e\u5c31\u662f inner \uff0c\u6307\u5411 inner \u7684\u5185\u5b58\u7a7a\u95f4\u3002\u901a\u8fc7 f() \u9a8c\u8bc1\u4e86\u8fd9\u4e00\u70b9\uff0c outer \u51fd\u6570\u4e2d\u7684\u53d8\u91cf a \u88ab\u6253\u5370\u51fa\u6765\u4e86\u3002 \u4e0a\u9762\u4f8b\u5b50\u4e2d outer \u5c31\u662f\u95ed\u5305\u51fd\u6570\uff0c\u5916\u5c42\u51fd\u6570\u7684\u53d8\u91cf\u53ef\u4ee5\u88ab\u5185\u5c42\u51fd\u6570\u8c03\u7528\uff0c\u7c7b\u4f3c\u4e8e\u5c01\u88c5\u7684\u6548\u679c\u3002\u5185\u5c42\u51fd\u6570\u4e0d\u4f1a\u7acb\u523b\u88ab\u6267\u884c\uff0c\u5f53\u518d\u6b21\u8c03\u7528\u65f6\uff0c\u5185\u5c42\u51fd\u6570\u624d\u4f1a\u6267\u884c\u3002 \u95ed\u5305\u51fd\u6570\u9700\u8981\u6709\u4e09\u4e2a\u6761\u4ef6\uff1a \u5fc5\u987b\u6709\u4e00\u4e2a\u5185\u5d4c\u51fd\u6570\uff0c\u4f8b\u5982\u51fd\u6570 inner \uff1b \u5185\u90e8\u51fd\u6570\u5f15\u7528\u5916\u90e8\u51fd\u6570\u53d8\u91cf\uff0c\u4f8b\u5982\u53d8\u91cf a \uff1b \u5916\u90e8\u51fd\u6570\u5fc5\u987b\u8fd4\u56de\u5185\u5d4c\u51fd\u6570\uff0c\u4f8b\u5982 outer \u51fd\u6570\u4e2d\u7684 return inner \uff1b \u5bf9\u4e0a\u9762\u7684\u4ee3\u7801\u518d\u8fdb\u884c\u4fee\u6539\uff0c\u5728 inner \u51fd\u6570\u4e2d\u518d\u6dfb\u52a0\u4e00\u4e2a\u540c\u540d\u7684\u53d8\u91cfa\u3002\u4ece\u7ed3\u679c\u53ef\u4ee5\u5f97\u51fa\u7ed3\u8bba\uff0c inner \u51fd\u6570\u4f18\u5148\u5728\u5185\u90e8\u67e5\u627e\u53d8\u91cf a=5 \u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): a = 5 print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662finner # inner\u6253\u5370: 5 \u7ed3\u8bba\uff1a\u5185\u5c42\u51fd\u6570\u4e2d\u8c03\u7528\u7684\u53d8\u91cf\uff1a \u9996\u5148\u4f1a\u4ece\u5185\u5c42\u51fd\u6570\u4e2d\u627e\uff0c \u627e\u4e0d\u5230\u5c31\u53bb\u5916\u5c42\u51fd\u6570\u4e2d\u627e\uff0c \u518d\u627e\u4e0d\u5230\u5c31\u5230\u51fd\u6570\u5916\u4e2d\u627e\uff0c \u518d\u627e\u4e0d\u5230\u5c31\u5230\u5185\u7f6e\u7684\u6a21\u5757\u4e2d\u627e\uff0c \u518d\u627e\u4e0d\u5230\uff0c\u5c31\u62a5\u9519\u3002 \u8fd9\u5c31\u662f\u4f5c\u7528\u57df\u7684\u6982\u5ff5\u3002 \u7ee7\u7eed\u4fee\u6539\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u5728 inner \u51fd\u6570\u4e2d\u4fee\u6539 outer \u51fd\u6570\u4e2d\u53d8\u91cf a \u7684\u503c\uff0c\u8fd0\u884c\u7ed3\u679c\u62a5\u9519\u3002\u7ed3\u8bba\uff1a\u5185\u5c42\u51fd\u6570\u4e0d\u80fd\u4fee\u6539\u5916\u5c42\u51fd\u6570\u7684\u53d8\u91cf\u503c\u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): a += 5 print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # UnboundLocalError: local variable 'a' referenced before assignment \u4fee\u6b63\u4e0a\u9762\u7684\u4ee3\u7801\u3002\u5728 inner \u51fd\u6570\u4e2d\u5bf9\u53d8\u91cfa\u6dfb\u52a0\u4e00\u4e2a nonlocal \u7684\u58f0\u660e\uff0c\u5c31\u53ef\u4ee5\u5728 inner \u51fd\u6570\u4e2d\u4fee\u6539\u5916\u5c42outer\u51fd\u6570\u7684\u53d8\u91cf a \u7684\u503c\u3002 def outer (): a = 1 print ( '\u6211\u662fouter' ) # \u5b9a\u4e49inner\u51fd\u6570 def inner (): nonlocal a a += 5 print ( '\u6211\u662finner' ) print ( 'inner\u6253\u5370: ' , a ) return inner f = outer () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662fouter f () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u6211\u662finner # inner\u6253\u5370: 6 \u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u662f\u9636\u4e58\uff08factorial\uff09\u9012\u5f52\u51fd\u6570\u7684\u4e24\u4e2a\u4e0d\u540c\u7684\u5b9a\u4e49\u3002 \u7b2c\u4e00\u4e2a\u5b9a\u4e49\u4f7f\u7528\u4e86\u5d4c\u5957\u7684\u8f85\u52a9\u51fd\u6570 recurse \u6765\u5bf9\u6240\u9700\u8981\u7684\u53c2\u6570\u8fdb\u884c\u9012\u5f52\uff1b\u8fd9\u91cc\u7684 factorial \u51fd\u6570\u5c31\u662f\u95ed\u5305\u51fd\u6570\u3002 \u7b2c\u4e00\u6b65\uff1a\u7b2c\u4e00\u6b21\u8c03\u7528 factorial() \u51fd\u6570\uff0c\u5373 n=5 \uff1b \u7b2c\u4e8c\u6b65\uff1a\u7b2c\u4e00\u6b21\u8c03\u7528\u5185\u5c42\u51fd\u6570 recurse() \uff0c\u4f46\u4e0d\u4f1a\u7acb\u523b\u88ab\u6267\u884c\uff1b \u7b2c\u4e09\u6b65\uff0c\u6267\u884c return recurse(5, 1) \uff0c\u5bf9\u53c2\u6570 product \u521d\u59cb\u5316\u8d4b\u503c 1 \u7b2c\u56db\u6b65\uff1a\u6267\u884c return recurse(5, 5 * 1) \uff0c\u6b64\u65f6 n=5 \uff0c product=1 \u3002 \u7b2c\u4e94\u6b65\uff1a\u6267\u884c return recurse(4, 4 * 5) \uff0c\u6b64\u65f6 n=4 \uff0c product=5 \u3002 \u7b2c\u516d\u6b65\uff1a\u6267\u884c return recurse(3, 3 * 20) \uff0c\u6b64\u65f6 n=3 \uff0c product=20 \u3002 \u7b2c\u4e03\u6b65\uff1a\u6267\u884c return recurse(2, 2 * 60) \uff0c\u6b64\u65f6 n=2 \uff0c product=60 \u3002 \u7b2c\u516b\u6b65\uff1a\u6267\u884c return recurse(1, 1 * 120) \uff0c\u6b64\u65f6 n=1 \uff0c product=120 \u3002 \u7b2c\u4e5d\u6b65\uff1a\u6b64\u65f6 n=1 \uff0c\u6267\u884c return product \uff0c\u5373 return 120 \uff0c\u7ed3\u675f\u3002 \u7b2c\u4e8c\u4e2a\u5b9a\u4e49\u5219\u662f\u4e3a\u7b2c\u4e8c\u4e2a\u53c2\u6570\u63d0\u4f9b\u4e86\u9ed8\u8ba4\u503c\uff0c\u4ece\u800c\u7b80\u5316\u4e86\u8bbe\u8ba1\u3002 # \u7b2c\u4e00\u4e2a\u5b9a\u4e49 def factorial ( n ): \"\"\"\u8fd4\u56de n \u7684\u9636\u4e58\"\"\" def recurse ( n , product ): \"\"\"\u8ba1\u7b97\u9636\u4e58\u7684\u5e2e\u52a9\u5668\"\"\" print ( n , product ) # \u63d2\u5165\u8fd9\u4e00\u53e5\u662f\u4e3a\u4e86\u80fd\u770b\u6e05\u695a\u6bcf\u4e00\u6b21\u9012\u5f52\u8c03\u7528\u7684n\u548cproduct\u53d8\u5316 if n == 1 : return product else : return recurse ( n - 1 , n * product ) return recurse ( n , 1 ) f = factorial ( 5 ) # \u8fd0\u884c\u7ed3\u679c 5 1 4 5 3 20 2 60 1 120 # \u7b2c\u4e8c\u4e2a\u5b9a\u4e49 def factorial ( n , product = 1 ): \"\"\"\u8fd4\u56de n \u7684\u9636\u4e58\"\"\" if n == 1 : return product else : return factorial ( n - 1 , n * product ) print ( factorial ( 5 )) # \u8fd0\u884c\u7ed3\u679c # 120","title":"1.5.3.\u51fd\u6570\u5d4c\u5957"},{"location":"python/DataStructure/01_PythonFundmantal/#154","text":"\u51fd\u6570\u672c\u8eab\u4e5f\u662f\u4e00\u79cd\u72ec\u7279\u7684\u6570\u636e\u5bf9\u8c61\u3002\u53ef\u4ee5\u628a\u5b83\u4eec\u8d4b\u7ed9\u53d8\u91cf\u3001\u5b58\u50a8\u5728\u6570\u636e\u7ed3\u6784\u91cc\u3001\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7ed9\u5176\u4ed6\u51fd\u6570\u4ee5\u53ca\u4f5c\u4e3a\u5176\u4ed6\u51fd\u6570\u7684\u503c\u8fd4\u56de\u3002 \u9ad8\u9636\u51fd\u6570\uff08higher-order function\uff09\uff1a\u5b83\u63a5\u6536\u53e6\u4e00\u4e2a\u51fd\u6570\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u4e14\u4ee5\u67d0\u79cd\u65b9\u5f0f\u5e94\u7528\u8be5\u51fd\u6570\u3002 Python\u6709\u4e24\u4e2a\u5185\u7f6e\u7684\u9ad8\u9636\u51fd\u6570\uff0c\u5206\u522b\u662f map \u548c filter \uff0c\u5b83\u4eec\u53ef\u4ee5\u7528\u4e8e\u5904\u7406\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 map \u51fd\u6570\u4f1a\u63a5\u6536\u53e6\u4e00\u4e2a\u51fd\u6570\u548c\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\uff0c\u8fd4\u56de\u53e6\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002\u8fd9\u4e2a\u51fd\u6570\u4f1a\u628a\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7684\u51fd\u6570\u5e94\u7528\u5728\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\u7684\u6bcf\u4e2a\u5143\u7d20\u4e0a\u3002\u7b80\u5355\u6765\u8bf4\uff0c map \u51fd\u6570\u4f1a\u5bf9\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\u7684\u6bcf\u4e2a\u5143\u7d20\u8fdb\u884c\u8f6c\u6362\u3002 filter \u4f1a\u63a5\u53d7\u4e00\u4e2a\u5e03\u5c14\u51fd\u6570\u548c\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\uff0c\u8fd4\u56de\u8fd9\u6837\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff0c\u5b83\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u90fd\u4f1a\u88ab\u4f20\u9012\u7ed9\u5e03\u5c14\u51fd\u6570\uff0c\u5982\u679c\u8fd9\u4e2a\u51fd\u6570\u8fd4\u56deTrue\uff0c\u90a3\u4e48\u8fd9\u4e2a\u5143\u7d20\u5c06\u88ab\u4fdd\u7559\u5728\u8fd4\u56de\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\uff1b\u5426\u5219\uff0c\u8fd9\u4e2a\u5143\u7d20\u5c06\u88ab\u5220\u9664\u3002\u7b80\u5355\u8bf4\uff0c filter \u51fd\u6570\u4f1a\u628a\u6240\u6709\u80fd\u591f\u901a\u8fc7\u68c0\u9a8c\u7684\u5143\u7d20\u4fdd\u7559\u5728\u53ef\u8fed\u4ee3\u5bf9\u8c61\u91cc\u3002 functools.reduce \u901a\u8fc7\u628a\u63a5\u6536\u4e24\u4e2a\u53c2\u6570\u7684\u51fd\u6570\u7684\u7ed3\u679c\u4ee5\u53ca\u8fed\u4ee3\u5bf9\u8c61\u7684\u4e0b\u4e00\u4e2a\u5143\u7d20\u518d\u6b21\u5e94\u7528\u4e8e\u8fd9\u4e2a\u63a5\u6536\u4e24\u4e2a\u53c2\u6570\u7684\u51fd\u6570\uff0c\u6765\u628a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u8ba1\u7b97\u6210\u5355\u4e00\u7684\u503c\u3002 \u793a\u4f8b\uff1a\u628a\u4e00\u4e2a\u6574\u6570\u5217\u8868\u8f6c\u6362\u6210\u53e6\u4e00\u4e2a\u5305\u542b\u8fd9\u4e9b\u6574\u6570\u7684\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\u5217\u8868\u3002 \u4f20\u7edf\u65b9\u6cd5\u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] for i in oldList : newList . append ( str ( i )) print ( newList ) # ['0', '1', '3', '5', '7', '9'] \u7528 map \u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] newList = list ( map ( str , oldList )) print ( newList ) # ['0', '1', '3', '5', '7', '9'] \u62d3\u5c55\uff1a\u628a\u4e00\u4e2a\u6574\u6570\u5217\u8868\u4e2d\u7684\u6b63\u6574\u6570\u8f6c\u6362\u6210\u53e6\u4e00\u4e2a\u5305\u542b\u8fd9\u4e9b\u6574\u6570\u7684\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\u5217\u8868\u3002 \u4f20\u7edf\u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] for i in oldList : if i > 0 : newList . append (( str ( i ))) print ( newList ) # ['1', '3', '5', '7', '9'] \u4f7f\u7528 filter \u5b9e\u73b0\uff1a oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] def isPositive ( n ): if n > 0 : return True # \u521b\u5efa\u4e00\u4e2a\u4e0d\u5305\u542b\u4efb\u4f55\u96f6\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61 newList = list ( filter ( isPositive , oldList )) print ( newList ) # [1, 3, 5, 7, 9] \u793a\u4f8b\uff1a\u8ba1\u7b97\u4ece1\u523010\u7684\u4e58\u79ef\u5e76\u8f93\u51fa\u7ed3\u679c\u3002 \u901a\u8fc7 for \u5faa\u73af\u5b9e\u73b0\uff1a result = 1 value = 1 for value in range ( 1 , 11 ): result *= value value += 1 print ( result ) # \u8fd0\u884c\u7ed3\u679c # 3628800 \u901a\u8fc7 functools.reduce \u5faa\u73af\u5b9e\u73b0\uff1a import functools result = functools . reduce ( lambda x , y : x * y , range ( 1 , 11 )) print ( result ) # 3628800","title":"1.5.4.\u9ad8\u9636\u51fd\u6570"},{"location":"python/DataStructure/01_PythonFundmantal/#155lambda","text":"\u8bed\u6cd5\u683c\u5f0f\uff1a lambda < argument list > : < expression > lambda\u8868\u8fbe\u5f0f\u4e0d\u80fd\u50cf\u5176\u4ed6Python\u51fd\u6570\u90a3\u6837\u5305\u542b\u4e00\u6574\u4e2a\u8bed\u53e5\u5e8f\u5217\u3002 \u62d3\u5c55\uff1a\u7528lambda\u5b9e\u73b0\u628a\u4e00\u4e2a\u6574\u6570\u5217\u8868\u4e2d\u7684\u6b63\u6574\u6570\u8f6c\u6362\u6210\u53e6\u4e00\u4e2a\u5305\u542b\u8fd9\u4e9b\u6574\u6570\u7684\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\u5217\u8868\uff0c\u5b9e\u9645\u5c31\u662f\u901a\u8fc7\u4f7f\u7528\u533f\u540d\u7684\u5e03\u5c14\u51fd\u6570\u6765\u4ece\u6574\u6570\u5217\u8868\u91cc\u5254\u9664\u6240\u6709\u4e3a\u96f6\u7684\u5143\u7d20\u3002 oldList = [ 0 , 1 , 3 , 5 , 7 , 9 ] newList = [] newList = list ( filter ( lambda i : i > 0 , oldList )) print ( newList ) # [1, 3, 5, 7, 9]","title":"1.5.5.lambda\u4e0e\u533f\u540d\u51fd\u6570"},{"location":"python/DataStructure/01_PythonFundmantal/#16","text":"\u8003\u8651\u4e24\u79cd\u5f02\u5e38\u60c5\u51b5\uff1a Python\u865a\u62df\u673a\u5728\u7a0b\u5e8f\u6267\u884c\u671f\u95f4\u9047\u5230\u4e86\u8bed\u4e49\u9519\u8bef\uff0c\u5219\u4f1a\u5f97\u5230\u76f8\u5e94\u7684\u9519\u8bef\u6d88\u606f\uff0c\u4ece\u800c\u5f15\u53d1\u4e00\u4e2a\u5f02\u5e38\u5e76\u4e14\u6682\u505c\u7a0b\u5e8f\u3002\u8bed\u4e49\u9519\u8bef\u5305\u62ec\u4f8b\u5982\u672a\u5b9a\u4e49\u7684\u53d8\u91cf\u540d\u3001\u9664\u4ee50\u4ee5\u53ca\u8d85\u51fa\u5217\u8868\u8303\u56f4\u7684\u7d22\u5f15\u7b49\u3002 \u7528\u6237\u5f15\u8d77\u7684\u67d0\u4e9b\u9519\u8bef\uff0c\u4f8b\u5982\uff0c\u671f\u671b\u8f93\u5165\u6570\u5b57\u7684\u65f6\u5019\u8f93\u5165\u4e86\u5176\u4ed6\u5b57\u7b26\u3002\u5bf9\u4e8e\u5728\u8fd9\u4e9b\u60c5\u51b5\u4e0b\u4ea7\u751f\u7684\u5f02\u5e38\uff0c\u7a0b\u5e8f\u4e0d\u5e94\u8be5\u505c\u6b62\u6267\u884c\uff0c\u800c\u5e94\u8be5\u5bf9\u8fd9\u4e9b\u5f02\u5e38\u8fdb\u884c\u6355\u83b7\uff0c\u5e76\u4e14\u5141\u8bb8\u7528\u6237\u4fee\u6b63\u9519\u8bef\u3002 Python\u63d0\u4f9b\u4e86try-except\u8bed\u53e5\uff0c\u53ef\u4ee5\u8ba9\u7a0b\u5e8f\u6355\u83b7\u5f02\u5e38\u5e76\u6267\u884c\u76f8\u5e94\u7684\u6062\u590d\u64cd\u4f5c\u3002 try \u5b50\u53e5\u4e2d\u7684\u8bed\u53e5\u5c06\u5148\u88ab\u6267\u884c\u3002\u5982\u679c\u8fd9\u4e9b\u8bed\u53e5\u4e2d\u7684\u4e00\u6761\u5f15\u53d1\u4e86\u5f02\u5e38\uff0c\u90a3\u4e48\u63a7\u5236\u6743\u4f1a\u7acb\u5373\u8f6c\u79fb\u5230 except \u5b50\u53e5\u53bb\u3002 \u5982\u679c\u5f15\u53d1\u7684\u5f02\u5e38\u7c7b\u578b\u548c\u8fd9\u4e2a\u5b50\u53e5\u91cc\u7684\u7c7b\u578b\u4e00\u81f4\uff0c\u90a3\u4e48\u4f1a\u6267\u884c\u5b83\u91cc\u9762\u7684\u8bed\u53e5\uff1b \u5426\u5219\uff0c\u5c06\u8f6c\u79fb\u5230try-except\u8bed\u53e5\u7684\u8c03\u7528\u8005\uff0c\u5e76\u57fa\u4e8e\u8c03\u7528\u94fe\u5411\u4e0a\u4f20\u9012\uff0c\u76f4\u5230\u8fd9\u4e2a\u5f02\u5e38\u88ab\u6210\u529f\u6355\u83b7\uff0c\u6216\u8005\u662f\u7a0b\u5e8f\u56e0\u9519\u8bef\u6d88\u606f\u800c\u505c\u6b62\u6267\u884c\u3002 \u5982\u679c try \u5b50\u53e5\u91cc\u7684\u8bed\u53e5\u6ca1\u6709\u5f15\u53d1\u4efb\u4f55\u5f02\u5e38\uff0c\u90a3\u4e48\u4f1a\u8df3\u8fc7 except \u5b50\u53e5\u5e76\u7ee7\u7eed\u6267\u884c\uff0c\u76f4\u5230try-except\u8bed\u53e5\u7684\u672b\u5c3e\u3002 try : < statements > except < exception type > : < statements > \u901a\u5e38\u6765\u8bf4\uff0c \u5bf9\u4e8e\u5df2\u77e5\u53ef\u80fd\u4f1a\u53d1\u751f\u7684\u5f02\u5e38\u7c7b\u578b\uff0c\u5e94\u8be5\u5c3d\u53ef\u80fd\u5730\u5305\u62ec\u5728\u5728 except \u8bed\u53e5\u91cc\u3002 \u5982\u679c\u4e0d\u77e5\u9053\u5f02\u5e38\u7684\u7c7b\u578b\uff0c\u53ef\u4ee5\u5728 except \u4e2d\u7528\u66f4\u901a\u7528\u7684Exception\u7c7b\u578b\u5339\u914d\u53ef\u80fd\u4f1a\u5f15\u53d1\u7684\u4efb\u4f55\u5f02\u5e38\u3002 \u793a\u4f8b\uff1a def getYourAge ( prompt ): \"\"\"\u63d0\u793a\u7528\u6237\u8f93\u5165\u4e00\u4e2a\u6574\u6570\uff0c\u5426\u5219\u7ed9\u51fa\u9519\u8bef\u63d0\u793a\uff0c\u5e76\u7ee7\u7eed\u63d0\u793a\u7528\u6237\u8f93\u5165\u3002\"\"\" inputStr = input ( prompt ) try : number = int ( inputStr ) return number except ValueError : print ( \"Error in number format:\" , inputStr ) return getYourAge ( prompt ) if __name__ == \"__main__\" : age = getYourAge ( \"Enter your age: \" ) print ( \"Your age is\" , age ) # \u8fd0\u884c\u7ed3\u679c # Enter your age: 3a # Error in number format: 3a # Enter your age: 3.5 # Error in number format: 3.5 # Enter your age: 20 # Your age is 20","title":"1.6.\u6355\u83b7\u5f02\u5e38"},{"location":"python/DataStructure/01_PythonFundmantal/#17","text":"","title":"1.7.\u6587\u4ef6\u53ca\u5176\u64cd\u4f5c"},{"location":"python/DataStructure/01_PythonFundmantal/#171","text":"\u53ef\u4ee5\u628a\u6587\u672c\u6587\u4ef6\u91cc\u7684\u6570\u636e\u770b\u4f5c\u5b57\u7b26\u3001\u5355\u8bcd\u3001\u6570\u5b57\u6216\u8005\u82e5\u5e72\u884c\u6587\u672c\u3002 \u5982\u679c\u628a\u6587\u672c\u6587\u4ef6\u91cc\u7684\u6570\u636e\u5f53\u4f5c\u6574\u6570\u6216\u6d6e\u70b9\u6570\uff0c\u5c31\u5fc5\u987b\u7528\u7a7a\u767d\u5b57\u7b26\uff08\u7a7a\u683c\u3001\u5236\u8868\u7b26\u548c\u6362\u884c\u7b26\uff09\u5c06\u5176\u5206\u9694\u5f00\u3002\u8f93\u51fa\u6216\u8f93\u5165\u5230\u6587\u672c\u6587\u4ef6\u7684\u6240\u6709\u6570\u636e\u5fc5\u987b\u662f\u5b57\u7b26\u4e32\u5f62\u5f0f\u7684\uff0c\u6240\u4ee5\u5728\u8f93\u5165/\u8f93\u51fa\u65f6\u9700\u8981\u505a\u76f8\u5e94\u7684\u7c7b\u578b\u8f6c\u6362\u3002 \u5982\u4e0b\u4f8b\uff1a 34.6 22.33 66.75 77.12 21.44 99.01 Python\u7684open\u51fd\u6570\u63a5\u6536\u4e0b\u9762\u4e24\u4e2a\u4e3b\u8981\u53c2\u6570\uff0c\u6253\u5f00\u4e00\u4e2a\u4e0e\u78c1\u76d8\u6587\u4ef6\u7684\u8fde\u63a5\u5e76\u4e14\u8fd4\u56de\u76f8\u5e94\u7684\u6587\u4ef6\u5bf9\u8c61\u3002 \u6587\u4ef6\u8def\u5f84\uff1b \u6253\u5f00\u6a21\u5f0f\uff1a \u6253\u5f00\u6a21\u5f0f\uff1a r \u8868\u793a\u6587\u4ef6\u53ea\u80fd\u8bfb\u53d6\uff1b w \u8868\u793a\u6587\u4ef6\u53ea\u80fd\u5199\u5165\uff1b a \u8868\u793a\u6253\u5f00\u6587\u4ef6\uff0c\u5728\u539f\u6709\u5185\u5bb9\u7684\u57fa\u7840\u4e0a\u8ffd\u52a0\u5185\u5bb9\uff0c\u5728\u672b\u5c3e\u5199\u5165\uff1b w+ \u8868\u793a\u53ef\u4ee5\u5bf9\u6587\u4ef6\u8fdb\u884c\u8bfb\u5199\u53cc\u91cd\u64cd\u4f5c\uff1b rb \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u53ea\u8bfb\uff1b wb \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u53ea\u5199\uff1b ab \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u8ffd\u52a0\uff1b wb+ \u4ee5\u4e8c\u8fdb\u5236\u683c\u5f0f\u6253\u5f00\u4e00\u4e2a\u6587\u4ef6\uff0c\u7528\u4e8e\u8bfb\u5199\uff1b \u793a\u4f8b\uff1a \u4e3a myfile.txt \u6587\u4ef6\u6253\u5f00\u4e00\u4e2a\u7528\u6765\u8f93\u51fa\u7684\u6587\u4ef6\u5bf9\u8c61\u3002 \u5b57\u7b26\u4e32\u6570\u636e\u901a\u8fc7 write \u65b9\u6cd5\u548c\u6587\u4ef6\u5bf9\u8c61\u5199\u5165\uff08\u6216\u8f93\u51fa\uff09\u5230\u6587\u4ef6\u91cc\u3002 \u8f6c\u4e49\u7b26 \\n \u5b9e\u73b0\u6362\u884c\u3002 \u4f7f\u7528 close \u65b9\u6cd5\u5173\u95ed\u6587\u4ef6\u3002\u5982\u679c\u6ca1\u6709\u5173\u95ed\u8f93\u51fa\u6587\u4ef6\uff0c\u5219\u53ef\u80fd\u5bfc\u81f4\u6570\u636e\u4e22\u5931\u3002 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) f . write ( \"First line. \\n Second line. \\n \" ) f . close () \u6587\u4ef6myfile.txt\u7684\u5185\u5bb9\uff1a First line. Second line.","title":"1.7.1.\u6587\u672c\u6587\u4ef6\u8bfb\u53d6"},{"location":"python/DataStructure/01_PythonFundmantal/#172","text":"\u6587\u4ef6\u7684 write \u65b9\u6cd5\u63a5\u6536\u4e00\u4e2a\u5b57\u7b26\u4e32\u4f5c\u4e3a\u53c2\u6570\u3002\u56e0\u6b64\uff0c\u5176\u4ed6\u7c7b\u578b\u7684\u6570\u636e\uff08\u5982\u6574\u6570\u6216\u6d6e\u70b9\u6570\uff09\u5728\u5199\u5165\u8f93\u51fa\u6587\u4ef6\u4e4b\u524d\uff0c\u90fd\u5fc5\u987b\u5148\u88ab\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\u3002 \u5728Python\u91cc\uff0c\u53ef\u4ee5\u4f7f\u7528 str \u51fd\u6570\u628a\u7edd\u5927\u591a\u6570\u7684\u6570\u636e\u7c7b\u578b\u7684\u503c\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\uff0c\u4ee5\u7a7a\u683c\u6216\u6362\u884c\u7b26\u4f5c\u4e3a\u5206\u9694\u7b26\uff0c\u5c06\u5176\u5199\u5165\u6587\u4ef6\u91cc\u3002 \u793a\u4f8b\uff1a\u751f\u6210500\u4e2a\u4ecb\u4e8e1\u548c500\u4e4b\u95f4\u7684\u968f\u673a\u6570\uff0c\u5e76\u8f93\u51fa\u5230\u6587\u672c\u6587\u4ef6\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) for count in range ( 500 ): number = random . randint ( 1 , 500 ) f . write ( str ( number ) + \" \\n \" ) f . close ()","title":"1.7.2.\u6587\u672c\u6587\u4ef6\u5199\u5165"},{"location":"python/DataStructure/01_PythonFundmantal/#173","text":"\u793a\u4f8b\uff1a\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) f . write ( \"First line. \\n Second line. \\n \" ) # \u521d\u59cb\u5316\u6587\u4ef6\u5185\u5bb9 f . close () # \u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) text1 = f . read () # \u628a\u6587\u4ef6\u7684\u5168\u90e8\u5185\u5bb9\u8f93\u5165\u5355\u4e2a\u5b57\u7b26\u4e32\u4e2d print ( text1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # First line. # Second line text2 = f . read () # \u518d\u6b21read\uff0c\u5f97\u5230\u4e00\u4e2a\u7a7a\u5b57\u4e32\uff0c\u8868\u8ff0\u5df2\u7ecf\u5230\u8fbe\u6587\u4ef6\u672b\u5c3e\u3002\u8981\u518d\u6b21\u8bfb\u53d6\u9700\u8981\u91cd\u65b0\u6253\u5f00\u6587\u4ef6 print ( \"======\" ) print ( text2 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ====== # f . close () # \u91cd\u65b0\u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) for line in f : # \u9010\u884c\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9 print ( \"======\" ) print ( line ) # \u6bcf\u884c\u90fd\u6709\u4e00\u4e2a\u6362\u884c\u7b26\uff0c\u8fd9\u662fprint\u51fd\u6570\u9ed8\u8ba4\u884c\u4e3a # \u8fd0\u884c\u7ed3\u679c\uff1a # ====== # First line. # ====== # Second line. # f . close () # \u91cd\u65b0\u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) while True : line = f . readline () # readline\u65b9\u6cd5\u4f1a\u4ece\u8f93\u5165\u7684\u6587\u672c\u91cc\u53ea\u83b7\u53d6\u4e00\u884c\u6570\u636e\uff0c\u5e76\u4e14\u8fd4\u56de\u8fd9\u4e2a\u5305\u542b\u6362\u884c\u7b26\u7684\u5b57\u7b26\u4e32\u3002\u5982\u679creadline\u9047\u5230\u4e86\u6587\u4ef6\u672b\u5c3e\uff0c\u90a3\u4e48\u4f1a\u8fd4\u56de\u7a7a\u5b57\u7b26\u4e32\u3002 if line == \"\" : break print ( \"******\" ) print ( line ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ****** # First line. # ****** # Second line. # f . close () # \u91cd\u65b0\u6253\u5f00\u6587\u4ef6\u8bfb\u53d6\u5185\u5bb9 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) line = f . readlines () # readlines\u65b9\u6cd5\u5219\u662f\u8bfb\u53d6\u6240\u6709\u884c\uff0c\u8fd4\u56de\u7684\u662f\u6240\u6709\u884c\u7ec4\u6210\u7684\u5217\u8868\u3002 print ( line ) # \u8fd0\u884c\u7ed3\u679c\uff1a # ['First line.\\n', 'Second line.\\n'] f . close ()","title":"1.7.3.\u4ece\u6587\u672c\u6587\u4ef6\u8bfb\u53d6\u6570\u636e"},{"location":"python/DataStructure/01_PythonFundmantal/#174","text":"\u793a\u4f8b\uff1a\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6574\u6570\uff0c\u6bcf\u884c\u53ea\u6709\u4e00\u4e2a\u6574\u6570\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'w' ) # \u751f\u62100~9\u6574\u6570\uff0c\u5e76\u5199\u5165\u6587\u4ef6 for count in range ( 10 ): f . write ( str ( count ) + \" \\n \" ) f . close () # \u6253\u5f00\u6587\u4ef6 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) # \u4f9d\u6b21\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6570\u5b57\uff0c\u5e76\u6c42\u548c theSum = 0 for line in f : line = line . strip () number = int ( line ) theSum += number print ( \"The sum is : \" , theSum ) # \u8fd0\u884c\u7ed3\u679c\uff1a # The sum is : 45 f . close () \u793a\u4f8b\uff1a\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6574\u6570\uff0c\u6bcf\u884c\u6709\u591a\u4e2a\u6574\u6570\u3002\u9700\u8981\u4e8b\u5148\u628a\u4e0b\u9762\u7684\u5185\u5bb9\u5199\u5165 myfile.txt \u6587\u4ef6\u4e2d\u3002 \u6587\u4ef6 myfile.txt \u7684\u5185\u5bb9\u3002 1 3 5 7 9 2 4 6 8 10 31 200 3000 50000 import random # \u6253\u5f00\u6587\u4ef6 f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) # \u4f9d\u6b21\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u6570\u5b57\uff0c\u5e76\u6c42\u548c theSum = 0 for line in f : lines = line . split () # split\u65b9\u6cd5\u4f1a\u81ea\u52a8\u5904\u7406\u6362\u884c\u7b26 for word in lines : number = int ( word ) theSum += number print ( \"The sum is : \" , theSum ) # \u8fd0\u884c\u7ed3\u679c\uff1a # The sum is : 53286 f . close () \u7b80\u5199\u4e0a\u9762\u7684\u4ee3\u7801\u3002 import random f = open ( \"./docs/python/DataStructure/code/myfile.txt\" , 'r' ) print ( \"The sum is: \" , sum ( map ( int , f . read () . split ()))) # \u8fd0\u884c\u7ed3\u679c\uff1a # The sum is : 53286 f . close ()","title":"1.7.4.\u4ece\u5176\u5b83\u6587\u4ef6\u8bfb\u53d6\u6570\u636e"},{"location":"python/DataStructure/01_PythonFundmantal/#175pickle","text":"\u5728\u628a\u4efb\u4f55\u5bf9\u8c61\u4fdd\u5b58\u5230\u6587\u4ef6\u4e4b\u524d\uff0c\u6211\u4eec\u53ef\u4ee5\u5bf9\u5b83\u8fdb\u884c\u201c\u814c\u5236\u201d\uff1b\u5728\u628a\u5bf9\u8c61\u4ece\u6587\u4ef6\u52a0\u8f7d\u5230\u7a0b\u5e8f\u4e2d\u65f6\uff0c\u4e5f\u53ef\u4ee5\u5bf9\u5b83\u8fdb\u884c\u201c\u53cd\u814c\u5236\u201d\u3002 \u793a\u4f8b\uff1a \u4f7f\u7528pickle\u6a21\u5757\u7684 pickle.dump \u628a\u540d\u4e3alyst\u7684\u5217\u8868\u91cc\u7684\u6240\u6709\u5bf9\u8c61\u4fdd\u5b58\u5230\u540d\u4e3aitems.dat\u7684\u6587\u4ef6\u91cc\uff08\u201c\u814c\u5236\u201d\uff09\u3002\u6211\u4eec\u4e0d\u9700\u8981\u77e5\u9053\u5217\u8868\u91cc\u6709\u54ea\u4e9b\u7c7b\u578b\u7684\u5bf9\u8c61\uff0c\u4e5f\u4e0d\u9700\u8981\u77e5\u9053\u6709\u591a\u5c11\u4e2a\u5bf9\u8c61\u3002 import pickle myList = [ 60 , \"A string object\" , 1977 ] fObj = open ( \"./docs/python/DataStructure/code/items.dat\" , \"wb\" ) for item in myList : pickle . dump ( item , fObj ) fObj . close () \u4f7f\u7528pickle\u6a21\u5757\u7684 pickle.load \u628aitems.dat\u7684\u6587\u4ef6\u5185\u5bb9\u52a0\u8f7d\u56de\u7a0b\u5e8f\uff08\u201c\u53cd\u814c\u5236\u201d\uff09\u3002 import pickle lyst = list () fileObj = open ( \"./docs/python/DataStructure/code/items.dat\" , \"rb\" ) while True : try : item = pickle . load ( fileObj ) lyst . append ( item ) except EOFError : # \u68c0\u6d4b\u5df2\u7ecf\u5230\u8fbe\u6587\u4ef6\u672b\u5c3e fileObj . close () break print ( lyst ) # \u8fd0\u884c\u7ed3\u679c\uff1a # [60, 'A string object', 1977]","title":"1.7.5.\u4f7f\u7528pickle\u8bfb\u5199\u5bf9\u8c61"},{"location":"python/DataStructure/01_PythonFundmantal/#18","text":"\u7c7b\uff08class\uff09\u7528\u6765\u63cf\u8ff0\u4e0e\u4e00\u7ec4\u5bf9\u8c61\u6709\u5173\u7684\u6570\u636e\u548c\u65b9\u6cd5\u3002\u5b83\u63d0\u4f9b\u4e86\u7528\u6765\u521b\u5efa\u5bf9\u8c61\u7684\u84dd\u56fe\uff0c\u4ee5\u53ca\u5728\u5bf9\u8c61\u4e0a\u8c03\u7528\u65b9\u6cd5\u65f6\u6240\u9700\u8981\u6267\u884c\u7684\u4ee3\u7801\u3002 Python\u91cc\u7684\u6570\u636e\u7c7b\u578b\u90fd\u662f\u7c7b\uff1b \u7c7b\u540d\u6309\u7167\u60ef\u4f8b\u9996\u5b57\u6bcd\u5e94\u4e3a\u5927\u5199\u6837\u5f0f\uff1b \u5b9a\u4e49\u7c7b\u7684\u4ee3\u7801\u901a\u5e38\u4f1a\u88ab\u5b58\u653e\u5728\u9996\u5b57\u6bcd\u5c0f\u5199\u7684\u7c7b\u540d\u7684\u6a21\u5757\u6587\u4ef6\u91cc\u3002 \u76f8\u5173\u7684\u7c7b\u4e5f\u53ef\u80fd\u4f1a\u51fa\u73b0\u5728\u540c\u4e00\u4e2a\u6a21\u5757\u91cc\u3002 \u7c7b\u7684\u8bed\u6cd5\uff1a def < class name > ( < parent class name > )[ 2 ]: < class variable assignments > < instance method definitions > \u7236\u7c7b\uff08parent class\uff09\u7684\u540d\u79f0\u662f\u53ef\u9009\u7684\uff0c\u5728\u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0c\u5b83\u4f1a\u662fobject\u3002 \u6240\u6709Python\u7c7b\u5c5e\u4e8e\u4e00\u4e2a\u4ee5 object \u4f5c\u4e3a\u6839\u8282\u70b9\u7684\u5c42\u6b21\u7ed3\u6784\u3002 \u5728 object \u91cc\uff0cPython\u5b9a\u4e49\u4e86\u51e0\u79cd\u65b9\u6cd5\uff1a __str__ \u548c __eq__ \uff0c\u56e0\u6b64\u6240\u6709\u5b50\u7c7b\u4f1a\u81ea\u52a8\u7ee7\u627f\u8fd9\u4e9b\u65b9\u6cd5\u3002 \u5b9e\u4f8b\u65b9\u6cd5\uff08instance method\uff09\u662f\u5728\u7c7b\u7684\u5bf9\u8c61\u4e0a\u8fd0\u884c\u7684\u3002\u5b83\u4eec\u5305\u542b\u7528\u6765\u8bbf\u95ee\u6216\u4fee\u6539\u5b9e\u4f8b\u53d8\u91cf\u7684\u4ee3\u7801\u3002 \u5b9e\u4f8b\u53d8\u91cf\uff08instance variable\uff09\u662f\u6307\u7531\u5355\u4e2a\u5bf9\u8c61\u6240\u62e5\u6709\u7684\u5b58\u50a8\u4fe1\u606f\u3002 \u7c7b\u53d8\u91cf\uff08class variable\uff09\u662f\u6307\u7531\u7c7b\u7684\u6240\u6709\u5bf9\u8c61\u5b58\u50a8\u6240\u6709\u7684\u4fe1\u606f\u3002 \u793a\u4f8b\uff1a\u89e3\u8bfbCounter\u7c7b\u3002 Counter \u7c7b\u662f object \u7684\u5b50\u7c7b\uff1b instances \u662f\u7c7b\u53d8\u91cf\uff0c\u8ddf\u8e2a\u5df2\u521b\u5efa\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u7684\u6570\u91cf\uff1b \u5b9e\u4f8b\u65b9\u6cd5 __init__ \u4e5f\u79f0\u4e3a\u6784\u9020\u51fd\u6570\uff1b\u8fd9\u4e2a\u65b9\u6cd5\u7528\u6765\u521d\u59cb\u5316\u5b9e\u4f8b\u53d8\u91cf\uff0c\u5e76\u4e14\u5bf9\u7c7b\u53d8\u91cf\u8fdb\u884c\u66f4\u65b0\uff1b self \u662f\u6307\u5728\u8fd0\u884c\u65f6\u8fd9\u4e2a\u65b9\u6cd5\u7684\u5bf9\u8c61\u672c\u8eab\uff1b \u4f7f\u7528\u5b9e\u4f8b\u53d8\u91cf\u90fd\u4f1a\u52a0\u4e0a\u524d\u7f00 self \uff1b\u548c\u53c2\u6570\u6216\u4e34\u65f6\u53d8\u91cf\u4e0d\u540c\u7684\u5730\u65b9\u662f\uff0c\u5b9e\u4f8b\u53d8\u91cf\u5728\u7c7b\u7684\u4efb\u4f55\u65b9\u6cd5\u91cc\u662f\u53ef\u89c1\u7684\uff1b \u5176\u4ed6\u5b9e\u4f8b\u65b9\u6cd5\u53ef\u4ee5\u5206\u4e3a\u4e24\u79cd\uff1a\u53d8\u5f02\u5668\uff08mutator\uff09\u548c\u8bbf\u95ee\u5668\uff08accessor\uff09\u3002\u53d8\u5f02\u5668\u4f1a\u901a\u8fc7\u4fee\u6539\u5bf9\u8c61\u7684\u5b9e\u4f8b\u53d8\u91cf\u5bf9\u5176\u5185\u90e8\u72b6\u6001\u8fdb\u884c\u4fee\u6539\u6216\u66f4\u6539\u3002\u8bbf\u95ee\u5668\u5219\u53ea\u4f1a\u67e5\u770b\u6216\u4f7f\u7528\u5bf9\u8c61\u7684\u5b9e\u4f8b\u53d8\u91cf\u7684\u503c\uff0c\u800c\u4e0d\u4f1a\u53bb\u4fee\u6539\u5b83\u4eec\uff1b __str__ \u65b9\u6cd5\u5c06\u8986\u76d6object\u7c7b\u91cc\u7684\u8fd9\u4e2a\u65b9\u6cd5\uff1b \u5f53Python\u7684 print \u51fd\u6570\u63a5\u6536\u5230\u4e00\u4e2a\u53c2\u6570\u65f6\uff0c\u8fd9\u4e2a\u53c2\u6570\u7684 __str__ \u65b9\u6cd5\u5c06\u81ea\u52a8\u8fd0\u884c\uff0c\u4ece\u800c\u5f97\u5230\u5b83\u7684\u5b57\u7b26\u4e32\u8868\u8fbe\u5f0f\uff0c\u4ee5\u4fbf\u7528\u6765\u8f93\u51fa\uff1b \u5f53\u770b\u5230 == \u8fd0\u7b97\u7b26\u65f6\uff0cPython\u5c06\u8fd0\u884c __eq__ \u65b9\u6cd5\uff1b\u5728 object \u7c7b\u91cc\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u7684\u9ed8\u8ba4\u5b9a\u4e49\u662f\u8fd0\u884c is \u8fd0\u7b97\u7b26\u3002 class Counter ( object ): # Counter\u7c7b\u662fobject\u7684\u5b50\u7c7b \"\"\"Models a counter.\"\"\" # Class variable \u7c7b\u53d8\u91cf instances = 0 # \u8ddf\u8e2a\u5df2\u521b\u5efa\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u7684\u6570\u91cf # Constructor \u6784\u9020\u5668 # \u5b9e\u4f8b\u65b9\u6cd5__init__\u4e5f\u79f0\u4e3a\u6784\u9020\u51fd\u6570\uff1b\u8fd9\u4e2a\u65b9\u6cd5\u7528\u6765\u521d\u59cb\u5316\u5b9e\u4f8b\u53d8\u91cf\uff0c\u5e76\u4e14\u5bf9\u7c7b\u53d8\u91cf\u8fdb\u884c\u66f4\u65b0\uff1b def __init__ ( self ): # self\u662f\u6307\u5728\u8fd0\u884c\u65f6\u8fd9\u4e2a\u65b9\u6cd5\u7684\u5bf9\u8c61\u672c\u8eab \"\"\"Sets up the counter.\"\"\" Counter . instances += 1 self . reset () # Mutator methods def reset ( self ): \"\"\"Sets the counter to 0.\"\"\" self . value = 0 def increment ( self , amount = 1 ): \"\"\"Adds amount to the counter.\"\"\" self . value += amount def decrement ( self , amount = 1 ): \"\"\"Subtracts amount from the counter.\"\"\" self . value -= amount # Accessor methods def getValue ( self ): \"\"\"Returns the counter's value.\"\"\" return self . value def __str__ ( self ): \"\"\"Returns the string representation of the counter.\"\"\" return str ( self . value ) def __eq__ ( self , other ): \"\"\"Returns True if self equals other or False otherwise.\"\"\" if self is other : return True if type ( self ) != type ( other ): return False return self . value == other . value c1 = Counter () print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 0 c1 . getValue () str ( c1 ) c1 . increment () print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 1 c1 . increment ( 5 ) print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 6 c1 . reset () print ( c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 0 c2 = Counter () print ( Counter . instances ) # \u8fd0\u884c\u7ed3\u679c\uff1a # 2 print ( c1 == c1 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # True print ( c1 == 0 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # False print ( c1 == c2 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # True c2 . increment () print ( c1 == c2 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # False","title":"1.8.\u521b\u5efa\u7c7b"},{"location":"python/DataStructure/01_PythonFundmantal/#19","text":"1\uff0e\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u4f7f\u4e4b\u80fd\u591f\u63a5\u6536\u7403\u4f53\u7684\u534a\u5f84\uff08\u6d6e\u70b9\u6570\uff09\uff0c\u5e76\u4e14\u53ef\u4ee5\u8f93\u51fa\u7403\u4f53\u7684\u76f4\u5f84\u3001\u5468\u957f\u3001\u8868\u9762\u79ef\u4ee5\u53ca\u4f53\u79ef\u3002 \u89e3\u7b54\uff1a PAI = 3.14 radius = float ( input ( \"\u8f93\u5165\u7403\u534a\u5f84\uff1a\" )) diameter = radius * 2 circumference = 2 * PAI * radius surfaceArea = 4 * PAI * radius ** 2 sphereVolume = 4 * ( PAI * radius ** 3 ) / 3 print ( \"\u7403\u534a\u5f84\uff1a\" , radius , \"\u7403\u76f4\u5f84\uff1a\" , diameter , \"\u7403\u8868\u9762\u79ef\uff1a\" , surfaceArea , \"\u7403\u4f53\u79ef\uff1a\" , sphereVolume ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u7403\u534a\u5f84\uff1a3.5 # \u7403\u534a\u5f84\uff1a 3.5 \u7403\u76f4\u5f84\uff1a 7.0 \u7403\u8868\u9762\u79ef\uff1a 153.86 \u7403\u4f53\u79ef\uff1a 179.50333333333333 import math def main (): try : radius = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u534a\u5f84\uff1a\" )) if radius <= 0 : print ( \"\u534a\u5f84\u5fc5\u987b\u4e3a\u6b63\u6570\uff01\" ) return diameter = 2 * radius circumference = 2 * math . pi * radius surfaceArea = 4 * math . pi * radius ** 2 volume = ( 4 / 3 ) * math . pi * radius ** 3 print ( f \"\u7403\u4f53\u7684\u76f4\u5f84\uff1a { diameter : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u5468\u957f\uff1a { circumference : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a { surfaceArea : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u4f53\u79ef\uff1a { volume : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u7403\u534a\u5f84\uff1a3.5 # \u7403\u4f53\u7684\u76f4\u5f84\uff1a7.00 # \u7403\u4f53\u7684\u5468\u957f\uff1a21.99 # \u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a153.94 # \u7403\u4f53\u7684\u4f53\u79ef\uff1a179.59 import math class Sphere : def __init__ ( self , radius ): self . radius = radius def diameter ( self ): return 2 * self . radius def circumference ( self ): return 2 * math . pi * self . radius def surfaceArea ( self ): return 4 * math . pi * self . radius ** 2 def volume ( self ): return ( 4 / 3 ) * math . pi * self . radius ** 3 def main (): try : radius = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u4f53\u7684\u534a\u5f84\uff1a\" )) if radius <= 0 : print ( \"\u534a\u5f84\u5fc5\u987b\u4e3a\u6b63\u6570\uff01\" ) return sphere = Sphere ( radius ) print ( f \"\u7403\u4f53\u7684\u76f4\u5f84\uff1a { sphere . diameter () : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u5468\u957f\uff1a { sphere . circumference () : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a { sphere . surfaceArea () : .2f } \" ) print ( f \"\u7403\u4f53\u7684\u4f53\u79ef\uff1a { sphere . volume () : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u7403\u4f53\u7684\u534a\u5f84\uff1a3.5 # \u7403\u4f53\u7684\u76f4\u5f84\uff1a7.00 # \u7403\u4f53\u7684\u5468\u957f\uff1a21.99 # \u7403\u4f53\u7684\u8868\u9762\u79ef\uff1a153.94 # \u7403\u4f53\u7684\u4f53\u79ef\uff1a179.59 2\uff0e\u5458\u5de5\u7684\u5468\u5de5\u8d44\u7b49\u4e8e\u5c0f\u65f6\u5de5\u8d44\u4e58\u4ee5\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\u518d\u52a0\u4e0a\u52a0\u73ed\u5de5\u8d44\u3002\u52a0\u73ed\u5de5\u8d44\u7b49\u4e8e\u603b\u52a0\u73ed\u65f6\u95f4\u4e58\u4ee5\u5c0f\u65f6\u5de5\u8d44\u76841.5\u500d\u3002\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\u3001\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\u4ee5\u53ca\u52a0\u73ed\u603b\u65f6\u95f4\uff0c\u7136\u540e\u663e\u793a\u51fa\u5458\u5de5\u7684\u5468\u5de5\u8d44\u3002 \u89e3\u7b54\uff1a hourSalary = float ( input ( \"\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff08\u5143\uff09\uff1a\" )) totalWorkingHours = float ( input ( \"\u8f93\u5165\u672c\u5468\u6b63\u5e38\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) totalOvertimeHours = float ( input ( \"\u8f93\u5165\u672c\u5468\u603b\u52a0\u73ed\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) weeklySalary = hourSalary * totalWorkingHours + hourSalary * totalOvertimeHours * 1.5 print ( \"\u5458\u5de5\u7684\u5468\u5de5\u8d44\uff08\u5143\uff09\u662f\uff1a\" , weeklySalary ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff08\u5143\uff09\uff1a20 # \u8f93\u5165\u672c\u5468\u6b63\u5e38\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a40 # \u8f93\u5165\u672c\u5468\u603b\u52a0\u73ed\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a10 # \u5458\u5de5\u7684\u5468\u5de5\u8d44\uff08\u5143\uff09\u662f\uff1a 1100.0 def calculate_weekly_salary ( hourly_wage , normal_hours , overtime_hours ): overtime_pay = overtime_hours * hourly_wage * 1.5 normal_pay = normal_hours * hourly_wage weekly_salary = normal_pay + overtime_pay return weekly_salary def main (): try : hourly_wage = float ( input ( \"\u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a\" )) normal_hours = float ( input ( \"\u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) overtime_hours = float ( input ( \"\u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) weekly_salary = calculate_weekly_salary ( hourly_wage , normal_hours , overtime_hours ) print ( f \"\u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a { weekly_salary : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a20 # \u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a40 # \u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a10 # \u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a1100.00 class Employee : def __init__ ( self , hourly_wage , normal_hours , overtime_hours ): self . hourly_wage = hourly_wage self . normal_hours = normal_hours self . overtime_hours = overtime_hours def calculate_weekly_salary ( self ): overtime_pay = self . overtime_hours * self . hourly_wage * 1.5 normal_pay = self . normal_hours * self . hourly_wage weekly_salary = normal_pay + overtime_pay return weekly_salary def main (): try : hourly_wage = float ( input ( \"\u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a\" )) normal_hours = float ( input ( \"\u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) overtime_hours = float ( input ( \"\u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a\" )) employee = Employee ( hourly_wage , normal_hours , overtime_hours ) weekly_salary = employee . calculate_weekly_salary () print ( f \"\u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a { weekly_salary : .2f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u5c0f\u65f6\u5de5\u8d44\uff1a20 # \u8bf7\u8f93\u5165\u6b63\u5e38\u7684\u603b\u5de5\u4f5c\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a40 # \u8bf7\u8f93\u5165\u52a0\u73ed\u603b\u65f6\u95f4\uff08\u5c0f\u65f6\uff09\uff1a10 # \u5458\u5de5\u7684\u5468\u5de5\u8d44\u4e3a\uff1a1100.00 3\uff0e\u6709\u4e00\u4e2a\u6807\u51c6\u7684\u79d1\u5b66\u5b9e\u9a8c\uff1a\u6254\u4e00\u4e2a\u7403\uff0c\u770b\u770b\u5b83\u80fd\u53cd\u5f39\u591a\u9ad8\u3002\u4e00\u65e6\u786e\u5b9a\u4e86\u7403\u7684\u201c\u53cd\u5f39\u9ad8\u5ea6\u201d\uff0c\u8fd9\u4e2a\u6bd4\u503c\u5c31\u7ed9\u51fa\u4e86\u76f8\u5e94\u7684\u53cd\u5f39\u5ea6\u6307\u6570\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4ece10ft\uff081ft=0.3048m\uff09\u9ad8\u5904\u6389\u843d\u7684\u7403\u53ef\u4ee5\u53cd\u5f39\u52306 ft\u9ad8\uff0c\u90a3\u4e48\u76f8\u5e94\u7684\u53cd\u5f39\u5ea6\u6307\u6570\u5c31\u662f0.6\uff1b\u5728\u4e00\u6b21\u53cd\u5f39\u4e4b\u540e\uff0c\u7403\u7684\u603b\u884c\u8fdb\u8ddd\u79bb\u662f16 ft\u3002\u63a5\u4e0b\u6765\uff0c\u7403\u7ee7\u7eed\u5f39\u8df3\uff0c\u90a3\u4e48\u4e24\u6b21\u5f39\u8df3\u540e\u7684\u603b\u8ddd\u79bb\u5e94\u8be5\u662f\uff1a10 ft + 6 ft + 6 ft + 3.6 ft = 25.6 ft\u3002\u53ef\u4ee5\u770b\u5230\uff0c\u6bcf\u6b21\u8fde\u7eed\u5f39\u8df3\u6240\u7ecf\u8fc7\u7684\u8ddd\u79bb\u662f\uff1a\u7403\u5230\u5730\u9762\u7684\u8ddd\u79bb\uff0c\u52a0\u4e0a\u8fd9\u4e2a\u8ddd\u79bb\u4e58\u4ee5 0.6\uff0c\u8fd9\u65f6\u7403\u53c8\u5f39\u56de\u6765\u4e86\u3002\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u53ef\u4ee5\u8ba9\u7528\u6237\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\u548c\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff0c\u5e76\u8f93\u51fa\u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u3002 \u89e3\u7b54\uff1a height = float ( input ( \"\u8f93\u5165\u5c0f\u7403\u521d\u59cb\u9ad8\u5ea6\uff08ft\uff09\uff1a\" )) times = float ( input ( \"\u8f93\u5165\u5141\u8bb8\u5c0f\u7403\u5f39\u8df3\u6b21\u6570\uff1a\" )) distance = 0 traceDistance = 0 while times : distance = height + 0.6 * height traceDistance += distance height = 0.6 * height times -= 1 print ( \"\u5c0f\u7403\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\uff08ft\uff09\uff1a\" , traceDistance ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u5c0f\u7403\u521d\u59cb\u9ad8\u5ea6\uff08ft\uff09\uff1a50 # \u8f93\u5165\u5141\u8bb8\u5c0f\u7403\u5f39\u8df3\u6b21\u6570\uff1a5 # \u5c0f\u7403\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\uff08ft\uff09\uff1a 184.448 # \u8f93\u5165\u5c0f\u7403\u521d\u59cb\u9ad8\u5ea6\uff08ft\uff09\uff1a100 # \u8f93\u5165\u5141\u8bb8\u5c0f\u7403\u5f39\u8df3\u6b21\u6570\uff1a10 # \u5c0f\u7403\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\uff08ft\uff09\uff1a 397.58135296000006 def calculate_total_distance ( initial_height , num_bounces ): rebound_factor = 0.6 total_distance = 0 height = initial_height for _ in range ( num_bounces + 1 ): total_distance += height height *= rebound_factor return total_distance def main (): try : initial_height = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a\" )) num_bounces = int ( input ( \"\u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a\" )) total_distance = calculate_total_distance ( initial_height , num_bounces ) print ( f \"\u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a { total_distance : .2f } ft\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a50 # \u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a5 # \u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a119.17 ft # \u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a100 # \u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a10 # \u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a249.09 ft class BouncingBall : def __init__ ( self , initial_height , num_bounces ): self . initial_height = initial_height self . num_bounces = num_bounces self . rebound_factor = 0.6 def calculate_total_distance ( self ): total_distance = 0 height = self . initial_height for _ in range ( self . num_bounces + 1 ): total_distance += height height *= self . rebound_factor return total_distance def main (): try : initial_height = float ( input ( \"\u8bf7\u8f93\u5165\u7403\u7684\u521d\u59cb\u9ad8\u5ea6\uff08\u5355\u4f4d\uff1aft\uff09\uff1a\" )) num_bounces = int ( input ( \"\u8bf7\u8f93\u5165\u5141\u8bb8\u7403\u5f39\u8df3\u7684\u6b21\u6570\uff1a\" )) bouncing_ball = BouncingBall ( initial_height , num_bounces ) total_distance = bouncing_ball . calculate_total_distance () print ( f \"\u7403\u6240\u7ecf\u8fc7\u7684\u603b\u8ddd\u79bb\u4e3a\uff1a { total_distance : .2f } ft\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () 4\uff0e\u5fb7\u56fd\u6570\u5b66\u5bb6Gottfried Leibniz\u53d1\u660e\u4e86\u4e0b\u9762\u8fd9\u4e2a\u7528\u6765\u6c42\u03c0\u7684\u8fd1\u4f3c\u503c\u7684\u65b9\u6cd5\uff1a \u03c0/4 = 1 - 1/3 + 1/5 - 1/7 + ...... \uff0c\u8bf7\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u6307\u5b9a\u8fd9\u4e2a\u8fd1\u4f3c\u503c\u6240\u4f7f\u7528\u7684\u8fed\u4ee3\u6b21\u6570\uff0c\u5e76\u4e14\u663e\u793a\u51fa\u7ed3\u679c\u3002 \u89e3\u7b54\uff1a n = int ( input ( \"\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a\" )) mySum = 0 while n : mySum += 1 / ( 2 * n - 1 ) * (( - 1 ) ** ( n + 1 )) n -= 1 print ( \"\u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a\" , mySum * 4 ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a5 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.33968253968254 # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.0418396189294024 # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a20 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.0916238066678385 # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10000000 # \u03c0\u7684\u8fd1\u4f3c\u503c\u662f\uff1a 3.1415925535897933 def calculate_pi_approximation ( iterations ): approximation = 0 sign = 1 for i in range ( 1 , iterations * 2 , 2 ): approximation += sign * ( 1 / i ) sign *= - 1 return approximation * 4 def main (): try : iterations = int ( input ( \"\u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a\" )) if iterations <= 0 : print ( \"\u8fed\u4ee3\u6b21\u6570\u5fc5\u987b\u4e3a\u6b63\u6574\u6570\uff01\" ) return pi_approximation = calculate_pi_approximation ( iterations ) print ( f \"\u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a { pi_approximation : .10f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6574\u6570\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a5 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.3396825397 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0418396189 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a20 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0916238067 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10000000 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.1415925536 class PiApproximation : @classmethod def calculate_pi_approximation ( cls , iterations ): approximation = 0 sign = 1 for i in range ( 1 , iterations * 2 , 2 ): approximation += sign * ( 1 / i ) sign *= - 1 return approximation * 4 def main (): try : iterations = int ( input ( \"\u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a\" )) if iterations <= 0 : print ( \"\u8fed\u4ee3\u6b21\u6570\u5fc5\u987b\u4e3a\u6b63\u6574\u6570\uff01\" ) return pi_approximation = PiApproximation . calculate_pi_approximation ( iterations ) print ( f \"\u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a { pi_approximation : .10f } \" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6574\u6570\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a5 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.3396825397 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0418396189 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a20 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.0916238067 # \u8bf7\u8f93\u5165\u8fed\u4ee3\u6b21\u6570\uff1a10000000 # \u03c0 \u7684\u8fd1\u4f3c\u503c\u4e3a\uff1a3.1415925536 5\uff0e\u67d0\u8ba1\u7b97\u673a\u5546\u5e97\u6709\u8d2d\u4e70\u8ba1\u7b97\u673a\u7684\u4fe1\u8d37\u8ba1\u5212\uff1a\u9996\u4ed810%\uff0c\u5e74\u5229\u7387\u4e3a12%\uff0c\u6bcf\u6708\u6240\u4ed8\u6b3e\u4e3a\u8d2d\u4e70\u4ef7\u683c\u51cf\u53bb\u9996\u4ed8\u4e4b\u540e\u76845%\u3002\u7f16\u5199\u4e00\u4e2a\u4ee5\u8d2d\u4e70\u4ef7\u683c\u4e3a\u8f93\u5165\u7684\u7a0b\u5e8f\uff0c\u53ef\u4ee5\u8f93\u51fa\u4e00\u4e2a\u6709\u9002\u5f53\u6807\u9898\u7684\u8868\u683c\uff0c\u663e\u793a\u8d37\u6b3e\u671f\u9650\u5185\u7684\u4ed8\u6b3e\u8ba1\u5212\u3002\u8868\u7684\u6bcf\u4e00\u884c\u90fd\u5e94\u5305\u542b\u4e0b\u9762\u5404\u9879\uff1a \u6708\u6570\uff08\u4ee51\u5f00\u5934\uff09\uff1b \u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d\uff1b \u5f53\u6708\u6240\u6b20\u7684\u5229\u606f\uff1b \u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1\uff1b \u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d\uff1b \u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d\u3002 \u4e00\u4e2a\u6708\u7684\u5229\u606f\u7b49\u4e8e\u4f59\u989d \u00d7 \u5229\u7387/12\uff1b\u4e00\u4e2a\u6708\u6240\u6b20\u7684\u672c\u91d1\u7b49\u4e8e\u5f53\u6708\u8fd8\u6b3e\u989d\u51cf\u53bb\u6240\u6b20\u7684\u5229\u606f\u3002 \u89e3\u7b54\uff1a def calculate_payment_schedule ( purchase_price ): down_payment = purchase_price * 0.1 loan_balance = purchase_price - down_payment annual_interest_rate = 0.12 monthly_interest_rate = annual_interest_rate / 12 monthly_payment = ( purchase_price - down_payment ) * 0.05 payment_schedule = [] for month in range ( 1 , 13 ): interest = loan_balance * monthly_interest_rate principal = monthly_payment - interest loan_balance -= principal payment_schedule . append (( month , loan_balance , interest , principal , monthly_payment , loan_balance + monthly_payment )) return payment_schedule def main (): try : purchase_price = float ( input ( \"\u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a\" )) payment_schedule = calculate_payment_schedule ( purchase_price ) print ( \" {:<10} {:<15} {:<15} {:<15} {:<15} {:<15} \" . format ( \"\u6708\u6570\" , \"\u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d\" , \"\u5f53\u6708\u6240\u6b20\u7684\u5229\u606f\" , \"\u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1\" , \"\u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d\" , \"\u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d\" )) for payment in payment_schedule : month , balance , interest , principal , monthly_payment , new_balance = payment print ( \" {:<10} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} \" . format ( month , balance , interest , principal , monthly_payment , new_balance )) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # \u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a5000 # \u6708\u6570 \u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d \u5f53\u6708\u6240\u6b20\u7684\u5229\u606f \u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1 \u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d \u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d # 1 4320.00 45.00 180.00 225.00 4545.00 # 2 4138.20 43.20 181.80 225.00 4363.20 # 3 3954.58 41.38 183.62 225.00 4179.58 # 4 3769.13 39.55 185.45 225.00 3994.13 # 5 3581.82 37.69 187.31 225.00 3806.82 # 6 3392.64 35.82 189.18 225.00 3617.64 # 7 3201.56 33.93 191.07 225.00 3426.56 # 8 3008.58 32.02 192.98 225.00 3233.58 # 9 2813.67 30.09 194.91 225.00 3038.67 # 10 2616.80 28.14 196.86 225.00 2841.80 # 11 2417.97 26.17 198.83 225.00 2642.97 # 12 2217.15 24.18 200.82 225.00 2442.15 class PaymentSchedule : def __init__ ( self , purchase_price ): self . purchase_price = purchase_price self . down_payment = purchase_price * 0.1 self . loan_balance = purchase_price - self . down_payment self . annual_interest_rate = 0.12 self . monthly_interest_rate = self . annual_interest_rate / 12 self . monthly_payment = ( purchase_price - self . down_payment ) * 0.05 def calculate_schedule ( self ): payment_schedule = [] for month in range ( 1 , 13 ): interest = self . loan_balance * self . monthly_interest_rate principal = self . monthly_payment - interest self . loan_balance -= principal payment_schedule . append (( month , self . loan_balance , interest , principal , self . monthly_payment , self . loan_balance + self . monthly_payment )) return payment_schedule def print_schedule_table ( self ): payment_schedule = self . calculate_schedule () print ( \" {:<10} {:<15} {:<15} {:<15} {:<15} {:<15} \" . format ( \"\u6708\u6570\" , \"\u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d\" , \"\u5f53\u6708\u6240\u6b20\u7684\u5229\u606f\" , \"\u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1\" , \"\u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d\" , \"\u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d\" )) for payment in payment_schedule : month , balance , interest , principal , monthly_payment , new_balance = payment print ( \" {:<10} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} {:<15.2f} \" . format ( month , balance , interest , principal , monthly_payment , new_balance )) def main (): try : purchase_price = float ( input ( \"\u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a\" )) payment_schedule = PaymentSchedule ( purchase_price ) payment_schedule . print_schedule_table () except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # \u8bf7\u8f93\u5165\u8d2d\u4e70\u4ef7\u683c\uff1a5000 # \u6708\u6570 \u5f53\u524d\u6240\u6b20\u7684\u4f59\u989d \u5f53\u6708\u6240\u6b20\u7684\u5229\u606f \u5f53\u6708\u6240\u6b20\u7684\u672c\u91d1 \u5f53\u6708\u6240\u9700\u4ed8\u6b3e\u91d1\u989d \u4ed8\u6b3e\u4e4b\u540e\u6240\u6b20\u7684\u91d1\u989d # 1 4320.00 45.00 180.00 225.00 4545.00 # 2 4138.20 43.20 181.80 225.00 4363.20 # 3 3954.58 41.38 183.62 225.00 4179.58 # 4 3769.13 39.55 185.45 225.00 3994.13 # 5 3581.82 37.69 187.31 225.00 3806.82 # 6 3392.64 35.82 189.18 225.00 3617.64 # 7 3201.56 33.93 191.07 225.00 3426.56 # 8 3008.58 32.02 192.98 225.00 3233.58 # 9 2813.67 30.09 194.91 225.00 3038.67 # 10 2616.80 28.14 196.86 225.00 2841.80 # 11 2417.97 26.17 198.83 225.00 2642.97 # 12 2217.15 24.18 200.82 225.00 2442.15 6\uff0e\u8d22\u52a1\u90e8\u95e8\u5728\u6587\u672c\u6587\u4ef6\u91cc\u4fdd\u5b58\u4e86\u6240\u6709\u5458\u5de5\u5728\u6bcf\u4e2a\u5de5\u8d44\u5468\u671f\u91cc\u7684\u4fe1\u606f\u5217\u8868\u3002\u6587\u4ef6\u4e2d\u6bcf\u4e00\u884c\u7684\u683c\u5f0f\u4e3a \u3002\u8bf7\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u8f93\u5165\u6587\u4ef6\u7684\u540d\u79f0\uff0c\u5e76\u5728\u7ec8\u7aef\u4e0a\u6253\u5370\u51fa\u7ed9\u5b9a\u65f6\u95f4\u5185\u652f\u4ed8\u7ed9\u6bcf\u4e2a\u5458\u5de5\u7684\u5de5\u8d44\u62a5\u544a\u3002\u8fd9\u4e2a\u62a5\u544a\u662f\u4e00\u4e2a\u6709\u5408\u9002\u6807\u9898\u7684\u8868\uff0c\u5176\u4e2d\u6bcf\u884c\u90fd\u5e94\u8be5\u5305\u542b\u5458\u5de5\u7684\u59d3\u540d\u3001\u5de5\u4f5c\u65f6\u957f\u4ee5\u53ca\u7ed9\u5b9a\u65f6\u95f4\u5185\u6240\u652f\u4ed8\u7684\u5de5\u8d44\u3002 \u89e3\u7b54\uff1a # \u7a0b\u5e8f\u4f1a\u63d0\u793a\u7528\u6237\u8f93\u5165\u6587\u4ef6\u540d\uff0c\u7136\u540e\u8bfb\u53d6\u6587\u4ef6\u4e2d\u7684\u5458\u5de5\u4fe1\u606f\uff0c\u8ba1\u7b97\u5de5\u8d44\u62a5\u544a\uff0c\u5e76\u6253\u5370\u51fa\u5458\u5de5\u7684\u59d3\u540d\u3001\u5de5\u4f5c\u65f6\u957f\u548c\u652f\u4ed8\u5de5\u8d44\u3002\u6ce8\u610f\uff0c\u7a0b\u5e8f\u4f1a\u68c0\u67e5\u6587\u4ef6\u662f\u5426\u5b58\u5728\uff0c\u5e76\u4f1a\u5bf9\u6587\u4ef6\u4e2d\u7684\u6bcf\u884c\u6570\u636e\u8fdb\u884c\u5904\u7406\u4ee5\u786e\u4fdd\u6b63\u786e\u89e3\u6790\u3002 class Employee : def __init__ ( self , last_name , hourly_wage , hours_worked ): self . last_name = last_name self . hourly_wage = float ( hourly_wage ) self . hours_worked = float ( hours_worked ) def calculate_salary ( self ): return self . hourly_wage * self . hours_worked def main (): try : filename = input ( \"\u8bf7\u8f93\u5165\u6587\u4ef6\u540d\uff1a\" ) with open ( filename , 'r' ) as file : employees = [] for line in file : parts = line . strip () . split () if len ( parts ) == 3 : last_name , hourly_wage , hours_worked = parts employee = Employee ( last_name , hourly_wage , hours_worked ) employees . append ( employee ) print ( \" {:<20} {:<15} {:<15} \" . format ( \"\u5458\u5de5\u59d3\u540d\" , \"\u5de5\u4f5c\u65f6\u957f\" , \"\u652f\u4ed8\u5de5\u8d44\" )) print ( \"=\" * 50 ) total_salary = 0 for employee in employees : salary = employee . calculate_salary () total_salary += salary print ( \" {:<20} {:<15.2f} {:<15.2f} \" . format ( employee . last_name , employee . hours_worked , salary )) print ( \"=\" * 50 ) print ( f \"\u603b\u652f\u4ed8\u5de5\u8d44\uff1a { total_salary : .2f } \" ) except FileNotFoundError : print ( \"\u6587\u4ef6\u4e0d\u5b58\u5728\uff01\" ) if __name__ == \"__main__\" : main () 7\uff0e\u7edf\u8ba1\u5b66\u5bb6\u5e0c\u671b\u4f7f\u7528\u4e00\u7ec4\u51fd\u6570\u8ba1\u7b97\u6570\u5b57\u5217\u8868\u7684\u4e2d\u4f4d\u6570\uff08median\uff09\u548c\u4f17\u6570\uff08mode\uff09\u3002\u4e2d\u4f4d\u6570\u662f\u6307\u5982\u679c\u5bf9\u5217\u8868\u8fdb\u884c\u6392\u5e8f\u5c06\u4f1a\u51fa\u73b0\u5728\u5217\u8868\u4e2d\u70b9\u7684\u6570\u5b57\uff0c\u4f17\u6570\u662f\u6307\u5217\u8868\u4e2d\u6700\u5e38\u51fa\u73b0\u7684\u6570\u5b57\u3002\u628a\u8fd9\u4e9b\u529f\u80fd\u5b9a\u4e49\u5728\u540d\u53ebstats.py\u7684\u6a21\u5757\u4e2d\u3002\u9664\u6b64\u4e4b\u5916\uff0c\u6a21\u5757\u8fd8\u5e94\u8be5\u5305\u542b\u4e00\u4e2a\u540d\u53ebmean\u7684\u51fd\u6570\uff0c\u7528\u6765\u8ba1\u7b97\u4e00\u7ec4\u6570\u5b57\u7684\u5e73\u5747\u503c\u3002\u6bcf\u4e2a\u51fd\u6570\u90fd\u4f1a\u63a5\u6536\u4e00\u4e2a\u6570\u5b57\u5217\u8868\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u8fd4\u56de\u4e00\u4e2a\u6570\u5b57\u3002 \u89e3\u7b54\uff1a def median ( numbers ): sorted_numbers = sorted ( numbers ) length = len ( sorted_numbers ) if length % 2 == 1 : return sorted_numbers [ length // 2 ] else : mid1 = sorted_numbers [ length // 2 - 1 ] mid2 = sorted_numbers [ length // 2 ] return ( mid1 + mid2 ) / 2 def mode ( numbers ): from collections import Counter counter = Counter ( numbers ) mode_list = counter . most_common () max_count = mode_list [ 0 ][ 1 ] modes = [ num for num , count in mode_list if count == max_count ] return modes def mean ( numbers ): total = sum ( numbers ) count = len ( numbers ) return total / count if __name__ == \"__main__\" : test_numbers = [ 4 , 2 , 7 , 2 , 1 , 9 , 4 , 7 ] print ( \"\u4e2d\u4f4d\u6570:\" , median ( test_numbers )) print ( \"\u4f17\u6570:\" , mode ( test_numbers )) print ( \"\u5e73\u5747\u503c:\" , mean ( test_numbers )) class Stats : @staticmethod def median ( numbers ): sorted_numbers = sorted ( numbers ) length = len ( sorted_numbers ) if length % 2 == 1 : return sorted_numbers [ length // 2 ] else : mid1 = sorted_numbers [ length // 2 - 1 ] mid2 = sorted_numbers [ length // 2 ] return ( mid1 + mid2 ) / 2 @staticmethod def mode ( numbers ): from collections import Counter counter = Counter ( numbers ) mode_list = counter . most_common () max_count = mode_list [ 0 ][ 1 ] modes = [ num for num , count in mode_list if count == max_count ] return modes @staticmethod def mean ( numbers ): total = sum ( numbers ) count = len ( numbers ) return total / count if __name__ == \"__main__\" : test_numbers = [ 4 , 2 , 7 , 2 , 1 , 9 , 4 , 7 ] print ( \"\u4e2d\u4f4d\u6570:\" , Stats . median ( test_numbers )) print ( \"\u4f17\u6570:\" , Stats . mode ( test_numbers )) print ( \"\u5e73\u5747\u503c:\" , Stats . mean ( test_numbers )) 8\uff0e\u7f16\u5199\u7a0b\u5e8f\uff0c\u8ba9\u7528\u6237\u53ef\u4ee5\u6d4f\u89c8\u6587\u4ef6\u91cc\u7684\u6587\u672c\u884c\u3002\u8fd9\u4e2a\u7a0b\u5e8f\u4f1a\u63d0\u793a\u7528\u6237\u8f93\u5165\u6587\u4ef6\u540d\uff0c\u7136\u540e\u628a\u6587\u672c\u884c\u90fd\u8f93\u5165\u5217\u8868\u3002\u63a5\u4e0b\u6765\uff0c\u8fd9\u4e2a\u7a0b\u5e8f\u4f1a\u8fdb\u5165\u4e00\u4e2a\u5faa\u73af\uff0c\u5728\u8fd9\u4e2a\u5faa\u73af\u91cc\u6253\u5370\u51fa\u6587\u4ef6\u7684\u603b\u884c\u6570\uff0c\u5e76\u63d0\u793a\u7528\u6237\u8f93\u5165\u884c\u53f7\u3002\u8fd9\u4e2a\u884c\u53f7\u7684\u8303\u56f4\u5e94\u5f53\u662f1\u5230\u6587\u4ef6\u7684\u603b\u884c\u6570\u3002\u5982\u679c\u8f93\u5165\u662f0\uff0c\u90a3\u4e48\u7a0b\u5e8f\u9000\u51fa\uff1b\u5426\u5219\uff0c\u7a0b\u5e8f\u5c06\u6253\u5370\u51fa\u884c\u53f7\u6240\u5bf9\u5e94\u7684\u6587\u672c\u884c\u3002 def read_file_lines ( filename ): try : with open ( filename , 'r' ) as file : lines = file . readlines () return lines except FileNotFoundError : print ( \"\u6587\u4ef6\u4e0d\u5b58\u5728\uff01\" ) return [] def main (): filename = input ( \"\u8bf7\u8f93\u5165\u6587\u4ef6\u540d\uff1a\" ) lines = read_file_lines ( filename ) if not lines : return total_lines = len ( lines ) while True : print ( f \"\u6587\u4ef6\u603b\u884c\u6570\uff1a { total_lines } \" ) try : line_number = int ( input ( \"\u8bf7\u8f93\u5165\u884c\u53f7\uff08\u8f93\u51650\u9000\u51fa\uff09\uff1a\" )) if line_number == 0 : break elif 1 <= line_number <= total_lines : print ( f \"\u884c\u53f7 { line_number } : { lines [ line_number - 1 ] . strip () } \" ) else : print ( \"\u65e0\u6548\u7684\u884c\u53f7\uff0c\u8bf7\u8f93\u5165\u6b63\u786e\u8303\u56f4\u5185\u7684\u884c\u53f7\uff01\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) if __name__ == \"__main__\" : main () class TextFileBrowser : @classmethod def read_file_lines ( cls , filename ): try : with open ( filename , 'r' ) as file : lines = file . readlines () return lines except FileNotFoundError : print ( \"\u6587\u4ef6\u4e0d\u5b58\u5728\uff01\" ) return [] @classmethod def browse_file ( cls , filename ): lines = cls . read_file_lines ( filename ) if not lines : return total_lines = len ( lines ) while True : print ( f \"\u6587\u4ef6\u603b\u884c\u6570\uff1a { total_lines } \" ) try : line_number = int ( input ( \"\u8bf7\u8f93\u5165\u884c\u53f7\uff08\u8f93\u51650\u9000\u51fa\uff09\uff1a\" )) if line_number == 0 : break elif 1 <= line_number <= total_lines : print ( f \"\u884c\u53f7 { line_number } : { lines [ line_number - 1 ] . strip () } \" ) else : print ( \"\u65e0\u6548\u7684\u884c\u53f7\uff0c\u8bf7\u8f93\u5165\u6b63\u786e\u8303\u56f4\u5185\u7684\u884c\u53f7\uff01\" ) except ValueError : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u6570\u5b57\uff01\" ) def main (): filename = input ( \"\u8bf7\u8f93\u5165\u6587\u4ef6\u540d\uff1a\" ) TextFileBrowser . browse_file ( filename ) if __name__ == \"__main__\" : main () 9\uff0e\u5728\u672c\u7ae0\u8ba8\u8bba\u7684numberguess\u7a0b\u5e8f\u91cc\uff0c\u8ba1\u7b97\u673a\u4f1a\u201c\u6784\u601d\u201d\u4e00\u4e2a\u6570\u5b57\uff0c\u800c\u7528\u6237\u5219\u8f93\u5165\u731c\u6d4b\u7684\u503c\uff0c\u76f4\u5230\u731c\u5bf9\u4e3a\u6b62\u3002\u7f16\u5199\u8fd9\u6837\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u4f7f\u5176\u53ef\u4ee5\u8c03\u6362\u8fd9\u4e24\u4e2a\u89d2\u8272\uff0c\u4e5f\u5c31\u662f\uff1a\u7528\u6237\u53bb\u201c\u6784\u601d\u201d\u4e00\u4e2a\u6570\u5b57\uff0c\u7136\u540e\u8ba1\u7b97\u673a\u53bb\u8ba1\u7b97\u5e76\u8f93\u51fa\u731c\u6d4b\u7684\u503c\u3002\u548c\u524d\u9762\u90a3\u4e2a\u6e38\u620f\u7248\u672c\u4e00\u6837\uff0c\u5f53\u8ba1\u7b97\u673a\u731c\u9519\u65f6\uff0c\u7528\u6237\u5fc5\u987b\u7ed9\u51fa\u76f8\u5e94\u7684\u63d0\u793a\uff0c\u4f8b\u5982\u201c<\u201d\u548c\u201c>\u201d\uff08\u5206\u522b\u4ee3\u8868\u201c\u6211\u7684\u6570\u5b57\u66f4\u5c0f\u201d\u548c\u201c\u6211\u7684\u6570\u5b57\u66f4\u5927\u201d\uff09\u3002\u5f53\u8ba1\u7b97\u673a\u731c\u5bf9\u65f6\uff0c\u7528\u6237\u5e94\u8be5\u8f93\u5165\u201c=\u201d\u3002\u7528\u6237\u9700\u8981\u5728\u7a0b\u5e8f\u542f\u52a8\u7684\u65f6\u5019\u8f93\u5165\u6570\u5b57\u7684\u4e0b\u9650\u548c\u4e0a\u9650\u3002\u8ba1\u7b97\u673a\u5e94\u8be5\u5728\u6700\u591a [log2(high\u2212low)+1] \u6b21\u731c\u6d4b\u91cc\u627e\u5230\u6b63\u786e\u7684\u6570\u5b57\u3002\u7a0b\u5e8f\u5e94\u8be5\u80fd\u591f\u8ddf\u8e2a\u731c\u6d4b\u6b21\u6570\uff0c\u5982\u679c\u731c\u6d4b\u9519\u8bef\u7684\u6b21\u6570\u5230\u4e86\u5141\u8bb8\u731c\u6d4b\u7684\u6700\u5927\u503c\u4f46\u8fd8\u6ca1\u6709\u731c\u5bf9\uff0c\u5c31\u8f93\u51fa\u6d88\u606f\u201cYou're cheating\uff01\u201d\u3002\u4e0b\u9762\u662f\u548c\u8fd9\u4e2a\u7a0b\u5e8f\u8fdb\u884c\u4ea4\u4e92\u7684\u793a\u4f8b\uff1a Enter the smaller number : 1 Enter the larger number : 100 Your number is 50 Enter = , < , or > : > Your number is 75 Enter = , < , or > : < Your number is 62 Enter = , < , or > : < Your number is 56 Enter = , < , or > : = Hooray , I 've got it in 4 tries! import math class ComputerGuesser : def __init__ ( self , lower_limit , upper_limit ): self . lower_limit = lower_limit self . upper_limit = upper_limit self . max_attempts = math . floor ( math . log2 ( upper_limit - lower_limit + 1 )) + 1 self . attempts = 0 def guess ( self ): return ( self . lower_limit + self . upper_limit ) // 2 def play ( self ): print ( f \"\u8bf7\u4f60\u9009\u62e9\u4e00\u4e2a\u5728 { self . lower_limit } \u5230 { self . upper_limit } \u4e4b\u95f4\u7684\u6570\u5b57\u3002\" ) while self . attempts < self . max_attempts : guess = self . guess () print ( f \"\u6211\u7684\u731c\u6d4b\u662f\uff1a { guess } \" ) response = input ( \"\u8bf7\u8f93\u5165 =, <, \u6216 > \u6765\u6307\u793a\u662f\u5426\u731c\u5bf9\uff1a\" ) self . attempts += 1 if response == '=' : print ( f \"\u6211\u5728\u7b2c { self . attempts } \u6b21\u731c\u5bf9\u4e86\uff01\" ) break elif response == '<' : self . upper_limit = guess - 1 elif response == '>' : self . lower_limit = guess + 1 else : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u64cd\u4f5c\u7b26\uff1a=, <, \u6216 >\" ) if self . attempts >= self . max_attempts : print ( \"\u4f60\u5728\u6b3a\u9a97\u6211\uff01\" ) def main (): lower_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5c0f\u7684\u6570\u5b57\uff1a\" )) upper_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5927\u7684\u6570\u5b57\uff1a\" )) guesser = ComputerGuesser ( lower_limit , upper_limit ) guesser . play () if __name__ == \"__main__\" : main () import math class ComputerGuesser : def __init__ ( self , lower_limit , upper_limit ): self . lower_limit = lower_limit self . upper_limit = upper_limit self . max_attempts = math . floor ( math . log2 ( upper_limit - lower_limit + 1 )) + 1 self . attempts = 0 @classmethod def guess ( cls , lower_limit , upper_limit ): return ( lower_limit + upper_limit ) // 2 @classmethod def play ( cls , lower_limit , upper_limit ): print ( f \"\u8bf7\u4f60\u9009\u62e9\u4e00\u4e2a\u5728 { lower_limit } \u5230 { upper_limit } \u4e4b\u95f4\u7684\u6570\u5b57\u3002\" ) attempts = 0 while attempts < cls . max_attempts : guess = cls . guess ( lower_limit , upper_limit ) print ( f \"\u6211\u7684\u731c\u6d4b\u662f\uff1a { guess } \" ) response = input ( \"\u8bf7\u8f93\u5165 =, <, \u6216 > \u6765\u6307\u793a\u662f\u5426\u731c\u5bf9\uff1a\" ) attempts += 1 if response == '=' : print ( f \"\u6211\u5728\u7b2c { attempts } \u6b21\u731c\u5bf9\u4e86\uff01\" ) break elif response == '<' : upper_limit = guess - 1 elif response == '>' : lower_limit = guess + 1 else : print ( \"\u8bf7\u8f93\u5165\u6709\u6548\u7684\u64cd\u4f5c\u7b26\uff1a=, <, \u6216 >\" ) if attempts >= cls . max_attempts : print ( \"\u4f60\u5728\u6b3a\u9a97\u6211\uff01\" ) def main (): lower_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5c0f\u7684\u6570\u5b57\uff1a\" )) upper_limit = int ( input ( \"\u8bf7\u8f93\u5165\u8f83\u5927\u7684\u6570\u5b57\uff1a\" )) ComputerGuesser . play ( lower_limit , upper_limit ) if __name__ == \"__main__\" : main () 10\uff0e\u6709\u4e00\u4e2a\u7b80\u5355\u7684\u8bfe\u7a0b\u7ba1\u7406\u7cfb\u7edf\uff0c\u5b83\u901a\u8fc7\u4f7f\u7528\u540d\u5b57\u548c\u4e00\u7ec4\u8003\u8bd5\u5206\u6570\u6765\u6a21\u62df\u5b66\u751f\u7684\u4fe1\u606f\u3002\u8fd9\u4e2a\u7cfb\u7edf\u5e94\u8be5\u80fd\u591f\u521b\u5efa\u4e00\u4e2a\u5177\u6709\u7ed9\u5b9a\u540d\u5b57\u548c\u5206\u6570\uff08\u8d77\u521d\u5747\u4e3a0\uff09\u7684\u5b66\u751f\u5bf9\u8c61\u3002\u7cfb\u7edf\u5e94\u8be5\u80fd\u591f\u8bbf\u95ee\u548c\u66ff\u6362\u6307\u5b9a\u4f4d\u7f6e\u5904\u7684\u5206\u6570\uff08\u4ece0\u5f00\u59cb\u8ba1\u6570\uff09\u3001\u5f97\u5230\u5b66\u751f\u6709\u591a\u5c11\u6b21\u8003\u8bd5\u3001\u5f97\u5230\u7684\u6700\u9ad8\u5206\u3001\u5f97\u5230\u7684\u5e73\u5747\u5206\u4ee5\u53ca\u5b66\u751f\u7684\u59d3\u540d\u3002\u9664\u6b64\u4e4b\u5916\uff0c\u5728\u6253\u5370\u5b66\u751f\u5bf9\u8c61\u7684\u65f6\u5019\uff0c\u5e94\u8be5\u50cf\u4e0b\u9762\u8fd9\u6837\u663e\u793a\u5b66\u751f\u7684\u59d3\u540d\u548c\u5206\u6570\uff1a Name : Ken Lambert Score 1 : 88 Score 2 : 77 Score 3 : 100 \u8bf7\u5b9a\u4e49\u4e00\u4e2a\u652f\u6301\u8fd9\u4e9b\u529f\u80fd\u548c\u884c\u4e3a\u7684Student\u7c7b\uff0c\u5e76\u4e14\u7f16\u5199\u4e00\u4e2a\u521b\u5efaStudent\u5bf9\u8c61\u5e76\u8fd0\u884c\u5176\u65b9\u6cd5\u7684\u7b80\u77ed\u7684\u6d4b\u8bd5\u51fd\u6570\u3002 class Student : def __init__ ( self , name ): self . name = name self . scores = [] def add_score ( self , score ): self . scores . append ( score ) def replace_score ( self , index , score ): if 0 <= index < len ( self . scores ): self . scores [ index ] = score else : print ( \"\u65e0\u6548\u7684\u5206\u6570\u7d22\u5f15\" ) def num_scores ( self ): return len ( self . scores ) def highest_score ( self ): if self . scores : return max ( self . scores ) else : return None def average_score ( self ): if self . scores : return sum ( self . scores ) / len ( self . scores ) else : return None def display ( self ): print ( f \"Name: { self . name } \" ) for i , score in enumerate ( self . scores , start = 1 ): print ( f \"Score { i } : { score } \" ) def test_student_class (): student = Student ( \"Ken Lambert\" ) student . add_score ( 88 ) student . add_score ( 77 ) student . add_score ( 100 ) student . display () print ( f \"Total Scores: { student . num_scores () } \" ) print ( f \"Highest Score: { student . highest_score () } \" ) print ( f \"Average Score: { student . average_score () } \" ) if __name__ == \"__main__\" : test_student_class ()","title":"1.9.\u7f16\u7a0b\u7ec3\u4e60"},{"location":"python/DataStructure/02_CollectionsOverview/","text":"2.\u591a\u9879\u96c6\u7684\u6982\u8ff0 \u00b6 \u591a\u9879\u96c6\uff08collection\uff09\u662f\u6307\u7531 0 \u4e2a\u6216\u8005\u591a\u4e2a\u5143\u7d20\u7ec4\u6210\u7684\u6982\u5ff5\u5355\u5143\u3002 \u4ece\u4e24\u4e2a\u89d2\u5ea6\u770b\u5f85\u591a\u9879\u96c6\uff1a \u591a\u9879\u96c6\u7684\u7528\u6237\u6216\u8005\u5ba2\u6237\u4f1a\u5173\u5fc3\u5b83\u4eec\u5728\u4e0d\u540c\u7684\u5e94\u7528\u7a0b\u5e8f\u91cc\u80fd\u505a\u4e9b\u4ec0\u4e48\u3002 \u591a\u9879\u96c6\u7684\u5f00\u53d1\u8005\u6216\u8005\u5b9e\u73b0\u8005\u5219\u4f1a\u5173\u5fc3\u5982\u4f55\u624d\u80fd\u8ba9\u5b83\u4eec\u6210\u4e3a\u6700\u597d\u7684\u901a\u7528\u8d44\u6e90\u4ee5\u88ab\u4f7f\u7528\u3002 \u76ee\u6807\uff1a \u5b9a\u4e49\u591a\u9879\u96c6\u76844\u4e2a\u901a\u7528\u7c7b\u578b\uff1a \u7ebf\u6027\u591a\u9879\u96c6 \u5206\u5c42\u591a\u9879\u96c6 \u56fe\u591a\u9879\u96c6 \u65e0\u5e8f\u591a\u9879\u96c6 \u4e86\u89e34\u4e2a\u591a\u9879\u96c6\u7c7b\u578b\u4e2d\u7684\u7279\u5b9a\u7c7b\u578b\uff1b \u4e86\u89e3\u8fd9\u4e9b\u591a\u9879\u96c6\u9002\u5408\u7528\u5728\u4ec0\u4e48\u7c7b\u578b\u7684\u5e94\u7528\u7a0b\u5e8f\u91cc\uff1b \u63cf\u8ff0\u6bcf\u79cd\u591a\u9879\u96c6\u7c7b\u578b\u7684\u5e38\u7528\u64cd\u4f5c\uff1b \u63cf\u8ff0\u591a\u9879\u96c6\u7684\u62bd\u8c61\u7c7b\u578b\u548c\u5b9e\u73b0\u4e4b\u95f4\u7684\u533a\u522b\uff1b 2.1.\u591a\u9879\u96c6\u7c7b\u578b \u00b6 \u5185\u7f6e\u591a\u9879\u96c6\u7c7b\u578b\uff1a \u5b57\u7b26\u4e32 str \u5217\u8868 list \u5143\u7ec4 tuple \u96c6\u5408 set \u5b57\u5178 dict \u5176\u4ed6\u591a\u9879\u96c6\u7c7b\u578b\uff1a \u6808 \u961f\u5217 \u4f18\u5148\u961f\u5217 \u4e8c\u53c9\u67e5\u627e\u6811 \u5806 \u56fe \u5305 \u6709\u5e8f\u591a\u9879\u96c6 \u591a\u9879\u96c6\u901a\u5e38\u4e0d\u662f\u9759\u6001\uff08static\uff09\u7684\uff0c\u800c\u662f\u52a8\u6001\uff08dynamic\uff09\u7684\uff0c\u53ef\u4ee5\u6839\u636e\u9700\u8981\u6765\u6269\u5927\u6216\u8005\u7f29\u5c0f\u591a\u9879\u96c6\u3002 \u4e0d\u53ef\u53d8\u591a\u9879\u96c6\uff08immutable collection\uff09\u7684\u5185\u5bb9\u5728\u7a0b\u5e8f\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u662f\u4e0d\u53ef\u6539\u53d8\u7684\uff08\u5143\u7d20\u4e0d\u53ef\u4ee5\u6dfb\u52a0\u3001\u5220\u9664\u6216\u8005\u66ff\u6362\uff09\uff0c\u6bd4\u5982\u5143\u7ec4tuple\u3002 \u53ef\u53d8\u591a\u9879\u96c6\uff08mutable collection\uff09\u91cc\u7684\u5185\u5bb9\u53ef\u4ee5\u5728\u7a0b\u5e8f\u7684\u6574\u4e2a\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u88ab\u6539\u53d8\uff0c\u6bd4\u5982\u5b57\u7b26\u4e32\u3001\u5217\u8868list\u3002 \u591a\u9879\u96c6\u6309\u6784\u6210\u65b9\u5f0f\u5212\u5206\u7684\u7c7b\u578b\uff1a \u7ebf\u6027\u591a\u9879\u96c6 \u5206\u5c42\u591a\u9879\u96c6 \u56fe\u591a\u9879\u96c6 \u65e0\u5e8f\u591a\u9879\u96c6 \u6709\u5e8f\u591a\u9879\u96c6 2.1.1.\u7ebf\u6027\u591a\u9879\u96c6 \u00b6 \u7ebf\u6027\u591a\u9879\u96c6\uff08linear collection\uff09\u91cc\u7684\u5143\u7d20\u6309\u7167\u4f4d\u7f6e\u8fdb\u884c\u6392\u5217\u3002 \u9664\u4e86\u7b2c\u4e00\u4e2a\u5143\u7d20\uff0c\u5176\u4ed6\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\uff1b \u9664\u4e86\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff0c\u5176\u4ed6\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u540e\u5e8f\uff1b \u5b9e\u4f8b\uff1a\u6392\u961f\u7684\u4eba\uff0c\u8d2d\u7269\u6e05\u5355\uff0c\u5806\u53e0\u5728\u4e00\u8d77\u7684\u9910\u76d8\u7b49\u3002 2.1.2.\u5206\u5c42\u591a\u9879\u96c6 \u00b6 \u5206\u5c42\u591a\u9879\u96c6\uff08hierarchical collection\uff09\u91cc\u7684\u6570\u636e\u5143\u7d20\u4f1a\u4ee5\u7c7b\u4f3c\u4e8e\u5012\u7f6e\u7684\u6811\u7ed3\u6784\u8fdb\u884c\u6392\u5217\u3002\u9664\u4e86\u9876\u90e8\u7684\u6570\u636e\u5143\u7d20\uff0c\u5176\u4ed6\u6bcf\u4e2a\u6570\u636e\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\uff0c\u88ab\u79f0\u4e3a\u7236\u5143\u7d20\uff08parent\uff09\uff0c\u4f46\u5b83\u4eec\u53ef\u4ee5\u6709\u8bb8\u591a\u7684\u540e\u5e8f\uff0c\u88ab\u79f0\u4e3a\u5b50\u5143\u7d20\uff08children\uff09\u3002 \u56fe\u4f8b\u4e2d\uff0c D3 \u7684\u524d\u5e8f\u7236\u5143\u7d20\u662f D1 \uff0c D3 \u7684\u540e\u7eed\u5b50\u5143\u7d20\u662f D4 \u3001 D5 \u3001 D6 \u3002 \u5b9e\u4f8b\uff1a\u6587\u4ef6\u76ee\u5f55\u7cfb\u7edf\u3001\u516c\u53f8\u7684\u7ec4\u7ec7\u67b6\u6784\u3001\u4e66\u7684\u76ee\u5f55\u7b49\u3002 2.1.3.\u56fe\u591a\u9879\u96c6 \u00b6 \u56fe\u591a\u9879\u96c6\uff08graph collection\uff09\u4e5f\u88ab\u79f0\u4e3a\u56fe\uff08graph\uff09\uff0c\u5b83\u662f\u8fd9\u6837\u4e00\u4e2a\u591a\u9879\u96c6\uff1a\u5b83\u7684\u6bcf\u4e00\u4e2a\u6570\u636e\u5143\u7d20\u90fd\u53ef\u4ee5\u6709\u591a\u4e2a\u524d\u5e8f\u548c\u591a\u4e2a\u540e\u5e8f\u3002 \u56fe\u4f8b\u4e2d\uff0c\u8fde\u63a5\u5230 D3 \u7684\u6240\u6709\u5143\u7d20\u4f1a\u88ab\u5f53\u4f5c\u5b83\u7684\u524d\u5e8f\u548c\u540e\u5e8f\uff0c\u5b83\u4eec\u4e5f\u56e0\u6b64\u88ab\u79f0\u4e3a D3 \u7684\u90bb\u5c45\u3002 \u5b9e\u4f8b\uff1a\u57ce\u5e02\u4e4b\u95f4\u7684\u822a\u7ebf\u56fe\u3001\u4e07\u7ef4\u7f51\u7b49\u3002 2.1.4.\u65e0\u5e8f\u591a\u9879\u96c6 \u00b6 \u65e0\u5e8f\u591a\u9879\u96c6\uff08unordered collection\uff09\u91cc\u7684\u5143\u7d20\u6ca1\u6709\u7279\u5b9a\u7684\u987a\u5e8f\uff0c\u5e76\u4e14\u4e0d\u4f1a\u7528\u4efb\u4f55\u660e\u786e\u7684\u65b9\u5f0f\u6765\u6307\u51fa\u5143\u7d20\u7684\u524d\u5e8f\u6216\u8005\u540e\u5e8f\u3002 \u5b9e\u4f8b\uff1a\u4e00\u888b\u5f39\u73e0\u7b49\u3002 2.1.5.\u6709\u5e8f\u591a\u9879\u96c6 \u00b6 \u6709\u5e8f\u591a\u9879\u96c6\uff08sorted collection\uff09\u4f1a\u5bf9\u5b83\u91cc\u9762\u7684\u5143\u7d20\u8fdb\u884c\u81ea\u7136\u6392\u5e8f\uff08natural ordering\uff09\u3002 \u8981\u8fdb\u884c\u81ea\u7136\u6392\u5e8f\uff0c\u5c31\u5fc5\u987b\u8981\u6709\u89c4\u5219\u6765\u5bf9\u6709\u5e8f\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u52a0\u4ee5\u6bd4\u8f83\uff0c\u4f8b\u5982 item(i) <= item(i+1) \u8fd9\u6837\u7684\u2014\u2014\u89c4\u5219\u3002 \u6709\u5e8f\u5217\u8868\u662f\u6700\u5e38\u89c1\u7684\u6709\u5e8f\u591a\u9879\u96c6\u3002\u6709\u5e8f\u591a\u9879\u96c6\u4e0d\u4e00\u5b9a\u662f\u7ebf\u6027\u7684\u6216\u8005\u6309\u7167\u4f4d\u7f6e\u8fdb\u884c\u6392\u5e8f\u7684\u3002 \u5bf9\u4e8e\u96c6\u5408\u3001\u5305\u3001\u5b57\u5178\uff0c\u867d\u7136\u4e0d\u80fd\u6309\u7167\u4f4d\u7f6e\u6765\u8bbf\u95ee\u5b83\u4eec\u7684\u5143\u7d20\uff0c\u4f46\u5b83\u4eec\u90fd\u53ef\u4ee5\u662f\u6709\u5e8f\u7684\u3002 \u7279\u6b8a\u7684\u5206\u5c42\u591a\u9879\u96c6\u7c7b\u578b\uff08\u5982\u4e8c\u53c9\u67e5\u627e\u6811\uff09\u4e5f\u4f1a\u5bf9\u5176\u4e2d\u7684\u5143\u7d20\u8fdb\u884c\u81ea\u7136\u6392\u5e8f\u3002 2.1.6.\u591a\u9879\u96c6\u7c7b\u578b\u7684\u5206\u7c7b \u00b6 \u4e0b\u9762\u5206\u7c7b\u91cc\u7684\u7c7b\u578b\u540d\u79f0\u6307\u7684\u5e76\u4e0d\u662f\u591a\u9879\u96c6\u7684\u7279\u5b9a\u5b9e\u73b0\u3002\u4e00\u79cd\u7279\u5b9a\u7c7b\u578b\u7684\u591a\u9879\u96c6\u53ef\u4ee5\u6709\u591a\u4e2a\u5b9e\u73b0\u3002 \u591a\u9879\u96c6 | ---\u56fe\u591a\u9879\u96c6 | ---\u5206\u5c42\u591a\u9879\u96c6 | | ---\u4e8c\u53c9\u67e5\u627e\u6811 | | ---\u5806 | ---\u7ebf\u6027\u591a\u9879\u96c6 | | ---\u5217\u8868 | | | ---\u6709\u5e8f\u5217\u8868 | | ---\u961f\u5217 | | | ---\u4f18\u5148\u5bf9\u5217 | | ---\u6808 | | ---\u5b57\u7b26\u4e32 | ---\u65e0\u5e8f\u591a\u9879\u96c6 | ---\u5305 | | ---\u6709\u5e8f\u5305 | ---\u5b57\u5178 | | ---\u6709\u5e8f\u5305 | ---\u96c6\u5408 | ---\u6709\u5e8f\u96c6\u5408 2.2.\u591a\u9879\u96c6\u64cd\u4f5c \u00b6 \u591a\u9879\u96c6\u64cd\u4f5c\u7c7b\u522b\uff1a \u786e\u5b9a\u5927\u5c0f\uff1a\u4f7f\u7528 len \u51fd\u6570\u83b7\u53d6\u5f53\u524d\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u6570\u91cf\u3002 \u68c0\u6d4b\u5143\u7d20\u6210\u5458\uff1a\u4f7f\u7528 in \u8fd0\u7b97\u7b26\u5728\u591a\u9879\u96c6\u91cc\u641c\u7d22\u6307\u5b9a\u7684\u76ee\u6807\u5143\u7d20\u3002\u5982\u679c\u627e\u5230\u4e86\u8fd9\u4e2a\u5143\u7d20\uff0c\u5219\u8fd4\u56deTrue\uff0c\u5426\u5219\u8fd4\u56deFalse\u3002 \u904d\u5386\u591a\u9879\u96c6\uff1a\u4f7f\u7528 for \u5faa\u73af\u8bbf\u95ee\u591a\u9879\u96c6\u91cc\u7684\u6b38\u4e00\u4e2a\u5143\u7d20\u3002\u5143\u7d20\u7684\u8bbf\u95ee\u987a\u5e8f\u53d6\u51b3\u4e8e\u591a\u9879\u96c6\u7684\u7c7b\u578b\u3002 \u83b7\u53d6\u591a\u9879\u96c6\u7684\u5b57\u7b26\u4e32\u8868\u793a\uff1a\u4f7f\u7528 str \u51fd\u6570\u83b7\u53d6\u591a\u9879\u96c6\u7684\u5b57\u7b26\u4e32\u8868\u793a\u3002 \u76f8\u7b49\u68c0\u6d4b\uff1a\u4f7f\u7528 == \u8fd0\u7b97\u7b26\u6765\u786e\u5b9a\u4e24\u4e2a\u591a\u9879\u96c6\u662f\u5426\u76f8\u7b49\u3002\u5982\u679c\u4e24\u4e2a\u591a\u9879\u96c6\u80b2\u6709\u76f8\u540c\u7684\u7c7b\u578b\uff0c\u5e76\u4e14\u5305\u542b\u76f8\u540c\u7684\u5143\u7d20\uff0c\u90a3\u4e48\u5b83\u4eec\u5c31\u662f\u76f8\u7b49\u7684\u3002\u6bd4\u8f83\u8fd9\u4e9b\u5143\u7d20\u5bf9\u7684\u987a\u5e8f\u53d6\u51b3\u4e8e\u591a\u9879\u96c6\u7684\u7c7b\u578b\u3002 \u8fde\u63a5\u4e24\u4e2a\u591a\u9879\u96c6\uff1a\u4f7f\u7528 + \u8fd0\u7b97\u7b26\u6765\u5f97\u5230\u4e00\u4e2a\u548c\u64cd\u4f5c\u6570\u76f8\u540c\u7c7b\u578b\u7684\u65b0\u591a\u9879\u96c6\uff0c\u5e76\u4e14\u5305\u542b\u4e24\u4e2a\u64cd\u4f5c\u6570\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002 \u8f6c\u6362\u4e3a\u5176\u4ed6\u7c7b\u578b\u7684\u591a\u9879\u96c6\uff1a\u521b\u5efa\u4e00\u4e2a\u4e0e\u6e90\u591a\u9879\u96c6\u5177\u6709\u76f8\u540c\u5143\u7d20\u7684\u65b0\u591a\u9879\u96c6\u3002\u514b\u9686\u64cd\u4f5c\u65f6\u7c7b\u578b\u8f6c\u6362\u7684\u4e00\u79cd\u7279\u6b8a\u60c5\u51b5\uff0c\u56e0\u4e3a\u8f93\u5165\u8f93\u51fa\u7684\u4e24\u4e2a\u591a\u9879\u96c6\u5177\u6709\u76f8\u540c\u7c7b\u578b\u3002 \u63d2\u5165\u4e00\u4e2a\u5143\u7d20\uff1a\u5982\u679c\u53ef\u4ee5\uff0c\u5219\u5728\u7ed9\u5b9a\u7684\u4f4d\u7f6e\u5c06\u5bf9\u5e94\u7684\u5143\u7d20\u6dfb\u52a0\u5230\u591a\u9879\u96c6\u91cc\u3002 \u5220\u9664\u4e00\u4e2a\u5143\u7d20\uff1a\u5982\u679c\u53ef\u4ee5\uff0c\u5219\u5728\u7ed9\u5b9a\u7684\u4f4d\u7f6e\u5c06\u5bf9\u5e94\u7684\u5143\u7d20\u4ece\u591a\u9879\u96c6\u4e2d\u5220\u9664\u3002 \u66ff\u6362\u4e00\u4e2a\u5143\u7d20\uff1a\u5c06\u5220\u9664\u548c\u63d2\u5165\u5408\u5e76\u4e3a\u4e00\u9879\u64cd\u4f5c\u3002 \u8bbf\u95ee\u6216\u8005\u83b7\u53d6\u5143\u7d20\uff1a\u5982\u679c\u800c\u5df2\uff0c\u5219\u5728\u7ed9\u5b9a\u7684\u4f4d\u7f6e\u83b7\u53d6\u5143\u7d20\u3002 2.2.1.\u6240\u6709\u591a\u9879\u96c6\u7c7b\u578b\u4e2d\u7684\u57fa\u672c\u64cd\u4f5c \u00b6 \u5728Python\u91cc\uff0c\u4e0d\u540c\u591a\u9879\u96c6\u7c7b\u578b\u7684\u63d2\u5165\u3001\u5220\u9664\u3001\u66ff\u6362\u6216\u8005\u8bbf\u95ee\u64cd\u4f5c\u5e76\u6ca1\u6709\u7edf\u4e00\u7684\u540d\u79f0\uff0c\u4f46\u662f\u4f1a\u6709\u4e00\u4e9b\u6807\u51c6\u53d8\u4f53\u3002\u6bd4\u5982\uff0c \u65b9\u6cd5pop\u4f1a\u88ab\u7528\u6765\u4ece\u5217\u8868\u91cc\u79fb\u9664\u6307\u5b9a\u4f4d\u7f6e\u7684\u5143\u7d20\uff1b \u65b9\u6cd5pop\u4f1a\u88ab\u7528\u6765\u4ece\u5b57\u5178\u91cc\u79fb\u9664\u7ed9\u5b9a\u952e\u6240\u5bf9\u5e94\u7684\u503c\uff1b \u65b9\u6cd5remove\u4f1a\u88ab\u7528\u6765\u4ece\u5217\u8868\u6216\u8005\u67d0\u4e9b\u591a\u9879\u96c6\u91cc\u5220\u9664\u6307\u5b9a\u7684\u5143\u7d20\uff1b \u5bf9\u4e8e\u65b0\u5f00\u53d1\u51fa\u7684\u3001Python\u5c1a\u4e0d\u652f\u6301\u7684\u591a\u9879\u96c6\u7c7b\u578b\uff0c\u5c3d\u53ef\u80fd\u5730\u4f7f\u7528\u6807\u51c6\u7684\u8fd0\u7b97\u7b26\u3001\u51fd\u6570\u4ee5\u53ca\u65b9\u6cd5\u540d\u79f0\u5bf9\u5b83\u4eec\u8fdb\u884c\u64cd\u4f5c\u3002 2.2.2.\u7c7b\u578b\u8f6c\u6362 \u00b6 \u7c7b\u578b\u8f6c\u6362\uff0c\u5c06\u4e00\u79cd\u7c7b\u578b\u7684\u591a\u9879\u96c6\u8f6c\u6362\u4e3a\u53e6\u4e00\u79cd\u7c7b\u578b\u7684\u591a\u9879\u96c6\u3002\u4f8b\u5982\uff0c\u901a\u8fc7 list \u6216 tuple \u51fd\u6570\u5c06\u5b57\u7b26\u4e32\u8f6c\u6362\u4e3a\u5217\u8868\u6216\u8005\u5143\u7ec4\u3002 list \u6216 tuple \u51fd\u6570\u7684\u53c2\u6570\u4e0d\u4e00\u5b9a\u662f\u53e6\u4e00\u4e2a\u591a\u9879\u96c6\uff0c\u4e5f\u53ef\u4ee5\u662f\u4efb\u4f55\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08iterable object\uff09\u3002 \u53ef\u8fed\u4ee3\u5bf9\u8c61\u662f\u6307\uff0c\u80fd\u591f\u4f7f\u7528for\u5faa\u73af\u6765\u8bbf\u95ee\u7684\u4e00\u7cfb\u5217\u5143\u7d20\u3002\uff08\u591a\u9879\u96c6\u672c\u8eab\u4e5f\u662f\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff09 2.2.3.\u514b\u9686\u548c\u76f8\u7b49\u6027 \u00b6 \u7c7b\u578b\u8f6c\u6362\u7684\u4e00\u79cd\u7279\u6b8a\u60c5\u51b5\u662f\u514b\u9686\uff0c\u5b83\u7684\u529f\u80fd\u662f\u8fd4\u56de\u8f6c\u6362\u51fd\u6570\u4e2d\u53c2\u6570\u7684\u5b8c\u6574\u526f\u672c\u3002 \u4f8b\u5982\uff1a myList1 = [ 2 , 4 , 8 ] myList2 = list ( myList1 ) myList1 is myList2 # False myList1 == myList2 # True \u6ce8\u610f\uff1a \u4e0a\u9762\u4e24\u4e2a\u5217\u8868\u4e0d\u4ec5\u6709\u76f8\u540c\u7684\u7ed3\u6784\uff0c\u5b83\u4eec\u8fd8\u6709\u76f8\u540c\u7684\u5143\u7d20\uff0c\u6bcf\u5bf9\u5143\u7d20\u5728\u4e24\u4e2a\u5217\u8868\u91cc\u7684\u4f4d\u7f6e\u90fd\u76f8\u540c\u3002\u4f46\u662f\uff0c\u4ed6\u4eec\u662f\u4e24\u4e2a\u4e0d\u540c\u7684\u5bf9\u8c61\u3002 \u4e0a\u4f8b\u4e2d list \u51fd\u6570\u5bf9\u5b83\u7684\u53c2\u6570\u5217\u8868\u8fdb\u884c\u6d45\u62f7\u8d1d\uff08shallow copy\uff09\u3002\u8fd9\u4e9b\u5143\u7d20\u7684\u672c\u8eab\u5728\u6dfb\u52a0\u5230\u65b0\u5217\u8868\u4e4b\u524d\u662f\u4e0d\u4f1a\u88ab\u514b\u9686\u7684\uff0c\u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e2d\u53ea\u4f1a\u590d\u5236\u5bf9\u8fd9\u4e9b\u5bf9\u8c61\u7684\u5f15\u7528\u3002\u5f53\u5143\u7d20\uff08\u6570\u5b57\u3001\u5b57\u7b26\u4e32\u6216\u8005Python\u7684\u5143\u7ec4\uff09\u4e0d\u53ef\u53d8\u65f6\uff0c\u8fd9\u4e2a\u7b56\u7565\u4e0d\u4f1a\u5f15\u8d77\u95ee\u9898\u3002\u4f46\u662f\uff0c\u5982\u679c\u591a\u9879\u96c6\u5305\u542b\u7684\u662f\u53ef\u53d8\u5143\u7d20\uff0c\u5c31\u53ef\u80fd\u4f1a\u4ea7\u751f\u526f\u4f5c\u7528\u3002\u4e3a\u4e86\u907f\u514d\u8fd9\u79cd\u60c5\u51b5\u7684\u53d1\u751f\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u5bf9\u6e90\u591a\u9879\u96c6\u7f16\u5199 for \u5faa\u73af\u6765\u521b\u5efa\u6df1\u62f7\u8d1d\uff08deep copy\uff09\uff0c\u8fd9\u4f1a\u628a\u5143\u7d20\u663e\u5f0f\u5730\u514b\u9686\u4e4b\u540e\u518d\u6dfb\u52a0\u5230\u65b0\u7684\u591a\u9879\u96c6\u91cc\u3002 2.3.\u8fed\u4ee3\u5668\u548c\u9ad8\u9636\u51fd\u6570 \u00b6 \u6bcf\u79cd\u7c7b\u578b\u7684\u591a\u9879\u96c6\u90fd\u652f\u6301\u4e00\u4e2a\u8fed\u4ee3\u5668\u6216 for \u5faa\u73af\uff0c\u8fd9\u4e2a\u64cd\u4f5c\u80fd\u591f\u8fed\u4ee3\u8fd9\u4e2a\u591a\u9879\u96c6\u7684\u6240\u6709\u5143\u7d20\u3002\u8fed\u4ee3\u5668\u662f\u591a\u9879\u96c6\u63d0\u4f9b\u7684\u6700\u5173\u952e\u7684\u64cd\u4f5c\u3002 for \u5faa\u73af\u670d\u52a1\u7684\u591a\u9879\u96c6\u4e2d\u5143\u7d20\u7684\u987a\u5e8f\u53d6\u51b3\u4e8e\u591a\u9879\u96c6\u7684\u7ec4\u7ec7\u65b9\u5f0f\u3002\u4f8b\u5982\uff1a \u5217\u8868\u91cc\u7684\u5143\u7d20\u4f1a\u4ece\u5934\u5230\u5c3e\u6309\u7167\u4f4d\u7f6e\u8fdb\u884c\u8bbf\u95ee\uff1b \u6709\u5e8f\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u4f1a\u6309\u4ece\u5c0f\u5230\u5927\u7684\u5347\u5e8f\u8fdb\u884c\u8bbf\u95ee\uff1b \u5bf9\u4e8e\u96c6\u5408\u6216\u8005\u5b57\u5178\u91cc\u7684\u5143\u7d20\u6765\u8bf4\uff0c\u4e0d\u4f1a\u6309\u7167\u7279\u5b9a\u7684\u987a\u5e8f\u8fdb\u884c\u8bbf\u95ee\u3002 \u8fed\u4ee3\u5668\uff08\u4f8b\u5982 for \u5faa\u73af\uff09\u8fd8\u652f\u6301\u4f7f\u7528\u9ad8\u9636\u51fd\u6570 map \u3001 filter \u548c reduce \u3002 \u8fd9\u4e9b\u9ad8\u9636\u51fd\u6570\u90fd\u4f7f\u7528\u53e6\u4e00\u4e2a\u51fd\u6570\u548c\u4e00\u4e2a\u591a\u9879\u96c6\u4f5c\u4e3a\u53c2\u6570\u3002 \u591a\u9879\u96c6\u90fd\u652f\u6301 for \u5faa\u73af\uff0c\u6240\u4ee5 map \u3001 filter \u548c reduce \u51fd\u6570\u53ef\u4ee5\u4e0e\u4efb\u4f55\u7c7b\u578b\u7684\u591a\u9879\u96c6\u4e00\u8d77\u4f7f\u7528\u3002 2.4.\u591a\u9879\u96c6\u7684\u5b9e\u73b0 \u00b6 \u4ece\u7528\u6237\uff08\u6bd4\u5982\uff0c\u7a0b\u5e8f\u5458\uff09\u7684\u89d2\u5ea6\u6765\u770b\uff0c\u591a\u9879\u96c6\u662f\u4e00\u79cd\u62bd\u8c61\uff0c\u662f\u4e00\u79cd\u4ee5\u67d0\u79cd\u9884\u5b9a\u884c\u4e3a\u6765\u5b58\u50a8\u548c\u8bbf\u95ee\u6570\u636e\u5143\u7d20\u7684\u65b9\u5f0f\uff0c\u5e76\u4e0d\u9700\u8981\u5173\u5fc3\u591a\u9879\u96c6\u5b9e\u73b0\u7684\u7ec6\u8282\u3002 \u591a\u9879\u96c6\u4e5f\u88ab\u79f0\u4e3a\u62bd\u8c61\u6570\u636e\u7c7b\u578b\uff08Abstract Data Type\uff0cADT\uff09\u3002\u62bd\u8c61\u6570\u636e\u7c7b\u578b\u7684\u7528\u6237\u53ea\u5173\u6ce8\u5b83\u7684\u63a5\u53e3\u4ee5\u53ca\u8fd9\u4e2a\u7c7b\u578b\u5bf9\u8c61\u6240\u63d0\u4f9b\u7684\u4e00\u7ec4\u64cd\u4f5c\u3002 \u5728Python\u91cc\uff0c\u51fd\u6570\u548c\u65b9\u6cd5\u662f\u6700\u5c0f\u7684\u62bd\u8c61\u5355\u5143\uff0c\u7c7b\u7684\u5927\u5c0f\u6b21\u4e4b\uff0c\u6a21\u5757\u662f\u6700\u5927\u7684\u62bd\u8c61\u5355\u5143\u3002 \u8fd9\u91cc\u4f1a\u628a\u62bd\u8c61\u591a\u9879\u96c6\u7c7b\u578b\u7684\u5b9e\u73b0\u5f53\u4f5c\u6a21\u5757\u91cc\u7684\u7c7b\u6216\u8005\u4e00\u7ec4\u76f8\u5173\u7684\u7c7b\u52a0\u4ee5\u63cf\u8ff0\u3002\u6784\u5efa\u8fd9\u4e9b\u7c7b\u5c31\u662f\u9762\u5411\u5bf9\u8c61\u7f16\u7a0b\u3002 2.5.\u5c0f\u7ed3 \u00b6 \u591a\u9879\u96c6\u662f\u5305\u542b0\u4e2a\u6216\u591a\u4e2a\u5176\u4ed6\u5bf9\u8c61\u7684\u5bf9\u8c61\u3002\u591a\u9879\u96c6\u53ef\u4ee5\u8fdb\u884c\u7684\u64cd\u4f5c\u6709\u8bbf\u95ee\u5bf9\u8c61\u3001\u63d2\u5165\u5bf9\u8c61\u3001\u5220\u9664\u5bf9\u8c61\u3001\u786e\u5b9a\u591a\u9879\u96c6\u7684\u5927\u5c0f\uff0c\u4ee5\u53ca\u904d\u5386\u6216\u8bbf\u95ee\u8fd9\u4e2a\u591a\u9879\u96c6\u7684\u5bf9\u8c61\u3002 \u591a\u9879\u96c6\u76845\u4e2a\u4e3b\u8981\u7c7b\u578b\u662f\uff1a\u7ebf\u6027\u591a\u9879\u96c6\u3001\u5206\u5c42\u591a\u9879\u96c6\u3001\u56fe\u591a\u9879\u96c6\u3001\u65e0\u5e8f\u591a\u9879\u96c6\u548c\u6709\u5e8f\u591a\u9879\u96c6\u3002 \u7ebf\u6027\u591a\u9879\u96c6\u4f1a\u6309\u7167\u4f4d\u7f6e\u5bf9\u5143\u7d20\u8fdb\u884c\u6392\u5e8f\uff0c\u5176\u4e2d\u9664\u4e86\u7b2c\u4e00\u4e2a\u5143\u7d20\uff0c\u6bcf\u4e2a\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\uff1b\u9664\u4e86\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff0c\u6bcf\u4e2a\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u540e\u5e8f\u3002 \u5728\u5206\u5c42\u591a\u9879\u96c6\u91cc\uff0c\u9664\u4e86\u4e00\u4e2a\u5143\u7d20\uff0c\u5176\u4ed6\u6240\u6709\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\u4ee5\u53ca0\u4e2a\u6216\u591a\u4e2a\u540e\u5e8f\u3002\u88ab\u79f0\u4e3a\u6839\u7684\u90a3\u4e2a\u989d\u5916\u5143\u7d20\u6ca1\u6709\u524d\u5e8f\u3002 \u56fe\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u53ef\u4ee5\u67090\u4e2a\u6216\u591a\u4e2a\u524d\u5e8f\u4ee5\u53ca0\u4e2a\u6216\u591a\u4e2a\u540e\u5e8f\u3002 \u65e0\u5e8f\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u6ca1\u6709\u7279\u5b9a\u7684\u987a\u5e8f\u3002 \u591a\u9879\u96c6\u662f\u53ef\u8fed\u4ee3\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\uff0c\u53ef\u4ee5\u4f7f\u7528for\u5faa\u73af\u8bbf\u95ee\u591a\u9879\u96c6\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u7a0b\u5e8f\u5458\u4e5f\u53ef\u4ee5\u4f7f\u7528\u9ad8\u9636\u51fd\u6570map\u3001filter\u548creduce\u7b80\u5316\u591a\u9879\u96c6\u7684\u6570\u636e\u5904\u7406\u3002 \u62bd\u8c61\u6570\u636e\u7c7b\u578b\u662f\u4e00\u7ec4\u5bf9\u8c61\u548c\u5bf9\u8fd9\u4e9b\u5bf9\u8c61\u7684\u64cd\u4f5c\u3002\u56e0\u6b64\uff0c\u591a\u9879\u96c6\u662f\u62bd\u8c61\u6570\u636e\u7c7b\u578b\u3002 \u6570\u636e\u7ed3\u6784\u662f\u4e00\u4e2a\u8868\u793a\u591a\u9879\u96c6\u91cc\u5305\u542b\u7684\u6570\u636e\u7684\u5bf9\u8c61\u3002 2.6.\u590d\u4e60\u9898 \u00b6 \u7ebf\u6027\u591a\u9879\u96c6\u7684\u4e00\u4e2a\u4f8b\u5b50\u662f\uff1a \u96c6\u5408\u548c\u6811 \u5217\u8868\u548c\u6808 \u65e0\u5e8f\u591a\u9879\u96c6\u7684\u4e00\u4e2a\u4f8b\u5b50\u662f\uff1a \u961f\u5217\u548c\u5217\u8868 \u96c6\u5408\u548c\u5b57\u5178 \u5206\u5c42\u591a\u9879\u96c6\u53ef\u4ee5\u7528\u6765\u8868\u793a\uff1a \u94f6\u884c\u6392\u961f\u7684\u5ba2\u6237 \u6587\u4ef6\u76ee\u5f55\u7cfb\u7edf \u56fe\u591a\u9879\u96c6\u6700\u80fd\u4ee3\u8868\uff1a \u4e00\u7ec4\u6570\u5b57 \u57ce\u5e02\u4e4b\u95f4\u7684\u822a\u7ebf\u56fe \u5728Python\u91cc\uff0c\u4e24\u4e2a\u591a\u9879\u96c6\u95f4\u7684\u7c7b\u578b\u8f6c\u6362\u64cd\u4f5c\uff1a \u5728\u6e90\u591a\u9879\u96c6\u91cc\u521b\u5efa\u5bf9\u8c61\u7684\u526f\u672c\uff0c\u5e76\u4e14\u628a\u8fd9\u4e9b\u65b0\u5bf9\u8c61\u6dfb\u52a0\u5230\u76ee\u6807\u591a\u9879\u96c6\u7684\u65b0\u5b9e\u4f8b\u91cc \u628a\u5bf9\u6e90\u591a\u9879\u96c6\u5bf9\u8c61\u7684\u5f15\u7528\u6dfb\u52a0\u5230\u76ee\u6807\u591a\u9879\u96c6\u7684\u65b0\u5b9e\u4f8b\u91cc \u4e24\u4e2a\u5217\u8868\u7684 == \u64cd\u4f5c\u5fc5\u987b\uff1a \u6bd4\u8f83\u6bcf\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u5bf9\u662f\u5426\u76f8\u7b49 \u53ea\u4f1a\u9a8c\u8bc1\u4e00\u4e2a\u5217\u8868\u91cc\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u662f\u5426\u4e5f\u5728\u53e6\u4e00\u4e2a\u5217\u8868\u91cc \u4e24\u4e2a\u96c6\u5408\u7684 == \u64cd\u4f5c\u5fc5\u987b\uff1a \u6bd4\u8f83\u6bcf\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u5bf9\u662f\u5426\u76f8\u7b49 \u9a8c\u8bc1\u96c6\u5408\u7684\u5927\u5c0f\u662f\u5426\u76f8\u7b49\uff0c\u5e76\u4e14\u4e00\u4e2a\u96c6\u5408\u91cc\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u662f\u5426\u4e5f\u5728\u53e6\u4e00\u4e2a\u96c6\u5408\u91cc \u5bf9\u5217\u8868\u8fdb\u884c for \u5faa\u73af\u65f6\uff0c\u8bbf\u95ee\u5143\u7d20\u7684\u987a\u5e8f\uff1a \u4ece\u5934\u5230\u5c3e\u7684\u6240\u6709\u4f4d\u7f6e \u4e0d\u4f1a\u6309\u7167\u7279\u5b9a\u7684\u987a\u5e8f map \u51fd\u6570\u4f1a\u521b\u5efa\u4e00\u4e2a\u4ec0\u4e48\u6837\u7684\u5e8f\u5217\uff1a \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u901a\u8fc7\u5e03\u5c14\u6d4b\u8bd5\u7684\u5143\u7d20 \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u5bf9\u5143\u7d20\u6267\u884c\u51fd\u6570\u7684\u7ed3\u679c filter \u51fd\u6570\u4f1a\u521b\u5efa\u4e00\u4e2a\u4ec0\u4e48\u6837\u7684\u5e8f\u5217\uff1a \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u901a\u8fc7\u5e03\u5c14\u6d4b\u8bd5\u7684\u5143\u7d20 \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u5bf9\u5143\u7d20\u6267\u884c\u51fd\u6570\u7684\u7ed3\u679c 2.7.\u7f16\u7a0b\u7ec3\u4e60 \u00b6 1\uff0e\u5728Shell\u7a97\u53e3\u7684\u63d0\u793a\u7b26\u4e0b\u4f7f\u7528 dir \u548c help \u51fd\u6570\u6765\u63a2\u7d22Python\u7684\u5185\u7f6e\u591a\u9879\u96c6\u7c7b\u578b str \u3001 list \u3001 tuple \u3001 set \u4ee5\u53ca dict \u7684\u63a5\u53e3\u3002\u5b83\u4eec\u7684\u8bed\u6cd5\u662f dir() \u548c help() \u3002 \u89e3\u7b54\uff1a \u53ef\u4ee5\u901a\u8fc7\u4ee5\u4e0b\u65b9\u5f0f\u6765\u4e86\u89e3\u5b83\u4eec\u7684\u63a5\u53e3\uff1a \u5b57\u7b26\u4e32 ( str ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5b57\u7b26\u4e32\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( str ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5b57\u7b26\u4e32\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( str ) \u5217\u8868 ( list ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5217\u8868\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( list ) x # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5217\u8868\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( list ) \u5143\u7ec4 ( tuple ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5143\u7ec4\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( tuple ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5143\u7ec4\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( tuple ) \u96c6\u5408 ( set ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u96c6\u5408\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( set ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u96c6\u5408\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( set ) \u5b57\u5178 ( dict ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5b57\u5178\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( dict ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5b57\u5178\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( dict ) dir() \u51fd\u6570\u5c06\u8fd4\u56de\u4e00\u4e2a\u5305\u542b\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027\u540d\u79f0\u7684\u5217\u8868\uff0c\u800c help() \u51fd\u6570\u5c06\u663e\u793a\u5173\u4e8e\u8be5\u7c7b\u578b\u7684\u8be6\u7ec6\u5e2e\u52a9\u4fe1\u606f\uff0c\u5305\u62ec\u6bcf\u4e2a\u65b9\u6cd5\u7684\u8bf4\u660e\u548c\u7528\u6cd5\u793a\u4f8b\u3002 2\uff0e\u67e5\u770b java.util \u5305\u91cc\u6240\u63d0\u4f9b\u7684Java\u591a\u9879\u96c6\u7c7b\u578b\uff0c\u5e76\u548cPython\u7684\u591a\u9879\u96c6\u7c7b\u578b\u52a0\u4ee5\u6bd4\u8f83\u3002 java.util \u5305\u4e2d\u63d0\u4f9b\u4e86\u8bb8\u591aJava\u7684\u96c6\u5408\u7c7b\u578b\uff0c\u5305\u62ec\u5217\u8868\u3001\u96c6\u5408\u3001\u6620\u5c04\u7b49\u3002\u4e0b\u9762\u5c06\u5217\u51fa\u5176\u4e2d\u4e00\u4e9b\u5e38\u7528\u7684\u591a\u9879\u96c6\u7c7b\u578b\uff0c\u5e76\u5c06\u5b83\u4eec\u4e0ePython\u4e2d\u7684\u591a\u9879\u96c6\u7c7b\u578b\u8fdb\u884c\u6bd4\u8f83\u3002 Java ArrayList vs Python List: Java ArrayList \u662f\u4e00\u4e2a\u53ef\u53d8\u5927\u5c0f\u7684\u52a8\u6001\u6570\u7ec4\u3002 Python List \u4e5f\u662f\u53ef\u53d8\u5927\u5c0f\u7684\u52a8\u6001\u6570\u7ec4\uff0c\u53ef\u4ee5\u5bb9\u7eb3\u4efb\u610f\u7c7b\u578b\u7684\u6570\u636e\u3002 Java HashSet vs Python Set: Java HashSet \u662f\u4e00\u4e2a\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\u7684\u96c6\u5408\u3002 Python Set \u4e5f\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\uff0c\u540c\u65f6\u8fd8\u6709\u4e00\u4e2a\u7279\u6b8a\u7c7b\u578b\u7684\u96c6\u5408\u53eb\u505a frozenset \uff0c\u5b83\u662f\u4e0d\u53ef\u53d8\u7684\u3002 Java LinkedHashSet vs Python OrderedDict: Java LinkedHashSet \u662f\u4e00\u4e2a\u4fdd\u6301\u5143\u7d20\u63d2\u5165\u987a\u5e8f\u7684\u96c6\u5408\uff0c\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\u3002 Python OrderedDict \u662f\u4e00\u4e2a\u6709\u5e8f\u5b57\u5178\uff0c\u4fdd\u6301\u5143\u7d20\u63d2\u5165\u987a\u5e8f\uff0c\u53ef\u4ee5\u7528\u4e8e\u521b\u5efa\u6709\u5e8f\u7684\u952e-\u503c\u5bf9\u96c6\u5408\u3002 Java TreeSet vs Python SortedSet: Java TreeSet \u662f\u4e00\u4e2a\u81ea\u7136\u6392\u5e8f\u6216\u8005\u901a\u8fc7\u63d0\u4f9b\u7684\u6bd4\u8f83\u5668\u8fdb\u884c\u6392\u5e8f\u7684\u96c6\u5408\uff0c\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\u3002 Python \u6ca1\u6709\u4e13\u95e8\u7684 SortedSet \u7c7b\uff0c\u4f46\u4f60\u53ef\u4ee5\u4f7f\u7528 sorted() \u51fd\u6570\u5bf9\u96c6\u5408\u8fdb\u884c\u6392\u5e8f\u3002 Java HashMap vs Python Dictionary: Java HashMap \u662f\u4e00\u4e2a\u65e0\u5e8f\u7684\u952e-\u503c\u5bf9\u6620\u5c04\uff0c\u4e0d\u5141\u8bb8\u91cd\u590d\u952e\u3002 Python Dictionary \u662f\u4e00\u4e2a\u65e0\u5e8f\u7684\u952e-\u503c\u5bf9\u6620\u5c04\uff0c\u952e\u662f\u552f\u4e00\u7684\u3002 Java TreeMap vs Python OrderedDict: Java TreeMap \u662f\u4e00\u4e2a\u57fa\u4e8e\u7ea2\u9ed1\u6811\u7684\u6709\u5e8f\u6620\u5c04\u3002 Python OrderedDict \u5728\u952e\u7684\u63d2\u5165\u987a\u5e8f\u4e0a\u4fdd\u6301\u6709\u5e8f\u3002 Java \u7684\u591a\u9879\u96c6\u7c7b\u578b\u548c Python \u7684\u591a\u9879\u96c6\u7c7b\u578b\u5728\u529f\u80fd\u4e0a\u975e\u5e38\u7c7b\u4f3c\uff0c\u90fd\u63d0\u4f9b\u4e86\u5404\u79cd\u4e0d\u540c\u7684\u96c6\u5408\u7c7b\u578b\u6765\u9002\u5e94\u4e0d\u540c\u7684\u9700\u6c42\u3002\u9700\u8981\u6839\u636e\u5177\u4f53\u7684\u4f7f\u7528\u60c5\u51b5\u6765\u9009\u62e9\u54ea\u79cd\u96c6\u5408\u7c7b\u578b\u66f4\u9002\u5408\u3002\u540c\u65f6\uff0cPython \u8fd8\u63d0\u4f9b\u4e86\u65b9\u4fbf\u7684\u5217\u8868\u63a8\u5bfc\u3001\u96c6\u5408\u63a8\u5bfc\u548c\u5b57\u5178\u63a8\u5bfc\u7b49\u7279\u6027\uff0c\u53ef\u4ee5\u66f4\u52a0\u4fbf\u6377\u5730\u521b\u5efa\u548c\u5904\u7406\u591a\u9879\u96c6\u3002","title":"\u591a\u9879\u96c6\u7684\u6982\u8ff0"},{"location":"python/DataStructure/02_CollectionsOverview/#2","text":"\u591a\u9879\u96c6\uff08collection\uff09\u662f\u6307\u7531 0 \u4e2a\u6216\u8005\u591a\u4e2a\u5143\u7d20\u7ec4\u6210\u7684\u6982\u5ff5\u5355\u5143\u3002 \u4ece\u4e24\u4e2a\u89d2\u5ea6\u770b\u5f85\u591a\u9879\u96c6\uff1a \u591a\u9879\u96c6\u7684\u7528\u6237\u6216\u8005\u5ba2\u6237\u4f1a\u5173\u5fc3\u5b83\u4eec\u5728\u4e0d\u540c\u7684\u5e94\u7528\u7a0b\u5e8f\u91cc\u80fd\u505a\u4e9b\u4ec0\u4e48\u3002 \u591a\u9879\u96c6\u7684\u5f00\u53d1\u8005\u6216\u8005\u5b9e\u73b0\u8005\u5219\u4f1a\u5173\u5fc3\u5982\u4f55\u624d\u80fd\u8ba9\u5b83\u4eec\u6210\u4e3a\u6700\u597d\u7684\u901a\u7528\u8d44\u6e90\u4ee5\u88ab\u4f7f\u7528\u3002 \u76ee\u6807\uff1a \u5b9a\u4e49\u591a\u9879\u96c6\u76844\u4e2a\u901a\u7528\u7c7b\u578b\uff1a \u7ebf\u6027\u591a\u9879\u96c6 \u5206\u5c42\u591a\u9879\u96c6 \u56fe\u591a\u9879\u96c6 \u65e0\u5e8f\u591a\u9879\u96c6 \u4e86\u89e34\u4e2a\u591a\u9879\u96c6\u7c7b\u578b\u4e2d\u7684\u7279\u5b9a\u7c7b\u578b\uff1b \u4e86\u89e3\u8fd9\u4e9b\u591a\u9879\u96c6\u9002\u5408\u7528\u5728\u4ec0\u4e48\u7c7b\u578b\u7684\u5e94\u7528\u7a0b\u5e8f\u91cc\uff1b \u63cf\u8ff0\u6bcf\u79cd\u591a\u9879\u96c6\u7c7b\u578b\u7684\u5e38\u7528\u64cd\u4f5c\uff1b \u63cf\u8ff0\u591a\u9879\u96c6\u7684\u62bd\u8c61\u7c7b\u578b\u548c\u5b9e\u73b0\u4e4b\u95f4\u7684\u533a\u522b\uff1b","title":"2.\u591a\u9879\u96c6\u7684\u6982\u8ff0"},{"location":"python/DataStructure/02_CollectionsOverview/#21","text":"\u5185\u7f6e\u591a\u9879\u96c6\u7c7b\u578b\uff1a \u5b57\u7b26\u4e32 str \u5217\u8868 list \u5143\u7ec4 tuple \u96c6\u5408 set \u5b57\u5178 dict \u5176\u4ed6\u591a\u9879\u96c6\u7c7b\u578b\uff1a \u6808 \u961f\u5217 \u4f18\u5148\u961f\u5217 \u4e8c\u53c9\u67e5\u627e\u6811 \u5806 \u56fe \u5305 \u6709\u5e8f\u591a\u9879\u96c6 \u591a\u9879\u96c6\u901a\u5e38\u4e0d\u662f\u9759\u6001\uff08static\uff09\u7684\uff0c\u800c\u662f\u52a8\u6001\uff08dynamic\uff09\u7684\uff0c\u53ef\u4ee5\u6839\u636e\u9700\u8981\u6765\u6269\u5927\u6216\u8005\u7f29\u5c0f\u591a\u9879\u96c6\u3002 \u4e0d\u53ef\u53d8\u591a\u9879\u96c6\uff08immutable collection\uff09\u7684\u5185\u5bb9\u5728\u7a0b\u5e8f\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u662f\u4e0d\u53ef\u6539\u53d8\u7684\uff08\u5143\u7d20\u4e0d\u53ef\u4ee5\u6dfb\u52a0\u3001\u5220\u9664\u6216\u8005\u66ff\u6362\uff09\uff0c\u6bd4\u5982\u5143\u7ec4tuple\u3002 \u53ef\u53d8\u591a\u9879\u96c6\uff08mutable collection\uff09\u91cc\u7684\u5185\u5bb9\u53ef\u4ee5\u5728\u7a0b\u5e8f\u7684\u6574\u4e2a\u8fd0\u884c\u8fc7\u7a0b\u4e2d\u88ab\u6539\u53d8\uff0c\u6bd4\u5982\u5b57\u7b26\u4e32\u3001\u5217\u8868list\u3002 \u591a\u9879\u96c6\u6309\u6784\u6210\u65b9\u5f0f\u5212\u5206\u7684\u7c7b\u578b\uff1a \u7ebf\u6027\u591a\u9879\u96c6 \u5206\u5c42\u591a\u9879\u96c6 \u56fe\u591a\u9879\u96c6 \u65e0\u5e8f\u591a\u9879\u96c6 \u6709\u5e8f\u591a\u9879\u96c6","title":"2.1.\u591a\u9879\u96c6\u7c7b\u578b"},{"location":"python/DataStructure/02_CollectionsOverview/#211","text":"\u7ebf\u6027\u591a\u9879\u96c6\uff08linear collection\uff09\u91cc\u7684\u5143\u7d20\u6309\u7167\u4f4d\u7f6e\u8fdb\u884c\u6392\u5217\u3002 \u9664\u4e86\u7b2c\u4e00\u4e2a\u5143\u7d20\uff0c\u5176\u4ed6\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\uff1b \u9664\u4e86\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff0c\u5176\u4ed6\u6bcf\u4e2a\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u540e\u5e8f\uff1b \u5b9e\u4f8b\uff1a\u6392\u961f\u7684\u4eba\uff0c\u8d2d\u7269\u6e05\u5355\uff0c\u5806\u53e0\u5728\u4e00\u8d77\u7684\u9910\u76d8\u7b49\u3002","title":"2.1.1.\u7ebf\u6027\u591a\u9879\u96c6"},{"location":"python/DataStructure/02_CollectionsOverview/#212","text":"\u5206\u5c42\u591a\u9879\u96c6\uff08hierarchical collection\uff09\u91cc\u7684\u6570\u636e\u5143\u7d20\u4f1a\u4ee5\u7c7b\u4f3c\u4e8e\u5012\u7f6e\u7684\u6811\u7ed3\u6784\u8fdb\u884c\u6392\u5217\u3002\u9664\u4e86\u9876\u90e8\u7684\u6570\u636e\u5143\u7d20\uff0c\u5176\u4ed6\u6bcf\u4e2a\u6570\u636e\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\uff0c\u88ab\u79f0\u4e3a\u7236\u5143\u7d20\uff08parent\uff09\uff0c\u4f46\u5b83\u4eec\u53ef\u4ee5\u6709\u8bb8\u591a\u7684\u540e\u5e8f\uff0c\u88ab\u79f0\u4e3a\u5b50\u5143\u7d20\uff08children\uff09\u3002 \u56fe\u4f8b\u4e2d\uff0c D3 \u7684\u524d\u5e8f\u7236\u5143\u7d20\u662f D1 \uff0c D3 \u7684\u540e\u7eed\u5b50\u5143\u7d20\u662f D4 \u3001 D5 \u3001 D6 \u3002 \u5b9e\u4f8b\uff1a\u6587\u4ef6\u76ee\u5f55\u7cfb\u7edf\u3001\u516c\u53f8\u7684\u7ec4\u7ec7\u67b6\u6784\u3001\u4e66\u7684\u76ee\u5f55\u7b49\u3002","title":"2.1.2.\u5206\u5c42\u591a\u9879\u96c6"},{"location":"python/DataStructure/02_CollectionsOverview/#213","text":"\u56fe\u591a\u9879\u96c6\uff08graph collection\uff09\u4e5f\u88ab\u79f0\u4e3a\u56fe\uff08graph\uff09\uff0c\u5b83\u662f\u8fd9\u6837\u4e00\u4e2a\u591a\u9879\u96c6\uff1a\u5b83\u7684\u6bcf\u4e00\u4e2a\u6570\u636e\u5143\u7d20\u90fd\u53ef\u4ee5\u6709\u591a\u4e2a\u524d\u5e8f\u548c\u591a\u4e2a\u540e\u5e8f\u3002 \u56fe\u4f8b\u4e2d\uff0c\u8fde\u63a5\u5230 D3 \u7684\u6240\u6709\u5143\u7d20\u4f1a\u88ab\u5f53\u4f5c\u5b83\u7684\u524d\u5e8f\u548c\u540e\u5e8f\uff0c\u5b83\u4eec\u4e5f\u56e0\u6b64\u88ab\u79f0\u4e3a D3 \u7684\u90bb\u5c45\u3002 \u5b9e\u4f8b\uff1a\u57ce\u5e02\u4e4b\u95f4\u7684\u822a\u7ebf\u56fe\u3001\u4e07\u7ef4\u7f51\u7b49\u3002","title":"2.1.3.\u56fe\u591a\u9879\u96c6"},{"location":"python/DataStructure/02_CollectionsOverview/#214","text":"\u65e0\u5e8f\u591a\u9879\u96c6\uff08unordered collection\uff09\u91cc\u7684\u5143\u7d20\u6ca1\u6709\u7279\u5b9a\u7684\u987a\u5e8f\uff0c\u5e76\u4e14\u4e0d\u4f1a\u7528\u4efb\u4f55\u660e\u786e\u7684\u65b9\u5f0f\u6765\u6307\u51fa\u5143\u7d20\u7684\u524d\u5e8f\u6216\u8005\u540e\u5e8f\u3002 \u5b9e\u4f8b\uff1a\u4e00\u888b\u5f39\u73e0\u7b49\u3002","title":"2.1.4.\u65e0\u5e8f\u591a\u9879\u96c6"},{"location":"python/DataStructure/02_CollectionsOverview/#215","text":"\u6709\u5e8f\u591a\u9879\u96c6\uff08sorted collection\uff09\u4f1a\u5bf9\u5b83\u91cc\u9762\u7684\u5143\u7d20\u8fdb\u884c\u81ea\u7136\u6392\u5e8f\uff08natural ordering\uff09\u3002 \u8981\u8fdb\u884c\u81ea\u7136\u6392\u5e8f\uff0c\u5c31\u5fc5\u987b\u8981\u6709\u89c4\u5219\u6765\u5bf9\u6709\u5e8f\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u52a0\u4ee5\u6bd4\u8f83\uff0c\u4f8b\u5982 item(i) <= item(i+1) \u8fd9\u6837\u7684\u2014\u2014\u89c4\u5219\u3002 \u6709\u5e8f\u5217\u8868\u662f\u6700\u5e38\u89c1\u7684\u6709\u5e8f\u591a\u9879\u96c6\u3002\u6709\u5e8f\u591a\u9879\u96c6\u4e0d\u4e00\u5b9a\u662f\u7ebf\u6027\u7684\u6216\u8005\u6309\u7167\u4f4d\u7f6e\u8fdb\u884c\u6392\u5e8f\u7684\u3002 \u5bf9\u4e8e\u96c6\u5408\u3001\u5305\u3001\u5b57\u5178\uff0c\u867d\u7136\u4e0d\u80fd\u6309\u7167\u4f4d\u7f6e\u6765\u8bbf\u95ee\u5b83\u4eec\u7684\u5143\u7d20\uff0c\u4f46\u5b83\u4eec\u90fd\u53ef\u4ee5\u662f\u6709\u5e8f\u7684\u3002 \u7279\u6b8a\u7684\u5206\u5c42\u591a\u9879\u96c6\u7c7b\u578b\uff08\u5982\u4e8c\u53c9\u67e5\u627e\u6811\uff09\u4e5f\u4f1a\u5bf9\u5176\u4e2d\u7684\u5143\u7d20\u8fdb\u884c\u81ea\u7136\u6392\u5e8f\u3002","title":"2.1.5.\u6709\u5e8f\u591a\u9879\u96c6"},{"location":"python/DataStructure/02_CollectionsOverview/#216","text":"\u4e0b\u9762\u5206\u7c7b\u91cc\u7684\u7c7b\u578b\u540d\u79f0\u6307\u7684\u5e76\u4e0d\u662f\u591a\u9879\u96c6\u7684\u7279\u5b9a\u5b9e\u73b0\u3002\u4e00\u79cd\u7279\u5b9a\u7c7b\u578b\u7684\u591a\u9879\u96c6\u53ef\u4ee5\u6709\u591a\u4e2a\u5b9e\u73b0\u3002 \u591a\u9879\u96c6 | ---\u56fe\u591a\u9879\u96c6 | ---\u5206\u5c42\u591a\u9879\u96c6 | | ---\u4e8c\u53c9\u67e5\u627e\u6811 | | ---\u5806 | ---\u7ebf\u6027\u591a\u9879\u96c6 | | ---\u5217\u8868 | | | ---\u6709\u5e8f\u5217\u8868 | | ---\u961f\u5217 | | | ---\u4f18\u5148\u5bf9\u5217 | | ---\u6808 | | ---\u5b57\u7b26\u4e32 | ---\u65e0\u5e8f\u591a\u9879\u96c6 | ---\u5305 | | ---\u6709\u5e8f\u5305 | ---\u5b57\u5178 | | ---\u6709\u5e8f\u5305 | ---\u96c6\u5408 | ---\u6709\u5e8f\u96c6\u5408","title":"2.1.6.\u591a\u9879\u96c6\u7c7b\u578b\u7684\u5206\u7c7b"},{"location":"python/DataStructure/02_CollectionsOverview/#22","text":"\u591a\u9879\u96c6\u64cd\u4f5c\u7c7b\u522b\uff1a \u786e\u5b9a\u5927\u5c0f\uff1a\u4f7f\u7528 len \u51fd\u6570\u83b7\u53d6\u5f53\u524d\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u6570\u91cf\u3002 \u68c0\u6d4b\u5143\u7d20\u6210\u5458\uff1a\u4f7f\u7528 in \u8fd0\u7b97\u7b26\u5728\u591a\u9879\u96c6\u91cc\u641c\u7d22\u6307\u5b9a\u7684\u76ee\u6807\u5143\u7d20\u3002\u5982\u679c\u627e\u5230\u4e86\u8fd9\u4e2a\u5143\u7d20\uff0c\u5219\u8fd4\u56deTrue\uff0c\u5426\u5219\u8fd4\u56deFalse\u3002 \u904d\u5386\u591a\u9879\u96c6\uff1a\u4f7f\u7528 for \u5faa\u73af\u8bbf\u95ee\u591a\u9879\u96c6\u91cc\u7684\u6b38\u4e00\u4e2a\u5143\u7d20\u3002\u5143\u7d20\u7684\u8bbf\u95ee\u987a\u5e8f\u53d6\u51b3\u4e8e\u591a\u9879\u96c6\u7684\u7c7b\u578b\u3002 \u83b7\u53d6\u591a\u9879\u96c6\u7684\u5b57\u7b26\u4e32\u8868\u793a\uff1a\u4f7f\u7528 str \u51fd\u6570\u83b7\u53d6\u591a\u9879\u96c6\u7684\u5b57\u7b26\u4e32\u8868\u793a\u3002 \u76f8\u7b49\u68c0\u6d4b\uff1a\u4f7f\u7528 == \u8fd0\u7b97\u7b26\u6765\u786e\u5b9a\u4e24\u4e2a\u591a\u9879\u96c6\u662f\u5426\u76f8\u7b49\u3002\u5982\u679c\u4e24\u4e2a\u591a\u9879\u96c6\u80b2\u6709\u76f8\u540c\u7684\u7c7b\u578b\uff0c\u5e76\u4e14\u5305\u542b\u76f8\u540c\u7684\u5143\u7d20\uff0c\u90a3\u4e48\u5b83\u4eec\u5c31\u662f\u76f8\u7b49\u7684\u3002\u6bd4\u8f83\u8fd9\u4e9b\u5143\u7d20\u5bf9\u7684\u987a\u5e8f\u53d6\u51b3\u4e8e\u591a\u9879\u96c6\u7684\u7c7b\u578b\u3002 \u8fde\u63a5\u4e24\u4e2a\u591a\u9879\u96c6\uff1a\u4f7f\u7528 + \u8fd0\u7b97\u7b26\u6765\u5f97\u5230\u4e00\u4e2a\u548c\u64cd\u4f5c\u6570\u76f8\u540c\u7c7b\u578b\u7684\u65b0\u591a\u9879\u96c6\uff0c\u5e76\u4e14\u5305\u542b\u4e24\u4e2a\u64cd\u4f5c\u6570\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002 \u8f6c\u6362\u4e3a\u5176\u4ed6\u7c7b\u578b\u7684\u591a\u9879\u96c6\uff1a\u521b\u5efa\u4e00\u4e2a\u4e0e\u6e90\u591a\u9879\u96c6\u5177\u6709\u76f8\u540c\u5143\u7d20\u7684\u65b0\u591a\u9879\u96c6\u3002\u514b\u9686\u64cd\u4f5c\u65f6\u7c7b\u578b\u8f6c\u6362\u7684\u4e00\u79cd\u7279\u6b8a\u60c5\u51b5\uff0c\u56e0\u4e3a\u8f93\u5165\u8f93\u51fa\u7684\u4e24\u4e2a\u591a\u9879\u96c6\u5177\u6709\u76f8\u540c\u7c7b\u578b\u3002 \u63d2\u5165\u4e00\u4e2a\u5143\u7d20\uff1a\u5982\u679c\u53ef\u4ee5\uff0c\u5219\u5728\u7ed9\u5b9a\u7684\u4f4d\u7f6e\u5c06\u5bf9\u5e94\u7684\u5143\u7d20\u6dfb\u52a0\u5230\u591a\u9879\u96c6\u91cc\u3002 \u5220\u9664\u4e00\u4e2a\u5143\u7d20\uff1a\u5982\u679c\u53ef\u4ee5\uff0c\u5219\u5728\u7ed9\u5b9a\u7684\u4f4d\u7f6e\u5c06\u5bf9\u5e94\u7684\u5143\u7d20\u4ece\u591a\u9879\u96c6\u4e2d\u5220\u9664\u3002 \u66ff\u6362\u4e00\u4e2a\u5143\u7d20\uff1a\u5c06\u5220\u9664\u548c\u63d2\u5165\u5408\u5e76\u4e3a\u4e00\u9879\u64cd\u4f5c\u3002 \u8bbf\u95ee\u6216\u8005\u83b7\u53d6\u5143\u7d20\uff1a\u5982\u679c\u800c\u5df2\uff0c\u5219\u5728\u7ed9\u5b9a\u7684\u4f4d\u7f6e\u83b7\u53d6\u5143\u7d20\u3002","title":"2.2.\u591a\u9879\u96c6\u64cd\u4f5c"},{"location":"python/DataStructure/02_CollectionsOverview/#221","text":"\u5728Python\u91cc\uff0c\u4e0d\u540c\u591a\u9879\u96c6\u7c7b\u578b\u7684\u63d2\u5165\u3001\u5220\u9664\u3001\u66ff\u6362\u6216\u8005\u8bbf\u95ee\u64cd\u4f5c\u5e76\u6ca1\u6709\u7edf\u4e00\u7684\u540d\u79f0\uff0c\u4f46\u662f\u4f1a\u6709\u4e00\u4e9b\u6807\u51c6\u53d8\u4f53\u3002\u6bd4\u5982\uff0c \u65b9\u6cd5pop\u4f1a\u88ab\u7528\u6765\u4ece\u5217\u8868\u91cc\u79fb\u9664\u6307\u5b9a\u4f4d\u7f6e\u7684\u5143\u7d20\uff1b \u65b9\u6cd5pop\u4f1a\u88ab\u7528\u6765\u4ece\u5b57\u5178\u91cc\u79fb\u9664\u7ed9\u5b9a\u952e\u6240\u5bf9\u5e94\u7684\u503c\uff1b \u65b9\u6cd5remove\u4f1a\u88ab\u7528\u6765\u4ece\u5217\u8868\u6216\u8005\u67d0\u4e9b\u591a\u9879\u96c6\u91cc\u5220\u9664\u6307\u5b9a\u7684\u5143\u7d20\uff1b \u5bf9\u4e8e\u65b0\u5f00\u53d1\u51fa\u7684\u3001Python\u5c1a\u4e0d\u652f\u6301\u7684\u591a\u9879\u96c6\u7c7b\u578b\uff0c\u5c3d\u53ef\u80fd\u5730\u4f7f\u7528\u6807\u51c6\u7684\u8fd0\u7b97\u7b26\u3001\u51fd\u6570\u4ee5\u53ca\u65b9\u6cd5\u540d\u79f0\u5bf9\u5b83\u4eec\u8fdb\u884c\u64cd\u4f5c\u3002","title":"2.2.1.\u6240\u6709\u591a\u9879\u96c6\u7c7b\u578b\u4e2d\u7684\u57fa\u672c\u64cd\u4f5c"},{"location":"python/DataStructure/02_CollectionsOverview/#222","text":"\u7c7b\u578b\u8f6c\u6362\uff0c\u5c06\u4e00\u79cd\u7c7b\u578b\u7684\u591a\u9879\u96c6\u8f6c\u6362\u4e3a\u53e6\u4e00\u79cd\u7c7b\u578b\u7684\u591a\u9879\u96c6\u3002\u4f8b\u5982\uff0c\u901a\u8fc7 list \u6216 tuple \u51fd\u6570\u5c06\u5b57\u7b26\u4e32\u8f6c\u6362\u4e3a\u5217\u8868\u6216\u8005\u5143\u7ec4\u3002 list \u6216 tuple \u51fd\u6570\u7684\u53c2\u6570\u4e0d\u4e00\u5b9a\u662f\u53e6\u4e00\u4e2a\u591a\u9879\u96c6\uff0c\u4e5f\u53ef\u4ee5\u662f\u4efb\u4f55\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08iterable object\uff09\u3002 \u53ef\u8fed\u4ee3\u5bf9\u8c61\u662f\u6307\uff0c\u80fd\u591f\u4f7f\u7528for\u5faa\u73af\u6765\u8bbf\u95ee\u7684\u4e00\u7cfb\u5217\u5143\u7d20\u3002\uff08\u591a\u9879\u96c6\u672c\u8eab\u4e5f\u662f\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff09","title":"2.2.2.\u7c7b\u578b\u8f6c\u6362"},{"location":"python/DataStructure/02_CollectionsOverview/#223","text":"\u7c7b\u578b\u8f6c\u6362\u7684\u4e00\u79cd\u7279\u6b8a\u60c5\u51b5\u662f\u514b\u9686\uff0c\u5b83\u7684\u529f\u80fd\u662f\u8fd4\u56de\u8f6c\u6362\u51fd\u6570\u4e2d\u53c2\u6570\u7684\u5b8c\u6574\u526f\u672c\u3002 \u4f8b\u5982\uff1a myList1 = [ 2 , 4 , 8 ] myList2 = list ( myList1 ) myList1 is myList2 # False myList1 == myList2 # True \u6ce8\u610f\uff1a \u4e0a\u9762\u4e24\u4e2a\u5217\u8868\u4e0d\u4ec5\u6709\u76f8\u540c\u7684\u7ed3\u6784\uff0c\u5b83\u4eec\u8fd8\u6709\u76f8\u540c\u7684\u5143\u7d20\uff0c\u6bcf\u5bf9\u5143\u7d20\u5728\u4e24\u4e2a\u5217\u8868\u91cc\u7684\u4f4d\u7f6e\u90fd\u76f8\u540c\u3002\u4f46\u662f\uff0c\u4ed6\u4eec\u662f\u4e24\u4e2a\u4e0d\u540c\u7684\u5bf9\u8c61\u3002 \u4e0a\u4f8b\u4e2d list \u51fd\u6570\u5bf9\u5b83\u7684\u53c2\u6570\u5217\u8868\u8fdb\u884c\u6d45\u62f7\u8d1d\uff08shallow copy\uff09\u3002\u8fd9\u4e9b\u5143\u7d20\u7684\u672c\u8eab\u5728\u6dfb\u52a0\u5230\u65b0\u5217\u8868\u4e4b\u524d\u662f\u4e0d\u4f1a\u88ab\u514b\u9686\u7684\uff0c\u5728\u8fd9\u4e2a\u8fc7\u7a0b\u4e2d\u53ea\u4f1a\u590d\u5236\u5bf9\u8fd9\u4e9b\u5bf9\u8c61\u7684\u5f15\u7528\u3002\u5f53\u5143\u7d20\uff08\u6570\u5b57\u3001\u5b57\u7b26\u4e32\u6216\u8005Python\u7684\u5143\u7ec4\uff09\u4e0d\u53ef\u53d8\u65f6\uff0c\u8fd9\u4e2a\u7b56\u7565\u4e0d\u4f1a\u5f15\u8d77\u95ee\u9898\u3002\u4f46\u662f\uff0c\u5982\u679c\u591a\u9879\u96c6\u5305\u542b\u7684\u662f\u53ef\u53d8\u5143\u7d20\uff0c\u5c31\u53ef\u80fd\u4f1a\u4ea7\u751f\u526f\u4f5c\u7528\u3002\u4e3a\u4e86\u907f\u514d\u8fd9\u79cd\u60c5\u51b5\u7684\u53d1\u751f\uff0c\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u5bf9\u6e90\u591a\u9879\u96c6\u7f16\u5199 for \u5faa\u73af\u6765\u521b\u5efa\u6df1\u62f7\u8d1d\uff08deep copy\uff09\uff0c\u8fd9\u4f1a\u628a\u5143\u7d20\u663e\u5f0f\u5730\u514b\u9686\u4e4b\u540e\u518d\u6dfb\u52a0\u5230\u65b0\u7684\u591a\u9879\u96c6\u91cc\u3002","title":"2.2.3.\u514b\u9686\u548c\u76f8\u7b49\u6027"},{"location":"python/DataStructure/02_CollectionsOverview/#23","text":"\u6bcf\u79cd\u7c7b\u578b\u7684\u591a\u9879\u96c6\u90fd\u652f\u6301\u4e00\u4e2a\u8fed\u4ee3\u5668\u6216 for \u5faa\u73af\uff0c\u8fd9\u4e2a\u64cd\u4f5c\u80fd\u591f\u8fed\u4ee3\u8fd9\u4e2a\u591a\u9879\u96c6\u7684\u6240\u6709\u5143\u7d20\u3002\u8fed\u4ee3\u5668\u662f\u591a\u9879\u96c6\u63d0\u4f9b\u7684\u6700\u5173\u952e\u7684\u64cd\u4f5c\u3002 for \u5faa\u73af\u670d\u52a1\u7684\u591a\u9879\u96c6\u4e2d\u5143\u7d20\u7684\u987a\u5e8f\u53d6\u51b3\u4e8e\u591a\u9879\u96c6\u7684\u7ec4\u7ec7\u65b9\u5f0f\u3002\u4f8b\u5982\uff1a \u5217\u8868\u91cc\u7684\u5143\u7d20\u4f1a\u4ece\u5934\u5230\u5c3e\u6309\u7167\u4f4d\u7f6e\u8fdb\u884c\u8bbf\u95ee\uff1b \u6709\u5e8f\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u4f1a\u6309\u4ece\u5c0f\u5230\u5927\u7684\u5347\u5e8f\u8fdb\u884c\u8bbf\u95ee\uff1b \u5bf9\u4e8e\u96c6\u5408\u6216\u8005\u5b57\u5178\u91cc\u7684\u5143\u7d20\u6765\u8bf4\uff0c\u4e0d\u4f1a\u6309\u7167\u7279\u5b9a\u7684\u987a\u5e8f\u8fdb\u884c\u8bbf\u95ee\u3002 \u8fed\u4ee3\u5668\uff08\u4f8b\u5982 for \u5faa\u73af\uff09\u8fd8\u652f\u6301\u4f7f\u7528\u9ad8\u9636\u51fd\u6570 map \u3001 filter \u548c reduce \u3002 \u8fd9\u4e9b\u9ad8\u9636\u51fd\u6570\u90fd\u4f7f\u7528\u53e6\u4e00\u4e2a\u51fd\u6570\u548c\u4e00\u4e2a\u591a\u9879\u96c6\u4f5c\u4e3a\u53c2\u6570\u3002 \u591a\u9879\u96c6\u90fd\u652f\u6301 for \u5faa\u73af\uff0c\u6240\u4ee5 map \u3001 filter \u548c reduce \u51fd\u6570\u53ef\u4ee5\u4e0e\u4efb\u4f55\u7c7b\u578b\u7684\u591a\u9879\u96c6\u4e00\u8d77\u4f7f\u7528\u3002","title":"2.3.\u8fed\u4ee3\u5668\u548c\u9ad8\u9636\u51fd\u6570"},{"location":"python/DataStructure/02_CollectionsOverview/#24","text":"\u4ece\u7528\u6237\uff08\u6bd4\u5982\uff0c\u7a0b\u5e8f\u5458\uff09\u7684\u89d2\u5ea6\u6765\u770b\uff0c\u591a\u9879\u96c6\u662f\u4e00\u79cd\u62bd\u8c61\uff0c\u662f\u4e00\u79cd\u4ee5\u67d0\u79cd\u9884\u5b9a\u884c\u4e3a\u6765\u5b58\u50a8\u548c\u8bbf\u95ee\u6570\u636e\u5143\u7d20\u7684\u65b9\u5f0f\uff0c\u5e76\u4e0d\u9700\u8981\u5173\u5fc3\u591a\u9879\u96c6\u5b9e\u73b0\u7684\u7ec6\u8282\u3002 \u591a\u9879\u96c6\u4e5f\u88ab\u79f0\u4e3a\u62bd\u8c61\u6570\u636e\u7c7b\u578b\uff08Abstract Data Type\uff0cADT\uff09\u3002\u62bd\u8c61\u6570\u636e\u7c7b\u578b\u7684\u7528\u6237\u53ea\u5173\u6ce8\u5b83\u7684\u63a5\u53e3\u4ee5\u53ca\u8fd9\u4e2a\u7c7b\u578b\u5bf9\u8c61\u6240\u63d0\u4f9b\u7684\u4e00\u7ec4\u64cd\u4f5c\u3002 \u5728Python\u91cc\uff0c\u51fd\u6570\u548c\u65b9\u6cd5\u662f\u6700\u5c0f\u7684\u62bd\u8c61\u5355\u5143\uff0c\u7c7b\u7684\u5927\u5c0f\u6b21\u4e4b\uff0c\u6a21\u5757\u662f\u6700\u5927\u7684\u62bd\u8c61\u5355\u5143\u3002 \u8fd9\u91cc\u4f1a\u628a\u62bd\u8c61\u591a\u9879\u96c6\u7c7b\u578b\u7684\u5b9e\u73b0\u5f53\u4f5c\u6a21\u5757\u91cc\u7684\u7c7b\u6216\u8005\u4e00\u7ec4\u76f8\u5173\u7684\u7c7b\u52a0\u4ee5\u63cf\u8ff0\u3002\u6784\u5efa\u8fd9\u4e9b\u7c7b\u5c31\u662f\u9762\u5411\u5bf9\u8c61\u7f16\u7a0b\u3002","title":"2.4.\u591a\u9879\u96c6\u7684\u5b9e\u73b0"},{"location":"python/DataStructure/02_CollectionsOverview/#25","text":"\u591a\u9879\u96c6\u662f\u5305\u542b0\u4e2a\u6216\u591a\u4e2a\u5176\u4ed6\u5bf9\u8c61\u7684\u5bf9\u8c61\u3002\u591a\u9879\u96c6\u53ef\u4ee5\u8fdb\u884c\u7684\u64cd\u4f5c\u6709\u8bbf\u95ee\u5bf9\u8c61\u3001\u63d2\u5165\u5bf9\u8c61\u3001\u5220\u9664\u5bf9\u8c61\u3001\u786e\u5b9a\u591a\u9879\u96c6\u7684\u5927\u5c0f\uff0c\u4ee5\u53ca\u904d\u5386\u6216\u8bbf\u95ee\u8fd9\u4e2a\u591a\u9879\u96c6\u7684\u5bf9\u8c61\u3002 \u591a\u9879\u96c6\u76845\u4e2a\u4e3b\u8981\u7c7b\u578b\u662f\uff1a\u7ebf\u6027\u591a\u9879\u96c6\u3001\u5206\u5c42\u591a\u9879\u96c6\u3001\u56fe\u591a\u9879\u96c6\u3001\u65e0\u5e8f\u591a\u9879\u96c6\u548c\u6709\u5e8f\u591a\u9879\u96c6\u3002 \u7ebf\u6027\u591a\u9879\u96c6\u4f1a\u6309\u7167\u4f4d\u7f6e\u5bf9\u5143\u7d20\u8fdb\u884c\u6392\u5e8f\uff0c\u5176\u4e2d\u9664\u4e86\u7b2c\u4e00\u4e2a\u5143\u7d20\uff0c\u6bcf\u4e2a\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\uff1b\u9664\u4e86\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff0c\u6bcf\u4e2a\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u540e\u5e8f\u3002 \u5728\u5206\u5c42\u591a\u9879\u96c6\u91cc\uff0c\u9664\u4e86\u4e00\u4e2a\u5143\u7d20\uff0c\u5176\u4ed6\u6240\u6709\u5143\u7d20\u90fd\u6709\u4e14\u53ea\u6709\u4e00\u4e2a\u524d\u5e8f\u4ee5\u53ca0\u4e2a\u6216\u591a\u4e2a\u540e\u5e8f\u3002\u88ab\u79f0\u4e3a\u6839\u7684\u90a3\u4e2a\u989d\u5916\u5143\u7d20\u6ca1\u6709\u524d\u5e8f\u3002 \u56fe\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u53ef\u4ee5\u67090\u4e2a\u6216\u591a\u4e2a\u524d\u5e8f\u4ee5\u53ca0\u4e2a\u6216\u591a\u4e2a\u540e\u5e8f\u3002 \u65e0\u5e8f\u591a\u9879\u96c6\u91cc\u7684\u5143\u7d20\u6ca1\u6709\u7279\u5b9a\u7684\u987a\u5e8f\u3002 \u591a\u9879\u96c6\u662f\u53ef\u8fed\u4ee3\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\uff0c\u53ef\u4ee5\u4f7f\u7528for\u5faa\u73af\u8bbf\u95ee\u591a\u9879\u96c6\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u7a0b\u5e8f\u5458\u4e5f\u53ef\u4ee5\u4f7f\u7528\u9ad8\u9636\u51fd\u6570map\u3001filter\u548creduce\u7b80\u5316\u591a\u9879\u96c6\u7684\u6570\u636e\u5904\u7406\u3002 \u62bd\u8c61\u6570\u636e\u7c7b\u578b\u662f\u4e00\u7ec4\u5bf9\u8c61\u548c\u5bf9\u8fd9\u4e9b\u5bf9\u8c61\u7684\u64cd\u4f5c\u3002\u56e0\u6b64\uff0c\u591a\u9879\u96c6\u662f\u62bd\u8c61\u6570\u636e\u7c7b\u578b\u3002 \u6570\u636e\u7ed3\u6784\u662f\u4e00\u4e2a\u8868\u793a\u591a\u9879\u96c6\u91cc\u5305\u542b\u7684\u6570\u636e\u7684\u5bf9\u8c61\u3002","title":"2.5.\u5c0f\u7ed3"},{"location":"python/DataStructure/02_CollectionsOverview/#26","text":"\u7ebf\u6027\u591a\u9879\u96c6\u7684\u4e00\u4e2a\u4f8b\u5b50\u662f\uff1a \u96c6\u5408\u548c\u6811 \u5217\u8868\u548c\u6808 \u65e0\u5e8f\u591a\u9879\u96c6\u7684\u4e00\u4e2a\u4f8b\u5b50\u662f\uff1a \u961f\u5217\u548c\u5217\u8868 \u96c6\u5408\u548c\u5b57\u5178 \u5206\u5c42\u591a\u9879\u96c6\u53ef\u4ee5\u7528\u6765\u8868\u793a\uff1a \u94f6\u884c\u6392\u961f\u7684\u5ba2\u6237 \u6587\u4ef6\u76ee\u5f55\u7cfb\u7edf \u56fe\u591a\u9879\u96c6\u6700\u80fd\u4ee3\u8868\uff1a \u4e00\u7ec4\u6570\u5b57 \u57ce\u5e02\u4e4b\u95f4\u7684\u822a\u7ebf\u56fe \u5728Python\u91cc\uff0c\u4e24\u4e2a\u591a\u9879\u96c6\u95f4\u7684\u7c7b\u578b\u8f6c\u6362\u64cd\u4f5c\uff1a \u5728\u6e90\u591a\u9879\u96c6\u91cc\u521b\u5efa\u5bf9\u8c61\u7684\u526f\u672c\uff0c\u5e76\u4e14\u628a\u8fd9\u4e9b\u65b0\u5bf9\u8c61\u6dfb\u52a0\u5230\u76ee\u6807\u591a\u9879\u96c6\u7684\u65b0\u5b9e\u4f8b\u91cc \u628a\u5bf9\u6e90\u591a\u9879\u96c6\u5bf9\u8c61\u7684\u5f15\u7528\u6dfb\u52a0\u5230\u76ee\u6807\u591a\u9879\u96c6\u7684\u65b0\u5b9e\u4f8b\u91cc \u4e24\u4e2a\u5217\u8868\u7684 == \u64cd\u4f5c\u5fc5\u987b\uff1a \u6bd4\u8f83\u6bcf\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u5bf9\u662f\u5426\u76f8\u7b49 \u53ea\u4f1a\u9a8c\u8bc1\u4e00\u4e2a\u5217\u8868\u91cc\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u662f\u5426\u4e5f\u5728\u53e6\u4e00\u4e2a\u5217\u8868\u91cc \u4e24\u4e2a\u96c6\u5408\u7684 == \u64cd\u4f5c\u5fc5\u987b\uff1a \u6bd4\u8f83\u6bcf\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u5bf9\u662f\u5426\u76f8\u7b49 \u9a8c\u8bc1\u96c6\u5408\u7684\u5927\u5c0f\u662f\u5426\u76f8\u7b49\uff0c\u5e76\u4e14\u4e00\u4e2a\u96c6\u5408\u91cc\u7684\u6bcf\u4e00\u4e2a\u5143\u7d20\u662f\u5426\u4e5f\u5728\u53e6\u4e00\u4e2a\u96c6\u5408\u91cc \u5bf9\u5217\u8868\u8fdb\u884c for \u5faa\u73af\u65f6\uff0c\u8bbf\u95ee\u5143\u7d20\u7684\u987a\u5e8f\uff1a \u4ece\u5934\u5230\u5c3e\u7684\u6240\u6709\u4f4d\u7f6e \u4e0d\u4f1a\u6309\u7167\u7279\u5b9a\u7684\u987a\u5e8f map \u51fd\u6570\u4f1a\u521b\u5efa\u4e00\u4e2a\u4ec0\u4e48\u6837\u7684\u5e8f\u5217\uff1a \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u901a\u8fc7\u5e03\u5c14\u6d4b\u8bd5\u7684\u5143\u7d20 \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u5bf9\u5143\u7d20\u6267\u884c\u51fd\u6570\u7684\u7ed3\u679c filter \u51fd\u6570\u4f1a\u521b\u5efa\u4e00\u4e2a\u4ec0\u4e48\u6837\u7684\u5e8f\u5217\uff1a \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u901a\u8fc7\u5e03\u5c14\u6d4b\u8bd5\u7684\u5143\u7d20 \u5728\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u91cc\uff0c\u5bf9\u5143\u7d20\u6267\u884c\u51fd\u6570\u7684\u7ed3\u679c","title":"2.6.\u590d\u4e60\u9898"},{"location":"python/DataStructure/02_CollectionsOverview/#27","text":"1\uff0e\u5728Shell\u7a97\u53e3\u7684\u63d0\u793a\u7b26\u4e0b\u4f7f\u7528 dir \u548c help \u51fd\u6570\u6765\u63a2\u7d22Python\u7684\u5185\u7f6e\u591a\u9879\u96c6\u7c7b\u578b str \u3001 list \u3001 tuple \u3001 set \u4ee5\u53ca dict \u7684\u63a5\u53e3\u3002\u5b83\u4eec\u7684\u8bed\u6cd5\u662f dir() \u548c help() \u3002 \u89e3\u7b54\uff1a \u53ef\u4ee5\u901a\u8fc7\u4ee5\u4e0b\u65b9\u5f0f\u6765\u4e86\u89e3\u5b83\u4eec\u7684\u63a5\u53e3\uff1a \u5b57\u7b26\u4e32 ( str ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5b57\u7b26\u4e32\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( str ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5b57\u7b26\u4e32\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( str ) \u5217\u8868 ( list ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5217\u8868\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( list ) x # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5217\u8868\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( list ) \u5143\u7ec4 ( tuple ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5143\u7ec4\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( tuple ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5143\u7ec4\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( tuple ) \u96c6\u5408 ( set ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u96c6\u5408\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( set ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u96c6\u5408\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( set ) \u5b57\u5178 ( dict ) \u7c7b\u578b\uff1a # \u4f7f\u7528 dir() \u51fd\u6570\u5217\u51fa\u5b57\u5178\u7c7b\u578b\u7684\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027 dir ( dict ) # \u4f7f\u7528 help() \u51fd\u6570\u83b7\u53d6\u5173\u4e8e\u5b57\u5178\u7c7b\u578b\u7684\u8be6\u7ec6\u4fe1\u606f help ( dict ) dir() \u51fd\u6570\u5c06\u8fd4\u56de\u4e00\u4e2a\u5305\u542b\u6240\u6709\u65b9\u6cd5\u548c\u5c5e\u6027\u540d\u79f0\u7684\u5217\u8868\uff0c\u800c help() \u51fd\u6570\u5c06\u663e\u793a\u5173\u4e8e\u8be5\u7c7b\u578b\u7684\u8be6\u7ec6\u5e2e\u52a9\u4fe1\u606f\uff0c\u5305\u62ec\u6bcf\u4e2a\u65b9\u6cd5\u7684\u8bf4\u660e\u548c\u7528\u6cd5\u793a\u4f8b\u3002 2\uff0e\u67e5\u770b java.util \u5305\u91cc\u6240\u63d0\u4f9b\u7684Java\u591a\u9879\u96c6\u7c7b\u578b\uff0c\u5e76\u548cPython\u7684\u591a\u9879\u96c6\u7c7b\u578b\u52a0\u4ee5\u6bd4\u8f83\u3002 java.util \u5305\u4e2d\u63d0\u4f9b\u4e86\u8bb8\u591aJava\u7684\u96c6\u5408\u7c7b\u578b\uff0c\u5305\u62ec\u5217\u8868\u3001\u96c6\u5408\u3001\u6620\u5c04\u7b49\u3002\u4e0b\u9762\u5c06\u5217\u51fa\u5176\u4e2d\u4e00\u4e9b\u5e38\u7528\u7684\u591a\u9879\u96c6\u7c7b\u578b\uff0c\u5e76\u5c06\u5b83\u4eec\u4e0ePython\u4e2d\u7684\u591a\u9879\u96c6\u7c7b\u578b\u8fdb\u884c\u6bd4\u8f83\u3002 Java ArrayList vs Python List: Java ArrayList \u662f\u4e00\u4e2a\u53ef\u53d8\u5927\u5c0f\u7684\u52a8\u6001\u6570\u7ec4\u3002 Python List \u4e5f\u662f\u53ef\u53d8\u5927\u5c0f\u7684\u52a8\u6001\u6570\u7ec4\uff0c\u53ef\u4ee5\u5bb9\u7eb3\u4efb\u610f\u7c7b\u578b\u7684\u6570\u636e\u3002 Java HashSet vs Python Set: Java HashSet \u662f\u4e00\u4e2a\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\u7684\u96c6\u5408\u3002 Python Set \u4e5f\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\uff0c\u540c\u65f6\u8fd8\u6709\u4e00\u4e2a\u7279\u6b8a\u7c7b\u578b\u7684\u96c6\u5408\u53eb\u505a frozenset \uff0c\u5b83\u662f\u4e0d\u53ef\u53d8\u7684\u3002 Java LinkedHashSet vs Python OrderedDict: Java LinkedHashSet \u662f\u4e00\u4e2a\u4fdd\u6301\u5143\u7d20\u63d2\u5165\u987a\u5e8f\u7684\u96c6\u5408\uff0c\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\u3002 Python OrderedDict \u662f\u4e00\u4e2a\u6709\u5e8f\u5b57\u5178\uff0c\u4fdd\u6301\u5143\u7d20\u63d2\u5165\u987a\u5e8f\uff0c\u53ef\u4ee5\u7528\u4e8e\u521b\u5efa\u6709\u5e8f\u7684\u952e-\u503c\u5bf9\u96c6\u5408\u3002 Java TreeSet vs Python SortedSet: Java TreeSet \u662f\u4e00\u4e2a\u81ea\u7136\u6392\u5e8f\u6216\u8005\u901a\u8fc7\u63d0\u4f9b\u7684\u6bd4\u8f83\u5668\u8fdb\u884c\u6392\u5e8f\u7684\u96c6\u5408\uff0c\u4e0d\u5141\u8bb8\u91cd\u590d\u5143\u7d20\u3002 Python \u6ca1\u6709\u4e13\u95e8\u7684 SortedSet \u7c7b\uff0c\u4f46\u4f60\u53ef\u4ee5\u4f7f\u7528 sorted() \u51fd\u6570\u5bf9\u96c6\u5408\u8fdb\u884c\u6392\u5e8f\u3002 Java HashMap vs Python Dictionary: Java HashMap \u662f\u4e00\u4e2a\u65e0\u5e8f\u7684\u952e-\u503c\u5bf9\u6620\u5c04\uff0c\u4e0d\u5141\u8bb8\u91cd\u590d\u952e\u3002 Python Dictionary \u662f\u4e00\u4e2a\u65e0\u5e8f\u7684\u952e-\u503c\u5bf9\u6620\u5c04\uff0c\u952e\u662f\u552f\u4e00\u7684\u3002 Java TreeMap vs Python OrderedDict: Java TreeMap \u662f\u4e00\u4e2a\u57fa\u4e8e\u7ea2\u9ed1\u6811\u7684\u6709\u5e8f\u6620\u5c04\u3002 Python OrderedDict \u5728\u952e\u7684\u63d2\u5165\u987a\u5e8f\u4e0a\u4fdd\u6301\u6709\u5e8f\u3002 Java \u7684\u591a\u9879\u96c6\u7c7b\u578b\u548c Python \u7684\u591a\u9879\u96c6\u7c7b\u578b\u5728\u529f\u80fd\u4e0a\u975e\u5e38\u7c7b\u4f3c\uff0c\u90fd\u63d0\u4f9b\u4e86\u5404\u79cd\u4e0d\u540c\u7684\u96c6\u5408\u7c7b\u578b\u6765\u9002\u5e94\u4e0d\u540c\u7684\u9700\u6c42\u3002\u9700\u8981\u6839\u636e\u5177\u4f53\u7684\u4f7f\u7528\u60c5\u51b5\u6765\u9009\u62e9\u54ea\u79cd\u96c6\u5408\u7c7b\u578b\u66f4\u9002\u5408\u3002\u540c\u65f6\uff0cPython \u8fd8\u63d0\u4f9b\u4e86\u65b9\u4fbf\u7684\u5217\u8868\u63a8\u5bfc\u3001\u96c6\u5408\u63a8\u5bfc\u548c\u5b57\u5178\u63a8\u5bfc\u7b49\u7279\u6027\uff0c\u53ef\u4ee5\u66f4\u52a0\u4fbf\u6377\u5730\u521b\u5efa\u548c\u5904\u7406\u591a\u9879\u96c6\u3002","title":"2.7.\u7f16\u7a0b\u7ec3\u4e60"},{"location":"python/DataStructure/03_TimeComplexity/","text":"3.\u641c\u7d22\u3001\u6392\u5e8f\u4ee5\u53ca\u590d\u6742\u5ea6\u5206\u6790 \u00b6 \u7b97\u6cd5\u63cf\u8ff0\u4e86\u4e00\u4e2a\u968f\u7740\u95ee\u9898\u88ab\u89e3\u51b3\u800c\u505c\u6b62\u7684\u8ba1\u7b97\u8fc7\u7a0b\u3002 \u7b97\u6cd5\u662f\u8ba1\u7b97\u673a\u7a0b\u5e8f\u7684\u57fa\u672c\u7ec4\u6210\u90e8\u5206\u4e4b\u4e00\uff0c\u53e6\u4e00\u4e2a\u57fa\u672c\u7ec4\u6210\u90e8\u5206\u662f\u6570\u636e\u7ed3\u6784\u3002 \u5728\u7b97\u6cd5\u6267\u884c\u8fc7\u7a0b\u4e2d\u4f1a\u6d88\u8017\u4e24\u4e2a\u8d44\u6e90\uff1a\u5904\u7406\u5bf9\u8c61\u6240\u9700\u7684\u65f6\u95f4\u548c\u7a7a\u95f4\uff08\u4e5f\u5c31\u662f\u5185\u5b58\uff09\u3002\u5bf9\u4e8e\u7b97\u6cd5\u6765\u8bf4\uff0c\u603b\u4f1a\u8ffd\u6c42\u6d88\u8017\u66f4\u77ed\u7684\u65f6\u95f4\u548c\u5360\u7528\u66f4\u5c11\u7684\u7a7a\u95f4\u3002\u5728\u9009\u62e9\u7b97\u6cd5\u65f6\uff0c\u901a\u5e38\u5728\u7a7a\u95f4/\u65f6\u95f4\u4e4b\u95f4\u8fdb\u884c\u6743\u8861\u3002 \u7b97\u6cd5\u8d28\u91cf\u7684\u4e3b\u8981\u8bc4\u4f30\u6807\u51c6\uff1a \u6b63\u786e\u6027\uff0c\u5373\u7b97\u6cd5\u80fd\u591f\u771f\u6b63\u89e3\u51b3\u6240\u9488\u5bf9\u7684\u95ee\u9898\uff1b \u53ef\u8bfb\u6027\u548c\u6613\u4e8e\u7ef4\u62a4\u6027\uff1b \u8fd0\u884c\u65f6\u6027\u80fd\uff1b \u76ee\u6807\uff1a \u6839\u636e\u95ee\u9898\u7684\u89c4\u6a21\u786e\u5b9a\u7b97\u6cd5\u5de5\u4f5c\u91cf\u7684\u589e\u957f\u7387\uff1b \u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u6765\u63cf\u8ff0\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\uff1b \u8ba4\u8bc6\u5e38\u89c1\u7684\u5de5\u4f5c\u91cf\u589e\u957f\u7387\u6216\u590d\u6742\u5ea6\u7684\u7c7b\u522b\uff08\u5e38\u6570\u3001\u5bf9\u6570\u3001\u7ebf\u6027\u3001\u5e73\u65b9\u548c\u6307\u6570\uff09\uff1b \u5c06\u7b97\u6cd5\u8f6c\u6362\u4e3a\u590d\u6742\u5ea6\u4f4e\u4e00\u4e2a\u6570\u91cf\u7ea7\u7684\u66f4\u5feb\u7684\u7248\u672c\uff1b \u63cf\u8ff0\u987a\u5e8f\u641c\u7d22\u7b97\u6cd5\u548c\u4e8c\u5206\u641c\u7d22\u7b97\u6cd5\u7684\u5de5\u4f5c\u65b9\u5f0f\uff1b \u63cf\u8ff0\u9009\u62e9\u6392\u5e8f\u7b97\u6cd5\u548c\u5feb\u901f\u6392\u5e8f\u7b97\u6cd5\u7684\u5de5\u4f5c\u65b9\u5f0f\u3002 3.1.\u8861\u91cf\u7b97\u6cd5\u7684\u6548\u7387 \u00b6 \u8861\u91cf\u7b97\u6cd5\u65f6\u95f4\u6210\u672c\u7684\u4e24\u79cd\u65b9\u6cd5\uff1a \u7528\u8ba1\u7b97\u673a\u65f6\u949f\u5f97\u5230\u7b97\u6cd5\u5b9e\u9645\u7684\u8fd0\u884c\u65f6\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u88ab\u79f0\u4e3a\u57fa\u51c6\u6d4b\u8bd5\uff08benchmarking\uff09\u6216\u6027\u80fd\u5206\u6790\uff08profiling\uff09\u3002\u9884\u6d4b\u7b97\u6cd5\u6267\u884c\u7684\u62bd\u8c61\u5de5\u4f5c\u91cf\u4f9d\u8d56\u4e8e\u7279\u5b9a\u7684\u786c\u4ef6\u6216\u8f6f\u4ef6\u5e73\u53f0\u3002 \u5728\u4e0d\u540c\u95ee\u9898\u89c4\u6a21\u4e0b\uff0c\u7edf\u8ba1\u9700\u8981\u6267\u884c\u7684\u6307\u4ee4\u6570\u3002\u9884\u6d4b\u7b97\u6cd5\u6267\u884c\u7684\u62bd\u8c61\u5de5\u4f5c\u91cf\u9002\u7528\u4e8e\u4e0d\u540c\u7684\u786c\u4ef6\u6216\u8f6f\u4ef6\u5e73\u53f0\u3002 3.1.1.\u8861\u91cf\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6 \u00b6 import time problemSize = 10000000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): \"\"\" \u5728\u4e00\u4e2a\u5faa\u73af\u4e2d\uff0c\u5c06\u95ee\u9898\u89c4\u6a21\u7ffb\u500d5\u6b21\uff0c\u8bb0\u5f55\u7b97\u6cd5\u6bcf\u6b21\u8fd0\u884c\u65f6\u95f4\u3002 \"\"\" start = time . time () # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f elapsed = time . time () - start print ( \" %12d%16.3f \" % ( problemSize , elapsed )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Seconds # 10000000 0.689 # 20000000 1.367 # 40000000 2.644 # 80000000 5.296 # 160000000 10.622 \u4e0a\u8ff0\u6d4b\u8bd5\u7a0b\u5e8f\u4f7f\u7528\u4e86 time \u6a21\u5757\u91cc\u7684 time() \u51fd\u6570\u6765\u8bb0\u5f55\u8fd0\u884c\u65f6\uff0c\u5373 time.time() \u3002\u8fd9\u4e2a\u51fd\u6570\u4f1a\u8fd4\u56de\u8ba1\u7b97\u673a\u7684\u5f53\u524d\u65f6\u95f4\u548c1970\u5e741\u67081\u65e5\uff3b\u4e5f\u79f0\u4e3a\u7eaa\u5143\uff08epoch\uff09\uff3d\u76f8\u5dee\u7684\u79d2\u6570\u3002\u4e24\u6b21\u8c03\u7528 time.time() \u7684\u7ed3\u679c\u4e4b\u95f4\u7684\u5dee\u503c\u5c31\u4ee3\u8868\u4e86\u4e2d\u95f4\u7ecf\u5386\u4e86\u591a\u5c11\u79d2\u3002 \u4e0a\u8ff0\u6d4b\u8bd5\u7a0b\u5e8f\u5728\u6bcf\u6b21\u5faa\u73af\u7684\u65f6\u5019\u90fd\u4f1a\u6267\u884c\u4e24\u4e2a\u6269\u5c55\u7684\u8d4b\u503c\u8bed\u53e5\uff0c\u4e5f\u5c31\u662f\u6bcf\u6b21\u90fd\u6267\u884c\u7684\u5de5\u4f5c\u91cf\u662f\u56fa\u5b9a\u7684\uff0c\u4f1a\u6d88\u8017\u4e86\u4e00\u5b9a\u7684\u65f6\u95f4\u3002 \u4fee\u6539\u4e0a\u8ff0\u7b97\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u4ece\u4e0b\u9762\u7684\u8fd0\u884c\u7ed3\u679c\u770b\u51fa\uff0c\u5f53 problemSize \u4e3a 1,000 \u65f6\uff0c\u7b97\u6cd5\u7684\u6d88\u8017\u65f6\u95f4\u5c31\u5df2\u7ecf\u8d85\u8fc7\u4e86\u539f\u5148\u7b97\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u63a8\u65ad\u51fa\u7ee7\u7eed\u6d4b\u8bd5 problemSize \u4e3a 10,000,000 \u7684\u8017\u65f6\u5df2\u7ecf\u53d8\u5f97\u4e0d\u5b9e\u9645\u4e86\u3002 import time problemSize = 1000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): start = time . time () # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): for y in range ( problemSize ): work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f elapsed = time . time () - start print ( \" %12d%16.3f \" % ( problemSize , elapsed )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Seconds # 1000 0.093 # 2000 0.350 # 4000 1.280 # 8000 5.004 # 16000 20.020 \u4e0d\u540c\u7684\u786c\u4ef6\u5e73\u53f0\u4f1a\u6709\u4e0d\u540c\u7684\u5904\u7406\u901f\u5ea6\uff0c\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u4f1a\u56e0\u673a\u5668\u7684\u4e0d\u540c\u800c\u5b58\u5728\u5dee\u5f02\u3002 \u7a0b\u5e8f\u7684\u8fd0\u884c\u65f6\u4e5f\u4f1a\u968f\u7740\u5b83\u548c\u786c\u4ef6\u4e4b\u95f4\u7684\u64cd\u4f5c\u7cfb\u7edf\u7c7b\u578b\u7684\u4e0d\u540c\u800c\u53d8\u5316\u3002 \u4e0d\u540c\u7684\u7f16\u7a0b\u8bed\u8a00\u548c\u7f16\u8bd1\u5668\u751f\u6210\u7684\u4ee3\u7801\u7684\u6027\u80fd\u4e5f\u4f1a\u6709\u6240\u4e0d\u540c\uff0c\u56e0\u6b64\uff0c\u5728\u67d0\u4e00\u4e2a\u786c\u4ef6\u6216\u8f6f\u4ef6\u5e73\u53f0\u4e0a\u6d4b\u5f97\u7684\u8fd0\u884c\u65f6\u7ed3\u679c\u901a\u5e38\u4e0d\u80fd\u7528\u6765\u9884\u6d4b\u5728\u5176\u4ed6\u5e73\u53f0\u4e0a\u7684\u6027\u80fd\u3002 \u7528\u975e\u5e38\u5927\u7684\u6570\u636e\u96c6\u786e\u5b9a\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u662f\u975e\u5e38\u4e0d\u5207\u5b9e\u9645\u7684\u3002\u5bf9\u4e8e\u67d0\u4e9b\u7b97\u6cd5\u6765\u8bf4\uff0c\u4e0d\u8bba\u662f\u7f16\u8bd1\u7684\u4ee3\u7801\u8fd8\u662f\u786c\u4ef6\u5904\u7406\u5668\u7684\u901f\u5ea6\u6709\u591a\u5feb\uff0c\u90fd\u6ca1\u6709\u4efb\u4f55\u7684\u533a\u522b\uff0c\u56e0\u4e3a\u5b83\u4eec\u5728\u4efb\u4f55\u8ba1\u7b97\u673a\u4e0a\u90fd\u6ca1\u529e\u6cd5\u5904\u7406\u975e\u5e38\u5927\u7684\u6570\u636e\u96c6\u3002 3.1.2.\u7edf\u8ba1\u6307\u4ee4\u6570 \u00b6 \u7edf\u8ba1\u6307\u4ee4\u6570\u65f6\uff0c\u7edf\u8ba1\u7684\u662f\u7f16\u5199\u7b97\u6cd5\u7684\u9ad8\u7ea7\u8bed\u8a00\u91cc\u7684\u6307\u4ee4\u6570\uff0c\u800c\u4e0d\u662f\u53ef\u6267\u884c\u673a\u5668\u8bed\u8a00\u7a0b\u5e8f\u91cc\u7684\u6307\u4ee4\u6570\u3002 \u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\u5bf9\u7b97\u6cd5\u8fdb\u884c\u5206\u6790\u65f6\uff0c\u628a\u5b83\u5206\u6210\u4e24\u4e2a\u90e8\u5206\uff1a \u65e0\u8bba\u95ee\u9898\u7684\u89c4\u6a21\u5982\u4f55\u53d8\u5316\uff0c\u6307\u4ee4\u6267\u884c\u7684\u6b21\u6570\u603b\u662f\u76f8\u540c\u7684\uff1b\u6211\u4eec\u5ffd\u7565\u8fd9\u79cd\u7c7b\u578b\uff0c\u56e0\u4e3a\u5206\u6790\u6548\u7387\u65f6\u5b83\u4eec\u7684\u4f5c\u7528\u5e76\u4e0d\u660e\u663e\u3002 \u6267\u884c\u7684\u6307\u4ee4\u6570\u968f\u7740\u95ee\u9898\u89c4\u6a21\u7684\u53d8\u5316\u800c\u53d8\u5316\uff1b\u6211\u4eec\u91cd\u70b9\u5173\u6ce8\u8fd9\u79cd\u7c7b\u578b\uff0c\u8fd9\u79cd\u7c7b\u578b\u7684\u6307\u4ee4\u901a\u5e38\u53ef\u4ee5\u5728\u5faa\u73af\u6216\u8005\u9012\u5f52\u51fd\u6570\u91cc\u627e\u5230\u3002 \u6211\u4eec\u6765\u6539\u5199\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u4ece\u7edf\u8ba1\u8fd0\u884c\u65f6\u95f4\u53d8\u4e3a\u7edf\u8ba1\u8fed\u4ee3\u6b21\u6570\u3002 \u4e0b\u9762\u7684\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u662f\u76f8\u7b49\u7684\u3002 import time problemSize = 10000000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): number = 0 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%16.3f \" % ( problemSize , Iterations )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Iterations # 10000000 10000000.000 # 20000000 20000000.000 # 40000000 40000000.000 # 80000000 80000000.000 # 160000000 160000000.000 \u4e0b\u9762\u7684\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u7684\u5e73\u65b9\u3002\u8fd9\u5c31\u89e3\u91ca\u4e86\u4e3a\u4ec0\u4e48\u8fd9\u4e2a\u7b97\u6cd5\u7684\u8017\u65f6\u975e\u5e38\u5927\u3002 import time problemSize = 1000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): number = 0 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): for y in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%16.3f \" % ( problemSize , number )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Iterations # 1000 1000000.000 # 2000 4000000.000 # 4000 16000000.000 # 8000 64000000.000 # 16000 256000000.000 \u5728\u4e0b\u9762\u7684\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7684\u4f8b\u5b50\u4e2d\uff0c\u51fd\u6570 fib(problemSize, counter) \u4e2d counter \u53c2\u6570\u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u7684\u65f6\u5019\uff0c\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u3002 \u4ece\u4e0b\u9762\u7684\u8fd0\u884c\u7ed3\u679c\u53ef\u4ee5\u770b\u51fa\uff0c\u968f\u7740\u95ee\u9898\u89c4\u6a21\uff08Problem Size\uff09\u7684\u7ffb\u500d\uff0c\u6307\u4ee4\u6570\uff08\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\uff09\u5728\u4e00\u5f00\u59cb\u7684\u65f6\u5019\u7f13\u6162\u589e\u957f\uff0c\u968f\u540e\u8fc5\u901f\u52a0\u5feb\u3002 \u7edf\u8ba1\u6307\u4ee4\u6570\u662f\u6b63\u786e\u7684\u601d\u8def\uff0c\u4f46\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u8fdb\u884c\u8ddf\u8e2a\u8ba1\u6570\u7684\u95ee\u9898\u5728\u4e8e\uff0c\u5bf9\u4e8e\u67d0\u4e9b\u7b97\u6cd5\u6765\u8bf4\uff0c\u5982\u679c\u95ee\u9898\u89c4\u6a21\u975e\u5e38\u5927\uff0c\u8ba1\u7b97\u673a\u65e0\u6cd5\u4ee5\u8db3\u591f\u5feb\u7684\u901f\u5ea6\u8fd0\u884c\uff0c\u5e76\u5728\u4e00\u5b9a\u65f6\u95f4\u5185\u5f97\u5230\u7ed3\u679c\u3002 class Counter ( object ): \"\"\"Models a counter.\"\"\" # Class variable instances = 0 #Constructor def __init__ ( self ): \"\"\"Sets up the counter.\"\"\" Counter . instances += 1 self . reset () # Mutator methods def reset ( self ): \"\"\"Sets the counter to 0.\"\"\" self . _value = 0 def increment ( self , amount = 1 ): \"\"\"Adds amount to the counter.\"\"\" self . _value += amount def decrement ( self , amount = 1 ): \"\"\"Subtracts amount from the counter.\"\"\" self . _value -= amount # Accessor methods def getValue ( self ): \"\"\"Returns the counter's value.\"\"\" return self . _value def __str__ ( self ): \"\"\"Returns the string representation of the counter.\"\"\" return str ( self . _value ) def __eq__ ( self , other ): \"\"\"Returns True if self equals other or False otherwise.\"\"\" if self is other : return True if type ( self ) != type ( other ): return False return self . _value == other . _value def fib ( n , counter ): \"\"\"\u7edf\u8ba1\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u88ab\u5916\u90e8\u8c03\u7528\u7684\u6b21\u6570\"\"\" counter . increment () if n < 3 : return 1 else : return fib ( n - 1 , counter ) + fib ( n - 2 , counter ) problemSize = 2 print ( \" %12s%15s \" % ( \"Problem Size\" , \"Calls\" )) for count in range ( 5 ): \"\"\"\u968f\u7740\u95ee\u9898\u89c4\u6a21\u589e\u52a0\uff0c\u8f93\u51fa\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u51fd\u6570\u88ab\u5916\u90e8\u8c03\u7528\u7684\u6b21\u6570\"\"\" counter = Counter () # \u7b97\u6cd5\u5f00\u59cb fib ( problemSize , counter ) # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%15s \" % ( problemSize , counter )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Calls # 2 1 # 4 5 # 8 41 # 16 1973 # 32 4356617 3.1.3.\u8861\u91cf\u7b97\u6cd5\u4f7f\u7528\u7684\u5185\u5b58 \u00b6 \u5bf9\u4e8e\u7b97\u6cd5\u6240\u7528\u8d44\u6e90\u7684\u5206\u6790\u4e5f\u9700\u8981\u5305\u542b\u5b83\u6240\u9700\u7684\u5185\u5b58\u91cf\u7684\u5206\u6790\u3002\u548c\u524d\u9762\u7c7b\u4f3c\u7684\u95ee\u9898\u4e5f\u4f1a\u5b58\u5728\uff0c\u4e00\u4e9b\u7b97\u6cd5\u4f1a\u968f\u7740\u95ee\u9898\u89c4\u6a21\u53d8\u5927\u800c\u9700\u8981\u989d\u5916\u66f4\u591a\u7684\u5185\u5b58\u3002 3.1.4.\u7ec3\u4e60\u9898 \u00b6 \u7f16\u5199\u4e00\u4e2a\u6d4b\u8bd5\u7a0b\u5e8f\uff0c\u8fd9\u4e2a\u7a0b\u5e8f\u7edf\u8ba1\u5e76\u663e\u793a\u51fa\u4e0b\u9762\u8fd9\u4e2a\u5faa\u73af\u7684\u8fed\u4ee3\u6b21\u6570\u3002 while problemSize > 0 : problemSize = problemSize // 2 \u89e3\u7b54\uff1a def count_iterations ( problemSize ): iterations = 0 # \u521d\u59cb\u5316\u8ba1\u6570\u5668 while problemSize > 0 : problemSize = problemSize // 2 iterations += 1 # \u6bcf\u6b21\u5faa\u73af\u8fed\u4ee3\uff0c\u8ba1\u6570\u5668\u52a0\u4e00 return iterations problemSize = 1000 # \u8bbe\u7f6e\u95ee\u9898\u89c4\u6a21 iterations = count_iterations ( problemSize ) print ( f \"Problem Size: { problemSize } \" ) print ( f \"Iterations: { iterations } \" ) # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size: 1000 # Iterations: 10 \u5728\u95ee\u9898\u89c4\u6a21\u5206\u522b\u4e3a1000\u30012000\u30014000\u300110000\u548c100000\u65f6\uff0c\u8fd0\u884c\u5728\u7ec3\u4e601\u91cc\u6240\u521b\u5efa\u7684\u7a0b\u5e8f\u3002\u5f53\u95ee\u9898\u89c4\u6a21\u7ffb\u500d\u6216\u662f\u4e58\u4ee510\u65f6\uff0c\u8fed\u4ee3\u6b21\u6570\u4f1a\u5982\u4f55\u53d8\u5316\uff1f \u89e3\u7b54\uff1a\u5206\u522b\u4ee5\u4e0d\u540c\u7684\u95ee\u9898\u89c4\u6a21\u8fd0\u884c\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u7ed3\u679c\u5982\u4e0b\uff1a Problem Size : 1000 Iterations : 10 Problem Size : 4000 Iterations : 12 Problem Size : 8000 Iterations : 13 Problem Size : 10000 Iterations : 14 Problem Size : 100000 Iterations : 17 \u4e24\u6b21\u8c03\u7528\u51fd\u6570 time.time() \u7684\u7ed3\u679c\u4e4b\u5dee\u5c31\u662f\u8fd0\u884c\u65f6\u3002\u7531\u4e8e\u64cd\u4f5c\u7cfb\u7edf\u4e5f\u53ef\u80fd\u4f1a\u5728\u8fd9\u6bb5\u65f6\u95f4\u5185\u4f7f\u7528CPU\uff0c\u56e0\u6b64\u8fd9\u4e2a\u8fd0\u884c\u65f6\u53ef\u80fd\u5e76\u4e0d\u80fd\u53cd\u6620\u51faPython\u4ee3\u7801\u4f7f\u7528CPU\u7684\u5b9e\u9645\u65f6\u95f4\u3002\u6d4f\u89c8Python\u6587\u6863\uff0c\u627e\u51fa\u53e6\u4e00\u79cd\u53ef\u4ee5\u5b8c\u6574\u8bb0\u5f55\u5904\u7406\u65f6\u95f4\u7684\u65b9\u6cd5\uff0c\u5e76\u63cf\u8ff0\u5982\u4f55\u5b9e\u73b0\u5b83\u3002 \u89e3\u7b54\uff1a \u5728Python\u4e2d\uff0c time \u6a21\u5757\u63d0\u4f9b\u4e86\u66f4\u7cbe\u786e\u7684\u8ba1\u65f6\u529f\u80fd\uff0c\u5176\u4e2d\u7684 time.perf_counter() \u51fd\u6570\u53ef\u4ee5\u7528\u6765\u6d4b\u91cf\u65f6\u95f4\u7684\u7cbe\u786e\u95f4\u9694\u3002\u4e0e time.time() \u4e0d\u540c\uff0c time. perf_counter() \u4f1a\u5728\u5927\u591a\u6570\u5e73\u53f0\u4e0a\u63d0\u4f9b\u4e00\u4e2a\u66f4\u9ad8\u5206\u8fa8\u7387\u7684\u8ba1\u65f6\u5668\uff0c\u53ef\u4ee5\u7528\u6765\u6d4b\u91cf\u4ee3\u7801\u5757\u7684\u6267\u884c\u65f6\u95f4\u3002 time.perf_counter() \u8fd4\u56de\u4e00\u4e2a\u6d6e\u70b9\u6570\uff0c\u8868\u793a\u4ece\u67d0\u4e2a\u7279\u5b9a\u65f6\u95f4\u70b9\u5230\u73b0\u5728\u7ecf\u8fc7\u7684\u79d2\u6570\u3002\u4ee5\u4e0b\u662f\u5982\u4f55\u4f7f\u7528 time.perf_counter() \u6765\u8ba1\u7b97\u4ee3\u7801\u5757\u7684\u6267\u884c\u65f6\u95f4\uff1a import time # \u83b7\u53d6\u8d77\u59cb\u65f6\u95f4\uff08\u5305\u62ecCPU\u65f6\u95f4\u548c\u7cfb\u7edf\u65f6\u95f4\uff09 start_cpu_time = time . process_time () start_real_time = time . perf_counter () start_system_time = time . time () # \u6267\u884c\u4ee3\u7801 for i in range ( 100000000 ): _ = i * i # \u83b7\u53d6\u7ed3\u675f\u65f6\u95f4\uff08\u5305\u62ecCPU\u65f6\u95f4\u548c\u7cfb\u7edf\u65f6\u95f4\uff09 end_cpu_time = time . process_time () end_real_time = time . perf_counter () end_system_time = time . time () # \u8ba1\u7b97CPU\u65f6\u95f4\u5dee cpu_execution_time = end_cpu_time - start_cpu_time real_execution_time = end_real_time - start_real_time system_execution_time = end_system_time - start_system_time print ( f \"CPU Execution Time: { cpu_execution_time : .6f } seconds\" ) print ( f \"Real Execution Time: { real_execution_time : .6f } seconds\" ) print ( f \"System Execution Time: { system_execution_time : .6f } seconds\" ) # \u8fd0\u884c\u7ed3\u679c\uff1a # CPU Execution Time: 7.157305 seconds # Real Execution Time: 7.156638 seconds # System Execution Time: 7.156638 seconds \u5728\u4e0a\u9762\u4ee3\u7801\u4e2d\uff0c start_system_time \u548c end_system_time \u5206\u522b\u8bb0\u5f55\u4e86\u4ee3\u7801\u5757\u5f00\u59cb\u548c\u7ed3\u675f\u65f6\u7684\u7cfb\u7edf\u65f6\u95f4\u3002\u7136\u540e\uff0c\u53ef\u4ee5\u901a\u8fc7\u8ba1\u7b97 end_system_time - start_system_time \u6765\u83b7\u53d6\u7cfb\u7edf\u65f6\u95f4\u7684\u6d88\u8017\u3002 \u7cfb\u7edf\u65f6\u95f4\u7684\u8ba1\u7b97\u53ef\u80fd\u53d7\u5230\u7cfb\u7edf\u7684\u5f71\u54cd\uff0c\u53ef\u80fd\u4f1a\u56e0\u4e3a\u7cfb\u7edf\u65f6\u95f4\u7684\u53d8\u5316\u800c\u4ea7\u751f\u4e0d\u51c6\u786e\u7684\u7ed3\u679c\u3002\u5728\u8fdb\u884c\u6027\u80fd\u6d4b\u8bd5\u65f6\uff0c\u5c3d\u91cf\u4ee5CPU\u65f6\u95f4\u548c\u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u4e3a\u4e3b\u8981\u53c2\u8003\u6307\u6807\u3002 \u8865\u5145\uff1a CPU \u65f6\u95f4\u3001\u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u548c\u7cfb\u7edf\u65f6\u95f4\u4ee3\u8868\u4e86\u4e0d\u540c\u7684\u65f6\u95f4\u6307\u6807\uff0c\u5b83\u4eec\u4e4b\u95f4\u6709\u4ee5\u4e0b\u533a\u522b\uff1a CPU \u65f6\u95f4\uff1a - CPU \u65f6\u95f4\u662f\u7a0b\u5e8f\u5728 CPU \u4e0a\u6267\u884c\u7684\u65f6\u95f4\uff0c\u5305\u62ec\u4e86\u5728\u7528\u6237\u6001\uff08\u6267\u884c\u5e94\u7528\u7a0b\u5e8f\u4ee3\u7801\uff09\u548c\u5185\u6838\u6001\uff08\u6267\u884c\u64cd\u4f5c\u7cfb\u7edf\u4ee3\u7801\uff09\u7684\u65f6\u95f4\u3002\u56e0\u6b64\uff0c\u5b83\u8003\u8651\u4e86\u5e94\u7528\u7a0b\u5e8f\u548c\u64cd\u4f5c\u7cfb\u7edf\u7684\u6267\u884c\u65f6\u95f4\u3002 - CPU \u65f6\u95f4\u901a\u5e38\u7528\u4e8e\u6d4b\u91cf\u7a0b\u5e8f\u7684\u8ba1\u7b97\u5bc6\u96c6\u578b\u5de5\u4f5c\u91cf\uff0c\u5373\u5927\u91cf\u8ba1\u7b97\u64cd\u4f5c\uff0c\u6bd4\u5982\u5faa\u73af\u548c\u6570\u5b66\u8ba1\u7b97\u3002 - \u901a\u8fc7 time.process_time() \u51fd\u6570\u53ef\u4ee5\u83b7\u53d6\u5f53\u524d\u8fdb\u7a0b\u7684 CPU \u65f6\u95f4\u3002 \u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\uff1a - \u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u662f\u4ece\u67d0\u4e2a\u65f6\u95f4\u70b9\u5230\u73b0\u5728\u7684\u5b9e\u9645\u7ecf\u8fc7\u7684\u65f6\u95f4\uff0c\u8003\u8651\u4e86\u6240\u6709\u56e0\u7d20\uff0c\u5305\u62ec\u4e86 CPU \u65f6\u95f4\u3001\u7b49\u5f85\u65f6\u95f4\u3001\u7cfb\u7edf\u8c03\u5ea6\u7b49\u3002 - \u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u7528\u4e8e\u6d4b\u91cf\u4ee3\u7801\u7684\u603b\u6267\u884c\u65f6\u95f4\uff0c\u5305\u62ec\u4e86\u8ba1\u7b97\u548c\u7b49\u5f85\u7684\u65f6\u95f4\u3002 - \u901a\u8fc7 time.perf_counter() \u51fd\u6570\u53ef\u4ee5\u83b7\u53d6\u5f53\u524d\u65f6\u95f4\u3002 \u7cfb\u7edf\u65f6\u95f4\uff1a - \u7cfb\u7edf\u65f6\u95f4\u662f\u64cd\u4f5c\u7cfb\u7edf\u5185\u90e8\u7ef4\u62a4\u7684\u4e00\u4e2a\u65f6\u95f4\u503c\uff0c\u5b83\u4ee3\u8868\u4e86\u4ece\u67d0\u4e2a\u56fa\u5b9a\u65f6\u95f4\u70b9\u5f00\u59cb\u7684\u79d2\u6570\u3002 - \u7cfb\u7edf\u65f6\u95f4\u901a\u5e38\u7528\u4e8e\u8bb0\u5f55\u4e8b\u4ef6\u548c\u8ba1\u7b97\u65f6\u95f4\u95f4\u9694\uff0c\u4e0d\u53d7\u7a0b\u5e8f\u7684\u6267\u884c\u5f71\u54cd\u3002 - \u901a\u8fc7 time.time() \u51fd\u6570\u53ef\u4ee5\u83b7\u53d6\u5f53\u524d\u7684\u7cfb\u7edf\u65f6\u95f4\u3002 \u603b\u7ed3\uff1aCPU \u65f6\u95f4\u5173\u6ce8\u7684\u662f\u7a0b\u5e8f\u5728 CPU \u4e0a\u7684\u6267\u884c\u65f6\u95f4\uff0c\u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u5173\u6ce8\u7684\u662f\u4ece\u4ee3\u7801\u5f00\u59cb\u5230\u7ed3\u675f\u6240\u7ecf\u8fc7\u7684\u771f\u5b9e\u65f6\u95f4\uff0c\u7cfb\u7edf\u65f6\u95f4\u662f\u7cfb\u7edf\u7ef4\u62a4\u7684\u5168\u5c40\u65f6\u95f4\u3002\u5728\u4e0d\u540c\u7684\u573a\u666f\u4e2d\uff0c\u4f60\u53ef\u4ee5\u6839\u636e\u9700\u8981\u9009\u62e9\u5408\u9002\u7684\u65f6\u95f4\u6307\u6807\u6765\u8fdb\u884c\u6027\u80fd\u6d4b\u91cf\u548c\u5206\u6790\u3002 3.2.\u590d\u6742\u5ea6\u5206\u6790 \u00b6 \u590d\u6742\u5ea6\u5206\u6790\uff08complexity analysis\uff09\u65b9\u6cd5\uff0c\u4e00\u79cd\u8bc4\u4f30\u7b97\u6cd5\u6548\u7387\u7684\u65b9\u6cd5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u53ef\u4ee5\u4e0d\u7528\u5173\u5fc3\u4e0e\u5e73\u53f0\u76f8\u5173\u7684\u65f6\u95f4\uff0c\u4e5f\u4e0d\u9700\u8981\u4f7f\u7528\u7edf\u8ba1\u6307\u4ee4\u6570\u91cf\u8fd9\u79cd\u65b9\u6cd5\u6765\u5bf9\u7b97\u6cd5\u8fdb\u884c\u8bc4\u4f30\u3002 3.2.1.\u590d\u6742\u5ea6\u7684\u9636 \u00b6 \u5728 3.1.2.\u7edf\u8ba1\u6307\u4ee4\u6570 \u4e2d\u5173\u4e8e\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u7684\u4e24\u4e2a\u7b97\u6cd5\uff0c\u5b83\u4eec\u590d\u6742\u5ea6\u7684\u9636\uff08order of complexity\uff09\u4e0a\u662f\u4e0d\u4e00\u6837\u7684\u3002 \u7b2c\u4e00\u4e2a\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u4e4b\u95f4\u662f\u7ebf\u6027\u5173\u7cfb\uff0c\u79f0\u5176\u590d\u6742\u5ea6\u4e3a\u7ebf\u6027\uff08linear\uff09\u9636\uff1b \u7b2c\u4e8c\u4e2a\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u4e4b\u95f4\u662f\u5e73\u65b9\u5173\u7cfb\uff0c\u79f0\u5176\u590d\u6742\u5ea6\u4e3a\u5e73\u65b9\uff08quadratic\uff09\u9636\uff1b \u5982\u679c\u7b97\u6cd5\u9700\u8981\u76f8\u540c\u6570\u91cf\u7684\u8fd0\u7b97\uff0c\u90a3\u4e48\u5b83\u7684\u6027\u80fd\u5c31\u662f\u5e38\u6570\uff08constant\uff09\u9636\u3002\u5217\u8868\u7d22\u5f15\u5c31\u662f\u4e00\u4e2a\u5e38\u6570\u65f6\u95f4\u7b97\u6cd5\u7684\u4f8b\u5b50\u3002 \u6bd4\u7ebf\u6027\u6027\u80fd\u597d\uff0c\u4f46\u6bd4\u5e38\u6570\u6027\u80fd\u5dee\u7684\u53e6\u4e00\u4e2a\u590d\u6742\u5ea6\u7684\u9636\u88ab\u79f0\u4e3a\u5bf9\u6570\uff08logarithmic\uff09\u9636\u3002\u5bf9\u6570\u7b97\u6cd5\u7684\u5de5\u4f5c\u91cf\u4e0e\u95ee\u9898\u89c4\u6a21\u7684\u4ee52\u4e3a\u5e95\u7684\u5bf9\u6570\u6210\u6b63\u6bd4\u3002\u5f53\u95ee\u9898\u89c4\u6a21\u6269\u5927\u4e00\u500d\u65f6\uff0c\u5de5\u4f5c\u91cf\u53ea\u4f1a\u52a01\u3002 \u591a\u9879\u5f0f\u65f6\u95f4\u7b97\u6cd5\uff08polynomial time algorithm\uff09\u7684\u5de5\u4f5c\u91cf\u4f1a\u4ee5 n^k \u7684\u901f\u7387\u589e\u957f\uff0c\u5176\u4e2d k \u662f\u5927\u4e8e 1 \u7684\u5e38\u6570\uff0c\u6bd4\u5982 n^2 \u3001 n^3 \u4ee5\u53ca n^10 \u3002\u4ece\u67d0\u79cd\u610f\u4e49\u4e0a\u8bb2\uff0c n^3 \u7684\u6027\u80fd\u8981\u6bd4 n^2 \u5dee\uff0c\u4f46\u90fd\u5c5e\u4e8e\u591a\u9879\u5f0f\uff08polynomial\uff09\u9636\u3002 \u6bd4\u591a\u9879\u5f0f\u8fd8\u8981\u5dee\u7684\u590d\u6742\u5ea6\u7684\u9636\u88ab\u79f0\u4e3a\u6307\u6570\uff08exponential\uff09\u9636\uff0c\u6bd4\u5982 2^n \u3002\u5bf9\u4e8e\u5927\u7684\u95ee\u9898\u89c4\u6a21\u6765\u8bf4\uff0c\u6307\u6570\u7b97\u6cd5\u662f\u4e0d\u53ef\u884c\u7684\u3002 \u4e0d\u540c\u590d\u6742\u5ea6\u9636\u7684\u7b97\u6cd5\u7684\u5de5\u4f5c\u91cf\u6bd4\u8f83\uff08\u4ece\u5c0f\u5230\u5927\uff09\uff1a\u5bf9\u6570\u9636 < \u7ebf\u6027\u9636 < \u5e73\u65b9\u9636 < \u6307\u6570\u9636\u3002\u968f\u7740\u95ee\u9898\u89c4\u6a21\u7684\u589e\u5927\uff0c\u5177\u6709\u8f83\u9ad8\u590d\u6742\u5ea6\u7684\u9636\u7684\u7b97\u6cd5\u7684\u6027\u80fd\u4f1a\u66f4\u5feb\u5730\u53d8\u5dee\u3002 3.2.2.\u5927O\u8868\u793a\u6cd5 \u00b6 \u5f88\u591a\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u4e2d\u7684\u5de5\u4f5c\u91cf\u901a\u5e38\u662f\u591a\u9879\u5f0f\u91cc\u591a\u9879\u7684\u603b\u548c\uff0c\u800c\u5f53\u5de5\u4f5c\u91cf\u8868\u793a\u4e3a\u591a\u9879\u5f0f\u65f6\uff0c\u5176\u4e2d\u4e00\u9879\u662f\u4e3b\u5bfc\u9879\uff08dominant\uff09\u3002\u968f\u7740 n \u8d8a\u6765\u8d8a\u5927\uff0c\u4e3b\u5bfc\u9879\u5c06\u53d8\u5f97\u975e\u5e38\u5927\uff0c\u4ee5\u81f3\u4e8e\u53ef\u4ee5\u5ffd\u7565\u5176\u4ed6\u9879\u6240\u4ee3\u8868\u7684\u5de5\u4f5c\u91cf\u3002\u56e0\u6b64\uff0c\u5bf9\u4e8e\u591a\u9879\u5f0f n^2+n \uff0c\u53ea\u9700\u8981\u7740\u91cd\u8003\u8651\u5e73\u65b9\u9879 n^2 \uff0c\u4e5f\u5c31\u662f\u5728\u8003\u8651\u7684\u65f6\u5019\u53ef\u4ee5\u5ffd\u7565\u7ebf\u6027\u9879 n \u3002\u968f\u7740 n^2 \u53d8\u5f97\u975e\u5e38\u5927\uff0c\u591a\u9879\u5f0f\u7684\u503c\u6e10\u8fd1\u5730\u63a5\u8fd1\u6216\u8fd1\u4f3c\u4e8e\u5b83\u7684\u6700\u5927\u9879\u503c\uff0c\u8fd9\u79cd\u5f62\u5f0f\u7684\u5206\u6790\u6709\u65f6\u88ab\u79f0\u4e3a\u6e10\u8fd1\u5206\u6790\uff08asymptotic analysis\uff09\u3002 \u8ba1\u7b97\u4e2d\u7528\u6765\u8868\u793a\u7b97\u6cd5\u7684\u6548\u7387\u6216\u8ba1\u7b97\u590d\u6742\u5ea6\u7684\u4e00\u79cd\u65b9\u6cd5\u88ab\u79f0\u4e3a\u5927O\u8868\u793a\u6cd5\uff08big-O notation\uff09\u3002\u201cO\u201d\u4ee3\u8868\u201c\u5728\u2026\u2026\u9636\u201d\uff0c\u6307\u7684\u662f\u7b97\u6cd5\u5de5\u4f5c\u7684\u590d\u6742\u5ea6\u7684\u9636\u3002\u4f8b\u5982\uff1a \u5e38\u6570\u65f6\u95f4\uff1aO(1) \u7ebf\u6027\u65f6\u95f4\uff1aO(n) \u5e73\u65b9\u65f6\u95f4\uff1aO(n^2) \u7acb\u65b9\u65f6\u95f4\uff1aO(n^3) \u591a\u9879\u5f0f\u65f6\u95f4\uff1aO(n^k) 3.2.3.\u6bd4\u4f8b\u5e38\u6570\u7684\u4f5c\u7528 \u00b6 \u6bd4\u4f8b\u5e38\u6570\uff08constant of proportionality\uff09\u5305\u542b\u5728\u5927O\u5206\u6790\u4e2d\u88ab\u5ffd\u7565\u7684\u9879\u548c\u7cfb\u6570\u3002\u6bd4\u5982\uff0c\u7ebf\u6027\u65f6\u95f4\u7b97\u6cd5\u6240\u6267\u884c\u7684\u5de5\u4f5c\u91cf\u53ef\u4ee5\u8868\u793a\u4e3a\uff1a work = 2 * size \uff0c\u5176\u4e2d\u6bd4\u4f8b\u5e38\u6570\u5c31\u662f work/size \uff0c\u4e5f\u5c31\u662f 2 \u3002\u5728\u5904\u7406\u4e2d\u5c0f\u578b\u6570\u636e\u96c6\u7684\u65f6\u5019\uff0c\u5982\u679c\u8fd9\u4e9b\u5e38\u6570\u5f88\u5927\uff0c\u90a3\u4e48\u5b83\u4eec\u4e5f\u4f1a\u5f71\u54cd\u5230\u7b97\u6cd5\u6548\u7387\u3002 \u56de\u987e\u4e0b\u9762\u7684\u4f8b\u5b50\u3002 import time problemSize = 10000000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): number = 0 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%16.3f \" % ( problemSize , Iterations )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Iterations # 10000000 10000000.000 # 20000000 20000000.000 # 40000000 40000000.000 # 80000000 80000000.000 # 160000000 160000000.000 \u5176\u4e2d\u7684\u7b97\u6cd5\u90e8\u5206\uff0c\u9664\u4e86\u5faa\u73af\u8bed\u53e5\u672c\u8eab\uff0c\u8fd8\u6709\u5176\u4ed63\u884c\u4ee3\u7801\uff0c\u5b83\u4eec\u90fd\u662f\u590d\u5236\u8bed\u53e5\uff0c\u90fd\u4f1a\u4ee5\u5e38\u6570\u65f6\u95f4\u8fd0\u884c\u3002\u5047\u8bbe\u5faa\u73af\u8bed\u53e5\u672c\u8eab\u4f1a\u6d88\u8017\u4e00\u4e2a\u65f6\u95f4\u5e38\u6570\uff0c\u90a3\u4e48\u8fd9\u4e2a\u7b97\u6cd5\u7684\u62bd\u8c61\u5de5\u4f5c\u65f6\u95f4\u5c31\u662f 3n+1 \u3002\u867d\u7136 3n+1 \u7684\u5de5\u4f5c\u91cf\u5927\u4e8e n \uff0c\u4f46\u4e8c\u8005\u5728\u8fd0\u884c\u65f6\u90fd\u662f\u7ebf\u6027\u589e\u52a0\uff0c\u6240\u4ee5\u4ed6\u4eec\u8fd0\u884c\u65f6\u90fd\u662f O(n) \u3002 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f 3.2.4.\u7ec3\u4e60\u9898 \u00b6 \u5047\u8bbe\u4e0b\u9762\u7684\u8868\u8fbe\u5f0f\u90fd\u5206\u522b\u8868\u793a\u5bf9\u95ee\u9898\u89c4\u6a21\u4e3a n \u7684\u7b97\u6cd5\u6240\u9700\u8981\u6267\u884c\u7684\u64cd\u4f5c\u6570\uff0c\u8bf7\u6307\u51fa\u6bcf\u79cd\u7b97\u6cd5\u4e2d\u7684\u4e3b\u5bfc\u9879\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u5bf9\u5b83\u8fdb\u884c\u5206\u7c7b\u3002 a. 2^n - 4n + 5n b. 2n^2 + 8 c. n^3 n^2 + n \u89e3\u7b54\uff1a a. 2^n\uff0cO(n) b. n 2\uff0cO(n 2) c. n 3\uff0cO(n 3) \u5bf9\u4e8e\u89c4\u6a21\u4e3a n \u7684\u95ee\u9898\uff0c\u7b97\u6cd5A\u548cB\u5206\u522b\u4f1a\u6267\u884c n^2 \u548c (1/2)*n^2+(1/2)*n \u6761\u6307\u4ee4\u3002\u54ea\u79cd\u7b97\u6cd5\u66f4\u9ad8\u6548\uff1f\u6709\u6ca1\u6709\u4e00\u79cd\u7b97\u6cd5\u6bd4\u53e6\u4e00\u79cd\u7b97\u6cd5\u6027\u80fd\u660e\u663e\u66f4\u597d\u7684\u7279\u5b9a\u7684\u95ee\u9898\u89c4\u6a21\uff1f\u662f\u5426\u6709\u8ba9\u4e24\u79cd\u7b97\u6cd5\u90fd\u6267\u884c\u5927\u81f4\u76f8\u540c\u5de5\u4f5c\u91cf\u7684\u7279\u5b9a\u7684\u95ee\u9898\u89c4\u6a21\uff1f \u89e3\u7b54\uff1a \u5728\u6bd4\u8f83\u4e24\u79cd\u7b97\u6cd5\u7684\u6548\u7387\u65f6\uff0c\u901a\u5e38\u5173\u6ce8\u7b97\u6cd5\u6267\u884c\u65f6\u95f4\u968f\u95ee\u9898\u89c4\u6a21\u589e\u957f\u7684\u8d8b\u52bf\u3002\u9898\u76ee\u4e2d\u7684\u4e24\u79cd\u7b97\u6cd5\u7684\u6267\u884c\u6307\u4ee4\u6570\u5206\u522b\u5982\u4e0b\uff1a \u7b97\u6cd5A\uff1a\u6267\u884c n^2 \u6761\u6307\u4ee4\u3002 \u7b97\u6cd5B\uff1a\u6267\u884c (1/2)*n^2+(1/2)*n \u6761\u6307\u4ee4\u3002 \u7528\u5982\u4e0b\u4ee3\u7801\u6a21\u62df\u7b97\u6cd5A\u548c\u7b97\u6cd5B\uff0c\u53ef\u4ee5\u770b\u51fa\uff0c\u968f\u7740 n \u7684\u589e\u52a0\uff0c\u7b97\u6cd5A\u7684\u589e\u957f\u901f\u7387\u8fdc\u5927\u4e8e\u7b97\u6cd5B\u3002\u6240\u4ee5\u53ef\u4ee5\u8ba4\u4e3a\u5728 n >= 2 \u7684\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5A\u4f18\u4e8e\u7b97\u6cd5B\u3002 n = 1 print ( \" %-15s%25s \" % ( \"ProblemSize: n\" , \"A/B\" )) while n < 1000000 : n *= 10 print ( \" %-15d%25d \" % ( n , int (( n ** 2 ) / ( 1 / 2 ) * n ** 2 + ( 1 / 2 ) * n ))) # ProblemSize: n A/B # 10 20005 # 100 200000050 # 1000 2000000000500 # 10000 20000000000005000 # 100000 200000000000000065536 # 1000000 1999999999999999966445568 \u7531\u6b64\u53ef\u5f97\uff0c\u5728\u5927\u95ee\u9898\u89c4\u6a21\u4e0b\uff0c\u7b97\u6cd5B\u7684\u589e\u957f\u901f\u7387\u4f1a\u66f4\u6162\uff0c\u56e0\u4e3a (1/2)*n^2+(1/2)*n \u4e2d\u7684 (1/2)*n \u90e8\u5206\u5bf9\u4e8e\u6574\u4f53\u589e\u957f\u6765\u8bf4\u76f8\u5bf9\u8f83\u5c0f\u3002 \u4e3a\u4e86\u8ba9\u4e24\u79cd\u7b97\u6cd5\u6267\u884c\u76f8\u8fd1\u7684\u5de5\u4f5c\u91cf\uff0c\u6211\u4eec\u53ef\u4ee5\u89e3\u4e0b\u9762\u7684\u65b9\u7a0b\uff1a ( 1 / 2 ) * n ^ 2 + ( 1 / 2 ) * n = k * n ^ 2 \u5176\u4e2d k \u662f\u4e00\u4e2a\u5e38\u6570\uff0c\u8868\u793a\u4e24\u79cd\u7b97\u6cd5\u6267\u884c\u7684\u5de5\u4f5c\u91cf\u76f8\u7b49\u65f6\u7684\u95ee\u9898\u89c4\u6a21\u3002\u901a\u8fc7\u89e3\u8fd9\u4e2a\u65b9\u7a0b\uff0c\u6211\u4eec\u53ef\u4ee5\u627e\u5230\u4e00\u4e2a\u95ee\u9898\u89c4\u6a21 k \uff0c\u5728\u8fd9\u4e2a\u95ee\u9898\u89c4\u6a21\u4e0b\uff0c\u4e24\u79cd\u7b97\u6cd5\u7684\u6267\u884c\u6307\u4ee4\u6570\u76f8\u8fd1\u3002 \u7b97\u6cd5\u7684\u6548\u7387\u5206\u6790\u5e76\u4e0d\u4ec5\u4ec5\u53d6\u51b3\u4e8e\u6307\u4ee4\u6570\uff0c\u8fd8\u53ef\u80fd\u53d7\u5230\u7b97\u6cd5\u4e2d\u5e38\u6570\u56e0\u5b50\u3001\u6570\u636e\u8bbf\u95ee\u6a21\u5f0f\u3001\u5185\u5b58\u5360\u7528\u7b49\u56e0\u7d20\u7684\u5f71\u54cd\u3002\u56e0\u6b64\uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u901a\u5e38\u9700\u8981\u7efc\u5408\u8003\u8651\u591a\u4e2a\u56e0\u7d20\u6765\u786e\u5b9a\u6700\u4f18\u7684\u7b97\u6cd5\u9009\u62e9\u3002 \u5728\u4ec0\u4e48\u65f6\u5019\u5f00\u59cb n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u8868\u73b0\u66f4\u597d\uff1f \u89e3\u7b54\uff1a\u7528\u4e0b\u9762\u7684\u7b97\u6cd5\u6a21\u62df n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u6267\u884c\u5de5\u4f5c\u91cf\u3002\u4ece\u8fd0\u884c\u7ed3\u679c\u53ef\u4ee5\u770b\u51fa\uff1a n=16 \u662f\u5206\u754c\u70b9\uff0c n^4 \u7b97\u6cd5\u4e0e 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u76f8\u7b49\uff1b \u5f53 n<16 \u65f6\uff0c n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u8981\u9ad8\uff1b \u5f53 n>16 \u65f6\uff0c n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u8981\u4f4e\uff1b\u800c\u4e14 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u589e\u957f\u901f\u5ea6\u8fdc\u5927\u4e8e n^4 \u7b97\u6cd5\uff1b n = 1 print ( \" %-8s%10s%15s%10s \" % ( \"Size:n\" , \"A:n^4\" , \"B:2^n\" , \"B/A\" )) while n < 30 : n += 1 print ( \" %-8d%10d%15d%10.3f \" % ( n , int ( n ** 4 ), int ( 2 ** n ), ( 2 ** n ) / ( n ** 4 ))) # \u8fd0\u884c\u7ed3\u679c\uff1a # Size:n A:n^4 B:2^n B/A # 2 16 4 0.250 # 3 81 8 0.099 # 4 256 16 0.062 # 5 625 32 0.051 # 6 1296 64 0.049 # 7 2401 128 0.053 # 8 4096 256 0.062 # 9 6561 512 0.078 # 10 10000 1024 0.102 # 11 14641 2048 0.140 # 12 20736 4096 0.198 # 13 28561 8192 0.287 # 14 38416 16384 0.426 # 15 50625 32768 0.647 # 16 65536 65536 1.000 # 17 83521 131072 1.569 # 18 104976 262144 2.497 # 19 130321 524288 4.023 # 20 160000 1048576 6.554 # 21 194481 2097152 10.783 # 22 234256 4194304 17.905 # 23 279841 8388608 29.976 # 24 331776 16777216 50.568 # 25 390625 33554432 85.899 # 26 456976 67108864 146.854 # 27 531441 134217728 252.554 # 28 614656 268435456 436.725 # 29 707281 536870912 759.063 # 30 810000 1073741824 1325.607 3.3.\u641c\u7d22\u7b97\u6cd5 \u00b6 \u7ea6\u5b9a\uff1a \u4ee5\u5217\u8868\u4e3a\u4f8b\uff0c\u4ecb\u7ecd\u641c\u7d22\u548c\u6392\u5e8f\u7684\u7b97\u6cd5\uff1b \u9610\u91ca\u8fd9\u4e9b\u7b97\u6cd5\u7684\u8bbe\u8ba1\uff0c\u5e76\u628a\u5b83\u5b9e\u73b0\u4e3aPython\u51fd\u6570\uff1b \u51fd\u6570\u53ea\u5904\u7406\u5168\u90e8\u662f\u6574\u6570\u7684\u5217\u8868\uff0c\u4e0d\u540c\u5927\u5c0f\u7684\u5217\u8868\u5c06\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7ed9\u51fd\u6570\uff1b \u5bf9\u8fd9\u4e9b\u7b97\u6cd5\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u8fdb\u884c\u5206\u6790\uff1b 3.3.1.\u6700\u5c0f\u503c\u641c\u7d22 \u00b6 Python\u4e2d\u6709 min \u51fd\u6570\uff0c\u4f1a\u8fd4\u56de\u5217\u8868\u91cc\u7684\u6700\u5c0f\u503c\u6216\u6700\u5c0f\u5143\u7d20\uff0c\u4e0b\u9762\u5199\u4e00\u4e2a\u65b0\u7b97\u6cd5\uff0c\u6765\u5206\u6790 min \u51fd\u6570\u7684\u7b97\u6cd5\u590d\u6742\u5ea6\u3002 \u7b97\u6cd5\u76ee\u6807\uff1a\u5047\u5b9a\u5217\u8868\u4e0d\u4e3a\u7a7a\uff0c\u5e76\u4e14\u5143\u7d20\u662f\u6309\u7167\u4efb\u610f\u987a\u5e8f\u5b58\u653e\u5728\u5217\u8868\u91cc\u7684\uff0c\u7b97\u6cd5\u8fd4\u56de\u6700\u5c0f\u5143\u7d20\u7684\u7d22\u5f15\uff08index\uff09\u3002 \u7b97\u6cd5\u89e3\u6790\uff1a \u9996\u5148\u628a\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u4f5c\u4e3a\u5b58\u653e\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\uff1b \u7136\u540e\u5411\u53f3\u4fa7\u641c\u7d22\u66f4\u5c0f\u7684\u5143\u7d20\uff1b \u5982\u679c\u627e\u5230\uff0c\u90a3\u4e48\u628a\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\u91cd\u7f6e\u4e3a\u5f53\u524d\u4f4d\u7f6e\uff1b \u5f53\u7b97\u6cd5\u5230\u8fbe\u5217\u8868\u672b\u5c3e\u65f6\uff0c\u5b83\u5c06\u8fd4\u56de\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\u3002 \u7b97\u6cd5\u5b9e\u73b0\uff1a def indexOfMin ( lyst ): \"\"\"\u8fd4\u56de\u6700\u5c0f\u5143\u7d20\u7684\u7d22\u5f15\uff0c\u76f8\u540c\u6700\u5c0f\u5143\u7d20\u8fd4\u56de\u7b2c\u4e00\u4e2a\u7d22\u5f15\"\"\" # \u7b97\u6cd5\u5f00\u59cb minIndex = 0 currentIndex = 1 while currentIndex < len ( lyst ): if lyst [ currentIndex ] < lyst [ minIndex ]: # \u6539\u6210<=\uff0c\u76f8\u540c\u6700\u5c0f\u5143\u7d20\u5219\u8fd4\u56de\u6700\u540e\u4e00\u4e2a\u7d22\u5f15 minIndex = currentIndex currentIndex += 1 return minIndex # \u7b97\u6cd5\u7ed3\u675f def main (): myList = [ 2 , 20 , 5 , 0 , 1 , 0 , 9 ] minIndex = indexOfMin ( myList ) print ( minIndex , myList [ minIndex ]) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # 3 0 # \u5982\u679c\u6539\u6210\u6539\u6210yst[currentIndex] <= lyst[minIndex]\uff0c\u5219\u76f8\u540c\u6700\u5c0f\u5143\u7d20\u5219\u8fd4\u56de\u6700\u540e\u4e00\u4e2a\u7d22\u5f15 # 5 0 \u65e0\u8bba\u5217\u8868\u7684\u5927\u5c0f\u5982\u4f55\uff0c\u5faa\u73af\u5916\u76843\u6761\u6307\u4ee4\uff082\u6761\u8d4b\u503c\u8bed\u53e5\uff0c\u4e00\u6761while\u8bed\u53e5\u672c\u8eab\uff09\u90fd\u4f1a\u6267\u884c\u76f8\u540c\u7684\u6b21\u6570\uff0c\u53ef\u4ee5\u5ffd\u7565\u5b83\u4eec\u90fd\u5f71\u54cd\u3002 \u5faa\u73af\u91cc\u8fd8\u67093\u6761\u6307\u4ee4\uff0c\u5176\u4e2d if \u8bed\u53e5\u5185\u7684\u6bd4\u8f83 lyst[currentIndex] < lyst[minIndex] \u548c currentIndex += 1 \u7684\u81ea\u589e\uff0c\u4f1a\u5728\u6bcf\u6b21\u5faa\u73af\u65f6\u90fd\u6267\u884c\uff0c\u4e14\u6ca1\u6709\u5176\u5b83\u5d4c\u5957\u6216\u9690\u85cf\u7684\u5faa\u73af\u3002 if \u8bed\u53e5\u4e2d\u7684\u6bd4\u8f83\u64cd\u4f5c\u5b9e\u73b0\u4e86\u8bbf\u95ee\u5217\u8868\u91cc\u7684\u6bcf\u4e2a\u5143\u7d20\uff0c\u4ece\u800c\u80fd\u591f\u627e\u5230\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\u3002 \u56e0\u6b64\uff0c\u8fd9\u4e2a\u7b97\u6cd5\u5fc5\u987b\u5bf9\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\u8fdb\u884c n-1 \u6b21\u6bd4\u8f83\uff0c\u5373\uff0c\u5b83\u7684\u590d\u6742\u5ea6\u4e3aO(n)\u3002 3.3.2.\u987a\u5e8f\u641c\u7d22\u5217\u8868 \u00b6 Python\u7684 in \u8fd0\u7b97\u7b26\u5728list\u7c7b\u91cc\u88ab\u5b9e\u73b0\u4e3a\u53eb\u4f5c __contains__ \u7684\u65b9\u6cd5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u5728\u4efb\u610f\u7684\u5143\u7d20\u5217\u8868\u91cc\u641c\u7d22\u7279\u5b9a\u7684\u5143\u7d20\uff0c\u5373\u76ee\u6807\u5143\u7d20\uff08target item\uff09\u3002 \u5728\u5217\u8868\u91cc\uff0c\u627e\u5230\u76ee\u6807\u5143\u7d20\u7684\u552f\u4e00\u65b9\u6cd5\u662f\u4ece\u4f4d\u4e8e\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u5f00\u59cb\uff0c\u5e76\u628a\u5b83\u548c\u76ee\u6807\u5143\u7d20\u8fdb\u884c\u6bd4\u8f83\u3002\u5982\u679c\u4e24\u4e2a\u5143\u7d20\u76f8\u7b49\uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u8fd4\u56de True \uff1b\u5426\u5219\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u5c06\u79fb\u52a8\u5230\u4e0b\u4e00\u4e2a\u4f4d\u7f6e\uff0c\u5e76\u628a\u5b83\u548c\u76ee\u6807\u5143\u7d20\u8fdb\u884c\u6bd4\u8f83\u3002\u5982\u679c\u8fd9\u4e2a\u65b9\u6cd5\u5230\u4e86\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u4ecd\u7136\u627e\u4e0d\u5230\u76ee\u6807\uff0c\u90a3\u4e48\u8fd4\u56de False \u3002\u8fd9\u79cd\u641c\u7d22\u79f0\u4e3a\u987a\u5e8f\u641c\u7d22\uff08sequential search\uff09\u6216\u7ebf\u6027\u641c\u7d22\uff08linear search\uff09\u3002 \u4e0b\u9762\u662f\u987a\u5e8f\u641c\u7d22\u51fd\u6570\u7684\u5b9e\u73b0\u3002\u82e5\u987a\u5e8f\u641c\u7d22\u7b97\u6cd5\u5728\u5217\u8868\u5f00\u5934\u5c31\u627e\u5230\u76ee\u6807\u5143\u7d20\uff0c\u90a3\u4e48\u8fd9\u65f6\u7684\u5de5\u4f5c\u91cf\u660e\u663e\u4f1a\u6bd4\u5728\u5217\u8868\u672b\u5c3e\u627e\u5230\u7684\u5de5\u4f5c\u91cf\u8981\u5c11\u3002 def sequentialSearch ( target , lyst ): \"\"\"\u627e\u5230\u76ee\u6807\u5143\u7d20\u65f6\u8fd4\u56de\u5143\u7d20\u7684\u7d22\u5f15, \u5426\u5219\u8fd4\u56de-1\"\"\" position = 0 while position < len ( lyst ): if target == lyst [ position ]: return position position += 1 return - 1 def main (): myList = [ 2 , 20 , 5 , 0 , 1 , 0 , 9 ] locatedIndex = sequentialSearch ( 9 , myList ) print ( locatedIndex , myList [ locatedIndex ]) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # 6 9 3.3.3.\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd \u00b6 \u4e00\u822c\u6765\u8bf4\uff0c\u91cd\u70b9\u5173\u6ce8\u5728\u5e73\u5747\u60c5\u51b5\u548c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\uff0c\u4e0d\u4f1a\u7279\u522b\u5173\u6ce8\u6700\u597d\u60c5\u51b5\u3002 \u5bf9\u987a\u5e8f\u641c\u7d22\u7684\u5206\u6790\u9700\u8981\u8003\u8651\u4e0b\u97623\u79cd\u60c5\u51b5\u3002 \u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u76ee\u6807\u5143\u7d20\u4f4d\u4e8e\u5217\u8868\u7684\u672b\u5c3e\u6216\u8005\u6839\u672c\u5c31\u4e0d\u5728\u5217\u8868\u91cc\u3002\u8fd9\u65f6\uff0c\u8fd9\u4e2a\u7b97\u6cd5\u5c31\u5fc5\u987b\u8bbf\u95ee\u6bcf\u4e00\u4e2a\u5143\u7d20\uff0c\u5bf9\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\u9700\u8981\u6267\u884c n \u6b21\u8fed\u4ee3\u3002\u56e0\u6b64\uff0c\u987a\u5e8f\u641c\u7d22\u7684\u6700\u574f\u60c5\u51b5\u7684\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u53ea\u9700\u8981O(1)\u7684\u590d\u6742\u5ea6\uff0c\u56e0\u4e3a\u8fd9\u4e2a\u7b97\u6cd5\u5728\u4e00\u6b21\u8fed\u4ee3\u4e4b\u540e\u5c31\u4f1a\u5728\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u627e\u5230\u76ee\u6807\u5143\u7d20\u3002 \u8981\u786e\u5b9a\u5e73\u5747\u60c5\u51b5\uff0c\u5c31\u9700\u8981\u628a\u6bcf\u4e2a\u53ef\u80fd\u4f4d\u7f6e\u627e\u5230\u76ee\u6807\u6240\u9700\u8981\u7684\u8fed\u4ee3\u6b21\u6570\u76f8\u52a0\uff0c\u7136\u540e\u518d\u5c06\u5b83\u4eec\u7684\u603b\u548c\u9664\u4ee5 n \u3002\u56e0\u6b64\uff0c\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u4f1a\u6267\u884c (n + n\u22121 + n\u22122+ ... +1)/n \u6216 (n+1)/2 \u6b21\u8fed\u4ee3\u3002\u5bf9\u4e8e\u975e\u5e38\u5927\u7684 n \u6765\u8bf4\uff0c\u5e38\u6570\u7cfb\u65702\u662f\u53ef\u4ee5\u5ffd\u7565\u7684\uff0c\u56e0\u6b64\uff0c\u5e73\u5747\u60c5\u51b5\u7684\u590d\u6742\u5ea6\u4ecd\u7136\u662fO(2)\u3002 \u7ed3\u8bba\uff1a\u6700\u597d\u60c5\u51b5\u4e0b\u987a\u5e8f\u641c\u7d22\u7684\u6027\u80fd\u548c\u5176\u4ed6\u4e24\u79cd\u60c5\u51b5\u6bd4\u8d77\u6765\u5c0f\u5f88\u591a\uff0c\u800c\u5176\u4ed6\u4e24\u79cd\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u662f\u5dee\u4e0d\u591a\u7684\u3002 3.3.4.\u57fa\u4e8e\u6709\u5e8f\u5217\u8868\u7684\u4e8c\u5206\u641c\u7d22 \u00b6 \u5728\u6570\u636e\u65e0\u5e8f\u7684\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528\u987a\u5e8f\u641c\u7d22\u6765\u627e\u5230\u76ee\u6807\u5143\u7d20\u3002 \u5728\u6570\u636e\u6709\u5e8f\u7684\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528\u4e8c\u5206\u641c\u7d22\u6765\u627e\u5230\u76ee\u6807\u5143\u7d20\u3002 Python\u4e2d\u5b9e\u73b0\u4e8c\u5206\u641c\u7d22\u7684\u601d\u8def\uff1a \u5047\u8bbe\u5217\u8868\u91cc\u7684\u5143\u7d20\u90fd\u4ee5\u5347\u5e8f\u6392\u5e8f\u3002 \u641c\u7d22\u7b97\u6cd5\u9996\u5148\u5230\u5217\u8868\u7684\u4e2d\u95f4\u4f4d\u7f6e\uff0c\u5e76\u628a\u8fd9\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u4e0e\u76ee\u6807\u5143\u7d20\u8fdb\u884c\u6bd4\u8f83\uff1b \u5982\u679c\u5339\u914d\uff0c\u90a3\u4e48\u7b97\u6cd5\u5c31\u8fd4\u56de\u5f53\u524d\u4f4d\u7f6e\u3002\u5982\u679c\u76ee\u6807\u5143\u7d20\u5c0f\u4e8e\u5f53\u524d\u5143\u7d20\uff0c\u90a3\u4e48\u7b97\u6cd5\u5c06\u4f1a\u641c\u7d22\u4e2d\u95f4\u4f4d\u7f6e\u4e4b\u524d\u7684\u90e8\u5206\uff1b \u5982\u679c\u76ee\u6807\u5143\u7d20\u5927\u4e8e\u5f53\u524d\u5143\u7d20\uff0c\u5219\u641c\u7d22\u4e2d\u95f4\u4f4d\u7f6e\u4e4b\u540e\u7684\u90e8\u5206\u3002 \u5728\u627e\u5230\u4e86\u76ee\u6807\u5143\u7d20\u6216\u8005\u5f53\u524d\u5f00\u59cb\u4f4d\u7f6e\u5927\u4e8e\u5f53\u524d\u7ed3\u675f\u4f4d\u7f6e\u65f6\uff0c\u505c\u6b62\u641c\u7d22\u8fc7\u7a0b\u3002 \u4e0b\u9762\u662f\u4e8c\u5206\u641c\u7d22\u51fd\u6570\u7684\u4ee3\u7801\u3002\u4ee5\u5217\u8868 [2, 20, 5, 0, 1, 0, 9] \u4e3a\u4f8b\uff1a \u6392\u5e8f\u540e\u7684\u5217\u8868\u4e3a [0, 0, 1, 2, 5, 9, 20] \uff1b \u6392\u5e8f\u540e\u5217\u8868\u957f\u5ea6\u662f7\uff0c\u6240\u4ee5\u521d\u59cbmidpoint=3\uff0c\u5bf9\u5e94\u5217\u8868\u503c\u662f2\uff1b def binarySearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 while left <= right : midpoint = ( left + right ) // 2 if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 return - 1 def main (): myList = [ 2 , 20 , 5 , 0 , 1 , 0 , 9 ] sortedList = sorted ( myList ) # \u5982\u679c\u4f7f\u7528myList.sort()\uff0c\u5219\u4f1a\u4fee\u6539myList\u672c\u8eab locatedIndex = binarySearch ( 5 , sortedList ) print ( sortedList ) print ( locatedIndex , sortedList [ locatedIndex ]) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # [0, 0, 1, 2, 5, 9, 20] # 4 5 # \u5982\u679c\u6267\u884cbinarySearch(0, sortedList)\uff0c\u5219\u4f1a\u8fd4\u56de\u7b2c\u4e8c\u4e2a0\u7684\u7d22\u5f15 # [0, 0, 1, 2, 5, 9, 20] # 1 0 \u4e0a\u9762\u4e8c\u5206\u6cd5\u7b97\u6cd5\u590d\u6742\u5ea6\u5206\u6790\uff1a \u7b97\u6cd5\u91cc\u53ea\u6709\u4e00\u4e2a\u5faa\u73af\uff0c\u5e76\u4e14\u6ca1\u6709\u5d4c\u5957\u6216\u9690\u85cf\u7684\u5faa\u73af\u3002\u5982\u679c\u76ee\u6807\u4e0d\u5728\u5217\u8868\u91cc\uff0c\u5c31\u4f1a\u5f97\u5230\u6700\u574f\u60c5\u51b5\uff0c\u5373\u904d\u5386\u5217\u8868\u7684\u4e00\u534a\uff0c\u5373\u5faa\u73af\u5217\u8868\u5927\u5c0f\u4e0d\u65ad\u9664\u4ee52\u76f4\u81f3\u5546\u4e3a1\u7684\u6b21\u6570\u3002 \u5bf9\u4e8e\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\u6765\u8bf4\uff0c\u4e5f\u5c31\u662f\u4f60\u9700\u8981\u6267\u884c n/2/2/.../2 \u6b21\uff0c\u76f4\u5230\u7ed3\u679c\u4e3a1\u3002\u5047\u8bbe k \u662f n \u53ef\u4ee5\u9664\u4ee52\u7684\u6b21\u6570\uff0c\u90a3\u4e48\u6c42\u89e3 k \u4f1a\u6709 n/(2^k)=1 \uff0c\u5373 n=2^k \uff0c\u5373 k=log(n,2) \u3002\u56e0\u6b64\uff0c\u4e8c\u5206\u641c\u7d22\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u590d\u6742\u5ea6\u4e3aO(log(n,2))\u3002 3.3.5.\u6bd4\u8f83\u6570\u636e\u5143\u7d20 \u00b6 \u4e8c\u5206\u641c\u7d22\u548c\u6700\u5c0f\u503c\u641c\u7d22\u90fd\u6709\u4e00\u4e2a\u5047\u8bbe\uff0c\u90a3\u5c31\u662f\u201c\u5217\u8868\u91cc\u7684\u5143\u7d20\u5f7c\u6b64\u4e4b\u95f4\u662f\u53ef\u4ee5\u6bd4\u8f83\u7684\u201d\u3002\u5373\uff0c\u8fd9\u4e9b\u5143\u7d20\u5c5e\u4e8e\u540c\u4e00\u4e2a\u7c7b\u578b\uff0c\u5373\uff0c\u53ef\u4ee5\u4f7f\u7528\u6bd4\u8f83\u8fd0\u7b97\u7b26 == \u3001 < \u548c > \u3002 Python\u5185\u7f6e\u7684\u7c7b\u578b\u5bf9\u8c61\uff0c\u5982\u6570\u5b57\u3001\u5b57\u7b26\u4e32\u548c\u5217\u8868\uff0c\u90fd\u652f\u6301\u6bd4\u8f83\u8fd0\u7b97\u7b26\u3002 \u4e3a\u4e86\u80fd\u591f\u8ba9\u7b97\u6cd5\u5bf9\u65b0\u7684\u7c7b\u5bf9\u8c61\u4f7f\u7528\u6bd4\u8f83\u8fd0\u7b97\u7b26 == \u3001 < \u548c > \uff0c\u5e94\u8be5\u5728\u8fd9\u4e2a\u7c7b\u91cc\u5b9a\u4e49 __eq__ \u3001 __lt__ \u548c __gt__ \u65b9\u6cd5\u3002\u5728\u5b9a\u4e49\u4e86\u8fd9\u4e9b\u65b9\u6cd5\u4e4b\u540e\uff0c\u5176\u4ed6\u6bd4\u8f83\u8fd0\u7b97\u7b26\u7684\u65b9\u6cd5\u5c06\u81ea\u52a8\u751f\u6210\u3002 \u4f8b\u5982\uff0c __lt__ \u7684\u5b9a\u4e49\u5982\u4e0b\uff0c\u5982\u679c self \u5c0f\u4e8e other \uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u5c06\u8fd4\u56de True \uff1b\u5426\u5219\uff0c\u8fd4\u56de False \u3002 __lt__ \u65b9\u6cd5\u4f1a\u4e3a\u4e24\u4e2a\u8d26\u6237\u5bf9\u8c61\u7684 name \u5b57\u6bb5\u8c03\u7528\u8fd0\u7b97\u7b26 < \u3002 \u540d\u79f0\u5b57\u6bb5\u662f\u5b57\u7b26\u4e32\uff0c\u5b57\u7b26\u4e32\u7c7b\u578b\u5df2\u7ecf\u5305\u542b\u5728 __lt__ \u65b9\u6cd5\u91cc\u3002 \u5728\u4f7f\u7528\u8fd0\u7b97\u7b26 < \u65f6\uff0cPython\u4f1a\u81ea\u52a8\u8fd0\u884c\u5b57\u7b26\u4e32\u7684 __lt__ \u65b9\u6cd5\uff0c\u8fd9\u4e0e\u8c03\u7528 str \u51fd\u6570\u65f6\u81ea\u52a8\u8fd0\u884c __str__ \u65b9\u6cd5\u662f\u7c7b\u4f3c\u7684\u3002 def __lt__ ( self , other ): \u793a\u4f8b\uff1a\u8fd4\u56de\u50a8\u84c4\u8d26\u6237\u7684\u6240\u6709\u4eba\u540d\u5b57\u3001PIN\u7801\u3001\u4f59\u989d\u3002 class SavingsAccount ( object ): \"\"\"\u8fd4\u56de\u50a8\u84c4\u8d26\u6237\u7684\u6240\u6709\u4eba\u540d\u5b57\u3001PIN\u7801\u3001\u4f59\u989d\"\"\" def __init__ ( self , name , pin , balance = 0.0 ): self . name = name self . pin = pin self . balance = balance def __lt__ ( self , other ): return self . name < other . name # Other methods, including __eq__ def main (): s1 = SavingsAccount ( \"Ken\" , \"1001\" , 0 ) s2 = SavingsAccount ( \"Bill\" , \"1001\" , 30 ) s3 = SavingsAccount ( \"Ken\" , \"1000\" , 0 ) s4 = s1 print ( \"s1 < s2: \" , s1 < s2 ) print ( \"s2 < s1: \" , s2 < s1 ) print ( \"s2 > s1: \" , s2 > s1 ) print ( \"s2 == s1: \" , s2 == s1 ) print ( \"s1 == s3: \" , s1 == s3 ) print ( \"s1 == s4: \" , s1 == s4 ) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # s1 < s2: False # s2 < s1: True # s2 > s1: False # s2 == s1: False # s1 == s3: False # s1 == s4: True \u63d0\u793a\uff1a\u5728Python\u4e2d\uff0c\u9ed8\u8ba4\u662f\u6309\u7167ASCII\u7684\u5927\u5c0f\u6bd4\u8f83\u5b57\u7b26\u4e32\u7684\uff0c\u5373\u4ece\u5b57\u7b26\u4e32\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\u8fdb\u884c\u6bd4\u8f83\uff0c\u5982\u679c\u76f8\u7b49\uff0c\u5219\u7ee7\u7eed\u6bd4\u8f83\u4e0b\u4e00\u4e2a\u5b57\u7b26\uff0c\u76f4\u5230\u5206\u51fa\u5927\u5c0f\uff0c\u6216\u8005\u8fd8\u6ca1\u5206\u51fa\u5927\u5c0f\uff0c\u6709\u4e00\u4e2a\u5b57\u7b26\u4e32\u5df2\u7ecf\u5230\u5934\u4e86\uff0c\u90a3\u4e48\u8f83\u957f\u7684\u90a3\u4e00\u4e2a\u5b57\u7b26\u4e32\u5927\u3002 3.3.6.\u7ec3\u4e60\u9898 \u00b6 \u5047\u8bbe\u4e00\u4e2a\u5217\u8868\u5728\u7d22\u5f150\uff5e9\u7684\u4f4d\u7f6e\u5904\u5305\u542b\u503c20\u300144\u300148\u300155\u300162\u300166\u300174\u300188\u300193\u300199\uff0c\u8bf7\u5728\u7528\u4e8c\u5206\u641c\u7d22\u67e5\u627e\u76ee\u6807\u5143\u7d2090\u7684\u65f6\u5019\uff0c\u5bf9\u53d8\u91cfleft\u3001right\u548cmidpoint\u7684\u503c\u8fdb\u884c\u8ddf\u8e2a\u3002\u6539\u53d8\u76ee\u6807\u5143\u7d20\u4e3a44\uff0c\u5e76\u91cd\u590d\u8fd9\u4e2a\u6b65\u9aa4\u3002 \u89e3\u7b54\uff1a \u4e0b\u9762\u662f\u4ee3\u7801\u548c\u8ddf\u8e2a\u7ed3\u679c\u3002 def binarySearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 print ( \" %5s%10s%10s \" % ( \"left\" , \"midpoint\" , \"right\" )) while left <= right : midpoint = ( left + right ) // 2 print ( \" %5s%10s%10s \" % ( left , midpoint , right )) if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 return - 1 def main (): myList = [ 20 , 44 , 48 , 55 , 62 , 66 , 74 , 88 , 93 , 99 ] sortedList = sorted ( myList ) locatedIndex = binarySearch ( 44 , sortedList ) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # Target = 90 # left midpoint right # 0 4 9 # 5 7 9 # 8 8 9 # # Target = 44 # left midpoint right # 0 4 9 # 0 1 3 \u901a\u5e38\u6765\u8bf4\uff0c\u67e5\u627e\u7535\u8bdd\u7c3f\u4e2d\u6761\u76ee\u7684\u65b9\u6cd5\u4e0e\u4e8c\u5206\u641c\u7d22\u5e76\u4e0d\u5b8c\u5168\u76f8\u540c\uff0c\u56e0\u4e3a\u4f7f\u7528\u7535\u8bdd\u7c3f\u7684\u65f6\u5019\uff0c\u5e76\u4e0d\u4f1a\u6bcf\u6b21\u90fd\u7ffb\u5230\u88ab\u641c\u7d22\u7684\u5b50\u5217\u8868\u7684\u4e2d\u70b9\u3002\u4e00\u822c\u6765\u8bf4\uff0c\u53ef\u4ee5\u6839\u636e\u8fd9\u4e2a\u4eba\u7684\u59d3\u6c0f\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd\u987a\u5e8f\u6765\u4f30\u7b97\u76ee\u6807\u53ef\u80fd\u4f1a\u5728\u7684\u4f4d\u7f6e\u3002\u4f8b\u5982\uff0c\u5f53\u67e5\u627e\u201cSmith\u201d\u7684\u7535\u8bdd\u65f6\uff0c\u4f60\u4f1a\u9996\u5148\u67e5\u770b\u7535\u8bdd\u7c3f\u4e0b\u534a\u90e8\u5206\u7684\u4e2d\u95f4\uff0c\u800c\u4e0d\u662f\u6574\u4e2a\u7535\u8bdd\u7c3f\u7684\u4e2d\u95f4\u3002\u8bf7\u5bf9\u4e8c\u5206\u641c\u7d22\u7b97\u6cd5\u5c1d\u8bd5\u8fdb\u884c\u4fee\u6539\uff0c\u4ece\u800c\u53ef\u4ee5\u5728\u5904\u7406\u540d\u79f0\u5217\u8868\u7684\u65f6\u5019\u6a21\u62df\u8fd9\u4e2a\u7b56\u7565\u3002\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u4e0e\u6807\u51c6\u7684\u4e8c\u5206\u641c\u7d22\u76f8\u6bd4\u8f83\u4f1a\u66f4\u597d\u5417\uff1f \u89e3\u7b54\uff1a\u4e0b\u9762\u662f\u4ee3\u7801\u548c\u8ffd\u8e2a\u7ed3\u679c\u3002\u901a\u8fc7\u5bf9\u6bd4\u4e0d\u540c\u6743\u91cd\u5355\u8bcd\u5230\u7684\u641c\u7d22\uff0c\u53ef\u4ee5\u53d1\u73b0\u6743\u91cd\u4e8c\u5206\u6cd5\u7684\u6548\u7387\u82e5\u8981\u4f18\u4e8e\u4f20\u7edf\u4e8c\u5206\u6cd5\uff0c\u662f\u9700\u8981\u6ee1\u8db3\u4e00\u5b9a\u7684\u6761\u4ef6\u7684\u3002 \u5728\u641c\u7d22\u7684\u7b2c\u4e00\u8f6e\u4e2d\uff0c\u4e2d\u95f4\u4f4d\u7f6e\u5c06\u53d6\u51b3\u4e8e\u5217\u8868\u7684\u5927\u5c0f\u548c\u76ee\u6807\u540d\u5b57\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd\u7684\u987a\u5e8f\u503c\u3002\u56e0\u6b64\uff0c\u7b2c\u4e00\u8f6e\u641c\u7d22\u5c06\u6d88\u9664\u6bd4\u4ee5\u524d\u66f4\u591a\u7684\u5143\u7d20\uff0c\u5e76\u4e14\u5982\u679c\u9700\u8981\u5176\u4ed6\u8f6e\u641c\u7d22\uff0c\u5b83\u4eec\u7684\u641c\u7d22\u7a7a\u95f4\u4e5f\u4f1a\u66f4\u5c0f\u3002\u7136\u800c\uff0c\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u4fee\u6539\u540e\u7684\u7b97\u6cd5\u4ecd\u7136\u6bd4O(1)\u66f4\u63a5\u8fd1O(log n)\u3002 def binarySearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 print ( \" %5s%10s%10s \" % ( \"left\" , \"midpoint\" , \"right\" )) while left <= right : midpoint = ( left + right ) // 2 print ( \" %5s%10s%10s \" % ( left , midpoint , right )) if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 return - 1 def letter_position ( myLetter ): letter = myLetter . lower () # \u8f6c\u6210\u5c0f\u5199\u5b57\u6bcd alphabet = \"abcdefghijklmnopqrstuvwxyz\" if letter in alphabet : return alphabet . index ( letter ) + 1 # \u4f4d\u7f6e\u63091\uff5e26\u8ba1\u7b97 else : return None # \u975e\u5b57\u6bcd def dictSearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 # \u9996\u5b57\u6bcd\u5728\u5b57\u6bcd\u8868\u4e2d\u7684\u767e\u5206\u4f4d letter_position_range = letter_position ( target [ 0 ]) * 100 // 26 # \u6309\u7167\u6240\u5f97\u7684\u9996\u5b57\u6bcd\u5728\u5b57\u6bcd\u8868\u4e2d\u7684\u767e\u5206\u4f4d\uff0c\u4f5c\u4e3a\u7ed9\u5b9a\u5b57\u4e32\u4e2d\u8bbe\u5b9a\u641c\u7d22\u8d77\u59cb\u767e\u5206\u4f4d midpoint = letter_position_range * ( len ( sortedLyst ) - 1 ) // 100 print ( \" %5s%10s%10s \" % ( \"left\" , \"midpoint\" , \"right\" )) while left <= right : print ( \" %5s%10s%10s \" % ( left , midpoint , right )) if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 midpoint = ( left + right ) // 2 return - 1 def main (): myList = [ \"Bob\" , \"Charlie\" , \"Eva\" , \"Alice\" , \"Grace\" , \"David\" , \"Smith\" , \"Frank\" , \"Zoe\" , \"Jack\" ] sortedList = sorted ( myList ) print ( sortedList ) print ( \"=====call binarySearch=====\" ) locatedIndex = binarySearch ( \"Alice\" , sortedList ) print ( \"Found\" , sortedList [ locatedIndex ], \"in position\" , locatedIndex ) print ( \"=====call dictSearch=====\" ) locatedIndex = dictSearch ( \"Alice\" , sortedList ) print ( \"Found\" , sortedList [ locatedIndex ], \"in position\" , locatedIndex ) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # \u641c\u7d22Alice # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 0 1 3 # 0 0 0 # Found Alice in position 0 # =====call dictSearch===== # left midpoint right # 0 0 9 # Found Alice in position 0 # \u641c\u7d22Bob # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 0 1 3 # Found Bob in position 1 # =====call dictSearch===== # left midpoint right # 0 0 9 # 1 5 9 # 1 2 4 # 1 1 1 # Found Bob in position 1 # \u641c\u7d22Smith # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 5 7 9 # 8 8 9 # Found Smith in position 8 # =====call dictSearch===== # left midpoint right # 0 6 9 # 7 8 9 # Found Smith in position 8 # \u641c\u7d22Zoe # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 5 7 9 # 8 8 9 # 9 9 9 # Found Zoe in position 9 # =====call dictSearch===== # left midpoint right # 0 9 9 # Found Zoe in position 9 3.4.\u57fa\u672c\u7684\u6392\u5e8f\u7b97\u6cd5 \u00b6 \u4e0b\u9762\u662fswap\u51fd\u6570\u7684\u4f8b\u5b50\uff0c\u5b9e\u73b0\u4e86\uff1a \u5047\u8bbe\u90fd\u5728\u6574\u6570\u5217\u8868\u4e0a\u8fd0\u884c\uff1b \u4ea4\u6362\u5217\u8868\u4e2d\u4e24\u4e2a\u5143\u7d20\u7684\u4f4d\u7f6e\uff1b def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( myList ) swap ( myList , 3 , 5 ) print ( myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # [9, 4, 2, 7, 6, 8, 1] # [9, 4, 2, 8, 6, 7, 1] 3.4.1.\u9009\u62e9\u6392\u5e8f \u00b6 \u9009\u62e9\u6392\u5e8f\uff08selection sort\uff09\uff1a\uff08\u4ee5\u5217\u8868\u4e3a\u4f8b\uff09 \u5728\u4e00\u4e2a\u957f\u5ea6\u4e3a N \u7684\u65e0\u5e8f\u5217\u8868\u4e2d\uff0c\u7b2c\u4e00\u6b21\u904d\u5386 n-1 \u4e2a\u6570\u627e\u5230\u6700\u5c0f\u7684\u548c\u7b2c\u4e00\u4e2a\u6570\u4ea4\u6362\u3002 \u7b2c\u4e8c\u6b21\u4ece\u4e0b\u4e00\u4e2a\u6570\u5f00\u59cb\u904d\u5386 n-2 \u4e2a\u6570\uff0c\u627e\u5230\u6700\u5c0f\u7684\u6570\u548c\u7b2c\u4e8c\u4e2a\u6570\u4ea4\u6362\u3002 \u91cd\u590d\u4ee5\u4e0a\u64cd\u4f5c\u76f4\u5230\u7b2c n-1 \u6b21\u904d\u5386\u6700\u5c0f\u7684\u6570\u548c\u7b2c n-1 \u4e2a\u6570\u4ea4\u6362\uff0c\u6392\u5e8f\u5b8c\u6210\u3002 \u8fd9\u4e2a\u7b97\u6cd5\u5728\u6bcf\u6b21\u901a\u8fc7\u4e3b\u5faa\u73af\u65f6\uff0c\u90fd\u4f1a\u9009\u62e9\u8981\u79fb\u52a8\u7684\u90a3\u4e00\u4e2a\u5143\u7d20\u3002 \u7b97\u6cd5\u590d\u6742\u5ea6\uff1a \u7b2c1\u6b21\u6267\u884c\u5916\u90e8\u5faa\u73af\u65f6\uff0c\u5185\u90e8\u5faa\u73af\u4f1a\u6267\u884cn-1\u6b21\uff1b \u7b2c2\u6b21\u6267\u884c\u5916\u90e8\u5faa\u73af\u65f6\uff0c\u5185\u90e8\u5faa\u73af\u4f1a\u6267\u884cn-2\u6b21\uff1b \u6700\u540e\u4e00\u6b21\u6267\u884c\u5916\u90e8\u5faa\u73af\u65f6\uff0c\u5185\u90e8\u5faa\u73af\u4f1a\u6267\u884c1\u6b21\uff1b \u6240\u4ee5\uff0c\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\uff0c\u4e00\u5171\u9700\u8981\u7684\u6bd4\u8f83\u6b21\u6570\u662f (n-1)+(n-2)+...+1 \uff0c\u5316\u7b80\u4e3a n*(n-1)/2 \uff0c\u5373 (1/2)*n^2+(1/2)*n \u3002\u5f53 n \u6bd4\u8f83\u5927\u65f6\uff0c\u53ef\u4ee5\u9009\u62e9\u6700\u9ad8\u6b21\u7684\u9879\u5e76\u5ffd\u7565\u7cfb\u6570\uff0c\u56e0\u6b64\u5728\u6240\u6709\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u7684\u590d\u6742\u5ea6\u90fd\u662fO(n^2)\u3002 \u5bf9\u4e8e\u5927\u578b\u6570\u636e\u96c6\u6765\u8bf4\uff0c\u4ea4\u6362\u5143\u7d20\u7684\u6210\u672c\u53ef\u80fd\u4f1a\u5f88\u9ad8\u3002\u56e0\u4e3a\u8fd9\u4e2a\u7b97\u6cd5\u53ea\u4f1a\u5728\u5916\u90e8\u5faa\u73af\u91cc\u5bf9\u6570\u636e\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\uff0c\u6240\u4ee5\u5728\u6700\u574f\u60c5\u51b5\u548c\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u7684\u989d\u5916\u6210\u672c\u662f\u7ebf\u6027\u7684\u3002 \u7b97\u6cd5\u4ee3\u7801\uff1a def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 minIndex = i # \u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , minIndex , i ) i += 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] 3.4.2.\u5192\u6ce1\u6392\u5e8f \u00b6 \u5192\u6ce1\u6392\u5e8f\uff08Bubble Sort\uff09\uff1a \u6bd4\u8f83\u76f8\u90bb\u4e24\u4e2a\u6570\u636e\u5982\u679c\u3002\u7b2c\u4e00\u4e2a\u6bd4\u7b2c\u4e8c\u4e2a\u5927\uff0c\u5c31\u4ea4\u6362\u4e24\u4e2a\u6570\uff1b \u5bf9\u6bcf\u4e00\u4e2a\u76f8\u90bb\u7684\u6570\u505a\u540c\u68371\u7684\u5de5\u4f5c\uff0c\u8fd9\u6837\u4ece\u5f00\u59cb\u4e00\u961f\u5230\u7ed3\u5c3e\u4e00\u961f\u5728\u6700\u540e\u7684\u6570\u5c31\u662f\u6700\u5927\u7684\u6570\u3002 \u9488\u5bf9\u6240\u6709\u5143\u7d20\u4e0a\u9762\u7684\u64cd\u4f5c\uff0c\u9664\u4e86\u6700\u540e\u4e00\u4e2a\u3002 \u91cd\u590d1~3\u6b65\u9aa4\uff0c\u76f4\u81f3\u5b8c\u6210\u3002 \u7b97\u6cd5\u590d\u6742\u5ea6\uff1a \u5192\u6ce1\u6392\u5e8f\u53ea\u4f1a\u6539\u5584\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u590d\u6742\u5ea6\u3002\u5bf9\u4e8e\u5e73\u5747\u60c5\u51b5\u800c\u8a00\uff0c\u7531\u4e8e\u4f9d\u7136\u662f\u53cc\u91cd\u5faa\u73af\u65f6\u95f4\uff0c\u6240\u4ee5\u590d\u6742\u5ea6\u662fO(n^2)\uff1b \u5bf9\u4e8e\u6709\u5e8f\u7684\u5217\u8868\u6765\u8bf4\uff0c\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u4f1a\u6bd4\u9009\u62e9\u6392\u5e8f\u7684\u6267\u884c\u6548\u7387\u66f4\u9ad8\u3002 \u7b97\u6cd5\u4ee3\u7801\uff1a def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 minIndex = i # \u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , minIndex , i ) i += 1 def bubbleSortWithTweak ( lyst ): \"\"\"\u5b9e\u73b0\u5192\u6ce1\u6392\u5e8f\u7b97\u6cd5\"\"\" n = len ( lyst ) while n > 1 : swapped = False # \u7528\u5e03\u5c14\u6807\u5fd7\u6765\u8ffd\u8e2a\u6709\u6ca1\u6709\u53d1\u751f\u4ea4\u6362 i = 1 while i < n : if lyst [ i ] < lyst [ i - 1 ]: # \u5982\u679c\u540e\u9762\u5143\u7d20\u7684\u503c\u6bd4\u524d\u9762\u5143\u7d20\u7684\u5927\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\uff0c\u76f4\u81f3\u628a\u5faa\u73af\u4e2d\u7684\u6700\u5927\u5143\u7d20\u79fb\u5230\u6700\u540e swap ( lyst , i , i - 1 ) swapped = True i += 1 if not swapped : # \u5982\u679c\u4e0d\u9700\u8981\u4ea4\u6362\uff0c\u76f4\u63a5return return n -= 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] # \u6bd4\u8f83\u6392\u5e8f print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) # \u5192\u6ce1\u6392\u5e8f myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before bubble sort \" , myList ) bubbleSortWithTweak ( myList ) print ( \"After bubble sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] # Before bubble sort [9, 4, 2, 7, 6, 8, 1] # After bubble sort [1, 2, 4, 6, 7, 8, 9] 3.4.3.\u63d2\u5165\u6392\u5e8f \u00b6 \u63d2\u5165\u6392\u5e8f\uff08Insertion-Sort\uff09\u662f\u901a\u8fc7\u6784\u5efa\u6709\u5e8f\u5e8f\u5217\uff0c\u5bf9\u4e8e\u672a\u6392\u5e8f\u6570\u636e\uff0c\u5728\u5df2\u6392\u5e8f\u5e8f\u5217\u4e2d\u4ece\u540e\u5411\u524d\u626b\u63cf\uff0c\u627e\u5230\u76f8\u5e94\u4f4d\u7f6e\u5e76\u63d2\u5165\u3002\u63d2\u5165\u6392\u5e8f\u90fd\u91c7\u7528 in-place \u5728\u6570\u7ec4\u4e0a\u5b9e\u73b0\uff1a \u4ece\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\uff0c\u8be5\u5143\u7d20\u53ef\u4ee5\u8ba4\u4e3a\u5df2\u7ecf\u88ab\u6392\u5e8f\uff1b \u53d6\u51fa\u4e0b\u4e00\u4e2a\u5143\u7d20\uff0c\u5728\u5df2\u7ecf\u6392\u5e8f\u7684\u5143\u7d20\u5e8f\u5217\u4ece\u540e\u5411\u524d\u626b\u63cf\uff1b \u5982\u679c\u65b0\u5143\u7d20\u5c0f\u4e8e\u5df2\u6392\u5e8f\u7684\u5143\u7d20\uff0c\u5c06\u65b0\u5143\u7d20\u79fb\u5230\u4e0b\u4e00\u4f4d\u7f6e\uff1b \u91cd\u590d\u6b65\u9aa43\uff0c\u76f4\u5230\u627e\u5230\u5df2\u6392\u5e8f\u7684\u5143\u7d20\u5c0f\u4e8e\u6216\u8005\u7b49\u4e8e\u65b0\u5143\u7d20\u7684\u4f4d\u7f6e\uff1b \u5c06\u65b0\u5143\u7d20\u63d2\u5165\u5230\u8be5\u4f4d\u7f6e\u540e\uff1b \u91cd\u590d\u6b65\u9aa42~5\u3002 \u590d\u6742\u5ea6\uff1a \u548c\u9009\u62e9\u6392\u5e8f\u7c7b\u4f3c\uff0c\u904d\u5386\u6b21\u6570\u4e5f\u662f (1/2)*n^2+(1/2)*n \uff0c\u6240\u4ee5\u590d\u6742\u5ea6\u4e5f\u662fO(n^2)\u3002 \u5217\u8868\u91cc\u6709\u5e8f\u5143\u7d20\u8d8a\u591a\uff0c\u63d2\u5165\u6392\u5e8f\u7684\u6027\u80fd\u5c31\u4f1a\u8d8a\u597d\uff1b \u5728\u6709\u5e8f\u5217\u8868\u7684\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u6392\u5e8f\u590d\u6742\u5ea6\u662f\u7ebf\u6027\u7684\uff1b def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 minIndex = i # \u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , minIndex , i ) i += 1 def bubbleSortWithTweak ( lyst ): \"\"\"\u5b9e\u73b0\u5192\u6ce1\u6392\u5e8f\u7b97\u6cd5\"\"\" n = len ( lyst ) while n > 1 : swapped = False # \u7528\u5e03\u5c14\u6807\u5fd7\u6765\u8ffd\u8e2a\u6709\u6ca1\u6709\u53d1\u751f\u4ea4\u6362 i = 1 while i < n : if lyst [ i ] < lyst [ i - 1 ]: # \u5982\u679c\u540e\u9762\u5143\u7d20\u7684\u503c\u6bd4\u524d\u9762\u5143\u7d20\u7684\u5927\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\uff0c\u76f4\u81f3\u628a\u5faa\u73af\u4e2d\u7684\u6700\u5927\u5143\u7d20\u79fb\u5230\u6700\u540e swap ( lyst , i , i - 1 ) swapped = True i += 1 if not swapped : # \u5982\u679c\u4e0d\u9700\u8981\u4ea4\u6362\uff0c\u76f4\u63a5return return n -= 1 def insertionSort ( lyst ): i = 1 # \u65b0\u5143\u7d20\u7684\u4f4d\u7f6e while i < len ( lyst ): itemToInsert = lyst [ i ] # \u65b0\u5143\u7d20 j = i - 1 # \u5df2\u6392\u5e8f\u7684\u5143\u7d20\u5e8f\u5217\u7684\u6700\u53f3\u4f4d\u7f6e while j >= 0 : if itemToInsert < lyst [ j ]: lyst [ j + 1 ] = lyst [ j ] # \u5982\u679c\u65b0\u5143\u7d20\u5c0f\u4e8e\u5df2\u6392\u5e8f\u5143\u7d20\uff0c\u5219\u5df2\u6392\u5e8f\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4e2a\u4f4d\u7f6e j -= 1 else : break # \u65b0\u5143\u7d20\u7b49\u4e8e\u6216\u8005\u5927\u4e8e\u5df2\u6392\u5e8f\u5143\u7d20\uff0c\u8df3\u51fa\u5faa\u73af\uff0c\u6b64\u65f6lyst[j + 1]\u662f\u548clyst[j]\u662f\u540c\u4e00\u4e2a\u5143\u7d20\u503c\uff0clyst[j + 1]\u4f4d\u7f6e\u662f\u7559\u7ed9\u65b0\u5143\u7d20\u7684 lyst [ j + 1 ] = itemToInsert # i += 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] # \u6bd4\u8f83\u6392\u5e8f print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) # \u5192\u6ce1\u6392\u5e8f myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before bubble sort \" , myList ) bubbleSortWithTweak ( myList ) print ( \"After bubble sort \" , myList ) # \u63d2\u5165\u6392\u5e8f myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before insertion sort \" , myList ) insertionSort ( myList ) print ( \"After insertion sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] # Before bubble sort [9, 4, 2, 7, 6, 8, 1] # After bubble sort [1, 2, 4, 6, 7, 8, 9] # Before insertion sort [9, 4, 2, 7, 6, 8, 1] # After insertion sort [1, 2, 4, 6, 7, 8, 9] 3.4.4.\u518d\u8bba\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd \u00b6 \u5bf9\u4e8e\u8bb8\u591a\u7b97\u6cd5\u6765\u8bf4\uff0c\u4e0d\u80fd\u5bf9\u6240\u6709\u60c5\u51b5\u91c7\u7528\u5355\u4e00\u7684\u590d\u6742\u5ea6\u6765\u8861\u91cf\u3002\u5f53\u9047\u5230\u7279\u5b9a\u987a\u5e8f\u7684\u6570\u636e\u65f6\uff0c\u7b97\u6cd5\u7684\u884c\u4e3a\u53ef\u80fd\u4f1a\u53d8\u5f97\u66f4\u597d\u6216\u66f4\u7cdf\u3002 \u5bf9\u7b97\u6cd5\u590d\u6742\u5ea6\u884c\u4e3a\u5206\u4e3a3\u79cd\u60c5\u51b5\uff1a \u6700\u597d\u60c5\u51b5\uff08best case\uff09\u2014\u2014\u7b97\u6cd5\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\u53ef\u4ee5\u4ee5\u6700\u5c11\u7684\u5de5\u4f5c\u91cf\u5b8c\u6210\u5de5\u4f5c\uff1f\u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u7684\u590d\u6742\u5ea6\u662f\u591a\u5c11\uff1f \u6700\u574f\u60c5\u51b5\uff08worst case\uff09\u2014\u2014\u7b97\u6cd5\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\u9700\u8981\u5b8c\u6210\u6700\u591a\u7684\u5de5\u4f5c\u91cf\uff1f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u7684\u590d\u6742\u5ea6\u662f\u591a\u5c11\uff1f \u5e73\u5747\u60c5\u51b5\uff08average case\uff09\u2014\u2014\u7b97\u6cd5\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\u7528\u9002\u91cf\u7684\u5de5\u4f5c\u91cf\u5c31\u80fd\u5b8c\u6210\u5de5\u4f5c\uff1f\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u7684\u590d\u6742\u5ea6\u662f\u591a\u5c11\uff1f \u4e0b\u9762\u5206\u522b\u5bf9\u6700\u5c0f\u503c\u641c\u7d22\u3001\u987a\u5e8f\u641c\u7d22\u548c\u5192\u6ce1\u6392\u5e8f\u8fdb\u884c\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u548c\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u5206\u6790\uff0c\u4e0d\u8003\u8651\u5b9e\u9645\u786c\u4ef6\u548c\u7f16\u7a0b\u8bed\u8a00\u7b49\u7684\u5f71\u54cd\u3002 \u6700\u5c0f\u503c\u641c\u7d22\uff08Minimum Value Search\uff09 \u6700\u597d\u60c5\u51b5\uff1a\u6700\u5c0f\u503c\u521a\u597d\u5728\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3002\u8fd9\u65f6\uff0c\u53ea\u9700\u8981\u4e00\u6b21\u6bd4\u8f83\u5c31\u53ef\u4ee5\u627e\u5230\u6700\u5c0f\u503c\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(1)\u3002 \u6700\u574f\u60c5\u51b5\uff1a\u6700\u5c0f\u503c\u5728\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u6216\u4e0d\u5b58\u5728\u3002\u8fd9\u65f6\uff0c\u9700\u8981\u8fdb\u884cn-1\u6b21\u6bd4\u8f83\u624d\u80fd\u786e\u5b9a\u6700\u5c0f\u503c\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5e73\u5747\u60c5\u51b5\uff1a\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u6bcf\u4e2a\u5143\u7d20\u6709\u76f8\u7b49\u7684\u6982\u7387\u6210\u4e3a\u6700\u5c0f\u503c\u3002\u56e0\u6b64\uff0c\u5e73\u5747\u6bd4\u8f83\u6b21\u6570\u4e3a(n-1)/2\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u987a\u5e8f\u641c\u7d22\uff08Sequential Search\uff09 \u6700\u597d\u60c5\u51b5\uff1a\u641c\u7d22\u7684\u5143\u7d20\u521a\u597d\u662f\u5217\u8868\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u3002\u8fd9\u65f6\uff0c\u53ea\u9700\u8981\u4e00\u6b21\u6bd4\u8f83\u5c31\u53ef\u4ee5\u627e\u5230\u76ee\u6807\u5143\u7d20\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(1)\u3002 \u6700\u574f\u60c5\u51b5\uff1a\u641c\u7d22\u7684\u5143\u7d20\u5728\u5217\u8868\u7684\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u6216\u4e0d\u5b58\u5728\u3002\u8fd9\u65f6\uff0c\u9700\u8981\u8fdb\u884cn\u6b21\u6bd4\u8f83\u624d\u80fd\u786e\u5b9a\u76ee\u6807\u5143\u7d20\u4e0d\u5b58\u5728\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5e73\u5747\u60c5\u51b5\uff1a\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u6bcf\u4e2a\u5143\u7d20\u6709\u76f8\u7b49\u7684\u6982\u7387\u6210\u4e3a\u76ee\u6807\u5143\u7d20\u3002\u56e0\u6b64\uff0c\u5e73\u5747\u6bd4\u8f83\u6b21\u6570\u4e3a (n+1)/2 \uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5192\u6ce1\u6392\u5e8f\uff08Bubble Sort\uff09 \u6700\u597d\u60c5\u51b5\uff1a\u5982\u679c\u8f93\u5165\u5217\u8868\u5df2\u7ecf\u662f\u6709\u5e8f\u7684\uff0c\u5192\u6ce1\u6392\u5e8f\u53ea\u9700\u8981\u8fdb\u884c\u4e00\u6b21\u904d\u5386\u6765\u68c0\u6d4b\u5217\u8868\u5df2\u7ecf\u6709\u5e8f\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002\u4f46\u5b9e\u9645\u4e0a\uff0c\u901a\u5e38\u9700\u8981\u8fdb\u884c\u591a\u6b21\u904d\u5386\u6765\u5b8c\u6210\u6392\u5e8f\uff0c\u56e0\u6b64\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662fO(n^2)\u3002 \u6700\u574f\u60c5\u51b5\uff1a\u5982\u679c\u8f93\u5165\u5217\u8868\u662f\u9006\u5e8f\u7684\uff0c\u6bcf\u6b21\u904d\u5386\u90fd\u9700\u8981\u8fdb\u884cn-1\u6b21\u4ea4\u6362\uff0c\u603b\u5171\u9700\u8981\u8fdb\u884cn-1\u8f6e\u904d\u5386\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n^2)\u3002 \u5e73\u5747\u60c5\u51b5\uff1a\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u5192\u6ce1\u6392\u5e8f\u9700\u8981\u8fdb\u884c n(n-1)/2 \u6b21\u6bd4\u8f83\u548c\u4ea4\u6362\u64cd\u4f5c\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n^2)\u3002 3.4.5.\u7ec3\u4e60\u9898 \u00b6 \u5217\u8868\u91cc\u5982\u4f55\u6392\u5217\u6570\u636e\u624d\u80fd\u8ba9\u9009\u62e9\u6392\u5e8f\u4e2d\u5143\u7d20\u4ea4\u6362\u7684\u6b21\u6570\u6700\u5c11\uff1f\u5982\u4f55\u6392\u5217\u6570\u636e\u624d\u80fd\u8ba9\u5b83\u6267\u884c\u6700\u591a\u7684\u4ea4\u6362\u6b21\u6570\uff1f \u89e3\u7b54\uff1a \u5728\u9009\u62e9\u6392\u5e8f\u4e2d\uff0c\u5143\u7d20\u7684\u4ea4\u6362\u6b21\u6570\u4e3b\u8981\u53d6\u51b3\u4e8e\u5f85\u6392\u5e8f\u5217\u8868\u7684\u521d\u59cb\u6392\u5217\uff1a \u6700\u5c0f\u5316\u4ea4\u6362\u6b21\u6570\uff1a \u8981\u6700\u5c0f\u5316\u9009\u62e9\u6392\u5e8f\u7684\u5143\u7d20\u4ea4\u6362\u6b21\u6570\uff0c\u53ef\u4ee5\u8ba9\u8f93\u5165\u5217\u8868\u5df2\u7ecf\u6309\u5347\u5e8f\u6392\u5217\u3002\u8fd9\u662f\u56e0\u4e3a\u5728\u5347\u5e8f\u6392\u5217\u7684\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u6bcf\u6b21\u9009\u62e9\u6700\u5c0f\u7684\u5143\u7d20\u5e76\u5c06\u5176\u653e\u7f6e\u5728\u6b63\u786e\u7684\u4f4d\u7f6e\uff0c\u65e0\u9700\u4ea4\u6362\u3002\u56e0\u6b64\uff0c\u5143\u7d20\u4ea4\u6362\u7684\u6b21\u6570\u4e3a 0 \u3002 \u6700\u5927\u5316\u4ea4\u6362\u6b21\u6570\uff1a \u8981\u6700\u5927\u5316\u9009\u62e9\u6392\u5e8f\u7684\u5143\u7d20\u4ea4\u6362\u6b21\u6570\uff0c\u53ef\u4ee5\u8ba9\u8f93\u5165\u5217\u8868\u6309\u964d\u5e8f\u6392\u5217\u3002\u5728\u964d\u5e8f\u6392\u5217\u7684\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u6bcf\u6b21\u9009\u62e9\u6700\u5927\u7684\u5143\u7d20\u5e76\u5c06\u5176\u653e\u7f6e\u5728\u6b63\u786e\u7684\u4f4d\u7f6e\uff0c\u8fd9\u5c06\u5bfc\u81f4\u5927\u91cf\u7684\u4ea4\u6362\u64cd\u4f5c\u3002\u5177\u4f53\u6765\u8bf4\uff0c\u5bf9\u4e8e\u957f\u5ea6\u4e3an\u7684\u5217\u8868\uff0c\u6700\u5927\u5316\u4ea4\u6362\u6b21\u6570\u7684\u60c5\u51b5\u4e0b\uff0c\u5c06\u6267\u884c n-1 \u6b21\u4ea4\u6362\u64cd\u4f5c\u3002 \u603b\u4e4b\uff0c\u8981\u6700\u5c0f\u5316\u9009\u62e9\u6392\u5e8f\u7684\u5143\u7d20\u4ea4\u6362\u6b21\u6570\uff0c\u8f93\u5165\u5217\u8868\u5e94\u8be5\u5df2\u7ecf\u6309\u5347\u5e8f\u6392\u5217\u3002\u8981\u6700\u5927\u5316\u4ea4\u6362\u6b21\u6570\uff0c\u8f93\u5165\u5217\u8868\u5e94\u8be5\u6309\u964d\u5e8f\u6392\u5217\u3002\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u9009\u62e9\u6392\u5e8f\u901a\u5e38\u4e0d\u662f\u9996\u9009\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u56e0\u4e3a\u5176\u4ea4\u6362\u6b21\u6570\u8f83\u591a\uff0c\u800c\u5176\u4ed6\u7b97\u6cd5\u5982\u5feb\u901f\u6392\u5e8f\u3001\u5f52\u5e76\u6392\u5e8f\u7b49\u5177\u6709\u66f4\u597d\u7684\u6027\u80fd\u3002 \u8bf7\u8bf4\u660e\u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\u5728\u5206\u6790\u9009\u62e9\u6392\u5e8f\u548c\u5192\u6ce1\u6392\u5e8f\u65f6\u6240\u8d77\u5230\u7684\u4f5c\u7528\u3002\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u5728\u5b83\u4eec\u4e4b\u95f4\u53d1\u6325\u7740\u4ec0\u4e48\u4f5c\u7528\uff08\u5982\u679c\u6709\u4f5c\u7528\uff09\uff1f \u89e3\u7b54\uff1a \u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\u5728\u5206\u6790\u9009\u62e9\u6392\u5e8f\u548c\u5192\u6ce1\u6392\u5e8f\u65f6\u8d77\u5230\u91cd\u8981\u4f5c\u7528\uff0c\u56e0\u4e3a\u5b83\u4eec\u76f4\u63a5\u5f71\u54cd\u5230\u6392\u5e8f\u7b97\u6cd5\u7684\u6027\u80fd\u548c\u6548\u7387\u3002 \u9009\u62e9\u6392\u5e8f\uff08Selection Sort\uff09\uff1a \u9009\u62e9\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e0e\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u76f4\u63a5\u76f8\u5173\u3002\u5728\u9009\u62e9\u6392\u5e8f\u4e2d\uff0c\u6bcf\u4e00\u8f6e\u90fd\u4f1a\u9009\u62e9\u672a\u6392\u5e8f\u90e8\u5206\u7684\u6700\u5c0f\u5143\u7d20\uff0c\u5e76\u5c06\u5176\u653e\u7f6e\u5728\u6b63\u786e\u7684\u4f4d\u7f6e\uff0c\u8fd9\u610f\u5473\u7740\u6bcf\u8f6e\u90fd\u9700\u8981\u4e00\u6b21\u4ea4\u6362\u64cd\u4f5c\u3002 \u9009\u62e9\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u662f\u4e0e\u8f93\u5165\u6570\u636e\u7684\u521d\u59cb\u6392\u5217\u65e0\u5173\u7684\uff0c\u56e0\u4e3a\u5b83\u603b\u662f\u4f1a\u6267\u884c\u76f8\u540c\u6570\u91cf\u7684\u4ea4\u6362\u64cd\u4f5c\uff0c\u65e0\u8bba\u6570\u636e\u662f\u5426\u6709\u5e8f\u3002 \u5bf9\u4e8e\u9009\u62e9\u6392\u5e8f\uff0c\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e3b\u8981\u53d7\u5230\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u5f71\u54cd\uff0c\u800c\u4e0d\u53d7\u6570\u636e\u7684\u5177\u4f53\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u65e0\u8bba\u6570\u636e\u7684\u6392\u5217\u5982\u4f55\uff0c\u9009\u62e9\u6392\u5e8f\u7684\u5e73\u5747\u548c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u90fd\u662f\u76f8\u540c\u7684\uff0c\u5373 n-1 \u6b21\u3002 \u5192\u6ce1\u6392\u5e8f\uff08Bubble Sort\uff09\uff1a \u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e5f\u4e0e\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u76f8\u5173\u3002\u5728\u5192\u6ce1\u6392\u5e8f\u4e2d\uff0c\u76f8\u90bb\u5143\u7d20\u9010\u4e00\u6bd4\u8f83\uff0c\u5982\u679c\u9006\u5e8f\u5c31\u4ea4\u6362\u4f4d\u7f6e\uff0c\u56e0\u6b64\u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e0e\u9006\u5e8f\u5bf9\u7684\u6570\u91cf\u76f8\u5173\u3002 \u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u5728\u4e0d\u540c\u7684\u6570\u636e\u6392\u5217\u60c5\u51b5\u4e0b\u53ef\u4ee5\u6709\u5f88\u5927\u5dee\u5f02\u3002\u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff08\u8f93\u5165\u6570\u636e\u5df2\u7ecf\u6709\u5e8f\uff09\uff0c\u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e3a 0 \u3002\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff08\u8f93\u5165\u6570\u636e\u5b8c\u5168\u9006\u5e8f\uff09\uff0c\u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u662f\u6700\u5927\u7684\u3002 \u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u65e2\u53d7\u5230\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u5f71\u54cd\uff0c\u53c8\u53d7\u5230\u6570\u636e\u7684\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u4ea4\u6362\u6b21\u6570\u4e3a 0 \uff0c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u4ea4\u6362\u6b21\u6570\u4e3a n*(n-1)/2 \uff0c\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u4ea4\u6362\u6b21\u6570\u53d6\u51b3\u4e8e\u6570\u636e\u6392\u5217\u7684\u968f\u673a\u6027\u3002 \u7efc\u4e0a\u6240\u8ff0\uff0c\u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\u5728\u9009\u62e9\u6392\u5e8f\u548c\u5192\u6ce1\u6392\u5e8f\u7684\u5206\u6790\u4e2d\u662f\u91cd\u8981\u7684\u6027\u80fd\u6307\u6807\u3002\u9009\u62e9\u6392\u5e8f\u7684\u4ea4\u6362\u6b21\u6570\u4e0e\u6570\u636e\u89c4\u6a21\u76f8\u5173\uff0c\u800c\u5192\u6ce1\u6392\u5e8f\u7684\u4ea4\u6362\u6b21\u6570\u65e2\u4e0e\u6570\u636e\u89c4\u6a21\u76f8\u5173\uff0c\u53c8\u53d7\u5230\u6570\u636e\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u5728\u5927\u89c4\u6a21\u6570\u636e\u96c6\u4e0a\uff0c\u5192\u6ce1\u6392\u5e8f\u901a\u5e38\u6bd4\u9009\u62e9\u6392\u5e8f\u66f4\u6162\uff0c\u56e0\u4e3a\u5b83\u7684\u4ea4\u6362\u64cd\u4f5c\u66f4\u591a\u3002\u56e0\u6b64\uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u901a\u5e38\u9009\u62e9\u6392\u5e8f\u6bd4\u5192\u6ce1\u6392\u5e8f\u66f4\u6709\u6548\u3002\u4f46\u4e24\u8005\u90fd\u4e0d\u662f\u9996\u9009\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u66f4\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\u5982\u5feb\u901f\u6392\u5e8f\u3001\u5f52\u5e76\u6392\u5e8f\u7b49\u901a\u5e38\u88ab\u4f18\u5148\u8003\u8651\u3002 \u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u6027\u80fd\u4ecd\u7136\u4e3aO(n^2)\u3002 \u89e3\u7b54\uff1a \u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u6027\u80fd\u4ecd\u7136\u4e3aO(n^2)\uff0c\u539f\u56e0\u5982\u4e0b\uff1a \u5192\u6ce1\u6392\u5e8f\u7684\u57fa\u672c\u64cd\u4f5c\u662f\u6bd4\u8f83\u76f8\u90bb\u5143\u7d20\u5e76\u4ea4\u6362\u5b83\u4eec\uff0c\u76f4\u5230\u6574\u4e2a\u5217\u8868\u6309\u7167\u5347\u5e8f\u6392\u5217\u3002\u5728\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u4e2d\uff0c\u5f53\u4e24\u4e2a\u76f8\u90bb\u5143\u7d20\u9006\u5e8f\u65f6\uff0c\u4f1a\u53d1\u751f\u4ea4\u6362\u3002\u8fd9\u4e2a\u57fa\u672c\u64cd\u4f5c\u7684\u590d\u6742\u5ea6\u662fO(1)\uff0c\u56e0\u4e3a\u5b83\u53ea\u6d89\u53ca\u4e24\u4e2a\u5143\u7d20\u7684\u6bd4\u8f83\u548c\u53ef\u80fd\u7684\u4ea4\u6362\u3002 \u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u6bcf\u4e00\u8f6e\u904d\u5386\u4e2d\uff0c\u4ecd\u7136\u9700\u8981\u68c0\u67e5\u76f8\u90bb\u5143\u7d20\u7684\u6bd4\u8f83\uff0c\u5373\u4f7f\u5728\u6709\u5e8f\u90e8\u5206\uff0c\u5b83\u4ecd\u7136\u9700\u8981\u8fdb\u884c\u6bd4\u8f83\u3002\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5b83\u4f1a\u6267\u884cn-1\u6b21\u904d\u5386\uff0c\u6bcf\u6b21\u90fd\u8981\u6bd4\u8f83\u76f8\u90bb\u5143\u7d20\u3002 \u5192\u6ce1\u6392\u5e8f\u7684\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n^2)\uff0c\u8fd9\u662f\u56e0\u4e3a\u5b83\u4e0d\u4f1a\u5229\u7528\u8f93\u5165\u6570\u636e\u7684\u4efb\u4f55\u6709\u5e8f\u6027\u3002\u65e0\u8bba\u8f93\u5165\u6570\u636e\u662f\u6709\u5e8f\u7684\u3001\u9006\u5e8f\u7684\uff0c\u8fd8\u662f\u968f\u673a\u6392\u5217\u7684\uff0c\u90fd\u9700\u8981\u6267\u884c\u76f8\u540c\u6570\u91cf\u7684\u6bd4\u8f83\u548c\u4ea4\u6362\u64cd\u4f5c\u3002 \u603b\u4e4b\uff0c\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u867d\u7136\u51cf\u5c11\u4e86\u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\uff0c\u4f46\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u4ecd\u7136\u9700\u8981\u6267\u884c\u5927\u7ea6 n(n-1)/2 \u6b21\u6bd4\u8f83\u64cd\u4f5c\uff0c\u56e0\u6b64\u5b83\u7684\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662fO(n^2)\u3002\u5192\u6ce1\u6392\u5e8f\u7684\u6027\u80fd\u4e3b\u8981\u53d7\u5230\u6570\u636e\u89c4\u6a21\u7684\u5f71\u54cd\uff0c\u800c\u4e0d\u592a\u53d7\u5230\u5177\u4f53\u6570\u636e\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u56e0\u6b64\uff0c\u5b83\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u4ecd\u7136\u5177\u6709\u4e8c\u6b21\u65f6\u95f4\u590d\u6742\u5ea6\u3002 \u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u63d2\u5165\u6392\u5e8f\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e0a\u80fd\u591f\u5f88\u597d\u5730\u5de5\u4f5c\u3002 \u89e3\u7b54\uff1a \u63d2\u5165\u6392\u5e8f\u4e4b\u6240\u4ee5\u80fd\u591f\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e0a\u5f88\u597d\u5730\u5de5\u4f5c\uff0c\u662f\u56e0\u4e3a\u5b83\u7684\u6838\u5fc3\u601d\u60f3\u662f\u9010\u6b65\u6784\u5efa\u6709\u5e8f\u7684\u5b50\u5217\u8868\uff0c\u800c\u4e0d\u662f\u50cf\u9009\u62e9\u6392\u5e8f\u6216\u5192\u6ce1\u6392\u5e8f\u4e00\u6837\u603b\u662f\u8003\u8651\u6574\u4e2a\u5217\u8868\u3002\u8fd9\u4f7f\u5f97\u63d2\u5165\u6392\u5e8f\u5728\u5904\u7406\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u65f6\u5177\u6709\u4e00\u4e9b\u4f18\u52bf\uff1a \u5c40\u90e8\u6027\u539f\u7406\uff1a\u63d2\u5165\u6392\u5e8f\u5229\u7528\u4e86\u5c40\u90e8\u6027\u539f\u7406\uff0c\u5373\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u6570\u636e\u9879\u7684\u6b63\u786e\u4f4d\u7f6e\u79bb\u5b83\u4eec\u5f53\u524d\u7684\u4f4d\u7f6e\u5f88\u8fd1\u3002\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e2d\uff0c\u5927\u591a\u6570\u6570\u636e\u9879\u5df2\u7ecf\u63a5\u8fd1\u4e8e\u5b83\u4eec\u7684\u6700\u7ec8\u4f4d\u7f6e\uff0c\u56e0\u6b64\u53ea\u9700\u8981\u8fdb\u884c\u5c11\u91cf\u7684\u79fb\u52a8\u64cd\u4f5c\u3002 \u9002\u5e94\u6027\uff1a\u63d2\u5165\u6392\u5e8f\u662f\u4e00\u79cd\u81ea\u9002\u5e94\u6392\u5e8f\u7b97\u6cd5\uff0c\u5b83\u53ef\u4ee5\u6839\u636e\u8f93\u5165\u6570\u636e\u7684\u6709\u5e8f\u6027\u8fdb\u884c\u81ea\u52a8\u8c03\u6574\u3002\u5728\u5904\u7406\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u65f6\uff0c\u63d2\u5165\u6392\u5e8f\u7684\u6027\u80fd\u4f1a\u66f4\u597d\uff0c\u56e0\u4e3a\u4e0d\u9700\u8981\u6267\u884c\u592a\u591a\u7684\u6bd4\u8f83\u548c\u4ea4\u6362\u64cd\u4f5c\u3002 \u7b80\u5355\u6027\uff1a\u63d2\u5165\u6392\u5e8f\u7684\u5b9e\u73b0\u975e\u5e38\u7b80\u5355\u76f4\u89c2\uff0c\u5b83\u53ea\u6d89\u53ca\u5230\u9010\u4e2a\u63d2\u5165\u5143\u7d20\u5230\u6b63\u786e\u7684\u4f4d\u7f6e\u3002\u8fd9\u79cd\u7b80\u5355\u6027\u4f7f\u5f97\u63d2\u5165\u6392\u5e8f\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\u6bd4\u66f4\u590d\u6742\u7684\u6392\u5e8f\u7b97\u6cd5\u66f4\u5177\u7ade\u4e89\u529b\u3002 \u867d\u7136\u63d2\u5165\u6392\u5e8f\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e0a\u8868\u73b0\u826f\u597d\uff0c\u4f46\u5728\u5904\u7406\u5927\u89c4\u6a21\u4e71\u5e8f\u6570\u636e\u96c6\u65f6\uff0c\u5b83\u7684\u6027\u80fd\u4e0d\u5982\u5feb\u901f\u6392\u5e8f\u3001\u5f52\u5e76\u6392\u5e8f\u7b49\u66f4\u9ad8\u7ea7\u7684\u6392\u5e8f\u7b97\u6cd5\u3002\u56e0\u6b64\uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u6839\u636e\u6570\u636e\u7684\u6027\u8d28\u9009\u62e9\u9002\u5f53\u7684\u6392\u5e8f\u7b97\u6cd5\u662f\u91cd\u8981\u7684\u3002\u63d2\u5165\u6392\u5e8f\u901a\u5e38\u9002\u7528\u4e8e\u5c0f\u89c4\u6a21\u6570\u636e\u6216\u8005\u5df2\u7ecf\u90e8\u5206\u6709\u5e8f\u7684\u6570\u636e\uff0c\u800c\u4e0d\u662f\u5927\u89c4\u6a21\u4e71\u5e8f\u6570\u636e\u7684\u6392\u5e8f\u3002 3.5.\u66f4\u5feb\u7684\u6392\u5e8f \u00b6 \u5206\u6cbb\u6cd5\uff08divide-and-conquer\uff09\u7b56\u7565\uff1a\u628a\u5217\u8868\u5206\u6210\u66f4\u5c0f\u7684\u5b50\u5217\u8868\uff0c\u7136\u540e\u518d\u901a\u8fc7\u9012\u5f52\u628a\u8fd9\u4e9b\u5b50\u5217\u8868\u6392\u5e8f\u3002 \u7406\u60f3\u60c5\u51b5\u4e0b\uff0c\u5982\u679c\u8fd9\u4e9b\u88ab\u62c6\u5206\u7684\u5b50\u5217\u8868\u7684\u6570\u91cf\u662f logn \uff0c\u800c\u628a\u6bcf\u4e2a\u5b50\u5217\u8868\u8fdb\u884c\u5408\u5e76\u6240\u9700\u7684\u5de5\u4f5c\u91cf\u4e3a n \uff0c\u90a3\u4e48\u8fd9\u79cd\u6392\u5e8f\u7b97\u6cd5\u7684\u603b\u590d\u6742\u5ea6\u5c31\u662f O(nlogn) \uff0c\u76f8\u6bd4 O(n^2) \u7684\u5de5\u4f5c\u91cf\u589e\u957f\u8981\u4f4e\u5f88\u591a\u3002 3.5.1.\u5feb\u901f\u6392\u5e8f \u00b6 \u5feb\u901f\u6392\u5e8f\uff08QuickSort\uff09\u662f\u6392\u9664\u7a33\u5b9a\u6027\u56e0\u7d20\u540e\u6700\u5e38\u7528\u7684\u6392\u5e8f\u3002 \u9996\u5148\u4ece\u5217\u8868\u7684\u4e2d\u95f4\u4f4d\u7f6e\u9009\u62e9\u4e00\u4e2a\u5143\u7d20\uff0c\u8fd9\u4e2a\u5143\u7d20\u88ab\u79f0\u4e3a\u57fa\u51c6\uff08pivot\uff09\uff1b \u5bf9\u5217\u8868\u91cc\u7684\u5143\u7d20\u8fdb\u884c\u5206\u5272\uff0c\u628a\u5c0f\u4e8e\u57fa\u51c6\u7684\u6240\u6709\u5143\u7d20\u79fb\u52a8\u5230\u57fa\u51c6\u7684\u5de6\u4fa7\uff0c\u800c\u628a\u5176\u4f59\u5143\u7d20\u90fd\u79fb\u5230\u57fa\u51c6\u7684\u53f3\u4fa7\u3002 \u5982\u679c\u57fa\u51c6\u6b63\u597d\u662f\u6700\u5927\u7684\u5143\u7d20\uff0c\u90a3\u4e48\u5b83\u6700\u7ec8\u4f1a\u5904\u4e8e\u5217\u8868\u7684\u6700\u53f3\u4fa7\uff1b \u5982\u679c\u57fa\u51c6\u6b63\u597d\u662f\u6700\u5c0f\u7684\u5143\u7d20\uff0c\u90a3\u4e48\u5b83\u5c31\u4f1a\u5728\u6700\u5de6\u4fa7\uff1b \u5206\u6cbb\u6cd5\u3002\u5c06\u8fd9\u4e2a\u8fc7\u7a0b\u9012\u5f52\u5730\u5e94\u7528\u5230\u901a\u8fc7\u57fa\u51c6\u800c\u628a\u539f\u5217\u8868\u5206\u5272\u7684\u5b50\u5217\u8868\u4e0a\uff0c\u5176\u4e2d\uff1a \u4e00\u4e2a\u65b0\u7684\u5b50\u5217\u8868\u7531\u57fa\u51c6\u5de6\u4fa7\u7684\u6240\u6709\u5143\u7d20\uff08\u8f83\u5c0f\u7684\u5143\u7d20\uff09\u7ec4\u6210\uff0c \u53e6\u4e00\u4e2a\u65b0\u7684\u5b50\u5217\u8868\u7531\u57fa\u51c6\u53f3\u4fa7\u7684\u6240\u6709\u5143\u7d20\uff08\u8f83\u5927\u7684\u5143\u7d20\uff09\u7ec4\u6210\uff1b \u5f53\u5206\u51fa\u7684\u5b50\u5217\u8868\u5185\u5c11\u4e8e\u4e24\u4e2a\u5143\u7d20\u65f6\uff0c\u8fd9\u4e2a\u8fc7\u7a0b\u7ec8\u6b62\uff1b 3.5.1.1.\u5206\u5272 \u00b6 \u8fd9\u4e2a\u7b97\u6cd5\u91cc\u6700\u590d\u6742\u7684\u90e8\u5206\u662f\u5bf9\u5143\u7d20\u8fdb\u884c\u5206\u5272\u4ece\u800c\u5f97\u5230\u5b50\u5217\u8868\u7684\u64cd\u4f5c\u3002 \u5c06\u57fa\u51c6\u4e0e\u5b50\u5217\u8868\u91cc\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\u3002 \u5728\u5df2\u77e5\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u548c\u5176\u4ed6\u5143\u7d20\u4e4b\u95f4\u6784\u5efa\u4e00\u4e2a\u8fb9\u754c\u3002\u4e00\u5f00\u59cb\uff0c\u8fd9\u4e2a\u8fb9\u754c\u4f1a\u5904\u4e8e\u7b2c\u4e00\u4e2a\u5143\u7d20\u4e4b\u524d\u3002 \u4ece\u5b50\u5217\u8868\u8fb9\u754c\u4e4b\u540e\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\u5411\u53f3\u626b\u63cf\u3002\u5f53\u6bcf\u6b21\u9047\u5230\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u65f6\uff0c\u5c06\u5b83\u548c\u8fb9\u754c\u4e4b\u540e\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\uff0c\u5e76\u4e14\u5c06\u8fb9\u754c\u5411\u53f3\u79fb\u52a8\u3002 \u5728\u7ed3\u675f\u7684\u65f6\u5019\uff0c\u5c06\u57fa\u51c6\u548c\u8fb9\u754c\u4e4b\u540e\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\u3002 \u793a\u4f8b\u5217\u8868\uff1a[12,19,17,18,14,11,15,13,16]\uff0c\u4e0b\u56fe\u5c55\u793a\u4e86\u5206\u5272\u7684\u6bcf\u4e00\u6b65\u8fc7\u7a0b\u3002 3.5.1.2.\u5feb\u901f\u6392\u5e8f\u590d\u6742\u5ea6\u5206\u6790 \u00b6 \u5feb\u901f\u6392\u5e8f\uff08Quick Sort\uff09\u662f\u4e00\u79cd\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u5176\u5e73\u5747\u548c\u6700\u574f\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662f O(n log n) \u3002\u4e0b\u9762\u662f\u5feb\u901f\u6392\u5e8f\u7684\u590d\u6742\u5ea6\u5206\u6790\uff1a \u5728\u7b2c\u4e00\u6b21\u8fdb\u884c\u5206\u5272\u64cd\u4f5c\u65f6\uff0c\u6211\u4eec\u5c06\u626b\u63cf\u5217\u8868\u91cc\u4ece\u5f00\u5934\u5230\u7ed3\u5c3e\u7684\u6240\u6709\u5143\u7d20\u3002\u56e0\u6b64\uff0c\u5728\u8fd9\u4e2a\u64cd\u4f5c\u671f\u95f4\u5de5\u4f5c\u91cf\u662f\u548c\u5217\u8868\u7684\u957f\u5ea6 n \u6210\u6b63\u6bd4\u7684\u3002\u8fd9\u6b21\u5206\u5272\u4e4b\u540e\u7684\u5de5\u4f5c\u91cf\u4f1a\u548c\u5de6\u5b50\u5217\u8868\u52a0\u4e0a\u53f3\u5b50\u5217\u8868\u7684\u603b\u957f\u5ea6\u6210\u6b63\u6bd4\uff0c\u4e5f\u5c31\u662f n-1 \u3002 \u518d\u6b21\u5bf9\u8fd9\u4e24\u4e2a\u5b50\u5217\u8868\u8fdb\u884c\u5206\u5272\u4e4b\u540e\uff0c\u5c31\u4f1a\u4ea7\u751f4\u4e2a\u52a0\u8d77\u6765\u603b\u957f\u5ea6\u5927\u7ea6\u4e3a n \u7684\u5217\u8868\u6bb5\u3002\u56e0\u6b64\uff0c\u5bf9\u5b83\u4eec\u8fdb\u884c\u5206\u5272\u7684\u603b\u5de5\u4f5c\u91cf\u8fd8\u662f\u548c n \u6210\u6b63\u6bd4\u7684\u3002\u968f\u7740\u5217\u8868\u88ab\u5206\u5272\u6210\u66f4\u591a\u6bb5\uff0c\u603b\u5de5\u4f5c\u91cf\u4f1a\u4e00\u76f4\u548c n \u6210\u6b63\u6bd4\u3002 \u8981\u5b8c\u6210\u6574\u4e2a\u5206\u6790\uff0c\u8fd8\u9700\u8981\u786e\u5b9a\u5217\u8868\u88ab\u5206\u5272\u4e86\u591a\u5c11\u6b21\u3002\u6309\u7167\u6700\u4e50\u89c2\u7684\u60c5\u51b5\u6765\u8bf4\uff08\u867d\u7136\u5728\u5b9e\u9645\u64cd\u4f5c\u7684\u65f6\u5019\uff0c\u901a\u5e38\u5e76\u4e0d\u4f1a\u51fa\u73b0\u8fd9\u4e48\u597d\u7684\u60c5\u51b5\uff09\uff0c\u5047\u8bbe\u6bcf\u6b21\u65b0\u5b50\u5217\u8868\u4e4b\u95f4\u7684\u5206\u754c\u7ebf\u90fd\u5c3d\u53ef\u80fd\u5730\u9760\u8fd1\u5f53\u524d\u5217\u8868\u7684\u4e2d\u5fc3\uff0c\u901a\u5e38\u8fd9\u79cd\u60c5\u51b5\u5e76\u4e0d\u5e38\u89c1\u3002\u4ece\u4e8c\u5206\u641c\u7d22\u7b97\u6cd5\u7684\u8ba8\u8bba\u91cc\u53ef\u77e5\uff0c\u8981\u628a\u5217\u8868\u4e0d\u65ad\u5730\u5206\u6210\u4e24\u534a\uff0c\u5927\u7ea6\u5728 log n \u6b65\u7684\u65f6\u5019\u5c31\u53ea\u5269\u4e0b\u4e00\u4e2a\u5143\u7d20\u4e86\u3002 \u56e0\u6b64\uff0c\u8fd9\u4e2a\u7b97\u6cd5\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u4e3a O(n log n) \u3002\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u6765\u8003\u8651\u6709\u5e8f\u5217\u8868\u7684\u60c5\u51b5\u3002\u5982\u679c\u9009\u62e9\u7684\u57fa\u51c6\u5143\u7d20\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20\uff0c\u90a3\u4e48\u5728\u7b2c\u4e00\u6b21\u5206\u5272\u4e4b\u540e\u5b83\u7684\u53f3\u8fb9\u4f1a\u6709 n-1 \u4e2a\u5143\u7d20\uff0c\u5728\u7b2c\u4e8c\u6b21\u5206\u5272\u4e4b\u540e\u5b83\u7684\u53f3\u8fb9\u6709 n-2 \u4e2a\u5143\u7d20\uff0c\u4ee5\u6b64\u7c7b\u63a8\uff0c \u5c3d\u7ba1\u6574\u4e2a\u64cd\u4f5c\u91cc\u6ca1\u6709\u4ea4\u6362\u4efb\u4f55\u5143\u7d20\uff0c\u4f46\u5206\u5272\u603b\u5171\u4e5f\u6267\u884c\u4e86 n-1 \u6b21\uff0c\u4e8e\u662f\u6267\u884c\u7684\u6bd4\u8f83\u603b\u6570\u5c31\u662f n^2/2-n/2 \u3002\u8fd9\u4e0e\u9009\u62e9\u6392\u5e8f\u4ee5\u53ca\u5192\u6ce1\u6392\u5e8f\u7684\u60c5\u51b5\u662f\u4e00\u6837\u7684\u3002\u56e0\u6b64\uff0c\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7b97\u6cd5\u7684\u6027\u80fd\u4e3a O(n^2) \u3002\u5982\u679c\u628a\u5feb\u901f\u6392\u5e8f\u5b9e\u73b0\u6210\u9012\u5f52\u7b97\u6cd5\uff0c\u90a3\u4e48\u5728\u5bf9\u5b83\u8fdb\u884c\u5206\u6790\u65f6\u8fd8\u5fc5\u987b\u8981\u8003\u8651\u8c03\u7528\u6808\u7684\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\u3002\u7531\u4e8e\u5bf9\u4e8e\u6808\u7684\u4e00\u5e27\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u90fd\u9700\u8981\u56fa\u5b9a\u7684\u5185\u5b58\uff0c\u5e76\u4e14\u6bcf\u6b21\u5206\u5272\u4e4b\u540e\u90fd\u4f1a\u6709\u4e24\u6b21\u9012\u5f52\u8c03\u7528\u3002\u56e0\u6b64\uff0c\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u5185\u5b58\u7684\u4f7f\u7528\u91cf\u4f1a\u662f O(log n) \uff0c\u800c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u5185\u5b58\u4f7f\u7528\u91cf\u662f O(n) \u3002 \u5c3d\u7ba1\u5feb\u901f\u6392\u5e8f\u5904\u4e8e\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u53ef\u80fd\u6027\u5f88\u5c0f\uff0c\u6211\u4eec\u8fd8\u662f\u4f1a\u52aa\u529b\u5730\u53bb\u907f\u514d\u8fd9\u79cd\u60c5\u51b5\uff0c\u56e0\u6b64\uff0c\u5b83\u4eec\u5e76\u4e0d\u4f1a\u5728\u7b2c\u4e00\u4e2a\u6216\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u9009\u62e9\u57fa\u51c6\u5143\u7d20\u3002\u6709\u5176\u4ed6\u4e00\u4e9b\u9009\u62e9\u57fa\u51c6\u7684\u65b9\u6cd5\u53ef\u4ee5\u8ba9\u8fd9\u4e2a\u7b97\u6cd5\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u6709\u5927\u7ea6 O(n log n) \u7684\u6027\u80fd\uff0c\u6bd4\u5982\uff0c\u53ef\u4ee5\u9009\u62e9\u968f\u673a\u4f4d\u7f6e\u4e0a\u7684\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\uff0c\u6216\u8005\u9009\u62e9\u6574\u4e2a\u5217\u8868\u91cc\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3001\u4e2d\u95f4\u4f4d\u7f6e\u4ee5\u53ca\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u8fd93\u4e2a\u5143\u7d20\u7684\u4e2d\u4f4d\u6570\u3002 \u603b\u7ed3\uff1a \u6700\u597d\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u4e5f\u5c31\u662f\u6bcf\u6b21\u9009\u62e9\u7684\u57fa\u51c6\u5143\u7d20\u90fd\u521a\u597d\u5c06\u8f93\u5165\u6570\u636e\u5206\u6210\u4e24\u4e2a\u7b49\u957f\u7684\u5b50\u6570\u7ec4\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n log n) \u3002\u8fd9\u79cd\u60c5\u51b5\u901a\u5e38\u53d1\u751f\u5728\u57fa\u51c6\u5143\u7d20\u7684\u9009\u62e9\u975e\u5e38\u5408\u7406\u7684\u60c5\u51b5\u4e0b\uff0c\u4f8b\u5982\u5728\u6bcf\u6b21\u9009\u62e9\u4e2d\u90fd\u9009\u62e9\u4e2d\u95f4\u5143\u7d20\u3002 \u5e73\u5747\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e5f\u662f O(n log n) \u3002\u8fd9\u662f\u56e0\u4e3a\u5feb\u901f\u6392\u5e8f\u662f\u4e00\u79cd\u5206\u6cbb\u7b97\u6cd5\uff0c\u6bcf\u6b21\u5c06\u95ee\u9898\u5206\u6210\u4e24\u4e2a\u5b50\u95ee\u9898\uff0c\u7136\u540e\u9012\u5f52\u5730\u89e3\u51b3\u8fd9\u4e9b\u5b50\u95ee\u9898\u3002\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u6bcf\u6b21\u5206\u5272\u64cd\u4f5c\u90fd\u80fd\u5c06\u95ee\u9898\u89c4\u6a21\u51cf\u534a\uff0c\u56e0\u6b64\u9700\u8981\u6267\u884c O(n log n) \u6b21\u5206\u5272\u64cd\u4f5c\uff0c\u6bcf\u6b21\u5206\u5272\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002\u56e0\u6b64\uff0c\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n log n) \u3002 \u6700\u574f\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n^2) \u3002\u6700\u574f\u60c5\u51b5\u53d1\u751f\u5728\u6bcf\u6b21\u9009\u62e9\u7684\u57fa\u51c6\u5143\u7d20\u90fd\u662f\u8f93\u5165\u6570\u636e\u4e2d\u7684\u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\uff0c\u5bfc\u81f4\u5206\u5272\u64cd\u4f5c\u4e0d\u5747\u8861\uff0c\u6bcf\u6b21\u5206\u5272\u53ea\u80fd\u5c06\u95ee\u9898\u89c4\u6a21\u51cf\u5c111\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u9000\u5316\u4e3a\u5192\u6ce1\u6392\u5e8f\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \u3002 \u5feb\u901f\u6392\u5e8f\u7684\u5e73\u5747\u548c\u6700\u597d\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n log n) \uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\u901a\u5e38\u6027\u80fd\u4f18\u8d8a\u3002\u7136\u800c\uff0c\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \uff0c\u56e0\u6b64\u5728\u5b9e\u73b0\u5feb\u901f\u6392\u5e8f\u65f6\u9700\u8981\u7279\u522b\u6ce8\u610f\u57fa\u51c6\u5143\u7d20\u7684\u9009\u62e9\u4ee5\u907f\u514d\u6700\u574f\u60c5\u51b5\u7684\u53d1\u751f\u3002 3.5.1.3.\u5b9e\u73b0\u5feb\u901f\u6392\u5e8f \u00b6 \u4ee5\u4e0a\u9762\u56fe\u793a\u7684\u5217\u8868 [12,19,17,18,14,11,15,13,16] \u4e3a\u4f8b\uff0c\u4e0b\u9762\u662f\u5b9e\u73b0\u4ee3\u7801\uff1a import random def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def quicksort ( lyst ): # left\u7684\u521d\u59cb\u503c\u662f0 # right\u7684\u521d\u59cb\u503c\u662f\u5217\u8868\u957f\u5ea6\u51cf1 quicksortHelper ( lyst , 0 , len ( lyst ) - 1 ) def quicksortHelper ( lyst , left , right ): print ( lyst ) if left < right : pivotLocation = partition ( lyst , left , right ) quicksortHelper ( lyst , left , pivotLocation - 1 ) quicksortHelper ( lyst , pivotLocation + 1 , right ) def partition ( lyst , left , right ): \"\"\"\u5bf9\u5217\u8868\u8fdb\u884c\u5206\u533a\"\"\" # \u627e\u5230\u57fa\u51c6\u5143\u7d20\uff08pivot\uff09\uff0c\u5e76\u548c\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u4e92\u6362 middle = ( left + right ) // 2 pivot = lyst [ middle ] lyst [ middle ] = lyst [ right ] lyst [ right ] = pivot # \u8bbe\u5b9a\u8fb9\u754c\u5143\u7d20\uff08boundary point\uff09\uff0c\u521d\u59cb\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20 boundary = left print ( \"pivot: \" , pivot , \"boundary: \" , lyst [ boundary ]) # \u628a\u6240\u6709\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u90fd\u79fb\u52a8\u5230\u8fb9\u754c\u7684\u5de6\u8fb9 for index in range ( left , right ): if lyst [ index ] < pivot : swap ( lyst , index , boundary ) boundary += 1 # \u4ea4\u6362\u57fa\u51c6\u5143\u7d20\u548c\u8fb9\u754c\u5143\u7d20 swap ( lyst , right , boundary ) print ( lyst ) return boundary def main ( size = 20 , sort = quicksort ): lyst = [ 12 , 19 , 17 , 18 , 14 , 11 , 15 , 13 , 16 ] sort ( lyst ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # [12, 19, 17, 18, 14, 11, 15, 13, 16] # pivot: 14 boundary: 12 # [12, 11, 13, 14, 16, 19, 15, 17, 18] # [12, 11, 13, 14, 16, 19, 15, 17, 18] # pivot: 11 boundary: 12 # [11, 13, 12, 14, 16, 19, 15, 17, 18] # [11, 13, 12, 14, 16, 19, 15, 17, 18] # [11, 13, 12, 14, 16, 19, 15, 17, 18] # pivot: 13 boundary: 12 # [11, 12, 13, 14, 16, 19, 15, 17, 18] # [11, 12, 13, 14, 16, 19, 15, 17, 18] # [11, 12, 13, 14, 16, 19, 15, 17, 18] # [11, 12, 13, 14, 16, 19, 15, 17, 18] # pivot: 15 boundary: 16 # [11, 12, 13, 14, 15, 19, 18, 17, 16] # [11, 12, 13, 14, 15, 19, 18, 17, 16] # [11, 12, 13, 14, 15, 19, 18, 17, 16] # pivot: 18 boundary: 19 # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] # pivot: 16 boundary: 17 # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] \u628amain()\u6539\u6210\u5982\u4e0b\uff0c\u5219\u53ef\u4ee5\u751f\u6210\u753120\u4e2a\u968f\u673a\u6574\u6570\u7ec4\u6210\u7684\u5217\u8868\uff1a def main ( size = 20 , sort = quicksort ): lyst = [] for count in range ( size ): lyst . append ( random . randint ( 1 , size + 1 )) print ( lyst ) sort ( lyst ) print ( lyst ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u7b2c\u4e00\u6b21\u8fd0\u884c # [3, 19, 18, 11, 2, 16, 2, 13, 14, 1, 20, 1, 1, 19, 19, 9, 16, 1, 7, 4] # [1, 1, 1, 1, 2, 2, 3, 4, 7, 9, 11, 13, 14, 16, 16, 18, 19, 19, 19, 20] # \u7b2c\u4e8c\u6b21\u8fd0\u884c # [20, 4, 1, 15, 6, 4, 3, 16, 21, 4, 12, 9, 16, 10, 3, 6, 2, 15, 21, 4] # [1, 2, 3, 3, 4, 4, 4, 4, 6, 6, 9, 10, 12, 15, 15, 16, 16, 20, 21, 21] 3.5.2.\u5f52\u5e76\u6392\u5e8f \u00b6 \u5f52\u5e76\u6392\u5e8f\u7684\u7b97\u6cd5\u4e5f\u662f\u91c7\u7528\u5206\u6cbb\u6cd5\uff08Divide and Conquer\uff09\u7684\u4e00\u4e2a\u975e\u5e38\u5178\u578b\u7684\u5e94\u7528\uff0c\u901a\u8fc7\u9012\u5f52\u548c\u5206\u6cbb\u7b56\u7565\u6765\u7a81\u7834 O(n^2) \u6027\u80fd\u74f6\u9888\u7684\u3002 \u4e0b\u9762\u662f\u5bf9\u8fd9\u4e2a\u7b97\u6cd5\u7684\u7b80\u5355\u63cf\u8ff0\u3002 \u5206\u89e3\uff08Divide\uff09\uff1a\u5c06n\u4e2a\u5143\u7d20\u5206\u6210\u4e2a\u542bn/2\u4e2a\u5143\u7d20\u7684\u5b50\u5e8f\u5217\u3002 \u89e3\u51b3\uff08Conquer\uff09\uff1a\u7528\u5408\u5e76\u6392\u5e8f\u6cd5\u5bf9\u4e24\u4e2a\u5b50\u5e8f\u5217\u9012\u5f52\u7684\u6392\u5e8f\u3002 \u5408\u5e76\uff08Combine\uff09\uff1a\u5408\u5e76\u4e24\u4e2a\u5df2\u6392\u5e8f\u7684\u5b50\u5e8f\u5217\u5df2\u5f97\u5230\u6392\u5e8f\u7ed3\u679c\u3002 \u7b97\u6cd5\u601d\u8def\uff1a \u8fed\u4ee3\u6cd5 \u7533\u8bf7\u7a7a\u95f4\uff0c\u4f7f\u5176\u5927\u5c0f\u4e3a\u4e24\u4e2a\u5df2\u7ecf\u6392\u5e8f\u5e8f\u5217\u4e4b\u548c\uff0c\u8be5\u7a7a\u95f4\u7528\u6765\u5b58\u653e\u5408\u5e76\u540e\u7684\u5e8f\u5217\uff1b \u8bbe\u5b9a\u4e24\u4e2a\u6307\u9488\uff0c\u6700\u521d\u4f4d\u7f6e\u5206\u522b\u4e3a\u4e24\u4e2a\u5df2\u7ecf\u6392\u5e8f\u5e8f\u5217\u7684\u8d77\u59cb\u4f4d\u7f6e\uff1b \u6bd4\u8f83\u4e24\u4e2a\u6307\u9488\u6240\u6307\u5411\u7684\u5143\u7d20\uff0c\u9009\u62e9\u76f8\u5bf9\u5c0f\u7684\u5143\u7d20\u653e\u5165\u5230\u5408\u5e76\u7a7a\u95f4\uff0c\u5e76\u79fb\u52a8\u6307\u9488\u5230\u4e0b\u4e00\u4f4d\u7f6e\uff1b \u91cd\u590d\u6b65\u9aa43\u76f4\u5230\u67d0\u4e00\u6307\u9488\u5230\u8fbe\u5e8f\u5217\u5c3e\uff1b \u5c06\u53e6\u4e00\u5e8f\u5217\u5269\u4e0b\u7684\u6240\u6709\u5143\u7d20\u76f4\u63a5\u590d\u5236\u5230\u5408\u5e76\u5e8f\u5217\u5c3e\uff1b \u9012\u5f52\u6cd5 \u5c06\u5e8f\u5217\u6bcf\u76f8\u90bb\u4e24\u4e2a\u6570\u5b57\u8fdb\u884c\u5f52\u5e76\u64cd\u4f5c\uff0c\u5f62\u6210 floor(n/2) \u4e2a\u5e8f\u5217\uff0c\u6392\u5e8f\u540e\u6bcf\u4e2a\u5e8f\u5217\u5305\u542b\u4e24\u4e2a\u5143\u7d20\uff1b \u5c06\u4e0a\u8ff0\u5e8f\u5217\u518d\u6b21\u5f52\u5e76\uff0c\u5f62\u6210 floor(n/4) \u4e2a\u5e8f\u5217\uff0c\u6bcf\u4e2a\u5e8f\u5217\u5305\u542b\u56db\u4e2a\u5143\u7d20\uff1b \u91cd\u590d\u6b65\u9aa42\uff0c\u76f4\u5230\u6240\u6709\u5143\u7d20\u6392\u5e8f\u5b8c\u6bd5\uff1b \u5728\u9876\u5c42\u5b9a\u4e49\u4e863\u4e2aPython\u51fd\u6570\u8fdb\u884c\u534f\u4f5c\u3002 mergeSort \uff1a\u7528\u6237\u8c03\u7528\u7684\u51fd\u6570\uff1b mergeSortHelper \uff1a\u8f85\u52a9\u51fd\u6570\uff0c\u7528\u6765\u9690\u85cf\u9012\u5f52\u8c03\u7528\u6240\u9700\u8981\u7684\u989d\u5916\u53c2\u6570\uff1b merge \uff1a\u5b9e\u73b0\u5408\u5e76\u8fc7\u7a0b\u7684\u51fd\u6570\uff1b 3.5.2.1.\u5408\u5e76\u8fc7\u7a0b\u7684\u5b9e\u73b0 \u00b6 \u5408\u5e76\u8fc7\u7a0b\u7528\u5230\u4e00\u4e2a\u4e0e\u5217\u8868\u5927\u5c0f\u76f8\u540c\u7684\u6570\u7ec4\uff0c\u8fd9\u4e2a\u6570\u7ec4\u53ef\u4ee5\u628a\u5b83\u79f0\u4e3a copyBuffer \u3002\u4e3a\u4e86\u907f\u514d\u6bcf\u6b21\u8c03\u7528 merge \u65f6\u90fd\u8981\u4e3a copyBuffer \u7684\u5206\u914d\u548c\u91ca\u653e\u4ea7\u751f\u5f00\u9500\uff0c\u8fd9\u4e2a\u7f13\u51b2\u533a\u4f1a\u5728 mergeSort \u51fd\u6570\u91cc\u5c31\u5206\u914d\u597d\uff0c\u7136\u540e\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7ed9 mergeSortHelper \u548c merge \u51fd\u6570\u3002\u6bcf\u6b21\u8c03\u7528 mergeSortHelper \u51fd\u6570\u65f6\uff0c\u5b83\u8fd8\u9700\u8981\u77e5\u9053\u5e94\u8be5\u4f7f\u7528\u7684\u5b50\u5217\u8868\u7684\u8303\u56f4\u3002\u8fd9\u4e2a\u8303\u56f4\u53ef\u4ee5\u7531\u53e6\u5916\u4e24\u4e2a\u53c2\u6570 low \u548c high \u6765\u63d0\u4f9b\u3002\u5177\u4f53\u5b9e\u73b0\u53c2\u8003 mergeSort \u51fd\u6570\u7684\u4ee3\u7801\u3002 \u5728\u68c0\u67e5\u4f20\u9012\u7684\u5b50\u5217\u8868\u662f\u4e0d\u662f\u81f3\u5c11\u6709\u4e24\u4e2a\u5143\u7d20\u4e4b\u540e\uff0c mergeSortHelper \u51fd\u6570\u5c06\u4f1a\u8ba1\u7b97\u8fd9\u4e2a\u5b50\u5217\u8868\u7684\u4e2d\u70b9\uff0c\u5e76\u4e14\u5bf9\u4e2d\u70b9\u5de6\u53f3\u4e24\u90e8\u5206\u8fdb\u884c\u9012\u5f52\u6392\u5e8f\uff0c\u6700\u540e\u518d\u8c03\u7528 merge \u51fd\u6570\u6765\u5408\u5e76\u7ed3\u679c\u3002\u5177\u4f53\u5b9e\u73b0\u53c2\u8003 mergeSortHelper \u51fd\u6570\u7684\u4ee3\u7801\u3002 merge \u51fd\u6570\u4f1a\u628a\u4e24\u4e2a\u5df2\u7ecf\u6392\u597d\u5e8f\u7684\u5b50\u5217\u8868\u5408\u5e76\u6210\u4e00\u4e2a\u66f4\u5927\u7684\u6709\u5e8f\u5217\u8868\u3002\u5728\u539f\u5217\u8868\u91cc\uff0c\u7b2c\u4e00\u4e2a\u5b50\u5217\u8868\u4f1a\u5728 low \u5230 middle \u4e4b\u95f4\uff1b\u7b2c\u4e8c\u4e2a\u5b50\u5217\u8868\u5219\u4f4d\u4e8e middle + 1 \u548c high \u4e4b\u95f4\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u5305\u542b\u5982\u4e0b3\u4e2a\u6b65\u9aa4\u3002 \u8bbe\u7f6e\u6307\u5411\u4e24\u4e2a\u5b50\u5217\u8868\u4e2d\u7b2c\u4e00\u4e2a\u5143\u7d20\u7684\u7d22\u5f15\u6307\u9488\u3002\u5b83\u4eec\u5206\u522b\u4f4d\u4e8e low \u548c middle +1 \uff1b \u4ece\u5b50\u5217\u8868\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\u91cd\u590d\u6bd4\u8f83\u8fd9\u4e9b\u5143\u7d20\u3002\u628a\u66f4\u5c0f\u7684\u90a3\u4e2a\u5143\u7d20\u4ece\u5b83\u6240\u5728\u7684\u5b50\u5217\u8868\u91cc\u590d\u5236\u5230\u62f7\u8d1d\u7f13\u51b2\u533a\u53bb\uff0c\u7136\u540e\u628a\u8fd9\u4e2a\u5b50\u5217\u8868\u7684\u7d22\u5f15\u79fb\u52a8\u5230\u4e0b\u4e00\u4e2a\u5143\u7d20\uff1b \u4e0d\u65ad\u5730\u6267\u884c\u8fd9\u4e2a\u64cd\u4f5c\uff0c\u76f4\u5230\u5df2\u7ecf\u5b8c\u5168\u590d\u5236\u4e86\u4e24\u4e2a\u5b50\u5217\u8868\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u5982\u679c\u5176\u4e2d\u4e00\u4e2a\u5b50\u5217\u8868\u5df2\u7ecf\u5230\u8fbe\u4e86\u672b\u5c3e\uff0c\u90a3\u4e48\u53ef\u4ee5\u628a\u53e6\u4e00\u4e2a\u5b50\u5217\u8868\u91cc\u7684\u5176\u4f59\u5143\u7d20\u76f4\u63a5\u590d\u5236\u8fc7\u53bb\uff1b \u628a copyBuffer \u4e2d low \u5230 high \u4e4b\u95f4\u7684\u90e8\u5206\u590d\u5236\u56de lyst \u4e2d\u7684\u76f8\u5e94\u4f4d\u7f6e\uff1b \u5b9e\u73b0\u4ee3\u7801\uff1a class Array ( object ): \"\"\" \u63cf\u8ff0\u4e00\u4e2a\u6570\u7ec4\u3002 \u6570\u7ec4\u7c7b\u4f3c\u5217\u8868\uff0c\u4f46\u6570\u7ec4\u53ea\u80fd\u4f7f\u7528[], len, iter, \u548c str\u8fd9\u4e9b\u5c5e\u6027\u3002 \u5b9e\u4f8b\u5316\u4e00\u4e2a\u6570\u7ec4\uff0c\u4f7f\u7528 = Array(, ) \u5176\u4e2dfill value\u9ed8\u8ba4\u503c\u662fNone\u3002 \"\"\" def __init__ ( self , capacity , fillValue = None ): \"\"\"Capacity\u662f\u6570\u7ec4\u7684\u5927\u5c0f. fillValue\u4f1a\u586b\u5145\u5728\u6bcf\u4e2a\u5143\u7d20\u4f4d\u7f6e, \u9ed8\u8ba4\u503c\u662fNone\"\"\" self . items = list () for count in range ( capacity ): self . items . append ( fillValue ) def __len__ ( self ): \"\"\"-> \u6570\u7ec4\u7684\u5927\u5c0f\"\"\" return len ( self . items ) def __str__ ( self ): \"\"\"-> \u5c06\u6570\u7ec4\u5b57\u7b26\u4e32\u5316\"\"\" return str ( self . items ) def __iter__ ( self ): \"\"\"\u652f\u6301for\u5faa\u73af\u5bf9\u6570\u7ec4\u8fdb\u884c\u904d\u5386.\"\"\" return iter ( self . items ) def __getitem__ ( self , index ): \"\"\"\u7528\u4e8e\u8bbf\u95ee\u7d22\u5f15\u5904\u7684\u4e0b\u6807\u8fd0\u7b97\u7b26.\"\"\" return self . items [ index ] def __setitem__ ( self , index , newItem ): \"\"\"\u4e0b\u6807\u8fd0\u7b97\u7b26\u7528\u4e8e\u5728\u7d22\u5f15\u5904\u8fdb\u884c\u66ff\u6362.\"\"\" self . items [ index ] = newItem def mergeSort ( lyst ): # lyst : \u7528\u4e8e\u6392\u5e8f\u7684\u5217\u8868 # copyBuffer : \u7528\u4e8e\u5408\u5e76\u7684\u4e34\u65f6\u7a7a\u95f4 copyBuffer = Array ( len ( lyst )) mergeSortHelper ( lyst , copyBuffer , 0 , len ( lyst ) - 1 ) def mergeSortHelper ( lyst , copyBuffer , low , high ): # lyst : \u7528\u4e8e\u6392\u5e8f\u7684\u5217\u8868 # copyBuffer : \u7528\u4e8e\u5408\u5e76\u7684\u4e34\u65f6\u7a7a\u95f4 # low, high : \u5b50\u5217\u8868\u7684\u8fb9\u754c # middle : \u5b50\u5217\u8868\u7684\u4e2d\u70b9 if low < high : middle = ( low + high ) // 2 print ( f 'low: { lyst [ low ] } , middle: { lyst [ middle ] } , high: { lyst [ high ] } , copyBuffer: { copyBuffer } ' ) # \u9012\u5f52\u5904\u7406\u7b2c\u4e00\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\uff0c\u5373\u4e2d\u503c\u7684\u5de6\u6bb5\uff0c\u76f4\u81f3\u4e0d\u6ee1\u8db3low < high\u65f6\u9000\u51fa mergeSortHelper ( lyst , copyBuffer , low , middle ) # \u9012\u5f52\u5904\u7406\u7b2c\u4e8c\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\uff0c\u5373\u4e2d\u503c\u7684\u53f3\u6bb5\uff0c\u76f4\u81f3\u4e0d\u6ee1\u8db3low < high\u65f6\u9000\u51fa mergeSortHelper ( lyst , copyBuffer , middle + 1 , high ) # \u5f53\u524d\u5904\u7406\u7684\u5b50\u8868\u6570\u636e\u9001\u5165copyBuffer\uff0c\u5408\u5e76\u4e14\u6392\u5e8f merge ( lyst , copyBuffer , low , middle , high ) def merge ( lyst , copyBuffer , low , middle , high ): # lyst : \u7528\u4e8e\u6392\u5e8f\u7684\u5217\u8868 # copyBuffer : \u7528\u4e8e\u5408\u5e76\u7684\u4e34\u65f6\u7a7a\u95f4 # low : \u7b2c\u4e00\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u5f00\u5934 # middle : \u7b2c\u4e00\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u7ed3\u5c3e # middle + 1 : \u7b2c\u4e8c\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u5f00\u5934 # high : \u7b2c\u4e8c\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u7ed3\u5c3e # \u5c06 i1 \u548c i2 \u521d\u59cb\u5316\u4e3a\u6bcf\u4e2a\u5b50\u5217\u8868\u4e2d\u7684\u7b2c\u4e00\u9879 i1 = low i2 = middle + 1 # \u5c06\u5b50\u5217\u8868\u4e2d\u7684\u5143\u7d20\u4ea4\u9519\u653e\u5165copyBuffer\u4e2d\uff0c\u5e76\u4fdd\u6301\u987a\u5e8f\u3002 for i in range ( low , high + 1 ): if i1 > middle : copyBuffer [ i ] = lyst [ i2 ] # \u7b2c\u4e00\u4e2a\u5b50\u5217\u8868\u5df2\u7528\u5b8c i2 += 1 elif i2 > high : copyBuffer [ i ] = lyst [ i1 ] # \u7b2c\u4e8c\u4e2a\u5b50\u5217\u8868\u5df2\u7528\u5b8c i1 += 1 elif lyst [ i1 ] < lyst [ i2 ]: copyBuffer [ i ] = lyst [ i1 ] # \u7b2c\u4e00\u4e2a\u5b50\u8868\u4e2d\u7684\u5143\u7d20 < i1 += 1 else : copyBuffer [ i ] = lyst [ i2 ] # \u7b2c\u4e8c\u4e2a\u5b50\u8868\u4e2d\u7684\u5143\u7d20 < i2 += 1 print ( \"i=\" , i , \"\" , \"i1=\" , i1 , \"i2=\" , i2 , \"copyBuffer:\" , copyBuffer ) for i in range ( low , high + 1 ): # \u5c06\u5df2\u6392\u5e8f\u7684\u5143\u7d20\u590d\u5236\u56delyst\u4e2d\u7684\u6b63\u786e\u4f4d\u7f6e lyst [ i ] = copyBuffer [ i ] def main (): lyst = [ 12 , 19 , 17 , 18 , 14 , 11 , 15 , 13 , 16 ] print ( \"Original List\" , lyst ) mergeSort ( lyst ) print ( \"Sorted List\" , lyst ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Original List [12, 19, 17, 18, 14, 11, 15, 13, 16] # low: 12, middle: 14, high: 16, copyBuffer: [None, None, None, None, None, None, None, None, None] # low: 12, middle: 17, high: 14, copyBuffer: [None, None, None, None, None, None, None, None, None] # low: 12, middle: 19, high: 17, copyBuffer: [None, None, None, None, None, None, None, None, None] # low: 12, middle: 12, high: 19, copyBuffer: [None, None, None, None, None, None, None, None, None] # i= 1 i1= 1 i2= 2 copyBuffer: [12, 19, None, None, None, None, None, None, None] # i= 2 i1= 2 i2= 3 copyBuffer: [12, 17, 19, None, None, None, None, None, None] # low: 18, middle: 18, high: 14, copyBuffer: [12, 17, 19, None, None, None, None, None, None] # i= 4 i1= 4 i2= 5 copyBuffer: [12, 17, 19, 14, 18, None, None, None, None] # i= 4 i1= 3 i2= 5 copyBuffer: [12, 14, 17, 18, 19, None, None, None, None] # low: 11, middle: 15, high: 16, copyBuffer: [12, 14, 17, 18, 19, None, None, None, None] # low: 11, middle: 11, high: 15, copyBuffer: [12, 14, 17, 18, 19, None, None, None, None] # i= 6 i1= 6 i2= 7 copyBuffer: [12, 14, 17, 18, 19, 11, 15, None, None] # low: 13, middle: 13, high: 16, copyBuffer: [12, 14, 17, 18, 19, 11, 15, None, None] # i= 8 i1= 8 i2= 9 copyBuffer: [12, 14, 17, 18, 19, 11, 15, 13, 16] # i= 8 i1= 7 i2= 9 copyBuffer: [12, 14, 17, 18, 19, 11, 13, 15, 16] # i= 8 i1= 5 i2= 9 copyBuffer: [11, 12, 13, 14, 15, 16, 17, 18, 19] # Sorted List [11, 12, 13, 14, 15, 16, 17, 18, 19] \u8fd0\u884c\u7ed3\u679c\u56fe\u793a\u5206\u6790\uff1a 3.5.2.2.\u5f52\u5e76\u6392\u5e8f\u7684\u590d\u6742\u5ea6\u5206\u6790 \u00b6 merge \u51fd\u6570\u7684\u8fd0\u884c\u65f6\u7531\u4e24\u4e2a for \u8bed\u53e5\u6765\u51b3\u5b9a\uff0c\u800c\u8fd9\u4e24\u4e2a\u5faa\u73af\u90fd\u4f1a\u88ab\u8fed\u4ee3 (high \u2013 low + 1) \u6b21\uff0c\u56e0\u6b64\uff0c\u8fd9\u4e2a\u51fd\u6570\u7684\u8fd0\u884c\u65f6\u662f O(high\u2212low) \uff0c\u4e8e\u662f\u6bcf\u4e00\u5c42\u4e0a\u7684\u6240\u6709\u5408\u5e76\u603b\u5171\u9700\u8981 O(n) \u7684\u65f6\u95f4\u3002\u56e0\u4e3a mergeSortHelper \u5728\u6bcf\u4e00\u5c42\u90fd\u5c3d\u53ef\u80fd\u5747\u5300\u5730\u62c6\u5206\u5b50\u5217\u8868\uff0c\u6240\u4ee5\u5c42\u6570\u5e94\u8be5\u662f O(log n) \uff0c\u5728\u6240\u6709\u7684\u60c5\u51b5\u4e0b\u8fd9\u4e2a\u51fd\u6570\u7684\u6700\u5927\u8fd0\u884c\u65f6\u90fd\u662f O(n log n) \u3002 \u5f52\u5e76\u6392\u5e8f\u4f1a\u6709\u4e24\u4e2a\u57fa\u4e8e\u5217\u8868\u5927\u5c0f\u7684\u7a7a\u95f4\u9700\u6c42\u3002\u9996\u5148\uff0c\u5728\u8c03\u7528\u6808\u4e0a\u9700\u8981 O(log n) \u7684\u7a7a\u95f4\u6765\u652f\u6301\u9012\u5f52\u8c03\u7528\uff1b\u5176\u6b21\uff0c\u62f7\u8d1d\u7f13\u51b2\u533a\u4f1a\u7528\u5230 O(n) \u7684\u7a7a\u95f4\u3002 3.5.3.\u7ec3\u4e60\u9898 \u00b6 \u63cf\u8ff0\u5feb\u901f\u6392\u5e8f\u7684\u7b56\u7565\uff0c\u5e76\u8bf4\u660e\u4e3a\u4ec0\u4e48\u5b83\u53ef\u4ee5\u628a\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ece O(n^2) \u964d\u4f4e\u5230 O(n log n) \u3002 \u89e3\u7b54\uff1a\u5feb\u901f\u6392\u5e8f\uff08Quick Sort\uff09\u662f\u4e00\u79cd\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u5b83\u91c7\u7528\u5206\u6cbb\u7b56\u7565\u6765\u5c06\u4e00\u4e2a\u5927\u95ee\u9898\u5206\u89e3\u6210\u82e5\u5e72\u4e2a\u5b50\u95ee\u9898\uff0c\u7136\u540e\u9012\u5f52\u5730\u89e3\u51b3\u8fd9\u4e9b\u5b50\u95ee\u9898\u3002\u4ee5\u4e0b\u662f\u5feb\u901f\u6392\u5e8f\u7684\u7b56\u7565\u548c\u539f\u7406\uff0c\u4ee5\u53ca\u4e3a\u4ec0\u4e48\u5b83\u80fd\u591f\u5c06\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ece O(n^2) \u964d\u4f4e\u5230 O(n log n) \uff1a \u5feb\u901f\u6392\u5e8f\u7684\u7b56\u7565\uff1a \u9009\u62e9\u4e3b\u5143\uff08Pivot\uff09\uff1a\u5728\u5feb\u901f\u6392\u5e8f\u4e2d\uff0c\u9996\u5148\u4ece\u5f85\u6392\u5e8f\u7684\u5143\u7d20\u4e2d\u9009\u62e9\u4e00\u4e2a\u4e3b\u5143\uff08\u901a\u5e38\u662f\u7b2c\u4e00\u4e2a\u6216\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff09\uff0c\u4e5f\u53eb\u57fa\u51c6\u5143\u7d20\u3002 \u5206\u5272\u64cd\u4f5c\uff1a\u5c06\u5143\u7d20\u5206\u4e3a\u4e24\u4e2a\u5b50\u6570\u7ec4\uff0c\u4e00\u4e2a\u5c0f\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\uff0c\u4e00\u4e2a\u5927\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u79f0\u4e3a\u5206\u5272\u3002 \u9012\u5f52\u6392\u5e8f\uff1a\u9012\u5f52\u5730\u5bf9\u4e24\u4e2a\u5b50\u6570\u7ec4\u8fdb\u884c\u6392\u5e8f\u3002\u5373\uff0c\u5bf9\u5c0f\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\u548c\u5927\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\u5206\u522b\u8fdb\u884c\u5feb\u901f\u6392\u5e8f\u3002 \u5408\u5e76\uff1a\u5c06\u5df2\u6392\u5e8f\u7684\u5b50\u6570\u7ec4\u5408\u5e76\u6210\u6700\u7ec8\u7684\u6709\u5e8f\u6570\u7ec4\u3002 \u4e3a\u4ec0\u4e48\u5feb\u901f\u6392\u5e8f\u80fd\u591f\u964d\u4f4e\u65f6\u95f4\u590d\u6742\u5ea6\uff1a \u5feb\u901f\u6392\u5e8f\u4e4b\u6240\u4ee5\u80fd\u591f\u5c06\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ece O(n^2) \u964d\u4f4e\u5230 O(n log n) \uff0c\u4e3b\u8981\u6709\u4ee5\u4e0b\u539f\u56e0\uff1a \u5206\u6cbb\u7b56\u7565\uff1a\u5feb\u901f\u6392\u5e8f\u91c7\u7528\u4e86\u5206\u6cbb\u7b56\u7565\uff0c\u5c06\u4e00\u4e2a\u5927\u95ee\u9898\u5206\u89e3\u6210\u4e24\u4e2a\u6216\u591a\u4e2a\u89c4\u6a21\u8f83\u5c0f\u7684\u5b50\u95ee\u9898\u3002\u8fd9\u79cd\u5206\u6cbb\u7b56\u7565\u80fd\u591f\u51cf\u5c0f\u95ee\u9898\u7684\u89c4\u6a21\uff0c\u4ece\u800c\u964d\u4f4e\u4e86\u89e3\u51b3\u95ee\u9898\u7684\u590d\u6742\u5ea6\u3002 \u597d\u7684\u5e73\u5747\u60c5\u51b5\uff1a\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u5bf9\u5f85\u6392\u5e8f\u7684\u6570\u636e\u8fdb\u884c\u4e86\u826f\u597d\u7684\u5e73\u5747\u5206\u5272\uff0c\u6bcf\u6b21\u5206\u5272\u90fd\u5c06\u95ee\u9898\u89c4\u6a21\u51cf\u534a\u3002\u8fd9\u4f7f\u5f97\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n log n) \u3002 **\u4e0d\u7a33\u5b9a\u6027\uff1a\u5feb\u901f\u6392\u5e8f\u662f\u4e0d\u7a33\u5b9a\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u8fd9\u610f\u5473\u7740\u76f8\u540c\u5143\u7d20\u7684\u76f8\u5bf9\u987a\u5e8f\u5728\u6392\u5e8f\u540e\u53ef\u80fd\u4f1a\u6539\u53d8\u3002\u8fd9\u79cd\u4e0d\u7a33\u5b9a\u6027\u4f7f\u5f97\u5feb\u901f\u6392\u5e8f\u53ef\u4ee5\u66f4\u5feb\u5730\u6392\u5e8f\u76f8\u540c\u5143\u7d20\u7684\u5927\u6570\u636e\u96c6\u3002 \u539f\u5730\u6392\u5e8f\uff1a\u5feb\u901f\u6392\u5e8f\u901a\u5e38\u662f\u539f\u5730\u6392\u5e8f\u7684\uff0c\u5b83\u4e0d\u9700\u8981\u989d\u5916\u7684\u5185\u5b58\u6765\u5b58\u50a8\u4e34\u65f6\u6570\u636e\u3002\u8fd9\u5bf9\u4e8e\u5185\u5b58\u5360\u7528\u6709\u9650\u7684\u60c5\u51b5\u5f88\u6709\u5229\u3002 \u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662f O(n^2) \uff0c\u8fd9\u79cd\u60c5\u51b5\u901a\u5e38\u53d1\u751f\u5728\u4e3b\u5143\u9009\u62e9\u4e0d\u5f53\u6216\u8f93\u5165\u6570\u636e\u5df2\u7ecf\u6709\u5e8f\u7684\u60c5\u51b5\u4e0b\u3002\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u901a\u5e38\u9700\u8981\u9009\u62e9\u4e00\u4e2a\u5408\u9002\u7684\u4e3b\u5143\u9009\u62e9\u7b56\u7565\uff0c\u4ee5\u5c3d\u91cf\u907f\u514d\u6700\u574f\u60c5\u51b5\u7684\u53d1\u751f\u3002 \u4e3a\u4ec0\u4e48\u5feb\u901f\u6392\u5e8f\u5e76\u4e0d\u5728\u6240\u6709\u60c5\u51b5\u4e0b\u90fd\u6709 O(n log n) \u7684\u590d\u6742\u5ea6\uff1f\u5bf9\u5feb\u901f\u6392\u5e8f\u7684\u6700\u574f\u60c5\u51b5\u8fdb\u884c\u63cf\u8ff0\uff0c\u5e76\u7ed9\u51fa\u4e00\u4e2a\u4f1a\u4ea7\u751f\u8fd9\u4e2a\u60c5\u51b5\u7684\u5305\u542b10\u4e2a\u6574\u6570\uff081\uff5e10\uff09\u7684\u5217\u8868\u3002 \u89e3\u7b54\uff1a\u5feb\u901f\u6392\u5e8f\u5e76\u4e0d\u5728\u6240\u6709\u60c5\u51b5\u4e0b\u90fd\u5177\u6709 O(n log n) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\uff0c\u5b83\u7684\u6027\u80fd\u53d6\u51b3\u4e8e\u4e3b\u5143\uff08pivot\uff09\u7684\u9009\u62e9\u548c\u8f93\u5165\u6570\u636e\u7684\u5206\u5e03\u60c5\u51b5\u3002\u6700\u574f\u60c5\u51b5\u53d1\u751f\u5728\u4ee5\u4e0b\u60c5\u51b5\u4e0b\uff1a \u4e3b\u5143\u9009\u62e9\u4e0d\u5f53\uff1a\u5982\u679c\u6bcf\u6b21\u9009\u62e9\u7684\u4e3b\u5143\u90fd\u662f\u8f93\u5165\u6570\u636e\u4e2d\u7684\u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\uff0c\u5feb\u901f\u6392\u5e8f\u5c06\u4f1a\u4ea7\u751f\u6700\u574f\u60c5\u51b5\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5206\u5272\u64cd\u4f5c\u5c06\u5bfc\u81f4\u4e00\u4e2a\u5b50\u6570\u7ec4\u4e3a\u7a7a\uff0c\u53e6\u4e00\u4e2a\u5b50\u6570\u7ec4\u7684\u5927\u5c0f\u4e3a\u539f\u59cb\u6570\u7ec4\u5927\u5c0f\u51cf\u4e00\u3002\u8fd9\u4f7f\u5f97\u6bcf\u6b21\u5206\u5272\u64cd\u4f5c\u53ea\u51cf\u5c11\u4e00\u4e2a\u5143\u7d20\uff0c\u5bfc\u81f4\u9012\u5f52\u6df1\u5ea6\u8fbe\u5230\u6700\u5927\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \u3002 \u8f93\u5165\u6570\u636e\u5df2\u7ecf\u6709\u5e8f\uff1a\u5982\u679c\u8f93\u5165\u6570\u636e\u5df2\u7ecf\u662f\u6709\u5e8f\u7684\uff0c\u4e0d\u7ba1\u662f\u5347\u5e8f\u8fd8\u662f\u964d\u5e8f\uff0c\u5feb\u901f\u6392\u5e8f\u4e5f\u4f1a\u4ea7\u751f\u6700\u574f\u60c5\u51b5\u3002\u56e0\u4e3a\u65e0\u8bba\u5982\u4f55\u9009\u62e9\u4e3b\u5143\uff0c\u5206\u5272\u64cd\u4f5c\u90fd\u5c06\u5bfc\u81f4\u4e00\u4e2a\u5b50\u6570\u7ec4\u4e3a\u7a7a\uff0c\u53e6\u4e00\u4e2a\u5b50\u6570\u7ec4\u7684\u5927\u5c0f\u4e3a\u539f\u59cb\u6570\u7ec4\u5927\u5c0f\u51cf\u4e00\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u5305\u542b10\u4e2a\u6574\u6570\uff081\uff5e10\uff09\u7684\u5217\u8868\uff0c\u6f14\u793a\u4e86\u5bfc\u81f4\u5feb\u901f\u6392\u5e8f\u6700\u574f\u60c5\u51b5\u7684\u8f93\u5165\u6570\u636e\uff1a [ 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 ] \u5728\u8fd9\u4e2a\u793a\u4f8b\u4e2d\uff0c\u6bcf\u6b21\u9009\u62e9\u7684\u4e3b\u5143\u90fd\u662f\u6700\u5927\u7684\u5143\u7d20\uff0810\uff09\uff0c\u5bfc\u81f4\u5206\u5272\u64cd\u4f5c\u4e0d\u65ad\u51cf\u5c11\u6570\u7ec4\u7684\u5927\u5c0f\uff0c\u9012\u5f52\u6df1\u5ea6\u8fbe\u5230\u6700\u5927\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \u3002 \u8981\u907f\u514d\u6700\u574f\u60c5\u51b5\uff0c\u901a\u5e38\u91c7\u7528\u4ee5\u4e0b\u7b56\u7565\uff1a \u9009\u62e9\u5408\u9002\u7684\u4e3b\u5143\uff0c\u4f8b\u5982\u9009\u62e9\u4e2d\u95f4\u5143\u7d20\uff0c\u4ee5\u786e\u4fdd\u5e73\u5747\u5206\u5272\u3002 \u968f\u673a\u9009\u62e9\u4e3b\u5143\uff0c\u4ee5\u51cf\u5c11\u51fa\u73b0\u6700\u574f\u60c5\u51b5\u7684\u6982\u7387\u3002 \u8fd9\u4e9b\u7b56\u7565\u6709\u52a9\u4e8e\u7ef4\u6301\u5feb\u901f\u6392\u5e8f\u7684\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n log n) \u3002 \u5feb\u901f\u6392\u5e8f\u91cc\u7684\u5206\u5272\u64cd\u4f5c\u4f1a\u9009\u62e9\u4e2d\u70b9\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\u3002\u8bf7\u63cf\u8ff0\u53e6\u5916\u4e24\u79cd\u9009\u62e9\u57fa\u51c6\u7684\u7b56\u7565\u3002 \u89e3\u7b54\uff1a\u5feb\u901f\u6392\u5e8f\u4e2d\u7684\u5206\u5272\u64cd\u4f5c\u53ef\u4ee5\u9009\u62e9\u4e2d\u70b9\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\uff0c\u4f46\u8fd8\u6709\u5176\u4ed6\u4e24\u79cd\u5e38\u89c1\u7684\u9009\u62e9\u57fa\u51c6\u7684\u7b56\u7565\uff0c\u5b83\u4eec\u5206\u522b\u662f\uff1a \u968f\u673a\u9009\u62e9\u57fa\u51c6\uff08Random Pivot\uff09\uff1a\u8fd9\u79cd\u7b56\u7565\u662f\u5728\u5f85\u6392\u5e8f\u6570\u7ec4\u4e2d\u968f\u673a\u9009\u62e9\u4e00\u4e2a\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\u3002\u968f\u673a\u9009\u62e9\u57fa\u51c6\u7684\u597d\u5904\u662f\u53ef\u4ee5\u964d\u4f4e\u51fa\u73b0\u6700\u574f\u60c5\u51b5\u7684\u6982\u7387\uff0c\u56e0\u4e3a\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u968f\u673a\u9009\u62e9\u7684\u57fa\u51c6\u4f1a\u6bd4\u56fa\u5b9a\u4f4d\u7f6e\u7684\u57fa\u51c6\u66f4\u5e73\u5747\u5730\u5212\u5206\u6570\u636e\u3002\u8fd9\u53ef\u4ee5\u63d0\u9ad8\u7b97\u6cd5\u7684\u6027\u80fd\u3002 \u4e09\u6570\u53d6\u4e2d\u6cd5\uff08Median-of-Three Pivot\uff09\uff1a\u8fd9\u79cd\u7b56\u7565\u662f\u5728\u5f85\u6392\u5e8f\u6570\u7ec4\u4e2d\u9009\u62e9\u4e09\u4e2a\u5143\u7d20\uff08\u901a\u5e38\u662f\u7b2c\u4e00\u4e2a\u3001\u4e2d\u95f4\u4e00\u4e2a\u548c\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff09\uff0c\u7136\u540e\u4ece\u8fd9\u4e09\u4e2a\u5143\u7d20\u4e2d\u9009\u62e9\u4e2d\u95f4\u503c\u4f5c\u4e3a\u57fa\u51c6\u3002\u8fd9\u4e2a\u7b56\u7565\u7684\u76ee\u7684\u662f\u5728\u5c3d\u91cf\u907f\u514d\u6700\u574f\u60c5\u51b5\u7684\u540c\u65f6\uff0c\u4fdd\u6301\u57fa\u51c6\u7684\u76f8\u5bf9\u4e2d\u95f4\u4f4d\u7f6e\u3002\u8fd9\u53ef\u4ee5\u63d0\u9ad8\u7b97\u6cd5\u7684\u5e73\u5747\u6027\u80fd\u3002 \u8fd9\u4e09\u79cd\u9009\u62e9\u57fa\u51c6\u7684\u7b56\u7565\u5404\u6709\u4f18\u52a3\uff0c\u4f46\u5b83\u4eec\u7684\u5171\u540c\u76ee\u6807\u662f\u964d\u4f4e\u6700\u574f\u60c5\u51b5\u7684\u6982\u7387\uff0c\u4ece\u800c\u63d0\u9ad8\u5feb\u901f\u6392\u5e8f\u7684\u6027\u80fd\u3002\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u9009\u62e9\u54ea\u79cd\u7b56\u7565\u53d6\u51b3\u4e8e\u5177\u4f53\u7684\u60c5\u51b5\u548c\u5b9e\u73b0\u3002 \u5f53\u5feb\u901f\u6392\u5e8f\u91cc\u7684\u5b50\u5217\u8868\u7684\u957f\u5ea6\u5c0f\u4e8e\u67d0\u4e2a\u6570\u5b57\uff08\u598230\uff09\u65f6\uff0c\u6267\u884c\u63d2\u5165\u6392\u5e8f\u6765\u5904\u7406\u8fd9\u4e2a\u5b50\u5217\u8868\u3002\u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u8fd9\u662f\u4e00\u4e2a\u597d\u65b9\u6cd5\u3002 \u89e3\u7b54\uff1a\u5728\u5feb\u901f\u6392\u5e8f\u4e2d\uff0c\u5f53\u5b50\u5217\u8868\u7684\u957f\u5ea6\u53d8\u5f97\u5f88\u5c0f\u65f6\uff08\u901a\u5e38\u5c0f\u4e8e\u67d0\u4e2a\u9884\u5b9a\u7684\u9608\u503c\uff0c\u598230\u6216\u5176\u4ed6\u7ecf\u9a8c\u503c\uff09\uff0c\u6267\u884c\u63d2\u5165\u6392\u5e8f\u6765\u5904\u7406\u8fd9\u4e2a\u5b50\u5217\u8868\u662f\u4e00\u4e2a\u597d\u65b9\u6cd5\uff0c\u4e3b\u8981\u57fa\u4e8e\u4ee5\u4e0b\u8003\u8651\uff1a \u63d2\u5165\u6392\u5e8f\u5bf9\u5c0f\u89c4\u6a21\u6570\u636e\u8868\u73b0\u826f\u597d\uff1a\u63d2\u5165\u6392\u5e8f\u662f\u4e00\u79cd\u7b80\u5355\u4f46\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u7279\u522b\u9002\u7528\u4e8e\u5c0f\u89c4\u6a21\u6570\u636e\u96c6\u3002\u5b83\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \uff0c\u4f46\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u5bf9\u4e8e\u5c0f\u89c4\u6a21\u7684\u6570\u636e\uff0c\u5b83\u7684\u6027\u80fd\u901a\u5e38\u5f88\u597d\u3002 \u51cf\u5c11\u9012\u5f52\u6df1\u5ea6\uff1a\u5728\u5feb\u901f\u6392\u5e8f\u4e2d\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u90fd\u4f1a\u589e\u52a0\u9012\u5f52\u6df1\u5ea6\uff0c\u800c\u9012\u5f52\u6df1\u5ea6\u8fc7\u5927\u53ef\u80fd\u4f1a\u5bfc\u81f4\u6808\u6ea2\u51fa\u6216\u6027\u80fd\u4e0b\u964d\u3002\u5f53\u5b50\u5217\u8868\u957f\u5ea6\u5c0f\u4e8e\u67d0\u4e2a\u9608\u503c\u65f6\uff0c\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u53ef\u4ee5\u907f\u514d\u4e0d\u5fc5\u8981\u7684\u9012\u5f52\u6df1\u5ea6\uff0c\u4ece\u800c\u51cf\u5c11\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u3002 \u9002\u7528\u4e8e\u90e8\u5206\u6709\u5e8f\u7684\u5b50\u5217\u8868\uff1a\u5f53\u5b50\u5217\u8868\u5df2\u7ecf\u90e8\u5206\u6709\u5e8f\u65f6\uff0c\u63d2\u5165\u6392\u5e8f\u7684\u6027\u80fd\u901a\u5e38\u6bd4\u5feb\u901f\u6392\u5e8f\u66f4\u597d\u3002\u56e0\u6b64\uff0c\u5bf9\u4e8e\u53ef\u80fd\u5305\u542b\u5df2\u6392\u5e8f\u90e8\u5206\u7684\u5c0f\u5b50\u5217\u8868\uff0c\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u53ef\u4ee5\u63d0\u9ad8\u7b97\u6cd5\u7684\u6548\u7387\u3002 \u51cf\u5c11\u9012\u5f52\u5f00\u9500\uff1a\u9012\u5f52\u5f00\u9500\u662f\u5feb\u901f\u6392\u5e8f\u7684\u4e00\u4e2a\u4e0d\u53ef\u5ffd\u89c6\u7684\u56e0\u7d20\uff0c\u7279\u522b\u662f\u5728\u5904\u7406\u5c0f\u89c4\u6a21\u5b50\u5217\u8868\u65f6\u3002\u901a\u8fc7\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u6765\u5904\u7406\u8fd9\u4e9b\u5c0f\u89c4\u6a21\u5b50\u5217\u8868\uff0c\u53ef\u4ee5\u51cf\u5c11\u9012\u5f52\u5f00\u9500\uff0c\u63d0\u9ad8\u7b97\u6cd5\u7684\u6574\u4f53\u6027\u80fd\u3002 \u5c06\u63d2\u5165\u6392\u5e8f\u4e0e\u5feb\u901f\u6392\u5e8f\u7ed3\u5408\u4f7f\u7528\u662f\u4e00\u79cd\u5e38\u89c1\u7684\u4f18\u5316\u7b56\u7565\uff0c\u5b83\u53ef\u4ee5\u5728\u5904\u7406\u5c0f\u89c4\u6a21\u5b50\u5217\u8868\u65f6\u63d0\u9ad8\u7b97\u6cd5\u7684\u6548\u7387\uff0c\u540c\u65f6\u4fdd\u6301\u5feb\u901f\u6392\u5e8f\u7684\u6574\u4f53\u6027\u80fd\u3002\u8fd9\u79cd\u65b9\u6cd5\u88ab\u79f0\u4e3a\u201c\u5feb\u901f\u6392\u5e8f\u7684\u6539\u8fdb\u201d\u6216\u201c\u5feb\u901f\u6392\u5e8f\u7684\u6df7\u5408\u6392\u5e8f\u201d\u7b56\u7565\uff0c\u7528\u4e8e\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\u63d0\u9ad8\u7b97\u6cd5\u7684\u6548\u7387\u3002 \u4e3a\u4ec0\u4e48\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4e5f\u662f\u4e00\u4e2a O(n log n) \u7b97\u6cd5\uff1f \u89e3\u7b54\uff1a\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4ecd\u7136\u5177\u6709 O(n log n) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\uff0c\u8fd9\u662f\u56e0\u4e3a\u5f52\u5e76\u6392\u5e8f\u7684\u7b97\u6cd5\u8bbe\u8ba1\u4f7f\u5176\u80fd\u591f\u7a33\u5b9a\u5730\u4fdd\u6301\u8fd9\u79cd\u6027\u80fd\uff0c\u4e0d\u53d7\u8f93\u5165\u6570\u636e\u5206\u5e03\u7684\u5f71\u54cd\u3002 \u4ee5\u4e0b\u662f\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4ecd\u7136\u5177\u6709 O(n log n) \u65f6\u95f4\u590d\u6742\u5ea6\u7684\u539f\u56e0\uff1a \u5206\u800c\u6cbb\u4e4b\u7b56\u7565\uff1a\u5f52\u5e76\u6392\u5e8f\u91c7\u7528\u4e86\u5206\u800c\u6cbb\u4e4b\u7684\u7b56\u7565\uff0c\u5c06\u95ee\u9898\u5206\u89e3\u4e3a\u8f83\u5c0f\u7684\u5b50\u95ee\u9898\uff0c\u7136\u540e\u5408\u5e76\u8fd9\u4e9b\u5b50\u95ee\u9898\u7684\u89e3\u3002\u8fd9\u4e2a\u7b56\u7565\u786e\u4fdd\u4e86\u7b97\u6cd5\u7684\u9012\u5f52\u6df1\u5ea6\u5728 log n \u7ea7\u522b\uff0c\u56e0\u4e3a\u6bcf\u6b21\u9012\u5f52\u90fd\u5c06\u6570\u636e\u5212\u5206\u6210\u4e24\u534a\uff0c\u76f4\u5230\u6700\u5c0f\u5b50\u95ee\u9898\u7684\u5927\u5c0f\u4e3a1\u3002 \u5408\u5e76\u64cd\u4f5c\u7684\u7ebf\u6027\u65f6\u95f4\uff1a\u5f52\u5e76\u6392\u5e8f\u7684\u5173\u952e\u64cd\u4f5c\u662f\u5408\u5e76\u5df2\u6392\u5e8f\u7684\u5b50\u6570\u7ec4\u3002\u5408\u5e76\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f\u7ebf\u6027\u7684\uff0c\u4e0e\u8f93\u5165\u6570\u636e\u7684\u89c4\u6a21 n \u6210\u6b63\u6bd4\u3002\u56e0\u6b64\uff0c\u5373\u4f7f\u5728\u5408\u5e76\u9636\u6bb5\uff0c\u7b97\u6cd5\u7684\u603b\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u53d7\u9650\u4e8e O(n log n) \u3002 \u7a33\u5b9a\u6027\uff1a\u5f52\u5e76\u6392\u5e8f\u662f\u4e00\u79cd\u7a33\u5b9a\u6392\u5e8f\u7b97\u6cd5\uff0c\u610f\u5473\u7740\u5b83\u5728\u6392\u5e8f\u76f8\u7b49\u5143\u7d20\u65f6\u4f1a\u4fdd\u6301\u5b83\u4eec\u7684\u76f8\u5bf9\u987a\u5e8f\u3002\u8fd9\u4e00\u6027\u8d28\u4f7f\u5f97\u7b97\u6cd5\u5728\u5904\u7406\u76f8\u7b49\u5143\u7d20\u6216\u8005\u5177\u6709\u7279\u5b9a\u6570\u636e\u5206\u5e03\u7684\u60c5\u51b5\u4e0b\u4ecd\u7136\u4fdd\u6301 O(n log n) \u7684\u6027\u80fd\uff0c\u800c\u4e0d\u4f1a\u51fa\u73b0\u6700\u574f\u60c5\u51b5\u3002 \u65e0\u8bba\u8f93\u5165\u6570\u636e\u5982\u4f55\u5206\u5e03\uff0c\u5f52\u5e76\u6392\u5e8f\u7684\u5206\u5272\u548c\u5408\u5e76\u64cd\u4f5c\u90fd\u662f\u786e\u5b9a\u6027\u7684\uff1a\u5f52\u5e76\u6392\u5e8f\u7684\u6bcf\u4e00\u6b65\u90fd\u662f\u786e\u5b9a\u6027\u7684\uff0c\u4e0d\u53d7\u8f93\u5165\u6570\u636e\u5206\u5e03\u7684\u5f71\u54cd\u3002\u4e0d\u50cf\u5feb\u901f\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u53ef\u80fd\u51fa\u73b0\u5206\u5272\u6781\u4e0d\u5e73\u8861\u7684\u60c5\u51b5\uff0c\u5bfc\u81f4\u6027\u80fd\u4e0b\u964d\u3002 \u56e0\u6b64\uff0c\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4ecd\u7136\u80fd\u591f\u4fdd\u6301 O(n log n) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\uff0c\u4f7f\u5176\u6210\u4e3a\u4e00\u79cd\u53ef\u9760\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u7279\u522b\u9002\u7528\u4e8e\u5bf9\u7a33\u5b9a\u6027\u548c\u6027\u80fd\u6709\u8981\u6c42\u7684\u60c5\u51b5\u3002 3.6.\u6307\u6570\u590d\u6742\u5ea6\u7684\u7b97\u6cd5 \u00b6 \u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7b97\u6cd5 \u00b6 \u4e0b\u9762\u662f\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7b97\u6cd5\u7684\u4f8b\u5b50\u3002 def fib ( n , depth = 0 ): \"\"\"\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u6570\u5217\"\"\" if n <= 1 : return 1 else : print ( f 'Depth: { depth } ,fib( { n } ) calls fib( { n - 1 } ) and fib( { n - 2 } )' ) return fib ( n - 1 , depth + 1 ) + fib ( n - 2 , depth + 1 ) def main (): fib ( 6 ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Depth:0,fib(6) calls fib(5) and fib(4) # Depth:1,fib(5) calls fib(4) and fib(3) # Depth:2,fib(4) calls fib(3) and fib(2) # Depth:3,fib(3) calls fib(2) and fib(1) # Depth:4,fib(2) calls fib(1) and fib(0) # Depth:3,fib(2) calls fib(1) and fib(0) # Depth:2,fib(3) calls fib(2) and fib(1) # Depth:3,fib(2) calls fib(1) and fib(0) # Depth:1,fib(4) calls fib(3) and fib(2) # Depth:2,fib(3) calls fib(2) and fib(1) # Depth:3,fib(2) calls fib(1) and fib(0) # Depth:2,fib(2) calls fib(1) and fib(0) \u4e0a\u4f8b\u53ef\u4ee5\u770b\u51fa\uff0c\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7b97\u6cd5\u7684\u8c03\u7528\u6b21\u6570\u6bd4\u95ee\u9898\u89c4\u6a21\u7684\u5e73\u65b9\u6570\u589e\u957f\u7684\u8fd8\u8981\u5feb\u5f88\u591a\u3002\u4f8b\u5982\uff0c fib(4) \u53ea\u9700\u89814\u6b21\u9012\u5f52\u8c03\u7528\uff0c\u770b\u8d77\u6765\u5b83\u597d\u50cf\u662f\u7ebf\u6027\u589e\u957f\u7684\uff0c\u4f46\u5728\u603b\u5171\u768414\u6b21\u9012\u5f52\u8c03\u7528\u91cc\uff0c fib(6) \u9700\u8981\u8c03\u75282\u6b21 fib(4) \u3002\u968f\u7740\u95ee\u9898\u89c4\u6a21\u7684\u6269\u5927\uff0c\u5de5\u4f5c\u91cf\u4f1a\u663e\u8457\u589e\u52a0\uff0c\u8fd9\u662f\u56e0\u4e3a\u5728\u8c03\u7528\u6811\uff08call tree\uff09\u91cc\u53ef\u80fd\u6709\u5f88\u591a\u91cd\u590d\u7684\u76f8\u540c\u5b50\u6811\u3002 \u5982\u679c\u8fd9\u68f5\u8c03\u7528\u6811\u662f\u5b8c\u5168\u5e73\u8861\u7684\uff0c\u5e76\u4e14\u5b8c\u5168\u586b\u5145\u4e86\u6700\u4e0b\u9762\u7684\u4e24\u5c42\u8c03\u7528\uff0c\u90a3\u4e48\u5f53\u53c2\u6570\u4e3a6\u65f6\uff0c\u4f1a\u67092 + 4 + 8 + 16 = 30\u6b21\u9012\u5f52\u8c03\u7528\u3002\u6bcf\u4e00\u5c42\u91cc\u7684\u6ee1\u8c03\u7528\u6570\u91cf\u90fd\u662f\u5b83\u4e0a\u4e00\u5c42\u76842\u500d\u3002\u56e0\u6b64\uff0c\u5728\u5b8c\u5168\u5e73\u8861\u7684\u8c03\u7528\u6811\u91cc\uff0c\u9012\u5f52\u8c03\u7528\u7684\u603b\u6570\u91cf\u901a\u5e38\u662f 2^(n+1)-2 \uff0c\u5176\u4e2d n \u662f\u8c03\u7528\u6811\u9876\u90e8\uff08\u6839\uff09\u7684\u53c2\u6570\u3002\u8fd9\u662f\u4e00\u4e2a\u6307\u6570\u7ea7\u7684\u589e\u957f\uff0c\u4e5f\u5c31\u662f O(k^n) \u7b97\u6cd5\u3002 \u5c3d\u7ba1\u5728\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u8c03\u7528\u6811\u7684\u5e95\u90e8\u4e24\u5c42\u5e76\u6ca1\u6709\u88ab\u5b8c\u5168\u586b\u5145\u6ee1\uff0c\u4f46\u5b83\u7684\u8c03\u7528\u6811\u5f62\u72b6\u548c\u5b8c\u5168\u5e73\u8861\u7684\u6811\u5df2\u7ecf\u8db3\u591f\u76f8\u8fd1\u4e86\uff0c\u56e0\u6b64\uff0c\u53ef\u4ee5\u628a\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u5f52\u4e3a\u6307\u6570\u7b97\u6cd5\u3002\u7ecf\u8fc7\u8ba1\u7b97\uff0c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u7684\u5e38\u6570 k \u5927\u7ea6\u662f1.63\u3002 \u6307\u6570\u7b97\u6cd5\u901a\u5e38\u53ea\u9002\u5408\u7528\u4e8e\u975e\u5e38\u5c0f\u7684\u95ee\u9898\u89c4\u6a21\u3002 \u5c06\u6590\u6ce2\u90a3\u5951\u8f6c\u6362\u4e3a\u7ebf\u6027\u7b97\u6cd5 \u00b6 \u4e0b\u9762\u7684\u4ee3\u7801\u7528\u7ebf\u6027\u7b97\u6cd5\u6539\u5199\u4e86\u4e0a\u9762\u7684\u9012\u5f52\u7b97\u6cd5\u3002\u5b83\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\u3002 def fibonacci_linear ( n ): if n <= 1 : return 1 prev , current = 0 , 1 for _ in range ( 2 , n + 1 ): next_value = prev + current prev , current = current , next_value return current def main (): n = 6 result = fibonacci_linear ( n ) print ( f \"Fibonacci( { n } ) = { result } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Fibonacci(6) = 8 3.7.\u6848\u4f8b\u7814\u7a76:\u7b97\u6cd5\u5206\u6790\u5668 \u00b6 \u76ee\u6807\uff1a\u7f16\u5199\u4e00\u4e2a\u53ef\u4ee5\u7528\u6765\u5206\u6790\u4e0d\u540c\u6392\u5e8f\u7b97\u6cd5\u7684\u7a0b\u5e8f\u3002 \u9700\u6c42\uff1a \u5206\u6790\u5668\u53ef\u4ee5\u8fd0\u884c\u6392\u5e8f\u7b97\u6cd5\u4ee5\u5bf9\u6570\u5b57\u5217\u8868\u8fdb\u884c\u6392\u5e8f\uff1b \u5206\u6790\u5668\u53ef\u4ee5\u8ffd\u8e2a\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u3001\u6bd4\u8f83\u6b21\u6570\u4ee5\u53ca\u6267\u884c\u4ea4\u6362\u7684\u6b21\u6570\uff1b \u5f53\u7b97\u6cd5\u4ea4\u6362\u4e24\u4e2a\u503c\u7684\u65f6\u5019\uff0c\u5206\u6790\u5668\u53ef\u4ee5\u6253\u5370\u51fa\u5217\u8868\u7684\u53d8\u5316\u8f68\u8ff9\uff1b \u5141\u8bb8\u7ed9\u5206\u6790\u5668\u63d0\u4f9b\u81ea\u5b9a\u4e49\u7684\u6570\u5b57\u5217\u8868\uff0c\u6216\u8005\u751f\u6210\u4e00\u4e2a\u5927\u5c0f\u7ed9\u5b9a\u7684\u968f\u673a\u6570\u5b57\u5217\u8868\uff1b\u5141\u8bb8\u5217\u8868\u53ea\u5305\u542b\u4e00\u4e2a\u6570\u5b57\uff0c\u6216\u8005\u5305\u542b\u91cd\u590d\u6570\u503c\uff1b \u5728\u8fd0\u884c\u7b97\u6cd5\u4e4b\u524d\uff0c\u5141\u8bb8\u7528\u6237\u9009\u62e9\u4e0a\u8ff0\u8fd9\u4e9b\u529f\u80fd\uff1b \u5206\u6790\u5668\u7684\u9ed8\u8ba4\u884c\u4e3a\u662f\u5728\u4e00\u4e2a\u5305\u542b10\u4e2a\u4e0d\u91cd\u590d\u6570\u5b57\u7684\u968f\u673a\u5217\u8868\u4e0a\u8fd0\u884c\u7b97\u6cd5\uff0c\u5e76\u8bb0\u5f55\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u3001\u6bd4\u8f83\u6b21\u6570\u4ee5\u53ca\u4ea4\u6362\u6b21\u6570\uff1b \u5b9e\u73b0\uff1a \u5206\u6790\u5668\u662f Profiler \u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\u3002\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u8fd0\u884c\u5206\u6790\u5668\u91cc\u7684 test \u65b9\u6cd5\u6765\u5206\u6790\u6392\u5e8f\u51fd\u6570\uff0c\u8fd9\u4e2a\u6392\u5e8f\u51fd\u6570\u4f1a\u4f5c\u4e3a\u65b9\u6cd5\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\uff0c\u4e0a\u9762\u9700\u6c42\u4e2d\u63d0\u5230\u7684\u90a3\u4e9b\u9009\u9879\u4e5f\u4f1a\u4f5c\u4e3a\u53c2\u6570\u540c\u65f6\u4f20\u9012\u7ed9\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u4e24\u4e2a\u6a21\u5757\uff1a profiler \uff1a\u8fd9\u4e2a\u6a21\u5757\u4f1a\u5b9a\u4e49 Profiler \u7c7b\u3002 algorithms \uff1a\u8fd9\u4e2a\u6a21\u5757\u5b9a\u4e49\u9488\u5bf9\u5206\u6790\u5668\u4fee\u6539\u8fc7\u7684\u6392\u5e8f\u51fd\u6570\u3002 import time import random class Profiler ( object ): \"\"\" \u5b9a\u4e49\u4e00\u4e2aProfiler\u7c7b, \u7528\u6765\u5206\u6790\u6392\u5e8f\u7b97\u6cd5\u3002 Profiler\u5bf9\u8c61\u8ddf\u8e2a\u4e00\u4e2a\u5217\u8868\u7684\u6bd4\u8f83\u6b21\u6570\u3001\u4ea4\u6362\u6b21\u6570\u3001\u548c\u8fd0\u884c\u65f6\u95f4\u3002 Profiler\u5bf9\u8c61\u4e5f\u80fd\u8f93\u51fa\u4e0a\u8ff0\u8ffd\u8e2a\u4fe1\u606f, \u5e76\u521b\u5efa\u4e00\u4e2a\u542b\u6709\u91cd\u590d\u6216\u4e0d\u91cd\u590d\u6570\u5b57\u7684\u5217\u8868\u3002 \u793a\u4f8b\uff1a from profiler import Profiler from algorithms import selectionSort p = Profiler() p.test(selectionSort, size = 15, comp = True, exch = True, trace = True) \"\"\" def test ( self , function , lyst = None , size = 10 , unique = True , comp = True , exch = True , trace = False ): \"\"\" function: \u914d\u7f6e\u7684\u7b97\u6cd5 target: \u914d\u7f6e\u7684\u641c\u7d22\u76ee\u6807 lyst: \u5141\u8bb8\u8c03\u7528\u8005\u4f7f\u7528\u7684\u5217\u8868 size: \u5217\u8868\u7684\u5927\u5c0f, \u9ed8\u8ba4\u503c\u662f10 unique: \u5982\u679c\u662fTrue, \u5219\u5217\u8868\u5305\u542b\u4e0d\u91cd\u590d\u7684\u6574\u6570 comp: \u5982\u679c\u662fTrue, \u5219\u7edf\u8ba1\u6bd4\u8f83\u6b21\u6570 exch: \u5982\u679c\u662fTrue, \u5219\u7edf\u8ba1\u4ea4\u6362\u6b21\u6570 trace: \u5982\u679c\u662fTrue, \u5219\u5728\u6bcf\u6b21\u4ea4\u6362\u540e\u90fd\u8f93\u51fa\u5217\u8868\u5185\u5bb9 \u6b64\u51fd\u6570\u4f9d\u636e\u7ed9\u5b9a\u7684\u4e0a\u8ff0\u5c5e\u6027, \u6253\u5370\u8f93\u51fa\u76f8\u5e94\u7684\u7ed3\u679c \"\"\" self . comp = comp self . exch = exch self . trace = trace if lyst != None : self . lyst = lyst elif unique : self . lyst = list ( range ( 1 , size + 1 )) random . shuffle ( self . lyst ) else : self . lyst = [] for count in range ( size ): self . lyst . append ( random . randint ( 1 , size )) self . exchCount = 0 self . cmpCount = 0 self . startClock () function ( self . lyst , self ) self . stopClock () print ( self ) def exchange ( self ): \"\"\"\u7edf\u8ba1\u4ea4\u6362\u6b21\u6570\"\"\" if self . exch : self . exchCount += 1 if self . trace : print ( self . lyst ) def comparison ( self ): \"\"\"\u7edf\u8ba1\u4ea4\u6362\u6b21\u6570\"\"\" if self . comp : self . cmpCount += 1 def startClock ( self ): \"\"\"\u8bb0\u5f55\u5f00\u59cb\u65f6\u95f4\"\"\" self . start = time . time () def stopClock ( self ): \"\"\"\u505c\u6b62\u8ba1\u65f6\u5e76\u4ee5\u79d2\u4e3a\u5355\u4f4d\u8ba1\u7b97\u6d88\u8017\u65f6\u95f4\"\"\" self . elapsedTime = round ( time . time () - self . start , 3 ) def __str__ ( self ): \"\"\"\u4ee5\u5b57\u7b26\u4e32\u65b9\u5f0f\u8fd4\u56de\u7ed3\u679c\"\"\" result = \"Problem size: \" result += str ( len ( self . lyst )) + \" \\n \" result += \"Elapsed time: \" result += str ( self . elapsedTime ) + \" \\n \" if self . comp : result += \"Comparisons: \" result += str ( self . cmpCount ) + \" \\n \" if self . exch : result += \"Exchanges: \" result += str ( self . exchCount ) + \" \\n \" return result def selectionSort ( lyst , profiler ): i = 0 while i < len ( lyst ) - 1 : minIndex = i j = i + 1 while j < len ( lyst ): profiler . comparison () # Count if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : swap ( lyst , minIndex , i , profiler ) i += 1 def swap ( lyst , i , j , profiler ): \"\"\"\u4ea4\u6362\u5904\u4e8e\u4f4d\u7f6ei\u548cj\u7684\u5143\u7d20\"\"\" profiler . exchange () # Count temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def main (): p = Profiler () # \u9ed8\u8ba4\u884c\u4e3a print ( \"The result of p.test(selectionSort)\" ) p . test ( selectionSort ) print ( \"The result of p.test(selectionSort, size=5, trace=True)\" ) p . test ( selectionSort , size = 5 , trace = True ) print ( \"The result of p.test(selectionSort, size=100)\" ) p . test ( selectionSort , size = 100 ) print ( \"The result of p.test(selectionSort, size=1000)\" ) p . test ( selectionSort , size = 1000 ) print ( \"The result of p.test(selectionSort, size=10000, exch=False, comp=False)\" ) p . test ( selectionSort , size = 10000 , exch = False , comp = False ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # The result of p.test(selectionSort) # Problem size: 20 # Elapsed time: 0.0 # Comparisons: 190 # Exchanges: 12 # The result of p.test(selectionSort, size=5, trace=True) # [5, 1, 4, 3, 2, 1, 1, 2, 4, 4] # [1, 5, 4, 3, 2, 1, 1, 2, 4, 4] # [1, 1, 4, 3, 2, 5, 1, 2, 4, 4] # [1, 1, 1, 3, 2, 5, 4, 2, 4, 4] # [1, 1, 1, 2, 3, 5, 4, 2, 4, 4] # [1, 1, 1, 2, 2, 5, 4, 3, 4, 4] # [1, 1, 1, 2, 2, 3, 4, 5, 4, 4] # [1, 1, 1, 2, 2, 3, 4, 4, 5, 4] # Problem size: 10 # Elapsed time: 0.0 # Comparisons: 45 # Exchanges: 8 # The result of p.test(selectionSort, size=100) # Problem size: 200 # Elapsed time: 0.003 # Comparisons: 19900 # Exchanges: 195 # The result of p.test(selectionSort, size=1000) # Problem size: 2000 # Elapsed time: 0.36 # Comparisons: 1999000 # Exchanges: 1992 # The result of p.test(selectionSort, size=10000, exch=False, comp=False) # Problem size: 20000 # Elapsed time: 26.535 3.8.\u5c0f\u7ed3 \u00b6 \u6839\u636e\u6240\u9700\u8981\u7684\u65f6\u95f4\u548c\u5185\u5b58\u8d44\u6e90\uff0c\u6211\u4eec\u53ef\u4ee5\u5bf9\u89e3\u51b3\u540c\u4e00\u4e2a\u95ee\u9898\u7684\u4e0d\u540c\u7b97\u6cd5\u8fdb\u884c\u6392\u540d\u3002\u4e0e\u9700\u8981\u66f4\u591a\u8d44\u6e90\u7684\u7b97\u6cd5\u76f8\u6bd4\uff0c\u6211\u4eec\u901a\u5e38\u8ba4\u4e3a\u8017\u8d39\u66f4\u5c11\u8fd0\u884c\u65f6\u548c\u5360\u7528\u66f4\u5c11\u5185\u5b58\u7684\u7b97\u6cd5\u66f4\u597d\u3002\u4f46\u662f\uff0c\u8fd9\u4e24\u79cd\u8d44\u6e90\u4e5f\u901a\u5e38\u9700\u8981\u8fdb\u884c\u6743\u8861\u53d6\u820d\uff1a\u6709\u65f6\u4ee5\u66f4\u591a\u5185\u5b58\u4e3a\u4ee3\u4ef7\u6765\u6539\u5584\u8fd0\u884c\u65f6\uff1b\u6709\u65f6\u4ee5\u8f83\u6162\u7684\u8fd0\u884c\u65f6\u4f5c\u4e3a\u4ee3\u4ef7\u6765\u63d0\u9ad8\u5185\u5b58\u7684\u4f7f\u7528\u7387\u3002 \u53ef\u4ee5\u6839\u636e\u8ba1\u7b97\u673a\u7684\u65f6\u949f\u6309\u7167\u8fc7\u5f80\u7ecf\u9a8c\u6d4b\u7b97\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u3002\u4f46\u662f\uff0c\u8fd9\u4e2a\u65f6\u95f4\u4f1a\u968f\u7740\u786c\u4ef6\u548c\u6240\u7528\u7f16\u7a0b\u8bed\u8a00\u7684\u4e0d\u540c\u800c\u53d8\u5316\u3002 \u7edf\u8ba1\u6307\u4ee4\u7684\u6570\u91cf\u63d0\u4f9b\u4e86\u53e6\u4e00\u79cd\u5bf9\u7b97\u6cd5\u6240\u9700\u5de5\u4f5c\u91cf\u8fdb\u884c\u7ecf\u9a8c\u6027\u5ea6\u91cf\u7684\u65b9\u5f0f\u3002\u6307\u4ee4\u7684\u8ba1\u6570\u53ef\u4ee5\u663e\u793a\u51fa\u7b97\u6cd5\u5de5\u4f5c\u91cf\u7684\u589e\u957f\u7387\u7684\u53d8\u5316\uff0c\u800c\u4e14\u8fd9\u4e2a\u6570\u636e\u548c\u786c\u4ef6\u4ee5\u53ca\u8f6f\u4ef6\u5e73\u53f0\u90fd\u6ca1\u6709\u5173\u7cfb\u3002 \u7b97\u6cd5\u5de5\u4f5c\u91cf\u7684\u589e\u957f\u7387\u53ef\u4ee5\u7528\u57fa\u4e8e\u95ee\u9898\u89c4\u6a21\u7684\u51fd\u6570\u6765\u8868\u793a\u3002\u590d\u6742\u5ea6\u5206\u6790\u67e5\u770b\u7b97\u6cd5\u91cc\u7684\u4ee3\u7801\u4ee5\u5f97\u5230\u8fd9\u4e9b\u6570\u5b66\u8868\u8fbe\u5f0f\uff0c\u4ece\u800c\u8ba9\u7a0b\u5e8f\u5458\u9884\u6d4b\u5728\u4efb\u4f55\u8ba1\u7b97\u673a\u4e0a\u6267\u884c\u8fd9\u4e2a\u7b97\u6cd5\u7684\u6548\u679c\u3002 \u5927O\u8868\u793a\u6cd5\u662f\u7528\u6765\u8868\u793a\u7b97\u6cd5\u8fd0\u884c\u65f6\u884c\u4e3a\u7684\u5e38\u7528\u65b9\u6cd5\u3002\u5b83\u7528 O(f(n)) \u7684\u5f62\u5f0f\u6765\u8868\u793a\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u6240\u9700\u8981\u7684\u5de5\u4f5c\u91cf\uff0c\u5176\u4e2d n \u662f\u7b97\u6cd5\u95ee\u9898\u7684\u89c4\u6a21\u3001 f(n) \u662f\u6570\u5b66\u51fd\u6570\u3002 \u8fd0\u884c\u65f6\u884c\u4e3a\u7684\u5e38\u89c1\u8868\u8fbe\u5f0f\u6709 O(log(n, 2)) \uff08\u5bf9\u6570\uff09\u3001 O(n) \uff08\u7ebf\u6027\uff09\u3001 O(n^2) \uff08\u5e73\u65b9\uff09\u4ee5\u53ca O(k^n) \uff08\u6307\u6570\uff09\u3002 \u7b97\u6cd5\u5728\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u53ef\u4ee5\u662f\u4e0d\u540c\u7684\u3002\u6bd4\u5982\uff0c\u5192\u6ce1\u6392\u5e8f\u548c\u63d2\u5165\u6392\u5e8f\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u90fd\u662f\u7ebf\u6027\u590d\u6742\u5ea6\uff0c\u4f46\u662f\u5b83\u4eec\u5728\u5e73\u5747\u60c5\u51b5\u548c\u6700\u574f\u60c5\u51b5\u4e0b\u662f\u5e73\u65b9\u9636\u590d\u6742\u5ea6\u3002 \u901a\u5e38\u6765\u8bf4\uff0c\u8981\u63d0\u9ad8\u7b97\u6cd5\u7684\u6027\u80fd\u6700\u597d\u662f\u5c1d\u8bd5\u964d\u4f4e\u5b83\u7684\u8fd0\u884c\u65f6\u590d\u6742\u5ea6\u7684\u9636\u6570\uff0c\u800c\u4e0d\u662f\u5bf9\u4ee3\u7801\u8fdb\u884c\u5fae\u8c03\u3002 \u4e8c\u5206\u641c\u7d22\u4f1a\u6bd4\u987a\u5e8f\u641c\u7d22\u8981\u5feb\u5f97\u591a\u3002\u4f46\u662f\uff0c\u5728\u7528\u4e8c\u5206\u641c\u7d22\u8fdb\u884c\u641c\u7d22\u65f6\uff0c\u6570\u636e\u5fc5\u987b\u662f\u6709\u5e8f\u7684\u3002 nlogn \u6392\u5e8f\u7b97\u6cd5\u901a\u8fc7\u9012\u5f52\u3001\u5206\u6cbb\u6cd5\u7b56\u7565\u6765\u7a81\u7834 n^2 \u7684\u6027\u80fd\u969c\u788d\u3002\u5feb\u901f\u6392\u5e8f\u4f1a\u5728\u57fa\u51c6\u5143\u7d20\u5de6\u53f3\u5bf9\u5176\u4ed6\u5143\u7d20\u91cd\u65b0\u6392\u5217\uff0c\u7136\u540e\u5bf9\u57fa\u51c6\u4e24\u4fa7\u7684\u5b50\u5217\u8868\u9012\u5f52\u5730\u6392\u5e8f\u3002\u5f52\u5e76\u6392\u5e8f\u5219\u4f1a\u628a\u4e00\u4e2a\u5217\u8868\u8fdb\u884c\u62c6\u5206\uff0c\u9012\u5f52\u5730\u5bf9\u6bcf\u4e2a\u90e8\u5206\u8fdb\u884c\u6392\u5e8f\uff0c\u7136\u540e\u5408\u5e76\u51fa\u6700\u7ec8\u7ed3\u679c\u3002 \u6307\u6570\u590d\u6742\u5ea6\u7684\u7b97\u6cd5\u901a\u5e38\u53ea\u5728\u7406\u8bba\u4e0a\u88ab\u5173\u6ce8\uff0c\u5728\u5904\u7406\u5927\u578b\u95ee\u9898\u7684\u65f6\u5019\uff0c\u5b83\u4eec\u662f\u6ca1\u6709\u4f7f\u7528\u4ef7\u503c\u7684\u3002 3.9.\u590d\u4e60\u9898 \u00b6 \u5728\u4e0d\u540c\u95ee\u9898\u89c4\u6a21\u7684\u60c5\u51b5\u4e0b\u8bb0\u5f55\u7b97\u6cd5\u8fd0\u884c\u65f6\uff1a \u53ef\u4ee5\u8ba9\u4f60\u5927\u81f4\u4e86\u89e3\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u884c\u4e3a \u53ef\u4ee5\u8ba9\u4f60\u4e86\u89e3\u7b97\u6cd5\u5728\u7279\u5b9a\u786c\u4ef6\u5e73\u53f0\u548c\u7279\u5b9a\u8f6f\u4ef6\u5e73\u53f0\u4e0a\u7684\u8fd0\u884c\u65f6\u884c\u4e3a \u7edf\u8ba1\u6307\u4ee4\u7684\u6570\u91cf\u4f1a\uff1a \u5728\u4e0d\u540c\u7684\u786c\u4ef6\u548c\u8f6f\u4ef6\u5e73\u53f0\u4e0a\u5f97\u5230\u76f8\u540c\u7684\u6570\u636e \u53ef\u4ee5\u8bc1\u660e\u5728\u95ee\u9898\u89c4\u6a21\u5f88\u5927\u7684\u60c5\u51b5\u4e0b\uff0c\u6307\u6570\u7b97\u6cd5\u662f\u6ca1\u6cd5\u4f7f\u7528\u7684 \u8868\u8fbe\u5f0f O(n) \u3001 O(n^2) \u548c O(k^n) \u5206\u522b\u4ee3\u8868\u7684\u590d\u6742\u5ea6\u662f\uff1a \u6307\u6570\u3001\u7ebf\u6027\u548c\u5e73\u65b9 \u7ebf\u6027\u3001\u5e73\u65b9\u548c\u6307\u6570 \u5bf9\u6570\u3001\u7ebf\u6027\u548c\u5e73\u65b9 \u4e8c\u5206\u641c\u7d22\u9700\u8981\u5047\u5b9a\u6570\u636e\uff1a \u6ca1\u6709\u4efb\u4f55\u7279\u522b\u7684\u987a\u5e8f\u5173\u7cfb \u6709\u5e8f\u7684 \u9009\u62e9\u6392\u5e8f\u6700\u591a\u53ef\u4ee5\u6709\uff1a n^2 \u6b21\u6570\u636e\u5143\u7d20\u7684\u4ea4\u6362 n \u6b21\u6570\u636e\u5143\u7d20\u7684\u4ea4\u6362 \u63d2\u5165\u6392\u5e8f\u548c\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u662f\uff1a \u7ebf\u6027\u7684 \u5e73\u65b9\u7684 \u6307\u6570\u7684 \u6700\u597d\u60c5\u51b5\u3001\u5e73\u5747\u60c5\u51b5\u4ee5\u53ca\u6700\u574f\u60c5\u51b5\u4e0b\u590d\u6742\u5ea6\u90fd\u76f8\u540c\u7684\u7b97\u6cd5\u662f\uff1a \u987a\u5e8f\u641c\u7d22 \u9009\u62e9\u6392\u5e8f \u5feb\u901f\u6392\u5e8f \u4e00\u822c\u6765\u8bf4\uff0c\u4e0b\u9762\u54ea\u4e2a\u9009\u62e9\u66f4\u597d\uff1a \u8c03\u6574\u7b97\u6cd5\u4ece\u800c\u8282\u7701\u82e5\u5e72\u79d2\u7684\u8fd0\u884c\u65f6 \u9009\u62e9\u8ba1\u7b97\u590d\u6742\u5ea6\u66f4\u4f4e\u7684\u7b97\u6cd5 \u5bf9\u4e8e\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\uff1a \u95ee\u9898\u89c4\u6a21\u4e3a n \u7684\u65f6\u5019\uff0c\u6709 n^2 \u6b21\u9012\u5f52\u8c03\u7528 \u95ee\u9898\u89c4\u6a21\u4e3a n \u7684\u65f6\u5019\uff0c\u6709 2n \u6b21\u9012\u5f52\u8c03\u7528 \u5b8c\u5168\u586b\u5145\u7684\u4e8c\u53c9\u8c03\u7528\u6811\u91cc\u6bcf\u4e00\u5c42\uff1a \u8c03\u7528\u6b21\u6570\u662f\u4e0a\u4e00\u5c42\u8c03\u7528\u6b21\u6570\u76842\u500d \u4e0e\u4e0a\u4e00\u5c42\u76f8\u540c\u7684\u8c03\u7528\u6b21\u6570 3.10.\u7f16\u7a0b\u7ec3\u4e60 \u00b6 1\uff0e\u5bf9\u4e00\u4e2a\u6709\u5e8f\u5217\u8868\u8fdb\u884c\u987a\u5e8f\u641c\u7d22\uff0c\u5f53\u76ee\u6807\u5c0f\u4e8e\u6709\u5e8f\u5217\u8868\u91cc\u7684\u67d0\u4e2a\u5143\u7d20\u65f6\uff0c\u987a\u5e8f\u641c\u7d22\u53ef\u4ee5\u63d0\u524d\u505c\u6b62\u3002\u5b9a\u4e49\u8fd9\u4e2a\u7b97\u6cd5\u7684\u4fee\u6539\u7248\u672c\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u6765\u63cf\u8ff0\u5b83\u5728\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 \u89e3\u7b54\uff1a \u5728\u6700\u597d\u7684\u60c5\u51b5\u4e0b\uff0c\u76ee\u6807\u5143\u7d20\u5728\u6709\u5e8f\u5217\u8868\u7684\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u51fd\u6570\u53ea\u9700\u8981\u8fdb\u884c\u4e00\u6b21\u6bd4\u8f83\u3002\u6240\u4ee5\uff0c\u6700\u4f73\u60c5\u51b5\u590d\u6742\u5ea6\u4e3a O(1) \u3002 \u5728\u6700\u574f\u7684\u60c5\u51b5\u4e0b\uff0c\u76ee\u6807\u5143\u7d20\u4e0d\u5728\u5217\u8868\u4e2d\uff0c\u5e76\u4e14\u6240\u6709\u5217\u8868\u5143\u7d20\u90fd\u5c0f\u4e8e\u76ee\u6807\u5143\u7d20\u3002\u8fd9\u5c06\u5bfc\u81f4\u51fd\u6570\u904d\u5386\u6574\u4e2a\u5217\u8868\uff0c\u6240\u4ee5\u6700\u574f\u60c5\u51b5\u590d\u6742\u5ea6\u4e3a O(n) \u3002 \u5bf9\u4e8e\u5e73\u5747\u60c5\u51b5\uff0c\u5047\u8bbe\u6709 n \u4e2a\u9879\u5728\u5217\u8868\u4e2d\uff0c\u641c\u7d22\u76ee\u6807\u4f1a\u5728\u5217\u8868\u524d n/2 \u4e2a\u9879\u6216\u8005\u4e0d\u5728\u6240\u6709\u3002\u5728\u8fd9\u4e2a\u7ea6\u5b9a\u4e0b\uff0c\u5e73\u5747\u6211\u4eec\u9700\u8981\u5bfb\u627e n/2 \u4e2a\u9879\uff0c\u56e0\u6b64\u590d\u6742\u5ea6\u4e3a O(n) \u3002\u4e4b\u6240\u4ee5\u662f n/2 \uff0c\u662f\u56e0\u4e3a\u8fd9\u4e2a\u4efb\u52a1\u53ef\u80fd\u4f1a\u5728\u4efb\u4f55\u5730\u65b9\u88ab\u505c\u6b62\uff0c\u6211\u4eec\u5bf9\u6b64\u505a\u5e73\u5747\u5904\u7406\u3002\u7136\u800c\u5728\u5927O\u6807\u8bb0\u6cd5\u4e2d\uff0c\u5e38\u6570\u5c06\u88ab\u9057\u5fd8\uff0c\u6240\u4ee5\u5b83\u4ecd\u7136\u662f O(n) \u3002 \u4ee3\u7801\u5982\u4e0b\uff1a def ordered_sequential_search ( arr , target ): comparisons = 0 # \u7528\u4e8e\u7edf\u8ba1\u6bd4\u8f83\u6b21\u6570 index = 0 while index < len ( arr ): comparisons += 1 if arr [ index ] == target : return comparisons , index # \u627e\u5230\u76ee\u6807\u5e76\u8fd4\u56de\u6bd4\u8f83\u6b21\u6570\u548c\u7d22\u5f15 elif arr [ index ] > target : break # \u5982\u679c\u76ee\u6807\u5c0f\u4e8e\u5f53\u524d\u5143\u7d20\uff0c\u63d0\u524d\u505c\u6b62\u641c\u7d22 index += 1 return comparisons , - 1 # \u6ca1\u627e\u5230\u76ee\u6807\u8fd4\u56de\u6bd4\u8f83\u6b21\u6570\u548c-1 def main (): # \u6d4b\u8bd5 arr = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] for target in [ 5 , 11 ]: comparisons , index = ordered_sequential_search ( arr , target ) if index != - 1 : print ( f \"\u76ee\u6807 { target } \u5728\u7d22\u5f15 { index } \u5904\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a { comparisons } \" ) else : print ( f \"\u76ee\u6807 { target } \u672a\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a { comparisons } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # \u76ee\u6807 5 \u5728\u7d22\u5f15 4 \u5904\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a 5 # \u76ee\u6807 11 \u672a\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a 10 2\uff0e\u5217\u8868\u7684 reverse \u65b9\u6cd5\u7528\u6765\u53cd\u8f6c\u5217\u8868\u91cc\u7684\u5143\u7d20\u3002\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c reverse \u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u53ef\u4ee5\u5728\u4e0d\u4f7f\u7528 reverse \u65b9\u6cd5\u7684\u60c5\u51b5\u4e0b\uff0c\u53cd\u8f6c\u5217\u8868\u53c2\u6570\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u5c1d\u8bd5\u8ba9\u8fd9\u4e2a\u51fd\u6570\u5c3d\u53ef\u80fd\u5730\u9ad8\u6548\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 \u89e3\u7b54\uff1a \u53ea\u9700\u8981\u904d\u5386\u5217\u8868\u7684\u4e00\u534a\uff0c\u6211\u4eec\u5c31\u80fd\u5230\u8fbe\u5217\u8868\u7684\u4e2d\u95f4\u4f4d\u7f6e\u628a\u5217\u8868\u4e24\u8fb9\u7684\u5143\u7d20\u4e92\u6362\uff0c\u8fd9\u6837\u5c31\u5b8c\u6210\u4e86\u5217\u8868\u7684\u53cd\u8f6c\u3002 \u8fd9\u4e2a\u7b97\u6cd5\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n/2) \uff0c\u5176\u4e2d n \u662f\u5217\u8868\u7684\u957f\u5ea6\u3002\u4f46\u5728\u5927O\u8868\u793a\u6cd5\u4e2d\uff0c\u5e38\u6570\u88ab\u5ffd\u7565\uff0c\u56e0\u6b64\u8be5\u7b97\u6cd5\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002\u5728\u8fd9\u4e2a\u7b97\u6cd5\u4e2d\uff0c n \u5c31\u4ee3\u8868\u7740\u5217\u8868\u7684\u957f\u5ea6\u3002\u610f\u5473\u7740\u65f6\u95f4\u590d\u6742\u5ea6\u53d7\u5217\u8868\u957f\u5ea6\u7684\u5f71\u54cd\u3002\u5217\u8868\u957f\u5ea6\u6bcf\u589e\u52a0\u4e00\u6b21\uff0c\u6267\u884c\u53cd\u8f6c\u7684\u65f6\u95f4\u5c31\u589e\u52a0\u4e00\u6b21\u3002\u8fd9\u5c31\u662f O(n) \u7684\u6982\u5ff5\u3002 \u8fd9\u4e2a\u51fd\u6570\u7684\u7a7a\u95f4\u590d\u6742\u5ea6\u662f O(1) \uff0c\u56e0\u4e3a\u5b83\u53ea\u662f\u5728\u539f\u5730\u4fee\u6539\u5217\u8868\uff0c\u4e0d\u9700\u8981\u989d\u5916\u7684\u5b58\u50a8\u7a7a\u95f4\u3002 \u4ee3\u7801\u5982\u4e0b\uff1a def custom_reverse ( arr ): left , right = 0 , len ( arr ) - 1 while left < right : arr [ left ], arr [ right ] = arr [ right ], arr [ left ] left += 1 right -= 1 def main (): # \u6d4b\u8bd5\u5217\u8868reverse\u65b9\u6cd5 my_list = [ 1 , 2 , 3 , 4 , 5 ] my_list . reverse () print ( my_list ) # \u6d4b\u8bd5\u81ea\u5b9a\u4e49\u7684reverse\u65b9\u6cd5 my_list = [ 1 , 2 , 3 , 4 , 5 ] custom_reverse ( my_list ) print ( my_list ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # [5, 4, 3, 2, 1] # [5, 4, 3, 2, 1] 3\uff0ePython\u7684pow\u51fd\u6570\u4f1a\u8fd4\u56de\u6570\u5b57\u7279\u5b9a\u5e42\u6b21\u7684\u7ed3\u679c\u3002\u5b9a\u4e49\u6267\u884c\u8fd9\u4e2a\u4efb\u52a1\u7684expo\u51fd\u6570\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002\u8fd9\u4e2a\u51fd\u6570\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u6570\u5b57\uff0c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u6307\u6570\uff08\u975e\u8d1f\u6570\uff09\u3002\u4f60\u53ef\u4ee5\u901a\u8fc7\u5faa\u73af\u6216\u9012\u5f52\u51fd\u6570\u6765\u5b9e\u73b0\uff0c\u4f46\u4e0d\u8981\u4f7f\u7528Python\u5185\u7f6e\u7684**\u8fd0\u7b97\u7b26\u6216\u662fpow\u51fd\u6570\u3002 \u89e3\u7b54\uff1a \u4e0b\u9762\u5b9e\u73b0\u7684 expo \u51fd\u6570\u4f7f\u7528\u5faa\u73af\u6765\u8fde\u7eed\u4e58\u4ee5 base \uff0c\u5faa\u73af\u7684\u6b21\u6570\u7b49\u4e8e exponent \u7684\u503c\u3002 \u65f6\u95f4\u590d\u6742\u5ea6\u662f O(exponent) \uff0c\u5176\u4e2d exponent \u662f\u6307\u6570\u7684\u503c\u3002 \u6700\u597d\u60c5\u51b5\uff1aO(exponent) \u6700\u574f\u60c5\u51b5\uff1aO(exponent) \u5e73\u5747\u60c5\u51b5\uff1aO(exponent) def expo ( base , exponent ): result = 1 for _ in range ( exponent ): result *= base return result def main (): # \u6d4b\u8bd5 base = 2 for exponent in [ 3 , - 3 ]: result = expo ( base , exponent ) print ( f \" { base } \u7684 { exponent } \u6b21\u65b9\u7b49\u4e8e { result } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # 2 \u7684 3 \u6b21\u65b9\u7b49\u4e8e 8 # 2 \u7684 -3 \u6b21\u65b9\u7b49\u4e8e 1 4\uff0e\u53e6\u4e00\u4e2a\u5b9e\u73b0 expo \u51fd\u6570\u7684\u7b56\u7565\u4f7f\u7528\u4e0b\u9762\u8fd9\u4e2a\u9012\u5f52\u3002\u8bf7\u5b9a\u4e49\u4f7f\u7528\u8fd9\u4e2a\u7b56\u7565\u7684\u9012\u5f52\u51fd\u6570 expo \uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 expo ( number \uff0c exponent ) = 1 \uff0c \u5f53 exponent = 0 \u7684\u65f6\u5019 = number * expo ( number , exponent \u2212 1 ) \uff0c \u5f53exponent\u4e3a\u5947\u6570\u7684\u65f6\u5019 = ( expo ( number , exponent / 2 )) 2 \uff0c \u5f53exponent\u4e3a\u5076\u6570\u7684\u65f6\u5019 \u89e3\u7b54\uff1a \u4e0b\u9762\u5b9e\u73b0expo\u51fd\u6570\u662f\u901a\u8fc7\u9012\u5f52\u5b9e\u73b0\uff0c\u5e76\u91c7\u7528\u4e86\u5206\u800c\u6cbb\u4e4b\u7684\u7b56\u7565\u3002 \u5982\u679c\u6307\u6570\u662f\u5947\u6570\uff0c\u5c31\u628a\u95ee\u9898\u5206\u89e3\u4e3a\u4e00\u4e2a\u66f4\u5c0f\u7684\u7248\u672c\uff08\u5373 num * num^(exp - 1) \uff09\uff1b \u5982\u679c\u6307\u6570\u662f\u5076\u6570\uff0c\u5219\u53ef\u4ee5\u5c06\u6307\u6570\u5206\u6210\u4e24\u534a\uff0c\u5e76\u53ea\u8ba1\u7b97\u5176\u4e2d\u7684\u4e00\u534a\uff08\u5373 num^(exp / 2) * num^(exp / 2) \uff09\u3002 \u8fd9\u5c31\u5229\u7528\u4e86\u5e42\u7684\u6027\u8d28 a^(m * n) = (a^m)^n \u3002 \u8be5\u9012\u5f52\u5b9e\u73b0\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(log n) \uff0c\u5176\u4e2dn\u4e3a\u6307\u6570\u3002\u8fd9\u662f\u56e0\u4e3a\u5728\u6307\u6570\u4e3a\u5076\u6570\u7684\u60c5\u51b5\u4e0b\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u90fd\u4f1a\u628a\u95ee\u9898\u89c4\u6a21\u7f29\u5c0f\u4e00\u534a\uff0c\u7c7b\u4f3c\u4e8e\u4e8c\u5206\u67e5\u627e\u7b49\u8bfe\u5206\u5272\u95ee\u9898\u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\u4e5f\u662f O(log n) \uff0c\u8fd9\u4e3b\u8981\u662f\u7531\u4e8e\u51fd\u6570\u8c03\u7528\u6808\u7684\u6df1\u5ea6\u5728\u6307\u6570\u4e3a\u5076\u6570\u7684\u60c5\u51b5\u4e0b\uff0c\u4f1a\u53d8\u4e3a\u539f\u6765\u7684\u4e00\u534a\u3002 def expo ( number , exponent ): if exponent <= 0 : return 1 elif exponent % 2 == 1 : # \u5f53 exponent \u4e3a\u5947\u6570 return number * expo ( number , exponent - 1 ) else : # \u5f53 exponent \u4e3a\u5076\u6570 half_expo = expo ( number , exponent // 2 ) return half_expo * half_expo def main (): # \u6d4b\u8bd5 base = 2 for exponent in [ 3 , - 3 ]: result = expo ( base , exponent ) print ( f \" { base } \u7684 { exponent } \u6b21\u65b9\u7b49\u4e8e { result } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # 2 \u7684 3 \u6b21\u65b9\u7b49\u4e8e 8 # 2 \u7684 -3 \u6b21\u65b9\u7b49\u4e8e 1 5\uff0ePython\u4e2dlist\u91cc\u7684sort\u65b9\u6cd5\u5305\u542b\u4e00\u4e2a\u7528\u5173\u952e\u5b57\u547d\u540d\u7684\u53c2\u6570reverse\uff0c\u5b83\u7684\u9ed8\u8ba4\u503c\u4e3aFalse\u3002\u7a0b\u5e8f\u5458\u53ef\u4ee5\u901a\u8fc7\u8986\u76d6\u8fd9\u4e2a\u503c\u4ee5\u5bf9\u5217\u8868\u8fdb\u884c\u964d\u5e8f\u6392\u5e8f\u3002\u4fee\u6539\u672c\u7ae0\u8ba8\u8bba\u7684selectionSort\u51fd\u6570\uff0c\u4f7f\u5b83\u53ef\u4ee5\u63d0\u4f9b\u8fd9\u4e2a\u9644\u52a0\u53c2\u6570\u6765\u8ba9\u7a0b\u5e8f\u5458\u51b3\u5b9a\u6392\u5e8f\u7684\u65b9\u5411\u3002 \u89e3\u7b54\uff1a \u901a\u8fc7\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a reverse \u7684\u53c2\u6570\u6765\u4fee\u6539 selectionSort \u51fd\u6570\uff0c\u4ee5\u4fbf\u8ba9\u7a0b\u5e8f\u5458\u51b3\u5b9a\u6392\u5e8f\u7684\u65b9\u5411\u3002\u5982\u679c reverse \u4e3a True \uff0c\u6392\u5e8f\u5c06\u662f\u964d\u5e8f\u7684\uff0c\u5982\u679c\u4e3a False \uff08\u9ed8\u8ba4\u503c\uff09\uff0c\u6392\u5e8f\u5c06\u662f\u5347\u5e8f\u7684\u3002 \u4e0b\u9762\u662f\u4fee\u6539\u540e\u7684 selectionSort \u51fd\u6570\uff1a def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst , reverse = False ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\uff0c\u53ef\u4ee5\u9009\u62e9\u5347\u5e8f\u6216\u964d\u5e8f\u6392\u5e8f\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 index = i # \u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\u4f4d\u7f6e if not reverse : if ( lyst [ j ] < lyst [ index ]): index = j else : if ( lyst [ j ] > lyst [ index ]): index = j j += 1 if index != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , index , i ) i += 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] 6\uff0e\u4fee\u6539\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\uff0c\u8ba9\u5b83\u652f\u6301\u672c\u7ae0\u91cc\u8ba8\u8bba\u8fc7\u7684\u8bb0\u5fc6\u5316\u6280\u672f\u3002\u8fd9\u4e2a\u51fd\u6570\u5e94\u6dfb\u52a0\u4e00\u4e2a\u5b57\u5178\u7c7b\u578b\u7684\u53c2\u6570\u3002\u5b83\u7684\u9876\u5c42\u8c03\u7528\u4f1a\u63a5\u6536\u4e00\u4e2a\u7a7a\u5b57\u5178\u4f5c\u4e3a\u53c2\u6570\uff0c\u8fd9\u4e2a\u5b57\u5178\u7684\u952e\u548c\u503c\u5e94\u8be5\u662f\u9012\u5f52\u8c03\u7528\u6240\u4f20\u9012\u7684\u53c2\u6570\u548c\u8ba1\u7b97\u51fa\u7684\u503c\u3002\u4e4b\u540e\uff0c\u7528\u672c\u7ae0\u8ba8\u8bba\u8fc7\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u5bf9\u9012\u5f52\u8c03\u7528\u7684\u6570\u91cf\u8fdb\u884c\u7edf\u8ba1\u3002 \u89e3\u7b54\uff1a \u4e0b\u9762\u662f\u4e00\u4e2a\u4fee\u6539\u540e\u7684\u7248\u672c\uff0c\u5b83\u4f7f\u7528\u4e00\u4e2a\u5b57\u5178\uff08\u7f13\u5b58\uff09\u6765\u5b58\u50a8\u5df2\u8ba1\u7b97\u7684\u7ed3\u679c\uff0c\u5e76\u4e14\u6dfb\u52a0\u4e86\u4e00\u4e2a\u8ba1\u6570\u5668\u5bf9\u8c61\u6765\u7edf\u8ba1\u9012\u5f52\u8c03\u7528\u6b21\u6570\u3002\u8fd9\u4e2a\u4ee3\u7801\u4f1a\u8f93\u51fa\u6307\u5b9a\u9879\u6570\u7684\u6590\u6ce2\u90a3\u5951\u6570\u4ee5\u53ca\u9012\u5f52\u8c03\u7528\u7684\u603b\u6b21\u6570\u3002\u8bb0\u5fc6\u5316\u6280\u672f\u53ef\u4ee5\u663e\u8457\u63d0\u9ad8\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u6027\u80fd\uff0c\u907f\u514d\u4e86\u91cd\u590d\u8ba1\u7b97\u3002 class Counter : def __init__ ( self ): self . count = 0 def increment ( self ): self . count += 1 def fib ( n , cache , counter ): \"\"\"\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u6570\u5217\uff0c\u5e26\u6709\u8bb0\u5fc6\u5316\u548c\u8c03\u7528\u8ba1\u6570\u5668\"\"\" if n in cache : return cache [ n ] counter . increment () if n <= 1 : result = 1 else : result = fib ( n - 1 , cache , counter ) + fib ( n - 2 , cache , counter ) cache [ n ] = result return result def main (): n = 10 # \u4f60\u53ef\u4ee5\u8bbe\u7f6e\u4e0d\u540c\u7684\u6590\u6ce2\u90a3\u5951\u6570\u5217\u9879\u6570 cache = {} # \u7528\u4e8e\u7f13\u5b58\u5df2\u8ba1\u7b97\u7ed3\u679c\u7684\u5b57\u5178 counter = Counter () # \u7528\u4e8e\u8ba1\u6570\u9012\u5f52\u8c03\u7528\u6b21\u6570\u7684\u8ba1\u6570\u5668\u5bf9\u8c61 result = fib ( n , cache , counter ) print ( f \"Fibonacci( { n } ) = { result } \" ) print ( f \"Total recursive calls: { counter . count } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Fibonacci(10) = 89 # Total recursive calls: 11 7\uff0e\u5206\u6790\u4e0a\u9762\u6590\u6ce2\u90a3\u5951\u6570\u5217\u91cc\u5b9a\u4e49\u7684\u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u6027\u80fd\uff0c\u7edf\u8ba1\u8fd9\u4e2a\u51fd\u6570\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u3002\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\uff0c\u5e76\u8bc1\u660e\u4f60\u7684\u7b54\u6848\u662f\u5408\u7406\u7684\u3002 \u89e3\u7b54\uff1a \u5728\u4e0a\u9762\u7684\u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u4e2d\uff0c\u6211\u4eec\u4f7f\u7528\u4e86\u8bb0\u5fc6\u5316\u6280\u672f\u6765\u907f\u514d\u91cd\u590d\u8ba1\u7b97\u3002\u8fd9\u79cd\u4f18\u5316\u4f1a\u663e\u8457\u51cf\u5c11\u8ba1\u7b97\u65f6\u95f4\uff0c\u56e0\u4e3a\u6bcf\u4e2a\u6590\u6ce2\u90a3\u5951\u6570\u53ea\u4f1a\u88ab\u8ba1\u7b97\u4e00\u6b21\u3002 \u8ba1\u7b97\u590d\u6742\u5ea6\u5206\u6790\uff1a \u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u662f O(n) \u3002\u8fd9\u662f\u56e0\u4e3a\u5b83\u9700\u8981\u8ba1\u7b97\u6590\u6ce2\u90a3\u5951\u6570\u5217\u7684\u524d n \u9879\uff0c\u6bcf\u4e00\u9879\u53ea\u9700\u8ba1\u7b97\u4e00\u6b21\uff0c\u7136\u540e\u5b58\u50a8\u5728\u7f13\u5b58\u4e2d\u3002\u56e0\u6b64\uff0c\u603b\u5171\u6267\u884c\u7684\u8ba1\u7b97\u91cf\u4e0e n \u6210\u6b63\u6bd4\uff0c\u5373 O(n) \u3002 \u9012\u5f52\u8c03\u7528\u6b21\u6570\uff1a \u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u53d6\u51b3\u4e8e\u8f93\u5165\u53c2\u6570 n \u3002\u5bf9\u4e8e\u6590\u6ce2\u90a3\u5951\u6570\u5217\uff0c\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u5927\u81f4\u7b49\u4e8e n \u3002\u56e0\u4e3a\u6bcf\u4e2a\u9879\u9700\u8981\u8ba1\u7b97\u4e00\u6b21\uff0c\u6240\u4ee5\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u4e0e\u8ba1\u7b97\u7684\u9879\u6570\u662f\u4e00\u81f4\u7684\u3002 \u6240\u4ee5\uff0c\u8fd9\u4e2a\u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u662f O(n) \uff0c\u800c\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u4e5f\u5927\u81f4\u7b49\u4e8e n \u3002\u8fd9\u4e2a\u6027\u80fd\u662f\u76f8\u5bf9\u8f83\u597d\u7684\uff0c\u56e0\u4e3a\u5b83\u907f\u514d\u4e86\u6307\u6570\u7ea7\u522b\u7684\u91cd\u590d\u8ba1\u7b97\uff0c\u800c\u662f\u7ebf\u6027\u5730\u8ba1\u7b97\u6590\u6ce2\u90a3\u5951\u6570\u5217\u7684\u5404\u9879\u3002 8\uff0e\u51fd\u6570makeRandomList\u4f1a\u521b\u5efa\u5e76\u8fd4\u56de\u4e00\u4e2a\u7ed9\u5b9a\u5927\u5c0f\uff08\u5b83\u7684\u53c2\u6570\uff09\u7684\u6570\u5b57\u5217\u8868\u3002\u5217\u8868\u91cc\u7684\u6570\u5b57\u6ca1\u6709\u91cd\u590d\uff0c\u5b83\u4eec\u7684\u8303\u56f4\u4e3a1\uff5esize\uff0c\u4f4d\u7f6e\u662f\u968f\u673a\u7684\u3002\u4e0b\u9762\u662f\u8fd9\u4e2a\u51fd\u6570\u7684\u4ee3\u7801\u3002\u53ef\u4ee5\u5047\u5b9arange\u3001randint\u548cappend\u51fd\u6570\u90fd\u662f\u5e38\u6570\u65f6\u95f4\u7684\u590d\u6742\u5ea6\u3002\u8fd8\u53ef\u4ee5\u5047\u8bberandom.randint\u968f\u7740\u53c2\u6570\u4e4b\u95f4\u5dee\u503c\u7684\u589e\u52a0\u800c\u66f4\u5c11\u5730\u8fd4\u56de\u91cd\u590d\u7684\u6570\u5b57\u3002\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u8fd9\u4e2a\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\uff0c\u5e76\u8bc1\u660e\u4f60\u7684\u7b54\u6848\u662f\u5408\u7406\u7684\u3002 def makeRandomList ( size ): lyst = [] for count in range ( size ): while True : number = random . randint ( 1 , size ) if not number in lyst : lyst . append ( number ) break return lyst \u89e3\u7b54\uff1a \u8fd9\u4e2a\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u5b83\u7684\u5185\u90e8\u5faa\u73af\uff0c\u8be5\u5faa\u73af\u4f1a\u4e0d\u65ad\u751f\u6210\u968f\u673a\u6570\uff0c\u5e76\u68c0\u67e5\u5b83\u662f\u5426\u5df2\u7ecf\u5728\u5217\u8868 lyst \u4e2d\u3002\u5177\u4f53\u5206\u6790\u5982\u4e0b\uff1a \u521b\u5efa\u4e00\u4e2a\u7a7a\u5217\u8868 lyst \uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(1)\u3002 \u8fdb\u5165 for \u5faa\u73af\uff0c\u5faa\u73af\u6b21\u6570\u4e3a size \uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(size)\u3002 \u5728\u5185\u90e8 while \u5faa\u73af\u4e2d\uff0c\u751f\u6210\u4e00\u4e2a\u968f\u673a\u6570 number \uff0c\u6700\u574f\u60c5\u51b5\u4e0b\u9700\u8981\u751f\u6210 size \u6b21\u968f\u673a\u6570\u624d\u80fd\u627e\u5230\u4e00\u4e2a\u4e0d\u5728 lyst \u4e2d\u7684\u6570\u5b57\u3002\u8fd9\u90e8\u5206\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(size)\u3002 \u7efc\u4e0a\u6240\u8ff0\uff0c\u8fd9\u4e2a\u51fd\u6570\u7684\u603b\u4f53\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(size^2)\u3002\u8fd9\u662f\u56e0\u4e3a\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u6bcf\u6b21\u751f\u6210\u7684\u968f\u673a\u6570\u90fd\u9700\u8981\u68c0\u67e5\u662f\u5426\u5728 lyst \u4e2d\uff0c\u800c\u968f\u673a\u6570\u7684\u751f\u6210\u53ef\u80fd\u9700\u8981\u591a\u6b21\u624d\u80fd\u751f\u6210\u4e00\u4e2a\u4e0d\u5728\u5217\u8868\u4e2d\u7684\u6570\u5b57\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u968f\u7740 size \u7684\u589e\u52a0\uff0c\u5185\u90e8\u5faa\u73af\u7684\u8fed\u4ee3\u6b21\u6570\u4e5f\u4f1a\u589e\u52a0\uff0c\u5bfc\u81f4\u65f6\u95f4\u590d\u6742\u5ea6\u5448\u4e8c\u6b21\u589e\u957f\u3002\u56e0\u6b64\uff0c\u8fd9\u4e2a\u51fd\u6570\u7684\u6027\u80fd\u5728\u5927\u89c4\u6a21\u6570\u636e\u4e0a\u53ef\u80fd\u4f1a\u53d7\u5230\u9650\u5236\u3002\u5982\u679c\u9700\u8981\u66f4\u597d\u7684\u6027\u80fd\uff0c\u53ef\u4ee5\u8003\u8651\u5176\u4ed6\u7b97\u6cd5\uff0c\u4ee5\u907f\u514d\u91cd\u590d\u68c0\u67e5\u548c\u751f\u6210\u968f\u673a\u6570\u3002 import random def makeRandomList ( size ): lyst = [] for count in range ( size ): while True : number = random . randint ( 1 , size ) if not number in lyst : lyst . append ( number ) break print ( \"count=\" , count , \"list=\" , lyst ) return lyst def main (): print ( \"final list=\" , makeRandomList ( 10 )) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # count= 0 list= [2] # count= 1 list= [2, 10] # count= 2 list= [2, 10, 9] # count= 3 list= [2, 10, 9, 5] # count= 4 list= [2, 10, 9, 5, 3] # count= 5 list= [2, 10, 9, 5, 3, 4] # count= 6 list= [2, 10, 9, 5, 3, 4, 8] # count= 7 list= [2, 10, 9, 5, 3, 4, 8, 7] # count= 8 list= [2, 10, 9, 5, 3, 4, 8, 7, 6] # count= 9 list= [2, 10, 9, 5, 3, 4, 8, 7, 6, 1] # final list= [2, 10, 9, 5, 3, 4, 8, 7, 6, 1] 9\uff0e\u4fee\u6539quicksort\u51fd\u6570\uff0c\u8ba9\u5b83\u53ef\u4ee5\u5bf9\u4efb\u4f55\u5c3a\u5bf8\u5c0f\u4e8e50\u7684\u5b50\u5217\u8868\u8c03\u7528\u63d2\u5165\u6392\u5e8f\u3002\u4f7f\u7528\u670950\u3001500\u548c5000\u4e2a\u5143\u7d20\u7684\u6570\u636e\u96c6\u6bd4\u8f83\u8fd9\u4e2a\u7248\u672c\u4e0e\u539f\u59cb\u7248\u672c\u7684\u6027\u80fd\u3002\u7136\u540e\u8c03\u6574\u8fd9\u4e2a\u9608\u503c\uff0c\u4ece\u800c\u786e\u5b9a\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u7684\u6700\u4f73\u8bbe\u7f6e\u3002 \u89e3\u7b54\uff1a \u53ef\u4ee5\u5728 quicksortHelper \u51fd\u6570\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u6761\u4ef6\uff0c\u68c0\u67e5\u5b50\u5217\u8868\u7684\u5927\u5c0f\u3002\u7136\u540e\u518d\u4fee\u6539 quicksort \u51fd\u6570\uff0c\u5b9e\u73b0\u5728\u5c0f\u4e8e50\u7684\u5b50\u5217\u8868\u4e0a\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u3002 \u5982\u679c\u5b50\u5217\u8868\u7684\u5927\u5c0f\u5c0f\u4e8e50\uff0c\u5c31\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u7b97\u6cd5\uff0c\u5426\u5219\u4f7f\u7528\u5feb\u901f\u6392\u5e8f\u7b97\u6cd5\u3002\u4e0b\u9762\u662f\u4fee\u6539\u540e\u7684\u4ee3\u7801\uff1a import random def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def quicksort ( lyst ): quicksortHelper ( lyst , 0 , len ( lyst ) - 1 ) def quicksortHelper ( lyst , left , right ): if left < right : # \u68c0\u67e5\u5b50\u5217\u8868\u7684\u5927\u5c0f\u662f\u5426\u5c0f\u4e8e50 if right - left < 50 : # \u5982\u679c\u5c0f\u4e8e50\uff0c\u4f7f\u7528\u63d2\u5165\u6392\u5e8f insertionSort ( lyst , left , right ) else : pivotLocation = partition ( lyst , left , right ) quicksortHelper ( lyst , left , pivotLocation - 1 ) quicksortHelper ( lyst , pivotLocation + 1 , right ) def partition ( lyst , left , right ): \"\"\"\u5bf9\u5217\u8868\u8fdb\u884c\u5206\u533a\"\"\" # \u627e\u5230\u57fa\u51c6\u5143\u7d20\uff08pivot\uff09\uff0c\u5e76\u548c\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u4e92\u6362 middle = ( left + right ) // 2 pivot = lyst [ middle ] lyst [ middle ] = lyst [ right ] lyst [ right ] = pivot # \u8bbe\u5b9a\u8fb9\u754c\u5143\u7d20\uff08boundary point\uff09\uff0c\u521d\u59cb\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20 boundary = left print ( \"pivot: \" , pivot , \"boundary: \" , lyst [ boundary ]) # \u628a\u6240\u6709\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u90fd\u79fb\u52a8\u5230\u8fb9\u754c\u7684\u5de6\u8fb9 for index in range ( left , right ): if lyst [ index ] < pivot : swap ( lyst , index , boundary ) boundary += 1 # \u4ea4\u6362\u57fa\u51c6\u5143\u7d20\u548c\u8fb9\u754c\u5143\u7d20 swap ( lyst , right , boundary ) print ( lyst ) return boundary def insertionSort ( lyst , left , right ): \"\"\"\u63d2\u5165\u6392\u5e8f\u7b97\u6cd5\"\"\" for i in range ( left + 1 , right + 1 ): currentElement = lyst [ i ] j = i while j > left and currentElement < lyst [ j - 1 ]: lyst [ j ] = lyst [ j - 1 ] j -= 1 lyst [ j ] = currentElement def main ( size = 20 , sort = quicksort ): lyst = [ random . randint ( 1 , size ) for _ in range ( size )] print ( \"Before sorted\" , lyst ) sort ( lyst ) print ( \"After sorted\" , lyst ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before sorted [1, 3, 6, 14, 9, 6, 14, 15, 17, 13, 4, 3, 1, 13, 11, 16, 2, 4, 6, 2] # After sorted [1, 1, 2, 2, 3, 3, 4, 4, 6, 6, 6, 9, 11, 13, 13, 14, 14, 15, 16, 17] 10\uff0e\u8ba1\u7b97\u673a\u4f7f\u7528\u540d\u4e3a\u8c03\u7528\u6808\u7684\u7ed3\u6784\u6765\u4e3a\u9012\u5f52\u51fd\u6570\u7684\u8c03\u7528\u63d0\u4f9b\u652f\u6301\u3002\u4e00\u822c\u800c\u8a00\uff0c\u8ba1\u7b97\u673a\u4f1a\u4e3a\u51fd\u6570\u7684\u6bcf\u6b21\u8c03\u7528\u90fd\u4fdd\u7559\u4e00\u5b9a\u6570\u91cf\u7684\u5185\u5b58\u3002\u56e0\u6b64\uff0c\u53ef\u4ee5\u5bf9\u9012\u5f52\u51fd\u6570\u4f7f\u7528\u7684\u5185\u5b58\u6570\u91cf\u8fdb\u884c\u590d\u6742\u5ea6\u5206\u6790\u3002\u8bf7\u8bf4\u660e\u9012\u5f52\u9636\u4e58\u51fd\u6570\u548c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u4f7f\u7528\u7684\u5185\u5b58\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 \u89e3\u7b54\uff1a \u9012\u5f52\u9636\u4e58\u51fd\u6570\u548c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u4f7f\u7528\u7684\u5185\u5b58\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u90fd\u4e0e\u9012\u5f52\u7684\u6df1\u5ea6\uff08\u9012\u5f52\u8c03\u7528\u7684\u5c42\u6570\uff09\u76f8\u5173\u3002\u9012\u5f52\u51fd\u6570\u6bcf\u6b21\u8c03\u7528\u90fd\u4f1a\u5728\u8c03\u7528\u6808\u4e2d\u5206\u914d\u4e00\u5b9a\u6570\u91cf\u7684\u5185\u5b58\uff0c\u5305\u62ec\u51fd\u6570\u7684\u53c2\u6570\u3001\u5c40\u90e8\u53d8\u91cf\u4ee5\u53ca\u8fd4\u56de\u5730\u5740\u7b49\u4fe1\u606f\u3002 \u9012\u5f52\u9636\u4e58\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\uff1a \u9012\u5f52\u9636\u4e58\u51fd\u6570\u662f\u4e00\u4e2a\u975e\u5e38\u7b80\u5355\u7684\u9012\u5f52\u51fd\u6570\uff0c\u5b83\u53ea\u9700\u8981\u4fdd\u5b58\u4e00\u4e2a\u6574\u6570\u53c2\u6570 n \u548c\u8fd4\u56de\u5730\u5740\u3002\u56e0\u6b64\uff0c\u5b83\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(1)\uff0c\u4e0e\u8f93\u5165\u53c2\u6570 n \u7684\u5927\u5c0f\u65e0\u5173\u3002\u6bcf\u4e2a\u9012\u5f52\u8c03\u7528\u90fd\u53ea\u9700\u8981\u5e38\u6570\u7ea7\u522b\u7684\u5185\u5b58\u7a7a\u95f4\u3002 \u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\uff1a \u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u9012\u5f52\u7684\u6df1\u5ea6\u3002\u6bcf\u4e2a\u9012\u5f52\u8c03\u7528\u90fd\u9700\u8981\u4fdd\u5b58\u4e24\u4e2a\u6574\u6570\u53c2\u6570 n \u548c depth \uff0c\u4ee5\u53ca\u8fd4\u56de\u5730\u5740\u3002\u56e0\u6b64\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u9700\u8981\u7684\u5185\u5b58\u7a7a\u95f4\u662f\u5e38\u6570\u7ea7\u522b\u7684\u3002 \u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u9012\u5f52\u6df1\u5ea6\u53d6\u51b3\u4e8e\u8f93\u5165\u53c2\u6570 n \u3002\u5177\u4f53\u6765\u8bf4\uff0c\u9012\u5f52\u6df1\u5ea6\u7b49\u4e8e n \u3002\u56e0\u6b64\uff0c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(n)\uff0c\u4e0e\u8f93\u5165\u53c2\u6570 n \u6210\u6b63\u6bd4\u3002 \u603b\u7ed3\u6765\u8bf4\uff0c\u9012\u5f52\u9636\u4e58\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(1)\uff0c\u800c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(n)\u3002\u5728\u9012\u5f52\u7b97\u6cd5\u4e2d\uff0c\u5185\u5b58\u590d\u6742\u5ea6\u901a\u5e38\u4e0e\u9012\u5f52\u6df1\u5ea6\u6210\u6b63\u6bd4\uff0c\u56e0\u6b64\u9700\u8981\u8c28\u614e\u5904\u7406\u9012\u5f52\u8c03\u7528\uff0c\u4ee5\u907f\u514d\u51fa\u73b0\u6808\u6ea2\u51fa\u7b49\u95ee\u9898\u3002\u53ef\u4ee5\u4f7f\u7528\u8fed\u4ee3\u6216\u52a8\u6001\u89c4\u5212\u7b49\u65b9\u6cd5\u6765\u964d\u4f4e\u5185\u5b58\u6d88\u8017\u3002","title":"\u641c\u7d22\u3001\u6392\u5e8f\u4ee5\u53ca\u590d\u6742\u5ea6\u5206\u6790"},{"location":"python/DataStructure/03_TimeComplexity/#3","text":"\u7b97\u6cd5\u63cf\u8ff0\u4e86\u4e00\u4e2a\u968f\u7740\u95ee\u9898\u88ab\u89e3\u51b3\u800c\u505c\u6b62\u7684\u8ba1\u7b97\u8fc7\u7a0b\u3002 \u7b97\u6cd5\u662f\u8ba1\u7b97\u673a\u7a0b\u5e8f\u7684\u57fa\u672c\u7ec4\u6210\u90e8\u5206\u4e4b\u4e00\uff0c\u53e6\u4e00\u4e2a\u57fa\u672c\u7ec4\u6210\u90e8\u5206\u662f\u6570\u636e\u7ed3\u6784\u3002 \u5728\u7b97\u6cd5\u6267\u884c\u8fc7\u7a0b\u4e2d\u4f1a\u6d88\u8017\u4e24\u4e2a\u8d44\u6e90\uff1a\u5904\u7406\u5bf9\u8c61\u6240\u9700\u7684\u65f6\u95f4\u548c\u7a7a\u95f4\uff08\u4e5f\u5c31\u662f\u5185\u5b58\uff09\u3002\u5bf9\u4e8e\u7b97\u6cd5\u6765\u8bf4\uff0c\u603b\u4f1a\u8ffd\u6c42\u6d88\u8017\u66f4\u77ed\u7684\u65f6\u95f4\u548c\u5360\u7528\u66f4\u5c11\u7684\u7a7a\u95f4\u3002\u5728\u9009\u62e9\u7b97\u6cd5\u65f6\uff0c\u901a\u5e38\u5728\u7a7a\u95f4/\u65f6\u95f4\u4e4b\u95f4\u8fdb\u884c\u6743\u8861\u3002 \u7b97\u6cd5\u8d28\u91cf\u7684\u4e3b\u8981\u8bc4\u4f30\u6807\u51c6\uff1a \u6b63\u786e\u6027\uff0c\u5373\u7b97\u6cd5\u80fd\u591f\u771f\u6b63\u89e3\u51b3\u6240\u9488\u5bf9\u7684\u95ee\u9898\uff1b \u53ef\u8bfb\u6027\u548c\u6613\u4e8e\u7ef4\u62a4\u6027\uff1b \u8fd0\u884c\u65f6\u6027\u80fd\uff1b \u76ee\u6807\uff1a \u6839\u636e\u95ee\u9898\u7684\u89c4\u6a21\u786e\u5b9a\u7b97\u6cd5\u5de5\u4f5c\u91cf\u7684\u589e\u957f\u7387\uff1b \u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u6765\u63cf\u8ff0\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\uff1b \u8ba4\u8bc6\u5e38\u89c1\u7684\u5de5\u4f5c\u91cf\u589e\u957f\u7387\u6216\u590d\u6742\u5ea6\u7684\u7c7b\u522b\uff08\u5e38\u6570\u3001\u5bf9\u6570\u3001\u7ebf\u6027\u3001\u5e73\u65b9\u548c\u6307\u6570\uff09\uff1b \u5c06\u7b97\u6cd5\u8f6c\u6362\u4e3a\u590d\u6742\u5ea6\u4f4e\u4e00\u4e2a\u6570\u91cf\u7ea7\u7684\u66f4\u5feb\u7684\u7248\u672c\uff1b \u63cf\u8ff0\u987a\u5e8f\u641c\u7d22\u7b97\u6cd5\u548c\u4e8c\u5206\u641c\u7d22\u7b97\u6cd5\u7684\u5de5\u4f5c\u65b9\u5f0f\uff1b \u63cf\u8ff0\u9009\u62e9\u6392\u5e8f\u7b97\u6cd5\u548c\u5feb\u901f\u6392\u5e8f\u7b97\u6cd5\u7684\u5de5\u4f5c\u65b9\u5f0f\u3002","title":"3.\u641c\u7d22\u3001\u6392\u5e8f\u4ee5\u53ca\u590d\u6742\u5ea6\u5206\u6790"},{"location":"python/DataStructure/03_TimeComplexity/#31","text":"\u8861\u91cf\u7b97\u6cd5\u65f6\u95f4\u6210\u672c\u7684\u4e24\u79cd\u65b9\u6cd5\uff1a \u7528\u8ba1\u7b97\u673a\u65f6\u949f\u5f97\u5230\u7b97\u6cd5\u5b9e\u9645\u7684\u8fd0\u884c\u65f6\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u88ab\u79f0\u4e3a\u57fa\u51c6\u6d4b\u8bd5\uff08benchmarking\uff09\u6216\u6027\u80fd\u5206\u6790\uff08profiling\uff09\u3002\u9884\u6d4b\u7b97\u6cd5\u6267\u884c\u7684\u62bd\u8c61\u5de5\u4f5c\u91cf\u4f9d\u8d56\u4e8e\u7279\u5b9a\u7684\u786c\u4ef6\u6216\u8f6f\u4ef6\u5e73\u53f0\u3002 \u5728\u4e0d\u540c\u95ee\u9898\u89c4\u6a21\u4e0b\uff0c\u7edf\u8ba1\u9700\u8981\u6267\u884c\u7684\u6307\u4ee4\u6570\u3002\u9884\u6d4b\u7b97\u6cd5\u6267\u884c\u7684\u62bd\u8c61\u5de5\u4f5c\u91cf\u9002\u7528\u4e8e\u4e0d\u540c\u7684\u786c\u4ef6\u6216\u8f6f\u4ef6\u5e73\u53f0\u3002","title":"3.1.\u8861\u91cf\u7b97\u6cd5\u7684\u6548\u7387"},{"location":"python/DataStructure/03_TimeComplexity/#311","text":"import time problemSize = 10000000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): \"\"\" \u5728\u4e00\u4e2a\u5faa\u73af\u4e2d\uff0c\u5c06\u95ee\u9898\u89c4\u6a21\u7ffb\u500d5\u6b21\uff0c\u8bb0\u5f55\u7b97\u6cd5\u6bcf\u6b21\u8fd0\u884c\u65f6\u95f4\u3002 \"\"\" start = time . time () # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f elapsed = time . time () - start print ( \" %12d%16.3f \" % ( problemSize , elapsed )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Seconds # 10000000 0.689 # 20000000 1.367 # 40000000 2.644 # 80000000 5.296 # 160000000 10.622 \u4e0a\u8ff0\u6d4b\u8bd5\u7a0b\u5e8f\u4f7f\u7528\u4e86 time \u6a21\u5757\u91cc\u7684 time() \u51fd\u6570\u6765\u8bb0\u5f55\u8fd0\u884c\u65f6\uff0c\u5373 time.time() \u3002\u8fd9\u4e2a\u51fd\u6570\u4f1a\u8fd4\u56de\u8ba1\u7b97\u673a\u7684\u5f53\u524d\u65f6\u95f4\u548c1970\u5e741\u67081\u65e5\uff3b\u4e5f\u79f0\u4e3a\u7eaa\u5143\uff08epoch\uff09\uff3d\u76f8\u5dee\u7684\u79d2\u6570\u3002\u4e24\u6b21\u8c03\u7528 time.time() \u7684\u7ed3\u679c\u4e4b\u95f4\u7684\u5dee\u503c\u5c31\u4ee3\u8868\u4e86\u4e2d\u95f4\u7ecf\u5386\u4e86\u591a\u5c11\u79d2\u3002 \u4e0a\u8ff0\u6d4b\u8bd5\u7a0b\u5e8f\u5728\u6bcf\u6b21\u5faa\u73af\u7684\u65f6\u5019\u90fd\u4f1a\u6267\u884c\u4e24\u4e2a\u6269\u5c55\u7684\u8d4b\u503c\u8bed\u53e5\uff0c\u4e5f\u5c31\u662f\u6bcf\u6b21\u90fd\u6267\u884c\u7684\u5de5\u4f5c\u91cf\u662f\u56fa\u5b9a\u7684\uff0c\u4f1a\u6d88\u8017\u4e86\u4e00\u5b9a\u7684\u65f6\u95f4\u3002 \u4fee\u6539\u4e0a\u8ff0\u7b97\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u4ece\u4e0b\u9762\u7684\u8fd0\u884c\u7ed3\u679c\u770b\u51fa\uff0c\u5f53 problemSize \u4e3a 1,000 \u65f6\uff0c\u7b97\u6cd5\u7684\u6d88\u8017\u65f6\u95f4\u5c31\u5df2\u7ecf\u8d85\u8fc7\u4e86\u539f\u5148\u7b97\u6cd5\uff0c\u6211\u4eec\u53ef\u4ee5\u63a8\u65ad\u51fa\u7ee7\u7eed\u6d4b\u8bd5 problemSize \u4e3a 10,000,000 \u7684\u8017\u65f6\u5df2\u7ecf\u53d8\u5f97\u4e0d\u5b9e\u9645\u4e86\u3002 import time problemSize = 1000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): start = time . time () # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): for y in range ( problemSize ): work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f elapsed = time . time () - start print ( \" %12d%16.3f \" % ( problemSize , elapsed )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Seconds # 1000 0.093 # 2000 0.350 # 4000 1.280 # 8000 5.004 # 16000 20.020 \u4e0d\u540c\u7684\u786c\u4ef6\u5e73\u53f0\u4f1a\u6709\u4e0d\u540c\u7684\u5904\u7406\u901f\u5ea6\uff0c\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u4f1a\u56e0\u673a\u5668\u7684\u4e0d\u540c\u800c\u5b58\u5728\u5dee\u5f02\u3002 \u7a0b\u5e8f\u7684\u8fd0\u884c\u65f6\u4e5f\u4f1a\u968f\u7740\u5b83\u548c\u786c\u4ef6\u4e4b\u95f4\u7684\u64cd\u4f5c\u7cfb\u7edf\u7c7b\u578b\u7684\u4e0d\u540c\u800c\u53d8\u5316\u3002 \u4e0d\u540c\u7684\u7f16\u7a0b\u8bed\u8a00\u548c\u7f16\u8bd1\u5668\u751f\u6210\u7684\u4ee3\u7801\u7684\u6027\u80fd\u4e5f\u4f1a\u6709\u6240\u4e0d\u540c\uff0c\u56e0\u6b64\uff0c\u5728\u67d0\u4e00\u4e2a\u786c\u4ef6\u6216\u8f6f\u4ef6\u5e73\u53f0\u4e0a\u6d4b\u5f97\u7684\u8fd0\u884c\u65f6\u7ed3\u679c\u901a\u5e38\u4e0d\u80fd\u7528\u6765\u9884\u6d4b\u5728\u5176\u4ed6\u5e73\u53f0\u4e0a\u7684\u6027\u80fd\u3002 \u7528\u975e\u5e38\u5927\u7684\u6570\u636e\u96c6\u786e\u5b9a\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u662f\u975e\u5e38\u4e0d\u5207\u5b9e\u9645\u7684\u3002\u5bf9\u4e8e\u67d0\u4e9b\u7b97\u6cd5\u6765\u8bf4\uff0c\u4e0d\u8bba\u662f\u7f16\u8bd1\u7684\u4ee3\u7801\u8fd8\u662f\u786c\u4ef6\u5904\u7406\u5668\u7684\u901f\u5ea6\u6709\u591a\u5feb\uff0c\u90fd\u6ca1\u6709\u4efb\u4f55\u7684\u533a\u522b\uff0c\u56e0\u4e3a\u5b83\u4eec\u5728\u4efb\u4f55\u8ba1\u7b97\u673a\u4e0a\u90fd\u6ca1\u529e\u6cd5\u5904\u7406\u975e\u5e38\u5927\u7684\u6570\u636e\u96c6\u3002","title":"3.1.1.\u8861\u91cf\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6"},{"location":"python/DataStructure/03_TimeComplexity/#312","text":"\u7edf\u8ba1\u6307\u4ee4\u6570\u65f6\uff0c\u7edf\u8ba1\u7684\u662f\u7f16\u5199\u7b97\u6cd5\u7684\u9ad8\u7ea7\u8bed\u8a00\u91cc\u7684\u6307\u4ee4\u6570\uff0c\u800c\u4e0d\u662f\u53ef\u6267\u884c\u673a\u5668\u8bed\u8a00\u7a0b\u5e8f\u91cc\u7684\u6307\u4ee4\u6570\u3002 \u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f\u5bf9\u7b97\u6cd5\u8fdb\u884c\u5206\u6790\u65f6\uff0c\u628a\u5b83\u5206\u6210\u4e24\u4e2a\u90e8\u5206\uff1a \u65e0\u8bba\u95ee\u9898\u7684\u89c4\u6a21\u5982\u4f55\u53d8\u5316\uff0c\u6307\u4ee4\u6267\u884c\u7684\u6b21\u6570\u603b\u662f\u76f8\u540c\u7684\uff1b\u6211\u4eec\u5ffd\u7565\u8fd9\u79cd\u7c7b\u578b\uff0c\u56e0\u4e3a\u5206\u6790\u6548\u7387\u65f6\u5b83\u4eec\u7684\u4f5c\u7528\u5e76\u4e0d\u660e\u663e\u3002 \u6267\u884c\u7684\u6307\u4ee4\u6570\u968f\u7740\u95ee\u9898\u89c4\u6a21\u7684\u53d8\u5316\u800c\u53d8\u5316\uff1b\u6211\u4eec\u91cd\u70b9\u5173\u6ce8\u8fd9\u79cd\u7c7b\u578b\uff0c\u8fd9\u79cd\u7c7b\u578b\u7684\u6307\u4ee4\u901a\u5e38\u53ef\u4ee5\u5728\u5faa\u73af\u6216\u8005\u9012\u5f52\u51fd\u6570\u91cc\u627e\u5230\u3002 \u6211\u4eec\u6765\u6539\u5199\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u4ece\u7edf\u8ba1\u8fd0\u884c\u65f6\u95f4\u53d8\u4e3a\u7edf\u8ba1\u8fed\u4ee3\u6b21\u6570\u3002 \u4e0b\u9762\u7684\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u662f\u76f8\u7b49\u7684\u3002 import time problemSize = 10000000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): number = 0 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%16.3f \" % ( problemSize , Iterations )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Iterations # 10000000 10000000.000 # 20000000 20000000.000 # 40000000 40000000.000 # 80000000 80000000.000 # 160000000 160000000.000 \u4e0b\u9762\u7684\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u7684\u5e73\u65b9\u3002\u8fd9\u5c31\u89e3\u91ca\u4e86\u4e3a\u4ec0\u4e48\u8fd9\u4e2a\u7b97\u6cd5\u7684\u8017\u65f6\u975e\u5e38\u5927\u3002 import time problemSize = 1000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): number = 0 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): for y in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%16.3f \" % ( problemSize , number )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Iterations # 1000 1000000.000 # 2000 4000000.000 # 4000 16000000.000 # 8000 64000000.000 # 16000 256000000.000 \u5728\u4e0b\u9762\u7684\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7684\u4f8b\u5b50\u4e2d\uff0c\u51fd\u6570 fib(problemSize, counter) \u4e2d counter \u53c2\u6570\u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u7684\u65f6\u5019\uff0c\u90fd\u4f1a\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u3002 \u4ece\u4e0b\u9762\u7684\u8fd0\u884c\u7ed3\u679c\u53ef\u4ee5\u770b\u51fa\uff0c\u968f\u7740\u95ee\u9898\u89c4\u6a21\uff08Problem Size\uff09\u7684\u7ffb\u500d\uff0c\u6307\u4ee4\u6570\uff08\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\uff09\u5728\u4e00\u5f00\u59cb\u7684\u65f6\u5019\u7f13\u6162\u589e\u957f\uff0c\u968f\u540e\u8fc5\u901f\u52a0\u5feb\u3002 \u7edf\u8ba1\u6307\u4ee4\u6570\u662f\u6b63\u786e\u7684\u601d\u8def\uff0c\u4f46\u4ee5\u8fd9\u79cd\u65b9\u5f0f\u8fdb\u884c\u8ddf\u8e2a\u8ba1\u6570\u7684\u95ee\u9898\u5728\u4e8e\uff0c\u5bf9\u4e8e\u67d0\u4e9b\u7b97\u6cd5\u6765\u8bf4\uff0c\u5982\u679c\u95ee\u9898\u89c4\u6a21\u975e\u5e38\u5927\uff0c\u8ba1\u7b97\u673a\u65e0\u6cd5\u4ee5\u8db3\u591f\u5feb\u7684\u901f\u5ea6\u8fd0\u884c\uff0c\u5e76\u5728\u4e00\u5b9a\u65f6\u95f4\u5185\u5f97\u5230\u7ed3\u679c\u3002 class Counter ( object ): \"\"\"Models a counter.\"\"\" # Class variable instances = 0 #Constructor def __init__ ( self ): \"\"\"Sets up the counter.\"\"\" Counter . instances += 1 self . reset () # Mutator methods def reset ( self ): \"\"\"Sets the counter to 0.\"\"\" self . _value = 0 def increment ( self , amount = 1 ): \"\"\"Adds amount to the counter.\"\"\" self . _value += amount def decrement ( self , amount = 1 ): \"\"\"Subtracts amount from the counter.\"\"\" self . _value -= amount # Accessor methods def getValue ( self ): \"\"\"Returns the counter's value.\"\"\" return self . _value def __str__ ( self ): \"\"\"Returns the string representation of the counter.\"\"\" return str ( self . _value ) def __eq__ ( self , other ): \"\"\"Returns True if self equals other or False otherwise.\"\"\" if self is other : return True if type ( self ) != type ( other ): return False return self . _value == other . _value def fib ( n , counter ): \"\"\"\u7edf\u8ba1\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u88ab\u5916\u90e8\u8c03\u7528\u7684\u6b21\u6570\"\"\" counter . increment () if n < 3 : return 1 else : return fib ( n - 1 , counter ) + fib ( n - 2 , counter ) problemSize = 2 print ( \" %12s%15s \" % ( \"Problem Size\" , \"Calls\" )) for count in range ( 5 ): \"\"\"\u968f\u7740\u95ee\u9898\u89c4\u6a21\u589e\u52a0\uff0c\u8f93\u51fa\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u51fd\u6570\u88ab\u5916\u90e8\u8c03\u7528\u7684\u6b21\u6570\"\"\" counter = Counter () # \u7b97\u6cd5\u5f00\u59cb fib ( problemSize , counter ) # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%15s \" % ( problemSize , counter )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Calls # 2 1 # 4 5 # 8 41 # 16 1973 # 32 4356617","title":"3.1.2.\u7edf\u8ba1\u6307\u4ee4\u6570"},{"location":"python/DataStructure/03_TimeComplexity/#313","text":"\u5bf9\u4e8e\u7b97\u6cd5\u6240\u7528\u8d44\u6e90\u7684\u5206\u6790\u4e5f\u9700\u8981\u5305\u542b\u5b83\u6240\u9700\u7684\u5185\u5b58\u91cf\u7684\u5206\u6790\u3002\u548c\u524d\u9762\u7c7b\u4f3c\u7684\u95ee\u9898\u4e5f\u4f1a\u5b58\u5728\uff0c\u4e00\u4e9b\u7b97\u6cd5\u4f1a\u968f\u7740\u95ee\u9898\u89c4\u6a21\u53d8\u5927\u800c\u9700\u8981\u989d\u5916\u66f4\u591a\u7684\u5185\u5b58\u3002","title":"3.1.3.\u8861\u91cf\u7b97\u6cd5\u4f7f\u7528\u7684\u5185\u5b58"},{"location":"python/DataStructure/03_TimeComplexity/#314","text":"\u7f16\u5199\u4e00\u4e2a\u6d4b\u8bd5\u7a0b\u5e8f\uff0c\u8fd9\u4e2a\u7a0b\u5e8f\u7edf\u8ba1\u5e76\u663e\u793a\u51fa\u4e0b\u9762\u8fd9\u4e2a\u5faa\u73af\u7684\u8fed\u4ee3\u6b21\u6570\u3002 while problemSize > 0 : problemSize = problemSize // 2 \u89e3\u7b54\uff1a def count_iterations ( problemSize ): iterations = 0 # \u521d\u59cb\u5316\u8ba1\u6570\u5668 while problemSize > 0 : problemSize = problemSize // 2 iterations += 1 # \u6bcf\u6b21\u5faa\u73af\u8fed\u4ee3\uff0c\u8ba1\u6570\u5668\u52a0\u4e00 return iterations problemSize = 1000 # \u8bbe\u7f6e\u95ee\u9898\u89c4\u6a21 iterations = count_iterations ( problemSize ) print ( f \"Problem Size: { problemSize } \" ) print ( f \"Iterations: { iterations } \" ) # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size: 1000 # Iterations: 10 \u5728\u95ee\u9898\u89c4\u6a21\u5206\u522b\u4e3a1000\u30012000\u30014000\u300110000\u548c100000\u65f6\uff0c\u8fd0\u884c\u5728\u7ec3\u4e601\u91cc\u6240\u521b\u5efa\u7684\u7a0b\u5e8f\u3002\u5f53\u95ee\u9898\u89c4\u6a21\u7ffb\u500d\u6216\u662f\u4e58\u4ee510\u65f6\uff0c\u8fed\u4ee3\u6b21\u6570\u4f1a\u5982\u4f55\u53d8\u5316\uff1f \u89e3\u7b54\uff1a\u5206\u522b\u4ee5\u4e0d\u540c\u7684\u95ee\u9898\u89c4\u6a21\u8fd0\u884c\u4e0a\u9762\u7684\u4ee3\u7801\uff0c\u7ed3\u679c\u5982\u4e0b\uff1a Problem Size : 1000 Iterations : 10 Problem Size : 4000 Iterations : 12 Problem Size : 8000 Iterations : 13 Problem Size : 10000 Iterations : 14 Problem Size : 100000 Iterations : 17 \u4e24\u6b21\u8c03\u7528\u51fd\u6570 time.time() \u7684\u7ed3\u679c\u4e4b\u5dee\u5c31\u662f\u8fd0\u884c\u65f6\u3002\u7531\u4e8e\u64cd\u4f5c\u7cfb\u7edf\u4e5f\u53ef\u80fd\u4f1a\u5728\u8fd9\u6bb5\u65f6\u95f4\u5185\u4f7f\u7528CPU\uff0c\u56e0\u6b64\u8fd9\u4e2a\u8fd0\u884c\u65f6\u53ef\u80fd\u5e76\u4e0d\u80fd\u53cd\u6620\u51faPython\u4ee3\u7801\u4f7f\u7528CPU\u7684\u5b9e\u9645\u65f6\u95f4\u3002\u6d4f\u89c8Python\u6587\u6863\uff0c\u627e\u51fa\u53e6\u4e00\u79cd\u53ef\u4ee5\u5b8c\u6574\u8bb0\u5f55\u5904\u7406\u65f6\u95f4\u7684\u65b9\u6cd5\uff0c\u5e76\u63cf\u8ff0\u5982\u4f55\u5b9e\u73b0\u5b83\u3002 \u89e3\u7b54\uff1a \u5728Python\u4e2d\uff0c time \u6a21\u5757\u63d0\u4f9b\u4e86\u66f4\u7cbe\u786e\u7684\u8ba1\u65f6\u529f\u80fd\uff0c\u5176\u4e2d\u7684 time.perf_counter() \u51fd\u6570\u53ef\u4ee5\u7528\u6765\u6d4b\u91cf\u65f6\u95f4\u7684\u7cbe\u786e\u95f4\u9694\u3002\u4e0e time.time() \u4e0d\u540c\uff0c time. perf_counter() \u4f1a\u5728\u5927\u591a\u6570\u5e73\u53f0\u4e0a\u63d0\u4f9b\u4e00\u4e2a\u66f4\u9ad8\u5206\u8fa8\u7387\u7684\u8ba1\u65f6\u5668\uff0c\u53ef\u4ee5\u7528\u6765\u6d4b\u91cf\u4ee3\u7801\u5757\u7684\u6267\u884c\u65f6\u95f4\u3002 time.perf_counter() \u8fd4\u56de\u4e00\u4e2a\u6d6e\u70b9\u6570\uff0c\u8868\u793a\u4ece\u67d0\u4e2a\u7279\u5b9a\u65f6\u95f4\u70b9\u5230\u73b0\u5728\u7ecf\u8fc7\u7684\u79d2\u6570\u3002\u4ee5\u4e0b\u662f\u5982\u4f55\u4f7f\u7528 time.perf_counter() \u6765\u8ba1\u7b97\u4ee3\u7801\u5757\u7684\u6267\u884c\u65f6\u95f4\uff1a import time # \u83b7\u53d6\u8d77\u59cb\u65f6\u95f4\uff08\u5305\u62ecCPU\u65f6\u95f4\u548c\u7cfb\u7edf\u65f6\u95f4\uff09 start_cpu_time = time . process_time () start_real_time = time . perf_counter () start_system_time = time . time () # \u6267\u884c\u4ee3\u7801 for i in range ( 100000000 ): _ = i * i # \u83b7\u53d6\u7ed3\u675f\u65f6\u95f4\uff08\u5305\u62ecCPU\u65f6\u95f4\u548c\u7cfb\u7edf\u65f6\u95f4\uff09 end_cpu_time = time . process_time () end_real_time = time . perf_counter () end_system_time = time . time () # \u8ba1\u7b97CPU\u65f6\u95f4\u5dee cpu_execution_time = end_cpu_time - start_cpu_time real_execution_time = end_real_time - start_real_time system_execution_time = end_system_time - start_system_time print ( f \"CPU Execution Time: { cpu_execution_time : .6f } seconds\" ) print ( f \"Real Execution Time: { real_execution_time : .6f } seconds\" ) print ( f \"System Execution Time: { system_execution_time : .6f } seconds\" ) # \u8fd0\u884c\u7ed3\u679c\uff1a # CPU Execution Time: 7.157305 seconds # Real Execution Time: 7.156638 seconds # System Execution Time: 7.156638 seconds \u5728\u4e0a\u9762\u4ee3\u7801\u4e2d\uff0c start_system_time \u548c end_system_time \u5206\u522b\u8bb0\u5f55\u4e86\u4ee3\u7801\u5757\u5f00\u59cb\u548c\u7ed3\u675f\u65f6\u7684\u7cfb\u7edf\u65f6\u95f4\u3002\u7136\u540e\uff0c\u53ef\u4ee5\u901a\u8fc7\u8ba1\u7b97 end_system_time - start_system_time \u6765\u83b7\u53d6\u7cfb\u7edf\u65f6\u95f4\u7684\u6d88\u8017\u3002 \u7cfb\u7edf\u65f6\u95f4\u7684\u8ba1\u7b97\u53ef\u80fd\u53d7\u5230\u7cfb\u7edf\u7684\u5f71\u54cd\uff0c\u53ef\u80fd\u4f1a\u56e0\u4e3a\u7cfb\u7edf\u65f6\u95f4\u7684\u53d8\u5316\u800c\u4ea7\u751f\u4e0d\u51c6\u786e\u7684\u7ed3\u679c\u3002\u5728\u8fdb\u884c\u6027\u80fd\u6d4b\u8bd5\u65f6\uff0c\u5c3d\u91cf\u4ee5CPU\u65f6\u95f4\u548c\u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u4e3a\u4e3b\u8981\u53c2\u8003\u6307\u6807\u3002 \u8865\u5145\uff1a CPU \u65f6\u95f4\u3001\u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u548c\u7cfb\u7edf\u65f6\u95f4\u4ee3\u8868\u4e86\u4e0d\u540c\u7684\u65f6\u95f4\u6307\u6807\uff0c\u5b83\u4eec\u4e4b\u95f4\u6709\u4ee5\u4e0b\u533a\u522b\uff1a CPU \u65f6\u95f4\uff1a - CPU \u65f6\u95f4\u662f\u7a0b\u5e8f\u5728 CPU \u4e0a\u6267\u884c\u7684\u65f6\u95f4\uff0c\u5305\u62ec\u4e86\u5728\u7528\u6237\u6001\uff08\u6267\u884c\u5e94\u7528\u7a0b\u5e8f\u4ee3\u7801\uff09\u548c\u5185\u6838\u6001\uff08\u6267\u884c\u64cd\u4f5c\u7cfb\u7edf\u4ee3\u7801\uff09\u7684\u65f6\u95f4\u3002\u56e0\u6b64\uff0c\u5b83\u8003\u8651\u4e86\u5e94\u7528\u7a0b\u5e8f\u548c\u64cd\u4f5c\u7cfb\u7edf\u7684\u6267\u884c\u65f6\u95f4\u3002 - CPU \u65f6\u95f4\u901a\u5e38\u7528\u4e8e\u6d4b\u91cf\u7a0b\u5e8f\u7684\u8ba1\u7b97\u5bc6\u96c6\u578b\u5de5\u4f5c\u91cf\uff0c\u5373\u5927\u91cf\u8ba1\u7b97\u64cd\u4f5c\uff0c\u6bd4\u5982\u5faa\u73af\u548c\u6570\u5b66\u8ba1\u7b97\u3002 - \u901a\u8fc7 time.process_time() \u51fd\u6570\u53ef\u4ee5\u83b7\u53d6\u5f53\u524d\u8fdb\u7a0b\u7684 CPU \u65f6\u95f4\u3002 \u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\uff1a - \u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u662f\u4ece\u67d0\u4e2a\u65f6\u95f4\u70b9\u5230\u73b0\u5728\u7684\u5b9e\u9645\u7ecf\u8fc7\u7684\u65f6\u95f4\uff0c\u8003\u8651\u4e86\u6240\u6709\u56e0\u7d20\uff0c\u5305\u62ec\u4e86 CPU \u65f6\u95f4\u3001\u7b49\u5f85\u65f6\u95f4\u3001\u7cfb\u7edf\u8c03\u5ea6\u7b49\u3002 - \u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u7528\u4e8e\u6d4b\u91cf\u4ee3\u7801\u7684\u603b\u6267\u884c\u65f6\u95f4\uff0c\u5305\u62ec\u4e86\u8ba1\u7b97\u548c\u7b49\u5f85\u7684\u65f6\u95f4\u3002 - \u901a\u8fc7 time.perf_counter() \u51fd\u6570\u53ef\u4ee5\u83b7\u53d6\u5f53\u524d\u65f6\u95f4\u3002 \u7cfb\u7edf\u65f6\u95f4\uff1a - \u7cfb\u7edf\u65f6\u95f4\u662f\u64cd\u4f5c\u7cfb\u7edf\u5185\u90e8\u7ef4\u62a4\u7684\u4e00\u4e2a\u65f6\u95f4\u503c\uff0c\u5b83\u4ee3\u8868\u4e86\u4ece\u67d0\u4e2a\u56fa\u5b9a\u65f6\u95f4\u70b9\u5f00\u59cb\u7684\u79d2\u6570\u3002 - \u7cfb\u7edf\u65f6\u95f4\u901a\u5e38\u7528\u4e8e\u8bb0\u5f55\u4e8b\u4ef6\u548c\u8ba1\u7b97\u65f6\u95f4\u95f4\u9694\uff0c\u4e0d\u53d7\u7a0b\u5e8f\u7684\u6267\u884c\u5f71\u54cd\u3002 - \u901a\u8fc7 time.time() \u51fd\u6570\u53ef\u4ee5\u83b7\u53d6\u5f53\u524d\u7684\u7cfb\u7edf\u65f6\u95f4\u3002 \u603b\u7ed3\uff1aCPU \u65f6\u95f4\u5173\u6ce8\u7684\u662f\u7a0b\u5e8f\u5728 CPU \u4e0a\u7684\u6267\u884c\u65f6\u95f4\uff0c\u5b9e\u9645\u7ecf\u8fc7\u65f6\u95f4\u5173\u6ce8\u7684\u662f\u4ece\u4ee3\u7801\u5f00\u59cb\u5230\u7ed3\u675f\u6240\u7ecf\u8fc7\u7684\u771f\u5b9e\u65f6\u95f4\uff0c\u7cfb\u7edf\u65f6\u95f4\u662f\u7cfb\u7edf\u7ef4\u62a4\u7684\u5168\u5c40\u65f6\u95f4\u3002\u5728\u4e0d\u540c\u7684\u573a\u666f\u4e2d\uff0c\u4f60\u53ef\u4ee5\u6839\u636e\u9700\u8981\u9009\u62e9\u5408\u9002\u7684\u65f6\u95f4\u6307\u6807\u6765\u8fdb\u884c\u6027\u80fd\u6d4b\u91cf\u548c\u5206\u6790\u3002","title":"3.1.4.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/03_TimeComplexity/#32","text":"\u590d\u6742\u5ea6\u5206\u6790\uff08complexity analysis\uff09\u65b9\u6cd5\uff0c\u4e00\u79cd\u8bc4\u4f30\u7b97\u6cd5\u6548\u7387\u7684\u65b9\u6cd5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u53ef\u4ee5\u4e0d\u7528\u5173\u5fc3\u4e0e\u5e73\u53f0\u76f8\u5173\u7684\u65f6\u95f4\uff0c\u4e5f\u4e0d\u9700\u8981\u4f7f\u7528\u7edf\u8ba1\u6307\u4ee4\u6570\u91cf\u8fd9\u79cd\u65b9\u6cd5\u6765\u5bf9\u7b97\u6cd5\u8fdb\u884c\u8bc4\u4f30\u3002","title":"3.2.\u590d\u6742\u5ea6\u5206\u6790"},{"location":"python/DataStructure/03_TimeComplexity/#321","text":"\u5728 3.1.2.\u7edf\u8ba1\u6307\u4ee4\u6570 \u4e2d\u5173\u4e8e\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u7684\u4e24\u4e2a\u7b97\u6cd5\uff0c\u5b83\u4eec\u590d\u6742\u5ea6\u7684\u9636\uff08order of complexity\uff09\u4e0a\u662f\u4e0d\u4e00\u6837\u7684\u3002 \u7b2c\u4e00\u4e2a\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u4e4b\u95f4\u662f\u7ebf\u6027\u5173\u7cfb\uff0c\u79f0\u5176\u590d\u6742\u5ea6\u4e3a\u7ebf\u6027\uff08linear\uff09\u9636\uff1b \u7b2c\u4e8c\u4e2a\u7b97\u6cd5\u4e2d\uff0c\u8fed\u4ee3\u6b21\u6570\u548c\u95ee\u9898\u89c4\u6a21\u4e4b\u95f4\u662f\u5e73\u65b9\u5173\u7cfb\uff0c\u79f0\u5176\u590d\u6742\u5ea6\u4e3a\u5e73\u65b9\uff08quadratic\uff09\u9636\uff1b \u5982\u679c\u7b97\u6cd5\u9700\u8981\u76f8\u540c\u6570\u91cf\u7684\u8fd0\u7b97\uff0c\u90a3\u4e48\u5b83\u7684\u6027\u80fd\u5c31\u662f\u5e38\u6570\uff08constant\uff09\u9636\u3002\u5217\u8868\u7d22\u5f15\u5c31\u662f\u4e00\u4e2a\u5e38\u6570\u65f6\u95f4\u7b97\u6cd5\u7684\u4f8b\u5b50\u3002 \u6bd4\u7ebf\u6027\u6027\u80fd\u597d\uff0c\u4f46\u6bd4\u5e38\u6570\u6027\u80fd\u5dee\u7684\u53e6\u4e00\u4e2a\u590d\u6742\u5ea6\u7684\u9636\u88ab\u79f0\u4e3a\u5bf9\u6570\uff08logarithmic\uff09\u9636\u3002\u5bf9\u6570\u7b97\u6cd5\u7684\u5de5\u4f5c\u91cf\u4e0e\u95ee\u9898\u89c4\u6a21\u7684\u4ee52\u4e3a\u5e95\u7684\u5bf9\u6570\u6210\u6b63\u6bd4\u3002\u5f53\u95ee\u9898\u89c4\u6a21\u6269\u5927\u4e00\u500d\u65f6\uff0c\u5de5\u4f5c\u91cf\u53ea\u4f1a\u52a01\u3002 \u591a\u9879\u5f0f\u65f6\u95f4\u7b97\u6cd5\uff08polynomial time algorithm\uff09\u7684\u5de5\u4f5c\u91cf\u4f1a\u4ee5 n^k \u7684\u901f\u7387\u589e\u957f\uff0c\u5176\u4e2d k \u662f\u5927\u4e8e 1 \u7684\u5e38\u6570\uff0c\u6bd4\u5982 n^2 \u3001 n^3 \u4ee5\u53ca n^10 \u3002\u4ece\u67d0\u79cd\u610f\u4e49\u4e0a\u8bb2\uff0c n^3 \u7684\u6027\u80fd\u8981\u6bd4 n^2 \u5dee\uff0c\u4f46\u90fd\u5c5e\u4e8e\u591a\u9879\u5f0f\uff08polynomial\uff09\u9636\u3002 \u6bd4\u591a\u9879\u5f0f\u8fd8\u8981\u5dee\u7684\u590d\u6742\u5ea6\u7684\u9636\u88ab\u79f0\u4e3a\u6307\u6570\uff08exponential\uff09\u9636\uff0c\u6bd4\u5982 2^n \u3002\u5bf9\u4e8e\u5927\u7684\u95ee\u9898\u89c4\u6a21\u6765\u8bf4\uff0c\u6307\u6570\u7b97\u6cd5\u662f\u4e0d\u53ef\u884c\u7684\u3002 \u4e0d\u540c\u590d\u6742\u5ea6\u9636\u7684\u7b97\u6cd5\u7684\u5de5\u4f5c\u91cf\u6bd4\u8f83\uff08\u4ece\u5c0f\u5230\u5927\uff09\uff1a\u5bf9\u6570\u9636 < \u7ebf\u6027\u9636 < \u5e73\u65b9\u9636 < \u6307\u6570\u9636\u3002\u968f\u7740\u95ee\u9898\u89c4\u6a21\u7684\u589e\u5927\uff0c\u5177\u6709\u8f83\u9ad8\u590d\u6742\u5ea6\u7684\u9636\u7684\u7b97\u6cd5\u7684\u6027\u80fd\u4f1a\u66f4\u5feb\u5730\u53d8\u5dee\u3002","title":"3.2.1.\u590d\u6742\u5ea6\u7684\u9636"},{"location":"python/DataStructure/03_TimeComplexity/#322o","text":"\u5f88\u591a\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u4e2d\u7684\u5de5\u4f5c\u91cf\u901a\u5e38\u662f\u591a\u9879\u5f0f\u91cc\u591a\u9879\u7684\u603b\u548c\uff0c\u800c\u5f53\u5de5\u4f5c\u91cf\u8868\u793a\u4e3a\u591a\u9879\u5f0f\u65f6\uff0c\u5176\u4e2d\u4e00\u9879\u662f\u4e3b\u5bfc\u9879\uff08dominant\uff09\u3002\u968f\u7740 n \u8d8a\u6765\u8d8a\u5927\uff0c\u4e3b\u5bfc\u9879\u5c06\u53d8\u5f97\u975e\u5e38\u5927\uff0c\u4ee5\u81f3\u4e8e\u53ef\u4ee5\u5ffd\u7565\u5176\u4ed6\u9879\u6240\u4ee3\u8868\u7684\u5de5\u4f5c\u91cf\u3002\u56e0\u6b64\uff0c\u5bf9\u4e8e\u591a\u9879\u5f0f n^2+n \uff0c\u53ea\u9700\u8981\u7740\u91cd\u8003\u8651\u5e73\u65b9\u9879 n^2 \uff0c\u4e5f\u5c31\u662f\u5728\u8003\u8651\u7684\u65f6\u5019\u53ef\u4ee5\u5ffd\u7565\u7ebf\u6027\u9879 n \u3002\u968f\u7740 n^2 \u53d8\u5f97\u975e\u5e38\u5927\uff0c\u591a\u9879\u5f0f\u7684\u503c\u6e10\u8fd1\u5730\u63a5\u8fd1\u6216\u8fd1\u4f3c\u4e8e\u5b83\u7684\u6700\u5927\u9879\u503c\uff0c\u8fd9\u79cd\u5f62\u5f0f\u7684\u5206\u6790\u6709\u65f6\u88ab\u79f0\u4e3a\u6e10\u8fd1\u5206\u6790\uff08asymptotic analysis\uff09\u3002 \u8ba1\u7b97\u4e2d\u7528\u6765\u8868\u793a\u7b97\u6cd5\u7684\u6548\u7387\u6216\u8ba1\u7b97\u590d\u6742\u5ea6\u7684\u4e00\u79cd\u65b9\u6cd5\u88ab\u79f0\u4e3a\u5927O\u8868\u793a\u6cd5\uff08big-O notation\uff09\u3002\u201cO\u201d\u4ee3\u8868\u201c\u5728\u2026\u2026\u9636\u201d\uff0c\u6307\u7684\u662f\u7b97\u6cd5\u5de5\u4f5c\u7684\u590d\u6742\u5ea6\u7684\u9636\u3002\u4f8b\u5982\uff1a \u5e38\u6570\u65f6\u95f4\uff1aO(1) \u7ebf\u6027\u65f6\u95f4\uff1aO(n) \u5e73\u65b9\u65f6\u95f4\uff1aO(n^2) \u7acb\u65b9\u65f6\u95f4\uff1aO(n^3) \u591a\u9879\u5f0f\u65f6\u95f4\uff1aO(n^k)","title":"3.2.2.\u5927O\u8868\u793a\u6cd5"},{"location":"python/DataStructure/03_TimeComplexity/#323","text":"\u6bd4\u4f8b\u5e38\u6570\uff08constant of proportionality\uff09\u5305\u542b\u5728\u5927O\u5206\u6790\u4e2d\u88ab\u5ffd\u7565\u7684\u9879\u548c\u7cfb\u6570\u3002\u6bd4\u5982\uff0c\u7ebf\u6027\u65f6\u95f4\u7b97\u6cd5\u6240\u6267\u884c\u7684\u5de5\u4f5c\u91cf\u53ef\u4ee5\u8868\u793a\u4e3a\uff1a work = 2 * size \uff0c\u5176\u4e2d\u6bd4\u4f8b\u5e38\u6570\u5c31\u662f work/size \uff0c\u4e5f\u5c31\u662f 2 \u3002\u5728\u5904\u7406\u4e2d\u5c0f\u578b\u6570\u636e\u96c6\u7684\u65f6\u5019\uff0c\u5982\u679c\u8fd9\u4e9b\u5e38\u6570\u5f88\u5927\uff0c\u90a3\u4e48\u5b83\u4eec\u4e5f\u4f1a\u5f71\u54cd\u5230\u7b97\u6cd5\u6548\u7387\u3002 \u56de\u987e\u4e0b\u9762\u7684\u4f8b\u5b50\u3002 import time problemSize = 10000000 print ( \" %12s%16s \" % ( \"Problem Size\" , \"Seconds\" )) for count in range ( 5 ): number = 0 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f print ( \" %12d%16.3f \" % ( problemSize , Iterations )) problemSize *= 2 # \u8fd0\u884c\u7ed3\u679c\uff1a # Problem Size Iterations # 10000000 10000000.000 # 20000000 20000000.000 # 40000000 40000000.000 # 80000000 80000000.000 # 160000000 160000000.000 \u5176\u4e2d\u7684\u7b97\u6cd5\u90e8\u5206\uff0c\u9664\u4e86\u5faa\u73af\u8bed\u53e5\u672c\u8eab\uff0c\u8fd8\u6709\u5176\u4ed63\u884c\u4ee3\u7801\uff0c\u5b83\u4eec\u90fd\u662f\u590d\u5236\u8bed\u53e5\uff0c\u90fd\u4f1a\u4ee5\u5e38\u6570\u65f6\u95f4\u8fd0\u884c\u3002\u5047\u8bbe\u5faa\u73af\u8bed\u53e5\u672c\u8eab\u4f1a\u6d88\u8017\u4e00\u4e2a\u65f6\u95f4\u5e38\u6570\uff0c\u90a3\u4e48\u8fd9\u4e2a\u7b97\u6cd5\u7684\u62bd\u8c61\u5de5\u4f5c\u65f6\u95f4\u5c31\u662f 3n+1 \u3002\u867d\u7136 3n+1 \u7684\u5de5\u4f5c\u91cf\u5927\u4e8e n \uff0c\u4f46\u4e8c\u8005\u5728\u8fd0\u884c\u65f6\u90fd\u662f\u7ebf\u6027\u589e\u52a0\uff0c\u6240\u4ee5\u4ed6\u4eec\u8fd0\u884c\u65f6\u90fd\u662f O(n) \u3002 # \u7b97\u6cd5\u5f00\u59cb work = 1 for x in range ( problemSize ): number += 1 work += 1 work -= 1 # \u7b97\u6cd5\u7ed3\u675f","title":"3.2.3.\u6bd4\u4f8b\u5e38\u6570\u7684\u4f5c\u7528"},{"location":"python/DataStructure/03_TimeComplexity/#324","text":"\u5047\u8bbe\u4e0b\u9762\u7684\u8868\u8fbe\u5f0f\u90fd\u5206\u522b\u8868\u793a\u5bf9\u95ee\u9898\u89c4\u6a21\u4e3a n \u7684\u7b97\u6cd5\u6240\u9700\u8981\u6267\u884c\u7684\u64cd\u4f5c\u6570\uff0c\u8bf7\u6307\u51fa\u6bcf\u79cd\u7b97\u6cd5\u4e2d\u7684\u4e3b\u5bfc\u9879\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u5bf9\u5b83\u8fdb\u884c\u5206\u7c7b\u3002 a. 2^n - 4n + 5n b. 2n^2 + 8 c. n^3 n^2 + n \u89e3\u7b54\uff1a a. 2^n\uff0cO(n) b. n 2\uff0cO(n 2) c. n 3\uff0cO(n 3) \u5bf9\u4e8e\u89c4\u6a21\u4e3a n \u7684\u95ee\u9898\uff0c\u7b97\u6cd5A\u548cB\u5206\u522b\u4f1a\u6267\u884c n^2 \u548c (1/2)*n^2+(1/2)*n \u6761\u6307\u4ee4\u3002\u54ea\u79cd\u7b97\u6cd5\u66f4\u9ad8\u6548\uff1f\u6709\u6ca1\u6709\u4e00\u79cd\u7b97\u6cd5\u6bd4\u53e6\u4e00\u79cd\u7b97\u6cd5\u6027\u80fd\u660e\u663e\u66f4\u597d\u7684\u7279\u5b9a\u7684\u95ee\u9898\u89c4\u6a21\uff1f\u662f\u5426\u6709\u8ba9\u4e24\u79cd\u7b97\u6cd5\u90fd\u6267\u884c\u5927\u81f4\u76f8\u540c\u5de5\u4f5c\u91cf\u7684\u7279\u5b9a\u7684\u95ee\u9898\u89c4\u6a21\uff1f \u89e3\u7b54\uff1a \u5728\u6bd4\u8f83\u4e24\u79cd\u7b97\u6cd5\u7684\u6548\u7387\u65f6\uff0c\u901a\u5e38\u5173\u6ce8\u7b97\u6cd5\u6267\u884c\u65f6\u95f4\u968f\u95ee\u9898\u89c4\u6a21\u589e\u957f\u7684\u8d8b\u52bf\u3002\u9898\u76ee\u4e2d\u7684\u4e24\u79cd\u7b97\u6cd5\u7684\u6267\u884c\u6307\u4ee4\u6570\u5206\u522b\u5982\u4e0b\uff1a \u7b97\u6cd5A\uff1a\u6267\u884c n^2 \u6761\u6307\u4ee4\u3002 \u7b97\u6cd5B\uff1a\u6267\u884c (1/2)*n^2+(1/2)*n \u6761\u6307\u4ee4\u3002 \u7528\u5982\u4e0b\u4ee3\u7801\u6a21\u62df\u7b97\u6cd5A\u548c\u7b97\u6cd5B\uff0c\u53ef\u4ee5\u770b\u51fa\uff0c\u968f\u7740 n \u7684\u589e\u52a0\uff0c\u7b97\u6cd5A\u7684\u589e\u957f\u901f\u7387\u8fdc\u5927\u4e8e\u7b97\u6cd5B\u3002\u6240\u4ee5\u53ef\u4ee5\u8ba4\u4e3a\u5728 n >= 2 \u7684\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5A\u4f18\u4e8e\u7b97\u6cd5B\u3002 n = 1 print ( \" %-15s%25s \" % ( \"ProblemSize: n\" , \"A/B\" )) while n < 1000000 : n *= 10 print ( \" %-15d%25d \" % ( n , int (( n ** 2 ) / ( 1 / 2 ) * n ** 2 + ( 1 / 2 ) * n ))) # ProblemSize: n A/B # 10 20005 # 100 200000050 # 1000 2000000000500 # 10000 20000000000005000 # 100000 200000000000000065536 # 1000000 1999999999999999966445568 \u7531\u6b64\u53ef\u5f97\uff0c\u5728\u5927\u95ee\u9898\u89c4\u6a21\u4e0b\uff0c\u7b97\u6cd5B\u7684\u589e\u957f\u901f\u7387\u4f1a\u66f4\u6162\uff0c\u56e0\u4e3a (1/2)*n^2+(1/2)*n \u4e2d\u7684 (1/2)*n \u90e8\u5206\u5bf9\u4e8e\u6574\u4f53\u589e\u957f\u6765\u8bf4\u76f8\u5bf9\u8f83\u5c0f\u3002 \u4e3a\u4e86\u8ba9\u4e24\u79cd\u7b97\u6cd5\u6267\u884c\u76f8\u8fd1\u7684\u5de5\u4f5c\u91cf\uff0c\u6211\u4eec\u53ef\u4ee5\u89e3\u4e0b\u9762\u7684\u65b9\u7a0b\uff1a ( 1 / 2 ) * n ^ 2 + ( 1 / 2 ) * n = k * n ^ 2 \u5176\u4e2d k \u662f\u4e00\u4e2a\u5e38\u6570\uff0c\u8868\u793a\u4e24\u79cd\u7b97\u6cd5\u6267\u884c\u7684\u5de5\u4f5c\u91cf\u76f8\u7b49\u65f6\u7684\u95ee\u9898\u89c4\u6a21\u3002\u901a\u8fc7\u89e3\u8fd9\u4e2a\u65b9\u7a0b\uff0c\u6211\u4eec\u53ef\u4ee5\u627e\u5230\u4e00\u4e2a\u95ee\u9898\u89c4\u6a21 k \uff0c\u5728\u8fd9\u4e2a\u95ee\u9898\u89c4\u6a21\u4e0b\uff0c\u4e24\u79cd\u7b97\u6cd5\u7684\u6267\u884c\u6307\u4ee4\u6570\u76f8\u8fd1\u3002 \u7b97\u6cd5\u7684\u6548\u7387\u5206\u6790\u5e76\u4e0d\u4ec5\u4ec5\u53d6\u51b3\u4e8e\u6307\u4ee4\u6570\uff0c\u8fd8\u53ef\u80fd\u53d7\u5230\u7b97\u6cd5\u4e2d\u5e38\u6570\u56e0\u5b50\u3001\u6570\u636e\u8bbf\u95ee\u6a21\u5f0f\u3001\u5185\u5b58\u5360\u7528\u7b49\u56e0\u7d20\u7684\u5f71\u54cd\u3002\u56e0\u6b64\uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u901a\u5e38\u9700\u8981\u7efc\u5408\u8003\u8651\u591a\u4e2a\u56e0\u7d20\u6765\u786e\u5b9a\u6700\u4f18\u7684\u7b97\u6cd5\u9009\u62e9\u3002 \u5728\u4ec0\u4e48\u65f6\u5019\u5f00\u59cb n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u8868\u73b0\u66f4\u597d\uff1f \u89e3\u7b54\uff1a\u7528\u4e0b\u9762\u7684\u7b97\u6cd5\u6a21\u62df n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u6267\u884c\u5de5\u4f5c\u91cf\u3002\u4ece\u8fd0\u884c\u7ed3\u679c\u53ef\u4ee5\u770b\u51fa\uff1a n=16 \u662f\u5206\u754c\u70b9\uff0c n^4 \u7b97\u6cd5\u4e0e 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u76f8\u7b49\uff1b \u5f53 n<16 \u65f6\uff0c n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u8981\u9ad8\uff1b \u5f53 n>16 \u65f6\uff0c n^4 \u7b97\u6cd5\u6bd4 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u8981\u4f4e\uff1b\u800c\u4e14 2^n \u7b97\u6cd5\u5de5\u4f5c\u91cf\u589e\u957f\u901f\u5ea6\u8fdc\u5927\u4e8e n^4 \u7b97\u6cd5\uff1b n = 1 print ( \" %-8s%10s%15s%10s \" % ( \"Size:n\" , \"A:n^4\" , \"B:2^n\" , \"B/A\" )) while n < 30 : n += 1 print ( \" %-8d%10d%15d%10.3f \" % ( n , int ( n ** 4 ), int ( 2 ** n ), ( 2 ** n ) / ( n ** 4 ))) # \u8fd0\u884c\u7ed3\u679c\uff1a # Size:n A:n^4 B:2^n B/A # 2 16 4 0.250 # 3 81 8 0.099 # 4 256 16 0.062 # 5 625 32 0.051 # 6 1296 64 0.049 # 7 2401 128 0.053 # 8 4096 256 0.062 # 9 6561 512 0.078 # 10 10000 1024 0.102 # 11 14641 2048 0.140 # 12 20736 4096 0.198 # 13 28561 8192 0.287 # 14 38416 16384 0.426 # 15 50625 32768 0.647 # 16 65536 65536 1.000 # 17 83521 131072 1.569 # 18 104976 262144 2.497 # 19 130321 524288 4.023 # 20 160000 1048576 6.554 # 21 194481 2097152 10.783 # 22 234256 4194304 17.905 # 23 279841 8388608 29.976 # 24 331776 16777216 50.568 # 25 390625 33554432 85.899 # 26 456976 67108864 146.854 # 27 531441 134217728 252.554 # 28 614656 268435456 436.725 # 29 707281 536870912 759.063 # 30 810000 1073741824 1325.607","title":"3.2.4.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/03_TimeComplexity/#33","text":"\u7ea6\u5b9a\uff1a \u4ee5\u5217\u8868\u4e3a\u4f8b\uff0c\u4ecb\u7ecd\u641c\u7d22\u548c\u6392\u5e8f\u7684\u7b97\u6cd5\uff1b \u9610\u91ca\u8fd9\u4e9b\u7b97\u6cd5\u7684\u8bbe\u8ba1\uff0c\u5e76\u628a\u5b83\u5b9e\u73b0\u4e3aPython\u51fd\u6570\uff1b \u51fd\u6570\u53ea\u5904\u7406\u5168\u90e8\u662f\u6574\u6570\u7684\u5217\u8868\uff0c\u4e0d\u540c\u5927\u5c0f\u7684\u5217\u8868\u5c06\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7ed9\u51fd\u6570\uff1b \u5bf9\u8fd9\u4e9b\u7b97\u6cd5\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u8fdb\u884c\u5206\u6790\uff1b","title":"3.3.\u641c\u7d22\u7b97\u6cd5"},{"location":"python/DataStructure/03_TimeComplexity/#331","text":"Python\u4e2d\u6709 min \u51fd\u6570\uff0c\u4f1a\u8fd4\u56de\u5217\u8868\u91cc\u7684\u6700\u5c0f\u503c\u6216\u6700\u5c0f\u5143\u7d20\uff0c\u4e0b\u9762\u5199\u4e00\u4e2a\u65b0\u7b97\u6cd5\uff0c\u6765\u5206\u6790 min \u51fd\u6570\u7684\u7b97\u6cd5\u590d\u6742\u5ea6\u3002 \u7b97\u6cd5\u76ee\u6807\uff1a\u5047\u5b9a\u5217\u8868\u4e0d\u4e3a\u7a7a\uff0c\u5e76\u4e14\u5143\u7d20\u662f\u6309\u7167\u4efb\u610f\u987a\u5e8f\u5b58\u653e\u5728\u5217\u8868\u91cc\u7684\uff0c\u7b97\u6cd5\u8fd4\u56de\u6700\u5c0f\u5143\u7d20\u7684\u7d22\u5f15\uff08index\uff09\u3002 \u7b97\u6cd5\u89e3\u6790\uff1a \u9996\u5148\u628a\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u4f5c\u4e3a\u5b58\u653e\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\uff1b \u7136\u540e\u5411\u53f3\u4fa7\u641c\u7d22\u66f4\u5c0f\u7684\u5143\u7d20\uff1b \u5982\u679c\u627e\u5230\uff0c\u90a3\u4e48\u628a\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\u91cd\u7f6e\u4e3a\u5f53\u524d\u4f4d\u7f6e\uff1b \u5f53\u7b97\u6cd5\u5230\u8fbe\u5217\u8868\u672b\u5c3e\u65f6\uff0c\u5b83\u5c06\u8fd4\u56de\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\u3002 \u7b97\u6cd5\u5b9e\u73b0\uff1a def indexOfMin ( lyst ): \"\"\"\u8fd4\u56de\u6700\u5c0f\u5143\u7d20\u7684\u7d22\u5f15\uff0c\u76f8\u540c\u6700\u5c0f\u5143\u7d20\u8fd4\u56de\u7b2c\u4e00\u4e2a\u7d22\u5f15\"\"\" # \u7b97\u6cd5\u5f00\u59cb minIndex = 0 currentIndex = 1 while currentIndex < len ( lyst ): if lyst [ currentIndex ] < lyst [ minIndex ]: # \u6539\u6210<=\uff0c\u76f8\u540c\u6700\u5c0f\u5143\u7d20\u5219\u8fd4\u56de\u6700\u540e\u4e00\u4e2a\u7d22\u5f15 minIndex = currentIndex currentIndex += 1 return minIndex # \u7b97\u6cd5\u7ed3\u675f def main (): myList = [ 2 , 20 , 5 , 0 , 1 , 0 , 9 ] minIndex = indexOfMin ( myList ) print ( minIndex , myList [ minIndex ]) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # 3 0 # \u5982\u679c\u6539\u6210\u6539\u6210yst[currentIndex] <= lyst[minIndex]\uff0c\u5219\u76f8\u540c\u6700\u5c0f\u5143\u7d20\u5219\u8fd4\u56de\u6700\u540e\u4e00\u4e2a\u7d22\u5f15 # 5 0 \u65e0\u8bba\u5217\u8868\u7684\u5927\u5c0f\u5982\u4f55\uff0c\u5faa\u73af\u5916\u76843\u6761\u6307\u4ee4\uff082\u6761\u8d4b\u503c\u8bed\u53e5\uff0c\u4e00\u6761while\u8bed\u53e5\u672c\u8eab\uff09\u90fd\u4f1a\u6267\u884c\u76f8\u540c\u7684\u6b21\u6570\uff0c\u53ef\u4ee5\u5ffd\u7565\u5b83\u4eec\u90fd\u5f71\u54cd\u3002 \u5faa\u73af\u91cc\u8fd8\u67093\u6761\u6307\u4ee4\uff0c\u5176\u4e2d if \u8bed\u53e5\u5185\u7684\u6bd4\u8f83 lyst[currentIndex] < lyst[minIndex] \u548c currentIndex += 1 \u7684\u81ea\u589e\uff0c\u4f1a\u5728\u6bcf\u6b21\u5faa\u73af\u65f6\u90fd\u6267\u884c\uff0c\u4e14\u6ca1\u6709\u5176\u5b83\u5d4c\u5957\u6216\u9690\u85cf\u7684\u5faa\u73af\u3002 if \u8bed\u53e5\u4e2d\u7684\u6bd4\u8f83\u64cd\u4f5c\u5b9e\u73b0\u4e86\u8bbf\u95ee\u5217\u8868\u91cc\u7684\u6bcf\u4e2a\u5143\u7d20\uff0c\u4ece\u800c\u80fd\u591f\u627e\u5230\u6700\u5c0f\u5143\u7d20\u7684\u4f4d\u7f6e\u3002 \u56e0\u6b64\uff0c\u8fd9\u4e2a\u7b97\u6cd5\u5fc5\u987b\u5bf9\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\u8fdb\u884c n-1 \u6b21\u6bd4\u8f83\uff0c\u5373\uff0c\u5b83\u7684\u590d\u6742\u5ea6\u4e3aO(n)\u3002","title":"3.3.1.\u6700\u5c0f\u503c\u641c\u7d22"},{"location":"python/DataStructure/03_TimeComplexity/#332","text":"Python\u7684 in \u8fd0\u7b97\u7b26\u5728list\u7c7b\u91cc\u88ab\u5b9e\u73b0\u4e3a\u53eb\u4f5c __contains__ \u7684\u65b9\u6cd5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u5728\u4efb\u610f\u7684\u5143\u7d20\u5217\u8868\u91cc\u641c\u7d22\u7279\u5b9a\u7684\u5143\u7d20\uff0c\u5373\u76ee\u6807\u5143\u7d20\uff08target item\uff09\u3002 \u5728\u5217\u8868\u91cc\uff0c\u627e\u5230\u76ee\u6807\u5143\u7d20\u7684\u552f\u4e00\u65b9\u6cd5\u662f\u4ece\u4f4d\u4e8e\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u5f00\u59cb\uff0c\u5e76\u628a\u5b83\u548c\u76ee\u6807\u5143\u7d20\u8fdb\u884c\u6bd4\u8f83\u3002\u5982\u679c\u4e24\u4e2a\u5143\u7d20\u76f8\u7b49\uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u8fd4\u56de True \uff1b\u5426\u5219\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u5c06\u79fb\u52a8\u5230\u4e0b\u4e00\u4e2a\u4f4d\u7f6e\uff0c\u5e76\u628a\u5b83\u548c\u76ee\u6807\u5143\u7d20\u8fdb\u884c\u6bd4\u8f83\u3002\u5982\u679c\u8fd9\u4e2a\u65b9\u6cd5\u5230\u4e86\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u4ecd\u7136\u627e\u4e0d\u5230\u76ee\u6807\uff0c\u90a3\u4e48\u8fd4\u56de False \u3002\u8fd9\u79cd\u641c\u7d22\u79f0\u4e3a\u987a\u5e8f\u641c\u7d22\uff08sequential search\uff09\u6216\u7ebf\u6027\u641c\u7d22\uff08linear search\uff09\u3002 \u4e0b\u9762\u662f\u987a\u5e8f\u641c\u7d22\u51fd\u6570\u7684\u5b9e\u73b0\u3002\u82e5\u987a\u5e8f\u641c\u7d22\u7b97\u6cd5\u5728\u5217\u8868\u5f00\u5934\u5c31\u627e\u5230\u76ee\u6807\u5143\u7d20\uff0c\u90a3\u4e48\u8fd9\u65f6\u7684\u5de5\u4f5c\u91cf\u660e\u663e\u4f1a\u6bd4\u5728\u5217\u8868\u672b\u5c3e\u627e\u5230\u7684\u5de5\u4f5c\u91cf\u8981\u5c11\u3002 def sequentialSearch ( target , lyst ): \"\"\"\u627e\u5230\u76ee\u6807\u5143\u7d20\u65f6\u8fd4\u56de\u5143\u7d20\u7684\u7d22\u5f15, \u5426\u5219\u8fd4\u56de-1\"\"\" position = 0 while position < len ( lyst ): if target == lyst [ position ]: return position position += 1 return - 1 def main (): myList = [ 2 , 20 , 5 , 0 , 1 , 0 , 9 ] locatedIndex = sequentialSearch ( 9 , myList ) print ( locatedIndex , myList [ locatedIndex ]) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # 6 9","title":"3.3.2.\u987a\u5e8f\u641c\u7d22\u5217\u8868"},{"location":"python/DataStructure/03_TimeComplexity/#333","text":"\u4e00\u822c\u6765\u8bf4\uff0c\u91cd\u70b9\u5173\u6ce8\u5728\u5e73\u5747\u60c5\u51b5\u548c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\uff0c\u4e0d\u4f1a\u7279\u522b\u5173\u6ce8\u6700\u597d\u60c5\u51b5\u3002 \u5bf9\u987a\u5e8f\u641c\u7d22\u7684\u5206\u6790\u9700\u8981\u8003\u8651\u4e0b\u97623\u79cd\u60c5\u51b5\u3002 \u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u76ee\u6807\u5143\u7d20\u4f4d\u4e8e\u5217\u8868\u7684\u672b\u5c3e\u6216\u8005\u6839\u672c\u5c31\u4e0d\u5728\u5217\u8868\u91cc\u3002\u8fd9\u65f6\uff0c\u8fd9\u4e2a\u7b97\u6cd5\u5c31\u5fc5\u987b\u8bbf\u95ee\u6bcf\u4e00\u4e2a\u5143\u7d20\uff0c\u5bf9\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\u9700\u8981\u6267\u884c n \u6b21\u8fed\u4ee3\u3002\u56e0\u6b64\uff0c\u987a\u5e8f\u641c\u7d22\u7684\u6700\u574f\u60c5\u51b5\u7684\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u53ea\u9700\u8981O(1)\u7684\u590d\u6742\u5ea6\uff0c\u56e0\u4e3a\u8fd9\u4e2a\u7b97\u6cd5\u5728\u4e00\u6b21\u8fed\u4ee3\u4e4b\u540e\u5c31\u4f1a\u5728\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u627e\u5230\u76ee\u6807\u5143\u7d20\u3002 \u8981\u786e\u5b9a\u5e73\u5747\u60c5\u51b5\uff0c\u5c31\u9700\u8981\u628a\u6bcf\u4e2a\u53ef\u80fd\u4f4d\u7f6e\u627e\u5230\u76ee\u6807\u6240\u9700\u8981\u7684\u8fed\u4ee3\u6b21\u6570\u76f8\u52a0\uff0c\u7136\u540e\u518d\u5c06\u5b83\u4eec\u7684\u603b\u548c\u9664\u4ee5 n \u3002\u56e0\u6b64\uff0c\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u4f1a\u6267\u884c (n + n\u22121 + n\u22122+ ... +1)/n \u6216 (n+1)/2 \u6b21\u8fed\u4ee3\u3002\u5bf9\u4e8e\u975e\u5e38\u5927\u7684 n \u6765\u8bf4\uff0c\u5e38\u6570\u7cfb\u65702\u662f\u53ef\u4ee5\u5ffd\u7565\u7684\uff0c\u56e0\u6b64\uff0c\u5e73\u5747\u60c5\u51b5\u7684\u590d\u6742\u5ea6\u4ecd\u7136\u662fO(2)\u3002 \u7ed3\u8bba\uff1a\u6700\u597d\u60c5\u51b5\u4e0b\u987a\u5e8f\u641c\u7d22\u7684\u6027\u80fd\u548c\u5176\u4ed6\u4e24\u79cd\u60c5\u51b5\u6bd4\u8d77\u6765\u5c0f\u5f88\u591a\uff0c\u800c\u5176\u4ed6\u4e24\u79cd\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u662f\u5dee\u4e0d\u591a\u7684\u3002","title":"3.3.3.\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd"},{"location":"python/DataStructure/03_TimeComplexity/#334","text":"\u5728\u6570\u636e\u65e0\u5e8f\u7684\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528\u987a\u5e8f\u641c\u7d22\u6765\u627e\u5230\u76ee\u6807\u5143\u7d20\u3002 \u5728\u6570\u636e\u6709\u5e8f\u7684\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528\u4e8c\u5206\u641c\u7d22\u6765\u627e\u5230\u76ee\u6807\u5143\u7d20\u3002 Python\u4e2d\u5b9e\u73b0\u4e8c\u5206\u641c\u7d22\u7684\u601d\u8def\uff1a \u5047\u8bbe\u5217\u8868\u91cc\u7684\u5143\u7d20\u90fd\u4ee5\u5347\u5e8f\u6392\u5e8f\u3002 \u641c\u7d22\u7b97\u6cd5\u9996\u5148\u5230\u5217\u8868\u7684\u4e2d\u95f4\u4f4d\u7f6e\uff0c\u5e76\u628a\u8fd9\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u4e0e\u76ee\u6807\u5143\u7d20\u8fdb\u884c\u6bd4\u8f83\uff1b \u5982\u679c\u5339\u914d\uff0c\u90a3\u4e48\u7b97\u6cd5\u5c31\u8fd4\u56de\u5f53\u524d\u4f4d\u7f6e\u3002\u5982\u679c\u76ee\u6807\u5143\u7d20\u5c0f\u4e8e\u5f53\u524d\u5143\u7d20\uff0c\u90a3\u4e48\u7b97\u6cd5\u5c06\u4f1a\u641c\u7d22\u4e2d\u95f4\u4f4d\u7f6e\u4e4b\u524d\u7684\u90e8\u5206\uff1b \u5982\u679c\u76ee\u6807\u5143\u7d20\u5927\u4e8e\u5f53\u524d\u5143\u7d20\uff0c\u5219\u641c\u7d22\u4e2d\u95f4\u4f4d\u7f6e\u4e4b\u540e\u7684\u90e8\u5206\u3002 \u5728\u627e\u5230\u4e86\u76ee\u6807\u5143\u7d20\u6216\u8005\u5f53\u524d\u5f00\u59cb\u4f4d\u7f6e\u5927\u4e8e\u5f53\u524d\u7ed3\u675f\u4f4d\u7f6e\u65f6\uff0c\u505c\u6b62\u641c\u7d22\u8fc7\u7a0b\u3002 \u4e0b\u9762\u662f\u4e8c\u5206\u641c\u7d22\u51fd\u6570\u7684\u4ee3\u7801\u3002\u4ee5\u5217\u8868 [2, 20, 5, 0, 1, 0, 9] \u4e3a\u4f8b\uff1a \u6392\u5e8f\u540e\u7684\u5217\u8868\u4e3a [0, 0, 1, 2, 5, 9, 20] \uff1b \u6392\u5e8f\u540e\u5217\u8868\u957f\u5ea6\u662f7\uff0c\u6240\u4ee5\u521d\u59cbmidpoint=3\uff0c\u5bf9\u5e94\u5217\u8868\u503c\u662f2\uff1b def binarySearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 while left <= right : midpoint = ( left + right ) // 2 if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 return - 1 def main (): myList = [ 2 , 20 , 5 , 0 , 1 , 0 , 9 ] sortedList = sorted ( myList ) # \u5982\u679c\u4f7f\u7528myList.sort()\uff0c\u5219\u4f1a\u4fee\u6539myList\u672c\u8eab locatedIndex = binarySearch ( 5 , sortedList ) print ( sortedList ) print ( locatedIndex , sortedList [ locatedIndex ]) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # [0, 0, 1, 2, 5, 9, 20] # 4 5 # \u5982\u679c\u6267\u884cbinarySearch(0, sortedList)\uff0c\u5219\u4f1a\u8fd4\u56de\u7b2c\u4e8c\u4e2a0\u7684\u7d22\u5f15 # [0, 0, 1, 2, 5, 9, 20] # 1 0 \u4e0a\u9762\u4e8c\u5206\u6cd5\u7b97\u6cd5\u590d\u6742\u5ea6\u5206\u6790\uff1a \u7b97\u6cd5\u91cc\u53ea\u6709\u4e00\u4e2a\u5faa\u73af\uff0c\u5e76\u4e14\u6ca1\u6709\u5d4c\u5957\u6216\u9690\u85cf\u7684\u5faa\u73af\u3002\u5982\u679c\u76ee\u6807\u4e0d\u5728\u5217\u8868\u91cc\uff0c\u5c31\u4f1a\u5f97\u5230\u6700\u574f\u60c5\u51b5\uff0c\u5373\u904d\u5386\u5217\u8868\u7684\u4e00\u534a\uff0c\u5373\u5faa\u73af\u5217\u8868\u5927\u5c0f\u4e0d\u65ad\u9664\u4ee52\u76f4\u81f3\u5546\u4e3a1\u7684\u6b21\u6570\u3002 \u5bf9\u4e8e\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\u6765\u8bf4\uff0c\u4e5f\u5c31\u662f\u4f60\u9700\u8981\u6267\u884c n/2/2/.../2 \u6b21\uff0c\u76f4\u5230\u7ed3\u679c\u4e3a1\u3002\u5047\u8bbe k \u662f n \u53ef\u4ee5\u9664\u4ee52\u7684\u6b21\u6570\uff0c\u90a3\u4e48\u6c42\u89e3 k \u4f1a\u6709 n/(2^k)=1 \uff0c\u5373 n=2^k \uff0c\u5373 k=log(n,2) \u3002\u56e0\u6b64\uff0c\u4e8c\u5206\u641c\u7d22\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u590d\u6742\u5ea6\u4e3aO(log(n,2))\u3002","title":"3.3.4.\u57fa\u4e8e\u6709\u5e8f\u5217\u8868\u7684\u4e8c\u5206\u641c\u7d22"},{"location":"python/DataStructure/03_TimeComplexity/#335","text":"\u4e8c\u5206\u641c\u7d22\u548c\u6700\u5c0f\u503c\u641c\u7d22\u90fd\u6709\u4e00\u4e2a\u5047\u8bbe\uff0c\u90a3\u5c31\u662f\u201c\u5217\u8868\u91cc\u7684\u5143\u7d20\u5f7c\u6b64\u4e4b\u95f4\u662f\u53ef\u4ee5\u6bd4\u8f83\u7684\u201d\u3002\u5373\uff0c\u8fd9\u4e9b\u5143\u7d20\u5c5e\u4e8e\u540c\u4e00\u4e2a\u7c7b\u578b\uff0c\u5373\uff0c\u53ef\u4ee5\u4f7f\u7528\u6bd4\u8f83\u8fd0\u7b97\u7b26 == \u3001 < \u548c > \u3002 Python\u5185\u7f6e\u7684\u7c7b\u578b\u5bf9\u8c61\uff0c\u5982\u6570\u5b57\u3001\u5b57\u7b26\u4e32\u548c\u5217\u8868\uff0c\u90fd\u652f\u6301\u6bd4\u8f83\u8fd0\u7b97\u7b26\u3002 \u4e3a\u4e86\u80fd\u591f\u8ba9\u7b97\u6cd5\u5bf9\u65b0\u7684\u7c7b\u5bf9\u8c61\u4f7f\u7528\u6bd4\u8f83\u8fd0\u7b97\u7b26 == \u3001 < \u548c > \uff0c\u5e94\u8be5\u5728\u8fd9\u4e2a\u7c7b\u91cc\u5b9a\u4e49 __eq__ \u3001 __lt__ \u548c __gt__ \u65b9\u6cd5\u3002\u5728\u5b9a\u4e49\u4e86\u8fd9\u4e9b\u65b9\u6cd5\u4e4b\u540e\uff0c\u5176\u4ed6\u6bd4\u8f83\u8fd0\u7b97\u7b26\u7684\u65b9\u6cd5\u5c06\u81ea\u52a8\u751f\u6210\u3002 \u4f8b\u5982\uff0c __lt__ \u7684\u5b9a\u4e49\u5982\u4e0b\uff0c\u5982\u679c self \u5c0f\u4e8e other \uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u5c06\u8fd4\u56de True \uff1b\u5426\u5219\uff0c\u8fd4\u56de False \u3002 __lt__ \u65b9\u6cd5\u4f1a\u4e3a\u4e24\u4e2a\u8d26\u6237\u5bf9\u8c61\u7684 name \u5b57\u6bb5\u8c03\u7528\u8fd0\u7b97\u7b26 < \u3002 \u540d\u79f0\u5b57\u6bb5\u662f\u5b57\u7b26\u4e32\uff0c\u5b57\u7b26\u4e32\u7c7b\u578b\u5df2\u7ecf\u5305\u542b\u5728 __lt__ \u65b9\u6cd5\u91cc\u3002 \u5728\u4f7f\u7528\u8fd0\u7b97\u7b26 < \u65f6\uff0cPython\u4f1a\u81ea\u52a8\u8fd0\u884c\u5b57\u7b26\u4e32\u7684 __lt__ \u65b9\u6cd5\uff0c\u8fd9\u4e0e\u8c03\u7528 str \u51fd\u6570\u65f6\u81ea\u52a8\u8fd0\u884c __str__ \u65b9\u6cd5\u662f\u7c7b\u4f3c\u7684\u3002 def __lt__ ( self , other ): \u793a\u4f8b\uff1a\u8fd4\u56de\u50a8\u84c4\u8d26\u6237\u7684\u6240\u6709\u4eba\u540d\u5b57\u3001PIN\u7801\u3001\u4f59\u989d\u3002 class SavingsAccount ( object ): \"\"\"\u8fd4\u56de\u50a8\u84c4\u8d26\u6237\u7684\u6240\u6709\u4eba\u540d\u5b57\u3001PIN\u7801\u3001\u4f59\u989d\"\"\" def __init__ ( self , name , pin , balance = 0.0 ): self . name = name self . pin = pin self . balance = balance def __lt__ ( self , other ): return self . name < other . name # Other methods, including __eq__ def main (): s1 = SavingsAccount ( \"Ken\" , \"1001\" , 0 ) s2 = SavingsAccount ( \"Bill\" , \"1001\" , 30 ) s3 = SavingsAccount ( \"Ken\" , \"1000\" , 0 ) s4 = s1 print ( \"s1 < s2: \" , s1 < s2 ) print ( \"s2 < s1: \" , s2 < s1 ) print ( \"s2 > s1: \" , s2 > s1 ) print ( \"s2 == s1: \" , s2 == s1 ) print ( \"s1 == s3: \" , s1 == s3 ) print ( \"s1 == s4: \" , s1 == s4 ) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # s1 < s2: False # s2 < s1: True # s2 > s1: False # s2 == s1: False # s1 == s3: False # s1 == s4: True \u63d0\u793a\uff1a\u5728Python\u4e2d\uff0c\u9ed8\u8ba4\u662f\u6309\u7167ASCII\u7684\u5927\u5c0f\u6bd4\u8f83\u5b57\u7b26\u4e32\u7684\uff0c\u5373\u4ece\u5b57\u7b26\u4e32\u7684\u7b2c\u4e00\u4e2a\u5b57\u7b26\u8fdb\u884c\u6bd4\u8f83\uff0c\u5982\u679c\u76f8\u7b49\uff0c\u5219\u7ee7\u7eed\u6bd4\u8f83\u4e0b\u4e00\u4e2a\u5b57\u7b26\uff0c\u76f4\u5230\u5206\u51fa\u5927\u5c0f\uff0c\u6216\u8005\u8fd8\u6ca1\u5206\u51fa\u5927\u5c0f\uff0c\u6709\u4e00\u4e2a\u5b57\u7b26\u4e32\u5df2\u7ecf\u5230\u5934\u4e86\uff0c\u90a3\u4e48\u8f83\u957f\u7684\u90a3\u4e00\u4e2a\u5b57\u7b26\u4e32\u5927\u3002","title":"3.3.5.\u6bd4\u8f83\u6570\u636e\u5143\u7d20"},{"location":"python/DataStructure/03_TimeComplexity/#336","text":"\u5047\u8bbe\u4e00\u4e2a\u5217\u8868\u5728\u7d22\u5f150\uff5e9\u7684\u4f4d\u7f6e\u5904\u5305\u542b\u503c20\u300144\u300148\u300155\u300162\u300166\u300174\u300188\u300193\u300199\uff0c\u8bf7\u5728\u7528\u4e8c\u5206\u641c\u7d22\u67e5\u627e\u76ee\u6807\u5143\u7d2090\u7684\u65f6\u5019\uff0c\u5bf9\u53d8\u91cfleft\u3001right\u548cmidpoint\u7684\u503c\u8fdb\u884c\u8ddf\u8e2a\u3002\u6539\u53d8\u76ee\u6807\u5143\u7d20\u4e3a44\uff0c\u5e76\u91cd\u590d\u8fd9\u4e2a\u6b65\u9aa4\u3002 \u89e3\u7b54\uff1a \u4e0b\u9762\u662f\u4ee3\u7801\u548c\u8ddf\u8e2a\u7ed3\u679c\u3002 def binarySearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 print ( \" %5s%10s%10s \" % ( \"left\" , \"midpoint\" , \"right\" )) while left <= right : midpoint = ( left + right ) // 2 print ( \" %5s%10s%10s \" % ( left , midpoint , right )) if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 return - 1 def main (): myList = [ 20 , 44 , 48 , 55 , 62 , 66 , 74 , 88 , 93 , 99 ] sortedList = sorted ( myList ) locatedIndex = binarySearch ( 44 , sortedList ) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # Target = 90 # left midpoint right # 0 4 9 # 5 7 9 # 8 8 9 # # Target = 44 # left midpoint right # 0 4 9 # 0 1 3 \u901a\u5e38\u6765\u8bf4\uff0c\u67e5\u627e\u7535\u8bdd\u7c3f\u4e2d\u6761\u76ee\u7684\u65b9\u6cd5\u4e0e\u4e8c\u5206\u641c\u7d22\u5e76\u4e0d\u5b8c\u5168\u76f8\u540c\uff0c\u56e0\u4e3a\u4f7f\u7528\u7535\u8bdd\u7c3f\u7684\u65f6\u5019\uff0c\u5e76\u4e0d\u4f1a\u6bcf\u6b21\u90fd\u7ffb\u5230\u88ab\u641c\u7d22\u7684\u5b50\u5217\u8868\u7684\u4e2d\u70b9\u3002\u4e00\u822c\u6765\u8bf4\uff0c\u53ef\u4ee5\u6839\u636e\u8fd9\u4e2a\u4eba\u7684\u59d3\u6c0f\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd\u987a\u5e8f\u6765\u4f30\u7b97\u76ee\u6807\u53ef\u80fd\u4f1a\u5728\u7684\u4f4d\u7f6e\u3002\u4f8b\u5982\uff0c\u5f53\u67e5\u627e\u201cSmith\u201d\u7684\u7535\u8bdd\u65f6\uff0c\u4f60\u4f1a\u9996\u5148\u67e5\u770b\u7535\u8bdd\u7c3f\u4e0b\u534a\u90e8\u5206\u7684\u4e2d\u95f4\uff0c\u800c\u4e0d\u662f\u6574\u4e2a\u7535\u8bdd\u7c3f\u7684\u4e2d\u95f4\u3002\u8bf7\u5bf9\u4e8c\u5206\u641c\u7d22\u7b97\u6cd5\u5c1d\u8bd5\u8fdb\u884c\u4fee\u6539\uff0c\u4ece\u800c\u53ef\u4ee5\u5728\u5904\u7406\u540d\u79f0\u5217\u8868\u7684\u65f6\u5019\u6a21\u62df\u8fd9\u4e2a\u7b56\u7565\u3002\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u4e0e\u6807\u51c6\u7684\u4e8c\u5206\u641c\u7d22\u76f8\u6bd4\u8f83\u4f1a\u66f4\u597d\u5417\uff1f \u89e3\u7b54\uff1a\u4e0b\u9762\u662f\u4ee3\u7801\u548c\u8ffd\u8e2a\u7ed3\u679c\u3002\u901a\u8fc7\u5bf9\u6bd4\u4e0d\u540c\u6743\u91cd\u5355\u8bcd\u5230\u7684\u641c\u7d22\uff0c\u53ef\u4ee5\u53d1\u73b0\u6743\u91cd\u4e8c\u5206\u6cd5\u7684\u6548\u7387\u82e5\u8981\u4f18\u4e8e\u4f20\u7edf\u4e8c\u5206\u6cd5\uff0c\u662f\u9700\u8981\u6ee1\u8db3\u4e00\u5b9a\u7684\u6761\u4ef6\u7684\u3002 \u5728\u641c\u7d22\u7684\u7b2c\u4e00\u8f6e\u4e2d\uff0c\u4e2d\u95f4\u4f4d\u7f6e\u5c06\u53d6\u51b3\u4e8e\u5217\u8868\u7684\u5927\u5c0f\u548c\u76ee\u6807\u540d\u5b57\u7684\u7b2c\u4e00\u4e2a\u5b57\u6bcd\u7684\u987a\u5e8f\u503c\u3002\u56e0\u6b64\uff0c\u7b2c\u4e00\u8f6e\u641c\u7d22\u5c06\u6d88\u9664\u6bd4\u4ee5\u524d\u66f4\u591a\u7684\u5143\u7d20\uff0c\u5e76\u4e14\u5982\u679c\u9700\u8981\u5176\u4ed6\u8f6e\u641c\u7d22\uff0c\u5b83\u4eec\u7684\u641c\u7d22\u7a7a\u95f4\u4e5f\u4f1a\u66f4\u5c0f\u3002\u7136\u800c\uff0c\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u4fee\u6539\u540e\u7684\u7b97\u6cd5\u4ecd\u7136\u6bd4O(1)\u66f4\u63a5\u8fd1O(log n)\u3002 def binarySearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 print ( \" %5s%10s%10s \" % ( \"left\" , \"midpoint\" , \"right\" )) while left <= right : midpoint = ( left + right ) // 2 print ( \" %5s%10s%10s \" % ( left , midpoint , right )) if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 return - 1 def letter_position ( myLetter ): letter = myLetter . lower () # \u8f6c\u6210\u5c0f\u5199\u5b57\u6bcd alphabet = \"abcdefghijklmnopqrstuvwxyz\" if letter in alphabet : return alphabet . index ( letter ) + 1 # \u4f4d\u7f6e\u63091\uff5e26\u8ba1\u7b97 else : return None # \u975e\u5b57\u6bcd def dictSearch ( target , sortedLyst ): left = 0 right = len ( sortedLyst ) - 1 # \u9996\u5b57\u6bcd\u5728\u5b57\u6bcd\u8868\u4e2d\u7684\u767e\u5206\u4f4d letter_position_range = letter_position ( target [ 0 ]) * 100 // 26 # \u6309\u7167\u6240\u5f97\u7684\u9996\u5b57\u6bcd\u5728\u5b57\u6bcd\u8868\u4e2d\u7684\u767e\u5206\u4f4d\uff0c\u4f5c\u4e3a\u7ed9\u5b9a\u5b57\u4e32\u4e2d\u8bbe\u5b9a\u641c\u7d22\u8d77\u59cb\u767e\u5206\u4f4d midpoint = letter_position_range * ( len ( sortedLyst ) - 1 ) // 100 print ( \" %5s%10s%10s \" % ( \"left\" , \"midpoint\" , \"right\" )) while left <= right : print ( \" %5s%10s%10s \" % ( left , midpoint , right )) if target == sortedLyst [ midpoint ]: return midpoint elif target < sortedLyst [ midpoint ]: right = midpoint - 1 else : left = midpoint + 1 midpoint = ( left + right ) // 2 return - 1 def main (): myList = [ \"Bob\" , \"Charlie\" , \"Eva\" , \"Alice\" , \"Grace\" , \"David\" , \"Smith\" , \"Frank\" , \"Zoe\" , \"Jack\" ] sortedList = sorted ( myList ) print ( sortedList ) print ( \"=====call binarySearch=====\" ) locatedIndex = binarySearch ( \"Alice\" , sortedList ) print ( \"Found\" , sortedList [ locatedIndex ], \"in position\" , locatedIndex ) print ( \"=====call dictSearch=====\" ) locatedIndex = dictSearch ( \"Alice\" , sortedList ) print ( \"Found\" , sortedList [ locatedIndex ], \"in position\" , locatedIndex ) if __name__ == \"__main__\" : main () # \u8fd0\u7b97\u7ed3\u679c\uff1a # \u641c\u7d22Alice # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 0 1 3 # 0 0 0 # Found Alice in position 0 # =====call dictSearch===== # left midpoint right # 0 0 9 # Found Alice in position 0 # \u641c\u7d22Bob # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 0 1 3 # Found Bob in position 1 # =====call dictSearch===== # left midpoint right # 0 0 9 # 1 5 9 # 1 2 4 # 1 1 1 # Found Bob in position 1 # \u641c\u7d22Smith # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 5 7 9 # 8 8 9 # Found Smith in position 8 # =====call dictSearch===== # left midpoint right # 0 6 9 # 7 8 9 # Found Smith in position 8 # \u641c\u7d22Zoe # ['Alice', 'Bob', 'Charlie', 'David', 'Eva', 'Frank', 'Grace', 'Jack', 'Smith', 'Zoe'] # =====call binarySearch===== # left midpoint right # 0 4 9 # 5 7 9 # 8 8 9 # 9 9 9 # Found Zoe in position 9 # =====call dictSearch===== # left midpoint right # 0 9 9 # Found Zoe in position 9","title":"3.3.6.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/03_TimeComplexity/#34","text":"\u4e0b\u9762\u662fswap\u51fd\u6570\u7684\u4f8b\u5b50\uff0c\u5b9e\u73b0\u4e86\uff1a \u5047\u8bbe\u90fd\u5728\u6574\u6570\u5217\u8868\u4e0a\u8fd0\u884c\uff1b \u4ea4\u6362\u5217\u8868\u4e2d\u4e24\u4e2a\u5143\u7d20\u7684\u4f4d\u7f6e\uff1b def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( myList ) swap ( myList , 3 , 5 ) print ( myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # [9, 4, 2, 7, 6, 8, 1] # [9, 4, 2, 8, 6, 7, 1]","title":"3.4.\u57fa\u672c\u7684\u6392\u5e8f\u7b97\u6cd5"},{"location":"python/DataStructure/03_TimeComplexity/#341","text":"\u9009\u62e9\u6392\u5e8f\uff08selection sort\uff09\uff1a\uff08\u4ee5\u5217\u8868\u4e3a\u4f8b\uff09 \u5728\u4e00\u4e2a\u957f\u5ea6\u4e3a N \u7684\u65e0\u5e8f\u5217\u8868\u4e2d\uff0c\u7b2c\u4e00\u6b21\u904d\u5386 n-1 \u4e2a\u6570\u627e\u5230\u6700\u5c0f\u7684\u548c\u7b2c\u4e00\u4e2a\u6570\u4ea4\u6362\u3002 \u7b2c\u4e8c\u6b21\u4ece\u4e0b\u4e00\u4e2a\u6570\u5f00\u59cb\u904d\u5386 n-2 \u4e2a\u6570\uff0c\u627e\u5230\u6700\u5c0f\u7684\u6570\u548c\u7b2c\u4e8c\u4e2a\u6570\u4ea4\u6362\u3002 \u91cd\u590d\u4ee5\u4e0a\u64cd\u4f5c\u76f4\u5230\u7b2c n-1 \u6b21\u904d\u5386\u6700\u5c0f\u7684\u6570\u548c\u7b2c n-1 \u4e2a\u6570\u4ea4\u6362\uff0c\u6392\u5e8f\u5b8c\u6210\u3002 \u8fd9\u4e2a\u7b97\u6cd5\u5728\u6bcf\u6b21\u901a\u8fc7\u4e3b\u5faa\u73af\u65f6\uff0c\u90fd\u4f1a\u9009\u62e9\u8981\u79fb\u52a8\u7684\u90a3\u4e00\u4e2a\u5143\u7d20\u3002 \u7b97\u6cd5\u590d\u6742\u5ea6\uff1a \u7b2c1\u6b21\u6267\u884c\u5916\u90e8\u5faa\u73af\u65f6\uff0c\u5185\u90e8\u5faa\u73af\u4f1a\u6267\u884cn-1\u6b21\uff1b \u7b2c2\u6b21\u6267\u884c\u5916\u90e8\u5faa\u73af\u65f6\uff0c\u5185\u90e8\u5faa\u73af\u4f1a\u6267\u884cn-2\u6b21\uff1b \u6700\u540e\u4e00\u6b21\u6267\u884c\u5916\u90e8\u5faa\u73af\u65f6\uff0c\u5185\u90e8\u5faa\u73af\u4f1a\u6267\u884c1\u6b21\uff1b \u6240\u4ee5\uff0c\u5927\u5c0f\u4e3a n \u7684\u5217\u8868\uff0c\u4e00\u5171\u9700\u8981\u7684\u6bd4\u8f83\u6b21\u6570\u662f (n-1)+(n-2)+...+1 \uff0c\u5316\u7b80\u4e3a n*(n-1)/2 \uff0c\u5373 (1/2)*n^2+(1/2)*n \u3002\u5f53 n \u6bd4\u8f83\u5927\u65f6\uff0c\u53ef\u4ee5\u9009\u62e9\u6700\u9ad8\u6b21\u7684\u9879\u5e76\u5ffd\u7565\u7cfb\u6570\uff0c\u56e0\u6b64\u5728\u6240\u6709\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u7684\u590d\u6742\u5ea6\u90fd\u662fO(n^2)\u3002 \u5bf9\u4e8e\u5927\u578b\u6570\u636e\u96c6\u6765\u8bf4\uff0c\u4ea4\u6362\u5143\u7d20\u7684\u6210\u672c\u53ef\u80fd\u4f1a\u5f88\u9ad8\u3002\u56e0\u4e3a\u8fd9\u4e2a\u7b97\u6cd5\u53ea\u4f1a\u5728\u5916\u90e8\u5faa\u73af\u91cc\u5bf9\u6570\u636e\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\uff0c\u6240\u4ee5\u5728\u6700\u574f\u60c5\u51b5\u548c\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u7684\u989d\u5916\u6210\u672c\u662f\u7ebf\u6027\u7684\u3002 \u7b97\u6cd5\u4ee3\u7801\uff1a def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 minIndex = i # \u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , minIndex , i ) i += 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9]","title":"3.4.1.\u9009\u62e9\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#342","text":"\u5192\u6ce1\u6392\u5e8f\uff08Bubble Sort\uff09\uff1a \u6bd4\u8f83\u76f8\u90bb\u4e24\u4e2a\u6570\u636e\u5982\u679c\u3002\u7b2c\u4e00\u4e2a\u6bd4\u7b2c\u4e8c\u4e2a\u5927\uff0c\u5c31\u4ea4\u6362\u4e24\u4e2a\u6570\uff1b \u5bf9\u6bcf\u4e00\u4e2a\u76f8\u90bb\u7684\u6570\u505a\u540c\u68371\u7684\u5de5\u4f5c\uff0c\u8fd9\u6837\u4ece\u5f00\u59cb\u4e00\u961f\u5230\u7ed3\u5c3e\u4e00\u961f\u5728\u6700\u540e\u7684\u6570\u5c31\u662f\u6700\u5927\u7684\u6570\u3002 \u9488\u5bf9\u6240\u6709\u5143\u7d20\u4e0a\u9762\u7684\u64cd\u4f5c\uff0c\u9664\u4e86\u6700\u540e\u4e00\u4e2a\u3002 \u91cd\u590d1~3\u6b65\u9aa4\uff0c\u76f4\u81f3\u5b8c\u6210\u3002 \u7b97\u6cd5\u590d\u6742\u5ea6\uff1a \u5192\u6ce1\u6392\u5e8f\u53ea\u4f1a\u6539\u5584\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u590d\u6742\u5ea6\u3002\u5bf9\u4e8e\u5e73\u5747\u60c5\u51b5\u800c\u8a00\uff0c\u7531\u4e8e\u4f9d\u7136\u662f\u53cc\u91cd\u5faa\u73af\u65f6\u95f4\uff0c\u6240\u4ee5\u590d\u6742\u5ea6\u662fO(n^2)\uff1b \u5bf9\u4e8e\u6709\u5e8f\u7684\u5217\u8868\u6765\u8bf4\uff0c\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u4f1a\u6bd4\u9009\u62e9\u6392\u5e8f\u7684\u6267\u884c\u6548\u7387\u66f4\u9ad8\u3002 \u7b97\u6cd5\u4ee3\u7801\uff1a def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 minIndex = i # \u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , minIndex , i ) i += 1 def bubbleSortWithTweak ( lyst ): \"\"\"\u5b9e\u73b0\u5192\u6ce1\u6392\u5e8f\u7b97\u6cd5\"\"\" n = len ( lyst ) while n > 1 : swapped = False # \u7528\u5e03\u5c14\u6807\u5fd7\u6765\u8ffd\u8e2a\u6709\u6ca1\u6709\u53d1\u751f\u4ea4\u6362 i = 1 while i < n : if lyst [ i ] < lyst [ i - 1 ]: # \u5982\u679c\u540e\u9762\u5143\u7d20\u7684\u503c\u6bd4\u524d\u9762\u5143\u7d20\u7684\u5927\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\uff0c\u76f4\u81f3\u628a\u5faa\u73af\u4e2d\u7684\u6700\u5927\u5143\u7d20\u79fb\u5230\u6700\u540e swap ( lyst , i , i - 1 ) swapped = True i += 1 if not swapped : # \u5982\u679c\u4e0d\u9700\u8981\u4ea4\u6362\uff0c\u76f4\u63a5return return n -= 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] # \u6bd4\u8f83\u6392\u5e8f print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) # \u5192\u6ce1\u6392\u5e8f myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before bubble sort \" , myList ) bubbleSortWithTweak ( myList ) print ( \"After bubble sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] # Before bubble sort [9, 4, 2, 7, 6, 8, 1] # After bubble sort [1, 2, 4, 6, 7, 8, 9]","title":"3.4.2.\u5192\u6ce1\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#343","text":"\u63d2\u5165\u6392\u5e8f\uff08Insertion-Sort\uff09\u662f\u901a\u8fc7\u6784\u5efa\u6709\u5e8f\u5e8f\u5217\uff0c\u5bf9\u4e8e\u672a\u6392\u5e8f\u6570\u636e\uff0c\u5728\u5df2\u6392\u5e8f\u5e8f\u5217\u4e2d\u4ece\u540e\u5411\u524d\u626b\u63cf\uff0c\u627e\u5230\u76f8\u5e94\u4f4d\u7f6e\u5e76\u63d2\u5165\u3002\u63d2\u5165\u6392\u5e8f\u90fd\u91c7\u7528 in-place \u5728\u6570\u7ec4\u4e0a\u5b9e\u73b0\uff1a \u4ece\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\uff0c\u8be5\u5143\u7d20\u53ef\u4ee5\u8ba4\u4e3a\u5df2\u7ecf\u88ab\u6392\u5e8f\uff1b \u53d6\u51fa\u4e0b\u4e00\u4e2a\u5143\u7d20\uff0c\u5728\u5df2\u7ecf\u6392\u5e8f\u7684\u5143\u7d20\u5e8f\u5217\u4ece\u540e\u5411\u524d\u626b\u63cf\uff1b \u5982\u679c\u65b0\u5143\u7d20\u5c0f\u4e8e\u5df2\u6392\u5e8f\u7684\u5143\u7d20\uff0c\u5c06\u65b0\u5143\u7d20\u79fb\u5230\u4e0b\u4e00\u4f4d\u7f6e\uff1b \u91cd\u590d\u6b65\u9aa43\uff0c\u76f4\u5230\u627e\u5230\u5df2\u6392\u5e8f\u7684\u5143\u7d20\u5c0f\u4e8e\u6216\u8005\u7b49\u4e8e\u65b0\u5143\u7d20\u7684\u4f4d\u7f6e\uff1b \u5c06\u65b0\u5143\u7d20\u63d2\u5165\u5230\u8be5\u4f4d\u7f6e\u540e\uff1b \u91cd\u590d\u6b65\u9aa42~5\u3002 \u590d\u6742\u5ea6\uff1a \u548c\u9009\u62e9\u6392\u5e8f\u7c7b\u4f3c\uff0c\u904d\u5386\u6b21\u6570\u4e5f\u662f (1/2)*n^2+(1/2)*n \uff0c\u6240\u4ee5\u590d\u6742\u5ea6\u4e5f\u662fO(n^2)\u3002 \u5217\u8868\u91cc\u6709\u5e8f\u5143\u7d20\u8d8a\u591a\uff0c\u63d2\u5165\u6392\u5e8f\u7684\u6027\u80fd\u5c31\u4f1a\u8d8a\u597d\uff1b \u5728\u6709\u5e8f\u5217\u8868\u7684\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u6392\u5e8f\u590d\u6742\u5ea6\u662f\u7ebf\u6027\u7684\uff1b def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 minIndex = i # \u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u5143\u7d20\u4f4d\u7f6e if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , minIndex , i ) i += 1 def bubbleSortWithTweak ( lyst ): \"\"\"\u5b9e\u73b0\u5192\u6ce1\u6392\u5e8f\u7b97\u6cd5\"\"\" n = len ( lyst ) while n > 1 : swapped = False # \u7528\u5e03\u5c14\u6807\u5fd7\u6765\u8ffd\u8e2a\u6709\u6ca1\u6709\u53d1\u751f\u4ea4\u6362 i = 1 while i < n : if lyst [ i ] < lyst [ i - 1 ]: # \u5982\u679c\u540e\u9762\u5143\u7d20\u7684\u503c\u6bd4\u524d\u9762\u5143\u7d20\u7684\u5927\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\uff0c\u76f4\u81f3\u628a\u5faa\u73af\u4e2d\u7684\u6700\u5927\u5143\u7d20\u79fb\u5230\u6700\u540e swap ( lyst , i , i - 1 ) swapped = True i += 1 if not swapped : # \u5982\u679c\u4e0d\u9700\u8981\u4ea4\u6362\uff0c\u76f4\u63a5return return n -= 1 def insertionSort ( lyst ): i = 1 # \u65b0\u5143\u7d20\u7684\u4f4d\u7f6e while i < len ( lyst ): itemToInsert = lyst [ i ] # \u65b0\u5143\u7d20 j = i - 1 # \u5df2\u6392\u5e8f\u7684\u5143\u7d20\u5e8f\u5217\u7684\u6700\u53f3\u4f4d\u7f6e while j >= 0 : if itemToInsert < lyst [ j ]: lyst [ j + 1 ] = lyst [ j ] # \u5982\u679c\u65b0\u5143\u7d20\u5c0f\u4e8e\u5df2\u6392\u5e8f\u5143\u7d20\uff0c\u5219\u5df2\u6392\u5e8f\u5143\u7d20\u5411\u540e\u79fb\u52a8\u4e00\u4e2a\u4f4d\u7f6e j -= 1 else : break # \u65b0\u5143\u7d20\u7b49\u4e8e\u6216\u8005\u5927\u4e8e\u5df2\u6392\u5e8f\u5143\u7d20\uff0c\u8df3\u51fa\u5faa\u73af\uff0c\u6b64\u65f6lyst[j + 1]\u662f\u548clyst[j]\u662f\u540c\u4e00\u4e2a\u5143\u7d20\u503c\uff0clyst[j + 1]\u4f4d\u7f6e\u662f\u7559\u7ed9\u65b0\u5143\u7d20\u7684 lyst [ j + 1 ] = itemToInsert # i += 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] # \u6bd4\u8f83\u6392\u5e8f print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) # \u5192\u6ce1\u6392\u5e8f myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before bubble sort \" , myList ) bubbleSortWithTweak ( myList ) print ( \"After bubble sort \" , myList ) # \u63d2\u5165\u6392\u5e8f myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before insertion sort \" , myList ) insertionSort ( myList ) print ( \"After insertion sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] # Before bubble sort [9, 4, 2, 7, 6, 8, 1] # After bubble sort [1, 2, 4, 6, 7, 8, 9] # Before insertion sort [9, 4, 2, 7, 6, 8, 1] # After insertion sort [1, 2, 4, 6, 7, 8, 9]","title":"3.4.3.\u63d2\u5165\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#344","text":"\u5bf9\u4e8e\u8bb8\u591a\u7b97\u6cd5\u6765\u8bf4\uff0c\u4e0d\u80fd\u5bf9\u6240\u6709\u60c5\u51b5\u91c7\u7528\u5355\u4e00\u7684\u590d\u6742\u5ea6\u6765\u8861\u91cf\u3002\u5f53\u9047\u5230\u7279\u5b9a\u987a\u5e8f\u7684\u6570\u636e\u65f6\uff0c\u7b97\u6cd5\u7684\u884c\u4e3a\u53ef\u80fd\u4f1a\u53d8\u5f97\u66f4\u597d\u6216\u66f4\u7cdf\u3002 \u5bf9\u7b97\u6cd5\u590d\u6742\u5ea6\u884c\u4e3a\u5206\u4e3a3\u79cd\u60c5\u51b5\uff1a \u6700\u597d\u60c5\u51b5\uff08best case\uff09\u2014\u2014\u7b97\u6cd5\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\u53ef\u4ee5\u4ee5\u6700\u5c11\u7684\u5de5\u4f5c\u91cf\u5b8c\u6210\u5de5\u4f5c\uff1f\u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u7684\u590d\u6742\u5ea6\u662f\u591a\u5c11\uff1f \u6700\u574f\u60c5\u51b5\uff08worst case\uff09\u2014\u2014\u7b97\u6cd5\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\u9700\u8981\u5b8c\u6210\u6700\u591a\u7684\u5de5\u4f5c\u91cf\uff1f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u7684\u590d\u6742\u5ea6\u662f\u591a\u5c11\uff1f \u5e73\u5747\u60c5\u51b5\uff08average case\uff09\u2014\u2014\u7b97\u6cd5\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\u7528\u9002\u91cf\u7684\u5de5\u4f5c\u91cf\u5c31\u80fd\u5b8c\u6210\u5de5\u4f5c\uff1f\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u7b97\u6cd5\u7684\u590d\u6742\u5ea6\u662f\u591a\u5c11\uff1f \u4e0b\u9762\u5206\u522b\u5bf9\u6700\u5c0f\u503c\u641c\u7d22\u3001\u987a\u5e8f\u641c\u7d22\u548c\u5192\u6ce1\u6392\u5e8f\u8fdb\u884c\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u548c\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u5206\u6790\uff0c\u4e0d\u8003\u8651\u5b9e\u9645\u786c\u4ef6\u548c\u7f16\u7a0b\u8bed\u8a00\u7b49\u7684\u5f71\u54cd\u3002 \u6700\u5c0f\u503c\u641c\u7d22\uff08Minimum Value Search\uff09 \u6700\u597d\u60c5\u51b5\uff1a\u6700\u5c0f\u503c\u521a\u597d\u5728\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3002\u8fd9\u65f6\uff0c\u53ea\u9700\u8981\u4e00\u6b21\u6bd4\u8f83\u5c31\u53ef\u4ee5\u627e\u5230\u6700\u5c0f\u503c\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(1)\u3002 \u6700\u574f\u60c5\u51b5\uff1a\u6700\u5c0f\u503c\u5728\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u6216\u4e0d\u5b58\u5728\u3002\u8fd9\u65f6\uff0c\u9700\u8981\u8fdb\u884cn-1\u6b21\u6bd4\u8f83\u624d\u80fd\u786e\u5b9a\u6700\u5c0f\u503c\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5e73\u5747\u60c5\u51b5\uff1a\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u6bcf\u4e2a\u5143\u7d20\u6709\u76f8\u7b49\u7684\u6982\u7387\u6210\u4e3a\u6700\u5c0f\u503c\u3002\u56e0\u6b64\uff0c\u5e73\u5747\u6bd4\u8f83\u6b21\u6570\u4e3a(n-1)/2\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u987a\u5e8f\u641c\u7d22\uff08Sequential Search\uff09 \u6700\u597d\u60c5\u51b5\uff1a\u641c\u7d22\u7684\u5143\u7d20\u521a\u597d\u662f\u5217\u8868\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u3002\u8fd9\u65f6\uff0c\u53ea\u9700\u8981\u4e00\u6b21\u6bd4\u8f83\u5c31\u53ef\u4ee5\u627e\u5230\u76ee\u6807\u5143\u7d20\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(1)\u3002 \u6700\u574f\u60c5\u51b5\uff1a\u641c\u7d22\u7684\u5143\u7d20\u5728\u5217\u8868\u7684\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u6216\u4e0d\u5b58\u5728\u3002\u8fd9\u65f6\uff0c\u9700\u8981\u8fdb\u884cn\u6b21\u6bd4\u8f83\u624d\u80fd\u786e\u5b9a\u76ee\u6807\u5143\u7d20\u4e0d\u5b58\u5728\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5e73\u5747\u60c5\u51b5\uff1a\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u6bcf\u4e2a\u5143\u7d20\u6709\u76f8\u7b49\u7684\u6982\u7387\u6210\u4e3a\u76ee\u6807\u5143\u7d20\u3002\u56e0\u6b64\uff0c\u5e73\u5747\u6bd4\u8f83\u6b21\u6570\u4e3a (n+1)/2 \uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002 \u5192\u6ce1\u6392\u5e8f\uff08Bubble Sort\uff09 \u6700\u597d\u60c5\u51b5\uff1a\u5982\u679c\u8f93\u5165\u5217\u8868\u5df2\u7ecf\u662f\u6709\u5e8f\u7684\uff0c\u5192\u6ce1\u6392\u5e8f\u53ea\u9700\u8981\u8fdb\u884c\u4e00\u6b21\u904d\u5386\u6765\u68c0\u6d4b\u5217\u8868\u5df2\u7ecf\u6709\u5e8f\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n)\u3002\u4f46\u5b9e\u9645\u4e0a\uff0c\u901a\u5e38\u9700\u8981\u8fdb\u884c\u591a\u6b21\u904d\u5386\u6765\u5b8c\u6210\u6392\u5e8f\uff0c\u56e0\u6b64\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662fO(n^2)\u3002 \u6700\u574f\u60c5\u51b5\uff1a\u5982\u679c\u8f93\u5165\u5217\u8868\u662f\u9006\u5e8f\u7684\uff0c\u6bcf\u6b21\u904d\u5386\u90fd\u9700\u8981\u8fdb\u884cn-1\u6b21\u4ea4\u6362\uff0c\u603b\u5171\u9700\u8981\u8fdb\u884cn-1\u8f6e\u904d\u5386\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n^2)\u3002 \u5e73\u5747\u60c5\u51b5\uff1a\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u5192\u6ce1\u6392\u5e8f\u9700\u8981\u8fdb\u884c n(n-1)/2 \u6b21\u6bd4\u8f83\u548c\u4ea4\u6362\u64cd\u4f5c\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3aO(n^2)\u3002","title":"3.4.4.\u518d\u8bba\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd"},{"location":"python/DataStructure/03_TimeComplexity/#345","text":"\u5217\u8868\u91cc\u5982\u4f55\u6392\u5217\u6570\u636e\u624d\u80fd\u8ba9\u9009\u62e9\u6392\u5e8f\u4e2d\u5143\u7d20\u4ea4\u6362\u7684\u6b21\u6570\u6700\u5c11\uff1f\u5982\u4f55\u6392\u5217\u6570\u636e\u624d\u80fd\u8ba9\u5b83\u6267\u884c\u6700\u591a\u7684\u4ea4\u6362\u6b21\u6570\uff1f \u89e3\u7b54\uff1a \u5728\u9009\u62e9\u6392\u5e8f\u4e2d\uff0c\u5143\u7d20\u7684\u4ea4\u6362\u6b21\u6570\u4e3b\u8981\u53d6\u51b3\u4e8e\u5f85\u6392\u5e8f\u5217\u8868\u7684\u521d\u59cb\u6392\u5217\uff1a \u6700\u5c0f\u5316\u4ea4\u6362\u6b21\u6570\uff1a \u8981\u6700\u5c0f\u5316\u9009\u62e9\u6392\u5e8f\u7684\u5143\u7d20\u4ea4\u6362\u6b21\u6570\uff0c\u53ef\u4ee5\u8ba9\u8f93\u5165\u5217\u8868\u5df2\u7ecf\u6309\u5347\u5e8f\u6392\u5217\u3002\u8fd9\u662f\u56e0\u4e3a\u5728\u5347\u5e8f\u6392\u5217\u7684\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u6bcf\u6b21\u9009\u62e9\u6700\u5c0f\u7684\u5143\u7d20\u5e76\u5c06\u5176\u653e\u7f6e\u5728\u6b63\u786e\u7684\u4f4d\u7f6e\uff0c\u65e0\u9700\u4ea4\u6362\u3002\u56e0\u6b64\uff0c\u5143\u7d20\u4ea4\u6362\u7684\u6b21\u6570\u4e3a 0 \u3002 \u6700\u5927\u5316\u4ea4\u6362\u6b21\u6570\uff1a \u8981\u6700\u5927\u5316\u9009\u62e9\u6392\u5e8f\u7684\u5143\u7d20\u4ea4\u6362\u6b21\u6570\uff0c\u53ef\u4ee5\u8ba9\u8f93\u5165\u5217\u8868\u6309\u964d\u5e8f\u6392\u5217\u3002\u5728\u964d\u5e8f\u6392\u5217\u7684\u60c5\u51b5\u4e0b\uff0c\u9009\u62e9\u6392\u5e8f\u6bcf\u6b21\u9009\u62e9\u6700\u5927\u7684\u5143\u7d20\u5e76\u5c06\u5176\u653e\u7f6e\u5728\u6b63\u786e\u7684\u4f4d\u7f6e\uff0c\u8fd9\u5c06\u5bfc\u81f4\u5927\u91cf\u7684\u4ea4\u6362\u64cd\u4f5c\u3002\u5177\u4f53\u6765\u8bf4\uff0c\u5bf9\u4e8e\u957f\u5ea6\u4e3an\u7684\u5217\u8868\uff0c\u6700\u5927\u5316\u4ea4\u6362\u6b21\u6570\u7684\u60c5\u51b5\u4e0b\uff0c\u5c06\u6267\u884c n-1 \u6b21\u4ea4\u6362\u64cd\u4f5c\u3002 \u603b\u4e4b\uff0c\u8981\u6700\u5c0f\u5316\u9009\u62e9\u6392\u5e8f\u7684\u5143\u7d20\u4ea4\u6362\u6b21\u6570\uff0c\u8f93\u5165\u5217\u8868\u5e94\u8be5\u5df2\u7ecf\u6309\u5347\u5e8f\u6392\u5217\u3002\u8981\u6700\u5927\u5316\u4ea4\u6362\u6b21\u6570\uff0c\u8f93\u5165\u5217\u8868\u5e94\u8be5\u6309\u964d\u5e8f\u6392\u5217\u3002\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u9009\u62e9\u6392\u5e8f\u901a\u5e38\u4e0d\u662f\u9996\u9009\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u56e0\u4e3a\u5176\u4ea4\u6362\u6b21\u6570\u8f83\u591a\uff0c\u800c\u5176\u4ed6\u7b97\u6cd5\u5982\u5feb\u901f\u6392\u5e8f\u3001\u5f52\u5e76\u6392\u5e8f\u7b49\u5177\u6709\u66f4\u597d\u7684\u6027\u80fd\u3002 \u8bf7\u8bf4\u660e\u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\u5728\u5206\u6790\u9009\u62e9\u6392\u5e8f\u548c\u5192\u6ce1\u6392\u5e8f\u65f6\u6240\u8d77\u5230\u7684\u4f5c\u7528\u3002\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u5728\u5b83\u4eec\u4e4b\u95f4\u53d1\u6325\u7740\u4ec0\u4e48\u4f5c\u7528\uff08\u5982\u679c\u6709\u4f5c\u7528\uff09\uff1f \u89e3\u7b54\uff1a \u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\u5728\u5206\u6790\u9009\u62e9\u6392\u5e8f\u548c\u5192\u6ce1\u6392\u5e8f\u65f6\u8d77\u5230\u91cd\u8981\u4f5c\u7528\uff0c\u56e0\u4e3a\u5b83\u4eec\u76f4\u63a5\u5f71\u54cd\u5230\u6392\u5e8f\u7b97\u6cd5\u7684\u6027\u80fd\u548c\u6548\u7387\u3002 \u9009\u62e9\u6392\u5e8f\uff08Selection Sort\uff09\uff1a \u9009\u62e9\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e0e\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u76f4\u63a5\u76f8\u5173\u3002\u5728\u9009\u62e9\u6392\u5e8f\u4e2d\uff0c\u6bcf\u4e00\u8f6e\u90fd\u4f1a\u9009\u62e9\u672a\u6392\u5e8f\u90e8\u5206\u7684\u6700\u5c0f\u5143\u7d20\uff0c\u5e76\u5c06\u5176\u653e\u7f6e\u5728\u6b63\u786e\u7684\u4f4d\u7f6e\uff0c\u8fd9\u610f\u5473\u7740\u6bcf\u8f6e\u90fd\u9700\u8981\u4e00\u6b21\u4ea4\u6362\u64cd\u4f5c\u3002 \u9009\u62e9\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u662f\u4e0e\u8f93\u5165\u6570\u636e\u7684\u521d\u59cb\u6392\u5217\u65e0\u5173\u7684\uff0c\u56e0\u4e3a\u5b83\u603b\u662f\u4f1a\u6267\u884c\u76f8\u540c\u6570\u91cf\u7684\u4ea4\u6362\u64cd\u4f5c\uff0c\u65e0\u8bba\u6570\u636e\u662f\u5426\u6709\u5e8f\u3002 \u5bf9\u4e8e\u9009\u62e9\u6392\u5e8f\uff0c\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e3b\u8981\u53d7\u5230\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u5f71\u54cd\uff0c\u800c\u4e0d\u53d7\u6570\u636e\u7684\u5177\u4f53\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u65e0\u8bba\u6570\u636e\u7684\u6392\u5217\u5982\u4f55\uff0c\u9009\u62e9\u6392\u5e8f\u7684\u5e73\u5747\u548c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u90fd\u662f\u76f8\u540c\u7684\uff0c\u5373 n-1 \u6b21\u3002 \u5192\u6ce1\u6392\u5e8f\uff08Bubble Sort\uff09\uff1a \u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e5f\u4e0e\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u76f8\u5173\u3002\u5728\u5192\u6ce1\u6392\u5e8f\u4e2d\uff0c\u76f8\u90bb\u5143\u7d20\u9010\u4e00\u6bd4\u8f83\uff0c\u5982\u679c\u9006\u5e8f\u5c31\u4ea4\u6362\u4f4d\u7f6e\uff0c\u56e0\u6b64\u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e0e\u9006\u5e8f\u5bf9\u7684\u6570\u91cf\u76f8\u5173\u3002 \u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u5728\u4e0d\u540c\u7684\u6570\u636e\u6392\u5217\u60c5\u51b5\u4e0b\u53ef\u4ee5\u6709\u5f88\u5927\u5dee\u5f02\u3002\u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff08\u8f93\u5165\u6570\u636e\u5df2\u7ecf\u6709\u5e8f\uff09\uff0c\u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u4e3a 0 \u3002\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff08\u8f93\u5165\u6570\u636e\u5b8c\u5168\u9006\u5e8f\uff09\uff0c\u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u662f\u6700\u5927\u7684\u3002 \u5192\u6ce1\u6392\u5e8f\u7684\u6570\u636e\u4ea4\u6362\u6b21\u6570\u65e2\u53d7\u5230\u6570\u636e\u5bf9\u8c61\u7684\u89c4\u6a21\u5f71\u54cd\uff0c\u53c8\u53d7\u5230\u6570\u636e\u7684\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u4ea4\u6362\u6b21\u6570\u4e3a 0 \uff0c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u4ea4\u6362\u6b21\u6570\u4e3a n*(n-1)/2 \uff0c\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u4ea4\u6362\u6b21\u6570\u53d6\u51b3\u4e8e\u6570\u636e\u6392\u5217\u7684\u968f\u673a\u6027\u3002 \u7efc\u4e0a\u6240\u8ff0\uff0c\u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\u5728\u9009\u62e9\u6392\u5e8f\u548c\u5192\u6ce1\u6392\u5e8f\u7684\u5206\u6790\u4e2d\u662f\u91cd\u8981\u7684\u6027\u80fd\u6307\u6807\u3002\u9009\u62e9\u6392\u5e8f\u7684\u4ea4\u6362\u6b21\u6570\u4e0e\u6570\u636e\u89c4\u6a21\u76f8\u5173\uff0c\u800c\u5192\u6ce1\u6392\u5e8f\u7684\u4ea4\u6362\u6b21\u6570\u65e2\u4e0e\u6570\u636e\u89c4\u6a21\u76f8\u5173\uff0c\u53c8\u53d7\u5230\u6570\u636e\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u5728\u5927\u89c4\u6a21\u6570\u636e\u96c6\u4e0a\uff0c\u5192\u6ce1\u6392\u5e8f\u901a\u5e38\u6bd4\u9009\u62e9\u6392\u5e8f\u66f4\u6162\uff0c\u56e0\u4e3a\u5b83\u7684\u4ea4\u6362\u64cd\u4f5c\u66f4\u591a\u3002\u56e0\u6b64\uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u901a\u5e38\u9009\u62e9\u6392\u5e8f\u6bd4\u5192\u6ce1\u6392\u5e8f\u66f4\u6709\u6548\u3002\u4f46\u4e24\u8005\u90fd\u4e0d\u662f\u9996\u9009\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u66f4\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\u5982\u5feb\u901f\u6392\u5e8f\u3001\u5f52\u5e76\u6392\u5e8f\u7b49\u901a\u5e38\u88ab\u4f18\u5148\u8003\u8651\u3002 \u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u6027\u80fd\u4ecd\u7136\u4e3aO(n^2)\u3002 \u89e3\u7b54\uff1a \u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u6027\u80fd\u4ecd\u7136\u4e3aO(n^2)\uff0c\u539f\u56e0\u5982\u4e0b\uff1a \u5192\u6ce1\u6392\u5e8f\u7684\u57fa\u672c\u64cd\u4f5c\u662f\u6bd4\u8f83\u76f8\u90bb\u5143\u7d20\u5e76\u4ea4\u6362\u5b83\u4eec\uff0c\u76f4\u5230\u6574\u4e2a\u5217\u8868\u6309\u7167\u5347\u5e8f\u6392\u5217\u3002\u5728\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u4e2d\uff0c\u5f53\u4e24\u4e2a\u76f8\u90bb\u5143\u7d20\u9006\u5e8f\u65f6\uff0c\u4f1a\u53d1\u751f\u4ea4\u6362\u3002\u8fd9\u4e2a\u57fa\u672c\u64cd\u4f5c\u7684\u590d\u6742\u5ea6\u662fO(1)\uff0c\u56e0\u4e3a\u5b83\u53ea\u6d89\u53ca\u4e24\u4e2a\u5143\u7d20\u7684\u6bd4\u8f83\u548c\u53ef\u80fd\u7684\u4ea4\u6362\u3002 \u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u6bcf\u4e00\u8f6e\u904d\u5386\u4e2d\uff0c\u4ecd\u7136\u9700\u8981\u68c0\u67e5\u76f8\u90bb\u5143\u7d20\u7684\u6bd4\u8f83\uff0c\u5373\u4f7f\u5728\u6709\u5e8f\u90e8\u5206\uff0c\u5b83\u4ecd\u7136\u9700\u8981\u8fdb\u884c\u6bd4\u8f83\u3002\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5b83\u4f1a\u6267\u884cn-1\u6b21\u904d\u5386\uff0c\u6bcf\u6b21\u90fd\u8981\u6bd4\u8f83\u76f8\u90bb\u5143\u7d20\u3002 \u5192\u6ce1\u6392\u5e8f\u7684\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n^2)\uff0c\u8fd9\u662f\u56e0\u4e3a\u5b83\u4e0d\u4f1a\u5229\u7528\u8f93\u5165\u6570\u636e\u7684\u4efb\u4f55\u6709\u5e8f\u6027\u3002\u65e0\u8bba\u8f93\u5165\u6570\u636e\u662f\u6709\u5e8f\u7684\u3001\u9006\u5e8f\u7684\uff0c\u8fd8\u662f\u968f\u673a\u6392\u5217\u7684\uff0c\u90fd\u9700\u8981\u6267\u884c\u76f8\u540c\u6570\u91cf\u7684\u6bd4\u8f83\u548c\u4ea4\u6362\u64cd\u4f5c\u3002 \u603b\u4e4b\uff0c\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u867d\u7136\u51cf\u5c11\u4e86\u6570\u636e\u4ea4\u6362\u7684\u6b21\u6570\uff0c\u4f46\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u4ecd\u7136\u9700\u8981\u6267\u884c\u5927\u7ea6 n(n-1)/2 \u6b21\u6bd4\u8f83\u64cd\u4f5c\uff0c\u56e0\u6b64\u5b83\u7684\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662fO(n^2)\u3002\u5192\u6ce1\u6392\u5e8f\u7684\u6027\u80fd\u4e3b\u8981\u53d7\u5230\u6570\u636e\u89c4\u6a21\u7684\u5f71\u54cd\uff0c\u800c\u4e0d\u592a\u53d7\u5230\u5177\u4f53\u6570\u636e\u6392\u5217\u65b9\u5f0f\u7684\u5f71\u54cd\u3002\u56e0\u6b64\uff0c\u5b83\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u4ecd\u7136\u5177\u6709\u4e8c\u6b21\u65f6\u95f4\u590d\u6742\u5ea6\u3002 \u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u63d2\u5165\u6392\u5e8f\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e0a\u80fd\u591f\u5f88\u597d\u5730\u5de5\u4f5c\u3002 \u89e3\u7b54\uff1a \u63d2\u5165\u6392\u5e8f\u4e4b\u6240\u4ee5\u80fd\u591f\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e0a\u5f88\u597d\u5730\u5de5\u4f5c\uff0c\u662f\u56e0\u4e3a\u5b83\u7684\u6838\u5fc3\u601d\u60f3\u662f\u9010\u6b65\u6784\u5efa\u6709\u5e8f\u7684\u5b50\u5217\u8868\uff0c\u800c\u4e0d\u662f\u50cf\u9009\u62e9\u6392\u5e8f\u6216\u5192\u6ce1\u6392\u5e8f\u4e00\u6837\u603b\u662f\u8003\u8651\u6574\u4e2a\u5217\u8868\u3002\u8fd9\u4f7f\u5f97\u63d2\u5165\u6392\u5e8f\u5728\u5904\u7406\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u65f6\u5177\u6709\u4e00\u4e9b\u4f18\u52bf\uff1a \u5c40\u90e8\u6027\u539f\u7406\uff1a\u63d2\u5165\u6392\u5e8f\u5229\u7528\u4e86\u5c40\u90e8\u6027\u539f\u7406\uff0c\u5373\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u6570\u636e\u9879\u7684\u6b63\u786e\u4f4d\u7f6e\u79bb\u5b83\u4eec\u5f53\u524d\u7684\u4f4d\u7f6e\u5f88\u8fd1\u3002\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e2d\uff0c\u5927\u591a\u6570\u6570\u636e\u9879\u5df2\u7ecf\u63a5\u8fd1\u4e8e\u5b83\u4eec\u7684\u6700\u7ec8\u4f4d\u7f6e\uff0c\u56e0\u6b64\u53ea\u9700\u8981\u8fdb\u884c\u5c11\u91cf\u7684\u79fb\u52a8\u64cd\u4f5c\u3002 \u9002\u5e94\u6027\uff1a\u63d2\u5165\u6392\u5e8f\u662f\u4e00\u79cd\u81ea\u9002\u5e94\u6392\u5e8f\u7b97\u6cd5\uff0c\u5b83\u53ef\u4ee5\u6839\u636e\u8f93\u5165\u6570\u636e\u7684\u6709\u5e8f\u6027\u8fdb\u884c\u81ea\u52a8\u8c03\u6574\u3002\u5728\u5904\u7406\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u65f6\uff0c\u63d2\u5165\u6392\u5e8f\u7684\u6027\u80fd\u4f1a\u66f4\u597d\uff0c\u56e0\u4e3a\u4e0d\u9700\u8981\u6267\u884c\u592a\u591a\u7684\u6bd4\u8f83\u548c\u4ea4\u6362\u64cd\u4f5c\u3002 \u7b80\u5355\u6027\uff1a\u63d2\u5165\u6392\u5e8f\u7684\u5b9e\u73b0\u975e\u5e38\u7b80\u5355\u76f4\u89c2\uff0c\u5b83\u53ea\u6d89\u53ca\u5230\u9010\u4e2a\u63d2\u5165\u5143\u7d20\u5230\u6b63\u786e\u7684\u4f4d\u7f6e\u3002\u8fd9\u79cd\u7b80\u5355\u6027\u4f7f\u5f97\u63d2\u5165\u6392\u5e8f\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\u6bd4\u66f4\u590d\u6742\u7684\u6392\u5e8f\u7b97\u6cd5\u66f4\u5177\u7ade\u4e89\u529b\u3002 \u867d\u7136\u63d2\u5165\u6392\u5e8f\u5728\u90e8\u5206\u6709\u5e8f\u7684\u5217\u8868\u4e0a\u8868\u73b0\u826f\u597d\uff0c\u4f46\u5728\u5904\u7406\u5927\u89c4\u6a21\u4e71\u5e8f\u6570\u636e\u96c6\u65f6\uff0c\u5b83\u7684\u6027\u80fd\u4e0d\u5982\u5feb\u901f\u6392\u5e8f\u3001\u5f52\u5e76\u6392\u5e8f\u7b49\u66f4\u9ad8\u7ea7\u7684\u6392\u5e8f\u7b97\u6cd5\u3002\u56e0\u6b64\uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u6839\u636e\u6570\u636e\u7684\u6027\u8d28\u9009\u62e9\u9002\u5f53\u7684\u6392\u5e8f\u7b97\u6cd5\u662f\u91cd\u8981\u7684\u3002\u63d2\u5165\u6392\u5e8f\u901a\u5e38\u9002\u7528\u4e8e\u5c0f\u89c4\u6a21\u6570\u636e\u6216\u8005\u5df2\u7ecf\u90e8\u5206\u6709\u5e8f\u7684\u6570\u636e\uff0c\u800c\u4e0d\u662f\u5927\u89c4\u6a21\u4e71\u5e8f\u6570\u636e\u7684\u6392\u5e8f\u3002","title":"3.4.5.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/03_TimeComplexity/#35","text":"\u5206\u6cbb\u6cd5\uff08divide-and-conquer\uff09\u7b56\u7565\uff1a\u628a\u5217\u8868\u5206\u6210\u66f4\u5c0f\u7684\u5b50\u5217\u8868\uff0c\u7136\u540e\u518d\u901a\u8fc7\u9012\u5f52\u628a\u8fd9\u4e9b\u5b50\u5217\u8868\u6392\u5e8f\u3002 \u7406\u60f3\u60c5\u51b5\u4e0b\uff0c\u5982\u679c\u8fd9\u4e9b\u88ab\u62c6\u5206\u7684\u5b50\u5217\u8868\u7684\u6570\u91cf\u662f logn \uff0c\u800c\u628a\u6bcf\u4e2a\u5b50\u5217\u8868\u8fdb\u884c\u5408\u5e76\u6240\u9700\u7684\u5de5\u4f5c\u91cf\u4e3a n \uff0c\u90a3\u4e48\u8fd9\u79cd\u6392\u5e8f\u7b97\u6cd5\u7684\u603b\u590d\u6742\u5ea6\u5c31\u662f O(nlogn) \uff0c\u76f8\u6bd4 O(n^2) \u7684\u5de5\u4f5c\u91cf\u589e\u957f\u8981\u4f4e\u5f88\u591a\u3002","title":"3.5.\u66f4\u5feb\u7684\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#351","text":"\u5feb\u901f\u6392\u5e8f\uff08QuickSort\uff09\u662f\u6392\u9664\u7a33\u5b9a\u6027\u56e0\u7d20\u540e\u6700\u5e38\u7528\u7684\u6392\u5e8f\u3002 \u9996\u5148\u4ece\u5217\u8868\u7684\u4e2d\u95f4\u4f4d\u7f6e\u9009\u62e9\u4e00\u4e2a\u5143\u7d20\uff0c\u8fd9\u4e2a\u5143\u7d20\u88ab\u79f0\u4e3a\u57fa\u51c6\uff08pivot\uff09\uff1b \u5bf9\u5217\u8868\u91cc\u7684\u5143\u7d20\u8fdb\u884c\u5206\u5272\uff0c\u628a\u5c0f\u4e8e\u57fa\u51c6\u7684\u6240\u6709\u5143\u7d20\u79fb\u52a8\u5230\u57fa\u51c6\u7684\u5de6\u4fa7\uff0c\u800c\u628a\u5176\u4f59\u5143\u7d20\u90fd\u79fb\u5230\u57fa\u51c6\u7684\u53f3\u4fa7\u3002 \u5982\u679c\u57fa\u51c6\u6b63\u597d\u662f\u6700\u5927\u7684\u5143\u7d20\uff0c\u90a3\u4e48\u5b83\u6700\u7ec8\u4f1a\u5904\u4e8e\u5217\u8868\u7684\u6700\u53f3\u4fa7\uff1b \u5982\u679c\u57fa\u51c6\u6b63\u597d\u662f\u6700\u5c0f\u7684\u5143\u7d20\uff0c\u90a3\u4e48\u5b83\u5c31\u4f1a\u5728\u6700\u5de6\u4fa7\uff1b \u5206\u6cbb\u6cd5\u3002\u5c06\u8fd9\u4e2a\u8fc7\u7a0b\u9012\u5f52\u5730\u5e94\u7528\u5230\u901a\u8fc7\u57fa\u51c6\u800c\u628a\u539f\u5217\u8868\u5206\u5272\u7684\u5b50\u5217\u8868\u4e0a\uff0c\u5176\u4e2d\uff1a \u4e00\u4e2a\u65b0\u7684\u5b50\u5217\u8868\u7531\u57fa\u51c6\u5de6\u4fa7\u7684\u6240\u6709\u5143\u7d20\uff08\u8f83\u5c0f\u7684\u5143\u7d20\uff09\u7ec4\u6210\uff0c \u53e6\u4e00\u4e2a\u65b0\u7684\u5b50\u5217\u8868\u7531\u57fa\u51c6\u53f3\u4fa7\u7684\u6240\u6709\u5143\u7d20\uff08\u8f83\u5927\u7684\u5143\u7d20\uff09\u7ec4\u6210\uff1b \u5f53\u5206\u51fa\u7684\u5b50\u5217\u8868\u5185\u5c11\u4e8e\u4e24\u4e2a\u5143\u7d20\u65f6\uff0c\u8fd9\u4e2a\u8fc7\u7a0b\u7ec8\u6b62\uff1b","title":"3.5.1.\u5feb\u901f\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#3511","text":"\u8fd9\u4e2a\u7b97\u6cd5\u91cc\u6700\u590d\u6742\u7684\u90e8\u5206\u662f\u5bf9\u5143\u7d20\u8fdb\u884c\u5206\u5272\u4ece\u800c\u5f97\u5230\u5b50\u5217\u8868\u7684\u64cd\u4f5c\u3002 \u5c06\u57fa\u51c6\u4e0e\u5b50\u5217\u8868\u91cc\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\u3002 \u5728\u5df2\u77e5\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u548c\u5176\u4ed6\u5143\u7d20\u4e4b\u95f4\u6784\u5efa\u4e00\u4e2a\u8fb9\u754c\u3002\u4e00\u5f00\u59cb\uff0c\u8fd9\u4e2a\u8fb9\u754c\u4f1a\u5904\u4e8e\u7b2c\u4e00\u4e2a\u5143\u7d20\u4e4b\u524d\u3002 \u4ece\u5b50\u5217\u8868\u8fb9\u754c\u4e4b\u540e\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\u5411\u53f3\u626b\u63cf\u3002\u5f53\u6bcf\u6b21\u9047\u5230\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u65f6\uff0c\u5c06\u5b83\u548c\u8fb9\u754c\u4e4b\u540e\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\uff0c\u5e76\u4e14\u5c06\u8fb9\u754c\u5411\u53f3\u79fb\u52a8\u3002 \u5728\u7ed3\u675f\u7684\u65f6\u5019\uff0c\u5c06\u57fa\u51c6\u548c\u8fb9\u754c\u4e4b\u540e\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u8fdb\u884c\u4ea4\u6362\u3002 \u793a\u4f8b\u5217\u8868\uff1a[12,19,17,18,14,11,15,13,16]\uff0c\u4e0b\u56fe\u5c55\u793a\u4e86\u5206\u5272\u7684\u6bcf\u4e00\u6b65\u8fc7\u7a0b\u3002","title":"3.5.1.1.\u5206\u5272"},{"location":"python/DataStructure/03_TimeComplexity/#3512","text":"\u5feb\u901f\u6392\u5e8f\uff08Quick Sort\uff09\u662f\u4e00\u79cd\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u5176\u5e73\u5747\u548c\u6700\u574f\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662f O(n log n) \u3002\u4e0b\u9762\u662f\u5feb\u901f\u6392\u5e8f\u7684\u590d\u6742\u5ea6\u5206\u6790\uff1a \u5728\u7b2c\u4e00\u6b21\u8fdb\u884c\u5206\u5272\u64cd\u4f5c\u65f6\uff0c\u6211\u4eec\u5c06\u626b\u63cf\u5217\u8868\u91cc\u4ece\u5f00\u5934\u5230\u7ed3\u5c3e\u7684\u6240\u6709\u5143\u7d20\u3002\u56e0\u6b64\uff0c\u5728\u8fd9\u4e2a\u64cd\u4f5c\u671f\u95f4\u5de5\u4f5c\u91cf\u662f\u548c\u5217\u8868\u7684\u957f\u5ea6 n \u6210\u6b63\u6bd4\u7684\u3002\u8fd9\u6b21\u5206\u5272\u4e4b\u540e\u7684\u5de5\u4f5c\u91cf\u4f1a\u548c\u5de6\u5b50\u5217\u8868\u52a0\u4e0a\u53f3\u5b50\u5217\u8868\u7684\u603b\u957f\u5ea6\u6210\u6b63\u6bd4\uff0c\u4e5f\u5c31\u662f n-1 \u3002 \u518d\u6b21\u5bf9\u8fd9\u4e24\u4e2a\u5b50\u5217\u8868\u8fdb\u884c\u5206\u5272\u4e4b\u540e\uff0c\u5c31\u4f1a\u4ea7\u751f4\u4e2a\u52a0\u8d77\u6765\u603b\u957f\u5ea6\u5927\u7ea6\u4e3a n \u7684\u5217\u8868\u6bb5\u3002\u56e0\u6b64\uff0c\u5bf9\u5b83\u4eec\u8fdb\u884c\u5206\u5272\u7684\u603b\u5de5\u4f5c\u91cf\u8fd8\u662f\u548c n \u6210\u6b63\u6bd4\u7684\u3002\u968f\u7740\u5217\u8868\u88ab\u5206\u5272\u6210\u66f4\u591a\u6bb5\uff0c\u603b\u5de5\u4f5c\u91cf\u4f1a\u4e00\u76f4\u548c n \u6210\u6b63\u6bd4\u3002 \u8981\u5b8c\u6210\u6574\u4e2a\u5206\u6790\uff0c\u8fd8\u9700\u8981\u786e\u5b9a\u5217\u8868\u88ab\u5206\u5272\u4e86\u591a\u5c11\u6b21\u3002\u6309\u7167\u6700\u4e50\u89c2\u7684\u60c5\u51b5\u6765\u8bf4\uff08\u867d\u7136\u5728\u5b9e\u9645\u64cd\u4f5c\u7684\u65f6\u5019\uff0c\u901a\u5e38\u5e76\u4e0d\u4f1a\u51fa\u73b0\u8fd9\u4e48\u597d\u7684\u60c5\u51b5\uff09\uff0c\u5047\u8bbe\u6bcf\u6b21\u65b0\u5b50\u5217\u8868\u4e4b\u95f4\u7684\u5206\u754c\u7ebf\u90fd\u5c3d\u53ef\u80fd\u5730\u9760\u8fd1\u5f53\u524d\u5217\u8868\u7684\u4e2d\u5fc3\uff0c\u901a\u5e38\u8fd9\u79cd\u60c5\u51b5\u5e76\u4e0d\u5e38\u89c1\u3002\u4ece\u4e8c\u5206\u641c\u7d22\u7b97\u6cd5\u7684\u8ba8\u8bba\u91cc\u53ef\u77e5\uff0c\u8981\u628a\u5217\u8868\u4e0d\u65ad\u5730\u5206\u6210\u4e24\u534a\uff0c\u5927\u7ea6\u5728 log n \u6b65\u7684\u65f6\u5019\u5c31\u53ea\u5269\u4e0b\u4e00\u4e2a\u5143\u7d20\u4e86\u3002 \u56e0\u6b64\uff0c\u8fd9\u4e2a\u7b97\u6cd5\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u4e3a O(n log n) \u3002\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u6765\u8003\u8651\u6709\u5e8f\u5217\u8868\u7684\u60c5\u51b5\u3002\u5982\u679c\u9009\u62e9\u7684\u57fa\u51c6\u5143\u7d20\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20\uff0c\u90a3\u4e48\u5728\u7b2c\u4e00\u6b21\u5206\u5272\u4e4b\u540e\u5b83\u7684\u53f3\u8fb9\u4f1a\u6709 n-1 \u4e2a\u5143\u7d20\uff0c\u5728\u7b2c\u4e8c\u6b21\u5206\u5272\u4e4b\u540e\u5b83\u7684\u53f3\u8fb9\u6709 n-2 \u4e2a\u5143\u7d20\uff0c\u4ee5\u6b64\u7c7b\u63a8\uff0c \u5c3d\u7ba1\u6574\u4e2a\u64cd\u4f5c\u91cc\u6ca1\u6709\u4ea4\u6362\u4efb\u4f55\u5143\u7d20\uff0c\u4f46\u5206\u5272\u603b\u5171\u4e5f\u6267\u884c\u4e86 n-1 \u6b21\uff0c\u4e8e\u662f\u6267\u884c\u7684\u6bd4\u8f83\u603b\u6570\u5c31\u662f n^2/2-n/2 \u3002\u8fd9\u4e0e\u9009\u62e9\u6392\u5e8f\u4ee5\u53ca\u5192\u6ce1\u6392\u5e8f\u7684\u60c5\u51b5\u662f\u4e00\u6837\u7684\u3002\u56e0\u6b64\uff0c\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7b97\u6cd5\u7684\u6027\u80fd\u4e3a O(n^2) \u3002\u5982\u679c\u628a\u5feb\u901f\u6392\u5e8f\u5b9e\u73b0\u6210\u9012\u5f52\u7b97\u6cd5\uff0c\u90a3\u4e48\u5728\u5bf9\u5b83\u8fdb\u884c\u5206\u6790\u65f6\u8fd8\u5fc5\u987b\u8981\u8003\u8651\u8c03\u7528\u6808\u7684\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\u3002\u7531\u4e8e\u5bf9\u4e8e\u6808\u7684\u4e00\u5e27\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u90fd\u9700\u8981\u56fa\u5b9a\u7684\u5185\u5b58\uff0c\u5e76\u4e14\u6bcf\u6b21\u5206\u5272\u4e4b\u540e\u90fd\u4f1a\u6709\u4e24\u6b21\u9012\u5f52\u8c03\u7528\u3002\u56e0\u6b64\uff0c\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u5185\u5b58\u7684\u4f7f\u7528\u91cf\u4f1a\u662f O(log n) \uff0c\u800c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u5185\u5b58\u4f7f\u7528\u91cf\u662f O(n) \u3002 \u5c3d\u7ba1\u5feb\u901f\u6392\u5e8f\u5904\u4e8e\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u53ef\u80fd\u6027\u5f88\u5c0f\uff0c\u6211\u4eec\u8fd8\u662f\u4f1a\u52aa\u529b\u5730\u53bb\u907f\u514d\u8fd9\u79cd\u60c5\u51b5\uff0c\u56e0\u6b64\uff0c\u5b83\u4eec\u5e76\u4e0d\u4f1a\u5728\u7b2c\u4e00\u4e2a\u6216\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u9009\u62e9\u57fa\u51c6\u5143\u7d20\u3002\u6709\u5176\u4ed6\u4e00\u4e9b\u9009\u62e9\u57fa\u51c6\u7684\u65b9\u6cd5\u53ef\u4ee5\u8ba9\u8fd9\u4e2a\u7b97\u6cd5\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\u6709\u5927\u7ea6 O(n log n) \u7684\u6027\u80fd\uff0c\u6bd4\u5982\uff0c\u53ef\u4ee5\u9009\u62e9\u968f\u673a\u4f4d\u7f6e\u4e0a\u7684\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\uff0c\u6216\u8005\u9009\u62e9\u6574\u4e2a\u5217\u8868\u91cc\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3001\u4e2d\u95f4\u4f4d\u7f6e\u4ee5\u53ca\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u8fd93\u4e2a\u5143\u7d20\u7684\u4e2d\u4f4d\u6570\u3002 \u603b\u7ed3\uff1a \u6700\u597d\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u5728\u6700\u597d\u60c5\u51b5\u4e0b\uff0c\u4e5f\u5c31\u662f\u6bcf\u6b21\u9009\u62e9\u7684\u57fa\u51c6\u5143\u7d20\u90fd\u521a\u597d\u5c06\u8f93\u5165\u6570\u636e\u5206\u6210\u4e24\u4e2a\u7b49\u957f\u7684\u5b50\u6570\u7ec4\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n log n) \u3002\u8fd9\u79cd\u60c5\u51b5\u901a\u5e38\u53d1\u751f\u5728\u57fa\u51c6\u5143\u7d20\u7684\u9009\u62e9\u975e\u5e38\u5408\u7406\u7684\u60c5\u51b5\u4e0b\uff0c\u4f8b\u5982\u5728\u6bcf\u6b21\u9009\u62e9\u4e2d\u90fd\u9009\u62e9\u4e2d\u95f4\u5143\u7d20\u3002 \u5e73\u5747\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e5f\u662f O(n log n) \u3002\u8fd9\u662f\u56e0\u4e3a\u5feb\u901f\u6392\u5e8f\u662f\u4e00\u79cd\u5206\u6cbb\u7b97\u6cd5\uff0c\u6bcf\u6b21\u5c06\u95ee\u9898\u5206\u6210\u4e24\u4e2a\u5b50\u95ee\u9898\uff0c\u7136\u540e\u9012\u5f52\u5730\u89e3\u51b3\u8fd9\u4e9b\u5b50\u95ee\u9898\u3002\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u6bcf\u6b21\u5206\u5272\u64cd\u4f5c\u90fd\u80fd\u5c06\u95ee\u9898\u89c4\u6a21\u51cf\u534a\uff0c\u56e0\u6b64\u9700\u8981\u6267\u884c O(n log n) \u6b21\u5206\u5272\u64cd\u4f5c\uff0c\u6bcf\u6b21\u5206\u5272\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002\u56e0\u6b64\uff0c\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n log n) \u3002 \u6700\u574f\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n^2) \u3002\u6700\u574f\u60c5\u51b5\u53d1\u751f\u5728\u6bcf\u6b21\u9009\u62e9\u7684\u57fa\u51c6\u5143\u7d20\u90fd\u662f\u8f93\u5165\u6570\u636e\u4e2d\u7684\u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\uff0c\u5bfc\u81f4\u5206\u5272\u64cd\u4f5c\u4e0d\u5747\u8861\uff0c\u6bcf\u6b21\u5206\u5272\u53ea\u80fd\u5c06\u95ee\u9898\u89c4\u6a21\u51cf\u5c111\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u9000\u5316\u4e3a\u5192\u6ce1\u6392\u5e8f\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \u3002 \u5feb\u901f\u6392\u5e8f\u7684\u5e73\u5747\u548c\u6700\u597d\u60c5\u51b5\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n log n) \uff0c\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\u901a\u5e38\u6027\u80fd\u4f18\u8d8a\u3002\u7136\u800c\uff0c\u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \uff0c\u56e0\u6b64\u5728\u5b9e\u73b0\u5feb\u901f\u6392\u5e8f\u65f6\u9700\u8981\u7279\u522b\u6ce8\u610f\u57fa\u51c6\u5143\u7d20\u7684\u9009\u62e9\u4ee5\u907f\u514d\u6700\u574f\u60c5\u51b5\u7684\u53d1\u751f\u3002","title":"3.5.1.2.\u5feb\u901f\u6392\u5e8f\u590d\u6742\u5ea6\u5206\u6790"},{"location":"python/DataStructure/03_TimeComplexity/#3513","text":"\u4ee5\u4e0a\u9762\u56fe\u793a\u7684\u5217\u8868 [12,19,17,18,14,11,15,13,16] \u4e3a\u4f8b\uff0c\u4e0b\u9762\u662f\u5b9e\u73b0\u4ee3\u7801\uff1a import random def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def quicksort ( lyst ): # left\u7684\u521d\u59cb\u503c\u662f0 # right\u7684\u521d\u59cb\u503c\u662f\u5217\u8868\u957f\u5ea6\u51cf1 quicksortHelper ( lyst , 0 , len ( lyst ) - 1 ) def quicksortHelper ( lyst , left , right ): print ( lyst ) if left < right : pivotLocation = partition ( lyst , left , right ) quicksortHelper ( lyst , left , pivotLocation - 1 ) quicksortHelper ( lyst , pivotLocation + 1 , right ) def partition ( lyst , left , right ): \"\"\"\u5bf9\u5217\u8868\u8fdb\u884c\u5206\u533a\"\"\" # \u627e\u5230\u57fa\u51c6\u5143\u7d20\uff08pivot\uff09\uff0c\u5e76\u548c\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u4e92\u6362 middle = ( left + right ) // 2 pivot = lyst [ middle ] lyst [ middle ] = lyst [ right ] lyst [ right ] = pivot # \u8bbe\u5b9a\u8fb9\u754c\u5143\u7d20\uff08boundary point\uff09\uff0c\u521d\u59cb\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20 boundary = left print ( \"pivot: \" , pivot , \"boundary: \" , lyst [ boundary ]) # \u628a\u6240\u6709\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u90fd\u79fb\u52a8\u5230\u8fb9\u754c\u7684\u5de6\u8fb9 for index in range ( left , right ): if lyst [ index ] < pivot : swap ( lyst , index , boundary ) boundary += 1 # \u4ea4\u6362\u57fa\u51c6\u5143\u7d20\u548c\u8fb9\u754c\u5143\u7d20 swap ( lyst , right , boundary ) print ( lyst ) return boundary def main ( size = 20 , sort = quicksort ): lyst = [ 12 , 19 , 17 , 18 , 14 , 11 , 15 , 13 , 16 ] sort ( lyst ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # [12, 19, 17, 18, 14, 11, 15, 13, 16] # pivot: 14 boundary: 12 # [12, 11, 13, 14, 16, 19, 15, 17, 18] # [12, 11, 13, 14, 16, 19, 15, 17, 18] # pivot: 11 boundary: 12 # [11, 13, 12, 14, 16, 19, 15, 17, 18] # [11, 13, 12, 14, 16, 19, 15, 17, 18] # [11, 13, 12, 14, 16, 19, 15, 17, 18] # pivot: 13 boundary: 12 # [11, 12, 13, 14, 16, 19, 15, 17, 18] # [11, 12, 13, 14, 16, 19, 15, 17, 18] # [11, 12, 13, 14, 16, 19, 15, 17, 18] # [11, 12, 13, 14, 16, 19, 15, 17, 18] # pivot: 15 boundary: 16 # [11, 12, 13, 14, 15, 19, 18, 17, 16] # [11, 12, 13, 14, 15, 19, 18, 17, 16] # [11, 12, 13, 14, 15, 19, 18, 17, 16] # pivot: 18 boundary: 19 # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] # pivot: 16 boundary: 17 # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] # [11, 12, 13, 14, 15, 16, 17, 18, 19] \u628amain()\u6539\u6210\u5982\u4e0b\uff0c\u5219\u53ef\u4ee5\u751f\u6210\u753120\u4e2a\u968f\u673a\u6574\u6570\u7ec4\u6210\u7684\u5217\u8868\uff1a def main ( size = 20 , sort = quicksort ): lyst = [] for count in range ( size ): lyst . append ( random . randint ( 1 , size + 1 )) print ( lyst ) sort ( lyst ) print ( lyst ) # \u8fd0\u884c\u7ed3\u679c\uff1a # \u7b2c\u4e00\u6b21\u8fd0\u884c # [3, 19, 18, 11, 2, 16, 2, 13, 14, 1, 20, 1, 1, 19, 19, 9, 16, 1, 7, 4] # [1, 1, 1, 1, 2, 2, 3, 4, 7, 9, 11, 13, 14, 16, 16, 18, 19, 19, 19, 20] # \u7b2c\u4e8c\u6b21\u8fd0\u884c # [20, 4, 1, 15, 6, 4, 3, 16, 21, 4, 12, 9, 16, 10, 3, 6, 2, 15, 21, 4] # [1, 2, 3, 3, 4, 4, 4, 4, 6, 6, 9, 10, 12, 15, 15, 16, 16, 20, 21, 21]","title":"3.5.1.3.\u5b9e\u73b0\u5feb\u901f\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#352","text":"\u5f52\u5e76\u6392\u5e8f\u7684\u7b97\u6cd5\u4e5f\u662f\u91c7\u7528\u5206\u6cbb\u6cd5\uff08Divide and Conquer\uff09\u7684\u4e00\u4e2a\u975e\u5e38\u5178\u578b\u7684\u5e94\u7528\uff0c\u901a\u8fc7\u9012\u5f52\u548c\u5206\u6cbb\u7b56\u7565\u6765\u7a81\u7834 O(n^2) \u6027\u80fd\u74f6\u9888\u7684\u3002 \u4e0b\u9762\u662f\u5bf9\u8fd9\u4e2a\u7b97\u6cd5\u7684\u7b80\u5355\u63cf\u8ff0\u3002 \u5206\u89e3\uff08Divide\uff09\uff1a\u5c06n\u4e2a\u5143\u7d20\u5206\u6210\u4e2a\u542bn/2\u4e2a\u5143\u7d20\u7684\u5b50\u5e8f\u5217\u3002 \u89e3\u51b3\uff08Conquer\uff09\uff1a\u7528\u5408\u5e76\u6392\u5e8f\u6cd5\u5bf9\u4e24\u4e2a\u5b50\u5e8f\u5217\u9012\u5f52\u7684\u6392\u5e8f\u3002 \u5408\u5e76\uff08Combine\uff09\uff1a\u5408\u5e76\u4e24\u4e2a\u5df2\u6392\u5e8f\u7684\u5b50\u5e8f\u5217\u5df2\u5f97\u5230\u6392\u5e8f\u7ed3\u679c\u3002 \u7b97\u6cd5\u601d\u8def\uff1a \u8fed\u4ee3\u6cd5 \u7533\u8bf7\u7a7a\u95f4\uff0c\u4f7f\u5176\u5927\u5c0f\u4e3a\u4e24\u4e2a\u5df2\u7ecf\u6392\u5e8f\u5e8f\u5217\u4e4b\u548c\uff0c\u8be5\u7a7a\u95f4\u7528\u6765\u5b58\u653e\u5408\u5e76\u540e\u7684\u5e8f\u5217\uff1b \u8bbe\u5b9a\u4e24\u4e2a\u6307\u9488\uff0c\u6700\u521d\u4f4d\u7f6e\u5206\u522b\u4e3a\u4e24\u4e2a\u5df2\u7ecf\u6392\u5e8f\u5e8f\u5217\u7684\u8d77\u59cb\u4f4d\u7f6e\uff1b \u6bd4\u8f83\u4e24\u4e2a\u6307\u9488\u6240\u6307\u5411\u7684\u5143\u7d20\uff0c\u9009\u62e9\u76f8\u5bf9\u5c0f\u7684\u5143\u7d20\u653e\u5165\u5230\u5408\u5e76\u7a7a\u95f4\uff0c\u5e76\u79fb\u52a8\u6307\u9488\u5230\u4e0b\u4e00\u4f4d\u7f6e\uff1b \u91cd\u590d\u6b65\u9aa43\u76f4\u5230\u67d0\u4e00\u6307\u9488\u5230\u8fbe\u5e8f\u5217\u5c3e\uff1b \u5c06\u53e6\u4e00\u5e8f\u5217\u5269\u4e0b\u7684\u6240\u6709\u5143\u7d20\u76f4\u63a5\u590d\u5236\u5230\u5408\u5e76\u5e8f\u5217\u5c3e\uff1b \u9012\u5f52\u6cd5 \u5c06\u5e8f\u5217\u6bcf\u76f8\u90bb\u4e24\u4e2a\u6570\u5b57\u8fdb\u884c\u5f52\u5e76\u64cd\u4f5c\uff0c\u5f62\u6210 floor(n/2) \u4e2a\u5e8f\u5217\uff0c\u6392\u5e8f\u540e\u6bcf\u4e2a\u5e8f\u5217\u5305\u542b\u4e24\u4e2a\u5143\u7d20\uff1b \u5c06\u4e0a\u8ff0\u5e8f\u5217\u518d\u6b21\u5f52\u5e76\uff0c\u5f62\u6210 floor(n/4) \u4e2a\u5e8f\u5217\uff0c\u6bcf\u4e2a\u5e8f\u5217\u5305\u542b\u56db\u4e2a\u5143\u7d20\uff1b \u91cd\u590d\u6b65\u9aa42\uff0c\u76f4\u5230\u6240\u6709\u5143\u7d20\u6392\u5e8f\u5b8c\u6bd5\uff1b \u5728\u9876\u5c42\u5b9a\u4e49\u4e863\u4e2aPython\u51fd\u6570\u8fdb\u884c\u534f\u4f5c\u3002 mergeSort \uff1a\u7528\u6237\u8c03\u7528\u7684\u51fd\u6570\uff1b mergeSortHelper \uff1a\u8f85\u52a9\u51fd\u6570\uff0c\u7528\u6765\u9690\u85cf\u9012\u5f52\u8c03\u7528\u6240\u9700\u8981\u7684\u989d\u5916\u53c2\u6570\uff1b merge \uff1a\u5b9e\u73b0\u5408\u5e76\u8fc7\u7a0b\u7684\u51fd\u6570\uff1b","title":"3.5.2.\u5f52\u5e76\u6392\u5e8f"},{"location":"python/DataStructure/03_TimeComplexity/#3521","text":"\u5408\u5e76\u8fc7\u7a0b\u7528\u5230\u4e00\u4e2a\u4e0e\u5217\u8868\u5927\u5c0f\u76f8\u540c\u7684\u6570\u7ec4\uff0c\u8fd9\u4e2a\u6570\u7ec4\u53ef\u4ee5\u628a\u5b83\u79f0\u4e3a copyBuffer \u3002\u4e3a\u4e86\u907f\u514d\u6bcf\u6b21\u8c03\u7528 merge \u65f6\u90fd\u8981\u4e3a copyBuffer \u7684\u5206\u914d\u548c\u91ca\u653e\u4ea7\u751f\u5f00\u9500\uff0c\u8fd9\u4e2a\u7f13\u51b2\u533a\u4f1a\u5728 mergeSort \u51fd\u6570\u91cc\u5c31\u5206\u914d\u597d\uff0c\u7136\u540e\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7ed9 mergeSortHelper \u548c merge \u51fd\u6570\u3002\u6bcf\u6b21\u8c03\u7528 mergeSortHelper \u51fd\u6570\u65f6\uff0c\u5b83\u8fd8\u9700\u8981\u77e5\u9053\u5e94\u8be5\u4f7f\u7528\u7684\u5b50\u5217\u8868\u7684\u8303\u56f4\u3002\u8fd9\u4e2a\u8303\u56f4\u53ef\u4ee5\u7531\u53e6\u5916\u4e24\u4e2a\u53c2\u6570 low \u548c high \u6765\u63d0\u4f9b\u3002\u5177\u4f53\u5b9e\u73b0\u53c2\u8003 mergeSort \u51fd\u6570\u7684\u4ee3\u7801\u3002 \u5728\u68c0\u67e5\u4f20\u9012\u7684\u5b50\u5217\u8868\u662f\u4e0d\u662f\u81f3\u5c11\u6709\u4e24\u4e2a\u5143\u7d20\u4e4b\u540e\uff0c mergeSortHelper \u51fd\u6570\u5c06\u4f1a\u8ba1\u7b97\u8fd9\u4e2a\u5b50\u5217\u8868\u7684\u4e2d\u70b9\uff0c\u5e76\u4e14\u5bf9\u4e2d\u70b9\u5de6\u53f3\u4e24\u90e8\u5206\u8fdb\u884c\u9012\u5f52\u6392\u5e8f\uff0c\u6700\u540e\u518d\u8c03\u7528 merge \u51fd\u6570\u6765\u5408\u5e76\u7ed3\u679c\u3002\u5177\u4f53\u5b9e\u73b0\u53c2\u8003 mergeSortHelper \u51fd\u6570\u7684\u4ee3\u7801\u3002 merge \u51fd\u6570\u4f1a\u628a\u4e24\u4e2a\u5df2\u7ecf\u6392\u597d\u5e8f\u7684\u5b50\u5217\u8868\u5408\u5e76\u6210\u4e00\u4e2a\u66f4\u5927\u7684\u6709\u5e8f\u5217\u8868\u3002\u5728\u539f\u5217\u8868\u91cc\uff0c\u7b2c\u4e00\u4e2a\u5b50\u5217\u8868\u4f1a\u5728 low \u5230 middle \u4e4b\u95f4\uff1b\u7b2c\u4e8c\u4e2a\u5b50\u5217\u8868\u5219\u4f4d\u4e8e middle + 1 \u548c high \u4e4b\u95f4\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u5305\u542b\u5982\u4e0b3\u4e2a\u6b65\u9aa4\u3002 \u8bbe\u7f6e\u6307\u5411\u4e24\u4e2a\u5b50\u5217\u8868\u4e2d\u7b2c\u4e00\u4e2a\u5143\u7d20\u7684\u7d22\u5f15\u6307\u9488\u3002\u5b83\u4eec\u5206\u522b\u4f4d\u4e8e low \u548c middle +1 \uff1b \u4ece\u5b50\u5217\u8868\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\u91cd\u590d\u6bd4\u8f83\u8fd9\u4e9b\u5143\u7d20\u3002\u628a\u66f4\u5c0f\u7684\u90a3\u4e2a\u5143\u7d20\u4ece\u5b83\u6240\u5728\u7684\u5b50\u5217\u8868\u91cc\u590d\u5236\u5230\u62f7\u8d1d\u7f13\u51b2\u533a\u53bb\uff0c\u7136\u540e\u628a\u8fd9\u4e2a\u5b50\u5217\u8868\u7684\u7d22\u5f15\u79fb\u52a8\u5230\u4e0b\u4e00\u4e2a\u5143\u7d20\uff1b \u4e0d\u65ad\u5730\u6267\u884c\u8fd9\u4e2a\u64cd\u4f5c\uff0c\u76f4\u5230\u5df2\u7ecf\u5b8c\u5168\u590d\u5236\u4e86\u4e24\u4e2a\u5b50\u5217\u8868\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u5982\u679c\u5176\u4e2d\u4e00\u4e2a\u5b50\u5217\u8868\u5df2\u7ecf\u5230\u8fbe\u4e86\u672b\u5c3e\uff0c\u90a3\u4e48\u53ef\u4ee5\u628a\u53e6\u4e00\u4e2a\u5b50\u5217\u8868\u91cc\u7684\u5176\u4f59\u5143\u7d20\u76f4\u63a5\u590d\u5236\u8fc7\u53bb\uff1b \u628a copyBuffer \u4e2d low \u5230 high \u4e4b\u95f4\u7684\u90e8\u5206\u590d\u5236\u56de lyst \u4e2d\u7684\u76f8\u5e94\u4f4d\u7f6e\uff1b \u5b9e\u73b0\u4ee3\u7801\uff1a class Array ( object ): \"\"\" \u63cf\u8ff0\u4e00\u4e2a\u6570\u7ec4\u3002 \u6570\u7ec4\u7c7b\u4f3c\u5217\u8868\uff0c\u4f46\u6570\u7ec4\u53ea\u80fd\u4f7f\u7528[], len, iter, \u548c str\u8fd9\u4e9b\u5c5e\u6027\u3002 \u5b9e\u4f8b\u5316\u4e00\u4e2a\u6570\u7ec4\uff0c\u4f7f\u7528 = Array(, ) \u5176\u4e2dfill value\u9ed8\u8ba4\u503c\u662fNone\u3002 \"\"\" def __init__ ( self , capacity , fillValue = None ): \"\"\"Capacity\u662f\u6570\u7ec4\u7684\u5927\u5c0f. fillValue\u4f1a\u586b\u5145\u5728\u6bcf\u4e2a\u5143\u7d20\u4f4d\u7f6e, \u9ed8\u8ba4\u503c\u662fNone\"\"\" self . items = list () for count in range ( capacity ): self . items . append ( fillValue ) def __len__ ( self ): \"\"\"-> \u6570\u7ec4\u7684\u5927\u5c0f\"\"\" return len ( self . items ) def __str__ ( self ): \"\"\"-> \u5c06\u6570\u7ec4\u5b57\u7b26\u4e32\u5316\"\"\" return str ( self . items ) def __iter__ ( self ): \"\"\"\u652f\u6301for\u5faa\u73af\u5bf9\u6570\u7ec4\u8fdb\u884c\u904d\u5386.\"\"\" return iter ( self . items ) def __getitem__ ( self , index ): \"\"\"\u7528\u4e8e\u8bbf\u95ee\u7d22\u5f15\u5904\u7684\u4e0b\u6807\u8fd0\u7b97\u7b26.\"\"\" return self . items [ index ] def __setitem__ ( self , index , newItem ): \"\"\"\u4e0b\u6807\u8fd0\u7b97\u7b26\u7528\u4e8e\u5728\u7d22\u5f15\u5904\u8fdb\u884c\u66ff\u6362.\"\"\" self . items [ index ] = newItem def mergeSort ( lyst ): # lyst : \u7528\u4e8e\u6392\u5e8f\u7684\u5217\u8868 # copyBuffer : \u7528\u4e8e\u5408\u5e76\u7684\u4e34\u65f6\u7a7a\u95f4 copyBuffer = Array ( len ( lyst )) mergeSortHelper ( lyst , copyBuffer , 0 , len ( lyst ) - 1 ) def mergeSortHelper ( lyst , copyBuffer , low , high ): # lyst : \u7528\u4e8e\u6392\u5e8f\u7684\u5217\u8868 # copyBuffer : \u7528\u4e8e\u5408\u5e76\u7684\u4e34\u65f6\u7a7a\u95f4 # low, high : \u5b50\u5217\u8868\u7684\u8fb9\u754c # middle : \u5b50\u5217\u8868\u7684\u4e2d\u70b9 if low < high : middle = ( low + high ) // 2 print ( f 'low: { lyst [ low ] } , middle: { lyst [ middle ] } , high: { lyst [ high ] } , copyBuffer: { copyBuffer } ' ) # \u9012\u5f52\u5904\u7406\u7b2c\u4e00\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\uff0c\u5373\u4e2d\u503c\u7684\u5de6\u6bb5\uff0c\u76f4\u81f3\u4e0d\u6ee1\u8db3low < high\u65f6\u9000\u51fa mergeSortHelper ( lyst , copyBuffer , low , middle ) # \u9012\u5f52\u5904\u7406\u7b2c\u4e8c\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\uff0c\u5373\u4e2d\u503c\u7684\u53f3\u6bb5\uff0c\u76f4\u81f3\u4e0d\u6ee1\u8db3low < high\u65f6\u9000\u51fa mergeSortHelper ( lyst , copyBuffer , middle + 1 , high ) # \u5f53\u524d\u5904\u7406\u7684\u5b50\u8868\u6570\u636e\u9001\u5165copyBuffer\uff0c\u5408\u5e76\u4e14\u6392\u5e8f merge ( lyst , copyBuffer , low , middle , high ) def merge ( lyst , copyBuffer , low , middle , high ): # lyst : \u7528\u4e8e\u6392\u5e8f\u7684\u5217\u8868 # copyBuffer : \u7528\u4e8e\u5408\u5e76\u7684\u4e34\u65f6\u7a7a\u95f4 # low : \u7b2c\u4e00\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u5f00\u5934 # middle : \u7b2c\u4e00\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u7ed3\u5c3e # middle + 1 : \u7b2c\u4e8c\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u5f00\u5934 # high : \u7b2c\u4e8c\u4e2a\u6392\u5e8f\u5b50\u5217\u8868\u7684\u7ed3\u5c3e # \u5c06 i1 \u548c i2 \u521d\u59cb\u5316\u4e3a\u6bcf\u4e2a\u5b50\u5217\u8868\u4e2d\u7684\u7b2c\u4e00\u9879 i1 = low i2 = middle + 1 # \u5c06\u5b50\u5217\u8868\u4e2d\u7684\u5143\u7d20\u4ea4\u9519\u653e\u5165copyBuffer\u4e2d\uff0c\u5e76\u4fdd\u6301\u987a\u5e8f\u3002 for i in range ( low , high + 1 ): if i1 > middle : copyBuffer [ i ] = lyst [ i2 ] # \u7b2c\u4e00\u4e2a\u5b50\u5217\u8868\u5df2\u7528\u5b8c i2 += 1 elif i2 > high : copyBuffer [ i ] = lyst [ i1 ] # \u7b2c\u4e8c\u4e2a\u5b50\u5217\u8868\u5df2\u7528\u5b8c i1 += 1 elif lyst [ i1 ] < lyst [ i2 ]: copyBuffer [ i ] = lyst [ i1 ] # \u7b2c\u4e00\u4e2a\u5b50\u8868\u4e2d\u7684\u5143\u7d20 < i1 += 1 else : copyBuffer [ i ] = lyst [ i2 ] # \u7b2c\u4e8c\u4e2a\u5b50\u8868\u4e2d\u7684\u5143\u7d20 < i2 += 1 print ( \"i=\" , i , \"\" , \"i1=\" , i1 , \"i2=\" , i2 , \"copyBuffer:\" , copyBuffer ) for i in range ( low , high + 1 ): # \u5c06\u5df2\u6392\u5e8f\u7684\u5143\u7d20\u590d\u5236\u56delyst\u4e2d\u7684\u6b63\u786e\u4f4d\u7f6e lyst [ i ] = copyBuffer [ i ] def main (): lyst = [ 12 , 19 , 17 , 18 , 14 , 11 , 15 , 13 , 16 ] print ( \"Original List\" , lyst ) mergeSort ( lyst ) print ( \"Sorted List\" , lyst ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Original List [12, 19, 17, 18, 14, 11, 15, 13, 16] # low: 12, middle: 14, high: 16, copyBuffer: [None, None, None, None, None, None, None, None, None] # low: 12, middle: 17, high: 14, copyBuffer: [None, None, None, None, None, None, None, None, None] # low: 12, middle: 19, high: 17, copyBuffer: [None, None, None, None, None, None, None, None, None] # low: 12, middle: 12, high: 19, copyBuffer: [None, None, None, None, None, None, None, None, None] # i= 1 i1= 1 i2= 2 copyBuffer: [12, 19, None, None, None, None, None, None, None] # i= 2 i1= 2 i2= 3 copyBuffer: [12, 17, 19, None, None, None, None, None, None] # low: 18, middle: 18, high: 14, copyBuffer: [12, 17, 19, None, None, None, None, None, None] # i= 4 i1= 4 i2= 5 copyBuffer: [12, 17, 19, 14, 18, None, None, None, None] # i= 4 i1= 3 i2= 5 copyBuffer: [12, 14, 17, 18, 19, None, None, None, None] # low: 11, middle: 15, high: 16, copyBuffer: [12, 14, 17, 18, 19, None, None, None, None] # low: 11, middle: 11, high: 15, copyBuffer: [12, 14, 17, 18, 19, None, None, None, None] # i= 6 i1= 6 i2= 7 copyBuffer: [12, 14, 17, 18, 19, 11, 15, None, None] # low: 13, middle: 13, high: 16, copyBuffer: [12, 14, 17, 18, 19, 11, 15, None, None] # i= 8 i1= 8 i2= 9 copyBuffer: [12, 14, 17, 18, 19, 11, 15, 13, 16] # i= 8 i1= 7 i2= 9 copyBuffer: [12, 14, 17, 18, 19, 11, 13, 15, 16] # i= 8 i1= 5 i2= 9 copyBuffer: [11, 12, 13, 14, 15, 16, 17, 18, 19] # Sorted List [11, 12, 13, 14, 15, 16, 17, 18, 19] \u8fd0\u884c\u7ed3\u679c\u56fe\u793a\u5206\u6790\uff1a","title":"3.5.2.1.\u5408\u5e76\u8fc7\u7a0b\u7684\u5b9e\u73b0"},{"location":"python/DataStructure/03_TimeComplexity/#3522","text":"merge \u51fd\u6570\u7684\u8fd0\u884c\u65f6\u7531\u4e24\u4e2a for \u8bed\u53e5\u6765\u51b3\u5b9a\uff0c\u800c\u8fd9\u4e24\u4e2a\u5faa\u73af\u90fd\u4f1a\u88ab\u8fed\u4ee3 (high \u2013 low + 1) \u6b21\uff0c\u56e0\u6b64\uff0c\u8fd9\u4e2a\u51fd\u6570\u7684\u8fd0\u884c\u65f6\u662f O(high\u2212low) \uff0c\u4e8e\u662f\u6bcf\u4e00\u5c42\u4e0a\u7684\u6240\u6709\u5408\u5e76\u603b\u5171\u9700\u8981 O(n) \u7684\u65f6\u95f4\u3002\u56e0\u4e3a mergeSortHelper \u5728\u6bcf\u4e00\u5c42\u90fd\u5c3d\u53ef\u80fd\u5747\u5300\u5730\u62c6\u5206\u5b50\u5217\u8868\uff0c\u6240\u4ee5\u5c42\u6570\u5e94\u8be5\u662f O(log n) \uff0c\u5728\u6240\u6709\u7684\u60c5\u51b5\u4e0b\u8fd9\u4e2a\u51fd\u6570\u7684\u6700\u5927\u8fd0\u884c\u65f6\u90fd\u662f O(n log n) \u3002 \u5f52\u5e76\u6392\u5e8f\u4f1a\u6709\u4e24\u4e2a\u57fa\u4e8e\u5217\u8868\u5927\u5c0f\u7684\u7a7a\u95f4\u9700\u6c42\u3002\u9996\u5148\uff0c\u5728\u8c03\u7528\u6808\u4e0a\u9700\u8981 O(log n) \u7684\u7a7a\u95f4\u6765\u652f\u6301\u9012\u5f52\u8c03\u7528\uff1b\u5176\u6b21\uff0c\u62f7\u8d1d\u7f13\u51b2\u533a\u4f1a\u7528\u5230 O(n) \u7684\u7a7a\u95f4\u3002","title":"3.5.2.2.\u5f52\u5e76\u6392\u5e8f\u7684\u590d\u6742\u5ea6\u5206\u6790"},{"location":"python/DataStructure/03_TimeComplexity/#353","text":"\u63cf\u8ff0\u5feb\u901f\u6392\u5e8f\u7684\u7b56\u7565\uff0c\u5e76\u8bf4\u660e\u4e3a\u4ec0\u4e48\u5b83\u53ef\u4ee5\u628a\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ece O(n^2) \u964d\u4f4e\u5230 O(n log n) \u3002 \u89e3\u7b54\uff1a\u5feb\u901f\u6392\u5e8f\uff08Quick Sort\uff09\u662f\u4e00\u79cd\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u5b83\u91c7\u7528\u5206\u6cbb\u7b56\u7565\u6765\u5c06\u4e00\u4e2a\u5927\u95ee\u9898\u5206\u89e3\u6210\u82e5\u5e72\u4e2a\u5b50\u95ee\u9898\uff0c\u7136\u540e\u9012\u5f52\u5730\u89e3\u51b3\u8fd9\u4e9b\u5b50\u95ee\u9898\u3002\u4ee5\u4e0b\u662f\u5feb\u901f\u6392\u5e8f\u7684\u7b56\u7565\u548c\u539f\u7406\uff0c\u4ee5\u53ca\u4e3a\u4ec0\u4e48\u5b83\u80fd\u591f\u5c06\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ece O(n^2) \u964d\u4f4e\u5230 O(n log n) \uff1a \u5feb\u901f\u6392\u5e8f\u7684\u7b56\u7565\uff1a \u9009\u62e9\u4e3b\u5143\uff08Pivot\uff09\uff1a\u5728\u5feb\u901f\u6392\u5e8f\u4e2d\uff0c\u9996\u5148\u4ece\u5f85\u6392\u5e8f\u7684\u5143\u7d20\u4e2d\u9009\u62e9\u4e00\u4e2a\u4e3b\u5143\uff08\u901a\u5e38\u662f\u7b2c\u4e00\u4e2a\u6216\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff09\uff0c\u4e5f\u53eb\u57fa\u51c6\u5143\u7d20\u3002 \u5206\u5272\u64cd\u4f5c\uff1a\u5c06\u5143\u7d20\u5206\u4e3a\u4e24\u4e2a\u5b50\u6570\u7ec4\uff0c\u4e00\u4e2a\u5c0f\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\uff0c\u4e00\u4e2a\u5927\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u79f0\u4e3a\u5206\u5272\u3002 \u9012\u5f52\u6392\u5e8f\uff1a\u9012\u5f52\u5730\u5bf9\u4e24\u4e2a\u5b50\u6570\u7ec4\u8fdb\u884c\u6392\u5e8f\u3002\u5373\uff0c\u5bf9\u5c0f\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\u548c\u5927\u4e8e\u4e3b\u5143\u7684\u5b50\u6570\u7ec4\u5206\u522b\u8fdb\u884c\u5feb\u901f\u6392\u5e8f\u3002 \u5408\u5e76\uff1a\u5c06\u5df2\u6392\u5e8f\u7684\u5b50\u6570\u7ec4\u5408\u5e76\u6210\u6700\u7ec8\u7684\u6709\u5e8f\u6570\u7ec4\u3002 \u4e3a\u4ec0\u4e48\u5feb\u901f\u6392\u5e8f\u80fd\u591f\u964d\u4f4e\u65f6\u95f4\u590d\u6742\u5ea6\uff1a \u5feb\u901f\u6392\u5e8f\u4e4b\u6240\u4ee5\u80fd\u591f\u5c06\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ece O(n^2) \u964d\u4f4e\u5230 O(n log n) \uff0c\u4e3b\u8981\u6709\u4ee5\u4e0b\u539f\u56e0\uff1a \u5206\u6cbb\u7b56\u7565\uff1a\u5feb\u901f\u6392\u5e8f\u91c7\u7528\u4e86\u5206\u6cbb\u7b56\u7565\uff0c\u5c06\u4e00\u4e2a\u5927\u95ee\u9898\u5206\u89e3\u6210\u4e24\u4e2a\u6216\u591a\u4e2a\u89c4\u6a21\u8f83\u5c0f\u7684\u5b50\u95ee\u9898\u3002\u8fd9\u79cd\u5206\u6cbb\u7b56\u7565\u80fd\u591f\u51cf\u5c0f\u95ee\u9898\u7684\u89c4\u6a21\uff0c\u4ece\u800c\u964d\u4f4e\u4e86\u89e3\u51b3\u95ee\u9898\u7684\u590d\u6742\u5ea6\u3002 \u597d\u7684\u5e73\u5747\u60c5\u51b5\uff1a\u5728\u5e73\u5747\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u5bf9\u5f85\u6392\u5e8f\u7684\u6570\u636e\u8fdb\u884c\u4e86\u826f\u597d\u7684\u5e73\u5747\u5206\u5272\uff0c\u6bcf\u6b21\u5206\u5272\u90fd\u5c06\u95ee\u9898\u89c4\u6a21\u51cf\u534a\u3002\u8fd9\u4f7f\u5f97\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n log n) \u3002 **\u4e0d\u7a33\u5b9a\u6027\uff1a\u5feb\u901f\u6392\u5e8f\u662f\u4e0d\u7a33\u5b9a\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u8fd9\u610f\u5473\u7740\u76f8\u540c\u5143\u7d20\u7684\u76f8\u5bf9\u987a\u5e8f\u5728\u6392\u5e8f\u540e\u53ef\u80fd\u4f1a\u6539\u53d8\u3002\u8fd9\u79cd\u4e0d\u7a33\u5b9a\u6027\u4f7f\u5f97\u5feb\u901f\u6392\u5e8f\u53ef\u4ee5\u66f4\u5feb\u5730\u6392\u5e8f\u76f8\u540c\u5143\u7d20\u7684\u5927\u6570\u636e\u96c6\u3002 \u539f\u5730\u6392\u5e8f\uff1a\u5feb\u901f\u6392\u5e8f\u901a\u5e38\u662f\u539f\u5730\u6392\u5e8f\u7684\uff0c\u5b83\u4e0d\u9700\u8981\u989d\u5916\u7684\u5185\u5b58\u6765\u5b58\u50a8\u4e34\u65f6\u6570\u636e\u3002\u8fd9\u5bf9\u4e8e\u5185\u5b58\u5360\u7528\u6709\u9650\u7684\u60c5\u51b5\u5f88\u6709\u5229\u3002 \u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u5feb\u901f\u6392\u5e8f\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662f O(n^2) \uff0c\u8fd9\u79cd\u60c5\u51b5\u901a\u5e38\u53d1\u751f\u5728\u4e3b\u5143\u9009\u62e9\u4e0d\u5f53\u6216\u8f93\u5165\u6570\u636e\u5df2\u7ecf\u6709\u5e8f\u7684\u60c5\u51b5\u4e0b\u3002\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u901a\u5e38\u9700\u8981\u9009\u62e9\u4e00\u4e2a\u5408\u9002\u7684\u4e3b\u5143\u9009\u62e9\u7b56\u7565\uff0c\u4ee5\u5c3d\u91cf\u907f\u514d\u6700\u574f\u60c5\u51b5\u7684\u53d1\u751f\u3002 \u4e3a\u4ec0\u4e48\u5feb\u901f\u6392\u5e8f\u5e76\u4e0d\u5728\u6240\u6709\u60c5\u51b5\u4e0b\u90fd\u6709 O(n log n) \u7684\u590d\u6742\u5ea6\uff1f\u5bf9\u5feb\u901f\u6392\u5e8f\u7684\u6700\u574f\u60c5\u51b5\u8fdb\u884c\u63cf\u8ff0\uff0c\u5e76\u7ed9\u51fa\u4e00\u4e2a\u4f1a\u4ea7\u751f\u8fd9\u4e2a\u60c5\u51b5\u7684\u5305\u542b10\u4e2a\u6574\u6570\uff081\uff5e10\uff09\u7684\u5217\u8868\u3002 \u89e3\u7b54\uff1a\u5feb\u901f\u6392\u5e8f\u5e76\u4e0d\u5728\u6240\u6709\u60c5\u51b5\u4e0b\u90fd\u5177\u6709 O(n log n) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\uff0c\u5b83\u7684\u6027\u80fd\u53d6\u51b3\u4e8e\u4e3b\u5143\uff08pivot\uff09\u7684\u9009\u62e9\u548c\u8f93\u5165\u6570\u636e\u7684\u5206\u5e03\u60c5\u51b5\u3002\u6700\u574f\u60c5\u51b5\u53d1\u751f\u5728\u4ee5\u4e0b\u60c5\u51b5\u4e0b\uff1a \u4e3b\u5143\u9009\u62e9\u4e0d\u5f53\uff1a\u5982\u679c\u6bcf\u6b21\u9009\u62e9\u7684\u4e3b\u5143\u90fd\u662f\u8f93\u5165\u6570\u636e\u4e2d\u7684\u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\uff0c\u5feb\u901f\u6392\u5e8f\u5c06\u4f1a\u4ea7\u751f\u6700\u574f\u60c5\u51b5\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u5206\u5272\u64cd\u4f5c\u5c06\u5bfc\u81f4\u4e00\u4e2a\u5b50\u6570\u7ec4\u4e3a\u7a7a\uff0c\u53e6\u4e00\u4e2a\u5b50\u6570\u7ec4\u7684\u5927\u5c0f\u4e3a\u539f\u59cb\u6570\u7ec4\u5927\u5c0f\u51cf\u4e00\u3002\u8fd9\u4f7f\u5f97\u6bcf\u6b21\u5206\u5272\u64cd\u4f5c\u53ea\u51cf\u5c11\u4e00\u4e2a\u5143\u7d20\uff0c\u5bfc\u81f4\u9012\u5f52\u6df1\u5ea6\u8fbe\u5230\u6700\u5927\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \u3002 \u8f93\u5165\u6570\u636e\u5df2\u7ecf\u6709\u5e8f\uff1a\u5982\u679c\u8f93\u5165\u6570\u636e\u5df2\u7ecf\u662f\u6709\u5e8f\u7684\uff0c\u4e0d\u7ba1\u662f\u5347\u5e8f\u8fd8\u662f\u964d\u5e8f\uff0c\u5feb\u901f\u6392\u5e8f\u4e5f\u4f1a\u4ea7\u751f\u6700\u574f\u60c5\u51b5\u3002\u56e0\u4e3a\u65e0\u8bba\u5982\u4f55\u9009\u62e9\u4e3b\u5143\uff0c\u5206\u5272\u64cd\u4f5c\u90fd\u5c06\u5bfc\u81f4\u4e00\u4e2a\u5b50\u6570\u7ec4\u4e3a\u7a7a\uff0c\u53e6\u4e00\u4e2a\u5b50\u6570\u7ec4\u7684\u5927\u5c0f\u4e3a\u539f\u59cb\u6570\u7ec4\u5927\u5c0f\u51cf\u4e00\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u5305\u542b10\u4e2a\u6574\u6570\uff081\uff5e10\uff09\u7684\u5217\u8868\uff0c\u6f14\u793a\u4e86\u5bfc\u81f4\u5feb\u901f\u6392\u5e8f\u6700\u574f\u60c5\u51b5\u7684\u8f93\u5165\u6570\u636e\uff1a [ 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 ] \u5728\u8fd9\u4e2a\u793a\u4f8b\u4e2d\uff0c\u6bcf\u6b21\u9009\u62e9\u7684\u4e3b\u5143\u90fd\u662f\u6700\u5927\u7684\u5143\u7d20\uff0810\uff09\uff0c\u5bfc\u81f4\u5206\u5272\u64cd\u4f5c\u4e0d\u65ad\u51cf\u5c11\u6570\u7ec4\u7684\u5927\u5c0f\uff0c\u9012\u5f52\u6df1\u5ea6\u8fbe\u5230\u6700\u5927\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \u3002 \u8981\u907f\u514d\u6700\u574f\u60c5\u51b5\uff0c\u901a\u5e38\u91c7\u7528\u4ee5\u4e0b\u7b56\u7565\uff1a \u9009\u62e9\u5408\u9002\u7684\u4e3b\u5143\uff0c\u4f8b\u5982\u9009\u62e9\u4e2d\u95f4\u5143\u7d20\uff0c\u4ee5\u786e\u4fdd\u5e73\u5747\u5206\u5272\u3002 \u968f\u673a\u9009\u62e9\u4e3b\u5143\uff0c\u4ee5\u51cf\u5c11\u51fa\u73b0\u6700\u574f\u60c5\u51b5\u7684\u6982\u7387\u3002 \u8fd9\u4e9b\u7b56\u7565\u6709\u52a9\u4e8e\u7ef4\u6301\u5feb\u901f\u6392\u5e8f\u7684\u5e73\u5747\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n log n) \u3002 \u5feb\u901f\u6392\u5e8f\u91cc\u7684\u5206\u5272\u64cd\u4f5c\u4f1a\u9009\u62e9\u4e2d\u70b9\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\u3002\u8bf7\u63cf\u8ff0\u53e6\u5916\u4e24\u79cd\u9009\u62e9\u57fa\u51c6\u7684\u7b56\u7565\u3002 \u89e3\u7b54\uff1a\u5feb\u901f\u6392\u5e8f\u4e2d\u7684\u5206\u5272\u64cd\u4f5c\u53ef\u4ee5\u9009\u62e9\u4e2d\u70b9\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\uff0c\u4f46\u8fd8\u6709\u5176\u4ed6\u4e24\u79cd\u5e38\u89c1\u7684\u9009\u62e9\u57fa\u51c6\u7684\u7b56\u7565\uff0c\u5b83\u4eec\u5206\u522b\u662f\uff1a \u968f\u673a\u9009\u62e9\u57fa\u51c6\uff08Random Pivot\uff09\uff1a\u8fd9\u79cd\u7b56\u7565\u662f\u5728\u5f85\u6392\u5e8f\u6570\u7ec4\u4e2d\u968f\u673a\u9009\u62e9\u4e00\u4e2a\u5143\u7d20\u4f5c\u4e3a\u57fa\u51c6\u3002\u968f\u673a\u9009\u62e9\u57fa\u51c6\u7684\u597d\u5904\u662f\u53ef\u4ee5\u964d\u4f4e\u51fa\u73b0\u6700\u574f\u60c5\u51b5\u7684\u6982\u7387\uff0c\u56e0\u4e3a\u5728\u5927\u591a\u6570\u60c5\u51b5\u4e0b\uff0c\u968f\u673a\u9009\u62e9\u7684\u57fa\u51c6\u4f1a\u6bd4\u56fa\u5b9a\u4f4d\u7f6e\u7684\u57fa\u51c6\u66f4\u5e73\u5747\u5730\u5212\u5206\u6570\u636e\u3002\u8fd9\u53ef\u4ee5\u63d0\u9ad8\u7b97\u6cd5\u7684\u6027\u80fd\u3002 \u4e09\u6570\u53d6\u4e2d\u6cd5\uff08Median-of-Three Pivot\uff09\uff1a\u8fd9\u79cd\u7b56\u7565\u662f\u5728\u5f85\u6392\u5e8f\u6570\u7ec4\u4e2d\u9009\u62e9\u4e09\u4e2a\u5143\u7d20\uff08\u901a\u5e38\u662f\u7b2c\u4e00\u4e2a\u3001\u4e2d\u95f4\u4e00\u4e2a\u548c\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff09\uff0c\u7136\u540e\u4ece\u8fd9\u4e09\u4e2a\u5143\u7d20\u4e2d\u9009\u62e9\u4e2d\u95f4\u503c\u4f5c\u4e3a\u57fa\u51c6\u3002\u8fd9\u4e2a\u7b56\u7565\u7684\u76ee\u7684\u662f\u5728\u5c3d\u91cf\u907f\u514d\u6700\u574f\u60c5\u51b5\u7684\u540c\u65f6\uff0c\u4fdd\u6301\u57fa\u51c6\u7684\u76f8\u5bf9\u4e2d\u95f4\u4f4d\u7f6e\u3002\u8fd9\u53ef\u4ee5\u63d0\u9ad8\u7b97\u6cd5\u7684\u5e73\u5747\u6027\u80fd\u3002 \u8fd9\u4e09\u79cd\u9009\u62e9\u57fa\u51c6\u7684\u7b56\u7565\u5404\u6709\u4f18\u52a3\uff0c\u4f46\u5b83\u4eec\u7684\u5171\u540c\u76ee\u6807\u662f\u964d\u4f4e\u6700\u574f\u60c5\u51b5\u7684\u6982\u7387\uff0c\u4ece\u800c\u63d0\u9ad8\u5feb\u901f\u6392\u5e8f\u7684\u6027\u80fd\u3002\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u9009\u62e9\u54ea\u79cd\u7b56\u7565\u53d6\u51b3\u4e8e\u5177\u4f53\u7684\u60c5\u51b5\u548c\u5b9e\u73b0\u3002 \u5f53\u5feb\u901f\u6392\u5e8f\u91cc\u7684\u5b50\u5217\u8868\u7684\u957f\u5ea6\u5c0f\u4e8e\u67d0\u4e2a\u6570\u5b57\uff08\u598230\uff09\u65f6\uff0c\u6267\u884c\u63d2\u5165\u6392\u5e8f\u6765\u5904\u7406\u8fd9\u4e2a\u5b50\u5217\u8868\u3002\u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u8fd9\u662f\u4e00\u4e2a\u597d\u65b9\u6cd5\u3002 \u89e3\u7b54\uff1a\u5728\u5feb\u901f\u6392\u5e8f\u4e2d\uff0c\u5f53\u5b50\u5217\u8868\u7684\u957f\u5ea6\u53d8\u5f97\u5f88\u5c0f\u65f6\uff08\u901a\u5e38\u5c0f\u4e8e\u67d0\u4e2a\u9884\u5b9a\u7684\u9608\u503c\uff0c\u598230\u6216\u5176\u4ed6\u7ecf\u9a8c\u503c\uff09\uff0c\u6267\u884c\u63d2\u5165\u6392\u5e8f\u6765\u5904\u7406\u8fd9\u4e2a\u5b50\u5217\u8868\u662f\u4e00\u4e2a\u597d\u65b9\u6cd5\uff0c\u4e3b\u8981\u57fa\u4e8e\u4ee5\u4e0b\u8003\u8651\uff1a \u63d2\u5165\u6392\u5e8f\u5bf9\u5c0f\u89c4\u6a21\u6570\u636e\u8868\u73b0\u826f\u597d\uff1a\u63d2\u5165\u6392\u5e8f\u662f\u4e00\u79cd\u7b80\u5355\u4f46\u9ad8\u6548\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u7279\u522b\u9002\u7528\u4e8e\u5c0f\u89c4\u6a21\u6570\u636e\u96c6\u3002\u5b83\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(n^2) \uff0c\u4f46\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u5bf9\u4e8e\u5c0f\u89c4\u6a21\u7684\u6570\u636e\uff0c\u5b83\u7684\u6027\u80fd\u901a\u5e38\u5f88\u597d\u3002 \u51cf\u5c11\u9012\u5f52\u6df1\u5ea6\uff1a\u5728\u5feb\u901f\u6392\u5e8f\u4e2d\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u90fd\u4f1a\u589e\u52a0\u9012\u5f52\u6df1\u5ea6\uff0c\u800c\u9012\u5f52\u6df1\u5ea6\u8fc7\u5927\u53ef\u80fd\u4f1a\u5bfc\u81f4\u6808\u6ea2\u51fa\u6216\u6027\u80fd\u4e0b\u964d\u3002\u5f53\u5b50\u5217\u8868\u957f\u5ea6\u5c0f\u4e8e\u67d0\u4e2a\u9608\u503c\u65f6\uff0c\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u53ef\u4ee5\u907f\u514d\u4e0d\u5fc5\u8981\u7684\u9012\u5f52\u6df1\u5ea6\uff0c\u4ece\u800c\u51cf\u5c11\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u3002 \u9002\u7528\u4e8e\u90e8\u5206\u6709\u5e8f\u7684\u5b50\u5217\u8868\uff1a\u5f53\u5b50\u5217\u8868\u5df2\u7ecf\u90e8\u5206\u6709\u5e8f\u65f6\uff0c\u63d2\u5165\u6392\u5e8f\u7684\u6027\u80fd\u901a\u5e38\u6bd4\u5feb\u901f\u6392\u5e8f\u66f4\u597d\u3002\u56e0\u6b64\uff0c\u5bf9\u4e8e\u53ef\u80fd\u5305\u542b\u5df2\u6392\u5e8f\u90e8\u5206\u7684\u5c0f\u5b50\u5217\u8868\uff0c\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u53ef\u4ee5\u63d0\u9ad8\u7b97\u6cd5\u7684\u6548\u7387\u3002 \u51cf\u5c11\u9012\u5f52\u5f00\u9500\uff1a\u9012\u5f52\u5f00\u9500\u662f\u5feb\u901f\u6392\u5e8f\u7684\u4e00\u4e2a\u4e0d\u53ef\u5ffd\u89c6\u7684\u56e0\u7d20\uff0c\u7279\u522b\u662f\u5728\u5904\u7406\u5c0f\u89c4\u6a21\u5b50\u5217\u8868\u65f6\u3002\u901a\u8fc7\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u6765\u5904\u7406\u8fd9\u4e9b\u5c0f\u89c4\u6a21\u5b50\u5217\u8868\uff0c\u53ef\u4ee5\u51cf\u5c11\u9012\u5f52\u5f00\u9500\uff0c\u63d0\u9ad8\u7b97\u6cd5\u7684\u6574\u4f53\u6027\u80fd\u3002 \u5c06\u63d2\u5165\u6392\u5e8f\u4e0e\u5feb\u901f\u6392\u5e8f\u7ed3\u5408\u4f7f\u7528\u662f\u4e00\u79cd\u5e38\u89c1\u7684\u4f18\u5316\u7b56\u7565\uff0c\u5b83\u53ef\u4ee5\u5728\u5904\u7406\u5c0f\u89c4\u6a21\u5b50\u5217\u8868\u65f6\u63d0\u9ad8\u7b97\u6cd5\u7684\u6548\u7387\uff0c\u540c\u65f6\u4fdd\u6301\u5feb\u901f\u6392\u5e8f\u7684\u6574\u4f53\u6027\u80fd\u3002\u8fd9\u79cd\u65b9\u6cd5\u88ab\u79f0\u4e3a\u201c\u5feb\u901f\u6392\u5e8f\u7684\u6539\u8fdb\u201d\u6216\u201c\u5feb\u901f\u6392\u5e8f\u7684\u6df7\u5408\u6392\u5e8f\u201d\u7b56\u7565\uff0c\u7528\u4e8e\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\u63d0\u9ad8\u7b97\u6cd5\u7684\u6548\u7387\u3002 \u4e3a\u4ec0\u4e48\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4e5f\u662f\u4e00\u4e2a O(n log n) \u7b97\u6cd5\uff1f \u89e3\u7b54\uff1a\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4ecd\u7136\u5177\u6709 O(n log n) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\uff0c\u8fd9\u662f\u56e0\u4e3a\u5f52\u5e76\u6392\u5e8f\u7684\u7b97\u6cd5\u8bbe\u8ba1\u4f7f\u5176\u80fd\u591f\u7a33\u5b9a\u5730\u4fdd\u6301\u8fd9\u79cd\u6027\u80fd\uff0c\u4e0d\u53d7\u8f93\u5165\u6570\u636e\u5206\u5e03\u7684\u5f71\u54cd\u3002 \u4ee5\u4e0b\u662f\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4ecd\u7136\u5177\u6709 O(n log n) \u65f6\u95f4\u590d\u6742\u5ea6\u7684\u539f\u56e0\uff1a \u5206\u800c\u6cbb\u4e4b\u7b56\u7565\uff1a\u5f52\u5e76\u6392\u5e8f\u91c7\u7528\u4e86\u5206\u800c\u6cbb\u4e4b\u7684\u7b56\u7565\uff0c\u5c06\u95ee\u9898\u5206\u89e3\u4e3a\u8f83\u5c0f\u7684\u5b50\u95ee\u9898\uff0c\u7136\u540e\u5408\u5e76\u8fd9\u4e9b\u5b50\u95ee\u9898\u7684\u89e3\u3002\u8fd9\u4e2a\u7b56\u7565\u786e\u4fdd\u4e86\u7b97\u6cd5\u7684\u9012\u5f52\u6df1\u5ea6\u5728 log n \u7ea7\u522b\uff0c\u56e0\u4e3a\u6bcf\u6b21\u9012\u5f52\u90fd\u5c06\u6570\u636e\u5212\u5206\u6210\u4e24\u534a\uff0c\u76f4\u5230\u6700\u5c0f\u5b50\u95ee\u9898\u7684\u5927\u5c0f\u4e3a1\u3002 \u5408\u5e76\u64cd\u4f5c\u7684\u7ebf\u6027\u65f6\u95f4\uff1a\u5f52\u5e76\u6392\u5e8f\u7684\u5173\u952e\u64cd\u4f5c\u662f\u5408\u5e76\u5df2\u6392\u5e8f\u7684\u5b50\u6570\u7ec4\u3002\u5408\u5e76\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f\u7ebf\u6027\u7684\uff0c\u4e0e\u8f93\u5165\u6570\u636e\u7684\u89c4\u6a21 n \u6210\u6b63\u6bd4\u3002\u56e0\u6b64\uff0c\u5373\u4f7f\u5728\u5408\u5e76\u9636\u6bb5\uff0c\u7b97\u6cd5\u7684\u603b\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u53d7\u9650\u4e8e O(n log n) \u3002 \u7a33\u5b9a\u6027\uff1a\u5f52\u5e76\u6392\u5e8f\u662f\u4e00\u79cd\u7a33\u5b9a\u6392\u5e8f\u7b97\u6cd5\uff0c\u610f\u5473\u7740\u5b83\u5728\u6392\u5e8f\u76f8\u7b49\u5143\u7d20\u65f6\u4f1a\u4fdd\u6301\u5b83\u4eec\u7684\u76f8\u5bf9\u987a\u5e8f\u3002\u8fd9\u4e00\u6027\u8d28\u4f7f\u5f97\u7b97\u6cd5\u5728\u5904\u7406\u76f8\u7b49\u5143\u7d20\u6216\u8005\u5177\u6709\u7279\u5b9a\u6570\u636e\u5206\u5e03\u7684\u60c5\u51b5\u4e0b\u4ecd\u7136\u4fdd\u6301 O(n log n) \u7684\u6027\u80fd\uff0c\u800c\u4e0d\u4f1a\u51fa\u73b0\u6700\u574f\u60c5\u51b5\u3002 \u65e0\u8bba\u8f93\u5165\u6570\u636e\u5982\u4f55\u5206\u5e03\uff0c\u5f52\u5e76\u6392\u5e8f\u7684\u5206\u5272\u548c\u5408\u5e76\u64cd\u4f5c\u90fd\u662f\u786e\u5b9a\u6027\u7684\uff1a\u5f52\u5e76\u6392\u5e8f\u7684\u6bcf\u4e00\u6b65\u90fd\u662f\u786e\u5b9a\u6027\u7684\uff0c\u4e0d\u53d7\u8f93\u5165\u6570\u636e\u5206\u5e03\u7684\u5f71\u54cd\u3002\u4e0d\u50cf\u5feb\u901f\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u53ef\u80fd\u51fa\u73b0\u5206\u5272\u6781\u4e0d\u5e73\u8861\u7684\u60c5\u51b5\uff0c\u5bfc\u81f4\u6027\u80fd\u4e0b\u964d\u3002 \u56e0\u6b64\uff0c\u5f52\u5e76\u6392\u5e8f\u5728\u6700\u574f\u60c5\u51b5\u4e0b\u4ecd\u7136\u80fd\u591f\u4fdd\u6301 O(n log n) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\uff0c\u4f7f\u5176\u6210\u4e3a\u4e00\u79cd\u53ef\u9760\u7684\u6392\u5e8f\u7b97\u6cd5\uff0c\u7279\u522b\u9002\u7528\u4e8e\u5bf9\u7a33\u5b9a\u6027\u548c\u6027\u80fd\u6709\u8981\u6c42\u7684\u60c5\u51b5\u3002","title":"3.5.3.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/03_TimeComplexity/#36","text":"","title":"3.6.\u6307\u6570\u590d\u6742\u5ea6\u7684\u7b97\u6cd5"},{"location":"python/DataStructure/03_TimeComplexity/#_1","text":"\u4e0b\u9762\u662f\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7b97\u6cd5\u7684\u4f8b\u5b50\u3002 def fib ( n , depth = 0 ): \"\"\"\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u6570\u5217\"\"\" if n <= 1 : return 1 else : print ( f 'Depth: { depth } ,fib( { n } ) calls fib( { n - 1 } ) and fib( { n - 2 } )' ) return fib ( n - 1 , depth + 1 ) + fib ( n - 2 , depth + 1 ) def main (): fib ( 6 ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Depth:0,fib(6) calls fib(5) and fib(4) # Depth:1,fib(5) calls fib(4) and fib(3) # Depth:2,fib(4) calls fib(3) and fib(2) # Depth:3,fib(3) calls fib(2) and fib(1) # Depth:4,fib(2) calls fib(1) and fib(0) # Depth:3,fib(2) calls fib(1) and fib(0) # Depth:2,fib(3) calls fib(2) and fib(1) # Depth:3,fib(2) calls fib(1) and fib(0) # Depth:1,fib(4) calls fib(3) and fib(2) # Depth:2,fib(3) calls fib(2) and fib(1) # Depth:3,fib(2) calls fib(1) and fib(0) # Depth:2,fib(2) calls fib(1) and fib(0) \u4e0a\u4f8b\u53ef\u4ee5\u770b\u51fa\uff0c\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7b97\u6cd5\u7684\u8c03\u7528\u6b21\u6570\u6bd4\u95ee\u9898\u89c4\u6a21\u7684\u5e73\u65b9\u6570\u589e\u957f\u7684\u8fd8\u8981\u5feb\u5f88\u591a\u3002\u4f8b\u5982\uff0c fib(4) \u53ea\u9700\u89814\u6b21\u9012\u5f52\u8c03\u7528\uff0c\u770b\u8d77\u6765\u5b83\u597d\u50cf\u662f\u7ebf\u6027\u589e\u957f\u7684\uff0c\u4f46\u5728\u603b\u5171\u768414\u6b21\u9012\u5f52\u8c03\u7528\u91cc\uff0c fib(6) \u9700\u8981\u8c03\u75282\u6b21 fib(4) \u3002\u968f\u7740\u95ee\u9898\u89c4\u6a21\u7684\u6269\u5927\uff0c\u5de5\u4f5c\u91cf\u4f1a\u663e\u8457\u589e\u52a0\uff0c\u8fd9\u662f\u56e0\u4e3a\u5728\u8c03\u7528\u6811\uff08call tree\uff09\u91cc\u53ef\u80fd\u6709\u5f88\u591a\u91cd\u590d\u7684\u76f8\u540c\u5b50\u6811\u3002 \u5982\u679c\u8fd9\u68f5\u8c03\u7528\u6811\u662f\u5b8c\u5168\u5e73\u8861\u7684\uff0c\u5e76\u4e14\u5b8c\u5168\u586b\u5145\u4e86\u6700\u4e0b\u9762\u7684\u4e24\u5c42\u8c03\u7528\uff0c\u90a3\u4e48\u5f53\u53c2\u6570\u4e3a6\u65f6\uff0c\u4f1a\u67092 + 4 + 8 + 16 = 30\u6b21\u9012\u5f52\u8c03\u7528\u3002\u6bcf\u4e00\u5c42\u91cc\u7684\u6ee1\u8c03\u7528\u6570\u91cf\u90fd\u662f\u5b83\u4e0a\u4e00\u5c42\u76842\u500d\u3002\u56e0\u6b64\uff0c\u5728\u5b8c\u5168\u5e73\u8861\u7684\u8c03\u7528\u6811\u91cc\uff0c\u9012\u5f52\u8c03\u7528\u7684\u603b\u6570\u91cf\u901a\u5e38\u662f 2^(n+1)-2 \uff0c\u5176\u4e2d n \u662f\u8c03\u7528\u6811\u9876\u90e8\uff08\u6839\uff09\u7684\u53c2\u6570\u3002\u8fd9\u662f\u4e00\u4e2a\u6307\u6570\u7ea7\u7684\u589e\u957f\uff0c\u4e5f\u5c31\u662f O(k^n) \u7b97\u6cd5\u3002 \u5c3d\u7ba1\u5728\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u8c03\u7528\u6811\u7684\u5e95\u90e8\u4e24\u5c42\u5e76\u6ca1\u6709\u88ab\u5b8c\u5168\u586b\u5145\u6ee1\uff0c\u4f46\u5b83\u7684\u8c03\u7528\u6811\u5f62\u72b6\u548c\u5b8c\u5168\u5e73\u8861\u7684\u6811\u5df2\u7ecf\u8db3\u591f\u76f8\u8fd1\u4e86\uff0c\u56e0\u6b64\uff0c\u53ef\u4ee5\u628a\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u5f52\u4e3a\u6307\u6570\u7b97\u6cd5\u3002\u7ecf\u8fc7\u8ba1\u7b97\uff0c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u7684\u5e38\u6570 k \u5927\u7ea6\u662f1.63\u3002 \u6307\u6570\u7b97\u6cd5\u901a\u5e38\u53ea\u9002\u5408\u7528\u4e8e\u975e\u5e38\u5c0f\u7684\u95ee\u9898\u89c4\u6a21\u3002","title":"\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u7b97\u6cd5"},{"location":"python/DataStructure/03_TimeComplexity/#_2","text":"\u4e0b\u9762\u7684\u4ee3\u7801\u7528\u7ebf\u6027\u7b97\u6cd5\u6539\u5199\u4e86\u4e0a\u9762\u7684\u9012\u5f52\u7b97\u6cd5\u3002\u5b83\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\u3002 def fibonacci_linear ( n ): if n <= 1 : return 1 prev , current = 0 , 1 for _ in range ( 2 , n + 1 ): next_value = prev + current prev , current = current , next_value return current def main (): n = 6 result = fibonacci_linear ( n ) print ( f \"Fibonacci( { n } ) = { result } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Fibonacci(6) = 8","title":"\u5c06\u6590\u6ce2\u90a3\u5951\u8f6c\u6362\u4e3a\u7ebf\u6027\u7b97\u6cd5"},{"location":"python/DataStructure/03_TimeComplexity/#37","text":"\u76ee\u6807\uff1a\u7f16\u5199\u4e00\u4e2a\u53ef\u4ee5\u7528\u6765\u5206\u6790\u4e0d\u540c\u6392\u5e8f\u7b97\u6cd5\u7684\u7a0b\u5e8f\u3002 \u9700\u6c42\uff1a \u5206\u6790\u5668\u53ef\u4ee5\u8fd0\u884c\u6392\u5e8f\u7b97\u6cd5\u4ee5\u5bf9\u6570\u5b57\u5217\u8868\u8fdb\u884c\u6392\u5e8f\uff1b \u5206\u6790\u5668\u53ef\u4ee5\u8ffd\u8e2a\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u3001\u6bd4\u8f83\u6b21\u6570\u4ee5\u53ca\u6267\u884c\u4ea4\u6362\u7684\u6b21\u6570\uff1b \u5f53\u7b97\u6cd5\u4ea4\u6362\u4e24\u4e2a\u503c\u7684\u65f6\u5019\uff0c\u5206\u6790\u5668\u53ef\u4ee5\u6253\u5370\u51fa\u5217\u8868\u7684\u53d8\u5316\u8f68\u8ff9\uff1b \u5141\u8bb8\u7ed9\u5206\u6790\u5668\u63d0\u4f9b\u81ea\u5b9a\u4e49\u7684\u6570\u5b57\u5217\u8868\uff0c\u6216\u8005\u751f\u6210\u4e00\u4e2a\u5927\u5c0f\u7ed9\u5b9a\u7684\u968f\u673a\u6570\u5b57\u5217\u8868\uff1b\u5141\u8bb8\u5217\u8868\u53ea\u5305\u542b\u4e00\u4e2a\u6570\u5b57\uff0c\u6216\u8005\u5305\u542b\u91cd\u590d\u6570\u503c\uff1b \u5728\u8fd0\u884c\u7b97\u6cd5\u4e4b\u524d\uff0c\u5141\u8bb8\u7528\u6237\u9009\u62e9\u4e0a\u8ff0\u8fd9\u4e9b\u529f\u80fd\uff1b \u5206\u6790\u5668\u7684\u9ed8\u8ba4\u884c\u4e3a\u662f\u5728\u4e00\u4e2a\u5305\u542b10\u4e2a\u4e0d\u91cd\u590d\u6570\u5b57\u7684\u968f\u673a\u5217\u8868\u4e0a\u8fd0\u884c\u7b97\u6cd5\uff0c\u5e76\u8bb0\u5f55\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u3001\u6bd4\u8f83\u6b21\u6570\u4ee5\u53ca\u4ea4\u6362\u6b21\u6570\uff1b \u5b9e\u73b0\uff1a \u5206\u6790\u5668\u662f Profiler \u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\u3002\u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u8fd0\u884c\u5206\u6790\u5668\u91cc\u7684 test \u65b9\u6cd5\u6765\u5206\u6790\u6392\u5e8f\u51fd\u6570\uff0c\u8fd9\u4e2a\u6392\u5e8f\u51fd\u6570\u4f1a\u4f5c\u4e3a\u65b9\u6cd5\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\uff0c\u4e0a\u9762\u9700\u6c42\u4e2d\u63d0\u5230\u7684\u90a3\u4e9b\u9009\u9879\u4e5f\u4f1a\u4f5c\u4e3a\u53c2\u6570\u540c\u65f6\u4f20\u9012\u7ed9\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u4e24\u4e2a\u6a21\u5757\uff1a profiler \uff1a\u8fd9\u4e2a\u6a21\u5757\u4f1a\u5b9a\u4e49 Profiler \u7c7b\u3002 algorithms \uff1a\u8fd9\u4e2a\u6a21\u5757\u5b9a\u4e49\u9488\u5bf9\u5206\u6790\u5668\u4fee\u6539\u8fc7\u7684\u6392\u5e8f\u51fd\u6570\u3002 import time import random class Profiler ( object ): \"\"\" \u5b9a\u4e49\u4e00\u4e2aProfiler\u7c7b, \u7528\u6765\u5206\u6790\u6392\u5e8f\u7b97\u6cd5\u3002 Profiler\u5bf9\u8c61\u8ddf\u8e2a\u4e00\u4e2a\u5217\u8868\u7684\u6bd4\u8f83\u6b21\u6570\u3001\u4ea4\u6362\u6b21\u6570\u3001\u548c\u8fd0\u884c\u65f6\u95f4\u3002 Profiler\u5bf9\u8c61\u4e5f\u80fd\u8f93\u51fa\u4e0a\u8ff0\u8ffd\u8e2a\u4fe1\u606f, \u5e76\u521b\u5efa\u4e00\u4e2a\u542b\u6709\u91cd\u590d\u6216\u4e0d\u91cd\u590d\u6570\u5b57\u7684\u5217\u8868\u3002 \u793a\u4f8b\uff1a from profiler import Profiler from algorithms import selectionSort p = Profiler() p.test(selectionSort, size = 15, comp = True, exch = True, trace = True) \"\"\" def test ( self , function , lyst = None , size = 10 , unique = True , comp = True , exch = True , trace = False ): \"\"\" function: \u914d\u7f6e\u7684\u7b97\u6cd5 target: \u914d\u7f6e\u7684\u641c\u7d22\u76ee\u6807 lyst: \u5141\u8bb8\u8c03\u7528\u8005\u4f7f\u7528\u7684\u5217\u8868 size: \u5217\u8868\u7684\u5927\u5c0f, \u9ed8\u8ba4\u503c\u662f10 unique: \u5982\u679c\u662fTrue, \u5219\u5217\u8868\u5305\u542b\u4e0d\u91cd\u590d\u7684\u6574\u6570 comp: \u5982\u679c\u662fTrue, \u5219\u7edf\u8ba1\u6bd4\u8f83\u6b21\u6570 exch: \u5982\u679c\u662fTrue, \u5219\u7edf\u8ba1\u4ea4\u6362\u6b21\u6570 trace: \u5982\u679c\u662fTrue, \u5219\u5728\u6bcf\u6b21\u4ea4\u6362\u540e\u90fd\u8f93\u51fa\u5217\u8868\u5185\u5bb9 \u6b64\u51fd\u6570\u4f9d\u636e\u7ed9\u5b9a\u7684\u4e0a\u8ff0\u5c5e\u6027, \u6253\u5370\u8f93\u51fa\u76f8\u5e94\u7684\u7ed3\u679c \"\"\" self . comp = comp self . exch = exch self . trace = trace if lyst != None : self . lyst = lyst elif unique : self . lyst = list ( range ( 1 , size + 1 )) random . shuffle ( self . lyst ) else : self . lyst = [] for count in range ( size ): self . lyst . append ( random . randint ( 1 , size )) self . exchCount = 0 self . cmpCount = 0 self . startClock () function ( self . lyst , self ) self . stopClock () print ( self ) def exchange ( self ): \"\"\"\u7edf\u8ba1\u4ea4\u6362\u6b21\u6570\"\"\" if self . exch : self . exchCount += 1 if self . trace : print ( self . lyst ) def comparison ( self ): \"\"\"\u7edf\u8ba1\u4ea4\u6362\u6b21\u6570\"\"\" if self . comp : self . cmpCount += 1 def startClock ( self ): \"\"\"\u8bb0\u5f55\u5f00\u59cb\u65f6\u95f4\"\"\" self . start = time . time () def stopClock ( self ): \"\"\"\u505c\u6b62\u8ba1\u65f6\u5e76\u4ee5\u79d2\u4e3a\u5355\u4f4d\u8ba1\u7b97\u6d88\u8017\u65f6\u95f4\"\"\" self . elapsedTime = round ( time . time () - self . start , 3 ) def __str__ ( self ): \"\"\"\u4ee5\u5b57\u7b26\u4e32\u65b9\u5f0f\u8fd4\u56de\u7ed3\u679c\"\"\" result = \"Problem size: \" result += str ( len ( self . lyst )) + \" \\n \" result += \"Elapsed time: \" result += str ( self . elapsedTime ) + \" \\n \" if self . comp : result += \"Comparisons: \" result += str ( self . cmpCount ) + \" \\n \" if self . exch : result += \"Exchanges: \" result += str ( self . exchCount ) + \" \\n \" return result def selectionSort ( lyst , profiler ): i = 0 while i < len ( lyst ) - 1 : minIndex = i j = i + 1 while j < len ( lyst ): profiler . comparison () # Count if lyst [ j ] < lyst [ minIndex ]: minIndex = j j += 1 if minIndex != i : swap ( lyst , minIndex , i , profiler ) i += 1 def swap ( lyst , i , j , profiler ): \"\"\"\u4ea4\u6362\u5904\u4e8e\u4f4d\u7f6ei\u548cj\u7684\u5143\u7d20\"\"\" profiler . exchange () # Count temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def main (): p = Profiler () # \u9ed8\u8ba4\u884c\u4e3a print ( \"The result of p.test(selectionSort)\" ) p . test ( selectionSort ) print ( \"The result of p.test(selectionSort, size=5, trace=True)\" ) p . test ( selectionSort , size = 5 , trace = True ) print ( \"The result of p.test(selectionSort, size=100)\" ) p . test ( selectionSort , size = 100 ) print ( \"The result of p.test(selectionSort, size=1000)\" ) p . test ( selectionSort , size = 1000 ) print ( \"The result of p.test(selectionSort, size=10000, exch=False, comp=False)\" ) p . test ( selectionSort , size = 10000 , exch = False , comp = False ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # The result of p.test(selectionSort) # Problem size: 20 # Elapsed time: 0.0 # Comparisons: 190 # Exchanges: 12 # The result of p.test(selectionSort, size=5, trace=True) # [5, 1, 4, 3, 2, 1, 1, 2, 4, 4] # [1, 5, 4, 3, 2, 1, 1, 2, 4, 4] # [1, 1, 4, 3, 2, 5, 1, 2, 4, 4] # [1, 1, 1, 3, 2, 5, 4, 2, 4, 4] # [1, 1, 1, 2, 3, 5, 4, 2, 4, 4] # [1, 1, 1, 2, 2, 5, 4, 3, 4, 4] # [1, 1, 1, 2, 2, 3, 4, 5, 4, 4] # [1, 1, 1, 2, 2, 3, 4, 4, 5, 4] # Problem size: 10 # Elapsed time: 0.0 # Comparisons: 45 # Exchanges: 8 # The result of p.test(selectionSort, size=100) # Problem size: 200 # Elapsed time: 0.003 # Comparisons: 19900 # Exchanges: 195 # The result of p.test(selectionSort, size=1000) # Problem size: 2000 # Elapsed time: 0.36 # Comparisons: 1999000 # Exchanges: 1992 # The result of p.test(selectionSort, size=10000, exch=False, comp=False) # Problem size: 20000 # Elapsed time: 26.535","title":"3.7.\u6848\u4f8b\u7814\u7a76:\u7b97\u6cd5\u5206\u6790\u5668"},{"location":"python/DataStructure/03_TimeComplexity/#38","text":"\u6839\u636e\u6240\u9700\u8981\u7684\u65f6\u95f4\u548c\u5185\u5b58\u8d44\u6e90\uff0c\u6211\u4eec\u53ef\u4ee5\u5bf9\u89e3\u51b3\u540c\u4e00\u4e2a\u95ee\u9898\u7684\u4e0d\u540c\u7b97\u6cd5\u8fdb\u884c\u6392\u540d\u3002\u4e0e\u9700\u8981\u66f4\u591a\u8d44\u6e90\u7684\u7b97\u6cd5\u76f8\u6bd4\uff0c\u6211\u4eec\u901a\u5e38\u8ba4\u4e3a\u8017\u8d39\u66f4\u5c11\u8fd0\u884c\u65f6\u548c\u5360\u7528\u66f4\u5c11\u5185\u5b58\u7684\u7b97\u6cd5\u66f4\u597d\u3002\u4f46\u662f\uff0c\u8fd9\u4e24\u79cd\u8d44\u6e90\u4e5f\u901a\u5e38\u9700\u8981\u8fdb\u884c\u6743\u8861\u53d6\u820d\uff1a\u6709\u65f6\u4ee5\u66f4\u591a\u5185\u5b58\u4e3a\u4ee3\u4ef7\u6765\u6539\u5584\u8fd0\u884c\u65f6\uff1b\u6709\u65f6\u4ee5\u8f83\u6162\u7684\u8fd0\u884c\u65f6\u4f5c\u4e3a\u4ee3\u4ef7\u6765\u63d0\u9ad8\u5185\u5b58\u7684\u4f7f\u7528\u7387\u3002 \u53ef\u4ee5\u6839\u636e\u8ba1\u7b97\u673a\u7684\u65f6\u949f\u6309\u7167\u8fc7\u5f80\u7ecf\u9a8c\u6d4b\u7b97\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u3002\u4f46\u662f\uff0c\u8fd9\u4e2a\u65f6\u95f4\u4f1a\u968f\u7740\u786c\u4ef6\u548c\u6240\u7528\u7f16\u7a0b\u8bed\u8a00\u7684\u4e0d\u540c\u800c\u53d8\u5316\u3002 \u7edf\u8ba1\u6307\u4ee4\u7684\u6570\u91cf\u63d0\u4f9b\u4e86\u53e6\u4e00\u79cd\u5bf9\u7b97\u6cd5\u6240\u9700\u5de5\u4f5c\u91cf\u8fdb\u884c\u7ecf\u9a8c\u6027\u5ea6\u91cf\u7684\u65b9\u5f0f\u3002\u6307\u4ee4\u7684\u8ba1\u6570\u53ef\u4ee5\u663e\u793a\u51fa\u7b97\u6cd5\u5de5\u4f5c\u91cf\u7684\u589e\u957f\u7387\u7684\u53d8\u5316\uff0c\u800c\u4e14\u8fd9\u4e2a\u6570\u636e\u548c\u786c\u4ef6\u4ee5\u53ca\u8f6f\u4ef6\u5e73\u53f0\u90fd\u6ca1\u6709\u5173\u7cfb\u3002 \u7b97\u6cd5\u5de5\u4f5c\u91cf\u7684\u589e\u957f\u7387\u53ef\u4ee5\u7528\u57fa\u4e8e\u95ee\u9898\u89c4\u6a21\u7684\u51fd\u6570\u6765\u8868\u793a\u3002\u590d\u6742\u5ea6\u5206\u6790\u67e5\u770b\u7b97\u6cd5\u91cc\u7684\u4ee3\u7801\u4ee5\u5f97\u5230\u8fd9\u4e9b\u6570\u5b66\u8868\u8fbe\u5f0f\uff0c\u4ece\u800c\u8ba9\u7a0b\u5e8f\u5458\u9884\u6d4b\u5728\u4efb\u4f55\u8ba1\u7b97\u673a\u4e0a\u6267\u884c\u8fd9\u4e2a\u7b97\u6cd5\u7684\u6548\u679c\u3002 \u5927O\u8868\u793a\u6cd5\u662f\u7528\u6765\u8868\u793a\u7b97\u6cd5\u8fd0\u884c\u65f6\u884c\u4e3a\u7684\u5e38\u7528\u65b9\u6cd5\u3002\u5b83\u7528 O(f(n)) \u7684\u5f62\u5f0f\u6765\u8868\u793a\u89e3\u51b3\u8fd9\u4e2a\u95ee\u9898\u6240\u9700\u8981\u7684\u5de5\u4f5c\u91cf\uff0c\u5176\u4e2d n \u662f\u7b97\u6cd5\u95ee\u9898\u7684\u89c4\u6a21\u3001 f(n) \u662f\u6570\u5b66\u51fd\u6570\u3002 \u8fd0\u884c\u65f6\u884c\u4e3a\u7684\u5e38\u89c1\u8868\u8fbe\u5f0f\u6709 O(log(n, 2)) \uff08\u5bf9\u6570\uff09\u3001 O(n) \uff08\u7ebf\u6027\uff09\u3001 O(n^2) \uff08\u5e73\u65b9\uff09\u4ee5\u53ca O(k^n) \uff08\u6307\u6570\uff09\u3002 \u7b97\u6cd5\u5728\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u6027\u80fd\u53ef\u4ee5\u662f\u4e0d\u540c\u7684\u3002\u6bd4\u5982\uff0c\u5192\u6ce1\u6392\u5e8f\u548c\u63d2\u5165\u6392\u5e8f\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u90fd\u662f\u7ebf\u6027\u590d\u6742\u5ea6\uff0c\u4f46\u662f\u5b83\u4eec\u5728\u5e73\u5747\u60c5\u51b5\u548c\u6700\u574f\u60c5\u51b5\u4e0b\u662f\u5e73\u65b9\u9636\u590d\u6742\u5ea6\u3002 \u901a\u5e38\u6765\u8bf4\uff0c\u8981\u63d0\u9ad8\u7b97\u6cd5\u7684\u6027\u80fd\u6700\u597d\u662f\u5c1d\u8bd5\u964d\u4f4e\u5b83\u7684\u8fd0\u884c\u65f6\u590d\u6742\u5ea6\u7684\u9636\u6570\uff0c\u800c\u4e0d\u662f\u5bf9\u4ee3\u7801\u8fdb\u884c\u5fae\u8c03\u3002 \u4e8c\u5206\u641c\u7d22\u4f1a\u6bd4\u987a\u5e8f\u641c\u7d22\u8981\u5feb\u5f97\u591a\u3002\u4f46\u662f\uff0c\u5728\u7528\u4e8c\u5206\u641c\u7d22\u8fdb\u884c\u641c\u7d22\u65f6\uff0c\u6570\u636e\u5fc5\u987b\u662f\u6709\u5e8f\u7684\u3002 nlogn \u6392\u5e8f\u7b97\u6cd5\u901a\u8fc7\u9012\u5f52\u3001\u5206\u6cbb\u6cd5\u7b56\u7565\u6765\u7a81\u7834 n^2 \u7684\u6027\u80fd\u969c\u788d\u3002\u5feb\u901f\u6392\u5e8f\u4f1a\u5728\u57fa\u51c6\u5143\u7d20\u5de6\u53f3\u5bf9\u5176\u4ed6\u5143\u7d20\u91cd\u65b0\u6392\u5217\uff0c\u7136\u540e\u5bf9\u57fa\u51c6\u4e24\u4fa7\u7684\u5b50\u5217\u8868\u9012\u5f52\u5730\u6392\u5e8f\u3002\u5f52\u5e76\u6392\u5e8f\u5219\u4f1a\u628a\u4e00\u4e2a\u5217\u8868\u8fdb\u884c\u62c6\u5206\uff0c\u9012\u5f52\u5730\u5bf9\u6bcf\u4e2a\u90e8\u5206\u8fdb\u884c\u6392\u5e8f\uff0c\u7136\u540e\u5408\u5e76\u51fa\u6700\u7ec8\u7ed3\u679c\u3002 \u6307\u6570\u590d\u6742\u5ea6\u7684\u7b97\u6cd5\u901a\u5e38\u53ea\u5728\u7406\u8bba\u4e0a\u88ab\u5173\u6ce8\uff0c\u5728\u5904\u7406\u5927\u578b\u95ee\u9898\u7684\u65f6\u5019\uff0c\u5b83\u4eec\u662f\u6ca1\u6709\u4f7f\u7528\u4ef7\u503c\u7684\u3002","title":"3.8.\u5c0f\u7ed3"},{"location":"python/DataStructure/03_TimeComplexity/#39","text":"\u5728\u4e0d\u540c\u95ee\u9898\u89c4\u6a21\u7684\u60c5\u51b5\u4e0b\u8bb0\u5f55\u7b97\u6cd5\u8fd0\u884c\u65f6\uff1a \u53ef\u4ee5\u8ba9\u4f60\u5927\u81f4\u4e86\u89e3\u7b97\u6cd5\u7684\u8fd0\u884c\u65f6\u884c\u4e3a \u53ef\u4ee5\u8ba9\u4f60\u4e86\u89e3\u7b97\u6cd5\u5728\u7279\u5b9a\u786c\u4ef6\u5e73\u53f0\u548c\u7279\u5b9a\u8f6f\u4ef6\u5e73\u53f0\u4e0a\u7684\u8fd0\u884c\u65f6\u884c\u4e3a \u7edf\u8ba1\u6307\u4ee4\u7684\u6570\u91cf\u4f1a\uff1a \u5728\u4e0d\u540c\u7684\u786c\u4ef6\u548c\u8f6f\u4ef6\u5e73\u53f0\u4e0a\u5f97\u5230\u76f8\u540c\u7684\u6570\u636e \u53ef\u4ee5\u8bc1\u660e\u5728\u95ee\u9898\u89c4\u6a21\u5f88\u5927\u7684\u60c5\u51b5\u4e0b\uff0c\u6307\u6570\u7b97\u6cd5\u662f\u6ca1\u6cd5\u4f7f\u7528\u7684 \u8868\u8fbe\u5f0f O(n) \u3001 O(n^2) \u548c O(k^n) \u5206\u522b\u4ee3\u8868\u7684\u590d\u6742\u5ea6\u662f\uff1a \u6307\u6570\u3001\u7ebf\u6027\u548c\u5e73\u65b9 \u7ebf\u6027\u3001\u5e73\u65b9\u548c\u6307\u6570 \u5bf9\u6570\u3001\u7ebf\u6027\u548c\u5e73\u65b9 \u4e8c\u5206\u641c\u7d22\u9700\u8981\u5047\u5b9a\u6570\u636e\uff1a \u6ca1\u6709\u4efb\u4f55\u7279\u522b\u7684\u987a\u5e8f\u5173\u7cfb \u6709\u5e8f\u7684 \u9009\u62e9\u6392\u5e8f\u6700\u591a\u53ef\u4ee5\u6709\uff1a n^2 \u6b21\u6570\u636e\u5143\u7d20\u7684\u4ea4\u6362 n \u6b21\u6570\u636e\u5143\u7d20\u7684\u4ea4\u6362 \u63d2\u5165\u6392\u5e8f\u548c\u4fee\u6539\u540e\u7684\u5192\u6ce1\u6392\u5e8f\u5728\u6700\u597d\u60c5\u51b5\u4e0b\u662f\uff1a \u7ebf\u6027\u7684 \u5e73\u65b9\u7684 \u6307\u6570\u7684 \u6700\u597d\u60c5\u51b5\u3001\u5e73\u5747\u60c5\u51b5\u4ee5\u53ca\u6700\u574f\u60c5\u51b5\u4e0b\u590d\u6742\u5ea6\u90fd\u76f8\u540c\u7684\u7b97\u6cd5\u662f\uff1a \u987a\u5e8f\u641c\u7d22 \u9009\u62e9\u6392\u5e8f \u5feb\u901f\u6392\u5e8f \u4e00\u822c\u6765\u8bf4\uff0c\u4e0b\u9762\u54ea\u4e2a\u9009\u62e9\u66f4\u597d\uff1a \u8c03\u6574\u7b97\u6cd5\u4ece\u800c\u8282\u7701\u82e5\u5e72\u79d2\u7684\u8fd0\u884c\u65f6 \u9009\u62e9\u8ba1\u7b97\u590d\u6742\u5ea6\u66f4\u4f4e\u7684\u7b97\u6cd5 \u5bf9\u4e8e\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\uff1a \u95ee\u9898\u89c4\u6a21\u4e3a n \u7684\u65f6\u5019\uff0c\u6709 n^2 \u6b21\u9012\u5f52\u8c03\u7528 \u95ee\u9898\u89c4\u6a21\u4e3a n \u7684\u65f6\u5019\uff0c\u6709 2n \u6b21\u9012\u5f52\u8c03\u7528 \u5b8c\u5168\u586b\u5145\u7684\u4e8c\u53c9\u8c03\u7528\u6811\u91cc\u6bcf\u4e00\u5c42\uff1a \u8c03\u7528\u6b21\u6570\u662f\u4e0a\u4e00\u5c42\u8c03\u7528\u6b21\u6570\u76842\u500d \u4e0e\u4e0a\u4e00\u5c42\u76f8\u540c\u7684\u8c03\u7528\u6b21\u6570","title":"3.9.\u590d\u4e60\u9898"},{"location":"python/DataStructure/03_TimeComplexity/#310","text":"1\uff0e\u5bf9\u4e00\u4e2a\u6709\u5e8f\u5217\u8868\u8fdb\u884c\u987a\u5e8f\u641c\u7d22\uff0c\u5f53\u76ee\u6807\u5c0f\u4e8e\u6709\u5e8f\u5217\u8868\u91cc\u7684\u67d0\u4e2a\u5143\u7d20\u65f6\uff0c\u987a\u5e8f\u641c\u7d22\u53ef\u4ee5\u63d0\u524d\u505c\u6b62\u3002\u5b9a\u4e49\u8fd9\u4e2a\u7b97\u6cd5\u7684\u4fee\u6539\u7248\u672c\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u6765\u63cf\u8ff0\u5b83\u5728\u6700\u597d\u60c5\u51b5\u3001\u6700\u574f\u60c5\u51b5\u4ee5\u53ca\u5e73\u5747\u60c5\u51b5\u4e0b\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 \u89e3\u7b54\uff1a \u5728\u6700\u597d\u7684\u60c5\u51b5\u4e0b\uff0c\u76ee\u6807\u5143\u7d20\u5728\u6709\u5e8f\u5217\u8868\u7684\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u51fd\u6570\u53ea\u9700\u8981\u8fdb\u884c\u4e00\u6b21\u6bd4\u8f83\u3002\u6240\u4ee5\uff0c\u6700\u4f73\u60c5\u51b5\u590d\u6742\u5ea6\u4e3a O(1) \u3002 \u5728\u6700\u574f\u7684\u60c5\u51b5\u4e0b\uff0c\u76ee\u6807\u5143\u7d20\u4e0d\u5728\u5217\u8868\u4e2d\uff0c\u5e76\u4e14\u6240\u6709\u5217\u8868\u5143\u7d20\u90fd\u5c0f\u4e8e\u76ee\u6807\u5143\u7d20\u3002\u8fd9\u5c06\u5bfc\u81f4\u51fd\u6570\u904d\u5386\u6574\u4e2a\u5217\u8868\uff0c\u6240\u4ee5\u6700\u574f\u60c5\u51b5\u590d\u6742\u5ea6\u4e3a O(n) \u3002 \u5bf9\u4e8e\u5e73\u5747\u60c5\u51b5\uff0c\u5047\u8bbe\u6709 n \u4e2a\u9879\u5728\u5217\u8868\u4e2d\uff0c\u641c\u7d22\u76ee\u6807\u4f1a\u5728\u5217\u8868\u524d n/2 \u4e2a\u9879\u6216\u8005\u4e0d\u5728\u6240\u6709\u3002\u5728\u8fd9\u4e2a\u7ea6\u5b9a\u4e0b\uff0c\u5e73\u5747\u6211\u4eec\u9700\u8981\u5bfb\u627e n/2 \u4e2a\u9879\uff0c\u56e0\u6b64\u590d\u6742\u5ea6\u4e3a O(n) \u3002\u4e4b\u6240\u4ee5\u662f n/2 \uff0c\u662f\u56e0\u4e3a\u8fd9\u4e2a\u4efb\u52a1\u53ef\u80fd\u4f1a\u5728\u4efb\u4f55\u5730\u65b9\u88ab\u505c\u6b62\uff0c\u6211\u4eec\u5bf9\u6b64\u505a\u5e73\u5747\u5904\u7406\u3002\u7136\u800c\u5728\u5927O\u6807\u8bb0\u6cd5\u4e2d\uff0c\u5e38\u6570\u5c06\u88ab\u9057\u5fd8\uff0c\u6240\u4ee5\u5b83\u4ecd\u7136\u662f O(n) \u3002 \u4ee3\u7801\u5982\u4e0b\uff1a def ordered_sequential_search ( arr , target ): comparisons = 0 # \u7528\u4e8e\u7edf\u8ba1\u6bd4\u8f83\u6b21\u6570 index = 0 while index < len ( arr ): comparisons += 1 if arr [ index ] == target : return comparisons , index # \u627e\u5230\u76ee\u6807\u5e76\u8fd4\u56de\u6bd4\u8f83\u6b21\u6570\u548c\u7d22\u5f15 elif arr [ index ] > target : break # \u5982\u679c\u76ee\u6807\u5c0f\u4e8e\u5f53\u524d\u5143\u7d20\uff0c\u63d0\u524d\u505c\u6b62\u641c\u7d22 index += 1 return comparisons , - 1 # \u6ca1\u627e\u5230\u76ee\u6807\u8fd4\u56de\u6bd4\u8f83\u6b21\u6570\u548c-1 def main (): # \u6d4b\u8bd5 arr = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] for target in [ 5 , 11 ]: comparisons , index = ordered_sequential_search ( arr , target ) if index != - 1 : print ( f \"\u76ee\u6807 { target } \u5728\u7d22\u5f15 { index } \u5904\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a { comparisons } \" ) else : print ( f \"\u76ee\u6807 { target } \u672a\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a { comparisons } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # \u76ee\u6807 5 \u5728\u7d22\u5f15 4 \u5904\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a 5 # \u76ee\u6807 11 \u672a\u627e\u5230\uff0c\u6bd4\u8f83\u6b21\u6570\u4e3a 10 2\uff0e\u5217\u8868\u7684 reverse \u65b9\u6cd5\u7528\u6765\u53cd\u8f6c\u5217\u8868\u91cc\u7684\u5143\u7d20\u3002\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c reverse \u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u53ef\u4ee5\u5728\u4e0d\u4f7f\u7528 reverse \u65b9\u6cd5\u7684\u60c5\u51b5\u4e0b\uff0c\u53cd\u8f6c\u5217\u8868\u53c2\u6570\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u5c1d\u8bd5\u8ba9\u8fd9\u4e2a\u51fd\u6570\u5c3d\u53ef\u80fd\u5730\u9ad8\u6548\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 \u89e3\u7b54\uff1a \u53ea\u9700\u8981\u904d\u5386\u5217\u8868\u7684\u4e00\u534a\uff0c\u6211\u4eec\u5c31\u80fd\u5230\u8fbe\u5217\u8868\u7684\u4e2d\u95f4\u4f4d\u7f6e\u628a\u5217\u8868\u4e24\u8fb9\u7684\u5143\u7d20\u4e92\u6362\uff0c\u8fd9\u6837\u5c31\u5b8c\u6210\u4e86\u5217\u8868\u7684\u53cd\u8f6c\u3002 \u8fd9\u4e2a\u7b97\u6cd5\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n/2) \uff0c\u5176\u4e2d n \u662f\u5217\u8868\u7684\u957f\u5ea6\u3002\u4f46\u5728\u5927O\u8868\u793a\u6cd5\u4e2d\uff0c\u5e38\u6570\u88ab\u5ffd\u7565\uff0c\u56e0\u6b64\u8be5\u7b97\u6cd5\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002\u5728\u8fd9\u4e2a\u7b97\u6cd5\u4e2d\uff0c n \u5c31\u4ee3\u8868\u7740\u5217\u8868\u7684\u957f\u5ea6\u3002\u610f\u5473\u7740\u65f6\u95f4\u590d\u6742\u5ea6\u53d7\u5217\u8868\u957f\u5ea6\u7684\u5f71\u54cd\u3002\u5217\u8868\u957f\u5ea6\u6bcf\u589e\u52a0\u4e00\u6b21\uff0c\u6267\u884c\u53cd\u8f6c\u7684\u65f6\u95f4\u5c31\u589e\u52a0\u4e00\u6b21\u3002\u8fd9\u5c31\u662f O(n) \u7684\u6982\u5ff5\u3002 \u8fd9\u4e2a\u51fd\u6570\u7684\u7a7a\u95f4\u590d\u6742\u5ea6\u662f O(1) \uff0c\u56e0\u4e3a\u5b83\u53ea\u662f\u5728\u539f\u5730\u4fee\u6539\u5217\u8868\uff0c\u4e0d\u9700\u8981\u989d\u5916\u7684\u5b58\u50a8\u7a7a\u95f4\u3002 \u4ee3\u7801\u5982\u4e0b\uff1a def custom_reverse ( arr ): left , right = 0 , len ( arr ) - 1 while left < right : arr [ left ], arr [ right ] = arr [ right ], arr [ left ] left += 1 right -= 1 def main (): # \u6d4b\u8bd5\u5217\u8868reverse\u65b9\u6cd5 my_list = [ 1 , 2 , 3 , 4 , 5 ] my_list . reverse () print ( my_list ) # \u6d4b\u8bd5\u81ea\u5b9a\u4e49\u7684reverse\u65b9\u6cd5 my_list = [ 1 , 2 , 3 , 4 , 5 ] custom_reverse ( my_list ) print ( my_list ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # [5, 4, 3, 2, 1] # [5, 4, 3, 2, 1] 3\uff0ePython\u7684pow\u51fd\u6570\u4f1a\u8fd4\u56de\u6570\u5b57\u7279\u5b9a\u5e42\u6b21\u7684\u7ed3\u679c\u3002\u5b9a\u4e49\u6267\u884c\u8fd9\u4e2a\u4efb\u52a1\u7684expo\u51fd\u6570\uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002\u8fd9\u4e2a\u51fd\u6570\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u6570\u5b57\uff0c\u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u6307\u6570\uff08\u975e\u8d1f\u6570\uff09\u3002\u4f60\u53ef\u4ee5\u901a\u8fc7\u5faa\u73af\u6216\u9012\u5f52\u51fd\u6570\u6765\u5b9e\u73b0\uff0c\u4f46\u4e0d\u8981\u4f7f\u7528Python\u5185\u7f6e\u7684**\u8fd0\u7b97\u7b26\u6216\u662fpow\u51fd\u6570\u3002 \u89e3\u7b54\uff1a \u4e0b\u9762\u5b9e\u73b0\u7684 expo \u51fd\u6570\u4f7f\u7528\u5faa\u73af\u6765\u8fde\u7eed\u4e58\u4ee5 base \uff0c\u5faa\u73af\u7684\u6b21\u6570\u7b49\u4e8e exponent \u7684\u503c\u3002 \u65f6\u95f4\u590d\u6742\u5ea6\u662f O(exponent) \uff0c\u5176\u4e2d exponent \u662f\u6307\u6570\u7684\u503c\u3002 \u6700\u597d\u60c5\u51b5\uff1aO(exponent) \u6700\u574f\u60c5\u51b5\uff1aO(exponent) \u5e73\u5747\u60c5\u51b5\uff1aO(exponent) def expo ( base , exponent ): result = 1 for _ in range ( exponent ): result *= base return result def main (): # \u6d4b\u8bd5 base = 2 for exponent in [ 3 , - 3 ]: result = expo ( base , exponent ) print ( f \" { base } \u7684 { exponent } \u6b21\u65b9\u7b49\u4e8e { result } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # 2 \u7684 3 \u6b21\u65b9\u7b49\u4e8e 8 # 2 \u7684 -3 \u6b21\u65b9\u7b49\u4e8e 1 4\uff0e\u53e6\u4e00\u4e2a\u5b9e\u73b0 expo \u51fd\u6570\u7684\u7b56\u7565\u4f7f\u7528\u4e0b\u9762\u8fd9\u4e2a\u9012\u5f52\u3002\u8bf7\u5b9a\u4e49\u4f7f\u7528\u8fd9\u4e2a\u7b56\u7565\u7684\u9012\u5f52\u51fd\u6570 expo \uff0c\u5e76\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 expo ( number \uff0c exponent ) = 1 \uff0c \u5f53 exponent = 0 \u7684\u65f6\u5019 = number * expo ( number , exponent \u2212 1 ) \uff0c \u5f53exponent\u4e3a\u5947\u6570\u7684\u65f6\u5019 = ( expo ( number , exponent / 2 )) 2 \uff0c \u5f53exponent\u4e3a\u5076\u6570\u7684\u65f6\u5019 \u89e3\u7b54\uff1a \u4e0b\u9762\u5b9e\u73b0expo\u51fd\u6570\u662f\u901a\u8fc7\u9012\u5f52\u5b9e\u73b0\uff0c\u5e76\u91c7\u7528\u4e86\u5206\u800c\u6cbb\u4e4b\u7684\u7b56\u7565\u3002 \u5982\u679c\u6307\u6570\u662f\u5947\u6570\uff0c\u5c31\u628a\u95ee\u9898\u5206\u89e3\u4e3a\u4e00\u4e2a\u66f4\u5c0f\u7684\u7248\u672c\uff08\u5373 num * num^(exp - 1) \uff09\uff1b \u5982\u679c\u6307\u6570\u662f\u5076\u6570\uff0c\u5219\u53ef\u4ee5\u5c06\u6307\u6570\u5206\u6210\u4e24\u534a\uff0c\u5e76\u53ea\u8ba1\u7b97\u5176\u4e2d\u7684\u4e00\u534a\uff08\u5373 num^(exp / 2) * num^(exp / 2) \uff09\u3002 \u8fd9\u5c31\u5229\u7528\u4e86\u5e42\u7684\u6027\u8d28 a^(m * n) = (a^m)^n \u3002 \u8be5\u9012\u5f52\u5b9e\u73b0\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(log n) \uff0c\u5176\u4e2dn\u4e3a\u6307\u6570\u3002\u8fd9\u662f\u56e0\u4e3a\u5728\u6307\u6570\u4e3a\u5076\u6570\u7684\u60c5\u51b5\u4e0b\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u90fd\u4f1a\u628a\u95ee\u9898\u89c4\u6a21\u7f29\u5c0f\u4e00\u534a\uff0c\u7c7b\u4f3c\u4e8e\u4e8c\u5206\u67e5\u627e\u7b49\u8bfe\u5206\u5272\u95ee\u9898\u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\u4e5f\u662f O(log n) \uff0c\u8fd9\u4e3b\u8981\u662f\u7531\u4e8e\u51fd\u6570\u8c03\u7528\u6808\u7684\u6df1\u5ea6\u5728\u6307\u6570\u4e3a\u5076\u6570\u7684\u60c5\u51b5\u4e0b\uff0c\u4f1a\u53d8\u4e3a\u539f\u6765\u7684\u4e00\u534a\u3002 def expo ( number , exponent ): if exponent <= 0 : return 1 elif exponent % 2 == 1 : # \u5f53 exponent \u4e3a\u5947\u6570 return number * expo ( number , exponent - 1 ) else : # \u5f53 exponent \u4e3a\u5076\u6570 half_expo = expo ( number , exponent // 2 ) return half_expo * half_expo def main (): # \u6d4b\u8bd5 base = 2 for exponent in [ 3 , - 3 ]: result = expo ( base , exponent ) print ( f \" { base } \u7684 { exponent } \u6b21\u65b9\u7b49\u4e8e { result } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # 2 \u7684 3 \u6b21\u65b9\u7b49\u4e8e 8 # 2 \u7684 -3 \u6b21\u65b9\u7b49\u4e8e 1 5\uff0ePython\u4e2dlist\u91cc\u7684sort\u65b9\u6cd5\u5305\u542b\u4e00\u4e2a\u7528\u5173\u952e\u5b57\u547d\u540d\u7684\u53c2\u6570reverse\uff0c\u5b83\u7684\u9ed8\u8ba4\u503c\u4e3aFalse\u3002\u7a0b\u5e8f\u5458\u53ef\u4ee5\u901a\u8fc7\u8986\u76d6\u8fd9\u4e2a\u503c\u4ee5\u5bf9\u5217\u8868\u8fdb\u884c\u964d\u5e8f\u6392\u5e8f\u3002\u4fee\u6539\u672c\u7ae0\u8ba8\u8bba\u7684selectionSort\u51fd\u6570\uff0c\u4f7f\u5b83\u53ef\u4ee5\u63d0\u4f9b\u8fd9\u4e2a\u9644\u52a0\u53c2\u6570\u6765\u8ba9\u7a0b\u5e8f\u5458\u51b3\u5b9a\u6392\u5e8f\u7684\u65b9\u5411\u3002 \u89e3\u7b54\uff1a \u901a\u8fc7\u6dfb\u52a0\u4e00\u4e2a\u540d\u4e3a reverse \u7684\u53c2\u6570\u6765\u4fee\u6539 selectionSort \u51fd\u6570\uff0c\u4ee5\u4fbf\u8ba9\u7a0b\u5e8f\u5458\u51b3\u5b9a\u6392\u5e8f\u7684\u65b9\u5411\u3002\u5982\u679c reverse \u4e3a True \uff0c\u6392\u5e8f\u5c06\u662f\u964d\u5e8f\u7684\uff0c\u5982\u679c\u4e3a False \uff08\u9ed8\u8ba4\u503c\uff09\uff0c\u6392\u5e8f\u5c06\u662f\u5347\u5e8f\u7684\u3002 \u4e0b\u9762\u662f\u4fee\u6539\u540e\u7684 selectionSort \u51fd\u6570\uff1a def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def selectionSort ( lyst , reverse = False ): \"\"\"\u5b9e\u73b0\u4ea4\u6362\u6392\u5e8f\u7b97\u6cd5\uff0c\u53ef\u4ee5\u9009\u62e9\u5347\u5e8f\u6216\u964d\u5e8f\u6392\u5e8f\"\"\" i = 0 while i < len ( lyst ) - 1 : # \u5b9e\u73b0n-1\u6b21\u641c\u7d22 index = i # \u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\u4f4d\u7f6e j = i + 1 while j < len ( lyst ): # \u5411\u540e\u904d\u5386\u641c\u7d22\uff0c\u66f4\u65b0\u6700\u5c0f\u6216\u6700\u5927\u5143\u7d20\u4f4d\u7f6e if not reverse : if ( lyst [ j ] < lyst [ index ]): index = j else : if ( lyst [ j ] > lyst [ index ]): index = j j += 1 if index != i : # \u5982\u679c\u9700\u8981\uff0c\u5219\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e swap ( lyst , index , i ) i += 1 def main (): myList = [ 9 , 4 , 2 , 7 , 6 , 8 , 1 ] print ( \"Before selection sort \" , myList ) selectionSort ( myList ) print ( \"After selection sort \" , myList ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before selection sort [9, 4, 2, 7, 6, 8, 1] # After selection sort [1, 2, 4, 6, 7, 8, 9] 6\uff0e\u4fee\u6539\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\uff0c\u8ba9\u5b83\u652f\u6301\u672c\u7ae0\u91cc\u8ba8\u8bba\u8fc7\u7684\u8bb0\u5fc6\u5316\u6280\u672f\u3002\u8fd9\u4e2a\u51fd\u6570\u5e94\u6dfb\u52a0\u4e00\u4e2a\u5b57\u5178\u7c7b\u578b\u7684\u53c2\u6570\u3002\u5b83\u7684\u9876\u5c42\u8c03\u7528\u4f1a\u63a5\u6536\u4e00\u4e2a\u7a7a\u5b57\u5178\u4f5c\u4e3a\u53c2\u6570\uff0c\u8fd9\u4e2a\u5b57\u5178\u7684\u952e\u548c\u503c\u5e94\u8be5\u662f\u9012\u5f52\u8c03\u7528\u6240\u4f20\u9012\u7684\u53c2\u6570\u548c\u8ba1\u7b97\u51fa\u7684\u503c\u3002\u4e4b\u540e\uff0c\u7528\u672c\u7ae0\u8ba8\u8bba\u8fc7\u7684\u8ba1\u6570\u5668\u5bf9\u8c61\u5bf9\u9012\u5f52\u8c03\u7528\u7684\u6570\u91cf\u8fdb\u884c\u7edf\u8ba1\u3002 \u89e3\u7b54\uff1a \u4e0b\u9762\u662f\u4e00\u4e2a\u4fee\u6539\u540e\u7684\u7248\u672c\uff0c\u5b83\u4f7f\u7528\u4e00\u4e2a\u5b57\u5178\uff08\u7f13\u5b58\uff09\u6765\u5b58\u50a8\u5df2\u8ba1\u7b97\u7684\u7ed3\u679c\uff0c\u5e76\u4e14\u6dfb\u52a0\u4e86\u4e00\u4e2a\u8ba1\u6570\u5668\u5bf9\u8c61\u6765\u7edf\u8ba1\u9012\u5f52\u8c03\u7528\u6b21\u6570\u3002\u8fd9\u4e2a\u4ee3\u7801\u4f1a\u8f93\u51fa\u6307\u5b9a\u9879\u6570\u7684\u6590\u6ce2\u90a3\u5951\u6570\u4ee5\u53ca\u9012\u5f52\u8c03\u7528\u7684\u603b\u6b21\u6570\u3002\u8bb0\u5fc6\u5316\u6280\u672f\u53ef\u4ee5\u663e\u8457\u63d0\u9ad8\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u6027\u80fd\uff0c\u907f\u514d\u4e86\u91cd\u590d\u8ba1\u7b97\u3002 class Counter : def __init__ ( self ): self . count = 0 def increment ( self ): self . count += 1 def fib ( n , cache , counter ): \"\"\"\u6590\u6ce2\u90a3\u5951\u9012\u5f52\u6570\u5217\uff0c\u5e26\u6709\u8bb0\u5fc6\u5316\u548c\u8c03\u7528\u8ba1\u6570\u5668\"\"\" if n in cache : return cache [ n ] counter . increment () if n <= 1 : result = 1 else : result = fib ( n - 1 , cache , counter ) + fib ( n - 2 , cache , counter ) cache [ n ] = result return result def main (): n = 10 # \u4f60\u53ef\u4ee5\u8bbe\u7f6e\u4e0d\u540c\u7684\u6590\u6ce2\u90a3\u5951\u6570\u5217\u9879\u6570 cache = {} # \u7528\u4e8e\u7f13\u5b58\u5df2\u8ba1\u7b97\u7ed3\u679c\u7684\u5b57\u5178 counter = Counter () # \u7528\u4e8e\u8ba1\u6570\u9012\u5f52\u8c03\u7528\u6b21\u6570\u7684\u8ba1\u6570\u5668\u5bf9\u8c61 result = fib ( n , cache , counter ) print ( f \"Fibonacci( { n } ) = { result } \" ) print ( f \"Total recursive calls: { counter . count } \" ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Fibonacci(10) = 89 # Total recursive calls: 11 7\uff0e\u5206\u6790\u4e0a\u9762\u6590\u6ce2\u90a3\u5951\u6570\u5217\u91cc\u5b9a\u4e49\u7684\u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u6027\u80fd\uff0c\u7edf\u8ba1\u8fd9\u4e2a\u51fd\u6570\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u3002\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u5b83\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\uff0c\u5e76\u8bc1\u660e\u4f60\u7684\u7b54\u6848\u662f\u5408\u7406\u7684\u3002 \u89e3\u7b54\uff1a \u5728\u4e0a\u9762\u7684\u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u4e2d\uff0c\u6211\u4eec\u4f7f\u7528\u4e86\u8bb0\u5fc6\u5316\u6280\u672f\u6765\u907f\u514d\u91cd\u590d\u8ba1\u7b97\u3002\u8fd9\u79cd\u4f18\u5316\u4f1a\u663e\u8457\u51cf\u5c11\u8ba1\u7b97\u65f6\u95f4\uff0c\u56e0\u4e3a\u6bcf\u4e2a\u6590\u6ce2\u90a3\u5951\u6570\u53ea\u4f1a\u88ab\u8ba1\u7b97\u4e00\u6b21\u3002 \u8ba1\u7b97\u590d\u6742\u5ea6\u5206\u6790\uff1a \u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u662f O(n) \u3002\u8fd9\u662f\u56e0\u4e3a\u5b83\u9700\u8981\u8ba1\u7b97\u6590\u6ce2\u90a3\u5951\u6570\u5217\u7684\u524d n \u9879\uff0c\u6bcf\u4e00\u9879\u53ea\u9700\u8ba1\u7b97\u4e00\u6b21\uff0c\u7136\u540e\u5b58\u50a8\u5728\u7f13\u5b58\u4e2d\u3002\u56e0\u6b64\uff0c\u603b\u5171\u6267\u884c\u7684\u8ba1\u7b97\u91cf\u4e0e n \u6210\u6b63\u6bd4\uff0c\u5373 O(n) \u3002 \u9012\u5f52\u8c03\u7528\u6b21\u6570\uff1a \u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u53d6\u51b3\u4e8e\u8f93\u5165\u53c2\u6570 n \u3002\u5bf9\u4e8e\u6590\u6ce2\u90a3\u5951\u6570\u5217\uff0c\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u5927\u81f4\u7b49\u4e8e n \u3002\u56e0\u4e3a\u6bcf\u4e2a\u9879\u9700\u8981\u8ba1\u7b97\u4e00\u6b21\uff0c\u6240\u4ee5\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u4e0e\u8ba1\u7b97\u7684\u9879\u6570\u662f\u4e00\u81f4\u7684\u3002 \u6240\u4ee5\uff0c\u8fd9\u4e2a\u8bb0\u5fc6\u5316\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u662f O(n) \uff0c\u800c\u9012\u5f52\u8c03\u7528\u7684\u6b21\u6570\u4e5f\u5927\u81f4\u7b49\u4e8e n \u3002\u8fd9\u4e2a\u6027\u80fd\u662f\u76f8\u5bf9\u8f83\u597d\u7684\uff0c\u56e0\u4e3a\u5b83\u907f\u514d\u4e86\u6307\u6570\u7ea7\u522b\u7684\u91cd\u590d\u8ba1\u7b97\uff0c\u800c\u662f\u7ebf\u6027\u5730\u8ba1\u7b97\u6590\u6ce2\u90a3\u5951\u6570\u5217\u7684\u5404\u9879\u3002 8\uff0e\u51fd\u6570makeRandomList\u4f1a\u521b\u5efa\u5e76\u8fd4\u56de\u4e00\u4e2a\u7ed9\u5b9a\u5927\u5c0f\uff08\u5b83\u7684\u53c2\u6570\uff09\u7684\u6570\u5b57\u5217\u8868\u3002\u5217\u8868\u91cc\u7684\u6570\u5b57\u6ca1\u6709\u91cd\u590d\uff0c\u5b83\u4eec\u7684\u8303\u56f4\u4e3a1\uff5esize\uff0c\u4f4d\u7f6e\u662f\u968f\u673a\u7684\u3002\u4e0b\u9762\u662f\u8fd9\u4e2a\u51fd\u6570\u7684\u4ee3\u7801\u3002\u53ef\u4ee5\u5047\u5b9arange\u3001randint\u548cappend\u51fd\u6570\u90fd\u662f\u5e38\u6570\u65f6\u95f4\u7684\u590d\u6742\u5ea6\u3002\u8fd8\u53ef\u4ee5\u5047\u8bberandom.randint\u968f\u7740\u53c2\u6570\u4e4b\u95f4\u5dee\u503c\u7684\u589e\u52a0\u800c\u66f4\u5c11\u5730\u8fd4\u56de\u91cd\u590d\u7684\u6570\u5b57\u3002\u4f7f\u7528\u5927O\u8868\u793a\u6cd5\u63cf\u8ff0\u8fd9\u4e2a\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\uff0c\u5e76\u8bc1\u660e\u4f60\u7684\u7b54\u6848\u662f\u5408\u7406\u7684\u3002 def makeRandomList ( size ): lyst = [] for count in range ( size ): while True : number = random . randint ( 1 , size ) if not number in lyst : lyst . append ( number ) break return lyst \u89e3\u7b54\uff1a \u8fd9\u4e2a\u51fd\u6570\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u5b83\u7684\u5185\u90e8\u5faa\u73af\uff0c\u8be5\u5faa\u73af\u4f1a\u4e0d\u65ad\u751f\u6210\u968f\u673a\u6570\uff0c\u5e76\u68c0\u67e5\u5b83\u662f\u5426\u5df2\u7ecf\u5728\u5217\u8868 lyst \u4e2d\u3002\u5177\u4f53\u5206\u6790\u5982\u4e0b\uff1a \u521b\u5efa\u4e00\u4e2a\u7a7a\u5217\u8868 lyst \uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(1)\u3002 \u8fdb\u5165 for \u5faa\u73af\uff0c\u5faa\u73af\u6b21\u6570\u4e3a size \uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(size)\u3002 \u5728\u5185\u90e8 while \u5faa\u73af\u4e2d\uff0c\u751f\u6210\u4e00\u4e2a\u968f\u673a\u6570 number \uff0c\u6700\u574f\u60c5\u51b5\u4e0b\u9700\u8981\u751f\u6210 size \u6b21\u968f\u673a\u6570\u624d\u80fd\u627e\u5230\u4e00\u4e2a\u4e0d\u5728 lyst \u4e2d\u7684\u6570\u5b57\u3002\u8fd9\u90e8\u5206\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(size)\u3002 \u7efc\u4e0a\u6240\u8ff0\uff0c\u8fd9\u4e2a\u51fd\u6570\u7684\u603b\u4f53\u65f6\u95f4\u590d\u6742\u5ea6\u4e3a O(size^2)\u3002\u8fd9\u662f\u56e0\u4e3a\u5728\u6700\u574f\u60c5\u51b5\u4e0b\uff0c\u6bcf\u6b21\u751f\u6210\u7684\u968f\u673a\u6570\u90fd\u9700\u8981\u68c0\u67e5\u662f\u5426\u5728 lyst \u4e2d\uff0c\u800c\u968f\u673a\u6570\u7684\u751f\u6210\u53ef\u80fd\u9700\u8981\u591a\u6b21\u624d\u80fd\u751f\u6210\u4e00\u4e2a\u4e0d\u5728\u5217\u8868\u4e2d\u7684\u6570\u5b57\u3002 \u9700\u8981\u6ce8\u610f\u7684\u662f\uff0c\u968f\u7740 size \u7684\u589e\u52a0\uff0c\u5185\u90e8\u5faa\u73af\u7684\u8fed\u4ee3\u6b21\u6570\u4e5f\u4f1a\u589e\u52a0\uff0c\u5bfc\u81f4\u65f6\u95f4\u590d\u6742\u5ea6\u5448\u4e8c\u6b21\u589e\u957f\u3002\u56e0\u6b64\uff0c\u8fd9\u4e2a\u51fd\u6570\u7684\u6027\u80fd\u5728\u5927\u89c4\u6a21\u6570\u636e\u4e0a\u53ef\u80fd\u4f1a\u53d7\u5230\u9650\u5236\u3002\u5982\u679c\u9700\u8981\u66f4\u597d\u7684\u6027\u80fd\uff0c\u53ef\u4ee5\u8003\u8651\u5176\u4ed6\u7b97\u6cd5\uff0c\u4ee5\u907f\u514d\u91cd\u590d\u68c0\u67e5\u548c\u751f\u6210\u968f\u673a\u6570\u3002 import random def makeRandomList ( size ): lyst = [] for count in range ( size ): while True : number = random . randint ( 1 , size ) if not number in lyst : lyst . append ( number ) break print ( \"count=\" , count , \"list=\" , lyst ) return lyst def main (): print ( \"final list=\" , makeRandomList ( 10 )) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # count= 0 list= [2] # count= 1 list= [2, 10] # count= 2 list= [2, 10, 9] # count= 3 list= [2, 10, 9, 5] # count= 4 list= [2, 10, 9, 5, 3] # count= 5 list= [2, 10, 9, 5, 3, 4] # count= 6 list= [2, 10, 9, 5, 3, 4, 8] # count= 7 list= [2, 10, 9, 5, 3, 4, 8, 7] # count= 8 list= [2, 10, 9, 5, 3, 4, 8, 7, 6] # count= 9 list= [2, 10, 9, 5, 3, 4, 8, 7, 6, 1] # final list= [2, 10, 9, 5, 3, 4, 8, 7, 6, 1] 9\uff0e\u4fee\u6539quicksort\u51fd\u6570\uff0c\u8ba9\u5b83\u53ef\u4ee5\u5bf9\u4efb\u4f55\u5c3a\u5bf8\u5c0f\u4e8e50\u7684\u5b50\u5217\u8868\u8c03\u7528\u63d2\u5165\u6392\u5e8f\u3002\u4f7f\u7528\u670950\u3001500\u548c5000\u4e2a\u5143\u7d20\u7684\u6570\u636e\u96c6\u6bd4\u8f83\u8fd9\u4e2a\u7248\u672c\u4e0e\u539f\u59cb\u7248\u672c\u7684\u6027\u80fd\u3002\u7136\u540e\u8c03\u6574\u8fd9\u4e2a\u9608\u503c\uff0c\u4ece\u800c\u786e\u5b9a\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u7684\u6700\u4f73\u8bbe\u7f6e\u3002 \u89e3\u7b54\uff1a \u53ef\u4ee5\u5728 quicksortHelper \u51fd\u6570\u4e2d\u6dfb\u52a0\u4e00\u4e2a\u6761\u4ef6\uff0c\u68c0\u67e5\u5b50\u5217\u8868\u7684\u5927\u5c0f\u3002\u7136\u540e\u518d\u4fee\u6539 quicksort \u51fd\u6570\uff0c\u5b9e\u73b0\u5728\u5c0f\u4e8e50\u7684\u5b50\u5217\u8868\u4e0a\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u3002 \u5982\u679c\u5b50\u5217\u8868\u7684\u5927\u5c0f\u5c0f\u4e8e50\uff0c\u5c31\u4f7f\u7528\u63d2\u5165\u6392\u5e8f\u7b97\u6cd5\uff0c\u5426\u5219\u4f7f\u7528\u5feb\u901f\u6392\u5e8f\u7b97\u6cd5\u3002\u4e0b\u9762\u662f\u4fee\u6539\u540e\u7684\u4ee3\u7801\uff1a import random def swap ( lyst , i , j ): \"\"\"\u4ea4\u6362\u5143\u7d20\u4f4d\u7f6e\u4e3ai\u548cj\u7684\u5143\u7d20\"\"\" temp = lyst [ i ] lyst [ i ] = lyst [ j ] lyst [ j ] = temp def quicksort ( lyst ): quicksortHelper ( lyst , 0 , len ( lyst ) - 1 ) def quicksortHelper ( lyst , left , right ): if left < right : # \u68c0\u67e5\u5b50\u5217\u8868\u7684\u5927\u5c0f\u662f\u5426\u5c0f\u4e8e50 if right - left < 50 : # \u5982\u679c\u5c0f\u4e8e50\uff0c\u4f7f\u7528\u63d2\u5165\u6392\u5e8f insertionSort ( lyst , left , right ) else : pivotLocation = partition ( lyst , left , right ) quicksortHelper ( lyst , left , pivotLocation - 1 ) quicksortHelper ( lyst , pivotLocation + 1 , right ) def partition ( lyst , left , right ): \"\"\"\u5bf9\u5217\u8868\u8fdb\u884c\u5206\u533a\"\"\" # \u627e\u5230\u57fa\u51c6\u5143\u7d20\uff08pivot\uff09\uff0c\u5e76\u548c\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u4e92\u6362 middle = ( left + right ) // 2 pivot = lyst [ middle ] lyst [ middle ] = lyst [ right ] lyst [ right ] = pivot # \u8bbe\u5b9a\u8fb9\u754c\u5143\u7d20\uff08boundary point\uff09\uff0c\u521d\u59cb\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20 boundary = left print ( \"pivot: \" , pivot , \"boundary: \" , lyst [ boundary ]) # \u628a\u6240\u6709\u5c0f\u4e8e\u57fa\u51c6\u7684\u5143\u7d20\u90fd\u79fb\u52a8\u5230\u8fb9\u754c\u7684\u5de6\u8fb9 for index in range ( left , right ): if lyst [ index ] < pivot : swap ( lyst , index , boundary ) boundary += 1 # \u4ea4\u6362\u57fa\u51c6\u5143\u7d20\u548c\u8fb9\u754c\u5143\u7d20 swap ( lyst , right , boundary ) print ( lyst ) return boundary def insertionSort ( lyst , left , right ): \"\"\"\u63d2\u5165\u6392\u5e8f\u7b97\u6cd5\"\"\" for i in range ( left + 1 , right + 1 ): currentElement = lyst [ i ] j = i while j > left and currentElement < lyst [ j - 1 ]: lyst [ j ] = lyst [ j - 1 ] j -= 1 lyst [ j ] = currentElement def main ( size = 20 , sort = quicksort ): lyst = [ random . randint ( 1 , size ) for _ in range ( size )] print ( \"Before sorted\" , lyst ) sort ( lyst ) print ( \"After sorted\" , lyst ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c\uff1a # Before sorted [1, 3, 6, 14, 9, 6, 14, 15, 17, 13, 4, 3, 1, 13, 11, 16, 2, 4, 6, 2] # After sorted [1, 1, 2, 2, 3, 3, 4, 4, 6, 6, 6, 9, 11, 13, 13, 14, 14, 15, 16, 17] 10\uff0e\u8ba1\u7b97\u673a\u4f7f\u7528\u540d\u4e3a\u8c03\u7528\u6808\u7684\u7ed3\u6784\u6765\u4e3a\u9012\u5f52\u51fd\u6570\u7684\u8c03\u7528\u63d0\u4f9b\u652f\u6301\u3002\u4e00\u822c\u800c\u8a00\uff0c\u8ba1\u7b97\u673a\u4f1a\u4e3a\u51fd\u6570\u7684\u6bcf\u6b21\u8c03\u7528\u90fd\u4fdd\u7559\u4e00\u5b9a\u6570\u91cf\u7684\u5185\u5b58\u3002\u56e0\u6b64\uff0c\u53ef\u4ee5\u5bf9\u9012\u5f52\u51fd\u6570\u4f7f\u7528\u7684\u5185\u5b58\u6570\u91cf\u8fdb\u884c\u590d\u6742\u5ea6\u5206\u6790\u3002\u8bf7\u8bf4\u660e\u9012\u5f52\u9636\u4e58\u51fd\u6570\u548c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u4f7f\u7528\u7684\u5185\u5b58\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u3002 \u89e3\u7b54\uff1a \u9012\u5f52\u9636\u4e58\u51fd\u6570\u548c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u4f7f\u7528\u7684\u5185\u5b58\u7684\u8ba1\u7b97\u590d\u6742\u5ea6\u90fd\u4e0e\u9012\u5f52\u7684\u6df1\u5ea6\uff08\u9012\u5f52\u8c03\u7528\u7684\u5c42\u6570\uff09\u76f8\u5173\u3002\u9012\u5f52\u51fd\u6570\u6bcf\u6b21\u8c03\u7528\u90fd\u4f1a\u5728\u8c03\u7528\u6808\u4e2d\u5206\u914d\u4e00\u5b9a\u6570\u91cf\u7684\u5185\u5b58\uff0c\u5305\u62ec\u51fd\u6570\u7684\u53c2\u6570\u3001\u5c40\u90e8\u53d8\u91cf\u4ee5\u53ca\u8fd4\u56de\u5730\u5740\u7b49\u4fe1\u606f\u3002 \u9012\u5f52\u9636\u4e58\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\uff1a \u9012\u5f52\u9636\u4e58\u51fd\u6570\u662f\u4e00\u4e2a\u975e\u5e38\u7b80\u5355\u7684\u9012\u5f52\u51fd\u6570\uff0c\u5b83\u53ea\u9700\u8981\u4fdd\u5b58\u4e00\u4e2a\u6574\u6570\u53c2\u6570 n \u548c\u8fd4\u56de\u5730\u5740\u3002\u56e0\u6b64\uff0c\u5b83\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(1)\uff0c\u4e0e\u8f93\u5165\u53c2\u6570 n \u7684\u5927\u5c0f\u65e0\u5173\u3002\u6bcf\u4e2a\u9012\u5f52\u8c03\u7528\u90fd\u53ea\u9700\u8981\u5e38\u6570\u7ea7\u522b\u7684\u5185\u5b58\u7a7a\u95f4\u3002 \u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\uff1a \u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u9012\u5f52\u7684\u6df1\u5ea6\u3002\u6bcf\u4e2a\u9012\u5f52\u8c03\u7528\u90fd\u9700\u8981\u4fdd\u5b58\u4e24\u4e2a\u6574\u6570\u53c2\u6570 n \u548c depth \uff0c\u4ee5\u53ca\u8fd4\u56de\u5730\u5740\u3002\u56e0\u6b64\uff0c\u6bcf\u6b21\u9012\u5f52\u8c03\u7528\u9700\u8981\u7684\u5185\u5b58\u7a7a\u95f4\u662f\u5e38\u6570\u7ea7\u522b\u7684\u3002 \u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u9012\u5f52\u6df1\u5ea6\u53d6\u51b3\u4e8e\u8f93\u5165\u53c2\u6570 n \u3002\u5177\u4f53\u6765\u8bf4\uff0c\u9012\u5f52\u6df1\u5ea6\u7b49\u4e8e n \u3002\u56e0\u6b64\uff0c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(n)\uff0c\u4e0e\u8f93\u5165\u53c2\u6570 n \u6210\u6b63\u6bd4\u3002 \u603b\u7ed3\u6765\u8bf4\uff0c\u9012\u5f52\u9636\u4e58\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(1)\uff0c\u800c\u9012\u5f52\u6590\u6ce2\u90a3\u5951\u51fd\u6570\u7684\u5185\u5b58\u590d\u6742\u5ea6\u662f O(n)\u3002\u5728\u9012\u5f52\u7b97\u6cd5\u4e2d\uff0c\u5185\u5b58\u590d\u6742\u5ea6\u901a\u5e38\u4e0e\u9012\u5f52\u6df1\u5ea6\u6210\u6b63\u6bd4\uff0c\u56e0\u6b64\u9700\u8981\u8c28\u614e\u5904\u7406\u9012\u5f52\u8c03\u7528\uff0c\u4ee5\u907f\u514d\u51fa\u73b0\u6808\u6ea2\u51fa\u7b49\u95ee\u9898\u3002\u53ef\u4ee5\u4f7f\u7528\u8fed\u4ee3\u6216\u52a8\u6001\u89c4\u5212\u7b49\u65b9\u6cd5\u6765\u964d\u4f4e\u5185\u5b58\u6d88\u8017\u3002","title":"3.10.\u7f16\u7a0b\u7ec3\u4e60"},{"location":"python/DataStructure/04_ArrayChain/","text":"4.\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784 \u00b6 \u6570\u636e\u7ed3\u6784\uff08data structure\uff09\u6216\u5177\u4f53\u6570\u636e\u7c7b\u578b\uff08concrete data type\uff09\u662f\u6307\u4e00\u7ec4\u6570\u636e\u7684\u5185\u90e8\u5b58\u50a8\u65b9\u5f0f\u3002 \u6570\u7ec4\uff08array\uff09\u548c\u94fe\u63a5\u7ed3\u6784\uff08linked structure\uff09\u8fd9\u4e24\u79cd\u6570\u636e\u7ed3\u6784\u662f\u7f16\u7a0b\u8bed\u8a00\u91cc\u591a\u9879\u96c6\u6700\u5e38\u7528\u7684\u5b9e\u73b0\u3002 \u76ee\u6807\uff1a \u521b\u5efa\u6570\u7ec4\uff1b \u5bf9\u6570\u7ec4\u6267\u884c\u5404\u79cd\u64cd\u4f5c\uff1b \u786e\u5b9a\u6570\u7ec4\u76f8\u5173\u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u7684\u4f7f\u7528\u60c5\u51b5\uff1b \u57fa\u4e8e\u6570\u7ec4\u5728\u8ba1\u7b97\u673a\u5185\u5b58\u91cc\u7684\u4e0d\u540c\u5b58\u50a8\u65b9\u5f0f\uff0c\u63cf\u8ff0\u6570\u7ec4\u76f8\u5173\u64cd\u4f5c\u7684\u6210\u672c\u548c\u6536\u76ca\uff1b \u4f7f\u7528\u5355\u5411\u94fe\u63a5\u8282\u70b9\u521b\u5efa\u94fe\u63a5\u7ed3\u6784\uff1b \u5bf9\u7531\u5355\u5411\u94fe\u63a5\u8282\u70b9\u6784\u6210\u7684\u94fe\u63a5\u7ed3\u6784\u6267\u884c\u5404\u79cd\u64cd\u4f5c\uff1b \u57fa\u4e8e\u94fe\u63a5\u7ed3\u6784\u5728\u8ba1\u7b97\u673a\u5185\u5b58\u91cc\u7684\u4e0d\u540c\u5b58\u50a8\u65b9\u5f0f\uff0c\u63cf\u8ff0\u5728\u94fe\u63a5\u7ed3\u6784\u4e0a\u6267\u884c\u76f8\u5173\u64cd\u4f5c\u7684\u6210\u672c\u548c\u6536\u76ca\uff1b \u6bd4\u8f83\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784\u5728\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u4f7f\u7528\u4e0a\u7684\u6743\u8861\uff1b 4.1.\u6570\u7ec4\u6570\u636e\u7ed3\u6784 \u00b6 \u5173\u4e8e\u6570\u7ec4\uff08array\uff09\uff1a \u6570\u7ec4\u662f\u6307\u5728\u7ed9\u5b9a\u7d22\u5f15\u4f4d\u7f6e\u53ef\u4ee5\u8bbf\u95ee\u548c\u66ff\u6362\u7684\u5143\u7d20\u5e8f\u5217\u3002 Python\u5217\u8868\u7684\u5e95\u5c42\u6570\u636e\u7ed3\u6784\u6b63\u662f\u4e00\u4e2a\u6570\u7ec4\u3002 Python\u4e2d\u6570\u7ec4\u7684\u9650\u5236\u8981\u6bd4\u5217\u8868\u66f4\u591a\u3002\u53ea\u80fd\u5728\u6307\u5b9a\u4f4d\u7f6e\u8bbf\u95ee\u548c\u66ff\u6362\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u3001\u68c0\u67e5\u6570\u7ec4\u7684\u957f\u5ea6\u3001\u83b7\u53d6\u5b83\u7684\u5b57\u7b26\u4e32\u8868\u8fbe\u5f0f\uff1b\u4e0d\u80fd\u57fa\u4e8e\u4f4d\u7f6e\u6dfb\u52a0\u6216\u5220\u9664\u5143\u7d20\uff1b\u6570\u7ec4\u7684\u957f\u5ea6\u4e5f\u5c31\u662f\u5b83\u7684\u5bb9\u91cf\uff0c\u5728\u521b\u5efa\u4e4b\u540e\u5c31\u662f\u56fa\u5b9a\u7684\u3002 4.1.1.\u968f\u673a\u8bbf\u95ee\u548c\u8fde\u7eed\u5185\u5b58 \u00b6 \u901a\u8fc7\u4e0b\u6807\u64cd\u4f5c\u6216\u7d22\u5f15\u64cd\u4f5c\u5b9e\u73b0\u5bf9\u6570\u7ec4\u5728\u6307\u5b9a\u4f4d\u7f6e\u5bf9\u5143\u7d20\u8fdb\u884c\u5b58\u50a8\u6216\u68c0\u7d22\u3002 \u6570\u7ec4\u7d22\u5f15\u662f\u968f\u673a\u8bbf\u95ee\uff08random access\uff09\u64cd\u4f5c\uff0c\u800c\u5728\u968f\u673a\u8bbf\u95ee\u65f6\uff0c\u8ba1\u7b97\u673a\u603b\u4f1a\u6267\u884c\u56fa\u5b9a\u7684\u6b65\u9aa4\u6765\u83b7\u53d6\u7b2c i \u4e2a\u5143\u7d20\u7684\u4f4d\u7f6e\u3002\u56e0\u6b64\uff0c\u4e0d\u8bba\u6570\u7ec4\u6709\u591a\u5927\uff0c\u8bbf\u95ee\u7b2c\u4e00\u4e2a\u5143\u7d20\u6240\u9700\u7684\u65f6\u95f4\u548c\u8bbf\u95ee\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u6240\u9700\u8981\u7684\u65f6\u95f4\u90fd\u662f\u76f8\u540c\u7684\u3002 \u8ba1\u7b97\u673a\u901a\u8fc7\u5206\u914d\u4e00\u5757\u8fde\u7eed\u5185\u5b58\uff08contiguous memory\uff09\u5355\u5143\u6765\u5b58\u50a8\u6570\u7ec4\u91cc\u7684\u5143\u7d20\uff0c\u4ece\u800c\u652f\u6301\u5bf9\u6570\u7ec4\u7684\u968f\u673a\u8bbf\u95ee\u3002 \u7531\u4e8e\u6570\u7ec4\u91cc\u7684\u5143\u7d20\u5730\u5740\u90fd\u662f\u6309\u7167\u6570\u5b57\u987a\u5e8f\u8fdb\u884c\u6392\u5217\u7684\uff0c\u56e0\u6b64\u53ef\u4ee5\u901a\u8fc7\u6dfb\u52a0\u4e24\u4e2a\u503c\u6765\u8ba1\u7b97\u51fa\u6570\u7ec4\u5143\u7d20\u7684\u673a\u5668\u5730\u5740\uff0c\u5b83\u4eec\u662f\u6570\u7ec4\u7684\u57fa\u5730\u5740\uff08base address\uff09\u4ee5\u53ca\u5143\u7d20\u7684\u504f\u79fb\u91cf\uff08offset\uff09\u3002\u5176\u4e2d\uff0c\u6570\u7ec4\u7684\u57fa\u5730\u5740\u5c31\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20\u7684\u673a\u5668\u5730\u5740\uff0c\u800c\u5143\u7d20\u7684\u504f\u79fb\u91cf\u5c31\u662f\u5b83\u7684\u7d22\u5f15\u503c\u518d\u4e58\u4ee5\u4e00\u4e2a\u4ee3\u8868\u6570\u7ec4\u5143\u7d20\u6240\u9700\u5185\u5b58\u5355\u5143\u6570\u7684\u5e38\u91cf\uff08\u5728Python\u91cc\uff0c\u8fd9\u4e2a\u503c\u59cb\u7ec8\u662f1\uff09\u3002 \u7b80\u800c\u8a00\u4e4b\uff0cPython\u6570\u7ec4\u91cc\u7684\u7d22\u5f15\u64cd\u4f5c\u5305\u62ec\u4e0b\u9762\u4e24\u4e2a\u6b65\u9aa4\uff1a \u5f97\u5230\u6570\u7ec4\u5185\u5b58\u5757\u7684\u57fa\u5730\u5740\u3002 \u5c06\u7d22\u5f15\u503c\u6dfb\u52a0\u5230\u8fd9\u4e2a\u5730\u5740\u5e76\u8fd4\u56de\u3002 4.1.2.\u9759\u6001\u5185\u5b58\u548c\u52a8\u6001\u5185\u5b58 \u00b6 \u5728\u6bd4\u8f83\u8001\u7684\u7f16\u7a0b\u8bed\u8a00\uff08\u5982FORTRAN\u6216Pascal\uff09\u91cc\uff0c\u6570\u7ec4\u662f\u9759\u6001\u6570\u636e\u7ed3\u6784\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u7684\u957f\u5ea6\u6216\u5bb9\u91cf\u5728\u7f16\u8bd1\u65f6\u5c31\u786e\u5b9a\u4e86\uff0c\u7a0b\u5e8f\u5458\u9700\u8981\u7533\u8bf7\u8db3\u591f\u591a\u7684\u5185\u5b58\u6765\u6ee1\u8db3\u5728\u6570\u7ec4\u91cc\u5b58\u50a8\u53ef\u80fd\u6709\u6700\u5927\u6570\u91cf\u5143\u7d20\u7684\u60c5\u51b5\uff0c\u8fd9\u6837\u505a\u4f1a\u6d6a\u8d39\u5927\u91cf\u7684\u5185\u5b58\u3002 \u50cfJava\u548cC++\u8fd9\u7c7b\u7684\u73b0\u4ee3\u7f16\u7a0b\u8bed\u8a00\u4f1a\u5141\u8bb8\u7a0b\u5e8f\u5458\u521b\u5efa\u52a8\u6001\u6570\u7ec4\uff08dynamic array\uff09\uff0c\u4ece\u800c\u4e3a\u8fd9\u4e2a\u95ee\u9898\u63d0\u4f9b\u4e86\u4e00\u79cd\u8865\u6551\u65b9\u6cd5\u3002\u548c\u9759\u6001\u6570\u7ec4\u76f8\u4f3c\u7684\u662f\uff0c\u52a8\u6001\u6570\u7ec4\u4e5f\u4f1a\u5360\u7528\u4e00\u5757\u8fde\u7eed\u5185\u5b58\uff0c\u5e76\u652f\u6301\u968f\u673a\u8bbf\u95ee\u3002\u52a8\u6001\u6570\u7ec4\u7684\u957f\u5ea6\u53ea\u5728\u8fd0\u884c\u65f6\u624d\u77e5\u9053\uff0c\u5728\u52a8\u6001\u6570\u7ec4\u5b9e\u4f8b\u5316\u7684\u65f6\u5019\u6307\u5b9a\u5b83\u7684\u957f\u5ea6\u3002\u5728Python\u91cc\u5b9e\u73b0\u7684Array\u7c7b\u7684\u884c\u4e3a\u4e5f\u662f\u8fd9\u6837\u7684\u3002 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u53e6\u4e00\u79cd\u65b9\u6cd5\u5728\u8fd0\u884c\u65f6\u6839\u636e\u5e94\u7528\u7a0b\u5e8f\u7684\u6570\u636e\u8981\u6c42\u6765\u8c03\u6574\u6570\u7ec4\u7684\u957f\u5ea6\uff0c\u8fd9\u4e9b\u8c03\u6574\u4f1a\u7531Python\u5217\u8868\u81ea\u52a8\u8fdb\u884c\u3002\u8fd9\u65f6\uff0c\u6570\u7ec4\u6709\u4ee5\u4e0b3\u79cd\u4e0d\u540c\u5f62\u5f0f\u3002 \u5728\u7a0b\u5e8f\u542f\u52a8\u65f6\u521b\u5efa\u4e00\u4e2a\u5177\u6709\u5408\u7406\u9ed8\u8ba4\u5927\u5c0f\u7684\u6570\u7ec4\u3002 \u5f53\u6570\u7ec4\u65e0\u6cd5\u5bb9\u7eb3\u66f4\u591a\u6570\u636e\u65f6\uff0c\u521b\u5efa\u4e00\u4e2a\u66f4\u5927\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u628a\u65e7\u6570\u7ec4\u91cc\u7684\u6570\u636e\u5143\u7d20\u4f20\u8f93\u7ed9\u5b83\u3002 \u5982\u679c\u6570\u7ec4\u5728\u6d6a\u8d39\u5185\u5b58\uff08\u5e94\u7528\u7a0b\u5e8f\u5220\u9664\u4e86\u4e00\u4e9b\u6570\u636e\uff09\uff0c\u90a3\u4e48\u7528\u7c7b\u4f3c\u7684\u65b9\u5f0f\u51cf\u5c0f\u6570\u7ec4\u7684\u957f\u5ea6\u3002 4.1.3.\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8 \u00b6 \u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\uff08physical size\uff09\u662f\u6307\u6570\u7ec4\u5355\u5143\u7684\u603b\u6570\uff0c\u6216\u8005\u521b\u5efa\u6570\u7ec4\u65f6\u6307\u5b9a\u5176\u5bb9\u91cf\u7684\u90a3\u4e2a\u6570\u5b57\uff1b \u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\uff08logical size\uff09\u662f\u6307\u5f53\u524d\u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528\u7684\u5143\u7d20\u6570\u91cf\u3002 \u5f53\u6570\u7ec4\u88ab\u586b\u6ee1\u7684\u65f6\u5019\uff0c\u6211\u4eec\u4e0d\u9700\u8981\u62c5\u5fc3\u5b83\u4eec\u7684\u4e0d\u540c\u3002\u5f53\u6570\u7ec4\u88ab\u90e8\u5206\u586b\u6ee1\u7684\u65f6\u5019\uff0c\u672a\u88ab\u586b\u5145\u7684\u5185\u5b58\u5355\u5143\u91cc\u7684\u6570\u636e\u5bf9\u5f53\u524d\u5e94\u7528\u7a0b\u5e8f\u662f\u6ca1\u6709\u7528\u7684\uff0c\u6211\u4eec\u79f0\u4e4b\u5783\u573e\u5185\u5bb9\uff08garbage\uff09\u3002\u5728\u5927\u591a\u6570\u5e94\u7528\u7a0b\u5e8f\u91cc\uff0c\u6211\u4eec\u662f\u8981\u6ce8\u610f\u5bf9\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u8fdb\u884c\u8ffd\u8e2a\u3002\u901a\u5e38\u6765\u8bf4\uff0c\u903b\u8f91\u5c3a\u5bf8\u548c\u7269\u7406\u5c3a\u5bf8\u4f1a\u53cd\u6620\u51fa\u6709\u5173\u6570\u7ec4\u72b6\u6001\u7684\u51e0\u4e2a\u91cd\u70b9\u3002 \u5982\u679c\u903b\u8f91\u5c3a\u5bf8\u4e3a0\uff0c\u90a3\u4e48\u6570\u7ec4\u5c31\u4e3a\u7a7a\u3002\u4e5f\u5c31\u662f\u8bf4\uff0c\u8fd9\u4e2a\u6570\u7ec4\u4e0d\u5305\u542b\u4efb\u4f55\u6570\u636e\u5143\u7d20\u3002 \u5982\u679c\u5e76\u975e\u4e0a\u8ff0\u60c5\u51b5\uff0c\u5728\u4efb\u4f55\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u4e2d\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u7684\u7d22\u5f15\u90fd\u662f\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\u51cf1\u3002 \u5982\u679c\u903b\u8f91\u5c3a\u5bf8\u7b49\u4e8e\u7269\u7406\u5c3a\u5bf8\uff0c\u90a3\u4e48\u8868\u793a\u6570\u7ec4\u5df2\u88ab\u586b\u6ee1\u4e86\u3002 4.1.4.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u8bf7\u8bf4\u660e\u968f\u673a\u8bbf\u95ee\u7684\u5de5\u4f5c\u539f\u7406\uff0c\u4ee5\u53ca\u8fd9\u4e2a\u64cd\u4f5c\u8fd9\u4e48\u5feb\u7684\u539f\u56e0\u3002 \u89e3\u7b54\uff1a\u968f\u673a\u8bbf\u95ee\u662f\u4e00\u79cd\u8ba1\u7b97\u673a\u5b58\u50a8\u7cfb\u7edf\u4e2d\u7684\u8bfb\u53d6\u6216\u5199\u5165\u6570\u636e\u7684\u64cd\u4f5c\uff0c\u5176\u4e2d\u6570\u636e\u53ef\u4ee5\u901a\u8fc7\u76f4\u63a5\u8df3\u8f6c\u5230\u5176\u5b58\u50a8\u4f4d\u7f6e\u800c\u4e0d\u9700\u8981\u987a\u5e8f\u626b\u63cf\u6765\u8bbf\u95ee\u3002\u8fd9\u4e0e\u987a\u5e8f\u8bbf\u95ee\u4e0d\u540c\uff0c\u540e\u8005\u9700\u8981\u6309\u987a\u5e8f\u904d\u5386\u6570\u636e\u4ee5\u627e\u5230\u6240\u9700\u7684\u4fe1\u606f\u3002\u968f\u673a\u8bbf\u95ee\u7684\u5de5\u4f5c\u539f\u7406\u5982\u4e0b\uff1a \u5b58\u50a8\u4ecb\u8d28\uff1a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u786c\u76d8\u7b49\u5b58\u50a8\u8bbe\u5907\u90fd\u652f\u6301\u968f\u673a\u8bbf\u95ee\u3002\u8fd9\u4e9b\u5b58\u50a8\u4ecb\u8d28\u4e2d\u7684\u6570\u636e\u901a\u5e38\u88ab\u5212\u5206\u4e3a\u5757\u6216\u6247\u533a\uff0c\u5e76\u4e14\u6bcf\u4e2a\u5757\u6216\u6247\u533a\u90fd\u6709\u4e00\u4e2a\u552f\u4e00\u7684\u5730\u5740\u6216\u7d22\u5f15\u3002 \u8bbf\u95ee\u5730\u5740\uff1a\u4e3a\u4e86\u8fdb\u884c\u968f\u673a\u8bbf\u95ee\uff0c\u8ba1\u7b97\u673a\u9700\u8981\u77e5\u9053\u8981\u8bbf\u95ee\u7684\u6570\u636e\u7684\u5730\u5740\u3002\u8fd9\u4e2a\u5730\u5740\u53ef\u4ee5\u662f\u5185\u5b58\u4e2d\u7684\u7279\u5b9a\u4f4d\u7f6e\uff0c\u4e5f\u53ef\u4ee5\u662f\u786c\u76d8\u4e0a\u7684\u67d0\u4e2a\u6247\u533a\u7684\u5730\u5740\u3002 \u5bfb\u5740\u548c\u4f20\u8f93\uff1a\u8ba1\u7b97\u673a\u4f7f\u7528\u5b58\u50a8\u8bbe\u5907\u7684\u63a7\u5236\u5668\u6216\u5b58\u50a8\u5668\u7ba1\u7406\u5355\u5143\u6765\u67e5\u627e\u6570\u636e\u7684\u5730\u5740\u3002\u4e00\u65e6\u627e\u5230\u4e86\u6b63\u786e\u7684\u5730\u5740\uff0c\u5b58\u50a8\u8bbe\u5907\u4f1a\u5c06\u6570\u636e\u4f20\u8f93\u5230\u8ba1\u7b97\u673a\u7684\u5185\u5b58\u4e2d\u4f9b\u5904\u7406\u5668\u4f7f\u7528\u3002 \u8bbf\u95ee\u901f\u5ea6\uff1a\u968f\u673a\u8bbf\u95ee\u4e4b\u6240\u4ee5\u5982\u6b64\u5feb\u901f\uff0c\u662f\u56e0\u4e3a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u73b0\u4ee3\u786c\u76d8\u9a71\u52a8\u5668\u7b49\u5b58\u50a8\u8bbe\u5907\u90fd\u7ecf\u8fc7\u4e86\u4f18\u5316\uff0c\u53ef\u4ee5\u5feb\u901f\u54cd\u5e94\u8bbf\u95ee\u8bf7\u6c42\u3002\u8fd9\u4e9b\u8bbe\u5907\u4f7f\u7528\u4e86\u9ad8\u901f\u7f13\u5b58\u3001\u8bfb\u5199\u5934\u3001\u5bfb\u9053\u673a\u6784\u7b49\u6280\u672f\u6765\u6700\u5c0f\u5316\u6570\u636e\u8bbf\u95ee\u7684\u5ef6\u8fdf\u3002 \u539f\u56e0\uff1a \u5b58\u50a8\u8bbe\u5907\u7684\u7269\u7406\u7ed3\u6784\uff1a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u786c\u76d8\u7b49\u5b58\u50a8\u8bbe\u5907\u7684\u7269\u7406\u7ed3\u6784\u88ab\u8bbe\u8ba1\u6210\u53ef\u4ee5\u968f\u673a\u8bbf\u95ee\u7684\u3002\u5185\u5b58\u4e2d\u7684\u6bcf\u4e2a\u5730\u5740\u90fd\u53ef\u4ee5\u77ac\u95f4\u8bbf\u95ee\uff0c\u800c\u786c\u76d8\u4e0a\u7684\u6247\u533a\u4e5f\u53ef\u4ee5\u901a\u8fc7\u78c1\u5934\u5bfb\u9053\u548c\u65cb\u8f6c\u78c1\u76d8\u7b49\u673a\u5236\u8fc5\u901f\u8bbf\u95ee\u3002 \u9ad8\u901f\u7f13\u5b58\uff1a\u73b0\u4ee3\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u5904\u7406\u5668\u90fd\u914d\u5907\u4e86\u9ad8\u901f\u7f13\u5b58\uff08\u4f8b\u5982\uff0cCPU\u7f13\u5b58\uff09\u3002\u8fd9\u4e9b\u9ad8\u901f\u7f13\u5b58\u5b58\u50a8\u4e86\u6700\u8fd1\u8bbf\u95ee\u7684\u6570\u636e\uff0c\u53ef\u4ee5\u5feb\u901f\u63d0\u4f9b\u7ed9\u5904\u7406\u5668\uff0c\u4ece\u800c\u964d\u4f4e\u4e86\u8bbf\u95ee\u5ef6\u8fdf\u3002 \u5b58\u50a8\u5668\u7ba1\u7406\uff1a\u64cd\u4f5c\u7cfb\u7edf\u548c\u5b58\u50a8\u8bbe\u5907\u7684\u63a7\u5236\u5668\u4f1a\u7ba1\u7406\u5b58\u50a8\u5668\u7684\u8bbf\u95ee\uff0c\u4ee5\u786e\u4fdd\u6570\u636e\u53ef\u4ee5\u9ad8\u6548\u5730\u88ab\u8bbf\u95ee\u548c\u4f20\u8f93\u3002\u8fd9\u5305\u62ec\u4e86\u78c1\u76d8\u8c03\u5ea6\u7b97\u6cd5\u3001\u5185\u5b58\u5206\u9875\u7b49\u7b56\u7565\u3002 \u6280\u672f\u8fdb\u6b65\uff1a\u786c\u4ef6\u5236\u9020\u6280\u672f\u7684\u8fdb\u6b65\u548c\u5b58\u50a8\u8bbe\u5907\u7684\u4f18\u5316\u4f7f\u5f97\u968f\u673a\u8bbf\u95ee\u901f\u5ea6\u66f4\u5feb\u3002\u4f8b\u5982\uff0c\u56fa\u6001\u786c\u76d8\uff08SSD\uff09\u7684\u51fa\u73b0\u663e\u8457\u63d0\u9ad8\u4e86\u6570\u636e\u7684\u968f\u673a\u8bbf\u95ee\u901f\u5ea6\u3002 \u603b\u4e4b\uff0c\u968f\u673a\u8bbf\u95ee\u4e4b\u6240\u4ee5\u5982\u6b64\u5feb\u901f\uff0c\u662f\u56e0\u4e3a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u5b58\u50a8\u8bbe\u5907\u7684\u7269\u7406\u548c\u6280\u672f\u7279\u6027\u4f7f\u5176\u80fd\u591f\u4ee5\u9ad8\u6548\u3001\u8fc5\u901f\u7684\u65b9\u5f0f\u8bbf\u95ee\u6570\u636e\u3002\u8fd9\u79cd\u8bbf\u95ee\u901f\u5ea6\u5bf9\u4e8e\u8ba1\u7b97\u673a\u7684\u6027\u80fd\u548c\u54cd\u5e94\u65f6\u95f4\u81f3\u5173\u91cd\u8981\u3002 2\uff0e\u6570\u7ec4\u548cPython\u5217\u8868\u4e4b\u95f4\u6709\u4ec0\u4e48\u533a\u522b\uff1f \u89e3\u7b54\uff1a\u6570\u7ec4\u548cPython\u5217\u8868\u4e4b\u95f4\u6709\u51e0\u4e2a\u5173\u952e\u533a\u522b\uff0c\u8fd9\u4e9b\u533a\u522b\u5728\u6570\u636e\u7ed3\u6784\u3001\u529f\u80fd\u548c\u7528\u9014\u4e0a\u5b58\u5728\u5dee\u5f02\uff1a \u6570\u636e\u7c7b\u578b\uff1a \u6570\u7ec4\uff1a\u901a\u5e38\u8981\u6c42\u6240\u6709\u5143\u7d20\u5177\u6709\u76f8\u540c\u7684\u6570\u636e\u7c7b\u578b\u3002\u8fd9\u662f\u56e0\u4e3a\u6570\u7ec4\u5728\u5185\u5b58\u4e2d\u4ee5\u7d27\u51d1\u7684\u65b9\u5f0f\u5b58\u50a8\u6570\u636e\uff0c\u9700\u8981\u77e5\u9053\u6bcf\u4e2a\u5143\u7d20\u7684\u5927\u5c0f\u4ee5\u4fbf\u8fdb\u884c\u968f\u673a\u8bbf\u95ee\u3002 Python\u5217\u8868\uff1aPython\u7684\u5217\u8868\u53ef\u4ee5\u5bb9\u7eb3\u4e0d\u540c\u6570\u636e\u7c7b\u578b\u7684\u5143\u7d20\uff0c\u56e0\u4e3a\u5b83\u4eec\u662f\u52a8\u6001\u7c7b\u578b\u7684\u3002 \u5185\u5b58\u7ba1\u7406\uff1a \u6570\u7ec4\uff1a\u901a\u5e38\u5728\u521b\u5efa\u65f6\u9700\u8981\u6307\u5b9a\u56fa\u5b9a\u5927\u5c0f\uff0c\u56e0\u6b64\u5728\u5185\u5b58\u4e2d\u4f1a\u5206\u914d\u4e00\u5757\u8fde\u7eed\u7684\u7a7a\u95f4\uff0c\u8fd9\u4f7f\u5f97\u6570\u7ec4\u5bf9\u4e8e\u9ad8\u6548\u7684\u968f\u673a\u8bbf\u95ee\u975e\u5e38\u9002\u7528\u3002 Python\u5217\u8868\uff1aPython\u7684\u5217\u8868\u662f\u52a8\u6001\u7684\uff0c\u5b83\u4eec\u53ef\u4ee5\u6839\u636e\u9700\u8981\u81ea\u52a8\u6269\u5c55\u6216\u7f29\u5c0f\u3002\u8fd9\u5bfc\u81f4\u4e86\u4e00\u4e9b\u989d\u5916\u7684\u5185\u5b58\u5f00\u9500\uff0c\u56e0\u4e3a\u5217\u8868\u9700\u8981\u66f4\u591a\u7684\u7a7a\u95f4\u6765\u7ba1\u7406\u5143\u7d20\u7684\u6dfb\u52a0\u548c\u5220\u9664\u3002 \u6027\u80fd\uff1a \u6570\u7ec4\uff1a\u7531\u4e8e\u5185\u5b58\u5e03\u5c40\u8fde\u7eed\uff0c\u56e0\u6b64\u6570\u7ec4\u901a\u5e38\u5728\u8bbf\u95ee\u5143\u7d20\u65f6\u66f4\u5feb\u3002\u6570\u7ec4\u8fd8\u652f\u6301\u66f4\u591a\u7684\u5e95\u5c42\u64cd\u4f5c\uff0c\u5982\u4f4d\u64cd\u4f5c\u3002 Python\u5217\u8868\uff1aPython\u5217\u8868\u66f4\u52a0\u7075\u6d3b\uff0c\u4f46\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\u53ef\u80fd\u4f1a\u5bfc\u81f4\u6027\u80fd\u4e0b\u964d\uff0c\u7279\u522b\u662f\u5f53\u6d89\u53ca\u5927\u91cf\u5143\u7d20\u7684\u63d2\u5165\u548c\u5220\u9664\u64cd\u4f5c\u65f6\u3002 \u64cd\u4f5c\u548c\u65b9\u6cd5\uff1a \u6570\u7ec4\uff1a\u901a\u5e38\u63d0\u4f9b\u4e00\u7ec4\u57fa\u672c\u64cd\u4f5c\uff0c\u5982\u8bfb\u53d6\u548c\u5199\u5165\u5143\u7d20\uff0c\u4ee5\u53ca\u4e00\u4e9b\u6570\u5b66\u8fd0\u7b97\uff0c\u5982\u5411\u91cf\u5316\u64cd\u4f5c\u3002 Python\u5217\u8868\uff1aPython\u5217\u8868\u63d0\u4f9b\u4e86\u66f4\u4e30\u5bcc\u7684\u65b9\u6cd5\u548c\u64cd\u4f5c\uff0c\u5305\u62ec\u5143\u7d20\u7684\u63d2\u5165\u3001\u5220\u9664\u3001\u8ffd\u52a0\u3001\u5207\u7247\u3001\u8fde\u63a5\u7b49\u3002 \u8bed\u8a00\u4f9d\u8d56\u6027\uff1a \u6570\u7ec4\uff1a\u6570\u7ec4\u901a\u5e38\u662f\u7f16\u7a0b\u8bed\u8a00\u7684\u4e00\u90e8\u5206\uff0c\u5177\u6709\u56fa\u5b9a\u7684\u8bed\u6cd5\u548c\u8bed\u4e49\u3002 Python\u5217\u8868\uff1aPython\u7684\u5217\u8868\u662fPython\u6807\u51c6\u5e93\u7684\u4e00\u90e8\u5206\uff0c\u4e0ePython\u7684\u52a8\u6001\u7279\u6027\u76f8\u9002\u5e94\u3002 \u9002\u7528\u573a\u666f\uff1a \u6570\u7ec4\uff1a\u9002\u7528\u4e8e\u9700\u8981\u9ad8\u6548\u968f\u673a\u8bbf\u95ee\u7684\u60c5\u51b5\uff0c\u5982\u6570\u503c\u8ba1\u7b97\u3001\u56fe\u50cf\u5904\u7406\u7b49\u3002 Python\u5217\u8868\uff1a\u9002\u7528\u4e8e\u66f4\u5e7f\u6cdb\u7684\u5e94\u7528\uff0c\u7279\u522b\u662f\u5728\u7f16\u5199Python\u4ee3\u7801\u65f6\uff0c\u56e0\u4e3a\u5b83\u4eec\u66f4\u7075\u6d3b\u4e14\u6613\u4e8e\u4f7f\u7528\u3002 \u603b\u4e4b\uff0c\u6570\u7ec4\u548cPython\u5217\u8868\u90fd\u6709\u81ea\u5df1\u7684\u4f18\u52bf\u548c\u9002\u7528\u573a\u666f\u3002\u9009\u62e9\u4f7f\u7528\u54ea\u79cd\u6570\u636e\u7ed3\u6784\u53d6\u51b3\u4e8e\u5177\u4f53\u7684\u9700\u6c42\u548c\u7f16\u7a0b\u8bed\u8a00\u3002\u5728Python\u4e2d\uff0c\u901a\u5e38\u4f1a\u4f18\u5148\u9009\u62e9\u4f7f\u7528\u5217\u8868\uff0c\u56e0\u4e3a\u5b83\u4eec\u66f4\u65b9\u4fbf\uff0c\u800c\u5728\u5176\u4ed6\u7f16\u7a0b\u8bed\u8a00\u4e2d\uff0c\u5982C\u6216Java\uff0c\u6570\u7ec4\u53ef\u80fd\u66f4\u4e3a\u5e38\u89c1\u3002 \u5728\u8fd9\u91cc\u9700\u8981\u8bf4\u660e\u4e00\u4e2a\u6982\u5ff5\u3002\u5728Python\u4e2d\uff0c\u672f\u8bed\"\u6570\u7ec4\"\u901a\u5e38\u6307\u7684\u662fNumPy\u5e93\u4e2d\u7684\u6570\u7ec4\u5bf9\u8c61\uff0c\u800c\"\u5217\u8868\"\u6307\u7684\u662fPython\u7684\u5185\u7f6e\u5217\u8868\uff08list\uff09\u6570\u636e\u7ed3\u6784\u3002\u8fd9\u4e24\u8005\u4e4b\u95f4\u6709\u4ee5\u4e0b\u533a\u522b\uff1a \u6570\u636e\u7c7b\u578b\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1aNumPy\u5e93\u63d0\u4f9b\u4e86\u4e00\u4e2a\u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61\uff0c\u5b83\u53ef\u4ee5\u5305\u542b\u76f8\u540c\u6570\u636e\u7c7b\u578b\u7684\u5143\u7d20\uff0c\u5e76\u652f\u6301\u9ad8\u7ea7\u6570\u5b66\u3001\u79d1\u5b66\u548c\u5de5\u7a0b\u8ba1\u7b97\u3002NumPy\u6570\u7ec4\u7684\u5143\u7d20\u7c7b\u578b\u901a\u5e38\u662f\u56fa\u5b9a\u7684\uff0c\u4f8b\u5982\uff0c\u53ef\u4ee5\u662f\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u590d\u6570\u7b49\u3002\u8fd9\u4e9b\u6570\u7ec4\u662f\u9ad8\u6027\u80fd\u7684\uff0c\u652f\u6301\u5411\u91cf\u5316\u64cd\u4f5c\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u7684\u5185\u7f6e\u5217\u8868\u662f\u4e00\u79cd\u901a\u7528\u7684\u3001\u52a8\u6001\u7c7b\u578b\u7684\u6570\u636e\u7ed3\u6784\uff0c\u53ef\u4ee5\u5305\u542b\u4e0d\u540c\u6570\u636e\u7c7b\u578b\u7684\u5143\u7d20\uff0c\u4f8b\u5982\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u5b57\u7b26\u4e32\u3001\u5bf9\u8c61\u7b49\u3002\u5217\u8868\u53ef\u4ee5\u52a8\u6001\u6269\u5c55\u548c\u7f29\u5c0f\uff0c\u5e76\u63d0\u4f9b\u4e86\u4e30\u5bcc\u7684\u5185\u7f6e\u65b9\u6cd5\u548c\u64cd\u4f5c\u3002 \u6027\u80fd\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1aNumPy\u6570\u7ec4\u901a\u5e38\u6bd4Python\u5217\u8868\u66f4\u9ad8\u6548\uff0c\u7279\u522b\u662f\u5728\u8fdb\u884c\u6570\u503c\u8ba1\u7b97\u548c\u79d1\u5b66\u8ba1\u7b97\u65f6\u3002\u5b83\u4eec\u5185\u90e8\u4f7f\u7528\u4e86C\u8bed\u8a00\u5b9e\u73b0\uff0c\u652f\u6301\u5411\u91cf\u5316\u64cd\u4f5c\uff0c\u56e0\u6b64\u5728\u5927\u89c4\u6a21\u6570\u636e\u5904\u7406\u4e2d\u901a\u5e38\u66f4\u5feb\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u5217\u8868\u867d\u7136\u7075\u6d3b\uff0c\u4f46\u6027\u80fd\u76f8\u5bf9\u8f83\u4f4e\uff0c\u4e0d\u9002\u5408\u5927\u89c4\u6a21\u7684\u6570\u503c\u8ba1\u7b97\u3002\u5b83\u4eec\u7684\u5143\u7d20\u7c7b\u578b\u53ef\u4ee5\u4e0d\u540c\uff0c\u8fd9\u610f\u5473\u7740\u9700\u8981\u66f4\u591a\u7684\u5185\u5b58\u548c\u5904\u7406\u65f6\u95f4\u6765\u7ba1\u7406\u5143\u7d20\u3002 \u5e93\u4f9d\u8d56\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1a\u4f7f\u7528NumPy\u5e93\u9700\u8981\u5b89\u88c5NumPy\u6a21\u5757\u3002NumPy\u662fPython\u4e2d\u7528\u4e8e\u6570\u503c\u8ba1\u7b97\u7684\u6838\u5fc3\u5e93\uff0c\u5e7f\u6cdb\u5e94\u7528\u4e8e\u79d1\u5b66\u8ba1\u7b97\u3001\u673a\u5668\u5b66\u4e60\u7b49\u9886\u57df\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u7684\u5185\u7f6e\u5217\u8868\u662fPython\u6807\u51c6\u5e93\u7684\u4e00\u90e8\u5206\uff0c\u65e0\u9700\u989d\u5916\u5b89\u88c5\u3002 \u529f\u80fd\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1aNumPy\u6570\u7ec4\u63d0\u4f9b\u4e86\u8bb8\u591a\u6570\u5b66\u548c\u79d1\u5b66\u8ba1\u7b97\u51fd\u6570\uff0c\u5982\u7ebf\u6027\u4ee3\u6570\u3001\u5085\u7acb\u53f6\u53d8\u6362\u3001\u7edf\u8ba1\u5206\u6790\u7b49\u3002\u5b83\u4eec\u9002\u7528\u4e8e\u5904\u7406\u5927\u91cf\u6570\u503c\u6570\u636e\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u5217\u8868\u63d0\u4f9b\u4e86\u901a\u7528\u7684\u6570\u636e\u5bb9\u5668\uff0c\u7528\u4e8e\u5b58\u50a8\u548c\u7ba1\u7406\u5404\u79cd\u7c7b\u578b\u7684\u6570\u636e\uff0c\u4f46\u4e0d\u63d0\u4f9b\u4e13\u95e8\u7684\u6570\u5b66\u548c\u79d1\u5b66\u8ba1\u7b97\u529f\u80fd\u3002 \u5982\u679c\u9700\u8981\u8fdb\u884c\u6570\u503c\u8ba1\u7b97\u3001\u79d1\u5b66\u8ba1\u7b97\u6216\u6570\u636e\u5206\u6790\uff0c\u901a\u5e38\u4f1a\u4f7f\u7528NumPy\u6570\u7ec4\u3002\u5982\u679c\u53ea\u662f\u9700\u8981\u4e00\u4e2a\u901a\u7528\u7684\u6570\u636e\u5bb9\u5668\uff0c\u7528\u4e8e\u5b58\u50a8\u548c\u7ba1\u7406\u6570\u636e\uff0c\u90a3\u4e48Python\u5217\u8868\u901a\u5e38\u8db3\u591f\u4e86\u3002 3\uff0e\u8bf7\u8bf4\u660e\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u4e4b\u95f4\u7684\u533a\u522b\u3002 \u89e3\u7b54\uff1a\"\u7269\u7406\u5c3a\u5bf8\"\u548c\"\u903b\u8f91\u5c3a\u5bf8\"\u901a\u5e38\u7528\u4e8e\u63cf\u8ff0\u6570\u636e\u7ed3\u6784\u4e2d\u7684\u4e24\u4e2a\u4e0d\u540c\u65b9\u9762\uff1a \u7269\u7406\u5c3a\u5bf8\uff08Physical Size\uff09\uff1a \u7269\u7406\u5c3a\u5bf8\u662f\u6307\u6570\u636e\u7ed3\u6784\u5b9e\u9645\u5360\u7528\u7684\u5185\u5b58\u7a7a\u95f4\u6216\u5b58\u50a8\u4ecb\u8d28\u4e2d\u7684\u7a7a\u95f4\u5927\u5c0f\u3002 \u5b83\u8868\u793a\u6570\u636e\u7ed3\u6784\u5728\u8ba1\u7b97\u673a\u5185\u5b58\u6216\u78c1\u76d8\u4e2d\u6240\u5360\u636e\u7684\u5b9e\u9645\u5b57\u8282\u6570\u3002 \u7269\u7406\u5c3a\u5bf8\u4e0e\u6570\u636e\u7ed3\u6784\u7684\u5b58\u50a8\u65b9\u5f0f\u3001\u6570\u636e\u7c7b\u578b\u4ee5\u53ca\u8ba1\u7b97\u673a\u67b6\u6784\u6709\u5173\u3002 \u903b\u8f91\u5c3a\u5bf8\uff08Logical Size\uff09\uff1a \u903b\u8f91\u5c3a\u5bf8\u662f\u6307\u6570\u636e\u7ed3\u6784\u4e2d\u5305\u542b\u7684\u5143\u7d20\u6570\u91cf\u6216\u6570\u636e\u9879\u7684\u6570\u91cf\u3002 \u5b83\u8868\u793a\u6570\u636e\u7ed3\u6784\u5185\u90e8\u7684\u5143\u7d20\u6570\u91cf\u6216\u6570\u636e\u9879\u7684\u4e2a\u6570\uff0c\u4e0d\u6d89\u53ca\u5b9e\u9645\u7684\u5b58\u50a8\u5927\u5c0f\u3002 \u903b\u8f91\u5c3a\u5bf8\u901a\u5e38\u7528\u4e8e\u63cf\u8ff0\u6570\u636e\u7ed3\u6784\u7684\u5bb9\u91cf\u3001\u89c4\u6a21\u6216\u7ef4\u5ea6\u3002 \u8fd9\u4e24\u4e2a\u6982\u5ff5\u4e4b\u95f4\u7684\u5173\u7cfb\u5982\u4e0b\uff1a \u4e00\u4e2a\u6570\u636e\u7ed3\u6784\u53ef\u4ee5\u5177\u6709\u56fa\u5b9a\u7684\u7269\u7406\u5c3a\u5bf8\uff08\u5360\u636e\u56fa\u5b9a\u6570\u91cf\u7684\u5b57\u8282\uff09\uff0c\u4f46\u5176\u903b\u8f91\u5c3a\u5bf8\u53ef\u4ee5\u6839\u636e\u5b9e\u9645\u5b58\u50a8\u7684\u5143\u7d20\u6570\u91cf\u800c\u53d8\u5316\u3002 \u7269\u7406\u5c3a\u5bf8\u901a\u5e38\u662f\u7531\u8ba1\u7b97\u673a\u786c\u4ef6\u548c\u64cd\u4f5c\u7cfb\u7edf\u7ba1\u7406\u7684\uff0c\u800c\u903b\u8f91\u5c3a\u5bf8\u5219\u662f\u7a0b\u5e8f\u5458\u6839\u636e\u6570\u636e\u7ed3\u6784\u7684\u8bbe\u8ba1\u6765\u7ba1\u7406\u7684\u3002 \u4e3e\u4f8b\u6765\u8bf4\uff0c\u4e00\u4e2a\u6574\u6570\u6570\u7ec4\u53ef\u4ee5\u5177\u6709\u56fa\u5b9a\u7684\u7269\u7406\u5c3a\u5bf8\uff0c\u4f8b\u59824\u5b57\u8282/\u6574\u6570\uff0c\u4f46\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\u53ef\u4ee5\u662f\u6570\u7ec4\u4e2d\u6574\u6570\u7684\u6570\u91cf\uff0c\u53ef\u4ee5\u662f0\u4e2a\u300110\u4e2a\u3001100\u4e2a\u7b49\u7b49\u3002\u56e0\u6b64\uff0c\u903b\u8f91\u5c3a\u5bf8\u63cf\u8ff0\u4e86\u6570\u7ec4\u53ef\u4ee5\u5bb9\u7eb3\u7684\u5143\u7d20\u6570\u91cf\uff0c\u800c\u7269\u7406\u5c3a\u5bf8\u63cf\u8ff0\u4e86\u5b9e\u9645\u5360\u7528\u7684\u5185\u5b58\u7a7a\u95f4\u3002 \u5728\u6570\u636e\u7ed3\u6784\u7684\u8bbe\u8ba1\u548c\u4f7f\u7528\u4e2d\uff0c\u4e86\u89e3\u548c\u7ba1\u7406\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u5bf9\u4e8e\u6709\u6548\u5730\u5229\u7528\u8ba1\u7b97\u673a\u8d44\u6e90\u975e\u5e38\u91cd\u8981\u3002 4.2.\u6570\u7ec4\u7684\u64cd\u4f5c \u00b6 Python\u7684 array \u6a21\u5757\u5305\u542b\u4e00\u4e2a\u53eb\u4f5c array \u7684\u7c7b\uff0c\u5b83\u975e\u5e38\u7c7b\u4f3c\u4e8e\u5217\u8868\uff0c\u4f46\u662f\u53ea\u80fd\u5b58\u50a8\u6570\u5b57\u3002\u6211\u4eec\u4f1a\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c Array \u7684\u65b0\u7c7b\uff0c\u4f7f\u7528\u5217\u8868\u4fdd\u5b58\u5143\u7d20\uff0c\u5b58\u50a8\u4efb\u4f55\u7c7b\u578b\u7684\u5143\u7d20\u3002 \u4e0b\u9762\u7684\u793a\u4f8b\u5b9a\u4e49\u4e86\u4e00\u4e2a\u6570\u7ec4\u7c7b Array \uff0c\u4e0b\u9762\u5bf9\u6570\u7ec4\u7684\u4e00\u4e9b\u64cd\u4f5c\u7684\u4ee3\u7801\u5b9e\u73b0\u4e5f\u5df2\u7ecf\u5305\u542b\u5728\u4e0b\u9762\u7684\u4ee3\u7801\u4e2d\u3002\u5176\u4e2d\uff1a \u6570\u7ec4\u9ed8\u8ba4\u7684\u7269\u7406\u5c3a\u5bf8\uff08\u4e5f\u5c31\u662f\u5bb9\u91cf\uff09\u662f5 \u6570\u7ec4\u7684\u521d\u59cb\u903b\u8f91\u5c3a\u5bf8\u662f0 class Array ( object ): \"\"\"\u63cf\u8ff0\u4e00\u4e2a\u6570\u7ec4\u3002\"\"\" def __init__ ( self , capacity , fillValue = None ): \"\"\"Capacity\u662f\u6570\u7ec4\u7684\u5927\u5c0f. fillValue\u4f1a\u586b\u5145\u5728\u6bcf\u4e2a\u5143\u7d20\u4f4d\u7f6e, \u9ed8\u8ba4\u503c\u662fNone\"\"\" # \u521d\u59cb\u5316\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u548c\u7269\u7406\u5c3a\u5bf8 self . logicalSize = 0 self . capacity = capacity self . fillValue = fillValue #\u521d\u59cb\u5316\u5185\u90e8\u6570\u7ec4\uff0c\u5e76\u586b\u5145\u5143\u7d20\u503c self . items = list () for count in range ( capacity ): self . items . append ( fillValue ) def __len__ ( self ): \"\"\"\u8fd4\u56de\u6570\u7ec4\u7684\u5927\u5c0f\"\"\" return len ( self . items ) def __str__ ( self ): \"\"\"\u5c06\u6570\u7ec4\u5b57\u7b26\u4e32\u5316\u5e76\u8fd4\u56de\"\"\" result = \"\" for index in range ( self . size ()): result += str ( self . items [ index ]) + \" \" return result def size ( self ): \"\"\"\u8fd4\u56de\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\"\"\" return self . logicalSize def __iter__ ( self ): \"\"\"\u652f\u6301for\u5faa\u73af\u5bf9\u6570\u7ec4\u8fdb\u884c\u904d\u5386.\"\"\" print ( \"__iter__ called\" ) # \u4ec5\u7528\u6765\u6d4b\u8bd5\u4f55\u65f6__iter__\u4f1a\u88ab\u8c03\u7528 return iter ( self . items ) def __getitem__ ( self , index ): \"\"\" \u7528\u4e8e\u8bbf\u95ee\u7d22\u5f15\u5904\u7684\u4e0b\u6807\u8fd0\u7b97\u7b26. \u5148\u51b3\u6761\u4ef6: 0 <= index < size() \"\"\" if index < 0 or index >= self . size (): raise IndexError ( \"\u8bfb\u53d6\u64cd\u4f5c\u51fa\u9519, \u6570\u7ec4\u7d22\u5f15\u8d8a\u754c(\u4e0d\u5728\u6570\u7ec4\u903b\u8f91\u8fb9\u754c\u8303\u56f4\u5185)\" ) return self . items [ index ] def __setitem__ ( self , index , newItem ): \"\"\" \u4e0b\u6807\u8fd0\u7b97\u7b26\u7528\u4e8e\u5728\u7d22\u5f15\u5904\u8fdb\u884c\u66ff\u6362. \u5148\u51b3\u6761\u4ef6: 0 <= index < size() \"\"\" if index < 0 or index >= self . size (): raise IndexError ( \"\u66f4\u65b0\u64cd\u4f5c\u51fa\u9519, \u6570\u7ec4\u7d22\u5f15\u8d8a\u754c(\u4e0d\u5728\u6570\u7ec4\u903b\u8f91\u8fb9\u754c\u8303\u56f4\u5185)\" ) self . items [ index ] = newItem def __eq__ ( self , other ): \"\"\" \u4e24\u4e2a\u6570\u7ec4\u76f8\u7b49\u5219\u8fd4\u56deTrue\uff0c\u5426\u5219\u8fd4\u56deFalse \"\"\" # \u5224\u65ad\u4e24\u4e2a\u6570\u7ec4\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff0c\u6ce8\u610f\uff0c\u4e0d\u662f\u5b83\u4eec\u7684\u503c\u662f\u5426\u76f8\u7b49 if self is other : return True # \u5224\u65ad\u4e24\u4e2a\u5bf9\u8c61\u7c7b\u578b\u662f\u5426\u4e00\u6837 if type ( self ) != type ( other ): return False # \u5224\u65ad\u4e24\u4e2a\u6570\u7ec4\u5927\u5c0f\u662f\u5426\u4e00\u6837 if self . size () != other . size (): return False # \u6bd4\u8f83\u4e24\u4e2a\u6570\u7ec4\u7684\u503c\u662f\u5426\u4e00\u6837 for index in range ( self . size ()): if self [ index ] != other [ index ]: return False return True def grow ( self ): \"\"\"\u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\"\"\" # \u57fa\u4e8e\u5f53\u524d\u7269\u7406\u5c3a\u5bf8\u52a0\u500d\uff0c\u5e76\u5c06fillValue\u8d4b\u503c\u5e95\u5c42\u5217\u8868\u7684\u65b0\u5143\u7d20 for count in range ( len ( self )): self . items . append ( self . fillValue ) def insert ( self , index , newItem ): \"\"\"\u5728\u6570\u7ec4\u6307\u5b9a\u7d22\u5f15\u5904\u63d2\u5165\u65b0\u5143\u7d20\"\"\" # \u5f53\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u4e00\u6837\u65f6\uff0c\u5219\u589e\u52a0\u7269\u7406\u5c3a\u5bf8 if self . size () == len ( self ): self . grow () # \u63d2\u5165\u65b0\u5143\u7d20 # \u5f53\u63d2\u5165\u4f4d\u7f6e\u5927\u4e8e\u6216\u7b49\u4e8e\u6700\u5927\u903b\u8f91\u4f4d\u7f6e\uff0c\u5219\u5728\u6570\u7ec4\u672b\u7aef\u63d2\u5165\u65b0\u5143\u7d20 # \u5f53\u63d2\u5165\u4f4d\u7f6e\u4ecb\u4e8e\u6570\u7ec4\u903b\u8f91\u4f4d\u7f6e\u7684\u4e2d\u95f4\uff0c\u5219\u4ece\u63d2\u5165\u4f4d\u7f6e\u8d77\u5c06\u5269\u4f59\u6570\u7ec4\u5143\u7d20\u5411\u5c3e\u90e8\u5e73\u79fb\u4e00\u4e2a\u4f4d\u7f6e if index >= self . size (): self . items [ self . size ()] = newItem else : index = max ( index , 0 ) # \u5c06\u6570\u7ec4\u5143\u7d20\u5411\u5c3e\u90e8\u5e73\u79fb\u4e00\u4e2a\u4f4d\u7f6e for i in range ( self . size (), index , - 1 ): self . items [ i ] = self . items [ i - 1 ] # \u63d2\u5165\u65b0\u5143\u7d20 self . items [ index ] = newItem # \u589e\u52a0\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8 self . logicalSize += 1 def shrink ( self ): \"\"\" \u51cf\u5c11\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8 \u5f53: - \u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u5c0f\u4e8e\u6216\u7b49\u4e8e\u5176\u7269\u7406\u5c3a\u5bf8\u76841/4 - \u5e76\u4e14\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u81f3\u5c11\u662f\u8fd9\u4e2a\u6570\u7ec4\u5efa\u7acb\u65f6\u9ed8\u8ba4\u5bb9\u91cf\u76842\u500d\u65f6 \u5219\u628a\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u51cf\u5c0f\u5230\u539f\u6765\u7684\u4e00\u534a\uff0c\u5e76\u4e14\u4e5f\u4e0d\u4f1a\u5c0f\u4e8e\u5176\u9ed8\u8ba4\u5bb9\u91cf \"\"\" # \u5728\u903b\u8f91\u5c3a\u5bf8\u548c\u7269\u7406\u5c3a\u5bf8\u7684\u4e00\u534a\u4e4b\u95f4\u9009\u62e9\u6700\u5927\u503c\u4f5c\u4e3a\u6570\u7ec4\u6536\u7f29\u540e\u7684\u7269\u7406\u5c3a\u5bf8 newSize = max ( self . capacity , len ( self ) // 2 ) # \u91ca\u653e\u591a\u4f59\u7684\u6570\u7ec4\u7a7a\u95f4 for count in range ( len ( self ) - newSize ): self . items . pop () def pop ( self , index ): \"\"\" \u5220\u9664\u6307\u5b9a\u7d22\u5f15\u503c\u7684\u6570\u7ec4\u5143\u7d20,\u5e76\u8fd4\u56de\u5220\u9664\u7684\u6570\u7ec4\u5143\u7d20\u503c \u5148\u51b3\u6761\u4ef6: 0 <= index < size() \"\"\" if index < 0 or index >= self . size (): raise IndexError ( \"\u5220\u9664\u64cd\u4f5c\u51fa\u9519, \u6570\u7ec4\u7d22\u5f15\u8d8a\u754c(\u4e0d\u5728\u6570\u7ec4\u903b\u8f91\u8fb9\u754c\u8303\u56f4\u5185)\" ) # \u4fdd\u5b58\u5373\u5c06\u88ab\u5220\u9664\u7684\u6570\u7ec4\u5143\u7d20\u503c itemToReturn = self . items [ index ] # \u5c06\u6570\u7ec4\u5143\u7d20\u5411\u5934\u90e8\u5e73\u79fb\u4e00\u4e2a\u4f4d\u7f6e for i in range ( index , self . size () - 1 ): self . items [ i ] = self . items [ i + 1 ] # \u5c06\u6570\u7ec4\u5c3e\u90e8\u7684\u7a7a\u4f59\u4f4d\u8d4b\u503cfillValue\uff0c\u9ed8\u8ba4\u662fNone self . items [ self . size () - 1 ] = self . fillValue # \u51cf\u5c11\u6570\u7ec4\u903b\u8f91\u5c3a\u5bf8 self . logicalSize -= 1 # \u51cf\u5c11\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 # \u5f53: # - \u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u5c0f\u4e8e\u6216\u7b49\u4e8e\u5176\u7269\u7406\u5c3a\u5bf8\u76841/4 # - \u5e76\u4e14\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u81f3\u5c11\u662f\u8fd9\u4e2a\u6570\u7ec4\u5efa\u7acb\u65f6\u9ed8\u8ba4\u5bb9\u91cf\u76842\u500d\u65f6 # \u5219\u628a\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u51cf\u5c0f\u5230\u539f\u6765\u7684\u4e00\u534a\uff0c\u5e76\u4e14\u4e5f\u4e0d\u4f1a\u5c0f\u4e8e\u5176\u9ed8\u8ba4\u5bb9\u91cf if self . size () <= len ( self ) // 4 and len ( self ) > self . capacity : self . shrink () # \u8fd4\u56de\u88ab\u5220\u9664\u5143\u7d20\u7684\u503c print ( f 'Item { itemToReturn } was deleted' ) return itemToReturn def main (): # \u521d\u59cb\u5316\u7a7a\u6570\u7ec4 DEFAULT_CAPACITY = 5 my_arr = Array ( DEFAULT_CAPACITY ) # \u6253\u5370\u8f93\u51fa\u6570\u7ec4\u521d\u59cb\u4fe1\u606f print ( \"Physical size:\" , len ( my_arr )) print ( \"Logical size:\" , my_arr . size ()) print ( \"Initial items:\" , my_arr . items ) # \u521d\u59cb\u5316\u6570\u7ec4\u5143\u7d20 print ( '------' ) for item in range ( 4 ): my_arr . insert ( 0 , item ) # \u5728\u6570\u7ec4\u5934\u90e8\u63d2\u5165\uff0c\u6bcf\u63d2\u5165\u4e00\u6b21\u90fd\u9700\u8981\u5411\u540e\u79fb\u52a8\u5df2\u6709\u6570\u7ec4\u5143\u7d20 print ( \"Items(logical):\" , my_arr ) print ( \"Items(physical):\" , my_arr . items ) # \u5728\u6570\u7ec4\u4e2d\u95f4\u63d2\u5165\u65b0\u5143\u7d20 print ( '------' ) my_arr . insert ( 3 , 99 ) print ( \"Items(logical):\" , my_arr ) print ( \"Items(physical):\" , my_arr . items ) # \u5728\u6570\u7ec4\u903b\u8f91\u5c3a\u5bf8\u5916\u63d2\u5165\u65b0\u5143\u7d20 print ( '------' ) my_arr . insert ( 20 , 88 ) print ( \"Items(logical):\" , my_arr ) print ( \"Items(physical):\" , my_arr . items ) # \u5220\u9664\u6570\u7ec4\u5143\u7d20 print ( '------' ) my_arr . pop ( 3 ) my_arr . pop ( 3 ) print ( \"Items(logical):\" , my_arr ) print ( \"Items(physical):\" , my_arr . items ) # \u6e05\u7a7a\u6570\u7ec4\u5143\u7d20 print ( '------' ) for count in range ( my_arr . size ()): my_arr . pop ( 0 ) print ( \"Items(logical):\" , my_arr ) print ( \"Items(physical):\" , my_arr . items ) # \u6570\u7ec4\u5143\u7d20\u5df2\u7ecf\u5168\u90e8\u5220\u9664\uff0c\u903b\u8f91\u5c3a\u5bf8\u4e3a\u96f6\uff0c\u4e0b\u9762\u547d\u4ee4\u8fd4\u56de\u9519\u8bef # print('------') # print(my_arr.pop(0)) # \u6570\u7ec4\u6bd4\u8f83 # \u521d\u59cb\u5316\u6570\u7ec4 print ( '------' ) arr_a = Array ( 5 ) for item in range ( 4 ): arr_a . insert ( 0 , item ) arr_b = arr_a arr_c = Array ( 5 ) for item in range ( 4 ): arr_c . insert ( 0 , item ) arr_d = [] print ( \"arr_a(physical):\" , arr_a . items ) print ( \"arr_b(physical):\" , arr_b . items ) print ( \"arr_c(physical):\" , arr_c . items ) print ( \"arr_d(physical):\" , arr_d ) print ( \"arr_a == arr_b:\" , arr_a == arr_b ) print ( \"arr_a is arr_b:\" , arr_a is arr_b ) print ( \"arr_a == arr_c:\" , arr_a == arr_c ) print ( \"arr_a is arr_c:\" , arr_a is arr_c ) arr_c . insert ( 10 , 10 ) print ( \"arr_a == arr_c:\" , arr_a == arr_c ) arr_c . pop ( arr_c . size () - 1 ) arr_c [ 2 ] = 6 print ( \"arr_a == arr_c:\" , arr_a == arr_c ) print ( \"arr_a == arr_d:\" , arr_a == arr_d ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # Physical size: 5 # Logical size: 0 # Initial items: [None, None, None, None, None] # ------ # Items(logical): 3 2 1 0 # Items(physical): [3, 2, 1, 0, None] # ------ # Items(logical): 3 2 1 99 0 # Items(physical): [3, 2, 1, 99, 0] # ------ # Items(logical): 3 2 1 99 0 88 # Items(physical): [3, 2, 1, 99, 0, 88, None, None, None, None] # ------ # Item 99 was deleted # Item 0 was deleted # Items(logical): 3 2 1 88 # Items(physical): [3, 2, 1, 88, None, None, None, None, None, None] # ------ # Item 3 was deleted # Item 2 was deleted # Item 1 was deleted # Item 88 was deleted # Items(logical): # Items(physical): [None, None, None, None, None] # ------ # IndexError: \u5220\u9664\u64cd\u4f5c\u51fa\u9519, \u6570\u7ec4\u7d22\u5f15\u8d8a\u754c(\u4e0d\u5728\u6570\u7ec4\u903b\u8f91\u8fb9\u754c\u8303\u56f4\u5185) # ------ # arr_a(physical): [3, 2, 1, 0, None] # arr_b(physical): [3, 2, 1, 0, None] # arr_c(physical): [3, 2, 1, 0, None] # arr_d(physical): [] # arr_a == arr_b: True # arr_a is arr_b: True # arr_a == arr_c: True # arr_a is arr_c: False # arr_a == arr_c: False # Item 10 was deleted # arr_a == arr_c: False # arr_a == arr_d: False 4.2.1.\u589e\u5927\u6570\u7ec4\u7684\u5c3a\u5bf8 \u00b6 \u5f53\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u7b49\u4e8e\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u65f6\uff0c\u5982\u679c\u8981\u63d2\u5165\u65b0\u7684\u5143\u7d20\uff0c\u5c31\u9700\u8981\u589e\u5927\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u3002 \u5982\u679c\u9700\u8981\u4e3a\u6570\u7ec4\u63d0\u4f9b\u66f4\u591a\u5185\u5b58\uff0cPython\u7684list\u7c7b\u578b\u4f1a\u5728\u8c03\u7528insert\u6216append\u65b9\u6cd5\u65f6\u6267\u884c\u8fd9\u4e2a\u64cd\u4f5c\u3002 \u8c03\u6574\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\u7684\u8fc7\u7a0b\u5305\u542b\u5982\u4e0b3\u4e2a\u6b65\u9aa4\u3002 \u521b\u5efa\u4e00\u4e2a\u66f4\u5927\u7684\u65b0\u6570\u7ec4\u3002 \u5c06\u6570\u636e\u4ece\u65e7\u6570\u7ec4\u4e2d\u590d\u5236\u5230\u65b0\u6570\u7ec4\u3002 \u5c06\u6307\u5411\u65e7\u6570\u7ec4\u7684\u53d8\u91cf\u6307\u5411\u65b0\u6570\u7ec4\u5bf9\u8c61\u3002 \u4e0b\u9762\u4ee3\u7801\u5b9e\u73b0\u3002 # \u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 if logicalSize == len ( my_array ): temp = Array ( len ( my_array ) + 1 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 \u5728\u4e0a\u9762\u4ee3\u7801\u4e2d\uff0c\u901a\u8fc7 temp[i] = my_array[i] \u6765\u8c03\u6574\u6570\u7ec4\u5c3a\u5bf8\uff0c\u8fd9\u4e2a\u590d\u5236\u64cd\u4f5c\u7684\u6570\u91cf\u662f\u7ebf\u6027\u589e\u957f\u7684\u3002\u56e0\u6b64\uff0c\u5c06 n \u4e2a\u5143\u7d20\u6dfb\u52a0\u5230\u6570\u7ec4\u91cc\u7684\u603b\u65f6\u95f4\u590d\u6742\u5ea6\u662f 1+2+3...+n \uff0c\u4e5f\u5c31\u662f n(n+1)/2 \uff0c\u56e0\u6b64\u662f O(n^2) \u3002 \u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\uff0c\u901a\u8fc7 temp = Array(len(my_array) + 1) \u5bf9\u6570\u7ec4\u8fdb\u884c\u52a8\u6001\u6269\u5c55\uff0c\u5bf9\u6027\u80fd\u4f1a\u4ea7\u751f\u4e00\u4e9b\u53ef\u80fd\u7684\u5f71\u54cd\uff1a \u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u52a8\u6001\u6269\u5c55\u6570\u7ec4\u901a\u5e38\u9700\u8981\u590d\u5236\u73b0\u6709\u6570\u636e\u5230\u65b0\u7684\u5185\u5b58\u4f4d\u7f6e\uff0c\u8fd9\u5c06\u6d89\u53ca\u5230\u5143\u7d20\u7684\u590d\u5236\u64cd\u4f5c\u3002\u8fd9\u4e9b\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u6570\u7ec4\u7684\u957f\u5ea6\uff0c\u901a\u5e38\u662f O(n) \uff0c\u5176\u4e2d n \u662f\u6570\u7ec4\u7684\u957f\u5ea6\u3002\u56e0\u6b64\uff0c\u5f53\u6570\u7ec4\u9700\u8981\u6269\u5c55\u65f6\uff0c\u53ef\u80fd\u4f1a\u4ea7\u751f\u4e00\u4e9b\u989d\u5916\u7684\u65f6\u95f4\u5f00\u9500\u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\uff1a\u52a8\u6001\u6269\u5c55\u6570\u7ec4\u4f1a\u5360\u7528\u989d\u5916\u7684\u5185\u5b58\u7a7a\u95f4\uff0c\u56e0\u4e3a\u9700\u8981\u5206\u914d\u65b0\u7684\u5185\u5b58\u5757\u6765\u5bb9\u7eb3\u6269\u5c55\u540e\u7684\u6570\u7ec4\u3002\u8fd9\u53ef\u80fd\u4f1a\u5bfc\u81f4\u5185\u5b58\u788e\u7247\u5316\uff0c\u7279\u522b\u662f\u5728\u9891\u7e41\u6269\u5c55\u548c\u7f29\u5c0f\u6570\u7ec4\u65f6\u3002 \u6269\u5c55\u9891\u7387\uff1a\u6269\u5c55\u6570\u7ec4\u7684\u9891\u7387\u4f1a\u5f71\u54cd\u6027\u80fd\u3002\u5982\u679c\u6570\u7ec4\u9700\u8981\u9891\u7e41\u6269\u5c55\uff0c\u90a3\u4e48\u590d\u5236\u548c\u5185\u5b58\u5206\u914d\u7684\u5f00\u9500\u4f1a\u66f4\u52a0\u663e\u8457\uff0c\u4ece\u800c\u964d\u4f4e\u6027\u80fd\u3002\u56e0\u6b64\uff0c\u5728\u8bbe\u8ba1\u6570\u636e\u7ed3\u6784\u65f6\uff0c\u901a\u5e38\u4f1a\u8003\u8651\u521d\u59cb\u5bb9\u91cf\u548c\u6269\u5c55\u7b56\u7565\uff0c\u4ee5\u51cf\u5c11\u4e0d\u5fc5\u8981\u7684\u6269\u5c55\u6b21\u6570\u3002 Amortized Analysis\uff1a\u4e00\u4e9b\u6570\u636e\u7ed3\u6784\uff0c\u4f8b\u5982Python\u7684\u5217\u8868\uff08list\uff09\uff0c\u91c7\u7528\u644a\u8fd8\u5206\u6790\u6765\u5e73\u644a\u52a8\u6001\u6269\u5c55\u7684\u5f00\u9500\u3002\u8fd9\u610f\u5473\u7740\u867d\u7136\u67d0\u4e9b\u64cd\u4f5c\u53ef\u80fd\u4f1a\u82b1\u8d39 O(n) \u7684\u65f6\u95f4\uff0c\u4f46\u8fd9\u4e9b\u5f00\u9500\u5728\u4e00\u7cfb\u5217\u64cd\u4f5c\u4e2d\u88ab\u5206\u644a\uff0c\u5e73\u5747\u4e0b\u6765\u4ecd\u7136\u4fdd\u6301\u8f83\u4f4e\u7684\u590d\u6742\u5ea6\u3002\u8fd9\u53ef\u4ee5\u5728\u4e00\u5b9a\u7a0b\u5ea6\u4e0a\u7f13\u89e3\u6027\u80fd\u95ee\u9898\u3002 \u52a8\u6001\u6269\u5c55\u6570\u7ec4\u4f1a\u5f15\u5165\u4e00\u4e9b\u6027\u80fd\u5f00\u9500\uff0c\u4f46\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u8fd9\u79cd\u5f00\u9500\u901a\u5e38\u662f\u53ef\u4ee5\u63a5\u53d7\u7684\u3002\u4e3a\u4e86\u4f18\u5316\u6027\u80fd\uff0c\u53ef\u4ee5\u8003\u8651\u4ee5\u4e0b\u51e0\u70b9\u7b56\u7565\uff0c\u9700\u8981\u6839\u636e\u5177\u4f53\u5e94\u7528\u7684\u9700\u6c42\u548c\u6027\u80fd\u8981\u6c42\u6765\u6743\u8861\u8fd9\u4e9b\u56e0\u7d20\uff1a \u9884\u5148\u5206\u914d\u8db3\u591f\u7684\u521d\u59cb\u5bb9\u91cf\uff0c\u4ee5\u51cf\u5c11\u6269\u5c55\u7684\u9891\u7387\u3002 \u4f7f\u7528\u644a\u8fd8\u5206\u6790\u6765\u5e73\u644a\u5f00\u9500\u3002 \u8003\u8651\u4f7f\u7528\u5176\u4ed6\u6570\u636e\u7ed3\u6784\uff0c\u5982\u94fe\u8868\uff0c\u5bf9\u63d2\u5165\u548c\u5220\u9664\u64cd\u4f5c\u7684\u6027\u80fd\u66f4\u52a0\u53cb\u597d\u3002 \u4e0b\u9762\uff0c\u5c1d\u8bd5\u5728\u6bcf\u6b21\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u65f6\u628a\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\uff0c\u4ee3\u7801\u5b9e\u73b0\u5982\u4e0b\uff1a # \u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 while logicalSize < DEFAULT_CAPACITY * 2 : logicalSize += 1 if logicalSize == len ( my_array ): # \u89e6\u53d1\u6761\u4ef6 temp = Array ( len ( my_array ) + 1 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 \u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u6765\u6269\u5c55\u6570\u7ec4\u7684\u65b9\u5f0f\u662f\u4e00\u79cd\u5e38\u89c1\u7684\u7b56\u7565\uff0c\u901a\u5e38\u7528\u4e8e\u51cf\u5c11\u52a8\u6001\u6570\u7ec4\u7684\u9891\u7e41\u6269\u5c55\u6b21\u6570\uff0c\u4ee5\u63d0\u9ad8\u6027\u80fd\u3002\u8fd9\u79cd\u65b9\u5f0f\u7684\u64cd\u4f5c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3b\u8981\u53d6\u51b3\u4e8e\u6269\u5c55\u64cd\u4f5c\u7684\u9891\u7387\u548c\u5143\u7d20\u7684\u590d\u5236\u6210\u672c\u3002 \u644a\u8fd8\u5206\u6790\uff1a\u5bf9\u4e8e\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u7684\u7b56\u7565\uff0c\u644a\u8fd8\u5206\u6790\u8868\u660e\uff0c\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u7684\u644a\u8fd8\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662f\u5e38\u6570\u65f6\u95f4\u7684\uff08\u901a\u5e38\u662fO(1)\uff09\uff0c\u8fd9\u610f\u5473\u7740\u5e73\u5747\u4e0b\u6765\uff0c\u6bcf\u6b21\u6269\u5c55\u7684\u5f00\u9500\u662f\u56fa\u5b9a\u7684\uff0c\u800c\u4e0d\u4f1a\u968f\u6570\u7ec4\u7684\u5927\u5c0f\u7ebf\u6027\u589e\u52a0\u3002 \u64cd\u4f5c\u65f6\u95f4\uff1a\u5047\u8bbe\u6570\u7ec4\u9700\u8981\u6269\u5c55\uff0c\u90a3\u4e48\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u9700\u8981\u5206\u914d\u65b0\u7684\u5185\u5b58\u5757\u5e76\u590d\u5236\u73b0\u6709\u5143\u7d20\uff0c\u8fd9\u4e2a\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\uff0c\u5176\u4e2dn\u662f\u6570\u7ec4\u7684\u5f53\u524d\u5927\u5c0f\u3002\u7136\u800c\uff0c\u7531\u4e8e\u6269\u5c55\u64cd\u4f5c\u4e0d\u662f\u6bcf\u6b21\u90fd\u6267\u884c\u7684\uff0c\u800c\u662f\u5f53\u6570\u7ec4\u5df2\u6ee1\u65f6\u624d\u6267\u884c\uff0c\u56e0\u6b64\u53ef\u4ee5\u8ba4\u4e3a\u8fd9\u4e2a\u64cd\u4f5c\u7684\u644a\u8fd8\u65f6\u95f4\u662f\u5e38\u6570\u65f6\u95f4\uff0c\u5373O(1)\u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\uff1a\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u4f1a\u5360\u7528\u989d\u5916\u7684\u5185\u5b58\u7a7a\u95f4\uff0c\u4f46\u968f\u7740\u6570\u7ec4\u7684\u589e\u957f\uff0c\u989d\u5916\u5185\u5b58\u7684\u5360\u7528\u76f8\u5bf9\u4e8e\u6570\u7ec4\u672c\u8eab\u7684\u5927\u5c0f\u6765\u8bf4\u662f\u6709\u9650\u7684\u3002\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u8fd9\u79cd\u5360\u7528\u53ef\u4ee5\u63a5\u53d7\u3002 \u603b\u7ed3\uff0c\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u7684\u7b56\u7565\u53ef\u4ee5\u663e\u8457\u51cf\u5c11\u52a8\u6001\u6570\u7ec4\u7684\u6269\u5c55\u6b21\u6570\uff0c\u4ece\u800c\u63d0\u9ad8\u6027\u80fd\u3002\u867d\u7136\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u53ef\u80fd\u4f1a\u82b1\u8d39\u4e00\u4e9b\u65f6\u95f4\u548c\u989d\u5916\u5185\u5b58\uff0c\u4f46\u8fd9\u4e9b\u5f00\u9500\u5728\u4e00\u7cfb\u5217\u64cd\u4f5c\u4e2d\u88ab\u5e73\u644a\uff0c\u5e73\u5747\u4e0b\u6765\u662f\u5e38\u6570\u65f6\u95f4\u3002\u8fd9\u662f\u4e00\u79cd\u9ad8\u6548\u7684\u52a8\u6001\u6570\u7ec4\u5b9e\u73b0\u65b9\u5f0f\uff0c\u5e38\u89c1\u4e8e\u8bb8\u591a\u7f16\u7a0b\u8bed\u8a00\u7684\u6807\u51c6\u5e93\u4e2d\uff0c\u5305\u62ecPython\u7684\u5217\u8868\uff08list\uff09\u3002 \u5728\u589e\u52a0\u6570\u7ec4\u7684\u957f\u5ea6\u65f6\uff0c\u6bcf\u6b21\u589e\u52a0\u4e00\u4e2a\u5185\u5b58\u5355\u5143\uff0c\u4e0e\u6bcf\u6b21\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u65f6\u628a\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u76f8\u6bd4\uff0c\u540e\u8005\u7684\u65b9\u6cd5\u901a\u5e38\u66f4\u9ad8\u6548\u3002 \u6bcf\u6b21\u589e\u52a0\u4e00\u4e2a\u5185\u5b58\u5355\u5143\uff1a\u8fd9\u79cd\u65b9\u5f0f\u5728\u6bcf\u6b21\u6dfb\u52a0\u65b0\u5143\u7d20\u65f6\u90fd\u9700\u8981\u5206\u914d\u989d\u5916\u7684\u5185\u5b58\uff0c\u5bfc\u81f4\u6570\u7ec4\u5c3a\u5bf8\u7684\u589e\u957f\u662f\u7ebf\u6027\u7684\u3002\u5982\u679c\u9891\u7e41\u6dfb\u52a0\u5143\u7d20\uff0c\u8fd9\u5c06\u5bfc\u81f4\u5927\u91cf\u7684\u5185\u5b58\u5206\u914d\u548c\u6570\u636e\u590d\u5236\u64cd\u4f5c\uff0c\u56e0\u6b64\u65f6\u95f4\u590d\u6742\u5ea6\u4f1a\u53d8\u5f97\u76f8\u5bf9\u8f83\u9ad8\u3002 \u6bcf\u6b21\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u65f6\u628a\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\uff1a\u8fd9\u662f\u4e00\u79cd\u66f4\u9ad8\u6548\u7684\u7b56\u7565\u3002\u5728\u8fd9\u79cd\u65b9\u5f0f\u4e0b\uff0c\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u90fd\u4f1a\u589e\u52a0\u6570\u7ec4\u7684\u5c3a\u5bf8\uff0c\u4f46\u589e\u5e45\u662f\u6307\u6570\u7ea7\u7684\uff0c\u800c\u4e0d\u662f\u7ebf\u6027\u7684\u3002\u8fd9\u610f\u5473\u7740\u968f\u7740\u6570\u7ec4\u7684\u589e\u957f\uff0c\u6269\u5c55\u64cd\u4f5c\u7684\u9891\u7387\u4f1a\u51cf\u5c11\uff0c\u56e0\u4e3a\u6570\u7ec4\u80fd\u591f\u5bb9\u7eb3\u66f4\u591a\u5143\u7d20\u3002\u8fd9\u6837\uff0c\u867d\u7136\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u9700\u8981\u590d\u5236\u66f4\u591a\u7684\u5143\u7d20\uff0c\u4f46\u5b83\u4eec\u7684\u644a\u8fd8\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662f\u5e38\u6570\u65f6\u95f4\uff0c\u56e0\u4e3a\u5b83\u4eec\u4e0d\u662f\u6bcf\u6b21\u90fd\u6267\u884c\u7684\u3002 \u603b\u7ed3\uff0c\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u7684\u7b56\u7565\u901a\u5e38\u66f4\u9ad8\u6548\uff0c\u56e0\u4e3a\u5b83\u53ef\u4ee5\u51cf\u5c11\u9891\u7e41\u7684\u5185\u5b58\u5206\u914d\u548c\u590d\u5236\u64cd\u4f5c\uff0c\u964d\u4f4e\u4e86\u65f6\u95f4\u590d\u6742\u5ea6\u3002\u8fd9\u662f\u8bb8\u591a\u52a8\u6001\u6570\u7ec4\u5b9e\u73b0\u7684\u5e38\u89c1\u505a\u6cd5\uff0c\u5305\u62ecPython\u7684\u5217\u8868\uff08list\uff09\u3002 \u5728 Array \u7c7b\u5b9e\u73b0\u4e2d\uff0c\u662f\u901a\u8fc7\u4e0b\u9762\u4ee3\u7801\u6bb5\u5b9e\u73b0\u7684\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\u589e\u52a0\u7684\uff0c\u5373\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u3002 def grow ( self ): \"\"\"\u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\"\"\" # \u57fa\u4e8e\u5f53\u524d\u7269\u7406\u5c3a\u5bf8\u52a0\u500d\uff0c\u5e76\u5c06fillValue\u8d4b\u503c\u5e95\u5c42\u5217\u8868\u7684\u65b0\u5143\u7d20 for count in range ( len ( self )): self . items . append ( self . fillValue ) 4.2.2.\u51cf\u5c0f\u6570\u7ec4\u7684\u5c3a\u5bf8 \u00b6 \u5982\u679c\u51cf\u5c0f\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\uff0c\u5c31\u4f1a\u6d6a\u8d39\u76f8\u5e94\u7684\u5185\u5b58\u5355\u5143\u3002\u56e0\u6b64\uff0c\u5f53\u5220\u9664\u67d0\u4e00\u4e2a\u5143\u7d20\uff0c\u5982\u679c\u672a\u4f7f\u7528\u7684\u5185\u5b58\u5355\u5143\u6570\u8fbe\u5230\u6216\u8d85\u8fc7\u4e86\u67d0\u4e2a\u9608\u503c\uff08\u5982\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\u7684\u00be\uff09\u65f6\uff0c\u5219\u5e94\u8be5\u51cf\u5c0f\u7269\u7406\u5c3a\u5bf8\u4e86\u3002\u5982\u679c\u6d6a\u8d39\u7684\u5185\u5b58\u8d85\u8fc7\u7279\u5b9a\u9608\u503c\uff0c\u90a3\u4e48Python\u7684list\u7c7b\u578b\u4f1a\u5728\u8c03\u7528 pop \u65b9\u6cd5\u65f6\u6267\u884c\u51cf\u5c0f\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\u7684\u64cd\u4f5c\u3002 \u51cf\u5c0f\u6570\u7ec4\u5c3a\u5bf8\u7684\u8fc7\u7a0b\u4e0e\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u7684\u8fc7\u7a0b\u76f8\u53cd\uff0c\u6b65\u9aa4\u5982\u4e0b\uff1a \u521b\u5efa\u4e00\u4e2a\u66f4\u5c0f\u7684\u65b0\u6570\u7ec4\u3002 \u5c06\u6570\u636e\u4ece\u65e7\u6570\u7ec4\u4e2d\u590d\u5236\u5230\u65b0\u6570\u7ec4\u3002 \u5c06\u6307\u5411\u65e7\u6570\u7ec4\u7684\u53d8\u91cf\u6307\u5411\u65b0\u6570\u7ec4\u5bf9\u8c61\u3002 \u4e0b\u9762\u7684\u4ee3\u7801\u5b9e\u73b0\u4e86\u51cf\u5c0f\u6570\u7ec4\u5c3a\u5bf8\u3002 \u5f53\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u5c0f\u4e8e\u6216\u7b49\u4e8e\u5176\u7269\u7406\u5c3a\u5bf8\u7684\u00bc\uff0c\u5e76\u4e14\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u81f3\u5c11\u662f\u8fd9\u4e2a\u6570\u7ec4\u5efa\u7acb\u65f6\u9ed8\u8ba4\u5bb9\u91cf\u76842\u500d\u65f6\uff0c\u5219\u4e0b\u9762\u7684\u7b97\u6cd5\u628a\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u51cf\u5c0f\u5230\u539f\u6765\u7684\u4e00\u534a\uff0c\u5e76\u4e14\u4e5f\u4e0d\u4f1a\u5c0f\u4e8e\u5176\u9ed8\u8ba4\u5bb9\u91cf\u3002 # \u51cf\u5c0f\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 while logicalSize > len ( my_array ) // 4 : logicalSize -= 1 if logicalSize <= len ( my_array ) // 4 and len ( my_array ) >= DEFAULT_CAPACITY * 2 : # \u89e6\u53d1\u6761\u4ef6 temp = Array ( len ( my_array ) // 2 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 \u6309\u7167\u4e0a\u9762\u7b97\u6cd5\u51cf\u5c11\u6570\u7ec4\u7684\u5c3a\u5bf8\uff0c\u6211\u4eec\u53ef\u4ee5\u5206\u6790\u5176\u65f6\u95f4\u548c\u7a7a\u95f4\u590d\u6742\u5ea6\u5982\u4e0b\uff1a \u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u4e3b\u8981\u6d89\u53ca\u4e24\u4e2a\u64cd\u4f5c\uff1a \u521b\u5efa\u65b0\u6570\u7ec4\u5e76\u5c06\u5143\u7d20\u4ece\u65e7\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\uff1b \u5c06\u65e7\u6570\u7ec4\u5f15\u7528\u66f4\u6539\u4e3a\u65b0\u6570\u7ec4\u3002 \u590d\u5236\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\uff0c\u53ef\u4ee5\u8868\u793a\u4e3a O(n) \uff0c\u5176\u4e2d n \u662f\u6570\u7ec4\u7684\u5f53\u524d\u7269\u7406\u5c3a\u5bf8\u3002\u5f15\u7528\u66f4\u6539\u662f\u4e00\u4e2a\u5e38\u6570\u65f6\u95f4\u64cd\u4f5c\uff0c\u4e0d\u5f71\u54cd\u65f6\u95f4\u590d\u6742\u5ea6\u3002\u6240\u4ee5\uff0c\u6574\u4f53\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\uff1a\u7a7a\u95f4\u590d\u6742\u5ea6\u4e5f\u6d89\u53ca\u4e24\u4e2a\u65b9\u9762\uff1a \u521b\u5efa\u65b0\u6570\u7ec4\u7684\u5185\u5b58\u6d88\u8017\uff0c\u5176\u7a7a\u95f4\u590d\u6742\u5ea6\u662fO(N)\uff1b \u5f15\u7528\u66f4\u6539\u6240\u9700\u7684\u5e38\u6570\u989d\u5916\u7a7a\u95f4\uff0c\u901a\u5e38\u5ffd\u7565\u4e0d\u8ba1\u3002 \u6240\u4ee5\uff0c\u603b\u7684\u7a7a\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002 \u8fd9\u4e2a\u7b97\u6cd5\u7b56\u7565\u4f1a\u5728\u9002\u5f53\u7684\u65f6\u5019\u51cf\u5c0f\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\uff0c\u4ee5\u51cf\u5c11\u5185\u5b58\u5360\u7528\uff0c\u4f46\u4ecd\u7136\u4fdd\u6301\u7740\u6570\u7ec4\u7684\u52a8\u6001\u6027\u3002\u65f6\u95f4\u590d\u6742\u5ea6\u548c\u7a7a\u95f4\u590d\u6742\u5ea6\u90fd\u4e0e\u5f53\u524d\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u6210\u7ebf\u6027\u5173\u7cfb\uff0c\u56e0\u6b64\u662f\u7ebf\u6027\u7684\uff0c\u8fd9\u662f\u4e00\u79cd\u6709\u6548\u7684\u7b56\u7565\u6765\u4f18\u5316\u5185\u5b58\u4f7f\u7528\u3002\u540c\u65f6\uff0c\u4fdd\u7559\u4e86\u4e00\u5b9a\u7684\u5197\u4f59\u7a7a\u95f4\uff0c\u4ee5\u907f\u514d\u9891\u7e41\u5730\u6269\u5c55\u548c\u7f29\u5c0f\u6570\u7ec4\uff0c\u4ece\u800c\u63d0\u9ad8\u4e86\u6027\u80fd\u3002 \u4e0b\u9762\u662f\u5728 Array \u7c7b\u4e2d\u5b9e\u73b0\u51cf\u5c0f\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u7684\u4ee3\u7801\u3002 def shrink ( self ): \"\"\" \u51cf\u5c11\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8 \u5f53: - \u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u5c0f\u4e8e\u6216\u7b49\u4e8e\u5176\u7269\u7406\u5c3a\u5bf8\u76841/4 - \u5e76\u4e14\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u81f3\u5c11\u662f\u8fd9\u4e2a\u6570\u7ec4\u5efa\u7acb\u65f6\u9ed8\u8ba4\u5bb9\u91cf\u76842\u500d\u65f6 \u5219\u628a\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u51cf\u5c0f\u5230\u539f\u6765\u7684\u4e00\u534a\uff0c\u5e76\u4e14\u4e5f\u4e0d\u4f1a\u5c0f\u4e8e\u5176\u9ed8\u8ba4\u5bb9\u91cf \"\"\" # \u5728\u903b\u8f91\u5c3a\u5bf8\u548c\u7269\u7406\u5c3a\u5bf8\u7684\u4e00\u534a\u4e4b\u95f4\u9009\u62e9\u6700\u5927\u503c\u4f5c\u4e3a\u6570\u7ec4\u6536\u7f29\u540e\u7684\u7269\u7406\u5c3a\u5bf8 newSize = max ( self . capacity , len ( self ) // 2 ) # \u91ca\u653e\u591a\u4f59\u7684\u6570\u7ec4\u7a7a\u95f4 for count in range ( len ( self ) - newSize ): self . items . pop () 4.2.3.\u5c06\u5143\u7d20\u63d2\u5165\u589e\u5927\u7684\u6570\u7ec4 \u00b6 \u628a\u5143\u7d20\u63d2\u5165\u6570\u7ec4\u4e2d\u548c\u66ff\u6362\u6570\u7ec4\u91cc\u7684\u5143\u7d20\u662f\u4e0d\u4e00\u6837\u7684\u3002 \u66ff\u6362\u6570\u7ec4\u5143\u7d20\u65f6\uff0c\u5143\u7d20\u5df2\u5728\u4e00\u4e2a\u7ed9\u5b9a\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0c\u5bf9\u8fd9\u4e2a\u4f4d\u7f6e\u8fdb\u884c\u7b80\u5355\u590d\u5236\u5373\u53ef\uff0c\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u5e76\u4e0d\u4f1a\u6539\u53d8\u3002 \u63d2\u5165\u6570\u7ec4\u5143\u7d20\u65f6\uff0c\u9700\u8981\u5b8c\u6210\u4e0b\u97624\u4e2a\u6b65\u9aa4\uff1a \u5728\u63d2\u5165\u5143\u7d20\u4e4b\u524d\u5148\u68c0\u67e5\u53ef\u4ee5\u4f7f\u7528\u7684\u7a7a\u95f4\uff0c\u6839\u636e\u9700\u8981\u6765\u589e\u5927\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u3002 \u5c06\u6570\u7ec4\u91cc\u4ece\u903b\u8f91\u7ed3\u5c3e\u5230\u76ee\u6807\u7d22\u5f15\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u4f1a\u5728\u76ee\u6807\u7d22\u5f15\u4f4d\u7f6e\u5904\u4e3a\u65b0\u5143\u7d20\u7559\u4e0b\u4e00\u4e2a\u7a7a\u683c\u3002 \u5c06\u65b0\u5143\u7d20\u5206\u914d\u5230\u76ee\u6807\u7d22\u5f15\u4f4d\u7f6e\u3002 \u5c06\u903b\u8f91\u5c3a\u5bf8\u52a01\u3002 4.2.4.\u4ece\u6570\u7ec4\u91cc\u5220\u9664\u5143\u7d20 \u00b6 4.2.5.\u590d\u6742\u5ea6\u7684\u6743\u8861\uff1a\u65f6\u95f4\u3001\u7a7a\u95f4\u548c\u6570\u7ec4 \u00b6 4.2.6.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u63d2\u5165\u6216\u5220\u9664\u7ed9\u5b9a\u5143\u7d20\u65f6\u5fc5\u987b\u8981\u79fb\u52a8\u6570\u7ec4\u91cc\u7684\u67d0\u4e9b\u5143\u7d20\u3002 2\uff0e\u5728\u63d2\u5165\u8fc7\u7a0b\u4e2d\uff0c\u79fb\u52a8\u6570\u7ec4\u5143\u7d20\u65f6\uff0c\u8981\u5148\u79fb\u52a8\u54ea\u4e2a\u5143\u7d20\uff1f\u5148\u79fb\u52a8\u63d2\u5165\u4f4d\u7f6e\u7684\u5143\u7d20\uff0c\u8fd8\u662f\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff1f\u4e3a\u4ec0\u4e48\uff1f 3\uff0e\u5982\u679c\u63d2\u5165\u4f4d\u7f6e\u662f\u6570\u7ec4\u7684\u903b\u8f91\u672b\u5c3e\uff0c\u8bf7\u8bf4\u660e\u8fd9\u4e2a\u63d2\u5165\u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u590d\u6742\u5ea6\u3002 4\uff0e\u5047\u8bbe\u6570\u7ec4\u5f53\u524d\u5305\u542b14\u4e2a\u5143\u7d20\uff0c\u5b83\u7684\u8d1f\u8f7d\u56e0\u5b50\u4e3a0.70\uff0c\u90a3\u4e48\u5b83\u7684\u7269\u7406\u5bb9\u91cf\u662f\u591a\u5c11\uff1f 4.3.\u4e8c\u7ef4\u6570\u7ec4\uff08\u7f51\u683c\uff09 \u00b6 4.3.1.\u4f7f\u7528\u7f51\u683c \u00b6 4.3.2.\u521b\u5efa\u5e76\u521d\u59cb\u5316\u7f51\u683c \u00b6 4.3.3.\u5b9a\u4e49Grid\u7c7b \u00b6 4.3.4.\u53c2\u5dee\u4e0d\u9f50\u7684\u7f51\u683c\u548c\u591a\u7ef4\u6570\u7ec4 \u00b6 4.3.5.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u4ec0\u4e48\u662f\u4e8c\u7ef4\u6570\u7ec4\uff08\u7f51\u683c\uff09\uff1f 2\uff0e\u8bf7\u63cf\u8ff0\u4e00\u4e2a\u53ef\u80fd\u4f1a\u7528\u5230\u4e8c\u7ef4\u6570\u7ec4\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 3\uff0e\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u4f7f\u4e4b\u53ef\u4ee5\u5728Grid\u5bf9\u8c61\u91cc\u641c\u7d22\u4e00\u4e2a\u8d1f\u6574\u6570\u3002\u5faa\u73af\u5e94\u8be5\u5728\u9047\u5230\u7f51\u683c\u91cc\u7684\u7b2c\u4e00\u4e2a\u8d1f\u6574\u6570\u7684\u5730\u65b9\u7ec8\u6b62\uff0c\u8fd9\u65f6\u53d8\u91cfrow\u548ccolumn\u5e94\u8be5\u88ab\u8bbe\u7f6e\u4e3a\u8fd9\u4e2a\u8d1f\u6570\u7684\u4f4d\u7f6e\u3002\u5982\u679c\u5728\u7f51\u683c\u91cc\u627e\u4e0d\u5230\u8d1f\u6570\uff0c\u90a3\u4e48\u53d8\u91cfrow\u548ccolumn\u5e94\u8be5\u7b49\u4e8e\u7f51\u683c\u7684\u884c\u6570\u548c\u5217\u6570\u3002 4\uff0e\u8bf4\u8bf4\u8fd0\u884c\u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u540e\u7f51\u683c\u91cc\u7684\u5185\u5bb9\u662f\u4ec0\u4e48\u3002 matrix = Grid ( 3 , 3 ) for row in range ( matrix . getHeight ()): for column in range ( matrix . getWidth ()): matrix [ row ][ column ] = row * column 5\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\u4ee5\u521b\u5efa\u4e00\u4e2a\u53c2\u5dee\u4e0d\u9f50\u7684\u7f51\u683c\uff0c\u5b83\u7684\u884c\u5206\u522b\u7528\u6765\u5b58\u50a83\u4e2a\u30016\u4e2a\u548c9\u4e2a\u5143\u7d20\u3002 6\uff0e\u63d0\u4f9b\u4e00\u4e2a\u628aGrid\u7c7b\u7528\u4f5c\u6570\u636e\u7ed3\u6784\u6765\u5b9e\u73b0\u4e09\u7ef4array\u7c7b\u7684\u7b56\u7565\u3002 7\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\uff1a\u8fd9\u6bb5\u4ee3\u7801\u4f1a\u628a\u4e09\u7ef4\u6570\u7ec4\u91cc\u6bcf\u4e2a\u5355\u5143\u7684\u503c\u90fd\u521d\u59cb\u5316\u4e3a\u5b83\u76843\u4e2a\u7d22\u5f15\u4f4d\u7f6e\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4f4d\u7f6e\u662f\uff08\u6df1\u5ea6\u3001\u884c\u3001\u5217\uff09\uff0c\u5219\u5bf9\u4e8e\u4f4d\u7f6e\uff082\u30013\u30013\uff09\u6765\u8bf4\uff0c\u5b83\u7684\u503c\u5c31\u662f233\u3002 8\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\uff1a\u8fd9\u6bb5\u4ee3\u7801\u53ef\u4ee5\u663e\u793a\u51fa\u4e09\u7ef4\u6570\u7ec4\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u6253\u5370\u51fa\u7684\u6bcf\u4e00\u884c\u6570\u636e\u90fd\u5e94\u8be5\u4ee3\u8868\u7ed9\u5b9a\u884c\u548c\u5217\u91cc\u7684\u6240\u6709\u5143\u7d20\uff0c\u800c\u6df1\u5ea6\u5c06\u4ece\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u5411\u540e\u9012\u5f52\u5230\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u3002\u904d\u5386\u5e94\u8be5\u4ece\u7b2c1\u884c\u3001\u7b2c1\u5217\u4ee5\u53ca\u7b2c\u4e00\u4e2a\u6df1\u5ea6\u4f4d\u7f6e\u5f00\u59cb\uff0c\u4f9d\u6b21\u904d\u5386\u6240\u6709\u7684\u6df1\u5ea6\u3001\u5217\u548c\u884c\u3002 4.4.\u94fe\u63a5\u7ed3\u6784 \u00b6 4.4.1.\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u548c\u53cc\u5411\u94fe\u63a5\u7ed3\u6784 \u00b6 4.4.2.\u975e\u8fde\u7eed\u5185\u5b58\u548c\u8282\u70b9 \u00b6 4.4.3.\u5b9a\u4e49\u5355\u5411\u94fe\u63a5\u8282\u70b9\u7c7b \u00b6 4.4.4.\u4f7f\u7528\u5355\u5411\u94fe\u63a5\u8282\u70b9\u7c7b \u00b6 4.4.5.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u7528\u6846\u548c\u6307\u9488\u7ed8\u5236\u6d4b\u8bd5\u7a0b\u5e8f\u91cc\u7b2c\u4e00\u4e2a\u5faa\u73af\u6240\u521b\u5efa\u7684\u8282\u70b9\u7684\u793a\u610f\u56fe\u3002 2\uff0e\u5f53\u8282\u70b9\u53d8\u91cf\u5f15\u7528\u7684\u662fNone\u65f6\uff0c\u5982\u679c\u7a0b\u5e8f\u5458\u5c1d\u8bd5\u8bbf\u95ee\u8282\u70b9\u7684\u6570\u636e\u5b57\u6bb5\uff0c\u5219\u4f1a\u53d1\u751f\u4ec0\u4e48\uff1f\u5982\u4f55\u9632\u6b62\u8fd9\u79cd\u60c5\u51b5\u7684\u53d1\u751f\uff1f 3\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\uff1a\u8fd9\u6bb5\u4ee3\u7801\u4f1a\u628a\u4e00\u4e2a\u88ab\u586b\u6ee1\u7684\u6570\u7ec4\u91cc\u7684\u5143\u7d20\u90fd\u8f6c\u79fb\u4e3a\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u6570\u636e\u3002\u8fd9\u4e2a\u64cd\u4f5c\u5e94\u4fdd\u7559\u5143\u7d20\u7684\u987a\u5e8f\u4e0d\u53d8\u3002 4.5.\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4e0a\u7684\u64cd\u4f5c \u00b6 4.5.1.\u904d\u5386 \u00b6 4.5.2.\u641c\u7d22 \u00b6 4.5.3.\u66ff\u6362 \u00b6 4.5.4.\u5728\u5f00\u59cb\u5904\u63d2\u5165 \u00b6 4.5.5.\u5728\u7ed3\u5c3e\u5904\u63d2\u5165 \u00b6 4.5.6.\u5728\u5f00\u59cb\u5904\u5220\u9664 \u00b6 4.5.7.\u5728\u7ed3\u5c3e\u5904\u5220\u9664 \u00b6 4.5.8.\u5728\u4efb\u610f\u4f4d\u7f6e\u5904\u63d2\u5165 \u00b6 4.5.9.\u5728\u4efb\u610f\u4f4d\u7f6e\u5904\u5220\u9664 \u00b6 4.5.10.\u590d\u6742\u5ea6\u7684\u6743\u8861\uff1a\u65f6\u95f4\u3001\u7a7a\u95f4\u548c\u5355\u5411\u94fe\u63a5\u7ed3\u6784 \u00b6 4.5.11.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u5047\u8bbe\u5df2\u7ecf\u627e\u5230\u4e86\u4ece\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u5220\u9664\u5143\u7d20\u7684\u4f4d\u7f6e\uff0c\u8bf7\u8bf4\u660e\u4ece\u8fd9\u4e2a\u65f6\u5019\u5f00\u59cb\u5b8c\u6210\u5220\u9664\u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u590d\u6742\u5ea6\u3002 2\uff0e\u53ef\u4ee5\u5bf9\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u6309\u987a\u5e8f\u6392\u5217\u7684\u5143\u7d20\u6267\u884c\u4e8c\u5206\u641c\u7d22\u5417\uff1f\u5982\u679c\u4e0d\u53ef\u4ee5\uff0c\u4e3a\u4ec0\u4e48\uff1f 3\uff0e\u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48Python\u5217\u8868\u4f1a\u4f7f\u7528\u6570\u7ec4\u800c\u4e0d\u662f\u94fe\u63a5\u7ed3\u6784\u6765\u4fdd\u5b58\u5b83\u7684\u5143\u7d20\u3002 4.6.\u94fe\u63a5\u4e0a\u7684\u53d8\u5316 \u00b6 4.6.1.\u5305\u542b\u865a\u62df\u5934\u8282\u70b9\u7684\u73af\u72b6\u94fe\u63a5\u7ed3\u6784 \u00b6 4.6.2.\u53cc\u5411\u94fe\u63a5\u7ed3\u6784 \u00b6 4.6.3.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u5305\u542b\u865a\u62df\u5934\u8282\u70b9\u7684\u73af\u72b6\u94fe\u63a5\u7ed3\u6784\u7ed9\u7a0b\u5e8f\u5458\u5e26\u6765\u4e86\u4ec0\u4e48\u597d\u5904\uff1f 2\uff0e\u548c\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u76f8\u6bd4\uff0c\u8bf7\u63cf\u8ff0\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u4e00\u4e2a\u597d\u5904\u548c\u4e00\u4e2a\u989d\u5916\u5f00\u9500\u3002 4.7.\u5c0f\u7ed3 \u00b6 \u6570\u636e\u7ed3\u6784\u662f\u4e00\u4e2a\u8868\u793a\u591a\u9879\u96c6\u91cc\u6240\u5305\u542b\u6570\u636e\u7684\u5bf9\u8c61\u3002 \u6570\u7ec4\u662f\u4e00\u79cd\u5728\u5e38\u6570\u65f6\u95f4\u5185\u652f\u6301\u5bf9\u4f4d\u7f6e\u9010\u9879\u968f\u673a\u8bbf\u95ee\u7684\u6570\u636e\u7ed3\u6784\u3002\u5728\u521b\u5efa\u6570\u7ec4\u65f6\uff0c\u4f1a\u4e3a\u5b83\u5206\u914d\u82e5\u5e72\u4e2a\u7528\u6765\u5b58\u653e\u6570\u636e\u7684\u5185\u5b58\u7a7a\u95f4\uff0c\u5e76\u4e14\u6570\u7ec4\u7684\u957f\u5ea6\u4f1a\u4fdd\u6301\u4e0d\u53d8\u3002\u63d2\u5165\u548c\u5220\u9664\u64cd\u4f5c\u9700\u8981\u79fb\u52a8\u6570\u636e\u5143\u7d20\uff0c\u5e76\u4e14\u53ef\u80fd\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u3001\u66f4\u5927\u6216\u66f4\u5c0f\u7684\u6570\u7ec4\u3002 \u4e8c\u7ef4\u6570\u7ec4\u91cc\u7684\u6bcf\u4e2a\u6570\u636e\u503c\u90fd\u4f4d\u4e8e\u77e9\u5f62\u7f51\u683c\u7684\u884c\u548c\u5217\u4e0a\u3002 \u94fe\u63a5\u7ed3\u6784\u662f\u75310\u4e2a\u6216\u591a\u4e2a\u8282\u70b9\u7ec4\u6210\u7684\u6570\u636e\u7ed3\u6784\u3002\u6bcf\u4e2a\u8282\u70b9\u90fd\u5305\u542b\u4e00\u4e2a\u6570\u636e\u5143\u7d20\u548c\u4e00\u4e2a\u6216\u591a\u4e2a\u6307\u5411\u5176\u4ed6\u8282\u70b9\u7684\u94fe\u63a5\u3002 \u5355\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u8282\u70b9\u5305\u542b\u6570\u636e\u5143\u7d20\u548c\u5230\u4e0b\u4e00\u4e2a\u8282\u70b9\u7684\u94fe\u63a5\u3002\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u8282\u70b9\u8fd8\u5305\u542b\u5230\u524d\u4e00\u4e2a\u8282\u70b9\u7684\u94fe\u63a5\u3002 \u5728\u94fe\u63a5\u7ed3\u6784\u91cc\u8fdb\u884c\u63d2\u5165\u6216\u5220\u9664\u64cd\u4f5c\u4e0d\u9700\u8981\u79fb\u52a8\u6570\u636e\u5143\u7d20\uff0c\u6bcf\u6b21\u6700\u591a\u53ea\u4f1a\u521b\u5efa\u4e00\u4e2a\u8282\u70b9\u3002\u4f46\u662f\uff0c\u5728\u94fe\u63a5\u7ed3\u6784\u91cc\u6267\u884c\u63d2\u5165\u3001\u5220\u9664\u548c\u8bbf\u95ee\u64cd\u4f5c\u9700\u8981\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662f\u7ebf\u6027\u7684\u3002 \u5728\u94fe\u63a5\u7ed3\u6784\u91cc\u4f7f\u7528\u5934\u8282\u70b9\u53ef\u4ee5\u7b80\u5316\u67d0\u4e9b\u64cd\u4f5c\uff0c\u5982\u6dfb\u52a0\u6216\u5220\u9664\u5143\u7d20\u3002 4.8.\u590d\u4e60\u9898 \u00b6 1\uff0e\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784\u90fd\u662f\uff1a \u62bd\u8c61\u6570\u636e\u7c7b\u578b\uff08ADT\uff09 \u6570\u636e\u7ed3\u6784 2\uff0e\u6570\u7ec4\u7684\u957f\u5ea6\uff1a \u5728\u521b\u5efa\u4e4b\u540e\u5927\u5c0f\u662f\u56fa\u5b9a\u7684 \u5728\u521b\u5efa\u4e4b\u540e\u5927\u5c0f\u53ef\u4ee5\u589e\u52a0\u6216\u51cf\u5c11 3\uff0e\u5728\u6570\u7ec4\u91cc\u8fdb\u884c\u968f\u673a\u8bbf\u95ee\u652f\u6301\u5728\uff1a \u5e38\u6570\u65f6\u95f4\u91cc\u8bbf\u95ee\u6570\u636e \u7ebf\u6027\u65f6\u95f4\u91cc\u8bbf\u95ee\u6570\u636e 4\uff0e\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u6570\u636e\u5305\u542b\u5728\uff1a \u5355\u5143\u91cc \u8282\u70b9\u91cc 5\uff0e\u5bf9\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u6267\u884c\u7684\u5927\u591a\u6570\u64cd\u4f5c\u90fd\u9700\u8981\uff1a \u5e38\u6570\u65f6\u95f4 \u7ebf\u6027\u65f6\u95f4 6\uff0e\u4ece\u4ee5\u4e0b\u54ea\u79cd\u7c7b\u578b\u91cc\u5220\u9664\u7b2c\u4e00\u4e2a\u5143\u7d20\u9700\u8981\u5e38\u6570\u65f6\u95f4\uff1a \u6570\u7ec4 \u5355\u5411\u94fe\u63a5\u7ed3\u6784 7\uff0e\u5728\u4e0b\u9762\u54ea\u79cd\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u91cc\u4f7f\u7528\u7684\u5185\u5b58\u4f1a\u5c11\u4e8e\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u7684\uff1a \u4e0d\u5230\u4e00\u534a\u7684\u4f4d\u7f6e\u653e\u7f6e\u4e86\u6570\u636e \u4e00\u534a\u4ee5\u4e0a\u7684\u4f4d\u7f6e\u653e\u7f6e\u4e86\u6570\u636e 8\uff0e\u5f53\u6570\u7ec4\u7684\u5185\u5b58\u4e0d\u8db3\u4ee5\u4fdd\u5b58\u6570\u636e\u65f6\uff0c\u6700\u597d\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u6570\u7ec4\uff0c\u8fd9\u4e2a\u65b0\u6570\u7ec4\u5e94\u8be5\uff1a \u5927\u5c0f\u6bd4\u65e7\u6570\u7ec4\u591a1\u4e2a\u4f4d\u7f6e \u5927\u5c0f\u662f\u65e7\u6570\u7ec4\u76842\u500d 9\uff0e\u5bf9\u4e8e\u5355\u5411\u94fe\u63a5\u7ed3\u6784\uff0c\u5f53\u4f60\u5728\u4ec0\u4e48\u5730\u65b9\u6267\u884c\u63d2\u5165\u64cd\u4f5c\u4f1a\u5f97\u5230\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u8fd0\u884c\u65f6\uff1a \u5728\u7ed3\u6784\u7684\u5f00\u5934 \u5728\u7ed3\u6784\u7684\u672b\u5c3e 10\uff0e\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u8ba9\u7a0b\u5e8f\u5458\u53ef\u4ee5\u79fb\u52a8\u5230\uff1a \u7ed9\u5b9a\u8282\u70b9\u7684\u540e\u4e00\u4e2a\u8282\u70b9\u6216\u524d\u4e00\u4e2a\u8282\u70b9 \u7ed9\u5b9a\u8282\u70b9\u7684\u540e\u4e00\u4e2a\u8282\u70b9 4.9.\u7f16\u7a0b\u7ec3\u4e60 \u00b6 \u5728\u524d6\u4e2a\u9879\u76ee\u91cc\uff0c\u4f60\u5c06\u4fee\u6539\u5728\u672c\u7ae0\u5b9a\u4e49\u7684Array\u7c7b\uff0c\u4ece\u800c\u8ba9\u5b83\u66f4\u50cfPython\u7684list\u7c7b\u3002\u5bf9\u4e8e\u8fd9\u4e9b\u9879\u76ee\u7684\u7b54\u6848\uff0c\u8bf7\u5305\u542b\u4f60\u5bf9Array\u7c7b\u6240\u505a\u4fee\u6539\u7684\u4ee3\u7801\u6d4b\u8bd5\u3002 1\uff0e\u4e3aArray\u7c7b\u6dfb\u52a0\u4e00\u4e2a\u5b9e\u4f8b\u53d8\u91cf logicalSize \u3002\u8fd9\u4e2a\u53d8\u91cf\u7684\u521d\u59cb\u503c\u4e3a 0 \uff0c\u7528\u6765\u8bb0\u5f55\u6570\u7ec4\u91cc\u5f53\u524d\u5df2\u7ecf\u5305\u542b\u7684\u5143\u7d20\u6570\u91cf\u3002\u7136\u540e\u4e3aArray\u7c7b\u6dfb\u52a0 size() \u65b9\u6cd5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u7528\u6765\u8fd4\u56de\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u3002 __len__ \u65b9\u6cd5\u4f9d\u7136\u4f1a\u8fd4\u56de\u6570\u7ec4\u7684\u5bb9\u91cf\uff0c\u4e5f\u5c31\u662f\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u3002 2\uff0e\u4e3aArray\u7c7b\u7684 __getitem__ \u548c_ _setitem__ \u65b9\u6cd5\u6dfb\u52a0\u5148\u9a8c\u6761\u4ef6\u3002\u5b83\u4eec\u7684\u5148\u9a8c\u6761\u4ef6\u662f 0<=index < size() \u3002\u5982\u679c\u4e0d\u6ee1\u8db3\u5148\u9a8c\u6761\u4ef6\uff0c\u5c31\u5f15\u53d1\u5f02\u5e38\u3002 3\uff0e\u5c06 grow \u548c shrink \u65b9\u6cd5\u6dfb\u52a0\u5230Array\u7c7b\u3002\u5b83\u4eec\u80fd\u591f\u57fa\u4e8e\u672c\u7ae0\u6240\u8ba8\u8bba\u7684\u7b56\u7565\u6765\u589e\u52a0\u6216\u51cf\u5c11\u6570\u7ec4\u91cc\u6240\u5305\u542b\u7684\u5217\u8868\u957f\u5ea6\u3002\u5728\u5b9e\u73b0\u65f6\uff0c\u8981\u4fdd\u8bc1\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u4e0d\u4f1a\u7f29\u5c0f\u5230\u7528\u6237\u6307\u5b9a\u7684\u5bb9\u91cf\u4e4b\u4e0b\uff0c\u5e76\u4e14\u5728\u589e\u52a0\u6570\u7ec4\u5c3a\u5bf8\u65f6\uff0c\u6570\u7ec4\u7684\u5185\u5b58\u5355\u5143\u5c06\u4f1a\u7528\u9ed8\u8ba4\u503c\u6765\u586b\u5145\u3002 4\uff0e\u5c06\u65b9\u6cd5 insert \u548c pop \u6dfb\u52a0\u5230Array\u7c7b\u4e2d\u3002\u5b83\u4eec\u57fa\u4e8e\u672c\u7ae0\u5df2\u7ecf\u8ba8\u8bba\u8fc7\u7684\u7b56\u7565\uff0c\u5728\u9700\u8981\u7684\u65f6\u5019\u5bf9\u6570\u7ec4\u7684\u957f\u5ea6\u8fdb\u884c\u8c03\u6574\u3002 insert \u65b9\u6cd5\u4f1a\u63a5\u6536\u4e00\u4e2a\u4f4d\u7f6e\u548c\u4e00\u4e2a\u5143\u7d20\u503c\u4f5c\u4e3a\u53c2\u6570\uff0c\u7136\u540e\u628a\u8fd9\u4e2a\u5143\u7d20\u63d2\u5165\u6307\u5b9a\u7684\u4f4d\u7f6e\u3002\u5982\u679c\u4f4d\u7f6e\u5927\u4e8e\u6216\u7b49\u4e8e\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u628a\u5143\u7d20\u63d2\u5165\u6570\u7ec4\u91cc\u5f53\u524d\u53ef\u83b7\u5f97\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u4e4b\u540e\u3002 pop \u65b9\u6cd5\u4f1a\u63a5\u6536\u4e00\u4e2a\u4f4d\u7f6e\u4f5c\u4e3a\u53c2\u6570\uff0c\u7136\u540e\u5220\u9664\u5e76\u8fd4\u56de\u8fd9\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u3002 pop \u65b9\u6cd5\u7684\u5148\u9a8c\u6761\u4ef6\u662f 0<=index < size() \u3002 pop \u65b9\u6cd5\u8fd8\u5e94\u8be5\u628a\u817e\u51fa\u6765\u7684\u6570\u7ec4\u5185\u5b58\u5355\u5143\u91cd\u7f6e\u4e3a\u586b\u5145\u503c\u3002 5\uff0e\u5c06\u65b9\u6cd5 __eq__ \u6dfb\u52a0\u5230Array\u7c7b\u4e2d\u3002\u5f53Array\u5bf9\u8c61\u4f5c\u4e3a == \u8fd0\u7b97\u7b26\u7684\u5de6\u64cd\u4f5c\u6570\u65f6\uff0cPython\u4f1a\u8fd0\u884c\u8fd9\u4e2a\u65b9\u6cd5\u3002\u5982\u679c\u8fd9\u4e2a\u65b9\u6cd5\u7684\u53c2\u6570\u4e5f\u662f\u4e00\u4e2aArray\u5bf9\u8c61\uff0c\u5e76\u4e14\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\u548c\u5de6\u64cd\u4f5c\u6570\u76f8\u540c\uff0c\u4e14\u5728\u4e24\u4e2a\u6570\u7ec4\u91cc\u6bcf\u4e2a\u903b\u8f91\u4f4d\u7f6e\u4e0a\u7684\u5143\u7d20\u90fd\u76f8\u7b49\uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u8fd4\u56de True \uff1b\u5426\u5219\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u8fd4\u56de False \u3002 6\uff0e\u4e3a\u4e86\u8ba9Array\u7c7b\u548c\u5217\u8868\u4e00\u6837\uff0c\u5e94\u8be5\u5220\u9664 __iter__ \u65b9\u6cd5\u7684\u5f53\u524d\u5b9e\u73b0\u3002\u8bf7\u89e3\u91ca\u8fd9\u4e3a\u4ec0\u4e48\u662f\u4e00\u4e2a\u597d\u5efa\u8bae\uff0c\u5e76\u8bf4\u660e\u5728\u8fd9\u4e2a\u60c5\u51b5\u4e0b\u5e94\u8be5\u5982\u4f55\u5bf9 __str__ \u65b9\u6cd5\u8fdb\u884c\u4fee\u6539\u3002 7\uff0e Matrix \u7c7b\u53ef\u4ee5\u6267\u884c\u7ebf\u6027\u4ee3\u6570\u91cc\u7684\u67d0\u4e9b\u8fd0\u7b97\uff0c\u6bd4\u5982\u77e9\u9635\u8fd0\u7b97\u3002\u5f00\u53d1\u4e00\u4e2a\u4f7f\u7528\u5185\u7f6e\u8fd0\u7b97\u7b26\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97\u7684 Matrix \u7c7b\uff0c\u8fd9\u4e2a Matrix \u7c7b\u5e94\u6269\u5c55\u81ea Grid \u7c7b\u3002\u5728\u63a5\u4e0b\u6765\u76844\u4e2a\u9879\u76ee\u91cc\uff0c\u4f60\u5e94\u5b9a\u4e49\u4e00\u4e9b\u7528\u6765\u64cd\u4f5c\u94fe\u63a5\u7ed3\u6784\u7684\u51fd\u6570\u3002\u5728\u89e3\u7b54\u7684\u8fc7\u7a0b\u4e2d\uff0c\u4f60\u5e94\u8be5\u7ee7\u7eed\u4f7f\u7528\u672c\u7ae0\u5b9a\u4e49\u7684 Node \u548c TwoWayNode \u7c7b\u3002\u521b\u5efa\u4e00\u4e2a\u6d4b\u8bd5\u6a21\u5757\u4ee5\u5305\u542b\u4f60\u7684\u51fd\u6570\u5b9a\u4e49\u548c\u7528\u6765\u6d4b\u8bd5\u5b83\u4eec\u7684\u4ee3\u7801\u3002 8\uff0e\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c length \u7684\u51fd\u6570\uff08\u4e0d\u662f len \uff09\uff0c\u8fd9\u4e2a\u51fd\u6570\u4f1a\u63a5\u53d7\u4e00\u4e2a\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u80fd\u591f\u8fd4\u56de\u7ed3\u6784\u91cc\u7684\u5143\u7d20\u6570\u91cf\u3002 9\uff0e\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c insert \u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u5177\u6709\u628a\u5143\u7d20\u63d2\u5165\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4e2d\u6307\u5b9a\u4f4d\u7f6e\u7684\u529f\u80fd\u3002\u8fd9\u4e2a\u51fd\u6570\u67093\u4e2a\u53c2\u6570\uff1a\u5143\u7d20\u3001\u4f4d\u7f6e\u4ee5\u53ca\u4e00\u4e2a\u94fe\u63a5\u7ed3\u6784\uff08\u8fd9\u4e2a\u94fe\u63a5\u7ed3\u6784\u53ef\u80fd\u4e3a\u7a7a\uff09\u3002\u8fd9\u4e2a\u51fd\u6570\u80fd\u591f\u8fd4\u56de\u4fee\u6539\u4e4b\u540e\u7684\u94fe\u63a5\u7ed3\u6784\u3002\u5982\u679c\u4f20\u9012\u7684\u4f4d\u7f6e\u5927\u4e8e\u6216\u7b49\u4e8e\u94fe\u63a5\u7ed3\u6784\u7684\u957f\u5ea6\uff0c\u90a3\u4e48\u8fd9\u4e2a\u51fd\u6570\u4f1a\u628a\u5143\u7d20\u63d2\u5165\u5b83\u7684\u672b\u5c3e\u3002\u8fd9\u4e2a\u51fd\u6570\u7684\u8c03\u7528\u793a\u4f8b\u662f head =insert(1,data,head) \uff0c\u5176\u4e2d head \u662f\u4e00\u4e2a\u53d8\u91cf\uff0c\u8fd9\u4e2a\u53d8\u91cf\u8981\u4e48\u4e3a\u7a7a\u94fe\u63a5\uff0c\u8981\u4e48\u6307\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u7b2c\u4e00\u4e2a\u8282\u70b9\u3002 10\uff0e\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c pop \u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u80fd\u591f\u5728\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u6307\u5b9a\u4f4d\u7f6e\u4e0a\u5220\u9664\u5143\u7d20\u3002\u8fd9\u4e2a\u51fd\u6570\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u4f4d\u7f6e\uff0c\u5b83\u7684\u5148\u9a8c\u6761\u4ef6\u662f 0<=position<\u7ed3\u6784\u7684\u957f\u5ea6 \u3002\u5b83\u7684\u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u4e00\u4e2a\u94fe\u63a5\u7ed3\u6784\uff0c\u5f88\u660e\u663e\u5b83\u4e0d\u5e94\u8be5\u4e3a\u7a7a\u3002\u8fd9\u4e2a\u51fd\u6570\u5c06\u4f1a\u8fd4\u56de\u4e00\u4e2a\u5143\u7ec4\uff0c\u5305\u542b\u4fee\u6539\u540e\u7684\u94fe\u63a5\u7ed3\u6784\u548c\u5220\u9664\u7684\u5143\u7d20\u3002\u5b83\u7684\u8c03\u7528\u793a\u4f8b\u662f (head, item) = pop(1,head) \u3002 11\uff0e\u5b9a\u4e49\u4e00\u4e2a\u51fd\u6570 makeTwoWay \uff0c\u8fd9\u4e2a\u51fd\u6570\u4f1a\u63a5\u53d7\u4e00\u4e2a\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4f5c\u4e3a\u53c2\u6570\uff0c\u7136\u540e\u751f\u6210\u5e76\u8fd4\u56de\u4e00\u4e2a\u5305\u542b\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u5143\u7d20\u7684\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u3002\uff08\u6ce8\u610f\uff1a\u8fd9\u4e2a\u51fd\u6570\u4e0d\u5e94\u8be5\u5bf9\u4f5c\u4e3a\u53c2\u6570\u7684\u94fe\u63a5\u7ed3\u6784\u8fdb\u884c\u4efb\u4f55\u4fee\u6539\u3002\uff09","title":"\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#4","text":"\u6570\u636e\u7ed3\u6784\uff08data structure\uff09\u6216\u5177\u4f53\u6570\u636e\u7c7b\u578b\uff08concrete data type\uff09\u662f\u6307\u4e00\u7ec4\u6570\u636e\u7684\u5185\u90e8\u5b58\u50a8\u65b9\u5f0f\u3002 \u6570\u7ec4\uff08array\uff09\u548c\u94fe\u63a5\u7ed3\u6784\uff08linked structure\uff09\u8fd9\u4e24\u79cd\u6570\u636e\u7ed3\u6784\u662f\u7f16\u7a0b\u8bed\u8a00\u91cc\u591a\u9879\u96c6\u6700\u5e38\u7528\u7684\u5b9e\u73b0\u3002 \u76ee\u6807\uff1a \u521b\u5efa\u6570\u7ec4\uff1b \u5bf9\u6570\u7ec4\u6267\u884c\u5404\u79cd\u64cd\u4f5c\uff1b \u786e\u5b9a\u6570\u7ec4\u76f8\u5173\u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u7684\u4f7f\u7528\u60c5\u51b5\uff1b \u57fa\u4e8e\u6570\u7ec4\u5728\u8ba1\u7b97\u673a\u5185\u5b58\u91cc\u7684\u4e0d\u540c\u5b58\u50a8\u65b9\u5f0f\uff0c\u63cf\u8ff0\u6570\u7ec4\u76f8\u5173\u64cd\u4f5c\u7684\u6210\u672c\u548c\u6536\u76ca\uff1b \u4f7f\u7528\u5355\u5411\u94fe\u63a5\u8282\u70b9\u521b\u5efa\u94fe\u63a5\u7ed3\u6784\uff1b \u5bf9\u7531\u5355\u5411\u94fe\u63a5\u8282\u70b9\u6784\u6210\u7684\u94fe\u63a5\u7ed3\u6784\u6267\u884c\u5404\u79cd\u64cd\u4f5c\uff1b \u57fa\u4e8e\u94fe\u63a5\u7ed3\u6784\u5728\u8ba1\u7b97\u673a\u5185\u5b58\u91cc\u7684\u4e0d\u540c\u5b58\u50a8\u65b9\u5f0f\uff0c\u63cf\u8ff0\u5728\u94fe\u63a5\u7ed3\u6784\u4e0a\u6267\u884c\u76f8\u5173\u64cd\u4f5c\u7684\u6210\u672c\u548c\u6536\u76ca\uff1b \u6bd4\u8f83\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784\u5728\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u4f7f\u7528\u4e0a\u7684\u6743\u8861\uff1b","title":"4.\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#41","text":"\u5173\u4e8e\u6570\u7ec4\uff08array\uff09\uff1a \u6570\u7ec4\u662f\u6307\u5728\u7ed9\u5b9a\u7d22\u5f15\u4f4d\u7f6e\u53ef\u4ee5\u8bbf\u95ee\u548c\u66ff\u6362\u7684\u5143\u7d20\u5e8f\u5217\u3002 Python\u5217\u8868\u7684\u5e95\u5c42\u6570\u636e\u7ed3\u6784\u6b63\u662f\u4e00\u4e2a\u6570\u7ec4\u3002 Python\u4e2d\u6570\u7ec4\u7684\u9650\u5236\u8981\u6bd4\u5217\u8868\u66f4\u591a\u3002\u53ea\u80fd\u5728\u6307\u5b9a\u4f4d\u7f6e\u8bbf\u95ee\u548c\u66ff\u6362\u6570\u7ec4\u4e2d\u7684\u5143\u7d20\u3001\u68c0\u67e5\u6570\u7ec4\u7684\u957f\u5ea6\u3001\u83b7\u53d6\u5b83\u7684\u5b57\u7b26\u4e32\u8868\u8fbe\u5f0f\uff1b\u4e0d\u80fd\u57fa\u4e8e\u4f4d\u7f6e\u6dfb\u52a0\u6216\u5220\u9664\u5143\u7d20\uff1b\u6570\u7ec4\u7684\u957f\u5ea6\u4e5f\u5c31\u662f\u5b83\u7684\u5bb9\u91cf\uff0c\u5728\u521b\u5efa\u4e4b\u540e\u5c31\u662f\u56fa\u5b9a\u7684\u3002","title":"4.1.\u6570\u7ec4\u6570\u636e\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#411","text":"\u901a\u8fc7\u4e0b\u6807\u64cd\u4f5c\u6216\u7d22\u5f15\u64cd\u4f5c\u5b9e\u73b0\u5bf9\u6570\u7ec4\u5728\u6307\u5b9a\u4f4d\u7f6e\u5bf9\u5143\u7d20\u8fdb\u884c\u5b58\u50a8\u6216\u68c0\u7d22\u3002 \u6570\u7ec4\u7d22\u5f15\u662f\u968f\u673a\u8bbf\u95ee\uff08random access\uff09\u64cd\u4f5c\uff0c\u800c\u5728\u968f\u673a\u8bbf\u95ee\u65f6\uff0c\u8ba1\u7b97\u673a\u603b\u4f1a\u6267\u884c\u56fa\u5b9a\u7684\u6b65\u9aa4\u6765\u83b7\u53d6\u7b2c i \u4e2a\u5143\u7d20\u7684\u4f4d\u7f6e\u3002\u56e0\u6b64\uff0c\u4e0d\u8bba\u6570\u7ec4\u6709\u591a\u5927\uff0c\u8bbf\u95ee\u7b2c\u4e00\u4e2a\u5143\u7d20\u6240\u9700\u7684\u65f6\u95f4\u548c\u8bbf\u95ee\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u6240\u9700\u8981\u7684\u65f6\u95f4\u90fd\u662f\u76f8\u540c\u7684\u3002 \u8ba1\u7b97\u673a\u901a\u8fc7\u5206\u914d\u4e00\u5757\u8fde\u7eed\u5185\u5b58\uff08contiguous memory\uff09\u5355\u5143\u6765\u5b58\u50a8\u6570\u7ec4\u91cc\u7684\u5143\u7d20\uff0c\u4ece\u800c\u652f\u6301\u5bf9\u6570\u7ec4\u7684\u968f\u673a\u8bbf\u95ee\u3002 \u7531\u4e8e\u6570\u7ec4\u91cc\u7684\u5143\u7d20\u5730\u5740\u90fd\u662f\u6309\u7167\u6570\u5b57\u987a\u5e8f\u8fdb\u884c\u6392\u5217\u7684\uff0c\u56e0\u6b64\u53ef\u4ee5\u901a\u8fc7\u6dfb\u52a0\u4e24\u4e2a\u503c\u6765\u8ba1\u7b97\u51fa\u6570\u7ec4\u5143\u7d20\u7684\u673a\u5668\u5730\u5740\uff0c\u5b83\u4eec\u662f\u6570\u7ec4\u7684\u57fa\u5730\u5740\uff08base address\uff09\u4ee5\u53ca\u5143\u7d20\u7684\u504f\u79fb\u91cf\uff08offset\uff09\u3002\u5176\u4e2d\uff0c\u6570\u7ec4\u7684\u57fa\u5730\u5740\u5c31\u662f\u7b2c\u4e00\u4e2a\u5143\u7d20\u7684\u673a\u5668\u5730\u5740\uff0c\u800c\u5143\u7d20\u7684\u504f\u79fb\u91cf\u5c31\u662f\u5b83\u7684\u7d22\u5f15\u503c\u518d\u4e58\u4ee5\u4e00\u4e2a\u4ee3\u8868\u6570\u7ec4\u5143\u7d20\u6240\u9700\u5185\u5b58\u5355\u5143\u6570\u7684\u5e38\u91cf\uff08\u5728Python\u91cc\uff0c\u8fd9\u4e2a\u503c\u59cb\u7ec8\u662f1\uff09\u3002 \u7b80\u800c\u8a00\u4e4b\uff0cPython\u6570\u7ec4\u91cc\u7684\u7d22\u5f15\u64cd\u4f5c\u5305\u62ec\u4e0b\u9762\u4e24\u4e2a\u6b65\u9aa4\uff1a \u5f97\u5230\u6570\u7ec4\u5185\u5b58\u5757\u7684\u57fa\u5730\u5740\u3002 \u5c06\u7d22\u5f15\u503c\u6dfb\u52a0\u5230\u8fd9\u4e2a\u5730\u5740\u5e76\u8fd4\u56de\u3002","title":"4.1.1.\u968f\u673a\u8bbf\u95ee\u548c\u8fde\u7eed\u5185\u5b58"},{"location":"python/DataStructure/04_ArrayChain/#412","text":"\u5728\u6bd4\u8f83\u8001\u7684\u7f16\u7a0b\u8bed\u8a00\uff08\u5982FORTRAN\u6216Pascal\uff09\u91cc\uff0c\u6570\u7ec4\u662f\u9759\u6001\u6570\u636e\u7ed3\u6784\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u7684\u957f\u5ea6\u6216\u5bb9\u91cf\u5728\u7f16\u8bd1\u65f6\u5c31\u786e\u5b9a\u4e86\uff0c\u7a0b\u5e8f\u5458\u9700\u8981\u7533\u8bf7\u8db3\u591f\u591a\u7684\u5185\u5b58\u6765\u6ee1\u8db3\u5728\u6570\u7ec4\u91cc\u5b58\u50a8\u53ef\u80fd\u6709\u6700\u5927\u6570\u91cf\u5143\u7d20\u7684\u60c5\u51b5\uff0c\u8fd9\u6837\u505a\u4f1a\u6d6a\u8d39\u5927\u91cf\u7684\u5185\u5b58\u3002 \u50cfJava\u548cC++\u8fd9\u7c7b\u7684\u73b0\u4ee3\u7f16\u7a0b\u8bed\u8a00\u4f1a\u5141\u8bb8\u7a0b\u5e8f\u5458\u521b\u5efa\u52a8\u6001\u6570\u7ec4\uff08dynamic array\uff09\uff0c\u4ece\u800c\u4e3a\u8fd9\u4e2a\u95ee\u9898\u63d0\u4f9b\u4e86\u4e00\u79cd\u8865\u6551\u65b9\u6cd5\u3002\u548c\u9759\u6001\u6570\u7ec4\u76f8\u4f3c\u7684\u662f\uff0c\u52a8\u6001\u6570\u7ec4\u4e5f\u4f1a\u5360\u7528\u4e00\u5757\u8fde\u7eed\u5185\u5b58\uff0c\u5e76\u652f\u6301\u968f\u673a\u8bbf\u95ee\u3002\u52a8\u6001\u6570\u7ec4\u7684\u957f\u5ea6\u53ea\u5728\u8fd0\u884c\u65f6\u624d\u77e5\u9053\uff0c\u5728\u52a8\u6001\u6570\u7ec4\u5b9e\u4f8b\u5316\u7684\u65f6\u5019\u6307\u5b9a\u5b83\u7684\u957f\u5ea6\u3002\u5728Python\u91cc\u5b9e\u73b0\u7684Array\u7c7b\u7684\u884c\u4e3a\u4e5f\u662f\u8fd9\u6837\u7684\u3002 \u6211\u4eec\u53ef\u4ee5\u901a\u8fc7\u53e6\u4e00\u79cd\u65b9\u6cd5\u5728\u8fd0\u884c\u65f6\u6839\u636e\u5e94\u7528\u7a0b\u5e8f\u7684\u6570\u636e\u8981\u6c42\u6765\u8c03\u6574\u6570\u7ec4\u7684\u957f\u5ea6\uff0c\u8fd9\u4e9b\u8c03\u6574\u4f1a\u7531Python\u5217\u8868\u81ea\u52a8\u8fdb\u884c\u3002\u8fd9\u65f6\uff0c\u6570\u7ec4\u6709\u4ee5\u4e0b3\u79cd\u4e0d\u540c\u5f62\u5f0f\u3002 \u5728\u7a0b\u5e8f\u542f\u52a8\u65f6\u521b\u5efa\u4e00\u4e2a\u5177\u6709\u5408\u7406\u9ed8\u8ba4\u5927\u5c0f\u7684\u6570\u7ec4\u3002 \u5f53\u6570\u7ec4\u65e0\u6cd5\u5bb9\u7eb3\u66f4\u591a\u6570\u636e\u65f6\uff0c\u521b\u5efa\u4e00\u4e2a\u66f4\u5927\u7684\u65b0\u6570\u7ec4\uff0c\u5e76\u628a\u65e7\u6570\u7ec4\u91cc\u7684\u6570\u636e\u5143\u7d20\u4f20\u8f93\u7ed9\u5b83\u3002 \u5982\u679c\u6570\u7ec4\u5728\u6d6a\u8d39\u5185\u5b58\uff08\u5e94\u7528\u7a0b\u5e8f\u5220\u9664\u4e86\u4e00\u4e9b\u6570\u636e\uff09\uff0c\u90a3\u4e48\u7528\u7c7b\u4f3c\u7684\u65b9\u5f0f\u51cf\u5c0f\u6570\u7ec4\u7684\u957f\u5ea6\u3002","title":"4.1.2.\u9759\u6001\u5185\u5b58\u548c\u52a8\u6001\u5185\u5b58"},{"location":"python/DataStructure/04_ArrayChain/#413","text":"\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\uff08physical size\uff09\u662f\u6307\u6570\u7ec4\u5355\u5143\u7684\u603b\u6570\uff0c\u6216\u8005\u521b\u5efa\u6570\u7ec4\u65f6\u6307\u5b9a\u5176\u5bb9\u91cf\u7684\u90a3\u4e2a\u6570\u5b57\uff1b \u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\uff08logical size\uff09\u662f\u6307\u5f53\u524d\u5e94\u7528\u7a0b\u5e8f\u4f7f\u7528\u7684\u5143\u7d20\u6570\u91cf\u3002 \u5f53\u6570\u7ec4\u88ab\u586b\u6ee1\u7684\u65f6\u5019\uff0c\u6211\u4eec\u4e0d\u9700\u8981\u62c5\u5fc3\u5b83\u4eec\u7684\u4e0d\u540c\u3002\u5f53\u6570\u7ec4\u88ab\u90e8\u5206\u586b\u6ee1\u7684\u65f6\u5019\uff0c\u672a\u88ab\u586b\u5145\u7684\u5185\u5b58\u5355\u5143\u91cc\u7684\u6570\u636e\u5bf9\u5f53\u524d\u5e94\u7528\u7a0b\u5e8f\u662f\u6ca1\u6709\u7528\u7684\uff0c\u6211\u4eec\u79f0\u4e4b\u5783\u573e\u5185\u5bb9\uff08garbage\uff09\u3002\u5728\u5927\u591a\u6570\u5e94\u7528\u7a0b\u5e8f\u91cc\uff0c\u6211\u4eec\u662f\u8981\u6ce8\u610f\u5bf9\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u8fdb\u884c\u8ffd\u8e2a\u3002\u901a\u5e38\u6765\u8bf4\uff0c\u903b\u8f91\u5c3a\u5bf8\u548c\u7269\u7406\u5c3a\u5bf8\u4f1a\u53cd\u6620\u51fa\u6709\u5173\u6570\u7ec4\u72b6\u6001\u7684\u51e0\u4e2a\u91cd\u70b9\u3002 \u5982\u679c\u903b\u8f91\u5c3a\u5bf8\u4e3a0\uff0c\u90a3\u4e48\u6570\u7ec4\u5c31\u4e3a\u7a7a\u3002\u4e5f\u5c31\u662f\u8bf4\uff0c\u8fd9\u4e2a\u6570\u7ec4\u4e0d\u5305\u542b\u4efb\u4f55\u6570\u636e\u5143\u7d20\u3002 \u5982\u679c\u5e76\u975e\u4e0a\u8ff0\u60c5\u51b5\uff0c\u5728\u4efb\u4f55\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u4e2d\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u7684\u7d22\u5f15\u90fd\u662f\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\u51cf1\u3002 \u5982\u679c\u903b\u8f91\u5c3a\u5bf8\u7b49\u4e8e\u7269\u7406\u5c3a\u5bf8\uff0c\u90a3\u4e48\u8868\u793a\u6570\u7ec4\u5df2\u88ab\u586b\u6ee1\u4e86\u3002","title":"4.1.3.\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8"},{"location":"python/DataStructure/04_ArrayChain/#414","text":"1\uff0e\u8bf7\u8bf4\u660e\u968f\u673a\u8bbf\u95ee\u7684\u5de5\u4f5c\u539f\u7406\uff0c\u4ee5\u53ca\u8fd9\u4e2a\u64cd\u4f5c\u8fd9\u4e48\u5feb\u7684\u539f\u56e0\u3002 \u89e3\u7b54\uff1a\u968f\u673a\u8bbf\u95ee\u662f\u4e00\u79cd\u8ba1\u7b97\u673a\u5b58\u50a8\u7cfb\u7edf\u4e2d\u7684\u8bfb\u53d6\u6216\u5199\u5165\u6570\u636e\u7684\u64cd\u4f5c\uff0c\u5176\u4e2d\u6570\u636e\u53ef\u4ee5\u901a\u8fc7\u76f4\u63a5\u8df3\u8f6c\u5230\u5176\u5b58\u50a8\u4f4d\u7f6e\u800c\u4e0d\u9700\u8981\u987a\u5e8f\u626b\u63cf\u6765\u8bbf\u95ee\u3002\u8fd9\u4e0e\u987a\u5e8f\u8bbf\u95ee\u4e0d\u540c\uff0c\u540e\u8005\u9700\u8981\u6309\u987a\u5e8f\u904d\u5386\u6570\u636e\u4ee5\u627e\u5230\u6240\u9700\u7684\u4fe1\u606f\u3002\u968f\u673a\u8bbf\u95ee\u7684\u5de5\u4f5c\u539f\u7406\u5982\u4e0b\uff1a \u5b58\u50a8\u4ecb\u8d28\uff1a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u786c\u76d8\u7b49\u5b58\u50a8\u8bbe\u5907\u90fd\u652f\u6301\u968f\u673a\u8bbf\u95ee\u3002\u8fd9\u4e9b\u5b58\u50a8\u4ecb\u8d28\u4e2d\u7684\u6570\u636e\u901a\u5e38\u88ab\u5212\u5206\u4e3a\u5757\u6216\u6247\u533a\uff0c\u5e76\u4e14\u6bcf\u4e2a\u5757\u6216\u6247\u533a\u90fd\u6709\u4e00\u4e2a\u552f\u4e00\u7684\u5730\u5740\u6216\u7d22\u5f15\u3002 \u8bbf\u95ee\u5730\u5740\uff1a\u4e3a\u4e86\u8fdb\u884c\u968f\u673a\u8bbf\u95ee\uff0c\u8ba1\u7b97\u673a\u9700\u8981\u77e5\u9053\u8981\u8bbf\u95ee\u7684\u6570\u636e\u7684\u5730\u5740\u3002\u8fd9\u4e2a\u5730\u5740\u53ef\u4ee5\u662f\u5185\u5b58\u4e2d\u7684\u7279\u5b9a\u4f4d\u7f6e\uff0c\u4e5f\u53ef\u4ee5\u662f\u786c\u76d8\u4e0a\u7684\u67d0\u4e2a\u6247\u533a\u7684\u5730\u5740\u3002 \u5bfb\u5740\u548c\u4f20\u8f93\uff1a\u8ba1\u7b97\u673a\u4f7f\u7528\u5b58\u50a8\u8bbe\u5907\u7684\u63a7\u5236\u5668\u6216\u5b58\u50a8\u5668\u7ba1\u7406\u5355\u5143\u6765\u67e5\u627e\u6570\u636e\u7684\u5730\u5740\u3002\u4e00\u65e6\u627e\u5230\u4e86\u6b63\u786e\u7684\u5730\u5740\uff0c\u5b58\u50a8\u8bbe\u5907\u4f1a\u5c06\u6570\u636e\u4f20\u8f93\u5230\u8ba1\u7b97\u673a\u7684\u5185\u5b58\u4e2d\u4f9b\u5904\u7406\u5668\u4f7f\u7528\u3002 \u8bbf\u95ee\u901f\u5ea6\uff1a\u968f\u673a\u8bbf\u95ee\u4e4b\u6240\u4ee5\u5982\u6b64\u5feb\u901f\uff0c\u662f\u56e0\u4e3a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u73b0\u4ee3\u786c\u76d8\u9a71\u52a8\u5668\u7b49\u5b58\u50a8\u8bbe\u5907\u90fd\u7ecf\u8fc7\u4e86\u4f18\u5316\uff0c\u53ef\u4ee5\u5feb\u901f\u54cd\u5e94\u8bbf\u95ee\u8bf7\u6c42\u3002\u8fd9\u4e9b\u8bbe\u5907\u4f7f\u7528\u4e86\u9ad8\u901f\u7f13\u5b58\u3001\u8bfb\u5199\u5934\u3001\u5bfb\u9053\u673a\u6784\u7b49\u6280\u672f\u6765\u6700\u5c0f\u5316\u6570\u636e\u8bbf\u95ee\u7684\u5ef6\u8fdf\u3002 \u539f\u56e0\uff1a \u5b58\u50a8\u8bbe\u5907\u7684\u7269\u7406\u7ed3\u6784\uff1a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u786c\u76d8\u7b49\u5b58\u50a8\u8bbe\u5907\u7684\u7269\u7406\u7ed3\u6784\u88ab\u8bbe\u8ba1\u6210\u53ef\u4ee5\u968f\u673a\u8bbf\u95ee\u7684\u3002\u5185\u5b58\u4e2d\u7684\u6bcf\u4e2a\u5730\u5740\u90fd\u53ef\u4ee5\u77ac\u95f4\u8bbf\u95ee\uff0c\u800c\u786c\u76d8\u4e0a\u7684\u6247\u533a\u4e5f\u53ef\u4ee5\u901a\u8fc7\u78c1\u5934\u5bfb\u9053\u548c\u65cb\u8f6c\u78c1\u76d8\u7b49\u673a\u5236\u8fc5\u901f\u8bbf\u95ee\u3002 \u9ad8\u901f\u7f13\u5b58\uff1a\u73b0\u4ee3\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u5904\u7406\u5668\u90fd\u914d\u5907\u4e86\u9ad8\u901f\u7f13\u5b58\uff08\u4f8b\u5982\uff0cCPU\u7f13\u5b58\uff09\u3002\u8fd9\u4e9b\u9ad8\u901f\u7f13\u5b58\u5b58\u50a8\u4e86\u6700\u8fd1\u8bbf\u95ee\u7684\u6570\u636e\uff0c\u53ef\u4ee5\u5feb\u901f\u63d0\u4f9b\u7ed9\u5904\u7406\u5668\uff0c\u4ece\u800c\u964d\u4f4e\u4e86\u8bbf\u95ee\u5ef6\u8fdf\u3002 \u5b58\u50a8\u5668\u7ba1\u7406\uff1a\u64cd\u4f5c\u7cfb\u7edf\u548c\u5b58\u50a8\u8bbe\u5907\u7684\u63a7\u5236\u5668\u4f1a\u7ba1\u7406\u5b58\u50a8\u5668\u7684\u8bbf\u95ee\uff0c\u4ee5\u786e\u4fdd\u6570\u636e\u53ef\u4ee5\u9ad8\u6548\u5730\u88ab\u8bbf\u95ee\u548c\u4f20\u8f93\u3002\u8fd9\u5305\u62ec\u4e86\u78c1\u76d8\u8c03\u5ea6\u7b97\u6cd5\u3001\u5185\u5b58\u5206\u9875\u7b49\u7b56\u7565\u3002 \u6280\u672f\u8fdb\u6b65\uff1a\u786c\u4ef6\u5236\u9020\u6280\u672f\u7684\u8fdb\u6b65\u548c\u5b58\u50a8\u8bbe\u5907\u7684\u4f18\u5316\u4f7f\u5f97\u968f\u673a\u8bbf\u95ee\u901f\u5ea6\u66f4\u5feb\u3002\u4f8b\u5982\uff0c\u56fa\u6001\u786c\u76d8\uff08SSD\uff09\u7684\u51fa\u73b0\u663e\u8457\u63d0\u9ad8\u4e86\u6570\u636e\u7684\u968f\u673a\u8bbf\u95ee\u901f\u5ea6\u3002 \u603b\u4e4b\uff0c\u968f\u673a\u8bbf\u95ee\u4e4b\u6240\u4ee5\u5982\u6b64\u5feb\u901f\uff0c\u662f\u56e0\u4e3a\u8ba1\u7b97\u673a\u5185\u5b58\u548c\u5b58\u50a8\u8bbe\u5907\u7684\u7269\u7406\u548c\u6280\u672f\u7279\u6027\u4f7f\u5176\u80fd\u591f\u4ee5\u9ad8\u6548\u3001\u8fc5\u901f\u7684\u65b9\u5f0f\u8bbf\u95ee\u6570\u636e\u3002\u8fd9\u79cd\u8bbf\u95ee\u901f\u5ea6\u5bf9\u4e8e\u8ba1\u7b97\u673a\u7684\u6027\u80fd\u548c\u54cd\u5e94\u65f6\u95f4\u81f3\u5173\u91cd\u8981\u3002 2\uff0e\u6570\u7ec4\u548cPython\u5217\u8868\u4e4b\u95f4\u6709\u4ec0\u4e48\u533a\u522b\uff1f \u89e3\u7b54\uff1a\u6570\u7ec4\u548cPython\u5217\u8868\u4e4b\u95f4\u6709\u51e0\u4e2a\u5173\u952e\u533a\u522b\uff0c\u8fd9\u4e9b\u533a\u522b\u5728\u6570\u636e\u7ed3\u6784\u3001\u529f\u80fd\u548c\u7528\u9014\u4e0a\u5b58\u5728\u5dee\u5f02\uff1a \u6570\u636e\u7c7b\u578b\uff1a \u6570\u7ec4\uff1a\u901a\u5e38\u8981\u6c42\u6240\u6709\u5143\u7d20\u5177\u6709\u76f8\u540c\u7684\u6570\u636e\u7c7b\u578b\u3002\u8fd9\u662f\u56e0\u4e3a\u6570\u7ec4\u5728\u5185\u5b58\u4e2d\u4ee5\u7d27\u51d1\u7684\u65b9\u5f0f\u5b58\u50a8\u6570\u636e\uff0c\u9700\u8981\u77e5\u9053\u6bcf\u4e2a\u5143\u7d20\u7684\u5927\u5c0f\u4ee5\u4fbf\u8fdb\u884c\u968f\u673a\u8bbf\u95ee\u3002 Python\u5217\u8868\uff1aPython\u7684\u5217\u8868\u53ef\u4ee5\u5bb9\u7eb3\u4e0d\u540c\u6570\u636e\u7c7b\u578b\u7684\u5143\u7d20\uff0c\u56e0\u4e3a\u5b83\u4eec\u662f\u52a8\u6001\u7c7b\u578b\u7684\u3002 \u5185\u5b58\u7ba1\u7406\uff1a \u6570\u7ec4\uff1a\u901a\u5e38\u5728\u521b\u5efa\u65f6\u9700\u8981\u6307\u5b9a\u56fa\u5b9a\u5927\u5c0f\uff0c\u56e0\u6b64\u5728\u5185\u5b58\u4e2d\u4f1a\u5206\u914d\u4e00\u5757\u8fde\u7eed\u7684\u7a7a\u95f4\uff0c\u8fd9\u4f7f\u5f97\u6570\u7ec4\u5bf9\u4e8e\u9ad8\u6548\u7684\u968f\u673a\u8bbf\u95ee\u975e\u5e38\u9002\u7528\u3002 Python\u5217\u8868\uff1aPython\u7684\u5217\u8868\u662f\u52a8\u6001\u7684\uff0c\u5b83\u4eec\u53ef\u4ee5\u6839\u636e\u9700\u8981\u81ea\u52a8\u6269\u5c55\u6216\u7f29\u5c0f\u3002\u8fd9\u5bfc\u81f4\u4e86\u4e00\u4e9b\u989d\u5916\u7684\u5185\u5b58\u5f00\u9500\uff0c\u56e0\u4e3a\u5217\u8868\u9700\u8981\u66f4\u591a\u7684\u7a7a\u95f4\u6765\u7ba1\u7406\u5143\u7d20\u7684\u6dfb\u52a0\u548c\u5220\u9664\u3002 \u6027\u80fd\uff1a \u6570\u7ec4\uff1a\u7531\u4e8e\u5185\u5b58\u5e03\u5c40\u8fde\u7eed\uff0c\u56e0\u6b64\u6570\u7ec4\u901a\u5e38\u5728\u8bbf\u95ee\u5143\u7d20\u65f6\u66f4\u5feb\u3002\u6570\u7ec4\u8fd8\u652f\u6301\u66f4\u591a\u7684\u5e95\u5c42\u64cd\u4f5c\uff0c\u5982\u4f4d\u64cd\u4f5c\u3002 Python\u5217\u8868\uff1aPython\u5217\u8868\u66f4\u52a0\u7075\u6d3b\uff0c\u4f46\u5728\u67d0\u4e9b\u60c5\u51b5\u4e0b\u53ef\u80fd\u4f1a\u5bfc\u81f4\u6027\u80fd\u4e0b\u964d\uff0c\u7279\u522b\u662f\u5f53\u6d89\u53ca\u5927\u91cf\u5143\u7d20\u7684\u63d2\u5165\u548c\u5220\u9664\u64cd\u4f5c\u65f6\u3002 \u64cd\u4f5c\u548c\u65b9\u6cd5\uff1a \u6570\u7ec4\uff1a\u901a\u5e38\u63d0\u4f9b\u4e00\u7ec4\u57fa\u672c\u64cd\u4f5c\uff0c\u5982\u8bfb\u53d6\u548c\u5199\u5165\u5143\u7d20\uff0c\u4ee5\u53ca\u4e00\u4e9b\u6570\u5b66\u8fd0\u7b97\uff0c\u5982\u5411\u91cf\u5316\u64cd\u4f5c\u3002 Python\u5217\u8868\uff1aPython\u5217\u8868\u63d0\u4f9b\u4e86\u66f4\u4e30\u5bcc\u7684\u65b9\u6cd5\u548c\u64cd\u4f5c\uff0c\u5305\u62ec\u5143\u7d20\u7684\u63d2\u5165\u3001\u5220\u9664\u3001\u8ffd\u52a0\u3001\u5207\u7247\u3001\u8fde\u63a5\u7b49\u3002 \u8bed\u8a00\u4f9d\u8d56\u6027\uff1a \u6570\u7ec4\uff1a\u6570\u7ec4\u901a\u5e38\u662f\u7f16\u7a0b\u8bed\u8a00\u7684\u4e00\u90e8\u5206\uff0c\u5177\u6709\u56fa\u5b9a\u7684\u8bed\u6cd5\u548c\u8bed\u4e49\u3002 Python\u5217\u8868\uff1aPython\u7684\u5217\u8868\u662fPython\u6807\u51c6\u5e93\u7684\u4e00\u90e8\u5206\uff0c\u4e0ePython\u7684\u52a8\u6001\u7279\u6027\u76f8\u9002\u5e94\u3002 \u9002\u7528\u573a\u666f\uff1a \u6570\u7ec4\uff1a\u9002\u7528\u4e8e\u9700\u8981\u9ad8\u6548\u968f\u673a\u8bbf\u95ee\u7684\u60c5\u51b5\uff0c\u5982\u6570\u503c\u8ba1\u7b97\u3001\u56fe\u50cf\u5904\u7406\u7b49\u3002 Python\u5217\u8868\uff1a\u9002\u7528\u4e8e\u66f4\u5e7f\u6cdb\u7684\u5e94\u7528\uff0c\u7279\u522b\u662f\u5728\u7f16\u5199Python\u4ee3\u7801\u65f6\uff0c\u56e0\u4e3a\u5b83\u4eec\u66f4\u7075\u6d3b\u4e14\u6613\u4e8e\u4f7f\u7528\u3002 \u603b\u4e4b\uff0c\u6570\u7ec4\u548cPython\u5217\u8868\u90fd\u6709\u81ea\u5df1\u7684\u4f18\u52bf\u548c\u9002\u7528\u573a\u666f\u3002\u9009\u62e9\u4f7f\u7528\u54ea\u79cd\u6570\u636e\u7ed3\u6784\u53d6\u51b3\u4e8e\u5177\u4f53\u7684\u9700\u6c42\u548c\u7f16\u7a0b\u8bed\u8a00\u3002\u5728Python\u4e2d\uff0c\u901a\u5e38\u4f1a\u4f18\u5148\u9009\u62e9\u4f7f\u7528\u5217\u8868\uff0c\u56e0\u4e3a\u5b83\u4eec\u66f4\u65b9\u4fbf\uff0c\u800c\u5728\u5176\u4ed6\u7f16\u7a0b\u8bed\u8a00\u4e2d\uff0c\u5982C\u6216Java\uff0c\u6570\u7ec4\u53ef\u80fd\u66f4\u4e3a\u5e38\u89c1\u3002 \u5728\u8fd9\u91cc\u9700\u8981\u8bf4\u660e\u4e00\u4e2a\u6982\u5ff5\u3002\u5728Python\u4e2d\uff0c\u672f\u8bed\"\u6570\u7ec4\"\u901a\u5e38\u6307\u7684\u662fNumPy\u5e93\u4e2d\u7684\u6570\u7ec4\u5bf9\u8c61\uff0c\u800c\"\u5217\u8868\"\u6307\u7684\u662fPython\u7684\u5185\u7f6e\u5217\u8868\uff08list\uff09\u6570\u636e\u7ed3\u6784\u3002\u8fd9\u4e24\u8005\u4e4b\u95f4\u6709\u4ee5\u4e0b\u533a\u522b\uff1a \u6570\u636e\u7c7b\u578b\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1aNumPy\u5e93\u63d0\u4f9b\u4e86\u4e00\u4e2a\u591a\u7ef4\u6570\u7ec4\u5bf9\u8c61\uff0c\u5b83\u53ef\u4ee5\u5305\u542b\u76f8\u540c\u6570\u636e\u7c7b\u578b\u7684\u5143\u7d20\uff0c\u5e76\u652f\u6301\u9ad8\u7ea7\u6570\u5b66\u3001\u79d1\u5b66\u548c\u5de5\u7a0b\u8ba1\u7b97\u3002NumPy\u6570\u7ec4\u7684\u5143\u7d20\u7c7b\u578b\u901a\u5e38\u662f\u56fa\u5b9a\u7684\uff0c\u4f8b\u5982\uff0c\u53ef\u4ee5\u662f\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u590d\u6570\u7b49\u3002\u8fd9\u4e9b\u6570\u7ec4\u662f\u9ad8\u6027\u80fd\u7684\uff0c\u652f\u6301\u5411\u91cf\u5316\u64cd\u4f5c\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u7684\u5185\u7f6e\u5217\u8868\u662f\u4e00\u79cd\u901a\u7528\u7684\u3001\u52a8\u6001\u7c7b\u578b\u7684\u6570\u636e\u7ed3\u6784\uff0c\u53ef\u4ee5\u5305\u542b\u4e0d\u540c\u6570\u636e\u7c7b\u578b\u7684\u5143\u7d20\uff0c\u4f8b\u5982\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u5b57\u7b26\u4e32\u3001\u5bf9\u8c61\u7b49\u3002\u5217\u8868\u53ef\u4ee5\u52a8\u6001\u6269\u5c55\u548c\u7f29\u5c0f\uff0c\u5e76\u63d0\u4f9b\u4e86\u4e30\u5bcc\u7684\u5185\u7f6e\u65b9\u6cd5\u548c\u64cd\u4f5c\u3002 \u6027\u80fd\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1aNumPy\u6570\u7ec4\u901a\u5e38\u6bd4Python\u5217\u8868\u66f4\u9ad8\u6548\uff0c\u7279\u522b\u662f\u5728\u8fdb\u884c\u6570\u503c\u8ba1\u7b97\u548c\u79d1\u5b66\u8ba1\u7b97\u65f6\u3002\u5b83\u4eec\u5185\u90e8\u4f7f\u7528\u4e86C\u8bed\u8a00\u5b9e\u73b0\uff0c\u652f\u6301\u5411\u91cf\u5316\u64cd\u4f5c\uff0c\u56e0\u6b64\u5728\u5927\u89c4\u6a21\u6570\u636e\u5904\u7406\u4e2d\u901a\u5e38\u66f4\u5feb\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u5217\u8868\u867d\u7136\u7075\u6d3b\uff0c\u4f46\u6027\u80fd\u76f8\u5bf9\u8f83\u4f4e\uff0c\u4e0d\u9002\u5408\u5927\u89c4\u6a21\u7684\u6570\u503c\u8ba1\u7b97\u3002\u5b83\u4eec\u7684\u5143\u7d20\u7c7b\u578b\u53ef\u4ee5\u4e0d\u540c\uff0c\u8fd9\u610f\u5473\u7740\u9700\u8981\u66f4\u591a\u7684\u5185\u5b58\u548c\u5904\u7406\u65f6\u95f4\u6765\u7ba1\u7406\u5143\u7d20\u3002 \u5e93\u4f9d\u8d56\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1a\u4f7f\u7528NumPy\u5e93\u9700\u8981\u5b89\u88c5NumPy\u6a21\u5757\u3002NumPy\u662fPython\u4e2d\u7528\u4e8e\u6570\u503c\u8ba1\u7b97\u7684\u6838\u5fc3\u5e93\uff0c\u5e7f\u6cdb\u5e94\u7528\u4e8e\u79d1\u5b66\u8ba1\u7b97\u3001\u673a\u5668\u5b66\u4e60\u7b49\u9886\u57df\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u7684\u5185\u7f6e\u5217\u8868\u662fPython\u6807\u51c6\u5e93\u7684\u4e00\u90e8\u5206\uff0c\u65e0\u9700\u989d\u5916\u5b89\u88c5\u3002 \u529f\u80fd\uff1a \u6570\u7ec4\uff08NumPy\u6570\u7ec4\uff09\uff1aNumPy\u6570\u7ec4\u63d0\u4f9b\u4e86\u8bb8\u591a\u6570\u5b66\u548c\u79d1\u5b66\u8ba1\u7b97\u51fd\u6570\uff0c\u5982\u7ebf\u6027\u4ee3\u6570\u3001\u5085\u7acb\u53f6\u53d8\u6362\u3001\u7edf\u8ba1\u5206\u6790\u7b49\u3002\u5b83\u4eec\u9002\u7528\u4e8e\u5904\u7406\u5927\u91cf\u6570\u503c\u6570\u636e\u3002 \u5217\u8868\uff08Python\u5217\u8868\uff09\uff1aPython\u5217\u8868\u63d0\u4f9b\u4e86\u901a\u7528\u7684\u6570\u636e\u5bb9\u5668\uff0c\u7528\u4e8e\u5b58\u50a8\u548c\u7ba1\u7406\u5404\u79cd\u7c7b\u578b\u7684\u6570\u636e\uff0c\u4f46\u4e0d\u63d0\u4f9b\u4e13\u95e8\u7684\u6570\u5b66\u548c\u79d1\u5b66\u8ba1\u7b97\u529f\u80fd\u3002 \u5982\u679c\u9700\u8981\u8fdb\u884c\u6570\u503c\u8ba1\u7b97\u3001\u79d1\u5b66\u8ba1\u7b97\u6216\u6570\u636e\u5206\u6790\uff0c\u901a\u5e38\u4f1a\u4f7f\u7528NumPy\u6570\u7ec4\u3002\u5982\u679c\u53ea\u662f\u9700\u8981\u4e00\u4e2a\u901a\u7528\u7684\u6570\u636e\u5bb9\u5668\uff0c\u7528\u4e8e\u5b58\u50a8\u548c\u7ba1\u7406\u6570\u636e\uff0c\u90a3\u4e48Python\u5217\u8868\u901a\u5e38\u8db3\u591f\u4e86\u3002 3\uff0e\u8bf7\u8bf4\u660e\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u4e4b\u95f4\u7684\u533a\u522b\u3002 \u89e3\u7b54\uff1a\"\u7269\u7406\u5c3a\u5bf8\"\u548c\"\u903b\u8f91\u5c3a\u5bf8\"\u901a\u5e38\u7528\u4e8e\u63cf\u8ff0\u6570\u636e\u7ed3\u6784\u4e2d\u7684\u4e24\u4e2a\u4e0d\u540c\u65b9\u9762\uff1a \u7269\u7406\u5c3a\u5bf8\uff08Physical Size\uff09\uff1a \u7269\u7406\u5c3a\u5bf8\u662f\u6307\u6570\u636e\u7ed3\u6784\u5b9e\u9645\u5360\u7528\u7684\u5185\u5b58\u7a7a\u95f4\u6216\u5b58\u50a8\u4ecb\u8d28\u4e2d\u7684\u7a7a\u95f4\u5927\u5c0f\u3002 \u5b83\u8868\u793a\u6570\u636e\u7ed3\u6784\u5728\u8ba1\u7b97\u673a\u5185\u5b58\u6216\u78c1\u76d8\u4e2d\u6240\u5360\u636e\u7684\u5b9e\u9645\u5b57\u8282\u6570\u3002 \u7269\u7406\u5c3a\u5bf8\u4e0e\u6570\u636e\u7ed3\u6784\u7684\u5b58\u50a8\u65b9\u5f0f\u3001\u6570\u636e\u7c7b\u578b\u4ee5\u53ca\u8ba1\u7b97\u673a\u67b6\u6784\u6709\u5173\u3002 \u903b\u8f91\u5c3a\u5bf8\uff08Logical Size\uff09\uff1a \u903b\u8f91\u5c3a\u5bf8\u662f\u6307\u6570\u636e\u7ed3\u6784\u4e2d\u5305\u542b\u7684\u5143\u7d20\u6570\u91cf\u6216\u6570\u636e\u9879\u7684\u6570\u91cf\u3002 \u5b83\u8868\u793a\u6570\u636e\u7ed3\u6784\u5185\u90e8\u7684\u5143\u7d20\u6570\u91cf\u6216\u6570\u636e\u9879\u7684\u4e2a\u6570\uff0c\u4e0d\u6d89\u53ca\u5b9e\u9645\u7684\u5b58\u50a8\u5927\u5c0f\u3002 \u903b\u8f91\u5c3a\u5bf8\u901a\u5e38\u7528\u4e8e\u63cf\u8ff0\u6570\u636e\u7ed3\u6784\u7684\u5bb9\u91cf\u3001\u89c4\u6a21\u6216\u7ef4\u5ea6\u3002 \u8fd9\u4e24\u4e2a\u6982\u5ff5\u4e4b\u95f4\u7684\u5173\u7cfb\u5982\u4e0b\uff1a \u4e00\u4e2a\u6570\u636e\u7ed3\u6784\u53ef\u4ee5\u5177\u6709\u56fa\u5b9a\u7684\u7269\u7406\u5c3a\u5bf8\uff08\u5360\u636e\u56fa\u5b9a\u6570\u91cf\u7684\u5b57\u8282\uff09\uff0c\u4f46\u5176\u903b\u8f91\u5c3a\u5bf8\u53ef\u4ee5\u6839\u636e\u5b9e\u9645\u5b58\u50a8\u7684\u5143\u7d20\u6570\u91cf\u800c\u53d8\u5316\u3002 \u7269\u7406\u5c3a\u5bf8\u901a\u5e38\u662f\u7531\u8ba1\u7b97\u673a\u786c\u4ef6\u548c\u64cd\u4f5c\u7cfb\u7edf\u7ba1\u7406\u7684\uff0c\u800c\u903b\u8f91\u5c3a\u5bf8\u5219\u662f\u7a0b\u5e8f\u5458\u6839\u636e\u6570\u636e\u7ed3\u6784\u7684\u8bbe\u8ba1\u6765\u7ba1\u7406\u7684\u3002 \u4e3e\u4f8b\u6765\u8bf4\uff0c\u4e00\u4e2a\u6574\u6570\u6570\u7ec4\u53ef\u4ee5\u5177\u6709\u56fa\u5b9a\u7684\u7269\u7406\u5c3a\u5bf8\uff0c\u4f8b\u59824\u5b57\u8282/\u6574\u6570\uff0c\u4f46\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\u53ef\u4ee5\u662f\u6570\u7ec4\u4e2d\u6574\u6570\u7684\u6570\u91cf\uff0c\u53ef\u4ee5\u662f0\u4e2a\u300110\u4e2a\u3001100\u4e2a\u7b49\u7b49\u3002\u56e0\u6b64\uff0c\u903b\u8f91\u5c3a\u5bf8\u63cf\u8ff0\u4e86\u6570\u7ec4\u53ef\u4ee5\u5bb9\u7eb3\u7684\u5143\u7d20\u6570\u91cf\uff0c\u800c\u7269\u7406\u5c3a\u5bf8\u63cf\u8ff0\u4e86\u5b9e\u9645\u5360\u7528\u7684\u5185\u5b58\u7a7a\u95f4\u3002 \u5728\u6570\u636e\u7ed3\u6784\u7684\u8bbe\u8ba1\u548c\u4f7f\u7528\u4e2d\uff0c\u4e86\u89e3\u548c\u7ba1\u7406\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u5bf9\u4e8e\u6709\u6548\u5730\u5229\u7528\u8ba1\u7b97\u673a\u8d44\u6e90\u975e\u5e38\u91cd\u8981\u3002","title":"4.1.4.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#42","text":"Python\u7684 array \u6a21\u5757\u5305\u542b\u4e00\u4e2a\u53eb\u4f5c array \u7684\u7c7b\uff0c\u5b83\u975e\u5e38\u7c7b\u4f3c\u4e8e\u5217\u8868\uff0c\u4f46\u662f\u53ea\u80fd\u5b58\u50a8\u6570\u5b57\u3002\u6211\u4eec\u4f1a\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c Array \u7684\u65b0\u7c7b\uff0c\u4f7f\u7528\u5217\u8868\u4fdd\u5b58\u5143\u7d20\uff0c\u5b58\u50a8\u4efb\u4f55\u7c7b\u578b\u7684\u5143\u7d20\u3002 \u4e0b\u9762\u7684\u793a\u4f8b\u5b9a\u4e49\u4e86\u4e00\u4e2a\u6570\u7ec4\u7c7b Array \uff0c\u4e0b\u9762\u5bf9\u6570\u7ec4\u7684\u4e00\u4e9b\u64cd\u4f5c\u7684\u4ee3\u7801\u5b9e\u73b0\u4e5f\u5df2\u7ecf\u5305\u542b\u5728\u4e0b\u9762\u7684\u4ee3\u7801\u4e2d\u3002\u5176\u4e2d\uff1a \u6570\u7ec4\u9ed8\u8ba4\u7684\u7269\u7406\u5c3a\u5bf8\uff08\u4e5f\u5c31\u662f\u5bb9\u91cf\uff09\u662f5 \u6570\u7ec4\u7684\u521d\u59cb\u903b\u8f91\u5c3a\u5bf8\u662f0 class Array ( object ): \"\"\"\u63cf\u8ff0\u4e00\u4e2a\u6570\u7ec4\u3002\"\"\" def __init__ ( self , capacity , fillValue = None ): \"\"\"Capacity\u662f\u6570\u7ec4\u7684\u5927\u5c0f. fillValue\u4f1a\u586b\u5145\u5728\u6bcf\u4e2a\u5143\u7d20\u4f4d\u7f6e, \u9ed8\u8ba4\u503c\u662fNone\"\"\" # \u521d\u59cb\u5316\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u548c\u7269\u7406\u5c3a\u5bf8 self . logicalSize = 0 self . capacity = capacity self . fillValue = fillValue #\u521d\u59cb\u5316\u5185\u90e8\u6570\u7ec4\uff0c\u5e76\u586b\u5145\u5143\u7d20\u503c self . items = list () for count in range ( capacity ): self . items . append ( fillValue ) def __len__ ( self ): \"\"\"\u8fd4\u56de\u6570\u7ec4\u7684\u5927\u5c0f\"\"\" return len ( self . items ) def __str__ ( self ): \"\"\"\u5c06\u6570\u7ec4\u5b57\u7b26\u4e32\u5316\u5e76\u8fd4\u56de\"\"\" result = \"\" for index in range ( self . size ()): result += str ( self . items [ index ]) + \" \" return result def size ( self ): \"\"\"\u8fd4\u56de\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\"\"\" return self . logicalSize def __iter__ ( self ): \"\"\"\u652f\u6301for\u5faa\u73af\u5bf9\u6570\u7ec4\u8fdb\u884c\u904d\u5386.\"\"\" print ( \"__iter__ called\" ) # \u4ec5\u7528\u6765\u6d4b\u8bd5\u4f55\u65f6__iter__\u4f1a\u88ab\u8c03\u7528 return iter ( self . items ) def __getitem__ ( self , index ): \"\"\" \u7528\u4e8e\u8bbf\u95ee\u7d22\u5f15\u5904\u7684\u4e0b\u6807\u8fd0\u7b97\u7b26. \u5148\u51b3\u6761\u4ef6: 0 <= index < size() \"\"\" if index < 0 or index >= self . size (): raise IndexError ( \"\u8bfb\u53d6\u64cd\u4f5c\u51fa\u9519, \u6570\u7ec4\u7d22\u5f15\u8d8a\u754c(\u4e0d\u5728\u6570\u7ec4\u903b\u8f91\u8fb9\u754c\u8303\u56f4\u5185)\" ) return self . items [ index ] def __setitem__ ( self , index , newItem ): \"\"\" \u4e0b\u6807\u8fd0\u7b97\u7b26\u7528\u4e8e\u5728\u7d22\u5f15\u5904\u8fdb\u884c\u66ff\u6362. \u5148\u51b3\u6761\u4ef6: 0 <= index < size() \"\"\" if index < 0 or index >= self . size (): raise IndexError ( \"\u66f4\u65b0\u64cd\u4f5c\u51fa\u9519, \u6570\u7ec4\u7d22\u5f15\u8d8a\u754c(\u4e0d\u5728\u6570\u7ec4\u903b\u8f91\u8fb9\u754c\u8303\u56f4\u5185)\" ) self . items [ index ] = newItem def __eq__ ( self , other ): \"\"\" \u4e24\u4e2a\u6570\u7ec4\u76f8\u7b49\u5219\u8fd4\u56deTrue\uff0c\u5426\u5219\u8fd4\u56deFalse \"\"\" # \u5224\u65ad\u4e24\u4e2a\u6570\u7ec4\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff0c\u6ce8\u610f\uff0c\u4e0d\u662f\u5b83\u4eec\u7684\u503c\u662f\u5426\u76f8\u7b49 if self is other : return True # \u5224\u65ad\u4e24\u4e2a\u5bf9\u8c61\u7c7b\u578b\u662f\u5426\u4e00\u6837 if type ( self ) != type ( other ): return False # \u5224\u65ad\u4e24\u4e2a\u6570\u7ec4\u5927\u5c0f\u662f\u5426\u4e00\u6837 if self . size () != other . size (): return False # \u6bd4\u8f83\u4e24\u4e2a\u6570\u7ec4\u7684\u503c\u662f\u5426\u4e00\u6837 for index in range ( self . size ()): if self [ index ] != other [ index ]: return False return True def grow ( self ): \"\"\"\u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\"\"\" # \u57fa\u4e8e\u5f53\u524d\u7269\u7406\u5c3a\u5bf8\u52a0\u500d\uff0c\u5e76\u5c06fillValue\u8d4b\u503c\u5e95\u5c42\u5217\u8868\u7684\u65b0\u5143\u7d20 for count in range ( len ( self )): self . items . append ( self . fillValue ) def insert ( self , index , newItem ): \"\"\"\u5728\u6570\u7ec4\u6307\u5b9a\u7d22\u5f15\u5904\u63d2\u5165\u65b0\u5143\u7d20\"\"\" # \u5f53\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u548c\u903b\u8f91\u5c3a\u5bf8\u4e00\u6837\u65f6\uff0c\u5219\u589e\u52a0\u7269\u7406\u5c3a\u5bf8 if self . size () == len ( self ): self . grow () # \u63d2\u5165\u65b0\u5143\u7d20 # \u5f53\u63d2\u5165\u4f4d\u7f6e\u5927\u4e8e\u6216\u7b49\u4e8e\u6700\u5927\u903b\u8f91\u4f4d\u7f6e\uff0c\u5219\u5728\u6570\u7ec4\u672b\u7aef\u63d2\u5165\u65b0\u5143\u7d20 # \u5f53\u63d2\u5165\u4f4d\u7f6e\u4ecb\u4e8e\u6570\u7ec4\u903b\u8f91\u4f4d\u7f6e\u7684\u4e2d\u95f4\uff0c\u5219\u4ece\u63d2\u5165\u4f4d\u7f6e\u8d77\u5c06\u5269\u4f59\u6570\u7ec4\u5143\u7d20\u5411\u5c3e\u90e8\u5e73\u79fb\u4e00\u4e2a\u4f4d\u7f6e if index >= self . size (): self . items [ self . size ()] = newItem else : index = max ( index , 0 ) # \u5c06\u6570\u7ec4\u5143\u7d20\u5411\u5c3e\u90e8\u5e73\u79fb\u4e00\u4e2a\u4f4d\u7f6e for i in range ( self . size (), index , - 1 ): self . items [ i ] = self . items [ i - 1 ] # \u63d2\u5165\u65b0\u5143\u7d20 self . items [ index ] = newItem # \u589e\u52a0\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8 self . logicalSize += 1 def shrink ( self ): \"\"\" \u51cf\u5c11\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8 \u5f53: - \u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u5c0f\u4e8e\u6216\u7b49\u4e8e\u5176\u7269\u7406\u5c3a\u5bf8\u76841/4 - \u5e76\u4e14\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u81f3\u5c11\u662f\u8fd9\u4e2a\u6570\u7ec4\u5efa\u7acb\u65f6\u9ed8\u8ba4\u5bb9\u91cf\u76842\u500d\u65f6 \u5219\u628a\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u51cf\u5c0f\u5230\u539f\u6765\u7684\u4e00\u534a\uff0c\u5e76\u4e14\u4e5f\u4e0d\u4f1a\u5c0f\u4e8e\u5176\u9ed8\u8ba4\u5bb9\u91cf \"\"\" # \u5728\u903b\u8f91\u5c3a\u5bf8\u548c\u7269\u7406\u5c3a\u5bf8\u7684\u4e00\u534a\u4e4b\u95f4\u9009\u62e9\u6700\u5927\u503c\u4f5c\u4e3a\u6570\u7ec4\u6536\u7f29\u540e\u7684\u7269\u7406\u5c3a\u5bf8 newSize = max ( self . capacity , len ( self ) // 2 ) # \u91ca\u653e\u591a\u4f59\u7684\u6570\u7ec4\u7a7a\u95f4 for count in range ( len ( self ) - newSize ): self . items . pop () def pop ( self , index ): \"\"\" \u5220\u9664\u6307\u5b9a\u7d22\u5f15\u503c\u7684\u6570\u7ec4\u5143\u7d20,\u5e76\u8fd4\u56de\u5220\u9664\u7684\u6570\u7ec4\u5143\u7d20\u503c \u5148\u51b3\u6761\u4ef6: 0 <= index < size() \"\"\" if index < 0 or index >= self . size (): raise IndexError ( \"\u5220\u9664\u64cd\u4f5c\u51fa\u9519, \u6570\u7ec4\u7d22\u5f15\u8d8a\u754c(\u4e0d\u5728\u6570\u7ec4\u903b\u8f91\u8fb9\u754c\u8303\u56f4\u5185)\" ) # \u4fdd\u5b58\u5373\u5c06\u88ab\u5220\u9664\u7684\u6570\u7ec4\u5143\u7d20\u503c itemToReturn = self . items [ index ] # \u5c06\u6570\u7ec4\u5143\u7d20\u5411\u5934\u90e8\u5e73\u79fb\u4e00\u4e2a\u4f4d\u7f6e for i in range ( index , self . size () - 1 ): self . items [ i ] = self . items [ i + 1 ] # \u5c06\u6570\u7ec4\u5c3e\u90e8\u7684\u7a7a\u4f59\u4f4d\u8d4b\u503cfillValue\uff0c\u9ed8\u8ba4\u662fNone self . items [ self . size () - 1 ] = self . fillValue # \u51cf\u5c11\u6570\u7ec4\u903b\u8f91\u5c3a\u5bf8 self . logicalSize -= 1 # \u51cf\u5c11\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 # \u5f53: # - \u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u5c0f\u4e8e\u6216\u7b49\u4e8e\u5176\u7269\u7406\u5c3a\u5bf8\u76841/4 # - \u5e76\u4e14\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u81f3\u5c11\u662f\u8fd9\u4e2a\u6570\u7ec4\u5efa\u7acb\u65f6\u9ed8\u8ba4\u5bb9\u91cf\u76842\u500d\u65f6 # \u5219\u628a\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u51cf\u5c0f\u5230\u539f\u6765\u7684\u4e00\u534a\uff0c\u5e76\u4e14\u4e5f\u4e0d\u4f1a\u5c0f\u4e8e\u5176\u9ed8\u8ba4\u5bb9\u91cf if self . size () <= len ( self ) // 4 and len ( self ) > self . capacity : self . shrink () # \u8fd4\u56de\u88ab\u5220\u9664\u5143\u7d20\u7684\u503c print ( f 'Item { itemToReturn } was deleted' ) return itemToReturn def main (): # \u521d\u59cb\u5316\u7a7a\u6570\u7ec4 DEFAULT_CAPACITY = 5 my_arr = Array ( DEFAULT_CAPACITY ) # \u6253\u5370\u8f93\u51fa\u6570\u7ec4\u521d\u59cb\u4fe1\u606f print ( \"Physical size:\" , len ( my_arr )) print ( \"Logical size:\" , my_arr . size ()) print ( \"Initial items:\" , my_arr . items ) # \u521d\u59cb\u5316\u6570\u7ec4\u5143\u7d20 print ( '------' ) for item in range ( 4 ): my_arr . insert ( 0 , item ) # \u5728\u6570\u7ec4\u5934\u90e8\u63d2\u5165\uff0c\u6bcf\u63d2\u5165\u4e00\u6b21\u90fd\u9700\u8981\u5411\u540e\u79fb\u52a8\u5df2\u6709\u6570\u7ec4\u5143\u7d20 print ( \"Items(logical):\" , my_arr ) print ( \"Items(physical):\" , my_arr . items ) # \u5728\u6570\u7ec4\u4e2d\u95f4\u63d2\u5165\u65b0\u5143\u7d20 print ( '------' ) my_arr . insert ( 3 , 99 ) print ( \"Items(logical):\" , my_arr ) print ( \"Items(physical):\" , my_arr . items ) # \u5728\u6570\u7ec4\u903b\u8f91\u5c3a\u5bf8\u5916\u63d2\u5165\u65b0\u5143\u7d20 print ( '------' ) my_arr . insert ( 20 , 88 ) print ( \"Items(logical):\" , my_arr ) print ( \"Items(physical):\" , my_arr . items ) # \u5220\u9664\u6570\u7ec4\u5143\u7d20 print ( '------' ) my_arr . pop ( 3 ) my_arr . pop ( 3 ) print ( \"Items(logical):\" , my_arr ) print ( \"Items(physical):\" , my_arr . items ) # \u6e05\u7a7a\u6570\u7ec4\u5143\u7d20 print ( '------' ) for count in range ( my_arr . size ()): my_arr . pop ( 0 ) print ( \"Items(logical):\" , my_arr ) print ( \"Items(physical):\" , my_arr . items ) # \u6570\u7ec4\u5143\u7d20\u5df2\u7ecf\u5168\u90e8\u5220\u9664\uff0c\u903b\u8f91\u5c3a\u5bf8\u4e3a\u96f6\uff0c\u4e0b\u9762\u547d\u4ee4\u8fd4\u56de\u9519\u8bef # print('------') # print(my_arr.pop(0)) # \u6570\u7ec4\u6bd4\u8f83 # \u521d\u59cb\u5316\u6570\u7ec4 print ( '------' ) arr_a = Array ( 5 ) for item in range ( 4 ): arr_a . insert ( 0 , item ) arr_b = arr_a arr_c = Array ( 5 ) for item in range ( 4 ): arr_c . insert ( 0 , item ) arr_d = [] print ( \"arr_a(physical):\" , arr_a . items ) print ( \"arr_b(physical):\" , arr_b . items ) print ( \"arr_c(physical):\" , arr_c . items ) print ( \"arr_d(physical):\" , arr_d ) print ( \"arr_a == arr_b:\" , arr_a == arr_b ) print ( \"arr_a is arr_b:\" , arr_a is arr_b ) print ( \"arr_a == arr_c:\" , arr_a == arr_c ) print ( \"arr_a is arr_c:\" , arr_a is arr_c ) arr_c . insert ( 10 , 10 ) print ( \"arr_a == arr_c:\" , arr_a == arr_c ) arr_c . pop ( arr_c . size () - 1 ) arr_c [ 2 ] = 6 print ( \"arr_a == arr_c:\" , arr_a == arr_c ) print ( \"arr_a == arr_d:\" , arr_a == arr_d ) if __name__ == \"__main__\" : main () # \u8fd0\u884c\u7ed3\u679c # Physical size: 5 # Logical size: 0 # Initial items: [None, None, None, None, None] # ------ # Items(logical): 3 2 1 0 # Items(physical): [3, 2, 1, 0, None] # ------ # Items(logical): 3 2 1 99 0 # Items(physical): [3, 2, 1, 99, 0] # ------ # Items(logical): 3 2 1 99 0 88 # Items(physical): [3, 2, 1, 99, 0, 88, None, None, None, None] # ------ # Item 99 was deleted # Item 0 was deleted # Items(logical): 3 2 1 88 # Items(physical): [3, 2, 1, 88, None, None, None, None, None, None] # ------ # Item 3 was deleted # Item 2 was deleted # Item 1 was deleted # Item 88 was deleted # Items(logical): # Items(physical): [None, None, None, None, None] # ------ # IndexError: \u5220\u9664\u64cd\u4f5c\u51fa\u9519, \u6570\u7ec4\u7d22\u5f15\u8d8a\u754c(\u4e0d\u5728\u6570\u7ec4\u903b\u8f91\u8fb9\u754c\u8303\u56f4\u5185) # ------ # arr_a(physical): [3, 2, 1, 0, None] # arr_b(physical): [3, 2, 1, 0, None] # arr_c(physical): [3, 2, 1, 0, None] # arr_d(physical): [] # arr_a == arr_b: True # arr_a is arr_b: True # arr_a == arr_c: True # arr_a is arr_c: False # arr_a == arr_c: False # Item 10 was deleted # arr_a == arr_c: False # arr_a == arr_d: False","title":"4.2.\u6570\u7ec4\u7684\u64cd\u4f5c"},{"location":"python/DataStructure/04_ArrayChain/#421","text":"\u5f53\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u7b49\u4e8e\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u65f6\uff0c\u5982\u679c\u8981\u63d2\u5165\u65b0\u7684\u5143\u7d20\uff0c\u5c31\u9700\u8981\u589e\u5927\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u3002 \u5982\u679c\u9700\u8981\u4e3a\u6570\u7ec4\u63d0\u4f9b\u66f4\u591a\u5185\u5b58\uff0cPython\u7684list\u7c7b\u578b\u4f1a\u5728\u8c03\u7528insert\u6216append\u65b9\u6cd5\u65f6\u6267\u884c\u8fd9\u4e2a\u64cd\u4f5c\u3002 \u8c03\u6574\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\u7684\u8fc7\u7a0b\u5305\u542b\u5982\u4e0b3\u4e2a\u6b65\u9aa4\u3002 \u521b\u5efa\u4e00\u4e2a\u66f4\u5927\u7684\u65b0\u6570\u7ec4\u3002 \u5c06\u6570\u636e\u4ece\u65e7\u6570\u7ec4\u4e2d\u590d\u5236\u5230\u65b0\u6570\u7ec4\u3002 \u5c06\u6307\u5411\u65e7\u6570\u7ec4\u7684\u53d8\u91cf\u6307\u5411\u65b0\u6570\u7ec4\u5bf9\u8c61\u3002 \u4e0b\u9762\u4ee3\u7801\u5b9e\u73b0\u3002 # \u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 if logicalSize == len ( my_array ): temp = Array ( len ( my_array ) + 1 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 \u5728\u4e0a\u9762\u4ee3\u7801\u4e2d\uff0c\u901a\u8fc7 temp[i] = my_array[i] \u6765\u8c03\u6574\u6570\u7ec4\u5c3a\u5bf8\uff0c\u8fd9\u4e2a\u590d\u5236\u64cd\u4f5c\u7684\u6570\u91cf\u662f\u7ebf\u6027\u589e\u957f\u7684\u3002\u56e0\u6b64\uff0c\u5c06 n \u4e2a\u5143\u7d20\u6dfb\u52a0\u5230\u6570\u7ec4\u91cc\u7684\u603b\u65f6\u95f4\u590d\u6742\u5ea6\u662f 1+2+3...+n \uff0c\u4e5f\u5c31\u662f n(n+1)/2 \uff0c\u56e0\u6b64\u662f O(n^2) \u3002 \u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\uff0c\u901a\u8fc7 temp = Array(len(my_array) + 1) \u5bf9\u6570\u7ec4\u8fdb\u884c\u52a8\u6001\u6269\u5c55\uff0c\u5bf9\u6027\u80fd\u4f1a\u4ea7\u751f\u4e00\u4e9b\u53ef\u80fd\u7684\u5f71\u54cd\uff1a \u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u52a8\u6001\u6269\u5c55\u6570\u7ec4\u901a\u5e38\u9700\u8981\u590d\u5236\u73b0\u6709\u6570\u636e\u5230\u65b0\u7684\u5185\u5b58\u4f4d\u7f6e\uff0c\u8fd9\u5c06\u6d89\u53ca\u5230\u5143\u7d20\u7684\u590d\u5236\u64cd\u4f5c\u3002\u8fd9\u4e9b\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u6570\u7ec4\u7684\u957f\u5ea6\uff0c\u901a\u5e38\u662f O(n) \uff0c\u5176\u4e2d n \u662f\u6570\u7ec4\u7684\u957f\u5ea6\u3002\u56e0\u6b64\uff0c\u5f53\u6570\u7ec4\u9700\u8981\u6269\u5c55\u65f6\uff0c\u53ef\u80fd\u4f1a\u4ea7\u751f\u4e00\u4e9b\u989d\u5916\u7684\u65f6\u95f4\u5f00\u9500\u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\uff1a\u52a8\u6001\u6269\u5c55\u6570\u7ec4\u4f1a\u5360\u7528\u989d\u5916\u7684\u5185\u5b58\u7a7a\u95f4\uff0c\u56e0\u4e3a\u9700\u8981\u5206\u914d\u65b0\u7684\u5185\u5b58\u5757\u6765\u5bb9\u7eb3\u6269\u5c55\u540e\u7684\u6570\u7ec4\u3002\u8fd9\u53ef\u80fd\u4f1a\u5bfc\u81f4\u5185\u5b58\u788e\u7247\u5316\uff0c\u7279\u522b\u662f\u5728\u9891\u7e41\u6269\u5c55\u548c\u7f29\u5c0f\u6570\u7ec4\u65f6\u3002 \u6269\u5c55\u9891\u7387\uff1a\u6269\u5c55\u6570\u7ec4\u7684\u9891\u7387\u4f1a\u5f71\u54cd\u6027\u80fd\u3002\u5982\u679c\u6570\u7ec4\u9700\u8981\u9891\u7e41\u6269\u5c55\uff0c\u90a3\u4e48\u590d\u5236\u548c\u5185\u5b58\u5206\u914d\u7684\u5f00\u9500\u4f1a\u66f4\u52a0\u663e\u8457\uff0c\u4ece\u800c\u964d\u4f4e\u6027\u80fd\u3002\u56e0\u6b64\uff0c\u5728\u8bbe\u8ba1\u6570\u636e\u7ed3\u6784\u65f6\uff0c\u901a\u5e38\u4f1a\u8003\u8651\u521d\u59cb\u5bb9\u91cf\u548c\u6269\u5c55\u7b56\u7565\uff0c\u4ee5\u51cf\u5c11\u4e0d\u5fc5\u8981\u7684\u6269\u5c55\u6b21\u6570\u3002 Amortized Analysis\uff1a\u4e00\u4e9b\u6570\u636e\u7ed3\u6784\uff0c\u4f8b\u5982Python\u7684\u5217\u8868\uff08list\uff09\uff0c\u91c7\u7528\u644a\u8fd8\u5206\u6790\u6765\u5e73\u644a\u52a8\u6001\u6269\u5c55\u7684\u5f00\u9500\u3002\u8fd9\u610f\u5473\u7740\u867d\u7136\u67d0\u4e9b\u64cd\u4f5c\u53ef\u80fd\u4f1a\u82b1\u8d39 O(n) \u7684\u65f6\u95f4\uff0c\u4f46\u8fd9\u4e9b\u5f00\u9500\u5728\u4e00\u7cfb\u5217\u64cd\u4f5c\u4e2d\u88ab\u5206\u644a\uff0c\u5e73\u5747\u4e0b\u6765\u4ecd\u7136\u4fdd\u6301\u8f83\u4f4e\u7684\u590d\u6742\u5ea6\u3002\u8fd9\u53ef\u4ee5\u5728\u4e00\u5b9a\u7a0b\u5ea6\u4e0a\u7f13\u89e3\u6027\u80fd\u95ee\u9898\u3002 \u52a8\u6001\u6269\u5c55\u6570\u7ec4\u4f1a\u5f15\u5165\u4e00\u4e9b\u6027\u80fd\u5f00\u9500\uff0c\u4f46\u5728\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u8fd9\u79cd\u5f00\u9500\u901a\u5e38\u662f\u53ef\u4ee5\u63a5\u53d7\u7684\u3002\u4e3a\u4e86\u4f18\u5316\u6027\u80fd\uff0c\u53ef\u4ee5\u8003\u8651\u4ee5\u4e0b\u51e0\u70b9\u7b56\u7565\uff0c\u9700\u8981\u6839\u636e\u5177\u4f53\u5e94\u7528\u7684\u9700\u6c42\u548c\u6027\u80fd\u8981\u6c42\u6765\u6743\u8861\u8fd9\u4e9b\u56e0\u7d20\uff1a \u9884\u5148\u5206\u914d\u8db3\u591f\u7684\u521d\u59cb\u5bb9\u91cf\uff0c\u4ee5\u51cf\u5c11\u6269\u5c55\u7684\u9891\u7387\u3002 \u4f7f\u7528\u644a\u8fd8\u5206\u6790\u6765\u5e73\u644a\u5f00\u9500\u3002 \u8003\u8651\u4f7f\u7528\u5176\u4ed6\u6570\u636e\u7ed3\u6784\uff0c\u5982\u94fe\u8868\uff0c\u5bf9\u63d2\u5165\u548c\u5220\u9664\u64cd\u4f5c\u7684\u6027\u80fd\u66f4\u52a0\u53cb\u597d\u3002 \u4e0b\u9762\uff0c\u5c1d\u8bd5\u5728\u6bcf\u6b21\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u65f6\u628a\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\uff0c\u4ee3\u7801\u5b9e\u73b0\u5982\u4e0b\uff1a # \u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 while logicalSize < DEFAULT_CAPACITY * 2 : logicalSize += 1 if logicalSize == len ( my_array ): # \u89e6\u53d1\u6761\u4ef6 temp = Array ( len ( my_array ) + 1 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 \u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u6765\u6269\u5c55\u6570\u7ec4\u7684\u65b9\u5f0f\u662f\u4e00\u79cd\u5e38\u89c1\u7684\u7b56\u7565\uff0c\u901a\u5e38\u7528\u4e8e\u51cf\u5c11\u52a8\u6001\u6570\u7ec4\u7684\u9891\u7e41\u6269\u5c55\u6b21\u6570\uff0c\u4ee5\u63d0\u9ad8\u6027\u80fd\u3002\u8fd9\u79cd\u65b9\u5f0f\u7684\u64cd\u4f5c\u65f6\u95f4\u590d\u6742\u5ea6\u4e3b\u8981\u53d6\u51b3\u4e8e\u6269\u5c55\u64cd\u4f5c\u7684\u9891\u7387\u548c\u5143\u7d20\u7684\u590d\u5236\u6210\u672c\u3002 \u644a\u8fd8\u5206\u6790\uff1a\u5bf9\u4e8e\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u7684\u7b56\u7565\uff0c\u644a\u8fd8\u5206\u6790\u8868\u660e\uff0c\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u7684\u644a\u8fd8\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662f\u5e38\u6570\u65f6\u95f4\u7684\uff08\u901a\u5e38\u662fO(1)\uff09\uff0c\u8fd9\u610f\u5473\u7740\u5e73\u5747\u4e0b\u6765\uff0c\u6bcf\u6b21\u6269\u5c55\u7684\u5f00\u9500\u662f\u56fa\u5b9a\u7684\uff0c\u800c\u4e0d\u4f1a\u968f\u6570\u7ec4\u7684\u5927\u5c0f\u7ebf\u6027\u589e\u52a0\u3002 \u64cd\u4f5c\u65f6\u95f4\uff1a\u5047\u8bbe\u6570\u7ec4\u9700\u8981\u6269\u5c55\uff0c\u90a3\u4e48\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u9700\u8981\u5206\u914d\u65b0\u7684\u5185\u5b58\u5757\u5e76\u590d\u5236\u73b0\u6709\u5143\u7d20\uff0c\u8fd9\u4e2a\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\uff0c\u5176\u4e2dn\u662f\u6570\u7ec4\u7684\u5f53\u524d\u5927\u5c0f\u3002\u7136\u800c\uff0c\u7531\u4e8e\u6269\u5c55\u64cd\u4f5c\u4e0d\u662f\u6bcf\u6b21\u90fd\u6267\u884c\u7684\uff0c\u800c\u662f\u5f53\u6570\u7ec4\u5df2\u6ee1\u65f6\u624d\u6267\u884c\uff0c\u56e0\u6b64\u53ef\u4ee5\u8ba4\u4e3a\u8fd9\u4e2a\u64cd\u4f5c\u7684\u644a\u8fd8\u65f6\u95f4\u662f\u5e38\u6570\u65f6\u95f4\uff0c\u5373O(1)\u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\uff1a\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u4f1a\u5360\u7528\u989d\u5916\u7684\u5185\u5b58\u7a7a\u95f4\uff0c\u4f46\u968f\u7740\u6570\u7ec4\u7684\u589e\u957f\uff0c\u989d\u5916\u5185\u5b58\u7684\u5360\u7528\u76f8\u5bf9\u4e8e\u6570\u7ec4\u672c\u8eab\u7684\u5927\u5c0f\u6765\u8bf4\u662f\u6709\u9650\u7684\u3002\u901a\u5e38\u60c5\u51b5\u4e0b\uff0c\u8fd9\u79cd\u5360\u7528\u53ef\u4ee5\u63a5\u53d7\u3002 \u603b\u7ed3\uff0c\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u7684\u7b56\u7565\u53ef\u4ee5\u663e\u8457\u51cf\u5c11\u52a8\u6001\u6570\u7ec4\u7684\u6269\u5c55\u6b21\u6570\uff0c\u4ece\u800c\u63d0\u9ad8\u6027\u80fd\u3002\u867d\u7136\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u53ef\u80fd\u4f1a\u82b1\u8d39\u4e00\u4e9b\u65f6\u95f4\u548c\u989d\u5916\u5185\u5b58\uff0c\u4f46\u8fd9\u4e9b\u5f00\u9500\u5728\u4e00\u7cfb\u5217\u64cd\u4f5c\u4e2d\u88ab\u5e73\u644a\uff0c\u5e73\u5747\u4e0b\u6765\u662f\u5e38\u6570\u65f6\u95f4\u3002\u8fd9\u662f\u4e00\u79cd\u9ad8\u6548\u7684\u52a8\u6001\u6570\u7ec4\u5b9e\u73b0\u65b9\u5f0f\uff0c\u5e38\u89c1\u4e8e\u8bb8\u591a\u7f16\u7a0b\u8bed\u8a00\u7684\u6807\u51c6\u5e93\u4e2d\uff0c\u5305\u62ecPython\u7684\u5217\u8868\uff08list\uff09\u3002 \u5728\u589e\u52a0\u6570\u7ec4\u7684\u957f\u5ea6\u65f6\uff0c\u6bcf\u6b21\u589e\u52a0\u4e00\u4e2a\u5185\u5b58\u5355\u5143\uff0c\u4e0e\u6bcf\u6b21\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u65f6\u628a\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u76f8\u6bd4\uff0c\u540e\u8005\u7684\u65b9\u6cd5\u901a\u5e38\u66f4\u9ad8\u6548\u3002 \u6bcf\u6b21\u589e\u52a0\u4e00\u4e2a\u5185\u5b58\u5355\u5143\uff1a\u8fd9\u79cd\u65b9\u5f0f\u5728\u6bcf\u6b21\u6dfb\u52a0\u65b0\u5143\u7d20\u65f6\u90fd\u9700\u8981\u5206\u914d\u989d\u5916\u7684\u5185\u5b58\uff0c\u5bfc\u81f4\u6570\u7ec4\u5c3a\u5bf8\u7684\u589e\u957f\u662f\u7ebf\u6027\u7684\u3002\u5982\u679c\u9891\u7e41\u6dfb\u52a0\u5143\u7d20\uff0c\u8fd9\u5c06\u5bfc\u81f4\u5927\u91cf\u7684\u5185\u5b58\u5206\u914d\u548c\u6570\u636e\u590d\u5236\u64cd\u4f5c\uff0c\u56e0\u6b64\u65f6\u95f4\u590d\u6742\u5ea6\u4f1a\u53d8\u5f97\u76f8\u5bf9\u8f83\u9ad8\u3002 \u6bcf\u6b21\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u65f6\u628a\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\uff1a\u8fd9\u662f\u4e00\u79cd\u66f4\u9ad8\u6548\u7684\u7b56\u7565\u3002\u5728\u8fd9\u79cd\u65b9\u5f0f\u4e0b\uff0c\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u90fd\u4f1a\u589e\u52a0\u6570\u7ec4\u7684\u5c3a\u5bf8\uff0c\u4f46\u589e\u5e45\u662f\u6307\u6570\u7ea7\u7684\uff0c\u800c\u4e0d\u662f\u7ebf\u6027\u7684\u3002\u8fd9\u610f\u5473\u7740\u968f\u7740\u6570\u7ec4\u7684\u589e\u957f\uff0c\u6269\u5c55\u64cd\u4f5c\u7684\u9891\u7387\u4f1a\u51cf\u5c11\uff0c\u56e0\u4e3a\u6570\u7ec4\u80fd\u591f\u5bb9\u7eb3\u66f4\u591a\u5143\u7d20\u3002\u8fd9\u6837\uff0c\u867d\u7136\u6bcf\u6b21\u6269\u5c55\u64cd\u4f5c\u9700\u8981\u590d\u5236\u66f4\u591a\u7684\u5143\u7d20\uff0c\u4f46\u5b83\u4eec\u7684\u644a\u8fd8\u65f6\u95f4\u590d\u6742\u5ea6\u4ecd\u7136\u662f\u5e38\u6570\u65f6\u95f4\uff0c\u56e0\u4e3a\u5b83\u4eec\u4e0d\u662f\u6bcf\u6b21\u90fd\u6267\u884c\u7684\u3002 \u603b\u7ed3\uff0c\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u7684\u7b56\u7565\u901a\u5e38\u66f4\u9ad8\u6548\uff0c\u56e0\u4e3a\u5b83\u53ef\u4ee5\u51cf\u5c11\u9891\u7e41\u7684\u5185\u5b58\u5206\u914d\u548c\u590d\u5236\u64cd\u4f5c\uff0c\u964d\u4f4e\u4e86\u65f6\u95f4\u590d\u6742\u5ea6\u3002\u8fd9\u662f\u8bb8\u591a\u52a8\u6001\u6570\u7ec4\u5b9e\u73b0\u7684\u5e38\u89c1\u505a\u6cd5\uff0c\u5305\u62ecPython\u7684\u5217\u8868\uff08list\uff09\u3002 \u5728 Array \u7c7b\u5b9e\u73b0\u4e2d\uff0c\u662f\u901a\u8fc7\u4e0b\u9762\u4ee3\u7801\u6bb5\u5b9e\u73b0\u7684\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\u589e\u52a0\u7684\uff0c\u5373\u5c06\u6570\u7ec4\u5c3a\u5bf8\u7ffb\u500d\u3002 def grow ( self ): \"\"\"\u589e\u5927\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\"\"\" # \u57fa\u4e8e\u5f53\u524d\u7269\u7406\u5c3a\u5bf8\u52a0\u500d\uff0c\u5e76\u5c06fillValue\u8d4b\u503c\u5e95\u5c42\u5217\u8868\u7684\u65b0\u5143\u7d20 for count in range ( len ( self )): self . items . append ( self . fillValue )","title":"4.2.1.\u589e\u5927\u6570\u7ec4\u7684\u5c3a\u5bf8"},{"location":"python/DataStructure/04_ArrayChain/#422","text":"\u5982\u679c\u51cf\u5c0f\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\uff0c\u5c31\u4f1a\u6d6a\u8d39\u76f8\u5e94\u7684\u5185\u5b58\u5355\u5143\u3002\u56e0\u6b64\uff0c\u5f53\u5220\u9664\u67d0\u4e00\u4e2a\u5143\u7d20\uff0c\u5982\u679c\u672a\u4f7f\u7528\u7684\u5185\u5b58\u5355\u5143\u6570\u8fbe\u5230\u6216\u8d85\u8fc7\u4e86\u67d0\u4e2a\u9608\u503c\uff08\u5982\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\u7684\u00be\uff09\u65f6\uff0c\u5219\u5e94\u8be5\u51cf\u5c0f\u7269\u7406\u5c3a\u5bf8\u4e86\u3002\u5982\u679c\u6d6a\u8d39\u7684\u5185\u5b58\u8d85\u8fc7\u7279\u5b9a\u9608\u503c\uff0c\u90a3\u4e48Python\u7684list\u7c7b\u578b\u4f1a\u5728\u8c03\u7528 pop \u65b9\u6cd5\u65f6\u6267\u884c\u51cf\u5c0f\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8\u7684\u64cd\u4f5c\u3002 \u51cf\u5c0f\u6570\u7ec4\u5c3a\u5bf8\u7684\u8fc7\u7a0b\u4e0e\u589e\u5927\u6570\u7ec4\u5c3a\u5bf8\u7684\u8fc7\u7a0b\u76f8\u53cd\uff0c\u6b65\u9aa4\u5982\u4e0b\uff1a \u521b\u5efa\u4e00\u4e2a\u66f4\u5c0f\u7684\u65b0\u6570\u7ec4\u3002 \u5c06\u6570\u636e\u4ece\u65e7\u6570\u7ec4\u4e2d\u590d\u5236\u5230\u65b0\u6570\u7ec4\u3002 \u5c06\u6307\u5411\u65e7\u6570\u7ec4\u7684\u53d8\u91cf\u6307\u5411\u65b0\u6570\u7ec4\u5bf9\u8c61\u3002 \u4e0b\u9762\u7684\u4ee3\u7801\u5b9e\u73b0\u4e86\u51cf\u5c0f\u6570\u7ec4\u5c3a\u5bf8\u3002 \u5f53\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u5c0f\u4e8e\u6216\u7b49\u4e8e\u5176\u7269\u7406\u5c3a\u5bf8\u7684\u00bc\uff0c\u5e76\u4e14\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u81f3\u5c11\u662f\u8fd9\u4e2a\u6570\u7ec4\u5efa\u7acb\u65f6\u9ed8\u8ba4\u5bb9\u91cf\u76842\u500d\u65f6\uff0c\u5219\u4e0b\u9762\u7684\u7b97\u6cd5\u628a\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u51cf\u5c0f\u5230\u539f\u6765\u7684\u4e00\u534a\uff0c\u5e76\u4e14\u4e5f\u4e0d\u4f1a\u5c0f\u4e8e\u5176\u9ed8\u8ba4\u5bb9\u91cf\u3002 # \u51cf\u5c0f\u6570\u7ec4\u7269\u7406\u5c3a\u5bf8 while logicalSize > len ( my_array ) // 4 : logicalSize -= 1 if logicalSize <= len ( my_array ) // 4 and len ( my_array ) >= DEFAULT_CAPACITY * 2 : # \u89e6\u53d1\u6761\u4ef6 temp = Array ( len ( my_array ) // 2 ) # \u521b\u5efa\u4e00\u4e2a\u65b0\u6570\u7ec4 for i in range ( logicalSize ): temp [ i ] = my_array [ i ] # \u4ece\u539f\u6570\u7ec4\u590d\u5236\u5185\u5bb9\u5230\u65b0\u6570\u7ec4 my_array = temp # \u628a\u65b0\u6570\u7ec4\u8d4b\u503c\u7ed9\u539f\u6570\u7ec4 \u6309\u7167\u4e0a\u9762\u7b97\u6cd5\u51cf\u5c11\u6570\u7ec4\u7684\u5c3a\u5bf8\uff0c\u6211\u4eec\u53ef\u4ee5\u5206\u6790\u5176\u65f6\u95f4\u548c\u7a7a\u95f4\u590d\u6742\u5ea6\u5982\u4e0b\uff1a \u65f6\u95f4\u590d\u6742\u5ea6\uff1a\u4e3b\u8981\u6d89\u53ca\u4e24\u4e2a\u64cd\u4f5c\uff1a \u521b\u5efa\u65b0\u6570\u7ec4\u5e76\u5c06\u5143\u7d20\u4ece\u65e7\u6570\u7ec4\u590d\u5236\u5230\u65b0\u6570\u7ec4\uff1b \u5c06\u65e7\u6570\u7ec4\u5f15\u7528\u66f4\u6539\u4e3a\u65b0\u6570\u7ec4\u3002 \u590d\u5236\u64cd\u4f5c\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u53d6\u51b3\u4e8e\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\uff0c\u53ef\u4ee5\u8868\u793a\u4e3a O(n) \uff0c\u5176\u4e2d n \u662f\u6570\u7ec4\u7684\u5f53\u524d\u7269\u7406\u5c3a\u5bf8\u3002\u5f15\u7528\u66f4\u6539\u662f\u4e00\u4e2a\u5e38\u6570\u65f6\u95f4\u64cd\u4f5c\uff0c\u4e0d\u5f71\u54cd\u65f6\u95f4\u590d\u6742\u5ea6\u3002\u6240\u4ee5\uff0c\u6574\u4f53\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002 \u7a7a\u95f4\u590d\u6742\u5ea6\uff1a\u7a7a\u95f4\u590d\u6742\u5ea6\u4e5f\u6d89\u53ca\u4e24\u4e2a\u65b9\u9762\uff1a \u521b\u5efa\u65b0\u6570\u7ec4\u7684\u5185\u5b58\u6d88\u8017\uff0c\u5176\u7a7a\u95f4\u590d\u6742\u5ea6\u662fO(N)\uff1b \u5f15\u7528\u66f4\u6539\u6240\u9700\u7684\u5e38\u6570\u989d\u5916\u7a7a\u95f4\uff0c\u901a\u5e38\u5ffd\u7565\u4e0d\u8ba1\u3002 \u6240\u4ee5\uff0c\u603b\u7684\u7a7a\u95f4\u590d\u6742\u5ea6\u662f O(n) \u3002 \u8fd9\u4e2a\u7b97\u6cd5\u7b56\u7565\u4f1a\u5728\u9002\u5f53\u7684\u65f6\u5019\u51cf\u5c0f\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\uff0c\u4ee5\u51cf\u5c11\u5185\u5b58\u5360\u7528\uff0c\u4f46\u4ecd\u7136\u4fdd\u6301\u7740\u6570\u7ec4\u7684\u52a8\u6001\u6027\u3002\u65f6\u95f4\u590d\u6742\u5ea6\u548c\u7a7a\u95f4\u590d\u6742\u5ea6\u90fd\u4e0e\u5f53\u524d\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u6210\u7ebf\u6027\u5173\u7cfb\uff0c\u56e0\u6b64\u662f\u7ebf\u6027\u7684\uff0c\u8fd9\u662f\u4e00\u79cd\u6709\u6548\u7684\u7b56\u7565\u6765\u4f18\u5316\u5185\u5b58\u4f7f\u7528\u3002\u540c\u65f6\uff0c\u4fdd\u7559\u4e86\u4e00\u5b9a\u7684\u5197\u4f59\u7a7a\u95f4\uff0c\u4ee5\u907f\u514d\u9891\u7e41\u5730\u6269\u5c55\u548c\u7f29\u5c0f\u6570\u7ec4\uff0c\u4ece\u800c\u63d0\u9ad8\u4e86\u6027\u80fd\u3002 \u4e0b\u9762\u662f\u5728 Array \u7c7b\u4e2d\u5b9e\u73b0\u51cf\u5c0f\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u7684\u4ee3\u7801\u3002 def shrink ( self ): \"\"\" \u51cf\u5c11\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8 \u5f53: - \u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u5c0f\u4e8e\u6216\u7b49\u4e8e\u5176\u7269\u7406\u5c3a\u5bf8\u76841/4 - \u5e76\u4e14\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u81f3\u5c11\u662f\u8fd9\u4e2a\u6570\u7ec4\u5efa\u7acb\u65f6\u9ed8\u8ba4\u5bb9\u91cf\u76842\u500d\u65f6 \u5219\u628a\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u51cf\u5c0f\u5230\u539f\u6765\u7684\u4e00\u534a\uff0c\u5e76\u4e14\u4e5f\u4e0d\u4f1a\u5c0f\u4e8e\u5176\u9ed8\u8ba4\u5bb9\u91cf \"\"\" # \u5728\u903b\u8f91\u5c3a\u5bf8\u548c\u7269\u7406\u5c3a\u5bf8\u7684\u4e00\u534a\u4e4b\u95f4\u9009\u62e9\u6700\u5927\u503c\u4f5c\u4e3a\u6570\u7ec4\u6536\u7f29\u540e\u7684\u7269\u7406\u5c3a\u5bf8 newSize = max ( self . capacity , len ( self ) // 2 ) # \u91ca\u653e\u591a\u4f59\u7684\u6570\u7ec4\u7a7a\u95f4 for count in range ( len ( self ) - newSize ): self . items . pop ()","title":"4.2.2.\u51cf\u5c0f\u6570\u7ec4\u7684\u5c3a\u5bf8"},{"location":"python/DataStructure/04_ArrayChain/#423","text":"\u628a\u5143\u7d20\u63d2\u5165\u6570\u7ec4\u4e2d\u548c\u66ff\u6362\u6570\u7ec4\u91cc\u7684\u5143\u7d20\u662f\u4e0d\u4e00\u6837\u7684\u3002 \u66ff\u6362\u6570\u7ec4\u5143\u7d20\u65f6\uff0c\u5143\u7d20\u5df2\u5728\u4e00\u4e2a\u7ed9\u5b9a\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0c\u5bf9\u8fd9\u4e2a\u4f4d\u7f6e\u8fdb\u884c\u7b80\u5355\u590d\u5236\u5373\u53ef\uff0c\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u5e76\u4e0d\u4f1a\u6539\u53d8\u3002 \u63d2\u5165\u6570\u7ec4\u5143\u7d20\u65f6\uff0c\u9700\u8981\u5b8c\u6210\u4e0b\u97624\u4e2a\u6b65\u9aa4\uff1a \u5728\u63d2\u5165\u5143\u7d20\u4e4b\u524d\u5148\u68c0\u67e5\u53ef\u4ee5\u4f7f\u7528\u7684\u7a7a\u95f4\uff0c\u6839\u636e\u9700\u8981\u6765\u589e\u5927\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u3002 \u5c06\u6570\u7ec4\u91cc\u4ece\u903b\u8f91\u7ed3\u5c3e\u5230\u76ee\u6807\u7d22\u5f15\u7684\u6240\u6709\u5143\u7d20\u5411\u540e\u79fb\u52a8\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u4f1a\u5728\u76ee\u6807\u7d22\u5f15\u4f4d\u7f6e\u5904\u4e3a\u65b0\u5143\u7d20\u7559\u4e0b\u4e00\u4e2a\u7a7a\u683c\u3002 \u5c06\u65b0\u5143\u7d20\u5206\u914d\u5230\u76ee\u6807\u7d22\u5f15\u4f4d\u7f6e\u3002 \u5c06\u903b\u8f91\u5c3a\u5bf8\u52a01\u3002","title":"4.2.3.\u5c06\u5143\u7d20\u63d2\u5165\u589e\u5927\u7684\u6570\u7ec4"},{"location":"python/DataStructure/04_ArrayChain/#424","text":"","title":"4.2.4.\u4ece\u6570\u7ec4\u91cc\u5220\u9664\u5143\u7d20"},{"location":"python/DataStructure/04_ArrayChain/#425","text":"","title":"4.2.5.\u590d\u6742\u5ea6\u7684\u6743\u8861\uff1a\u65f6\u95f4\u3001\u7a7a\u95f4\u548c\u6570\u7ec4"},{"location":"python/DataStructure/04_ArrayChain/#426","text":"1\uff0e\u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48\u63d2\u5165\u6216\u5220\u9664\u7ed9\u5b9a\u5143\u7d20\u65f6\u5fc5\u987b\u8981\u79fb\u52a8\u6570\u7ec4\u91cc\u7684\u67d0\u4e9b\u5143\u7d20\u3002 2\uff0e\u5728\u63d2\u5165\u8fc7\u7a0b\u4e2d\uff0c\u79fb\u52a8\u6570\u7ec4\u5143\u7d20\u65f6\uff0c\u8981\u5148\u79fb\u52a8\u54ea\u4e2a\u5143\u7d20\uff1f\u5148\u79fb\u52a8\u63d2\u5165\u4f4d\u7f6e\u7684\u5143\u7d20\uff0c\u8fd8\u662f\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff1f\u4e3a\u4ec0\u4e48\uff1f 3\uff0e\u5982\u679c\u63d2\u5165\u4f4d\u7f6e\u662f\u6570\u7ec4\u7684\u903b\u8f91\u672b\u5c3e\uff0c\u8bf7\u8bf4\u660e\u8fd9\u4e2a\u63d2\u5165\u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u590d\u6742\u5ea6\u3002 4\uff0e\u5047\u8bbe\u6570\u7ec4\u5f53\u524d\u5305\u542b14\u4e2a\u5143\u7d20\uff0c\u5b83\u7684\u8d1f\u8f7d\u56e0\u5b50\u4e3a0.70\uff0c\u90a3\u4e48\u5b83\u7684\u7269\u7406\u5bb9\u91cf\u662f\u591a\u5c11\uff1f","title":"4.2.6.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#43","text":"","title":"4.3.\u4e8c\u7ef4\u6570\u7ec4\uff08\u7f51\u683c\uff09"},{"location":"python/DataStructure/04_ArrayChain/#431","text":"","title":"4.3.1.\u4f7f\u7528\u7f51\u683c"},{"location":"python/DataStructure/04_ArrayChain/#432","text":"","title":"4.3.2.\u521b\u5efa\u5e76\u521d\u59cb\u5316\u7f51\u683c"},{"location":"python/DataStructure/04_ArrayChain/#433grid","text":"","title":"4.3.3.\u5b9a\u4e49Grid\u7c7b"},{"location":"python/DataStructure/04_ArrayChain/#434","text":"","title":"4.3.4.\u53c2\u5dee\u4e0d\u9f50\u7684\u7f51\u683c\u548c\u591a\u7ef4\u6570\u7ec4"},{"location":"python/DataStructure/04_ArrayChain/#435","text":"1\uff0e\u4ec0\u4e48\u662f\u4e8c\u7ef4\u6570\u7ec4\uff08\u7f51\u683c\uff09\uff1f 2\uff0e\u8bf7\u63cf\u8ff0\u4e00\u4e2a\u53ef\u80fd\u4f1a\u7528\u5230\u4e8c\u7ef4\u6570\u7ec4\u7684\u5e94\u7528\u7a0b\u5e8f\u3002 3\uff0e\u7f16\u5199\u4e00\u4e2a\u7a0b\u5e8f\uff0c\u4f7f\u4e4b\u53ef\u4ee5\u5728Grid\u5bf9\u8c61\u91cc\u641c\u7d22\u4e00\u4e2a\u8d1f\u6574\u6570\u3002\u5faa\u73af\u5e94\u8be5\u5728\u9047\u5230\u7f51\u683c\u91cc\u7684\u7b2c\u4e00\u4e2a\u8d1f\u6574\u6570\u7684\u5730\u65b9\u7ec8\u6b62\uff0c\u8fd9\u65f6\u53d8\u91cfrow\u548ccolumn\u5e94\u8be5\u88ab\u8bbe\u7f6e\u4e3a\u8fd9\u4e2a\u8d1f\u6570\u7684\u4f4d\u7f6e\u3002\u5982\u679c\u5728\u7f51\u683c\u91cc\u627e\u4e0d\u5230\u8d1f\u6570\uff0c\u90a3\u4e48\u53d8\u91cfrow\u548ccolumn\u5e94\u8be5\u7b49\u4e8e\u7f51\u683c\u7684\u884c\u6570\u548c\u5217\u6570\u3002 4\uff0e\u8bf4\u8bf4\u8fd0\u884c\u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u540e\u7f51\u683c\u91cc\u7684\u5185\u5bb9\u662f\u4ec0\u4e48\u3002 matrix = Grid ( 3 , 3 ) for row in range ( matrix . getHeight ()): for column in range ( matrix . getWidth ()): matrix [ row ][ column ] = row * column 5\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\u4ee5\u521b\u5efa\u4e00\u4e2a\u53c2\u5dee\u4e0d\u9f50\u7684\u7f51\u683c\uff0c\u5b83\u7684\u884c\u5206\u522b\u7528\u6765\u5b58\u50a83\u4e2a\u30016\u4e2a\u548c9\u4e2a\u5143\u7d20\u3002 6\uff0e\u63d0\u4f9b\u4e00\u4e2a\u628aGrid\u7c7b\u7528\u4f5c\u6570\u636e\u7ed3\u6784\u6765\u5b9e\u73b0\u4e09\u7ef4array\u7c7b\u7684\u7b56\u7565\u3002 7\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\uff1a\u8fd9\u6bb5\u4ee3\u7801\u4f1a\u628a\u4e09\u7ef4\u6570\u7ec4\u91cc\u6bcf\u4e2a\u5355\u5143\u7684\u503c\u90fd\u521d\u59cb\u5316\u4e3a\u5b83\u76843\u4e2a\u7d22\u5f15\u4f4d\u7f6e\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4f4d\u7f6e\u662f\uff08\u6df1\u5ea6\u3001\u884c\u3001\u5217\uff09\uff0c\u5219\u5bf9\u4e8e\u4f4d\u7f6e\uff082\u30013\u30013\uff09\u6765\u8bf4\uff0c\u5b83\u7684\u503c\u5c31\u662f233\u3002 8\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\uff1a\u8fd9\u6bb5\u4ee3\u7801\u53ef\u4ee5\u663e\u793a\u51fa\u4e09\u7ef4\u6570\u7ec4\u91cc\u7684\u6240\u6709\u5143\u7d20\u3002\u6253\u5370\u51fa\u7684\u6bcf\u4e00\u884c\u6570\u636e\u90fd\u5e94\u8be5\u4ee3\u8868\u7ed9\u5b9a\u884c\u548c\u5217\u91cc\u7684\u6240\u6709\u5143\u7d20\uff0c\u800c\u6df1\u5ea6\u5c06\u4ece\u7b2c\u4e00\u4e2a\u4f4d\u7f6e\u5411\u540e\u9012\u5f52\u5230\u6700\u540e\u4e00\u4e2a\u4f4d\u7f6e\u3002\u904d\u5386\u5e94\u8be5\u4ece\u7b2c1\u884c\u3001\u7b2c1\u5217\u4ee5\u53ca\u7b2c\u4e00\u4e2a\u6df1\u5ea6\u4f4d\u7f6e\u5f00\u59cb\uff0c\u4f9d\u6b21\u904d\u5386\u6240\u6709\u7684\u6df1\u5ea6\u3001\u5217\u548c\u884c\u3002","title":"4.3.5.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#44","text":"","title":"4.4.\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#441","text":"","title":"4.4.1.\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u548c\u53cc\u5411\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#442","text":"","title":"4.4.2.\u975e\u8fde\u7eed\u5185\u5b58\u548c\u8282\u70b9"},{"location":"python/DataStructure/04_ArrayChain/#443","text":"","title":"4.4.3.\u5b9a\u4e49\u5355\u5411\u94fe\u63a5\u8282\u70b9\u7c7b"},{"location":"python/DataStructure/04_ArrayChain/#444","text":"","title":"4.4.4.\u4f7f\u7528\u5355\u5411\u94fe\u63a5\u8282\u70b9\u7c7b"},{"location":"python/DataStructure/04_ArrayChain/#445","text":"1\uff0e\u7528\u6846\u548c\u6307\u9488\u7ed8\u5236\u6d4b\u8bd5\u7a0b\u5e8f\u91cc\u7b2c\u4e00\u4e2a\u5faa\u73af\u6240\u521b\u5efa\u7684\u8282\u70b9\u7684\u793a\u610f\u56fe\u3002 2\uff0e\u5f53\u8282\u70b9\u53d8\u91cf\u5f15\u7528\u7684\u662fNone\u65f6\uff0c\u5982\u679c\u7a0b\u5e8f\u5458\u5c1d\u8bd5\u8bbf\u95ee\u8282\u70b9\u7684\u6570\u636e\u5b57\u6bb5\uff0c\u5219\u4f1a\u53d1\u751f\u4ec0\u4e48\uff1f\u5982\u4f55\u9632\u6b62\u8fd9\u79cd\u60c5\u51b5\u7684\u53d1\u751f\uff1f 3\uff0e\u7f16\u5199\u4e00\u6bb5\u4ee3\u7801\uff1a\u8fd9\u6bb5\u4ee3\u7801\u4f1a\u628a\u4e00\u4e2a\u88ab\u586b\u6ee1\u7684\u6570\u7ec4\u91cc\u7684\u5143\u7d20\u90fd\u8f6c\u79fb\u4e3a\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u6570\u636e\u3002\u8fd9\u4e2a\u64cd\u4f5c\u5e94\u4fdd\u7559\u5143\u7d20\u7684\u987a\u5e8f\u4e0d\u53d8\u3002","title":"4.4.5.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#45","text":"","title":"4.5.\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4e0a\u7684\u64cd\u4f5c"},{"location":"python/DataStructure/04_ArrayChain/#451","text":"","title":"4.5.1.\u904d\u5386"},{"location":"python/DataStructure/04_ArrayChain/#452","text":"","title":"4.5.2.\u641c\u7d22"},{"location":"python/DataStructure/04_ArrayChain/#453","text":"","title":"4.5.3.\u66ff\u6362"},{"location":"python/DataStructure/04_ArrayChain/#454","text":"","title":"4.5.4.\u5728\u5f00\u59cb\u5904\u63d2\u5165"},{"location":"python/DataStructure/04_ArrayChain/#455","text":"","title":"4.5.5.\u5728\u7ed3\u5c3e\u5904\u63d2\u5165"},{"location":"python/DataStructure/04_ArrayChain/#456","text":"","title":"4.5.6.\u5728\u5f00\u59cb\u5904\u5220\u9664"},{"location":"python/DataStructure/04_ArrayChain/#457","text":"","title":"4.5.7.\u5728\u7ed3\u5c3e\u5904\u5220\u9664"},{"location":"python/DataStructure/04_ArrayChain/#458","text":"","title":"4.5.8.\u5728\u4efb\u610f\u4f4d\u7f6e\u5904\u63d2\u5165"},{"location":"python/DataStructure/04_ArrayChain/#459","text":"","title":"4.5.9.\u5728\u4efb\u610f\u4f4d\u7f6e\u5904\u5220\u9664"},{"location":"python/DataStructure/04_ArrayChain/#4510","text":"","title":"4.5.10.\u590d\u6742\u5ea6\u7684\u6743\u8861\uff1a\u65f6\u95f4\u3001\u7a7a\u95f4\u548c\u5355\u5411\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#4511","text":"1\uff0e\u5047\u8bbe\u5df2\u7ecf\u627e\u5230\u4e86\u4ece\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u5220\u9664\u5143\u7d20\u7684\u4f4d\u7f6e\uff0c\u8bf7\u8bf4\u660e\u4ece\u8fd9\u4e2a\u65f6\u5019\u5f00\u59cb\u5b8c\u6210\u5220\u9664\u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u590d\u6742\u5ea6\u3002 2\uff0e\u53ef\u4ee5\u5bf9\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u6309\u987a\u5e8f\u6392\u5217\u7684\u5143\u7d20\u6267\u884c\u4e8c\u5206\u641c\u7d22\u5417\uff1f\u5982\u679c\u4e0d\u53ef\u4ee5\uff0c\u4e3a\u4ec0\u4e48\uff1f 3\uff0e\u8bf7\u8bf4\u660e\u4e3a\u4ec0\u4e48Python\u5217\u8868\u4f1a\u4f7f\u7528\u6570\u7ec4\u800c\u4e0d\u662f\u94fe\u63a5\u7ed3\u6784\u6765\u4fdd\u5b58\u5b83\u7684\u5143\u7d20\u3002","title":"4.5.11.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#46","text":"","title":"4.6.\u94fe\u63a5\u4e0a\u7684\u53d8\u5316"},{"location":"python/DataStructure/04_ArrayChain/#461","text":"","title":"4.6.1.\u5305\u542b\u865a\u62df\u5934\u8282\u70b9\u7684\u73af\u72b6\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#462","text":"","title":"4.6.2.\u53cc\u5411\u94fe\u63a5\u7ed3\u6784"},{"location":"python/DataStructure/04_ArrayChain/#463","text":"1\uff0e\u5305\u542b\u865a\u62df\u5934\u8282\u70b9\u7684\u73af\u72b6\u94fe\u63a5\u7ed3\u6784\u7ed9\u7a0b\u5e8f\u5458\u5e26\u6765\u4e86\u4ec0\u4e48\u597d\u5904\uff1f 2\uff0e\u548c\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u76f8\u6bd4\uff0c\u8bf7\u63cf\u8ff0\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u4e00\u4e2a\u597d\u5904\u548c\u4e00\u4e2a\u989d\u5916\u5f00\u9500\u3002","title":"4.6.3.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#47","text":"\u6570\u636e\u7ed3\u6784\u662f\u4e00\u4e2a\u8868\u793a\u591a\u9879\u96c6\u91cc\u6240\u5305\u542b\u6570\u636e\u7684\u5bf9\u8c61\u3002 \u6570\u7ec4\u662f\u4e00\u79cd\u5728\u5e38\u6570\u65f6\u95f4\u5185\u652f\u6301\u5bf9\u4f4d\u7f6e\u9010\u9879\u968f\u673a\u8bbf\u95ee\u7684\u6570\u636e\u7ed3\u6784\u3002\u5728\u521b\u5efa\u6570\u7ec4\u65f6\uff0c\u4f1a\u4e3a\u5b83\u5206\u914d\u82e5\u5e72\u4e2a\u7528\u6765\u5b58\u653e\u6570\u636e\u7684\u5185\u5b58\u7a7a\u95f4\uff0c\u5e76\u4e14\u6570\u7ec4\u7684\u957f\u5ea6\u4f1a\u4fdd\u6301\u4e0d\u53d8\u3002\u63d2\u5165\u548c\u5220\u9664\u64cd\u4f5c\u9700\u8981\u79fb\u52a8\u6570\u636e\u5143\u7d20\uff0c\u5e76\u4e14\u53ef\u80fd\u9700\u8981\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u3001\u66f4\u5927\u6216\u66f4\u5c0f\u7684\u6570\u7ec4\u3002 \u4e8c\u7ef4\u6570\u7ec4\u91cc\u7684\u6bcf\u4e2a\u6570\u636e\u503c\u90fd\u4f4d\u4e8e\u77e9\u5f62\u7f51\u683c\u7684\u884c\u548c\u5217\u4e0a\u3002 \u94fe\u63a5\u7ed3\u6784\u662f\u75310\u4e2a\u6216\u591a\u4e2a\u8282\u70b9\u7ec4\u6210\u7684\u6570\u636e\u7ed3\u6784\u3002\u6bcf\u4e2a\u8282\u70b9\u90fd\u5305\u542b\u4e00\u4e2a\u6570\u636e\u5143\u7d20\u548c\u4e00\u4e2a\u6216\u591a\u4e2a\u6307\u5411\u5176\u4ed6\u8282\u70b9\u7684\u94fe\u63a5\u3002 \u5355\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u8282\u70b9\u5305\u542b\u6570\u636e\u5143\u7d20\u548c\u5230\u4e0b\u4e00\u4e2a\u8282\u70b9\u7684\u94fe\u63a5\u3002\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u8282\u70b9\u8fd8\u5305\u542b\u5230\u524d\u4e00\u4e2a\u8282\u70b9\u7684\u94fe\u63a5\u3002 \u5728\u94fe\u63a5\u7ed3\u6784\u91cc\u8fdb\u884c\u63d2\u5165\u6216\u5220\u9664\u64cd\u4f5c\u4e0d\u9700\u8981\u79fb\u52a8\u6570\u636e\u5143\u7d20\uff0c\u6bcf\u6b21\u6700\u591a\u53ea\u4f1a\u521b\u5efa\u4e00\u4e2a\u8282\u70b9\u3002\u4f46\u662f\uff0c\u5728\u94fe\u63a5\u7ed3\u6784\u91cc\u6267\u884c\u63d2\u5165\u3001\u5220\u9664\u548c\u8bbf\u95ee\u64cd\u4f5c\u9700\u8981\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662f\u7ebf\u6027\u7684\u3002 \u5728\u94fe\u63a5\u7ed3\u6784\u91cc\u4f7f\u7528\u5934\u8282\u70b9\u53ef\u4ee5\u7b80\u5316\u67d0\u4e9b\u64cd\u4f5c\uff0c\u5982\u6dfb\u52a0\u6216\u5220\u9664\u5143\u7d20\u3002","title":"4.7.\u5c0f\u7ed3"},{"location":"python/DataStructure/04_ArrayChain/#48","text":"1\uff0e\u6570\u7ec4\u548c\u94fe\u63a5\u7ed3\u6784\u90fd\u662f\uff1a \u62bd\u8c61\u6570\u636e\u7c7b\u578b\uff08ADT\uff09 \u6570\u636e\u7ed3\u6784 2\uff0e\u6570\u7ec4\u7684\u957f\u5ea6\uff1a \u5728\u521b\u5efa\u4e4b\u540e\u5927\u5c0f\u662f\u56fa\u5b9a\u7684 \u5728\u521b\u5efa\u4e4b\u540e\u5927\u5c0f\u53ef\u4ee5\u589e\u52a0\u6216\u51cf\u5c11 3\uff0e\u5728\u6570\u7ec4\u91cc\u8fdb\u884c\u968f\u673a\u8bbf\u95ee\u652f\u6301\u5728\uff1a \u5e38\u6570\u65f6\u95f4\u91cc\u8bbf\u95ee\u6570\u636e \u7ebf\u6027\u65f6\u95f4\u91cc\u8bbf\u95ee\u6570\u636e 4\uff0e\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u6570\u636e\u5305\u542b\u5728\uff1a \u5355\u5143\u91cc \u8282\u70b9\u91cc 5\uff0e\u5bf9\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u6267\u884c\u7684\u5927\u591a\u6570\u64cd\u4f5c\u90fd\u9700\u8981\uff1a \u5e38\u6570\u65f6\u95f4 \u7ebf\u6027\u65f6\u95f4 6\uff0e\u4ece\u4ee5\u4e0b\u54ea\u79cd\u7c7b\u578b\u91cc\u5220\u9664\u7b2c\u4e00\u4e2a\u5143\u7d20\u9700\u8981\u5e38\u6570\u65f6\u95f4\uff1a \u6570\u7ec4 \u5355\u5411\u94fe\u63a5\u7ed3\u6784 7\uff0e\u5728\u4e0b\u9762\u54ea\u79cd\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u91cc\u4f7f\u7528\u7684\u5185\u5b58\u4f1a\u5c11\u4e8e\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u7684\uff1a \u4e0d\u5230\u4e00\u534a\u7684\u4f4d\u7f6e\u653e\u7f6e\u4e86\u6570\u636e \u4e00\u534a\u4ee5\u4e0a\u7684\u4f4d\u7f6e\u653e\u7f6e\u4e86\u6570\u636e 8\uff0e\u5f53\u6570\u7ec4\u7684\u5185\u5b58\u4e0d\u8db3\u4ee5\u4fdd\u5b58\u6570\u636e\u65f6\uff0c\u6700\u597d\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u6570\u7ec4\uff0c\u8fd9\u4e2a\u65b0\u6570\u7ec4\u5e94\u8be5\uff1a \u5927\u5c0f\u6bd4\u65e7\u6570\u7ec4\u591a1\u4e2a\u4f4d\u7f6e \u5927\u5c0f\u662f\u65e7\u6570\u7ec4\u76842\u500d 9\uff0e\u5bf9\u4e8e\u5355\u5411\u94fe\u63a5\u7ed3\u6784\uff0c\u5f53\u4f60\u5728\u4ec0\u4e48\u5730\u65b9\u6267\u884c\u63d2\u5165\u64cd\u4f5c\u4f1a\u5f97\u5230\u6700\u574f\u60c5\u51b5\u4e0b\u7684\u8fd0\u884c\u65f6\uff1a \u5728\u7ed3\u6784\u7684\u5f00\u5934 \u5728\u7ed3\u6784\u7684\u672b\u5c3e 10\uff0e\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u8ba9\u7a0b\u5e8f\u5458\u53ef\u4ee5\u79fb\u52a8\u5230\uff1a \u7ed9\u5b9a\u8282\u70b9\u7684\u540e\u4e00\u4e2a\u8282\u70b9\u6216\u524d\u4e00\u4e2a\u8282\u70b9 \u7ed9\u5b9a\u8282\u70b9\u7684\u540e\u4e00\u4e2a\u8282\u70b9","title":"4.8.\u590d\u4e60\u9898"},{"location":"python/DataStructure/04_ArrayChain/#49","text":"\u5728\u524d6\u4e2a\u9879\u76ee\u91cc\uff0c\u4f60\u5c06\u4fee\u6539\u5728\u672c\u7ae0\u5b9a\u4e49\u7684Array\u7c7b\uff0c\u4ece\u800c\u8ba9\u5b83\u66f4\u50cfPython\u7684list\u7c7b\u3002\u5bf9\u4e8e\u8fd9\u4e9b\u9879\u76ee\u7684\u7b54\u6848\uff0c\u8bf7\u5305\u542b\u4f60\u5bf9Array\u7c7b\u6240\u505a\u4fee\u6539\u7684\u4ee3\u7801\u6d4b\u8bd5\u3002 1\uff0e\u4e3aArray\u7c7b\u6dfb\u52a0\u4e00\u4e2a\u5b9e\u4f8b\u53d8\u91cf logicalSize \u3002\u8fd9\u4e2a\u53d8\u91cf\u7684\u521d\u59cb\u503c\u4e3a 0 \uff0c\u7528\u6765\u8bb0\u5f55\u6570\u7ec4\u91cc\u5f53\u524d\u5df2\u7ecf\u5305\u542b\u7684\u5143\u7d20\u6570\u91cf\u3002\u7136\u540e\u4e3aArray\u7c7b\u6dfb\u52a0 size() \u65b9\u6cd5\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u7528\u6765\u8fd4\u56de\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\u3002 __len__ \u65b9\u6cd5\u4f9d\u7136\u4f1a\u8fd4\u56de\u6570\u7ec4\u7684\u5bb9\u91cf\uff0c\u4e5f\u5c31\u662f\u5b83\u7684\u7269\u7406\u5c3a\u5bf8\u3002 2\uff0e\u4e3aArray\u7c7b\u7684 __getitem__ \u548c_ _setitem__ \u65b9\u6cd5\u6dfb\u52a0\u5148\u9a8c\u6761\u4ef6\u3002\u5b83\u4eec\u7684\u5148\u9a8c\u6761\u4ef6\u662f 0<=index < size() \u3002\u5982\u679c\u4e0d\u6ee1\u8db3\u5148\u9a8c\u6761\u4ef6\uff0c\u5c31\u5f15\u53d1\u5f02\u5e38\u3002 3\uff0e\u5c06 grow \u548c shrink \u65b9\u6cd5\u6dfb\u52a0\u5230Array\u7c7b\u3002\u5b83\u4eec\u80fd\u591f\u57fa\u4e8e\u672c\u7ae0\u6240\u8ba8\u8bba\u7684\u7b56\u7565\u6765\u589e\u52a0\u6216\u51cf\u5c11\u6570\u7ec4\u91cc\u6240\u5305\u542b\u7684\u5217\u8868\u957f\u5ea6\u3002\u5728\u5b9e\u73b0\u65f6\uff0c\u8981\u4fdd\u8bc1\u6570\u7ec4\u7684\u7269\u7406\u5c3a\u5bf8\u4e0d\u4f1a\u7f29\u5c0f\u5230\u7528\u6237\u6307\u5b9a\u7684\u5bb9\u91cf\u4e4b\u4e0b\uff0c\u5e76\u4e14\u5728\u589e\u52a0\u6570\u7ec4\u5c3a\u5bf8\u65f6\uff0c\u6570\u7ec4\u7684\u5185\u5b58\u5355\u5143\u5c06\u4f1a\u7528\u9ed8\u8ba4\u503c\u6765\u586b\u5145\u3002 4\uff0e\u5c06\u65b9\u6cd5 insert \u548c pop \u6dfb\u52a0\u5230Array\u7c7b\u4e2d\u3002\u5b83\u4eec\u57fa\u4e8e\u672c\u7ae0\u5df2\u7ecf\u8ba8\u8bba\u8fc7\u7684\u7b56\u7565\uff0c\u5728\u9700\u8981\u7684\u65f6\u5019\u5bf9\u6570\u7ec4\u7684\u957f\u5ea6\u8fdb\u884c\u8c03\u6574\u3002 insert \u65b9\u6cd5\u4f1a\u63a5\u6536\u4e00\u4e2a\u4f4d\u7f6e\u548c\u4e00\u4e2a\u5143\u7d20\u503c\u4f5c\u4e3a\u53c2\u6570\uff0c\u7136\u540e\u628a\u8fd9\u4e2a\u5143\u7d20\u63d2\u5165\u6307\u5b9a\u7684\u4f4d\u7f6e\u3002\u5982\u679c\u4f4d\u7f6e\u5927\u4e8e\u6216\u7b49\u4e8e\u6570\u7ec4\u7684\u903b\u8f91\u5c3a\u5bf8\uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u628a\u5143\u7d20\u63d2\u5165\u6570\u7ec4\u91cc\u5f53\u524d\u53ef\u83b7\u5f97\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\u4e4b\u540e\u3002 pop \u65b9\u6cd5\u4f1a\u63a5\u6536\u4e00\u4e2a\u4f4d\u7f6e\u4f5c\u4e3a\u53c2\u6570\uff0c\u7136\u540e\u5220\u9664\u5e76\u8fd4\u56de\u8fd9\u4e2a\u4f4d\u7f6e\u7684\u5143\u7d20\u3002 pop \u65b9\u6cd5\u7684\u5148\u9a8c\u6761\u4ef6\u662f 0<=index < size() \u3002 pop \u65b9\u6cd5\u8fd8\u5e94\u8be5\u628a\u817e\u51fa\u6765\u7684\u6570\u7ec4\u5185\u5b58\u5355\u5143\u91cd\u7f6e\u4e3a\u586b\u5145\u503c\u3002 5\uff0e\u5c06\u65b9\u6cd5 __eq__ \u6dfb\u52a0\u5230Array\u7c7b\u4e2d\u3002\u5f53Array\u5bf9\u8c61\u4f5c\u4e3a == \u8fd0\u7b97\u7b26\u7684\u5de6\u64cd\u4f5c\u6570\u65f6\uff0cPython\u4f1a\u8fd0\u884c\u8fd9\u4e2a\u65b9\u6cd5\u3002\u5982\u679c\u8fd9\u4e2a\u65b9\u6cd5\u7684\u53c2\u6570\u4e5f\u662f\u4e00\u4e2aArray\u5bf9\u8c61\uff0c\u5e76\u4e14\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\u548c\u5de6\u64cd\u4f5c\u6570\u76f8\u540c\uff0c\u4e14\u5728\u4e24\u4e2a\u6570\u7ec4\u91cc\u6bcf\u4e2a\u903b\u8f91\u4f4d\u7f6e\u4e0a\u7684\u5143\u7d20\u90fd\u76f8\u7b49\uff0c\u90a3\u4e48\u8fd9\u4e2a\u65b9\u6cd5\u4f1a\u8fd4\u56de True \uff1b\u5426\u5219\uff0c\u8fd9\u4e2a\u65b9\u6cd5\u8fd4\u56de False \u3002 6\uff0e\u4e3a\u4e86\u8ba9Array\u7c7b\u548c\u5217\u8868\u4e00\u6837\uff0c\u5e94\u8be5\u5220\u9664 __iter__ \u65b9\u6cd5\u7684\u5f53\u524d\u5b9e\u73b0\u3002\u8bf7\u89e3\u91ca\u8fd9\u4e3a\u4ec0\u4e48\u662f\u4e00\u4e2a\u597d\u5efa\u8bae\uff0c\u5e76\u8bf4\u660e\u5728\u8fd9\u4e2a\u60c5\u51b5\u4e0b\u5e94\u8be5\u5982\u4f55\u5bf9 __str__ \u65b9\u6cd5\u8fdb\u884c\u4fee\u6539\u3002 7\uff0e Matrix \u7c7b\u53ef\u4ee5\u6267\u884c\u7ebf\u6027\u4ee3\u6570\u91cc\u7684\u67d0\u4e9b\u8fd0\u7b97\uff0c\u6bd4\u5982\u77e9\u9635\u8fd0\u7b97\u3002\u5f00\u53d1\u4e00\u4e2a\u4f7f\u7528\u5185\u7f6e\u8fd0\u7b97\u7b26\u8fdb\u884c\u7b97\u672f\u8fd0\u7b97\u7684 Matrix \u7c7b\uff0c\u8fd9\u4e2a Matrix \u7c7b\u5e94\u6269\u5c55\u81ea Grid \u7c7b\u3002\u5728\u63a5\u4e0b\u6765\u76844\u4e2a\u9879\u76ee\u91cc\uff0c\u4f60\u5e94\u5b9a\u4e49\u4e00\u4e9b\u7528\u6765\u64cd\u4f5c\u94fe\u63a5\u7ed3\u6784\u7684\u51fd\u6570\u3002\u5728\u89e3\u7b54\u7684\u8fc7\u7a0b\u4e2d\uff0c\u4f60\u5e94\u8be5\u7ee7\u7eed\u4f7f\u7528\u672c\u7ae0\u5b9a\u4e49\u7684 Node \u548c TwoWayNode \u7c7b\u3002\u521b\u5efa\u4e00\u4e2a\u6d4b\u8bd5\u6a21\u5757\u4ee5\u5305\u542b\u4f60\u7684\u51fd\u6570\u5b9a\u4e49\u548c\u7528\u6765\u6d4b\u8bd5\u5b83\u4eec\u7684\u4ee3\u7801\u3002 8\uff0e\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c length \u7684\u51fd\u6570\uff08\u4e0d\u662f len \uff09\uff0c\u8fd9\u4e2a\u51fd\u6570\u4f1a\u63a5\u53d7\u4e00\u4e2a\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4f5c\u4e3a\u53c2\u6570\uff0c\u5e76\u80fd\u591f\u8fd4\u56de\u7ed3\u6784\u91cc\u7684\u5143\u7d20\u6570\u91cf\u3002 9\uff0e\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c insert \u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u5177\u6709\u628a\u5143\u7d20\u63d2\u5165\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4e2d\u6307\u5b9a\u4f4d\u7f6e\u7684\u529f\u80fd\u3002\u8fd9\u4e2a\u51fd\u6570\u67093\u4e2a\u53c2\u6570\uff1a\u5143\u7d20\u3001\u4f4d\u7f6e\u4ee5\u53ca\u4e00\u4e2a\u94fe\u63a5\u7ed3\u6784\uff08\u8fd9\u4e2a\u94fe\u63a5\u7ed3\u6784\u53ef\u80fd\u4e3a\u7a7a\uff09\u3002\u8fd9\u4e2a\u51fd\u6570\u80fd\u591f\u8fd4\u56de\u4fee\u6539\u4e4b\u540e\u7684\u94fe\u63a5\u7ed3\u6784\u3002\u5982\u679c\u4f20\u9012\u7684\u4f4d\u7f6e\u5927\u4e8e\u6216\u7b49\u4e8e\u94fe\u63a5\u7ed3\u6784\u7684\u957f\u5ea6\uff0c\u90a3\u4e48\u8fd9\u4e2a\u51fd\u6570\u4f1a\u628a\u5143\u7d20\u63d2\u5165\u5b83\u7684\u672b\u5c3e\u3002\u8fd9\u4e2a\u51fd\u6570\u7684\u8c03\u7528\u793a\u4f8b\u662f head =insert(1,data,head) \uff0c\u5176\u4e2d head \u662f\u4e00\u4e2a\u53d8\u91cf\uff0c\u8fd9\u4e2a\u53d8\u91cf\u8981\u4e48\u4e3a\u7a7a\u94fe\u63a5\uff0c\u8981\u4e48\u6307\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u7b2c\u4e00\u4e2a\u8282\u70b9\u3002 10\uff0e\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c pop \u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u80fd\u591f\u5728\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u7684\u6307\u5b9a\u4f4d\u7f6e\u4e0a\u5220\u9664\u5143\u7d20\u3002\u8fd9\u4e2a\u51fd\u6570\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u662f\u4f4d\u7f6e\uff0c\u5b83\u7684\u5148\u9a8c\u6761\u4ef6\u662f 0<=position<\u7ed3\u6784\u7684\u957f\u5ea6 \u3002\u5b83\u7684\u7b2c\u4e8c\u4e2a\u53c2\u6570\u662f\u4e00\u4e2a\u94fe\u63a5\u7ed3\u6784\uff0c\u5f88\u660e\u663e\u5b83\u4e0d\u5e94\u8be5\u4e3a\u7a7a\u3002\u8fd9\u4e2a\u51fd\u6570\u5c06\u4f1a\u8fd4\u56de\u4e00\u4e2a\u5143\u7ec4\uff0c\u5305\u542b\u4fee\u6539\u540e\u7684\u94fe\u63a5\u7ed3\u6784\u548c\u5220\u9664\u7684\u5143\u7d20\u3002\u5b83\u7684\u8c03\u7528\u793a\u4f8b\u662f (head, item) = pop(1,head) \u3002 11\uff0e\u5b9a\u4e49\u4e00\u4e2a\u51fd\u6570 makeTwoWay \uff0c\u8fd9\u4e2a\u51fd\u6570\u4f1a\u63a5\u53d7\u4e00\u4e2a\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u4f5c\u4e3a\u53c2\u6570\uff0c\u7136\u540e\u751f\u6210\u5e76\u8fd4\u56de\u4e00\u4e2a\u5305\u542b\u5355\u5411\u94fe\u63a5\u7ed3\u6784\u91cc\u7684\u5143\u7d20\u7684\u53cc\u5411\u94fe\u63a5\u7ed3\u6784\u3002\uff08\u6ce8\u610f\uff1a\u8fd9\u4e2a\u51fd\u6570\u4e0d\u5e94\u8be5\u5bf9\u4f5c\u4e3a\u53c2\u6570\u7684\u94fe\u63a5\u7ed3\u6784\u8fdb\u884c\u4efb\u4f55\u4fee\u6539\u3002\uff09","title":"4.9.\u7f16\u7a0b\u7ec3\u4e60"},{"location":"python/DataStructure/05_InterfacePolymorphism/","text":"5.\u63a5\u53e3\u3001\u5b9e\u73b0\u548c\u591a\u6001 \u00b6 \u76ee\u6807\uff1a \u4e3a\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u7c7b\u578b\u5f00\u53d1\u63a5\u53e3\uff1b \u6309\u7167\u591a\u9879\u96c6\u7c7b\u578b\u7684\u63a5\u53e3\u5b9e\u73b0\u591a\u4e2a\u7c7b\uff1b \u5bf9\u7ed9\u5b9a\u591a\u9879\u96c6\u7c7b\u578b\u7684\u4e0d\u540c\u5b9e\u73b0\u8bc4\u4f30\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\u7684\u6743\u8861\uff1b \u5b9e\u73b0\u4e00\u4e2a\u7b80\u5355\u7684\u8fed\u4ee3\u5668\uff1b \u4f7f\u7528\u65b9\u6cd5\u5bf9\u5305\u548c\u96c6\u5408\u8fdb\u884c\u64cd\u4f5c\uff1b \u5224\u65ad\u5305\u6216\u96c6\u5408\u662f\u5426\u9002\u5408\u5728\u7ed9\u5b9a\u7684\u5e94\u7528\u7a0b\u5e8f\u91cc\u4f7f\u7528\uff1b \u5c06\u5305\u7684\u5b9e\u73b0\u8f6c\u6362\u6210\u6709\u5e8f\u5305\u7684\u5b9e\u73b0\u3002 5.1.\u5f00\u53d1\u63a5\u53e3 \u00b6 5.1.1.\u8bbe\u8ba1\u5305\u63a5\u53e3 \u00b6 5.1.2.\u6307\u5b9a\u53c2\u6570\u548c\u8fd4\u56de\u503c \u00b6 5.2.\u6784\u9020\u51fd\u6570\u548c\u7c7b\u7684\u5b9e\u73b0 \u00b6 5.2.1.\u524d\u7f6e\u6761\u4ef6\u3001\u540e\u7f6e\u6761\u4ef6\u3001\u5f02\u5e38\u548c\u6587\u6863 \u00b6 5.2.2.\u5728Python\u91cc\u7f16\u5199\u63a5\u53e3 \u00b6 \u7ec3\u4e60\u9898 1\uff0e\u5305\u91cc\u7684\u5143\u7d20\u662f\u6709\u5e8f\u7684\uff0c\u8fd8\u662f\u65e0\u5e8f\u7684\uff1f 2\uff0e\u54ea\u4e9b\u64cd\u4f5c\u4f1a\u51fa\u73b0\u5728\u6240\u6709\u591a\u9879\u96c6\u7684\u63a5\u53e3\u91cc\uff1f 3\uff0e\u54ea\u4e2a\u65b9\u6cd5\u8d1f\u8d23\u521b\u5efa\u591a\u9879\u96c6\u5bf9\u8c61\uff1f 4\uff0e\u8bf7\u8bf4\u51fa\u63a5\u53e3\u4e0e\u5b9e\u73b0\u5206\u79bb\u76843\u4e2a\u539f\u56e0\u3002 5.3.\u5f00\u53d1\u57fa\u4e8e\u6570\u7ec4\u7684\u5b9e\u73b0 \u00b6 5.3.1.\u9009\u62e9\u5e76\u521d\u59cb\u5316\u6570\u636e\u7ed3\u6784 \u00b6 5.3.2.\u5148\u5b8c\u6210\u7b80\u5355\u7684\u65b9\u6cd5 \u00b6 5.3.3.\u5b8c\u6210\u8fed\u4ee3\u5668 \u00b6 5.3.4.\u5b8c\u6210\u4f7f\u7528\u8fed\u4ee3\u5668\u7684\u65b9\u6cd5 \u00b6 5.3.5.in\u8fd0\u7b97\u7b26\u548c__contains__\u65b9\u6cd5 \u00b6 5.3.6.\u5b8c\u6210remove\u65b9\u6cd5 \u00b6 5.3.7.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u89e3\u91ca\u591a\u9879\u96c6\u7c7b\u7684__init__\u65b9\u6cd5\u7684\u4f5c\u7528\u3002 2\uff0e\u4e3a\u4ec0\u4e48\u8c03\u7528\u65b9\u6cd5\u6bd4\u76f4\u63a5\u5728\u7c7b\u91cc\u5f15\u7528\u5b9e\u4f8b\u53d8\u91cf\u66f4\u597d\uff1f 3\uff0e\u5bf9\u4e8eArrayBag\u7684__init__\u65b9\u6cd5\uff0c\u5c55\u793a\u5982\u4f55\u901a\u8fc7\u8c03\u7528clear\u65b9\u6cd5\u6765\u7b80\u5316\u4ee3\u7801\u3002 4\uff0e\u89e3\u91ca\u4e3a\u4ec0\u4e48__iter__\u65b9\u6cd5\u53ef\u80fd\u4f1a\u662f\u591a\u9879\u96c6\u7c7b\u91cc\u6700\u6709\u7528\u7684\u65b9\u6cd5\u3002 5\uff0e\u89e3\u91ca\u4e3a\u4ec0\u4e48\u5728ArrayBag\u7c7b\u4e2d\u4e0d\u7528\u5305\u542b__contains__\u65b9\u6cd5\u3002 5.4.\u5f00\u53d1\u57fa\u4e8e\u94fe\u63a5\u7684\u5b9e\u73b0 \u00b6 5.4.1.\u521d\u59cb\u5316\u6570\u636e\u7ed3\u6784 \u00b6 5.4.2.\u5b8c\u6210\u8fed\u4ee3\u5668 \u00b6 5.4.3.\u5b8c\u6210clear\u548cadd\u65b9\u6cd5 \u00b6 5.4.4.\u5b8c\u6210remove\u65b9\u6cd5 \u00b6 5.4.5.\u7ec3\u4e60\u9898 \u00b6 1\uff0e\u5047\u8bbea\u662f\u4e00\u4e2a\u6570\u7ec4\u5305\uff0cb\u662f\u4e00\u4e2a\u94fe\u63a5\u5305\uff0c\u5b83\u4eec\u90fd\u4e0d\u5305\u542b\u4efb\u4f55\u5143\u7d20\u3002\u8bf7\u63cf\u8ff0\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\u5b83\u4eec\u5728\u5185\u5b58\u4f7f\u7528\u4e0a\u7684\u5dee\u5f02\u3002 2\uff0e\u4e3a\u4ec0\u4e48\u94fe\u63a5\u5305\u4ecd\u7136\u9700\u8981\u4e00\u4e2a\u5355\u72ec\u7684\u5b9e\u4f8b\u53d8\u91cf\u6765\u8bb0\u5f55\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\uff1f 3\uff0e\u4e3a\u4ec0\u4e48\u4ece\u94fe\u63a5\u5305\u91cc\u5220\u9664\u5143\u7d20\u4e4b\u540e\uff0c\u7a0b\u5e8f\u5458\u4e0d\u7528\u62c5\u5fc3\u51fa\u73b0\u5185\u5b58\u6d6a\u8d39\u7684\u60c5\u51b5\uff1f 5.5.\u4e24\u79cd\u5305\u5b9e\u73b0\u7684\u8fd0\u884c\u65f6\u6027\u80fd \u00b6 5.6.\u6d4b\u8bd5\u5305\u7684\u4e24\u79cd\u5b9e\u73b0 \u00b6 5.7.\u4f7f\u7528UML\u7ed8\u5236\u5305\u8d44\u6e90 \u00b6 5.8.\u5c0f\u7ed3 \u00b6 \u63a5\u53e3\u662f\u7528\u6237\u7684\u8f6f\u4ef6\u8d44\u6e90\u53ef\u4ee5\u4f7f\u7528\u7684\u4e00\u7ec4\u64cd\u4f5c\u3002 \u63a5\u53e3\u91cc\u7684\u5143\u7d20\u662f\u51fd\u6570\u548c\u65b9\u6cd5\u7684\u5b9a\u4e49\u4ee5\u53ca\u5b83\u4eec\u7684\u6587\u6863\u3002 \u524d\u7f6e\u6761\u4ef6\u662f\u6307\u5728\u51fd\u6570\u6216\u65b9\u6cd5\u53ef\u4ee5\u6b63\u786e\u5b8c\u6210\u4efb\u52a1\u4e4b\u524d\u5fc5\u987b\u8981\u6ee1\u8db3\u7684\u6761\u4ef6\u3002 \u540e\u7f6e\u6761\u4ef6\u662f\u6307\u5728\u51fd\u6570\u6216\u65b9\u6cd5\u6b63\u786e\u5b8c\u6210\u4efb\u52a1\u4e4b\u540e\u5fc5\u987b\u4e3a\u771f\u7684\u6761\u4ef6\u3002 \u8bbe\u8ba1\u826f\u597d\u7684\u8f6f\u4ef6\u7cfb\u7edf\u4f1a\u628a\u63a5\u53e3\u548c\u5b83\u7684\u5b9e\u73b0\u5206\u5f00\u3002 \u5b9e\u73b0\u662f\u6307\u6ee1\u8db3\u63a5\u53e3\u7684\u51fd\u6570\u3001\u65b9\u6cd5\u6216\u7c7b\u3002 \u591a\u9879\u96c6\u7c7b\u578b\u53ef\u4ee5\u901a\u8fc7\u63a5\u53e3\u8fdb\u884c\u6307\u5b9a\u3002 \u591a\u9879\u96c6\u7c7b\u578b\u53ef\u4ee5\u6709\u51e0\u4e2a\u4e0d\u540c\u7684\u5b9e\u73b0\u7c7b\u3002 \u591a\u6001\u662f\u6307\u5728\u4e24\u4e2a\u6216\u591a\u4e2a\u5b9e\u73b0\u91cc\u4f7f\u7528\u76f8\u540c\u7684\u8fd0\u7b97\u7b26\u3001\u51fd\u6570\u540d\u79f0\u6216\u65b9\u6cd5\u540d\u79f0\u3002\u591a\u6001\u51fd\u6570\u7684\u793a\u4f8b\u662f str \u548c len \uff1b\u591a\u6001\u8fd0\u7b97\u7b26\u7684\u793a\u4f8b\u662f + \u548c == \uff1b\u591a\u6001\u65b9\u6cd5\u7684\u793a\u4f8b\u5305\u62ecadd\u548c isEmpty \u3002 \u5305\u591a\u9879\u96c6\u7c7b\u578b\u662f\u65e0\u5e8f\u7684\uff0c\u5e76\u4e14\u652f\u6301\u6dfb\u52a0\u3001\u5220\u9664\u548c\u8bbf\u95ee\u5176\u5143\u7d20\u7b49\u64cd\u4f5c\u3002 \u7c7b\u56fe\u662f\u4e00\u79cd\u63cf\u8ff0\u7c7b\u4e0e\u7c7b\u4e4b\u95f4\u5173\u7cfb\u7684\u53ef\u89c6\u5316\u8868\u793a\u65b9\u6cd5\u3002 \u7ec4\u5408\u8868\u793a\u4e24\u4e2a\u7c7b\u4e4b\u95f4\u6574\u4f53\u4e0e\u5c40\u90e8\u7684\u5173\u7cfb\u3002 \u805a\u5408\u8868\u793a\u4e24\u4e2a\u7c7b\u4e4b\u95f4\u4e00\u5bf9\u591a\u7684\u5173\u7cfb\u3002 UML\u662f\u4e00\u79cd\u63cf\u8ff0\u8f6f\u4ef6\u8d44\u6e90\u4e4b\u95f4\u5173\u7cfb\u7684\u53ef\u89c6\u5316\u8868\u793a\u65b9\u6cd5\u3002 5.9.\u590d\u4e60\u9898 \u00b6 1\uff0e\u5305\u662f\uff1a \u7ebf\u6027\u591a\u9879\u96c6 \u65e0\u5e8f\u591a\u9879\u96c6 2\uff0e\u7528\u6765\u8bbe\u7f6e\u5bf9\u8c61\u5b9e\u4f8b\u53d8\u91cf\u7684\u521d\u59cb\u72b6\u6001\u7684\u65b9\u6cd5\u662f\uff1a __init__ \u65b9\u6cd5 __str__ \u65b9\u6cd5 3\uff0e\u8ba9\u7a0b\u5e8f\u5458\u53ef\u4ee5\u8bbf\u95ee\u591a\u9879\u96c6\u91cc\u6240\u6709\u5143\u7d20\u7684\u65b9\u6cd5\u662f\uff1a __init__ \u65b9\u6cd5 __iter__ \u65b9\u6cd5 4\uff0e\u6539\u53d8\u5bf9\u8c61\u5185\u90e8\u72b6\u6001\u7684\u65b9\u6cd5\u662f\uff1a \u8bbf\u95ee\u5668\u65b9\u6cd5 \u53d8\u5f02\u5668\u65b9\u6cd5 5\uff0e\u4e00\u7ec4\u53ef\u4ee5\u88ab\u7c7b\u7684\u5ba2\u6237\u7aef\u4f7f\u7528\u7684\u65b9\u6cd5\u96c6\u79f0\u4e3a\uff1a \u5b9e\u73b0 \u63a5\u53e3 6\uff0e\u591a\u6001\u7528\u6765\u4ee3\u8868\u7684\u672f\u8bed\u662f\uff1a \u591a\u4e2a\u7c7b\u91cc\u76f8\u540c\u7684\u65b9\u6cd5\u540d\u79f0 \u7528\u6765\u5b58\u50a8\u53e6\u4e00\u4e2a\u7c7b\u91cc\u6240\u5305\u542b\u6570\u636e\u7684\u7c7b 7\uff0e\u7ec4\u5408\u662f\u6307\uff1a \u4e24\u4e2a\u7c7b\u4e4b\u95f4\u90e8\u5206\u4e0e\u6574\u4f53\u5173\u7cfb \u4e24\u4e2a\u7c7b\u4e4b\u95f4\u591a\u5bf9\u4e00\u5173\u7cfb 8\uff0e\u5305\u4e2dadd\u65b9\u6cd5\u7684\u5e73\u5747\u8fd0\u884c\u65f6\u4e3a\uff1a O(n) O(k) 9\uff0e\u5305\u4e2dremove\u65b9\u6cd5\u7684\u5e73\u5747\u8fd0\u884c\u65f6\u4e3a\uff1a O(n) O(k) 10\uff0e\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u5305\u5b9e\u73b0\u4f1a\u6bd4\u94fe\u63a5\u5305\u5b9e\u73b0\u4f7f\u7528\u66f4\u5c11\u7684\u5185\u5b58\uff1a \u542b\u6709\u5c11\u4e8e\u4e00\u534a\u7684\u6570\u636e \u542b\u6709\u4e00\u534a\u4ee5\u4e0a\u7684\u6570\u636e 5.10.\u7f16\u7a0b\u7ec3\u4e60 \u00b6 1\uff0e\u5bf9\u4e8e\u4e24\u4e2a\u5305\u5b9e\u73b0\uff0c\u786e\u5b9a == \u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u3002\u53ef\u4ee5\u9884\u89c1\u5230\uff0c\u8fd9\u91cc\u6709\u51e0\u79cd\u60c5\u51b5\u9700\u8981\u5206\u6790\u3002 2\uff0e\u5bf9\u4e8e\u5305\u7684\u4e24\u4e2a\u5b9e\u73b0\uff0c\u786e\u5b9a + \u8fd0\u7b97\u7b26\u7684\u8fd0\u884c\u65f6\u3002 3\uff0e\u7f16\u7801 ArrayBag \u91cc add \u65b9\u6cd5\u7684\u4ee3\u7801\uff0c\u4ece\u800c\u53ef\u4ee5\u5728\u9700\u8981\u7684\u65f6\u5019\u5bf9\u6570\u7ec4\u5c3a\u5bf8\u8fdb\u884c\u8c03\u6574\u3002 4\uff0e\u7f16\u7801 ArrayBag \u91cc remove \u65b9\u6cd5\u7684\u4ee3\u7801\uff0c\u4ece\u800c\u53ef\u4ee5\u5728\u9700\u8981\u7684\u65f6\u5019\u5bf9\u6570\u7ec4\u5c3a\u5bf8\u8fdb\u884c\u8c03\u6574\u3002 5\uff0e\u5728 ArrayBag \u548c LinkedBag \u7c7b\u91cc\u6dfb\u52a0 clone \u65b9\u6cd5\u3002\u8fd9\u4e2a\u65b9\u6cd5\u5728\u8c03\u7528\u7684\u65f6\u5019\uff0c\u4e0d\u4f1a\u63a5\u6536\u4efb\u4f55\u53c2\u6570\uff0c\u5e76\u4e14\u4f1a\u8fd4\u56de\u5f53\u524d\u5305\u7c7b\u578b\u7684\u4e00\u4e2a\u5b8c\u6574\u526f\u672c\u3002\u5728\u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u7684\u6700\u540e\uff0c\u53d8\u91cf bag2 \u5c06\u5305\u542b\u6570\u5b57 2 \u3001 3 \u548c 4 \u3002 bag1 = ArrayBag ([ 2 , 3 , 4 ]) bag2 = bag1 . clone () bag1 == bag2 # Returns True bag1 is bag2 # Returns False 6\uff0e\u96c6\u5408\u662f\u4e00\u4e2a\u65e0\u5e8f\u591a\u9879\u96c6\uff0c\u5e76\u4e14\u548c\u5305\u5177\u6709\u76f8\u540c\u7684\u63a5\u53e3\u3002\u4f46\u662f\u5728\u96c6\u5408\u91cc\uff0c\u5143\u7d20\u662f\u552f\u4e00\u7684\uff0c\u800c\u5305\u91cc\u53ef\u4ee5\u5305\u542b\u91cd\u590d\u7684\u7269\u54c1\u3002\u5b9a\u4e49\u4e00\u4e2a\u57fa\u4e8e\u6570\u7ec4\u7684\u53eb\u4f5c ArraySet \u7684\u591a\u9879\u96c6\u65b0\u7c7b\u3002\u5982\u679c\u96c6\u5408\u91cc\u7684\u5143\u7d20\u5df2\u7ecf\u5b58\u5728\u4e86\uff0c\u90a3\u4e48 add \u65b9\u6cd5\u5c06\u4f1a\u5ffd\u7565\u8fd9\u4e2a\u5143\u7d20\u3002 7\uff0e\u4f7f\u7528\u94fe\u63a5\u8282\u70b9\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c LinkedSet \u7684\u591a\u9879\u96c6\u65b0\u7c7b\u6765\u5b9e\u73b0\u96c6\u5408\u7c7b\u578b\u3002\u5982\u679c\u96c6\u5408\u91cc\u7684\u5143\u7d20\u5df2\u7ecf\u5b58\u5728\u4e86\uff0c\u90a3\u4e48 add \u65b9\u6cd5\u5c06\u4f1a\u5ffd\u7565\u8fd9\u4e2a\u5143\u7d20\u3002 8\uff0e\u6709\u5e8f\u5305\u7684\u884c\u4e3a\u548c\u666e\u901a\u5305\u7684\u662f\u4e00\u6837\u7684\uff0c\u4f46\u662f\u5b83\u80fd\u591f\u8ba9\u7528\u6237\u5728\u4f7f\u7528 for \u5faa\u73af\u65f6\u6309\u7167\u5347\u5e8f\u8bbf\u95ee\u91cc\u9762\u7684\u5143\u7d20\u3002\u56e0\u6b64\uff0c\u6dfb\u52a0\u5230\u8fd9\u4e2a\u5305\u7c7b\u578b\u91cc\u7684\u5143\u7d20\uff0c\u90fd\u5fc5\u987b\u5177\u6709\u4e00\u5b9a\u7684\u987a\u5e8f\u5e76\u4e14\u652f\u6301\u6bd4\u8f83\u8fd0\u7b97\u7b26\u3002\u8fd9\u79cd\u7c7b\u578b\u5143\u7d20\u7684\u7b80\u5355\u4f8b\u5b50\u662f\uff1a\u5b57\u7b26\u4e32\u548c\u6574\u6570\u3002\u5b9a\u4e49\u4e00\u4e2a\u652f\u6301\u8fd9\u4e2a\u529f\u80fd\u7684\u53eb\u4f5c ArraySortedBag \u7684\u65b0\u7c7b\u3002\u548c ArrayBag \u4e00\u6837\uff0c\u8fd9\u4e2a\u65b0\u7c7b\u4f1a\u57fa\u4e8e\u6570\u7ec4\uff0c\u4f46\u662f\u5b83\u7684 in \u64cd\u4f5c\u73b0\u5728\u53ef\u4ee5\u5728\u5bf9\u6570\u65f6\u95f4\u91cc\u8fd0\u884c\u3002\u8981\u5b8c\u6210\u8fd9\u4e00\u70b9\uff0c ArraySortedBag \u5fc5\u987b\u5c06\u65b0\u6dfb\u52a0\u7684\u5143\u7d20\u6309\u7167\u987a\u5e8f\u653e\u5230\u6570\u7ec4\u91cc\u3002\u6700\u7b80\u5355\u7684\u529e\u6cd5\u662f\u4fee\u6539 add \u65b9\u6cd5\uff0c\u4ece\u800c\u8ba9\u65b0\u5143\u7d20\u63d2\u5165\u9002\u5f53\u7684\u4f4d\u7f6e\uff1b\u7136\u540e\uff0c\u6dfb\u52a0_ _contains__ \u65b9\u6cd5\u6765\u63d0\u4f9b\u65b0\u7684\u4e14\u66f4\u6709\u6548\u7684\u641c\u7d22\uff1b\u6700\u540e\uff0c\u8981\u628a\u5bf9 ArrayBag \u7684\u6240\u6709\u5f15\u7528\u90fd\u66ff\u6362\u4e3a ArraySortedBag \u3002\uff08\u63d0\u793a\uff1a\u628a\u4ee3\u7801\u4ece ArrayBag \u7c7b\u4e2d\u590d\u5236\u5230\u4e00\u4e2a\u65b0\u6587\u4ef6\u91cc\uff0c\u7136\u540e\u5728\u8fd9\u4e2a\u65b0\u6587\u4ef6\u91cc\u5f00\u59cb\u4fee\u6539\u3002\uff09 9\uff0e\u786e\u5b9a ArraySortedBag \u91cc add \u65b9\u6cd5\u7684\u8fd0\u884c\u65f6\u3002 10\uff0ePython\u7684 for \u5faa\u73af\u53ef\u4ee5\u8ba9\u7a0b\u5e8f\u5458\u5728\u5faa\u73af\u8fed\u4ee3\u591a\u9879\u96c6\u7684\u65f6\u5019\u5bf9\u5b83\u6267\u884c\u6dfb\u52a0\u6216\u5220\u9664\u5143\u7d20\u7684\u64cd\u4f5c\u3002\u4e00\u4e9b\u8bbe\u8ba1\u4eba\u5458\u62c5\u5fc3\u5728\u8fed\u4ee3\u8fc7\u7a0b\u4e2d\u5bf9\u591a\u9879\u96c6\u7684\u7ed3\u6784\u8fdb\u884c\u4fee\u6539\u53ef\u80fd\u4f1a\u5bfc\u81f4\u7a0b\u5e8f\u5d29\u6e83\u3002\u6709\u4e00\u79cd\u4fee\u6539\u7b56\u7565\u662f\u901a\u8fc7\u7981\u6b62\u5728\u8fed\u4ee3\u671f\u95f4\u5bf9\u591a\u9879\u96c6\u8fdb\u884c\u53d8\u5f02\u6765\u8ba9 for \u5faa\u73af\u6210\u4e3a\u53ea\u8bfb\u3002\u4f60\u53ef\u4ee5\u901a\u8fc7\u5bf9\u53d8\u5f02\u64cd\u4f5c\u8fdb\u884c\u8ba1\u6570\uff0c\u5e76\u4e14\u5224\u65ad\u8fd9\u4e2a\u8ba1\u6570\u6709\u6ca1\u6709\u5728\u591a\u9879\u96c6\u7684 __iter__ \u65b9\u6cd5\u7684\u4efb\u610f\u8282\u62cd\u4e2d\u88ab\u589e\u52a0\u6765\u68c0\u6d4b\u8fd9\u79cd\u7c7b\u578b\u7684\u53d8\u5f02\u3002\u5f53\u53d1\u751f\u8fd9\u79cd\u60c5\u51b5\u65f6\uff0c\u5c31\u53ef\u4ee5\u5f15\u53d1\u5f02\u5e38\u4ece\u800c\u907f\u514d\u8ba1\u7b97\u7684\u7ee7\u7eed\u8fdb\u884c\u3002\u628a\u8fd9\u4e2a\u673a\u5236\u6dfb\u52a0\u5230 ArrayBag \u7c7b\u91cc\u3002\u53ef\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u53eb\u4f5c modCount \u7684\u65b0\u5b9e\u4f8b\u53d8\u91cf\uff0c\u8fd9\u4e2a\u5b9e\u4f8b\u53d8\u91cf\u4f1a\u5728 __init__ \u65b9\u6cd5\u91cc\u8bbe\u7f6e\u4e3a 0 \uff1b\u7136\u540e\uff0c\u6bcf\u4e2a\u53d8\u5f02\u5668\u65b9\u6cd5\u90fd\u4f1a\u9012\u589e\u8fd9\u4e2a\u53d8\u91cf\uff1b\u6700\u540e\uff0c __iter__ \u65b9\u6cd5\u6709\u4e00\u4e2a\u53eb\u4f5c modCount \u7684\u4e34\u65f6\u53d8\u91cf\uff0c\u8fd9\u4e2a\u4e34\u65f6\u53d8\u91cf\u7684\u521d\u59cb\u503c\u662f\u5b9e\u4f8b\u53d8\u91cf self.modCount \u7684\u503c\u3002\u5728 __iter__ \u65b9\u6cd5\u91cc\u8fd4\u56de\u4e00\u4e2a\u5143\u7d20\u540e\uff0c\u5982\u679c\u8fd9\u4e24\u4e2a\u4fee\u6539\u8fc7\u7684\u8ba1\u6570\u5668\u503c\u4e0d\u76f8\u7b49\uff0c\u5c31\u7acb\u5373\u5f15\u53d1\u5f02\u5e38\u3002\u7528\u4e00\u4e2a\u7a0b\u5e8f\u6765\u6d4b\u8bd5\u4f60\u7684\u4fee\u6539\uff0c\u4ece\u800c\u4fdd\u8bc1\u6ee1\u8db3\u76f8\u5e94\u7684\u9700\u6c42\u3002","title":"\u63a5\u53e3\u3001\u5b9e\u73b0\u548c\u591a\u6001"},{"location":"python/DataStructure/05_InterfacePolymorphism/#5","text":"\u76ee\u6807\uff1a \u4e3a\u7ed9\u5b9a\u7684\u591a\u9879\u96c6\u7c7b\u578b\u5f00\u53d1\u63a5\u53e3\uff1b \u6309\u7167\u591a\u9879\u96c6\u7c7b\u578b\u7684\u63a5\u53e3\u5b9e\u73b0\u591a\u4e2a\u7c7b\uff1b \u5bf9\u7ed9\u5b9a\u591a\u9879\u96c6\u7c7b\u578b\u7684\u4e0d\u540c\u5b9e\u73b0\u8bc4\u4f30\u8fd0\u884c\u65f6\u548c\u5185\u5b58\u4f7f\u7528\u60c5\u51b5\u7684\u6743\u8861\uff1b \u5b9e\u73b0\u4e00\u4e2a\u7b80\u5355\u7684\u8fed\u4ee3\u5668\uff1b \u4f7f\u7528\u65b9\u6cd5\u5bf9\u5305\u548c\u96c6\u5408\u8fdb\u884c\u64cd\u4f5c\uff1b \u5224\u65ad\u5305\u6216\u96c6\u5408\u662f\u5426\u9002\u5408\u5728\u7ed9\u5b9a\u7684\u5e94\u7528\u7a0b\u5e8f\u91cc\u4f7f\u7528\uff1b \u5c06\u5305\u7684\u5b9e\u73b0\u8f6c\u6362\u6210\u6709\u5e8f\u5305\u7684\u5b9e\u73b0\u3002","title":"5.\u63a5\u53e3\u3001\u5b9e\u73b0\u548c\u591a\u6001"},{"location":"python/DataStructure/05_InterfacePolymorphism/#51","text":"","title":"5.1.\u5f00\u53d1\u63a5\u53e3"},{"location":"python/DataStructure/05_InterfacePolymorphism/#511","text":"","title":"5.1.1.\u8bbe\u8ba1\u5305\u63a5\u53e3"},{"location":"python/DataStructure/05_InterfacePolymorphism/#512","text":"","title":"5.1.2.\u6307\u5b9a\u53c2\u6570\u548c\u8fd4\u56de\u503c"},{"location":"python/DataStructure/05_InterfacePolymorphism/#52","text":"","title":"5.2.\u6784\u9020\u51fd\u6570\u548c\u7c7b\u7684\u5b9e\u73b0"},{"location":"python/DataStructure/05_InterfacePolymorphism/#521","text":"","title":"5.2.1.\u524d\u7f6e\u6761\u4ef6\u3001\u540e\u7f6e\u6761\u4ef6\u3001\u5f02\u5e38\u548c\u6587\u6863"},{"location":"python/DataStructure/05_InterfacePolymorphism/#522python","text":"\u7ec3\u4e60\u9898 1\uff0e\u5305\u91cc\u7684\u5143\u7d20\u662f\u6709\u5e8f\u7684\uff0c\u8fd8\u662f\u65e0\u5e8f\u7684\uff1f 2\uff0e\u54ea\u4e9b\u64cd\u4f5c\u4f1a\u51fa\u73b0\u5728\u6240\u6709\u591a\u9879\u96c6\u7684\u63a5\u53e3\u91cc\uff1f 3\uff0e\u54ea\u4e2a\u65b9\u6cd5\u8d1f\u8d23\u521b\u5efa\u591a\u9879\u96c6\u5bf9\u8c61\uff1f 4\uff0e\u8bf7\u8bf4\u51fa\u63a5\u53e3\u4e0e\u5b9e\u73b0\u5206\u79bb\u76843\u4e2a\u539f\u56e0\u3002","title":"5.2.2.\u5728Python\u91cc\u7f16\u5199\u63a5\u53e3"},{"location":"python/DataStructure/05_InterfacePolymorphism/#53","text":"","title":"5.3.\u5f00\u53d1\u57fa\u4e8e\u6570\u7ec4\u7684\u5b9e\u73b0"},{"location":"python/DataStructure/05_InterfacePolymorphism/#531","text":"","title":"5.3.1.\u9009\u62e9\u5e76\u521d\u59cb\u5316\u6570\u636e\u7ed3\u6784"},{"location":"python/DataStructure/05_InterfacePolymorphism/#532","text":"","title":"5.3.2.\u5148\u5b8c\u6210\u7b80\u5355\u7684\u65b9\u6cd5"},{"location":"python/DataStructure/05_InterfacePolymorphism/#533","text":"","title":"5.3.3.\u5b8c\u6210\u8fed\u4ee3\u5668"},{"location":"python/DataStructure/05_InterfacePolymorphism/#534","text":"","title":"5.3.4.\u5b8c\u6210\u4f7f\u7528\u8fed\u4ee3\u5668\u7684\u65b9\u6cd5"},{"location":"python/DataStructure/05_InterfacePolymorphism/#535in__contains__","text":"","title":"5.3.5.in\u8fd0\u7b97\u7b26\u548c__contains__\u65b9\u6cd5"},{"location":"python/DataStructure/05_InterfacePolymorphism/#536remove","text":"","title":"5.3.6.\u5b8c\u6210remove\u65b9\u6cd5"},{"location":"python/DataStructure/05_InterfacePolymorphism/#537","text":"1\uff0e\u89e3\u91ca\u591a\u9879\u96c6\u7c7b\u7684__init__\u65b9\u6cd5\u7684\u4f5c\u7528\u3002 2\uff0e\u4e3a\u4ec0\u4e48\u8c03\u7528\u65b9\u6cd5\u6bd4\u76f4\u63a5\u5728\u7c7b\u91cc\u5f15\u7528\u5b9e\u4f8b\u53d8\u91cf\u66f4\u597d\uff1f 3\uff0e\u5bf9\u4e8eArrayBag\u7684__init__\u65b9\u6cd5\uff0c\u5c55\u793a\u5982\u4f55\u901a\u8fc7\u8c03\u7528clear\u65b9\u6cd5\u6765\u7b80\u5316\u4ee3\u7801\u3002 4\uff0e\u89e3\u91ca\u4e3a\u4ec0\u4e48__iter__\u65b9\u6cd5\u53ef\u80fd\u4f1a\u662f\u591a\u9879\u96c6\u7c7b\u91cc\u6700\u6709\u7528\u7684\u65b9\u6cd5\u3002 5\uff0e\u89e3\u91ca\u4e3a\u4ec0\u4e48\u5728ArrayBag\u7c7b\u4e2d\u4e0d\u7528\u5305\u542b__contains__\u65b9\u6cd5\u3002","title":"5.3.7.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/05_InterfacePolymorphism/#54","text":"","title":"5.4.\u5f00\u53d1\u57fa\u4e8e\u94fe\u63a5\u7684\u5b9e\u73b0"},{"location":"python/DataStructure/05_InterfacePolymorphism/#541","text":"","title":"5.4.1.\u521d\u59cb\u5316\u6570\u636e\u7ed3\u6784"},{"location":"python/DataStructure/05_InterfacePolymorphism/#542","text":"","title":"5.4.2.\u5b8c\u6210\u8fed\u4ee3\u5668"},{"location":"python/DataStructure/05_InterfacePolymorphism/#543clearadd","text":"","title":"5.4.3.\u5b8c\u6210clear\u548cadd\u65b9\u6cd5"},{"location":"python/DataStructure/05_InterfacePolymorphism/#544remove","text":"","title":"5.4.4.\u5b8c\u6210remove\u65b9\u6cd5"},{"location":"python/DataStructure/05_InterfacePolymorphism/#545","text":"1\uff0e\u5047\u8bbea\u662f\u4e00\u4e2a\u6570\u7ec4\u5305\uff0cb\u662f\u4e00\u4e2a\u94fe\u63a5\u5305\uff0c\u5b83\u4eec\u90fd\u4e0d\u5305\u542b\u4efb\u4f55\u5143\u7d20\u3002\u8bf7\u63cf\u8ff0\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\u5b83\u4eec\u5728\u5185\u5b58\u4f7f\u7528\u4e0a\u7684\u5dee\u5f02\u3002 2\uff0e\u4e3a\u4ec0\u4e48\u94fe\u63a5\u5305\u4ecd\u7136\u9700\u8981\u4e00\u4e2a\u5355\u72ec\u7684\u5b9e\u4f8b\u53d8\u91cf\u6765\u8bb0\u5f55\u5b83\u7684\u903b\u8f91\u5c3a\u5bf8\uff1f 3\uff0e\u4e3a\u4ec0\u4e48\u4ece\u94fe\u63a5\u5305\u91cc\u5220\u9664\u5143\u7d20\u4e4b\u540e\uff0c\u7a0b\u5e8f\u5458\u4e0d\u7528\u62c5\u5fc3\u51fa\u73b0\u5185\u5b58\u6d6a\u8d39\u7684\u60c5\u51b5\uff1f","title":"5.4.5.\u7ec3\u4e60\u9898"},{"location":"python/DataStructure/05_InterfacePolymorphism/#55","text":"","title":"5.5.\u4e24\u79cd\u5305\u5b9e\u73b0\u7684\u8fd0\u884c\u65f6\u6027\u80fd"},{"location":"python/DataStructure/05_InterfacePolymorphism/#56","text":"","title":"5.6.\u6d4b\u8bd5\u5305\u7684\u4e24\u79cd\u5b9e\u73b0"},{"location":"python/DataStructure/05_InterfacePolymorphism/#57uml","text":"","title":"5.7.\u4f7f\u7528UML\u7ed8\u5236\u5305\u8d44\u6e90"},{"location":"python/DataStructure/05_InterfacePolymorphism/#58","text":"\u63a5\u53e3\u662f\u7528\u6237\u7684\u8f6f\u4ef6\u8d44\u6e90\u53ef\u4ee5\u4f7f\u7528\u7684\u4e00\u7ec4\u64cd\u4f5c\u3002 \u63a5\u53e3\u91cc\u7684\u5143\u7d20\u662f\u51fd\u6570\u548c\u65b9\u6cd5\u7684\u5b9a\u4e49\u4ee5\u53ca\u5b83\u4eec\u7684\u6587\u6863\u3002 \u524d\u7f6e\u6761\u4ef6\u662f\u6307\u5728\u51fd\u6570\u6216\u65b9\u6cd5\u53ef\u4ee5\u6b63\u786e\u5b8c\u6210\u4efb\u52a1\u4e4b\u524d\u5fc5\u987b\u8981\u6ee1\u8db3\u7684\u6761\u4ef6\u3002 \u540e\u7f6e\u6761\u4ef6\u662f\u6307\u5728\u51fd\u6570\u6216\u65b9\u6cd5\u6b63\u786e\u5b8c\u6210\u4efb\u52a1\u4e4b\u540e\u5fc5\u987b\u4e3a\u771f\u7684\u6761\u4ef6\u3002 \u8bbe\u8ba1\u826f\u597d\u7684\u8f6f\u4ef6\u7cfb\u7edf\u4f1a\u628a\u63a5\u53e3\u548c\u5b83\u7684\u5b9e\u73b0\u5206\u5f00\u3002 \u5b9e\u73b0\u662f\u6307\u6ee1\u8db3\u63a5\u53e3\u7684\u51fd\u6570\u3001\u65b9\u6cd5\u6216\u7c7b\u3002 \u591a\u9879\u96c6\u7c7b\u578b\u53ef\u4ee5\u901a\u8fc7\u63a5\u53e3\u8fdb\u884c\u6307\u5b9a\u3002 \u591a\u9879\u96c6\u7c7b\u578b\u53ef\u4ee5\u6709\u51e0\u4e2a\u4e0d\u540c\u7684\u5b9e\u73b0\u7c7b\u3002 \u591a\u6001\u662f\u6307\u5728\u4e24\u4e2a\u6216\u591a\u4e2a\u5b9e\u73b0\u91cc\u4f7f\u7528\u76f8\u540c\u7684\u8fd0\u7b97\u7b26\u3001\u51fd\u6570\u540d\u79f0\u6216\u65b9\u6cd5\u540d\u79f0\u3002\u591a\u6001\u51fd\u6570\u7684\u793a\u4f8b\u662f str \u548c len \uff1b\u591a\u6001\u8fd0\u7b97\u7b26\u7684\u793a\u4f8b\u662f + \u548c == \uff1b\u591a\u6001\u65b9\u6cd5\u7684\u793a\u4f8b\u5305\u62ecadd\u548c isEmpty \u3002 \u5305\u591a\u9879\u96c6\u7c7b\u578b\u662f\u65e0\u5e8f\u7684\uff0c\u5e76\u4e14\u652f\u6301\u6dfb\u52a0\u3001\u5220\u9664\u548c\u8bbf\u95ee\u5176\u5143\u7d20\u7b49\u64cd\u4f5c\u3002 \u7c7b\u56fe\u662f\u4e00\u79cd\u63cf\u8ff0\u7c7b\u4e0e\u7c7b\u4e4b\u95f4\u5173\u7cfb\u7684\u53ef\u89c6\u5316\u8868\u793a\u65b9\u6cd5\u3002 \u7ec4\u5408\u8868\u793a\u4e24\u4e2a\u7c7b\u4e4b\u95f4\u6574\u4f53\u4e0e\u5c40\u90e8\u7684\u5173\u7cfb\u3002 \u805a\u5408\u8868\u793a\u4e24\u4e2a\u7c7b\u4e4b\u95f4\u4e00\u5bf9\u591a\u7684\u5173\u7cfb\u3002 UML\u662f\u4e00\u79cd\u63cf\u8ff0\u8f6f\u4ef6\u8d44\u6e90\u4e4b\u95f4\u5173\u7cfb\u7684\u53ef\u89c6\u5316\u8868\u793a\u65b9\u6cd5\u3002","title":"5.8.\u5c0f\u7ed3"},{"location":"python/DataStructure/05_InterfacePolymorphism/#59","text":"1\uff0e\u5305\u662f\uff1a \u7ebf\u6027\u591a\u9879\u96c6 \u65e0\u5e8f\u591a\u9879\u96c6 2\uff0e\u7528\u6765\u8bbe\u7f6e\u5bf9\u8c61\u5b9e\u4f8b\u53d8\u91cf\u7684\u521d\u59cb\u72b6\u6001\u7684\u65b9\u6cd5\u662f\uff1a __init__ \u65b9\u6cd5 __str__ \u65b9\u6cd5 3\uff0e\u8ba9\u7a0b\u5e8f\u5458\u53ef\u4ee5\u8bbf\u95ee\u591a\u9879\u96c6\u91cc\u6240\u6709\u5143\u7d20\u7684\u65b9\u6cd5\u662f\uff1a __init__ \u65b9\u6cd5 __iter__ \u65b9\u6cd5 4\uff0e\u6539\u53d8\u5bf9\u8c61\u5185\u90e8\u72b6\u6001\u7684\u65b9\u6cd5\u662f\uff1a \u8bbf\u95ee\u5668\u65b9\u6cd5 \u53d8\u5f02\u5668\u65b9\u6cd5 5\uff0e\u4e00\u7ec4\u53ef\u4ee5\u88ab\u7c7b\u7684\u5ba2\u6237\u7aef\u4f7f\u7528\u7684\u65b9\u6cd5\u96c6\u79f0\u4e3a\uff1a \u5b9e\u73b0 \u63a5\u53e3 6\uff0e\u591a\u6001\u7528\u6765\u4ee3\u8868\u7684\u672f\u8bed\u662f\uff1a \u591a\u4e2a\u7c7b\u91cc\u76f8\u540c\u7684\u65b9\u6cd5\u540d\u79f0 \u7528\u6765\u5b58\u50a8\u53e6\u4e00\u4e2a\u7c7b\u91cc\u6240\u5305\u542b\u6570\u636e\u7684\u7c7b 7\uff0e\u7ec4\u5408\u662f\u6307\uff1a \u4e24\u4e2a\u7c7b\u4e4b\u95f4\u90e8\u5206\u4e0e\u6574\u4f53\u5173\u7cfb \u4e24\u4e2a\u7c7b\u4e4b\u95f4\u591a\u5bf9\u4e00\u5173\u7cfb 8\uff0e\u5305\u4e2dadd\u65b9\u6cd5\u7684\u5e73\u5747\u8fd0\u884c\u65f6\u4e3a\uff1a O(n) O(k) 9\uff0e\u5305\u4e2dremove\u65b9\u6cd5\u7684\u5e73\u5747\u8fd0\u884c\u65f6\u4e3a\uff1a O(n) O(k) 10\uff0e\u5728\u4ec0\u4e48\u60c5\u51b5\u4e0b\uff0c\u6570\u7ec4\u5305\u5b9e\u73b0\u4f1a\u6bd4\u94fe\u63a5\u5305\u5b9e\u73b0\u4f7f\u7528\u66f4\u5c11\u7684\u5185\u5b58\uff1a \u542b\u6709\u5c11\u4e8e\u4e00\u534a\u7684\u6570\u636e \u542b\u6709\u4e00\u534a\u4ee5\u4e0a\u7684\u6570\u636e","title":"5.9.\u590d\u4e60\u9898"},{"location":"python/DataStructure/05_InterfacePolymorphism/#510","text":"1\uff0e\u5bf9\u4e8e\u4e24\u4e2a\u5305\u5b9e\u73b0\uff0c\u786e\u5b9a == \u64cd\u4f5c\u7684\u8fd0\u884c\u65f6\u3002\u53ef\u4ee5\u9884\u89c1\u5230\uff0c\u8fd9\u91cc\u6709\u51e0\u79cd\u60c5\u51b5\u9700\u8981\u5206\u6790\u3002 2\uff0e\u5bf9\u4e8e\u5305\u7684\u4e24\u4e2a\u5b9e\u73b0\uff0c\u786e\u5b9a + \u8fd0\u7b97\u7b26\u7684\u8fd0\u884c\u65f6\u3002 3\uff0e\u7f16\u7801 ArrayBag \u91cc add \u65b9\u6cd5\u7684\u4ee3\u7801\uff0c\u4ece\u800c\u53ef\u4ee5\u5728\u9700\u8981\u7684\u65f6\u5019\u5bf9\u6570\u7ec4\u5c3a\u5bf8\u8fdb\u884c\u8c03\u6574\u3002 4\uff0e\u7f16\u7801 ArrayBag \u91cc remove \u65b9\u6cd5\u7684\u4ee3\u7801\uff0c\u4ece\u800c\u53ef\u4ee5\u5728\u9700\u8981\u7684\u65f6\u5019\u5bf9\u6570\u7ec4\u5c3a\u5bf8\u8fdb\u884c\u8c03\u6574\u3002 5\uff0e\u5728 ArrayBag \u548c LinkedBag \u7c7b\u91cc\u6dfb\u52a0 clone \u65b9\u6cd5\u3002\u8fd9\u4e2a\u65b9\u6cd5\u5728\u8c03\u7528\u7684\u65f6\u5019\uff0c\u4e0d\u4f1a\u63a5\u6536\u4efb\u4f55\u53c2\u6570\uff0c\u5e76\u4e14\u4f1a\u8fd4\u56de\u5f53\u524d\u5305\u7c7b\u578b\u7684\u4e00\u4e2a\u5b8c\u6574\u526f\u672c\u3002\u5728\u4e0b\u9762\u8fd9\u6bb5\u4ee3\u7801\u7684\u6700\u540e\uff0c\u53d8\u91cf bag2 \u5c06\u5305\u542b\u6570\u5b57 2 \u3001 3 \u548c 4 \u3002 bag1 = ArrayBag ([ 2 , 3 , 4 ]) bag2 = bag1 . clone () bag1 == bag2 # Returns True bag1 is bag2 # Returns False 6\uff0e\u96c6\u5408\u662f\u4e00\u4e2a\u65e0\u5e8f\u591a\u9879\u96c6\uff0c\u5e76\u4e14\u548c\u5305\u5177\u6709\u76f8\u540c\u7684\u63a5\u53e3\u3002\u4f46\u662f\u5728\u96c6\u5408\u91cc\uff0c\u5143\u7d20\u662f\u552f\u4e00\u7684\uff0c\u800c\u5305\u91cc\u53ef\u4ee5\u5305\u542b\u91cd\u590d\u7684\u7269\u54c1\u3002\u5b9a\u4e49\u4e00\u4e2a\u57fa\u4e8e\u6570\u7ec4\u7684\u53eb\u4f5c ArraySet \u7684\u591a\u9879\u96c6\u65b0\u7c7b\u3002\u5982\u679c\u96c6\u5408\u91cc\u7684\u5143\u7d20\u5df2\u7ecf\u5b58\u5728\u4e86\uff0c\u90a3\u4e48 add \u65b9\u6cd5\u5c06\u4f1a\u5ffd\u7565\u8fd9\u4e2a\u5143\u7d20\u3002 7\uff0e\u4f7f\u7528\u94fe\u63a5\u8282\u70b9\u5b9a\u4e49\u4e00\u4e2a\u53eb\u4f5c LinkedSet \u7684\u591a\u9879\u96c6\u65b0\u7c7b\u6765\u5b9e\u73b0\u96c6\u5408\u7c7b\u578b\u3002\u5982\u679c\u96c6\u5408\u91cc\u7684\u5143\u7d20\u5df2\u7ecf\u5b58\u5728\u4e86\uff0c\u90a3\u4e48 add \u65b9\u6cd5\u5c06\u4f1a\u5ffd\u7565\u8fd9\u4e2a\u5143\u7d20\u3002 8\uff0e\u6709\u5e8f\u5305\u7684\u884c\u4e3a\u548c\u666e\u901a\u5305\u7684\u662f\u4e00\u6837\u7684\uff0c\u4f46\u662f\u5b83\u80fd\u591f\u8ba9\u7528\u6237\u5728\u4f7f\u7528 for \u5faa\u73af\u65f6\u6309\u7167\u5347\u5e8f\u8bbf\u95ee\u91cc\u9762\u7684\u5143\u7d20\u3002\u56e0\u6b64\uff0c\u6dfb\u52a0\u5230\u8fd9\u4e2a\u5305\u7c7b\u578b\u91cc\u7684\u5143\u7d20\uff0c\u90fd\u5fc5\u987b\u5177\u6709\u4e00\u5b9a\u7684\u987a\u5e8f\u5e76\u4e14\u652f\u6301\u6bd4\u8f83\u8fd0\u7b97\u7b26\u3002\u8fd9\u79cd\u7c7b\u578b\u5143\u7d20\u7684\u7b80\u5355\u4f8b\u5b50\u662f\uff1a\u5b57\u7b26\u4e32\u548c\u6574\u6570\u3002\u5b9a\u4e49\u4e00\u4e2a\u652f\u6301\u8fd9\u4e2a\u529f\u80fd\u7684\u53eb\u4f5c ArraySortedBag \u7684\u65b0\u7c7b\u3002\u548c ArrayBag \u4e00\u6837\uff0c\u8fd9\u4e2a\u65b0\u7c7b\u4f1a\u57fa\u4e8e\u6570\u7ec4\uff0c\u4f46\u662f\u5b83\u7684 in \u64cd\u4f5c\u73b0\u5728\u53ef\u4ee5\u5728\u5bf9\u6570\u65f6\u95f4\u91cc\u8fd0\u884c\u3002\u8981\u5b8c\u6210\u8fd9\u4e00\u70b9\uff0c ArraySortedBag \u5fc5\u987b\u5c06\u65b0\u6dfb\u52a0\u7684\u5143\u7d20\u6309\u7167\u987a\u5e8f\u653e\u5230\u6570\u7ec4\u91cc\u3002\u6700\u7b80\u5355\u7684\u529e\u6cd5\u662f\u4fee\u6539 add \u65b9\u6cd5\uff0c\u4ece\u800c\u8ba9\u65b0\u5143\u7d20\u63d2\u5165\u9002\u5f53\u7684\u4f4d\u7f6e\uff1b\u7136\u540e\uff0c\u6dfb\u52a0_ _contains__ \u65b9\u6cd5\u6765\u63d0\u4f9b\u65b0\u7684\u4e14\u66f4\u6709\u6548\u7684\u641c\u7d22\uff1b\u6700\u540e\uff0c\u8981\u628a\u5bf9 ArrayBag \u7684\u6240\u6709\u5f15\u7528\u90fd\u66ff\u6362\u4e3a ArraySortedBag \u3002\uff08\u63d0\u793a\uff1a\u628a\u4ee3\u7801\u4ece ArrayBag \u7c7b\u4e2d\u590d\u5236\u5230\u4e00\u4e2a\u65b0\u6587\u4ef6\u91cc\uff0c\u7136\u540e\u5728\u8fd9\u4e2a\u65b0\u6587\u4ef6\u91cc\u5f00\u59cb\u4fee\u6539\u3002\uff09 9\uff0e\u786e\u5b9a ArraySortedBag \u91cc add \u65b9\u6cd5\u7684\u8fd0\u884c\u65f6\u3002 10\uff0ePython\u7684 for \u5faa\u73af\u53ef\u4ee5\u8ba9\u7a0b\u5e8f\u5458\u5728\u5faa\u73af\u8fed\u4ee3\u591a\u9879\u96c6\u7684\u65f6\u5019\u5bf9\u5b83\u6267\u884c\u6dfb\u52a0\u6216\u5220\u9664\u5143\u7d20\u7684\u64cd\u4f5c\u3002\u4e00\u4e9b\u8bbe\u8ba1\u4eba\u5458\u62c5\u5fc3\u5728\u8fed\u4ee3\u8fc7\u7a0b\u4e2d\u5bf9\u591a\u9879\u96c6\u7684\u7ed3\u6784\u8fdb\u884c\u4fee\u6539\u53ef\u80fd\u4f1a\u5bfc\u81f4\u7a0b\u5e8f\u5d29\u6e83\u3002\u6709\u4e00\u79cd\u4fee\u6539\u7b56\u7565\u662f\u901a\u8fc7\u7981\u6b62\u5728\u8fed\u4ee3\u671f\u95f4\u5bf9\u591a\u9879\u96c6\u8fdb\u884c\u53d8\u5f02\u6765\u8ba9 for \u5faa\u73af\u6210\u4e3a\u53ea\u8bfb\u3002\u4f60\u53ef\u4ee5\u901a\u8fc7\u5bf9\u53d8\u5f02\u64cd\u4f5c\u8fdb\u884c\u8ba1\u6570\uff0c\u5e76\u4e14\u5224\u65ad\u8fd9\u4e2a\u8ba1\u6570\u6709\u6ca1\u6709\u5728\u591a\u9879\u96c6\u7684 __iter__ \u65b9\u6cd5\u7684\u4efb\u610f\u8282\u62cd\u4e2d\u88ab\u589e\u52a0\u6765\u68c0\u6d4b\u8fd9\u79cd\u7c7b\u578b\u7684\u53d8\u5f02\u3002\u5f53\u53d1\u751f\u8fd9\u79cd\u60c5\u51b5\u65f6\uff0c\u5c31\u53ef\u4ee5\u5f15\u53d1\u5f02\u5e38\u4ece\u800c\u907f\u514d\u8ba1\u7b97\u7684\u7ee7\u7eed\u8fdb\u884c\u3002\u628a\u8fd9\u4e2a\u673a\u5236\u6dfb\u52a0\u5230 ArrayBag \u7c7b\u91cc\u3002\u53ef\u4ee5\u6dfb\u52a0\u4e00\u4e2a\u53eb\u4f5c modCount \u7684\u65b0\u5b9e\u4f8b\u53d8\u91cf\uff0c\u8fd9\u4e2a\u5b9e\u4f8b\u53d8\u91cf\u4f1a\u5728 __init__ \u65b9\u6cd5\u91cc\u8bbe\u7f6e\u4e3a 0 \uff1b\u7136\u540e\uff0c\u6bcf\u4e2a\u53d8\u5f02\u5668\u65b9\u6cd5\u90fd\u4f1a\u9012\u589e\u8fd9\u4e2a\u53d8\u91cf\uff1b\u6700\u540e\uff0c __iter__ \u65b9\u6cd5\u6709\u4e00\u4e2a\u53eb\u4f5c modCount \u7684\u4e34\u65f6\u53d8\u91cf\uff0c\u8fd9\u4e2a\u4e34\u65f6\u53d8\u91cf\u7684\u521d\u59cb\u503c\u662f\u5b9e\u4f8b\u53d8\u91cf self.modCount \u7684\u503c\u3002\u5728 __iter__ \u65b9\u6cd5\u91cc\u8fd4\u56de\u4e00\u4e2a\u5143\u7d20\u540e\uff0c\u5982\u679c\u8fd9\u4e24\u4e2a\u4fee\u6539\u8fc7\u7684\u8ba1\u6570\u5668\u503c\u4e0d\u76f8\u7b49\uff0c\u5c31\u7acb\u5373\u5f15\u53d1\u5f02\u5e38\u3002\u7528\u4e00\u4e2a\u7a0b\u5e8f\u6765\u6d4b\u8bd5\u4f60\u7684\u4fee\u6539\uff0c\u4ece\u800c\u4fdd\u8bc1\u6ee1\u8db3\u76f8\u5e94\u7684\u9700\u6c42\u3002","title":"5.10.\u7f16\u7a0b\u7ec3\u4e60"},{"location":"python/DataStructure/06_InheritanceAbstractClass/","text":"\u7ee7\u627f\u4e0e\u62bd\u8c61\u7c7b \u00b6","title":"\u7ee7\u627f\u4e0e\u62bd\u8c61\u7c7b"},{"location":"python/DataStructure/06_InheritanceAbstractClass/#_1","text":"","title":"\u7ee7\u627f\u4e0e\u62bd\u8c61\u7c7b"},{"location":"python/Demo/CourseSystem/","text":"\u9009\u8bfe\u7cfb\u7edf \u00b6 \u4efb\u52a1\u9700\u6c42 \u00b6 \u89d2\u8272\uff1a\u5b66\u6821\u3001\u5b66\u5458\u3001\u8bfe\u7a0b\u3001\u8bb2\u5e08 \u8981\u6c42\uff1a \u521b\u5efa\u5317\u4eac\u3001\u4e0a\u6d772\u6240\u5b66\u6821\u3002 \u521b\u5efaLinux\u3001Python\u3001go\u4e09\u4e2a\u8bfe\u7a0b\uff0cLinux\u548cPython\u5728\u5317\u4eac\u5f00\uff0cgo\u5728\u4e0a\u6d77\u5f00\u3002 \u8bfe\u7a0b\u5305\u542b\u5468\u671f\u3001\u4ef7\u683c\uff0c\u901a\u8fc7\u5b66\u6821\u521b\u5efa\u8bfe\u7a0b\u3002 \u901a\u8fc7\u5b66\u6821\u521b\u5efa\u73ed\u7ea7\uff0c\u73ed\u7ea7\u5173\u8054\u8bfe\u7a0b\u3001\u8bb2\u5e08\u3002 \u521b\u5efa\u8bb2\u5e08\u3002 \u521b\u5efa\u5b66\u5458\u65f6\uff0c\u9009\u62e9\u5b66\u6821\uff0c\u5173\u8054\u73ed\u7ea7\u3002 \u521b\u5efa\u8bb2\u5e08\u89d2\u8272\uff08\u4e0d\u9700\u8981\u5173\u8054\u5b66\u6821\uff09\u3002 \u63d0\u4f9b\u4e24\u4e2a\u89d2\u8272\u63a5\u53e3\u3002 \u5b66\u5458\u89c6\u56fe\uff1a\u53ef\u4ee5\u6ce8\u518c\uff0c\u4ea4\u5b66\u8d39\uff0c\u9009\u62e9\u73ed\u7ea7\u3002 \u8bb2\u5e08\u89c6\u56fe\uff1a\u8bb2\u5e08\u53ef\u4ee5\u7ba1\u7406\u81ea\u5df1\u7684\u73ed\u7ea7\uff0c\u4e0a\u8bfe\u65f6\u9009\u62e9\u73ed\u7ea7\uff0c\u67e5\u770b\u73ed\u7ea7\u5b66\u5458\u5217\u8868\uff0c\u4fee\u6539\u6240\u7ba1\u7406\u7684\u5b66\u5458\u7684\u6210\u7ee9\u3002 \u7ba1\u7406\u89c6\u56fe\uff1a\u521b\u5efa\u8bb2\u5e08\uff0c\u521b\u5efa\u73ed\u7ea7\uff0c\u521b\u5efa\u8bfe\u7a0b\u3002 \u4e0a\u8ff0\u64cd\u4f5c\u6240\u4ea7\u751f\u7684\u6570\u636e\u901a\u8fc7pickle\u4fdd\u5b58\u5230\u6587\u4ef6\u3002 \u9700\u6c42\u5206\u6790 \u00b6 \u7ba1\u7406\u89c6\u56fe \u6ce8\u518c \u767b\u5f55 \u521b\u5efa\u5b66\u6821 \u521b\u5efa\u8bfe\u7a0b\uff08\u5148\u9009\u62e9\u5b66\u6821\uff09 \u521b\u5efa\u8bb2\u5e08 \u5b66\u5458\u89c6\u56fe \u6ce8\u518c \u767b\u5f55\u529f\u80fd \u9009\u62e9\u6821\u533a \u9009\u62e9\u8bfe\u7a0b\uff08\u5148\u9009\u62e9\u6821\u533a\uff0c\u5728\u9009\u62e9\u6821\u533a\u4e2d\u7684\u67d0\u4e00\u95e8\u8bfe\u7a0b\uff0c\u9009\u62e9\u8bfe\u7a0b\u5373\u9009\u62e9\u73ed\u7ea7\uff09 \u5b66\u751f\u9009\u62e9\u8bfe\u7a0b\uff0c\u8bfe\u7a0b\u4e5f\u9009\u62e9\u5b66\u751f \u67e5\u770b\u5206\u6570 \u4ea4\u5b66\u8d39 \u8bb2\u5e08\u89c6\u56fe \u767b\u5f55 \u67e5\u770b\u6559\u6388\u8bfe\u7a0b \u9009\u62e9\u6559\u6388\u8bfe\u7a0b \u67e5\u770b\u8bfe\u7a0b\u4e0b\u7684\u5b66\u751f \u4fee\u6539\u5b66\u751f\u5206\u6570 \u67b6\u6784\u8bbe\u8ba1\uff08\u4e09\u5c42\u67b6\u6784\uff09 \u00b6 \u7528\u6237\u89c6\u56fe\u5c42 \u7528\u4e8e\u4e0e\u7528\u6237\u8fdb\u884c\u4ea4\u4e92\u3002 \u5b9e\u73b0\u7b80\u5355\u7684\u903b\u8f91\u5224\u65ad\uff0c\u6bd4\u5982\u6ce8\u518c\u529f\u80fd\u4e2d\u4e24\u6b21\u5bc6\u7801\u662f\u5426\u4e00\u81f4\u7684\u6821\u9a8c\u3002 core src.py \u4e3b\u89c6\u56fe admin.py: \u7ba1\u7406\u89c6\u56fe student.py: \u5b66\u5458\u89c6\u56fe teacher.py: \u8bb2\u5e08\u89c6\u56fe \u903b\u8f91\u63a5\u53e3\u5c42 \u6838\u5fc3\u4e1a\u52a1\u903b\u8f91\u7684\u5904\u7406 interface admin_interface.py studeng_interface.py teacher_interface.py \u6570\u636e\u5904\u7406\u5c42 \u6570\u636e\u5904\u7406\uff0c\u6bd4\u5982\u589e\u5220\u6539\u67e5\u3002 db models.py db_handler.py pickle\u4fdd\u5b58\u5bf9\u8c61 object \u2192 pickle \u6587\u4ef6\u7ed3\u6784 \u00b6 /--conf/ | |--settings.py | |--core/ | |--src.py | |--admin.py | |--student.py | |--teacher.py | |--db/ | |--models.py | |--db_handler.py | |--pickle | |--interface/ | |--admin_interface.py | |--student_interface.py | |--teacher_interface.py | |--common_interface.py | |--lib/ | |--common.py | |--start.py \u9009\u8bfe\u7cfb\u7edf\u603b\u7ed3 \u00b6 1.\u7ba1\u7406\u5458 \u00b6 1.1.\u6ce8\u518c \u00b6 \u7528\u6237\u518d\u89c6\u56fe\u5c42\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u4ea4\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u7684models.get()\u8fdb\u884c\u6821\u9a8c\u3002 \u82e5\u4e0d\u5b58\u5728\u5219\u521b\u5efa\uff0c\u5e76\u8bb2\u6ce8\u518c\u6210\u529f\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 1.2.\u767b\u5f55 \u00b6 \u7528\u6237\u5728\u89c6\u56fe\u5c42\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u4ea4\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u7684models.get()\u8fdb\u884c\u6821\u9a8c\u3002 \u82e5\u4e0d\u5b58\u5728\u5219\u521b\u5efa\uff0c\u5e76\u8bb2\u6ce8\u518c\u6210\u529f\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 1.3.\u521b\u5efa\u5b66\u6821 \u00b6 \u8ba9\u7528\u6237\u8f93\u5165\u5b66\u6821\u540d\u548c\u5b66\u6821\u5730\u5740\u3002 \u8c03\u7528\u7ba1\u7406\u5458\u63a5\u53e3\u521b\u5efa\u5b66\u6821\u3002 \u5224\u65ad\u5b66\u6821\u662f\u5426\u5b58\u5728\uff0c\u82e5\u5b58\u5728\uff0c\u4e0d\u521b\u5efa\u3002 \u82e5\u4e0d\u5b58\u5728\uff0c\u5219\u8c03\u7528\u63a5\u53e3\u5c42\u521b\u5efa\u5b66\u6821\uff0c\u83b7\u53d6\u7ba1\u7406\u5458\u5bf9\u8c61\u7684\u521b\u5efa\u5b66\u6821\u65b9\u6cd5\u4fdd\u6301\u5b66\u6821\u5bf9\u8c61\u3002 \u5c06\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 1.4.\u521b\u5efa\u8bfe\u7a0b \u00b6 \u83b7\u53d6\u6240\u6709\u5b66\u6821\uff0c\u5e76\u6253\u5370\uff0c\u8ba9\u7528\u6237\u9009\u62e9\u3002 \u83b7\u53d6\u7528\u6237\u9009\u62e9\u7684\u5b66\u6821\u4e0e\u521b\u5efa\u7684\u8bfe\u7a0b\uff0c\u4ea4\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u7ba1\u7406\u5458\u5bf9\u8c61\u4e2d\u7684\u521b\u5efa\u8bfe\u7a0b\u65b9\u6cd5\uff0c\u4fdd\u5b58\u8bfe\u7a0b\u5bf9\u8c61\u3002 \u8bfe\u7a0b\u9700\u8981\u7ed1\u5b9a\u7ed9\u5b66\u6821\u5bf9\u8c61\uff0c\u6700\u7ec8\u5c06\u521b\u5efa\u6210\u529f\u7684\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 1.5.\u521b\u5efa\u8001\u5e08 \u00b6 \u7528\u6237\u8f93\u5165\u8001\u5e08\u540d\u79f0\u3002 \u8c03\u7528\u63a5\u53e3\u5c42\uff0c\u63a5\u53e3\u5c42\u4e2d\u8bbe\u7f6e\u9ed8\u8ba4\u5bc6\u7801123\uff0c\u8c03\u7528\u6570\u636e\u5c42\u3002 \u5224\u65ad\u8001\u5e08\u662f\u5426\u5b58\u5728\uff0c\u4e0d\u5b58\u5728\u5219\u8c03\u7528\u7ba1\u7406\u5458\u5bf9\u8c61\u4e2d\u7684\u521b\u5efa\u8001\u5e08\u65b9\u6cd5\u3002 \u4fdd\u5b58\u8001\u5e08\u5bf9\u8c61\uff0c\u5e76\u5c06\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 2.\u5b66\u751f \u00b6 2.1.\u6ce8\u518c \u00b6 \u540c\u4e0a 2.2.\u767b\u5f55 \u00b6 \u540c\u4e0a 2.3.\u9009\u62e9\u5b66\u6821 \u00b6 \u83b7\u53d6\u6240\u6709\u5b66\u6821\uff0c\u8ba9\u5b66\u751f\u9009\u62e9\uff0c\u5e76\u5c06\u9009\u62e9\u7684\u5b66\u6821\u4f20\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u5224\u65ad\u5f53\u524d\u5b66\u751f\u662f\u5426\u9009\u62e9\u5b66\u6821\u3002 \u82e5\u6ca1\u6709\u9009\u62e9\uff0c\u5219\u8c03\u7528\u5b66\u751f\u5bf9\u8c61\u4e2d\u7684\u6dfb\u52a0\u5b66\u6821\u65b9\u6cd5\u3002 \u5c06\u6dfb\u52a0\u540e\u6d88\u606f\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 2.4.\u9009\u62e9\u8bfe\u7a0b \u00b6 \u5148\u83b7\u53d6\u5f53\u524d\u5b66\u751f\u6240\u5728\u5b66\u6821\u7684\u6240\u6709\u8bfe\u7a0b\uff0c\u5e76\u9009\u62e9\u3002 \u63a5\u53e3\u5c42\u5c06\u9009\u62e9\u540e\u7684\u8bfe\u7a0b\uff0c\u8c03\u7528\u6570\u636e\u5c42\u7684\u6dfb\u52a0\u8bfe\u7a0b\u65b9\u6cd5\u4fdd\u5b58\u3002 \u5b66\u751f\u5bf9\u8c61\u4e2d\u8bfe\u7a0b\u5217\u8868\u6dfb\u52a0\u8bfe\u7a0b\uff0c\u8bbe\u7f6e\u8bfe\u7a0b\u5206\u6570\uff0c\u9ed8\u8ba4\u4e3a0. \u6700\u7ec8\u5c06\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 2.5.\u67e5\u770b\u6210\u7ee9 \u00b6 \u76f4\u63a5\u8c03\u7528\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u7684\u67e5\u770b\u6210\u7ee9\u65b9\u6cd5\u3002 \u8fd4\u56de\u6210\u7ee9\u7ed9\u89c6\u56fe\u5c42\u5e76\u6253\u5370\u3002 3.\u8001\u5e08 \u00b6 3.1.\u767b\u5f55 \u00b6 \u540c\u4e0a 3.2.\u67e5\u770b\u6559\u6388\u8bfe\u7a0b \u00b6 \u76f4\u63a5\u8c03\u7528\u63a5\u53e3\u5c42\uff0c\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\u4e0b\u8bfe\u7a0b\u5217\u8868\u6570\u636e\u3002 \u82e5\u6709\u5219\u6253\u5370\uff0c\u6ca1\u6709\u5219\u9000\u51fa\u3002 3.3.\u9009\u62e9\u6559\u6388\u8bfe\u7a0b \u00b6 \u8c03\u7528\u63a5\u53e3\u5c42\u4e2d\u7684\u9009\u62e9\u6559\u6388\u8bfe\u7a0b\u63a5\u53e3\uff0c\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u6539\u8bfe\u7a0b\u4e0b\u6240\u6709\u7684\u5b66\u751f\uff0c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 \u6253\u5370\u6240\u6709\u7684\u8bfe\u7a0b\uff0c\u8ba9\u8001\u5e08\u9009\u62e9\uff0c\u82e5\u8001\u5e08\u8bfe\u7a0b\u4e2d\u6709\u8be5\u8bfe\u7a0b\u5219\u4e0d\u6dfb\u52a0\u3002 \u6ca1\u6709\uff0c\u5219\u55f2\u7528\u8001\u5e08\u5bf9\u8c61\u4e2d\u7684\u6dfb\u52a0\u8bfe\u7a0b\u65b9\u6cd5\u8fdb\u884c\u6dfb\u52a0\u3002 3.4.\u67e5\u770b\u8bfe\u7a0b\u4e0b\u7684\u5b66\u751f \u00b6 \u76f4\u63a5\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\u4e0b\u6240\u6709\u7684\u8bfe\u7a0b\uff0c\u9009\u62e9\u8bfe\u7a0b\u3002 \u4ece\u8001\u5e08\u5bf9\u8c61\u4e2d\uff0c\u8c03\u7528\u67e5\u770b\u8bfe\u7a0b\u4e0b\u5b66\u751f\u7684\u65b9\u6cd5\uff0c\u83b7\u53d6\u8bfe\u7a0b\u5bf9\u8c61\u4e0b\u7684\u6240\u6709\u5b66\u751f\uff0c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 \u89c6\u56fe\u5c42\u6253\u5370\u8be5\u8bfe\u7a0b\u4e0b\u6240\u6709\u7684\u5b66\u751f\u3002 3.5.\u4fee\u6539\u5b66\u751f\u5206\u6570 \u00b6 \u76f4\u63a5\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\u4e0b\u6240\u6709\u7684\u8bfe\u7a0b\u3002 \u4ece\u8001\u5e08\u5bf9\u8c61\u4e2d\uff0c\u8c03\u7528\u67e5\u770b\u8bfe\u7a0b\u4e0b\u5b66\u751f\u65b9\u6cd5\uff0c\u83b7\u53d6\u8bfe\u7a0b\u5bf9\u8c61\u4e0b\u6240\u6709\u7684\u5b66\u751f\uff0c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 \u89c6\u56fe\u5c42\u6253\u5370\u6539\u8bfe\u7a0b\u4e0b\u6240\u6709\u7684\u5b66\u751f\uff0c\u5e76\u8ba9\u7528\u6237\u9009\u62e9\u9700\u8981\u5206\u6570\u7684\u5b66\u751f\u3002 \u55f2\u7528\u8001\u5e08\u4fee\u6539\u5206\u6570\u63a5\u53e3\uff0c\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\uff0c\u8c03\u7528\u5bf9\u8c61\u4e2d\u4fee\u6539\u5206\u6570\u65b9\u6cd5\u3002 \u83b7\u53d6\u5b66\u751f\u5bf9\u8c61\u4e2d\u7684\u5206\u6570\u5b57\u5178\uff0c\u8fdb\u884c\u4fee\u6539\u3002 3.4.\u67e5\u770b\u6210\u7ee9 \u00b6 \u793a\u610f\u56fe \u00b6 \u53c2\u8003\u4ee3\u7801 \u00b6 \u4ee3\u7801","title":"\u9009\u8bfe\u7cfb\u7edf"},{"location":"python/Demo/CourseSystem/#_1","text":"","title":"\u9009\u8bfe\u7cfb\u7edf"},{"location":"python/Demo/CourseSystem/#_2","text":"\u89d2\u8272\uff1a\u5b66\u6821\u3001\u5b66\u5458\u3001\u8bfe\u7a0b\u3001\u8bb2\u5e08 \u8981\u6c42\uff1a \u521b\u5efa\u5317\u4eac\u3001\u4e0a\u6d772\u6240\u5b66\u6821\u3002 \u521b\u5efaLinux\u3001Python\u3001go\u4e09\u4e2a\u8bfe\u7a0b\uff0cLinux\u548cPython\u5728\u5317\u4eac\u5f00\uff0cgo\u5728\u4e0a\u6d77\u5f00\u3002 \u8bfe\u7a0b\u5305\u542b\u5468\u671f\u3001\u4ef7\u683c\uff0c\u901a\u8fc7\u5b66\u6821\u521b\u5efa\u8bfe\u7a0b\u3002 \u901a\u8fc7\u5b66\u6821\u521b\u5efa\u73ed\u7ea7\uff0c\u73ed\u7ea7\u5173\u8054\u8bfe\u7a0b\u3001\u8bb2\u5e08\u3002 \u521b\u5efa\u8bb2\u5e08\u3002 \u521b\u5efa\u5b66\u5458\u65f6\uff0c\u9009\u62e9\u5b66\u6821\uff0c\u5173\u8054\u73ed\u7ea7\u3002 \u521b\u5efa\u8bb2\u5e08\u89d2\u8272\uff08\u4e0d\u9700\u8981\u5173\u8054\u5b66\u6821\uff09\u3002 \u63d0\u4f9b\u4e24\u4e2a\u89d2\u8272\u63a5\u53e3\u3002 \u5b66\u5458\u89c6\u56fe\uff1a\u53ef\u4ee5\u6ce8\u518c\uff0c\u4ea4\u5b66\u8d39\uff0c\u9009\u62e9\u73ed\u7ea7\u3002 \u8bb2\u5e08\u89c6\u56fe\uff1a\u8bb2\u5e08\u53ef\u4ee5\u7ba1\u7406\u81ea\u5df1\u7684\u73ed\u7ea7\uff0c\u4e0a\u8bfe\u65f6\u9009\u62e9\u73ed\u7ea7\uff0c\u67e5\u770b\u73ed\u7ea7\u5b66\u5458\u5217\u8868\uff0c\u4fee\u6539\u6240\u7ba1\u7406\u7684\u5b66\u5458\u7684\u6210\u7ee9\u3002 \u7ba1\u7406\u89c6\u56fe\uff1a\u521b\u5efa\u8bb2\u5e08\uff0c\u521b\u5efa\u73ed\u7ea7\uff0c\u521b\u5efa\u8bfe\u7a0b\u3002 \u4e0a\u8ff0\u64cd\u4f5c\u6240\u4ea7\u751f\u7684\u6570\u636e\u901a\u8fc7pickle\u4fdd\u5b58\u5230\u6587\u4ef6\u3002","title":"\u4efb\u52a1\u9700\u6c42"},{"location":"python/Demo/CourseSystem/#_3","text":"\u7ba1\u7406\u89c6\u56fe \u6ce8\u518c \u767b\u5f55 \u521b\u5efa\u5b66\u6821 \u521b\u5efa\u8bfe\u7a0b\uff08\u5148\u9009\u62e9\u5b66\u6821\uff09 \u521b\u5efa\u8bb2\u5e08 \u5b66\u5458\u89c6\u56fe \u6ce8\u518c \u767b\u5f55\u529f\u80fd \u9009\u62e9\u6821\u533a \u9009\u62e9\u8bfe\u7a0b\uff08\u5148\u9009\u62e9\u6821\u533a\uff0c\u5728\u9009\u62e9\u6821\u533a\u4e2d\u7684\u67d0\u4e00\u95e8\u8bfe\u7a0b\uff0c\u9009\u62e9\u8bfe\u7a0b\u5373\u9009\u62e9\u73ed\u7ea7\uff09 \u5b66\u751f\u9009\u62e9\u8bfe\u7a0b\uff0c\u8bfe\u7a0b\u4e5f\u9009\u62e9\u5b66\u751f \u67e5\u770b\u5206\u6570 \u4ea4\u5b66\u8d39 \u8bb2\u5e08\u89c6\u56fe \u767b\u5f55 \u67e5\u770b\u6559\u6388\u8bfe\u7a0b \u9009\u62e9\u6559\u6388\u8bfe\u7a0b \u67e5\u770b\u8bfe\u7a0b\u4e0b\u7684\u5b66\u751f \u4fee\u6539\u5b66\u751f\u5206\u6570","title":"\u9700\u6c42\u5206\u6790"},{"location":"python/Demo/CourseSystem/#_4","text":"\u7528\u6237\u89c6\u56fe\u5c42 \u7528\u4e8e\u4e0e\u7528\u6237\u8fdb\u884c\u4ea4\u4e92\u3002 \u5b9e\u73b0\u7b80\u5355\u7684\u903b\u8f91\u5224\u65ad\uff0c\u6bd4\u5982\u6ce8\u518c\u529f\u80fd\u4e2d\u4e24\u6b21\u5bc6\u7801\u662f\u5426\u4e00\u81f4\u7684\u6821\u9a8c\u3002 core src.py \u4e3b\u89c6\u56fe admin.py: \u7ba1\u7406\u89c6\u56fe student.py: \u5b66\u5458\u89c6\u56fe teacher.py: \u8bb2\u5e08\u89c6\u56fe \u903b\u8f91\u63a5\u53e3\u5c42 \u6838\u5fc3\u4e1a\u52a1\u903b\u8f91\u7684\u5904\u7406 interface admin_interface.py studeng_interface.py teacher_interface.py \u6570\u636e\u5904\u7406\u5c42 \u6570\u636e\u5904\u7406\uff0c\u6bd4\u5982\u589e\u5220\u6539\u67e5\u3002 db models.py db_handler.py pickle\u4fdd\u5b58\u5bf9\u8c61 object \u2192 pickle","title":"\u67b6\u6784\u8bbe\u8ba1\uff08\u4e09\u5c42\u67b6\u6784\uff09"},{"location":"python/Demo/CourseSystem/#_5","text":"/--conf/ | |--settings.py | |--core/ | |--src.py | |--admin.py | |--student.py | |--teacher.py | |--db/ | |--models.py | |--db_handler.py | |--pickle | |--interface/ | |--admin_interface.py | |--student_interface.py | |--teacher_interface.py | |--common_interface.py | |--lib/ | |--common.py | |--start.py","title":"\u6587\u4ef6\u7ed3\u6784"},{"location":"python/Demo/CourseSystem/#_6","text":"","title":"\u9009\u8bfe\u7cfb\u7edf\u603b\u7ed3"},{"location":"python/Demo/CourseSystem/#1","text":"","title":"1.\u7ba1\u7406\u5458"},{"location":"python/Demo/CourseSystem/#11","text":"\u7528\u6237\u518d\u89c6\u56fe\u5c42\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u4ea4\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u7684models.get()\u8fdb\u884c\u6821\u9a8c\u3002 \u82e5\u4e0d\u5b58\u5728\u5219\u521b\u5efa\uff0c\u5e76\u8bb2\u6ce8\u518c\u6210\u529f\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"1.1.\u6ce8\u518c"},{"location":"python/Demo/CourseSystem/#12","text":"\u7528\u6237\u5728\u89c6\u56fe\u5c42\u8f93\u5165\u7528\u6237\u540d\u548c\u5bc6\u7801\uff0c\u4ea4\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u7684models.get()\u8fdb\u884c\u6821\u9a8c\u3002 \u82e5\u4e0d\u5b58\u5728\u5219\u521b\u5efa\uff0c\u5e76\u8bb2\u6ce8\u518c\u6210\u529f\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"1.2.\u767b\u5f55"},{"location":"python/Demo/CourseSystem/#13","text":"\u8ba9\u7528\u6237\u8f93\u5165\u5b66\u6821\u540d\u548c\u5b66\u6821\u5730\u5740\u3002 \u8c03\u7528\u7ba1\u7406\u5458\u63a5\u53e3\u521b\u5efa\u5b66\u6821\u3002 \u5224\u65ad\u5b66\u6821\u662f\u5426\u5b58\u5728\uff0c\u82e5\u5b58\u5728\uff0c\u4e0d\u521b\u5efa\u3002 \u82e5\u4e0d\u5b58\u5728\uff0c\u5219\u8c03\u7528\u63a5\u53e3\u5c42\u521b\u5efa\u5b66\u6821\uff0c\u83b7\u53d6\u7ba1\u7406\u5458\u5bf9\u8c61\u7684\u521b\u5efa\u5b66\u6821\u65b9\u6cd5\u4fdd\u6301\u5b66\u6821\u5bf9\u8c61\u3002 \u5c06\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"1.3.\u521b\u5efa\u5b66\u6821"},{"location":"python/Demo/CourseSystem/#14","text":"\u83b7\u53d6\u6240\u6709\u5b66\u6821\uff0c\u5e76\u6253\u5370\uff0c\u8ba9\u7528\u6237\u9009\u62e9\u3002 \u83b7\u53d6\u7528\u6237\u9009\u62e9\u7684\u5b66\u6821\u4e0e\u521b\u5efa\u7684\u8bfe\u7a0b\uff0c\u4ea4\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u7ba1\u7406\u5458\u5bf9\u8c61\u4e2d\u7684\u521b\u5efa\u8bfe\u7a0b\u65b9\u6cd5\uff0c\u4fdd\u5b58\u8bfe\u7a0b\u5bf9\u8c61\u3002 \u8bfe\u7a0b\u9700\u8981\u7ed1\u5b9a\u7ed9\u5b66\u6821\u5bf9\u8c61\uff0c\u6700\u7ec8\u5c06\u521b\u5efa\u6210\u529f\u7684\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"1.4.\u521b\u5efa\u8bfe\u7a0b"},{"location":"python/Demo/CourseSystem/#15","text":"\u7528\u6237\u8f93\u5165\u8001\u5e08\u540d\u79f0\u3002 \u8c03\u7528\u63a5\u53e3\u5c42\uff0c\u63a5\u53e3\u5c42\u4e2d\u8bbe\u7f6e\u9ed8\u8ba4\u5bc6\u7801123\uff0c\u8c03\u7528\u6570\u636e\u5c42\u3002 \u5224\u65ad\u8001\u5e08\u662f\u5426\u5b58\u5728\uff0c\u4e0d\u5b58\u5728\u5219\u8c03\u7528\u7ba1\u7406\u5458\u5bf9\u8c61\u4e2d\u7684\u521b\u5efa\u8001\u5e08\u65b9\u6cd5\u3002 \u4fdd\u5b58\u8001\u5e08\u5bf9\u8c61\uff0c\u5e76\u5c06\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"1.5.\u521b\u5efa\u8001\u5e08"},{"location":"python/Demo/CourseSystem/#2","text":"","title":"2.\u5b66\u751f"},{"location":"python/Demo/CourseSystem/#21","text":"\u540c\u4e0a","title":"2.1.\u6ce8\u518c"},{"location":"python/Demo/CourseSystem/#22","text":"\u540c\u4e0a","title":"2.2.\u767b\u5f55"},{"location":"python/Demo/CourseSystem/#23","text":"\u83b7\u53d6\u6240\u6709\u5b66\u6821\uff0c\u8ba9\u5b66\u751f\u9009\u62e9\uff0c\u5e76\u5c06\u9009\u62e9\u7684\u5b66\u6821\u4f20\u7ed9\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u5224\u65ad\u5f53\u524d\u5b66\u751f\u662f\u5426\u9009\u62e9\u5b66\u6821\u3002 \u82e5\u6ca1\u6709\u9009\u62e9\uff0c\u5219\u8c03\u7528\u5b66\u751f\u5bf9\u8c61\u4e2d\u7684\u6dfb\u52a0\u5b66\u6821\u65b9\u6cd5\u3002 \u5c06\u6dfb\u52a0\u540e\u6d88\u606f\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"2.3.\u9009\u62e9\u5b66\u6821"},{"location":"python/Demo/CourseSystem/#24","text":"\u5148\u83b7\u53d6\u5f53\u524d\u5b66\u751f\u6240\u5728\u5b66\u6821\u7684\u6240\u6709\u8bfe\u7a0b\uff0c\u5e76\u9009\u62e9\u3002 \u63a5\u53e3\u5c42\u5c06\u9009\u62e9\u540e\u7684\u8bfe\u7a0b\uff0c\u8c03\u7528\u6570\u636e\u5c42\u7684\u6dfb\u52a0\u8bfe\u7a0b\u65b9\u6cd5\u4fdd\u5b58\u3002 \u5b66\u751f\u5bf9\u8c61\u4e2d\u8bfe\u7a0b\u5217\u8868\u6dfb\u52a0\u8bfe\u7a0b\uff0c\u8bbe\u7f6e\u8bfe\u7a0b\u5206\u6570\uff0c\u9ed8\u8ba4\u4e3a0. \u6700\u7ec8\u5c06\u7ed3\u679c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002","title":"2.4.\u9009\u62e9\u8bfe\u7a0b"},{"location":"python/Demo/CourseSystem/#25","text":"\u76f4\u63a5\u8c03\u7528\u63a5\u53e3\u5c42\u3002 \u63a5\u53e3\u5c42\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u7684\u67e5\u770b\u6210\u7ee9\u65b9\u6cd5\u3002 \u8fd4\u56de\u6210\u7ee9\u7ed9\u89c6\u56fe\u5c42\u5e76\u6253\u5370\u3002","title":"2.5.\u67e5\u770b\u6210\u7ee9"},{"location":"python/Demo/CourseSystem/#3","text":"","title":"3.\u8001\u5e08"},{"location":"python/Demo/CourseSystem/#31","text":"\u540c\u4e0a","title":"3.1.\u767b\u5f55"},{"location":"python/Demo/CourseSystem/#32","text":"\u76f4\u63a5\u8c03\u7528\u63a5\u53e3\u5c42\uff0c\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\u4e0b\u8bfe\u7a0b\u5217\u8868\u6570\u636e\u3002 \u82e5\u6709\u5219\u6253\u5370\uff0c\u6ca1\u6709\u5219\u9000\u51fa\u3002","title":"3.2.\u67e5\u770b\u6559\u6388\u8bfe\u7a0b"},{"location":"python/Demo/CourseSystem/#33","text":"\u8c03\u7528\u63a5\u53e3\u5c42\u4e2d\u7684\u9009\u62e9\u6559\u6388\u8bfe\u7a0b\u63a5\u53e3\uff0c\u8c03\u7528\u6570\u636e\u5c42\u4e2d\u6539\u8bfe\u7a0b\u4e0b\u6240\u6709\u7684\u5b66\u751f\uff0c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 \u6253\u5370\u6240\u6709\u7684\u8bfe\u7a0b\uff0c\u8ba9\u8001\u5e08\u9009\u62e9\uff0c\u82e5\u8001\u5e08\u8bfe\u7a0b\u4e2d\u6709\u8be5\u8bfe\u7a0b\u5219\u4e0d\u6dfb\u52a0\u3002 \u6ca1\u6709\uff0c\u5219\u55f2\u7528\u8001\u5e08\u5bf9\u8c61\u4e2d\u7684\u6dfb\u52a0\u8bfe\u7a0b\u65b9\u6cd5\u8fdb\u884c\u6dfb\u52a0\u3002","title":"3.3.\u9009\u62e9\u6559\u6388\u8bfe\u7a0b"},{"location":"python/Demo/CourseSystem/#34","text":"\u76f4\u63a5\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\u4e0b\u6240\u6709\u7684\u8bfe\u7a0b\uff0c\u9009\u62e9\u8bfe\u7a0b\u3002 \u4ece\u8001\u5e08\u5bf9\u8c61\u4e2d\uff0c\u8c03\u7528\u67e5\u770b\u8bfe\u7a0b\u4e0b\u5b66\u751f\u7684\u65b9\u6cd5\uff0c\u83b7\u53d6\u8bfe\u7a0b\u5bf9\u8c61\u4e0b\u7684\u6240\u6709\u5b66\u751f\uff0c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 \u89c6\u56fe\u5c42\u6253\u5370\u8be5\u8bfe\u7a0b\u4e0b\u6240\u6709\u7684\u5b66\u751f\u3002","title":"3.4.\u67e5\u770b\u8bfe\u7a0b\u4e0b\u7684\u5b66\u751f"},{"location":"python/Demo/CourseSystem/#35","text":"\u76f4\u63a5\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\u4e0b\u6240\u6709\u7684\u8bfe\u7a0b\u3002 \u4ece\u8001\u5e08\u5bf9\u8c61\u4e2d\uff0c\u8c03\u7528\u67e5\u770b\u8bfe\u7a0b\u4e0b\u5b66\u751f\u65b9\u6cd5\uff0c\u83b7\u53d6\u8bfe\u7a0b\u5bf9\u8c61\u4e0b\u6240\u6709\u7684\u5b66\u751f\uff0c\u8fd4\u56de\u7ed9\u89c6\u56fe\u5c42\u3002 \u89c6\u56fe\u5c42\u6253\u5370\u6539\u8bfe\u7a0b\u4e0b\u6240\u6709\u7684\u5b66\u751f\uff0c\u5e76\u8ba9\u7528\u6237\u9009\u62e9\u9700\u8981\u5206\u6570\u7684\u5b66\u751f\u3002 \u55f2\u7528\u8001\u5e08\u4fee\u6539\u5206\u6570\u63a5\u53e3\uff0c\u83b7\u53d6\u8001\u5e08\u5bf9\u8c61\uff0c\u8c03\u7528\u5bf9\u8c61\u4e2d\u4fee\u6539\u5206\u6570\u65b9\u6cd5\u3002 \u83b7\u53d6\u5b66\u751f\u5bf9\u8c61\u4e2d\u7684\u5206\u6570\u5b57\u5178\uff0c\u8fdb\u884c\u4fee\u6539\u3002","title":"3.5.\u4fee\u6539\u5b66\u751f\u5206\u6570"},{"location":"python/Demo/CourseSystem/#34_1","text":"","title":"3.4.\u67e5\u770b\u6210\u7ee9"},{"location":"python/Demo/CourseSystem/#_7","text":"","title":"\u793a\u610f\u56fe"},{"location":"python/Demo/CourseSystem/#_8","text":"\u4ee3\u7801","title":"\u53c2\u8003\u4ee3\u7801"},{"location":"python/Foundation/Algorithms/","text":"Python\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5 \u00b6 \u53c2\u8003\u4e66\u76ee\uff1a \"Problem Solving with Algorithms and Data Structures Using Python (Second Edition)\" by Bradley N.Miller and David L.Ranum. \u5927O\u8bb0\u6cd5 \u00b6 \u7b97\u6cd5\u5206\u6790\u662f\u4e00\u79cd\u72ec\u7acb\u4e8e\u5b9e\u73b0\u7684\u7b97\u6cd5\u5ea6\u91cf\u65b9\u6cd5\u3002 \u6570\u91cf\u7ea7\uff08order of magnitude\uff09\u5e38\u88ab\u79f0\u4f5c\u5927O\u8bb0\u6cd5\uff08O\u6307order\uff09\uff0c\u8bb0\u4f5cO(f(n))\u3002\u5b83\u63d0\u4f9b\u4e86\u6b65\u9aa4\u6570\u7684\u4e00\u4e2a\u6709\u7528\u7684\u8fd1\u4f3c\u65b9\u6cd5\u3002f(n)\u51fd\u6570\u4e3aT(n)\u51fd\u6570\u4e2d\u8d77\u51b3\u5b9a\u6027\u4f5c\u7528\u7684\u90e8\u5206\u63d0\u4f9b\u4e86\u7b80\u5355\u7684\u8868\u793a\u3002 \u5927O\u8bb0\u6cd5\u4f7f\u5f97\u7b97\u6cd5\u53ef\u4ee5\u6839\u636e\u968f\u95ee\u9898\u89c4\u6a21\u589e\u957f\u800c\u8d77\u4e3b\u5bfc\u4f5c\u7528\u7684\u90e8\u5206\u8fdb\u884c\u5f52\u7c7b\u3002 \u5f02\u5e8f\u8bcd\u68c0\u6d4b\u95ee\u9898 \u00b6 \u5982\u679c\u4e00\u4e2a\u5b57\u7b26\u4e32\u53ea\u662f\u91cd\u6392\u4e86\u53e6\u4e00\u4e2a\u5b57\u7b26\u4e32\u7684\u5b57\u7b26\uff0c\u90a3\u4e48\u8fd9\u4e2a\u5b57\u7b26\u4e32\u5c31\u662f\u53e6\u4e00\u4e2a\u7684\u5f02\u5e8f\u8bcd\u3002 \u65b9\u68481\uff1a\u6e05\u70b9\u6cd5 \u6e05\u70b9\u7b2c1\u4e2a\u5b57\u7b26\u4e32\u7684\u6bcf\u4e2a\u5b57\u7b26\uff0c\u770b\u770b\u5b83\u4eec\u662f\u5426\u90fd\u51fa\u73b0\u5728\u7b2c2\u4e2a\u5b57\u7b26\u4e32\u4e2d\u3002 \u5728\u5b57\u7b26\u5217\u8868\u4e2d\u68c0\u67e5\u7b2c1\u4e2a\u5b57\u7b26\u4e32\u4e2d\u7684\u6bcf\u4e2a\u5b57\u7b26\uff0c\u5982\u679c\u627e\u5230\u4e86\uff0c\u5c31\u66ff\u6362\u6389\u3002 \u8fd9\u4e2a\u65b9\u6848\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n^2)\u3002 def allotropyWord_1 ( s1 , s2 ): list_a = list ( s2 ) pos1 = 0 stillOK = True while pos1 < len ( s1 ) and stillOK : pos2 = 0 found = False while pos2 < len ( list_a ) and not found : if s1 [ pos1 ] == list_a [ pos2 ]: found = True else : pos2 = pos2 + 1 if found : list_a [ pos2 ] = None else : stillOK = False pos1 = pos1 + 1 return stillOK \u8fd0\u884c\uff1a allotropyWord_1 ( 'hello' , 'olleh' ) \u6ce8\u610flist_a\u7684\u53d8\u5316\u8fc7\u7a0b(\u5339\u914d\u5230\u5373\u66ff\u6362None)\u3002 [ 'o' , 'l' , 'l' , 'e' , None ] [ 'o' , 'l' , 'l' , None , None ] [ 'o' , None , 'l' , None , None ] [ 'o' , None , None , None , None ] [ None , None , None , None , None ] \u65b9\u68482\uff1a\u6392\u5e8f\u6cd5 \u6309\u7167\u5b57\u6bcd\u8868\u987a\u5e8f\u7ed9\u5b57\u7b26\u6392\u5e8f\uff0c\u5f02\u5e8f\u8bcd\u5f97\u5230\u7684\u7ed3\u679c\u5c06\u662f\u540c\u4e00\u4e2a\u5b57\u7b26\u4e32\u3002 \u8fd9\u4e2a\u65b9\u6848\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n^2)\u3002 def allotropyWord_2 ( s1 , s2 ): list1 = list ( s1 ) list2 = list ( s2 ) list1 . sort () list2 . sort () pos = 0 matched = True while pos < len ( s1 ) and matched : if list1 [ pos ] == list2 [ pos ]: pos = pos + 1 else : matched = False return matched \u8fd0\u884c\uff1a allotropyWord_2 ( 'hello' , 'olleh' ) \u65b9\u68483\uff1a\u8ba1\u6570\u6cd5 \u4e24\u4e2a\u5f02\u5e8f\u8bcd\u6709\u540c\u6837\u6570\u76ee\u7684a\u3001\u540c\u6837\u6570\u76ee\u7684b\u3001\u540c\u6837\u6570\u76ee\u7684c\uff0c\u7b49\u7b49\u3002 \u4f7f\u752826\u4e2a\u8ba1\u6570\u5668\uff0c\u5bf9\u5e94\u6bcf\u4e2a\u5b57\u7b26\u3002\u6bcf\u9047\u5230\u4e00\u4e2a\u5b57\u7b26\uff0c\u5c31\u5c06\u5bf9\u5e94\u7684\u8ba1\u6570\u5668\u52a01\u3002 \u5982\u679c\u4e24\u4e2a\u8ba1\u6570\u5668\u5217\u8868\u76f8\u540c\uff0c\u90a3\u4e48\u4e24\u4e2a\u5b57\u7b26\u4e32\u80af\u5b9a\u662f\u5f02\u5e8f\u8bcd\u3002 \u8fd9\u4e2a\u65b9\u6848\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\u3002 def allotropyWord_3 ( s1 , s2 ): c1 = [ 0 ] * 26 c2 = [ 0 ] * 26 for i in range ( len ( s1 )): # \u6bcf\u4e2a\u5b57\u7b26\u7684ASCII\u7801\u4e0e\u5b57\u7b26a\u7684ASCII\u7801\u7684\u5dee\u503c(\u504f\u79fb\u91cf) pos = ord ( s1 [ i ]) - ord ( 'a' ) c1 [ pos ] = c1 [ pos ] + 1 for i in range ( len ( s2 )): pos = ord ( s2 [ i ]) - ord ( 'a' ) c2 [ pos ] = c2 [ pos ] + 1 j = 0 stillOK = True while j < 26 and stillOK : if c1 [ j ] == c2 [ j ]: j = j + 1 else : stillOK = False return stillOK \u8fd0\u884c\uff1a allotropyWord_3 ( 'hello' , 'olleh' ) \u53c2\u8003\uff1a Python\u7684\u65f6\u95f4\u590d\u6742\u5ea6(Time Complexity) \u7ebf\u6027\u6570\u636e\u7ed3\u6784 \u00b6 \u771f\u6b63\u533a\u5206\u7ebf\u6027\u6570\u636e\u7ed3\u6784\u7684\u662f\u5143\u7d20\u7684\u6dfb\u52a0\u65b9\u5f0f\u548c\u79fb\u9664\u65b9\u5f0f\uff0c\u5c24\u5176\u662f\u6dfb\u52a0\u64cd\u4f5c\u548c\u79fb\u9664\u64cd\u4f5c\u53d1\u751f\u7684\u4f4d\u7f6e\u3002 \u6808 \u00b6 \u6808\u6709\u65f6\u4e5f\u88ab\u79f0\u4f5c\u201c\u4e0b\u63a8\u6808\u201d\u3002\u5b83\u662f\u6709\u5e8f\u96c6\u5408\uff0c\u6dfb\u52a0\u64cd\u4f5c\u548c\u79fb\u9664\u64cd\u4f5c\u603b\u53d1\u751f\u5728\u540c\u4e00\u7aef\uff0c\u5373\u201c\u9876\u7aef\u201d\uff0c\u53e6\u4e00\u7aef\u5219\u88ab\u79f0\u4e3a\u201c\u5e95\u7aef\u201d\u3002 \u6700\u65b0\u6dfb\u52a0\u7684\u5143\u7d20\u5c06\u88ab\u6700\u5148\u79fb\u9664\u3002\u8fd9\u79cd\u6392\u5e8f\u539f\u5219\u88ab\u79f0\u4f5cLIFO\uff08last-in first-out\uff09\uff0c\u5373\u540e\u8fdb\u5148\u51fa\u3002 \u6808\u7684\u53cd\u8f6c\u7279\u6027\u3002 \u6808\u7684\u5b9e\u73b0\u65b9\u6cd51: append() \u548c pop() \u7684\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662fO(1)\uff0c\u6240\u4ee5\u4e0d\u8bba\u6808\u4e2d\u6709\u591a\u5c11\u4e2a\u5143\u7d20\uff0c push \u64cd\u4f5c\u548c pop \u64cd\u4f5c\u90fd\u4f1a\u5728\u6052\u5b9a\u7684\u65f6\u95f4\u5185\u5b8c\u6210\u3002 class Stack (): def __init__ ( self ) -> None : self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . append ( item ) def pop ( self ): return self . items . pop () def peek ( self ): return self . items [ len ( self . items ) - 1 ] def size ( self ): return len ( self . items ) \u6808\u7684\u5b9e\u73b0\u65b9\u6cd52: insert(0) \u548c pop(0) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662fO(n)\uff0c\u5143\u7d20\u8d8a\u591a\u5c31\u8d8a\u6162\uff0c\u6027\u80fd\u5219\u53d7\u5236\u4e8e\u6808\u4e2d\u7684\u5143\u7d20\u4e2a\u6570\u3002 class Stack (): def __init__ ( self ) -> None : self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . insert ( 0 , item ) def pop ( self ): return self . items . pop ( 0 ) def peek ( self ): return self . items [ 0 ] def size ( self ): return len ( self . items ) \u5bf9\u4e0a\u9762\u7684\u5b9e\u73b0\uff0c\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u8fdb\u884c\u5206\u522b\u9a8c\u8bc1\uff1a s = Stack () s . isEmpty () s . push ( 3 ) s . push ( 'dog' ) s . peek () s . size () s . isEmpty () s . push ( 6.6 ) s . pop () s . size () \u62ec\u53f7\u5339\u914d\u95ee\u9898 \u00b6 #!/usr/bin/python3 #!/usr/bin/env python3 # -*- coding: utf-8 -*- class Stack (): def __init__ ( self ): self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . append ( item ) def pop ( self ): return self . items . pop () def peek ( self ): return self . items [ len ( self . items ) - 1 ] def size ( self ): return len ( self . items ) # \u5173\u8054\u5de6\u53f3\u62ec\u53f7 def matches ( open , close ): opens = \"([{\" closers = \")]}\" # \u7b26\u5408\u5173\u8054\u7684\uff0c\u8fd4\u56deTrue return opens . index ( open ) == closers . index ( close ) def parChecker ( symbolString ): s = Stack () matched = True index = 0 # \u8bfb\u53d6\u8f93\u5165\u5b57\u4e32\u6bcf\u4e2a\u5b57\u7b26 while index < len ( symbolString ) and matched : symbol = symbolString [ index ] if symbol in \"([{\" : # \u5de6\u62ec\u53f7\u5165\u6808 s . push ( symbol ) else : if s . isEmpty (): # \u9047\u5230\u975e\u5de6\u62ec\u53f7\u5b57\u7b26\uff0c\u5982\u4e3a\u7a7a\uff0c\u5219\u9000\u51fa\u5faa\u73af matched = False else : top = s . pop () # \u9047\u5230\u975e\u5de6\u62ec\u53f7\u5b57\u7b26\uff0c\u5982\u4e0d\u4e3a\u7a7a\uff0c\u5219\u51fa\u6808\uff0c\u5e76\u5224\u65ad\u662f\u5426\u672a\u4e3a\u5bf9\u5e94\u7684\u53f3\u62ec\u53f7 if not matches ( top , symbol ): # \u5426\u5219\u9000\u51fa\u5faa\u73af matched = False index = index + 1 # \u5b8c\u6210\u6bcf\u4e2a\u5b57\u7b26\u7684\u51fa\u5165\u6808\u68c0\u67e5\uff0c\u5f53\u524d\u6808\u4e3a\u7a7a\uff0c\u4e14\u90fd\u5339\u914d\uff0c\u5219\u8fd4\u56deTrue if matched and s . isEmpty (): return True else : return False if __name__ == '__main__' : parChecker ( \"([[ {} ])\" ) parChecker ( \"([ {} ])\" ) \u6267\u884c\u7ed3\u679c\u5982\u4e0b\uff0c\u7b26\u5408\u9884\u671f\u3002 False True \u8fdb\u5236\u8f6c\u6362\u95ee\u9898 \u00b6 \u4f8b\u5982\uff0c\u4f7f\u7528\u201c\u9664\u4ee52\u201d\u7684\u7b97\u6cd5\uff0c\u5341\u8fdb\u5236\u6570\u8f6c\u6362\u6210\u4e8c\u8fdb\u5236\u6570\uff0c\u5229\u7528\u6808\u6765\u4fdd\u5b58\u4e8c\u8fdb\u5236\u7ed3\u679c\u7684\u6bcf\u4e00\u4f4d\u3002 \u201c\u9664\u4ee52\u201d\u7b97\u6cd5\u5047\u8bbe\u5f85\u5904\u7406\u7684\u6574\u6570\u5927\u4e8e0\u3002 \u5b83\u7528\u4e00\u4e2a\u7b80\u5355\u7684\u5faa\u73af\u4e0d\u505c\u5730\u5c06\u5341\u8fdb\u5236\u6570\u9664\u4ee52\uff0c\u5e76\u4e14\u8bb0\u5f55\u4f59\u6570\u3002 \u7b2c\u4e00\u6b21\u9664\u4ee52\u7684\u7ed3\u679c\u80fd\u591f\u7528\u4e8e\u533a\u5206\u5076\u6570\u548c\u5947\u6570\u3002 \u5982\u679c\u662f\u5076\u6570\uff0c\u5219\u4f59\u6570\u4e3a0\uff0c\u56e0\u6b64\u4e2a\u4f4d\u4e0a\u7684\u6570\u5b57\u4e3a0\uff1b \u5982\u679c\u662f\u5947\u6570\uff0c\u5219\u4f59\u6570\u4e3a1\uff0c\u56e0\u6b64\u4e2a\u4f4d\u4e0a\u7684\u6570\u5b57\u4e3a1\u3002 \u53ef\u4ee5\u5c06\u8981\u6784\u5efa\u7684\u4e8c\u8fdb\u5236\u6570\u770b\u6210\u4e00\u7cfb\u5217\u6570\u5b57\uff1b\u8ba1\u7b97\u51fa\u7684\u7b2c\u4e00\u4e2a\u4f59\u6570\u662f\u6700\u540e\u4e00\u4f4d\u3002 \u8fd9\u4f53\u73b0\u4e86\u53cd\u8f6c\u7279\u6027\uff0c\u56e0\u6b64\u9002\u7528\u6808\u6765\u5904\u7406\u3002 class Stack (): def __init__ ( self ): self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . append ( item ) def pop ( self ): return self . items . pop () def peek ( self ): return self . items [ len ( self . items ) - 1 ] def size ( self ): return len ( self . items ) def decConverter ( decNumber , baseNumber ): remstack = Stack () digits = \"0123456789ABCDEF\" while decNumber > 0 : rem = decNumber % baseNumber remstack . push ( rem ) decNumber = decNumber // baseNumber newString = \"\" while not remstack . isEmpty (): newString = newString + digits [ remstack . pop ()] return newString if __name__ == '__main__' : decConverter ( 233 , 2 ) decConverter ( 233 , 8 ) decConverter ( 233 , 10 ) decConverter ( 233 , 16 ) \u8fd0\u884c\u7ed3\u679c\uff1a '11101001' '351' '233' 'E9' \u961f\u5217 \u00b6 \u4f7f\u7528 insert() \u5411\u961f\u5217\u7684\u5c3e\u90e8\u6dfb\u52a0\u65b0\u5143\u7d20\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\u3002 \u4f7f\u7528 pop() \u79fb\u9664\u961f\u5217\u5934\u90e8\u7684\u5143\u7d20\uff08\u5217\u8868\u4e2d\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff09\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(1)\u3002 class Queue (): def __init__ ( self ): self . items = [] def isEmpty ( self ): return self . items == [] def enqueue ( self , item ): return self . items . insert ( 0 , item ) def dequeue ( self ): return self . items . pop () def size ( self ): return len ( self . items ) if __name__ == '__main__' : q = Queue () q . isEmpty () q . enqueue ( 2 ) q . enqueue ( 'h' ) q . size () q . isEmpty () q . dequeue () q . size () \u8fd0\u884c\u7ed3\u679c: True 2 False 2 1 \u7ea6\u745f\u592b\u65af\u95ee\u9898 \u00b6 \u901a\u8fc7\u6a21\u62df\u5b9e\u73b0\u4f20\u571f\u8c46\u6e38\u620f\u6765\u89e3\u91ca\u7ea6\u745f\u592b\u65af\u95ee\u9898\u3002 ```python class Queue(): def init (self): self.items = [] def isEmpty(self): return self.items == [] def enqueue(self, item): return self.items.insert(0, item) def dequeue(self): return self.items.pop() def size(self): return len(self.items) def hotPotato(namelist, num): simqueue = Queue() for name in namelist: simqueue.enqueue(name) while simqueue.size() > 1: for i in range(num): simqueue.enqueue(simqueue.dequeue()) simqueue.dequeue() return simqueue.dequeue() if name == ' main ': hotPotato([\"Bill\", \"David\", \"Susan\", \"Jane\", \"Ken\", \"Brad\"], 7) ``` \u8fd0\u884c\u7ed3\u679c\u5982\u4e0b\uff0c\u6700\u540e\u53ea\u5269Susan\u3002\u8bbe\u5b9a\u4e0d\u540c\u7684num\uff08\u8fd9\u91cc\u662f7\uff09\u4f1a\u5f97\u5230\u4e0d\u540c\u7684\u7ed3\u679c\u3002 python 'Susan' \u6253\u5370\u4efb\u52a1 \u00b6 \u53cc\u7aef\u961f\u5217 \u00b6 \u5217\u8868 \u00b6","title":"Python\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5"},{"location":"python/Foundation/Algorithms/#python","text":"\u53c2\u8003\u4e66\u76ee\uff1a \"Problem Solving with Algorithms and Data Structures Using Python (Second Edition)\" by Bradley N.Miller and David L.Ranum.","title":"Python\u6570\u636e\u7ed3\u6784\u548c\u7b97\u6cd5"},{"location":"python/Foundation/Algorithms/#o","text":"\u7b97\u6cd5\u5206\u6790\u662f\u4e00\u79cd\u72ec\u7acb\u4e8e\u5b9e\u73b0\u7684\u7b97\u6cd5\u5ea6\u91cf\u65b9\u6cd5\u3002 \u6570\u91cf\u7ea7\uff08order of magnitude\uff09\u5e38\u88ab\u79f0\u4f5c\u5927O\u8bb0\u6cd5\uff08O\u6307order\uff09\uff0c\u8bb0\u4f5cO(f(n))\u3002\u5b83\u63d0\u4f9b\u4e86\u6b65\u9aa4\u6570\u7684\u4e00\u4e2a\u6709\u7528\u7684\u8fd1\u4f3c\u65b9\u6cd5\u3002f(n)\u51fd\u6570\u4e3aT(n)\u51fd\u6570\u4e2d\u8d77\u51b3\u5b9a\u6027\u4f5c\u7528\u7684\u90e8\u5206\u63d0\u4f9b\u4e86\u7b80\u5355\u7684\u8868\u793a\u3002 \u5927O\u8bb0\u6cd5\u4f7f\u5f97\u7b97\u6cd5\u53ef\u4ee5\u6839\u636e\u968f\u95ee\u9898\u89c4\u6a21\u589e\u957f\u800c\u8d77\u4e3b\u5bfc\u4f5c\u7528\u7684\u90e8\u5206\u8fdb\u884c\u5f52\u7c7b\u3002","title":"\u5927O\u8bb0\u6cd5"},{"location":"python/Foundation/Algorithms/#_1","text":"\u5982\u679c\u4e00\u4e2a\u5b57\u7b26\u4e32\u53ea\u662f\u91cd\u6392\u4e86\u53e6\u4e00\u4e2a\u5b57\u7b26\u4e32\u7684\u5b57\u7b26\uff0c\u90a3\u4e48\u8fd9\u4e2a\u5b57\u7b26\u4e32\u5c31\u662f\u53e6\u4e00\u4e2a\u7684\u5f02\u5e8f\u8bcd\u3002 \u65b9\u68481\uff1a\u6e05\u70b9\u6cd5 \u6e05\u70b9\u7b2c1\u4e2a\u5b57\u7b26\u4e32\u7684\u6bcf\u4e2a\u5b57\u7b26\uff0c\u770b\u770b\u5b83\u4eec\u662f\u5426\u90fd\u51fa\u73b0\u5728\u7b2c2\u4e2a\u5b57\u7b26\u4e32\u4e2d\u3002 \u5728\u5b57\u7b26\u5217\u8868\u4e2d\u68c0\u67e5\u7b2c1\u4e2a\u5b57\u7b26\u4e32\u4e2d\u7684\u6bcf\u4e2a\u5b57\u7b26\uff0c\u5982\u679c\u627e\u5230\u4e86\uff0c\u5c31\u66ff\u6362\u6389\u3002 \u8fd9\u4e2a\u65b9\u6848\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n^2)\u3002 def allotropyWord_1 ( s1 , s2 ): list_a = list ( s2 ) pos1 = 0 stillOK = True while pos1 < len ( s1 ) and stillOK : pos2 = 0 found = False while pos2 < len ( list_a ) and not found : if s1 [ pos1 ] == list_a [ pos2 ]: found = True else : pos2 = pos2 + 1 if found : list_a [ pos2 ] = None else : stillOK = False pos1 = pos1 + 1 return stillOK \u8fd0\u884c\uff1a allotropyWord_1 ( 'hello' , 'olleh' ) \u6ce8\u610flist_a\u7684\u53d8\u5316\u8fc7\u7a0b(\u5339\u914d\u5230\u5373\u66ff\u6362None)\u3002 [ 'o' , 'l' , 'l' , 'e' , None ] [ 'o' , 'l' , 'l' , None , None ] [ 'o' , None , 'l' , None , None ] [ 'o' , None , None , None , None ] [ None , None , None , None , None ] \u65b9\u68482\uff1a\u6392\u5e8f\u6cd5 \u6309\u7167\u5b57\u6bcd\u8868\u987a\u5e8f\u7ed9\u5b57\u7b26\u6392\u5e8f\uff0c\u5f02\u5e8f\u8bcd\u5f97\u5230\u7684\u7ed3\u679c\u5c06\u662f\u540c\u4e00\u4e2a\u5b57\u7b26\u4e32\u3002 \u8fd9\u4e2a\u65b9\u6848\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n^2)\u3002 def allotropyWord_2 ( s1 , s2 ): list1 = list ( s1 ) list2 = list ( s2 ) list1 . sort () list2 . sort () pos = 0 matched = True while pos < len ( s1 ) and matched : if list1 [ pos ] == list2 [ pos ]: pos = pos + 1 else : matched = False return matched \u8fd0\u884c\uff1a allotropyWord_2 ( 'hello' , 'olleh' ) \u65b9\u68483\uff1a\u8ba1\u6570\u6cd5 \u4e24\u4e2a\u5f02\u5e8f\u8bcd\u6709\u540c\u6837\u6570\u76ee\u7684a\u3001\u540c\u6837\u6570\u76ee\u7684b\u3001\u540c\u6837\u6570\u76ee\u7684c\uff0c\u7b49\u7b49\u3002 \u4f7f\u752826\u4e2a\u8ba1\u6570\u5668\uff0c\u5bf9\u5e94\u6bcf\u4e2a\u5b57\u7b26\u3002\u6bcf\u9047\u5230\u4e00\u4e2a\u5b57\u7b26\uff0c\u5c31\u5c06\u5bf9\u5e94\u7684\u8ba1\u6570\u5668\u52a01\u3002 \u5982\u679c\u4e24\u4e2a\u8ba1\u6570\u5668\u5217\u8868\u76f8\u540c\uff0c\u90a3\u4e48\u4e24\u4e2a\u5b57\u7b26\u4e32\u80af\u5b9a\u662f\u5f02\u5e8f\u8bcd\u3002 \u8fd9\u4e2a\u65b9\u6848\u7684\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\u3002 def allotropyWord_3 ( s1 , s2 ): c1 = [ 0 ] * 26 c2 = [ 0 ] * 26 for i in range ( len ( s1 )): # \u6bcf\u4e2a\u5b57\u7b26\u7684ASCII\u7801\u4e0e\u5b57\u7b26a\u7684ASCII\u7801\u7684\u5dee\u503c(\u504f\u79fb\u91cf) pos = ord ( s1 [ i ]) - ord ( 'a' ) c1 [ pos ] = c1 [ pos ] + 1 for i in range ( len ( s2 )): pos = ord ( s2 [ i ]) - ord ( 'a' ) c2 [ pos ] = c2 [ pos ] + 1 j = 0 stillOK = True while j < 26 and stillOK : if c1 [ j ] == c2 [ j ]: j = j + 1 else : stillOK = False return stillOK \u8fd0\u884c\uff1a allotropyWord_3 ( 'hello' , 'olleh' ) \u53c2\u8003\uff1a Python\u7684\u65f6\u95f4\u590d\u6742\u5ea6(Time Complexity)","title":"\u5f02\u5e8f\u8bcd\u68c0\u6d4b\u95ee\u9898"},{"location":"python/Foundation/Algorithms/#_2","text":"\u771f\u6b63\u533a\u5206\u7ebf\u6027\u6570\u636e\u7ed3\u6784\u7684\u662f\u5143\u7d20\u7684\u6dfb\u52a0\u65b9\u5f0f\u548c\u79fb\u9664\u65b9\u5f0f\uff0c\u5c24\u5176\u662f\u6dfb\u52a0\u64cd\u4f5c\u548c\u79fb\u9664\u64cd\u4f5c\u53d1\u751f\u7684\u4f4d\u7f6e\u3002","title":"\u7ebf\u6027\u6570\u636e\u7ed3\u6784"},{"location":"python/Foundation/Algorithms/#_3","text":"\u6808\u6709\u65f6\u4e5f\u88ab\u79f0\u4f5c\u201c\u4e0b\u63a8\u6808\u201d\u3002\u5b83\u662f\u6709\u5e8f\u96c6\u5408\uff0c\u6dfb\u52a0\u64cd\u4f5c\u548c\u79fb\u9664\u64cd\u4f5c\u603b\u53d1\u751f\u5728\u540c\u4e00\u7aef\uff0c\u5373\u201c\u9876\u7aef\u201d\uff0c\u53e6\u4e00\u7aef\u5219\u88ab\u79f0\u4e3a\u201c\u5e95\u7aef\u201d\u3002 \u6700\u65b0\u6dfb\u52a0\u7684\u5143\u7d20\u5c06\u88ab\u6700\u5148\u79fb\u9664\u3002\u8fd9\u79cd\u6392\u5e8f\u539f\u5219\u88ab\u79f0\u4f5cLIFO\uff08last-in first-out\uff09\uff0c\u5373\u540e\u8fdb\u5148\u51fa\u3002 \u6808\u7684\u53cd\u8f6c\u7279\u6027\u3002 \u6808\u7684\u5b9e\u73b0\u65b9\u6cd51: append() \u548c pop() \u7684\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662fO(1)\uff0c\u6240\u4ee5\u4e0d\u8bba\u6808\u4e2d\u6709\u591a\u5c11\u4e2a\u5143\u7d20\uff0c push \u64cd\u4f5c\u548c pop \u64cd\u4f5c\u90fd\u4f1a\u5728\u6052\u5b9a\u7684\u65f6\u95f4\u5185\u5b8c\u6210\u3002 class Stack (): def __init__ ( self ) -> None : self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . append ( item ) def pop ( self ): return self . items . pop () def peek ( self ): return self . items [ len ( self . items ) - 1 ] def size ( self ): return len ( self . items ) \u6808\u7684\u5b9e\u73b0\u65b9\u6cd52: insert(0) \u548c pop(0) \u7684\u65f6\u95f4\u590d\u6742\u5ea6\u90fd\u662fO(n)\uff0c\u5143\u7d20\u8d8a\u591a\u5c31\u8d8a\u6162\uff0c\u6027\u80fd\u5219\u53d7\u5236\u4e8e\u6808\u4e2d\u7684\u5143\u7d20\u4e2a\u6570\u3002 class Stack (): def __init__ ( self ) -> None : self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . insert ( 0 , item ) def pop ( self ): return self . items . pop ( 0 ) def peek ( self ): return self . items [ 0 ] def size ( self ): return len ( self . items ) \u5bf9\u4e0a\u9762\u7684\u5b9e\u73b0\uff0c\u53ef\u4ee5\u901a\u8fc7\u4e0b\u9762\u8fdb\u884c\u5206\u522b\u9a8c\u8bc1\uff1a s = Stack () s . isEmpty () s . push ( 3 ) s . push ( 'dog' ) s . peek () s . size () s . isEmpty () s . push ( 6.6 ) s . pop () s . size ()","title":"\u6808"},{"location":"python/Foundation/Algorithms/#_4","text":"#!/usr/bin/python3 #!/usr/bin/env python3 # -*- coding: utf-8 -*- class Stack (): def __init__ ( self ): self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . append ( item ) def pop ( self ): return self . items . pop () def peek ( self ): return self . items [ len ( self . items ) - 1 ] def size ( self ): return len ( self . items ) # \u5173\u8054\u5de6\u53f3\u62ec\u53f7 def matches ( open , close ): opens = \"([{\" closers = \")]}\" # \u7b26\u5408\u5173\u8054\u7684\uff0c\u8fd4\u56deTrue return opens . index ( open ) == closers . index ( close ) def parChecker ( symbolString ): s = Stack () matched = True index = 0 # \u8bfb\u53d6\u8f93\u5165\u5b57\u4e32\u6bcf\u4e2a\u5b57\u7b26 while index < len ( symbolString ) and matched : symbol = symbolString [ index ] if symbol in \"([{\" : # \u5de6\u62ec\u53f7\u5165\u6808 s . push ( symbol ) else : if s . isEmpty (): # \u9047\u5230\u975e\u5de6\u62ec\u53f7\u5b57\u7b26\uff0c\u5982\u4e3a\u7a7a\uff0c\u5219\u9000\u51fa\u5faa\u73af matched = False else : top = s . pop () # \u9047\u5230\u975e\u5de6\u62ec\u53f7\u5b57\u7b26\uff0c\u5982\u4e0d\u4e3a\u7a7a\uff0c\u5219\u51fa\u6808\uff0c\u5e76\u5224\u65ad\u662f\u5426\u672a\u4e3a\u5bf9\u5e94\u7684\u53f3\u62ec\u53f7 if not matches ( top , symbol ): # \u5426\u5219\u9000\u51fa\u5faa\u73af matched = False index = index + 1 # \u5b8c\u6210\u6bcf\u4e2a\u5b57\u7b26\u7684\u51fa\u5165\u6808\u68c0\u67e5\uff0c\u5f53\u524d\u6808\u4e3a\u7a7a\uff0c\u4e14\u90fd\u5339\u914d\uff0c\u5219\u8fd4\u56deTrue if matched and s . isEmpty (): return True else : return False if __name__ == '__main__' : parChecker ( \"([[ {} ])\" ) parChecker ( \"([ {} ])\" ) \u6267\u884c\u7ed3\u679c\u5982\u4e0b\uff0c\u7b26\u5408\u9884\u671f\u3002 False True","title":"\u62ec\u53f7\u5339\u914d\u95ee\u9898"},{"location":"python/Foundation/Algorithms/#_5","text":"\u4f8b\u5982\uff0c\u4f7f\u7528\u201c\u9664\u4ee52\u201d\u7684\u7b97\u6cd5\uff0c\u5341\u8fdb\u5236\u6570\u8f6c\u6362\u6210\u4e8c\u8fdb\u5236\u6570\uff0c\u5229\u7528\u6808\u6765\u4fdd\u5b58\u4e8c\u8fdb\u5236\u7ed3\u679c\u7684\u6bcf\u4e00\u4f4d\u3002 \u201c\u9664\u4ee52\u201d\u7b97\u6cd5\u5047\u8bbe\u5f85\u5904\u7406\u7684\u6574\u6570\u5927\u4e8e0\u3002 \u5b83\u7528\u4e00\u4e2a\u7b80\u5355\u7684\u5faa\u73af\u4e0d\u505c\u5730\u5c06\u5341\u8fdb\u5236\u6570\u9664\u4ee52\uff0c\u5e76\u4e14\u8bb0\u5f55\u4f59\u6570\u3002 \u7b2c\u4e00\u6b21\u9664\u4ee52\u7684\u7ed3\u679c\u80fd\u591f\u7528\u4e8e\u533a\u5206\u5076\u6570\u548c\u5947\u6570\u3002 \u5982\u679c\u662f\u5076\u6570\uff0c\u5219\u4f59\u6570\u4e3a0\uff0c\u56e0\u6b64\u4e2a\u4f4d\u4e0a\u7684\u6570\u5b57\u4e3a0\uff1b \u5982\u679c\u662f\u5947\u6570\uff0c\u5219\u4f59\u6570\u4e3a1\uff0c\u56e0\u6b64\u4e2a\u4f4d\u4e0a\u7684\u6570\u5b57\u4e3a1\u3002 \u53ef\u4ee5\u5c06\u8981\u6784\u5efa\u7684\u4e8c\u8fdb\u5236\u6570\u770b\u6210\u4e00\u7cfb\u5217\u6570\u5b57\uff1b\u8ba1\u7b97\u51fa\u7684\u7b2c\u4e00\u4e2a\u4f59\u6570\u662f\u6700\u540e\u4e00\u4f4d\u3002 \u8fd9\u4f53\u73b0\u4e86\u53cd\u8f6c\u7279\u6027\uff0c\u56e0\u6b64\u9002\u7528\u6808\u6765\u5904\u7406\u3002 class Stack (): def __init__ ( self ): self . items = [] def isEmpty ( self ): return self . items == [] def push ( self , item ): self . items . append ( item ) def pop ( self ): return self . items . pop () def peek ( self ): return self . items [ len ( self . items ) - 1 ] def size ( self ): return len ( self . items ) def decConverter ( decNumber , baseNumber ): remstack = Stack () digits = \"0123456789ABCDEF\" while decNumber > 0 : rem = decNumber % baseNumber remstack . push ( rem ) decNumber = decNumber // baseNumber newString = \"\" while not remstack . isEmpty (): newString = newString + digits [ remstack . pop ()] return newString if __name__ == '__main__' : decConverter ( 233 , 2 ) decConverter ( 233 , 8 ) decConverter ( 233 , 10 ) decConverter ( 233 , 16 ) \u8fd0\u884c\u7ed3\u679c\uff1a '11101001' '351' '233' 'E9'","title":"\u8fdb\u5236\u8f6c\u6362\u95ee\u9898"},{"location":"python/Foundation/Algorithms/#_6","text":"\u4f7f\u7528 insert() \u5411\u961f\u5217\u7684\u5c3e\u90e8\u6dfb\u52a0\u65b0\u5143\u7d20\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(n)\u3002 \u4f7f\u7528 pop() \u79fb\u9664\u961f\u5217\u5934\u90e8\u7684\u5143\u7d20\uff08\u5217\u8868\u4e2d\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff09\uff0c\u65f6\u95f4\u590d\u6742\u5ea6\u662fO(1)\u3002 class Queue (): def __init__ ( self ): self . items = [] def isEmpty ( self ): return self . items == [] def enqueue ( self , item ): return self . items . insert ( 0 , item ) def dequeue ( self ): return self . items . pop () def size ( self ): return len ( self . items ) if __name__ == '__main__' : q = Queue () q . isEmpty () q . enqueue ( 2 ) q . enqueue ( 'h' ) q . size () q . isEmpty () q . dequeue () q . size () \u8fd0\u884c\u7ed3\u679c: True 2 False 2 1","title":"\u961f\u5217"},{"location":"python/Foundation/Algorithms/#_7","text":"\u901a\u8fc7\u6a21\u62df\u5b9e\u73b0\u4f20\u571f\u8c46\u6e38\u620f\u6765\u89e3\u91ca\u7ea6\u745f\u592b\u65af\u95ee\u9898\u3002 ```python class Queue(): def init (self): self.items = [] def isEmpty(self): return self.items == [] def enqueue(self, item): return self.items.insert(0, item) def dequeue(self): return self.items.pop() def size(self): return len(self.items) def hotPotato(namelist, num): simqueue = Queue() for name in namelist: simqueue.enqueue(name) while simqueue.size() > 1: for i in range(num): simqueue.enqueue(simqueue.dequeue()) simqueue.dequeue() return simqueue.dequeue() if name == ' main ': hotPotato([\"Bill\", \"David\", \"Susan\", \"Jane\", \"Ken\", \"Brad\"], 7) ``` \u8fd0\u884c\u7ed3\u679c\u5982\u4e0b\uff0c\u6700\u540e\u53ea\u5269Susan\u3002\u8bbe\u5b9a\u4e0d\u540c\u7684num\uff08\u8fd9\u91cc\u662f7\uff09\u4f1a\u5f97\u5230\u4e0d\u540c\u7684\u7ed3\u679c\u3002 python 'Susan'","title":"\u7ea6\u745f\u592b\u65af\u95ee\u9898"},{"location":"python/Foundation/Algorithms/#_8","text":"","title":"\u6253\u5370\u4efb\u52a1"},{"location":"python/Foundation/Algorithms/#_9","text":"","title":"\u53cc\u7aef\u961f\u5217"},{"location":"python/Foundation/Algorithms/#_10","text":"","title":"\u5217\u8868"},{"location":"python/Foundation/ch00/","text":"Python\u5b89\u88c5 \u00b6 Python\u73af\u5883 \u00b6 \u8fd9\u91cc\u4f7f\u7528\u7cfb\u7edf\u81ea\u5e26\u7684Python\u73af\u5883\uff1a \u4e3b\u673a\uff1aVMWare\u865a\u62df\u673a \u64cd\u4f5c\u7cfb\u7edf(Guest)\uff1aopenSUSE 15.3 Python\u7248\u672c\uff1a3.6.15(openSUSE\u81ea\u5e26) \u68c0\u67e5Python\u7248\u672c \u00b6 $ python --version Python 2 .7.18 $ python3 --version Python 3 .6.15 \u5347\u7ea7pip \u00b6 $ pip3 install --upgrade pip $ pip --version pip 21 .3.1 from /home/james/.local/lib/python3.6/site-packages/pip ( python 3 .6 ) $ pip3 --version pip 21 .3.1 from /home/james/.local/lib/python3.6/site-packages/pip ( python 3 .6 ) pip\u56fd\u5185\u6e90 \u00b6 https://mirrors.aliyun.com/pypi/simple/ https://pypi.tuna.tsinghua.edu.cn/simple/ http://pypi.doubanio.com/simple/ https://mirrors.cloud.tencent.com/pypi/simple/ \u5b89\u88c5Python\u5305(\u6307\u5b9a\u6e90) \u00b6 pip3 install jinja2 -i https://mirrors.aliyun.com/pypi/simple/ pip3 install Django -i https://mirrors.aliyun.com/pypi/simple/ pip3 install sqlite_utils -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pymongo -i https://mirrors.aliyun.com/pypi/simple/ pip3 install numpy -i https://mirrors.aliyun.com/pypi/simple/ pip3 install matplotlib -i https://mirrors.aliyun.com/pypi/simple/ pip3 install scikit-learn -i https://mirrors.aliyun.com/pypi/simple/ pip3 install xlrd -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pandas -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pydotplus -i https://mirrors.aliyun.com/pypi/simple/ pip3 install seaborn -i https://mirrors.aliyun.com/pypi/simple/ pip3 install selenium -i https://mirrors.aliyun.com/pypi/simple/ pip3 install mlxtend -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pandas-datareader -i https://mirrors.aliyun.com/pypi/simple/ pip3 install lxml -i https://mirrors.aliyun.com/pypi/simple/ pip3 install beautifulsoup4 -i https://mirrors.aliyun.com/pypi/simple/ pip3 install html5lib -i https://mirrors.aliyun.com/pypi/simple/ pip3 install tables -i https://mirrors.aliyun.com/pypi/simple/ pip3 install openpyxl -i https://mirrors.aliyun.com/pypi/simple/ pip3 install sqlalchemy -i https://mirrors.aliyun.com/pypi/simple/ pip3 install statsmodels -i https://mirrors.aliyun.com/pypi/simple/ pip3 install patsy -i https://mirrors.aliyun.com/pypi/simple/ pip3 install numba -i https://mirrors.aliyun.com/pypi/simple/ pip3 install jason -i https://mirrors.aliyun.com/pypi/simple/ pip3 install openpyxl -i https://mirrors.aliyun.com/pypi/simple/ \u6e90\u7801\u7f16\u8bd1\u65b9\u6cd5 \u00b6 \u4e0b\u9762\u662f\u6e90\u7801\u7f16\u8bd1\u65b9\u5f0f\u81ea\u884c\u5b89\u88c5Python\u7684\u65b9\u6cd5\uff0c\u4ee53.9.6\u7248\u672c\u4e3a\u4f8b\u3002 \u5b98\u7f51\u4e0b\u8f7dpython3.9.6 \uff08 \u8fde\u63a5 \uff09 \u89e3\u538b\u5b89\u88c5\u5305 tar xvf Python-3.9.6.tgz \u5b89\u88c5\u8def\u5f84\u4e3a /opt/Python-3.9.6/ \uff0c\u9700\u8981\u628a\u5b89\u88c5\u8def\u5f84\u7684owner\u6539\u4e3a\u5f53\u524d\u7528\u6237\uff0c\u5426\u5219\u540e\u671fpython\u7f16\u8bd1\u4ee5\u53ca\u4f7f\u7528pip\u5b89\u88c5python\u5305\u4f1a\u62a5\u9519\u3002 chown -R james.wheel /opt/Python-3.9.6 \u5728\u5b89\u88c5\u524d\u7684\u4e00\u4e9b\u5efa\u8bae \u5728openSUSE\u4e2d\u628a\u5f00\u53d1\u5305\u90fd\u5b89\u88c5\u4e00\u4e0b\uff0c\u7279\u522b\u662fc\u548cc++\u7684\u5f00\u53d1\u5305\u3002\u8fd9\u4e9b\u90fd\u662fPython\u7f16\u8bd1\u7684\u4f9d\u8d56\u5305\u3002 \u5728openSUSE\u4e2d\u5b89\u88c5sqlite3. \u4f7f\u7528openSUSE\u81ea\u5e26\u7684openSSL\uff0c\u5982\u679c\u81ea\u884c\u7f16\u8bd1openSSL\uff0c\u5728\u7f16\u8bd1Python\u65f6\u4f1a\u9047\u5230\u4e00\u4e9b\u672a\u77e5\u95ee\u9898\u3002 \u7f16\u8bd1\u548c\u5b89\u88c5\uff1a cd /opt/Python-3.9.6 sudo ./configure --enable-optimizations --with-ensurepip = install sudo make sudo make test sudo make install \u4fee\u6539\u7cfb\u7edf\u9ed8\u8ba4Python\u7684\u914d\u7f6e\uff0c\u5c06python3\u6307\u5411\u65b0\u5b89\u88c5\u7684Python\u3002\u9700\u8981\u4fee\u6539\u7684\u8def\u5f84\u67092\u4e2a\uff0c /usr/bin/python3 \u548c /usr/local/bin/ \u5c06 /usr/bin/python3 \u91cd\u65b0\u6307\u5411\u65b0\u5b89\u88c5\u7684Python\u3002 sudo rm /usr/bin/python3 sudo ln -s /opt/Python-3.9.6/python /usr/bin/python3 \u68c0\u67e5 /usr/local/bin/ \u76ee\u5f55\u4e0b\u7684python\u6587\u4ef6\u662f\u5426\u6307\u5411\u65b0\u5b89\u88c5\u7684Pyton\u3002\u9ed8\u8ba4\u662f\u7f16\u8bd1\u5b89\u88c5\u5b8c\u6210\u540e\u5df2\u7ecf\u88ab\u4fee\u6539\u4e86\u3002 $ ls -l /usr/local/bin/python* lrwxrwxrwx 1 root root 9 Jul 25 02 :15 python3 -> python3.9 -rwxr-xr-x 1 root root 17645928 Jul 25 02 :14 python3.9 -rwxr-xr-x 1 root root 3087 Jul 25 02 :15 python3.9-config lrwxrwxrwx 1 root root 16 Jul 25 02 :15 python3-config -> python3.9-config \u9a8c\u8bc1python\u7684\u7248\u672c\u3002 $ python Python 2 .7.18 ( default, Mar 04 2021 , 23 :25:57 ) [ GCC ] on linux2 $ python3 Python 3 .9.6 ( default, Jul 25 2021 , 02 :13:27 ) [ GCC 7 .5.0 ] on linux \u6dfb\u52a0\u4e0b\u9762\u7684\u73af\u5883\u53d8\u91cf\u5230\u914d\u7f6e\u6587\u4ef6 /etc/profile.local \u3002 export PATH = /usr/local/bin:/home/ $USER /.local/bin: $PATH \u5e76\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u4f7f\u4e4b\u751f\u6548\u3002 source /etc/profile.local \u4e0b\u9762\u4fee\u6539pip\u7684\u914d\u7f6e\u3002 $ whereis pip pip: /usr/bin/pip /usr/bin/pip3.6 /usr/local/bin/pip3.9 \u901a\u8fc7\u4e0b\u9762\u53ef\u4ee5\u770b\u5230pip\u5b9e\u9645\u6307\u5411\u7684\u662f\u7cfb\u7edf\u9ed8\u8ba4\u76843.6\u7248\u672c\u3002 $ l /usr/bin/pip* lrwxrwxrwx 1 root root 21 Dec 4 2020 /usr/bin/pip -> /etc/alternatives/pip* -rwxr-xr-x 1 root root 367 Dec 4 2020 /usr/bin/pip3* -rwxr-xr-x 1 root root 371 Dec 4 2020 /usr/bin/pip3.6* -rwxr-xr-x 1 root root 10608 Jun 10 06 :15 /usr/bin/pipewire* -rwxr-xr-x 1 root root 720208 Jun 10 06 :15 /usr/bin/pipewire-media-session* james@lizard:/opt> l /etc/alternatives/pip* lrwxrwxrwx 1 root root 15 Jul 24 20 :24 /etc/alternatives/pip -> /usr/bin/pip3.6* \u68c0\u67e5\u4e00\u4e0b\u5f53\u524dpip\u5728alternative\u91cc\u9762\u7684\u8bbe\u7f6e\u3002 $ sudo update-alternatives --display pip pip - auto mode link best version is /usr/bin/pip3.6 link currently points to /usr/bin/pip3.6 link pip is /usr/bin/pip /usr/bin/pip3.6 - priority 36 \u5220\u9664\u8001\u7248\u672c\uff0c\u6dfb\u52a0\u65b0\u7248\u672c\u3002 $ sudo update-alternatives --remove pip /usr/bin/pip3.6 $ sudo update-alternatives --install /usr/bin/pip pip /usr/bin/pip3.9 100 update-alternatives: using /usr/bin/pip3.9 to provide /usr/bin/pip ( pip ) in auto mode","title":"Python\u5b89\u88c5"},{"location":"python/Foundation/ch00/#python","text":"","title":"Python\u5b89\u88c5"},{"location":"python/Foundation/ch00/#python_1","text":"\u8fd9\u91cc\u4f7f\u7528\u7cfb\u7edf\u81ea\u5e26\u7684Python\u73af\u5883\uff1a \u4e3b\u673a\uff1aVMWare\u865a\u62df\u673a \u64cd\u4f5c\u7cfb\u7edf(Guest)\uff1aopenSUSE 15.3 Python\u7248\u672c\uff1a3.6.15(openSUSE\u81ea\u5e26)","title":"Python\u73af\u5883"},{"location":"python/Foundation/ch00/#python_2","text":"$ python --version Python 2 .7.18 $ python3 --version Python 3 .6.15","title":"\u68c0\u67e5Python\u7248\u672c"},{"location":"python/Foundation/ch00/#pip","text":"$ pip3 install --upgrade pip $ pip --version pip 21 .3.1 from /home/james/.local/lib/python3.6/site-packages/pip ( python 3 .6 ) $ pip3 --version pip 21 .3.1 from /home/james/.local/lib/python3.6/site-packages/pip ( python 3 .6 )","title":"\u5347\u7ea7pip"},{"location":"python/Foundation/ch00/#pip_1","text":"https://mirrors.aliyun.com/pypi/simple/ https://pypi.tuna.tsinghua.edu.cn/simple/ http://pypi.doubanio.com/simple/ https://mirrors.cloud.tencent.com/pypi/simple/","title":"pip\u56fd\u5185\u6e90"},{"location":"python/Foundation/ch00/#python_3","text":"pip3 install jinja2 -i https://mirrors.aliyun.com/pypi/simple/ pip3 install Django -i https://mirrors.aliyun.com/pypi/simple/ pip3 install sqlite_utils -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pymongo -i https://mirrors.aliyun.com/pypi/simple/ pip3 install numpy -i https://mirrors.aliyun.com/pypi/simple/ pip3 install matplotlib -i https://mirrors.aliyun.com/pypi/simple/ pip3 install scikit-learn -i https://mirrors.aliyun.com/pypi/simple/ pip3 install xlrd -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pandas -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pydotplus -i https://mirrors.aliyun.com/pypi/simple/ pip3 install seaborn -i https://mirrors.aliyun.com/pypi/simple/ pip3 install selenium -i https://mirrors.aliyun.com/pypi/simple/ pip3 install mlxtend -i https://mirrors.aliyun.com/pypi/simple/ pip3 install pandas-datareader -i https://mirrors.aliyun.com/pypi/simple/ pip3 install lxml -i https://mirrors.aliyun.com/pypi/simple/ pip3 install beautifulsoup4 -i https://mirrors.aliyun.com/pypi/simple/ pip3 install html5lib -i https://mirrors.aliyun.com/pypi/simple/ pip3 install tables -i https://mirrors.aliyun.com/pypi/simple/ pip3 install openpyxl -i https://mirrors.aliyun.com/pypi/simple/ pip3 install sqlalchemy -i https://mirrors.aliyun.com/pypi/simple/ pip3 install statsmodels -i https://mirrors.aliyun.com/pypi/simple/ pip3 install patsy -i https://mirrors.aliyun.com/pypi/simple/ pip3 install numba -i https://mirrors.aliyun.com/pypi/simple/ pip3 install jason -i https://mirrors.aliyun.com/pypi/simple/ pip3 install openpyxl -i https://mirrors.aliyun.com/pypi/simple/","title":"\u5b89\u88c5Python\u5305(\u6307\u5b9a\u6e90)"},{"location":"python/Foundation/ch00/#_1","text":"\u4e0b\u9762\u662f\u6e90\u7801\u7f16\u8bd1\u65b9\u5f0f\u81ea\u884c\u5b89\u88c5Python\u7684\u65b9\u6cd5\uff0c\u4ee53.9.6\u7248\u672c\u4e3a\u4f8b\u3002 \u5b98\u7f51\u4e0b\u8f7dpython3.9.6 \uff08 \u8fde\u63a5 \uff09 \u89e3\u538b\u5b89\u88c5\u5305 tar xvf Python-3.9.6.tgz \u5b89\u88c5\u8def\u5f84\u4e3a /opt/Python-3.9.6/ \uff0c\u9700\u8981\u628a\u5b89\u88c5\u8def\u5f84\u7684owner\u6539\u4e3a\u5f53\u524d\u7528\u6237\uff0c\u5426\u5219\u540e\u671fpython\u7f16\u8bd1\u4ee5\u53ca\u4f7f\u7528pip\u5b89\u88c5python\u5305\u4f1a\u62a5\u9519\u3002 chown -R james.wheel /opt/Python-3.9.6 \u5728\u5b89\u88c5\u524d\u7684\u4e00\u4e9b\u5efa\u8bae \u5728openSUSE\u4e2d\u628a\u5f00\u53d1\u5305\u90fd\u5b89\u88c5\u4e00\u4e0b\uff0c\u7279\u522b\u662fc\u548cc++\u7684\u5f00\u53d1\u5305\u3002\u8fd9\u4e9b\u90fd\u662fPython\u7f16\u8bd1\u7684\u4f9d\u8d56\u5305\u3002 \u5728openSUSE\u4e2d\u5b89\u88c5sqlite3. \u4f7f\u7528openSUSE\u81ea\u5e26\u7684openSSL\uff0c\u5982\u679c\u81ea\u884c\u7f16\u8bd1openSSL\uff0c\u5728\u7f16\u8bd1Python\u65f6\u4f1a\u9047\u5230\u4e00\u4e9b\u672a\u77e5\u95ee\u9898\u3002 \u7f16\u8bd1\u548c\u5b89\u88c5\uff1a cd /opt/Python-3.9.6 sudo ./configure --enable-optimizations --with-ensurepip = install sudo make sudo make test sudo make install \u4fee\u6539\u7cfb\u7edf\u9ed8\u8ba4Python\u7684\u914d\u7f6e\uff0c\u5c06python3\u6307\u5411\u65b0\u5b89\u88c5\u7684Python\u3002\u9700\u8981\u4fee\u6539\u7684\u8def\u5f84\u67092\u4e2a\uff0c /usr/bin/python3 \u548c /usr/local/bin/ \u5c06 /usr/bin/python3 \u91cd\u65b0\u6307\u5411\u65b0\u5b89\u88c5\u7684Python\u3002 sudo rm /usr/bin/python3 sudo ln -s /opt/Python-3.9.6/python /usr/bin/python3 \u68c0\u67e5 /usr/local/bin/ \u76ee\u5f55\u4e0b\u7684python\u6587\u4ef6\u662f\u5426\u6307\u5411\u65b0\u5b89\u88c5\u7684Pyton\u3002\u9ed8\u8ba4\u662f\u7f16\u8bd1\u5b89\u88c5\u5b8c\u6210\u540e\u5df2\u7ecf\u88ab\u4fee\u6539\u4e86\u3002 $ ls -l /usr/local/bin/python* lrwxrwxrwx 1 root root 9 Jul 25 02 :15 python3 -> python3.9 -rwxr-xr-x 1 root root 17645928 Jul 25 02 :14 python3.9 -rwxr-xr-x 1 root root 3087 Jul 25 02 :15 python3.9-config lrwxrwxrwx 1 root root 16 Jul 25 02 :15 python3-config -> python3.9-config \u9a8c\u8bc1python\u7684\u7248\u672c\u3002 $ python Python 2 .7.18 ( default, Mar 04 2021 , 23 :25:57 ) [ GCC ] on linux2 $ python3 Python 3 .9.6 ( default, Jul 25 2021 , 02 :13:27 ) [ GCC 7 .5.0 ] on linux \u6dfb\u52a0\u4e0b\u9762\u7684\u73af\u5883\u53d8\u91cf\u5230\u914d\u7f6e\u6587\u4ef6 /etc/profile.local \u3002 export PATH = /usr/local/bin:/home/ $USER /.local/bin: $PATH \u5e76\u6267\u884c\u4e0b\u9762\u7684\u547d\u4ee4\u4f7f\u4e4b\u751f\u6548\u3002 source /etc/profile.local \u4e0b\u9762\u4fee\u6539pip\u7684\u914d\u7f6e\u3002 $ whereis pip pip: /usr/bin/pip /usr/bin/pip3.6 /usr/local/bin/pip3.9 \u901a\u8fc7\u4e0b\u9762\u53ef\u4ee5\u770b\u5230pip\u5b9e\u9645\u6307\u5411\u7684\u662f\u7cfb\u7edf\u9ed8\u8ba4\u76843.6\u7248\u672c\u3002 $ l /usr/bin/pip* lrwxrwxrwx 1 root root 21 Dec 4 2020 /usr/bin/pip -> /etc/alternatives/pip* -rwxr-xr-x 1 root root 367 Dec 4 2020 /usr/bin/pip3* -rwxr-xr-x 1 root root 371 Dec 4 2020 /usr/bin/pip3.6* -rwxr-xr-x 1 root root 10608 Jun 10 06 :15 /usr/bin/pipewire* -rwxr-xr-x 1 root root 720208 Jun 10 06 :15 /usr/bin/pipewire-media-session* james@lizard:/opt> l /etc/alternatives/pip* lrwxrwxrwx 1 root root 15 Jul 24 20 :24 /etc/alternatives/pip -> /usr/bin/pip3.6* \u68c0\u67e5\u4e00\u4e0b\u5f53\u524dpip\u5728alternative\u91cc\u9762\u7684\u8bbe\u7f6e\u3002 $ sudo update-alternatives --display pip pip - auto mode link best version is /usr/bin/pip3.6 link currently points to /usr/bin/pip3.6 link pip is /usr/bin/pip /usr/bin/pip3.6 - priority 36 \u5220\u9664\u8001\u7248\u672c\uff0c\u6dfb\u52a0\u65b0\u7248\u672c\u3002 $ sudo update-alternatives --remove pip /usr/bin/pip3.6 $ sudo update-alternatives --install /usr/bin/pip pip /usr/bin/pip3.9 100 update-alternatives: using /usr/bin/pip3.9 to provide /usr/bin/pip ( pip ) in auto mode","title":"\u6e90\u7801\u7f16\u8bd1\u65b9\u6cd5"},{"location":"python/Foundation/ch01/","text":"Python\u8bed\u8a00\u57fa\u7840 \u00b6 1. Python\u6570\u636e\u7c7b\u578b\uff086\u4e2a\uff09 \u00b6 6\u4e2aPython\u6570\u636e\u7c7b\u578b\uff1a \u6570\u503c\u578b\uff08number\uff09\uff1a\u8868\u793a\u6570\u636e\u7ec4\u6210\u4e3a\u6570\u5b57 \u6574\u578b\uff08int\uff09 \u5341\u8fdb\u5236 \u516b\u8fdb\u5236 \u5341\u516d\u8fdb\u5236 \u6d6e\u70b9\u578b\uff08float\uff09 \u5e03\u5c14\u578b\uff08bool\uff09 \u590d\u6570\u6027\uff08complex\uff09 \u5b57\u7b26\u578b\uff08string\uff09\uff1a\u8868\u793a\u6570\u636e\u7ec4\u6210\u662f\u5b57\u7b26 \u5217\u8868\uff08list\uff09\uff1a\u7528\u6765\u8868\u793a\u4e00\u7ec4\u6709\u5e8f\u5143\u7d20\uff0c\u540e\u671f\u6570\u636e\u53ef\u4ee5\u4fee\u6539 ['A','B','C'] \u5143\u7ec4\uff08tuple\uff09\uff1a\u7528\u6765\u8868\u793a\u4e00\u7ec4\u6709\u5e8f\u5143\u7d20\uff0c\u540e\u671f\u6570\u636e\u4e0d\u53ef\u4fee\u6539 ('A','B','C','1') \u96c6\u5408\uff08set\uff09\uff1a\u4e00\u7ec4\u6570\u636e\u65e0\u5e8f\u4e0d\u91cd\u590d\u5143\u7d20 set([1,2,3,4]) \u5b57\u5178\uff08dictionary\uff09\uff1a\u7528\u952e\u503c\u5bf9\u7684\u5f62\u5f0f\u4fdd\u5b58\u4e00\u7ec4\u5143\u7d20 {'A':7,'B':1,'C':9} \u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08Iterable\uff09\uff1a An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an iter() method or with a getitem() method that implements Sequence semantics. \u5e8f\u5217\uff08Sequence\uff09\uff1a An iterable which supports efficient element access using integer indices via the getitem() special method and defines a len() method that returns the length of the sequence. Some built-in sequence types are list, str, tuple, and bytes. Note that dict also supports getitem() and len(), but is considered a mapping rather than a sequence because the lookups use arbitrary immutable keys rather than integers. \u8fed\u4ee3\u5668\uff08Iterator\uff09\uff1a An object representing a stream of data. Repeated calls to the iterator\u2019s next() method (or passing it to the built-in function next()) return successive items in the stream. When no more data are available a StopIteration exception is raised instead. At this point, the iterator object is exhausted and any further calls to its next() method just raise StopIteration again. Iterators are required to have an iter() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a list) produces a fresh new iterator each time you pass it to the iter() function or use it in a for loop. Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container. \u53ef\u53d8\u6570\u636e\uff08immutable\uff09 \u5217\u8868\uff08list\uff09 \u5b57\u5178\uff08dictionary\uff09 \u96c6\u5408\uff08set\uff09\u3002 \u4e0d\u53ef\u53d8\u6570\u636e\uff08immutable\uff09 \u6570\u5b57\uff08number\uff09 \u5b57\u7b26\uff08string\uff09 \u5143\u7ec4\uff08tuple\uff09 \u53ef\u8fed\u4ee3\uff08iterable\uff09 \u5b57\u7b26\uff08string\uff09 \u5143\u7ec4\uff08tuple\uff09 \u5217\u8868\uff08list\uff09 \u5b57\u5178\uff08dictionary\uff09 \u96c6\u5408\uff08set\uff09 \u5e8f\u5217 \u6709\u5e8f\u5e8f\u5217\uff1a\u5b57\u7b26\uff08string\uff09\uff0c\u5143\u7ec4\uff08tuple\uff09\uff0c\u5217\u8868\uff08list\uff09 \u65e0\u5e8f\u5e8f\u5217\uff1a\u5b57\u5178\uff08dictionary\uff09\uff0c\u96c6\u5408\uff08set\uff09 Python\u5e8f\u5217\u7c7b\u578b\u6700\u5e38\u89c1\u7684\u5206\u7c7b\u5c31\u662f\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u5e8f\u5217\u3002\u4f46\u53e6\u5916\u4e00\u79cd\u5206\u7c7b\u65b9\u5f0f\u4e5f\u5f88\u6709\u7528\uff0c\u90a3\u5c31\u662f\u628a\u5b83\u4eec\u5206\u4e3a**\u6241\u5e73\u5e8f\u5217**\u548c**\u5bb9\u5668\u5e8f\u5217**\u3002\u524d\u8005\u7684\u4f53\u79ef\u66f4\u5c0f\u3001\u901f\u5ea6\u66f4\u5feb\u800c\u4e14\u7528\u8d77\u6765\u66f4\u7b80\u5355\uff0c\u4f46\u662f\u5b83\u53ea\u80fd\u4fdd\u5b58\u4e00\u4e9b\u539f\u5b50\u6027\u7684\u6570\u636e\uff0c\u6bd4\u5982\u6570\u5b57\u3001\u5b57\u7b26\u548c\u5b57\u8282\u3002\u5bb9\u5668\u5e8f\u5217\u5219\u6bd4\u8f83\u7075\u6d3b\uff0c\u4f46\u662f\u5f53\u5bb9\u5668\u5e8f\u5217\u9047\u5230\u53ef\u53d8\u5bf9\u8c61\u65f6\uff0c\u5c31\u9700\u8981\u683c\u5916\u5c0f\u5fc3\uff0c\u56e0\u4e3a\u8fd9\u79cd\u7ec4\u5408\u65f6\u5e38\u4f1a\u51fa\u73b0\u4e00\u4e9b\u201c\u610f\u5916\u201d\uff0c\u7279\u522b\u662f\u5e26\u5d4c\u5957\u7684\u6570\u636e\u7ed3\u6784\u51fa\u73b0\u65f6\uff0c\u66f4\u9700\u8981\u9a8c\u8bc1\u4ee3\u7801\u7684\u6b63\u786e\u6027\u3002 Python\u4e2d\u7684\u53d8\u91cf\u3001\u5e38\u91cf\u548c\u5b57\u9762\u91cf \u53d8\u91cf \u53d8\u91cf\u662f\u7528\u4e8e\u5728\u5185\u5b58\u4e2d\u5b58\u50a8\u6570\u636e\u7684\u547d\u540d\u4f4d\u7f6e\u3002\u53ef\u4ee5\u5c06\u53d8\u91cf\u89c6\u4e3a\u4fdd\u5b58\u6570\u636e\u7684\u5bb9\u5668\uff0c\u8fd9\u4e9b\u6570\u636e\u53ef\u4ee5\u5728\u540e\u9762\u7a0b\u5e8f\u4e2d\u8fdb\u884c\u66f4\u6539\u3002\u4f8b\u5982\uff1a number = 10 \u3002\u4ece\u4f8b\u5b50\u4e2d\u53ef\u4ee5\u770b\u5230\uff0cPython\u4f7f\u7528\u8d4b\u503c\u8fd0\u7b97\u7b26 = \u4e3a\u53d8\u91cf\u8d4b\u503c\u3002 \u5e38\u91cf \u5e38\u91cf\u4e5f\u662f\u4e00\u79cd\u53d8\u91cf\uff0c\u53ea\u662f\u5176\u503c\u4e00\u65e6\u8d4b\u4e88\u540e\u65e0\u6cd5\u66f4\u6539\u3002\u53ef\u4ee5\u5c06\u5e38\u91cf\u89c6\u4e3a\u4fdd\u5b58\u4e86\u4ee5\u540e\u65e0\u6cd5\u66f4\u6539\u7684\u4fe1\u606f\u7684\u5bb9\u5668\u3002 \u5728Python\u4e2d\uff0c\u5e38\u91cf\u901a\u5e38\u662f\u5728\u6a21\u5757\u4e2d\u58f0\u660e\u548c\u5206\u914d\u7684\u3002\u5728\u8fd9\u91cc\uff0c\u6a21\u5757\u662f\u4e00\u4e2a\u5305\u542b\u53d8\u91cf\uff0c\u51fd\u6570\u7b49\u7684\u65b0\u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u88ab\u5bfc\u5165\u5230\u4e3b\u6587\u4ef6\u4e2d\u3002\u5728\u6a21\u5757\u5185\u90e8\uff0c\u7528\u6240\u6709\u5927\u5199\u5b57\u6bcd\u5199\u7684\u5e38\u91cf\u548c\u4e0b\u5212\u7ebf\u5c06\u5355\u8bcd\u5206\u5f00\u3002\u5b9e\u9645\u4e0a\uff0c\u6211\u4eec\u4e0d\u5728Python\u4e2d\u4f7f\u7528\u5e38\u91cf\u3002\u7528\u5927\u5199\u5b57\u6bcd\u547d\u540d\u5b83\u4eec\u662f\u4e00\u79cd\u5c06\u5176\u4e0e\u666e\u901a\u53d8\u91cf\u5206\u5f00\u7684\u4e00\u79cd\u7ea6\u5b9a\uff0c\u4f46\u662f\uff0c\u5b9e\u9645\u4e0a\u5e76\u4e0d\u80fd\u963b\u6b62\u91cd\u65b0\u5206\u914d\u3002 \u5b57\u9762\u91cf\uff08literal\uff09 \u5b57\u9762\u91cf\u662f\u4ee5\u53d8\u91cf\u6216\u5e38\u91cf\u7ed9\u51fa\u7684\u539f\u59cb\u6570\u636e\uff08\u5176\u5b9e\u5c31\u662f\u6307\u53d8\u91cf\u7684\u5e38\u6570\u503c\uff0c\u5b57\u9762\u4e0a\u6240\u770b\u5230\u7684\u503c\uff09\u3002\u5728Python\u4e2d\u5b57\u9762\u91cf\u7c7b\u578b\u5982\u4e0b\uff1a \u6570\u5b57\u5b57\u9762\u91cf\u3002\u6570\u5b57\u5b57\u9762\u91cf\u662f\u4e0d\u53ef\u53d8\u7684\uff08\u4e0d\u53ef\u66f4\u6539\uff09\u3002\u6570\u5b57\u5b57\u9762\u91cf\u53ef\u4ee5\u5c5e\u4e8e3\u79cd\u4e0d\u540c\u7684\u6570\u503c\u7c7b\u578b\uff1aInteger\uff0cFloat \u548c Complex\u3002\u4f8b\u5982\uff1a float_1 = 10.5 \u662f\u5c5e\u4e8eFloat\u5b57\u9762\u91cf\u3002 \u5b57\u7b26\u4e32\u5b57\u9762\u91cf\u662f\u7531\u5f15\u53f7\u62ec\u8d77\u6765\u7684\u4e00\u7cfb\u5217\u5b57\u7b26\u3002\u6211\u4eec\u53ef\u4ee5\u5bf9\u5b57\u7b26\u4e32\u4f7f\u7528\u5355\u5f15\u53f7\uff0c\u53cc\u5f15\u53f7 \u6216 \u4e09\u5f15\u53f7\u3002\u5e76\u4e14\uff0c\u5b57\u7b26\u5b57\u9762\u91cf\u662f\u7528\u5355\u5f15\u53f7\u6216\u53cc\u5f15\u53f7\u5f15\u8d77\u6765\u7684\u5355\u4e2a\u5b57\u7b26\u3002\u4f8b\u5982\uff1a strings = \"This is Python\" \u3002 \u5e03\u5c14\u5b57\u9762\u91cf\u3002\u5e03\u5c14\u5b57\u9762\u91cf\u53ef\u4ee5\u5177\u6709\u4e24\u4e2a\u503c\u4e2d\u7684\u4efb\u4f55\u4e00\u4e2a\uff1a True \u6216 False \u3002\u4f8b\u5982\uff1a a = True + 4 \u3002 \u7279\u6b8a\u5b57\u9762\u91cf\u3002Python\u5305\u542b\u4e00\u4e2a\u7279\u6b8a\u5b57\u9762\u91cf\uff0c\u5373 None \u3002 \u5b57\u9762\u91cf\u96c6\u3002\u6709\u56db\u79cd\u4e0d\u540c\u7684\u5b57\u9762\u91cf\u96c6\u5408\uff1a\u5217\u8868\u5b57\u9762\u91cf\uff0c\u5143\u7ec4\u5b57\u9762\u91cf\uff0c\u5b57\u5178\u5b57\u9762\u91cf \u548c \u96c6\u5408\u5b57\u9762\u91cf\u3002 1.1 \u6570\u503c\u578b\uff08number\uff09 \u00b6 \u4f8b\u5b50\uff1a a , b , c , d = 20 , 5.5 , True , 4 + 3 j print ( a , b , c , d ) # 20 5.5 True (4+3j) print ( type ( a ), type ( b ), type ( c ), type ( d )) # Python\u4e5f\u53ef\u4ee5\u8fd9\u6837\u8d4b\u503c\uff1a a = b = c = d = 1 print ( a , b , c , d ) # 1 1 1 1 \u8fdb\u5236\u8f6c\u6362\uff1a a = - 15 print ( f ' { a } \u5bf9\u5e94\u7684\u5341\u8fdb\u5236\u662f { a } , \u4e8c\u8fdb\u5236\u662f { a : b } , \u516b\u8fdb\u5236\u662f { a : o } , \u5341\u516d\u8fdb\u5236\u662f { a : x } ' ) 1.2 \u5b57\u7b26\u578b\uff08string\uff09 \u00b6 \u5355\u5f15\u53f7\uff1a\u5185\u5bb9\u4e2d\u5305\u542b\u5927\u91cf\u53cc\u5f15\u53f7 \u53cc\u5f15\u53f7\uff1a\u5185\u5bb9\u4e2d\u5305\u542b\u5927\u91cf\u5355\u5f15\u53f7 \u4e09\u5f15\u53f7\uff1a\u5185\u5bb9\u4e2d\u540c\u65f6\u5305\u542b\u5355\u53cc\u5f15\u53f7\uff0c\u4e09\u4e2a\u5355\u5f15\u53f7\u6bd4\u8f83\u597d\u3002 a = 'string is \"special\"' b = \"string's value\" c = '''string's value is \"special\"''' d = \"\"\"string's context \"\"\" \u5b57\u7b26\u4e32\u5e38\u7528\u65b9\u6cd5 \u00b6 \u5b57\u7b26\u4e32\u5207\u7247 s = 'Python is very good' print ( s [ 2 : 4 ]) # th print ( s [ 5 ]) # n print ( s [ - 1 ]) # d print ( s [ - 3 : - 1 ]) # oo # \u975e\u8fed\u4ee3\u578b\uff0c\u4e0d\u53ef\u4fee\u6539 s [ 3 ] = 'b' # Traceback (most recent call last): # File \"\", line 1, in # TypeError: 'str' object does not support item assignment \u5b57\u7b26\u4e32\u5408\u5e76 print ( s + '!!!' ) # Python is very good!!! replace( a,b \u5c06\u5b57\u7b26\u4e32\u4e2d\u7684 a \u66ff\u6362\u6210 b print ( s . replace ( 'is' , 'we' )) # Python we very good find(str) : \u8fd4\u56de str \u51fa\u73b0\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0c\u5982\u679c\u627e\u4e0d\u5230\u8be5\u503c\uff0c\u5219 find() \u65b9\u6cd5\u5c06\u8fd4\u56de -1\u3002 print ( s . find ( 'a' )) # -1 print ( s . find ( 's' )) # 8 str.index(a): \u67e5\u627e\u6307\u5b9a\u503c\u7684\u9996\u6b21\u51fa\u73b0\u3002\u5982\u679c\u627e\u4e0d\u5230\u8be5\u503c\uff0cindex() \u65b9\u6cd5\u5c06\u5f15\u53d1\u5f02\u5e38\u3002 print ( s . index ( 's' )) # 8 print ( s . index ( 'a' )) # Traceback (most recent call last): # File \"\", line 1, in # ValueError: substring not found str.count(a): \u7edf\u8ba1\u5b57\u7b26\u4e32\u4e2d a \u51fa\u73b0\u7684\u6b21\u6570 print ( s . count ( 'a' )) # 0 print ( s . count ( 'o' )) # 3 split: \u5bf9\u5b57\u7b26\u4e32\u8fdb\u884c\u5206\u5272\u3002\u5982\u679c\u53c2\u6570 num \u6709\u6307\u5b9a\u503c\uff0c\u5219\u5206\u9694 num+1 \u4e2a\u5b50\u5b57\u7b26\u4e32\u3002 # \u6309\u7a7a\u683c\u5206\u5272 print ( s . split ( ' ' )) # ['Python', 'is', 'very', 'good'] # \u6309\u7a7a\u683c\u5206\u5272\u62102\u4e2a\u5b50\u5b57\u7b26\u4e32 print ( s . split ( ' ' , 1 )) # ['Python', 'is very good'] strip: \u79fb\u9664\u5b57\u7b26\u4e32\u9996\u5c3e\u6307\u5b9a\u7684\u5b57\u7b26 \u9ed8\u8ba4\u4e3a\u7a7a\u683c\u3002\u8be5\u65b9\u6cd5\u53ea\u80fd\u5220\u9664\u5f00\u5934\u6216\u662f\u7ed3\u5c3e\u7684\u5b57\u7b26\uff0c\u4e0d\u80fd\u5220\u9664\u4e2d\u95f4\u90e8\u5206\u7684\u5b57\u7b26\u3002 print ( s ) # Python is very good # \u79fb\u9664\u672b\u5c3e\u5b57\u7b26d print ( s . strip ( 'd' )) # Python is very goo endswith (str): \u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u4ee5 str \u7ed3\u5c3e print ( s . endswith ( 'd' )) # True print ( s . endswith ( 'a' )) # False startswith (str): \u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u4ee5 str \u5f00\u5934 print ( s . startswith ( 'p' )) # False print ( s . startswith ( 'P' )) # True isdigit \uff1a\u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u5168\u4e3a\u6570\u5b57 d = '+86-123' print ( d . isdigit ()) # False d = '86123' print ( d . isdigit ()) # True isalpha \uff1a\u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u5168\u4e3a\u5b57\u6bcd b = 'Ab?' print ( b . isalpha ()) # False c = 'Ab' print () c . isalpha () # True \u8f6c\u4e49\u5b57\u7b26 \u00b6 \u4f7f\u7528\u53cd\u659c\u6760\\\u8868\u793a\u8f6c\u4e49\u5b57\u7b26\u3002\u53cd\u659c\u6760\u524d\u9762\u52a0r\u4ee3\u8868\u539f\u59cb\u5b57\u7b26\u3002 a = 'str \\n ing' print ( a ) # str # ing a = r 'str\\ning' print ( a ) # str\\ning \u8f6c\u4e49\u7b26 \u63cf\u8ff0 \\\u5728\u884c\u5c3e \u7eed\u884c\u7b26 \\\\ \u53cd\u659c\u6760\u7b26\u53f7\\ \\' \u5355\u5f15\u53f7 \\b \u9000\u683c(Backspace) \\000 \u7a7a \\n \u6362\u884c \\v \u7eb5\u5411\u5236\u8868\u7b26 \\t \u6a2a\u5411\u5236\u8868\u7b26 \\r \u56de\u8f66\uff0c\u5c06 \\r \u540e\u9762\u7684\u5185\u5bb9\u79fb\u5230\u5b57\u7b26\u4e32\u5f00\u5934\uff0c\u5e76\u9010\u4e00\u66ff\u6362\u5f00\u5934\u90e8\u5206\u7684\u5b57\u7b26\uff0c\u76f4\u81f3\u5c06 \\r \u540e\u9762\u7684\u5185\u5bb9\u5b8c\u5168\u66ff\u6362\u5b8c\u6210\u3002 \\yyy \u516b\u8fdb\u5236\u6570\uff0cy \u4ee3\u8868 0~7 \u7684\u5b57\u7b26 \\xyy \u5341\u516d\u8fdb\u5236\u6570\uff0c\u4ee5 \\x \u5f00\u5934\uff0cy \u4ee3\u8868\u7684\u5b57\u7b26 \u53ef\u8fed\u4ee3\u6027 \u00b6 \u5b57\u7b26\u4e32\u662f\u53ef\u8fed\u4ee3\u7684\u3002\u7d22\u5f15\u503c\u4ece0\u5f00\u59cb\uff0c-1\u4ee3\u8868\u4ece\u672b\u5c3e\u5f00\u59cb\u3002\u7d22\u5f15\u533a\u95f4\u662f\u5de6\u95ed\u53f3\u5f00\u3002 a = 'string is \"special\"' print ( a [ 2 : 4 ]) 'ri' print ( a [ - 4 : - 1 ]) # ial f-string \u00b6 f-string\u662fPython3.6\u63a8\u51fa\u7684\u65b0\u529f\u80fd\u3002\u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5bf9\u6bd4\u4f20\u7edf\u8868\u793a\u65b9\u6cd5\u548cf-string\u7684\u65b9\u6cd5\u3002 age = 32 name = 'Tom' fstring = f 'My name is { name } and I am { age } years old.' print ( fstring ) # My name is Tom and I am 32 years old. \u5728f-string\u4e2d\u4f7f\u7528\u8868\u8fbe\u5f0f\u3002 height = 2 base = 3 fstring = f 'The area of the triangle is { base * height / 2 } .' print ( fstring ) # The area of the triangle is 3.0. \u901a\u8fc7f-string\u5bf9\u5b57\u5178\u8fdb\u884c\u64cd\u4f5c\u3002 person1 = { 'name' : 'Tom' , 'age' : 20 , 'gender' : 'male' } person2 = { 'name' : 'Jerry' , 'age' : 20 , 'gender' : 'female' } # \u8bfb\u53d6\u5b57\u5178 fstring = f ' { person1 . get ( \"name\" ) } is { person1 . get ( \"age\" ) } and is { person1 . get ( \"ender\" ) } ' print ( fstring ) # Tom is 20 and is None # \u904d\u5386\u5b57\u5178 people = [ person1 , person2 ] for person in people : fstring = f ' { person . get ( \"name\" ) } is { person . get ( \"age\" ) } and is { person . get ( \"ender\" ) } ' print ( fstring ) # Tom is 20 and is None # Jerry is 20 and is None \u5728f-string\u4e2d\u4f7f\u7528\u6761\u4ef6\u3002 person1 = { 'name' : 'Tom' , 'age' : 20 , 'gender' : 'male' } person2 = { 'name' : 'Jerry' , 'age' : 20 , 'gender' : 'female' } people = [ person1 , person2 ] for person in people : fstring = f ' { \"She\" if person . get ( \"gender\" ) == \"female\" else \"He\" } is watching TV.' print ( fstring ) # He is watching TV. # She is watching TV. \u4f7f\u7528f-string\u683c\u5f0f\u5316\u8f93\u51fa\u3002 \u5de6\u5bf9\u9f50\uff1a< \u53f3\u5bf9\u9f50\uff1a> \u5c45\u4e2d\u5bf9\u9f50\uff1a^ print ( f ' { \"apple\" : >30 } ' ) print ( f ' { \"apple\" : ^30 } ' ) print ( f ' { \"apple\" : <30 } ' ) # apple # apple # apple \u4f7f\u7528f-string\u683c\u5f0f\u5316\u6570\u5b57\u3002 number = 0.9124325345 # \u767e\u5206\u6bd4 fstring = f 'Percentage format for number with two decimal places: { number : .2% } ' print ( fstring ) # Percentage format for number with two decimal places: 91.24% # \u4fdd\u7559\u5c0f\u6570\u70b9\u540e3\u4f4d fstring = f 'Fixed point format for number with three decimal places: { number : .3f } ' print ( fstring ) # Fixed point format for number with three decimal places: 0.912 # \u79d1\u5b66\u8ba1\u6570\u6cd5\u8868\u793a fstring = f 'Exponent format for number: { number : e } ' print ( fstring ) # Exponent format for number: 9.124325e-01 # \u5e26\u8d27\u5e01\u7b26\u53f7 number = 123456.78921 fstring = f 'Currency format for number with two decimal places: $ { number : .2f } ' print ( fstring ) # Currency format for number with two decimal places: $123456.79 # \u5e26\u8d27\u5e01\u7b26\u53f7\u548c\u5343\u5206\u4f4d number = 123456.78921 fstring = f 'Currency format for number with two decimal places and comma seperators: $ { number : ,.2f } ' print ( fstring ) # Currency format for number with two decimal places and comma seperators: $123,456.79 # \u8f93\u51fa\u6570\u503c\u5e26\u6b63\u8d1f\u7b26\u5408 numbers = [ 1 , - 3 , 5 ] for number in numbers : fstring = f 'The number is { number : + } ' print ( fstring ) # The number is +1 # The number is -3 # The number is +5 # Debug\u8c03\u8bd5 number = 2 print ( f ' { number = } ' ) # number = 2 1.3 \u5217\u8868\uff08list\uff09 \u00b6 \u5217\u8868\u662f Python \u5185\u7f6e\u7684\u4e00\u79cd\u6570\u636e\u7ed3\u6784\uff0c\u662f\u4e00\u79cd\u6709\u5e8f\u7684\u96c6\u5408\uff0c\u7528\u6765\u5b58\u50a8\u4e00\u8fde\u4e32\u5143\u7d20\u7684\u5bb9\u5668\u3002\u5217\u8868\u4e2d\u5143\u7d20\u7c7b\u578b\u53ef\u4ee5\u4e0d\u76f8\u540c\uff0c\u5b83\u652f\u6301\u6570\u5b57\u3001\u5b57\u7b26\u4e32\u7b49\u3002 \u5217\u8868\u7684\u6bcf\u4e2a\u503c\u90fd\u6709\u5bf9\u5e94\u7684\u7d22\u5f15\u503c\uff0c\u7d22\u5f15\u503c\u4ece0\u5f00\u59cb\u3002 \u5217\u8868\u5207\u7247\uff1a \u4f7f\u7528\u5207\u7247\u7b26\u53f7\u53ef\u4ee5\u5bf9\u5927\u591a\u6570\u5e8f\u5217\u7c7b\u578b\u9009\u53d6\u5176\u5b50\u96c6\u3002 \u8d77\u59cb\u4f4d\u7f6estart\u7684\u7d22\u5f15\u662f\u5305\u542b\u7684\uff0c\u800c\u7ed3\u675f\u4f4d\u7f6estop\u7684\u7d22\u5f15\u5e76\u4e0d\u5305\u542b\uff08\u5de6\u95ed\u53f3\u5f00\uff09\u3002 \u6b65\u8fdb\u503cstep\u53ef\u4ee5\u5728\u7b2c\u4e8c\u4e2a\u5192\u53f7\u540e\u9762\u4f7f\u7528\uff0c\u610f\u601d\u662f\u6bcf\u9694\u591a\u5c11\u4e2a\u6570\u53d6\u4e00\u4e2a\u503c \u3002 color = [ 'red' , 'green' , 'blue' , 'yellow' , 'white' , 'black' ] # \u4ece0\u5f00\u59cb\u7edf\u8ba1\uff0c\u8bfb\u53d6\u7b2c1\uff0c2\u4f4d print ( color [ 1 : 3 ]) # ['green', 'blue'] # \u4ece0\u5f00\u59cb\u7edf\u8ba1\uff0c\u8bfb\u53d6\u4ece\u7b2c1\u4f4d\u5230\u5012\u6570\u7b2c3\u4f4d print ( color [ 1 : - 2 ]) # ['green', 'blue', 'yellow'] # \u4ece0\u5f00\u59cb\u7edf\u8ba1\uff0c\u8bfb\u53d6\u4ece\u5012\u6570\u7b2c4\u4f4d\u5230\u5012\u6570\u7b2c3\u4f4d print ( color [ - 4 : - 2 ]) # ['blue', 'yellow'] # \u5982\u679c\u5199\u6210\u4e0b\u9762\u8fd9\u6837\uff0c\u5219\u65e0\u8f93\u51fa\u3002 print ( color [ - 2 : - 4 ]) # [] print ( color [:: 2 ]) # ['red', 'blue', 'white'] \u5bf9\u4e8e\u7c7b\u4f3c\u4e0b\u9762 invoice \u683c\u5f0f\u7684\u7eaf\u6587\u672c\u89e3\u6790\uff0c\u4f7f\u7528\u6709\u540d\u5b57\u7684\u5207\u7247\u6bd4\u7528\u4e0a\u9762\u6240\u5217\u4e3e\u7684\u786c\u7f16\u7801\u7684\u6570\u5b57\u533a\u95f4\u8981\u65b9\u4fbf\u5f97\u591a\u3002 invoice = \"\"\" 0 6 40 52 55 1909 Primoroni PiBrella $17.50 3 $52.50 1489 6mm Tactile Switch x20 $4.19 2 $9.90 1510 Panavise JR.-PV-201 $28.00 1 $28.00 1601 PiTFT Mini Kit 320x240 $34.95 1 $34.95 \"\"\" SKU = slice ( 0 , 6 ) DESCRIPTION = slice ( 6 , 40 ) UNIT_PRICE = slice ( 40 , 52 ) QUANTITY = slice ( 52 , 55 ) ITEM_TOTAL = slice ( 55 , None ) line_items = invoice . split ( ' \\n ' )[ 2 :] # \u6309\u4e0a\u9762invoice\u7684\u683c\u5f0f\uff0c\u7b2c0\u548c1\u884c\u820d\u5f03 for item in line_items : print ( item [ UNIT_PRICE ], item [ DESCRIPTION ]) # $17.50 Primoroni PiBrella # $4.19 6mm Tactile Switch x20 # $28.00 Panavise JR.-PV-201 # $34.95 PiTFT Mini Kit 320x240 Python\u5185\u7f6e\u7684\u5e8f\u5217\u7c7b\u578b\u90fd\u662f\u4e00\u7ef4\u7684\uff0c\u56e0\u6b64\u5b83\u4eec\u53ea\u652f\u6301\u5355\u4e00\u7684\u7d22\u5f15\uff0c\u6210\u5bf9\u51fa\u73b0\u7684\u7d22\u5f15\u662f\u6ca1\u6709\u7528\u7684\u3002 **\u7701\u7565\uff08ellipsis\uff09**\u7684\u6b63\u786e\u4e66\u5199\u65b9\u6cd5\u662f\u4e09\u4e2a\u82f1\u8bed\u53e5\u53f7\uff08...\uff09\uff0c\u800c\u4e0d\u662fUnicdoe\u7801\u4f4dU+2026\u8868\u793a\u7684\u534a\u4e2a\u7701\u7565\u53f7\uff08...\uff09\u3002 \u7701\u7565\u5728Python\u89e3\u6790\u5668\u773c\u91cc\u662f\u4e00\u4e2a\u7b26\u53f7\uff0c\u800c\u5b9e\u9645\u4e0a\u5b83\u662f Ellipsis \u5bf9\u8c61\u7684\u522b\u540d\uff0c\u800c Ellipsis \u5bf9\u8c61\u53c8\u662f ellipsis \u7c7b\u7684\u5355\u4e00\u5b9e\u4f8b\u3002 \u5b83\u53ef\u4ee5\u5f53\u4f5c\u5207\u7247\u89c4\u8303\u7684\u4e00\u90e8\u5206\uff0c\u4e5f\u53ef\u4ee5\u7528\u5728\u51fd\u6570\u7684\u53c2\u6570\u6e05\u5355\u4e2d\uff0c\u6bd4\u5982 f(a, ..., z) \uff0c\u6216 a[i:...] \u3002 \u5728NumPy\u4e2d\uff0c ... \u7528\u4f5c\u591a\u7ef4\u6570\u7ec4\u5207\u7247\u7684\u5feb\u6377\u65b9\u5f0f\u3002\u5982\u679c `x\u662f\u56db\u7ef4\u6570\u7ec4\uff0c\u90a3\u4e48 x[i, ...] \u5c31\u662f x[i, :, :, :]`\u7684\u7f29\u5199\u3002\u5982\u679c\u60f3\u4e86\u89e3\u66f4\u591a\uff0c\u8bf7\u53c2\u89c1\u201cTentative NumPy Tutorial\u201d\u3002 \u5217\u8868\u5e38\u7528\u65b9\u6cd5 \u65b9\u6cd5\u540d\u79f0 \u4f5c\u7528 a.index() \u8fd4\u56dea\u4e2d\u9996\u4e2a\u5339\u914d\u9879\u7684\u4f4d\u7f6e a.pop() \u5220\u9664\u6307\u5b9a\u4f4d\u7f6e\u7684\u5143\u7d20 a.insert() \u5411\u6307\u5b9a\u4f4d\u7f6e\u63d2\u5165\u5143\u7d20 a.reverse() \u53cd\u5411\u6392\u5e8f a.append() \u5411\u672b\u5c3e\u6dfb\u52a0\u5143\u7d20 a.sort() \u5bf9\u5217\u8868\u8fdb\u884c\u6392\u5e8f a.remove() \u5220\u9664\u9996\u4e2a\u5339\u914d\u9879\u7684\u5143\u7d20 a.extend() \u5c06\u4e00\u4e2a\u5217\u8868\u6269\u5c55\u81f3\u53e6\u4e00\u4e2a\u5217\u8868 a.count() \u7edf\u8ba1\u67d0\u4e2a\u5143\u7d20\u51fa\u73b0\u7684\u6b21\u6570 \u521b\u5efa\u5217\u8868list a = [ 1 , 2 , 3 , 4 , 5 ] print ( a ) # [1, 2, 3, 4, 5] b = list ( '12345' ) print ( b ) # ['1', '2', '3', '4', '5'] c = list ( 12345 ) # Traceback (most recent call last): # File \"\", line 1, in # TypeError: 'int' object is not iterable \u5217\u8868\u5207\u7247\uff08\u4ece0\u5f00\u59cb\uff0c\u5de6\u95ed\u53f3\u5f00\uff09\uff1a print ( a [ 2 : 3 ]) # [3] print ( a [: 3 ]) # [1, 2, 3] print ( a [:: - 1 ]) # \u5012\u5e8f # [5, 4, 3, 2, 1] print ( a [::]) # [1, 2, 3, 4, 5] print ( a [:: 1 ]) [ 1 , 2 , 3 , 4 , 5 ] \u5217\u8868\u662f\u53ef\u4fee\u6539\u7684\uff1a print ( a [ 1 ]) # 2 a [ 1 ] = 'one' print ( a ) @ [ 1 , 'one' , 3 , 4 , 5 ] \u5217\u8868\u8ffd\u52a0\u548c\u63d2\u5165\u3002insert\u4e0eappend\u76f8\u6bd4\uff0c\u8ba1\u7b97\u4ee3\u4ef7\u66f4\u9ad8\u3002\u56e0\u4e3a\u5b50\u5e8f\u5217\u5143\u7d20\u9700\u8981\u5728\u5185\u90e8\u79fb\u52a8\u4e3a\u65b0\u5143\u7d20\u63d0\u4f9b\u7a7a\u95f4\u3002 a . append ( 6 ) # \u6ce8\u610f\uff0c\u76f4\u63a5\u4fee\u6539\u539f\u5217\u8868\uff0c\u4e0d\u662f\u521b\u5efa\u526f\u672c\u3002 print ( a ) # [1, 'one', 3, 4, 5, 6] a . extend ([ 7 , 8 , 9 ]) print ( a ) # [1, 'one', 3, 4, 5, 6, 7, 8, 9] a . insert ( 0 , 'Italy' ) print ( a ) # ['Italy', 1, 3, 5, 6, 7, 8] \u5217\u8868\u5220\u9664\u5143\u7d20\uff0c\u9ed8\u8ba4\u5220\u9664\u6700\u540e\u4e00\u4e2a\u3002insert\u7684\u53cd\u64cd\u4f5c\u662fpop\u3002 a . pop () # 9 print ( a ) # [1, 'one', 3, 4, 5, 6, 7, 8] a . pop ( 3 ) # 4 print ( a ) # [1, 'one', 3, 5, 6, 7, 8] \u5220\u9664\u5217\u8868\u4e2d\u67d0\u4e2a\u5143\u7d20\u3002 print ( a [ 1 ]) # one del a [ 1 ] print ( a ) [ 1 , 3 , 5 , 6 , 7 , 8 ] \u5220\u9664\u5217\u8868\u4e2d\u67d0\u4e2a\u5143\u7d20\u3002remove\u65b9\u6cd5\u4f1a\u5b9a\u4f4d\u7b2c\u4e00\u4e2a\u7b26\u5408\u8981\u6c42\u7684\u503c\u5e76\u79fb\u9664 a . remove ( 'Italy' ) print ( a ) # [1, 3, 5, 6, 7, 8] \u7edf\u8ba1\u67d0\u4e2a\u5143\u7d20\u51fa\u73b0\u7684\u6b21\u6570\u3002 print ( a . count ( 1 )) # 1 \u8fd4\u56de\u5217\u8868\u4e2d\u5339\u914d\u9879\u7684\u7d22\u5f15\u4f4d\u7f6e\u3002\u5339\u914d\u4e0d\u5230\u629b\u51fa\u5f02\u5e38\u3002 print ( a . index ( 2 )) # Traceback (most recent call last): # File \"\", line 1, in # ValueError: 2 is not in list print ( a . index ( 3 )) # 1 \u5224\u65ad\u5143\u7d20\u662f\u5426\u5b58\u5728\u4e8e\u5217\u8868\u3002 print ( 3 in a ) # True print ( '3' in a ) # False \u53cd\u5411\u8f93\u51fa\u5217\u8868\u3002 a . reverse () print ( a ) # [8, 7, 6, 5, 3, 1] \u53d6\u5217\u8868\u4e2d\u6700\u5927\u503c\u3001\u6700\u5c0f\u503c\u3002 print ( min ( a )) # 1 print ( max ( a )) # 78 \u8ba1\u7b97\u5217\u8868\u957f\u5ea6\u3002 print ( len ( a )) # 6 \u5217\u8868\u6269\u5c55\uff1a a = [ 1 , 2 , 3 ] b = [ 4 , 5 , 6 ] print ( a + b ) # [1, 2, 3, 4, 5, 6] a . extend ( b ) # a\u5217\u8868\u88ab\u4fee\u6539 print ( a ) # [1, 2, 3, 4, 5, 6] print ( b ) # [4, 5, 6] \u4f7f\u7528extend\u6dfb\u52a0\u5143\u7d20\u6bd4\u4f7f\u7528\u52a0\u53f7\uff08+\uff09\u8fde\u63a5\u6548\u7387\u66f4\u9ad8\u3002\u56e0\u4e3a\u4f7f\u7528\u52a0\u53f7\uff08+\uff09\u8fde\u63a5\u8fc7\u7a0b\u4e2d\u521b\u5efa\u4e86\u65b0\u5217\u8868\uff0c\u5e76\u4e14\u8fd8\u8981\u590d\u5236\u5bf9\u8c61\u3002 a_list = [ 4 , None , 'foo' ] b_list = [ 7 , 8 , ( 2 , 3 )] print ( a_list + b_list ) # [4, None, 'foo', 7, 8, (2, 3)] \u4f7f\u7528+\u53f7\u8fde\u63a5 a_list . extend ( b_list ) print ( a_list ) # [4, None, 'foo', 7, 8, (2, 3)] Python\u7684\u4e00\u4e2a\u60ef\u4f8b\uff1a\u5982\u679c\u4e00\u4e2a\u51fd\u6570\u6216\u8005\u65b9\u6cd5\u5bf9\u5bf9\u8c61\u8fdb\u884c\u7684\u662f\u5c31\u5730\u6539\u52a8\uff0c\u90a3\u5b83\u5c31\u5e94\u8be5\u8fd4\u56deNone\uff0c\u597d\u8ba9\u8c03\u7528\u8005\u77e5\u9053\u4f20\u5165\u7684\u53c2\u6570\u53d1\u751f\u4e86\u53d8\u52a8\uff0c\u800c\u4e14\u5e76\u672a\u4ea7\u751f\u65b0\u7684\u5bf9\u8c61\u3002 \u4e0b\u9762\u662f\u6392\u5e8f\u7684\u4f8b\u5b50 list.sort() \u548c sorted(list) \u7684\u533a\u522b\u3002 list1 = [ '1' , 'one' , '3' , 'Four' , '5' , 'two' , 'apple' , '8' , '9' ] print ( list1 ) # ['1', 'one', '3', 'Four', '5', 'two', 'apple', '8', '9'] # \u4e0b\u9762\u7684\u64cd\u4f5c\u4e0d\u6539\u53d8\u539f\u5217\u8868 print ( sorted ( list1 )) # ['1', '3', '5', '8', '9', 'Four', 'apple', 'one', 'two'] print ( sorted ( list1 , reverse = True )) # ['two', 'one', 'apple', 'Four', '9', '8', '5', '3', '1'] print ( sorted ( list1 , key = len )) # ['1', '3', '5', '8', '9', 'one', 'two', 'Four', 'apple'] print ( list1 ) # ['1', 'one', '3', 'Four', '5', 'two', 'apple', '8', '9'] # \u4e0b\u9762\u7684\u64cd\u4f5c\u76f4\u63a5\u4fee\u6539\u539f\u5217\u8868\uff0c\u8fd4\u56de\u503c\u662fNone print ( list1 . sort ()) # None print ( list1 ) # ['1', '3', '5', '8', '9', 'Four', 'apple', 'one', 'two'] \u5217\u8868\u590d\u5236\uff0c + \u548c * \u7684\u64cd\u4f5c\u90fd\u662f\u4e0d\u4fee\u6539\u539f\u6709\u7684\u64cd\u4f5c\u5bf9\u8c61\uff0c\u800c\u662f\u6784\u5efa\u4e00\u4e2a\u5168\u65b0\u7684\u5217\u8868\u3002 c = list ( 'Python' ) print ( a + c ) # [1, 2, 3, 4, 5, 6, 'P', 'y', 't', 'h', 'o', 'n'] print ( a * 3 ) # [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6] \u5982\u679c\u5728 a * n \u8fd9\u4e2a\u8bed\u53e5\u4e2d\uff0c\u5e8f\u5217 a \u91cc\u7684\u5143\u7d20\u662f\u5bf9\u5176\u4ed6\u53ef\u53d8\u5bf9\u8c61\u7684\u5f15\u7528\u7684\u8bdd\uff0c\u5c31\u9700\u8981\u683c\u5916\u6ce8\u610f\u4e86\uff0c\u56e0\u4e3a\u8fd9\u4e2a\u5f0f\u5b50\u7684\u7ed3\u679c\u53ef\u80fd\u4f1a\u51fa\u4e4e\u610f\u6599\u3002 \u6bd4\u5982\uff0c\u6211\u4eec\u60f3\u7528 my_list=[[]] * 3 \u6765\u521d\u59cb\u5316\u4e00\u4e2a\u7531\u5217\u8868\u7ec4\u6210\u7684\u5217\u8868\uff0c\u4f46\u662f\u6211\u4eec\u5b9e\u9645\u5f97\u5230\u7684\u5217\u8868\u91cc\u5305\u542b\u76843\u4e2a\u5143\u7d20\u5176\u5b9e\u662f3\u4e2a\u5f15\u7528\uff0c\u800c\u4e14\u8fd93\u4e2a\u5f15\u7528\u6307\u5411\u7684\u90fd\u662f*\u540c\u4e00\u4e2a*\u5217\u8868\u3002\u770b\u4e0b\u9762\u4f8b\u5b50\u3002 # \u505a\u6cd51 board = [[ '_' ] * 3 for i in range ( 3 )] print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 1 ][ 2 ] = 'X' print ( board ) # [['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']] # \u505a\u6cd52 board = [[ '_' ] * 3 ] * 3 print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 1 ][ 2 ] = 'X' print ( board ) # [['_', '_', 'X'], ['_', '_', 'X'], ['_', '_', 'X']] \u4e0b\u9762\u4e5f\u662f\u540c\u6837\u7684\u95ee\u9898\u3002 # \u65b9\u6cd51 row = [ '_' ] * 3 board = [] for i in range ( 3 ): board . append ( row ) print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 2 ][ 0 ] = 'X' print ( board ) # [['X', '_', '_'], ['X', '_', '_'], ['X', '_', '_']] # \u65b9\u6cd52 row = [] board = [] for i in range ( 3 ): row = [ '_' ] * 3 board . append ( row ) print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 2 ][ 0 ] = 'X' print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['X', '_', '_']] \u53cc\u7aef\u961f\u5217collections.deque \uff0c\u53ef\u4ee5\u6ee1\u8db3\u5217\u8868\u5934\u5c3e\u90e8\u90fd\u589e\u52a0\u7684\u8981\u6c42\u3002 deque() \u4e2d maxlen \u662f\u4e00\u4e2a\u53ef\u9009\u53c2\u6570\uff0c\u4ee3\u8868\u8fd9\u4e2a\u961f\u5217\u53ef\u4ee5\u5bb9\u7eb3\u7684\u5143\u7d20\u7684\u6570\u91cf\uff0c\u800c\u4e14\u4e00\u65e6\u8bbe\u5b9a\uff0c\u8fd9\u4e2a\u5c5e\u6027\u5c31\u4e0d\u80fd\u4fee\u6539\u4e86\u3002 \u5f53\u8bd5\u56fe\u5bf9\u4e00\u4e2a\u5df2\u6ee1 len(d)==d.maxlen \u7684\u961f\u5217\u505a\u5934\u90e8\u6dfb\u52a0\u64cd\u4f5c\u7684\u65f6\u5019\uff0c\u5b83\u5c3e\u90e8\u7684\u5143\u7d20\u4f1a\u88ab\u5220\u9664\u6389\u3002 extendleft(iter) \u65b9\u6cd5\u4f1a\u628a\u8fed\u4ee3\u5668\u91cc\u7684\u5143\u7d20\u9010\u4e2a\u6dfb\u52a0\u5230\u53cc\u5411\u961f\u5217\u7684\u5de6\u8fb9\uff0c\u56e0\u6b64\u8fed\u4ee3\u5668\u91cc\u7684\u5143\u7d20\u4f1a\u9006\u5e8f\u51fa\u73b0\u5728\u961f\u5217\u91cc\u3002 \u961f\u5217\u7684\u65cb\u8f6c\u64cd\u4f5c rotate \u63a5\u53d7\u4e00\u4e2a\u53c2\u6570n\uff0c\u5f53n > 0\u65f6\uff0c\u961f\u5217\u7684\u6700\u53f3\u8fb9\u7684n\u4e2a\u5143\u7d20\u4f1a\u88ab\u79fb\u52a8\u5230\u961f\u5217\u7684\u5de6\u8fb9\u3002\u5f53n < 0\u65f6\uff0c\u6700\u5de6\u8fb9\u7684n\u4e2a\u5143\u7d20\u4f1a\u88ab\u79fb\u52a8\u5230\u53f3\u8fb9\u3002 from collections import deque d = deque ([ 1 , 2 , 3 ]) print ( d ) # deque([1, 2, 3]) # \u6ce8\u610f\u63d2\u5165\u987a\u5e8f d . extendleft ([ 'a' , 'b' , 'c' ]) print ( d ) # deque(['c', 'b', 'a', 1, 2, 3]) print ( len ( d )) # 6 print ( d [ - 2 ]) # 2 # \u7edf\u8ba1\u5b57\u7b26a\u51fa\u73b0\u7684\u6b21\u6570 print ( d . count ( 'a' )) # 1 # \u8fd4\u56de\u5b57\u7b26a\u7684\u7d22\u5f15\u503c print ( d . index ( 'a' )) # 2 # \u7b2c0\u4f4d\u63d2\u5165\u6570\u5b571\uff0c\u5176\u4f59\u987a\u79fb d . insert ( 0 , 1 ) print ( d ) # deque([1, 'c', 'b', 'a', 1, 2, 3]) # \u628a\u53f3\u8fb92\u4e2a\u5143\u7d20\u653e\u5230\u5de6\u8fb9\uff0c\u6ce8\u610f\u987a\u5e8f\uff0c\u548cextendleft\u4e0d\u4e00\u6837 d . rotate ( 2 ) print ( d ) # deque([2, 3, 1, 'c', 'b', 'a', 1]) d . rotate ( - 2 ) print ( d ) # deque([1, 'c', 'b', 'a', 1, 2, 3]) \u4e0b\u8868\u603b\u7ed3\u4e86\u5217\u8868\u548c\u53cc\u5411\u961f\u5217\u7684\u65b9\u6cd5\uff08\u4e0d\u5305\u62ec\u7531\u5bf9\u8c61\u5b9e\u73b0\u7684\u65b9\u6cd5\uff09\u3002 \u5217\u8868\u6392\u5e8f\u3002\u6392\u5e8f\u5bf9\u5217\u8868\u5143\u7d20\u7684\u6570\u636e\u7c7b\u578b\u662f\u6709\u8981\u6c42\u7684\u3002 a_list = [ 4 , None , 'foo' , 7 , 8 , ( 2 , 3 )] a_list . sort () # Traceback (most recent call last): # File \"\", line 1, in # TypeError: '<' not supported between instances of 'NoneType' and 'int' b_list = [ 7 , 8 , ( 2 , 3 )] b_list . sort () # Traceback (most recent call last): # File \"\", line 1, in # TypeError: '<' not supported between instances of 'tuple' and 'int' a_list = [ 7 , 2 , 5 , 1 , 3 ] a_list . sort () # \u6309\u6570\u503c\u5927\u5c0f\u6392\u5e8f print ( a_list ) # [1, 2, 3, 5, 7] b_list = [ 'saw' , 'small' , 'He' , 'foxes' , 'six' ] b_list . sort ( key = len ) # \u901a\u8fc7\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u8fdb\u884c\u6392\u5e8f print ( b_list ) # ['He', 'saw', 'six', 'small', 'foxes'] \u5217\u8868\u4e8c\u5206\u641c\u7d22\u548c\u5df2\u6392\u5e8f\u5217\u8868\u7684\u7ef4\u62a4 bisect \u8fd4\u56de\u8981\u63d2\u5165\u5143\u7d20\u5728\u5217\u8868\u4e2d\u7684\u4e0b\u6807\u3002\u5047\u5b9a\u5217\u8868\u662f\u6709\u5e8f\u7684\u3002 bisect_left \u4e0e bisect \u7c7b\u4f3c\uff0c\u53ea\u4e0d\u8fc7\u5176\u9ed8\u8ba4\u5c06\u5143\u7d20\u63d2\u5230\u5de6\u8fb9\uff0c\u6240\u4ee5\u8fd4\u56de\u7684\u662f\u63d2\u5165\u5230\u5de6\u8fb9\u7684\u4e0b\u6807 bisect_right\u4e0e bisect_left \u76f8\u53cd\u3002 \u4ee5\u4e0a\u65b9\u6cd5\u82e5\u5217\u8868\u65e0\u5e8f\uff0c\u90a3\u4e48\u4f1a\u8fd4\u56de\u63d2\u5165\u5230\u5217\u8868\u6700\u540e\u4e00\u4e2a\u5408\u9002\u7684\u4f4d\u7f6e\u3002 insort \u4f1a\u5728\u5217\u8868\u4e2d\u63d2\u5165\u5143\u7d20\u5230\u6b63\u786e\u4f4d\u7f6e\uff0c\u5047\u5b9a\u5217\u8868\u6709\u5e8f\u3002\u5982\u679c\u5217\u8868\u65e0\u5e8f\uff0c\u90a3\u4e48\u4f1a\u8fd4\u56de\u7a7a\u3002\u9ed8\u8ba4\u63d2\u5165\u5230\u53f3\u8fb9\u3002 insort_left \u548cinsort_right \u7c7b\u4f3c\u3002 import bisect c = [ 1 , 2 , 3 , 4 , 7 ] print ( bisect . bisect ( c , 2 )) # 2 bisect\u4f1a\u627e\u5230\u7b2c\u4e00\u4e2a2,\u5e76\u628a\u65b0\u76842\u63d2\u5165\u5b83\u540e\u9762 bisect . insort ( c , 2 ) # [1, 2, 2, 3, 4, 7] print ( bisect . bisect ( c , 5 )) # 5 bisect\u4f1a\u627e\u5230\u7b2c\u4e00\u4e2a4,\u5e76\u628a\u65b0\u76845\u63d2\u5165\u5b83\u540e\u9762 bisect . insort ( c , 5 ) print ( bisect . bisect ( c , 6 )) # 6 bisect\u4f1a\u627e\u5230\u7b2c\u4e00\u4e2a5,\u5e76\u628a\u65b0\u76846\u63d2\u5165\u5b83\u540e\u9762 bisect . insort ( c , 6 ) print ( c ) # [1, 2, 2, 3, 4, 5, 6, 7] bisect\u53ef\u4ee5\u7528\u6765\u5efa\u7acb\u4e00\u4e2a\u7528\u6570\u5b57\u4f5c\u4e3a\u7d22\u5f15\u7684\u67e5\u8be2\u8868\u683c\uff0c\u5982\u4e0b\u4f8b\uff0c\u628a\u5206\u6570\u548c\u6210\u7ee9\u5bf9\u5e94\u8d77\u6765\uff0c\u6839\u636e\u4e00\u4e2a\u5206\u6570\uff0c\u627e\u5230\u5b83\u6240\u5bf9\u5e94\u7684\u6210\u7ee9\u3002 import bisect def grade ( score , breakpoints = [ 60 , 70 , 80 , 90 ], grades = 'FDCBA' ): i = bisect . bisect ( breakpoints , score ) return grades [ i ] [ grade ( score ) for score in [ 15 , 26 , 31 , 62 , 79 , 85 ]] # ['F', 'F', 'F', 'D', 'C', 'B'] \u7528bisect.insort\u63d2\u5165\u65b0\u5143\u7d20\uff0c\u5e76\u80fd\u4fdd\u6301seq\u7684\u5347\u5e8f\u987a\u5e8f\u3002 import bisect import random size = 7 random . seed ( 1729 ) my_list = [] for i in range ( size ): new_item = random . randrange ( size * 2 ) bisect . insort ( my_list , new_item ) print ( f ' { new_item : 2d } :--> { my_list } ' ) # 10 :--> [10] # 0 :--> [0, 10] # 6 :--> [0, 6, 10] # 8 :--> [0, 6, 8, 10] # 7 :--> [0, 6, 7, 8, 10] # 2 :--> [0, 2, 6, 7, 8, 10] # 10 :--> [0, 2, 6, 7, 8, 10, 10] 1.4 \u5b57\u5178\uff08dictionary\uff09 \u00b6 \u5b57\u5178(dict)\u662f\u4f7f\u7528\u952e-\u503c\uff08key-value\uff09\u5b58\u50a8\uff0c\u952e\u662f\u4e0d\u53ef\u53d8\u5bf9\u8c61\uff0c\u4e14\u4e0d\u5141\u8bb8\u91cd\u590d\u3002 dict\uff08\u5b57\u5178\uff09\u66f4\u4e3a\u5e38\u7528\u7684\u540d\u5b57\u662f\u54c8\u5e0c\u8868\u6216\u8005\u662f\u5173\u8054\u6570\u7ec4\u3002 \u5b57\u5178\u662f\u62e5\u6709\u7075\u6d3b\u5c3a\u5bf8\u7684\u952e\u503c\u5bf9\u96c6\u5408\uff0c\u4e0d\u662f\u901a\u8fc7\u4f4d\u7f6e\u8fdb\u884c\u7d22\u5f15\uff0c\u5176\u4e2d\u952e\u548c\u503c\u90fd\u662fPython\u5bf9\u8c61\u3002\u7528\u5927\u62ec\u53f7{}\u662f\u521b\u5efa\u5b57\u5178\u7684\u4e00\u79cd\u65b9\u5f0f\uff0c\u5728\u5b57\u5178\u4e2d\u7528\u9017\u53f7\u5c06\u952e\u503c\u5bf9\u5206\u9694\u3002 \u521b\u5efa\u5b57\u5178\u7684\u51e0\u79cd\u65b9\u6cd5\uff1a a = dict ( one = 1 , two = 2 , three = 3 ) b = { 'one' : 1 , 'two' : 2 , 'three' : 3 } c = dict ( zip ([ 'one' , 'two' , 'three' ], [ 1 , 2 , 3 ])) d = dict ([( 'two' , 2 ), ( 'three' , 3 ), ( 'one' , 1 )]) e = dict ({ 'three' : 3 , 'one' : 1 , 'two' : 2 }) print ( a == b == c == d == e ) # True \u5b57\u5178\u5e38\u7528\u65b9\u6cd5 \u65b9\u6cd5\u540d\u79f0 \u4f5c\u7528 a.items() \u8fd4\u56dea\u4e2d\u6240\u6709\u952e\u503c\u5bf9 a.values() \u8fd4\u56dea\u4e2d\u6240\u6709\u503c a.keys() \u8fd4\u56dea\u4e2d\u6240\u6709\u952e a.get() \u901a\u8fc7\u952e\u6765\u67e5\u503c\uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u503c a.clear() \u6e05\u7a7a\u5b57\u5178a\u7684\u503c a.setdefault \u901a\u8fc7\u952e\u503c\u6765\u67e5\u627e\u503c\uff0c\u627e\u4e0d\u5230\u5219\u63d2\u5165 a.update() \u952e\u548c\u503c\u66f4\u65b0\u5230\u65b0\u7684\u5b57\u5178 a.pop() \u5220\u9664\u6307\u5b9a\u4f4d\u7f6e\u7684\u5143\u7d20 \u751f\u6210\u4e00\u4e2a\u5b57\u5178\u3002 dict_a = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } print ( type ( dict_a )) # dict_b = dict ( city = 'Shanghai' , strict = 'Xuhui' , zip = '200000' ) print ( type ( dict_b )) # \u901a\u8fc7\u952e\u67e5\u8be2\u503c\uff0c\u67e5\u8be2\u4e0d\u5230\u629b\u51fa\u5f02\u5e38\u3002 print ( dict_a [ 'name' ]) # Ming print ( dict_a [ 'Name' ]) # Traceback (most recent call last): # File \"\", line 1, in # KeyError: 'Name' \u63d2\u5165\u65b0\u7684\u952e\u503c\u5bf9\u3002 dict_a [ 'city' ] = 'Chengdu' print ( dict_a ) # {'name': 'Ming', 'id': 1001, 'city': 'Chengdu'} \u5220\u9664\u67d0\u4e2a\u952e\u503c\u5bf9\u3002pop\u65b9\u6cd5\u4f1a\u5728\u5220\u9664\u7684\u540c\u65f6\u8fd4\u56de\u88ab\u5220\u7684\u503c\uff0c\u5e76\u5220\u9664\u952e\u3002 dict_a . pop ( 'city' ) # Chengdu print ( dict_a ) # {'name': 'Ming', 'id': 1001} \u53e6\u4e00\u79cd\u65b9\u5f0f\u5220\u9664\u67d0\u4e2a\u952e\u503c\u5bf9\u3002 del dict_a [ 'age' ] # Traceback (most recent call last): # File \"\", line 1, in # KeyError: 'age' del dict_a [ 'id' ] print ( dict_a ) # {'name': 'Ming'} \u5224\u65ad\u952e\u662f\u5426\u5b58\u5728\u3002 dict_a [ 23 ] = 'Hello World' print ( dict_a ) # {'name': 'Ming', 23: 'Hello World'} print ( 23 in dict_a ) # True print ( 35 in dict_a ) # False \u901a\u8fc7\u952e\u67e5\u8be2\u503c\u7684\u53e6\u4e00\u79cd\u65b9\u5f0f\uff0c\u67e5\u8be2\u4e0d\u5230\u4e0d\u629b\u5f02\u5e38\u3002 dict_a . get ( 'hai' ) dict_a . get ( 'hai' , 1 ) # 1 dict_a . get ( 'name' , 1 ) # Ming dict_a [ 'hai' ] # Traceback (most recent call last): # File \"\", line 1, in # KeyError: 'hai' \u901a\u8fc7\u952e\u67e5\u8be2\u503c\u7684\u53e6\u4e00\u79cd\u65b9\u5f0f\uff0c\u67e5\u8be2\u4e0d\u5230\u5219\u6dfb\u52a0\u3002 dict_a . setdefault ( 'name' ) # Ming dict_a . setdefault ( 'hai' , 1 ) # 1 print ( dict_a ) # {'name': 'Ming', 23: 'Hello World', 'hai': 1} dict_a . setdefault ( 'go' ) print ( dict_a ) # {'name': 'Ming', 23: 'Hello World', 'hai': 1, 'go': None} \u8bfb\u53d6\u5b57\u5178\u6240\u6709\u952e\u503c\u5bf9\uff0c\u8fd4\u56de\u7684\u662f\u5217\u8868\u5f62\u5f0f\u3002 print ( dict_a . items ()) # dict_items([('name', 'Ming'), (23, 'Hello World'), ('hai', 1), ('go', None)]) \u8bfb\u53d6\u5b57\u5178\u7684\u952e\u3002 print ( dict_a . keys ()) # dict_keys(['name', 23, 'hai', 'go']) \u8bfb\u53d6\u5b57\u5178\u7684\u503c\u3002 print ( dict_a . values ()) # dict_values(['Ming', 'Hello World', 1, None]) \u5c06\u5b57\u5178\u503c\u8f6c\u5316\u6210\u5217\u8868\u3002 print ( list ( dict_a . values ())) # ['Ming', 'Hello World', 1, None] for key in dict_a . keys (): print ( dict_a [ key ]) # Ming # Hello World # 1 # None \u6e05\u7a7a\u5b57\u5178\u3002 dict_a . clear () print ( dict_a ) # {} print ( len ( dict_a )) # 0 \u5bf9\u4e8e\u4efb\u4f55\u539f\u5b57\u5178\u4e2d\u5df2\u7ecf\u5b58\u5728\u7684\u952e\uff0c\u5982\u679c\u4f20\u7ed9update\u65b9\u6cd5\u7684\u6570\u636e\u4e5f\u542b\u6709\u76f8\u540c\u7684\u952e\uff0c\u5219\u5b83\u7684\u503c\u5c06\u4f1a\u88ab\u8986\u76d6\u3002 dict_a = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } dict_b = dict ( city = 'Shanghai' , id = 2001 , zip = '200000' ) dict_a . update ( dict_b ) print ( dict_a ) # {'name': 'Ming', 'id': 2001, 'age': 35, 'city': 'Shanghai', 'zip': '200000'} \u4ece\u5217\u8868\u751f\u6210\u5b57\u5178\u3002 \u5b57\u5178\u672c\u8d28\u4e0a\u662f2-\u5143\u7ec4\uff08\u542b\u67092\u4e2a\u5143\u7d20\u7684\u5143\u7ec4\uff09\u7684\u96c6\u5408\uff0c\u5b57\u5178\u662f\u53ef\u4ee5\u63a5\u53d7\u4e00\u4e2a2-\u5143\u7ec4\u7684\u5217\u8868\u4f5c\u4e3a\u53c2\u6570\u7684\u3002 # \u65b9\u6cd51 mapping = {} key_list = list ( range ( 5 )) value_list = list ( reversed ( range ( 5 ))) for key , value in zip ( key_list , value_list ): mapping [ key ] = value print ( mapping ) # {0: 4, 1: 3, 2: 2, 3: 1, 4: 0} # \u65b9\u6cd52\u3002 mapping = {} key_list = list ( range ( 5 )) value_list = list ( reversed ( range ( 5 ))) mapping = dict ( zip ( key_list , value_list )) print ( mapping ) # {0: 4, 1: 3, 2: 2, 3: 1, 4: 0} \u6709\u6548\u7684\u5b57\u5178\u952e\u7c7b\u578b\u3002 \u5c3d\u7ba1\u5b57\u5178\u7684\u503c\u53ef\u4ee5\u662f\u4efb\u4f55Python\u5bf9\u8c61\uff0c\u4f46\u952e\u5fc5\u987b\u662f\u4e0d\u53ef\u53d8\u7684\u5bf9\u8c61\uff0c\u6bd4\u5982\u6807\u91cf\u7c7b\u578b\uff08\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u5b57\u7b26\u4e32\uff09\u6216\u5143\u7ec4\uff08\u4e14\u5143\u7ec4\u5185\u5bf9\u8c61\u4e5f\u5fc5\u987b\u662f\u4e0d\u53ef\u53d8\u5bf9\u8c61\uff09\u3002 \u901a\u8fc7hash\u51fd\u6570\u53ef\u4ee5\u68c0\u67e5\u4e00\u4e2a\u5bf9\u8c61\u662f\u5426\u53ef\u4ee5\u54c8\u5e0c\u5316\uff08\u5373\u662f\u5426\u53ef\u4ee5\u7528\u4f5c\u5b57\u5178\u7684\u952e\uff09\uff0c\u672f\u8bed\u53eb\u4f5c\u54c8\u5e0c\u5316\u3002 print ( hash ( 'string' )) # -4368784820203065343 print ( hash (( 1 , 2 , ( 2 , 3 )))) # -9209053662355515447 print ( hash (( 1 , 2 , [ 2 , 3 ]))) # TypeError: unhashable type: 'list' print ( hash (( 1 , 2 , tuple ([ 2 , 3 ])))) # -9209053662355515447 \u4e3a\u4e86\u5c06\u5217\u8868\u4f5c\u4e3a\u952e\uff0c\u4e00\u79cd\u65b9\u5f0f\u5c31\u662f\u5c06\u5176\u8f6c\u6362\u4e3a\u5143\u7ec4 \u5b57\u5178\u9ed8\u8ba4\u503c\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5b9e\u73b0\u4e86\u5c06\u4e00\u4e2a\u5355\u8bcd\u7ec4\u6210\u7684\u5217\u8868\uff0c\u8f6c\u6362\u6210\u5355\u8bcd\u9996\u5b57\u6bcd\u548c\u5355\u8bcd\u4e3a\u952e\u503c\u5bf9\u7684\u5b57\u5178\u3002\u5148\u7528\u4f20\u7edf\u65b9\u6cd5\u5b9e\u73b0\uff0c\u518d\u7528\u5b57\u5178\u7684setdefault\u65b9\u6cd5\u8fdb\u884c\u6539\u5199\u3002 \u5148\u770b\u4f20\u7edf\u65b9\u6cd5\u3002 words = [ 'apple' , 'bat' , 'bar' , 'atom' , 'book' ] by_letter = {} for word in words : letter = word [ 0 ] # word[0]\u628a\u5217\u8868words\u7684\u6bcf\u4e2a\u5143\u7d20\u5217\u8868\u5316\uff0c\u5e76\u53d6\u9996\u5b57\u6bcd\u3002\u8f93\u51fa\u7684\u662fa, b, b, a, b\u8fd95\u4e2a\u5217\u8868\u5143\u7d20\u7684\u9996\u5b57\u6bcd if letter not in by_letter : # \u751f\u6210\u7b2c\u4e00\u4e2a\u952e\u503c\u5bf9 print ( letter ) by_letter [ letter ] = [ word ] # \u5bf9\u6bd4[word]\u548cword[]\u7684\u7528\u6cd5 print ( by_letter ) # a # {'a': ['apple']} # b # {'a': ['apple'], 'b': ['bat']} else : # append\u5176\u4ed6\u952e\u503c\u5bf9 print ( letter ) by_letter [ letter ] . append ( word ) print ( by_letter ) # b # {'a': ['apple'], 'b': ['bat', 'bar']} # a # {'a': ['apple', 'atom'], 'b': ['bat', 'bar']} # b # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} print ( by_letter ) # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} \u7528\u5b57\u5178\u7684setdefault\u65b9\u6cd5\uff0c\u4e0a\u8ff0\u7684for\u5faa\u73af\u8bed\u53e5\u53ef\u4ee5\u88ab\u5199\u4e3a\u5982\u4e0b\u3002 words = [ 'apple' , 'bat' , 'bar' , 'atom' , 'book' ] by_letter = {} for word in words : letter = word [ 0 ] # word[0]\u7684\u8f93\u51fa\u4f9d\u7136\u662f5\u4e2a\u5217\u8868\u5143\u7d20\u7684\u9996\u5b57\u6bcda, b, b, a, b by_letter . setdefault ( letter , []) . append ( word ) # \u5982\u679cletter\u4e0d\u5728[]\u5219\u901a\u8fc7append\u6dfb\u52a0word print ( by_letter ) # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} \u5982\u679c\u6539\u5199\u4e3a by_letter.setdefault(letter, ['a']).append(word) \uff0c\u5219\u8f93\u51fa by_letter \u662f {'a': ['a', 'apple', 'atom'], 'b': ['a', 'bat', 'bar', 'book']} \u3002 words = [ 'apple' , 'bat' , 'bar' , 'atom' , 'book' ] by_letter = {} for word in words : letter = word [ 0 ] # word[0]\u7684\u8f93\u51fa\u4f9d\u7136\u662f5\u4e2a\u5217\u8868\u5143\u7d20\u7684\u9996\u5b57\u6bcda, b, b, a, b by_letter . setdefault ( letter , [ 'a' ]) . append ( word ) print ( by_letter ) # {'a': ['a', 'apple', 'atom'], 'b': ['a', 'bat', 'bar', 'book']} \u4f53\u4f1asetdefault()\u7684\u6ce8\u91ca\u201cInsert key with a value of default if key is not in the dictionary. Return the value for key if key is in the dictionary, else default.\u201d \u901a\u8fc7defaultdict\u7c7b\u4f7f\u5f97\u4e0a\u8ff0\u76ee\u7684\u5b9e\u73b0\u66f4\u4e3a\u7b80\u5355\u3002 from collections import defaultdict by_letter = defaultdict ( list ) # list\u662f\u5185\u7f6e\u7684\u53ef\u53d8\u5e8f\u5217(Built-in mutable sequence) print ( dict ( by_letter )) # {} for word in words : by_letter [ word [ 0 ]] . append ( word ) print ( by_letter ) # defaultdict(, {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']}) print ( dict ( by_letter )) # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} \u4e0b\u8868\u5c55\u793a\u4e86 dict \u3001 defaultdict \u548c OrderedDict \u7684\u5e38\u89c1\u65b9\u6cd5\uff0c\u540e\u9762\u4e24\u4e2a\u6570\u636e\u7c7b\u578b\u662f dict \u7684\u53d8\u79cd\uff0c\u4f4d\u4e8e collections \u6a21\u5757\u5185\u3002 default_factory \u5e76\u4e0d\u662f\u4e00\u4e2a\u65b9\u6cd5\uff0c\u800c\u662f\u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61\uff08callable\uff09\uff0c\u5b83\u7684\u503c\u5728 defaultdict \u521d\u59cb\u5316\u7684\u65f6\u5019\u7531\u7528\u6237\u8bbe\u5b9a\u3002 OrderedDict.popitem() \u4f1a\u79fb\u9664\u5b57\u5178\u91cc\u6700\u5148\u63d2\u5165\u7684\u5143\u7d20\uff08\u5148\u8fdb\u5148\u51fa\uff09\uff1b\u540c\u65f6\u8fd9\u4e2a\u65b9\u6cd5\u8fd8\u6709\u4e00\u4e2a\u53ef\u9009\u7684last\u53c2\u6570\uff0c\u82e5\u4e3a\u771f\uff0c\u5219\u4f1a\u79fb\u9664\u6700\u540e\u63d2\u5165\u7684\u5143\u7d20\uff08\u540e\u8fdb\u5148\u51fa\uff09\u3002 \u4e0a\u9762\u7684\u8868\u683c\u4e2d\uff0cupdate\u65b9\u6cd5\u5904\u7406\u53c2\u6570m\u7684\u65b9\u5f0f\uff0c\u662f\u5178\u578b\u7684\u201c\u9e2d\u5b50\u7c7b\u578b\u201d\u3002\u51fd\u6570\u9996\u5148\u68c0\u67e5m\u662f\u5426\u6709keys\u65b9\u6cd5\uff0c\u5982\u679c\u6709\uff0c\u90a3\u4e48update\u51fd\u6570\u5c31\u628a\u5b83\u5f53\u4f5c\u6620\u5c04\u5bf9\u8c61\u6765\u5904\u7406\u3002\u5426\u5219\uff0c\u51fd\u6570\u4f1a\u9000\u4e00\u6b65\uff0c\u8f6c\u800c\u628am\u5f53\u4f5c\u5305\u542b\u4e86\u952e\u503c\u5bf9(key, value)\u5143\u7d20\u7684\u8fed\u4ee3\u5668\u3002Python\u91cc\u5927\u591a\u6570\u6620\u5c04\u7c7b\u578b\u7684\u6784\u9020\u65b9\u6cd5\u90fd\u91c7\u7528\u4e86\u7c7b\u4f3c\u7684\u903b\u8f91\uff0c\u56e0\u6b64\u4f60\u65e2\u53ef\u4ee5\u7528\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\u6765\u65b0\u5efa\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\uff0c\u4e5f\u53ef\u4ee5\u7528\u5305\u542b(key, value)\u5143\u7d20\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\u6765\u521d\u59cb\u5316\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\u3002 \u5b57\u5178\u7684\u53d8\u79cd\uff1a collections.OrderedDict \u8fd9\u4e2a\u7c7b\u578b\u5728\u6dfb\u52a0\u952e\u7684\u65f6\u5019\u4f1a\u4fdd\u6301\u987a\u5e8f\uff0c\u56e0\u6b64\u952e\u7684\u8fed\u4ee3\u6b21\u5e8f\u603b\u662f\u4e00\u81f4\u7684\u3002OrderedDict\u7684popitem\u65b9\u6cd5\u9ed8\u8ba4\u5220\u9664\u5e76\u8fd4\u56de\u7684\u662f\u5b57\u5178\u91cc\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff0c\u4f46\u662f\u5982\u679c\u50cfmy_odict.popitem(last=False)\u8fd9\u6837\u8c03\u7528\u5b83\uff0c\u90a3\u4e48\u5b83\u5220\u9664\u5e76\u8fd4\u56de\u7b2c\u4e00\u4e2a\u88ab\u6dfb\u52a0\u8fdb\u53bb\u7684\u5143\u7d20\u3002 collections.ChainMap \u8be5\u7c7b\u578b\u53ef\u4ee5\u5bb9\u7eb3\u6570\u4e2a\u4e0d\u540c\u7684\u6620\u5c04\u5bf9\u8c61\uff0c\u7136\u540e\u5728\u8fdb\u884c\u952e\u67e5\u627e\u64cd\u4f5c\u7684\u65f6\u5019\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u4f1a\u88ab\u5f53\u4f5c\u4e00\u4e2a\u6574\u4f53\u88ab\u9010\u4e2a\u67e5\u627e\uff0c\u76f4\u5230\u952e\u88ab\u627e\u5230\u4e3a\u6b62\u3002\u8fd9\u4e2a\u529f\u80fd\u5728\u7ed9\u6709\u5d4c\u5957\u4f5c\u7528\u57df\u7684\u8bed\u8a00\u505a\u89e3\u91ca\u5668\u7684\u65f6\u5019\u5f88\u6709\u7528\uff0c\u53ef\u4ee5\u7528\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\u6765\u4ee3\u8868\u4e00\u4e2a\u4f5c\u7528\u57df\u7684\u4e0a\u4e0b\u6587\u3002 collections.Counter \u8fd9\u4e2a\u6620\u5c04\u7c7b\u578b\u4f1a\u7ed9\u952e\u51c6\u5907\u4e00\u4e2a\u6574\u6570\u8ba1\u6570\u5668\u3002\u6bcf\u6b21\u66f4\u65b0\u4e00\u4e2a\u952e\u7684\u65f6\u5019\u90fd\u4f1a\u589e\u52a0\u8fd9\u4e2a\u8ba1\u6570\u5668\u3002\u6240\u4ee5\u8fd9\u4e2a\u7c7b\u578b\u53ef\u4ee5\u7528\u6765\u7ed9\u53ef\u6563\u5217\u8868\u5bf9\u8c61\u8ba1\u6570\uff0c\u6216\u8005\u662f\u5f53\u6210\u591a\u91cd\u96c6\u6765\u7528\u2014\u2014\u591a\u91cd\u96c6\u5408\u5c31\u662f\u96c6\u5408\u91cc\u7684\u5143\u7d20\u53ef\u4ee5\u51fa\u73b0\u4e0d\u6b62\u4e00\u6b21\u3002Counter\u5b9e\u73b0\u4e86+\u548c-\u8fd0\u7b97\u7b26\u7528\u6765\u5408\u5e76\u8bb0\u5f55\uff0c\u8fd8\u6709\u50cfmost_common([n])\u8fd9\u7c7b\u5f88\u6709\u7528\u7684\u65b9\u6cd5\u3002most_common([n])\u4f1a\u6309\u7167\u6b21\u5e8f\u8fd4\u56de\u6620\u5c04\u91cc\u6700\u5e38\u89c1\u7684n\u4e2a\u952e\u548c\u5b83\u4eec\u7684\u8ba1\u6570 collections.UserDict \u8fd9\u4e2a\u7c7b\u5176\u5b9e\u5c31\u662f\u628a\u6807\u51c6dict\u7528\u7eafPython\u53c8\u5b9e\u73b0\u4e86\u4e00\u904d\u3002\u8ddfOrderedDict\u3001ChainMap\u548cCounter\u8fd9\u4e9b\u5f00\u7bb1\u5373\u7528\u7684\u7c7b\u578b\u4e0d\u540c\uff0cUserDict\u662f\u8ba9\u7528\u6237\u7ee7\u627f\u5199\u5b50\u7c7b\u7684\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u5229\u7528Counter\u6765\u8ba1\u7b97\u5355\u8bcd\u4e2d\u5404\u4e2a\u5b57\u6bcd\u51fa\u73b0\u7684\u6b21\u6570\uff1a str = 'abracadabra' ct = collections . Counter ( str ) print ( ct ) # Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}) \u4e0d\u53ef\u53d8\u6620\u5c04\u7c7b\u578b\u3002 \u6807\u51c6\u5e93\u91cc\u6240\u6709\u7684\u6620\u5c04\u7c7b\u578b\u90fd\u662f\u53ef\u53d8\u7684\uff0c\u4f46\u6709\u65f6\u5019\u4f60\u4f1a\u6709\u8fd9\u6837\u7684\u9700\u6c42\uff0c\u6bd4\u5982\u4e0d\u80fd\u8ba9\u7528\u6237\u9519\u8bef\u5730\u4fee\u6539\u67d0\u4e2a\u6620\u5c04\u3002 \u4ecePython 3.3\u5f00\u59cb\uff0c types \u6a21\u5757\u4e2d\u5f15\u5165\u4e86\u4e00\u4e2a\u5c01\u88c5\u7c7b\u540d\u53eb MappingProxyType \u3002\u5982\u679c\u7ed9\u8fd9\u4e2a\u7c7b\u4e00\u4e2a\u6620\u5c04\uff0c\u5b83\u4f1a\u8fd4\u56de\u4e00\u4e2a\u53ea\u8bfb\u7684\u6620\u5c04\u89c6\u56fe\u3002\u867d\u7136\u662f\u4e2a\u53ea\u8bfb\u89c6\u56fe\uff0c\u4f46\u662f\u5b83\u662f\u52a8\u6001\u7684\u3002\u8fd9\u610f\u5473\u7740\u5982\u679c\u5bf9\u539f\u6620\u5c04\u505a\u51fa\u4e86\u6539\u52a8\uff0c\u6211\u4eec\u901a\u8fc7\u8fd9\u4e2a\u89c6\u56fe\u53ef\u4ee5\u89c2\u5bdf\u5230\uff0c\u4f46\u662f\u65e0\u6cd5\u901a\u8fc7\u8fd9\u4e2a\u89c6\u56fe\u5bf9\u539f\u6620\u5c04\u505a\u51fa\u4fee\u6539\u3002 \u901a\u8fc7\u4e0b\u4f8b\u53ef\u4ee5\u770b\u51fa\uff0c d \u4e2d\u7684\u5185\u5bb9\u53ef\u4ee5\u901a\u8fc7 d_proxy \u770b\u5230\u3002\u4f46\u662f\u901a\u8fc7 d_proxy \u5e76\u4e0d\u80fd\u505a\u4efb\u4f55\u4fee\u6539\u3002 d_proxy \u662f\u52a8\u6001\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\u5bf9 d \u6240\u505a\u7684\u4efb\u4f55\u6539\u52a8\u90fd\u4f1a\u53cd\u9988\u5230\u5b83\u4e0a\u9762\u3002 from types import MappingProxyType d = { 1 : 'A' } d_proxy = MappingProxyType ( d ) print ( d ) # {1: 'A'} print ( d_proxy ) # {1: 'A'} print ( d [ 1 ]) # A print ( d_proxy [ 1 ]) # A d [ 2 ] = 'W' print ( d ) # {1: 'A', 2: 'W'} d_proxy [ 2 ] = 'W' # TypeError: 'mappingproxy' object does not support item assignment print ( d_proxy ) # {1: 'A', 2: 'W'} 1.5 \u96c6\u5408\uff08set\uff09 \u00b6 \u201c\u96c6\u201d\u8fd9\u4e2a\u6982\u5ff5\u5728Python\u4e2d\u7b97\u662f\u6bd4\u8f83\u5e74\u8f7b\u7684\uff0c\u540c\u65f6\u5b83\u7684\u4f7f\u7528\u7387\u4e5f\u6bd4\u8f83\u4f4e\u3002set\u548c\u5b83\u7684\u4e0d\u53ef\u53d8\u7684\u59ca\u59b9\u7c7b\u578bfrozenset\u76f4\u5230Python 2.3\u624d\u9996\u6b21\u4ee5\u6a21\u5757\u7684\u5f62\u5f0f\u51fa\u73b0\uff0c\u7136\u540e\u5728Python 2.6\u4e2d\u5b83\u4eec\u5347\u7ea7\u6210\u4e3a\u5185\u7f6e\u7c7b\u578b\u3002 \u96c6\u5408(set) \uff0c\u5305\u542b\u4e0d\u53ef\u53d8\u7684\u96c6\u5408\uff08frozenset\uff09\uff0c\u662f\u4e00\u79cd\u65e0\u5e8f\u4e14\u5143\u7d20\u552f\u4e00\u7684\u5e8f\u5217\uff0c\u6240\u4ee5\u96c6\u5408\u7684\u672c\u8d28\u662f\u8bb8\u591a\u552f\u4e00\u5bf9\u8c61\u7684\u805a\u96c6\u3002 \u548c\u5b57\u5178\u7c7b\u4f3c\uff0c\u96c6\u5408\u7684\u5143\u7d20\u662f\u4e0d\u53ef\u53d8\u7684\u3002\u53ef\u4ee5\u8ba4\u4e3a\u96c6\u5408\u4e5f\u50cf\u5b57\u5178\uff0c\u4f46\u662f\u53ea\u6709\u952e\u6ca1\u6709\u503c\u3002\u57fa\u672c\u529f\u80fd\u662f\u8fdb\u884c\u6210\u5458\u5173\u7cfb\u6d4b\u8bd5\u548c\u5220\u9664\u91cd\u590d\u5143\u7d20\u3002\u6240\u4ee5\u96c6\u5408\u53e6\u4e00\u4e2a\u7528\u9014\u662f\u53bb\u91cd\u590d\u3002 \u96c6\u5408\u4e2d\u7684\u5143\u7d20\u5fc5\u987b\u662f\u53ef\u6563\u5217\u7684\uff0cset\u7c7b\u578b\u672c\u8eab\u662f\u4e0d\u53ef\u6563\u5217\u7684\uff0c\u4f46\u662ffrozenset\u53ef\u4ee5\u3002\u56e0\u6b64\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u5305\u542b\u4e0d\u540cfrozenset\u7684set\u3002 \u96c6\u5408\u53ef\u4ee5\u6709\u4e24\u79cd\u521b\u5efa\u65b9\u5f0f\uff1a\u901a\u8fc7set()\u51fd\u6570\u6216\u8005{}\u6765\u521b\u5efa\uff08\u7528\u5927\u62ec\u53f7\u62ec\u4f4f\u7684\u5185\u5bb9\uff0cPython3\u81ea\u52a8\u5b9a\u4e49\u4e3a\u96c6\u5408\uff09\u3002 \u96c6\u5408\u4e0d\u5c5e\u4e8e\u5e8f\u5217\u7c7b\u6570\u636e\uff0c \u96c6\u5408\u4e0d\u652f\u6301\u901a\u8fc7\u7d22\u5f15\u8bbf\u95ee\u6307\u5b9a\u5143\u7d20\uff0c\u4f46\u53ef\u4ee5\u589e\u52a0\u548c\u5220\u9664\u5143\u7d20\u3002 \u9762\u7684\u4f8b\u5b50\u662f\u6c42 haystacke \u548c needles \u4e24\u4e2a\u96c6\u5408\u7684\u4ea4\u96c6\u5143\u7d20\u4e2a\u6570\u3002 haystacke = { 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'f' , 'g' , 'h' , 'c' , 'd' , 'e' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' } needles = { 'c' , 'h' , 'w' } type ( haystacke ) # type ( needles ) # # \u4f20\u7edf\u65b9\u6cd5 found = 0 for i in needles : if i in haystacke : found += 1 print ( found ) # 2 # \u96c6\u5408\u65b9\u6cd5\u4e00 found = len ( needles & haystacke ) print ( found ) # 2 # \u96c6\u5408\u65b9\u6cd5\u4e8c found = len ( needles . intersection ( haystacke )) print ( found ) # 2 \u96c6\u5408\u5b9e\u73b0\u4e86\u5f88\u591a\u57fa\u7840\u7684\u4e2d\u7f00\u8fd0\u7b97\u7b26\uff0c\u6bd4\u5982\uff0c\u96c6\u5408\u652f\u6301\u6570\u5b66\u4e0a\u7684\u96c6\u5408\u64cd\u4f5c\uff1a\u5e76\u96c6\u3001\u4ea4\u96c6\u3001\u5dee\u96c6\u3001\u5bf9\u79f0\u5dee\u96c6\u3002 \u65b9\u6cd5\u540d\u79f0 \u8bf4\u660e add() \u4e3a\u96c6\u5408\u6dfb\u52a0\u5143\u7d20 update() \u7ed9\u96c6\u5408\u6dfb\u52a0\u5143\u7d20 clear() \u79fb\u9664\u96c6\u5408\u4e2d\u7684\u6240\u6709\u5143\u7d20 copy() \u62f7\u8d1d\u4e00\u4e2a\u96c6\u5408 remove() \u79fb\u9664\u6307\u5b9a\u5143\u7d20 pop() \u968f\u673a\u79fb\u9664\u5143\u7d20 discard() \u5220\u9664\u96c6\u5408\u4e2d\u6307\u5b9a\u7684\u5143\u7d20 < \u6216\u8005issubset() \u5224\u65ad\u6307\u5b9a\u96c6\u5408\u662f\u5426\u4e3a\u8be5\u65b9\u6cd5\u53c2\u6570\u96c6\u5408\u7684\u5b50\u96c6 | \u6216\u8005union() \u8fd4\u56de\u4e24\u4e2a\u96c6\u5408\u7684\u5e76\u96c6 & \u6216\u8005intersection() \u8fd4\u56de\u96c6\u5408\u7684\u4ea4\u96c6 intersection_update() \u8fd4\u56de\u96c6\u5408\u7684\u4ea4\u96c6 - \u6216\u8005difference() \u8fd4\u56de\u591a\u4e2a\u96c6\u5408\u7684\u5dee\u96c6 difference_update() \u79fb\u9664\u96c6\u5408\u4e2d\u7684\u5143\u7d20\uff0c\u8be5\u5143\u7d20\u5728\u6307\u5b9a\u7684\u96c6\u5408\u4e5f\u5b58\u5728 ^ \u6216\u8005symmetric_difference() \u8fd4\u56de\u4e24\u4e2a\u96c6\u5408\u4e2d\u4e0d\u91cd\u590d\u7684\u5143\u7d20\u96c6\u5408(\u4e24\u96c6\u5408\u9664\u53bb\u4ea4\u96c6\u90e8\u5206\u7684\u5143\u7d20) symmetric_difference_update() \u79fb\u9664\u5f53\u524d\u96c6\u5408\u4e2d\u5728\u53e6\u5916\u4e00\u4e2a\u6307\u5b9a\u96c6\u5408\u76f8\u540c\u7684\u5143\u7d20\uff0c\u5e76\u5c06\u53e6\u5916\u4e00\u4e2a\u6307\u5b9a\u96c6\u5408\u4e2d\u4e0d\u540c\u7684\u5143\u7d20\u63d2\u5165\u5230\u5f53\u524d\u96c6\u5408\u4e2d isdisjoint() \u5224\u65ad\u4e24\u4e2a\u96c6\u5408\u662f\u5426\u5305\u542b\u76f8\u540c\u7684\u5143\u7d20\uff0c\u5982\u679c\u6ca1\u6709\u8fd4\u56de True\uff0c\u5426\u5219\u8fd4\u56de False issuperset() \u5224\u65ad\u8be5\u65b9\u6cd5\u7684\u53c2\u6570\u96c6\u5408\u662f\u5426\u4e3a\u6307\u5b9a\u96c6\u5408\u7684\u5b50\u96c6 \u4e3e\u4f8b\uff1a a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } \u5e76\u96c6(a\u548cb\u4e2d\u7684\u6240\u6709\u4e0d\u540c\u5143\u7d20)\u3002 print ( a . union ( b )) # {'c', 1, 2, 'd', 'a', 'b'} print ( a | b ) # {'c', 1, 2, 'd', 'a', 'b'} \u4ea4\u96c6(a\u3001b\u4e2d\u540c\u65f6\u5305\u542b\u7684\u5143\u7d20)\u3002 print ( a . intersection ( b )) # {'c', 1} print ( a & b ) # {'c', 1} \u5c06a\u7684\u5185\u5bb9\u8bbe\u7f6e\u4e3aa\u548cb\u7684\u4ea4\u96c6\u3002 a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a . intersection_update ( b ) print ( a ) # {1, 'c'} \u5728a\u4e0d\u5728b\u7684\u5143\u7d20\u3002 print ( a . difference ( b )) # {'a', 2, 'b'} print ( a - b ) # {2, 'a', 'b'} \u5c06a\u7684\u5185\u5bb9\u8bbe\u4e3a\u5728a\u4e0d\u5728b\u7684\u5143\u7d20\u3002 a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a . difference_update ( b ) print ( a ) # {2, 'b', 'a'} a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a -= b print ( a ) # {2, 'a', 'b'} \u5c06\u5143\u7d20\u52a0\u5165\u96c6\u5408a\u3002 a . add ( 7 ) print ( a ) # {1, 2, 'c', 7, 'a', 'b'} \u6bcf\u6b21\u8f93\u51fa\u7684\u987a\u5e8f\u662f\u4e0d\u4e00\u6837\u7684 \u4ece\u96c6\u5408a\u79fb\u9664\u67d0\u4e2a\u5143\u7d20\u3002 a . remove ( 7 ) print ( a ) # {1, 2, 'c', 'a', 'b'} \u5982\u679ca\u88ab\u6e05\u7a7a\uff0c\u5219\u62a5\u9519 KeyError: 7 \u6240\u6709\u5728a\u6216b\u4e2d\uff0c\u4f46\u4e0d\u662f\u540c\u65f6\u5728a\u3001b\u4e2d\u7684\u5143\u7d20\u3002 print ( a . symmetric_difference ( b )) # {2, 'd', 'b', 'a'} print ( a ^ b ) # {2, 'd', 'b', 'a'} \u5c06a\u7684\u5185\u5bb9\u8bbe\u4e3a\u6240\u6709\u5728a\u6216b\u4e2d\uff0c\u4f46\u4e0d\u662f\u540c\u65f6\u5728a\u3001b\u4e2d\u7684\u5143\u7d20\u3002 a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a . symmetric_difference_update ( b ) print ( a ) # {'a', 2, 'd', 'b'} a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a ^= b print ( a ) # {2, 'd', 'a', 'b'} \u5982\u679ca\u5305\u542b\u4e8eb\uff0c\u8fd4\u56deTure\u3002 print ( a . issubset ( b )) # False \u5c06a\u7684\u5185\u5bb9\u8bbe\u7f6e\u4e3aa\u548cb\u7684\u5e76\u96c6\u3002 print ( a ) # {'a', 2, 'd', 'b'} a = { 'a' , 'b' , 'c' , 1 , 2 } a . update ( b ) print ( a ) # {1, 2, 'a', 'b', 'd', 'c'} \u79fb\u9664\u4efb\u610f\u5143\u7d20\uff0c\u5982\u679c\u96c6\u5408\u662f\u7a7a\u7684\uff0c\u629b\u51fakeyError\u3002 a . pop () # \u968f\u673a\u79fb\u9664\u67d0\u4e2a\u5143\u7d20\uff0c\u6ca1\u6709\u8f93\u5165\u53d8\u91cf\uff0c\u5982\u679c\u96c6\u5408\u662f\u7a7a\u7684\uff0c\u629b\u51faKeyError: 'pop from an empty set' print ( a ) # {2, 1, 'd', 'b', 'a'} \u5c06\u96c6\u5408\u91cd\u7f6e\u4e3a\u7a7a\uff0c\u6e05\u7a7a\u6240\u6709\u5143\u7d20\u3002 a . clear () print ( a ) # set() \u96c6\u5408\u7684\u5143\u7d20\u5fc5\u987b\u662f\u4e0d\u53ef\u53d8\u7684\uff0c\u5982\u679c\u60f3\u8981\u5305\u542b\u5217\u8868\u578b\u7684\u5143\u7d20\uff0c\u5fc5\u987b\u5148\u8f6c\u6362\u4e3a\u5143\u7ec4\u3002 my_data1 = [ 1 , 2 , 3 , 4 ] my_data2 = [ 3 , 4 , 5 , 6 ] my_set = { tuple ( my_data1 ), tuple ( my_data2 )} print ( my_set ) # {(1, 2, 3, 4), (3, 4, 5, 6)} 1.6 \u5143\u7ec4\uff08tuple\uff09 \u00b6 Python \u7684\u5143\u7ec4\u4e0e\u5217\u8868\u7c7b\u4f3c\uff0c\u4e0d\u540c\u4e4b\u5904\u5728\u4e8e\u5143\u7ec4\u7684\u5143\u7d20\u4e0d\u80fd\u4fee\u6539\u3002 \u5143\u7ec4\u4f7f\u7528\u5c0f\u62ec\u53f7( )\uff0c\u5217\u8868\u4f7f\u7528\u65b9\u62ec\u53f7[ ]\u3002 \u5143\u7ec4\u4e2d\u53ea\u5305\u542b\u4e00\u4e2a\u5143\u7d20\u65f6\uff0c\u9700\u8981\u5728\u5143\u7d20\u540e\u9762\u6dfb\u52a0\u9017\u53f7 \uff0c\u5426\u5219\u62ec\u53f7\u4f1a\u88ab\u5f53\u4f5c\u8fd0\u7b97\u7b26\u4f7f\u7528\u3002 \u5143\u7ec4\u53ef\u4ee5\u4f7f\u7528\u4e0b\u6807\u7d22\u5f15\u6765\u8bbf\u95ee\u5143\u7ec4\u4e2d\u7684\u503c\u3002 \u5143\u7ec4\u4e2d\u7684\u5143\u7d20\u503c\u662f\u4e0d\u5141\u8bb8\u4fee\u6539\u7684\uff0c\u4f46\u6211\u4eec\u53ef\u4ee5\u5bf9\u5143\u7ec4\u8fdb\u884c\u8fde\u63a5\u7ec4\u5408\u3002 \u5143\u7ec4\u4e2d\u7684\u5143\u7d20\u503c\u662f\u4e0d\u5141\u8bb8\u5220\u9664\u7684\uff0c\u4f46\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528del\u8bed\u53e5\u6765\u5220\u9664\u6574\u4e2a\u5143\u7ec4\u3002 # \u6b64\u5904\u62ec\u53f7\u88ab\u89e3\u6790\u4e3a\u8fd0\u7b97\u7b26\uff0c\u9700\u8981\u5728\u540e\u9762\u52a0\u4e0a\u9017\u53f7\u624d\u4f1a\u88ab\u89e3\u91ca\u4e3a\u5143\u7ec4 tup1 = ( 10 ) print ( type ( tup1 )) # tup1 = ( 10 ,) print ( type ( tup1 )) # \u521b\u5efa\u5143\u7ec4\u6700\u7b80\u5355\u7684\u529e\u6cd5\u5c31\u662f\u7528\u9017\u53f7\u5206\u9694\u5e8f\u5217\u503c\u3002\u5143\u7ec4\u5bf9\u6570\u636e\u7c7b\u578b\u6ca1\u6709\u4e00\u81f4\u6027\u8981\u6c42\u3002 tup = 4 , 5 , 6 print ( tup ) # (4, 5, 6) nested_tup = ( 4 , 5 , 6 ), ( 7 , 8 ) print ( nested_tup ) # # ((4, 5, 6), (7, 8)) tup = ( 'a' , 'b' , { 'one' : 1 }) print ( type ( tup )) # \u4f7f\u7528\u52a0\u53f7\uff08+\uff09\u8fdb\u884c\u5143\u7ec4\u8fde\u63a5\u5408\u5e76\u3002 tup = tuple (( 4 , None , 'fool' ) + ( 6 , 0 ) + ( 'bar' ,)) print ( tup ) # (4, None, 'fool', 6, 0, 'bar') \u5143\u7ec4\u7684\u4e0d\u53ef\u53d8\u6307\u7684\u662f**\u5143\u7ec4\u6240\u6307\u5411\u7684\u5185\u5b58\u4e2d\u7684\u5185\u5bb9\u4e0d\u53ef\u53d8**\u3002 tup = ( 'h' , 'e' , 'l' , 'l' , 'o' ) print ( id ( tup )) # 139820353350208 tup = ( 1 , 2 , 3 , 4 , 5 ) print ( id ( tup )) # 139820353298896 tup [ 0 ] = 'x' # Traceback (most recent call last): # File \"\", line 1, in # TypeError: 'tuple' object does not support item assignment \u5c06\u5143\u7ec4\u4e58\u4ee5\u6574\u6570\uff0c\u5219\u4f1a\u548c\u5217\u8868\u4e00\u6837\uff0c\u751f\u6210\u542b\u6709\u591a\u4efd\u62f7\u8d1d\u7684\u5143\u7ec4\u3002\u5bf9\u8c61\u81ea\u8eab\u5e76\u6ca1\u6709\u590d\u5236\uff0c\u53ea\u662f\u6307\u5411\u5b83\u4eec\u7684\u5f15\u7528\u8fdb\u884c\u4e86\u590d\u5236\u3002 tup = tuple (( 'fool' , 'bar' ) * 4 ) print ( tup ) # ('fool', 'bar', 'fool', 'bar', 'fool', 'bar', 'fool', 'bar') \u5982\u679c\u5143\u7ec4\u4e2d\u7684\u4e00\u4e2a\u5bf9\u8c61\u662f\u53ef\u53d8\u7684\uff0c\u4f8b\u5982\u5217\u8868\uff0c\u4f60\u53ef\u4ee5\u5728\u5b83\u5185\u90e8\u8fdb\u884c\u4fee\u6539\u3002 tup = tuple ([ 'foo' , [ 4 , 5 , 6 ], True ]) tup [ 1 ] . append ( 0 ) print ( tup ) # ('foo', [4, 5, 6, 0], True) tup [ 1 ] . append ([ 9 ]) print ( tup ) # ('foo', [4, 5, 6, 0, [9]], True) \u4f7f\u7528tuple\u51fd\u6570\u5c06\u4efb\u610f\u5e8f\u5217\u6216\u8fed\u4ee3\u5668\u8f6c\u6362\u4e3a\u5143\u7ec4\u3002 tup = tuple ([ 4 , 5 , 6 ]) print ( tup ) # (4, 5, 6) tup = tuple ( 'string' ) print ( tup ) # ('s', 't', 'r', 'i', 'n', 'g') print ( tup [ 2 ]) # r # \u5143\u7ec4\u7684\u5143\u7d20\u53ef\u4ee5\u901a\u8fc7\u4e2d\u62ec\u53f7[]\u6765\u83b7\u53d6 \u5982\u679c\u8981\u5c06\u5143\u7ec4\u578b\u7684\u8868\u8fbe\u5f0f\u8d4b\u503c\u7ed9\u53d8\u91cf\uff0cPython\u4f1a\u5bf9\u7b49\u53f7\u53f3\u8fb9\u7684\u503c\u8fdb\u884c \u62c6\u5305 \u3002 tup = ( 9 , 5 , ( 8 , 7 )) a , b , c = tup print ( a ) # 9 print ( b ) # 5 print ( c ) # (8, 7) a , b , ( c , d ) = tup print ( a ) # 9 print ( b ) # 5 print ( c ) # 8 print ( d ) # 7 tup = ( 9 , 5 , ( 8 , 7 )) a , b , c = tup c , a = a , c # \u5229\u7528\u62c6\u5305\u5b9e\u73b0\u4ea4\u6362 print ( a ) # (8, 7) print ( b ) # 5 print ( c ) # 9 \u5229\u7528\u62c6\u5305\u5b9e\u73b0\u904d\u5386\u5143\u7ec4\u6216\u5217\u8868\u7ec4\u6210\u7684\u5e8f\u5217\u3002 seq = [( 1 , 2 , 3 ), ( 4 , 5 , 6 ), ( 7 , 8 , 9 )] for a , b , c in seq : print ( 'a= {0} , b= {0} , c= {0} ' . format ( a , b , c )) # \u5217\u8868\u6bcf\u4e2a\u5143\u7d20\u7684\u53d6\u503c\u987a\u5e8f # a=1, b=1, c=1 # a=4, b=4, c=4 # a=7, b=7, c=7 print ( 'a= {0} , b= {1} , c= {2} ' . format ( a , b , c )) # a=1, b=2, c=3 # a=4, b=5, c=6 # a=7, b=8, c=9 print ( 'a= {2} , b= {0} , c= {1} ' . format ( a , b , c )) # a=3, b=1, c=2 # a=6, b=4, c=5 # a=9, b=7, c=8 \u5143\u7ec4\u62c6\u5305\u529f\u80fd\u8fd8\u5305\u62ec\u7279\u6b8a\u7684\u8bed\u6cd5*rest\u3002\u5f88\u591aPython\u7f16\u7a0b\u8005\u4f1a\u4f7f\u7528\u4e0b\u5212\u7ebf\uff08_\uff09\u6765\u8868\u793a\u4e0d\u60f3\u8981\u7684\u53d8\u91cf\u3002 values = 1 , 2 , 3 , 4 , 5 a , b , * rest = values print ( a ) # 1 print ( b ) # 2 print ( * rest ) # 3 4 5 a , b , * _ = values print ( * _ ) # 3 4 5 \u5177\u540d\u5143\u7ec4\u3002 collections.namedtuple \u662f\u4e00\u4e2a\u5de5\u5382\u51fd\u6570\uff0c\u5b83\u53ef\u4ee5\u7528\u6765\u6784\u5efa\u4e00\u4e2a\u5e26\u5b57\u6bb5\u540d\u7684\u5143\u7ec4\u548c\u4e00\u4e2a\u6709\u540d\u5b57\u7684\u7c7b\u3002 \u7528namedtuple\u6784\u5efa\u7684\u7c7b\u7684\u5b9e\u4f8b\u6240\u6d88\u8017\u7684\u5185\u5b58\u8ddf\u5143\u7ec4\u662f\u4e00\u6837\u7684\uff0c\u56e0\u4e3a\u5b57\u6bb5\u540d\u90fd\u88ab\u5b58\u5728\u5bf9\u5e94\u7684\u7c7b\u91cc\u9762\u3002 \u521b\u5efa\u4e00\u4e2a\u5177\u540d\u5143\u7ec4\u9700\u8981\u4e24\u4e2a\u53c2\u6570\uff0c\u4e00\u4e2a\u662f\u7c7b\u540d( City )\uff0c\u53e6\u4e00\u4e2a\u662f\u7c7b\u7684\u5404\u4e2a\u5b57\u6bb5\u7684\u540d\u5b57( 'name country population coordinates' )\u3002\u540e\u8005\u53ef\u4ee5\u662f\u7531\u6570\u4e2a\u5b57\u7b26\u4e32\u7ec4\u6210\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff0c\u6216\u8005\u662f\u7531\u7a7a\u683c\u5206\u9694\u5f00\u7684\u5b57\u6bb5\u540d\u7ec4\u6210\u7684\u5b57\u7b26\u4e32\u3002 \u5b58\u653e\u5728\u5bf9\u5e94\u5b57\u6bb5\u91cc\u7684\u6570\u636e\u8981\u4ee5\u4e00\u4e32\u53c2\u6570\u7684\u5f62\u5f0f\u4f20\u5165\u5230\u6784\u9020\u51fd\u6570\u4e2d\uff08\u6ce8\u610f\uff0c\u5143\u7ec4\u7684\u6784\u9020\u51fd\u6570\u5374\u53ea\u63a5\u53d7\u5355\u4e00\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff09\u3002 \u5177\u540d\u5143\u7ec4\u8fd8\u6709\u4e00\u4e9b\u81ea\u5df1\u4e13\u6709\u7684\u5c5e\u6027\u3002\u4e0b\u9762\u5c55\u793a\u4e86\u51e0\u4e2a\u6700\u6709\u7528\u7684\uff1a _fields \u7c7b\u5c5e\u6027\u3001\u7c7b\u65b9\u6cd5 _make(iterable) \u548c\u5b9e\u4f8b\u65b9\u6cd5 _asdict() \u3002 _fields \u5c5e\u6027\u662f\u4e00\u4e2a\u5305\u542b\u8fd9\u4e2a\u7c7b\u6240\u6709\u5b57\u6bb5\u540d\u79f0\u7684\u5143\u7ec4\u3002 \u7528 _make() \u901a\u8fc7\u63a5\u53d7\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u6765\u751f\u6210\u8fd9\u4e2a\u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u5b83\u7684\u4f5c\u7528\u8ddf City(*delhi_data) \u662f\u4e00\u6837\u7684\u3002 _asdict() \u628a\u5177\u540d\u5143\u7ec4\u4ee5 collections.OrderedDict \u7684\u5f62\u5f0f\u8fd4\u56de\uff0c\u6211\u4eec\u53ef\u4ee5\u5229\u7528\u5b83\u6765\u628a\u5143\u7ec4\u91cc\u7684\u4fe1\u606f\u53cb\u597d\u5730\u5448\u73b0\u51fa\u6765\u3002 from collections import namedtuple City = namedtuple ( 'City' , 'name country population coordinates' ) tokyo = City ( 'Tokyo' , 'JP' , 36.933 , ( 35.689722 , 139691667 )) print ( tokyo ) # City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139691667)) print ( tokyo . population ) # 36.933 print ( tokyo [ 3 ]) # (35.689722, 139691667) print ( City . _fields ) # ('name', 'country', 'population', 'coordinates') LatLong = namedtuple ( 'LatLong' , 'lat long' ) delhi_data = ( 'Delhi NCR' , 'IN' , 21.935 , LatLong ( 28.613899 , 77.208889 )) delhi = City . _make ( delhi_data ) print ( delhi ) # City(name='Delhi NCR', country='IN', population=21.935, coordinates=LatLong(lat=28.613899, long=77.208889)) print ( delhi . _asdict ()) # OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935), ('coordinates', LatLong(lat=28.613899, long=77.208889))]) for key , value in delhi . _asdict () . items (): print ( key + ':' , value ) # name: Delhi NCR # country: IN # population: 21.935 # coordinates: LatLong(lat=28.613899, long=77.208889) \u5143\u7ec4\u8fd8\u6709\u7b2c\u4e8c\u91cd\u529f\u80fd\uff1a\u4f5c\u4e3a\u4e0d\u53ef\u53d8\u5217\u8868\u7684\u5143\u7ec4\u3002 \u4e0b\u9762\u662f\u5217\u8868\u6216\u5143\u7ec4\u7684\u65b9\u6cd5\u548c\u5c5e\u6027\u5bf9\u6bd4\u3002\u9664\u4e86\u8ddf\u589e\u51cf\u5143\u7d20\u76f8\u5173\u7684\u65b9\u6cd5\u4e4b\u5916\uff0c\u5143\u7ec4\u652f\u6301\u5217\u8868\u7684\u5176\u4ed6\u6240\u6709\u65b9\u6cd5\u3002\u8fd8\u6709\u4e00\u4e2a\u4f8b\u5916\uff0c\u5143\u7ec4\u6ca1\u6709__reversed__\u65b9\u6cd5\u3002 \u4e00\u4e2a\u5173\u4e8e+=\u548c*=\u7684\u8c1c\u9898\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u5c55\u793a\u4e86 *= \u5728\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u5e8f\u5217\u4e0a\u7684\u4f5c\u7528\u3002\u5217\u8868\u7684ID\u6ca1\u53d8\uff0c\u65b0\u5143\u7d20\u8ffd\u52a0\u5230\u5217\u8868\u4e0a\uff0c\u4f46\u6267\u884c\u589e\u91cf\u4e58\u6cd5\u540e\uff0c\u65b0\u7684\u5143\u7ec4\u88ab\u521b\u5efa\u3002 list1 = [ 1 , 2 , 3 , 4 ] id ( list1 ) # 140409777308808 list1 *= 2 print ( list1 ) # [1, 2, 3, 4, 1, 2, 3, 4] id ( list1 ) # 140409777308808 tuple1 = ( 1 , 2 , 3 , 4 ) id ( tuple1 ) # 140409777230536 tuple1 *= 2 print ( tuple1 ) # (1, 2, 3, 4, 1, 2, 3, 4) id ( tuple1 ) # 140409780104888 \u4f46\u5bf9\u4e8e\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u867d\u7136 tuple1[2] += [50, 60] \u6267\u884c\u65f6\u6709\u5f02\u5e38\u629b\u51fa\uff0c\u4f46 tuple1 \u5374\u88ab\u4fee\u6539\u4e86\u3002 t = ( 1 , 2 , [ 10 , 20 ]) t [ 2 ] += [ 50 , 60 ] # TypeError: 'tuple' object does not support item assignment print ( t ) # (1, 2, [10, 20, 50, 60]) \u4e0b\u56fe\u5927\u81f4\u63cf\u8ff0\u4e86\u4e0a\u8ff0\u6267\u884c\u8fc7\u7a0b\u3002 \u4e3a\u4e86\u907f\u514d\u4e0a\u9762\u60c5\u51b5\u7684\u53d1\u751f\uff0c\u6211\u4eec**\u4e0d\u8981\u628a\u53ef\u53d8\u5bf9\u8c61\u653e\u5728\u5143\u7ec4\u91cc\u9762**\u3002\u589e\u91cf\u8d4b\u503c\u4e0d\u662f\u4e00\u4e2a\u539f\u5b50\u64cd\u4f5c\uff0c\u5b83\u867d\u7136\u629b\u51fa\u4e86\u5f02\u5e38\uff0c\u4f46\u8fd8\u662f\u5b8c\u6210\u4e86\u64cd\u4f5c\u3002 1.7 \u5185\u5b58\u89c6\u56feMemoryview \u00b6 memoryview \u662f\u4e00\u4e2a\u5185\u7f6e\u7c7b\uff0c\u5b83\u80fd\u8ba9\u7528\u6237\u5728\u4e0d\u590d\u5236\u5185\u5bb9\u7684\u60c5\u51b5\u4e0b\u64cd\u4f5c\u540c\u4e00\u4e2a\u6570\u7ec4\u7684\u4e0d\u540c\u5207\u7247\u3002 \u5185\u5b58\u89c6\u56fe\u5176\u5b9e\u662f\u6cdb\u5316\u548c\u53bb\u6570\u5b66\u5316\u7684NumPy\u6570\u7ec4\u3002\u5b83\u8ba9\u4f60\u5728\u4e0d\u9700\u8981\u590d\u5236\u5185\u5bb9\u7684\u524d\u63d0\u4e0b\uff0c\u5728\u6570\u636e\u7ed3\u6784\u4e4b\u95f4\u5171\u4eab\u5185\u5b58\u3002 \u5176\u4e2d\u6570\u636e\u7ed3\u6784\u53ef\u4ee5\u662f\u4efb\u4f55\u5f62\u5f0f\uff0c\u6bd4\u5982PIL\u56fe\u7247\u3001SQLite\u6570\u636e\u5e93\u548cNumPy\u7684\u6570\u7ec4\uff0c\u7b49\u7b49\u3002\u8fd9\u4e2a\u529f\u80fd\u5728\u5904\u7406\u5927\u578b\u6570\u636e\u96c6\u5408\u7684\u65f6\u5019\u975e\u5e38\u91cd\u8981\u3002 memoryview.cast \u7684\u6982\u5ff5\u8ddf\u6570\u7ec4\u6a21\u5757\u7c7b\u4f3c\uff0c\u80fd\u7528\u4e0d\u540c\u7684\u65b9\u5f0f\u8bfb\u5199\u540c\u4e00\u5757\u5185\u5b58\u6570\u636e\uff0c\u800c\u4e14\u5185\u5bb9\u5b57\u8282\u4e0d\u4f1a\u968f\u610f\u79fb\u52a8\u3002\u8fd9\u8ddfC\u8bed\u8a00\u4e2d\u7c7b\u578b\u8f6c\u6362\u7684\u6982\u5ff5\u5dee\u4e0d\u591a\u3002 memoryview.cast \u4f1a\u628a\u540c\u4e00\u5757\u5185\u5b58\u91cc\u7684\u5185\u5bb9\u6253\u5305\u6210\u4e00\u4e2a\u5168\u65b0\u7684memoryview\u5bf9\u8c61\u7ed9\u4f60\u3002 array \u91cc\u9762\u7684Type code\uff1a 'b' signed integer 1 'B' unsigned integer 1 'u' Unicode character 2 (see note) 'h' signed integer 2 'H' unsigned integer 2 'i' signed integer 2 'I' unsigned integer 2 'l' signed integer 4 'L' unsigned integer 4 'q' signed integer 8 (see note) 'Q' unsigned integer 8 (see note) 'f' floating point 4 'd' floating point 8 numbers = array ( 'h' , [ - 2 , - 1 , 0 , 1 , 2 ]) # array('h', [-2, -1, 0, 1, 2]) # \u75285\u4e2a\u77ed\u6574\u578b\u6709\u7b26\u53f7\u6574\u6570\u7684\u6570\u7ec4\uff08\u7c7b\u578b\u7801\u662f'h'\uff09\u521b\u5efa\u4e00\u4e2amemoryview\u3002 memv = memoryview ( numbers ) # memv\u91cc\u76845\u4e2a\u5143\u7d20\u8ddf\u6570\u7ec4\u91cc\u7684\u6ca1\u6709\u533a\u522b\u3002 print ( len ( memv )) # 5 print ( memv [ 0 ]) # -2 print ( memv . tolist ()) # [-2, -1, 0, 1, 2] # \u521b\u5efa\u4e00\u4e2amemv_oct\uff0c\u8fd9\u4e00\u6b21\u662f\u628amemv\u91cc\u7684\u5185\u5bb9\u8f6c\u6362\u6210'B'\u7c7b\u578b\uff0c\u4e5f\u5c31\u662f\u65e0\u7b26\u53f7\u5b57\u7b26\u3002 memv_oct = memv . cast ( 'B' ) print ( memv_oct . tolist ()) # [254, 255, 255, 255, 0, 0, 1, 0, 2, 0] # \u628a\u4f4d\u4e8e\u4f4d\u7f6e5\u7684\u5b57\u8282\u8d4b\u503c\u62104\u3002\u56e0\u4e3a\u6211\u4eec\u628a\u53602\u4e2a\u5b57\u8282\u7684\u6574\u6570\u7684\u9ad8\u4f4d\u5b57\u8282\u6539\u6210\u4e864\uff0c\u6240\u4ee5\u8fd9\u4e2a\u6709\u7b26\u53f7\u6574\u6570\u7684\u503c\u5c31\u53d8\u6210\u4e861024\u3002 memv_oct [ 5 ] = 4 print ( numbers ) # array('h', [-2, -1, 1024, 1, 2]) 2. \u52a8\u6001\u5f15\u7528\u3001\u5f3a\u7c7b\u578b \u00b6 \u661f\u53f7 * \u7684\u53c2\u6570\u4f1a\u4ee5\u5143\u7ec4(tuple)\u7684\u5f62\u5f0f\u5bfc\u5165\uff0c\u5b58\u653e\u6240\u6709\u672a\u547d\u540d\u7684\u53d8\u91cf\u53c2\u6570 def printinfo ( arg1 , * vartuple ): print ( \"\u8f93\u51fa\u4efb\u4f55\u4f20\u5165\u7684\u53c2\u6570: \" ) print ( arg1 ) print ( vartuple ) for var in vartuple : print ( var ) return printinfo ( 10 ) # 10 # () printinfo ( 70 , 60 , 50 ) # 70 # (60, 50) # 60 # 50 \u4e24\u4e2a\u661f\u53f7 ** \u7684\u53c2\u6570\u4f1a\u4ee5\u5b57\u5178\u7684\u5f62\u5f0f\u5bfc\u5165\u3002 def printinfo ( arg1 , ** vardict ): print ( \"\u8f93\u51fa\u4efb\u4f55\u4f20\u5165\u7684\u53c2\u6570: \" ) print ( arg1 ) print ( vardict ) printinfo ( 1 , a = 2 , b = 3 ) # 1 # {'a': 2, 'b': 3} \u5b57\u5178\u683c\u5f0f\u8f93\u51fa Python\u4e2d\u7684\u5bf9\u8c61\u5f15\u7528\u5e76\u4e0d\u6d89\u53ca\u7c7b\u578b\u3002\u53d8\u91cf\u5bf9\u4e8e\u5bf9\u8c61\u6765\u8bf4\u53ea\u662f\u7279\u5b9a\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u540d\u79f0\uff1b\u7c7b\u578b\u4fe1\u606f\u662f\u5b58\u50a8\u5728\u5bf9\u8c61\u81ea\u8eab\u4e4b\u4e2d\u3002 a = 5 print ( type ( a )) # a = 'foo' print ( type ( a )) # Python\u662f\u5f3a\u7c7b\u578b\u8bed\u8a00\uff0c\u6240\u6709\u7684\u5bf9\u8c61\u90fd\u62e5\u6709\u4e00\u4e2a\u6307\u5b9a\u7684\u7c7b\u578b\uff08\u6216\u7c7b\uff09\uff0c\u9690\u5f0f\u7684\u8f6c\u6362\u53ea\u5728\u67d0\u4e9b\u7279\u5b9a\u3001\u660e\u663e\u7684\u60c5\u51b5\u4e0b\u53d1\u751f\u3002 a = 4.5 b = 2 print ( 'a is {0} , b is {1} ' . format ( type ( a ), type ( b ))) # a is , b is \u5b57\u4e32\u683c\u5f0f\u5316\uff0c\u7528\u4e8e\u540e\u7eed\u8bbf\u95ee print ( a / b ) # 2.25 \u4f7f\u7528isinstance\u51fd\u6570\u6765\u68c0\u67e5\u4e00\u4e2a\u5bf9\u8c61\u662f\u5426\u662f\u7279\u5b9a\u7c7b\u578b\u7684\u5b9e\u4f8b\u3002isinstance\u63a5\u53d7\u4e00\u4e2a\u5305\u542b\u7c7b\u578b\u7684\u5143\u7ec4\uff0c\u53ef\u4ee5\u68c0\u67e5\u5bf9\u8c61\u7684\u7c7b\u578b\u662f\u5426\u5728\u5143\u7ec4\u4e2d\u7684\u7c7b\u578b\u4e2d\u3002 a = 5 b = 4.5 c = 'foo' print ( isinstance ( a , int )) # True print ( isinstance ( b , str )) # False print ( isinstance ( c , ( str , int ))) # True print ( isinstance ( c , ( float , int ))) # False \u5c5e\u6027\u548c\u65b9\u6cd5\u4e5f\u53ef\u4ee5\u901a\u8fc7getattr\u51fd\u6570\u83b7\u5f97\u3002\u5728\u5176\u4ed6\u7684\u8bed\u8a00\u4e2d\uff0c\u901a\u8fc7\u53d8\u91cf\u540d\u8bbf\u95ee\u5bf9\u8c61\u901a\u5e38\u88ab\u79f0\u4e3a\u201c\u53cd\u5c04\u201d\u3002 b = 'foo' print ( getattr ( b , 'split' )) # 3. \u4e8c\u5143\u8fd0\u7b97\u7b26\u548c\u6bd4\u8f83\u8fd0\u7b97 \u00b6 \u68c0\u67e5\u4e24\u4e2a\u5f15\u7528\u662f\u5426\u6307\u5411\u540c\u4e00\u4e2a\u5bf9\u8c61\uff0c\u53ef\u4ee5\u4f7f\u7528is\u5173\u952e\u5b57\u3002 is\u548cis not\u7684\u5e38\u7528\u4e4b\u5904\u662f\u68c0\u67e5\u4e00\u4e2a\u53d8\u91cf\u662f\u5426\u4e3aNone\uff0c\u56e0\u4e3aNone\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b\u3002 a = [ 1 , 2 , 3 ] b = a c = list ( a ) # list\u51fd\u6570\u603b\u662f\u521b\u5efa\u4e00\u4e2a\u65b0\u7684Python\u5217\u8868\uff08\u5373\u4e00\u4efd\u62f7\u8d1d\uff09 print ( a is b ) # True print ( a is not c ) # True print ( a == c ) # True d = None print ( d is None ) # True Python\u4e2d\u7684\u5927\u90e8\u5206\u5bf9\u8c61\uff0c\u4f8b\u5982\u5217\u8868\u3001\u5b57\u5178\u3001NumPy\u6570\u7ec4\u90fd\u662f\u53ef\u53d8\u5bf9\u8c61\uff0c\u5927\u591a\u6570\u7528\u6237\u5b9a\u4e49\u7684\u7c7b\u578b\uff08\u7c7b\uff09\u4e5f\u662f\u53ef\u53d8\u7684\u3002 \u53ef\u53d8\u5bf9\u8c61\u4e2d\u5305\u542b\u7684\u5bf9\u8c61\u548c\u503c\u662f\u53ef\u4ee5\u88ab\u4fee\u6539\u7684\u3002\u8fd8\u6709\u5176\u4ed6\u4e00\u4e9b\u5bf9\u8c61\u662f\u4e0d\u53ef\u53d8\u7684\uff0c\u6bd4\u5982\u5b57\u7b26\u4e32\u3001\u5143\u7ec4\u3002 a_list = [ 'foo' , 2 , [ 4 , 5 ]] # \u5217\u8868 a_list [ 2 ] = ( 3 , 4 ) print ( a_list ) # ['foo', 2, (3, 4)] a_tuple = ( 3 , 5 , ( 4 , 5 )) # \u5143\u7ec4 a_tuple [ 1 ] = 'four' # TypeError: 'tuple' object does not support item assignment \u4e0d\u53ef\u88ab\u4fee\u6539 print ( a_tuple ) # (3, 5, (4, 5)) 4. \u6807\u91cf\u7c7b\u578b \u00b6 Python\u6807\u91cf\u7c7b\u578b\uff1aNone, str, bytes, float, bool, int\u3002 \u6570\u503c\u7c7b\u578b\u3002 \u57fa\u7840\u7684Python\u6570\u5b57\u7c7b\u578b\u5c31\u662fint\u548cfloat\u3002int\u53ef\u4ee5\u5b58\u50a8\u4efb\u610f\u5927\u5c0f\u6570\u5b57\u3002\u6d6e\u70b9\u6570\u5728Python\u4e2d\u7528float\u8868\u793a\uff0c\u6bcf\u4e00\u4e2a\u6d6e\u70b9\u6570\u90fd\u662f\u53cc\u7cbe\u5ea664\u4f4d\u6570\u503c\u3002 ival = 17338971 print ( ival ** 6 ) # 27173145946003847721495630081806010734757321 fval = 17338971.0 print ( fval ** 6 ) # 2.7173145946003847e+43 print ( 3 / 2 ) # 1.5 print ( 3 // 2 ) # 1 \u5b57\u7b26\u4e32\u3002 Python\u7684\u5b57\u7b26\u4e32\u662f\u4e0d\u53ef\u53d8\u7684\u3002 a = 5.6 s = str ( a ) print ( s ) # 5.6 b = 'python' print ( list ( b )) # ['p', 'y', 't', 'h', 'o', 'n'] print ( b [ 2 ]) # t b [ 2 ] = 'f' # TypeError: 'str' object does not support item assignment \u5b57\u7b26\u4e32\u662f\u4e0d\u53ef\u53d8\u7684 \u53cd\u659c\u6760\u7b26\u53f7\\\u662f\u4e00\u79cd\u8f6c\u4e49\u7b26\u53f7\uff0c\u5b83\u7528\u6765\u6307\u660e\u7279\u6b8a\u7b26\u53f7\u3002 \u5982\u679c\u4f60\u6709\u4e00\u4e2a\u4e0d\u542b\u7279\u6b8a\u7b26\u53f7\u4f46\u542b\u6709\u5927\u91cf\u53cd\u659c\u6760\u7684\u5b57\u7b26\u4e32\u65f6\uff0c\u53ef\u4ee5\u5728\u5b57\u7b26\u4e32\u524d\u9762\u52a0\u4e00\u4e2a\u524d\u7f00\u7b26\u53f7r\uff0c\u8868\u660e\u8fd9\u4e9b\u5b57\u7b26\u662f\u539f\u751f\u5b57\u7b26\uff0cr\u662fraw\u7684\u7b80\u5199\uff0c\u8868\u793a\u539f\u751f\u7684\u3002 x = '12 \\\\ 34' y = r 'this\\has\\no\\special\\characters' print ( x ) # 12\\34 print ( y ) # this\\has\\no\\special\\characters \u5b57\u7b26\u4e32\u683c\u5f0f\u5316 {0:.2f}\u8868\u793a\u5c06\u7b2c\u4e00\u4e2a\u53c2\u6570\u683c\u5f0f\u5316\u4e3a2\u4f4d\u5c0f\u6570\u7684\u6d6e\u70b9\u6570 {1:s}\u8868\u793a\u5c06\u7b2c\u4e8c\u4e2a\u53c2\u6570\u683c\u5f0f\u5316\u4e3a\u5b57\u7b26\u4e32 {2:d}\u8868\u793a\u5c06\u7b2c\u4e09\u4e2a\u53c2\u6570\u683c\u5f0f\u5316\u6574\u6570 \u53c2\u8003Python\u5b98\u65b9\u6587\u6863 https://docs.python.org/3.6/library/string.html template = ' {0:.2f} {1:s} are worth US$ {2:d} ' print ( template . format ( 4.5560 , 'Argentine Pesos' , 1 )) # 4.56 Argentine Pesos are worth US$1 \u65e5\u671f\u548c\u65f6\u95f4 from datetime import datetime , date , time dt = datetime ( 2011 , 10 , 29 , 20 , 30 , 21 ) print ( dt . day ) # 29 print ( dt . minute ) # 30 print ( dt . date ()) # 2011-10-29 print ( dt . time ()) # 20:30:21 print ( dt . replace ( minute = 0 , second = 0 )) # 2011-10-29 20:00:00 \u5c06\u5206\u949f\u3001\u79d2\u66ff\u6362\u4e3a0 print ( datetime . strptime ( '20091021' , '%Y%m %d ' )) # 2009-10-21 00:00:00 \u5b57\u7b26\u4e32\u53ef\u4ee5\u901a\u8fc7 strptime \u51fd\u6570\u8f6c\u6362\u4e3adatetime\u5bf9\u8c61 dt2 = datetime ( 2011 , 11 , 15 , 22 , 30 ) delta = dt2 - dt print ( delta ) # 17 days, 1:59:39 print ( dt + delta ) # 2011-11-15 22:30:00 range\u51fd\u6570\u8fd4\u56de\u4e00\u4e2a\u8fed\u4ee3\u5668\uff0c\u8be5\u8fed\u4ee3\u5668\u751f\u6210\u4e00\u4e2a\u7b49\u5dee\u6574\u6570\u5e8f\u5217\u3002 print ( range ( 10 )) # range(0, 10) print ( list ( range ( 10 ))) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print ( list ( range ( 0 , 20 , 2 ))) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 5. \u4e09\u5143\u8868\u8fbe\u5f0f \u00b6 value = true-expr if condition else false-expr x = 5 print ( 'non-negative' if x >= 0 else 'negative' ) # non-negative","title":"Python\u8bed\u8a00\u57fa\u7840"},{"location":"python/Foundation/ch01/#python","text":"","title":"Python\u8bed\u8a00\u57fa\u7840"},{"location":"python/Foundation/ch01/#1-python6","text":"6\u4e2aPython\u6570\u636e\u7c7b\u578b\uff1a \u6570\u503c\u578b\uff08number\uff09\uff1a\u8868\u793a\u6570\u636e\u7ec4\u6210\u4e3a\u6570\u5b57 \u6574\u578b\uff08int\uff09 \u5341\u8fdb\u5236 \u516b\u8fdb\u5236 \u5341\u516d\u8fdb\u5236 \u6d6e\u70b9\u578b\uff08float\uff09 \u5e03\u5c14\u578b\uff08bool\uff09 \u590d\u6570\u6027\uff08complex\uff09 \u5b57\u7b26\u578b\uff08string\uff09\uff1a\u8868\u793a\u6570\u636e\u7ec4\u6210\u662f\u5b57\u7b26 \u5217\u8868\uff08list\uff09\uff1a\u7528\u6765\u8868\u793a\u4e00\u7ec4\u6709\u5e8f\u5143\u7d20\uff0c\u540e\u671f\u6570\u636e\u53ef\u4ee5\u4fee\u6539 ['A','B','C'] \u5143\u7ec4\uff08tuple\uff09\uff1a\u7528\u6765\u8868\u793a\u4e00\u7ec4\u6709\u5e8f\u5143\u7d20\uff0c\u540e\u671f\u6570\u636e\u4e0d\u53ef\u4fee\u6539 ('A','B','C','1') \u96c6\u5408\uff08set\uff09\uff1a\u4e00\u7ec4\u6570\u636e\u65e0\u5e8f\u4e0d\u91cd\u590d\u5143\u7d20 set([1,2,3,4]) \u5b57\u5178\uff08dictionary\uff09\uff1a\u7528\u952e\u503c\u5bf9\u7684\u5f62\u5f0f\u4fdd\u5b58\u4e00\u7ec4\u5143\u7d20 {'A':7,'B':1,'C':9} \u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08Iterable\uff09\uff1a An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict, file objects, and objects of any classes you define with an iter() method or with a getitem() method that implements Sequence semantics. \u5e8f\u5217\uff08Sequence\uff09\uff1a An iterable which supports efficient element access using integer indices via the getitem() special method and defines a len() method that returns the length of the sequence. Some built-in sequence types are list, str, tuple, and bytes. Note that dict also supports getitem() and len(), but is considered a mapping rather than a sequence because the lookups use arbitrary immutable keys rather than integers. \u8fed\u4ee3\u5668\uff08Iterator\uff09\uff1a An object representing a stream of data. Repeated calls to the iterator\u2019s next() method (or passing it to the built-in function next()) return successive items in the stream. When no more data are available a StopIteration exception is raised instead. At this point, the iterator object is exhausted and any further calls to its next() method just raise StopIteration again. Iterators are required to have an iter() method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a list) produces a fresh new iterator each time you pass it to the iter() function or use it in a for loop. Attempting this with an iterator will just return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container. \u53ef\u53d8\u6570\u636e\uff08immutable\uff09 \u5217\u8868\uff08list\uff09 \u5b57\u5178\uff08dictionary\uff09 \u96c6\u5408\uff08set\uff09\u3002 \u4e0d\u53ef\u53d8\u6570\u636e\uff08immutable\uff09 \u6570\u5b57\uff08number\uff09 \u5b57\u7b26\uff08string\uff09 \u5143\u7ec4\uff08tuple\uff09 \u53ef\u8fed\u4ee3\uff08iterable\uff09 \u5b57\u7b26\uff08string\uff09 \u5143\u7ec4\uff08tuple\uff09 \u5217\u8868\uff08list\uff09 \u5b57\u5178\uff08dictionary\uff09 \u96c6\u5408\uff08set\uff09 \u5e8f\u5217 \u6709\u5e8f\u5e8f\u5217\uff1a\u5b57\u7b26\uff08string\uff09\uff0c\u5143\u7ec4\uff08tuple\uff09\uff0c\u5217\u8868\uff08list\uff09 \u65e0\u5e8f\u5e8f\u5217\uff1a\u5b57\u5178\uff08dictionary\uff09\uff0c\u96c6\u5408\uff08set\uff09 Python\u5e8f\u5217\u7c7b\u578b\u6700\u5e38\u89c1\u7684\u5206\u7c7b\u5c31\u662f\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u5e8f\u5217\u3002\u4f46\u53e6\u5916\u4e00\u79cd\u5206\u7c7b\u65b9\u5f0f\u4e5f\u5f88\u6709\u7528\uff0c\u90a3\u5c31\u662f\u628a\u5b83\u4eec\u5206\u4e3a**\u6241\u5e73\u5e8f\u5217**\u548c**\u5bb9\u5668\u5e8f\u5217**\u3002\u524d\u8005\u7684\u4f53\u79ef\u66f4\u5c0f\u3001\u901f\u5ea6\u66f4\u5feb\u800c\u4e14\u7528\u8d77\u6765\u66f4\u7b80\u5355\uff0c\u4f46\u662f\u5b83\u53ea\u80fd\u4fdd\u5b58\u4e00\u4e9b\u539f\u5b50\u6027\u7684\u6570\u636e\uff0c\u6bd4\u5982\u6570\u5b57\u3001\u5b57\u7b26\u548c\u5b57\u8282\u3002\u5bb9\u5668\u5e8f\u5217\u5219\u6bd4\u8f83\u7075\u6d3b\uff0c\u4f46\u662f\u5f53\u5bb9\u5668\u5e8f\u5217\u9047\u5230\u53ef\u53d8\u5bf9\u8c61\u65f6\uff0c\u5c31\u9700\u8981\u683c\u5916\u5c0f\u5fc3\uff0c\u56e0\u4e3a\u8fd9\u79cd\u7ec4\u5408\u65f6\u5e38\u4f1a\u51fa\u73b0\u4e00\u4e9b\u201c\u610f\u5916\u201d\uff0c\u7279\u522b\u662f\u5e26\u5d4c\u5957\u7684\u6570\u636e\u7ed3\u6784\u51fa\u73b0\u65f6\uff0c\u66f4\u9700\u8981\u9a8c\u8bc1\u4ee3\u7801\u7684\u6b63\u786e\u6027\u3002 Python\u4e2d\u7684\u53d8\u91cf\u3001\u5e38\u91cf\u548c\u5b57\u9762\u91cf \u53d8\u91cf \u53d8\u91cf\u662f\u7528\u4e8e\u5728\u5185\u5b58\u4e2d\u5b58\u50a8\u6570\u636e\u7684\u547d\u540d\u4f4d\u7f6e\u3002\u53ef\u4ee5\u5c06\u53d8\u91cf\u89c6\u4e3a\u4fdd\u5b58\u6570\u636e\u7684\u5bb9\u5668\uff0c\u8fd9\u4e9b\u6570\u636e\u53ef\u4ee5\u5728\u540e\u9762\u7a0b\u5e8f\u4e2d\u8fdb\u884c\u66f4\u6539\u3002\u4f8b\u5982\uff1a number = 10 \u3002\u4ece\u4f8b\u5b50\u4e2d\u53ef\u4ee5\u770b\u5230\uff0cPython\u4f7f\u7528\u8d4b\u503c\u8fd0\u7b97\u7b26 = \u4e3a\u53d8\u91cf\u8d4b\u503c\u3002 \u5e38\u91cf \u5e38\u91cf\u4e5f\u662f\u4e00\u79cd\u53d8\u91cf\uff0c\u53ea\u662f\u5176\u503c\u4e00\u65e6\u8d4b\u4e88\u540e\u65e0\u6cd5\u66f4\u6539\u3002\u53ef\u4ee5\u5c06\u5e38\u91cf\u89c6\u4e3a\u4fdd\u5b58\u4e86\u4ee5\u540e\u65e0\u6cd5\u66f4\u6539\u7684\u4fe1\u606f\u7684\u5bb9\u5668\u3002 \u5728Python\u4e2d\uff0c\u5e38\u91cf\u901a\u5e38\u662f\u5728\u6a21\u5757\u4e2d\u58f0\u660e\u548c\u5206\u914d\u7684\u3002\u5728\u8fd9\u91cc\uff0c\u6a21\u5757\u662f\u4e00\u4e2a\u5305\u542b\u53d8\u91cf\uff0c\u51fd\u6570\u7b49\u7684\u65b0\u6587\u4ef6\uff0c\u8be5\u6587\u4ef6\u88ab\u5bfc\u5165\u5230\u4e3b\u6587\u4ef6\u4e2d\u3002\u5728\u6a21\u5757\u5185\u90e8\uff0c\u7528\u6240\u6709\u5927\u5199\u5b57\u6bcd\u5199\u7684\u5e38\u91cf\u548c\u4e0b\u5212\u7ebf\u5c06\u5355\u8bcd\u5206\u5f00\u3002\u5b9e\u9645\u4e0a\uff0c\u6211\u4eec\u4e0d\u5728Python\u4e2d\u4f7f\u7528\u5e38\u91cf\u3002\u7528\u5927\u5199\u5b57\u6bcd\u547d\u540d\u5b83\u4eec\u662f\u4e00\u79cd\u5c06\u5176\u4e0e\u666e\u901a\u53d8\u91cf\u5206\u5f00\u7684\u4e00\u79cd\u7ea6\u5b9a\uff0c\u4f46\u662f\uff0c\u5b9e\u9645\u4e0a\u5e76\u4e0d\u80fd\u963b\u6b62\u91cd\u65b0\u5206\u914d\u3002 \u5b57\u9762\u91cf\uff08literal\uff09 \u5b57\u9762\u91cf\u662f\u4ee5\u53d8\u91cf\u6216\u5e38\u91cf\u7ed9\u51fa\u7684\u539f\u59cb\u6570\u636e\uff08\u5176\u5b9e\u5c31\u662f\u6307\u53d8\u91cf\u7684\u5e38\u6570\u503c\uff0c\u5b57\u9762\u4e0a\u6240\u770b\u5230\u7684\u503c\uff09\u3002\u5728Python\u4e2d\u5b57\u9762\u91cf\u7c7b\u578b\u5982\u4e0b\uff1a \u6570\u5b57\u5b57\u9762\u91cf\u3002\u6570\u5b57\u5b57\u9762\u91cf\u662f\u4e0d\u53ef\u53d8\u7684\uff08\u4e0d\u53ef\u66f4\u6539\uff09\u3002\u6570\u5b57\u5b57\u9762\u91cf\u53ef\u4ee5\u5c5e\u4e8e3\u79cd\u4e0d\u540c\u7684\u6570\u503c\u7c7b\u578b\uff1aInteger\uff0cFloat \u548c Complex\u3002\u4f8b\u5982\uff1a float_1 = 10.5 \u662f\u5c5e\u4e8eFloat\u5b57\u9762\u91cf\u3002 \u5b57\u7b26\u4e32\u5b57\u9762\u91cf\u662f\u7531\u5f15\u53f7\u62ec\u8d77\u6765\u7684\u4e00\u7cfb\u5217\u5b57\u7b26\u3002\u6211\u4eec\u53ef\u4ee5\u5bf9\u5b57\u7b26\u4e32\u4f7f\u7528\u5355\u5f15\u53f7\uff0c\u53cc\u5f15\u53f7 \u6216 \u4e09\u5f15\u53f7\u3002\u5e76\u4e14\uff0c\u5b57\u7b26\u5b57\u9762\u91cf\u662f\u7528\u5355\u5f15\u53f7\u6216\u53cc\u5f15\u53f7\u5f15\u8d77\u6765\u7684\u5355\u4e2a\u5b57\u7b26\u3002\u4f8b\u5982\uff1a strings = \"This is Python\" \u3002 \u5e03\u5c14\u5b57\u9762\u91cf\u3002\u5e03\u5c14\u5b57\u9762\u91cf\u53ef\u4ee5\u5177\u6709\u4e24\u4e2a\u503c\u4e2d\u7684\u4efb\u4f55\u4e00\u4e2a\uff1a True \u6216 False \u3002\u4f8b\u5982\uff1a a = True + 4 \u3002 \u7279\u6b8a\u5b57\u9762\u91cf\u3002Python\u5305\u542b\u4e00\u4e2a\u7279\u6b8a\u5b57\u9762\u91cf\uff0c\u5373 None \u3002 \u5b57\u9762\u91cf\u96c6\u3002\u6709\u56db\u79cd\u4e0d\u540c\u7684\u5b57\u9762\u91cf\u96c6\u5408\uff1a\u5217\u8868\u5b57\u9762\u91cf\uff0c\u5143\u7ec4\u5b57\u9762\u91cf\uff0c\u5b57\u5178\u5b57\u9762\u91cf \u548c \u96c6\u5408\u5b57\u9762\u91cf\u3002","title":"1. Python\u6570\u636e\u7c7b\u578b\uff086\u4e2a\uff09"},{"location":"python/Foundation/ch01/#11-number","text":"\u4f8b\u5b50\uff1a a , b , c , d = 20 , 5.5 , True , 4 + 3 j print ( a , b , c , d ) # 20 5.5 True (4+3j) print ( type ( a ), type ( b ), type ( c ), type ( d )) # Python\u4e5f\u53ef\u4ee5\u8fd9\u6837\u8d4b\u503c\uff1a a = b = c = d = 1 print ( a , b , c , d ) # 1 1 1 1 \u8fdb\u5236\u8f6c\u6362\uff1a a = - 15 print ( f ' { a } \u5bf9\u5e94\u7684\u5341\u8fdb\u5236\u662f { a } , \u4e8c\u8fdb\u5236\u662f { a : b } , \u516b\u8fdb\u5236\u662f { a : o } , \u5341\u516d\u8fdb\u5236\u662f { a : x } ' )","title":"1.1 \u6570\u503c\u578b\uff08number\uff09"},{"location":"python/Foundation/ch01/#12-string","text":"\u5355\u5f15\u53f7\uff1a\u5185\u5bb9\u4e2d\u5305\u542b\u5927\u91cf\u53cc\u5f15\u53f7 \u53cc\u5f15\u53f7\uff1a\u5185\u5bb9\u4e2d\u5305\u542b\u5927\u91cf\u5355\u5f15\u53f7 \u4e09\u5f15\u53f7\uff1a\u5185\u5bb9\u4e2d\u540c\u65f6\u5305\u542b\u5355\u53cc\u5f15\u53f7\uff0c\u4e09\u4e2a\u5355\u5f15\u53f7\u6bd4\u8f83\u597d\u3002 a = 'string is \"special\"' b = \"string's value\" c = '''string's value is \"special\"''' d = \"\"\"string's context \"\"\"","title":"1.2 \u5b57\u7b26\u578b\uff08string\uff09"},{"location":"python/Foundation/ch01/#_1","text":"\u5b57\u7b26\u4e32\u5207\u7247 s = 'Python is very good' print ( s [ 2 : 4 ]) # th print ( s [ 5 ]) # n print ( s [ - 1 ]) # d print ( s [ - 3 : - 1 ]) # oo # \u975e\u8fed\u4ee3\u578b\uff0c\u4e0d\u53ef\u4fee\u6539 s [ 3 ] = 'b' # Traceback (most recent call last): # File \"\", line 1, in # TypeError: 'str' object does not support item assignment \u5b57\u7b26\u4e32\u5408\u5e76 print ( s + '!!!' ) # Python is very good!!! replace( a,b \u5c06\u5b57\u7b26\u4e32\u4e2d\u7684 a \u66ff\u6362\u6210 b print ( s . replace ( 'is' , 'we' )) # Python we very good find(str) : \u8fd4\u56de str \u51fa\u73b0\u7684\u7d22\u5f15\u4f4d\u7f6e\uff0c\u5982\u679c\u627e\u4e0d\u5230\u8be5\u503c\uff0c\u5219 find() \u65b9\u6cd5\u5c06\u8fd4\u56de -1\u3002 print ( s . find ( 'a' )) # -1 print ( s . find ( 's' )) # 8 str.index(a): \u67e5\u627e\u6307\u5b9a\u503c\u7684\u9996\u6b21\u51fa\u73b0\u3002\u5982\u679c\u627e\u4e0d\u5230\u8be5\u503c\uff0cindex() \u65b9\u6cd5\u5c06\u5f15\u53d1\u5f02\u5e38\u3002 print ( s . index ( 's' )) # 8 print ( s . index ( 'a' )) # Traceback (most recent call last): # File \"\", line 1, in # ValueError: substring not found str.count(a): \u7edf\u8ba1\u5b57\u7b26\u4e32\u4e2d a \u51fa\u73b0\u7684\u6b21\u6570 print ( s . count ( 'a' )) # 0 print ( s . count ( 'o' )) # 3 split: \u5bf9\u5b57\u7b26\u4e32\u8fdb\u884c\u5206\u5272\u3002\u5982\u679c\u53c2\u6570 num \u6709\u6307\u5b9a\u503c\uff0c\u5219\u5206\u9694 num+1 \u4e2a\u5b50\u5b57\u7b26\u4e32\u3002 # \u6309\u7a7a\u683c\u5206\u5272 print ( s . split ( ' ' )) # ['Python', 'is', 'very', 'good'] # \u6309\u7a7a\u683c\u5206\u5272\u62102\u4e2a\u5b50\u5b57\u7b26\u4e32 print ( s . split ( ' ' , 1 )) # ['Python', 'is very good'] strip: \u79fb\u9664\u5b57\u7b26\u4e32\u9996\u5c3e\u6307\u5b9a\u7684\u5b57\u7b26 \u9ed8\u8ba4\u4e3a\u7a7a\u683c\u3002\u8be5\u65b9\u6cd5\u53ea\u80fd\u5220\u9664\u5f00\u5934\u6216\u662f\u7ed3\u5c3e\u7684\u5b57\u7b26\uff0c\u4e0d\u80fd\u5220\u9664\u4e2d\u95f4\u90e8\u5206\u7684\u5b57\u7b26\u3002 print ( s ) # Python is very good # \u79fb\u9664\u672b\u5c3e\u5b57\u7b26d print ( s . strip ( 'd' )) # Python is very goo endswith (str): \u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u4ee5 str \u7ed3\u5c3e print ( s . endswith ( 'd' )) # True print ( s . endswith ( 'a' )) # False startswith (str): \u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u4ee5 str \u5f00\u5934 print ( s . startswith ( 'p' )) # False print ( s . startswith ( 'P' )) # True isdigit \uff1a\u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u5168\u4e3a\u6570\u5b57 d = '+86-123' print ( d . isdigit ()) # False d = '86123' print ( d . isdigit ()) # True isalpha \uff1a\u5224\u65ad\u5b57\u7b26\u4e32\u662f\u5426\u5168\u4e3a\u5b57\u6bcd b = 'Ab?' print ( b . isalpha ()) # False c = 'Ab' print () c . isalpha () # True","title":"\u5b57\u7b26\u4e32\u5e38\u7528\u65b9\u6cd5"},{"location":"python/Foundation/ch01/#_2","text":"\u4f7f\u7528\u53cd\u659c\u6760\\\u8868\u793a\u8f6c\u4e49\u5b57\u7b26\u3002\u53cd\u659c\u6760\u524d\u9762\u52a0r\u4ee3\u8868\u539f\u59cb\u5b57\u7b26\u3002 a = 'str \\n ing' print ( a ) # str # ing a = r 'str\\ning' print ( a ) # str\\ning \u8f6c\u4e49\u7b26 \u63cf\u8ff0 \\\u5728\u884c\u5c3e \u7eed\u884c\u7b26 \\\\ \u53cd\u659c\u6760\u7b26\u53f7\\ \\' \u5355\u5f15\u53f7 \\b \u9000\u683c(Backspace) \\000 \u7a7a \\n \u6362\u884c \\v \u7eb5\u5411\u5236\u8868\u7b26 \\t \u6a2a\u5411\u5236\u8868\u7b26 \\r \u56de\u8f66\uff0c\u5c06 \\r \u540e\u9762\u7684\u5185\u5bb9\u79fb\u5230\u5b57\u7b26\u4e32\u5f00\u5934\uff0c\u5e76\u9010\u4e00\u66ff\u6362\u5f00\u5934\u90e8\u5206\u7684\u5b57\u7b26\uff0c\u76f4\u81f3\u5c06 \\r \u540e\u9762\u7684\u5185\u5bb9\u5b8c\u5168\u66ff\u6362\u5b8c\u6210\u3002 \\yyy \u516b\u8fdb\u5236\u6570\uff0cy \u4ee3\u8868 0~7 \u7684\u5b57\u7b26 \\xyy \u5341\u516d\u8fdb\u5236\u6570\uff0c\u4ee5 \\x \u5f00\u5934\uff0cy \u4ee3\u8868\u7684\u5b57\u7b26","title":"\u8f6c\u4e49\u5b57\u7b26"},{"location":"python/Foundation/ch01/#_3","text":"\u5b57\u7b26\u4e32\u662f\u53ef\u8fed\u4ee3\u7684\u3002\u7d22\u5f15\u503c\u4ece0\u5f00\u59cb\uff0c-1\u4ee3\u8868\u4ece\u672b\u5c3e\u5f00\u59cb\u3002\u7d22\u5f15\u533a\u95f4\u662f\u5de6\u95ed\u53f3\u5f00\u3002 a = 'string is \"special\"' print ( a [ 2 : 4 ]) 'ri' print ( a [ - 4 : - 1 ]) # ial","title":"\u53ef\u8fed\u4ee3\u6027"},{"location":"python/Foundation/ch01/#f-string","text":"f-string\u662fPython3.6\u63a8\u51fa\u7684\u65b0\u529f\u80fd\u3002\u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5bf9\u6bd4\u4f20\u7edf\u8868\u793a\u65b9\u6cd5\u548cf-string\u7684\u65b9\u6cd5\u3002 age = 32 name = 'Tom' fstring = f 'My name is { name } and I am { age } years old.' print ( fstring ) # My name is Tom and I am 32 years old. \u5728f-string\u4e2d\u4f7f\u7528\u8868\u8fbe\u5f0f\u3002 height = 2 base = 3 fstring = f 'The area of the triangle is { base * height / 2 } .' print ( fstring ) # The area of the triangle is 3.0. \u901a\u8fc7f-string\u5bf9\u5b57\u5178\u8fdb\u884c\u64cd\u4f5c\u3002 person1 = { 'name' : 'Tom' , 'age' : 20 , 'gender' : 'male' } person2 = { 'name' : 'Jerry' , 'age' : 20 , 'gender' : 'female' } # \u8bfb\u53d6\u5b57\u5178 fstring = f ' { person1 . get ( \"name\" ) } is { person1 . get ( \"age\" ) } and is { person1 . get ( \"ender\" ) } ' print ( fstring ) # Tom is 20 and is None # \u904d\u5386\u5b57\u5178 people = [ person1 , person2 ] for person in people : fstring = f ' { person . get ( \"name\" ) } is { person . get ( \"age\" ) } and is { person . get ( \"ender\" ) } ' print ( fstring ) # Tom is 20 and is None # Jerry is 20 and is None \u5728f-string\u4e2d\u4f7f\u7528\u6761\u4ef6\u3002 person1 = { 'name' : 'Tom' , 'age' : 20 , 'gender' : 'male' } person2 = { 'name' : 'Jerry' , 'age' : 20 , 'gender' : 'female' } people = [ person1 , person2 ] for person in people : fstring = f ' { \"She\" if person . get ( \"gender\" ) == \"female\" else \"He\" } is watching TV.' print ( fstring ) # He is watching TV. # She is watching TV. \u4f7f\u7528f-string\u683c\u5f0f\u5316\u8f93\u51fa\u3002 \u5de6\u5bf9\u9f50\uff1a< \u53f3\u5bf9\u9f50\uff1a> \u5c45\u4e2d\u5bf9\u9f50\uff1a^ print ( f ' { \"apple\" : >30 } ' ) print ( f ' { \"apple\" : ^30 } ' ) print ( f ' { \"apple\" : <30 } ' ) # apple # apple # apple \u4f7f\u7528f-string\u683c\u5f0f\u5316\u6570\u5b57\u3002 number = 0.9124325345 # \u767e\u5206\u6bd4 fstring = f 'Percentage format for number with two decimal places: { number : .2% } ' print ( fstring ) # Percentage format for number with two decimal places: 91.24% # \u4fdd\u7559\u5c0f\u6570\u70b9\u540e3\u4f4d fstring = f 'Fixed point format for number with three decimal places: { number : .3f } ' print ( fstring ) # Fixed point format for number with three decimal places: 0.912 # \u79d1\u5b66\u8ba1\u6570\u6cd5\u8868\u793a fstring = f 'Exponent format for number: { number : e } ' print ( fstring ) # Exponent format for number: 9.124325e-01 # \u5e26\u8d27\u5e01\u7b26\u53f7 number = 123456.78921 fstring = f 'Currency format for number with two decimal places: $ { number : .2f } ' print ( fstring ) # Currency format for number with two decimal places: $123456.79 # \u5e26\u8d27\u5e01\u7b26\u53f7\u548c\u5343\u5206\u4f4d number = 123456.78921 fstring = f 'Currency format for number with two decimal places and comma seperators: $ { number : ,.2f } ' print ( fstring ) # Currency format for number with two decimal places and comma seperators: $123,456.79 # \u8f93\u51fa\u6570\u503c\u5e26\u6b63\u8d1f\u7b26\u5408 numbers = [ 1 , - 3 , 5 ] for number in numbers : fstring = f 'The number is { number : + } ' print ( fstring ) # The number is +1 # The number is -3 # The number is +5 # Debug\u8c03\u8bd5 number = 2 print ( f ' { number = } ' ) # number = 2","title":"f-string"},{"location":"python/Foundation/ch01/#13-list","text":"\u5217\u8868\u662f Python \u5185\u7f6e\u7684\u4e00\u79cd\u6570\u636e\u7ed3\u6784\uff0c\u662f\u4e00\u79cd\u6709\u5e8f\u7684\u96c6\u5408\uff0c\u7528\u6765\u5b58\u50a8\u4e00\u8fde\u4e32\u5143\u7d20\u7684\u5bb9\u5668\u3002\u5217\u8868\u4e2d\u5143\u7d20\u7c7b\u578b\u53ef\u4ee5\u4e0d\u76f8\u540c\uff0c\u5b83\u652f\u6301\u6570\u5b57\u3001\u5b57\u7b26\u4e32\u7b49\u3002 \u5217\u8868\u7684\u6bcf\u4e2a\u503c\u90fd\u6709\u5bf9\u5e94\u7684\u7d22\u5f15\u503c\uff0c\u7d22\u5f15\u503c\u4ece0\u5f00\u59cb\u3002 \u5217\u8868\u5207\u7247\uff1a \u4f7f\u7528\u5207\u7247\u7b26\u53f7\u53ef\u4ee5\u5bf9\u5927\u591a\u6570\u5e8f\u5217\u7c7b\u578b\u9009\u53d6\u5176\u5b50\u96c6\u3002 \u8d77\u59cb\u4f4d\u7f6estart\u7684\u7d22\u5f15\u662f\u5305\u542b\u7684\uff0c\u800c\u7ed3\u675f\u4f4d\u7f6estop\u7684\u7d22\u5f15\u5e76\u4e0d\u5305\u542b\uff08\u5de6\u95ed\u53f3\u5f00\uff09\u3002 \u6b65\u8fdb\u503cstep\u53ef\u4ee5\u5728\u7b2c\u4e8c\u4e2a\u5192\u53f7\u540e\u9762\u4f7f\u7528\uff0c\u610f\u601d\u662f\u6bcf\u9694\u591a\u5c11\u4e2a\u6570\u53d6\u4e00\u4e2a\u503c \u3002 color = [ 'red' , 'green' , 'blue' , 'yellow' , 'white' , 'black' ] # \u4ece0\u5f00\u59cb\u7edf\u8ba1\uff0c\u8bfb\u53d6\u7b2c1\uff0c2\u4f4d print ( color [ 1 : 3 ]) # ['green', 'blue'] # \u4ece0\u5f00\u59cb\u7edf\u8ba1\uff0c\u8bfb\u53d6\u4ece\u7b2c1\u4f4d\u5230\u5012\u6570\u7b2c3\u4f4d print ( color [ 1 : - 2 ]) # ['green', 'blue', 'yellow'] # \u4ece0\u5f00\u59cb\u7edf\u8ba1\uff0c\u8bfb\u53d6\u4ece\u5012\u6570\u7b2c4\u4f4d\u5230\u5012\u6570\u7b2c3\u4f4d print ( color [ - 4 : - 2 ]) # ['blue', 'yellow'] # \u5982\u679c\u5199\u6210\u4e0b\u9762\u8fd9\u6837\uff0c\u5219\u65e0\u8f93\u51fa\u3002 print ( color [ - 2 : - 4 ]) # [] print ( color [:: 2 ]) # ['red', 'blue', 'white'] \u5bf9\u4e8e\u7c7b\u4f3c\u4e0b\u9762 invoice \u683c\u5f0f\u7684\u7eaf\u6587\u672c\u89e3\u6790\uff0c\u4f7f\u7528\u6709\u540d\u5b57\u7684\u5207\u7247\u6bd4\u7528\u4e0a\u9762\u6240\u5217\u4e3e\u7684\u786c\u7f16\u7801\u7684\u6570\u5b57\u533a\u95f4\u8981\u65b9\u4fbf\u5f97\u591a\u3002 invoice = \"\"\" 0 6 40 52 55 1909 Primoroni PiBrella $17.50 3 $52.50 1489 6mm Tactile Switch x20 $4.19 2 $9.90 1510 Panavise JR.-PV-201 $28.00 1 $28.00 1601 PiTFT Mini Kit 320x240 $34.95 1 $34.95 \"\"\" SKU = slice ( 0 , 6 ) DESCRIPTION = slice ( 6 , 40 ) UNIT_PRICE = slice ( 40 , 52 ) QUANTITY = slice ( 52 , 55 ) ITEM_TOTAL = slice ( 55 , None ) line_items = invoice . split ( ' \\n ' )[ 2 :] # \u6309\u4e0a\u9762invoice\u7684\u683c\u5f0f\uff0c\u7b2c0\u548c1\u884c\u820d\u5f03 for item in line_items : print ( item [ UNIT_PRICE ], item [ DESCRIPTION ]) # $17.50 Primoroni PiBrella # $4.19 6mm Tactile Switch x20 # $28.00 Panavise JR.-PV-201 # $34.95 PiTFT Mini Kit 320x240 Python\u5185\u7f6e\u7684\u5e8f\u5217\u7c7b\u578b\u90fd\u662f\u4e00\u7ef4\u7684\uff0c\u56e0\u6b64\u5b83\u4eec\u53ea\u652f\u6301\u5355\u4e00\u7684\u7d22\u5f15\uff0c\u6210\u5bf9\u51fa\u73b0\u7684\u7d22\u5f15\u662f\u6ca1\u6709\u7528\u7684\u3002 **\u7701\u7565\uff08ellipsis\uff09**\u7684\u6b63\u786e\u4e66\u5199\u65b9\u6cd5\u662f\u4e09\u4e2a\u82f1\u8bed\u53e5\u53f7\uff08...\uff09\uff0c\u800c\u4e0d\u662fUnicdoe\u7801\u4f4dU+2026\u8868\u793a\u7684\u534a\u4e2a\u7701\u7565\u53f7\uff08...\uff09\u3002 \u7701\u7565\u5728Python\u89e3\u6790\u5668\u773c\u91cc\u662f\u4e00\u4e2a\u7b26\u53f7\uff0c\u800c\u5b9e\u9645\u4e0a\u5b83\u662f Ellipsis \u5bf9\u8c61\u7684\u522b\u540d\uff0c\u800c Ellipsis \u5bf9\u8c61\u53c8\u662f ellipsis \u7c7b\u7684\u5355\u4e00\u5b9e\u4f8b\u3002 \u5b83\u53ef\u4ee5\u5f53\u4f5c\u5207\u7247\u89c4\u8303\u7684\u4e00\u90e8\u5206\uff0c\u4e5f\u53ef\u4ee5\u7528\u5728\u51fd\u6570\u7684\u53c2\u6570\u6e05\u5355\u4e2d\uff0c\u6bd4\u5982 f(a, ..., z) \uff0c\u6216 a[i:...] \u3002 \u5728NumPy\u4e2d\uff0c ... \u7528\u4f5c\u591a\u7ef4\u6570\u7ec4\u5207\u7247\u7684\u5feb\u6377\u65b9\u5f0f\u3002\u5982\u679c `x\u662f\u56db\u7ef4\u6570\u7ec4\uff0c\u90a3\u4e48 x[i, ...] \u5c31\u662f x[i, :, :, :]`\u7684\u7f29\u5199\u3002\u5982\u679c\u60f3\u4e86\u89e3\u66f4\u591a\uff0c\u8bf7\u53c2\u89c1\u201cTentative NumPy Tutorial\u201d\u3002 \u5217\u8868\u5e38\u7528\u65b9\u6cd5 \u65b9\u6cd5\u540d\u79f0 \u4f5c\u7528 a.index() \u8fd4\u56dea\u4e2d\u9996\u4e2a\u5339\u914d\u9879\u7684\u4f4d\u7f6e a.pop() \u5220\u9664\u6307\u5b9a\u4f4d\u7f6e\u7684\u5143\u7d20 a.insert() \u5411\u6307\u5b9a\u4f4d\u7f6e\u63d2\u5165\u5143\u7d20 a.reverse() \u53cd\u5411\u6392\u5e8f a.append() \u5411\u672b\u5c3e\u6dfb\u52a0\u5143\u7d20 a.sort() \u5bf9\u5217\u8868\u8fdb\u884c\u6392\u5e8f a.remove() \u5220\u9664\u9996\u4e2a\u5339\u914d\u9879\u7684\u5143\u7d20 a.extend() \u5c06\u4e00\u4e2a\u5217\u8868\u6269\u5c55\u81f3\u53e6\u4e00\u4e2a\u5217\u8868 a.count() \u7edf\u8ba1\u67d0\u4e2a\u5143\u7d20\u51fa\u73b0\u7684\u6b21\u6570 \u521b\u5efa\u5217\u8868list a = [ 1 , 2 , 3 , 4 , 5 ] print ( a ) # [1, 2, 3, 4, 5] b = list ( '12345' ) print ( b ) # ['1', '2', '3', '4', '5'] c = list ( 12345 ) # Traceback (most recent call last): # File \"\", line 1, in # TypeError: 'int' object is not iterable \u5217\u8868\u5207\u7247\uff08\u4ece0\u5f00\u59cb\uff0c\u5de6\u95ed\u53f3\u5f00\uff09\uff1a print ( a [ 2 : 3 ]) # [3] print ( a [: 3 ]) # [1, 2, 3] print ( a [:: - 1 ]) # \u5012\u5e8f # [5, 4, 3, 2, 1] print ( a [::]) # [1, 2, 3, 4, 5] print ( a [:: 1 ]) [ 1 , 2 , 3 , 4 , 5 ] \u5217\u8868\u662f\u53ef\u4fee\u6539\u7684\uff1a print ( a [ 1 ]) # 2 a [ 1 ] = 'one' print ( a ) @ [ 1 , 'one' , 3 , 4 , 5 ] \u5217\u8868\u8ffd\u52a0\u548c\u63d2\u5165\u3002insert\u4e0eappend\u76f8\u6bd4\uff0c\u8ba1\u7b97\u4ee3\u4ef7\u66f4\u9ad8\u3002\u56e0\u4e3a\u5b50\u5e8f\u5217\u5143\u7d20\u9700\u8981\u5728\u5185\u90e8\u79fb\u52a8\u4e3a\u65b0\u5143\u7d20\u63d0\u4f9b\u7a7a\u95f4\u3002 a . append ( 6 ) # \u6ce8\u610f\uff0c\u76f4\u63a5\u4fee\u6539\u539f\u5217\u8868\uff0c\u4e0d\u662f\u521b\u5efa\u526f\u672c\u3002 print ( a ) # [1, 'one', 3, 4, 5, 6] a . extend ([ 7 , 8 , 9 ]) print ( a ) # [1, 'one', 3, 4, 5, 6, 7, 8, 9] a . insert ( 0 , 'Italy' ) print ( a ) # ['Italy', 1, 3, 5, 6, 7, 8] \u5217\u8868\u5220\u9664\u5143\u7d20\uff0c\u9ed8\u8ba4\u5220\u9664\u6700\u540e\u4e00\u4e2a\u3002insert\u7684\u53cd\u64cd\u4f5c\u662fpop\u3002 a . pop () # 9 print ( a ) # [1, 'one', 3, 4, 5, 6, 7, 8] a . pop ( 3 ) # 4 print ( a ) # [1, 'one', 3, 5, 6, 7, 8] \u5220\u9664\u5217\u8868\u4e2d\u67d0\u4e2a\u5143\u7d20\u3002 print ( a [ 1 ]) # one del a [ 1 ] print ( a ) [ 1 , 3 , 5 , 6 , 7 , 8 ] \u5220\u9664\u5217\u8868\u4e2d\u67d0\u4e2a\u5143\u7d20\u3002remove\u65b9\u6cd5\u4f1a\u5b9a\u4f4d\u7b2c\u4e00\u4e2a\u7b26\u5408\u8981\u6c42\u7684\u503c\u5e76\u79fb\u9664 a . remove ( 'Italy' ) print ( a ) # [1, 3, 5, 6, 7, 8] \u7edf\u8ba1\u67d0\u4e2a\u5143\u7d20\u51fa\u73b0\u7684\u6b21\u6570\u3002 print ( a . count ( 1 )) # 1 \u8fd4\u56de\u5217\u8868\u4e2d\u5339\u914d\u9879\u7684\u7d22\u5f15\u4f4d\u7f6e\u3002\u5339\u914d\u4e0d\u5230\u629b\u51fa\u5f02\u5e38\u3002 print ( a . index ( 2 )) # Traceback (most recent call last): # File \"\", line 1, in # ValueError: 2 is not in list print ( a . index ( 3 )) # 1 \u5224\u65ad\u5143\u7d20\u662f\u5426\u5b58\u5728\u4e8e\u5217\u8868\u3002 print ( 3 in a ) # True print ( '3' in a ) # False \u53cd\u5411\u8f93\u51fa\u5217\u8868\u3002 a . reverse () print ( a ) # [8, 7, 6, 5, 3, 1] \u53d6\u5217\u8868\u4e2d\u6700\u5927\u503c\u3001\u6700\u5c0f\u503c\u3002 print ( min ( a )) # 1 print ( max ( a )) # 78 \u8ba1\u7b97\u5217\u8868\u957f\u5ea6\u3002 print ( len ( a )) # 6 \u5217\u8868\u6269\u5c55\uff1a a = [ 1 , 2 , 3 ] b = [ 4 , 5 , 6 ] print ( a + b ) # [1, 2, 3, 4, 5, 6] a . extend ( b ) # a\u5217\u8868\u88ab\u4fee\u6539 print ( a ) # [1, 2, 3, 4, 5, 6] print ( b ) # [4, 5, 6] \u4f7f\u7528extend\u6dfb\u52a0\u5143\u7d20\u6bd4\u4f7f\u7528\u52a0\u53f7\uff08+\uff09\u8fde\u63a5\u6548\u7387\u66f4\u9ad8\u3002\u56e0\u4e3a\u4f7f\u7528\u52a0\u53f7\uff08+\uff09\u8fde\u63a5\u8fc7\u7a0b\u4e2d\u521b\u5efa\u4e86\u65b0\u5217\u8868\uff0c\u5e76\u4e14\u8fd8\u8981\u590d\u5236\u5bf9\u8c61\u3002 a_list = [ 4 , None , 'foo' ] b_list = [ 7 , 8 , ( 2 , 3 )] print ( a_list + b_list ) # [4, None, 'foo', 7, 8, (2, 3)] \u4f7f\u7528+\u53f7\u8fde\u63a5 a_list . extend ( b_list ) print ( a_list ) # [4, None, 'foo', 7, 8, (2, 3)] Python\u7684\u4e00\u4e2a\u60ef\u4f8b\uff1a\u5982\u679c\u4e00\u4e2a\u51fd\u6570\u6216\u8005\u65b9\u6cd5\u5bf9\u5bf9\u8c61\u8fdb\u884c\u7684\u662f\u5c31\u5730\u6539\u52a8\uff0c\u90a3\u5b83\u5c31\u5e94\u8be5\u8fd4\u56deNone\uff0c\u597d\u8ba9\u8c03\u7528\u8005\u77e5\u9053\u4f20\u5165\u7684\u53c2\u6570\u53d1\u751f\u4e86\u53d8\u52a8\uff0c\u800c\u4e14\u5e76\u672a\u4ea7\u751f\u65b0\u7684\u5bf9\u8c61\u3002 \u4e0b\u9762\u662f\u6392\u5e8f\u7684\u4f8b\u5b50 list.sort() \u548c sorted(list) \u7684\u533a\u522b\u3002 list1 = [ '1' , 'one' , '3' , 'Four' , '5' , 'two' , 'apple' , '8' , '9' ] print ( list1 ) # ['1', 'one', '3', 'Four', '5', 'two', 'apple', '8', '9'] # \u4e0b\u9762\u7684\u64cd\u4f5c\u4e0d\u6539\u53d8\u539f\u5217\u8868 print ( sorted ( list1 )) # ['1', '3', '5', '8', '9', 'Four', 'apple', 'one', 'two'] print ( sorted ( list1 , reverse = True )) # ['two', 'one', 'apple', 'Four', '9', '8', '5', '3', '1'] print ( sorted ( list1 , key = len )) # ['1', '3', '5', '8', '9', 'one', 'two', 'Four', 'apple'] print ( list1 ) # ['1', 'one', '3', 'Four', '5', 'two', 'apple', '8', '9'] # \u4e0b\u9762\u7684\u64cd\u4f5c\u76f4\u63a5\u4fee\u6539\u539f\u5217\u8868\uff0c\u8fd4\u56de\u503c\u662fNone print ( list1 . sort ()) # None print ( list1 ) # ['1', '3', '5', '8', '9', 'Four', 'apple', 'one', 'two'] \u5217\u8868\u590d\u5236\uff0c + \u548c * \u7684\u64cd\u4f5c\u90fd\u662f\u4e0d\u4fee\u6539\u539f\u6709\u7684\u64cd\u4f5c\u5bf9\u8c61\uff0c\u800c\u662f\u6784\u5efa\u4e00\u4e2a\u5168\u65b0\u7684\u5217\u8868\u3002 c = list ( 'Python' ) print ( a + c ) # [1, 2, 3, 4, 5, 6, 'P', 'y', 't', 'h', 'o', 'n'] print ( a * 3 ) # [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6] \u5982\u679c\u5728 a * n \u8fd9\u4e2a\u8bed\u53e5\u4e2d\uff0c\u5e8f\u5217 a \u91cc\u7684\u5143\u7d20\u662f\u5bf9\u5176\u4ed6\u53ef\u53d8\u5bf9\u8c61\u7684\u5f15\u7528\u7684\u8bdd\uff0c\u5c31\u9700\u8981\u683c\u5916\u6ce8\u610f\u4e86\uff0c\u56e0\u4e3a\u8fd9\u4e2a\u5f0f\u5b50\u7684\u7ed3\u679c\u53ef\u80fd\u4f1a\u51fa\u4e4e\u610f\u6599\u3002 \u6bd4\u5982\uff0c\u6211\u4eec\u60f3\u7528 my_list=[[]] * 3 \u6765\u521d\u59cb\u5316\u4e00\u4e2a\u7531\u5217\u8868\u7ec4\u6210\u7684\u5217\u8868\uff0c\u4f46\u662f\u6211\u4eec\u5b9e\u9645\u5f97\u5230\u7684\u5217\u8868\u91cc\u5305\u542b\u76843\u4e2a\u5143\u7d20\u5176\u5b9e\u662f3\u4e2a\u5f15\u7528\uff0c\u800c\u4e14\u8fd93\u4e2a\u5f15\u7528\u6307\u5411\u7684\u90fd\u662f*\u540c\u4e00\u4e2a*\u5217\u8868\u3002\u770b\u4e0b\u9762\u4f8b\u5b50\u3002 # \u505a\u6cd51 board = [[ '_' ] * 3 for i in range ( 3 )] print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 1 ][ 2 ] = 'X' print ( board ) # [['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']] # \u505a\u6cd52 board = [[ '_' ] * 3 ] * 3 print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 1 ][ 2 ] = 'X' print ( board ) # [['_', '_', 'X'], ['_', '_', 'X'], ['_', '_', 'X']] \u4e0b\u9762\u4e5f\u662f\u540c\u6837\u7684\u95ee\u9898\u3002 # \u65b9\u6cd51 row = [ '_' ] * 3 board = [] for i in range ( 3 ): board . append ( row ) print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 2 ][ 0 ] = 'X' print ( board ) # [['X', '_', '_'], ['X', '_', '_'], ['X', '_', '_']] # \u65b9\u6cd52 row = [] board = [] for i in range ( 3 ): row = [ '_' ] * 3 board . append ( row ) print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']] board [ 2 ][ 0 ] = 'X' print ( board ) # [['_', '_', '_'], ['_', '_', '_'], ['X', '_', '_']] \u53cc\u7aef\u961f\u5217collections.deque \uff0c\u53ef\u4ee5\u6ee1\u8db3\u5217\u8868\u5934\u5c3e\u90e8\u90fd\u589e\u52a0\u7684\u8981\u6c42\u3002 deque() \u4e2d maxlen \u662f\u4e00\u4e2a\u53ef\u9009\u53c2\u6570\uff0c\u4ee3\u8868\u8fd9\u4e2a\u961f\u5217\u53ef\u4ee5\u5bb9\u7eb3\u7684\u5143\u7d20\u7684\u6570\u91cf\uff0c\u800c\u4e14\u4e00\u65e6\u8bbe\u5b9a\uff0c\u8fd9\u4e2a\u5c5e\u6027\u5c31\u4e0d\u80fd\u4fee\u6539\u4e86\u3002 \u5f53\u8bd5\u56fe\u5bf9\u4e00\u4e2a\u5df2\u6ee1 len(d)==d.maxlen \u7684\u961f\u5217\u505a\u5934\u90e8\u6dfb\u52a0\u64cd\u4f5c\u7684\u65f6\u5019\uff0c\u5b83\u5c3e\u90e8\u7684\u5143\u7d20\u4f1a\u88ab\u5220\u9664\u6389\u3002 extendleft(iter) \u65b9\u6cd5\u4f1a\u628a\u8fed\u4ee3\u5668\u91cc\u7684\u5143\u7d20\u9010\u4e2a\u6dfb\u52a0\u5230\u53cc\u5411\u961f\u5217\u7684\u5de6\u8fb9\uff0c\u56e0\u6b64\u8fed\u4ee3\u5668\u91cc\u7684\u5143\u7d20\u4f1a\u9006\u5e8f\u51fa\u73b0\u5728\u961f\u5217\u91cc\u3002 \u961f\u5217\u7684\u65cb\u8f6c\u64cd\u4f5c rotate \u63a5\u53d7\u4e00\u4e2a\u53c2\u6570n\uff0c\u5f53n > 0\u65f6\uff0c\u961f\u5217\u7684\u6700\u53f3\u8fb9\u7684n\u4e2a\u5143\u7d20\u4f1a\u88ab\u79fb\u52a8\u5230\u961f\u5217\u7684\u5de6\u8fb9\u3002\u5f53n < 0\u65f6\uff0c\u6700\u5de6\u8fb9\u7684n\u4e2a\u5143\u7d20\u4f1a\u88ab\u79fb\u52a8\u5230\u53f3\u8fb9\u3002 from collections import deque d = deque ([ 1 , 2 , 3 ]) print ( d ) # deque([1, 2, 3]) # \u6ce8\u610f\u63d2\u5165\u987a\u5e8f d . extendleft ([ 'a' , 'b' , 'c' ]) print ( d ) # deque(['c', 'b', 'a', 1, 2, 3]) print ( len ( d )) # 6 print ( d [ - 2 ]) # 2 # \u7edf\u8ba1\u5b57\u7b26a\u51fa\u73b0\u7684\u6b21\u6570 print ( d . count ( 'a' )) # 1 # \u8fd4\u56de\u5b57\u7b26a\u7684\u7d22\u5f15\u503c print ( d . index ( 'a' )) # 2 # \u7b2c0\u4f4d\u63d2\u5165\u6570\u5b571\uff0c\u5176\u4f59\u987a\u79fb d . insert ( 0 , 1 ) print ( d ) # deque([1, 'c', 'b', 'a', 1, 2, 3]) # \u628a\u53f3\u8fb92\u4e2a\u5143\u7d20\u653e\u5230\u5de6\u8fb9\uff0c\u6ce8\u610f\u987a\u5e8f\uff0c\u548cextendleft\u4e0d\u4e00\u6837 d . rotate ( 2 ) print ( d ) # deque([2, 3, 1, 'c', 'b', 'a', 1]) d . rotate ( - 2 ) print ( d ) # deque([1, 'c', 'b', 'a', 1, 2, 3]) \u4e0b\u8868\u603b\u7ed3\u4e86\u5217\u8868\u548c\u53cc\u5411\u961f\u5217\u7684\u65b9\u6cd5\uff08\u4e0d\u5305\u62ec\u7531\u5bf9\u8c61\u5b9e\u73b0\u7684\u65b9\u6cd5\uff09\u3002 \u5217\u8868\u6392\u5e8f\u3002\u6392\u5e8f\u5bf9\u5217\u8868\u5143\u7d20\u7684\u6570\u636e\u7c7b\u578b\u662f\u6709\u8981\u6c42\u7684\u3002 a_list = [ 4 , None , 'foo' , 7 , 8 , ( 2 , 3 )] a_list . sort () # Traceback (most recent call last): # File \"\", line 1, in # TypeError: '<' not supported between instances of 'NoneType' and 'int' b_list = [ 7 , 8 , ( 2 , 3 )] b_list . sort () # Traceback (most recent call last): # File \"\", line 1, in # TypeError: '<' not supported between instances of 'tuple' and 'int' a_list = [ 7 , 2 , 5 , 1 , 3 ] a_list . sort () # \u6309\u6570\u503c\u5927\u5c0f\u6392\u5e8f print ( a_list ) # [1, 2, 3, 5, 7] b_list = [ 'saw' , 'small' , 'He' , 'foxes' , 'six' ] b_list . sort ( key = len ) # \u901a\u8fc7\u5b57\u7b26\u4e32\u7684\u957f\u5ea6\u8fdb\u884c\u6392\u5e8f print ( b_list ) # ['He', 'saw', 'six', 'small', 'foxes'] \u5217\u8868\u4e8c\u5206\u641c\u7d22\u548c\u5df2\u6392\u5e8f\u5217\u8868\u7684\u7ef4\u62a4 bisect \u8fd4\u56de\u8981\u63d2\u5165\u5143\u7d20\u5728\u5217\u8868\u4e2d\u7684\u4e0b\u6807\u3002\u5047\u5b9a\u5217\u8868\u662f\u6709\u5e8f\u7684\u3002 bisect_left \u4e0e bisect \u7c7b\u4f3c\uff0c\u53ea\u4e0d\u8fc7\u5176\u9ed8\u8ba4\u5c06\u5143\u7d20\u63d2\u5230\u5de6\u8fb9\uff0c\u6240\u4ee5\u8fd4\u56de\u7684\u662f\u63d2\u5165\u5230\u5de6\u8fb9\u7684\u4e0b\u6807 bisect_right\u4e0e bisect_left \u76f8\u53cd\u3002 \u4ee5\u4e0a\u65b9\u6cd5\u82e5\u5217\u8868\u65e0\u5e8f\uff0c\u90a3\u4e48\u4f1a\u8fd4\u56de\u63d2\u5165\u5230\u5217\u8868\u6700\u540e\u4e00\u4e2a\u5408\u9002\u7684\u4f4d\u7f6e\u3002 insort \u4f1a\u5728\u5217\u8868\u4e2d\u63d2\u5165\u5143\u7d20\u5230\u6b63\u786e\u4f4d\u7f6e\uff0c\u5047\u5b9a\u5217\u8868\u6709\u5e8f\u3002\u5982\u679c\u5217\u8868\u65e0\u5e8f\uff0c\u90a3\u4e48\u4f1a\u8fd4\u56de\u7a7a\u3002\u9ed8\u8ba4\u63d2\u5165\u5230\u53f3\u8fb9\u3002 insort_left \u548cinsort_right \u7c7b\u4f3c\u3002 import bisect c = [ 1 , 2 , 3 , 4 , 7 ] print ( bisect . bisect ( c , 2 )) # 2 bisect\u4f1a\u627e\u5230\u7b2c\u4e00\u4e2a2,\u5e76\u628a\u65b0\u76842\u63d2\u5165\u5b83\u540e\u9762 bisect . insort ( c , 2 ) # [1, 2, 2, 3, 4, 7] print ( bisect . bisect ( c , 5 )) # 5 bisect\u4f1a\u627e\u5230\u7b2c\u4e00\u4e2a4,\u5e76\u628a\u65b0\u76845\u63d2\u5165\u5b83\u540e\u9762 bisect . insort ( c , 5 ) print ( bisect . bisect ( c , 6 )) # 6 bisect\u4f1a\u627e\u5230\u7b2c\u4e00\u4e2a5,\u5e76\u628a\u65b0\u76846\u63d2\u5165\u5b83\u540e\u9762 bisect . insort ( c , 6 ) print ( c ) # [1, 2, 2, 3, 4, 5, 6, 7] bisect\u53ef\u4ee5\u7528\u6765\u5efa\u7acb\u4e00\u4e2a\u7528\u6570\u5b57\u4f5c\u4e3a\u7d22\u5f15\u7684\u67e5\u8be2\u8868\u683c\uff0c\u5982\u4e0b\u4f8b\uff0c\u628a\u5206\u6570\u548c\u6210\u7ee9\u5bf9\u5e94\u8d77\u6765\uff0c\u6839\u636e\u4e00\u4e2a\u5206\u6570\uff0c\u627e\u5230\u5b83\u6240\u5bf9\u5e94\u7684\u6210\u7ee9\u3002 import bisect def grade ( score , breakpoints = [ 60 , 70 , 80 , 90 ], grades = 'FDCBA' ): i = bisect . bisect ( breakpoints , score ) return grades [ i ] [ grade ( score ) for score in [ 15 , 26 , 31 , 62 , 79 , 85 ]] # ['F', 'F', 'F', 'D', 'C', 'B'] \u7528bisect.insort\u63d2\u5165\u65b0\u5143\u7d20\uff0c\u5e76\u80fd\u4fdd\u6301seq\u7684\u5347\u5e8f\u987a\u5e8f\u3002 import bisect import random size = 7 random . seed ( 1729 ) my_list = [] for i in range ( size ): new_item = random . randrange ( size * 2 ) bisect . insort ( my_list , new_item ) print ( f ' { new_item : 2d } :--> { my_list } ' ) # 10 :--> [10] # 0 :--> [0, 10] # 6 :--> [0, 6, 10] # 8 :--> [0, 6, 8, 10] # 7 :--> [0, 6, 7, 8, 10] # 2 :--> [0, 2, 6, 7, 8, 10] # 10 :--> [0, 2, 6, 7, 8, 10, 10]","title":"1.3 \u5217\u8868\uff08list\uff09"},{"location":"python/Foundation/ch01/#14-dictionary","text":"\u5b57\u5178(dict)\u662f\u4f7f\u7528\u952e-\u503c\uff08key-value\uff09\u5b58\u50a8\uff0c\u952e\u662f\u4e0d\u53ef\u53d8\u5bf9\u8c61\uff0c\u4e14\u4e0d\u5141\u8bb8\u91cd\u590d\u3002 dict\uff08\u5b57\u5178\uff09\u66f4\u4e3a\u5e38\u7528\u7684\u540d\u5b57\u662f\u54c8\u5e0c\u8868\u6216\u8005\u662f\u5173\u8054\u6570\u7ec4\u3002 \u5b57\u5178\u662f\u62e5\u6709\u7075\u6d3b\u5c3a\u5bf8\u7684\u952e\u503c\u5bf9\u96c6\u5408\uff0c\u4e0d\u662f\u901a\u8fc7\u4f4d\u7f6e\u8fdb\u884c\u7d22\u5f15\uff0c\u5176\u4e2d\u952e\u548c\u503c\u90fd\u662fPython\u5bf9\u8c61\u3002\u7528\u5927\u62ec\u53f7{}\u662f\u521b\u5efa\u5b57\u5178\u7684\u4e00\u79cd\u65b9\u5f0f\uff0c\u5728\u5b57\u5178\u4e2d\u7528\u9017\u53f7\u5c06\u952e\u503c\u5bf9\u5206\u9694\u3002 \u521b\u5efa\u5b57\u5178\u7684\u51e0\u79cd\u65b9\u6cd5\uff1a a = dict ( one = 1 , two = 2 , three = 3 ) b = { 'one' : 1 , 'two' : 2 , 'three' : 3 } c = dict ( zip ([ 'one' , 'two' , 'three' ], [ 1 , 2 , 3 ])) d = dict ([( 'two' , 2 ), ( 'three' , 3 ), ( 'one' , 1 )]) e = dict ({ 'three' : 3 , 'one' : 1 , 'two' : 2 }) print ( a == b == c == d == e ) # True \u5b57\u5178\u5e38\u7528\u65b9\u6cd5 \u65b9\u6cd5\u540d\u79f0 \u4f5c\u7528 a.items() \u8fd4\u56dea\u4e2d\u6240\u6709\u952e\u503c\u5bf9 a.values() \u8fd4\u56dea\u4e2d\u6240\u6709\u503c a.keys() \u8fd4\u56dea\u4e2d\u6240\u6709\u952e a.get() \u901a\u8fc7\u952e\u6765\u67e5\u503c\uff0c\u8fd4\u56de\u5bf9\u5e94\u7684\u503c a.clear() \u6e05\u7a7a\u5b57\u5178a\u7684\u503c a.setdefault \u901a\u8fc7\u952e\u503c\u6765\u67e5\u627e\u503c\uff0c\u627e\u4e0d\u5230\u5219\u63d2\u5165 a.update() \u952e\u548c\u503c\u66f4\u65b0\u5230\u65b0\u7684\u5b57\u5178 a.pop() \u5220\u9664\u6307\u5b9a\u4f4d\u7f6e\u7684\u5143\u7d20 \u751f\u6210\u4e00\u4e2a\u5b57\u5178\u3002 dict_a = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } print ( type ( dict_a )) # dict_b = dict ( city = 'Shanghai' , strict = 'Xuhui' , zip = '200000' ) print ( type ( dict_b )) # \u901a\u8fc7\u952e\u67e5\u8be2\u503c\uff0c\u67e5\u8be2\u4e0d\u5230\u629b\u51fa\u5f02\u5e38\u3002 print ( dict_a [ 'name' ]) # Ming print ( dict_a [ 'Name' ]) # Traceback (most recent call last): # File \"\", line 1, in # KeyError: 'Name' \u63d2\u5165\u65b0\u7684\u952e\u503c\u5bf9\u3002 dict_a [ 'city' ] = 'Chengdu' print ( dict_a ) # {'name': 'Ming', 'id': 1001, 'city': 'Chengdu'} \u5220\u9664\u67d0\u4e2a\u952e\u503c\u5bf9\u3002pop\u65b9\u6cd5\u4f1a\u5728\u5220\u9664\u7684\u540c\u65f6\u8fd4\u56de\u88ab\u5220\u7684\u503c\uff0c\u5e76\u5220\u9664\u952e\u3002 dict_a . pop ( 'city' ) # Chengdu print ( dict_a ) # {'name': 'Ming', 'id': 1001} \u53e6\u4e00\u79cd\u65b9\u5f0f\u5220\u9664\u67d0\u4e2a\u952e\u503c\u5bf9\u3002 del dict_a [ 'age' ] # Traceback (most recent call last): # File \"\", line 1, in # KeyError: 'age' del dict_a [ 'id' ] print ( dict_a ) # {'name': 'Ming'} \u5224\u65ad\u952e\u662f\u5426\u5b58\u5728\u3002 dict_a [ 23 ] = 'Hello World' print ( dict_a ) # {'name': 'Ming', 23: 'Hello World'} print ( 23 in dict_a ) # True print ( 35 in dict_a ) # False \u901a\u8fc7\u952e\u67e5\u8be2\u503c\u7684\u53e6\u4e00\u79cd\u65b9\u5f0f\uff0c\u67e5\u8be2\u4e0d\u5230\u4e0d\u629b\u5f02\u5e38\u3002 dict_a . get ( 'hai' ) dict_a . get ( 'hai' , 1 ) # 1 dict_a . get ( 'name' , 1 ) # Ming dict_a [ 'hai' ] # Traceback (most recent call last): # File \"\", line 1, in # KeyError: 'hai' \u901a\u8fc7\u952e\u67e5\u8be2\u503c\u7684\u53e6\u4e00\u79cd\u65b9\u5f0f\uff0c\u67e5\u8be2\u4e0d\u5230\u5219\u6dfb\u52a0\u3002 dict_a . setdefault ( 'name' ) # Ming dict_a . setdefault ( 'hai' , 1 ) # 1 print ( dict_a ) # {'name': 'Ming', 23: 'Hello World', 'hai': 1} dict_a . setdefault ( 'go' ) print ( dict_a ) # {'name': 'Ming', 23: 'Hello World', 'hai': 1, 'go': None} \u8bfb\u53d6\u5b57\u5178\u6240\u6709\u952e\u503c\u5bf9\uff0c\u8fd4\u56de\u7684\u662f\u5217\u8868\u5f62\u5f0f\u3002 print ( dict_a . items ()) # dict_items([('name', 'Ming'), (23, 'Hello World'), ('hai', 1), ('go', None)]) \u8bfb\u53d6\u5b57\u5178\u7684\u952e\u3002 print ( dict_a . keys ()) # dict_keys(['name', 23, 'hai', 'go']) \u8bfb\u53d6\u5b57\u5178\u7684\u503c\u3002 print ( dict_a . values ()) # dict_values(['Ming', 'Hello World', 1, None]) \u5c06\u5b57\u5178\u503c\u8f6c\u5316\u6210\u5217\u8868\u3002 print ( list ( dict_a . values ())) # ['Ming', 'Hello World', 1, None] for key in dict_a . keys (): print ( dict_a [ key ]) # Ming # Hello World # 1 # None \u6e05\u7a7a\u5b57\u5178\u3002 dict_a . clear () print ( dict_a ) # {} print ( len ( dict_a )) # 0 \u5bf9\u4e8e\u4efb\u4f55\u539f\u5b57\u5178\u4e2d\u5df2\u7ecf\u5b58\u5728\u7684\u952e\uff0c\u5982\u679c\u4f20\u7ed9update\u65b9\u6cd5\u7684\u6570\u636e\u4e5f\u542b\u6709\u76f8\u540c\u7684\u952e\uff0c\u5219\u5b83\u7684\u503c\u5c06\u4f1a\u88ab\u8986\u76d6\u3002 dict_a = { 'name' : 'Ming' , 'id' : 1001 , 'age' : 35 } dict_b = dict ( city = 'Shanghai' , id = 2001 , zip = '200000' ) dict_a . update ( dict_b ) print ( dict_a ) # {'name': 'Ming', 'id': 2001, 'age': 35, 'city': 'Shanghai', 'zip': '200000'} \u4ece\u5217\u8868\u751f\u6210\u5b57\u5178\u3002 \u5b57\u5178\u672c\u8d28\u4e0a\u662f2-\u5143\u7ec4\uff08\u542b\u67092\u4e2a\u5143\u7d20\u7684\u5143\u7ec4\uff09\u7684\u96c6\u5408\uff0c\u5b57\u5178\u662f\u53ef\u4ee5\u63a5\u53d7\u4e00\u4e2a2-\u5143\u7ec4\u7684\u5217\u8868\u4f5c\u4e3a\u53c2\u6570\u7684\u3002 # \u65b9\u6cd51 mapping = {} key_list = list ( range ( 5 )) value_list = list ( reversed ( range ( 5 ))) for key , value in zip ( key_list , value_list ): mapping [ key ] = value print ( mapping ) # {0: 4, 1: 3, 2: 2, 3: 1, 4: 0} # \u65b9\u6cd52\u3002 mapping = {} key_list = list ( range ( 5 )) value_list = list ( reversed ( range ( 5 ))) mapping = dict ( zip ( key_list , value_list )) print ( mapping ) # {0: 4, 1: 3, 2: 2, 3: 1, 4: 0} \u6709\u6548\u7684\u5b57\u5178\u952e\u7c7b\u578b\u3002 \u5c3d\u7ba1\u5b57\u5178\u7684\u503c\u53ef\u4ee5\u662f\u4efb\u4f55Python\u5bf9\u8c61\uff0c\u4f46\u952e\u5fc5\u987b\u662f\u4e0d\u53ef\u53d8\u7684\u5bf9\u8c61\uff0c\u6bd4\u5982\u6807\u91cf\u7c7b\u578b\uff08\u6574\u6570\u3001\u6d6e\u70b9\u6570\u3001\u5b57\u7b26\u4e32\uff09\u6216\u5143\u7ec4\uff08\u4e14\u5143\u7ec4\u5185\u5bf9\u8c61\u4e5f\u5fc5\u987b\u662f\u4e0d\u53ef\u53d8\u5bf9\u8c61\uff09\u3002 \u901a\u8fc7hash\u51fd\u6570\u53ef\u4ee5\u68c0\u67e5\u4e00\u4e2a\u5bf9\u8c61\u662f\u5426\u53ef\u4ee5\u54c8\u5e0c\u5316\uff08\u5373\u662f\u5426\u53ef\u4ee5\u7528\u4f5c\u5b57\u5178\u7684\u952e\uff09\uff0c\u672f\u8bed\u53eb\u4f5c\u54c8\u5e0c\u5316\u3002 print ( hash ( 'string' )) # -4368784820203065343 print ( hash (( 1 , 2 , ( 2 , 3 )))) # -9209053662355515447 print ( hash (( 1 , 2 , [ 2 , 3 ]))) # TypeError: unhashable type: 'list' print ( hash (( 1 , 2 , tuple ([ 2 , 3 ])))) # -9209053662355515447 \u4e3a\u4e86\u5c06\u5217\u8868\u4f5c\u4e3a\u952e\uff0c\u4e00\u79cd\u65b9\u5f0f\u5c31\u662f\u5c06\u5176\u8f6c\u6362\u4e3a\u5143\u7ec4 \u5b57\u5178\u9ed8\u8ba4\u503c\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5b9e\u73b0\u4e86\u5c06\u4e00\u4e2a\u5355\u8bcd\u7ec4\u6210\u7684\u5217\u8868\uff0c\u8f6c\u6362\u6210\u5355\u8bcd\u9996\u5b57\u6bcd\u548c\u5355\u8bcd\u4e3a\u952e\u503c\u5bf9\u7684\u5b57\u5178\u3002\u5148\u7528\u4f20\u7edf\u65b9\u6cd5\u5b9e\u73b0\uff0c\u518d\u7528\u5b57\u5178\u7684setdefault\u65b9\u6cd5\u8fdb\u884c\u6539\u5199\u3002 \u5148\u770b\u4f20\u7edf\u65b9\u6cd5\u3002 words = [ 'apple' , 'bat' , 'bar' , 'atom' , 'book' ] by_letter = {} for word in words : letter = word [ 0 ] # word[0]\u628a\u5217\u8868words\u7684\u6bcf\u4e2a\u5143\u7d20\u5217\u8868\u5316\uff0c\u5e76\u53d6\u9996\u5b57\u6bcd\u3002\u8f93\u51fa\u7684\u662fa, b, b, a, b\u8fd95\u4e2a\u5217\u8868\u5143\u7d20\u7684\u9996\u5b57\u6bcd if letter not in by_letter : # \u751f\u6210\u7b2c\u4e00\u4e2a\u952e\u503c\u5bf9 print ( letter ) by_letter [ letter ] = [ word ] # \u5bf9\u6bd4[word]\u548cword[]\u7684\u7528\u6cd5 print ( by_letter ) # a # {'a': ['apple']} # b # {'a': ['apple'], 'b': ['bat']} else : # append\u5176\u4ed6\u952e\u503c\u5bf9 print ( letter ) by_letter [ letter ] . append ( word ) print ( by_letter ) # b # {'a': ['apple'], 'b': ['bat', 'bar']} # a # {'a': ['apple', 'atom'], 'b': ['bat', 'bar']} # b # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} print ( by_letter ) # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} \u7528\u5b57\u5178\u7684setdefault\u65b9\u6cd5\uff0c\u4e0a\u8ff0\u7684for\u5faa\u73af\u8bed\u53e5\u53ef\u4ee5\u88ab\u5199\u4e3a\u5982\u4e0b\u3002 words = [ 'apple' , 'bat' , 'bar' , 'atom' , 'book' ] by_letter = {} for word in words : letter = word [ 0 ] # word[0]\u7684\u8f93\u51fa\u4f9d\u7136\u662f5\u4e2a\u5217\u8868\u5143\u7d20\u7684\u9996\u5b57\u6bcda, b, b, a, b by_letter . setdefault ( letter , []) . append ( word ) # \u5982\u679cletter\u4e0d\u5728[]\u5219\u901a\u8fc7append\u6dfb\u52a0word print ( by_letter ) # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} \u5982\u679c\u6539\u5199\u4e3a by_letter.setdefault(letter, ['a']).append(word) \uff0c\u5219\u8f93\u51fa by_letter \u662f {'a': ['a', 'apple', 'atom'], 'b': ['a', 'bat', 'bar', 'book']} \u3002 words = [ 'apple' , 'bat' , 'bar' , 'atom' , 'book' ] by_letter = {} for word in words : letter = word [ 0 ] # word[0]\u7684\u8f93\u51fa\u4f9d\u7136\u662f5\u4e2a\u5217\u8868\u5143\u7d20\u7684\u9996\u5b57\u6bcda, b, b, a, b by_letter . setdefault ( letter , [ 'a' ]) . append ( word ) print ( by_letter ) # {'a': ['a', 'apple', 'atom'], 'b': ['a', 'bat', 'bar', 'book']} \u4f53\u4f1asetdefault()\u7684\u6ce8\u91ca\u201cInsert key with a value of default if key is not in the dictionary. Return the value for key if key is in the dictionary, else default.\u201d \u901a\u8fc7defaultdict\u7c7b\u4f7f\u5f97\u4e0a\u8ff0\u76ee\u7684\u5b9e\u73b0\u66f4\u4e3a\u7b80\u5355\u3002 from collections import defaultdict by_letter = defaultdict ( list ) # list\u662f\u5185\u7f6e\u7684\u53ef\u53d8\u5e8f\u5217(Built-in mutable sequence) print ( dict ( by_letter )) # {} for word in words : by_letter [ word [ 0 ]] . append ( word ) print ( by_letter ) # defaultdict(, {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']}) print ( dict ( by_letter )) # {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']} \u4e0b\u8868\u5c55\u793a\u4e86 dict \u3001 defaultdict \u548c OrderedDict \u7684\u5e38\u89c1\u65b9\u6cd5\uff0c\u540e\u9762\u4e24\u4e2a\u6570\u636e\u7c7b\u578b\u662f dict \u7684\u53d8\u79cd\uff0c\u4f4d\u4e8e collections \u6a21\u5757\u5185\u3002 default_factory \u5e76\u4e0d\u662f\u4e00\u4e2a\u65b9\u6cd5\uff0c\u800c\u662f\u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61\uff08callable\uff09\uff0c\u5b83\u7684\u503c\u5728 defaultdict \u521d\u59cb\u5316\u7684\u65f6\u5019\u7531\u7528\u6237\u8bbe\u5b9a\u3002 OrderedDict.popitem() \u4f1a\u79fb\u9664\u5b57\u5178\u91cc\u6700\u5148\u63d2\u5165\u7684\u5143\u7d20\uff08\u5148\u8fdb\u5148\u51fa\uff09\uff1b\u540c\u65f6\u8fd9\u4e2a\u65b9\u6cd5\u8fd8\u6709\u4e00\u4e2a\u53ef\u9009\u7684last\u53c2\u6570\uff0c\u82e5\u4e3a\u771f\uff0c\u5219\u4f1a\u79fb\u9664\u6700\u540e\u63d2\u5165\u7684\u5143\u7d20\uff08\u540e\u8fdb\u5148\u51fa\uff09\u3002 \u4e0a\u9762\u7684\u8868\u683c\u4e2d\uff0cupdate\u65b9\u6cd5\u5904\u7406\u53c2\u6570m\u7684\u65b9\u5f0f\uff0c\u662f\u5178\u578b\u7684\u201c\u9e2d\u5b50\u7c7b\u578b\u201d\u3002\u51fd\u6570\u9996\u5148\u68c0\u67e5m\u662f\u5426\u6709keys\u65b9\u6cd5\uff0c\u5982\u679c\u6709\uff0c\u90a3\u4e48update\u51fd\u6570\u5c31\u628a\u5b83\u5f53\u4f5c\u6620\u5c04\u5bf9\u8c61\u6765\u5904\u7406\u3002\u5426\u5219\uff0c\u51fd\u6570\u4f1a\u9000\u4e00\u6b65\uff0c\u8f6c\u800c\u628am\u5f53\u4f5c\u5305\u542b\u4e86\u952e\u503c\u5bf9(key, value)\u5143\u7d20\u7684\u8fed\u4ee3\u5668\u3002Python\u91cc\u5927\u591a\u6570\u6620\u5c04\u7c7b\u578b\u7684\u6784\u9020\u65b9\u6cd5\u90fd\u91c7\u7528\u4e86\u7c7b\u4f3c\u7684\u903b\u8f91\uff0c\u56e0\u6b64\u4f60\u65e2\u53ef\u4ee5\u7528\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\u6765\u65b0\u5efa\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\uff0c\u4e5f\u53ef\u4ee5\u7528\u5305\u542b(key, value)\u5143\u7d20\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\u6765\u521d\u59cb\u5316\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\u3002 \u5b57\u5178\u7684\u53d8\u79cd\uff1a collections.OrderedDict \u8fd9\u4e2a\u7c7b\u578b\u5728\u6dfb\u52a0\u952e\u7684\u65f6\u5019\u4f1a\u4fdd\u6301\u987a\u5e8f\uff0c\u56e0\u6b64\u952e\u7684\u8fed\u4ee3\u6b21\u5e8f\u603b\u662f\u4e00\u81f4\u7684\u3002OrderedDict\u7684popitem\u65b9\u6cd5\u9ed8\u8ba4\u5220\u9664\u5e76\u8fd4\u56de\u7684\u662f\u5b57\u5178\u91cc\u7684\u6700\u540e\u4e00\u4e2a\u5143\u7d20\uff0c\u4f46\u662f\u5982\u679c\u50cfmy_odict.popitem(last=False)\u8fd9\u6837\u8c03\u7528\u5b83\uff0c\u90a3\u4e48\u5b83\u5220\u9664\u5e76\u8fd4\u56de\u7b2c\u4e00\u4e2a\u88ab\u6dfb\u52a0\u8fdb\u53bb\u7684\u5143\u7d20\u3002 collections.ChainMap \u8be5\u7c7b\u578b\u53ef\u4ee5\u5bb9\u7eb3\u6570\u4e2a\u4e0d\u540c\u7684\u6620\u5c04\u5bf9\u8c61\uff0c\u7136\u540e\u5728\u8fdb\u884c\u952e\u67e5\u627e\u64cd\u4f5c\u7684\u65f6\u5019\uff0c\u8fd9\u4e9b\u5bf9\u8c61\u4f1a\u88ab\u5f53\u4f5c\u4e00\u4e2a\u6574\u4f53\u88ab\u9010\u4e2a\u67e5\u627e\uff0c\u76f4\u5230\u952e\u88ab\u627e\u5230\u4e3a\u6b62\u3002\u8fd9\u4e2a\u529f\u80fd\u5728\u7ed9\u6709\u5d4c\u5957\u4f5c\u7528\u57df\u7684\u8bed\u8a00\u505a\u89e3\u91ca\u5668\u7684\u65f6\u5019\u5f88\u6709\u7528\uff0c\u53ef\u4ee5\u7528\u4e00\u4e2a\u6620\u5c04\u5bf9\u8c61\u6765\u4ee3\u8868\u4e00\u4e2a\u4f5c\u7528\u57df\u7684\u4e0a\u4e0b\u6587\u3002 collections.Counter \u8fd9\u4e2a\u6620\u5c04\u7c7b\u578b\u4f1a\u7ed9\u952e\u51c6\u5907\u4e00\u4e2a\u6574\u6570\u8ba1\u6570\u5668\u3002\u6bcf\u6b21\u66f4\u65b0\u4e00\u4e2a\u952e\u7684\u65f6\u5019\u90fd\u4f1a\u589e\u52a0\u8fd9\u4e2a\u8ba1\u6570\u5668\u3002\u6240\u4ee5\u8fd9\u4e2a\u7c7b\u578b\u53ef\u4ee5\u7528\u6765\u7ed9\u53ef\u6563\u5217\u8868\u5bf9\u8c61\u8ba1\u6570\uff0c\u6216\u8005\u662f\u5f53\u6210\u591a\u91cd\u96c6\u6765\u7528\u2014\u2014\u591a\u91cd\u96c6\u5408\u5c31\u662f\u96c6\u5408\u91cc\u7684\u5143\u7d20\u53ef\u4ee5\u51fa\u73b0\u4e0d\u6b62\u4e00\u6b21\u3002Counter\u5b9e\u73b0\u4e86+\u548c-\u8fd0\u7b97\u7b26\u7528\u6765\u5408\u5e76\u8bb0\u5f55\uff0c\u8fd8\u6709\u50cfmost_common([n])\u8fd9\u7c7b\u5f88\u6709\u7528\u7684\u65b9\u6cd5\u3002most_common([n])\u4f1a\u6309\u7167\u6b21\u5e8f\u8fd4\u56de\u6620\u5c04\u91cc\u6700\u5e38\u89c1\u7684n\u4e2a\u952e\u548c\u5b83\u4eec\u7684\u8ba1\u6570 collections.UserDict \u8fd9\u4e2a\u7c7b\u5176\u5b9e\u5c31\u662f\u628a\u6807\u51c6dict\u7528\u7eafPython\u53c8\u5b9e\u73b0\u4e86\u4e00\u904d\u3002\u8ddfOrderedDict\u3001ChainMap\u548cCounter\u8fd9\u4e9b\u5f00\u7bb1\u5373\u7528\u7684\u7c7b\u578b\u4e0d\u540c\uff0cUserDict\u662f\u8ba9\u7528\u6237\u7ee7\u627f\u5199\u5b50\u7c7b\u7684\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u5229\u7528Counter\u6765\u8ba1\u7b97\u5355\u8bcd\u4e2d\u5404\u4e2a\u5b57\u6bcd\u51fa\u73b0\u7684\u6b21\u6570\uff1a str = 'abracadabra' ct = collections . Counter ( str ) print ( ct ) # Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}) \u4e0d\u53ef\u53d8\u6620\u5c04\u7c7b\u578b\u3002 \u6807\u51c6\u5e93\u91cc\u6240\u6709\u7684\u6620\u5c04\u7c7b\u578b\u90fd\u662f\u53ef\u53d8\u7684\uff0c\u4f46\u6709\u65f6\u5019\u4f60\u4f1a\u6709\u8fd9\u6837\u7684\u9700\u6c42\uff0c\u6bd4\u5982\u4e0d\u80fd\u8ba9\u7528\u6237\u9519\u8bef\u5730\u4fee\u6539\u67d0\u4e2a\u6620\u5c04\u3002 \u4ecePython 3.3\u5f00\u59cb\uff0c types \u6a21\u5757\u4e2d\u5f15\u5165\u4e86\u4e00\u4e2a\u5c01\u88c5\u7c7b\u540d\u53eb MappingProxyType \u3002\u5982\u679c\u7ed9\u8fd9\u4e2a\u7c7b\u4e00\u4e2a\u6620\u5c04\uff0c\u5b83\u4f1a\u8fd4\u56de\u4e00\u4e2a\u53ea\u8bfb\u7684\u6620\u5c04\u89c6\u56fe\u3002\u867d\u7136\u662f\u4e2a\u53ea\u8bfb\u89c6\u56fe\uff0c\u4f46\u662f\u5b83\u662f\u52a8\u6001\u7684\u3002\u8fd9\u610f\u5473\u7740\u5982\u679c\u5bf9\u539f\u6620\u5c04\u505a\u51fa\u4e86\u6539\u52a8\uff0c\u6211\u4eec\u901a\u8fc7\u8fd9\u4e2a\u89c6\u56fe\u53ef\u4ee5\u89c2\u5bdf\u5230\uff0c\u4f46\u662f\u65e0\u6cd5\u901a\u8fc7\u8fd9\u4e2a\u89c6\u56fe\u5bf9\u539f\u6620\u5c04\u505a\u51fa\u4fee\u6539\u3002 \u901a\u8fc7\u4e0b\u4f8b\u53ef\u4ee5\u770b\u51fa\uff0c d \u4e2d\u7684\u5185\u5bb9\u53ef\u4ee5\u901a\u8fc7 d_proxy \u770b\u5230\u3002\u4f46\u662f\u901a\u8fc7 d_proxy \u5e76\u4e0d\u80fd\u505a\u4efb\u4f55\u4fee\u6539\u3002 d_proxy \u662f\u52a8\u6001\u7684\uff0c\u4e5f\u5c31\u662f\u8bf4\u5bf9 d \u6240\u505a\u7684\u4efb\u4f55\u6539\u52a8\u90fd\u4f1a\u53cd\u9988\u5230\u5b83\u4e0a\u9762\u3002 from types import MappingProxyType d = { 1 : 'A' } d_proxy = MappingProxyType ( d ) print ( d ) # {1: 'A'} print ( d_proxy ) # {1: 'A'} print ( d [ 1 ]) # A print ( d_proxy [ 1 ]) # A d [ 2 ] = 'W' print ( d ) # {1: 'A', 2: 'W'} d_proxy [ 2 ] = 'W' # TypeError: 'mappingproxy' object does not support item assignment print ( d_proxy ) # {1: 'A', 2: 'W'}","title":"1.4 \u5b57\u5178\uff08dictionary\uff09"},{"location":"python/Foundation/ch01/#15-set","text":"\u201c\u96c6\u201d\u8fd9\u4e2a\u6982\u5ff5\u5728Python\u4e2d\u7b97\u662f\u6bd4\u8f83\u5e74\u8f7b\u7684\uff0c\u540c\u65f6\u5b83\u7684\u4f7f\u7528\u7387\u4e5f\u6bd4\u8f83\u4f4e\u3002set\u548c\u5b83\u7684\u4e0d\u53ef\u53d8\u7684\u59ca\u59b9\u7c7b\u578bfrozenset\u76f4\u5230Python 2.3\u624d\u9996\u6b21\u4ee5\u6a21\u5757\u7684\u5f62\u5f0f\u51fa\u73b0\uff0c\u7136\u540e\u5728Python 2.6\u4e2d\u5b83\u4eec\u5347\u7ea7\u6210\u4e3a\u5185\u7f6e\u7c7b\u578b\u3002 \u96c6\u5408(set) \uff0c\u5305\u542b\u4e0d\u53ef\u53d8\u7684\u96c6\u5408\uff08frozenset\uff09\uff0c\u662f\u4e00\u79cd\u65e0\u5e8f\u4e14\u5143\u7d20\u552f\u4e00\u7684\u5e8f\u5217\uff0c\u6240\u4ee5\u96c6\u5408\u7684\u672c\u8d28\u662f\u8bb8\u591a\u552f\u4e00\u5bf9\u8c61\u7684\u805a\u96c6\u3002 \u548c\u5b57\u5178\u7c7b\u4f3c\uff0c\u96c6\u5408\u7684\u5143\u7d20\u662f\u4e0d\u53ef\u53d8\u7684\u3002\u53ef\u4ee5\u8ba4\u4e3a\u96c6\u5408\u4e5f\u50cf\u5b57\u5178\uff0c\u4f46\u662f\u53ea\u6709\u952e\u6ca1\u6709\u503c\u3002\u57fa\u672c\u529f\u80fd\u662f\u8fdb\u884c\u6210\u5458\u5173\u7cfb\u6d4b\u8bd5\u548c\u5220\u9664\u91cd\u590d\u5143\u7d20\u3002\u6240\u4ee5\u96c6\u5408\u53e6\u4e00\u4e2a\u7528\u9014\u662f\u53bb\u91cd\u590d\u3002 \u96c6\u5408\u4e2d\u7684\u5143\u7d20\u5fc5\u987b\u662f\u53ef\u6563\u5217\u7684\uff0cset\u7c7b\u578b\u672c\u8eab\u662f\u4e0d\u53ef\u6563\u5217\u7684\uff0c\u4f46\u662ffrozenset\u53ef\u4ee5\u3002\u56e0\u6b64\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u5305\u542b\u4e0d\u540cfrozenset\u7684set\u3002 \u96c6\u5408\u53ef\u4ee5\u6709\u4e24\u79cd\u521b\u5efa\u65b9\u5f0f\uff1a\u901a\u8fc7set()\u51fd\u6570\u6216\u8005{}\u6765\u521b\u5efa\uff08\u7528\u5927\u62ec\u53f7\u62ec\u4f4f\u7684\u5185\u5bb9\uff0cPython3\u81ea\u52a8\u5b9a\u4e49\u4e3a\u96c6\u5408\uff09\u3002 \u96c6\u5408\u4e0d\u5c5e\u4e8e\u5e8f\u5217\u7c7b\u6570\u636e\uff0c \u96c6\u5408\u4e0d\u652f\u6301\u901a\u8fc7\u7d22\u5f15\u8bbf\u95ee\u6307\u5b9a\u5143\u7d20\uff0c\u4f46\u53ef\u4ee5\u589e\u52a0\u548c\u5220\u9664\u5143\u7d20\u3002 \u9762\u7684\u4f8b\u5b50\u662f\u6c42 haystacke \u548c needles \u4e24\u4e2a\u96c6\u5408\u7684\u4ea4\u96c6\u5143\u7d20\u4e2a\u6570\u3002 haystacke = { 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'f' , 'g' , 'h' , 'c' , 'd' , 'e' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' } needles = { 'c' , 'h' , 'w' } type ( haystacke ) # type ( needles ) # # \u4f20\u7edf\u65b9\u6cd5 found = 0 for i in needles : if i in haystacke : found += 1 print ( found ) # 2 # \u96c6\u5408\u65b9\u6cd5\u4e00 found = len ( needles & haystacke ) print ( found ) # 2 # \u96c6\u5408\u65b9\u6cd5\u4e8c found = len ( needles . intersection ( haystacke )) print ( found ) # 2 \u96c6\u5408\u5b9e\u73b0\u4e86\u5f88\u591a\u57fa\u7840\u7684\u4e2d\u7f00\u8fd0\u7b97\u7b26\uff0c\u6bd4\u5982\uff0c\u96c6\u5408\u652f\u6301\u6570\u5b66\u4e0a\u7684\u96c6\u5408\u64cd\u4f5c\uff1a\u5e76\u96c6\u3001\u4ea4\u96c6\u3001\u5dee\u96c6\u3001\u5bf9\u79f0\u5dee\u96c6\u3002 \u65b9\u6cd5\u540d\u79f0 \u8bf4\u660e add() \u4e3a\u96c6\u5408\u6dfb\u52a0\u5143\u7d20 update() \u7ed9\u96c6\u5408\u6dfb\u52a0\u5143\u7d20 clear() \u79fb\u9664\u96c6\u5408\u4e2d\u7684\u6240\u6709\u5143\u7d20 copy() \u62f7\u8d1d\u4e00\u4e2a\u96c6\u5408 remove() \u79fb\u9664\u6307\u5b9a\u5143\u7d20 pop() \u968f\u673a\u79fb\u9664\u5143\u7d20 discard() \u5220\u9664\u96c6\u5408\u4e2d\u6307\u5b9a\u7684\u5143\u7d20 < \u6216\u8005issubset() \u5224\u65ad\u6307\u5b9a\u96c6\u5408\u662f\u5426\u4e3a\u8be5\u65b9\u6cd5\u53c2\u6570\u96c6\u5408\u7684\u5b50\u96c6 | \u6216\u8005union() \u8fd4\u56de\u4e24\u4e2a\u96c6\u5408\u7684\u5e76\u96c6 & \u6216\u8005intersection() \u8fd4\u56de\u96c6\u5408\u7684\u4ea4\u96c6 intersection_update() \u8fd4\u56de\u96c6\u5408\u7684\u4ea4\u96c6 - \u6216\u8005difference() \u8fd4\u56de\u591a\u4e2a\u96c6\u5408\u7684\u5dee\u96c6 difference_update() \u79fb\u9664\u96c6\u5408\u4e2d\u7684\u5143\u7d20\uff0c\u8be5\u5143\u7d20\u5728\u6307\u5b9a\u7684\u96c6\u5408\u4e5f\u5b58\u5728 ^ \u6216\u8005symmetric_difference() \u8fd4\u56de\u4e24\u4e2a\u96c6\u5408\u4e2d\u4e0d\u91cd\u590d\u7684\u5143\u7d20\u96c6\u5408(\u4e24\u96c6\u5408\u9664\u53bb\u4ea4\u96c6\u90e8\u5206\u7684\u5143\u7d20) symmetric_difference_update() \u79fb\u9664\u5f53\u524d\u96c6\u5408\u4e2d\u5728\u53e6\u5916\u4e00\u4e2a\u6307\u5b9a\u96c6\u5408\u76f8\u540c\u7684\u5143\u7d20\uff0c\u5e76\u5c06\u53e6\u5916\u4e00\u4e2a\u6307\u5b9a\u96c6\u5408\u4e2d\u4e0d\u540c\u7684\u5143\u7d20\u63d2\u5165\u5230\u5f53\u524d\u96c6\u5408\u4e2d isdisjoint() \u5224\u65ad\u4e24\u4e2a\u96c6\u5408\u662f\u5426\u5305\u542b\u76f8\u540c\u7684\u5143\u7d20\uff0c\u5982\u679c\u6ca1\u6709\u8fd4\u56de True\uff0c\u5426\u5219\u8fd4\u56de False issuperset() \u5224\u65ad\u8be5\u65b9\u6cd5\u7684\u53c2\u6570\u96c6\u5408\u662f\u5426\u4e3a\u6307\u5b9a\u96c6\u5408\u7684\u5b50\u96c6 \u4e3e\u4f8b\uff1a a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } \u5e76\u96c6(a\u548cb\u4e2d\u7684\u6240\u6709\u4e0d\u540c\u5143\u7d20)\u3002 print ( a . union ( b )) # {'c', 1, 2, 'd', 'a', 'b'} print ( a | b ) # {'c', 1, 2, 'd', 'a', 'b'} \u4ea4\u96c6(a\u3001b\u4e2d\u540c\u65f6\u5305\u542b\u7684\u5143\u7d20)\u3002 print ( a . intersection ( b )) # {'c', 1} print ( a & b ) # {'c', 1} \u5c06a\u7684\u5185\u5bb9\u8bbe\u7f6e\u4e3aa\u548cb\u7684\u4ea4\u96c6\u3002 a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a . intersection_update ( b ) print ( a ) # {1, 'c'} \u5728a\u4e0d\u5728b\u7684\u5143\u7d20\u3002 print ( a . difference ( b )) # {'a', 2, 'b'} print ( a - b ) # {2, 'a', 'b'} \u5c06a\u7684\u5185\u5bb9\u8bbe\u4e3a\u5728a\u4e0d\u5728b\u7684\u5143\u7d20\u3002 a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a . difference_update ( b ) print ( a ) # {2, 'b', 'a'} a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a -= b print ( a ) # {2, 'a', 'b'} \u5c06\u5143\u7d20\u52a0\u5165\u96c6\u5408a\u3002 a . add ( 7 ) print ( a ) # {1, 2, 'c', 7, 'a', 'b'} \u6bcf\u6b21\u8f93\u51fa\u7684\u987a\u5e8f\u662f\u4e0d\u4e00\u6837\u7684 \u4ece\u96c6\u5408a\u79fb\u9664\u67d0\u4e2a\u5143\u7d20\u3002 a . remove ( 7 ) print ( a ) # {1, 2, 'c', 'a', 'b'} \u5982\u679ca\u88ab\u6e05\u7a7a\uff0c\u5219\u62a5\u9519 KeyError: 7 \u6240\u6709\u5728a\u6216b\u4e2d\uff0c\u4f46\u4e0d\u662f\u540c\u65f6\u5728a\u3001b\u4e2d\u7684\u5143\u7d20\u3002 print ( a . symmetric_difference ( b )) # {2, 'd', 'b', 'a'} print ( a ^ b ) # {2, 'd', 'b', 'a'} \u5c06a\u7684\u5185\u5bb9\u8bbe\u4e3a\u6240\u6709\u5728a\u6216b\u4e2d\uff0c\u4f46\u4e0d\u662f\u540c\u65f6\u5728a\u3001b\u4e2d\u7684\u5143\u7d20\u3002 a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a . symmetric_difference_update ( b ) print ( a ) # {'a', 2, 'd', 'b'} a = { 'a' , 'b' , 'c' , 1 , 2 } b = { 1 , 'c' , 'd' } a ^= b print ( a ) # {2, 'd', 'a', 'b'} \u5982\u679ca\u5305\u542b\u4e8eb\uff0c\u8fd4\u56deTure\u3002 print ( a . issubset ( b )) # False \u5c06a\u7684\u5185\u5bb9\u8bbe\u7f6e\u4e3aa\u548cb\u7684\u5e76\u96c6\u3002 print ( a ) # {'a', 2, 'd', 'b'} a = { 'a' , 'b' , 'c' , 1 , 2 } a . update ( b ) print ( a ) # {1, 2, 'a', 'b', 'd', 'c'} \u79fb\u9664\u4efb\u610f\u5143\u7d20\uff0c\u5982\u679c\u96c6\u5408\u662f\u7a7a\u7684\uff0c\u629b\u51fakeyError\u3002 a . pop () # \u968f\u673a\u79fb\u9664\u67d0\u4e2a\u5143\u7d20\uff0c\u6ca1\u6709\u8f93\u5165\u53d8\u91cf\uff0c\u5982\u679c\u96c6\u5408\u662f\u7a7a\u7684\uff0c\u629b\u51faKeyError: 'pop from an empty set' print ( a ) # {2, 1, 'd', 'b', 'a'} \u5c06\u96c6\u5408\u91cd\u7f6e\u4e3a\u7a7a\uff0c\u6e05\u7a7a\u6240\u6709\u5143\u7d20\u3002 a . clear () print ( a ) # set() \u96c6\u5408\u7684\u5143\u7d20\u5fc5\u987b\u662f\u4e0d\u53ef\u53d8\u7684\uff0c\u5982\u679c\u60f3\u8981\u5305\u542b\u5217\u8868\u578b\u7684\u5143\u7d20\uff0c\u5fc5\u987b\u5148\u8f6c\u6362\u4e3a\u5143\u7ec4\u3002 my_data1 = [ 1 , 2 , 3 , 4 ] my_data2 = [ 3 , 4 , 5 , 6 ] my_set = { tuple ( my_data1 ), tuple ( my_data2 )} print ( my_set ) # {(1, 2, 3, 4), (3, 4, 5, 6)}","title":"1.5 \u96c6\u5408\uff08set\uff09"},{"location":"python/Foundation/ch01/#16-tuple","text":"Python \u7684\u5143\u7ec4\u4e0e\u5217\u8868\u7c7b\u4f3c\uff0c\u4e0d\u540c\u4e4b\u5904\u5728\u4e8e\u5143\u7ec4\u7684\u5143\u7d20\u4e0d\u80fd\u4fee\u6539\u3002 \u5143\u7ec4\u4f7f\u7528\u5c0f\u62ec\u53f7( )\uff0c\u5217\u8868\u4f7f\u7528\u65b9\u62ec\u53f7[ ]\u3002 \u5143\u7ec4\u4e2d\u53ea\u5305\u542b\u4e00\u4e2a\u5143\u7d20\u65f6\uff0c\u9700\u8981\u5728\u5143\u7d20\u540e\u9762\u6dfb\u52a0\u9017\u53f7 \uff0c\u5426\u5219\u62ec\u53f7\u4f1a\u88ab\u5f53\u4f5c\u8fd0\u7b97\u7b26\u4f7f\u7528\u3002 \u5143\u7ec4\u53ef\u4ee5\u4f7f\u7528\u4e0b\u6807\u7d22\u5f15\u6765\u8bbf\u95ee\u5143\u7ec4\u4e2d\u7684\u503c\u3002 \u5143\u7ec4\u4e2d\u7684\u5143\u7d20\u503c\u662f\u4e0d\u5141\u8bb8\u4fee\u6539\u7684\uff0c\u4f46\u6211\u4eec\u53ef\u4ee5\u5bf9\u5143\u7ec4\u8fdb\u884c\u8fde\u63a5\u7ec4\u5408\u3002 \u5143\u7ec4\u4e2d\u7684\u5143\u7d20\u503c\u662f\u4e0d\u5141\u8bb8\u5220\u9664\u7684\uff0c\u4f46\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528del\u8bed\u53e5\u6765\u5220\u9664\u6574\u4e2a\u5143\u7ec4\u3002 # \u6b64\u5904\u62ec\u53f7\u88ab\u89e3\u6790\u4e3a\u8fd0\u7b97\u7b26\uff0c\u9700\u8981\u5728\u540e\u9762\u52a0\u4e0a\u9017\u53f7\u624d\u4f1a\u88ab\u89e3\u91ca\u4e3a\u5143\u7ec4 tup1 = ( 10 ) print ( type ( tup1 )) # tup1 = ( 10 ,) print ( type ( tup1 )) # \u521b\u5efa\u5143\u7ec4\u6700\u7b80\u5355\u7684\u529e\u6cd5\u5c31\u662f\u7528\u9017\u53f7\u5206\u9694\u5e8f\u5217\u503c\u3002\u5143\u7ec4\u5bf9\u6570\u636e\u7c7b\u578b\u6ca1\u6709\u4e00\u81f4\u6027\u8981\u6c42\u3002 tup = 4 , 5 , 6 print ( tup ) # (4, 5, 6) nested_tup = ( 4 , 5 , 6 ), ( 7 , 8 ) print ( nested_tup ) # # ((4, 5, 6), (7, 8)) tup = ( 'a' , 'b' , { 'one' : 1 }) print ( type ( tup )) # \u4f7f\u7528\u52a0\u53f7\uff08+\uff09\u8fdb\u884c\u5143\u7ec4\u8fde\u63a5\u5408\u5e76\u3002 tup = tuple (( 4 , None , 'fool' ) + ( 6 , 0 ) + ( 'bar' ,)) print ( tup ) # (4, None, 'fool', 6, 0, 'bar') \u5143\u7ec4\u7684\u4e0d\u53ef\u53d8\u6307\u7684\u662f**\u5143\u7ec4\u6240\u6307\u5411\u7684\u5185\u5b58\u4e2d\u7684\u5185\u5bb9\u4e0d\u53ef\u53d8**\u3002 tup = ( 'h' , 'e' , 'l' , 'l' , 'o' ) print ( id ( tup )) # 139820353350208 tup = ( 1 , 2 , 3 , 4 , 5 ) print ( id ( tup )) # 139820353298896 tup [ 0 ] = 'x' # Traceback (most recent call last): # File \"\", line 1, in # TypeError: 'tuple' object does not support item assignment \u5c06\u5143\u7ec4\u4e58\u4ee5\u6574\u6570\uff0c\u5219\u4f1a\u548c\u5217\u8868\u4e00\u6837\uff0c\u751f\u6210\u542b\u6709\u591a\u4efd\u62f7\u8d1d\u7684\u5143\u7ec4\u3002\u5bf9\u8c61\u81ea\u8eab\u5e76\u6ca1\u6709\u590d\u5236\uff0c\u53ea\u662f\u6307\u5411\u5b83\u4eec\u7684\u5f15\u7528\u8fdb\u884c\u4e86\u590d\u5236\u3002 tup = tuple (( 'fool' , 'bar' ) * 4 ) print ( tup ) # ('fool', 'bar', 'fool', 'bar', 'fool', 'bar', 'fool', 'bar') \u5982\u679c\u5143\u7ec4\u4e2d\u7684\u4e00\u4e2a\u5bf9\u8c61\u662f\u53ef\u53d8\u7684\uff0c\u4f8b\u5982\u5217\u8868\uff0c\u4f60\u53ef\u4ee5\u5728\u5b83\u5185\u90e8\u8fdb\u884c\u4fee\u6539\u3002 tup = tuple ([ 'foo' , [ 4 , 5 , 6 ], True ]) tup [ 1 ] . append ( 0 ) print ( tup ) # ('foo', [4, 5, 6, 0], True) tup [ 1 ] . append ([ 9 ]) print ( tup ) # ('foo', [4, 5, 6, 0, [9]], True) \u4f7f\u7528tuple\u51fd\u6570\u5c06\u4efb\u610f\u5e8f\u5217\u6216\u8fed\u4ee3\u5668\u8f6c\u6362\u4e3a\u5143\u7ec4\u3002 tup = tuple ([ 4 , 5 , 6 ]) print ( tup ) # (4, 5, 6) tup = tuple ( 'string' ) print ( tup ) # ('s', 't', 'r', 'i', 'n', 'g') print ( tup [ 2 ]) # r # \u5143\u7ec4\u7684\u5143\u7d20\u53ef\u4ee5\u901a\u8fc7\u4e2d\u62ec\u53f7[]\u6765\u83b7\u53d6 \u5982\u679c\u8981\u5c06\u5143\u7ec4\u578b\u7684\u8868\u8fbe\u5f0f\u8d4b\u503c\u7ed9\u53d8\u91cf\uff0cPython\u4f1a\u5bf9\u7b49\u53f7\u53f3\u8fb9\u7684\u503c\u8fdb\u884c \u62c6\u5305 \u3002 tup = ( 9 , 5 , ( 8 , 7 )) a , b , c = tup print ( a ) # 9 print ( b ) # 5 print ( c ) # (8, 7) a , b , ( c , d ) = tup print ( a ) # 9 print ( b ) # 5 print ( c ) # 8 print ( d ) # 7 tup = ( 9 , 5 , ( 8 , 7 )) a , b , c = tup c , a = a , c # \u5229\u7528\u62c6\u5305\u5b9e\u73b0\u4ea4\u6362 print ( a ) # (8, 7) print ( b ) # 5 print ( c ) # 9 \u5229\u7528\u62c6\u5305\u5b9e\u73b0\u904d\u5386\u5143\u7ec4\u6216\u5217\u8868\u7ec4\u6210\u7684\u5e8f\u5217\u3002 seq = [( 1 , 2 , 3 ), ( 4 , 5 , 6 ), ( 7 , 8 , 9 )] for a , b , c in seq : print ( 'a= {0} , b= {0} , c= {0} ' . format ( a , b , c )) # \u5217\u8868\u6bcf\u4e2a\u5143\u7d20\u7684\u53d6\u503c\u987a\u5e8f # a=1, b=1, c=1 # a=4, b=4, c=4 # a=7, b=7, c=7 print ( 'a= {0} , b= {1} , c= {2} ' . format ( a , b , c )) # a=1, b=2, c=3 # a=4, b=5, c=6 # a=7, b=8, c=9 print ( 'a= {2} , b= {0} , c= {1} ' . format ( a , b , c )) # a=3, b=1, c=2 # a=6, b=4, c=5 # a=9, b=7, c=8 \u5143\u7ec4\u62c6\u5305\u529f\u80fd\u8fd8\u5305\u62ec\u7279\u6b8a\u7684\u8bed\u6cd5*rest\u3002\u5f88\u591aPython\u7f16\u7a0b\u8005\u4f1a\u4f7f\u7528\u4e0b\u5212\u7ebf\uff08_\uff09\u6765\u8868\u793a\u4e0d\u60f3\u8981\u7684\u53d8\u91cf\u3002 values = 1 , 2 , 3 , 4 , 5 a , b , * rest = values print ( a ) # 1 print ( b ) # 2 print ( * rest ) # 3 4 5 a , b , * _ = values print ( * _ ) # 3 4 5 \u5177\u540d\u5143\u7ec4\u3002 collections.namedtuple \u662f\u4e00\u4e2a\u5de5\u5382\u51fd\u6570\uff0c\u5b83\u53ef\u4ee5\u7528\u6765\u6784\u5efa\u4e00\u4e2a\u5e26\u5b57\u6bb5\u540d\u7684\u5143\u7ec4\u548c\u4e00\u4e2a\u6709\u540d\u5b57\u7684\u7c7b\u3002 \u7528namedtuple\u6784\u5efa\u7684\u7c7b\u7684\u5b9e\u4f8b\u6240\u6d88\u8017\u7684\u5185\u5b58\u8ddf\u5143\u7ec4\u662f\u4e00\u6837\u7684\uff0c\u56e0\u4e3a\u5b57\u6bb5\u540d\u90fd\u88ab\u5b58\u5728\u5bf9\u5e94\u7684\u7c7b\u91cc\u9762\u3002 \u521b\u5efa\u4e00\u4e2a\u5177\u540d\u5143\u7ec4\u9700\u8981\u4e24\u4e2a\u53c2\u6570\uff0c\u4e00\u4e2a\u662f\u7c7b\u540d( City )\uff0c\u53e6\u4e00\u4e2a\u662f\u7c7b\u7684\u5404\u4e2a\u5b57\u6bb5\u7684\u540d\u5b57( 'name country population coordinates' )\u3002\u540e\u8005\u53ef\u4ee5\u662f\u7531\u6570\u4e2a\u5b57\u7b26\u4e32\u7ec4\u6210\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff0c\u6216\u8005\u662f\u7531\u7a7a\u683c\u5206\u9694\u5f00\u7684\u5b57\u6bb5\u540d\u7ec4\u6210\u7684\u5b57\u7b26\u4e32\u3002 \u5b58\u653e\u5728\u5bf9\u5e94\u5b57\u6bb5\u91cc\u7684\u6570\u636e\u8981\u4ee5\u4e00\u4e32\u53c2\u6570\u7684\u5f62\u5f0f\u4f20\u5165\u5230\u6784\u9020\u51fd\u6570\u4e2d\uff08\u6ce8\u610f\uff0c\u5143\u7ec4\u7684\u6784\u9020\u51fd\u6570\u5374\u53ea\u63a5\u53d7\u5355\u4e00\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff09\u3002 \u5177\u540d\u5143\u7ec4\u8fd8\u6709\u4e00\u4e9b\u81ea\u5df1\u4e13\u6709\u7684\u5c5e\u6027\u3002\u4e0b\u9762\u5c55\u793a\u4e86\u51e0\u4e2a\u6700\u6709\u7528\u7684\uff1a _fields \u7c7b\u5c5e\u6027\u3001\u7c7b\u65b9\u6cd5 _make(iterable) \u548c\u5b9e\u4f8b\u65b9\u6cd5 _asdict() \u3002 _fields \u5c5e\u6027\u662f\u4e00\u4e2a\u5305\u542b\u8fd9\u4e2a\u7c7b\u6240\u6709\u5b57\u6bb5\u540d\u79f0\u7684\u5143\u7ec4\u3002 \u7528 _make() \u901a\u8fc7\u63a5\u53d7\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u6765\u751f\u6210\u8fd9\u4e2a\u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u5b83\u7684\u4f5c\u7528\u8ddf City(*delhi_data) \u662f\u4e00\u6837\u7684\u3002 _asdict() \u628a\u5177\u540d\u5143\u7ec4\u4ee5 collections.OrderedDict \u7684\u5f62\u5f0f\u8fd4\u56de\uff0c\u6211\u4eec\u53ef\u4ee5\u5229\u7528\u5b83\u6765\u628a\u5143\u7ec4\u91cc\u7684\u4fe1\u606f\u53cb\u597d\u5730\u5448\u73b0\u51fa\u6765\u3002 from collections import namedtuple City = namedtuple ( 'City' , 'name country population coordinates' ) tokyo = City ( 'Tokyo' , 'JP' , 36.933 , ( 35.689722 , 139691667 )) print ( tokyo ) # City(name='Tokyo', country='JP', population=36.933, coordinates=(35.689722, 139691667)) print ( tokyo . population ) # 36.933 print ( tokyo [ 3 ]) # (35.689722, 139691667) print ( City . _fields ) # ('name', 'country', 'population', 'coordinates') LatLong = namedtuple ( 'LatLong' , 'lat long' ) delhi_data = ( 'Delhi NCR' , 'IN' , 21.935 , LatLong ( 28.613899 , 77.208889 )) delhi = City . _make ( delhi_data ) print ( delhi ) # City(name='Delhi NCR', country='IN', population=21.935, coordinates=LatLong(lat=28.613899, long=77.208889)) print ( delhi . _asdict ()) # OrderedDict([('name', 'Delhi NCR'), ('country', 'IN'), ('population', 21.935), ('coordinates', LatLong(lat=28.613899, long=77.208889))]) for key , value in delhi . _asdict () . items (): print ( key + ':' , value ) # name: Delhi NCR # country: IN # population: 21.935 # coordinates: LatLong(lat=28.613899, long=77.208889) \u5143\u7ec4\u8fd8\u6709\u7b2c\u4e8c\u91cd\u529f\u80fd\uff1a\u4f5c\u4e3a\u4e0d\u53ef\u53d8\u5217\u8868\u7684\u5143\u7ec4\u3002 \u4e0b\u9762\u662f\u5217\u8868\u6216\u5143\u7ec4\u7684\u65b9\u6cd5\u548c\u5c5e\u6027\u5bf9\u6bd4\u3002\u9664\u4e86\u8ddf\u589e\u51cf\u5143\u7d20\u76f8\u5173\u7684\u65b9\u6cd5\u4e4b\u5916\uff0c\u5143\u7ec4\u652f\u6301\u5217\u8868\u7684\u5176\u4ed6\u6240\u6709\u65b9\u6cd5\u3002\u8fd8\u6709\u4e00\u4e2a\u4f8b\u5916\uff0c\u5143\u7ec4\u6ca1\u6709__reversed__\u65b9\u6cd5\u3002 \u4e00\u4e2a\u5173\u4e8e+=\u548c*=\u7684\u8c1c\u9898\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u5c55\u793a\u4e86 *= \u5728\u53ef\u53d8\u548c\u4e0d\u53ef\u53d8\u5e8f\u5217\u4e0a\u7684\u4f5c\u7528\u3002\u5217\u8868\u7684ID\u6ca1\u53d8\uff0c\u65b0\u5143\u7d20\u8ffd\u52a0\u5230\u5217\u8868\u4e0a\uff0c\u4f46\u6267\u884c\u589e\u91cf\u4e58\u6cd5\u540e\uff0c\u65b0\u7684\u5143\u7ec4\u88ab\u521b\u5efa\u3002 list1 = [ 1 , 2 , 3 , 4 ] id ( list1 ) # 140409777308808 list1 *= 2 print ( list1 ) # [1, 2, 3, 4, 1, 2, 3, 4] id ( list1 ) # 140409777308808 tuple1 = ( 1 , 2 , 3 , 4 ) id ( tuple1 ) # 140409777230536 tuple1 *= 2 print ( tuple1 ) # (1, 2, 3, 4, 1, 2, 3, 4) id ( tuple1 ) # 140409780104888 \u4f46\u5bf9\u4e8e\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u867d\u7136 tuple1[2] += [50, 60] \u6267\u884c\u65f6\u6709\u5f02\u5e38\u629b\u51fa\uff0c\u4f46 tuple1 \u5374\u88ab\u4fee\u6539\u4e86\u3002 t = ( 1 , 2 , [ 10 , 20 ]) t [ 2 ] += [ 50 , 60 ] # TypeError: 'tuple' object does not support item assignment print ( t ) # (1, 2, [10, 20, 50, 60]) \u4e0b\u56fe\u5927\u81f4\u63cf\u8ff0\u4e86\u4e0a\u8ff0\u6267\u884c\u8fc7\u7a0b\u3002 \u4e3a\u4e86\u907f\u514d\u4e0a\u9762\u60c5\u51b5\u7684\u53d1\u751f\uff0c\u6211\u4eec**\u4e0d\u8981\u628a\u53ef\u53d8\u5bf9\u8c61\u653e\u5728\u5143\u7ec4\u91cc\u9762**\u3002\u589e\u91cf\u8d4b\u503c\u4e0d\u662f\u4e00\u4e2a\u539f\u5b50\u64cd\u4f5c\uff0c\u5b83\u867d\u7136\u629b\u51fa\u4e86\u5f02\u5e38\uff0c\u4f46\u8fd8\u662f\u5b8c\u6210\u4e86\u64cd\u4f5c\u3002","title":"1.6 \u5143\u7ec4\uff08tuple\uff09"},{"location":"python/Foundation/ch01/#17-memoryview","text":"memoryview \u662f\u4e00\u4e2a\u5185\u7f6e\u7c7b\uff0c\u5b83\u80fd\u8ba9\u7528\u6237\u5728\u4e0d\u590d\u5236\u5185\u5bb9\u7684\u60c5\u51b5\u4e0b\u64cd\u4f5c\u540c\u4e00\u4e2a\u6570\u7ec4\u7684\u4e0d\u540c\u5207\u7247\u3002 \u5185\u5b58\u89c6\u56fe\u5176\u5b9e\u662f\u6cdb\u5316\u548c\u53bb\u6570\u5b66\u5316\u7684NumPy\u6570\u7ec4\u3002\u5b83\u8ba9\u4f60\u5728\u4e0d\u9700\u8981\u590d\u5236\u5185\u5bb9\u7684\u524d\u63d0\u4e0b\uff0c\u5728\u6570\u636e\u7ed3\u6784\u4e4b\u95f4\u5171\u4eab\u5185\u5b58\u3002 \u5176\u4e2d\u6570\u636e\u7ed3\u6784\u53ef\u4ee5\u662f\u4efb\u4f55\u5f62\u5f0f\uff0c\u6bd4\u5982PIL\u56fe\u7247\u3001SQLite\u6570\u636e\u5e93\u548cNumPy\u7684\u6570\u7ec4\uff0c\u7b49\u7b49\u3002\u8fd9\u4e2a\u529f\u80fd\u5728\u5904\u7406\u5927\u578b\u6570\u636e\u96c6\u5408\u7684\u65f6\u5019\u975e\u5e38\u91cd\u8981\u3002 memoryview.cast \u7684\u6982\u5ff5\u8ddf\u6570\u7ec4\u6a21\u5757\u7c7b\u4f3c\uff0c\u80fd\u7528\u4e0d\u540c\u7684\u65b9\u5f0f\u8bfb\u5199\u540c\u4e00\u5757\u5185\u5b58\u6570\u636e\uff0c\u800c\u4e14\u5185\u5bb9\u5b57\u8282\u4e0d\u4f1a\u968f\u610f\u79fb\u52a8\u3002\u8fd9\u8ddfC\u8bed\u8a00\u4e2d\u7c7b\u578b\u8f6c\u6362\u7684\u6982\u5ff5\u5dee\u4e0d\u591a\u3002 memoryview.cast \u4f1a\u628a\u540c\u4e00\u5757\u5185\u5b58\u91cc\u7684\u5185\u5bb9\u6253\u5305\u6210\u4e00\u4e2a\u5168\u65b0\u7684memoryview\u5bf9\u8c61\u7ed9\u4f60\u3002 array \u91cc\u9762\u7684Type code\uff1a 'b' signed integer 1 'B' unsigned integer 1 'u' Unicode character 2 (see note) 'h' signed integer 2 'H' unsigned integer 2 'i' signed integer 2 'I' unsigned integer 2 'l' signed integer 4 'L' unsigned integer 4 'q' signed integer 8 (see note) 'Q' unsigned integer 8 (see note) 'f' floating point 4 'd' floating point 8 numbers = array ( 'h' , [ - 2 , - 1 , 0 , 1 , 2 ]) # array('h', [-2, -1, 0, 1, 2]) # \u75285\u4e2a\u77ed\u6574\u578b\u6709\u7b26\u53f7\u6574\u6570\u7684\u6570\u7ec4\uff08\u7c7b\u578b\u7801\u662f'h'\uff09\u521b\u5efa\u4e00\u4e2amemoryview\u3002 memv = memoryview ( numbers ) # memv\u91cc\u76845\u4e2a\u5143\u7d20\u8ddf\u6570\u7ec4\u91cc\u7684\u6ca1\u6709\u533a\u522b\u3002 print ( len ( memv )) # 5 print ( memv [ 0 ]) # -2 print ( memv . tolist ()) # [-2, -1, 0, 1, 2] # \u521b\u5efa\u4e00\u4e2amemv_oct\uff0c\u8fd9\u4e00\u6b21\u662f\u628amemv\u91cc\u7684\u5185\u5bb9\u8f6c\u6362\u6210'B'\u7c7b\u578b\uff0c\u4e5f\u5c31\u662f\u65e0\u7b26\u53f7\u5b57\u7b26\u3002 memv_oct = memv . cast ( 'B' ) print ( memv_oct . tolist ()) # [254, 255, 255, 255, 0, 0, 1, 0, 2, 0] # \u628a\u4f4d\u4e8e\u4f4d\u7f6e5\u7684\u5b57\u8282\u8d4b\u503c\u62104\u3002\u56e0\u4e3a\u6211\u4eec\u628a\u53602\u4e2a\u5b57\u8282\u7684\u6574\u6570\u7684\u9ad8\u4f4d\u5b57\u8282\u6539\u6210\u4e864\uff0c\u6240\u4ee5\u8fd9\u4e2a\u6709\u7b26\u53f7\u6574\u6570\u7684\u503c\u5c31\u53d8\u6210\u4e861024\u3002 memv_oct [ 5 ] = 4 print ( numbers ) # array('h', [-2, -1, 1024, 1, 2])","title":"1.7 \u5185\u5b58\u89c6\u56feMemoryview"},{"location":"python/Foundation/ch01/#2","text":"\u661f\u53f7 * \u7684\u53c2\u6570\u4f1a\u4ee5\u5143\u7ec4(tuple)\u7684\u5f62\u5f0f\u5bfc\u5165\uff0c\u5b58\u653e\u6240\u6709\u672a\u547d\u540d\u7684\u53d8\u91cf\u53c2\u6570 def printinfo ( arg1 , * vartuple ): print ( \"\u8f93\u51fa\u4efb\u4f55\u4f20\u5165\u7684\u53c2\u6570: \" ) print ( arg1 ) print ( vartuple ) for var in vartuple : print ( var ) return printinfo ( 10 ) # 10 # () printinfo ( 70 , 60 , 50 ) # 70 # (60, 50) # 60 # 50 \u4e24\u4e2a\u661f\u53f7 ** \u7684\u53c2\u6570\u4f1a\u4ee5\u5b57\u5178\u7684\u5f62\u5f0f\u5bfc\u5165\u3002 def printinfo ( arg1 , ** vardict ): print ( \"\u8f93\u51fa\u4efb\u4f55\u4f20\u5165\u7684\u53c2\u6570: \" ) print ( arg1 ) print ( vardict ) printinfo ( 1 , a = 2 , b = 3 ) # 1 # {'a': 2, 'b': 3} \u5b57\u5178\u683c\u5f0f\u8f93\u51fa Python\u4e2d\u7684\u5bf9\u8c61\u5f15\u7528\u5e76\u4e0d\u6d89\u53ca\u7c7b\u578b\u3002\u53d8\u91cf\u5bf9\u4e8e\u5bf9\u8c61\u6765\u8bf4\u53ea\u662f\u7279\u5b9a\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u540d\u79f0\uff1b\u7c7b\u578b\u4fe1\u606f\u662f\u5b58\u50a8\u5728\u5bf9\u8c61\u81ea\u8eab\u4e4b\u4e2d\u3002 a = 5 print ( type ( a )) # a = 'foo' print ( type ( a )) # Python\u662f\u5f3a\u7c7b\u578b\u8bed\u8a00\uff0c\u6240\u6709\u7684\u5bf9\u8c61\u90fd\u62e5\u6709\u4e00\u4e2a\u6307\u5b9a\u7684\u7c7b\u578b\uff08\u6216\u7c7b\uff09\uff0c\u9690\u5f0f\u7684\u8f6c\u6362\u53ea\u5728\u67d0\u4e9b\u7279\u5b9a\u3001\u660e\u663e\u7684\u60c5\u51b5\u4e0b\u53d1\u751f\u3002 a = 4.5 b = 2 print ( 'a is {0} , b is {1} ' . format ( type ( a ), type ( b ))) # a is , b is \u5b57\u4e32\u683c\u5f0f\u5316\uff0c\u7528\u4e8e\u540e\u7eed\u8bbf\u95ee print ( a / b ) # 2.25 \u4f7f\u7528isinstance\u51fd\u6570\u6765\u68c0\u67e5\u4e00\u4e2a\u5bf9\u8c61\u662f\u5426\u662f\u7279\u5b9a\u7c7b\u578b\u7684\u5b9e\u4f8b\u3002isinstance\u63a5\u53d7\u4e00\u4e2a\u5305\u542b\u7c7b\u578b\u7684\u5143\u7ec4\uff0c\u53ef\u4ee5\u68c0\u67e5\u5bf9\u8c61\u7684\u7c7b\u578b\u662f\u5426\u5728\u5143\u7ec4\u4e2d\u7684\u7c7b\u578b\u4e2d\u3002 a = 5 b = 4.5 c = 'foo' print ( isinstance ( a , int )) # True print ( isinstance ( b , str )) # False print ( isinstance ( c , ( str , int ))) # True print ( isinstance ( c , ( float , int ))) # False \u5c5e\u6027\u548c\u65b9\u6cd5\u4e5f\u53ef\u4ee5\u901a\u8fc7getattr\u51fd\u6570\u83b7\u5f97\u3002\u5728\u5176\u4ed6\u7684\u8bed\u8a00\u4e2d\uff0c\u901a\u8fc7\u53d8\u91cf\u540d\u8bbf\u95ee\u5bf9\u8c61\u901a\u5e38\u88ab\u79f0\u4e3a\u201c\u53cd\u5c04\u201d\u3002 b = 'foo' print ( getattr ( b , 'split' )) # ","title":"2. \u52a8\u6001\u5f15\u7528\u3001\u5f3a\u7c7b\u578b"},{"location":"python/Foundation/ch01/#3","text":"\u68c0\u67e5\u4e24\u4e2a\u5f15\u7528\u662f\u5426\u6307\u5411\u540c\u4e00\u4e2a\u5bf9\u8c61\uff0c\u53ef\u4ee5\u4f7f\u7528is\u5173\u952e\u5b57\u3002 is\u548cis not\u7684\u5e38\u7528\u4e4b\u5904\u662f\u68c0\u67e5\u4e00\u4e2a\u53d8\u91cf\u662f\u5426\u4e3aNone\uff0c\u56e0\u4e3aNone\u53ea\u6709\u4e00\u4e2a\u5b9e\u4f8b\u3002 a = [ 1 , 2 , 3 ] b = a c = list ( a ) # list\u51fd\u6570\u603b\u662f\u521b\u5efa\u4e00\u4e2a\u65b0\u7684Python\u5217\u8868\uff08\u5373\u4e00\u4efd\u62f7\u8d1d\uff09 print ( a is b ) # True print ( a is not c ) # True print ( a == c ) # True d = None print ( d is None ) # True Python\u4e2d\u7684\u5927\u90e8\u5206\u5bf9\u8c61\uff0c\u4f8b\u5982\u5217\u8868\u3001\u5b57\u5178\u3001NumPy\u6570\u7ec4\u90fd\u662f\u53ef\u53d8\u5bf9\u8c61\uff0c\u5927\u591a\u6570\u7528\u6237\u5b9a\u4e49\u7684\u7c7b\u578b\uff08\u7c7b\uff09\u4e5f\u662f\u53ef\u53d8\u7684\u3002 \u53ef\u53d8\u5bf9\u8c61\u4e2d\u5305\u542b\u7684\u5bf9\u8c61\u548c\u503c\u662f\u53ef\u4ee5\u88ab\u4fee\u6539\u7684\u3002\u8fd8\u6709\u5176\u4ed6\u4e00\u4e9b\u5bf9\u8c61\u662f\u4e0d\u53ef\u53d8\u7684\uff0c\u6bd4\u5982\u5b57\u7b26\u4e32\u3001\u5143\u7ec4\u3002 a_list = [ 'foo' , 2 , [ 4 , 5 ]] # \u5217\u8868 a_list [ 2 ] = ( 3 , 4 ) print ( a_list ) # ['foo', 2, (3, 4)] a_tuple = ( 3 , 5 , ( 4 , 5 )) # \u5143\u7ec4 a_tuple [ 1 ] = 'four' # TypeError: 'tuple' object does not support item assignment \u4e0d\u53ef\u88ab\u4fee\u6539 print ( a_tuple ) # (3, 5, (4, 5))","title":"3. \u4e8c\u5143\u8fd0\u7b97\u7b26\u548c\u6bd4\u8f83\u8fd0\u7b97"},{"location":"python/Foundation/ch01/#4","text":"Python\u6807\u91cf\u7c7b\u578b\uff1aNone, str, bytes, float, bool, int\u3002 \u6570\u503c\u7c7b\u578b\u3002 \u57fa\u7840\u7684Python\u6570\u5b57\u7c7b\u578b\u5c31\u662fint\u548cfloat\u3002int\u53ef\u4ee5\u5b58\u50a8\u4efb\u610f\u5927\u5c0f\u6570\u5b57\u3002\u6d6e\u70b9\u6570\u5728Python\u4e2d\u7528float\u8868\u793a\uff0c\u6bcf\u4e00\u4e2a\u6d6e\u70b9\u6570\u90fd\u662f\u53cc\u7cbe\u5ea664\u4f4d\u6570\u503c\u3002 ival = 17338971 print ( ival ** 6 ) # 27173145946003847721495630081806010734757321 fval = 17338971.0 print ( fval ** 6 ) # 2.7173145946003847e+43 print ( 3 / 2 ) # 1.5 print ( 3 // 2 ) # 1 \u5b57\u7b26\u4e32\u3002 Python\u7684\u5b57\u7b26\u4e32\u662f\u4e0d\u53ef\u53d8\u7684\u3002 a = 5.6 s = str ( a ) print ( s ) # 5.6 b = 'python' print ( list ( b )) # ['p', 'y', 't', 'h', 'o', 'n'] print ( b [ 2 ]) # t b [ 2 ] = 'f' # TypeError: 'str' object does not support item assignment \u5b57\u7b26\u4e32\u662f\u4e0d\u53ef\u53d8\u7684 \u53cd\u659c\u6760\u7b26\u53f7\\\u662f\u4e00\u79cd\u8f6c\u4e49\u7b26\u53f7\uff0c\u5b83\u7528\u6765\u6307\u660e\u7279\u6b8a\u7b26\u53f7\u3002 \u5982\u679c\u4f60\u6709\u4e00\u4e2a\u4e0d\u542b\u7279\u6b8a\u7b26\u53f7\u4f46\u542b\u6709\u5927\u91cf\u53cd\u659c\u6760\u7684\u5b57\u7b26\u4e32\u65f6\uff0c\u53ef\u4ee5\u5728\u5b57\u7b26\u4e32\u524d\u9762\u52a0\u4e00\u4e2a\u524d\u7f00\u7b26\u53f7r\uff0c\u8868\u660e\u8fd9\u4e9b\u5b57\u7b26\u662f\u539f\u751f\u5b57\u7b26\uff0cr\u662fraw\u7684\u7b80\u5199\uff0c\u8868\u793a\u539f\u751f\u7684\u3002 x = '12 \\\\ 34' y = r 'this\\has\\no\\special\\characters' print ( x ) # 12\\34 print ( y ) # this\\has\\no\\special\\characters \u5b57\u7b26\u4e32\u683c\u5f0f\u5316 {0:.2f}\u8868\u793a\u5c06\u7b2c\u4e00\u4e2a\u53c2\u6570\u683c\u5f0f\u5316\u4e3a2\u4f4d\u5c0f\u6570\u7684\u6d6e\u70b9\u6570 {1:s}\u8868\u793a\u5c06\u7b2c\u4e8c\u4e2a\u53c2\u6570\u683c\u5f0f\u5316\u4e3a\u5b57\u7b26\u4e32 {2:d}\u8868\u793a\u5c06\u7b2c\u4e09\u4e2a\u53c2\u6570\u683c\u5f0f\u5316\u6574\u6570 \u53c2\u8003Python\u5b98\u65b9\u6587\u6863 https://docs.python.org/3.6/library/string.html template = ' {0:.2f} {1:s} are worth US$ {2:d} ' print ( template . format ( 4.5560 , 'Argentine Pesos' , 1 )) # 4.56 Argentine Pesos are worth US$1 \u65e5\u671f\u548c\u65f6\u95f4 from datetime import datetime , date , time dt = datetime ( 2011 , 10 , 29 , 20 , 30 , 21 ) print ( dt . day ) # 29 print ( dt . minute ) # 30 print ( dt . date ()) # 2011-10-29 print ( dt . time ()) # 20:30:21 print ( dt . replace ( minute = 0 , second = 0 )) # 2011-10-29 20:00:00 \u5c06\u5206\u949f\u3001\u79d2\u66ff\u6362\u4e3a0 print ( datetime . strptime ( '20091021' , '%Y%m %d ' )) # 2009-10-21 00:00:00 \u5b57\u7b26\u4e32\u53ef\u4ee5\u901a\u8fc7 strptime \u51fd\u6570\u8f6c\u6362\u4e3adatetime\u5bf9\u8c61 dt2 = datetime ( 2011 , 11 , 15 , 22 , 30 ) delta = dt2 - dt print ( delta ) # 17 days, 1:59:39 print ( dt + delta ) # 2011-11-15 22:30:00 range\u51fd\u6570\u8fd4\u56de\u4e00\u4e2a\u8fed\u4ee3\u5668\uff0c\u8be5\u8fed\u4ee3\u5668\u751f\u6210\u4e00\u4e2a\u7b49\u5dee\u6574\u6570\u5e8f\u5217\u3002 print ( range ( 10 )) # range(0, 10) print ( list ( range ( 10 ))) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print ( list ( range ( 0 , 20 , 2 ))) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]","title":"4. \u6807\u91cf\u7c7b\u578b"},{"location":"python/Foundation/ch01/#5","text":"value = true-expr if condition else false-expr x = 5 print ( 'non-negative' if x >= 0 else 'negative' ) # non-negative","title":"5. \u4e09\u5143\u8868\u8fbe\u5f0f"},{"location":"python/Foundation/ch02/","text":"Python\u6253\u5305\u548c\u89e3\u5305 \u00b6 \u89e3\u5305Unpacking \u00b6 Python \u5141\u8bb8\u53d8\u91cf\u7684\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\u51fa\u73b0\u5728\u8d4b\u503c\u64cd\u4f5c\u7684\u5de6\u4fa7\u3002 \u5143\u7ec4\u4e2d\u7684\u6bcf\u4e2a\u53d8\u91cf\u90fd\u53ef\u4ee5\u4ece\u8d4b\u503c\u53f3\u4fa7\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08iterable\uff09\u4e2d\u63a5\u6536\u4e00\u4e2a\u503c\uff08\u6216\u8005\u66f4\u591a\uff0c\u5982\u679c\u6211\u4eec\u4f7f\u7528 * \u8fd0\u7b97\u7b26\uff09\u3002 Python \u4e2d\u7684\u89e3\u5305\u662f\u6307\u4e00\u79cd\u64cd\u4f5c\uff0c\u8be5\u64cd\u4f5c\u5305\u62ec\u5728\u5355\u4e2a\u8d4b\u503c\u8bed\u53e5\u4e2d\u5c06\u53ef\u8fed\u4ee3\u7684\u503c\u5206\u914d\u7ed9\u53d8\u91cf\u7684\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\u3002 \u5728 Python \u4e2d\uff0c\u53ef\u4ee5\u5728\u8d4b\u503c\u8fd0\u7b97\u7b26 = \u7684\u5de6\u4fa7\u653e\u7f6e\u4e00\u4e2a\u53d8\u91cf\u5143\u7ec4\uff0c\u5728\u53f3\u4fa7\u653e\u7f6e\u4e00\u4e2a\u503c\u5143\u7ec4\u3002 \u53f3\u8fb9\u7684\u503c\u5c06\u6839\u636e\u5b83\u4eec\u5728\u5143\u7ec4\u4e2d\u7684\u4f4d\u7f6e\u81ea\u52a8\u5206\u914d\u7ed9\u5de6\u8fb9\u7684\u53d8\u91cf\u3002 \u8fd9\u5728 Python \u4e2d\u901a\u5e38\u79f0\u4e3a\u5143\u7ec4\u89e3\u5305\u3002 \u5982\u4e0b\u793a\u4f8b\uff1a >>> ( a , b , c ) = ( 1 , 2 , 3 ) >>> a 1 >>> b 2 >>> c 3 >>> birthday = ( 'April' , 5 , 2001 ) >>> month , day , year = birthday >>> month 'April' >>> day 5 >>> year 2001 \u5143\u7ec4\u89e3\u5305\u529f\u80fd\u5728 Python \u4e2d\u53ef\u4ee5\u6269\u5c55\u4e3a\u9002\u7528\u4e8e\u4efb\u4f55\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 \u552f\u4e00\u7684\u8981\u6c42\u662f\u53ef\u8fed\u4ee3\u7684\u63a5\u6536\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\u4e2d\u7684\u6bcf\u4e2a\u53d8\u91cf\u6070\u597d\u5bf9\u5e94\u53ef\u8fed\u4ee3\u5bf9\u8c61\u7684\u4e00\u4e2a\u5143\u7d20\uff08item\uff09\u3002 \u4e0b\u9762\u7684\u793a\u4f8b\u4ecb\u7ecd\u4e86 Python \u4e2d\u53ef\u8fed\u4ee3\u89e3\u5305\u7684\u5de5\u4f5c\u539f\u7406\uff1a >>> # Unpackage strings >>> a , b , c = '123' >>> a '1' >>> b '2' >>> c '3' >>> # Unpacking lists >>> a , b , c = [ 1 , 2 , 3 ] >>> a 1 >>> b 2 >>> c 3 >>> # Unpacking generators >>> gen = ( i ** 2 for i in range ( 3 )) >>> a , b , c = gen >>> a 0 >>> b 1 >>> c 4 >>> # Upacking dictionaries (keys, values, and items) >>> my_dict = { 'one' : 1 , 'two' : 2 , 'three' : 3 } >>> a , b , c = my_dict >>> a 'one' >>> b 'two' >>> c 'three' >>> a , b , c = my_dict . values () >>> a 1 >>> b 2 >>> c 3 >>> a , b , c = my_dict . items () >>> a ( 'one' , 1 ) >>> b ( 'two' , 2 ) >>> c ( 'three' , 3 ) >>> # Use a tuple on the right side of assignment statement >>> [ a , b , c ] = 1 , 2 , 3 >>> a 1 >>> b 2 >>> c 3 >>> # Use range() iterator >>> x , y , z = range ( 3 ) >>> x 0 >>> y 1 >>> z 2 \u6253\u5305Packing \u00b6 \u6253\u5305\u53ef\u4ee5\u7406\u89e3\u4e3a\u4f7f\u7528\u53ef\u8fed\u4ee3\u89e3\u5305\u8fd0\u7b97\u7b26\u5728\u5355\u4e2a\u53d8\u91cf\u4e2d\u6536\u96c6\u591a\u4e2a\u503c\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c * \u8fd0\u7b97\u7b26\u88ab\u79f0\u4e3a\u5143\u7ec4\uff08\u6216\u53ef\u8fed\u4ee3\uff09\u89e3\u5305\u8fd0\u7b97\u7b26\u3002 \u5b83\u6269\u5c55\u4e86\u89e3\u5305\u529f\u80fd\uff0c\u5141\u8bb8\u5728\u5355\u4e2a\u53d8\u91cf\u4e2d\u6536\u96c6\u6216\u6253\u5305\u591a\u4e2a\u503c\u3002 \u5728\u4ee5\u4e0b\u793a\u4f8b\u4e2d\u53ef\u4ee5\u770b\u5230 * \u8fd0\u7b97\u7b26\u5c06\u5143\u7ec4\u503c\u6253\u5305\u5230\u5355\u4e2a\u53d8\u91cf\u4e2d\uff1a >>> # The right side is a tuple, the left side is a list >>> * a , = 1 , 2 >>> a [ 1 , 2 ] >>> type ( a ) < class ' list '> \u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\uff0c\u8d4b\u503c\u7684\u5de6\u4fa7\u5fc5\u987b\u662f\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\uff0c\u8fd9\u5c31\u662f\u4f7f\u7528\u5c3e\u968f\u9017\u53f7\u7684\u539f\u56e0\u3002\u8fd9\u4e2a\u5143\u7ec4\u53ef\u4ee5\u5305\u542b\u6240\u9700\u8981\u7684\u5c3d\u53ef\u80fd\u591a\u7684\u53d8\u91cf\uff0c\u4f46\u662f\uff0c\u5b83\u53ea\u80fd\u5305\u542b\u4e00\u4e2a\u661f\u53f7\u8868\u8fbe\u5f0f(starred expression)\u3002 >>> # Packing trailing values >>> a , * b = 1 , 2 , 3 >>> a 1 >>> b [ 2 , 3 ] >>> type ( a ) < class ' int '> >>> type ( b ) < class ' list '> >>> >>> * a , b , c = 1 , 2 , 3 >>> a [ 1 ] >>> b 2 >>> c 3 >>> * a , b , c , d , e = 1 , 2 , 3 Traceback ( most recent call last ): File \"\" , line 1 , in < module > ValueError : not enough values to unpack ( expected at least 4 , got 3 ) >>> * a , b , c , d = 1 , 2 , 3 >>> a [] >>> b 1 >>> c 2 >>> d 3 >>> >>> seq = [ 1 , 2 , 3 , 4 ] >>> first , * body , last = seq >>> first , body , last ( 1 , [ 2 , 3 ], 4 ) >>> first , body , * last = seq >>> first , body , last ( 1 , 2 , [ 3 , 4 ]) >>> >>> ran = range ( 10 ) >>> * r , = ran >>> r [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] \u4e0b\u9762\u662f\u4e00\u4e9b\u6253\u5305\u548c\u89e3\u5305\u7684\u4f8b\u5b50\u3002 >>> employee = [ 'John Doe' , '40' , 'Software Engineer' ] >>> name = employee [ 0 ] >>> age = employee [ 1 ] >>> job = employee [ 2 ] >>> name 'John Doe' >>> age '40' >>> job 'Software Engineer' >>> >>> name , age , job = [ 'John Doe' , '40' , 'Software Engineer' ] >>> name 'John Doe' >>> age '40' >>> job 'Software Engineer' >>> >>> a = 100 >>> b = 200 >>> a , b = b , a >>> a 200 >>> b 100 \u4f7f\u7528 * \u5220\u9664\u4e0d\u9700\u8981\u7684\u503c\u3002 >>> a , b , * _ = 1 , 2 , 0 , 0 , 0 , 0 >>> a 1 >>> b 2 >>> _ [ 0 , 0 , 0 , 0 ] \u5728\u4e0a\u4f8b\u4e2d\uff0c\u4e0d\u9700\u8981\u7684\u4fe1\u606f\u5b58\u50a8\u5728\u865a\u62df\u53d8\u91cf _ \u4e2d\uff0c\u5728\u540e\u7eed\u7684\u4f7f\u7528\u4e2d\u53ef\u4ee5\u5ffd\u7565\u5b83\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cPython \u89e3\u91ca\u5668\u4f7f\u7528\u4e0b\u5212\u7ebf\u5b57\u7b26 _ \u6765\u5b58\u50a8\u5728\u4ea4\u4e92\u5f0f\u4f1a\u8bdd\u4e2d\u8fd0\u884c\u7684\u8bed\u53e5\u7684\u7ed3\u679c\u503c\u3002 \u56e0\u6b64\uff0c\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528\u8fd9\u4e2a\u5b57\u7b26\u6765\u8bc6\u522b\u865a\u62df\u53d8\u91cf\u53ef\u80fd\u662f\u6a21\u68f1\u4e24\u53ef\u7684\u3002 \u5728\u51fd\u6570\u4e2d\u8fd4\u56de\u5143\u7ec4\u3002 >>> def powers ( num ): ... return num , num ** 2 , num ** 3 ... >>> # Packaging returned values in a tuple >>> result = powers ( 3 ) >>> result ( 3 , 9 , 27 ) >>> # Unpacking returned values to multiple variables >>> number , square , cube = powers ( 3 ) >>> number 3 >>> square 9 >>> cube 27 >>> * _ , cube = powers ( 3 ) >>> cube 27 \u4f7f\u7528 * \u548c ** \u8fd0\u7b97\u7b26 \u00b6 \u4f7f\u7528 * \u8fd0\u7b97\u7b26\u5408\u5e76\u8fed\u4ee3\u53d8\u91cf\uff08iterables\uff09\u3002\u4e0a\u9762\u4e24\u4e2a\u4f8b\u5b50\u8bf4\u660e\uff0c\u8fd9\u4e2d\u65b9\u6cd5\u4e5f\u662f\u8fde\u63a5\u8fed\u4ee3\u53d8\u91cf\uff08iterables\uff09\u7684\u4e00\u79cd\u66f4\u6613\u8bfb\u548c\u66f4\u6709\u6548\u7684\u65b9\u6cd5\u3002 \u8fd9\u4e2a\u65b9\u6cd5 (my_set) + my_list + list(my_tuple) + list(range(1, 4)) + list(my_str) \u53ef\u4ee5\u751f\u6210\u4e00\u4e2a\u5217\u8868 \uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u66f4\u7b80\u6d01\u7684\u65b9\u6cd5 [*my_set, *my_list, *my_tuple, *range(1, 4), *my_str] \u3002 >>> my_tuple = ( 1 , 2 , 3 ) >>> ( 0 , * my_tuple , 4 ) ( 0 , 1 , 2 , 3 , 4 ) >>> my_list = [ 1 , 2 , 3 ] >>> [ 0 , * my_list , 4 ] [ 0 , 1 , 2 , 3 , 4 ] >>> my_set = { 1 , 2 , 3 } >>> { 0 , * my_set , 4 } { 0 , 1 , 2 , 3 , 4 } >>> [ * my_set , * my_list , * my_tuple , * range ( 1 , 4 )] [ 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 ] >>> my_str = \"123\" >>> [ * my_set , * my_list , * my_tuple , * range ( 1 , 4 ), * my_str ] [ 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 , '1' , '2' , '3' ] \u4f7f\u7528 ** \u8fd0\u7b97\u7b26\u89e3\u5305\u5b57\u5178\u3002 >>> numbers = { 'one' : 1 , 'two' : 2 , 'three' : 3 } >>> letters = { 'a' : 'A' , 'b' : 'B' , 'c' : 'C' } >>> combination = { ** numbers , ** letters } >>> combination { 'one' : 1 , 'two' : 2 , 'three' : 3 , 'a' : 'A' , 'b' : 'B' , 'c' : 'C' } \u9700\u8981\u6ce8\u610f\u7684\u91cd\u8981\u4e00\u70b9\u662f\uff0c\u5982\u679c\u6211\u4eec\u5408\u5e76\u7684\u5b57\u5178\u5177\u6709\u91cd\u590d\u952e\u6216\u516c\u5171\u952e\uff0c\u5219\u6700\u53f3\u4fa7\u5b57\u5178\u7684\u503c\u5c06\u8986\u76d6\u6700\u5de6\u4fa7\u5b57\u5178\u7684\u503c\u3002\u4f8b\u5982: >>> letters = { 'a' : 'A' , 'b' : 'B' , 'c' : 'C' } >>> vowels = { 'a' : 'a' , 'e' : 'e' , 'i' : 'i' , 'o' : 'o' , 'u' : 'u' } >>> { ** letters , ** vowels } { 'a' : 'a' , 'b' : 'B' , 'c' : 'C' , 'e' : 'e' , 'i' : 'i' , 'o' : 'o' , 'u' : 'u' } >>> { ** vowels , ** letters } { 'a' : 'A' , 'e' : 'e' , 'i' : 'i' , 'o' : 'o' , 'u' : 'u' , 'b' : 'B' , 'c' : 'C' } \u901a\u8fc7 For-Loops \u89e3\u5305 \u00b6 \u6211\u4eec\u8fd8\u53ef\u4ee5\u5728 for \u5faa\u73af\u7684\u4e0a\u4e0b\u6587\u4e2d\u4f7f\u7528\u53ef\u8fed\u4ee3\u89e3\u5305\u3002 \u5f53\u6211\u4eec\u8fd0\u884c for \u5faa\u73af\u65f6\uff0c\u5728\u6bcf\u6b21\u5faa\u73af\u8fed\u4ee3\u4e2d\u5c06\u5176\u53ef\u8fed\u4ee3\u5bf9\u8c61\u4e2d\u7684\u4e00\u9879(item)\u5206\u914d\u7ed9\u76ee\u6807\u53d8\u91cf\u3002 \u5982\u679c\u8981\u5206\u914d\u7684\u9879(item)\u662f\u53ef\u8fed\u4ee3\u7684\uff0c\u90a3\u4e48\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u5143\u7ec4\u4f5c\u4e3a\u76ee\u6807\u53d8\u91cf\uff0c\u901a\u8fc7\u5faa\u73af\u5c06\u53ef\u8fed\u4ee3\u5bf9\u8c61\u89e3\u5305\u5230\u76ee\u6807\u53d8\u91cf\u7684\u5143\u7ec4\u4e2d\u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u6784\u5efa\u4e00\u4e2a\u5305\u542b\u4e24\u4e2a\u5143\u7d20\u7684\u5143\u7ec4\u7684\u5217\u8868\u3002 \u6bcf\u4e2a\u5143\u7ec4\u5c06\u5305\u542b\u4ea7\u54c1\u540d\u79f0\u3001\u4ef7\u683c\u548c\u9500\u552e\u5355\u4f4d\uff0c\u6211\u4eec\u901a\u8fc7 for \u5faa\u73af\u904d\u5386\u6bcf\u4e2a\u5143\u7ec4\u5143\u7d20\u6765\u8ba1\u7b97\u6bcf\u4e2a\u4ea7\u54c1\u7684\u6536\u5165\u3002 >>> sales = [( 'Pencle' , 0.22 , 1500 ), ( 'Notebook' , 1.30 , 550 ), ( 'Eraser' , 0.75 , 1000 )] >>> for items in sales : ... print ( f \"Income for { items [ 0 ] } is: { items [ 1 ] * items [ 2 ] } \" ) ... Income for Pencle is : 330.0 Income for Notebook is : 715.0 Income for Eraser is : 750.0 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u7d22\u5f15\u6765\u8bbf\u95ee\u6bcf\u4e2a\u5143\u7ec4\u7684\u5404\u4e2a\u5143\u7d20\u3002\u4e0b\u9762\u7684\u793a\u4f8b\u4ee3\u7801\u4e2d\uff0c\u5728 for \u5faa\u73af\u4f7f\u7528\u89e3\u5305\uff0c\u8fd9\u4e5f\u662f Python \u4e2d\u89e3\u5305\u7684\u4e00\u79cd\u5b9e\u73b0\u3002 >>> sales = [( 'Pencle' , 0.22 , 1500 ), ( 'Notebook' , 1.30 , 550 ), ( 'Eraser' , 0.75 , 1000 )] >>> for product , price , sold_units in sales : ... print ( f \"Income for { product } is: { price * sold_units } \" ) ... Income for Pencle is : 330.0 Income for Notebook is : 715.0 Income for Eraser is : 750.0 \u4e5f\u53ef\u4ee5\u5728 for \u5faa\u73af\u4e2d\u4f7f\u7528 * \u8fd0\u7b97\u7b26\u5c06\u591a\u4e2a\u9879\u6253\u5305\u5230\u5355\u4e2a\u76ee\u6807\u53d8\u91cf\u4e2d\u3002 \u5728\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u9996\u5148\u53d6\u5f97\u6bcf\u4e2a\u5e8f\u5217\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u3002 \u5176\u4f59\u503c\u901a\u8fc7 * \u8fd0\u7b97\u7b26\u8d4b\u7ed9\u76ee\u6807\u53d8\u91cf rest \u3002 >>> for first , * rest in [( 1 , 2 , 3 ),( 4 , 5 , 6 )]: ... print ( 'First: ' , first ) ... print ( 'Rest: ' , rest ) ... First : 1 Rest : [ 2 , 3 ] First : 4 Rest : [ 5 , 6 ] >>> \u76ee\u6807\u53d8\u91cf\u7684\u7ed3\u6784\u5fc5\u987b\u4e0e\u53ef\u8fed\u4ee3\u5bf9\u8c61\u7684\u7ed3\u6784\u4e00\u81f4\uff0c\u5426\u5219\u4f1a\u62a5\u9519\u3002\u770b\u4e0b\u9762\u7684\u4f8b\u5b50\u3002 >>> data = [(( 1 , 2 ), 3 ), (( 2 , 3 ), 3 )] >>> for ( a , b ), c in data : ... print ( a , b , c ) ... 1 2 3 2 3 3 >>> for a , b , c in data : ... print ( a , b , c ) ... Traceback ( most recent call last ): File \"\" , line 1 , in < module > ValueError : not enough values to unpack ( expected 3 , got 2 ) \u7528 * \u548c ** \u5b9a\u4e49\u51fd\u6570 \u00b6 \u4e0b\u9762\u4f8b\u5b50\u4e2d\u7684\u51fd\u6570func\u81f3\u5c11\u9700\u8981\u4e00\u4e2a\u540d\u4e3a required \u7684\u53c2\u6570\u3002 \u5b83\u4e5f\u53ef\u4ee5\u63a5\u53d7\u4e00\u4e2a\u6216\u591a\u4e2a\u4f4d\u7f6e\u53c2\u6570\u6216\u5173\u952e\u5b57\u53c2\u6570\u3002 \u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c * \u8fd0\u7b97\u7b26\u5728\u4e00\u4e2a\u53eb args \u7684\u5143\u7ec4\u4e2d\u6536\u96c6\u6216\u6253\u5305\u989d\u5916\u7684\u4f4d\u7f6e\u53c2\u6570\uff0c\u800c ** \u8fd0\u7b97\u7b26\u5728\u4e00\u4e2a\u53eb kwargs \u7684\u5b57\u5178\u4e2d\u6536\u96c6\u6216\u6253\u5305\u989d\u5916\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 args \u548c kwargs \u90fd\u662f\u53ef\u9009\u7684\uff0c\u5e76\u4e14\u5206\u522b\u81ea\u52a8\u9ed8\u8ba4\u4e3a\u5143\u7ec4 () \u548c\u5b57\u5178 {} \u3002 \u8fd9\u91cc args \u548c kwargs \u7684\u547d\u540d\u5e76\u4e0d\u662f\u5fc5\u987b\u7684\uff0c\u8bed\u6cd5\u4e0a\u53ea\u9700\u8981 * \u6216 ** \u540e\u8ddf\u6709\u6548\u6807\u8bc6\u7b26\u5373\u53ef\uff0c\u5efa\u8bae\u7ed9\u53d8\u91cf\u8d77\u4e2a\u6709\u610f\u4e49\u7684\u540d\u5b57\uff0c\u63d0\u9ad8\u4ee3\u7801\u7684\u53ef\u8bfb\u6027\u3002 >>> def func ( required , * args , ** kwargs ): ... print ( required ) ... print ( args ) ... print ( kwargs ) ... >>> func ( 'Welcome to ...' , 1 , 2 , 3 , site = 'CloudAcademy.com' ) Welcome to ... ( 1 , 2 , 3 ) { 'site' : 'CloudAcademy.com' } >>> func ( 'Welcome to ...' , 1 , 2 , 3 , 4 ) Welcome to ... ( 1 , 2 , 3 , 4 ) {} >>> func ( 'Welcome to ...' , 1 , 2 , 3 , ( 1 , 2 )) Welcome to ... ( 1 , 2 , 3 , ( 1 , 2 )) {} >>> func ( 'Welcome to ...' , 1 , 2 , 3 , [ 1 , 2 ]) Welcome to ... ( 1 , 2 , 3 , [ 1 , 2 ]) {} >>> func ( 'Welcome to ...' , 1 , 2 , 3 , ([ 2 , 3 ], [ 1 , 2 ])) Welcome to ... ( 1 , 2 , 3 , ([ 2 , 3 ], [ 1 , 2 ])) {} \u4f7f\u7528 * \u548c ** \u8c03\u7528\u51fd\u6570 \u00b6 \u8c03\u7528\u51fd\u6570\u65f6\uff0c\u6211\u4eec\u8fd8\u53ef\u4ee5\u53d7\u76ca\u4e8e\u4f7f\u7528 * \u548c ** \u8fd0\u7b97\u7b26\u5c06\u53c2\u6570\u96c6\u5408\u5206\u522b\u89e3\u538b\u7f29\u4e3a\u5355\u72ec\u7684\u4f4d\u7f6e\u53c2\u6570\u6216\u5173\u952e\u5b57\u53c2\u6570\u3002 \u8fd9\u4e0e\u5728\u51fd\u6570\u7b7e\u540d(signature of a function)\u4e2d\u4f7f\u7528 * \u548c ** \u662f\u76f8\u53cd\u7684\u3002 \u5728\u51fd\u6570\u7b7e\u540d\u4e2d\uff0c\u8fd0\u7b97\u7b26\u7684\u610f\u601d\u662f\u5728\u4e00\u4e2a\u6807\u8bc6\u7b26\u4e2d\u6536\u96c6\u6216\u6253\u5305\u53ef\u53d8\u6570\u91cf\u7684\u53c2\u6570\u3002 \u5728\u8c03\u7528(calling)\u4e2d\uff0c\u5b83\u4eec\u7684\u610f\u601d\u662f\u89e3\u5305(unpack)\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u5230\u591a\u4e2a\u53c2\u6570\u4e2d\u3002 \u7eed\u4e0a\u4f8b\uff0c * \u8fd0\u7b97\u7b26\u5c06\u50cf [\"Welcome\", \"to\"] \u8fd9\u6837\u7684\u5e8f\u5217\u89e3\u5305\u5230\u4f4d\u7f6e\u53c2\u6570\u4e2d\u3002 \u7c7b\u4f3c\u5730\uff0c ** \u8fd0\u7b97\u7b26\u5c06\u5b57\u5178\u89e3\u5305\u4e3a\u4e0e\u5b57\u5178\u7684\u952e\u503c\u5339\u914d\u7684\u53c2\u6570\u540d\u3002 >>> def func ( welcome , to , site ): ... print ( welcome , to , site ) ... >>> func ( * [ 'Welcome' , 'to' ], ** { 'site' : 'CloudAcademy.com' }) Welcome to CloudAcademy . com \u7efc\u5408\u8fd0\u7528\u524d\u9762\u7684\u65b9\u6cd5\u6765\u7f16\u5199\u975e\u5e38\u7075\u6d3b\u7684\u51fd\u6570\uff0c\u6bd4\u5982\uff0c\u5728\u5b9a\u4e49\u548c\u8c03\u7528 Python \u51fd\u6570\u65f6\uff0c\u66f4\u7075\u6d3b\u7684\u4f7f\u7528 * \u548c ** \u8fd0\u7b97\u7b26\u3002 \u4f8b\u5982\uff1a >>> def func ( required , * args , ** kwargs ): ... print ( required ) ... print ( args ) ... print ( kwargs ) ... >>> func ( 'Welcome to...' , * ( 1 , 2 , 3 ), ** { 'Site' : 'CloudAcademy.com' }) Welcome to ... ( 1 , 2 , 3 ) { 'Site' : 'CloudAcademy.com' } \u603b\u7ed3 \u00b6 \u53ef\u8fed\u4ee3\u89e3\u5305\uff08iterable unpacking\uff09\u8fd9\u4e2a\u7279\u6027\u5141\u8bb8\u6211\u4eec\u5c06\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u89e3\u5305\u6210\u51e0\u4e2a\u53d8\u91cf\u3002 \u53e6\u4e00\u65b9\u9762\uff0c\u6253\u5305\u5305\u62ec\u4f7f\u7528\u89e3\u5305\u8fd0\u7b97\u7b26 * \u5c06\u591a\u4e2a\u503c\u8d4b\u5230\u4e00\u4e2a\u53d8\u91cf\u4e2d\u3002 \u53ef\u8fed\u4ee3\u89e3\u5305\uff08iterable unpacking\uff09\u4e5f\u53ef\u4ee5\u7528\u6765\u8fdb\u884c\u5e76\u884c\u8d4b\u503c\u548c\u53d8\u91cf\u4e4b\u95f4\u7684\u503c\u4ea4\u6362\uff0c\u4e5f\u53ef\u4ee5\u7528\u5728 for \u5faa\u73af\u3001\u51fd\u6570\u8c03\u7528\u548c\u51fd\u6570\u5b9a\u4e49\u4e2d\u3002","title":"Python\u6253\u5305\u548c\u89e3\u5305"},{"location":"python/Foundation/ch02/#python","text":"","title":"Python\u6253\u5305\u548c\u89e3\u5305"},{"location":"python/Foundation/ch02/#unpacking","text":"Python \u5141\u8bb8\u53d8\u91cf\u7684\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\u51fa\u73b0\u5728\u8d4b\u503c\u64cd\u4f5c\u7684\u5de6\u4fa7\u3002 \u5143\u7ec4\u4e2d\u7684\u6bcf\u4e2a\u53d8\u91cf\u90fd\u53ef\u4ee5\u4ece\u8d4b\u503c\u53f3\u4fa7\u7684\u53ef\u8fed\u4ee3\u5bf9\u8c61\uff08iterable\uff09\u4e2d\u63a5\u6536\u4e00\u4e2a\u503c\uff08\u6216\u8005\u66f4\u591a\uff0c\u5982\u679c\u6211\u4eec\u4f7f\u7528 * \u8fd0\u7b97\u7b26\uff09\u3002 Python \u4e2d\u7684\u89e3\u5305\u662f\u6307\u4e00\u79cd\u64cd\u4f5c\uff0c\u8be5\u64cd\u4f5c\u5305\u62ec\u5728\u5355\u4e2a\u8d4b\u503c\u8bed\u53e5\u4e2d\u5c06\u53ef\u8fed\u4ee3\u7684\u503c\u5206\u914d\u7ed9\u53d8\u91cf\u7684\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\u3002 \u5728 Python \u4e2d\uff0c\u53ef\u4ee5\u5728\u8d4b\u503c\u8fd0\u7b97\u7b26 = \u7684\u5de6\u4fa7\u653e\u7f6e\u4e00\u4e2a\u53d8\u91cf\u5143\u7ec4\uff0c\u5728\u53f3\u4fa7\u653e\u7f6e\u4e00\u4e2a\u503c\u5143\u7ec4\u3002 \u53f3\u8fb9\u7684\u503c\u5c06\u6839\u636e\u5b83\u4eec\u5728\u5143\u7ec4\u4e2d\u7684\u4f4d\u7f6e\u81ea\u52a8\u5206\u914d\u7ed9\u5de6\u8fb9\u7684\u53d8\u91cf\u3002 \u8fd9\u5728 Python \u4e2d\u901a\u5e38\u79f0\u4e3a\u5143\u7ec4\u89e3\u5305\u3002 \u5982\u4e0b\u793a\u4f8b\uff1a >>> ( a , b , c ) = ( 1 , 2 , 3 ) >>> a 1 >>> b 2 >>> c 3 >>> birthday = ( 'April' , 5 , 2001 ) >>> month , day , year = birthday >>> month 'April' >>> day 5 >>> year 2001 \u5143\u7ec4\u89e3\u5305\u529f\u80fd\u5728 Python \u4e2d\u53ef\u4ee5\u6269\u5c55\u4e3a\u9002\u7528\u4e8e\u4efb\u4f55\u53ef\u8fed\u4ee3\u5bf9\u8c61\u3002 \u552f\u4e00\u7684\u8981\u6c42\u662f\u53ef\u8fed\u4ee3\u7684\u63a5\u6536\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\u4e2d\u7684\u6bcf\u4e2a\u53d8\u91cf\u6070\u597d\u5bf9\u5e94\u53ef\u8fed\u4ee3\u5bf9\u8c61\u7684\u4e00\u4e2a\u5143\u7d20\uff08item\uff09\u3002 \u4e0b\u9762\u7684\u793a\u4f8b\u4ecb\u7ecd\u4e86 Python \u4e2d\u53ef\u8fed\u4ee3\u89e3\u5305\u7684\u5de5\u4f5c\u539f\u7406\uff1a >>> # Unpackage strings >>> a , b , c = '123' >>> a '1' >>> b '2' >>> c '3' >>> # Unpacking lists >>> a , b , c = [ 1 , 2 , 3 ] >>> a 1 >>> b 2 >>> c 3 >>> # Unpacking generators >>> gen = ( i ** 2 for i in range ( 3 )) >>> a , b , c = gen >>> a 0 >>> b 1 >>> c 4 >>> # Upacking dictionaries (keys, values, and items) >>> my_dict = { 'one' : 1 , 'two' : 2 , 'three' : 3 } >>> a , b , c = my_dict >>> a 'one' >>> b 'two' >>> c 'three' >>> a , b , c = my_dict . values () >>> a 1 >>> b 2 >>> c 3 >>> a , b , c = my_dict . items () >>> a ( 'one' , 1 ) >>> b ( 'two' , 2 ) >>> c ( 'three' , 3 ) >>> # Use a tuple on the right side of assignment statement >>> [ a , b , c ] = 1 , 2 , 3 >>> a 1 >>> b 2 >>> c 3 >>> # Use range() iterator >>> x , y , z = range ( 3 ) >>> x 0 >>> y 1 >>> z 2","title":"\u89e3\u5305Unpacking"},{"location":"python/Foundation/ch02/#packing","text":"\u6253\u5305\u53ef\u4ee5\u7406\u89e3\u4e3a\u4f7f\u7528\u53ef\u8fed\u4ee3\u89e3\u5305\u8fd0\u7b97\u7b26\u5728\u5355\u4e2a\u53d8\u91cf\u4e2d\u6536\u96c6\u591a\u4e2a\u503c\u3002\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c * \u8fd0\u7b97\u7b26\u88ab\u79f0\u4e3a\u5143\u7ec4\uff08\u6216\u53ef\u8fed\u4ee3\uff09\u89e3\u5305\u8fd0\u7b97\u7b26\u3002 \u5b83\u6269\u5c55\u4e86\u89e3\u5305\u529f\u80fd\uff0c\u5141\u8bb8\u5728\u5355\u4e2a\u53d8\u91cf\u4e2d\u6536\u96c6\u6216\u6253\u5305\u591a\u4e2a\u503c\u3002 \u5728\u4ee5\u4e0b\u793a\u4f8b\u4e2d\u53ef\u4ee5\u770b\u5230 * \u8fd0\u7b97\u7b26\u5c06\u5143\u7ec4\u503c\u6253\u5305\u5230\u5355\u4e2a\u53d8\u91cf\u4e2d\uff1a >>> # The right side is a tuple, the left side is a list >>> * a , = 1 , 2 >>> a [ 1 , 2 ] >>> type ( a ) < class ' list '> \u5728\u4e0a\u9762\u7684\u4ee3\u7801\u4e2d\uff0c\u8d4b\u503c\u7684\u5de6\u4fa7\u5fc5\u987b\u662f\u5143\u7ec4\uff08\u6216\u5217\u8868\uff09\uff0c\u8fd9\u5c31\u662f\u4f7f\u7528\u5c3e\u968f\u9017\u53f7\u7684\u539f\u56e0\u3002\u8fd9\u4e2a\u5143\u7ec4\u53ef\u4ee5\u5305\u542b\u6240\u9700\u8981\u7684\u5c3d\u53ef\u80fd\u591a\u7684\u53d8\u91cf\uff0c\u4f46\u662f\uff0c\u5b83\u53ea\u80fd\u5305\u542b\u4e00\u4e2a\u661f\u53f7\u8868\u8fbe\u5f0f(starred expression)\u3002 >>> # Packing trailing values >>> a , * b = 1 , 2 , 3 >>> a 1 >>> b [ 2 , 3 ] >>> type ( a ) < class ' int '> >>> type ( b ) < class ' list '> >>> >>> * a , b , c = 1 , 2 , 3 >>> a [ 1 ] >>> b 2 >>> c 3 >>> * a , b , c , d , e = 1 , 2 , 3 Traceback ( most recent call last ): File \"\" , line 1 , in < module > ValueError : not enough values to unpack ( expected at least 4 , got 3 ) >>> * a , b , c , d = 1 , 2 , 3 >>> a [] >>> b 1 >>> c 2 >>> d 3 >>> >>> seq = [ 1 , 2 , 3 , 4 ] >>> first , * body , last = seq >>> first , body , last ( 1 , [ 2 , 3 ], 4 ) >>> first , body , * last = seq >>> first , body , last ( 1 , 2 , [ 3 , 4 ]) >>> >>> ran = range ( 10 ) >>> * r , = ran >>> r [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] \u4e0b\u9762\u662f\u4e00\u4e9b\u6253\u5305\u548c\u89e3\u5305\u7684\u4f8b\u5b50\u3002 >>> employee = [ 'John Doe' , '40' , 'Software Engineer' ] >>> name = employee [ 0 ] >>> age = employee [ 1 ] >>> job = employee [ 2 ] >>> name 'John Doe' >>> age '40' >>> job 'Software Engineer' >>> >>> name , age , job = [ 'John Doe' , '40' , 'Software Engineer' ] >>> name 'John Doe' >>> age '40' >>> job 'Software Engineer' >>> >>> a = 100 >>> b = 200 >>> a , b = b , a >>> a 200 >>> b 100 \u4f7f\u7528 * \u5220\u9664\u4e0d\u9700\u8981\u7684\u503c\u3002 >>> a , b , * _ = 1 , 2 , 0 , 0 , 0 , 0 >>> a 1 >>> b 2 >>> _ [ 0 , 0 , 0 , 0 ] \u5728\u4e0a\u4f8b\u4e2d\uff0c\u4e0d\u9700\u8981\u7684\u4fe1\u606f\u5b58\u50a8\u5728\u865a\u62df\u53d8\u91cf _ \u4e2d\uff0c\u5728\u540e\u7eed\u7684\u4f7f\u7528\u4e2d\u53ef\u4ee5\u5ffd\u7565\u5b83\u3002 \u9ed8\u8ba4\u60c5\u51b5\u4e0b\uff0cPython \u89e3\u91ca\u5668\u4f7f\u7528\u4e0b\u5212\u7ebf\u5b57\u7b26 _ \u6765\u5b58\u50a8\u5728\u4ea4\u4e92\u5f0f\u4f1a\u8bdd\u4e2d\u8fd0\u884c\u7684\u8bed\u53e5\u7684\u7ed3\u679c\u503c\u3002 \u56e0\u6b64\uff0c\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u4f7f\u7528\u8fd9\u4e2a\u5b57\u7b26\u6765\u8bc6\u522b\u865a\u62df\u53d8\u91cf\u53ef\u80fd\u662f\u6a21\u68f1\u4e24\u53ef\u7684\u3002 \u5728\u51fd\u6570\u4e2d\u8fd4\u56de\u5143\u7ec4\u3002 >>> def powers ( num ): ... return num , num ** 2 , num ** 3 ... >>> # Packaging returned values in a tuple >>> result = powers ( 3 ) >>> result ( 3 , 9 , 27 ) >>> # Unpacking returned values to multiple variables >>> number , square , cube = powers ( 3 ) >>> number 3 >>> square 9 >>> cube 27 >>> * _ , cube = powers ( 3 ) >>> cube 27","title":"\u6253\u5305Packing"},{"location":"python/Foundation/ch02/#_1","text":"\u4f7f\u7528 * \u8fd0\u7b97\u7b26\u5408\u5e76\u8fed\u4ee3\u53d8\u91cf\uff08iterables\uff09\u3002\u4e0a\u9762\u4e24\u4e2a\u4f8b\u5b50\u8bf4\u660e\uff0c\u8fd9\u4e2d\u65b9\u6cd5\u4e5f\u662f\u8fde\u63a5\u8fed\u4ee3\u53d8\u91cf\uff08iterables\uff09\u7684\u4e00\u79cd\u66f4\u6613\u8bfb\u548c\u66f4\u6709\u6548\u7684\u65b9\u6cd5\u3002 \u8fd9\u4e2a\u65b9\u6cd5 (my_set) + my_list + list(my_tuple) + list(range(1, 4)) + list(my_str) \u53ef\u4ee5\u751f\u6210\u4e00\u4e2a\u5217\u8868 \uff0c\u4e5f\u53ef\u4ee5\u4f7f\u7528\u66f4\u7b80\u6d01\u7684\u65b9\u6cd5 [*my_set, *my_list, *my_tuple, *range(1, 4), *my_str] \u3002 >>> my_tuple = ( 1 , 2 , 3 ) >>> ( 0 , * my_tuple , 4 ) ( 0 , 1 , 2 , 3 , 4 ) >>> my_list = [ 1 , 2 , 3 ] >>> [ 0 , * my_list , 4 ] [ 0 , 1 , 2 , 3 , 4 ] >>> my_set = { 1 , 2 , 3 } >>> { 0 , * my_set , 4 } { 0 , 1 , 2 , 3 , 4 } >>> [ * my_set , * my_list , * my_tuple , * range ( 1 , 4 )] [ 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 ] >>> my_str = \"123\" >>> [ * my_set , * my_list , * my_tuple , * range ( 1 , 4 ), * my_str ] [ 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 , 1 , 2 , 3 , '1' , '2' , '3' ] \u4f7f\u7528 ** \u8fd0\u7b97\u7b26\u89e3\u5305\u5b57\u5178\u3002 >>> numbers = { 'one' : 1 , 'two' : 2 , 'three' : 3 } >>> letters = { 'a' : 'A' , 'b' : 'B' , 'c' : 'C' } >>> combination = { ** numbers , ** letters } >>> combination { 'one' : 1 , 'two' : 2 , 'three' : 3 , 'a' : 'A' , 'b' : 'B' , 'c' : 'C' } \u9700\u8981\u6ce8\u610f\u7684\u91cd\u8981\u4e00\u70b9\u662f\uff0c\u5982\u679c\u6211\u4eec\u5408\u5e76\u7684\u5b57\u5178\u5177\u6709\u91cd\u590d\u952e\u6216\u516c\u5171\u952e\uff0c\u5219\u6700\u53f3\u4fa7\u5b57\u5178\u7684\u503c\u5c06\u8986\u76d6\u6700\u5de6\u4fa7\u5b57\u5178\u7684\u503c\u3002\u4f8b\u5982: >>> letters = { 'a' : 'A' , 'b' : 'B' , 'c' : 'C' } >>> vowels = { 'a' : 'a' , 'e' : 'e' , 'i' : 'i' , 'o' : 'o' , 'u' : 'u' } >>> { ** letters , ** vowels } { 'a' : 'a' , 'b' : 'B' , 'c' : 'C' , 'e' : 'e' , 'i' : 'i' , 'o' : 'o' , 'u' : 'u' } >>> { ** vowels , ** letters } { 'a' : 'A' , 'e' : 'e' , 'i' : 'i' , 'o' : 'o' , 'u' : 'u' , 'b' : 'B' , 'c' : 'C' }","title":"\u4f7f\u7528*\u548c**\u8fd0\u7b97\u7b26"},{"location":"python/Foundation/ch02/#for-loops","text":"\u6211\u4eec\u8fd8\u53ef\u4ee5\u5728 for \u5faa\u73af\u7684\u4e0a\u4e0b\u6587\u4e2d\u4f7f\u7528\u53ef\u8fed\u4ee3\u89e3\u5305\u3002 \u5f53\u6211\u4eec\u8fd0\u884c for \u5faa\u73af\u65f6\uff0c\u5728\u6bcf\u6b21\u5faa\u73af\u8fed\u4ee3\u4e2d\u5c06\u5176\u53ef\u8fed\u4ee3\u5bf9\u8c61\u4e2d\u7684\u4e00\u9879(item)\u5206\u914d\u7ed9\u76ee\u6807\u53d8\u91cf\u3002 \u5982\u679c\u8981\u5206\u914d\u7684\u9879(item)\u662f\u53ef\u8fed\u4ee3\u7684\uff0c\u90a3\u4e48\u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u5143\u7ec4\u4f5c\u4e3a\u76ee\u6807\u53d8\u91cf\uff0c\u901a\u8fc7\u5faa\u73af\u5c06\u53ef\u8fed\u4ee3\u5bf9\u8c61\u89e3\u5305\u5230\u76ee\u6807\u53d8\u91cf\u7684\u5143\u7ec4\u4e2d\u3002 \u4f8b\u5982\uff0c\u6211\u4eec\u53ef\u4ee5\u6784\u5efa\u4e00\u4e2a\u5305\u542b\u4e24\u4e2a\u5143\u7d20\u7684\u5143\u7ec4\u7684\u5217\u8868\u3002 \u6bcf\u4e2a\u5143\u7ec4\u5c06\u5305\u542b\u4ea7\u54c1\u540d\u79f0\u3001\u4ef7\u683c\u548c\u9500\u552e\u5355\u4f4d\uff0c\u6211\u4eec\u901a\u8fc7 for \u5faa\u73af\u904d\u5386\u6bcf\u4e2a\u5143\u7ec4\u5143\u7d20\u6765\u8ba1\u7b97\u6bcf\u4e2a\u4ea7\u54c1\u7684\u6536\u5165\u3002 >>> sales = [( 'Pencle' , 0.22 , 1500 ), ( 'Notebook' , 1.30 , 550 ), ( 'Eraser' , 0.75 , 1000 )] >>> for items in sales : ... print ( f \"Income for { items [ 0 ] } is: { items [ 1 ] * items [ 2 ] } \" ) ... Income for Pencle is : 330.0 Income for Notebook is : 715.0 Income for Eraser is : 750.0 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u7d22\u5f15\u6765\u8bbf\u95ee\u6bcf\u4e2a\u5143\u7ec4\u7684\u5404\u4e2a\u5143\u7d20\u3002\u4e0b\u9762\u7684\u793a\u4f8b\u4ee3\u7801\u4e2d\uff0c\u5728 for \u5faa\u73af\u4f7f\u7528\u89e3\u5305\uff0c\u8fd9\u4e5f\u662f Python \u4e2d\u89e3\u5305\u7684\u4e00\u79cd\u5b9e\u73b0\u3002 >>> sales = [( 'Pencle' , 0.22 , 1500 ), ( 'Notebook' , 1.30 , 550 ), ( 'Eraser' , 0.75 , 1000 )] >>> for product , price , sold_units in sales : ... print ( f \"Income for { product } is: { price * sold_units } \" ) ... Income for Pencle is : 330.0 Income for Notebook is : 715.0 Income for Eraser is : 750.0 \u4e5f\u53ef\u4ee5\u5728 for \u5faa\u73af\u4e2d\u4f7f\u7528 * \u8fd0\u7b97\u7b26\u5c06\u591a\u4e2a\u9879\u6253\u5305\u5230\u5355\u4e2a\u76ee\u6807\u53d8\u91cf\u4e2d\u3002 \u5728\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u9996\u5148\u53d6\u5f97\u6bcf\u4e2a\u5e8f\u5217\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u3002 \u5176\u4f59\u503c\u901a\u8fc7 * \u8fd0\u7b97\u7b26\u8d4b\u7ed9\u76ee\u6807\u53d8\u91cf rest \u3002 >>> for first , * rest in [( 1 , 2 , 3 ),( 4 , 5 , 6 )]: ... print ( 'First: ' , first ) ... print ( 'Rest: ' , rest ) ... First : 1 Rest : [ 2 , 3 ] First : 4 Rest : [ 5 , 6 ] >>> \u76ee\u6807\u53d8\u91cf\u7684\u7ed3\u6784\u5fc5\u987b\u4e0e\u53ef\u8fed\u4ee3\u5bf9\u8c61\u7684\u7ed3\u6784\u4e00\u81f4\uff0c\u5426\u5219\u4f1a\u62a5\u9519\u3002\u770b\u4e0b\u9762\u7684\u4f8b\u5b50\u3002 >>> data = [(( 1 , 2 ), 3 ), (( 2 , 3 ), 3 )] >>> for ( a , b ), c in data : ... print ( a , b , c ) ... 1 2 3 2 3 3 >>> for a , b , c in data : ... print ( a , b , c ) ... Traceback ( most recent call last ): File \"\" , line 1 , in < module > ValueError : not enough values to unpack ( expected 3 , got 2 )","title":"\u901a\u8fc7 For-Loops \u89e3\u5305"},{"location":"python/Foundation/ch02/#_2","text":"\u4e0b\u9762\u4f8b\u5b50\u4e2d\u7684\u51fd\u6570func\u81f3\u5c11\u9700\u8981\u4e00\u4e2a\u540d\u4e3a required \u7684\u53c2\u6570\u3002 \u5b83\u4e5f\u53ef\u4ee5\u63a5\u53d7\u4e00\u4e2a\u6216\u591a\u4e2a\u4f4d\u7f6e\u53c2\u6570\u6216\u5173\u952e\u5b57\u53c2\u6570\u3002 \u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c * \u8fd0\u7b97\u7b26\u5728\u4e00\u4e2a\u53eb args \u7684\u5143\u7ec4\u4e2d\u6536\u96c6\u6216\u6253\u5305\u989d\u5916\u7684\u4f4d\u7f6e\u53c2\u6570\uff0c\u800c ** \u8fd0\u7b97\u7b26\u5728\u4e00\u4e2a\u53eb kwargs \u7684\u5b57\u5178\u4e2d\u6536\u96c6\u6216\u6253\u5305\u989d\u5916\u7684\u5173\u952e\u5b57\u53c2\u6570\u3002 args \u548c kwargs \u90fd\u662f\u53ef\u9009\u7684\uff0c\u5e76\u4e14\u5206\u522b\u81ea\u52a8\u9ed8\u8ba4\u4e3a\u5143\u7ec4 () \u548c\u5b57\u5178 {} \u3002 \u8fd9\u91cc args \u548c kwargs \u7684\u547d\u540d\u5e76\u4e0d\u662f\u5fc5\u987b\u7684\uff0c\u8bed\u6cd5\u4e0a\u53ea\u9700\u8981 * \u6216 ** \u540e\u8ddf\u6709\u6548\u6807\u8bc6\u7b26\u5373\u53ef\uff0c\u5efa\u8bae\u7ed9\u53d8\u91cf\u8d77\u4e2a\u6709\u610f\u4e49\u7684\u540d\u5b57\uff0c\u63d0\u9ad8\u4ee3\u7801\u7684\u53ef\u8bfb\u6027\u3002 >>> def func ( required , * args , ** kwargs ): ... print ( required ) ... print ( args ) ... print ( kwargs ) ... >>> func ( 'Welcome to ...' , 1 , 2 , 3 , site = 'CloudAcademy.com' ) Welcome to ... ( 1 , 2 , 3 ) { 'site' : 'CloudAcademy.com' } >>> func ( 'Welcome to ...' , 1 , 2 , 3 , 4 ) Welcome to ... ( 1 , 2 , 3 , 4 ) {} >>> func ( 'Welcome to ...' , 1 , 2 , 3 , ( 1 , 2 )) Welcome to ... ( 1 , 2 , 3 , ( 1 , 2 )) {} >>> func ( 'Welcome to ...' , 1 , 2 , 3 , [ 1 , 2 ]) Welcome to ... ( 1 , 2 , 3 , [ 1 , 2 ]) {} >>> func ( 'Welcome to ...' , 1 , 2 , 3 , ([ 2 , 3 ], [ 1 , 2 ])) Welcome to ... ( 1 , 2 , 3 , ([ 2 , 3 ], [ 1 , 2 ])) {}","title":"\u7528*\u548c**\u5b9a\u4e49\u51fd\u6570"},{"location":"python/Foundation/ch02/#_3","text":"\u8c03\u7528\u51fd\u6570\u65f6\uff0c\u6211\u4eec\u8fd8\u53ef\u4ee5\u53d7\u76ca\u4e8e\u4f7f\u7528 * \u548c ** \u8fd0\u7b97\u7b26\u5c06\u53c2\u6570\u96c6\u5408\u5206\u522b\u89e3\u538b\u7f29\u4e3a\u5355\u72ec\u7684\u4f4d\u7f6e\u53c2\u6570\u6216\u5173\u952e\u5b57\u53c2\u6570\u3002 \u8fd9\u4e0e\u5728\u51fd\u6570\u7b7e\u540d(signature of a function)\u4e2d\u4f7f\u7528 * \u548c ** \u662f\u76f8\u53cd\u7684\u3002 \u5728\u51fd\u6570\u7b7e\u540d\u4e2d\uff0c\u8fd0\u7b97\u7b26\u7684\u610f\u601d\u662f\u5728\u4e00\u4e2a\u6807\u8bc6\u7b26\u4e2d\u6536\u96c6\u6216\u6253\u5305\u53ef\u53d8\u6570\u91cf\u7684\u53c2\u6570\u3002 \u5728\u8c03\u7528(calling)\u4e2d\uff0c\u5b83\u4eec\u7684\u610f\u601d\u662f\u89e3\u5305(unpack)\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u5230\u591a\u4e2a\u53c2\u6570\u4e2d\u3002 \u7eed\u4e0a\u4f8b\uff0c * \u8fd0\u7b97\u7b26\u5c06\u50cf [\"Welcome\", \"to\"] \u8fd9\u6837\u7684\u5e8f\u5217\u89e3\u5305\u5230\u4f4d\u7f6e\u53c2\u6570\u4e2d\u3002 \u7c7b\u4f3c\u5730\uff0c ** \u8fd0\u7b97\u7b26\u5c06\u5b57\u5178\u89e3\u5305\u4e3a\u4e0e\u5b57\u5178\u7684\u952e\u503c\u5339\u914d\u7684\u53c2\u6570\u540d\u3002 >>> def func ( welcome , to , site ): ... print ( welcome , to , site ) ... >>> func ( * [ 'Welcome' , 'to' ], ** { 'site' : 'CloudAcademy.com' }) Welcome to CloudAcademy . com \u7efc\u5408\u8fd0\u7528\u524d\u9762\u7684\u65b9\u6cd5\u6765\u7f16\u5199\u975e\u5e38\u7075\u6d3b\u7684\u51fd\u6570\uff0c\u6bd4\u5982\uff0c\u5728\u5b9a\u4e49\u548c\u8c03\u7528 Python \u51fd\u6570\u65f6\uff0c\u66f4\u7075\u6d3b\u7684\u4f7f\u7528 * \u548c ** \u8fd0\u7b97\u7b26\u3002 \u4f8b\u5982\uff1a >>> def func ( required , * args , ** kwargs ): ... print ( required ) ... print ( args ) ... print ( kwargs ) ... >>> func ( 'Welcome to...' , * ( 1 , 2 , 3 ), ** { 'Site' : 'CloudAcademy.com' }) Welcome to ... ( 1 , 2 , 3 ) { 'Site' : 'CloudAcademy.com' }","title":"\u4f7f\u7528*\u548c**\u8c03\u7528\u51fd\u6570"},{"location":"python/Foundation/ch02/#_4","text":"\u53ef\u8fed\u4ee3\u89e3\u5305\uff08iterable unpacking\uff09\u8fd9\u4e2a\u7279\u6027\u5141\u8bb8\u6211\u4eec\u5c06\u4e00\u4e2a\u53ef\u8fed\u4ee3\u5bf9\u8c61\u89e3\u5305\u6210\u51e0\u4e2a\u53d8\u91cf\u3002 \u53e6\u4e00\u65b9\u9762\uff0c\u6253\u5305\u5305\u62ec\u4f7f\u7528\u89e3\u5305\u8fd0\u7b97\u7b26 * \u5c06\u591a\u4e2a\u503c\u8d4b\u5230\u4e00\u4e2a\u53d8\u91cf\u4e2d\u3002 \u53ef\u8fed\u4ee3\u89e3\u5305\uff08iterable unpacking\uff09\u4e5f\u53ef\u4ee5\u7528\u6765\u8fdb\u884c\u5e76\u884c\u8d4b\u503c\u548c\u53d8\u91cf\u4e4b\u95f4\u7684\u503c\u4ea4\u6362\uff0c\u4e5f\u53ef\u4ee5\u7528\u5728 for \u5faa\u73af\u3001\u51fd\u6570\u8c03\u7528\u548c\u51fd\u6570\u5b9a\u4e49\u4e2d\u3002","title":"\u603b\u7ed3"},{"location":"python/Foundation/ch03/","text":"Python\u5185\u7f6e\u51fd\u6570\u53ca\u6587\u4ef6 \u00b6 1. \u533f\u540d\uff08Lambda\uff09\u51fd\u6570 \u00b6 \u533f\u540d\u51fd\u6570\u662f\u4e00\u79cd\u901a\u8fc7\u5355\u4e2a\u8bed\u53e5\u751f\u6210\u51fd\u6570\u7684\u65b9\u5f0f\uff0c\u5176\u7ed3\u679c\u662f\u8fd4\u56de\u503c\u3002\u533f\u540d\u51fd\u6570\u4f7f\u7528lambda\u5173\u952e\u5b57\u5b9a\u4e49\uff0c\u8be5\u5173\u952e\u5b57\u4ec5\u8868\u8fbe\u201c\u6211\u4eec\u58f0\u660e\u4e00\u4e2a\u533f\u540d\u51fd\u6570\u201d\u7684\u610f\u601d\u3002 lambda \u51fd\u6570\u53ef\u4ee5\u63a5\u6536\u4efb\u610f\u591a\u4e2a\u53c2\u6570 (\u5305\u62ec\u53ef\u9009\u53c2\u6570) \u5e76\u4e14\u8fd4\u56de\u5355\u4e2a\u8868\u8fbe\u5f0f\u7684\u503c\u3002 \u8bed\u6cd5\u683c\u5f0f\uff1a lambda arg1,arg2,arg3\u2026 :<\u8868\u8fbe\u5f0f> f = lambda x , y : x * y print ( f ( 2 , 3 )) # 6 f = [ lambda a : a * 2 , lambda b : b * 3 ] print ( f [ 0 ]( 5 )) # \u6267\u884cf\u5217\u8868\u7b2c\u4e00\u4e2a\u5143\u7d20 # 10 print ( f [ 1 ]( 5 )) # \u6267\u884cf\u5143\u7d20\u7b2c\u4e8c\u4e2a\u5143\u7d20 # 15 print ( f [ 0 , 1 ]( 5 , 5 )) # TypeError: list indices must be integers or slices, not tuple \u793a\u4f8b1\uff1a def short_func1 ( x ): return x * 2 short_func2 = lambda x : x * 2 print ( short_func1 ( 5 )) # 10 print ( short_func2 ( 5 )) # 10 \u793a\u4f8b2\uff1a def apply_to_list ( some_list , f ): return [ f ( x ) for x in some_list ] ints = [ 4 , 0 , 1 , 5 , 6 ] result5 = apply_to_list ( ints , lambda x : x * 2 ) print ( result5 ) # [8, 0, 2, 10, 12] lambda: None \u51fd\u6570\u6ca1\u6709\u8f93\u5165\u53c2\u6570\uff0c\u8f93\u51fa\u662fNone\u3002 print ( lambda : None ) # at 0x7fa5c4097670> lambda **kwargs: 1 \u8f93\u5165\u662f\u4efb\u610f\u952e\u503c\u5bf9\u53c2\u6570\uff0c\u8f93\u51fa\u662f1\u3002 print ( lambda ** kwargs : 1 ) # at 0x7fa5c4097670> 2. \u5185\u7f6e\u5e8f\u5217\u51fd\u6570enumerate \u00b6 \u5f53\u9700\u8981\u5bf9\u6570\u636e\u5efa\u7acb\u7d22\u5f15\u65f6\uff0c\u4e00\u79cd\u6709\u6548\u7684\u6a21\u5f0f\u5c31\u662f\u4f7f\u7528enumerate\u6784\u9020\u4e00\u4e2a\u5b57\u5178\uff0c\u5c06\u5e8f\u5217\u503c\uff08\u5047\u8bbe\u662f\u552f\u4e00\u7684\uff09\u6620\u5c04\u5230\u7d22\u5f15\u4f4d\u7f6e\u4e0a\u3002 seasons = [ 'Spring' , 'Summer' , 'Fall' , 'Winter' ] print ( list ( enumerate ( seasons ))) # [(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')] \u5bf9\u6bd4\u4e0b\u97622\u4e2a\u5faa\u73af a_list = [ 'foo' , 'bar' , 'baz' ] mapping = {} for i , v in enumerate ( a_list ): # enumerate\u751f\u6210\u7d22\u5f15\u503ci\u548c\u5e8f\u5217\u503cv mapping [ v ] = i print ( mapping ) # {'foo': 0, 'bar': 1, 'baz': 2} i = 0 mapping = {} for v in a_list : print ( i , a_list [ i ]) mapping [ v ] = i # \u53ef\u4ee5\u628ai\u548cv\u4e92\u6362 i += 1 print ( mapping ) # {'foo': 0, 'bar': 1, 'baz': 2} \u5229\u7528 enumerate() \u6279\u91cf\u4fee\u6539\u5217\u8868\u5185\u7684\u5143\u7d20 a_list = [ '01' , '02' , '03' ] unit_element = '1' for i , element in enumerate ( a_list ): a_list [ i ] = unit_element + element print ( a_list ) # ['101', '102', '103'] sorted\u51fd\u6570\u8fd4\u56de\u4e00\u4e2a\u6839\u636e\u4efb\u610f\u5e8f\u5217\u4e2d\u7684\u5143\u7d20\u65b0\u5efa\u7684\u5df2\u6392\u5e8f\u5217\u8868\u3002sorted\u51fd\u6570\u63a5\u53d7\u7684\u53c2\u6570\u4e0e\u5217\u8868\u7684sort\u65b9\u6cd5\u4e00\u81f4\u3002 y = sorted ([ 7 , 1 , 2 , 6 , 0 , 3 , 2 ]) print ( y ) # [0, 1, 2, 2, 3, 6, 7] \u7ed3\u679c\u5df2\u6392\u5e8f z = sorted ( 'Hello World' ) print ( z ) # [' ', 'H', 'W', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r'] zip\u5c06\u5217\u8868\u3001\u5143\u7ec4\u6216\u5176\u4ed6\u5e8f\u5217\u7684\u5143\u7d20\u914d\u5bf9\uff0c\u65b0\u5efa\u4e00\u4e2a\u5143\u7ec4\u6784\u6210\u7684\u5217\u8868\u3002 seq1 = [ 'foo' , 'bar' , 'baz' ] seq2 = [ 'one' , 'two' , 'three' ] seq3 = [ False , True ] zipped = zip ( seq1 , seq2 ) print ( list ( zipped )) # [('foo', 'one'), ('bar', 'two'), ('baz', 'three')] zipped = zip ( seq1 , seq2 , seq3 ) print ( list ( zipped )) # [('foo', 'one', False), ('bar', 'two', True)] for i , ( a , b ) in enumerate ( zip ( seq1 , seq2 )): print ( ' {0} : {1} , {2} ' . format ( i , a , b )) # \u65b9\u6cd51 {0}\u5217\u8868\u5143\u7d20\u7684\u7d22\u5f15, {1}\u5143\u7ec4\u4e2d\u7b2c\u4e00\u4e2a\u503c, {2}\u5143\u7ec4\u4e2d\u7b2c\u4e8c\u4e2a\u503c print ( f ' { i } : { a } , { b } ' ) # \u65b9\u6cd52 # 0: foo, one # 1: bar, two # 2: baz, three \u7ed9\u5b9a\u4e00\u4e2a\u5df2\u201c\u914d\u5bf9\u201d\u7684\u5e8f\u5217\u65f6\uff0czip\u51fd\u6570\u53ef\u4ee5\u53bb\u201c\u62c6\u5206\u201d\u5e8f\u5217\u3002\u8fd9\u79cd\u65b9\u5f0f\u7684\u53e6\u4e00\u79cd\u601d\u8def\u5c31\u662f\u5c06\u884c\u7684\u5217\u8868\u8f6c\u6362\u4e3a\u5217\u7684\u5217\u8868\u3002\u53c2\u8003Python\u7684 Unpacking pitchers = [( 'Jack' , 'Ma' ), ( 'Tom' , 'Li' ), ( 'Jimmy' , 'Zhang' )] first_names , last_names = zip ( * pitchers ) print ( first_names ) # ('Jack', 'Tom', 'Jimmy') print ( last_names ) # ('Ma', 'Li', 'Zhang') reversed\u51fd\u6570\u5c06\u5e8f\u5217\u7684\u5143\u7d20\u5012\u5e8f\u6392\u5217 print ( list ( reversed ( range ( 10 )))) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] 3. \u5217\u8868\u3001\u96c6\u5408\u548c\u5b57\u5178\u7684\u63a8\u5bfc\u5f0f \u00b6 \u63a8\u5bfc\u5f0fcomprehensions\uff08\u53c8\u79f0\u89e3\u6790\u5f0f\uff09\uff0c\u662fPython\u7684\u4e00\u79cd\u7279\u6027\u3002\u4f7f\u7528\u63a8\u5bfc\u5f0f\u53ef\u4ee5\u5feb\u901f\u751f\u6210\u5217\u8868\u3001\u5143\u7ec4\u3001\u96c6\u5408\u3001\u5b57\u5178\u7c7b\u578b\u7684\u6570\u636e\u3002\u63a8\u5bfc\u5f0f\u53c8\u5206\u4e3a\u5217\u8868\u63a8\u5bfc\u5f0f\u3001\u5143\u7ec4\u63a8\u5bfc\u5f0f\u3001\u96c6\u5408\u63a8\u5bfc\u5f0f\u3001\u5b57\u5178\u63a8\u5bfc\u5f0f\u3002 \u5217\u8868\u63a8\u5bfc\u5f0f(list comprehension) \u00b6 \u5217\u8868\u63a8\u5bfc\u5f0f(list comprehension)\u5141\u8bb8\u4f60\u8fc7\u6ee4\u4e00\u4e2a\u5bb9\u5668\u7684\u5143\u7d20\uff0c\u7528\u4e00\u79cd\u7b80\u660e\u7684\u8868\u8fbe\u5f0f\u8f6c\u6362\u4f20\u9012\u7ed9\u8fc7\u6ee4\u5668\u7684\u5143\u7d20\uff0c\u4ece\u800c\u751f\u6210\u4e00\u4e2a\u65b0\u7684\u5217\u8868\u3002 \u5217\u8868\u63a8\u5bfc\u5f0f\u7684\u57fa\u672c\u5f62\u5f0f\u4e3a\uff1a[expr for val in collection if condition]\uff0c\u6761\u4ef6if-condition\u4e0d\u662f\u5fc5\u987b\u7684\uff0c\u53ef\u4ee5\u53ea\u4fdd\u7559\u8868\u8fbe\u5f0f\u3002\u5217\u8868\u63a8\u5bfc\u5f0f\u4e0e\u4e0b\u9762\u7684for\u5faa\u73af\u662f\u7b49\u4ef7\u7684\uff1a result = [] for val in collection : if condition : result . append ( expr ) \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a data = [] for i in range ( - 5 , 5 ): if i >= - 1 : data . append ( i ** 2 ) print ( data ) # [1, 0, 1, 4, 9, 16] data = [ i ** 2 for i in range ( - 5 , 5 ) if i >= - 1 ] print ( data ) # [1, 0, 1, 4, 9, 16] \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u4f7f\u7528for\u53bb\u904d\u5386\u4e00\u4e2a\u53ef\u8fed\u4ee3\u7684\u5217\u8868\u3002 data = [] fruit = [ 'pomegranate' , 'cherry' , 'apricot' , 'date' , 'Apple' , 'lemon' , 'kiwi' , 'ORANGE' , 'lime' , 'Watermelon' , 'guava' , 'papaya' , 'FIG' , 'pear' , 'banana' , 'Tamarind' , 'persimmon' , 'elderberry' , 'peach' , 'BLUEberry' , 'lychee' , 'grape' ] data = [ x . upper () if x . startswith ( 'p' ) else x . title () for x in fruit ] print ( data ) # ['POMEGRANATE', 'Cherry', 'Apricot', 'Date', 'Apple', 'Lemon', 'Kiwi', 'Orange', 'Lime', 'Watermelon', 'Guava', 'PAPAYA', 'Fig', 'PEAR', 'Banana', 'Tamarind', 'PERSIMMON', 'Elderberry', 'PEACH', 'Blueberry', 'Lychee', 'Grape'] \u5957\u5217\u8868\u63a8\u5bfc\u5f0f \u00b6 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u7528\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u4ee3\u66ff2\u5c42for\u5faa\u73af\u3002 data = [] for i in range ( 1 , 3 ): if i >= 0 : for j in range ( 1 , 3 ): data . append (( i , j )) print ( data ) # [(1, 1), (1, 2), (2, 1), (2, 2)] data = [( i , j ) for i in range ( 1 , 3 ) if i >= - 1 for j in range ( 1 , 3 )] print ( data ) # [(1, 1), (1, 2), (2, 1), (2, 2)] \u518d\u4e3e\u4e00\u4e2a\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u7684\u4f8b\u5b50\u3002 all_data = [ [ 'John' , 'Emily' , 'Michael' , 'Lee' , 'Steven' ], [ 'Maria' , 'Juan' , 'Javier' , 'Natalia' , 'Pilar' ], ] names_of_interest = [] for names in all_data : enough_es = [ name for name in names if name . count ( 'e' ) >= 2 ] names_of_interest . extend ( enough_es ) print ( names_of_interest ) # ['Lee', 'Steven'] result = [ name for names in all_data for name in names if name . count ( 'e' ) >= 2 ] print ( result ) # ['Lee', 'Steven'] \u7528\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u5c06\u77e9\u9635\u6241\u5e73\u5316\u3002 \u8003\u8651\u4e0b\u9762\u8fd9\u4e2a3x4\u7684\u77e9\u9635\uff0c\u5b83\u75313\u4e2a\u957f\u5ea6\u4e3a4\u7684\u5217\u8868\u7ec4\u6210\u3002\u4e0b\u9762\u4f8b\u5b50\u5bf9\u6bd4\u4e86\u7528\u4f20\u7edffor\u5faa\u73af\u5c06\u77e9\u9635\u6241\u5e73\u5316\uff0c\u548c\u7528\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u5c06\u77e9\u9635\u6241\u5e73\u5316\u3002\u5e76\u4e14\u901a\u8fc7\u5217\u8868\u63a8\u5bfc\u5f0f\u4e2d\u7684\u5217\u8868\u63a8\u5bfc\u5f0f\u5c06\u6241\u5e73\u77e9\u9635\u8fd8\u539f\u4e3a3x4\u77e9\u9635\u3002 matrix = [ [ 1 , 2 , 3 , 4 ], [ 5 , 6 , 7 , 8 ], [ 9 , 10 , 11 , 12 ], ] flattened = [] # \u4f20\u7edffor\u5faa\u73af\u5d4c\u5957 for m in matrix : for x in m : flattened . append ( x ) print ( flattened ) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] # \u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f flattened = [ x for m in matrix for x in m ] print ( flattened ) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] # \u5217\u8868\u63a8\u5bfc\u5f0f\u4e2d\u7684\u5217\u8868\u63a8\u5bfc\u5f0f z = [[ x for x in m ] for m in matrix ] print ( z ) # [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] \u5143\u7ec4\u63a8\u5bfc\u5f0f \u00b6 \u4e0b\u9762\u7684\u4f8b\u5b50\u751f\u6210\u4e00\u4e2a\u5305\u542b\u6570\u5b571~5\u7684\u5143\u7ec4\u3002\u4ece\u7ed3\u679c\u53ef\u4ee5\u770b\u5230\uff0c\u5143\u7ec4\u63a8\u5bfc\u5f0f\u751f\u6210\u7684\u7ed3\u679c\u5e76\u4e0d\u662f\u4e00\u4e2a\u5143\u7ec4\uff0c\u800c\u662f\u4e00\u4e2a\u751f\u6210\u5668\u5bf9\u8c61\uff0c\u9700\u8981\u901a\u8fc7tuple()\u51fd\u6570\uff0c\u5c06\u751f\u6210\u5668\u5bf9\u8c61\u8f6c\u6362\u6210\u5143\u7ec4\u3002 data = ( x for x in range ( 5 )) print ( data ) # at 0x7f87217a8e40> print ( type ( data )) # print ( tuple ( data )) # (0, 1, 2, 3, 4) \u96c6\u5408\u63a8\u5bfc\u5f0f \u00b6 \u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u96c6\u5408\u63a8\u5bfc\u5f0f\u4f8b\u5b50\u3002 data = { x ** 2 for x in range ( 5 )} print ( data ) # {0, 1, 4, 9, 16} print ( type ( data )) # \u96c6\u5408\u8981\u4fdd\u8bc1\u5143\u7d20\u5fc5\u987b\u662f\u552f\u4e00\u7684\u3002 data = ( 1 , 1 , 2 , 2 , 3 , 3 , 4 , 5 , 6 ) newset = { x ** 2 for x in data } print ( newset ) # {1, 4, 36, 9, 16, 25} print ( type ( newset ) # \u5b57\u5178\u63a8\u5bfc\u5f0f \u00b6 \u5b57\u5178\u63a8\u5bfc\u5f0f: dict_comp = {key-expr : value-expr for value in collection if condition} \u5b57\u5178\u63a8\u5bfc\u5f0f\u7684\u7b80\u5355\u793a\u4f8b\uff1a strings = [ 'a' , 'as' , 'bat' , 'car' , 'dove' , 'python' ] loc_mapping = { index : val for index , val in enumerate ( strings )} print ( loc_mapping ) # {0: 'a', 1: 'as', 2: 'bat', 3: 'car', 4: 'dove', 5: 'python'} # \u4ea4\u6362\u952e\u548c\u503c loc_mapping = { index : val for val , index in enumerate ( strings )} print ( loc_mapping ) # {'a': 0, 'as': 1, 'bat': 2, 'car': 3, 'dove': 4, 'python': 5} 4. \u51fd\u6570\u58f0\u660e \u00b6 \u5982\u679cPython\u8fbe\u5230\u51fd\u6570\u7684\u5c3e\u90e8\u65f6\u4ecd\u7136\u6ca1\u6709\u9047\u5230return\u8bed\u53e5\uff0c\u5c31\u4f1a\u81ea\u52a8\u8fd4\u56deNone\u3002 \u6bcf\u4e2a\u51fd\u6570\u90fd\u53ef\u4ee5\u6709\u4f4d\u7f6e\u53c2\u6570\u548c\u5173\u952e\u5b57\u53c2\u6570\u3002\u5173\u952e\u5b57\u53c2\u6570\u6700\u5e38\u7528\u4e8e\u6307\u5b9a\u9ed8\u8ba4\u503c\u6216\u53ef\u9009\u53c2\u6570\u3002\u5173\u952e\u5b57\u53c2\u6570\u5fc5\u987b\u8ddf\u5728\u4f4d\u7f6e\u53c2\u6570\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u5173\u952e\u5b57\u53c2\u6570\u5411\u4f4d\u7f6e\u53c2\u6570\u4f20\u53c2\u3002 import sys def my_function1 ( x , y , z = 1.5 ): if z > 1 : return z * ( x + y ) else : return z / ( x + y ) result1 = my_function1 ( 5 , 6 , z = 0.7 ) print ( result1 ) # 0.06363636363636363 result1 = my_function1 ( x = 5 , y = 6 , z = 0.7 ) print ( result1 ) # 0.06363636363636363 result1 = my_function1 ( 3.14 , 7 , 3.5 ) print ( result1 ) # 35.49 result1 = my_function1 ( 10 , 20 ) print ( result1 ) # 45.0 5. \u547d\u540d\u7a7a\u95f4\u3001\u4f5c\u7528\u57df\u548c\u672c\u5730\u51fd\u6570 \u00b6 \u51fd\u6570\u6709\u4e24\u79cd\u8fde\u63a5\u53d8\u91cf\u7684\u65b9\u5f0f\uff1a\u5168\u5c40\u3001\u672c\u5730\u3002 def func1 (): list1 = [] # \u672c\u5730\u53d8\u91cf for i in range ( 5 ): list1 . append ( i ) print ( list1 ) func1 () # [0, 1, 2, 3, 4] list2 = [] # \u5168\u5c40\u53d8\u91cf def func2 (): global list2 # \u5168\u5c40\u53d8\u91cf for i in range ( 5 ): list2 . append ( i ) print ( list2 ) func2 () # [0, 1, 2, 3, 4] \u6570\u636e\u6e05\u6d17\u793a\u4f8b states = [ ' Alabama' , 'Georgia!' , 'georgia' , 'Georgia' , 'FlOrIda' , 'south carolina##' , 'West virginia? ' ] # \u65b9\u6cd51 import re def clean_string1 ( strings ): result2 = [] for value in strings : value = value . strip () value = re . sub ( '[! #? ]' , '' , value ) value = value . title () result2 . append ( value ) return result2 print ( clean_string1 (( states ))) # ['Alabama', 'Georgia', 'Georgia', 'Georgia', 'Florida', 'Southcarolina', 'Westvirginia'] # \u65b9\u6cd52 def remove_punctuaion ( value ): return re . sub ( '[! #? ]' , '' , value ) clean_ops = [ str . strip , remove_punctuaion , str . title ] def clean_string2 ( strings , ops ): result3 = [] for value in strings : for function in ops : value = function ( value ) result3 . append ( value ) return result3 result4 = clean_string2 ( states , clean_ops ) print ( result4 ) # ['Alabama', 'Georgia', 'Georgia', 'Georgia', 'Florida', 'Southcarolina', 'Westvirginia'] # \u53ef\u4ee5\u5c06\u51fd\u6570\u4f5c\u4e3a\u4e00\u4e2a\u53c2\u6570\u4f20\u7ed9\u5176\u4ed6\u7684\u51fd\u6570\u3002 for x in map ( remove_punctuaion , states ): print ( x ) # Alabama # Georgia # georgia # Georgia # FlOrIda # southcarolina # Westvirginia 6. \u67ef\u91cc\u5316\uff1a\u90e8\u5206\u53c2\u6570\u5e94\u7528 \u00b6 \u67ef\u91cc\u5316\u662f\u8ba1\u7b97\u673a\u79d1\u5b66\u672f\u8bed\uff08\u4ee5\u6570\u5b66\u5bb6Haskell Curry\u547d\u540d\uff09\uff0c\u5b83\u8868\u793a\u901a\u8fc7\u90e8\u5206\u53c2\u6570\u5e94\u7528\u7684\u65b9\u5f0f\u4ece\u5df2\u6709\u7684\u51fd\u6570\u4e2d\u884d\u751f\u51fa\u65b0\u7684\u51fd\u6570\u3002\u67ef\u91cc\u5316\u662f\u4e00\u79cd\u5c06\u591a\u53c2\u6570\u51fd\u6570\u8f6c\u5316\u4e3a\u5355\u53c2\u6570\u9ad8\u9636\u51fd\u6570\u7684\u6280\u672f\uff0c\u5982\u679c\u4f60\u56fa\u5b9a\u67d0\u4e9b\u53c2\u6570\uff0c\u4f60\u5c06\u5f97\u5230\u63a5\u53d7\u4f59\u4e0b\u53c2\u6570\u7684\u4e00\u4e2a\u51fd\u6570\u3002 \u5b9a\u4e49\u4e00\uff1a \u67ef\u91cc\u5316\uff1a\u4e00\u4e2a\u51fd\u6570\u4e2d\u6709\u4e2a\u591a\u4e2a\u53c2\u6570\uff0c\u60f3\u56fa\u5b9a\u5176\u4e2d\u67d0\u4e2a\u6216\u8005\u51e0\u4e2a\u53c2\u6570\u7684\u503c\uff0c\u800c\u53ea\u63a5\u53d7\u53e6\u5916\u51e0\u4e2a\u8fd8\u672a\u56fa\u5b9a\u7684\u53c2\u6570\uff0c\u8fd9\u6837\u51fd\u6570\u6f14\u53d8\u6210\u65b0\u7684\u51fd\u6570\u3002 \u5b9a\u4e49\u4e8c\uff1a \u51fd\u6570\u67ef\u91cc\u5316\uff08currying\uff09\u53c8\u79f0\u90e8\u5206\u6c42\u503c\u3002\u4e00\u4e2a currying \u7684\u51fd\u6570\u9996\u5148\u4f1a\u63a5\u53d7\u4e00\u4e9b\u53c2\u6570\uff0c\u63a5\u53d7\u4e86\u8fd9\u4e9b\u53c2\u6570\u4e4b\u540e\uff0c\u8be5\u51fd\u6570\u5e76\u4e0d\u4f1a\u7acb\u5373\u6c42\u503c\uff0c\u800c\u662f\u7ee7\u7eed\u8fd4\u56de\u53e6\u5916\u4e00\u4e2a\u51fd\u6570\uff0c\u521a\u624d\u4f20\u5165\u7684\u53c2\u6570\u5728\u51fd\u6570\u5f62\u6210\u7684\u95ed\u5305\u4e2d\u88ab\u4fdd\u5b58\u8d77\u6765\u3002\u5f85\u5230\u51fd\u6570\u88ab\u771f\u6b63\u9700\u8981\u6c42\u503c\u7684\u65f6\u5019\uff0c\u4e4b\u524d\u4f20\u5165\u7684\u6240\u6709\u53c2\u6570\u90fd\u4f1a\u88ab\u4e00\u6b21\u6027\u7528\u4e8e\u6c42\u503c\u3002 \u5b9a\u4e49\u4e09\uff1a \u4e00\u4e9b\u51fd\u6570\u5f0f\u8bed\u8a00\u7684\u5de5\u4f5c\u539f\u7406\u662f\u5c06\u591a\u53c2\u6570\u51fd\u6570\u8bed\u6cd5\u8f6c\u5316\u4e3a\u5355\u53c2\u6570\u51fd\u6570\u96c6\u5408\uff0c\u8fd9\u4e00\u8fc7\u7a0b\u79f0\u4e3a\u67ef\u91cc\u5316\uff0c\u5b83\u662f\u4ee5\u903b\u8f91\u5b66\u5bb6Haskell Curry\u7684\u540d\u5b57\u547d\u540d\u7684\u3002Haskell Curry\u4ece\u65e9\u671f\u6982\u5ff5\u4e2d\u53d1\u5c55\u51fa\u4e86\u8be5\u7406\u8bba\u3002\u5176\u5f62\u5f0f\u76f8\u5f53\u4e8e\u5c06z=f(x, y)\u8f6c\u6362\u6210z=f(x)(y)\u7684\u5f62\u5f0f\uff0c\u539f\u51fd\u6570\u7531\u4e24\u4e2a\u53c2\u6570\uff0c\u73b0\u5728\u53d8\u4e3a\u4e24\u4e2a\u63a5\u53d7\u5355\u53c2\u6570\u7684\u51fd\u6570\uff0c \u793a\u4f8b1\uff1a\u67ef\u91cc\u5316\u7684\u8fc7\u7a0b\u5c31\u662f\u628a\u539f\u6765\u5e26\u4e24\u4e2a\u53c2\u6570\u7684\u51fd\u6570add(x, y)\uff0c\u53d8\u6210\u4e86\u4e00\u4e2a\u5d4c\u5957\u51fd\u6570\uff0c\u5728add_currying\u51fd\u6570\u5185\uff0c\u53c8\u5b9a\u4e49\u4e86\u4e00\u4e2a_add\u51fd\u6570\uff0c\u5e76\u4e14_add\u51fd\u6570\u53c8\u5f15\u7528\u4e86\u5916\u90e8\u51fd\u6570add_currying\u7684\u53d8\u91cfx\uff0c\u8fd9\u5c31\u662f\u4e00\u4e2a\u95ed\u5305\u3002 \u95ed\u5305\uff0c\u4e00\u53e5\u8bdd\u8bf4\u5c31\u662f\u5728\u51fd\u6570\u4e2d\u518d\u5d4c\u5957\u4e00\u4e2a\u51fd\u6570\uff0c\u5e76\u4e14\u5f15\u7528\u5916\u90e8\u51fd\u6570\u7684\u53d8\u91cf\u3002 # \u666e\u901a\u5199\u6cd5 def add ( x , y ): return x + y print ( add ( 1 , 2 )) # 3 # \u67ef\u91cc\u5316\u5199\u6cd5 def add_currying ( x ): def _add ( y ): return x + y return _add print ( add_currying ( 1 )( 2 )) # 3 \u793a\u4f8b2\uff0c\u901a\u8fc7\u56fa\u5b9a\u5176\u4e2d\u7684\u7b2c\u4e8c\u4e2a\u53c2\u6570\u4e0d\u53d8\u6765\u5b9e\u73b0\u67ef\u91cc\u5316\u3002 def add2 ( a , b ): def add1 ( a , b , c ): return a + b + c return add1 ( a , 666 , b ) result6 = add2 ( 12 , 13 ) print ( result6 ) # 691 result6 = add2 ( 12 , 555 , 13 ) # TypeError: add2() takes 2 positional arguments but 3 were given \u793a\u4f8b3\uff0c\u901a\u8fc7functools\u63d0\u4f9b\u7684\u504f\u51fd\u6570\u6765\u5b9e\u73b0\u67ef\u91cc\u5316\u3002 from functools import partial def add1 ( a , b , c ): return a + b + c add3 = partial ( add1 , b = 666 ) result7 = add3 ( a = 12 , c = 13 ) print ( result7 ) # 691 \u793a\u4f8b4\uff0c\u901a\u8fc7lambda\u8868\u8fbe\u5f0f\u6765\u5b9e\u73b0\u67ef\u91cc\u5316\u3002 def add1 ( a , b , c ): return a + b + c add4 = lambda x , y : add1 ( x , 666 , y ) result8 = add4 ( 12 , 13 ) print ( result8 ) # 691 \u793a\u4f8b5\uff0c\u901a\u8fc7python\u7684\u88c5\u9970\u5668\u6765\u5b9e\u73b0\u67ef\u91cc\u5316 def add1 ( a , b , c ): return a + b + c def currying_add ( func ): def wrapper ( a , c , b = 666 ): return func ( a , b , c ) return wrapper result9 = currying_add ( add1 )( 12 , 13 ) print ( result9 ) # 691 \u793a\u4f8b6\uff0c\u901a\u8fc7python\u7684\u88c5\u9970\u5668\u7b26\u53f7@\u6765\u5b9e\u73b0\u67ef\u91cc\u5316 def currying_add ( func ): def wrapper ( a , c , b = 666 ): return func ( a , b , c ) return wrapper @currying_add def add5 ( a , b , c ): return a + b + c result10 = add5 ( 12 , 13 ) print ( result10 ) # 691 7. \u8fed\u4ee3\u5668\u4e0e\u751f\u6210\u5668 \u00b6 \u8fed\u4ee3\u5668 \u00b6 \u8fed\u4ee3\u662fPython\u6700\u5f3a\u5927\u7684\u529f\u80fd\u4e4b\u4e00\uff0c\u662f\u8bbf\u95ee\u96c6\u5408\u5143\u7d20\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u8fed\u4ee3\u5668\u662f\u4e00\u4e2a\u53ef\u4ee5\u8bb0\u4f4f\u904d\u5386\u7684\u4f4d\u7f6e\u7684\u5bf9\u8c61\u3002 \u8fed\u4ee3\u5668\u5bf9\u8c61\u4ece\u96c6\u5408\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\u8bbf\u95ee\uff0c\u76f4\u5230\u6240\u6709\u7684\u5143\u7d20\u88ab\u8bbf\u95ee\u5b8c\u7ed3\u675f\u3002\u8fed\u4ee3\u5668\u53ea\u80fd\u5f80\u524d\u4e0d\u4f1a\u540e\u9000\u3002 \u8fed\u4ee3\u5668\u6709\u4e24\u4e2a\u57fa\u672c\u7684\u65b9\u6cd5\uff1aiter() \u548c next()\u3002 \u8fed\u4ee3\u5668\u793a\u4f8b\uff1a list_a = [ 1 , 2 , 3 , 4 ] it = iter ( list_a ) # \u521b\u5efa\u8fed\u4ee3\u5668\u5bf9\u8c61 print ( next ( it )) # \u8f93\u51fa\u8fed\u4ee3\u5668\u7684\u4e0b\u4e00\u4e2a\u5143\u7d20 # 1 print ( next ( it )) # \u8f93\u51fa\u8fed\u4ee3\u5668\u7684\u4e0b\u4e00\u4e2a\u5143\u7d20 # 2 \u8fed\u4ee3\u5668\u5bf9\u8c61\u53ef\u4ee5\u4f7f\u7528\u5e38\u89c4for\u8bed\u53e5\u8fdb\u884c\u904d\u5386\u3002 list_a = [ 1 , 2 , 3 , 4 ] it = iter ( list_a ) # \u521b\u5efa\u8fed\u4ee3\u5668\u5bf9\u8c61 for x in it : print ( x , end = \" \" ) print ( end = \" \\n \" ) # 1 2 3 4 \u751f\u6210\u5668 \u00b6 \u5728 Python \u4e2d\uff0c\u4f7f\u7528\u4e86 yield \u7684\u51fd\u6570\u88ab\u79f0\u4e3a\u751f\u6210\u5668\uff08generator\uff09\u3002\u8ddf\u666e\u901a\u51fd\u6570\u4e0d\u540c\u7684\u662f\uff0c\u751f\u6210\u5668\u662f\u4e00\u4e2a\u8fd4\u56de\u8fed\u4ee3\u5668\u7684\u51fd\u6570\uff0c\u53ea\u80fd\u7528\u4e8e\u8fed\u4ee3\u64cd\u4f5c\uff0c\u751f\u6210\u5668\u5c31\u662f\u4e00\u4e2a\u8fed\u4ee3\u5668\u3002 \u5728\u8c03\u7528\u751f\u6210\u5668\u8fd0\u884c\u7684\u8fc7\u7a0b\u4e2d\uff0c\u6bcf\u6b21\u9047\u5230 yield \u65f6\u51fd\u6570\u4f1a\u6682\u505c\u5e76\u4fdd\u5b58\u5f53\u524d\u6240\u6709\u7684\u8fd0\u884c\u4fe1\u606f\uff0c\u8fd4\u56de yield \u7684\u503c, \u5e76\u5728\u4e0b\u4e00\u6b21\u6267\u884c next() \u65b9\u6cd5\u65f6\u4ece\u5f53\u524d\u4f4d\u7f6e\u7ee7\u7eed\u8fd0\u884c\u3002 \u8c03\u7528\u4e00\u4e2a\u751f\u6210\u5668\u51fd\u6570\uff0c\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u8fed\u4ee3\u5668\u5bf9\u8c61\u3002 \u793a\u4f8b, \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a def fibonacci ( n ): a , b , counter = 0 , 1 , 0 while True : if ( counter > n ): return yield a a , b = b , a + b counter += 1 f = fibonacci ( 10 ) # f \u662f\u4e00\u4e2a\u8fed\u4ee3\u5668\uff0c\u7531\u751f\u6210\u5668\u8fd4\u56de\u751f\u6210 print ( f ) # \u5b9e\u9645\u8c03\u7528\u751f\u6210\u5668\u65f6\uff0c\u4ee3\u7801\u5e76\u4e0d\u4f1a\u7acb\u5373\u6267\u884c for x in f : # \u8bf7\u6c42\u751f\u6210\u5668\u4e2d\u7684\u5143\u7d20\u65f6\uff0c\u5b83\u624d\u4f1a\u6267\u884c\u5b83\u7684\u4ee3\u7801 print ( x , end = \" \" ) print ( end = \" \\n \" ) # 0 1 1 2 3 5 8 13 21 34 55 \u751f\u6210\u5668\u8868\u8fbe\u5f0f\uff1a \u7528\u751f\u6210\u5668\u8868\u8fbe\u5f0f\u6765\u521b\u5efa\u751f\u6210\u5668\u66f4\u4e3a\u7b80\u5355\u3002\u751f\u6210\u5668\u8868\u8fbe\u5f0f\u4e0e\u5217\u8868\u3001\u5b57\u5178\u3001\u96c6\u5408\u7684\u63a8\u5bfc\u5f0f\u5f88\u7c7b\u4f3c\uff0c\u521b\u5efa\u4e00\u4e2a\u751f\u6210\u5668\u8868\u8fbe\u5f0f\uff0c\u53ea\u9700\u8981\u5c06\u5217\u8868\u63a8\u5bfc\u5f0f\u7684\u4e2d\u62ec\u53f7\u66ff\u6362\u4e3a\u5c0f\u62ec\u53f7\u5373\u53ef\u3002 gen1 = ( x ** 2 for x in range ( 100 )) print ( gen1 ) # at 0x7fd3f30c9580> \u4e0a\u9762\u7684\u4ee3\u7801\u4e0e\u4e0b\u9762\u7684\u751f\u6210\u5668\u662f\u7b49\u4ef7\u7684 def _make_gen (): for x in range ( 100 ): yield x ** 2 gen2 = _make_gen () print ( gen2 ) # \u751f\u6210\u5668\u8868\u8fbe\u5f0f\u53ef\u4ee5\u4f5c\u4e3a\u51fd\u6570\u53c2\u6570\u7528\u4e8e\u66ff\u4ee3\u5217\u8868\u63a8\u5bfc\u5f0f\u3002\u5bf9\u6bd4\u4e0b\u97622\u4e2a\u4f8b\u5b50\u3002 # \u793a\u4f8b1 result11 = sum ( x ** 2 for x in range ( 100 )) print ( result11 ) # 328350 gen1 = ( x ** 2 for x in range ( 100 )) result11 = sum ( gen1 ) print ( result11 ) # 328350 # \u793a\u4f8b2 result12 = dict (( i , i ** 2 ) for i in range ( 5 )) print ( result12 ) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} gen2 = (( i , i ** 2 ) for i in range ( 5 )) result12 = dict ( gen2 ) print ( result12 ) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} \u751f\u6210\u5668\uff1aitertools\u6a21\u5757 \u00b6 \u6807\u51c6\u5e93\u4e2d\u7684itertools\u6a21\u5757\u662f\u9002\u7528\u4e8e\u5927\u591a\u6570\u6570\u636e\u7b97\u6cd5\u7684\u751f\u6210\u5668\u96c6\u5408\u3002 import itertools first_letter = lambda x : x [ 0 ] names = [ 'Alan' , 'Adam' , 'Wes' , 'Will' , 'Albert' , 'Steven' ] for letter , names in itertools . groupby ( names , first_letter ): print ( letter ) print ( first_letter ) print ( letter , list ( names )) # names is generator # A # at 0x7fa598a7a0d0> # A ['Alan', 'Adam'] # W # at 0x7fa598a7a0d0> # W ['Wes', 'Will'] # A # at 0x7fa598a7a0d0> # A ['Albert'] # S # at 0x7fa598a7a0d0> # S ['Steven'] 8. \u9519\u8bef\u548c\u5f02\u5e38\u5904\u7406 \u00b6 Python\u7528\u5f02\u5e38\u5bf9\u8c61(exception object)\u6765\u8868\u793a\u5f02\u5e38\u60c5\u51b5\u3002\u9047\u5230\u9519\u8bef\u540e\uff0c\u4f1a\u5f15\u53d1\u5f02\u5e38\u3002\u5982\u679c\u5f02\u5e38\u5bf9\u8c61\u5e76\u672a\u88ab\u5904\u7406\u6216\u6355\u6349\uff0c\u7a0b\u5e8f\u5c31\u4f1a\u7528\u6240\u8c13\u7684\u56de\u6eaf(traceback\uff0c \u4e00\u79cd\u9519\u8bef\u4fe1\u606f)\u7ec8\u6b62\u6267\u884c\u3002 \u5f02\u5e38\u548c\u8bed\u6cd5\u9519\u8bef\u662f\u6709\u533a\u522b\u7684\u3002 \u9519\u8bef\uff1a\u662f\u6307\u4ee3\u7801\u4e0d\u7b26\u5408\u89e3\u91ca\u5668\u6216\u8005\u7f16\u8bd1\u5668\u8bed\u6cd5\u3002 \u5f02\u5e38\uff1a\u662f\u6307\u4e0d\u5b8c\u6574\u3001\u4e0d\u5408\u6cd5\u8f93\u5165\uff0c\u6216\u8005\u8ba1\u7b97\u51fa\u73b0\u9519\u8bef\u3002 python\u91cc\u7528try...except...\u8bed\u53e5\u6765\u5904\u7406\u5f02\u5e38\u60c5\u51b5\u3002 def attempt_float ( x ): try : return float ( x ) except ( TypeError , ValueError ): return \"Type error, not numbers\" r1 = attempt_float ( '1.2256' ) print ( r1 ) # 1.2256 r1 = attempt_float ( 'friends' ) print ( r1 ) # Type error, not numbers 9. \u6587\u4ef6\u4e0e\u64cd\u4f5c\u7cfb\u7edf \u00b6 f=open(path, 'w')\uff0c\u4e00\u4e2a\u65b0\u7684\u6587\u4ef6\u4f1a\u5728path\u6307\u5b9a\u7684\u8def\u5f84\u88ab\u521b\u5efa\uff0c\u5e76\u5728\u540c\u4e00\u8def\u5f84\u4e0b\u8986\u76d6\u540c\u540d\u6587\u4ef6\u3002\uff08\u8bf7\u5c0f\u5fc3\uff01\uff09 f=open(path, 'x')\uff0c\u4e00\u4e2a\u65b0\u7684\u6587\u4ef6\u4f1a\u5728path\u6307\u5b9a\u7684\u8def\u5f84\u88ab\u521b\u5efa\uff0c\u5982\u679c\u7ed9\u5b9a\u8def\u5f84\u4e0b\u5df2\u7ecf\u5b58\u5728\u540c\u540d\u6587\u4ef6\u5c31\u4f1a\u521b\u5efa\u5931\u8d25\u3002 import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f = open ( path ) # \u8bfb\u53d6\u6587\u4ef6\u6bcf\u4e00\u884c\uff0c\u6587\u4ef6\u6bcf\u4e00\u884c\u4f5c\u4e3a\u5217\u8868\u4e00\u4e2a\u5143\u7d20 lines = [ x . rstrip () for x in open ( path )] # \u8f93\u51fa\u5217\u8868 print ( lines ) # \u5173\u95ed\u6587\u4ef6\u4f1a\u5c06\u8d44\u6e90\u91ca\u653e\u56de\u64cd\u4f5c\u7cfb\u7edf f . close () \u53e6\u4e00\u79cd\u66f4\u7b80\u5355\u7684\u5173\u95ed\u6587\u4ef6\u7684\u65b9\u5f0f import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f = open ( path ) # \u4f7f\u7528with\u8bed\u53e5\u8bfb\u53d6\u6587\u4ef6\uff0c\u6587\u4ef6\u4f1a\u5728with\u4ee3\u7801\u5757\u7ed3\u675f\u540e\u81ea\u52a8\u5173\u95ed\u3002 with open ( path ) as f : lines = [ x . rstrip () for x in open ( path )] # \u8f93\u51fa\uff1a\u6587\u4ef6\u6bcf\u4e00\u884c\u4f5c\u4e3a\u5217\u8868\u4e00\u4e2a\u5143\u7d20 print ( lines ) \u5728\u6253\u5f00\u6587\u4ef6\u65f6\u4f7f\u7528seek\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u8981\u5f53\u5fc3\u3002\u5982\u679c\u6587\u4ef6\u7684\u53e5\u67c4\u4f4d\u7f6e\u6070\u597d\u5728\u4e00\u4e2aUnicode\u7b26\u53f7\u7684\u5b57\u8282\u4e2d\u95f4\u65f6\uff0c\u540e\u7eed\u7684\u8bfb\u53d6\u4f1a\u5bfc\u81f4\u9519\u8bef\u3002 import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f = open ( path ) # \u8bfb\u53d6\u6587\u4ef6\u3002 print ( f . read ( 5 )) # \u8f93\u51fa\u524d5\u4e2a\u5b57\u7b26\u3002 read\u65b9\u6cd5\u901a\u8fc7\u8bfb\u53d6\u7684\u5b57\u8282\u6570\u6765\u63a8\u8fdb\u6587\u4ef6\u53e5\u67c4\u7684\u4f4d\u7f6e\u3002 # I Thi print ( f . tell ()) # tell\u65b9\u6cd5\u53ef\u4ee5\u7ed9\u51fa\u53e5\u67c4\u5f53\u524d\u7684\u4f4d\u7f6e # 5 print ( f . seek ( 6 )) # seek\u65b9\u6cd5\u53ef\u4ee5\u5c06\u53e5\u67c4\u4f4d\u7f6e\u6539\u53d8\u5230\u6587\u4ef6\u4e2d\u7279\u5b9a\u7684\u5b57\u8282 # 6 print ( f . read ( 1 )) # \u4ece\u7b2c7\u4e2a\u5b57\u8282\u5f00\u59cb\uff0c\u8f93\u51fa1\u4e2a\u5b57\u8282 # k # \u5173\u95ed\u6587\u4ef6\u4f1a\u5c06\u8d44\u6e90\u91ca\u653e\u56de\u64cd\u4f5c\u7cfb\u7edf f . close () \u5982\u679c\u4f7f\u7528\u4e8c\u8fdb\u5236\u65b9\u5f0f\u6253\u5f00\u6587\u4ef6\uff0c\u5219\uff1a import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f2 = open ( path , 'rb' ) # \u4e8c\u8fdb\u5236\u6a21\u5f0f # \u8bfb\u53d6\u6587\u4ef6 print ( f2 . read ( 5 )) # \u7b2c\u4e00\u4e2ab\u4ee3\u8868\u4e8c\u8fdb\u5236\u683c\u5f0f # b'I Thi' print ( f2 . tell ()) # 5 print ( f2 . seek ( 6 )) # 6 print ( f2 . read ( 2 )) # \u4ece\u7b2c7\u4e2a\u5b57\u8282\u5f00\u59cb\uff0c\u8f93\u51fa2\u4e2a\u5b57\u8282 # b'k ' # \u5173\u95ed\u6587\u4ef6\u4f1a\u5c06\u8d44\u6e90\u91ca\u653e\u56de\u64cd\u4f5c\u7cfb\u7edf f2 . close () \u5c06\u672c\u6587\u5199\u5165\u6587\u4ef6\uff0c\u53ef\u4ee5\u4f7f\u7528\u6587\u4ef6\u5bf9\u8c61\u7684write\u6216wirtelines\u65b9\u6cd5\u3002 import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path1 = 'file01.txt' path2 = 'file02.txt' # file02.txt\u662f\u4e00\u4e2a\u7a7a\u6587\u4ef6 with open ( path2 , 'r+' , encoding = 'utf-8' ) as f : f . writelines ( x for x in open ( path1 , 'r' , encoding = 'utf-8' ) if len ( x ) > 1 ) # \u628afile01.txt\u7684\u5185\u5bb9\u5199\u5165file02.txt lines = f . readlines () print ( lines ) 10. \u88c5\u9970\u5668 \u00b6 \u95ed\u5305 \u00b6 \u7ef4\u57fa\u767e\u79d1\u4e2d\u7684\u89e3\u91ca\uff1a \u95ed\u5305\uff08Closure\uff09 \uff0c\u53c8\u79f0\u8bcd\u6cd5\u95ed\u5305\uff08Lexical Closure\uff09\u6216\u51fd\u6570\u95ed\u5305\uff08function closures\uff09\uff0c\u662f\u5f15\u7528\u4e86\u81ea\u7531\u53d8\u91cf\u7684\u51fd\u6570\u3002\u8fd9\u4e2a\u88ab\u5f15\u7528\u7684\u81ea\u7531\u53d8\u91cf\u5c06\u548c\u8fd9\u4e2a\u51fd\u6570\u4e00\u540c\u5b58\u5728\uff0c\u5373\u4f7f\u5df2\u7ecf\u79bb\u5f00\u4e86\u521b\u9020\u5b83\u7684\u73af\u5883\u4e5f\u4e0d\u4f8b\u5916\u3002 \u95ed\u5305\u5ef6\u4f38\u4e86\u4f5c\u7528\u57df\u7684\u51fd\u6570\uff0c\u5176\u4e2d\u5305\u542b\u51fd\u6570\u5b9a\u4e49\u4f53\u4e2d\u5f15\u7528\u3001\u4f46\u662f\u4e0d\u5728\u5b9a\u4e49\u4f53\u4e2d\u5b9a\u4e49\u7684\u975e\u5168\u5c40\u53d8\u91cf\u3002\u51fd\u6570\u662f\u4e0d\u662f\u533f\u540d\u7684\u6ca1\u6709\u5173\u7cfb\uff0c\u5173\u952e\u662f\u5b83\u80fd\u8bbf\u95ee\u5b9a\u4e49\u4f53\u4e4b\u5916\u5b9a\u4e49\u7684\u975e\u5168\u5c40\u53d8\u91cf\u3002 \u4f8b\u4e00\uff0c\u8ba1\u7b97\u79fb\u52a8\u5e73\u5747\u503c\u3002 \u4e0b\u9762\u662f\u662f\u4f20\u7edf\u7c7b\u5b9e\u73b0\u65b9\u5f0f\uff0cAvg\u7684\u5b9e\u4f8b\u662f\u53ef\u8c03\u7528\u7684\u5bf9\u8c61\u3002 class Avg (): def __init__ ( self ): self . mylist = [] def __call__ ( self , newValue ): self . mylist . append ( newValue ) total = sum ( self . mylist ) return total / len ( self . mylist ) avg = Avg () avg ( 10 ) # 10.0 avg ( 20 ) # 15.0 avg ( 30 ) # 20.0 \u4e0b\u9762\u662f\u9ad8\u9636\u51fd\u6570\u5b9e\u73b0\u65b9\u5f0f\u3002\u8c03\u7528 make_avg \u65f6\uff0c\u8fd4\u56de\u4e00\u4e2a my_avg \u51fd\u6570\u5bf9\u8c61\u3002\u6bcf\u6b21\u8c03\u7528 my_avg \u65f6\uff0c\u5b83\u4f1a\u628a\u53c2\u6570\u6dfb\u52a0\u5230\u7cfb\u5217\u503c\u4e2d\uff0c\u7136\u540e\u8ba1\u7b97\u5f53\u524d\u5e73\u5747\u503c\u3002 def make_avg (): my_list = [] def avg ( newValue ): my_list . append ( newValue ) total = sum ( my_list ) return total / len ( my_list ) return avg my_avg = make_avg () my_avg ( 10 ) # 10.0 my_avg ( 20 ) # 15.0 my_avg ( 30 ) # 20.0 my_avg . __code__ . co_varnames # ('newValue', 'total') my_avg . __code__ . co_freevars # ('my_list',) my_avg . __closure__ # (,) my_avg . __closure__ [ 0 ] . cell_contents # [10, 20, 30] \u8fd9\u4e24\u4e2a\u793a\u4f8b\u6709\u5171\u901a\u4e4b\u5904\uff1a\u8c03\u7528 Avg() \u6216 make_avg() \u5f97\u5230\u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61 avg \uff0c\u5b83\u4f1a\u66f4\u65b0\u5386\u53f2\u503c\uff0c\u7136\u540e\u8ba1\u7b97\u5f53\u524d\u5747\u503c\u3002 \u5728\u7c7b\u5b9e\u73b0\u4e2d\uff0c avg \u662f Avg \u7684\u5b9e\u4f8b\uff1b\u5728\u9ad8\u9636\u51fd\u6570\u5b9e\u73b0\u4e2d\u662f\u5185\u90e8\u51fd\u6570 avg \u3002 \u4e24\u79cd\u5b9e\u73b0\u65b9\u5f0f\u4e2d\uff0c\u6211\u4eec\u90fd\u53ea\u9700\u8c03\u7528 avg(n) \uff0c\u628a n \u653e\u5165\u7cfb\u5217\u503c\u4e2d\uff0c\u7136\u540e\u91cd\u65b0\u8ba1\u7b97\u5747\u503c\u3002 \u7b2c\u4e00\u4e2a\u4f8b\u5b50\u4e2d\uff0c Avg \u7c7b\u7684\u5b9e\u4f8b avg \u5728 self.series \u5b9e\u4f8b\u5c5e\u6027\u4e2d\u5b58\u50a8\u5386\u53f2\u503c\u3002 \u7b2c\u4e8c\u4e2a\u4f8b\u5b50\u4e2d\u7684 my_list \u662f\u51fd\u6570 make_avg() \u7684\u5c40\u90e8\u53d8\u91cf\uff0c\u4e5f\u79f0\u4e3a\u8be5\u51fd\u6570\u7684**\u81ea\u7531\u53d8\u91cf\uff08free variable\uff09**\uff0c\u6307\u672a\u5728\u672c\u5730\u4f5c\u7528\u57df\u4e2d\u7ed1\u5b9a\u7684\u53d8\u91cf\u3002 avg() \u51fd\u6570\u7684\u95ed\u5305\u5ef6\u4f38\u5230\u51fd\u6570\u7684\u4f5c\u7528\u57df\u4e4b\u5916\uff0c\u5305\u542b\u4e86 make_avg() \u7684\u81ea\u7531\u53d8\u91cf my_list \u7684\u7ed1\u5b9a\u3002 \u5bf9\u4e8e\u8fd4\u56de\u7684 my_avg \u5bf9\u8c61\uff0c\u5176 __code__ \u5c5e\u6027\uff08\u8868\u793a\u7f16\u8bd1\u540e\u7684\u51fd\u6570\u5b9a\u4e49\u4f53\uff09\u4e2d\u4fdd\u5b58\u4e86\u5c40\u90e8\u53d8\u91cf\u548c\u81ea\u7531\u53d8\u91cf\u7684\u540d\u79f0\uff0c\u5373 my_avg.__code__.co_varnames \u8fd4\u56de\u4e86\u5c40\u90e8\u53d8\u91cf ('newValue', 'total') \u548c my_avg.__code__.co_freevars \u8fd4\u56de\u4e86\u81ea\u7531\u53d8\u91cf ('my_list',) \u3002 \u81ea\u7531\u53d8\u91cf my_list \u7ed1\u5b9a\u5728\u8fd4\u56de\u7684 my_avg \u7684 __closure__ \u7684\u5c5e\u6027\u4e2d\uff0c my_avg.__closure__ \u4e2d\u7684\u5404\u4e2a\u5143\u7d20\u5bf9\u5e94\u4e86 my_avg.__code__.co_freevars \u4e2d\u7684\u4e00\u4e2a\u540d\u79f0\u3002\u8fd9\u4e9b\u5143\u7d20\u662f cell \u5bf9\u8c61\uff0c\u6709\u4e2a cell_contents \u5c5e\u6027\uff0c\u5982\uff1a my_avg.__closure__ \u8fd4\u56de (,) \uff0c\u91cc\u9762\u4fdd\u5b58\u7740\u771f\u6b63\u7684\u503c\uff0c\u5982 my_avg.__closure__[0].cell_contents \u91cc\u9762\u4fdd\u5b58\u6bcf\u6b21\u8c03\u7528\u7684\u771f\u5b9e\u503c [10, 20, 30] \u3002 \u4e0a\u9762 my_list \u662f\u4e00\u4e2a\u53ef\u53d8\u7c7b\u578b\uff0c\u5982\u679c\u7528\u4e0d\u53ef\u53d8\u7c7b\u578b\u6539\u5199\uff0c\u5e76\u5b9e\u73b0\u95ed\u5305\uff0c\u53ef\u4ee5\u4f7f\u7528 nolocal \u8fdb\u884c\u58f0\u660e\u3002\u5b83\u7684\u4f5c\u7528\u662f\u628a\u53d8\u91cf\u6807\u8bb0\u4e3a\u81ea\u7531\u53d8\u91cf\uff0c\u5373\u4f7f\u5728\u51fd\u6570\u4e2d\u4e3a\u53d8\u91cf\u8d4b\u4e88\u65b0\u503c\u4e86\uff0c\u4e5f\u4f1a\u53d8\u6210\u81ea\u7531\u53d8\u91cf\u3002\u5982\u679c\u4e3anonlocal\u58f0\u660e\u7684\u53d8\u91cf\u8d4b\u4e88\u65b0\u503c\uff0c\u95ed\u5305\u4e2d\u4fdd\u5b58\u7684\u7ed1\u5b9a\u4f1a\u66f4\u65b0\u3002 my_avg.__code__.co_freevars \u8fd4\u56de\u4e862\u4e2a\u81ea\u7531\u53d8\u91cf ('count', 'total') \uff0c\u5e76\u5728 my_avg.__closure__[0].cell_contents \u548c my_avg.__closure__[1].cell_contents \u91cc\u9762\u4fdd\u5b58\u4e86\u6700\u540e\u4e00\u6b21\u6267\u884c\u7684\u771f\u5b9e\u503c\u3002 def make_avg (): count = 0 total = 0 def avg ( newValue ): nonlocal count , total count += 1 total += newValue return total / count return avg my_avg = make_avg () my_avg ( 10 ) # 10.0 my_avg ( 20 ) # 15.0 my_avg ( 30 ) # 20.0 my_avg . __code__ . co_varnames # ('newValue',) my_avg . __code__ . co_freevars # ('count', 'total') my_avg . __closure__ # (, ) my_avg . __closure__ [ 0 ] . cell_contents # 3 my_avg . __closure__ [ 1 ] . cell_contents # 60 \u4f8b\u4e8c\uff1a money \u662f\u4e00\u4e2a\u5c40\u90e8\u53d8\u91cf\uff0c\u5728 get_money \u662f\u5916\u56f4\u51fd\u6570\uff0c\u51fd\u6570\u6267\u884c\u4e4b\u540e\u5e94\u8be5\u5c31\u4e0d\u4f1a\u5b58\u5728\u4e86\u3002 \u4f46\u662f\u5d4c\u5957\u51fd\u6570 work \u5f15\u7528\u4e86 money \u8fd9\u4e2a\u81ea\u7531\u53d8\u91cf\uff0c\u5c06\u8fd9\u4e2a\u5c40\u90e8\u53d8\u91cf\u5c01\u95ed\u5728\u4e86\u5d4c\u5957\u51fd\u6570 work \u4e2d\uff0c\u8fd9\u6837\u5c31\u5f62\u6210\u4e86\u4e00\u4e2a\u95ed\u5305\u3002 closure = get_money() \u83b7\u5f97\u7684\u5c31\u662f\u4e00\u4e2a\u95ed\u5305\u3002 closure() \u8f93\u51fa\u95ed\u5305\uff0c\u5373\uff0c\u6267\u884c\u4e86 work() \uff0c\u6253\u5370\u8f93\u51fa money \u7684\u503c\u3002 \u672c\u5730\u51fd\u6570\u901a\u8fc7global\u58f0\u660e\u5bf9\u5168\u5c40\u53d8\u91cf\u8fdb\u884c\u5f15\u7528\u4fee\u6539\uff0c\u90a3\u4e48\u5bf9\u4e8e\u5185\u5d4c\u51fd\u6570 work() \u4f5c\u7528\u57df\u4e2d\u7684\u53d8\u91cf\u8fdb\u884c\u4fee\u6539\uff0c\u5c31\u8981\u4f7f\u7528 nonlocal \u8fdb\u884c\u58f0\u660e\u3002 def get_money (): money = 0 def work (): nonlocal money money += 100 print ( money ) return work closure = get_money () closure () # 100 closure () # 200 closure () # 300 \u4f8b\u4e09\uff1a \u51fd\u6570 maker \u4e2d\u5b9a\u4e49\u4e86\u51fd\u6570 action \uff0c action \u5f15\u7528\u4e86 maker \u5d4c\u5957\u4f5c\u7528\u57df\u5185\u7684\u53d8\u91cf k \uff0c\u5e76\u4e14\uff0c maker \u5c06\u51fd\u6570 action \u4f5c\u4e3a\u8fd4\u56de\u5bf9\u8c61\u8fdb\u884c\u8fd4\u56de\u3002 \u8fd9\u6837\uff0c\u6211\u4eec\u901a\u8fc7\u6267\u884c f = maker(2) \uff0c f \u83b7\u53d6\u4e86\u8fd4\u56de\u5bf9\u8c61 action \uff0c\u867d\u7136\u6b64\u65f6 maker \u51fd\u6570\u4ee5\u53ca\u7ed3\u675f\u9000\u51fa\u4e86\uff0c\u4f46\u5bf9\u8c61 f \u4ecd\u7136\u8bb0\u4f4f\u4e86\u51fd\u6570 maker \u5d4c\u5957\u4f5c\u7528\u57df\u5185\u7684\u53d8\u91cf k \u548c n \uff0c\u5e76\u5728\u6267\u884c f(3) \u65f6\uff0c\u5c06 x=3 \u4ee5\u53ca\u4e4b\u524d\u8bb0\u4f4f\u7684 k \u548c n \uff0c\u4e00\u5e76\u4f20\u5165 action() \uff0c\u8ba1\u7b97\u5e76\u8fd4\u56de x + n + k \u503c\u3002 make \u4e5f\u79f0\u4e3a**\u5de5\u5382\u51fd\u6570**\u3002 def maker ( n ): k = 8 def action ( x ): return x + n + k return action f = maker ( 2 ) print ( f ( 3 )) # 13 print ( f ( 4 )) # 14 print ( f ( 5 )) # 15 \u7ed3\u5408\u524d\u97622\u4e2a\u4f8b\u5b50\u518d\u770b\u4e0a\u9762\u7684\u89e3\u91ca\uff0c\u95ed\u5305\u5c31\u662f\u5f15\u7528\u4e86\u81ea\u7531\u53d8\u91cf\u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u4fdd\u5b58\u4e86\u6267\u884c\u7684\u4e0a\u4e0b\u6587\uff0c\u53ef\u4ee5\u8131\u79bb\u539f\u672c\u7684\u4f5c\u7528\u57df\u72ec\u7acb\u5b58\u5728\u3002 \u88c5\u9970\u5668 \u00b6 \u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u5c06\u51fd\u6570\u4f5c\u4e3a\u53c2\u6570\u4f20\u7ed9\u53e6\u4e00\u4e2a\u51fd\u6570\uff0c\u51fd\u6570 my_decorator \u7684\u4f20\u5165\u53c2\u6570\u6b63\u597d\u662f\u5176\u5d4c\u5957\u51fd\u6570 myFunc \u3002 def my_decorator ( nestedFunc ): def myFunc (): print ( \"Before executing nestedFunc()\" ) nestedFunc () print ( \"After executing nestedFunc()\" ) return myFunc def nestedFunc (): print ( \"Decoration - executing nestedFunc()\" ) nestedFunc () # Decoration - executing nestedFunc() nestedFunc = my_decorator ( nestedFunc ) nestedFunc () # Before executing nestedFunc() # Decoration - executing nestedFunc() # After executing nestedFunc() \u88c5\u9970\u5668\u53ea\u662f\u4e2a\u65b9\u6cd5\uff0c\u4f7f\u7528\u65f6\u7528\u4e86 @ \u8bed\u6cd5\u3002 @ \u8bed\u6cd5\u53ea\u662f\u5c06\u51fd\u6570 nestedFunc \u4f20\u5165\u88c5\u9970\u5668\u51fd\u6570 my_decorator \u3002 @my_decorator \u662f nestedFunc = my_decorator(nestedFunc) \u7684\u5feb\u6377\u8868\u8fbe\u65b9\u5f0f\uff0c @my_decorator def nestedFunc (): print ( \"New added to decoration - executing nestedFunc()\" ) nestedFunc () # Before executing nestedFunc() # New added to decoration - executing nestedFunc() # After executing nestedFunc() print ( nestedFunc . __name__ ) # myFunc \u4f46\u4e0a\u4f8b\u6700\u540e\u7684\u8f93\u51fa\u4e0d\u662f\u6211\u4eec\u60f3\u8981\u7684\uff0c\u6211\u4eec\u5e0c\u671b\u8f93\u51fa nestedFunc \uff0c\u4f46\u5374\u88ab myFunc \u66ff\u4ee3\u4e86\uff0c\u5b83\u91cd\u5199\u4e86\u6211\u4eec\u51fd\u6570\u7684\u540d\u5b57\u548c\u6ce8\u91ca\u6587\u6863(docstring)\u3002 \u4e0b\u9762\u4f7f\u7528 functools.wraps \u6765\u4fee\u6b63\u4e0a\u9762\u7684\u95ee\u9898\u3002 from functools import wraps def my_decorator ( nestedFunc ): @wraps ( nestedFunc ) def myFunc (): print ( \"Before executing nestedFunc()\" ) nestedFunc () print ( \"After executing nestedFunc()\" ) return myFunc def nestedFunc (): print ( \"Decoration - executing nestedFunc()\" ) @my_decorator def nestedFunc (): print ( \"New added to decoration - executing nestedFunc()\" ) nestedFunc () # Before executing nestedFunc() # New added to decoration - executing nestedFunc() # After executing nestedFunc() print ( nestedFunc . __name__ ) # nestedFunc \u4e0b\u9762\u662f\u88c5\u9970\u5668\u7684\u84dd\u672c\u89c4\u8303\u3002 from functools import wraps def decorator_name ( f ): @wraps ( f ) def decorated ( * args , ** kwargs ): if not can_run : return \"Function will not run\" return f ( * args , ** kwargs ) return decorated @decorator_name def func (): return ( \"Function is running\" ) can_run = True print ( func ()) # Output: Function is running can_run = False print ( func ()) # Output: Function will not run \u4e0b\u9762\u8fd8\u662f\u4e00\u4e2a\u88c5\u9970\u5668\u7684\u4f8b\u5b50\u3002\u628a\u4e0b\u9762\u7684\u4ee3\u7801\u6bb5\u4fdd\u5b58\u5230\u6587\u4ef6 test.py \u3002 registry = [] def register ( func ): print ( f 'running register { func } ' ) registry . append ( func ) return func @register def f1 (): print ( 'running f1()' ) @register def f2 (): print ( 'running f2()' ) def f3 (): print ( 'running f3()' ) def main (): print ( 'runnning main()' ) print ( f 'registry--> { registry } ' ) f1 () f2 () f3 () if __name__ == '__main__' : main () \u6267\u884c\u4e0a\u8ff0\u4ee3\u7801\u6bb5 python3 test.py \uff0c\u5f97\u5230\u4e0b\u9762\u7684\u7ed3\u679c\u3002 running register < function f1 at 0x7f70847bec80 > running register < function f2 at 0x7f70705aa9d8 > runnning main () registry --> [ < function f1 at 0x7f70847bec80 > , < function f2 at 0x7f70705aa9d8 > ] running f1 () running f2 () running f3 () register \u5728\u6a21\u5757\u4e2d\u5176\u4ed6\u51fd\u6570\u4e4b\u524d\u8fd0\u884c\uff08\u4e24\u6b21\uff09\u3002\u8c03\u7528 register \u65f6\uff0c\u4f20\u7ed9\u5b83\u7684\u53c2\u6570\u662f\u88ab\u88c5\u9970\u7684\u51fd\u6570\uff0c\u4f8b\u5982 function f1 at 0x7f70847bec80> \u3002\u52a0\u8f7d\u6a21\u5757\u540e\uff0c registry \u4e2d\u6709\u4e24\u4e2a\u88ab\u88c5\u9970\u51fd\u6570\u7684\u5f15\u7528\uff1a f1 \u548c f2 \u3002\u8fd9\u4e24\u4e2a\u51fd\u6570\uff0c\u4ee5\u53ca f3 \uff0c\u53ea\u5728 main \u660e\u786e\u8c03\u7528\u5b83\u4eec\u65f6\u624d\u6267\u884c\u3002 \u7531\u6b64\u5f97\uff0c\u51fd\u6570\u88c5\u9970\u5668\u5728\u5bfc\u5165\u6a21\u5757\u65f6\u7acb\u5373\u6267\u884c\uff0c\u800c\u88ab\u88c5\u9970\u7684\u51fd\u6570\u53ea\u5728\u660e\u786e\u8c03\u7528\u65f6\u8fd0\u884c\uff0c\u5373Python\u4e2d\u63d0\u5230\u7684**\u5bfc\u5165\u65f6**\u548c**\u8fd0\u884c\u65f6**\u4e4b\u95f4\u7684\u533a\u522b\u3002 \u4e0a\u9762\u4f8b\u5b50\u4e2d\u88c5\u9970\u5668\u51fd\u6570\u4e0e\u88ab\u88c5\u9970\u7684\u51fd\u6570\u5728\u540c\u4e00\u4e2a\u6a21\u5757\u4e2d\u5b9a\u4e49\u3002\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u88c5\u9970\u5668\u901a\u5e38\u5728\u4e00\u4e2a\u6a21\u5757\u4e2d\u5b9a\u4e49\uff0c\u7136\u540e\u5e94\u7528\u5230\u5176\u4ed6\u6a21\u5757\u4e2d\u7684\u51fd\u6570\u4e0a\u3002 \u4e0a\u9762\u4f8b\u5b50\u4e2d register \u88c5\u9970\u5668\u8fd4\u56de\u7684\u51fd\u6570\u4e0e\u901a\u8fc7\u53c2\u6570\u4f20\u5165\u7684\u76f8\u540c\u3002\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u5927\u591a\u6570\u88c5\u9970\u5668\u4f1a\u5728\u5185\u90e8\u5b9a\u4e49\u4e00\u4e2a\u51fd\u6570\uff0c\u7136\u540e\u5c06\u5176\u8fd4\u56de\u3002","title":"Python\u5185\u7f6e\u51fd\u6570\u53ca\u6587\u4ef6"},{"location":"python/Foundation/ch03/#python","text":"","title":"Python\u5185\u7f6e\u51fd\u6570\u53ca\u6587\u4ef6"},{"location":"python/Foundation/ch03/#1-lambda","text":"\u533f\u540d\u51fd\u6570\u662f\u4e00\u79cd\u901a\u8fc7\u5355\u4e2a\u8bed\u53e5\u751f\u6210\u51fd\u6570\u7684\u65b9\u5f0f\uff0c\u5176\u7ed3\u679c\u662f\u8fd4\u56de\u503c\u3002\u533f\u540d\u51fd\u6570\u4f7f\u7528lambda\u5173\u952e\u5b57\u5b9a\u4e49\uff0c\u8be5\u5173\u952e\u5b57\u4ec5\u8868\u8fbe\u201c\u6211\u4eec\u58f0\u660e\u4e00\u4e2a\u533f\u540d\u51fd\u6570\u201d\u7684\u610f\u601d\u3002 lambda \u51fd\u6570\u53ef\u4ee5\u63a5\u6536\u4efb\u610f\u591a\u4e2a\u53c2\u6570 (\u5305\u62ec\u53ef\u9009\u53c2\u6570) \u5e76\u4e14\u8fd4\u56de\u5355\u4e2a\u8868\u8fbe\u5f0f\u7684\u503c\u3002 \u8bed\u6cd5\u683c\u5f0f\uff1a lambda arg1,arg2,arg3\u2026 :<\u8868\u8fbe\u5f0f> f = lambda x , y : x * y print ( f ( 2 , 3 )) # 6 f = [ lambda a : a * 2 , lambda b : b * 3 ] print ( f [ 0 ]( 5 )) # \u6267\u884cf\u5217\u8868\u7b2c\u4e00\u4e2a\u5143\u7d20 # 10 print ( f [ 1 ]( 5 )) # \u6267\u884cf\u5143\u7d20\u7b2c\u4e8c\u4e2a\u5143\u7d20 # 15 print ( f [ 0 , 1 ]( 5 , 5 )) # TypeError: list indices must be integers or slices, not tuple \u793a\u4f8b1\uff1a def short_func1 ( x ): return x * 2 short_func2 = lambda x : x * 2 print ( short_func1 ( 5 )) # 10 print ( short_func2 ( 5 )) # 10 \u793a\u4f8b2\uff1a def apply_to_list ( some_list , f ): return [ f ( x ) for x in some_list ] ints = [ 4 , 0 , 1 , 5 , 6 ] result5 = apply_to_list ( ints , lambda x : x * 2 ) print ( result5 ) # [8, 0, 2, 10, 12] lambda: None \u51fd\u6570\u6ca1\u6709\u8f93\u5165\u53c2\u6570\uff0c\u8f93\u51fa\u662fNone\u3002 print ( lambda : None ) # at 0x7fa5c4097670> lambda **kwargs: 1 \u8f93\u5165\u662f\u4efb\u610f\u952e\u503c\u5bf9\u53c2\u6570\uff0c\u8f93\u51fa\u662f1\u3002 print ( lambda ** kwargs : 1 ) # at 0x7fa5c4097670>","title":"1. \u533f\u540d\uff08Lambda\uff09\u51fd\u6570"},{"location":"python/Foundation/ch03/#2-enumerate","text":"\u5f53\u9700\u8981\u5bf9\u6570\u636e\u5efa\u7acb\u7d22\u5f15\u65f6\uff0c\u4e00\u79cd\u6709\u6548\u7684\u6a21\u5f0f\u5c31\u662f\u4f7f\u7528enumerate\u6784\u9020\u4e00\u4e2a\u5b57\u5178\uff0c\u5c06\u5e8f\u5217\u503c\uff08\u5047\u8bbe\u662f\u552f\u4e00\u7684\uff09\u6620\u5c04\u5230\u7d22\u5f15\u4f4d\u7f6e\u4e0a\u3002 seasons = [ 'Spring' , 'Summer' , 'Fall' , 'Winter' ] print ( list ( enumerate ( seasons ))) # [(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')] \u5bf9\u6bd4\u4e0b\u97622\u4e2a\u5faa\u73af a_list = [ 'foo' , 'bar' , 'baz' ] mapping = {} for i , v in enumerate ( a_list ): # enumerate\u751f\u6210\u7d22\u5f15\u503ci\u548c\u5e8f\u5217\u503cv mapping [ v ] = i print ( mapping ) # {'foo': 0, 'bar': 1, 'baz': 2} i = 0 mapping = {} for v in a_list : print ( i , a_list [ i ]) mapping [ v ] = i # \u53ef\u4ee5\u628ai\u548cv\u4e92\u6362 i += 1 print ( mapping ) # {'foo': 0, 'bar': 1, 'baz': 2} \u5229\u7528 enumerate() \u6279\u91cf\u4fee\u6539\u5217\u8868\u5185\u7684\u5143\u7d20 a_list = [ '01' , '02' , '03' ] unit_element = '1' for i , element in enumerate ( a_list ): a_list [ i ] = unit_element + element print ( a_list ) # ['101', '102', '103'] sorted\u51fd\u6570\u8fd4\u56de\u4e00\u4e2a\u6839\u636e\u4efb\u610f\u5e8f\u5217\u4e2d\u7684\u5143\u7d20\u65b0\u5efa\u7684\u5df2\u6392\u5e8f\u5217\u8868\u3002sorted\u51fd\u6570\u63a5\u53d7\u7684\u53c2\u6570\u4e0e\u5217\u8868\u7684sort\u65b9\u6cd5\u4e00\u81f4\u3002 y = sorted ([ 7 , 1 , 2 , 6 , 0 , 3 , 2 ]) print ( y ) # [0, 1, 2, 2, 3, 6, 7] \u7ed3\u679c\u5df2\u6392\u5e8f z = sorted ( 'Hello World' ) print ( z ) # [' ', 'H', 'W', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r'] zip\u5c06\u5217\u8868\u3001\u5143\u7ec4\u6216\u5176\u4ed6\u5e8f\u5217\u7684\u5143\u7d20\u914d\u5bf9\uff0c\u65b0\u5efa\u4e00\u4e2a\u5143\u7ec4\u6784\u6210\u7684\u5217\u8868\u3002 seq1 = [ 'foo' , 'bar' , 'baz' ] seq2 = [ 'one' , 'two' , 'three' ] seq3 = [ False , True ] zipped = zip ( seq1 , seq2 ) print ( list ( zipped )) # [('foo', 'one'), ('bar', 'two'), ('baz', 'three')] zipped = zip ( seq1 , seq2 , seq3 ) print ( list ( zipped )) # [('foo', 'one', False), ('bar', 'two', True)] for i , ( a , b ) in enumerate ( zip ( seq1 , seq2 )): print ( ' {0} : {1} , {2} ' . format ( i , a , b )) # \u65b9\u6cd51 {0}\u5217\u8868\u5143\u7d20\u7684\u7d22\u5f15, {1}\u5143\u7ec4\u4e2d\u7b2c\u4e00\u4e2a\u503c, {2}\u5143\u7ec4\u4e2d\u7b2c\u4e8c\u4e2a\u503c print ( f ' { i } : { a } , { b } ' ) # \u65b9\u6cd52 # 0: foo, one # 1: bar, two # 2: baz, three \u7ed9\u5b9a\u4e00\u4e2a\u5df2\u201c\u914d\u5bf9\u201d\u7684\u5e8f\u5217\u65f6\uff0czip\u51fd\u6570\u53ef\u4ee5\u53bb\u201c\u62c6\u5206\u201d\u5e8f\u5217\u3002\u8fd9\u79cd\u65b9\u5f0f\u7684\u53e6\u4e00\u79cd\u601d\u8def\u5c31\u662f\u5c06\u884c\u7684\u5217\u8868\u8f6c\u6362\u4e3a\u5217\u7684\u5217\u8868\u3002\u53c2\u8003Python\u7684 Unpacking pitchers = [( 'Jack' , 'Ma' ), ( 'Tom' , 'Li' ), ( 'Jimmy' , 'Zhang' )] first_names , last_names = zip ( * pitchers ) print ( first_names ) # ('Jack', 'Tom', 'Jimmy') print ( last_names ) # ('Ma', 'Li', 'Zhang') reversed\u51fd\u6570\u5c06\u5e8f\u5217\u7684\u5143\u7d20\u5012\u5e8f\u6392\u5217 print ( list ( reversed ( range ( 10 )))) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]","title":"2. \u5185\u7f6e\u5e8f\u5217\u51fd\u6570enumerate"},{"location":"python/Foundation/ch03/#3","text":"\u63a8\u5bfc\u5f0fcomprehensions\uff08\u53c8\u79f0\u89e3\u6790\u5f0f\uff09\uff0c\u662fPython\u7684\u4e00\u79cd\u7279\u6027\u3002\u4f7f\u7528\u63a8\u5bfc\u5f0f\u53ef\u4ee5\u5feb\u901f\u751f\u6210\u5217\u8868\u3001\u5143\u7ec4\u3001\u96c6\u5408\u3001\u5b57\u5178\u7c7b\u578b\u7684\u6570\u636e\u3002\u63a8\u5bfc\u5f0f\u53c8\u5206\u4e3a\u5217\u8868\u63a8\u5bfc\u5f0f\u3001\u5143\u7ec4\u63a8\u5bfc\u5f0f\u3001\u96c6\u5408\u63a8\u5bfc\u5f0f\u3001\u5b57\u5178\u63a8\u5bfc\u5f0f\u3002","title":"3. \u5217\u8868\u3001\u96c6\u5408\u548c\u5b57\u5178\u7684\u63a8\u5bfc\u5f0f"},{"location":"python/Foundation/ch03/#list-comprehension","text":"\u5217\u8868\u63a8\u5bfc\u5f0f(list comprehension)\u5141\u8bb8\u4f60\u8fc7\u6ee4\u4e00\u4e2a\u5bb9\u5668\u7684\u5143\u7d20\uff0c\u7528\u4e00\u79cd\u7b80\u660e\u7684\u8868\u8fbe\u5f0f\u8f6c\u6362\u4f20\u9012\u7ed9\u8fc7\u6ee4\u5668\u7684\u5143\u7d20\uff0c\u4ece\u800c\u751f\u6210\u4e00\u4e2a\u65b0\u7684\u5217\u8868\u3002 \u5217\u8868\u63a8\u5bfc\u5f0f\u7684\u57fa\u672c\u5f62\u5f0f\u4e3a\uff1a[expr for val in collection if condition]\uff0c\u6761\u4ef6if-condition\u4e0d\u662f\u5fc5\u987b\u7684\uff0c\u53ef\u4ee5\u53ea\u4fdd\u7559\u8868\u8fbe\u5f0f\u3002\u5217\u8868\u63a8\u5bfc\u5f0f\u4e0e\u4e0b\u9762\u7684for\u5faa\u73af\u662f\u7b49\u4ef7\u7684\uff1a result = [] for val in collection : if condition : result . append ( expr ) \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a data = [] for i in range ( - 5 , 5 ): if i >= - 1 : data . append ( i ** 2 ) print ( data ) # [1, 0, 1, 4, 9, 16] data = [ i ** 2 for i in range ( - 5 , 5 ) if i >= - 1 ] print ( data ) # [1, 0, 1, 4, 9, 16] \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u4f7f\u7528for\u53bb\u904d\u5386\u4e00\u4e2a\u53ef\u8fed\u4ee3\u7684\u5217\u8868\u3002 data = [] fruit = [ 'pomegranate' , 'cherry' , 'apricot' , 'date' , 'Apple' , 'lemon' , 'kiwi' , 'ORANGE' , 'lime' , 'Watermelon' , 'guava' , 'papaya' , 'FIG' , 'pear' , 'banana' , 'Tamarind' , 'persimmon' , 'elderberry' , 'peach' , 'BLUEberry' , 'lychee' , 'grape' ] data = [ x . upper () if x . startswith ( 'p' ) else x . title () for x in fruit ] print ( data ) # ['POMEGRANATE', 'Cherry', 'Apricot', 'Date', 'Apple', 'Lemon', 'Kiwi', 'Orange', 'Lime', 'Watermelon', 'Guava', 'PAPAYA', 'Fig', 'PEAR', 'Banana', 'Tamarind', 'PERSIMMON', 'Elderberry', 'PEACH', 'Blueberry', 'Lychee', 'Grape']","title":"\u5217\u8868\u63a8\u5bfc\u5f0f(list comprehension)"},{"location":"python/Foundation/ch03/#_1","text":"\u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u7528\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u4ee3\u66ff2\u5c42for\u5faa\u73af\u3002 data = [] for i in range ( 1 , 3 ): if i >= 0 : for j in range ( 1 , 3 ): data . append (( i , j )) print ( data ) # [(1, 1), (1, 2), (2, 1), (2, 2)] data = [( i , j ) for i in range ( 1 , 3 ) if i >= - 1 for j in range ( 1 , 3 )] print ( data ) # [(1, 1), (1, 2), (2, 1), (2, 2)] \u518d\u4e3e\u4e00\u4e2a\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u7684\u4f8b\u5b50\u3002 all_data = [ [ 'John' , 'Emily' , 'Michael' , 'Lee' , 'Steven' ], [ 'Maria' , 'Juan' , 'Javier' , 'Natalia' , 'Pilar' ], ] names_of_interest = [] for names in all_data : enough_es = [ name for name in names if name . count ( 'e' ) >= 2 ] names_of_interest . extend ( enough_es ) print ( names_of_interest ) # ['Lee', 'Steven'] result = [ name for names in all_data for name in names if name . count ( 'e' ) >= 2 ] print ( result ) # ['Lee', 'Steven'] \u7528\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u5c06\u77e9\u9635\u6241\u5e73\u5316\u3002 \u8003\u8651\u4e0b\u9762\u8fd9\u4e2a3x4\u7684\u77e9\u9635\uff0c\u5b83\u75313\u4e2a\u957f\u5ea6\u4e3a4\u7684\u5217\u8868\u7ec4\u6210\u3002\u4e0b\u9762\u4f8b\u5b50\u5bf9\u6bd4\u4e86\u7528\u4f20\u7edffor\u5faa\u73af\u5c06\u77e9\u9635\u6241\u5e73\u5316\uff0c\u548c\u7528\u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f\u5c06\u77e9\u9635\u6241\u5e73\u5316\u3002\u5e76\u4e14\u901a\u8fc7\u5217\u8868\u63a8\u5bfc\u5f0f\u4e2d\u7684\u5217\u8868\u63a8\u5bfc\u5f0f\u5c06\u6241\u5e73\u77e9\u9635\u8fd8\u539f\u4e3a3x4\u77e9\u9635\u3002 matrix = [ [ 1 , 2 , 3 , 4 ], [ 5 , 6 , 7 , 8 ], [ 9 , 10 , 11 , 12 ], ] flattened = [] # \u4f20\u7edffor\u5faa\u73af\u5d4c\u5957 for m in matrix : for x in m : flattened . append ( x ) print ( flattened ) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] # \u5d4c\u5957\u5217\u8868\u63a8\u5bfc\u5f0f flattened = [ x for m in matrix for x in m ] print ( flattened ) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] # \u5217\u8868\u63a8\u5bfc\u5f0f\u4e2d\u7684\u5217\u8868\u63a8\u5bfc\u5f0f z = [[ x for x in m ] for m in matrix ] print ( z ) # [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]","title":"\u5957\u5217\u8868\u63a8\u5bfc\u5f0f"},{"location":"python/Foundation/ch03/#_2","text":"\u4e0b\u9762\u7684\u4f8b\u5b50\u751f\u6210\u4e00\u4e2a\u5305\u542b\u6570\u5b571~5\u7684\u5143\u7ec4\u3002\u4ece\u7ed3\u679c\u53ef\u4ee5\u770b\u5230\uff0c\u5143\u7ec4\u63a8\u5bfc\u5f0f\u751f\u6210\u7684\u7ed3\u679c\u5e76\u4e0d\u662f\u4e00\u4e2a\u5143\u7ec4\uff0c\u800c\u662f\u4e00\u4e2a\u751f\u6210\u5668\u5bf9\u8c61\uff0c\u9700\u8981\u901a\u8fc7tuple()\u51fd\u6570\uff0c\u5c06\u751f\u6210\u5668\u5bf9\u8c61\u8f6c\u6362\u6210\u5143\u7ec4\u3002 data = ( x for x in range ( 5 )) print ( data ) # at 0x7f87217a8e40> print ( type ( data )) # print ( tuple ( data )) # (0, 1, 2, 3, 4)","title":"\u5143\u7ec4\u63a8\u5bfc\u5f0f"},{"location":"python/Foundation/ch03/#_3","text":"\u4e0b\u9762\u662f\u4e00\u4e2a\u7b80\u5355\u7684\u96c6\u5408\u63a8\u5bfc\u5f0f\u4f8b\u5b50\u3002 data = { x ** 2 for x in range ( 5 )} print ( data ) # {0, 1, 4, 9, 16} print ( type ( data )) # \u96c6\u5408\u8981\u4fdd\u8bc1\u5143\u7d20\u5fc5\u987b\u662f\u552f\u4e00\u7684\u3002 data = ( 1 , 1 , 2 , 2 , 3 , 3 , 4 , 5 , 6 ) newset = { x ** 2 for x in data } print ( newset ) # {1, 4, 36, 9, 16, 25} print ( type ( newset ) # ","title":"\u96c6\u5408\u63a8\u5bfc\u5f0f"},{"location":"python/Foundation/ch03/#_4","text":"\u5b57\u5178\u63a8\u5bfc\u5f0f: dict_comp = {key-expr : value-expr for value in collection if condition} \u5b57\u5178\u63a8\u5bfc\u5f0f\u7684\u7b80\u5355\u793a\u4f8b\uff1a strings = [ 'a' , 'as' , 'bat' , 'car' , 'dove' , 'python' ] loc_mapping = { index : val for index , val in enumerate ( strings )} print ( loc_mapping ) # {0: 'a', 1: 'as', 2: 'bat', 3: 'car', 4: 'dove', 5: 'python'} # \u4ea4\u6362\u952e\u548c\u503c loc_mapping = { index : val for val , index in enumerate ( strings )} print ( loc_mapping ) # {'a': 0, 'as': 1, 'bat': 2, 'car': 3, 'dove': 4, 'python': 5}","title":"\u5b57\u5178\u63a8\u5bfc\u5f0f"},{"location":"python/Foundation/ch03/#4","text":"\u5982\u679cPython\u8fbe\u5230\u51fd\u6570\u7684\u5c3e\u90e8\u65f6\u4ecd\u7136\u6ca1\u6709\u9047\u5230return\u8bed\u53e5\uff0c\u5c31\u4f1a\u81ea\u52a8\u8fd4\u56deNone\u3002 \u6bcf\u4e2a\u51fd\u6570\u90fd\u53ef\u4ee5\u6709\u4f4d\u7f6e\u53c2\u6570\u548c\u5173\u952e\u5b57\u53c2\u6570\u3002\u5173\u952e\u5b57\u53c2\u6570\u6700\u5e38\u7528\u4e8e\u6307\u5b9a\u9ed8\u8ba4\u503c\u6216\u53ef\u9009\u53c2\u6570\u3002\u5173\u952e\u5b57\u53c2\u6570\u5fc5\u987b\u8ddf\u5728\u4f4d\u7f6e\u53c2\u6570\u540e\uff0c\u53ef\u4ee5\u4f7f\u7528\u5173\u952e\u5b57\u53c2\u6570\u5411\u4f4d\u7f6e\u53c2\u6570\u4f20\u53c2\u3002 import sys def my_function1 ( x , y , z = 1.5 ): if z > 1 : return z * ( x + y ) else : return z / ( x + y ) result1 = my_function1 ( 5 , 6 , z = 0.7 ) print ( result1 ) # 0.06363636363636363 result1 = my_function1 ( x = 5 , y = 6 , z = 0.7 ) print ( result1 ) # 0.06363636363636363 result1 = my_function1 ( 3.14 , 7 , 3.5 ) print ( result1 ) # 35.49 result1 = my_function1 ( 10 , 20 ) print ( result1 ) # 45.0","title":"4. \u51fd\u6570\u58f0\u660e"},{"location":"python/Foundation/ch03/#5","text":"\u51fd\u6570\u6709\u4e24\u79cd\u8fde\u63a5\u53d8\u91cf\u7684\u65b9\u5f0f\uff1a\u5168\u5c40\u3001\u672c\u5730\u3002 def func1 (): list1 = [] # \u672c\u5730\u53d8\u91cf for i in range ( 5 ): list1 . append ( i ) print ( list1 ) func1 () # [0, 1, 2, 3, 4] list2 = [] # \u5168\u5c40\u53d8\u91cf def func2 (): global list2 # \u5168\u5c40\u53d8\u91cf for i in range ( 5 ): list2 . append ( i ) print ( list2 ) func2 () # [0, 1, 2, 3, 4] \u6570\u636e\u6e05\u6d17\u793a\u4f8b states = [ ' Alabama' , 'Georgia!' , 'georgia' , 'Georgia' , 'FlOrIda' , 'south carolina##' , 'West virginia? ' ] # \u65b9\u6cd51 import re def clean_string1 ( strings ): result2 = [] for value in strings : value = value . strip () value = re . sub ( '[! #? ]' , '' , value ) value = value . title () result2 . append ( value ) return result2 print ( clean_string1 (( states ))) # ['Alabama', 'Georgia', 'Georgia', 'Georgia', 'Florida', 'Southcarolina', 'Westvirginia'] # \u65b9\u6cd52 def remove_punctuaion ( value ): return re . sub ( '[! #? ]' , '' , value ) clean_ops = [ str . strip , remove_punctuaion , str . title ] def clean_string2 ( strings , ops ): result3 = [] for value in strings : for function in ops : value = function ( value ) result3 . append ( value ) return result3 result4 = clean_string2 ( states , clean_ops ) print ( result4 ) # ['Alabama', 'Georgia', 'Georgia', 'Georgia', 'Florida', 'Southcarolina', 'Westvirginia'] # \u53ef\u4ee5\u5c06\u51fd\u6570\u4f5c\u4e3a\u4e00\u4e2a\u53c2\u6570\u4f20\u7ed9\u5176\u4ed6\u7684\u51fd\u6570\u3002 for x in map ( remove_punctuaion , states ): print ( x ) # Alabama # Georgia # georgia # Georgia # FlOrIda # southcarolina # Westvirginia","title":"5. \u547d\u540d\u7a7a\u95f4\u3001\u4f5c\u7528\u57df\u548c\u672c\u5730\u51fd\u6570"},{"location":"python/Foundation/ch03/#6","text":"\u67ef\u91cc\u5316\u662f\u8ba1\u7b97\u673a\u79d1\u5b66\u672f\u8bed\uff08\u4ee5\u6570\u5b66\u5bb6Haskell Curry\u547d\u540d\uff09\uff0c\u5b83\u8868\u793a\u901a\u8fc7\u90e8\u5206\u53c2\u6570\u5e94\u7528\u7684\u65b9\u5f0f\u4ece\u5df2\u6709\u7684\u51fd\u6570\u4e2d\u884d\u751f\u51fa\u65b0\u7684\u51fd\u6570\u3002\u67ef\u91cc\u5316\u662f\u4e00\u79cd\u5c06\u591a\u53c2\u6570\u51fd\u6570\u8f6c\u5316\u4e3a\u5355\u53c2\u6570\u9ad8\u9636\u51fd\u6570\u7684\u6280\u672f\uff0c\u5982\u679c\u4f60\u56fa\u5b9a\u67d0\u4e9b\u53c2\u6570\uff0c\u4f60\u5c06\u5f97\u5230\u63a5\u53d7\u4f59\u4e0b\u53c2\u6570\u7684\u4e00\u4e2a\u51fd\u6570\u3002 \u5b9a\u4e49\u4e00\uff1a \u67ef\u91cc\u5316\uff1a\u4e00\u4e2a\u51fd\u6570\u4e2d\u6709\u4e2a\u591a\u4e2a\u53c2\u6570\uff0c\u60f3\u56fa\u5b9a\u5176\u4e2d\u67d0\u4e2a\u6216\u8005\u51e0\u4e2a\u53c2\u6570\u7684\u503c\uff0c\u800c\u53ea\u63a5\u53d7\u53e6\u5916\u51e0\u4e2a\u8fd8\u672a\u56fa\u5b9a\u7684\u53c2\u6570\uff0c\u8fd9\u6837\u51fd\u6570\u6f14\u53d8\u6210\u65b0\u7684\u51fd\u6570\u3002 \u5b9a\u4e49\u4e8c\uff1a \u51fd\u6570\u67ef\u91cc\u5316\uff08currying\uff09\u53c8\u79f0\u90e8\u5206\u6c42\u503c\u3002\u4e00\u4e2a currying \u7684\u51fd\u6570\u9996\u5148\u4f1a\u63a5\u53d7\u4e00\u4e9b\u53c2\u6570\uff0c\u63a5\u53d7\u4e86\u8fd9\u4e9b\u53c2\u6570\u4e4b\u540e\uff0c\u8be5\u51fd\u6570\u5e76\u4e0d\u4f1a\u7acb\u5373\u6c42\u503c\uff0c\u800c\u662f\u7ee7\u7eed\u8fd4\u56de\u53e6\u5916\u4e00\u4e2a\u51fd\u6570\uff0c\u521a\u624d\u4f20\u5165\u7684\u53c2\u6570\u5728\u51fd\u6570\u5f62\u6210\u7684\u95ed\u5305\u4e2d\u88ab\u4fdd\u5b58\u8d77\u6765\u3002\u5f85\u5230\u51fd\u6570\u88ab\u771f\u6b63\u9700\u8981\u6c42\u503c\u7684\u65f6\u5019\uff0c\u4e4b\u524d\u4f20\u5165\u7684\u6240\u6709\u53c2\u6570\u90fd\u4f1a\u88ab\u4e00\u6b21\u6027\u7528\u4e8e\u6c42\u503c\u3002 \u5b9a\u4e49\u4e09\uff1a \u4e00\u4e9b\u51fd\u6570\u5f0f\u8bed\u8a00\u7684\u5de5\u4f5c\u539f\u7406\u662f\u5c06\u591a\u53c2\u6570\u51fd\u6570\u8bed\u6cd5\u8f6c\u5316\u4e3a\u5355\u53c2\u6570\u51fd\u6570\u96c6\u5408\uff0c\u8fd9\u4e00\u8fc7\u7a0b\u79f0\u4e3a\u67ef\u91cc\u5316\uff0c\u5b83\u662f\u4ee5\u903b\u8f91\u5b66\u5bb6Haskell Curry\u7684\u540d\u5b57\u547d\u540d\u7684\u3002Haskell Curry\u4ece\u65e9\u671f\u6982\u5ff5\u4e2d\u53d1\u5c55\u51fa\u4e86\u8be5\u7406\u8bba\u3002\u5176\u5f62\u5f0f\u76f8\u5f53\u4e8e\u5c06z=f(x, y)\u8f6c\u6362\u6210z=f(x)(y)\u7684\u5f62\u5f0f\uff0c\u539f\u51fd\u6570\u7531\u4e24\u4e2a\u53c2\u6570\uff0c\u73b0\u5728\u53d8\u4e3a\u4e24\u4e2a\u63a5\u53d7\u5355\u53c2\u6570\u7684\u51fd\u6570\uff0c \u793a\u4f8b1\uff1a\u67ef\u91cc\u5316\u7684\u8fc7\u7a0b\u5c31\u662f\u628a\u539f\u6765\u5e26\u4e24\u4e2a\u53c2\u6570\u7684\u51fd\u6570add(x, y)\uff0c\u53d8\u6210\u4e86\u4e00\u4e2a\u5d4c\u5957\u51fd\u6570\uff0c\u5728add_currying\u51fd\u6570\u5185\uff0c\u53c8\u5b9a\u4e49\u4e86\u4e00\u4e2a_add\u51fd\u6570\uff0c\u5e76\u4e14_add\u51fd\u6570\u53c8\u5f15\u7528\u4e86\u5916\u90e8\u51fd\u6570add_currying\u7684\u53d8\u91cfx\uff0c\u8fd9\u5c31\u662f\u4e00\u4e2a\u95ed\u5305\u3002 \u95ed\u5305\uff0c\u4e00\u53e5\u8bdd\u8bf4\u5c31\u662f\u5728\u51fd\u6570\u4e2d\u518d\u5d4c\u5957\u4e00\u4e2a\u51fd\u6570\uff0c\u5e76\u4e14\u5f15\u7528\u5916\u90e8\u51fd\u6570\u7684\u53d8\u91cf\u3002 # \u666e\u901a\u5199\u6cd5 def add ( x , y ): return x + y print ( add ( 1 , 2 )) # 3 # \u67ef\u91cc\u5316\u5199\u6cd5 def add_currying ( x ): def _add ( y ): return x + y return _add print ( add_currying ( 1 )( 2 )) # 3 \u793a\u4f8b2\uff0c\u901a\u8fc7\u56fa\u5b9a\u5176\u4e2d\u7684\u7b2c\u4e8c\u4e2a\u53c2\u6570\u4e0d\u53d8\u6765\u5b9e\u73b0\u67ef\u91cc\u5316\u3002 def add2 ( a , b ): def add1 ( a , b , c ): return a + b + c return add1 ( a , 666 , b ) result6 = add2 ( 12 , 13 ) print ( result6 ) # 691 result6 = add2 ( 12 , 555 , 13 ) # TypeError: add2() takes 2 positional arguments but 3 were given \u793a\u4f8b3\uff0c\u901a\u8fc7functools\u63d0\u4f9b\u7684\u504f\u51fd\u6570\u6765\u5b9e\u73b0\u67ef\u91cc\u5316\u3002 from functools import partial def add1 ( a , b , c ): return a + b + c add3 = partial ( add1 , b = 666 ) result7 = add3 ( a = 12 , c = 13 ) print ( result7 ) # 691 \u793a\u4f8b4\uff0c\u901a\u8fc7lambda\u8868\u8fbe\u5f0f\u6765\u5b9e\u73b0\u67ef\u91cc\u5316\u3002 def add1 ( a , b , c ): return a + b + c add4 = lambda x , y : add1 ( x , 666 , y ) result8 = add4 ( 12 , 13 ) print ( result8 ) # 691 \u793a\u4f8b5\uff0c\u901a\u8fc7python\u7684\u88c5\u9970\u5668\u6765\u5b9e\u73b0\u67ef\u91cc\u5316 def add1 ( a , b , c ): return a + b + c def currying_add ( func ): def wrapper ( a , c , b = 666 ): return func ( a , b , c ) return wrapper result9 = currying_add ( add1 )( 12 , 13 ) print ( result9 ) # 691 \u793a\u4f8b6\uff0c\u901a\u8fc7python\u7684\u88c5\u9970\u5668\u7b26\u53f7@\u6765\u5b9e\u73b0\u67ef\u91cc\u5316 def currying_add ( func ): def wrapper ( a , c , b = 666 ): return func ( a , b , c ) return wrapper @currying_add def add5 ( a , b , c ): return a + b + c result10 = add5 ( 12 , 13 ) print ( result10 ) # 691","title":"6. \u67ef\u91cc\u5316\uff1a\u90e8\u5206\u53c2\u6570\u5e94\u7528"},{"location":"python/Foundation/ch03/#7","text":"","title":"7. \u8fed\u4ee3\u5668\u4e0e\u751f\u6210\u5668"},{"location":"python/Foundation/ch03/#_5","text":"\u8fed\u4ee3\u662fPython\u6700\u5f3a\u5927\u7684\u529f\u80fd\u4e4b\u4e00\uff0c\u662f\u8bbf\u95ee\u96c6\u5408\u5143\u7d20\u7684\u4e00\u79cd\u65b9\u5f0f\u3002\u8fed\u4ee3\u5668\u662f\u4e00\u4e2a\u53ef\u4ee5\u8bb0\u4f4f\u904d\u5386\u7684\u4f4d\u7f6e\u7684\u5bf9\u8c61\u3002 \u8fed\u4ee3\u5668\u5bf9\u8c61\u4ece\u96c6\u5408\u7684\u7b2c\u4e00\u4e2a\u5143\u7d20\u5f00\u59cb\u8bbf\u95ee\uff0c\u76f4\u5230\u6240\u6709\u7684\u5143\u7d20\u88ab\u8bbf\u95ee\u5b8c\u7ed3\u675f\u3002\u8fed\u4ee3\u5668\u53ea\u80fd\u5f80\u524d\u4e0d\u4f1a\u540e\u9000\u3002 \u8fed\u4ee3\u5668\u6709\u4e24\u4e2a\u57fa\u672c\u7684\u65b9\u6cd5\uff1aiter() \u548c next()\u3002 \u8fed\u4ee3\u5668\u793a\u4f8b\uff1a list_a = [ 1 , 2 , 3 , 4 ] it = iter ( list_a ) # \u521b\u5efa\u8fed\u4ee3\u5668\u5bf9\u8c61 print ( next ( it )) # \u8f93\u51fa\u8fed\u4ee3\u5668\u7684\u4e0b\u4e00\u4e2a\u5143\u7d20 # 1 print ( next ( it )) # \u8f93\u51fa\u8fed\u4ee3\u5668\u7684\u4e0b\u4e00\u4e2a\u5143\u7d20 # 2 \u8fed\u4ee3\u5668\u5bf9\u8c61\u53ef\u4ee5\u4f7f\u7528\u5e38\u89c4for\u8bed\u53e5\u8fdb\u884c\u904d\u5386\u3002 list_a = [ 1 , 2 , 3 , 4 ] it = iter ( list_a ) # \u521b\u5efa\u8fed\u4ee3\u5668\u5bf9\u8c61 for x in it : print ( x , end = \" \" ) print ( end = \" \\n \" ) # 1 2 3 4","title":"\u8fed\u4ee3\u5668"},{"location":"python/Foundation/ch03/#_6","text":"\u5728 Python \u4e2d\uff0c\u4f7f\u7528\u4e86 yield \u7684\u51fd\u6570\u88ab\u79f0\u4e3a\u751f\u6210\u5668\uff08generator\uff09\u3002\u8ddf\u666e\u901a\u51fd\u6570\u4e0d\u540c\u7684\u662f\uff0c\u751f\u6210\u5668\u662f\u4e00\u4e2a\u8fd4\u56de\u8fed\u4ee3\u5668\u7684\u51fd\u6570\uff0c\u53ea\u80fd\u7528\u4e8e\u8fed\u4ee3\u64cd\u4f5c\uff0c\u751f\u6210\u5668\u5c31\u662f\u4e00\u4e2a\u8fed\u4ee3\u5668\u3002 \u5728\u8c03\u7528\u751f\u6210\u5668\u8fd0\u884c\u7684\u8fc7\u7a0b\u4e2d\uff0c\u6bcf\u6b21\u9047\u5230 yield \u65f6\u51fd\u6570\u4f1a\u6682\u505c\u5e76\u4fdd\u5b58\u5f53\u524d\u6240\u6709\u7684\u8fd0\u884c\u4fe1\u606f\uff0c\u8fd4\u56de yield \u7684\u503c, \u5e76\u5728\u4e0b\u4e00\u6b21\u6267\u884c next() \u65b9\u6cd5\u65f6\u4ece\u5f53\u524d\u4f4d\u7f6e\u7ee7\u7eed\u8fd0\u884c\u3002 \u8c03\u7528\u4e00\u4e2a\u751f\u6210\u5668\u51fd\u6570\uff0c\u8fd4\u56de\u7684\u662f\u4e00\u4e2a\u8fed\u4ee3\u5668\u5bf9\u8c61\u3002 \u793a\u4f8b, \u6590\u6ce2\u90a3\u5951\u6570\u5217\uff1a def fibonacci ( n ): a , b , counter = 0 , 1 , 0 while True : if ( counter > n ): return yield a a , b = b , a + b counter += 1 f = fibonacci ( 10 ) # f \u662f\u4e00\u4e2a\u8fed\u4ee3\u5668\uff0c\u7531\u751f\u6210\u5668\u8fd4\u56de\u751f\u6210 print ( f ) # \u5b9e\u9645\u8c03\u7528\u751f\u6210\u5668\u65f6\uff0c\u4ee3\u7801\u5e76\u4e0d\u4f1a\u7acb\u5373\u6267\u884c for x in f : # \u8bf7\u6c42\u751f\u6210\u5668\u4e2d\u7684\u5143\u7d20\u65f6\uff0c\u5b83\u624d\u4f1a\u6267\u884c\u5b83\u7684\u4ee3\u7801 print ( x , end = \" \" ) print ( end = \" \\n \" ) # 0 1 1 2 3 5 8 13 21 34 55 \u751f\u6210\u5668\u8868\u8fbe\u5f0f\uff1a \u7528\u751f\u6210\u5668\u8868\u8fbe\u5f0f\u6765\u521b\u5efa\u751f\u6210\u5668\u66f4\u4e3a\u7b80\u5355\u3002\u751f\u6210\u5668\u8868\u8fbe\u5f0f\u4e0e\u5217\u8868\u3001\u5b57\u5178\u3001\u96c6\u5408\u7684\u63a8\u5bfc\u5f0f\u5f88\u7c7b\u4f3c\uff0c\u521b\u5efa\u4e00\u4e2a\u751f\u6210\u5668\u8868\u8fbe\u5f0f\uff0c\u53ea\u9700\u8981\u5c06\u5217\u8868\u63a8\u5bfc\u5f0f\u7684\u4e2d\u62ec\u53f7\u66ff\u6362\u4e3a\u5c0f\u62ec\u53f7\u5373\u53ef\u3002 gen1 = ( x ** 2 for x in range ( 100 )) print ( gen1 ) # at 0x7fd3f30c9580> \u4e0a\u9762\u7684\u4ee3\u7801\u4e0e\u4e0b\u9762\u7684\u751f\u6210\u5668\u662f\u7b49\u4ef7\u7684 def _make_gen (): for x in range ( 100 ): yield x ** 2 gen2 = _make_gen () print ( gen2 ) # \u751f\u6210\u5668\u8868\u8fbe\u5f0f\u53ef\u4ee5\u4f5c\u4e3a\u51fd\u6570\u53c2\u6570\u7528\u4e8e\u66ff\u4ee3\u5217\u8868\u63a8\u5bfc\u5f0f\u3002\u5bf9\u6bd4\u4e0b\u97622\u4e2a\u4f8b\u5b50\u3002 # \u793a\u4f8b1 result11 = sum ( x ** 2 for x in range ( 100 )) print ( result11 ) # 328350 gen1 = ( x ** 2 for x in range ( 100 )) result11 = sum ( gen1 ) print ( result11 ) # 328350 # \u793a\u4f8b2 result12 = dict (( i , i ** 2 ) for i in range ( 5 )) print ( result12 ) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} gen2 = (( i , i ** 2 ) for i in range ( 5 )) result12 = dict ( gen2 ) print ( result12 ) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}","title":"\u751f\u6210\u5668"},{"location":"python/Foundation/ch03/#itertools","text":"\u6807\u51c6\u5e93\u4e2d\u7684itertools\u6a21\u5757\u662f\u9002\u7528\u4e8e\u5927\u591a\u6570\u6570\u636e\u7b97\u6cd5\u7684\u751f\u6210\u5668\u96c6\u5408\u3002 import itertools first_letter = lambda x : x [ 0 ] names = [ 'Alan' , 'Adam' , 'Wes' , 'Will' , 'Albert' , 'Steven' ] for letter , names in itertools . groupby ( names , first_letter ): print ( letter ) print ( first_letter ) print ( letter , list ( names )) # names is generator # A # at 0x7fa598a7a0d0> # A ['Alan', 'Adam'] # W # at 0x7fa598a7a0d0> # W ['Wes', 'Will'] # A # at 0x7fa598a7a0d0> # A ['Albert'] # S # at 0x7fa598a7a0d0> # S ['Steven']","title":"\u751f\u6210\u5668\uff1aitertools\u6a21\u5757"},{"location":"python/Foundation/ch03/#8","text":"Python\u7528\u5f02\u5e38\u5bf9\u8c61(exception object)\u6765\u8868\u793a\u5f02\u5e38\u60c5\u51b5\u3002\u9047\u5230\u9519\u8bef\u540e\uff0c\u4f1a\u5f15\u53d1\u5f02\u5e38\u3002\u5982\u679c\u5f02\u5e38\u5bf9\u8c61\u5e76\u672a\u88ab\u5904\u7406\u6216\u6355\u6349\uff0c\u7a0b\u5e8f\u5c31\u4f1a\u7528\u6240\u8c13\u7684\u56de\u6eaf(traceback\uff0c \u4e00\u79cd\u9519\u8bef\u4fe1\u606f)\u7ec8\u6b62\u6267\u884c\u3002 \u5f02\u5e38\u548c\u8bed\u6cd5\u9519\u8bef\u662f\u6709\u533a\u522b\u7684\u3002 \u9519\u8bef\uff1a\u662f\u6307\u4ee3\u7801\u4e0d\u7b26\u5408\u89e3\u91ca\u5668\u6216\u8005\u7f16\u8bd1\u5668\u8bed\u6cd5\u3002 \u5f02\u5e38\uff1a\u662f\u6307\u4e0d\u5b8c\u6574\u3001\u4e0d\u5408\u6cd5\u8f93\u5165\uff0c\u6216\u8005\u8ba1\u7b97\u51fa\u73b0\u9519\u8bef\u3002 python\u91cc\u7528try...except...\u8bed\u53e5\u6765\u5904\u7406\u5f02\u5e38\u60c5\u51b5\u3002 def attempt_float ( x ): try : return float ( x ) except ( TypeError , ValueError ): return \"Type error, not numbers\" r1 = attempt_float ( '1.2256' ) print ( r1 ) # 1.2256 r1 = attempt_float ( 'friends' ) print ( r1 ) # Type error, not numbers","title":"8. \u9519\u8bef\u548c\u5f02\u5e38\u5904\u7406"},{"location":"python/Foundation/ch03/#9","text":"f=open(path, 'w')\uff0c\u4e00\u4e2a\u65b0\u7684\u6587\u4ef6\u4f1a\u5728path\u6307\u5b9a\u7684\u8def\u5f84\u88ab\u521b\u5efa\uff0c\u5e76\u5728\u540c\u4e00\u8def\u5f84\u4e0b\u8986\u76d6\u540c\u540d\u6587\u4ef6\u3002\uff08\u8bf7\u5c0f\u5fc3\uff01\uff09 f=open(path, 'x')\uff0c\u4e00\u4e2a\u65b0\u7684\u6587\u4ef6\u4f1a\u5728path\u6307\u5b9a\u7684\u8def\u5f84\u88ab\u521b\u5efa\uff0c\u5982\u679c\u7ed9\u5b9a\u8def\u5f84\u4e0b\u5df2\u7ecf\u5b58\u5728\u540c\u540d\u6587\u4ef6\u5c31\u4f1a\u521b\u5efa\u5931\u8d25\u3002 import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f = open ( path ) # \u8bfb\u53d6\u6587\u4ef6\u6bcf\u4e00\u884c\uff0c\u6587\u4ef6\u6bcf\u4e00\u884c\u4f5c\u4e3a\u5217\u8868\u4e00\u4e2a\u5143\u7d20 lines = [ x . rstrip () for x in open ( path )] # \u8f93\u51fa\u5217\u8868 print ( lines ) # \u5173\u95ed\u6587\u4ef6\u4f1a\u5c06\u8d44\u6e90\u91ca\u653e\u56de\u64cd\u4f5c\u7cfb\u7edf f . close () \u53e6\u4e00\u79cd\u66f4\u7b80\u5355\u7684\u5173\u95ed\u6587\u4ef6\u7684\u65b9\u5f0f import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f = open ( path ) # \u4f7f\u7528with\u8bed\u53e5\u8bfb\u53d6\u6587\u4ef6\uff0c\u6587\u4ef6\u4f1a\u5728with\u4ee3\u7801\u5757\u7ed3\u675f\u540e\u81ea\u52a8\u5173\u95ed\u3002 with open ( path ) as f : lines = [ x . rstrip () for x in open ( path )] # \u8f93\u51fa\uff1a\u6587\u4ef6\u6bcf\u4e00\u884c\u4f5c\u4e3a\u5217\u8868\u4e00\u4e2a\u5143\u7d20 print ( lines ) \u5728\u6253\u5f00\u6587\u4ef6\u65f6\u4f7f\u7528seek\u8bfb\u53d6\u6587\u4ef6\u5185\u5bb9\u8981\u5f53\u5fc3\u3002\u5982\u679c\u6587\u4ef6\u7684\u53e5\u67c4\u4f4d\u7f6e\u6070\u597d\u5728\u4e00\u4e2aUnicode\u7b26\u53f7\u7684\u5b57\u8282\u4e2d\u95f4\u65f6\uff0c\u540e\u7eed\u7684\u8bfb\u53d6\u4f1a\u5bfc\u81f4\u9519\u8bef\u3002 import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f = open ( path ) # \u8bfb\u53d6\u6587\u4ef6\u3002 print ( f . read ( 5 )) # \u8f93\u51fa\u524d5\u4e2a\u5b57\u7b26\u3002 read\u65b9\u6cd5\u901a\u8fc7\u8bfb\u53d6\u7684\u5b57\u8282\u6570\u6765\u63a8\u8fdb\u6587\u4ef6\u53e5\u67c4\u7684\u4f4d\u7f6e\u3002 # I Thi print ( f . tell ()) # tell\u65b9\u6cd5\u53ef\u4ee5\u7ed9\u51fa\u53e5\u67c4\u5f53\u524d\u7684\u4f4d\u7f6e # 5 print ( f . seek ( 6 )) # seek\u65b9\u6cd5\u53ef\u4ee5\u5c06\u53e5\u67c4\u4f4d\u7f6e\u6539\u53d8\u5230\u6587\u4ef6\u4e2d\u7279\u5b9a\u7684\u5b57\u8282 # 6 print ( f . read ( 1 )) # \u4ece\u7b2c7\u4e2a\u5b57\u8282\u5f00\u59cb\uff0c\u8f93\u51fa1\u4e2a\u5b57\u8282 # k # \u5173\u95ed\u6587\u4ef6\u4f1a\u5c06\u8d44\u6e90\u91ca\u653e\u56de\u64cd\u4f5c\u7cfb\u7edf f . close () \u5982\u679c\u4f7f\u7528\u4e8c\u8fdb\u5236\u65b9\u5f0f\u6253\u5f00\u6587\u4ef6\uff0c\u5219\uff1a import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path = 'file01.txt' # \u6253\u5f00\u6587\u4ef6 f2 = open ( path , 'rb' ) # \u4e8c\u8fdb\u5236\u6a21\u5f0f # \u8bfb\u53d6\u6587\u4ef6 print ( f2 . read ( 5 )) # \u7b2c\u4e00\u4e2ab\u4ee3\u8868\u4e8c\u8fdb\u5236\u683c\u5f0f # b'I Thi' print ( f2 . tell ()) # 5 print ( f2 . seek ( 6 )) # 6 print ( f2 . read ( 2 )) # \u4ece\u7b2c7\u4e2a\u5b57\u8282\u5f00\u59cb\uff0c\u8f93\u51fa2\u4e2a\u5b57\u8282 # b'k ' # \u5173\u95ed\u6587\u4ef6\u4f1a\u5c06\u8d44\u6e90\u91ca\u653e\u56de\u64cd\u4f5c\u7cfb\u7edf f2 . close () \u5c06\u672c\u6587\u5199\u5165\u6587\u4ef6\uff0c\u53ef\u4ee5\u4f7f\u7528\u6587\u4ef6\u5bf9\u8c61\u7684write\u6216wirtelines\u65b9\u6cd5\u3002 import os # \u67e5\u770b\u5f53\u524d\u8def\u5f84 os . getcwd () # '/opt/myMemo' # \u66f4\u6539\u6587\u4ef6\u8bfb\u53d6\u9ed8\u8ba4\u8def\u5f84 os . chdir ( '/opt/myMemo/python/datasets/examples' ) # \u6307\u5b9a\u6587\u4ef6\u540d path1 = 'file01.txt' path2 = 'file02.txt' # file02.txt\u662f\u4e00\u4e2a\u7a7a\u6587\u4ef6 with open ( path2 , 'r+' , encoding = 'utf-8' ) as f : f . writelines ( x for x in open ( path1 , 'r' , encoding = 'utf-8' ) if len ( x ) > 1 ) # \u628afile01.txt\u7684\u5185\u5bb9\u5199\u5165file02.txt lines = f . readlines () print ( lines )","title":"9. \u6587\u4ef6\u4e0e\u64cd\u4f5c\u7cfb\u7edf"},{"location":"python/Foundation/ch03/#10","text":"","title":"10. \u88c5\u9970\u5668"},{"location":"python/Foundation/ch03/#_7","text":"\u7ef4\u57fa\u767e\u79d1\u4e2d\u7684\u89e3\u91ca\uff1a \u95ed\u5305\uff08Closure\uff09 \uff0c\u53c8\u79f0\u8bcd\u6cd5\u95ed\u5305\uff08Lexical Closure\uff09\u6216\u51fd\u6570\u95ed\u5305\uff08function closures\uff09\uff0c\u662f\u5f15\u7528\u4e86\u81ea\u7531\u53d8\u91cf\u7684\u51fd\u6570\u3002\u8fd9\u4e2a\u88ab\u5f15\u7528\u7684\u81ea\u7531\u53d8\u91cf\u5c06\u548c\u8fd9\u4e2a\u51fd\u6570\u4e00\u540c\u5b58\u5728\uff0c\u5373\u4f7f\u5df2\u7ecf\u79bb\u5f00\u4e86\u521b\u9020\u5b83\u7684\u73af\u5883\u4e5f\u4e0d\u4f8b\u5916\u3002 \u95ed\u5305\u5ef6\u4f38\u4e86\u4f5c\u7528\u57df\u7684\u51fd\u6570\uff0c\u5176\u4e2d\u5305\u542b\u51fd\u6570\u5b9a\u4e49\u4f53\u4e2d\u5f15\u7528\u3001\u4f46\u662f\u4e0d\u5728\u5b9a\u4e49\u4f53\u4e2d\u5b9a\u4e49\u7684\u975e\u5168\u5c40\u53d8\u91cf\u3002\u51fd\u6570\u662f\u4e0d\u662f\u533f\u540d\u7684\u6ca1\u6709\u5173\u7cfb\uff0c\u5173\u952e\u662f\u5b83\u80fd\u8bbf\u95ee\u5b9a\u4e49\u4f53\u4e4b\u5916\u5b9a\u4e49\u7684\u975e\u5168\u5c40\u53d8\u91cf\u3002 \u4f8b\u4e00\uff0c\u8ba1\u7b97\u79fb\u52a8\u5e73\u5747\u503c\u3002 \u4e0b\u9762\u662f\u662f\u4f20\u7edf\u7c7b\u5b9e\u73b0\u65b9\u5f0f\uff0cAvg\u7684\u5b9e\u4f8b\u662f\u53ef\u8c03\u7528\u7684\u5bf9\u8c61\u3002 class Avg (): def __init__ ( self ): self . mylist = [] def __call__ ( self , newValue ): self . mylist . append ( newValue ) total = sum ( self . mylist ) return total / len ( self . mylist ) avg = Avg () avg ( 10 ) # 10.0 avg ( 20 ) # 15.0 avg ( 30 ) # 20.0 \u4e0b\u9762\u662f\u9ad8\u9636\u51fd\u6570\u5b9e\u73b0\u65b9\u5f0f\u3002\u8c03\u7528 make_avg \u65f6\uff0c\u8fd4\u56de\u4e00\u4e2a my_avg \u51fd\u6570\u5bf9\u8c61\u3002\u6bcf\u6b21\u8c03\u7528 my_avg \u65f6\uff0c\u5b83\u4f1a\u628a\u53c2\u6570\u6dfb\u52a0\u5230\u7cfb\u5217\u503c\u4e2d\uff0c\u7136\u540e\u8ba1\u7b97\u5f53\u524d\u5e73\u5747\u503c\u3002 def make_avg (): my_list = [] def avg ( newValue ): my_list . append ( newValue ) total = sum ( my_list ) return total / len ( my_list ) return avg my_avg = make_avg () my_avg ( 10 ) # 10.0 my_avg ( 20 ) # 15.0 my_avg ( 30 ) # 20.0 my_avg . __code__ . co_varnames # ('newValue', 'total') my_avg . __code__ . co_freevars # ('my_list',) my_avg . __closure__ # (,) my_avg . __closure__ [ 0 ] . cell_contents # [10, 20, 30] \u8fd9\u4e24\u4e2a\u793a\u4f8b\u6709\u5171\u901a\u4e4b\u5904\uff1a\u8c03\u7528 Avg() \u6216 make_avg() \u5f97\u5230\u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61 avg \uff0c\u5b83\u4f1a\u66f4\u65b0\u5386\u53f2\u503c\uff0c\u7136\u540e\u8ba1\u7b97\u5f53\u524d\u5747\u503c\u3002 \u5728\u7c7b\u5b9e\u73b0\u4e2d\uff0c avg \u662f Avg \u7684\u5b9e\u4f8b\uff1b\u5728\u9ad8\u9636\u51fd\u6570\u5b9e\u73b0\u4e2d\u662f\u5185\u90e8\u51fd\u6570 avg \u3002 \u4e24\u79cd\u5b9e\u73b0\u65b9\u5f0f\u4e2d\uff0c\u6211\u4eec\u90fd\u53ea\u9700\u8c03\u7528 avg(n) \uff0c\u628a n \u653e\u5165\u7cfb\u5217\u503c\u4e2d\uff0c\u7136\u540e\u91cd\u65b0\u8ba1\u7b97\u5747\u503c\u3002 \u7b2c\u4e00\u4e2a\u4f8b\u5b50\u4e2d\uff0c Avg \u7c7b\u7684\u5b9e\u4f8b avg \u5728 self.series \u5b9e\u4f8b\u5c5e\u6027\u4e2d\u5b58\u50a8\u5386\u53f2\u503c\u3002 \u7b2c\u4e8c\u4e2a\u4f8b\u5b50\u4e2d\u7684 my_list \u662f\u51fd\u6570 make_avg() \u7684\u5c40\u90e8\u53d8\u91cf\uff0c\u4e5f\u79f0\u4e3a\u8be5\u51fd\u6570\u7684**\u81ea\u7531\u53d8\u91cf\uff08free variable\uff09**\uff0c\u6307\u672a\u5728\u672c\u5730\u4f5c\u7528\u57df\u4e2d\u7ed1\u5b9a\u7684\u53d8\u91cf\u3002 avg() \u51fd\u6570\u7684\u95ed\u5305\u5ef6\u4f38\u5230\u51fd\u6570\u7684\u4f5c\u7528\u57df\u4e4b\u5916\uff0c\u5305\u542b\u4e86 make_avg() \u7684\u81ea\u7531\u53d8\u91cf my_list \u7684\u7ed1\u5b9a\u3002 \u5bf9\u4e8e\u8fd4\u56de\u7684 my_avg \u5bf9\u8c61\uff0c\u5176 __code__ \u5c5e\u6027\uff08\u8868\u793a\u7f16\u8bd1\u540e\u7684\u51fd\u6570\u5b9a\u4e49\u4f53\uff09\u4e2d\u4fdd\u5b58\u4e86\u5c40\u90e8\u53d8\u91cf\u548c\u81ea\u7531\u53d8\u91cf\u7684\u540d\u79f0\uff0c\u5373 my_avg.__code__.co_varnames \u8fd4\u56de\u4e86\u5c40\u90e8\u53d8\u91cf ('newValue', 'total') \u548c my_avg.__code__.co_freevars \u8fd4\u56de\u4e86\u81ea\u7531\u53d8\u91cf ('my_list',) \u3002 \u81ea\u7531\u53d8\u91cf my_list \u7ed1\u5b9a\u5728\u8fd4\u56de\u7684 my_avg \u7684 __closure__ \u7684\u5c5e\u6027\u4e2d\uff0c my_avg.__closure__ \u4e2d\u7684\u5404\u4e2a\u5143\u7d20\u5bf9\u5e94\u4e86 my_avg.__code__.co_freevars \u4e2d\u7684\u4e00\u4e2a\u540d\u79f0\u3002\u8fd9\u4e9b\u5143\u7d20\u662f cell \u5bf9\u8c61\uff0c\u6709\u4e2a cell_contents \u5c5e\u6027\uff0c\u5982\uff1a my_avg.__closure__ \u8fd4\u56de (,) \uff0c\u91cc\u9762\u4fdd\u5b58\u7740\u771f\u6b63\u7684\u503c\uff0c\u5982 my_avg.__closure__[0].cell_contents \u91cc\u9762\u4fdd\u5b58\u6bcf\u6b21\u8c03\u7528\u7684\u771f\u5b9e\u503c [10, 20, 30] \u3002 \u4e0a\u9762 my_list \u662f\u4e00\u4e2a\u53ef\u53d8\u7c7b\u578b\uff0c\u5982\u679c\u7528\u4e0d\u53ef\u53d8\u7c7b\u578b\u6539\u5199\uff0c\u5e76\u5b9e\u73b0\u95ed\u5305\uff0c\u53ef\u4ee5\u4f7f\u7528 nolocal \u8fdb\u884c\u58f0\u660e\u3002\u5b83\u7684\u4f5c\u7528\u662f\u628a\u53d8\u91cf\u6807\u8bb0\u4e3a\u81ea\u7531\u53d8\u91cf\uff0c\u5373\u4f7f\u5728\u51fd\u6570\u4e2d\u4e3a\u53d8\u91cf\u8d4b\u4e88\u65b0\u503c\u4e86\uff0c\u4e5f\u4f1a\u53d8\u6210\u81ea\u7531\u53d8\u91cf\u3002\u5982\u679c\u4e3anonlocal\u58f0\u660e\u7684\u53d8\u91cf\u8d4b\u4e88\u65b0\u503c\uff0c\u95ed\u5305\u4e2d\u4fdd\u5b58\u7684\u7ed1\u5b9a\u4f1a\u66f4\u65b0\u3002 my_avg.__code__.co_freevars \u8fd4\u56de\u4e862\u4e2a\u81ea\u7531\u53d8\u91cf ('count', 'total') \uff0c\u5e76\u5728 my_avg.__closure__[0].cell_contents \u548c my_avg.__closure__[1].cell_contents \u91cc\u9762\u4fdd\u5b58\u4e86\u6700\u540e\u4e00\u6b21\u6267\u884c\u7684\u771f\u5b9e\u503c\u3002 def make_avg (): count = 0 total = 0 def avg ( newValue ): nonlocal count , total count += 1 total += newValue return total / count return avg my_avg = make_avg () my_avg ( 10 ) # 10.0 my_avg ( 20 ) # 15.0 my_avg ( 30 ) # 20.0 my_avg . __code__ . co_varnames # ('newValue',) my_avg . __code__ . co_freevars # ('count', 'total') my_avg . __closure__ # (, ) my_avg . __closure__ [ 0 ] . cell_contents # 3 my_avg . __closure__ [ 1 ] . cell_contents # 60 \u4f8b\u4e8c\uff1a money \u662f\u4e00\u4e2a\u5c40\u90e8\u53d8\u91cf\uff0c\u5728 get_money \u662f\u5916\u56f4\u51fd\u6570\uff0c\u51fd\u6570\u6267\u884c\u4e4b\u540e\u5e94\u8be5\u5c31\u4e0d\u4f1a\u5b58\u5728\u4e86\u3002 \u4f46\u662f\u5d4c\u5957\u51fd\u6570 work \u5f15\u7528\u4e86 money \u8fd9\u4e2a\u81ea\u7531\u53d8\u91cf\uff0c\u5c06\u8fd9\u4e2a\u5c40\u90e8\u53d8\u91cf\u5c01\u95ed\u5728\u4e86\u5d4c\u5957\u51fd\u6570 work \u4e2d\uff0c\u8fd9\u6837\u5c31\u5f62\u6210\u4e86\u4e00\u4e2a\u95ed\u5305\u3002 closure = get_money() \u83b7\u5f97\u7684\u5c31\u662f\u4e00\u4e2a\u95ed\u5305\u3002 closure() \u8f93\u51fa\u95ed\u5305\uff0c\u5373\uff0c\u6267\u884c\u4e86 work() \uff0c\u6253\u5370\u8f93\u51fa money \u7684\u503c\u3002 \u672c\u5730\u51fd\u6570\u901a\u8fc7global\u58f0\u660e\u5bf9\u5168\u5c40\u53d8\u91cf\u8fdb\u884c\u5f15\u7528\u4fee\u6539\uff0c\u90a3\u4e48\u5bf9\u4e8e\u5185\u5d4c\u51fd\u6570 work() \u4f5c\u7528\u57df\u4e2d\u7684\u53d8\u91cf\u8fdb\u884c\u4fee\u6539\uff0c\u5c31\u8981\u4f7f\u7528 nonlocal \u8fdb\u884c\u58f0\u660e\u3002 def get_money (): money = 0 def work (): nonlocal money money += 100 print ( money ) return work closure = get_money () closure () # 100 closure () # 200 closure () # 300 \u4f8b\u4e09\uff1a \u51fd\u6570 maker \u4e2d\u5b9a\u4e49\u4e86\u51fd\u6570 action \uff0c action \u5f15\u7528\u4e86 maker \u5d4c\u5957\u4f5c\u7528\u57df\u5185\u7684\u53d8\u91cf k \uff0c\u5e76\u4e14\uff0c maker \u5c06\u51fd\u6570 action \u4f5c\u4e3a\u8fd4\u56de\u5bf9\u8c61\u8fdb\u884c\u8fd4\u56de\u3002 \u8fd9\u6837\uff0c\u6211\u4eec\u901a\u8fc7\u6267\u884c f = maker(2) \uff0c f \u83b7\u53d6\u4e86\u8fd4\u56de\u5bf9\u8c61 action \uff0c\u867d\u7136\u6b64\u65f6 maker \u51fd\u6570\u4ee5\u53ca\u7ed3\u675f\u9000\u51fa\u4e86\uff0c\u4f46\u5bf9\u8c61 f \u4ecd\u7136\u8bb0\u4f4f\u4e86\u51fd\u6570 maker \u5d4c\u5957\u4f5c\u7528\u57df\u5185\u7684\u53d8\u91cf k \u548c n \uff0c\u5e76\u5728\u6267\u884c f(3) \u65f6\uff0c\u5c06 x=3 \u4ee5\u53ca\u4e4b\u524d\u8bb0\u4f4f\u7684 k \u548c n \uff0c\u4e00\u5e76\u4f20\u5165 action() \uff0c\u8ba1\u7b97\u5e76\u8fd4\u56de x + n + k \u503c\u3002 make \u4e5f\u79f0\u4e3a**\u5de5\u5382\u51fd\u6570**\u3002 def maker ( n ): k = 8 def action ( x ): return x + n + k return action f = maker ( 2 ) print ( f ( 3 )) # 13 print ( f ( 4 )) # 14 print ( f ( 5 )) # 15 \u7ed3\u5408\u524d\u97622\u4e2a\u4f8b\u5b50\u518d\u770b\u4e0a\u9762\u7684\u89e3\u91ca\uff0c\u95ed\u5305\u5c31\u662f\u5f15\u7528\u4e86\u81ea\u7531\u53d8\u91cf\u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u4fdd\u5b58\u4e86\u6267\u884c\u7684\u4e0a\u4e0b\u6587\uff0c\u53ef\u4ee5\u8131\u79bb\u539f\u672c\u7684\u4f5c\u7528\u57df\u72ec\u7acb\u5b58\u5728\u3002","title":"\u95ed\u5305"},{"location":"python/Foundation/ch03/#_8","text":"\u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u5c06\u51fd\u6570\u4f5c\u4e3a\u53c2\u6570\u4f20\u7ed9\u53e6\u4e00\u4e2a\u51fd\u6570\uff0c\u51fd\u6570 my_decorator \u7684\u4f20\u5165\u53c2\u6570\u6b63\u597d\u662f\u5176\u5d4c\u5957\u51fd\u6570 myFunc \u3002 def my_decorator ( nestedFunc ): def myFunc (): print ( \"Before executing nestedFunc()\" ) nestedFunc () print ( \"After executing nestedFunc()\" ) return myFunc def nestedFunc (): print ( \"Decoration - executing nestedFunc()\" ) nestedFunc () # Decoration - executing nestedFunc() nestedFunc = my_decorator ( nestedFunc ) nestedFunc () # Before executing nestedFunc() # Decoration - executing nestedFunc() # After executing nestedFunc() \u88c5\u9970\u5668\u53ea\u662f\u4e2a\u65b9\u6cd5\uff0c\u4f7f\u7528\u65f6\u7528\u4e86 @ \u8bed\u6cd5\u3002 @ \u8bed\u6cd5\u53ea\u662f\u5c06\u51fd\u6570 nestedFunc \u4f20\u5165\u88c5\u9970\u5668\u51fd\u6570 my_decorator \u3002 @my_decorator \u662f nestedFunc = my_decorator(nestedFunc) \u7684\u5feb\u6377\u8868\u8fbe\u65b9\u5f0f\uff0c @my_decorator def nestedFunc (): print ( \"New added to decoration - executing nestedFunc()\" ) nestedFunc () # Before executing nestedFunc() # New added to decoration - executing nestedFunc() # After executing nestedFunc() print ( nestedFunc . __name__ ) # myFunc \u4f46\u4e0a\u4f8b\u6700\u540e\u7684\u8f93\u51fa\u4e0d\u662f\u6211\u4eec\u60f3\u8981\u7684\uff0c\u6211\u4eec\u5e0c\u671b\u8f93\u51fa nestedFunc \uff0c\u4f46\u5374\u88ab myFunc \u66ff\u4ee3\u4e86\uff0c\u5b83\u91cd\u5199\u4e86\u6211\u4eec\u51fd\u6570\u7684\u540d\u5b57\u548c\u6ce8\u91ca\u6587\u6863(docstring)\u3002 \u4e0b\u9762\u4f7f\u7528 functools.wraps \u6765\u4fee\u6b63\u4e0a\u9762\u7684\u95ee\u9898\u3002 from functools import wraps def my_decorator ( nestedFunc ): @wraps ( nestedFunc ) def myFunc (): print ( \"Before executing nestedFunc()\" ) nestedFunc () print ( \"After executing nestedFunc()\" ) return myFunc def nestedFunc (): print ( \"Decoration - executing nestedFunc()\" ) @my_decorator def nestedFunc (): print ( \"New added to decoration - executing nestedFunc()\" ) nestedFunc () # Before executing nestedFunc() # New added to decoration - executing nestedFunc() # After executing nestedFunc() print ( nestedFunc . __name__ ) # nestedFunc \u4e0b\u9762\u662f\u88c5\u9970\u5668\u7684\u84dd\u672c\u89c4\u8303\u3002 from functools import wraps def decorator_name ( f ): @wraps ( f ) def decorated ( * args , ** kwargs ): if not can_run : return \"Function will not run\" return f ( * args , ** kwargs ) return decorated @decorator_name def func (): return ( \"Function is running\" ) can_run = True print ( func ()) # Output: Function is running can_run = False print ( func ()) # Output: Function will not run \u4e0b\u9762\u8fd8\u662f\u4e00\u4e2a\u88c5\u9970\u5668\u7684\u4f8b\u5b50\u3002\u628a\u4e0b\u9762\u7684\u4ee3\u7801\u6bb5\u4fdd\u5b58\u5230\u6587\u4ef6 test.py \u3002 registry = [] def register ( func ): print ( f 'running register { func } ' ) registry . append ( func ) return func @register def f1 (): print ( 'running f1()' ) @register def f2 (): print ( 'running f2()' ) def f3 (): print ( 'running f3()' ) def main (): print ( 'runnning main()' ) print ( f 'registry--> { registry } ' ) f1 () f2 () f3 () if __name__ == '__main__' : main () \u6267\u884c\u4e0a\u8ff0\u4ee3\u7801\u6bb5 python3 test.py \uff0c\u5f97\u5230\u4e0b\u9762\u7684\u7ed3\u679c\u3002 running register < function f1 at 0x7f70847bec80 > running register < function f2 at 0x7f70705aa9d8 > runnning main () registry --> [ < function f1 at 0x7f70847bec80 > , < function f2 at 0x7f70705aa9d8 > ] running f1 () running f2 () running f3 () register \u5728\u6a21\u5757\u4e2d\u5176\u4ed6\u51fd\u6570\u4e4b\u524d\u8fd0\u884c\uff08\u4e24\u6b21\uff09\u3002\u8c03\u7528 register \u65f6\uff0c\u4f20\u7ed9\u5b83\u7684\u53c2\u6570\u662f\u88ab\u88c5\u9970\u7684\u51fd\u6570\uff0c\u4f8b\u5982 function f1 at 0x7f70847bec80> \u3002\u52a0\u8f7d\u6a21\u5757\u540e\uff0c registry \u4e2d\u6709\u4e24\u4e2a\u88ab\u88c5\u9970\u51fd\u6570\u7684\u5f15\u7528\uff1a f1 \u548c f2 \u3002\u8fd9\u4e24\u4e2a\u51fd\u6570\uff0c\u4ee5\u53ca f3 \uff0c\u53ea\u5728 main \u660e\u786e\u8c03\u7528\u5b83\u4eec\u65f6\u624d\u6267\u884c\u3002 \u7531\u6b64\u5f97\uff0c\u51fd\u6570\u88c5\u9970\u5668\u5728\u5bfc\u5165\u6a21\u5757\u65f6\u7acb\u5373\u6267\u884c\uff0c\u800c\u88ab\u88c5\u9970\u7684\u51fd\u6570\u53ea\u5728\u660e\u786e\u8c03\u7528\u65f6\u8fd0\u884c\uff0c\u5373Python\u4e2d\u63d0\u5230\u7684**\u5bfc\u5165\u65f6**\u548c**\u8fd0\u884c\u65f6**\u4e4b\u95f4\u7684\u533a\u522b\u3002 \u4e0a\u9762\u4f8b\u5b50\u4e2d\u88c5\u9970\u5668\u51fd\u6570\u4e0e\u88ab\u88c5\u9970\u7684\u51fd\u6570\u5728\u540c\u4e00\u4e2a\u6a21\u5757\u4e2d\u5b9a\u4e49\u3002\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u88c5\u9970\u5668\u901a\u5e38\u5728\u4e00\u4e2a\u6a21\u5757\u4e2d\u5b9a\u4e49\uff0c\u7136\u540e\u5e94\u7528\u5230\u5176\u4ed6\u6a21\u5757\u4e2d\u7684\u51fd\u6570\u4e0a\u3002 \u4e0a\u9762\u4f8b\u5b50\u4e2d register \u88c5\u9970\u5668\u8fd4\u56de\u7684\u51fd\u6570\u4e0e\u901a\u8fc7\u53c2\u6570\u4f20\u5165\u7684\u76f8\u540c\u3002\u5b9e\u9645\u5e94\u7528\u4e2d\uff0c\u5927\u591a\u6570\u88c5\u9970\u5668\u4f1a\u5728\u5185\u90e8\u5b9a\u4e49\u4e00\u4e2a\u51fd\u6570\uff0c\u7136\u540e\u5c06\u5176\u8fd4\u56de\u3002","title":"\u88c5\u9970\u5668"},{"location":"python/Foundation/ch04/","text":"Python\u9762\u5411\u5bf9\u8c61\u6982\u5ff5 \u00b6 \u7c7b(class)\u628a\u6570\u636e\u4e0e\u529f\u80fd\u7ed1\u5b9a\u5728\u4e00\u8d77\u3002\u521b\u5efa\u65b0\u7c7b\u5c31\u662f\u521b\u5efa\u65b0\u7684\u5bf9\u8c61\u7c7b\u578b\uff08type of object\uff09\uff0c\u4ece\u800c\u521b\u5efa\u8be5\u7c7b\u578b\u7684\u65b0\u5b9e\u4f8b\uff08instances\uff09\u3002 \u7c7b\u5b9e\u4f8b\u5177\u6709\u591a\u79cd\u4fdd\u6301\u81ea\u8eab\u72b6\u6001\u7684\u5c5e\u6027\uff08attributes\uff09\u3002 \u7c7b\u5b9e\u4f8b\u8fd8\u652f\u6301\uff08\u7531\u7c7b\u5b9a\u4e49\u7684\uff09\u4fee\u6539\u81ea\u8eab\u72b6\u6001\u7684\u65b9\u6cd5\uff08methods\uff09\u3002 Python\u7684\u7c7b\u652f\u6301\u6240\u6709\u9762\u5411\u5bf9\u8c61\u7f16\u7a0b\uff08OOP\uff09\u7684\u6807\u51c6\u7279\u6027\uff1a \u7c7b\u7ee7\u627f\uff08class inheritance\uff09\u673a\u5236\u652f\u6301\u591a\u4e2a\u57fa\u7c7b\uff08base classes\uff09\uff1b \u6d3e\u751f\u7c7b\uff08derived class\uff09\u53ef\u4ee5\u8986\u76d6\u57fa\u7c7b\u7684\u4efb\u4f55\u65b9\u6cd5\uff08methods\uff09\uff1b \u7c7b\u7684\u65b9\u6cd5\u53ef\u4ee5\u8c03\u7528\u57fa\u7c7b\u4e2d\u76f8\u540c\u540d\u79f0\u7684\u65b9\u6cd5 \u5bf9\u8c61\u53ef\u4ee5\u5305\u542b\u4efb\u610f\u6570\u91cf\u548c\u7c7b\u578b\u7684\u6570\u636e\u3002 \u7c7b\uff08class\uff09\u548c\u6a21\u5757\uff08module\uff09\u90fd\u62e5\u6709\u52a8\u6001\u7279\u6027\uff08dynamic nature\uff09\uff1a\u5728\u8fd0\u884c\u65f6\u521b\u5efa\uff0c\u521b\u5efa\u540e\u4e5f\u53ef\u4ee5\u4fee\u6539\u3002 \u540d\u79f0Names\u548c\u5bf9\u8c61Objects \u00b6 \u5bf9\u8c61\u4e4b\u95f4\u76f8\u4e92\u72ec\u7acb\uff0c\u591a\u4e2a\u540d\u79f0\uff08names\uff09\uff08\u5728\u591a\u4e2a\u4f5c\u7528\u57df\u5185\uff09\u53ef\u4ee5\u7ed1\u5b9a\u5230\u540c\u4e00\u4e2a\u5bf9\u8c61\u3002 \u5176\u4ed6\u8bed\u8a00\u79f0\u4e4b\u4e3a\u522b\u540d\uff08alias\uff09\u3002 \u522b\u540d\u5728\u67d0\u4e9b\u65b9\u9762\u5c31\u50cf\u6307\u9488\u3002\u4f8b\u5982\uff0c\u4f20\u9012\u5bf9\u8c61\u7684\u4ee3\u4ef7\u5f88\u5c0f\uff0c\u56e0\u4e3a\u5b9e\u73b0\u53ea\u4f20\u9012\u4e00\u4e2a\u6307\u9488\uff1b\u5982\u679c\u51fd\u6570\u4fee\u6539\u4e86\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7684\u5bf9\u8c61\uff0c\u8c03\u7528\u8005\u5c31\u53ef\u4ee5\u770b\u5230\u66f4\u6539\u3002 \u4f5c\u7528\u57dfScopes\u548c\u547d\u540d\u7a7a\u95f4Namespaces \u00b6 **\u547d\u540d\u7a7a\u95f4\uff08namespace\uff09**\u662f\u4e00\u4e2a\u4ece\u540d\u5b57\u5230\u5bf9\u8c61\u7684\u6620\u5c04\u3002 \u5f53\u524d\u5927\u90e8\u5206\u547d\u540d\u7a7a\u95f4\u90fd\u7531 Python \u5b57\u5178\u5b9e\u73b0\u3002 \u4e0b\u9762\u662f\u51e0\u4e2a\u547d\u540d\u7a7a\u95f4\u7684\u4f8b\u5b50\uff1a \u5b58\u653e\u5185\u7f6e\u51fd\u6570\u7684\u96c6\u5408\uff08\u5305\u542b abs() \u8fd9\u6837\u7684\u51fd\u6570\uff0c\u548c\u5185\u5efa\u7684\u5f02\u5e38\u7b49\uff09\uff1b \u6a21\u5757\u4e2d\u7684\u5168\u5c40\u540d\u79f0\uff1b \u51fd\u6570\u8c03\u7528\u4e2d\u7684\u5c40\u90e8\u540d\u79f0\uff1b \u4ece\u67d0\u79cd\u610f\u4e49\u4e0a\u8bf4\uff0c \u5bf9\u8c61\u7684\u5c5e\u6027\u96c6\u5408\uff08the set of attributes of an object\uff09\u4e5f\u662f\u4e00\u79cd\u547d\u540d\u7a7a\u95f4\u7684\u5f62\u5f0f \u3002 \u5173\u4e8e\u547d\u540d\u7a7a\u95f4\u7684\u91cd\u8981\u4e00\u70b9\u662f\uff0c\u4e0d\u540c\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u540d\u79f0\u4e4b\u95f4\u7edd\u5bf9\u6ca1\u6709\u5173\u7cfb\uff1b \u4f8b\u5982\uff0c\u5728\u4e24\u4e2a\u4e0d\u540c\u7684\u6a21\u5757\u4e2d\u90fd\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a maximize \u51fd\u6570\u800c\u4e0d\u4f1a\u4ea7\u751f\u6df7\u6dc6\uff0c\u4f46\u5728\u8c03\u7528 maximize \u51fd\u6570\u65f6\u5fc5\u987b\u5fc5\u987b\u5728\u5176\u524d\u9762\u52a0\u4e0a\u6a21\u5757\u540d\u79f0\u3002 \u4efb\u4f55\u8ddf\u5728\u4e00\u4e2a\u70b9\u53f7\u4e4b\u540e\u7684\u540d\u79f0\u90fd\u79f0\u4e3a**\u5c5e\u6027\uff08attribute\uff09**\u3002\u4f8b\u5982\uff0c\u5728\u8868\u8fbe\u5f0f z.real \u4e2d\uff0c real \u662f\u5bf9\u8c61 z \u7684\u4e00\u4e2a\u5c5e\u6027\u3002 \u6309\u4e25\u683c\u7684\u8bf4\u6cd5\uff0c \u5bf9\u6a21\u5757\uff08module\uff09\u4e2d\u7684\u540d\u79f0\u7684\u5f15\u7528\uff08reference\uff09\u90fd\u5c5e\u4e8e\u5c5e\u6027\u5f15\u7528\uff08attribute reference\uff09 \uff1a \u5728\u8868\u8fbe\u5f0f modname.funcname \u4e2d\uff0c modname \u662f\u4e00\u4e2a\u6a21\u5757\u5bf9\u8c61\uff08module object\uff09\u800c funcname \u662f\u5b83\u7684\u4e00\u4e2a\u5c5e\u6027\u3002 \u5728\u6b64\u60c5\u51b5\u4e0b\u5728\u6a21\u5757\u7684\u5c5e\u6027\uff08module\u2019s attribute\uff09\u548c\u6a21\u5757\u4e2d\u5b9a\u4e49\u7684\u5168\u5c40\u540d\u79f0\u4e4b\u95f4\u6b63\u597d\u5b58\u5728\u4e00\u4e2a\u76f4\u89c2\u7684\u6620\u5c04\uff1a\u5b83\u4eec\u5171\u4eab\u76f8\u540c\u7684\u547d\u540d\u7a7a\u95f4\u3002 \u4f46\u5b58\u5728\u4e00\u4e2a\u4f8b\u5916\u3002 \u6a21\u5757\u5bf9\u8c61\u6709\u4e00\u4e2a\u53ea\u8bfb\u5c5e\u6027 __dict__ \uff0c\u5b83\u8fd4\u56de\u7528\u4e8e\u5b9e\u73b0\u6a21\u5757\u547d\u540d\u7a7a\u95f4\u7684\u5b57\u5178\uff1b __dict__ \u662f\u5c5e\u6027\u4f46\u4e0d\u662f\u5168\u5c40\u540d\u79f0\u3002 \u4f7f\u7528\u8fd9\u4e2a\u5c06\u8fdd\u53cd\u547d\u540d\u7a7a\u95f4\u5b9e\u73b0\u7684\u62bd\u8c61\uff0c\u5e94\u5f53\u4ec5\u88ab\u7528\u4e8e\u4e8b\u540e\u8c03\u8bd5\u5668\u4e4b\u7c7b\u7684\u573a\u5408\u3002 **\u5c5e\u6027\uff08attribute\uff09**\u53ef\u4ee5\u662f\u53ea\u8bfb\u6216\u8005\u53ef\u5199\u7684\uff0c\u6240\u4ee5\u53ef\u4ee5\u5bf9\u5c5e\u6027\u8fdb\u884c\u8d4b\u503c\uff0c\u4f8b\u5982 modname.the_answer = 42 \u3002 \u5220\u9664\u5c5e\u6027\u53ef\u4ee5\u7528del\u8bed\u53e5\uff0c\u4f8b\u5982\uff0c del modname.the_answer \u5c06\u4f1a\u4ece\u540d\u4e3a modname \u7684\u5bf9\u8c61\u4e2d\u79fb\u9664 the_answer \u5c5e\u6027\u3002 \u547d\u540d\u7a7a\u95f4\u5728\u4e0d\u540c\u65f6\u523b\u88ab\u521b\u5efa\uff0c\u62e5\u6709\u4e0d\u540c\u7684\u751f\u5b58\u671f\uff08lifetimes\uff09\u3002\u5305\u542b\u5185\u7f6e\u540d\u79f0\uff08built-in names\uff09\u7684\u547d\u540d\u7a7a\u95f4\u662f\u5728Python\u89e3\u91ca\u5668\u542f\u52a8\u65f6\u521b\u5efa\u7684\uff0c\u6c38\u8fdc\u4e0d\u4f1a\u88ab\u5220\u9664\u3002 \u6a21\u5757\u7684\u5168\u5c40\u547d\u540d\u7a7a\u95f4\uff08global namespace\uff09\u5728\u6a21\u5757\u5b9a\u4e49\u88ab\u8bfb\u5165\u65f6\u521b\u5efa\uff1b\u901a\u5e38\uff0c\u6a21\u5757\u547d\u540d\u7a7a\u95f4\u4e5f\u4f1a\u6301\u7eed\u5230\u89e3\u91ca\u5668\u9000\u51fa\u3002 \u88ab\u89e3\u91ca\u5668\u7684\u9876\u5c42\u8c03\u7528\uff08top-level invocation\uff09\u6267\u884c\u7684\u8bed\u53e5\uff0c\u4ece\u4e00\u4e2a\u811a\u672c\u6587\u4ef6\u8bfb\u53d6\u6216\u4ea4\u4e92\u5f0f\u5730\u8bfb\u53d6\uff0c\u88ab\u8ba4\u4e3a\u662f __main__ \u6a21\u5757\u8c03\u7528\u7684\u4e00\u90e8\u5206\uff0c\u56e0\u6b64\u5b83\u4eec\u62e5\u6709\u81ea\u5df1\u7684\u5168\u5c40\u547d\u540d\u7a7a\u95f4\u3002 \u5185\u7f6e\u540d\u79f0\uff08built-in names\uff09\u5b9e\u9645\u4e0a\u4e5f\u5b58\u5728\u4e8e\u4e00\u4e2a\u6a21\u5757\u4e2d\uff0c\u8fd9\u4e2a\u6a21\u5757\u88ab\u79f0\u4f5c builtins \u3002 \u4e00\u4e2a\u51fd\u6570\u7684\u672c\u5730\u547d\u540d\u7a7a\u95f4\uff08local namespace\uff09\u5728\u8fd9\u4e2a\u51fd\u6570\u88ab\u8c03\u7528\u65f6\u521b\u5efa\uff0c\u5e76\u5728\u51fd\u6570\u8fd4\u56de\u6216\u629b\u51fa\u4e00\u4e2a\u65e0\u6cd5\u5728\u8be5\u51fd\u6570\u5185\u90e8\u5904\u7406\u7684\u9519\u8bef\u65f6\u88ab\u5220\u9664\u3002 \u6bcf\u6b21\u9012\u5f52\u8c03\u7528\uff08recursive invocations\uff09\u90fd\u4f1a\u6709\u5b83\u81ea\u5df1\u7684\u672c\u5730\u547d\u540d\u7a7a\u95f4\u3002 \u4e00\u4e2a**\u4f5c\u7528\u57df\uff08scope\uff09**\u662f\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4\u53ef\u76f4\u63a5\u8bbf\u95ee\uff08directly accessible\uff09\u7684Python\u7a0b\u5e8f\u7684\u4ee3\u7801\u533a\u57df\u3002 \u8fd9\u91cc\u7684 \u201c\u53ef\u76f4\u63a5\u8bbf\u95ee\u201d \u610f\u5473\u7740\u4e0d\u52a0\u4efb\u4f55\u9650\u5b9a\u7684\u540d\u79f0\u5f15\u7528\u4f1a\u5728\u547d\u540d\u7a7a\u95f4\u4e2d\u8fdb\u884c\u67e5\u627e\u3002 \u867d\u7136\u4f5c\u7528\u57df\u662f\u9759\u6001\u5730\u786e\u5b9a\u7684\uff0c\u4f46\u5b83\u4eec\u4f1a\u88ab\u52a8\u6001\u5730\u4f7f\u7528\u3002 \u5728\u4ee3\u7801\u6267\u884c\u671f\u95f4\u7684\u4efb\u4f55\u65f6\u523b\uff0c\u4f1a\u67093\u62164\u4e2a\u7684\u5d4c\u5957\u4f5c\u7528\u57df\u4f9b\u547d\u540d\u7a7a\u95f4\u76f4\u63a5\u8bbf\u95ee: \u6700\u5148\u641c\u7d22\u7684\u6700\u5185\u90e8\u4f5c\u7528\u57df\u5305\u542b\u5c40\u90e8\u540d\u79f0 \u4ece\u6700\u8fd1\u7684\u5c01\u95ed\u4f5c\u7528\u57df\u5f00\u59cb\u641c\u7d22\u7684\u4efb\u4f55\u5c01\u95ed\u51fd\u6570\u7684\u4f5c\u7528\u57df\u5305\u542b\u975e\u5c40\u90e8\u540d\u79f0\uff0c\u4e5f\u5305\u62ec\u975e\u5168\u5c40\u540d\u79f0 \u5012\u6570\u7b2c\u4e8c\u4e2a\u4f5c\u7528\u57df\u5305\u542b\u5f53\u524d\u6a21\u5757\u7684\u5168\u5c40\u540d\u79f0 \u6700\u5916\u9762\u7684\u4f5c\u7528\u57df\uff08\u6700\u540e\u641c\u7d22\uff09\u662f\u5305\u542b\u5185\u7f6e\u540d\u79f0\u7684\u547d\u540d\u7a7a\u95f4 \u5982\u679c\u4e00\u4e2a\u540d\u79f0\u88ab\u58f0\u660e\u4e3a\u5168\u5c40\u53d8\u91cf\uff0c\u5219\u6240\u6709\u5f15\u7528\u548c\u8d4b\u503c\u5c06\u76f4\u63a5\u6307\u5411\u8be5\u6a21\u5757\u5168\u5c40\u540d\u79f0\u6240\u5728\u7684\u4e2d\u95f4\u4f5c\u7528\u57df\u3002 \u5982\u679c\u8981\u91cd\u65b0\u7ed1\u5b9a\u5728\u6700\u5185\u5c42\u4f5c\u7528\u57df\u4ee5\u5916\u7684\u53d8\u91cf\uff0c\u53ef\u4ee5\u4f7f\u7528 nonlocal \u8bed\u53e5\u58f0\u660e\u4e3a\u975e\u672c\u5730\u53d8\u91cf\u3002 \u5982\u679c\u6ca1\u6709\u88ab\u58f0\u660e\u4e3a\u975e\u672c\u5730\u53d8\u91cf\uff0c\u8fd9\u4e9b\u53d8\u91cf\u5c06\u662f\u53ea\u8bfb\u7684\u3002\u7ed9\u8fd9\u6837\u7684\u53d8\u91cf\u8d4b\u65b0\u503c\u53ea\u4f1a\u5728\u6700\u5185\u5c42\u4f5c\u7528\u57df\u4e2d\u521b\u5efa\u4e00\u4e2a*\u65b0\u7684*\u5c40\u90e8\u53d8\u91cf\uff0c\u800c\u540c\u540d\u7684\u5916\u90e8\u5168\u5c40\u53d8\u91cf\u5c06\u4fdd\u6301\u4e0d\u53d8\u3002 \u901a\u5e38\uff0c\u5f53\u524d\u5c40\u90e8\u4f5c\u7528\u57df\uff08local scope\uff09\u5c06\u5f15\u7528\u5f53\u524d\u51fd\u6570\u4f5c\u7528\u57df\u7684\u540d\u79f0\uff08local name\uff09\u3002 \u5728\u51fd\u6570\u4f5c\u7528\u57df\u4ee5\u5916\uff0c\u5f53\u524d\u5c40\u90e8\u4f5c\u7528\u57df\u5c06\u5f15\u7528\u4e0e\u5168\u5c40\u4f5c\u7528\u57df\u76f8\u4e00\u81f4\u7684\u547d\u540d\u7a7a\u95f4\uff1a\u6a21\u5757\u7684\u547d\u540d\u7a7a\u95f4\uff08the module\u2019s namespace\uff09\u3002 \u5b9a\u4e49\u4e00\u4e2a\u7c7b\uff0c\u662f\u5728\u672c\u5730\u5c40\u90e8\u547d\u540d\u7a7a\u95f4\u5185\u5efa\u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u3002 \u5728\u4e00\u4e2a\u6a21\u5757\uff08module \uff09\u5185\u5b9a\u4e49\u7684\u51fd\u6570\u7684\u4f5c\u7528\u57df\u5c31\u662f\u8be5\u6a21\u5757\u7684\u547d\u540d\u7a7a\u95f4\uff0c\u65e0\u8bba\u8be5\u51fd\u6570\u4ece\u4ec0\u4e48\u5730\u65b9\u6216\u4ee5\u4ec0\u4e48\u522b\u540d\u88ab\u8c03\u7528\u3002 \u53e6\u4e00\u65b9\u9762\uff0c\u5b9e\u9645\u7684\u540d\u79f0\u641c\u7d22\u662f\u5728\u8fd0\u884c\u65f6\u52a8\u6001\u5b8c\u6210\u7684\u3002 \u4f46\u662f\uff0cPython\u6b63\u5728\u671d\u7740\u201c\u7f16\u8bd1\u65f6\u9759\u6001\u540d\u79f0\u89e3\u6790\u201d\u7684\u65b9\u5411\u53d1\u5c55\uff0c\u56e0\u6b64\u4e0d\u8981\u8fc7\u4e8e\u4f9d\u8d56\u52a8\u6001\u540d\u79f0\u89e3\u6790\uff01\u4e8b\u5b9e\u4e0a\uff0c\u5c40\u90e8\u53d8\u91cf\u5df2\u7ecf\u662f\u88ab\u9759\u6001\u786e\u5b9a\u4e86\u3002 \u5982\u679c\u4e0d\u5b58\u5728\u751f\u6548\u7684 global \u6216 nonlocal \u8bed\u53e5\uff0c\u5219\u5bf9\u540d\u79f0\u7684\u8d4b\u503c\u603b\u662f\u4f1a\u8fdb\u5165\u6700\u5185\u5c42\u4f5c\u7528\u57df\u3002\u8d4b\u503c\u4e0d\u4f1a\u590d\u5236\u6570\u636e\uff0c\u662f\u5c06\u540d\u79f0\u7ed1\u5b9a\u5230\u5bf9\u8c61\u3002 \u5220\u9664\u4e5f\u662f\u5982\u6b64\uff1a\u8bed\u53e5 del x \u4f1a\u4ece\u5c40\u90e8\u4f5c\u7528\u57df\u6240\u5f15\u7528\u7684\u547d\u540d\u7a7a\u95f4\u4e2d\u79fb\u9664\u5bf9 x \u7684\u7ed1\u5b9a\u3002\u4e8b\u5b9e\u4e0a\uff0c\u6240\u6709\u5f15\u5165\u65b0\u540d\u79f0\u7684\u64cd\u4f5c\u90fd\u662f\u4f7f\u7528\u5c40\u90e8\u4f5c\u7528\u57df\u3002\u7279\u522b\u5730\uff0c import \u8bed\u53e5\u548c\u51fd\u6570\u5b9a\u4e49\u4f1a\u5728\u5c40\u90e8\u4f5c\u7528\u57df\u4e2d\u7ed1\u5b9a\u6a21\u5757\u6216\u51fd\u6570\u540d\u79f0\u3002 global \u8bed\u53e5\u53ef\u88ab\u7528\u6765\u8868\u660e\u7279\u5b9a\u53d8\u91cf\u5b58\u5728\u4e8e\u5168\u5c40\u4f5c\u7528\u57df\uff0c\u5e76\u4e14\u5e94\u5f53\u5728\u5168\u5c40\u4f5c\u7528\u57df\u4e2d\u88ab**\u91cd\u65b0**\u7ed1\u5b9a\uff1b nonlocal \u8bed\u53e5\u8868\u660e\u7279\u5b9a\u53d8\u91cf\u751f\u5b58\u4e8e\u5916\u5c42\u4f5c\u7528\u57df\u4e2d\uff0c\u5e76\u4e14\u5e94\u5f53\u5728\u5176\u6240\u5904\u7684\u5916\u5c42\u4f5c\u7528\u57df\u4e2d\u88ab**\u91cd\u65b0**\u7ed1\u5b9a\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a \u5c40\u90e8\u8d4b\u503c\uff08local assignment\uff0c\u8fd9\u662f\u9ed8\u8ba4\u72b6\u6001\uff09\u4e0d\u4f1a\u6539\u53d8 scope_test \u5bf9 spam \u7684\u7ed1\u5b9a\u3002 nonlocal \u8d4b\u503c\u4f1a\u6539\u53d8 scope_test \u5bf9 spam \u7684\u7ed1\u5b9a\u3002 global \u8d4b\u503c\u4f1a\u6539\u53d8\u6a21\u5757\u5c42\u7ea7\u7684\u7ed1\u5b9a\uff0c\u5373\uff0c global spam \u91cd\u65b0\u7ed1\u5b9a\u4e86spam\u7684\u5168\u5c40\u5b9a\u4e49\uff0c\u4ece spam = \"spam out of func\" \u53d8\u6210\u4e86 spam = \"global spam\" \u3002\u5982\u679c\u6ce8\u91ca\u6389def do_global()\u8fd9\u4e00\u6bb5\u4ee3\u7801\uff0c\u5219 spam = \"spam out of func\" \u8d77\u4f5c\u7528\u3002 spam = \"spam out of func\" def scope_test (): def do_local (): spam = \"local spam\" def do_nonlocal (): nonlocal spam spam = \"nonlocal spam\" def do_global (): global spam spam = \"global spam\" spam = \"test spam\" do_local () print ( \"After local assignment:\" , spam ) do_nonlocal () print ( \"After nonlocal assignment:\" , spam ) do_global () print ( \"After global assignment:\" , spam ) scope_test () print ( \"In global scope:\" , spam ) # \u8fd0\u884c\u7ed3\u679c # scope_test() After local assignment : test spam After nonlocal assignment : nonlocal spam After global assignment : nonlocal spam # print(\"In global scope:\", spam) In global scope : global spam \u7c7bClass \u00b6 \u7c7b\u5b9a\u4e49 Class Definition \u00b6 \u7c7b\u5b9a\u4e49\u4e0e\u51fd\u6570\u5b9a\u4e49 (def \u8bed\u53e5) \u4e00\u6837\u5fc5\u987b\u88ab\u6267\u884c\u624d\u4f1a\u8d77\u4f5c\u7528\u3002 class ClassName : < statement - 1 > ... < statement - N > \u5728\u5b9e\u8df5\u4e2d\uff0c\u7c7b\u5b9a\u4e49\u5185\u7684\u8bed\u53e5\u901a\u5e38\u90fd\u662f\u51fd\u6570\u5b9a\u4e49\uff0c\u4f46\u4e5f\u5141\u8bb8\u6709\u5176\u4ed6\u8bed\u53e5\u3002\u5728\u7c7b\u5185\u90e8\u7684\u51fd\u6570\u5b9a\u4e49\u901a\u5e38\u5177\u6709\u4e00\u79cd\u7279\u6709\u5f62\u5f0f\u7684\u53c2\u6570\u5217\u8868\uff0c\u8fd9\u662f\u7ea6\u5b9a\u7684\u65b9\u6cd5\u89c4\u8303\uff08conventions for methods\uff09\u3002 \u7f16\u8bd1\u8fc7\u7a0b\u4e2d\uff0c\u8fdb\u5165\u4e00\u4e2a\u7c7b\u7684\u5185\u90e8\uff0c\u5c06\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\uff0c\u4e00\u4e2a\u5c40\u90e8\u4f5c\u7528\u57df\u3002\u56e0\u6b64\uff0c\u6240\u6709\u5bf9\u7c7b\u5185\u90e8\u5c40\u90e8\u53d8\u91cf\u7684\u8d4b\u503c\u90fd\u662f\u5728\u8fd9\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u4e4b\u5185\uff0c\u5305\u62ec\u65b0\u5b9a\u4e49\u7684\u51fd\u6570\u540d\u79f0\u3002 \u5f53\u6b63\u5e38\u79bb\u5f00\u4e00\u4e2a\u7c7b\u65f6\uff0c\u7f16\u8bd1\u8fc7\u7a0b\u5c06\u521b\u5efa\u4e00\u4e2a\u7c7b\u5bf9\u8c61\uff08class object\uff09\uff0c\u5c01\u88c5\u4e86\u7c7b\u5b9a\u4e49\u6240\u521b\u5efa\u7684\u547d\u540d\u7a7a\u95f4\u91cc\u7684\u5185\u5bb9\u3002 \u6700\u521d\u7684\uff08\u5728\u8fdb\u5165\u7c7b\u5b9a\u4e49\u4e4b\u524d\u8d77\u4f5c\u7528\u7684\uff09\u5c40\u90e8\u4f5c\u7528\u57df\u5c06\u91cd\u65b0\u751f\u6548\uff0c\u7c7b\u5bf9\u8c61\uff08class object\uff09\u5c06\u5728\u8fd9\u91cc\u88ab\u7ed1\u5b9a\u5230\u7c7b\u5b9a\u4e49\u5934\u90e8\u6240\u58f0\u660e\u7684\u7c7b\u540d\u79f0 (\u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\u662f ClassName )\u3002 \u7c7b\u5bf9\u8c61 Class Objects \u00b6 \u7c7b\u5bf9\u8c61\u652f\u6301\u4e24\u79cd\u64cd\u4f5c\uff1a\u5c5e\u6027\u5f15\u7528\uff08attribute references\uff09\u548c\u5b9e\u4f8b\u5316\uff08instantiation\uff09\u3002 \u5c5e\u6027\u5f15\u7528\uff08attribute references\uff09 \u4f7f\u7528Python\u4e2d\u5c5e\u6027\u5f15\u7528\u7684\u6807\u51c6\u8bed\u6cd5: obj.name \u3002 \u5b58\u5728\u4e8e\u7c7b\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u6240\u6709\u540d\u79f0\uff0c\u7c7b\u5bf9\u8c61\u88ab\u521b\u5efa\u65f6\u540c\u65f6\u88ab\u521b\u5efa\u4e86\uff0c\u8fd9\u4e9b\u5c31\u662f\u6709\u6548\u7684\u5c5e\u6027\u540d\u79f0\u3002\u56e0\u6b64\uff0c\u5982\u679c\u7c7b\u5b9a\u4e49\u662f\u5982\u4e0b\u6240\u793a\uff0c\u90a3\u4e48 MyClass.i \u548c MyClass.f \u5c31\u662f\u6709\u6548\u7684\u5c5e\u6027\u5f15\u7528\uff0c\u5c06\u5206\u522b\u8fd4\u56de\u4e00\u4e2a\u6574\u6570\u548c\u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\u3002 \u7c7b\u5c5e\u6027\u4e5f\u53ef\u4ee5\u88ab\u8d4b\u503c\uff0c\u56e0\u6b64\u53ef\u4ee5\u901a\u8fc7\u8d4b\u503c\u6765\u66f4\u6539 MyClass.i \u7684\u503c\u3002 __doc__ \u4e5f\u662f\u4e00\u4e2a\u6709\u6548\u7684\u5c5e\u6027\uff0c\u5c06\u8fd4\u56de\u6240\u5c5e\u7c7b\u7684\u6587\u6863\u5b57\u7b26\u4e32: \"A simple example class\"\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' print ( MyClass . i ) # 12345 print ( MyClass . __doc__ ) # A simple example class MyClass . i = 10 print ( MyClass . i ) # 10 \u7c7b\u7684**\u5b9e\u4f8b\u5316\uff08instantiation\uff09**\u4f7f\u7528\u51fd\u6570\u8868\u793a\u6cd5\u3002 \u53ef\u4ee5\u628a\u7c7b\u5bf9\u8c61\uff08class object\uff09\u770b\u4f5c\u662f\u4e00\u4e2a\u4e0d\u5e26\u53c2\u6570\u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u8fd4\u56de\u4e86\u8be5\u7c7b\u7684\u4e00\u4e2a\u65b0\u5b9e\u4f8b\u3002 \u5728\u4e0b\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c x = MyClass() \u521b\u5efa\u4e86 MyClass() \u8fd9\u4e2a\u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u5e76\u8d4b\u503c\u7ed9\u5c40\u90e8\u53d8\u91cf x \u3002 \u5b9e\u4f8b\u5316\u64cd\u4f5c\uff08\u8c03\u7528\u7c7b\u5bf9\u8c61\uff09\u4f1a\u521b\u5efa\u4e00\u4e2a\u7a7a\u5bf9\u8c61\u3002\u8bb8\u591a\u7c7b\u4f1a\u521b\u5efa\u5e26\u6709\u7279\u5b9a\u521d\u59cb\u72b6\u6001\u7684\u81ea\u5b9a\u4e49\u5b9e\u4f8b\u3002\u4e3a\u6b64\u7c7b\u5b9a\u4e49\u4e2d\u9700\u8981\u5305\u542b\u4e00\u4e2a\u540d\u4e3a __init__() \u7684\u7279\u6b8a\u65b9\u6cd5\u3002 \u5f53\u4e00\u4e2a\u7c7b\u5b9a\u4e49\u4e86 __init__() \u65b9\u6cd5\u65f6\uff0c\u7c7b\u7684\u5b9e\u4f8b\u5316\u64cd\u4f5c\u4f1a\u81ea\u52a8\u4e3a\u65b0\u521b\u5efa\u7684\u7c7b\u5b9e\u4f8b\u8c03\u7528 __init__() \u3002 \u66f4\u65b0\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u6ce8\u610f __dict__ \u4e24\u6b21\u8fd4\u56de\u7684\u4e0d\u540c\u7684\u5b57\u5178\u3002\u590d\u4e60\u4e00\u4e0b\uff0c\u5728\u547d\u540d\u7a7a\u95f4\u4e2d\u63d0\u5230\uff0c __dict__ \u662f\u5c5e\u6027\u4f46\u4e0d\u662f\u5168\u5c40\u540d\u79f0\uff0c\u8fd4\u56de\u7528\u4e8e\u5b9e\u73b0\u6a21\u5757\u547d\u540d\u7a7a\u95f4\u7684\u5b57\u5178\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' def __init__ ( self ): self . data = [] x = MyClass () print ( x . __dict__ ) # {'data': []} x . i = 10 print ( x . __dict__ ) # {'data': [], 'i': 10} __init__() \u65b9\u6cd5\u53ef\u4ee5\u6709\u989d\u5916\u7684\u53c2\u6570\u8f93\u5165\uff0c\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u7c7b\u5b9e\u4f8b\u5316\u7684\u53c2\u6570\u5c06\u88ab\u4f20\u9012\u7ed9 __init__() \u3002 \u5982\u4e0b\u4f8b: class Complex : def __init__ ( self , realpart , imagpart ): self . r = realpart self . i = imagpart x = Complex ( 3.0 , - 4.5 ) print ( x . r , x . i ) # 3.0 -4.5 \u5b9e\u4f8b\u5bf9\u8c61 Instance Objects \u00b6 \u5bf9\u5b9e\u4f8b\u5bf9\u8c61\u552f\u4e00\u7684\u64cd\u4f5c\u662f\u5c5e\u6027\u5f15\u7528\u3002\u6709\u4e24\u79cd\u6709\u6548\u7684\u5c5e\u6027\u540d\u79f0\uff1a\u6570\u636e\u5c5e\u6027\uff08data attributes\uff09\u548c\u65b9\u6cd5\uff08methods\uff09\u3002 **\u6570\u636e\u5c5e\u6027\uff08data attributes\uff09**\u7c7b\u4f3c\u4e8e\u5b9e\u4f8b\u53d8\u91cf\uff0c\u6570\u636e\u5c5e\u6027\u4e0d\u9700\u8981\u58f0\u660e\u3002\u50cf\u5c40\u90e8\u53d8\u91cf\u4e00\u6837\uff0c\u6570\u636e\u5c5e\u6027\u5c06\u5728\u7b2c\u4e00\u6b21\u88ab\u8d4b\u503c\u65f6\u4ea7\u751f\u3002 \u4f8b\u5982\uff0c\u5982\u679c x \u662f\u4e0a\u9762\u521b\u5efa\u7684 MyClass \u7684\u5b9e\u4f8b\uff0c\u5219\u4ee5\u4e0b\u4ee3\u7801\u6bb5\u5c06\u6253\u5370\u6570\u503c 16 \uff0c\u4e14\u6ca1\u6709\u7559\u4e0b\u5173\u4e8e x.counter \u7684\u75d5\u8ff9\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' def __init__ ( self ): self . data = [] x = MyClass () x . counter = 1 while x . counter < 10 : x . counter = x . counter * 2 print ( x . counter ) # 16 print ( x . __dict__ ) # {'data': [], 'counter': 16} del x . counter print ( x . __dict__ ) # {'data': []} \u53e6\u4e00\u7c7b\u5b9e\u4f8b\u5c5e\u6027\u5f15\u7528\u79f0\u4e3a**\u65b9\u6cd5\uff08methods\uff09 \u3002 \u65b9\u6cd5\u662f\u96b6\u5c5e\u4e8e\u5bf9\u8c61\u7684**\u51fd\u6570 \u3002 \u5728Python\u4e2d\uff0c\u65b9\u6cd5\u8fd9\u4e2a\u672f\u8bed\u5e76\u4e0d\u662f\u7c7b\u5b9e\u4f8b\u6240\u7279\u6709\u7684\uff0c\u5176\u4ed6\u5bf9\u8c61\u4e5f\u53ef\u4ee5\u6709\u65b9\u6cd5\u3002 \u4f8b\u5982\uff0c\u5217\u8868\u5bf9\u8c61\uff08list objects\uff09\u5177\u6709append, insert, remove, sort\u7b49\u65b9\u6cd5\u3002 \u5728\u4ee5\u4e0b\u8ba8\u8bba\u4e2d\uff0c\u6211\u4eec\u4f7f\u7528\u65b9\u6cd5\u4e00\u8bcd\u5c06\u4e13\u6307\u7c7b\u5b9e\u4f8b\u5bf9\u8c61\u7684\u65b9\u6cd5\uff0c\u9664\u975e\u53e6\u5916\u660e\u786e\u8bf4\u660e\u3002 \u5b9e\u4f8b\u5bf9\u8c61\u7684\u6709\u6548\u65b9\u6cd5\u540d\u79f0\u4f9d\u8d56\u4e8e\u5176\u6240\u5c5e\u7684\u7c7b\u3002 \u6839\u636e\u5b9a\u4e49\uff0c\u4e00\u4e2a\u7c7b\u5b9a\u4e49\u4e2d\u6240\u5305\u542b\u7684\u6240\u6709\u51fd\u6570\u5bf9\u8c61\uff08function objects\uff09\u90fd\u79f0\u4e3a\u5c5e\u6027\u3002 \u56e0\u6b64\u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c x.f \u662f\u6709\u6548\u7684\u65b9\u6cd5\u5f15\u7528\uff0c\u56e0\u4e3a MyClass.f \u662f\u4e00\u4e2a\u51fd\u6570\uff0c\u800c x.i \u4e0d\u662f\u65b9\u6cd5\uff0c\u56e0\u4e3a MyClass.i \u4e0d\u662f\u51fd\u6570\u3002\u4f46\u662f x.f \u4e0e MyClass.f \u5e76\u4e0d\u662f\u4e00\u56de\u4e8b\uff0c x.f \u662f\u4e00\u4e2a**\u65b9\u6cd5\u5bf9\u8c61**\uff0c\u800c MyClass.f \u662f\u4e00\u4e2a**\u51fd\u6570\u5bf9\u8c61**\u3002\u5dee\u522b\u5728\u4e8e f() \u662f\u5426\u4e0e\u5b9e\u4f8b\u7ed1\u5b9a\uff0c\u672a\u7ed1\u5b9a\uff0c\u5c31\u662f\u51fd\u6570\uff0c\u7ed1\u5b9a\uff0c\u5c31\u662f\u65b9\u6cd5\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' def __init__ ( self ): self . data = [] x = MyClass () print ( MyClass . f ( 0 )) # hello world print ( x . f ()) # hello world print ( MyClass . f ) # print ( x . f ) # > print ( type ( MyClass . f )) # print ( type ( x . f )) # \u8fd9\u91cc\u505a\u4e2a\u5c0f\u7ed3\uff1a \u51fd\u6570(function)\u662fPython\u4e2d\u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61(callable), \u65b9\u6cd5(method)\u662f\u4e00\u79cd\u7279\u6b8a\u7684\u51fd\u6570\u3002 \u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61\u662f\u65b9\u6cd5\u548c\u51fd\u6570\uff0c\u548c\u8fd9\u4e2a\u5bf9\u8c61\u65e0\u5173\uff0c\u4ec5\u548c\u8fd9\u4e2a\u5bf9\u8c61\u662f\u5426\u4e0e\u7c7b\u6216\u5b9e\u4f8b\u7ed1\u5b9a\u6709\u5173\uff08bound method\uff09\u3002 \u9759\u6001\u65b9\u6cd5\u6ca1\u6709\u548c\u4efb\u4f55\u7c7b\u6216\u5b9e\u4f8b\u7ed1\u5b9a\uff0c\u6240\u4ee5**\u9759\u6001\u65b9\u6cd5\u662f\u4e2a\u51fd\u6570**\u3002 \u65b9\u6cd5\u5bf9\u8c61 Method Objects \u00b6 \u5728 MyClass \u793a\u4f8b\u4e2d\uff0c x.f() \u662f\u4e00\u4e2a\u65b9\u6cd5\u5bf9\u8c61\uff0c\u88ab\u8c03\u7528\u540e\uff0c\u5c06\u8fd4\u56de\u5b57\u7b26\u4e32 'hello world' \u3002\u53ef\u4ee5\u7acb\u5373\u8c03\u7528\uff0c\u4e5f\u53ef\u4ee5\u4fdd\u5b58\u8d77\u6765\u4ee5\u540e\u518d\u8c03\u7528 xf = x.f \u3002 \u867d\u7136 f() \u7684\u51fd\u6570\u5b9a\u4e49\u6307\u5b9a\u4e86\u4e00\u4e2a\u53c2\u6570\uff0c\u4f46\u4e0a\u9762\u4f8b\u5b50\u4e2d\u8c03\u7528 x.f() \u65f6\u5e76\u6ca1\u6709\u5e26\u53c2\u6570\uff0c\u4e5f\u6ca1\u6709\u5f15\u53d1\u5f02\u5e38\u62a5\u9519\u3002\u539f\u56e0\u5728\u4e8e\uff0c \u65b9\u6cd5(method)\u7684\u7279\u6b8a\u4e4b\u5904\u5c31\u5728\u4e8e\u5b9e\u4f8b\u5bf9\u8c61\u4f1a\u4f5c\u4e3a\u51fd\u6570\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u88ab\u4f20\u5165\u3002 \u8c03\u7528 x.f() \u5176\u5b9e\u5c31\u76f8\u5f53\u4e8e MyClass.f(x) \u3002 \u603b\u4e4b\uff0c\u8c03\u7528\u4e00\u4e2a\u5177\u6709 n \u4e2a\u53c2\u6570\u7684\u65b9\u6cd5(method)\u5c31\u76f8\u5f53\u4e8e\u8c03\u7528\u518d\u591a\u4e00\u4e2a\u53c2\u6570\u7684\u5bf9\u5e94\u51fd\u6570\uff0c\u8fd9\u4e2a\u53c2\u6570\u503c\u4e3a\u65b9\u6cd5\u6240\u5c5e\u5b9e\u4f8b\u5bf9\u8c61\uff0c \u4f4d\u7f6e\u5728\u5176\u4ed6\u53c2\u6570\u4e4b\u524d \u3002 \u5f53\u4e00\u4e2a\u5b9e\u4f8b\u7684\u975e\u6570\u636e\u5c5e\u6027\u88ab\u5f15\u7528\u65f6\uff0c\u5c06\u641c\u7d22\u5b9e\u4f8b\u6240\u5c5e\u7684\u7c7b\u3002 \u5982\u679c\u88ab\u5f15\u7528\u7684\u5c5e\u6027\u540d\u79f0\u662f\u7c7b\u4e2d\u4e00\u4e2a\u6709\u6548\u7684\u51fd\u6570\u5bf9\u8c61\uff0c\u5219\u4f1a\u521b\u5efa\u4e00\u4e2a\u62bd\u8c61\u7684\u5bf9\u8c61\uff0c\u901a\u8fc7\u6253\u5305\uff08parking\uff0c\u5373\u6307\u5411\uff09\u5339\u914d\u5230\u7684\u5b9e\u4f8b\u5bf9\u8c61\u548c\u51fd\u6570\u5bf9\u8c61\uff0c\u8fd9\u4e2a\u62bd\u8c61\u5bf9\u8c61\u5c31\u662f\u65b9\u6cd5\u5bf9\u8c61\u3002 \u5f53\u5e26\u53c2\u6570\u8c03\u7528\u65b9\u6cd5\u5bf9\u8c61\u65f6\uff0c\u5c06\u57fa\u4e8e\u5b9e\u4f8b\u5bf9\u8c61\u548c\u53c2\u6570\u5217\u8868\u6784\u5efa\u4e00\u4e2a\u65b0\u7684\u53c2\u6570\u5217\u8868\uff0c\u5e76\u4f7f\u7528\u8fd9\u4e2a\u65b0\u53c2\u6570\u5217\u8868\u8c03\u7528\u76f8\u5e94\u7684\u51fd\u6570\u5bf9\u8c61\u3002 \u7c7b\u548c\u5b9e\u4f8b\u53d8\u91cf Class and Instance Variables \u00b6 \u4e00\u822c\u6765\u8bf4\uff0c**\u5b9e\u4f8b\u53d8\u91cf**\u7528\u4e8e\u6bcf\u4e2a\u5b9e\u4f8b\u7684\u552f\u4e00\u6570\u636e\uff0c\u800c**\u7c7b\u53d8\u91cf**\u7528\u4e8e\u7c7b\u7684\u6240\u6709\u5b9e\u4f8b\u5171\u4eab\u7684\u5c5e\u6027\u548c\u65b9\u6cd5: class Dog : kind = 'canine' # class variable shared by all instances def __init__ ( self , name ): self . name = name # instance variable unique to each instance d = Dog ( 'Fido' ) e = Dog ( 'Buddy' ) print ( d . kind ) # shared by all dogs # 'canine' print ( e . kind ) # shared by all dogs # 'canine' print ( d . name ) # unique to d instance # 'Fido' print ( e . name ) # unique to e instance # 'Buddy' \u4e0b\u4ee3\u7801\u4e2d\u7684 tricks \u5217\u8868\u4e0d\u5e94\u8be5\u88ab\u7528\u4f5c\u7c7b\u53d8\u91cf\uff0c\u56e0\u4e3a\u6240\u6709\u7684 Dog \u5b9e\u4f8b\u5c06\u53ea\u5171\u4eab\u4e00\u4e2a\u5355\u72ec\u7684\u5217\u8868: class Dog : kind = 'canine' # class variable shared by all instances tricks = [] # mistaken use of a class variable def __init__ ( self , name ): self . name = name # instance variable unique to each instance def add_trick ( self , trick ): self . tricks . append ( trick ) d = Dog ( 'Fido' ) e = Dog ( 'Buddy' ) d . add_trick ( 'roll over' ) e . add_trick ( 'play dead' ) print ( d . tricks ) # ['roll over', 'play dead'] \u6b63\u786e\u7684\u7c7b\u8bbe\u8ba1\u5e94\u8be5\u4f7f\u7528\u5b9e\u4f8b\u53d8\u91cf: class Dog : kind = 'canine' # class variable shared by all instances def __init__ ( self , name ): self . name = name # instance variable unique to each instance self . tricks = [] # creates a new empty list for each dog def add_trick ( self , trick ): self . tricks . append ( trick ) d = Dog ( 'Fido' ) e = Dog ( 'Buddy' ) d . add_trick ( 'roll over' ) e . add_trick ( 'play dead' ) print ( d . tricks ) # ['roll over'] print ( e . tricks ) # ['play dead'] \u5982\u679c\u540c\u6837\u7684\u5c5e\u6027\u540d\u79f0\u540c\u65f6\u51fa\u73b0\u5728\u5b9e\u4f8b\u548c\u7c7b\u4e2d\uff0c\u5219\u5c5e\u6027\u67e5\u627e\u4f1a**\u4f18\u5148\u9009\u62e9\u5b9e\u4f8b**: class Warehouse : purpose = 'storage' region = 'west' w1 = Warehouse () print ( w1 . purpose , w1 . region ) # storage west w2 = Warehouse () w2 . region = 'east' # Instance W2 has higher priority than class print ( w2 . purpose , w2 . region ) # storage east \u6570\u636e\u5c5e\u6027\uff08Data attributes\uff09\u53ef\u4ee5\u88ab\u65b9\u6cd5\uff08method\uff09\u4ee5\u53ca\u4e00\u4e2a\u5bf9\u8c61\u7684\u666e\u901a\u7528\u6237\uff08ordinary users\uff09\uff08\u201c\u5ba2\u6237\u7aefClient\u201d\uff09\u6240\u5f15\u7528\u3002 \u6362\u53e5\u8bdd\u8bf4\uff0c\u7c7b\u4e0d\u80fd\u7528\u4e8e\u5b9e\u73b0\u7eaf\u62bd\u8c61\u6570\u636e\u7c7b\u578b\u3002 \u65b9\u6cd5\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u5e38\u5e38\u88ab\u547d\u540d\u4e3a self \uff0c\u8fd9\u53ea\u662f\u4e00\u4e2a\u7ea6\u5b9a: self \u8fd9\u4e00\u540d\u79f0\u5728Python\u4e2d\u6ca1\u6709\u7279\u6b8a\u542b\u4e49\u3002 \u4f46\u662f\u9075\u5faa\u6b64\u7ea6\u5b9a\u4f1a\u4f7f\u5f97\u4ee3\u7801\u5177\u6709\u5f88\u597d\u7684\u53ef\u8bfb\u6027\u3002 \u4efb\u4f55\u4e00\u4e2a\u4f5c\u4e3a\u7c7b\u5c5e\u6027\uff08class attribute\uff09\u7684\u51fd\u6570\u5bf9\u8c61\uff08function object\uff09\u90fd\u4e3a\u8be5\u7c7b\u7684\u5b9e\u4f8b\u5b9a\u4e49\u4e86\u4e00\u4e2a\u76f8\u5e94\u65b9\u6cd5\u3002 \u51fd\u6570\u5b9a\u4e49\u7684\u6587\u672c\u5e76\u975e\u5fc5\u987b\u5305\u542b\u4e8e\u7c7b\u5b9a\u4e49\u4e4b\u5185\uff1a\u5c06\u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\u8d4b\u503c\u7ed9\u4e00\u4e2a\u5c40\u90e8\u53d8\u91cf\u4e5f\u662f\u53ef\u4ee5\u7684\u3002\u5982\u4e0b\u4f8b\u3002\u73b0\u5728 f , g \u548c h \u90fd\u662f\u7c7b C \u7684\u5f15\u7528\u51fd\u6570\u5bf9\u8c61\u7684\u5c5e\u6027\uff0c\u56e0\u800c\u5b83\u4eec\u5c31\u90fd\u662f\u7c7b C \u7684\u5b9e\u4f8b\u7684\u65b9\u6cd5\uff0c\u5176\u4e2d h \u5b8c\u5168\u7b49\u540c\u4e8e g \u3002\u4f46\u8bf7\u6ce8\u610f\uff0c\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u7684\u53ef\u8bfb\u6027\u975e\u5e38\u4e0d\u597d\u3002 # Function defined outside the class def f1 ( self , x , y ): return min ( x , x + y ) class C : f = f1 # Assign a function object to a local variable in the class def g ( self ): return 'hello world' h = g \u65b9\u6cd5\uff08methods\uff09\u53ef\u4ee5\u901a\u8fc7\u4f7f\u7528 self \u53c2\u6570\u7684\u65b9\u6cd5\u5c5e\u6027\uff08method attributes\uff09\u8c03\u7528\u5176\u4ed6\u65b9\u6cd5\uff08method\uff09: class Bag : def __init__ ( self ): self . data = [] def add ( self , x ): self . data . append ( x ) def addtwice ( self , x ): self . add ( x ) self . add ( x ) \u65b9\u6cd5\u53ef\u4ee5\u901a\u8fc7\u4e0e\u666e\u901a\u51fd\u6570\u76f8\u540c\u7684\u65b9\u5f0f\u5f15\u7528\u5168\u5c40\u540d\u79f0\u3002 \u4e0e\u65b9\u6cd5\u76f8\u5173\u8054\u7684\u5168\u5c40\u4f5c\u7528\u57df\u5c31\u662f\u5305\u542b\u5176\u5b9a\u4e49\u7684\u6a21\u5757\u3002 \uff08\u7c7b\u6c38\u8fdc\u4e0d\u4f1a\u88ab\u4f5c\u4e3a\u5168\u5c40\u4f5c\u7528\u57df\u3002\uff09 \u867d\u7136\u6211\u4eec\u5f88\u5c11\u4f1a\u6709\u5145\u5206\u7684\u7406\u7531\u5728\u65b9\u6cd5\u4e2d\u4f7f\u7528\u5168\u5c40\u4f5c\u7528\u57df\uff0c\u4f46\u5168\u5c40\u4f5c\u7528\u57df\u5b58\u5728\u8bb8\u591a\u5408\u7406\u7684\u4f7f\u7528\u573a\u666f\uff1a\u4e3e\u4e2a\u4f8b\u5b50\uff0c\u5bfc\u5165\u5230\u5168\u5c40\u4f5c\u7528\u57df\u7684\u51fd\u6570\u548c\u6a21\u5757\u53ef\u4ee5\u88ab\u65b9\u6cd5\u6240\u4f7f\u7528\uff0c\u5728\u5176\u4e2d\u5b9a\u4e49\u7684\u51fd\u6570\u548c\u7c7b\u4e5f\u4e00\u6837\u3002 \u901a\u5e38\uff0c\u5305\u542b\u8be5\u65b9\u6cd5\u7684\u7c7b\u672c\u8eab\u662f\u5728\u5168\u5c40\u4f5c\u7528\u57df\u4e2d\u5b9a\u4e49\u7684\u3002 \u603b\u7ed3 \u00b6 \u7c7b\u5b9a\u4e49\u5c0f\u7ed3 \u00b6 \u4e00\u4e2a\u7c7b\u5b9a\u4e49\u7c7b\u6210\u5458\u5c5e\u6027\u548c\u6210\u5458\u65b9\u6cd5\u3002 \u4e00\u4e2a\u7c7b\u53ef\u4ee5\u5b9e\u4f8b\u5316\u591a\u4e2a\u5bf9\u8c61\uff0c\u6bcf\u4e2a\u5b9e\u4f8b\u5316\u5bf9\u8c61\u90fd\u662f\u72ec\u7acb\u7684\u3002 \u521b\u5efa\u7684\u7c7b\u5b9e\u4f8b\u5316\u5bf9\u8c61\uff0c\u4f1a\u5f15\u7528\u7236\u7c7b\u4e2d\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\uff0c\u5e76\u4e0d\u4f1a\u628a\u7c7b\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\u590d\u5236\u7ed9\u5bf9\u8c61\uff0c\u56e0\u6b64\uff1a \u5728\u8bbf\u95ee\u5b9e\u4f8b\u5316\u5bf9\u8c61\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\u65f6\uff0c\u4f1a\u5148\u53bb\u627e\u5bf9\u8c61\u81ea\u5df1\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\uff0c\u7136\u540e\u518d\u53bb\u5b9e\u4f8b\u5316\u8fd9\u4e2a\u5bf9\u8c61\u7684\u7c7b\u4e2d\u67e5\u627e\uff08\u5f15\u7528\uff09\u3002 \u5bf9\u8c61\u6210\u5458\u7684\u6dfb\u52a0\u548c\u4fee\u6539\uff0c\u90fd\u53ea\u4f1a\u5f71\u54cd\u5f53\u524d\u5bf9\u8c61\u81ea\u5df1\uff0c\u4e0d\u4f1a\u5f71\u54cd\u7c7b\u548c\u5176\u5b83\u5bf9\u8c61\u3002 \u5220\u9664\u5bf9\u8c61\u6210\u5458\u7684\u65f6\u5019\uff0c\u5fc5\u987b\u662f\u8be5\u5bf9\u8c61\u81ea\u5df1\u5177\u5907\u7684\u6210\u5458\u624d\u53ef\u4ee5\uff0c\u4e0d\u80fd\u5220\u9664\u7c7b\u4e2d\u5f15\u7528\u7684\u6210\u5458\u3002 \u5bf9\u7c7b\u6210\u5458\u7684\u64cd\u4f5c\uff0c\u4f1a\u5f71\u54cd\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\uff0c\u5305\u62ec\u4e4b\u524d\u521b\u5efa\u7684\u5bf9\u8c61\uff08\u5f15\u7528\uff09\u3002 \u7c7b\u6210\u5458\u64cd\u4f5c\uff08\u4e0d\u63a8\u8350\uff09 \u00b6 \u6210\u5458\u5c5e\u6027\uff1a \u8bbf\u95ee\uff1a ClassName.AttributeName \u4fee\u6539\uff1a ClassName.AttributeName = NewValue \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u5c5e\u6027\u3002 \u6dfb\u52a0\uff1a ClassName.NewAttributeName = Value \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u5c5e\u6027\u3002 \u5220\u9664\uff1a del ClassName.AttributeName \uff0c\u6ce8\u610f\uff0c\u53ea\u80fd\u5220\u9664\u7c7b\u5bf9\u8c61\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u4e0d\u518d\u5177\u6709\u8fd9\u4e2a\u5c5e\u6027\u3002 \u6210\u5458\u65b9\u6cd5\uff1a \u8bbf\u95ee\uff1a ClassName.MethodName() \u4fee\u6539\uff1a ClassName.MethodName = NewFunction \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u65b9\u6cd5\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u6dfb\u52a0\uff1a ClassName.MethodName = Function \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u65b9\u6cd5\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u5220\u9664\uff1a del ClassName.MethodName \uff0c\u6ce8\u610f\uff0c\u53ea\u80fd\u5220\u9664\u7c7b\u5bf9\u8c61\u81ea\u5df1\u7684\u65b9\u6cd5\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u4e0d\u518d\u5177\u6709\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u6210\u5458\u65b9\u6cd5\u4e2d\u7684self \u00b6 self \u53ea\u662f\u4e00\u4e2a\u5f62\u53c2\uff0c\u4e0d\u662f\u5173\u952e\u5b57\u3002 self \u5728\u65b9\u6cd5\uff08method\uff09\u4ee3\u8868\u5f53\u524d\u5bf9\u8c61\u81ea\u5df1\u3002\u524d\u9762\u63d0\u5230\u8fc7\uff0c\u65b9\u6cd5\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u5e38\u5e38\u88ab\u547d\u540d\u4e3a self \uff0c\u8fd9\u53ea\u662f\u4e00\u4e2a\u7ea6\u5b9a\u3002 \u53ef\u4ee5\u4f7f\u7528 self \u5728\u7c7b\u5185\u90e8\u64cd\u4f5c\u6210\u5458\uff08\u6dfb\u52a0\u3001\u4fee\u6539\u3001\u5220\u9664\u7b49\uff09\u3002 \u65b9\u6cd5\u7684\u5206\u7c7b\uff1a \u542b\u6709self\u6216\u8005\u53ef\u4ee5\u63a5\u53d7\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\u7684\u65b9\u6cd5\uff0c\u79f0\u4e3a**\u975e\u7ed1\u5b9a\u7c7b\u65b9\u6cd5**\uff0c\u975e\u7ed1\u5b9a\u7c7b\u7684\u65b9\u6cd5\u53ef\u4ee5\u4f7f\u7528\u5bf9\u8c61\u53bb\u8bbf\u95ee\u3002 \u4e0d\u542b\u6709self\u6216\u8005\u4e0d\u80fd\u63a5\u53d7\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\u7684\u65b9\u6cd5\uff0c\u79f0\u4e3a**\u7ed1\u5b9a\u7c7b\u65b9\u6cd5**\uff0c\u7ed1\u5b9a\u65b9\u6cd5\u53ea\u80fd\u4f7f\u7528\u7c7b\u53bb\u8bbf\u95ee\u3002 \u9b54\u672f\u65b9\u6cd5 \u00b6 \u9b54\u672f\u65b9\u6cd5\uff08Magic Method\uff09\u548c\u666e\u901a\u65b9\u6cd5\u4e00\u6837\uff0c\u90fd\u662f\u7c7b\u4e2d\u5b9a\u4e49\u7684\u6210\u5458\u65b9\u6cd5\u3002 \u9b54\u672f\u65b9\u6cd5\u540d\u79f0\u524d\u540e\u5404\u67092\u4e2a\u4e0b\u5212\u7ebf\uff0c\u6bd4\u5982 __init__ \u9b54\u672f\u65b9\u6cd5\u662f\u4e0d\u9700\u8981\u624b\u52a8\u8c03\u7528\u7684\uff0c\u4f1a\u5728\u67d0\u79cd\u60c5\u51b5\u4e0b\u81ea\u52a8\u89e6\u53d1\uff08\u81ea\u52a8\u6267\u884c\uff09\u3002 \u9b54\u672f\u65b9\u6cd5\u662f\u7cfb\u7edf\u5b9a\u4e49\u597d\u7684\uff0c\u4e0d\u662f\u7528\u6237\u5b9a\u4e49\u7684\u3002 __init__ \u521d\u59cb\u5316\u65b9\u6cd5\uff0c\u4e5f\u79f0\u4f5c**\u6784\u9020\u65b9\u6cd5** \u00b6 \u7c7b\u5b9e\u4f8b\u5316\u5bf9\u8c61\u521b\u5efa\u540e\u81ea\u52a8\u89e6\u53d1\u3002 __init__ \u521d\u59cb\u5316\u65b9\u6cd5\u53ef\u4ee5\u7528\u6765\u5728\u5bf9\u8c61\u5b9e\u4f8b\u5316\u540e\u5b8c\u6210\u5bf9\u8c61\u7684\u521d\u59cb\u5316\uff0c\u6bd4\u5982\u5c5e\u6027\u8d4b\u503c\uff0c\u65b9\u6cd5\u8c03\u7528\u7b49\u3002 __del__ \u6790\u6784\u65b9\u6cd5 \u00b6 \u7c7b\u5b9e\u4f8b\u5316\u5bf9\u8c61\u88ab\u9500\u6bc1\u65f6\u81ea\u52a8\u89e6\u53d1\u3002 __del__ \u6790\u6784\u65b9\u6cd5\u53ef\u4ee5\u5728\u9500\u6bc1\u5bf9\u8c61\u65f6\u5b8c\u6210\u4e00\u4e9b\u7279\u6b8a\u4efb\u52a1\uff0c\u5173\u95ed\u5bf9\u8c61\u6253\u5f00\u7684\u4e00\u4e9b\u8d44\u6e90\uff0c\u5982\u6587\u4ef6\u7b49\u3002 \u6ce8\u610f\uff0c\u662f\u5bf9\u8c61\u88ab\u9500\u6bc1\u65f6\u89e6\u53d1\u4e86\u6790\u6784\u65b9\u6cd5\uff0c\u800c\u4e0d\u662f\u8fd9\u4e2a\u6790\u6784\u65b9\u6cd5\u9500\u6bc1\u4e86\u5bf9\u8c61\u3002 \u5bf9\u8c61\u9500\u6bc1\u7684\u60c5\u51b5\uff1a \u5f53\u7a0b\u5e8f\u6267\u884c\u5b8c\u6bd5\uff0c\u9500\u6bc1\u548c\u91ca\u653e\u5185\u5b58\u4e2d\u7684\u8d44\u6e90\u3002 \u4f7f\u7528 del \u5220\u9664\u65f6\u3002 \u5bf9\u8c61\u4e0d\u518d\u88ab\u4efb\u4f55\u5bf9\u8c61\u5f15\u7528\u65f6\uff0c\u4f1a\u81ea\u52a8\u9500\u6bc1\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5bf9\u6bd4 bmw = Car('BMW') \u548c Car('BMW') \u6765\u7406\u89e3 init \u548c del \u7684\u89e6\u53d1\u673a\u5236\u3002 \u7f16\u8f91\u6587\u4ef6 file1.py class Car (): brand = \"\" def __init__ ( self , car_brand ): self . brand = car_brand print ( f \"initial method called, create { self . brand } car\" ) def __del__ ( self ): print ( f \"delete method called, destroy { self . brand } car\" ) bmw = Car ( 'BMW' ) vw = Car ( 'VW' ) \u6267\u884c\u4e0a\u9762\u7684\u4ee3\u7801 python3 file1.py \u5f97\u5230\u5982\u4e0b\u8f93\u51fa\uff0c\u5728\u7a0b\u5e8f\u6267\u884c\u5b8c\u6bd5\u65f6\uff0c\u4f9d\u6b21\u6267\u884c __del__ \u3002 initial method called , create BMW car initial method called , create VW car delete method called , destroy BMW car delete method called , destroy VW car \u7f16\u8f91\u6587\u4ef6 file2.py class Car (): brand = \"\" def __init__ ( self , car_brand ): self . brand = car_brand print ( f \"initial method called, create { self . brand } car\" ) def __del__ ( self ): print ( f \"delete method called, destroy { self . brand } car\" ) Car ( 'BMW' ) Car ( 'VW' ) \u6267\u884c\u4e0a\u9762\u7684\u4ee3\u7801 python3 file2.py \u5f97\u5230\u5982\u4e0b\u8f93\u51fa\uff1a initial method called , create BMW car delete method called , destroy BMW car initial method called , create VW car delete method called , destroy VW car Python\u51fd\u6570\u5185\u7701\u5185\u7701 \u00b6 \u4ece\u9b54\u672f\u65b9\u6cd5\u53ef\u4ee5\u5ef6\u7533\u5230Python\u7684**\u51fd\u6570\u5185\u7701**\uff0c\u51fd\u6570\u5185\u7701\u7684\u610f\u601d\u662f\u8bf4\uff0c\u5f53\u4f60\u62ff\u5230\u4e00\u4e2a\u201c\u51fd\u6570\u5bf9\u8c61\u201d\u7684\u65f6\u5019\uff0c\u4f60\u53ef\u4ee5\u7ee7\u7eed\u77e5\u9053\uff0c\u5b83\u7684\u540d\u5b57\uff0c\u53c2\u6570\u5b9a\u4e49\u7b49\u4fe1\u606f\u3002\u8fd9\u4e9b\u4fe1\u606f\u53ef\u4ee5\u901a\u8fc7\u51fd\u6570\u5bf9\u8c61\u7684\u5c5e\u6027\uff08\u4e00\u4e9b\u53cc\u4e0b\u5212\u7ebf\u7684\u9b54\u6cd5\u65b9\u6cd5\uff09\u5f97\u5230\u3002\u7b80\u8a00\u4e4b\uff0c\u5185\u7701\u662f\u5728\u8fd0\u884c\u65f6\u786e\u5b9a\u5bf9\u8c61\u7c7b\u578b\u7684\u80fd\u529b\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u5217\u51fa\u4e86\u5e38\u89c4\u5bf9\u8c61\u6ca1\u6709\u800c\u51fd\u6570\u6709\u7684\u5c5e\u6027\u3002 class C : pass obj = C () def func (): pass sorted ( set ( dir ( obj )) - set ( dir ( func ))) # ['__weakref__'] sorted ( set ( dir ( func )) - set ( dir ( obj ))) # ['__annotations__', '__call__', '__closure__', '__code__', '__defaults__', '__get__', '__globals__', '__kwdefaults__', '__name__', '__qualname__'] \u4e0b\u8868\u603b\u7ed3\u4e86\u7528\u6237\u5b9a\u4e49\u7684\u51fd\u6570\u7684\u5c5e\u6027\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u6f14\u793a\u4e86\u5728\u6307\u5b9a\u957f\u5ea6\u9644\u8fd1\u622a\u65ad\u5b57\u7b26\u4e32\u7684\u51fd\u6570\uff0c\u4ee5\u53ca\u63d0\u53d6\u5173\u4e8e\u51fd\u6570\u53c2\u6570\u7684\u4fe1\u606f\u7684\u65b9\u6cd5\u3002 \u53c2\u6570\u540d\u79f0\u5728 __code__.co_varnames \u4e2d\uff0c\u4f46\u8fd9\u91cc\u9762\u4e5f\u5305\u542b\u51fd\u6570\u5b9a\u4e49\u4f53\u4e2d\u521b\u5efa\u7684\u5c40\u90e8\u53d8\u91cf\u3002\u56e0\u6b64\uff0c\u53c2\u6570\u540d\u79f0\u662f\u524d N \u4e2a\u5b57\u7b26\u4e32\uff0c N \u7684\u503c\u7531 __code__.co_argcount \u786e\u5b9a\uff0c\u4f8b\u5b50\u91cc\u9762N\u662f2\uff0c\u5373\u53c2\u6570\u540d\u79f0\u662f text \u548c max_len \uff0c\u5c40\u90e8\u53d8\u91cf\u662f end \u3001 space_before \u3001 space_after \u3002 def clip ( text , max_len = 80 ): \"\"\" Get sub-string by the first blank before or after specified position. rfind() \u8fd4\u56de\u5b57\u7b26\u4e32\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u9879\u5219\u8fd4\u56de -1. \"\"\" end = None if len ( text ) > max_len : space_before = text . rfind ( ' ' , 0 , max_len ) if space_before >= 0 : end = space_before else : space_after = text . rfind ( ' ' , max_len ) if space_after >= 0 : end = space_after if end is None : end = len ( text ) return text [: end ] . rstrip () clip ( 'This is the string' , max_len = 10 ) # 'This is' clip . __defaults__ # (80,) clip . __code__ # \", line 1> clip . __code__ . co_varnames # ('text', 'max_len', 'end', 'space_before', 'space_after') clip . __code__ . co_argcount # 2 clip . __doc__ # '\\n Get sub-string by the first blank before or after specified position.\\n rfind() \u8fd4\u56de\u5b57\u7b26\u4e32\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u9879\u5219\u8fd4\u56de -1.\\n ' \u4e0a\u4f8b\u4e2d\uff0c\u53c2\u6570\u7684\u9ed8\u8ba4\u503c\u53ea\u80fd\u901a\u8fc7\u5b83\u4eec\u5728 __defaults__ \u5143\u7ec4\u4e2d\u7684\u4f4d\u7f6e\u786e\u5b9a\uff0c\u56e0\u6b64\u8981\u4ece\u540e\u5411\u524d\u626b\u63cf\u624d\u80fd\u628a\u53c2\u6570\u548c\u9ed8\u8ba4\u503c\u5bf9\u5e94\u8d77\u6765\uff0c\u6709\u4e9b\u4e0d\u5408\u7406\u3002\u5f15\u5165 inspect \u6a21\u5757\u540e\uff0c\u4e0a\u9762\u7684\u64cd\u4f5c\u5c31\u66f4\u5bb9\u6613\u4e86\u3002 inspect.signature \u51fd\u6570\u8fd4\u56de\u4e00\u4e2a inspect.Signature \u5bf9\u8c61\uff0c\u5b83\u6709\u4e00\u4e2a parameters \u5c5e\u6027\uff0c\u8fd9\u662f\u4e00\u4e2a\u6709\u5e8f\u6620\u5c04\uff0c\u628a\u53c2\u6570\u540d\u548c inspect.Parameter \u5bf9\u8c61\u5bf9\u5e94\u8d77\u6765\u3002\u5404\u4e2a Parameter \u5c5e\u6027\u4e5f\u6709\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u4f8b\u5982 name \u3001 default \u548c kind \u3002 from inspect import signature sig = signature ( clip ) type ( sig ) # print ( sig ) # (text, max_len=80) print ( str ( sig )) # (text, max_len=80) for name , param in sig . parameters . items (): print ( f ' { param . kind } : { name } = { param . default } ' ) # 1 : text = # 1 : max_len = 80 \u51fd\u6570\u6ce8\u89e3\u3002 Python 3 \u63d0\u4f9b\u4e86\u4e00\u79cd\u53e5\u6cd5\uff0c\u7528\u4e8e\u4e3a\u51fd\u6570\u58f0\u660e\u4e2d\u7684\u53c2\u6570\u548c\u8fd4\u56de\u503c\u9644\u52a0\u5143\u6570\u636e\u3002\u5bf9\u4e0a\u4f8b\u6dfb\u52a0\u6ce8\u89e3\u540e\u5982\u4e0b\u6240\u793a\uff0c\u4e8c\u8005\u552f\u4e00\u7684\u533a\u522b\u5728\u7b2c\u4e00\u884c\u3002 \u51fd\u6570\u58f0\u660e\u4e2d\u7684\u5404\u4e2a\u53c2\u6570\u53ef\u4ee5\u5728:\u4e4b\u540e\u589e\u52a0\u6ce8\u89e3\u8868\u8fbe\u5f0f\u3002 \u5982\u679c\u53c2\u6570\u6709\u9ed8\u8ba4\u503c\uff0c\u6ce8\u89e3\u653e\u5728\u53c2\u6570\u540d\u548c = \u53f7\u4e4b\u95f4\u3002 \u5982\u679c\u60f3\u6ce8\u89e3\u8fd4\u56de\u503c\uff0c\u5728)\u548c\u51fd\u6570\u58f0\u660e\u672b\u5c3e\u7684 : \u4e4b\u95f4\u6dfb\u52a0 -> \u548c\u4e00\u4e2a\u8868\u8fbe\u5f0f\u3002\u90a3\u4e2a\u8868\u8fbe\u5f0f\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\u3002 \u6ce8\u89e3\u4e2d\u6700\u5e38\u7528\u7684\u7c7b\u578b\u662f\u7c7b\uff08\u5982 str \u6216 int \uff09\u548c\u5b57\u7b26\u4e32\uff08\u5982'int > 0'\uff09\u3002\u5728\u4e0b\u4f8b\u4e2d\uff0cmax_len\u53c2\u6570\u7684\u6ce8\u89e3\u7528\u7684\u662f\u5b57\u7b26\u4e32\u3002 \u6ce8\u89e3\u4e0d\u4f1a\u505a\u4efb\u4f55\u5904\u7406\uff0c\u53ea\u662f\u5b58\u50a8\u5728\u51fd\u6570\u7684 __annotations__ \u5c5e\u6027\uff08\u4e00\u4e2a\u5b57\u5178\uff09\u4e2d\u3002\u6362\u53e5\u8bdd\u8bf4\uff0c\u6ce8\u89e3\u5bf9Python\u89e3\u91ca\u5668\u6ca1\u6709\u4efb\u4f55\u610f\u4e49\u3002 \u6ce8\u89e3\u53ea\u662f\u5143\u6570\u636e \uff0c\u53ef\u4ee5\u4f9bIDE\u3001\u6846\u67b6\u548c\u88c5\u9970\u5668\u7b49\u5de5\u5177\u4f7f\u7528\u3002 return \u952e\u4fdd\u5b58\u7684\u662f\u8fd4\u56de\u503c\u6ce8\u89e3\uff0c\u5373\u4e0b\u4f8b\u4e2d\u51fd\u6570\u58f0\u660e\u91cc\u4ee5 -> \u6807\u8bb0\u7684\u90e8\u5206\u3002 def clip ( text : str , max_len : 'int > 0' = 80 ) -> str : \"\"\" Get sub-string by the first blank before or after specified position. rfind() \u8fd4\u56de\u5b57\u7b26\u4e32\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u9879\u5219\u8fd4\u56de -1. \"\"\" end = None if len ( text ) > max_len : space_before = text . rfind ( ' ' , 0 , max_len ) if space_before >= 0 : end = space_before else : space_after = text . rfind ( ' ' , max_len ) if space_after >= 0 : end = space_after if end is None : end = len ( text ) return text [: end ] . rstrip () clip ( 'This is the string' , max_len = 10 ) # 'This is' clip . __annotations__ # {'text': , 'max_len': 'int > 0', 'return': } signature \u51fd\u6570\u8fd4\u56de\u4e00\u4e2a Signature \u5bf9\u8c61\uff0c\u5b83\u6709\u4e00\u4e2a return_annotation \u5c5e\u6027\u548c\u4e00\u4e2a parameters \u5c5e\u6027\uff0c\u540e\u8005\u662f\u4e00\u4e2a\u5b57\u5178\uff0c\u628a\u53c2\u6570\u540d\u6620\u5c04\u5230 Parameter \u5bf9\u8c61\u4e0a\u3002\u6bcf\u4e2a Parameter \u5bf9\u8c61\u81ea\u5df1\u4e5f\u6709 annotation \u5c5e\u6027\u3002 from inspect import signature sig = signature ( clip ) print ( sig . return_annotation ) # for param in sig . parameters . values (): note = repr ( param . annotation ) . ljust ( 13 ) print ( f ' { note } : { param . name } = { param . default } ' ) # : text = # 'int > 0' : max_len = 80","title":"Python\u9762\u5411\u5bf9\u8c61\u6982\u5ff5"},{"location":"python/Foundation/ch04/#python","text":"\u7c7b(class)\u628a\u6570\u636e\u4e0e\u529f\u80fd\u7ed1\u5b9a\u5728\u4e00\u8d77\u3002\u521b\u5efa\u65b0\u7c7b\u5c31\u662f\u521b\u5efa\u65b0\u7684\u5bf9\u8c61\u7c7b\u578b\uff08type of object\uff09\uff0c\u4ece\u800c\u521b\u5efa\u8be5\u7c7b\u578b\u7684\u65b0\u5b9e\u4f8b\uff08instances\uff09\u3002 \u7c7b\u5b9e\u4f8b\u5177\u6709\u591a\u79cd\u4fdd\u6301\u81ea\u8eab\u72b6\u6001\u7684\u5c5e\u6027\uff08attributes\uff09\u3002 \u7c7b\u5b9e\u4f8b\u8fd8\u652f\u6301\uff08\u7531\u7c7b\u5b9a\u4e49\u7684\uff09\u4fee\u6539\u81ea\u8eab\u72b6\u6001\u7684\u65b9\u6cd5\uff08methods\uff09\u3002 Python\u7684\u7c7b\u652f\u6301\u6240\u6709\u9762\u5411\u5bf9\u8c61\u7f16\u7a0b\uff08OOP\uff09\u7684\u6807\u51c6\u7279\u6027\uff1a \u7c7b\u7ee7\u627f\uff08class inheritance\uff09\u673a\u5236\u652f\u6301\u591a\u4e2a\u57fa\u7c7b\uff08base classes\uff09\uff1b \u6d3e\u751f\u7c7b\uff08derived class\uff09\u53ef\u4ee5\u8986\u76d6\u57fa\u7c7b\u7684\u4efb\u4f55\u65b9\u6cd5\uff08methods\uff09\uff1b \u7c7b\u7684\u65b9\u6cd5\u53ef\u4ee5\u8c03\u7528\u57fa\u7c7b\u4e2d\u76f8\u540c\u540d\u79f0\u7684\u65b9\u6cd5 \u5bf9\u8c61\u53ef\u4ee5\u5305\u542b\u4efb\u610f\u6570\u91cf\u548c\u7c7b\u578b\u7684\u6570\u636e\u3002 \u7c7b\uff08class\uff09\u548c\u6a21\u5757\uff08module\uff09\u90fd\u62e5\u6709\u52a8\u6001\u7279\u6027\uff08dynamic nature\uff09\uff1a\u5728\u8fd0\u884c\u65f6\u521b\u5efa\uff0c\u521b\u5efa\u540e\u4e5f\u53ef\u4ee5\u4fee\u6539\u3002","title":"Python\u9762\u5411\u5bf9\u8c61\u6982\u5ff5"},{"location":"python/Foundation/ch04/#namesobjects","text":"\u5bf9\u8c61\u4e4b\u95f4\u76f8\u4e92\u72ec\u7acb\uff0c\u591a\u4e2a\u540d\u79f0\uff08names\uff09\uff08\u5728\u591a\u4e2a\u4f5c\u7528\u57df\u5185\uff09\u53ef\u4ee5\u7ed1\u5b9a\u5230\u540c\u4e00\u4e2a\u5bf9\u8c61\u3002 \u5176\u4ed6\u8bed\u8a00\u79f0\u4e4b\u4e3a\u522b\u540d\uff08alias\uff09\u3002 \u522b\u540d\u5728\u67d0\u4e9b\u65b9\u9762\u5c31\u50cf\u6307\u9488\u3002\u4f8b\u5982\uff0c\u4f20\u9012\u5bf9\u8c61\u7684\u4ee3\u4ef7\u5f88\u5c0f\uff0c\u56e0\u4e3a\u5b9e\u73b0\u53ea\u4f20\u9012\u4e00\u4e2a\u6307\u9488\uff1b\u5982\u679c\u51fd\u6570\u4fee\u6539\u4e86\u4f5c\u4e3a\u53c2\u6570\u4f20\u9012\u7684\u5bf9\u8c61\uff0c\u8c03\u7528\u8005\u5c31\u53ef\u4ee5\u770b\u5230\u66f4\u6539\u3002","title":"\u540d\u79f0Names\u548c\u5bf9\u8c61Objects"},{"location":"python/Foundation/ch04/#scopesnamespaces","text":"**\u547d\u540d\u7a7a\u95f4\uff08namespace\uff09**\u662f\u4e00\u4e2a\u4ece\u540d\u5b57\u5230\u5bf9\u8c61\u7684\u6620\u5c04\u3002 \u5f53\u524d\u5927\u90e8\u5206\u547d\u540d\u7a7a\u95f4\u90fd\u7531 Python \u5b57\u5178\u5b9e\u73b0\u3002 \u4e0b\u9762\u662f\u51e0\u4e2a\u547d\u540d\u7a7a\u95f4\u7684\u4f8b\u5b50\uff1a \u5b58\u653e\u5185\u7f6e\u51fd\u6570\u7684\u96c6\u5408\uff08\u5305\u542b abs() \u8fd9\u6837\u7684\u51fd\u6570\uff0c\u548c\u5185\u5efa\u7684\u5f02\u5e38\u7b49\uff09\uff1b \u6a21\u5757\u4e2d\u7684\u5168\u5c40\u540d\u79f0\uff1b \u51fd\u6570\u8c03\u7528\u4e2d\u7684\u5c40\u90e8\u540d\u79f0\uff1b \u4ece\u67d0\u79cd\u610f\u4e49\u4e0a\u8bf4\uff0c \u5bf9\u8c61\u7684\u5c5e\u6027\u96c6\u5408\uff08the set of attributes of an object\uff09\u4e5f\u662f\u4e00\u79cd\u547d\u540d\u7a7a\u95f4\u7684\u5f62\u5f0f \u3002 \u5173\u4e8e\u547d\u540d\u7a7a\u95f4\u7684\u91cd\u8981\u4e00\u70b9\u662f\uff0c\u4e0d\u540c\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u540d\u79f0\u4e4b\u95f4\u7edd\u5bf9\u6ca1\u6709\u5173\u7cfb\uff1b \u4f8b\u5982\uff0c\u5728\u4e24\u4e2a\u4e0d\u540c\u7684\u6a21\u5757\u4e2d\u90fd\u53ef\u4ee5\u5b9a\u4e49\u4e00\u4e2a maximize \u51fd\u6570\u800c\u4e0d\u4f1a\u4ea7\u751f\u6df7\u6dc6\uff0c\u4f46\u5728\u8c03\u7528 maximize \u51fd\u6570\u65f6\u5fc5\u987b\u5fc5\u987b\u5728\u5176\u524d\u9762\u52a0\u4e0a\u6a21\u5757\u540d\u79f0\u3002 \u4efb\u4f55\u8ddf\u5728\u4e00\u4e2a\u70b9\u53f7\u4e4b\u540e\u7684\u540d\u79f0\u90fd\u79f0\u4e3a**\u5c5e\u6027\uff08attribute\uff09**\u3002\u4f8b\u5982\uff0c\u5728\u8868\u8fbe\u5f0f z.real \u4e2d\uff0c real \u662f\u5bf9\u8c61 z \u7684\u4e00\u4e2a\u5c5e\u6027\u3002 \u6309\u4e25\u683c\u7684\u8bf4\u6cd5\uff0c \u5bf9\u6a21\u5757\uff08module\uff09\u4e2d\u7684\u540d\u79f0\u7684\u5f15\u7528\uff08reference\uff09\u90fd\u5c5e\u4e8e\u5c5e\u6027\u5f15\u7528\uff08attribute reference\uff09 \uff1a \u5728\u8868\u8fbe\u5f0f modname.funcname \u4e2d\uff0c modname \u662f\u4e00\u4e2a\u6a21\u5757\u5bf9\u8c61\uff08module object\uff09\u800c funcname \u662f\u5b83\u7684\u4e00\u4e2a\u5c5e\u6027\u3002 \u5728\u6b64\u60c5\u51b5\u4e0b\u5728\u6a21\u5757\u7684\u5c5e\u6027\uff08module\u2019s attribute\uff09\u548c\u6a21\u5757\u4e2d\u5b9a\u4e49\u7684\u5168\u5c40\u540d\u79f0\u4e4b\u95f4\u6b63\u597d\u5b58\u5728\u4e00\u4e2a\u76f4\u89c2\u7684\u6620\u5c04\uff1a\u5b83\u4eec\u5171\u4eab\u76f8\u540c\u7684\u547d\u540d\u7a7a\u95f4\u3002 \u4f46\u5b58\u5728\u4e00\u4e2a\u4f8b\u5916\u3002 \u6a21\u5757\u5bf9\u8c61\u6709\u4e00\u4e2a\u53ea\u8bfb\u5c5e\u6027 __dict__ \uff0c\u5b83\u8fd4\u56de\u7528\u4e8e\u5b9e\u73b0\u6a21\u5757\u547d\u540d\u7a7a\u95f4\u7684\u5b57\u5178\uff1b __dict__ \u662f\u5c5e\u6027\u4f46\u4e0d\u662f\u5168\u5c40\u540d\u79f0\u3002 \u4f7f\u7528\u8fd9\u4e2a\u5c06\u8fdd\u53cd\u547d\u540d\u7a7a\u95f4\u5b9e\u73b0\u7684\u62bd\u8c61\uff0c\u5e94\u5f53\u4ec5\u88ab\u7528\u4e8e\u4e8b\u540e\u8c03\u8bd5\u5668\u4e4b\u7c7b\u7684\u573a\u5408\u3002 **\u5c5e\u6027\uff08attribute\uff09**\u53ef\u4ee5\u662f\u53ea\u8bfb\u6216\u8005\u53ef\u5199\u7684\uff0c\u6240\u4ee5\u53ef\u4ee5\u5bf9\u5c5e\u6027\u8fdb\u884c\u8d4b\u503c\uff0c\u4f8b\u5982 modname.the_answer = 42 \u3002 \u5220\u9664\u5c5e\u6027\u53ef\u4ee5\u7528del\u8bed\u53e5\uff0c\u4f8b\u5982\uff0c del modname.the_answer \u5c06\u4f1a\u4ece\u540d\u4e3a modname \u7684\u5bf9\u8c61\u4e2d\u79fb\u9664 the_answer \u5c5e\u6027\u3002 \u547d\u540d\u7a7a\u95f4\u5728\u4e0d\u540c\u65f6\u523b\u88ab\u521b\u5efa\uff0c\u62e5\u6709\u4e0d\u540c\u7684\u751f\u5b58\u671f\uff08lifetimes\uff09\u3002\u5305\u542b\u5185\u7f6e\u540d\u79f0\uff08built-in names\uff09\u7684\u547d\u540d\u7a7a\u95f4\u662f\u5728Python\u89e3\u91ca\u5668\u542f\u52a8\u65f6\u521b\u5efa\u7684\uff0c\u6c38\u8fdc\u4e0d\u4f1a\u88ab\u5220\u9664\u3002 \u6a21\u5757\u7684\u5168\u5c40\u547d\u540d\u7a7a\u95f4\uff08global namespace\uff09\u5728\u6a21\u5757\u5b9a\u4e49\u88ab\u8bfb\u5165\u65f6\u521b\u5efa\uff1b\u901a\u5e38\uff0c\u6a21\u5757\u547d\u540d\u7a7a\u95f4\u4e5f\u4f1a\u6301\u7eed\u5230\u89e3\u91ca\u5668\u9000\u51fa\u3002 \u88ab\u89e3\u91ca\u5668\u7684\u9876\u5c42\u8c03\u7528\uff08top-level invocation\uff09\u6267\u884c\u7684\u8bed\u53e5\uff0c\u4ece\u4e00\u4e2a\u811a\u672c\u6587\u4ef6\u8bfb\u53d6\u6216\u4ea4\u4e92\u5f0f\u5730\u8bfb\u53d6\uff0c\u88ab\u8ba4\u4e3a\u662f __main__ \u6a21\u5757\u8c03\u7528\u7684\u4e00\u90e8\u5206\uff0c\u56e0\u6b64\u5b83\u4eec\u62e5\u6709\u81ea\u5df1\u7684\u5168\u5c40\u547d\u540d\u7a7a\u95f4\u3002 \u5185\u7f6e\u540d\u79f0\uff08built-in names\uff09\u5b9e\u9645\u4e0a\u4e5f\u5b58\u5728\u4e8e\u4e00\u4e2a\u6a21\u5757\u4e2d\uff0c\u8fd9\u4e2a\u6a21\u5757\u88ab\u79f0\u4f5c builtins \u3002 \u4e00\u4e2a\u51fd\u6570\u7684\u672c\u5730\u547d\u540d\u7a7a\u95f4\uff08local namespace\uff09\u5728\u8fd9\u4e2a\u51fd\u6570\u88ab\u8c03\u7528\u65f6\u521b\u5efa\uff0c\u5e76\u5728\u51fd\u6570\u8fd4\u56de\u6216\u629b\u51fa\u4e00\u4e2a\u65e0\u6cd5\u5728\u8be5\u51fd\u6570\u5185\u90e8\u5904\u7406\u7684\u9519\u8bef\u65f6\u88ab\u5220\u9664\u3002 \u6bcf\u6b21\u9012\u5f52\u8c03\u7528\uff08recursive invocations\uff09\u90fd\u4f1a\u6709\u5b83\u81ea\u5df1\u7684\u672c\u5730\u547d\u540d\u7a7a\u95f4\u3002 \u4e00\u4e2a**\u4f5c\u7528\u57df\uff08scope\uff09**\u662f\u4e00\u4e2a\u547d\u540d\u7a7a\u95f4\u53ef\u76f4\u63a5\u8bbf\u95ee\uff08directly accessible\uff09\u7684Python\u7a0b\u5e8f\u7684\u4ee3\u7801\u533a\u57df\u3002 \u8fd9\u91cc\u7684 \u201c\u53ef\u76f4\u63a5\u8bbf\u95ee\u201d \u610f\u5473\u7740\u4e0d\u52a0\u4efb\u4f55\u9650\u5b9a\u7684\u540d\u79f0\u5f15\u7528\u4f1a\u5728\u547d\u540d\u7a7a\u95f4\u4e2d\u8fdb\u884c\u67e5\u627e\u3002 \u867d\u7136\u4f5c\u7528\u57df\u662f\u9759\u6001\u5730\u786e\u5b9a\u7684\uff0c\u4f46\u5b83\u4eec\u4f1a\u88ab\u52a8\u6001\u5730\u4f7f\u7528\u3002 \u5728\u4ee3\u7801\u6267\u884c\u671f\u95f4\u7684\u4efb\u4f55\u65f6\u523b\uff0c\u4f1a\u67093\u62164\u4e2a\u7684\u5d4c\u5957\u4f5c\u7528\u57df\u4f9b\u547d\u540d\u7a7a\u95f4\u76f4\u63a5\u8bbf\u95ee: \u6700\u5148\u641c\u7d22\u7684\u6700\u5185\u90e8\u4f5c\u7528\u57df\u5305\u542b\u5c40\u90e8\u540d\u79f0 \u4ece\u6700\u8fd1\u7684\u5c01\u95ed\u4f5c\u7528\u57df\u5f00\u59cb\u641c\u7d22\u7684\u4efb\u4f55\u5c01\u95ed\u51fd\u6570\u7684\u4f5c\u7528\u57df\u5305\u542b\u975e\u5c40\u90e8\u540d\u79f0\uff0c\u4e5f\u5305\u62ec\u975e\u5168\u5c40\u540d\u79f0 \u5012\u6570\u7b2c\u4e8c\u4e2a\u4f5c\u7528\u57df\u5305\u542b\u5f53\u524d\u6a21\u5757\u7684\u5168\u5c40\u540d\u79f0 \u6700\u5916\u9762\u7684\u4f5c\u7528\u57df\uff08\u6700\u540e\u641c\u7d22\uff09\u662f\u5305\u542b\u5185\u7f6e\u540d\u79f0\u7684\u547d\u540d\u7a7a\u95f4 \u5982\u679c\u4e00\u4e2a\u540d\u79f0\u88ab\u58f0\u660e\u4e3a\u5168\u5c40\u53d8\u91cf\uff0c\u5219\u6240\u6709\u5f15\u7528\u548c\u8d4b\u503c\u5c06\u76f4\u63a5\u6307\u5411\u8be5\u6a21\u5757\u5168\u5c40\u540d\u79f0\u6240\u5728\u7684\u4e2d\u95f4\u4f5c\u7528\u57df\u3002 \u5982\u679c\u8981\u91cd\u65b0\u7ed1\u5b9a\u5728\u6700\u5185\u5c42\u4f5c\u7528\u57df\u4ee5\u5916\u7684\u53d8\u91cf\uff0c\u53ef\u4ee5\u4f7f\u7528 nonlocal \u8bed\u53e5\u58f0\u660e\u4e3a\u975e\u672c\u5730\u53d8\u91cf\u3002 \u5982\u679c\u6ca1\u6709\u88ab\u58f0\u660e\u4e3a\u975e\u672c\u5730\u53d8\u91cf\uff0c\u8fd9\u4e9b\u53d8\u91cf\u5c06\u662f\u53ea\u8bfb\u7684\u3002\u7ed9\u8fd9\u6837\u7684\u53d8\u91cf\u8d4b\u65b0\u503c\u53ea\u4f1a\u5728\u6700\u5185\u5c42\u4f5c\u7528\u57df\u4e2d\u521b\u5efa\u4e00\u4e2a*\u65b0\u7684*\u5c40\u90e8\u53d8\u91cf\uff0c\u800c\u540c\u540d\u7684\u5916\u90e8\u5168\u5c40\u53d8\u91cf\u5c06\u4fdd\u6301\u4e0d\u53d8\u3002 \u901a\u5e38\uff0c\u5f53\u524d\u5c40\u90e8\u4f5c\u7528\u57df\uff08local scope\uff09\u5c06\u5f15\u7528\u5f53\u524d\u51fd\u6570\u4f5c\u7528\u57df\u7684\u540d\u79f0\uff08local name\uff09\u3002 \u5728\u51fd\u6570\u4f5c\u7528\u57df\u4ee5\u5916\uff0c\u5f53\u524d\u5c40\u90e8\u4f5c\u7528\u57df\u5c06\u5f15\u7528\u4e0e\u5168\u5c40\u4f5c\u7528\u57df\u76f8\u4e00\u81f4\u7684\u547d\u540d\u7a7a\u95f4\uff1a\u6a21\u5757\u7684\u547d\u540d\u7a7a\u95f4\uff08the module\u2019s namespace\uff09\u3002 \u5b9a\u4e49\u4e00\u4e2a\u7c7b\uff0c\u662f\u5728\u672c\u5730\u5c40\u90e8\u547d\u540d\u7a7a\u95f4\u5185\u5efa\u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u3002 \u5728\u4e00\u4e2a\u6a21\u5757\uff08module \uff09\u5185\u5b9a\u4e49\u7684\u51fd\u6570\u7684\u4f5c\u7528\u57df\u5c31\u662f\u8be5\u6a21\u5757\u7684\u547d\u540d\u7a7a\u95f4\uff0c\u65e0\u8bba\u8be5\u51fd\u6570\u4ece\u4ec0\u4e48\u5730\u65b9\u6216\u4ee5\u4ec0\u4e48\u522b\u540d\u88ab\u8c03\u7528\u3002 \u53e6\u4e00\u65b9\u9762\uff0c\u5b9e\u9645\u7684\u540d\u79f0\u641c\u7d22\u662f\u5728\u8fd0\u884c\u65f6\u52a8\u6001\u5b8c\u6210\u7684\u3002 \u4f46\u662f\uff0cPython\u6b63\u5728\u671d\u7740\u201c\u7f16\u8bd1\u65f6\u9759\u6001\u540d\u79f0\u89e3\u6790\u201d\u7684\u65b9\u5411\u53d1\u5c55\uff0c\u56e0\u6b64\u4e0d\u8981\u8fc7\u4e8e\u4f9d\u8d56\u52a8\u6001\u540d\u79f0\u89e3\u6790\uff01\u4e8b\u5b9e\u4e0a\uff0c\u5c40\u90e8\u53d8\u91cf\u5df2\u7ecf\u662f\u88ab\u9759\u6001\u786e\u5b9a\u4e86\u3002 \u5982\u679c\u4e0d\u5b58\u5728\u751f\u6548\u7684 global \u6216 nonlocal \u8bed\u53e5\uff0c\u5219\u5bf9\u540d\u79f0\u7684\u8d4b\u503c\u603b\u662f\u4f1a\u8fdb\u5165\u6700\u5185\u5c42\u4f5c\u7528\u57df\u3002\u8d4b\u503c\u4e0d\u4f1a\u590d\u5236\u6570\u636e\uff0c\u662f\u5c06\u540d\u79f0\u7ed1\u5b9a\u5230\u5bf9\u8c61\u3002 \u5220\u9664\u4e5f\u662f\u5982\u6b64\uff1a\u8bed\u53e5 del x \u4f1a\u4ece\u5c40\u90e8\u4f5c\u7528\u57df\u6240\u5f15\u7528\u7684\u547d\u540d\u7a7a\u95f4\u4e2d\u79fb\u9664\u5bf9 x \u7684\u7ed1\u5b9a\u3002\u4e8b\u5b9e\u4e0a\uff0c\u6240\u6709\u5f15\u5165\u65b0\u540d\u79f0\u7684\u64cd\u4f5c\u90fd\u662f\u4f7f\u7528\u5c40\u90e8\u4f5c\u7528\u57df\u3002\u7279\u522b\u5730\uff0c import \u8bed\u53e5\u548c\u51fd\u6570\u5b9a\u4e49\u4f1a\u5728\u5c40\u90e8\u4f5c\u7528\u57df\u4e2d\u7ed1\u5b9a\u6a21\u5757\u6216\u51fd\u6570\u540d\u79f0\u3002 global \u8bed\u53e5\u53ef\u88ab\u7528\u6765\u8868\u660e\u7279\u5b9a\u53d8\u91cf\u5b58\u5728\u4e8e\u5168\u5c40\u4f5c\u7528\u57df\uff0c\u5e76\u4e14\u5e94\u5f53\u5728\u5168\u5c40\u4f5c\u7528\u57df\u4e2d\u88ab**\u91cd\u65b0**\u7ed1\u5b9a\uff1b nonlocal \u8bed\u53e5\u8868\u660e\u7279\u5b9a\u53d8\u91cf\u751f\u5b58\u4e8e\u5916\u5c42\u4f5c\u7528\u57df\u4e2d\uff0c\u5e76\u4e14\u5e94\u5f53\u5728\u5176\u6240\u5904\u7684\u5916\u5c42\u4f5c\u7528\u57df\u4e2d\u88ab**\u91cd\u65b0**\u7ed1\u5b9a\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff1a \u5c40\u90e8\u8d4b\u503c\uff08local assignment\uff0c\u8fd9\u662f\u9ed8\u8ba4\u72b6\u6001\uff09\u4e0d\u4f1a\u6539\u53d8 scope_test \u5bf9 spam \u7684\u7ed1\u5b9a\u3002 nonlocal \u8d4b\u503c\u4f1a\u6539\u53d8 scope_test \u5bf9 spam \u7684\u7ed1\u5b9a\u3002 global \u8d4b\u503c\u4f1a\u6539\u53d8\u6a21\u5757\u5c42\u7ea7\u7684\u7ed1\u5b9a\uff0c\u5373\uff0c global spam \u91cd\u65b0\u7ed1\u5b9a\u4e86spam\u7684\u5168\u5c40\u5b9a\u4e49\uff0c\u4ece spam = \"spam out of func\" \u53d8\u6210\u4e86 spam = \"global spam\" \u3002\u5982\u679c\u6ce8\u91ca\u6389def do_global()\u8fd9\u4e00\u6bb5\u4ee3\u7801\uff0c\u5219 spam = \"spam out of func\" \u8d77\u4f5c\u7528\u3002 spam = \"spam out of func\" def scope_test (): def do_local (): spam = \"local spam\" def do_nonlocal (): nonlocal spam spam = \"nonlocal spam\" def do_global (): global spam spam = \"global spam\" spam = \"test spam\" do_local () print ( \"After local assignment:\" , spam ) do_nonlocal () print ( \"After nonlocal assignment:\" , spam ) do_global () print ( \"After global assignment:\" , spam ) scope_test () print ( \"In global scope:\" , spam ) # \u8fd0\u884c\u7ed3\u679c # scope_test() After local assignment : test spam After nonlocal assignment : nonlocal spam After global assignment : nonlocal spam # print(\"In global scope:\", spam) In global scope : global spam","title":"\u4f5c\u7528\u57dfScopes\u548c\u547d\u540d\u7a7a\u95f4Namespaces"},{"location":"python/Foundation/ch04/#class","text":"","title":"\u7c7bClass"},{"location":"python/Foundation/ch04/#class-definition","text":"\u7c7b\u5b9a\u4e49\u4e0e\u51fd\u6570\u5b9a\u4e49 (def \u8bed\u53e5) \u4e00\u6837\u5fc5\u987b\u88ab\u6267\u884c\u624d\u4f1a\u8d77\u4f5c\u7528\u3002 class ClassName : < statement - 1 > ... < statement - N > \u5728\u5b9e\u8df5\u4e2d\uff0c\u7c7b\u5b9a\u4e49\u5185\u7684\u8bed\u53e5\u901a\u5e38\u90fd\u662f\u51fd\u6570\u5b9a\u4e49\uff0c\u4f46\u4e5f\u5141\u8bb8\u6709\u5176\u4ed6\u8bed\u53e5\u3002\u5728\u7c7b\u5185\u90e8\u7684\u51fd\u6570\u5b9a\u4e49\u901a\u5e38\u5177\u6709\u4e00\u79cd\u7279\u6709\u5f62\u5f0f\u7684\u53c2\u6570\u5217\u8868\uff0c\u8fd9\u662f\u7ea6\u5b9a\u7684\u65b9\u6cd5\u89c4\u8303\uff08conventions for methods\uff09\u3002 \u7f16\u8bd1\u8fc7\u7a0b\u4e2d\uff0c\u8fdb\u5165\u4e00\u4e2a\u7c7b\u7684\u5185\u90e8\uff0c\u5c06\u521b\u5efa\u4e00\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\uff0c\u4e00\u4e2a\u5c40\u90e8\u4f5c\u7528\u57df\u3002\u56e0\u6b64\uff0c\u6240\u6709\u5bf9\u7c7b\u5185\u90e8\u5c40\u90e8\u53d8\u91cf\u7684\u8d4b\u503c\u90fd\u662f\u5728\u8fd9\u4e2a\u65b0\u7684\u547d\u540d\u7a7a\u95f4\u4e4b\u5185\uff0c\u5305\u62ec\u65b0\u5b9a\u4e49\u7684\u51fd\u6570\u540d\u79f0\u3002 \u5f53\u6b63\u5e38\u79bb\u5f00\u4e00\u4e2a\u7c7b\u65f6\uff0c\u7f16\u8bd1\u8fc7\u7a0b\u5c06\u521b\u5efa\u4e00\u4e2a\u7c7b\u5bf9\u8c61\uff08class object\uff09\uff0c\u5c01\u88c5\u4e86\u7c7b\u5b9a\u4e49\u6240\u521b\u5efa\u7684\u547d\u540d\u7a7a\u95f4\u91cc\u7684\u5185\u5bb9\u3002 \u6700\u521d\u7684\uff08\u5728\u8fdb\u5165\u7c7b\u5b9a\u4e49\u4e4b\u524d\u8d77\u4f5c\u7528\u7684\uff09\u5c40\u90e8\u4f5c\u7528\u57df\u5c06\u91cd\u65b0\u751f\u6548\uff0c\u7c7b\u5bf9\u8c61\uff08class object\uff09\u5c06\u5728\u8fd9\u91cc\u88ab\u7ed1\u5b9a\u5230\u7c7b\u5b9a\u4e49\u5934\u90e8\u6240\u58f0\u660e\u7684\u7c7b\u540d\u79f0 (\u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\u662f ClassName )\u3002","title":"\u7c7b\u5b9a\u4e49 Class Definition"},{"location":"python/Foundation/ch04/#class-objects","text":"\u7c7b\u5bf9\u8c61\u652f\u6301\u4e24\u79cd\u64cd\u4f5c\uff1a\u5c5e\u6027\u5f15\u7528\uff08attribute references\uff09\u548c\u5b9e\u4f8b\u5316\uff08instantiation\uff09\u3002 \u5c5e\u6027\u5f15\u7528\uff08attribute references\uff09 \u4f7f\u7528Python\u4e2d\u5c5e\u6027\u5f15\u7528\u7684\u6807\u51c6\u8bed\u6cd5: obj.name \u3002 \u5b58\u5728\u4e8e\u7c7b\u547d\u540d\u7a7a\u95f4\u4e2d\u7684\u6240\u6709\u540d\u79f0\uff0c\u7c7b\u5bf9\u8c61\u88ab\u521b\u5efa\u65f6\u540c\u65f6\u88ab\u521b\u5efa\u4e86\uff0c\u8fd9\u4e9b\u5c31\u662f\u6709\u6548\u7684\u5c5e\u6027\u540d\u79f0\u3002\u56e0\u6b64\uff0c\u5982\u679c\u7c7b\u5b9a\u4e49\u662f\u5982\u4e0b\u6240\u793a\uff0c\u90a3\u4e48 MyClass.i \u548c MyClass.f \u5c31\u662f\u6709\u6548\u7684\u5c5e\u6027\u5f15\u7528\uff0c\u5c06\u5206\u522b\u8fd4\u56de\u4e00\u4e2a\u6574\u6570\u548c\u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\u3002 \u7c7b\u5c5e\u6027\u4e5f\u53ef\u4ee5\u88ab\u8d4b\u503c\uff0c\u56e0\u6b64\u53ef\u4ee5\u901a\u8fc7\u8d4b\u503c\u6765\u66f4\u6539 MyClass.i \u7684\u503c\u3002 __doc__ \u4e5f\u662f\u4e00\u4e2a\u6709\u6548\u7684\u5c5e\u6027\uff0c\u5c06\u8fd4\u56de\u6240\u5c5e\u7c7b\u7684\u6587\u6863\u5b57\u7b26\u4e32: \"A simple example class\"\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' print ( MyClass . i ) # 12345 print ( MyClass . __doc__ ) # A simple example class MyClass . i = 10 print ( MyClass . i ) # 10 \u7c7b\u7684**\u5b9e\u4f8b\u5316\uff08instantiation\uff09**\u4f7f\u7528\u51fd\u6570\u8868\u793a\u6cd5\u3002 \u53ef\u4ee5\u628a\u7c7b\u5bf9\u8c61\uff08class object\uff09\u770b\u4f5c\u662f\u4e00\u4e2a\u4e0d\u5e26\u53c2\u6570\u7684\u51fd\u6570\uff0c\u8fd9\u4e2a\u51fd\u6570\u8fd4\u56de\u4e86\u8be5\u7c7b\u7684\u4e00\u4e2a\u65b0\u5b9e\u4f8b\u3002 \u5728\u4e0b\u9762\u7684\u4f8b\u5b50\u4e2d\uff0c x = MyClass() \u521b\u5efa\u4e86 MyClass() \u8fd9\u4e2a\u7c7b\u7684\u4e00\u4e2a\u5b9e\u4f8b\uff0c\u5e76\u8d4b\u503c\u7ed9\u5c40\u90e8\u53d8\u91cf x \u3002 \u5b9e\u4f8b\u5316\u64cd\u4f5c\uff08\u8c03\u7528\u7c7b\u5bf9\u8c61\uff09\u4f1a\u521b\u5efa\u4e00\u4e2a\u7a7a\u5bf9\u8c61\u3002\u8bb8\u591a\u7c7b\u4f1a\u521b\u5efa\u5e26\u6709\u7279\u5b9a\u521d\u59cb\u72b6\u6001\u7684\u81ea\u5b9a\u4e49\u5b9e\u4f8b\u3002\u4e3a\u6b64\u7c7b\u5b9a\u4e49\u4e2d\u9700\u8981\u5305\u542b\u4e00\u4e2a\u540d\u4e3a __init__() \u7684\u7279\u6b8a\u65b9\u6cd5\u3002 \u5f53\u4e00\u4e2a\u7c7b\u5b9a\u4e49\u4e86 __init__() \u65b9\u6cd5\u65f6\uff0c\u7c7b\u7684\u5b9e\u4f8b\u5316\u64cd\u4f5c\u4f1a\u81ea\u52a8\u4e3a\u65b0\u521b\u5efa\u7684\u7c7b\u5b9e\u4f8b\u8c03\u7528 __init__() \u3002 \u66f4\u65b0\u4e0a\u9762\u7684\u4f8b\u5b50\uff0c\u6ce8\u610f __dict__ \u4e24\u6b21\u8fd4\u56de\u7684\u4e0d\u540c\u7684\u5b57\u5178\u3002\u590d\u4e60\u4e00\u4e0b\uff0c\u5728\u547d\u540d\u7a7a\u95f4\u4e2d\u63d0\u5230\uff0c __dict__ \u662f\u5c5e\u6027\u4f46\u4e0d\u662f\u5168\u5c40\u540d\u79f0\uff0c\u8fd4\u56de\u7528\u4e8e\u5b9e\u73b0\u6a21\u5757\u547d\u540d\u7a7a\u95f4\u7684\u5b57\u5178\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' def __init__ ( self ): self . data = [] x = MyClass () print ( x . __dict__ ) # {'data': []} x . i = 10 print ( x . __dict__ ) # {'data': [], 'i': 10} __init__() \u65b9\u6cd5\u53ef\u4ee5\u6709\u989d\u5916\u7684\u53c2\u6570\u8f93\u5165\uff0c\u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u7c7b\u5b9e\u4f8b\u5316\u7684\u53c2\u6570\u5c06\u88ab\u4f20\u9012\u7ed9 __init__() \u3002 \u5982\u4e0b\u4f8b: class Complex : def __init__ ( self , realpart , imagpart ): self . r = realpart self . i = imagpart x = Complex ( 3.0 , - 4.5 ) print ( x . r , x . i ) # 3.0 -4.5","title":"\u7c7b\u5bf9\u8c61 Class Objects"},{"location":"python/Foundation/ch04/#instance-objects","text":"\u5bf9\u5b9e\u4f8b\u5bf9\u8c61\u552f\u4e00\u7684\u64cd\u4f5c\u662f\u5c5e\u6027\u5f15\u7528\u3002\u6709\u4e24\u79cd\u6709\u6548\u7684\u5c5e\u6027\u540d\u79f0\uff1a\u6570\u636e\u5c5e\u6027\uff08data attributes\uff09\u548c\u65b9\u6cd5\uff08methods\uff09\u3002 **\u6570\u636e\u5c5e\u6027\uff08data attributes\uff09**\u7c7b\u4f3c\u4e8e\u5b9e\u4f8b\u53d8\u91cf\uff0c\u6570\u636e\u5c5e\u6027\u4e0d\u9700\u8981\u58f0\u660e\u3002\u50cf\u5c40\u90e8\u53d8\u91cf\u4e00\u6837\uff0c\u6570\u636e\u5c5e\u6027\u5c06\u5728\u7b2c\u4e00\u6b21\u88ab\u8d4b\u503c\u65f6\u4ea7\u751f\u3002 \u4f8b\u5982\uff0c\u5982\u679c x \u662f\u4e0a\u9762\u521b\u5efa\u7684 MyClass \u7684\u5b9e\u4f8b\uff0c\u5219\u4ee5\u4e0b\u4ee3\u7801\u6bb5\u5c06\u6253\u5370\u6570\u503c 16 \uff0c\u4e14\u6ca1\u6709\u7559\u4e0b\u5173\u4e8e x.counter \u7684\u75d5\u8ff9\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' def __init__ ( self ): self . data = [] x = MyClass () x . counter = 1 while x . counter < 10 : x . counter = x . counter * 2 print ( x . counter ) # 16 print ( x . __dict__ ) # {'data': [], 'counter': 16} del x . counter print ( x . __dict__ ) # {'data': []} \u53e6\u4e00\u7c7b\u5b9e\u4f8b\u5c5e\u6027\u5f15\u7528\u79f0\u4e3a**\u65b9\u6cd5\uff08methods\uff09 \u3002 \u65b9\u6cd5\u662f\u96b6\u5c5e\u4e8e\u5bf9\u8c61\u7684**\u51fd\u6570 \u3002 \u5728Python\u4e2d\uff0c\u65b9\u6cd5\u8fd9\u4e2a\u672f\u8bed\u5e76\u4e0d\u662f\u7c7b\u5b9e\u4f8b\u6240\u7279\u6709\u7684\uff0c\u5176\u4ed6\u5bf9\u8c61\u4e5f\u53ef\u4ee5\u6709\u65b9\u6cd5\u3002 \u4f8b\u5982\uff0c\u5217\u8868\u5bf9\u8c61\uff08list objects\uff09\u5177\u6709append, insert, remove, sort\u7b49\u65b9\u6cd5\u3002 \u5728\u4ee5\u4e0b\u8ba8\u8bba\u4e2d\uff0c\u6211\u4eec\u4f7f\u7528\u65b9\u6cd5\u4e00\u8bcd\u5c06\u4e13\u6307\u7c7b\u5b9e\u4f8b\u5bf9\u8c61\u7684\u65b9\u6cd5\uff0c\u9664\u975e\u53e6\u5916\u660e\u786e\u8bf4\u660e\u3002 \u5b9e\u4f8b\u5bf9\u8c61\u7684\u6709\u6548\u65b9\u6cd5\u540d\u79f0\u4f9d\u8d56\u4e8e\u5176\u6240\u5c5e\u7684\u7c7b\u3002 \u6839\u636e\u5b9a\u4e49\uff0c\u4e00\u4e2a\u7c7b\u5b9a\u4e49\u4e2d\u6240\u5305\u542b\u7684\u6240\u6709\u51fd\u6570\u5bf9\u8c61\uff08function objects\uff09\u90fd\u79f0\u4e3a\u5c5e\u6027\u3002 \u56e0\u6b64\u5728\u4e0a\u9762\u7684\u793a\u4f8b\u4e2d\uff0c x.f \u662f\u6709\u6548\u7684\u65b9\u6cd5\u5f15\u7528\uff0c\u56e0\u4e3a MyClass.f \u662f\u4e00\u4e2a\u51fd\u6570\uff0c\u800c x.i \u4e0d\u662f\u65b9\u6cd5\uff0c\u56e0\u4e3a MyClass.i \u4e0d\u662f\u51fd\u6570\u3002\u4f46\u662f x.f \u4e0e MyClass.f \u5e76\u4e0d\u662f\u4e00\u56de\u4e8b\uff0c x.f \u662f\u4e00\u4e2a**\u65b9\u6cd5\u5bf9\u8c61**\uff0c\u800c MyClass.f \u662f\u4e00\u4e2a**\u51fd\u6570\u5bf9\u8c61**\u3002\u5dee\u522b\u5728\u4e8e f() \u662f\u5426\u4e0e\u5b9e\u4f8b\u7ed1\u5b9a\uff0c\u672a\u7ed1\u5b9a\uff0c\u5c31\u662f\u51fd\u6570\uff0c\u7ed1\u5b9a\uff0c\u5c31\u662f\u65b9\u6cd5\u3002 class MyClass : \"\"\"A simple example class\"\"\" i = 12345 def f ( self ): return 'hello world' def __init__ ( self ): self . data = [] x = MyClass () print ( MyClass . f ( 0 )) # hello world print ( x . f ()) # hello world print ( MyClass . f ) # print ( x . f ) # > print ( type ( MyClass . f )) # print ( type ( x . f )) # \u8fd9\u91cc\u505a\u4e2a\u5c0f\u7ed3\uff1a \u51fd\u6570(function)\u662fPython\u4e2d\u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61(callable), \u65b9\u6cd5(method)\u662f\u4e00\u79cd\u7279\u6b8a\u7684\u51fd\u6570\u3002 \u4e00\u4e2a\u53ef\u8c03\u7528\u5bf9\u8c61\u662f\u65b9\u6cd5\u548c\u51fd\u6570\uff0c\u548c\u8fd9\u4e2a\u5bf9\u8c61\u65e0\u5173\uff0c\u4ec5\u548c\u8fd9\u4e2a\u5bf9\u8c61\u662f\u5426\u4e0e\u7c7b\u6216\u5b9e\u4f8b\u7ed1\u5b9a\u6709\u5173\uff08bound method\uff09\u3002 \u9759\u6001\u65b9\u6cd5\u6ca1\u6709\u548c\u4efb\u4f55\u7c7b\u6216\u5b9e\u4f8b\u7ed1\u5b9a\uff0c\u6240\u4ee5**\u9759\u6001\u65b9\u6cd5\u662f\u4e2a\u51fd\u6570**\u3002","title":"\u5b9e\u4f8b\u5bf9\u8c61 Instance Objects"},{"location":"python/Foundation/ch04/#method-objects","text":"\u5728 MyClass \u793a\u4f8b\u4e2d\uff0c x.f() \u662f\u4e00\u4e2a\u65b9\u6cd5\u5bf9\u8c61\uff0c\u88ab\u8c03\u7528\u540e\uff0c\u5c06\u8fd4\u56de\u5b57\u7b26\u4e32 'hello world' \u3002\u53ef\u4ee5\u7acb\u5373\u8c03\u7528\uff0c\u4e5f\u53ef\u4ee5\u4fdd\u5b58\u8d77\u6765\u4ee5\u540e\u518d\u8c03\u7528 xf = x.f \u3002 \u867d\u7136 f() \u7684\u51fd\u6570\u5b9a\u4e49\u6307\u5b9a\u4e86\u4e00\u4e2a\u53c2\u6570\uff0c\u4f46\u4e0a\u9762\u4f8b\u5b50\u4e2d\u8c03\u7528 x.f() \u65f6\u5e76\u6ca1\u6709\u5e26\u53c2\u6570\uff0c\u4e5f\u6ca1\u6709\u5f15\u53d1\u5f02\u5e38\u62a5\u9519\u3002\u539f\u56e0\u5728\u4e8e\uff0c \u65b9\u6cd5(method)\u7684\u7279\u6b8a\u4e4b\u5904\u5c31\u5728\u4e8e\u5b9e\u4f8b\u5bf9\u8c61\u4f1a\u4f5c\u4e3a\u51fd\u6570\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u88ab\u4f20\u5165\u3002 \u8c03\u7528 x.f() \u5176\u5b9e\u5c31\u76f8\u5f53\u4e8e MyClass.f(x) \u3002 \u603b\u4e4b\uff0c\u8c03\u7528\u4e00\u4e2a\u5177\u6709 n \u4e2a\u53c2\u6570\u7684\u65b9\u6cd5(method)\u5c31\u76f8\u5f53\u4e8e\u8c03\u7528\u518d\u591a\u4e00\u4e2a\u53c2\u6570\u7684\u5bf9\u5e94\u51fd\u6570\uff0c\u8fd9\u4e2a\u53c2\u6570\u503c\u4e3a\u65b9\u6cd5\u6240\u5c5e\u5b9e\u4f8b\u5bf9\u8c61\uff0c \u4f4d\u7f6e\u5728\u5176\u4ed6\u53c2\u6570\u4e4b\u524d \u3002 \u5f53\u4e00\u4e2a\u5b9e\u4f8b\u7684\u975e\u6570\u636e\u5c5e\u6027\u88ab\u5f15\u7528\u65f6\uff0c\u5c06\u641c\u7d22\u5b9e\u4f8b\u6240\u5c5e\u7684\u7c7b\u3002 \u5982\u679c\u88ab\u5f15\u7528\u7684\u5c5e\u6027\u540d\u79f0\u662f\u7c7b\u4e2d\u4e00\u4e2a\u6709\u6548\u7684\u51fd\u6570\u5bf9\u8c61\uff0c\u5219\u4f1a\u521b\u5efa\u4e00\u4e2a\u62bd\u8c61\u7684\u5bf9\u8c61\uff0c\u901a\u8fc7\u6253\u5305\uff08parking\uff0c\u5373\u6307\u5411\uff09\u5339\u914d\u5230\u7684\u5b9e\u4f8b\u5bf9\u8c61\u548c\u51fd\u6570\u5bf9\u8c61\uff0c\u8fd9\u4e2a\u62bd\u8c61\u5bf9\u8c61\u5c31\u662f\u65b9\u6cd5\u5bf9\u8c61\u3002 \u5f53\u5e26\u53c2\u6570\u8c03\u7528\u65b9\u6cd5\u5bf9\u8c61\u65f6\uff0c\u5c06\u57fa\u4e8e\u5b9e\u4f8b\u5bf9\u8c61\u548c\u53c2\u6570\u5217\u8868\u6784\u5efa\u4e00\u4e2a\u65b0\u7684\u53c2\u6570\u5217\u8868\uff0c\u5e76\u4f7f\u7528\u8fd9\u4e2a\u65b0\u53c2\u6570\u5217\u8868\u8c03\u7528\u76f8\u5e94\u7684\u51fd\u6570\u5bf9\u8c61\u3002","title":"\u65b9\u6cd5\u5bf9\u8c61 Method Objects"},{"location":"python/Foundation/ch04/#class-and-instance-variables","text":"\u4e00\u822c\u6765\u8bf4\uff0c**\u5b9e\u4f8b\u53d8\u91cf**\u7528\u4e8e\u6bcf\u4e2a\u5b9e\u4f8b\u7684\u552f\u4e00\u6570\u636e\uff0c\u800c**\u7c7b\u53d8\u91cf**\u7528\u4e8e\u7c7b\u7684\u6240\u6709\u5b9e\u4f8b\u5171\u4eab\u7684\u5c5e\u6027\u548c\u65b9\u6cd5: class Dog : kind = 'canine' # class variable shared by all instances def __init__ ( self , name ): self . name = name # instance variable unique to each instance d = Dog ( 'Fido' ) e = Dog ( 'Buddy' ) print ( d . kind ) # shared by all dogs # 'canine' print ( e . kind ) # shared by all dogs # 'canine' print ( d . name ) # unique to d instance # 'Fido' print ( e . name ) # unique to e instance # 'Buddy' \u4e0b\u4ee3\u7801\u4e2d\u7684 tricks \u5217\u8868\u4e0d\u5e94\u8be5\u88ab\u7528\u4f5c\u7c7b\u53d8\u91cf\uff0c\u56e0\u4e3a\u6240\u6709\u7684 Dog \u5b9e\u4f8b\u5c06\u53ea\u5171\u4eab\u4e00\u4e2a\u5355\u72ec\u7684\u5217\u8868: class Dog : kind = 'canine' # class variable shared by all instances tricks = [] # mistaken use of a class variable def __init__ ( self , name ): self . name = name # instance variable unique to each instance def add_trick ( self , trick ): self . tricks . append ( trick ) d = Dog ( 'Fido' ) e = Dog ( 'Buddy' ) d . add_trick ( 'roll over' ) e . add_trick ( 'play dead' ) print ( d . tricks ) # ['roll over', 'play dead'] \u6b63\u786e\u7684\u7c7b\u8bbe\u8ba1\u5e94\u8be5\u4f7f\u7528\u5b9e\u4f8b\u53d8\u91cf: class Dog : kind = 'canine' # class variable shared by all instances def __init__ ( self , name ): self . name = name # instance variable unique to each instance self . tricks = [] # creates a new empty list for each dog def add_trick ( self , trick ): self . tricks . append ( trick ) d = Dog ( 'Fido' ) e = Dog ( 'Buddy' ) d . add_trick ( 'roll over' ) e . add_trick ( 'play dead' ) print ( d . tricks ) # ['roll over'] print ( e . tricks ) # ['play dead'] \u5982\u679c\u540c\u6837\u7684\u5c5e\u6027\u540d\u79f0\u540c\u65f6\u51fa\u73b0\u5728\u5b9e\u4f8b\u548c\u7c7b\u4e2d\uff0c\u5219\u5c5e\u6027\u67e5\u627e\u4f1a**\u4f18\u5148\u9009\u62e9\u5b9e\u4f8b**: class Warehouse : purpose = 'storage' region = 'west' w1 = Warehouse () print ( w1 . purpose , w1 . region ) # storage west w2 = Warehouse () w2 . region = 'east' # Instance W2 has higher priority than class print ( w2 . purpose , w2 . region ) # storage east \u6570\u636e\u5c5e\u6027\uff08Data attributes\uff09\u53ef\u4ee5\u88ab\u65b9\u6cd5\uff08method\uff09\u4ee5\u53ca\u4e00\u4e2a\u5bf9\u8c61\u7684\u666e\u901a\u7528\u6237\uff08ordinary users\uff09\uff08\u201c\u5ba2\u6237\u7aefClient\u201d\uff09\u6240\u5f15\u7528\u3002 \u6362\u53e5\u8bdd\u8bf4\uff0c\u7c7b\u4e0d\u80fd\u7528\u4e8e\u5b9e\u73b0\u7eaf\u62bd\u8c61\u6570\u636e\u7c7b\u578b\u3002 \u65b9\u6cd5\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u5e38\u5e38\u88ab\u547d\u540d\u4e3a self \uff0c\u8fd9\u53ea\u662f\u4e00\u4e2a\u7ea6\u5b9a: self \u8fd9\u4e00\u540d\u79f0\u5728Python\u4e2d\u6ca1\u6709\u7279\u6b8a\u542b\u4e49\u3002 \u4f46\u662f\u9075\u5faa\u6b64\u7ea6\u5b9a\u4f1a\u4f7f\u5f97\u4ee3\u7801\u5177\u6709\u5f88\u597d\u7684\u53ef\u8bfb\u6027\u3002 \u4efb\u4f55\u4e00\u4e2a\u4f5c\u4e3a\u7c7b\u5c5e\u6027\uff08class attribute\uff09\u7684\u51fd\u6570\u5bf9\u8c61\uff08function object\uff09\u90fd\u4e3a\u8be5\u7c7b\u7684\u5b9e\u4f8b\u5b9a\u4e49\u4e86\u4e00\u4e2a\u76f8\u5e94\u65b9\u6cd5\u3002 \u51fd\u6570\u5b9a\u4e49\u7684\u6587\u672c\u5e76\u975e\u5fc5\u987b\u5305\u542b\u4e8e\u7c7b\u5b9a\u4e49\u4e4b\u5185\uff1a\u5c06\u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\u8d4b\u503c\u7ed9\u4e00\u4e2a\u5c40\u90e8\u53d8\u91cf\u4e5f\u662f\u53ef\u4ee5\u7684\u3002\u5982\u4e0b\u4f8b\u3002\u73b0\u5728 f , g \u548c h \u90fd\u662f\u7c7b C \u7684\u5f15\u7528\u51fd\u6570\u5bf9\u8c61\u7684\u5c5e\u6027\uff0c\u56e0\u800c\u5b83\u4eec\u5c31\u90fd\u662f\u7c7b C \u7684\u5b9e\u4f8b\u7684\u65b9\u6cd5\uff0c\u5176\u4e2d h \u5b8c\u5168\u7b49\u540c\u4e8e g \u3002\u4f46\u8bf7\u6ce8\u610f\uff0c\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u7684\u53ef\u8bfb\u6027\u975e\u5e38\u4e0d\u597d\u3002 # Function defined outside the class def f1 ( self , x , y ): return min ( x , x + y ) class C : f = f1 # Assign a function object to a local variable in the class def g ( self ): return 'hello world' h = g \u65b9\u6cd5\uff08methods\uff09\u53ef\u4ee5\u901a\u8fc7\u4f7f\u7528 self \u53c2\u6570\u7684\u65b9\u6cd5\u5c5e\u6027\uff08method attributes\uff09\u8c03\u7528\u5176\u4ed6\u65b9\u6cd5\uff08method\uff09: class Bag : def __init__ ( self ): self . data = [] def add ( self , x ): self . data . append ( x ) def addtwice ( self , x ): self . add ( x ) self . add ( x ) \u65b9\u6cd5\u53ef\u4ee5\u901a\u8fc7\u4e0e\u666e\u901a\u51fd\u6570\u76f8\u540c\u7684\u65b9\u5f0f\u5f15\u7528\u5168\u5c40\u540d\u79f0\u3002 \u4e0e\u65b9\u6cd5\u76f8\u5173\u8054\u7684\u5168\u5c40\u4f5c\u7528\u57df\u5c31\u662f\u5305\u542b\u5176\u5b9a\u4e49\u7684\u6a21\u5757\u3002 \uff08\u7c7b\u6c38\u8fdc\u4e0d\u4f1a\u88ab\u4f5c\u4e3a\u5168\u5c40\u4f5c\u7528\u57df\u3002\uff09 \u867d\u7136\u6211\u4eec\u5f88\u5c11\u4f1a\u6709\u5145\u5206\u7684\u7406\u7531\u5728\u65b9\u6cd5\u4e2d\u4f7f\u7528\u5168\u5c40\u4f5c\u7528\u57df\uff0c\u4f46\u5168\u5c40\u4f5c\u7528\u57df\u5b58\u5728\u8bb8\u591a\u5408\u7406\u7684\u4f7f\u7528\u573a\u666f\uff1a\u4e3e\u4e2a\u4f8b\u5b50\uff0c\u5bfc\u5165\u5230\u5168\u5c40\u4f5c\u7528\u57df\u7684\u51fd\u6570\u548c\u6a21\u5757\u53ef\u4ee5\u88ab\u65b9\u6cd5\u6240\u4f7f\u7528\uff0c\u5728\u5176\u4e2d\u5b9a\u4e49\u7684\u51fd\u6570\u548c\u7c7b\u4e5f\u4e00\u6837\u3002 \u901a\u5e38\uff0c\u5305\u542b\u8be5\u65b9\u6cd5\u7684\u7c7b\u672c\u8eab\u662f\u5728\u5168\u5c40\u4f5c\u7528\u57df\u4e2d\u5b9a\u4e49\u7684\u3002","title":"\u7c7b\u548c\u5b9e\u4f8b\u53d8\u91cf Class and Instance Variables"},{"location":"python/Foundation/ch04/#_1","text":"","title":"\u603b\u7ed3"},{"location":"python/Foundation/ch04/#_2","text":"\u4e00\u4e2a\u7c7b\u5b9a\u4e49\u7c7b\u6210\u5458\u5c5e\u6027\u548c\u6210\u5458\u65b9\u6cd5\u3002 \u4e00\u4e2a\u7c7b\u53ef\u4ee5\u5b9e\u4f8b\u5316\u591a\u4e2a\u5bf9\u8c61\uff0c\u6bcf\u4e2a\u5b9e\u4f8b\u5316\u5bf9\u8c61\u90fd\u662f\u72ec\u7acb\u7684\u3002 \u521b\u5efa\u7684\u7c7b\u5b9e\u4f8b\u5316\u5bf9\u8c61\uff0c\u4f1a\u5f15\u7528\u7236\u7c7b\u4e2d\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\uff0c\u5e76\u4e0d\u4f1a\u628a\u7c7b\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\u590d\u5236\u7ed9\u5bf9\u8c61\uff0c\u56e0\u6b64\uff1a \u5728\u8bbf\u95ee\u5b9e\u4f8b\u5316\u5bf9\u8c61\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\u65f6\uff0c\u4f1a\u5148\u53bb\u627e\u5bf9\u8c61\u81ea\u5df1\u7684\u5c5e\u6027\u548c\u65b9\u6cd5\uff0c\u7136\u540e\u518d\u53bb\u5b9e\u4f8b\u5316\u8fd9\u4e2a\u5bf9\u8c61\u7684\u7c7b\u4e2d\u67e5\u627e\uff08\u5f15\u7528\uff09\u3002 \u5bf9\u8c61\u6210\u5458\u7684\u6dfb\u52a0\u548c\u4fee\u6539\uff0c\u90fd\u53ea\u4f1a\u5f71\u54cd\u5f53\u524d\u5bf9\u8c61\u81ea\u5df1\uff0c\u4e0d\u4f1a\u5f71\u54cd\u7c7b\u548c\u5176\u5b83\u5bf9\u8c61\u3002 \u5220\u9664\u5bf9\u8c61\u6210\u5458\u7684\u65f6\u5019\uff0c\u5fc5\u987b\u662f\u8be5\u5bf9\u8c61\u81ea\u5df1\u5177\u5907\u7684\u6210\u5458\u624d\u53ef\u4ee5\uff0c\u4e0d\u80fd\u5220\u9664\u7c7b\u4e2d\u5f15\u7528\u7684\u6210\u5458\u3002 \u5bf9\u7c7b\u6210\u5458\u7684\u64cd\u4f5c\uff0c\u4f1a\u5f71\u54cd\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\uff0c\u5305\u62ec\u4e4b\u524d\u521b\u5efa\u7684\u5bf9\u8c61\uff08\u5f15\u7528\uff09\u3002","title":"\u7c7b\u5b9a\u4e49\u5c0f\u7ed3"},{"location":"python/Foundation/ch04/#_3","text":"\u6210\u5458\u5c5e\u6027\uff1a \u8bbf\u95ee\uff1a ClassName.AttributeName \u4fee\u6539\uff1a ClassName.AttributeName = NewValue \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u5c5e\u6027\u3002 \u6dfb\u52a0\uff1a ClassName.NewAttributeName = Value \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u5c5e\u6027\u3002 \u5220\u9664\uff1a del ClassName.AttributeName \uff0c\u6ce8\u610f\uff0c\u53ea\u80fd\u5220\u9664\u7c7b\u5bf9\u8c61\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u4e0d\u518d\u5177\u6709\u8fd9\u4e2a\u5c5e\u6027\u3002 \u6210\u5458\u65b9\u6cd5\uff1a \u8bbf\u95ee\uff1a ClassName.MethodName() \u4fee\u6539\uff1a ClassName.MethodName = NewFunction \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u65b9\u6cd5\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u6dfb\u52a0\uff1a ClassName.MethodName = Function \uff0c\u7b49\u4e8e\u7ed9\u8fd9\u4e2a\u7c7b\u5bf9\u8c61\u521b\u5efa\u4e86\u4e00\u4e2a\u81ea\u5df1\u7684\u65b9\u6cd5\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u5177\u6709\u8fd9\u4e2a\u65b9\u6cd5\u3002 \u5220\u9664\uff1a del ClassName.MethodName \uff0c\u6ce8\u610f\uff0c\u53ea\u80fd\u5220\u9664\u7c7b\u5bf9\u8c61\u81ea\u5df1\u7684\u65b9\u6cd5\uff0c\u901a\u8fc7\u8fd9\u4e2a\u7c7b\u521b\u5efa\u7684\u5bf9\u8c61\u90fd\u4e0d\u518d\u5177\u6709\u8fd9\u4e2a\u65b9\u6cd5\u3002","title":"\u7c7b\u6210\u5458\u64cd\u4f5c\uff08\u4e0d\u63a8\u8350\uff09"},{"location":"python/Foundation/ch04/#self","text":"self \u53ea\u662f\u4e00\u4e2a\u5f62\u53c2\uff0c\u4e0d\u662f\u5173\u952e\u5b57\u3002 self \u5728\u65b9\u6cd5\uff08method\uff09\u4ee3\u8868\u5f53\u524d\u5bf9\u8c61\u81ea\u5df1\u3002\u524d\u9762\u63d0\u5230\u8fc7\uff0c\u65b9\u6cd5\u7684\u7b2c\u4e00\u4e2a\u53c2\u6570\u5e38\u5e38\u88ab\u547d\u540d\u4e3a self \uff0c\u8fd9\u53ea\u662f\u4e00\u4e2a\u7ea6\u5b9a\u3002 \u53ef\u4ee5\u4f7f\u7528 self \u5728\u7c7b\u5185\u90e8\u64cd\u4f5c\u6210\u5458\uff08\u6dfb\u52a0\u3001\u4fee\u6539\u3001\u5220\u9664\u7b49\uff09\u3002 \u65b9\u6cd5\u7684\u5206\u7c7b\uff1a \u542b\u6709self\u6216\u8005\u53ef\u4ee5\u63a5\u53d7\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\u7684\u65b9\u6cd5\uff0c\u79f0\u4e3a**\u975e\u7ed1\u5b9a\u7c7b\u65b9\u6cd5**\uff0c\u975e\u7ed1\u5b9a\u7c7b\u7684\u65b9\u6cd5\u53ef\u4ee5\u4f7f\u7528\u5bf9\u8c61\u53bb\u8bbf\u95ee\u3002 \u4e0d\u542b\u6709self\u6216\u8005\u4e0d\u80fd\u63a5\u53d7\u5bf9\u8c61\u4f5c\u4e3a\u53c2\u6570\u7684\u65b9\u6cd5\uff0c\u79f0\u4e3a**\u7ed1\u5b9a\u7c7b\u65b9\u6cd5**\uff0c\u7ed1\u5b9a\u65b9\u6cd5\u53ea\u80fd\u4f7f\u7528\u7c7b\u53bb\u8bbf\u95ee\u3002","title":"\u6210\u5458\u65b9\u6cd5\u4e2d\u7684self"},{"location":"python/Foundation/ch04/#_4","text":"\u9b54\u672f\u65b9\u6cd5\uff08Magic Method\uff09\u548c\u666e\u901a\u65b9\u6cd5\u4e00\u6837\uff0c\u90fd\u662f\u7c7b\u4e2d\u5b9a\u4e49\u7684\u6210\u5458\u65b9\u6cd5\u3002 \u9b54\u672f\u65b9\u6cd5\u540d\u79f0\u524d\u540e\u5404\u67092\u4e2a\u4e0b\u5212\u7ebf\uff0c\u6bd4\u5982 __init__ \u9b54\u672f\u65b9\u6cd5\u662f\u4e0d\u9700\u8981\u624b\u52a8\u8c03\u7528\u7684\uff0c\u4f1a\u5728\u67d0\u79cd\u60c5\u51b5\u4e0b\u81ea\u52a8\u89e6\u53d1\uff08\u81ea\u52a8\u6267\u884c\uff09\u3002 \u9b54\u672f\u65b9\u6cd5\u662f\u7cfb\u7edf\u5b9a\u4e49\u597d\u7684\uff0c\u4e0d\u662f\u7528\u6237\u5b9a\u4e49\u7684\u3002","title":"\u9b54\u672f\u65b9\u6cd5"},{"location":"python/Foundation/ch04/#__init__","text":"\u7c7b\u5b9e\u4f8b\u5316\u5bf9\u8c61\u521b\u5efa\u540e\u81ea\u52a8\u89e6\u53d1\u3002 __init__ \u521d\u59cb\u5316\u65b9\u6cd5\u53ef\u4ee5\u7528\u6765\u5728\u5bf9\u8c61\u5b9e\u4f8b\u5316\u540e\u5b8c\u6210\u5bf9\u8c61\u7684\u521d\u59cb\u5316\uff0c\u6bd4\u5982\u5c5e\u6027\u8d4b\u503c\uff0c\u65b9\u6cd5\u8c03\u7528\u7b49\u3002","title":"__init__\u521d\u59cb\u5316\u65b9\u6cd5\uff0c\u4e5f\u79f0\u4f5c**\u6784\u9020\u65b9\u6cd5**"},{"location":"python/Foundation/ch04/#__del__","text":"\u7c7b\u5b9e\u4f8b\u5316\u5bf9\u8c61\u88ab\u9500\u6bc1\u65f6\u81ea\u52a8\u89e6\u53d1\u3002 __del__ \u6790\u6784\u65b9\u6cd5\u53ef\u4ee5\u5728\u9500\u6bc1\u5bf9\u8c61\u65f6\u5b8c\u6210\u4e00\u4e9b\u7279\u6b8a\u4efb\u52a1\uff0c\u5173\u95ed\u5bf9\u8c61\u6253\u5f00\u7684\u4e00\u4e9b\u8d44\u6e90\uff0c\u5982\u6587\u4ef6\u7b49\u3002 \u6ce8\u610f\uff0c\u662f\u5bf9\u8c61\u88ab\u9500\u6bc1\u65f6\u89e6\u53d1\u4e86\u6790\u6784\u65b9\u6cd5\uff0c\u800c\u4e0d\u662f\u8fd9\u4e2a\u6790\u6784\u65b9\u6cd5\u9500\u6bc1\u4e86\u5bf9\u8c61\u3002 \u5bf9\u8c61\u9500\u6bc1\u7684\u60c5\u51b5\uff1a \u5f53\u7a0b\u5e8f\u6267\u884c\u5b8c\u6bd5\uff0c\u9500\u6bc1\u548c\u91ca\u653e\u5185\u5b58\u4e2d\u7684\u8d44\u6e90\u3002 \u4f7f\u7528 del \u5220\u9664\u65f6\u3002 \u5bf9\u8c61\u4e0d\u518d\u88ab\u4efb\u4f55\u5bf9\u8c61\u5f15\u7528\u65f6\uff0c\u4f1a\u81ea\u52a8\u9500\u6bc1\u3002 \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\uff0c\u5bf9\u6bd4 bmw = Car('BMW') \u548c Car('BMW') \u6765\u7406\u89e3 init \u548c del \u7684\u89e6\u53d1\u673a\u5236\u3002 \u7f16\u8f91\u6587\u4ef6 file1.py class Car (): brand = \"\" def __init__ ( self , car_brand ): self . brand = car_brand print ( f \"initial method called, create { self . brand } car\" ) def __del__ ( self ): print ( f \"delete method called, destroy { self . brand } car\" ) bmw = Car ( 'BMW' ) vw = Car ( 'VW' ) \u6267\u884c\u4e0a\u9762\u7684\u4ee3\u7801 python3 file1.py \u5f97\u5230\u5982\u4e0b\u8f93\u51fa\uff0c\u5728\u7a0b\u5e8f\u6267\u884c\u5b8c\u6bd5\u65f6\uff0c\u4f9d\u6b21\u6267\u884c __del__ \u3002 initial method called , create BMW car initial method called , create VW car delete method called , destroy BMW car delete method called , destroy VW car \u7f16\u8f91\u6587\u4ef6 file2.py class Car (): brand = \"\" def __init__ ( self , car_brand ): self . brand = car_brand print ( f \"initial method called, create { self . brand } car\" ) def __del__ ( self ): print ( f \"delete method called, destroy { self . brand } car\" ) Car ( 'BMW' ) Car ( 'VW' ) \u6267\u884c\u4e0a\u9762\u7684\u4ee3\u7801 python3 file2.py \u5f97\u5230\u5982\u4e0b\u8f93\u51fa\uff1a initial method called , create BMW car delete method called , destroy BMW car initial method called , create VW car delete method called , destroy VW car","title":"__del__\u6790\u6784\u65b9\u6cd5"},{"location":"python/Foundation/ch04/#python_1","text":"\u4ece\u9b54\u672f\u65b9\u6cd5\u53ef\u4ee5\u5ef6\u7533\u5230Python\u7684**\u51fd\u6570\u5185\u7701**\uff0c\u51fd\u6570\u5185\u7701\u7684\u610f\u601d\u662f\u8bf4\uff0c\u5f53\u4f60\u62ff\u5230\u4e00\u4e2a\u201c\u51fd\u6570\u5bf9\u8c61\u201d\u7684\u65f6\u5019\uff0c\u4f60\u53ef\u4ee5\u7ee7\u7eed\u77e5\u9053\uff0c\u5b83\u7684\u540d\u5b57\uff0c\u53c2\u6570\u5b9a\u4e49\u7b49\u4fe1\u606f\u3002\u8fd9\u4e9b\u4fe1\u606f\u53ef\u4ee5\u901a\u8fc7\u51fd\u6570\u5bf9\u8c61\u7684\u5c5e\u6027\uff08\u4e00\u4e9b\u53cc\u4e0b\u5212\u7ebf\u7684\u9b54\u6cd5\u65b9\u6cd5\uff09\u5f97\u5230\u3002\u7b80\u8a00\u4e4b\uff0c\u5185\u7701\u662f\u5728\u8fd0\u884c\u65f6\u786e\u5b9a\u5bf9\u8c61\u7c7b\u578b\u7684\u80fd\u529b\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u5217\u51fa\u4e86\u5e38\u89c4\u5bf9\u8c61\u6ca1\u6709\u800c\u51fd\u6570\u6709\u7684\u5c5e\u6027\u3002 class C : pass obj = C () def func (): pass sorted ( set ( dir ( obj )) - set ( dir ( func ))) # ['__weakref__'] sorted ( set ( dir ( func )) - set ( dir ( obj ))) # ['__annotations__', '__call__', '__closure__', '__code__', '__defaults__', '__get__', '__globals__', '__kwdefaults__', '__name__', '__qualname__'] \u4e0b\u8868\u603b\u7ed3\u4e86\u7528\u6237\u5b9a\u4e49\u7684\u51fd\u6570\u7684\u5c5e\u6027\u3002 \u4e0b\u9762\u7684\u4f8b\u5b50\u662f\u6f14\u793a\u4e86\u5728\u6307\u5b9a\u957f\u5ea6\u9644\u8fd1\u622a\u65ad\u5b57\u7b26\u4e32\u7684\u51fd\u6570\uff0c\u4ee5\u53ca\u63d0\u53d6\u5173\u4e8e\u51fd\u6570\u53c2\u6570\u7684\u4fe1\u606f\u7684\u65b9\u6cd5\u3002 \u53c2\u6570\u540d\u79f0\u5728 __code__.co_varnames \u4e2d\uff0c\u4f46\u8fd9\u91cc\u9762\u4e5f\u5305\u542b\u51fd\u6570\u5b9a\u4e49\u4f53\u4e2d\u521b\u5efa\u7684\u5c40\u90e8\u53d8\u91cf\u3002\u56e0\u6b64\uff0c\u53c2\u6570\u540d\u79f0\u662f\u524d N \u4e2a\u5b57\u7b26\u4e32\uff0c N \u7684\u503c\u7531 __code__.co_argcount \u786e\u5b9a\uff0c\u4f8b\u5b50\u91cc\u9762N\u662f2\uff0c\u5373\u53c2\u6570\u540d\u79f0\u662f text \u548c max_len \uff0c\u5c40\u90e8\u53d8\u91cf\u662f end \u3001 space_before \u3001 space_after \u3002 def clip ( text , max_len = 80 ): \"\"\" Get sub-string by the first blank before or after specified position. rfind() \u8fd4\u56de\u5b57\u7b26\u4e32\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u9879\u5219\u8fd4\u56de -1. \"\"\" end = None if len ( text ) > max_len : space_before = text . rfind ( ' ' , 0 , max_len ) if space_before >= 0 : end = space_before else : space_after = text . rfind ( ' ' , max_len ) if space_after >= 0 : end = space_after if end is None : end = len ( text ) return text [: end ] . rstrip () clip ( 'This is the string' , max_len = 10 ) # 'This is' clip . __defaults__ # (80,) clip . __code__ # \", line 1> clip . __code__ . co_varnames # ('text', 'max_len', 'end', 'space_before', 'space_after') clip . __code__ . co_argcount # 2 clip . __doc__ # '\\n Get sub-string by the first blank before or after specified position.\\n rfind() \u8fd4\u56de\u5b57\u7b26\u4e32\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u9879\u5219\u8fd4\u56de -1.\\n ' \u4e0a\u4f8b\u4e2d\uff0c\u53c2\u6570\u7684\u9ed8\u8ba4\u503c\u53ea\u80fd\u901a\u8fc7\u5b83\u4eec\u5728 __defaults__ \u5143\u7ec4\u4e2d\u7684\u4f4d\u7f6e\u786e\u5b9a\uff0c\u56e0\u6b64\u8981\u4ece\u540e\u5411\u524d\u626b\u63cf\u624d\u80fd\u628a\u53c2\u6570\u548c\u9ed8\u8ba4\u503c\u5bf9\u5e94\u8d77\u6765\uff0c\u6709\u4e9b\u4e0d\u5408\u7406\u3002\u5f15\u5165 inspect \u6a21\u5757\u540e\uff0c\u4e0a\u9762\u7684\u64cd\u4f5c\u5c31\u66f4\u5bb9\u6613\u4e86\u3002 inspect.signature \u51fd\u6570\u8fd4\u56de\u4e00\u4e2a inspect.Signature \u5bf9\u8c61\uff0c\u5b83\u6709\u4e00\u4e2a parameters \u5c5e\u6027\uff0c\u8fd9\u662f\u4e00\u4e2a\u6709\u5e8f\u6620\u5c04\uff0c\u628a\u53c2\u6570\u540d\u548c inspect.Parameter \u5bf9\u8c61\u5bf9\u5e94\u8d77\u6765\u3002\u5404\u4e2a Parameter \u5c5e\u6027\u4e5f\u6709\u81ea\u5df1\u7684\u5c5e\u6027\uff0c\u4f8b\u5982 name \u3001 default \u548c kind \u3002 from inspect import signature sig = signature ( clip ) type ( sig ) # print ( sig ) # (text, max_len=80) print ( str ( sig )) # (text, max_len=80) for name , param in sig . parameters . items (): print ( f ' { param . kind } : { name } = { param . default } ' ) # 1 : text = # 1 : max_len = 80 \u51fd\u6570\u6ce8\u89e3\u3002 Python 3 \u63d0\u4f9b\u4e86\u4e00\u79cd\u53e5\u6cd5\uff0c\u7528\u4e8e\u4e3a\u51fd\u6570\u58f0\u660e\u4e2d\u7684\u53c2\u6570\u548c\u8fd4\u56de\u503c\u9644\u52a0\u5143\u6570\u636e\u3002\u5bf9\u4e0a\u4f8b\u6dfb\u52a0\u6ce8\u89e3\u540e\u5982\u4e0b\u6240\u793a\uff0c\u4e8c\u8005\u552f\u4e00\u7684\u533a\u522b\u5728\u7b2c\u4e00\u884c\u3002 \u51fd\u6570\u58f0\u660e\u4e2d\u7684\u5404\u4e2a\u53c2\u6570\u53ef\u4ee5\u5728:\u4e4b\u540e\u589e\u52a0\u6ce8\u89e3\u8868\u8fbe\u5f0f\u3002 \u5982\u679c\u53c2\u6570\u6709\u9ed8\u8ba4\u503c\uff0c\u6ce8\u89e3\u653e\u5728\u53c2\u6570\u540d\u548c = \u53f7\u4e4b\u95f4\u3002 \u5982\u679c\u60f3\u6ce8\u89e3\u8fd4\u56de\u503c\uff0c\u5728)\u548c\u51fd\u6570\u58f0\u660e\u672b\u5c3e\u7684 : \u4e4b\u95f4\u6dfb\u52a0 -> \u548c\u4e00\u4e2a\u8868\u8fbe\u5f0f\u3002\u90a3\u4e2a\u8868\u8fbe\u5f0f\u53ef\u4ee5\u662f\u4efb\u4f55\u7c7b\u578b\u3002 \u6ce8\u89e3\u4e2d\u6700\u5e38\u7528\u7684\u7c7b\u578b\u662f\u7c7b\uff08\u5982 str \u6216 int \uff09\u548c\u5b57\u7b26\u4e32\uff08\u5982'int > 0'\uff09\u3002\u5728\u4e0b\u4f8b\u4e2d\uff0cmax_len\u53c2\u6570\u7684\u6ce8\u89e3\u7528\u7684\u662f\u5b57\u7b26\u4e32\u3002 \u6ce8\u89e3\u4e0d\u4f1a\u505a\u4efb\u4f55\u5904\u7406\uff0c\u53ea\u662f\u5b58\u50a8\u5728\u51fd\u6570\u7684 __annotations__ \u5c5e\u6027\uff08\u4e00\u4e2a\u5b57\u5178\uff09\u4e2d\u3002\u6362\u53e5\u8bdd\u8bf4\uff0c\u6ce8\u89e3\u5bf9Python\u89e3\u91ca\u5668\u6ca1\u6709\u4efb\u4f55\u610f\u4e49\u3002 \u6ce8\u89e3\u53ea\u662f\u5143\u6570\u636e \uff0c\u53ef\u4ee5\u4f9bIDE\u3001\u6846\u67b6\u548c\u88c5\u9970\u5668\u7b49\u5de5\u5177\u4f7f\u7528\u3002 return \u952e\u4fdd\u5b58\u7684\u662f\u8fd4\u56de\u503c\u6ce8\u89e3\uff0c\u5373\u4e0b\u4f8b\u4e2d\u51fd\u6570\u58f0\u660e\u91cc\u4ee5 -> \u6807\u8bb0\u7684\u90e8\u5206\u3002 def clip ( text : str , max_len : 'int > 0' = 80 ) -> str : \"\"\" Get sub-string by the first blank before or after specified position. rfind() \u8fd4\u56de\u5b57\u7b26\u4e32\u6700\u540e\u4e00\u6b21\u51fa\u73b0\u7684\u4f4d\u7f6e\uff0c\u5982\u679c\u6ca1\u6709\u5339\u914d\u9879\u5219\u8fd4\u56de -1. \"\"\" end = None if len ( text ) > max_len : space_before = text . rfind ( ' ' , 0 , max_len ) if space_before >= 0 : end = space_before else : space_after = text . rfind ( ' ' , max_len ) if space_after >= 0 : end = space_after if end is None : end = len ( text ) return text [: end ] . rstrip () clip ( 'This is the string' , max_len = 10 ) # 'This is' clip . __annotations__ # {'text': , 'max_len': 'int > 0', 'return': } signature \u51fd\u6570\u8fd4\u56de\u4e00\u4e2a Signature \u5bf9\u8c61\uff0c\u5b83\u6709\u4e00\u4e2a return_annotation \u5c5e\u6027\u548c\u4e00\u4e2a parameters \u5c5e\u6027\uff0c\u540e\u8005\u662f\u4e00\u4e2a\u5b57\u5178\uff0c\u628a\u53c2\u6570\u540d\u6620\u5c04\u5230 Parameter \u5bf9\u8c61\u4e0a\u3002\u6bcf\u4e2a Parameter \u5bf9\u8c61\u81ea\u5df1\u4e5f\u6709 annotation \u5c5e\u6027\u3002 from inspect import signature sig = signature ( clip ) print ( sig . return_annotation ) # for param in sig . parameters . values (): note = repr ( param . annotation ) . ljust ( 13 ) print ( f ' { note } : { param . name } = { param . default } ' ) # : text = # 'int > 0' : max_len = 80","title":"Python\u51fd\u6570\u5185\u7701\u5185\u7701"},{"location":"python/Foundation/ch05/","text":"Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027 \u00b6 Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027\uff1a \u5c01\u88c5 \u7ee7\u627f \u591a\u6001 \u5c01\u88c5 Encapsulation \u00b6 \u5c01\u88c5\u662f\u4f7f\u7528\u7279\u6b8a\u7684\u8bed\u6cd5\uff0c\u5bf9\u6210\u5458\u5c5e\u6027\u548c\u6210\u5458\u65b9\u6cd5\u8fdb\u884c\u5305\u88c5\uff0c\u9650\u5236\u4e00\u4e9b\u8bbf\u95ee\u548c\u64cd\u4f5c\uff0c\u8fbe\u5230\u4fdd\u62a4\u548c\u9690\u85cf\u7684\u76ee\u7684\u3002 \u5c01\u88c5\u673a\u5236\u4fdd\u8bc1\u4e86\u7c7b\u5185\u90e8\u6570\u636e\u7ed3\u6784\u7684\u5b8c\u6574\u6027\uff0c\u56e0\u4e3a\u4f7f\u7528\u7c7b\u7684\u7528\u6237\u65e0\u6cd5\u76f4\u63a5\u770b\u5230\u7c7b\u4e2d\u7684\u6570\u636e\u7ed3\u6784\uff0c\u53ea\u80fd\u4f7f\u7528\u7c7b\u5141\u8bb8\u516c\u5f00\u7684\u6570\u636e\uff0c\u5f88\u597d\u5730\u907f\u514d\u4e86\u5916\u90e8\u5bf9\u5185\u90e8\u6570\u636e\u7684\u5f71\u54cd\uff0c\u63d0\u9ad8\u4e86\u7a0b\u5e8f\u7684\u53ef\u7ef4\u62a4\u6027\u3002 \u5bf9\u4e00\u4e2a\u7c7b\u5b9e\u73b0\u826f\u597d\u7684\u5c01\u88c5\uff0c\u7528\u6237\u53ea\u80fd\u501f\u52a9\u66b4\u9732\u51fa\u6765\u7684\u7c7b\u65b9\u6cd5\u6765\u8bbf\u95ee\u6570\u636e\uff0c\u53ef\u4ee5\u5728\u8fd9\u4e9b\u66b4\u9732\u7684\u65b9\u6cd5\u4e2d\u52a0\u5165\u9002\u5f53\u7684\u63a7\u5236\u903b\u8f91\uff0c\u5373\u53ef\u63a7\u5236\u7528\u6237\u5bf9\u7c7b\u4e2d\u5c5e\u6027\u6216\u65b9\u6cd5\u7684\u64cd\u4f5c\u3002 \u5bf9\u7c7b\u8fdb\u884c\u826f\u597d\u7684\u5c01\u88c5\uff0c\u4e3b\u8981\u662f\u5185\u90e8\u4f7f\u7528\u5c01\u88c5\u7684\u6210\u5458\uff0c\u4e5f\u63d0\u9ad8\u4e86\u4ee3\u7801\u7684\u590d\u7528\u6027\u3002 \u7c7b\u6210\u5458\u5c01\u88c5\u7684\u7ea7\u522b\uff1a \u516c\u6709\u7684\uff08public\uff09 \u4fdd\u62a4\u7684\uff08protected\uff09\uff0c\u5728Python\u4e2d\u5e76\u6ca1\u6709\u5b9e\u73b0protected\u5c01\u88c5\uff0c\u5c5e\u4e8e\u5f00\u53d1\u8005\u7684\u7ea6\u5b9a\u4fd7\u6210\u3002 \u79c1\u6709\u7684\uff08private\uff09\uff0c\u5728Python\u4e2dprivate\u5c01\u88c5\u662f\u901a\u8fc7\u6539\u540d\u7b56\u7565\u6765\u5b9e\u73b0\u7684\uff0c\u5e76\u4e0d\u662f\u771f\u6b63\u7684\u79c1\u6709\u5316\u3002 \u8bbf\u95ee\u9650\u5236 \u5171\u6709\u7684public \u53d7\u4fdd\u62a4\u7684protected \u79c1\u6709\u7684private \u5728\u7c7b\u7684\u5185\u90e8 OK OK OK \u5728\u7c7b\u7684\u5916\u90e8 OK No (Python\u4e2d\u53ef\u4ee5) No \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\u3002(\u53c2\u8003 \u79c1\u6709\u53d8\u91cfPrivate Variables ) name \u662f\u5171\u6709\u5c5e\u6027\uff0c\u53ef\u4ee5\u5728\u5916\u90e8\u8c03\u7528tom.name\u3002 _age \u662f\u53d7\u4fdd\u62a4\u7684\u5c5e\u6027\uff0c\u7406\u8bba\u4e0a\u5728\u5916\u90e8\u662f\u4e0d\u53ef\u8c03\u7528\u7684\uff0c\u4f46\u5728Python\u4e2d\u662f\u53ef\u4ee5\u8c03\u7528\u7684 tom._age \u3002 __phone \u662f\u79c1\u6709\u5c5e\u6027\uff0c\u5728\u5916\u90e8\u662f\u4e0d\u53ef\u8c03\u7528\u7684\uff0c tom.__get_phone() \u62a5\u9519\u201c\u5c5e\u6027\u4e0d\u5b58\u5728\u201d\u3002 \u5bf9\u5e94\u65b9\u6cd5\u4e5f\u662f\u7c7b\u4f3c\u3002 \u5728\u7c7b\u7684\u5185\u90e8\u5bf9\u53d7\u4fdd\u62a4\u5bf9\u8c61\u548c\u79c1\u6709\u5bf9\u8c61\u6ca1\u6709\u8bbf\u95ee\u9650\u5236\u3002 _get_age \u53ef\u4ee5\u8c03\u7528\u79c1\u6709\u5c5e\u6027 __phone \u3002 class Person (): name = 'name' # public _age = 0 # protected __phone = 'phone' # private def __init__ ( self , n , a , p ): self . name = n self . _age = a self . __phone = p def get_name ( self ): print ( f 'My name is { self . name } ' ) def _get_age ( self ): print ( f 'My age is { self . _age } ' ) print ( f 'My age is { self . __phone } ' ) def __get_phone ( self ): print ( f 'My phone is { self . __phone } ' ) tom = Person ( 'Tom' , 18 , 12345678 ) tom . name # 'Tom' tom . _age # 18 tom . __phone # AttributeError: 'Person' object has no attribute '__phone' tom . get_name () # My name is Tom tom . _get_age () # My age is 18 # My age is 12345678 tom . __get_phone () # AttributeError: 'Person' object has no attribute '__get_phone' \u7ee7\u627f Inheritance \u00b6 \u5728\u4e0d\u6307\u5b9a\u7ee7\u627f\u7684\u7236\u7c7b\u65f6\uff0c\u6240\u6709\u7c7b\u90fd\u7ee7\u627fobject\u7c7b\uff08\u7cfb\u7edf\u63d0\u4f9b\uff09\u3002 \u88ab\u5176\u5b83\u7c7b\u7ee7\u627f\u7684\u7c7b\uff0c\u79f0\u4e3a\u7236\u7c7b\uff0c\u6216\u8005\u57fa\u7c7b\uff0c\u6216\u8005\u8d85\u7c7b\u3002 \u7ee7\u627f\u5176\u5b83\u7c7b\u7684\u7c7b\uff0c\u79f0\u4e3a\u5b50\u7c7b\uff0c\u6216\u8005\u6d3e\u751f\u7c7b\uff08derived class\uff09\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u5c31\u62e5\u6709\u4e86\u7236\u7c7b\u4e2d\u7684\u6240\u6709\u6210\u5458\uff08\u9664\u4e86\u79c1\u6709\u6210\u5458\uff09\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u5e76\u4e0d\u4f1a\u628a\u7236\u7c7b\u7684\u6210\u5458\u590d\u5236\u7ed9\u5b50\u7c7b\uff0c\u800c\u662f\u5f15\u7528\u3002 \u5b50\u7c7b\u53ef\u4ee5\u76f4\u63a5\u8c03\u7528\u7236\u7c7b\u7684\u65b9\u6cd5 super().BaseClassName \u3002\u5982\u679c\u7236\u7c7b\u65b9\u6cd5\u6709\u53c2\u6570\u8981\u6c42\uff0c\u5b50\u7c7b\u8c03\u7528\u65f6\u4e5f\u6709\u53c2\u6570\u8981\u6c42\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u53ef\u4ee5\u91cd\u65b0\u5b9a\u4e49\u7236\u7c7b\u4e2d\u7684\u65b9\u6cd5\uff0c\u79f0\u4e3a**\u91cd\u5199\uff08Override\uff09**\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u5b9a\u4e49\u7236\u7c7b\u4e2d\u6ca1\u6709\u7684\u65b9\u6cd5\uff0c\u88ab\u79f0\u4e3a\u5bf9\u7236\u7c7b\u7684\u6269\u5c55\u3002 \u4e00\u4e2a\u7236\u7c7b\u53ef\u4ee5\u88ab\u591a\u4e2a\u5b50\u7c7b\u7ee7\u627f\u3002 **\u6d3e\u751f\u7c7b\uff08derived class\uff09**\u5b9a\u4e49\u7684\u8bed\u6cd5\u5982\u4e0b\u6240\u793a: class BaseClassName (): < statement - 1 > . . . < statement - N > class DerivedClassName ( BaseClassName ): < statement - 1 > . . . < statement - N > \u540d\u79f0 BaseClassName \u5fc5\u987b\u5b9a\u4e49\u4e8e\u5305\u542b\u6d3e\u751f\u7c7b\u5b9a\u4e49\u7684\u4f5c\u7528\u57df\u4e2d\u3002 \u4e5f\u5141\u8bb8\u7528\u5176\u4ed6\u4efb\u610f\u8868\u8fbe\u5f0f\u4ee3\u66ff\u57fa\u7c7b\u540d\u79f0\u6240\u5728\u7684\u4f4d\u7f6e\uff0c\u4f8b\u5982\uff0c\u5f53\u57fa\u7c7b\u5b9a\u4e49\u5728\u53e6\u4e00\u4e2a\u6a21\u5757\u4e2d\u7684\u65f6\u5019: class DerivedClassName ( modname . BaseClassName ): \u6d3e\u751f\u7c7b\u5b9a\u4e49\u7684\u6267\u884c\u8fc7\u7a0b\u4e0e\u57fa\u7c7b\u76f8\u540c\u3002 \u5f53\u6784\u9020\u7c7b\u5bf9\u8c61\u65f6\uff0c\u57fa\u7c7b\u4f1a\u88ab\u8bb0\u4f4f\u3002 \u6b64\u4fe1\u606f\u5c06\u88ab\u7528\u6765\u89e3\u6790\u5c5e\u6027\u5f15\u7528\uff1a\u5982\u679c\u8bf7\u6c42\u7684\u5c5e\u6027\u5728\u7c7b\u4e2d\u627e\u4e0d\u5230\uff0c\u641c\u7d22\u5c06\u8f6c\u5f80\u57fa\u7c7b\u4e2d\u8fdb\u884c\u67e5\u627e\u3002 \u5982\u679c\u57fa\u7c7b\u672c\u8eab\u4e5f\u6d3e\u751f\u81ea\u5176\u4ed6\u67d0\u4e2a\u7c7b\uff0c\u5219\u6b64\u89c4\u5219\u5c06\u88ab\u9012\u5f52\u5730\uff08recursively\uff09\u5e94\u7528\u3002 \u6d3e\u751f\u7c7b\u7684\u5b9e\u4f8b\u5316\u6ca1\u6709\u4efb\u4f55\u7279\u6b8a\u4e4b\u5904: DerivedClassName() \u4f1a\u521b\u5efa\u8be5\u7c7b\u7684\u4e00\u4e2a*\u65b0\u5b9e\u4f8b*\u3002 \u65b9\u6cd5\u5f15\u7528\u5c06\u6309\u4ee5\u4e0b\u65b9\u5f0f\u89e3\u6790\uff1a\u641c\u7d22\u76f8\u5e94\u7684\u7c7b\u5c5e\u6027\uff0c\u5982\u6709\u5fc5\u8981\u5c06\u6309\u57fa\u7c7b\u7ee7\u627f\u94fe\u9010\u6b65\u5411\u4e0b\u67e5\u627e\uff0c\u5982\u679c\u4ea7\u751f\u4e86\u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\u5219\u65b9\u6cd5\u5f15\u7528\u5c31\u751f\u6548\u3002 \u6d3e\u751f\u7c7b\u53ef\u80fd\u4f1a\u91cd\u5199\uff08override\uff09\u5176\u57fa\u7c7b\u7684\u65b9\u6cd5\u3002 \u56e0\u4e3a\u65b9\u6cd5\u5728\u8c03\u7528\u540c\u4e00\u5bf9\u8c61\u7684\u5176\u4ed6\u65b9\u6cd5\u65f6\u6ca1\u6709\u7279\u6b8a\u6743\u9650\uff0c\u6240\u4ee5\u8c03\u7528\u540c\u4e00\u57fa\u7c7b\u4e2d\u5b9a\u4e49\u7684\u53e6\u4e00\u65b9\u6cd5\u7684\u57fa\u7c7b\u65b9\u6cd5\u6700\u7ec8\u53ef\u80fd\u4f1a\u8c03\u7528\u8986\u76d6\u5b83\u7684\u6d3e\u751f\u7c7b\u7684\u65b9\u6cd5\u3002 \u5728\u6d3e\u751f\u7c7b\u4e2d\u7684\u91cd\u8f7d\u65b9\u6cd5\uff08overriding method\uff09\u5b9e\u9645\u4e0a\u53ef\u80fd\u60f3\u8981\u6269\u5c55\u800c\u975e\u7b80\u5355\u5730\u66ff\u6362\u540c\u540d\u7684\u57fa\u7c7b\u65b9\u6cd5\u3002 \u6709\u4e00\u79cd\u65b9\u5f0f\u53ef\u4ee5\u7b80\u5355\u5730\u76f4\u63a5\u8c03\u7528\u57fa\u7c7b\u65b9\u6cd5\uff1a\u5373\u8c03\u7528 BaseClassName.methodname(self, arguments) \u3002 \u8bf7\u6ce8\u610f\uff0c\u4ec5\u5f53\u6b64\u57fa\u7c7b\u53ef\u5728\u5168\u5c40\u4f5c\u7528\u57df\u4e2d\u4ee5 BaseClassName \u7684\u540d\u79f0\u88ab\u8bbf\u95ee\u65f6\u65b9\u53ef\u4f7f\u7528\u6b64\u65b9\u5f0f\u3002 Python\u6709\u4e24\u4e2a\u5185\u7f6e\u51fd\u6570\u53ef\u88ab\u7528\u4e8e\u7ee7\u627f\u673a\u5236\uff1a \u4f7f\u7528 isinstance() \u6765\u68c0\u67e5\u4e00\u4e2a\u5b9e\u4f8b\u7684\u7c7b\u578b: isinstance(obj, int) \u4ec5\u4f1a\u5728 obj.__class__ \u4e3a int \u6216\u67d0\u4e2a\u6d3e\u751f\u81ea int \u7684\u7c7b\u65f6\u4e3a True \u3002 \u4f7f\u7528 issubclass() \u6765\u68c0\u67e5\u7c7b\u7684\u7ee7\u627f\u5173\u7cfb: issubclass(bool, int) \u4e3a True \uff0c\u56e0\u4e3a bool \u662f int \u7684\u5b50\u7c7b\u3002 \u4f46\u662f\uff0c issubclass(float, int) \u4e3a False \uff0c\u56e0\u4e3a float \u4e0d\u662f int \u7684\u5b50\u7c7b\u3002 \u591a\u91cd\u7ee7\u627f Multiple Inheritance \u00b6 \u5355\u7ee7\u627f\uff08single-inheritance\uff09\uff1a\u4e00\u4e2a\u7c7b\u53ea\u80fd\u7ee7\u627f\u4e00\u4e2a\u7236\u7c7b\u65b9\u5f0f\u3002 class DerivedClassName ( BaseClassName ): < statement - 1 > . . . < statement - N > \u591a\u7ee7\u627f\uff08Multiple Inheritance\uff09\uff1a\u4e00\u4e2a\u7c7b\u53bb\u7ee7\u627f\u591a\u4e2a\u7c7b\u7684\u65b9\u5f0f\u3002\u5b9a\u4e49\u8bed\u53e5\u5982\u4e0b\u6240\u793a class DerivedClassName ( Base1 , Base2 , Base3 ): < statement - 1 > . . . < statement - N > \u5728\u6700\u7b80\u5355\u7684\u60c5\u51b5\u4e0b\uff0c\u641c\u7d22\u4ece\u7236\u7c7b\u6240\u7ee7\u627f\u5c5e\u6027\u7684\u64cd\u4f5c\u662f\u6df1\u5ea6\u4f18\u5148\uff08depth-first\uff09\u3001\u4ece\u5de6\u81f3\u53f3\uff08left-to-right\uff09\u7684\uff0c\u5f53\u5c42\u6b21\u7ed3\u6784\u4e2d\u5b58\u5728\u91cd\u53e0\u65f6\u4e0d\u4f1a\u5728\u540c\u4e00\u4e2a\u7c7b\u4e2d\u641c\u7d22\u4e24\u6b21\u3002 \u56e0\u6b64\uff0c\u5982\u679c\u67d0\u4e00\u5c5e\u6027\u5728 DerivedClassName \u4e2d\u672a\u627e\u5230\uff0c\u5219\u4f1a\u5230 Base1 \u4e2d\u641c\u7d22\u5b83\uff0c\u7136\u540e\uff08\u9012\u5f52\u5730\uff09\u5230 Base1 \u7684\u57fa\u7c7b\u4e2d\u641c\u7d22\uff0c\u5982\u679c\u5728\u90a3\u91cc\u672a\u627e\u5230\uff0c\u518d\u5230 Base2 \u4e2d\u641c\u7d22\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002 \u771f\u5b9e\u60c5\u51b5\u66f4\u590d\u6742\uff1b\u65b9\u6cd5\u89e3\u6790\u987a\u5e8f\u4f1a\u52a8\u6001\u6539\u53d8\u4ee5\u652f\u6301\u5bf9 super() \u7684\u534f\u540c\u8c03\u7528\u3002 \u8fd9\u79cd\u65b9\u5f0f\u5728\u67d0\u4e9b\u5176\u4ed6\u591a\u91cd\u7ee7\u627f\u578b\u8bed\u8a00\u4e2d\u88ab\u79f0\u4e3a**\u540e\u7eed\u65b9\u6cd5\u8c03\u7528\uff08call-next-method\uff09**\uff0c\u5b83\u6bd4**\u5355\u7ee7\u627f\uff08single-inheritance\uff09**\u8bed\u8a00\u4e2d\u7684 uper \u8c03\u7528\u66f4\u5f3a\u5927\u3002 \u52a8\u6001\u6539\u53d8\u987a\u5e8f\u662f\u6709\u5fc5\u8981\u7684\uff0c\u56e0\u4e3a\u6240\u6709\u591a\u91cd\u7ee7\u627f\u7684\u60c5\u51b5\u90fd\u4f1a\u663e\u793a\u51fa\u4e00\u4e2a\u6216\u66f4\u591a\u7684\u83f1\u5f62\u5173\u8054\uff08diamond relationships\uff09\uff08\u5373\u81f3\u5c11\u6709\u4e00\u4e2a\u7236\u7c7b\u53ef\u901a\u8fc7\u591a\u6761\u8def\u5f84\u88ab\u6700\u5e95\u5c42\u7c7b\u6240\u8bbf\u95ee\uff09\u3002 \u4f8b\u5982\uff0c\u6240\u6709\u7c7b\u90fd\u662f\u7ee7\u627f\u81ea object \uff0c\u56e0\u6b64\u4efb\u4f55\u591a\u91cd\u7ee7\u627f\u7684\u60c5\u51b5\u90fd\u63d0\u4f9b\u4e86\u4e00\u6761\u4ee5\u4e0a\u7684\u8def\u5f84\u53ef\u4ee5\u901a\u5411 object \u3002 \u4e3a\u4e86\u786e\u4fdd\u57fa\u7c7b\u4e0d\u4f1a\u88ab\u8bbf\u95ee\u4e00\u6b21\u4ee5\u4e0a\uff0c\u52a8\u6001\u7b97\u6cd5\u4f1a\u7528\u4e00\u79cd\u7279\u6b8a\u65b9\u5f0f\u5c06\u641c\u7d22\u987a\u5e8f\u7ebf\u6027\u5316\uff0c \u4fdd\u7559\u6bcf\u4e2a\u7c7b\u6240\u6307\u5b9a\u7684\u4ece\u5de6\u81f3\u53f3\u7684\u987a\u5e8f\uff0c\u53ea\u8c03\u7528\u6bcf\u4e2a\u7236\u7c7b\u4e00\u6b21\uff0c\u5e76\u4e14\u4fdd\u6301\u5355\u8c03\uff08monotonic\uff09\uff08\u5373\u4e00\u4e2a\u7c7b\u53ef\u4ee5\u88ab\u5b50\u7c7b\u5316\u800c\u4e0d\u5f71\u54cd\u5176\u7236\u7c7b\u7684\u4f18\u5148\u987a\u5e8f\uff09\u3002 \u603b\u800c\u8a00\u4e4b\uff0c\u8fd9\u4e9b\u7279\u6027\u4f7f\u5f97\u8bbe\u8ba1\u5177\u6709\u591a\u91cd\u7ee7\u627f\u7684\u53ef\u9760\u4e14\u53ef\u6269\u5c55\u7684\u7c7b\u6210\u4e3a\u53ef\u80fd\u3002 \u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u5b9a\u4e49\u4e863\u4e2a\u7c7b\u548c\u7ee7\u627f\u5173\u7cfb\u3002 class F (): def drink ( self ): print ( \"Drink Beer\" ) class M (): def drink ( self ): print ( \"Drink Red Wine\" ) class C ( F , M ): def drink ( self ): print ( \"Drink Water\" ) \u6267\u884c\u7ed3\u679c\u662f c = C () c . drink () # Drink Water \u65b9\u6cd51\uff1a\u6309\u7167mro\u8fdb\u884c\u7ee7\u627f\u67e5\u627e\u3002 \u5982\u679c\u628a C \u7c7b\u6539\u5199\u4e3a\u5982\u4e0b\uff0c\u53ef\u4ee5\u8c03\u7528\u7236\u7c7b\uff0c\u53c2\u7167 C \u7c7b\u7684mro\u8fdb\u884c\uff0c mro \u91cc\u9762\u7c7b F \u7684\u4e0a\u4e00\u7ea7\u662f\u7c7b M \uff0c\u6240\u4ee5\u7c7b F \u4e2d\u7684 super() \u5c31\u662f\u6307\u7c7b M \u3002 class C ( F , M ): def drink ( self ): super () . drink () print ( \"Drink Water\" ) c = C () c . drink () # Drink Beer # Drink Water C . mro () # [, , , ] \u65b9\u6cd52\uff1a\u201c\u6307\u540d\u9053\u59d3\u201d\u8c03\u7528\u3002\u5982\u679c\u628a C \u7c7b\u6539\u5199\u4e3a\u5982\u4e0b\uff0c\u53ef\u4ee5\u8c03\u7528 M \u7c7b\u3002 class C ( F , M ): def drink ( self ): M . drink ( self ) print ( \"Drink Water\" ) c = C () c . drink () # Drink Red Wine # Drink Water \u83f1\u5f62\u7ee7\u627f\u548c\u7ee7\u627f\u5173\u7cfb\u68c0\u6d4b \u00b6 \u83f1\u5f62\u7ee7\u627f\u7684\u63cf\u8ff0\u662f\uff0c\u7c7b A \u4f5c\u4e3a\u57fa\u7c7b\uff08\u8fd9\u91cc\u57fa\u7c7b\u662f\u6307\u975e object \u7c7b\uff09\uff0c\u7c7b B \u548c\u7c7b C \u540c\u65f6\u7ee7\u627f\u7c7b A \uff0c\u7136\u540e\u7c7b D \u53c8\u7ee7\u627f\u7c7b B \u548c\u7c7b C \uff0c\u5982\u4e0b\u56fe\uff0c\u770b\u8d77\u6765\u50cf\u4e2a\u94bb\u77f3\u7684\u5f62\u72b6\u3002 A / \\ B C \\ / D \u5728\u8fd9\u79cd\u7ed3\u6784\u4e2d\uff0c\u5728\u8c03\u7528\u987a\u5e8f\u4e0a\u5c31\u4f1a\u51fa\u73b0\u7591\u60d1\uff0c\u8c03\u7528\u987a\u5e8f\u7a76\u7adf\u662f\u4ee5\u4e0b\u54ea\u4e00\u79cd\u987a\u5e8f\u5462\uff1f D->B->A->C\uff08\u6df1\u5ea6\u4f18\u5148\uff09 D->B->C->A\uff08\u5e7f\u5ea6\u4f18\u5148\uff09 \u770b\u4e0b\u9762\u4ee3\u7801\uff0c\u5728Python3\u4e2d\uff0c**\u83f1\u5f62**\u7684\u591a\u7ee7\u627f\u5173\u7cfb\u662f\u6309\u7167D->B->C->A**\u5e7f\u5ea6\u4f18\u5148**\u7684\u641c\u7d22\u65b9\u5f0f\u3002 class A (): pass class B ( A ): def test ( self ): print ( \"init B.test()\" ) class C ( A ): def test ( self ): print ( \"init C.test()\" ) class D ( B , C ): pass d = D () d . test () # init B.test() D . mro () # [, , , , ] \u5bf9\u4e8e\u4e0b\u9762\u8fd9\u79cd**\u975e\u83f1\u5f62**\u7684\u591a\u7ee7\u627f\u5173\u7cfb\uff0c\u67e5\u627e\u987a\u5e8f\u662fA->B->E->C->F->D**\u6df1\u5ea6\u4f18\u5148**\u7684\u641c\u7d22\u65b9\u5f0f\u3002 E F | | B ( E ) C ( F ) D | | | \\ | / \\ | / A ( B , C , D ) \u4ee3\u7801\u5b9e\u73b0\uff1a class D (): def test ( self ): print ( \"init D.test()\" ) class F (): def test ( self ): print ( \"init F.test()\" ) class C ( F ): pass class E (): pass class B ( E ): pass class A ( B , C , D ): pass a = A () a . test () # init F.test() A . mro () # [, , , , , , ] \u603b\u7ed3\uff1a \u7ee7\u627f\u7ed3\u6784\u8981\u5c3d\u91cf\u7b80\u5355\uff0c\u4e0d\u8981\u8fc7\u4e8e\u590d\u6742\u3002 \u63a8\u8350\u4f7f\u7528minxins\u673a\u5236\uff0c\u5728\u591a\u7ee7\u627f\u80cc\u666f\u4e0b\uff0c\u6ee1\u8db3\u7ee7\u627f\u7684\u4ec0\u4e48\u662f\u4ec0\u4e48\u7684\u5173\u7cfb\uff08is-a\uff09 \u591a\u7ee7\u627f\u5173\u7cfb\u7684minxins\u673a\u5236 \u00b6 \u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u5982\u679c\u5728 Vehicle \u7c7b\u4e2d\u5b9a\u4e49\u4e86 fly \u7684\u65b9\u6cd5\uff0c\u4f1a\u5bfc\u81f4 Car(Vehicle) \u7684\u7ee7\u627f\u5173\u7cfb\u51fa\u73b0\u77db\u76fe\uff0c\u6c7d\u8f66\u5e76\u4e0d\u4f1a\u98de\uff0c\u4f46\u6309\u7167\u4e0a\u8ff0\u7ee7\u627f\u5173\u7cfb\uff0c\u6c7d\u8f66\u4e5f\u80fd\u98de\u4e86\u3002 \u4f46\u662f\u5982\u679c\u6c11\u822a\u98de\u673a\u548c\u76f4\u5347\u673a\u90fd\u5404\u81ea\u5199\u81ea\u5df1\u7684\u98de\u884cfly\u65b9\u6cd5\uff0c\u53c8\u8fdd\u80cc\u4e86\u4ee3\u7801\u5c3d\u53ef\u80fd\u91cd\u7528\u7684\u539f\u5219\u3002 class Vehicle : # \u4ea4\u901a\u5de5\u5177 def fly ( self ): ''' \u98de\u884c\u529f\u80fd\u76f8\u5e94\u7684\u4ee3\u7801 ''' print ( \"I am flying\" ) # \u6c11\u822a\u98de\u673a class CivilAircraft ( Vehicle ): pass # \u76f4\u5347\u98de\u673a class Helicopter ( Vehicle ): pass # \u6c7d\u8f66 class Car ( Vehicle ): pass Python\u4e2d\u6ca1\u6709\u7c7b\u4f3cJava\u63a5\u53e3interface\u7684\u529f\u80fd\uff0c\u4f46\u63d0\u4f9b\u4e86Mixins\u673a\u5236\u3002 Python\u5bf9\u4e8e Mixin \u7c7b\u7684\u547d\u540d\u65b9\u5f0f\u4e00\u822c\u4ee5 Mixin , able , ible \u4e3a\u540e\u7f00\u3002 Mixin \u7c7b\u5fc5\u987b\u529f\u80fd\u5355\u4e00\uff0c\u5982\u679c\u6709\u591a\u4e2a\u529f\u80fd\uff0c\u90a3\u5c31\u5199\u591a\u4e2aMixin\u7c7b\u3002 \u4e00\u4e2a\u7c7b\u53ef\u4ee5\u7ee7\u627f\u591a\u4e2a Mixin \u7c7b\uff0c\u4e3a\u4e86\u4fdd\u8bc1\u9075\u5faa\u7ee7\u627f\u7684\u201cis-a\u201d\u539f\u5219\uff0c\u53ea\u80fd\u7ee7\u627f\u4e00\u4e2a\u6807\u8bc6\u5176\u5f52\u5c5e\u542b\u4e49\u7684\u7236\u7c7b Mixin \u7c7b\u4e0d\u4f9d\u8d56\u4e8e\u5b50\u7c7b\u7684\u5b9e\u73b0\u3002 \u5b50\u7c7b\u5373\u4fbf\u6ca1\u6709\u7ee7\u627f\u8fd9\u4e2a Mixin \u7c7b\u7c7b\uff0c\u4e5f\u7167\u6837\u53ef\u4ee5\u5de5\u4f5c\uff0c\u5c31\u662f\u7f3a\u5c11\u4e86\u67d0\u4e2a\u529f\u80fd\u3002 \u6211\u4eec\u5b9a\u4e49\u7684 Mixin \u7c7b\u8d8a\u591a\uff0c\u5b50\u7c7b\u7684\u4ee3\u7801\u53ef\u8bfb\u6027\u5c31\u4f1a\u8d8a\u5dee\u3002 # \u4ea4\u901a\u5de5\u5177 class Vehicle : pass # \u4e3a\u5f53\u524d\u7c7b\u6df7\u5165\u4e00\u4e9b\u529f\u80fd\uff0c\u4e0d\u662f\u4e00\u4e2a\u5355\u7eaf\u7684\u7c7b class FlyableMixin : def fly ( self ): ''' \u98de\u884c\u529f\u80fd\u76f8\u5e94\u7684\u4ee3\u7801 ''' print ( \"I am flying\" ) # \u6c11\u822a\u98de\u673a class CivilAircraft ( FlyableMixin , Vehicle ): pass # \u76f4\u5347\u98de\u673a class Helicopter ( FlyableMixin , Vehicle ): pass # \u6c7d\u8f66 class Car ( Vehicle ): pass \u7ec4\u5408\uff08Class Combination\uff09 \u00b6 \u5728\u4e00\u4e2a\u7c7b\u4e2d\u4ee5\u53e6\u4e00\u4e2a\u7c7b\u7684\u5bf9\u8c61\u4f5c\u4e3a\u6570\u636e\u5c5e\u6027\uff0c\u79f0\u4e3a\u7c7b\u7684**\u7ec4\u5408**\u3002\u7ec4\u5408\u4e0e\u7ee7\u627f\u90fd\u662f\u7528\u6765\u89e3\u51b3\u4ee3\u7801\u7684\u91cd\u7528\u6027\u95ee\u9898\u3002 \u7ee7\u627f\u4f53\u73b0\u201c\u662f\u201d\u7684\u5173\u7cfb\uff0c\u5f53\u7c7b\u4e4b\u95f4\u6709\u5f88\u591a\u76f8\u540c\u4e4b\u5904\uff0c\u7528\u7ee7\u627f\u3002 \u7ec4\u5408\u4f53\u73b0\u201c\u6709\u201d\u7684\u5173\u7cfb\uff0c\u5f53\u7c7b\u4e4b\u95f4\u6709\u663e\u8457\u4e0d\u540c\uff0c\u4e00\u4e2a\u7c7b\u662f\u53e6\u4e00\u4e2a\u7c7b\u7684\u5c5e\u6027\u662f\uff0c\u7528\u7ec4\u5408\u3002 \u4e0b\u4f8b\u662f\u8ba1\u7b97\u5706\u73af\u7684\u9762\u79ef\u548c\u5468\u957f\uff0c\u5706\u73af\u662f\u7531\u4e24\u4e2a\u5706\u7ec4\u6210\u7684\uff0c\u5706\u73af\u7684\u9762\u79ef\u662f\u5916\u9762\u5706\u7684\u9762\u79ef\u51cf\u53bb\u5185\u90e8\u5706\u7684\u9762\u79ef\u3002\u5706\u73af\u7684\u5468\u957f\u662f\u5185\u90e8\u5706\u7684\u5468\u957f\u52a0\u4e0a\u5916\u90e8\u5706\u7684\u5468\u957f\u3002 \u8fd9\u4e2a\u4f8b\u5b50\u6f14\u793a\u4e86\u7c7b ring \u91cc\u9762\u7684\u5c5e\u6027 circle1 \u548c circle2 \u6b63\u662f\u53e6\u4e00\u4e2a\u7c7b Circle \u3002 from math import pi class Circle (): def __init__ ( self , r ): self . r = r def area ( self ): return pi * self . r * self . r def perimeter ( self ): return 2 * pi * self . r class Ring (): def __init__ ( self , r1 , r2 ): self . circle1 = Circle ( r1 ) self . circle2 = Circle ( r2 ) def area ( self ): return abs ( self . circle1 . area () - self . circle2 . area ()) def permiter ( self ): return self . circle1 . perimeter () + self . circle2 . perimeter () ring = Ring ( 5 , 8 ) print ( ring . area ()) # 122.52211349000193 print ( ring . permiter ()) # 81.68140899333463 \u4e0b\u9762\u7684\u4f8b\u5b50\u6f14\u793a\u4e86\u5982\u4f55\u901a\u8fc7\u4f20\u53c2\u7684\u65b9\u5f0f\u8fdb\u884c\u7c7b\u7684\u7ec4\u5408\u3002 class Birthday (): def __init__ ( self , year , month , day ): self . year = year self . month = month self . day = day class Course (): def __init__ ( self , course_name , course_period ): self . course_name = course_name self . course_period = course_period class Professor (): def __init__ ( self , name , gender , birth , course ): self . name = name self . gender = gender self . birth = birth self . course = course def teach ( self ): print ( f \"Professor name: { self . name } ; Gender: { self . gender } ; Birthday: { self . birth . year } - { self . birth . month }{ self . birth . day } , Course name: { self . course . course_name } and period: { self . course . course_period } \" ) prof = Professor ( 'Tom' , 'Male' , Birthday ( 1985 , 5 , 5 ), Course ( 'Chinese' , '2022/3/1 ~ 2022/6/30' )) prof . teach () # Professor name: Tom; Gender: Male; Birthday: 1985-55, Course name: Chinese and period: 2022/3/1 ~ 2022/6/30 \u591a\u6001 Polymorphism \u00b6 \u591a\u6001\u610f\u5473\u7740\u76f8\u540c\u7684\u51fd\u6570\u540d\u7528\u4e8e\u4e0d\u540c\u7684\u60c5\u5f62\u3002 \u5982\u4e0b\u4f8b\uff0c len() \u88ab\u7528\u4e8e\u4e0d\u540c\u7684\u60c5\u5f62\u3002 # len() being used for a string print ( len ( \"geeks\" )) # 5 # len() being used for a list print ( len ([ 10 , 20 , 30 ])) # 3 \u7c7b\u65b9\u6cd5\u7684\u591a\u6001\u6027 \u00b6 \u4e0b\u9762\u7684\u4ee3\u7801\u5c55\u793a\u4e86 Python \u5982\u4f55\u4ee5\u76f8\u540c\u7684\u65b9\u5f0f\u4f7f\u7528\u4e24\u79cd\u4e0d\u540c\u7684\u7c7b\u7c7b\u578b\u3002 \u6211\u4eec\u521b\u5efa\u4e86\u4e00\u4e2a\u904d\u5386\u5bf9\u8c61\u5143\u7ec4\u7684 for \u5faa\u73af\u3002 \u7136\u540e\u8c03\u7528\u65b9\u6cd5\u800c\u4e0d\u7528\u5173\u5fc3\u6bcf\u4e2a\u5bf9\u8c61\u662f\u54ea\u4e2a\u7c7b\u7c7b\u578b\u3002 \u6211\u4eec\u5047\u8bbe\u8fd9\u4e9b\u65b9\u6cd5\u5b9e\u9645\u4e0a\u5b58\u5728\u4e8e\u6bcf\u4e2a\u7c7b\u4e2d\u3002 class India (): def capital ( self ): print ( \"New Delhi is the capital of India.\" ) def language ( self ): print ( \"Hindi is the most widely spoken language of India.\" ) def type ( self ): print ( \"India is a developing country.\" ) class USA (): def capital ( self ): print ( \"Washington, D.C. is the capital of USA.\" ) def language ( self ): print ( \"English is the primary language of USA.\" ) def type ( self ): print ( \"USA is a developed country.\" ) obj_ind = India () obj_usa = USA () for country in ( obj_ind , obj_usa ): country . capital () country . language () country . type () # New Delhi is the capital of India. # Hindi is the most widely spoken language of India. # India is a developing country. # Washington, D.C. is the capital of USA. # English is the primary language of USA. # USA is a developed country. \u7ee7\u627f\u7684\u591a\u6001\u6027 \u00b6 \u5728 Python \u4e2d\uff0c\u591a\u6001\u5141\u8bb8\u6211\u4eec\u5728\u5b50\u7c7b\u4e2d\u5b9a\u4e49\u4e0e\u7236\u7c7b\u4e2d\u7684\u65b9\u6cd5\u540c\u540d\u7684\u65b9\u6cd5\u3002 \u5728\u7ee7\u627f\u4e2d\uff0c\u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u7684\u65b9\u6cd5\u3002 \u4f46\u662f\uff0c\u53ef\u4ee5\u4fee\u6539\u4ece\u7236\u7c7b\u7ee7\u627f\u7684\u5b50\u7c7b\u4e2d\u7684\u65b9\u6cd5\u3002 \u8fd9\u5728\u4ece\u7236\u7c7b\u7ee7\u627f\u7684\u65b9\u6cd5\u4e0d\u592a\u9002\u5408\u5b50\u7c7b\u7684\u60c5\u51b5\u4e0b\u7279\u522b\u6709\u7528\u3002 \u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u5728\u5b50\u7c7b\u4e2d\u91cd\u65b0\u5b9e\u73b0\u8be5\u65b9\u6cd5\u3002 \u8fd9\u79cd\u5728\u5b50\u7c7b\u4e2d\u91cd\u65b0\u5b9e\u73b0\u65b9\u6cd5\u7684\u8fc7\u7a0b\u79f0\u4e3a**\u65b9\u6cd5\u8986\u76d6\uff08Method Overriding\uff09**\u3002 class Bird : def intro ( self ): print ( \"There are many types of birds.\" ) def flight ( self ): print ( \"Most of the birds can fly but some cannot.\" ) class sparrow ( Bird ): def flight ( self ): print ( \"Sparrows can fly.\" ) class ostrich ( Bird ): def flight ( self ): print ( \"Ostriches cannot fly.\" ) obj_bird = Bird () obj_spr = sparrow () obj_ost = ostrich () obj_bird . intro () # There are many types of birds. obj_bird . flight () # Most of the birds can fly but some cannot. obj_spr . intro () # There are many types of birds. obj_spr . flight () # Sparrows can fly. obj_ost . intro () # There are many types of birds. obj_ost . flight () # Ostriches cannot fly. \u51fd\u6570\u548c\u5bf9\u8c61\u7684\u591a\u6001\u6027 \u00b6 \u6211\u4eec\u4e5f\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u53ef\u4ee5\u63a5\u53d7\u4efb\u4f55\u5bf9\u8c61\u7684\u51fd\u6570\uff0c\u5141\u8bb8\u591a\u6001\u6027\u3002 \u5728\u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a func() \u7684\u51fd\u6570\uff0c\u4f20\u5165\u53c2\u6570\u662f obj \u7684\u5bf9\u8c61\u3002 \u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u8c03\u7528\u4e09\u4e2a\u65b9\u6cd5\uff0c\u5373 capital() \u3001 language() \u548c type() \uff0c\u6bcf\u4e2a\u65b9\u6cd5\u90fd\u5b9a\u4e49\u5728 India \u548c USA \u4e24\u4e2a\u7c7b\u4e2d\u3002 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u76f8\u540c\u7684 func() \u51fd\u6570\u8c03\u7528\u5b83\u4eec\u7684\u52a8\u4f5c\uff1a class India (): def capital ( self ): print ( \"New Delhi is the capital of India.\" ) def language ( self ): print ( \"Hindi is the most widely spoken language of India.\" ) def type ( self ): print ( \"India is a developing country.\" ) class USA (): def capital ( self ): print ( \"Washington, D.C. is the capital of USA.\" ) def language ( self ): print ( \"English is the primary language of USA.\" ) def type ( self ): print ( \"USA is a developed country.\" ) def func ( obj ): obj . capital () obj . language () obj . type () obj_ind = India () obj_usa = USA () func ( obj_ind ) # New Delhi is the capital of India. # Hindi is the most widely spoken language of India. # India is a developing country. func ( obj_usa ) # Washington, D.C. is the capital of USA. # English is the primary language of USA. # USA is a developed country. \u9e2d\u5b50\u7c7b\u578b\uff08Ducking Typing\uff09\u548c\u767d\u9e45\u7c7b\u578b\uff08Goose Typing\uff09 \u00b6 \u5728Python\u4e2d\u5b9e\u73b0\u591a\u6001\u4e3b\u8981\u6709\u4e24\u79cd\u673a\u5236\uff1a\u767d\u9e45\u7c7b\u578b\u548c\u9e2d\u5b50\u7c7b\u578b\u3002\u767d\u9e45\u7c7b\u578b\u548c\u9e2d\u5b50\u7c7b\u578b\u4e0d\u4ec5\u662f\u4e24\u79cd\u673a\u5236\uff0c\u4e5f\u662f\u4e24\u79cd\u4e0d\u540c\u7684\u7f16\u7a0b\u98ce\u683c\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u6253\u5370\u5546\u54c1\u4ef7\u683c\u7684\u4f8b\u5b50\uff0c\u5206\u522b\u7528\u9e2d\u5b50\u7c7b\u578b\u548c\u767d\u9e45\u7c7b\u578b\u5b9e\u73b0\u3002 \u9e2d\u5b50\u7c7b\u578b\u3002 \u5728\u9e2d\u5b50\u7c7b\u578b\u7684\u5b9e\u73b0\u4e2d\uff0c\u6211\u4eec\u53ea\u9700\u8981\u4fdd\u8bc1\u8c03\u7528 price \u65b9\u6cd5\u7684\u6bcf\u4e2a\u5bf9\u8c61\u90fd\u6709 price \u65b9\u6cd5\u5373\u53ef\u3002 class Food : def price ( self ): print ( \" {} price:$4\" . format ( __class__ . __name__ )) class Clothes : def price ( self ): print ( \" {} price:$5\" . format ( __class__ . __name__ )) class Coffee : def price ( self ): print ( \" {} price:$6\" . format ( __class__ . __name__ )) if __name__ == '__main__' : goods = [ Food (), Clothes (), Coffee ()] for good in goods : good . price () # Food price:$4 # Clothes price:$5 # Coffee price:$6 \u767d\u9e45\u7c7b\u578b\u3002 \u5728\u767d\u9e45\u7c7b\u578b\u4e2d\uff0c\u76f4\u63a5\u8ba9\u6240\u6709\u5bf9\u8c61\u7684\u7c7b\u7ee7\u627f\u7236\u7c7b Good \u4e2d\u7684\u62bd\u8c61\u65b9\u6cd5 price \u3002Python\u4e2d\u7684\u767d\u9e45\u7c7b\u578b\u673a\u5236\u5c31\u662f\u5f3a\u7c7b\u578b\u8bed\u8a00\u4e2d\u5b9e\u73b0\u591a\u6001\u7684\u6807\u51c6\u6a21\u5f0f\uff0c\u5373\u901a\u8fc7\u8c03\u53d6\u7236\u7c7b\u7684\u865a\u51fd\u6570\u6216\u8005\u7ee7\u627f\u7684\u51fd\u6570\u6765\u5b8c\u6210\u4e0d\u540c\u7684\u884c\u4e3a\u3002 import abc class Good ( abc . ABC ): @abc . abstractmethod def price ( self ): pass class Food ( Good ): def price ( self ): print ( \" {} price:$4\" . format ( __class__ . __name__ )) class Clothes ( Good ): def price ( self ): print ( \" {} price:$5\" . format ( __class__ . __name__ )) if __name__ == '__main__' : goods = [ Food (), Clothes (), Coffee ()] for good in goods : good . price () # Food price:$4 # Clothes price:$5 # Coffee price:$6 \u7c7b\u65b9\u6cd5\uff08Class method\uff09\u548c\u9759\u6001\u65b9\u6cd5\uff08Static Method\uff09 \u00b6 \u7c7b\u65b9\u6cd5\uff08Class method\uff09\u4e5f\u53eb\u7ed1\u5b9a\u65b9\u6cd5\uff0c\u5fc5\u987b\u628a\u7c7b\u4f5c\u4e3a\u4f20\u5165\u53c2\u6570\uff0c\u4f7f\u7528 cls \u4f5c\u4e3a\u7b2c\u4e00\u4e2a\u4f20\u5165\u53c2\u6570\uff0c\u800c\u9759\u6001\u65b9\u6cd5\uff08Static Method\uff09\uff0c\u4e5f\u53eb\u975e\u7ed1\u5b9a\u65b9\u6cd5\uff0c\u4e0d\u9700\u8981\u7279\u5b9a\u7684\u53c2\u6570\u3002 \u7c7b\u65b9\u6cd5\u662f\u7ed1\u5b9a\u5230\u7c7b\u7684\uff0c\u4e0d\u662f\u7ed1\u5b9a\u5230\u7c7b\u5bf9\u8c61\uff0c\u6240\u4ee5\u7c7b\u65b9\u6cd5\u53ef\u4ee5\u8bbf\u95ee\u6216\u4fee\u6539\u7c7b\uff0c\u5e76\u5bf9\u6240\u6709\u7c7b\u5b9e\u4f8b\u751f\u6548\u3002 \u9759\u6001\u65b9\u6cd5\u65e0\u6cd5\u76f4\u63a5\u8bbf\u95ee\u6216\u4fee\u6539\u7c7b\uff0c\u56e0\u4e3a\u9759\u6001\u65b9\u6cd5\u662f\u4e0d\u77e5\u9053\u7c7b\u672c\u8eab\u7684\uff0c\u9759\u6001\u65b9\u6cd5\u662f\u5c5e\u4e8e\u5de5\u5177\u7c7b\u65b9\u6cd5\uff0c\u57fa\u4e8e\u4f20\u5165\u7684\u53c2\u6570\u5b8c\u6210\u7279\u5b9a\u7684\u529f\u80fd\uff0c\u5176\u5b9e\u5c31\u662f\u4e00\u4e2a\u666e\u901a\u51fd\u6570\u800c\u5df2\u3002 Python\u4e2d\u4f7f\u7528 @classmethod \u88c5\u9970\u5668\uff08decorator\uff09\u6765\u521b\u5efa\u4e00\u4e2a\u7c7b\u65b9\u6cd5\uff0c\u7528@staticmethod\u88c5\u9970\u5668\u6765\u521b\u5efa\u4e00\u4e2a\u9759\u6001\u65b9\u6cd5\u3002 \u8bed\u6cd5\u683c\u5f0f\uff1a @classmethod def fun ( cls , arg1 , arg2 , ... ): \u5176\u4e2d\uff1a fun : \u9700\u8981\u8f6c\u6362\u6210\u7c7b\u65b9\u6cd5\u7684\u51fd\u6570 returns : \u51fd\u6570\u7684\u7c7b\u65b9\u6cd5 classmethod() \u65b9\u6cd5\u7ed1\u5b9a\u5230\u7c7b\u800c\u4e0d\u662f\u5bf9\u8c61\u3002\u7c7b\u65b9\u6cd5\u53ef\u4ee5\u88ab\u7c7b\u548c\u5bf9\u8c61\u8c03\u7528\u3002\u8fd9\u4e9b\u65b9\u6cd5\u53ef\u4ee5\u901a\u8fc7\u7c7b\u6216\u5bf9\u8c61\u8fdb\u884c\u8c03\u7528\u3002 \u4f8b1\uff1a\u521b\u5efa\u4e00\u4e2a\u7b80\u5355\u7684 classmethod \u3002 \u521b\u5efa\u4e00\u4e2a\u7c7b Training \uff0c\u6709\u7c7b\u53d8\u91cf course \u548c\u65b9\u6cd5 purchase \u3002 \u6211\u4eec\u901a\u8fc7\u628a\u51fd\u6570 Training.purchase \u4f20\u7ed9 classmethod() \uff0c\u628a\u8be5\u65b9\u6cd5\u8f6c\u6210\u7c7b\u65b9\u6cd5\uff0c\u7136\u540e\u76f4\u63a5\u8c03\u7528\u5b83\uff0c\u800c\u65e0\u9700\u5148\u521b\u5efa\u5bf9\u8c61\u3002 \u53ef\u4ee5\u770b\u51fa\u8f6c\u6362\u524d\u540e Training.purchase \u7684\u7c7b\u578b\u53d8\u5316\u3002 class Training : course = 'Python for Data Analysis' def purchase ( obj ): print ( \"Puchase course : \" , obj . course ) type ( Training . purchase ) # Training . purchase = classmethod ( Training . purchase ) Training . purchase () # Puchase course : Python for Data Analysis type ( Training . purchase ) # \u4f8b2\uff1a\u4f7f\u7528\u88c5\u9970\u5668 @classmethod \u521b\u5efa\u5de5\u5382\u7c7b\u3002 class Training : def __init__ ( self , course ): self . course = course @classmethod def purchase ( cls , course ): return cls ( course ) def display ( self ): print ( 'Purchase course: ' , self . course ) training = Training ( \"Python for Data Analysis\" ) training . display () # Purchase course: Python for Data Analysis \u4f8b3\uff1a\u901a\u8fc7 staticmethod() \u548c classmethod() \u6765\u68c0\u67e5\u4e00\u4e2aperson\u662f\u5426\u662fadult\u3002 person1\u662f\u901a\u8fc7\u59d3\u540d\u548c\u5e74\u9f84\u521b\u5efa\u7684\u5b9e\u4f8b\u3002person2\u662f\u901a\u8fc7\u59d3\u540d\u548c\u5e74\u4efd\u521b\u5efa\u7684\u5b9e\u4f8b\u3002 from datetime import date class Person : def __init__ ( self , name , age ): self . name = name self . age = age @classmethod def fromBirthYear ( cls , name , year ): return cls ( name , date . today () . year - year ) @staticmethod def isAdult ( age ): return age > 18 person1 = Person ( 'mayank' , 21 ) person2 = Person . fromBirthYear ( 'mayank' , 1996 ) print ( person1 . age ) # 21 print ( person2 . age ) # 26 print ( Person . isAdult ( 22 )) # True \u5c0f\u7ed3\uff1a \u82e5\u7c7b\u4e2d\u9700\u8981\u4e00\u4e2a\u529f\u80fd\uff0c\u8be5\u529f\u80fd\u7684\u5b9e\u73b0\u4ee3\u7801\u4e2d\u9700\u8981\u5f15\u7528\u5bf9\u8c61\uff0c\u5219\u5c06\u5176\u5b9a\u4e49\u6210\u5bf9\u8c61\u65b9\u6cd5\uff1b\u9700\u8981\u5f15\u7528\u7c7b\uff0c\u5219\u5c06\u5176\u5b9a\u4e49\u6210\u7c7b\u65b9\u6cd5\uff1b\u65e0\u9700\u5f15\u7528\u7c7b\u6216\u5bf9\u8c61\uff0c\u5219\u5c06\u5176\u5b9a\u4e49\u6210\u9759\u6001\u65b9\u6cd5\u3002 \u7334\u5b50\u8865\u4e01\uff08monkey patch\uff09 \u00b6 \u7334\u5b50\u8865\u4e01\u662f\u52a8\u6001\u4e3a\u5df2\u7ecf\u521b\u5efa\u51fa\u7684\u5bf9\u8c61\u589e\u52a0\u65b0\u7684\u65b9\u6cd5\u548c\u5c5e\u6027\u6210\u5458\u7684\u4e00\u79cd\u673a\u5236\uff0c\u4e5f\u5c31\u662f\u52a8\u6001\u6253\u8865\u4e01\u3002 \u5b9e\u4f8b\u5316\u5bf9\u8c61\u7684\u7334\u5b50\u8865\u4e01\u3002 class Test : def __init__ ( self ): self . a = 1 def func1 ( self , x , y ): print ( x + y ) # \u6b63\u5e38\u5b9e\u4f8b\u5316 test = Test () test . func1 ( 1 , 1 ) # 2 # \u4fee\u6539\u5b9e\u4f8b test . func1 = lambda x , y : print ( x + 2 * y ) test . func1 ( 1 , 1 ) # 3 # \u901a\u8fc7\u4fee\u6539\u5b9e\u4f8b\uff0c\u8bbf\u95ee\u5185\u90e8\u6210\u5458\u53d8\u91cf\u3002 test . func1 = lambda x , y : print ( x + 2 * y + self . a ) test . func1 ( 1 , 1 ) # NameError: name 'self' is not defined test . func1 = lambda self , x , y : print ( x + 2 * y + self . a ) test . func1 ( test , 1 , 1 ) # 4 \u7c7b\u5bf9\u8c61\u7684\u7334\u5b50\u8865\u4e01\u3002 class Test : def __init__ ( self ): self . a = 1 def func1 ( self , x , y ): print ( x + y ) # \u4fee\u6539\u7c7b\u6210\u5458\uff0c\u5b9e\u4f8b\u5316\u540e\u7684\u7ed3\u679c\u5df2\u4fee\u6539\u3002 Test . func1 = lambda self , x , y : print ( x + 2 * y ) test = Test () test . func1 ( 1 , 1 ) # 3 # \u4fee\u6539\u7c7b\u6210\u5458\uff0c\u5e76\u8bbf\u95ee\u6210\u5458\u53d8\u91cf\uff0c\u5b9e\u4f8b\u5316\u540e\u7684\u7ed3\u679c\u5df2\u4fee\u6539\u3002 Test . func1 = lambda self , x , y : print ( x + 2 * y + self . a ) test = Test () test . func1 ( 1 , 1 ) # 4 # \u589e\u52a0\u7c7b\u6210\u5458\u3002 Test . func2 = lambda self , p , q : print ( p + 3 * q + self . a ) test = Test () test . func1 ( 1 , 1 ) # 4 test . func2 ( 1 , 3 ) # 11 \u79c1\u6709\u53d8\u91cf Private Variables \u00b6 \u90a3\u79cd\u4ec5\u9650\u4ece\u4e00\u4e2a\u5bf9\u8c61\u5185\u90e8\u8bbf\u95ee\u7684\u201c\u79c1\u6709\u201d\u5b9e\u4f8b\u53d8\u91cf\uff08\u201cPrivate\u201d instance variables\uff09\u5728 Python \u4e2d\u5e76\u4e0d\u5b58\u5728\u3002 \u4f46\u662f\uff0c\u5927\u591a\u6570 Python \u4ee3\u7801\u90fd\u9075\u5faa\u8fd9\u6837\u4e00\u4e2a\u7ea6\u5b9a\uff1a\u5e26\u6709*\u4e00\u4e2a\u524d\u7f00\u4e0b\u5212\u7ebf*\u7684\u540d\u79f0 (\u4f8b\u5982 _spam ) \u5e94\u8be5\u88ab\u5f53\u4f5c\u662f API \u7684\u975e\u516c\u6709\uff08non-public\uff09\u90e8\u5206 (\u65e0\u8bba\u5b83\u662f\u51fd\u6570\u3001\u65b9\u6cd5\u6216\u662f\u6570\u636e\u6210\u5458)\u3002 \u8fd9\u5e94\u5f53\u88ab\u89c6\u4e3a\u4e00\u4e2a\u5b9e\u73b0\u7ec6\u8282\uff0c\u53ef\u80fd\u4e0d\u7ecf\u901a\u77e5\u5373\u52a0\u4ee5\u6539\u53d8\u3002 \u7531\u4e8e\u5b58\u5728\u5bf9\u4e8e\u7c7b\u79c1\u6709\u6210\u5458\uff08class-private members\uff09\u7684\u6709\u6548\u4f7f\u7528\u573a\u666f\uff08\u4f8b\u5982\u907f\u514d\u540d\u79f0\u4e0e\u5b50\u7c7b\u6240\u5b9a\u4e49\u7684\u540d\u79f0\u76f8\u51b2\u7a81\uff09\uff0c\u56e0\u6b64\u5b58\u5728\u5bf9\u6b64\u79cd\u673a\u5236\u7684\u6709\u9650\u652f\u6301\uff0c\u79f0\u4e3a**\u540d\u79f0\u6539\u5199\uff08name mangling\uff09**\u3002 \u4efb\u4f55\u5f62\u5f0f\u4e3a __spam \u7684\u6807\u8bc6\u7b26\uff08\u81f3\u5c11\u5e26\u6709*\u4e24\u4e2a\u524d\u7f00\u4e0b\u5212\u7ebf*\uff0c\u81f3\u591a\u4e00\u4e2a\u540e\u7f00\u4e0b\u5212\u7ebf\uff09\u7684\u6587\u672c\u5c06\u88ab\u66ff\u6362\u4e3a _classname__spam \uff0c\u5176\u4e2d classname \u4e3a\u53bb\u9664\u4e86\u524d\u7f00\u4e0b\u5212\u7ebf\u7684\u5f53\u524d\u7c7b\u540d\u79f0\u3002 \u8fd9\u79cd\u6539\u5199\u4e0d\u8003\u8651\u6807\u8bc6\u7b26\u7684\u53e5\u6cd5\u4f4d\u7f6e\uff0c\u53ea\u8981\u5b83\u51fa\u73b0\u5728\u7c7b\u5b9a\u4e49\u5185\u90e8\u5c31\u4f1a\u8fdb\u884c\u3002 \u540d\u79f0\u6539\u5199\uff08Name mangling\uff09\u6709\u52a9\u4e8e\u8ba9\u5b50\u7c7b\u91cd\u8f7d\u65b9\u6cd5\uff08\uff09override methods\u800c\u4e0d\u7834\u574f\u7c7b\u5185\u65b9\u6cd5\uff08intraclass method\uff09\u8c03\u7528\u3002\u4f8b\u5982: class Mapping : def __init__ ( self , iterable ): self . items_list = [] self . __update ( iterable ) def update ( self , iterable ): for item in iterable : self . items_list . append ( item ) __update = update # private copy of original update() method class MappingSubclass ( Mapping ): def update ( self , keys , values ): # provides new signature for update() # but does not break __init__() for item in zip ( keys , values ): self . items_list . append ( item ) \u4e0a\u9762\u7684\u793a\u4f8b\u5373\u4f7f\u5728 MappingSubclass \u5f15\u5165\u4e86\u4e00\u4e2a __update \u6807\u8bc6\u7b26\u7684\u60c5\u51b5\u4e0b\u4e5f\u4e0d\u4f1a\u51fa\u9519\uff0c\u56e0\u4e3a\u5b83\u4f1a\u5728 Mapping \u7c7b\u4e2d\u88ab\u66ff\u6362\u4e3a _Mapping__update \u800c\u5728 MappingSubclass \u7c7b\u4e2d\u88ab\u66ff\u6362\u4e3a _MappingSubclass__update \u3002 \u8bf7\u6ce8\u610f\uff0c\u6539\u5199\u89c4\u5219\uff08mangling rules\uff09\u7684\u8bbe\u8ba1\u4e3b\u8981\u662f\u4e3a\u4e86\u907f\u514d\u610f\u5916\u51b2\u7a81\uff1b\u8bbf\u95ee\u6216\u4fee\u6539\u79c1\u6709\u53d8\u91cf\u4ecd\u7136\u662f\u53ef\u80fd\u7684\u3002\u8fd9\u5728\u7279\u6b8a\u60c5\u51b5\u4e0b\u751a\u81f3\u4f1a\u5f88\u6709\u7528\uff0c\u4f8b\u5982\u5728\u8c03\u8bd5\u5668\uff08debugger\uff09\u4e2d\u3002 \u8bf7\u6ce8\u610f\u4f20\u9012\u7ed9 exec() \u6216 eval() \u7684\u4ee3\u7801\u4e0d\u4f1a\u628a\u53d1\u8d77\u8c03\u7528\u7c7b\u7684\u7c7b\u540d\u89c6\u4f5c\u5f53\u524d\u7c7b\uff1b\u8fd9\u7c7b\u4f3c\u4e8e global \u8bed\u53e5\u7684\u6548\u679c\uff0c\u56e0\u6b64\u8fd9\u79cd\u6548\u679c\u4ec5\u9650\u4e8e\u540c\u65f6\u7ecf\u8fc7\u5b57\u8282\u7801\u7f16\u8bd1\u7684\u4ee3\u7801\u3002 \u540c\u6837\u7684\u9650\u5236\u4e5f\u9002\u7528\u4e8e getattr() , setattr() \u548c delattr() \uff0c\u4ee5\u53ca\u5bf9\u4e8e __dict__ \u7684\u76f4\u63a5\u5f15\u7528\u3002 \u53cd\u5c04(reflection) \u00b6 \u53cd\u5c04(reflection)\u662f\u52a8\u6001\u8bed\u8a00\u7684\u4e00\u4e2a\u7279\u6027\u3002**\u53cd\u5c04\u673a\u5236**\u6307\u7684\u662f\u5728\u7a0b\u5e8f\u7684\u8fd0\u884c\u72b6\u6001\u4e2d\uff0c\u5bf9\u4e8e\u4efb\u610f\u4e00\u4e2a\u7c7b\uff0c\u90fd\u53ef\u4ee5\u77e5\u9053\u8fd9\u4e2a\u7c7b\u7684\u6240\u6709\u5c5e\u6027\u548c\u65b9\u6cd5\uff1b\u5bf9\u4e8e\u4efb\u610f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u90fd\u80fd\u591f\u8c03\u7528\u4ed6\u7684\u4efb\u610f\u65b9\u6cd5\u548c\u5c5e\u6027\u3002\u8fd9\u79cd\u52a8\u6001\u83b7\u53d6\u7a0b\u5e8f\u4fe1\u606f\u4ee5\u53ca\u52a8\u6001\u8c03\u7528\u5bf9\u8c61\u7684\u529f\u80fd\u79f0\u4e3a\u53cd\u5c04\u673a\u5236\u3002 \u901a\u8fc7\u4e0b\u9762\u4f8b\u5b50\u53ef\u77e5\uff0c\u901a\u8fc7 dir(person) \u83b7\u53d6\u4efb\u610f\u4e00\u4e2a\u7c7b\u6216\u8005\u5bf9\u8c61\u7684\u5c5e\u6027\u5217\u8868\u3002\u901a\u8fc7\u5185\u7f6e\u51fd\u6570 hasattr \u3001 getattr \u3001 setattr \u3001 delattr \u64cd\u4f5c\u7c7b\u548c\u5bf9\u8c61\u3002 class Person : def __init__ ( self , name , age , gender ): self . name = name self . age = age self . gender = gender person = Person ( 'Tom' , 21 , 'Male' ) print ( dir ( person )) # ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'gender', 'name'] # hasattr(object,'name') # \u6309\u5b57\u7b26\u4e32'name'\u5224\u65ad\u6709\u65e0\u5c5e\u6027person.name hasattr ( person , 'name' ) # True # getattr(object, 'name', default=None) # \u7b49\u540c\u4e8eperson.name,\u4e0d\u5b58\u5728\u8be5\u5c5e\u6027\u5219\u8fd4\u56de\u9ed8\u8ba4\u503cNone getattr ( person , 'name' , None ) # 'Tom' # setattr(x, 'y', v) # \u7b49\u540c\u4e8eperson.age = 18 setattr ( person , 'age' , 18 ) print ( person . age ) # 18 # delattr(x, 'y') # \u7b49\u540c\u4e8edel person.age delattr ( person , 'age' ) print ( person . age ) # AttributeError: 'Person' object has no attribute 'age' \u4e0b\u9762\u662f\u4e00\u4e2a\u5b9e\u9645\u5e94\u7528\u7684\u4f8b\u5b50\u3002 class FtpServer (): def server_run ( self ): while True : inp = input ( 'Input your command >>:' ) . strip () cmd , file = inp . split () if hasattr ( self , cmd ): func = getattr ( self , cmd ) func ( file ) def get ( self , file ): print ( f 'Downloading { file } ...' ) def put ( self , file ): print ( f 'Uploading { file } ...' ) ftp_server = FtpServer () ftp_server . server_run () # Input your command >>:get a.ext # Downloading a.ext... # Input your command >>:put a.txt # Uploading a.txt... \u8fed\u4ee3\u5668 Iterators \u00b6 \u5728Python\u4e2d\uff0c\u5927\u591a\u6570\u5bb9\u5668\u5bf9\u8c61\uff08container object\uff09\u90fd\u53ef\u4ee5\u4f7f\u7528 for \u8bed\u53e5: for element in [ 1 , 2 , 3 ]: print ( element ) for element in ( 1 , 2 , 3 ): print ( element ) for key in { 'one' : 1 , 'two' : 2 }: print ( key ) for char in \"123\" : print ( char ) for line in open ( \"myfile.txt\" ): print ( line , end = '' ) for \u8bed\u53e5\u4f1a\u5728\u5bb9\u5668\u5bf9\u8c61\u4e0a\u8c03\u7528 iter()\u3002 \u8be5\u51fd\u6570\u8fd4\u56de\u4e00\u4e2a\u5b9a\u4e49\u4e86 __next__() \u65b9\u6cd5\u7684\u8fed\u4ee3\u5668\u5bf9\u8c61\uff0c\u6b64\u65b9\u6cd5\u5c06\u9010\u4e00\u8bbf\u95ee\u5bb9\u5668\u4e2d\u7684\u5143\u7d20\u3002 \u5f53\u5143\u7d20\u7528\u5c3d\u65f6\uff0c __next__() \u5c06\u5f15\u53d1 StopIteration \u5f02\u5e38\u6765\u901a\u77e5\u7ec8\u6b62 for \u5faa\u73af\u3002 \u53ef\u4ee5\u4f7f\u7528 next() \u5185\u7f6e\u51fd\u6570\u6765\u8c03\u7528 __next__() \u65b9\u6cd5\uff1b\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u5c55\u793a\u4e86\u521a\u521a\u63cf\u8ff0\u7684\u5177\u4f53\u8fd0\u884c\u65b9\u5f0f: >>> s = 'abc' >>> it = iter ( s ) >>> it < str_iterator object at 0x10c90e650 > >>> next ( it ) 'a' >>> next ( it ) 'b' >>> next ( it ) 'c' >>> next ( it ) Traceback ( most recent call last ): File \"\" , line 1 , in < module > next ( it ) StopIteration \u5728\u4e86\u89e3\u4e86\u8fed\u4ee3\u5668\u534f\u8bae\uff08iterator protocol\uff09\u7684\u673a\u5236\u540e\uff0c\u7ed9\u7c7b\u6dfb\u52a0\u8fed\u4ee3\u5668\u5c31\u5f88\u5bb9\u6613\u4e86\u3002 \u5b9a\u4e49\u4e00\u4e2a __iter__() \u65b9\u6cd5\u6765\u8fd4\u56de\u4e00\u4e2a\u5e26\u6709 __next__() \u65b9\u6cd5\u7684\u5bf9\u8c61\u3002 \u5982\u679c\u7c7b\u5df2\u5b9a\u4e49\u4e86 __next__() \uff0c\u5219 __iter__() \u53ef\u4ee5\u7b80\u5355\u5730\u8fd4\u56de self : class Reverse : \"\"\"Iterator for looping over a sequence backwards.\"\"\" def __init__ ( self , data ): self . data = data self . index = len ( data ) def __iter__ ( self ): return self def __next__ ( self ): if self . index == 0 : raise StopIteration self . index = self . index - 1 return self . data [ self . index ] rev = Reverse ( 'spam' ) print ( iter ( rev )) for char in rev : print ( char ) # m # a # p # s \u751f\u6210\u5668 Generators \u00b6 **\u751f\u6210\u5668\uff08Generators\uff09**\u662f\u4e00\u4e2a\u7528\u4e8e\u521b\u5efa\u8fed\u4ee3\u5668\u7684\u7b80\u5355\u800c\u5f3a\u5927\u7684\u5de5\u5177\u3002 \u5b83\u4eec\u7684\u5199\u6cd5\u7c7b\u4f3c\u4e8e\u6807\u51c6\u7684\u51fd\u6570\uff0c\u4f46\u5f53\u5b83\u4eec\u8981\u8fd4\u56de\u6570\u636e\u65f6\u4f1a\u4f7f\u7528 yield \u8bed\u53e5\u3002 \u6bcf\u6b21\u5728\u751f\u6210\u5668\u4e0a\u8c03\u7528 next() \u65f6\uff0c\u5b83\u4f1a\u4ece\u4e0a\u6b21\u79bb\u5f00\u7684\u4f4d\u7f6e\u6062\u590d\u6267\u884c\uff08\u5b83\u4f1a\u8bb0\u4f4f\u4e0a\u6b21\u6267\u884c\u8bed\u53e5\u65f6\u7684\u6240\u6709\u6570\u636e\u503c\uff09\u3002 \u4e00\u4e2a\u521b\u5efa\u751f\u6210\u5668\u7684\u793a\u4f8b\u5982\u4e0b\uff08\u6539\u5199\u4e0a\u9762\u8fed\u4ee3\u5668\u4e2d\u6240\u4e3e\u7684\u4f8b\u5b50\uff09: def reverse ( data ): for index in range ( len ( data ) - 1 , - 1 , - 1 ): yield data [ index ] for char in reverse ( 'golf' ): print ( char ) # f # l # o # g \u53ef\u4ee5\u7528\u751f\u6210\u5668\u6765\u5b8c\u6210\u7684\u64cd\u4f5c\u540c\u6837\u53ef\u4ee5\u7528\u524d\u9762\u6240\u63cf\u8ff0\u7684\u57fa\u4e8e\u7c7b\u7684\u8fed\u4ee3\u5668\u6765\u5b8c\u6210\u3002\u4f46\u751f\u6210\u5668\u7684\u5199\u6cd5\u66f4\u4e3a\u7d27\u51d1\uff0c\u56e0\u4e3a\u5b83\u4f1a\u81ea\u52a8\u521b\u5efa __iter__() \u548c __next__() \u65b9\u6cd5\u3002 \u53e6\u4e00\u4e2a\u5173\u952e\u7279\u6027\u5728\u4e8e\u5c40\u90e8\u53d8\u91cf\u548c\u6267\u884c\u72b6\u6001\u4f1a\u5728\u6bcf\u6b21\u8c03\u7528\u4e4b\u95f4\u81ea\u52a8\u4fdd\u5b58\u3002 \u8fd9\u4f7f\u5f97\u8be5\u51fd\u6570\u76f8\u6bd4\u4f7f\u7528 self.index \u548c self.data \u8fd9\u79cd\u5b9e\u4f8b\u53d8\u91cf\u7684\u65b9\u5f0f\u66f4\u6613\u7f16\u5199\u4e14\u66f4\u4e3a\u6e05\u6670\u3002 \u9664\u4e86\u4f1a\u81ea\u52a8\u521b\u5efa\u65b9\u6cd5\u548c\u4fdd\u5b58\u7a0b\u5e8f\u72b6\u6001\uff0c\u5f53\u751f\u6210\u5668\u7ec8\u7ed3\u65f6\uff0c\u5b83\u4eec\u8fd8\u4f1a\u81ea\u52a8\u5f15\u53d1 StopIteration \u3002 \u751f\u6210\u5668\u8868\u8fbe\u5f0f Generator Expressions \u00b6 \u67d0\u4e9b\u7b80\u5355\u7684\u751f\u6210\u5668\u53ef\u4ee5\u5199\u6210\u7b80\u6d01\u7684\u8868\u8fbe\u5f0f\u4ee3\u7801\uff0c\u6240\u7528\u8bed\u6cd5\u7c7b\u4f3c\u5217\u8868\u63a8\u5bfc\u5f0f\uff0c\u4f46\u5916\u5c42\u4e3a\u5706\u62ec\u53f7\u800c\u975e\u65b9\u62ec\u53f7\u3002 \u8fd9\u79cd\u8868\u8fbe\u5f0f\u88ab\u8bbe\u8ba1\u7528\u4e8e\u751f\u6210\u5668\u5c06\u7acb\u5373\u88ab\u5916\u5c42\u51fd\u6570\u6240\u4f7f\u7528\u7684\u60c5\u51b5\u3002 \u751f\u6210\u5668\u8868\u8fbe\u5f0f\u76f8\u6bd4\u5b8c\u6574\u7684\u751f\u6210\u5668\u66f4\u7d27\u51d1\u4f46\u8f83\u4e0d\u7075\u6d3b\uff0c\u76f8\u6bd4\u7b49\u6548\u7684\u5217\u8868\u63a8\u5bfc\u5f0f\u5219\u66f4\u4e3a\u8282\u7701\u5185\u5b58\u3002 \u793a\u4f8b: >>> sum ( i * i for i in range ( 10 )) # sum of squares 285 >>> xvec = [ 10 , 20 , 30 ] >>> yvec = [ 7 , 5 , 3 ] >>> sum ( x * y for x , y in zip ( xvec , yvec )) # dot product 260 >>> unique_words = set ( word for line in page for word in line . split ()) >>> valedictorian = max (( student . gpa , student . name ) for student in graduates ) >>> data = 'golf' >>> list ( data [ i ] for i in range ( len ( data ) - 1 , - 1 , - 1 )) [ 'f' , 'l' , 'o' , 'g' ] \u5143\u7c7b\uff08metaclass\uff09 \u00b6 \u6240\u6709\u7684\u5bf9\u8c61\u90fd\u662f\u5b9e\u4f8b\u5316\u6216\u8005\u8bf4\u8c03\u7528\u7c7b\u800c\u5f97\u5230\u7684\uff08\u8c03\u7528\u7c7b\u7684\u8fc7\u7a0b\u79f0\u4e3a\u7c7b\u7684\u5b9e\u4f8b\u5316\u3002 class StandfordProfessor ( object ): university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) \u4e0a\u4f8b\u4e2d\uff0c\u5bf9\u8c61 professor \u662f\u8c03\u7528\u7c7b StandfordProfessor \u5f97\u5230\u7684\u3002\u7c7b StandfordProfessor \u672c\u8d28\u4e5f\u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c \u4e0b\u9762\u53ef\u4ee5\u9a8c\u8bc1\uff0c StandfordProfessor \u662f\u8c03\u7528\u4e86\u5185\u7f6e\u7684\u7c7b type \u5f97\u5230\u7684\u3002\u8fd9\u4e2a type \u79f0\u4e3a\u5143\u7c7b\u3002 print ( type ( StandfordProfessor )) # \u5982\u679c\u4e00\u4e2a\u7c7b\u6ca1\u6709\u58f0\u660e\u81ea\u5df1\u7684\u5143\u7c7b\uff0c\u9ed8\u8ba4\u5b83\u7684\u5143\u7c7b\u5c31\u662f type \uff0c\u9664\u4e86\u4f7f\u7528\u5185\u7f6e\u5143\u7c7b type \uff0c\u6211\u4eec\u4e5f\u53ef\u4ee5\u901a\u8fc7\u7ee7\u627f type \u6765\u81ea\u5b9a\u4e49\u5143\u7c7b\uff0c\u7136\u540e\u4f7f\u7528 metaclass \u5173\u952e\u5b57\u53c2\u6570\u4e3a\u4e00\u4e2a\u7c7b\u7684\u6307\u5b9a\u5143\u7c7b\u3002 \u53ea\u6709\u7ee7\u627f\u4e86type\u7c7b\u624d\u80fd\u79f0\u4e4b\u4e3a\u4e00\u4e2a\u5143\u7c7b\uff0c\u5426\u5219\u5c31\u662f\u4e00\u4e2a\u666e\u901a\u7684\u81ea\u5b9a\u4e49\u7c7b\u3002 class Mymeta ( type ): pass class StandfordProfessor ( object , metaclass = Mymeta ): university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) \u4e0b\u9762\u8fdb\u884c\u81ea\u5b9a\u4e49\u5143\u7c7b\uff0c\u63a7\u5236\u7c7b StandfordProfessor \u7684\u8c03\u7528\u3002 \u8981\u60f3\u8ba9 professor \u8fd9\u4e2a\u5bf9\u8c61\u53d8\u6210\u4e00\u4e2a\u53ef\u8c03\u7528\u7684\u5bf9\u8c61\uff0c\u9700\u8981\u5728\u8be5\u5bf9\u8c61\u7684\u7c7b\u4e2d\u5b9a\u4e49\u4e00\u4e2a\u65b9\u6cd5 __call__ \uff0c\u8be5\u65b9\u6cd5\u4f1a\u5728\u8c03\u7528\u5bf9\u8c61\u65f6\u81ea\u52a8\u89e6\u53d1\u3002\u8c03\u7528 professor \u7684\u8fd4\u56de\u503c\u5c31\u662f __call__ \u65b9\u6cd5\u7684\u8fd4\u56de\u503c\u3002 class Mymeta ( type ): def __call__ ( self , * args , ** kwargs ): print ( self ) # \u7c7b\u540d print ( args ) # \u8f93\u5165\u53c2\u6570 print ( kwargs ) # \u8f93\u5165\u53c2\u6570 return 10086 class StandfordProfessor ( object , metaclass = Mymeta ): university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) # # ('Tom', 'Male') # {} \u7c7b\u7684\u4ea7\u751f\u8fc7\u7a0b\u5176\u5b9e\u5c31\u662f\u5143\u7c7b\u7684\u8c03\u7528\u8fc7\u7a0b,\u5373 StandfordProfessor = Mymeta('StandfordProfessor', (object), {...}) \uff0c\u8c03\u7528 Mymeta \u4f1a\u5148\u4ea7\u751f\u4e00\u4e2a\u7a7a\u5bf9\u8c61 StandfordProfessor \uff0c\u7136\u540e\u8fde\u540c\u8c03\u7528 Mymeta \u62ec\u53f7\u5185\u7684\u53c2\u6570\u4e00\u540c\u4f20\u7ed9 Mymeta \u4e0b\u7684 __init__ \u65b9\u6cd5\uff0c\u5b8c\u6210\u521d\u59cb\u5316\u3002\u6211\u4eec\u53ef\u4ee5\u57fa\u4e8e\u4e0a\u4f8b\u505a\u5982\u4e0b\u6539\u5199\u3002 class Mymeta ( type ): def __init__ ( self , class_name , class_bases , class_dic ): super ( Mymeta , self ) . __init__ ( class_name , class_bases , class_dic ) if class_name . islower (): raise TypeError ( f 'Please follow Camel-Case to change class name { class_name } ' ) if '__doc__' not in class_dic or len ( class_dic [ '__doc__' ] . strip ( ' \\n ' )) == 0 : raise TypeError ( 'Please add documentation in class {class_name} , which is mandatory.' ) class StandfordProfessor ( object , metaclass = Mymeta ): \"\"\" Documentation of class StanfordTeacher \"\"\" university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) professor . display () # Professor Tom says welcome to Standford! print ( professor . __dict__ ) # {'name': 'Tom', 'gender': 'Male'} StandfordProfessor . mro () # [, ]","title":"Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027"},{"location":"python/Foundation/ch05/#python","text":"Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027\uff1a \u5c01\u88c5 \u7ee7\u627f \u591a\u6001","title":"Python\u9762\u5411\u5bf9\u8c61\u4e09\u5927\u7279\u6027"},{"location":"python/Foundation/ch05/#encapsulation","text":"\u5c01\u88c5\u662f\u4f7f\u7528\u7279\u6b8a\u7684\u8bed\u6cd5\uff0c\u5bf9\u6210\u5458\u5c5e\u6027\u548c\u6210\u5458\u65b9\u6cd5\u8fdb\u884c\u5305\u88c5\uff0c\u9650\u5236\u4e00\u4e9b\u8bbf\u95ee\u548c\u64cd\u4f5c\uff0c\u8fbe\u5230\u4fdd\u62a4\u548c\u9690\u85cf\u7684\u76ee\u7684\u3002 \u5c01\u88c5\u673a\u5236\u4fdd\u8bc1\u4e86\u7c7b\u5185\u90e8\u6570\u636e\u7ed3\u6784\u7684\u5b8c\u6574\u6027\uff0c\u56e0\u4e3a\u4f7f\u7528\u7c7b\u7684\u7528\u6237\u65e0\u6cd5\u76f4\u63a5\u770b\u5230\u7c7b\u4e2d\u7684\u6570\u636e\u7ed3\u6784\uff0c\u53ea\u80fd\u4f7f\u7528\u7c7b\u5141\u8bb8\u516c\u5f00\u7684\u6570\u636e\uff0c\u5f88\u597d\u5730\u907f\u514d\u4e86\u5916\u90e8\u5bf9\u5185\u90e8\u6570\u636e\u7684\u5f71\u54cd\uff0c\u63d0\u9ad8\u4e86\u7a0b\u5e8f\u7684\u53ef\u7ef4\u62a4\u6027\u3002 \u5bf9\u4e00\u4e2a\u7c7b\u5b9e\u73b0\u826f\u597d\u7684\u5c01\u88c5\uff0c\u7528\u6237\u53ea\u80fd\u501f\u52a9\u66b4\u9732\u51fa\u6765\u7684\u7c7b\u65b9\u6cd5\u6765\u8bbf\u95ee\u6570\u636e\uff0c\u53ef\u4ee5\u5728\u8fd9\u4e9b\u66b4\u9732\u7684\u65b9\u6cd5\u4e2d\u52a0\u5165\u9002\u5f53\u7684\u63a7\u5236\u903b\u8f91\uff0c\u5373\u53ef\u63a7\u5236\u7528\u6237\u5bf9\u7c7b\u4e2d\u5c5e\u6027\u6216\u65b9\u6cd5\u7684\u64cd\u4f5c\u3002 \u5bf9\u7c7b\u8fdb\u884c\u826f\u597d\u7684\u5c01\u88c5\uff0c\u4e3b\u8981\u662f\u5185\u90e8\u4f7f\u7528\u5c01\u88c5\u7684\u6210\u5458\uff0c\u4e5f\u63d0\u9ad8\u4e86\u4ee3\u7801\u7684\u590d\u7528\u6027\u3002 \u7c7b\u6210\u5458\u5c01\u88c5\u7684\u7ea7\u522b\uff1a \u516c\u6709\u7684\uff08public\uff09 \u4fdd\u62a4\u7684\uff08protected\uff09\uff0c\u5728Python\u4e2d\u5e76\u6ca1\u6709\u5b9e\u73b0protected\u5c01\u88c5\uff0c\u5c5e\u4e8e\u5f00\u53d1\u8005\u7684\u7ea6\u5b9a\u4fd7\u6210\u3002 \u79c1\u6709\u7684\uff08private\uff09\uff0c\u5728Python\u4e2dprivate\u5c01\u88c5\u662f\u901a\u8fc7\u6539\u540d\u7b56\u7565\u6765\u5b9e\u73b0\u7684\uff0c\u5e76\u4e0d\u662f\u771f\u6b63\u7684\u79c1\u6709\u5316\u3002 \u8bbf\u95ee\u9650\u5236 \u5171\u6709\u7684public \u53d7\u4fdd\u62a4\u7684protected \u79c1\u6709\u7684private \u5728\u7c7b\u7684\u5185\u90e8 OK OK OK \u5728\u7c7b\u7684\u5916\u90e8 OK No (Python\u4e2d\u53ef\u4ee5) No \u770b\u4e0b\u9762\u7684\u4f8b\u5b50\u3002(\u53c2\u8003 \u79c1\u6709\u53d8\u91cfPrivate Variables ) name \u662f\u5171\u6709\u5c5e\u6027\uff0c\u53ef\u4ee5\u5728\u5916\u90e8\u8c03\u7528tom.name\u3002 _age \u662f\u53d7\u4fdd\u62a4\u7684\u5c5e\u6027\uff0c\u7406\u8bba\u4e0a\u5728\u5916\u90e8\u662f\u4e0d\u53ef\u8c03\u7528\u7684\uff0c\u4f46\u5728Python\u4e2d\u662f\u53ef\u4ee5\u8c03\u7528\u7684 tom._age \u3002 __phone \u662f\u79c1\u6709\u5c5e\u6027\uff0c\u5728\u5916\u90e8\u662f\u4e0d\u53ef\u8c03\u7528\u7684\uff0c tom.__get_phone() \u62a5\u9519\u201c\u5c5e\u6027\u4e0d\u5b58\u5728\u201d\u3002 \u5bf9\u5e94\u65b9\u6cd5\u4e5f\u662f\u7c7b\u4f3c\u3002 \u5728\u7c7b\u7684\u5185\u90e8\u5bf9\u53d7\u4fdd\u62a4\u5bf9\u8c61\u548c\u79c1\u6709\u5bf9\u8c61\u6ca1\u6709\u8bbf\u95ee\u9650\u5236\u3002 _get_age \u53ef\u4ee5\u8c03\u7528\u79c1\u6709\u5c5e\u6027 __phone \u3002 class Person (): name = 'name' # public _age = 0 # protected __phone = 'phone' # private def __init__ ( self , n , a , p ): self . name = n self . _age = a self . __phone = p def get_name ( self ): print ( f 'My name is { self . name } ' ) def _get_age ( self ): print ( f 'My age is { self . _age } ' ) print ( f 'My age is { self . __phone } ' ) def __get_phone ( self ): print ( f 'My phone is { self . __phone } ' ) tom = Person ( 'Tom' , 18 , 12345678 ) tom . name # 'Tom' tom . _age # 18 tom . __phone # AttributeError: 'Person' object has no attribute '__phone' tom . get_name () # My name is Tom tom . _get_age () # My age is 18 # My age is 12345678 tom . __get_phone () # AttributeError: 'Person' object has no attribute '__get_phone'","title":"\u5c01\u88c5 Encapsulation"},{"location":"python/Foundation/ch05/#inheritance","text":"\u5728\u4e0d\u6307\u5b9a\u7ee7\u627f\u7684\u7236\u7c7b\u65f6\uff0c\u6240\u6709\u7c7b\u90fd\u7ee7\u627fobject\u7c7b\uff08\u7cfb\u7edf\u63d0\u4f9b\uff09\u3002 \u88ab\u5176\u5b83\u7c7b\u7ee7\u627f\u7684\u7c7b\uff0c\u79f0\u4e3a\u7236\u7c7b\uff0c\u6216\u8005\u57fa\u7c7b\uff0c\u6216\u8005\u8d85\u7c7b\u3002 \u7ee7\u627f\u5176\u5b83\u7c7b\u7684\u7c7b\uff0c\u79f0\u4e3a\u5b50\u7c7b\uff0c\u6216\u8005\u6d3e\u751f\u7c7b\uff08derived class\uff09\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u5c31\u62e5\u6709\u4e86\u7236\u7c7b\u4e2d\u7684\u6240\u6709\u6210\u5458\uff08\u9664\u4e86\u79c1\u6709\u6210\u5458\uff09\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u5e76\u4e0d\u4f1a\u628a\u7236\u7c7b\u7684\u6210\u5458\u590d\u5236\u7ed9\u5b50\u7c7b\uff0c\u800c\u662f\u5f15\u7528\u3002 \u5b50\u7c7b\u53ef\u4ee5\u76f4\u63a5\u8c03\u7528\u7236\u7c7b\u7684\u65b9\u6cd5 super().BaseClassName \u3002\u5982\u679c\u7236\u7c7b\u65b9\u6cd5\u6709\u53c2\u6570\u8981\u6c42\uff0c\u5b50\u7c7b\u8c03\u7528\u65f6\u4e5f\u6709\u53c2\u6570\u8981\u6c42\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u53ef\u4ee5\u91cd\u65b0\u5b9a\u4e49\u7236\u7c7b\u4e2d\u7684\u65b9\u6cd5\uff0c\u79f0\u4e3a**\u91cd\u5199\uff08Override\uff09**\u3002 \u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u540e\uff0c\u5b9a\u4e49\u7236\u7c7b\u4e2d\u6ca1\u6709\u7684\u65b9\u6cd5\uff0c\u88ab\u79f0\u4e3a\u5bf9\u7236\u7c7b\u7684\u6269\u5c55\u3002 \u4e00\u4e2a\u7236\u7c7b\u53ef\u4ee5\u88ab\u591a\u4e2a\u5b50\u7c7b\u7ee7\u627f\u3002 **\u6d3e\u751f\u7c7b\uff08derived class\uff09**\u5b9a\u4e49\u7684\u8bed\u6cd5\u5982\u4e0b\u6240\u793a: class BaseClassName (): < statement - 1 > . . . < statement - N > class DerivedClassName ( BaseClassName ): < statement - 1 > . . . < statement - N > \u540d\u79f0 BaseClassName \u5fc5\u987b\u5b9a\u4e49\u4e8e\u5305\u542b\u6d3e\u751f\u7c7b\u5b9a\u4e49\u7684\u4f5c\u7528\u57df\u4e2d\u3002 \u4e5f\u5141\u8bb8\u7528\u5176\u4ed6\u4efb\u610f\u8868\u8fbe\u5f0f\u4ee3\u66ff\u57fa\u7c7b\u540d\u79f0\u6240\u5728\u7684\u4f4d\u7f6e\uff0c\u4f8b\u5982\uff0c\u5f53\u57fa\u7c7b\u5b9a\u4e49\u5728\u53e6\u4e00\u4e2a\u6a21\u5757\u4e2d\u7684\u65f6\u5019: class DerivedClassName ( modname . BaseClassName ): \u6d3e\u751f\u7c7b\u5b9a\u4e49\u7684\u6267\u884c\u8fc7\u7a0b\u4e0e\u57fa\u7c7b\u76f8\u540c\u3002 \u5f53\u6784\u9020\u7c7b\u5bf9\u8c61\u65f6\uff0c\u57fa\u7c7b\u4f1a\u88ab\u8bb0\u4f4f\u3002 \u6b64\u4fe1\u606f\u5c06\u88ab\u7528\u6765\u89e3\u6790\u5c5e\u6027\u5f15\u7528\uff1a\u5982\u679c\u8bf7\u6c42\u7684\u5c5e\u6027\u5728\u7c7b\u4e2d\u627e\u4e0d\u5230\uff0c\u641c\u7d22\u5c06\u8f6c\u5f80\u57fa\u7c7b\u4e2d\u8fdb\u884c\u67e5\u627e\u3002 \u5982\u679c\u57fa\u7c7b\u672c\u8eab\u4e5f\u6d3e\u751f\u81ea\u5176\u4ed6\u67d0\u4e2a\u7c7b\uff0c\u5219\u6b64\u89c4\u5219\u5c06\u88ab\u9012\u5f52\u5730\uff08recursively\uff09\u5e94\u7528\u3002 \u6d3e\u751f\u7c7b\u7684\u5b9e\u4f8b\u5316\u6ca1\u6709\u4efb\u4f55\u7279\u6b8a\u4e4b\u5904: DerivedClassName() \u4f1a\u521b\u5efa\u8be5\u7c7b\u7684\u4e00\u4e2a*\u65b0\u5b9e\u4f8b*\u3002 \u65b9\u6cd5\u5f15\u7528\u5c06\u6309\u4ee5\u4e0b\u65b9\u5f0f\u89e3\u6790\uff1a\u641c\u7d22\u76f8\u5e94\u7684\u7c7b\u5c5e\u6027\uff0c\u5982\u6709\u5fc5\u8981\u5c06\u6309\u57fa\u7c7b\u7ee7\u627f\u94fe\u9010\u6b65\u5411\u4e0b\u67e5\u627e\uff0c\u5982\u679c\u4ea7\u751f\u4e86\u4e00\u4e2a\u51fd\u6570\u5bf9\u8c61\u5219\u65b9\u6cd5\u5f15\u7528\u5c31\u751f\u6548\u3002 \u6d3e\u751f\u7c7b\u53ef\u80fd\u4f1a\u91cd\u5199\uff08override\uff09\u5176\u57fa\u7c7b\u7684\u65b9\u6cd5\u3002 \u56e0\u4e3a\u65b9\u6cd5\u5728\u8c03\u7528\u540c\u4e00\u5bf9\u8c61\u7684\u5176\u4ed6\u65b9\u6cd5\u65f6\u6ca1\u6709\u7279\u6b8a\u6743\u9650\uff0c\u6240\u4ee5\u8c03\u7528\u540c\u4e00\u57fa\u7c7b\u4e2d\u5b9a\u4e49\u7684\u53e6\u4e00\u65b9\u6cd5\u7684\u57fa\u7c7b\u65b9\u6cd5\u6700\u7ec8\u53ef\u80fd\u4f1a\u8c03\u7528\u8986\u76d6\u5b83\u7684\u6d3e\u751f\u7c7b\u7684\u65b9\u6cd5\u3002 \u5728\u6d3e\u751f\u7c7b\u4e2d\u7684\u91cd\u8f7d\u65b9\u6cd5\uff08overriding method\uff09\u5b9e\u9645\u4e0a\u53ef\u80fd\u60f3\u8981\u6269\u5c55\u800c\u975e\u7b80\u5355\u5730\u66ff\u6362\u540c\u540d\u7684\u57fa\u7c7b\u65b9\u6cd5\u3002 \u6709\u4e00\u79cd\u65b9\u5f0f\u53ef\u4ee5\u7b80\u5355\u5730\u76f4\u63a5\u8c03\u7528\u57fa\u7c7b\u65b9\u6cd5\uff1a\u5373\u8c03\u7528 BaseClassName.methodname(self, arguments) \u3002 \u8bf7\u6ce8\u610f\uff0c\u4ec5\u5f53\u6b64\u57fa\u7c7b\u53ef\u5728\u5168\u5c40\u4f5c\u7528\u57df\u4e2d\u4ee5 BaseClassName \u7684\u540d\u79f0\u88ab\u8bbf\u95ee\u65f6\u65b9\u53ef\u4f7f\u7528\u6b64\u65b9\u5f0f\u3002 Python\u6709\u4e24\u4e2a\u5185\u7f6e\u51fd\u6570\u53ef\u88ab\u7528\u4e8e\u7ee7\u627f\u673a\u5236\uff1a \u4f7f\u7528 isinstance() \u6765\u68c0\u67e5\u4e00\u4e2a\u5b9e\u4f8b\u7684\u7c7b\u578b: isinstance(obj, int) \u4ec5\u4f1a\u5728 obj.__class__ \u4e3a int \u6216\u67d0\u4e2a\u6d3e\u751f\u81ea int \u7684\u7c7b\u65f6\u4e3a True \u3002 \u4f7f\u7528 issubclass() \u6765\u68c0\u67e5\u7c7b\u7684\u7ee7\u627f\u5173\u7cfb: issubclass(bool, int) \u4e3a True \uff0c\u56e0\u4e3a bool \u662f int \u7684\u5b50\u7c7b\u3002 \u4f46\u662f\uff0c issubclass(float, int) \u4e3a False \uff0c\u56e0\u4e3a float \u4e0d\u662f int \u7684\u5b50\u7c7b\u3002","title":"\u7ee7\u627f Inheritance"},{"location":"python/Foundation/ch05/#multiple-inheritance","text":"\u5355\u7ee7\u627f\uff08single-inheritance\uff09\uff1a\u4e00\u4e2a\u7c7b\u53ea\u80fd\u7ee7\u627f\u4e00\u4e2a\u7236\u7c7b\u65b9\u5f0f\u3002 class DerivedClassName ( BaseClassName ): < statement - 1 > . . . < statement - N > \u591a\u7ee7\u627f\uff08Multiple Inheritance\uff09\uff1a\u4e00\u4e2a\u7c7b\u53bb\u7ee7\u627f\u591a\u4e2a\u7c7b\u7684\u65b9\u5f0f\u3002\u5b9a\u4e49\u8bed\u53e5\u5982\u4e0b\u6240\u793a class DerivedClassName ( Base1 , Base2 , Base3 ): < statement - 1 > . . . < statement - N > \u5728\u6700\u7b80\u5355\u7684\u60c5\u51b5\u4e0b\uff0c\u641c\u7d22\u4ece\u7236\u7c7b\u6240\u7ee7\u627f\u5c5e\u6027\u7684\u64cd\u4f5c\u662f\u6df1\u5ea6\u4f18\u5148\uff08depth-first\uff09\u3001\u4ece\u5de6\u81f3\u53f3\uff08left-to-right\uff09\u7684\uff0c\u5f53\u5c42\u6b21\u7ed3\u6784\u4e2d\u5b58\u5728\u91cd\u53e0\u65f6\u4e0d\u4f1a\u5728\u540c\u4e00\u4e2a\u7c7b\u4e2d\u641c\u7d22\u4e24\u6b21\u3002 \u56e0\u6b64\uff0c\u5982\u679c\u67d0\u4e00\u5c5e\u6027\u5728 DerivedClassName \u4e2d\u672a\u627e\u5230\uff0c\u5219\u4f1a\u5230 Base1 \u4e2d\u641c\u7d22\u5b83\uff0c\u7136\u540e\uff08\u9012\u5f52\u5730\uff09\u5230 Base1 \u7684\u57fa\u7c7b\u4e2d\u641c\u7d22\uff0c\u5982\u679c\u5728\u90a3\u91cc\u672a\u627e\u5230\uff0c\u518d\u5230 Base2 \u4e2d\u641c\u7d22\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002 \u771f\u5b9e\u60c5\u51b5\u66f4\u590d\u6742\uff1b\u65b9\u6cd5\u89e3\u6790\u987a\u5e8f\u4f1a\u52a8\u6001\u6539\u53d8\u4ee5\u652f\u6301\u5bf9 super() \u7684\u534f\u540c\u8c03\u7528\u3002 \u8fd9\u79cd\u65b9\u5f0f\u5728\u67d0\u4e9b\u5176\u4ed6\u591a\u91cd\u7ee7\u627f\u578b\u8bed\u8a00\u4e2d\u88ab\u79f0\u4e3a**\u540e\u7eed\u65b9\u6cd5\u8c03\u7528\uff08call-next-method\uff09**\uff0c\u5b83\u6bd4**\u5355\u7ee7\u627f\uff08single-inheritance\uff09**\u8bed\u8a00\u4e2d\u7684 uper \u8c03\u7528\u66f4\u5f3a\u5927\u3002 \u52a8\u6001\u6539\u53d8\u987a\u5e8f\u662f\u6709\u5fc5\u8981\u7684\uff0c\u56e0\u4e3a\u6240\u6709\u591a\u91cd\u7ee7\u627f\u7684\u60c5\u51b5\u90fd\u4f1a\u663e\u793a\u51fa\u4e00\u4e2a\u6216\u66f4\u591a\u7684\u83f1\u5f62\u5173\u8054\uff08diamond relationships\uff09\uff08\u5373\u81f3\u5c11\u6709\u4e00\u4e2a\u7236\u7c7b\u53ef\u901a\u8fc7\u591a\u6761\u8def\u5f84\u88ab\u6700\u5e95\u5c42\u7c7b\u6240\u8bbf\u95ee\uff09\u3002 \u4f8b\u5982\uff0c\u6240\u6709\u7c7b\u90fd\u662f\u7ee7\u627f\u81ea object \uff0c\u56e0\u6b64\u4efb\u4f55\u591a\u91cd\u7ee7\u627f\u7684\u60c5\u51b5\u90fd\u63d0\u4f9b\u4e86\u4e00\u6761\u4ee5\u4e0a\u7684\u8def\u5f84\u53ef\u4ee5\u901a\u5411 object \u3002 \u4e3a\u4e86\u786e\u4fdd\u57fa\u7c7b\u4e0d\u4f1a\u88ab\u8bbf\u95ee\u4e00\u6b21\u4ee5\u4e0a\uff0c\u52a8\u6001\u7b97\u6cd5\u4f1a\u7528\u4e00\u79cd\u7279\u6b8a\u65b9\u5f0f\u5c06\u641c\u7d22\u987a\u5e8f\u7ebf\u6027\u5316\uff0c \u4fdd\u7559\u6bcf\u4e2a\u7c7b\u6240\u6307\u5b9a\u7684\u4ece\u5de6\u81f3\u53f3\u7684\u987a\u5e8f\uff0c\u53ea\u8c03\u7528\u6bcf\u4e2a\u7236\u7c7b\u4e00\u6b21\uff0c\u5e76\u4e14\u4fdd\u6301\u5355\u8c03\uff08monotonic\uff09\uff08\u5373\u4e00\u4e2a\u7c7b\u53ef\u4ee5\u88ab\u5b50\u7c7b\u5316\u800c\u4e0d\u5f71\u54cd\u5176\u7236\u7c7b\u7684\u4f18\u5148\u987a\u5e8f\uff09\u3002 \u603b\u800c\u8a00\u4e4b\uff0c\u8fd9\u4e9b\u7279\u6027\u4f7f\u5f97\u8bbe\u8ba1\u5177\u6709\u591a\u91cd\u7ee7\u627f\u7684\u53ef\u9760\u4e14\u53ef\u6269\u5c55\u7684\u7c7b\u6210\u4e3a\u53ef\u80fd\u3002 \u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u5b9a\u4e49\u4e863\u4e2a\u7c7b\u548c\u7ee7\u627f\u5173\u7cfb\u3002 class F (): def drink ( self ): print ( \"Drink Beer\" ) class M (): def drink ( self ): print ( \"Drink Red Wine\" ) class C ( F , M ): def drink ( self ): print ( \"Drink Water\" ) \u6267\u884c\u7ed3\u679c\u662f c = C () c . drink () # Drink Water \u65b9\u6cd51\uff1a\u6309\u7167mro\u8fdb\u884c\u7ee7\u627f\u67e5\u627e\u3002 \u5982\u679c\u628a C \u7c7b\u6539\u5199\u4e3a\u5982\u4e0b\uff0c\u53ef\u4ee5\u8c03\u7528\u7236\u7c7b\uff0c\u53c2\u7167 C \u7c7b\u7684mro\u8fdb\u884c\uff0c mro \u91cc\u9762\u7c7b F \u7684\u4e0a\u4e00\u7ea7\u662f\u7c7b M \uff0c\u6240\u4ee5\u7c7b F \u4e2d\u7684 super() \u5c31\u662f\u6307\u7c7b M \u3002 class C ( F , M ): def drink ( self ): super () . drink () print ( \"Drink Water\" ) c = C () c . drink () # Drink Beer # Drink Water C . mro () # [, , , ] \u65b9\u6cd52\uff1a\u201c\u6307\u540d\u9053\u59d3\u201d\u8c03\u7528\u3002\u5982\u679c\u628a C \u7c7b\u6539\u5199\u4e3a\u5982\u4e0b\uff0c\u53ef\u4ee5\u8c03\u7528 M \u7c7b\u3002 class C ( F , M ): def drink ( self ): M . drink ( self ) print ( \"Drink Water\" ) c = C () c . drink () # Drink Red Wine # Drink Water","title":"\u591a\u91cd\u7ee7\u627f Multiple Inheritance"},{"location":"python/Foundation/ch05/#_1","text":"\u83f1\u5f62\u7ee7\u627f\u7684\u63cf\u8ff0\u662f\uff0c\u7c7b A \u4f5c\u4e3a\u57fa\u7c7b\uff08\u8fd9\u91cc\u57fa\u7c7b\u662f\u6307\u975e object \u7c7b\uff09\uff0c\u7c7b B \u548c\u7c7b C \u540c\u65f6\u7ee7\u627f\u7c7b A \uff0c\u7136\u540e\u7c7b D \u53c8\u7ee7\u627f\u7c7b B \u548c\u7c7b C \uff0c\u5982\u4e0b\u56fe\uff0c\u770b\u8d77\u6765\u50cf\u4e2a\u94bb\u77f3\u7684\u5f62\u72b6\u3002 A / \\ B C \\ / D \u5728\u8fd9\u79cd\u7ed3\u6784\u4e2d\uff0c\u5728\u8c03\u7528\u987a\u5e8f\u4e0a\u5c31\u4f1a\u51fa\u73b0\u7591\u60d1\uff0c\u8c03\u7528\u987a\u5e8f\u7a76\u7adf\u662f\u4ee5\u4e0b\u54ea\u4e00\u79cd\u987a\u5e8f\u5462\uff1f D->B->A->C\uff08\u6df1\u5ea6\u4f18\u5148\uff09 D->B->C->A\uff08\u5e7f\u5ea6\u4f18\u5148\uff09 \u770b\u4e0b\u9762\u4ee3\u7801\uff0c\u5728Python3\u4e2d\uff0c**\u83f1\u5f62**\u7684\u591a\u7ee7\u627f\u5173\u7cfb\u662f\u6309\u7167D->B->C->A**\u5e7f\u5ea6\u4f18\u5148**\u7684\u641c\u7d22\u65b9\u5f0f\u3002 class A (): pass class B ( A ): def test ( self ): print ( \"init B.test()\" ) class C ( A ): def test ( self ): print ( \"init C.test()\" ) class D ( B , C ): pass d = D () d . test () # init B.test() D . mro () # [, , , , ] \u5bf9\u4e8e\u4e0b\u9762\u8fd9\u79cd**\u975e\u83f1\u5f62**\u7684\u591a\u7ee7\u627f\u5173\u7cfb\uff0c\u67e5\u627e\u987a\u5e8f\u662fA->B->E->C->F->D**\u6df1\u5ea6\u4f18\u5148**\u7684\u641c\u7d22\u65b9\u5f0f\u3002 E F | | B ( E ) C ( F ) D | | | \\ | / \\ | / A ( B , C , D ) \u4ee3\u7801\u5b9e\u73b0\uff1a class D (): def test ( self ): print ( \"init D.test()\" ) class F (): def test ( self ): print ( \"init F.test()\" ) class C ( F ): pass class E (): pass class B ( E ): pass class A ( B , C , D ): pass a = A () a . test () # init F.test() A . mro () # [, , , , , , ] \u603b\u7ed3\uff1a \u7ee7\u627f\u7ed3\u6784\u8981\u5c3d\u91cf\u7b80\u5355\uff0c\u4e0d\u8981\u8fc7\u4e8e\u590d\u6742\u3002 \u63a8\u8350\u4f7f\u7528minxins\u673a\u5236\uff0c\u5728\u591a\u7ee7\u627f\u80cc\u666f\u4e0b\uff0c\u6ee1\u8db3\u7ee7\u627f\u7684\u4ec0\u4e48\u662f\u4ec0\u4e48\u7684\u5173\u7cfb\uff08is-a\uff09","title":"\u83f1\u5f62\u7ee7\u627f\u548c\u7ee7\u627f\u5173\u7cfb\u68c0\u6d4b"},{"location":"python/Foundation/ch05/#minxins","text":"\u770b\u4e0b\u9762\u4f8b\u5b50\uff0c\u5982\u679c\u5728 Vehicle \u7c7b\u4e2d\u5b9a\u4e49\u4e86 fly \u7684\u65b9\u6cd5\uff0c\u4f1a\u5bfc\u81f4 Car(Vehicle) \u7684\u7ee7\u627f\u5173\u7cfb\u51fa\u73b0\u77db\u76fe\uff0c\u6c7d\u8f66\u5e76\u4e0d\u4f1a\u98de\uff0c\u4f46\u6309\u7167\u4e0a\u8ff0\u7ee7\u627f\u5173\u7cfb\uff0c\u6c7d\u8f66\u4e5f\u80fd\u98de\u4e86\u3002 \u4f46\u662f\u5982\u679c\u6c11\u822a\u98de\u673a\u548c\u76f4\u5347\u673a\u90fd\u5404\u81ea\u5199\u81ea\u5df1\u7684\u98de\u884cfly\u65b9\u6cd5\uff0c\u53c8\u8fdd\u80cc\u4e86\u4ee3\u7801\u5c3d\u53ef\u80fd\u91cd\u7528\u7684\u539f\u5219\u3002 class Vehicle : # \u4ea4\u901a\u5de5\u5177 def fly ( self ): ''' \u98de\u884c\u529f\u80fd\u76f8\u5e94\u7684\u4ee3\u7801 ''' print ( \"I am flying\" ) # \u6c11\u822a\u98de\u673a class CivilAircraft ( Vehicle ): pass # \u76f4\u5347\u98de\u673a class Helicopter ( Vehicle ): pass # \u6c7d\u8f66 class Car ( Vehicle ): pass Python\u4e2d\u6ca1\u6709\u7c7b\u4f3cJava\u63a5\u53e3interface\u7684\u529f\u80fd\uff0c\u4f46\u63d0\u4f9b\u4e86Mixins\u673a\u5236\u3002 Python\u5bf9\u4e8e Mixin \u7c7b\u7684\u547d\u540d\u65b9\u5f0f\u4e00\u822c\u4ee5 Mixin , able , ible \u4e3a\u540e\u7f00\u3002 Mixin \u7c7b\u5fc5\u987b\u529f\u80fd\u5355\u4e00\uff0c\u5982\u679c\u6709\u591a\u4e2a\u529f\u80fd\uff0c\u90a3\u5c31\u5199\u591a\u4e2aMixin\u7c7b\u3002 \u4e00\u4e2a\u7c7b\u53ef\u4ee5\u7ee7\u627f\u591a\u4e2a Mixin \u7c7b\uff0c\u4e3a\u4e86\u4fdd\u8bc1\u9075\u5faa\u7ee7\u627f\u7684\u201cis-a\u201d\u539f\u5219\uff0c\u53ea\u80fd\u7ee7\u627f\u4e00\u4e2a\u6807\u8bc6\u5176\u5f52\u5c5e\u542b\u4e49\u7684\u7236\u7c7b Mixin \u7c7b\u4e0d\u4f9d\u8d56\u4e8e\u5b50\u7c7b\u7684\u5b9e\u73b0\u3002 \u5b50\u7c7b\u5373\u4fbf\u6ca1\u6709\u7ee7\u627f\u8fd9\u4e2a Mixin \u7c7b\u7c7b\uff0c\u4e5f\u7167\u6837\u53ef\u4ee5\u5de5\u4f5c\uff0c\u5c31\u662f\u7f3a\u5c11\u4e86\u67d0\u4e2a\u529f\u80fd\u3002 \u6211\u4eec\u5b9a\u4e49\u7684 Mixin \u7c7b\u8d8a\u591a\uff0c\u5b50\u7c7b\u7684\u4ee3\u7801\u53ef\u8bfb\u6027\u5c31\u4f1a\u8d8a\u5dee\u3002 # \u4ea4\u901a\u5de5\u5177 class Vehicle : pass # \u4e3a\u5f53\u524d\u7c7b\u6df7\u5165\u4e00\u4e9b\u529f\u80fd\uff0c\u4e0d\u662f\u4e00\u4e2a\u5355\u7eaf\u7684\u7c7b class FlyableMixin : def fly ( self ): ''' \u98de\u884c\u529f\u80fd\u76f8\u5e94\u7684\u4ee3\u7801 ''' print ( \"I am flying\" ) # \u6c11\u822a\u98de\u673a class CivilAircraft ( FlyableMixin , Vehicle ): pass # \u76f4\u5347\u98de\u673a class Helicopter ( FlyableMixin , Vehicle ): pass # \u6c7d\u8f66 class Car ( Vehicle ): pass","title":"\u591a\u7ee7\u627f\u5173\u7cfb\u7684minxins\u673a\u5236"},{"location":"python/Foundation/ch05/#class-combination","text":"\u5728\u4e00\u4e2a\u7c7b\u4e2d\u4ee5\u53e6\u4e00\u4e2a\u7c7b\u7684\u5bf9\u8c61\u4f5c\u4e3a\u6570\u636e\u5c5e\u6027\uff0c\u79f0\u4e3a\u7c7b\u7684**\u7ec4\u5408**\u3002\u7ec4\u5408\u4e0e\u7ee7\u627f\u90fd\u662f\u7528\u6765\u89e3\u51b3\u4ee3\u7801\u7684\u91cd\u7528\u6027\u95ee\u9898\u3002 \u7ee7\u627f\u4f53\u73b0\u201c\u662f\u201d\u7684\u5173\u7cfb\uff0c\u5f53\u7c7b\u4e4b\u95f4\u6709\u5f88\u591a\u76f8\u540c\u4e4b\u5904\uff0c\u7528\u7ee7\u627f\u3002 \u7ec4\u5408\u4f53\u73b0\u201c\u6709\u201d\u7684\u5173\u7cfb\uff0c\u5f53\u7c7b\u4e4b\u95f4\u6709\u663e\u8457\u4e0d\u540c\uff0c\u4e00\u4e2a\u7c7b\u662f\u53e6\u4e00\u4e2a\u7c7b\u7684\u5c5e\u6027\u662f\uff0c\u7528\u7ec4\u5408\u3002 \u4e0b\u4f8b\u662f\u8ba1\u7b97\u5706\u73af\u7684\u9762\u79ef\u548c\u5468\u957f\uff0c\u5706\u73af\u662f\u7531\u4e24\u4e2a\u5706\u7ec4\u6210\u7684\uff0c\u5706\u73af\u7684\u9762\u79ef\u662f\u5916\u9762\u5706\u7684\u9762\u79ef\u51cf\u53bb\u5185\u90e8\u5706\u7684\u9762\u79ef\u3002\u5706\u73af\u7684\u5468\u957f\u662f\u5185\u90e8\u5706\u7684\u5468\u957f\u52a0\u4e0a\u5916\u90e8\u5706\u7684\u5468\u957f\u3002 \u8fd9\u4e2a\u4f8b\u5b50\u6f14\u793a\u4e86\u7c7b ring \u91cc\u9762\u7684\u5c5e\u6027 circle1 \u548c circle2 \u6b63\u662f\u53e6\u4e00\u4e2a\u7c7b Circle \u3002 from math import pi class Circle (): def __init__ ( self , r ): self . r = r def area ( self ): return pi * self . r * self . r def perimeter ( self ): return 2 * pi * self . r class Ring (): def __init__ ( self , r1 , r2 ): self . circle1 = Circle ( r1 ) self . circle2 = Circle ( r2 ) def area ( self ): return abs ( self . circle1 . area () - self . circle2 . area ()) def permiter ( self ): return self . circle1 . perimeter () + self . circle2 . perimeter () ring = Ring ( 5 , 8 ) print ( ring . area ()) # 122.52211349000193 print ( ring . permiter ()) # 81.68140899333463 \u4e0b\u9762\u7684\u4f8b\u5b50\u6f14\u793a\u4e86\u5982\u4f55\u901a\u8fc7\u4f20\u53c2\u7684\u65b9\u5f0f\u8fdb\u884c\u7c7b\u7684\u7ec4\u5408\u3002 class Birthday (): def __init__ ( self , year , month , day ): self . year = year self . month = month self . day = day class Course (): def __init__ ( self , course_name , course_period ): self . course_name = course_name self . course_period = course_period class Professor (): def __init__ ( self , name , gender , birth , course ): self . name = name self . gender = gender self . birth = birth self . course = course def teach ( self ): print ( f \"Professor name: { self . name } ; Gender: { self . gender } ; Birthday: { self . birth . year } - { self . birth . month }{ self . birth . day } , Course name: { self . course . course_name } and period: { self . course . course_period } \" ) prof = Professor ( 'Tom' , 'Male' , Birthday ( 1985 , 5 , 5 ), Course ( 'Chinese' , '2022/3/1 ~ 2022/6/30' )) prof . teach () # Professor name: Tom; Gender: Male; Birthday: 1985-55, Course name: Chinese and period: 2022/3/1 ~ 2022/6/30","title":"\u7ec4\u5408\uff08Class Combination\uff09"},{"location":"python/Foundation/ch05/#polymorphism","text":"\u591a\u6001\u610f\u5473\u7740\u76f8\u540c\u7684\u51fd\u6570\u540d\u7528\u4e8e\u4e0d\u540c\u7684\u60c5\u5f62\u3002 \u5982\u4e0b\u4f8b\uff0c len() \u88ab\u7528\u4e8e\u4e0d\u540c\u7684\u60c5\u5f62\u3002 # len() being used for a string print ( len ( \"geeks\" )) # 5 # len() being used for a list print ( len ([ 10 , 20 , 30 ])) # 3","title":"\u591a\u6001 Polymorphism"},{"location":"python/Foundation/ch05/#_2","text":"\u4e0b\u9762\u7684\u4ee3\u7801\u5c55\u793a\u4e86 Python \u5982\u4f55\u4ee5\u76f8\u540c\u7684\u65b9\u5f0f\u4f7f\u7528\u4e24\u79cd\u4e0d\u540c\u7684\u7c7b\u7c7b\u578b\u3002 \u6211\u4eec\u521b\u5efa\u4e86\u4e00\u4e2a\u904d\u5386\u5bf9\u8c61\u5143\u7ec4\u7684 for \u5faa\u73af\u3002 \u7136\u540e\u8c03\u7528\u65b9\u6cd5\u800c\u4e0d\u7528\u5173\u5fc3\u6bcf\u4e2a\u5bf9\u8c61\u662f\u54ea\u4e2a\u7c7b\u7c7b\u578b\u3002 \u6211\u4eec\u5047\u8bbe\u8fd9\u4e9b\u65b9\u6cd5\u5b9e\u9645\u4e0a\u5b58\u5728\u4e8e\u6bcf\u4e2a\u7c7b\u4e2d\u3002 class India (): def capital ( self ): print ( \"New Delhi is the capital of India.\" ) def language ( self ): print ( \"Hindi is the most widely spoken language of India.\" ) def type ( self ): print ( \"India is a developing country.\" ) class USA (): def capital ( self ): print ( \"Washington, D.C. is the capital of USA.\" ) def language ( self ): print ( \"English is the primary language of USA.\" ) def type ( self ): print ( \"USA is a developed country.\" ) obj_ind = India () obj_usa = USA () for country in ( obj_ind , obj_usa ): country . capital () country . language () country . type () # New Delhi is the capital of India. # Hindi is the most widely spoken language of India. # India is a developing country. # Washington, D.C. is the capital of USA. # English is the primary language of USA. # USA is a developed country.","title":"\u7c7b\u65b9\u6cd5\u7684\u591a\u6001\u6027"},{"location":"python/Foundation/ch05/#_3","text":"\u5728 Python \u4e2d\uff0c\u591a\u6001\u5141\u8bb8\u6211\u4eec\u5728\u5b50\u7c7b\u4e2d\u5b9a\u4e49\u4e0e\u7236\u7c7b\u4e2d\u7684\u65b9\u6cd5\u540c\u540d\u7684\u65b9\u6cd5\u3002 \u5728\u7ee7\u627f\u4e2d\uff0c\u5b50\u7c7b\u7ee7\u627f\u7236\u7c7b\u7684\u65b9\u6cd5\u3002 \u4f46\u662f\uff0c\u53ef\u4ee5\u4fee\u6539\u4ece\u7236\u7c7b\u7ee7\u627f\u7684\u5b50\u7c7b\u4e2d\u7684\u65b9\u6cd5\u3002 \u8fd9\u5728\u4ece\u7236\u7c7b\u7ee7\u627f\u7684\u65b9\u6cd5\u4e0d\u592a\u9002\u5408\u5b50\u7c7b\u7684\u60c5\u51b5\u4e0b\u7279\u522b\u6709\u7528\u3002 \u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u5728\u5b50\u7c7b\u4e2d\u91cd\u65b0\u5b9e\u73b0\u8be5\u65b9\u6cd5\u3002 \u8fd9\u79cd\u5728\u5b50\u7c7b\u4e2d\u91cd\u65b0\u5b9e\u73b0\u65b9\u6cd5\u7684\u8fc7\u7a0b\u79f0\u4e3a**\u65b9\u6cd5\u8986\u76d6\uff08Method Overriding\uff09**\u3002 class Bird : def intro ( self ): print ( \"There are many types of birds.\" ) def flight ( self ): print ( \"Most of the birds can fly but some cannot.\" ) class sparrow ( Bird ): def flight ( self ): print ( \"Sparrows can fly.\" ) class ostrich ( Bird ): def flight ( self ): print ( \"Ostriches cannot fly.\" ) obj_bird = Bird () obj_spr = sparrow () obj_ost = ostrich () obj_bird . intro () # There are many types of birds. obj_bird . flight () # Most of the birds can fly but some cannot. obj_spr . intro () # There are many types of birds. obj_spr . flight () # Sparrows can fly. obj_ost . intro () # There are many types of birds. obj_ost . flight () # Ostriches cannot fly.","title":"\u7ee7\u627f\u7684\u591a\u6001\u6027"},{"location":"python/Foundation/ch05/#_4","text":"\u6211\u4eec\u4e5f\u53ef\u4ee5\u521b\u5efa\u4e00\u4e2a\u53ef\u4ee5\u63a5\u53d7\u4efb\u4f55\u5bf9\u8c61\u7684\u51fd\u6570\uff0c\u5141\u8bb8\u591a\u6001\u6027\u3002 \u5728\u4e0b\u9762\u4f8b\u5b50\u4e2d\uff0c\u6211\u4eec\u521b\u5efa\u4e00\u4e2a\u540d\u4e3a func() \u7684\u51fd\u6570\uff0c\u4f20\u5165\u53c2\u6570\u662f obj \u7684\u5bf9\u8c61\u3002 \u5728\u8fd9\u79cd\u60c5\u51b5\u4e0b\uff0c\u6211\u4eec\u8c03\u7528\u4e09\u4e2a\u65b9\u6cd5\uff0c\u5373 capital() \u3001 language() \u548c type() \uff0c\u6bcf\u4e2a\u65b9\u6cd5\u90fd\u5b9a\u4e49\u5728 India \u548c USA \u4e24\u4e2a\u7c7b\u4e2d\u3002 \u6211\u4eec\u53ef\u4ee5\u4f7f\u7528\u76f8\u540c\u7684 func() \u51fd\u6570\u8c03\u7528\u5b83\u4eec\u7684\u52a8\u4f5c\uff1a class India (): def capital ( self ): print ( \"New Delhi is the capital of India.\" ) def language ( self ): print ( \"Hindi is the most widely spoken language of India.\" ) def type ( self ): print ( \"India is a developing country.\" ) class USA (): def capital ( self ): print ( \"Washington, D.C. is the capital of USA.\" ) def language ( self ): print ( \"English is the primary language of USA.\" ) def type ( self ): print ( \"USA is a developed country.\" ) def func ( obj ): obj . capital () obj . language () obj . type () obj_ind = India () obj_usa = USA () func ( obj_ind ) # New Delhi is the capital of India. # Hindi is the most widely spoken language of India. # India is a developing country. func ( obj_usa ) # Washington, D.C. is the capital of USA. # English is the primary language of USA. # USA is a developed country.","title":"\u51fd\u6570\u548c\u5bf9\u8c61\u7684\u591a\u6001\u6027"},{"location":"python/Foundation/ch05/#ducking-typinggoose-typing","text":"\u5728Python\u4e2d\u5b9e\u73b0\u591a\u6001\u4e3b\u8981\u6709\u4e24\u79cd\u673a\u5236\uff1a\u767d\u9e45\u7c7b\u578b\u548c\u9e2d\u5b50\u7c7b\u578b\u3002\u767d\u9e45\u7c7b\u578b\u548c\u9e2d\u5b50\u7c7b\u578b\u4e0d\u4ec5\u662f\u4e24\u79cd\u673a\u5236\uff0c\u4e5f\u662f\u4e24\u79cd\u4e0d\u540c\u7684\u7f16\u7a0b\u98ce\u683c\u3002 \u4e0b\u9762\u662f\u4e00\u4e2a\u6253\u5370\u5546\u54c1\u4ef7\u683c\u7684\u4f8b\u5b50\uff0c\u5206\u522b\u7528\u9e2d\u5b50\u7c7b\u578b\u548c\u767d\u9e45\u7c7b\u578b\u5b9e\u73b0\u3002 \u9e2d\u5b50\u7c7b\u578b\u3002 \u5728\u9e2d\u5b50\u7c7b\u578b\u7684\u5b9e\u73b0\u4e2d\uff0c\u6211\u4eec\u53ea\u9700\u8981\u4fdd\u8bc1\u8c03\u7528 price \u65b9\u6cd5\u7684\u6bcf\u4e2a\u5bf9\u8c61\u90fd\u6709 price \u65b9\u6cd5\u5373\u53ef\u3002 class Food : def price ( self ): print ( \" {} price:$4\" . format ( __class__ . __name__ )) class Clothes : def price ( self ): print ( \" {} price:$5\" . format ( __class__ . __name__ )) class Coffee : def price ( self ): print ( \" {} price:$6\" . format ( __class__ . __name__ )) if __name__ == '__main__' : goods = [ Food (), Clothes (), Coffee ()] for good in goods : good . price () # Food price:$4 # Clothes price:$5 # Coffee price:$6 \u767d\u9e45\u7c7b\u578b\u3002 \u5728\u767d\u9e45\u7c7b\u578b\u4e2d\uff0c\u76f4\u63a5\u8ba9\u6240\u6709\u5bf9\u8c61\u7684\u7c7b\u7ee7\u627f\u7236\u7c7b Good \u4e2d\u7684\u62bd\u8c61\u65b9\u6cd5 price \u3002Python\u4e2d\u7684\u767d\u9e45\u7c7b\u578b\u673a\u5236\u5c31\u662f\u5f3a\u7c7b\u578b\u8bed\u8a00\u4e2d\u5b9e\u73b0\u591a\u6001\u7684\u6807\u51c6\u6a21\u5f0f\uff0c\u5373\u901a\u8fc7\u8c03\u53d6\u7236\u7c7b\u7684\u865a\u51fd\u6570\u6216\u8005\u7ee7\u627f\u7684\u51fd\u6570\u6765\u5b8c\u6210\u4e0d\u540c\u7684\u884c\u4e3a\u3002 import abc class Good ( abc . ABC ): @abc . abstractmethod def price ( self ): pass class Food ( Good ): def price ( self ): print ( \" {} price:$4\" . format ( __class__ . __name__ )) class Clothes ( Good ): def price ( self ): print ( \" {} price:$5\" . format ( __class__ . __name__ )) if __name__ == '__main__' : goods = [ Food (), Clothes (), Coffee ()] for good in goods : good . price () # Food price:$4 # Clothes price:$5 # Coffee price:$6","title":"\u9e2d\u5b50\u7c7b\u578b\uff08Ducking Typing\uff09\u548c\u767d\u9e45\u7c7b\u578b\uff08Goose Typing\uff09"},{"location":"python/Foundation/ch05/#class-methodstatic-method","text":"\u7c7b\u65b9\u6cd5\uff08Class method\uff09\u4e5f\u53eb\u7ed1\u5b9a\u65b9\u6cd5\uff0c\u5fc5\u987b\u628a\u7c7b\u4f5c\u4e3a\u4f20\u5165\u53c2\u6570\uff0c\u4f7f\u7528 cls \u4f5c\u4e3a\u7b2c\u4e00\u4e2a\u4f20\u5165\u53c2\u6570\uff0c\u800c\u9759\u6001\u65b9\u6cd5\uff08Static Method\uff09\uff0c\u4e5f\u53eb\u975e\u7ed1\u5b9a\u65b9\u6cd5\uff0c\u4e0d\u9700\u8981\u7279\u5b9a\u7684\u53c2\u6570\u3002 \u7c7b\u65b9\u6cd5\u662f\u7ed1\u5b9a\u5230\u7c7b\u7684\uff0c\u4e0d\u662f\u7ed1\u5b9a\u5230\u7c7b\u5bf9\u8c61\uff0c\u6240\u4ee5\u7c7b\u65b9\u6cd5\u53ef\u4ee5\u8bbf\u95ee\u6216\u4fee\u6539\u7c7b\uff0c\u5e76\u5bf9\u6240\u6709\u7c7b\u5b9e\u4f8b\u751f\u6548\u3002 \u9759\u6001\u65b9\u6cd5\u65e0\u6cd5\u76f4\u63a5\u8bbf\u95ee\u6216\u4fee\u6539\u7c7b\uff0c\u56e0\u4e3a\u9759\u6001\u65b9\u6cd5\u662f\u4e0d\u77e5\u9053\u7c7b\u672c\u8eab\u7684\uff0c\u9759\u6001\u65b9\u6cd5\u662f\u5c5e\u4e8e\u5de5\u5177\u7c7b\u65b9\u6cd5\uff0c\u57fa\u4e8e\u4f20\u5165\u7684\u53c2\u6570\u5b8c\u6210\u7279\u5b9a\u7684\u529f\u80fd\uff0c\u5176\u5b9e\u5c31\u662f\u4e00\u4e2a\u666e\u901a\u51fd\u6570\u800c\u5df2\u3002 Python\u4e2d\u4f7f\u7528 @classmethod \u88c5\u9970\u5668\uff08decorator\uff09\u6765\u521b\u5efa\u4e00\u4e2a\u7c7b\u65b9\u6cd5\uff0c\u7528@staticmethod\u88c5\u9970\u5668\u6765\u521b\u5efa\u4e00\u4e2a\u9759\u6001\u65b9\u6cd5\u3002 \u8bed\u6cd5\u683c\u5f0f\uff1a @classmethod def fun ( cls , arg1 , arg2 , ... ): \u5176\u4e2d\uff1a fun : \u9700\u8981\u8f6c\u6362\u6210\u7c7b\u65b9\u6cd5\u7684\u51fd\u6570 returns : \u51fd\u6570\u7684\u7c7b\u65b9\u6cd5 classmethod() \u65b9\u6cd5\u7ed1\u5b9a\u5230\u7c7b\u800c\u4e0d\u662f\u5bf9\u8c61\u3002\u7c7b\u65b9\u6cd5\u53ef\u4ee5\u88ab\u7c7b\u548c\u5bf9\u8c61\u8c03\u7528\u3002\u8fd9\u4e9b\u65b9\u6cd5\u53ef\u4ee5\u901a\u8fc7\u7c7b\u6216\u5bf9\u8c61\u8fdb\u884c\u8c03\u7528\u3002 \u4f8b1\uff1a\u521b\u5efa\u4e00\u4e2a\u7b80\u5355\u7684 classmethod \u3002 \u521b\u5efa\u4e00\u4e2a\u7c7b Training \uff0c\u6709\u7c7b\u53d8\u91cf course \u548c\u65b9\u6cd5 purchase \u3002 \u6211\u4eec\u901a\u8fc7\u628a\u51fd\u6570 Training.purchase \u4f20\u7ed9 classmethod() \uff0c\u628a\u8be5\u65b9\u6cd5\u8f6c\u6210\u7c7b\u65b9\u6cd5\uff0c\u7136\u540e\u76f4\u63a5\u8c03\u7528\u5b83\uff0c\u800c\u65e0\u9700\u5148\u521b\u5efa\u5bf9\u8c61\u3002 \u53ef\u4ee5\u770b\u51fa\u8f6c\u6362\u524d\u540e Training.purchase \u7684\u7c7b\u578b\u53d8\u5316\u3002 class Training : course = 'Python for Data Analysis' def purchase ( obj ): print ( \"Puchase course : \" , obj . course ) type ( Training . purchase ) # Training . purchase = classmethod ( Training . purchase ) Training . purchase () # Puchase course : Python for Data Analysis type ( Training . purchase ) # \u4f8b2\uff1a\u4f7f\u7528\u88c5\u9970\u5668 @classmethod \u521b\u5efa\u5de5\u5382\u7c7b\u3002 class Training : def __init__ ( self , course ): self . course = course @classmethod def purchase ( cls , course ): return cls ( course ) def display ( self ): print ( 'Purchase course: ' , self . course ) training = Training ( \"Python for Data Analysis\" ) training . display () # Purchase course: Python for Data Analysis \u4f8b3\uff1a\u901a\u8fc7 staticmethod() \u548c classmethod() \u6765\u68c0\u67e5\u4e00\u4e2aperson\u662f\u5426\u662fadult\u3002 person1\u662f\u901a\u8fc7\u59d3\u540d\u548c\u5e74\u9f84\u521b\u5efa\u7684\u5b9e\u4f8b\u3002person2\u662f\u901a\u8fc7\u59d3\u540d\u548c\u5e74\u4efd\u521b\u5efa\u7684\u5b9e\u4f8b\u3002 from datetime import date class Person : def __init__ ( self , name , age ): self . name = name self . age = age @classmethod def fromBirthYear ( cls , name , year ): return cls ( name , date . today () . year - year ) @staticmethod def isAdult ( age ): return age > 18 person1 = Person ( 'mayank' , 21 ) person2 = Person . fromBirthYear ( 'mayank' , 1996 ) print ( person1 . age ) # 21 print ( person2 . age ) # 26 print ( Person . isAdult ( 22 )) # True \u5c0f\u7ed3\uff1a \u82e5\u7c7b\u4e2d\u9700\u8981\u4e00\u4e2a\u529f\u80fd\uff0c\u8be5\u529f\u80fd\u7684\u5b9e\u73b0\u4ee3\u7801\u4e2d\u9700\u8981\u5f15\u7528\u5bf9\u8c61\uff0c\u5219\u5c06\u5176\u5b9a\u4e49\u6210\u5bf9\u8c61\u65b9\u6cd5\uff1b\u9700\u8981\u5f15\u7528\u7c7b\uff0c\u5219\u5c06\u5176\u5b9a\u4e49\u6210\u7c7b\u65b9\u6cd5\uff1b\u65e0\u9700\u5f15\u7528\u7c7b\u6216\u5bf9\u8c61\uff0c\u5219\u5c06\u5176\u5b9a\u4e49\u6210\u9759\u6001\u65b9\u6cd5\u3002","title":"\u7c7b\u65b9\u6cd5\uff08Class method\uff09\u548c\u9759\u6001\u65b9\u6cd5\uff08Static Method\uff09"},{"location":"python/Foundation/ch05/#monkey-patch","text":"\u7334\u5b50\u8865\u4e01\u662f\u52a8\u6001\u4e3a\u5df2\u7ecf\u521b\u5efa\u51fa\u7684\u5bf9\u8c61\u589e\u52a0\u65b0\u7684\u65b9\u6cd5\u548c\u5c5e\u6027\u6210\u5458\u7684\u4e00\u79cd\u673a\u5236\uff0c\u4e5f\u5c31\u662f\u52a8\u6001\u6253\u8865\u4e01\u3002 \u5b9e\u4f8b\u5316\u5bf9\u8c61\u7684\u7334\u5b50\u8865\u4e01\u3002 class Test : def __init__ ( self ): self . a = 1 def func1 ( self , x , y ): print ( x + y ) # \u6b63\u5e38\u5b9e\u4f8b\u5316 test = Test () test . func1 ( 1 , 1 ) # 2 # \u4fee\u6539\u5b9e\u4f8b test . func1 = lambda x , y : print ( x + 2 * y ) test . func1 ( 1 , 1 ) # 3 # \u901a\u8fc7\u4fee\u6539\u5b9e\u4f8b\uff0c\u8bbf\u95ee\u5185\u90e8\u6210\u5458\u53d8\u91cf\u3002 test . func1 = lambda x , y : print ( x + 2 * y + self . a ) test . func1 ( 1 , 1 ) # NameError: name 'self' is not defined test . func1 = lambda self , x , y : print ( x + 2 * y + self . a ) test . func1 ( test , 1 , 1 ) # 4 \u7c7b\u5bf9\u8c61\u7684\u7334\u5b50\u8865\u4e01\u3002 class Test : def __init__ ( self ): self . a = 1 def func1 ( self , x , y ): print ( x + y ) # \u4fee\u6539\u7c7b\u6210\u5458\uff0c\u5b9e\u4f8b\u5316\u540e\u7684\u7ed3\u679c\u5df2\u4fee\u6539\u3002 Test . func1 = lambda self , x , y : print ( x + 2 * y ) test = Test () test . func1 ( 1 , 1 ) # 3 # \u4fee\u6539\u7c7b\u6210\u5458\uff0c\u5e76\u8bbf\u95ee\u6210\u5458\u53d8\u91cf\uff0c\u5b9e\u4f8b\u5316\u540e\u7684\u7ed3\u679c\u5df2\u4fee\u6539\u3002 Test . func1 = lambda self , x , y : print ( x + 2 * y + self . a ) test = Test () test . func1 ( 1 , 1 ) # 4 # \u589e\u52a0\u7c7b\u6210\u5458\u3002 Test . func2 = lambda self , p , q : print ( p + 3 * q + self . a ) test = Test () test . func1 ( 1 , 1 ) # 4 test . func2 ( 1 , 3 ) # 11","title":"\u7334\u5b50\u8865\u4e01\uff08monkey patch\uff09"},{"location":"python/Foundation/ch05/#private-variables","text":"\u90a3\u79cd\u4ec5\u9650\u4ece\u4e00\u4e2a\u5bf9\u8c61\u5185\u90e8\u8bbf\u95ee\u7684\u201c\u79c1\u6709\u201d\u5b9e\u4f8b\u53d8\u91cf\uff08\u201cPrivate\u201d instance variables\uff09\u5728 Python \u4e2d\u5e76\u4e0d\u5b58\u5728\u3002 \u4f46\u662f\uff0c\u5927\u591a\u6570 Python \u4ee3\u7801\u90fd\u9075\u5faa\u8fd9\u6837\u4e00\u4e2a\u7ea6\u5b9a\uff1a\u5e26\u6709*\u4e00\u4e2a\u524d\u7f00\u4e0b\u5212\u7ebf*\u7684\u540d\u79f0 (\u4f8b\u5982 _spam ) \u5e94\u8be5\u88ab\u5f53\u4f5c\u662f API \u7684\u975e\u516c\u6709\uff08non-public\uff09\u90e8\u5206 (\u65e0\u8bba\u5b83\u662f\u51fd\u6570\u3001\u65b9\u6cd5\u6216\u662f\u6570\u636e\u6210\u5458)\u3002 \u8fd9\u5e94\u5f53\u88ab\u89c6\u4e3a\u4e00\u4e2a\u5b9e\u73b0\u7ec6\u8282\uff0c\u53ef\u80fd\u4e0d\u7ecf\u901a\u77e5\u5373\u52a0\u4ee5\u6539\u53d8\u3002 \u7531\u4e8e\u5b58\u5728\u5bf9\u4e8e\u7c7b\u79c1\u6709\u6210\u5458\uff08class-private members\uff09\u7684\u6709\u6548\u4f7f\u7528\u573a\u666f\uff08\u4f8b\u5982\u907f\u514d\u540d\u79f0\u4e0e\u5b50\u7c7b\u6240\u5b9a\u4e49\u7684\u540d\u79f0\u76f8\u51b2\u7a81\uff09\uff0c\u56e0\u6b64\u5b58\u5728\u5bf9\u6b64\u79cd\u673a\u5236\u7684\u6709\u9650\u652f\u6301\uff0c\u79f0\u4e3a**\u540d\u79f0\u6539\u5199\uff08name mangling\uff09**\u3002 \u4efb\u4f55\u5f62\u5f0f\u4e3a __spam \u7684\u6807\u8bc6\u7b26\uff08\u81f3\u5c11\u5e26\u6709*\u4e24\u4e2a\u524d\u7f00\u4e0b\u5212\u7ebf*\uff0c\u81f3\u591a\u4e00\u4e2a\u540e\u7f00\u4e0b\u5212\u7ebf\uff09\u7684\u6587\u672c\u5c06\u88ab\u66ff\u6362\u4e3a _classname__spam \uff0c\u5176\u4e2d classname \u4e3a\u53bb\u9664\u4e86\u524d\u7f00\u4e0b\u5212\u7ebf\u7684\u5f53\u524d\u7c7b\u540d\u79f0\u3002 \u8fd9\u79cd\u6539\u5199\u4e0d\u8003\u8651\u6807\u8bc6\u7b26\u7684\u53e5\u6cd5\u4f4d\u7f6e\uff0c\u53ea\u8981\u5b83\u51fa\u73b0\u5728\u7c7b\u5b9a\u4e49\u5185\u90e8\u5c31\u4f1a\u8fdb\u884c\u3002 \u540d\u79f0\u6539\u5199\uff08Name mangling\uff09\u6709\u52a9\u4e8e\u8ba9\u5b50\u7c7b\u91cd\u8f7d\u65b9\u6cd5\uff08\uff09override methods\u800c\u4e0d\u7834\u574f\u7c7b\u5185\u65b9\u6cd5\uff08intraclass method\uff09\u8c03\u7528\u3002\u4f8b\u5982: class Mapping : def __init__ ( self , iterable ): self . items_list = [] self . __update ( iterable ) def update ( self , iterable ): for item in iterable : self . items_list . append ( item ) __update = update # private copy of original update() method class MappingSubclass ( Mapping ): def update ( self , keys , values ): # provides new signature for update() # but does not break __init__() for item in zip ( keys , values ): self . items_list . append ( item ) \u4e0a\u9762\u7684\u793a\u4f8b\u5373\u4f7f\u5728 MappingSubclass \u5f15\u5165\u4e86\u4e00\u4e2a __update \u6807\u8bc6\u7b26\u7684\u60c5\u51b5\u4e0b\u4e5f\u4e0d\u4f1a\u51fa\u9519\uff0c\u56e0\u4e3a\u5b83\u4f1a\u5728 Mapping \u7c7b\u4e2d\u88ab\u66ff\u6362\u4e3a _Mapping__update \u800c\u5728 MappingSubclass \u7c7b\u4e2d\u88ab\u66ff\u6362\u4e3a _MappingSubclass__update \u3002 \u8bf7\u6ce8\u610f\uff0c\u6539\u5199\u89c4\u5219\uff08mangling rules\uff09\u7684\u8bbe\u8ba1\u4e3b\u8981\u662f\u4e3a\u4e86\u907f\u514d\u610f\u5916\u51b2\u7a81\uff1b\u8bbf\u95ee\u6216\u4fee\u6539\u79c1\u6709\u53d8\u91cf\u4ecd\u7136\u662f\u53ef\u80fd\u7684\u3002\u8fd9\u5728\u7279\u6b8a\u60c5\u51b5\u4e0b\u751a\u81f3\u4f1a\u5f88\u6709\u7528\uff0c\u4f8b\u5982\u5728\u8c03\u8bd5\u5668\uff08debugger\uff09\u4e2d\u3002 \u8bf7\u6ce8\u610f\u4f20\u9012\u7ed9 exec() \u6216 eval() \u7684\u4ee3\u7801\u4e0d\u4f1a\u628a\u53d1\u8d77\u8c03\u7528\u7c7b\u7684\u7c7b\u540d\u89c6\u4f5c\u5f53\u524d\u7c7b\uff1b\u8fd9\u7c7b\u4f3c\u4e8e global \u8bed\u53e5\u7684\u6548\u679c\uff0c\u56e0\u6b64\u8fd9\u79cd\u6548\u679c\u4ec5\u9650\u4e8e\u540c\u65f6\u7ecf\u8fc7\u5b57\u8282\u7801\u7f16\u8bd1\u7684\u4ee3\u7801\u3002 \u540c\u6837\u7684\u9650\u5236\u4e5f\u9002\u7528\u4e8e getattr() , setattr() \u548c delattr() \uff0c\u4ee5\u53ca\u5bf9\u4e8e __dict__ \u7684\u76f4\u63a5\u5f15\u7528\u3002","title":"\u79c1\u6709\u53d8\u91cf Private Variables"},{"location":"python/Foundation/ch05/#reflection","text":"\u53cd\u5c04(reflection)\u662f\u52a8\u6001\u8bed\u8a00\u7684\u4e00\u4e2a\u7279\u6027\u3002**\u53cd\u5c04\u673a\u5236**\u6307\u7684\u662f\u5728\u7a0b\u5e8f\u7684\u8fd0\u884c\u72b6\u6001\u4e2d\uff0c\u5bf9\u4e8e\u4efb\u610f\u4e00\u4e2a\u7c7b\uff0c\u90fd\u53ef\u4ee5\u77e5\u9053\u8fd9\u4e2a\u7c7b\u7684\u6240\u6709\u5c5e\u6027\u548c\u65b9\u6cd5\uff1b\u5bf9\u4e8e\u4efb\u610f\u4e00\u4e2a\u5bf9\u8c61\uff0c\u90fd\u80fd\u591f\u8c03\u7528\u4ed6\u7684\u4efb\u610f\u65b9\u6cd5\u548c\u5c5e\u6027\u3002\u8fd9\u79cd\u52a8\u6001\u83b7\u53d6\u7a0b\u5e8f\u4fe1\u606f\u4ee5\u53ca\u52a8\u6001\u8c03\u7528\u5bf9\u8c61\u7684\u529f\u80fd\u79f0\u4e3a\u53cd\u5c04\u673a\u5236\u3002 \u901a\u8fc7\u4e0b\u9762\u4f8b\u5b50\u53ef\u77e5\uff0c\u901a\u8fc7 dir(person) \u83b7\u53d6\u4efb\u610f\u4e00\u4e2a\u7c7b\u6216\u8005\u5bf9\u8c61\u7684\u5c5e\u6027\u5217\u8868\u3002\u901a\u8fc7\u5185\u7f6e\u51fd\u6570 hasattr \u3001 getattr \u3001 setattr \u3001 delattr \u64cd\u4f5c\u7c7b\u548c\u5bf9\u8c61\u3002 class Person : def __init__ ( self , name , age , gender ): self . name = name self . age = age self . gender = gender person = Person ( 'Tom' , 21 , 'Male' ) print ( dir ( person )) # ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'gender', 'name'] # hasattr(object,'name') # \u6309\u5b57\u7b26\u4e32'name'\u5224\u65ad\u6709\u65e0\u5c5e\u6027person.name hasattr ( person , 'name' ) # True # getattr(object, 'name', default=None) # \u7b49\u540c\u4e8eperson.name,\u4e0d\u5b58\u5728\u8be5\u5c5e\u6027\u5219\u8fd4\u56de\u9ed8\u8ba4\u503cNone getattr ( person , 'name' , None ) # 'Tom' # setattr(x, 'y', v) # \u7b49\u540c\u4e8eperson.age = 18 setattr ( person , 'age' , 18 ) print ( person . age ) # 18 # delattr(x, 'y') # \u7b49\u540c\u4e8edel person.age delattr ( person , 'age' ) print ( person . age ) # AttributeError: 'Person' object has no attribute 'age' \u4e0b\u9762\u662f\u4e00\u4e2a\u5b9e\u9645\u5e94\u7528\u7684\u4f8b\u5b50\u3002 class FtpServer (): def server_run ( self ): while True : inp = input ( 'Input your command >>:' ) . strip () cmd , file = inp . split () if hasattr ( self , cmd ): func = getattr ( self , cmd ) func ( file ) def get ( self , file ): print ( f 'Downloading { file } ...' ) def put ( self , file ): print ( f 'Uploading { file } ...' ) ftp_server = FtpServer () ftp_server . server_run () # Input your command >>:get a.ext # Downloading a.ext... # Input your command >>:put a.txt # Uploading a.txt...","title":"\u53cd\u5c04(reflection)"},{"location":"python/Foundation/ch05/#iterators","text":"\u5728Python\u4e2d\uff0c\u5927\u591a\u6570\u5bb9\u5668\u5bf9\u8c61\uff08container object\uff09\u90fd\u53ef\u4ee5\u4f7f\u7528 for \u8bed\u53e5: for element in [ 1 , 2 , 3 ]: print ( element ) for element in ( 1 , 2 , 3 ): print ( element ) for key in { 'one' : 1 , 'two' : 2 }: print ( key ) for char in \"123\" : print ( char ) for line in open ( \"myfile.txt\" ): print ( line , end = '' ) for \u8bed\u53e5\u4f1a\u5728\u5bb9\u5668\u5bf9\u8c61\u4e0a\u8c03\u7528 iter()\u3002 \u8be5\u51fd\u6570\u8fd4\u56de\u4e00\u4e2a\u5b9a\u4e49\u4e86 __next__() \u65b9\u6cd5\u7684\u8fed\u4ee3\u5668\u5bf9\u8c61\uff0c\u6b64\u65b9\u6cd5\u5c06\u9010\u4e00\u8bbf\u95ee\u5bb9\u5668\u4e2d\u7684\u5143\u7d20\u3002 \u5f53\u5143\u7d20\u7528\u5c3d\u65f6\uff0c __next__() \u5c06\u5f15\u53d1 StopIteration \u5f02\u5e38\u6765\u901a\u77e5\u7ec8\u6b62 for \u5faa\u73af\u3002 \u53ef\u4ee5\u4f7f\u7528 next() \u5185\u7f6e\u51fd\u6570\u6765\u8c03\u7528 __next__() \u65b9\u6cd5\uff1b\u4e0b\u9762\u8fd9\u4e2a\u4f8b\u5b50\u5c55\u793a\u4e86\u521a\u521a\u63cf\u8ff0\u7684\u5177\u4f53\u8fd0\u884c\u65b9\u5f0f: >>> s = 'abc' >>> it = iter ( s ) >>> it < str_iterator object at 0x10c90e650 > >>> next ( it ) 'a' >>> next ( it ) 'b' >>> next ( it ) 'c' >>> next ( it ) Traceback ( most recent call last ): File \"\" , line 1 , in < module > next ( it ) StopIteration \u5728\u4e86\u89e3\u4e86\u8fed\u4ee3\u5668\u534f\u8bae\uff08iterator protocol\uff09\u7684\u673a\u5236\u540e\uff0c\u7ed9\u7c7b\u6dfb\u52a0\u8fed\u4ee3\u5668\u5c31\u5f88\u5bb9\u6613\u4e86\u3002 \u5b9a\u4e49\u4e00\u4e2a __iter__() \u65b9\u6cd5\u6765\u8fd4\u56de\u4e00\u4e2a\u5e26\u6709 __next__() \u65b9\u6cd5\u7684\u5bf9\u8c61\u3002 \u5982\u679c\u7c7b\u5df2\u5b9a\u4e49\u4e86 __next__() \uff0c\u5219 __iter__() \u53ef\u4ee5\u7b80\u5355\u5730\u8fd4\u56de self : class Reverse : \"\"\"Iterator for looping over a sequence backwards.\"\"\" def __init__ ( self , data ): self . data = data self . index = len ( data ) def __iter__ ( self ): return self def __next__ ( self ): if self . index == 0 : raise StopIteration self . index = self . index - 1 return self . data [ self . index ] rev = Reverse ( 'spam' ) print ( iter ( rev )) for char in rev : print ( char ) # m # a # p # s","title":"\u8fed\u4ee3\u5668 Iterators"},{"location":"python/Foundation/ch05/#generators","text":"**\u751f\u6210\u5668\uff08Generators\uff09**\u662f\u4e00\u4e2a\u7528\u4e8e\u521b\u5efa\u8fed\u4ee3\u5668\u7684\u7b80\u5355\u800c\u5f3a\u5927\u7684\u5de5\u5177\u3002 \u5b83\u4eec\u7684\u5199\u6cd5\u7c7b\u4f3c\u4e8e\u6807\u51c6\u7684\u51fd\u6570\uff0c\u4f46\u5f53\u5b83\u4eec\u8981\u8fd4\u56de\u6570\u636e\u65f6\u4f1a\u4f7f\u7528 yield \u8bed\u53e5\u3002 \u6bcf\u6b21\u5728\u751f\u6210\u5668\u4e0a\u8c03\u7528 next() \u65f6\uff0c\u5b83\u4f1a\u4ece\u4e0a\u6b21\u79bb\u5f00\u7684\u4f4d\u7f6e\u6062\u590d\u6267\u884c\uff08\u5b83\u4f1a\u8bb0\u4f4f\u4e0a\u6b21\u6267\u884c\u8bed\u53e5\u65f6\u7684\u6240\u6709\u6570\u636e\u503c\uff09\u3002 \u4e00\u4e2a\u521b\u5efa\u751f\u6210\u5668\u7684\u793a\u4f8b\u5982\u4e0b\uff08\u6539\u5199\u4e0a\u9762\u8fed\u4ee3\u5668\u4e2d\u6240\u4e3e\u7684\u4f8b\u5b50\uff09: def reverse ( data ): for index in range ( len ( data ) - 1 , - 1 , - 1 ): yield data [ index ] for char in reverse ( 'golf' ): print ( char ) # f # l # o # g \u53ef\u4ee5\u7528\u751f\u6210\u5668\u6765\u5b8c\u6210\u7684\u64cd\u4f5c\u540c\u6837\u53ef\u4ee5\u7528\u524d\u9762\u6240\u63cf\u8ff0\u7684\u57fa\u4e8e\u7c7b\u7684\u8fed\u4ee3\u5668\u6765\u5b8c\u6210\u3002\u4f46\u751f\u6210\u5668\u7684\u5199\u6cd5\u66f4\u4e3a\u7d27\u51d1\uff0c\u56e0\u4e3a\u5b83\u4f1a\u81ea\u52a8\u521b\u5efa __iter__() \u548c __next__() \u65b9\u6cd5\u3002 \u53e6\u4e00\u4e2a\u5173\u952e\u7279\u6027\u5728\u4e8e\u5c40\u90e8\u53d8\u91cf\u548c\u6267\u884c\u72b6\u6001\u4f1a\u5728\u6bcf\u6b21\u8c03\u7528\u4e4b\u95f4\u81ea\u52a8\u4fdd\u5b58\u3002 \u8fd9\u4f7f\u5f97\u8be5\u51fd\u6570\u76f8\u6bd4\u4f7f\u7528 self.index \u548c self.data \u8fd9\u79cd\u5b9e\u4f8b\u53d8\u91cf\u7684\u65b9\u5f0f\u66f4\u6613\u7f16\u5199\u4e14\u66f4\u4e3a\u6e05\u6670\u3002 \u9664\u4e86\u4f1a\u81ea\u52a8\u521b\u5efa\u65b9\u6cd5\u548c\u4fdd\u5b58\u7a0b\u5e8f\u72b6\u6001\uff0c\u5f53\u751f\u6210\u5668\u7ec8\u7ed3\u65f6\uff0c\u5b83\u4eec\u8fd8\u4f1a\u81ea\u52a8\u5f15\u53d1 StopIteration \u3002","title":"\u751f\u6210\u5668 Generators"},{"location":"python/Foundation/ch05/#generator-expressions","text":"\u67d0\u4e9b\u7b80\u5355\u7684\u751f\u6210\u5668\u53ef\u4ee5\u5199\u6210\u7b80\u6d01\u7684\u8868\u8fbe\u5f0f\u4ee3\u7801\uff0c\u6240\u7528\u8bed\u6cd5\u7c7b\u4f3c\u5217\u8868\u63a8\u5bfc\u5f0f\uff0c\u4f46\u5916\u5c42\u4e3a\u5706\u62ec\u53f7\u800c\u975e\u65b9\u62ec\u53f7\u3002 \u8fd9\u79cd\u8868\u8fbe\u5f0f\u88ab\u8bbe\u8ba1\u7528\u4e8e\u751f\u6210\u5668\u5c06\u7acb\u5373\u88ab\u5916\u5c42\u51fd\u6570\u6240\u4f7f\u7528\u7684\u60c5\u51b5\u3002 \u751f\u6210\u5668\u8868\u8fbe\u5f0f\u76f8\u6bd4\u5b8c\u6574\u7684\u751f\u6210\u5668\u66f4\u7d27\u51d1\u4f46\u8f83\u4e0d\u7075\u6d3b\uff0c\u76f8\u6bd4\u7b49\u6548\u7684\u5217\u8868\u63a8\u5bfc\u5f0f\u5219\u66f4\u4e3a\u8282\u7701\u5185\u5b58\u3002 \u793a\u4f8b: >>> sum ( i * i for i in range ( 10 )) # sum of squares 285 >>> xvec = [ 10 , 20 , 30 ] >>> yvec = [ 7 , 5 , 3 ] >>> sum ( x * y for x , y in zip ( xvec , yvec )) # dot product 260 >>> unique_words = set ( word for line in page for word in line . split ()) >>> valedictorian = max (( student . gpa , student . name ) for student in graduates ) >>> data = 'golf' >>> list ( data [ i ] for i in range ( len ( data ) - 1 , - 1 , - 1 )) [ 'f' , 'l' , 'o' , 'g' ]","title":"\u751f\u6210\u5668\u8868\u8fbe\u5f0f Generator Expressions"},{"location":"python/Foundation/ch05/#metaclass","text":"\u6240\u6709\u7684\u5bf9\u8c61\u90fd\u662f\u5b9e\u4f8b\u5316\u6216\u8005\u8bf4\u8c03\u7528\u7c7b\u800c\u5f97\u5230\u7684\uff08\u8c03\u7528\u7c7b\u7684\u8fc7\u7a0b\u79f0\u4e3a\u7c7b\u7684\u5b9e\u4f8b\u5316\u3002 class StandfordProfessor ( object ): university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) \u4e0a\u4f8b\u4e2d\uff0c\u5bf9\u8c61 professor \u662f\u8c03\u7528\u7c7b StandfordProfessor \u5f97\u5230\u7684\u3002\u7c7b StandfordProfessor \u672c\u8d28\u4e5f\u662f\u4e00\u4e2a\u5bf9\u8c61\uff0c \u4e0b\u9762\u53ef\u4ee5\u9a8c\u8bc1\uff0c StandfordProfessor \u662f\u8c03\u7528\u4e86\u5185\u7f6e\u7684\u7c7b type \u5f97\u5230\u7684\u3002\u8fd9\u4e2a type \u79f0\u4e3a\u5143\u7c7b\u3002 print ( type ( StandfordProfessor )) # \u5982\u679c\u4e00\u4e2a\u7c7b\u6ca1\u6709\u58f0\u660e\u81ea\u5df1\u7684\u5143\u7c7b\uff0c\u9ed8\u8ba4\u5b83\u7684\u5143\u7c7b\u5c31\u662f type \uff0c\u9664\u4e86\u4f7f\u7528\u5185\u7f6e\u5143\u7c7b type \uff0c\u6211\u4eec\u4e5f\u53ef\u4ee5\u901a\u8fc7\u7ee7\u627f type \u6765\u81ea\u5b9a\u4e49\u5143\u7c7b\uff0c\u7136\u540e\u4f7f\u7528 metaclass \u5173\u952e\u5b57\u53c2\u6570\u4e3a\u4e00\u4e2a\u7c7b\u7684\u6307\u5b9a\u5143\u7c7b\u3002 \u53ea\u6709\u7ee7\u627f\u4e86type\u7c7b\u624d\u80fd\u79f0\u4e4b\u4e3a\u4e00\u4e2a\u5143\u7c7b\uff0c\u5426\u5219\u5c31\u662f\u4e00\u4e2a\u666e\u901a\u7684\u81ea\u5b9a\u4e49\u7c7b\u3002 class Mymeta ( type ): pass class StandfordProfessor ( object , metaclass = Mymeta ): university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) \u4e0b\u9762\u8fdb\u884c\u81ea\u5b9a\u4e49\u5143\u7c7b\uff0c\u63a7\u5236\u7c7b StandfordProfessor \u7684\u8c03\u7528\u3002 \u8981\u60f3\u8ba9 professor \u8fd9\u4e2a\u5bf9\u8c61\u53d8\u6210\u4e00\u4e2a\u53ef\u8c03\u7528\u7684\u5bf9\u8c61\uff0c\u9700\u8981\u5728\u8be5\u5bf9\u8c61\u7684\u7c7b\u4e2d\u5b9a\u4e49\u4e00\u4e2a\u65b9\u6cd5 __call__ \uff0c\u8be5\u65b9\u6cd5\u4f1a\u5728\u8c03\u7528\u5bf9\u8c61\u65f6\u81ea\u52a8\u89e6\u53d1\u3002\u8c03\u7528 professor \u7684\u8fd4\u56de\u503c\u5c31\u662f __call__ \u65b9\u6cd5\u7684\u8fd4\u56de\u503c\u3002 class Mymeta ( type ): def __call__ ( self , * args , ** kwargs ): print ( self ) # \u7c7b\u540d print ( args ) # \u8f93\u5165\u53c2\u6570 print ( kwargs ) # \u8f93\u5165\u53c2\u6570 return 10086 class StandfordProfessor ( object , metaclass = Mymeta ): university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) # # ('Tom', 'Male') # {} \u7c7b\u7684\u4ea7\u751f\u8fc7\u7a0b\u5176\u5b9e\u5c31\u662f\u5143\u7c7b\u7684\u8c03\u7528\u8fc7\u7a0b,\u5373 StandfordProfessor = Mymeta('StandfordProfessor', (object), {...}) \uff0c\u8c03\u7528 Mymeta \u4f1a\u5148\u4ea7\u751f\u4e00\u4e2a\u7a7a\u5bf9\u8c61 StandfordProfessor \uff0c\u7136\u540e\u8fde\u540c\u8c03\u7528 Mymeta \u62ec\u53f7\u5185\u7684\u53c2\u6570\u4e00\u540c\u4f20\u7ed9 Mymeta \u4e0b\u7684 __init__ \u65b9\u6cd5\uff0c\u5b8c\u6210\u521d\u59cb\u5316\u3002\u6211\u4eec\u53ef\u4ee5\u57fa\u4e8e\u4e0a\u4f8b\u505a\u5982\u4e0b\u6539\u5199\u3002 class Mymeta ( type ): def __init__ ( self , class_name , class_bases , class_dic ): super ( Mymeta , self ) . __init__ ( class_name , class_bases , class_dic ) if class_name . islower (): raise TypeError ( f 'Please follow Camel-Case to change class name { class_name } ' ) if '__doc__' not in class_dic or len ( class_dic [ '__doc__' ] . strip ( ' \\n ' )) == 0 : raise TypeError ( 'Please add documentation in class {class_name} , which is mandatory.' ) class StandfordProfessor ( object , metaclass = Mymeta ): \"\"\" Documentation of class StanfordTeacher \"\"\" university = 'Standford' def __init__ ( self , name , gender ): self . name = name self . gender = gender def display ( self ): print ( f 'Professor { self . name } says welcome to { self . university } !' ) professor = StandfordProfessor ( 'Tom' , 'Male' ) professor . display () # Professor Tom says welcome to Standford! print ( professor . __dict__ ) # {'name': 'Tom', 'gender': 'Male'} StandfordProfessor . mro () # [, ]","title":"\u5143\u7c7b\uff08metaclass\uff09"}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml index 5f5e123c..ccda71a5 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -2,522 +2,522 @@ https://huyuhui001.github.io/mySite/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/about/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/basics/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/casestudy-calico/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/casestudy-health-check/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/casestudy-operation-resources/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/clustermgt/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/configuration/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/daemonset/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/deployment/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/docker/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/healthcheck/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/helming/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/hpa/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/ingress/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/job/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/memo/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/namespace/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/networkpolicy/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/overview/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/persistence/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/pod/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/policy/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/rbac/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/scheduling/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/secrets/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/service/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/statefulset/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/foundamentals/troubleshooting/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/installation/aliyun-ubuntu/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/installation/multiple-local/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_cn/installation/single-local/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/basics/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/casestudy-calico/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/casestudy-health-check/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/casestudy-operation-resources/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/clustermgt/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/configuration/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/daemonset/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/deployment/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/docker/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/healthcheck/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/helming/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/hpa/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/ingress/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/job/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/kyma/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/memo/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/namespace/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/networkpolicy/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/overview/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/persistence/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/pod/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/policy/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/rbac/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/scheduling/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/secrets/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/service/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/statefulset/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/foundamentals/troubleshooting/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/installation/aliyun-ubuntu/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/installation/multiple-local/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/cka_en/installation/single-local/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/k8s/demo/cap_on_kyma/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/linux/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/linux/Administration/01/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/linux/Administration/02/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/linux/Administration/03/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/linux/SES/linux_ses_demo/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/linux/SES/linux_ses_memo/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/linux/SRE/01-fundamentals/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/linux/SRE/02-filesystem/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/linux/SRE/03-identity-security/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/linux/SRE/04-TextTools/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/linux/SRE/05-RegExpress/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/linux/SRE/06-FileLookup/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/linux/SRE/07-FilePacking/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataAnalysis/ch01/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataAnalysis/ch02/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataAnalysis/ch03/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataAnalysis/ch04/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataAnalysis/ch05/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataAnalysis/ch06/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataAnalysis/ch07/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataAnalysis/ch08/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataAnalysis/ch09/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataAnalysis/ch10/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataAnalysis/ch11/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataStructure/01_PythonFundmantal/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataStructure/02_CollectionsOverview/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataStructure/03_TimeComplexity/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataStructure/04_ArrayChain/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataStructure/05_InterfacePolymorphism/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/DataStructure/06_InheritanceAbstractClass/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/Demo/CourseSystem/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/Foundation/Algorithms/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/Foundation/ch00/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/Foundation/ch01/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/Foundation/ch02/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/Foundation/ch03/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/Foundation/ch04/ - 2023-09-27 + 2023-10-02 daily https://huyuhui001.github.io/mySite/python/Foundation/ch05/ - 2023-09-27 + 2023-10-02 daily \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz index 349f7d0c04c612554423de597268ca5f19c1acab..70897660cd2d66e392a6e032c9a2a2e14abe0cad 100644 GIT binary patch delta 629 zcmV-*0*d{s2df7MABzYG$pRaZ2OodcilIVuMygb)qcUAb#<>s|KT{b&So2Jm2kh!=NG=(S)J%n>@&xZ$f@*%!}ds!R*}?f4TvVSBKA3J2`*rMhQGj zo!V351`^lidO&e?21g zsDPx#IUASJCmE9`F22g=L;Dk#U`BKm7-AITa^bWl*=dIG72*}=+ks5V7iDPSOrvSv z`{L~F7_Q5?_o7|YLRm!qoAR@b4=eyl*7*r%9nlN;JlLuMzO~_A;c`!##)m$oGzl$Hv*KL=bXnGkFU-F zEs~q;D{Y?kP5&+L8T4)T%q#n|bKBIwK;IppUxeKDzDQ`=Soi%^>51{9lidO&e*uwt zR6tVWoQ=!qlZ?p|7hmPeq5YXlFeADO3^9svxo}#O>@-980`ZFT?La2wt1`53rqQ(T zeR1}74A